Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Trickey <howard.trickey@gmail.com>2021-10-30 22:37:05 +0300
committerHoward Trickey <howard.trickey@gmail.com>2021-10-30 22:37:05 +0300
commite9bbfd0c8c7a508d220bf355722ff03f91e93183 (patch)
tree1230f26bc82f24547aeccbaa7fcd6d3db2655fd3
parent1aa953bd1913c81b22c80a00edbf4ad88a32c52f (diff)
parent03a962d8cab44221650f59eb223cb0a767e05b2b (diff)
Merge branch 'master' into soc-2020-io-performancesoc-2020-io-performance
-rw-r--r--CMakeLists.txt5
-rw-r--r--build_files/windows/parse_arguments.cmd3
-rw-r--r--build_files/windows/svn_fix.cmd26
-rw-r--r--doc/doxygen/Doxyfile2
-rw-r--r--doc/python_api/sphinx_doc_gen.py7
-rw-r--r--intern/cycles/CMakeLists.txt10
-rw-r--r--intern/cycles/app/CMakeLists.txt3
-rw-r--r--intern/cycles/app/cycles_server.cpp14
-rw-r--r--intern/cycles/app/cycles_standalone.cpp38
-rw-r--r--intern/cycles/app/cycles_xml.cpp42
-rw-r--r--intern/cycles/app/oiio_output_driver.h12
-rw-r--r--intern/cycles/blender/CMakeLists.txt65
-rw-r--r--intern/cycles/blender/addon/properties.py31
-rw-r--r--intern/cycles/blender/addon/ui.py20
-rw-r--r--intern/cycles/blender/blender_camera.cpp965
-rw-r--r--intern/cycles/blender/blender_curves.cpp914
-rw-r--r--intern/cycles/blender/blender_device.cpp120
-rw-r--r--intern/cycles/blender/blender_display_driver.cpp754
-rw-r--r--intern/cycles/blender/blender_display_driver.h210
-rw-r--r--intern/cycles/blender/blender_geometry.cpp241
-rw-r--r--intern/cycles/blender/blender_id_map.h295
-rw-r--r--intern/cycles/blender/blender_image.cpp220
-rw-r--r--intern/cycles/blender/blender_image.h61
-rw-r--r--intern/cycles/blender/blender_light.cpp205
-rw-r--r--intern/cycles/blender/blender_logging.cpp33
-rw-r--r--intern/cycles/blender/blender_mesh.cpp1301
-rw-r--r--intern/cycles/blender/blender_object.cpp769
-rw-r--r--intern/cycles/blender/blender_object_cull.cpp142
-rw-r--r--intern/cycles/blender/blender_object_cull.h48
-rw-r--r--intern/cycles/blender/blender_output_driver.cpp126
-rw-r--r--intern/cycles/blender/blender_output_driver.h40
-rw-r--r--intern/cycles/blender/blender_particles.cpp94
-rw-r--r--intern/cycles/blender/blender_python.cpp1063
-rw-r--r--intern/cycles/blender/blender_session.cpp1003
-rw-r--r--intern/cycles/blender/blender_session.h164
-rw-r--r--intern/cycles/blender/blender_shader.cpp1572
-rw-r--r--intern/cycles/blender/blender_sync.cpp945
-rw-r--r--intern/cycles/blender/blender_sync.h276
-rw-r--r--intern/cycles/blender/blender_texture.cpp57
-rw-r--r--intern/cycles/blender/blender_texture.h32
-rw-r--r--intern/cycles/blender/blender_util.h720
-rw-r--r--intern/cycles/blender/blender_viewport.cpp106
-rw-r--r--intern/cycles/blender/blender_viewport.h63
-rw-r--r--intern/cycles/blender/blender_volume.cpp322
-rw-r--r--intern/cycles/blender/camera.cpp965
-rw-r--r--intern/cycles/blender/curves.cpp915
-rw-r--r--intern/cycles/blender/device.cpp120
-rw-r--r--intern/cycles/blender/device.h (renamed from intern/cycles/blender/blender_device.h)0
-rw-r--r--intern/cycles/blender/display_driver.cpp771
-rw-r--r--intern/cycles/blender/display_driver.h213
-rw-r--r--intern/cycles/blender/geometry.cpp241
-rw-r--r--intern/cycles/blender/id_map.h295
-rw-r--r--intern/cycles/blender/image.cpp220
-rw-r--r--intern/cycles/blender/image.h61
-rw-r--r--intern/cycles/blender/light.cpp205
-rw-r--r--intern/cycles/blender/logging.cpp33
-rw-r--r--intern/cycles/blender/mesh.cpp1302
-rw-r--r--intern/cycles/blender/object.cpp769
-rw-r--r--intern/cycles/blender/object_cull.cpp142
-rw-r--r--intern/cycles/blender/object_cull.h48
-rw-r--r--intern/cycles/blender/output_driver.cpp126
-rw-r--r--intern/cycles/blender/output_driver.h40
-rw-r--r--intern/cycles/blender/particles.cpp94
-rw-r--r--intern/cycles/blender/python.cpp1063
-rw-r--r--intern/cycles/blender/session.cpp1003
-rw-r--r--intern/cycles/blender/session.h166
-rw-r--r--intern/cycles/blender/shader.cpp1589
-rw-r--r--intern/cycles/blender/sync.cpp966
-rw-r--r--intern/cycles/blender/sync.h276
-rw-r--r--intern/cycles/blender/texture.cpp57
-rw-r--r--intern/cycles/blender/texture.h32
-rw-r--r--intern/cycles/blender/util.h720
-rw-r--r--intern/cycles/blender/viewport.cpp107
-rw-r--r--intern/cycles/blender/viewport.h63
-rw-r--r--intern/cycles/blender/volume.cpp322
-rw-r--r--intern/cycles/bvh/CMakeLists.txt40
-rw-r--r--intern/cycles/bvh/binning.cpp293
-rw-r--r--intern/cycles/bvh/binning.h115
-rw-r--r--intern/cycles/bvh/build.cpp1144
-rw-r--r--intern/cycles/bvh/build.h142
-rw-r--r--intern/cycles/bvh/bvh.cpp10
-rw-r--r--intern/cycles/bvh/bvh.h8
-rw-r--r--intern/cycles/bvh/bvh2.cpp16
-rw-r--r--intern/cycles/bvh/bvh2.h6
-rw-r--r--intern/cycles/bvh/bvh_binning.cpp293
-rw-r--r--intern/cycles/bvh/bvh_binning.h115
-rw-r--r--intern/cycles/bvh/bvh_build.cpp1144
-rw-r--r--intern/cycles/bvh/bvh_build.h142
-rw-r--r--intern/cycles/bvh/bvh_embree.cpp728
-rw-r--r--intern/cycles/bvh/bvh_embree.h68
-rw-r--r--intern/cycles/bvh/bvh_multi.cpp37
-rw-r--r--intern/cycles/bvh/bvh_multi.h39
-rw-r--r--intern/cycles/bvh/bvh_node.cpp224
-rw-r--r--intern/cycles/bvh/bvh_node.h255
-rw-r--r--intern/cycles/bvh/bvh_optix.cpp47
-rw-r--r--intern/cycles/bvh/bvh_optix.h49
-rw-r--r--intern/cycles/bvh/bvh_params.h335
-rw-r--r--intern/cycles/bvh/bvh_sort.cpp187
-rw-r--r--intern/cycles/bvh/bvh_split.cpp518
-rw-r--r--intern/cycles/bvh/bvh_split.h240
-rw-r--r--intern/cycles/bvh/bvh_unaligned.cpp165
-rw-r--r--intern/cycles/bvh/bvh_unaligned.h73
-rw-r--r--intern/cycles/bvh/embree.cpp728
-rw-r--r--intern/cycles/bvh/embree.h68
-rw-r--r--intern/cycles/bvh/multi.cpp37
-rw-r--r--intern/cycles/bvh/multi.h39
-rw-r--r--intern/cycles/bvh/node.cpp224
-rw-r--r--intern/cycles/bvh/node.h255
-rw-r--r--intern/cycles/bvh/optix.cpp47
-rw-r--r--intern/cycles/bvh/optix.h50
-rw-r--r--intern/cycles/bvh/params.h335
-rw-r--r--intern/cycles/bvh/sort.cpp187
-rw-r--r--intern/cycles/bvh/sort.h (renamed from intern/cycles/bvh/bvh_sort.h)0
-rw-r--r--intern/cycles/bvh/split.cpp518
-rw-r--r--intern/cycles/bvh/split.h240
-rw-r--r--intern/cycles/bvh/unaligned.cpp165
-rw-r--r--intern/cycles/bvh/unaligned.h73
-rw-r--r--intern/cycles/device/CMakeLists.txt23
-rw-r--r--intern/cycles/device/cpu/device.cpp2
-rw-r--r--intern/cycles/device/cpu/device.h4
-rw-r--r--intern/cycles/device/cpu/device_impl.cpp38
-rw-r--r--intern/cycles/device/cpu/device_impl.h8
-rw-r--r--intern/cycles/device/cpu/kernel.h2
-rw-r--r--intern/cycles/device/cpu/kernel_function.h4
-rw-r--r--intern/cycles/device/cpu/kernel_thread_globals.cpp6
-rw-r--r--intern/cycles/device/cuda/device.cpp6
-rw-r--r--intern/cycles/device/cuda/device.h4
-rw-r--r--intern/cycles/device/cuda/device_impl.cpp24
-rw-r--r--intern/cycles/device/cuda/device_impl.h2
-rw-r--r--intern/cycles/device/cuda/graphics_interop.h2
-rw-r--r--intern/cycles/device/cuda/kernel.h2
-rw-r--r--intern/cycles/device/cuda/queue.h6
-rw-r--r--intern/cycles/device/denoise.cpp88
-rw-r--r--intern/cycles/device/denoise.h110
-rw-r--r--intern/cycles/device/device.cpp22
-rw-r--r--intern/cycles/device/device.h30
-rw-r--r--intern/cycles/device/device_denoise.cpp88
-rw-r--r--intern/cycles/device/device_denoise.h110
-rw-r--r--intern/cycles/device/device_graphics_interop.cpp21
-rw-r--r--intern/cycles/device/device_graphics_interop.h42
-rw-r--r--intern/cycles/device/device_kernel.cpp165
-rw-r--r--intern/cycles/device/device_kernel.h33
-rw-r--r--intern/cycles/device/device_memory.cpp285
-rw-r--r--intern/cycles/device/device_memory.h650
-rw-r--r--intern/cycles/device/device_queue.cpp95
-rw-r--r--intern/cycles/device/device_queue.h115
-rw-r--r--intern/cycles/device/dummy/device.cpp2
-rw-r--r--intern/cycles/device/dummy/device.h4
-rw-r--r--intern/cycles/device/graphics_interop.cpp21
-rw-r--r--intern/cycles/device/graphics_interop.h42
-rw-r--r--intern/cycles/device/hip/device.cpp6
-rw-r--r--intern/cycles/device/hip/device.h4
-rw-r--r--intern/cycles/device/hip/device_impl.cpp26
-rw-r--r--intern/cycles/device/hip/device_impl.h4
-rw-r--r--intern/cycles/device/hip/graphics_interop.h2
-rw-r--r--intern/cycles/device/hip/kernel.h2
-rw-r--r--intern/cycles/device/hip/queue.h6
-rw-r--r--intern/cycles/device/kernel.cpp165
-rw-r--r--intern/cycles/device/kernel.h33
-rw-r--r--intern/cycles/device/memory.cpp285
-rw-r--r--intern/cycles/device/memory.h650
-rw-r--r--intern/cycles/device/multi/device.cpp17
-rw-r--r--intern/cycles/device/multi/device.h4
-rw-r--r--intern/cycles/device/optix/device.cpp3
-rw-r--r--intern/cycles/device/optix/device.h4
-rw-r--r--intern/cycles/device/optix/device_impl.cpp31
-rw-r--r--intern/cycles/device/optix/device_impl.h2
-rw-r--r--intern/cycles/device/optix/queue.cpp2
-rw-r--r--intern/cycles/device/queue.cpp95
-rw-r--r--intern/cycles/device/queue.h115
-rw-r--r--intern/cycles/graph/node.cpp8
-rw-r--r--intern/cycles/graph/node.h6
-rw-r--r--intern/cycles/graph/node_enum.h4
-rw-r--r--intern/cycles/graph/node_type.cpp4
-rw-r--r--intern/cycles/graph/node_type.h10
-rw-r--r--intern/cycles/graph/node_xml.cpp6
-rw-r--r--intern/cycles/graph/node_xml.h6
-rw-r--r--intern/cycles/integrator/CMakeLists.txt4
-rw-r--r--intern/cycles/integrator/adaptive_sampling.cpp2
-rw-r--r--intern/cycles/integrator/denoiser.cpp6
-rw-r--r--intern/cycles/integrator/denoiser.h6
-rw-r--r--intern/cycles/integrator/denoiser_device.cpp12
-rw-r--r--intern/cycles/integrator/denoiser_device.h2
-rw-r--r--intern/cycles/integrator/denoiser_oidn.cpp10
-rw-r--r--intern/cycles/integrator/denoiser_oidn.h4
-rw-r--r--intern/cycles/integrator/denoiser_optix.cpp2
-rw-r--r--intern/cycles/integrator/pass_accessor.cpp6
-rw-r--r--intern/cycles/integrator/pass_accessor.h8
-rw-r--r--intern/cycles/integrator/pass_accessor_cpu.cpp10
-rw-r--r--intern/cycles/integrator/pass_accessor_gpu.cpp6
-rw-r--r--intern/cycles/integrator/pass_accessor_gpu.h2
-rw-r--r--intern/cycles/integrator/path_trace.cpp16
-rw-r--r--intern/cycles/integrator/path_trace.h10
-rw-r--r--intern/cycles/integrator/path_trace_display.cpp23
-rw-r--r--intern/cycles/integrator/path_trace_display.h19
-rw-r--r--intern/cycles/integrator/path_trace_tile.cpp8
-rw-r--r--intern/cycles/integrator/path_trace_tile.h2
-rw-r--r--intern/cycles/integrator/path_trace_work.cpp8
-rw-r--r--intern/cycles/integrator/path_trace_work.h8
-rw-r--r--intern/cycles/integrator/path_trace_work_cpu.cpp12
-rw-r--r--intern/cycles/integrator/path_trace_work_cpu.h6
-rw-r--r--intern/cycles/integrator/path_trace_work_gpu.cpp33
-rw-r--r--intern/cycles/integrator/path_trace_work_gpu.h10
-rw-r--r--intern/cycles/integrator/render_scheduler.cpp10
-rw-r--r--intern/cycles/integrator/render_scheduler.h4
-rw-r--r--intern/cycles/integrator/shader_eval.cpp8
-rw-r--r--intern/cycles/integrator/shader_eval.h6
-rw-r--r--intern/cycles/integrator/tile.cpp32
-rw-r--r--intern/cycles/integrator/tile.h5
-rw-r--r--intern/cycles/integrator/work_balancer.cpp4
-rw-r--r--intern/cycles/integrator/work_balancer.h2
-rw-r--r--intern/cycles/integrator/work_tile_scheduler.cpp17
-rw-r--r--intern/cycles/integrator/work_tile_scheduler.h10
-rw-r--r--intern/cycles/kernel/CMakeLists.txt558
-rw-r--r--intern/cycles/kernel/bake/bake.h119
-rw-r--r--intern/cycles/kernel/bvh/bvh.h38
-rw-r--r--intern/cycles/kernel/bvh/bvh_embree.h156
-rw-r--r--intern/cycles/kernel/bvh/embree.h156
-rw-r--r--intern/cycles/kernel/bvh/local.h (renamed from intern/cycles/kernel/bvh/bvh_local.h)0
-rw-r--r--intern/cycles/kernel/bvh/nodes.h (renamed from intern/cycles/kernel/bvh/bvh_nodes.h)0
-rw-r--r--intern/cycles/kernel/bvh/shadow_all.h (renamed from intern/cycles/kernel/bvh/bvh_shadow_all.h)0
-rw-r--r--intern/cycles/kernel/bvh/traversal.h (renamed from intern/cycles/kernel/bvh/bvh_traversal.h)0
-rw-r--r--intern/cycles/kernel/bvh/types.h (renamed from intern/cycles/kernel/bvh/bvh_types.h)0
-rw-r--r--intern/cycles/kernel/bvh/util.h (renamed from intern/cycles/kernel/bvh/bvh_util.h)0
-rw-r--r--intern/cycles/kernel/bvh/volume.h (renamed from intern/cycles/kernel/bvh/bvh_volume.h)0
-rw-r--r--intern/cycles/kernel/bvh/volume_all.h (renamed from intern/cycles/kernel/bvh/bvh_volume_all.h)0
-rw-r--r--intern/cycles/kernel/camera/camera.h521
-rw-r--r--intern/cycles/kernel/camera/projection.h (renamed from intern/cycles/kernel/kernel_projection.h)0
-rw-r--r--intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_diffuse.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_diffuse_ramp.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_hair_principled.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h25
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h13
-rw-r--r--intern/cycles/kernel/closure/bsdf_oren_nayar.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_principled_diffuse.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_toon.h8
-rw-r--r--intern/cycles/kernel/closure/bsdf_util.h106
-rw-r--r--intern/cycles/kernel/device/cpu/compat.h10
-rw-r--r--intern/cycles/kernel/device/cpu/globals.h6
-rw-r--r--intern/cycles/kernel/device/cpu/kernel.cpp2
-rw-r--r--intern/cycles/kernel/device/cpu/kernel.h4
-rw-r--r--intern/cycles/kernel/device/cpu/kernel_arch_impl.h43
-rw-r--r--intern/cycles/kernel/device/cpu/kernel_avx.cpp2
-rw-r--r--intern/cycles/kernel/device/cpu/kernel_avx2.cpp2
-rw-r--r--intern/cycles/kernel/device/cpu/kernel_sse2.cpp2
-rw-r--r--intern/cycles/kernel/device/cpu/kernel_sse3.cpp2
-rw-r--r--intern/cycles/kernel/device/cpu/kernel_sse41.cpp2
-rw-r--r--intern/cycles/kernel/device/cuda/compat.h4
-rw-r--r--intern/cycles/kernel/device/cuda/globals.h9
-rw-r--r--intern/cycles/kernel/device/gpu/kernel.h43
-rw-r--r--intern/cycles/kernel/device/gpu/parallel_active_index.h2
-rw-r--r--intern/cycles/kernel/device/gpu/parallel_prefix_sum.h2
-rw-r--r--intern/cycles/kernel/device/gpu/parallel_sorted_index.h2
-rw-r--r--intern/cycles/kernel/device/gpu/work_stealing.h (renamed from intern/cycles/kernel/kernel_work_stealing.h)0
-rw-r--r--intern/cycles/kernel/device/hip/compat.h4
-rw-r--r--intern/cycles/kernel/device/hip/globals.h9
-rw-r--r--intern/cycles/kernel/device/optix/compat.h4
-rw-r--r--intern/cycles/kernel/device/optix/globals.h9
-rw-r--r--intern/cycles/kernel/device/optix/kernel.cu16
-rw-r--r--intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu3
-rw-r--r--intern/cycles/kernel/film/accumulate.h559
-rw-r--r--intern/cycles/kernel/film/adaptive_sampling.h160
-rw-r--r--intern/cycles/kernel/film/id_passes.h (renamed from intern/cycles/kernel/kernel_id_passes.h)0
-rw-r--r--intern/cycles/kernel/film/passes.h342
-rw-r--r--intern/cycles/kernel/film/read.h532
-rw-r--r--intern/cycles/kernel/film/write_passes.h (renamed from intern/cycles/kernel/kernel_write_passes.h)0
-rw-r--r--intern/cycles/kernel/geom/attribute.h (renamed from intern/cycles/kernel/geom/geom_attribute.h)0
-rw-r--r--intern/cycles/kernel/geom/curve.h (renamed from intern/cycles/kernel/geom/geom_curve.h)0
-rw-r--r--intern/cycles/kernel/geom/curve_intersect.h (renamed from intern/cycles/kernel/geom/geom_curve_intersect.h)0
-rw-r--r--intern/cycles/kernel/geom/geom.h30
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle.h155
-rw-r--r--intern/cycles/kernel/geom/geom_patch.h468
-rw-r--r--intern/cycles/kernel/geom/geom_primitive.h351
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h312
-rw-r--r--intern/cycles/kernel/geom/motion_curve.h (renamed from intern/cycles/kernel/geom/geom_motion_curve.h)0
-rw-r--r--intern/cycles/kernel/geom/motion_triangle.h155
-rw-r--r--intern/cycles/kernel/geom/motion_triangle_intersect.h (renamed from intern/cycles/kernel/geom/geom_motion_triangle_intersect.h)0
-rw-r--r--intern/cycles/kernel/geom/motion_triangle_shader.h (renamed from intern/cycles/kernel/geom/geom_motion_triangle_shader.h)0
-rw-r--r--intern/cycles/kernel/geom/object.h (renamed from intern/cycles/kernel/geom/geom_object.h)0
-rw-r--r--intern/cycles/kernel/geom/patch.h470
-rw-r--r--intern/cycles/kernel/geom/primitive.h351
-rw-r--r--intern/cycles/kernel/geom/shader_data.h (renamed from intern/cycles/kernel/geom/geom_shader_data.h)0
-rw-r--r--intern/cycles/kernel/geom/subd_triangle.h (renamed from intern/cycles/kernel/geom/geom_subd_triangle.h)0
-rw-r--r--intern/cycles/kernel/geom/triangle.h (renamed from intern/cycles/kernel/geom/geom_triangle.h)0
-rw-r--r--intern/cycles/kernel/geom/triangle_intersect.h312
-rw-r--r--intern/cycles/kernel/geom/volume.h (renamed from intern/cycles/kernel/geom/geom_volume.h)0
-rw-r--r--intern/cycles/kernel/integrator/init_from_bake.h202
-rw-r--r--intern/cycles/kernel/integrator/init_from_camera.h124
-rw-r--r--intern/cycles/kernel/integrator/integrator_init_from_bake.h199
-rw-r--r--intern/cycles/kernel/integrator/integrator_init_from_camera.h121
-rw-r--r--intern/cycles/kernel/integrator/integrator_intersect_closest.h241
-rw-r--r--intern/cycles/kernel/integrator/integrator_intersect_subsurface.h36
-rw-r--r--intern/cycles/kernel/integrator/integrator_intersect_volume_stack.h206
-rw-r--r--intern/cycles/kernel/integrator/integrator_megakernel.h113
-rw-r--r--intern/cycles/kernel/integrator/integrator_shade_background.h218
-rw-r--r--intern/cycles/kernel/integrator/integrator_shade_light.h128
-rw-r--r--intern/cycles/kernel/integrator/integrator_shade_shadow.h190
-rw-r--r--intern/cycles/kernel/integrator/integrator_shade_surface.h543
-rw-r--r--intern/cycles/kernel/integrator/integrator_shade_volume.h1046
-rw-r--r--intern/cycles/kernel/integrator/integrator_shadow_state_template.h83
-rw-r--r--intern/cycles/kernel/integrator/integrator_state.h195
-rw-r--r--intern/cycles/kernel/integrator/integrator_state_flow.h148
-rw-r--r--intern/cycles/kernel/integrator/integrator_state_util.h439
-rw-r--r--intern/cycles/kernel/integrator/integrator_subsurface.h201
-rw-r--r--intern/cycles/kernel/integrator/integrator_subsurface_disk.h196
-rw-r--r--intern/cycles/kernel/integrator/integrator_subsurface_random_walk.h469
-rw-r--r--intern/cycles/kernel/integrator/intersect_closest.h246
-rw-r--r--intern/cycles/kernel/integrator/intersect_shadow.h (renamed from intern/cycles/kernel/integrator/integrator_intersect_shadow.h)0
-rw-r--r--intern/cycles/kernel/integrator/intersect_subsurface.h36
-rw-r--r--intern/cycles/kernel/integrator/intersect_volume_stack.h206
-rw-r--r--intern/cycles/kernel/integrator/megakernel.h113
-rw-r--r--intern/cycles/kernel/integrator/path_state.h376
-rw-r--r--intern/cycles/kernel/integrator/shade_background.h219
-rw-r--r--intern/cycles/kernel/integrator/shade_light.h128
-rw-r--r--intern/cycles/kernel/integrator/shade_shadow.h189
-rw-r--r--intern/cycles/kernel/integrator/shade_surface.h557
-rw-r--r--intern/cycles/kernel/integrator/shade_volume.h1049
-rw-r--r--intern/cycles/kernel/integrator/shader_eval.h869
-rw-r--r--intern/cycles/kernel/integrator/shadow_catcher.h120
-rw-r--r--intern/cycles/kernel/integrator/shadow_state_template.h86
-rw-r--r--intern/cycles/kernel/integrator/state.h195
-rw-r--r--intern/cycles/kernel/integrator/state_flow.h148
-rw-r--r--intern/cycles/kernel/integrator/state_template.h (renamed from intern/cycles/kernel/integrator/integrator_state_template.h)0
-rw-r--r--intern/cycles/kernel/integrator/state_util.h440
-rw-r--r--intern/cycles/kernel/integrator/subsurface.h201
-rw-r--r--intern/cycles/kernel/integrator/subsurface_disk.h206
-rw-r--r--intern/cycles/kernel/integrator/subsurface_random_walk.h469
-rw-r--r--intern/cycles/kernel/integrator/volume_stack.h (renamed from intern/cycles/kernel/integrator/integrator_volume_stack.h)0
-rw-r--r--intern/cycles/kernel/kernel_accumulate.h553
-rw-r--r--intern/cycles/kernel/kernel_adaptive_sampling.h160
-rw-r--r--intern/cycles/kernel/kernel_bake.h120
-rw-r--r--intern/cycles/kernel/kernel_camera.h521
-rw-r--r--intern/cycles/kernel/kernel_color.h35
-rw-r--r--intern/cycles/kernel/kernel_emission.h269
-rw-r--r--intern/cycles/kernel/kernel_film.h532
-rw-r--r--intern/cycles/kernel/kernel_jitter.h169
-rw-r--r--intern/cycles/kernel/kernel_light.h875
-rw-r--r--intern/cycles/kernel/kernel_light_background.h453
-rw-r--r--intern/cycles/kernel/kernel_light_common.h227
-rw-r--r--intern/cycles/kernel/kernel_lookup_table.h56
-rw-r--r--intern/cycles/kernel/kernel_math.h25
-rw-r--r--intern/cycles/kernel/kernel_montecarlo.h308
-rw-r--r--intern/cycles/kernel/kernel_passes.h334
-rw-r--r--intern/cycles/kernel/kernel_path_state.h376
-rw-r--r--intern/cycles/kernel/kernel_profiling.h40
-rw-r--r--intern/cycles/kernel/kernel_random.h216
-rw-r--r--intern/cycles/kernel/kernel_shader.h863
-rw-r--r--intern/cycles/kernel/kernel_shadow_catcher.h120
-rw-r--r--intern/cycles/kernel/kernel_types.h1594
-rw-r--r--intern/cycles/kernel/light/background.h453
-rw-r--r--intern/cycles/kernel/light/common.h227
-rw-r--r--intern/cycles/kernel/light/light.h872
-rw-r--r--intern/cycles/kernel/light/sample.h271
-rw-r--r--intern/cycles/kernel/osl/CMakeLists.txt18
-rw-r--r--intern/cycles/kernel/osl/background.cpp2
-rw-r--r--intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp5
-rw-r--r--intern/cycles/kernel/osl/bsdf_phong_ramp.cpp4
-rw-r--r--intern/cycles/kernel/osl/bssrdf.cpp122
-rw-r--r--intern/cycles/kernel/osl/closures.cpp1006
-rw-r--r--intern/cycles/kernel/osl/closures.h164
-rw-r--r--intern/cycles/kernel/osl/emissive.cpp4
-rw-r--r--intern/cycles/kernel/osl/globals.h109
-rw-r--r--intern/cycles/kernel/osl/osl_bssrdf.cpp123
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp1008
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h164
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h109
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp1721
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp431
-rw-r--r--intern/cycles/kernel/osl/osl_shader.h82
-rw-r--r--intern/cycles/kernel/osl/services.cpp1724
-rw-r--r--intern/cycles/kernel/osl/services.h (renamed from intern/cycles/kernel/osl/osl_services.h)0
-rw-r--r--intern/cycles/kernel/osl/shader.cpp428
-rw-r--r--intern/cycles/kernel/osl/shader.h82
-rw-r--r--intern/cycles/kernel/osl/shaders/CMakeLists.txt (renamed from intern/cycles/kernel/shaders/CMakeLists.txt)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_absorption_volume.osl (renamed from intern/cycles/kernel/shaders/node_absorption_volume.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_add_closure.osl (renamed from intern/cycles/kernel/shaders/node_add_closure.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_ambient_occlusion.osl (renamed from intern/cycles/kernel/shaders/node_ambient_occlusion.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_anisotropic_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_attribute.osl (renamed from intern/cycles/kernel/shaders/node_attribute.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_background.osl (renamed from intern/cycles/kernel/shaders/node_background.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_bevel.osl (renamed from intern/cycles/kernel/shaders/node_bevel.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_blackbody.osl (renamed from intern/cycles/kernel/shaders/node_blackbody.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_brick_texture.osl (renamed from intern/cycles/kernel/shaders/node_brick_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_brightness.osl (renamed from intern/cycles/kernel/shaders/node_brightness.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_bump.osl (renamed from intern/cycles/kernel/shaders/node_bump.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_camera.osl (renamed from intern/cycles/kernel/shaders/node_camera.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_checker_texture.osl (renamed from intern/cycles/kernel/shaders/node_checker_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_clamp.osl (renamed from intern/cycles/kernel/shaders/node_clamp.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_color.h (renamed from intern/cycles/kernel/shaders/node_color.h)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_combine_hsv.osl (renamed from intern/cycles/kernel/shaders/node_combine_hsv.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_combine_rgb.osl (renamed from intern/cycles/kernel/shaders/node_combine_rgb.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_combine_xyz.osl (renamed from intern/cycles/kernel/shaders/node_combine_xyz.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_convert_from_color.osl (renamed from intern/cycles/kernel/shaders/node_convert_from_color.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_convert_from_float.osl (renamed from intern/cycles/kernel/shaders/node_convert_from_float.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_convert_from_int.osl (renamed from intern/cycles/kernel/shaders/node_convert_from_int.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_convert_from_normal.osl (renamed from intern/cycles/kernel/shaders/node_convert_from_normal.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_convert_from_point.osl (renamed from intern/cycles/kernel/shaders/node_convert_from_point.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_convert_from_string.osl (renamed from intern/cycles/kernel/shaders/node_convert_from_string.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_convert_from_vector.osl (renamed from intern/cycles/kernel/shaders/node_convert_from_vector.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_diffuse_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_diffuse_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_displacement.osl (renamed from intern/cycles/kernel/shaders/node_displacement.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_emission.osl (renamed from intern/cycles/kernel/shaders/node_emission.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_environment_texture.osl (renamed from intern/cycles/kernel/shaders/node_environment_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_float_curve.osl (renamed from intern/cycles/kernel/shaders/node_float_curve.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_fresnel.h (renamed from intern/cycles/kernel/shaders/node_fresnel.h)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_fresnel.osl (renamed from intern/cycles/kernel/shaders/node_fresnel.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_gamma.osl (renamed from intern/cycles/kernel/shaders/node_gamma.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_geometry.osl (renamed from intern/cycles/kernel/shaders/node_geometry.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_glass_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_glass_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_glossy_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_gradient_texture.osl (renamed from intern/cycles/kernel/shaders/node_gradient_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_hair_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_hair_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_hair_info.osl (renamed from intern/cycles/kernel/shaders/node_hair_info.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_hash.h (renamed from intern/cycles/kernel/shaders/node_hash.h)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_holdout.osl (renamed from intern/cycles/kernel/shaders/node_holdout.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_hsv.osl (renamed from intern/cycles/kernel/shaders/node_hsv.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_ies_light.osl (renamed from intern/cycles/kernel/shaders/node_ies_light.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_image_texture.osl (renamed from intern/cycles/kernel/shaders/node_image_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_invert.osl (renamed from intern/cycles/kernel/shaders/node_invert.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_layer_weight.osl (renamed from intern/cycles/kernel/shaders/node_layer_weight.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_light_falloff.osl (renamed from intern/cycles/kernel/shaders/node_light_falloff.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_light_path.osl (renamed from intern/cycles/kernel/shaders/node_light_path.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_magic_texture.osl (renamed from intern/cycles/kernel/shaders/node_magic_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_map_range.osl (renamed from intern/cycles/kernel/shaders/node_map_range.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_mapping.osl (renamed from intern/cycles/kernel/shaders/node_mapping.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_math.h (renamed from intern/cycles/kernel/shaders/node_math.h)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_math.osl (renamed from intern/cycles/kernel/shaders/node_math.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_mix.osl (renamed from intern/cycles/kernel/shaders/node_mix.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_mix_closure.osl (renamed from intern/cycles/kernel/shaders/node_mix_closure.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl (renamed from intern/cycles/kernel/shaders/node_musgrave_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_noise.h (renamed from intern/cycles/kernel/shaders/node_noise.h)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_noise_texture.osl (renamed from intern/cycles/kernel/shaders/node_noise_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_normal.osl (renamed from intern/cycles/kernel/shaders/node_normal.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_normal_map.osl (renamed from intern/cycles/kernel/shaders/node_normal_map.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_object_info.osl (renamed from intern/cycles/kernel/shaders/node_object_info.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_output_displacement.osl (renamed from intern/cycles/kernel/shaders/node_output_displacement.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_output_surface.osl (renamed from intern/cycles/kernel/shaders/node_output_surface.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_output_volume.osl (renamed from intern/cycles/kernel/shaders/node_output_volume.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_particle_info.osl (renamed from intern/cycles/kernel/shaders/node_particle_info.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_principled_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_principled_hair_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_principled_volume.osl (renamed from intern/cycles/kernel/shaders/node_principled_volume.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_ramp_util.h (renamed from intern/cycles/kernel/shaders/node_ramp_util.h)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_refraction_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_refraction_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_rgb_curves.osl (renamed from intern/cycles/kernel/shaders/node_rgb_curves.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_rgb_ramp.osl (renamed from intern/cycles/kernel/shaders/node_rgb_ramp.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_rgb_to_bw.osl (renamed from intern/cycles/kernel/shaders/node_rgb_to_bw.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_scatter_volume.osl (renamed from intern/cycles/kernel/shaders/node_scatter_volume.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_separate_hsv.osl (renamed from intern/cycles/kernel/shaders/node_separate_hsv.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_separate_rgb.osl (renamed from intern/cycles/kernel/shaders/node_separate_rgb.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_separate_xyz.osl (renamed from intern/cycles/kernel/shaders/node_separate_xyz.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_set_normal.osl (renamed from intern/cycles/kernel/shaders/node_set_normal.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_sky_texture.osl (renamed from intern/cycles/kernel/shaders/node_sky_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_subsurface_scattering.osl (renamed from intern/cycles/kernel/shaders/node_subsurface_scattering.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_tangent.osl (renamed from intern/cycles/kernel/shaders/node_tangent.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_texture_coordinate.osl (renamed from intern/cycles/kernel/shaders/node_texture_coordinate.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_toon_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_toon_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_translucent_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_translucent_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_transparent_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_transparent_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_uv_map.osl (renamed from intern/cycles/kernel/shaders/node_uv_map.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_value.osl (renamed from intern/cycles/kernel/shaders/node_value.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_vector_curves.osl (renamed from intern/cycles/kernel/shaders/node_vector_curves.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_vector_displacement.osl (renamed from intern/cycles/kernel/shaders/node_vector_displacement.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_vector_math.osl (renamed from intern/cycles/kernel/shaders/node_vector_math.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_vector_rotate.osl (renamed from intern/cycles/kernel/shaders/node_vector_rotate.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_vector_transform.osl (renamed from intern/cycles/kernel/shaders/node_vector_transform.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_velvet_bsdf.osl (renamed from intern/cycles/kernel/shaders/node_velvet_bsdf.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_vertex_color.osl (renamed from intern/cycles/kernel/shaders/node_vertex_color.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl (renamed from intern/cycles/kernel/shaders/node_voronoi_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_voxel_texture.osl (renamed from intern/cycles/kernel/shaders/node_voxel_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_wave_texture.osl (renamed from intern/cycles/kernel/shaders/node_wave_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_wavelength.osl (renamed from intern/cycles/kernel/shaders/node_wavelength.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_white_noise_texture.osl (renamed from intern/cycles/kernel/shaders/node_white_noise_texture.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/node_wireframe.osl (renamed from intern/cycles/kernel/shaders/node_wireframe.osl)0
-rw-r--r--intern/cycles/kernel/osl/shaders/stdcycles.h (renamed from intern/cycles/kernel/shaders/stdcycles.h)0
-rw-r--r--intern/cycles/kernel/sample/jitter.h195
-rw-r--r--intern/cycles/kernel/sample/lcg.h51
-rw-r--r--intern/cycles/kernel/sample/mapping.h177
-rw-r--r--intern/cycles/kernel/sample/mis.h64
-rw-r--r--intern/cycles/kernel/sample/pattern.h185
-rw-r--r--intern/cycles/kernel/svm/ao.h141
-rw-r--r--intern/cycles/kernel/svm/aov.h70
-rw-r--r--intern/cycles/kernel/svm/attribute.h346
-rw-r--r--intern/cycles/kernel/svm/bevel.h327
-rw-r--r--intern/cycles/kernel/svm/blackbody.h55
-rw-r--r--intern/cycles/kernel/svm/brick.h141
-rw-r--r--intern/cycles/kernel/svm/brightness.h39
-rw-r--r--intern/cycles/kernel/svm/bump.h61
-rw-r--r--intern/cycles/kernel/svm/camera.h47
-rw-r--r--intern/cycles/kernel/svm/checker.h61
-rw-r--r--intern/cycles/kernel/svm/clamp.h49
-rw-r--r--intern/cycles/kernel/svm/closure.h1260
-rw-r--r--intern/cycles/kernel/svm/color_util.h323
-rw-r--r--intern/cycles/kernel/svm/convert.h78
-rw-r--r--intern/cycles/kernel/svm/displace.h180
-rw-r--r--intern/cycles/kernel/svm/fractal_noise.h139
-rw-r--r--intern/cycles/kernel/svm/fresnel.h84
-rw-r--r--intern/cycles/kernel/svm/gamma.h36
-rw-r--r--intern/cycles/kernel/svm/geometry.h261
-rw-r--r--intern/cycles/kernel/svm/gradient.h84
-rw-r--r--intern/cycles/kernel/svm/hsv.h61
-rw-r--r--intern/cycles/kernel/svm/ies.h122
-rw-r--r--intern/cycles/kernel/svm/image.h253
-rw-r--r--intern/cycles/kernel/svm/invert.h43
-rw-r--r--intern/cycles/kernel/svm/light_path.h148
-rw-r--r--intern/cycles/kernel/svm/magic.h115
-rw-r--r--intern/cycles/kernel/svm/map_range.h91
-rw-r--r--intern/cycles/kernel/svm/mapping.h86
-rw-r--r--intern/cycles/kernel/svm/mapping_util.h41
-rw-r--r--intern/cycles/kernel/svm/math.h77
-rw-r--r--intern/cycles/kernel/svm/math_util.h285
-rw-r--r--intern/cycles/kernel/svm/mix.h43
-rw-r--r--intern/cycles/kernel/svm/musgrave.h854
-rw-r--r--intern/cycles/kernel/svm/noise.h744
-rw-r--r--intern/cycles/kernel/svm/noisetex.h222
-rw-r--r--intern/cycles/kernel/svm/normal.h47
-rw-r--r--intern/cycles/kernel/svm/ramp.h165
-rw-r--r--intern/cycles/kernel/svm/ramp_util.h87
-rw-r--r--intern/cycles/kernel/svm/sepcomb_hsv.h69
-rw-r--r--intern/cycles/kernel/svm/sepcomb_vector.h53
-rw-r--r--intern/cycles/kernel/svm/sky.h335
-rw-r--r--intern/cycles/kernel/svm/svm.h106
-rw-r--r--intern/cycles/kernel/svm/svm_ao.h139
-rw-r--r--intern/cycles/kernel/svm/svm_aov.h68
-rw-r--r--intern/cycles/kernel/svm/svm_attribute.h344
-rw-r--r--intern/cycles/kernel/svm/svm_bevel.h325
-rw-r--r--intern/cycles/kernel/svm/svm_blackbody.h51
-rw-r--r--intern/cycles/kernel/svm/svm_brick.h139
-rw-r--r--intern/cycles/kernel/svm/svm_brightness.h35
-rw-r--r--intern/cycles/kernel/svm/svm_bump.h59
-rw-r--r--intern/cycles/kernel/svm/svm_camera.h45
-rw-r--r--intern/cycles/kernel/svm/svm_checker.h59
-rw-r--r--intern/cycles/kernel/svm/svm_clamp.h47
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h1258
-rw-r--r--intern/cycles/kernel/svm/svm_color_util.h321
-rw-r--r--intern/cycles/kernel/svm/svm_convert.h76
-rw-r--r--intern/cycles/kernel/svm/svm_displace.h178
-rw-r--r--intern/cycles/kernel/svm/svm_fractal_noise.h135
-rw-r--r--intern/cycles/kernel/svm/svm_fresnel.h82
-rw-r--r--intern/cycles/kernel/svm/svm_gamma.h34
-rw-r--r--intern/cycles/kernel/svm/svm_geometry.h259
-rw-r--r--intern/cycles/kernel/svm/svm_gradient.h82
-rw-r--r--intern/cycles/kernel/svm/svm_hsv.h64
-rw-r--r--intern/cycles/kernel/svm/svm_ies.h120
-rw-r--r--intern/cycles/kernel/svm/svm_image.h251
-rw-r--r--intern/cycles/kernel/svm/svm_invert.h41
-rw-r--r--intern/cycles/kernel/svm/svm_light_path.h146
-rw-r--r--intern/cycles/kernel/svm/svm_magic.h113
-rw-r--r--intern/cycles/kernel/svm/svm_map_range.h89
-rw-r--r--intern/cycles/kernel/svm/svm_mapping.h82
-rw-r--r--intern/cycles/kernel/svm/svm_mapping_util.h39
-rw-r--r--intern/cycles/kernel/svm/svm_math.h75
-rw-r--r--intern/cycles/kernel/svm/svm_math_util.h283
-rw-r--r--intern/cycles/kernel/svm/svm_mix.h41
-rw-r--r--intern/cycles/kernel/svm/svm_musgrave.h850
-rw-r--r--intern/cycles/kernel/svm/svm_noise.h742
-rw-r--r--intern/cycles/kernel/svm/svm_noisetex.h218
-rw-r--r--intern/cycles/kernel/svm/svm_normal.h45
-rw-r--r--intern/cycles/kernel/svm/svm_ramp.h168
-rw-r--r--intern/cycles/kernel/svm/svm_ramp_util.h90
-rw-r--r--intern/cycles/kernel/svm/svm_sepcomb_hsv.h67
-rw-r--r--intern/cycles/kernel/svm/svm_sepcomb_vector.h51
-rw-r--r--intern/cycles/kernel/svm/svm_sky.h333
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h424
-rw-r--r--intern/cycles/kernel/svm/svm_types.h604
-rw-r--r--intern/cycles/kernel/svm/svm_value.h45
-rw-r--r--intern/cycles/kernel/svm/svm_vector_rotate.h83
-rw-r--r--intern/cycles/kernel/svm/svm_vector_transform.h107
-rw-r--r--intern/cycles/kernel/svm/svm_vertex_color.h80
-rw-r--r--intern/cycles/kernel/svm/svm_voronoi.h1162
-rw-r--r--intern/cycles/kernel/svm/svm_voxel.h53
-rw-r--r--intern/cycles/kernel/svm/svm_wave.h131
-rw-r--r--intern/cycles/kernel/svm/svm_wavelength.h101
-rw-r--r--intern/cycles/kernel/svm/svm_white_noise.h80
-rw-r--r--intern/cycles/kernel/svm/svm_wireframe.h125
-rw-r--r--intern/cycles/kernel/svm/tex_coord.h426
-rw-r--r--intern/cycles/kernel/svm/types.h601
-rw-r--r--intern/cycles/kernel/svm/value.h47
-rw-r--r--intern/cycles/kernel/svm/vector_rotate.h85
-rw-r--r--intern/cycles/kernel/svm/vector_transform.h109
-rw-r--r--intern/cycles/kernel/svm/vertex_color.h82
-rw-r--r--intern/cycles/kernel/svm/voronoi.h1164
-rw-r--r--intern/cycles/kernel/svm/voxel.h55
-rw-r--r--intern/cycles/kernel/svm/wave.h133
-rw-r--r--intern/cycles/kernel/svm/wavelength.h103
-rw-r--r--intern/cycles/kernel/svm/white_noise.h82
-rw-r--r--intern/cycles/kernel/svm/wireframe.h127
-rw-r--r--intern/cycles/kernel/textures.h (renamed from intern/cycles/kernel/kernel_textures.h)0
-rw-r--r--intern/cycles/kernel/types.h1608
-rw-r--r--intern/cycles/kernel/util/color.h35
-rw-r--r--intern/cycles/kernel/util/differential.h (renamed from intern/cycles/kernel/kernel_differential.h)0
-rw-r--r--intern/cycles/kernel/util/lookup_table.h56
-rw-r--r--intern/cycles/kernel/util/profiling.h40
-rw-r--r--intern/cycles/render/CMakeLists.txt180
-rw-r--r--intern/cycles/render/alembic.cpp1431
-rw-r--r--intern/cycles/render/alembic.h568
-rw-r--r--intern/cycles/render/alembic_read.cpp1037
-rw-r--r--intern/cycles/render/alembic_read.h134
-rw-r--r--intern/cycles/render/attribute.cpp896
-rw-r--r--intern/cycles/render/attribute.h287
-rw-r--r--intern/cycles/render/background.cpp140
-rw-r--r--intern/cycles/render/background.h59
-rw-r--r--intern/cycles/render/bake.cpp104
-rw-r--r--intern/cycles/render/bake.h50
-rw-r--r--intern/cycles/render/buffers.cpp384
-rw-r--r--intern/cycles/render/buffers.h199
-rw-r--r--intern/cycles/render/camera.cpp819
-rw-r--r--intern/cycles/render/camera.h236
-rw-r--r--intern/cycles/render/colorspace.cpp398
-rw-r--r--intern/cycles/render/colorspace.h66
-rw-r--r--intern/cycles/render/constant_fold.cpp451
-rw-r--r--intern/cycles/render/constant_fold.h74
-rw-r--r--intern/cycles/render/curves.cpp79
-rw-r--r--intern/cycles/render/curves.h61
-rw-r--r--intern/cycles/render/denoising.cpp934
-rw-r--r--intern/cycles/render/display_driver.h131
-rw-r--r--intern/cycles/render/film.cpp685
-rw-r--r--intern/cycles/render/film.h100
-rw-r--r--intern/cycles/render/geometry.cpp2074
-rw-r--r--intern/cycles/render/geometry.h272
-rw-r--r--intern/cycles/render/graph.cpp1239
-rw-r--r--intern/cycles/render/graph.h385
-rw-r--r--intern/cycles/render/hair.cpp632
-rw-r--r--intern/cycles/render/hair.h164
-rw-r--r--intern/cycles/render/image.cpp905
-rw-r--r--intern/cycles/render/image.h249
-rw-r--r--intern/cycles/render/image_oiio.cpp238
-rw-r--r--intern/cycles/render/image_oiio.h48
-rw-r--r--intern/cycles/render/image_sky.cpp94
-rw-r--r--intern/cycles/render/image_sky.h49
-rw-r--r--intern/cycles/render/image_vdb.cpp249
-rw-r--r--intern/cycles/render/image_vdb.h69
-rw-r--r--intern/cycles/render/integrator.cpp332
-rw-r--r--intern/cycles/render/integrator.h110
-rw-r--r--intern/cycles/render/jitter.cpp281
-rw-r--r--intern/cycles/render/jitter.h29
-rw-r--r--intern/cycles/render/light.cpp1150
-rw-r--r--intern/cycles/render/light.h171
-rw-r--r--intern/cycles/render/merge.cpp516
-rw-r--r--intern/cycles/render/merge.h43
-rw-r--r--intern/cycles/render/mesh.cpp812
-rw-r--r--intern/cycles/render/mesh.h259
-rw-r--r--intern/cycles/render/mesh_displace.cpp410
-rw-r--r--intern/cycles/render/mesh_subdivision.cpp648
-rw-r--r--intern/cycles/render/nodes.cpp7170
-rw-r--r--intern/cycles/render/nodes.h1569
-rw-r--r--intern/cycles/render/object.cpp997
-rw-r--r--intern/cycles/render/object.h193
-rw-r--r--intern/cycles/render/osl.cpp1324
-rw-r--r--intern/cycles/render/osl.h200
-rw-r--r--intern/cycles/render/output_driver.h82
-rw-r--r--intern/cycles/render/particles.cpp149
-rw-r--r--intern/cycles/render/particles.h80
-rw-r--r--intern/cycles/render/pass.cpp422
-rw-r--r--intern/cycles/render/pass.h106
-rw-r--r--intern/cycles/render/procedural.cpp89
-rw-r--r--intern/cycles/render/scene.cpp959
-rw-r--r--intern/cycles/render/scene.h414
-rw-r--r--intern/cycles/render/session.cpp631
-rw-r--r--intern/cycles/render/session.h229
-rw-r--r--intern/cycles/render/shader.cpp885
-rw-r--r--intern/cycles/render/shader.h262
-rw-r--r--intern/cycles/render/sobol.cpp21307
-rw-r--r--intern/cycles/render/sobol.h31
-rw-r--r--intern/cycles/render/stats.cpp382
-rw-r--r--intern/cycles/render/stats.h231
-rw-r--r--intern/cycles/render/svm.cpp999
-rw-r--r--intern/cycles/render/svm.h241
-rw-r--r--intern/cycles/render/tables.cpp130
-rw-r--r--intern/cycles/render/tables.h57
-rw-r--r--intern/cycles/render/tile.cpp629
-rw-r--r--intern/cycles/render/tile.h182
-rw-r--r--intern/cycles/render/volume.cpp635
-rw-r--r--intern/cycles/render/volume.h38
-rw-r--r--intern/cycles/scene/CMakeLists.txt163
-rw-r--r--intern/cycles/scene/alembic.cpp1431
-rw-r--r--intern/cycles/scene/alembic.h568
-rw-r--r--intern/cycles/scene/alembic_read.cpp1037
-rw-r--r--intern/cycles/scene/alembic_read.h134
-rw-r--r--intern/cycles/scene/attribute.cpp896
-rw-r--r--intern/cycles/scene/attribute.h287
-rw-r--r--intern/cycles/scene/background.cpp140
-rw-r--r--intern/cycles/scene/background.h59
-rw-r--r--intern/cycles/scene/bake.cpp104
-rw-r--r--intern/cycles/scene/bake.h50
-rw-r--r--intern/cycles/scene/camera.cpp818
-rw-r--r--intern/cycles/scene/camera.h236
-rw-r--r--intern/cycles/scene/colorspace.cpp398
-rw-r--r--intern/cycles/scene/colorspace.h66
-rw-r--r--intern/cycles/scene/constant_fold.cpp451
-rw-r--r--intern/cycles/scene/constant_fold.h74
-rw-r--r--intern/cycles/scene/curves.cpp79
-rw-r--r--intern/cycles/scene/curves.h61
-rw-r--r--intern/cycles/scene/film.cpp693
-rw-r--r--intern/cycles/scene/film.h100
-rw-r--r--intern/cycles/scene/geometry.cpp2074
-rw-r--r--intern/cycles/scene/geometry.h272
-rw-r--r--intern/cycles/scene/hair.cpp632
-rw-r--r--intern/cycles/scene/hair.h164
-rw-r--r--intern/cycles/scene/image.cpp905
-rw-r--r--intern/cycles/scene/image.h249
-rw-r--r--intern/cycles/scene/image_oiio.cpp238
-rw-r--r--intern/cycles/scene/image_oiio.h48
-rw-r--r--intern/cycles/scene/image_sky.cpp94
-rw-r--r--intern/cycles/scene/image_sky.h49
-rw-r--r--intern/cycles/scene/image_vdb.cpp249
-rw-r--r--intern/cycles/scene/image_vdb.h69
-rw-r--r--intern/cycles/scene/integrator.cpp347
-rw-r--r--intern/cycles/scene/integrator.h114
-rw-r--r--intern/cycles/scene/jitter.cpp281
-rw-r--r--intern/cycles/scene/jitter.h29
-rw-r--r--intern/cycles/scene/light.cpp1150
-rw-r--r--intern/cycles/scene/light.h171
-rw-r--r--intern/cycles/scene/mesh.cpp812
-rw-r--r--intern/cycles/scene/mesh.h259
-rw-r--r--intern/cycles/scene/mesh_displace.cpp410
-rw-r--r--intern/cycles/scene/mesh_subdivision.cpp648
-rw-r--r--intern/cycles/scene/object.cpp984
-rw-r--r--intern/cycles/scene/object.h189
-rw-r--r--intern/cycles/scene/osl.cpp1309
-rw-r--r--intern/cycles/scene/osl.h198
-rw-r--r--intern/cycles/scene/particles.cpp149
-rw-r--r--intern/cycles/scene/particles.h80
-rw-r--r--intern/cycles/scene/pass.cpp427
-rw-r--r--intern/cycles/scene/pass.h106
-rw-r--r--intern/cycles/scene/procedural.cpp88
-rw-r--r--intern/cycles/scene/procedural.h (renamed from intern/cycles/render/procedural.h)0
-rw-r--r--intern/cycles/scene/scene.cpp961
-rw-r--r--intern/cycles/scene/scene.h412
-rw-r--r--intern/cycles/scene/shader.cpp876
-rw-r--r--intern/cycles/scene/shader.h259
-rw-r--r--intern/cycles/scene/shader_graph.cpp1239
-rw-r--r--intern/cycles/scene/shader_graph.h385
-rw-r--r--intern/cycles/scene/shader_nodes.cpp7171
-rw-r--r--intern/cycles/scene/shader_nodes.h1569
-rw-r--r--intern/cycles/scene/sobol.cpp94
-rw-r--r--intern/cycles/scene/sobol.h31
-rw-r--r--intern/cycles/scene/sobol.tables21258
-rw-r--r--intern/cycles/scene/stats.cpp382
-rw-r--r--intern/cycles/scene/stats.h231
-rw-r--r--intern/cycles/scene/svm.cpp984
-rw-r--r--intern/cycles/scene/svm.h238
-rw-r--r--intern/cycles/scene/tables.cpp130
-rw-r--r--intern/cycles/scene/tables.h57
-rw-r--r--intern/cycles/scene/volume.cpp635
-rw-r--r--intern/cycles/scene/volume.h38
-rw-r--r--intern/cycles/session/CMakeLists.txt48
-rw-r--r--intern/cycles/session/buffers.cpp384
-rw-r--r--intern/cycles/session/buffers.h199
-rw-r--r--intern/cycles/session/denoising.cpp934
-rw-r--r--intern/cycles/session/denoising.h (renamed from intern/cycles/render/denoising.h)0
-rw-r--r--intern/cycles/session/display_driver.h131
-rw-r--r--intern/cycles/session/merge.cpp516
-rw-r--r--intern/cycles/session/merge.h43
-rw-r--r--intern/cycles/session/output_driver.h82
-rw-r--r--intern/cycles/session/session.cpp624
-rw-r--r--intern/cycles/session/session.h229
-rw-r--r--intern/cycles/session/tile.cpp635
-rw-r--r--intern/cycles/session/tile.h182
-rw-r--r--intern/cycles/subd/CMakeLists.txt18
-rw-r--r--intern/cycles/subd/dice.cpp283
-rw-r--r--intern/cycles/subd/dice.h103
-rw-r--r--intern/cycles/subd/patch.cpp121
-rw-r--r--intern/cycles/subd/patch.h63
-rw-r--r--intern/cycles/subd/patch_table.cpp295
-rw-r--r--intern/cycles/subd/patch_table.h64
-rw-r--r--intern/cycles/subd/split.cpp748
-rw-r--r--intern/cycles/subd/split.h75
-rw-r--r--intern/cycles/subd/subd_dice.cpp283
-rw-r--r--intern/cycles/subd/subd_dice.h103
-rw-r--r--intern/cycles/subd/subd_patch.cpp121
-rw-r--r--intern/cycles/subd/subd_patch.h63
-rw-r--r--intern/cycles/subd/subd_patch_table.cpp295
-rw-r--r--intern/cycles/subd/subd_patch_table.h64
-rw-r--r--intern/cycles/subd/subd_split.cpp748
-rw-r--r--intern/cycles/subd/subd_split.h75
-rw-r--r--intern/cycles/subd/subd_subpatch.h219
-rw-r--r--intern/cycles/subd/subpatch.h219
-rw-r--r--intern/cycles/test/CMakeLists.txt11
-rw-r--r--intern/cycles/test/integrator_adaptive_sampling_test.cpp2
-rw-r--r--intern/cycles/test/integrator_tile_test.cpp21
-rw-r--r--intern/cycles/test/render_graph_finalize_test.cpp18
-rw-r--r--intern/cycles/test/util_aligned_malloc_test.cpp2
-rw-r--r--intern/cycles/test/util_avxf_test.h4
-rw-r--r--intern/cycles/test/util_math_test.cpp2
-rw-r--r--intern/cycles/test/util_path_test.cpp2
-rw-r--r--intern/cycles/test/util_string_test.cpp2
-rw-r--r--intern/cycles/test/util_task_test.cpp2
-rw-r--r--intern/cycles/test/util_time_test.cpp2
-rw-r--r--intern/cycles/test/util_transform_test.cpp4
-rw-r--r--intern/cycles/util/CMakeLists.txt240
-rw-r--r--intern/cycles/util/algorithm.h (renamed from intern/cycles/util/util_algorithm.h)0
-rw-r--r--intern/cycles/util/aligned_malloc.cpp76
-rw-r--r--intern/cycles/util/aligned_malloc.h50
-rw-r--r--intern/cycles/util/args.h (renamed from intern/cycles/util/util_args.h)0
-rw-r--r--intern/cycles/util/array.h318
-rw-r--r--intern/cycles/util/atomic.h (renamed from intern/cycles/util/util_atomic.h)0
-rw-r--r--intern/cycles/util/avxb.h (renamed from intern/cycles/util/util_avxb.h)0
-rw-r--r--intern/cycles/util/avxf.h (renamed from intern/cycles/util/util_avxf.h)0
-rw-r--r--intern/cycles/util/avxi.h (renamed from intern/cycles/util/util_avxi.h)0
-rw-r--r--intern/cycles/util/boundbox.h282
-rw-r--r--intern/cycles/util/color.h296
-rw-r--r--intern/cycles/util/debug.cpp124
-rw-r--r--intern/cycles/util/debug.h167
-rw-r--r--intern/cycles/util/defines.h151
-rw-r--r--intern/cycles/util/deque.h (renamed from intern/cycles/util/util_deque.h)0
-rw-r--r--intern/cycles/util/disjoint_set.h75
-rw-r--r--intern/cycles/util/foreach.h (renamed from intern/cycles/util/util_foreach.h)0
-rw-r--r--intern/cycles/util/function.h (renamed from intern/cycles/util/util_function.h)0
-rw-r--r--intern/cycles/util/guarded_allocator.cpp48
-rw-r--r--intern/cycles/util/guarded_allocator.h (renamed from intern/cycles/util/util_guarded_allocator.h)0
-rw-r--r--intern/cycles/util/half.h169
-rw-r--r--intern/cycles/util/hash.h389
-rw-r--r--intern/cycles/util/ies.cpp411
-rw-r--r--intern/cycles/util/ies.h59
-rw-r--r--intern/cycles/util/image.h98
-rw-r--r--intern/cycles/util/image_impl.h175
-rw-r--r--intern/cycles/util/list.h (renamed from intern/cycles/util/util_list.h)0
-rw-r--r--intern/cycles/util/log.cpp96
-rw-r--r--intern/cycles/util/log.h (renamed from intern/cycles/util/util_logging.h)0
-rw-r--r--intern/cycles/util/map.h (renamed from intern/cycles/util/util_map.h)0
-rw-r--r--intern/cycles/util/math.h875
-rw-r--r--intern/cycles/util/math_cdf.cpp70
-rw-r--r--intern/cycles/util/math_cdf.h75
-rw-r--r--intern/cycles/util/math_fast.h (renamed from intern/cycles/util/util_math_fast.h)0
-rw-r--r--intern/cycles/util/math_float2.h269
-rw-r--r--intern/cycles/util/math_float3.h530
-rw-r--r--intern/cycles/util/math_float4.h536
-rw-r--r--intern/cycles/util/math_int2.h73
-rw-r--r--intern/cycles/util/math_int3.h110
-rw-r--r--intern/cycles/util/math_int4.h156
-rw-r--r--intern/cycles/util/math_intersect.h (renamed from intern/cycles/util/util_math_intersect.h)0
-rw-r--r--intern/cycles/util/math_matrix.h (renamed from intern/cycles/util/util_math_matrix.h)0
-rw-r--r--intern/cycles/util/md5.cpp387
-rw-r--r--intern/cycles/util/md5.h61
-rw-r--r--intern/cycles/util/murmurhash.cpp126
-rw-r--r--intern/cycles/util/murmurhash.h29
-rw-r--r--intern/cycles/util/opengl.h (renamed from intern/cycles/util/util_opengl.h)0
-rw-r--r--intern/cycles/util/openimagedenoise.h44
-rw-r--r--intern/cycles/util/openvdb.h (renamed from intern/cycles/util/util_openvdb.h)0
-rw-r--r--intern/cycles/util/optimization.h (renamed from intern/cycles/util/util_optimization.h)0
-rw-r--r--intern/cycles/util/param.h (renamed from intern/cycles/util/util_param.h)0
-rw-r--r--intern/cycles/util/path.cpp781
-rw-r--r--intern/cycles/util/path.h74
-rw-r--r--intern/cycles/util/profiling.cpp174
-rw-r--r--intern/cycles/util/profiling.h180
-rw-r--r--intern/cycles/util/progress.h370
-rw-r--r--intern/cycles/util/projection.h217
-rw-r--r--intern/cycles/util/queue.h (renamed from intern/cycles/util/util_queue.h)0
-rw-r--r--intern/cycles/util/rect.h75
-rw-r--r--intern/cycles/util/semaphore.h61
-rw-r--r--intern/cycles/util/set.h (renamed from intern/cycles/util/util_set.h)0
-rw-r--r--intern/cycles/util/simd.cpp44
-rw-r--r--intern/cycles/util/simd.h572
-rw-r--r--intern/cycles/util/sseb.h (renamed from intern/cycles/util/util_sseb.h)0
-rw-r--r--intern/cycles/util/ssef.h1104
-rw-r--r--intern/cycles/util/ssei.h (renamed from intern/cycles/util/util_ssei.h)0
-rw-r--r--intern/cycles/util/stack_allocator.h (renamed from intern/cycles/util/util_stack_allocator.h)0
-rw-r--r--intern/cycles/util/static_assert.h (renamed from intern/cycles/util/util_static_assert.h)0
-rw-r--r--intern/cycles/util/stats.h54
-rw-r--r--intern/cycles/util/string.cpp268
-rw-r--r--intern/cycles/util/string.h81
-rw-r--r--intern/cycles/util/system.cpp415
-rw-r--r--intern/cycles/util/system.h73
-rw-r--r--intern/cycles/util/task.cpp251
-rw-r--r--intern/cycles/util/task.h148
-rw-r--r--intern/cycles/util/tbb.h55
-rw-r--r--intern/cycles/util/texture.h99
-rw-r--r--intern/cycles/util/thread.cpp72
-rw-r--r--intern/cycles/util/thread.h90
-rw-r--r--intern/cycles/util/time.cpp139
-rw-r--r--intern/cycles/util/time.h91
-rw-r--r--intern/cycles/util/transform.cpp345
-rw-r--r--intern/cycles/util/transform.h512
-rw-r--r--intern/cycles/util/types.h138
-rw-r--r--intern/cycles/util/types_float2.h40
-rw-r--r--intern/cycles/util/types_float2_impl.h59
-rw-r--r--intern/cycles/util/types_float3.h60
-rw-r--r--intern/cycles/util/types_float3_impl.h103
-rw-r--r--intern/cycles/util/types_float4.h63
-rw-r--r--intern/cycles/util/types_float4_impl.h109
-rw-r--r--intern/cycles/util/types_float8.h74
-rw-r--r--intern/cycles/util/types_float8_impl.h112
-rw-r--r--intern/cycles/util/types_int2.h39
-rw-r--r--intern/cycles/util/types_int2_impl.h50
-rw-r--r--intern/cycles/util/types_int3.h60
-rw-r--r--intern/cycles/util/types_int3_impl.h104
-rw-r--r--intern/cycles/util/types_int4.h66
-rw-r--r--intern/cycles/util/types_int4_impl.h123
-rw-r--r--intern/cycles/util/types_uchar2.h39
-rw-r--r--intern/cycles/util/types_uchar2_impl.h50
-rw-r--r--intern/cycles/util/types_uchar3.h39
-rw-r--r--intern/cycles/util/types_uchar3_impl.h50
-rw-r--r--intern/cycles/util/types_uchar4.h39
-rw-r--r--intern/cycles/util/types_uchar4_impl.h50
-rw-r--r--intern/cycles/util/types_uint2.h39
-rw-r--r--intern/cycles/util/types_uint2_impl.h48
-rw-r--r--intern/cycles/util/types_uint3.h39
-rw-r--r--intern/cycles/util/types_uint3_impl.h48
-rw-r--r--intern/cycles/util/types_uint4.h39
-rw-r--r--intern/cycles/util/types_uint4_impl.h48
-rw-r--r--intern/cycles/util/types_ushort4.h36
-rw-r--r--intern/cycles/util/types_vector3.h39
-rw-r--r--intern/cycles/util/types_vector3_impl.h43
-rw-r--r--intern/cycles/util/unique_ptr.h (renamed from intern/cycles/util/util_unique_ptr.h)0
-rw-r--r--intern/cycles/util/util_aligned_malloc.cpp76
-rw-r--r--intern/cycles/util/util_aligned_malloc.h50
-rw-r--r--intern/cycles/util/util_array.h318
-rw-r--r--intern/cycles/util/util_boundbox.h282
-rw-r--r--intern/cycles/util/util_color.h296
-rw-r--r--intern/cycles/util/util_debug.cpp124
-rw-r--r--intern/cycles/util/util_debug.h167
-rw-r--r--intern/cycles/util/util_defines.h146
-rw-r--r--intern/cycles/util/util_disjoint_set.h75
-rw-r--r--intern/cycles/util/util_guarded_allocator.cpp48
-rw-r--r--intern/cycles/util/util_half.h169
-rw-r--r--intern/cycles/util/util_hash.h389
-rw-r--r--intern/cycles/util/util_ies.cpp411
-rw-r--r--intern/cycles/util/util_ies.h59
-rw-r--r--intern/cycles/util/util_image.h98
-rw-r--r--intern/cycles/util/util_image_impl.h175
-rw-r--r--intern/cycles/util/util_logging.cpp96
-rw-r--r--intern/cycles/util/util_math.h870
-rw-r--r--intern/cycles/util/util_math_cdf.cpp70
-rw-r--r--intern/cycles/util/util_math_cdf.h75
-rw-r--r--intern/cycles/util/util_math_float2.h269
-rw-r--r--intern/cycles/util/util_math_float3.h530
-rw-r--r--intern/cycles/util/util_math_float4.h536
-rw-r--r--intern/cycles/util/util_math_int2.h73
-rw-r--r--intern/cycles/util/util_math_int3.h110
-rw-r--r--intern/cycles/util/util_math_int4.h156
-rw-r--r--intern/cycles/util/util_md5.cpp387
-rw-r--r--intern/cycles/util/util_md5.h61
-rw-r--r--intern/cycles/util/util_murmurhash.cpp126
-rw-r--r--intern/cycles/util/util_murmurhash.h29
-rw-r--r--intern/cycles/util/util_openimagedenoise.h44
-rw-r--r--intern/cycles/util/util_path.cpp781
-rw-r--r--intern/cycles/util/util_path.h74
-rw-r--r--intern/cycles/util/util_profiling.cpp174
-rw-r--r--intern/cycles/util/util_profiling.h180
-rw-r--r--intern/cycles/util/util_progress.h370
-rw-r--r--intern/cycles/util/util_projection.h217
-rw-r--r--intern/cycles/util/util_rect.h75
-rw-r--r--intern/cycles/util/util_semaphore.h61
-rw-r--r--intern/cycles/util/util_simd.cpp44
-rw-r--r--intern/cycles/util/util_simd.h572
-rw-r--r--intern/cycles/util/util_ssef.h1104
-rw-r--r--intern/cycles/util/util_stats.h54
-rw-r--r--intern/cycles/util/util_string.cpp268
-rw-r--r--intern/cycles/util/util_string.h84
-rw-r--r--intern/cycles/util/util_system.cpp415
-rw-r--r--intern/cycles/util/util_system.h73
-rw-r--r--intern/cycles/util/util_task.cpp251
-rw-r--r--intern/cycles/util/util_task.h148
-rw-r--r--intern/cycles/util/util_tbb.h55
-rw-r--r--intern/cycles/util/util_texture.h99
-rw-r--r--intern/cycles/util/util_thread.cpp72
-rw-r--r--intern/cycles/util/util_thread.h90
-rw-r--r--intern/cycles/util/util_time.cpp139
-rw-r--r--intern/cycles/util/util_time.h91
-rw-r--r--intern/cycles/util/util_transform.cpp345
-rw-r--r--intern/cycles/util/util_transform.h512
-rw-r--r--intern/cycles/util/util_types.h138
-rw-r--r--intern/cycles/util/util_types_float2.h40
-rw-r--r--intern/cycles/util/util_types_float2_impl.h59
-rw-r--r--intern/cycles/util/util_types_float3.h60
-rw-r--r--intern/cycles/util/util_types_float3_impl.h103
-rw-r--r--intern/cycles/util/util_types_float4.h63
-rw-r--r--intern/cycles/util/util_types_float4_impl.h109
-rw-r--r--intern/cycles/util/util_types_float8.h74
-rw-r--r--intern/cycles/util/util_types_float8_impl.h112
-rw-r--r--intern/cycles/util/util_types_int2.h39
-rw-r--r--intern/cycles/util/util_types_int2_impl.h50
-rw-r--r--intern/cycles/util/util_types_int3.h60
-rw-r--r--intern/cycles/util/util_types_int3_impl.h104
-rw-r--r--intern/cycles/util/util_types_int4.h66
-rw-r--r--intern/cycles/util/util_types_int4_impl.h123
-rw-r--r--intern/cycles/util/util_types_uchar2.h39
-rw-r--r--intern/cycles/util/util_types_uchar2_impl.h50
-rw-r--r--intern/cycles/util/util_types_uchar3.h39
-rw-r--r--intern/cycles/util/util_types_uchar3_impl.h50
-rw-r--r--intern/cycles/util/util_types_uchar4.h39
-rw-r--r--intern/cycles/util/util_types_uchar4_impl.h50
-rw-r--r--intern/cycles/util/util_types_uint2.h39
-rw-r--r--intern/cycles/util/util_types_uint2_impl.h48
-rw-r--r--intern/cycles/util/util_types_uint3.h39
-rw-r--r--intern/cycles/util/util_types_uint3_impl.h48
-rw-r--r--intern/cycles/util/util_types_uint4.h39
-rw-r--r--intern/cycles/util/util_types_uint4_impl.h48
-rw-r--r--intern/cycles/util/util_types_ushort4.h36
-rw-r--r--intern/cycles/util/util_types_vector3.h39
-rw-r--r--intern/cycles/util/util_types_vector3_impl.h43
-rw-r--r--intern/cycles/util/util_vector.h59
-rw-r--r--intern/cycles/util/util_view.cpp282
-rw-r--r--intern/cycles/util/util_windows.cpp54
-rw-r--r--intern/cycles/util/vector.h59
-rw-r--r--intern/cycles/util/version.h (renamed from intern/cycles/util/util_version.h)0
-rw-r--r--intern/cycles/util/view.cpp282
-rw-r--r--intern/cycles/util/view.h (renamed from intern/cycles/util/util_view.h)0
-rw-r--r--intern/cycles/util/windows.cpp54
-rw-r--r--intern/cycles/util/windows.h (renamed from intern/cycles/util/util_windows.h)0
-rw-r--r--intern/cycles/util/xml.h (renamed from intern/cycles/util/util_xml.h)0
-rw-r--r--intern/ghost/intern/GHOST_XrSession.cpp26
-rw-r--r--intern/locale/boost_locale_wrapper.cpp7
-rw-r--r--intern/locale/osx_user_locale.mm12
-rw-r--r--make.bat5
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c854
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/modules/rna_prop_ui.py90
-rw-r--r--release/scripts/presets/interface_theme/Blender_Light.xml42
-rw-r--r--release/scripts/presets/keyconfig/Blender.py16
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py530
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py12
-rw-r--r--release/scripts/startup/bl_operators/spreadsheet.py13
-rw-r--r--release/scripts/startup/bl_operators/userpref.py8
-rw-r--r--release/scripts/startup/bl_operators/wm.py85
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py2
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py7
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py264
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py12
-rw-r--r--release/scripts/startup/nodeitems_builtins.py65
-rw-r--r--source/blender/blendthumb/CMakeLists.txt11
-rw-r--r--source/blender/blenfont/intern/blf_font.c142
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c110
-rw-r--r--source/blender/blenfont/intern/blf_internal.h7
-rw-r--r--source/blender/blenkernel/BKE_asset.h17
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh4
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h4
-rw-r--r--source/blender/blenkernel/BKE_curve_to_mesh.hh2
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh33
-rw-r--r--source/blender/blenkernel/BKE_idtype.h5
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h22
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h3
-rw-r--r--source/blender/blenkernel/BKE_main.h4
-rw-r--r--source/blender/blenkernel/BKE_node.h6
-rw-r--r--source/blender/blenkernel/BKE_preferences.h3
-rw-r--r--source/blender/blenkernel/BKE_spline.hh2
-rw-r--r--source/blender/blenkernel/BKE_volume.h5
-rw-r--r--source/blender/blenkernel/BKE_volume_to_mesh.hh32
-rw-r--r--source/blender/blenkernel/intern/action.c4
-rw-r--r--source/blender/blenkernel/intern/anim_data.c6
-rw-r--r--source/blender/blenkernel/intern/appdir.c21
-rw-r--r--source/blender/blenkernel/intern/armature.c20
-rw-r--r--source/blender/blenkernel/intern/armature_test.cc2
-rw-r--r--source/blender/blenkernel/intern/asset.cc25
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_path.cc2
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_path_test.cc40
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_test.cc43
-rw-r--r--source/blender/blenkernel/intern/asset_library_service_test.cc3
-rw-r--r--source/blender/blenkernel/intern/asset_library_test.cc3
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc47
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh4
-rw-r--r--source/blender/blenkernel/intern/brush.c13
-rw-r--r--source/blender/blenkernel/intern/callbacks.c29
-rw-r--r--source/blender/blenkernel/intern/camera.c6
-rw-r--r--source/blender/blenkernel/intern/collection.c9
-rw-r--r--source/blender/blenkernel/intern/curve.c18
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc7
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc63
-rw-r--r--source/blender/blenkernel/intern/fcurve.c16
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc60
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc131
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc2
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc34
-rw-r--r--source/blender/blenkernel/intern/gpencil.c4
-rw-r--r--source/blender/blenkernel/intern/hair.c2
-rw-r--r--source/blender/blenkernel/intern/icons.cc30
-rw-r--r--source/blender/blenkernel/intern/image.c6
-rw-r--r--source/blender/blenkernel/intern/lattice.c2
-rw-r--r--source/blender/blenkernel/intern/lib_query.c158
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c68
-rw-r--r--source/blender/blenkernel/intern/library.c2
-rw-r--r--source/blender/blenkernel/intern/light.c3
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c4
-rw-r--r--source/blender/blenkernel/intern/linestyle.c12
-rw-r--r--source/blender/blenkernel/intern/material.c11
-rw-r--r--source/blender/blenkernel/intern/mball.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c6
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c10
-rw-r--r--source/blender/blenkernel/intern/movieclip.c8
-rw-r--r--source/blender/blenkernel/intern/nla.c6
-rw-r--r--source/blender/blenkernel/intern/node.cc52
-rw-r--r--source/blender/blenkernel/intern/object.c131
-rw-r--r--source/blender/blenkernel/intern/particle.c27
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc2
-rw-r--r--source/blender/blenkernel/intern/preferences.c3
-rw-r--r--source/blender/blenkernel/intern/scene.c350
-rw-r--r--source/blender/blenkernel/intern/screen.c81
-rw-r--r--source/blender/blenkernel/intern/simulation.cc3
-rw-r--r--source/blender/blenkernel/intern/speaker.c2
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc6
-rw-r--r--source/blender/blenkernel/intern/texture.c9
-rw-r--r--source/blender/blenkernel/intern/volume.cc19
-rw-r--r--source/blender/blenkernel/intern/volume_to_mesh.cc93
-rw-r--r--source/blender/blenkernel/intern/workspace.c2
-rw-r--r--source/blender/blenkernel/intern/world.c3
-rw-r--r--source/blender/blenlib/BLI_serialize.hh329
-rw-r--r--source/blender/blenlib/CMakeLists.txt8
-rw-r--r--source/blender/blenlib/intern/noise.cc204
-rw-r--r--source/blender/blenlib/intern/serialize.cc216
-rw-r--r--source/blender/blenlib/intern/winstuff.c2
-rw-r--r--source/blender/blenlib/tests/BLI_serialize_test.cc207
-rw-r--r--source/blender/blenloader/intern/readfile.c3
-rw-r--r--source/blender/blenloader/intern/versioning_280.c55
-rw-r--r--source/blender/blenloader/intern/versioning_290.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c135
-rw-r--r--source/blender/blenloader/intern/versioning_common.cc54
-rw-r--r--source/blender/blenloader/intern/versioning_common.h8
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c35
-rw-r--r--source/blender/draw/CMakeLists.txt1
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c9
-rw-r--r--source/blender/draw/engines/overlay/overlay_grid.c9
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h23
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc3
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c352
-rw-r--r--source/blender/draw/intern/draw_manager_data.c8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.h1
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc398
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc64
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c79
-rw-r--r--source/blender/editors/armature/armature_select.c6
-rw-r--r--source/blender/editors/asset/ED_asset_catalog.hh3
-rw-r--r--source/blender/editors/asset/ED_asset_mark_clear.h3
-rw-r--r--source/blender/editors/asset/ED_asset_type.h5
-rw-r--r--source/blender/editors/asset/intern/asset_catalog.cc35
-rw-r--r--source/blender/editors/asset/intern/asset_mark_clear.cc19
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc9
-rw-r--r--source/blender/editors/asset/intern/asset_type.cc2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c10
-rw-r--r--source/blender/editors/include/ED_fileselect.h6
-rw-r--r--source/blender/editors/include/ED_node.h3
-rw-r--r--source/blender/editors/include/ED_object.h4
-rw-r--r--source/blender/editors/include/ED_screen.h1
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h1
-rw-r--r--source/blender/editors/include/ED_view3d.h5
-rw-r--r--source/blender/editors/include/UI_interface.h34
-rw-r--r--source/blender/editors/include/UI_interface.hh25
-rw-r--r--source/blender/editors/include/UI_tree_view.hh94
-rw-r--r--source/blender/editors/include/UI_view2d.h7
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/interface.c3
-rw-r--r--source/blender/editors/interface/interface_context_path.cc85
-rw-r--r--source/blender/editors/interface/interface_draw.c29
-rw-r--r--source/blender/editors/interface/interface_dropboxes.cc39
-rw-r--r--source/blender/editors/interface/interface_handlers.c128
-rw-r--r--source/blender/editors/interface/interface_intern.h2
-rw-r--r--source/blender/editors/interface/interface_layout.c8
-rw-r--r--source/blender/editors/interface/interface_ops.c34
-rw-r--r--source/blender/editors/interface/interface_panel.c2
-rw-r--r--source/blender/editors/interface/interface_style.c31
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc1
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc7
-rw-r--r--source/blender/editors/interface/interface_widgets.c56
-rw-r--r--source/blender/editors/interface/resources.c7
-rw-r--r--source/blender/editors/interface/tree_view.cc95
-rw-r--r--source/blender/editors/interface/view2d.c111
-rw-r--r--source/blender/editors/interface/view2d_edge_pan.c11
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c63
-rw-r--r--source/blender/editors/mesh/editmesh_select.c8
-rw-r--r--source/blender/editors/object/object_add.c235
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_relations.c24
-rw-r--r--source/blender/editors/object/object_utils.c68
-rw-r--r--source/blender/editors/physics/particle_object.c12
-rw-r--r--source/blender/editors/screen/area.c6
-rw-r--r--source/blender/editors/screen/screen_edit.c4
-rw-r--r--source/blender/editors/screen/screen_ops.c54
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c2
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc259
-rw-r--r--source/blender/editors/space_file/file_draw.c54
-rw-r--r--source/blender/editors/space_file/file_intern.h3
-rw-r--r--source/blender/editors/space_file/file_ops.c32
-rw-r--r--source/blender/editors/space_file/file_panels.c2
-rw-r--r--source/blender/editors/space_file/filelist.c209
-rw-r--r--source/blender/editors/space_file/filesel.c27
-rw-r--r--source/blender/editors/space_file/space_file.c3
-rw-r--r--source/blender/editors/space_nla/nla_draw.c54
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_node/drawnode.cc62
-rw-r--r--source/blender/editors/space_node/node_add.cc14
-rw-r--r--source/blender/editors/space_node/node_context_path.cc184
-rw-r--r--source/blender/editors/space_node/node_draw.cc502
-rw-r--r--source/blender/editors/space_node/node_intern.h10
-rw-r--r--source/blender/editors/space_node/node_ops.c1
-rw-r--r--source/blender/editors/space_node/node_relationships.cc360
-rw-r--r--source/blender/editors/space_node/space_node.c26
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c61
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c16
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c259
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c9
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc66
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cache.cc79
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cache.hh78
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh5
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_context.cc25
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh6
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc333
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh38
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_intern.hh22
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c209
-rw-r--r--source/blender/editors/space_view3d/view3d_cursor_snap.c150
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c21
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c9
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c7
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c11
-rw-r--r--source/blender/editors/transform/transform_snap_object.c7
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c12
-rw-r--r--source/blender/functions/FN_field.hh16
-rw-r--r--source/blender/functions/intern/field.cc7
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencildash.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c75
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h15
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c173
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c48
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c4
-rw-r--r--source/blender/gpu/GPU_batch.h8
-rw-r--r--source/blender/gpu/GPU_immediate_util.h8
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c38
-rw-r--r--source/blender/makesdna/DNA_asset_types.h7
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h7
-rw-r--r--source/blender/makesdna/DNA_lineart_types.h2
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h4
-rw-r--r--source/blender/makesdna/DNA_node_types.h10
-rw-r--r--source/blender/makesdna/DNA_object_types.h3
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h6
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h9
-rw-r--r--source/blender/makesdna/DNA_xr_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_asset.c42
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c6
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c42
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c72
-rw-r--r--source/blender/makesrna/intern/rna_space.c34
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c8
-rw-r--r--source/blender/makesrna/intern/rna_world.c1
-rw-r--r--source/blender/makesrna/intern/rna_xr.c102
-rw-r--r--source/blender/modifiers/intern/MOD_fluid.c44
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc9
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc1
-rw-r--r--source/blender/nodes/CMakeLists.txt10
-rw-r--r--source/blender/nodes/NOD_geometry.h26
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh16
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh25
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh28
-rw-r--r--source/blender/nodes/NOD_socket_declarations.hh10
-rw-r--r--source/blender/nodes/NOD_socket_declarations_geometry.hh58
-rw-r--r--source/blender/nodes/NOD_static_types.h36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehimage.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.cc8
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_composite.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.cc13
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_exposure.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_gamma.cc11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc16
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_idMask.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_invert.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_levels.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mask.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_movieclip.cc12
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_premulkey.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rgb.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_setalpha.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_texture.cc8
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_tonemap.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_trackpos.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_valToRgb.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_value.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_viewer.cc6
-rw-r--r--source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc8
-rw-r--r--source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc12
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc6
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_compare.cc8
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_bool.cc2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_color.cc2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_int.cc2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_special_characters.cc4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_string.cc2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_vector.cc2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc26
-rw-r--r--source/blender/nodes/function/nodes/node_fn_replace_string.cc9
-rw-r--r--source/blender/nodes/function/nodes/node_fn_rotate_euler.cc10
-rw-r--r--source/blender/nodes/function/nodes/node_fn_slice_string.cc8
-rw-r--r--source/blender/nodes/function/nodes/node_fn_string_length.cc4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_value_to_string.cc6
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh1
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc173
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collection_info.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc38
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc21
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc40
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_image_texture.cc429
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_id.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_index.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_normal.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_position.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_radius.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc49
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_replace.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_proximity.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc59
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc57
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_components.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc94
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_join.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc89
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc57
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc63
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc137
-rw-r--r--source/blender/nodes/intern/extern_implementations.cc1
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc63
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc71
-rw-r--r--source/blender/nodes/intern/node_socket_declarations.cc41
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc135
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc16
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc16
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.cc198
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.cc12
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.cc10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.cc16
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc505
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.cc18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.cc10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.cc12
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc12
-rw-r--r--source/blender/python/generic/bl_math_py_api.c30
-rw-r--r--source/blender/sequencer/SEQ_iterator.h5
-rw-r--r--source/blender/sequencer/SEQ_time.h2
-rw-r--r--source/blender/sequencer/intern/effects.c11
-rw-r--r--source/blender/sequencer/intern/iterator.c26
-rw-r--r--source/blender/sequencer/intern/strip_time.c31
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_api.h30
-rw-r--r--source/blender/windowmanager/WM_types.h33
-rw-r--r--source/blender/windowmanager/intern/wm.c11
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c449
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c4
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c22
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c59
-rw-r--r--source/blender/windowmanager/intern/wm_files.c5
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c11
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c1
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c88
-rw-r--r--source/blender/windowmanager/wm_event_system.h4
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_draw.c45
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h21
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_operators.c1537
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c187
-rw-r--r--source/blender/windowmanager/xr/wm_xr.h3
-rw-r--r--source/creator/CMakeLists.txt7
m---------source/tools0
-rwxr-xr-xtests/performance/benchmark16
1496 files changed, 141509 insertions, 132157 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 558e1545c4d..62e7d9b2941 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,7 +30,7 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
"CMake generation for blender is not allowed within the source directory!"
"\n Remove \"${CMAKE_SOURCE_DIR}/CMakeCache.txt\" and try again from another folder, e.g.:"
"\n "
- "\n rm CMakeCache.txt"
+ "\n rm -rf CMakeCache.txt CMakeFiles"
"\n cd .."
"\n mkdir cmake-make"
"\n cd cmake-make"
@@ -160,8 +160,7 @@ if(APPLE)
# Currently this causes a build error linking, disable.
set(WITH_BLENDER_THUMBNAILER OFF)
elseif(WIN32)
- # Building the thumbnail extraction DLL could be made optional.
- set(WITH_BLENDER_THUMBNAILER ON)
+ option(WITH_BLENDER_THUMBNAILER "Build \"BlendThumb.dll\" helper for Windows explorer integration" ON)
else()
option(WITH_BLENDER_THUMBNAILER "Build \"blender-thumbnailer\" thumbnail extraction utility" ON)
endif()
diff --git a/build_files/windows/parse_arguments.cmd b/build_files/windows/parse_arguments.cmd
index c63f062dfef..dcef46c2c9a 100644
--- a/build_files/windows/parse_arguments.cmd
+++ b/build_files/windows/parse_arguments.cmd
@@ -116,6 +116,9 @@ if NOT "%1" == "" (
) else if "%1" == "doc_py" (
set DOC_PY=1
goto EOF
+ ) else if "%1" == "svnfix" (
+ set SVN_FIX=1
+ goto EOF
) else (
echo Command "%1" unknown, aborting!
goto ERR
diff --git a/build_files/windows/svn_fix.cmd b/build_files/windows/svn_fix.cmd
new file mode 100644
index 00000000000..a9dcdf36847
--- /dev/null
+++ b/build_files/windows/svn_fix.cmd
@@ -0,0 +1,26 @@
+if "%BUILD_VS_YEAR%"=="2017" set BUILD_VS_LIBDIRPOST=vc15
+if "%BUILD_VS_YEAR%"=="2019" set BUILD_VS_LIBDIRPOST=vc15
+if "%BUILD_VS_YEAR%"=="2022" set BUILD_VS_LIBDIRPOST=vc15
+
+set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST%
+set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%"
+
+echo Starting cleanup in %BUILD_VS_LIBDIR%.
+cd %BUILD_VS_LIBDIR%
+:RETRY
+"%SVN%" cleanup
+"%SVN%" update
+if errorlevel 1 (
+ set /p LibRetry= "Error during update, retry? y/n"
+ if /I "!LibRetry!"=="Y" (
+ goto RETRY
+ )
+ echo.
+ echo Error: Download of external libraries failed.
+ echo This is needed for building, please manually run 'svn cleanup' and 'svn update' in
+ echo %BUILD_VS_LIBDIR% , until this is resolved you CANNOT make a successful blender build
+ echo.
+ exit /b 1
+)
+echo Cleanup complete
+
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index 96eb30a852e..89954d8a155 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = V3.0
+PROJECT_NUMBER = V3.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index afc84834dd1..04efe49f778 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -1108,7 +1108,9 @@ context_type_map = {
"selected_editable_keyframes": ("Keyframe", True),
"selected_editable_objects": ("Object", True),
"selected_editable_sequences": ("Sequence", True),
+ "selected_ids": ("ID", True),
"selected_files": ("FileSelectEntry", True),
+ "selected_ids": ("ID", True),
"selected_nla_strips": ("NlaStrip", True),
"selected_movieclip_tracks": ("MovieTrackingTrack", True),
"selected_nodes": ("Node", True),
@@ -1222,7 +1224,10 @@ def pycontext2sphinx(basepath):
while char_array[i] is not None:
member = ctypes.string_at(char_array[i]).decode(encoding="ascii")
fw(".. data:: %s\n\n" % member)
- member_type, is_seq = context_type_map[member]
+ try:
+ member_type, is_seq = context_type_map[member]
+ except KeyError:
+ raise SystemExit("Error: context key %r not found in context_type_map; update %s" % (member, __file__)) from None
fw(" :type: %s :class:`bpy.types.%s`\n\n" % ("sequence of " if is_seq else "", member_type))
unique.add(member)
i += 1
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index 2018c1d9648..1500743763b 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -295,13 +295,6 @@ if(WITH_OPENIMAGEDENOISE)
)
endif()
-if(WITH_CYCLES_STANDALONE)
- set(WITH_CYCLES_DEVICE_CUDA TRUE)
- set(WITH_CYCLES_DEVICE_HIP TRUE)
-endif()
-# TODO(sergey): Consider removing it, only causes confusion in interface.
-set(WITH_CYCLES_DEVICE_MULTI TRUE)
-
# Logging capabilities using GLog library.
if(WITH_CYCLES_LOGGING)
add_definitions(-DWITH_CYCLES_LOGGING)
@@ -400,7 +393,8 @@ add_subdirectory(doc)
add_subdirectory(graph)
add_subdirectory(integrator)
add_subdirectory(kernel)
-add_subdirectory(render)
+add_subdirectory(scene)
+add_subdirectory(session)
add_subdirectory(subd)
add_subdirectory(util)
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt
index 3ed3f54ef9f..50600793854 100644
--- a/intern/cycles/app/CMakeLists.txt
+++ b/intern/cycles/app/CMakeLists.txt
@@ -25,7 +25,8 @@ set(INC_SYS
set(LIBRARIES
cycles_device
cycles_kernel
- cycles_render
+ cycles_scene
+ cycles_session
cycles_bvh
cycles_subd
cycles_graph
diff --git a/intern/cycles/app/cycles_server.cpp b/intern/cycles/app/cycles_server.cpp
index 1ad70a376ed..38771b8aed8 100644
--- a/intern/cycles/app/cycles_server.cpp
+++ b/intern/cycles/app/cycles_server.cpp
@@ -18,13 +18,13 @@
#include "device/device.h"
-#include "util/util_args.h"
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_path.h"
-#include "util/util_stats.h"
-#include "util/util_string.h"
-#include "util/util_task.h"
+#include "util/args.h"
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/path.h"
+#include "util/stats.h"
+#include "util/string.h"
+#include "util/task.h"
using namespace ccl;
diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp
index 00dc140648a..0032938b116 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -17,30 +17,30 @@
#include <stdio.h>
#include "device/device.h"
-#include "render/buffers.h"
-#include "render/camera.h"
-#include "render/integrator.h"
-#include "render/scene.h"
-#include "render/session.h"
-
-#include "util/util_args.h"
-#include "util/util_foreach.h"
-#include "util/util_function.h"
-#include "util/util_image.h"
-#include "util/util_logging.h"
-#include "util/util_path.h"
-#include "util/util_progress.h"
-#include "util/util_string.h"
-#include "util/util_time.h"
-#include "util/util_transform.h"
-#include "util/util_unique_ptr.h"
-#include "util/util_version.h"
+#include "scene/camera.h"
+#include "scene/integrator.h"
+#include "scene/scene.h"
+#include "session/buffers.h"
+#include "session/session.h"
+
+#include "util/args.h"
+#include "util/foreach.h"
+#include "util/function.h"
+#include "util/image.h"
+#include "util/log.h"
+#include "util/path.h"
+#include "util/progress.h"
+#include "util/string.h"
+#include "util/time.h"
+#include "util/transform.h"
+#include "util/unique_ptr.h"
+#include "util/version.h"
#include "app/cycles_xml.h"
#include "app/oiio_output_driver.h"
#ifdef WITH_CYCLES_STANDALONE_GUI
-# include "util/util_view.h"
+# include "util/view.h"
#endif
#include "app/cycles_xml.h"
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 0b83c60f32d..6144d2c60a9 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -22,27 +22,27 @@
#include "graph/node_xml.h"
-#include "render/background.h"
-#include "render/camera.h"
-#include "render/film.h"
-#include "render/graph.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/nodes.h"
-#include "render/object.h"
-#include "render/osl.h"
-#include "render/scene.h"
-#include "render/shader.h"
-
-#include "subd/subd_patch.h"
-#include "subd/subd_split.h"
-
-#include "util/util_foreach.h"
-#include "util/util_path.h"
-#include "util/util_projection.h"
-#include "util/util_transform.h"
-#include "util/util_xml.h"
+#include "scene/background.h"
+#include "scene/camera.h"
+#include "scene/film.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/osl.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+
+#include "subd/patch.h"
+#include "subd/split.h"
+
+#include "util/foreach.h"
+#include "util/path.h"
+#include "util/projection.h"
+#include "util/transform.h"
+#include "util/xml.h"
#include "app/cycles_xml.h"
diff --git a/intern/cycles/app/oiio_output_driver.h b/intern/cycles/app/oiio_output_driver.h
index cdc4085d962..a5c88e0e890 100644
--- a/intern/cycles/app/oiio_output_driver.h
+++ b/intern/cycles/app/oiio_output_driver.h
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-#include "render/output_driver.h"
+#include "session/output_driver.h"
-#include "util/util_function.h"
-#include "util/util_image.h"
-#include "util/util_string.h"
-#include "util/util_unique_ptr.h"
-#include "util/util_vector.h"
+#include "util/function.h"
+#include "util/image.h"
+#include "util/string.h"
+#include "util/unique_ptr.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index a0442b3394b..149967ad331 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -29,39 +29,39 @@ set(INC_SYS
)
set(SRC
- blender_camera.cpp
- blender_device.cpp
- blender_display_driver.cpp
- blender_image.cpp
- blender_geometry.cpp
- blender_light.cpp
- blender_mesh.cpp
- blender_object.cpp
- blender_object_cull.cpp
- blender_output_driver.cpp
- blender_particles.cpp
- blender_curves.cpp
- blender_logging.cpp
- blender_python.cpp
- blender_session.cpp
- blender_shader.cpp
- blender_sync.cpp
- blender_texture.cpp
- blender_viewport.cpp
- blender_volume.cpp
+ camera.cpp
+ device.cpp
+ display_driver.cpp
+ image.cpp
+ geometry.cpp
+ light.cpp
+ mesh.cpp
+ object.cpp
+ object_cull.cpp
+ output_driver.cpp
+ particles.cpp
+ curves.cpp
+ logging.cpp
+ python.cpp
+ session.cpp
+ shader.cpp
+ sync.cpp
+ texture.cpp
+ viewport.cpp
+ volume.cpp
CCL_api.h
- blender_device.h
- blender_display_driver.h
- blender_id_map.h
- blender_image.h
- blender_object_cull.h
- blender_output_driver.h
- blender_sync.h
- blender_session.h
- blender_texture.h
- blender_util.h
- blender_viewport.h
+ device.h
+ display_driver.h
+ id_map.h
+ image.h
+ object_cull.h
+ output_driver.h
+ sync.h
+ session.h
+ texture.h
+ util.h
+ viewport.h
)
set(LIB
@@ -69,7 +69,8 @@ set(LIB
cycles_device
cycles_graph
cycles_kernel
- cycles_render
+ cycles_scene
+ cycles_session
cycles_subd
cycles_util
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 2a51e0be2a4..1e98e6d0a7c 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -125,6 +125,11 @@ enum_texture_limit = (
('8192', "8192", "Limit texture size to 8192 pixels", 7),
)
+enum_fast_gi_method = (
+ ('REPLACE', "Replace", "Replace global illumination with ambient occlusion after a specified number of bounces"),
+ ('ADD', "Add", "Add ambient occlusion to diffuse surfaces"),
+)
+
# NOTE: Identifiers are expected to be an upper case version of identifiers from `Pass::get_type_enum()`
enum_view3d_shading_render_pass = (
('', "General", ""),
@@ -337,6 +342,24 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default='PROGRESSIVE_MUTI_JITTER',
)
+ scrambling_distance: FloatProperty(
+ name="Scrambling Distance",
+ default=1.0,
+ min=0.0, max=1.0,
+ description="Lower values give faster rendering with GPU rendering and less noise with all devices at the cost of possible artifacts if set too low. Only works when not using adaptive sampling",
+ )
+ preview_scrambling_distance: BoolProperty(
+ name="Scrambling Distance viewport",
+ default=False,
+ description="Uses the Scrambling Distance value for the viewport. Faster but may flicker",
+ )
+
+ adaptive_scrambling_distance: BoolProperty(
+ name="Adaptive Scrambling Distance",
+ default=False,
+ description="Uses a formula to adapt the scrambling distance strength based on the sample count",
+ )
+
use_layer_samples: EnumProperty(
name="Layer Samples",
description="How to use per view layer sample settings",
@@ -724,6 +747,14 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Approximate diffuse indirect light with background tinted ambient occlusion. This provides fast alternative to full global illumination, for interactive viewport rendering or final renders with reduced quality",
default=False,
)
+
+ fast_gi_method: EnumProperty(
+ name="Fast GI Method",
+ default='REPLACE',
+ description="Fast GI approximation method",
+ items=enum_fast_gi_method
+ )
+
ao_bounces: IntProperty(
name="AO Bounces",
default=1,
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 0ed2dd24f2e..0c9179b4ccf 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -287,12 +287,22 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
row.prop(cscene, "use_animated_seed", text="", icon='TIME')
col = layout.column(align=True)
- col.active = not(cscene.use_adaptive_sampling)
+ col.active = not (cscene.use_adaptive_sampling and cscene.use_preview_adaptive_sampling)
col.prop(cscene, "sampling_pattern", text="Pattern")
layout.separator()
col = layout.column(align=True)
+ col.active = not (cscene.use_adaptive_sampling and cscene.use_preview_adaptive_sampling)
+ col.prop(cscene, "scrambling_distance", text="Scrambling Distance")
+ col.prop(cscene, "adaptive_scrambling_distance", text="Adaptive")
+ sub = col.row(align=True)
+ sub.active = not cscene.use_preview_adaptive_sampling
+ sub.prop(cscene, "preview_scrambling_distance", text="Viewport")
+
+ layout.separator()
+
+ col = layout.column(align=True)
col.prop(cscene, "min_light_bounces")
col.prop(cscene, "min_transparent_bounces")
col.prop(cscene, "light_sampling_threshold", text="Light Threshold")
@@ -465,8 +475,7 @@ class CYCLES_RENDER_PT_light_paths_fast_gi(CyclesButtonsPanel, Panel):
layout.active = cscene.use_fast_gi
col = layout.column(align=True)
- col.prop(cscene, "ao_bounces", text="Viewport Bounces")
- col.prop(cscene, "ao_bounces_render", text="Render Bounces")
+ col.prop(cscene, "fast_gi_method", text="Method")
if world:
light = world.light_settings
@@ -474,6 +483,11 @@ class CYCLES_RENDER_PT_light_paths_fast_gi(CyclesButtonsPanel, Panel):
col.prop(light, "ao_factor", text="AO Factor")
col.prop(light, "distance", text="AO Distance")
+ if cscene.fast_gi_method == 'REPLACE':
+ col = layout.column(align=True)
+ col.prop(cscene, "ao_bounces", text="Viewport Bounces")
+ col.prop(cscene, "ao_bounces_render", text="Render Bounces")
+
class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel):
bl_label = "Motion Blur"
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
deleted file mode 100644
index 52acc2573f5..00000000000
--- a/intern/cycles/blender/blender_camera.cpp
+++ /dev/null
@@ -1,965 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/camera.h"
-#include "render/scene.h"
-
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-#include "util/util_logging.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Blender Camera Intermediate: we first convert both the offline and 3d view
- * render camera to this, and from there convert to our native camera format. */
-
-struct BlenderCamera {
- float nearclip;
- float farclip;
-
- CameraType type;
- float ortho_scale;
-
- float lens;
- float shuttertime;
- Camera::MotionPosition motion_position;
- array<float> shutter_curve;
-
- Camera::RollingShutterType rolling_shutter_type;
- float rolling_shutter_duration;
-
- float aperturesize;
- uint apertureblades;
- float aperturerotation;
- float focaldistance;
-
- float2 shift;
- float2 offset;
- float zoom;
-
- float2 pixelaspect;
-
- float aperture_ratio;
-
- PanoramaType panorama_type;
- float fisheye_fov;
- float fisheye_lens;
- float latitude_min;
- float latitude_max;
- float longitude_min;
- float longitude_max;
- bool use_spherical_stereo;
- float interocular_distance;
- float convergence_distance;
- bool use_pole_merge;
- float pole_merge_angle_from;
- float pole_merge_angle_to;
-
- enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
- float sensor_width;
- float sensor_height;
-
- int full_width;
- int full_height;
-
- int render_width;
- int render_height;
-
- BoundBox2D border;
- BoundBox2D viewport_camera_border;
- BoundBox2D pano_viewplane;
- float pano_aspectratio;
-
- float passepartout_alpha;
-
- Transform matrix;
-
- float offscreen_dicing_scale;
-
- int motion_steps;
-};
-
-static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings &b_render)
-{
- memset((void *)bcam, 0, sizeof(BlenderCamera));
-
- bcam->nearclip = 1e-5f;
- bcam->farclip = 1e5f;
-
- bcam->type = CAMERA_PERSPECTIVE;
- bcam->ortho_scale = 1.0f;
-
- bcam->lens = 50.0f;
- bcam->shuttertime = 1.0f;
-
- bcam->rolling_shutter_type = Camera::ROLLING_SHUTTER_NONE;
- bcam->rolling_shutter_duration = 0.1f;
-
- bcam->aperturesize = 0.0f;
- bcam->apertureblades = 0;
- bcam->aperturerotation = 0.0f;
- bcam->focaldistance = 10.0f;
-
- bcam->zoom = 1.0f;
- bcam->pixelaspect = one_float2();
- bcam->aperture_ratio = 1.0f;
-
- bcam->sensor_width = 36.0f;
- bcam->sensor_height = 24.0f;
- bcam->sensor_fit = BlenderCamera::AUTO;
- bcam->motion_position = Camera::MOTION_POSITION_CENTER;
- bcam->border.right = 1.0f;
- bcam->border.top = 1.0f;
- bcam->viewport_camera_border.right = 1.0f;
- bcam->viewport_camera_border.top = 1.0f;
- bcam->pano_viewplane.right = 1.0f;
- bcam->pano_viewplane.top = 1.0f;
- bcam->pano_aspectratio = 0.0f;
- bcam->passepartout_alpha = 0.5f;
- bcam->offscreen_dicing_scale = 1.0f;
- bcam->matrix = transform_identity();
-
- /* render resolution */
- bcam->render_width = render_resolution_x(b_render);
- bcam->render_height = render_resolution_y(b_render);
- bcam->full_width = bcam->render_width;
- bcam->full_height = bcam->render_height;
-}
-
-static float blender_camera_focal_distance(BL::RenderEngine &b_engine,
- BL::Object &b_ob,
- BL::Camera &b_camera,
- BlenderCamera *bcam)
-{
- BL::Object b_dof_object = b_camera.dof().focus_object();
-
- if (!b_dof_object)
- return b_camera.dof().focus_distance();
-
- /* for dof object, return distance along camera Z direction */
- BL::Array<float, 16> b_ob_matrix;
- b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix);
- Transform obmat = transform_clear_scale(get_transform(b_ob_matrix));
- Transform dofmat = get_transform(b_dof_object.matrix_world());
- float3 view_dir = normalize(transform_get_column(&obmat, 2));
- float3 dof_dir = transform_get_column(&obmat, 3) - transform_get_column(&dofmat, 3);
- return fabsf(dot(view_dir, dof_dir));
-}
-
-static void blender_camera_from_object(BlenderCamera *bcam,
- BL::RenderEngine &b_engine,
- BL::Object &b_ob,
- bool skip_panorama = false)
-{
- BL::ID b_ob_data = b_ob.data();
-
- if (b_ob_data.is_a(&RNA_Camera)) {
- BL::Camera b_camera(b_ob_data);
- PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
-
- bcam->nearclip = b_camera.clip_start();
- bcam->farclip = b_camera.clip_end();
-
- switch (b_camera.type()) {
- case BL::Camera::type_ORTHO:
- bcam->type = CAMERA_ORTHOGRAPHIC;
- break;
- case BL::Camera::type_PANO:
- if (!skip_panorama)
- bcam->type = CAMERA_PANORAMA;
- else
- bcam->type = CAMERA_PERSPECTIVE;
- break;
- case BL::Camera::type_PERSP:
- default:
- bcam->type = CAMERA_PERSPECTIVE;
- break;
- }
-
- bcam->panorama_type = (PanoramaType)get_enum(
- ccamera, "panorama_type", PANORAMA_NUM_TYPES, PANORAMA_EQUIRECTANGULAR);
-
- bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov");
- bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens");
- bcam->latitude_min = RNA_float_get(&ccamera, "latitude_min");
- bcam->latitude_max = RNA_float_get(&ccamera, "latitude_max");
- bcam->longitude_min = RNA_float_get(&ccamera, "longitude_min");
- bcam->longitude_max = RNA_float_get(&ccamera, "longitude_max");
-
- bcam->interocular_distance = b_camera.stereo().interocular_distance();
- if (b_camera.stereo().convergence_mode() == BL::CameraStereoData::convergence_mode_PARALLEL) {
- bcam->convergence_distance = FLT_MAX;
- }
- else {
- bcam->convergence_distance = b_camera.stereo().convergence_distance();
- }
- bcam->use_spherical_stereo = b_engine.use_spherical_stereo(b_ob);
-
- bcam->use_pole_merge = b_camera.stereo().use_pole_merge();
- bcam->pole_merge_angle_from = b_camera.stereo().pole_merge_angle_from();
- bcam->pole_merge_angle_to = b_camera.stereo().pole_merge_angle_to();
-
- bcam->ortho_scale = b_camera.ortho_scale();
-
- bcam->lens = b_camera.lens();
-
- bcam->passepartout_alpha = b_camera.show_passepartout() ? b_camera.passepartout_alpha() : 0.0f;
-
- if (b_camera.dof().use_dof()) {
- /* allow f/stop number to change aperture_size but still
- * give manual control over aperture radius */
- float fstop = b_camera.dof().aperture_fstop();
- fstop = max(fstop, 1e-5f);
-
- if (bcam->type == CAMERA_ORTHOGRAPHIC)
- bcam->aperturesize = 1.0f / (2.0f * fstop);
- else
- bcam->aperturesize = (bcam->lens * 1e-3f) / (2.0f * fstop);
-
- bcam->apertureblades = b_camera.dof().aperture_blades();
- bcam->aperturerotation = b_camera.dof().aperture_rotation();
- bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam);
- bcam->aperture_ratio = b_camera.dof().aperture_ratio();
- }
- else {
- /* DOF is turned of for the camera. */
- bcam->aperturesize = 0.0f;
- bcam->apertureblades = 0;
- bcam->aperturerotation = 0.0f;
- bcam->focaldistance = 0.0f;
- bcam->aperture_ratio = 1.0f;
- }
-
- bcam->shift.x = b_engine.camera_shift_x(b_ob, bcam->use_spherical_stereo);
- bcam->shift.y = b_camera.shift_y();
-
- bcam->sensor_width = b_camera.sensor_width();
- bcam->sensor_height = b_camera.sensor_height();
-
- if (b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO)
- bcam->sensor_fit = BlenderCamera::AUTO;
- else if (b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL)
- bcam->sensor_fit = BlenderCamera::HORIZONTAL;
- else
- bcam->sensor_fit = BlenderCamera::VERTICAL;
- }
- else if (b_ob_data.is_a(&RNA_Light)) {
- /* Can also look through spot light. */
- BL::SpotLight b_light(b_ob_data);
- float lens = 16.0f / tanf(b_light.spot_size() * 0.5f);
- if (lens > 0.0f) {
- bcam->lens = lens;
- }
- }
-
- bcam->motion_steps = object_motion_steps(b_ob, b_ob);
-}
-
-static Transform blender_camera_matrix(const Transform &tfm,
- const CameraType type,
- const PanoramaType panorama_type)
-{
- Transform result;
-
- if (type == CAMERA_PANORAMA) {
- if (panorama_type == PANORAMA_MIRRORBALL) {
- /* Mirror ball camera is looking into the negative Y direction
- * which matches texture mirror ball mapping.
- */
- result = tfm * make_transform(
- 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
- }
- else {
- /* Make it so environment camera needs to be pointed in the direction
- * of the positive x-axis to match an environment texture, this way
- * it is looking at the center of the texture
- */
- result = tfm * make_transform(
- 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f);
- }
- }
- else {
- /* note the blender camera points along the negative z-axis */
- result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
- }
-
- return transform_clear_scale(result);
-}
-
-static void blender_camera_viewplane(BlenderCamera *bcam,
- int width,
- int height,
- BoundBox2D *viewplane,
- float *aspectratio,
- float *sensor_size)
-{
- /* dimensions */
- float xratio = (float)width * bcam->pixelaspect.x;
- float yratio = (float)height * bcam->pixelaspect.y;
-
- /* compute x/y aspect and ratio */
- float xaspect, yaspect;
- bool horizontal_fit;
-
- /* sensor fitting */
- if (bcam->sensor_fit == BlenderCamera::AUTO) {
- horizontal_fit = (xratio > yratio);
- if (sensor_size != NULL) {
- *sensor_size = bcam->sensor_width;
- }
- }
- else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
- horizontal_fit = true;
- if (sensor_size != NULL) {
- *sensor_size = bcam->sensor_width;
- }
- }
- else {
- horizontal_fit = false;
- if (sensor_size != NULL) {
- *sensor_size = bcam->sensor_height;
- }
- }
-
- if (horizontal_fit) {
- if (aspectratio != NULL) {
- *aspectratio = xratio / yratio;
- }
- xaspect = *aspectratio;
- yaspect = 1.0f;
- }
- else {
- if (aspectratio != NULL) {
- *aspectratio = yratio / xratio;
- }
- xaspect = 1.0f;
- yaspect = *aspectratio;
- }
-
- /* modify aspect for orthographic scale */
- if (bcam->type == CAMERA_ORTHOGRAPHIC) {
- xaspect = xaspect * bcam->ortho_scale / (*aspectratio * 2.0f);
- yaspect = yaspect * bcam->ortho_scale / (*aspectratio * 2.0f);
- if (aspectratio != NULL) {
- *aspectratio = bcam->ortho_scale / 2.0f;
- }
- }
-
- if (bcam->type == CAMERA_PANORAMA) {
- /* Set viewplane for panoramic camera. */
- if (viewplane != NULL) {
- *viewplane = bcam->pano_viewplane;
-
- /* Modify viewplane for camera shift. */
- const float shift_factor = (bcam->pano_aspectratio == 0.0f) ?
- 1.0f :
- *aspectratio / bcam->pano_aspectratio;
- const float dx = bcam->shift.x * shift_factor;
- const float dy = bcam->shift.y * shift_factor;
-
- viewplane->left += dx;
- viewplane->right += dx;
- viewplane->bottom += dy;
- viewplane->top += dy;
- }
- }
- else {
- /* set viewplane */
- if (viewplane != NULL) {
- viewplane->left = -xaspect;
- viewplane->right = xaspect;
- viewplane->bottom = -yaspect;
- viewplane->top = yaspect;
-
- /* zoom for 3d camera view */
- *viewplane = (*viewplane) * bcam->zoom;
-
- /* modify viewplane with camera shift and 3d camera view offset */
- const float dx = 2.0f * (*aspectratio * bcam->shift.x + bcam->offset.x * xaspect * 2.0f);
- const float dy = 2.0f * (*aspectratio * bcam->shift.y + bcam->offset.y * yaspect * 2.0f);
-
- viewplane->left += dx;
- viewplane->right += dx;
- viewplane->bottom += dy;
- viewplane->top += dy;
- }
- }
-}
-
-static void blender_camera_sync(Camera *cam,
- BlenderCamera *bcam,
- int width,
- int height,
- const char *viewname,
- PointerRNA *cscene)
-{
- float aspectratio, sensor_size;
-
- /* viewplane */
- BoundBox2D viewplane;
- blender_camera_viewplane(bcam, width, height, &viewplane, &aspectratio, &sensor_size);
-
- cam->set_viewplane_left(viewplane.left);
- cam->set_viewplane_right(viewplane.right);
- cam->set_viewplane_top(viewplane.top);
- cam->set_viewplane_bottom(viewplane.bottom);
-
- cam->set_full_width(width);
- cam->set_full_height(height);
-
- /* panorama sensor */
- if (bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) {
- float fit_xratio = (float)bcam->render_width * bcam->pixelaspect.x;
- float fit_yratio = (float)bcam->render_height * bcam->pixelaspect.y;
- bool horizontal_fit;
- float sensor_size;
-
- if (bcam->sensor_fit == BlenderCamera::AUTO) {
- horizontal_fit = (fit_xratio > fit_yratio);
- sensor_size = bcam->sensor_width;
- }
- else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
- horizontal_fit = true;
- sensor_size = bcam->sensor_width;
- }
- else { /* vertical */
- horizontal_fit = false;
- sensor_size = bcam->sensor_height;
- }
-
- if (horizontal_fit) {
- cam->set_sensorwidth(sensor_size);
- cam->set_sensorheight(sensor_size * fit_yratio / fit_xratio);
- }
- else {
- cam->set_sensorwidth(sensor_size * fit_xratio / fit_yratio);
- cam->set_sensorheight(sensor_size);
- }
- }
-
- /* clipping distances */
- cam->set_nearclip(bcam->nearclip);
- cam->set_farclip(bcam->farclip);
-
- /* type */
- cam->set_camera_type(bcam->type);
-
- /* panorama */
- cam->set_panorama_type(bcam->panorama_type);
- cam->set_fisheye_fov(bcam->fisheye_fov);
- cam->set_fisheye_lens(bcam->fisheye_lens);
- cam->set_latitude_min(bcam->latitude_min);
- cam->set_latitude_max(bcam->latitude_max);
-
- cam->set_longitude_min(bcam->longitude_min);
- cam->set_longitude_max(bcam->longitude_max);
-
- /* panorama stereo */
- cam->set_interocular_distance(bcam->interocular_distance);
- cam->set_convergence_distance(bcam->convergence_distance);
- cam->set_use_spherical_stereo(bcam->use_spherical_stereo);
-
- if (cam->get_use_spherical_stereo()) {
- if (strcmp(viewname, "left") == 0)
- cam->set_stereo_eye(Camera::STEREO_LEFT);
- else if (strcmp(viewname, "right") == 0)
- cam->set_stereo_eye(Camera::STEREO_RIGHT);
- else
- cam->set_stereo_eye(Camera::STEREO_NONE);
- }
-
- cam->set_use_pole_merge(bcam->use_pole_merge);
- cam->set_pole_merge_angle_from(bcam->pole_merge_angle_from);
- cam->set_pole_merge_angle_to(bcam->pole_merge_angle_to);
-
- /* anamorphic lens bokeh */
- cam->set_aperture_ratio(bcam->aperture_ratio);
-
- /* perspective */
- cam->set_fov(2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio));
- cam->set_focaldistance(bcam->focaldistance);
- cam->set_aperturesize(bcam->aperturesize);
- cam->set_blades(bcam->apertureblades);
- cam->set_bladesrotation(bcam->aperturerotation);
-
- /* transform */
- cam->set_matrix(blender_camera_matrix(bcam->matrix, bcam->type, bcam->panorama_type));
-
- array<Transform> motion;
- motion.resize(bcam->motion_steps, cam->get_matrix());
- cam->set_motion(motion);
- cam->set_use_perspective_motion(false);
-
- cam->set_shuttertime(bcam->shuttertime);
- cam->set_fov_pre(cam->get_fov());
- cam->set_fov_post(cam->get_fov());
- cam->set_motion_position(bcam->motion_position);
-
- cam->set_rolling_shutter_type(bcam->rolling_shutter_type);
- cam->set_rolling_shutter_duration(bcam->rolling_shutter_duration);
-
- cam->set_shutter_curve(bcam->shutter_curve);
-
- /* border */
- cam->set_border_left(bcam->border.left);
- cam->set_border_right(bcam->border.right);
- cam->set_border_top(bcam->border.top);
- cam->set_border_bottom(bcam->border.bottom);
-
- cam->set_viewport_camera_border_left(bcam->viewport_camera_border.left);
- cam->set_viewport_camera_border_right(bcam->viewport_camera_border.right);
- cam->set_viewport_camera_border_top(bcam->viewport_camera_border.top);
- cam->set_viewport_camera_border_bottom(bcam->viewport_camera_border.bottom);
-
- bcam->offscreen_dicing_scale = RNA_float_get(cscene, "offscreen_dicing_scale");
- cam->set_offscreen_dicing_scale(bcam->offscreen_dicing_scale);
-}
-
-/* Sync Render Camera */
-
-void BlenderSync::sync_camera(BL::RenderSettings &b_render,
- BL::Object &b_override,
- int width,
- int height,
- const char *viewname)
-{
- BlenderCamera bcam;
- blender_camera_init(&bcam, b_render);
-
- /* pixel aspect */
- bcam.pixelaspect.x = b_render.pixel_aspect_x();
- bcam.pixelaspect.y = b_render.pixel_aspect_y();
- bcam.shuttertime = b_render.motion_blur_shutter();
-
- BL::CurveMapping b_shutter_curve(b_render.motion_blur_shutter_curve());
- curvemapping_to_array(b_shutter_curve, bcam.shutter_curve, RAMP_TABLE_SIZE);
-
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- bcam.motion_position = (Camera::MotionPosition)get_enum(cscene,
- "motion_blur_position",
- Camera::MOTION_NUM_POSITIONS,
- Camera::MOTION_POSITION_CENTER);
- bcam.rolling_shutter_type = (Camera::RollingShutterType)get_enum(
- cscene,
- "rolling_shutter_type",
- Camera::ROLLING_SHUTTER_NUM_TYPES,
- Camera::ROLLING_SHUTTER_NONE);
- bcam.rolling_shutter_duration = RNA_float_get(&cscene, "rolling_shutter_duration");
-
- /* border */
- if (b_render.use_border()) {
- bcam.border.left = b_render.border_min_x();
- bcam.border.right = b_render.border_max_x();
- bcam.border.bottom = b_render.border_min_y();
- bcam.border.top = b_render.border_max_y();
- }
-
- /* camera object */
- BL::Object b_ob = b_scene.camera();
-
- if (b_override)
- b_ob = b_override;
-
- if (b_ob) {
- BL::Array<float, 16> b_ob_matrix;
- blender_camera_from_object(&bcam, b_engine, b_ob);
- b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
- bcam.matrix = get_transform(b_ob_matrix);
- }
-
- /* sync */
- Camera *cam = scene->camera;
- blender_camera_sync(cam, &bcam, width, height, viewname, &cscene);
-
- /* dicing camera */
- b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
- if (b_ob) {
- BL::Array<float, 16> b_ob_matrix;
- blender_camera_from_object(&bcam, b_engine, b_ob);
- b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
- bcam.matrix = get_transform(b_ob_matrix);
-
- blender_camera_sync(scene->dicing_camera, &bcam, width, height, viewname, &cscene);
- }
- else {
- *scene->dicing_camera = *cam;
- }
-}
-
-void BlenderSync::sync_camera_motion(
- BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time)
-{
- if (!b_ob)
- return;
-
- Camera *cam = scene->camera;
- BL::Array<float, 16> b_ob_matrix;
- b_engine.camera_model_matrix(b_ob, cam->get_use_spherical_stereo(), b_ob_matrix);
- Transform tfm = get_transform(b_ob_matrix);
- tfm = blender_camera_matrix(tfm, cam->get_camera_type(), cam->get_panorama_type());
-
- if (motion_time == 0.0f) {
- /* When motion blur is not centered in frame, cam->matrix gets reset. */
- cam->set_matrix(tfm);
- }
-
- /* Set transform in motion array. */
- int motion_step = cam->motion_step(motion_time);
- if (motion_step >= 0) {
- array<Transform> motion = cam->get_motion();
- motion[motion_step] = tfm;
- cam->set_motion(motion);
- }
-
- if (cam->get_camera_type() == CAMERA_PERSPECTIVE) {
- BlenderCamera bcam;
- float aspectratio, sensor_size;
- blender_camera_init(&bcam, b_render);
-
- /* TODO(sergey): Consider making it a part of blender_camera_init(). */
- bcam.pixelaspect.x = b_render.pixel_aspect_x();
- bcam.pixelaspect.y = b_render.pixel_aspect_y();
-
- blender_camera_from_object(&bcam, b_engine, b_ob);
- blender_camera_viewplane(&bcam, width, height, NULL, &aspectratio, &sensor_size);
- /* TODO(sergey): De-duplicate calculation with camera sync. */
- float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio);
- if (fov != cam->get_fov()) {
- VLOG(1) << "Camera " << b_ob.name() << " FOV change detected.";
- if (motion_time == 0.0f) {
- cam->set_fov(fov);
- }
- else if (motion_time == -1.0f) {
- cam->set_fov_pre(fov);
- cam->set_use_perspective_motion(true);
- }
- else if (motion_time == 1.0f) {
- cam->set_fov_post(fov);
- cam->set_use_perspective_motion(true);
- }
- }
- }
-}
-
-/* Sync 3D View Camera */
-
-static void blender_camera_view_subset(BL::RenderEngine &b_engine,
- BL::RenderSettings &b_render,
- BL::Scene &b_scene,
- BL::Object &b_ob,
- BL::SpaceView3D &b_v3d,
- BL::RegionView3D &b_rv3d,
- int width,
- int height,
- BoundBox2D *view_box,
- BoundBox2D *cam_box,
- float *view_aspect);
-
-static void blender_camera_from_view(BlenderCamera *bcam,
- BL::RenderEngine &b_engine,
- BL::Scene &b_scene,
- BL::SpaceView3D &b_v3d,
- BL::RegionView3D &b_rv3d,
- int width,
- int height,
- bool skip_panorama = false)
-{
- /* 3d view parameters */
- bcam->nearclip = b_v3d.clip_start();
- bcam->farclip = b_v3d.clip_end();
- bcam->lens = b_v3d.lens();
- bcam->shuttertime = b_scene.render().motion_blur_shutter();
-
- BL::CurveMapping b_shutter_curve(b_scene.render().motion_blur_shutter_curve());
- curvemapping_to_array(b_shutter_curve, bcam->shutter_curve, RAMP_TABLE_SIZE);
-
- if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
- /* camera view */
- BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera();
-
- if (b_ob) {
- blender_camera_from_object(bcam, b_engine, b_ob, skip_panorama);
-
- if (!skip_panorama && bcam->type == CAMERA_PANORAMA) {
- /* in panorama camera view, we map viewplane to camera border */
- BoundBox2D view_box, cam_box;
- float view_aspect;
-
- BL::RenderSettings b_render_settings(b_scene.render());
- blender_camera_view_subset(b_engine,
- b_render_settings,
- b_scene,
- b_ob,
- b_v3d,
- b_rv3d,
- width,
- height,
- &view_box,
- &cam_box,
- &view_aspect);
-
- bcam->pano_viewplane = view_box.make_relative_to(cam_box);
- bcam->pano_aspectratio = view_aspect;
- }
- else {
- /* magic zoom formula */
- bcam->zoom = (float)b_rv3d.view_camera_zoom();
- bcam->zoom = (1.41421f + bcam->zoom / 50.0f);
- bcam->zoom *= bcam->zoom;
- bcam->zoom = 2.0f / bcam->zoom;
-
- /* offset */
- bcam->offset = get_float2(b_rv3d.view_camera_offset());
- }
- }
- }
- else if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
- /* orthographic view */
- bcam->farclip *= 0.5f;
- bcam->nearclip = -bcam->farclip;
-
- float sensor_size;
- if (bcam->sensor_fit == BlenderCamera::VERTICAL)
- sensor_size = bcam->sensor_height;
- else
- sensor_size = bcam->sensor_width;
-
- bcam->type = CAMERA_ORTHOGRAPHIC;
- bcam->ortho_scale = b_rv3d.view_distance() * sensor_size / b_v3d.lens();
- }
-
- bcam->zoom *= 2.0f;
-
- /* 3d view transform */
- bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
-
- /* dimensions */
- bcam->full_width = width;
- bcam->full_height = height;
-}
-
-static void blender_camera_view_subset(BL::RenderEngine &b_engine,
- BL::RenderSettings &b_render,
- BL::Scene &b_scene,
- BL::Object &b_ob,
- BL::SpaceView3D &b_v3d,
- BL::RegionView3D &b_rv3d,
- int width,
- int height,
- BoundBox2D *view_box,
- BoundBox2D *cam_box,
- float *view_aspect)
-{
- BoundBox2D cam, view;
- float cam_aspect, sensor_size;
-
- /* Get viewport viewplane. */
- BlenderCamera view_bcam;
- blender_camera_init(&view_bcam, b_render);
- blender_camera_from_view(&view_bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height, true);
-
- blender_camera_viewplane(&view_bcam, width, height, &view, view_aspect, &sensor_size);
-
- /* Get camera viewplane. */
- BlenderCamera cam_bcam;
- blender_camera_init(&cam_bcam, b_render);
- blender_camera_from_object(&cam_bcam, b_engine, b_ob, true);
-
- /* Camera border is affect by aspect, viewport is not. */
- cam_bcam.pixelaspect.x = b_render.pixel_aspect_x();
- cam_bcam.pixelaspect.y = b_render.pixel_aspect_y();
-
- blender_camera_viewplane(
- &cam_bcam, cam_bcam.full_width, cam_bcam.full_height, &cam, &cam_aspect, &sensor_size);
-
- /* Return */
- *view_box = view * (1.0f / *view_aspect);
- *cam_box = cam * (1.0f / cam_aspect);
-}
-
-static void blender_camera_border_subset(BL::RenderEngine &b_engine,
- BL::RenderSettings &b_render,
- BL::Scene &b_scene,
- BL::SpaceView3D &b_v3d,
- BL::RegionView3D &b_rv3d,
- BL::Object &b_ob,
- int width,
- int height,
- const BoundBox2D &border,
- BoundBox2D *result)
-{
- /* Determine camera viewport subset. */
- BoundBox2D view_box, cam_box;
- float view_aspect;
- blender_camera_view_subset(b_engine,
- b_render,
- b_scene,
- b_ob,
- b_v3d,
- b_rv3d,
- width,
- height,
- &view_box,
- &cam_box,
- &view_aspect);
-
- /* Determine viewport subset matching given border. */
- cam_box = cam_box.make_relative_to(view_box);
- *result = cam_box.subset(border);
-}
-
-static void blender_camera_border(BlenderCamera *bcam,
- BL::RenderEngine &b_engine,
- BL::RenderSettings &b_render,
- BL::Scene &b_scene,
- BL::SpaceView3D &b_v3d,
- BL::RegionView3D &b_rv3d,
- int width,
- int height)
-{
- bool is_camera_view;
-
- /* camera view? */
- is_camera_view = b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA;
-
- if (!is_camera_view) {
- /* for non-camera view check whether render border is enabled for viewport
- * and if so use border from 3d viewport
- * assume viewport has got correctly clamped border already
- */
- if (b_v3d.use_render_border()) {
- bcam->border.left = b_v3d.render_border_min_x();
- bcam->border.right = b_v3d.render_border_max_x();
- bcam->border.bottom = b_v3d.render_border_min_y();
- bcam->border.top = b_v3d.render_border_max_y();
- }
- return;
- }
-
- BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera();
-
- if (!b_ob)
- return;
-
- /* Determine camera border inside the viewport. */
- BoundBox2D full_border;
- blender_camera_border_subset(b_engine,
- b_render,
- b_scene,
- b_v3d,
- b_rv3d,
- b_ob,
- width,
- height,
- full_border,
- &bcam->viewport_camera_border);
-
- if (b_render.use_border()) {
- bcam->border.left = b_render.border_min_x();
- bcam->border.right = b_render.border_max_x();
- bcam->border.bottom = b_render.border_min_y();
- bcam->border.top = b_render.border_max_y();
- }
- else if (bcam->passepartout_alpha == 1.0f) {
- bcam->border = full_border;
- }
- else {
- return;
- }
-
- /* Determine viewport subset matching camera border. */
- blender_camera_border_subset(b_engine,
- b_render,
- b_scene,
- b_v3d,
- b_rv3d,
- b_ob,
- width,
- height,
- bcam->border,
- &bcam->border);
- bcam->border = bcam->border.clamp();
-}
-
-void BlenderSync::sync_view(BL::SpaceView3D &b_v3d,
- BL::RegionView3D &b_rv3d,
- int width,
- int height)
-{
- BlenderCamera bcam;
- BL::RenderSettings b_render_settings(b_scene.render());
- blender_camera_init(&bcam, b_render_settings);
- blender_camera_from_view(&bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height);
- blender_camera_border(&bcam, b_engine, b_render_settings, b_scene, b_v3d, b_rv3d, width, height);
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- blender_camera_sync(scene->camera, &bcam, width, height, "", &cscene);
-
- /* dicing camera */
- BL::Object b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
- if (b_ob) {
- BL::Array<float, 16> b_ob_matrix;
- blender_camera_from_object(&bcam, b_engine, b_ob);
- b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
- bcam.matrix = get_transform(b_ob_matrix);
-
- blender_camera_sync(scene->dicing_camera, &bcam, width, height, "", &cscene);
- }
- else {
- *scene->dicing_camera = *scene->camera;
- }
-}
-
-BufferParams BlenderSync::get_buffer_params(
- BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height)
-{
- BufferParams params;
- bool use_border = false;
-
- params.full_width = width;
- params.full_height = height;
-
- if (b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA)
- use_border = b_v3d.use_render_border();
- else
- /* the camera can always have a passepartout */
- use_border = true;
-
- if (use_border) {
- /* border render */
- /* the viewport may offset the border outside the view */
- BoundBox2D border = cam->border.clamp();
- params.full_x = (int)(border.left * (float)width);
- params.full_y = (int)(border.bottom * (float)height);
- params.width = (int)(border.right * (float)width) - params.full_x;
- params.height = (int)(border.top * (float)height) - params.full_y;
-
- /* survive in case border goes out of view or becomes too small */
- params.width = max(params.width, 1);
- params.height = max(params.height, 1);
- }
- else {
- params.width = width;
- params.height = height;
- }
-
- params.window_width = params.width;
- params.window_height = params.height;
-
- return params;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
deleted file mode 100644
index b6b4f206620..00000000000
--- a/intern/cycles/blender/blender_curves.cpp
+++ /dev/null
@@ -1,914 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/attribute.h"
-#include "render/camera.h"
-#include "render/curves.h"
-#include "render/hair.h"
-#include "render/object.h"
-#include "render/scene.h"
-
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-#include "util/util_logging.h"
-
-CCL_NAMESPACE_BEGIN
-
-ParticleCurveData::ParticleCurveData()
-{
-}
-
-ParticleCurveData::~ParticleCurveData()
-{
-}
-
-static float shaperadius(float shape, float root, float tip, float time)
-{
- assert(time >= 0.0f);
- assert(time <= 1.0f);
- float radius = 1.0f - time;
-
- if (shape != 0.0f) {
- if (shape < 0.0f)
- radius = powf(radius, 1.0f + shape);
- else
- radius = powf(radius, 1.0f / (1.0f - shape));
- }
- return (radius * (root - tip)) + tip;
-}
-
-/* curve functions */
-
-static bool ObtainCacheParticleData(
- Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
-{
- int curvenum = 0;
- int keyno = 0;
-
- if (!(hair && b_mesh && b_ob && CData))
- return false;
-
- Transform tfm = get_transform(b_ob->matrix_world());
- Transform itfm = transform_quick_inverse(tfm);
-
- for (BL::Modifier &b_mod : b_ob->modifiers) {
- if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
- (background ? b_mod.show_render() : b_mod.show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
-
- if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
- (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int shader = clamp(b_part.material() - 1, 0, hair->get_used_shaders().size() - 1);
- int display_step = background ? b_part.render_step() : b_part.display_step();
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() :
- (int)((float)b_psys.child_particles.length() *
- (float)b_part.display_percentage() / 100.0f);
- int totcurves = totchild;
-
- if (b_part.child_type() == 0 || totchild == 0)
- totcurves += totparts;
-
- if (totcurves == 0)
- continue;
-
- int ren_step = (1 << display_step) + 1;
- if (b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
- ren_step += b_part.kink_extra_steps();
-
- CData->psys_firstcurve.push_back_slow(curvenum);
- CData->psys_curvenum.push_back_slow(totcurves);
- CData->psys_shader.push_back_slow(shader);
-
- float radius = b_part.radius_scale() * 0.5f;
-
- CData->psys_rootradius.push_back_slow(radius * b_part.root_radius());
- CData->psys_tipradius.push_back_slow(radius * b_part.tip_radius());
- CData->psys_shape.push_back_slow(b_part.shape());
- CData->psys_closetip.push_back_slow(b_part.use_close_tip());
-
- int pa_no = 0;
- if (!(b_part.child_type() == 0) && totchild != 0)
- pa_no = totparts;
-
- int num_add = (totparts + totchild - pa_no);
- CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
- CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
- CData->curve_length.reserve(CData->curve_length.size() + num_add);
- CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add * ren_step);
- CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add * ren_step);
-
- for (; pa_no < totparts + totchild; pa_no++) {
- int keynum = 0;
- CData->curve_firstkey.push_back_slow(keyno);
-
- float curve_length = 0.0f;
- float3 prev_co_world = zero_float3();
- float3 prev_co_object = zero_float3();
- for (int step_no = 0; step_no < ren_step; step_no++) {
- float3 co_world = prev_co_world;
- b_psys.co_hair(*b_ob, pa_no, step_no, &co_world.x);
- float3 co_object = transform_point(&itfm, co_world);
- if (step_no > 0) {
- const float step_length = len(co_object - prev_co_object);
- curve_length += step_length;
- }
- CData->curvekey_co.push_back_slow(co_object);
- CData->curvekey_time.push_back_slow(curve_length);
- prev_co_object = co_object;
- prev_co_world = co_world;
- keynum++;
- }
- keyno += keynum;
-
- CData->curve_keynum.push_back_slow(keynum);
- CData->curve_length.push_back_slow(curve_length);
- curvenum++;
- }
- }
- }
- }
-
- return true;
-}
-
-static bool ObtainCacheParticleUV(Hair *hair,
- BL::Mesh *b_mesh,
- BL::Object *b_ob,
- ParticleCurveData *CData,
- bool background,
- int uv_num)
-{
- if (!(hair && b_mesh && b_ob && CData))
- return false;
-
- CData->curve_uv.clear();
-
- for (BL::Modifier &b_mod : b_ob->modifiers) {
- if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
- (background ? b_mod.show_render() : b_mod.show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
-
- if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
- (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() :
- (int)((float)b_psys.child_particles.length() *
- (float)b_part.display_percentage() / 100.0f);
- int totcurves = totchild;
-
- if (b_part.child_type() == 0 || totchild == 0)
- totcurves += totparts;
-
- if (totcurves == 0)
- continue;
-
- int pa_no = 0;
- if (!(b_part.child_type() == 0) && totchild != 0)
- pa_no = totparts;
-
- int num_add = (totparts + totchild - pa_no);
- CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
-
- BL::ParticleSystem::particles_iterator b_pa;
- b_psys.particles.begin(b_pa);
- for (; pa_no < totparts + totchild; pa_no++) {
- /* Add UVs */
- BL::Mesh::uv_layers_iterator l;
- b_mesh->uv_layers.begin(l);
-
- float2 uv = zero_float2();
- if (b_mesh->uv_layers.length())
- b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
- CData->curve_uv.push_back_slow(uv);
-
- if (pa_no < totparts && b_pa != b_psys.particles.end())
- ++b_pa;
- }
- }
- }
- }
-
- return true;
-}
-
-static bool ObtainCacheParticleVcol(Hair *hair,
- BL::Mesh *b_mesh,
- BL::Object *b_ob,
- ParticleCurveData *CData,
- bool background,
- int vcol_num)
-{
- if (!(hair && b_mesh && b_ob && CData))
- return false;
-
- CData->curve_vcol.clear();
-
- for (BL::Modifier &b_mod : b_ob->modifiers) {
- if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
- (background ? b_mod.show_render() : b_mod.show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
-
- if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
- (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() :
- (int)((float)b_psys.child_particles.length() *
- (float)b_part.display_percentage() / 100.0f);
- int totcurves = totchild;
-
- if (b_part.child_type() == 0 || totchild == 0)
- totcurves += totparts;
-
- if (totcurves == 0)
- continue;
-
- int pa_no = 0;
- if (!(b_part.child_type() == 0) && totchild != 0)
- pa_no = totparts;
-
- int num_add = (totparts + totchild - pa_no);
- CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
-
- BL::ParticleSystem::particles_iterator b_pa;
- b_psys.particles.begin(b_pa);
- for (; pa_no < totparts + totchild; pa_no++) {
- /* Add vertex colors */
- BL::Mesh::vertex_colors_iterator l;
- b_mesh->vertex_colors.begin(l);
-
- float4 vcol = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
- if (b_mesh->vertex_colors.length())
- b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
- CData->curve_vcol.push_back_slow(vcol);
-
- if (pa_no < totparts && b_pa != b_psys.particles.end())
- ++b_pa;
- }
- }
- }
- }
-
- return true;
-}
-
-static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CData)
-{
- int num_keys = 0;
- int num_curves = 0;
-
- if (hair->num_curves())
- return;
-
- Attribute *attr_intercept = NULL;
- Attribute *attr_length = NULL;
- Attribute *attr_random = NULL;
-
- if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
- attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
- if (hair->need_attribute(scene, ATTR_STD_CURVE_LENGTH))
- attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH);
- if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM))
- attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
-
- /* compute and reserve size of arrays */
- for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
- for (int curve = CData->psys_firstcurve[sys];
- curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
- curve++) {
- num_keys += CData->curve_keynum[curve];
- num_curves++;
- }
- }
-
- if (num_curves > 0) {
- VLOG(1) << "Exporting curve segments for mesh " << hair->name;
- }
-
- hair->reserve_curves(hair->num_curves() + num_curves, hair->get_curve_keys().size() + num_keys);
-
- num_keys = 0;
- num_curves = 0;
-
- /* actually export */
- for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
- for (int curve = CData->psys_firstcurve[sys];
- curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
- curve++) {
- size_t num_curve_keys = 0;
-
- for (int curvekey = CData->curve_firstkey[curve];
- curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve];
- curvekey++) {
- const float3 ickey_loc = CData->curvekey_co[curvekey];
- const float curve_time = CData->curvekey_time[curvekey];
- const float curve_length = CData->curve_length[curve];
- const float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
- float radius = shaperadius(
- CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
- if (CData->psys_closetip[sys] &&
- (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) {
- radius = 0.0f;
- }
- hair->add_curve_key(ickey_loc, radius);
- if (attr_intercept)
- attr_intercept->add(time);
-
- num_curve_keys++;
- }
-
- if (attr_length != NULL) {
- attr_length->add(CData->curve_length[curve]);
- }
-
- if (attr_random != NULL) {
- attr_random->add(hash_uint2_to_float(num_curves, 0));
- }
-
- hair->add_curve(num_keys, CData->psys_shader[sys]);
- num_keys += num_curve_keys;
- num_curves++;
- }
- }
-
- /* check allocation */
- if ((hair->get_curve_keys().size() != num_keys) || (hair->num_curves() != num_curves)) {
- VLOG(1) << "Allocation failed, clearing data";
- hair->clear(true);
- }
-}
-
-static float4 CurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, int curvekey)
-{
- const float3 ickey_loc = CData->curvekey_co[curvekey];
- const float curve_time = CData->curvekey_time[curvekey];
- const float curve_length = CData->curve_length[curve];
- float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
- float radius = shaperadius(
- CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
-
- if (CData->psys_closetip[sys] &&
- (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
- radius = 0.0f;
-
- /* curve motion keys store both position and radius in float4 */
- float4 mP = float3_to_float4(ickey_loc);
- mP.w = radius;
- return mP;
-}
-
-static float4 LerpCurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, float step)
-{
- assert(step >= 0.0f);
- assert(step <= 1.0f);
- const int first_curve_key = CData->curve_firstkey[curve];
- const float curve_key_f = step * (CData->curve_keynum[curve] - 1);
- int curvekey = (int)floorf(curve_key_f);
- const float remainder = curve_key_f - curvekey;
- if (remainder == 0.0f) {
- return CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey);
- }
- int curvekey2 = curvekey + 1;
- if (curvekey2 >= (CData->curve_keynum[curve] - 1)) {
- curvekey2 = (CData->curve_keynum[curve] - 1);
- curvekey = curvekey2 - 1;
- }
- const float4 mP = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey);
- const float4 mP2 = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey2);
- return lerp(mP, mP2, remainder);
-}
-
-static void export_hair_motion_validate_attribute(Hair *hair,
- int motion_step,
- int num_motion_keys,
- bool have_motion)
-{
- Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- const int num_keys = hair->get_curve_keys().size();
-
- if (num_motion_keys != num_keys || !have_motion) {
- /* No motion or hair "topology" changed, remove attributes again. */
- if (num_motion_keys != num_keys) {
- VLOG(1) << "Hair topology changed, removing attribute.";
- }
- else {
- VLOG(1) << "No motion, removing attribute.";
- }
- hair->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
- }
- else if (motion_step > 0) {
- VLOG(1) << "Filling in new motion vertex position for motion_step " << motion_step;
-
- /* Motion, fill up previous steps that we might have skipped because
- * they had no motion, but we need them anyway now. */
- for (int step = 0; step < motion_step; step++) {
- float4 *mP = attr_mP->data_float4() + step * num_keys;
-
- for (int key = 0; key < num_keys; key++) {
- mP[key] = float3_to_float4(hair->get_curve_keys()[key]);
- mP[key].w = hair->get_curve_radius()[key];
- }
- }
- }
-}
-
-static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int motion_step)
-{
- VLOG(1) << "Exporting curve motion segments for hair " << hair->name << ", motion step "
- << motion_step;
-
- /* find attribute */
- Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- bool new_attribute = false;
-
- /* add new attribute if it doesn't exist already */
- if (!attr_mP) {
- VLOG(1) << "Creating new motion vertex position attribute";
- attr_mP = hair->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
- new_attribute = true;
- }
-
- /* export motion vectors for curve keys */
- size_t numkeys = hair->get_curve_keys().size();
- float4 *mP = attr_mP->data_float4() + motion_step * numkeys;
- bool have_motion = false;
- int i = 0;
- int num_curves = 0;
-
- for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
- for (int curve = CData->psys_firstcurve[sys];
- curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
- curve++) {
- /* Curve lengths may not match! Curves can be clipped. */
- int curve_key_end = (num_curves + 1 < (int)hair->get_curve_first_key().size() ?
- hair->get_curve_first_key()[num_curves + 1] :
- (int)hair->get_curve_keys().size());
- const int num_center_curve_keys = curve_key_end - hair->get_curve_first_key()[num_curves];
- const int is_num_keys_different = CData->curve_keynum[curve] - num_center_curve_keys;
-
- if (!is_num_keys_different) {
- for (int curvekey = CData->curve_firstkey[curve];
- curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve];
- curvekey++) {
- if (i < hair->get_curve_keys().size()) {
- mP[i] = CurveSegmentMotionCV(CData, sys, curve, curvekey);
- if (!have_motion) {
- /* unlike mesh coordinates, these tend to be slightly different
- * between frames due to particle transforms into/out of object
- * space, so we use an epsilon to detect actual changes */
- float4 curve_key = float3_to_float4(hair->get_curve_keys()[i]);
- curve_key.w = hair->get_curve_radius()[i];
- if (len_squared(mP[i] - curve_key) > 1e-5f * 1e-5f)
- have_motion = true;
- }
- }
- i++;
- }
- }
- else {
- /* Number of keys has changed. Generate an interpolated version
- * to preserve motion blur. */
- const float step_size = num_center_curve_keys > 1 ? 1.0f / (num_center_curve_keys - 1) :
- 0.0f;
- for (int step_index = 0; step_index < num_center_curve_keys; ++step_index) {
- const float step = step_index * step_size;
- mP[i] = LerpCurveSegmentMotionCV(CData, sys, curve, step);
- i++;
- }
- have_motion = true;
- }
- num_curves++;
- }
- }
-
- /* In case of new attribute, we verify if there really was any motion. */
- if (new_attribute) {
- export_hair_motion_validate_attribute(hair, motion_step, i, have_motion);
- }
-}
-
-/* Hair Curve Sync */
-
-bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
-{
- /* Test if the object has a particle modifier with hair. */
- for (BL::Modifier &b_mod : b_ob.modifiers) {
- if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
- (preview ? b_mod.show_viewport() : b_mod.show_render())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
-
- if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
- (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-/* Old particle hair. */
-void BlenderSync::sync_particle_hair(
- Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step)
-{
- if (!b_ob_info.is_real_object_data()) {
- return;
- }
- BL::Object b_ob = b_ob_info.real_object;
-
- /* obtain general settings */
- if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) {
- return;
- }
-
- /* Extract particle hair data - should be combined with connecting to mesh later. */
-
- ParticleCurveData CData;
-
- ObtainCacheParticleData(hair, &b_mesh, &b_ob, &CData, !preview);
-
- /* add hair geometry */
- if (motion)
- ExportCurveSegmentsMotion(hair, &CData, motion_step);
- else
- ExportCurveSegments(scene, hair, &CData);
-
- /* generated coordinates from first key. we should ideally get this from
- * blender to handle deforming objects */
- if (!motion) {
- if (hair->need_attribute(scene, ATTR_STD_GENERATED)) {
- float3 loc, size;
- mesh_texture_space(b_mesh, loc, size);
-
- Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED);
- float3 *generated = attr_generated->data_float3();
-
- for (size_t i = 0; i < hair->num_curves(); i++) {
- float3 co = hair->get_curve_keys()[hair->get_curve(i).first_key];
- generated[i] = co * size - loc;
- }
- }
- }
-
- /* create vertex color attributes */
- if (!motion) {
- BL::Mesh::vertex_colors_iterator l;
- int vcol_num = 0;
-
- for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l, vcol_num++) {
- if (!hair->need_attribute(scene, ustring(l->name().c_str())))
- continue;
-
- ObtainCacheParticleVcol(hair, &b_mesh, &b_ob, &CData, !preview, vcol_num);
-
- Attribute *attr_vcol = hair->attributes.add(
- ustring(l->name().c_str()), TypeRGBA, ATTR_ELEMENT_CURVE);
-
- float4 *fdata = attr_vcol->data_float4();
-
- if (fdata) {
- size_t i = 0;
-
- /* Encode vertex color using the sRGB curve. */
- for (size_t curve = 0; curve < CData.curve_vcol.size(); curve++) {
- fdata[i++] = color_srgb_to_linear_v4(CData.curve_vcol[curve]);
- }
- }
- }
- }
-
- /* create UV attributes */
- if (!motion) {
- BL::Mesh::uv_layers_iterator l;
- int uv_num = 0;
-
- for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, uv_num++) {
- bool active_render = l->active_render();
- AttributeStandard std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
- ustring name = ustring(l->name().c_str());
-
- /* UV map */
- if (hair->need_attribute(scene, name) || hair->need_attribute(scene, std)) {
- Attribute *attr_uv;
-
- ObtainCacheParticleUV(hair, &b_mesh, &b_ob, &CData, !preview, uv_num);
-
- if (active_render)
- attr_uv = hair->attributes.add(std, name);
- else
- attr_uv = hair->attributes.add(name, TypeFloat2, ATTR_ELEMENT_CURVE);
-
- float2 *uv = attr_uv->data_float2();
-
- if (uv) {
- size_t i = 0;
-
- for (size_t curve = 0; curve < CData.curve_uv.size(); curve++) {
- uv[i++] = CData.curve_uv[curve];
- }
- }
- }
- }
- }
-}
-
-#ifdef WITH_HAIR_NODES
-static float4 hair_point_as_float4(BL::HairPoint b_point)
-{
- float4 mP = float3_to_float4(get_float3(b_point.co()));
- mP.w = b_point.radius();
- return mP;
-}
-
-static float4 interpolate_hair_points(BL::Hair b_hair,
- const int first_point_index,
- const int num_points,
- const float step)
-{
- const float curve_t = step * (num_points - 1);
- const int point_a = clamp((int)curve_t, 0, num_points - 1);
- const int point_b = min(point_a + 1, num_points - 1);
- const float t = curve_t - (float)point_a;
- return lerp(hair_point_as_float4(b_hair.points[first_point_index + point_a]),
- hair_point_as_float4(b_hair.points[first_point_index + point_b]),
- t);
-}
-
-static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
-{
- /* TODO: optimize so we can straight memcpy arrays from Blender? */
-
- /* Add requested attributes. */
- Attribute *attr_intercept = NULL;
- Attribute *attr_length = NULL;
- Attribute *attr_random = NULL;
-
- if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) {
- attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
- }
- if (hair->need_attribute(scene, ATTR_STD_CURVE_LENGTH)) {
- attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH);
- }
- if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) {
- attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
- }
-
- /* Reserve memory. */
- const int num_keys = b_hair.points.length();
- const int num_curves = b_hair.curves.length();
-
- if (num_curves > 0) {
- VLOG(1) << "Exporting curve segments for hair " << hair->name;
- }
-
- hair->reserve_curves(num_curves, num_keys);
-
- /* Export curves and points. */
- vector<float> points_length;
-
- for (BL::HairCurve &b_curve : b_hair.curves) {
- const int first_point_index = b_curve.first_point_index();
- const int num_points = b_curve.num_points();
-
- float3 prev_co = zero_float3();
- float length = 0.0f;
- if (attr_intercept) {
- points_length.clear();
- points_length.reserve(num_points);
- }
-
- /* Position and radius. */
- for (int i = 0; i < num_points; i++) {
- BL::HairPoint b_point = b_hair.points[first_point_index + i];
-
- const float3 co = get_float3(b_point.co());
- const float radius = b_point.radius();
- hair->add_curve_key(co, radius);
-
- if (attr_intercept) {
- if (i > 0) {
- length += len(co - prev_co);
- points_length.push_back(length);
- }
- prev_co = co;
- }
- }
-
- /* Normalized 0..1 attribute along curve. */
- if (attr_intercept) {
- for (int i = 0; i < num_points; i++) {
- attr_intercept->add((length == 0.0f) ? 0.0f : points_length[i] / length);
- }
- }
-
- if (attr_length) {
- attr_length->add(length);
- }
-
- /* Random number per curve. */
- if (attr_random != NULL) {
- attr_random->add(hash_uint2_to_float(b_curve.index(), 0));
- }
-
- /* Curve. */
- const int shader_index = 0;
- hair->add_curve(first_point_index, shader_index);
- }
-}
-
-static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_step)
-{
- VLOG(1) << "Exporting curve motion segments for hair " << hair->name << ", motion step "
- << motion_step;
-
- /* Find or add attribute. */
- Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- bool new_attribute = false;
-
- if (!attr_mP) {
- VLOG(1) << "Creating new motion vertex position attribute";
- attr_mP = hair->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
- new_attribute = true;
- }
-
- /* Export motion keys. */
- const int num_keys = hair->get_curve_keys().size();
- float4 *mP = attr_mP->data_float4() + motion_step * num_keys;
- bool have_motion = false;
- int num_motion_keys = 0;
- int curve_index = 0;
-
- for (BL::HairCurve &b_curve : b_hair.curves) {
- const int first_point_index = b_curve.first_point_index();
- const int num_points = b_curve.num_points();
-
- Hair::Curve curve = hair->get_curve(curve_index);
- curve_index++;
-
- if (num_points == curve.num_keys) {
- /* Number of keys matches. */
- for (int i = 0; i < num_points; i++) {
- int point_index = first_point_index + i;
-
- if (point_index < num_keys) {
- mP[num_motion_keys] = hair_point_as_float4(b_hair.points[point_index]);
- num_motion_keys++;
-
- if (!have_motion) {
- /* TODO: use epsilon for comparison? Was needed for particles due to
- * transform, but ideally should not happen anymore. */
- float4 curve_key = float3_to_float4(hair->get_curve_keys()[i]);
- curve_key.w = hair->get_curve_radius()[i];
- have_motion = !(mP[i] == curve_key);
- }
- }
- }
- }
- else {
- /* Number of keys has changed. Generate an interpolated version
- * to preserve motion blur. */
- const float step_size = curve.num_keys > 1 ? 1.0f / (curve.num_keys - 1) : 0.0f;
- for (int i = 0; i < curve.num_keys; i++) {
- const float step = i * step_size;
- mP[num_motion_keys] = interpolate_hair_points(b_hair, first_point_index, num_points, step);
- num_motion_keys++;
- }
- have_motion = true;
- }
- }
-
- /* In case of new attribute, we verify if there really was any motion. */
- if (new_attribute) {
- export_hair_motion_validate_attribute(hair, motion_step, num_motion_keys, have_motion);
- }
-}
-
-/* Hair object. */
-void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
-{
- /* Convert Blender hair to Cycles curves. */
- BL::Hair b_hair(b_ob_info.object_data);
- if (motion) {
- export_hair_curves_motion(hair, b_hair, motion_step);
- }
- else {
- export_hair_curves(scene, hair, b_hair);
- }
-}
-#else
-void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
-{
- (void)hair;
- (void)b_ob_info;
- (void)motion;
- (void)motion_step;
-}
-#endif
-
-void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair)
-{
- /* make a copy of the shaders as the caller in the main thread still need them for syncing the
- * attributes */
- array<Node *> used_shaders = hair->get_used_shaders();
-
- Hair new_hair;
- new_hair.set_used_shaders(used_shaders);
-
- if (view_layer.use_hair) {
- if (b_ob_info.object_data.is_a(&RNA_Hair)) {
- /* Hair object. */
- sync_hair(&new_hair, b_ob_info, false);
- }
- else {
- /* Particle hair. */
- bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED);
- BL::Mesh b_mesh = object_to_mesh(
- b_data, b_ob_info, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
-
- if (b_mesh) {
- sync_particle_hair(&new_hair, b_mesh, b_ob_info, false);
- free_object_to_mesh(b_data, b_ob_info, b_mesh);
- }
- }
- }
-
- /* update original sockets */
-
- for (const SocketType &socket : new_hair.type->inputs) {
- /* Those sockets are updated in sync_object, so do not modify them. */
- if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
- socket.name == "used_shaders") {
- continue;
- }
- hair->set_value(socket, new_hair, socket);
- }
-
- hair->attributes.update(std::move(new_hair.attributes));
-
- /* tag update */
-
- /* Compares curve_keys rather than strands in order to handle quick hair
- * adjustments in dynamic BVH - other methods could probably do this better. */
- const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
-
- hair->tag_update(scene, rebuild);
-}
-
-void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
- BObjectInfo &b_ob_info,
- Hair *hair,
- int motion_step)
-{
- /* Skip if nothing exported. */
- if (hair->num_keys() == 0) {
- return;
- }
-
- /* Export deformed coordinates. */
- if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
- if (b_ob_info.object_data.is_a(&RNA_Hair)) {
- /* Hair object. */
- sync_hair(hair, b_ob_info, true, motion_step);
- return;
- }
- else {
- /* Particle hair. */
- BL::Mesh b_mesh = object_to_mesh(
- b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
- if (b_mesh) {
- sync_particle_hair(hair, b_mesh, b_ob_info, true, motion_step);
- free_object_to_mesh(b_data, b_ob_info, b_mesh);
- return;
- }
- }
- }
-
- /* No deformation on this frame, copy coordinates if other frames did have it. */
- hair->copy_center_to_motion_step(motion_step);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_device.cpp b/intern/cycles/blender/blender_device.cpp
deleted file mode 100644
index 7bed33855c2..00000000000
--- a/intern/cycles/blender/blender_device.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "blender/blender_device.h"
-#include "blender/blender_session.h"
-#include "blender/blender_util.h"
-
-#include "util/util_foreach.h"
-
-CCL_NAMESPACE_BEGIN
-
-enum ComputeDevice {
- COMPUTE_DEVICE_CPU = 0,
- COMPUTE_DEVICE_CUDA = 1,
- COMPUTE_DEVICE_OPTIX = 3,
- COMPUTE_DEVICE_HIP = 4,
-
- COMPUTE_DEVICE_NUM
-};
-
-int blender_device_threads(BL::Scene &b_scene)
-{
- BL::RenderSettings b_r = b_scene.render();
-
- if (b_r.threads_mode() == BL::RenderSettings::threads_mode_FIXED)
- return b_r.threads();
- else
- return 0;
-}
-
-DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scene, bool background)
-{
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-
- /* Find cycles preferences. */
- PointerRNA cpreferences;
- for (BL::Addon &b_addon : b_preferences.addons) {
- if (b_addon.module() == "cycles") {
- cpreferences = b_addon.preferences().ptr;
- break;
- }
- }
-
- /* Default to CPU device. */
- DeviceInfo device = Device::available_devices(DEVICE_MASK_CPU).front();
-
- if (BlenderSession::device_override != DEVICE_MASK_ALL) {
- vector<DeviceInfo> devices = Device::available_devices(BlenderSession::device_override);
-
- if (devices.empty()) {
- device = Device::dummy_device("Found no Cycles device of the specified type");
- }
- else {
- int threads = blender_device_threads(b_scene);
- device = Device::get_multi_device(devices, threads, background);
- }
- }
- else if (get_enum(cscene, "device") == 1) {
- /* Test if we are using GPU devices. */
- ComputeDevice compute_device = (ComputeDevice)get_enum(
- cpreferences, "compute_device_type", COMPUTE_DEVICE_NUM, COMPUTE_DEVICE_CPU);
-
- if (compute_device != COMPUTE_DEVICE_CPU) {
- /* Query GPU devices with matching types. */
- uint mask = DEVICE_MASK_CPU;
- if (compute_device == COMPUTE_DEVICE_CUDA) {
- mask |= DEVICE_MASK_CUDA;
- }
- else if (compute_device == COMPUTE_DEVICE_OPTIX) {
- mask |= DEVICE_MASK_OPTIX;
- }
- else if (compute_device == COMPUTE_DEVICE_HIP) {
- mask |= DEVICE_MASK_HIP;
- }
- vector<DeviceInfo> devices = Device::available_devices(mask);
-
- /* Match device preferences and available devices. */
- vector<DeviceInfo> used_devices;
- RNA_BEGIN (&cpreferences, device, "devices") {
- if (get_boolean(device, "use")) {
- string id = get_string(device, "id");
- foreach (DeviceInfo &info, devices) {
- if (info.id == id) {
- used_devices.push_back(info);
- break;
- }
- }
- }
- }
- RNA_END;
-
- if (!used_devices.empty()) {
- int threads = blender_device_threads(b_scene);
- device = Device::get_multi_device(used_devices, threads, background);
- }
- /* Else keep using the CPU device that was set before. */
- }
- }
-
- if (!get_boolean(cpreferences, "peer_memory")) {
- device.has_peer_memory = false;
- }
-
- return device;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_display_driver.cpp b/intern/cycles/blender/blender_display_driver.cpp
deleted file mode 100644
index f55a8ce8c4e..00000000000
--- a/intern/cycles/blender/blender_display_driver.cpp
+++ /dev/null
@@ -1,754 +0,0 @@
-/*
- * Copyright 2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "blender/blender_display_driver.h"
-
-#include "device/device.h"
-#include "util/util_logging.h"
-#include "util/util_opengl.h"
-
-extern "C" {
-struct RenderEngine;
-
-bool RE_engine_has_render_context(struct RenderEngine *engine);
-void RE_engine_render_context_enable(struct RenderEngine *engine);
-void RE_engine_render_context_disable(struct RenderEngine *engine);
-
-bool DRW_opengl_context_release();
-void DRW_opengl_context_activate(bool drw_state);
-
-void *WM_opengl_context_create();
-void WM_opengl_context_activate(void *gl_context);
-void WM_opengl_context_dispose(void *gl_context);
-void WM_opengl_context_release(void *context);
-}
-
-CCL_NAMESPACE_BEGIN
-
-/* --------------------------------------------------------------------
- * BlenderDisplayShader.
- */
-
-unique_ptr<BlenderDisplayShader> BlenderDisplayShader::create(BL::RenderEngine &b_engine,
- BL::Scene &b_scene)
-{
- if (b_engine.support_display_space_shader(b_scene)) {
- return make_unique<BlenderDisplaySpaceShader>(b_engine, b_scene);
- }
-
- return make_unique<BlenderFallbackDisplayShader>();
-}
-
-int BlenderDisplayShader::get_position_attrib_location()
-{
- if (position_attribute_location_ == -1) {
- const uint shader_program = get_shader_program();
- position_attribute_location_ = glGetAttribLocation(shader_program, position_attribute_name);
- }
- return position_attribute_location_;
-}
-
-int BlenderDisplayShader::get_tex_coord_attrib_location()
-{
- if (tex_coord_attribute_location_ == -1) {
- const uint shader_program = get_shader_program();
- tex_coord_attribute_location_ = glGetAttribLocation(shader_program, tex_coord_attribute_name);
- }
- return tex_coord_attribute_location_;
-}
-
-/* --------------------------------------------------------------------
- * BlenderFallbackDisplayShader.
- */
-
-/* TODO move shaders to standalone .glsl file. */
-static const char *FALLBACK_VERTEX_SHADER =
- "#version 330\n"
- "uniform vec2 fullscreen;\n"
- "in vec2 texCoord;\n"
- "in vec2 pos;\n"
- "out vec2 texCoord_interp;\n"
- "\n"
- "vec2 normalize_coordinates()\n"
- "{\n"
- " return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n"
- "}\n"
- "\n"
- "void main()\n"
- "{\n"
- " gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n"
- " texCoord_interp = texCoord;\n"
- "}\n\0";
-
-static const char *FALLBACK_FRAGMENT_SHADER =
- "#version 330\n"
- "uniform sampler2D image_texture;\n"
- "in vec2 texCoord_interp;\n"
- "out vec4 fragColor;\n"
- "\n"
- "void main()\n"
- "{\n"
- " fragColor = texture(image_texture, texCoord_interp);\n"
- "}\n\0";
-
-static void shader_print_errors(const char *task, const char *log, const char *code)
-{
- LOG(ERROR) << "Shader: " << task << " error:";
- LOG(ERROR) << "===== shader string ====";
-
- stringstream stream(code);
- string partial;
-
- int line = 1;
- while (getline(stream, partial, '\n')) {
- if (line < 10) {
- LOG(ERROR) << " " << line << " " << partial;
- }
- else {
- LOG(ERROR) << line << " " << partial;
- }
- line++;
- }
- LOG(ERROR) << log;
-}
-
-static int compile_fallback_shader(void)
-{
- const struct Shader {
- const char *source;
- const GLenum type;
- } shaders[2] = {{FALLBACK_VERTEX_SHADER, GL_VERTEX_SHADER},
- {FALLBACK_FRAGMENT_SHADER, GL_FRAGMENT_SHADER}};
-
- const GLuint program = glCreateProgram();
-
- for (int i = 0; i < 2; i++) {
- const GLuint shader = glCreateShader(shaders[i].type);
-
- string source_str = shaders[i].source;
- const char *c_str = source_str.c_str();
-
- glShaderSource(shader, 1, &c_str, NULL);
- glCompileShader(shader);
-
- GLint compile_status;
- glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
-
- if (!compile_status) {
- GLchar log[5000];
- GLsizei length = 0;
- glGetShaderInfoLog(shader, sizeof(log), &length, log);
- shader_print_errors("compile", log, c_str);
- return 0;
- }
-
- glAttachShader(program, shader);
- }
-
- /* Link output. */
- glBindFragDataLocation(program, 0, "fragColor");
-
- /* Link and error check. */
- glLinkProgram(program);
-
- /* TODO(sergey): Find a way to nicely de-duplicate the error checking. */
- GLint link_status;
- glGetProgramiv(program, GL_LINK_STATUS, &link_status);
- if (!link_status) {
- GLchar log[5000];
- GLsizei length = 0;
- /* TODO(sergey): Is it really program passed to glGetShaderInfoLog? */
- glGetShaderInfoLog(program, sizeof(log), &length, log);
- shader_print_errors("linking", log, FALLBACK_VERTEX_SHADER);
- shader_print_errors("linking", log, FALLBACK_FRAGMENT_SHADER);
- return 0;
- }
-
- return program;
-}
-
-void BlenderFallbackDisplayShader::bind(int width, int height)
-{
- create_shader_if_needed();
-
- if (!shader_program_) {
- return;
- }
-
- glUseProgram(shader_program_);
- glUniform1i(image_texture_location_, 0);
- glUniform2f(fullscreen_location_, width, height);
-}
-
-void BlenderFallbackDisplayShader::unbind()
-{
-}
-
-uint BlenderFallbackDisplayShader::get_shader_program()
-{
- return shader_program_;
-}
-
-void BlenderFallbackDisplayShader::create_shader_if_needed()
-{
- if (shader_program_ || shader_compile_attempted_) {
- return;
- }
-
- shader_compile_attempted_ = true;
-
- shader_program_ = compile_fallback_shader();
- if (!shader_program_) {
- return;
- }
-
- glUseProgram(shader_program_);
-
- image_texture_location_ = glGetUniformLocation(shader_program_, "image_texture");
- if (image_texture_location_ < 0) {
- LOG(ERROR) << "Shader doesn't contain the 'image_texture' uniform.";
- destroy_shader();
- return;
- }
-
- fullscreen_location_ = glGetUniformLocation(shader_program_, "fullscreen");
- if (fullscreen_location_ < 0) {
- LOG(ERROR) << "Shader doesn't contain the 'fullscreen' uniform.";
- destroy_shader();
- return;
- }
-}
-
-void BlenderFallbackDisplayShader::destroy_shader()
-{
- glDeleteProgram(shader_program_);
- shader_program_ = 0;
-}
-
-/* --------------------------------------------------------------------
- * BlenderDisplaySpaceShader.
- */
-
-BlenderDisplaySpaceShader::BlenderDisplaySpaceShader(BL::RenderEngine &b_engine,
- BL::Scene &b_scene)
- : b_engine_(b_engine), b_scene_(b_scene)
-{
- DCHECK(b_engine_.support_display_space_shader(b_scene_));
-}
-
-void BlenderDisplaySpaceShader::bind(int /*width*/, int /*height*/)
-{
- b_engine_.bind_display_space_shader(b_scene_);
-}
-
-void BlenderDisplaySpaceShader::unbind()
-{
- b_engine_.unbind_display_space_shader();
-}
-
-uint BlenderDisplaySpaceShader::get_shader_program()
-{
- if (!shader_program_) {
- glGetIntegerv(GL_CURRENT_PROGRAM, reinterpret_cast<int *>(&shader_program_));
- }
-
- if (!shader_program_) {
- LOG(ERROR) << "Error retrieving shader program for display space shader.";
- }
-
- return shader_program_;
-}
-
-/* --------------------------------------------------------------------
- * BlenderDisplayDriver.
- */
-
-BlenderDisplayDriver::BlenderDisplayDriver(BL::RenderEngine &b_engine, BL::Scene &b_scene)
- : b_engine_(b_engine), display_shader_(BlenderDisplayShader::create(b_engine, b_scene))
-{
- /* Create context while on the main thread. */
- gl_context_create();
-}
-
-BlenderDisplayDriver::~BlenderDisplayDriver()
-{
- gl_resources_destroy();
-}
-
-/* --------------------------------------------------------------------
- * Update procedure.
- */
-
-bool BlenderDisplayDriver::update_begin(const Params &params,
- int texture_width,
- int texture_height)
-{
- /* Note that it's the responsibility of BlenderDisplayDriver to ensure updating and drawing
- * the texture does not happen at the same time. This is achieved indirectly.
- *
- * When enabling the OpenGL context, it uses an internal mutex lock DST.gl_context_lock.
- * This same lock is also held when do_draw() is called, which together ensure mutual
- * exclusion.
- *
- * This locking is not performed on the Cycles side, because that would cause lock inversion. */
- if (!gl_context_enable()) {
- return false;
- }
-
- if (gl_render_sync_) {
- glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
- }
-
- if (!gl_texture_resources_ensure()) {
- gl_context_disable();
- return false;
- }
-
- /* Update texture dimensions if needed. */
- if (texture_.width != texture_width || texture_.height != texture_height) {
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
- glTexImage2D(
- GL_TEXTURE_2D, 0, GL_RGBA16F, texture_width, texture_height, 0, GL_RGBA, GL_HALF_FLOAT, 0);
- texture_.width = texture_width;
- texture_.height = texture_height;
- glBindTexture(GL_TEXTURE_2D, 0);
-
- /* Texture did change, and no pixel storage was provided. Tag for an explicit zeroing out to
- * avoid undefined content. */
- texture_.need_clear = true;
- }
-
- /* Update PBO dimensions if needed.
- *
- * NOTE: Allocate the PBO for the the size which will fit the final render resolution (as in,
- * at a resolution divider 1. This was we don't need to recreate graphics interoperability
- * objects which are costly and which are tied to the specific underlying buffer size.
- * The downside of this approach is that when graphics interoperability is not used we are
- * sending too much data to GPU when resolution divider is not 1. */
- /* TODO(sergey): Investigate whether keeping the PBO exact size of the texture makes non-interop
- * mode faster. */
- const int buffer_width = params.full_size.x;
- const int buffer_height = params.full_size.y;
- if (texture_.buffer_width != buffer_width || texture_.buffer_height != buffer_height) {
- const size_t size_in_bytes = sizeof(half4) * buffer_width * buffer_height;
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
- glBufferData(GL_PIXEL_UNPACK_BUFFER, size_in_bytes, 0, GL_DYNAMIC_DRAW);
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
-
- texture_.buffer_width = buffer_width;
- texture_.buffer_height = buffer_height;
- }
-
- /* New content will be provided to the texture in one way or another, so mark this in a
- * centralized place. */
- texture_.need_update = true;
-
- return true;
-}
-
-void BlenderDisplayDriver::update_end()
-{
- gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- glFlush();
-
- gl_context_disable();
-}
-
-/* --------------------------------------------------------------------
- * Texture buffer mapping.
- */
-
-half4 *BlenderDisplayDriver::map_texture_buffer()
-{
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
-
- half4 *mapped_rgba_pixels = reinterpret_cast<half4 *>(
- glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
- if (!mapped_rgba_pixels) {
- LOG(ERROR) << "Error mapping BlenderDisplayDriver pixel buffer object.";
- }
-
- if (texture_.need_clear) {
- const int64_t texture_width = texture_.width;
- const int64_t texture_height = texture_.height;
- memset(reinterpret_cast<void *>(mapped_rgba_pixels),
- 0,
- texture_width * texture_height * sizeof(half4));
- texture_.need_clear = false;
- }
-
- return mapped_rgba_pixels;
-}
-
-void BlenderDisplayDriver::unmap_texture_buffer()
-{
- glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
-
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
-}
-
-/* --------------------------------------------------------------------
- * Graphics interoperability.
- */
-
-BlenderDisplayDriver::GraphicsInterop BlenderDisplayDriver::graphics_interop_get()
-{
- GraphicsInterop interop_dst;
-
- interop_dst.buffer_width = texture_.buffer_width;
- interop_dst.buffer_height = texture_.buffer_height;
- interop_dst.opengl_pbo_id = texture_.gl_pbo_id;
-
- interop_dst.need_clear = texture_.need_clear;
- texture_.need_clear = false;
-
- return interop_dst;
-}
-
-void BlenderDisplayDriver::graphics_interop_activate()
-{
- gl_context_enable();
-}
-
-void BlenderDisplayDriver::graphics_interop_deactivate()
-{
- gl_context_disable();
-}
-
-/* --------------------------------------------------------------------
- * Drawing.
- */
-
-void BlenderDisplayDriver::clear()
-{
- texture_.need_clear = true;
-}
-
-void BlenderDisplayDriver::set_zoom(float zoom_x, float zoom_y)
-{
- zoom_ = make_float2(zoom_x, zoom_y);
-}
-
-void BlenderDisplayDriver::draw(const Params &params)
-{
- /* See do_update_begin() for why no locking is required here. */
- const bool transparent = true; // TODO(sergey): Derive this from Film.
-
- if (!gl_draw_resources_ensure()) {
- return;
- }
-
- if (use_gl_context_) {
- gl_context_mutex_.lock();
- }
-
- if (texture_.need_clear) {
- /* Texture is requested to be cleared and was not yet cleared.
- *
- * Do early return which should be equivalent of drawing all-zero texture.
- * Watch out for the lock though so that the clear happening during update is properly
- * synchronized here. */
- gl_context_mutex_.unlock();
- return;
- }
-
- if (gl_upload_sync_) {
- glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
- }
-
- if (transparent) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- }
-
- display_shader_->bind(params.full_size.x, params.full_size.y);
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
-
- /* Trick to keep sharp rendering without jagged edges on all GPUs.
- *
- * The idea here is to enforce driver to use linear interpolation when the image is not zoomed
- * in.
- * For the render result with a resolution divider in effect we always use nearest interpolation.
- *
- * Use explicit MIN assignment to make sure the driver does not have an undefined behavior at
- * the zoom level 1. The MAG filter is always NEAREST. */
- const float zoomed_width = params.size.x * zoom_.x;
- const float zoomed_height = params.size.y * zoom_.y;
- if (texture_.width != params.size.x || texture_.height != params.size.y) {
- /* Resolution divider is different from 1, force nearest interpolation. */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- }
- else if (zoomed_width - params.size.x > 0.5f || zoomed_height - params.size.y > 0.5f) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- }
- else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
-
- glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
-
- texture_update_if_needed();
- vertex_buffer_update(params);
-
- /* TODO(sergey): Does it make sense/possible to cache/reuse the VAO? */
- GLuint vertex_array_object;
- glGenVertexArrays(1, &vertex_array_object);
- glBindVertexArray(vertex_array_object);
-
- const int texcoord_attribute = display_shader_->get_tex_coord_attrib_location();
- const int position_attribute = display_shader_->get_position_attrib_location();
-
- glEnableVertexAttribArray(texcoord_attribute);
- glEnableVertexAttribArray(position_attribute);
-
- glVertexAttribPointer(
- texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0);
- glVertexAttribPointer(position_attribute,
- 2,
- GL_FLOAT,
- GL_FALSE,
- 4 * sizeof(float),
- (const GLvoid *)(sizeof(float) * 2));
-
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindTexture(GL_TEXTURE_2D, 0);
-
- glDeleteVertexArrays(1, &vertex_array_object);
-
- display_shader_->unbind();
-
- if (transparent) {
- glDisable(GL_BLEND);
- }
-
- gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- glFlush();
-
- if (use_gl_context_) {
- gl_context_mutex_.unlock();
- }
-}
-
-void BlenderDisplayDriver::gl_context_create()
-{
- /* When rendering in viewport there is no render context available via engine.
- * Check whether own context is to be created here.
- *
- * NOTE: If the `b_engine_`'s context is not available, we are expected to be on a main thread
- * here. */
- use_gl_context_ = !RE_engine_has_render_context(
- reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
-
- if (use_gl_context_) {
- const bool drw_state = DRW_opengl_context_release();
- gl_context_ = WM_opengl_context_create();
- if (gl_context_) {
- /* On Windows an old context is restored after creation, and subsequent release of context
- * generates a Win32 error. Harmless for users, but annoying to have possible misleading
- * error prints in the console. */
-#ifndef _WIN32
- WM_opengl_context_release(gl_context_);
-#endif
- }
- else {
- LOG(ERROR) << "Error creating OpenGL context.";
- }
-
- DRW_opengl_context_activate(drw_state);
- }
-}
-
-bool BlenderDisplayDriver::gl_context_enable()
-{
- if (use_gl_context_) {
- if (!gl_context_) {
- return false;
- }
- gl_context_mutex_.lock();
- WM_opengl_context_activate(gl_context_);
- return true;
- }
-
- RE_engine_render_context_enable(reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
- return true;
-}
-
-void BlenderDisplayDriver::gl_context_disable()
-{
- if (use_gl_context_) {
- if (gl_context_) {
- WM_opengl_context_release(gl_context_);
- gl_context_mutex_.unlock();
- }
- return;
- }
-
- RE_engine_render_context_disable(reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
-}
-
-void BlenderDisplayDriver::gl_context_dispose()
-{
- if (gl_context_) {
- const bool drw_state = DRW_opengl_context_release();
-
- WM_opengl_context_activate(gl_context_);
- WM_opengl_context_dispose(gl_context_);
-
- DRW_opengl_context_activate(drw_state);
- }
-}
-
-bool BlenderDisplayDriver::gl_draw_resources_ensure()
-{
- if (!texture_.gl_id) {
- /* If there is no texture allocated, there is nothing to draw. Inform the draw call that it can
- * can not continue. Note that this is not an unrecoverable error, so once the texture is known
- * we will come back here and create all the GPU resources needed for draw. */
- return false;
- }
-
- if (gl_draw_resource_creation_attempted_) {
- return gl_draw_resources_created_;
- }
- gl_draw_resource_creation_attempted_ = true;
-
- if (!vertex_buffer_) {
- glGenBuffers(1, &vertex_buffer_);
- if (!vertex_buffer_) {
- LOG(ERROR) << "Error creating vertex buffer.";
- return false;
- }
- }
-
- gl_draw_resources_created_ = true;
-
- return true;
-}
-
-void BlenderDisplayDriver::gl_resources_destroy()
-{
- gl_context_enable();
-
- if (vertex_buffer_ != 0) {
- glDeleteBuffers(1, &vertex_buffer_);
- }
-
- if (texture_.gl_pbo_id) {
- glDeleteBuffers(1, &texture_.gl_pbo_id);
- texture_.gl_pbo_id = 0;
- }
-
- if (texture_.gl_id) {
- glDeleteTextures(1, &texture_.gl_id);
- texture_.gl_id = 0;
- }
-
- gl_context_disable();
-
- gl_context_dispose();
-}
-
-bool BlenderDisplayDriver::gl_texture_resources_ensure()
-{
- if (texture_.creation_attempted) {
- return texture_.is_created;
- }
- texture_.creation_attempted = true;
-
- DCHECK(!texture_.gl_id);
- DCHECK(!texture_.gl_pbo_id);
-
- /* Create texture. */
- glGenTextures(1, &texture_.gl_id);
- if (!texture_.gl_id) {
- LOG(ERROR) << "Error creating texture.";
- return false;
- }
-
- /* Configure the texture. */
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glBindTexture(GL_TEXTURE_2D, 0);
-
- /* Create PBO for the texture. */
- glGenBuffers(1, &texture_.gl_pbo_id);
- if (!texture_.gl_pbo_id) {
- LOG(ERROR) << "Error creating texture pixel buffer object.";
- return false;
- }
-
- /* Creation finished with a success. */
- texture_.is_created = true;
-
- return true;
-}
-
-void BlenderDisplayDriver::texture_update_if_needed()
-{
- if (!texture_.need_update) {
- return;
- }
-
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
- glTexSubImage2D(
- GL_TEXTURE_2D, 0, 0, 0, texture_.width, texture_.height, GL_RGBA, GL_HALF_FLOAT, 0);
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
-
- texture_.need_update = false;
-}
-
-void BlenderDisplayDriver::vertex_buffer_update(const Params &params)
-{
- /* Invalidate old contents - avoids stalling if the buffer is still waiting in queue to be
- * rendered. */
- glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
-
- float *vpointer = reinterpret_cast<float *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
- if (!vpointer) {
- return;
- }
-
- vpointer[0] = 0.0f;
- vpointer[1] = 0.0f;
- vpointer[2] = params.full_offset.x;
- vpointer[3] = params.full_offset.y;
-
- vpointer[4] = 1.0f;
- vpointer[5] = 0.0f;
- vpointer[6] = (float)params.size.x + params.full_offset.x;
- vpointer[7] = params.full_offset.y;
-
- vpointer[8] = 1.0f;
- vpointer[9] = 1.0f;
- vpointer[10] = (float)params.size.x + params.full_offset.x;
- vpointer[11] = (float)params.size.y + params.full_offset.y;
-
- vpointer[12] = 0.0f;
- vpointer[13] = 1.0f;
- vpointer[14] = params.full_offset.x;
- vpointer[15] = (float)params.size.y + params.full_offset.y;
-
- glUnmapBuffer(GL_ARRAY_BUFFER);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_display_driver.h b/intern/cycles/blender/blender_display_driver.h
deleted file mode 100644
index 558997c6b4f..00000000000
--- a/intern/cycles/blender/blender_display_driver.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright 2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <atomic>
-
-#include "MEM_guardedalloc.h"
-
-#include "RNA_blender_cpp.h"
-
-#include "render/display_driver.h"
-
-#include "util/util_thread.h"
-#include "util/util_unique_ptr.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Base class of shader used for display driver rendering. */
-class BlenderDisplayShader {
- public:
- static constexpr const char *position_attribute_name = "pos";
- static constexpr const char *tex_coord_attribute_name = "texCoord";
-
- /* Create shader implementation suitable for the given render engine and scene configuration. */
- static unique_ptr<BlenderDisplayShader> create(BL::RenderEngine &b_engine, BL::Scene &b_scene);
-
- BlenderDisplayShader() = default;
- virtual ~BlenderDisplayShader() = default;
-
- virtual void bind(int width, int height) = 0;
- virtual void unbind() = 0;
-
- /* Get attribute location for position and texture coordinate respectively.
- * NOTE: The shader needs to be bound to have access to those. */
- virtual int get_position_attrib_location();
- virtual int get_tex_coord_attrib_location();
-
- protected:
- /* Get program of this display shader.
- * NOTE: The shader needs to be bound to have access to this. */
- virtual uint get_shader_program() = 0;
-
- /* Cached values of various OpenGL resources. */
- int position_attribute_location_ = -1;
- int tex_coord_attribute_location_ = -1;
-};
-
-/* Implementation of display rendering shader used in the case when render engine does not support
- * display space shader. */
-class BlenderFallbackDisplayShader : public BlenderDisplayShader {
- public:
- virtual void bind(int width, int height) override;
- virtual void unbind() override;
-
- protected:
- virtual uint get_shader_program() override;
-
- void create_shader_if_needed();
- void destroy_shader();
-
- uint shader_program_ = 0;
- int image_texture_location_ = -1;
- int fullscreen_location_ = -1;
-
- /* Shader compilation attempted. Which means, that if the shader program is 0 then compilation or
- * linking has failed. Do not attempt to re-compile the shader. */
- bool shader_compile_attempted_ = false;
-};
-
-class BlenderDisplaySpaceShader : public BlenderDisplayShader {
- public:
- BlenderDisplaySpaceShader(BL::RenderEngine &b_engine, BL::Scene &b_scene);
-
- virtual void bind(int width, int height) override;
- virtual void unbind() override;
-
- protected:
- virtual uint get_shader_program() override;
-
- BL::RenderEngine b_engine_;
- BL::Scene &b_scene_;
-
- /* Cached values of various OpenGL resources. */
- uint shader_program_ = 0;
-};
-
-/* Display driver implementation which is specific for Blender viewport integration. */
-class BlenderDisplayDriver : public DisplayDriver {
- public:
- BlenderDisplayDriver(BL::RenderEngine &b_engine, BL::Scene &b_scene);
- ~BlenderDisplayDriver();
-
- virtual void graphics_interop_activate() override;
- virtual void graphics_interop_deactivate() override;
-
- virtual void clear() override;
-
- void set_zoom(float zoom_x, float zoom_y);
-
- protected:
- virtual bool update_begin(const Params &params, int texture_width, int texture_height) override;
- virtual void update_end() override;
-
- virtual half4 *map_texture_buffer() override;
- virtual void unmap_texture_buffer() override;
-
- virtual GraphicsInterop graphics_interop_get() override;
-
- virtual void draw(const Params &params) override;
-
- /* Helper function which allocates new GPU context. */
- void gl_context_create();
- bool gl_context_enable();
- void gl_context_disable();
- void gl_context_dispose();
-
- /* Make sure texture is allocated and its initial configuration is performed. */
- bool gl_texture_resources_ensure();
-
- /* Ensure all runtime GPU resources needed for drawing are allocated.
- * Returns true if all resources needed for drawing are available. */
- bool gl_draw_resources_ensure();
-
- /* Destroy all GPU resources which are being used by this object. */
- void gl_resources_destroy();
-
- /* Update GPU texture dimensions and content if needed (new pixel data was provided).
- *
- * NOTE: The texture needs to be bound. */
- void texture_update_if_needed();
-
- /* Update vertex buffer with new coordinates of vertex positions and texture coordinates.
- * This buffer is used to render texture in the viewport.
- *
- * NOTE: The buffer needs to be bound. */
- void vertex_buffer_update(const Params &params);
-
- BL::RenderEngine b_engine_;
-
- /* OpenGL context which is used the render engine doesn't have its own. */
- void *gl_context_ = nullptr;
- /* The when Blender RenderEngine side context is not available and the DisplayDriver is to create
- * its own context. */
- bool use_gl_context_ = false;
- /* Mutex used to guard the `gl_context_`. */
- thread_mutex gl_context_mutex_;
-
- /* Texture which contains pixels of the render result. */
- struct {
- /* Indicates whether texture creation was attempted and succeeded.
- * Used to avoid multiple attempts of texture creation on GPU issues or GPU context
- * misconfiguration. */
- bool creation_attempted = false;
- bool is_created = false;
-
- /* OpenGL resource IDs of the texture itself and Pixel Buffer Object (PBO) used to write
- * pixels to it.
- *
- * NOTE: Allocated on the engine's context. */
- uint gl_id = 0;
- uint gl_pbo_id = 0;
-
- /* Is true when new data was written to the PBO, meaning, the texture might need to be resized
- * and new data is to be uploaded to the GPU. */
- bool need_update = false;
-
- /* Content of the texture is to be filled with zeroes. */
- std::atomic<bool> need_clear = true;
-
- /* Dimensions of the texture in pixels. */
- int width = 0;
- int height = 0;
-
- /* Dimensions of the underlying PBO. */
- int buffer_width = 0;
- int buffer_height = 0;
- } texture_;
-
- unique_ptr<BlenderDisplayShader> display_shader_;
-
- /* Special track of whether GPU resources were attempted to be created, to avoid attempts of
- * their re-creation on failure on every redraw. */
- bool gl_draw_resource_creation_attempted_ = false;
- bool gl_draw_resources_created_ = false;
-
- /* Vertex buffer which hold vertices of a triangle fan which is textures with the texture
- * holding the render result. */
- uint vertex_buffer_ = 0;
-
- void *gl_render_sync_ = nullptr;
- void *gl_upload_sync_ = nullptr;
-
- float2 zoom_ = make_float2(1.0f, 1.0f);
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp
deleted file mode 100644
index 7b49bb7fbb7..00000000000
--- a/intern/cycles/blender/blender_geometry.cpp
+++ /dev/null
@@ -1,241 +0,0 @@
-
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/curves.h"
-#include "render/hair.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/volume.h"
-
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-#include "util/util_foreach.h"
-#include "util/util_task.h"
-
-CCL_NAMESPACE_BEGIN
-
-static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair)
-{
- if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
- return Geometry::HAIR;
- }
-
- if (b_ob_info.object_data.is_a(&RNA_Volume) ||
- (b_ob_info.object_data == b_ob_info.real_object.data() &&
- object_fluid_gas_domain_find(b_ob_info.real_object))) {
- return Geometry::VOLUME;
- }
-
- return Geometry::MESH;
-}
-
-array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob)
-{
- BL::Material material_override = view_layer.material_override;
- Shader *default_shader = (b_ob.type() == BL::Object::type_VOLUME) ? scene->default_volume :
- scene->default_surface;
-
- array<Node *> used_shaders;
-
- for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
- if (material_override) {
- find_shader(material_override, used_shaders, default_shader);
- }
- else {
- BL::ID b_material(b_slot.material());
- find_shader(b_material, used_shaders, default_shader);
- }
- }
-
- if (used_shaders.size() == 0) {
- if (material_override)
- find_shader(material_override, used_shaders, default_shader);
- else
- used_shaders.push_back_slow(default_shader);
- }
-
- return used_shaders;
-}
-
-Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
- BObjectInfo &b_ob_info,
- bool object_updated,
- bool use_particle_hair,
- TaskPool *task_pool)
-{
- /* Test if we can instance or if the object is modified. */
- Geometry::Type geom_type = determine_geom_type(b_ob_info, use_particle_hair);
- BL::ID b_key_id = (b_ob_info.is_real_object_data() &&
- BKE_object_is_modified(b_ob_info.real_object)) ?
- b_ob_info.real_object :
- b_ob_info.object_data;
- GeometryKey key(b_key_id.ptr.data, geom_type);
-
- /* Find shader indices. */
- array<Node *> used_shaders = find_used_shaders(b_ob_info.iter_object);
-
- /* Ensure we only sync instanced geometry once. */
- Geometry *geom = geometry_map.find(key);
- if (geom) {
- if (geometry_synced.find(geom) != geometry_synced.end()) {
- return geom;
- }
- }
-
- /* Test if we need to sync. */
- bool sync = true;
- if (geom == NULL) {
- /* Add new geometry if it did not exist yet. */
- if (geom_type == Geometry::HAIR) {
- geom = scene->create_node<Hair>();
- }
- else if (geom_type == Geometry::VOLUME) {
- geom = scene->create_node<Volume>();
- }
- else {
- geom = scene->create_node<Mesh>();
- }
- geometry_map.add(key, geom);
- }
- else {
- /* Test if we need to update existing geometry. */
- sync = geometry_map.update(geom, b_key_id);
- }
-
- if (!sync) {
- /* If transform was applied to geometry, need full update. */
- if (object_updated && geom->transform_applied) {
- ;
- }
- /* Test if shaders changed, these can be object level so geometry
- * does not get tagged for recalc. */
- else if (geom->get_used_shaders() != used_shaders) {
- ;
- }
- else {
- /* Even if not tagged for recalc, we may need to sync anyway
- * because the shader needs different geometry attributes. */
- bool attribute_recalc = false;
-
- foreach (Node *node, geom->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->need_update_geometry()) {
- attribute_recalc = true;
- }
- }
-
- if (!attribute_recalc) {
- return geom;
- }
- }
- }
-
- geometry_synced.insert(geom);
-
- geom->name = ustring(b_ob_info.object_data.name().c_str());
-
- /* Store the shaders immediately for the object attribute code. */
- geom->set_used_shaders(used_shaders);
-
- auto sync_func = [=]() mutable {
- if (progress.get_cancel())
- return;
-
- progress.set_sync_status("Synchronizing object", b_ob_info.real_object.name());
-
- if (geom_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- sync_hair(b_depsgraph, b_ob_info, hair);
- }
- else if (geom_type == Geometry::VOLUME) {
- Volume *volume = static_cast<Volume *>(geom);
- sync_volume(b_ob_info, volume);
- }
- else {
- Mesh *mesh = static_cast<Mesh *>(geom);
- sync_mesh(b_depsgraph, b_ob_info, mesh);
- }
- };
-
- /* Defer the actual geometry sync to the task_pool for multithreading */
- if (task_pool) {
- task_pool->push(sync_func);
- }
- else {
- sync_func();
- }
-
- return geom;
-}
-
-void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
- BObjectInfo &b_ob_info,
- Object *object,
- float motion_time,
- bool use_particle_hair,
- TaskPool *task_pool)
-{
- /* Ensure we only sync instanced geometry once. */
- Geometry *geom = object->get_geometry();
-
- if (geometry_motion_synced.find(geom) != geometry_motion_synced.end() ||
- geometry_motion_attribute_synced.find(geom) != geometry_motion_attribute_synced.end()) {
- return;
- }
-
- geometry_motion_synced.insert(geom);
-
- /* Ensure we only motion sync geometry that also had geometry synced, to avoid
- * unnecessary work and to ensure that its attributes were clear. */
- if (geometry_synced.find(geom) == geometry_synced.end())
- return;
-
- /* Find time matching motion step required by geometry. */
- int motion_step = geom->motion_step(motion_time);
- if (motion_step < 0) {
- return;
- }
-
- auto sync_func = [=]() mutable {
- if (progress.get_cancel())
- return;
-
- if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
- Hair *hair = static_cast<Hair *>(geom);
- sync_hair_motion(b_depsgraph, b_ob_info, hair, motion_step);
- }
- else if (b_ob_info.object_data.is_a(&RNA_Volume) ||
- object_fluid_gas_domain_find(b_ob_info.real_object)) {
- /* No volume motion blur support yet. */
- }
- else {
- Mesh *mesh = static_cast<Mesh *>(geom);
- sync_mesh_motion(b_depsgraph, b_ob_info, mesh, motion_step);
- }
- };
-
- /* Defer the actual geometry sync to the task_pool for multithreading */
- if (task_pool) {
- task_pool->push(sync_func);
- }
- else {
- sync_func();
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_id_map.h b/intern/cycles/blender/blender_id_map.h
deleted file mode 100644
index 198cfb4b29a..00000000000
--- a/intern/cycles/blender/blender_id_map.h
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BLENDER_ID_MAP_H__
-#define __BLENDER_ID_MAP_H__
-
-#include <string.h>
-
-#include "render/geometry.h"
-#include "render/scene.h"
-
-#include "util/util_map.h"
-#include "util/util_set.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* ID Map
- *
- * Utility class to map between Blender datablocks and Cycles data structures,
- * and keep track of recalc tags from the dependency graph. */
-
-template<typename K, typename T> class id_map {
- public:
- id_map(Scene *scene_) : scene(scene_)
- {
- }
-
- ~id_map()
- {
- set<T *> nodes;
-
- typename map<K, T *>::iterator jt;
- for (jt = b_map.begin(); jt != b_map.end(); jt++) {
- nodes.insert(jt->second);
- }
-
- scene->delete_nodes(nodes);
- }
-
- T *find(const BL::ID &id)
- {
- return find(id.ptr.owner_id);
- }
-
- T *find(const K &key)
- {
- if (b_map.find(key) != b_map.end()) {
- T *data = b_map[key];
- return data;
- }
-
- return NULL;
- }
-
- void set_recalc(const BL::ID &id)
- {
- b_recalc.insert(id.ptr.data);
- }
-
- void set_recalc(void *id_ptr)
- {
- b_recalc.insert(id_ptr);
- }
-
- bool has_recalc()
- {
- return !(b_recalc.empty());
- }
-
- void pre_sync()
- {
- used_set.clear();
- }
-
- /* Add new data. */
- void add(const K &key, T *data)
- {
- assert(find(key) == NULL);
- b_map[key] = data;
- used(data);
- }
-
- /* Update existing data. */
- bool update(T *data, const BL::ID &id)
- {
- return update(data, id, id);
- }
- bool update(T *data, const BL::ID &id, const BL::ID &parent)
- {
- bool recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
- if (parent.ptr.data && parent.ptr.data != id.ptr.data) {
- recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
- }
- used(data);
- return recalc;
- }
-
- /* Combined add and update as needed. */
- bool add_or_update(T **r_data, const BL::ID &id)
- {
- return add_or_update(r_data, id, id, id.ptr.owner_id);
- }
- bool add_or_update(T **r_data, const BL::ID &id, const K &key)
- {
- return add_or_update(r_data, id, id, key);
- }
- bool add_or_update(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key)
- {
- T *data = find(key);
- bool recalc;
-
- if (!data) {
- /* Add data if it didn't exist yet. */
- data = scene->create_node<T>();
- add(key, data);
- recalc = true;
- }
- else {
- /* check if updated needed. */
- recalc = update(data, id, parent);
- }
-
- *r_data = data;
- return recalc;
- }
-
- /* Combined add or update for convenience. */
-
- bool is_used(const K &key)
- {
- T *data = find(key);
- return (data) ? used_set.find(data) != used_set.end() : false;
- }
-
- void used(T *data)
- {
- /* tag data as still in use */
- used_set.insert(data);
- }
-
- void set_default(T *data)
- {
- b_map[NULL] = data;
- }
-
- void post_sync(bool do_delete = true)
- {
- map<K, T *> new_map;
- typedef pair<const K, T *> TMapPair;
- typename map<K, T *>::iterator jt;
-
- for (jt = b_map.begin(); jt != b_map.end(); jt++) {
- TMapPair &pair = *jt;
-
- if (do_delete && used_set.find(pair.second) == used_set.end()) {
- scene->delete_node(pair.second);
- }
- else {
- new_map[pair.first] = pair.second;
- }
- }
-
- used_set.clear();
- b_recalc.clear();
- b_map = new_map;
- }
-
- const map<K, T *> &key_to_scene_data()
- {
- return b_map;
- }
-
- protected:
- map<K, T *> b_map;
- set<T *> used_set;
- set<void *> b_recalc;
- Scene *scene;
-};
-
-/* Object Key
- *
- * To uniquely identify instances, we use the parent, object and persistent instance ID.
- * We also export separate object for a mesh and its particle hair. */
-
-enum { OBJECT_PERSISTENT_ID_SIZE = 8 /* MAX_DUPLI_RECUR in Blender. */ };
-
-struct ObjectKey {
- void *parent;
- int id[OBJECT_PERSISTENT_ID_SIZE];
- void *ob;
- bool use_particle_hair;
-
- ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_, bool use_particle_hair_)
- : parent(parent_), ob(ob_), use_particle_hair(use_particle_hair_)
- {
- if (id_)
- memcpy(id, id_, sizeof(id));
- else
- memset(id, 0, sizeof(id));
- }
-
- bool operator<(const ObjectKey &k) const
- {
- if (ob < k.ob) {
- return true;
- }
- else if (ob == k.ob) {
- if (parent < k.parent) {
- return true;
- }
- else if (parent == k.parent) {
- if (use_particle_hair < k.use_particle_hair) {
- return true;
- }
- else if (use_particle_hair == k.use_particle_hair) {
- return memcmp(id, k.id, sizeof(id)) < 0;
- }
- }
- }
-
- return false;
- }
-};
-
-/* Geometry Key
- *
- * We export separate geometry for a mesh and its particle hair, so key needs to
- * distinguish between them. */
-
-struct GeometryKey {
- void *id;
- Geometry::Type geometry_type;
-
- GeometryKey(void *id, Geometry::Type geometry_type) : id(id), geometry_type(geometry_type)
- {
- }
-
- bool operator<(const GeometryKey &k) const
- {
- if (id < k.id) {
- return true;
- }
- else if (id == k.id) {
- if (geometry_type < k.geometry_type) {
- return true;
- }
- }
-
- return false;
- }
-};
-
-/* Particle System Key */
-
-struct ParticleSystemKey {
- void *ob;
- int id[OBJECT_PERSISTENT_ID_SIZE];
-
- ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) : ob(ob_)
- {
- if (id_)
- memcpy(id, id_, sizeof(id));
- else
- memset(id, 0, sizeof(id));
- }
-
- bool operator<(const ParticleSystemKey &k) const
- {
- /* first id is particle index, we don't compare that */
- if (ob < k.ob)
- return true;
- else if (ob == k.ob)
- return memcmp(id + 1, k.id + 1, sizeof(int) * (OBJECT_PERSISTENT_ID_SIZE - 1)) < 0;
-
- return false;
- }
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BLENDER_ID_MAP_H__ */
diff --git a/intern/cycles/blender/blender_image.cpp b/intern/cycles/blender/blender_image.cpp
deleted file mode 100644
index f27275bd457..00000000000
--- a/intern/cycles/blender/blender_image.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "blender/blender_image.h"
-#include "blender/blender_session.h"
-#include "blender/blender_util.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Packed Images */
-
-BlenderImageLoader::BlenderImageLoader(BL::Image b_image, int frame)
- : b_image(b_image), frame(frame), free_cache(!b_image.has_data())
-{
-}
-
-bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
-{
- metadata.width = b_image.size()[0];
- metadata.height = b_image.size()[1];
- metadata.depth = 1;
- metadata.channels = b_image.channels();
-
- if (b_image.is_float()) {
- if (metadata.channels == 1) {
- metadata.type = IMAGE_DATA_TYPE_FLOAT;
- }
- else if (metadata.channels == 4) {
- metadata.type = IMAGE_DATA_TYPE_FLOAT4;
- }
- else {
- return false;
- }
-
- /* Float images are already converted on the Blender side,
- * no need to do anything in Cycles. */
- metadata.colorspace = u_colorspace_raw;
- }
- else {
- if (metadata.channels == 1) {
- metadata.type = IMAGE_DATA_TYPE_BYTE;
- }
- else if (metadata.channels == 4) {
- metadata.type = IMAGE_DATA_TYPE_BYTE4;
- }
- else {
- return false;
- }
- }
-
- return true;
-}
-
-bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t pixels_size,
- const bool associate_alpha)
-{
- const size_t num_pixels = ((size_t)metadata.width) * metadata.height;
- const int channels = metadata.channels;
- const int tile = 0; /* TODO(lukas): Support tiles here? */
-
- if (b_image.is_float()) {
- /* image data */
- float *image_pixels;
- image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile);
-
- if (image_pixels && num_pixels * channels == pixels_size) {
- memcpy(pixels, image_pixels, pixels_size * sizeof(float));
- }
- else {
- if (channels == 1) {
- memset(pixels, 0, num_pixels * sizeof(float));
- }
- else {
- const size_t num_pixels_safe = pixels_size / channels;
- float *fp = (float *)pixels;
- for (int i = 0; i < num_pixels_safe; i++, fp += channels) {
- fp[0] = 1.0f;
- fp[1] = 0.0f;
- fp[2] = 1.0f;
- if (channels == 4) {
- fp[3] = 1.0f;
- }
- }
- }
- }
-
- if (image_pixels) {
- MEM_freeN(image_pixels);
- }
- }
- else {
- unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile);
-
- if (image_pixels && num_pixels * channels == pixels_size) {
- memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
- }
- else {
- if (channels == 1) {
- memset(pixels, 0, pixels_size * sizeof(unsigned char));
- }
- else {
- const size_t num_pixels_safe = pixels_size / channels;
- unsigned char *cp = (unsigned char *)pixels;
- for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) {
- cp[0] = 255;
- cp[1] = 0;
- cp[2] = 255;
- if (channels == 4) {
- cp[3] = 255;
- }
- }
- }
- }
-
- if (image_pixels) {
- MEM_freeN(image_pixels);
- }
-
- if (associate_alpha) {
- /* Premultiply, byte images are always straight for Blender. */
- unsigned char *cp = (unsigned char *)pixels;
- for (size_t i = 0; i < num_pixels; i++, cp += channels) {
- cp[0] = (cp[0] * cp[3]) / 255;
- cp[1] = (cp[1] * cp[3]) / 255;
- cp[2] = (cp[2] * cp[3]) / 255;
- }
- }
- }
-
- /* Free image buffers to save memory during render. */
- if (free_cache) {
- b_image.buffers_free();
- }
-
- return true;
-}
-
-string BlenderImageLoader::name() const
-{
- return BL::Image(b_image).name();
-}
-
-bool BlenderImageLoader::equals(const ImageLoader &other) const
-{
- const BlenderImageLoader &other_loader = (const BlenderImageLoader &)other;
- return b_image == other_loader.b_image && frame == other_loader.frame;
-}
-
-/* Point Density */
-
-BlenderPointDensityLoader::BlenderPointDensityLoader(BL::Depsgraph b_depsgraph,
- BL::ShaderNodeTexPointDensity b_node)
- : b_depsgraph(b_depsgraph), b_node(b_node)
-{
-}
-
-bool BlenderPointDensityLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
-{
- metadata.channels = 4;
- metadata.width = b_node.resolution();
- metadata.height = metadata.width;
- metadata.depth = metadata.width;
- metadata.type = IMAGE_DATA_TYPE_FLOAT4;
- return true;
-}
-
-bool BlenderPointDensityLoader::load_pixels(const ImageMetaData &,
- void *pixels,
- const size_t,
- const bool)
-{
- int length;
- b_node.calc_point_density(b_depsgraph, &length, (float **)&pixels);
- return true;
-}
-
-void BlenderSession::builtin_images_load()
-{
- /* Force builtin images to be loaded along with Blender data sync. This
- * is needed because we may be reading from depsgraph evaluated data which
- * can be freed by Blender before Cycles reads it.
- *
- * TODO: the assumption that no further access to builtin image data will
- * happen is really weak, and likely to break in the future. We should find
- * a better solution to hand over the data directly to the image manager
- * instead of through callbacks whose timing is difficult to control. */
- ImageManager *manager = session->scene->image_manager;
- Device *device = session->device;
- manager->device_load_builtin(device, session->scene, session->progress);
-}
-
-string BlenderPointDensityLoader::name() const
-{
- return BL::ShaderNodeTexPointDensity(b_node).name();
-}
-
-bool BlenderPointDensityLoader::equals(const ImageLoader &other) const
-{
- const BlenderPointDensityLoader &other_loader = (const BlenderPointDensityLoader &)other;
- return b_node == other_loader.b_node && b_depsgraph == other_loader.b_depsgraph;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_image.h b/intern/cycles/blender/blender_image.h
deleted file mode 100644
index fddbbfd9c37..00000000000
--- a/intern/cycles/blender/blender_image.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BLENDER_IMAGE_H__
-#define __BLENDER_IMAGE_H__
-
-#include "RNA_blender_cpp.h"
-
-#include "render/image.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BlenderImageLoader : public ImageLoader {
- public:
- BlenderImageLoader(BL::Image b_image, int frame);
-
- bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
- bool load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t pixels_size,
- const bool associate_alpha) override;
- string name() const override;
- bool equals(const ImageLoader &other) const override;
-
- BL::Image b_image;
- int frame;
- bool free_cache;
-};
-
-class BlenderPointDensityLoader : public ImageLoader {
- public:
- BlenderPointDensityLoader(BL::Depsgraph depsgraph, BL::ShaderNodeTexPointDensity b_node);
-
- bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
- bool load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t pixels_size,
- const bool associate_alpha) override;
- string name() const override;
- bool equals(const ImageLoader &other) const override;
-
- BL::Depsgraph b_depsgraph;
- BL::ShaderNodeTexPointDensity b_node;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BLENDER_IMAGE_H__ */
diff --git a/intern/cycles/blender/blender_light.cpp b/intern/cycles/blender/blender_light.cpp
deleted file mode 100644
index 4df1e720dde..00000000000
--- a/intern/cycles/blender/blender_light.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-
-
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/light.h"
-
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-#include "util/util_hash.h"
-
-CCL_NAMESPACE_BEGIN
-
-void BlenderSync::sync_light(BL::Object &b_parent,
- int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
- BObjectInfo &b_ob_info,
- int random_id,
- Transform &tfm,
- bool *use_portal)
-{
- /* test if we need to sync */
- ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, false);
- BL::Light b_light(b_ob_info.object_data);
-
- Light *light = light_map.find(key);
-
- /* Check if the transform was modified, in case a linked collection is moved we do not get a
- * specific depsgraph update (T88515). This also mimics the behavior for Objects. */
- const bool tfm_updated = (light && light->get_tfm() != tfm);
-
- /* Update if either object or light data changed. */
- if (!light_map.add_or_update(&light, b_ob_info.real_object, b_parent, key) && !tfm_updated) {
- Shader *shader;
- if (!shader_map.add_or_update(&shader, b_light)) {
- if (light->get_is_portal())
- *use_portal = true;
- return;
- }
- }
-
- /* type */
- switch (b_light.type()) {
- case BL::Light::type_POINT: {
- BL::PointLight b_point_light(b_light);
- light->set_size(b_point_light.shadow_soft_size());
- light->set_light_type(LIGHT_POINT);
- break;
- }
- case BL::Light::type_SPOT: {
- BL::SpotLight b_spot_light(b_light);
- light->set_size(b_spot_light.shadow_soft_size());
- light->set_light_type(LIGHT_SPOT);
- light->set_spot_angle(b_spot_light.spot_size());
- light->set_spot_smooth(b_spot_light.spot_blend());
- break;
- }
- /* Hemi were removed from 2.8 */
- // case BL::Light::type_HEMI: {
- // light->type = LIGHT_DISTANT;
- // light->size = 0.0f;
- // break;
- // }
- case BL::Light::type_SUN: {
- BL::SunLight b_sun_light(b_light);
- light->set_angle(b_sun_light.angle());
- light->set_light_type(LIGHT_DISTANT);
- break;
- }
- case BL::Light::type_AREA: {
- BL::AreaLight b_area_light(b_light);
- light->set_size(1.0f);
- light->set_axisu(transform_get_column(&tfm, 0));
- light->set_axisv(transform_get_column(&tfm, 1));
- light->set_sizeu(b_area_light.size());
- light->set_spread(b_area_light.spread());
- switch (b_area_light.shape()) {
- case BL::AreaLight::shape_SQUARE:
- light->set_sizev(light->get_sizeu());
- light->set_round(false);
- break;
- case BL::AreaLight::shape_RECTANGLE:
- light->set_sizev(b_area_light.size_y());
- light->set_round(false);
- break;
- case BL::AreaLight::shape_DISK:
- light->set_sizev(light->get_sizeu());
- light->set_round(true);
- break;
- case BL::AreaLight::shape_ELLIPSE:
- light->set_sizev(b_area_light.size_y());
- light->set_round(true);
- break;
- }
- light->set_light_type(LIGHT_AREA);
- break;
- }
- }
-
- /* strength */
- float3 strength = get_float3(b_light.color()) * BL::PointLight(b_light).energy();
- light->set_strength(strength);
-
- /* location and (inverted!) direction */
- light->set_co(transform_get_column(&tfm, 3));
- light->set_dir(-transform_get_column(&tfm, 2));
- light->set_tfm(tfm);
-
- /* shader */
- array<Node *> used_shaders;
- find_shader(b_light, used_shaders, scene->default_light);
- light->set_shader(static_cast<Shader *>(used_shaders[0]));
-
- /* shadow */
- PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
- light->set_cast_shadow(get_boolean(clight, "cast_shadow"));
- light->set_use_mis(get_boolean(clight, "use_multiple_importance_sampling"));
-
- light->set_max_bounces(get_int(clight, "max_bounces"));
-
- if (b_ob_info.real_object != b_ob_info.iter_object) {
- light->set_random_id(random_id);
- }
- else {
- light->set_random_id(hash_uint2(hash_string(b_ob_info.real_object.name().c_str()), 0));
- }
-
- if (light->get_light_type() == LIGHT_AREA)
- light->set_is_portal(get_boolean(clight, "is_portal"));
- else
- light->set_is_portal(false);
-
- if (light->get_is_portal())
- *use_portal = true;
-
- /* visibility */
- uint visibility = object_ray_visibility(b_ob_info.real_object);
- light->set_use_camera((visibility & PATH_RAY_CAMERA) != 0);
- light->set_use_diffuse((visibility & PATH_RAY_DIFFUSE) != 0);
- light->set_use_glossy((visibility & PATH_RAY_GLOSSY) != 0);
- light->set_use_transmission((visibility & PATH_RAY_TRANSMIT) != 0);
- light->set_use_scatter((visibility & PATH_RAY_VOLUME_SCATTER) != 0);
- light->set_is_shadow_catcher(b_ob_info.real_object.is_shadow_catcher());
-
- /* tag */
- light->tag_update(scene);
-}
-
-void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
-{
- BL::World b_world = b_scene.world();
-
- if (b_world) {
- PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
-
- enum SamplingMethod { SAMPLING_NONE = 0, SAMPLING_AUTOMATIC, SAMPLING_MANUAL, SAMPLING_NUM };
- int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC);
- bool sample_as_light = (sampling_method != SAMPLING_NONE);
-
- if (sample_as_light || use_portal) {
- /* test if we need to sync */
- Light *light;
- ObjectKey key(b_world, 0, b_world, false);
-
- if (light_map.add_or_update(&light, b_world, b_world, key) || world_recalc ||
- b_world.ptr.data != world_map) {
- light->set_light_type(LIGHT_BACKGROUND);
- if (sampling_method == SAMPLING_MANUAL) {
- light->set_map_resolution(get_int(cworld, "sample_map_resolution"));
- }
- else {
- light->set_map_resolution(0);
- }
- light->set_shader(scene->default_background);
- light->set_use_mis(sample_as_light);
- light->set_max_bounces(get_int(cworld, "max_bounces"));
-
- /* force enable light again when world is resynced */
- light->set_is_enabled(true);
-
- light->tag_update(scene);
- light_map.set_recalc(b_world);
- }
- }
- }
-
- world_map = b_world.ptr.data;
- world_recalc = false;
- viewport_parameters = BlenderViewportParameters(b_v3d, use_developer_ui);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_logging.cpp b/intern/cycles/blender/blender_logging.cpp
deleted file mode 100644
index b42a1f47821..00000000000
--- a/intern/cycles/blender/blender_logging.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2011-2014 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "blender/CCL_api.h"
-#include "util/util_logging.h"
-
-void CCL_init_logging(const char *argv0)
-{
- ccl::util_logging_init(argv0);
-}
-
-void CCL_start_debug_logging()
-{
- ccl::util_logging_start();
-}
-
-void CCL_logging_verbosity_set(int verbosity)
-{
- ccl::util_logging_verbosity_set(verbosity);
-}
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
deleted file mode 100644
index 7ec430eb7fe..00000000000
--- a/intern/cycles/blender/blender_mesh.cpp
+++ /dev/null
@@ -1,1301 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/camera.h"
-#include "render/colorspace.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/scene.h"
-
-#include "blender/blender_session.h"
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-#include "subd/subd_patch.h"
-#include "subd/subd_split.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_disjoint_set.h"
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-#include "util/util_logging.h"
-#include "util/util_math.h"
-
-#include "mikktspace.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Tangent Space */
-
-struct MikkUserData {
- MikkUserData(const BL::Mesh &b_mesh,
- const char *layer_name,
- const Mesh *mesh,
- float3 *tangent,
- float *tangent_sign)
- : mesh(mesh), texface(NULL), orco(NULL), tangent(tangent), tangent_sign(tangent_sign)
- {
- const AttributeSet &attributes = (mesh->get_num_subd_faces()) ? mesh->subd_attributes :
- mesh->attributes;
-
- Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
- vertex_normal = attr_vN->data_float3();
-
- if (layer_name == NULL) {
- Attribute *attr_orco = attributes.find(ATTR_STD_GENERATED);
-
- if (attr_orco) {
- orco = attr_orco->data_float3();
- mesh_texture_space(*(BL::Mesh *)&b_mesh, orco_loc, orco_size);
- }
- }
- else {
- Attribute *attr_uv = attributes.find(ustring(layer_name));
- if (attr_uv != NULL) {
- texface = attr_uv->data_float2();
- }
- }
- }
-
- const Mesh *mesh;
- int num_faces;
-
- float3 *vertex_normal;
- float2 *texface;
- float3 *orco;
- float3 orco_loc, orco_size;
-
- float3 *tangent;
- float *tangent_sign;
-};
-
-static int mikk_get_num_faces(const SMikkTSpaceContext *context)
-{
- const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
- if (userdata->mesh->get_num_subd_faces()) {
- return userdata->mesh->get_num_subd_faces();
- }
- else {
- return userdata->mesh->num_triangles();
- }
-}
-
-static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const int face_num)
-{
- const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
- if (userdata->mesh->get_num_subd_faces()) {
- const Mesh *mesh = userdata->mesh;
- return mesh->get_subd_num_corners()[face_num];
- }
- else {
- return 3;
- }
-}
-
-static int mikk_vertex_index(const Mesh *mesh, const int face_num, const int vert_num)
-{
- if (mesh->get_num_subd_faces()) {
- const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
- return mesh->get_subd_face_corners()[face.start_corner + vert_num];
- }
- else {
- return mesh->get_triangles()[face_num * 3 + vert_num];
- }
-}
-
-static int mikk_corner_index(const Mesh *mesh, const int face_num, const int vert_num)
-{
- if (mesh->get_num_subd_faces()) {
- const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
- return face.start_corner + vert_num;
- }
- else {
- return face_num * 3 + vert_num;
- }
-}
-
-static void mikk_get_position(const SMikkTSpaceContext *context,
- float P[3],
- const int face_num,
- const int vert_num)
-{
- const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
- const Mesh *mesh = userdata->mesh;
- const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
- const float3 vP = mesh->get_verts()[vertex_index];
- P[0] = vP.x;
- P[1] = vP.y;
- P[2] = vP.z;
-}
-
-static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context,
- float uv[2],
- const int face_num,
- const int vert_num)
-{
- const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
- const Mesh *mesh = userdata->mesh;
- if (userdata->texface != NULL) {
- const int corner_index = mikk_corner_index(mesh, face_num, vert_num);
- float2 tfuv = userdata->texface[corner_index];
- uv[0] = tfuv.x;
- uv[1] = tfuv.y;
- }
- else if (userdata->orco != NULL) {
- const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
- const float3 orco_loc = userdata->orco_loc;
- const float3 orco_size = userdata->orco_size;
- const float3 orco = (userdata->orco[vertex_index] + orco_loc) / orco_size;
-
- const float2 tmp = map_to_sphere(orco);
- uv[0] = tmp.x;
- uv[1] = tmp.y;
- }
- else {
- uv[0] = 0.0f;
- uv[1] = 0.0f;
- }
-}
-
-static void mikk_get_normal(const SMikkTSpaceContext *context,
- float N[3],
- const int face_num,
- const int vert_num)
-{
- const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
- const Mesh *mesh = userdata->mesh;
- float3 vN;
- if (mesh->get_num_subd_faces()) {
- const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
- if (face.smooth) {
- const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
- vN = userdata->vertex_normal[vertex_index];
- }
- else {
- vN = face.normal(mesh);
- }
- }
- else {
- if (mesh->get_smooth()[face_num]) {
- const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
- vN = userdata->vertex_normal[vertex_index];
- }
- else {
- const Mesh::Triangle tri = mesh->get_triangle(face_num);
- vN = tri.compute_normal(&mesh->get_verts()[0]);
- }
- }
- N[0] = vN.x;
- N[1] = vN.y;
- N[2] = vN.z;
-}
-
-static void mikk_set_tangent_space(const SMikkTSpaceContext *context,
- const float T[],
- const float sign,
- const int face_num,
- const int vert_num)
-{
- MikkUserData *userdata = (MikkUserData *)context->m_pUserData;
- const Mesh *mesh = userdata->mesh;
- const int corner_index = mikk_corner_index(mesh, face_num, vert_num);
- userdata->tangent[corner_index] = make_float3(T[0], T[1], T[2]);
- if (userdata->tangent_sign != NULL) {
- userdata->tangent_sign[corner_index] = sign;
- }
-}
-
-static void mikk_compute_tangents(
- const BL::Mesh &b_mesh, const char *layer_name, Mesh *mesh, bool need_sign, bool active_render)
-{
- /* Create tangent attributes. */
- AttributeSet &attributes = (mesh->get_num_subd_faces()) ? mesh->subd_attributes :
- mesh->attributes;
- Attribute *attr;
- ustring name;
- if (layer_name != NULL) {
- name = ustring((string(layer_name) + ".tangent").c_str());
- }
- else {
- name = ustring("orco.tangent");
- }
- if (active_render) {
- attr = attributes.add(ATTR_STD_UV_TANGENT, name);
- }
- else {
- attr = attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
- }
- float3 *tangent = attr->data_float3();
- /* Create bitangent sign attribute. */
- float *tangent_sign = NULL;
- if (need_sign) {
- Attribute *attr_sign;
- ustring name_sign;
- if (layer_name != NULL) {
- name_sign = ustring((string(layer_name) + ".tangent_sign").c_str());
- }
- else {
- name_sign = ustring("orco.tangent_sign");
- }
-
- if (active_render) {
- attr_sign = attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
- }
- else {
- attr_sign = attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
- }
- tangent_sign = attr_sign->data_float();
- }
- /* Setup userdata. */
- MikkUserData userdata(b_mesh, layer_name, mesh, tangent, tangent_sign);
- /* Setup interface. */
- SMikkTSpaceInterface sm_interface;
- memset(&sm_interface, 0, sizeof(sm_interface));
- sm_interface.m_getNumFaces = mikk_get_num_faces;
- sm_interface.m_getNumVerticesOfFace = mikk_get_num_verts_of_face;
- sm_interface.m_getPosition = mikk_get_position;
- sm_interface.m_getTexCoord = mikk_get_texture_coordinate;
- sm_interface.m_getNormal = mikk_get_normal;
- sm_interface.m_setTSpaceBasic = mikk_set_tangent_space;
- /* Setup context. */
- SMikkTSpaceContext context;
- memset(&context, 0, sizeof(context));
- context.m_pUserData = &userdata;
- context.m_pInterface = &sm_interface;
- /* Compute tangents. */
- genTangSpaceDefault(&context);
-}
-
-/* Create sculpt vertex color attributes. */
-static void attr_create_sculpt_vertex_color(Scene *scene,
- Mesh *mesh,
- BL::Mesh &b_mesh,
- bool subdivision)
-{
- for (BL::MeshVertColorLayer &l : b_mesh.sculpt_vertex_colors) {
- const bool active_render = l.active_render();
- AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
- ustring vcol_name = ustring(l.name().c_str());
-
- const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
- mesh->need_attribute(scene, vcol_std);
-
- if (!need_vcol) {
- continue;
- }
-
- AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
- Attribute *vcol_attr = attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_VERTEX);
- vcol_attr->std = vcol_std;
-
- float4 *cdata = vcol_attr->data_float4();
- int numverts = b_mesh.vertices.length();
-
- for (int i = 0; i < numverts; i++) {
- *(cdata++) = get_float4(l.data[i].color());
- }
- }
-}
-
-template<typename TypeInCycles, typename GetValueAtIndex>
-static void fill_generic_attribute(BL::Mesh &b_mesh,
- TypeInCycles *data,
- const AttributeElement element,
- const GetValueAtIndex &get_value_at_index)
-{
- switch (element) {
- case ATTR_ELEMENT_CORNER: {
- for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
- const int index = t.index() * 3;
- BL::Array<int, 3> loops = t.loops();
- data[index] = get_value_at_index(loops[0]);
- data[index + 1] = get_value_at_index(loops[1]);
- data[index + 2] = get_value_at_index(loops[2]);
- }
- break;
- }
- case ATTR_ELEMENT_VERTEX: {
- const int num_verts = b_mesh.vertices.length();
- for (int i = 0; i < num_verts; i++) {
- data[i] = get_value_at_index(i);
- }
- break;
- }
- case ATTR_ELEMENT_FACE: {
- for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
- data[t.index()] = get_value_at_index(t.polygon_index());
- }
- break;
- }
- default: {
- assert(false);
- break;
- }
- }
-}
-
-static void attr_create_motion(Mesh *mesh, BL::Attribute &b_attribute, const float motion_scale)
-{
- if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
- (b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) {
- return;
- }
-
- BL::FloatVectorAttribute b_vector_attribute(b_attribute);
- const int numverts = mesh->get_verts().size();
-
- /* Find or add attribute */
- float3 *P = &mesh->get_verts()[0];
- Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if (!attr_mP) {
- attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
- }
-
- /* Only export previous and next frame, we don't have any in between data. */
- float motion_times[2] = {-1.0f, 1.0f};
- for (int step = 0; step < 2; step++) {
- const float relative_time = motion_times[step] * 0.5f * motion_scale;
- float3 *mP = attr_mP->data_float3() + step * numverts;
-
- for (int i = 0; i < numverts; i++) {
- mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time;
- }
- }
-}
-
-static void attr_create_generic(Scene *scene,
- Mesh *mesh,
- BL::Mesh &b_mesh,
- const bool subdivision,
- const bool need_motion,
- const float motion_scale)
-{
- if (subdivision) {
- /* TODO: Handle subdivision correctly. */
- return;
- }
- AttributeSet &attributes = mesh->attributes;
- static const ustring u_velocity("velocity");
-
- for (BL::Attribute &b_attribute : b_mesh.attributes) {
- const ustring name{b_attribute.name().c_str()};
-
- if (need_motion && name == u_velocity) {
- attr_create_motion(mesh, b_attribute, motion_scale);
- }
-
- if (!mesh->need_attribute(scene, name)) {
- continue;
- }
- if (attributes.find(name)) {
- continue;
- }
-
- const BL::Attribute::domain_enum b_domain = b_attribute.domain();
- const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type();
-
- AttributeElement element = ATTR_ELEMENT_NONE;
- switch (b_domain) {
- case BL::Attribute::domain_CORNER:
- element = ATTR_ELEMENT_CORNER;
- break;
- case BL::Attribute::domain_POINT:
- element = ATTR_ELEMENT_VERTEX;
- break;
- case BL::Attribute::domain_FACE:
- element = ATTR_ELEMENT_FACE;
- break;
- default:
- break;
- }
- if (element == ATTR_ELEMENT_NONE) {
- /* Not supported. */
- continue;
- }
- switch (b_data_type) {
- case BL::Attribute::data_type_FLOAT: {
- BL::FloatAttribute b_float_attribute{b_attribute};
- Attribute *attr = attributes.add(name, TypeFloat, element);
- float *data = attr->data_float();
- fill_generic_attribute(
- b_mesh, data, element, [&](int i) { return b_float_attribute.data[i].value(); });
- break;
- }
- case BL::Attribute::data_type_BOOLEAN: {
- BL::BoolAttribute b_bool_attribute{b_attribute};
- Attribute *attr = attributes.add(name, TypeFloat, element);
- float *data = attr->data_float();
- fill_generic_attribute(
- b_mesh, data, element, [&](int i) { return (float)b_bool_attribute.data[i].value(); });
- break;
- }
- case BL::Attribute::data_type_INT: {
- BL::IntAttribute b_int_attribute{b_attribute};
- Attribute *attr = attributes.add(name, TypeFloat, element);
- float *data = attr->data_float();
- fill_generic_attribute(
- b_mesh, data, element, [&](int i) { return (float)b_int_attribute.data[i].value(); });
- break;
- }
- case BL::Attribute::data_type_FLOAT_VECTOR: {
- BL::FloatVectorAttribute b_vector_attribute{b_attribute};
- Attribute *attr = attributes.add(name, TypeVector, element);
- float3 *data = attr->data_float3();
- fill_generic_attribute(b_mesh, data, element, [&](int i) {
- BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
- return make_float3(v[0], v[1], v[2]);
- });
- break;
- }
- case BL::Attribute::data_type_FLOAT_COLOR: {
- BL::FloatColorAttribute b_color_attribute{b_attribute};
- Attribute *attr = attributes.add(name, TypeRGBA, element);
- float4 *data = attr->data_float4();
- fill_generic_attribute(b_mesh, data, element, [&](int i) {
- BL::Array<float, 4> v = b_color_attribute.data[i].color();
- return make_float4(v[0], v[1], v[2], v[3]);
- });
- break;
- }
- case BL::Attribute::data_type_FLOAT2: {
- BL::Float2Attribute b_float2_attribute{b_attribute};
- Attribute *attr = attributes.add(name, TypeFloat2, element);
- float2 *data = attr->data_float2();
- fill_generic_attribute(b_mesh, data, element, [&](int i) {
- BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
- return make_float2(v[0], v[1]);
- });
- break;
- }
- default:
- /* Not supported. */
- break;
- }
- }
-}
-
-/* Create vertex color attributes. */
-static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
-{
- for (BL::MeshLoopColorLayer &l : b_mesh.vertex_colors) {
- const bool active_render = l.active_render();
- AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
- ustring vcol_name = ustring(l.name().c_str());
-
- const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
- mesh->need_attribute(scene, vcol_std);
-
- if (!need_vcol) {
- continue;
- }
-
- Attribute *vcol_attr = NULL;
-
- if (subdivision) {
- if (active_render) {
- vcol_attr = mesh->subd_attributes.add(vcol_std, vcol_name);
- }
- else {
- vcol_attr = mesh->subd_attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
- }
-
- uchar4 *cdata = vcol_attr->data_uchar4();
-
- for (BL::MeshPolygon &p : b_mesh.polygons) {
- int n = p.loop_total();
- for (int i = 0; i < n; i++) {
- float4 color = get_float4(l.data[p.loop_start() + i].color());
- /* Compress/encode vertex color using the sRGB curve. */
- *(cdata++) = color_float4_to_uchar4(color);
- }
- }
- }
- else {
- if (active_render) {
- vcol_attr = mesh->attributes.add(vcol_std, vcol_name);
- }
- else {
- vcol_attr = mesh->attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
- }
-
- uchar4 *cdata = vcol_attr->data_uchar4();
-
- for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
- int3 li = get_int3(t.loops());
- float4 c1 = get_float4(l.data[li[0]].color());
- float4 c2 = get_float4(l.data[li[1]].color());
- float4 c3 = get_float4(l.data[li[2]].color());
-
- /* Compress/encode vertex color using the sRGB curve. */
- cdata[0] = color_float4_to_uchar4(c1);
- cdata[1] = color_float4_to_uchar4(c2);
- cdata[2] = color_float4_to_uchar4(c3);
-
- cdata += 3;
- }
- }
- }
-}
-
-/* Create uv map attributes. */
-static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
-{
- if (b_mesh.uv_layers.length() != 0) {
- for (BL::MeshUVLoopLayer &l : b_mesh.uv_layers) {
- const bool active_render = l.active_render();
- AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
- ustring uv_name = ustring(l.name().c_str());
- AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE;
- ustring tangent_name = ustring((string(l.name().c_str()) + ".tangent").c_str());
-
- /* Denotes whether UV map was requested directly. */
- const bool need_uv = mesh->need_attribute(scene, uv_name) ||
- mesh->need_attribute(scene, uv_std);
- /* Denotes whether tangent was requested directly. */
- const bool need_tangent = mesh->need_attribute(scene, tangent_name) ||
- (active_render && mesh->need_attribute(scene, tangent_std));
-
- /* UV map */
- /* NOTE: We create temporary UV layer if its needed for tangent but
- * wasn't requested by other nodes in shaders.
- */
- Attribute *uv_attr = NULL;
- if (need_uv || need_tangent) {
- if (active_render) {
- uv_attr = mesh->attributes.add(uv_std, uv_name);
- }
- else {
- uv_attr = mesh->attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
- }
-
- float2 *fdata = uv_attr->data_float2();
-
- for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
- int3 li = get_int3(t.loops());
- fdata[0] = get_float2(l.data[li[0]].uv());
- fdata[1] = get_float2(l.data[li[1]].uv());
- fdata[2] = get_float2(l.data[li[2]].uv());
- fdata += 3;
- }
- }
-
- /* UV tangent */
- if (need_tangent) {
- AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE;
- ustring sign_name = ustring((string(l.name().c_str()) + ".tangent_sign").c_str());
- bool need_sign = (mesh->need_attribute(scene, sign_name) ||
- mesh->need_attribute(scene, sign_std));
- mikk_compute_tangents(b_mesh, l.name().c_str(), mesh, need_sign, active_render);
- }
- /* Remove temporarily created UV attribute. */
- if (!need_uv && uv_attr != NULL) {
- mesh->attributes.remove(uv_attr);
- }
- }
- }
- else if (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
- bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
- mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true);
- if (!mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
- mesh->attributes.remove(ATTR_STD_GENERATED);
- }
- }
-}
-
-static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivide_uvs)
-{
- if (b_mesh.uv_layers.length() != 0) {
- BL::Mesh::uv_layers_iterator l;
- int i = 0;
-
- for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) {
- bool active_render = l->active_render();
- AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
- ustring uv_name = ustring(l->name().c_str());
- AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE;
- ustring tangent_name = ustring((string(l->name().c_str()) + ".tangent").c_str());
-
- /* Denotes whether UV map was requested directly. */
- const bool need_uv = mesh->need_attribute(scene, uv_name) ||
- mesh->need_attribute(scene, uv_std);
- /* Denotes whether tangent was requested directly. */
- const bool need_tangent = mesh->need_attribute(scene, tangent_name) ||
- (active_render && mesh->need_attribute(scene, tangent_std));
-
- Attribute *uv_attr = NULL;
-
- /* UV map */
- if (need_uv || need_tangent) {
- if (active_render)
- uv_attr = mesh->subd_attributes.add(uv_std, uv_name);
- else
- uv_attr = mesh->subd_attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
-
- if (subdivide_uvs) {
- uv_attr->flags |= ATTR_SUBDIVIDED;
- }
-
- float2 *fdata = uv_attr->data_float2();
-
- for (BL::MeshPolygon &p : b_mesh.polygons) {
- int n = p.loop_total();
- for (int j = 0; j < n; j++) {
- *(fdata++) = get_float2(l->data[p.loop_start() + j].uv());
- }
- }
- }
-
- /* UV tangent */
- if (need_tangent) {
- AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE;
- ustring sign_name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str());
- bool need_sign = (mesh->need_attribute(scene, sign_name) ||
- mesh->need_attribute(scene, sign_std));
- mikk_compute_tangents(b_mesh, l->name().c_str(), mesh, need_sign, active_render);
- }
- /* Remove temporarily created UV attribute. */
- if (!need_uv && uv_attr != NULL) {
- mesh->subd_attributes.remove(uv_attr);
- }
- }
- }
- else if (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
- bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
- mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true);
- if (!mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
- mesh->subd_attributes.remove(ATTR_STD_GENERATED);
- }
- }
-}
-
-/* Create vertex pointiness attributes. */
-
-/* Compare vertices by sum of their coordinates. */
-class VertexAverageComparator {
- public:
- VertexAverageComparator(const array<float3> &verts) : verts_(verts)
- {
- }
-
- bool operator()(const int &vert_idx_a, const int &vert_idx_b)
- {
- const float3 &vert_a = verts_[vert_idx_a];
- const float3 &vert_b = verts_[vert_idx_b];
- if (vert_a == vert_b) {
- /* Special case for doubles, so we ensure ordering. */
- return vert_idx_a > vert_idx_b;
- }
- const float x1 = vert_a.x + vert_a.y + vert_a.z;
- const float x2 = vert_b.x + vert_b.y + vert_b.z;
- return x1 < x2;
- }
-
- protected:
- const array<float3> &verts_;
-};
-
-static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
-{
- if (!mesh->need_attribute(scene, ATTR_STD_POINTINESS)) {
- return;
- }
- const int num_verts = b_mesh.vertices.length();
- if (num_verts == 0) {
- return;
- }
- /* STEP 1: Find out duplicated vertices and point duplicates to a single
- * original vertex.
- */
- vector<int> sorted_vert_indeices(num_verts);
- for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
- sorted_vert_indeices[vert_index] = vert_index;
- }
- VertexAverageComparator compare(mesh->get_verts());
- sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare);
- /* This array stores index of the original vertex for the given vertex
- * index.
- */
- vector<int> vert_orig_index(num_verts);
- for (int sorted_vert_index = 0; sorted_vert_index < num_verts; ++sorted_vert_index) {
- const int vert_index = sorted_vert_indeices[sorted_vert_index];
- const float3 &vert_co = mesh->get_verts()[vert_index];
- bool found = false;
- for (int other_sorted_vert_index = sorted_vert_index + 1; other_sorted_vert_index < num_verts;
- ++other_sorted_vert_index) {
- const int other_vert_index = sorted_vert_indeices[other_sorted_vert_index];
- const float3 &other_vert_co = mesh->get_verts()[other_vert_index];
- /* We are too far away now, we wouldn't have duplicate. */
- if ((other_vert_co.x + other_vert_co.y + other_vert_co.z) -
- (vert_co.x + vert_co.y + vert_co.z) >
- 3 * FLT_EPSILON) {
- break;
- }
- /* Found duplicate. */
- if (len_squared(other_vert_co - vert_co) < FLT_EPSILON) {
- found = true;
- vert_orig_index[vert_index] = other_vert_index;
- break;
- }
- }
- if (!found) {
- vert_orig_index[vert_index] = vert_index;
- }
- }
- /* Make sure we always points to the very first orig vertex. */
- for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
- int orig_index = vert_orig_index[vert_index];
- while (orig_index != vert_orig_index[orig_index]) {
- orig_index = vert_orig_index[orig_index];
- }
- vert_orig_index[vert_index] = orig_index;
- }
- sorted_vert_indeices.free_memory();
- /* STEP 2: Calculate vertex normals taking into account their possible
- * duplicates which gets "welded" together.
- */
- vector<float3> vert_normal(num_verts, zero_float3());
- /* First we accumulate all vertex normals in the original index. */
- for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
- const float3 normal = get_float3(b_mesh.vertices[vert_index].normal());
- const int orig_index = vert_orig_index[vert_index];
- vert_normal[orig_index] += normal;
- }
- /* Then we normalize the accumulated result and flush it to all duplicates
- * as well.
- */
- for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
- const int orig_index = vert_orig_index[vert_index];
- vert_normal[vert_index] = normalize(vert_normal[orig_index]);
- }
- /* STEP 3: Calculate pointiness using single ring neighborhood. */
- vector<int> counter(num_verts, 0);
- vector<float> raw_data(num_verts, 0.0f);
- vector<float3> edge_accum(num_verts, zero_float3());
- BL::Mesh::edges_iterator e;
- EdgeMap visited_edges;
- int edge_index = 0;
- memset(&counter[0], 0, sizeof(int) * counter.size());
- for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) {
- const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]],
- v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]];
- if (visited_edges.exists(v0, v1)) {
- continue;
- }
- visited_edges.insert(v0, v1);
- float3 co0 = get_float3(b_mesh.vertices[v0].co()), co1 = get_float3(b_mesh.vertices[v1].co());
- float3 edge = normalize(co1 - co0);
- edge_accum[v0] += edge;
- edge_accum[v1] += -edge;
- ++counter[v0];
- ++counter[v1];
- }
- for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
- const int orig_index = vert_orig_index[vert_index];
- if (orig_index != vert_index) {
- /* Skip duplicates, they'll be overwritten later on. */
- continue;
- }
- if (counter[vert_index] > 0) {
- const float3 normal = vert_normal[vert_index];
- const float angle = safe_acosf(dot(normal, edge_accum[vert_index] / counter[vert_index]));
- raw_data[vert_index] = angle * M_1_PI_F;
- }
- else {
- raw_data[vert_index] = 0.0f;
- }
- }
- /* STEP 3: Blur vertices to approximate 2 ring neighborhood. */
- AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
- Attribute *attr = attributes.add(ATTR_STD_POINTINESS);
- float *data = attr->data_float();
- memcpy(data, &raw_data[0], sizeof(float) * raw_data.size());
- memset(&counter[0], 0, sizeof(int) * counter.size());
- edge_index = 0;
- visited_edges.clear();
- for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) {
- const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]],
- v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]];
- if (visited_edges.exists(v0, v1)) {
- continue;
- }
- visited_edges.insert(v0, v1);
- data[v0] += raw_data[v1];
- data[v1] += raw_data[v0];
- ++counter[v0];
- ++counter[v1];
- }
- for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
- data[vert_index] /= counter[vert_index] + 1;
- }
- /* STEP 4: Copy attribute to the duplicated vertices. */
- for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
- const int orig_index = vert_orig_index[vert_index];
- data[vert_index] = data[orig_index];
- }
-}
-
-/* The Random Per Island attribute is a random float associated with each
- * connected component (island) of the mesh. The attribute is computed by
- * first classifying the vertices into different sets using a Disjoint Set
- * data structure. Then the index of the root of each vertex (Which is the
- * representative of the set the vertex belongs to) is hashed and stored.
- *
- * We are using a face attribute to avoid interpolation during rendering,
- * allowing the user to safely hash the output further. Had we used vertex
- * attribute, the interpolation will introduce very slight variations,
- * making the output unsafe to hash. */
-static void attr_create_random_per_island(Scene *scene,
- Mesh *mesh,
- BL::Mesh &b_mesh,
- bool subdivision)
-{
- if (!mesh->need_attribute(scene, ATTR_STD_RANDOM_PER_ISLAND)) {
- return;
- }
-
- int number_of_vertices = b_mesh.vertices.length();
- if (number_of_vertices == 0) {
- return;
- }
-
- DisjointSet vertices_sets(number_of_vertices);
-
- for (BL::MeshEdge &e : b_mesh.edges) {
- vertices_sets.join(e.vertices()[0], e.vertices()[1]);
- }
-
- AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
- Attribute *attribute = attributes.add(ATTR_STD_RANDOM_PER_ISLAND);
- float *data = attribute->data_float();
-
- if (!subdivision) {
- for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
- data[t.index()] = hash_uint_to_float(vertices_sets.find(t.vertices()[0]));
- }
- }
- else {
- for (BL::MeshPolygon &p : b_mesh.polygons) {
- data[p.index()] = hash_uint_to_float(vertices_sets.find(p.vertices()[0]));
- }
- }
-}
-
-/* Create Mesh */
-
-static void create_mesh(Scene *scene,
- Mesh *mesh,
- BL::Mesh &b_mesh,
- const array<Node *> &used_shaders,
- const bool need_motion,
- const float motion_scale,
- const bool subdivision = false,
- const bool subdivide_uvs = true)
-{
- /* count vertices and faces */
- int numverts = b_mesh.vertices.length();
- int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length();
- int numtris = 0;
- int numcorners = 0;
- int numngons = 0;
- bool use_loop_normals = b_mesh.use_auto_smooth() &&
- (mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK);
-
- /* If no faces, create empty mesh. */
- if (numfaces == 0) {
- return;
- }
-
- if (!subdivision) {
- numtris = numfaces;
- }
- else {
- for (BL::MeshPolygon &p : b_mesh.polygons) {
- numngons += (p.loop_total() == 4) ? 0 : 1;
- numcorners += p.loop_total();
- }
- }
-
- /* allocate memory */
- if (subdivision) {
- mesh->reserve_subd_faces(numfaces, numngons, numcorners);
- }
-
- mesh->reserve_mesh(numverts, numtris);
-
- /* create vertex coordinates and normals */
- BL::Mesh::vertices_iterator v;
- for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
- mesh->add_vertex(get_float3(v->co()));
-
- AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
- Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL);
- float3 *N = attr_N->data_float3();
-
- for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
- *N = get_float3(v->normal());
- N = attr_N->data_float3();
-
- /* create generated coordinates from undeformed coordinates */
- const bool need_default_tangent = (subdivision == false) && (b_mesh.uv_layers.length() == 0) &&
- (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT));
- if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) {
- Attribute *attr = attributes.add(ATTR_STD_GENERATED);
- attr->flags |= ATTR_SUBDIVIDED;
-
- float3 loc, size;
- mesh_texture_space(b_mesh, loc, size);
-
- float3 *generated = attr->data_float3();
- size_t i = 0;
-
- for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) {
- generated[i++] = get_float3(v->undeformed_co()) * size - loc;
- }
- }
-
- /* create faces */
- if (!subdivision) {
- for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
- BL::MeshPolygon p = b_mesh.polygons[t.polygon_index()];
- int3 vi = get_int3(t.vertices());
-
- int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
- bool smooth = p.use_smooth() || use_loop_normals;
-
- if (use_loop_normals) {
- BL::Array<float, 9> loop_normals = t.split_normals();
- for (int i = 0; i < 3; i++) {
- N[vi[i]] = make_float3(
- loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);
- }
- }
-
- /* Create triangles.
- *
- * NOTE: Autosmooth is already taken care about.
- */
- mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
- }
- }
- else {
- vector<int> vi;
-
- for (BL::MeshPolygon &p : b_mesh.polygons) {
- int n = p.loop_total();
- int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
- bool smooth = p.use_smooth() || use_loop_normals;
-
- vi.resize(n);
- for (int i = 0; i < n; i++) {
- /* NOTE: Autosmooth is already taken care about. */
- vi[i] = b_mesh.loops[p.loop_start() + i].vertex_index();
- }
-
- /* create subd faces */
- mesh->add_subd_face(&vi[0], n, shader, smooth);
- }
- }
-
- /* Create all needed attributes.
- * The calculate functions will check whether they're needed or not.
- */
- attr_create_pointiness(scene, mesh, b_mesh, subdivision);
- attr_create_vertex_color(scene, mesh, b_mesh, subdivision);
- attr_create_sculpt_vertex_color(scene, mesh, b_mesh, subdivision);
- attr_create_random_per_island(scene, mesh, b_mesh, subdivision);
- attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale);
-
- if (subdivision) {
- attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs);
- }
- else {
- attr_create_uv_map(scene, mesh, b_mesh);
- }
-
- /* For volume objects, create a matrix to transform from object space to
- * mesh texture space. this does not work with deformations but that can
- * probably only be done well with a volume grid mapping of coordinates. */
- if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
- Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
- Transform *tfm = attr->data_transform();
-
- float3 loc, size;
- mesh_texture_space(b_mesh, loc, size);
-
- *tfm = transform_translate(-loc) * transform_scale(size);
- }
-}
-
-static void create_subd_mesh(Scene *scene,
- Mesh *mesh,
- BObjectInfo &b_ob_info,
- BL::Mesh &b_mesh,
- const array<Node *> &used_shaders,
- const bool need_motion,
- const float motion_scale,
- float dicing_rate,
- int max_subdivisions)
-{
- BL::Object b_ob = b_ob_info.real_object;
-
- BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]);
- bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE;
-
- create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true, subdivide_uvs);
-
- /* export creases */
- size_t num_creases = 0;
-
- for (BL::MeshEdge &e : b_mesh.edges) {
- if (e.crease() != 0.0f) {
- num_creases++;
- }
- }
-
- mesh->reserve_subd_creases(num_creases);
-
- for (BL::MeshEdge &e : b_mesh.edges) {
- if (e.crease() != 0.0f) {
- mesh->add_crease(e.vertices()[0], e.vertices()[1], e.crease());
- }
- }
-
- /* set subd params */
- PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
- float subd_dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
-
- mesh->set_subd_dicing_rate(subd_dicing_rate);
- mesh->set_subd_max_level(max_subdivisions);
- mesh->set_subd_objecttoworld(get_transform(b_ob.matrix_world()));
-}
-
-/* Sync */
-
-/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
- * things like velocity from cache modifier, fluid simulation).
- *
- * NOTE: This code is run prior to object motion blur initialization. so can not access properties
- * set by `sync_object_motion_init()`. */
-static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
-{
- const Scene::MotionType need_motion = scene->need_motion();
- if (need_motion == Scene::MOTION_NONE) {
- /* Simple case: neither motion pass nor motion blur is needed, no need in the motion related
- * attributes. */
- return false;
- }
-
- if (need_motion == Scene::MOTION_BLUR) {
- /* A bit tricky and implicit case:
- * - Motion blur is enabled in the scene, which implies specific number of time steps for
- * objects.
- * - If the object has motion blur disabled on it, it will have 0 time steps.
- * - Motion attribute expects non-zero time steps.
- *
- * Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
- PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
- const bool use_motion = get_boolean(cobject, "use_motion_blur");
- if (!use_motion) {
- return false;
- }
- }
-
- /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object
- * level. */
- return true;
-}
-
-void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh)
-{
- /* make a copy of the shaders as the caller in the main thread still need them for syncing the
- * attributes */
- array<Node *> used_shaders = mesh->get_used_shaders();
-
- Mesh new_mesh;
- new_mesh.set_used_shaders(used_shaders);
-
- if (view_layer.use_surfaces) {
- /* Adaptive subdivision setup. Not for baking since that requires
- * exact mapping to the Blender mesh. */
- if (!scene->bake_manager->get_baking()) {
- new_mesh.set_subdivision_type(
- object_subdivision_type(b_ob_info.real_object, preview, experimental));
- }
-
- /* For some reason, meshes do not need this... */
- bool need_undeformed = new_mesh.need_attribute(scene, ATTR_STD_GENERATED);
- BL::Mesh b_mesh = object_to_mesh(
- b_data, b_ob_info, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type());
-
- if (b_mesh) {
- /* Motion blur attribute is relative to seconds, we need it relative to frames. */
- const bool need_motion = mesh_need_motion_attribute(b_ob_info, scene);
- const float motion_scale = (need_motion) ?
- scene->motion_shutter_time() /
- (b_scene.render().fps() / b_scene.render().fps_base()) :
- 0.0f;
-
- /* Sync mesh itself. */
- if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE)
- create_subd_mesh(scene,
- &new_mesh,
- b_ob_info,
- b_mesh,
- new_mesh.get_used_shaders(),
- need_motion,
- motion_scale,
- dicing_rate,
- max_subdivisions);
- else
- create_mesh(scene,
- &new_mesh,
- b_mesh,
- new_mesh.get_used_shaders(),
- need_motion,
- motion_scale,
- false);
-
- free_object_to_mesh(b_data, b_ob_info, b_mesh);
- }
- }
-
- /* update original sockets */
-
- mesh->clear_non_sockets();
-
- for (const SocketType &socket : new_mesh.type->inputs) {
- /* Those sockets are updated in sync_object, so do not modify them. */
- if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
- socket.name == "used_shaders") {
- continue;
- }
- mesh->set_value(socket, new_mesh, socket);
- }
-
- mesh->attributes.update(std::move(new_mesh.attributes));
- mesh->subd_attributes.update(std::move(new_mesh.subd_attributes));
-
- mesh->set_num_subd_faces(new_mesh.get_num_subd_faces());
-
- /* tag update */
- bool rebuild = (mesh->triangles_is_modified()) || (mesh->subd_num_corners_is_modified()) ||
- (mesh->subd_shader_is_modified()) || (mesh->subd_smooth_is_modified()) ||
- (mesh->subd_ptex_offset_is_modified()) ||
- (mesh->subd_start_corner_is_modified()) ||
- (mesh->subd_face_corners_is_modified());
-
- mesh->tag_update(scene, rebuild);
-}
-
-void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
- BObjectInfo &b_ob_info,
- Mesh *mesh,
- int motion_step)
-{
- /* Skip if no vertices were exported. */
- size_t numverts = mesh->get_verts().size();
- if (numverts == 0) {
- return;
- }
-
- /* Skip objects without deforming modifiers. this is not totally reliable,
- * would need a more extensive check to see which objects are animated. */
- BL::Mesh b_mesh(PointerRNA_NULL);
- if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
- /* get derived mesh */
- b_mesh = object_to_mesh(b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
- }
-
- const std::string ob_name = b_ob_info.real_object.name();
-
- /* TODO(sergey): Perform preliminary check for number of vertices. */
- if (b_mesh) {
- /* Export deformed coordinates. */
- /* Find attributes. */
- Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
- Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
- bool new_attribute = false;
- /* Add new attributes if they don't exist already. */
- if (!attr_mP) {
- attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
- if (attr_N)
- attr_mN = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
-
- new_attribute = true;
- }
- /* Load vertex data from mesh. */
- float3 *mP = attr_mP->data_float3() + motion_step * numverts;
- float3 *mN = (attr_mN) ? attr_mN->data_float3() + motion_step * numverts : NULL;
- /* NOTE: We don't copy more that existing amount of vertices to prevent
- * possible memory corruption.
- */
- BL::Mesh::vertices_iterator v;
- int i = 0;
- for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i) {
- mP[i] = get_float3(v->co());
- if (mN)
- mN[i] = get_float3(v->normal());
- }
- if (new_attribute) {
- /* In case of new attribute, we verify if there really was any motion. */
- if (b_mesh.vertices.length() != numverts ||
- memcmp(mP, &mesh->get_verts()[0], sizeof(float3) * numverts) == 0) {
- /* no motion, remove attributes again */
- if (b_mesh.vertices.length() != numverts) {
- VLOG(1) << "Topology differs, disabling motion blur for object " << ob_name;
- }
- else {
- VLOG(1) << "No actual deformation motion for object " << ob_name;
- }
- mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
- if (attr_mN)
- mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
- }
- else if (motion_step > 0) {
- VLOG(1) << "Filling deformation motion for object " << ob_name;
- /* motion, fill up previous steps that we might have skipped because
- * they had no motion, but we need them anyway now */
- float3 *P = &mesh->get_verts()[0];
- float3 *N = (attr_N) ? attr_N->data_float3() : NULL;
- for (int step = 0; step < motion_step; step++) {
- memcpy(attr_mP->data_float3() + step * numverts, P, sizeof(float3) * numverts);
- if (attr_mN)
- memcpy(attr_mN->data_float3() + step * numverts, N, sizeof(float3) * numverts);
- }
- }
- }
- else {
- if (b_mesh.vertices.length() != numverts) {
- VLOG(1) << "Topology differs, discarding motion blur for object " << ob_name << " at time "
- << motion_step;
- memcpy(mP, &mesh->get_verts()[0], sizeof(float3) * numverts);
- if (mN != NULL) {
- memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts);
- }
- }
- }
-
- free_object_to_mesh(b_data, b_ob_info, b_mesh);
- return;
- }
-
- /* No deformation on this frame, copy coordinates if other frames did have it. */
- mesh->copy_center_to_motion_step(motion_step);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
deleted file mode 100644
index 4b1c4edef7e..00000000000
--- a/intern/cycles/blender/blender_object.cpp
+++ /dev/null
@@ -1,769 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/alembic.h"
-#include "render/camera.h"
-#include "render/graph.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/nodes.h"
-#include "render/object.h"
-#include "render/particles.h"
-#include "render/scene.h"
-#include "render/shader.h"
-
-#include "blender/blender_object_cull.h"
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-#include "util/util_logging.h"
-#include "util/util_task.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Utilities */
-
-bool BlenderSync::BKE_object_is_modified(BL::Object &b_ob)
-{
- /* test if we can instance or if the object is modified */
- if (b_ob.type() == BL::Object::type_META) {
- /* multi-user and dupli metaballs are fused, can't instance */
- return true;
- }
- else if (ccl::BKE_object_is_modified(b_ob, b_scene, preview)) {
- /* modifiers */
- return true;
- }
- else {
- /* object level material links */
- for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
- if (b_slot.link() == BL::MaterialSlot::link_OBJECT) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool BlenderSync::object_is_geometry(BL::Object &b_ob)
-{
- BL::ID b_ob_data = b_ob.data();
-
- if (!b_ob_data) {
- return false;
- }
-
- BL::Object::type_enum type = b_ob.type();
-
- if (type == BL::Object::type_VOLUME || type == BL::Object::type_HAIR) {
- /* Will be exported attached to mesh. */
- return true;
- }
- else if (type == BL::Object::type_CURVE) {
- /* Skip exporting curves without faces, overhead can be
- * significant if there are many for path animation. */
- BL::Curve b_curve(b_ob_data);
-
- return (b_curve.bevel_object() || b_curve.extrude() != 0.0f || b_curve.bevel_depth() != 0.0f ||
- b_curve.dimensions() == BL::Curve::dimensions_2D || b_ob.modifiers.length());
- }
- else {
- return (b_ob_data.is_a(&RNA_Mesh) || b_ob_data.is_a(&RNA_Curve) ||
- b_ob_data.is_a(&RNA_MetaBall));
- }
-}
-
-bool BlenderSync::object_is_light(BL::Object &b_ob)
-{
- BL::ID b_ob_data = b_ob.data();
-
- return (b_ob_data && b_ob_data.is_a(&RNA_Light));
-}
-
-void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object)
-{
- /* Initialize motion blur for object, detecting if it's enabled and creating motion
- * steps array if so. */
- array<Transform> motion;
- object->set_motion(motion);
-
- Geometry *geom = object->get_geometry();
- if (!geom) {
- return;
- }
-
- int motion_steps = 0;
- bool use_motion_blur = false;
-
- Scene::MotionType need_motion = scene->need_motion();
- if (need_motion == Scene::MOTION_BLUR) {
- motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
- if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
- use_motion_blur = true;
- }
- }
- else if (need_motion != Scene::MOTION_NONE) {
- motion_steps = 3;
- }
-
- geom->set_use_motion_blur(use_motion_blur);
- geom->set_motion_steps(motion_steps);
-
- motion.resize(motion_steps, transform_empty());
-
- if (motion_steps) {
- motion[motion_steps / 2] = object->get_tfm();
-
- /* update motion socket before trying to access object->motion_time */
- object->set_motion(motion);
-
- for (size_t step = 0; step < motion_steps; step++) {
- motion_times.insert(object->motion_time(step));
- }
- }
-}
-
-Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
- BL::ViewLayer &b_view_layer,
- BL::DepsgraphObjectInstance &b_instance,
- float motion_time,
- bool use_particle_hair,
- bool show_lights,
- BlenderObjectCulling &culling,
- bool *use_portal,
- TaskPool *geom_task_pool)
-{
- const bool is_instance = b_instance.is_instance();
- BL::Object b_ob = b_instance.object();
- BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object();
- BObjectInfo b_ob_info{b_ob, is_instance ? b_instance.instance_object() : b_ob, b_ob.data()};
- const bool motion = motion_time != 0.0f;
- /*const*/ Transform tfm = get_transform(b_ob.matrix_world());
- int *persistent_id = NULL;
- BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id_array;
- if (is_instance) {
- persistent_id_array = b_instance.persistent_id();
- persistent_id = persistent_id_array.data;
- }
-
- /* light is handled separately */
- if (!motion && object_is_light(b_ob)) {
- if (!show_lights) {
- return NULL;
- }
-
- /* TODO: don't use lights for excluded layers used as mask layer,
- * when dynamic overrides are back. */
-#if 0
- if (!((layer_flag & view_layer.holdout_layer) && (layer_flag & view_layer.exclude_layer)))
-#endif
- {
- sync_light(b_parent,
- persistent_id,
- b_ob_info,
- is_instance ? b_instance.random_id() : 0,
- tfm,
- use_portal);
- }
-
- return NULL;
- }
-
- /* only interested in object that we can create meshes from */
- if (!object_is_geometry(b_ob)) {
- return NULL;
- }
-
- /* Perform object culling. */
- if (culling.test(scene, b_ob, tfm)) {
- return NULL;
- }
-
- /* Visibility flags for both parent and child. */
- PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
- bool use_holdout = b_parent.holdout_get(PointerRNA_NULL, b_view_layer);
- uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY;
-
- if (b_parent.ptr.data != b_ob.ptr.data) {
- visibility &= object_ray_visibility(b_parent);
- }
-
- /* TODO: make holdout objects on excluded layer invisible for non-camera rays. */
-#if 0
- if (use_holdout && (layer_flag & view_layer.exclude_layer)) {
- visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA);
- }
-#endif
-
- /* Clear camera visibility for indirect only objects. */
- bool use_indirect_only = !use_holdout &&
- b_parent.indirect_only_get(PointerRNA_NULL, b_view_layer);
- if (use_indirect_only) {
- visibility &= ~PATH_RAY_CAMERA;
- }
-
- /* Don't export completely invisible objects. */
- if (visibility == 0) {
- return NULL;
- }
-
- /* Use task pool only for non-instances, since sync_dupli_particle accesses
- * geometry. This restriction should be removed for better performance. */
- TaskPool *object_geom_task_pool = (is_instance) ? NULL : geom_task_pool;
-
- /* key to lookup object */
- ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, use_particle_hair);
- Object *object;
-
- /* motion vector case */
- if (motion) {
- object = object_map.find(key);
-
- if (object && object->use_motion()) {
- /* Set transform at matching motion time step. */
- int time_index = object->motion_step(motion_time);
- if (time_index >= 0) {
- array<Transform> motion = object->get_motion();
- motion[time_index] = tfm;
- object->set_motion(motion);
- }
-
- /* mesh deformation */
- if (object->get_geometry())
- sync_geometry_motion(
- b_depsgraph, b_ob_info, object, motion_time, use_particle_hair, object_geom_task_pool);
- }
-
- return object;
- }
-
- /* test if we need to sync */
- bool object_updated = object_map.add_or_update(&object, b_ob, b_parent, key) ||
- (tfm != object->get_tfm());
-
- /* mesh sync */
- Geometry *geometry = sync_geometry(
- b_depsgraph, b_ob_info, object_updated, use_particle_hair, object_geom_task_pool);
- object->set_geometry(geometry);
-
- /* special case not tracked by object update flags */
-
- if (sync_object_attributes(b_instance, object)) {
- object_updated = true;
- }
-
- /* holdout */
- object->set_use_holdout(use_holdout);
-
- object->set_visibility(visibility);
-
- object->set_is_shadow_catcher(b_ob.is_shadow_catcher());
-
- float shadow_terminator_shading_offset = get_float(cobject, "shadow_terminator_offset");
- object->set_shadow_terminator_shading_offset(shadow_terminator_shading_offset);
-
- float shadow_terminator_geometry_offset = get_float(cobject,
- "shadow_terminator_geometry_offset");
- object->set_shadow_terminator_geometry_offset(shadow_terminator_geometry_offset);
-
- float ao_distance = get_float(cobject, "ao_distance");
- if (ao_distance == 0.0f && b_parent.ptr.data != b_ob.ptr.data) {
- PointerRNA cparent = RNA_pointer_get(&b_parent.ptr, "cycles");
- ao_distance = get_float(cparent, "ao_distance");
- }
- object->set_ao_distance(ao_distance);
-
- /* sync the asset name for Cryptomatte */
- BL::Object parent = b_ob.parent();
- ustring parent_name;
- if (parent) {
- while (parent.parent()) {
- parent = parent.parent();
- }
- parent_name = parent.name();
- }
- else {
- parent_name = b_ob.name();
- }
- object->set_asset_name(parent_name);
-
- /* object sync
- * transform comparison should not be needed, but duplis don't work perfect
- * in the depsgraph and may not signal changes, so this is a workaround */
- if (object->is_modified() || object_updated ||
- (object->get_geometry() && object->get_geometry()->is_modified())) {
- object->name = b_ob.name().c_str();
- object->set_pass_id(b_ob.pass_index());
- object->set_color(get_float3(b_ob.color()));
- object->set_tfm(tfm);
-
- /* dupli texture coordinates and random_id */
- if (is_instance) {
- object->set_dupli_generated(0.5f * get_float3(b_instance.orco()) -
- make_float3(0.5f, 0.5f, 0.5f));
- object->set_dupli_uv(get_float2(b_instance.uv()));
- object->set_random_id(b_instance.random_id());
- }
- else {
- object->set_dupli_generated(zero_float3());
- object->set_dupli_uv(zero_float2());
- object->set_random_id(hash_uint2(hash_string(object->name.c_str()), 0));
- }
-
- object->tag_update(scene);
- }
-
- sync_object_motion_init(b_parent, b_ob, object);
-
- if (is_instance) {
- /* Sync possible particle data. */
- sync_dupli_particle(b_parent, b_instance, object);
- }
-
- return object;
-}
-
-/* This function mirrors drw_uniform_property_lookup in draw_instance_data.cpp */
-static bool lookup_property(BL::ID b_id, const string &name, float4 *r_value)
-{
- PointerRNA ptr;
- PropertyRNA *prop;
-
- if (!RNA_path_resolve(&b_id.ptr, name.c_str(), &ptr, &prop)) {
- return false;
- }
-
- if (prop == NULL) {
- return false;
- }
-
- PropertyType type = RNA_property_type(prop);
- int arraylen = RNA_property_array_length(&ptr, prop);
-
- if (arraylen == 0) {
- float value;
-
- if (type == PROP_FLOAT)
- value = RNA_property_float_get(&ptr, prop);
- else if (type == PROP_INT)
- value = static_cast<float>(RNA_property_int_get(&ptr, prop));
- else
- return false;
-
- *r_value = make_float4(value, value, value, 1.0f);
- return true;
- }
- else if (type == PROP_FLOAT && arraylen <= 4) {
- *r_value = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
- RNA_property_float_get_array(&ptr, prop, &r_value->x);
- return true;
- }
-
- return false;
-}
-
-/* This function mirrors drw_uniform_attribute_lookup in draw_instance_data.cpp */
-static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance,
- const string &name,
- bool use_instancer)
-{
- string idprop_name = string_printf("[\"%s\"]", name.c_str());
- float4 value;
-
- /* If requesting instance data, check the parent particle system and object. */
- if (use_instancer && b_instance.is_instance()) {
- BL::ParticleSystem b_psys = b_instance.particle_system();
-
- if (b_psys) {
- if (lookup_property(b_psys.settings(), idprop_name, &value) ||
- lookup_property(b_psys.settings(), name, &value)) {
- return value;
- }
- }
- if (lookup_property(b_instance.parent(), idprop_name, &value) ||
- lookup_property(b_instance.parent(), name, &value)) {
- return value;
- }
- }
-
- /* Check the object and mesh. */
- BL::Object b_ob = b_instance.object();
- BL::ID b_data = b_ob.data();
-
- if (lookup_property(b_ob, idprop_name, &value) || lookup_property(b_ob, name, &value) ||
- lookup_property(b_data, idprop_name, &value) || lookup_property(b_data, name, &value)) {
- return value;
- }
-
- return make_float4(0.0f);
-}
-
-bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object)
-{
- /* Find which attributes are needed. */
- AttributeRequestSet requests = object->get_geometry()->needed_attributes();
-
- /* Delete attributes that became unnecessary. */
- vector<ParamValue> &attributes = object->attributes;
- bool changed = false;
-
- for (int i = attributes.size() - 1; i >= 0; i--) {
- if (!requests.find(attributes[i].name())) {
- attributes.erase(attributes.begin() + i);
- changed = true;
- }
- }
-
- /* Update attribute values. */
- foreach (AttributeRequest &req, requests.requests) {
- ustring name = req.name;
-
- std::string real_name;
- BlenderAttributeType type = blender_attribute_name_split_type(name, &real_name);
-
- if (type != BL::ShaderNodeAttribute::attribute_type_GEOMETRY) {
- bool use_instancer = (type == BL::ShaderNodeAttribute::attribute_type_INSTANCER);
- float4 value = lookup_instance_property(b_instance, real_name, use_instancer);
-
- /* Try finding the existing attribute value. */
- ParamValue *param = NULL;
-
- for (size_t i = 0; i < attributes.size(); i++) {
- if (attributes[i].name() == name) {
- param = &attributes[i];
- break;
- }
- }
-
- /* Replace or add the value. */
- ParamValue new_param(name, TypeDesc::TypeFloat4, 1, &value);
- assert(new_param.datasize() == sizeof(value));
-
- if (!param) {
- changed = true;
- attributes.push_back(new_param);
- }
- else if (memcmp(param->data(), &value, sizeof(value)) != 0) {
- changed = true;
- *param = new_param;
- }
- }
- }
-
- return changed;
-}
-
-/* Object Loop */
-
-void BlenderSync::sync_procedural(BL::Object &b_ob,
- BL::MeshSequenceCacheModifier &b_mesh_cache,
- bool has_subdivision_modifier)
-{
-#ifdef WITH_ALEMBIC
- BL::CacheFile cache_file = b_mesh_cache.cache_file();
- void *cache_file_key = cache_file.ptr.data;
-
- AlembicProcedural *procedural = static_cast<AlembicProcedural *>(
- procedural_map.find(cache_file_key));
-
- if (procedural == nullptr) {
- procedural = scene->create_node<AlembicProcedural>();
- procedural_map.add(cache_file_key, procedural);
- }
- else {
- procedural_map.used(procedural);
- }
-
- float current_frame = static_cast<float>(b_scene.frame_current());
- if (cache_file.override_frame()) {
- current_frame = cache_file.frame();
- }
-
- if (!cache_file.override_frame()) {
- procedural->set_start_frame(static_cast<float>(b_scene.frame_start()));
- procedural->set_end_frame(static_cast<float>(b_scene.frame_end()));
- }
-
- procedural->set_frame(current_frame);
- procedural->set_frame_rate(b_scene.render().fps() / b_scene.render().fps_base());
- procedural->set_frame_offset(cache_file.frame_offset());
-
- string absolute_path = blender_absolute_path(b_data, b_ob, b_mesh_cache.cache_file().filepath());
- procedural->set_filepath(ustring(absolute_path));
-
- procedural->set_scale(cache_file.scale());
-
- procedural->set_use_prefetch(cache_file.use_prefetch());
- procedural->set_prefetch_cache_size(cache_file.prefetch_cache_size());
-
- /* create or update existing AlembicObjects */
- ustring object_path = ustring(b_mesh_cache.object_path());
-
- AlembicObject *abc_object = procedural->get_or_create_object(object_path);
-
- array<Node *> used_shaders = find_used_shaders(b_ob);
- abc_object->set_used_shaders(used_shaders);
-
- PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
- const float subd_dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
- abc_object->set_subd_dicing_rate(subd_dicing_rate);
- abc_object->set_subd_max_level(max_subdivisions);
-
- abc_object->set_ignore_subdivision(!has_subdivision_modifier);
-
- if (abc_object->is_modified() || procedural->is_modified()) {
- procedural->tag_update(scene);
- }
-#else
- (void)b_ob;
- (void)b_mesh_cache;
- (void)has_subdivision_modifier;
-#endif
-}
-
-void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
- BL::SpaceView3D &b_v3d,
- float motion_time)
-{
- /* Task pool for multithreaded geometry sync. */
- TaskPool geom_task_pool;
-
- /* layer data */
- bool motion = motion_time != 0.0f;
-
- if (!motion) {
- /* prepare for sync */
- light_map.pre_sync();
- geometry_map.pre_sync();
- object_map.pre_sync();
- procedural_map.pre_sync();
- particle_system_map.pre_sync();
- motion_times.clear();
- }
- else {
- geometry_motion_synced.clear();
- }
-
- /* initialize culling */
- BlenderObjectCulling culling(scene, b_scene);
-
- /* object loop */
- bool cancel = false;
- bool use_portal = false;
- const bool show_lights = BlenderViewportParameters(b_v3d, use_developer_ui).use_scene_lights;
-
- BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
- BL::Depsgraph::object_instances_iterator b_instance_iter;
-
- for (b_depsgraph.object_instances.begin(b_instance_iter);
- b_instance_iter != b_depsgraph.object_instances.end() && !cancel;
- ++b_instance_iter) {
- BL::DepsgraphObjectInstance b_instance = *b_instance_iter;
- BL::Object b_ob = b_instance.object();
-
- /* Viewport visibility. */
- const bool show_in_viewport = !b_v3d || b_ob.visible_in_viewport_get(b_v3d);
- if (show_in_viewport == false) {
- continue;
- }
-
- /* Load per-object culling data. */
- culling.init_object(scene, b_ob);
-
- /* Ensure the object geom supporting the hair is processed before adding
- * the hair processing task to the task pool, calling .to_mesh() on the
- * same object in parallel does not work. */
- const bool sync_hair = b_instance.show_particles() && object_has_particle_hair(b_ob);
-
- /* Object itself. */
- if (b_instance.show_self()) {
-#ifdef WITH_ALEMBIC
- bool use_procedural = false;
- bool has_subdivision_modifier = false;
- BL::MeshSequenceCacheModifier b_mesh_cache(PointerRNA_NULL);
-
- /* Experimental as Blender does not have good support for procedurals at the moment, also
- * only available in preview renders since currently do not have a good cache policy, the
- * data being loaded at once for all the frames. */
- if (experimental && b_v3d) {
- b_mesh_cache = object_mesh_cache_find(b_ob, &has_subdivision_modifier);
- use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural();
- }
-
- if (use_procedural) {
- /* Skip in the motion case, as generating motion blur data will be handled in the
- * procedural. */
- if (!motion) {
- sync_procedural(b_ob, b_mesh_cache, has_subdivision_modifier);
- }
- }
- else
-#endif
- {
- sync_object(b_depsgraph,
- b_view_layer,
- b_instance,
- motion_time,
- false,
- show_lights,
- culling,
- &use_portal,
- sync_hair ? NULL : &geom_task_pool);
- }
- }
-
- /* Particle hair as separate object. */
- if (sync_hair) {
- sync_object(b_depsgraph,
- b_view_layer,
- b_instance,
- motion_time,
- true,
- show_lights,
- culling,
- &use_portal,
- &geom_task_pool);
- }
-
- cancel = progress.get_cancel();
- }
-
- geom_task_pool.wait_work();
-
- progress.set_sync_status("");
-
- if (!cancel && !motion) {
- sync_background_light(b_v3d, use_portal);
-
- /* Handle removed data and modified pointers, as this may free memory, delete Nodes in the
- * right order to ensure that dependent data is freed after their users. Objects should be
- * freed before particle systems and geometries. */
- light_map.post_sync();
- object_map.post_sync();
- geometry_map.post_sync();
- particle_system_map.post_sync();
- procedural_map.post_sync();
- }
-
- if (motion)
- geometry_motion_synced.clear();
-}
-
-void BlenderSync::sync_motion(BL::RenderSettings &b_render,
- BL::Depsgraph &b_depsgraph,
- BL::SpaceView3D &b_v3d,
- BL::Object &b_override,
- int width,
- int height,
- void **python_thread_state)
-{
- if (scene->need_motion() == Scene::MOTION_NONE)
- return;
-
- /* get camera object here to deal with camera switch */
- BL::Object b_cam = b_scene.camera();
- if (b_override)
- b_cam = b_override;
-
- int frame_center = b_scene.frame_current();
- float subframe_center = b_scene.frame_subframe();
- float frame_center_delta = 0.0f;
-
- if (scene->need_motion() != Scene::MOTION_PASS &&
- scene->camera->get_motion_position() != Camera::MOTION_POSITION_CENTER) {
- float shuttertime = scene->camera->get_shuttertime();
- if (scene->camera->get_motion_position() == Camera::MOTION_POSITION_END) {
- frame_center_delta = -shuttertime * 0.5f;
- }
- else {
- assert(scene->camera->get_motion_position() == Camera::MOTION_POSITION_START);
- frame_center_delta = shuttertime * 0.5f;
- }
-
- float time = frame_center + subframe_center + frame_center_delta;
- int frame = (int)floorf(time);
- float subframe = time - frame;
- python_thread_state_restore(python_thread_state);
- b_engine.frame_set(frame, subframe);
- python_thread_state_save(python_thread_state);
- if (b_cam) {
- sync_camera_motion(b_render, b_cam, width, height, 0.0f);
- }
- sync_objects(b_depsgraph, b_v3d);
- }
-
- /* Insert motion times from camera. Motion times from other objects
- * have already been added in a sync_objects call. */
- if (b_cam) {
- uint camera_motion_steps = object_motion_steps(b_cam, b_cam);
- for (size_t step = 0; step < camera_motion_steps; step++) {
- motion_times.insert(scene->camera->motion_time(step));
- }
- }
-
- /* Check which geometry already has motion blur so it can be skipped. */
- geometry_motion_attribute_synced.clear();
- for (Geometry *geom : scene->geometry) {
- if (geom->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
- geometry_motion_attribute_synced.insert(geom);
- }
- }
-
- /* note iteration over motion_times set happens in sorted order */
- foreach (float relative_time, motion_times) {
- /* center time is already handled. */
- if (relative_time == 0.0f) {
- continue;
- }
-
- VLOG(1) << "Synchronizing motion for the relative time " << relative_time << ".";
-
- /* fixed shutter time to get previous and next frame for motion pass */
- float shuttertime = scene->motion_shutter_time();
-
- /* compute frame and subframe time */
- float time = frame_center + subframe_center + frame_center_delta +
- relative_time * shuttertime * 0.5f;
- int frame = (int)floorf(time);
- float subframe = time - frame;
-
- /* change frame */
- python_thread_state_restore(python_thread_state);
- b_engine.frame_set(frame, subframe);
- python_thread_state_save(python_thread_state);
-
- /* Syncs camera motion if relative_time is one of the camera's motion times. */
- sync_camera_motion(b_render, b_cam, width, height, relative_time);
-
- /* sync object */
- sync_objects(b_depsgraph, b_v3d, relative_time);
- }
-
- geometry_motion_attribute_synced.clear();
-
- /* we need to set the python thread state again because this
- * function assumes it is being executed from python and will
- * try to save the thread state */
- python_thread_state_restore(python_thread_state);
- b_engine.frame_set(frame_center, subframe_center);
- python_thread_state_save(python_thread_state);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_object_cull.cpp b/intern/cycles/blender/blender_object_cull.cpp
deleted file mode 100644
index cb7827b3c4a..00000000000
--- a/intern/cycles/blender/blender_object_cull.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cstdlib>
-
-#include "render/camera.h"
-
-#include "blender/blender_object_cull.h"
-#include "blender/blender_util.h"
-
-CCL_NAMESPACE_BEGIN
-
-BlenderObjectCulling::BlenderObjectCulling(Scene *scene, BL::Scene &b_scene)
- : use_scene_camera_cull_(false),
- use_camera_cull_(false),
- camera_cull_margin_(0.0f),
- use_scene_distance_cull_(false),
- use_distance_cull_(false),
- distance_cull_margin_(0.0f)
-{
- if (b_scene.render().use_simplify()) {
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-
- use_scene_camera_cull_ = scene->camera->get_camera_type() != CAMERA_PANORAMA &&
- !b_scene.render().use_multiview() &&
- get_boolean(cscene, "use_camera_cull");
- use_scene_distance_cull_ = scene->camera->get_camera_type() != CAMERA_PANORAMA &&
- !b_scene.render().use_multiview() &&
- get_boolean(cscene, "use_distance_cull");
-
- camera_cull_margin_ = get_float(cscene, "camera_cull_margin");
- distance_cull_margin_ = get_float(cscene, "distance_cull_margin");
-
- if (distance_cull_margin_ == 0.0f) {
- use_scene_distance_cull_ = false;
- }
- }
-}
-
-void BlenderObjectCulling::init_object(Scene *scene, BL::Object &b_ob)
-{
- if (!use_scene_camera_cull_ && !use_scene_distance_cull_) {
- return;
- }
-
- PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
-
- use_camera_cull_ = use_scene_camera_cull_ && get_boolean(cobject, "use_camera_cull");
- use_distance_cull_ = use_scene_distance_cull_ && get_boolean(cobject, "use_distance_cull");
-
- if (use_camera_cull_ || use_distance_cull_) {
- /* Need to have proper projection matrix. */
- scene->camera->update(scene);
- }
-}
-
-bool BlenderObjectCulling::test(Scene *scene, BL::Object &b_ob, Transform &tfm)
-{
- if (!use_camera_cull_ && !use_distance_cull_) {
- return false;
- }
-
- /* Compute world space bounding box corners. */
- float3 bb[8];
- BL::Array<float, 24> boundbox = b_ob.bound_box();
- for (int i = 0; i < 8; ++i) {
- float3 p = make_float3(boundbox[3 * i + 0], boundbox[3 * i + 1], boundbox[3 * i + 2]);
- bb[i] = transform_point(&tfm, p);
- }
-
- bool camera_culled = use_camera_cull_ && test_camera(scene, bb);
- bool distance_culled = use_distance_cull_ && test_distance(scene, bb);
-
- return ((camera_culled && distance_culled) || (camera_culled && !use_distance_cull_) ||
- (distance_culled && !use_camera_cull_));
-}
-
-/* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order
- * to reduce number of objects which are wrongly considered visible.
- */
-bool BlenderObjectCulling::test_camera(Scene *scene, float3 bb[8])
-{
- Camera *cam = scene->camera;
- const ProjectionTransform &worldtondc = cam->worldtondc;
- float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
- bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
- bool all_behind = true;
- for (int i = 0; i < 8; ++i) {
- float3 p = bb[i];
- float4 b = make_float4(p.x, p.y, p.z, 1.0f);
- float4 c = make_float4(
- dot(worldtondc.x, b), dot(worldtondc.y, b), dot(worldtondc.z, b), dot(worldtondc.w, b));
- p = float4_to_float3(c / c.w);
- if (c.z < 0.0f) {
- p.x = 1.0f - p.x;
- p.y = 1.0f - p.y;
- }
- if (c.z >= -camera_cull_margin_) {
- all_behind = false;
- }
- bb_min = min(bb_min, p);
- bb_max = max(bb_max, p);
- }
- if (all_behind) {
- return true;
- }
- return (bb_min.x >= 1.0f + camera_cull_margin_ || bb_min.y >= 1.0f + camera_cull_margin_ ||
- bb_max.x <= -camera_cull_margin_ || bb_max.y <= -camera_cull_margin_);
-}
-
-bool BlenderObjectCulling::test_distance(Scene *scene, float3 bb[8])
-{
- float3 camera_position = transform_get_column(&scene->camera->get_matrix(), 3);
- float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
- bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
-
- /* Find min & max points for x & y & z on bounding box */
- for (int i = 0; i < 8; ++i) {
- float3 p = bb[i];
- bb_min = min(bb_min, p);
- bb_max = max(bb_max, p);
- }
-
- float3 closest_point = max(min(bb_max, camera_position), bb_min);
- return (len_squared(camera_position - closest_point) >
- distance_cull_margin_ * distance_cull_margin_);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_object_cull.h b/intern/cycles/blender/blender_object_cull.h
deleted file mode 100644
index 0879db4f802..00000000000
--- a/intern/cycles/blender/blender_object_cull.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BLENDER_OBJECT_CULL_H__
-#define __BLENDER_OBJECT_CULL_H__
-
-#include "blender/blender_sync.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Scene;
-
-class BlenderObjectCulling {
- public:
- BlenderObjectCulling(Scene *scene, BL::Scene &b_scene);
-
- void init_object(Scene *scene, BL::Object &b_ob);
- bool test(Scene *scene, BL::Object &b_ob, Transform &tfm);
-
- private:
- bool test_camera(Scene *scene, float3 bb[8]);
- bool test_distance(Scene *scene, float3 bb[8]);
-
- bool use_scene_camera_cull_;
- bool use_camera_cull_;
- float camera_cull_margin_;
- bool use_scene_distance_cull_;
- bool use_distance_cull_;
- float distance_cull_margin_;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BLENDER_OBJECT_CULL_H__ */
diff --git a/intern/cycles/blender/blender_output_driver.cpp b/intern/cycles/blender/blender_output_driver.cpp
deleted file mode 100644
index 2f2844d4820..00000000000
--- a/intern/cycles/blender/blender_output_driver.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "blender/blender_output_driver.h"
-
-CCL_NAMESPACE_BEGIN
-
-BlenderOutputDriver::BlenderOutputDriver(BL::RenderEngine &b_engine) : b_engine_(b_engine)
-{
-}
-
-BlenderOutputDriver::~BlenderOutputDriver()
-{
-}
-
-bool BlenderOutputDriver::read_render_tile(const Tile &tile)
-{
- /* Get render result. */
- BL::RenderResult b_rr = b_engine_.begin_result(tile.offset.x,
- tile.offset.y,
- tile.size.x,
- tile.size.y,
- tile.layer.c_str(),
- tile.view.c_str());
-
- /* Can happen if the intersected rectangle gives 0 width or height. */
- if (b_rr.ptr.data == NULL) {
- return false;
- }
-
- BL::RenderResult::layers_iterator b_single_rlay;
- b_rr.layers.begin(b_single_rlay);
-
- /* layer will be missing if it was disabled in the UI */
- if (b_single_rlay == b_rr.layers.end()) {
- return false;
- }
-
- BL::RenderLayer b_rlay = *b_single_rlay;
-
- vector<float> pixels(tile.size.x * tile.size.y * 4);
-
- /* Copy each pass.
- * TODO:copy only the required ones for better performance? */
- for (BL::RenderPass &b_pass : b_rlay.passes) {
- tile.set_pass_pixels(b_pass.name(), b_pass.channels(), (float *)b_pass.rect());
- }
-
- b_engine_.end_result(b_rr, false, false, false);
-
- return true;
-}
-
-bool BlenderOutputDriver::update_render_tile(const Tile &tile)
-{
- /* Use final write for preview renders, otherwise render result wouldn't be be updated
- * quickly on Blender side. For all other cases we use the display driver. */
- if (b_engine_.is_preview()) {
- write_render_tile(tile);
- return true;
- }
-
- /* Don't highlight full-frame tile. */
- if (!(tile.size == tile.full_size)) {
- b_engine_.tile_highlight_clear_all();
- b_engine_.tile_highlight_set(tile.offset.x, tile.offset.y, tile.size.x, tile.size.y, true);
- }
-
- return false;
-}
-
-void BlenderOutputDriver::write_render_tile(const Tile &tile)
-{
- b_engine_.tile_highlight_clear_all();
-
- /* Get render result. */
- BL::RenderResult b_rr = b_engine_.begin_result(tile.offset.x,
- tile.offset.y,
- tile.size.x,
- tile.size.y,
- tile.layer.c_str(),
- tile.view.c_str());
-
- /* Can happen if the intersected rectangle gives 0 width or height. */
- if (b_rr.ptr.data == NULL) {
- return;
- }
-
- BL::RenderResult::layers_iterator b_single_rlay;
- b_rr.layers.begin(b_single_rlay);
-
- /* Layer will be missing if it was disabled in the UI. */
- if (b_single_rlay == b_rr.layers.end()) {
- return;
- }
-
- BL::RenderLayer b_rlay = *b_single_rlay;
-
- vector<float> pixels(tile.size.x * tile.size.y * 4);
-
- /* Copy each pass. */
- for (BL::RenderPass &b_pass : b_rlay.passes) {
- if (!tile.get_pass_pixels(b_pass.name(), b_pass.channels(), &pixels[0])) {
- memset(&pixels[0], 0, pixels.size() * sizeof(float));
- }
-
- b_pass.rect(&pixels[0]);
- }
-
- b_engine_.end_result(b_rr, true, false, true);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_output_driver.h b/intern/cycles/blender/blender_output_driver.h
deleted file mode 100644
index 0852cba1b34..00000000000
--- a/intern/cycles/blender/blender_output_driver.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "MEM_guardedalloc.h"
-
-#include "RNA_blender_cpp.h"
-
-#include "render/output_driver.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BlenderOutputDriver : public OutputDriver {
- public:
- explicit BlenderOutputDriver(BL::RenderEngine &b_engine);
- ~BlenderOutputDriver();
-
- virtual void write_render_tile(const Tile &tile) override;
- virtual bool update_render_tile(const Tile &tile) override;
- virtual bool read_render_tile(const Tile &tile) override;
-
- protected:
- BL::RenderEngine b_engine_;
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp
deleted file mode 100644
index 206ee24a093..00000000000
--- a/intern/cycles/blender/blender_particles.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/particles.h"
-
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-#include "util/util_foreach.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Utilities */
-
-bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
- BL::DepsgraphObjectInstance &b_instance,
- Object *object)
-{
- /* Test if this dupli was generated from a particle system. */
- BL::ParticleSystem b_psys = b_instance.particle_system();
- if (!b_psys)
- return false;
-
- object->set_hide_on_missing_motion(true);
-
- /* test if we need particle data */
- if (!object->get_geometry()->need_attribute(scene, ATTR_STD_PARTICLE))
- return false;
-
- /* don't handle child particles yet */
- BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_instance.persistent_id();
-
- if (persistent_id[0] >= b_psys.particles.length())
- return false;
-
- /* find particle system */
- ParticleSystemKey key(b_ob, persistent_id);
- ParticleSystem *psys;
-
- bool first_use = !particle_system_map.is_used(key);
- bool need_update = particle_system_map.add_or_update(&psys, b_ob, b_instance.object(), key);
-
- /* no update needed? */
- if (!need_update && !object->get_geometry()->is_modified() &&
- !scene->object_manager->need_update())
- return true;
-
- /* first time used in this sync loop? clear and tag update */
- if (first_use) {
- psys->particles.clear();
- psys->tag_update(scene);
- }
-
- /* add particle */
- BL::Particle b_pa = b_psys.particles[persistent_id[0]];
- Particle pa;
-
- pa.index = persistent_id[0];
- pa.age = b_scene.frame_current_final() - b_pa.birth_time();
- pa.lifetime = b_pa.lifetime();
- pa.location = get_float3(b_pa.location());
- pa.rotation = get_float4(b_pa.rotation());
- pa.size = b_pa.size();
- pa.velocity = get_float3(b_pa.velocity());
- pa.angular_velocity = get_float3(b_pa.angular_velocity());
-
- psys->particles.push_back_slow(pa);
-
- object->set_particle_system(psys);
- object->set_particle_index(psys->particles.size() - 1);
-
- if (object->particle_index_is_modified())
- scene->object_manager->tag_update(scene, ObjectManager::PARTICLE_MODIFIED);
-
- /* return that this object has particle data */
- return true;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
deleted file mode 100644
index d681517c9e1..00000000000
--- a/intern/cycles/blender/blender_python.cpp
+++ /dev/null
@@ -1,1063 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <Python.h>
-
-#include "blender/CCL_api.h"
-
-#include "blender/blender_device.h"
-#include "blender/blender_session.h"
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-#include "render/denoising.h"
-#include "render/merge.h"
-
-#include "util/util_debug.h"
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_md5.h"
-#include "util/util_opengl.h"
-#include "util/util_openimagedenoise.h"
-#include "util/util_path.h"
-#include "util/util_string.h"
-#include "util/util_task.h"
-#include "util/util_tbb.h"
-#include "util/util_types.h"
-
-#ifdef WITH_OSL
-# include "render/osl.h"
-
-# include <OSL/oslconfig.h>
-# include <OSL/oslquery.h>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-namespace {
-
-/* Flag describing whether debug flags were synchronized from scene. */
-bool debug_flags_set = false;
-
-void *pylong_as_voidptr_typesafe(PyObject *object)
-{
- if (object == Py_None)
- return NULL;
- return PyLong_AsVoidPtr(object);
-}
-
-PyObject *pyunicode_from_string(const char *str)
-{
- /* Ignore errors if device API returns invalid UTF-8 strings. */
- return PyUnicode_DecodeUTF8(str, strlen(str), "ignore");
-}
-
-/* Synchronize debug flags from a given Blender scene.
- * Return truth when device list needs invalidation.
- */
-static void debug_flags_sync_from_scene(BL::Scene b_scene)
-{
- DebugFlagsRef flags = DebugFlags();
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- /* Synchronize shared flags. */
- flags.viewport_static_bvh = get_enum(cscene, "debug_bvh_type");
- /* Synchronize CPU flags. */
- flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2");
- flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx");
- flags.cpu.sse41 = get_boolean(cscene, "debug_use_cpu_sse41");
- flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3");
- flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2");
- flags.cpu.bvh_layout = (BVHLayout)get_enum(cscene, "debug_bvh_layout");
- /* Synchronize CUDA flags. */
- flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile");
- /* Synchronize OptiX flags. */
- flags.optix.use_debug = get_boolean(cscene, "debug_use_optix_debug");
-}
-
-/* Reset debug flags to default values.
- * Return truth when device list needs invalidation.
- */
-static void debug_flags_reset()
-{
- DebugFlagsRef flags = DebugFlags();
- flags.reset();
-}
-
-} /* namespace */
-
-void python_thread_state_save(void **python_thread_state)
-{
- *python_thread_state = (void *)PyEval_SaveThread();
-}
-
-void python_thread_state_restore(void **python_thread_state)
-{
- PyEval_RestoreThread((PyThreadState *)*python_thread_state);
- *python_thread_state = NULL;
-}
-
-static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
-{
- const char *result = PyUnicode_AsUTF8(py_str);
- if (result) {
- /* 99% of the time this is enough but we better support non unicode
- * chars since blender doesn't limit this.
- */
- return result;
- }
- else {
- PyErr_Clear();
- if (PyBytes_Check(py_str)) {
- return PyBytes_AS_STRING(py_str);
- }
- else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
- return PyBytes_AS_STRING(*coerce);
- }
- else {
- /* Clear the error, so Cycles can be at least used without
- * GPU and OSL support,
- */
- PyErr_Clear();
- return "";
- }
- }
-}
-
-static PyObject *init_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *path, *user_path, *temp_path;
- int headless;
-
- if (!PyArg_ParseTuple(args, "OOOi", &path, &user_path, &temp_path, &headless)) {
- return nullptr;
- }
-
- PyObject *path_coerce = nullptr, *user_path_coerce = nullptr, *temp_path_coerce = nullptr;
- path_init(PyC_UnicodeAsByte(path, &path_coerce),
- PyC_UnicodeAsByte(user_path, &user_path_coerce),
- PyC_UnicodeAsByte(temp_path, &temp_path_coerce));
- Py_XDECREF(path_coerce);
- Py_XDECREF(user_path_coerce);
- Py_XDECREF(temp_path_coerce);
-
- BlenderSession::headless = headless;
-
- DebugFlags().running_inside_blender = true;
-
- VLOG(2) << "Debug flags initialized to:\n" << DebugFlags();
-
- Py_RETURN_NONE;
-}
-
-static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/)
-{
- ShaderManager::free_memory();
- TaskScheduler::free_memory();
- Device::free_memory();
- Py_RETURN_NONE;
-}
-
-static PyObject *create_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *pyengine, *pypreferences, *pydata, *pyscreen, *pyregion, *pyv3d, *pyrv3d;
- int preview_osl;
-
- if (!PyArg_ParseTuple(args,
- "OOOOOOOi",
- &pyengine,
- &pypreferences,
- &pydata,
- &pyscreen,
- &pyregion,
- &pyv3d,
- &pyrv3d,
- &preview_osl)) {
- return NULL;
- }
-
- /* RNA */
- ID *bScreen = (ID *)PyLong_AsVoidPtr(pyscreen);
-
- PointerRNA engineptr;
- RNA_pointer_create(NULL, &RNA_RenderEngine, (void *)PyLong_AsVoidPtr(pyengine), &engineptr);
- BL::RenderEngine engine(engineptr);
-
- PointerRNA preferencesptr;
- RNA_pointer_create(
- NULL, &RNA_Preferences, (void *)PyLong_AsVoidPtr(pypreferences), &preferencesptr);
- BL::Preferences preferences(preferencesptr);
-
- PointerRNA dataptr;
- RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr);
- BL::BlendData data(dataptr);
-
- PointerRNA regionptr;
- RNA_pointer_create(bScreen, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), &regionptr);
- BL::Region region(regionptr);
-
- PointerRNA v3dptr;
- RNA_pointer_create(bScreen, &RNA_SpaceView3D, pylong_as_voidptr_typesafe(pyv3d), &v3dptr);
- BL::SpaceView3D v3d(v3dptr);
-
- PointerRNA rv3dptr;
- RNA_pointer_create(bScreen, &RNA_RegionView3D, pylong_as_voidptr_typesafe(pyrv3d), &rv3dptr);
- BL::RegionView3D rv3d(rv3dptr);
-
- /* create session */
- BlenderSession *session;
-
- if (rv3d) {
- /* interactive viewport session */
- int width = region.width();
- int height = region.height();
-
- session = new BlenderSession(engine, preferences, data, v3d, rv3d, width, height);
- }
- else {
- /* offline session or preview render */
- session = new BlenderSession(engine, preferences, data, preview_osl);
- }
-
- return PyLong_FromVoidPtr(session);
-}
-
-static PyObject *free_func(PyObject * /*self*/, PyObject *value)
-{
- delete (BlenderSession *)PyLong_AsVoidPtr(value);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *render_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *pysession, *pydepsgraph;
-
- if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph))
- return NULL;
-
- BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
-
- PointerRNA depsgraphptr;
- RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
- BL::Depsgraph b_depsgraph(depsgraphptr);
-
- /* Allow Blender to execute other Python scripts. */
- python_thread_state_save(&session->python_thread_state);
-
- session->render(b_depsgraph);
-
- python_thread_state_restore(&session->python_thread_state);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *render_frame_finish_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *pysession;
-
- if (!PyArg_ParseTuple(args, "O", &pysession)) {
- return nullptr;
- }
-
- BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
-
- /* Allow Blender to execute other Python scripts. */
- python_thread_state_save(&session->python_thread_state);
-
- session->render_frame_finish();
-
- python_thread_state_restore(&session->python_thread_state);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *py_session, *py_graph, *py_screen, *py_space_image;
-
- if (!PyArg_ParseTuple(args, "OOOO", &py_session, &py_graph, &py_screen, &py_space_image)) {
- return nullptr;
- }
-
- BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(py_session);
-
- ID *b_screen = (ID *)PyLong_AsVoidPtr(py_screen);
-
- PointerRNA b_space_image_ptr;
- RNA_pointer_create(b_screen,
- &RNA_SpaceImageEditor,
- pylong_as_voidptr_typesafe(py_space_image),
- &b_space_image_ptr);
- BL::SpaceImageEditor b_space_image(b_space_image_ptr);
-
- session->draw(b_space_image);
-
- Py_RETURN_NONE;
-}
-
-/* pixel_array and result passed as pointers */
-static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *pysession, *pydepsgraph, *pyobject;
- const char *pass_type;
- int pass_filter, width, height;
-
- if (!PyArg_ParseTuple(args,
- "OOOsiii",
- &pysession,
- &pydepsgraph,
- &pyobject,
- &pass_type,
- &pass_filter,
- &width,
- &height))
- return NULL;
-
- BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
-
- PointerRNA depsgraphptr;
- RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
- BL::Depsgraph b_depsgraph(depsgraphptr);
-
- PointerRNA objectptr;
- RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyobject), &objectptr);
- BL::Object b_object(objectptr);
-
- python_thread_state_save(&session->python_thread_state);
-
- session->bake(b_depsgraph, b_object, pass_type, pass_filter, width, height);
-
- python_thread_state_restore(&session->python_thread_state);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *view_draw_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *pysession, *pygraph, *pyv3d, *pyrv3d;
-
- if (!PyArg_ParseTuple(args, "OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d))
- return NULL;
-
- BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
-
- if (PyLong_AsVoidPtr(pyrv3d)) {
- /* 3d view drawing */
- int viewport[4];
- glGetIntegerv(GL_VIEWPORT, viewport);
-
- session->view_draw(viewport[2], viewport[3]);
- }
-
- Py_RETURN_NONE;
-}
-
-static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *pysession, *pydata, *pydepsgraph;
-
- if (!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pydepsgraph))
- return NULL;
-
- BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
-
- PointerRNA dataptr;
- RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr);
- BL::BlendData b_data(dataptr);
-
- PointerRNA depsgraphptr;
- RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
- BL::Depsgraph b_depsgraph(depsgraphptr);
-
- python_thread_state_save(&session->python_thread_state);
-
- session->reset_session(b_data, b_depsgraph);
-
- python_thread_state_restore(&session->python_thread_state);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *sync_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *pysession, *pydepsgraph;
-
- if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph))
- return NULL;
-
- BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
-
- PointerRNA depsgraphptr;
- RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
- BL::Depsgraph b_depsgraph(depsgraphptr);
-
- python_thread_state_save(&session->python_thread_state);
-
- session->synchronize(b_depsgraph);
-
- python_thread_state_restore(&session->python_thread_state);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *available_devices_func(PyObject * /*self*/, PyObject *args)
-{
- const char *type_name;
- if (!PyArg_ParseTuple(args, "s", &type_name)) {
- return NULL;
- }
-
- DeviceType type = Device::type_from_string(type_name);
- /* "NONE" is defined by the add-on, see: `CyclesPreferences.get_device_types`. */
- if ((type == DEVICE_NONE) && (strcmp(type_name, "NONE") != 0)) {
- PyErr_Format(PyExc_ValueError, "Device \"%s\" not known.", type_name);
- return NULL;
- }
-
- uint mask = (type == DEVICE_NONE) ? DEVICE_MASK_ALL : DEVICE_MASK(type);
- mask |= DEVICE_MASK_CPU;
-
- vector<DeviceInfo> devices = Device::available_devices(mask);
- PyObject *ret = PyTuple_New(devices.size());
-
- for (size_t i = 0; i < devices.size(); i++) {
- DeviceInfo &device = devices[i];
- string type_name = Device::string_from_type(device.type);
- PyObject *device_tuple = PyTuple_New(4);
- PyTuple_SET_ITEM(device_tuple, 0, pyunicode_from_string(device.description.c_str()));
- PyTuple_SET_ITEM(device_tuple, 1, pyunicode_from_string(type_name.c_str()));
- PyTuple_SET_ITEM(device_tuple, 2, pyunicode_from_string(device.id.c_str()));
- PyTuple_SET_ITEM(device_tuple, 3, PyBool_FromLong(device.has_peer_memory));
- PyTuple_SET_ITEM(ret, i, device_tuple);
- }
-
- return ret;
-}
-
-#ifdef WITH_OSL
-
-static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *pydata, *pynodegroup, *pynode;
- const char *filepath = NULL;
-
- if (!PyArg_ParseTuple(args, "OOOs", &pydata, &pynodegroup, &pynode, &filepath))
- return NULL;
-
- /* RNA */
- PointerRNA dataptr;
- RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr);
- BL::BlendData b_data(dataptr);
-
- PointerRNA nodeptr;
- RNA_pointer_create((ID *)PyLong_AsVoidPtr(pynodegroup),
- &RNA_ShaderNodeScript,
- (void *)PyLong_AsVoidPtr(pynode),
- &nodeptr);
- BL::ShaderNodeScript b_node(nodeptr);
-
- /* update bytecode hash */
- string bytecode = b_node.bytecode();
-
- if (!bytecode.empty()) {
- MD5Hash md5;
- md5.append((const uint8_t *)bytecode.c_str(), bytecode.size());
- b_node.bytecode_hash(md5.get_hex().c_str());
- }
- else
- b_node.bytecode_hash("");
-
- /* query from file path */
- OSL::OSLQuery query;
-
- if (!OSLShaderManager::osl_query(query, filepath))
- Py_RETURN_FALSE;
-
- /* add new sockets from parameters */
- set<void *> used_sockets;
-
- for (int i = 0; i < query.nparams(); i++) {
- const OSL::OSLQuery::Parameter *param = query.getparam(i);
-
- /* skip unsupported types */
- if (param->varlenarray || param->isstruct || param->type.arraylen > 1)
- continue;
-
- /* Read metadata. */
- bool is_bool_param = false;
- ustring param_label = param->name;
-
- for (const OSL::OSLQuery::Parameter &metadata : param->metadata) {
- if (metadata.type == TypeDesc::STRING) {
- if (metadata.name == "widget") {
- /* Boolean socket. */
- if (metadata.sdefault[0] == "boolean" || metadata.sdefault[0] == "checkBox") {
- is_bool_param = true;
- }
- }
- else if (metadata.name == "label") {
- /* Socket label. */
- param_label = metadata.sdefault[0];
- }
- }
- }
- /* determine socket type */
- string socket_type;
- BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
- float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
- float default_float = 0.0f;
- int default_int = 0;
- string default_string = "";
- bool default_boolean = false;
-
- if (param->isclosure) {
- socket_type = "NodeSocketShader";
- data_type = BL::NodeSocket::type_SHADER;
- }
- else if (param->type.vecsemantics == TypeDesc::COLOR) {
- socket_type = "NodeSocketColor";
- data_type = BL::NodeSocket::type_RGBA;
-
- if (param->validdefault) {
- default_float4[0] = param->fdefault[0];
- default_float4[1] = param->fdefault[1];
- default_float4[2] = param->fdefault[2];
- }
- }
- else if (param->type.vecsemantics == TypeDesc::POINT ||
- param->type.vecsemantics == TypeDesc::VECTOR ||
- param->type.vecsemantics == TypeDesc::NORMAL) {
- socket_type = "NodeSocketVector";
- data_type = BL::NodeSocket::type_VECTOR;
-
- if (param->validdefault) {
- default_float4[0] = param->fdefault[0];
- default_float4[1] = param->fdefault[1];
- default_float4[2] = param->fdefault[2];
- }
- }
- else if (param->type.aggregate == TypeDesc::SCALAR) {
- if (param->type.basetype == TypeDesc::INT) {
- if (is_bool_param) {
- socket_type = "NodeSocketBool";
- data_type = BL::NodeSocket::type_BOOLEAN;
- if (param->validdefault) {
- default_boolean = (bool)param->idefault[0];
- }
- }
- else {
- socket_type = "NodeSocketInt";
- data_type = BL::NodeSocket::type_INT;
- if (param->validdefault)
- default_int = param->idefault[0];
- }
- }
- else if (param->type.basetype == TypeDesc::FLOAT) {
- socket_type = "NodeSocketFloat";
- data_type = BL::NodeSocket::type_VALUE;
- if (param->validdefault)
- default_float = param->fdefault[0];
- }
- else if (param->type.basetype == TypeDesc::STRING) {
- socket_type = "NodeSocketString";
- data_type = BL::NodeSocket::type_STRING;
- if (param->validdefault)
- default_string = param->sdefault[0].string();
- }
- else
- continue;
- }
- else
- continue;
-
- /* Update existing socket. */
- bool found_existing = false;
- if (param->isoutput) {
- for (BL::NodeSocket &b_sock : b_node.outputs) {
- if (b_sock.identifier() == param->name) {
- if (b_sock.bl_idname() != socket_type) {
- /* Remove if type no longer matches. */
- b_node.outputs.remove(b_data, b_sock);
- }
- else {
- /* Reuse and update label. */
- if (b_sock.name() != param_label) {
- b_sock.name(param_label.string());
- }
- used_sockets.insert(b_sock.ptr.data);
- found_existing = true;
- }
- break;
- }
- }
- }
- else {
- for (BL::NodeSocket &b_sock : b_node.inputs) {
- if (b_sock.identifier() == param->name) {
- if (b_sock.bl_idname() != socket_type) {
- /* Remove if type no longer matches. */
- b_node.inputs.remove(b_data, b_sock);
- }
- else {
- /* Reuse and update label. */
- if (b_sock.name() != param_label) {
- b_sock.name(param_label.string());
- }
- used_sockets.insert(b_sock.ptr.data);
- found_existing = true;
- }
- break;
- }
- }
- }
-
- if (!found_existing) {
- /* Create new socket. */
- BL::NodeSocket b_sock = (param->isoutput) ? b_node.outputs.create(b_data,
- socket_type.c_str(),
- param_label.c_str(),
- param->name.c_str()) :
- b_node.inputs.create(b_data,
- socket_type.c_str(),
- param_label.c_str(),
- param->name.c_str());
-
- /* set default value */
- if (data_type == BL::NodeSocket::type_VALUE) {
- set_float(b_sock.ptr, "default_value", default_float);
- }
- else if (data_type == BL::NodeSocket::type_INT) {
- set_int(b_sock.ptr, "default_value", default_int);
- }
- else if (data_type == BL::NodeSocket::type_RGBA) {
- set_float4(b_sock.ptr, "default_value", default_float4);
- }
- else if (data_type == BL::NodeSocket::type_VECTOR) {
- set_float3(b_sock.ptr, "default_value", float4_to_float3(default_float4));
- }
- else if (data_type == BL::NodeSocket::type_STRING) {
- set_string(b_sock.ptr, "default_value", default_string);
- }
- else if (data_type == BL::NodeSocket::type_BOOLEAN) {
- set_boolean(b_sock.ptr, "default_value", default_boolean);
- }
-
- used_sockets.insert(b_sock.ptr.data);
- }
- }
-
- /* remove unused parameters */
- bool removed;
-
- do {
- removed = false;
-
- for (BL::NodeSocket &b_input : b_node.inputs) {
- if (used_sockets.find(b_input.ptr.data) == used_sockets.end()) {
- b_node.inputs.remove(b_data, b_input);
- removed = true;
- break;
- }
- }
-
- for (BL::NodeSocket &b_output : b_node.outputs) {
- if (used_sockets.find(b_output.ptr.data) == used_sockets.end()) {
- b_node.outputs.remove(b_data, b_output);
- removed = true;
- break;
- }
- }
- } while (removed);
-
- Py_RETURN_TRUE;
-}
-
-static PyObject *osl_compile_func(PyObject * /*self*/, PyObject *args)
-{
- const char *inputfile = NULL, *outputfile = NULL;
-
- if (!PyArg_ParseTuple(args, "ss", &inputfile, &outputfile))
- return NULL;
-
- /* return */
- if (!OSLShaderManager::osl_compile(inputfile, outputfile))
- Py_RETURN_FALSE;
-
- Py_RETURN_TRUE;
-}
-#endif
-
-static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
-{
- string system_info = Device::device_capabilities();
- return pyunicode_from_string(system_info.c_str());
-}
-
-static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepaths)
-{
- if (PyUnicode_Check(pyfilepaths)) {
- const char *filepath = PyUnicode_AsUTF8(pyfilepaths);
- filepaths.push_back(filepath);
- return true;
- }
-
- PyObject *sequence = PySequence_Fast(pyfilepaths,
- "File paths must be a string or sequence of strings");
- if (sequence == NULL) {
- return false;
- }
-
- for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) {
- PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
- const char *filepath = PyUnicode_AsUTF8(item);
- if (filepath == NULL) {
- PyErr_SetString(PyExc_ValueError, "File paths must be a string or sequence of strings.");
- Py_DECREF(sequence);
- return false;
- }
- filepaths.push_back(filepath);
- }
- Py_DECREF(sequence);
-
- return true;
-}
-
-static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
-{
-#if 1
- (void)args;
- (void)keywords;
-#else
- static const char *keyword_list[] = {
- "preferences", "scene", "view_layer", "input", "output", "tile_size", "samples", NULL};
- PyObject *pypreferences, *pyscene, *pyviewlayer;
- PyObject *pyinput, *pyoutput = NULL;
- int tile_size = 0, samples = 0;
-
- if (!PyArg_ParseTupleAndKeywords(args,
- keywords,
- "OOOO|Oii",
- (char **)keyword_list,
- &pypreferences,
- &pyscene,
- &pyviewlayer,
- &pyinput,
- &pyoutput,
- &tile_size,
- &samples)) {
- return NULL;
- }
-
- /* Get device specification from preferences and scene. */
- PointerRNA preferencesptr;
- RNA_pointer_create(
- NULL, &RNA_Preferences, (void *)PyLong_AsVoidPtr(pypreferences), &preferencesptr);
- BL::Preferences b_preferences(preferencesptr);
-
- PointerRNA sceneptr;
- RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), &sceneptr);
- BL::Scene b_scene(sceneptr);
-
- DeviceInfo device = blender_device_info(b_preferences, b_scene, true);
-
- /* Get denoising parameters from view layer. */
- PointerRNA viewlayerptr;
- RNA_pointer_create((ID *)PyLong_AsVoidPtr(pyscene),
- &RNA_ViewLayer,
- PyLong_AsVoidPtr(pyviewlayer),
- &viewlayerptr);
- PointerRNA cviewlayer = RNA_pointer_get(&viewlayerptr, "cycles");
-
- DenoiseParams params;
- params.radius = get_int(cviewlayer, "denoising_radius");
- params.strength = get_float(cviewlayer, "denoising_strength");
- params.feature_strength = get_float(cviewlayer, "denoising_feature_strength");
- params.relative_pca = get_boolean(cviewlayer, "denoising_relative_pca");
- params.neighbor_frames = get_int(cviewlayer, "denoising_neighbor_frames");
-
- /* Parse file paths list. */
- vector<string> input, output;
-
- if (!image_parse_filepaths(pyinput, input)) {
- return NULL;
- }
-
- if (pyoutput) {
- if (!image_parse_filepaths(pyoutput, output)) {
- return NULL;
- }
- }
- else {
- output = input;
- }
-
- if (input.empty()) {
- PyErr_SetString(PyExc_ValueError, "No input file paths specified.");
- return NULL;
- }
- if (input.size() != output.size()) {
- PyErr_SetString(PyExc_ValueError, "Number of input and output file paths does not match.");
- return NULL;
- }
-
- /* Create denoiser. */
- DenoiserPipeline denoiser(device);
- denoiser.params = params;
- denoiser.input = input;
- denoiser.output = output;
-
- if (tile_size > 0) {
- denoiser.tile_size = make_int2(tile_size, tile_size);
- }
- if (samples > 0) {
- denoiser.samples_override = samples;
- }
-
- /* Run denoiser. */
- if (!denoiser.run()) {
- PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
- return NULL;
- }
-#endif
-
- Py_RETURN_NONE;
-}
-
-static PyObject *merge_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
-{
- static const char *keyword_list[] = {"input", "output", NULL};
- PyObject *pyinput, *pyoutput = NULL;
-
- if (!PyArg_ParseTupleAndKeywords(
- args, keywords, "OO", (char **)keyword_list, &pyinput, &pyoutput)) {
- return NULL;
- }
-
- /* Parse input list. */
- vector<string> input;
- if (!image_parse_filepaths(pyinput, input)) {
- return NULL;
- }
-
- /* Parse output string. */
- if (!PyUnicode_Check(pyoutput)) {
- PyErr_SetString(PyExc_ValueError, "Output must be a string.");
- return NULL;
- }
- string output = PyUnicode_AsUTF8(pyoutput);
-
- /* Merge. */
- ImageMerger merger;
- merger.input = input;
- merger.output = output;
-
- if (!merger.run()) {
- PyErr_SetString(PyExc_ValueError, merger.error.c_str());
- return NULL;
- }
-
- Py_RETURN_NONE;
-}
-
-static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
-{
- PyObject *pyscene;
- if (!PyArg_ParseTuple(args, "O", &pyscene)) {
- return NULL;
- }
-
- PointerRNA sceneptr;
- RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), &sceneptr);
- BL::Scene b_scene(sceneptr);
-
- debug_flags_sync_from_scene(b_scene);
-
- VLOG(2) << "Debug flags set to:\n" << DebugFlags();
-
- debug_flags_set = true;
-
- Py_RETURN_NONE;
-}
-
-static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/)
-{
- debug_flags_reset();
- if (debug_flags_set) {
- VLOG(2) << "Debug flags reset to:\n" << DebugFlags();
- debug_flags_set = false;
- }
- Py_RETURN_NONE;
-}
-
-static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/)
-{
- BlenderSession::print_render_stats = true;
- Py_RETURN_NONE;
-}
-
-static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
-{
- vector<DeviceType> device_types = Device::available_types();
- bool has_cuda = false, has_optix = false, has_hip = false;
- foreach (DeviceType device_type, device_types) {
- has_cuda |= (device_type == DEVICE_CUDA);
- has_optix |= (device_type == DEVICE_OPTIX);
- has_hip |= (device_type == DEVICE_HIP);
- }
- PyObject *list = PyTuple_New(3);
- PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
- PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
- PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_hip));
- return list;
-}
-
-static PyObject *set_device_override_func(PyObject * /*self*/, PyObject *arg)
-{
- PyObject *override_string = PyObject_Str(arg);
- string override = PyUnicode_AsUTF8(override_string);
- Py_DECREF(override_string);
-
- bool include_cpu = false;
- const string cpu_suffix = "+CPU";
- if (string_endswith(override, cpu_suffix)) {
- include_cpu = true;
- override = override.substr(0, override.length() - cpu_suffix.length());
- }
-
- if (override == "CPU") {
- BlenderSession::device_override = DEVICE_MASK_CPU;
- }
- else if (override == "CUDA") {
- BlenderSession::device_override = DEVICE_MASK_CUDA;
- }
- else if (override == "OPTIX") {
- BlenderSession::device_override = DEVICE_MASK_OPTIX;
- }
- else if (override == "HIP") {
- BlenderSession::device_override = DEVICE_MASK_HIP;
- }
- else {
- printf("\nError: %s is not a valid Cycles device.\n", override.c_str());
- Py_RETURN_FALSE;
- }
-
- if (include_cpu) {
- BlenderSession::device_override = (DeviceTypeMask)(BlenderSession::device_override |
- DEVICE_MASK_CPU);
- }
-
- Py_RETURN_TRUE;
-}
-
-static PyMethodDef methods[] = {
- {"init", init_func, METH_VARARGS, ""},
- {"exit", exit_func, METH_VARARGS, ""},
- {"create", create_func, METH_VARARGS, ""},
- {"free", free_func, METH_O, ""},
- {"render", render_func, METH_VARARGS, ""},
- {"render_frame_finish", render_frame_finish_func, METH_VARARGS, ""},
- {"draw", draw_func, METH_VARARGS, ""},
- {"bake", bake_func, METH_VARARGS, ""},
- {"view_draw", view_draw_func, METH_VARARGS, ""},
- {"sync", sync_func, METH_VARARGS, ""},
- {"reset", reset_func, METH_VARARGS, ""},
-#ifdef WITH_OSL
- {"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
- {"osl_compile", osl_compile_func, METH_VARARGS, ""},
-#endif
- {"available_devices", available_devices_func, METH_VARARGS, ""},
- {"system_info", system_info_func, METH_NOARGS, ""},
-
- /* Standalone denoising */
- {"denoise", (PyCFunction)denoise_func, METH_VARARGS | METH_KEYWORDS, ""},
- {"merge", (PyCFunction)merge_func, METH_VARARGS | METH_KEYWORDS, ""},
-
- /* Debugging routines */
- {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""},
- {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""},
-
- /* Statistics. */
- {"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""},
-
- /* Compute Device selection */
- {"get_device_types", get_device_types_func, METH_VARARGS, ""},
- {"set_device_override", set_device_override_func, METH_O, ""},
-
- {NULL, NULL, 0, NULL},
-};
-
-static struct PyModuleDef module = {
- PyModuleDef_HEAD_INIT,
- "_cycles",
- "Blender cycles render integration",
- -1,
- methods,
- NULL,
- NULL,
- NULL,
- NULL,
-};
-
-CCL_NAMESPACE_END
-
-void *CCL_python_module_init()
-{
- PyObject *mod = PyModule_Create(&ccl::module);
-
-#ifdef WITH_OSL
- /* TODO(sergey): This gives us library we've been linking against.
- * In theory with dynamic OSL library it might not be
- * accurate, but there's nothing in OSL API which we
- * might use to get version in runtime.
- */
- int curversion = OSL_LIBRARY_VERSION_CODE;
- PyModule_AddObject(mod, "with_osl", Py_True);
- Py_INCREF(Py_True);
- PyModule_AddObject(
- mod,
- "osl_version",
- Py_BuildValue("(iii)", curversion / 10000, (curversion / 100) % 100, curversion % 100));
- PyModule_AddObject(
- mod,
- "osl_version_string",
- PyUnicode_FromFormat(
- "%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100));
-#else
- PyModule_AddObject(mod, "with_osl", Py_False);
- Py_INCREF(Py_False);
- PyModule_AddStringConstant(mod, "osl_version", "unknown");
- PyModule_AddStringConstant(mod, "osl_version_string", "unknown");
-#endif
-
-#ifdef WITH_EMBREE
- PyModule_AddObject(mod, "with_embree", Py_True);
- Py_INCREF(Py_True);
-#else /* WITH_EMBREE */
- PyModule_AddObject(mod, "with_embree", Py_False);
- Py_INCREF(Py_False);
-#endif /* WITH_EMBREE */
-
- if (ccl::openimagedenoise_supported()) {
- PyModule_AddObject(mod, "with_openimagedenoise", Py_True);
- Py_INCREF(Py_True);
- }
- else {
- PyModule_AddObject(mod, "with_openimagedenoise", Py_False);
- Py_INCREF(Py_False);
- }
-
- return (void *)mod;
-}
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
deleted file mode 100644
index 0b4b5c60def..00000000000
--- a/intern/cycles/blender/blender_session.cpp
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-
-#include "device/device.h"
-#include "render/background.h"
-#include "render/buffers.h"
-#include "render/camera.h"
-#include "render/colorspace.h"
-#include "render/film.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/scene.h"
-#include "render/session.h"
-#include "render/shader.h"
-#include "render/stats.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_color.h"
-#include "util/util_foreach.h"
-#include "util/util_function.h"
-#include "util/util_hash.h"
-#include "util/util_logging.h"
-#include "util/util_murmurhash.h"
-#include "util/util_path.h"
-#include "util/util_progress.h"
-#include "util/util_time.h"
-
-#include "blender/blender_display_driver.h"
-#include "blender/blender_output_driver.h"
-#include "blender/blender_session.h"
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-CCL_NAMESPACE_BEGIN
-
-DeviceTypeMask BlenderSession::device_override = DEVICE_MASK_ALL;
-bool BlenderSession::headless = false;
-bool BlenderSession::print_render_stats = false;
-
-BlenderSession::BlenderSession(BL::RenderEngine &b_engine,
- BL::Preferences &b_userpref,
- BL::BlendData &b_data,
- bool preview_osl)
- : session(NULL),
- scene(NULL),
- sync(NULL),
- b_engine(b_engine),
- b_userpref(b_userpref),
- b_data(b_data),
- b_render(b_engine.render()),
- b_depsgraph(PointerRNA_NULL),
- b_scene(PointerRNA_NULL),
- b_v3d(PointerRNA_NULL),
- b_rv3d(PointerRNA_NULL),
- width(0),
- height(0),
- preview_osl(preview_osl),
- python_thread_state(NULL),
- use_developer_ui(false)
-{
- /* offline render */
- background = true;
- last_redraw_time = 0.0;
- start_resize_time = 0.0;
- last_status_time = 0.0;
-}
-
-BlenderSession::BlenderSession(BL::RenderEngine &b_engine,
- BL::Preferences &b_userpref,
- BL::BlendData &b_data,
- BL::SpaceView3D &b_v3d,
- BL::RegionView3D &b_rv3d,
- int width,
- int height)
- : session(NULL),
- scene(NULL),
- sync(NULL),
- b_engine(b_engine),
- b_userpref(b_userpref),
- b_data(b_data),
- b_render(b_engine.render()),
- b_depsgraph(PointerRNA_NULL),
- b_scene(PointerRNA_NULL),
- b_v3d(b_v3d),
- b_rv3d(b_rv3d),
- width(width),
- height(height),
- preview_osl(false),
- python_thread_state(NULL),
- use_developer_ui(b_userpref.experimental().use_cycles_debug() &&
- b_userpref.view().show_developer_ui())
-{
- /* 3d view render */
- background = false;
- last_redraw_time = 0.0;
- start_resize_time = 0.0;
- last_status_time = 0.0;
-}
-
-BlenderSession::~BlenderSession()
-{
- free_session();
-}
-
-void BlenderSession::create_session()
-{
- const SessionParams session_params = BlenderSync::get_session_params(
- b_engine, b_userpref, b_scene, background);
- const SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
- const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
-
- /* reset status/progress */
- last_status = "";
- last_error = "";
- last_progress = -1.0f;
- start_resize_time = 0.0;
-
- /* create session */
- session = new Session(session_params, scene_params);
- session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
- session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
- session->set_pause(session_pause);
-
- /* create scene */
- scene = session->scene;
- scene->name = b_scene.name();
-
- /* create sync */
- sync = new BlenderSync(
- b_engine, b_data, b_scene, scene, !background, use_developer_ui, session->progress);
- BL::Object b_camera_override(b_engine.camera_override());
- if (b_v3d) {
- sync->sync_view(b_v3d, b_rv3d, width, height);
- }
- else {
- sync->sync_camera(b_render, b_camera_override, width, height, "");
- }
-
- /* set buffer parameters */
- const BufferParams buffer_params = BlenderSync::get_buffer_params(
- b_v3d, b_rv3d, scene->camera, width, height);
- session->reset(session_params, buffer_params);
-
- /* Viewport and preview (as in, material preview) does not do tiled rendering, so can inform
- * engine that no tracking of the tiles state is needed.
- * The offline rendering will make a decision when tile is being written. The penalty of asking
- * the engine to keep track of tiles state is minimal, so there is nothing to worry about here
- * about possible single-tiled final render. */
- if (!b_engine.is_preview() && !b_v3d) {
- b_engine.use_highlight_tiles(true);
- }
-}
-
-void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph)
-{
- /* Update data, scene and depsgraph pointers. These can change after undo. */
- this->b_data = b_data;
- this->b_depsgraph = b_depsgraph;
- this->b_scene = b_depsgraph.scene_eval();
- if (sync) {
- sync->reset(this->b_data, this->b_scene);
- }
-
- if (preview_osl) {
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- RNA_boolean_set(&cscene, "shading_system", preview_osl);
- }
-
- if (b_v3d) {
- this->b_render = b_scene.render();
- }
- else {
- this->b_render = b_engine.render();
- width = render_resolution_x(b_render);
- height = render_resolution_y(b_render);
- }
-
- bool is_new_session = (session == NULL);
- if (is_new_session) {
- /* Initialize session and remember it was just created so not to
- * re-create it below.
- */
- create_session();
- }
-
- if (b_v3d) {
- /* NOTE: We need to create session, but all the code from below
- * will make viewport render to stuck on initialization.
- */
- return;
- }
-
- const SessionParams session_params = BlenderSync::get_session_params(
- b_engine, b_userpref, b_scene, background);
- const SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
-
- if (scene->params.modified(scene_params) || session->params.modified(session_params) ||
- !this->b_render.use_persistent_data()) {
- /* if scene or session parameters changed, it's easier to simply re-create
- * them rather than trying to distinguish which settings need to be updated
- */
- if (!is_new_session) {
- free_session();
- create_session();
- }
- return;
- }
-
- session->progress.reset();
-
- /* peak memory usage should show current render peak, not peak for all renders
- * made by this render session
- */
- session->stats.mem_peak = session->stats.mem_used;
-
- if (is_new_session) {
- /* Sync object should be re-created for new scene. */
- delete sync;
- sync = new BlenderSync(
- b_engine, b_data, b_scene, scene, !background, use_developer_ui, session->progress);
- }
- else {
- /* Sync recalculations to do just the required updates. */
- sync->sync_recalc(b_depsgraph, b_v3d);
- }
-
- BL::Object b_camera_override(b_engine.camera_override());
- sync->sync_camera(b_render, b_camera_override, width, height, "");
-
- BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
- BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
- const BufferParams buffer_params = BlenderSync::get_buffer_params(
- b_null_space_view3d, b_null_region_view3d, scene->camera, width, height);
- session->reset(session_params, buffer_params);
-
- /* reset time */
- start_resize_time = 0.0;
-
- {
- thread_scoped_lock lock(draw_state_.mutex);
- draw_state_.last_pass_index = -1;
- }
-}
-
-void BlenderSession::free_session()
-{
- if (session) {
- session->cancel(true);
- }
-
- delete sync;
- sync = nullptr;
-
- delete session;
- session = nullptr;
-
- display_driver_ = nullptr;
-}
-
-void BlenderSession::full_buffer_written(string_view filename)
-{
- full_buffer_files_.emplace_back(filename);
-}
-
-static void add_cryptomatte_layer(BL::RenderResult &b_rr, string name, string manifest)
-{
- string identifier = string_printf("%08x", util_murmur_hash3(name.c_str(), name.length(), 0));
- string prefix = "cryptomatte/" + identifier.substr(0, 7) + "/";
-
- render_add_metadata(b_rr, prefix + "name", name);
- render_add_metadata(b_rr, prefix + "hash", "MurmurHash3_32");
- render_add_metadata(b_rr, prefix + "conversion", "uint32_to_float32");
- render_add_metadata(b_rr, prefix + "manifest", manifest);
-}
-
-void BlenderSession::stamp_view_layer_metadata(Scene *scene, const string &view_layer_name)
-{
- BL::RenderResult b_rr = b_engine.get_result();
- string prefix = "cycles." + view_layer_name + ".";
-
- /* Configured number of samples for the view layer. */
- b_rr.stamp_data_add_field((prefix + "samples").c_str(),
- to_string(session->params.samples).c_str());
-
- /* Store ranged samples information. */
- /* TODO(sergey): Need to bring this information back. */
-#if 0
- if (session->tile_manager.range_num_samples != -1) {
- b_rr.stamp_data_add_field((prefix + "range_start_sample").c_str(),
- to_string(session->tile_manager.range_start_sample).c_str());
- b_rr.stamp_data_add_field((prefix + "range_num_samples").c_str(),
- to_string(session->tile_manager.range_num_samples).c_str());
- }
-#endif
-
- /* Write cryptomatte metadata. */
- if (scene->film->get_cryptomatte_passes() & CRYPT_OBJECT) {
- add_cryptomatte_layer(b_rr,
- view_layer_name + ".CryptoObject",
- scene->object_manager->get_cryptomatte_objects(scene));
- }
- if (scene->film->get_cryptomatte_passes() & CRYPT_MATERIAL) {
- add_cryptomatte_layer(b_rr,
- view_layer_name + ".CryptoMaterial",
- scene->shader_manager->get_cryptomatte_materials(scene));
- }
- if (scene->film->get_cryptomatte_passes() & CRYPT_ASSET) {
- add_cryptomatte_layer(b_rr,
- view_layer_name + ".CryptoAsset",
- scene->object_manager->get_cryptomatte_assets(scene));
- }
-
- /* Store synchronization and bare-render times. */
- double total_time, render_time;
- session->progress.get_time(total_time, render_time);
- b_rr.stamp_data_add_field((prefix + "total_time").c_str(),
- time_human_readable_from_seconds(total_time).c_str());
- b_rr.stamp_data_add_field((prefix + "render_time").c_str(),
- time_human_readable_from_seconds(render_time).c_str());
- b_rr.stamp_data_add_field((prefix + "synchronization_time").c_str(),
- time_human_readable_from_seconds(total_time - render_time).c_str());
-}
-
-void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
-{
- b_depsgraph = b_depsgraph_;
-
- if (session->progress.get_cancel()) {
- update_status_progress();
- return;
- }
-
- /* Create driver to write out render results. */
- ensure_display_driver_if_needed();
- session->set_output_driver(make_unique<BlenderOutputDriver>(b_engine));
-
- session->full_buffer_written_cb = [&](string_view filename) { full_buffer_written(filename); };
-
- BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
-
- /* get buffer parameters */
- const SessionParams session_params = BlenderSync::get_session_params(
- b_engine, b_userpref, b_scene, background);
- BufferParams buffer_params = BlenderSync::get_buffer_params(
- b_v3d, b_rv3d, scene->camera, width, height);
-
- /* temporary render result to find needed passes and views */
- BL::RenderResult b_rr = b_engine.begin_result(0, 0, 1, 1, b_view_layer.name().c_str(), NULL);
- BL::RenderResult::layers_iterator b_single_rlay;
- b_rr.layers.begin(b_single_rlay);
- BL::RenderLayer b_rlay = *b_single_rlay;
-
- {
- thread_scoped_lock lock(draw_state_.mutex);
- b_rlay_name = b_view_layer.name();
-
- /* Signal that the display pass is to be updated. */
- draw_state_.last_pass_index = -1;
- }
-
- /* Compute render passes and film settings. */
- sync->sync_render_passes(b_rlay, b_view_layer);
-
- BL::RenderResult::views_iterator b_view_iter;
-
- int num_views = 0;
- for (b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) {
- num_views++;
- }
-
- int view_index = 0;
- for (b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end();
- ++b_view_iter, ++view_index) {
- b_rview_name = b_view_iter->name();
-
- buffer_params.layer = b_view_layer.name();
- buffer_params.view = b_rview_name;
-
- /* set the current view */
- b_engine.active_view_set(b_rview_name.c_str());
-
- /* update scene */
- BL::Object b_camera_override(b_engine.camera_override());
- sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str());
- sync->sync_data(
- b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state);
- builtin_images_load();
-
- /* Attempt to free all data which is held by Blender side, since at this
- * point we know that we've got everything to render current view layer.
- */
- /* At the moment we only free if we are not doing multi-view
- * (or if we are rendering the last view). See T58142/D4239 for discussion.
- */
- if (view_index == num_views - 1) {
- free_blender_memory_if_possible();
- }
-
- /* Make sure all views have different noise patterns. - hardcoded value just to make it random
- */
- if (view_index != 0) {
- int seed = scene->integrator->get_seed();
- seed += hash_uint2(seed, hash_uint2(view_index * 0xdeadbeef, 0));
- scene->integrator->set_seed(seed);
- }
-
- /* Update number of samples per layer. */
- const int samples = sync->get_layer_samples();
- const bool bound_samples = sync->get_layer_bound_samples();
-
- SessionParams effective_session_params = session_params;
- if (samples != 0 && (!bound_samples || (samples < session_params.samples))) {
- effective_session_params.samples = samples;
- }
-
- /* Update session itself. */
- session->reset(effective_session_params, buffer_params);
-
- /* render */
- if (!b_engine.is_preview() && background && print_render_stats) {
- scene->enable_update_stats();
- }
-
- session->start();
- session->wait();
-
- if (!b_engine.is_preview() && background && print_render_stats) {
- RenderStats stats;
- session->collect_statistics(&stats);
- printf("Render statistics:\n%s\n", stats.full_report().c_str());
- }
-
- if (session->progress.get_cancel())
- break;
- }
-
- /* add metadata */
- stamp_view_layer_metadata(scene, b_rlay_name);
-
- /* free result without merging */
- b_engine.end_result(b_rr, true, false, false);
-
- /* When tiled rendering is used there will be no "write" done for the tile. Forcefully clear
- * highlighted tiles now, so that the highlight will be removed while processing full frame from
- * file. */
- b_engine.tile_highlight_clear_all();
-
- double total_time, render_time;
- session->progress.get_time(total_time, render_time);
- VLOG(1) << "Total render time: " << total_time;
- VLOG(1) << "Render time (without synchronization): " << render_time;
-}
-
-void BlenderSession::render_frame_finish()
-{
- /* Processing of all layers and views is done. Clear the strings so that we can communicate
- * progress about reading files and denoising them. */
- b_rlay_name = "";
- b_rview_name = "";
-
- if (!b_render.use_persistent_data()) {
- /* Free the sync object so that it can properly dereference nodes from the scene graph before
- * the graph is freed. */
- delete sync;
- sync = nullptr;
-
- session->device_free();
- }
-
- for (string_view filename : full_buffer_files_) {
- session->process_full_buffer_from_disk(filename);
- if (check_and_report_session_error()) {
- break;
- }
- }
-
- for (string_view filename : full_buffer_files_) {
- path_remove(filename);
- }
-
- /* Clear driver. */
- session->set_output_driver(nullptr);
- session->full_buffer_written_cb = function_null;
-
- /* All the files are handled.
- * Clear the list so that this session can be re-used by Persistent Data. */
- full_buffer_files_.clear();
-}
-
-static PassType bake_type_to_pass(const string &bake_type_str, const int bake_filter)
-{
- const char *bake_type = bake_type_str.c_str();
-
- /* data passes */
- if (strcmp(bake_type, "POSITION") == 0) {
- return PASS_POSITION;
- }
- else if (strcmp(bake_type, "NORMAL") == 0) {
- return PASS_NORMAL;
- }
- else if (strcmp(bake_type, "UV") == 0) {
- return PASS_UV;
- }
- else if (strcmp(bake_type, "ROUGHNESS") == 0) {
- return PASS_ROUGHNESS;
- }
- else if (strcmp(bake_type, "EMIT") == 0) {
- return PASS_EMISSION;
- }
- /* light passes */
- else if (strcmp(bake_type, "AO") == 0) {
- return PASS_AO;
- }
- else if (strcmp(bake_type, "COMBINED") == 0) {
- return PASS_COMBINED;
- }
- else if (strcmp(bake_type, "SHADOW") == 0) {
- return PASS_SHADOW;
- }
- else if (strcmp(bake_type, "DIFFUSE") == 0) {
- if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
- bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
- return PASS_DIFFUSE;
- }
- else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
- return PASS_DIFFUSE_DIRECT;
- }
- else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
- return PASS_DIFFUSE_INDIRECT;
- }
- else {
- return PASS_DIFFUSE_COLOR;
- }
- }
- else if (strcmp(bake_type, "GLOSSY") == 0) {
- if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
- bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
- return PASS_GLOSSY;
- }
- else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
- return PASS_GLOSSY_DIRECT;
- }
- else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
- return PASS_GLOSSY_INDIRECT;
- }
- else {
- return PASS_GLOSSY_COLOR;
- }
- }
- else if (strcmp(bake_type, "TRANSMISSION") == 0) {
- if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
- bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
- return PASS_TRANSMISSION;
- }
- else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
- return PASS_TRANSMISSION_DIRECT;
- }
- else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
- return PASS_TRANSMISSION_INDIRECT;
- }
- else {
- return PASS_TRANSMISSION_COLOR;
- }
- }
- /* extra */
- else if (strcmp(bake_type, "ENVIRONMENT") == 0) {
- return PASS_BACKGROUND;
- }
-
- return PASS_COMBINED;
-}
-
-void BlenderSession::bake(BL::Depsgraph &b_depsgraph_,
- BL::Object &b_object,
- const string &bake_type,
- const int bake_filter,
- const int bake_width,
- const int bake_height)
-{
- b_depsgraph = b_depsgraph_;
-
- /* Initialize bake manager, before we load the baking kernels. */
- scene->bake_manager->set(scene, b_object.name());
-
- /* Add render pass that we want to bake, and name it Combined so that it is
- * used as that on the Blender side. */
- Pass *pass = scene->create_node<Pass>();
- pass->set_name(ustring("Combined"));
- pass->set_type(bake_type_to_pass(bake_type, bake_filter));
- pass->set_include_albedo((bake_filter & BL::BakeSettings::pass_filter_COLOR));
-
- session->set_display_driver(nullptr);
- session->set_output_driver(make_unique<BlenderOutputDriver>(b_engine));
-
- if (!session->progress.get_cancel()) {
- /* Sync scene. */
- BL::Object b_camera_override(b_engine.camera_override());
- sync->sync_camera(b_render, b_camera_override, width, height, "");
- sync->sync_data(
- b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state);
- builtin_images_load();
- }
-
- /* Object might have been disabled for rendering or excluded in some
- * other way, in that case Blender will report a warning afterwards. */
- bool object_found = false;
- foreach (Object *ob, scene->objects) {
- if (ob->name == b_object.name()) {
- object_found = true;
- break;
- }
- }
-
- if (object_found && !session->progress.get_cancel()) {
- /* Get session and buffer parameters. */
- const SessionParams session_params = BlenderSync::get_session_params(
- b_engine, b_userpref, b_scene, background);
-
- BufferParams buffer_params;
- buffer_params.width = bake_width;
- buffer_params.height = bake_height;
-
- /* Update session. */
- session->reset(session_params, buffer_params);
-
- session->progress.set_update_callback(
- function_bind(&BlenderSession::update_bake_progress, this));
- }
-
- /* Perform bake. Check cancel to avoid crash with incomplete scene data. */
- if (object_found && !session->progress.get_cancel()) {
- session->start();
- session->wait();
- }
-
- session->set_output_driver(nullptr);
-}
-
-void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
-{
- /* only used for viewport render */
- if (!b_v3d)
- return;
-
- /* on session/scene parameter changes, we recreate session entirely */
- const SessionParams session_params = BlenderSync::get_session_params(
- b_engine, b_userpref, b_scene, background);
- const SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
- const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
-
- if (session->params.modified(session_params) || scene->params.modified(scene_params)) {
- free_session();
- create_session();
- }
-
- ensure_display_driver_if_needed();
-
- /* increase samples and render time, but never decrease */
- session->set_samples(session_params.samples);
- session->set_time_limit(session_params.time_limit);
- session->set_pause(session_pause);
-
- /* copy recalc flags, outside of mutex so we can decide to do the real
- * synchronization at a later time to not block on running updates */
- sync->sync_recalc(b_depsgraph_, b_v3d);
-
- /* don't do synchronization if on pause */
- if (session_pause) {
- tag_update();
- return;
- }
-
- /* try to acquire mutex. if we don't want to or can't, come back later */
- if (!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
- tag_update();
- return;
- }
-
- /* data and camera synchronize */
- b_depsgraph = b_depsgraph_;
-
- BL::Object b_camera_override(b_engine.camera_override());
- sync->sync_data(
- b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state);
-
- if (b_rv3d)
- sync->sync_view(b_v3d, b_rv3d, width, height);
- else
- sync->sync_camera(b_render, b_camera_override, width, height, "");
-
- /* get buffer parameters */
- const BufferParams buffer_params = BlenderSync::get_buffer_params(
- b_v3d, b_rv3d, scene->camera, width, height);
-
- /* reset if needed */
- if (scene->need_reset()) {
- session->reset(session_params, buffer_params);
-
- /* After session reset, so device is not accessing image data anymore. */
- builtin_images_load();
-
- /* reset time */
- start_resize_time = 0.0;
- }
-
- /* unlock */
- session->scene->mutex.unlock();
-
- /* Start rendering thread, if it's not running already. Do this
- * after all scene data has been synced at least once. */
- session->start();
-}
-
-void BlenderSession::draw(BL::SpaceImageEditor &space_image)
-{
- if (!session || !session->scene) {
- /* Offline render drawing does not force the render engine update, which means it's possible
- * that the Session is not created yet. */
- return;
- }
-
- thread_scoped_lock lock(draw_state_.mutex);
-
- const int pass_index = space_image.image_user().multilayer_pass();
- if (pass_index != draw_state_.last_pass_index) {
- BL::RenderPass b_display_pass(b_engine.pass_by_index_get(b_rlay_name.c_str(), pass_index));
- if (!b_display_pass) {
- return;
- }
-
- Scene *scene = session->scene;
-
- thread_scoped_lock lock(scene->mutex);
-
- const Pass *pass = Pass::find(scene->passes, b_display_pass.name());
- if (!pass) {
- return;
- }
-
- scene->film->set_display_pass(pass->get_type());
-
- draw_state_.last_pass_index = pass_index;
- }
-
- if (display_driver_) {
- BL::Array<float, 2> zoom = space_image.zoom();
- display_driver_->set_zoom(zoom[0], zoom[1]);
- }
-
- session->draw();
-}
-
-void BlenderSession::view_draw(int w, int h)
-{
- /* pause in redraw in case update is not being called due to final render */
- session->set_pause(BlenderSync::get_session_pause(b_scene, background));
-
- /* before drawing, we verify camera and viewport size changes, because
- * we do not get update callbacks for those, we must detect them here */
- if (session->ready_to_reset()) {
- bool reset = false;
-
- /* if dimensions changed, reset */
- if (width != w || height != h) {
- if (start_resize_time == 0.0) {
- /* don't react immediately to resizes to avoid flickery resizing
- * of the viewport, and some window managers changing the window
- * size temporarily on unminimize */
- start_resize_time = time_dt();
- tag_redraw();
- }
- else if (time_dt() - start_resize_time < 0.2) {
- tag_redraw();
- }
- else {
- width = w;
- height = h;
- reset = true;
- }
- }
-
- /* try to acquire mutex. if we can't, come back later */
- if (!session->scene->mutex.try_lock()) {
- tag_update();
- }
- else {
- /* update camera from 3d view */
-
- sync->sync_view(b_v3d, b_rv3d, width, height);
-
- if (scene->camera->is_modified())
- reset = true;
-
- session->scene->mutex.unlock();
- }
-
- /* reset if requested */
- if (reset) {
- const SessionParams session_params = BlenderSync::get_session_params(
- b_engine, b_userpref, b_scene, background);
- const BufferParams buffer_params = BlenderSync::get_buffer_params(
- b_v3d, b_rv3d, scene->camera, width, height);
- const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
-
- if (session_pause == false) {
- session->reset(session_params, buffer_params);
- start_resize_time = 0.0;
- }
- }
- }
- else {
- tag_update();
- }
-
- /* update status and progress for 3d view draw */
- update_status_progress();
-
- /* draw */
- session->draw();
-}
-
-void BlenderSession::get_status(string &status, string &substatus)
-{
- session->progress.get_status(status, substatus);
-}
-
-void BlenderSession::get_progress(float &progress, double &total_time, double &render_time)
-{
- session->progress.get_time(total_time, render_time);
- progress = session->progress.get_progress();
-}
-
-void BlenderSession::update_bake_progress()
-{
- float progress = session->progress.get_progress();
-
- if (progress != last_progress) {
- b_engine.update_progress(progress);
- last_progress = progress;
- }
-}
-
-void BlenderSession::update_status_progress()
-{
- string timestatus, status, substatus;
- string scene_status = "";
- float progress;
- double total_time, remaining_time = 0, render_time;
- float mem_used = (float)session->stats.mem_used / 1024.0f / 1024.0f;
- float mem_peak = (float)session->stats.mem_peak / 1024.0f / 1024.0f;
-
- get_status(status, substatus);
- get_progress(progress, total_time, render_time);
-
- if (progress > 0) {
- remaining_time = session->get_estimated_remaining_time();
- }
-
- if (background) {
- if (scene)
- scene_status += " | " + scene->name;
- if (b_rlay_name != "")
- scene_status += ", " + b_rlay_name;
-
- if (b_rview_name != "")
- scene_status += ", " + b_rview_name;
-
- if (remaining_time > 0) {
- timestatus += "Remaining:" + time_human_readable_from_seconds(remaining_time) + " | ";
- }
-
- timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak);
-
- if (status.size() > 0)
- status = " | " + status;
- if (substatus.size() > 0)
- status += " | " + substatus;
- }
-
- double current_time = time_dt();
- /* When rendering in a window, redraw the status at least once per second to keep the elapsed
- * and remaining time up-to-date. For headless rendering, only report when something
- * significant changes to keep the console output readable. */
- if (status != last_status || (!headless && (current_time - last_status_time) > 1.0)) {
- b_engine.update_stats("", (timestatus + scene_status + status).c_str());
- b_engine.update_memory_stats(mem_used, mem_peak);
- last_status = status;
- last_status_time = current_time;
- }
- if (progress != last_progress) {
- b_engine.update_progress(progress);
- last_progress = progress;
- }
-
- check_and_report_session_error();
-}
-
-bool BlenderSession::check_and_report_session_error()
-{
- if (!session->progress.get_error()) {
- return false;
- }
-
- const string error = session->progress.get_error_message();
- if (error != last_error) {
- /* TODO(sergey): Currently C++ RNA API doesn't let us to use mnemonic name for the variable.
- * Would be nice to have this figured out.
- *
- * For until then, 1 << 5 means RPT_ERROR. */
- b_engine.report(1 << 5, error.c_str());
- b_engine.error_set(error.c_str());
- last_error = error;
- }
-
- return true;
-}
-
-void BlenderSession::tag_update()
-{
- /* tell blender that we want to get another update callback */
- b_engine.tag_update();
-}
-
-void BlenderSession::tag_redraw()
-{
- if (background) {
- /* update stats and progress, only for background here because
- * in 3d view we do it in draw for thread safety reasons */
- update_status_progress();
-
- /* offline render, redraw if timeout passed */
- if (time_dt() - last_redraw_time > 1.0) {
- b_engine.tag_redraw();
- last_redraw_time = time_dt();
- }
- }
- else {
- /* tell blender that we want to redraw */
- b_engine.tag_redraw();
- }
-}
-
-void BlenderSession::test_cancel()
-{
- /* test if we need to cancel rendering */
- if (background)
- if (b_engine.test_break())
- session->progress.set_cancel("Cancelled");
-}
-
-void BlenderSession::free_blender_memory_if_possible()
-{
- if (!background) {
- /* During interactive render we can not free anything: attempts to save
- * memory would cause things to be allocated and evaluated for every
- * updated sample.
- */
- return;
- }
- b_engine.free_blender_memory();
-}
-
-void BlenderSession::ensure_display_driver_if_needed()
-{
- if (display_driver_) {
- /* Driver is already created. */
- return;
- }
-
- if (headless) {
- /* No display needed for headless. */
- return;
- }
-
- if (b_engine.is_preview()) {
- /* TODO(sergey): Investigate whether DisplayDriver can be used for the preview as well. */
- return;
- }
-
- unique_ptr<BlenderDisplayDriver> display_driver = make_unique<BlenderDisplayDriver>(b_engine,
- b_scene);
- display_driver_ = display_driver.get();
- session->set_display_driver(move(display_driver));
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
deleted file mode 100644
index 7d3be5f8054..00000000000
--- a/intern/cycles/blender/blender_session.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BLENDER_SESSION_H__
-#define __BLENDER_SESSION_H__
-
-#include "RNA_blender_cpp.h"
-
-#include "device/device.h"
-
-#include "render/bake.h"
-#include "render/scene.h"
-#include "render/session.h"
-
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BlenderDisplayDriver;
-class BlenderSync;
-class ImageMetaData;
-class Scene;
-class Session;
-
-class BlenderSession {
- public:
- BlenderSession(BL::RenderEngine &b_engine,
- BL::Preferences &b_userpref,
- BL::BlendData &b_data,
- bool preview_osl);
-
- BlenderSession(BL::RenderEngine &b_engine,
- BL::Preferences &b_userpref,
- BL::BlendData &b_data,
- BL::SpaceView3D &b_v3d,
- BL::RegionView3D &b_rv3d,
- int width,
- int height);
-
- ~BlenderSession();
-
- /* session */
- void create_session();
- void free_session();
-
- void reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph);
-
- /* offline render */
- void render(BL::Depsgraph &b_depsgraph);
-
- void render_frame_finish();
-
- void bake(BL::Depsgraph &b_depsgrah,
- BL::Object &b_object,
- const string &pass_type,
- const int custom_flag,
- const int bake_width,
- const int bake_height);
-
- void full_buffer_written(string_view filename);
- /* interactive updates */
- void synchronize(BL::Depsgraph &b_depsgraph);
-
- /* drawing */
- void draw(BL::SpaceImageEditor &space_image);
- void view_draw(int w, int h);
- void tag_redraw();
- void tag_update();
- void get_status(string &status, string &substatus);
- void get_progress(float &progress, double &total_time, double &render_time);
- void test_cancel();
- void update_status_progress();
- void update_bake_progress();
-
- bool background;
- Session *session;
- Scene *scene;
- BlenderSync *sync;
- double last_redraw_time;
-
- BL::RenderEngine b_engine;
- BL::Preferences b_userpref;
- BL::BlendData b_data;
- BL::RenderSettings b_render;
- BL::Depsgraph b_depsgraph;
- /* NOTE: Blender's scene might become invalid after call
- * #free_blender_memory_if_possible(). */
- BL::Scene b_scene;
- BL::SpaceView3D b_v3d;
- BL::RegionView3D b_rv3d;
- string b_rlay_name;
- string b_rview_name;
-
- string last_status;
- string last_error;
- float last_progress;
- double last_status_time;
-
- int width, height;
- bool preview_osl;
- double start_resize_time;
-
- void *python_thread_state;
-
- bool use_developer_ui;
-
- /* Global state which is common for all render sessions created from Blender.
- * Usually denotes command line arguments.
- */
- static DeviceTypeMask device_override;
-
- /* Blender is running from the command line, no windows are shown and some
- * extra render optimization is possible (possible to free draw-only data and
- * so on.
- */
- static bool headless;
-
- static bool print_render_stats;
-
- protected:
- void stamp_view_layer_metadata(Scene *scene, const string &view_layer_name);
-
- /* Check whether session error happened.
- * If so, it is reported to the render engine and true is returned.
- * Otherwise false is returned. */
- bool check_and_report_session_error();
-
- void builtin_images_load();
-
- /* Is used after each render layer synchronization is done with the goal
- * of freeing render engine data which is held from Blender side (for
- * example, dependency graph).
- */
- void free_blender_memory_if_possible();
-
- void ensure_display_driver_if_needed();
-
- struct {
- thread_mutex mutex;
- int last_pass_index = -1;
- } draw_state_;
-
- /* NOTE: The BlenderSession references the display driver. */
- BlenderDisplayDriver *display_driver_ = nullptr;
-
- vector<string> full_buffer_files_;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BLENDER_SESSION_H__ */
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
deleted file mode 100644
index db5eadeed56..00000000000
--- a/intern/cycles/blender/blender_shader.cpp
+++ /dev/null
@@ -1,1572 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/background.h"
-#include "render/colorspace.h"
-#include "render/graph.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/nodes.h"
-#include "render/osl.h"
-#include "render/scene.h"
-#include "render/shader.h"
-
-#include "blender/blender_image.h"
-#include "blender/blender_sync.h"
-#include "blender/blender_texture.h"
-#include "blender/blender_util.h"
-
-#include "util/util_debug.h"
-#include "util/util_foreach.h"
-#include "util/util_set.h"
-#include "util/util_string.h"
-#include "util/util_task.h"
-
-CCL_NAMESPACE_BEGIN
-
-typedef map<void *, ShaderInput *> PtrInputMap;
-typedef map<void *, ShaderOutput *> PtrOutputMap;
-typedef map<string, ConvertNode *> ProxyMap;
-
-/* Find */
-
-void BlenderSync::find_shader(BL::ID &id, array<Node *> &used_shaders, Shader *default_shader)
-{
- Shader *shader = (id) ? shader_map.find(id) : default_shader;
-
- used_shaders.push_back_slow(shader);
- shader->tag_used(scene);
-}
-
-/* RNA translation utilities */
-
-static VolumeSampling get_volume_sampling(PointerRNA &ptr)
-{
- return (VolumeSampling)get_enum(
- ptr, "volume_sampling", VOLUME_NUM_SAMPLING, VOLUME_SAMPLING_DISTANCE);
-}
-
-static VolumeInterpolation get_volume_interpolation(PointerRNA &ptr)
-{
- return (VolumeInterpolation)get_enum(
- ptr, "volume_interpolation", VOLUME_NUM_INTERPOLATION, VOLUME_INTERPOLATION_LINEAR);
-}
-
-static DisplacementMethod get_displacement_method(PointerRNA &ptr)
-{
- return (DisplacementMethod)get_enum(
- ptr, "displacement_method", DISPLACE_NUM_METHODS, DISPLACE_BUMP);
-}
-
-static int validate_enum_value(int value, int num_values, int default_value)
-{
- if (value >= num_values) {
- return default_value;
- }
- return value;
-}
-
-template<typename NodeType> static InterpolationType get_image_interpolation(NodeType &b_node)
-{
- int value = b_node.interpolation();
- return (InterpolationType)validate_enum_value(
- value, INTERPOLATION_NUM_TYPES, INTERPOLATION_LINEAR);
-}
-
-template<typename NodeType> static ExtensionType get_image_extension(NodeType &b_node)
-{
- int value = b_node.extension();
- return (ExtensionType)validate_enum_value(value, EXTENSION_NUM_TYPES, EXTENSION_REPEAT);
-}
-
-static ImageAlphaType get_image_alpha_type(BL::Image &b_image)
-{
- int value = b_image.alpha_mode();
- return (ImageAlphaType)validate_enum_value(value, IMAGE_ALPHA_NUM_TYPES, IMAGE_ALPHA_AUTO);
-}
-
-/* Attribute name translation utilities */
-
-/* Since Eevee needs to know whether the attribute is uniform or varying
- * at the time it compiles the shader for the material, Blender had to
- * introduce different namespaces (types) in its attribute node. However,
- * Cycles already has object attributes that form a uniform namespace with
- * the more common varying attributes. Without completely reworking the
- * attribute handling in Cycles to introduce separate namespaces (this could
- * be especially hard for OSL which directly uses the name string), the
- * space identifier has to be added to the attribute name as a prefix.
- *
- * The prefixes include a control character to ensure the user specified
- * name can't accidentally include a special prefix.
- */
-
-static const string_view object_attr_prefix("\x01object:");
-static const string_view instancer_attr_prefix("\x01instancer:");
-
-static ustring blender_attribute_name_add_type(const string &name, BlenderAttributeType type)
-{
- switch (type) {
- case BL::ShaderNodeAttribute::attribute_type_OBJECT:
- return ustring::concat(object_attr_prefix, name);
- case BL::ShaderNodeAttribute::attribute_type_INSTANCER:
- return ustring::concat(instancer_attr_prefix, name);
- default:
- return ustring(name);
- }
-}
-
-BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name)
-{
- string_view sname(name);
-
- if (sname.substr(0, object_attr_prefix.size()) == object_attr_prefix) {
- *r_real_name = sname.substr(object_attr_prefix.size());
- return BL::ShaderNodeAttribute::attribute_type_OBJECT;
- }
-
- if (sname.substr(0, instancer_attr_prefix.size()) == instancer_attr_prefix) {
- *r_real_name = sname.substr(instancer_attr_prefix.size());
- return BL::ShaderNodeAttribute::attribute_type_INSTANCER;
- }
-
- return BL::ShaderNodeAttribute::attribute_type_GEOMETRY;
-}
-
-/* Graph */
-
-static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name)
-{
- for (BL::NodeSocket &b_out : b_node.outputs) {
- if (b_out.identifier() == name) {
- return b_out;
- }
- }
- assert(0);
- return *b_node.outputs.begin();
-}
-
-static float3 get_node_output_rgba(BL::Node &b_node, const string &name)
-{
- BL::NodeSocket b_sock = get_node_output(b_node, name);
- float value[4];
- RNA_float_get_array(&b_sock.ptr, "default_value", value);
- return make_float3(value[0], value[1], value[2]);
-}
-
-static float get_node_output_value(BL::Node &b_node, const string &name)
-{
- BL::NodeSocket b_sock = get_node_output(b_node, name);
- return RNA_float_get(&b_sock.ptr, "default_value");
-}
-
-static float3 get_node_output_vector(BL::Node &b_node, const string &name)
-{
- BL::NodeSocket b_sock = get_node_output(b_node, name);
- float value[3];
- RNA_float_get_array(&b_sock.ptr, "default_value", value);
- return make_float3(value[0], value[1], value[2]);
-}
-
-static SocketType::Type convert_socket_type(BL::NodeSocket &b_socket)
-{
- switch (b_socket.type()) {
- case BL::NodeSocket::type_VALUE:
- return SocketType::FLOAT;
- case BL::NodeSocket::type_INT:
- return SocketType::INT;
- case BL::NodeSocket::type_VECTOR:
- return SocketType::VECTOR;
- case BL::NodeSocket::type_RGBA:
- return SocketType::COLOR;
- case BL::NodeSocket::type_STRING:
- return SocketType::STRING;
- case BL::NodeSocket::type_SHADER:
- return SocketType::CLOSURE;
-
- default:
- return SocketType::UNDEFINED;
- }
-}
-
-static void set_default_value(ShaderInput *input,
- BL::NodeSocket &b_sock,
- BL::BlendData &b_data,
- BL::ID &b_id)
-{
- Node *node = input->parent;
- const SocketType &socket = input->socket_type;
-
- /* copy values for non linked inputs */
- switch (input->type()) {
- case SocketType::FLOAT: {
- node->set(socket, get_float(b_sock.ptr, "default_value"));
- break;
- }
- case SocketType::INT: {
- if (b_sock.type() == BL::NodeSocket::type_BOOLEAN) {
- node->set(socket, get_boolean(b_sock.ptr, "default_value"));
- }
- else {
- node->set(socket, get_int(b_sock.ptr, "default_value"));
- }
- break;
- }
- case SocketType::COLOR: {
- node->set(socket, float4_to_float3(get_float4(b_sock.ptr, "default_value")));
- break;
- }
- case SocketType::NORMAL:
- case SocketType::POINT:
- case SocketType::VECTOR: {
- node->set(socket, get_float3(b_sock.ptr, "default_value"));
- break;
- }
- case SocketType::STRING: {
- node->set(
- socket,
- (ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
- break;
- }
- default:
- break;
- }
-}
-
-static void get_tex_mapping(TextureNode *mapping, BL::TexMapping &b_mapping)
-{
- if (!b_mapping)
- return;
-
- mapping->set_tex_mapping_translation(get_float3(b_mapping.translation()));
- mapping->set_tex_mapping_rotation(get_float3(b_mapping.rotation()));
- mapping->set_tex_mapping_scale(get_float3(b_mapping.scale()));
- mapping->set_tex_mapping_type((TextureMapping::Type)b_mapping.vector_type());
-
- mapping->set_tex_mapping_x_mapping((TextureMapping::Mapping)b_mapping.mapping_x());
- mapping->set_tex_mapping_y_mapping((TextureMapping::Mapping)b_mapping.mapping_y());
- mapping->set_tex_mapping_z_mapping((TextureMapping::Mapping)b_mapping.mapping_z());
-}
-
-static ShaderNode *add_node(Scene *scene,
- BL::RenderEngine &b_engine,
- BL::BlendData &b_data,
- BL::Depsgraph &b_depsgraph,
- BL::Scene &b_scene,
- ShaderGraph *graph,
- BL::ShaderNodeTree &b_ntree,
- BL::ShaderNode &b_node)
-{
- ShaderNode *node = NULL;
-
- /* existing blender nodes */
- if (b_node.is_a(&RNA_ShaderNodeRGBCurve)) {
- BL::ShaderNodeRGBCurve b_curve_node(b_node);
- BL::CurveMapping mapping(b_curve_node.mapping());
- RGBCurvesNode *curves = graph->create_node<RGBCurvesNode>();
- array<float3> curve_mapping_curves;
- float min_x, max_x;
- curvemapping_color_to_array(mapping, curve_mapping_curves, RAMP_TABLE_SIZE, true);
- curvemapping_minmax(mapping, 4, &min_x, &max_x);
- curves->set_min_x(min_x);
- curves->set_max_x(max_x);
- curves->set_curves(curve_mapping_curves);
- node = curves;
- }
- if (b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
- BL::ShaderNodeVectorCurve b_curve_node(b_node);
- BL::CurveMapping mapping(b_curve_node.mapping());
- VectorCurvesNode *curves = graph->create_node<VectorCurvesNode>();
- array<float3> curve_mapping_curves;
- float min_x, max_x;
- curvemapping_color_to_array(mapping, curve_mapping_curves, RAMP_TABLE_SIZE, false);
- curvemapping_minmax(mapping, 3, &min_x, &max_x);
- curves->set_min_x(min_x);
- curves->set_max_x(max_x);
- curves->set_curves(curve_mapping_curves);
- node = curves;
- }
- else if (b_node.is_a(&RNA_ShaderNodeFloatCurve)) {
- BL::ShaderNodeFloatCurve b_curve_node(b_node);
- BL::CurveMapping mapping(b_curve_node.mapping());
- FloatCurveNode *curve = graph->create_node<FloatCurveNode>();
- array<float> curve_mapping_curve;
- float min_x, max_x;
- curvemapping_float_to_array(mapping, curve_mapping_curve, RAMP_TABLE_SIZE);
- curvemapping_minmax(mapping, 1, &min_x, &max_x);
- curve->set_min_x(min_x);
- curve->set_max_x(max_x);
- curve->set_curve(curve_mapping_curve);
- node = curve;
- }
- else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) {
- RGBRampNode *ramp = graph->create_node<RGBRampNode>();
- BL::ShaderNodeValToRGB b_ramp_node(b_node);
- BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp());
- array<float3> ramp_values;
- array<float> ramp_alpha;
- colorramp_to_array(b_color_ramp, ramp_values, ramp_alpha, RAMP_TABLE_SIZE);
- ramp->set_ramp(ramp_values);
- ramp->set_ramp_alpha(ramp_alpha);
- ramp->set_interpolate(b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT);
- node = ramp;
- }
- else if (b_node.is_a(&RNA_ShaderNodeRGB)) {
- ColorNode *color = graph->create_node<ColorNode>();
- color->set_value(get_node_output_rgba(b_node, "Color"));
- node = color;
- }
- else if (b_node.is_a(&RNA_ShaderNodeValue)) {
- ValueNode *value = graph->create_node<ValueNode>();
- value->set_value(get_node_output_value(b_node, "Value"));
- node = value;
- }
- else if (b_node.is_a(&RNA_ShaderNodeCameraData)) {
- node = graph->create_node<CameraNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeInvert)) {
- node = graph->create_node<InvertNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeGamma)) {
- node = graph->create_node<GammaNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
- node = graph->create_node<BrightContrastNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeMixRGB)) {
- BL::ShaderNodeMixRGB b_mix_node(b_node);
- MixNode *mix = graph->create_node<MixNode>();
- mix->set_mix_type((NodeMix)b_mix_node.blend_type());
- mix->set_use_clamp(b_mix_node.use_clamp());
- node = mix;
- }
- else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
- node = graph->create_node<SeparateRGBNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
- node = graph->create_node<CombineRGBNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeSeparateHSV)) {
- node = graph->create_node<SeparateHSVNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
- node = graph->create_node<CombineHSVNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) {
- node = graph->create_node<SeparateXYZNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeCombineXYZ)) {
- node = graph->create_node<CombineXYZNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeHueSaturation)) {
- node = graph->create_node<HSVNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
- node = graph->create_node<RGBToBWNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeMapRange)) {
- BL::ShaderNodeMapRange b_map_range_node(b_node);
- MapRangeNode *map_range_node = graph->create_node<MapRangeNode>();
- map_range_node->set_clamp(b_map_range_node.clamp());
- map_range_node->set_range_type((NodeMapRangeType)b_map_range_node.interpolation_type());
- node = map_range_node;
- }
- else if (b_node.is_a(&RNA_ShaderNodeClamp)) {
- BL::ShaderNodeClamp b_clamp_node(b_node);
- ClampNode *clamp_node = graph->create_node<ClampNode>();
- clamp_node->set_clamp_type((NodeClampType)b_clamp_node.clamp_type());
- node = clamp_node;
- }
- else if (b_node.is_a(&RNA_ShaderNodeMath)) {
- BL::ShaderNodeMath b_math_node(b_node);
- MathNode *math_node = graph->create_node<MathNode>();
- math_node->set_math_type((NodeMathType)b_math_node.operation());
- math_node->set_use_clamp(b_math_node.use_clamp());
- node = math_node;
- }
- else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
- BL::ShaderNodeVectorMath b_vector_math_node(b_node);
- VectorMathNode *vector_math_node = graph->create_node<VectorMathNode>();
- vector_math_node->set_math_type((NodeVectorMathType)b_vector_math_node.operation());
- node = vector_math_node;
- }
- else if (b_node.is_a(&RNA_ShaderNodeVectorRotate)) {
- BL::ShaderNodeVectorRotate b_vector_rotate_node(b_node);
- VectorRotateNode *vector_rotate_node = graph->create_node<VectorRotateNode>();
- vector_rotate_node->set_rotate_type(
- (NodeVectorRotateType)b_vector_rotate_node.rotation_type());
- vector_rotate_node->set_invert(b_vector_rotate_node.invert());
- node = vector_rotate_node;
- }
- else if (b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
- BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
- VectorTransformNode *vtransform = graph->create_node<VectorTransformNode>();
- vtransform->set_transform_type((NodeVectorTransformType)b_vector_transform_node.vector_type());
- vtransform->set_convert_from(
- (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from());
- vtransform->set_convert_to(
- (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to());
- node = vtransform;
- }
- else if (b_node.is_a(&RNA_ShaderNodeNormal)) {
- BL::Node::outputs_iterator out_it;
- b_node.outputs.begin(out_it);
-
- NormalNode *norm = graph->create_node<NormalNode>();
- norm->set_direction(get_node_output_vector(b_node, "Normal"));
- node = norm;
- }
- else if (b_node.is_a(&RNA_ShaderNodeMapping)) {
- BL::ShaderNodeMapping b_mapping_node(b_node);
- MappingNode *mapping = graph->create_node<MappingNode>();
- mapping->set_mapping_type((NodeMappingType)b_mapping_node.vector_type());
- node = mapping;
- }
- else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {
- node = graph->create_node<FresnelNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
- node = graph->create_node<LayerWeightNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeAddShader)) {
- node = graph->create_node<AddClosureNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeMixShader)) {
- node = graph->create_node<MixClosureNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeAttribute)) {
- BL::ShaderNodeAttribute b_attr_node(b_node);
- AttributeNode *attr = graph->create_node<AttributeNode>();
- attr->set_attribute(blender_attribute_name_add_type(b_attr_node.attribute_name(),
- b_attr_node.attribute_type()));
- node = attr;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBackground)) {
- node = graph->create_node<BackgroundNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeHoldout)) {
- node = graph->create_node<HoldoutNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
- BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node);
- AnisotropicBsdfNode *aniso = graph->create_node<AnisotropicBsdfNode>();
-
- switch (b_aniso_node.distribution()) {
- case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
- aniso->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
- break;
- case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
- aniso->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
- break;
- case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
- aniso->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
- break;
- case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
- aniso->set_distribution(CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
- break;
- }
-
- node = aniso;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
- node = graph->create_node<DiffuseBsdfNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) {
- BL::ShaderNodeSubsurfaceScattering b_subsurface_node(b_node);
-
- SubsurfaceScatteringNode *subsurface = graph->create_node<SubsurfaceScatteringNode>();
-
- switch (b_subsurface_node.falloff()) {
- case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
- subsurface->set_method(CLOSURE_BSSRDF_BURLEY_ID);
- break;
- case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK_FIXED_RADIUS:
- subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
- break;
- case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK:
- subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
- break;
- }
-
- node = subsurface;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
- BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
- GlossyBsdfNode *glossy = graph->create_node<GlossyBsdfNode>();
-
- switch (b_glossy_node.distribution()) {
- case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
- glossy->set_distribution(CLOSURE_BSDF_REFLECTION_ID);
- break;
- case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
- glossy->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
- break;
- case BL::ShaderNodeBsdfGlossy::distribution_GGX:
- glossy->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
- break;
- case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
- glossy->set_distribution(CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
- break;
- case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
- glossy->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
- break;
- }
- node = glossy;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfGlass)) {
- BL::ShaderNodeBsdfGlass b_glass_node(b_node);
- GlassBsdfNode *glass = graph->create_node<GlassBsdfNode>();
- switch (b_glass_node.distribution()) {
- case BL::ShaderNodeBsdfGlass::distribution_SHARP:
- glass->set_distribution(CLOSURE_BSDF_SHARP_GLASS_ID);
- break;
- case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
- glass->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
- break;
- case BL::ShaderNodeBsdfGlass::distribution_GGX:
- glass->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
- break;
- case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX:
- glass->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
- break;
- }
- node = glass;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) {
- BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
- RefractionBsdfNode *refraction = graph->create_node<RefractionBsdfNode>();
- switch (b_refraction_node.distribution()) {
- case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
- refraction->set_distribution(CLOSURE_BSDF_REFRACTION_ID);
- break;
- case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
- refraction->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
- break;
- case BL::ShaderNodeBsdfRefraction::distribution_GGX:
- refraction->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
- break;
- }
- node = refraction;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfToon)) {
- BL::ShaderNodeBsdfToon b_toon_node(b_node);
- ToonBsdfNode *toon = graph->create_node<ToonBsdfNode>();
- switch (b_toon_node.component()) {
- case BL::ShaderNodeBsdfToon::component_DIFFUSE:
- toon->set_component(CLOSURE_BSDF_DIFFUSE_TOON_ID);
- break;
- case BL::ShaderNodeBsdfToon::component_GLOSSY:
- toon->set_component(CLOSURE_BSDF_GLOSSY_TOON_ID);
- break;
- }
- node = toon;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfHair)) {
- BL::ShaderNodeBsdfHair b_hair_node(b_node);
- HairBsdfNode *hair = graph->create_node<HairBsdfNode>();
- switch (b_hair_node.component()) {
- case BL::ShaderNodeBsdfHair::component_Reflection:
- hair->set_component(CLOSURE_BSDF_HAIR_REFLECTION_ID);
- break;
- case BL::ShaderNodeBsdfHair::component_Transmission:
- hair->set_component(CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
- break;
- }
- node = hair;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfHairPrincipled)) {
- BL::ShaderNodeBsdfHairPrincipled b_principled_hair_node(b_node);
- PrincipledHairBsdfNode *principled_hair = graph->create_node<PrincipledHairBsdfNode>();
- principled_hair->set_parametrization(
- (NodePrincipledHairParametrization)get_enum(b_principled_hair_node.ptr,
- "parametrization",
- NODE_PRINCIPLED_HAIR_NUM,
- NODE_PRINCIPLED_HAIR_REFLECTANCE));
- node = principled_hair;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) {
- BL::ShaderNodeBsdfPrincipled b_principled_node(b_node);
- PrincipledBsdfNode *principled = graph->create_node<PrincipledBsdfNode>();
- switch (b_principled_node.distribution()) {
- case BL::ShaderNodeBsdfPrincipled::distribution_GGX:
- principled->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
- break;
- case BL::ShaderNodeBsdfPrincipled::distribution_MULTI_GGX:
- principled->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
- break;
- }
- switch (b_principled_node.subsurface_method()) {
- case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY:
- principled->set_subsurface_method(CLOSURE_BSSRDF_BURLEY_ID);
- break;
- case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK_FIXED_RADIUS:
- principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
- break;
- case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK:
- principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
- break;
- }
- node = principled;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
- node = graph->create_node<TranslucentBsdfNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
- node = graph->create_node<TransparentBsdfNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
- node = graph->create_node<VelvetBsdfNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeEmission)) {
- node = graph->create_node<EmissionNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
- BL::ShaderNodeAmbientOcclusion b_ao_node(b_node);
- AmbientOcclusionNode *ao = graph->create_node<AmbientOcclusionNode>();
- ao->set_samples(b_ao_node.samples());
- ao->set_inside(b_ao_node.inside());
- ao->set_only_local(b_ao_node.only_local());
- node = ao;
- }
- else if (b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
- node = graph->create_node<ScatterVolumeNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
- node = graph->create_node<AbsorptionVolumeNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeVolumePrincipled)) {
- PrincipledVolumeNode *principled = graph->create_node<PrincipledVolumeNode>();
- node = principled;
- }
- else if (b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
- node = graph->create_node<GeometryNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeWireframe)) {
- BL::ShaderNodeWireframe b_wireframe_node(b_node);
- WireframeNode *wire = graph->create_node<WireframeNode>();
- wire->set_use_pixel_size(b_wireframe_node.use_pixel_size());
- node = wire;
- }
- else if (b_node.is_a(&RNA_ShaderNodeWavelength)) {
- node = graph->create_node<WavelengthNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeBlackbody)) {
- node = graph->create_node<BlackbodyNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeLightPath)) {
- node = graph->create_node<LightPathNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
- node = graph->create_node<LightFalloffNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
- node = graph->create_node<ObjectInfoNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
- node = graph->create_node<ParticleInfoNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeHairInfo)) {
- node = graph->create_node<HairInfoNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeVolumeInfo)) {
- node = graph->create_node<VolumeInfoNode>();
- }
- else if (b_node.is_a(&RNA_ShaderNodeVertexColor)) {
- BL::ShaderNodeVertexColor b_vertex_color_node(b_node);
- VertexColorNode *vertex_color_node = graph->create_node<VertexColorNode>();
- vertex_color_node->set_layer_name(ustring(b_vertex_color_node.layer_name()));
- node = vertex_color_node;
- }
- else if (b_node.is_a(&RNA_ShaderNodeBump)) {
- BL::ShaderNodeBump b_bump_node(b_node);
- BumpNode *bump = graph->create_node<BumpNode>();
- bump->set_invert(b_bump_node.invert());
- node = bump;
- }
- else if (b_node.is_a(&RNA_ShaderNodeScript)) {
-#ifdef WITH_OSL
- if (scene->shader_manager->use_osl()) {
- /* create script node */
- BL::ShaderNodeScript b_script_node(b_node);
-
- ShaderManager *manager = scene->shader_manager;
- string bytecode_hash = b_script_node.bytecode_hash();
-
- if (!bytecode_hash.empty()) {
- node = OSLShaderManager::osl_node(
- graph, manager, "", bytecode_hash, b_script_node.bytecode());
- }
- else {
- string absolute_filepath = blender_absolute_path(
- b_data, b_ntree, b_script_node.filepath());
- node = OSLShaderManager::osl_node(graph, manager, absolute_filepath, "");
- }
- }
-#else
- (void)b_data;
- (void)b_ntree;
-#endif
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexImage)) {
- BL::ShaderNodeTexImage b_image_node(b_node);
- BL::Image b_image(b_image_node.image());
- BL::ImageUser b_image_user(b_image_node.image_user());
- ImageTextureNode *image = graph->create_node<ImageTextureNode>();
-
- image->set_interpolation(get_image_interpolation(b_image_node));
- image->set_extension(get_image_extension(b_image_node));
- image->set_projection((NodeImageProjection)b_image_node.projection());
- image->set_projection_blend(b_image_node.projection_blend());
- BL::TexMapping b_texture_mapping(b_image_node.texture_mapping());
- get_tex_mapping(image, b_texture_mapping);
-
- if (b_image) {
- PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
- image->set_colorspace(ustring(get_enum_identifier(colorspace_ptr, "name")));
-
- image->set_animated(b_image_node.image_user().use_auto_refresh());
- image->set_alpha_type(get_image_alpha_type(b_image));
-
- array<int> tiles;
- for (BL::UDIMTile &b_tile : b_image.tiles) {
- tiles.push_back_slow(b_tile.number());
- }
- image->set_tiles(tiles);
-
- /* builtin images will use callback-based reading because
- * they could only be loaded correct from blender side
- */
- bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED ||
- b_image.source() == BL::Image::source_MOVIE ||
- (b_engine.is_preview() && b_image.source() != BL::Image::source_SEQUENCE);
-
- if (is_builtin) {
- /* for builtin images we're using image datablock name to find an image to
- * read pixels from later
- *
- * also store frame number as well, so there's no differences in handling
- * builtin names for packed images and movies
- */
- int scene_frame = b_scene.frame_current();
- int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
- image->handle = scene->image_manager->add_image(
- new BlenderImageLoader(b_image, image_frame), image->image_params());
- }
- else {
- ustring filename = ustring(
- image_user_file_path(b_image_user, b_image, b_scene.frame_current(), true));
- image->set_filename(filename);
- }
- }
- node = image;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexEnvironment)) {
- BL::ShaderNodeTexEnvironment b_env_node(b_node);
- BL::Image b_image(b_env_node.image());
- BL::ImageUser b_image_user(b_env_node.image_user());
- EnvironmentTextureNode *env = graph->create_node<EnvironmentTextureNode>();
-
- env->set_interpolation(get_image_interpolation(b_env_node));
- env->set_projection((NodeEnvironmentProjection)b_env_node.projection());
- BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
- get_tex_mapping(env, b_texture_mapping);
-
- if (b_image) {
- PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
- env->set_colorspace(ustring(get_enum_identifier(colorspace_ptr, "name")));
-
- env->set_animated(b_env_node.image_user().use_auto_refresh());
- env->set_alpha_type(get_image_alpha_type(b_image));
-
- bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED ||
- b_image.source() == BL::Image::source_MOVIE ||
- (b_engine.is_preview() && b_image.source() != BL::Image::source_SEQUENCE);
-
- if (is_builtin) {
- int scene_frame = b_scene.frame_current();
- int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
- env->handle = scene->image_manager->add_image(new BlenderImageLoader(b_image, image_frame),
- env->image_params());
- }
- else {
- env->set_filename(
- ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current(), false)));
- }
- }
- node = env;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexGradient)) {
- BL::ShaderNodeTexGradient b_gradient_node(b_node);
- GradientTextureNode *gradient = graph->create_node<GradientTextureNode>();
- gradient->set_gradient_type((NodeGradientType)b_gradient_node.gradient_type());
- BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping());
- get_tex_mapping(gradient, b_texture_mapping);
- node = gradient;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
- BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
- VoronoiTextureNode *voronoi = graph->create_node<VoronoiTextureNode>();
- voronoi->set_dimensions(b_voronoi_node.voronoi_dimensions());
- voronoi->set_feature((NodeVoronoiFeature)b_voronoi_node.feature());
- voronoi->set_metric((NodeVoronoiDistanceMetric)b_voronoi_node.distance());
- BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
- get_tex_mapping(voronoi, b_texture_mapping);
- node = voronoi;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexMagic)) {
- BL::ShaderNodeTexMagic b_magic_node(b_node);
- MagicTextureNode *magic = graph->create_node<MagicTextureNode>();
- magic->set_depth(b_magic_node.turbulence_depth());
- BL::TexMapping b_texture_mapping(b_magic_node.texture_mapping());
- get_tex_mapping(magic, b_texture_mapping);
- node = magic;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexWave)) {
- BL::ShaderNodeTexWave b_wave_node(b_node);
- WaveTextureNode *wave = graph->create_node<WaveTextureNode>();
- wave->set_wave_type((NodeWaveType)b_wave_node.wave_type());
- wave->set_bands_direction((NodeWaveBandsDirection)b_wave_node.bands_direction());
- wave->set_rings_direction((NodeWaveRingsDirection)b_wave_node.rings_direction());
- wave->set_profile((NodeWaveProfile)b_wave_node.wave_profile());
- BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping());
- get_tex_mapping(wave, b_texture_mapping);
- node = wave;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexChecker)) {
- BL::ShaderNodeTexChecker b_checker_node(b_node);
- CheckerTextureNode *checker = graph->create_node<CheckerTextureNode>();
- BL::TexMapping b_texture_mapping(b_checker_node.texture_mapping());
- get_tex_mapping(checker, b_texture_mapping);
- node = checker;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexBrick)) {
- BL::ShaderNodeTexBrick b_brick_node(b_node);
- BrickTextureNode *brick = graph->create_node<BrickTextureNode>();
- brick->set_offset(b_brick_node.offset());
- brick->set_offset_frequency(b_brick_node.offset_frequency());
- brick->set_squash(b_brick_node.squash());
- brick->set_squash_frequency(b_brick_node.squash_frequency());
- BL::TexMapping b_texture_mapping(b_brick_node.texture_mapping());
- get_tex_mapping(brick, b_texture_mapping);
- node = brick;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) {
- BL::ShaderNodeTexNoise b_noise_node(b_node);
- NoiseTextureNode *noise = graph->create_node<NoiseTextureNode>();
- noise->set_dimensions(b_noise_node.noise_dimensions());
- BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping());
- get_tex_mapping(noise, b_texture_mapping);
- node = noise;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
- BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
- MusgraveTextureNode *musgrave_node = graph->create_node<MusgraveTextureNode>();
- musgrave_node->set_musgrave_type((NodeMusgraveType)b_musgrave_node.musgrave_type());
- musgrave_node->set_dimensions(b_musgrave_node.musgrave_dimensions());
- BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
- get_tex_mapping(musgrave_node, b_texture_mapping);
- node = musgrave_node;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexCoord)) {
- BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
- TextureCoordinateNode *tex_coord = graph->create_node<TextureCoordinateNode>();
- tex_coord->set_from_dupli(b_tex_coord_node.from_instancer());
- if (b_tex_coord_node.object()) {
- tex_coord->set_use_transform(true);
- tex_coord->set_ob_tfm(get_transform(b_tex_coord_node.object().matrix_world()));
- }
- node = tex_coord;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexSky)) {
- BL::ShaderNodeTexSky b_sky_node(b_node);
- SkyTextureNode *sky = graph->create_node<SkyTextureNode>();
- sky->set_sky_type((NodeSkyType)b_sky_node.sky_type());
- sky->set_sun_direction(normalize(get_float3(b_sky_node.sun_direction())));
- sky->set_turbidity(b_sky_node.turbidity());
- sky->set_ground_albedo(b_sky_node.ground_albedo());
- sky->set_sun_disc(b_sky_node.sun_disc());
- sky->set_sun_size(b_sky_node.sun_size());
- sky->set_sun_intensity(b_sky_node.sun_intensity());
- sky->set_sun_elevation(b_sky_node.sun_elevation());
- sky->set_sun_rotation(b_sky_node.sun_rotation());
- sky->set_altitude(b_sky_node.altitude());
- sky->set_air_density(b_sky_node.air_density());
- sky->set_dust_density(b_sky_node.dust_density());
- sky->set_ozone_density(b_sky_node.ozone_density());
- BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping());
- get_tex_mapping(sky, b_texture_mapping);
- node = sky;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexIES)) {
- BL::ShaderNodeTexIES b_ies_node(b_node);
- IESLightNode *ies = graph->create_node<IESLightNode>();
- switch (b_ies_node.mode()) {
- case BL::ShaderNodeTexIES::mode_EXTERNAL:
- ies->set_filename(ustring(blender_absolute_path(b_data, b_ntree, b_ies_node.filepath())));
- break;
- case BL::ShaderNodeTexIES::mode_INTERNAL:
- ustring ies_content = ustring(get_text_datablock_content(b_ies_node.ies().ptr));
- if (ies_content.empty()) {
- ies_content = "\n";
- }
- ies->set_ies(ies_content);
- break;
- }
- node = ies;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexWhiteNoise)) {
- BL::ShaderNodeTexWhiteNoise b_tex_white_noise_node(b_node);
- WhiteNoiseTextureNode *white_noise_node = graph->create_node<WhiteNoiseTextureNode>();
- white_noise_node->set_dimensions(b_tex_white_noise_node.noise_dimensions());
- node = white_noise_node;
- }
- else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) {
- BL::ShaderNodeNormalMap b_normal_map_node(b_node);
- NormalMapNode *nmap = graph->create_node<NormalMapNode>();
- nmap->set_space((NodeNormalMapSpace)b_normal_map_node.space());
- nmap->set_attribute(ustring(b_normal_map_node.uv_map()));
- node = nmap;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTangent)) {
- BL::ShaderNodeTangent b_tangent_node(b_node);
- TangentNode *tangent = graph->create_node<TangentNode>();
- tangent->set_direction_type((NodeTangentDirectionType)b_tangent_node.direction_type());
- tangent->set_axis((NodeTangentAxis)b_tangent_node.axis());
- tangent->set_attribute(ustring(b_tangent_node.uv_map()));
- node = tangent;
- }
- else if (b_node.is_a(&RNA_ShaderNodeUVMap)) {
- BL::ShaderNodeUVMap b_uvmap_node(b_node);
- UVMapNode *uvm = graph->create_node<UVMapNode>();
- uvm->set_attribute(ustring(b_uvmap_node.uv_map()));
- uvm->set_from_dupli(b_uvmap_node.from_instancer());
- node = uvm;
- }
- else if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
- BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
- PointDensityTextureNode *point_density = graph->create_node<PointDensityTextureNode>();
- point_density->set_space((NodeTexVoxelSpace)b_point_density_node.space());
- point_density->set_interpolation(get_image_interpolation(b_point_density_node));
- point_density->handle = scene->image_manager->add_image(
- new BlenderPointDensityLoader(b_depsgraph, b_point_density_node),
- point_density->image_params());
-
- b_point_density_node.cache_point_density(b_depsgraph);
- node = point_density;
-
- /* Transformation form world space to texture space.
- *
- * NOTE: Do this after the texture is cached, this is because getting
- * min/max will need to access this cache.
- */
- BL::Object b_ob(b_point_density_node.object());
- if (b_ob) {
- float3 loc, size;
- point_density_texture_space(b_depsgraph, b_point_density_node, loc, size);
- point_density->set_tfm(transform_translate(-loc) * transform_scale(size) *
- transform_inverse(get_transform(b_ob.matrix_world())));
- }
- }
- else if (b_node.is_a(&RNA_ShaderNodeBevel)) {
- BL::ShaderNodeBevel b_bevel_node(b_node);
- BevelNode *bevel = graph->create_node<BevelNode>();
- bevel->set_samples(b_bevel_node.samples());
- node = bevel;
- }
- else if (b_node.is_a(&RNA_ShaderNodeDisplacement)) {
- BL::ShaderNodeDisplacement b_disp_node(b_node);
- DisplacementNode *disp = graph->create_node<DisplacementNode>();
- disp->set_space((NodeNormalMapSpace)b_disp_node.space());
- node = disp;
- }
- else if (b_node.is_a(&RNA_ShaderNodeVectorDisplacement)) {
- BL::ShaderNodeVectorDisplacement b_disp_node(b_node);
- VectorDisplacementNode *disp = graph->create_node<VectorDisplacementNode>();
- disp->set_space((NodeNormalMapSpace)b_disp_node.space());
- disp->set_attribute(ustring(""));
- node = disp;
- }
- else if (b_node.is_a(&RNA_ShaderNodeOutputAOV)) {
- BL::ShaderNodeOutputAOV b_aov_node(b_node);
- OutputAOVNode *aov = graph->create_node<OutputAOVNode>();
- aov->set_name(ustring(b_aov_node.name()));
- node = aov;
- }
-
- if (node) {
- node->name = b_node.name();
- graph->add(node);
- }
-
- return node;
-}
-
-static bool node_use_modified_socket_name(ShaderNode *node)
-{
- if (node->special_type == SHADER_SPECIAL_TYPE_OSL)
- return false;
-
- return true;
-}
-
-static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_socket)
-{
- string name = b_socket.identifier();
- ShaderInput *input = node->input(name.c_str());
-
- if (!input && node_use_modified_socket_name(node)) {
- /* Different internal name for shader. */
- if (string_startswith(name, "Shader")) {
- string_replace(name, "Shader", "Closure");
- }
- input = node->input(name.c_str());
-
- if (!input) {
- /* Different internal numbering of two sockets with same name.
- * Note that the Blender convention for unique socket names changed
- * from . to _ at some point, so we check both to handle old files. */
- if (string_endswith(name, "_001")) {
- string_replace(name, "_001", "2");
- }
- else if (string_endswith(name, ".001")) {
- string_replace(name, ".001", "2");
- }
- else if (string_endswith(name, "_002")) {
- string_replace(name, "_002", "3");
- }
- else if (string_endswith(name, ".002")) {
- string_replace(name, ".002", "3");
- }
- else {
- name += "1";
- }
-
- input = node->input(name.c_str());
- }
- }
-
- return input;
-}
-
-static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::NodeSocket &b_socket)
-{
- string name = b_socket.identifier();
- ShaderOutput *output = node->output(name.c_str());
-
- if (!output && node_use_modified_socket_name(node)) {
- /* Different internal name for shader. */
- if (name == "Shader") {
- name = "Closure";
- output = node->output(name.c_str());
- }
- }
-
- return output;
-}
-
-static void add_nodes(Scene *scene,
- BL::RenderEngine &b_engine,
- BL::BlendData &b_data,
- BL::Depsgraph &b_depsgraph,
- BL::Scene &b_scene,
- ShaderGraph *graph,
- BL::ShaderNodeTree &b_ntree,
- const ProxyMap &proxy_input_map,
- const ProxyMap &proxy_output_map)
-{
- /* add nodes */
- PtrInputMap input_map;
- PtrOutputMap output_map;
-
- /* find the node to use for output if there are multiple */
- BL::ShaderNode output_node = b_ntree.get_output_node(
- BL::ShaderNodeOutputMaterial::target_CYCLES);
-
- /* add nodes */
- for (BL::Node &b_node : b_ntree.nodes) {
- if (b_node.mute() || b_node.is_a(&RNA_NodeReroute)) {
- /* replace muted node with internal links */
- for (BL::NodeLink &b_link : b_node.internal_links) {
- BL::NodeSocket to_socket(b_link.to_socket());
- SocketType::Type to_socket_type = convert_socket_type(to_socket);
- if (to_socket_type == SocketType::UNDEFINED) {
- continue;
- }
-
- ConvertNode *proxy = graph->create_node<ConvertNode>(to_socket_type, to_socket_type, true);
-
- input_map[b_link.from_socket().ptr.data] = proxy->inputs[0];
- output_map[b_link.to_socket().ptr.data] = proxy->outputs[0];
-
- graph->add(proxy);
- }
- }
- else if (b_node.is_a(&RNA_ShaderNodeGroup) || b_node.is_a(&RNA_NodeCustomGroup) ||
- b_node.is_a(&RNA_ShaderNodeCustomGroup)) {
-
- BL::ShaderNodeTree b_group_ntree(PointerRNA_NULL);
- if (b_node.is_a(&RNA_ShaderNodeGroup))
- b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(b_node)).node_tree());
- else if (b_node.is_a(&RNA_NodeCustomGroup))
- b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(b_node)).node_tree());
- else
- b_group_ntree = BL::ShaderNodeTree(((BL::ShaderNodeCustomGroup)(b_node)).node_tree());
-
- ProxyMap group_proxy_input_map, group_proxy_output_map;
-
- /* Add a proxy node for each socket
- * Do this even if the node group has no internal tree,
- * so that links have something to connect to and assert won't fail.
- */
- for (BL::NodeSocket &b_input : b_node.inputs) {
- SocketType::Type input_type = convert_socket_type(b_input);
- if (input_type == SocketType::UNDEFINED) {
- continue;
- }
-
- ConvertNode *proxy = graph->create_node<ConvertNode>(input_type, input_type, true);
- graph->add(proxy);
-
- /* register the proxy node for internal binding */
- group_proxy_input_map[b_input.identifier()] = proxy;
-
- input_map[b_input.ptr.data] = proxy->inputs[0];
-
- set_default_value(proxy->inputs[0], b_input, b_data, b_ntree);
- }
- for (BL::NodeSocket &b_output : b_node.outputs) {
- SocketType::Type output_type = convert_socket_type(b_output);
- if (output_type == SocketType::UNDEFINED) {
- continue;
- }
-
- ConvertNode *proxy = graph->create_node<ConvertNode>(output_type, output_type, true);
- graph->add(proxy);
-
- /* register the proxy node for internal binding */
- group_proxy_output_map[b_output.identifier()] = proxy;
-
- output_map[b_output.ptr.data] = proxy->outputs[0];
- }
-
- if (b_group_ntree) {
- add_nodes(scene,
- b_engine,
- b_data,
- b_depsgraph,
- b_scene,
- graph,
- b_group_ntree,
- group_proxy_input_map,
- group_proxy_output_map);
- }
- }
- else if (b_node.is_a(&RNA_NodeGroupInput)) {
- /* map each socket to a proxy node */
- for (BL::NodeSocket &b_output : b_node.outputs) {
- ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output.identifier());
- if (proxy_it != proxy_input_map.end()) {
- ConvertNode *proxy = proxy_it->second;
-
- output_map[b_output.ptr.data] = proxy->outputs[0];
- }
- }
- }
- else if (b_node.is_a(&RNA_NodeGroupOutput)) {
- BL::NodeGroupOutput b_output_node(b_node);
- /* only the active group output is used */
- if (b_output_node.is_active_output()) {
- /* map each socket to a proxy node */
- for (BL::NodeSocket &b_input : b_node.inputs) {
- ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input.identifier());
- if (proxy_it != proxy_output_map.end()) {
- ConvertNode *proxy = proxy_it->second;
-
- input_map[b_input.ptr.data] = proxy->inputs[0];
-
- set_default_value(proxy->inputs[0], b_input, b_data, b_ntree);
- }
- }
- }
- }
- else {
- ShaderNode *node = NULL;
-
- if (b_node.ptr.data == output_node.ptr.data) {
- node = graph->output();
- }
- else {
- BL::ShaderNode b_shader_node(b_node);
- node = add_node(
- scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree, b_shader_node);
- }
-
- if (node) {
- /* map node sockets for linking */
- for (BL::NodeSocket &b_input : b_node.inputs) {
- ShaderInput *input = node_find_input_by_name(node, b_input);
- if (!input) {
- /* XXX should not happen, report error? */
- continue;
- }
- input_map[b_input.ptr.data] = input;
-
- set_default_value(input, b_input, b_data, b_ntree);
- }
- for (BL::NodeSocket &b_output : b_node.outputs) {
- ShaderOutput *output = node_find_output_by_name(node, b_output);
- if (!output) {
- /* XXX should not happen, report error? */
- continue;
- }
- output_map[b_output.ptr.data] = output;
- }
- }
- }
- }
-
- /* connect nodes */
- for (BL::NodeLink &b_link : b_ntree.links) {
- /* Ignore invalid links to avoid unwanted cycles created in graph.
- * Also ignore links with unavailable sockets. */
- if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled()) ||
- b_link.is_muted()) {
- continue;
- }
- /* get blender link data */
- BL::NodeSocket b_from_sock = b_link.from_socket();
- BL::NodeSocket b_to_sock = b_link.to_socket();
-
- ShaderOutput *output = 0;
- ShaderInput *input = 0;
-
- PtrOutputMap::iterator output_it = output_map.find(b_from_sock.ptr.data);
- if (output_it != output_map.end())
- output = output_it->second;
- PtrInputMap::iterator input_it = input_map.find(b_to_sock.ptr.data);
- if (input_it != input_map.end())
- input = input_it->second;
-
- /* either node may be NULL when the node was not exported, typically
- * because the node type is not supported */
- if (output && input)
- graph->connect(output, input);
- }
-}
-
-static void add_nodes(Scene *scene,
- BL::RenderEngine &b_engine,
- BL::BlendData &b_data,
- BL::Depsgraph &b_depsgraph,
- BL::Scene &b_scene,
- ShaderGraph *graph,
- BL::ShaderNodeTree &b_ntree)
-{
- static const ProxyMap empty_proxy_map;
- add_nodes(scene,
- b_engine,
- b_data,
- b_depsgraph,
- b_scene,
- graph,
- b_ntree,
- empty_proxy_map,
- empty_proxy_map);
-}
-
-/* Sync Materials */
-
-void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
-{
- shader_map.set_default(scene->default_surface);
-
- TaskPool pool;
- set<Shader *> updated_shaders;
-
- for (BL::ID &b_id : b_depsgraph.ids) {
- if (!b_id.is_a(&RNA_Material)) {
- continue;
- }
-
- BL::Material b_mat(b_id);
- Shader *shader;
-
- /* test if we need to sync */
- if (shader_map.add_or_update(&shader, b_mat) || update_all) {
- ShaderGraph *graph = new ShaderGraph();
-
- shader->name = b_mat.name().c_str();
- shader->set_pass_id(b_mat.pass_index());
-
- /* create nodes */
- if (b_mat.use_nodes() && b_mat.node_tree()) {
- BL::ShaderNodeTree b_ntree(b_mat.node_tree());
-
- add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
- }
- else {
- DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
- diffuse->set_color(get_float3(b_mat.diffuse_color()));
- graph->add(diffuse);
-
- ShaderNode *out = graph->output();
- graph->connect(diffuse->output("BSDF"), out->input("Surface"));
- }
-
- /* settings */
- PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles");
- shader->set_use_mis(get_boolean(cmat, "sample_as_light"));
- shader->set_use_transparent_shadow(get_boolean(cmat, "use_transparent_shadow"));
- shader->set_heterogeneous_volume(!get_boolean(cmat, "homogeneous_volume"));
- shader->set_volume_sampling_method(get_volume_sampling(cmat));
- shader->set_volume_interpolation_method(get_volume_interpolation(cmat));
- shader->set_volume_step_rate(get_float(cmat, "volume_step_rate"));
- shader->set_displacement_method(get_displacement_method(cmat));
-
- shader->set_graph(graph);
-
- /* By simplifying the shader graph as soon as possible, some
- * redundant shader nodes might be removed which prevents loading
- * unnecessary attributes later.
- *
- * However, since graph simplification also accounts for e.g. mix
- * weight, this would cause frequent expensive resyncs in interactive
- * sessions, so for those sessions optimization is only performed
- * right before compiling.
- */
- if (!preview) {
- pool.push(function_bind(&ShaderGraph::simplify, graph, scene));
- /* NOTE: Update shaders out of the threads since those routines
- * are accessing and writing to a global context.
- */
- updated_shaders.insert(shader);
- }
- else {
- /* NOTE: Update tagging can access links which are being
- * optimized out.
- */
- shader->tag_update(scene);
- }
- }
- }
-
- pool.wait_work();
-
- foreach (Shader *shader, updated_shaders) {
- shader->tag_update(scene);
- }
-}
-
-/* Sync World */
-
-void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all)
-{
- Background *background = scene->background;
- Integrator *integrator = scene->integrator;
-
- BL::World b_world = b_scene.world();
-
- BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
-
- if (world_recalc || update_all || b_world.ptr.data != world_map ||
- viewport_parameters.shader_modified(new_viewport_parameters)) {
- Shader *shader = scene->default_background;
- ShaderGraph *graph = new ShaderGraph();
-
- /* create nodes */
- if (new_viewport_parameters.use_scene_world && b_world && b_world.use_nodes() &&
- b_world.node_tree()) {
- BL::ShaderNodeTree b_ntree(b_world.node_tree());
-
- add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
-
- /* volume */
- PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
- shader->set_heterogeneous_volume(!get_boolean(cworld, "homogeneous_volume"));
- shader->set_volume_sampling_method(get_volume_sampling(cworld));
- shader->set_volume_interpolation_method(get_volume_interpolation(cworld));
- shader->set_volume_step_rate(get_float(cworld, "volume_step_size"));
- }
- else if (new_viewport_parameters.use_scene_world && b_world) {
- BackgroundNode *background = graph->create_node<BackgroundNode>();
- background->set_color(get_float3(b_world.color()));
- graph->add(background);
-
- ShaderNode *out = graph->output();
- graph->connect(background->output("Background"), out->input("Surface"));
- }
- else if (!new_viewport_parameters.use_scene_world) {
- float3 world_color;
- if (b_world) {
- world_color = get_float3(b_world.color());
- }
- else {
- world_color = zero_float3();
- }
-
- BackgroundNode *background = graph->create_node<BackgroundNode>();
- graph->add(background);
-
- LightPathNode *light_path = graph->create_node<LightPathNode>();
- graph->add(light_path);
-
- MixNode *mix_scene_with_background = graph->create_node<MixNode>();
- mix_scene_with_background->set_color2(world_color);
- graph->add(mix_scene_with_background);
-
- EnvironmentTextureNode *texture_environment = graph->create_node<EnvironmentTextureNode>();
- texture_environment->set_tex_mapping_type(TextureMapping::VECTOR);
- float3 rotation_z = texture_environment->get_tex_mapping_rotation();
- rotation_z[2] = new_viewport_parameters.studiolight_rotate_z;
- texture_environment->set_tex_mapping_rotation(rotation_z);
- texture_environment->set_filename(new_viewport_parameters.studiolight_path);
- graph->add(texture_environment);
-
- MixNode *mix_intensity = graph->create_node<MixNode>();
- mix_intensity->set_mix_type(NODE_MIX_MUL);
- mix_intensity->set_fac(1.0f);
- mix_intensity->set_color2(make_float3(new_viewport_parameters.studiolight_intensity,
- new_viewport_parameters.studiolight_intensity,
- new_viewport_parameters.studiolight_intensity));
- graph->add(mix_intensity);
-
- TextureCoordinateNode *texture_coordinate = graph->create_node<TextureCoordinateNode>();
- graph->add(texture_coordinate);
-
- MixNode *mix_background_with_environment = graph->create_node<MixNode>();
- mix_background_with_environment->set_fac(
- new_viewport_parameters.studiolight_background_alpha);
- mix_background_with_environment->set_color1(world_color);
- graph->add(mix_background_with_environment);
-
- ShaderNode *out = graph->output();
-
- graph->connect(texture_coordinate->output("Generated"),
- texture_environment->input("Vector"));
- graph->connect(texture_environment->output("Color"), mix_intensity->input("Color1"));
- graph->connect(light_path->output("Is Camera Ray"), mix_scene_with_background->input("Fac"));
- graph->connect(mix_intensity->output("Color"), mix_scene_with_background->input("Color1"));
- graph->connect(mix_intensity->output("Color"),
- mix_background_with_environment->input("Color2"));
- graph->connect(mix_background_with_environment->output("Color"),
- mix_scene_with_background->input("Color2"));
- graph->connect(mix_scene_with_background->output("Color"), background->input("Color"));
- graph->connect(background->output("Background"), out->input("Surface"));
- }
-
- if (b_world) {
- /* AO */
- BL::WorldLighting b_light = b_world.light_settings();
-
- integrator->set_ao_factor(b_light.ao_factor());
- integrator->set_ao_distance(b_light.distance());
-
- /* visibility */
- PointerRNA cvisibility = RNA_pointer_get(&b_world.ptr, "cycles_visibility");
- uint visibility = 0;
-
- visibility |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0;
- visibility |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0;
- visibility |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0;
- visibility |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0;
- visibility |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0;
-
- background->set_visibility(visibility);
- }
- else {
- integrator->set_ao_factor(1.0f);
- integrator->set_ao_distance(10.0f);
- }
-
- shader->set_graph(graph);
- shader->tag_update(scene);
- }
-
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- background->set_transparent(b_scene.render().film_transparent());
-
- if (background->get_transparent()) {
- background->set_transparent_glass(get_boolean(cscene, "film_transparent_glass"));
- background->set_transparent_roughness_threshold(
- get_float(cscene, "film_transparent_roughness"));
- }
- else {
- background->set_transparent_glass(false);
- background->set_transparent_roughness_threshold(0.0f);
- }
-
- background->set_use_shader(view_layer.use_background_shader ||
- viewport_parameters.use_custom_shader());
-
- background->tag_update(scene);
-}
-
-/* Sync Lights */
-
-void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
-{
- shader_map.set_default(scene->default_light);
-
- for (BL::ID &b_id : b_depsgraph.ids) {
- if (!b_id.is_a(&RNA_Light)) {
- continue;
- }
-
- BL::Light b_light(b_id);
- Shader *shader;
-
- /* test if we need to sync */
- if (shader_map.add_or_update(&shader, b_light) || update_all) {
- ShaderGraph *graph = new ShaderGraph();
-
- /* create nodes */
- if (b_light.use_nodes() && b_light.node_tree()) {
- shader->name = b_light.name().c_str();
-
- BL::ShaderNodeTree b_ntree(b_light.node_tree());
-
- add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
- }
- else {
- EmissionNode *emission = graph->create_node<EmissionNode>();
- emission->set_color(one_float3());
- emission->set_strength(1.0f);
- graph->add(emission);
-
- ShaderNode *out = graph->output();
- graph->connect(emission->output("Emission"), out->input("Surface"));
- }
-
- shader->set_graph(graph);
- shader->tag_update(scene);
- }
- }
-}
-
-void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
-{
- /* for auto refresh images */
- ImageManager *image_manager = scene->image_manager;
- const int frame = b_scene.frame_current();
- const bool auto_refresh_update = image_manager->set_animation_frame_update(frame);
-
- shader_map.pre_sync();
-
- sync_world(b_depsgraph, b_v3d, auto_refresh_update);
- sync_lights(b_depsgraph, auto_refresh_update);
- sync_materials(b_depsgraph, auto_refresh_update);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
deleted file mode 100644
index 9f5bbddbe77..00000000000
--- a/intern/cycles/blender/blender_sync.cpp
+++ /dev/null
@@ -1,945 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/background.h"
-#include "render/camera.h"
-#include "render/curves.h"
-#include "render/film.h"
-#include "render/graph.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/nodes.h"
-#include "render/object.h"
-#include "render/procedural.h"
-#include "render/scene.h"
-#include "render/shader.h"
-
-#include "device/device.h"
-
-#include "blender/blender_device.h"
-#include "blender/blender_session.h"
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-#include "util/util_debug.h"
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-#include "util/util_logging.h"
-#include "util/util_opengl.h"
-#include "util/util_openimagedenoise.h"
-
-CCL_NAMESPACE_BEGIN
-
-static const char *cryptomatte_prefix = "Crypto";
-
-/* Constructor */
-
-BlenderSync::BlenderSync(BL::RenderEngine &b_engine,
- BL::BlendData &b_data,
- BL::Scene &b_scene,
- Scene *scene,
- bool preview,
- bool use_developer_ui,
- Progress &progress)
- : b_engine(b_engine),
- b_data(b_data),
- b_scene(b_scene),
- shader_map(scene),
- object_map(scene),
- procedural_map(scene),
- geometry_map(scene),
- light_map(scene),
- particle_system_map(scene),
- world_map(NULL),
- world_recalc(false),
- scene(scene),
- preview(preview),
- experimental(false),
- use_developer_ui(use_developer_ui),
- dicing_rate(1.0f),
- max_subdivisions(12),
- progress(progress),
- has_updates_(true)
-{
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate") :
- RNA_float_get(&cscene, "dicing_rate");
- max_subdivisions = RNA_int_get(&cscene, "max_subdivisions");
-}
-
-BlenderSync::~BlenderSync()
-{
-}
-
-void BlenderSync::reset(BL::BlendData &b_data, BL::Scene &b_scene)
-{
- /* Update data and scene pointers in case they change in session reset,
- * for example after undo.
- * Note that we do not modify the `has_updates_` flag here because the sync
- * reset is also used during viewport navigation. */
- this->b_data = b_data;
- this->b_scene = b_scene;
-}
-
-/* Sync */
-
-void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
-{
- /* Sync recalc flags from blender to cycles. Actual update is done separate,
- * so we can do it later on if doing it immediate is not suitable. */
-
- if (experimental) {
- /* Mark all meshes as needing to be exported again if dicing changed. */
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- bool dicing_prop_changed = false;
-
- float updated_dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate") :
- RNA_float_get(&cscene, "dicing_rate");
-
- if (dicing_rate != updated_dicing_rate) {
- dicing_rate = updated_dicing_rate;
- dicing_prop_changed = true;
- }
-
- int updated_max_subdivisions = RNA_int_get(&cscene, "max_subdivisions");
-
- if (max_subdivisions != updated_max_subdivisions) {
- max_subdivisions = updated_max_subdivisions;
- dicing_prop_changed = true;
- }
-
- if (dicing_prop_changed) {
- has_updates_ = true;
-
- for (const pair<const GeometryKey, Geometry *> &iter : geometry_map.key_to_scene_data()) {
- Geometry *geom = iter.second;
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
- PointerRNA id_ptr;
- RNA_id_pointer_create((::ID *)iter.first.id, &id_ptr);
- geometry_map.set_recalc(BL::ID(id_ptr));
- }
- }
- }
- }
- }
-
- /* Iterate over all IDs in this depsgraph. */
- for (BL::DepsgraphUpdate &b_update : b_depsgraph.updates) {
- /* TODO(sergey): Can do more selective filter here. For example, ignore changes made to
- * screen datablock. Note that sync_data() needs to be called after object deletion, and
- * currently this is ensured by the scene ID tagged for update, which sets the `has_updates_`
- * flag. */
- has_updates_ = true;
-
- BL::ID b_id(b_update.id());
-
- /* Material */
- if (b_id.is_a(&RNA_Material)) {
- BL::Material b_mat(b_id);
- shader_map.set_recalc(b_mat);
- }
- /* Light */
- else if (b_id.is_a(&RNA_Light)) {
- BL::Light b_light(b_id);
- shader_map.set_recalc(b_light);
- }
- /* Object */
- else if (b_id.is_a(&RNA_Object)) {
- BL::Object b_ob(b_id);
- const bool is_geometry = object_is_geometry(b_ob);
- const bool is_light = !is_geometry && object_is_light(b_ob);
-
- if (b_ob.is_instancer() && b_update.is_updated_shading()) {
- /* Needed for e.g. object color updates on instancer. */
- object_map.set_recalc(b_ob);
- }
-
- if (is_geometry || is_light) {
- const bool updated_geometry = b_update.is_updated_geometry();
-
- /* Geometry (mesh, hair, volume). */
- if (is_geometry) {
- if (b_update.is_updated_transform() || b_update.is_updated_shading()) {
- object_map.set_recalc(b_ob);
- }
-
- if (updated_geometry ||
- (object_subdivision_type(b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE)) {
- BL::ID key = BKE_object_is_modified(b_ob) ? b_ob : b_ob.data();
- geometry_map.set_recalc(key);
- }
-
- if (updated_geometry) {
- BL::Object::particle_systems_iterator b_psys;
- for (b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end();
- ++b_psys) {
- particle_system_map.set_recalc(b_ob);
- }
- }
- }
- /* Light */
- else if (is_light) {
- if (b_update.is_updated_transform() || b_update.is_updated_shading()) {
- object_map.set_recalc(b_ob);
- light_map.set_recalc(b_ob);
- }
-
- if (updated_geometry) {
- light_map.set_recalc(b_ob);
- }
- }
- }
- }
- /* Mesh */
- else if (b_id.is_a(&RNA_Mesh)) {
- BL::Mesh b_mesh(b_id);
- geometry_map.set_recalc(b_mesh);
- }
- /* World */
- else if (b_id.is_a(&RNA_World)) {
- BL::World b_world(b_id);
- if (world_map == b_world.ptr.data) {
- world_recalc = true;
- }
- }
- /* Volume */
- else if (b_id.is_a(&RNA_Volume)) {
- BL::Volume b_volume(b_id);
- geometry_map.set_recalc(b_volume);
- }
- }
-
- if (b_v3d) {
- BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
-
- if (viewport_parameters.shader_modified(new_viewport_parameters)) {
- world_recalc = true;
- has_updates_ = true;
- }
-
- has_updates_ |= viewport_parameters.modified(new_viewport_parameters);
- }
-}
-
-void BlenderSync::sync_data(BL::RenderSettings &b_render,
- BL::Depsgraph &b_depsgraph,
- BL::SpaceView3D &b_v3d,
- BL::Object &b_override,
- int width,
- int height,
- void **python_thread_state)
-{
- if (!has_updates_) {
- return;
- }
-
- scoped_timer timer;
-
- BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
-
- /* TODO(sergey): This feels weak to pass view layer to the integrator, and even weaker to have an
- * implicit check on whether it is a background render or not. What is the nicer thing here? */
- const bool background = !b_v3d;
-
- sync_view_layer(b_view_layer);
- sync_integrator(b_view_layer, background);
- sync_film(b_view_layer, b_v3d);
- sync_shaders(b_depsgraph, b_v3d);
- sync_images();
-
- geometry_synced.clear(); /* use for objects and motion sync */
-
- if (scene->need_motion() == Scene::MOTION_PASS || scene->need_motion() == Scene::MOTION_NONE ||
- scene->camera->get_motion_position() == Camera::MOTION_POSITION_CENTER) {
- sync_objects(b_depsgraph, b_v3d);
- }
- sync_motion(b_render, b_depsgraph, b_v3d, b_override, width, height, python_thread_state);
-
- geometry_synced.clear();
-
- /* Shader sync done at the end, since object sync uses it.
- * false = don't delete unused shaders, not supported. */
- shader_map.post_sync(false);
-
- free_data_after_sync(b_depsgraph);
-
- VLOG(1) << "Total time spent synchronizing data: " << timer.get_time();
-
- has_updates_ = false;
-}
-
-/* Integrator */
-
-void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
-{
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-
- experimental = (get_enum(cscene, "feature_set") != 0);
-
- Integrator *integrator = scene->integrator;
-
- integrator->set_min_bounce(get_int(cscene, "min_light_bounces"));
- integrator->set_max_bounce(get_int(cscene, "max_bounces"));
-
- integrator->set_max_diffuse_bounce(get_int(cscene, "diffuse_bounces"));
- integrator->set_max_glossy_bounce(get_int(cscene, "glossy_bounces"));
- integrator->set_max_transmission_bounce(get_int(cscene, "transmission_bounces"));
- integrator->set_max_volume_bounce(get_int(cscene, "volume_bounces"));
-
- integrator->set_transparent_min_bounce(get_int(cscene, "min_transparent_bounces"));
- integrator->set_transparent_max_bounce(get_int(cscene, "transparent_max_bounces"));
-
- integrator->set_volume_max_steps(get_int(cscene, "volume_max_steps"));
- float volume_step_rate = (preview) ? get_float(cscene, "volume_preview_step_rate") :
- get_float(cscene, "volume_step_rate");
- integrator->set_volume_step_rate(volume_step_rate);
-
- integrator->set_caustics_reflective(get_boolean(cscene, "caustics_reflective"));
- integrator->set_caustics_refractive(get_boolean(cscene, "caustics_refractive"));
- integrator->set_filter_glossy(get_float(cscene, "blur_glossy"));
-
- int seed = get_int(cscene, "seed");
- if (get_boolean(cscene, "use_animated_seed")) {
- seed = hash_uint2(b_scene.frame_current(), get_int(cscene, "seed"));
- if (b_scene.frame_subframe() != 0.0f) {
- /* TODO(sergey): Ideally should be some sort of hash_merge,
- * but this is good enough for now.
- */
- seed += hash_uint2((int)(b_scene.frame_subframe() * (float)INT_MAX),
- get_int(cscene, "seed"));
- }
- }
-
- integrator->set_seed(seed);
-
- integrator->set_sample_clamp_direct(get_float(cscene, "sample_clamp_direct"));
- integrator->set_sample_clamp_indirect(get_float(cscene, "sample_clamp_indirect"));
- if (!preview) {
- integrator->set_motion_blur(view_layer.use_motion_blur);
- }
-
- integrator->set_light_sampling_threshold(get_float(cscene, "light_sampling_threshold"));
-
- SamplingPattern sampling_pattern = (SamplingPattern)get_enum(
- cscene, "sampling_pattern", SAMPLING_NUM_PATTERNS, SAMPLING_PATTERN_SOBOL);
- integrator->set_sampling_pattern(sampling_pattern);
-
- if (preview) {
- integrator->set_use_adaptive_sampling(
- RNA_boolean_get(&cscene, "use_preview_adaptive_sampling"));
- integrator->set_adaptive_threshold(get_float(cscene, "preview_adaptive_threshold"));
- integrator->set_adaptive_min_samples(get_int(cscene, "preview_adaptive_min_samples"));
- }
- else {
- integrator->set_use_adaptive_sampling(RNA_boolean_get(&cscene, "use_adaptive_sampling"));
- integrator->set_adaptive_threshold(get_float(cscene, "adaptive_threshold"));
- integrator->set_adaptive_min_samples(get_int(cscene, "adaptive_min_samples"));
- }
-
- if (get_boolean(cscene, "use_fast_gi")) {
- if (preview) {
- integrator->set_ao_bounces(get_int(cscene, "ao_bounces"));
- }
- else {
- integrator->set_ao_bounces(get_int(cscene, "ao_bounces_render"));
- }
- }
- else {
- integrator->set_ao_bounces(0);
- }
-
- const DenoiseParams denoise_params = get_denoise_params(b_scene, b_view_layer, background);
- integrator->set_use_denoise(denoise_params.use);
-
- /* Only update denoiser parameters if the denoiser is actually used. This allows to tweak
- * denoiser parameters before enabling it without render resetting on every change. The downside
- * is that the interface and the integrator are technically out of sync. */
- if (denoise_params.use) {
- integrator->set_denoiser_type(denoise_params.type);
- integrator->set_denoise_start_sample(denoise_params.start_sample);
- integrator->set_use_denoise_pass_albedo(denoise_params.use_pass_albedo);
- integrator->set_use_denoise_pass_normal(denoise_params.use_pass_normal);
- integrator->set_denoiser_prefilter(denoise_params.prefilter);
- }
-
- /* UPDATE_NONE as we don't want to tag the integrator as modified (this was done by the
- * set calls above), but we need to make sure that the dependent things are tagged. */
- integrator->tag_update(scene, Integrator::UPDATE_NONE);
-}
-
-/* Film */
-
-void BlenderSync::sync_film(BL::ViewLayer &b_view_layer, BL::SpaceView3D &b_v3d)
-{
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
-
- Film *film = scene->film;
-
- if (b_v3d) {
- const BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
- film->set_display_pass(new_viewport_parameters.display_pass);
- film->set_show_active_pixels(new_viewport_parameters.show_active_pixels);
- }
-
- film->set_exposure(get_float(cscene, "film_exposure"));
- film->set_filter_type(
- (FilterType)get_enum(cscene, "pixel_filter_type", FILTER_NUM_TYPES, FILTER_BLACKMAN_HARRIS));
- float filter_width = (film->get_filter_type() == FILTER_BOX) ? 1.0f :
- get_float(cscene, "filter_width");
- film->set_filter_width(filter_width);
-
- if (b_scene.world()) {
- BL::WorldMistSettings b_mist = b_scene.world().mist_settings();
-
- film->set_mist_start(b_mist.start());
- film->set_mist_depth(b_mist.depth());
-
- switch (b_mist.falloff()) {
- case BL::WorldMistSettings::falloff_QUADRATIC:
- film->set_mist_falloff(2.0f);
- break;
- case BL::WorldMistSettings::falloff_LINEAR:
- film->set_mist_falloff(1.0f);
- break;
- case BL::WorldMistSettings::falloff_INVERSE_QUADRATIC:
- film->set_mist_falloff(0.5f);
- break;
- }
- }
-
- /* Blender viewport does not support proper shadow catcher compositing, so force an approximate
- * mode to improve visual feedback. */
- if (b_v3d) {
- film->set_use_approximate_shadow_catcher(true);
- }
- else {
- film->set_use_approximate_shadow_catcher(!get_boolean(crl, "use_pass_shadow_catcher"));
- }
-}
-
-/* Render Layer */
-
-void BlenderSync::sync_view_layer(BL::ViewLayer &b_view_layer)
-{
- view_layer.name = b_view_layer.name();
-
- /* Filter. */
- view_layer.use_background_shader = b_view_layer.use_sky();
- /* Always enable surfaces for baking, otherwise there is nothing to bake to. */
- view_layer.use_surfaces = b_view_layer.use_solid() || scene->bake_manager->get_baking();
- view_layer.use_hair = b_view_layer.use_strand();
- view_layer.use_volumes = b_view_layer.use_volumes();
- view_layer.use_motion_blur = b_view_layer.use_motion_blur() &&
- b_scene.render().use_motion_blur();
-
- /* Material override. */
- view_layer.material_override = b_view_layer.material_override();
-
- /* Sample override. */
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- int use_layer_samples = get_enum(cscene, "use_layer_samples");
-
- view_layer.bound_samples = (use_layer_samples == 1);
- view_layer.samples = 0;
-
- if (use_layer_samples != 2) {
- int samples = b_view_layer.samples();
- view_layer.samples = samples;
- }
-}
-
-/* Images */
-void BlenderSync::sync_images()
-{
- /* Sync is a convention for this API, but currently it frees unused buffers. */
-
- const bool is_interface_locked = b_engine.render() && b_engine.render().use_lock_interface();
- if (is_interface_locked == false && BlenderSession::headless == false) {
- /* If interface is not locked, it's possible image is needed for
- * the display.
- */
- return;
- }
- /* Free buffers used by images which are not needed for render. */
- for (BL::Image &b_image : b_data.images) {
- /* TODO(sergey): Consider making it an utility function to check
- * whether image is considered builtin.
- */
- const bool is_builtin = b_image.packed_file() ||
- b_image.source() == BL::Image::source_GENERATED ||
- b_image.source() == BL::Image::source_MOVIE || b_engine.is_preview();
- if (is_builtin == false) {
- b_image.buffers_free();
- }
- /* TODO(sergey): Free builtin images not used by any shader. */
- }
-}
-
-/* Passes */
-
-static PassType get_blender_pass_type(BL::RenderPass &b_pass)
-{
- string name = b_pass.name();
-#define MAP_PASS(passname, passtype) \
- if (name == passname) { \
- return passtype; \
- } \
- ((void)0)
-
- /* NOTE: Keep in sync with defined names from DNA_scene_types.h */
-
- MAP_PASS("Combined", PASS_COMBINED);
- MAP_PASS("Noisy Image", PASS_COMBINED);
-
- MAP_PASS("Depth", PASS_DEPTH);
- MAP_PASS("Mist", PASS_MIST);
- MAP_PASS("Position", PASS_POSITION);
- MAP_PASS("Normal", PASS_NORMAL);
- MAP_PASS("IndexOB", PASS_OBJECT_ID);
- MAP_PASS("UV", PASS_UV);
- MAP_PASS("Vector", PASS_MOTION);
- MAP_PASS("IndexMA", PASS_MATERIAL_ID);
-
- MAP_PASS("DiffDir", PASS_DIFFUSE_DIRECT);
- MAP_PASS("GlossDir", PASS_GLOSSY_DIRECT);
- MAP_PASS("TransDir", PASS_TRANSMISSION_DIRECT);
- MAP_PASS("VolumeDir", PASS_VOLUME_DIRECT);
-
- MAP_PASS("DiffInd", PASS_DIFFUSE_INDIRECT);
- MAP_PASS("GlossInd", PASS_GLOSSY_INDIRECT);
- MAP_PASS("TransInd", PASS_TRANSMISSION_INDIRECT);
- MAP_PASS("VolumeInd", PASS_VOLUME_INDIRECT);
-
- MAP_PASS("DiffCol", PASS_DIFFUSE_COLOR);
- MAP_PASS("GlossCol", PASS_GLOSSY_COLOR);
- MAP_PASS("TransCol", PASS_TRANSMISSION_COLOR);
-
- MAP_PASS("Emit", PASS_EMISSION);
- MAP_PASS("Env", PASS_BACKGROUND);
- MAP_PASS("AO", PASS_AO);
- MAP_PASS("Shadow", PASS_SHADOW);
-
- MAP_PASS("BakePrimitive", PASS_BAKE_PRIMITIVE);
- MAP_PASS("BakeDifferential", PASS_BAKE_DIFFERENTIAL);
-
- MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL);
- MAP_PASS("Denoising Albedo", PASS_DENOISING_ALBEDO);
-
- MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER);
- MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER);
-
- MAP_PASS("AdaptiveAuxBuffer", PASS_ADAPTIVE_AUX_BUFFER);
- MAP_PASS("Debug Sample Count", PASS_SAMPLE_COUNT);
-
- if (string_startswith(name, cryptomatte_prefix)) {
- return PASS_CRYPTOMATTE;
- }
-
-#undef MAP_PASS
-
- return PASS_NONE;
-}
-
-static Pass *pass_add(Scene *scene,
- PassType type,
- const char *name,
- PassMode mode = PassMode::DENOISED)
-{
- Pass *pass = scene->create_node<Pass>();
-
- pass->set_type(type);
- pass->set_name(ustring(name));
- pass->set_mode(mode);
-
- return pass;
-}
-
-void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer)
-{
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-
- /* Delete all existing passes. */
- set<Pass *> clear_passes(scene->passes.begin(), scene->passes.end());
- scene->delete_nodes(clear_passes);
-
- /* Always add combined pass. */
- pass_add(scene, PASS_COMBINED, "Combined");
-
- /* Blender built-in data and light passes. */
- for (BL::RenderPass &b_pass : b_rlay.passes) {
- const PassType pass_type = get_blender_pass_type(b_pass);
-
- if (pass_type == PASS_NONE) {
- LOG(ERROR) << "Unknown pass " << b_pass.name();
- continue;
- }
-
- if (pass_type == PASS_MOTION &&
- (b_view_layer.use_motion_blur() && b_scene.render().use_motion_blur())) {
- continue;
- }
-
- pass_add(scene, pass_type, b_pass.name().c_str());
- }
-
- PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
-
- /* Debug passes. */
- if (get_boolean(crl, "pass_debug_sample_count")) {
- b_engine.add_pass("Debug Sample Count", 1, "X", b_view_layer.name().c_str());
- pass_add(scene, PASS_SAMPLE_COUNT, "Debug Sample Count");
- }
-
- /* Cycles specific passes. */
- if (get_boolean(crl, "use_pass_volume_direct")) {
- b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str());
- pass_add(scene, PASS_VOLUME_DIRECT, "VolumeDir");
- }
- if (get_boolean(crl, "use_pass_volume_indirect")) {
- b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str());
- pass_add(scene, PASS_VOLUME_INDIRECT, "VolumeInd");
- }
- if (get_boolean(crl, "use_pass_shadow_catcher")) {
- b_engine.add_pass("Shadow Catcher", 3, "RGB", b_view_layer.name().c_str());
- pass_add(scene, PASS_SHADOW_CATCHER, "Shadow Catcher");
- }
-
- /* Cryptomatte stores two ID/weight pairs per RGBA layer.
- * User facing parameter is the number of pairs. */
- int crypto_depth = divide_up(min(16, b_view_layer.pass_cryptomatte_depth()), 2);
- scene->film->set_cryptomatte_depth(crypto_depth);
- CryptomatteType cryptomatte_passes = CRYPT_NONE;
- if (b_view_layer.use_pass_cryptomatte_object()) {
- for (int i = 0; i < crypto_depth; i++) {
- string passname = cryptomatte_prefix + string_printf("Object%02d", i);
- b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
- pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
- }
- cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_OBJECT);
- }
- if (b_view_layer.use_pass_cryptomatte_material()) {
- for (int i = 0; i < crypto_depth; i++) {
- string passname = cryptomatte_prefix + string_printf("Material%02d", i);
- b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
- pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
- }
- cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_MATERIAL);
- }
- if (b_view_layer.use_pass_cryptomatte_asset()) {
- for (int i = 0; i < crypto_depth; i++) {
- string passname = cryptomatte_prefix + string_printf("Asset%02d", i);
- b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
- pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
- }
- cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ASSET);
- }
- scene->film->set_cryptomatte_passes(cryptomatte_passes);
-
- /* Denoising passes. */
- const bool use_denoising = get_boolean(cscene, "use_denoising") &&
- get_boolean(crl, "use_denoising");
- const bool store_denoising_passes = get_boolean(crl, "denoising_store_passes");
- if (use_denoising) {
- b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
- pass_add(scene, PASS_COMBINED, "Noisy Image", PassMode::NOISY);
- if (get_boolean(crl, "use_pass_shadow_catcher")) {
- b_engine.add_pass("Noisy Shadow Catcher", 3, "RGB", b_view_layer.name().c_str());
- pass_add(scene, PASS_SHADOW_CATCHER, "Noisy Shadow Catcher", PassMode::NOISY);
- }
- }
- if (store_denoising_passes) {
- b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
- pass_add(scene, PASS_DENOISING_NORMAL, "Denoising Normal", PassMode::NOISY);
-
- b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str());
- pass_add(scene, PASS_DENOISING_ALBEDO, "Denoising Albedo", PassMode::NOISY);
- }
-
- /* Custom AOV passes. */
- BL::ViewLayer::aovs_iterator b_aov_iter;
- for (b_view_layer.aovs.begin(b_aov_iter); b_aov_iter != b_view_layer.aovs.end(); ++b_aov_iter) {
- BL::AOV b_aov(*b_aov_iter);
- if (!b_aov.is_valid()) {
- continue;
- }
-
- string name = b_aov.name();
- bool is_color = b_aov.type() == BL::AOV::type_COLOR;
-
- if (is_color) {
- b_engine.add_pass(name.c_str(), 4, "RGBA", b_view_layer.name().c_str());
- pass_add(scene, PASS_AOV_COLOR, name.c_str());
- }
- else {
- b_engine.add_pass(name.c_str(), 1, "X", b_view_layer.name().c_str());
- pass_add(scene, PASS_AOV_VALUE, name.c_str());
- }
- }
-
- scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
-}
-
-void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
-{
- /* When viewport display is not needed during render we can force some
- * caches to be releases from blender side in order to reduce peak memory
- * footprint during synchronization process.
- */
-
- const bool is_interface_locked = b_engine.render() && b_engine.render().use_lock_interface();
- const bool is_persistent_data = b_engine.render() && b_engine.render().use_persistent_data();
- const bool can_free_caches =
- (BlenderSession::headless || is_interface_locked) &&
- /* Baking re-uses the depsgraph multiple times, clearing crashes
- * reading un-evaluated mesh data which isn't aligned with the
- * geometry we're baking, see T71012. */
- !scene->bake_manager->get_baking() &&
- /* Persistent data must main caches for performance and correctness. */
- !is_persistent_data;
-
- if (!can_free_caches) {
- return;
- }
- /* TODO(sergey): We can actually remove the whole dependency graph,
- * but that will need some API support first.
- */
- for (BL::Object &b_ob : b_depsgraph.objects) {
- b_ob.cache_release();
- }
-}
-
-/* Scene Parameters */
-
-SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background)
-{
- SceneParams params;
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system");
-
- if (shadingsystem == 0)
- params.shadingsystem = SHADINGSYSTEM_SVM;
- else if (shadingsystem == 1)
- params.shadingsystem = SHADINGSYSTEM_OSL;
-
- if (background || DebugFlags().viewport_static_bvh)
- params.bvh_type = BVH_TYPE_STATIC;
- else
- params.bvh_type = BVH_TYPE_DYNAMIC;
-
- params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
- params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh");
- params.num_bvh_time_steps = RNA_int_get(&cscene, "debug_bvh_time_steps");
-
- PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
- params.hair_subdivisions = get_int(csscene, "subdivisions");
- params.hair_shape = (CurveShapeType)get_enum(
- csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK);
-
- int texture_limit;
- if (background) {
- texture_limit = RNA_enum_get(&cscene, "texture_limit_render");
- }
- else {
- texture_limit = RNA_enum_get(&cscene, "texture_limit");
- }
- if (texture_limit > 0 && b_scene.render().use_simplify()) {
- params.texture_limit = 1 << (texture_limit + 6);
- }
- else {
- params.texture_limit = 0;
- }
-
- params.bvh_layout = DebugFlags().cpu.bvh_layout;
-
- params.background = background;
-
- return params;
-}
-
-/* Session Parameters */
-
-bool BlenderSync::get_session_pause(BL::Scene &b_scene, bool background)
-{
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- return (background) ? false : get_boolean(cscene, "preview_pause");
-}
-
-SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
- BL::Preferences &b_preferences,
- BL::Scene &b_scene,
- bool background)
-{
- SessionParams params;
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-
- /* feature set */
- params.experimental = (get_enum(cscene, "feature_set") != 0);
-
- /* Headless and background rendering. */
- params.headless = BlenderSession::headless;
- params.background = background;
-
- /* Device */
- params.threads = blender_device_threads(b_scene);
- params.device = blender_device_info(b_preferences, b_scene, params.background);
-
- /* samples */
- int samples = get_int(cscene, "samples");
- int preview_samples = get_int(cscene, "preview_samples");
-
- if (background) {
- params.samples = samples;
- }
- else {
- params.samples = preview_samples;
- if (params.samples == 0)
- params.samples = INT_MAX;
- }
-
- /* Clamp samples. */
- params.samples = min(params.samples, Integrator::MAX_SAMPLES);
-
- /* Viewport Performance */
- params.pixel_size = b_engine.get_preview_pixel_size(b_scene);
-
- if (background) {
- params.pixel_size = 1;
- }
-
- /* shading system - scene level needs full refresh */
- const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system");
-
- if (shadingsystem == 0)
- params.shadingsystem = SHADINGSYSTEM_SVM;
- else if (shadingsystem == 1)
- params.shadingsystem = SHADINGSYSTEM_OSL;
-
- /* Time limit. */
- if (background) {
- params.time_limit = get_float(cscene, "time_limit");
- }
- else {
- /* For the viewport it kind of makes more sense to think in terms of the noise floor, which is
- * usually higher than acceptable level for the final frame. */
- /* TODO: It might be useful to support time limit in the viewport as well, but needs some
- * extra thoughts and input. */
- params.time_limit = 0.0;
- }
-
- /* Profiling. */
- params.use_profiling = params.device.has_profiling && !b_engine.is_preview() && background &&
- BlenderSession::print_render_stats;
-
- if (background) {
- params.use_auto_tile = RNA_boolean_get(&cscene, "use_auto_tile");
- params.tile_size = max(get_int(cscene, "tile_size"), 8);
- }
- else {
- params.use_auto_tile = false;
- }
-
- return params;
-}
-
-DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
- BL::ViewLayer &b_view_layer,
- bool background)
-{
- enum DenoiserInput {
- DENOISER_INPUT_RGB = 1,
- DENOISER_INPUT_RGB_ALBEDO = 2,
- DENOISER_INPUT_RGB_ALBEDO_NORMAL = 3,
-
- DENOISER_INPUT_NUM,
- };
-
- DenoiseParams denoising;
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-
- int input_passes = -1;
-
- if (background) {
- /* Final Render Denoising */
- denoising.use = get_boolean(cscene, "use_denoising");
- denoising.type = (DenoiserType)get_enum(cscene, "denoiser", DENOISER_NUM, DENOISER_NONE);
- denoising.prefilter = (DenoiserPrefilter)get_enum(
- cscene, "denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_NONE);
-
- input_passes = (DenoiserInput)get_enum(
- cscene, "denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO_NORMAL);
-
- if (b_view_layer) {
- PointerRNA clayer = RNA_pointer_get(&b_view_layer.ptr, "cycles");
- if (!get_boolean(clayer, "use_denoising")) {
- denoising.use = false;
- }
- }
- }
- else {
- /* Viewport Denoising */
- denoising.use = get_boolean(cscene, "use_preview_denoising");
- denoising.type = (DenoiserType)get_enum(
- cscene, "preview_denoiser", DENOISER_NUM, DENOISER_NONE);
- denoising.prefilter = (DenoiserPrefilter)get_enum(
- cscene, "preview_denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_FAST);
- denoising.start_sample = get_int(cscene, "preview_denoising_start_sample");
-
- input_passes = (DenoiserInput)get_enum(
- cscene, "preview_denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO);
-
- /* Auto select fastest denoiser. */
- if (denoising.type == DENOISER_NONE) {
- if (!Device::available_devices(DEVICE_MASK_OPTIX).empty()) {
- denoising.type = DENOISER_OPTIX;
- }
- else if (openimagedenoise_supported()) {
- denoising.type = DENOISER_OPENIMAGEDENOISE;
- }
- else {
- denoising.use = false;
- }
- }
- }
-
- switch (input_passes) {
- case DENOISER_INPUT_RGB:
- denoising.use_pass_albedo = false;
- denoising.use_pass_normal = false;
- break;
-
- case DENOISER_INPUT_RGB_ALBEDO:
- denoising.use_pass_albedo = true;
- denoising.use_pass_normal = false;
- break;
-
- case DENOISER_INPUT_RGB_ALBEDO_NORMAL:
- denoising.use_pass_albedo = true;
- denoising.use_pass_normal = true;
- break;
-
- default:
- LOG(ERROR) << "Unhandled input passes enum " << input_passes;
- break;
- }
-
- return denoising;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
deleted file mode 100644
index 786479ac0f8..00000000000
--- a/intern/cycles/blender/blender_sync.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BLENDER_SYNC_H__
-#define __BLENDER_SYNC_H__
-
-#include "MEM_guardedalloc.h"
-#include "RNA_access.h"
-#include "RNA_blender_cpp.h"
-#include "RNA_types.h"
-
-#include "blender/blender_id_map.h"
-#include "blender/blender_util.h"
-#include "blender/blender_viewport.h"
-
-#include "render/scene.h"
-#include "render/session.h"
-
-#include "util/util_map.h"
-#include "util/util_set.h"
-#include "util/util_transform.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Background;
-class BlenderObjectCulling;
-class BlenderViewportParameters;
-class Camera;
-class Film;
-class Hair;
-class Light;
-class Mesh;
-class Object;
-class ParticleSystem;
-class Scene;
-class ViewLayer;
-class Shader;
-class ShaderGraph;
-class ShaderNode;
-class TaskPool;
-
-class BlenderSync {
- public:
- BlenderSync(BL::RenderEngine &b_engine,
- BL::BlendData &b_data,
- BL::Scene &b_scene,
- Scene *scene,
- bool preview,
- bool use_developer_ui,
- Progress &progress);
- ~BlenderSync();
-
- void reset(BL::BlendData &b_data, BL::Scene &b_scene);
-
- /* sync */
- void sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
- void sync_data(BL::RenderSettings &b_render,
- BL::Depsgraph &b_depsgraph,
- BL::SpaceView3D &b_v3d,
- BL::Object &b_override,
- int width,
- int height,
- void **python_thread_state);
- void sync_view_layer(BL::ViewLayer &b_view_layer);
- void sync_render_passes(BL::RenderLayer &b_render_layer, BL::ViewLayer &b_view_layer);
- void sync_integrator(BL::ViewLayer &b_view_layer, bool background);
- void sync_camera(BL::RenderSettings &b_render,
- BL::Object &b_override,
- int width,
- int height,
- const char *viewname);
- void sync_view(BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, int width, int height);
- inline int get_layer_samples()
- {
- return view_layer.samples;
- }
- inline int get_layer_bound_samples()
- {
- return view_layer.bound_samples;
- }
-
- /* get parameters */
- static SceneParams get_scene_params(BL::Scene &b_scene, bool background);
- static SessionParams get_session_params(BL::RenderEngine &b_engine,
- BL::Preferences &b_userpref,
- BL::Scene &b_scene,
- bool background);
- static bool get_session_pause(BL::Scene &b_scene, bool background);
- static BufferParams get_buffer_params(
- BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height);
-
- private:
- static DenoiseParams get_denoise_params(BL::Scene &b_scene,
- BL::ViewLayer &b_view_layer,
- bool background);
-
- /* sync */
- void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all);
- void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all);
- void sync_objects(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, float motion_time = 0.0f);
- void sync_motion(BL::RenderSettings &b_render,
- BL::Depsgraph &b_depsgraph,
- BL::SpaceView3D &b_v3d,
- BL::Object &b_override,
- int width,
- int height,
- void **python_thread_state);
- void sync_film(BL::ViewLayer &b_view_layer, BL::SpaceView3D &b_v3d);
- void sync_view();
-
- /* Shader */
- array<Node *> find_used_shaders(BL::Object &b_ob);
- void sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all);
- void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
- void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree);
-
- /* Object */
- Object *sync_object(BL::Depsgraph &b_depsgraph,
- BL::ViewLayer &b_view_layer,
- BL::DepsgraphObjectInstance &b_instance,
- float motion_time,
- bool use_particle_hair,
- bool show_lights,
- BlenderObjectCulling &culling,
- bool *use_portal,
- TaskPool *geom_task_pool);
- void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object);
-
- void sync_procedural(BL::Object &b_ob,
- BL::MeshSequenceCacheModifier &b_mesh_cache,
- bool has_subdivision);
-
- bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);
-
- /* Volume */
- void sync_volume(BObjectInfo &b_ob_info, Volume *volume);
-
- /* Mesh */
- void sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh);
- void sync_mesh_motion(BL::Depsgraph b_depsgraph,
- BObjectInfo &b_ob_info,
- Mesh *mesh,
- int motion_step);
-
- /* Hair */
- void sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair);
- void sync_hair_motion(BL::Depsgraph b_depsgraph,
- BObjectInfo &b_ob_info,
- Hair *hair,
- int motion_step);
- void sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
- void sync_particle_hair(
- Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
- bool object_has_particle_hair(BL::Object b_ob);
-
- /* Camera */
- void sync_camera_motion(
- BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time);
-
- /* Geometry */
- Geometry *sync_geometry(BL::Depsgraph &b_depsgrpah,
- BObjectInfo &b_ob_info,
- bool object_updated,
- bool use_particle_hair,
- TaskPool *task_pool);
-
- void sync_geometry_motion(BL::Depsgraph &b_depsgraph,
- BObjectInfo &b_ob_info,
- Object *object,
- float motion_time,
- bool use_particle_hair,
- TaskPool *task_pool);
-
- /* Light */
- void sync_light(BL::Object &b_parent,
- int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
- BObjectInfo &b_ob_info,
- int random_id,
- Transform &tfm,
- bool *use_portal);
- void sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal);
-
- /* Particles */
- bool sync_dupli_particle(BL::Object &b_ob,
- BL::DepsgraphObjectInstance &b_instance,
- Object *object);
-
- /* Images. */
- void sync_images();
-
- /* Early data free. */
- void free_data_after_sync(BL::Depsgraph &b_depsgraph);
-
- /* util */
- void find_shader(BL::ID &id, array<Node *> &used_shaders, Shader *default_shader);
- bool BKE_object_is_modified(BL::Object &b_ob);
- bool object_is_geometry(BL::Object &b_ob);
- bool object_is_light(BL::Object &b_ob);
-
- /* variables */
- BL::RenderEngine b_engine;
- BL::BlendData b_data;
- BL::Scene b_scene;
-
- id_map<void *, Shader> shader_map;
- id_map<ObjectKey, Object> object_map;
- id_map<void *, Procedural> procedural_map;
- id_map<GeometryKey, Geometry> geometry_map;
- id_map<ObjectKey, Light> light_map;
- id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
- set<Geometry *> geometry_synced;
- set<Geometry *> geometry_motion_synced;
- set<Geometry *> geometry_motion_attribute_synced;
- set<float> motion_times;
- void *world_map;
- bool world_recalc;
- BlenderViewportParameters viewport_parameters;
-
- Scene *scene;
- bool preview;
- bool experimental;
- bool use_developer_ui;
-
- float dicing_rate;
- int max_subdivisions;
-
- struct RenderLayerInfo {
- RenderLayerInfo()
- : material_override(PointerRNA_NULL),
- use_background_shader(true),
- use_surfaces(true),
- use_hair(true),
- use_volumes(true),
- use_motion_blur(true),
- samples(0),
- bound_samples(false)
- {
- }
-
- string name;
- BL::Material material_override;
- bool use_background_shader;
- bool use_surfaces;
- bool use_hair;
- bool use_volumes;
- bool use_motion_blur;
- int samples;
- bool bound_samples;
- } view_layer;
-
- Progress &progress;
-
- protected:
- /* Indicates that `sync_recalc()` detected changes in the scene.
- * If this flag is false then the data is considered to be up-to-date and will not be
- * synchronized at all. */
- bool has_updates_ = true;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BLENDER_SYNC_H__ */
diff --git a/intern/cycles/blender/blender_texture.cpp b/intern/cycles/blender/blender_texture.cpp
deleted file mode 100644
index 0d593f2b385..00000000000
--- a/intern/cycles/blender/blender_texture.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2011-2015 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "blender/blender_texture.h"
-
-CCL_NAMESPACE_BEGIN
-
-namespace {
-
-/* Point density helpers. */
-
-void density_texture_space_invert(float3 &loc, float3 &size)
-{
- if (size.x != 0.0f)
- size.x = 0.5f / size.x;
- if (size.y != 0.0f)
- size.y = 0.5f / size.y;
- if (size.z != 0.0f)
- size.z = 0.5f / size.z;
-
- loc = loc * size - make_float3(0.5f, 0.5f, 0.5f);
-}
-
-} /* namespace */
-
-void point_density_texture_space(BL::Depsgraph &b_depsgraph,
- BL::ShaderNodeTexPointDensity &b_point_density_node,
- float3 &loc,
- float3 &size)
-{
- BL::Object b_ob(b_point_density_node.object());
- if (!b_ob) {
- loc = zero_float3();
- size = zero_float3();
- return;
- }
- float3 min, max;
- b_point_density_node.calc_point_density_minmax(b_depsgraph, &min[0], &max[0]);
- loc = (min + max) * 0.5f;
- size = (max - min) * 0.5f;
- density_texture_space_invert(loc, size);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_texture.h b/intern/cycles/blender/blender_texture.h
deleted file mode 100644
index 8ab061aaed9..00000000000
--- a/intern/cycles/blender/blender_texture.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2011-2015 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BLENDER_TEXTURE_H__
-#define __BLENDER_TEXTURE_H__
-
-#include "blender/blender_sync.h"
-#include <stdlib.h>
-
-CCL_NAMESPACE_BEGIN
-
-void point_density_texture_space(BL::Depsgraph &b_depsgraph,
- BL::ShaderNodeTexPointDensity &b_point_density_node,
- float3 &loc,
- float3 &size);
-
-CCL_NAMESPACE_END
-
-#endif /* __BLENDER_TEXTURE_H__ */
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
deleted file mode 100644
index 77b2bd5ac4f..00000000000
--- a/intern/cycles/blender/blender_util.h
+++ /dev/null
@@ -1,720 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BLENDER_UTIL_H__
-#define __BLENDER_UTIL_H__
-
-#include "render/mesh.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_array.h"
-#include "util/util_map.h"
-#include "util/util_path.h"
-#include "util/util_set.h"
-#include "util/util_transform.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-/* Hacks to hook into Blender API
- * todo: clean this up ... */
-
-extern "C" {
-void BKE_image_user_frame_calc(void *ima, void *iuser, int cfra);
-void BKE_image_user_file_path(void *iuser, void *ima, char *path);
-unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame, int tile);
-float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
-}
-
-CCL_NAMESPACE_BEGIN
-
-struct BObjectInfo {
- /* Object directly provided by the depsgraph iterator. This object is only valid during one
- * iteration and must not be accessed afterwards. Transforms and visibility should be checked on
- * this object. */
- BL::Object iter_object;
-
- /* This object remains alive even after the object iterator is done. It corresponds to one
- * original object. It is the object that owns the object data below. */
- BL::Object real_object;
-
- /* The object-data referenced by the iter object. This is still valid after the depsgraph
- * iterator is done. It might have a different type compared to real_object.data(). */
- BL::ID object_data;
-
- /* True when the current geometry is the data of the referenced object. False when it is a
- * geometry instance that does not have a 1-to-1 relationship with an object. */
- bool is_real_object_data() const
- {
- return const_cast<BL::Object &>(real_object).data() == object_data;
- }
-};
-
-typedef BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType;
-BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name);
-
-void python_thread_state_save(void **python_thread_state);
-void python_thread_state_restore(void **python_thread_state);
-
-static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
- BObjectInfo &b_ob_info,
- BL::Depsgraph & /*depsgraph*/,
- bool /*calc_undeformed*/,
- Mesh::SubdivisionType subdivision_type)
-{
- /* TODO: make this work with copy-on-write, modifiers are already evaluated. */
-#if 0
- bool subsurf_mod_show_render = false;
- bool subsurf_mod_show_viewport = false;
-
- if (subdivision_type != Mesh::SUBDIVISION_NONE) {
- BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1];
-
- subsurf_mod_show_render = subsurf_mod.show_render();
- subsurf_mod_show_viewport = subsurf_mod.show_viewport();
-
- subsurf_mod.show_render(false);
- subsurf_mod.show_viewport(false);
- }
-#endif
-
- BL::Mesh mesh = (b_ob_info.object_data.is_a(&RNA_Mesh)) ? BL::Mesh(b_ob_info.object_data) :
- BL::Mesh(PointerRNA_NULL);
-
- if (b_ob_info.is_real_object_data()) {
- if (mesh) {
- /* Make a copy to split faces if we use autosmooth, otherwise not needed.
- * Also in edit mode do we need to make a copy, to ensure data layers like
- * UV are not empty. */
- if (mesh.is_editmode() ||
- (mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) {
- BL::Depsgraph depsgraph(PointerRNA_NULL);
- mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
- }
- }
- else {
- BL::Depsgraph depsgraph(PointerRNA_NULL);
- mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
- }
- }
- else {
- /* TODO: what to do about non-mesh geometry instances? */
- }
-
-#if 0
- if (subdivision_type != Mesh::SUBDIVISION_NONE) {
- BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1];
-
- subsurf_mod.show_render(subsurf_mod_show_render);
- subsurf_mod.show_viewport(subsurf_mod_show_viewport);
- }
-#endif
-
- if ((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) {
- if (mesh.use_auto_smooth()) {
- mesh.split_faces(false);
- }
-
- mesh.calc_loop_triangles();
- }
-
- return mesh;
-}
-
-static inline void free_object_to_mesh(BL::BlendData & /*data*/,
- BObjectInfo &b_ob_info,
- BL::Mesh &mesh)
-{
- if (!b_ob_info.is_real_object_data()) {
- return;
- }
- /* Free mesh if we didn't just use the existing one. */
- BL::Object object = b_ob_info.real_object;
- if (object.data().ptr.data != mesh.ptr.data) {
- object.to_mesh_clear();
- }
-}
-
-static inline void colorramp_to_array(BL::ColorRamp &ramp,
- array<float3> &ramp_color,
- array<float> &ramp_alpha,
- int size)
-{
- ramp_color.resize(size);
- ramp_alpha.resize(size);
-
- for (int i = 0; i < size; i++) {
- float color[4];
-
- ramp.evaluate((float)i / (float)(size - 1), color);
- ramp_color[i] = make_float3(color[0], color[1], color[2]);
- ramp_alpha[i] = color[3];
- }
-}
-
-static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap &curve, float *min_x, float *max_x)
-{
- *min_x = min(*min_x, curve.points[0].location()[0]);
- *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]);
-}
-
-static inline void curvemapping_minmax(/*const*/ BL::CurveMapping &cumap,
- int num_curves,
- float *min_x,
- float *max_x)
-{
- // const int num_curves = cumap.curves.length(); /* Gives linking error so far. */
- *min_x = FLT_MAX;
- *max_x = -FLT_MAX;
- for (int i = 0; i < num_curves; ++i) {
- BL::CurveMap map(cumap.curves[i]);
- curvemap_minmax_curve(map, min_x, max_x);
- }
-}
-
-static inline void curvemapping_to_array(BL::CurveMapping &cumap, array<float> &data, int size)
-{
- cumap.update();
- BL::CurveMap curve = cumap.curves[0];
- data.resize(size);
- for (int i = 0; i < size; i++) {
- float t = (float)i / (float)(size - 1);
- data[i] = cumap.evaluate(curve, t);
- }
-}
-
-static inline void curvemapping_float_to_array(BL::CurveMapping &cumap,
- array<float> &data,
- int size)
-{
- float min = 0.0f, max = 1.0f;
-
- curvemapping_minmax(cumap, 1, &min, &max);
-
- const float range = max - min;
-
- cumap.update();
-
- BL::CurveMap map = cumap.curves[0];
-
- data.resize(size);
-
- for (int i = 0; i < size; i++) {
- float t = min + (float)i / (float)(size - 1) * range;
- data[i] = cumap.evaluate(map, t);
- }
-}
-
-static inline void curvemapping_color_to_array(BL::CurveMapping &cumap,
- array<float3> &data,
- int size,
- bool rgb_curve)
-{
- float min_x = 0.0f, max_x = 1.0f;
-
- /* TODO(sergey): There is no easy way to automatically guess what is
- * the range to be used here for the case when mapping is applied on
- * top of another mapping (i.e. R curve applied on top of common
- * one).
- *
- * Using largest possible range form all curves works correct for the
- * cases like vector curves and should be good enough heuristic for
- * the color curves as well.
- *
- * There might be some better estimations here tho.
- */
- const int num_curves = rgb_curve ? 4 : 3;
- curvemapping_minmax(cumap, num_curves, &min_x, &max_x);
-
- const float range_x = max_x - min_x;
-
- cumap.update();
-
- BL::CurveMap mapR = cumap.curves[0];
- BL::CurveMap mapG = cumap.curves[1];
- BL::CurveMap mapB = cumap.curves[2];
-
- data.resize(size);
-
- if (rgb_curve) {
- BL::CurveMap mapI = cumap.curves[3];
- for (int i = 0; i < size; i++) {
- const float t = min_x + (float)i / (float)(size - 1) * range_x;
- data[i] = make_float3(cumap.evaluate(mapR, cumap.evaluate(mapI, t)),
- cumap.evaluate(mapG, cumap.evaluate(mapI, t)),
- cumap.evaluate(mapB, cumap.evaluate(mapI, t)));
- }
- }
- else {
- for (int i = 0; i < size; i++) {
- float t = min_x + (float)i / (float)(size - 1) * range_x;
- data[i] = make_float3(
- cumap.evaluate(mapR, t), cumap.evaluate(mapG, t), cumap.evaluate(mapB, t));
- }
- }
-}
-
-static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bool preview)
-{
- return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
-}
-
-static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview)
-{
- if (!self.is_real_object_data()) {
- return false;
- }
- return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true :
- false;
-}
-
-static inline int render_resolution_x(BL::RenderSettings &b_render)
-{
- return b_render.resolution_x() * b_render.resolution_percentage() / 100;
-}
-
-static inline int render_resolution_y(BL::RenderSettings &b_render)
-{
- return b_render.resolution_y() * b_render.resolution_percentage() / 100;
-}
-
-static inline string image_user_file_path(BL::ImageUser &iuser,
- BL::Image &ima,
- int cfra,
- bool load_tiled)
-{
- char filepath[1024];
- iuser.tile(0);
- BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra);
- BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath);
-
- string filepath_str = string(filepath);
- if (load_tiled && ima.source() == BL::Image::source_TILED) {
- string udim;
- if (ima.tiles.length() > 0) {
- udim = to_string(ima.tiles[0].number());
- }
- string_replace(filepath_str, udim, "<UDIM>");
- }
- return filepath_str;
-}
-
-static inline int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, int cfra)
-{
- BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra);
- return iuser.frame_current();
-}
-
-static inline unsigned char *image_get_pixels_for_frame(BL::Image &image, int frame, int tile)
-{
- return BKE_image_get_pixels_for_frame(image.ptr.data, frame, tile);
-}
-
-static inline float *image_get_float_pixels_for_frame(BL::Image &image, int frame, int tile)
-{
- return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame, tile);
-}
-
-static inline void render_add_metadata(BL::RenderResult &b_rr, string name, string value)
-{
- b_rr.stamp_data_add_field(name.c_str(), value.c_str());
-}
-
-/* Utilities */
-
-static inline Transform get_transform(const BL::Array<float, 16> &array)
-{
- ProjectionTransform projection;
-
- /* We assume both types to be just 16 floats, and transpose because blender
- * use column major matrix order while we use row major. */
- memcpy((void *)&projection, &array, sizeof(float) * 16);
- projection = projection_transpose(projection);
-
- /* Drop last row, matrix is assumed to be affine transform. */
- return projection_to_transform(projection);
-}
-
-static inline float2 get_float2(const BL::Array<float, 2> &array)
-{
- return make_float2(array[0], array[1]);
-}
-
-static inline float3 get_float3(const BL::Array<float, 2> &array)
-{
- return make_float3(array[0], array[1], 0.0f);
-}
-
-static inline float3 get_float3(const BL::Array<float, 3> &array)
-{
- return make_float3(array[0], array[1], array[2]);
-}
-
-static inline float3 get_float3(const BL::Array<float, 4> &array)
-{
- return make_float3(array[0], array[1], array[2]);
-}
-
-static inline float4 get_float4(const BL::Array<float, 4> &array)
-{
- return make_float4(array[0], array[1], array[2], array[3]);
-}
-
-static inline int3 get_int3(const BL::Array<int, 3> &array)
-{
- return make_int3(array[0], array[1], array[2]);
-}
-
-static inline int4 get_int4(const BL::Array<int, 4> &array)
-{
- return make_int4(array[0], array[1], array[2], array[3]);
-}
-
-static inline float3 get_float3(PointerRNA &ptr, const char *name)
-{
- float3 f;
- RNA_float_get_array(&ptr, name, &f.x);
- return f;
-}
-
-static inline void set_float3(PointerRNA &ptr, const char *name, float3 value)
-{
- RNA_float_set_array(&ptr, name, &value.x);
-}
-
-static inline float4 get_float4(PointerRNA &ptr, const char *name)
-{
- float4 f;
- RNA_float_get_array(&ptr, name, &f.x);
- return f;
-}
-
-static inline void set_float4(PointerRNA &ptr, const char *name, float4 value)
-{
- RNA_float_set_array(&ptr, name, &value.x);
-}
-
-static inline bool get_boolean(PointerRNA &ptr, const char *name)
-{
- return RNA_boolean_get(&ptr, name) ? true : false;
-}
-
-static inline void set_boolean(PointerRNA &ptr, const char *name, bool value)
-{
- RNA_boolean_set(&ptr, name, (int)value);
-}
-
-static inline float get_float(PointerRNA &ptr, const char *name)
-{
- return RNA_float_get(&ptr, name);
-}
-
-static inline void set_float(PointerRNA &ptr, const char *name, float value)
-{
- RNA_float_set(&ptr, name, value);
-}
-
-static inline int get_int(PointerRNA &ptr, const char *name)
-{
- return RNA_int_get(&ptr, name);
-}
-
-static inline void set_int(PointerRNA &ptr, const char *name, int value)
-{
- RNA_int_set(&ptr, name, value);
-}
-
-/* Get a RNA enum value with sanity check: if the RNA value is above num_values
- * the function will return a fallback default value.
- *
- * NOTE: This function assumes that RNA enum values are a continuous sequence
- * from 0 to num_values-1. Be careful to use it with enums where some values are
- * deprecated!
- */
-static inline int get_enum(PointerRNA &ptr,
- const char *name,
- int num_values = -1,
- int default_value = -1)
-{
- int value = RNA_enum_get(&ptr, name);
- if (num_values != -1 && value >= num_values) {
- assert(default_value != -1);
- value = default_value;
- }
- return value;
-}
-
-static inline string get_enum_identifier(PointerRNA &ptr, const char *name)
-{
- PropertyRNA *prop = RNA_struct_find_property(&ptr, name);
- const char *identifier = "";
- int value = RNA_property_enum_get(&ptr, prop);
-
- RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
-
- return string(identifier);
-}
-
-static inline void set_enum(PointerRNA &ptr, const char *name, int value)
-{
- RNA_enum_set(&ptr, name, value);
-}
-
-static inline void set_enum(PointerRNA &ptr, const char *name, const string &identifier)
-{
- RNA_enum_set_identifier(NULL, &ptr, name, identifier.c_str());
-}
-
-static inline string get_string(PointerRNA &ptr, const char *name)
-{
- char cstrbuf[1024];
- char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf), NULL);
- string str(cstr);
- if (cstr != cstrbuf)
- MEM_freeN(cstr);
-
- return str;
-}
-
-static inline void set_string(PointerRNA &ptr, const char *name, const string &value)
-{
- RNA_string_set(&ptr, name, value.c_str());
-}
-
-/* Relative Paths */
-
-static inline string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path)
-{
- if (path.size() >= 2 && path[0] == '/' && path[1] == '/') {
- string dirname;
-
- if (b_id.library()) {
- BL::ID b_library_id(b_id.library());
- dirname = blender_absolute_path(b_data, b_library_id, b_id.library().filepath());
- }
- else
- dirname = b_data.filepath();
-
- return path_join(path_dirname(dirname), path.substr(2));
- }
-
- return path;
-}
-
-static inline string get_text_datablock_content(const PointerRNA &ptr)
-{
- if (ptr.data == NULL) {
- return "";
- }
-
- string content;
- BL::Text::lines_iterator iter;
- for (iter.begin(ptr); iter; ++iter) {
- content += iter->body() + "\n";
- }
-
- return content;
-}
-
-/* Texture Space */
-
-static inline void mesh_texture_space(BL::Mesh &b_mesh, float3 &loc, float3 &size)
-{
- loc = get_float3(b_mesh.texspace_location());
- size = get_float3(b_mesh.texspace_size());
-
- if (size.x != 0.0f)
- size.x = 0.5f / size.x;
- if (size.y != 0.0f)
- size.y = 0.5f / size.y;
- if (size.z != 0.0f)
- size.z = 0.5f / size.z;
-
- loc = loc * size - make_float3(0.5f, 0.5f, 0.5f);
-}
-
-/* Object motion steps, returns 0 if no motion blur needed. */
-static inline uint object_motion_steps(BL::Object &b_parent,
- BL::Object &b_ob,
- const int max_steps = INT_MAX)
-{
- /* Get motion enabled and steps from object itself. */
- PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
- bool use_motion = get_boolean(cobject, "use_motion_blur");
- if (!use_motion) {
- return 0;
- }
-
- int steps = max(1, get_int(cobject, "motion_steps"));
-
- /* Also check parent object, so motion blur and steps can be
- * controlled by dupligroup duplicator for linked groups. */
- if (b_parent.ptr.data != b_ob.ptr.data) {
- PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
- use_motion &= get_boolean(parent_cobject, "use_motion_blur");
-
- if (!use_motion) {
- return 0;
- }
-
- steps = max(steps, get_int(parent_cobject, "motion_steps"));
- }
-
- /* Use uneven number of steps so we get one keyframe at the current frame,
- * and use 2^(steps - 1) so objects with more/fewer steps still have samples
- * at the same times, to avoid sampling at many different times. */
- return min((2 << (steps - 1)) + 1, max_steps);
-}
-
-/* object uses deformation motion blur */
-static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob)
-{
- PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
- bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
- /* If motion blur is enabled for the object we also check
- * whether it's enabled for the parent object as well.
- *
- * This way we can control motion blur from the dupligroup
- * duplicator much easier.
- */
- if (use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
- PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
- use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
- }
- return use_deform_motion;
-}
-
-static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
-{
- for (BL::Modifier &b_mod : b_ob.modifiers) {
- if (b_mod.is_a(&RNA_FluidModifier)) {
- BL::FluidModifier b_mmd(b_mod);
-
- if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
- b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_GAS) {
- return b_mmd.domain_settings();
- }
- }
- }
-
- return BL::FluidDomainSettings(PointerRNA_NULL);
-}
-
-static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob,
- bool *has_subdivision_modifier)
-{
- for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
- BL::Modifier b_mod = b_ob.modifiers[i];
-
- if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
- BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
- return mesh_cache;
- }
-
- /* Skip possible particles system modifiers as they do not modify the geometry. */
- if (b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) {
- continue;
- }
-
- if (b_mod.type() == BL::Modifier::type_SUBSURF) {
- if (has_subdivision_modifier) {
- *has_subdivision_modifier = true;
- }
- continue;
- }
-
- break;
- }
-
- return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
-}
-
-static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
- bool preview,
- bool experimental)
-{
- PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
-
- if (cobj.data && b_ob.modifiers.length() > 0 && experimental) {
- BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
- bool enabled = preview ? mod.show_viewport() : mod.show_render();
-
- if (enabled && mod.type() == BL::Modifier::type_SUBSURF &&
- RNA_boolean_get(&cobj, "use_adaptive_subdivision")) {
- BL::SubsurfModifier subsurf(mod);
-
- if (subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
- return Mesh::SUBDIVISION_CATMULL_CLARK;
- }
- else {
- return Mesh::SUBDIVISION_LINEAR;
- }
- }
- }
-
- return Mesh::SUBDIVISION_NONE;
-}
-
-static inline uint object_ray_visibility(BL::Object &b_ob)
-{
- uint flag = 0;
-
- flag |= b_ob.visible_camera() ? PATH_RAY_CAMERA : 0;
- flag |= b_ob.visible_diffuse() ? PATH_RAY_DIFFUSE : 0;
- flag |= b_ob.visible_glossy() ? PATH_RAY_GLOSSY : 0;
- flag |= b_ob.visible_transmission() ? PATH_RAY_TRANSMIT : 0;
- flag |= b_ob.visible_shadow() ? PATH_RAY_SHADOW : 0;
- flag |= b_ob.visible_volume_scatter() ? PATH_RAY_VOLUME_SCATTER : 0;
-
- return flag;
-}
-
-class EdgeMap {
- public:
- EdgeMap()
- {
- }
-
- void clear()
- {
- edges_.clear();
- }
-
- void insert(int v0, int v1)
- {
- get_sorted_verts(v0, v1);
- edges_.insert(std::pair<int, int>(v0, v1));
- }
-
- bool exists(int v0, int v1)
- {
- get_sorted_verts(v0, v1);
- return edges_.find(std::pair<int, int>(v0, v1)) != edges_.end();
- }
-
- protected:
- void get_sorted_verts(int &v0, int &v1)
- {
- if (v0 > v1) {
- swap(v0, v1);
- }
- }
-
- set<std::pair<int, int>> edges_;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BLENDER_UTIL_H__ */
diff --git a/intern/cycles/blender/blender_viewport.cpp b/intern/cycles/blender/blender_viewport.cpp
deleted file mode 100644
index 62e32240bba..00000000000
--- a/intern/cycles/blender/blender_viewport.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2019 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "blender_viewport.h"
-
-#include "blender_util.h"
-#include "render/pass.h"
-#include "util/util_logging.h"
-
-CCL_NAMESPACE_BEGIN
-
-BlenderViewportParameters::BlenderViewportParameters()
- : use_scene_world(true),
- use_scene_lights(true),
- studiolight_rotate_z(0.0f),
- studiolight_intensity(1.0f),
- studiolight_background_alpha(1.0f),
- display_pass(PASS_COMBINED),
- show_active_pixels(false)
-{
-}
-
-BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d, bool use_developer_ui)
- : BlenderViewportParameters()
-{
- if (!b_v3d) {
- return;
- }
-
- BL::View3DShading shading = b_v3d.shading();
- PointerRNA cshading = RNA_pointer_get(&shading.ptr, "cycles");
-
- /* We only copy the shading parameters if we are in look-dev mode.
- * Otherwise defaults are being used. These defaults mimic normal render settings. */
- if (shading.type() == BL::View3DShading::type_RENDERED) {
- use_scene_world = shading.use_scene_world_render();
- use_scene_lights = shading.use_scene_lights_render();
-
- if (!use_scene_world) {
- studiolight_rotate_z = shading.studiolight_rotate_z();
- studiolight_intensity = shading.studiolight_intensity();
- studiolight_background_alpha = shading.studiolight_background_alpha();
- studiolight_path = shading.selected_studio_light().path();
- }
- }
-
- /* Film. */
-
- /* Lookup display pass based on the enum identifier.
- * This is because integer values of python enum are not aligned with the passes definition in
- * the kernel. */
-
- display_pass = PASS_COMBINED;
-
- const string display_pass_identifier = get_enum_identifier(cshading, "render_pass");
- if (!display_pass_identifier.empty()) {
- const ustring pass_type_identifier(string_to_lower(display_pass_identifier));
- const NodeEnum *pass_type_enum = Pass::get_type_enum();
- if (pass_type_enum->exists(pass_type_identifier)) {
- display_pass = static_cast<PassType>((*pass_type_enum)[pass_type_identifier]);
- }
- }
-
- if (use_developer_ui) {
- show_active_pixels = get_boolean(cshading, "show_active_pixels");
- }
-}
-
-bool BlenderViewportParameters::shader_modified(const BlenderViewportParameters &other) const
-{
- return use_scene_world != other.use_scene_world || use_scene_lights != other.use_scene_lights ||
- studiolight_rotate_z != other.studiolight_rotate_z ||
- studiolight_intensity != other.studiolight_intensity ||
- studiolight_background_alpha != other.studiolight_background_alpha ||
- studiolight_path != other.studiolight_path;
-}
-
-bool BlenderViewportParameters::film_modified(const BlenderViewportParameters &other) const
-{
- return display_pass != other.display_pass || show_active_pixels != other.show_active_pixels;
-}
-
-bool BlenderViewportParameters::modified(const BlenderViewportParameters &other) const
-{
- return shader_modified(other) || film_modified(other);
-}
-
-bool BlenderViewportParameters::use_custom_shader() const
-{
- return !(use_scene_world && use_scene_lights);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_viewport.h b/intern/cycles/blender/blender_viewport.h
deleted file mode 100644
index b5adafc30c9..00000000000
--- a/intern/cycles/blender/blender_viewport.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2019 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BLENDER_VIEWPORT_H__
-#define __BLENDER_VIEWPORT_H__
-
-#include "MEM_guardedalloc.h"
-
-#include "RNA_access.h"
-#include "RNA_blender_cpp.h"
-#include "RNA_types.h"
-
-#include "render/film.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BlenderViewportParameters {
- public:
- /* Shader. */
- bool use_scene_world;
- bool use_scene_lights;
- float studiolight_rotate_z;
- float studiolight_intensity;
- float studiolight_background_alpha;
- ustring studiolight_path;
-
- /* Film. */
- PassType display_pass;
- bool show_active_pixels;
-
- BlenderViewportParameters();
- BlenderViewportParameters(BL::SpaceView3D &b_v3d, bool use_developer_ui);
-
- /* Check whether any of shading related settings are different from the given parameters. */
- bool shader_modified(const BlenderViewportParameters &other) const;
-
- /* Check whether any of film related settings are different from the given parameters. */
- bool film_modified(const BlenderViewportParameters &other) const;
-
- /* Check whether any of settings are different from the given parameters. */
- bool modified(const BlenderViewportParameters &other) const;
-
- /* Returns truth when a custom shader defined by the viewport is to be used instead of the
- * regular background shader or scene light. */
- bool use_custom_shader() const;
-};
-
-CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp
deleted file mode 100644
index 0a5b19d7d4c..00000000000
--- a/intern/cycles/blender/blender_volume.cpp
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/colorspace.h"
-#include "render/image.h"
-#include "render/image_vdb.h"
-#include "render/object.h"
-#include "render/volume.h"
-
-#include "blender/blender_sync.h"
-#include "blender/blender_util.h"
-
-#ifdef WITH_OPENVDB
-# include <openvdb/openvdb.h>
-openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const struct Volume *volume,
- const struct VolumeGrid *grid);
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/* TODO: verify this is not loading unnecessary attributes. */
-class BlenderSmokeLoader : public ImageLoader {
- public:
- BlenderSmokeLoader(BL::Object &b_ob, AttributeStandard attribute)
- : b_domain(object_fluid_gas_domain_find(b_ob)), attribute(attribute)
- {
- BL::Mesh b_mesh(b_ob.data());
- mesh_texture_space(b_mesh, texspace_loc, texspace_size);
- }
-
- bool load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) override
- {
- if (!b_domain) {
- return false;
- }
-
- if (attribute == ATTR_STD_VOLUME_DENSITY || attribute == ATTR_STD_VOLUME_FLAME ||
- attribute == ATTR_STD_VOLUME_HEAT || attribute == ATTR_STD_VOLUME_TEMPERATURE) {
- metadata.type = IMAGE_DATA_TYPE_FLOAT;
- metadata.channels = 1;
- }
- else if (attribute == ATTR_STD_VOLUME_COLOR) {
- metadata.type = IMAGE_DATA_TYPE_FLOAT4;
- metadata.channels = 4;
- }
- else if (attribute == ATTR_STD_VOLUME_VELOCITY) {
- metadata.type = IMAGE_DATA_TYPE_FLOAT4;
- metadata.channels = 3;
- }
- else {
- return false;
- }
-
- int3 resolution = get_int3(b_domain.domain_resolution());
- int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
-
- /* Velocity and heat data is always low-resolution. */
- if (attribute == ATTR_STD_VOLUME_VELOCITY || attribute == ATTR_STD_VOLUME_HEAT) {
- amplify = 1;
- }
-
- metadata.width = resolution.x * amplify;
- metadata.height = resolution.y * amplify;
- metadata.depth = resolution.z * amplify;
-
- /* Create a matrix to transform from object space to mesh texture space.
- * This does not work with deformations but that can probably only be done
- * well with a volume grid mapping of coordinates. */
- metadata.transform_3d = transform_translate(-texspace_loc) * transform_scale(texspace_size);
- metadata.use_transform_3d = true;
-
- return true;
- }
-
- bool load_pixels(const ImageMetaData &, void *pixels, const size_t, const bool) override
- {
- if (!b_domain) {
- return false;
- }
-#ifdef WITH_FLUID
- int3 resolution = get_int3(b_domain.domain_resolution());
- int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
-
- /* Velocity and heat data is always low-resolution. */
- if (attribute == ATTR_STD_VOLUME_VELOCITY || attribute == ATTR_STD_VOLUME_HEAT) {
- amplify = 1;
- }
-
- const int width = resolution.x * amplify;
- const int height = resolution.y * amplify;
- const int depth = resolution.z * amplify;
- const size_t num_pixels = ((size_t)width) * height * depth;
-
- float *fpixels = (float *)pixels;
-
- if (attribute == ATTR_STD_VOLUME_DENSITY) {
- FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels) {
- FluidDomainSettings_density_grid_get(&b_domain.ptr, fpixels);
- return true;
- }
- }
- else if (attribute == ATTR_STD_VOLUME_FLAME) {
- /* this is in range 0..1, and interpreted by the OpenGL smoke viewer
- * as 1500..3000 K with the first part faded to zero density */
- FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels) {
- FluidDomainSettings_flame_grid_get(&b_domain.ptr, fpixels);
- return true;
- }
- }
- else if (attribute == ATTR_STD_VOLUME_COLOR) {
- /* the RGB is "premultiplied" by density for better interpolation results */
- FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels * 4) {
- FluidDomainSettings_color_grid_get(&b_domain.ptr, fpixels);
- return true;
- }
- }
- else if (attribute == ATTR_STD_VOLUME_VELOCITY) {
- FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels * 3) {
- FluidDomainSettings_velocity_grid_get(&b_domain.ptr, fpixels);
- return true;
- }
- }
- else if (attribute == ATTR_STD_VOLUME_HEAT) {
- FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels) {
- FluidDomainSettings_heat_grid_get(&b_domain.ptr, fpixels);
- return true;
- }
- }
- else if (attribute == ATTR_STD_VOLUME_TEMPERATURE) {
- FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels) {
- FluidDomainSettings_temperature_grid_get(&b_domain.ptr, fpixels);
- return true;
- }
- }
- else {
- fprintf(stderr,
- "Cycles error: unknown volume attribute %s, skipping\n",
- Attribute::standard_name(attribute));
- fpixels[0] = 0.0f;
- return false;
- }
-#else
- (void)pixels;
-#endif
- fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
- return false;
- }
-
- string name() const override
- {
- return Attribute::standard_name(attribute);
- }
-
- bool equals(const ImageLoader &other) const override
- {
- const BlenderSmokeLoader &other_loader = (const BlenderSmokeLoader &)other;
- return b_domain == other_loader.b_domain && attribute == other_loader.attribute;
- }
-
- BL::FluidDomainSettings b_domain;
- float3 texspace_loc, texspace_size;
- AttributeStandard attribute;
-};
-
-static void sync_smoke_volume(Scene *scene, BObjectInfo &b_ob_info, Volume *volume, float frame)
-{
- if (!b_ob_info.is_real_object_data()) {
- return;
- }
- BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob_info.real_object);
- if (!b_domain) {
- return;
- }
-
- AttributeStandard attributes[] = {ATTR_STD_VOLUME_DENSITY,
- ATTR_STD_VOLUME_COLOR,
- ATTR_STD_VOLUME_FLAME,
- ATTR_STD_VOLUME_HEAT,
- ATTR_STD_VOLUME_TEMPERATURE,
- ATTR_STD_VOLUME_VELOCITY,
- ATTR_STD_NONE};
-
- for (int i = 0; attributes[i] != ATTR_STD_NONE; i++) {
- AttributeStandard std = attributes[i];
- if (!volume->need_attribute(scene, std)) {
- continue;
- }
-
- volume->set_clipping(b_domain.clipping());
-
- Attribute *attr = volume->attributes.add(std);
-
- ImageLoader *loader = new BlenderSmokeLoader(b_ob_info.real_object, std);
- ImageParams params;
- params.frame = frame;
-
- attr->data_voxel() = scene->image_manager->add_image(loader, params);
- }
-}
-
-class BlenderVolumeLoader : public VDBImageLoader {
- public:
- BlenderVolumeLoader(BL::BlendData &b_data, BL::Volume &b_volume, const string &grid_name)
- : VDBImageLoader(grid_name), b_volume(b_volume)
- {
- b_volume.grids.load(b_data.ptr.data);
-
-#ifdef WITH_OPENVDB
- for (BL::VolumeGrid &b_volume_grid : b_volume.grids) {
- if (b_volume_grid.name() == grid_name) {
- const bool unload = !b_volume_grid.is_loaded();
-
- ::Volume *volume = (::Volume *)b_volume.ptr.data;
- const VolumeGrid *volume_grid = (VolumeGrid *)b_volume_grid.ptr.data;
- grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
-
- if (unload) {
- b_volume_grid.unload();
- }
-
- break;
- }
- }
-#endif
- }
-
- BL::Volume b_volume;
-};
-
-static void sync_volume_object(BL::BlendData &b_data,
- BObjectInfo &b_ob_info,
- Scene *scene,
- Volume *volume)
-{
- BL::Volume b_volume(b_ob_info.object_data);
- b_volume.grids.load(b_data.ptr.data);
-
- BL::VolumeRender b_render(b_volume.render());
-
- volume->set_clipping(b_render.clipping());
- volume->set_step_size(b_render.step_size());
- volume->set_object_space((b_render.space() == BL::VolumeRender::space_OBJECT));
-
- /* Find grid with matching name. */
- for (BL::VolumeGrid &b_grid : b_volume.grids) {
- ustring name = ustring(b_grid.name());
- AttributeStandard std = ATTR_STD_NONE;
-
- if (name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
- std = ATTR_STD_VOLUME_DENSITY;
- }
- else if (name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
- std = ATTR_STD_VOLUME_COLOR;
- }
- else if (name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) {
- std = ATTR_STD_VOLUME_FLAME;
- }
- else if (name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
- std = ATTR_STD_VOLUME_HEAT;
- }
- else if (name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) {
- std = ATTR_STD_VOLUME_TEMPERATURE;
- }
- else if (name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) {
- std = ATTR_STD_VOLUME_VELOCITY;
- }
-
- if ((std != ATTR_STD_NONE && volume->need_attribute(scene, std)) ||
- volume->need_attribute(scene, name)) {
- Attribute *attr = (std != ATTR_STD_NONE) ?
- volume->attributes.add(std) :
- volume->attributes.add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL);
-
- ImageLoader *loader = new BlenderVolumeLoader(b_data, b_volume, name.string());
- ImageParams params;
- params.frame = b_volume.grids.frame();
-
- attr->data_voxel() = scene->image_manager->add_image(loader, params, false);
- }
- }
-}
-
-void BlenderSync::sync_volume(BObjectInfo &b_ob_info, Volume *volume)
-{
- volume->clear(true);
-
- if (view_layer.use_volumes) {
- if (b_ob_info.object_data.is_a(&RNA_Volume)) {
- /* Volume object. Create only attributes, bounding mesh will then
- * be automatically generated later. */
- sync_volume_object(b_data, b_ob_info, scene, volume);
- }
- else {
- /* Smoke domain. */
- sync_smoke_volume(scene, b_ob_info, volume, b_scene.frame_current());
- }
- }
-
- /* Tag update. */
- volume->tag_update(scene, true);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/camera.cpp b/intern/cycles/blender/camera.cpp
new file mode 100644
index 00000000000..f87ebe39d21
--- /dev/null
+++ b/intern/cycles/blender/camera.cpp
@@ -0,0 +1,965 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/camera.h"
+#include "scene/scene.h"
+
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "util/log.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Blender Camera Intermediate: we first convert both the offline and 3d view
+ * render camera to this, and from there convert to our native camera format. */
+
+struct BlenderCamera {
+ float nearclip;
+ float farclip;
+
+ CameraType type;
+ float ortho_scale;
+
+ float lens;
+ float shuttertime;
+ Camera::MotionPosition motion_position;
+ array<float> shutter_curve;
+
+ Camera::RollingShutterType rolling_shutter_type;
+ float rolling_shutter_duration;
+
+ float aperturesize;
+ uint apertureblades;
+ float aperturerotation;
+ float focaldistance;
+
+ float2 shift;
+ float2 offset;
+ float zoom;
+
+ float2 pixelaspect;
+
+ float aperture_ratio;
+
+ PanoramaType panorama_type;
+ float fisheye_fov;
+ float fisheye_lens;
+ float latitude_min;
+ float latitude_max;
+ float longitude_min;
+ float longitude_max;
+ bool use_spherical_stereo;
+ float interocular_distance;
+ float convergence_distance;
+ bool use_pole_merge;
+ float pole_merge_angle_from;
+ float pole_merge_angle_to;
+
+ enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
+ float sensor_width;
+ float sensor_height;
+
+ int full_width;
+ int full_height;
+
+ int render_width;
+ int render_height;
+
+ BoundBox2D border;
+ BoundBox2D viewport_camera_border;
+ BoundBox2D pano_viewplane;
+ float pano_aspectratio;
+
+ float passepartout_alpha;
+
+ Transform matrix;
+
+ float offscreen_dicing_scale;
+
+ int motion_steps;
+};
+
+static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings &b_render)
+{
+ memset((void *)bcam, 0, sizeof(BlenderCamera));
+
+ bcam->nearclip = 1e-5f;
+ bcam->farclip = 1e5f;
+
+ bcam->type = CAMERA_PERSPECTIVE;
+ bcam->ortho_scale = 1.0f;
+
+ bcam->lens = 50.0f;
+ bcam->shuttertime = 1.0f;
+
+ bcam->rolling_shutter_type = Camera::ROLLING_SHUTTER_NONE;
+ bcam->rolling_shutter_duration = 0.1f;
+
+ bcam->aperturesize = 0.0f;
+ bcam->apertureblades = 0;
+ bcam->aperturerotation = 0.0f;
+ bcam->focaldistance = 10.0f;
+
+ bcam->zoom = 1.0f;
+ bcam->pixelaspect = one_float2();
+ bcam->aperture_ratio = 1.0f;
+
+ bcam->sensor_width = 36.0f;
+ bcam->sensor_height = 24.0f;
+ bcam->sensor_fit = BlenderCamera::AUTO;
+ bcam->motion_position = Camera::MOTION_POSITION_CENTER;
+ bcam->border.right = 1.0f;
+ bcam->border.top = 1.0f;
+ bcam->viewport_camera_border.right = 1.0f;
+ bcam->viewport_camera_border.top = 1.0f;
+ bcam->pano_viewplane.right = 1.0f;
+ bcam->pano_viewplane.top = 1.0f;
+ bcam->pano_aspectratio = 0.0f;
+ bcam->passepartout_alpha = 0.5f;
+ bcam->offscreen_dicing_scale = 1.0f;
+ bcam->matrix = transform_identity();
+
+ /* render resolution */
+ bcam->render_width = render_resolution_x(b_render);
+ bcam->render_height = render_resolution_y(b_render);
+ bcam->full_width = bcam->render_width;
+ bcam->full_height = bcam->render_height;
+}
+
+static float blender_camera_focal_distance(BL::RenderEngine &b_engine,
+ BL::Object &b_ob,
+ BL::Camera &b_camera,
+ BlenderCamera *bcam)
+{
+ BL::Object b_dof_object = b_camera.dof().focus_object();
+
+ if (!b_dof_object)
+ return b_camera.dof().focus_distance();
+
+ /* for dof object, return distance along camera Z direction */
+ BL::Array<float, 16> b_ob_matrix;
+ b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix);
+ Transform obmat = transform_clear_scale(get_transform(b_ob_matrix));
+ Transform dofmat = get_transform(b_dof_object.matrix_world());
+ float3 view_dir = normalize(transform_get_column(&obmat, 2));
+ float3 dof_dir = transform_get_column(&obmat, 3) - transform_get_column(&dofmat, 3);
+ return fabsf(dot(view_dir, dof_dir));
+}
+
+static void blender_camera_from_object(BlenderCamera *bcam,
+ BL::RenderEngine &b_engine,
+ BL::Object &b_ob,
+ bool skip_panorama = false)
+{
+ BL::ID b_ob_data = b_ob.data();
+
+ if (b_ob_data.is_a(&RNA_Camera)) {
+ BL::Camera b_camera(b_ob_data);
+ PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
+
+ bcam->nearclip = b_camera.clip_start();
+ bcam->farclip = b_camera.clip_end();
+
+ switch (b_camera.type()) {
+ case BL::Camera::type_ORTHO:
+ bcam->type = CAMERA_ORTHOGRAPHIC;
+ break;
+ case BL::Camera::type_PANO:
+ if (!skip_panorama)
+ bcam->type = CAMERA_PANORAMA;
+ else
+ bcam->type = CAMERA_PERSPECTIVE;
+ break;
+ case BL::Camera::type_PERSP:
+ default:
+ bcam->type = CAMERA_PERSPECTIVE;
+ break;
+ }
+
+ bcam->panorama_type = (PanoramaType)get_enum(
+ ccamera, "panorama_type", PANORAMA_NUM_TYPES, PANORAMA_EQUIRECTANGULAR);
+
+ bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov");
+ bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens");
+ bcam->latitude_min = RNA_float_get(&ccamera, "latitude_min");
+ bcam->latitude_max = RNA_float_get(&ccamera, "latitude_max");
+ bcam->longitude_min = RNA_float_get(&ccamera, "longitude_min");
+ bcam->longitude_max = RNA_float_get(&ccamera, "longitude_max");
+
+ bcam->interocular_distance = b_camera.stereo().interocular_distance();
+ if (b_camera.stereo().convergence_mode() == BL::CameraStereoData::convergence_mode_PARALLEL) {
+ bcam->convergence_distance = FLT_MAX;
+ }
+ else {
+ bcam->convergence_distance = b_camera.stereo().convergence_distance();
+ }
+ bcam->use_spherical_stereo = b_engine.use_spherical_stereo(b_ob);
+
+ bcam->use_pole_merge = b_camera.stereo().use_pole_merge();
+ bcam->pole_merge_angle_from = b_camera.stereo().pole_merge_angle_from();
+ bcam->pole_merge_angle_to = b_camera.stereo().pole_merge_angle_to();
+
+ bcam->ortho_scale = b_camera.ortho_scale();
+
+ bcam->lens = b_camera.lens();
+
+ bcam->passepartout_alpha = b_camera.show_passepartout() ? b_camera.passepartout_alpha() : 0.0f;
+
+ if (b_camera.dof().use_dof()) {
+ /* allow f/stop number to change aperture_size but still
+ * give manual control over aperture radius */
+ float fstop = b_camera.dof().aperture_fstop();
+ fstop = max(fstop, 1e-5f);
+
+ if (bcam->type == CAMERA_ORTHOGRAPHIC)
+ bcam->aperturesize = 1.0f / (2.0f * fstop);
+ else
+ bcam->aperturesize = (bcam->lens * 1e-3f) / (2.0f * fstop);
+
+ bcam->apertureblades = b_camera.dof().aperture_blades();
+ bcam->aperturerotation = b_camera.dof().aperture_rotation();
+ bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam);
+ bcam->aperture_ratio = b_camera.dof().aperture_ratio();
+ }
+ else {
+ /* DOF is turned of for the camera. */
+ bcam->aperturesize = 0.0f;
+ bcam->apertureblades = 0;
+ bcam->aperturerotation = 0.0f;
+ bcam->focaldistance = 0.0f;
+ bcam->aperture_ratio = 1.0f;
+ }
+
+ bcam->shift.x = b_engine.camera_shift_x(b_ob, bcam->use_spherical_stereo);
+ bcam->shift.y = b_camera.shift_y();
+
+ bcam->sensor_width = b_camera.sensor_width();
+ bcam->sensor_height = b_camera.sensor_height();
+
+ if (b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO)
+ bcam->sensor_fit = BlenderCamera::AUTO;
+ else if (b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL)
+ bcam->sensor_fit = BlenderCamera::HORIZONTAL;
+ else
+ bcam->sensor_fit = BlenderCamera::VERTICAL;
+ }
+ else if (b_ob_data.is_a(&RNA_Light)) {
+ /* Can also look through spot light. */
+ BL::SpotLight b_light(b_ob_data);
+ float lens = 16.0f / tanf(b_light.spot_size() * 0.5f);
+ if (lens > 0.0f) {
+ bcam->lens = lens;
+ }
+ }
+
+ bcam->motion_steps = object_motion_steps(b_ob, b_ob);
+}
+
+static Transform blender_camera_matrix(const Transform &tfm,
+ const CameraType type,
+ const PanoramaType panorama_type)
+{
+ Transform result;
+
+ if (type == CAMERA_PANORAMA) {
+ if (panorama_type == PANORAMA_MIRRORBALL) {
+ /* Mirror ball camera is looking into the negative Y direction
+ * which matches texture mirror ball mapping.
+ */
+ result = tfm * make_transform(
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
+ }
+ else {
+ /* Make it so environment camera needs to be pointed in the direction
+ * of the positive x-axis to match an environment texture, this way
+ * it is looking at the center of the texture
+ */
+ result = tfm * make_transform(
+ 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+ else {
+ /* note the blender camera points along the negative z-axis */
+ result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
+ }
+
+ return transform_clear_scale(result);
+}
+
+static void blender_camera_viewplane(BlenderCamera *bcam,
+ int width,
+ int height,
+ BoundBox2D *viewplane,
+ float *aspectratio,
+ float *sensor_size)
+{
+ /* dimensions */
+ float xratio = (float)width * bcam->pixelaspect.x;
+ float yratio = (float)height * bcam->pixelaspect.y;
+
+ /* compute x/y aspect and ratio */
+ float xaspect, yaspect;
+ bool horizontal_fit;
+
+ /* sensor fitting */
+ if (bcam->sensor_fit == BlenderCamera::AUTO) {
+ horizontal_fit = (xratio > yratio);
+ if (sensor_size != NULL) {
+ *sensor_size = bcam->sensor_width;
+ }
+ }
+ else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
+ horizontal_fit = true;
+ if (sensor_size != NULL) {
+ *sensor_size = bcam->sensor_width;
+ }
+ }
+ else {
+ horizontal_fit = false;
+ if (sensor_size != NULL) {
+ *sensor_size = bcam->sensor_height;
+ }
+ }
+
+ if (horizontal_fit) {
+ if (aspectratio != NULL) {
+ *aspectratio = xratio / yratio;
+ }
+ xaspect = *aspectratio;
+ yaspect = 1.0f;
+ }
+ else {
+ if (aspectratio != NULL) {
+ *aspectratio = yratio / xratio;
+ }
+ xaspect = 1.0f;
+ yaspect = *aspectratio;
+ }
+
+ /* modify aspect for orthographic scale */
+ if (bcam->type == CAMERA_ORTHOGRAPHIC) {
+ xaspect = xaspect * bcam->ortho_scale / (*aspectratio * 2.0f);
+ yaspect = yaspect * bcam->ortho_scale / (*aspectratio * 2.0f);
+ if (aspectratio != NULL) {
+ *aspectratio = bcam->ortho_scale / 2.0f;
+ }
+ }
+
+ if (bcam->type == CAMERA_PANORAMA) {
+ /* Set viewplane for panoramic camera. */
+ if (viewplane != NULL) {
+ *viewplane = bcam->pano_viewplane;
+
+ /* Modify viewplane for camera shift. */
+ const float shift_factor = (bcam->pano_aspectratio == 0.0f) ?
+ 1.0f :
+ *aspectratio / bcam->pano_aspectratio;
+ const float dx = bcam->shift.x * shift_factor;
+ const float dy = bcam->shift.y * shift_factor;
+
+ viewplane->left += dx;
+ viewplane->right += dx;
+ viewplane->bottom += dy;
+ viewplane->top += dy;
+ }
+ }
+ else {
+ /* set viewplane */
+ if (viewplane != NULL) {
+ viewplane->left = -xaspect;
+ viewplane->right = xaspect;
+ viewplane->bottom = -yaspect;
+ viewplane->top = yaspect;
+
+ /* zoom for 3d camera view */
+ *viewplane = (*viewplane) * bcam->zoom;
+
+ /* modify viewplane with camera shift and 3d camera view offset */
+ const float dx = 2.0f * (*aspectratio * bcam->shift.x + bcam->offset.x * xaspect * 2.0f);
+ const float dy = 2.0f * (*aspectratio * bcam->shift.y + bcam->offset.y * yaspect * 2.0f);
+
+ viewplane->left += dx;
+ viewplane->right += dx;
+ viewplane->bottom += dy;
+ viewplane->top += dy;
+ }
+ }
+}
+
+static void blender_camera_sync(Camera *cam,
+ BlenderCamera *bcam,
+ int width,
+ int height,
+ const char *viewname,
+ PointerRNA *cscene)
+{
+ float aspectratio, sensor_size;
+
+ /* viewplane */
+ BoundBox2D viewplane;
+ blender_camera_viewplane(bcam, width, height, &viewplane, &aspectratio, &sensor_size);
+
+ cam->set_viewplane_left(viewplane.left);
+ cam->set_viewplane_right(viewplane.right);
+ cam->set_viewplane_top(viewplane.top);
+ cam->set_viewplane_bottom(viewplane.bottom);
+
+ cam->set_full_width(width);
+ cam->set_full_height(height);
+
+ /* panorama sensor */
+ if (bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) {
+ float fit_xratio = (float)bcam->render_width * bcam->pixelaspect.x;
+ float fit_yratio = (float)bcam->render_height * bcam->pixelaspect.y;
+ bool horizontal_fit;
+ float sensor_size;
+
+ if (bcam->sensor_fit == BlenderCamera::AUTO) {
+ horizontal_fit = (fit_xratio > fit_yratio);
+ sensor_size = bcam->sensor_width;
+ }
+ else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
+ horizontal_fit = true;
+ sensor_size = bcam->sensor_width;
+ }
+ else { /* vertical */
+ horizontal_fit = false;
+ sensor_size = bcam->sensor_height;
+ }
+
+ if (horizontal_fit) {
+ cam->set_sensorwidth(sensor_size);
+ cam->set_sensorheight(sensor_size * fit_yratio / fit_xratio);
+ }
+ else {
+ cam->set_sensorwidth(sensor_size * fit_xratio / fit_yratio);
+ cam->set_sensorheight(sensor_size);
+ }
+ }
+
+ /* clipping distances */
+ cam->set_nearclip(bcam->nearclip);
+ cam->set_farclip(bcam->farclip);
+
+ /* type */
+ cam->set_camera_type(bcam->type);
+
+ /* panorama */
+ cam->set_panorama_type(bcam->panorama_type);
+ cam->set_fisheye_fov(bcam->fisheye_fov);
+ cam->set_fisheye_lens(bcam->fisheye_lens);
+ cam->set_latitude_min(bcam->latitude_min);
+ cam->set_latitude_max(bcam->latitude_max);
+
+ cam->set_longitude_min(bcam->longitude_min);
+ cam->set_longitude_max(bcam->longitude_max);
+
+ /* panorama stereo */
+ cam->set_interocular_distance(bcam->interocular_distance);
+ cam->set_convergence_distance(bcam->convergence_distance);
+ cam->set_use_spherical_stereo(bcam->use_spherical_stereo);
+
+ if (cam->get_use_spherical_stereo()) {
+ if (strcmp(viewname, "left") == 0)
+ cam->set_stereo_eye(Camera::STEREO_LEFT);
+ else if (strcmp(viewname, "right") == 0)
+ cam->set_stereo_eye(Camera::STEREO_RIGHT);
+ else
+ cam->set_stereo_eye(Camera::STEREO_NONE);
+ }
+
+ cam->set_use_pole_merge(bcam->use_pole_merge);
+ cam->set_pole_merge_angle_from(bcam->pole_merge_angle_from);
+ cam->set_pole_merge_angle_to(bcam->pole_merge_angle_to);
+
+ /* anamorphic lens bokeh */
+ cam->set_aperture_ratio(bcam->aperture_ratio);
+
+ /* perspective */
+ cam->set_fov(2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio));
+ cam->set_focaldistance(bcam->focaldistance);
+ cam->set_aperturesize(bcam->aperturesize);
+ cam->set_blades(bcam->apertureblades);
+ cam->set_bladesrotation(bcam->aperturerotation);
+
+ /* transform */
+ cam->set_matrix(blender_camera_matrix(bcam->matrix, bcam->type, bcam->panorama_type));
+
+ array<Transform> motion;
+ motion.resize(bcam->motion_steps, cam->get_matrix());
+ cam->set_motion(motion);
+ cam->set_use_perspective_motion(false);
+
+ cam->set_shuttertime(bcam->shuttertime);
+ cam->set_fov_pre(cam->get_fov());
+ cam->set_fov_post(cam->get_fov());
+ cam->set_motion_position(bcam->motion_position);
+
+ cam->set_rolling_shutter_type(bcam->rolling_shutter_type);
+ cam->set_rolling_shutter_duration(bcam->rolling_shutter_duration);
+
+ cam->set_shutter_curve(bcam->shutter_curve);
+
+ /* border */
+ cam->set_border_left(bcam->border.left);
+ cam->set_border_right(bcam->border.right);
+ cam->set_border_top(bcam->border.top);
+ cam->set_border_bottom(bcam->border.bottom);
+
+ cam->set_viewport_camera_border_left(bcam->viewport_camera_border.left);
+ cam->set_viewport_camera_border_right(bcam->viewport_camera_border.right);
+ cam->set_viewport_camera_border_top(bcam->viewport_camera_border.top);
+ cam->set_viewport_camera_border_bottom(bcam->viewport_camera_border.bottom);
+
+ bcam->offscreen_dicing_scale = RNA_float_get(cscene, "offscreen_dicing_scale");
+ cam->set_offscreen_dicing_scale(bcam->offscreen_dicing_scale);
+}
+
+/* Sync Render Camera */
+
+void BlenderSync::sync_camera(BL::RenderSettings &b_render,
+ BL::Object &b_override,
+ int width,
+ int height,
+ const char *viewname)
+{
+ BlenderCamera bcam;
+ blender_camera_init(&bcam, b_render);
+
+ /* pixel aspect */
+ bcam.pixelaspect.x = b_render.pixel_aspect_x();
+ bcam.pixelaspect.y = b_render.pixel_aspect_y();
+ bcam.shuttertime = b_render.motion_blur_shutter();
+
+ BL::CurveMapping b_shutter_curve(b_render.motion_blur_shutter_curve());
+ curvemapping_to_array(b_shutter_curve, bcam.shutter_curve, RAMP_TABLE_SIZE);
+
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ bcam.motion_position = (Camera::MotionPosition)get_enum(cscene,
+ "motion_blur_position",
+ Camera::MOTION_NUM_POSITIONS,
+ Camera::MOTION_POSITION_CENTER);
+ bcam.rolling_shutter_type = (Camera::RollingShutterType)get_enum(
+ cscene,
+ "rolling_shutter_type",
+ Camera::ROLLING_SHUTTER_NUM_TYPES,
+ Camera::ROLLING_SHUTTER_NONE);
+ bcam.rolling_shutter_duration = RNA_float_get(&cscene, "rolling_shutter_duration");
+
+ /* border */
+ if (b_render.use_border()) {
+ bcam.border.left = b_render.border_min_x();
+ bcam.border.right = b_render.border_max_x();
+ bcam.border.bottom = b_render.border_min_y();
+ bcam.border.top = b_render.border_max_y();
+ }
+
+ /* camera object */
+ BL::Object b_ob = b_scene.camera();
+
+ if (b_override)
+ b_ob = b_override;
+
+ if (b_ob) {
+ BL::Array<float, 16> b_ob_matrix;
+ blender_camera_from_object(&bcam, b_engine, b_ob);
+ b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
+ bcam.matrix = get_transform(b_ob_matrix);
+ }
+
+ /* sync */
+ Camera *cam = scene->camera;
+ blender_camera_sync(cam, &bcam, width, height, viewname, &cscene);
+
+ /* dicing camera */
+ b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
+ if (b_ob) {
+ BL::Array<float, 16> b_ob_matrix;
+ blender_camera_from_object(&bcam, b_engine, b_ob);
+ b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
+ bcam.matrix = get_transform(b_ob_matrix);
+
+ blender_camera_sync(scene->dicing_camera, &bcam, width, height, viewname, &cscene);
+ }
+ else {
+ *scene->dicing_camera = *cam;
+ }
+}
+
+void BlenderSync::sync_camera_motion(
+ BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time)
+{
+ if (!b_ob)
+ return;
+
+ Camera *cam = scene->camera;
+ BL::Array<float, 16> b_ob_matrix;
+ b_engine.camera_model_matrix(b_ob, cam->get_use_spherical_stereo(), b_ob_matrix);
+ Transform tfm = get_transform(b_ob_matrix);
+ tfm = blender_camera_matrix(tfm, cam->get_camera_type(), cam->get_panorama_type());
+
+ if (motion_time == 0.0f) {
+ /* When motion blur is not centered in frame, cam->matrix gets reset. */
+ cam->set_matrix(tfm);
+ }
+
+ /* Set transform in motion array. */
+ int motion_step = cam->motion_step(motion_time);
+ if (motion_step >= 0) {
+ array<Transform> motion = cam->get_motion();
+ motion[motion_step] = tfm;
+ cam->set_motion(motion);
+ }
+
+ if (cam->get_camera_type() == CAMERA_PERSPECTIVE) {
+ BlenderCamera bcam;
+ float aspectratio, sensor_size;
+ blender_camera_init(&bcam, b_render);
+
+ /* TODO(sergey): Consider making it a part of blender_camera_init(). */
+ bcam.pixelaspect.x = b_render.pixel_aspect_x();
+ bcam.pixelaspect.y = b_render.pixel_aspect_y();
+
+ blender_camera_from_object(&bcam, b_engine, b_ob);
+ blender_camera_viewplane(&bcam, width, height, NULL, &aspectratio, &sensor_size);
+ /* TODO(sergey): De-duplicate calculation with camera sync. */
+ float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio);
+ if (fov != cam->get_fov()) {
+ VLOG(1) << "Camera " << b_ob.name() << " FOV change detected.";
+ if (motion_time == 0.0f) {
+ cam->set_fov(fov);
+ }
+ else if (motion_time == -1.0f) {
+ cam->set_fov_pre(fov);
+ cam->set_use_perspective_motion(true);
+ }
+ else if (motion_time == 1.0f) {
+ cam->set_fov_post(fov);
+ cam->set_use_perspective_motion(true);
+ }
+ }
+ }
+}
+
+/* Sync 3D View Camera */
+
+static void blender_camera_view_subset(BL::RenderEngine &b_engine,
+ BL::RenderSettings &b_render,
+ BL::Scene &b_scene,
+ BL::Object &b_ob,
+ BL::SpaceView3D &b_v3d,
+ BL::RegionView3D &b_rv3d,
+ int width,
+ int height,
+ BoundBox2D *view_box,
+ BoundBox2D *cam_box,
+ float *view_aspect);
+
+static void blender_camera_from_view(BlenderCamera *bcam,
+ BL::RenderEngine &b_engine,
+ BL::Scene &b_scene,
+ BL::SpaceView3D &b_v3d,
+ BL::RegionView3D &b_rv3d,
+ int width,
+ int height,
+ bool skip_panorama = false)
+{
+ /* 3d view parameters */
+ bcam->nearclip = b_v3d.clip_start();
+ bcam->farclip = b_v3d.clip_end();
+ bcam->lens = b_v3d.lens();
+ bcam->shuttertime = b_scene.render().motion_blur_shutter();
+
+ BL::CurveMapping b_shutter_curve(b_scene.render().motion_blur_shutter_curve());
+ curvemapping_to_array(b_shutter_curve, bcam->shutter_curve, RAMP_TABLE_SIZE);
+
+ if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
+ /* camera view */
+ BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera();
+
+ if (b_ob) {
+ blender_camera_from_object(bcam, b_engine, b_ob, skip_panorama);
+
+ if (!skip_panorama && bcam->type == CAMERA_PANORAMA) {
+ /* in panorama camera view, we map viewplane to camera border */
+ BoundBox2D view_box, cam_box;
+ float view_aspect;
+
+ BL::RenderSettings b_render_settings(b_scene.render());
+ blender_camera_view_subset(b_engine,
+ b_render_settings,
+ b_scene,
+ b_ob,
+ b_v3d,
+ b_rv3d,
+ width,
+ height,
+ &view_box,
+ &cam_box,
+ &view_aspect);
+
+ bcam->pano_viewplane = view_box.make_relative_to(cam_box);
+ bcam->pano_aspectratio = view_aspect;
+ }
+ else {
+ /* magic zoom formula */
+ bcam->zoom = (float)b_rv3d.view_camera_zoom();
+ bcam->zoom = (1.41421f + bcam->zoom / 50.0f);
+ bcam->zoom *= bcam->zoom;
+ bcam->zoom = 2.0f / bcam->zoom;
+
+ /* offset */
+ bcam->offset = get_float2(b_rv3d.view_camera_offset());
+ }
+ }
+ }
+ else if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
+ /* orthographic view */
+ bcam->farclip *= 0.5f;
+ bcam->nearclip = -bcam->farclip;
+
+ float sensor_size;
+ if (bcam->sensor_fit == BlenderCamera::VERTICAL)
+ sensor_size = bcam->sensor_height;
+ else
+ sensor_size = bcam->sensor_width;
+
+ bcam->type = CAMERA_ORTHOGRAPHIC;
+ bcam->ortho_scale = b_rv3d.view_distance() * sensor_size / b_v3d.lens();
+ }
+
+ bcam->zoom *= 2.0f;
+
+ /* 3d view transform */
+ bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
+
+ /* dimensions */
+ bcam->full_width = width;
+ bcam->full_height = height;
+}
+
+static void blender_camera_view_subset(BL::RenderEngine &b_engine,
+ BL::RenderSettings &b_render,
+ BL::Scene &b_scene,
+ BL::Object &b_ob,
+ BL::SpaceView3D &b_v3d,
+ BL::RegionView3D &b_rv3d,
+ int width,
+ int height,
+ BoundBox2D *view_box,
+ BoundBox2D *cam_box,
+ float *view_aspect)
+{
+ BoundBox2D cam, view;
+ float cam_aspect, sensor_size;
+
+ /* Get viewport viewplane. */
+ BlenderCamera view_bcam;
+ blender_camera_init(&view_bcam, b_render);
+ blender_camera_from_view(&view_bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height, true);
+
+ blender_camera_viewplane(&view_bcam, width, height, &view, view_aspect, &sensor_size);
+
+ /* Get camera viewplane. */
+ BlenderCamera cam_bcam;
+ blender_camera_init(&cam_bcam, b_render);
+ blender_camera_from_object(&cam_bcam, b_engine, b_ob, true);
+
+ /* Camera border is affect by aspect, viewport is not. */
+ cam_bcam.pixelaspect.x = b_render.pixel_aspect_x();
+ cam_bcam.pixelaspect.y = b_render.pixel_aspect_y();
+
+ blender_camera_viewplane(
+ &cam_bcam, cam_bcam.full_width, cam_bcam.full_height, &cam, &cam_aspect, &sensor_size);
+
+ /* Return */
+ *view_box = view * (1.0f / *view_aspect);
+ *cam_box = cam * (1.0f / cam_aspect);
+}
+
+static void blender_camera_border_subset(BL::RenderEngine &b_engine,
+ BL::RenderSettings &b_render,
+ BL::Scene &b_scene,
+ BL::SpaceView3D &b_v3d,
+ BL::RegionView3D &b_rv3d,
+ BL::Object &b_ob,
+ int width,
+ int height,
+ const BoundBox2D &border,
+ BoundBox2D *result)
+{
+ /* Determine camera viewport subset. */
+ BoundBox2D view_box, cam_box;
+ float view_aspect;
+ blender_camera_view_subset(b_engine,
+ b_render,
+ b_scene,
+ b_ob,
+ b_v3d,
+ b_rv3d,
+ width,
+ height,
+ &view_box,
+ &cam_box,
+ &view_aspect);
+
+ /* Determine viewport subset matching given border. */
+ cam_box = cam_box.make_relative_to(view_box);
+ *result = cam_box.subset(border);
+}
+
+static void blender_camera_border(BlenderCamera *bcam,
+ BL::RenderEngine &b_engine,
+ BL::RenderSettings &b_render,
+ BL::Scene &b_scene,
+ BL::SpaceView3D &b_v3d,
+ BL::RegionView3D &b_rv3d,
+ int width,
+ int height)
+{
+ bool is_camera_view;
+
+ /* camera view? */
+ is_camera_view = b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA;
+
+ if (!is_camera_view) {
+ /* for non-camera view check whether render border is enabled for viewport
+ * and if so use border from 3d viewport
+ * assume viewport has got correctly clamped border already
+ */
+ if (b_v3d.use_render_border()) {
+ bcam->border.left = b_v3d.render_border_min_x();
+ bcam->border.right = b_v3d.render_border_max_x();
+ bcam->border.bottom = b_v3d.render_border_min_y();
+ bcam->border.top = b_v3d.render_border_max_y();
+ }
+ return;
+ }
+
+ BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera();
+
+ if (!b_ob)
+ return;
+
+ /* Determine camera border inside the viewport. */
+ BoundBox2D full_border;
+ blender_camera_border_subset(b_engine,
+ b_render,
+ b_scene,
+ b_v3d,
+ b_rv3d,
+ b_ob,
+ width,
+ height,
+ full_border,
+ &bcam->viewport_camera_border);
+
+ if (b_render.use_border()) {
+ bcam->border.left = b_render.border_min_x();
+ bcam->border.right = b_render.border_max_x();
+ bcam->border.bottom = b_render.border_min_y();
+ bcam->border.top = b_render.border_max_y();
+ }
+ else if (bcam->passepartout_alpha == 1.0f) {
+ bcam->border = full_border;
+ }
+ else {
+ return;
+ }
+
+ /* Determine viewport subset matching camera border. */
+ blender_camera_border_subset(b_engine,
+ b_render,
+ b_scene,
+ b_v3d,
+ b_rv3d,
+ b_ob,
+ width,
+ height,
+ bcam->border,
+ &bcam->border);
+ bcam->border = bcam->border.clamp();
+}
+
+void BlenderSync::sync_view(BL::SpaceView3D &b_v3d,
+ BL::RegionView3D &b_rv3d,
+ int width,
+ int height)
+{
+ BlenderCamera bcam;
+ BL::RenderSettings b_render_settings(b_scene.render());
+ blender_camera_init(&bcam, b_render_settings);
+ blender_camera_from_view(&bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height);
+ blender_camera_border(&bcam, b_engine, b_render_settings, b_scene, b_v3d, b_rv3d, width, height);
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ blender_camera_sync(scene->camera, &bcam, width, height, "", &cscene);
+
+ /* dicing camera */
+ BL::Object b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
+ if (b_ob) {
+ BL::Array<float, 16> b_ob_matrix;
+ blender_camera_from_object(&bcam, b_engine, b_ob);
+ b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
+ bcam.matrix = get_transform(b_ob_matrix);
+
+ blender_camera_sync(scene->dicing_camera, &bcam, width, height, "", &cscene);
+ }
+ else {
+ *scene->dicing_camera = *scene->camera;
+ }
+}
+
+BufferParams BlenderSync::get_buffer_params(
+ BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height)
+{
+ BufferParams params;
+ bool use_border = false;
+
+ params.full_width = width;
+ params.full_height = height;
+
+ if (b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA)
+ use_border = b_v3d.use_render_border();
+ else
+ /* the camera can always have a passepartout */
+ use_border = true;
+
+ if (use_border) {
+ /* border render */
+ /* the viewport may offset the border outside the view */
+ BoundBox2D border = cam->border.clamp();
+ params.full_x = (int)(border.left * (float)width);
+ params.full_y = (int)(border.bottom * (float)height);
+ params.width = (int)(border.right * (float)width) - params.full_x;
+ params.height = (int)(border.top * (float)height) - params.full_y;
+
+ /* survive in case border goes out of view or becomes too small */
+ params.width = max(params.width, 1);
+ params.height = max(params.height, 1);
+ }
+ else {
+ params.width = width;
+ params.height = height;
+ }
+
+ params.window_width = params.width;
+ params.window_height = params.height;
+
+ return params;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/curves.cpp b/intern/cycles/blender/curves.cpp
new file mode 100644
index 00000000000..fb2b329e61d
--- /dev/null
+++ b/intern/cycles/blender/curves.cpp
@@ -0,0 +1,915 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "scene/attribute.h"
+#include "scene/camera.h"
+#include "scene/curves.h"
+#include "scene/hair.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+
+#include "util/color.h"
+#include "util/foreach.h"
+#include "util/hash.h"
+#include "util/log.h"
+
+CCL_NAMESPACE_BEGIN
+
+ParticleCurveData::ParticleCurveData()
+{
+}
+
+ParticleCurveData::~ParticleCurveData()
+{
+}
+
+static float shaperadius(float shape, float root, float tip, float time)
+{
+ assert(time >= 0.0f);
+ assert(time <= 1.0f);
+ float radius = 1.0f - time;
+
+ if (shape != 0.0f) {
+ if (shape < 0.0f)
+ radius = powf(radius, 1.0f + shape);
+ else
+ radius = powf(radius, 1.0f / (1.0f - shape));
+ }
+ return (radius * (root - tip)) + tip;
+}
+
+/* curve functions */
+
+static bool ObtainCacheParticleData(
+ Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
+{
+ int curvenum = 0;
+ int keyno = 0;
+
+ if (!(hair && b_mesh && b_ob && CData))
+ return false;
+
+ Transform tfm = get_transform(b_ob->matrix_world());
+ Transform itfm = transform_quick_inverse(tfm);
+
+ for (BL::Modifier &b_mod : b_ob->modifiers) {
+ if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
+ (background ? b_mod.show_render() : b_mod.show_viewport())) {
+ BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
+ BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+
+ if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
+ (b_part.type() == BL::ParticleSettings::type_HAIR)) {
+ int shader = clamp(b_part.material() - 1, 0, hair->get_used_shaders().size() - 1);
+ int display_step = background ? b_part.render_step() : b_part.display_step();
+ int totparts = b_psys.particles.length();
+ int totchild = background ? b_psys.child_particles.length() :
+ (int)((float)b_psys.child_particles.length() *
+ (float)b_part.display_percentage() / 100.0f);
+ int totcurves = totchild;
+
+ if (b_part.child_type() == 0 || totchild == 0)
+ totcurves += totparts;
+
+ if (totcurves == 0)
+ continue;
+
+ int ren_step = (1 << display_step) + 1;
+ if (b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
+ ren_step += b_part.kink_extra_steps();
+
+ CData->psys_firstcurve.push_back_slow(curvenum);
+ CData->psys_curvenum.push_back_slow(totcurves);
+ CData->psys_shader.push_back_slow(shader);
+
+ float radius = b_part.radius_scale() * 0.5f;
+
+ CData->psys_rootradius.push_back_slow(radius * b_part.root_radius());
+ CData->psys_tipradius.push_back_slow(radius * b_part.tip_radius());
+ CData->psys_shape.push_back_slow(b_part.shape());
+ CData->psys_closetip.push_back_slow(b_part.use_close_tip());
+
+ int pa_no = 0;
+ if (!(b_part.child_type() == 0) && totchild != 0)
+ pa_no = totparts;
+
+ int num_add = (totparts + totchild - pa_no);
+ CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
+ CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
+ CData->curve_length.reserve(CData->curve_length.size() + num_add);
+ CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add * ren_step);
+ CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add * ren_step);
+
+ for (; pa_no < totparts + totchild; pa_no++) {
+ int keynum = 0;
+ CData->curve_firstkey.push_back_slow(keyno);
+
+ float curve_length = 0.0f;
+ float3 prev_co_world = zero_float3();
+ float3 prev_co_object = zero_float3();
+ for (int step_no = 0; step_no < ren_step; step_no++) {
+ float3 co_world = prev_co_world;
+ b_psys.co_hair(*b_ob, pa_no, step_no, &co_world.x);
+ float3 co_object = transform_point(&itfm, co_world);
+ if (step_no > 0) {
+ const float step_length = len(co_object - prev_co_object);
+ curve_length += step_length;
+ }
+ CData->curvekey_co.push_back_slow(co_object);
+ CData->curvekey_time.push_back_slow(curve_length);
+ prev_co_object = co_object;
+ prev_co_world = co_world;
+ keynum++;
+ }
+ keyno += keynum;
+
+ CData->curve_keynum.push_back_slow(keynum);
+ CData->curve_length.push_back_slow(curve_length);
+ curvenum++;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool ObtainCacheParticleUV(Hair *hair,
+ BL::Mesh *b_mesh,
+ BL::Object *b_ob,
+ ParticleCurveData *CData,
+ bool background,
+ int uv_num)
+{
+ if (!(hair && b_mesh && b_ob && CData))
+ return false;
+
+ CData->curve_uv.clear();
+
+ for (BL::Modifier &b_mod : b_ob->modifiers) {
+ if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
+ (background ? b_mod.show_render() : b_mod.show_viewport())) {
+ BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
+ BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+
+ if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
+ (b_part.type() == BL::ParticleSettings::type_HAIR)) {
+ int totparts = b_psys.particles.length();
+ int totchild = background ? b_psys.child_particles.length() :
+ (int)((float)b_psys.child_particles.length() *
+ (float)b_part.display_percentage() / 100.0f);
+ int totcurves = totchild;
+
+ if (b_part.child_type() == 0 || totchild == 0)
+ totcurves += totparts;
+
+ if (totcurves == 0)
+ continue;
+
+ int pa_no = 0;
+ if (!(b_part.child_type() == 0) && totchild != 0)
+ pa_no = totparts;
+
+ int num_add = (totparts + totchild - pa_no);
+ CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
+
+ BL::ParticleSystem::particles_iterator b_pa;
+ b_psys.particles.begin(b_pa);
+ for (; pa_no < totparts + totchild; pa_no++) {
+ /* Add UVs */
+ BL::Mesh::uv_layers_iterator l;
+ b_mesh->uv_layers.begin(l);
+
+ float2 uv = zero_float2();
+ if (b_mesh->uv_layers.length())
+ b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
+ CData->curve_uv.push_back_slow(uv);
+
+ if (pa_no < totparts && b_pa != b_psys.particles.end())
+ ++b_pa;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool ObtainCacheParticleVcol(Hair *hair,
+ BL::Mesh *b_mesh,
+ BL::Object *b_ob,
+ ParticleCurveData *CData,
+ bool background,
+ int vcol_num)
+{
+ if (!(hair && b_mesh && b_ob && CData))
+ return false;
+
+ CData->curve_vcol.clear();
+
+ for (BL::Modifier &b_mod : b_ob->modifiers) {
+ if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
+ (background ? b_mod.show_render() : b_mod.show_viewport())) {
+ BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
+ BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+
+ if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
+ (b_part.type() == BL::ParticleSettings::type_HAIR)) {
+ int totparts = b_psys.particles.length();
+ int totchild = background ? b_psys.child_particles.length() :
+ (int)((float)b_psys.child_particles.length() *
+ (float)b_part.display_percentage() / 100.0f);
+ int totcurves = totchild;
+
+ if (b_part.child_type() == 0 || totchild == 0)
+ totcurves += totparts;
+
+ if (totcurves == 0)
+ continue;
+
+ int pa_no = 0;
+ if (!(b_part.child_type() == 0) && totchild != 0)
+ pa_no = totparts;
+
+ int num_add = (totparts + totchild - pa_no);
+ CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
+
+ BL::ParticleSystem::particles_iterator b_pa;
+ b_psys.particles.begin(b_pa);
+ for (; pa_no < totparts + totchild; pa_no++) {
+ /* Add vertex colors */
+ BL::Mesh::vertex_colors_iterator l;
+ b_mesh->vertex_colors.begin(l);
+
+ float4 vcol = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
+ if (b_mesh->vertex_colors.length())
+ b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
+ CData->curve_vcol.push_back_slow(vcol);
+
+ if (pa_no < totparts && b_pa != b_psys.particles.end())
+ ++b_pa;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CData)
+{
+ int num_keys = 0;
+ int num_curves = 0;
+
+ if (hair->num_curves())
+ return;
+
+ Attribute *attr_intercept = NULL;
+ Attribute *attr_length = NULL;
+ Attribute *attr_random = NULL;
+
+ if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
+ attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
+ if (hair->need_attribute(scene, ATTR_STD_CURVE_LENGTH))
+ attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH);
+ if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM))
+ attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
+
+ /* compute and reserve size of arrays */
+ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for (int curve = CData->psys_firstcurve[sys];
+ curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
+ curve++) {
+ num_keys += CData->curve_keynum[curve];
+ num_curves++;
+ }
+ }
+
+ if (num_curves > 0) {
+ VLOG(1) << "Exporting curve segments for mesh " << hair->name;
+ }
+
+ hair->reserve_curves(hair->num_curves() + num_curves, hair->get_curve_keys().size() + num_keys);
+
+ num_keys = 0;
+ num_curves = 0;
+
+ /* actually export */
+ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for (int curve = CData->psys_firstcurve[sys];
+ curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
+ curve++) {
+ size_t num_curve_keys = 0;
+
+ for (int curvekey = CData->curve_firstkey[curve];
+ curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve];
+ curvekey++) {
+ const float3 ickey_loc = CData->curvekey_co[curvekey];
+ const float curve_time = CData->curvekey_time[curvekey];
+ const float curve_length = CData->curve_length[curve];
+ const float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
+ float radius = shaperadius(
+ CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
+ if (CData->psys_closetip[sys] &&
+ (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) {
+ radius = 0.0f;
+ }
+ hair->add_curve_key(ickey_loc, radius);
+ if (attr_intercept)
+ attr_intercept->add(time);
+
+ num_curve_keys++;
+ }
+
+ if (attr_length != NULL) {
+ attr_length->add(CData->curve_length[curve]);
+ }
+
+ if (attr_random != NULL) {
+ attr_random->add(hash_uint2_to_float(num_curves, 0));
+ }
+
+ hair->add_curve(num_keys, CData->psys_shader[sys]);
+ num_keys += num_curve_keys;
+ num_curves++;
+ }
+ }
+
+ /* check allocation */
+ if ((hair->get_curve_keys().size() != num_keys) || (hair->num_curves() != num_curves)) {
+ VLOG(1) << "Allocation failed, clearing data";
+ hair->clear(true);
+ }
+}
+
+static float4 CurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, int curvekey)
+{
+ const float3 ickey_loc = CData->curvekey_co[curvekey];
+ const float curve_time = CData->curvekey_time[curvekey];
+ const float curve_length = CData->curve_length[curve];
+ float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
+ float radius = shaperadius(
+ CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
+
+ if (CData->psys_closetip[sys] &&
+ (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
+ radius = 0.0f;
+
+ /* curve motion keys store both position and radius in float4 */
+ float4 mP = float3_to_float4(ickey_loc);
+ mP.w = radius;
+ return mP;
+}
+
+static float4 LerpCurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, float step)
+{
+ assert(step >= 0.0f);
+ assert(step <= 1.0f);
+ const int first_curve_key = CData->curve_firstkey[curve];
+ const float curve_key_f = step * (CData->curve_keynum[curve] - 1);
+ int curvekey = (int)floorf(curve_key_f);
+ const float remainder = curve_key_f - curvekey;
+ if (remainder == 0.0f) {
+ return CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey);
+ }
+ int curvekey2 = curvekey + 1;
+ if (curvekey2 >= (CData->curve_keynum[curve] - 1)) {
+ curvekey2 = (CData->curve_keynum[curve] - 1);
+ curvekey = curvekey2 - 1;
+ }
+ const float4 mP = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey);
+ const float4 mP2 = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey2);
+ return lerp(mP, mP2, remainder);
+}
+
+static void export_hair_motion_validate_attribute(Hair *hair,
+ int motion_step,
+ int num_motion_keys,
+ bool have_motion)
+{
+ Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ const int num_keys = hair->get_curve_keys().size();
+
+ if (num_motion_keys != num_keys || !have_motion) {
+ /* No motion or hair "topology" changed, remove attributes again. */
+ if (num_motion_keys != num_keys) {
+ VLOG(1) << "Hair topology changed, removing attribute.";
+ }
+ else {
+ VLOG(1) << "No motion, removing attribute.";
+ }
+ hair->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+ else if (motion_step > 0) {
+ VLOG(1) << "Filling in new motion vertex position for motion_step " << motion_step;
+
+ /* Motion, fill up previous steps that we might have skipped because
+ * they had no motion, but we need them anyway now. */
+ for (int step = 0; step < motion_step; step++) {
+ float4 *mP = attr_mP->data_float4() + step * num_keys;
+
+ for (int key = 0; key < num_keys; key++) {
+ mP[key] = float3_to_float4(hair->get_curve_keys()[key]);
+ mP[key].w = hair->get_curve_radius()[key];
+ }
+ }
+ }
+}
+
+static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int motion_step)
+{
+ VLOG(1) << "Exporting curve motion segments for hair " << hair->name << ", motion step "
+ << motion_step;
+
+ /* find attribute */
+ Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ bool new_attribute = false;
+
+ /* add new attribute if it doesn't exist already */
+ if (!attr_mP) {
+ VLOG(1) << "Creating new motion vertex position attribute";
+ attr_mP = hair->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+ new_attribute = true;
+ }
+
+ /* export motion vectors for curve keys */
+ size_t numkeys = hair->get_curve_keys().size();
+ float4 *mP = attr_mP->data_float4() + motion_step * numkeys;
+ bool have_motion = false;
+ int i = 0;
+ int num_curves = 0;
+
+ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+ for (int curve = CData->psys_firstcurve[sys];
+ curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
+ curve++) {
+ /* Curve lengths may not match! Curves can be clipped. */
+ int curve_key_end = (num_curves + 1 < (int)hair->get_curve_first_key().size() ?
+ hair->get_curve_first_key()[num_curves + 1] :
+ (int)hair->get_curve_keys().size());
+ const int num_center_curve_keys = curve_key_end - hair->get_curve_first_key()[num_curves];
+ const int is_num_keys_different = CData->curve_keynum[curve] - num_center_curve_keys;
+
+ if (!is_num_keys_different) {
+ for (int curvekey = CData->curve_firstkey[curve];
+ curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve];
+ curvekey++) {
+ if (i < hair->get_curve_keys().size()) {
+ mP[i] = CurveSegmentMotionCV(CData, sys, curve, curvekey);
+ if (!have_motion) {
+ /* unlike mesh coordinates, these tend to be slightly different
+ * between frames due to particle transforms into/out of object
+ * space, so we use an epsilon to detect actual changes */
+ float4 curve_key = float3_to_float4(hair->get_curve_keys()[i]);
+ curve_key.w = hair->get_curve_radius()[i];
+ if (len_squared(mP[i] - curve_key) > 1e-5f * 1e-5f)
+ have_motion = true;
+ }
+ }
+ i++;
+ }
+ }
+ else {
+ /* Number of keys has changed. Generate an interpolated version
+ * to preserve motion blur. */
+ const float step_size = num_center_curve_keys > 1 ? 1.0f / (num_center_curve_keys - 1) :
+ 0.0f;
+ for (int step_index = 0; step_index < num_center_curve_keys; ++step_index) {
+ const float step = step_index * step_size;
+ mP[i] = LerpCurveSegmentMotionCV(CData, sys, curve, step);
+ i++;
+ }
+ have_motion = true;
+ }
+ num_curves++;
+ }
+ }
+
+ /* In case of new attribute, we verify if there really was any motion. */
+ if (new_attribute) {
+ export_hair_motion_validate_attribute(hair, motion_step, i, have_motion);
+ }
+}
+
+/* Hair Curve Sync */
+
+bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
+{
+ /* Test if the object has a particle modifier with hair. */
+ for (BL::Modifier &b_mod : b_ob.modifiers) {
+ if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
+ (preview ? b_mod.show_viewport() : b_mod.show_render())) {
+ BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
+ BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+
+ if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
+ (b_part.type() == BL::ParticleSettings::type_HAIR)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/* Old particle hair. */
+void BlenderSync::sync_particle_hair(
+ Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step)
+{
+ if (!b_ob_info.is_real_object_data()) {
+ return;
+ }
+ BL::Object b_ob = b_ob_info.real_object;
+
+ /* obtain general settings */
+ if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) {
+ return;
+ }
+
+ /* Extract particle hair data - should be combined with connecting to mesh later. */
+
+ ParticleCurveData CData;
+
+ ObtainCacheParticleData(hair, &b_mesh, &b_ob, &CData, !preview);
+
+ /* add hair geometry */
+ if (motion)
+ ExportCurveSegmentsMotion(hair, &CData, motion_step);
+ else
+ ExportCurveSegments(scene, hair, &CData);
+
+ /* generated coordinates from first key. we should ideally get this from
+ * blender to handle deforming objects */
+ if (!motion) {
+ if (hair->need_attribute(scene, ATTR_STD_GENERATED)) {
+ float3 loc, size;
+ mesh_texture_space(b_mesh, loc, size);
+
+ Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED);
+ float3 *generated = attr_generated->data_float3();
+
+ for (size_t i = 0; i < hair->num_curves(); i++) {
+ float3 co = hair->get_curve_keys()[hair->get_curve(i).first_key];
+ generated[i] = co * size - loc;
+ }
+ }
+ }
+
+ /* create vertex color attributes */
+ if (!motion) {
+ BL::Mesh::vertex_colors_iterator l;
+ int vcol_num = 0;
+
+ for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l, vcol_num++) {
+ if (!hair->need_attribute(scene, ustring(l->name().c_str())))
+ continue;
+
+ ObtainCacheParticleVcol(hair, &b_mesh, &b_ob, &CData, !preview, vcol_num);
+
+ Attribute *attr_vcol = hair->attributes.add(
+ ustring(l->name().c_str()), TypeRGBA, ATTR_ELEMENT_CURVE);
+
+ float4 *fdata = attr_vcol->data_float4();
+
+ if (fdata) {
+ size_t i = 0;
+
+ /* Encode vertex color using the sRGB curve. */
+ for (size_t curve = 0; curve < CData.curve_vcol.size(); curve++) {
+ fdata[i++] = color_srgb_to_linear_v4(CData.curve_vcol[curve]);
+ }
+ }
+ }
+ }
+
+ /* create UV attributes */
+ if (!motion) {
+ BL::Mesh::uv_layers_iterator l;
+ int uv_num = 0;
+
+ for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, uv_num++) {
+ bool active_render = l->active_render();
+ AttributeStandard std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
+ ustring name = ustring(l->name().c_str());
+
+ /* UV map */
+ if (hair->need_attribute(scene, name) || hair->need_attribute(scene, std)) {
+ Attribute *attr_uv;
+
+ ObtainCacheParticleUV(hair, &b_mesh, &b_ob, &CData, !preview, uv_num);
+
+ if (active_render)
+ attr_uv = hair->attributes.add(std, name);
+ else
+ attr_uv = hair->attributes.add(name, TypeFloat2, ATTR_ELEMENT_CURVE);
+
+ float2 *uv = attr_uv->data_float2();
+
+ if (uv) {
+ size_t i = 0;
+
+ for (size_t curve = 0; curve < CData.curve_uv.size(); curve++) {
+ uv[i++] = CData.curve_uv[curve];
+ }
+ }
+ }
+ }
+ }
+}
+
+#ifdef WITH_HAIR_NODES
+static float4 hair_point_as_float4(BL::HairPoint b_point)
+{
+ float4 mP = float3_to_float4(get_float3(b_point.co()));
+ mP.w = b_point.radius();
+ return mP;
+}
+
+static float4 interpolate_hair_points(BL::Hair b_hair,
+ const int first_point_index,
+ const int num_points,
+ const float step)
+{
+ const float curve_t = step * (num_points - 1);
+ const int point_a = clamp((int)curve_t, 0, num_points - 1);
+ const int point_b = min(point_a + 1, num_points - 1);
+ const float t = curve_t - (float)point_a;
+ return lerp(hair_point_as_float4(b_hair.points[first_point_index + point_a]),
+ hair_point_as_float4(b_hair.points[first_point_index + point_b]),
+ t);
+}
+
+static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
+{
+ /* TODO: optimize so we can straight memcpy arrays from Blender? */
+
+ /* Add requested attributes. */
+ Attribute *attr_intercept = NULL;
+ Attribute *attr_length = NULL;
+ Attribute *attr_random = NULL;
+
+ if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) {
+ attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
+ }
+ if (hair->need_attribute(scene, ATTR_STD_CURVE_LENGTH)) {
+ attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH);
+ }
+ if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) {
+ attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
+ }
+
+ /* Reserve memory. */
+ const int num_keys = b_hair.points.length();
+ const int num_curves = b_hair.curves.length();
+
+ if (num_curves > 0) {
+ VLOG(1) << "Exporting curve segments for hair " << hair->name;
+ }
+
+ hair->reserve_curves(num_curves, num_keys);
+
+ /* Export curves and points. */
+ vector<float> points_length;
+
+ for (BL::HairCurve &b_curve : b_hair.curves) {
+ const int first_point_index = b_curve.first_point_index();
+ const int num_points = b_curve.num_points();
+
+ float3 prev_co = zero_float3();
+ float length = 0.0f;
+ if (attr_intercept) {
+ points_length.clear();
+ points_length.reserve(num_points);
+ }
+
+ /* Position and radius. */
+ for (int i = 0; i < num_points; i++) {
+ BL::HairPoint b_point = b_hair.points[first_point_index + i];
+
+ const float3 co = get_float3(b_point.co());
+ const float radius = b_point.radius();
+ hair->add_curve_key(co, radius);
+
+ if (attr_intercept) {
+ if (i > 0) {
+ length += len(co - prev_co);
+ points_length.push_back(length);
+ }
+ prev_co = co;
+ }
+ }
+
+ /* Normalized 0..1 attribute along curve. */
+ if (attr_intercept) {
+ for (int i = 0; i < num_points; i++) {
+ attr_intercept->add((length == 0.0f) ? 0.0f : points_length[i] / length);
+ }
+ }
+
+ if (attr_length) {
+ attr_length->add(length);
+ }
+
+ /* Random number per curve. */
+ if (attr_random != NULL) {
+ attr_random->add(hash_uint2_to_float(b_curve.index(), 0));
+ }
+
+ /* Curve. */
+ const int shader_index = 0;
+ hair->add_curve(first_point_index, shader_index);
+ }
+}
+
+static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_step)
+{
+ VLOG(1) << "Exporting curve motion segments for hair " << hair->name << ", motion step "
+ << motion_step;
+
+ /* Find or add attribute. */
+ Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ bool new_attribute = false;
+
+ if (!attr_mP) {
+ VLOG(1) << "Creating new motion vertex position attribute";
+ attr_mP = hair->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+ new_attribute = true;
+ }
+
+ /* Export motion keys. */
+ const int num_keys = hair->get_curve_keys().size();
+ float4 *mP = attr_mP->data_float4() + motion_step * num_keys;
+ bool have_motion = false;
+ int num_motion_keys = 0;
+ int curve_index = 0;
+
+ for (BL::HairCurve &b_curve : b_hair.curves) {
+ const int first_point_index = b_curve.first_point_index();
+ const int num_points = b_curve.num_points();
+
+ Hair::Curve curve = hair->get_curve(curve_index);
+ curve_index++;
+
+ if (num_points == curve.num_keys) {
+ /* Number of keys matches. */
+ for (int i = 0; i < num_points; i++) {
+ int point_index = first_point_index + i;
+
+ if (point_index < num_keys) {
+ mP[num_motion_keys] = hair_point_as_float4(b_hair.points[point_index]);
+ num_motion_keys++;
+
+ if (!have_motion) {
+ /* TODO: use epsilon for comparison? Was needed for particles due to
+ * transform, but ideally should not happen anymore. */
+ float4 curve_key = float3_to_float4(hair->get_curve_keys()[i]);
+ curve_key.w = hair->get_curve_radius()[i];
+ have_motion = !(mP[i] == curve_key);
+ }
+ }
+ }
+ }
+ else {
+ /* Number of keys has changed. Generate an interpolated version
+ * to preserve motion blur. */
+ const float step_size = curve.num_keys > 1 ? 1.0f / (curve.num_keys - 1) : 0.0f;
+ for (int i = 0; i < curve.num_keys; i++) {
+ const float step = i * step_size;
+ mP[num_motion_keys] = interpolate_hair_points(b_hair, first_point_index, num_points, step);
+ num_motion_keys++;
+ }
+ have_motion = true;
+ }
+ }
+
+ /* In case of new attribute, we verify if there really was any motion. */
+ if (new_attribute) {
+ export_hair_motion_validate_attribute(hair, motion_step, num_motion_keys, have_motion);
+ }
+}
+
+/* Hair object. */
+void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
+{
+ /* Convert Blender hair to Cycles curves. */
+ BL::Hair b_hair(b_ob_info.object_data);
+ if (motion) {
+ export_hair_curves_motion(hair, b_hair, motion_step);
+ }
+ else {
+ export_hair_curves(scene, hair, b_hair);
+ }
+}
+#else
+void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
+{
+ (void)hair;
+ (void)b_ob_info;
+ (void)motion;
+ (void)motion_step;
+}
+#endif
+
+void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair)
+{
+ /* make a copy of the shaders as the caller in the main thread still need them for syncing the
+ * attributes */
+ array<Node *> used_shaders = hair->get_used_shaders();
+
+ Hair new_hair;
+ new_hair.set_used_shaders(used_shaders);
+
+ if (view_layer.use_hair) {
+ if (b_ob_info.object_data.is_a(&RNA_Hair)) {
+ /* Hair object. */
+ sync_hair(&new_hair, b_ob_info, false);
+ }
+ else {
+ /* Particle hair. */
+ bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED);
+ BL::Mesh b_mesh = object_to_mesh(
+ b_data, b_ob_info, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
+
+ if (b_mesh) {
+ sync_particle_hair(&new_hair, b_mesh, b_ob_info, false);
+ free_object_to_mesh(b_data, b_ob_info, b_mesh);
+ }
+ }
+ }
+
+ /* update original sockets */
+
+ for (const SocketType &socket : new_hair.type->inputs) {
+ /* Those sockets are updated in sync_object, so do not modify them. */
+ if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
+ socket.name == "used_shaders") {
+ continue;
+ }
+ hair->set_value(socket, new_hair, socket);
+ }
+
+ hair->attributes.update(std::move(new_hair.attributes));
+
+ /* tag update */
+
+ /* Compares curve_keys rather than strands in order to handle quick hair
+ * adjustments in dynamic BVH - other methods could probably do this better. */
+ const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
+
+ hair->tag_update(scene, rebuild);
+}
+
+void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
+ BObjectInfo &b_ob_info,
+ Hair *hair,
+ int motion_step)
+{
+ /* Skip if nothing exported. */
+ if (hair->num_keys() == 0) {
+ return;
+ }
+
+ /* Export deformed coordinates. */
+ if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
+ if (b_ob_info.object_data.is_a(&RNA_Hair)) {
+ /* Hair object. */
+ sync_hair(hair, b_ob_info, true, motion_step);
+ return;
+ }
+ else {
+ /* Particle hair. */
+ BL::Mesh b_mesh = object_to_mesh(
+ b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
+ if (b_mesh) {
+ sync_particle_hair(hair, b_mesh, b_ob_info, true, motion_step);
+ free_object_to_mesh(b_data, b_ob_info, b_mesh);
+ return;
+ }
+ }
+ }
+
+ /* No deformation on this frame, copy coordinates if other frames did have it. */
+ hair->copy_center_to_motion_step(motion_step);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/device.cpp b/intern/cycles/blender/device.cpp
new file mode 100644
index 00000000000..9fabc33a96b
--- /dev/null
+++ b/intern/cycles/blender/device.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "blender/device.h"
+#include "blender/session.h"
+#include "blender/util.h"
+
+#include "util/foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+enum ComputeDevice {
+ COMPUTE_DEVICE_CPU = 0,
+ COMPUTE_DEVICE_CUDA = 1,
+ COMPUTE_DEVICE_OPTIX = 3,
+ COMPUTE_DEVICE_HIP = 4,
+
+ COMPUTE_DEVICE_NUM
+};
+
+int blender_device_threads(BL::Scene &b_scene)
+{
+ BL::RenderSettings b_r = b_scene.render();
+
+ if (b_r.threads_mode() == BL::RenderSettings::threads_mode_FIXED)
+ return b_r.threads();
+ else
+ return 0;
+}
+
+DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scene, bool background)
+{
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+ /* Find cycles preferences. */
+ PointerRNA cpreferences;
+ for (BL::Addon &b_addon : b_preferences.addons) {
+ if (b_addon.module() == "cycles") {
+ cpreferences = b_addon.preferences().ptr;
+ break;
+ }
+ }
+
+ /* Default to CPU device. */
+ DeviceInfo device = Device::available_devices(DEVICE_MASK_CPU).front();
+
+ if (BlenderSession::device_override != DEVICE_MASK_ALL) {
+ vector<DeviceInfo> devices = Device::available_devices(BlenderSession::device_override);
+
+ if (devices.empty()) {
+ device = Device::dummy_device("Found no Cycles device of the specified type");
+ }
+ else {
+ int threads = blender_device_threads(b_scene);
+ device = Device::get_multi_device(devices, threads, background);
+ }
+ }
+ else if (get_enum(cscene, "device") == 1) {
+ /* Test if we are using GPU devices. */
+ ComputeDevice compute_device = (ComputeDevice)get_enum(
+ cpreferences, "compute_device_type", COMPUTE_DEVICE_NUM, COMPUTE_DEVICE_CPU);
+
+ if (compute_device != COMPUTE_DEVICE_CPU) {
+ /* Query GPU devices with matching types. */
+ uint mask = DEVICE_MASK_CPU;
+ if (compute_device == COMPUTE_DEVICE_CUDA) {
+ mask |= DEVICE_MASK_CUDA;
+ }
+ else if (compute_device == COMPUTE_DEVICE_OPTIX) {
+ mask |= DEVICE_MASK_OPTIX;
+ }
+ else if (compute_device == COMPUTE_DEVICE_HIP) {
+ mask |= DEVICE_MASK_HIP;
+ }
+ vector<DeviceInfo> devices = Device::available_devices(mask);
+
+ /* Match device preferences and available devices. */
+ vector<DeviceInfo> used_devices;
+ RNA_BEGIN (&cpreferences, device, "devices") {
+ if (get_boolean(device, "use")) {
+ string id = get_string(device, "id");
+ foreach (DeviceInfo &info, devices) {
+ if (info.id == id) {
+ used_devices.push_back(info);
+ break;
+ }
+ }
+ }
+ }
+ RNA_END;
+
+ if (!used_devices.empty()) {
+ int threads = blender_device_threads(b_scene);
+ device = Device::get_multi_device(used_devices, threads, background);
+ }
+ /* Else keep using the CPU device that was set before. */
+ }
+ }
+
+ if (!get_boolean(cpreferences, "peer_memory")) {
+ device.has_peer_memory = false;
+ }
+
+ return device;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_device.h b/intern/cycles/blender/device.h
index 8d2ecac7483..8d2ecac7483 100644
--- a/intern/cycles/blender/blender_device.h
+++ b/intern/cycles/blender/device.h
diff --git a/intern/cycles/blender/display_driver.cpp b/intern/cycles/blender/display_driver.cpp
new file mode 100644
index 00000000000..d5f6d85251e
--- /dev/null
+++ b/intern/cycles/blender/display_driver.cpp
@@ -0,0 +1,771 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "blender/display_driver.h"
+
+#include "device/device.h"
+#include "util/log.h"
+#include "util/opengl.h"
+
+extern "C" {
+struct RenderEngine;
+
+bool RE_engine_has_render_context(struct RenderEngine *engine);
+void RE_engine_render_context_enable(struct RenderEngine *engine);
+void RE_engine_render_context_disable(struct RenderEngine *engine);
+
+bool DRW_opengl_context_release();
+void DRW_opengl_context_activate(bool drw_state);
+
+void *WM_opengl_context_create();
+void WM_opengl_context_activate(void *gl_context);
+void WM_opengl_context_dispose(void *gl_context);
+void WM_opengl_context_release(void *context);
+}
+
+CCL_NAMESPACE_BEGIN
+
+/* --------------------------------------------------------------------
+ * BlenderDisplayShader.
+ */
+
+unique_ptr<BlenderDisplayShader> BlenderDisplayShader::create(BL::RenderEngine &b_engine,
+ BL::Scene &b_scene)
+{
+ if (b_engine.support_display_space_shader(b_scene)) {
+ return make_unique<BlenderDisplaySpaceShader>(b_engine, b_scene);
+ }
+
+ return make_unique<BlenderFallbackDisplayShader>();
+}
+
+int BlenderDisplayShader::get_position_attrib_location()
+{
+ if (position_attribute_location_ == -1) {
+ const uint shader_program = get_shader_program();
+ position_attribute_location_ = glGetAttribLocation(shader_program, position_attribute_name);
+ }
+ return position_attribute_location_;
+}
+
+int BlenderDisplayShader::get_tex_coord_attrib_location()
+{
+ if (tex_coord_attribute_location_ == -1) {
+ const uint shader_program = get_shader_program();
+ tex_coord_attribute_location_ = glGetAttribLocation(shader_program, tex_coord_attribute_name);
+ }
+ return tex_coord_attribute_location_;
+}
+
+/* --------------------------------------------------------------------
+ * BlenderFallbackDisplayShader.
+ */
+
+/* TODO move shaders to standalone .glsl file. */
+static const char *FALLBACK_VERTEX_SHADER =
+ "#version 330\n"
+ "uniform vec2 fullscreen;\n"
+ "in vec2 texCoord;\n"
+ "in vec2 pos;\n"
+ "out vec2 texCoord_interp;\n"
+ "\n"
+ "vec2 normalize_coordinates()\n"
+ "{\n"
+ " return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n"
+ "}\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n"
+ " texCoord_interp = texCoord;\n"
+ "}\n\0";
+
+static const char *FALLBACK_FRAGMENT_SHADER =
+ "#version 330\n"
+ "uniform sampler2D image_texture;\n"
+ "in vec2 texCoord_interp;\n"
+ "out vec4 fragColor;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = texture(image_texture, texCoord_interp);\n"
+ "}\n\0";
+
+static void shader_print_errors(const char *task, const char *log, const char *code)
+{
+ LOG(ERROR) << "Shader: " << task << " error:";
+ LOG(ERROR) << "===== shader string ====";
+
+ stringstream stream(code);
+ string partial;
+
+ int line = 1;
+ while (getline(stream, partial, '\n')) {
+ if (line < 10) {
+ LOG(ERROR) << " " << line << " " << partial;
+ }
+ else {
+ LOG(ERROR) << line << " " << partial;
+ }
+ line++;
+ }
+ LOG(ERROR) << log;
+}
+
+static int compile_fallback_shader(void)
+{
+ const struct Shader {
+ const char *source;
+ const GLenum type;
+ } shaders[2] = {{FALLBACK_VERTEX_SHADER, GL_VERTEX_SHADER},
+ {FALLBACK_FRAGMENT_SHADER, GL_FRAGMENT_SHADER}};
+
+ const GLuint program = glCreateProgram();
+
+ for (int i = 0; i < 2; i++) {
+ const GLuint shader = glCreateShader(shaders[i].type);
+
+ string source_str = shaders[i].source;
+ const char *c_str = source_str.c_str();
+
+ glShaderSource(shader, 1, &c_str, NULL);
+ glCompileShader(shader);
+
+ GLint compile_status;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
+
+ if (!compile_status) {
+ GLchar log[5000];
+ GLsizei length = 0;
+ glGetShaderInfoLog(shader, sizeof(log), &length, log);
+ shader_print_errors("compile", log, c_str);
+ return 0;
+ }
+
+ glAttachShader(program, shader);
+ }
+
+ /* Link output. */
+ glBindFragDataLocation(program, 0, "fragColor");
+
+ /* Link and error check. */
+ glLinkProgram(program);
+
+ /* TODO(sergey): Find a way to nicely de-duplicate the error checking. */
+ GLint link_status;
+ glGetProgramiv(program, GL_LINK_STATUS, &link_status);
+ if (!link_status) {
+ GLchar log[5000];
+ GLsizei length = 0;
+ /* TODO(sergey): Is it really program passed to glGetShaderInfoLog? */
+ glGetShaderInfoLog(program, sizeof(log), &length, log);
+ shader_print_errors("linking", log, FALLBACK_VERTEX_SHADER);
+ shader_print_errors("linking", log, FALLBACK_FRAGMENT_SHADER);
+ return 0;
+ }
+
+ return program;
+}
+
+void BlenderFallbackDisplayShader::bind(int width, int height)
+{
+ create_shader_if_needed();
+
+ if (!shader_program_) {
+ return;
+ }
+
+ glUseProgram(shader_program_);
+ glUniform1i(image_texture_location_, 0);
+ glUniform2f(fullscreen_location_, width, height);
+}
+
+void BlenderFallbackDisplayShader::unbind()
+{
+}
+
+uint BlenderFallbackDisplayShader::get_shader_program()
+{
+ return shader_program_;
+}
+
+void BlenderFallbackDisplayShader::create_shader_if_needed()
+{
+ if (shader_program_ || shader_compile_attempted_) {
+ return;
+ }
+
+ shader_compile_attempted_ = true;
+
+ shader_program_ = compile_fallback_shader();
+ if (!shader_program_) {
+ return;
+ }
+
+ glUseProgram(shader_program_);
+
+ image_texture_location_ = glGetUniformLocation(shader_program_, "image_texture");
+ if (image_texture_location_ < 0) {
+ LOG(ERROR) << "Shader doesn't contain the 'image_texture' uniform.";
+ destroy_shader();
+ return;
+ }
+
+ fullscreen_location_ = glGetUniformLocation(shader_program_, "fullscreen");
+ if (fullscreen_location_ < 0) {
+ LOG(ERROR) << "Shader doesn't contain the 'fullscreen' uniform.";
+ destroy_shader();
+ return;
+ }
+}
+
+void BlenderFallbackDisplayShader::destroy_shader()
+{
+ glDeleteProgram(shader_program_);
+ shader_program_ = 0;
+}
+
+/* --------------------------------------------------------------------
+ * BlenderDisplaySpaceShader.
+ */
+
+BlenderDisplaySpaceShader::BlenderDisplaySpaceShader(BL::RenderEngine &b_engine,
+ BL::Scene &b_scene)
+ : b_engine_(b_engine), b_scene_(b_scene)
+{
+ DCHECK(b_engine_.support_display_space_shader(b_scene_));
+}
+
+void BlenderDisplaySpaceShader::bind(int /*width*/, int /*height*/)
+{
+ b_engine_.bind_display_space_shader(b_scene_);
+}
+
+void BlenderDisplaySpaceShader::unbind()
+{
+ b_engine_.unbind_display_space_shader();
+}
+
+uint BlenderDisplaySpaceShader::get_shader_program()
+{
+ if (!shader_program_) {
+ glGetIntegerv(GL_CURRENT_PROGRAM, reinterpret_cast<int *>(&shader_program_));
+ }
+
+ if (!shader_program_) {
+ LOG(ERROR) << "Error retrieving shader program for display space shader.";
+ }
+
+ return shader_program_;
+}
+
+/* --------------------------------------------------------------------
+ * BlenderDisplayDriver.
+ */
+
+BlenderDisplayDriver::BlenderDisplayDriver(BL::RenderEngine &b_engine, BL::Scene &b_scene)
+ : b_engine_(b_engine), display_shader_(BlenderDisplayShader::create(b_engine, b_scene))
+{
+ /* Create context while on the main thread. */
+ gl_context_create();
+}
+
+BlenderDisplayDriver::~BlenderDisplayDriver()
+{
+ gl_resources_destroy();
+}
+
+/* --------------------------------------------------------------------
+ * Update procedure.
+ */
+
+bool BlenderDisplayDriver::update_begin(const Params &params,
+ int texture_width,
+ int texture_height)
+{
+ /* Note that it's the responsibility of BlenderDisplayDriver to ensure updating and drawing
+ * the texture does not happen at the same time. This is achieved indirectly.
+ *
+ * When enabling the OpenGL context, it uses an internal mutex lock DST.gl_context_lock.
+ * This same lock is also held when do_draw() is called, which together ensure mutual
+ * exclusion.
+ *
+ * This locking is not performed on the Cycles side, because that would cause lock inversion. */
+ if (!gl_context_enable()) {
+ return false;
+ }
+
+ if (gl_render_sync_) {
+ glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
+ }
+
+ if (!gl_texture_resources_ensure()) {
+ gl_context_disable();
+ return false;
+ }
+
+ /* Update texture dimensions if needed. */
+ if (texture_.width != texture_width || texture_.height != texture_height) {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
+ glTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA16F, texture_width, texture_height, 0, GL_RGBA, GL_HALF_FLOAT, 0);
+ texture_.width = texture_width;
+ texture_.height = texture_height;
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ /* Texture did change, and no pixel storage was provided. Tag for an explicit zeroing out to
+ * avoid undefined content. */
+ texture_.need_clear = true;
+ }
+
+ /* Update PBO dimensions if needed.
+ *
+ * NOTE: Allocate the PBO for the the size which will fit the final render resolution (as in,
+ * at a resolution divider 1. This was we don't need to recreate graphics interoperability
+ * objects which are costly and which are tied to the specific underlying buffer size.
+ * The downside of this approach is that when graphics interoperability is not used we are
+ * sending too much data to GPU when resolution divider is not 1. */
+ /* TODO(sergey): Investigate whether keeping the PBO exact size of the texture makes non-interop
+ * mode faster. */
+ const int buffer_width = params.full_size.x;
+ const int buffer_height = params.full_size.y;
+ if (texture_.buffer_width != buffer_width || texture_.buffer_height != buffer_height) {
+ const size_t size_in_bytes = sizeof(half4) * buffer_width * buffer_height;
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, size_in_bytes, 0, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ texture_.buffer_width = buffer_width;
+ texture_.buffer_height = buffer_height;
+ }
+
+ /* New content will be provided to the texture in one way or another, so mark this in a
+ * centralized place. */
+ texture_.need_update = true;
+
+ texture_.params = params;
+
+ return true;
+}
+
+void BlenderDisplayDriver::update_end()
+{
+ gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ glFlush();
+
+ gl_context_disable();
+}
+
+/* --------------------------------------------------------------------
+ * Texture buffer mapping.
+ */
+
+half4 *BlenderDisplayDriver::map_texture_buffer()
+{
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
+
+ half4 *mapped_rgba_pixels = reinterpret_cast<half4 *>(
+ glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
+ if (!mapped_rgba_pixels) {
+ LOG(ERROR) << "Error mapping BlenderDisplayDriver pixel buffer object.";
+ }
+
+ if (texture_.need_clear) {
+ const int64_t texture_width = texture_.width;
+ const int64_t texture_height = texture_.height;
+ memset(reinterpret_cast<void *>(mapped_rgba_pixels),
+ 0,
+ texture_width * texture_height * sizeof(half4));
+ texture_.need_clear = false;
+ }
+
+ return mapped_rgba_pixels;
+}
+
+void BlenderDisplayDriver::unmap_texture_buffer()
+{
+ glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+}
+
+/* --------------------------------------------------------------------
+ * Graphics interoperability.
+ */
+
+BlenderDisplayDriver::GraphicsInterop BlenderDisplayDriver::graphics_interop_get()
+{
+ GraphicsInterop interop_dst;
+
+ interop_dst.buffer_width = texture_.buffer_width;
+ interop_dst.buffer_height = texture_.buffer_height;
+ interop_dst.opengl_pbo_id = texture_.gl_pbo_id;
+
+ interop_dst.need_clear = texture_.need_clear;
+ texture_.need_clear = false;
+
+ return interop_dst;
+}
+
+void BlenderDisplayDriver::graphics_interop_activate()
+{
+ gl_context_enable();
+}
+
+void BlenderDisplayDriver::graphics_interop_deactivate()
+{
+ gl_context_disable();
+}
+
+/* --------------------------------------------------------------------
+ * Drawing.
+ */
+
+void BlenderDisplayDriver::clear()
+{
+ texture_.need_clear = true;
+}
+
+void BlenderDisplayDriver::set_zoom(float zoom_x, float zoom_y)
+{
+ zoom_ = make_float2(zoom_x, zoom_y);
+}
+
+void BlenderDisplayDriver::draw(const Params &params)
+{
+ /* See do_update_begin() for why no locking is required here. */
+ const bool transparent = true; // TODO(sergey): Derive this from Film.
+
+ if (!gl_draw_resources_ensure()) {
+ return;
+ }
+
+ if (use_gl_context_) {
+ gl_context_mutex_.lock();
+ }
+
+ if (texture_.need_clear) {
+ /* Texture is requested to be cleared and was not yet cleared.
+ *
+ * Do early return which should be equivalent of drawing all-zero texture.
+ * Watch out for the lock though so that the clear happening during update is properly
+ * synchronized here. */
+ gl_context_mutex_.unlock();
+ return;
+ }
+
+ if (gl_upload_sync_) {
+ glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
+ }
+
+ if (transparent) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ display_shader_->bind(params.full_size.x, params.full_size.y);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
+
+ /* Trick to keep sharp rendering without jagged edges on all GPUs.
+ *
+ * The idea here is to enforce driver to use linear interpolation when the image is not zoomed
+ * in.
+ * For the render result with a resolution divider in effect we always use nearest interpolation.
+ *
+ * Use explicit MIN assignment to make sure the driver does not have an undefined behavior at
+ * the zoom level 1. The MAG filter is always NEAREST. */
+ const float zoomed_width = params.size.x * zoom_.x;
+ const float zoomed_height = params.size.y * zoom_.y;
+ if (texture_.width != params.size.x || texture_.height != params.size.y) {
+ /* Resolution divider is different from 1, force nearest interpolation. */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ else if (zoomed_width - params.size.x > 0.5f || zoomed_height - params.size.y > 0.5f) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
+
+ texture_update_if_needed();
+ vertex_buffer_update(params);
+
+ /* TODO(sergey): Does it make sense/possible to cache/reuse the VAO? */
+ GLuint vertex_array_object;
+ glGenVertexArrays(1, &vertex_array_object);
+ glBindVertexArray(vertex_array_object);
+
+ const int texcoord_attribute = display_shader_->get_tex_coord_attrib_location();
+ const int position_attribute = display_shader_->get_position_attrib_location();
+
+ glEnableVertexAttribArray(texcoord_attribute);
+ glEnableVertexAttribArray(position_attribute);
+
+ glVertexAttribPointer(
+ texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0);
+ glVertexAttribPointer(position_attribute,
+ 2,
+ GL_FLOAT,
+ GL_FALSE,
+ 4 * sizeof(float),
+ (const GLvoid *)(sizeof(float) * 2));
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ glDeleteVertexArrays(1, &vertex_array_object);
+
+ display_shader_->unbind();
+
+ if (transparent) {
+ glDisable(GL_BLEND);
+ }
+
+ gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ glFlush();
+
+ if (use_gl_context_) {
+ gl_context_mutex_.unlock();
+ }
+}
+
+void BlenderDisplayDriver::gl_context_create()
+{
+ /* When rendering in viewport there is no render context available via engine.
+ * Check whether own context is to be created here.
+ *
+ * NOTE: If the `b_engine_`'s context is not available, we are expected to be on a main thread
+ * here. */
+ use_gl_context_ = !RE_engine_has_render_context(
+ reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
+
+ if (use_gl_context_) {
+ const bool drw_state = DRW_opengl_context_release();
+ gl_context_ = WM_opengl_context_create();
+ if (gl_context_) {
+ /* On Windows an old context is restored after creation, and subsequent release of context
+ * generates a Win32 error. Harmless for users, but annoying to have possible misleading
+ * error prints in the console. */
+#ifndef _WIN32
+ WM_opengl_context_release(gl_context_);
+#endif
+ }
+ else {
+ LOG(ERROR) << "Error creating OpenGL context.";
+ }
+
+ DRW_opengl_context_activate(drw_state);
+ }
+}
+
+bool BlenderDisplayDriver::gl_context_enable()
+{
+ if (use_gl_context_) {
+ if (!gl_context_) {
+ return false;
+ }
+ gl_context_mutex_.lock();
+ WM_opengl_context_activate(gl_context_);
+ return true;
+ }
+
+ RE_engine_render_context_enable(reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
+ return true;
+}
+
+void BlenderDisplayDriver::gl_context_disable()
+{
+ if (use_gl_context_) {
+ if (gl_context_) {
+ WM_opengl_context_release(gl_context_);
+ gl_context_mutex_.unlock();
+ }
+ return;
+ }
+
+ RE_engine_render_context_disable(reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
+}
+
+void BlenderDisplayDriver::gl_context_dispose()
+{
+ if (gl_context_) {
+ const bool drw_state = DRW_opengl_context_release();
+
+ WM_opengl_context_activate(gl_context_);
+ WM_opengl_context_dispose(gl_context_);
+
+ DRW_opengl_context_activate(drw_state);
+ }
+}
+
+bool BlenderDisplayDriver::gl_draw_resources_ensure()
+{
+ if (!texture_.gl_id) {
+ /* If there is no texture allocated, there is nothing to draw. Inform the draw call that it can
+ * can not continue. Note that this is not an unrecoverable error, so once the texture is known
+ * we will come back here and create all the GPU resources needed for draw. */
+ return false;
+ }
+
+ if (gl_draw_resource_creation_attempted_) {
+ return gl_draw_resources_created_;
+ }
+ gl_draw_resource_creation_attempted_ = true;
+
+ if (!vertex_buffer_) {
+ glGenBuffers(1, &vertex_buffer_);
+ if (!vertex_buffer_) {
+ LOG(ERROR) << "Error creating vertex buffer.";
+ return false;
+ }
+ }
+
+ gl_draw_resources_created_ = true;
+
+ return true;
+}
+
+void BlenderDisplayDriver::gl_resources_destroy()
+{
+ gl_context_enable();
+
+ if (vertex_buffer_ != 0) {
+ glDeleteBuffers(1, &vertex_buffer_);
+ }
+
+ if (texture_.gl_pbo_id) {
+ glDeleteBuffers(1, &texture_.gl_pbo_id);
+ texture_.gl_pbo_id = 0;
+ }
+
+ if (texture_.gl_id) {
+ glDeleteTextures(1, &texture_.gl_id);
+ texture_.gl_id = 0;
+ }
+
+ gl_context_disable();
+
+ gl_context_dispose();
+}
+
+bool BlenderDisplayDriver::gl_texture_resources_ensure()
+{
+ if (texture_.creation_attempted) {
+ return texture_.is_created;
+ }
+ texture_.creation_attempted = true;
+
+ DCHECK(!texture_.gl_id);
+ DCHECK(!texture_.gl_pbo_id);
+
+ /* Create texture. */
+ glGenTextures(1, &texture_.gl_id);
+ if (!texture_.gl_id) {
+ LOG(ERROR) << "Error creating texture.";
+ return false;
+ }
+
+ /* Configure the texture. */
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ /* Create PBO for the texture. */
+ glGenBuffers(1, &texture_.gl_pbo_id);
+ if (!texture_.gl_pbo_id) {
+ LOG(ERROR) << "Error creating texture pixel buffer object.";
+ return false;
+ }
+
+ /* Creation finished with a success. */
+ texture_.is_created = true;
+
+ return true;
+}
+
+void BlenderDisplayDriver::texture_update_if_needed()
+{
+ if (!texture_.need_update) {
+ return;
+ }
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
+ glTexSubImage2D(
+ GL_TEXTURE_2D, 0, 0, 0, texture_.width, texture_.height, GL_RGBA, GL_HALF_FLOAT, 0);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ texture_.need_update = false;
+}
+
+void BlenderDisplayDriver::vertex_buffer_update(const Params & /*params*/)
+{
+ /* Draw at the parameters for which the texture has been updated for. This allows to always draw
+ * texture during bordered-rendered camera view without flickering. The validness of the display
+ * parameters for a texture is guaranteed by the initial "clear" state which makes drawing to
+ * have an early output.
+ *
+ * Such approach can cause some extra "jelly" effect during panning, but it is not more jelly
+ * than overlay of selected objects. Also, it's possible to redraw texture at an intersection of
+ * the texture draw parameters and the latest updated draw parameters (although, complexity of
+ * doing it might not worth it. */
+ const int x = texture_.params.full_offset.x;
+ const int y = texture_.params.full_offset.y;
+
+ const int width = texture_.params.size.x;
+ const int height = texture_.params.size.y;
+
+ /* Invalidate old contents - avoids stalling if the buffer is still waiting in queue to be
+ * rendered. */
+ glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
+
+ float *vpointer = reinterpret_cast<float *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
+ if (!vpointer) {
+ return;
+ }
+
+ vpointer[0] = 0.0f;
+ vpointer[1] = 0.0f;
+ vpointer[2] = x;
+ vpointer[3] = y;
+
+ vpointer[4] = 1.0f;
+ vpointer[5] = 0.0f;
+ vpointer[6] = x + width;
+ vpointer[7] = y;
+
+ vpointer[8] = 1.0f;
+ vpointer[9] = 1.0f;
+ vpointer[10] = x + width;
+ vpointer[11] = y + height;
+
+ vpointer[12] = 0.0f;
+ vpointer[13] = 1.0f;
+ vpointer[14] = x;
+ vpointer[15] = y + height;
+
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/display_driver.h b/intern/cycles/blender/display_driver.h
new file mode 100644
index 00000000000..66cfc8cffcc
--- /dev/null
+++ b/intern/cycles/blender/display_driver.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_blender_cpp.h"
+
+#include "session/display_driver.h"
+
+#include "util/thread.h"
+#include "util/unique_ptr.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Base class of shader used for display driver rendering. */
+class BlenderDisplayShader {
+ public:
+ static constexpr const char *position_attribute_name = "pos";
+ static constexpr const char *tex_coord_attribute_name = "texCoord";
+
+ /* Create shader implementation suitable for the given render engine and scene configuration. */
+ static unique_ptr<BlenderDisplayShader> create(BL::RenderEngine &b_engine, BL::Scene &b_scene);
+
+ BlenderDisplayShader() = default;
+ virtual ~BlenderDisplayShader() = default;
+
+ virtual void bind(int width, int height) = 0;
+ virtual void unbind() = 0;
+
+ /* Get attribute location for position and texture coordinate respectively.
+ * NOTE: The shader needs to be bound to have access to those. */
+ virtual int get_position_attrib_location();
+ virtual int get_tex_coord_attrib_location();
+
+ protected:
+ /* Get program of this display shader.
+ * NOTE: The shader needs to be bound to have access to this. */
+ virtual uint get_shader_program() = 0;
+
+ /* Cached values of various OpenGL resources. */
+ int position_attribute_location_ = -1;
+ int tex_coord_attribute_location_ = -1;
+};
+
+/* Implementation of display rendering shader used in the case when render engine does not support
+ * display space shader. */
+class BlenderFallbackDisplayShader : public BlenderDisplayShader {
+ public:
+ virtual void bind(int width, int height) override;
+ virtual void unbind() override;
+
+ protected:
+ virtual uint get_shader_program() override;
+
+ void create_shader_if_needed();
+ void destroy_shader();
+
+ uint shader_program_ = 0;
+ int image_texture_location_ = -1;
+ int fullscreen_location_ = -1;
+
+ /* Shader compilation attempted. Which means, that if the shader program is 0 then compilation or
+ * linking has failed. Do not attempt to re-compile the shader. */
+ bool shader_compile_attempted_ = false;
+};
+
+class BlenderDisplaySpaceShader : public BlenderDisplayShader {
+ public:
+ BlenderDisplaySpaceShader(BL::RenderEngine &b_engine, BL::Scene &b_scene);
+
+ virtual void bind(int width, int height) override;
+ virtual void unbind() override;
+
+ protected:
+ virtual uint get_shader_program() override;
+
+ BL::RenderEngine b_engine_;
+ BL::Scene &b_scene_;
+
+ /* Cached values of various OpenGL resources. */
+ uint shader_program_ = 0;
+};
+
+/* Display driver implementation which is specific for Blender viewport integration. */
+class BlenderDisplayDriver : public DisplayDriver {
+ public:
+ BlenderDisplayDriver(BL::RenderEngine &b_engine, BL::Scene &b_scene);
+ ~BlenderDisplayDriver();
+
+ virtual void graphics_interop_activate() override;
+ virtual void graphics_interop_deactivate() override;
+
+ virtual void clear() override;
+
+ void set_zoom(float zoom_x, float zoom_y);
+
+ protected:
+ virtual bool update_begin(const Params &params, int texture_width, int texture_height) override;
+ virtual void update_end() override;
+
+ virtual half4 *map_texture_buffer() override;
+ virtual void unmap_texture_buffer() override;
+
+ virtual GraphicsInterop graphics_interop_get() override;
+
+ virtual void draw(const Params &params) override;
+
+ /* Helper function which allocates new GPU context. */
+ void gl_context_create();
+ bool gl_context_enable();
+ void gl_context_disable();
+ void gl_context_dispose();
+
+ /* Make sure texture is allocated and its initial configuration is performed. */
+ bool gl_texture_resources_ensure();
+
+ /* Ensure all runtime GPU resources needed for drawing are allocated.
+ * Returns true if all resources needed for drawing are available. */
+ bool gl_draw_resources_ensure();
+
+ /* Destroy all GPU resources which are being used by this object. */
+ void gl_resources_destroy();
+
+ /* Update GPU texture dimensions and content if needed (new pixel data was provided).
+ *
+ * NOTE: The texture needs to be bound. */
+ void texture_update_if_needed();
+
+ /* Update vertex buffer with new coordinates of vertex positions and texture coordinates.
+ * This buffer is used to render texture in the viewport.
+ *
+ * NOTE: The buffer needs to be bound. */
+ void vertex_buffer_update(const Params &params);
+
+ BL::RenderEngine b_engine_;
+
+ /* OpenGL context which is used the render engine doesn't have its own. */
+ void *gl_context_ = nullptr;
+ /* The when Blender RenderEngine side context is not available and the DisplayDriver is to create
+ * its own context. */
+ bool use_gl_context_ = false;
+ /* Mutex used to guard the `gl_context_`. */
+ thread_mutex gl_context_mutex_;
+
+ /* Texture which contains pixels of the render result. */
+ struct {
+ /* Indicates whether texture creation was attempted and succeeded.
+ * Used to avoid multiple attempts of texture creation on GPU issues or GPU context
+ * misconfiguration. */
+ bool creation_attempted = false;
+ bool is_created = false;
+
+ /* OpenGL resource IDs of the texture itself and Pixel Buffer Object (PBO) used to write
+ * pixels to it.
+ *
+ * NOTE: Allocated on the engine's context. */
+ uint gl_id = 0;
+ uint gl_pbo_id = 0;
+
+ /* Is true when new data was written to the PBO, meaning, the texture might need to be resized
+ * and new data is to be uploaded to the GPU. */
+ bool need_update = false;
+
+ /* Content of the texture is to be filled with zeroes. */
+ std::atomic<bool> need_clear = true;
+
+ /* Dimensions of the texture in pixels. */
+ int width = 0;
+ int height = 0;
+
+ /* Dimensions of the underlying PBO. */
+ int buffer_width = 0;
+ int buffer_height = 0;
+
+ /* Display parameters the texture has been updated for. */
+ Params params;
+ } texture_;
+
+ unique_ptr<BlenderDisplayShader> display_shader_;
+
+ /* Special track of whether GPU resources were attempted to be created, to avoid attempts of
+ * their re-creation on failure on every redraw. */
+ bool gl_draw_resource_creation_attempted_ = false;
+ bool gl_draw_resources_created_ = false;
+
+ /* Vertex buffer which hold vertices of a triangle fan which is textures with the texture
+ * holding the render result. */
+ uint vertex_buffer_ = 0;
+
+ void *gl_render_sync_ = nullptr;
+ void *gl_upload_sync_ = nullptr;
+
+ float2 zoom_ = make_float2(1.0f, 1.0f);
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/geometry.cpp b/intern/cycles/blender/geometry.cpp
new file mode 100644
index 00000000000..479e76f68bc
--- /dev/null
+++ b/intern/cycles/blender/geometry.cpp
@@ -0,0 +1,241 @@
+
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/curves.h"
+#include "scene/hair.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/volume.h"
+
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "util/foreach.h"
+#include "util/task.h"
+
+CCL_NAMESPACE_BEGIN
+
+static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair)
+{
+ if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
+ return Geometry::HAIR;
+ }
+
+ if (b_ob_info.object_data.is_a(&RNA_Volume) ||
+ (b_ob_info.object_data == b_ob_info.real_object.data() &&
+ object_fluid_gas_domain_find(b_ob_info.real_object))) {
+ return Geometry::VOLUME;
+ }
+
+ return Geometry::MESH;
+}
+
+array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob)
+{
+ BL::Material material_override = view_layer.material_override;
+ Shader *default_shader = (b_ob.type() == BL::Object::type_VOLUME) ? scene->default_volume :
+ scene->default_surface;
+
+ array<Node *> used_shaders;
+
+ for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
+ if (material_override) {
+ find_shader(material_override, used_shaders, default_shader);
+ }
+ else {
+ BL::ID b_material(b_slot.material());
+ find_shader(b_material, used_shaders, default_shader);
+ }
+ }
+
+ if (used_shaders.size() == 0) {
+ if (material_override)
+ find_shader(material_override, used_shaders, default_shader);
+ else
+ used_shaders.push_back_slow(default_shader);
+ }
+
+ return used_shaders;
+}
+
+Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
+ BObjectInfo &b_ob_info,
+ bool object_updated,
+ bool use_particle_hair,
+ TaskPool *task_pool)
+{
+ /* Test if we can instance or if the object is modified. */
+ Geometry::Type geom_type = determine_geom_type(b_ob_info, use_particle_hair);
+ BL::ID b_key_id = (b_ob_info.is_real_object_data() &&
+ BKE_object_is_modified(b_ob_info.real_object)) ?
+ b_ob_info.real_object :
+ b_ob_info.object_data;
+ GeometryKey key(b_key_id.ptr.data, geom_type);
+
+ /* Find shader indices. */
+ array<Node *> used_shaders = find_used_shaders(b_ob_info.iter_object);
+
+ /* Ensure we only sync instanced geometry once. */
+ Geometry *geom = geometry_map.find(key);
+ if (geom) {
+ if (geometry_synced.find(geom) != geometry_synced.end()) {
+ return geom;
+ }
+ }
+
+ /* Test if we need to sync. */
+ bool sync = true;
+ if (geom == NULL) {
+ /* Add new geometry if it did not exist yet. */
+ if (geom_type == Geometry::HAIR) {
+ geom = scene->create_node<Hair>();
+ }
+ else if (geom_type == Geometry::VOLUME) {
+ geom = scene->create_node<Volume>();
+ }
+ else {
+ geom = scene->create_node<Mesh>();
+ }
+ geometry_map.add(key, geom);
+ }
+ else {
+ /* Test if we need to update existing geometry. */
+ sync = geometry_map.update(geom, b_key_id);
+ }
+
+ if (!sync) {
+ /* If transform was applied to geometry, need full update. */
+ if (object_updated && geom->transform_applied) {
+ ;
+ }
+ /* Test if shaders changed, these can be object level so geometry
+ * does not get tagged for recalc. */
+ else if (geom->get_used_shaders() != used_shaders) {
+ ;
+ }
+ else {
+ /* Even if not tagged for recalc, we may need to sync anyway
+ * because the shader needs different geometry attributes. */
+ bool attribute_recalc = false;
+
+ foreach (Node *node, geom->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->need_update_geometry()) {
+ attribute_recalc = true;
+ }
+ }
+
+ if (!attribute_recalc) {
+ return geom;
+ }
+ }
+ }
+
+ geometry_synced.insert(geom);
+
+ geom->name = ustring(b_ob_info.object_data.name().c_str());
+
+ /* Store the shaders immediately for the object attribute code. */
+ geom->set_used_shaders(used_shaders);
+
+ auto sync_func = [=]() mutable {
+ if (progress.get_cancel())
+ return;
+
+ progress.set_sync_status("Synchronizing object", b_ob_info.real_object.name());
+
+ if (geom_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ sync_hair(b_depsgraph, b_ob_info, hair);
+ }
+ else if (geom_type == Geometry::VOLUME) {
+ Volume *volume = static_cast<Volume *>(geom);
+ sync_volume(b_ob_info, volume);
+ }
+ else {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ sync_mesh(b_depsgraph, b_ob_info, mesh);
+ }
+ };
+
+ /* Defer the actual geometry sync to the task_pool for multithreading */
+ if (task_pool) {
+ task_pool->push(sync_func);
+ }
+ else {
+ sync_func();
+ }
+
+ return geom;
+}
+
+void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
+ BObjectInfo &b_ob_info,
+ Object *object,
+ float motion_time,
+ bool use_particle_hair,
+ TaskPool *task_pool)
+{
+ /* Ensure we only sync instanced geometry once. */
+ Geometry *geom = object->get_geometry();
+
+ if (geometry_motion_synced.find(geom) != geometry_motion_synced.end() ||
+ geometry_motion_attribute_synced.find(geom) != geometry_motion_attribute_synced.end()) {
+ return;
+ }
+
+ geometry_motion_synced.insert(geom);
+
+ /* Ensure we only motion sync geometry that also had geometry synced, to avoid
+ * unnecessary work and to ensure that its attributes were clear. */
+ if (geometry_synced.find(geom) == geometry_synced.end())
+ return;
+
+ /* Find time matching motion step required by geometry. */
+ int motion_step = geom->motion_step(motion_time);
+ if (motion_step < 0) {
+ return;
+ }
+
+ auto sync_func = [=]() mutable {
+ if (progress.get_cancel())
+ return;
+
+ if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
+ Hair *hair = static_cast<Hair *>(geom);
+ sync_hair_motion(b_depsgraph, b_ob_info, hair, motion_step);
+ }
+ else if (b_ob_info.object_data.is_a(&RNA_Volume) ||
+ object_fluid_gas_domain_find(b_ob_info.real_object)) {
+ /* No volume motion blur support yet. */
+ }
+ else {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ sync_mesh_motion(b_depsgraph, b_ob_info, mesh, motion_step);
+ }
+ };
+
+ /* Defer the actual geometry sync to the task_pool for multithreading */
+ if (task_pool) {
+ task_pool->push(sync_func);
+ }
+ else {
+ sync_func();
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/id_map.h b/intern/cycles/blender/id_map.h
new file mode 100644
index 00000000000..c1b800026c3
--- /dev/null
+++ b/intern/cycles/blender/id_map.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLENDER_ID_MAP_H__
+#define __BLENDER_ID_MAP_H__
+
+#include <string.h>
+
+#include "scene/geometry.h"
+#include "scene/scene.h"
+
+#include "util/map.h"
+#include "util/set.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* ID Map
+ *
+ * Utility class to map between Blender datablocks and Cycles data structures,
+ * and keep track of recalc tags from the dependency graph. */
+
+template<typename K, typename T> class id_map {
+ public:
+ id_map(Scene *scene_) : scene(scene_)
+ {
+ }
+
+ ~id_map()
+ {
+ set<T *> nodes;
+
+ typename map<K, T *>::iterator jt;
+ for (jt = b_map.begin(); jt != b_map.end(); jt++) {
+ nodes.insert(jt->second);
+ }
+
+ scene->delete_nodes(nodes);
+ }
+
+ T *find(const BL::ID &id)
+ {
+ return find(id.ptr.owner_id);
+ }
+
+ T *find(const K &key)
+ {
+ if (b_map.find(key) != b_map.end()) {
+ T *data = b_map[key];
+ return data;
+ }
+
+ return NULL;
+ }
+
+ void set_recalc(const BL::ID &id)
+ {
+ b_recalc.insert(id.ptr.data);
+ }
+
+ void set_recalc(void *id_ptr)
+ {
+ b_recalc.insert(id_ptr);
+ }
+
+ bool has_recalc()
+ {
+ return !(b_recalc.empty());
+ }
+
+ void pre_sync()
+ {
+ used_set.clear();
+ }
+
+ /* Add new data. */
+ void add(const K &key, T *data)
+ {
+ assert(find(key) == NULL);
+ b_map[key] = data;
+ used(data);
+ }
+
+ /* Update existing data. */
+ bool update(T *data, const BL::ID &id)
+ {
+ return update(data, id, id);
+ }
+ bool update(T *data, const BL::ID &id, const BL::ID &parent)
+ {
+ bool recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
+ if (parent.ptr.data && parent.ptr.data != id.ptr.data) {
+ recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
+ }
+ used(data);
+ return recalc;
+ }
+
+ /* Combined add and update as needed. */
+ bool add_or_update(T **r_data, const BL::ID &id)
+ {
+ return add_or_update(r_data, id, id, id.ptr.owner_id);
+ }
+ bool add_or_update(T **r_data, const BL::ID &id, const K &key)
+ {
+ return add_or_update(r_data, id, id, key);
+ }
+ bool add_or_update(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key)
+ {
+ T *data = find(key);
+ bool recalc;
+
+ if (!data) {
+ /* Add data if it didn't exist yet. */
+ data = scene->create_node<T>();
+ add(key, data);
+ recalc = true;
+ }
+ else {
+ /* check if updated needed. */
+ recalc = update(data, id, parent);
+ }
+
+ *r_data = data;
+ return recalc;
+ }
+
+ /* Combined add or update for convenience. */
+
+ bool is_used(const K &key)
+ {
+ T *data = find(key);
+ return (data) ? used_set.find(data) != used_set.end() : false;
+ }
+
+ void used(T *data)
+ {
+ /* tag data as still in use */
+ used_set.insert(data);
+ }
+
+ void set_default(T *data)
+ {
+ b_map[NULL] = data;
+ }
+
+ void post_sync(bool do_delete = true)
+ {
+ map<K, T *> new_map;
+ typedef pair<const K, T *> TMapPair;
+ typename map<K, T *>::iterator jt;
+
+ for (jt = b_map.begin(); jt != b_map.end(); jt++) {
+ TMapPair &pair = *jt;
+
+ if (do_delete && used_set.find(pair.second) == used_set.end()) {
+ scene->delete_node(pair.second);
+ }
+ else {
+ new_map[pair.first] = pair.second;
+ }
+ }
+
+ used_set.clear();
+ b_recalc.clear();
+ b_map = new_map;
+ }
+
+ const map<K, T *> &key_to_scene_data()
+ {
+ return b_map;
+ }
+
+ protected:
+ map<K, T *> b_map;
+ set<T *> used_set;
+ set<void *> b_recalc;
+ Scene *scene;
+};
+
+/* Object Key
+ *
+ * To uniquely identify instances, we use the parent, object and persistent instance ID.
+ * We also export separate object for a mesh and its particle hair. */
+
+enum { OBJECT_PERSISTENT_ID_SIZE = 8 /* MAX_DUPLI_RECUR in Blender. */ };
+
+struct ObjectKey {
+ void *parent;
+ int id[OBJECT_PERSISTENT_ID_SIZE];
+ void *ob;
+ bool use_particle_hair;
+
+ ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_, bool use_particle_hair_)
+ : parent(parent_), ob(ob_), use_particle_hair(use_particle_hair_)
+ {
+ if (id_)
+ memcpy(id, id_, sizeof(id));
+ else
+ memset(id, 0, sizeof(id));
+ }
+
+ bool operator<(const ObjectKey &k) const
+ {
+ if (ob < k.ob) {
+ return true;
+ }
+ else if (ob == k.ob) {
+ if (parent < k.parent) {
+ return true;
+ }
+ else if (parent == k.parent) {
+ if (use_particle_hair < k.use_particle_hair) {
+ return true;
+ }
+ else if (use_particle_hair == k.use_particle_hair) {
+ return memcmp(id, k.id, sizeof(id)) < 0;
+ }
+ }
+ }
+
+ return false;
+ }
+};
+
+/* Geometry Key
+ *
+ * We export separate geometry for a mesh and its particle hair, so key needs to
+ * distinguish between them. */
+
+struct GeometryKey {
+ void *id;
+ Geometry::Type geometry_type;
+
+ GeometryKey(void *id, Geometry::Type geometry_type) : id(id), geometry_type(geometry_type)
+ {
+ }
+
+ bool operator<(const GeometryKey &k) const
+ {
+ if (id < k.id) {
+ return true;
+ }
+ else if (id == k.id) {
+ if (geometry_type < k.geometry_type) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+};
+
+/* Particle System Key */
+
+struct ParticleSystemKey {
+ void *ob;
+ int id[OBJECT_PERSISTENT_ID_SIZE];
+
+ ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) : ob(ob_)
+ {
+ if (id_)
+ memcpy(id, id_, sizeof(id));
+ else
+ memset(id, 0, sizeof(id));
+ }
+
+ bool operator<(const ParticleSystemKey &k) const
+ {
+ /* first id is particle index, we don't compare that */
+ if (ob < k.ob)
+ return true;
+ else if (ob == k.ob)
+ return memcmp(id + 1, k.id + 1, sizeof(int) * (OBJECT_PERSISTENT_ID_SIZE - 1)) < 0;
+
+ return false;
+ }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_ID_MAP_H__ */
diff --git a/intern/cycles/blender/image.cpp b/intern/cycles/blender/image.cpp
new file mode 100644
index 00000000000..3ea3a47c1f4
--- /dev/null
+++ b/intern/cycles/blender/image.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "blender/image.h"
+#include "blender/session.h"
+#include "blender/util.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Packed Images */
+
+BlenderImageLoader::BlenderImageLoader(BL::Image b_image, int frame)
+ : b_image(b_image), frame(frame), free_cache(!b_image.has_data())
+{
+}
+
+bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
+{
+ metadata.width = b_image.size()[0];
+ metadata.height = b_image.size()[1];
+ metadata.depth = 1;
+ metadata.channels = b_image.channels();
+
+ if (b_image.is_float()) {
+ if (metadata.channels == 1) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT;
+ }
+ else if (metadata.channels == 4) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
+ }
+ else {
+ return false;
+ }
+
+ /* Float images are already converted on the Blender side,
+ * no need to do anything in Cycles. */
+ metadata.colorspace = u_colorspace_raw;
+ }
+ else {
+ if (metadata.channels == 1) {
+ metadata.type = IMAGE_DATA_TYPE_BYTE;
+ }
+ else if (metadata.channels == 4) {
+ metadata.type = IMAGE_DATA_TYPE_BYTE4;
+ }
+ else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha)
+{
+ const size_t num_pixels = ((size_t)metadata.width) * metadata.height;
+ const int channels = metadata.channels;
+ const int tile = 0; /* TODO(lukas): Support tiles here? */
+
+ if (b_image.is_float()) {
+ /* image data */
+ float *image_pixels;
+ image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile);
+
+ if (image_pixels && num_pixels * channels == pixels_size) {
+ memcpy(pixels, image_pixels, pixels_size * sizeof(float));
+ }
+ else {
+ if (channels == 1) {
+ memset(pixels, 0, num_pixels * sizeof(float));
+ }
+ else {
+ const size_t num_pixels_safe = pixels_size / channels;
+ float *fp = (float *)pixels;
+ for (int i = 0; i < num_pixels_safe; i++, fp += channels) {
+ fp[0] = 1.0f;
+ fp[1] = 0.0f;
+ fp[2] = 1.0f;
+ if (channels == 4) {
+ fp[3] = 1.0f;
+ }
+ }
+ }
+ }
+
+ if (image_pixels) {
+ MEM_freeN(image_pixels);
+ }
+ }
+ else {
+ unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile);
+
+ if (image_pixels && num_pixels * channels == pixels_size) {
+ memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
+ }
+ else {
+ if (channels == 1) {
+ memset(pixels, 0, pixels_size * sizeof(unsigned char));
+ }
+ else {
+ const size_t num_pixels_safe = pixels_size / channels;
+ unsigned char *cp = (unsigned char *)pixels;
+ for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) {
+ cp[0] = 255;
+ cp[1] = 0;
+ cp[2] = 255;
+ if (channels == 4) {
+ cp[3] = 255;
+ }
+ }
+ }
+ }
+
+ if (image_pixels) {
+ MEM_freeN(image_pixels);
+ }
+
+ if (associate_alpha) {
+ /* Premultiply, byte images are always straight for Blender. */
+ unsigned char *cp = (unsigned char *)pixels;
+ for (size_t i = 0; i < num_pixels; i++, cp += channels) {
+ cp[0] = (cp[0] * cp[3]) / 255;
+ cp[1] = (cp[1] * cp[3]) / 255;
+ cp[2] = (cp[2] * cp[3]) / 255;
+ }
+ }
+ }
+
+ /* Free image buffers to save memory during render. */
+ if (free_cache) {
+ b_image.buffers_free();
+ }
+
+ return true;
+}
+
+string BlenderImageLoader::name() const
+{
+ return BL::Image(b_image).name();
+}
+
+bool BlenderImageLoader::equals(const ImageLoader &other) const
+{
+ const BlenderImageLoader &other_loader = (const BlenderImageLoader &)other;
+ return b_image == other_loader.b_image && frame == other_loader.frame;
+}
+
+/* Point Density */
+
+BlenderPointDensityLoader::BlenderPointDensityLoader(BL::Depsgraph b_depsgraph,
+ BL::ShaderNodeTexPointDensity b_node)
+ : b_depsgraph(b_depsgraph), b_node(b_node)
+{
+}
+
+bool BlenderPointDensityLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
+{
+ metadata.channels = 4;
+ metadata.width = b_node.resolution();
+ metadata.height = metadata.width;
+ metadata.depth = metadata.width;
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
+ return true;
+}
+
+bool BlenderPointDensityLoader::load_pixels(const ImageMetaData &,
+ void *pixels,
+ const size_t,
+ const bool)
+{
+ int length;
+ b_node.calc_point_density(b_depsgraph, &length, (float **)&pixels);
+ return true;
+}
+
+void BlenderSession::builtin_images_load()
+{
+ /* Force builtin images to be loaded along with Blender data sync. This
+ * is needed because we may be reading from depsgraph evaluated data which
+ * can be freed by Blender before Cycles reads it.
+ *
+ * TODO: the assumption that no further access to builtin image data will
+ * happen is really weak, and likely to break in the future. We should find
+ * a better solution to hand over the data directly to the image manager
+ * instead of through callbacks whose timing is difficult to control. */
+ ImageManager *manager = session->scene->image_manager;
+ Device *device = session->device;
+ manager->device_load_builtin(device, session->scene, session->progress);
+}
+
+string BlenderPointDensityLoader::name() const
+{
+ return BL::ShaderNodeTexPointDensity(b_node).name();
+}
+
+bool BlenderPointDensityLoader::equals(const ImageLoader &other) const
+{
+ const BlenderPointDensityLoader &other_loader = (const BlenderPointDensityLoader &)other;
+ return b_node == other_loader.b_node && b_depsgraph == other_loader.b_depsgraph;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/image.h b/intern/cycles/blender/image.h
new file mode 100644
index 00000000000..6f1e72c21af
--- /dev/null
+++ b/intern/cycles/blender/image.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLENDER_IMAGE_H__
+#define __BLENDER_IMAGE_H__
+
+#include "RNA_blender_cpp.h"
+
+#include "scene/image.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BlenderImageLoader : public ImageLoader {
+ public:
+ BlenderImageLoader(BL::Image b_image, int frame);
+
+ bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
+ bool load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha) override;
+ string name() const override;
+ bool equals(const ImageLoader &other) const override;
+
+ BL::Image b_image;
+ int frame;
+ bool free_cache;
+};
+
+class BlenderPointDensityLoader : public ImageLoader {
+ public:
+ BlenderPointDensityLoader(BL::Depsgraph depsgraph, BL::ShaderNodeTexPointDensity b_node);
+
+ bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
+ bool load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha) override;
+ string name() const override;
+ bool equals(const ImageLoader &other) const override;
+
+ BL::Depsgraph b_depsgraph;
+ BL::ShaderNodeTexPointDensity b_node;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_IMAGE_H__ */
diff --git a/intern/cycles/blender/light.cpp b/intern/cycles/blender/light.cpp
new file mode 100644
index 00000000000..1e4cc0f1d14
--- /dev/null
+++ b/intern/cycles/blender/light.cpp
@@ -0,0 +1,205 @@
+
+
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/light.h"
+
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "util/hash.h"
+
+CCL_NAMESPACE_BEGIN
+
+void BlenderSync::sync_light(BL::Object &b_parent,
+ int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
+ BObjectInfo &b_ob_info,
+ int random_id,
+ Transform &tfm,
+ bool *use_portal)
+{
+ /* test if we need to sync */
+ ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, false);
+ BL::Light b_light(b_ob_info.object_data);
+
+ Light *light = light_map.find(key);
+
+ /* Check if the transform was modified, in case a linked collection is moved we do not get a
+ * specific depsgraph update (T88515). This also mimics the behavior for Objects. */
+ const bool tfm_updated = (light && light->get_tfm() != tfm);
+
+ /* Update if either object or light data changed. */
+ if (!light_map.add_or_update(&light, b_ob_info.real_object, b_parent, key) && !tfm_updated) {
+ Shader *shader;
+ if (!shader_map.add_or_update(&shader, b_light)) {
+ if (light->get_is_portal())
+ *use_portal = true;
+ return;
+ }
+ }
+
+ /* type */
+ switch (b_light.type()) {
+ case BL::Light::type_POINT: {
+ BL::PointLight b_point_light(b_light);
+ light->set_size(b_point_light.shadow_soft_size());
+ light->set_light_type(LIGHT_POINT);
+ break;
+ }
+ case BL::Light::type_SPOT: {
+ BL::SpotLight b_spot_light(b_light);
+ light->set_size(b_spot_light.shadow_soft_size());
+ light->set_light_type(LIGHT_SPOT);
+ light->set_spot_angle(b_spot_light.spot_size());
+ light->set_spot_smooth(b_spot_light.spot_blend());
+ break;
+ }
+ /* Hemi were removed from 2.8 */
+ // case BL::Light::type_HEMI: {
+ // light->type = LIGHT_DISTANT;
+ // light->size = 0.0f;
+ // break;
+ // }
+ case BL::Light::type_SUN: {
+ BL::SunLight b_sun_light(b_light);
+ light->set_angle(b_sun_light.angle());
+ light->set_light_type(LIGHT_DISTANT);
+ break;
+ }
+ case BL::Light::type_AREA: {
+ BL::AreaLight b_area_light(b_light);
+ light->set_size(1.0f);
+ light->set_axisu(transform_get_column(&tfm, 0));
+ light->set_axisv(transform_get_column(&tfm, 1));
+ light->set_sizeu(b_area_light.size());
+ light->set_spread(b_area_light.spread());
+ switch (b_area_light.shape()) {
+ case BL::AreaLight::shape_SQUARE:
+ light->set_sizev(light->get_sizeu());
+ light->set_round(false);
+ break;
+ case BL::AreaLight::shape_RECTANGLE:
+ light->set_sizev(b_area_light.size_y());
+ light->set_round(false);
+ break;
+ case BL::AreaLight::shape_DISK:
+ light->set_sizev(light->get_sizeu());
+ light->set_round(true);
+ break;
+ case BL::AreaLight::shape_ELLIPSE:
+ light->set_sizev(b_area_light.size_y());
+ light->set_round(true);
+ break;
+ }
+ light->set_light_type(LIGHT_AREA);
+ break;
+ }
+ }
+
+ /* strength */
+ float3 strength = get_float3(b_light.color()) * BL::PointLight(b_light).energy();
+ light->set_strength(strength);
+
+ /* location and (inverted!) direction */
+ light->set_co(transform_get_column(&tfm, 3));
+ light->set_dir(-transform_get_column(&tfm, 2));
+ light->set_tfm(tfm);
+
+ /* shader */
+ array<Node *> used_shaders;
+ find_shader(b_light, used_shaders, scene->default_light);
+ light->set_shader(static_cast<Shader *>(used_shaders[0]));
+
+ /* shadow */
+ PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
+ light->set_cast_shadow(get_boolean(clight, "cast_shadow"));
+ light->set_use_mis(get_boolean(clight, "use_multiple_importance_sampling"));
+
+ light->set_max_bounces(get_int(clight, "max_bounces"));
+
+ if (b_ob_info.real_object != b_ob_info.iter_object) {
+ light->set_random_id(random_id);
+ }
+ else {
+ light->set_random_id(hash_uint2(hash_string(b_ob_info.real_object.name().c_str()), 0));
+ }
+
+ if (light->get_light_type() == LIGHT_AREA)
+ light->set_is_portal(get_boolean(clight, "is_portal"));
+ else
+ light->set_is_portal(false);
+
+ if (light->get_is_portal())
+ *use_portal = true;
+
+ /* visibility */
+ uint visibility = object_ray_visibility(b_ob_info.real_object);
+ light->set_use_camera((visibility & PATH_RAY_CAMERA) != 0);
+ light->set_use_diffuse((visibility & PATH_RAY_DIFFUSE) != 0);
+ light->set_use_glossy((visibility & PATH_RAY_GLOSSY) != 0);
+ light->set_use_transmission((visibility & PATH_RAY_TRANSMIT) != 0);
+ light->set_use_scatter((visibility & PATH_RAY_VOLUME_SCATTER) != 0);
+ light->set_is_shadow_catcher(b_ob_info.real_object.is_shadow_catcher());
+
+ /* tag */
+ light->tag_update(scene);
+}
+
+void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
+{
+ BL::World b_world = b_scene.world();
+
+ if (b_world) {
+ PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
+
+ enum SamplingMethod { SAMPLING_NONE = 0, SAMPLING_AUTOMATIC, SAMPLING_MANUAL, SAMPLING_NUM };
+ int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC);
+ bool sample_as_light = (sampling_method != SAMPLING_NONE);
+
+ if (sample_as_light || use_portal) {
+ /* test if we need to sync */
+ Light *light;
+ ObjectKey key(b_world, 0, b_world, false);
+
+ if (light_map.add_or_update(&light, b_world, b_world, key) || world_recalc ||
+ b_world.ptr.data != world_map) {
+ light->set_light_type(LIGHT_BACKGROUND);
+ if (sampling_method == SAMPLING_MANUAL) {
+ light->set_map_resolution(get_int(cworld, "sample_map_resolution"));
+ }
+ else {
+ light->set_map_resolution(0);
+ }
+ light->set_shader(scene->default_background);
+ light->set_use_mis(sample_as_light);
+ light->set_max_bounces(get_int(cworld, "max_bounces"));
+
+ /* force enable light again when world is resynced */
+ light->set_is_enabled(true);
+
+ light->tag_update(scene);
+ light_map.set_recalc(b_world);
+ }
+ }
+ }
+
+ world_map = b_world.ptr.data;
+ world_recalc = false;
+ viewport_parameters = BlenderViewportParameters(b_v3d, use_developer_ui);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/logging.cpp b/intern/cycles/blender/logging.cpp
new file mode 100644
index 00000000000..613b4084aa8
--- /dev/null
+++ b/intern/cycles/blender/logging.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011-2014 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "blender/CCL_api.h"
+#include "util/log.h"
+
+void CCL_init_logging(const char *argv0)
+{
+ ccl::util_logging_init(argv0);
+}
+
+void CCL_start_debug_logging()
+{
+ ccl::util_logging_start();
+}
+
+void CCL_logging_verbosity_set(int verbosity)
+{
+ ccl::util_logging_verbosity_set(verbosity);
+}
diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp
new file mode 100644
index 00000000000..b69bf88c213
--- /dev/null
+++ b/intern/cycles/blender/mesh.cpp
@@ -0,0 +1,1302 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "blender/session.h"
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "scene/camera.h"
+#include "scene/colorspace.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+
+#include "subd/patch.h"
+#include "subd/split.h"
+
+#include "util/algorithm.h"
+#include "util/color.h"
+#include "util/disjoint_set.h"
+#include "util/foreach.h"
+#include "util/hash.h"
+#include "util/log.h"
+#include "util/math.h"
+
+#include "mikktspace.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Tangent Space */
+
+struct MikkUserData {
+ MikkUserData(const BL::Mesh &b_mesh,
+ const char *layer_name,
+ const Mesh *mesh,
+ float3 *tangent,
+ float *tangent_sign)
+ : mesh(mesh), texface(NULL), orco(NULL), tangent(tangent), tangent_sign(tangent_sign)
+ {
+ const AttributeSet &attributes = (mesh->get_num_subd_faces()) ? mesh->subd_attributes :
+ mesh->attributes;
+
+ Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
+ vertex_normal = attr_vN->data_float3();
+
+ if (layer_name == NULL) {
+ Attribute *attr_orco = attributes.find(ATTR_STD_GENERATED);
+
+ if (attr_orco) {
+ orco = attr_orco->data_float3();
+ mesh_texture_space(*(BL::Mesh *)&b_mesh, orco_loc, orco_size);
+ }
+ }
+ else {
+ Attribute *attr_uv = attributes.find(ustring(layer_name));
+ if (attr_uv != NULL) {
+ texface = attr_uv->data_float2();
+ }
+ }
+ }
+
+ const Mesh *mesh;
+ int num_faces;
+
+ float3 *vertex_normal;
+ float2 *texface;
+ float3 *orco;
+ float3 orco_loc, orco_size;
+
+ float3 *tangent;
+ float *tangent_sign;
+};
+
+static int mikk_get_num_faces(const SMikkTSpaceContext *context)
+{
+ const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
+ if (userdata->mesh->get_num_subd_faces()) {
+ return userdata->mesh->get_num_subd_faces();
+ }
+ else {
+ return userdata->mesh->num_triangles();
+ }
+}
+
+static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const int face_num)
+{
+ const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
+ if (userdata->mesh->get_num_subd_faces()) {
+ const Mesh *mesh = userdata->mesh;
+ return mesh->get_subd_num_corners()[face_num];
+ }
+ else {
+ return 3;
+ }
+}
+
+static int mikk_vertex_index(const Mesh *mesh, const int face_num, const int vert_num)
+{
+ if (mesh->get_num_subd_faces()) {
+ const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
+ return mesh->get_subd_face_corners()[face.start_corner + vert_num];
+ }
+ else {
+ return mesh->get_triangles()[face_num * 3 + vert_num];
+ }
+}
+
+static int mikk_corner_index(const Mesh *mesh, const int face_num, const int vert_num)
+{
+ if (mesh->get_num_subd_faces()) {
+ const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
+ return face.start_corner + vert_num;
+ }
+ else {
+ return face_num * 3 + vert_num;
+ }
+}
+
+static void mikk_get_position(const SMikkTSpaceContext *context,
+ float P[3],
+ const int face_num,
+ const int vert_num)
+{
+ const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
+ const Mesh *mesh = userdata->mesh;
+ const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
+ const float3 vP = mesh->get_verts()[vertex_index];
+ P[0] = vP.x;
+ P[1] = vP.y;
+ P[2] = vP.z;
+}
+
+static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context,
+ float uv[2],
+ const int face_num,
+ const int vert_num)
+{
+ const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
+ const Mesh *mesh = userdata->mesh;
+ if (userdata->texface != NULL) {
+ const int corner_index = mikk_corner_index(mesh, face_num, vert_num);
+ float2 tfuv = userdata->texface[corner_index];
+ uv[0] = tfuv.x;
+ uv[1] = tfuv.y;
+ }
+ else if (userdata->orco != NULL) {
+ const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
+ const float3 orco_loc = userdata->orco_loc;
+ const float3 orco_size = userdata->orco_size;
+ const float3 orco = (userdata->orco[vertex_index] + orco_loc) / orco_size;
+
+ const float2 tmp = map_to_sphere(orco);
+ uv[0] = tmp.x;
+ uv[1] = tmp.y;
+ }
+ else {
+ uv[0] = 0.0f;
+ uv[1] = 0.0f;
+ }
+}
+
+static void mikk_get_normal(const SMikkTSpaceContext *context,
+ float N[3],
+ const int face_num,
+ const int vert_num)
+{
+ const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
+ const Mesh *mesh = userdata->mesh;
+ float3 vN;
+ if (mesh->get_num_subd_faces()) {
+ const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
+ if (face.smooth) {
+ const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
+ vN = userdata->vertex_normal[vertex_index];
+ }
+ else {
+ vN = face.normal(mesh);
+ }
+ }
+ else {
+ if (mesh->get_smooth()[face_num]) {
+ const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
+ vN = userdata->vertex_normal[vertex_index];
+ }
+ else {
+ const Mesh::Triangle tri = mesh->get_triangle(face_num);
+ vN = tri.compute_normal(&mesh->get_verts()[0]);
+ }
+ }
+ N[0] = vN.x;
+ N[1] = vN.y;
+ N[2] = vN.z;
+}
+
+static void mikk_set_tangent_space(const SMikkTSpaceContext *context,
+ const float T[],
+ const float sign,
+ const int face_num,
+ const int vert_num)
+{
+ MikkUserData *userdata = (MikkUserData *)context->m_pUserData;
+ const Mesh *mesh = userdata->mesh;
+ const int corner_index = mikk_corner_index(mesh, face_num, vert_num);
+ userdata->tangent[corner_index] = make_float3(T[0], T[1], T[2]);
+ if (userdata->tangent_sign != NULL) {
+ userdata->tangent_sign[corner_index] = sign;
+ }
+}
+
+static void mikk_compute_tangents(
+ const BL::Mesh &b_mesh, const char *layer_name, Mesh *mesh, bool need_sign, bool active_render)
+{
+ /* Create tangent attributes. */
+ AttributeSet &attributes = (mesh->get_num_subd_faces()) ? mesh->subd_attributes :
+ mesh->attributes;
+ Attribute *attr;
+ ustring name;
+ if (layer_name != NULL) {
+ name = ustring((string(layer_name) + ".tangent").c_str());
+ }
+ else {
+ name = ustring("orco.tangent");
+ }
+ if (active_render) {
+ attr = attributes.add(ATTR_STD_UV_TANGENT, name);
+ }
+ else {
+ attr = attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
+ }
+ float3 *tangent = attr->data_float3();
+ /* Create bitangent sign attribute. */
+ float *tangent_sign = NULL;
+ if (need_sign) {
+ Attribute *attr_sign;
+ ustring name_sign;
+ if (layer_name != NULL) {
+ name_sign = ustring((string(layer_name) + ".tangent_sign").c_str());
+ }
+ else {
+ name_sign = ustring("orco.tangent_sign");
+ }
+
+ if (active_render) {
+ attr_sign = attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
+ }
+ else {
+ attr_sign = attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
+ }
+ tangent_sign = attr_sign->data_float();
+ }
+ /* Setup userdata. */
+ MikkUserData userdata(b_mesh, layer_name, mesh, tangent, tangent_sign);
+ /* Setup interface. */
+ SMikkTSpaceInterface sm_interface;
+ memset(&sm_interface, 0, sizeof(sm_interface));
+ sm_interface.m_getNumFaces = mikk_get_num_faces;
+ sm_interface.m_getNumVerticesOfFace = mikk_get_num_verts_of_face;
+ sm_interface.m_getPosition = mikk_get_position;
+ sm_interface.m_getTexCoord = mikk_get_texture_coordinate;
+ sm_interface.m_getNormal = mikk_get_normal;
+ sm_interface.m_setTSpaceBasic = mikk_set_tangent_space;
+ /* Setup context. */
+ SMikkTSpaceContext context;
+ memset(&context, 0, sizeof(context));
+ context.m_pUserData = &userdata;
+ context.m_pInterface = &sm_interface;
+ /* Compute tangents. */
+ genTangSpaceDefault(&context);
+}
+
+/* Create sculpt vertex color attributes. */
+static void attr_create_sculpt_vertex_color(Scene *scene,
+ Mesh *mesh,
+ BL::Mesh &b_mesh,
+ bool subdivision)
+{
+ for (BL::MeshVertColorLayer &l : b_mesh.sculpt_vertex_colors) {
+ const bool active_render = l.active_render();
+ AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
+ ustring vcol_name = ustring(l.name().c_str());
+
+ const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
+ mesh->need_attribute(scene, vcol_std);
+
+ if (!need_vcol) {
+ continue;
+ }
+
+ AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
+ Attribute *vcol_attr = attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_VERTEX);
+ vcol_attr->std = vcol_std;
+
+ float4 *cdata = vcol_attr->data_float4();
+ int numverts = b_mesh.vertices.length();
+
+ for (int i = 0; i < numverts; i++) {
+ *(cdata++) = get_float4(l.data[i].color());
+ }
+ }
+}
+
+template<typename TypeInCycles, typename GetValueAtIndex>
+static void fill_generic_attribute(BL::Mesh &b_mesh,
+ TypeInCycles *data,
+ const AttributeElement element,
+ const GetValueAtIndex &get_value_at_index)
+{
+ switch (element) {
+ case ATTR_ELEMENT_CORNER: {
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ const int index = t.index() * 3;
+ BL::Array<int, 3> loops = t.loops();
+ data[index] = get_value_at_index(loops[0]);
+ data[index + 1] = get_value_at_index(loops[1]);
+ data[index + 2] = get_value_at_index(loops[2]);
+ }
+ break;
+ }
+ case ATTR_ELEMENT_VERTEX: {
+ const int num_verts = b_mesh.vertices.length();
+ for (int i = 0; i < num_verts; i++) {
+ data[i] = get_value_at_index(i);
+ }
+ break;
+ }
+ case ATTR_ELEMENT_FACE: {
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ data[t.index()] = get_value_at_index(t.polygon_index());
+ }
+ break;
+ }
+ default: {
+ assert(false);
+ break;
+ }
+ }
+}
+
+static void attr_create_motion(Mesh *mesh, BL::Attribute &b_attribute, const float motion_scale)
+{
+ if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
+ (b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) {
+ return;
+ }
+
+ BL::FloatVectorAttribute b_vector_attribute(b_attribute);
+ const int numverts = mesh->get_verts().size();
+
+ /* Find or add attribute */
+ float3 *P = &mesh->get_verts()[0];
+ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (!attr_mP) {
+ attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+
+ /* Only export previous and next frame, we don't have any in between data. */
+ float motion_times[2] = {-1.0f, 1.0f};
+ for (int step = 0; step < 2; step++) {
+ const float relative_time = motion_times[step] * 0.5f * motion_scale;
+ float3 *mP = attr_mP->data_float3() + step * numverts;
+
+ for (int i = 0; i < numverts; i++) {
+ mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time;
+ }
+ }
+}
+
+static void attr_create_generic(Scene *scene,
+ Mesh *mesh,
+ BL::Mesh &b_mesh,
+ const bool subdivision,
+ const bool need_motion,
+ const float motion_scale)
+{
+ if (subdivision) {
+ /* TODO: Handle subdivision correctly. */
+ return;
+ }
+ AttributeSet &attributes = mesh->attributes;
+ static const ustring u_velocity("velocity");
+
+ for (BL::Attribute &b_attribute : b_mesh.attributes) {
+ const ustring name{b_attribute.name().c_str()};
+
+ if (need_motion && name == u_velocity) {
+ attr_create_motion(mesh, b_attribute, motion_scale);
+ }
+
+ if (!mesh->need_attribute(scene, name)) {
+ continue;
+ }
+ if (attributes.find(name)) {
+ continue;
+ }
+
+ const BL::Attribute::domain_enum b_domain = b_attribute.domain();
+ const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type();
+
+ AttributeElement element = ATTR_ELEMENT_NONE;
+ switch (b_domain) {
+ case BL::Attribute::domain_CORNER:
+ element = ATTR_ELEMENT_CORNER;
+ break;
+ case BL::Attribute::domain_POINT:
+ element = ATTR_ELEMENT_VERTEX;
+ break;
+ case BL::Attribute::domain_FACE:
+ element = ATTR_ELEMENT_FACE;
+ break;
+ default:
+ break;
+ }
+ if (element == ATTR_ELEMENT_NONE) {
+ /* Not supported. */
+ continue;
+ }
+ switch (b_data_type) {
+ case BL::Attribute::data_type_FLOAT: {
+ BL::FloatAttribute b_float_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeFloat, element);
+ float *data = attr->data_float();
+ fill_generic_attribute(
+ b_mesh, data, element, [&](int i) { return b_float_attribute.data[i].value(); });
+ break;
+ }
+ case BL::Attribute::data_type_BOOLEAN: {
+ BL::BoolAttribute b_bool_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeFloat, element);
+ float *data = attr->data_float();
+ fill_generic_attribute(
+ b_mesh, data, element, [&](int i) { return (float)b_bool_attribute.data[i].value(); });
+ break;
+ }
+ case BL::Attribute::data_type_INT: {
+ BL::IntAttribute b_int_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeFloat, element);
+ float *data = attr->data_float();
+ fill_generic_attribute(
+ b_mesh, data, element, [&](int i) { return (float)b_int_attribute.data[i].value(); });
+ break;
+ }
+ case BL::Attribute::data_type_FLOAT_VECTOR: {
+ BL::FloatVectorAttribute b_vector_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeVector, element);
+ float3 *data = attr->data_float3();
+ fill_generic_attribute(b_mesh, data, element, [&](int i) {
+ BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
+ return make_float3(v[0], v[1], v[2]);
+ });
+ break;
+ }
+ case BL::Attribute::data_type_FLOAT_COLOR: {
+ BL::FloatColorAttribute b_color_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeRGBA, element);
+ float4 *data = attr->data_float4();
+ fill_generic_attribute(b_mesh, data, element, [&](int i) {
+ BL::Array<float, 4> v = b_color_attribute.data[i].color();
+ return make_float4(v[0], v[1], v[2], v[3]);
+ });
+ break;
+ }
+ case BL::Attribute::data_type_FLOAT2: {
+ BL::Float2Attribute b_float2_attribute{b_attribute};
+ Attribute *attr = attributes.add(name, TypeFloat2, element);
+ float2 *data = attr->data_float2();
+ fill_generic_attribute(b_mesh, data, element, [&](int i) {
+ BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
+ return make_float2(v[0], v[1]);
+ });
+ break;
+ }
+ default:
+ /* Not supported. */
+ break;
+ }
+ }
+}
+
+/* Create vertex color attributes. */
+static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
+{
+ for (BL::MeshLoopColorLayer &l : b_mesh.vertex_colors) {
+ const bool active_render = l.active_render();
+ AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
+ ustring vcol_name = ustring(l.name().c_str());
+
+ const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
+ mesh->need_attribute(scene, vcol_std);
+
+ if (!need_vcol) {
+ continue;
+ }
+
+ Attribute *vcol_attr = NULL;
+
+ if (subdivision) {
+ if (active_render) {
+ vcol_attr = mesh->subd_attributes.add(vcol_std, vcol_name);
+ }
+ else {
+ vcol_attr = mesh->subd_attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
+ }
+
+ uchar4 *cdata = vcol_attr->data_uchar4();
+
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ int n = p.loop_total();
+ for (int i = 0; i < n; i++) {
+ float4 color = get_float4(l.data[p.loop_start() + i].color());
+ /* Compress/encode vertex color using the sRGB curve. */
+ *(cdata++) = color_float4_to_uchar4(color);
+ }
+ }
+ }
+ else {
+ if (active_render) {
+ vcol_attr = mesh->attributes.add(vcol_std, vcol_name);
+ }
+ else {
+ vcol_attr = mesh->attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
+ }
+
+ uchar4 *cdata = vcol_attr->data_uchar4();
+
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ int3 li = get_int3(t.loops());
+ float4 c1 = get_float4(l.data[li[0]].color());
+ float4 c2 = get_float4(l.data[li[1]].color());
+ float4 c3 = get_float4(l.data[li[2]].color());
+
+ /* Compress/encode vertex color using the sRGB curve. */
+ cdata[0] = color_float4_to_uchar4(c1);
+ cdata[1] = color_float4_to_uchar4(c2);
+ cdata[2] = color_float4_to_uchar4(c3);
+
+ cdata += 3;
+ }
+ }
+ }
+}
+
+/* Create uv map attributes. */
+static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
+{
+ if (b_mesh.uv_layers.length() != 0) {
+ for (BL::MeshUVLoopLayer &l : b_mesh.uv_layers) {
+ const bool active_render = l.active_render();
+ AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
+ ustring uv_name = ustring(l.name().c_str());
+ AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE;
+ ustring tangent_name = ustring((string(l.name().c_str()) + ".tangent").c_str());
+
+ /* Denotes whether UV map was requested directly. */
+ const bool need_uv = mesh->need_attribute(scene, uv_name) ||
+ mesh->need_attribute(scene, uv_std);
+ /* Denotes whether tangent was requested directly. */
+ const bool need_tangent = mesh->need_attribute(scene, tangent_name) ||
+ (active_render && mesh->need_attribute(scene, tangent_std));
+
+ /* UV map */
+ /* NOTE: We create temporary UV layer if its needed for tangent but
+ * wasn't requested by other nodes in shaders.
+ */
+ Attribute *uv_attr = NULL;
+ if (need_uv || need_tangent) {
+ if (active_render) {
+ uv_attr = mesh->attributes.add(uv_std, uv_name);
+ }
+ else {
+ uv_attr = mesh->attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
+ }
+
+ float2 *fdata = uv_attr->data_float2();
+
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ int3 li = get_int3(t.loops());
+ fdata[0] = get_float2(l.data[li[0]].uv());
+ fdata[1] = get_float2(l.data[li[1]].uv());
+ fdata[2] = get_float2(l.data[li[2]].uv());
+ fdata += 3;
+ }
+ }
+
+ /* UV tangent */
+ if (need_tangent) {
+ AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE;
+ ustring sign_name = ustring((string(l.name().c_str()) + ".tangent_sign").c_str());
+ bool need_sign = (mesh->need_attribute(scene, sign_name) ||
+ mesh->need_attribute(scene, sign_std));
+ mikk_compute_tangents(b_mesh, l.name().c_str(), mesh, need_sign, active_render);
+ }
+ /* Remove temporarily created UV attribute. */
+ if (!need_uv && uv_attr != NULL) {
+ mesh->attributes.remove(uv_attr);
+ }
+ }
+ }
+ else if (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
+ bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
+ mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true);
+ if (!mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+ mesh->attributes.remove(ATTR_STD_GENERATED);
+ }
+ }
+}
+
+static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivide_uvs)
+{
+ if (b_mesh.uv_layers.length() != 0) {
+ BL::Mesh::uv_layers_iterator l;
+ int i = 0;
+
+ for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) {
+ bool active_render = l->active_render();
+ AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
+ ustring uv_name = ustring(l->name().c_str());
+ AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE;
+ ustring tangent_name = ustring((string(l->name().c_str()) + ".tangent").c_str());
+
+ /* Denotes whether UV map was requested directly. */
+ const bool need_uv = mesh->need_attribute(scene, uv_name) ||
+ mesh->need_attribute(scene, uv_std);
+ /* Denotes whether tangent was requested directly. */
+ const bool need_tangent = mesh->need_attribute(scene, tangent_name) ||
+ (active_render && mesh->need_attribute(scene, tangent_std));
+
+ Attribute *uv_attr = NULL;
+
+ /* UV map */
+ if (need_uv || need_tangent) {
+ if (active_render)
+ uv_attr = mesh->subd_attributes.add(uv_std, uv_name);
+ else
+ uv_attr = mesh->subd_attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
+
+ if (subdivide_uvs) {
+ uv_attr->flags |= ATTR_SUBDIVIDED;
+ }
+
+ float2 *fdata = uv_attr->data_float2();
+
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ int n = p.loop_total();
+ for (int j = 0; j < n; j++) {
+ *(fdata++) = get_float2(l->data[p.loop_start() + j].uv());
+ }
+ }
+ }
+
+ /* UV tangent */
+ if (need_tangent) {
+ AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE;
+ ustring sign_name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str());
+ bool need_sign = (mesh->need_attribute(scene, sign_name) ||
+ mesh->need_attribute(scene, sign_std));
+ mikk_compute_tangents(b_mesh, l->name().c_str(), mesh, need_sign, active_render);
+ }
+ /* Remove temporarily created UV attribute. */
+ if (!need_uv && uv_attr != NULL) {
+ mesh->subd_attributes.remove(uv_attr);
+ }
+ }
+ }
+ else if (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
+ bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
+ mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true);
+ if (!mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+ mesh->subd_attributes.remove(ATTR_STD_GENERATED);
+ }
+ }
+}
+
+/* Create vertex pointiness attributes. */
+
+/* Compare vertices by sum of their coordinates. */
+class VertexAverageComparator {
+ public:
+ VertexAverageComparator(const array<float3> &verts) : verts_(verts)
+ {
+ }
+
+ bool operator()(const int &vert_idx_a, const int &vert_idx_b)
+ {
+ const float3 &vert_a = verts_[vert_idx_a];
+ const float3 &vert_b = verts_[vert_idx_b];
+ if (vert_a == vert_b) {
+ /* Special case for doubles, so we ensure ordering. */
+ return vert_idx_a > vert_idx_b;
+ }
+ const float x1 = vert_a.x + vert_a.y + vert_a.z;
+ const float x2 = vert_b.x + vert_b.y + vert_b.z;
+ return x1 < x2;
+ }
+
+ protected:
+ const array<float3> &verts_;
+};
+
+static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
+{
+ if (!mesh->need_attribute(scene, ATTR_STD_POINTINESS)) {
+ return;
+ }
+ const int num_verts = b_mesh.vertices.length();
+ if (num_verts == 0) {
+ return;
+ }
+ /* STEP 1: Find out duplicated vertices and point duplicates to a single
+ * original vertex.
+ */
+ vector<int> sorted_vert_indeices(num_verts);
+ for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ sorted_vert_indeices[vert_index] = vert_index;
+ }
+ VertexAverageComparator compare(mesh->get_verts());
+ sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare);
+ /* This array stores index of the original vertex for the given vertex
+ * index.
+ */
+ vector<int> vert_orig_index(num_verts);
+ for (int sorted_vert_index = 0; sorted_vert_index < num_verts; ++sorted_vert_index) {
+ const int vert_index = sorted_vert_indeices[sorted_vert_index];
+ const float3 &vert_co = mesh->get_verts()[vert_index];
+ bool found = false;
+ for (int other_sorted_vert_index = sorted_vert_index + 1; other_sorted_vert_index < num_verts;
+ ++other_sorted_vert_index) {
+ const int other_vert_index = sorted_vert_indeices[other_sorted_vert_index];
+ const float3 &other_vert_co = mesh->get_verts()[other_vert_index];
+ /* We are too far away now, we wouldn't have duplicate. */
+ if ((other_vert_co.x + other_vert_co.y + other_vert_co.z) -
+ (vert_co.x + vert_co.y + vert_co.z) >
+ 3 * FLT_EPSILON) {
+ break;
+ }
+ /* Found duplicate. */
+ if (len_squared(other_vert_co - vert_co) < FLT_EPSILON) {
+ found = true;
+ vert_orig_index[vert_index] = other_vert_index;
+ break;
+ }
+ }
+ if (!found) {
+ vert_orig_index[vert_index] = vert_index;
+ }
+ }
+ /* Make sure we always points to the very first orig vertex. */
+ for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ int orig_index = vert_orig_index[vert_index];
+ while (orig_index != vert_orig_index[orig_index]) {
+ orig_index = vert_orig_index[orig_index];
+ }
+ vert_orig_index[vert_index] = orig_index;
+ }
+ sorted_vert_indeices.free_memory();
+ /* STEP 2: Calculate vertex normals taking into account their possible
+ * duplicates which gets "welded" together.
+ */
+ vector<float3> vert_normal(num_verts, zero_float3());
+ /* First we accumulate all vertex normals in the original index. */
+ for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ const float3 normal = get_float3(b_mesh.vertices[vert_index].normal());
+ const int orig_index = vert_orig_index[vert_index];
+ vert_normal[orig_index] += normal;
+ }
+ /* Then we normalize the accumulated result and flush it to all duplicates
+ * as well.
+ */
+ for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ const int orig_index = vert_orig_index[vert_index];
+ vert_normal[vert_index] = normalize(vert_normal[orig_index]);
+ }
+ /* STEP 3: Calculate pointiness using single ring neighborhood. */
+ vector<int> counter(num_verts, 0);
+ vector<float> raw_data(num_verts, 0.0f);
+ vector<float3> edge_accum(num_verts, zero_float3());
+ BL::Mesh::edges_iterator e;
+ EdgeMap visited_edges;
+ int edge_index = 0;
+ memset(&counter[0], 0, sizeof(int) * counter.size());
+ for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) {
+ const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]],
+ v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]];
+ if (visited_edges.exists(v0, v1)) {
+ continue;
+ }
+ visited_edges.insert(v0, v1);
+ float3 co0 = get_float3(b_mesh.vertices[v0].co()), co1 = get_float3(b_mesh.vertices[v1].co());
+ float3 edge = normalize(co1 - co0);
+ edge_accum[v0] += edge;
+ edge_accum[v1] += -edge;
+ ++counter[v0];
+ ++counter[v1];
+ }
+ for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ const int orig_index = vert_orig_index[vert_index];
+ if (orig_index != vert_index) {
+ /* Skip duplicates, they'll be overwritten later on. */
+ continue;
+ }
+ if (counter[vert_index] > 0) {
+ const float3 normal = vert_normal[vert_index];
+ const float angle = safe_acosf(dot(normal, edge_accum[vert_index] / counter[vert_index]));
+ raw_data[vert_index] = angle * M_1_PI_F;
+ }
+ else {
+ raw_data[vert_index] = 0.0f;
+ }
+ }
+ /* STEP 3: Blur vertices to approximate 2 ring neighborhood. */
+ AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
+ Attribute *attr = attributes.add(ATTR_STD_POINTINESS);
+ float *data = attr->data_float();
+ memcpy(data, &raw_data[0], sizeof(float) * raw_data.size());
+ memset(&counter[0], 0, sizeof(int) * counter.size());
+ edge_index = 0;
+ visited_edges.clear();
+ for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) {
+ const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]],
+ v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]];
+ if (visited_edges.exists(v0, v1)) {
+ continue;
+ }
+ visited_edges.insert(v0, v1);
+ data[v0] += raw_data[v1];
+ data[v1] += raw_data[v0];
+ ++counter[v0];
+ ++counter[v1];
+ }
+ for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ data[vert_index] /= counter[vert_index] + 1;
+ }
+ /* STEP 4: Copy attribute to the duplicated vertices. */
+ for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ const int orig_index = vert_orig_index[vert_index];
+ data[vert_index] = data[orig_index];
+ }
+}
+
+/* The Random Per Island attribute is a random float associated with each
+ * connected component (island) of the mesh. The attribute is computed by
+ * first classifying the vertices into different sets using a Disjoint Set
+ * data structure. Then the index of the root of each vertex (Which is the
+ * representative of the set the vertex belongs to) is hashed and stored.
+ *
+ * We are using a face attribute to avoid interpolation during rendering,
+ * allowing the user to safely hash the output further. Had we used vertex
+ * attribute, the interpolation will introduce very slight variations,
+ * making the output unsafe to hash. */
+static void attr_create_random_per_island(Scene *scene,
+ Mesh *mesh,
+ BL::Mesh &b_mesh,
+ bool subdivision)
+{
+ if (!mesh->need_attribute(scene, ATTR_STD_RANDOM_PER_ISLAND)) {
+ return;
+ }
+
+ int number_of_vertices = b_mesh.vertices.length();
+ if (number_of_vertices == 0) {
+ return;
+ }
+
+ DisjointSet vertices_sets(number_of_vertices);
+
+ for (BL::MeshEdge &e : b_mesh.edges) {
+ vertices_sets.join(e.vertices()[0], e.vertices()[1]);
+ }
+
+ AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
+ Attribute *attribute = attributes.add(ATTR_STD_RANDOM_PER_ISLAND);
+ float *data = attribute->data_float();
+
+ if (!subdivision) {
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ data[t.index()] = hash_uint_to_float(vertices_sets.find(t.vertices()[0]));
+ }
+ }
+ else {
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ data[p.index()] = hash_uint_to_float(vertices_sets.find(p.vertices()[0]));
+ }
+ }
+}
+
+/* Create Mesh */
+
+static void create_mesh(Scene *scene,
+ Mesh *mesh,
+ BL::Mesh &b_mesh,
+ const array<Node *> &used_shaders,
+ const bool need_motion,
+ const float motion_scale,
+ const bool subdivision = false,
+ const bool subdivide_uvs = true)
+{
+ /* count vertices and faces */
+ int numverts = b_mesh.vertices.length();
+ int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length();
+ int numtris = 0;
+ int numcorners = 0;
+ int numngons = 0;
+ bool use_loop_normals = b_mesh.use_auto_smooth() &&
+ (mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK);
+
+ /* If no faces, create empty mesh. */
+ if (numfaces == 0) {
+ return;
+ }
+
+ if (!subdivision) {
+ numtris = numfaces;
+ }
+ else {
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ numngons += (p.loop_total() == 4) ? 0 : 1;
+ numcorners += p.loop_total();
+ }
+ }
+
+ /* allocate memory */
+ if (subdivision) {
+ mesh->reserve_subd_faces(numfaces, numngons, numcorners);
+ }
+
+ mesh->reserve_mesh(numverts, numtris);
+
+ /* create vertex coordinates and normals */
+ BL::Mesh::vertices_iterator v;
+ for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
+ mesh->add_vertex(get_float3(v->co()));
+
+ AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
+ Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL);
+ float3 *N = attr_N->data_float3();
+
+ for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
+ *N = get_float3(v->normal());
+ N = attr_N->data_float3();
+
+ /* create generated coordinates from undeformed coordinates */
+ const bool need_default_tangent = (subdivision == false) && (b_mesh.uv_layers.length() == 0) &&
+ (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT));
+ if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) {
+ Attribute *attr = attributes.add(ATTR_STD_GENERATED);
+ attr->flags |= ATTR_SUBDIVIDED;
+
+ float3 loc, size;
+ mesh_texture_space(b_mesh, loc, size);
+
+ float3 *generated = attr->data_float3();
+ size_t i = 0;
+
+ for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) {
+ generated[i++] = get_float3(v->undeformed_co()) * size - loc;
+ }
+ }
+
+ /* create faces */
+ if (!subdivision) {
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ BL::MeshPolygon p = b_mesh.polygons[t.polygon_index()];
+ int3 vi = get_int3(t.vertices());
+
+ int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
+ bool smooth = p.use_smooth() || use_loop_normals;
+
+ if (use_loop_normals) {
+ BL::Array<float, 9> loop_normals = t.split_normals();
+ for (int i = 0; i < 3; i++) {
+ N[vi[i]] = make_float3(
+ loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);
+ }
+ }
+
+ /* Create triangles.
+ *
+ * NOTE: Autosmooth is already taken care about.
+ */
+ mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
+ }
+ }
+ else {
+ vector<int> vi;
+
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ int n = p.loop_total();
+ int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
+ bool smooth = p.use_smooth() || use_loop_normals;
+
+ vi.resize(n);
+ for (int i = 0; i < n; i++) {
+ /* NOTE: Autosmooth is already taken care about. */
+ vi[i] = b_mesh.loops[p.loop_start() + i].vertex_index();
+ }
+
+ /* create subd faces */
+ mesh->add_subd_face(&vi[0], n, shader, smooth);
+ }
+ }
+
+ /* Create all needed attributes.
+ * The calculate functions will check whether they're needed or not.
+ */
+ attr_create_pointiness(scene, mesh, b_mesh, subdivision);
+ attr_create_vertex_color(scene, mesh, b_mesh, subdivision);
+ attr_create_sculpt_vertex_color(scene, mesh, b_mesh, subdivision);
+ attr_create_random_per_island(scene, mesh, b_mesh, subdivision);
+ attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale);
+
+ if (subdivision) {
+ attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs);
+ }
+ else {
+ attr_create_uv_map(scene, mesh, b_mesh);
+ }
+
+ /* For volume objects, create a matrix to transform from object space to
+ * mesh texture space. this does not work with deformations but that can
+ * probably only be done well with a volume grid mapping of coordinates. */
+ if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
+ Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
+ Transform *tfm = attr->data_transform();
+
+ float3 loc, size;
+ mesh_texture_space(b_mesh, loc, size);
+
+ *tfm = transform_translate(-loc) * transform_scale(size);
+ }
+}
+
+static void create_subd_mesh(Scene *scene,
+ Mesh *mesh,
+ BObjectInfo &b_ob_info,
+ BL::Mesh &b_mesh,
+ const array<Node *> &used_shaders,
+ const bool need_motion,
+ const float motion_scale,
+ float dicing_rate,
+ int max_subdivisions)
+{
+ BL::Object b_ob = b_ob_info.real_object;
+
+ BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]);
+ bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE;
+
+ create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true, subdivide_uvs);
+
+ /* export creases */
+ size_t num_creases = 0;
+
+ for (BL::MeshEdge &e : b_mesh.edges) {
+ if (e.crease() != 0.0f) {
+ num_creases++;
+ }
+ }
+
+ mesh->reserve_subd_creases(num_creases);
+
+ for (BL::MeshEdge &e : b_mesh.edges) {
+ if (e.crease() != 0.0f) {
+ mesh->add_crease(e.vertices()[0], e.vertices()[1], e.crease());
+ }
+ }
+
+ /* set subd params */
+ PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
+ float subd_dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
+
+ mesh->set_subd_dicing_rate(subd_dicing_rate);
+ mesh->set_subd_max_level(max_subdivisions);
+ mesh->set_subd_objecttoworld(get_transform(b_ob.matrix_world()));
+}
+
+/* Sync */
+
+/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
+ * things like velocity from cache modifier, fluid simulation).
+ *
+ * NOTE: This code is run prior to object motion blur initialization. so can not access properties
+ * set by `sync_object_motion_init()`. */
+static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
+{
+ const Scene::MotionType need_motion = scene->need_motion();
+ if (need_motion == Scene::MOTION_NONE) {
+ /* Simple case: neither motion pass nor motion blur is needed, no need in the motion related
+ * attributes. */
+ return false;
+ }
+
+ if (need_motion == Scene::MOTION_BLUR) {
+ /* A bit tricky and implicit case:
+ * - Motion blur is enabled in the scene, which implies specific number of time steps for
+ * objects.
+ * - If the object has motion blur disabled on it, it will have 0 time steps.
+ * - Motion attribute expects non-zero time steps.
+ *
+ * Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
+ PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
+ const bool use_motion = get_boolean(cobject, "use_motion_blur");
+ if (!use_motion) {
+ return false;
+ }
+ }
+
+ /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object
+ * level. */
+ return true;
+}
+
+void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh)
+{
+ /* make a copy of the shaders as the caller in the main thread still need them for syncing the
+ * attributes */
+ array<Node *> used_shaders = mesh->get_used_shaders();
+
+ Mesh new_mesh;
+ new_mesh.set_used_shaders(used_shaders);
+
+ if (view_layer.use_surfaces) {
+ /* Adaptive subdivision setup. Not for baking since that requires
+ * exact mapping to the Blender mesh. */
+ if (!scene->bake_manager->get_baking()) {
+ new_mesh.set_subdivision_type(
+ object_subdivision_type(b_ob_info.real_object, preview, experimental));
+ }
+
+ /* For some reason, meshes do not need this... */
+ bool need_undeformed = new_mesh.need_attribute(scene, ATTR_STD_GENERATED);
+ BL::Mesh b_mesh = object_to_mesh(
+ b_data, b_ob_info, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type());
+
+ if (b_mesh) {
+ /* Motion blur attribute is relative to seconds, we need it relative to frames. */
+ const bool need_motion = mesh_need_motion_attribute(b_ob_info, scene);
+ const float motion_scale = (need_motion) ?
+ scene->motion_shutter_time() /
+ (b_scene.render().fps() / b_scene.render().fps_base()) :
+ 0.0f;
+
+ /* Sync mesh itself. */
+ if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE)
+ create_subd_mesh(scene,
+ &new_mesh,
+ b_ob_info,
+ b_mesh,
+ new_mesh.get_used_shaders(),
+ need_motion,
+ motion_scale,
+ dicing_rate,
+ max_subdivisions);
+ else
+ create_mesh(scene,
+ &new_mesh,
+ b_mesh,
+ new_mesh.get_used_shaders(),
+ need_motion,
+ motion_scale,
+ false);
+
+ free_object_to_mesh(b_data, b_ob_info, b_mesh);
+ }
+ }
+
+ /* update original sockets */
+
+ mesh->clear_non_sockets();
+
+ for (const SocketType &socket : new_mesh.type->inputs) {
+ /* Those sockets are updated in sync_object, so do not modify them. */
+ if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
+ socket.name == "used_shaders") {
+ continue;
+ }
+ mesh->set_value(socket, new_mesh, socket);
+ }
+
+ mesh->attributes.update(std::move(new_mesh.attributes));
+ mesh->subd_attributes.update(std::move(new_mesh.subd_attributes));
+
+ mesh->set_num_subd_faces(new_mesh.get_num_subd_faces());
+
+ /* tag update */
+ bool rebuild = (mesh->triangles_is_modified()) || (mesh->subd_num_corners_is_modified()) ||
+ (mesh->subd_shader_is_modified()) || (mesh->subd_smooth_is_modified()) ||
+ (mesh->subd_ptex_offset_is_modified()) ||
+ (mesh->subd_start_corner_is_modified()) ||
+ (mesh->subd_face_corners_is_modified());
+
+ mesh->tag_update(scene, rebuild);
+}
+
+void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
+ BObjectInfo &b_ob_info,
+ Mesh *mesh,
+ int motion_step)
+{
+ /* Skip if no vertices were exported. */
+ size_t numverts = mesh->get_verts().size();
+ if (numverts == 0) {
+ return;
+ }
+
+ /* Skip objects without deforming modifiers. this is not totally reliable,
+ * would need a more extensive check to see which objects are animated. */
+ BL::Mesh b_mesh(PointerRNA_NULL);
+ if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
+ /* get derived mesh */
+ b_mesh = object_to_mesh(b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
+ }
+
+ const std::string ob_name = b_ob_info.real_object.name();
+
+ /* TODO(sergey): Perform preliminary check for number of vertices. */
+ if (b_mesh) {
+ /* Export deformed coordinates. */
+ /* Find attributes. */
+ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
+ Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
+ bool new_attribute = false;
+ /* Add new attributes if they don't exist already. */
+ if (!attr_mP) {
+ attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_N)
+ attr_mN = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
+
+ new_attribute = true;
+ }
+ /* Load vertex data from mesh. */
+ float3 *mP = attr_mP->data_float3() + motion_step * numverts;
+ float3 *mN = (attr_mN) ? attr_mN->data_float3() + motion_step * numverts : NULL;
+ /* NOTE: We don't copy more that existing amount of vertices to prevent
+ * possible memory corruption.
+ */
+ BL::Mesh::vertices_iterator v;
+ int i = 0;
+ for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i) {
+ mP[i] = get_float3(v->co());
+ if (mN)
+ mN[i] = get_float3(v->normal());
+ }
+ if (new_attribute) {
+ /* In case of new attribute, we verify if there really was any motion. */
+ if (b_mesh.vertices.length() != numverts ||
+ memcmp(mP, &mesh->get_verts()[0], sizeof(float3) * numverts) == 0) {
+ /* no motion, remove attributes again */
+ if (b_mesh.vertices.length() != numverts) {
+ VLOG(1) << "Topology differs, disabling motion blur for object " << ob_name;
+ }
+ else {
+ VLOG(1) << "No actual deformation motion for object " << ob_name;
+ }
+ mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mN)
+ mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
+ }
+ else if (motion_step > 0) {
+ VLOG(1) << "Filling deformation motion for object " << ob_name;
+ /* motion, fill up previous steps that we might have skipped because
+ * they had no motion, but we need them anyway now */
+ float3 *P = &mesh->get_verts()[0];
+ float3 *N = (attr_N) ? attr_N->data_float3() : NULL;
+ for (int step = 0; step < motion_step; step++) {
+ memcpy(attr_mP->data_float3() + step * numverts, P, sizeof(float3) * numverts);
+ if (attr_mN)
+ memcpy(attr_mN->data_float3() + step * numverts, N, sizeof(float3) * numverts);
+ }
+ }
+ }
+ else {
+ if (b_mesh.vertices.length() != numverts) {
+ VLOG(1) << "Topology differs, discarding motion blur for object " << ob_name << " at time "
+ << motion_step;
+ memcpy(mP, &mesh->get_verts()[0], sizeof(float3) * numverts);
+ if (mN != NULL) {
+ memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts);
+ }
+ }
+ }
+
+ free_object_to_mesh(b_data, b_ob_info, b_mesh);
+ return;
+ }
+
+ /* No deformation on this frame, copy coordinates if other frames did have it. */
+ mesh->copy_center_to_motion_step(motion_step);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp
new file mode 100644
index 00000000000..9919b9d1836
--- /dev/null
+++ b/intern/cycles/blender/object.cpp
@@ -0,0 +1,769 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "blender/object_cull.h"
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "scene/alembic.h"
+#include "scene/camera.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/particles.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+
+#include "util/foreach.h"
+#include "util/hash.h"
+#include "util/log.h"
+#include "util/task.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Utilities */
+
+bool BlenderSync::BKE_object_is_modified(BL::Object &b_ob)
+{
+ /* test if we can instance or if the object is modified */
+ if (b_ob.type() == BL::Object::type_META) {
+ /* multi-user and dupli metaballs are fused, can't instance */
+ return true;
+ }
+ else if (ccl::BKE_object_is_modified(b_ob, b_scene, preview)) {
+ /* modifiers */
+ return true;
+ }
+ else {
+ /* object level material links */
+ for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
+ if (b_slot.link() == BL::MaterialSlot::link_OBJECT) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool BlenderSync::object_is_geometry(BL::Object &b_ob)
+{
+ BL::ID b_ob_data = b_ob.data();
+
+ if (!b_ob_data) {
+ return false;
+ }
+
+ BL::Object::type_enum type = b_ob.type();
+
+ if (type == BL::Object::type_VOLUME || type == BL::Object::type_HAIR) {
+ /* Will be exported attached to mesh. */
+ return true;
+ }
+ else if (type == BL::Object::type_CURVE) {
+ /* Skip exporting curves without faces, overhead can be
+ * significant if there are many for path animation. */
+ BL::Curve b_curve(b_ob_data);
+
+ return (b_curve.bevel_object() || b_curve.extrude() != 0.0f || b_curve.bevel_depth() != 0.0f ||
+ b_curve.dimensions() == BL::Curve::dimensions_2D || b_ob.modifiers.length());
+ }
+ else {
+ return (b_ob_data.is_a(&RNA_Mesh) || b_ob_data.is_a(&RNA_Curve) ||
+ b_ob_data.is_a(&RNA_MetaBall));
+ }
+}
+
+bool BlenderSync::object_is_light(BL::Object &b_ob)
+{
+ BL::ID b_ob_data = b_ob.data();
+
+ return (b_ob_data && b_ob_data.is_a(&RNA_Light));
+}
+
+void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object)
+{
+ /* Initialize motion blur for object, detecting if it's enabled and creating motion
+ * steps array if so. */
+ array<Transform> motion;
+ object->set_motion(motion);
+
+ Geometry *geom = object->get_geometry();
+ if (!geom) {
+ return;
+ }
+
+ int motion_steps = 0;
+ bool use_motion_blur = false;
+
+ Scene::MotionType need_motion = scene->need_motion();
+ if (need_motion == Scene::MOTION_BLUR) {
+ motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
+ if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
+ use_motion_blur = true;
+ }
+ }
+ else if (need_motion != Scene::MOTION_NONE) {
+ motion_steps = 3;
+ }
+
+ geom->set_use_motion_blur(use_motion_blur);
+ geom->set_motion_steps(motion_steps);
+
+ motion.resize(motion_steps, transform_empty());
+
+ if (motion_steps) {
+ motion[motion_steps / 2] = object->get_tfm();
+
+ /* update motion socket before trying to access object->motion_time */
+ object->set_motion(motion);
+
+ for (size_t step = 0; step < motion_steps; step++) {
+ motion_times.insert(object->motion_time(step));
+ }
+ }
+}
+
+Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
+ BL::ViewLayer &b_view_layer,
+ BL::DepsgraphObjectInstance &b_instance,
+ float motion_time,
+ bool use_particle_hair,
+ bool show_lights,
+ BlenderObjectCulling &culling,
+ bool *use_portal,
+ TaskPool *geom_task_pool)
+{
+ const bool is_instance = b_instance.is_instance();
+ BL::Object b_ob = b_instance.object();
+ BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object();
+ BObjectInfo b_ob_info{b_ob, is_instance ? b_instance.instance_object() : b_ob, b_ob.data()};
+ const bool motion = motion_time != 0.0f;
+ /*const*/ Transform tfm = get_transform(b_ob.matrix_world());
+ int *persistent_id = NULL;
+ BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id_array;
+ if (is_instance) {
+ persistent_id_array = b_instance.persistent_id();
+ persistent_id = persistent_id_array.data;
+ }
+
+ /* light is handled separately */
+ if (!motion && object_is_light(b_ob)) {
+ if (!show_lights) {
+ return NULL;
+ }
+
+ /* TODO: don't use lights for excluded layers used as mask layer,
+ * when dynamic overrides are back. */
+#if 0
+ if (!((layer_flag & view_layer.holdout_layer) && (layer_flag & view_layer.exclude_layer)))
+#endif
+ {
+ sync_light(b_parent,
+ persistent_id,
+ b_ob_info,
+ is_instance ? b_instance.random_id() : 0,
+ tfm,
+ use_portal);
+ }
+
+ return NULL;
+ }
+
+ /* only interested in object that we can create meshes from */
+ if (!object_is_geometry(b_ob)) {
+ return NULL;
+ }
+
+ /* Perform object culling. */
+ if (culling.test(scene, b_ob, tfm)) {
+ return NULL;
+ }
+
+ /* Visibility flags for both parent and child. */
+ PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+ bool use_holdout = b_parent.holdout_get(PointerRNA_NULL, b_view_layer);
+ uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY;
+
+ if (b_parent.ptr.data != b_ob.ptr.data) {
+ visibility &= object_ray_visibility(b_parent);
+ }
+
+ /* TODO: make holdout objects on excluded layer invisible for non-camera rays. */
+#if 0
+ if (use_holdout && (layer_flag & view_layer.exclude_layer)) {
+ visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA);
+ }
+#endif
+
+ /* Clear camera visibility for indirect only objects. */
+ bool use_indirect_only = !use_holdout &&
+ b_parent.indirect_only_get(PointerRNA_NULL, b_view_layer);
+ if (use_indirect_only) {
+ visibility &= ~PATH_RAY_CAMERA;
+ }
+
+ /* Don't export completely invisible objects. */
+ if (visibility == 0) {
+ return NULL;
+ }
+
+ /* Use task pool only for non-instances, since sync_dupli_particle accesses
+ * geometry. This restriction should be removed for better performance. */
+ TaskPool *object_geom_task_pool = (is_instance) ? NULL : geom_task_pool;
+
+ /* key to lookup object */
+ ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, use_particle_hair);
+ Object *object;
+
+ /* motion vector case */
+ if (motion) {
+ object = object_map.find(key);
+
+ if (object && object->use_motion()) {
+ /* Set transform at matching motion time step. */
+ int time_index = object->motion_step(motion_time);
+ if (time_index >= 0) {
+ array<Transform> motion = object->get_motion();
+ motion[time_index] = tfm;
+ object->set_motion(motion);
+ }
+
+ /* mesh deformation */
+ if (object->get_geometry())
+ sync_geometry_motion(
+ b_depsgraph, b_ob_info, object, motion_time, use_particle_hair, object_geom_task_pool);
+ }
+
+ return object;
+ }
+
+ /* test if we need to sync */
+ bool object_updated = object_map.add_or_update(&object, b_ob, b_parent, key) ||
+ (tfm != object->get_tfm());
+
+ /* mesh sync */
+ Geometry *geometry = sync_geometry(
+ b_depsgraph, b_ob_info, object_updated, use_particle_hair, object_geom_task_pool);
+ object->set_geometry(geometry);
+
+ /* special case not tracked by object update flags */
+
+ if (sync_object_attributes(b_instance, object)) {
+ object_updated = true;
+ }
+
+ /* holdout */
+ object->set_use_holdout(use_holdout);
+
+ object->set_visibility(visibility);
+
+ object->set_is_shadow_catcher(b_ob.is_shadow_catcher());
+
+ float shadow_terminator_shading_offset = get_float(cobject, "shadow_terminator_offset");
+ object->set_shadow_terminator_shading_offset(shadow_terminator_shading_offset);
+
+ float shadow_terminator_geometry_offset = get_float(cobject,
+ "shadow_terminator_geometry_offset");
+ object->set_shadow_terminator_geometry_offset(shadow_terminator_geometry_offset);
+
+ float ao_distance = get_float(cobject, "ao_distance");
+ if (ao_distance == 0.0f && b_parent.ptr.data != b_ob.ptr.data) {
+ PointerRNA cparent = RNA_pointer_get(&b_parent.ptr, "cycles");
+ ao_distance = get_float(cparent, "ao_distance");
+ }
+ object->set_ao_distance(ao_distance);
+
+ /* sync the asset name for Cryptomatte */
+ BL::Object parent = b_ob.parent();
+ ustring parent_name;
+ if (parent) {
+ while (parent.parent()) {
+ parent = parent.parent();
+ }
+ parent_name = parent.name();
+ }
+ else {
+ parent_name = b_ob.name();
+ }
+ object->set_asset_name(parent_name);
+
+ /* object sync
+ * transform comparison should not be needed, but duplis don't work perfect
+ * in the depsgraph and may not signal changes, so this is a workaround */
+ if (object->is_modified() || object_updated ||
+ (object->get_geometry() && object->get_geometry()->is_modified())) {
+ object->name = b_ob.name().c_str();
+ object->set_pass_id(b_ob.pass_index());
+ object->set_color(get_float3(b_ob.color()));
+ object->set_tfm(tfm);
+
+ /* dupli texture coordinates and random_id */
+ if (is_instance) {
+ object->set_dupli_generated(0.5f * get_float3(b_instance.orco()) -
+ make_float3(0.5f, 0.5f, 0.5f));
+ object->set_dupli_uv(get_float2(b_instance.uv()));
+ object->set_random_id(b_instance.random_id());
+ }
+ else {
+ object->set_dupli_generated(zero_float3());
+ object->set_dupli_uv(zero_float2());
+ object->set_random_id(hash_uint2(hash_string(object->name.c_str()), 0));
+ }
+
+ object->tag_update(scene);
+ }
+
+ sync_object_motion_init(b_parent, b_ob, object);
+
+ if (is_instance) {
+ /* Sync possible particle data. */
+ sync_dupli_particle(b_parent, b_instance, object);
+ }
+
+ return object;
+}
+
+/* This function mirrors drw_uniform_property_lookup in draw_instance_data.cpp */
+static bool lookup_property(BL::ID b_id, const string &name, float4 *r_value)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ if (!RNA_path_resolve(&b_id.ptr, name.c_str(), &ptr, &prop)) {
+ return false;
+ }
+
+ if (prop == NULL) {
+ return false;
+ }
+
+ PropertyType type = RNA_property_type(prop);
+ int arraylen = RNA_property_array_length(&ptr, prop);
+
+ if (arraylen == 0) {
+ float value;
+
+ if (type == PROP_FLOAT)
+ value = RNA_property_float_get(&ptr, prop);
+ else if (type == PROP_INT)
+ value = static_cast<float>(RNA_property_int_get(&ptr, prop));
+ else
+ return false;
+
+ *r_value = make_float4(value, value, value, 1.0f);
+ return true;
+ }
+ else if (type == PROP_FLOAT && arraylen <= 4) {
+ *r_value = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
+ RNA_property_float_get_array(&ptr, prop, &r_value->x);
+ return true;
+ }
+
+ return false;
+}
+
+/* This function mirrors drw_uniform_attribute_lookup in draw_instance_data.cpp */
+static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance,
+ const string &name,
+ bool use_instancer)
+{
+ string idprop_name = string_printf("[\"%s\"]", name.c_str());
+ float4 value;
+
+ /* If requesting instance data, check the parent particle system and object. */
+ if (use_instancer && b_instance.is_instance()) {
+ BL::ParticleSystem b_psys = b_instance.particle_system();
+
+ if (b_psys) {
+ if (lookup_property(b_psys.settings(), idprop_name, &value) ||
+ lookup_property(b_psys.settings(), name, &value)) {
+ return value;
+ }
+ }
+ if (lookup_property(b_instance.parent(), idprop_name, &value) ||
+ lookup_property(b_instance.parent(), name, &value)) {
+ return value;
+ }
+ }
+
+ /* Check the object and mesh. */
+ BL::Object b_ob = b_instance.object();
+ BL::ID b_data = b_ob.data();
+
+ if (lookup_property(b_ob, idprop_name, &value) || lookup_property(b_ob, name, &value) ||
+ lookup_property(b_data, idprop_name, &value) || lookup_property(b_data, name, &value)) {
+ return value;
+ }
+
+ return make_float4(0.0f);
+}
+
+bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object)
+{
+ /* Find which attributes are needed. */
+ AttributeRequestSet requests = object->get_geometry()->needed_attributes();
+
+ /* Delete attributes that became unnecessary. */
+ vector<ParamValue> &attributes = object->attributes;
+ bool changed = false;
+
+ for (int i = attributes.size() - 1; i >= 0; i--) {
+ if (!requests.find(attributes[i].name())) {
+ attributes.erase(attributes.begin() + i);
+ changed = true;
+ }
+ }
+
+ /* Update attribute values. */
+ foreach (AttributeRequest &req, requests.requests) {
+ ustring name = req.name;
+
+ std::string real_name;
+ BlenderAttributeType type = blender_attribute_name_split_type(name, &real_name);
+
+ if (type != BL::ShaderNodeAttribute::attribute_type_GEOMETRY) {
+ bool use_instancer = (type == BL::ShaderNodeAttribute::attribute_type_INSTANCER);
+ float4 value = lookup_instance_property(b_instance, real_name, use_instancer);
+
+ /* Try finding the existing attribute value. */
+ ParamValue *param = NULL;
+
+ for (size_t i = 0; i < attributes.size(); i++) {
+ if (attributes[i].name() == name) {
+ param = &attributes[i];
+ break;
+ }
+ }
+
+ /* Replace or add the value. */
+ ParamValue new_param(name, TypeDesc::TypeFloat4, 1, &value);
+ assert(new_param.datasize() == sizeof(value));
+
+ if (!param) {
+ changed = true;
+ attributes.push_back(new_param);
+ }
+ else if (memcmp(param->data(), &value, sizeof(value)) != 0) {
+ changed = true;
+ *param = new_param;
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* Object Loop */
+
+void BlenderSync::sync_procedural(BL::Object &b_ob,
+ BL::MeshSequenceCacheModifier &b_mesh_cache,
+ bool has_subdivision_modifier)
+{
+#ifdef WITH_ALEMBIC
+ BL::CacheFile cache_file = b_mesh_cache.cache_file();
+ void *cache_file_key = cache_file.ptr.data;
+
+ AlembicProcedural *procedural = static_cast<AlembicProcedural *>(
+ procedural_map.find(cache_file_key));
+
+ if (procedural == nullptr) {
+ procedural = scene->create_node<AlembicProcedural>();
+ procedural_map.add(cache_file_key, procedural);
+ }
+ else {
+ procedural_map.used(procedural);
+ }
+
+ float current_frame = static_cast<float>(b_scene.frame_current());
+ if (cache_file.override_frame()) {
+ current_frame = cache_file.frame();
+ }
+
+ if (!cache_file.override_frame()) {
+ procedural->set_start_frame(static_cast<float>(b_scene.frame_start()));
+ procedural->set_end_frame(static_cast<float>(b_scene.frame_end()));
+ }
+
+ procedural->set_frame(current_frame);
+ procedural->set_frame_rate(b_scene.render().fps() / b_scene.render().fps_base());
+ procedural->set_frame_offset(cache_file.frame_offset());
+
+ string absolute_path = blender_absolute_path(b_data, b_ob, b_mesh_cache.cache_file().filepath());
+ procedural->set_filepath(ustring(absolute_path));
+
+ procedural->set_scale(cache_file.scale());
+
+ procedural->set_use_prefetch(cache_file.use_prefetch());
+ procedural->set_prefetch_cache_size(cache_file.prefetch_cache_size());
+
+ /* create or update existing AlembicObjects */
+ ustring object_path = ustring(b_mesh_cache.object_path());
+
+ AlembicObject *abc_object = procedural->get_or_create_object(object_path);
+
+ array<Node *> used_shaders = find_used_shaders(b_ob);
+ abc_object->set_used_shaders(used_shaders);
+
+ PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
+ const float subd_dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
+ abc_object->set_subd_dicing_rate(subd_dicing_rate);
+ abc_object->set_subd_max_level(max_subdivisions);
+
+ abc_object->set_ignore_subdivision(!has_subdivision_modifier);
+
+ if (abc_object->is_modified() || procedural->is_modified()) {
+ procedural->tag_update(scene);
+ }
+#else
+ (void)b_ob;
+ (void)b_mesh_cache;
+ (void)has_subdivision_modifier;
+#endif
+}
+
+void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
+ BL::SpaceView3D &b_v3d,
+ float motion_time)
+{
+ /* Task pool for multithreaded geometry sync. */
+ TaskPool geom_task_pool;
+
+ /* layer data */
+ bool motion = motion_time != 0.0f;
+
+ if (!motion) {
+ /* prepare for sync */
+ light_map.pre_sync();
+ geometry_map.pre_sync();
+ object_map.pre_sync();
+ procedural_map.pre_sync();
+ particle_system_map.pre_sync();
+ motion_times.clear();
+ }
+ else {
+ geometry_motion_synced.clear();
+ }
+
+ /* initialize culling */
+ BlenderObjectCulling culling(scene, b_scene);
+
+ /* object loop */
+ bool cancel = false;
+ bool use_portal = false;
+ const bool show_lights = BlenderViewportParameters(b_v3d, use_developer_ui).use_scene_lights;
+
+ BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
+ BL::Depsgraph::object_instances_iterator b_instance_iter;
+
+ for (b_depsgraph.object_instances.begin(b_instance_iter);
+ b_instance_iter != b_depsgraph.object_instances.end() && !cancel;
+ ++b_instance_iter) {
+ BL::DepsgraphObjectInstance b_instance = *b_instance_iter;
+ BL::Object b_ob = b_instance.object();
+
+ /* Viewport visibility. */
+ const bool show_in_viewport = !b_v3d || b_ob.visible_in_viewport_get(b_v3d);
+ if (show_in_viewport == false) {
+ continue;
+ }
+
+ /* Load per-object culling data. */
+ culling.init_object(scene, b_ob);
+
+ /* Ensure the object geom supporting the hair is processed before adding
+ * the hair processing task to the task pool, calling .to_mesh() on the
+ * same object in parallel does not work. */
+ const bool sync_hair = b_instance.show_particles() && object_has_particle_hair(b_ob);
+
+ /* Object itself. */
+ if (b_instance.show_self()) {
+#ifdef WITH_ALEMBIC
+ bool use_procedural = false;
+ bool has_subdivision_modifier = false;
+ BL::MeshSequenceCacheModifier b_mesh_cache(PointerRNA_NULL);
+
+ /* Experimental as Blender does not have good support for procedurals at the moment, also
+ * only available in preview renders since currently do not have a good cache policy, the
+ * data being loaded at once for all the frames. */
+ if (experimental && b_v3d) {
+ b_mesh_cache = object_mesh_cache_find(b_ob, &has_subdivision_modifier);
+ use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural();
+ }
+
+ if (use_procedural) {
+ /* Skip in the motion case, as generating motion blur data will be handled in the
+ * procedural. */
+ if (!motion) {
+ sync_procedural(b_ob, b_mesh_cache, has_subdivision_modifier);
+ }
+ }
+ else
+#endif
+ {
+ sync_object(b_depsgraph,
+ b_view_layer,
+ b_instance,
+ motion_time,
+ false,
+ show_lights,
+ culling,
+ &use_portal,
+ sync_hair ? NULL : &geom_task_pool);
+ }
+ }
+
+ /* Particle hair as separate object. */
+ if (sync_hair) {
+ sync_object(b_depsgraph,
+ b_view_layer,
+ b_instance,
+ motion_time,
+ true,
+ show_lights,
+ culling,
+ &use_portal,
+ &geom_task_pool);
+ }
+
+ cancel = progress.get_cancel();
+ }
+
+ geom_task_pool.wait_work();
+
+ progress.set_sync_status("");
+
+ if (!cancel && !motion) {
+ sync_background_light(b_v3d, use_portal);
+
+ /* Handle removed data and modified pointers, as this may free memory, delete Nodes in the
+ * right order to ensure that dependent data is freed after their users. Objects should be
+ * freed before particle systems and geometries. */
+ light_map.post_sync();
+ object_map.post_sync();
+ geometry_map.post_sync();
+ particle_system_map.post_sync();
+ procedural_map.post_sync();
+ }
+
+ if (motion)
+ geometry_motion_synced.clear();
+}
+
+void BlenderSync::sync_motion(BL::RenderSettings &b_render,
+ BL::Depsgraph &b_depsgraph,
+ BL::SpaceView3D &b_v3d,
+ BL::Object &b_override,
+ int width,
+ int height,
+ void **python_thread_state)
+{
+ if (scene->need_motion() == Scene::MOTION_NONE)
+ return;
+
+ /* get camera object here to deal with camera switch */
+ BL::Object b_cam = b_scene.camera();
+ if (b_override)
+ b_cam = b_override;
+
+ int frame_center = b_scene.frame_current();
+ float subframe_center = b_scene.frame_subframe();
+ float frame_center_delta = 0.0f;
+
+ if (scene->need_motion() != Scene::MOTION_PASS &&
+ scene->camera->get_motion_position() != Camera::MOTION_POSITION_CENTER) {
+ float shuttertime = scene->camera->get_shuttertime();
+ if (scene->camera->get_motion_position() == Camera::MOTION_POSITION_END) {
+ frame_center_delta = -shuttertime * 0.5f;
+ }
+ else {
+ assert(scene->camera->get_motion_position() == Camera::MOTION_POSITION_START);
+ frame_center_delta = shuttertime * 0.5f;
+ }
+
+ float time = frame_center + subframe_center + frame_center_delta;
+ int frame = (int)floorf(time);
+ float subframe = time - frame;
+ python_thread_state_restore(python_thread_state);
+ b_engine.frame_set(frame, subframe);
+ python_thread_state_save(python_thread_state);
+ if (b_cam) {
+ sync_camera_motion(b_render, b_cam, width, height, 0.0f);
+ }
+ sync_objects(b_depsgraph, b_v3d);
+ }
+
+ /* Insert motion times from camera. Motion times from other objects
+ * have already been added in a sync_objects call. */
+ if (b_cam) {
+ uint camera_motion_steps = object_motion_steps(b_cam, b_cam);
+ for (size_t step = 0; step < camera_motion_steps; step++) {
+ motion_times.insert(scene->camera->motion_time(step));
+ }
+ }
+
+ /* Check which geometry already has motion blur so it can be skipped. */
+ geometry_motion_attribute_synced.clear();
+ for (Geometry *geom : scene->geometry) {
+ if (geom->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
+ geometry_motion_attribute_synced.insert(geom);
+ }
+ }
+
+ /* note iteration over motion_times set happens in sorted order */
+ foreach (float relative_time, motion_times) {
+ /* center time is already handled. */
+ if (relative_time == 0.0f) {
+ continue;
+ }
+
+ VLOG(1) << "Synchronizing motion for the relative time " << relative_time << ".";
+
+ /* fixed shutter time to get previous and next frame for motion pass */
+ float shuttertime = scene->motion_shutter_time();
+
+ /* compute frame and subframe time */
+ float time = frame_center + subframe_center + frame_center_delta +
+ relative_time * shuttertime * 0.5f;
+ int frame = (int)floorf(time);
+ float subframe = time - frame;
+
+ /* change frame */
+ python_thread_state_restore(python_thread_state);
+ b_engine.frame_set(frame, subframe);
+ python_thread_state_save(python_thread_state);
+
+ /* Syncs camera motion if relative_time is one of the camera's motion times. */
+ sync_camera_motion(b_render, b_cam, width, height, relative_time);
+
+ /* sync object */
+ sync_objects(b_depsgraph, b_v3d, relative_time);
+ }
+
+ geometry_motion_attribute_synced.clear();
+
+ /* we need to set the python thread state again because this
+ * function assumes it is being executed from python and will
+ * try to save the thread state */
+ python_thread_state_restore(python_thread_state);
+ b_engine.frame_set(frame_center, subframe_center);
+ python_thread_state_save(python_thread_state);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/object_cull.cpp b/intern/cycles/blender/object_cull.cpp
new file mode 100644
index 00000000000..c2493be26dd
--- /dev/null
+++ b/intern/cycles/blender/object_cull.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdlib>
+
+#include "scene/camera.h"
+
+#include "blender/object_cull.h"
+#include "blender/util.h"
+
+CCL_NAMESPACE_BEGIN
+
+BlenderObjectCulling::BlenderObjectCulling(Scene *scene, BL::Scene &b_scene)
+ : use_scene_camera_cull_(false),
+ use_camera_cull_(false),
+ camera_cull_margin_(0.0f),
+ use_scene_distance_cull_(false),
+ use_distance_cull_(false),
+ distance_cull_margin_(0.0f)
+{
+ if (b_scene.render().use_simplify()) {
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+ use_scene_camera_cull_ = scene->camera->get_camera_type() != CAMERA_PANORAMA &&
+ !b_scene.render().use_multiview() &&
+ get_boolean(cscene, "use_camera_cull");
+ use_scene_distance_cull_ = scene->camera->get_camera_type() != CAMERA_PANORAMA &&
+ !b_scene.render().use_multiview() &&
+ get_boolean(cscene, "use_distance_cull");
+
+ camera_cull_margin_ = get_float(cscene, "camera_cull_margin");
+ distance_cull_margin_ = get_float(cscene, "distance_cull_margin");
+
+ if (distance_cull_margin_ == 0.0f) {
+ use_scene_distance_cull_ = false;
+ }
+ }
+}
+
+void BlenderObjectCulling::init_object(Scene *scene, BL::Object &b_ob)
+{
+ if (!use_scene_camera_cull_ && !use_scene_distance_cull_) {
+ return;
+ }
+
+ PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+
+ use_camera_cull_ = use_scene_camera_cull_ && get_boolean(cobject, "use_camera_cull");
+ use_distance_cull_ = use_scene_distance_cull_ && get_boolean(cobject, "use_distance_cull");
+
+ if (use_camera_cull_ || use_distance_cull_) {
+ /* Need to have proper projection matrix. */
+ scene->camera->update(scene);
+ }
+}
+
+bool BlenderObjectCulling::test(Scene *scene, BL::Object &b_ob, Transform &tfm)
+{
+ if (!use_camera_cull_ && !use_distance_cull_) {
+ return false;
+ }
+
+ /* Compute world space bounding box corners. */
+ float3 bb[8];
+ BL::Array<float, 24> boundbox = b_ob.bound_box();
+ for (int i = 0; i < 8; ++i) {
+ float3 p = make_float3(boundbox[3 * i + 0], boundbox[3 * i + 1], boundbox[3 * i + 2]);
+ bb[i] = transform_point(&tfm, p);
+ }
+
+ bool camera_culled = use_camera_cull_ && test_camera(scene, bb);
+ bool distance_culled = use_distance_cull_ && test_distance(scene, bb);
+
+ return ((camera_culled && distance_culled) || (camera_culled && !use_distance_cull_) ||
+ (distance_culled && !use_camera_cull_));
+}
+
+/* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order
+ * to reduce number of objects which are wrongly considered visible.
+ */
+bool BlenderObjectCulling::test_camera(Scene *scene, float3 bb[8])
+{
+ Camera *cam = scene->camera;
+ const ProjectionTransform &worldtondc = cam->worldtondc;
+ float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
+ bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+ bool all_behind = true;
+ for (int i = 0; i < 8; ++i) {
+ float3 p = bb[i];
+ float4 b = make_float4(p.x, p.y, p.z, 1.0f);
+ float4 c = make_float4(
+ dot(worldtondc.x, b), dot(worldtondc.y, b), dot(worldtondc.z, b), dot(worldtondc.w, b));
+ p = float4_to_float3(c / c.w);
+ if (c.z < 0.0f) {
+ p.x = 1.0f - p.x;
+ p.y = 1.0f - p.y;
+ }
+ if (c.z >= -camera_cull_margin_) {
+ all_behind = false;
+ }
+ bb_min = min(bb_min, p);
+ bb_max = max(bb_max, p);
+ }
+ if (all_behind) {
+ return true;
+ }
+ return (bb_min.x >= 1.0f + camera_cull_margin_ || bb_min.y >= 1.0f + camera_cull_margin_ ||
+ bb_max.x <= -camera_cull_margin_ || bb_max.y <= -camera_cull_margin_);
+}
+
+bool BlenderObjectCulling::test_distance(Scene *scene, float3 bb[8])
+{
+ float3 camera_position = transform_get_column(&scene->camera->get_matrix(), 3);
+ float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
+ bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+
+ /* Find min & max points for x & y & z on bounding box */
+ for (int i = 0; i < 8; ++i) {
+ float3 p = bb[i];
+ bb_min = min(bb_min, p);
+ bb_max = max(bb_max, p);
+ }
+
+ float3 closest_point = max(min(bb_max, camera_position), bb_min);
+ return (len_squared(camera_position - closest_point) >
+ distance_cull_margin_ * distance_cull_margin_);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/object_cull.h b/intern/cycles/blender/object_cull.h
new file mode 100644
index 00000000000..be3068ef4e7
--- /dev/null
+++ b/intern/cycles/blender/object_cull.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLENDER_OBJECT_CULL_H__
+#define __BLENDER_OBJECT_CULL_H__
+
+#include "blender/sync.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Scene;
+
+class BlenderObjectCulling {
+ public:
+ BlenderObjectCulling(Scene *scene, BL::Scene &b_scene);
+
+ void init_object(Scene *scene, BL::Object &b_ob);
+ bool test(Scene *scene, BL::Object &b_ob, Transform &tfm);
+
+ private:
+ bool test_camera(Scene *scene, float3 bb[8]);
+ bool test_distance(Scene *scene, float3 bb[8]);
+
+ bool use_scene_camera_cull_;
+ bool use_camera_cull_;
+ float camera_cull_margin_;
+ bool use_scene_distance_cull_;
+ bool use_distance_cull_;
+ float distance_cull_margin_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_OBJECT_CULL_H__ */
diff --git a/intern/cycles/blender/output_driver.cpp b/intern/cycles/blender/output_driver.cpp
new file mode 100644
index 00000000000..2b3586af668
--- /dev/null
+++ b/intern/cycles/blender/output_driver.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "blender/output_driver.h"
+
+CCL_NAMESPACE_BEGIN
+
+BlenderOutputDriver::BlenderOutputDriver(BL::RenderEngine &b_engine) : b_engine_(b_engine)
+{
+}
+
+BlenderOutputDriver::~BlenderOutputDriver()
+{
+}
+
+bool BlenderOutputDriver::read_render_tile(const Tile &tile)
+{
+ /* Get render result. */
+ BL::RenderResult b_rr = b_engine_.begin_result(tile.offset.x,
+ tile.offset.y,
+ tile.size.x,
+ tile.size.y,
+ tile.layer.c_str(),
+ tile.view.c_str());
+
+ /* Can happen if the intersected rectangle gives 0 width or height. */
+ if (b_rr.ptr.data == NULL) {
+ return false;
+ }
+
+ BL::RenderResult::layers_iterator b_single_rlay;
+ b_rr.layers.begin(b_single_rlay);
+
+ /* layer will be missing if it was disabled in the UI */
+ if (b_single_rlay == b_rr.layers.end()) {
+ return false;
+ }
+
+ BL::RenderLayer b_rlay = *b_single_rlay;
+
+ vector<float> pixels(tile.size.x * tile.size.y * 4);
+
+ /* Copy each pass.
+ * TODO:copy only the required ones for better performance? */
+ for (BL::RenderPass &b_pass : b_rlay.passes) {
+ tile.set_pass_pixels(b_pass.name(), b_pass.channels(), (float *)b_pass.rect());
+ }
+
+ b_engine_.end_result(b_rr, false, false, false);
+
+ return true;
+}
+
+bool BlenderOutputDriver::update_render_tile(const Tile &tile)
+{
+ /* Use final write for preview renders, otherwise render result wouldn't be be updated
+ * quickly on Blender side. For all other cases we use the display driver. */
+ if (b_engine_.is_preview()) {
+ write_render_tile(tile);
+ return true;
+ }
+
+ /* Don't highlight full-frame tile. */
+ if (!(tile.size == tile.full_size)) {
+ b_engine_.tile_highlight_clear_all();
+ b_engine_.tile_highlight_set(tile.offset.x, tile.offset.y, tile.size.x, tile.size.y, true);
+ }
+
+ return false;
+}
+
+void BlenderOutputDriver::write_render_tile(const Tile &tile)
+{
+ b_engine_.tile_highlight_clear_all();
+
+ /* Get render result. */
+ BL::RenderResult b_rr = b_engine_.begin_result(tile.offset.x,
+ tile.offset.y,
+ tile.size.x,
+ tile.size.y,
+ tile.layer.c_str(),
+ tile.view.c_str());
+
+ /* Can happen if the intersected rectangle gives 0 width or height. */
+ if (b_rr.ptr.data == NULL) {
+ return;
+ }
+
+ BL::RenderResult::layers_iterator b_single_rlay;
+ b_rr.layers.begin(b_single_rlay);
+
+ /* Layer will be missing if it was disabled in the UI. */
+ if (b_single_rlay == b_rr.layers.end()) {
+ return;
+ }
+
+ BL::RenderLayer b_rlay = *b_single_rlay;
+
+ vector<float> pixels(tile.size.x * tile.size.y * 4);
+
+ /* Copy each pass. */
+ for (BL::RenderPass &b_pass : b_rlay.passes) {
+ if (!tile.get_pass_pixels(b_pass.name(), b_pass.channels(), &pixels[0])) {
+ memset(&pixels[0], 0, pixels.size() * sizeof(float));
+ }
+
+ b_pass.rect(&pixels[0]);
+ }
+
+ b_engine_.end_result(b_rr, true, false, true);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/output_driver.h b/intern/cycles/blender/output_driver.h
new file mode 100644
index 00000000000..1d016f8bcb9
--- /dev/null
+++ b/intern/cycles/blender/output_driver.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_blender_cpp.h"
+
+#include "session/output_driver.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BlenderOutputDriver : public OutputDriver {
+ public:
+ explicit BlenderOutputDriver(BL::RenderEngine &b_engine);
+ ~BlenderOutputDriver();
+
+ virtual void write_render_tile(const Tile &tile) override;
+ virtual bool update_render_tile(const Tile &tile) override;
+ virtual bool read_render_tile(const Tile &tile) override;
+
+ protected:
+ BL::RenderEngine b_engine_;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/particles.cpp b/intern/cycles/blender/particles.cpp
new file mode 100644
index 00000000000..3a2c1b0ecf9
--- /dev/null
+++ b/intern/cycles/blender/particles.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/particles.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "util/foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Utilities */
+
+bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
+ BL::DepsgraphObjectInstance &b_instance,
+ Object *object)
+{
+ /* Test if this dupli was generated from a particle system. */
+ BL::ParticleSystem b_psys = b_instance.particle_system();
+ if (!b_psys)
+ return false;
+
+ object->set_hide_on_missing_motion(true);
+
+ /* test if we need particle data */
+ if (!object->get_geometry()->need_attribute(scene, ATTR_STD_PARTICLE))
+ return false;
+
+ /* don't handle child particles yet */
+ BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_instance.persistent_id();
+
+ if (persistent_id[0] >= b_psys.particles.length())
+ return false;
+
+ /* find particle system */
+ ParticleSystemKey key(b_ob, persistent_id);
+ ParticleSystem *psys;
+
+ bool first_use = !particle_system_map.is_used(key);
+ bool need_update = particle_system_map.add_or_update(&psys, b_ob, b_instance.object(), key);
+
+ /* no update needed? */
+ if (!need_update && !object->get_geometry()->is_modified() &&
+ !scene->object_manager->need_update())
+ return true;
+
+ /* first time used in this sync loop? clear and tag update */
+ if (first_use) {
+ psys->particles.clear();
+ psys->tag_update(scene);
+ }
+
+ /* add particle */
+ BL::Particle b_pa = b_psys.particles[persistent_id[0]];
+ Particle pa;
+
+ pa.index = persistent_id[0];
+ pa.age = b_scene.frame_current_final() - b_pa.birth_time();
+ pa.lifetime = b_pa.lifetime();
+ pa.location = get_float3(b_pa.location());
+ pa.rotation = get_float4(b_pa.rotation());
+ pa.size = b_pa.size();
+ pa.velocity = get_float3(b_pa.velocity());
+ pa.angular_velocity = get_float3(b_pa.angular_velocity());
+
+ psys->particles.push_back_slow(pa);
+
+ object->set_particle_system(psys);
+ object->set_particle_index(psys->particles.size() - 1);
+
+ if (object->particle_index_is_modified())
+ scene->object_manager->tag_update(scene, ObjectManager::PARTICLE_MODIFIED);
+
+ /* return that this object has particle data */
+ return true;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/python.cpp b/intern/cycles/blender/python.cpp
new file mode 100644
index 00000000000..20bf6385999
--- /dev/null
+++ b/intern/cycles/blender/python.cpp
@@ -0,0 +1,1063 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Python.h>
+
+#include "blender/CCL_api.h"
+
+#include "blender/device.h"
+#include "blender/session.h"
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "session/denoising.h"
+#include "session/merge.h"
+
+#include "util/debug.h"
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/md5.h"
+#include "util/opengl.h"
+#include "util/openimagedenoise.h"
+#include "util/path.h"
+#include "util/string.h"
+#include "util/task.h"
+#include "util/tbb.h"
+#include "util/types.h"
+
+#ifdef WITH_OSL
+# include "scene/osl.h"
+
+# include <OSL/oslconfig.h>
+# include <OSL/oslquery.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+namespace {
+
+/* Flag describing whether debug flags were synchronized from scene. */
+bool debug_flags_set = false;
+
+void *pylong_as_voidptr_typesafe(PyObject *object)
+{
+ if (object == Py_None)
+ return NULL;
+ return PyLong_AsVoidPtr(object);
+}
+
+PyObject *pyunicode_from_string(const char *str)
+{
+ /* Ignore errors if device API returns invalid UTF-8 strings. */
+ return PyUnicode_DecodeUTF8(str, strlen(str), "ignore");
+}
+
+/* Synchronize debug flags from a given Blender scene.
+ * Return truth when device list needs invalidation.
+ */
+static void debug_flags_sync_from_scene(BL::Scene b_scene)
+{
+ DebugFlagsRef flags = DebugFlags();
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ /* Synchronize shared flags. */
+ flags.viewport_static_bvh = get_enum(cscene, "debug_bvh_type");
+ /* Synchronize CPU flags. */
+ flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2");
+ flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx");
+ flags.cpu.sse41 = get_boolean(cscene, "debug_use_cpu_sse41");
+ flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3");
+ flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2");
+ flags.cpu.bvh_layout = (BVHLayout)get_enum(cscene, "debug_bvh_layout");
+ /* Synchronize CUDA flags. */
+ flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile");
+ /* Synchronize OptiX flags. */
+ flags.optix.use_debug = get_boolean(cscene, "debug_use_optix_debug");
+}
+
+/* Reset debug flags to default values.
+ * Return truth when device list needs invalidation.
+ */
+static void debug_flags_reset()
+{
+ DebugFlagsRef flags = DebugFlags();
+ flags.reset();
+}
+
+} /* namespace */
+
+void python_thread_state_save(void **python_thread_state)
+{
+ *python_thread_state = (void *)PyEval_SaveThread();
+}
+
+void python_thread_state_restore(void **python_thread_state)
+{
+ PyEval_RestoreThread((PyThreadState *)*python_thread_state);
+ *python_thread_state = NULL;
+}
+
+static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
+{
+ const char *result = PyUnicode_AsUTF8(py_str);
+ if (result) {
+ /* 99% of the time this is enough but we better support non unicode
+ * chars since blender doesn't limit this.
+ */
+ return result;
+ }
+ else {
+ PyErr_Clear();
+ if (PyBytes_Check(py_str)) {
+ return PyBytes_AS_STRING(py_str);
+ }
+ else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
+ return PyBytes_AS_STRING(*coerce);
+ }
+ else {
+ /* Clear the error, so Cycles can be at least used without
+ * GPU and OSL support,
+ */
+ PyErr_Clear();
+ return "";
+ }
+ }
+}
+
+static PyObject *init_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *path, *user_path, *temp_path;
+ int headless;
+
+ if (!PyArg_ParseTuple(args, "OOOi", &path, &user_path, &temp_path, &headless)) {
+ return nullptr;
+ }
+
+ PyObject *path_coerce = nullptr, *user_path_coerce = nullptr, *temp_path_coerce = nullptr;
+ path_init(PyC_UnicodeAsByte(path, &path_coerce),
+ PyC_UnicodeAsByte(user_path, &user_path_coerce),
+ PyC_UnicodeAsByte(temp_path, &temp_path_coerce));
+ Py_XDECREF(path_coerce);
+ Py_XDECREF(user_path_coerce);
+ Py_XDECREF(temp_path_coerce);
+
+ BlenderSession::headless = headless;
+
+ DebugFlags().running_inside_blender = true;
+
+ VLOG(2) << "Debug flags initialized to:\n" << DebugFlags();
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/)
+{
+ ShaderManager::free_memory();
+ TaskScheduler::free_memory();
+ Device::free_memory();
+ Py_RETURN_NONE;
+}
+
+static PyObject *create_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *pyengine, *pypreferences, *pydata, *pyscreen, *pyregion, *pyv3d, *pyrv3d;
+ int preview_osl;
+
+ if (!PyArg_ParseTuple(args,
+ "OOOOOOOi",
+ &pyengine,
+ &pypreferences,
+ &pydata,
+ &pyscreen,
+ &pyregion,
+ &pyv3d,
+ &pyrv3d,
+ &preview_osl)) {
+ return NULL;
+ }
+
+ /* RNA */
+ ID *bScreen = (ID *)PyLong_AsVoidPtr(pyscreen);
+
+ PointerRNA engineptr;
+ RNA_pointer_create(NULL, &RNA_RenderEngine, (void *)PyLong_AsVoidPtr(pyengine), &engineptr);
+ BL::RenderEngine engine(engineptr);
+
+ PointerRNA preferencesptr;
+ RNA_pointer_create(
+ NULL, &RNA_Preferences, (void *)PyLong_AsVoidPtr(pypreferences), &preferencesptr);
+ BL::Preferences preferences(preferencesptr);
+
+ PointerRNA dataptr;
+ RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr);
+ BL::BlendData data(dataptr);
+
+ PointerRNA regionptr;
+ RNA_pointer_create(bScreen, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), &regionptr);
+ BL::Region region(regionptr);
+
+ PointerRNA v3dptr;
+ RNA_pointer_create(bScreen, &RNA_SpaceView3D, pylong_as_voidptr_typesafe(pyv3d), &v3dptr);
+ BL::SpaceView3D v3d(v3dptr);
+
+ PointerRNA rv3dptr;
+ RNA_pointer_create(bScreen, &RNA_RegionView3D, pylong_as_voidptr_typesafe(pyrv3d), &rv3dptr);
+ BL::RegionView3D rv3d(rv3dptr);
+
+ /* create session */
+ BlenderSession *session;
+
+ if (rv3d) {
+ /* interactive viewport session */
+ int width = region.width();
+ int height = region.height();
+
+ session = new BlenderSession(engine, preferences, data, v3d, rv3d, width, height);
+ }
+ else {
+ /* offline session or preview render */
+ session = new BlenderSession(engine, preferences, data, preview_osl);
+ }
+
+ return PyLong_FromVoidPtr(session);
+}
+
+static PyObject *free_func(PyObject * /*self*/, PyObject *value)
+{
+ delete (BlenderSession *)PyLong_AsVoidPtr(value);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *render_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *pysession, *pydepsgraph;
+
+ if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph))
+ return NULL;
+
+ BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
+
+ PointerRNA depsgraphptr;
+ RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
+ BL::Depsgraph b_depsgraph(depsgraphptr);
+
+ /* Allow Blender to execute other Python scripts. */
+ python_thread_state_save(&session->python_thread_state);
+
+ session->render(b_depsgraph);
+
+ python_thread_state_restore(&session->python_thread_state);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *render_frame_finish_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *pysession;
+
+ if (!PyArg_ParseTuple(args, "O", &pysession)) {
+ return nullptr;
+ }
+
+ BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
+
+ /* Allow Blender to execute other Python scripts. */
+ python_thread_state_save(&session->python_thread_state);
+
+ session->render_frame_finish();
+
+ python_thread_state_restore(&session->python_thread_state);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *py_session, *py_graph, *py_screen, *py_space_image;
+
+ if (!PyArg_ParseTuple(args, "OOOO", &py_session, &py_graph, &py_screen, &py_space_image)) {
+ return nullptr;
+ }
+
+ BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(py_session);
+
+ ID *b_screen = (ID *)PyLong_AsVoidPtr(py_screen);
+
+ PointerRNA b_space_image_ptr;
+ RNA_pointer_create(b_screen,
+ &RNA_SpaceImageEditor,
+ pylong_as_voidptr_typesafe(py_space_image),
+ &b_space_image_ptr);
+ BL::SpaceImageEditor b_space_image(b_space_image_ptr);
+
+ session->draw(b_space_image);
+
+ Py_RETURN_NONE;
+}
+
+/* pixel_array and result passed as pointers */
+static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *pysession, *pydepsgraph, *pyobject;
+ const char *pass_type;
+ int pass_filter, width, height;
+
+ if (!PyArg_ParseTuple(args,
+ "OOOsiii",
+ &pysession,
+ &pydepsgraph,
+ &pyobject,
+ &pass_type,
+ &pass_filter,
+ &width,
+ &height))
+ return NULL;
+
+ BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
+
+ PointerRNA depsgraphptr;
+ RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
+ BL::Depsgraph b_depsgraph(depsgraphptr);
+
+ PointerRNA objectptr;
+ RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyobject), &objectptr);
+ BL::Object b_object(objectptr);
+
+ python_thread_state_save(&session->python_thread_state);
+
+ session->bake(b_depsgraph, b_object, pass_type, pass_filter, width, height);
+
+ python_thread_state_restore(&session->python_thread_state);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *view_draw_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *pysession, *pygraph, *pyv3d, *pyrv3d;
+
+ if (!PyArg_ParseTuple(args, "OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d))
+ return NULL;
+
+ BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
+
+ if (PyLong_AsVoidPtr(pyrv3d)) {
+ /* 3d view drawing */
+ int viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+
+ session->view_draw(viewport[2], viewport[3]);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *pysession, *pydata, *pydepsgraph;
+
+ if (!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pydepsgraph))
+ return NULL;
+
+ BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
+
+ PointerRNA dataptr;
+ RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr);
+ BL::BlendData b_data(dataptr);
+
+ PointerRNA depsgraphptr;
+ RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
+ BL::Depsgraph b_depsgraph(depsgraphptr);
+
+ python_thread_state_save(&session->python_thread_state);
+
+ session->reset_session(b_data, b_depsgraph);
+
+ python_thread_state_restore(&session->python_thread_state);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *sync_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *pysession, *pydepsgraph;
+
+ if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph))
+ return NULL;
+
+ BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
+
+ PointerRNA depsgraphptr;
+ RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
+ BL::Depsgraph b_depsgraph(depsgraphptr);
+
+ python_thread_state_save(&session->python_thread_state);
+
+ session->synchronize(b_depsgraph);
+
+ python_thread_state_restore(&session->python_thread_state);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *available_devices_func(PyObject * /*self*/, PyObject *args)
+{
+ const char *type_name;
+ if (!PyArg_ParseTuple(args, "s", &type_name)) {
+ return NULL;
+ }
+
+ DeviceType type = Device::type_from_string(type_name);
+ /* "NONE" is defined by the add-on, see: `CyclesPreferences.get_device_types`. */
+ if ((type == DEVICE_NONE) && (strcmp(type_name, "NONE") != 0)) {
+ PyErr_Format(PyExc_ValueError, "Device \"%s\" not known.", type_name);
+ return NULL;
+ }
+
+ uint mask = (type == DEVICE_NONE) ? DEVICE_MASK_ALL : DEVICE_MASK(type);
+ mask |= DEVICE_MASK_CPU;
+
+ vector<DeviceInfo> devices = Device::available_devices(mask);
+ PyObject *ret = PyTuple_New(devices.size());
+
+ for (size_t i = 0; i < devices.size(); i++) {
+ DeviceInfo &device = devices[i];
+ string type_name = Device::string_from_type(device.type);
+ PyObject *device_tuple = PyTuple_New(4);
+ PyTuple_SET_ITEM(device_tuple, 0, pyunicode_from_string(device.description.c_str()));
+ PyTuple_SET_ITEM(device_tuple, 1, pyunicode_from_string(type_name.c_str()));
+ PyTuple_SET_ITEM(device_tuple, 2, pyunicode_from_string(device.id.c_str()));
+ PyTuple_SET_ITEM(device_tuple, 3, PyBool_FromLong(device.has_peer_memory));
+ PyTuple_SET_ITEM(ret, i, device_tuple);
+ }
+
+ return ret;
+}
+
+#ifdef WITH_OSL
+
+static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *pydata, *pynodegroup, *pynode;
+ const char *filepath = NULL;
+
+ if (!PyArg_ParseTuple(args, "OOOs", &pydata, &pynodegroup, &pynode, &filepath))
+ return NULL;
+
+ /* RNA */
+ PointerRNA dataptr;
+ RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr);
+ BL::BlendData b_data(dataptr);
+
+ PointerRNA nodeptr;
+ RNA_pointer_create((ID *)PyLong_AsVoidPtr(pynodegroup),
+ &RNA_ShaderNodeScript,
+ (void *)PyLong_AsVoidPtr(pynode),
+ &nodeptr);
+ BL::ShaderNodeScript b_node(nodeptr);
+
+ /* update bytecode hash */
+ string bytecode = b_node.bytecode();
+
+ if (!bytecode.empty()) {
+ MD5Hash md5;
+ md5.append((const uint8_t *)bytecode.c_str(), bytecode.size());
+ b_node.bytecode_hash(md5.get_hex().c_str());
+ }
+ else
+ b_node.bytecode_hash("");
+
+ /* query from file path */
+ OSL::OSLQuery query;
+
+ if (!OSLShaderManager::osl_query(query, filepath))
+ Py_RETURN_FALSE;
+
+ /* add new sockets from parameters */
+ set<void *> used_sockets;
+
+ for (int i = 0; i < query.nparams(); i++) {
+ const OSL::OSLQuery::Parameter *param = query.getparam(i);
+
+ /* skip unsupported types */
+ if (param->varlenarray || param->isstruct || param->type.arraylen > 1)
+ continue;
+
+ /* Read metadata. */
+ bool is_bool_param = false;
+ ustring param_label = param->name;
+
+ for (const OSL::OSLQuery::Parameter &metadata : param->metadata) {
+ if (metadata.type == TypeDesc::STRING) {
+ if (metadata.name == "widget") {
+ /* Boolean socket. */
+ if (metadata.sdefault[0] == "boolean" || metadata.sdefault[0] == "checkBox") {
+ is_bool_param = true;
+ }
+ }
+ else if (metadata.name == "label") {
+ /* Socket label. */
+ param_label = metadata.sdefault[0];
+ }
+ }
+ }
+ /* determine socket type */
+ string socket_type;
+ BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
+ float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
+ float default_float = 0.0f;
+ int default_int = 0;
+ string default_string = "";
+ bool default_boolean = false;
+
+ if (param->isclosure) {
+ socket_type = "NodeSocketShader";
+ data_type = BL::NodeSocket::type_SHADER;
+ }
+ else if (param->type.vecsemantics == TypeDesc::COLOR) {
+ socket_type = "NodeSocketColor";
+ data_type = BL::NodeSocket::type_RGBA;
+
+ if (param->validdefault) {
+ default_float4[0] = param->fdefault[0];
+ default_float4[1] = param->fdefault[1];
+ default_float4[2] = param->fdefault[2];
+ }
+ }
+ else if (param->type.vecsemantics == TypeDesc::POINT ||
+ param->type.vecsemantics == TypeDesc::VECTOR ||
+ param->type.vecsemantics == TypeDesc::NORMAL) {
+ socket_type = "NodeSocketVector";
+ data_type = BL::NodeSocket::type_VECTOR;
+
+ if (param->validdefault) {
+ default_float4[0] = param->fdefault[0];
+ default_float4[1] = param->fdefault[1];
+ default_float4[2] = param->fdefault[2];
+ }
+ }
+ else if (param->type.aggregate == TypeDesc::SCALAR) {
+ if (param->type.basetype == TypeDesc::INT) {
+ if (is_bool_param) {
+ socket_type = "NodeSocketBool";
+ data_type = BL::NodeSocket::type_BOOLEAN;
+ if (param->validdefault) {
+ default_boolean = (bool)param->idefault[0];
+ }
+ }
+ else {
+ socket_type = "NodeSocketInt";
+ data_type = BL::NodeSocket::type_INT;
+ if (param->validdefault)
+ default_int = param->idefault[0];
+ }
+ }
+ else if (param->type.basetype == TypeDesc::FLOAT) {
+ socket_type = "NodeSocketFloat";
+ data_type = BL::NodeSocket::type_VALUE;
+ if (param->validdefault)
+ default_float = param->fdefault[0];
+ }
+ else if (param->type.basetype == TypeDesc::STRING) {
+ socket_type = "NodeSocketString";
+ data_type = BL::NodeSocket::type_STRING;
+ if (param->validdefault)
+ default_string = param->sdefault[0].string();
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+
+ /* Update existing socket. */
+ bool found_existing = false;
+ if (param->isoutput) {
+ for (BL::NodeSocket &b_sock : b_node.outputs) {
+ if (b_sock.identifier() == param->name) {
+ if (b_sock.bl_idname() != socket_type) {
+ /* Remove if type no longer matches. */
+ b_node.outputs.remove(b_data, b_sock);
+ }
+ else {
+ /* Reuse and update label. */
+ if (b_sock.name() != param_label) {
+ b_sock.name(param_label.string());
+ }
+ used_sockets.insert(b_sock.ptr.data);
+ found_existing = true;
+ }
+ break;
+ }
+ }
+ }
+ else {
+ for (BL::NodeSocket &b_sock : b_node.inputs) {
+ if (b_sock.identifier() == param->name) {
+ if (b_sock.bl_idname() != socket_type) {
+ /* Remove if type no longer matches. */
+ b_node.inputs.remove(b_data, b_sock);
+ }
+ else {
+ /* Reuse and update label. */
+ if (b_sock.name() != param_label) {
+ b_sock.name(param_label.string());
+ }
+ used_sockets.insert(b_sock.ptr.data);
+ found_existing = true;
+ }
+ break;
+ }
+ }
+ }
+
+ if (!found_existing) {
+ /* Create new socket. */
+ BL::NodeSocket b_sock = (param->isoutput) ? b_node.outputs.create(b_data,
+ socket_type.c_str(),
+ param_label.c_str(),
+ param->name.c_str()) :
+ b_node.inputs.create(b_data,
+ socket_type.c_str(),
+ param_label.c_str(),
+ param->name.c_str());
+
+ /* set default value */
+ if (data_type == BL::NodeSocket::type_VALUE) {
+ set_float(b_sock.ptr, "default_value", default_float);
+ }
+ else if (data_type == BL::NodeSocket::type_INT) {
+ set_int(b_sock.ptr, "default_value", default_int);
+ }
+ else if (data_type == BL::NodeSocket::type_RGBA) {
+ set_float4(b_sock.ptr, "default_value", default_float4);
+ }
+ else if (data_type == BL::NodeSocket::type_VECTOR) {
+ set_float3(b_sock.ptr, "default_value", float4_to_float3(default_float4));
+ }
+ else if (data_type == BL::NodeSocket::type_STRING) {
+ set_string(b_sock.ptr, "default_value", default_string);
+ }
+ else if (data_type == BL::NodeSocket::type_BOOLEAN) {
+ set_boolean(b_sock.ptr, "default_value", default_boolean);
+ }
+
+ used_sockets.insert(b_sock.ptr.data);
+ }
+ }
+
+ /* remove unused parameters */
+ bool removed;
+
+ do {
+ removed = false;
+
+ for (BL::NodeSocket &b_input : b_node.inputs) {
+ if (used_sockets.find(b_input.ptr.data) == used_sockets.end()) {
+ b_node.inputs.remove(b_data, b_input);
+ removed = true;
+ break;
+ }
+ }
+
+ for (BL::NodeSocket &b_output : b_node.outputs) {
+ if (used_sockets.find(b_output.ptr.data) == used_sockets.end()) {
+ b_node.outputs.remove(b_data, b_output);
+ removed = true;
+ break;
+ }
+ }
+ } while (removed);
+
+ Py_RETURN_TRUE;
+}
+
+static PyObject *osl_compile_func(PyObject * /*self*/, PyObject *args)
+{
+ const char *inputfile = NULL, *outputfile = NULL;
+
+ if (!PyArg_ParseTuple(args, "ss", &inputfile, &outputfile))
+ return NULL;
+
+ /* return */
+ if (!OSLShaderManager::osl_compile(inputfile, outputfile))
+ Py_RETURN_FALSE;
+
+ Py_RETURN_TRUE;
+}
+#endif
+
+static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
+{
+ string system_info = Device::device_capabilities();
+ return pyunicode_from_string(system_info.c_str());
+}
+
+static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepaths)
+{
+ if (PyUnicode_Check(pyfilepaths)) {
+ const char *filepath = PyUnicode_AsUTF8(pyfilepaths);
+ filepaths.push_back(filepath);
+ return true;
+ }
+
+ PyObject *sequence = PySequence_Fast(pyfilepaths,
+ "File paths must be a string or sequence of strings");
+ if (sequence == NULL) {
+ return false;
+ }
+
+ for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) {
+ PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
+ const char *filepath = PyUnicode_AsUTF8(item);
+ if (filepath == NULL) {
+ PyErr_SetString(PyExc_ValueError, "File paths must be a string or sequence of strings.");
+ Py_DECREF(sequence);
+ return false;
+ }
+ filepaths.push_back(filepath);
+ }
+ Py_DECREF(sequence);
+
+ return true;
+}
+
+static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
+{
+#if 1
+ (void)args;
+ (void)keywords;
+#else
+ static const char *keyword_list[] = {
+ "preferences", "scene", "view_layer", "input", "output", "tile_size", "samples", NULL};
+ PyObject *pypreferences, *pyscene, *pyviewlayer;
+ PyObject *pyinput, *pyoutput = NULL;
+ int tile_size = 0, samples = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args,
+ keywords,
+ "OOOO|Oii",
+ (char **)keyword_list,
+ &pypreferences,
+ &pyscene,
+ &pyviewlayer,
+ &pyinput,
+ &pyoutput,
+ &tile_size,
+ &samples)) {
+ return NULL;
+ }
+
+ /* Get device specification from preferences and scene. */
+ PointerRNA preferencesptr;
+ RNA_pointer_create(
+ NULL, &RNA_Preferences, (void *)PyLong_AsVoidPtr(pypreferences), &preferencesptr);
+ BL::Preferences b_preferences(preferencesptr);
+
+ PointerRNA sceneptr;
+ RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), &sceneptr);
+ BL::Scene b_scene(sceneptr);
+
+ DeviceInfo device = blender_device_info(b_preferences, b_scene, true);
+
+ /* Get denoising parameters from view layer. */
+ PointerRNA viewlayerptr;
+ RNA_pointer_create((ID *)PyLong_AsVoidPtr(pyscene),
+ &RNA_ViewLayer,
+ PyLong_AsVoidPtr(pyviewlayer),
+ &viewlayerptr);
+ PointerRNA cviewlayer = RNA_pointer_get(&viewlayerptr, "cycles");
+
+ DenoiseParams params;
+ params.radius = get_int(cviewlayer, "denoising_radius");
+ params.strength = get_float(cviewlayer, "denoising_strength");
+ params.feature_strength = get_float(cviewlayer, "denoising_feature_strength");
+ params.relative_pca = get_boolean(cviewlayer, "denoising_relative_pca");
+ params.neighbor_frames = get_int(cviewlayer, "denoising_neighbor_frames");
+
+ /* Parse file paths list. */
+ vector<string> input, output;
+
+ if (!image_parse_filepaths(pyinput, input)) {
+ return NULL;
+ }
+
+ if (pyoutput) {
+ if (!image_parse_filepaths(pyoutput, output)) {
+ return NULL;
+ }
+ }
+ else {
+ output = input;
+ }
+
+ if (input.empty()) {
+ PyErr_SetString(PyExc_ValueError, "No input file paths specified.");
+ return NULL;
+ }
+ if (input.size() != output.size()) {
+ PyErr_SetString(PyExc_ValueError, "Number of input and output file paths does not match.");
+ return NULL;
+ }
+
+ /* Create denoiser. */
+ DenoiserPipeline denoiser(device);
+ denoiser.params = params;
+ denoiser.input = input;
+ denoiser.output = output;
+
+ if (tile_size > 0) {
+ denoiser.tile_size = make_int2(tile_size, tile_size);
+ }
+ if (samples > 0) {
+ denoiser.samples_override = samples;
+ }
+
+ /* Run denoiser. */
+ if (!denoiser.run()) {
+ PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
+ return NULL;
+ }
+#endif
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *merge_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
+{
+ static const char *keyword_list[] = {"input", "output", NULL};
+ PyObject *pyinput, *pyoutput = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, keywords, "OO", (char **)keyword_list, &pyinput, &pyoutput)) {
+ return NULL;
+ }
+
+ /* Parse input list. */
+ vector<string> input;
+ if (!image_parse_filepaths(pyinput, input)) {
+ return NULL;
+ }
+
+ /* Parse output string. */
+ if (!PyUnicode_Check(pyoutput)) {
+ PyErr_SetString(PyExc_ValueError, "Output must be a string.");
+ return NULL;
+ }
+ string output = PyUnicode_AsUTF8(pyoutput);
+
+ /* Merge. */
+ ImageMerger merger;
+ merger.input = input;
+ merger.output = output;
+
+ if (!merger.run()) {
+ PyErr_SetString(PyExc_ValueError, merger.error.c_str());
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *pyscene;
+ if (!PyArg_ParseTuple(args, "O", &pyscene)) {
+ return NULL;
+ }
+
+ PointerRNA sceneptr;
+ RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), &sceneptr);
+ BL::Scene b_scene(sceneptr);
+
+ debug_flags_sync_from_scene(b_scene);
+
+ VLOG(2) << "Debug flags set to:\n" << DebugFlags();
+
+ debug_flags_set = true;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/)
+{
+ debug_flags_reset();
+ if (debug_flags_set) {
+ VLOG(2) << "Debug flags reset to:\n" << DebugFlags();
+ debug_flags_set = false;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/)
+{
+ BlenderSession::print_render_stats = true;
+ Py_RETURN_NONE;
+}
+
+static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
+{
+ vector<DeviceType> device_types = Device::available_types();
+ bool has_cuda = false, has_optix = false, has_hip = false;
+ foreach (DeviceType device_type, device_types) {
+ has_cuda |= (device_type == DEVICE_CUDA);
+ has_optix |= (device_type == DEVICE_OPTIX);
+ has_hip |= (device_type == DEVICE_HIP);
+ }
+ PyObject *list = PyTuple_New(3);
+ PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
+ PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
+ PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_hip));
+ return list;
+}
+
+static PyObject *set_device_override_func(PyObject * /*self*/, PyObject *arg)
+{
+ PyObject *override_string = PyObject_Str(arg);
+ string override = PyUnicode_AsUTF8(override_string);
+ Py_DECREF(override_string);
+
+ bool include_cpu = false;
+ const string cpu_suffix = "+CPU";
+ if (string_endswith(override, cpu_suffix)) {
+ include_cpu = true;
+ override = override.substr(0, override.length() - cpu_suffix.length());
+ }
+
+ if (override == "CPU") {
+ BlenderSession::device_override = DEVICE_MASK_CPU;
+ }
+ else if (override == "CUDA") {
+ BlenderSession::device_override = DEVICE_MASK_CUDA;
+ }
+ else if (override == "OPTIX") {
+ BlenderSession::device_override = DEVICE_MASK_OPTIX;
+ }
+ else if (override == "HIP") {
+ BlenderSession::device_override = DEVICE_MASK_HIP;
+ }
+ else {
+ printf("\nError: %s is not a valid Cycles device.\n", override.c_str());
+ Py_RETURN_FALSE;
+ }
+
+ if (include_cpu) {
+ BlenderSession::device_override = (DeviceTypeMask)(BlenderSession::device_override |
+ DEVICE_MASK_CPU);
+ }
+
+ Py_RETURN_TRUE;
+}
+
+static PyMethodDef methods[] = {
+ {"init", init_func, METH_VARARGS, ""},
+ {"exit", exit_func, METH_VARARGS, ""},
+ {"create", create_func, METH_VARARGS, ""},
+ {"free", free_func, METH_O, ""},
+ {"render", render_func, METH_VARARGS, ""},
+ {"render_frame_finish", render_frame_finish_func, METH_VARARGS, ""},
+ {"draw", draw_func, METH_VARARGS, ""},
+ {"bake", bake_func, METH_VARARGS, ""},
+ {"view_draw", view_draw_func, METH_VARARGS, ""},
+ {"sync", sync_func, METH_VARARGS, ""},
+ {"reset", reset_func, METH_VARARGS, ""},
+#ifdef WITH_OSL
+ {"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
+ {"osl_compile", osl_compile_func, METH_VARARGS, ""},
+#endif
+ {"available_devices", available_devices_func, METH_VARARGS, ""},
+ {"system_info", system_info_func, METH_NOARGS, ""},
+
+ /* Standalone denoising */
+ {"denoise", (PyCFunction)denoise_func, METH_VARARGS | METH_KEYWORDS, ""},
+ {"merge", (PyCFunction)merge_func, METH_VARARGS | METH_KEYWORDS, ""},
+
+ /* Debugging routines */
+ {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""},
+ {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""},
+
+ /* Statistics. */
+ {"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""},
+
+ /* Compute Device selection */
+ {"get_device_types", get_device_types_func, METH_VARARGS, ""},
+ {"set_device_override", set_device_override_func, METH_O, ""},
+
+ {NULL, NULL, 0, NULL},
+};
+
+static struct PyModuleDef module = {
+ PyModuleDef_HEAD_INIT,
+ "_cycles",
+ "Blender cycles render integration",
+ -1,
+ methods,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+CCL_NAMESPACE_END
+
+void *CCL_python_module_init()
+{
+ PyObject *mod = PyModule_Create(&ccl::module);
+
+#ifdef WITH_OSL
+ /* TODO(sergey): This gives us library we've been linking against.
+ * In theory with dynamic OSL library it might not be
+ * accurate, but there's nothing in OSL API which we
+ * might use to get version in runtime.
+ */
+ int curversion = OSL_LIBRARY_VERSION_CODE;
+ PyModule_AddObject(mod, "with_osl", Py_True);
+ Py_INCREF(Py_True);
+ PyModule_AddObject(
+ mod,
+ "osl_version",
+ Py_BuildValue("(iii)", curversion / 10000, (curversion / 100) % 100, curversion % 100));
+ PyModule_AddObject(
+ mod,
+ "osl_version_string",
+ PyUnicode_FromFormat(
+ "%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100));
+#else
+ PyModule_AddObject(mod, "with_osl", Py_False);
+ Py_INCREF(Py_False);
+ PyModule_AddStringConstant(mod, "osl_version", "unknown");
+ PyModule_AddStringConstant(mod, "osl_version_string", "unknown");
+#endif
+
+#ifdef WITH_EMBREE
+ PyModule_AddObject(mod, "with_embree", Py_True);
+ Py_INCREF(Py_True);
+#else /* WITH_EMBREE */
+ PyModule_AddObject(mod, "with_embree", Py_False);
+ Py_INCREF(Py_False);
+#endif /* WITH_EMBREE */
+
+ if (ccl::openimagedenoise_supported()) {
+ PyModule_AddObject(mod, "with_openimagedenoise", Py_True);
+ Py_INCREF(Py_True);
+ }
+ else {
+ PyModule_AddObject(mod, "with_openimagedenoise", Py_False);
+ Py_INCREF(Py_False);
+ }
+
+ return (void *)mod;
+}
diff --git a/intern/cycles/blender/session.cpp b/intern/cycles/blender/session.cpp
new file mode 100644
index 00000000000..d9a2d3d3029
--- /dev/null
+++ b/intern/cycles/blender/session.cpp
@@ -0,0 +1,1003 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include "device/device.h"
+#include "scene/background.h"
+#include "scene/camera.h"
+#include "scene/colorspace.h"
+#include "scene/film.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/stats.h"
+#include "session/buffers.h"
+#include "session/session.h"
+
+#include "util/algorithm.h"
+#include "util/color.h"
+#include "util/foreach.h"
+#include "util/function.h"
+#include "util/hash.h"
+#include "util/log.h"
+#include "util/murmurhash.h"
+#include "util/path.h"
+#include "util/progress.h"
+#include "util/time.h"
+
+#include "blender/display_driver.h"
+#include "blender/output_driver.h"
+#include "blender/session.h"
+#include "blender/sync.h"
+#include "blender/util.h"
+
+CCL_NAMESPACE_BEGIN
+
+DeviceTypeMask BlenderSession::device_override = DEVICE_MASK_ALL;
+bool BlenderSession::headless = false;
+bool BlenderSession::print_render_stats = false;
+
+BlenderSession::BlenderSession(BL::RenderEngine &b_engine,
+ BL::Preferences &b_userpref,
+ BL::BlendData &b_data,
+ bool preview_osl)
+ : session(NULL),
+ scene(NULL),
+ sync(NULL),
+ b_engine(b_engine),
+ b_userpref(b_userpref),
+ b_data(b_data),
+ b_render(b_engine.render()),
+ b_depsgraph(PointerRNA_NULL),
+ b_scene(PointerRNA_NULL),
+ b_v3d(PointerRNA_NULL),
+ b_rv3d(PointerRNA_NULL),
+ width(0),
+ height(0),
+ preview_osl(preview_osl),
+ python_thread_state(NULL),
+ use_developer_ui(false)
+{
+ /* offline render */
+ background = true;
+ last_redraw_time = 0.0;
+ start_resize_time = 0.0;
+ last_status_time = 0.0;
+}
+
+BlenderSession::BlenderSession(BL::RenderEngine &b_engine,
+ BL::Preferences &b_userpref,
+ BL::BlendData &b_data,
+ BL::SpaceView3D &b_v3d,
+ BL::RegionView3D &b_rv3d,
+ int width,
+ int height)
+ : session(NULL),
+ scene(NULL),
+ sync(NULL),
+ b_engine(b_engine),
+ b_userpref(b_userpref),
+ b_data(b_data),
+ b_render(b_engine.render()),
+ b_depsgraph(PointerRNA_NULL),
+ b_scene(PointerRNA_NULL),
+ b_v3d(b_v3d),
+ b_rv3d(b_rv3d),
+ width(width),
+ height(height),
+ preview_osl(false),
+ python_thread_state(NULL),
+ use_developer_ui(b_userpref.experimental().use_cycles_debug() &&
+ b_userpref.view().show_developer_ui())
+{
+ /* 3d view render */
+ background = false;
+ last_redraw_time = 0.0;
+ start_resize_time = 0.0;
+ last_status_time = 0.0;
+}
+
+BlenderSession::~BlenderSession()
+{
+ free_session();
+}
+
+void BlenderSession::create_session()
+{
+ const SessionParams session_params = BlenderSync::get_session_params(
+ b_engine, b_userpref, b_scene, background);
+ const SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
+ const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
+
+ /* reset status/progress */
+ last_status = "";
+ last_error = "";
+ last_progress = -1.0f;
+ start_resize_time = 0.0;
+
+ /* create session */
+ session = new Session(session_params, scene_params);
+ session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
+ session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
+ session->set_pause(session_pause);
+
+ /* create scene */
+ scene = session->scene;
+ scene->name = b_scene.name();
+
+ /* create sync */
+ sync = new BlenderSync(
+ b_engine, b_data, b_scene, scene, !background, use_developer_ui, session->progress);
+ BL::Object b_camera_override(b_engine.camera_override());
+ if (b_v3d) {
+ sync->sync_view(b_v3d, b_rv3d, width, height);
+ }
+ else {
+ sync->sync_camera(b_render, b_camera_override, width, height, "");
+ }
+
+ /* set buffer parameters */
+ const BufferParams buffer_params = BlenderSync::get_buffer_params(
+ b_v3d, b_rv3d, scene->camera, width, height);
+ session->reset(session_params, buffer_params);
+
+ /* Viewport and preview (as in, material preview) does not do tiled rendering, so can inform
+ * engine that no tracking of the tiles state is needed.
+ * The offline rendering will make a decision when tile is being written. The penalty of asking
+ * the engine to keep track of tiles state is minimal, so there is nothing to worry about here
+ * about possible single-tiled final render. */
+ if (!b_engine.is_preview() && !b_v3d) {
+ b_engine.use_highlight_tiles(true);
+ }
+}
+
+void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph)
+{
+ /* Update data, scene and depsgraph pointers. These can change after undo. */
+ this->b_data = b_data;
+ this->b_depsgraph = b_depsgraph;
+ this->b_scene = b_depsgraph.scene_eval();
+ if (sync) {
+ sync->reset(this->b_data, this->b_scene);
+ }
+
+ if (preview_osl) {
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ RNA_boolean_set(&cscene, "shading_system", preview_osl);
+ }
+
+ if (b_v3d) {
+ this->b_render = b_scene.render();
+ }
+ else {
+ this->b_render = b_engine.render();
+ width = render_resolution_x(b_render);
+ height = render_resolution_y(b_render);
+ }
+
+ bool is_new_session = (session == NULL);
+ if (is_new_session) {
+ /* Initialize session and remember it was just created so not to
+ * re-create it below.
+ */
+ create_session();
+ }
+
+ if (b_v3d) {
+ /* NOTE: We need to create session, but all the code from below
+ * will make viewport render to stuck on initialization.
+ */
+ return;
+ }
+
+ const SessionParams session_params = BlenderSync::get_session_params(
+ b_engine, b_userpref, b_scene, background);
+ const SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
+
+ if (scene->params.modified(scene_params) || session->params.modified(session_params) ||
+ !this->b_render.use_persistent_data()) {
+ /* if scene or session parameters changed, it's easier to simply re-create
+ * them rather than trying to distinguish which settings need to be updated
+ */
+ if (!is_new_session) {
+ free_session();
+ create_session();
+ }
+ return;
+ }
+
+ session->progress.reset();
+
+ /* peak memory usage should show current render peak, not peak for all renders
+ * made by this render session
+ */
+ session->stats.mem_peak = session->stats.mem_used;
+
+ if (is_new_session) {
+ /* Sync object should be re-created for new scene. */
+ delete sync;
+ sync = new BlenderSync(
+ b_engine, b_data, b_scene, scene, !background, use_developer_ui, session->progress);
+ }
+ else {
+ /* Sync recalculations to do just the required updates. */
+ sync->sync_recalc(b_depsgraph, b_v3d);
+ }
+
+ BL::Object b_camera_override(b_engine.camera_override());
+ sync->sync_camera(b_render, b_camera_override, width, height, "");
+
+ BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
+ BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
+ const BufferParams buffer_params = BlenderSync::get_buffer_params(
+ b_null_space_view3d, b_null_region_view3d, scene->camera, width, height);
+ session->reset(session_params, buffer_params);
+
+ /* reset time */
+ start_resize_time = 0.0;
+
+ {
+ thread_scoped_lock lock(draw_state_.mutex);
+ draw_state_.last_pass_index = -1;
+ }
+}
+
+void BlenderSession::free_session()
+{
+ if (session) {
+ session->cancel(true);
+ }
+
+ delete sync;
+ sync = nullptr;
+
+ delete session;
+ session = nullptr;
+
+ display_driver_ = nullptr;
+}
+
+void BlenderSession::full_buffer_written(string_view filename)
+{
+ full_buffer_files_.emplace_back(filename);
+}
+
+static void add_cryptomatte_layer(BL::RenderResult &b_rr, string name, string manifest)
+{
+ string identifier = string_printf("%08x", util_murmur_hash3(name.c_str(), name.length(), 0));
+ string prefix = "cryptomatte/" + identifier.substr(0, 7) + "/";
+
+ render_add_metadata(b_rr, prefix + "name", name);
+ render_add_metadata(b_rr, prefix + "hash", "MurmurHash3_32");
+ render_add_metadata(b_rr, prefix + "conversion", "uint32_to_float32");
+ render_add_metadata(b_rr, prefix + "manifest", manifest);
+}
+
+void BlenderSession::stamp_view_layer_metadata(Scene *scene, const string &view_layer_name)
+{
+ BL::RenderResult b_rr = b_engine.get_result();
+ string prefix = "cycles." + view_layer_name + ".";
+
+ /* Configured number of samples for the view layer. */
+ b_rr.stamp_data_add_field((prefix + "samples").c_str(),
+ to_string(session->params.samples).c_str());
+
+ /* Store ranged samples information. */
+ /* TODO(sergey): Need to bring this information back. */
+#if 0
+ if (session->tile_manager.range_num_samples != -1) {
+ b_rr.stamp_data_add_field((prefix + "range_start_sample").c_str(),
+ to_string(session->tile_manager.range_start_sample).c_str());
+ b_rr.stamp_data_add_field((prefix + "range_num_samples").c_str(),
+ to_string(session->tile_manager.range_num_samples).c_str());
+ }
+#endif
+
+ /* Write cryptomatte metadata. */
+ if (scene->film->get_cryptomatte_passes() & CRYPT_OBJECT) {
+ add_cryptomatte_layer(b_rr,
+ view_layer_name + ".CryptoObject",
+ scene->object_manager->get_cryptomatte_objects(scene));
+ }
+ if (scene->film->get_cryptomatte_passes() & CRYPT_MATERIAL) {
+ add_cryptomatte_layer(b_rr,
+ view_layer_name + ".CryptoMaterial",
+ scene->shader_manager->get_cryptomatte_materials(scene));
+ }
+ if (scene->film->get_cryptomatte_passes() & CRYPT_ASSET) {
+ add_cryptomatte_layer(b_rr,
+ view_layer_name + ".CryptoAsset",
+ scene->object_manager->get_cryptomatte_assets(scene));
+ }
+
+ /* Store synchronization and bare-render times. */
+ double total_time, render_time;
+ session->progress.get_time(total_time, render_time);
+ b_rr.stamp_data_add_field((prefix + "total_time").c_str(),
+ time_human_readable_from_seconds(total_time).c_str());
+ b_rr.stamp_data_add_field((prefix + "render_time").c_str(),
+ time_human_readable_from_seconds(render_time).c_str());
+ b_rr.stamp_data_add_field((prefix + "synchronization_time").c_str(),
+ time_human_readable_from_seconds(total_time - render_time).c_str());
+}
+
+void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
+{
+ b_depsgraph = b_depsgraph_;
+
+ if (session->progress.get_cancel()) {
+ update_status_progress();
+ return;
+ }
+
+ /* Create driver to write out render results. */
+ ensure_display_driver_if_needed();
+ session->set_output_driver(make_unique<BlenderOutputDriver>(b_engine));
+
+ session->full_buffer_written_cb = [&](string_view filename) { full_buffer_written(filename); };
+
+ BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
+
+ /* get buffer parameters */
+ const SessionParams session_params = BlenderSync::get_session_params(
+ b_engine, b_userpref, b_scene, background);
+ BufferParams buffer_params = BlenderSync::get_buffer_params(
+ b_v3d, b_rv3d, scene->camera, width, height);
+
+ /* temporary render result to find needed passes and views */
+ BL::RenderResult b_rr = b_engine.begin_result(0, 0, 1, 1, b_view_layer.name().c_str(), NULL);
+ BL::RenderResult::layers_iterator b_single_rlay;
+ b_rr.layers.begin(b_single_rlay);
+ BL::RenderLayer b_rlay = *b_single_rlay;
+
+ {
+ thread_scoped_lock lock(draw_state_.mutex);
+ b_rlay_name = b_view_layer.name();
+
+ /* Signal that the display pass is to be updated. */
+ draw_state_.last_pass_index = -1;
+ }
+
+ /* Compute render passes and film settings. */
+ sync->sync_render_passes(b_rlay, b_view_layer);
+
+ BL::RenderResult::views_iterator b_view_iter;
+
+ int num_views = 0;
+ for (b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) {
+ num_views++;
+ }
+
+ int view_index = 0;
+ for (b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end();
+ ++b_view_iter, ++view_index) {
+ b_rview_name = b_view_iter->name();
+
+ buffer_params.layer = b_view_layer.name();
+ buffer_params.view = b_rview_name;
+
+ /* set the current view */
+ b_engine.active_view_set(b_rview_name.c_str());
+
+ /* update scene */
+ BL::Object b_camera_override(b_engine.camera_override());
+ sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str());
+ sync->sync_data(
+ b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state);
+ builtin_images_load();
+
+ /* Attempt to free all data which is held by Blender side, since at this
+ * point we know that we've got everything to render current view layer.
+ */
+ /* At the moment we only free if we are not doing multi-view
+ * (or if we are rendering the last view). See T58142/D4239 for discussion.
+ */
+ if (view_index == num_views - 1) {
+ free_blender_memory_if_possible();
+ }
+
+ /* Make sure all views have different noise patterns. - hardcoded value just to make it random
+ */
+ if (view_index != 0) {
+ int seed = scene->integrator->get_seed();
+ seed += hash_uint2(seed, hash_uint2(view_index * 0xdeadbeef, 0));
+ scene->integrator->set_seed(seed);
+ }
+
+ /* Update number of samples per layer. */
+ const int samples = sync->get_layer_samples();
+ const bool bound_samples = sync->get_layer_bound_samples();
+
+ SessionParams effective_session_params = session_params;
+ if (samples != 0 && (!bound_samples || (samples < session_params.samples))) {
+ effective_session_params.samples = samples;
+ }
+
+ /* Update session itself. */
+ session->reset(effective_session_params, buffer_params);
+
+ /* render */
+ if (!b_engine.is_preview() && background && print_render_stats) {
+ scene->enable_update_stats();
+ }
+
+ session->start();
+ session->wait();
+
+ if (!b_engine.is_preview() && background && print_render_stats) {
+ RenderStats stats;
+ session->collect_statistics(&stats);
+ printf("Render statistics:\n%s\n", stats.full_report().c_str());
+ }
+
+ if (session->progress.get_cancel())
+ break;
+ }
+
+ /* add metadata */
+ stamp_view_layer_metadata(scene, b_rlay_name);
+
+ /* free result without merging */
+ b_engine.end_result(b_rr, true, false, false);
+
+ /* When tiled rendering is used there will be no "write" done for the tile. Forcefully clear
+ * highlighted tiles now, so that the highlight will be removed while processing full frame from
+ * file. */
+ b_engine.tile_highlight_clear_all();
+
+ double total_time, render_time;
+ session->progress.get_time(total_time, render_time);
+ VLOG(1) << "Total render time: " << total_time;
+ VLOG(1) << "Render time (without synchronization): " << render_time;
+}
+
+void BlenderSession::render_frame_finish()
+{
+ /* Processing of all layers and views is done. Clear the strings so that we can communicate
+ * progress about reading files and denoising them. */
+ b_rlay_name = "";
+ b_rview_name = "";
+
+ if (!b_render.use_persistent_data()) {
+ /* Free the sync object so that it can properly dereference nodes from the scene graph before
+ * the graph is freed. */
+ delete sync;
+ sync = nullptr;
+
+ session->device_free();
+ }
+
+ for (string_view filename : full_buffer_files_) {
+ session->process_full_buffer_from_disk(filename);
+ if (check_and_report_session_error()) {
+ break;
+ }
+ }
+
+ for (string_view filename : full_buffer_files_) {
+ path_remove(filename);
+ }
+
+ /* Clear driver. */
+ session->set_output_driver(nullptr);
+ session->full_buffer_written_cb = function_null;
+
+ /* All the files are handled.
+ * Clear the list so that this session can be re-used by Persistent Data. */
+ full_buffer_files_.clear();
+}
+
+static PassType bake_type_to_pass(const string &bake_type_str, const int bake_filter)
+{
+ const char *bake_type = bake_type_str.c_str();
+
+ /* data passes */
+ if (strcmp(bake_type, "POSITION") == 0) {
+ return PASS_POSITION;
+ }
+ else if (strcmp(bake_type, "NORMAL") == 0) {
+ return PASS_NORMAL;
+ }
+ else if (strcmp(bake_type, "UV") == 0) {
+ return PASS_UV;
+ }
+ else if (strcmp(bake_type, "ROUGHNESS") == 0) {
+ return PASS_ROUGHNESS;
+ }
+ else if (strcmp(bake_type, "EMIT") == 0) {
+ return PASS_EMISSION;
+ }
+ /* light passes */
+ else if (strcmp(bake_type, "AO") == 0) {
+ return PASS_AO;
+ }
+ else if (strcmp(bake_type, "COMBINED") == 0) {
+ return PASS_COMBINED;
+ }
+ else if (strcmp(bake_type, "SHADOW") == 0) {
+ return PASS_SHADOW;
+ }
+ else if (strcmp(bake_type, "DIFFUSE") == 0) {
+ if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
+ bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
+ return PASS_DIFFUSE;
+ }
+ else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
+ return PASS_DIFFUSE_DIRECT;
+ }
+ else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
+ return PASS_DIFFUSE_INDIRECT;
+ }
+ else {
+ return PASS_DIFFUSE_COLOR;
+ }
+ }
+ else if (strcmp(bake_type, "GLOSSY") == 0) {
+ if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
+ bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
+ return PASS_GLOSSY;
+ }
+ else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
+ return PASS_GLOSSY_DIRECT;
+ }
+ else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
+ return PASS_GLOSSY_INDIRECT;
+ }
+ else {
+ return PASS_GLOSSY_COLOR;
+ }
+ }
+ else if (strcmp(bake_type, "TRANSMISSION") == 0) {
+ if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
+ bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
+ return PASS_TRANSMISSION;
+ }
+ else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
+ return PASS_TRANSMISSION_DIRECT;
+ }
+ else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
+ return PASS_TRANSMISSION_INDIRECT;
+ }
+ else {
+ return PASS_TRANSMISSION_COLOR;
+ }
+ }
+ /* extra */
+ else if (strcmp(bake_type, "ENVIRONMENT") == 0) {
+ return PASS_BACKGROUND;
+ }
+
+ return PASS_COMBINED;
+}
+
+void BlenderSession::bake(BL::Depsgraph &b_depsgraph_,
+ BL::Object &b_object,
+ const string &bake_type,
+ const int bake_filter,
+ const int bake_width,
+ const int bake_height)
+{
+ b_depsgraph = b_depsgraph_;
+
+ /* Initialize bake manager, before we load the baking kernels. */
+ scene->bake_manager->set(scene, b_object.name());
+
+ /* Add render pass that we want to bake, and name it Combined so that it is
+ * used as that on the Blender side. */
+ Pass *pass = scene->create_node<Pass>();
+ pass->set_name(ustring("Combined"));
+ pass->set_type(bake_type_to_pass(bake_type, bake_filter));
+ pass->set_include_albedo((bake_filter & BL::BakeSettings::pass_filter_COLOR));
+
+ session->set_display_driver(nullptr);
+ session->set_output_driver(make_unique<BlenderOutputDriver>(b_engine));
+
+ if (!session->progress.get_cancel()) {
+ /* Sync scene. */
+ BL::Object b_camera_override(b_engine.camera_override());
+ sync->sync_camera(b_render, b_camera_override, width, height, "");
+ sync->sync_data(
+ b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state);
+ builtin_images_load();
+ }
+
+ /* Object might have been disabled for rendering or excluded in some
+ * other way, in that case Blender will report a warning afterwards. */
+ bool object_found = false;
+ foreach (Object *ob, scene->objects) {
+ if (ob->name == b_object.name()) {
+ object_found = true;
+ break;
+ }
+ }
+
+ if (object_found && !session->progress.get_cancel()) {
+ /* Get session and buffer parameters. */
+ const SessionParams session_params = BlenderSync::get_session_params(
+ b_engine, b_userpref, b_scene, background);
+
+ BufferParams buffer_params;
+ buffer_params.width = bake_width;
+ buffer_params.height = bake_height;
+
+ /* Update session. */
+ session->reset(session_params, buffer_params);
+
+ session->progress.set_update_callback(
+ function_bind(&BlenderSession::update_bake_progress, this));
+ }
+
+ /* Perform bake. Check cancel to avoid crash with incomplete scene data. */
+ if (object_found && !session->progress.get_cancel()) {
+ session->start();
+ session->wait();
+ }
+
+ session->set_output_driver(nullptr);
+}
+
+void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
+{
+ /* only used for viewport render */
+ if (!b_v3d)
+ return;
+
+ /* on session/scene parameter changes, we recreate session entirely */
+ const SessionParams session_params = BlenderSync::get_session_params(
+ b_engine, b_userpref, b_scene, background);
+ const SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
+ const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
+
+ if (session->params.modified(session_params) || scene->params.modified(scene_params)) {
+ free_session();
+ create_session();
+ }
+
+ ensure_display_driver_if_needed();
+
+ /* increase samples and render time, but never decrease */
+ session->set_samples(session_params.samples);
+ session->set_time_limit(session_params.time_limit);
+ session->set_pause(session_pause);
+
+ /* copy recalc flags, outside of mutex so we can decide to do the real
+ * synchronization at a later time to not block on running updates */
+ sync->sync_recalc(b_depsgraph_, b_v3d);
+
+ /* don't do synchronization if on pause */
+ if (session_pause) {
+ tag_update();
+ return;
+ }
+
+ /* try to acquire mutex. if we don't want to or can't, come back later */
+ if (!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
+ tag_update();
+ return;
+ }
+
+ /* data and camera synchronize */
+ b_depsgraph = b_depsgraph_;
+
+ BL::Object b_camera_override(b_engine.camera_override());
+ sync->sync_data(
+ b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state);
+
+ if (b_rv3d)
+ sync->sync_view(b_v3d, b_rv3d, width, height);
+ else
+ sync->sync_camera(b_render, b_camera_override, width, height, "");
+
+ /* get buffer parameters */
+ const BufferParams buffer_params = BlenderSync::get_buffer_params(
+ b_v3d, b_rv3d, scene->camera, width, height);
+
+ /* reset if needed */
+ if (scene->need_reset()) {
+ session->reset(session_params, buffer_params);
+
+ /* After session reset, so device is not accessing image data anymore. */
+ builtin_images_load();
+
+ /* reset time */
+ start_resize_time = 0.0;
+ }
+
+ /* unlock */
+ session->scene->mutex.unlock();
+
+ /* Start rendering thread, if it's not running already. Do this
+ * after all scene data has been synced at least once. */
+ session->start();
+}
+
+void BlenderSession::draw(BL::SpaceImageEditor &space_image)
+{
+ if (!session || !session->scene) {
+ /* Offline render drawing does not force the render engine update, which means it's possible
+ * that the Session is not created yet. */
+ return;
+ }
+
+ thread_scoped_lock lock(draw_state_.mutex);
+
+ const int pass_index = space_image.image_user().multilayer_pass();
+ if (pass_index != draw_state_.last_pass_index) {
+ BL::RenderPass b_display_pass(b_engine.pass_by_index_get(b_rlay_name.c_str(), pass_index));
+ if (!b_display_pass) {
+ return;
+ }
+
+ Scene *scene = session->scene;
+
+ thread_scoped_lock lock(scene->mutex);
+
+ const Pass *pass = Pass::find(scene->passes, b_display_pass.name());
+ if (!pass) {
+ return;
+ }
+
+ scene->film->set_display_pass(pass->get_type());
+
+ draw_state_.last_pass_index = pass_index;
+ }
+
+ if (display_driver_) {
+ BL::Array<float, 2> zoom = space_image.zoom();
+ display_driver_->set_zoom(zoom[0], zoom[1]);
+ }
+
+ session->draw();
+}
+
+void BlenderSession::view_draw(int w, int h)
+{
+ /* pause in redraw in case update is not being called due to final render */
+ session->set_pause(BlenderSync::get_session_pause(b_scene, background));
+
+ /* before drawing, we verify camera and viewport size changes, because
+ * we do not get update callbacks for those, we must detect them here */
+ if (session->ready_to_reset()) {
+ bool reset = false;
+
+ /* if dimensions changed, reset */
+ if (width != w || height != h) {
+ if (start_resize_time == 0.0) {
+ /* don't react immediately to resizes to avoid flickery resizing
+ * of the viewport, and some window managers changing the window
+ * size temporarily on unminimize */
+ start_resize_time = time_dt();
+ tag_redraw();
+ }
+ else if (time_dt() - start_resize_time < 0.2) {
+ tag_redraw();
+ }
+ else {
+ width = w;
+ height = h;
+ reset = true;
+ }
+ }
+
+ /* try to acquire mutex. if we can't, come back later */
+ if (!session->scene->mutex.try_lock()) {
+ tag_update();
+ }
+ else {
+ /* update camera from 3d view */
+
+ sync->sync_view(b_v3d, b_rv3d, width, height);
+
+ if (scene->camera->is_modified())
+ reset = true;
+
+ session->scene->mutex.unlock();
+ }
+
+ /* reset if requested */
+ if (reset) {
+ const SessionParams session_params = BlenderSync::get_session_params(
+ b_engine, b_userpref, b_scene, background);
+ const BufferParams buffer_params = BlenderSync::get_buffer_params(
+ b_v3d, b_rv3d, scene->camera, width, height);
+ const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
+
+ if (session_pause == false) {
+ session->reset(session_params, buffer_params);
+ start_resize_time = 0.0;
+ }
+ }
+ }
+ else {
+ tag_update();
+ }
+
+ /* update status and progress for 3d view draw */
+ update_status_progress();
+
+ /* draw */
+ session->draw();
+}
+
+void BlenderSession::get_status(string &status, string &substatus)
+{
+ session->progress.get_status(status, substatus);
+}
+
+void BlenderSession::get_progress(float &progress, double &total_time, double &render_time)
+{
+ session->progress.get_time(total_time, render_time);
+ progress = session->progress.get_progress();
+}
+
+void BlenderSession::update_bake_progress()
+{
+ float progress = session->progress.get_progress();
+
+ if (progress != last_progress) {
+ b_engine.update_progress(progress);
+ last_progress = progress;
+ }
+}
+
+void BlenderSession::update_status_progress()
+{
+ string timestatus, status, substatus;
+ string scene_status = "";
+ float progress;
+ double total_time, remaining_time = 0, render_time;
+ float mem_used = (float)session->stats.mem_used / 1024.0f / 1024.0f;
+ float mem_peak = (float)session->stats.mem_peak / 1024.0f / 1024.0f;
+
+ get_status(status, substatus);
+ get_progress(progress, total_time, render_time);
+
+ if (progress > 0) {
+ remaining_time = session->get_estimated_remaining_time();
+ }
+
+ if (background) {
+ if (scene)
+ scene_status += " | " + scene->name;
+ if (b_rlay_name != "")
+ scene_status += ", " + b_rlay_name;
+
+ if (b_rview_name != "")
+ scene_status += ", " + b_rview_name;
+
+ if (remaining_time > 0) {
+ timestatus += "Remaining:" + time_human_readable_from_seconds(remaining_time) + " | ";
+ }
+
+ timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak);
+
+ if (status.size() > 0)
+ status = " | " + status;
+ if (substatus.size() > 0)
+ status += " | " + substatus;
+ }
+
+ double current_time = time_dt();
+ /* When rendering in a window, redraw the status at least once per second to keep the elapsed
+ * and remaining time up-to-date. For headless rendering, only report when something
+ * significant changes to keep the console output readable. */
+ if (status != last_status || (!headless && (current_time - last_status_time) > 1.0)) {
+ b_engine.update_stats("", (timestatus + scene_status + status).c_str());
+ b_engine.update_memory_stats(mem_used, mem_peak);
+ last_status = status;
+ last_status_time = current_time;
+ }
+ if (progress != last_progress) {
+ b_engine.update_progress(progress);
+ last_progress = progress;
+ }
+
+ check_and_report_session_error();
+}
+
+bool BlenderSession::check_and_report_session_error()
+{
+ if (!session->progress.get_error()) {
+ return false;
+ }
+
+ const string error = session->progress.get_error_message();
+ if (error != last_error) {
+ /* TODO(sergey): Currently C++ RNA API doesn't let us to use mnemonic name for the variable.
+ * Would be nice to have this figured out.
+ *
+ * For until then, 1 << 5 means RPT_ERROR. */
+ b_engine.report(1 << 5, error.c_str());
+ b_engine.error_set(error.c_str());
+ last_error = error;
+ }
+
+ return true;
+}
+
+void BlenderSession::tag_update()
+{
+ /* tell blender that we want to get another update callback */
+ b_engine.tag_update();
+}
+
+void BlenderSession::tag_redraw()
+{
+ if (background) {
+ /* update stats and progress, only for background here because
+ * in 3d view we do it in draw for thread safety reasons */
+ update_status_progress();
+
+ /* offline render, redraw if timeout passed */
+ if (time_dt() - last_redraw_time > 1.0) {
+ b_engine.tag_redraw();
+ last_redraw_time = time_dt();
+ }
+ }
+ else {
+ /* tell blender that we want to redraw */
+ b_engine.tag_redraw();
+ }
+}
+
+void BlenderSession::test_cancel()
+{
+ /* test if we need to cancel rendering */
+ if (background)
+ if (b_engine.test_break())
+ session->progress.set_cancel("Cancelled");
+}
+
+void BlenderSession::free_blender_memory_if_possible()
+{
+ if (!background) {
+ /* During interactive render we can not free anything: attempts to save
+ * memory would cause things to be allocated and evaluated for every
+ * updated sample.
+ */
+ return;
+ }
+ b_engine.free_blender_memory();
+}
+
+void BlenderSession::ensure_display_driver_if_needed()
+{
+ if (display_driver_) {
+ /* Driver is already created. */
+ return;
+ }
+
+ if (headless) {
+ /* No display needed for headless. */
+ return;
+ }
+
+ if (b_engine.is_preview()) {
+ /* TODO(sergey): Investigate whether DisplayDriver can be used for the preview as well. */
+ return;
+ }
+
+ unique_ptr<BlenderDisplayDriver> display_driver = make_unique<BlenderDisplayDriver>(b_engine,
+ b_scene);
+ display_driver_ = display_driver.get();
+ session->set_display_driver(move(display_driver));
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/session.h b/intern/cycles/blender/session.h
new file mode 100644
index 00000000000..fa24b5f7467
--- /dev/null
+++ b/intern/cycles/blender/session.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLENDER_SESSION_H__
+#define __BLENDER_SESSION_H__
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_blender_cpp.h"
+
+#include "device/device.h"
+
+#include "scene/bake.h"
+#include "scene/scene.h"
+#include "session/session.h"
+
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BlenderDisplayDriver;
+class BlenderSync;
+class ImageMetaData;
+class Scene;
+class Session;
+
+class BlenderSession {
+ public:
+ BlenderSession(BL::RenderEngine &b_engine,
+ BL::Preferences &b_userpref,
+ BL::BlendData &b_data,
+ bool preview_osl);
+
+ BlenderSession(BL::RenderEngine &b_engine,
+ BL::Preferences &b_userpref,
+ BL::BlendData &b_data,
+ BL::SpaceView3D &b_v3d,
+ BL::RegionView3D &b_rv3d,
+ int width,
+ int height);
+
+ ~BlenderSession();
+
+ /* session */
+ void create_session();
+ void free_session();
+
+ void reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph);
+
+ /* offline render */
+ void render(BL::Depsgraph &b_depsgraph);
+
+ void render_frame_finish();
+
+ void bake(BL::Depsgraph &b_depsgrah,
+ BL::Object &b_object,
+ const string &pass_type,
+ const int custom_flag,
+ const int bake_width,
+ const int bake_height);
+
+ void full_buffer_written(string_view filename);
+ /* interactive updates */
+ void synchronize(BL::Depsgraph &b_depsgraph);
+
+ /* drawing */
+ void draw(BL::SpaceImageEditor &space_image);
+ void view_draw(int w, int h);
+ void tag_redraw();
+ void tag_update();
+ void get_status(string &status, string &substatus);
+ void get_progress(float &progress, double &total_time, double &render_time);
+ void test_cancel();
+ void update_status_progress();
+ void update_bake_progress();
+
+ bool background;
+ Session *session;
+ Scene *scene;
+ BlenderSync *sync;
+ double last_redraw_time;
+
+ BL::RenderEngine b_engine;
+ BL::Preferences b_userpref;
+ BL::BlendData b_data;
+ BL::RenderSettings b_render;
+ BL::Depsgraph b_depsgraph;
+ /* NOTE: Blender's scene might become invalid after call
+ * #free_blender_memory_if_possible(). */
+ BL::Scene b_scene;
+ BL::SpaceView3D b_v3d;
+ BL::RegionView3D b_rv3d;
+ string b_rlay_name;
+ string b_rview_name;
+
+ string last_status;
+ string last_error;
+ float last_progress;
+ double last_status_time;
+
+ int width, height;
+ bool preview_osl;
+ double start_resize_time;
+
+ void *python_thread_state;
+
+ bool use_developer_ui;
+
+ /* Global state which is common for all render sessions created from Blender.
+ * Usually denotes command line arguments.
+ */
+ static DeviceTypeMask device_override;
+
+ /* Blender is running from the command line, no windows are shown and some
+ * extra render optimization is possible (possible to free draw-only data and
+ * so on.
+ */
+ static bool headless;
+
+ static bool print_render_stats;
+
+ protected:
+ void stamp_view_layer_metadata(Scene *scene, const string &view_layer_name);
+
+ /* Check whether session error happened.
+ * If so, it is reported to the render engine and true is returned.
+ * Otherwise false is returned. */
+ bool check_and_report_session_error();
+
+ void builtin_images_load();
+
+ /* Is used after each render layer synchronization is done with the goal
+ * of freeing render engine data which is held from Blender side (for
+ * example, dependency graph).
+ */
+ void free_blender_memory_if_possible();
+
+ void ensure_display_driver_if_needed();
+
+ struct {
+ thread_mutex mutex;
+ int last_pass_index = -1;
+ } draw_state_;
+
+ /* NOTE: The BlenderSession references the display driver. */
+ BlenderDisplayDriver *display_driver_ = nullptr;
+
+ vector<string> full_buffer_files_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_SESSION_H__ */
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
new file mode 100644
index 00000000000..0cd9052b47a
--- /dev/null
+++ b/intern/cycles/blender/shader.cpp
@@ -0,0 +1,1589 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/shader.h"
+#include "scene/background.h"
+#include "scene/colorspace.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/osl.h"
+#include "scene/scene.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+
+#include "blender/image.h"
+#include "blender/sync.h"
+#include "blender/texture.h"
+#include "blender/util.h"
+
+#include "util/debug.h"
+#include "util/foreach.h"
+#include "util/set.h"
+#include "util/string.h"
+#include "util/task.h"
+
+CCL_NAMESPACE_BEGIN
+
+typedef map<void *, ShaderInput *> PtrInputMap;
+typedef map<void *, ShaderOutput *> PtrOutputMap;
+typedef map<string, ConvertNode *> ProxyMap;
+
+/* Find */
+
+void BlenderSync::find_shader(BL::ID &id, array<Node *> &used_shaders, Shader *default_shader)
+{
+ Shader *shader = (id) ? shader_map.find(id) : default_shader;
+
+ used_shaders.push_back_slow(shader);
+ shader->tag_used(scene);
+}
+
+/* RNA translation utilities */
+
+static VolumeSampling get_volume_sampling(PointerRNA &ptr)
+{
+ return (VolumeSampling)get_enum(
+ ptr, "volume_sampling", VOLUME_NUM_SAMPLING, VOLUME_SAMPLING_DISTANCE);
+}
+
+static VolumeInterpolation get_volume_interpolation(PointerRNA &ptr)
+{
+ return (VolumeInterpolation)get_enum(
+ ptr, "volume_interpolation", VOLUME_NUM_INTERPOLATION, VOLUME_INTERPOLATION_LINEAR);
+}
+
+static DisplacementMethod get_displacement_method(PointerRNA &ptr)
+{
+ return (DisplacementMethod)get_enum(
+ ptr, "displacement_method", DISPLACE_NUM_METHODS, DISPLACE_BUMP);
+}
+
+static int validate_enum_value(int value, int num_values, int default_value)
+{
+ if (value >= num_values) {
+ return default_value;
+ }
+ return value;
+}
+
+template<typename NodeType> static InterpolationType get_image_interpolation(NodeType &b_node)
+{
+ int value = b_node.interpolation();
+ return (InterpolationType)validate_enum_value(
+ value, INTERPOLATION_NUM_TYPES, INTERPOLATION_LINEAR);
+}
+
+template<typename NodeType> static ExtensionType get_image_extension(NodeType &b_node)
+{
+ int value = b_node.extension();
+ return (ExtensionType)validate_enum_value(value, EXTENSION_NUM_TYPES, EXTENSION_REPEAT);
+}
+
+static ImageAlphaType get_image_alpha_type(BL::Image &b_image)
+{
+ int value = b_image.alpha_mode();
+ return (ImageAlphaType)validate_enum_value(value, IMAGE_ALPHA_NUM_TYPES, IMAGE_ALPHA_AUTO);
+}
+
+/* Attribute name translation utilities */
+
+/* Since Eevee needs to know whether the attribute is uniform or varying
+ * at the time it compiles the shader for the material, Blender had to
+ * introduce different namespaces (types) in its attribute node. However,
+ * Cycles already has object attributes that form a uniform namespace with
+ * the more common varying attributes. Without completely reworking the
+ * attribute handling in Cycles to introduce separate namespaces (this could
+ * be especially hard for OSL which directly uses the name string), the
+ * space identifier has to be added to the attribute name as a prefix.
+ *
+ * The prefixes include a control character to ensure the user specified
+ * name can't accidentally include a special prefix.
+ */
+
+static const string_view object_attr_prefix("\x01object:");
+static const string_view instancer_attr_prefix("\x01instancer:");
+
+static ustring blender_attribute_name_add_type(const string &name, BlenderAttributeType type)
+{
+ switch (type) {
+ case BL::ShaderNodeAttribute::attribute_type_OBJECT:
+ return ustring::concat(object_attr_prefix, name);
+ case BL::ShaderNodeAttribute::attribute_type_INSTANCER:
+ return ustring::concat(instancer_attr_prefix, name);
+ default:
+ return ustring(name);
+ }
+}
+
+BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name)
+{
+ string_view sname(name);
+
+ if (sname.substr(0, object_attr_prefix.size()) == object_attr_prefix) {
+ *r_real_name = sname.substr(object_attr_prefix.size());
+ return BL::ShaderNodeAttribute::attribute_type_OBJECT;
+ }
+
+ if (sname.substr(0, instancer_attr_prefix.size()) == instancer_attr_prefix) {
+ *r_real_name = sname.substr(instancer_attr_prefix.size());
+ return BL::ShaderNodeAttribute::attribute_type_INSTANCER;
+ }
+
+ return BL::ShaderNodeAttribute::attribute_type_GEOMETRY;
+}
+
+/* Graph */
+
+static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name)
+{
+ for (BL::NodeSocket &b_out : b_node.outputs) {
+ if (b_out.identifier() == name) {
+ return b_out;
+ }
+ }
+ assert(0);
+ return *b_node.outputs.begin();
+}
+
+static float3 get_node_output_rgba(BL::Node &b_node, const string &name)
+{
+ BL::NodeSocket b_sock = get_node_output(b_node, name);
+ float value[4];
+ RNA_float_get_array(&b_sock.ptr, "default_value", value);
+ return make_float3(value[0], value[1], value[2]);
+}
+
+static float get_node_output_value(BL::Node &b_node, const string &name)
+{
+ BL::NodeSocket b_sock = get_node_output(b_node, name);
+ return RNA_float_get(&b_sock.ptr, "default_value");
+}
+
+static float3 get_node_output_vector(BL::Node &b_node, const string &name)
+{
+ BL::NodeSocket b_sock = get_node_output(b_node, name);
+ float value[3];
+ RNA_float_get_array(&b_sock.ptr, "default_value", value);
+ return make_float3(value[0], value[1], value[2]);
+}
+
+static SocketType::Type convert_socket_type(BL::NodeSocket &b_socket)
+{
+ switch (b_socket.type()) {
+ case BL::NodeSocket::type_VALUE:
+ return SocketType::FLOAT;
+ case BL::NodeSocket::type_INT:
+ return SocketType::INT;
+ case BL::NodeSocket::type_VECTOR:
+ return SocketType::VECTOR;
+ case BL::NodeSocket::type_RGBA:
+ return SocketType::COLOR;
+ case BL::NodeSocket::type_STRING:
+ return SocketType::STRING;
+ case BL::NodeSocket::type_SHADER:
+ return SocketType::CLOSURE;
+
+ default:
+ return SocketType::UNDEFINED;
+ }
+}
+
+static void set_default_value(ShaderInput *input,
+ BL::NodeSocket &b_sock,
+ BL::BlendData &b_data,
+ BL::ID &b_id)
+{
+ Node *node = input->parent;
+ const SocketType &socket = input->socket_type;
+
+ /* copy values for non linked inputs */
+ switch (input->type()) {
+ case SocketType::FLOAT: {
+ node->set(socket, get_float(b_sock.ptr, "default_value"));
+ break;
+ }
+ case SocketType::INT: {
+ if (b_sock.type() == BL::NodeSocket::type_BOOLEAN) {
+ node->set(socket, get_boolean(b_sock.ptr, "default_value"));
+ }
+ else {
+ node->set(socket, get_int(b_sock.ptr, "default_value"));
+ }
+ break;
+ }
+ case SocketType::COLOR: {
+ node->set(socket, float4_to_float3(get_float4(b_sock.ptr, "default_value")));
+ break;
+ }
+ case SocketType::NORMAL:
+ case SocketType::POINT:
+ case SocketType::VECTOR: {
+ node->set(socket, get_float3(b_sock.ptr, "default_value"));
+ break;
+ }
+ case SocketType::STRING: {
+ node->set(
+ socket,
+ (ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void get_tex_mapping(TextureNode *mapping, BL::TexMapping &b_mapping)
+{
+ if (!b_mapping)
+ return;
+
+ mapping->set_tex_mapping_translation(get_float3(b_mapping.translation()));
+ mapping->set_tex_mapping_rotation(get_float3(b_mapping.rotation()));
+ mapping->set_tex_mapping_scale(get_float3(b_mapping.scale()));
+ mapping->set_tex_mapping_type((TextureMapping::Type)b_mapping.vector_type());
+
+ mapping->set_tex_mapping_x_mapping((TextureMapping::Mapping)b_mapping.mapping_x());
+ mapping->set_tex_mapping_y_mapping((TextureMapping::Mapping)b_mapping.mapping_y());
+ mapping->set_tex_mapping_z_mapping((TextureMapping::Mapping)b_mapping.mapping_z());
+}
+
+static ShaderNode *add_node(Scene *scene,
+ BL::RenderEngine &b_engine,
+ BL::BlendData &b_data,
+ BL::Depsgraph &b_depsgraph,
+ BL::Scene &b_scene,
+ ShaderGraph *graph,
+ BL::ShaderNodeTree &b_ntree,
+ BL::ShaderNode &b_node)
+{
+ ShaderNode *node = NULL;
+
+ /* existing blender nodes */
+ if (b_node.is_a(&RNA_ShaderNodeRGBCurve)) {
+ BL::ShaderNodeRGBCurve b_curve_node(b_node);
+ BL::CurveMapping mapping(b_curve_node.mapping());
+ RGBCurvesNode *curves = graph->create_node<RGBCurvesNode>();
+ array<float3> curve_mapping_curves;
+ float min_x, max_x;
+ curvemapping_color_to_array(mapping, curve_mapping_curves, RAMP_TABLE_SIZE, true);
+ curvemapping_minmax(mapping, 4, &min_x, &max_x);
+ curves->set_min_x(min_x);
+ curves->set_max_x(max_x);
+ curves->set_curves(curve_mapping_curves);
+ node = curves;
+ }
+ if (b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
+ BL::ShaderNodeVectorCurve b_curve_node(b_node);
+ BL::CurveMapping mapping(b_curve_node.mapping());
+ VectorCurvesNode *curves = graph->create_node<VectorCurvesNode>();
+ array<float3> curve_mapping_curves;
+ float min_x, max_x;
+ curvemapping_color_to_array(mapping, curve_mapping_curves, RAMP_TABLE_SIZE, false);
+ curvemapping_minmax(mapping, 3, &min_x, &max_x);
+ curves->set_min_x(min_x);
+ curves->set_max_x(max_x);
+ curves->set_curves(curve_mapping_curves);
+ node = curves;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeFloatCurve)) {
+ BL::ShaderNodeFloatCurve b_curve_node(b_node);
+ BL::CurveMapping mapping(b_curve_node.mapping());
+ FloatCurveNode *curve = graph->create_node<FloatCurveNode>();
+ array<float> curve_mapping_curve;
+ float min_x, max_x;
+ curvemapping_float_to_array(mapping, curve_mapping_curve, RAMP_TABLE_SIZE);
+ curvemapping_minmax(mapping, 1, &min_x, &max_x);
+ curve->set_min_x(min_x);
+ curve->set_max_x(max_x);
+ curve->set_curve(curve_mapping_curve);
+ node = curve;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) {
+ RGBRampNode *ramp = graph->create_node<RGBRampNode>();
+ BL::ShaderNodeValToRGB b_ramp_node(b_node);
+ BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp());
+ array<float3> ramp_values;
+ array<float> ramp_alpha;
+ colorramp_to_array(b_color_ramp, ramp_values, ramp_alpha, RAMP_TABLE_SIZE);
+ ramp->set_ramp(ramp_values);
+ ramp->set_ramp_alpha(ramp_alpha);
+ ramp->set_interpolate(b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT);
+ node = ramp;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeRGB)) {
+ ColorNode *color = graph->create_node<ColorNode>();
+ color->set_value(get_node_output_rgba(b_node, "Color"));
+ node = color;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeValue)) {
+ ValueNode *value = graph->create_node<ValueNode>();
+ value->set_value(get_node_output_value(b_node, "Value"));
+ node = value;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeCameraData)) {
+ node = graph->create_node<CameraNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeInvert)) {
+ node = graph->create_node<InvertNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeGamma)) {
+ node = graph->create_node<GammaNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
+ node = graph->create_node<BrightContrastNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeMixRGB)) {
+ BL::ShaderNodeMixRGB b_mix_node(b_node);
+ MixNode *mix = graph->create_node<MixNode>();
+ mix->set_mix_type((NodeMix)b_mix_node.blend_type());
+ mix->set_use_clamp(b_mix_node.use_clamp());
+ node = mix;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
+ node = graph->create_node<SeparateRGBNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
+ node = graph->create_node<CombineRGBNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeSeparateHSV)) {
+ node = graph->create_node<SeparateHSVNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
+ node = graph->create_node<CombineHSVNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) {
+ node = graph->create_node<SeparateXYZNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeCombineXYZ)) {
+ node = graph->create_node<CombineXYZNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeHueSaturation)) {
+ node = graph->create_node<HSVNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
+ node = graph->create_node<RGBToBWNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeMapRange)) {
+ BL::ShaderNodeMapRange b_map_range_node(b_node);
+ MapRangeNode *map_range_node = graph->create_node<MapRangeNode>();
+ map_range_node->set_clamp(b_map_range_node.clamp());
+ map_range_node->set_range_type((NodeMapRangeType)b_map_range_node.interpolation_type());
+ node = map_range_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeClamp)) {
+ BL::ShaderNodeClamp b_clamp_node(b_node);
+ ClampNode *clamp_node = graph->create_node<ClampNode>();
+ clamp_node->set_clamp_type((NodeClampType)b_clamp_node.clamp_type());
+ node = clamp_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeMath)) {
+ BL::ShaderNodeMath b_math_node(b_node);
+ MathNode *math_node = graph->create_node<MathNode>();
+ math_node->set_math_type((NodeMathType)b_math_node.operation());
+ math_node->set_use_clamp(b_math_node.use_clamp());
+ node = math_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
+ BL::ShaderNodeVectorMath b_vector_math_node(b_node);
+ VectorMathNode *vector_math_node = graph->create_node<VectorMathNode>();
+ vector_math_node->set_math_type((NodeVectorMathType)b_vector_math_node.operation());
+ node = vector_math_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeVectorRotate)) {
+ BL::ShaderNodeVectorRotate b_vector_rotate_node(b_node);
+ VectorRotateNode *vector_rotate_node = graph->create_node<VectorRotateNode>();
+ vector_rotate_node->set_rotate_type(
+ (NodeVectorRotateType)b_vector_rotate_node.rotation_type());
+ vector_rotate_node->set_invert(b_vector_rotate_node.invert());
+ node = vector_rotate_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
+ BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
+ VectorTransformNode *vtransform = graph->create_node<VectorTransformNode>();
+ vtransform->set_transform_type((NodeVectorTransformType)b_vector_transform_node.vector_type());
+ vtransform->set_convert_from(
+ (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from());
+ vtransform->set_convert_to(
+ (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to());
+ node = vtransform;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeNormal)) {
+ BL::Node::outputs_iterator out_it;
+ b_node.outputs.begin(out_it);
+
+ NormalNode *norm = graph->create_node<NormalNode>();
+ norm->set_direction(get_node_output_vector(b_node, "Normal"));
+ node = norm;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeMapping)) {
+ BL::ShaderNodeMapping b_mapping_node(b_node);
+ MappingNode *mapping = graph->create_node<MappingNode>();
+ mapping->set_mapping_type((NodeMappingType)b_mapping_node.vector_type());
+ node = mapping;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {
+ node = graph->create_node<FresnelNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
+ node = graph->create_node<LayerWeightNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeAddShader)) {
+ node = graph->create_node<AddClosureNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeMixShader)) {
+ node = graph->create_node<MixClosureNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeAttribute)) {
+ BL::ShaderNodeAttribute b_attr_node(b_node);
+ AttributeNode *attr = graph->create_node<AttributeNode>();
+ attr->set_attribute(blender_attribute_name_add_type(b_attr_node.attribute_name(),
+ b_attr_node.attribute_type()));
+ node = attr;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBackground)) {
+ node = graph->create_node<BackgroundNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeHoldout)) {
+ node = graph->create_node<HoldoutNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
+ BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node);
+ AnisotropicBsdfNode *aniso = graph->create_node<AnisotropicBsdfNode>();
+
+ switch (b_aniso_node.distribution()) {
+ case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
+ aniso->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
+ break;
+ case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
+ aniso->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
+ break;
+ case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
+ aniso->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
+ break;
+ case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
+ aniso->set_distribution(CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
+ break;
+ }
+
+ node = aniso;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
+ node = graph->create_node<DiffuseBsdfNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) {
+ BL::ShaderNodeSubsurfaceScattering b_subsurface_node(b_node);
+
+ SubsurfaceScatteringNode *subsurface = graph->create_node<SubsurfaceScatteringNode>();
+
+ switch (b_subsurface_node.falloff()) {
+ case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
+ subsurface->set_method(CLOSURE_BSSRDF_BURLEY_ID);
+ break;
+ case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK_FIXED_RADIUS:
+ subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
+ break;
+ case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK:
+ subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
+ break;
+ }
+
+ node = subsurface;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
+ BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
+ GlossyBsdfNode *glossy = graph->create_node<GlossyBsdfNode>();
+
+ switch (b_glossy_node.distribution()) {
+ case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
+ glossy->set_distribution(CLOSURE_BSDF_REFLECTION_ID);
+ break;
+ case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
+ glossy->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
+ break;
+ case BL::ShaderNodeBsdfGlossy::distribution_GGX:
+ glossy->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
+ break;
+ case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
+ glossy->set_distribution(CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
+ break;
+ case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
+ glossy->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
+ break;
+ }
+ node = glossy;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfGlass)) {
+ BL::ShaderNodeBsdfGlass b_glass_node(b_node);
+ GlassBsdfNode *glass = graph->create_node<GlassBsdfNode>();
+ switch (b_glass_node.distribution()) {
+ case BL::ShaderNodeBsdfGlass::distribution_SHARP:
+ glass->set_distribution(CLOSURE_BSDF_SHARP_GLASS_ID);
+ break;
+ case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
+ glass->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
+ break;
+ case BL::ShaderNodeBsdfGlass::distribution_GGX:
+ glass->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+ break;
+ case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX:
+ glass->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
+ break;
+ }
+ node = glass;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) {
+ BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
+ RefractionBsdfNode *refraction = graph->create_node<RefractionBsdfNode>();
+ switch (b_refraction_node.distribution()) {
+ case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
+ refraction->set_distribution(CLOSURE_BSDF_REFRACTION_ID);
+ break;
+ case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
+ refraction->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
+ break;
+ case BL::ShaderNodeBsdfRefraction::distribution_GGX:
+ refraction->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+ break;
+ }
+ node = refraction;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfToon)) {
+ BL::ShaderNodeBsdfToon b_toon_node(b_node);
+ ToonBsdfNode *toon = graph->create_node<ToonBsdfNode>();
+ switch (b_toon_node.component()) {
+ case BL::ShaderNodeBsdfToon::component_DIFFUSE:
+ toon->set_component(CLOSURE_BSDF_DIFFUSE_TOON_ID);
+ break;
+ case BL::ShaderNodeBsdfToon::component_GLOSSY:
+ toon->set_component(CLOSURE_BSDF_GLOSSY_TOON_ID);
+ break;
+ }
+ node = toon;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfHair)) {
+ BL::ShaderNodeBsdfHair b_hair_node(b_node);
+ HairBsdfNode *hair = graph->create_node<HairBsdfNode>();
+ switch (b_hair_node.component()) {
+ case BL::ShaderNodeBsdfHair::component_Reflection:
+ hair->set_component(CLOSURE_BSDF_HAIR_REFLECTION_ID);
+ break;
+ case BL::ShaderNodeBsdfHair::component_Transmission:
+ hair->set_component(CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
+ break;
+ }
+ node = hair;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfHairPrincipled)) {
+ BL::ShaderNodeBsdfHairPrincipled b_principled_hair_node(b_node);
+ PrincipledHairBsdfNode *principled_hair = graph->create_node<PrincipledHairBsdfNode>();
+ principled_hair->set_parametrization(
+ (NodePrincipledHairParametrization)get_enum(b_principled_hair_node.ptr,
+ "parametrization",
+ NODE_PRINCIPLED_HAIR_NUM,
+ NODE_PRINCIPLED_HAIR_REFLECTANCE));
+ node = principled_hair;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) {
+ BL::ShaderNodeBsdfPrincipled b_principled_node(b_node);
+ PrincipledBsdfNode *principled = graph->create_node<PrincipledBsdfNode>();
+ switch (b_principled_node.distribution()) {
+ case BL::ShaderNodeBsdfPrincipled::distribution_GGX:
+ principled->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+ break;
+ case BL::ShaderNodeBsdfPrincipled::distribution_MULTI_GGX:
+ principled->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
+ break;
+ }
+ switch (b_principled_node.subsurface_method()) {
+ case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY:
+ principled->set_subsurface_method(CLOSURE_BSSRDF_BURLEY_ID);
+ break;
+ case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK_FIXED_RADIUS:
+ principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
+ break;
+ case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK:
+ principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
+ break;
+ }
+ node = principled;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
+ node = graph->create_node<TranslucentBsdfNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
+ node = graph->create_node<TransparentBsdfNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
+ node = graph->create_node<VelvetBsdfNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeEmission)) {
+ node = graph->create_node<EmissionNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
+ BL::ShaderNodeAmbientOcclusion b_ao_node(b_node);
+ AmbientOcclusionNode *ao = graph->create_node<AmbientOcclusionNode>();
+ ao->set_samples(b_ao_node.samples());
+ ao->set_inside(b_ao_node.inside());
+ ao->set_only_local(b_ao_node.only_local());
+ node = ao;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
+ node = graph->create_node<ScatterVolumeNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
+ node = graph->create_node<AbsorptionVolumeNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeVolumePrincipled)) {
+ PrincipledVolumeNode *principled = graph->create_node<PrincipledVolumeNode>();
+ node = principled;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
+ node = graph->create_node<GeometryNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeWireframe)) {
+ BL::ShaderNodeWireframe b_wireframe_node(b_node);
+ WireframeNode *wire = graph->create_node<WireframeNode>();
+ wire->set_use_pixel_size(b_wireframe_node.use_pixel_size());
+ node = wire;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeWavelength)) {
+ node = graph->create_node<WavelengthNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBlackbody)) {
+ node = graph->create_node<BlackbodyNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeLightPath)) {
+ node = graph->create_node<LightPathNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
+ node = graph->create_node<LightFalloffNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
+ node = graph->create_node<ObjectInfoNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
+ node = graph->create_node<ParticleInfoNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeHairInfo)) {
+ node = graph->create_node<HairInfoNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeVolumeInfo)) {
+ node = graph->create_node<VolumeInfoNode>();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeVertexColor)) {
+ BL::ShaderNodeVertexColor b_vertex_color_node(b_node);
+ VertexColorNode *vertex_color_node = graph->create_node<VertexColorNode>();
+ vertex_color_node->set_layer_name(ustring(b_vertex_color_node.layer_name()));
+ node = vertex_color_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBump)) {
+ BL::ShaderNodeBump b_bump_node(b_node);
+ BumpNode *bump = graph->create_node<BumpNode>();
+ bump->set_invert(b_bump_node.invert());
+ node = bump;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeScript)) {
+#ifdef WITH_OSL
+ if (scene->shader_manager->use_osl()) {
+ /* create script node */
+ BL::ShaderNodeScript b_script_node(b_node);
+
+ ShaderManager *manager = scene->shader_manager;
+ string bytecode_hash = b_script_node.bytecode_hash();
+
+ if (!bytecode_hash.empty()) {
+ node = OSLShaderManager::osl_node(
+ graph, manager, "", bytecode_hash, b_script_node.bytecode());
+ }
+ else {
+ string absolute_filepath = blender_absolute_path(
+ b_data, b_ntree, b_script_node.filepath());
+ node = OSLShaderManager::osl_node(graph, manager, absolute_filepath, "");
+ }
+ }
+#else
+ (void)b_data;
+ (void)b_ntree;
+#endif
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexImage)) {
+ BL::ShaderNodeTexImage b_image_node(b_node);
+ BL::Image b_image(b_image_node.image());
+ BL::ImageUser b_image_user(b_image_node.image_user());
+ ImageTextureNode *image = graph->create_node<ImageTextureNode>();
+
+ image->set_interpolation(get_image_interpolation(b_image_node));
+ image->set_extension(get_image_extension(b_image_node));
+ image->set_projection((NodeImageProjection)b_image_node.projection());
+ image->set_projection_blend(b_image_node.projection_blend());
+ BL::TexMapping b_texture_mapping(b_image_node.texture_mapping());
+ get_tex_mapping(image, b_texture_mapping);
+
+ if (b_image) {
+ PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
+ image->set_colorspace(ustring(get_enum_identifier(colorspace_ptr, "name")));
+
+ image->set_animated(b_image_node.image_user().use_auto_refresh());
+ image->set_alpha_type(get_image_alpha_type(b_image));
+
+ array<int> tiles;
+ for (BL::UDIMTile &b_tile : b_image.tiles) {
+ tiles.push_back_slow(b_tile.number());
+ }
+ image->set_tiles(tiles);
+
+ /* builtin images will use callback-based reading because
+ * they could only be loaded correct from blender side
+ */
+ bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED ||
+ b_image.source() == BL::Image::source_MOVIE ||
+ (b_engine.is_preview() && b_image.source() != BL::Image::source_SEQUENCE);
+
+ if (is_builtin) {
+ /* for builtin images we're using image datablock name to find an image to
+ * read pixels from later
+ *
+ * also store frame number as well, so there's no differences in handling
+ * builtin names for packed images and movies
+ */
+ int scene_frame = b_scene.frame_current();
+ int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
+ image->handle = scene->image_manager->add_image(
+ new BlenderImageLoader(b_image, image_frame), image->image_params());
+ }
+ else {
+ ustring filename = ustring(
+ image_user_file_path(b_image_user, b_image, b_scene.frame_current(), true));
+ image->set_filename(filename);
+ }
+ }
+ node = image;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexEnvironment)) {
+ BL::ShaderNodeTexEnvironment b_env_node(b_node);
+ BL::Image b_image(b_env_node.image());
+ BL::ImageUser b_image_user(b_env_node.image_user());
+ EnvironmentTextureNode *env = graph->create_node<EnvironmentTextureNode>();
+
+ env->set_interpolation(get_image_interpolation(b_env_node));
+ env->set_projection((NodeEnvironmentProjection)b_env_node.projection());
+ BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
+ get_tex_mapping(env, b_texture_mapping);
+
+ if (b_image) {
+ PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
+ env->set_colorspace(ustring(get_enum_identifier(colorspace_ptr, "name")));
+
+ env->set_animated(b_env_node.image_user().use_auto_refresh());
+ env->set_alpha_type(get_image_alpha_type(b_image));
+
+ bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED ||
+ b_image.source() == BL::Image::source_MOVIE ||
+ (b_engine.is_preview() && b_image.source() != BL::Image::source_SEQUENCE);
+
+ if (is_builtin) {
+ int scene_frame = b_scene.frame_current();
+ int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
+ env->handle = scene->image_manager->add_image(new BlenderImageLoader(b_image, image_frame),
+ env->image_params());
+ }
+ else {
+ env->set_filename(
+ ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current(), false)));
+ }
+ }
+ node = env;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexGradient)) {
+ BL::ShaderNodeTexGradient b_gradient_node(b_node);
+ GradientTextureNode *gradient = graph->create_node<GradientTextureNode>();
+ gradient->set_gradient_type((NodeGradientType)b_gradient_node.gradient_type());
+ BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping());
+ get_tex_mapping(gradient, b_texture_mapping);
+ node = gradient;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
+ BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
+ VoronoiTextureNode *voronoi = graph->create_node<VoronoiTextureNode>();
+ voronoi->set_dimensions(b_voronoi_node.voronoi_dimensions());
+ voronoi->set_feature((NodeVoronoiFeature)b_voronoi_node.feature());
+ voronoi->set_metric((NodeVoronoiDistanceMetric)b_voronoi_node.distance());
+ BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
+ get_tex_mapping(voronoi, b_texture_mapping);
+ node = voronoi;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexMagic)) {
+ BL::ShaderNodeTexMagic b_magic_node(b_node);
+ MagicTextureNode *magic = graph->create_node<MagicTextureNode>();
+ magic->set_depth(b_magic_node.turbulence_depth());
+ BL::TexMapping b_texture_mapping(b_magic_node.texture_mapping());
+ get_tex_mapping(magic, b_texture_mapping);
+ node = magic;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexWave)) {
+ BL::ShaderNodeTexWave b_wave_node(b_node);
+ WaveTextureNode *wave = graph->create_node<WaveTextureNode>();
+ wave->set_wave_type((NodeWaveType)b_wave_node.wave_type());
+ wave->set_bands_direction((NodeWaveBandsDirection)b_wave_node.bands_direction());
+ wave->set_rings_direction((NodeWaveRingsDirection)b_wave_node.rings_direction());
+ wave->set_profile((NodeWaveProfile)b_wave_node.wave_profile());
+ BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping());
+ get_tex_mapping(wave, b_texture_mapping);
+ node = wave;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexChecker)) {
+ BL::ShaderNodeTexChecker b_checker_node(b_node);
+ CheckerTextureNode *checker = graph->create_node<CheckerTextureNode>();
+ BL::TexMapping b_texture_mapping(b_checker_node.texture_mapping());
+ get_tex_mapping(checker, b_texture_mapping);
+ node = checker;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexBrick)) {
+ BL::ShaderNodeTexBrick b_brick_node(b_node);
+ BrickTextureNode *brick = graph->create_node<BrickTextureNode>();
+ brick->set_offset(b_brick_node.offset());
+ brick->set_offset_frequency(b_brick_node.offset_frequency());
+ brick->set_squash(b_brick_node.squash());
+ brick->set_squash_frequency(b_brick_node.squash_frequency());
+ BL::TexMapping b_texture_mapping(b_brick_node.texture_mapping());
+ get_tex_mapping(brick, b_texture_mapping);
+ node = brick;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) {
+ BL::ShaderNodeTexNoise b_noise_node(b_node);
+ NoiseTextureNode *noise = graph->create_node<NoiseTextureNode>();
+ noise->set_dimensions(b_noise_node.noise_dimensions());
+ BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping());
+ get_tex_mapping(noise, b_texture_mapping);
+ node = noise;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
+ BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
+ MusgraveTextureNode *musgrave_node = graph->create_node<MusgraveTextureNode>();
+ musgrave_node->set_musgrave_type((NodeMusgraveType)b_musgrave_node.musgrave_type());
+ musgrave_node->set_dimensions(b_musgrave_node.musgrave_dimensions());
+ BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
+ get_tex_mapping(musgrave_node, b_texture_mapping);
+ node = musgrave_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexCoord)) {
+ BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
+ TextureCoordinateNode *tex_coord = graph->create_node<TextureCoordinateNode>();
+ tex_coord->set_from_dupli(b_tex_coord_node.from_instancer());
+ if (b_tex_coord_node.object()) {
+ tex_coord->set_use_transform(true);
+ tex_coord->set_ob_tfm(get_transform(b_tex_coord_node.object().matrix_world()));
+ }
+ node = tex_coord;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexSky)) {
+ BL::ShaderNodeTexSky b_sky_node(b_node);
+ SkyTextureNode *sky = graph->create_node<SkyTextureNode>();
+ sky->set_sky_type((NodeSkyType)b_sky_node.sky_type());
+ sky->set_sun_direction(normalize(get_float3(b_sky_node.sun_direction())));
+ sky->set_turbidity(b_sky_node.turbidity());
+ sky->set_ground_albedo(b_sky_node.ground_albedo());
+ sky->set_sun_disc(b_sky_node.sun_disc());
+ sky->set_sun_size(b_sky_node.sun_size());
+ sky->set_sun_intensity(b_sky_node.sun_intensity());
+ sky->set_sun_elevation(b_sky_node.sun_elevation());
+ sky->set_sun_rotation(b_sky_node.sun_rotation());
+ sky->set_altitude(b_sky_node.altitude());
+ sky->set_air_density(b_sky_node.air_density());
+ sky->set_dust_density(b_sky_node.dust_density());
+ sky->set_ozone_density(b_sky_node.ozone_density());
+ BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping());
+ get_tex_mapping(sky, b_texture_mapping);
+ node = sky;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexIES)) {
+ BL::ShaderNodeTexIES b_ies_node(b_node);
+ IESLightNode *ies = graph->create_node<IESLightNode>();
+ switch (b_ies_node.mode()) {
+ case BL::ShaderNodeTexIES::mode_EXTERNAL:
+ ies->set_filename(ustring(blender_absolute_path(b_data, b_ntree, b_ies_node.filepath())));
+ break;
+ case BL::ShaderNodeTexIES::mode_INTERNAL:
+ ustring ies_content = ustring(get_text_datablock_content(b_ies_node.ies().ptr));
+ if (ies_content.empty()) {
+ ies_content = "\n";
+ }
+ ies->set_ies(ies_content);
+ break;
+ }
+ node = ies;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexWhiteNoise)) {
+ BL::ShaderNodeTexWhiteNoise b_tex_white_noise_node(b_node);
+ WhiteNoiseTextureNode *white_noise_node = graph->create_node<WhiteNoiseTextureNode>();
+ white_noise_node->set_dimensions(b_tex_white_noise_node.noise_dimensions());
+ node = white_noise_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) {
+ BL::ShaderNodeNormalMap b_normal_map_node(b_node);
+ NormalMapNode *nmap = graph->create_node<NormalMapNode>();
+ nmap->set_space((NodeNormalMapSpace)b_normal_map_node.space());
+ nmap->set_attribute(ustring(b_normal_map_node.uv_map()));
+ node = nmap;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTangent)) {
+ BL::ShaderNodeTangent b_tangent_node(b_node);
+ TangentNode *tangent = graph->create_node<TangentNode>();
+ tangent->set_direction_type((NodeTangentDirectionType)b_tangent_node.direction_type());
+ tangent->set_axis((NodeTangentAxis)b_tangent_node.axis());
+ tangent->set_attribute(ustring(b_tangent_node.uv_map()));
+ node = tangent;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeUVMap)) {
+ BL::ShaderNodeUVMap b_uvmap_node(b_node);
+ UVMapNode *uvm = graph->create_node<UVMapNode>();
+ uvm->set_attribute(ustring(b_uvmap_node.uv_map()));
+ uvm->set_from_dupli(b_uvmap_node.from_instancer());
+ node = uvm;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+ BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
+ PointDensityTextureNode *point_density = graph->create_node<PointDensityTextureNode>();
+ point_density->set_space((NodeTexVoxelSpace)b_point_density_node.space());
+ point_density->set_interpolation(get_image_interpolation(b_point_density_node));
+ point_density->handle = scene->image_manager->add_image(
+ new BlenderPointDensityLoader(b_depsgraph, b_point_density_node),
+ point_density->image_params());
+
+ b_point_density_node.cache_point_density(b_depsgraph);
+ node = point_density;
+
+ /* Transformation form world space to texture space.
+ *
+ * NOTE: Do this after the texture is cached, this is because getting
+ * min/max will need to access this cache.
+ */
+ BL::Object b_ob(b_point_density_node.object());
+ if (b_ob) {
+ float3 loc, size;
+ point_density_texture_space(b_depsgraph, b_point_density_node, loc, size);
+ point_density->set_tfm(transform_translate(-loc) * transform_scale(size) *
+ transform_inverse(get_transform(b_ob.matrix_world())));
+ }
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeBevel)) {
+ BL::ShaderNodeBevel b_bevel_node(b_node);
+ BevelNode *bevel = graph->create_node<BevelNode>();
+ bevel->set_samples(b_bevel_node.samples());
+ node = bevel;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeDisplacement)) {
+ BL::ShaderNodeDisplacement b_disp_node(b_node);
+ DisplacementNode *disp = graph->create_node<DisplacementNode>();
+ disp->set_space((NodeNormalMapSpace)b_disp_node.space());
+ node = disp;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeVectorDisplacement)) {
+ BL::ShaderNodeVectorDisplacement b_disp_node(b_node);
+ VectorDisplacementNode *disp = graph->create_node<VectorDisplacementNode>();
+ disp->set_space((NodeNormalMapSpace)b_disp_node.space());
+ disp->set_attribute(ustring(""));
+ node = disp;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeOutputAOV)) {
+ BL::ShaderNodeOutputAOV b_aov_node(b_node);
+ OutputAOVNode *aov = graph->create_node<OutputAOVNode>();
+ aov->set_name(ustring(b_aov_node.name()));
+ node = aov;
+ }
+
+ if (node) {
+ node->name = b_node.name();
+ graph->add(node);
+ }
+
+ return node;
+}
+
+static bool node_use_modified_socket_name(ShaderNode *node)
+{
+ if (node->special_type == SHADER_SPECIAL_TYPE_OSL)
+ return false;
+
+ return true;
+}
+
+static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_socket)
+{
+ string name = b_socket.identifier();
+ ShaderInput *input = node->input(name.c_str());
+
+ if (!input && node_use_modified_socket_name(node)) {
+ /* Different internal name for shader. */
+ if (string_startswith(name, "Shader")) {
+ string_replace(name, "Shader", "Closure");
+ }
+ input = node->input(name.c_str());
+
+ if (!input) {
+ /* Different internal numbering of two sockets with same name.
+ * Note that the Blender convention for unique socket names changed
+ * from . to _ at some point, so we check both to handle old files. */
+ if (string_endswith(name, "_001")) {
+ string_replace(name, "_001", "2");
+ }
+ else if (string_endswith(name, ".001")) {
+ string_replace(name, ".001", "2");
+ }
+ else if (string_endswith(name, "_002")) {
+ string_replace(name, "_002", "3");
+ }
+ else if (string_endswith(name, ".002")) {
+ string_replace(name, ".002", "3");
+ }
+ else {
+ name += "1";
+ }
+
+ input = node->input(name.c_str());
+ }
+ }
+
+ return input;
+}
+
+static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::NodeSocket &b_socket)
+{
+ string name = b_socket.identifier();
+ ShaderOutput *output = node->output(name.c_str());
+
+ if (!output && node_use_modified_socket_name(node)) {
+ /* Different internal name for shader. */
+ if (name == "Shader") {
+ name = "Closure";
+ output = node->output(name.c_str());
+ }
+ }
+
+ return output;
+}
+
+static void add_nodes(Scene *scene,
+ BL::RenderEngine &b_engine,
+ BL::BlendData &b_data,
+ BL::Depsgraph &b_depsgraph,
+ BL::Scene &b_scene,
+ ShaderGraph *graph,
+ BL::ShaderNodeTree &b_ntree,
+ const ProxyMap &proxy_input_map,
+ const ProxyMap &proxy_output_map)
+{
+ /* add nodes */
+ PtrInputMap input_map;
+ PtrOutputMap output_map;
+
+ /* find the node to use for output if there are multiple */
+ BL::ShaderNode output_node = b_ntree.get_output_node(
+ BL::ShaderNodeOutputMaterial::target_CYCLES);
+
+ /* add nodes */
+ for (BL::Node &b_node : b_ntree.nodes) {
+ if (b_node.mute() || b_node.is_a(&RNA_NodeReroute)) {
+ /* replace muted node with internal links */
+ for (BL::NodeLink &b_link : b_node.internal_links) {
+ BL::NodeSocket to_socket(b_link.to_socket());
+ SocketType::Type to_socket_type = convert_socket_type(to_socket);
+ if (to_socket_type == SocketType::UNDEFINED) {
+ continue;
+ }
+
+ ConvertNode *proxy = graph->create_node<ConvertNode>(to_socket_type, to_socket_type, true);
+
+ input_map[b_link.from_socket().ptr.data] = proxy->inputs[0];
+ output_map[b_link.to_socket().ptr.data] = proxy->outputs[0];
+
+ graph->add(proxy);
+ }
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeGroup) || b_node.is_a(&RNA_NodeCustomGroup) ||
+ b_node.is_a(&RNA_ShaderNodeCustomGroup)) {
+
+ BL::ShaderNodeTree b_group_ntree(PointerRNA_NULL);
+ if (b_node.is_a(&RNA_ShaderNodeGroup))
+ b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(b_node)).node_tree());
+ else if (b_node.is_a(&RNA_NodeCustomGroup))
+ b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(b_node)).node_tree());
+ else
+ b_group_ntree = BL::ShaderNodeTree(((BL::ShaderNodeCustomGroup)(b_node)).node_tree());
+
+ ProxyMap group_proxy_input_map, group_proxy_output_map;
+
+ /* Add a proxy node for each socket
+ * Do this even if the node group has no internal tree,
+ * so that links have something to connect to and assert won't fail.
+ */
+ for (BL::NodeSocket &b_input : b_node.inputs) {
+ SocketType::Type input_type = convert_socket_type(b_input);
+ if (input_type == SocketType::UNDEFINED) {
+ continue;
+ }
+
+ ConvertNode *proxy = graph->create_node<ConvertNode>(input_type, input_type, true);
+ graph->add(proxy);
+
+ /* register the proxy node for internal binding */
+ group_proxy_input_map[b_input.identifier()] = proxy;
+
+ input_map[b_input.ptr.data] = proxy->inputs[0];
+
+ set_default_value(proxy->inputs[0], b_input, b_data, b_ntree);
+ }
+ for (BL::NodeSocket &b_output : b_node.outputs) {
+ SocketType::Type output_type = convert_socket_type(b_output);
+ if (output_type == SocketType::UNDEFINED) {
+ continue;
+ }
+
+ ConvertNode *proxy = graph->create_node<ConvertNode>(output_type, output_type, true);
+ graph->add(proxy);
+
+ /* register the proxy node for internal binding */
+ group_proxy_output_map[b_output.identifier()] = proxy;
+
+ output_map[b_output.ptr.data] = proxy->outputs[0];
+ }
+
+ if (b_group_ntree) {
+ add_nodes(scene,
+ b_engine,
+ b_data,
+ b_depsgraph,
+ b_scene,
+ graph,
+ b_group_ntree,
+ group_proxy_input_map,
+ group_proxy_output_map);
+ }
+ }
+ else if (b_node.is_a(&RNA_NodeGroupInput)) {
+ /* map each socket to a proxy node */
+ for (BL::NodeSocket &b_output : b_node.outputs) {
+ ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output.identifier());
+ if (proxy_it != proxy_input_map.end()) {
+ ConvertNode *proxy = proxy_it->second;
+
+ output_map[b_output.ptr.data] = proxy->outputs[0];
+ }
+ }
+ }
+ else if (b_node.is_a(&RNA_NodeGroupOutput)) {
+ BL::NodeGroupOutput b_output_node(b_node);
+ /* only the active group output is used */
+ if (b_output_node.is_active_output()) {
+ /* map each socket to a proxy node */
+ for (BL::NodeSocket &b_input : b_node.inputs) {
+ ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input.identifier());
+ if (proxy_it != proxy_output_map.end()) {
+ ConvertNode *proxy = proxy_it->second;
+
+ input_map[b_input.ptr.data] = proxy->inputs[0];
+
+ set_default_value(proxy->inputs[0], b_input, b_data, b_ntree);
+ }
+ }
+ }
+ }
+ else {
+ ShaderNode *node = NULL;
+
+ if (b_node.ptr.data == output_node.ptr.data) {
+ node = graph->output();
+ }
+ else {
+ BL::ShaderNode b_shader_node(b_node);
+ node = add_node(
+ scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree, b_shader_node);
+ }
+
+ if (node) {
+ /* map node sockets for linking */
+ for (BL::NodeSocket &b_input : b_node.inputs) {
+ ShaderInput *input = node_find_input_by_name(node, b_input);
+ if (!input) {
+ /* XXX should not happen, report error? */
+ continue;
+ }
+ input_map[b_input.ptr.data] = input;
+
+ set_default_value(input, b_input, b_data, b_ntree);
+ }
+ for (BL::NodeSocket &b_output : b_node.outputs) {
+ ShaderOutput *output = node_find_output_by_name(node, b_output);
+ if (!output) {
+ /* XXX should not happen, report error? */
+ continue;
+ }
+ output_map[b_output.ptr.data] = output;
+ }
+ }
+ }
+ }
+
+ /* connect nodes */
+ for (BL::NodeLink &b_link : b_ntree.links) {
+ /* Ignore invalid links to avoid unwanted cycles created in graph.
+ * Also ignore links with unavailable sockets. */
+ if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled()) ||
+ b_link.is_muted()) {
+ continue;
+ }
+ /* get blender link data */
+ BL::NodeSocket b_from_sock = b_link.from_socket();
+ BL::NodeSocket b_to_sock = b_link.to_socket();
+
+ ShaderOutput *output = 0;
+ ShaderInput *input = 0;
+
+ PtrOutputMap::iterator output_it = output_map.find(b_from_sock.ptr.data);
+ if (output_it != output_map.end())
+ output = output_it->second;
+ PtrInputMap::iterator input_it = input_map.find(b_to_sock.ptr.data);
+ if (input_it != input_map.end())
+ input = input_it->second;
+
+ /* either node may be NULL when the node was not exported, typically
+ * because the node type is not supported */
+ if (output && input)
+ graph->connect(output, input);
+ }
+}
+
+static void add_nodes(Scene *scene,
+ BL::RenderEngine &b_engine,
+ BL::BlendData &b_data,
+ BL::Depsgraph &b_depsgraph,
+ BL::Scene &b_scene,
+ ShaderGraph *graph,
+ BL::ShaderNodeTree &b_ntree)
+{
+ static const ProxyMap empty_proxy_map;
+ add_nodes(scene,
+ b_engine,
+ b_data,
+ b_depsgraph,
+ b_scene,
+ graph,
+ b_ntree,
+ empty_proxy_map,
+ empty_proxy_map);
+}
+
+/* Sync Materials */
+
+void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
+{
+ shader_map.set_default(scene->default_surface);
+
+ TaskPool pool;
+ set<Shader *> updated_shaders;
+
+ for (BL::ID &b_id : b_depsgraph.ids) {
+ if (!b_id.is_a(&RNA_Material)) {
+ continue;
+ }
+
+ BL::Material b_mat(b_id);
+ Shader *shader;
+
+ /* test if we need to sync */
+ if (shader_map.add_or_update(&shader, b_mat) || update_all) {
+ ShaderGraph *graph = new ShaderGraph();
+
+ shader->name = b_mat.name().c_str();
+ shader->set_pass_id(b_mat.pass_index());
+
+ /* create nodes */
+ if (b_mat.use_nodes() && b_mat.node_tree()) {
+ BL::ShaderNodeTree b_ntree(b_mat.node_tree());
+
+ add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
+ }
+ else {
+ DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
+ diffuse->set_color(get_float3(b_mat.diffuse_color()));
+ graph->add(diffuse);
+
+ ShaderNode *out = graph->output();
+ graph->connect(diffuse->output("BSDF"), out->input("Surface"));
+ }
+
+ /* settings */
+ PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles");
+ shader->set_use_mis(get_boolean(cmat, "sample_as_light"));
+ shader->set_use_transparent_shadow(get_boolean(cmat, "use_transparent_shadow"));
+ shader->set_heterogeneous_volume(!get_boolean(cmat, "homogeneous_volume"));
+ shader->set_volume_sampling_method(get_volume_sampling(cmat));
+ shader->set_volume_interpolation_method(get_volume_interpolation(cmat));
+ shader->set_volume_step_rate(get_float(cmat, "volume_step_rate"));
+ shader->set_displacement_method(get_displacement_method(cmat));
+
+ shader->set_graph(graph);
+
+ /* By simplifying the shader graph as soon as possible, some
+ * redundant shader nodes might be removed which prevents loading
+ * unnecessary attributes later.
+ *
+ * However, since graph simplification also accounts for e.g. mix
+ * weight, this would cause frequent expensive resyncs in interactive
+ * sessions, so for those sessions optimization is only performed
+ * right before compiling.
+ */
+ if (!preview) {
+ pool.push(function_bind(&ShaderGraph::simplify, graph, scene));
+ /* NOTE: Update shaders out of the threads since those routines
+ * are accessing and writing to a global context.
+ */
+ updated_shaders.insert(shader);
+ }
+ else {
+ /* NOTE: Update tagging can access links which are being
+ * optimized out.
+ */
+ shader->tag_update(scene);
+ }
+ }
+ }
+
+ pool.wait_work();
+
+ foreach (Shader *shader, updated_shaders) {
+ shader->tag_update(scene);
+ }
+}
+
+/* Sync World */
+
+void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all)
+{
+ Background *background = scene->background;
+ Integrator *integrator = scene->integrator;
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+ BL::World b_world = b_scene.world();
+
+ BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
+
+ if (world_recalc || update_all || b_world.ptr.data != world_map ||
+ viewport_parameters.shader_modified(new_viewport_parameters)) {
+ Shader *shader = scene->default_background;
+ ShaderGraph *graph = new ShaderGraph();
+
+ /* create nodes */
+ if (new_viewport_parameters.use_scene_world && b_world && b_world.use_nodes() &&
+ b_world.node_tree()) {
+ BL::ShaderNodeTree b_ntree(b_world.node_tree());
+
+ add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
+
+ /* volume */
+ PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
+ shader->set_heterogeneous_volume(!get_boolean(cworld, "homogeneous_volume"));
+ shader->set_volume_sampling_method(get_volume_sampling(cworld));
+ shader->set_volume_interpolation_method(get_volume_interpolation(cworld));
+ shader->set_volume_step_rate(get_float(cworld, "volume_step_size"));
+ }
+ else if (new_viewport_parameters.use_scene_world && b_world) {
+ BackgroundNode *background = graph->create_node<BackgroundNode>();
+ background->set_color(get_float3(b_world.color()));
+ graph->add(background);
+
+ ShaderNode *out = graph->output();
+ graph->connect(background->output("Background"), out->input("Surface"));
+ }
+ else if (!new_viewport_parameters.use_scene_world) {
+ float3 world_color;
+ if (b_world) {
+ world_color = get_float3(b_world.color());
+ }
+ else {
+ world_color = zero_float3();
+ }
+
+ BackgroundNode *background = graph->create_node<BackgroundNode>();
+ graph->add(background);
+
+ LightPathNode *light_path = graph->create_node<LightPathNode>();
+ graph->add(light_path);
+
+ MixNode *mix_scene_with_background = graph->create_node<MixNode>();
+ mix_scene_with_background->set_color2(world_color);
+ graph->add(mix_scene_with_background);
+
+ EnvironmentTextureNode *texture_environment = graph->create_node<EnvironmentTextureNode>();
+ texture_environment->set_tex_mapping_type(TextureMapping::VECTOR);
+ float3 rotation_z = texture_environment->get_tex_mapping_rotation();
+ rotation_z[2] = new_viewport_parameters.studiolight_rotate_z;
+ texture_environment->set_tex_mapping_rotation(rotation_z);
+ texture_environment->set_filename(new_viewport_parameters.studiolight_path);
+ graph->add(texture_environment);
+
+ MixNode *mix_intensity = graph->create_node<MixNode>();
+ mix_intensity->set_mix_type(NODE_MIX_MUL);
+ mix_intensity->set_fac(1.0f);
+ mix_intensity->set_color2(make_float3(new_viewport_parameters.studiolight_intensity,
+ new_viewport_parameters.studiolight_intensity,
+ new_viewport_parameters.studiolight_intensity));
+ graph->add(mix_intensity);
+
+ TextureCoordinateNode *texture_coordinate = graph->create_node<TextureCoordinateNode>();
+ graph->add(texture_coordinate);
+
+ MixNode *mix_background_with_environment = graph->create_node<MixNode>();
+ mix_background_with_environment->set_fac(
+ new_viewport_parameters.studiolight_background_alpha);
+ mix_background_with_environment->set_color1(world_color);
+ graph->add(mix_background_with_environment);
+
+ ShaderNode *out = graph->output();
+
+ graph->connect(texture_coordinate->output("Generated"),
+ texture_environment->input("Vector"));
+ graph->connect(texture_environment->output("Color"), mix_intensity->input("Color1"));
+ graph->connect(light_path->output("Is Camera Ray"), mix_scene_with_background->input("Fac"));
+ graph->connect(mix_intensity->output("Color"), mix_scene_with_background->input("Color1"));
+ graph->connect(mix_intensity->output("Color"),
+ mix_background_with_environment->input("Color2"));
+ graph->connect(mix_background_with_environment->output("Color"),
+ mix_scene_with_background->input("Color2"));
+ graph->connect(mix_scene_with_background->output("Color"), background->input("Color"));
+ graph->connect(background->output("Background"), out->input("Surface"));
+ }
+
+ /* Visibility */
+ if (b_world) {
+ PointerRNA cvisibility = RNA_pointer_get(&b_world.ptr, "cycles_visibility");
+ uint visibility = 0;
+
+ visibility |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0;
+ visibility |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0;
+ visibility |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0;
+ visibility |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0;
+ visibility |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0;
+
+ background->set_visibility(visibility);
+ }
+
+ shader->set_graph(graph);
+ shader->tag_update(scene);
+ }
+
+ /* Fast GI */
+ if (b_world) {
+ BL::WorldLighting b_light = b_world.light_settings();
+ enum { FAST_GI_METHOD_REPLACE = 0, FAST_GI_METHOD_ADD = 1, FAST_GI_METHOD_NUM };
+
+ const bool use_fast_gi = get_boolean(cscene, "use_fast_gi");
+ if (use_fast_gi) {
+ const int fast_gi_method = get_enum(
+ cscene, "fast_gi_method", FAST_GI_METHOD_NUM, FAST_GI_METHOD_REPLACE);
+ integrator->set_ao_factor((fast_gi_method == FAST_GI_METHOD_REPLACE) ? b_light.ao_factor() :
+ 0.0f);
+ integrator->set_ao_additive_factor(
+ (fast_gi_method == FAST_GI_METHOD_ADD) ? b_light.ao_factor() : 0.0f);
+ }
+ else {
+ integrator->set_ao_factor(0.0f);
+ integrator->set_ao_additive_factor(0.0f);
+ }
+
+ integrator->set_ao_distance(b_light.distance());
+ }
+ else {
+ integrator->set_ao_factor(0.0f);
+ integrator->set_ao_additive_factor(0.0f);
+ integrator->set_ao_distance(10.0f);
+ }
+
+ background->set_transparent(b_scene.render().film_transparent());
+
+ if (background->get_transparent()) {
+ background->set_transparent_glass(get_boolean(cscene, "film_transparent_glass"));
+ background->set_transparent_roughness_threshold(
+ get_float(cscene, "film_transparent_roughness"));
+ }
+ else {
+ background->set_transparent_glass(false);
+ background->set_transparent_roughness_threshold(0.0f);
+ }
+
+ background->set_use_shader(view_layer.use_background_shader ||
+ viewport_parameters.use_custom_shader());
+
+ background->tag_update(scene);
+}
+
+/* Sync Lights */
+
+void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
+{
+ shader_map.set_default(scene->default_light);
+
+ for (BL::ID &b_id : b_depsgraph.ids) {
+ if (!b_id.is_a(&RNA_Light)) {
+ continue;
+ }
+
+ BL::Light b_light(b_id);
+ Shader *shader;
+
+ /* test if we need to sync */
+ if (shader_map.add_or_update(&shader, b_light) || update_all) {
+ ShaderGraph *graph = new ShaderGraph();
+
+ /* create nodes */
+ if (b_light.use_nodes() && b_light.node_tree()) {
+ shader->name = b_light.name().c_str();
+
+ BL::ShaderNodeTree b_ntree(b_light.node_tree());
+
+ add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
+ }
+ else {
+ EmissionNode *emission = graph->create_node<EmissionNode>();
+ emission->set_color(one_float3());
+ emission->set_strength(1.0f);
+ graph->add(emission);
+
+ ShaderNode *out = graph->output();
+ graph->connect(emission->output("Emission"), out->input("Surface"));
+ }
+
+ shader->set_graph(graph);
+ shader->tag_update(scene);
+ }
+ }
+}
+
+void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
+{
+ /* for auto refresh images */
+ ImageManager *image_manager = scene->image_manager;
+ const int frame = b_scene.frame_current();
+ const bool auto_refresh_update = image_manager->set_animation_frame_update(frame);
+
+ shader_map.pre_sync();
+
+ sync_world(b_depsgraph, b_v3d, auto_refresh_update);
+ sync_lights(b_depsgraph, auto_refresh_update);
+ sync_materials(b_depsgraph, auto_refresh_update);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
new file mode 100644
index 00000000000..e0a13625962
--- /dev/null
+++ b/intern/cycles/blender/sync.cpp
@@ -0,0 +1,966 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/background.h"
+#include "scene/camera.h"
+#include "scene/curves.h"
+#include "scene/film.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/procedural.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+
+#include "device/device.h"
+
+#include "blender/device.h"
+#include "blender/session.h"
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "util/debug.h"
+#include "util/foreach.h"
+#include "util/hash.h"
+#include "util/log.h"
+#include "util/opengl.h"
+#include "util/openimagedenoise.h"
+
+CCL_NAMESPACE_BEGIN
+
+static const char *cryptomatte_prefix = "Crypto";
+
+/* Constructor */
+
+BlenderSync::BlenderSync(BL::RenderEngine &b_engine,
+ BL::BlendData &b_data,
+ BL::Scene &b_scene,
+ Scene *scene,
+ bool preview,
+ bool use_developer_ui,
+ Progress &progress)
+ : b_engine(b_engine),
+ b_data(b_data),
+ b_scene(b_scene),
+ shader_map(scene),
+ object_map(scene),
+ procedural_map(scene),
+ geometry_map(scene),
+ light_map(scene),
+ particle_system_map(scene),
+ world_map(NULL),
+ world_recalc(false),
+ scene(scene),
+ preview(preview),
+ experimental(false),
+ use_developer_ui(use_developer_ui),
+ dicing_rate(1.0f),
+ max_subdivisions(12),
+ progress(progress),
+ has_updates_(true)
+{
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate") :
+ RNA_float_get(&cscene, "dicing_rate");
+ max_subdivisions = RNA_int_get(&cscene, "max_subdivisions");
+}
+
+BlenderSync::~BlenderSync()
+{
+}
+
+void BlenderSync::reset(BL::BlendData &b_data, BL::Scene &b_scene)
+{
+ /* Update data and scene pointers in case they change in session reset,
+ * for example after undo.
+ * Note that we do not modify the `has_updates_` flag here because the sync
+ * reset is also used during viewport navigation. */
+ this->b_data = b_data;
+ this->b_scene = b_scene;
+}
+
+/* Sync */
+
+void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
+{
+ /* Sync recalc flags from blender to cycles. Actual update is done separate,
+ * so we can do it later on if doing it immediate is not suitable. */
+
+ if (experimental) {
+ /* Mark all meshes as needing to be exported again if dicing changed. */
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ bool dicing_prop_changed = false;
+
+ float updated_dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate") :
+ RNA_float_get(&cscene, "dicing_rate");
+
+ if (dicing_rate != updated_dicing_rate) {
+ dicing_rate = updated_dicing_rate;
+ dicing_prop_changed = true;
+ }
+
+ int updated_max_subdivisions = RNA_int_get(&cscene, "max_subdivisions");
+
+ if (max_subdivisions != updated_max_subdivisions) {
+ max_subdivisions = updated_max_subdivisions;
+ dicing_prop_changed = true;
+ }
+
+ if (dicing_prop_changed) {
+ has_updates_ = true;
+
+ for (const pair<const GeometryKey, Geometry *> &iter : geometry_map.key_to_scene_data()) {
+ Geometry *geom = iter.second;
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
+ PointerRNA id_ptr;
+ RNA_id_pointer_create((::ID *)iter.first.id, &id_ptr);
+ geometry_map.set_recalc(BL::ID(id_ptr));
+ }
+ }
+ }
+ }
+ }
+
+ /* Iterate over all IDs in this depsgraph. */
+ for (BL::DepsgraphUpdate &b_update : b_depsgraph.updates) {
+ /* TODO(sergey): Can do more selective filter here. For example, ignore changes made to
+ * screen datablock. Note that sync_data() needs to be called after object deletion, and
+ * currently this is ensured by the scene ID tagged for update, which sets the `has_updates_`
+ * flag. */
+ has_updates_ = true;
+
+ BL::ID b_id(b_update.id());
+
+ /* Material */
+ if (b_id.is_a(&RNA_Material)) {
+ BL::Material b_mat(b_id);
+ shader_map.set_recalc(b_mat);
+ }
+ /* Light */
+ else if (b_id.is_a(&RNA_Light)) {
+ BL::Light b_light(b_id);
+ shader_map.set_recalc(b_light);
+ }
+ /* Object */
+ else if (b_id.is_a(&RNA_Object)) {
+ BL::Object b_ob(b_id);
+ const bool is_geometry = object_is_geometry(b_ob);
+ const bool is_light = !is_geometry && object_is_light(b_ob);
+
+ if (b_ob.is_instancer() && b_update.is_updated_shading()) {
+ /* Needed for e.g. object color updates on instancer. */
+ object_map.set_recalc(b_ob);
+ }
+
+ if (is_geometry || is_light) {
+ const bool updated_geometry = b_update.is_updated_geometry();
+
+ /* Geometry (mesh, hair, volume). */
+ if (is_geometry) {
+ if (b_update.is_updated_transform() || b_update.is_updated_shading()) {
+ object_map.set_recalc(b_ob);
+ }
+
+ if (updated_geometry ||
+ (object_subdivision_type(b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE)) {
+ BL::ID key = BKE_object_is_modified(b_ob) ? b_ob : b_ob.data();
+ geometry_map.set_recalc(key);
+ }
+
+ if (updated_geometry) {
+ BL::Object::particle_systems_iterator b_psys;
+ for (b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end();
+ ++b_psys) {
+ particle_system_map.set_recalc(b_ob);
+ }
+ }
+ }
+ /* Light */
+ else if (is_light) {
+ if (b_update.is_updated_transform() || b_update.is_updated_shading()) {
+ object_map.set_recalc(b_ob);
+ light_map.set_recalc(b_ob);
+ }
+
+ if (updated_geometry) {
+ light_map.set_recalc(b_ob);
+ }
+ }
+ }
+ }
+ /* Mesh */
+ else if (b_id.is_a(&RNA_Mesh)) {
+ BL::Mesh b_mesh(b_id);
+ geometry_map.set_recalc(b_mesh);
+ }
+ /* World */
+ else if (b_id.is_a(&RNA_World)) {
+ BL::World b_world(b_id);
+ if (world_map == b_world.ptr.data) {
+ world_recalc = true;
+ }
+ }
+ /* Volume */
+ else if (b_id.is_a(&RNA_Volume)) {
+ BL::Volume b_volume(b_id);
+ geometry_map.set_recalc(b_volume);
+ }
+ }
+
+ if (b_v3d) {
+ BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
+
+ if (viewport_parameters.shader_modified(new_viewport_parameters)) {
+ world_recalc = true;
+ has_updates_ = true;
+ }
+
+ has_updates_ |= viewport_parameters.modified(new_viewport_parameters);
+ }
+}
+
+void BlenderSync::sync_data(BL::RenderSettings &b_render,
+ BL::Depsgraph &b_depsgraph,
+ BL::SpaceView3D &b_v3d,
+ BL::Object &b_override,
+ int width,
+ int height,
+ void **python_thread_state)
+{
+ if (!has_updates_) {
+ return;
+ }
+
+ scoped_timer timer;
+
+ BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
+
+ /* TODO(sergey): This feels weak to pass view layer to the integrator, and even weaker to have an
+ * implicit check on whether it is a background render or not. What is the nicer thing here? */
+ const bool background = !b_v3d;
+
+ sync_view_layer(b_view_layer);
+ sync_integrator(b_view_layer, background);
+ sync_film(b_view_layer, b_v3d);
+ sync_shaders(b_depsgraph, b_v3d);
+ sync_images();
+
+ geometry_synced.clear(); /* use for objects and motion sync */
+
+ if (scene->need_motion() == Scene::MOTION_PASS || scene->need_motion() == Scene::MOTION_NONE ||
+ scene->camera->get_motion_position() == Camera::MOTION_POSITION_CENTER) {
+ sync_objects(b_depsgraph, b_v3d);
+ }
+ sync_motion(b_render, b_depsgraph, b_v3d, b_override, width, height, python_thread_state);
+
+ geometry_synced.clear();
+
+ /* Shader sync done at the end, since object sync uses it.
+ * false = don't delete unused shaders, not supported. */
+ shader_map.post_sync(false);
+
+ free_data_after_sync(b_depsgraph);
+
+ VLOG(1) << "Total time spent synchronizing data: " << timer.get_time();
+
+ has_updates_ = false;
+}
+
+/* Integrator */
+
+void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
+{
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+ experimental = (get_enum(cscene, "feature_set") != 0);
+
+ Integrator *integrator = scene->integrator;
+
+ integrator->set_min_bounce(get_int(cscene, "min_light_bounces"));
+ integrator->set_max_bounce(get_int(cscene, "max_bounces"));
+
+ integrator->set_max_diffuse_bounce(get_int(cscene, "diffuse_bounces"));
+ integrator->set_max_glossy_bounce(get_int(cscene, "glossy_bounces"));
+ integrator->set_max_transmission_bounce(get_int(cscene, "transmission_bounces"));
+ integrator->set_max_volume_bounce(get_int(cscene, "volume_bounces"));
+
+ integrator->set_transparent_min_bounce(get_int(cscene, "min_transparent_bounces"));
+ integrator->set_transparent_max_bounce(get_int(cscene, "transparent_max_bounces"));
+
+ integrator->set_volume_max_steps(get_int(cscene, "volume_max_steps"));
+ float volume_step_rate = (preview) ? get_float(cscene, "volume_preview_step_rate") :
+ get_float(cscene, "volume_step_rate");
+ integrator->set_volume_step_rate(volume_step_rate);
+
+ integrator->set_caustics_reflective(get_boolean(cscene, "caustics_reflective"));
+ integrator->set_caustics_refractive(get_boolean(cscene, "caustics_refractive"));
+ integrator->set_filter_glossy(get_float(cscene, "blur_glossy"));
+
+ int seed = get_int(cscene, "seed");
+ if (get_boolean(cscene, "use_animated_seed")) {
+ seed = hash_uint2(b_scene.frame_current(), get_int(cscene, "seed"));
+ if (b_scene.frame_subframe() != 0.0f) {
+ /* TODO(sergey): Ideally should be some sort of hash_merge,
+ * but this is good enough for now.
+ */
+ seed += hash_uint2((int)(b_scene.frame_subframe() * (float)INT_MAX),
+ get_int(cscene, "seed"));
+ }
+ }
+
+ integrator->set_seed(seed);
+
+ integrator->set_sample_clamp_direct(get_float(cscene, "sample_clamp_direct"));
+ integrator->set_sample_clamp_indirect(get_float(cscene, "sample_clamp_indirect"));
+ if (!preview) {
+ integrator->set_motion_blur(view_layer.use_motion_blur);
+ }
+
+ integrator->set_light_sampling_threshold(get_float(cscene, "light_sampling_threshold"));
+
+ SamplingPattern sampling_pattern = (SamplingPattern)get_enum(
+ cscene, "sampling_pattern", SAMPLING_NUM_PATTERNS, SAMPLING_PATTERN_SOBOL);
+ integrator->set_sampling_pattern(sampling_pattern);
+
+ bool use_adaptive_sampling = false;
+ if (preview) {
+ use_adaptive_sampling = RNA_boolean_get(&cscene, "use_preview_adaptive_sampling");
+ integrator->set_use_adaptive_sampling(use_adaptive_sampling);
+ integrator->set_adaptive_threshold(get_float(cscene, "preview_adaptive_threshold"));
+ integrator->set_adaptive_min_samples(get_int(cscene, "preview_adaptive_min_samples"));
+ }
+ else {
+ use_adaptive_sampling = RNA_boolean_get(&cscene, "use_adaptive_sampling");
+ integrator->set_use_adaptive_sampling(use_adaptive_sampling);
+ integrator->set_adaptive_threshold(get_float(cscene, "adaptive_threshold"));
+ integrator->set_adaptive_min_samples(get_int(cscene, "adaptive_min_samples"));
+ }
+
+ int samples = get_int(cscene, "samples");
+ float scrambling_distance = get_float(cscene, "scrambling_distance");
+ bool adaptive_scrambling_distance = get_boolean(cscene, "adaptive_scrambling_distance");
+ if (adaptive_scrambling_distance) {
+ scrambling_distance *= 4.0f / sqrtf(samples);
+ }
+
+ /* only use scrambling distance in the viewport if user wants to and disable with AS */
+ bool preview_scrambling_distance = get_boolean(cscene, "preview_scrambling_distance");
+ if ((preview && !preview_scrambling_distance) || use_adaptive_sampling)
+ scrambling_distance = 1.0f;
+
+ VLOG(1) << "Used Scrambling Distance: " << scrambling_distance;
+ integrator->set_scrambling_distance(scrambling_distance);
+
+ if (get_boolean(cscene, "use_fast_gi")) {
+ if (preview) {
+ integrator->set_ao_bounces(get_int(cscene, "ao_bounces"));
+ }
+ else {
+ integrator->set_ao_bounces(get_int(cscene, "ao_bounces_render"));
+ }
+ }
+ else {
+ integrator->set_ao_bounces(0);
+ }
+
+ const DenoiseParams denoise_params = get_denoise_params(b_scene, b_view_layer, background);
+ integrator->set_use_denoise(denoise_params.use);
+
+ /* Only update denoiser parameters if the denoiser is actually used. This allows to tweak
+ * denoiser parameters before enabling it without render resetting on every change. The downside
+ * is that the interface and the integrator are technically out of sync. */
+ if (denoise_params.use) {
+ integrator->set_denoiser_type(denoise_params.type);
+ integrator->set_denoise_start_sample(denoise_params.start_sample);
+ integrator->set_use_denoise_pass_albedo(denoise_params.use_pass_albedo);
+ integrator->set_use_denoise_pass_normal(denoise_params.use_pass_normal);
+ integrator->set_denoiser_prefilter(denoise_params.prefilter);
+ }
+
+ /* UPDATE_NONE as we don't want to tag the integrator as modified (this was done by the
+ * set calls above), but we need to make sure that the dependent things are tagged. */
+ integrator->tag_update(scene, Integrator::UPDATE_NONE);
+}
+
+/* Film */
+
+void BlenderSync::sync_film(BL::ViewLayer &b_view_layer, BL::SpaceView3D &b_v3d)
+{
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
+
+ Film *film = scene->film;
+
+ if (b_v3d) {
+ const BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
+ film->set_display_pass(new_viewport_parameters.display_pass);
+ film->set_show_active_pixels(new_viewport_parameters.show_active_pixels);
+ }
+
+ film->set_exposure(get_float(cscene, "film_exposure"));
+ film->set_filter_type(
+ (FilterType)get_enum(cscene, "pixel_filter_type", FILTER_NUM_TYPES, FILTER_BLACKMAN_HARRIS));
+ float filter_width = (film->get_filter_type() == FILTER_BOX) ? 1.0f :
+ get_float(cscene, "filter_width");
+ film->set_filter_width(filter_width);
+
+ if (b_scene.world()) {
+ BL::WorldMistSettings b_mist = b_scene.world().mist_settings();
+
+ film->set_mist_start(b_mist.start());
+ film->set_mist_depth(b_mist.depth());
+
+ switch (b_mist.falloff()) {
+ case BL::WorldMistSettings::falloff_QUADRATIC:
+ film->set_mist_falloff(2.0f);
+ break;
+ case BL::WorldMistSettings::falloff_LINEAR:
+ film->set_mist_falloff(1.0f);
+ break;
+ case BL::WorldMistSettings::falloff_INVERSE_QUADRATIC:
+ film->set_mist_falloff(0.5f);
+ break;
+ }
+ }
+
+ /* Blender viewport does not support proper shadow catcher compositing, so force an approximate
+ * mode to improve visual feedback. */
+ if (b_v3d) {
+ film->set_use_approximate_shadow_catcher(true);
+ }
+ else {
+ film->set_use_approximate_shadow_catcher(!get_boolean(crl, "use_pass_shadow_catcher"));
+ }
+}
+
+/* Render Layer */
+
+void BlenderSync::sync_view_layer(BL::ViewLayer &b_view_layer)
+{
+ view_layer.name = b_view_layer.name();
+
+ /* Filter. */
+ view_layer.use_background_shader = b_view_layer.use_sky();
+ /* Always enable surfaces for baking, otherwise there is nothing to bake to. */
+ view_layer.use_surfaces = b_view_layer.use_solid() || scene->bake_manager->get_baking();
+ view_layer.use_hair = b_view_layer.use_strand();
+ view_layer.use_volumes = b_view_layer.use_volumes();
+ view_layer.use_motion_blur = b_view_layer.use_motion_blur() &&
+ b_scene.render().use_motion_blur();
+
+ /* Material override. */
+ view_layer.material_override = b_view_layer.material_override();
+
+ /* Sample override. */
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ int use_layer_samples = get_enum(cscene, "use_layer_samples");
+
+ view_layer.bound_samples = (use_layer_samples == 1);
+ view_layer.samples = 0;
+
+ if (use_layer_samples != 2) {
+ int samples = b_view_layer.samples();
+ view_layer.samples = samples;
+ }
+}
+
+/* Images */
+void BlenderSync::sync_images()
+{
+ /* Sync is a convention for this API, but currently it frees unused buffers. */
+
+ const bool is_interface_locked = b_engine.render() && b_engine.render().use_lock_interface();
+ if (is_interface_locked == false && BlenderSession::headless == false) {
+ /* If interface is not locked, it's possible image is needed for
+ * the display.
+ */
+ return;
+ }
+ /* Free buffers used by images which are not needed for render. */
+ for (BL::Image &b_image : b_data.images) {
+ /* TODO(sergey): Consider making it an utility function to check
+ * whether image is considered builtin.
+ */
+ const bool is_builtin = b_image.packed_file() ||
+ b_image.source() == BL::Image::source_GENERATED ||
+ b_image.source() == BL::Image::source_MOVIE || b_engine.is_preview();
+ if (is_builtin == false) {
+ b_image.buffers_free();
+ }
+ /* TODO(sergey): Free builtin images not used by any shader. */
+ }
+}
+
+/* Passes */
+
+static PassType get_blender_pass_type(BL::RenderPass &b_pass)
+{
+ string name = b_pass.name();
+#define MAP_PASS(passname, passtype) \
+ if (name == passname) { \
+ return passtype; \
+ } \
+ ((void)0)
+
+ /* NOTE: Keep in sync with defined names from DNA_scene_types.h */
+
+ MAP_PASS("Combined", PASS_COMBINED);
+ MAP_PASS("Noisy Image", PASS_COMBINED);
+
+ MAP_PASS("Depth", PASS_DEPTH);
+ MAP_PASS("Mist", PASS_MIST);
+ MAP_PASS("Position", PASS_POSITION);
+ MAP_PASS("Normal", PASS_NORMAL);
+ MAP_PASS("IndexOB", PASS_OBJECT_ID);
+ MAP_PASS("UV", PASS_UV);
+ MAP_PASS("Vector", PASS_MOTION);
+ MAP_PASS("IndexMA", PASS_MATERIAL_ID);
+
+ MAP_PASS("DiffDir", PASS_DIFFUSE_DIRECT);
+ MAP_PASS("GlossDir", PASS_GLOSSY_DIRECT);
+ MAP_PASS("TransDir", PASS_TRANSMISSION_DIRECT);
+ MAP_PASS("VolumeDir", PASS_VOLUME_DIRECT);
+
+ MAP_PASS("DiffInd", PASS_DIFFUSE_INDIRECT);
+ MAP_PASS("GlossInd", PASS_GLOSSY_INDIRECT);
+ MAP_PASS("TransInd", PASS_TRANSMISSION_INDIRECT);
+ MAP_PASS("VolumeInd", PASS_VOLUME_INDIRECT);
+
+ MAP_PASS("DiffCol", PASS_DIFFUSE_COLOR);
+ MAP_PASS("GlossCol", PASS_GLOSSY_COLOR);
+ MAP_PASS("TransCol", PASS_TRANSMISSION_COLOR);
+
+ MAP_PASS("Emit", PASS_EMISSION);
+ MAP_PASS("Env", PASS_BACKGROUND);
+ MAP_PASS("AO", PASS_AO);
+ MAP_PASS("Shadow", PASS_SHADOW);
+
+ MAP_PASS("BakePrimitive", PASS_BAKE_PRIMITIVE);
+ MAP_PASS("BakeDifferential", PASS_BAKE_DIFFERENTIAL);
+
+ MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL);
+ MAP_PASS("Denoising Albedo", PASS_DENOISING_ALBEDO);
+ MAP_PASS("Denoising Depth", PASS_DENOISING_DEPTH);
+
+ MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER);
+ MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER);
+
+ MAP_PASS("AdaptiveAuxBuffer", PASS_ADAPTIVE_AUX_BUFFER);
+ MAP_PASS("Debug Sample Count", PASS_SAMPLE_COUNT);
+
+ if (string_startswith(name, cryptomatte_prefix)) {
+ return PASS_CRYPTOMATTE;
+ }
+
+#undef MAP_PASS
+
+ return PASS_NONE;
+}
+
+static Pass *pass_add(Scene *scene,
+ PassType type,
+ const char *name,
+ PassMode mode = PassMode::DENOISED)
+{
+ Pass *pass = scene->create_node<Pass>();
+
+ pass->set_type(type);
+ pass->set_name(ustring(name));
+ pass->set_mode(mode);
+
+ return pass;
+}
+
+void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer)
+{
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+ /* Delete all existing passes. */
+ set<Pass *> clear_passes(scene->passes.begin(), scene->passes.end());
+ scene->delete_nodes(clear_passes);
+
+ /* Always add combined pass. */
+ pass_add(scene, PASS_COMBINED, "Combined");
+
+ /* Blender built-in data and light passes. */
+ for (BL::RenderPass &b_pass : b_rlay.passes) {
+ const PassType pass_type = get_blender_pass_type(b_pass);
+
+ if (pass_type == PASS_NONE) {
+ LOG(ERROR) << "Unknown pass " << b_pass.name();
+ continue;
+ }
+
+ if (pass_type == PASS_MOTION &&
+ (b_view_layer.use_motion_blur() && b_scene.render().use_motion_blur())) {
+ continue;
+ }
+
+ pass_add(scene, pass_type, b_pass.name().c_str());
+ }
+
+ PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
+
+ /* Debug passes. */
+ if (get_boolean(crl, "pass_debug_sample_count")) {
+ b_engine.add_pass("Debug Sample Count", 1, "X", b_view_layer.name().c_str());
+ pass_add(scene, PASS_SAMPLE_COUNT, "Debug Sample Count");
+ }
+
+ /* Cycles specific passes. */
+ if (get_boolean(crl, "use_pass_volume_direct")) {
+ b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str());
+ pass_add(scene, PASS_VOLUME_DIRECT, "VolumeDir");
+ }
+ if (get_boolean(crl, "use_pass_volume_indirect")) {
+ b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str());
+ pass_add(scene, PASS_VOLUME_INDIRECT, "VolumeInd");
+ }
+ if (get_boolean(crl, "use_pass_shadow_catcher")) {
+ b_engine.add_pass("Shadow Catcher", 3, "RGB", b_view_layer.name().c_str());
+ pass_add(scene, PASS_SHADOW_CATCHER, "Shadow Catcher");
+ }
+
+ /* Cryptomatte stores two ID/weight pairs per RGBA layer.
+ * User facing parameter is the number of pairs. */
+ int crypto_depth = divide_up(min(16, b_view_layer.pass_cryptomatte_depth()), 2);
+ scene->film->set_cryptomatte_depth(crypto_depth);
+ CryptomatteType cryptomatte_passes = CRYPT_NONE;
+ if (b_view_layer.use_pass_cryptomatte_object()) {
+ for (int i = 0; i < crypto_depth; i++) {
+ string passname = cryptomatte_prefix + string_printf("Object%02d", i);
+ b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
+ pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
+ }
+ cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_OBJECT);
+ }
+ if (b_view_layer.use_pass_cryptomatte_material()) {
+ for (int i = 0; i < crypto_depth; i++) {
+ string passname = cryptomatte_prefix + string_printf("Material%02d", i);
+ b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
+ pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
+ }
+ cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_MATERIAL);
+ }
+ if (b_view_layer.use_pass_cryptomatte_asset()) {
+ for (int i = 0; i < crypto_depth; i++) {
+ string passname = cryptomatte_prefix + string_printf("Asset%02d", i);
+ b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
+ pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
+ }
+ cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ASSET);
+ }
+ scene->film->set_cryptomatte_passes(cryptomatte_passes);
+
+ /* Denoising passes. */
+ const bool use_denoising = get_boolean(cscene, "use_denoising") &&
+ get_boolean(crl, "use_denoising");
+ const bool store_denoising_passes = get_boolean(crl, "denoising_store_passes");
+ if (use_denoising) {
+ b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
+ pass_add(scene, PASS_COMBINED, "Noisy Image", PassMode::NOISY);
+ if (get_boolean(crl, "use_pass_shadow_catcher")) {
+ b_engine.add_pass("Noisy Shadow Catcher", 3, "RGB", b_view_layer.name().c_str());
+ pass_add(scene, PASS_SHADOW_CATCHER, "Noisy Shadow Catcher", PassMode::NOISY);
+ }
+ }
+ if (store_denoising_passes) {
+ b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
+ pass_add(scene, PASS_DENOISING_NORMAL, "Denoising Normal", PassMode::NOISY);
+
+ b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str());
+ pass_add(scene, PASS_DENOISING_ALBEDO, "Denoising Albedo", PassMode::NOISY);
+
+ b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str());
+ pass_add(scene, PASS_DENOISING_DEPTH, "Denoising Depth", PassMode::NOISY);
+ }
+
+ /* Custom AOV passes. */
+ BL::ViewLayer::aovs_iterator b_aov_iter;
+ for (b_view_layer.aovs.begin(b_aov_iter); b_aov_iter != b_view_layer.aovs.end(); ++b_aov_iter) {
+ BL::AOV b_aov(*b_aov_iter);
+ if (!b_aov.is_valid()) {
+ continue;
+ }
+
+ string name = b_aov.name();
+ bool is_color = b_aov.type() == BL::AOV::type_COLOR;
+
+ if (is_color) {
+ b_engine.add_pass(name.c_str(), 4, "RGBA", b_view_layer.name().c_str());
+ pass_add(scene, PASS_AOV_COLOR, name.c_str());
+ }
+ else {
+ b_engine.add_pass(name.c_str(), 1, "X", b_view_layer.name().c_str());
+ pass_add(scene, PASS_AOV_VALUE, name.c_str());
+ }
+ }
+
+ scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
+}
+
+void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
+{
+ /* When viewport display is not needed during render we can force some
+ * caches to be releases from blender side in order to reduce peak memory
+ * footprint during synchronization process.
+ */
+
+ const bool is_interface_locked = b_engine.render() && b_engine.render().use_lock_interface();
+ const bool is_persistent_data = b_engine.render() && b_engine.render().use_persistent_data();
+ const bool can_free_caches =
+ (BlenderSession::headless || is_interface_locked) &&
+ /* Baking re-uses the depsgraph multiple times, clearing crashes
+ * reading un-evaluated mesh data which isn't aligned with the
+ * geometry we're baking, see T71012. */
+ !scene->bake_manager->get_baking() &&
+ /* Persistent data must main caches for performance and correctness. */
+ !is_persistent_data;
+
+ if (!can_free_caches) {
+ return;
+ }
+ /* TODO(sergey): We can actually remove the whole dependency graph,
+ * but that will need some API support first.
+ */
+ for (BL::Object &b_ob : b_depsgraph.objects) {
+ b_ob.cache_release();
+ }
+}
+
+/* Scene Parameters */
+
+SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background)
+{
+ SceneParams params;
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system");
+
+ if (shadingsystem == 0)
+ params.shadingsystem = SHADINGSYSTEM_SVM;
+ else if (shadingsystem == 1)
+ params.shadingsystem = SHADINGSYSTEM_OSL;
+
+ if (background || DebugFlags().viewport_static_bvh)
+ params.bvh_type = BVH_TYPE_STATIC;
+ else
+ params.bvh_type = BVH_TYPE_DYNAMIC;
+
+ params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
+ params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh");
+ params.num_bvh_time_steps = RNA_int_get(&cscene, "debug_bvh_time_steps");
+
+ PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
+ params.hair_subdivisions = get_int(csscene, "subdivisions");
+ params.hair_shape = (CurveShapeType)get_enum(
+ csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK);
+
+ int texture_limit;
+ if (background) {
+ texture_limit = RNA_enum_get(&cscene, "texture_limit_render");
+ }
+ else {
+ texture_limit = RNA_enum_get(&cscene, "texture_limit");
+ }
+ if (texture_limit > 0 && b_scene.render().use_simplify()) {
+ params.texture_limit = 1 << (texture_limit + 6);
+ }
+ else {
+ params.texture_limit = 0;
+ }
+
+ params.bvh_layout = DebugFlags().cpu.bvh_layout;
+
+ params.background = background;
+
+ return params;
+}
+
+/* Session Parameters */
+
+bool BlenderSync::get_session_pause(BL::Scene &b_scene, bool background)
+{
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ return (background) ? false : get_boolean(cscene, "preview_pause");
+}
+
+SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
+ BL::Preferences &b_preferences,
+ BL::Scene &b_scene,
+ bool background)
+{
+ SessionParams params;
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+ /* feature set */
+ params.experimental = (get_enum(cscene, "feature_set") != 0);
+
+ /* Headless and background rendering. */
+ params.headless = BlenderSession::headless;
+ params.background = background;
+
+ /* Device */
+ params.threads = blender_device_threads(b_scene);
+ params.device = blender_device_info(b_preferences, b_scene, params.background);
+
+ /* samples */
+ int samples = get_int(cscene, "samples");
+ int preview_samples = get_int(cscene, "preview_samples");
+
+ if (background) {
+ params.samples = samples;
+ }
+ else {
+ params.samples = preview_samples;
+ if (params.samples == 0)
+ params.samples = INT_MAX;
+ }
+
+ /* Clamp samples. */
+ params.samples = min(params.samples, Integrator::MAX_SAMPLES);
+
+ /* Viewport Performance */
+ params.pixel_size = b_engine.get_preview_pixel_size(b_scene);
+
+ if (background) {
+ params.pixel_size = 1;
+ }
+
+ /* shading system - scene level needs full refresh */
+ const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system");
+
+ if (shadingsystem == 0)
+ params.shadingsystem = SHADINGSYSTEM_SVM;
+ else if (shadingsystem == 1)
+ params.shadingsystem = SHADINGSYSTEM_OSL;
+
+ /* Time limit. */
+ if (background) {
+ params.time_limit = get_float(cscene, "time_limit");
+ }
+ else {
+ /* For the viewport it kind of makes more sense to think in terms of the noise floor, which is
+ * usually higher than acceptable level for the final frame. */
+ /* TODO: It might be useful to support time limit in the viewport as well, but needs some
+ * extra thoughts and input. */
+ params.time_limit = 0.0;
+ }
+
+ /* Profiling. */
+ params.use_profiling = params.device.has_profiling && !b_engine.is_preview() && background &&
+ BlenderSession::print_render_stats;
+
+ if (background) {
+ params.use_auto_tile = RNA_boolean_get(&cscene, "use_auto_tile");
+ params.tile_size = max(get_int(cscene, "tile_size"), 8);
+ }
+ else {
+ params.use_auto_tile = false;
+ }
+
+ return params;
+}
+
+DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
+ BL::ViewLayer &b_view_layer,
+ bool background)
+{
+ enum DenoiserInput {
+ DENOISER_INPUT_RGB = 1,
+ DENOISER_INPUT_RGB_ALBEDO = 2,
+ DENOISER_INPUT_RGB_ALBEDO_NORMAL = 3,
+
+ DENOISER_INPUT_NUM,
+ };
+
+ DenoiseParams denoising;
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+ int input_passes = -1;
+
+ if (background) {
+ /* Final Render Denoising */
+ denoising.use = get_boolean(cscene, "use_denoising");
+ denoising.type = (DenoiserType)get_enum(cscene, "denoiser", DENOISER_NUM, DENOISER_NONE);
+ denoising.prefilter = (DenoiserPrefilter)get_enum(
+ cscene, "denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_NONE);
+
+ input_passes = (DenoiserInput)get_enum(
+ cscene, "denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO_NORMAL);
+
+ if (b_view_layer) {
+ PointerRNA clayer = RNA_pointer_get(&b_view_layer.ptr, "cycles");
+ if (!get_boolean(clayer, "use_denoising")) {
+ denoising.use = false;
+ }
+ }
+ }
+ else {
+ /* Viewport Denoising */
+ denoising.use = get_boolean(cscene, "use_preview_denoising");
+ denoising.type = (DenoiserType)get_enum(
+ cscene, "preview_denoiser", DENOISER_NUM, DENOISER_NONE);
+ denoising.prefilter = (DenoiserPrefilter)get_enum(
+ cscene, "preview_denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_FAST);
+ denoising.start_sample = get_int(cscene, "preview_denoising_start_sample");
+
+ input_passes = (DenoiserInput)get_enum(
+ cscene, "preview_denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO);
+
+ /* Auto select fastest denoiser. */
+ if (denoising.type == DENOISER_NONE) {
+ if (!Device::available_devices(DEVICE_MASK_OPTIX).empty()) {
+ denoising.type = DENOISER_OPTIX;
+ }
+ else if (openimagedenoise_supported()) {
+ denoising.type = DENOISER_OPENIMAGEDENOISE;
+ }
+ else {
+ denoising.use = false;
+ }
+ }
+ }
+
+ switch (input_passes) {
+ case DENOISER_INPUT_RGB:
+ denoising.use_pass_albedo = false;
+ denoising.use_pass_normal = false;
+ break;
+
+ case DENOISER_INPUT_RGB_ALBEDO:
+ denoising.use_pass_albedo = true;
+ denoising.use_pass_normal = false;
+ break;
+
+ case DENOISER_INPUT_RGB_ALBEDO_NORMAL:
+ denoising.use_pass_albedo = true;
+ denoising.use_pass_normal = true;
+ break;
+
+ default:
+ LOG(ERROR) << "Unhandled input passes enum " << input_passes;
+ break;
+ }
+
+ return denoising;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h
new file mode 100644
index 00000000000..c2377406876
--- /dev/null
+++ b/intern/cycles/blender/sync.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLENDER_SYNC_H__
+#define __BLENDER_SYNC_H__
+
+#include "MEM_guardedalloc.h"
+#include "RNA_access.h"
+#include "RNA_blender_cpp.h"
+#include "RNA_types.h"
+
+#include "blender/id_map.h"
+#include "blender/util.h"
+#include "blender/viewport.h"
+
+#include "scene/scene.h"
+#include "session/session.h"
+
+#include "util/map.h"
+#include "util/set.h"
+#include "util/transform.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Background;
+class BlenderObjectCulling;
+class BlenderViewportParameters;
+class Camera;
+class Film;
+class Hair;
+class Light;
+class Mesh;
+class Object;
+class ParticleSystem;
+class Scene;
+class ViewLayer;
+class Shader;
+class ShaderGraph;
+class ShaderNode;
+class TaskPool;
+
+class BlenderSync {
+ public:
+ BlenderSync(BL::RenderEngine &b_engine,
+ BL::BlendData &b_data,
+ BL::Scene &b_scene,
+ Scene *scene,
+ bool preview,
+ bool use_developer_ui,
+ Progress &progress);
+ ~BlenderSync();
+
+ void reset(BL::BlendData &b_data, BL::Scene &b_scene);
+
+ /* sync */
+ void sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
+ void sync_data(BL::RenderSettings &b_render,
+ BL::Depsgraph &b_depsgraph,
+ BL::SpaceView3D &b_v3d,
+ BL::Object &b_override,
+ int width,
+ int height,
+ void **python_thread_state);
+ void sync_view_layer(BL::ViewLayer &b_view_layer);
+ void sync_render_passes(BL::RenderLayer &b_render_layer, BL::ViewLayer &b_view_layer);
+ void sync_integrator(BL::ViewLayer &b_view_layer, bool background);
+ void sync_camera(BL::RenderSettings &b_render,
+ BL::Object &b_override,
+ int width,
+ int height,
+ const char *viewname);
+ void sync_view(BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, int width, int height);
+ inline int get_layer_samples()
+ {
+ return view_layer.samples;
+ }
+ inline int get_layer_bound_samples()
+ {
+ return view_layer.bound_samples;
+ }
+
+ /* get parameters */
+ static SceneParams get_scene_params(BL::Scene &b_scene, bool background);
+ static SessionParams get_session_params(BL::RenderEngine &b_engine,
+ BL::Preferences &b_userpref,
+ BL::Scene &b_scene,
+ bool background);
+ static bool get_session_pause(BL::Scene &b_scene, bool background);
+ static BufferParams get_buffer_params(
+ BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height);
+
+ private:
+ static DenoiseParams get_denoise_params(BL::Scene &b_scene,
+ BL::ViewLayer &b_view_layer,
+ bool background);
+
+ /* sync */
+ void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all);
+ void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all);
+ void sync_objects(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, float motion_time = 0.0f);
+ void sync_motion(BL::RenderSettings &b_render,
+ BL::Depsgraph &b_depsgraph,
+ BL::SpaceView3D &b_v3d,
+ BL::Object &b_override,
+ int width,
+ int height,
+ void **python_thread_state);
+ void sync_film(BL::ViewLayer &b_view_layer, BL::SpaceView3D &b_v3d);
+ void sync_view();
+
+ /* Shader */
+ array<Node *> find_used_shaders(BL::Object &b_ob);
+ void sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all);
+ void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
+ void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree);
+
+ /* Object */
+ Object *sync_object(BL::Depsgraph &b_depsgraph,
+ BL::ViewLayer &b_view_layer,
+ BL::DepsgraphObjectInstance &b_instance,
+ float motion_time,
+ bool use_particle_hair,
+ bool show_lights,
+ BlenderObjectCulling &culling,
+ bool *use_portal,
+ TaskPool *geom_task_pool);
+ void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object);
+
+ void sync_procedural(BL::Object &b_ob,
+ BL::MeshSequenceCacheModifier &b_mesh_cache,
+ bool has_subdivision);
+
+ bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);
+
+ /* Volume */
+ void sync_volume(BObjectInfo &b_ob_info, Volume *volume);
+
+ /* Mesh */
+ void sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh);
+ void sync_mesh_motion(BL::Depsgraph b_depsgraph,
+ BObjectInfo &b_ob_info,
+ Mesh *mesh,
+ int motion_step);
+
+ /* Hair */
+ void sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair);
+ void sync_hair_motion(BL::Depsgraph b_depsgraph,
+ BObjectInfo &b_ob_info,
+ Hair *hair,
+ int motion_step);
+ void sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
+ void sync_particle_hair(
+ Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
+ bool object_has_particle_hair(BL::Object b_ob);
+
+ /* Camera */
+ void sync_camera_motion(
+ BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time);
+
+ /* Geometry */
+ Geometry *sync_geometry(BL::Depsgraph &b_depsgrpah,
+ BObjectInfo &b_ob_info,
+ bool object_updated,
+ bool use_particle_hair,
+ TaskPool *task_pool);
+
+ void sync_geometry_motion(BL::Depsgraph &b_depsgraph,
+ BObjectInfo &b_ob_info,
+ Object *object,
+ float motion_time,
+ bool use_particle_hair,
+ TaskPool *task_pool);
+
+ /* Light */
+ void sync_light(BL::Object &b_parent,
+ int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
+ BObjectInfo &b_ob_info,
+ int random_id,
+ Transform &tfm,
+ bool *use_portal);
+ void sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal);
+
+ /* Particles */
+ bool sync_dupli_particle(BL::Object &b_ob,
+ BL::DepsgraphObjectInstance &b_instance,
+ Object *object);
+
+ /* Images. */
+ void sync_images();
+
+ /* Early data free. */
+ void free_data_after_sync(BL::Depsgraph &b_depsgraph);
+
+ /* util */
+ void find_shader(BL::ID &id, array<Node *> &used_shaders, Shader *default_shader);
+ bool BKE_object_is_modified(BL::Object &b_ob);
+ bool object_is_geometry(BL::Object &b_ob);
+ bool object_is_light(BL::Object &b_ob);
+
+ /* variables */
+ BL::RenderEngine b_engine;
+ BL::BlendData b_data;
+ BL::Scene b_scene;
+
+ id_map<void *, Shader> shader_map;
+ id_map<ObjectKey, Object> object_map;
+ id_map<void *, Procedural> procedural_map;
+ id_map<GeometryKey, Geometry> geometry_map;
+ id_map<ObjectKey, Light> light_map;
+ id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
+ set<Geometry *> geometry_synced;
+ set<Geometry *> geometry_motion_synced;
+ set<Geometry *> geometry_motion_attribute_synced;
+ set<float> motion_times;
+ void *world_map;
+ bool world_recalc;
+ BlenderViewportParameters viewport_parameters;
+
+ Scene *scene;
+ bool preview;
+ bool experimental;
+ bool use_developer_ui;
+
+ float dicing_rate;
+ int max_subdivisions;
+
+ struct RenderLayerInfo {
+ RenderLayerInfo()
+ : material_override(PointerRNA_NULL),
+ use_background_shader(true),
+ use_surfaces(true),
+ use_hair(true),
+ use_volumes(true),
+ use_motion_blur(true),
+ samples(0),
+ bound_samples(false)
+ {
+ }
+
+ string name;
+ BL::Material material_override;
+ bool use_background_shader;
+ bool use_surfaces;
+ bool use_hair;
+ bool use_volumes;
+ bool use_motion_blur;
+ int samples;
+ bool bound_samples;
+ } view_layer;
+
+ Progress &progress;
+
+ protected:
+ /* Indicates that `sync_recalc()` detected changes in the scene.
+ * If this flag is false then the data is considered to be up-to-date and will not be
+ * synchronized at all. */
+ bool has_updates_ = true;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_SYNC_H__ */
diff --git a/intern/cycles/blender/texture.cpp b/intern/cycles/blender/texture.cpp
new file mode 100644
index 00000000000..43745bb8376
--- /dev/null
+++ b/intern/cycles/blender/texture.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "blender/texture.h"
+
+CCL_NAMESPACE_BEGIN
+
+namespace {
+
+/* Point density helpers. */
+
+void density_texture_space_invert(float3 &loc, float3 &size)
+{
+ if (size.x != 0.0f)
+ size.x = 0.5f / size.x;
+ if (size.y != 0.0f)
+ size.y = 0.5f / size.y;
+ if (size.z != 0.0f)
+ size.z = 0.5f / size.z;
+
+ loc = loc * size - make_float3(0.5f, 0.5f, 0.5f);
+}
+
+} /* namespace */
+
+void point_density_texture_space(BL::Depsgraph &b_depsgraph,
+ BL::ShaderNodeTexPointDensity &b_point_density_node,
+ float3 &loc,
+ float3 &size)
+{
+ BL::Object b_ob(b_point_density_node.object());
+ if (!b_ob) {
+ loc = zero_float3();
+ size = zero_float3();
+ return;
+ }
+ float3 min, max;
+ b_point_density_node.calc_point_density_minmax(b_depsgraph, &min[0], &max[0]);
+ loc = (min + max) * 0.5f;
+ size = (max - min) * 0.5f;
+ density_texture_space_invert(loc, size);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/texture.h b/intern/cycles/blender/texture.h
new file mode 100644
index 00000000000..ead0c4e631b
--- /dev/null
+++ b/intern/cycles/blender/texture.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLENDER_TEXTURE_H__
+#define __BLENDER_TEXTURE_H__
+
+#include "blender/sync.h"
+#include <stdlib.h>
+
+CCL_NAMESPACE_BEGIN
+
+void point_density_texture_space(BL::Depsgraph &b_depsgraph,
+ BL::ShaderNodeTexPointDensity &b_point_density_node,
+ float3 &loc,
+ float3 &size);
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_TEXTURE_H__ */
diff --git a/intern/cycles/blender/util.h b/intern/cycles/blender/util.h
new file mode 100644
index 00000000000..33fd2c416c8
--- /dev/null
+++ b/intern/cycles/blender/util.h
@@ -0,0 +1,720 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLENDER_UTIL_H__
+#define __BLENDER_UTIL_H__
+
+#include "scene/mesh.h"
+
+#include "util/algorithm.h"
+#include "util/array.h"
+#include "util/map.h"
+#include "util/path.h"
+#include "util/set.h"
+#include "util/transform.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+/* Hacks to hook into Blender API
+ * todo: clean this up ... */
+
+extern "C" {
+void BKE_image_user_frame_calc(void *ima, void *iuser, int cfra);
+void BKE_image_user_file_path(void *iuser, void *ima, char *path);
+unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame, int tile);
+float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
+}
+
+CCL_NAMESPACE_BEGIN
+
+struct BObjectInfo {
+ /* Object directly provided by the depsgraph iterator. This object is only valid during one
+ * iteration and must not be accessed afterwards. Transforms and visibility should be checked on
+ * this object. */
+ BL::Object iter_object;
+
+ /* This object remains alive even after the object iterator is done. It corresponds to one
+ * original object. It is the object that owns the object data below. */
+ BL::Object real_object;
+
+ /* The object-data referenced by the iter object. This is still valid after the depsgraph
+ * iterator is done. It might have a different type compared to real_object.data(). */
+ BL::ID object_data;
+
+ /* True when the current geometry is the data of the referenced object. False when it is a
+ * geometry instance that does not have a 1-to-1 relationship with an object. */
+ bool is_real_object_data() const
+ {
+ return const_cast<BL::Object &>(real_object).data() == object_data;
+ }
+};
+
+typedef BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType;
+BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name);
+
+void python_thread_state_save(void **python_thread_state);
+void python_thread_state_restore(void **python_thread_state);
+
+static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
+ BObjectInfo &b_ob_info,
+ BL::Depsgraph & /*depsgraph*/,
+ bool /*calc_undeformed*/,
+ Mesh::SubdivisionType subdivision_type)
+{
+ /* TODO: make this work with copy-on-write, modifiers are already evaluated. */
+#if 0
+ bool subsurf_mod_show_render = false;
+ bool subsurf_mod_show_viewport = false;
+
+ if (subdivision_type != Mesh::SUBDIVISION_NONE) {
+ BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1];
+
+ subsurf_mod_show_render = subsurf_mod.show_render();
+ subsurf_mod_show_viewport = subsurf_mod.show_viewport();
+
+ subsurf_mod.show_render(false);
+ subsurf_mod.show_viewport(false);
+ }
+#endif
+
+ BL::Mesh mesh = (b_ob_info.object_data.is_a(&RNA_Mesh)) ? BL::Mesh(b_ob_info.object_data) :
+ BL::Mesh(PointerRNA_NULL);
+
+ if (b_ob_info.is_real_object_data()) {
+ if (mesh) {
+ /* Make a copy to split faces if we use autosmooth, otherwise not needed.
+ * Also in edit mode do we need to make a copy, to ensure data layers like
+ * UV are not empty. */
+ if (mesh.is_editmode() ||
+ (mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) {
+ BL::Depsgraph depsgraph(PointerRNA_NULL);
+ mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
+ }
+ }
+ else {
+ BL::Depsgraph depsgraph(PointerRNA_NULL);
+ mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
+ }
+ }
+ else {
+ /* TODO: what to do about non-mesh geometry instances? */
+ }
+
+#if 0
+ if (subdivision_type != Mesh::SUBDIVISION_NONE) {
+ BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1];
+
+ subsurf_mod.show_render(subsurf_mod_show_render);
+ subsurf_mod.show_viewport(subsurf_mod_show_viewport);
+ }
+#endif
+
+ if ((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) {
+ if (mesh.use_auto_smooth()) {
+ mesh.split_faces(false);
+ }
+
+ mesh.calc_loop_triangles();
+ }
+
+ return mesh;
+}
+
+static inline void free_object_to_mesh(BL::BlendData & /*data*/,
+ BObjectInfo &b_ob_info,
+ BL::Mesh &mesh)
+{
+ if (!b_ob_info.is_real_object_data()) {
+ return;
+ }
+ /* Free mesh if we didn't just use the existing one. */
+ BL::Object object = b_ob_info.real_object;
+ if (object.data().ptr.data != mesh.ptr.data) {
+ object.to_mesh_clear();
+ }
+}
+
+static inline void colorramp_to_array(BL::ColorRamp &ramp,
+ array<float3> &ramp_color,
+ array<float> &ramp_alpha,
+ int size)
+{
+ ramp_color.resize(size);
+ ramp_alpha.resize(size);
+
+ for (int i = 0; i < size; i++) {
+ float color[4];
+
+ ramp.evaluate((float)i / (float)(size - 1), color);
+ ramp_color[i] = make_float3(color[0], color[1], color[2]);
+ ramp_alpha[i] = color[3];
+ }
+}
+
+static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap &curve, float *min_x, float *max_x)
+{
+ *min_x = min(*min_x, curve.points[0].location()[0]);
+ *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]);
+}
+
+static inline void curvemapping_minmax(/*const*/ BL::CurveMapping &cumap,
+ int num_curves,
+ float *min_x,
+ float *max_x)
+{
+ // const int num_curves = cumap.curves.length(); /* Gives linking error so far. */
+ *min_x = FLT_MAX;
+ *max_x = -FLT_MAX;
+ for (int i = 0; i < num_curves; ++i) {
+ BL::CurveMap map(cumap.curves[i]);
+ curvemap_minmax_curve(map, min_x, max_x);
+ }
+}
+
+static inline void curvemapping_to_array(BL::CurveMapping &cumap, array<float> &data, int size)
+{
+ cumap.update();
+ BL::CurveMap curve = cumap.curves[0];
+ data.resize(size);
+ for (int i = 0; i < size; i++) {
+ float t = (float)i / (float)(size - 1);
+ data[i] = cumap.evaluate(curve, t);
+ }
+}
+
+static inline void curvemapping_float_to_array(BL::CurveMapping &cumap,
+ array<float> &data,
+ int size)
+{
+ float min = 0.0f, max = 1.0f;
+
+ curvemapping_minmax(cumap, 1, &min, &max);
+
+ const float range = max - min;
+
+ cumap.update();
+
+ BL::CurveMap map = cumap.curves[0];
+
+ data.resize(size);
+
+ for (int i = 0; i < size; i++) {
+ float t = min + (float)i / (float)(size - 1) * range;
+ data[i] = cumap.evaluate(map, t);
+ }
+}
+
+static inline void curvemapping_color_to_array(BL::CurveMapping &cumap,
+ array<float3> &data,
+ int size,
+ bool rgb_curve)
+{
+ float min_x = 0.0f, max_x = 1.0f;
+
+ /* TODO(sergey): There is no easy way to automatically guess what is
+ * the range to be used here for the case when mapping is applied on
+ * top of another mapping (i.e. R curve applied on top of common
+ * one).
+ *
+ * Using largest possible range form all curves works correct for the
+ * cases like vector curves and should be good enough heuristic for
+ * the color curves as well.
+ *
+ * There might be some better estimations here tho.
+ */
+ const int num_curves = rgb_curve ? 4 : 3;
+ curvemapping_minmax(cumap, num_curves, &min_x, &max_x);
+
+ const float range_x = max_x - min_x;
+
+ cumap.update();
+
+ BL::CurveMap mapR = cumap.curves[0];
+ BL::CurveMap mapG = cumap.curves[1];
+ BL::CurveMap mapB = cumap.curves[2];
+
+ data.resize(size);
+
+ if (rgb_curve) {
+ BL::CurveMap mapI = cumap.curves[3];
+ for (int i = 0; i < size; i++) {
+ const float t = min_x + (float)i / (float)(size - 1) * range_x;
+ data[i] = make_float3(cumap.evaluate(mapR, cumap.evaluate(mapI, t)),
+ cumap.evaluate(mapG, cumap.evaluate(mapI, t)),
+ cumap.evaluate(mapB, cumap.evaluate(mapI, t)));
+ }
+ }
+ else {
+ for (int i = 0; i < size; i++) {
+ float t = min_x + (float)i / (float)(size - 1) * range_x;
+ data[i] = make_float3(
+ cumap.evaluate(mapR, t), cumap.evaluate(mapG, t), cumap.evaluate(mapB, t));
+ }
+ }
+}
+
+static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bool preview)
+{
+ return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
+}
+
+static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview)
+{
+ if (!self.is_real_object_data()) {
+ return false;
+ }
+ return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true :
+ false;
+}
+
+static inline int render_resolution_x(BL::RenderSettings &b_render)
+{
+ return b_render.resolution_x() * b_render.resolution_percentage() / 100;
+}
+
+static inline int render_resolution_y(BL::RenderSettings &b_render)
+{
+ return b_render.resolution_y() * b_render.resolution_percentage() / 100;
+}
+
+static inline string image_user_file_path(BL::ImageUser &iuser,
+ BL::Image &ima,
+ int cfra,
+ bool load_tiled)
+{
+ char filepath[1024];
+ iuser.tile(0);
+ BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra);
+ BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath);
+
+ string filepath_str = string(filepath);
+ if (load_tiled && ima.source() == BL::Image::source_TILED) {
+ string udim;
+ if (ima.tiles.length() > 0) {
+ udim = to_string(ima.tiles[0].number());
+ }
+ string_replace(filepath_str, udim, "<UDIM>");
+ }
+ return filepath_str;
+}
+
+static inline int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, int cfra)
+{
+ BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra);
+ return iuser.frame_current();
+}
+
+static inline unsigned char *image_get_pixels_for_frame(BL::Image &image, int frame, int tile)
+{
+ return BKE_image_get_pixels_for_frame(image.ptr.data, frame, tile);
+}
+
+static inline float *image_get_float_pixels_for_frame(BL::Image &image, int frame, int tile)
+{
+ return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame, tile);
+}
+
+static inline void render_add_metadata(BL::RenderResult &b_rr, string name, string value)
+{
+ b_rr.stamp_data_add_field(name.c_str(), value.c_str());
+}
+
+/* Utilities */
+
+static inline Transform get_transform(const BL::Array<float, 16> &array)
+{
+ ProjectionTransform projection;
+
+ /* We assume both types to be just 16 floats, and transpose because blender
+ * use column major matrix order while we use row major. */
+ memcpy((void *)&projection, &array, sizeof(float) * 16);
+ projection = projection_transpose(projection);
+
+ /* Drop last row, matrix is assumed to be affine transform. */
+ return projection_to_transform(projection);
+}
+
+static inline float2 get_float2(const BL::Array<float, 2> &array)
+{
+ return make_float2(array[0], array[1]);
+}
+
+static inline float3 get_float3(const BL::Array<float, 2> &array)
+{
+ return make_float3(array[0], array[1], 0.0f);
+}
+
+static inline float3 get_float3(const BL::Array<float, 3> &array)
+{
+ return make_float3(array[0], array[1], array[2]);
+}
+
+static inline float3 get_float3(const BL::Array<float, 4> &array)
+{
+ return make_float3(array[0], array[1], array[2]);
+}
+
+static inline float4 get_float4(const BL::Array<float, 4> &array)
+{
+ return make_float4(array[0], array[1], array[2], array[3]);
+}
+
+static inline int3 get_int3(const BL::Array<int, 3> &array)
+{
+ return make_int3(array[0], array[1], array[2]);
+}
+
+static inline int4 get_int4(const BL::Array<int, 4> &array)
+{
+ return make_int4(array[0], array[1], array[2], array[3]);
+}
+
+static inline float3 get_float3(PointerRNA &ptr, const char *name)
+{
+ float3 f;
+ RNA_float_get_array(&ptr, name, &f.x);
+ return f;
+}
+
+static inline void set_float3(PointerRNA &ptr, const char *name, float3 value)
+{
+ RNA_float_set_array(&ptr, name, &value.x);
+}
+
+static inline float4 get_float4(PointerRNA &ptr, const char *name)
+{
+ float4 f;
+ RNA_float_get_array(&ptr, name, &f.x);
+ return f;
+}
+
+static inline void set_float4(PointerRNA &ptr, const char *name, float4 value)
+{
+ RNA_float_set_array(&ptr, name, &value.x);
+}
+
+static inline bool get_boolean(PointerRNA &ptr, const char *name)
+{
+ return RNA_boolean_get(&ptr, name) ? true : false;
+}
+
+static inline void set_boolean(PointerRNA &ptr, const char *name, bool value)
+{
+ RNA_boolean_set(&ptr, name, (int)value);
+}
+
+static inline float get_float(PointerRNA &ptr, const char *name)
+{
+ return RNA_float_get(&ptr, name);
+}
+
+static inline void set_float(PointerRNA &ptr, const char *name, float value)
+{
+ RNA_float_set(&ptr, name, value);
+}
+
+static inline int get_int(PointerRNA &ptr, const char *name)
+{
+ return RNA_int_get(&ptr, name);
+}
+
+static inline void set_int(PointerRNA &ptr, const char *name, int value)
+{
+ RNA_int_set(&ptr, name, value);
+}
+
+/* Get a RNA enum value with sanity check: if the RNA value is above num_values
+ * the function will return a fallback default value.
+ *
+ * NOTE: This function assumes that RNA enum values are a continuous sequence
+ * from 0 to num_values-1. Be careful to use it with enums where some values are
+ * deprecated!
+ */
+static inline int get_enum(PointerRNA &ptr,
+ const char *name,
+ int num_values = -1,
+ int default_value = -1)
+{
+ int value = RNA_enum_get(&ptr, name);
+ if (num_values != -1 && value >= num_values) {
+ assert(default_value != -1);
+ value = default_value;
+ }
+ return value;
+}
+
+static inline string get_enum_identifier(PointerRNA &ptr, const char *name)
+{
+ PropertyRNA *prop = RNA_struct_find_property(&ptr, name);
+ const char *identifier = "";
+ int value = RNA_property_enum_get(&ptr, prop);
+
+ RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
+
+ return string(identifier);
+}
+
+static inline void set_enum(PointerRNA &ptr, const char *name, int value)
+{
+ RNA_enum_set(&ptr, name, value);
+}
+
+static inline void set_enum(PointerRNA &ptr, const char *name, const string &identifier)
+{
+ RNA_enum_set_identifier(NULL, &ptr, name, identifier.c_str());
+}
+
+static inline string get_string(PointerRNA &ptr, const char *name)
+{
+ char cstrbuf[1024];
+ char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf), NULL);
+ string str(cstr);
+ if (cstr != cstrbuf)
+ MEM_freeN(cstr);
+
+ return str;
+}
+
+static inline void set_string(PointerRNA &ptr, const char *name, const string &value)
+{
+ RNA_string_set(&ptr, name, value.c_str());
+}
+
+/* Relative Paths */
+
+static inline string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path)
+{
+ if (path.size() >= 2 && path[0] == '/' && path[1] == '/') {
+ string dirname;
+
+ if (b_id.library()) {
+ BL::ID b_library_id(b_id.library());
+ dirname = blender_absolute_path(b_data, b_library_id, b_id.library().filepath());
+ }
+ else
+ dirname = b_data.filepath();
+
+ return path_join(path_dirname(dirname), path.substr(2));
+ }
+
+ return path;
+}
+
+static inline string get_text_datablock_content(const PointerRNA &ptr)
+{
+ if (ptr.data == NULL) {
+ return "";
+ }
+
+ string content;
+ BL::Text::lines_iterator iter;
+ for (iter.begin(ptr); iter; ++iter) {
+ content += iter->body() + "\n";
+ }
+
+ return content;
+}
+
+/* Texture Space */
+
+static inline void mesh_texture_space(BL::Mesh &b_mesh, float3 &loc, float3 &size)
+{
+ loc = get_float3(b_mesh.texspace_location());
+ size = get_float3(b_mesh.texspace_size());
+
+ if (size.x != 0.0f)
+ size.x = 0.5f / size.x;
+ if (size.y != 0.0f)
+ size.y = 0.5f / size.y;
+ if (size.z != 0.0f)
+ size.z = 0.5f / size.z;
+
+ loc = loc * size - make_float3(0.5f, 0.5f, 0.5f);
+}
+
+/* Object motion steps, returns 0 if no motion blur needed. */
+static inline uint object_motion_steps(BL::Object &b_parent,
+ BL::Object &b_ob,
+ const int max_steps = INT_MAX)
+{
+ /* Get motion enabled and steps from object itself. */
+ PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+ bool use_motion = get_boolean(cobject, "use_motion_blur");
+ if (!use_motion) {
+ return 0;
+ }
+
+ int steps = max(1, get_int(cobject, "motion_steps"));
+
+ /* Also check parent object, so motion blur and steps can be
+ * controlled by dupligroup duplicator for linked groups. */
+ if (b_parent.ptr.data != b_ob.ptr.data) {
+ PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
+ use_motion &= get_boolean(parent_cobject, "use_motion_blur");
+
+ if (!use_motion) {
+ return 0;
+ }
+
+ steps = max(steps, get_int(parent_cobject, "motion_steps"));
+ }
+
+ /* Use uneven number of steps so we get one keyframe at the current frame,
+ * and use 2^(steps - 1) so objects with more/fewer steps still have samples
+ * at the same times, to avoid sampling at many different times. */
+ return min((2 << (steps - 1)) + 1, max_steps);
+}
+
+/* object uses deformation motion blur */
+static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob)
+{
+ PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+ bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
+ /* If motion blur is enabled for the object we also check
+ * whether it's enabled for the parent object as well.
+ *
+ * This way we can control motion blur from the dupligroup
+ * duplicator much easier.
+ */
+ if (use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
+ PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
+ use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
+ }
+ return use_deform_motion;
+}
+
+static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
+{
+ for (BL::Modifier &b_mod : b_ob.modifiers) {
+ if (b_mod.is_a(&RNA_FluidModifier)) {
+ BL::FluidModifier b_mmd(b_mod);
+
+ if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
+ b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_GAS) {
+ return b_mmd.domain_settings();
+ }
+ }
+ }
+
+ return BL::FluidDomainSettings(PointerRNA_NULL);
+}
+
+static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob,
+ bool *has_subdivision_modifier)
+{
+ for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
+ BL::Modifier b_mod = b_ob.modifiers[i];
+
+ if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
+ BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
+ return mesh_cache;
+ }
+
+ /* Skip possible particles system modifiers as they do not modify the geometry. */
+ if (b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) {
+ continue;
+ }
+
+ if (b_mod.type() == BL::Modifier::type_SUBSURF) {
+ if (has_subdivision_modifier) {
+ *has_subdivision_modifier = true;
+ }
+ continue;
+ }
+
+ break;
+ }
+
+ return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
+}
+
+static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
+ bool preview,
+ bool experimental)
+{
+ PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
+
+ if (cobj.data && b_ob.modifiers.length() > 0 && experimental) {
+ BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
+ bool enabled = preview ? mod.show_viewport() : mod.show_render();
+
+ if (enabled && mod.type() == BL::Modifier::type_SUBSURF &&
+ RNA_boolean_get(&cobj, "use_adaptive_subdivision")) {
+ BL::SubsurfModifier subsurf(mod);
+
+ if (subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
+ return Mesh::SUBDIVISION_CATMULL_CLARK;
+ }
+ else {
+ return Mesh::SUBDIVISION_LINEAR;
+ }
+ }
+ }
+
+ return Mesh::SUBDIVISION_NONE;
+}
+
+static inline uint object_ray_visibility(BL::Object &b_ob)
+{
+ uint flag = 0;
+
+ flag |= b_ob.visible_camera() ? PATH_RAY_CAMERA : 0;
+ flag |= b_ob.visible_diffuse() ? PATH_RAY_DIFFUSE : 0;
+ flag |= b_ob.visible_glossy() ? PATH_RAY_GLOSSY : 0;
+ flag |= b_ob.visible_transmission() ? PATH_RAY_TRANSMIT : 0;
+ flag |= b_ob.visible_shadow() ? PATH_RAY_SHADOW : 0;
+ flag |= b_ob.visible_volume_scatter() ? PATH_RAY_VOLUME_SCATTER : 0;
+
+ return flag;
+}
+
+class EdgeMap {
+ public:
+ EdgeMap()
+ {
+ }
+
+ void clear()
+ {
+ edges_.clear();
+ }
+
+ void insert(int v0, int v1)
+ {
+ get_sorted_verts(v0, v1);
+ edges_.insert(std::pair<int, int>(v0, v1));
+ }
+
+ bool exists(int v0, int v1)
+ {
+ get_sorted_verts(v0, v1);
+ return edges_.find(std::pair<int, int>(v0, v1)) != edges_.end();
+ }
+
+ protected:
+ void get_sorted_verts(int &v0, int &v1)
+ {
+ if (v0 > v1) {
+ swap(v0, v1);
+ }
+ }
+
+ set<std::pair<int, int>> edges_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_UTIL_H__ */
diff --git a/intern/cycles/blender/viewport.cpp b/intern/cycles/blender/viewport.cpp
new file mode 100644
index 00000000000..2a6f7e3ecee
--- /dev/null
+++ b/intern/cycles/blender/viewport.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "blender/viewport.h"
+#include "blender/util.h"
+
+#include "scene/pass.h"
+
+#include "util/log.h"
+
+CCL_NAMESPACE_BEGIN
+
+BlenderViewportParameters::BlenderViewportParameters()
+ : use_scene_world(true),
+ use_scene_lights(true),
+ studiolight_rotate_z(0.0f),
+ studiolight_intensity(1.0f),
+ studiolight_background_alpha(1.0f),
+ display_pass(PASS_COMBINED),
+ show_active_pixels(false)
+{
+}
+
+BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d, bool use_developer_ui)
+ : BlenderViewportParameters()
+{
+ if (!b_v3d) {
+ return;
+ }
+
+ BL::View3DShading shading = b_v3d.shading();
+ PointerRNA cshading = RNA_pointer_get(&shading.ptr, "cycles");
+
+ /* We only copy the shading parameters if we are in look-dev mode.
+ * Otherwise defaults are being used. These defaults mimic normal render settings. */
+ if (shading.type() == BL::View3DShading::type_RENDERED) {
+ use_scene_world = shading.use_scene_world_render();
+ use_scene_lights = shading.use_scene_lights_render();
+
+ if (!use_scene_world) {
+ studiolight_rotate_z = shading.studiolight_rotate_z();
+ studiolight_intensity = shading.studiolight_intensity();
+ studiolight_background_alpha = shading.studiolight_background_alpha();
+ studiolight_path = shading.selected_studio_light().path();
+ }
+ }
+
+ /* Film. */
+
+ /* Lookup display pass based on the enum identifier.
+ * This is because integer values of python enum are not aligned with the passes definition in
+ * the kernel. */
+
+ display_pass = PASS_COMBINED;
+
+ const string display_pass_identifier = get_enum_identifier(cshading, "render_pass");
+ if (!display_pass_identifier.empty()) {
+ const ustring pass_type_identifier(string_to_lower(display_pass_identifier));
+ const NodeEnum *pass_type_enum = Pass::get_type_enum();
+ if (pass_type_enum->exists(pass_type_identifier)) {
+ display_pass = static_cast<PassType>((*pass_type_enum)[pass_type_identifier]);
+ }
+ }
+
+ if (use_developer_ui) {
+ show_active_pixels = get_boolean(cshading, "show_active_pixels");
+ }
+}
+
+bool BlenderViewportParameters::shader_modified(const BlenderViewportParameters &other) const
+{
+ return use_scene_world != other.use_scene_world || use_scene_lights != other.use_scene_lights ||
+ studiolight_rotate_z != other.studiolight_rotate_z ||
+ studiolight_intensity != other.studiolight_intensity ||
+ studiolight_background_alpha != other.studiolight_background_alpha ||
+ studiolight_path != other.studiolight_path;
+}
+
+bool BlenderViewportParameters::film_modified(const BlenderViewportParameters &other) const
+{
+ return display_pass != other.display_pass || show_active_pixels != other.show_active_pixels;
+}
+
+bool BlenderViewportParameters::modified(const BlenderViewportParameters &other) const
+{
+ return shader_modified(other) || film_modified(other);
+}
+
+bool BlenderViewportParameters::use_custom_shader() const
+{
+ return !(use_scene_world && use_scene_lights);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/viewport.h b/intern/cycles/blender/viewport.h
new file mode 100644
index 00000000000..a445973f4d2
--- /dev/null
+++ b/intern/cycles/blender/viewport.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLENDER_VIEWPORT_H__
+#define __BLENDER_VIEWPORT_H__
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_blender_cpp.h"
+#include "RNA_types.h"
+
+#include "scene/film.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BlenderViewportParameters {
+ public:
+ /* Shader. */
+ bool use_scene_world;
+ bool use_scene_lights;
+ float studiolight_rotate_z;
+ float studiolight_intensity;
+ float studiolight_background_alpha;
+ ustring studiolight_path;
+
+ /* Film. */
+ PassType display_pass;
+ bool show_active_pixels;
+
+ BlenderViewportParameters();
+ BlenderViewportParameters(BL::SpaceView3D &b_v3d, bool use_developer_ui);
+
+ /* Check whether any of shading related settings are different from the given parameters. */
+ bool shader_modified(const BlenderViewportParameters &other) const;
+
+ /* Check whether any of film related settings are different from the given parameters. */
+ bool film_modified(const BlenderViewportParameters &other) const;
+
+ /* Check whether any of settings are different from the given parameters. */
+ bool modified(const BlenderViewportParameters &other) const;
+
+ /* Returns truth when a custom shader defined by the viewport is to be used instead of the
+ * regular background shader or scene light. */
+ bool use_custom_shader() const;
+};
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/blender/volume.cpp b/intern/cycles/blender/volume.cpp
new file mode 100644
index 00000000000..a41e15621a7
--- /dev/null
+++ b/intern/cycles/blender/volume.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/volume.h"
+#include "scene/colorspace.h"
+#include "scene/image.h"
+#include "scene/image_vdb.h"
+#include "scene/object.h"
+
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const struct Volume *volume,
+ const struct VolumeGrid *grid);
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* TODO: verify this is not loading unnecessary attributes. */
+class BlenderSmokeLoader : public ImageLoader {
+ public:
+ BlenderSmokeLoader(BL::Object &b_ob, AttributeStandard attribute)
+ : b_domain(object_fluid_gas_domain_find(b_ob)), attribute(attribute)
+ {
+ BL::Mesh b_mesh(b_ob.data());
+ mesh_texture_space(b_mesh, texspace_loc, texspace_size);
+ }
+
+ bool load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) override
+ {
+ if (!b_domain) {
+ return false;
+ }
+
+ if (attribute == ATTR_STD_VOLUME_DENSITY || attribute == ATTR_STD_VOLUME_FLAME ||
+ attribute == ATTR_STD_VOLUME_HEAT || attribute == ATTR_STD_VOLUME_TEMPERATURE) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT;
+ metadata.channels = 1;
+ }
+ else if (attribute == ATTR_STD_VOLUME_COLOR) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
+ metadata.channels = 4;
+ }
+ else if (attribute == ATTR_STD_VOLUME_VELOCITY) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
+ metadata.channels = 3;
+ }
+ else {
+ return false;
+ }
+
+ int3 resolution = get_int3(b_domain.domain_resolution());
+ int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
+
+ /* Velocity and heat data is always low-resolution. */
+ if (attribute == ATTR_STD_VOLUME_VELOCITY || attribute == ATTR_STD_VOLUME_HEAT) {
+ amplify = 1;
+ }
+
+ metadata.width = resolution.x * amplify;
+ metadata.height = resolution.y * amplify;
+ metadata.depth = resolution.z * amplify;
+
+ /* Create a matrix to transform from object space to mesh texture space.
+ * This does not work with deformations but that can probably only be done
+ * well with a volume grid mapping of coordinates. */
+ metadata.transform_3d = transform_translate(-texspace_loc) * transform_scale(texspace_size);
+ metadata.use_transform_3d = true;
+
+ return true;
+ }
+
+ bool load_pixels(const ImageMetaData &, void *pixels, const size_t, const bool) override
+ {
+ if (!b_domain) {
+ return false;
+ }
+#ifdef WITH_FLUID
+ int3 resolution = get_int3(b_domain.domain_resolution());
+ int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
+
+ /* Velocity and heat data is always low-resolution. */
+ if (attribute == ATTR_STD_VOLUME_VELOCITY || attribute == ATTR_STD_VOLUME_HEAT) {
+ amplify = 1;
+ }
+
+ const int width = resolution.x * amplify;
+ const int height = resolution.y * amplify;
+ const int depth = resolution.z * amplify;
+ const size_t num_pixels = ((size_t)width) * height * depth;
+
+ float *fpixels = (float *)pixels;
+
+ if (attribute == ATTR_STD_VOLUME_DENSITY) {
+ FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels) {
+ FluidDomainSettings_density_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else if (attribute == ATTR_STD_VOLUME_FLAME) {
+ /* this is in range 0..1, and interpreted by the OpenGL smoke viewer
+ * as 1500..3000 K with the first part faded to zero density */
+ FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels) {
+ FluidDomainSettings_flame_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else if (attribute == ATTR_STD_VOLUME_COLOR) {
+ /* the RGB is "premultiplied" by density for better interpolation results */
+ FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels * 4) {
+ FluidDomainSettings_color_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else if (attribute == ATTR_STD_VOLUME_VELOCITY) {
+ FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels * 3) {
+ FluidDomainSettings_velocity_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else if (attribute == ATTR_STD_VOLUME_HEAT) {
+ FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels) {
+ FluidDomainSettings_heat_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else if (attribute == ATTR_STD_VOLUME_TEMPERATURE) {
+ FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels) {
+ FluidDomainSettings_temperature_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else {
+ fprintf(stderr,
+ "Cycles error: unknown volume attribute %s, skipping\n",
+ Attribute::standard_name(attribute));
+ fpixels[0] = 0.0f;
+ return false;
+ }
+#else
+ (void)pixels;
+#endif
+ fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
+ return false;
+ }
+
+ string name() const override
+ {
+ return Attribute::standard_name(attribute);
+ }
+
+ bool equals(const ImageLoader &other) const override
+ {
+ const BlenderSmokeLoader &other_loader = (const BlenderSmokeLoader &)other;
+ return b_domain == other_loader.b_domain && attribute == other_loader.attribute;
+ }
+
+ BL::FluidDomainSettings b_domain;
+ float3 texspace_loc, texspace_size;
+ AttributeStandard attribute;
+};
+
+static void sync_smoke_volume(Scene *scene, BObjectInfo &b_ob_info, Volume *volume, float frame)
+{
+ if (!b_ob_info.is_real_object_data()) {
+ return;
+ }
+ BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob_info.real_object);
+ if (!b_domain) {
+ return;
+ }
+
+ AttributeStandard attributes[] = {ATTR_STD_VOLUME_DENSITY,
+ ATTR_STD_VOLUME_COLOR,
+ ATTR_STD_VOLUME_FLAME,
+ ATTR_STD_VOLUME_HEAT,
+ ATTR_STD_VOLUME_TEMPERATURE,
+ ATTR_STD_VOLUME_VELOCITY,
+ ATTR_STD_NONE};
+
+ for (int i = 0; attributes[i] != ATTR_STD_NONE; i++) {
+ AttributeStandard std = attributes[i];
+ if (!volume->need_attribute(scene, std)) {
+ continue;
+ }
+
+ volume->set_clipping(b_domain.clipping());
+
+ Attribute *attr = volume->attributes.add(std);
+
+ ImageLoader *loader = new BlenderSmokeLoader(b_ob_info.real_object, std);
+ ImageParams params;
+ params.frame = frame;
+
+ attr->data_voxel() = scene->image_manager->add_image(loader, params);
+ }
+}
+
+class BlenderVolumeLoader : public VDBImageLoader {
+ public:
+ BlenderVolumeLoader(BL::BlendData &b_data, BL::Volume &b_volume, const string &grid_name)
+ : VDBImageLoader(grid_name), b_volume(b_volume)
+ {
+ b_volume.grids.load(b_data.ptr.data);
+
+#ifdef WITH_OPENVDB
+ for (BL::VolumeGrid &b_volume_grid : b_volume.grids) {
+ if (b_volume_grid.name() == grid_name) {
+ const bool unload = !b_volume_grid.is_loaded();
+
+ ::Volume *volume = (::Volume *)b_volume.ptr.data;
+ const VolumeGrid *volume_grid = (VolumeGrid *)b_volume_grid.ptr.data;
+ grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
+
+ if (unload) {
+ b_volume_grid.unload();
+ }
+
+ break;
+ }
+ }
+#endif
+ }
+
+ BL::Volume b_volume;
+};
+
+static void sync_volume_object(BL::BlendData &b_data,
+ BObjectInfo &b_ob_info,
+ Scene *scene,
+ Volume *volume)
+{
+ BL::Volume b_volume(b_ob_info.object_data);
+ b_volume.grids.load(b_data.ptr.data);
+
+ BL::VolumeRender b_render(b_volume.render());
+
+ volume->set_clipping(b_render.clipping());
+ volume->set_step_size(b_render.step_size());
+ volume->set_object_space((b_render.space() == BL::VolumeRender::space_OBJECT));
+
+ /* Find grid with matching name. */
+ for (BL::VolumeGrid &b_grid : b_volume.grids) {
+ ustring name = ustring(b_grid.name());
+ AttributeStandard std = ATTR_STD_NONE;
+
+ if (name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
+ std = ATTR_STD_VOLUME_DENSITY;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
+ std = ATTR_STD_VOLUME_COLOR;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) {
+ std = ATTR_STD_VOLUME_FLAME;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
+ std = ATTR_STD_VOLUME_HEAT;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) {
+ std = ATTR_STD_VOLUME_TEMPERATURE;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) {
+ std = ATTR_STD_VOLUME_VELOCITY;
+ }
+
+ if ((std != ATTR_STD_NONE && volume->need_attribute(scene, std)) ||
+ volume->need_attribute(scene, name)) {
+ Attribute *attr = (std != ATTR_STD_NONE) ?
+ volume->attributes.add(std) :
+ volume->attributes.add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL);
+
+ ImageLoader *loader = new BlenderVolumeLoader(b_data, b_volume, name.string());
+ ImageParams params;
+ params.frame = b_volume.grids.frame();
+
+ attr->data_voxel() = scene->image_manager->add_image(loader, params, false);
+ }
+ }
+}
+
+void BlenderSync::sync_volume(BObjectInfo &b_ob_info, Volume *volume)
+{
+ volume->clear(true);
+
+ if (view_layer.use_volumes) {
+ if (b_ob_info.object_data.is_a(&RNA_Volume)) {
+ /* Volume object. Create only attributes, bounding mesh will then
+ * be automatically generated later. */
+ sync_volume_object(b_data, b_ob_info, scene, volume);
+ }
+ else {
+ /* Smoke domain. */
+ sync_smoke_volume(scene, b_ob_info, volume, b_scene.frame_current());
+ }
+ }
+
+ /* Tag update. */
+ volume->tag_update(scene, true);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt
index 8cc72359757..9edc30cf9c4 100644
--- a/intern/cycles/bvh/CMakeLists.txt
+++ b/intern/cycles/bvh/CMakeLists.txt
@@ -22,34 +22,34 @@ set(INC_SYS
set(SRC
bvh.cpp
bvh2.cpp
- bvh_binning.cpp
- bvh_build.cpp
- bvh_embree.cpp
- bvh_multi.cpp
- bvh_node.cpp
- bvh_optix.cpp
- bvh_sort.cpp
- bvh_split.cpp
- bvh_unaligned.cpp
+ binning.cpp
+ build.cpp
+ embree.cpp
+ multi.cpp
+ node.cpp
+ optix.cpp
+ sort.cpp
+ split.cpp
+ unaligned.cpp
)
set(SRC_HEADERS
bvh.h
bvh2.h
- bvh_binning.h
- bvh_build.h
- bvh_embree.h
- bvh_multi.h
- bvh_node.h
- bvh_optix.h
- bvh_params.h
- bvh_sort.h
- bvh_split.h
- bvh_unaligned.h
+ binning.h
+ build.h
+ embree.h
+ multi.h
+ node.h
+ optix.h
+ params.h
+ sort.h
+ split.h
+ unaligned.h
)
set(LIB
- cycles_render
+ cycles_scene
cycles_util
)
diff --git a/intern/cycles/bvh/binning.cpp b/intern/cycles/bvh/binning.cpp
new file mode 100644
index 00000000000..da591ef5cea
--- /dev/null
+++ b/intern/cycles/bvh/binning.cpp
@@ -0,0 +1,293 @@
+/*
+ * Adapted from code copyright 2009-2011 Intel Corporation
+ * Modifications Copyright 2012, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define __KERNEL_SSE__
+
+#include "bvh/binning.h"
+
+#include <stdlib.h>
+
+#include "util/algorithm.h"
+#include "util/boundbox.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* SSE replacements */
+
+__forceinline void prefetch_L1(const void * /*ptr*/)
+{
+}
+__forceinline void prefetch_L2(const void * /*ptr*/)
+{
+}
+__forceinline void prefetch_L3(const void * /*ptr*/)
+{
+}
+__forceinline void prefetch_NTA(const void * /*ptr*/)
+{
+}
+
+template<size_t src> __forceinline float extract(const int4 &b)
+{
+ return b[src];
+}
+template<size_t dst> __forceinline const float4 insert(const float4 &a, const float b)
+{
+ float4 r = a;
+ r[dst] = b;
+ return r;
+}
+
+__forceinline int get_best_dimension(const float4 &bestSAH)
+{
+ // return (int)__bsf(movemask(reduce_min(bestSAH) == bestSAH));
+
+ float minSAH = min(bestSAH.x, min(bestSAH.y, bestSAH.z));
+
+ if (bestSAH.x == minSAH)
+ return 0;
+ else if (bestSAH.y == minSAH)
+ return 1;
+ else
+ return 2;
+}
+
+/* BVH Object Binning */
+
+BVHObjectBinning::BVHObjectBinning(const BVHRange &job,
+ BVHReference *prims,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
+ : BVHRange(job),
+ splitSAH(FLT_MAX),
+ dim(0),
+ pos(0),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
+{
+ if (aligned_space_ == NULL) {
+ bounds_ = bounds();
+ cent_bounds_ = cent_bounds();
+ }
+ else {
+ /* TODO(sergey): With some additional storage we can avoid
+ * need in re-calculating this.
+ */
+ bounds_ = unaligned_heuristic->compute_aligned_boundbox(
+ *this, prims, *aligned_space, &cent_bounds_);
+ }
+
+ /* compute number of bins to use and precompute scaling factor for binning */
+ num_bins = min(size_t(MAX_BINS), size_t(4.0f + 0.05f * size()));
+ scale = rcp(cent_bounds_.size()) * make_float3((float)num_bins);
+
+ /* initialize binning counter and bounds */
+ BoundBox bin_bounds[MAX_BINS][4]; /* bounds for every bin in every dimension */
+ int4 bin_count[MAX_BINS]; /* number of primitives mapped to bin */
+
+ for (size_t i = 0; i < num_bins; i++) {
+ bin_count[i] = make_int4(0);
+ bin_bounds[i][0] = bin_bounds[i][1] = bin_bounds[i][2] = BoundBox::empty;
+ }
+
+ /* map geometry to bins, unrolled once */
+ {
+ int64_t i;
+
+ for (i = 0; i < int64_t(size()) - 1; i += 2) {
+ prefetch_L2(&prims[start() + i + 8]);
+
+ /* map even and odd primitive to bin */
+ const BVHReference &prim0 = prims[start() + i + 0];
+ const BVHReference &prim1 = prims[start() + i + 1];
+
+ BoundBox bounds0 = get_prim_bounds(prim0);
+ BoundBox bounds1 = get_prim_bounds(prim1);
+
+ int4 bin0 = get_bin(bounds0);
+ int4 bin1 = get_bin(bounds1);
+
+ /* increase bounds for bins for even primitive */
+ int b00 = (int)extract<0>(bin0);
+ bin_count[b00][0]++;
+ bin_bounds[b00][0].grow(bounds0);
+ int b01 = (int)extract<1>(bin0);
+ bin_count[b01][1]++;
+ bin_bounds[b01][1].grow(bounds0);
+ int b02 = (int)extract<2>(bin0);
+ bin_count[b02][2]++;
+ bin_bounds[b02][2].grow(bounds0);
+
+ /* increase bounds of bins for odd primitive */
+ int b10 = (int)extract<0>(bin1);
+ bin_count[b10][0]++;
+ bin_bounds[b10][0].grow(bounds1);
+ int b11 = (int)extract<1>(bin1);
+ bin_count[b11][1]++;
+ bin_bounds[b11][1].grow(bounds1);
+ int b12 = (int)extract<2>(bin1);
+ bin_count[b12][2]++;
+ bin_bounds[b12][2].grow(bounds1);
+ }
+
+ /* for uneven number of primitives */
+ if (i < int64_t(size())) {
+ /* map primitive to bin */
+ const BVHReference &prim0 = prims[start() + i];
+ BoundBox bounds0 = get_prim_bounds(prim0);
+ int4 bin0 = get_bin(bounds0);
+
+ /* increase bounds of bins */
+ int b00 = (int)extract<0>(bin0);
+ bin_count[b00][0]++;
+ bin_bounds[b00][0].grow(bounds0);
+ int b01 = (int)extract<1>(bin0);
+ bin_count[b01][1]++;
+ bin_bounds[b01][1].grow(bounds0);
+ int b02 = (int)extract<2>(bin0);
+ bin_count[b02][2]++;
+ bin_bounds[b02][2].grow(bounds0);
+ }
+ }
+
+ /* sweep from right to left and compute parallel prefix of merged bounds */
+ float4 r_area[MAX_BINS]; /* area of bounds of primitives on the right */
+ float4 r_count[MAX_BINS]; /* number of primitives on the right */
+ int4 count = make_int4(0);
+
+ BoundBox bx = BoundBox::empty;
+ BoundBox by = BoundBox::empty;
+ BoundBox bz = BoundBox::empty;
+
+ for (size_t i = num_bins - 1; i > 0; i--) {
+ count = count + bin_count[i];
+ r_count[i] = blocks(count);
+
+ bx = merge(bx, bin_bounds[i][0]);
+ r_area[i][0] = bx.half_area();
+ by = merge(by, bin_bounds[i][1]);
+ r_area[i][1] = by.half_area();
+ bz = merge(bz, bin_bounds[i][2]);
+ r_area[i][2] = bz.half_area();
+ r_area[i][3] = r_area[i][2];
+ }
+
+ /* sweep from left to right and compute SAH */
+ int4 ii = make_int4(1);
+ float4 bestSAH = make_float4(FLT_MAX);
+ int4 bestSplit = make_int4(-1);
+
+ count = make_int4(0);
+
+ bx = BoundBox::empty;
+ by = BoundBox::empty;
+ bz = BoundBox::empty;
+
+ for (size_t i = 1; i < num_bins; i++, ii += make_int4(1)) {
+ count = count + bin_count[i - 1];
+
+ bx = merge(bx, bin_bounds[i - 1][0]);
+ float Ax = bx.half_area();
+ by = merge(by, bin_bounds[i - 1][1]);
+ float Ay = by.half_area();
+ bz = merge(bz, bin_bounds[i - 1][2]);
+ float Az = bz.half_area();
+
+ float4 lCount = blocks(count);
+ float4 lArea = make_float4(Ax, Ay, Az, Az);
+ float4 sah = lArea * lCount + r_area[i] * r_count[i];
+
+ bestSplit = select(sah < bestSAH, ii, bestSplit);
+ bestSAH = min(sah, bestSAH);
+ }
+
+ int4 mask = float3_to_float4(cent_bounds_.size()) <= make_float4(0.0f);
+ bestSAH = insert<3>(select(mask, make_float4(FLT_MAX), bestSAH), FLT_MAX);
+
+ /* find best dimension */
+ dim = get_best_dimension(bestSAH);
+ splitSAH = bestSAH[dim];
+ pos = bestSplit[dim];
+ leafSAH = bounds_.half_area() * blocks(size());
+}
+
+void BVHObjectBinning::split(BVHReference *prims,
+ BVHObjectBinning &left_o,
+ BVHObjectBinning &right_o) const
+{
+ size_t N = size();
+
+ BoundBox lgeom_bounds = BoundBox::empty;
+ BoundBox rgeom_bounds = BoundBox::empty;
+ BoundBox lcent_bounds = BoundBox::empty;
+ BoundBox rcent_bounds = BoundBox::empty;
+
+ int64_t l = 0, r = N - 1;
+
+ while (l <= r) {
+ prefetch_L2(&prims[start() + l + 8]);
+ prefetch_L2(&prims[start() + r - 8]);
+
+ BVHReference prim = prims[start() + l];
+ BoundBox unaligned_bounds = get_prim_bounds(prim);
+ float3 unaligned_center = unaligned_bounds.center2();
+ float3 center = prim.bounds().center2();
+
+ if (get_bin(unaligned_center)[dim] < pos) {
+ lgeom_bounds.grow(prim.bounds());
+ lcent_bounds.grow(center);
+ l++;
+ }
+ else {
+ rgeom_bounds.grow(prim.bounds());
+ rcent_bounds.grow(center);
+ swap(prims[start() + l], prims[start() + r]);
+ r--;
+ }
+ }
+ /* finish */
+ if (l != 0 && N - 1 - r != 0) {
+ right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + l, N - 1 - r),
+ prims);
+ left_o = BVHObjectBinning(BVHRange(lgeom_bounds, lcent_bounds, start(), l), prims);
+ return;
+ }
+
+ /* object medium split if we did not make progress, can happen when all
+ * primitives have same centroid */
+ lgeom_bounds = BoundBox::empty;
+ rgeom_bounds = BoundBox::empty;
+ lcent_bounds = BoundBox::empty;
+ rcent_bounds = BoundBox::empty;
+
+ for (size_t i = 0; i < N / 2; i++) {
+ lgeom_bounds.grow(prims[start() + i].bounds());
+ lcent_bounds.grow(prims[start() + i].bounds().center2());
+ }
+
+ for (size_t i = N / 2; i < N; i++) {
+ rgeom_bounds.grow(prims[start() + i].bounds());
+ rcent_bounds.grow(prims[start() + i].bounds().center2());
+ }
+
+ right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + N / 2, N / 2 + N % 2),
+ prims);
+ left_o = BVHObjectBinning(BVHRange(lgeom_bounds, lcent_bounds, start(), N / 2), prims);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/binning.h b/intern/cycles/bvh/binning.h
new file mode 100644
index 00000000000..876500ec540
--- /dev/null
+++ b/intern/cycles/bvh/binning.h
@@ -0,0 +1,115 @@
+/*
+ * Adapted from code copyright 2009-2011 Intel Corporation
+ * Modifications Copyright 2012, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_BINNING_H__
+#define __BVH_BINNING_H__
+
+#include "bvh/params.h"
+#include "bvh/unaligned.h"
+
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BVHBuild;
+
+/* Single threaded object binner. Finds the split with the best SAH heuristic
+ * by testing for each dimension multiple partitionings for regular spaced
+ * partition locations. A partitioning for a partition location is computed,
+ * by putting primitives whose centroid is on the left and right of the split
+ * location to different sets. The SAH is evaluated by computing the number of
+ * blocks occupied by the primitives in the partitions. */
+
+class BVHObjectBinning : public BVHRange {
+ public:
+ __forceinline BVHObjectBinning() : leafSAH(FLT_MAX)
+ {
+ }
+
+ BVHObjectBinning(const BVHRange &job,
+ BVHReference *prims,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
+
+ void split(BVHReference *prims, BVHObjectBinning &left_o, BVHObjectBinning &right_o) const;
+
+ __forceinline const BoundBox &unaligned_bounds()
+ {
+ return bounds_;
+ }
+
+ float splitSAH; /* SAH cost of the best split */
+ float leafSAH; /* SAH cost of creating a leaf */
+
+ protected:
+ int dim; /* best split dimension */
+ int pos; /* best split position */
+ size_t num_bins; /* actual number of bins to use */
+ float3 scale; /* scaling factor to compute bin */
+
+ /* Effective bounds and centroid bounds. */
+ BoundBox bounds_;
+ BoundBox cent_bounds_;
+
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
+
+ enum { MAX_BINS = 32 };
+ enum { LOG_BLOCK_SIZE = 2 };
+
+ /* computes the bin numbers for each dimension for a box. */
+ __forceinline int4 get_bin(const BoundBox &box) const
+ {
+ int4 a = make_int4((box.center2() - cent_bounds_.min) * scale - make_float3(0.5f));
+ int4 mn = make_int4(0);
+ int4 mx = make_int4((int)num_bins - 1);
+
+ return clamp(a, mn, mx);
+ }
+
+ /* computes the bin numbers for each dimension for a point. */
+ __forceinline int4 get_bin(const float3 &c) const
+ {
+ return make_int4((c - cent_bounds_.min) * scale - make_float3(0.5f));
+ }
+
+ /* compute the number of blocks occupied for each dimension. */
+ __forceinline float4 blocks(const int4 &a) const
+ {
+ return make_float4((a + make_int4((1 << LOG_BLOCK_SIZE) - 1)) >> LOG_BLOCK_SIZE);
+ }
+
+ /* compute the number of blocks occupied in one dimension. */
+ __forceinline int blocks(size_t a) const
+ {
+ return (int)((a + ((1LL << LOG_BLOCK_SIZE) - 1)) >> LOG_BLOCK_SIZE);
+ }
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
+ {
+ if (aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(prim, *aligned_space_);
+ }
+ }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_BINNING_H__ */
diff --git a/intern/cycles/bvh/build.cpp b/intern/cycles/bvh/build.cpp
new file mode 100644
index 00000000000..3ce268dfb25
--- /dev/null
+++ b/intern/cycles/bvh/build.cpp
@@ -0,0 +1,1144 @@
+/*
+ * Adapted from code copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bvh/build.h"
+
+#include "bvh/binning.h"
+#include "bvh/node.h"
+#include "bvh/params.h"
+#include "bvh/split.h"
+
+#include "scene/curves.h"
+#include "scene/hair.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+
+#include "util/algorithm.h"
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/progress.h"
+#include "util/queue.h"
+#include "util/simd.h"
+#include "util/stack_allocator.h"
+#include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Constructor / Destructor */
+
+BVHBuild::BVHBuild(const vector<Object *> &objects_,
+ array<int> &prim_type_,
+ array<int> &prim_index_,
+ array<int> &prim_object_,
+ array<float2> &prim_time_,
+ const BVHParams &params_,
+ Progress &progress_)
+ : objects(objects_),
+ prim_type(prim_type_),
+ prim_index(prim_index_),
+ prim_object(prim_object_),
+ prim_time(prim_time_),
+ params(params_),
+ progress(progress_),
+ progress_start_time(0.0),
+ unaligned_heuristic(objects_)
+{
+ spatial_min_overlap = 0.0f;
+}
+
+BVHBuild::~BVHBuild()
+{
+}
+
+/* Adding References */
+
+void BVHBuild::add_reference_triangles(BoundBox &root,
+ BoundBox &center,
+ Mesh *mesh,
+ int object_index)
+{
+ const PrimitiveType primitive_type = mesh->primitive_type();
+ const Attribute *attr_mP = NULL;
+ if (mesh->has_motion_blur()) {
+ attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+ const size_t num_triangles = mesh->num_triangles();
+ for (uint j = 0; j < num_triangles; j++) {
+ Mesh::Triangle t = mesh->get_triangle(j);
+ const float3 *verts = &mesh->verts[0];
+ if (attr_mP == NULL) {
+ BoundBox bounds = BoundBox::empty;
+ t.bounds_grow(verts, bounds);
+ if (bounds.valid() && t.valid(verts)) {
+ references.push_back(BVHReference(bounds, j, object_index, primitive_type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ else if (params.num_motion_triangle_steps == 0 || params.use_spatial_split) {
+ /* Motion triangles, simple case: single node for the whole
+ * primitive. Lowest memory footprint and faster BVH build but
+ * least optimal ray-tracing.
+ */
+ /* TODO(sergey): Support motion steps for spatially split BVH. */
+ const size_t num_verts = mesh->verts.size();
+ const size_t num_steps = mesh->motion_steps;
+ const float3 *vert_steps = attr_mP->data_float3();
+ BoundBox bounds = BoundBox::empty;
+ t.bounds_grow(verts, bounds);
+ for (size_t step = 0; step < num_steps - 1; step++) {
+ t.bounds_grow(vert_steps + step * num_verts, bounds);
+ }
+ if (bounds.valid()) {
+ references.push_back(BVHReference(bounds, j, object_index, primitive_type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ else {
+ /* Motion triangles, trace optimized case: we split triangle
+ * primitives into separate nodes for each of the time steps.
+ * This way we minimize overlap of neighbor curve primitives.
+ */
+ const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
+ const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
+ const size_t num_verts = mesh->verts.size();
+ const size_t num_steps = mesh->motion_steps;
+ const float3 *vert_steps = attr_mP->data_float3();
+ /* Calculate bounding box of the previous time step.
+ * Will be reused later to avoid duplicated work on
+ * calculating BVH time step boundbox.
+ */
+ float3 prev_verts[3];
+ t.motion_verts(verts, vert_steps, num_verts, num_steps, 0.0f, prev_verts);
+ BoundBox prev_bounds = BoundBox::empty;
+ prev_bounds.grow(prev_verts[0]);
+ prev_bounds.grow(prev_verts[1]);
+ prev_bounds.grow(prev_verts[2]);
+ /* Create all primitive time steps, */
+ for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
+ const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
+ float3 curr_verts[3];
+ t.motion_verts(verts, vert_steps, num_verts, num_steps, curr_time, curr_verts);
+ BoundBox curr_bounds = BoundBox::empty;
+ curr_bounds.grow(curr_verts[0]);
+ curr_bounds.grow(curr_verts[1]);
+ curr_bounds.grow(curr_verts[2]);
+ BoundBox bounds = prev_bounds;
+ bounds.grow(curr_bounds);
+ if (bounds.valid()) {
+ const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
+ references.push_back(
+ BVHReference(bounds, j, object_index, primitive_type, prev_time, curr_time));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ /* Current time boundbox becomes previous one for the
+ * next time step.
+ */
+ prev_bounds = curr_bounds;
+ }
+ }
+ }
+}
+
+void BVHBuild::add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair, int object_index)
+{
+ const Attribute *curve_attr_mP = NULL;
+ if (hair->has_motion_blur()) {
+ curve_attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+
+ const PrimitiveType primitive_type = hair->primitive_type();
+
+ const size_t num_curves = hair->num_curves();
+ for (uint j = 0; j < num_curves; j++) {
+ const Hair::Curve curve = hair->get_curve(j);
+ const float *curve_radius = &hair->get_curve_radius()[0];
+ for (int k = 0; k < curve.num_keys - 1; k++) {
+ if (curve_attr_mP == NULL) {
+ /* Really simple logic for static hair. */
+ BoundBox bounds = BoundBox::empty;
+ curve.bounds_grow(k, &hair->get_curve_keys()[0], curve_radius, bounds);
+ if (bounds.valid()) {
+ int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
+ references.push_back(BVHReference(bounds, j, object_index, packed_type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ else if (params.num_motion_curve_steps == 0 || params.use_spatial_split) {
+ /* Simple case of motion curves: single node for the while
+ * shutter time. Lowest memory usage but less optimal
+ * rendering.
+ */
+ /* TODO(sergey): Support motion steps for spatially split BVH. */
+ BoundBox bounds = BoundBox::empty;
+ curve.bounds_grow(k, &hair->get_curve_keys()[0], curve_radius, bounds);
+ const size_t num_keys = hair->get_curve_keys().size();
+ const size_t num_steps = hair->get_motion_steps();
+ const float3 *key_steps = curve_attr_mP->data_float3();
+ for (size_t step = 0; step < num_steps - 1; step++) {
+ curve.bounds_grow(k, key_steps + step * num_keys, curve_radius, bounds);
+ }
+ if (bounds.valid()) {
+ int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
+ references.push_back(BVHReference(bounds, j, object_index, packed_type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ else {
+ /* Motion curves, trace optimized case: we split curve keys
+ * primitives into separate nodes for each of the time steps.
+ * This way we minimize overlap of neighbor curve primitives.
+ */
+ const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
+ const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
+ const size_t num_steps = hair->get_motion_steps();
+ const float3 *curve_keys = &hair->get_curve_keys()[0];
+ const float3 *key_steps = curve_attr_mP->data_float3();
+ const size_t num_keys = hair->get_curve_keys().size();
+ /* Calculate bounding box of the previous time step.
+ * Will be reused later to avoid duplicated work on
+ * calculating BVH time step boundbox.
+ */
+ float4 prev_keys[4];
+ curve.cardinal_motion_keys(curve_keys,
+ curve_radius,
+ key_steps,
+ num_keys,
+ num_steps,
+ 0.0f,
+ k - 1,
+ k,
+ k + 1,
+ k + 2,
+ prev_keys);
+ BoundBox prev_bounds = BoundBox::empty;
+ curve.bounds_grow(prev_keys, prev_bounds);
+ /* Create all primitive time steps, */
+ for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
+ const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
+ float4 curr_keys[4];
+ curve.cardinal_motion_keys(curve_keys,
+ curve_radius,
+ key_steps,
+ num_keys,
+ num_steps,
+ curr_time,
+ k - 1,
+ k,
+ k + 1,
+ k + 2,
+ curr_keys);
+ BoundBox curr_bounds = BoundBox::empty;
+ curve.bounds_grow(curr_keys, curr_bounds);
+ BoundBox bounds = prev_bounds;
+ bounds.grow(curr_bounds);
+ if (bounds.valid()) {
+ const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
+ int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
+ references.push_back(
+ BVHReference(bounds, j, object_index, packed_type, prev_time, curr_time));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ /* Current time boundbox becomes previous one for the
+ * next time step.
+ */
+ prev_bounds = curr_bounds;
+ }
+ }
+ }
+ }
+}
+
+void BVHBuild::add_reference_geometry(BoundBox &root,
+ BoundBox &center,
+ Geometry *geom,
+ int object_index)
+{
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ add_reference_triangles(root, center, mesh, object_index);
+ }
+ else if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ add_reference_curves(root, center, hair, object_index);
+ }
+}
+
+void BVHBuild::add_reference_object(BoundBox &root, BoundBox &center, Object *ob, int i)
+{
+ references.push_back(BVHReference(ob->bounds, -1, i, 0));
+ root.grow(ob->bounds);
+ center.grow(ob->bounds.center2());
+}
+
+static size_t count_curve_segments(Hair *hair)
+{
+ size_t num = 0, num_curves = hair->num_curves();
+
+ for (size_t i = 0; i < num_curves; i++)
+ num += hair->get_curve(i).num_keys - 1;
+
+ return num;
+}
+
+static size_t count_primitives(Geometry *geom)
+{
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ return mesh->num_triangles();
+ }
+ else if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ return count_curve_segments(hair);
+ }
+
+ return 0;
+}
+
+void BVHBuild::add_references(BVHRange &root)
+{
+ /* reserve space for references */
+ size_t num_alloc_references = 0;
+
+ foreach (Object *ob, objects) {
+ if (params.top_level) {
+ if (!ob->is_traceable()) {
+ continue;
+ }
+ if (!ob->get_geometry()->is_instanced()) {
+ num_alloc_references += count_primitives(ob->get_geometry());
+ }
+ else
+ num_alloc_references++;
+ }
+ else {
+ num_alloc_references += count_primitives(ob->get_geometry());
+ }
+ }
+
+ references.reserve(num_alloc_references);
+
+ /* add references from objects */
+ BoundBox bounds = BoundBox::empty, center = BoundBox::empty;
+ int i = 0;
+
+ foreach (Object *ob, objects) {
+ if (params.top_level) {
+ if (!ob->is_traceable()) {
+ ++i;
+ continue;
+ }
+ if (!ob->get_geometry()->is_instanced())
+ add_reference_geometry(bounds, center, ob->get_geometry(), i);
+ else
+ add_reference_object(bounds, center, ob, i);
+ }
+ else
+ add_reference_geometry(bounds, center, ob->get_geometry(), i);
+
+ i++;
+
+ if (progress.get_cancel())
+ return;
+ }
+
+ /* happens mostly on empty meshes */
+ if (!bounds.valid())
+ bounds.grow(zero_float3());
+
+ root = BVHRange(bounds, center, 0, references.size());
+}
+
+/* Build */
+
+BVHNode *BVHBuild::run()
+{
+ BVHRange root;
+
+ /* add references */
+ add_references(root);
+
+ if (progress.get_cancel())
+ return NULL;
+
+ /* init spatial splits */
+ if (params.top_level) {
+ /* NOTE: Technically it is supported by the builder but it's not really
+ * optimized for speed yet and not really clear yet if it has measurable
+ * improvement on render time. Needs some extra investigation before
+ * enabling spatial split for top level BVH.
+ */
+ params.use_spatial_split = false;
+ }
+
+ spatial_min_overlap = root.bounds().safe_area() * params.spatial_split_alpha;
+ spatial_free_index = 0;
+
+ need_prim_time = params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0;
+
+ /* init progress updates */
+ double build_start_time;
+ build_start_time = progress_start_time = time_dt();
+ progress_count = 0;
+ progress_total = references.size();
+ progress_original_total = progress_total;
+
+ prim_type.resize(references.size());
+ prim_index.resize(references.size());
+ prim_object.resize(references.size());
+ if (need_prim_time) {
+ prim_time.resize(references.size());
+ }
+ else {
+ prim_time.resize(0);
+ }
+
+ /* build recursively */
+ BVHNode *rootnode;
+
+ if (params.use_spatial_split) {
+ /* Perform multithreaded spatial split build. */
+ BVHSpatialStorage *local_storage = &spatial_storage.local();
+ rootnode = build_node(root, references, 0, local_storage);
+ task_pool.wait_work();
+ }
+ else {
+ /* Perform multithreaded binning build. */
+ BVHObjectBinning rootbin(root, (references.size()) ? &references[0] : NULL);
+ rootnode = build_node(rootbin, 0);
+ task_pool.wait_work();
+ }
+
+ /* clean up temporary memory usage by threads */
+ spatial_storage.clear();
+
+ /* delete if we canceled */
+ if (rootnode) {
+ if (progress.get_cancel()) {
+ rootnode->deleteSubtree();
+ rootnode = NULL;
+ VLOG(1) << "BVH build cancelled.";
+ }
+ else {
+ /*rotate(rootnode, 4, 5);*/
+ rootnode->update_visibility();
+ rootnode->update_time();
+ }
+ if (rootnode != NULL) {
+ VLOG(1) << "BVH build statistics:\n"
+ << " Build time: " << time_dt() - build_start_time << "\n"
+ << " Total number of nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT))
+ << "\n"
+ << " Number of inner nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT))
+ << "\n"
+ << " Number of leaf nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT))
+ << "\n"
+ << " Number of unaligned nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT))
+ << "\n"
+ << " Allocation slop factor: "
+ << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() :
+ 1.0f)
+ << "\n"
+ << " Maximum depth: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_DEPTH)) << "\n";
+ }
+ }
+
+ return rootnode;
+}
+
+void BVHBuild::progress_update()
+{
+ if (time_dt() - progress_start_time < 0.25)
+ return;
+
+ double progress_start = (double)progress_count / (double)progress_total;
+ double duplicates = (double)(progress_total - progress_original_total) / (double)progress_total;
+
+ string msg = string_printf(
+ "Building BVH %.0f%%, duplicates %.0f%%", progress_start * 100.0, duplicates * 100.0);
+
+ progress.set_substatus(msg);
+ progress_start_time = time_dt();
+}
+
+void BVHBuild::thread_build_node(InnerNode *inner,
+ int child,
+ const BVHObjectBinning &range,
+ int level)
+{
+ if (progress.get_cancel())
+ return;
+
+ /* build nodes */
+ BVHNode *node = build_node(range, level);
+
+ /* set child in inner node */
+ inner->children[child] = node;
+
+ /* update progress */
+ if (range.size() < THREAD_TASK_SIZE) {
+ /*rotate(node, INT_MAX, 5);*/
+
+ thread_scoped_lock lock(build_mutex);
+
+ progress_count += range.size();
+ progress_update();
+ }
+}
+
+void BVHBuild::thread_build_spatial_split_node(InnerNode *inner,
+ int child,
+ const BVHRange &range,
+ vector<BVHReference> &references,
+ int level)
+{
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ /* Get per-thread memory for spatial split. */
+ BVHSpatialStorage *local_storage = &spatial_storage.local();
+
+ /* build nodes */
+ BVHNode *node = build_node(range, references, level, local_storage);
+
+ /* set child in inner node */
+ inner->children[child] = node;
+}
+
+bool BVHBuild::range_within_max_leaf_size(const BVHRange &range,
+ const vector<BVHReference> &references) const
+{
+ size_t size = range.size();
+ size_t max_leaf_size = max(params.max_triangle_leaf_size, params.max_curve_leaf_size);
+
+ if (size > max_leaf_size)
+ return false;
+
+ size_t num_triangles = 0;
+ size_t num_motion_triangles = 0;
+ size_t num_curves = 0;
+ size_t num_motion_curves = 0;
+
+ for (int i = 0; i < size; i++) {
+ const BVHReference &ref = references[range.start() + i];
+
+ if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
+ if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
+ num_motion_curves++;
+ }
+ else {
+ num_curves++;
+ }
+ }
+ else if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
+ if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
+ num_motion_triangles++;
+ }
+ else {
+ num_triangles++;
+ }
+ }
+ }
+
+ return (num_triangles <= params.max_triangle_leaf_size) &&
+ (num_motion_triangles <= params.max_motion_triangle_leaf_size) &&
+ (num_curves <= params.max_curve_leaf_size) &&
+ (num_motion_curves <= params.max_motion_curve_leaf_size);
+}
+
+/* multithreaded binning builder */
+BVHNode *BVHBuild::build_node(const BVHObjectBinning &range, int level)
+{
+ size_t size = range.size();
+ float leafSAH = params.sah_primitive_cost * range.leafSAH;
+ float splitSAH = params.sah_node_cost * range.bounds().half_area() +
+ params.sah_primitive_cost * range.splitSAH;
+
+ /* Have at least one inner node on top level, for performance and correct
+ * visibility tests, since object instances do not check visibility flag.
+ */
+ if (!(range.size() > 0 && params.top_level && level == 0)) {
+ /* Make leaf node when threshold reached or SAH tells us. */
+ if ((params.small_enough_for_leaf(size, level)) ||
+ (range_within_max_leaf_size(range, references) && leafSAH < splitSAH)) {
+ return create_leaf_node(range, references);
+ }
+ }
+
+ BVHObjectBinning unaligned_range;
+ float unalignedSplitSAH = FLT_MAX;
+ float unalignedLeafSAH = FLT_MAX;
+ Transform aligned_space;
+ bool do_unalinged_split = false;
+ if (params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold * leafSAH) {
+ aligned_space = unaligned_heuristic.compute_aligned_space(range, &references[0]);
+ unaligned_range = BVHObjectBinning(
+ range, &references[0], &unaligned_heuristic, &aligned_space);
+ unalignedSplitSAH = params.sah_node_cost * unaligned_range.unaligned_bounds().half_area() +
+ params.sah_primitive_cost * unaligned_range.splitSAH;
+ unalignedLeafSAH = params.sah_primitive_cost * unaligned_range.leafSAH;
+ if (!(range.size() > 0 && params.top_level && level == 0)) {
+ if (unalignedLeafSAH < unalignedSplitSAH && unalignedSplitSAH < splitSAH &&
+ range_within_max_leaf_size(range, references)) {
+ return create_leaf_node(range, references);
+ }
+ }
+ /* Check whether unaligned split is better than the regular one. */
+ if (unalignedSplitSAH < splitSAH) {
+ do_unalinged_split = true;
+ }
+ }
+
+ /* Perform split. */
+ BVHObjectBinning left, right;
+ if (do_unalinged_split) {
+ unaligned_range.split(&references[0], left, right);
+ }
+ else {
+ range.split(&references[0], left, right);
+ }
+
+ BoundBox bounds;
+ if (do_unalinged_split) {
+ bounds = unaligned_heuristic.compute_aligned_boundbox(range, &references[0], aligned_space);
+ }
+ else {
+ bounds = range.bounds();
+ }
+
+ /* Create inner node. */
+ InnerNode *inner;
+ if (range.size() < THREAD_TASK_SIZE) {
+ /* local build */
+ BVHNode *leftnode = build_node(left, level + 1);
+ BVHNode *rightnode = build_node(right, level + 1);
+
+ inner = new InnerNode(bounds, leftnode, rightnode);
+ }
+ else {
+ /* Threaded build */
+ inner = new InnerNode(bounds);
+
+ task_pool.push([=] { thread_build_node(inner, 0, left, level + 1); });
+ task_pool.push([=] { thread_build_node(inner, 1, right, level + 1); });
+ }
+
+ if (do_unalinged_split) {
+ inner->set_aligned_space(aligned_space);
+ }
+
+ return inner;
+}
+
+/* multithreaded spatial split builder */
+BVHNode *BVHBuild::build_node(const BVHRange &range,
+ vector<BVHReference> &references,
+ int level,
+ BVHSpatialStorage *storage)
+{
+ /* Update progress.
+ *
+ * TODO(sergey): Currently it matches old behavior, but we can move it to the
+ * task thread (which will mimic non=split builder) and save some CPU ticks
+ * on checking cancel status.
+ */
+ progress_update();
+ if (progress.get_cancel()) {
+ return NULL;
+ }
+
+ /* Small enough or too deep => create leaf. */
+ if (!(range.size() > 0 && params.top_level && level == 0)) {
+ if (params.small_enough_for_leaf(range.size(), level)) {
+ progress_count += range.size();
+ return create_leaf_node(range, references);
+ }
+ }
+
+ /* Perform splitting test. */
+ BVHMixedSplit split(this, storage, range, references, level);
+
+ if (!(range.size() > 0 && params.top_level && level == 0)) {
+ if (split.no_split) {
+ progress_count += range.size();
+ return create_leaf_node(range, references);
+ }
+ }
+ float leafSAH = params.sah_primitive_cost * split.leafSAH;
+ float splitSAH = params.sah_node_cost * range.bounds().half_area() +
+ params.sah_primitive_cost * split.nodeSAH;
+
+ BVHMixedSplit unaligned_split;
+ float unalignedSplitSAH = FLT_MAX;
+ /* float unalignedLeafSAH = FLT_MAX; */
+ Transform aligned_space;
+ bool do_unalinged_split = false;
+ if (params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold * leafSAH) {
+ aligned_space = unaligned_heuristic.compute_aligned_space(range, &references.at(0));
+ unaligned_split = BVHMixedSplit(
+ this, storage, range, references, level, &unaligned_heuristic, &aligned_space);
+ /* unalignedLeafSAH = params.sah_primitive_cost * split.leafSAH; */
+ unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() +
+ params.sah_primitive_cost * unaligned_split.nodeSAH;
+ /* TOOD(sergey): Check we can create leaf already. */
+ /* Check whether unaligned split is better than the regular one. */
+ if (unalignedSplitSAH < splitSAH) {
+ do_unalinged_split = true;
+ }
+ }
+
+ /* Do split. */
+ BVHRange left, right;
+ if (do_unalinged_split) {
+ unaligned_split.split(this, left, right, range);
+ }
+ else {
+ split.split(this, left, right, range);
+ }
+
+ progress_total += left.size() + right.size() - range.size();
+
+ BoundBox bounds;
+ if (do_unalinged_split) {
+ bounds = unaligned_heuristic.compute_aligned_boundbox(range, &references.at(0), aligned_space);
+ }
+ else {
+ bounds = range.bounds();
+ }
+
+ /* Create inner node. */
+ InnerNode *inner;
+ if (range.size() < THREAD_TASK_SIZE) {
+ /* Local build. */
+
+ /* Build left node. */
+ vector<BVHReference> right_references(references.begin() + right.start(),
+ references.begin() + right.end());
+ right.set_start(0);
+
+ BVHNode *leftnode = build_node(left, references, level + 1, storage);
+
+ /* Build right node. */
+ BVHNode *rightnode = build_node(right, right_references, level + 1, storage);
+
+ inner = new InnerNode(bounds, leftnode, rightnode);
+ }
+ else {
+ /* Threaded build. */
+ inner = new InnerNode(bounds);
+
+ vector<BVHReference> left_references(references.begin() + left.start(),
+ references.begin() + left.end());
+ vector<BVHReference> right_references(references.begin() + right.start(),
+ references.begin() + right.end());
+ right.set_start(0);
+
+ /* Create tasks for left and right nodes, using copy for most arguments and
+ * move for reference to avoid memory copies. */
+ task_pool.push([=, refs = std::move(left_references)]() mutable {
+ thread_build_spatial_split_node(inner, 0, left, refs, level + 1);
+ });
+ task_pool.push([=, refs = std::move(right_references)]() mutable {
+ thread_build_spatial_split_node(inner, 1, right, refs, level + 1);
+ });
+ }
+
+ if (do_unalinged_split) {
+ inner->set_aligned_space(aligned_space);
+ }
+
+ return inner;
+}
+
+/* Create Nodes */
+
+BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, int num)
+{
+ if (num == 0) {
+ BoundBox bounds = BoundBox::empty;
+ return new LeafNode(bounds, 0, 0, 0);
+ }
+ else if (num == 1) {
+ assert(start < prim_type.size());
+ prim_type[start] = ref->prim_type();
+ prim_index[start] = ref->prim_index();
+ prim_object[start] = ref->prim_object();
+ if (need_prim_time) {
+ prim_time[start] = make_float2(ref->time_from(), ref->time_to());
+ }
+
+ const uint visibility = objects[ref->prim_object()]->visibility_for_tracing();
+ BVHNode *leaf_node = new LeafNode(ref->bounds(), visibility, start, start + 1);
+ leaf_node->time_from = ref->time_from();
+ leaf_node->time_to = ref->time_to();
+ return leaf_node;
+ }
+ else {
+ int mid = num / 2;
+ BVHNode *leaf0 = create_object_leaf_nodes(ref, start, mid);
+ BVHNode *leaf1 = create_object_leaf_nodes(ref + mid, start + mid, num - mid);
+
+ BoundBox bounds = BoundBox::empty;
+ bounds.grow(leaf0->bounds);
+ bounds.grow(leaf1->bounds);
+
+ BVHNode *inner_node = new InnerNode(bounds, leaf0, leaf1);
+ inner_node->time_from = min(leaf0->time_from, leaf1->time_from);
+ inner_node->time_to = max(leaf0->time_to, leaf1->time_to);
+ return inner_node;
+ }
+}
+
+BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHReference> &references)
+{
+ /* This is a bit overallocating here (considering leaf size into account),
+ * but chunk-based re-allocation in vector makes it difficult to use small
+ * size of stack storage here. Some tweaks are possible tho.
+ *
+ * NOTES:
+ * - If the size is too big, we'll have inefficient stack usage,
+ * and lots of cache misses.
+ * - If the size is too small, then we can run out of memory
+ * allowed to be used by vector.
+ * In practice it wouldn't mean crash, just allocator will fallback
+ * to heap which is slower.
+ * - Optimistic re-allocation in STL could jump us out of stack usage
+ * because re-allocation happens in chunks and size of those chunks we
+ * can not control.
+ */
+ typedef StackAllocator<256, int> LeafStackAllocator;
+ typedef StackAllocator<256, float2> LeafTimeStackAllocator;
+ typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator;
+
+ vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM];
+ vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM];
+ vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM];
+ vector<float2, LeafTimeStackAllocator> p_time[PRIMITIVE_NUM];
+ vector<BVHReference, LeafReferenceStackAllocator> p_ref[PRIMITIVE_NUM];
+
+ /* TODO(sergey): In theory we should be able to store references. */
+ vector<BVHReference, LeafReferenceStackAllocator> object_references;
+
+ uint visibility[PRIMITIVE_NUM] = {0};
+ /* NOTE: Keep initialization in sync with actual number of primitives. */
+ BoundBox bounds[PRIMITIVE_NUM] = {
+ BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty};
+ int ob_num = 0;
+ int num_new_prims = 0;
+ /* Fill in per-type type/index array. */
+ for (int i = 0; i < range.size(); i++) {
+ const BVHReference &ref = references[range.start() + i];
+ if (ref.prim_index() != -1) {
+ uint32_t type_index = bitscan((uint32_t)(ref.prim_type() & PRIMITIVE_ALL));
+ p_ref[type_index].push_back(ref);
+ p_type[type_index].push_back(ref.prim_type());
+ p_index[type_index].push_back(ref.prim_index());
+ p_object[type_index].push_back(ref.prim_object());
+ p_time[type_index].push_back(make_float2(ref.time_from(), ref.time_to()));
+
+ bounds[type_index].grow(ref.bounds());
+ visibility[type_index] |= objects[ref.prim_object()]->visibility_for_tracing();
+ ++num_new_prims;
+ }
+ else {
+ object_references.push_back(ref);
+ ++ob_num;
+ }
+ }
+
+ /* Create leaf nodes for every existing primitive.
+ *
+ * Here we write primitive types, indices and objects to a temporary array.
+ * This way we keep all the heavy memory allocation code outside of the
+ * thread lock in the case of spatial split building.
+ *
+ * TODO(sergey): With some pointer trickery we can write directly to the
+ * destination buffers for the non-spatial split BVH.
+ */
+ BVHNode *leaves[PRIMITIVE_NUM + 1] = {NULL};
+ int num_leaves = 0;
+ size_t start_index = 0;
+ vector<int, LeafStackAllocator> local_prim_type, local_prim_index, local_prim_object;
+ vector<float2, LeafTimeStackAllocator> local_prim_time;
+ local_prim_type.resize(num_new_prims);
+ local_prim_index.resize(num_new_prims);
+ local_prim_object.resize(num_new_prims);
+ if (need_prim_time) {
+ local_prim_time.resize(num_new_prims);
+ }
+ for (int i = 0; i < PRIMITIVE_NUM; ++i) {
+ int num = (int)p_type[i].size();
+ if (num != 0) {
+ assert(p_type[i].size() == p_index[i].size());
+ assert(p_type[i].size() == p_object[i].size());
+ Transform aligned_space;
+ bool alignment_found = false;
+ for (int j = 0; j < num; ++j) {
+ const int index = start_index + j;
+ local_prim_type[index] = p_type[i][j];
+ local_prim_index[index] = p_index[i][j];
+ local_prim_object[index] = p_object[i][j];
+ if (need_prim_time) {
+ local_prim_time[index] = p_time[i][j];
+ }
+ if (params.use_unaligned_nodes && !alignment_found) {
+ alignment_found = unaligned_heuristic.compute_aligned_space(p_ref[i][j], &aligned_space);
+ }
+ }
+ LeafNode *leaf_node = new LeafNode(bounds[i], visibility[i], start_index, start_index + num);
+ if (true) {
+ float time_from = 1.0f, time_to = 0.0f;
+ for (int j = 0; j < num; ++j) {
+ const BVHReference &ref = p_ref[i][j];
+ time_from = min(time_from, ref.time_from());
+ time_to = max(time_to, ref.time_to());
+ }
+ leaf_node->time_from = time_from;
+ leaf_node->time_to = time_to;
+ }
+ if (alignment_found) {
+ /* Need to recalculate leaf bounds with new alignment. */
+ leaf_node->bounds = BoundBox::empty;
+ for (int j = 0; j < num; ++j) {
+ const BVHReference &ref = p_ref[i][j];
+ BoundBox ref_bounds = unaligned_heuristic.compute_aligned_prim_boundbox(ref,
+ aligned_space);
+ leaf_node->bounds.grow(ref_bounds);
+ }
+ /* Set alignment space. */
+ leaf_node->set_aligned_space(aligned_space);
+ }
+ leaves[num_leaves++] = leaf_node;
+ start_index += num;
+ }
+ }
+ /* Get size of new data to be copied to the packed arrays. */
+ const int num_new_leaf_data = start_index;
+ const size_t new_leaf_data_size = sizeof(int) * num_new_leaf_data;
+ /* Copy actual data to the packed array. */
+ if (params.use_spatial_split) {
+ spatial_spin_lock.lock();
+ /* We use first free index in the packed arrays and mode pointer to the
+ * end of the current range.
+ *
+ * This doesn't give deterministic packed arrays, but it shouldn't really
+ * matter because order of children in BVH is deterministic.
+ */
+ start_index = spatial_free_index;
+ spatial_free_index += range.size();
+ /* Extend an array when needed. */
+ const size_t range_end = start_index + range.size();
+ if (prim_type.size() < range_end) {
+ /* Avoid extra re-allocations by pre-allocating bigger array in an
+ * advance.
+ */
+ if (range_end >= prim_type.capacity()) {
+ float progress = (float)progress_count / (float)progress_total;
+ float factor = (1.0f - progress);
+ const size_t reserve = (size_t)(range_end + (float)range_end * factor);
+ prim_type.reserve(reserve);
+ prim_index.reserve(reserve);
+ prim_object.reserve(reserve);
+ if (need_prim_time) {
+ prim_time.reserve(reserve);
+ }
+ }
+
+ prim_type.resize(range_end);
+ prim_index.resize(range_end);
+ prim_object.resize(range_end);
+ if (need_prim_time) {
+ prim_time.resize(range_end);
+ }
+ }
+ /* Perform actual data copy. */
+ if (new_leaf_data_size > 0) {
+ memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
+ memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
+ memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
+ if (need_prim_time) {
+ memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2) * num_new_leaf_data);
+ }
+ }
+ spatial_spin_lock.unlock();
+ }
+ else {
+ /* For the regular BVH builder we simply copy new data starting at the
+ * range start. This is totally thread-safe, all threads are living
+ * inside of their own range.
+ */
+ start_index = range.start();
+ if (new_leaf_data_size > 0) {
+ memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
+ memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
+ memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
+ if (need_prim_time) {
+ memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2) * num_new_leaf_data);
+ }
+ }
+ }
+
+ /* So far leaves were created with the zero-based index in an arrays,
+ * here we modify the indices to correspond to actual packed array start
+ * index.
+ */
+ for (int i = 0; i < num_leaves; ++i) {
+ LeafNode *leaf = (LeafNode *)leaves[i];
+ leaf->lo += start_index;
+ leaf->hi += start_index;
+ }
+
+ /* Create leaf node for object. */
+ if (num_leaves == 0 || ob_num) {
+ /* Only create object leaf nodes if there are objects or no other
+ * nodes created.
+ */
+ const BVHReference *ref = (ob_num) ? &object_references[0] : NULL;
+ leaves[num_leaves] = create_object_leaf_nodes(ref, start_index + num_new_leaf_data, ob_num);
+ ++num_leaves;
+ }
+
+ /* TODO(sergey): Need to take care of alignment when number of leaves
+ * is more than 1.
+ */
+ if (num_leaves == 1) {
+ /* Simplest case: single leaf, just return it.
+ * In all the rest cases we'll be creating intermediate inner node with
+ * an appropriate bounding box.
+ */
+ return leaves[0];
+ }
+ else if (num_leaves == 2) {
+ return new InnerNode(range.bounds(), leaves[0], leaves[1]);
+ }
+ else if (num_leaves == 3) {
+ BoundBox inner_bounds = merge(leaves[1]->bounds, leaves[2]->bounds);
+ BVHNode *inner = new InnerNode(inner_bounds, leaves[1], leaves[2]);
+ return new InnerNode(range.bounds(), leaves[0], inner);
+ }
+ else {
+ /* Should be doing more branches if more primitive types added. */
+ assert(num_leaves <= 5);
+ BoundBox inner_bounds_a = merge(leaves[0]->bounds, leaves[1]->bounds);
+ BoundBox inner_bounds_b = merge(leaves[2]->bounds, leaves[3]->bounds);
+ BVHNode *inner_a = new InnerNode(inner_bounds_a, leaves[0], leaves[1]);
+ BVHNode *inner_b = new InnerNode(inner_bounds_b, leaves[2], leaves[3]);
+ BoundBox inner_bounds_c = merge(inner_a->bounds, inner_b->bounds);
+ BVHNode *inner_c = new InnerNode(inner_bounds_c, inner_a, inner_b);
+ if (num_leaves == 5) {
+ return new InnerNode(range.bounds(), inner_c, leaves[4]);
+ }
+ return inner_c;
+ }
+
+#undef MAX_ITEMS_PER_LEAF
+}
+
+/* Tree Rotations */
+
+void BVHBuild::rotate(BVHNode *node, int max_depth, int iterations)
+{
+ /* in tested scenes, this resulted in slightly slower raytracing, so disabled
+ * it for now. could be implementation bug, or depend on the scene */
+ if (node)
+ for (int i = 0; i < iterations; i++)
+ rotate(node, max_depth);
+}
+
+void BVHBuild::rotate(BVHNode *node, int max_depth)
+{
+ /* nothing to rotate if we reached a leaf node. */
+ if (node->is_leaf() || max_depth < 0)
+ return;
+
+ InnerNode *parent = (InnerNode *)node;
+
+ /* rotate all children first */
+ for (size_t c = 0; c < 2; c++)
+ rotate(parent->children[c], max_depth - 1);
+
+ /* compute current area of all children */
+ BoundBox bounds0 = parent->children[0]->bounds;
+ BoundBox bounds1 = parent->children[1]->bounds;
+
+ float area0 = bounds0.half_area();
+ float area1 = bounds1.half_area();
+ float4 child_area = make_float4(area0, area1, 0.0f, 0.0f);
+
+ /* find best rotation. we pick a target child of a first child, and swap
+ * this with an other child. we perform the best such swap. */
+ float best_cost = FLT_MAX;
+ int best_child = -1, best_target = -1, best_other = -1;
+
+ for (size_t c = 0; c < 2; c++) {
+ /* ignore leaf nodes as we cannot descent into */
+ if (parent->children[c]->is_leaf())
+ continue;
+
+ InnerNode *child = (InnerNode *)parent->children[c];
+ BoundBox &other = (c == 0) ? bounds1 : bounds0;
+
+ /* transpose child bounds */
+ BoundBox target0 = child->children[0]->bounds;
+ BoundBox target1 = child->children[1]->bounds;
+
+ /* compute cost for both possible swaps */
+ float cost0 = merge(other, target1).half_area() - child_area[c];
+ float cost1 = merge(target0, other).half_area() - child_area[c];
+
+ if (min(cost0, cost1) < best_cost) {
+ best_child = (int)c;
+ best_other = (int)(1 - c);
+
+ if (cost0 < cost1) {
+ best_cost = cost0;
+ best_target = 0;
+ }
+ else {
+ best_cost = cost0;
+ best_target = 1;
+ }
+ }
+ }
+
+ /* if we did not find a swap that improves the SAH then do nothing */
+ if (best_cost >= 0)
+ return;
+
+ assert(best_child == 0 || best_child == 1);
+ assert(best_target != -1);
+
+ /* perform the best found tree rotation */
+ InnerNode *child = (InnerNode *)parent->children[best_child];
+
+ swap(parent->children[best_other], child->children[best_target]);
+ child->bounds = merge(child->children[0]->bounds, child->children[1]->bounds);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/build.h b/intern/cycles/bvh/build.h
new file mode 100644
index 00000000000..06b318f1ee0
--- /dev/null
+++ b/intern/cycles/bvh/build.h
@@ -0,0 +1,142 @@
+/*
+ * Adapted from code copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_BUILD_H__
+#define __BVH_BUILD_H__
+
+#include <float.h>
+
+#include "bvh/params.h"
+#include "bvh/unaligned.h"
+
+#include "util/array.h"
+#include "util/task.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Boundbox;
+class BVHBuildTask;
+class BVHNode;
+class BVHSpatialSplitBuildTask;
+class BVHParams;
+class InnerNode;
+class Geometry;
+class Hair;
+class Mesh;
+class Object;
+class Progress;
+
+/* BVH Builder */
+
+class BVHBuild {
+ public:
+ /* Constructor/Destructor */
+ BVHBuild(const vector<Object *> &objects,
+ array<int> &prim_type,
+ array<int> &prim_index,
+ array<int> &prim_object,
+ array<float2> &prim_time,
+ const BVHParams &params,
+ Progress &progress);
+ ~BVHBuild();
+
+ BVHNode *run();
+
+ protected:
+ friend class BVHMixedSplit;
+ friend class BVHObjectSplit;
+ friend class BVHSpatialSplit;
+ friend class BVHBuildTask;
+ friend class BVHSpatialSplitBuildTask;
+ friend class BVHObjectBinning;
+
+ /* Adding references. */
+ void add_reference_triangles(BoundBox &root, BoundBox &center, Mesh *mesh, int i);
+ void add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair, int i);
+ void add_reference_geometry(BoundBox &root, BoundBox &center, Geometry *geom, int i);
+ void add_reference_object(BoundBox &root, BoundBox &center, Object *ob, int i);
+ void add_references(BVHRange &root);
+
+ /* Building. */
+ BVHNode *build_node(const BVHRange &range,
+ vector<BVHReference> &references,
+ int level,
+ BVHSpatialStorage *storage);
+ BVHNode *build_node(const BVHObjectBinning &range, int level);
+ BVHNode *create_leaf_node(const BVHRange &range, const vector<BVHReference> &references);
+ BVHNode *create_object_leaf_nodes(const BVHReference *ref, int start, int num);
+
+ bool range_within_max_leaf_size(const BVHRange &range,
+ const vector<BVHReference> &references) const;
+
+ /* Threads. */
+ enum { THREAD_TASK_SIZE = 4096 };
+ void thread_build_node(InnerNode *node, int child, const BVHObjectBinning &range, int level);
+ void thread_build_spatial_split_node(InnerNode *node,
+ int child,
+ const BVHRange &range,
+ vector<BVHReference> &references,
+ int level);
+ thread_mutex build_mutex;
+
+ /* Progress. */
+ void progress_update();
+
+ /* Tree rotations. */
+ void rotate(BVHNode *node, int max_depth);
+ void rotate(BVHNode *node, int max_depth, int iterations);
+
+ /* Objects and primitive references. */
+ vector<Object *> objects;
+ vector<BVHReference> references;
+ int num_original_references;
+
+ /* Output primitive indexes and objects. */
+ array<int> &prim_type;
+ array<int> &prim_index;
+ array<int> &prim_object;
+ array<float2> &prim_time;
+
+ bool need_prim_time;
+
+ /* Build parameters. */
+ BVHParams params;
+
+ /* Progress reporting. */
+ Progress &progress;
+ double progress_start_time;
+ size_t progress_count;
+ size_t progress_total;
+ size_t progress_original_total;
+
+ /* Spatial splitting. */
+ float spatial_min_overlap;
+ enumerable_thread_specific<BVHSpatialStorage> spatial_storage;
+ size_t spatial_free_index;
+ thread_spin_lock spatial_spin_lock;
+
+ /* Threads. */
+ TaskPool task_pool;
+
+ /* Unaligned building. */
+ BVHUnaligned unaligned_heuristic;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_BUILD_H__ */
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index 050e090bddf..ae6655eb27b 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -18,12 +18,12 @@
#include "bvh/bvh.h"
#include "bvh/bvh2.h"
-#include "bvh/bvh_embree.h"
-#include "bvh/bvh_multi.h"
-#include "bvh/bvh_optix.h"
+#include "bvh/embree.h"
+#include "bvh/multi.h"
+#include "bvh/optix.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
+#include "util/log.h"
+#include "util/progress.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index b222dfb14ed..c1f55ee917e 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -18,10 +18,10 @@
#ifndef __BVH_H__
#define __BVH_H__
-#include "bvh/bvh_params.h"
-#include "util/util_array.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
+#include "bvh/params.h"
+#include "util/array.h"
+#include "util/types.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp
index 4a90a1e8796..04290602145 100644
--- a/intern/cycles/bvh/bvh2.cpp
+++ b/intern/cycles/bvh/bvh2.cpp
@@ -17,16 +17,16 @@
#include "bvh/bvh2.h"
-#include "render/hair.h"
-#include "render/mesh.h"
-#include "render/object.h"
+#include "scene/hair.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
-#include "bvh/bvh_build.h"
-#include "bvh/bvh_node.h"
-#include "bvh/bvh_unaligned.h"
+#include "bvh/build.h"
+#include "bvh/node.h"
+#include "bvh/unaligned.h"
-#include "util/util_foreach.h"
-#include "util/util_progress.h"
+#include "util/foreach.h"
+#include "util/progress.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/bvh/bvh2.h b/intern/cycles/bvh/bvh2.h
index 1030a0f76c7..7937288f271 100644
--- a/intern/cycles/bvh/bvh2.h
+++ b/intern/cycles/bvh/bvh2.h
@@ -19,10 +19,10 @@
#define __BVH2_H__
#include "bvh/bvh.h"
-#include "bvh/bvh_params.h"
+#include "bvh/params.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
+#include "util/types.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/bvh/bvh_binning.cpp b/intern/cycles/bvh/bvh_binning.cpp
deleted file mode 100644
index 1cc38275d11..00000000000
--- a/intern/cycles/bvh/bvh_binning.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Adapted from code copyright 2009-2011 Intel Corporation
- * Modifications Copyright 2012, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define __KERNEL_SSE__
-
-#include "bvh/bvh_binning.h"
-
-#include <stdlib.h>
-
-#include "util/util_algorithm.h"
-#include "util/util_boundbox.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* SSE replacements */
-
-__forceinline void prefetch_L1(const void * /*ptr*/)
-{
-}
-__forceinline void prefetch_L2(const void * /*ptr*/)
-{
-}
-__forceinline void prefetch_L3(const void * /*ptr*/)
-{
-}
-__forceinline void prefetch_NTA(const void * /*ptr*/)
-{
-}
-
-template<size_t src> __forceinline float extract(const int4 &b)
-{
- return b[src];
-}
-template<size_t dst> __forceinline const float4 insert(const float4 &a, const float b)
-{
- float4 r = a;
- r[dst] = b;
- return r;
-}
-
-__forceinline int get_best_dimension(const float4 &bestSAH)
-{
- // return (int)__bsf(movemask(reduce_min(bestSAH) == bestSAH));
-
- float minSAH = min(bestSAH.x, min(bestSAH.y, bestSAH.z));
-
- if (bestSAH.x == minSAH)
- return 0;
- else if (bestSAH.y == minSAH)
- return 1;
- else
- return 2;
-}
-
-/* BVH Object Binning */
-
-BVHObjectBinning::BVHObjectBinning(const BVHRange &job,
- BVHReference *prims,
- const BVHUnaligned *unaligned_heuristic,
- const Transform *aligned_space)
- : BVHRange(job),
- splitSAH(FLT_MAX),
- dim(0),
- pos(0),
- unaligned_heuristic_(unaligned_heuristic),
- aligned_space_(aligned_space)
-{
- if (aligned_space_ == NULL) {
- bounds_ = bounds();
- cent_bounds_ = cent_bounds();
- }
- else {
- /* TODO(sergey): With some additional storage we can avoid
- * need in re-calculating this.
- */
- bounds_ = unaligned_heuristic->compute_aligned_boundbox(
- *this, prims, *aligned_space, &cent_bounds_);
- }
-
- /* compute number of bins to use and precompute scaling factor for binning */
- num_bins = min(size_t(MAX_BINS), size_t(4.0f + 0.05f * size()));
- scale = rcp(cent_bounds_.size()) * make_float3((float)num_bins);
-
- /* initialize binning counter and bounds */
- BoundBox bin_bounds[MAX_BINS][4]; /* bounds for every bin in every dimension */
- int4 bin_count[MAX_BINS]; /* number of primitives mapped to bin */
-
- for (size_t i = 0; i < num_bins; i++) {
- bin_count[i] = make_int4(0);
- bin_bounds[i][0] = bin_bounds[i][1] = bin_bounds[i][2] = BoundBox::empty;
- }
-
- /* map geometry to bins, unrolled once */
- {
- int64_t i;
-
- for (i = 0; i < int64_t(size()) - 1; i += 2) {
- prefetch_L2(&prims[start() + i + 8]);
-
- /* map even and odd primitive to bin */
- const BVHReference &prim0 = prims[start() + i + 0];
- const BVHReference &prim1 = prims[start() + i + 1];
-
- BoundBox bounds0 = get_prim_bounds(prim0);
- BoundBox bounds1 = get_prim_bounds(prim1);
-
- int4 bin0 = get_bin(bounds0);
- int4 bin1 = get_bin(bounds1);
-
- /* increase bounds for bins for even primitive */
- int b00 = (int)extract<0>(bin0);
- bin_count[b00][0]++;
- bin_bounds[b00][0].grow(bounds0);
- int b01 = (int)extract<1>(bin0);
- bin_count[b01][1]++;
- bin_bounds[b01][1].grow(bounds0);
- int b02 = (int)extract<2>(bin0);
- bin_count[b02][2]++;
- bin_bounds[b02][2].grow(bounds0);
-
- /* increase bounds of bins for odd primitive */
- int b10 = (int)extract<0>(bin1);
- bin_count[b10][0]++;
- bin_bounds[b10][0].grow(bounds1);
- int b11 = (int)extract<1>(bin1);
- bin_count[b11][1]++;
- bin_bounds[b11][1].grow(bounds1);
- int b12 = (int)extract<2>(bin1);
- bin_count[b12][2]++;
- bin_bounds[b12][2].grow(bounds1);
- }
-
- /* for uneven number of primitives */
- if (i < int64_t(size())) {
- /* map primitive to bin */
- const BVHReference &prim0 = prims[start() + i];
- BoundBox bounds0 = get_prim_bounds(prim0);
- int4 bin0 = get_bin(bounds0);
-
- /* increase bounds of bins */
- int b00 = (int)extract<0>(bin0);
- bin_count[b00][0]++;
- bin_bounds[b00][0].grow(bounds0);
- int b01 = (int)extract<1>(bin0);
- bin_count[b01][1]++;
- bin_bounds[b01][1].grow(bounds0);
- int b02 = (int)extract<2>(bin0);
- bin_count[b02][2]++;
- bin_bounds[b02][2].grow(bounds0);
- }
- }
-
- /* sweep from right to left and compute parallel prefix of merged bounds */
- float4 r_area[MAX_BINS]; /* area of bounds of primitives on the right */
- float4 r_count[MAX_BINS]; /* number of primitives on the right */
- int4 count = make_int4(0);
-
- BoundBox bx = BoundBox::empty;
- BoundBox by = BoundBox::empty;
- BoundBox bz = BoundBox::empty;
-
- for (size_t i = num_bins - 1; i > 0; i--) {
- count = count + bin_count[i];
- r_count[i] = blocks(count);
-
- bx = merge(bx, bin_bounds[i][0]);
- r_area[i][0] = bx.half_area();
- by = merge(by, bin_bounds[i][1]);
- r_area[i][1] = by.half_area();
- bz = merge(bz, bin_bounds[i][2]);
- r_area[i][2] = bz.half_area();
- r_area[i][3] = r_area[i][2];
- }
-
- /* sweep from left to right and compute SAH */
- int4 ii = make_int4(1);
- float4 bestSAH = make_float4(FLT_MAX);
- int4 bestSplit = make_int4(-1);
-
- count = make_int4(0);
-
- bx = BoundBox::empty;
- by = BoundBox::empty;
- bz = BoundBox::empty;
-
- for (size_t i = 1; i < num_bins; i++, ii += make_int4(1)) {
- count = count + bin_count[i - 1];
-
- bx = merge(bx, bin_bounds[i - 1][0]);
- float Ax = bx.half_area();
- by = merge(by, bin_bounds[i - 1][1]);
- float Ay = by.half_area();
- bz = merge(bz, bin_bounds[i - 1][2]);
- float Az = bz.half_area();
-
- float4 lCount = blocks(count);
- float4 lArea = make_float4(Ax, Ay, Az, Az);
- float4 sah = lArea * lCount + r_area[i] * r_count[i];
-
- bestSplit = select(sah < bestSAH, ii, bestSplit);
- bestSAH = min(sah, bestSAH);
- }
-
- int4 mask = float3_to_float4(cent_bounds_.size()) <= make_float4(0.0f);
- bestSAH = insert<3>(select(mask, make_float4(FLT_MAX), bestSAH), FLT_MAX);
-
- /* find best dimension */
- dim = get_best_dimension(bestSAH);
- splitSAH = bestSAH[dim];
- pos = bestSplit[dim];
- leafSAH = bounds_.half_area() * blocks(size());
-}
-
-void BVHObjectBinning::split(BVHReference *prims,
- BVHObjectBinning &left_o,
- BVHObjectBinning &right_o) const
-{
- size_t N = size();
-
- BoundBox lgeom_bounds = BoundBox::empty;
- BoundBox rgeom_bounds = BoundBox::empty;
- BoundBox lcent_bounds = BoundBox::empty;
- BoundBox rcent_bounds = BoundBox::empty;
-
- int64_t l = 0, r = N - 1;
-
- while (l <= r) {
- prefetch_L2(&prims[start() + l + 8]);
- prefetch_L2(&prims[start() + r - 8]);
-
- BVHReference prim = prims[start() + l];
- BoundBox unaligned_bounds = get_prim_bounds(prim);
- float3 unaligned_center = unaligned_bounds.center2();
- float3 center = prim.bounds().center2();
-
- if (get_bin(unaligned_center)[dim] < pos) {
- lgeom_bounds.grow(prim.bounds());
- lcent_bounds.grow(center);
- l++;
- }
- else {
- rgeom_bounds.grow(prim.bounds());
- rcent_bounds.grow(center);
- swap(prims[start() + l], prims[start() + r]);
- r--;
- }
- }
- /* finish */
- if (l != 0 && N - 1 - r != 0) {
- right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + l, N - 1 - r),
- prims);
- left_o = BVHObjectBinning(BVHRange(lgeom_bounds, lcent_bounds, start(), l), prims);
- return;
- }
-
- /* object medium split if we did not make progress, can happen when all
- * primitives have same centroid */
- lgeom_bounds = BoundBox::empty;
- rgeom_bounds = BoundBox::empty;
- lcent_bounds = BoundBox::empty;
- rcent_bounds = BoundBox::empty;
-
- for (size_t i = 0; i < N / 2; i++) {
- lgeom_bounds.grow(prims[start() + i].bounds());
- lcent_bounds.grow(prims[start() + i].bounds().center2());
- }
-
- for (size_t i = N / 2; i < N; i++) {
- rgeom_bounds.grow(prims[start() + i].bounds());
- rcent_bounds.grow(prims[start() + i].bounds().center2());
- }
-
- right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + N / 2, N / 2 + N % 2),
- prims);
- left_o = BVHObjectBinning(BVHRange(lgeom_bounds, lcent_bounds, start(), N / 2), prims);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_binning.h b/intern/cycles/bvh/bvh_binning.h
deleted file mode 100644
index ae6dba2805d..00000000000
--- a/intern/cycles/bvh/bvh_binning.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Adapted from code copyright 2009-2011 Intel Corporation
- * Modifications Copyright 2012, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BVH_BINNING_H__
-#define __BVH_BINNING_H__
-
-#include "bvh/bvh_params.h"
-#include "bvh/bvh_unaligned.h"
-
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BVHBuild;
-
-/* Single threaded object binner. Finds the split with the best SAH heuristic
- * by testing for each dimension multiple partitionings for regular spaced
- * partition locations. A partitioning for a partition location is computed,
- * by putting primitives whose centroid is on the left and right of the split
- * location to different sets. The SAH is evaluated by computing the number of
- * blocks occupied by the primitives in the partitions. */
-
-class BVHObjectBinning : public BVHRange {
- public:
- __forceinline BVHObjectBinning() : leafSAH(FLT_MAX)
- {
- }
-
- BVHObjectBinning(const BVHRange &job,
- BVHReference *prims,
- const BVHUnaligned *unaligned_heuristic = NULL,
- const Transform *aligned_space = NULL);
-
- void split(BVHReference *prims, BVHObjectBinning &left_o, BVHObjectBinning &right_o) const;
-
- __forceinline const BoundBox &unaligned_bounds()
- {
- return bounds_;
- }
-
- float splitSAH; /* SAH cost of the best split */
- float leafSAH; /* SAH cost of creating a leaf */
-
- protected:
- int dim; /* best split dimension */
- int pos; /* best split position */
- size_t num_bins; /* actual number of bins to use */
- float3 scale; /* scaling factor to compute bin */
-
- /* Effective bounds and centroid bounds. */
- BoundBox bounds_;
- BoundBox cent_bounds_;
-
- const BVHUnaligned *unaligned_heuristic_;
- const Transform *aligned_space_;
-
- enum { MAX_BINS = 32 };
- enum { LOG_BLOCK_SIZE = 2 };
-
- /* computes the bin numbers for each dimension for a box. */
- __forceinline int4 get_bin(const BoundBox &box) const
- {
- int4 a = make_int4((box.center2() - cent_bounds_.min) * scale - make_float3(0.5f));
- int4 mn = make_int4(0);
- int4 mx = make_int4((int)num_bins - 1);
-
- return clamp(a, mn, mx);
- }
-
- /* computes the bin numbers for each dimension for a point. */
- __forceinline int4 get_bin(const float3 &c) const
- {
- return make_int4((c - cent_bounds_.min) * scale - make_float3(0.5f));
- }
-
- /* compute the number of blocks occupied for each dimension. */
- __forceinline float4 blocks(const int4 &a) const
- {
- return make_float4((a + make_int4((1 << LOG_BLOCK_SIZE) - 1)) >> LOG_BLOCK_SIZE);
- }
-
- /* compute the number of blocks occupied in one dimension. */
- __forceinline int blocks(size_t a) const
- {
- return (int)((a + ((1LL << LOG_BLOCK_SIZE) - 1)) >> LOG_BLOCK_SIZE);
- }
-
- __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
- {
- if (aligned_space_ == NULL) {
- return prim.bounds();
- }
- else {
- return unaligned_heuristic_->compute_aligned_prim_boundbox(prim, *aligned_space_);
- }
- }
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BVH_BINNING_H__ */
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
deleted file mode 100644
index 025a103d6f8..00000000000
--- a/intern/cycles/bvh/bvh_build.cpp
+++ /dev/null
@@ -1,1144 +0,0 @@
-/*
- * Adapted from code copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bvh/bvh_build.h"
-
-#include "bvh/bvh_binning.h"
-#include "bvh/bvh_node.h"
-#include "bvh/bvh_params.h"
-#include "bvh_split.h"
-
-#include "render/curves.h"
-#include "render/hair.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/scene.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
-#include "util/util_queue.h"
-#include "util/util_simd.h"
-#include "util/util_stack_allocator.h"
-#include "util/util_time.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Constructor / Destructor */
-
-BVHBuild::BVHBuild(const vector<Object *> &objects_,
- array<int> &prim_type_,
- array<int> &prim_index_,
- array<int> &prim_object_,
- array<float2> &prim_time_,
- const BVHParams &params_,
- Progress &progress_)
- : objects(objects_),
- prim_type(prim_type_),
- prim_index(prim_index_),
- prim_object(prim_object_),
- prim_time(prim_time_),
- params(params_),
- progress(progress_),
- progress_start_time(0.0),
- unaligned_heuristic(objects_)
-{
- spatial_min_overlap = 0.0f;
-}
-
-BVHBuild::~BVHBuild()
-{
-}
-
-/* Adding References */
-
-void BVHBuild::add_reference_triangles(BoundBox &root,
- BoundBox &center,
- Mesh *mesh,
- int object_index)
-{
- const PrimitiveType primitive_type = mesh->primitive_type();
- const Attribute *attr_mP = NULL;
- if (mesh->has_motion_blur()) {
- attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- }
- const size_t num_triangles = mesh->num_triangles();
- for (uint j = 0; j < num_triangles; j++) {
- Mesh::Triangle t = mesh->get_triangle(j);
- const float3 *verts = &mesh->verts[0];
- if (attr_mP == NULL) {
- BoundBox bounds = BoundBox::empty;
- t.bounds_grow(verts, bounds);
- if (bounds.valid() && t.valid(verts)) {
- references.push_back(BVHReference(bounds, j, object_index, primitive_type));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- }
- else if (params.num_motion_triangle_steps == 0 || params.use_spatial_split) {
- /* Motion triangles, simple case: single node for the whole
- * primitive. Lowest memory footprint and faster BVH build but
- * least optimal ray-tracing.
- */
- /* TODO(sergey): Support motion steps for spatially split BVH. */
- const size_t num_verts = mesh->verts.size();
- const size_t num_steps = mesh->motion_steps;
- const float3 *vert_steps = attr_mP->data_float3();
- BoundBox bounds = BoundBox::empty;
- t.bounds_grow(verts, bounds);
- for (size_t step = 0; step < num_steps - 1; step++) {
- t.bounds_grow(vert_steps + step * num_verts, bounds);
- }
- if (bounds.valid()) {
- references.push_back(BVHReference(bounds, j, object_index, primitive_type));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- }
- else {
- /* Motion triangles, trace optimized case: we split triangle
- * primitives into separate nodes for each of the time steps.
- * This way we minimize overlap of neighbor curve primitives.
- */
- const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
- const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
- const size_t num_verts = mesh->verts.size();
- const size_t num_steps = mesh->motion_steps;
- const float3 *vert_steps = attr_mP->data_float3();
- /* Calculate bounding box of the previous time step.
- * Will be reused later to avoid duplicated work on
- * calculating BVH time step boundbox.
- */
- float3 prev_verts[3];
- t.motion_verts(verts, vert_steps, num_verts, num_steps, 0.0f, prev_verts);
- BoundBox prev_bounds = BoundBox::empty;
- prev_bounds.grow(prev_verts[0]);
- prev_bounds.grow(prev_verts[1]);
- prev_bounds.grow(prev_verts[2]);
- /* Create all primitive time steps, */
- for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
- const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
- float3 curr_verts[3];
- t.motion_verts(verts, vert_steps, num_verts, num_steps, curr_time, curr_verts);
- BoundBox curr_bounds = BoundBox::empty;
- curr_bounds.grow(curr_verts[0]);
- curr_bounds.grow(curr_verts[1]);
- curr_bounds.grow(curr_verts[2]);
- BoundBox bounds = prev_bounds;
- bounds.grow(curr_bounds);
- if (bounds.valid()) {
- const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
- references.push_back(
- BVHReference(bounds, j, object_index, primitive_type, prev_time, curr_time));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- /* Current time boundbox becomes previous one for the
- * next time step.
- */
- prev_bounds = curr_bounds;
- }
- }
- }
-}
-
-void BVHBuild::add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair, int object_index)
-{
- const Attribute *curve_attr_mP = NULL;
- if (hair->has_motion_blur()) {
- curve_attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- }
-
- const PrimitiveType primitive_type = hair->primitive_type();
-
- const size_t num_curves = hair->num_curves();
- for (uint j = 0; j < num_curves; j++) {
- const Hair::Curve curve = hair->get_curve(j);
- const float *curve_radius = &hair->get_curve_radius()[0];
- for (int k = 0; k < curve.num_keys - 1; k++) {
- if (curve_attr_mP == NULL) {
- /* Really simple logic for static hair. */
- BoundBox bounds = BoundBox::empty;
- curve.bounds_grow(k, &hair->get_curve_keys()[0], curve_radius, bounds);
- if (bounds.valid()) {
- int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
- references.push_back(BVHReference(bounds, j, object_index, packed_type));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- }
- else if (params.num_motion_curve_steps == 0 || params.use_spatial_split) {
- /* Simple case of motion curves: single node for the while
- * shutter time. Lowest memory usage but less optimal
- * rendering.
- */
- /* TODO(sergey): Support motion steps for spatially split BVH. */
- BoundBox bounds = BoundBox::empty;
- curve.bounds_grow(k, &hair->get_curve_keys()[0], curve_radius, bounds);
- const size_t num_keys = hair->get_curve_keys().size();
- const size_t num_steps = hair->get_motion_steps();
- const float3 *key_steps = curve_attr_mP->data_float3();
- for (size_t step = 0; step < num_steps - 1; step++) {
- curve.bounds_grow(k, key_steps + step * num_keys, curve_radius, bounds);
- }
- if (bounds.valid()) {
- int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
- references.push_back(BVHReference(bounds, j, object_index, packed_type));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- }
- else {
- /* Motion curves, trace optimized case: we split curve keys
- * primitives into separate nodes for each of the time steps.
- * This way we minimize overlap of neighbor curve primitives.
- */
- const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
- const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
- const size_t num_steps = hair->get_motion_steps();
- const float3 *curve_keys = &hair->get_curve_keys()[0];
- const float3 *key_steps = curve_attr_mP->data_float3();
- const size_t num_keys = hair->get_curve_keys().size();
- /* Calculate bounding box of the previous time step.
- * Will be reused later to avoid duplicated work on
- * calculating BVH time step boundbox.
- */
- float4 prev_keys[4];
- curve.cardinal_motion_keys(curve_keys,
- curve_radius,
- key_steps,
- num_keys,
- num_steps,
- 0.0f,
- k - 1,
- k,
- k + 1,
- k + 2,
- prev_keys);
- BoundBox prev_bounds = BoundBox::empty;
- curve.bounds_grow(prev_keys, prev_bounds);
- /* Create all primitive time steps, */
- for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
- const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
- float4 curr_keys[4];
- curve.cardinal_motion_keys(curve_keys,
- curve_radius,
- key_steps,
- num_keys,
- num_steps,
- curr_time,
- k - 1,
- k,
- k + 1,
- k + 2,
- curr_keys);
- BoundBox curr_bounds = BoundBox::empty;
- curve.bounds_grow(curr_keys, curr_bounds);
- BoundBox bounds = prev_bounds;
- bounds.grow(curr_bounds);
- if (bounds.valid()) {
- const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
- int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
- references.push_back(
- BVHReference(bounds, j, object_index, packed_type, prev_time, curr_time));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- /* Current time boundbox becomes previous one for the
- * next time step.
- */
- prev_bounds = curr_bounds;
- }
- }
- }
- }
-}
-
-void BVHBuild::add_reference_geometry(BoundBox &root,
- BoundBox &center,
- Geometry *geom,
- int object_index)
-{
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- add_reference_triangles(root, center, mesh, object_index);
- }
- else if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- add_reference_curves(root, center, hair, object_index);
- }
-}
-
-void BVHBuild::add_reference_object(BoundBox &root, BoundBox &center, Object *ob, int i)
-{
- references.push_back(BVHReference(ob->bounds, -1, i, 0));
- root.grow(ob->bounds);
- center.grow(ob->bounds.center2());
-}
-
-static size_t count_curve_segments(Hair *hair)
-{
- size_t num = 0, num_curves = hair->num_curves();
-
- for (size_t i = 0; i < num_curves; i++)
- num += hair->get_curve(i).num_keys - 1;
-
- return num;
-}
-
-static size_t count_primitives(Geometry *geom)
-{
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- return mesh->num_triangles();
- }
- else if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- return count_curve_segments(hair);
- }
-
- return 0;
-}
-
-void BVHBuild::add_references(BVHRange &root)
-{
- /* reserve space for references */
- size_t num_alloc_references = 0;
-
- foreach (Object *ob, objects) {
- if (params.top_level) {
- if (!ob->is_traceable()) {
- continue;
- }
- if (!ob->get_geometry()->is_instanced()) {
- num_alloc_references += count_primitives(ob->get_geometry());
- }
- else
- num_alloc_references++;
- }
- else {
- num_alloc_references += count_primitives(ob->get_geometry());
- }
- }
-
- references.reserve(num_alloc_references);
-
- /* add references from objects */
- BoundBox bounds = BoundBox::empty, center = BoundBox::empty;
- int i = 0;
-
- foreach (Object *ob, objects) {
- if (params.top_level) {
- if (!ob->is_traceable()) {
- ++i;
- continue;
- }
- if (!ob->get_geometry()->is_instanced())
- add_reference_geometry(bounds, center, ob->get_geometry(), i);
- else
- add_reference_object(bounds, center, ob, i);
- }
- else
- add_reference_geometry(bounds, center, ob->get_geometry(), i);
-
- i++;
-
- if (progress.get_cancel())
- return;
- }
-
- /* happens mostly on empty meshes */
- if (!bounds.valid())
- bounds.grow(zero_float3());
-
- root = BVHRange(bounds, center, 0, references.size());
-}
-
-/* Build */
-
-BVHNode *BVHBuild::run()
-{
- BVHRange root;
-
- /* add references */
- add_references(root);
-
- if (progress.get_cancel())
- return NULL;
-
- /* init spatial splits */
- if (params.top_level) {
- /* NOTE: Technically it is supported by the builder but it's not really
- * optimized for speed yet and not really clear yet if it has measurable
- * improvement on render time. Needs some extra investigation before
- * enabling spatial split for top level BVH.
- */
- params.use_spatial_split = false;
- }
-
- spatial_min_overlap = root.bounds().safe_area() * params.spatial_split_alpha;
- spatial_free_index = 0;
-
- need_prim_time = params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0;
-
- /* init progress updates */
- double build_start_time;
- build_start_time = progress_start_time = time_dt();
- progress_count = 0;
- progress_total = references.size();
- progress_original_total = progress_total;
-
- prim_type.resize(references.size());
- prim_index.resize(references.size());
- prim_object.resize(references.size());
- if (need_prim_time) {
- prim_time.resize(references.size());
- }
- else {
- prim_time.resize(0);
- }
-
- /* build recursively */
- BVHNode *rootnode;
-
- if (params.use_spatial_split) {
- /* Perform multithreaded spatial split build. */
- BVHSpatialStorage *local_storage = &spatial_storage.local();
- rootnode = build_node(root, references, 0, local_storage);
- task_pool.wait_work();
- }
- else {
- /* Perform multithreaded binning build. */
- BVHObjectBinning rootbin(root, (references.size()) ? &references[0] : NULL);
- rootnode = build_node(rootbin, 0);
- task_pool.wait_work();
- }
-
- /* clean up temporary memory usage by threads */
- spatial_storage.clear();
-
- /* delete if we canceled */
- if (rootnode) {
- if (progress.get_cancel()) {
- rootnode->deleteSubtree();
- rootnode = NULL;
- VLOG(1) << "BVH build cancelled.";
- }
- else {
- /*rotate(rootnode, 4, 5);*/
- rootnode->update_visibility();
- rootnode->update_time();
- }
- if (rootnode != NULL) {
- VLOG(1) << "BVH build statistics:\n"
- << " Build time: " << time_dt() - build_start_time << "\n"
- << " Total number of nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT))
- << "\n"
- << " Number of inner nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT))
- << "\n"
- << " Number of leaf nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT))
- << "\n"
- << " Number of unaligned nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT))
- << "\n"
- << " Allocation slop factor: "
- << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() :
- 1.0f)
- << "\n"
- << " Maximum depth: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_DEPTH)) << "\n";
- }
- }
-
- return rootnode;
-}
-
-void BVHBuild::progress_update()
-{
- if (time_dt() - progress_start_time < 0.25)
- return;
-
- double progress_start = (double)progress_count / (double)progress_total;
- double duplicates = (double)(progress_total - progress_original_total) / (double)progress_total;
-
- string msg = string_printf(
- "Building BVH %.0f%%, duplicates %.0f%%", progress_start * 100.0, duplicates * 100.0);
-
- progress.set_substatus(msg);
- progress_start_time = time_dt();
-}
-
-void BVHBuild::thread_build_node(InnerNode *inner,
- int child,
- const BVHObjectBinning &range,
- int level)
-{
- if (progress.get_cancel())
- return;
-
- /* build nodes */
- BVHNode *node = build_node(range, level);
-
- /* set child in inner node */
- inner->children[child] = node;
-
- /* update progress */
- if (range.size() < THREAD_TASK_SIZE) {
- /*rotate(node, INT_MAX, 5);*/
-
- thread_scoped_lock lock(build_mutex);
-
- progress_count += range.size();
- progress_update();
- }
-}
-
-void BVHBuild::thread_build_spatial_split_node(InnerNode *inner,
- int child,
- const BVHRange &range,
- vector<BVHReference> &references,
- int level)
-{
- if (progress.get_cancel()) {
- return;
- }
-
- /* Get per-thread memory for spatial split. */
- BVHSpatialStorage *local_storage = &spatial_storage.local();
-
- /* build nodes */
- BVHNode *node = build_node(range, references, level, local_storage);
-
- /* set child in inner node */
- inner->children[child] = node;
-}
-
-bool BVHBuild::range_within_max_leaf_size(const BVHRange &range,
- const vector<BVHReference> &references) const
-{
- size_t size = range.size();
- size_t max_leaf_size = max(params.max_triangle_leaf_size, params.max_curve_leaf_size);
-
- if (size > max_leaf_size)
- return false;
-
- size_t num_triangles = 0;
- size_t num_motion_triangles = 0;
- size_t num_curves = 0;
- size_t num_motion_curves = 0;
-
- for (int i = 0; i < size; i++) {
- const BVHReference &ref = references[range.start() + i];
-
- if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
- if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
- num_motion_curves++;
- }
- else {
- num_curves++;
- }
- }
- else if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
- if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
- num_motion_triangles++;
- }
- else {
- num_triangles++;
- }
- }
- }
-
- return (num_triangles <= params.max_triangle_leaf_size) &&
- (num_motion_triangles <= params.max_motion_triangle_leaf_size) &&
- (num_curves <= params.max_curve_leaf_size) &&
- (num_motion_curves <= params.max_motion_curve_leaf_size);
-}
-
-/* multithreaded binning builder */
-BVHNode *BVHBuild::build_node(const BVHObjectBinning &range, int level)
-{
- size_t size = range.size();
- float leafSAH = params.sah_primitive_cost * range.leafSAH;
- float splitSAH = params.sah_node_cost * range.bounds().half_area() +
- params.sah_primitive_cost * range.splitSAH;
-
- /* Have at least one inner node on top level, for performance and correct
- * visibility tests, since object instances do not check visibility flag.
- */
- if (!(range.size() > 0 && params.top_level && level == 0)) {
- /* Make leaf node when threshold reached or SAH tells us. */
- if ((params.small_enough_for_leaf(size, level)) ||
- (range_within_max_leaf_size(range, references) && leafSAH < splitSAH)) {
- return create_leaf_node(range, references);
- }
- }
-
- BVHObjectBinning unaligned_range;
- float unalignedSplitSAH = FLT_MAX;
- float unalignedLeafSAH = FLT_MAX;
- Transform aligned_space;
- bool do_unalinged_split = false;
- if (params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold * leafSAH) {
- aligned_space = unaligned_heuristic.compute_aligned_space(range, &references[0]);
- unaligned_range = BVHObjectBinning(
- range, &references[0], &unaligned_heuristic, &aligned_space);
- unalignedSplitSAH = params.sah_node_cost * unaligned_range.unaligned_bounds().half_area() +
- params.sah_primitive_cost * unaligned_range.splitSAH;
- unalignedLeafSAH = params.sah_primitive_cost * unaligned_range.leafSAH;
- if (!(range.size() > 0 && params.top_level && level == 0)) {
- if (unalignedLeafSAH < unalignedSplitSAH && unalignedSplitSAH < splitSAH &&
- range_within_max_leaf_size(range, references)) {
- return create_leaf_node(range, references);
- }
- }
- /* Check whether unaligned split is better than the regular one. */
- if (unalignedSplitSAH < splitSAH) {
- do_unalinged_split = true;
- }
- }
-
- /* Perform split. */
- BVHObjectBinning left, right;
- if (do_unalinged_split) {
- unaligned_range.split(&references[0], left, right);
- }
- else {
- range.split(&references[0], left, right);
- }
-
- BoundBox bounds;
- if (do_unalinged_split) {
- bounds = unaligned_heuristic.compute_aligned_boundbox(range, &references[0], aligned_space);
- }
- else {
- bounds = range.bounds();
- }
-
- /* Create inner node. */
- InnerNode *inner;
- if (range.size() < THREAD_TASK_SIZE) {
- /* local build */
- BVHNode *leftnode = build_node(left, level + 1);
- BVHNode *rightnode = build_node(right, level + 1);
-
- inner = new InnerNode(bounds, leftnode, rightnode);
- }
- else {
- /* Threaded build */
- inner = new InnerNode(bounds);
-
- task_pool.push([=] { thread_build_node(inner, 0, left, level + 1); });
- task_pool.push([=] { thread_build_node(inner, 1, right, level + 1); });
- }
-
- if (do_unalinged_split) {
- inner->set_aligned_space(aligned_space);
- }
-
- return inner;
-}
-
-/* multithreaded spatial split builder */
-BVHNode *BVHBuild::build_node(const BVHRange &range,
- vector<BVHReference> &references,
- int level,
- BVHSpatialStorage *storage)
-{
- /* Update progress.
- *
- * TODO(sergey): Currently it matches old behavior, but we can move it to the
- * task thread (which will mimic non=split builder) and save some CPU ticks
- * on checking cancel status.
- */
- progress_update();
- if (progress.get_cancel()) {
- return NULL;
- }
-
- /* Small enough or too deep => create leaf. */
- if (!(range.size() > 0 && params.top_level && level == 0)) {
- if (params.small_enough_for_leaf(range.size(), level)) {
- progress_count += range.size();
- return create_leaf_node(range, references);
- }
- }
-
- /* Perform splitting test. */
- BVHMixedSplit split(this, storage, range, references, level);
-
- if (!(range.size() > 0 && params.top_level && level == 0)) {
- if (split.no_split) {
- progress_count += range.size();
- return create_leaf_node(range, references);
- }
- }
- float leafSAH = params.sah_primitive_cost * split.leafSAH;
- float splitSAH = params.sah_node_cost * range.bounds().half_area() +
- params.sah_primitive_cost * split.nodeSAH;
-
- BVHMixedSplit unaligned_split;
- float unalignedSplitSAH = FLT_MAX;
- /* float unalignedLeafSAH = FLT_MAX; */
- Transform aligned_space;
- bool do_unalinged_split = false;
- if (params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold * leafSAH) {
- aligned_space = unaligned_heuristic.compute_aligned_space(range, &references.at(0));
- unaligned_split = BVHMixedSplit(
- this, storage, range, references, level, &unaligned_heuristic, &aligned_space);
- /* unalignedLeafSAH = params.sah_primitive_cost * split.leafSAH; */
- unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() +
- params.sah_primitive_cost * unaligned_split.nodeSAH;
- /* TOOD(sergey): Check we can create leaf already. */
- /* Check whether unaligned split is better than the regular one. */
- if (unalignedSplitSAH < splitSAH) {
- do_unalinged_split = true;
- }
- }
-
- /* Do split. */
- BVHRange left, right;
- if (do_unalinged_split) {
- unaligned_split.split(this, left, right, range);
- }
- else {
- split.split(this, left, right, range);
- }
-
- progress_total += left.size() + right.size() - range.size();
-
- BoundBox bounds;
- if (do_unalinged_split) {
- bounds = unaligned_heuristic.compute_aligned_boundbox(range, &references.at(0), aligned_space);
- }
- else {
- bounds = range.bounds();
- }
-
- /* Create inner node. */
- InnerNode *inner;
- if (range.size() < THREAD_TASK_SIZE) {
- /* Local build. */
-
- /* Build left node. */
- vector<BVHReference> right_references(references.begin() + right.start(),
- references.begin() + right.end());
- right.set_start(0);
-
- BVHNode *leftnode = build_node(left, references, level + 1, storage);
-
- /* Build right node. */
- BVHNode *rightnode = build_node(right, right_references, level + 1, storage);
-
- inner = new InnerNode(bounds, leftnode, rightnode);
- }
- else {
- /* Threaded build. */
- inner = new InnerNode(bounds);
-
- vector<BVHReference> left_references(references.begin() + left.start(),
- references.begin() + left.end());
- vector<BVHReference> right_references(references.begin() + right.start(),
- references.begin() + right.end());
- right.set_start(0);
-
- /* Create tasks for left and right nodes, using copy for most arguments and
- * move for reference to avoid memory copies. */
- task_pool.push([=, refs = std::move(left_references)]() mutable {
- thread_build_spatial_split_node(inner, 0, left, refs, level + 1);
- });
- task_pool.push([=, refs = std::move(right_references)]() mutable {
- thread_build_spatial_split_node(inner, 1, right, refs, level + 1);
- });
- }
-
- if (do_unalinged_split) {
- inner->set_aligned_space(aligned_space);
- }
-
- return inner;
-}
-
-/* Create Nodes */
-
-BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, int num)
-{
- if (num == 0) {
- BoundBox bounds = BoundBox::empty;
- return new LeafNode(bounds, 0, 0, 0);
- }
- else if (num == 1) {
- assert(start < prim_type.size());
- prim_type[start] = ref->prim_type();
- prim_index[start] = ref->prim_index();
- prim_object[start] = ref->prim_object();
- if (need_prim_time) {
- prim_time[start] = make_float2(ref->time_from(), ref->time_to());
- }
-
- const uint visibility = objects[ref->prim_object()]->visibility_for_tracing();
- BVHNode *leaf_node = new LeafNode(ref->bounds(), visibility, start, start + 1);
- leaf_node->time_from = ref->time_from();
- leaf_node->time_to = ref->time_to();
- return leaf_node;
- }
- else {
- int mid = num / 2;
- BVHNode *leaf0 = create_object_leaf_nodes(ref, start, mid);
- BVHNode *leaf1 = create_object_leaf_nodes(ref + mid, start + mid, num - mid);
-
- BoundBox bounds = BoundBox::empty;
- bounds.grow(leaf0->bounds);
- bounds.grow(leaf1->bounds);
-
- BVHNode *inner_node = new InnerNode(bounds, leaf0, leaf1);
- inner_node->time_from = min(leaf0->time_from, leaf1->time_from);
- inner_node->time_to = max(leaf0->time_to, leaf1->time_to);
- return inner_node;
- }
-}
-
-BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHReference> &references)
-{
- /* This is a bit overallocating here (considering leaf size into account),
- * but chunk-based re-allocation in vector makes it difficult to use small
- * size of stack storage here. Some tweaks are possible tho.
- *
- * NOTES:
- * - If the size is too big, we'll have inefficient stack usage,
- * and lots of cache misses.
- * - If the size is too small, then we can run out of memory
- * allowed to be used by vector.
- * In practice it wouldn't mean crash, just allocator will fallback
- * to heap which is slower.
- * - Optimistic re-allocation in STL could jump us out of stack usage
- * because re-allocation happens in chunks and size of those chunks we
- * can not control.
- */
- typedef StackAllocator<256, int> LeafStackAllocator;
- typedef StackAllocator<256, float2> LeafTimeStackAllocator;
- typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator;
-
- vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM];
- vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM];
- vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM];
- vector<float2, LeafTimeStackAllocator> p_time[PRIMITIVE_NUM];
- vector<BVHReference, LeafReferenceStackAllocator> p_ref[PRIMITIVE_NUM];
-
- /* TODO(sergey): In theory we should be able to store references. */
- vector<BVHReference, LeafReferenceStackAllocator> object_references;
-
- uint visibility[PRIMITIVE_NUM] = {0};
- /* NOTE: Keep initialization in sync with actual number of primitives. */
- BoundBox bounds[PRIMITIVE_NUM] = {
- BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty};
- int ob_num = 0;
- int num_new_prims = 0;
- /* Fill in per-type type/index array. */
- for (int i = 0; i < range.size(); i++) {
- const BVHReference &ref = references[range.start() + i];
- if (ref.prim_index() != -1) {
- uint32_t type_index = bitscan((uint32_t)(ref.prim_type() & PRIMITIVE_ALL));
- p_ref[type_index].push_back(ref);
- p_type[type_index].push_back(ref.prim_type());
- p_index[type_index].push_back(ref.prim_index());
- p_object[type_index].push_back(ref.prim_object());
- p_time[type_index].push_back(make_float2(ref.time_from(), ref.time_to()));
-
- bounds[type_index].grow(ref.bounds());
- visibility[type_index] |= objects[ref.prim_object()]->visibility_for_tracing();
- ++num_new_prims;
- }
- else {
- object_references.push_back(ref);
- ++ob_num;
- }
- }
-
- /* Create leaf nodes for every existing primitive.
- *
- * Here we write primitive types, indices and objects to a temporary array.
- * This way we keep all the heavy memory allocation code outside of the
- * thread lock in the case of spatial split building.
- *
- * TODO(sergey): With some pointer trickery we can write directly to the
- * destination buffers for the non-spatial split BVH.
- */
- BVHNode *leaves[PRIMITIVE_NUM + 1] = {NULL};
- int num_leaves = 0;
- size_t start_index = 0;
- vector<int, LeafStackAllocator> local_prim_type, local_prim_index, local_prim_object;
- vector<float2, LeafTimeStackAllocator> local_prim_time;
- local_prim_type.resize(num_new_prims);
- local_prim_index.resize(num_new_prims);
- local_prim_object.resize(num_new_prims);
- if (need_prim_time) {
- local_prim_time.resize(num_new_prims);
- }
- for (int i = 0; i < PRIMITIVE_NUM; ++i) {
- int num = (int)p_type[i].size();
- if (num != 0) {
- assert(p_type[i].size() == p_index[i].size());
- assert(p_type[i].size() == p_object[i].size());
- Transform aligned_space;
- bool alignment_found = false;
- for (int j = 0; j < num; ++j) {
- const int index = start_index + j;
- local_prim_type[index] = p_type[i][j];
- local_prim_index[index] = p_index[i][j];
- local_prim_object[index] = p_object[i][j];
- if (need_prim_time) {
- local_prim_time[index] = p_time[i][j];
- }
- if (params.use_unaligned_nodes && !alignment_found) {
- alignment_found = unaligned_heuristic.compute_aligned_space(p_ref[i][j], &aligned_space);
- }
- }
- LeafNode *leaf_node = new LeafNode(bounds[i], visibility[i], start_index, start_index + num);
- if (true) {
- float time_from = 1.0f, time_to = 0.0f;
- for (int j = 0; j < num; ++j) {
- const BVHReference &ref = p_ref[i][j];
- time_from = min(time_from, ref.time_from());
- time_to = max(time_to, ref.time_to());
- }
- leaf_node->time_from = time_from;
- leaf_node->time_to = time_to;
- }
- if (alignment_found) {
- /* Need to recalculate leaf bounds with new alignment. */
- leaf_node->bounds = BoundBox::empty;
- for (int j = 0; j < num; ++j) {
- const BVHReference &ref = p_ref[i][j];
- BoundBox ref_bounds = unaligned_heuristic.compute_aligned_prim_boundbox(ref,
- aligned_space);
- leaf_node->bounds.grow(ref_bounds);
- }
- /* Set alignment space. */
- leaf_node->set_aligned_space(aligned_space);
- }
- leaves[num_leaves++] = leaf_node;
- start_index += num;
- }
- }
- /* Get size of new data to be copied to the packed arrays. */
- const int num_new_leaf_data = start_index;
- const size_t new_leaf_data_size = sizeof(int) * num_new_leaf_data;
- /* Copy actual data to the packed array. */
- if (params.use_spatial_split) {
- spatial_spin_lock.lock();
- /* We use first free index in the packed arrays and mode pointer to the
- * end of the current range.
- *
- * This doesn't give deterministic packed arrays, but it shouldn't really
- * matter because order of children in BVH is deterministic.
- */
- start_index = spatial_free_index;
- spatial_free_index += range.size();
- /* Extend an array when needed. */
- const size_t range_end = start_index + range.size();
- if (prim_type.size() < range_end) {
- /* Avoid extra re-allocations by pre-allocating bigger array in an
- * advance.
- */
- if (range_end >= prim_type.capacity()) {
- float progress = (float)progress_count / (float)progress_total;
- float factor = (1.0f - progress);
- const size_t reserve = (size_t)(range_end + (float)range_end * factor);
- prim_type.reserve(reserve);
- prim_index.reserve(reserve);
- prim_object.reserve(reserve);
- if (need_prim_time) {
- prim_time.reserve(reserve);
- }
- }
-
- prim_type.resize(range_end);
- prim_index.resize(range_end);
- prim_object.resize(range_end);
- if (need_prim_time) {
- prim_time.resize(range_end);
- }
- }
- /* Perform actual data copy. */
- if (new_leaf_data_size > 0) {
- memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
- memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
- memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
- if (need_prim_time) {
- memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2) * num_new_leaf_data);
- }
- }
- spatial_spin_lock.unlock();
- }
- else {
- /* For the regular BVH builder we simply copy new data starting at the
- * range start. This is totally thread-safe, all threads are living
- * inside of their own range.
- */
- start_index = range.start();
- if (new_leaf_data_size > 0) {
- memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
- memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
- memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
- if (need_prim_time) {
- memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2) * num_new_leaf_data);
- }
- }
- }
-
- /* So far leaves were created with the zero-based index in an arrays,
- * here we modify the indices to correspond to actual packed array start
- * index.
- */
- for (int i = 0; i < num_leaves; ++i) {
- LeafNode *leaf = (LeafNode *)leaves[i];
- leaf->lo += start_index;
- leaf->hi += start_index;
- }
-
- /* Create leaf node for object. */
- if (num_leaves == 0 || ob_num) {
- /* Only create object leaf nodes if there are objects or no other
- * nodes created.
- */
- const BVHReference *ref = (ob_num) ? &object_references[0] : NULL;
- leaves[num_leaves] = create_object_leaf_nodes(ref, start_index + num_new_leaf_data, ob_num);
- ++num_leaves;
- }
-
- /* TODO(sergey): Need to take care of alignment when number of leaves
- * is more than 1.
- */
- if (num_leaves == 1) {
- /* Simplest case: single leaf, just return it.
- * In all the rest cases we'll be creating intermediate inner node with
- * an appropriate bounding box.
- */
- return leaves[0];
- }
- else if (num_leaves == 2) {
- return new InnerNode(range.bounds(), leaves[0], leaves[1]);
- }
- else if (num_leaves == 3) {
- BoundBox inner_bounds = merge(leaves[1]->bounds, leaves[2]->bounds);
- BVHNode *inner = new InnerNode(inner_bounds, leaves[1], leaves[2]);
- return new InnerNode(range.bounds(), leaves[0], inner);
- }
- else {
- /* Should be doing more branches if more primitive types added. */
- assert(num_leaves <= 5);
- BoundBox inner_bounds_a = merge(leaves[0]->bounds, leaves[1]->bounds);
- BoundBox inner_bounds_b = merge(leaves[2]->bounds, leaves[3]->bounds);
- BVHNode *inner_a = new InnerNode(inner_bounds_a, leaves[0], leaves[1]);
- BVHNode *inner_b = new InnerNode(inner_bounds_b, leaves[2], leaves[3]);
- BoundBox inner_bounds_c = merge(inner_a->bounds, inner_b->bounds);
- BVHNode *inner_c = new InnerNode(inner_bounds_c, inner_a, inner_b);
- if (num_leaves == 5) {
- return new InnerNode(range.bounds(), inner_c, leaves[4]);
- }
- return inner_c;
- }
-
-#undef MAX_ITEMS_PER_LEAF
-}
-
-/* Tree Rotations */
-
-void BVHBuild::rotate(BVHNode *node, int max_depth, int iterations)
-{
- /* in tested scenes, this resulted in slightly slower raytracing, so disabled
- * it for now. could be implementation bug, or depend on the scene */
- if (node)
- for (int i = 0; i < iterations; i++)
- rotate(node, max_depth);
-}
-
-void BVHBuild::rotate(BVHNode *node, int max_depth)
-{
- /* nothing to rotate if we reached a leaf node. */
- if (node->is_leaf() || max_depth < 0)
- return;
-
- InnerNode *parent = (InnerNode *)node;
-
- /* rotate all children first */
- for (size_t c = 0; c < 2; c++)
- rotate(parent->children[c], max_depth - 1);
-
- /* compute current area of all children */
- BoundBox bounds0 = parent->children[0]->bounds;
- BoundBox bounds1 = parent->children[1]->bounds;
-
- float area0 = bounds0.half_area();
- float area1 = bounds1.half_area();
- float4 child_area = make_float4(area0, area1, 0.0f, 0.0f);
-
- /* find best rotation. we pick a target child of a first child, and swap
- * this with an other child. we perform the best such swap. */
- float best_cost = FLT_MAX;
- int best_child = -1, best_target = -1, best_other = -1;
-
- for (size_t c = 0; c < 2; c++) {
- /* ignore leaf nodes as we cannot descent into */
- if (parent->children[c]->is_leaf())
- continue;
-
- InnerNode *child = (InnerNode *)parent->children[c];
- BoundBox &other = (c == 0) ? bounds1 : bounds0;
-
- /* transpose child bounds */
- BoundBox target0 = child->children[0]->bounds;
- BoundBox target1 = child->children[1]->bounds;
-
- /* compute cost for both possible swaps */
- float cost0 = merge(other, target1).half_area() - child_area[c];
- float cost1 = merge(target0, other).half_area() - child_area[c];
-
- if (min(cost0, cost1) < best_cost) {
- best_child = (int)c;
- best_other = (int)(1 - c);
-
- if (cost0 < cost1) {
- best_cost = cost0;
- best_target = 0;
- }
- else {
- best_cost = cost0;
- best_target = 1;
- }
- }
- }
-
- /* if we did not find a swap that improves the SAH then do nothing */
- if (best_cost >= 0)
- return;
-
- assert(best_child == 0 || best_child == 1);
- assert(best_target != -1);
-
- /* perform the best found tree rotation */
- InnerNode *child = (InnerNode *)parent->children[best_child];
-
- swap(parent->children[best_other], child->children[best_target]);
- child->bounds = merge(child->children[0]->bounds, child->children[1]->bounds);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h
deleted file mode 100644
index c35af083fbd..00000000000
--- a/intern/cycles/bvh/bvh_build.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Adapted from code copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BVH_BUILD_H__
-#define __BVH_BUILD_H__
-
-#include <float.h>
-
-#include "bvh/bvh_params.h"
-#include "bvh/bvh_unaligned.h"
-
-#include "util/util_array.h"
-#include "util/util_task.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Boundbox;
-class BVHBuildTask;
-class BVHNode;
-class BVHSpatialSplitBuildTask;
-class BVHParams;
-class InnerNode;
-class Geometry;
-class Hair;
-class Mesh;
-class Object;
-class Progress;
-
-/* BVH Builder */
-
-class BVHBuild {
- public:
- /* Constructor/Destructor */
- BVHBuild(const vector<Object *> &objects,
- array<int> &prim_type,
- array<int> &prim_index,
- array<int> &prim_object,
- array<float2> &prim_time,
- const BVHParams &params,
- Progress &progress);
- ~BVHBuild();
-
- BVHNode *run();
-
- protected:
- friend class BVHMixedSplit;
- friend class BVHObjectSplit;
- friend class BVHSpatialSplit;
- friend class BVHBuildTask;
- friend class BVHSpatialSplitBuildTask;
- friend class BVHObjectBinning;
-
- /* Adding references. */
- void add_reference_triangles(BoundBox &root, BoundBox &center, Mesh *mesh, int i);
- void add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair, int i);
- void add_reference_geometry(BoundBox &root, BoundBox &center, Geometry *geom, int i);
- void add_reference_object(BoundBox &root, BoundBox &center, Object *ob, int i);
- void add_references(BVHRange &root);
-
- /* Building. */
- BVHNode *build_node(const BVHRange &range,
- vector<BVHReference> &references,
- int level,
- BVHSpatialStorage *storage);
- BVHNode *build_node(const BVHObjectBinning &range, int level);
- BVHNode *create_leaf_node(const BVHRange &range, const vector<BVHReference> &references);
- BVHNode *create_object_leaf_nodes(const BVHReference *ref, int start, int num);
-
- bool range_within_max_leaf_size(const BVHRange &range,
- const vector<BVHReference> &references) const;
-
- /* Threads. */
- enum { THREAD_TASK_SIZE = 4096 };
- void thread_build_node(InnerNode *node, int child, const BVHObjectBinning &range, int level);
- void thread_build_spatial_split_node(InnerNode *node,
- int child,
- const BVHRange &range,
- vector<BVHReference> &references,
- int level);
- thread_mutex build_mutex;
-
- /* Progress. */
- void progress_update();
-
- /* Tree rotations. */
- void rotate(BVHNode *node, int max_depth);
- void rotate(BVHNode *node, int max_depth, int iterations);
-
- /* Objects and primitive references. */
- vector<Object *> objects;
- vector<BVHReference> references;
- int num_original_references;
-
- /* Output primitive indexes and objects. */
- array<int> &prim_type;
- array<int> &prim_index;
- array<int> &prim_object;
- array<float2> &prim_time;
-
- bool need_prim_time;
-
- /* Build parameters. */
- BVHParams params;
-
- /* Progress reporting. */
- Progress &progress;
- double progress_start_time;
- size_t progress_count;
- size_t progress_total;
- size_t progress_original_total;
-
- /* Spatial splitting. */
- float spatial_min_overlap;
- enumerable_thread_specific<BVHSpatialStorage> spatial_storage;
- size_t spatial_free_index;
- thread_spin_lock spatial_spin_lock;
-
- /* Threads. */
- TaskPool task_pool;
-
- /* Unaligned building. */
- BVHUnaligned unaligned_heuristic;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BVH_BUILD_H__ */
diff --git a/intern/cycles/bvh/bvh_embree.cpp b/intern/cycles/bvh/bvh_embree.cpp
deleted file mode 100644
index cd19e009bf3..00000000000
--- a/intern/cycles/bvh/bvh_embree.cpp
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- * Copyright 2018, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* This class implements a ray accelerator for Cycles using Intel's Embree library.
- * It supports triangles, curves, object and deformation blur and instancing.
- *
- * Since Embree allows object to be either curves or triangles but not both, Cycles object IDs are
- * mapped to Embree IDs by multiplying by two and adding one for curves.
- *
- * This implementation shares RTCDevices between Cycles instances. Eventually each instance should
- * get a separate RTCDevice to correctly keep track of memory usage.
- *
- * Vertex and index buffers are duplicated between Cycles device arrays and Embree. These could be
- * merged, which would require changes to intersection refinement, shader setup, mesh light
- * sampling and a few other places in Cycles where direct access to vertex data is required.
- */
-
-#ifdef WITH_EMBREE
-
-# include <embree3/rtcore_geometry.h>
-
-# include "bvh/bvh_embree.h"
-
-/* Kernel includes are necessary so that the filter function for Embree can access the packed BVH.
- */
-# include "kernel/bvh/bvh_embree.h"
-# include "kernel/bvh/bvh_util.h"
-# include "kernel/device/cpu/compat.h"
-# include "kernel/device/cpu/globals.h"
-# include "kernel/kernel_random.h"
-
-# include "render/hair.h"
-# include "render/mesh.h"
-# include "render/object.h"
-
-# include "util/util_foreach.h"
-# include "util/util_logging.h"
-# include "util/util_progress.h"
-# include "util/util_stats.h"
-
-CCL_NAMESPACE_BEGIN
-
-static_assert(Object::MAX_MOTION_STEPS <= RTC_MAX_TIME_STEP_COUNT,
- "Object and Embree max motion steps inconsistent");
-static_assert(Object::MAX_MOTION_STEPS == Geometry::MAX_MOTION_STEPS,
- "Object and Geometry max motion steps inconsistent");
-
-# define IS_HAIR(x) (x & 1)
-
-/* This gets called by Embree at every valid ray/object intersection.
- * Things like recording subsurface or shadow hits for later evaluation
- * as well as filtering for volume objects happen here.
- * Cycles' own BVH does that directly inside the traversal calls.
- */
-static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
-{
- /* Current implementation in Cycles assumes only single-ray intersection queries. */
- assert(args->N == 1);
-
- const RTCRay *ray = (RTCRay *)args->ray;
- RTCHit *hit = (RTCHit *)args->hit;
- CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
- const KernelGlobalsCPU *kg = ctx->kg;
-
- switch (ctx->type) {
- case CCLIntersectContext::RAY_SHADOW_ALL: {
- Intersection current_isect;
- kernel_embree_convert_hit(kg, ray, hit, &current_isect);
-
- /* If no transparent shadows or max number of hits exceeded, all light is blocked. */
- const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type);
- if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->num_hits >= ctx->max_hits) {
- ctx->opaque_hit = true;
- return;
- }
-
- ++ctx->num_hits;
-
- /* Always use baked shadow transparency for curves. */
- if (current_isect.type & PRIMITIVE_ALL_CURVE) {
- ctx->throughput *= intersection_curve_shadow_transparency(
- kg, current_isect.object, current_isect.prim, current_isect.u);
-
- if (ctx->throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
- ctx->opaque_hit = true;
- return;
- }
- else {
- *args->valid = 0;
- return;
- }
- }
-
- /* Test if we need to record this transparent intersection. */
- const uint max_record_hits = min(ctx->max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
- if (ctx->num_recorded_hits < max_record_hits || ray->tfar < ctx->max_t) {
- /* If maximum number of hits was reached, replace the intersection with the
- * highest distance. We want to find the N closest intersections. */
- const uint num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits);
- uint isect_index = num_recorded_hits;
- if (num_recorded_hits + 1 >= max_record_hits) {
- float max_t = ctx->isect_s[0].t;
- uint max_recorded_hit = 0;
-
- for (uint i = 1; i < num_recorded_hits; ++i) {
- if (ctx->isect_s[i].t > max_t) {
- max_recorded_hit = i;
- max_t = ctx->isect_s[i].t;
- }
- }
-
- if (num_recorded_hits >= max_record_hits) {
- isect_index = max_recorded_hit;
- }
-
- /* Limit the ray distance and stop counting hits beyond this.
- * TODO: is there some way we can tell Embree to stop intersecting beyond
- * this distance when max number of hits is reached?. Or maybe it will
- * become irrelevant if we make max_hits a very high number on the CPU. */
- ctx->max_t = max(current_isect.t, max_t);
- }
-
- ctx->isect_s[isect_index] = current_isect;
- }
-
- /* Always increase the number of recorded hits, even beyond the maximum,
- * so that we can detect this and trace another ray if needed. */
- ++ctx->num_recorded_hits;
-
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
- case CCLIntersectContext::RAY_LOCAL:
- case CCLIntersectContext::RAY_SSS: {
- /* Check if it's hitting the correct object. */
- Intersection current_isect;
- if (ctx->type == CCLIntersectContext::RAY_SSS) {
- kernel_embree_convert_sss_hit(kg, ray, hit, &current_isect, ctx->local_object_id);
- }
- else {
- kernel_embree_convert_hit(kg, ray, hit, &current_isect);
- if (ctx->local_object_id != current_isect.object) {
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
- }
-
- /* No intersection information requested, just return a hit. */
- if (ctx->max_hits == 0) {
- break;
- }
-
- /* Ignore curves. */
- if (IS_HAIR(hit->geomID)) {
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
-
- LocalIntersection *local_isect = ctx->local_isect;
- int hit_idx = 0;
-
- if (ctx->lcg_state) {
- /* See triangle_intersect_subsurface() for the native equivalent. */
- for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
- if (local_isect->hits[i].t == ray->tfar) {
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- return;
- }
- }
-
- local_isect->num_hits++;
-
- if (local_isect->num_hits <= ctx->max_hits) {
- hit_idx = local_isect->num_hits - 1;
- }
- else {
- /* reservoir sampling: if we are at the maximum number of
- * hits, randomly replace element or skip it */
- hit_idx = lcg_step_uint(ctx->lcg_state) % local_isect->num_hits;
-
- if (hit_idx >= ctx->max_hits) {
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- return;
- }
- }
- }
- else {
- /* Record closest intersection only. */
- if (local_isect->num_hits && current_isect.t > local_isect->hits[0].t) {
- *args->valid = 0;
- return;
- }
-
- local_isect->num_hits = 1;
- }
-
- /* record intersection */
- local_isect->hits[hit_idx] = current_isect;
- local_isect->Ng[hit_idx] = normalize(make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z));
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
- case CCLIntersectContext::RAY_VOLUME_ALL: {
- /* Append the intersection to the end of the array. */
- if (ctx->num_hits < ctx->max_hits) {
- Intersection current_isect;
- kernel_embree_convert_hit(kg, ray, hit, &current_isect);
- Intersection *isect = &ctx->isect_s[ctx->num_hits];
- ++ctx->num_hits;
- *isect = current_isect;
- /* Only primitives from volume object. */
- uint tri_object = isect->object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
- if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
- --ctx->num_hits;
- }
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
- }
- case CCLIntersectContext::RAY_REGULAR:
- default:
- /* Nothing to do here. */
- break;
- }
-}
-
-static void rtc_filter_func_thick_curve(const RTCFilterFunctionNArguments *args)
-{
- const RTCRay *ray = (RTCRay *)args->ray;
- RTCHit *hit = (RTCHit *)args->hit;
-
- /* Always ignore back-facing intersections. */
- if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
- make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
- *args->valid = 0;
- return;
- }
-}
-
-static void rtc_filter_occluded_func_thick_curve(const RTCFilterFunctionNArguments *args)
-{
- const RTCRay *ray = (RTCRay *)args->ray;
- RTCHit *hit = (RTCHit *)args->hit;
-
- /* Always ignore back-facing intersections. */
- if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
- make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
- *args->valid = 0;
- return;
- }
-
- rtc_filter_occluded_func(args);
-}
-
-static size_t unaccounted_mem = 0;
-
-static bool rtc_memory_monitor_func(void *userPtr, const ssize_t bytes, const bool)
-{
- Stats *stats = (Stats *)userPtr;
- if (stats) {
- if (bytes > 0) {
- stats->mem_alloc(bytes);
- }
- else {
- stats->mem_free(-bytes);
- }
- }
- else {
- /* A stats pointer may not yet be available. Keep track of the memory usage for later. */
- if (bytes >= 0) {
- atomic_add_and_fetch_z(&unaccounted_mem, bytes);
- }
- else {
- atomic_sub_and_fetch_z(&unaccounted_mem, -bytes);
- }
- }
- return true;
-}
-
-static void rtc_error_func(void *, enum RTCError, const char *str)
-{
- VLOG(1) << str;
-}
-
-static double progress_start_time = 0.0f;
-
-static bool rtc_progress_func(void *user_ptr, const double n)
-{
- Progress *progress = (Progress *)user_ptr;
-
- if (time_dt() - progress_start_time < 0.25) {
- return true;
- }
-
- string msg = string_printf("Building BVH %.0f%%", n * 100.0);
- progress->set_substatus(msg);
- progress_start_time = time_dt();
-
- return !progress->get_cancel();
-}
-
-BVHEmbree::BVHEmbree(const BVHParams &params_,
- const vector<Geometry *> &geometry_,
- const vector<Object *> &objects_)
- : BVH(params_, geometry_, objects_),
- scene(NULL),
- rtc_device(NULL),
- build_quality(RTC_BUILD_QUALITY_REFIT)
-{
- SIMD_SET_FLUSH_TO_ZERO;
-}
-
-BVHEmbree::~BVHEmbree()
-{
- if (scene) {
- rtcReleaseScene(scene);
- }
-}
-
-void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
-{
- rtc_device = rtc_device_;
- assert(rtc_device);
-
- rtcSetDeviceErrorFunction(rtc_device, rtc_error_func, NULL);
- rtcSetDeviceMemoryMonitorFunction(rtc_device, rtc_memory_monitor_func, stats);
-
- progress.set_substatus("Building BVH");
-
- if (scene) {
- rtcReleaseScene(scene);
- scene = NULL;
- }
-
- const bool dynamic = params.bvh_type == BVH_TYPE_DYNAMIC;
-
- scene = rtcNewScene(rtc_device);
- const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
- RTC_SCENE_FLAG_COMPACT | RTC_SCENE_FLAG_ROBUST;
- rtcSetSceneFlags(scene, scene_flags);
- build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
- (params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH :
- RTC_BUILD_QUALITY_MEDIUM);
- rtcSetSceneBuildQuality(scene, build_quality);
-
- int i = 0;
- foreach (Object *ob, objects) {
- if (params.top_level) {
- if (!ob->is_traceable()) {
- ++i;
- continue;
- }
- if (!ob->get_geometry()->is_instanced()) {
- add_object(ob, i);
- }
- else {
- add_instance(ob, i);
- }
- }
- else {
- add_object(ob, i);
- }
- ++i;
- if (progress.get_cancel())
- return;
- }
-
- if (progress.get_cancel()) {
- return;
- }
-
- rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
- rtcCommitScene(scene);
-}
-
-void BVHEmbree::add_object(Object *ob, int i)
-{
- Geometry *geom = ob->get_geometry();
-
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (mesh->num_triangles() > 0) {
- add_triangles(ob, mesh, i);
- }
- }
- else if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- if (hair->num_curves() > 0) {
- add_curves(ob, hair, i);
- }
- }
-}
-
-void BVHEmbree::add_instance(Object *ob, int i)
-{
- BVHEmbree *instance_bvh = (BVHEmbree *)(ob->get_geometry()->bvh);
- assert(instance_bvh != NULL);
-
- const size_t num_object_motion_steps = ob->use_motion() ? ob->get_motion().size() : 1;
- const size_t num_motion_steps = min(num_object_motion_steps, RTC_MAX_TIME_STEP_COUNT);
- assert(num_object_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
-
- RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_INSTANCE);
- rtcSetGeometryInstancedScene(geom_id, instance_bvh->scene);
- rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
-
- if (ob->use_motion()) {
- array<DecomposedTransform> decomp(ob->get_motion().size());
- transform_motion_decompose(decomp.data(), ob->get_motion().data(), ob->get_motion().size());
- for (size_t step = 0; step < num_motion_steps; ++step) {
- RTCQuaternionDecomposition rtc_decomp;
- rtcInitQuaternionDecomposition(&rtc_decomp);
- rtcQuaternionDecompositionSetQuaternion(
- &rtc_decomp, decomp[step].x.w, decomp[step].x.x, decomp[step].x.y, decomp[step].x.z);
- rtcQuaternionDecompositionSetScale(
- &rtc_decomp, decomp[step].y.w, decomp[step].z.w, decomp[step].w.w);
- rtcQuaternionDecompositionSetTranslation(
- &rtc_decomp, decomp[step].y.x, decomp[step].y.y, decomp[step].y.z);
- rtcQuaternionDecompositionSetSkew(
- &rtc_decomp, decomp[step].z.x, decomp[step].z.y, decomp[step].w.x);
- rtcSetGeometryTransformQuaternion(geom_id, step, &rtc_decomp);
- }
- }
- else {
- rtcSetGeometryTransform(
- geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float *)&ob->get_tfm());
- }
-
- rtcSetGeometryUserData(geom_id, (void *)instance_bvh->scene);
- rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
-
- rtcCommitGeometry(geom_id);
- rtcAttachGeometryByID(scene, geom_id, i * 2);
- rtcReleaseGeometry(geom_id);
-}
-
-void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
-{
- size_t prim_offset = mesh->prim_offset;
-
- const Attribute *attr_mP = NULL;
- size_t num_motion_steps = 1;
- if (mesh->has_motion_blur()) {
- attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (attr_mP) {
- num_motion_steps = mesh->get_motion_steps();
- }
- }
-
- assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
- num_motion_steps = min(num_motion_steps, RTC_MAX_TIME_STEP_COUNT);
-
- const size_t num_triangles = mesh->num_triangles();
-
- RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_TRIANGLE);
- rtcSetGeometryBuildQuality(geom_id, build_quality);
- rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
-
- unsigned *rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
- geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(int) * 3, num_triangles);
- assert(rtc_indices);
- if (!rtc_indices) {
- VLOG(1) << "Embree could not create new geometry buffer for mesh " << mesh->name.c_str()
- << ".\n";
- return;
- }
- for (size_t j = 0; j < num_triangles; ++j) {
- Mesh::Triangle t = mesh->get_triangle(j);
- rtc_indices[j * 3] = t.v[0];
- rtc_indices[j * 3 + 1] = t.v[1];
- rtc_indices[j * 3 + 2] = t.v[2];
- }
-
- set_tri_vertex_buffer(geom_id, mesh, false);
-
- rtcSetGeometryUserData(geom_id, (void *)prim_offset);
- rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
- rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
-
- rtcCommitGeometry(geom_id);
- rtcAttachGeometryByID(scene, geom_id, i * 2);
- rtcReleaseGeometry(geom_id);
-}
-
-void BVHEmbree::set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, const bool update)
-{
- const Attribute *attr_mP = NULL;
- size_t num_motion_steps = 1;
- int t_mid = 0;
- if (mesh->has_motion_blur()) {
- attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (attr_mP) {
- num_motion_steps = mesh->get_motion_steps();
- t_mid = (num_motion_steps - 1) / 2;
- if (num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
- assert(0);
- num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
- }
- }
- }
- const size_t num_verts = mesh->get_verts().size();
-
- for (int t = 0; t < num_motion_steps; ++t) {
- const float3 *verts;
- if (t == t_mid) {
- verts = mesh->get_verts().data();
- }
- else {
- int t_ = (t > t_mid) ? (t - 1) : t;
- verts = &attr_mP->data_float3()[t_ * num_verts];
- }
-
- float *rtc_verts = (update) ?
- (float *)rtcGetGeometryBufferData(geom_id, RTC_BUFFER_TYPE_VERTEX, t) :
- (float *)rtcSetNewGeometryBuffer(geom_id,
- RTC_BUFFER_TYPE_VERTEX,
- t,
- RTC_FORMAT_FLOAT3,
- sizeof(float) * 3,
- num_verts + 1);
-
- assert(rtc_verts);
- if (rtc_verts) {
- for (size_t j = 0; j < num_verts; ++j) {
- rtc_verts[0] = verts[j].x;
- rtc_verts[1] = verts[j].y;
- rtc_verts[2] = verts[j].z;
- rtc_verts += 3;
- }
- }
-
- if (update) {
- rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
- }
- }
-}
-
-void BVHEmbree::set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, const bool update)
-{
- const Attribute *attr_mP = NULL;
- size_t num_motion_steps = 1;
- if (hair->has_motion_blur()) {
- attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (attr_mP) {
- num_motion_steps = hair->get_motion_steps();
- }
- }
-
- const size_t num_curves = hair->num_curves();
- size_t num_keys = 0;
- for (size_t j = 0; j < num_curves; ++j) {
- const Hair::Curve c = hair->get_curve(j);
- num_keys += c.num_keys;
- }
-
- /* Catmull-Rom splines need extra CVs at the beginning and end of each curve. */
- size_t num_keys_embree = num_keys;
- num_keys_embree += num_curves * 2;
-
- /* Copy the CV data to Embree */
- const int t_mid = (num_motion_steps - 1) / 2;
- const float *curve_radius = &hair->get_curve_radius()[0];
- for (int t = 0; t < num_motion_steps; ++t) {
- const float3 *verts;
- if (t == t_mid || attr_mP == NULL) {
- verts = &hair->get_curve_keys()[0];
- }
- else {
- int t_ = (t > t_mid) ? (t - 1) : t;
- verts = &attr_mP->data_float3()[t_ * num_keys];
- }
-
- float4 *rtc_verts = (update) ? (float4 *)rtcGetGeometryBufferData(
- geom_id, RTC_BUFFER_TYPE_VERTEX, t) :
- (float4 *)rtcSetNewGeometryBuffer(geom_id,
- RTC_BUFFER_TYPE_VERTEX,
- t,
- RTC_FORMAT_FLOAT4,
- sizeof(float) * 4,
- num_keys_embree);
-
- assert(rtc_verts);
- if (rtc_verts) {
- const size_t num_curves = hair->num_curves();
- for (size_t j = 0; j < num_curves; ++j) {
- Hair::Curve c = hair->get_curve(j);
- int fk = c.first_key;
- int k = 1;
- for (; k < c.num_keys + 1; ++k, ++fk) {
- rtc_verts[k] = float3_to_float4(verts[fk]);
- rtc_verts[k].w = curve_radius[fk];
- }
- /* Duplicate Embree's Catmull-Rom spline CVs at the start and end of each curve. */
- rtc_verts[0] = rtc_verts[1];
- rtc_verts[k] = rtc_verts[k - 1];
- rtc_verts += c.num_keys + 2;
- }
- }
-
- if (update) {
- rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
- }
- }
-}
-
-void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
-{
- size_t prim_offset = hair->curve_segment_offset;
-
- const Attribute *attr_mP = NULL;
- size_t num_motion_steps = 1;
- if (hair->has_motion_blur()) {
- attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (attr_mP) {
- num_motion_steps = hair->get_motion_steps();
- }
- }
-
- assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
- num_motion_steps = min(num_motion_steps, RTC_MAX_TIME_STEP_COUNT);
-
- const size_t num_curves = hair->num_curves();
- size_t num_segments = 0;
- for (size_t j = 0; j < num_curves; ++j) {
- Hair::Curve c = hair->get_curve(j);
- assert(c.num_segments() > 0);
- num_segments += c.num_segments();
- }
-
- enum RTCGeometryType type = (hair->curve_shape == CURVE_RIBBON ?
- RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE :
- RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE);
-
- RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
- rtcSetGeometryTessellationRate(geom_id, params.curve_subdivisions + 1);
- unsigned *rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
- geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof(int), num_segments);
- size_t rtc_index = 0;
- for (size_t j = 0; j < num_curves; ++j) {
- Hair::Curve c = hair->get_curve(j);
- for (size_t k = 0; k < c.num_segments(); ++k) {
- rtc_indices[rtc_index] = c.first_key + k;
- /* Room for extra CVs at Catmull-Rom splines. */
- rtc_indices[rtc_index] += j * 2;
-
- ++rtc_index;
- }
- }
-
- rtcSetGeometryBuildQuality(geom_id, build_quality);
- rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
-
- set_curve_vertex_buffer(geom_id, hair, false);
-
- rtcSetGeometryUserData(geom_id, (void *)prim_offset);
- if (hair->curve_shape == CURVE_RIBBON) {
- rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
- }
- else {
- rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_thick_curve);
- rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_thick_curve);
- }
- rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
-
- rtcCommitGeometry(geom_id);
- rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);
- rtcReleaseGeometry(geom_id);
-}
-
-void BVHEmbree::refit(Progress &progress)
-{
- progress.set_substatus("Refitting BVH nodes");
-
- /* Update all vertex buffers, then tell Embree to rebuild/-fit the BVHs. */
- unsigned geom_id = 0;
- foreach (Object *ob, objects) {
- if (!params.top_level || (ob->is_traceable() && !ob->get_geometry()->is_instanced())) {
- Geometry *geom = ob->get_geometry();
-
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (mesh->num_triangles() > 0) {
- RTCGeometry geom = rtcGetGeometry(scene, geom_id);
- set_tri_vertex_buffer(geom, mesh, true);
- rtcSetGeometryUserData(geom, (void *)mesh->prim_offset);
- rtcCommitGeometry(geom);
- }
- }
- else if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- if (hair->num_curves() > 0) {
- RTCGeometry geom = rtcGetGeometry(scene, geom_id + 1);
- set_curve_vertex_buffer(geom, hair, true);
- rtcSetGeometryUserData(geom, (void *)hair->curve_segment_offset);
- rtcCommitGeometry(geom);
- }
- }
- }
- geom_id += 2;
- }
-
- rtcCommitScene(scene);
-}
-
-CCL_NAMESPACE_END
-
-#endif /* WITH_EMBREE */
diff --git a/intern/cycles/bvh/bvh_embree.h b/intern/cycles/bvh/bvh_embree.h
deleted file mode 100644
index 01636fbd1dc..00000000000
--- a/intern/cycles/bvh/bvh_embree.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2018, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BVH_EMBREE_H__
-#define __BVH_EMBREE_H__
-
-#ifdef WITH_EMBREE
-
-# include <embree3/rtcore.h>
-# include <embree3/rtcore_scene.h>
-
-# include "bvh/bvh.h"
-# include "bvh/bvh_params.h"
-
-# include "util/util_thread.h"
-# include "util/util_types.h"
-# include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Hair;
-class Mesh;
-
-class BVHEmbree : public BVH {
- public:
- void build(Progress &progress, Stats *stats, RTCDevice rtc_device);
- void refit(Progress &progress);
-
- RTCScene scene;
-
- protected:
- friend class BVH;
- BVHEmbree(const BVHParams &params,
- const vector<Geometry *> &geometry,
- const vector<Object *> &objects);
- virtual ~BVHEmbree();
-
- void add_object(Object *ob, int i);
- void add_instance(Object *ob, int i);
- void add_curves(const Object *ob, const Hair *hair, int i);
- void add_triangles(const Object *ob, const Mesh *mesh, int i);
-
- private:
- void set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, const bool update);
- void set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, const bool update);
-
- RTCDevice rtc_device;
- enum RTCBuildQuality build_quality;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* WITH_EMBREE */
-
-#endif /* __BVH_EMBREE_H__ */
diff --git a/intern/cycles/bvh/bvh_multi.cpp b/intern/cycles/bvh/bvh_multi.cpp
deleted file mode 100644
index a9e771f20f1..00000000000
--- a/intern/cycles/bvh/bvh_multi.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2020, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bvh/bvh_multi.h"
-
-#include "util/util_foreach.h"
-
-CCL_NAMESPACE_BEGIN
-
-BVHMulti::BVHMulti(const BVHParams &params_,
- const vector<Geometry *> &geometry_,
- const vector<Object *> &objects_)
- : BVH(params_, geometry_, objects_)
-{
-}
-
-BVHMulti::~BVHMulti()
-{
- foreach (BVH *bvh, sub_bvhs) {
- delete bvh;
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_multi.h b/intern/cycles/bvh/bvh_multi.h
deleted file mode 100644
index 840438c5d0c..00000000000
--- a/intern/cycles/bvh/bvh_multi.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2020, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BVH_MULTI_H__
-#define __BVH_MULTI_H__
-
-#include "bvh/bvh.h"
-#include "bvh/bvh_params.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BVHMulti : public BVH {
- public:
- vector<BVH *> sub_bvhs;
-
- protected:
- friend class BVH;
- BVHMulti(const BVHParams &params,
- const vector<Geometry *> &geometry,
- const vector<Object *> &objects);
- virtual ~BVHMulti();
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BVH_MULTI_H__ */
diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp
deleted file mode 100644
index 38b554acfbf..00000000000
--- a/intern/cycles/bvh/bvh_node.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Adapted from code copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bvh/bvh_node.h"
-
-#include "bvh/bvh.h"
-#include "bvh/bvh_build.h"
-
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* BVH Node */
-
-int BVHNode::getSubtreeSize(BVH_STAT stat) const
-{
- int cnt = 0;
-
- switch (stat) {
- case BVH_STAT_NODE_COUNT:
- cnt = 1;
- break;
- case BVH_STAT_LEAF_COUNT:
- cnt = is_leaf() ? 1 : 0;
- break;
- case BVH_STAT_INNER_COUNT:
- cnt = is_leaf() ? 0 : 1;
- break;
- case BVH_STAT_TRIANGLE_COUNT:
- cnt = is_leaf() ? reinterpret_cast<const LeafNode *>(this)->num_triangles() : 0;
- break;
- case BVH_STAT_CHILDNODE_COUNT:
- cnt = num_children();
- break;
- case BVH_STAT_ALIGNED_COUNT:
- if (!is_unaligned) {
- cnt = 1;
- }
- break;
- case BVH_STAT_UNALIGNED_COUNT:
- if (is_unaligned) {
- cnt = 1;
- }
- break;
- case BVH_STAT_ALIGNED_INNER_COUNT:
- if (!is_leaf()) {
- bool has_unaligned = false;
- for (int j = 0; j < num_children(); j++) {
- has_unaligned |= get_child(j)->is_unaligned;
- }
- cnt += has_unaligned ? 0 : 1;
- }
- break;
- case BVH_STAT_UNALIGNED_INNER_COUNT:
- if (!is_leaf()) {
- bool has_unaligned = false;
- for (int j = 0; j < num_children(); j++) {
- has_unaligned |= get_child(j)->is_unaligned;
- }
- cnt += has_unaligned ? 1 : 0;
- }
- break;
- case BVH_STAT_ALIGNED_LEAF_COUNT:
- cnt = (is_leaf() && !is_unaligned) ? 1 : 0;
- break;
- case BVH_STAT_UNALIGNED_LEAF_COUNT:
- cnt = (is_leaf() && is_unaligned) ? 1 : 0;
- break;
- case BVH_STAT_DEPTH:
- if (is_leaf()) {
- cnt = 1;
- }
- else {
- for (int i = 0; i < num_children(); i++) {
- cnt = max(cnt, get_child(i)->getSubtreeSize(stat));
- }
- cnt += 1;
- }
- return cnt;
- default:
- assert(0); /* unknown mode */
- }
-
- if (!is_leaf())
- for (int i = 0; i < num_children(); i++)
- cnt += get_child(i)->getSubtreeSize(stat);
-
- return cnt;
-}
-
-void BVHNode::deleteSubtree()
-{
- for (int i = 0; i < num_children(); i++)
- if (get_child(i))
- get_child(i)->deleteSubtree();
-
- delete this;
-}
-
-float BVHNode::computeSubtreeSAHCost(const BVHParams &p, float probability) const
-{
- float SAH = probability * p.cost(num_children(), num_triangles());
-
- for (int i = 0; i < num_children(); i++) {
- BVHNode *child = get_child(i);
- SAH += child->computeSubtreeSAHCost(
- p, probability * child->bounds.safe_area() / bounds.safe_area());
- }
-
- return SAH;
-}
-
-uint BVHNode::update_visibility()
-{
- if (!is_leaf() && visibility == 0) {
- InnerNode *inner = (InnerNode *)this;
- BVHNode *child0 = inner->children[0];
- BVHNode *child1 = inner->children[1];
-
- visibility = child0->update_visibility() | child1->update_visibility();
- }
-
- return visibility;
-}
-
-void BVHNode::update_time()
-{
- if (!is_leaf()) {
- InnerNode *inner = (InnerNode *)this;
- BVHNode *child0 = inner->children[0];
- BVHNode *child1 = inner->children[1];
- child0->update_time();
- child1->update_time();
- time_from = min(child0->time_from, child1->time_from);
- time_to = max(child0->time_to, child1->time_to);
- }
-}
-
-namespace {
-
-struct DumpTraversalContext {
- /* Descriptor of wile where writing is happening. */
- FILE *stream;
- /* Unique identifier of the node current. */
- int id;
-};
-
-void dump_subtree(DumpTraversalContext *context, const BVHNode *node, const BVHNode *parent = NULL)
-{
- if (node->is_leaf()) {
- fprintf(context->stream,
- " node_%p [label=\"%d\",fillcolor=\"#ccccee\",style=filled]\n",
- node,
- context->id);
- }
- else {
- fprintf(context->stream,
- " node_%p [label=\"%d\",fillcolor=\"#cceecc\",style=filled]\n",
- node,
- context->id);
- }
- if (parent != NULL) {
- fprintf(context->stream, " node_%p -> node_%p;\n", parent, node);
- }
- context->id += 1;
- for (int i = 0; i < node->num_children(); ++i) {
- dump_subtree(context, node->get_child(i), node);
- }
-}
-
-} // namespace
-
-void BVHNode::dump_graph(const char *filename)
-{
- DumpTraversalContext context;
- context.stream = fopen(filename, "w");
- if (context.stream == NULL) {
- return;
- }
- context.id = 0;
- fprintf(context.stream, "digraph BVH {\n");
- dump_subtree(&context, this);
- fprintf(context.stream, "}\n");
- fclose(context.stream);
-}
-
-/* Inner Node */
-
-void InnerNode::print(int depth) const
-{
- for (int i = 0; i < depth; i++)
- printf(" ");
-
- printf("inner node %p\n", (void *)this);
-
- if (children[0])
- children[0]->print(depth + 1);
- if (children[1])
- children[1]->print(depth + 1);
-}
-
-void LeafNode::print(int depth) const
-{
- for (int i = 0; i < depth; i++)
- printf(" ");
-
- printf("leaf node %d to %d\n", lo, hi);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h
deleted file mode 100644
index b3b5c43a394..00000000000
--- a/intern/cycles/bvh/bvh_node.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Adapted from code copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BVH_NODE_H__
-#define __BVH_NODE_H__
-
-#include "util/util_boundbox.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-enum BVH_STAT {
- BVH_STAT_NODE_COUNT,
- BVH_STAT_INNER_COUNT,
- BVH_STAT_LEAF_COUNT,
- BVH_STAT_TRIANGLE_COUNT,
- BVH_STAT_CHILDNODE_COUNT,
- BVH_STAT_ALIGNED_COUNT,
- BVH_STAT_UNALIGNED_COUNT,
- BVH_STAT_ALIGNED_INNER_COUNT,
- BVH_STAT_UNALIGNED_INNER_COUNT,
- BVH_STAT_ALIGNED_LEAF_COUNT,
- BVH_STAT_UNALIGNED_LEAF_COUNT,
- BVH_STAT_DEPTH,
-};
-
-class BVHParams;
-
-class BVHNode {
- public:
- virtual ~BVHNode()
- {
- delete aligned_space;
- }
-
- virtual bool is_leaf() const = 0;
- virtual int num_children() const = 0;
- virtual BVHNode *get_child(int i) const = 0;
- virtual int num_triangles() const
- {
- return 0;
- }
- virtual void print(int depth = 0) const = 0;
-
- inline void set_aligned_space(const Transform &aligned_space)
- {
- is_unaligned = true;
- if (this->aligned_space == NULL) {
- this->aligned_space = new Transform(aligned_space);
- }
- else {
- *this->aligned_space = aligned_space;
- }
- }
-
- inline Transform get_aligned_space() const
- {
- if (aligned_space == NULL) {
- return transform_identity();
- }
- return *aligned_space;
- }
-
- inline bool has_unaligned() const
- {
- if (is_leaf()) {
- return false;
- }
- for (int i = 0; i < num_children(); ++i) {
- if (get_child(i)->is_unaligned) {
- return true;
- }
- }
- return false;
- }
-
- // Subtree functions
- int getSubtreeSize(BVH_STAT stat = BVH_STAT_NODE_COUNT) const;
- float computeSubtreeSAHCost(const BVHParams &p, float probability = 1.0f) const;
- void deleteSubtree();
-
- uint update_visibility();
- void update_time();
-
- /* Dump the content of the tree as a graphviz file. */
- void dump_graph(const char *filename);
-
- // Properties.
- BoundBox bounds;
- uint visibility;
-
- bool is_unaligned;
-
- /* TODO(sergey): Can be stored as 3x3 matrix, but better to have some
- * utilities and type defines in util_transform first.
- */
- Transform *aligned_space;
-
- float time_from, time_to;
-
- protected:
- explicit BVHNode(const BoundBox &bounds)
- : bounds(bounds),
- visibility(0),
- is_unaligned(false),
- aligned_space(NULL),
- time_from(0.0f),
- time_to(1.0f)
- {
- }
-
- explicit BVHNode(const BVHNode &other)
- : bounds(other.bounds),
- visibility(other.visibility),
- is_unaligned(other.is_unaligned),
- aligned_space(NULL),
- time_from(other.time_from),
- time_to(other.time_to)
- {
- if (other.aligned_space != NULL) {
- assert(other.is_unaligned);
- aligned_space = new Transform();
- *aligned_space = *other.aligned_space;
- }
- else {
- assert(!other.is_unaligned);
- }
- }
-};
-
-class InnerNode : public BVHNode {
- public:
- static constexpr int kNumMaxChildren = 8;
-
- InnerNode(const BoundBox &bounds, BVHNode *child0, BVHNode *child1)
- : BVHNode(bounds), num_children_(2)
- {
- children[0] = child0;
- children[1] = child1;
- reset_unused_children();
-
- if (child0 && child1) {
- visibility = child0->visibility | child1->visibility;
- }
- else {
- /* Happens on build cancel. */
- visibility = 0;
- }
- }
-
- InnerNode(const BoundBox &bounds, BVHNode **children, const int num_children)
- : BVHNode(bounds), num_children_(num_children)
- {
- visibility = 0;
- time_from = FLT_MAX;
- time_to = -FLT_MAX;
- for (int i = 0; i < num_children; ++i) {
- assert(children[i] != NULL);
- visibility |= children[i]->visibility;
- this->children[i] = children[i];
- time_from = min(time_from, children[i]->time_from);
- time_to = max(time_to, children[i]->time_to);
- }
- reset_unused_children();
- }
-
- /* NOTE: This function is only used during binary BVH builder, and it
- * supposed to be configured to have 2 children which will be filled-in in a
- * bit. But this is important to have children reset to NULL. */
- explicit InnerNode(const BoundBox &bounds) : BVHNode(bounds), num_children_(0)
- {
- reset_unused_children();
- visibility = 0;
- num_children_ = 2;
- }
-
- bool is_leaf() const
- {
- return false;
- }
- int num_children() const
- {
- return num_children_;
- }
- BVHNode *get_child(int i) const
- {
- assert(i >= 0 && i < num_children_);
- return children[i];
- }
- void print(int depth) const;
-
- int num_children_;
- BVHNode *children[kNumMaxChildren];
-
- protected:
- void reset_unused_children()
- {
- for (int i = num_children_; i < kNumMaxChildren; ++i) {
- children[i] = NULL;
- }
- }
-};
-
-class LeafNode : public BVHNode {
- public:
- LeafNode(const BoundBox &bounds, uint visibility, int lo, int hi)
- : BVHNode(bounds), lo(lo), hi(hi)
- {
- this->bounds = bounds;
- this->visibility = visibility;
- }
-
- LeafNode(const LeafNode &other) : BVHNode(other), lo(other.lo), hi(other.hi)
- {
- }
-
- bool is_leaf() const
- {
- return true;
- }
- int num_children() const
- {
- return 0;
- }
- BVHNode *get_child(int) const
- {
- return NULL;
- }
- int num_triangles() const
- {
- return hi - lo;
- }
- void print(int depth) const;
-
- int lo;
- int hi;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BVH_NODE_H__ */
diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp
deleted file mode 100644
index cd266f72f89..00000000000
--- a/intern/cycles/bvh/bvh_optix.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2019, NVIDIA Corporation.
- * Copyright 2019, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifdef WITH_OPTIX
-
-# include "device/device.h"
-
-# include "bvh/bvh_optix.h"
-
-CCL_NAMESPACE_BEGIN
-
-BVHOptiX::BVHOptiX(const BVHParams &params_,
- const vector<Geometry *> &geometry_,
- const vector<Object *> &objects_,
- Device *device)
- : BVH(params_, geometry_, objects_),
- device(device),
- traversable_handle(0),
- as_data(device, params_.top_level ? "optix tlas" : "optix blas", false),
- motion_transform_data(device, "optix motion transform", false)
-{
-}
-
-BVHOptiX::~BVHOptiX()
-{
- // Acceleration structure memory is delayed freed on device, since deleting the
- // BVH may happen while still being used for rendering.
- device->release_optix_bvh(this);
-}
-
-CCL_NAMESPACE_END
-
-#endif /* WITH_OPTIX */
diff --git a/intern/cycles/bvh/bvh_optix.h b/intern/cycles/bvh/bvh_optix.h
deleted file mode 100644
index ba5d90471d1..00000000000
--- a/intern/cycles/bvh/bvh_optix.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2019, NVIDIA Corporation.
- * Copyright 2019, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BVH_OPTIX_H__
-#define __BVH_OPTIX_H__
-
-#ifdef WITH_OPTIX
-
-# include "bvh/bvh.h"
-# include "bvh/bvh_params.h"
-# include "device/device_memory.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BVHOptiX : public BVH {
- public:
- Device *device;
- uint64_t traversable_handle;
- device_only_memory<char> as_data;
- device_only_memory<char> motion_transform_data;
-
- protected:
- friend class BVH;
- BVHOptiX(const BVHParams &params,
- const vector<Geometry *> &geometry,
- const vector<Object *> &objects,
- Device *device);
- virtual ~BVHOptiX();
-};
-
-CCL_NAMESPACE_END
-
-#endif /* WITH_OPTIX */
-
-#endif /* __BVH_OPTIX_H__ */
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
deleted file mode 100644
index 31b3971c110..00000000000
--- a/intern/cycles/bvh/bvh_params.h
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Adapted from code copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BVH_PARAMS_H__
-#define __BVH_PARAMS_H__
-
-#include "util/util_boundbox.h"
-
-#include "kernel/kernel_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Layout of BVH tree.
- *
- * For example, how wide BVH tree is, in terms of number of children
- * per node.
- */
-typedef KernelBVHLayout BVHLayout;
-
-/* Type of BVH, in terms whether it is supported dynamic updates of meshes
- * or whether modifying geometry requires full BVH rebuild.
- */
-enum BVHType {
- /* BVH supports dynamic updates of geometry.
- *
- * Faster for updating BVH tree when doing modifications in viewport,
- * but slower for rendering.
- */
- BVH_TYPE_DYNAMIC = 0,
- /* BVH tree is calculated for specific scene, updates in geometry
- * requires full tree rebuild.
- *
- * Slower to update BVH tree when modifying objects in viewport, also
- * slower to build final BVH tree but gives best possible render speed.
- */
- BVH_TYPE_STATIC = 1,
-
- BVH_NUM_TYPES,
-};
-
-/* Names bitflag type to denote which BVH layouts are supported by
- * particular area.
- *
- * Bitflags are the BVH_LAYOUT_* values.
- */
-typedef int BVHLayoutMask;
-
-/* Get human readable name of BVH layout. */
-const char *bvh_layout_name(BVHLayout layout);
-
-/* BVH Parameters */
-
-class BVHParams {
- public:
- /* spatial split area threshold */
- bool use_spatial_split;
- float spatial_split_alpha;
-
- /* Unaligned nodes creation threshold */
- float unaligned_split_threshold;
-
- /* SAH costs */
- float sah_node_cost;
- float sah_primitive_cost;
-
- /* number of primitives in leaf */
- int min_leaf_size;
- int max_triangle_leaf_size;
- int max_motion_triangle_leaf_size;
- int max_curve_leaf_size;
- int max_motion_curve_leaf_size;
-
- /* object or mesh level bvh */
- bool top_level;
-
- /* BVH layout to be built. */
- BVHLayout bvh_layout;
-
- /* Use unaligned bounding boxes.
- * Only used for curves BVH.
- */
- bool use_unaligned_nodes;
-
- /* Split time range to this number of steps and create leaf node for each
- * of this time steps.
- *
- * Speeds up rendering of motion curve primitives in the cost of higher
- * memory usage.
- */
- int num_motion_curve_steps;
-
- /* Same as above, but for triangle primitives. */
- int num_motion_triangle_steps;
-
- /* Same as in SceneParams. */
- int bvh_type;
-
- /* These are needed for Embree. */
- int curve_subdivisions;
-
- /* fixed parameters */
- enum { MAX_DEPTH = 64, MAX_SPATIAL_DEPTH = 48, NUM_SPATIAL_BINS = 32 };
-
- BVHParams()
- {
- use_spatial_split = true;
- spatial_split_alpha = 1e-5f;
-
- unaligned_split_threshold = 0.7f;
-
- /* todo: see if splitting up primitive cost to be separate for triangles
- * and curves can help. so far in tests it doesn't help, but why? */
- sah_node_cost = 1.0f;
- sah_primitive_cost = 1.0f;
-
- min_leaf_size = 1;
- max_triangle_leaf_size = 8;
- max_motion_triangle_leaf_size = 8;
- max_curve_leaf_size = 1;
- max_motion_curve_leaf_size = 4;
-
- top_level = false;
- bvh_layout = BVH_LAYOUT_BVH2;
- use_unaligned_nodes = false;
-
- num_motion_curve_steps = 0;
- num_motion_triangle_steps = 0;
-
- bvh_type = 0;
-
- curve_subdivisions = 4;
- }
-
- /* SAH costs */
- __forceinline float cost(int num_nodes, int num_primitives) const
- {
- return node_cost(num_nodes) + primitive_cost(num_primitives);
- }
-
- __forceinline float primitive_cost(int n) const
- {
- return n * sah_primitive_cost;
- }
-
- __forceinline float node_cost(int n) const
- {
- return n * sah_node_cost;
- }
-
- __forceinline bool small_enough_for_leaf(int size, int level)
- {
- return (size <= min_leaf_size || level >= MAX_DEPTH);
- }
-
- /* Gets best matching BVH.
- *
- * If the requested layout is supported by the device, it will be used.
- * Otherwise, widest supported layout below that will be used.
- */
- static BVHLayout best_bvh_layout(BVHLayout requested_layout, BVHLayoutMask supported_layouts);
-};
-
-/* BVH Reference
- *
- * Reference to a primitive. Primitive index and object are sneakily packed
- * into BoundBox to reduce memory usage and align nicely */
-
-class BVHReference {
- public:
- __forceinline BVHReference()
- {
- }
-
- __forceinline BVHReference(const BoundBox &bounds_,
- int prim_index_,
- int prim_object_,
- int prim_type,
- float time_from = 0.0f,
- float time_to = 1.0f)
- : rbounds(bounds_), time_from_(time_from), time_to_(time_to)
- {
- rbounds.min.w = __int_as_float(prim_index_);
- rbounds.max.w = __int_as_float(prim_object_);
- type = prim_type;
- }
-
- __forceinline const BoundBox &bounds() const
- {
- return rbounds;
- }
- __forceinline int prim_index() const
- {
- return __float_as_int(rbounds.min.w);
- }
- __forceinline int prim_object() const
- {
- return __float_as_int(rbounds.max.w);
- }
- __forceinline int prim_type() const
- {
- return type;
- }
- __forceinline float time_from() const
- {
- return time_from_;
- }
- __forceinline float time_to() const
- {
- return time_to_;
- }
-
- BVHReference &operator=(const BVHReference &arg)
- {
- if (&arg != this) {
- /* TODO(sergey): Check if it is still faster to memcpy() with
- * modern compilers.
- */
- memcpy((void *)this, &arg, sizeof(BVHReference));
- }
- return *this;
- }
-
- protected:
- BoundBox rbounds;
- uint type;
- float time_from_, time_to_;
-};
-
-/* BVH Range
- *
- * Build range used during construction, to indicate the bounds and place in
- * the reference array of a subset of primitives Again uses trickery to pack
- * integers into BoundBox for alignment purposes. */
-
-class BVHRange {
- public:
- __forceinline BVHRange()
- {
- rbounds.min.w = __int_as_float(0);
- rbounds.max.w = __int_as_float(0);
- }
-
- __forceinline BVHRange(const BoundBox &bounds_, int start_, int size_) : rbounds(bounds_)
- {
- rbounds.min.w = __int_as_float(start_);
- rbounds.max.w = __int_as_float(size_);
- }
-
- __forceinline BVHRange(const BoundBox &bounds_, const BoundBox &cbounds_, int start_, int size_)
- : rbounds(bounds_), cbounds(cbounds_)
- {
- rbounds.min.w = __int_as_float(start_);
- rbounds.max.w = __int_as_float(size_);
- }
-
- __forceinline void set_start(int start_)
- {
- rbounds.min.w = __int_as_float(start_);
- }
-
- __forceinline const BoundBox &bounds() const
- {
- return rbounds;
- }
- __forceinline const BoundBox &cent_bounds() const
- {
- return cbounds;
- }
- __forceinline int start() const
- {
- return __float_as_int(rbounds.min.w);
- }
- __forceinline int size() const
- {
- return __float_as_int(rbounds.max.w);
- }
- __forceinline int end() const
- {
- return start() + size();
- }
-
- protected:
- BoundBox rbounds;
- BoundBox cbounds;
-};
-
-/* BVH Spatial Bin */
-
-struct BVHSpatialBin {
- BoundBox bounds;
- int enter;
- int exit;
-
- __forceinline BVHSpatialBin()
- {
- }
-};
-
-/* BVH Spatial Storage
- *
- * The idea of this storage is have thread-specific storage for the spatial
- * splitters. We can pre-allocate this storage in advance and avoid heavy memory
- * operations during split process.
- */
-
-struct BVHSpatialStorage {
- /* Accumulated bounds when sweeping from right to left. */
- vector<BoundBox> right_bounds;
-
- /* Bins used for histogram when selecting best split plane. */
- BVHSpatialBin bins[3][BVHParams::NUM_SPATIAL_BINS];
-
- /* Temporary storage for the new references. Used by spatial split to store
- * new references in before they're getting inserted into actual array,
- */
- vector<BVHReference> new_references;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BVH_PARAMS_H__ */
diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp
deleted file mode 100644
index b01785b547a..00000000000
--- a/intern/cycles/bvh/bvh_sort.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Adapted from code copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bvh/bvh_sort.h"
-
-#include "bvh/bvh_build.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_task.h"
-
-CCL_NAMESPACE_BEGIN
-
-static const int BVH_SORT_THRESHOLD = 4096;
-
-struct BVHReferenceCompare {
- public:
- int dim;
- const BVHUnaligned *unaligned_heuristic;
- const Transform *aligned_space;
-
- BVHReferenceCompare(int dim,
- const BVHUnaligned *unaligned_heuristic,
- const Transform *aligned_space)
- : dim(dim), unaligned_heuristic(unaligned_heuristic), aligned_space(aligned_space)
- {
- }
-
- __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
- {
- return (aligned_space != NULL) ?
- unaligned_heuristic->compute_aligned_prim_boundbox(prim, *aligned_space) :
- prim.bounds();
- }
-
- /* Compare two references.
- *
- * Returns value is similar to return value of strcmp().
- */
- __forceinline int compare(const BVHReference &ra, const BVHReference &rb) const
- {
- BoundBox ra_bounds = get_prim_bounds(ra), rb_bounds = get_prim_bounds(rb);
- float ca = ra_bounds.min[dim] + ra_bounds.max[dim];
- float cb = rb_bounds.min[dim] + rb_bounds.max[dim];
-
- if (ca < cb)
- return -1;
- else if (ca > cb)
- return 1;
- else if (ra.prim_object() < rb.prim_object())
- return -1;
- else if (ra.prim_object() > rb.prim_object())
- return 1;
- else if (ra.prim_index() < rb.prim_index())
- return -1;
- else if (ra.prim_index() > rb.prim_index())
- return 1;
- else if (ra.prim_type() < rb.prim_type())
- return -1;
- else if (ra.prim_type() > rb.prim_type())
- return 1;
-
- return 0;
- }
-
- bool operator()(const BVHReference &ra, const BVHReference &rb)
- {
- return (compare(ra, rb) < 0);
- }
-};
-
-static void bvh_reference_sort_threaded(TaskPool *task_pool,
- BVHReference *data,
- const int job_start,
- const int job_end,
- const BVHReferenceCompare &compare);
-
-/* Multi-threaded reference sort. */
-static void bvh_reference_sort_threaded(TaskPool *task_pool,
- BVHReference *data,
- const int job_start,
- const int job_end,
- const BVHReferenceCompare &compare)
-{
- int start = job_start, end = job_end;
- bool have_work = (start < end);
- while (have_work) {
- const int count = job_end - job_start;
- if (count < BVH_SORT_THRESHOLD) {
- /* Number of reference low enough, faster to finish the job
- * in one thread rather than to spawn more threads.
- */
- sort(data + job_start, data + job_end + 1, compare);
- break;
- }
- /* Single QSort step.
- * Use median-of-three method for the pivot point.
- */
- int left = start, right = end;
- int center = (left + right) >> 1;
- if (compare.compare(data[left], data[center]) > 0) {
- swap(data[left], data[center]);
- }
- if (compare.compare(data[left], data[right]) > 0) {
- swap(data[left], data[right]);
- }
- if (compare.compare(data[center], data[right]) > 0) {
- swap(data[center], data[right]);
- }
- swap(data[center], data[right - 1]);
- BVHReference median = data[right - 1];
- do {
- while (compare.compare(data[left], median) < 0) {
- ++left;
- }
- while (compare.compare(data[right], median) > 0) {
- --right;
- }
- if (left <= right) {
- swap(data[left], data[right]);
- ++left;
- --right;
- }
- } while (left <= right);
- /* We only create one new task here to reduce downside effects of
- * latency in TaskScheduler.
- * So generally current thread keeps working on the left part of the
- * array, and we create new task for the right side.
- * However, if there's nothing to be done in the left side of the array
- * we don't create any tasks and make it so current thread works on the
- * right side.
- */
- have_work = false;
- if (left < end) {
- if (start < right) {
- task_pool->push(
- function_bind(bvh_reference_sort_threaded, task_pool, data, left, end, compare));
- }
- else {
- start = left;
- have_work = true;
- }
- }
- if (start < right) {
- end = right;
- have_work = true;
- }
- }
-}
-
-void bvh_reference_sort(int start,
- int end,
- BVHReference *data,
- int dim,
- const BVHUnaligned *unaligned_heuristic,
- const Transform *aligned_space)
-{
- const int count = end - start;
- BVHReferenceCompare compare(dim, unaligned_heuristic, aligned_space);
- if (count < BVH_SORT_THRESHOLD) {
- /* It is important to not use any mutex if array is small enough,
- * otherwise we end up in situation when we're going to sleep far
- * too often.
- */
- sort(data + start, data + end, compare);
- }
- else {
- TaskPool task_pool;
- bvh_reference_sort_threaded(&task_pool, data, start, end - 1, compare);
- task_pool.wait_work();
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp
deleted file mode 100644
index d4c79253834..00000000000
--- a/intern/cycles/bvh/bvh_split.cpp
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Adapted from code copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bvh/bvh_split.h"
-
-#include "bvh/bvh_build.h"
-#include "bvh/bvh_sort.h"
-
-#include "render/hair.h"
-#include "render/mesh.h"
-#include "render/object.h"
-
-#include "util/util_algorithm.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Object Split */
-
-BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
- BVHSpatialStorage *storage,
- const BVHRange &range,
- vector<BVHReference> &references,
- float nodeSAH,
- const BVHUnaligned *unaligned_heuristic,
- const Transform *aligned_space)
- : sah(FLT_MAX),
- dim(0),
- num_left(0),
- left_bounds(BoundBox::empty),
- right_bounds(BoundBox::empty),
- storage_(storage),
- references_(&references),
- unaligned_heuristic_(unaligned_heuristic),
- aligned_space_(aligned_space)
-{
- const BVHReference *ref_ptr = &references_->at(range.start());
- float min_sah = FLT_MAX;
-
- storage_->right_bounds.resize(range.size());
-
- for (int dim = 0; dim < 3; dim++) {
- /* Sort references. */
- bvh_reference_sort(range.start(),
- range.end(),
- &references_->at(0),
- dim,
- unaligned_heuristic_,
- aligned_space_);
-
- /* sweep right to left and determine bounds. */
- BoundBox right_bounds = BoundBox::empty;
- for (int i = range.size() - 1; i > 0; i--) {
- BoundBox prim_bounds = get_prim_bounds(ref_ptr[i]);
- right_bounds.grow(prim_bounds);
- storage_->right_bounds[i - 1] = right_bounds;
- }
-
- /* sweep left to right and select lowest SAH. */
- BoundBox left_bounds = BoundBox::empty;
-
- for (int i = 1; i < range.size(); i++) {
- BoundBox prim_bounds = get_prim_bounds(ref_ptr[i - 1]);
- left_bounds.grow(prim_bounds);
- right_bounds = storage_->right_bounds[i - 1];
-
- float sah = nodeSAH + left_bounds.safe_area() * builder->params.primitive_cost(i) +
- right_bounds.safe_area() * builder->params.primitive_cost(range.size() - i);
-
- if (sah < min_sah) {
- min_sah = sah;
-
- this->sah = sah;
- this->dim = dim;
- this->num_left = i;
- this->left_bounds = left_bounds;
- this->right_bounds = right_bounds;
- }
- }
- }
-}
-
-void BVHObjectSplit::split(BVHRange &left, BVHRange &right, const BVHRange &range)
-{
- assert(references_->size() > 0);
- /* sort references according to split */
- bvh_reference_sort(range.start(),
- range.end(),
- &references_->at(0),
- this->dim,
- unaligned_heuristic_,
- aligned_space_);
-
- BoundBox effective_left_bounds, effective_right_bounds;
- const int num_right = range.size() - this->num_left;
- if (aligned_space_ == NULL) {
- effective_left_bounds = left_bounds;
- effective_right_bounds = right_bounds;
- }
- else {
- effective_left_bounds = BoundBox::empty;
- effective_right_bounds = BoundBox::empty;
- for (int i = 0; i < this->num_left; ++i) {
- BoundBox prim_boundbox = references_->at(range.start() + i).bounds();
- effective_left_bounds.grow(prim_boundbox);
- }
- for (int i = 0; i < num_right; ++i) {
- BoundBox prim_boundbox = references_->at(range.start() + this->num_left + i).bounds();
- effective_right_bounds.grow(prim_boundbox);
- }
- }
-
- /* split node ranges */
- left = BVHRange(effective_left_bounds, range.start(), this->num_left);
- right = BVHRange(effective_right_bounds, left.end(), num_right);
-}
-
-/* Spatial Split */
-
-BVHSpatialSplit::BVHSpatialSplit(const BVHBuild &builder,
- BVHSpatialStorage *storage,
- const BVHRange &range,
- vector<BVHReference> &references,
- float nodeSAH,
- const BVHUnaligned *unaligned_heuristic,
- const Transform *aligned_space)
- : sah(FLT_MAX),
- dim(0),
- pos(0.0f),
- storage_(storage),
- references_(&references),
- unaligned_heuristic_(unaligned_heuristic),
- aligned_space_(aligned_space)
-{
- /* initialize bins. */
- BoundBox range_bounds;
- if (aligned_space == NULL) {
- range_bounds = range.bounds();
- }
- else {
- range_bounds = unaligned_heuristic->compute_aligned_boundbox(
- range, &references_->at(0), *aligned_space);
- }
-
- float3 origin = range_bounds.min;
- float3 binSize = (range_bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
- float3 invBinSize = 1.0f / binSize;
-
- for (int dim = 0; dim < 3; dim++) {
- for (int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
- BVHSpatialBin &bin = storage_->bins[dim][i];
-
- bin.bounds = BoundBox::empty;
- bin.enter = 0;
- bin.exit = 0;
- }
- }
-
- /* chop references into bins. */
- for (unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) {
- const BVHReference &ref = references_->at(refIdx);
- BoundBox prim_bounds = get_prim_bounds(ref);
- float3 firstBinf = (prim_bounds.min - origin) * invBinSize;
- float3 lastBinf = (prim_bounds.max - origin) * invBinSize;
- int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
- int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z);
-
- firstBin = clamp(firstBin, 0, BVHParams::NUM_SPATIAL_BINS - 1);
- lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
-
- for (int dim = 0; dim < 3; dim++) {
- BVHReference currRef(
- get_prim_bounds(ref), ref.prim_index(), ref.prim_object(), ref.prim_type());
-
- for (int i = firstBin[dim]; i < lastBin[dim]; i++) {
- BVHReference leftRef, rightRef;
-
- split_reference(
- builder, leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
- storage_->bins[dim][i].bounds.grow(leftRef.bounds());
- currRef = rightRef;
- }
-
- storage_->bins[dim][lastBin[dim]].bounds.grow(currRef.bounds());
- storage_->bins[dim][firstBin[dim]].enter++;
- storage_->bins[dim][lastBin[dim]].exit++;
- }
- }
-
- /* select best split plane. */
- storage_->right_bounds.resize(BVHParams::NUM_SPATIAL_BINS);
- for (int dim = 0; dim < 3; dim++) {
- /* sweep right to left and determine bounds. */
- BoundBox right_bounds = BoundBox::empty;
- for (int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
- right_bounds.grow(storage_->bins[dim][i].bounds);
- storage_->right_bounds[i - 1] = right_bounds;
- }
-
- /* sweep left to right and select lowest SAH. */
- BoundBox left_bounds = BoundBox::empty;
- int leftNum = 0;
- int rightNum = range.size();
-
- for (int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
- left_bounds.grow(storage_->bins[dim][i - 1].bounds);
- leftNum += storage_->bins[dim][i - 1].enter;
- rightNum -= storage_->bins[dim][i - 1].exit;
-
- float sah = nodeSAH + left_bounds.safe_area() * builder.params.primitive_cost(leftNum) +
- storage_->right_bounds[i - 1].safe_area() *
- builder.params.primitive_cost(rightNum);
-
- if (sah < this->sah) {
- this->sah = sah;
- this->dim = dim;
- this->pos = origin[dim] + binSize[dim] * (float)i;
- }
- }
- }
-}
-
-void BVHSpatialSplit::split(BVHBuild *builder,
- BVHRange &left,
- BVHRange &right,
- const BVHRange &range)
-{
- /* Categorize references and compute bounds.
- *
- * Left-hand side: [left_start, left_end[
- * Uncategorized/split: [left_end, right_start[
- * Right-hand side: [right_start, refs.size()[ */
-
- vector<BVHReference> &refs = *references_;
- int left_start = range.start();
- int left_end = left_start;
- int right_start = range.end();
- int right_end = range.end();
- BoundBox left_bounds = BoundBox::empty;
- BoundBox right_bounds = BoundBox::empty;
-
- for (int i = left_end; i < right_start; i++) {
- BoundBox prim_bounds = get_prim_bounds(refs[i]);
- if (prim_bounds.max[this->dim] <= this->pos) {
- /* entirely on the left-hand side */
- left_bounds.grow(prim_bounds);
- swap(refs[i], refs[left_end++]);
- }
- else if (prim_bounds.min[this->dim] >= this->pos) {
- /* entirely on the right-hand side */
- right_bounds.grow(prim_bounds);
- swap(refs[i--], refs[--right_start]);
- }
- }
-
- /* Duplicate or unsplit references intersecting both sides.
- *
- * Duplication happens into a temporary pre-allocated vector in order to
- * reduce number of memmove() calls happening in vector.insert().
- */
- vector<BVHReference> &new_refs = storage_->new_references;
- new_refs.clear();
- new_refs.reserve(right_start - left_end);
- while (left_end < right_start) {
- /* split reference. */
- BVHReference curr_ref(get_prim_bounds(refs[left_end]),
- refs[left_end].prim_index(),
- refs[left_end].prim_object(),
- refs[left_end].prim_type());
- BVHReference lref, rref;
- split_reference(*builder, lref, rref, curr_ref, this->dim, this->pos);
-
- /* compute SAH for duplicate/unsplit candidates. */
- BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds.
- BoundBox rub = right_bounds; // Unsplit to right: new right-hand bounds.
- BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds.
- BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds.
-
- lub.grow(curr_ref.bounds());
- rub.grow(curr_ref.bounds());
- ldb.grow(lref.bounds());
- rdb.grow(rref.bounds());
-
- float lac = builder->params.primitive_cost(left_end - left_start);
- float rac = builder->params.primitive_cost(right_end - right_start);
- float lbc = builder->params.primitive_cost(left_end - left_start + 1);
- float rbc = builder->params.primitive_cost(right_end - right_start + 1);
-
- float unsplitLeftSAH = lub.safe_area() * lbc + right_bounds.safe_area() * rac;
- float unsplitRightSAH = left_bounds.safe_area() * lac + rub.safe_area() * rbc;
- float duplicateSAH = ldb.safe_area() * lbc + rdb.safe_area() * rbc;
- float minSAH = min(min(unsplitLeftSAH, unsplitRightSAH), duplicateSAH);
-
- if (minSAH == unsplitLeftSAH) {
- /* unsplit to left */
- left_bounds = lub;
- left_end++;
- }
- else if (minSAH == unsplitRightSAH) {
- /* unsplit to right */
- right_bounds = rub;
- swap(refs[left_end], refs[--right_start]);
- }
- else {
- /* duplicate */
- left_bounds = ldb;
- right_bounds = rdb;
- refs[left_end++] = lref;
- new_refs.push_back(rref);
- right_end++;
- }
- }
- /* Insert duplicated references into actual array in one go. */
- if (new_refs.size() != 0) {
- refs.insert(refs.begin() + (right_end - new_refs.size()), new_refs.begin(), new_refs.end());
- }
- if (aligned_space_ != NULL) {
- left_bounds = right_bounds = BoundBox::empty;
- for (int i = left_start; i < left_end - left_start; ++i) {
- BoundBox prim_boundbox = references_->at(i).bounds();
- left_bounds.grow(prim_boundbox);
- }
- for (int i = right_start; i < right_end - right_start; ++i) {
- BoundBox prim_boundbox = references_->at(i).bounds();
- right_bounds.grow(prim_boundbox);
- }
- }
- left = BVHRange(left_bounds, left_start, left_end - left_start);
- right = BVHRange(right_bounds, right_start, right_end - right_start);
-}
-
-void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh,
- const Transform *tfm,
- int prim_index,
- int dim,
- float pos,
- BoundBox &left_bounds,
- BoundBox &right_bounds)
-{
- Mesh::Triangle t = mesh->get_triangle(prim_index);
- const float3 *verts = &mesh->verts[0];
- float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]];
- v1 = get_unaligned_point(v1);
-
- for (int i = 0; i < 3; i++) {
- float3 v0 = v1;
- int vindex = t.v[i];
- v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex];
- v1 = get_unaligned_point(v1);
- float v0p = v0[dim];
- float v1p = v1[dim];
-
- /* insert vertex to the boxes it belongs to. */
- if (v0p <= pos)
- left_bounds.grow(v0);
-
- if (v0p >= pos)
- right_bounds.grow(v0);
-
- /* edge intersects the plane => insert intersection to both boxes. */
- if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
- float3 t = lerp(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
- left_bounds.grow(t);
- right_bounds.grow(t);
- }
- }
-}
-
-void BVHSpatialSplit::split_curve_primitive(const Hair *hair,
- const Transform *tfm,
- int prim_index,
- int segment_index,
- int dim,
- float pos,
- BoundBox &left_bounds,
- BoundBox &right_bounds)
-{
- /* curve split: NOTE - Currently ignores curve width and needs to be fixed. */
- Hair::Curve curve = hair->get_curve(prim_index);
- const int k0 = curve.first_key + segment_index;
- const int k1 = k0 + 1;
- float3 v0 = hair->get_curve_keys()[k0];
- float3 v1 = hair->get_curve_keys()[k1];
-
- if (tfm != NULL) {
- v0 = transform_point(tfm, v0);
- v1 = transform_point(tfm, v1);
- }
- v0 = get_unaligned_point(v0);
- v1 = get_unaligned_point(v1);
-
- float v0p = v0[dim];
- float v1p = v1[dim];
-
- /* insert vertex to the boxes it belongs to. */
- if (v0p <= pos)
- left_bounds.grow(v0);
-
- if (v0p >= pos)
- right_bounds.grow(v0);
-
- if (v1p <= pos)
- left_bounds.grow(v1);
-
- if (v1p >= pos)
- right_bounds.grow(v1);
-
- /* edge intersects the plane => insert intersection to both boxes. */
- if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
- float3 t = lerp(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
- left_bounds.grow(t);
- right_bounds.grow(t);
- }
-}
-
-void BVHSpatialSplit::split_triangle_reference(const BVHReference &ref,
- const Mesh *mesh,
- int dim,
- float pos,
- BoundBox &left_bounds,
- BoundBox &right_bounds)
-{
- split_triangle_primitive(mesh, NULL, ref.prim_index(), dim, pos, left_bounds, right_bounds);
-}
-
-void BVHSpatialSplit::split_curve_reference(const BVHReference &ref,
- const Hair *hair,
- int dim,
- float pos,
- BoundBox &left_bounds,
- BoundBox &right_bounds)
-{
- split_curve_primitive(hair,
- NULL,
- ref.prim_index(),
- PRIMITIVE_UNPACK_SEGMENT(ref.prim_type()),
- dim,
- pos,
- left_bounds,
- right_bounds);
-}
-
-void BVHSpatialSplit::split_object_reference(
- const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
-{
- Geometry *geom = object->get_geometry();
-
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- for (int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) {
- split_triangle_primitive(
- mesh, &object->get_tfm(), tri_idx, dim, pos, left_bounds, right_bounds);
- }
- }
- else if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- for (int curve_idx = 0; curve_idx < hair->num_curves(); ++curve_idx) {
- Hair::Curve curve = hair->get_curve(curve_idx);
- for (int segment_idx = 0; segment_idx < curve.num_keys - 1; ++segment_idx) {
- split_curve_primitive(
- hair, &object->get_tfm(), curve_idx, segment_idx, dim, pos, left_bounds, right_bounds);
- }
- }
- }
-}
-
-void BVHSpatialSplit::split_reference(const BVHBuild &builder,
- BVHReference &left,
- BVHReference &right,
- const BVHReference &ref,
- int dim,
- float pos)
-{
- /* initialize boundboxes */
- BoundBox left_bounds = BoundBox::empty;
- BoundBox right_bounds = BoundBox::empty;
-
- /* loop over vertices/edges. */
- const Object *ob = builder.objects[ref.prim_object()];
-
- if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
- Mesh *mesh = static_cast<Mesh *>(ob->get_geometry());
- split_triangle_reference(ref, mesh, dim, pos, left_bounds, right_bounds);
- }
- else if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
- Hair *hair = static_cast<Hair *>(ob->get_geometry());
- split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds);
- }
- else {
- split_object_reference(ob, dim, pos, left_bounds, right_bounds);
- }
-
- /* intersect with original bounds. */
- left_bounds.max[dim] = pos;
- right_bounds.min[dim] = pos;
-
- left_bounds.intersect(ref.bounds());
- right_bounds.intersect(ref.bounds());
-
- /* set references */
- left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
- right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h
deleted file mode 100644
index 5582d90bf83..00000000000
--- a/intern/cycles/bvh/bvh_split.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Adapted from code copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BVH_SPLIT_H__
-#define __BVH_SPLIT_H__
-
-#include "bvh/bvh_build.h"
-#include "bvh/bvh_params.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BVHBuild;
-class Hair;
-class Mesh;
-struct Transform;
-
-/* Object Split */
-
-class BVHObjectSplit {
- public:
- float sah;
- int dim;
- int num_left;
- BoundBox left_bounds;
- BoundBox right_bounds;
-
- BVHObjectSplit()
- {
- }
- BVHObjectSplit(BVHBuild *builder,
- BVHSpatialStorage *storage,
- const BVHRange &range,
- vector<BVHReference> &references,
- float nodeSAH,
- const BVHUnaligned *unaligned_heuristic = NULL,
- const Transform *aligned_space = NULL);
-
- void split(BVHRange &left, BVHRange &right, const BVHRange &range);
-
- protected:
- BVHSpatialStorage *storage_;
- vector<BVHReference> *references_;
- const BVHUnaligned *unaligned_heuristic_;
- const Transform *aligned_space_;
-
- __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
- {
- if (aligned_space_ == NULL) {
- return prim.bounds();
- }
- else {
- return unaligned_heuristic_->compute_aligned_prim_boundbox(prim, *aligned_space_);
- }
- }
-};
-
-/* Spatial Split */
-
-class BVHSpatialSplit {
- public:
- float sah;
- int dim;
- float pos;
-
- BVHSpatialSplit() : sah(FLT_MAX), dim(0), pos(0.0f), storage_(NULL), references_(NULL)
- {
- }
- BVHSpatialSplit(const BVHBuild &builder,
- BVHSpatialStorage *storage,
- const BVHRange &range,
- vector<BVHReference> &references,
- float nodeSAH,
- const BVHUnaligned *unaligned_heuristic = NULL,
- const Transform *aligned_space = NULL);
-
- void split(BVHBuild *builder, BVHRange &left, BVHRange &right, const BVHRange &range);
-
- void split_reference(const BVHBuild &builder,
- BVHReference &left,
- BVHReference &right,
- const BVHReference &ref,
- int dim,
- float pos);
-
- protected:
- BVHSpatialStorage *storage_;
- vector<BVHReference> *references_;
- const BVHUnaligned *unaligned_heuristic_;
- const Transform *aligned_space_;
-
- /* Lower-level functions which calculates boundaries of left and right nodes
- * needed for spatial split.
- *
- * Operates directly with primitive specified by its index, reused by higher
- * level splitting functions.
- */
- void split_triangle_primitive(const Mesh *mesh,
- const Transform *tfm,
- int prim_index,
- int dim,
- float pos,
- BoundBox &left_bounds,
- BoundBox &right_bounds);
- void split_curve_primitive(const Hair *hair,
- const Transform *tfm,
- int prim_index,
- int segment_index,
- int dim,
- float pos,
- BoundBox &left_bounds,
- BoundBox &right_bounds);
-
- /* Lower-level functions which calculates boundaries of left and right nodes
- * needed for spatial split.
- *
- * Operates with BVHReference, internally uses lower level API functions.
- */
- void split_triangle_reference(const BVHReference &ref,
- const Mesh *mesh,
- int dim,
- float pos,
- BoundBox &left_bounds,
- BoundBox &right_bounds);
- void split_curve_reference(const BVHReference &ref,
- const Hair *hair,
- int dim,
- float pos,
- BoundBox &left_bounds,
- BoundBox &right_bounds);
- void split_object_reference(
- const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds);
-
- __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
- {
- if (aligned_space_ == NULL) {
- return prim.bounds();
- }
- else {
- return unaligned_heuristic_->compute_aligned_prim_boundbox(prim, *aligned_space_);
- }
- }
-
- __forceinline float3 get_unaligned_point(const float3 &point) const
- {
- if (aligned_space_ == NULL) {
- return point;
- }
- else {
- return transform_point(aligned_space_, point);
- }
- }
-};
-
-/* Mixed Object-Spatial Split */
-
-class BVHMixedSplit {
- public:
- BVHObjectSplit object;
- BVHSpatialSplit spatial;
-
- float leafSAH;
- float nodeSAH;
- float minSAH;
-
- bool no_split;
-
- BoundBox bounds;
-
- BVHMixedSplit()
- {
- }
-
- __forceinline BVHMixedSplit(BVHBuild *builder,
- BVHSpatialStorage *storage,
- const BVHRange &range,
- vector<BVHReference> &references,
- int level,
- const BVHUnaligned *unaligned_heuristic = NULL,
- const Transform *aligned_space = NULL)
- {
- if (aligned_space == NULL) {
- bounds = range.bounds();
- }
- else {
- bounds = unaligned_heuristic->compute_aligned_boundbox(
- range, &references.at(0), *aligned_space);
- }
- /* find split candidates. */
- float area = bounds.safe_area();
-
- leafSAH = area * builder->params.primitive_cost(range.size());
- nodeSAH = area * builder->params.node_cost(2);
-
- object = BVHObjectSplit(
- builder, storage, range, references, nodeSAH, unaligned_heuristic, aligned_space);
-
- if (builder->params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
- BoundBox overlap = object.left_bounds;
- overlap.intersect(object.right_bounds);
-
- if (overlap.safe_area() >= builder->spatial_min_overlap) {
- spatial = BVHSpatialSplit(
- *builder, storage, range, references, nodeSAH, unaligned_heuristic, aligned_space);
- }
- }
-
- /* leaf SAH is the lowest => create leaf. */
- minSAH = min(min(leafSAH, object.sah), spatial.sah);
- no_split = (minSAH == leafSAH && builder->range_within_max_leaf_size(range, references));
- }
-
- __forceinline void split(BVHBuild *builder,
- BVHRange &left,
- BVHRange &right,
- const BVHRange &range)
- {
- if (builder->params.use_spatial_split && minSAH == spatial.sah)
- spatial.split(builder, left, right, range);
- if (!left.size() || !right.size())
- object.split(left, right, range);
- }
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BVH_SPLIT_H__ */
diff --git a/intern/cycles/bvh/bvh_unaligned.cpp b/intern/cycles/bvh/bvh_unaligned.cpp
deleted file mode 100644
index 38e55307848..00000000000
--- a/intern/cycles/bvh/bvh_unaligned.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bvh/bvh_unaligned.h"
-
-#include "render/hair.h"
-#include "render/object.h"
-
-#include "bvh/bvh_binning.h"
-#include "bvh_params.h"
-
-#include "util/util_boundbox.h"
-#include "util/util_transform.h"
-
-CCL_NAMESPACE_BEGIN
-
-BVHUnaligned::BVHUnaligned(const vector<Object *> &objects) : objects_(objects)
-{
-}
-
-Transform BVHUnaligned::compute_aligned_space(const BVHObjectBinning &range,
- const BVHReference *references) const
-{
- for (int i = range.start(); i < range.end(); ++i) {
- const BVHReference &ref = references[i];
- Transform aligned_space;
- /* Use first primitive which defines correct direction to define
- * the orientation space.
- */
- if (compute_aligned_space(ref, &aligned_space)) {
- return aligned_space;
- }
- }
- return transform_identity();
-}
-
-Transform BVHUnaligned::compute_aligned_space(const BVHRange &range,
- const BVHReference *references) const
-{
- for (int i = range.start(); i < range.end(); ++i) {
- const BVHReference &ref = references[i];
- Transform aligned_space;
- /* Use first primitive which defines correct direction to define
- * the orientation space.
- */
- if (compute_aligned_space(ref, &aligned_space)) {
- return aligned_space;
- }
- }
- return transform_identity();
-}
-
-bool BVHUnaligned::compute_aligned_space(const BVHReference &ref, Transform *aligned_space) const
-{
- const Object *object = objects_[ref.prim_object()];
- const int packed_type = ref.prim_type();
- const int type = (packed_type & PRIMITIVE_ALL);
- /* No motion blur curves here, we can't fit them to aligned boxes well. */
- if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
- const int curve_index = ref.prim_index();
- const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
- const Hair *hair = static_cast<const Hair *>(object->get_geometry());
- const Hair::Curve &curve = hair->get_curve(curve_index);
- const int key = curve.first_key + segment;
- const float3 v1 = hair->get_curve_keys()[key], v2 = hair->get_curve_keys()[key + 1];
- float length;
- const float3 axis = normalize_len(v2 - v1, &length);
- if (length > 1e-6f) {
- *aligned_space = make_transform_frame(axis);
- return true;
- }
- }
- *aligned_space = transform_identity();
- return false;
-}
-
-BoundBox BVHUnaligned::compute_aligned_prim_boundbox(const BVHReference &prim,
- const Transform &aligned_space) const
-{
- BoundBox bounds = BoundBox::empty;
- const Object *object = objects_[prim.prim_object()];
- const int packed_type = prim.prim_type();
- const int type = (packed_type & PRIMITIVE_ALL);
- /* No motion blur curves here, we can't fit them to aligned boxes well. */
- if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
- const int curve_index = prim.prim_index();
- const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
- const Hair *hair = static_cast<const Hair *>(object->get_geometry());
- const Hair::Curve &curve = hair->get_curve(curve_index);
- curve.bounds_grow(
- segment, &hair->get_curve_keys()[0], &hair->get_curve_radius()[0], aligned_space, bounds);
- }
- else {
- bounds = prim.bounds().transformed(&aligned_space);
- }
- return bounds;
-}
-
-BoundBox BVHUnaligned::compute_aligned_boundbox(const BVHObjectBinning &range,
- const BVHReference *references,
- const Transform &aligned_space,
- BoundBox *cent_bounds) const
-{
- BoundBox bounds = BoundBox::empty;
- if (cent_bounds != NULL) {
- *cent_bounds = BoundBox::empty;
- }
- for (int i = range.start(); i < range.end(); ++i) {
- const BVHReference &ref = references[i];
- BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
- bounds.grow(ref_bounds);
- if (cent_bounds != NULL) {
- cent_bounds->grow(ref_bounds.center2());
- }
- }
- return bounds;
-}
-
-BoundBox BVHUnaligned::compute_aligned_boundbox(const BVHRange &range,
- const BVHReference *references,
- const Transform &aligned_space,
- BoundBox *cent_bounds) const
-{
- BoundBox bounds = BoundBox::empty;
- if (cent_bounds != NULL) {
- *cent_bounds = BoundBox::empty;
- }
- for (int i = range.start(); i < range.end(); ++i) {
- const BVHReference &ref = references[i];
- BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
- bounds.grow(ref_bounds);
- if (cent_bounds != NULL) {
- cent_bounds->grow(ref_bounds.center2());
- }
- }
- return bounds;
-}
-
-Transform BVHUnaligned::compute_node_transform(const BoundBox &bounds,
- const Transform &aligned_space)
-{
- Transform space = aligned_space;
- space.x.w -= bounds.min.x;
- space.y.w -= bounds.min.y;
- space.z.w -= bounds.min.z;
- float3 dim = bounds.max - bounds.min;
- return transform_scale(
- 1.0f / max(1e-18f, dim.x), 1.0f / max(1e-18f, dim.y), 1.0f / max(1e-18f, dim.z)) *
- space;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_unaligned.h b/intern/cycles/bvh/bvh_unaligned.h
deleted file mode 100644
index e8a9a25daa8..00000000000
--- a/intern/cycles/bvh/bvh_unaligned.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BVH_UNALIGNED_H__
-#define __BVH_UNALIGNED_H__
-
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BoundBox;
-class BVHObjectBinning;
-class BVHRange;
-class BVHReference;
-struct Transform;
-class Object;
-
-/* Helper class to perform calculations needed for unaligned nodes. */
-class BVHUnaligned {
- public:
- BVHUnaligned(const vector<Object *> &objects);
-
- /* Calculate alignment for the oriented node for a given range. */
- Transform compute_aligned_space(const BVHObjectBinning &range,
- const BVHReference *references) const;
- Transform compute_aligned_space(const BVHRange &range, const BVHReference *references) const;
-
- /* Calculate alignment for the oriented node for a given reference.
- *
- * Return true when space was calculated successfully.
- */
- bool compute_aligned_space(const BVHReference &ref, Transform *aligned_space) const;
-
- /* Calculate primitive's bounding box in given space. */
- BoundBox compute_aligned_prim_boundbox(const BVHReference &prim,
- const Transform &aligned_space) const;
-
- /* Calculate bounding box in given space. */
- BoundBox compute_aligned_boundbox(const BVHObjectBinning &range,
- const BVHReference *references,
- const Transform &aligned_space,
- BoundBox *cent_bounds = NULL) const;
- BoundBox compute_aligned_boundbox(const BVHRange &range,
- const BVHReference *references,
- const Transform &aligned_space,
- BoundBox *cent_bounds = NULL) const;
-
- /* Calculate affine transform for node packing.
- * Bounds will be in the range of 0..1.
- */
- static Transform compute_node_transform(const BoundBox &bounds, const Transform &aligned_space);
-
- protected:
- /* List of objects BVH is being created for. */
- const vector<Object *> &objects_;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BVH_UNALIGNED_H__ */
diff --git a/intern/cycles/bvh/embree.cpp b/intern/cycles/bvh/embree.cpp
new file mode 100644
index 00000000000..944a84ce0da
--- /dev/null
+++ b/intern/cycles/bvh/embree.cpp
@@ -0,0 +1,728 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This class implements a ray accelerator for Cycles using Intel's Embree library.
+ * It supports triangles, curves, object and deformation blur and instancing.
+ *
+ * Since Embree allows object to be either curves or triangles but not both, Cycles object IDs are
+ * mapped to Embree IDs by multiplying by two and adding one for curves.
+ *
+ * This implementation shares RTCDevices between Cycles instances. Eventually each instance should
+ * get a separate RTCDevice to correctly keep track of memory usage.
+ *
+ * Vertex and index buffers are duplicated between Cycles device arrays and Embree. These could be
+ * merged, which would require changes to intersection refinement, shader setup, mesh light
+ * sampling and a few other places in Cycles where direct access to vertex data is required.
+ */
+
+#ifdef WITH_EMBREE
+
+# include <embree3/rtcore_geometry.h>
+
+# include "bvh/embree.h"
+
+/* Kernel includes are necessary so that the filter function for Embree can access the packed BVH.
+ */
+# include "kernel/bvh/embree.h"
+# include "kernel/bvh/util.h"
+# include "kernel/device/cpu/compat.h"
+# include "kernel/device/cpu/globals.h"
+# include "kernel/sample/lcg.h"
+
+# include "scene/hair.h"
+# include "scene/mesh.h"
+# include "scene/object.h"
+
+# include "util/foreach.h"
+# include "util/log.h"
+# include "util/progress.h"
+# include "util/stats.h"
+
+CCL_NAMESPACE_BEGIN
+
+static_assert(Object::MAX_MOTION_STEPS <= RTC_MAX_TIME_STEP_COUNT,
+ "Object and Embree max motion steps inconsistent");
+static_assert(Object::MAX_MOTION_STEPS == Geometry::MAX_MOTION_STEPS,
+ "Object and Geometry max motion steps inconsistent");
+
+# define IS_HAIR(x) (x & 1)
+
+/* This gets called by Embree at every valid ray/object intersection.
+ * Things like recording subsurface or shadow hits for later evaluation
+ * as well as filtering for volume objects happen here.
+ * Cycles' own BVH does that directly inside the traversal calls.
+ */
+static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
+{
+ /* Current implementation in Cycles assumes only single-ray intersection queries. */
+ assert(args->N == 1);
+
+ const RTCRay *ray = (RTCRay *)args->ray;
+ RTCHit *hit = (RTCHit *)args->hit;
+ CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
+ const KernelGlobalsCPU *kg = ctx->kg;
+
+ switch (ctx->type) {
+ case CCLIntersectContext::RAY_SHADOW_ALL: {
+ Intersection current_isect;
+ kernel_embree_convert_hit(kg, ray, hit, &current_isect);
+
+ /* If no transparent shadows or max number of hits exceeded, all light is blocked. */
+ const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type);
+ if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->num_hits >= ctx->max_hits) {
+ ctx->opaque_hit = true;
+ return;
+ }
+
+ ++ctx->num_hits;
+
+ /* Always use baked shadow transparency for curves. */
+ if (current_isect.type & PRIMITIVE_ALL_CURVE) {
+ ctx->throughput *= intersection_curve_shadow_transparency(
+ kg, current_isect.object, current_isect.prim, current_isect.u);
+
+ if (ctx->throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
+ ctx->opaque_hit = true;
+ return;
+ }
+ else {
+ *args->valid = 0;
+ return;
+ }
+ }
+
+ /* Test if we need to record this transparent intersection. */
+ const uint max_record_hits = min(ctx->max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
+ if (ctx->num_recorded_hits < max_record_hits || ray->tfar < ctx->max_t) {
+ /* If maximum number of hits was reached, replace the intersection with the
+ * highest distance. We want to find the N closest intersections. */
+ const uint num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits);
+ uint isect_index = num_recorded_hits;
+ if (num_recorded_hits + 1 >= max_record_hits) {
+ float max_t = ctx->isect_s[0].t;
+ uint max_recorded_hit = 0;
+
+ for (uint i = 1; i < num_recorded_hits; ++i) {
+ if (ctx->isect_s[i].t > max_t) {
+ max_recorded_hit = i;
+ max_t = ctx->isect_s[i].t;
+ }
+ }
+
+ if (num_recorded_hits >= max_record_hits) {
+ isect_index = max_recorded_hit;
+ }
+
+ /* Limit the ray distance and stop counting hits beyond this.
+ * TODO: is there some way we can tell Embree to stop intersecting beyond
+ * this distance when max number of hits is reached?. Or maybe it will
+ * become irrelevant if we make max_hits a very high number on the CPU. */
+ ctx->max_t = max(current_isect.t, max_t);
+ }
+
+ ctx->isect_s[isect_index] = current_isect;
+ }
+
+ /* Always increase the number of recorded hits, even beyond the maximum,
+ * so that we can detect this and trace another ray if needed. */
+ ++ctx->num_recorded_hits;
+
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ break;
+ }
+ case CCLIntersectContext::RAY_LOCAL:
+ case CCLIntersectContext::RAY_SSS: {
+ /* Check if it's hitting the correct object. */
+ Intersection current_isect;
+ if (ctx->type == CCLIntersectContext::RAY_SSS) {
+ kernel_embree_convert_sss_hit(kg, ray, hit, &current_isect, ctx->local_object_id);
+ }
+ else {
+ kernel_embree_convert_hit(kg, ray, hit, &current_isect);
+ if (ctx->local_object_id != current_isect.object) {
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ break;
+ }
+ }
+
+ /* No intersection information requested, just return a hit. */
+ if (ctx->max_hits == 0) {
+ break;
+ }
+
+ /* Ignore curves. */
+ if (IS_HAIR(hit->geomID)) {
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ break;
+ }
+
+ LocalIntersection *local_isect = ctx->local_isect;
+ int hit_idx = 0;
+
+ if (ctx->lcg_state) {
+ /* See triangle_intersect_subsurface() for the native equivalent. */
+ for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
+ if (local_isect->hits[i].t == ray->tfar) {
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ return;
+ }
+ }
+
+ local_isect->num_hits++;
+
+ if (local_isect->num_hits <= ctx->max_hits) {
+ hit_idx = local_isect->num_hits - 1;
+ }
+ else {
+ /* reservoir sampling: if we are at the maximum number of
+ * hits, randomly replace element or skip it */
+ hit_idx = lcg_step_uint(ctx->lcg_state) % local_isect->num_hits;
+
+ if (hit_idx >= ctx->max_hits) {
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ return;
+ }
+ }
+ }
+ else {
+ /* Record closest intersection only. */
+ if (local_isect->num_hits && current_isect.t > local_isect->hits[0].t) {
+ *args->valid = 0;
+ return;
+ }
+
+ local_isect->num_hits = 1;
+ }
+
+ /* record intersection */
+ local_isect->hits[hit_idx] = current_isect;
+ local_isect->Ng[hit_idx] = normalize(make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z));
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ break;
+ }
+ case CCLIntersectContext::RAY_VOLUME_ALL: {
+ /* Append the intersection to the end of the array. */
+ if (ctx->num_hits < ctx->max_hits) {
+ Intersection current_isect;
+ kernel_embree_convert_hit(kg, ray, hit, &current_isect);
+ Intersection *isect = &ctx->isect_s[ctx->num_hits];
+ ++ctx->num_hits;
+ *isect = current_isect;
+ /* Only primitives from volume object. */
+ uint tri_object = isect->object;
+ int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+ if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ --ctx->num_hits;
+ }
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ break;
+ }
+ }
+ case CCLIntersectContext::RAY_REGULAR:
+ default:
+ /* Nothing to do here. */
+ break;
+ }
+}
+
+static void rtc_filter_func_thick_curve(const RTCFilterFunctionNArguments *args)
+{
+ const RTCRay *ray = (RTCRay *)args->ray;
+ RTCHit *hit = (RTCHit *)args->hit;
+
+ /* Always ignore back-facing intersections. */
+ if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
+ make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
+ *args->valid = 0;
+ return;
+ }
+}
+
+static void rtc_filter_occluded_func_thick_curve(const RTCFilterFunctionNArguments *args)
+{
+ const RTCRay *ray = (RTCRay *)args->ray;
+ RTCHit *hit = (RTCHit *)args->hit;
+
+ /* Always ignore back-facing intersections. */
+ if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
+ make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
+ *args->valid = 0;
+ return;
+ }
+
+ rtc_filter_occluded_func(args);
+}
+
+static size_t unaccounted_mem = 0;
+
+static bool rtc_memory_monitor_func(void *userPtr, const ssize_t bytes, const bool)
+{
+ Stats *stats = (Stats *)userPtr;
+ if (stats) {
+ if (bytes > 0) {
+ stats->mem_alloc(bytes);
+ }
+ else {
+ stats->mem_free(-bytes);
+ }
+ }
+ else {
+ /* A stats pointer may not yet be available. Keep track of the memory usage for later. */
+ if (bytes >= 0) {
+ atomic_add_and_fetch_z(&unaccounted_mem, bytes);
+ }
+ else {
+ atomic_sub_and_fetch_z(&unaccounted_mem, -bytes);
+ }
+ }
+ return true;
+}
+
+static void rtc_error_func(void *, enum RTCError, const char *str)
+{
+ VLOG(1) << str;
+}
+
+static double progress_start_time = 0.0f;
+
+static bool rtc_progress_func(void *user_ptr, const double n)
+{
+ Progress *progress = (Progress *)user_ptr;
+
+ if (time_dt() - progress_start_time < 0.25) {
+ return true;
+ }
+
+ string msg = string_printf("Building BVH %.0f%%", n * 100.0);
+ progress->set_substatus(msg);
+ progress_start_time = time_dt();
+
+ return !progress->get_cancel();
+}
+
+BVHEmbree::BVHEmbree(const BVHParams &params_,
+ const vector<Geometry *> &geometry_,
+ const vector<Object *> &objects_)
+ : BVH(params_, geometry_, objects_),
+ scene(NULL),
+ rtc_device(NULL),
+ build_quality(RTC_BUILD_QUALITY_REFIT)
+{
+ SIMD_SET_FLUSH_TO_ZERO;
+}
+
+BVHEmbree::~BVHEmbree()
+{
+ if (scene) {
+ rtcReleaseScene(scene);
+ }
+}
+
+void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
+{
+ rtc_device = rtc_device_;
+ assert(rtc_device);
+
+ rtcSetDeviceErrorFunction(rtc_device, rtc_error_func, NULL);
+ rtcSetDeviceMemoryMonitorFunction(rtc_device, rtc_memory_monitor_func, stats);
+
+ progress.set_substatus("Building BVH");
+
+ if (scene) {
+ rtcReleaseScene(scene);
+ scene = NULL;
+ }
+
+ const bool dynamic = params.bvh_type == BVH_TYPE_DYNAMIC;
+
+ scene = rtcNewScene(rtc_device);
+ const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
+ RTC_SCENE_FLAG_COMPACT | RTC_SCENE_FLAG_ROBUST;
+ rtcSetSceneFlags(scene, scene_flags);
+ build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
+ (params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH :
+ RTC_BUILD_QUALITY_MEDIUM);
+ rtcSetSceneBuildQuality(scene, build_quality);
+
+ int i = 0;
+ foreach (Object *ob, objects) {
+ if (params.top_level) {
+ if (!ob->is_traceable()) {
+ ++i;
+ continue;
+ }
+ if (!ob->get_geometry()->is_instanced()) {
+ add_object(ob, i);
+ }
+ else {
+ add_instance(ob, i);
+ }
+ }
+ else {
+ add_object(ob, i);
+ }
+ ++i;
+ if (progress.get_cancel())
+ return;
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
+ rtcCommitScene(scene);
+}
+
+void BVHEmbree::add_object(Object *ob, int i)
+{
+ Geometry *geom = ob->get_geometry();
+
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->num_triangles() > 0) {
+ add_triangles(ob, mesh, i);
+ }
+ }
+ else if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ if (hair->num_curves() > 0) {
+ add_curves(ob, hair, i);
+ }
+ }
+}
+
+void BVHEmbree::add_instance(Object *ob, int i)
+{
+ BVHEmbree *instance_bvh = (BVHEmbree *)(ob->get_geometry()->bvh);
+ assert(instance_bvh != NULL);
+
+ const size_t num_object_motion_steps = ob->use_motion() ? ob->get_motion().size() : 1;
+ const size_t num_motion_steps = min(num_object_motion_steps, RTC_MAX_TIME_STEP_COUNT);
+ assert(num_object_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
+
+ RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_INSTANCE);
+ rtcSetGeometryInstancedScene(geom_id, instance_bvh->scene);
+ rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
+
+ if (ob->use_motion()) {
+ array<DecomposedTransform> decomp(ob->get_motion().size());
+ transform_motion_decompose(decomp.data(), ob->get_motion().data(), ob->get_motion().size());
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ RTCQuaternionDecomposition rtc_decomp;
+ rtcInitQuaternionDecomposition(&rtc_decomp);
+ rtcQuaternionDecompositionSetQuaternion(
+ &rtc_decomp, decomp[step].x.w, decomp[step].x.x, decomp[step].x.y, decomp[step].x.z);
+ rtcQuaternionDecompositionSetScale(
+ &rtc_decomp, decomp[step].y.w, decomp[step].z.w, decomp[step].w.w);
+ rtcQuaternionDecompositionSetTranslation(
+ &rtc_decomp, decomp[step].y.x, decomp[step].y.y, decomp[step].y.z);
+ rtcQuaternionDecompositionSetSkew(
+ &rtc_decomp, decomp[step].z.x, decomp[step].z.y, decomp[step].w.x);
+ rtcSetGeometryTransformQuaternion(geom_id, step, &rtc_decomp);
+ }
+ }
+ else {
+ rtcSetGeometryTransform(
+ geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float *)&ob->get_tfm());
+ }
+
+ rtcSetGeometryUserData(geom_id, (void *)instance_bvh->scene);
+ rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
+
+ rtcCommitGeometry(geom_id);
+ rtcAttachGeometryByID(scene, geom_id, i * 2);
+ rtcReleaseGeometry(geom_id);
+}
+
+void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
+{
+ size_t prim_offset = mesh->prim_offset;
+
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ if (mesh->has_motion_blur()) {
+ attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = mesh->get_motion_steps();
+ }
+ }
+
+ assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
+ num_motion_steps = min(num_motion_steps, RTC_MAX_TIME_STEP_COUNT);
+
+ const size_t num_triangles = mesh->num_triangles();
+
+ RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_TRIANGLE);
+ rtcSetGeometryBuildQuality(geom_id, build_quality);
+ rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
+
+ unsigned *rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
+ geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(int) * 3, num_triangles);
+ assert(rtc_indices);
+ if (!rtc_indices) {
+ VLOG(1) << "Embree could not create new geometry buffer for mesh " << mesh->name.c_str()
+ << ".\n";
+ return;
+ }
+ for (size_t j = 0; j < num_triangles; ++j) {
+ Mesh::Triangle t = mesh->get_triangle(j);
+ rtc_indices[j * 3] = t.v[0];
+ rtc_indices[j * 3 + 1] = t.v[1];
+ rtc_indices[j * 3 + 2] = t.v[2];
+ }
+
+ set_tri_vertex_buffer(geom_id, mesh, false);
+
+ rtcSetGeometryUserData(geom_id, (void *)prim_offset);
+ rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
+ rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
+
+ rtcCommitGeometry(geom_id);
+ rtcAttachGeometryByID(scene, geom_id, i * 2);
+ rtcReleaseGeometry(geom_id);
+}
+
+void BVHEmbree::set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, const bool update)
+{
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ int t_mid = 0;
+ if (mesh->has_motion_blur()) {
+ attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = mesh->get_motion_steps();
+ t_mid = (num_motion_steps - 1) / 2;
+ if (num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
+ assert(0);
+ num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
+ }
+ }
+ }
+ const size_t num_verts = mesh->get_verts().size();
+
+ for (int t = 0; t < num_motion_steps; ++t) {
+ const float3 *verts;
+ if (t == t_mid) {
+ verts = mesh->get_verts().data();
+ }
+ else {
+ int t_ = (t > t_mid) ? (t - 1) : t;
+ verts = &attr_mP->data_float3()[t_ * num_verts];
+ }
+
+ float *rtc_verts = (update) ?
+ (float *)rtcGetGeometryBufferData(geom_id, RTC_BUFFER_TYPE_VERTEX, t) :
+ (float *)rtcSetNewGeometryBuffer(geom_id,
+ RTC_BUFFER_TYPE_VERTEX,
+ t,
+ RTC_FORMAT_FLOAT3,
+ sizeof(float) * 3,
+ num_verts + 1);
+
+ assert(rtc_verts);
+ if (rtc_verts) {
+ for (size_t j = 0; j < num_verts; ++j) {
+ rtc_verts[0] = verts[j].x;
+ rtc_verts[1] = verts[j].y;
+ rtc_verts[2] = verts[j].z;
+ rtc_verts += 3;
+ }
+ }
+
+ if (update) {
+ rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
+ }
+ }
+}
+
+void BVHEmbree::set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, const bool update)
+{
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ if (hair->has_motion_blur()) {
+ attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = hair->get_motion_steps();
+ }
+ }
+
+ const size_t num_curves = hair->num_curves();
+ size_t num_keys = 0;
+ for (size_t j = 0; j < num_curves; ++j) {
+ const Hair::Curve c = hair->get_curve(j);
+ num_keys += c.num_keys;
+ }
+
+ /* Catmull-Rom splines need extra CVs at the beginning and end of each curve. */
+ size_t num_keys_embree = num_keys;
+ num_keys_embree += num_curves * 2;
+
+ /* Copy the CV data to Embree */
+ const int t_mid = (num_motion_steps - 1) / 2;
+ const float *curve_radius = &hair->get_curve_radius()[0];
+ for (int t = 0; t < num_motion_steps; ++t) {
+ const float3 *verts;
+ if (t == t_mid || attr_mP == NULL) {
+ verts = &hair->get_curve_keys()[0];
+ }
+ else {
+ int t_ = (t > t_mid) ? (t - 1) : t;
+ verts = &attr_mP->data_float3()[t_ * num_keys];
+ }
+
+ float4 *rtc_verts = (update) ? (float4 *)rtcGetGeometryBufferData(
+ geom_id, RTC_BUFFER_TYPE_VERTEX, t) :
+ (float4 *)rtcSetNewGeometryBuffer(geom_id,
+ RTC_BUFFER_TYPE_VERTEX,
+ t,
+ RTC_FORMAT_FLOAT4,
+ sizeof(float) * 4,
+ num_keys_embree);
+
+ assert(rtc_verts);
+ if (rtc_verts) {
+ const size_t num_curves = hair->num_curves();
+ for (size_t j = 0; j < num_curves; ++j) {
+ Hair::Curve c = hair->get_curve(j);
+ int fk = c.first_key;
+ int k = 1;
+ for (; k < c.num_keys + 1; ++k, ++fk) {
+ rtc_verts[k] = float3_to_float4(verts[fk]);
+ rtc_verts[k].w = curve_radius[fk];
+ }
+ /* Duplicate Embree's Catmull-Rom spline CVs at the start and end of each curve. */
+ rtc_verts[0] = rtc_verts[1];
+ rtc_verts[k] = rtc_verts[k - 1];
+ rtc_verts += c.num_keys + 2;
+ }
+ }
+
+ if (update) {
+ rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
+ }
+ }
+}
+
+void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
+{
+ size_t prim_offset = hair->curve_segment_offset;
+
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ if (hair->has_motion_blur()) {
+ attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = hair->get_motion_steps();
+ }
+ }
+
+ assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
+ num_motion_steps = min(num_motion_steps, RTC_MAX_TIME_STEP_COUNT);
+
+ const size_t num_curves = hair->num_curves();
+ size_t num_segments = 0;
+ for (size_t j = 0; j < num_curves; ++j) {
+ Hair::Curve c = hair->get_curve(j);
+ assert(c.num_segments() > 0);
+ num_segments += c.num_segments();
+ }
+
+ enum RTCGeometryType type = (hair->curve_shape == CURVE_RIBBON ?
+ RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE :
+ RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE);
+
+ RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
+ rtcSetGeometryTessellationRate(geom_id, params.curve_subdivisions + 1);
+ unsigned *rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
+ geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof(int), num_segments);
+ size_t rtc_index = 0;
+ for (size_t j = 0; j < num_curves; ++j) {
+ Hair::Curve c = hair->get_curve(j);
+ for (size_t k = 0; k < c.num_segments(); ++k) {
+ rtc_indices[rtc_index] = c.first_key + k;
+ /* Room for extra CVs at Catmull-Rom splines. */
+ rtc_indices[rtc_index] += j * 2;
+
+ ++rtc_index;
+ }
+ }
+
+ rtcSetGeometryBuildQuality(geom_id, build_quality);
+ rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
+
+ set_curve_vertex_buffer(geom_id, hair, false);
+
+ rtcSetGeometryUserData(geom_id, (void *)prim_offset);
+ if (hair->curve_shape == CURVE_RIBBON) {
+ rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
+ }
+ else {
+ rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_thick_curve);
+ rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_thick_curve);
+ }
+ rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
+
+ rtcCommitGeometry(geom_id);
+ rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);
+ rtcReleaseGeometry(geom_id);
+}
+
+void BVHEmbree::refit(Progress &progress)
+{
+ progress.set_substatus("Refitting BVH nodes");
+
+ /* Update all vertex buffers, then tell Embree to rebuild/-fit the BVHs. */
+ unsigned geom_id = 0;
+ foreach (Object *ob, objects) {
+ if (!params.top_level || (ob->is_traceable() && !ob->get_geometry()->is_instanced())) {
+ Geometry *geom = ob->get_geometry();
+
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->num_triangles() > 0) {
+ RTCGeometry geom = rtcGetGeometry(scene, geom_id);
+ set_tri_vertex_buffer(geom, mesh, true);
+ rtcSetGeometryUserData(geom, (void *)mesh->prim_offset);
+ rtcCommitGeometry(geom);
+ }
+ }
+ else if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ if (hair->num_curves() > 0) {
+ RTCGeometry geom = rtcGetGeometry(scene, geom_id + 1);
+ set_curve_vertex_buffer(geom, hair, true);
+ rtcSetGeometryUserData(geom, (void *)hair->curve_segment_offset);
+ rtcCommitGeometry(geom);
+ }
+ }
+ }
+ geom_id += 2;
+ }
+
+ rtcCommitScene(scene);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_EMBREE */
diff --git a/intern/cycles/bvh/embree.h b/intern/cycles/bvh/embree.h
new file mode 100644
index 00000000000..746ca97b504
--- /dev/null
+++ b/intern/cycles/bvh/embree.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_EMBREE_H__
+#define __BVH_EMBREE_H__
+
+#ifdef WITH_EMBREE
+
+# include <embree3/rtcore.h>
+# include <embree3/rtcore_scene.h>
+
+# include "bvh/bvh.h"
+# include "bvh/params.h"
+
+# include "util/thread.h"
+# include "util/types.h"
+# include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Hair;
+class Mesh;
+
+class BVHEmbree : public BVH {
+ public:
+ void build(Progress &progress, Stats *stats, RTCDevice rtc_device);
+ void refit(Progress &progress);
+
+ RTCScene scene;
+
+ protected:
+ friend class BVH;
+ BVHEmbree(const BVHParams &params,
+ const vector<Geometry *> &geometry,
+ const vector<Object *> &objects);
+ virtual ~BVHEmbree();
+
+ void add_object(Object *ob, int i);
+ void add_instance(Object *ob, int i);
+ void add_curves(const Object *ob, const Hair *hair, int i);
+ void add_triangles(const Object *ob, const Mesh *mesh, int i);
+
+ private:
+ void set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, const bool update);
+ void set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, const bool update);
+
+ RTCDevice rtc_device;
+ enum RTCBuildQuality build_quality;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_EMBREE */
+
+#endif /* __BVH_EMBREE_H__ */
diff --git a/intern/cycles/bvh/multi.cpp b/intern/cycles/bvh/multi.cpp
new file mode 100644
index 00000000000..db0ff5c7847
--- /dev/null
+++ b/intern/cycles/bvh/multi.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bvh/multi.h"
+
+#include "util/foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+BVHMulti::BVHMulti(const BVHParams &params_,
+ const vector<Geometry *> &geometry_,
+ const vector<Object *> &objects_)
+ : BVH(params_, geometry_, objects_)
+{
+}
+
+BVHMulti::~BVHMulti()
+{
+ foreach (BVH *bvh, sub_bvhs) {
+ delete bvh;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/multi.h b/intern/cycles/bvh/multi.h
new file mode 100644
index 00000000000..88a459605c3
--- /dev/null
+++ b/intern/cycles/bvh/multi.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_MULTI_H__
+#define __BVH_MULTI_H__
+
+#include "bvh/bvh.h"
+#include "bvh/params.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BVHMulti : public BVH {
+ public:
+ vector<BVH *> sub_bvhs;
+
+ protected:
+ friend class BVH;
+ BVHMulti(const BVHParams &params,
+ const vector<Geometry *> &geometry,
+ const vector<Object *> &objects);
+ virtual ~BVHMulti();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_MULTI_H__ */
diff --git a/intern/cycles/bvh/node.cpp b/intern/cycles/bvh/node.cpp
new file mode 100644
index 00000000000..d3a665adfe7
--- /dev/null
+++ b/intern/cycles/bvh/node.cpp
@@ -0,0 +1,224 @@
+/*
+ * Adapted from code copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bvh/node.h"
+
+#include "bvh/build.h"
+#include "bvh/bvh.h"
+
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* BVH Node */
+
+int BVHNode::getSubtreeSize(BVH_STAT stat) const
+{
+ int cnt = 0;
+
+ switch (stat) {
+ case BVH_STAT_NODE_COUNT:
+ cnt = 1;
+ break;
+ case BVH_STAT_LEAF_COUNT:
+ cnt = is_leaf() ? 1 : 0;
+ break;
+ case BVH_STAT_INNER_COUNT:
+ cnt = is_leaf() ? 0 : 1;
+ break;
+ case BVH_STAT_TRIANGLE_COUNT:
+ cnt = is_leaf() ? reinterpret_cast<const LeafNode *>(this)->num_triangles() : 0;
+ break;
+ case BVH_STAT_CHILDNODE_COUNT:
+ cnt = num_children();
+ break;
+ case BVH_STAT_ALIGNED_COUNT:
+ if (!is_unaligned) {
+ cnt = 1;
+ }
+ break;
+ case BVH_STAT_UNALIGNED_COUNT:
+ if (is_unaligned) {
+ cnt = 1;
+ }
+ break;
+ case BVH_STAT_ALIGNED_INNER_COUNT:
+ if (!is_leaf()) {
+ bool has_unaligned = false;
+ for (int j = 0; j < num_children(); j++) {
+ has_unaligned |= get_child(j)->is_unaligned;
+ }
+ cnt += has_unaligned ? 0 : 1;
+ }
+ break;
+ case BVH_STAT_UNALIGNED_INNER_COUNT:
+ if (!is_leaf()) {
+ bool has_unaligned = false;
+ for (int j = 0; j < num_children(); j++) {
+ has_unaligned |= get_child(j)->is_unaligned;
+ }
+ cnt += has_unaligned ? 1 : 0;
+ }
+ break;
+ case BVH_STAT_ALIGNED_LEAF_COUNT:
+ cnt = (is_leaf() && !is_unaligned) ? 1 : 0;
+ break;
+ case BVH_STAT_UNALIGNED_LEAF_COUNT:
+ cnt = (is_leaf() && is_unaligned) ? 1 : 0;
+ break;
+ case BVH_STAT_DEPTH:
+ if (is_leaf()) {
+ cnt = 1;
+ }
+ else {
+ for (int i = 0; i < num_children(); i++) {
+ cnt = max(cnt, get_child(i)->getSubtreeSize(stat));
+ }
+ cnt += 1;
+ }
+ return cnt;
+ default:
+ assert(0); /* unknown mode */
+ }
+
+ if (!is_leaf())
+ for (int i = 0; i < num_children(); i++)
+ cnt += get_child(i)->getSubtreeSize(stat);
+
+ return cnt;
+}
+
+void BVHNode::deleteSubtree()
+{
+ for (int i = 0; i < num_children(); i++)
+ if (get_child(i))
+ get_child(i)->deleteSubtree();
+
+ delete this;
+}
+
+float BVHNode::computeSubtreeSAHCost(const BVHParams &p, float probability) const
+{
+ float SAH = probability * p.cost(num_children(), num_triangles());
+
+ for (int i = 0; i < num_children(); i++) {
+ BVHNode *child = get_child(i);
+ SAH += child->computeSubtreeSAHCost(
+ p, probability * child->bounds.safe_area() / bounds.safe_area());
+ }
+
+ return SAH;
+}
+
+uint BVHNode::update_visibility()
+{
+ if (!is_leaf() && visibility == 0) {
+ InnerNode *inner = (InnerNode *)this;
+ BVHNode *child0 = inner->children[0];
+ BVHNode *child1 = inner->children[1];
+
+ visibility = child0->update_visibility() | child1->update_visibility();
+ }
+
+ return visibility;
+}
+
+void BVHNode::update_time()
+{
+ if (!is_leaf()) {
+ InnerNode *inner = (InnerNode *)this;
+ BVHNode *child0 = inner->children[0];
+ BVHNode *child1 = inner->children[1];
+ child0->update_time();
+ child1->update_time();
+ time_from = min(child0->time_from, child1->time_from);
+ time_to = max(child0->time_to, child1->time_to);
+ }
+}
+
+namespace {
+
+struct DumpTraversalContext {
+ /* Descriptor of wile where writing is happening. */
+ FILE *stream;
+ /* Unique identifier of the node current. */
+ int id;
+};
+
+void dump_subtree(DumpTraversalContext *context, const BVHNode *node, const BVHNode *parent = NULL)
+{
+ if (node->is_leaf()) {
+ fprintf(context->stream,
+ " node_%p [label=\"%d\",fillcolor=\"#ccccee\",style=filled]\n",
+ node,
+ context->id);
+ }
+ else {
+ fprintf(context->stream,
+ " node_%p [label=\"%d\",fillcolor=\"#cceecc\",style=filled]\n",
+ node,
+ context->id);
+ }
+ if (parent != NULL) {
+ fprintf(context->stream, " node_%p -> node_%p;\n", parent, node);
+ }
+ context->id += 1;
+ for (int i = 0; i < node->num_children(); ++i) {
+ dump_subtree(context, node->get_child(i), node);
+ }
+}
+
+} // namespace
+
+void BVHNode::dump_graph(const char *filename)
+{
+ DumpTraversalContext context;
+ context.stream = fopen(filename, "w");
+ if (context.stream == NULL) {
+ return;
+ }
+ context.id = 0;
+ fprintf(context.stream, "digraph BVH {\n");
+ dump_subtree(&context, this);
+ fprintf(context.stream, "}\n");
+ fclose(context.stream);
+}
+
+/* Inner Node */
+
+void InnerNode::print(int depth) const
+{
+ for (int i = 0; i < depth; i++)
+ printf(" ");
+
+ printf("inner node %p\n", (void *)this);
+
+ if (children[0])
+ children[0]->print(depth + 1);
+ if (children[1])
+ children[1]->print(depth + 1);
+}
+
+void LeafNode::print(int depth) const
+{
+ for (int i = 0; i < depth; i++)
+ printf(" ");
+
+ printf("leaf node %d to %d\n", lo, hi);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/node.h b/intern/cycles/bvh/node.h
new file mode 100644
index 00000000000..d5de9e062fc
--- /dev/null
+++ b/intern/cycles/bvh/node.h
@@ -0,0 +1,255 @@
+/*
+ * Adapted from code copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_NODE_H__
+#define __BVH_NODE_H__
+
+#include "util/boundbox.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+enum BVH_STAT {
+ BVH_STAT_NODE_COUNT,
+ BVH_STAT_INNER_COUNT,
+ BVH_STAT_LEAF_COUNT,
+ BVH_STAT_TRIANGLE_COUNT,
+ BVH_STAT_CHILDNODE_COUNT,
+ BVH_STAT_ALIGNED_COUNT,
+ BVH_STAT_UNALIGNED_COUNT,
+ BVH_STAT_ALIGNED_INNER_COUNT,
+ BVH_STAT_UNALIGNED_INNER_COUNT,
+ BVH_STAT_ALIGNED_LEAF_COUNT,
+ BVH_STAT_UNALIGNED_LEAF_COUNT,
+ BVH_STAT_DEPTH,
+};
+
+class BVHParams;
+
+class BVHNode {
+ public:
+ virtual ~BVHNode()
+ {
+ delete aligned_space;
+ }
+
+ virtual bool is_leaf() const = 0;
+ virtual int num_children() const = 0;
+ virtual BVHNode *get_child(int i) const = 0;
+ virtual int num_triangles() const
+ {
+ return 0;
+ }
+ virtual void print(int depth = 0) const = 0;
+
+ inline void set_aligned_space(const Transform &aligned_space)
+ {
+ is_unaligned = true;
+ if (this->aligned_space == NULL) {
+ this->aligned_space = new Transform(aligned_space);
+ }
+ else {
+ *this->aligned_space = aligned_space;
+ }
+ }
+
+ inline Transform get_aligned_space() const
+ {
+ if (aligned_space == NULL) {
+ return transform_identity();
+ }
+ return *aligned_space;
+ }
+
+ inline bool has_unaligned() const
+ {
+ if (is_leaf()) {
+ return false;
+ }
+ for (int i = 0; i < num_children(); ++i) {
+ if (get_child(i)->is_unaligned) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Subtree functions
+ int getSubtreeSize(BVH_STAT stat = BVH_STAT_NODE_COUNT) const;
+ float computeSubtreeSAHCost(const BVHParams &p, float probability = 1.0f) const;
+ void deleteSubtree();
+
+ uint update_visibility();
+ void update_time();
+
+ /* Dump the content of the tree as a graphviz file. */
+ void dump_graph(const char *filename);
+
+ // Properties.
+ BoundBox bounds;
+ uint visibility;
+
+ bool is_unaligned;
+
+ /* TODO(sergey): Can be stored as 3x3 matrix, but better to have some
+ * utilities and type defines in util_transform first.
+ */
+ Transform *aligned_space;
+
+ float time_from, time_to;
+
+ protected:
+ explicit BVHNode(const BoundBox &bounds)
+ : bounds(bounds),
+ visibility(0),
+ is_unaligned(false),
+ aligned_space(NULL),
+ time_from(0.0f),
+ time_to(1.0f)
+ {
+ }
+
+ explicit BVHNode(const BVHNode &other)
+ : bounds(other.bounds),
+ visibility(other.visibility),
+ is_unaligned(other.is_unaligned),
+ aligned_space(NULL),
+ time_from(other.time_from),
+ time_to(other.time_to)
+ {
+ if (other.aligned_space != NULL) {
+ assert(other.is_unaligned);
+ aligned_space = new Transform();
+ *aligned_space = *other.aligned_space;
+ }
+ else {
+ assert(!other.is_unaligned);
+ }
+ }
+};
+
+class InnerNode : public BVHNode {
+ public:
+ static constexpr int kNumMaxChildren = 8;
+
+ InnerNode(const BoundBox &bounds, BVHNode *child0, BVHNode *child1)
+ : BVHNode(bounds), num_children_(2)
+ {
+ children[0] = child0;
+ children[1] = child1;
+ reset_unused_children();
+
+ if (child0 && child1) {
+ visibility = child0->visibility | child1->visibility;
+ }
+ else {
+ /* Happens on build cancel. */
+ visibility = 0;
+ }
+ }
+
+ InnerNode(const BoundBox &bounds, BVHNode **children, const int num_children)
+ : BVHNode(bounds), num_children_(num_children)
+ {
+ visibility = 0;
+ time_from = FLT_MAX;
+ time_to = -FLT_MAX;
+ for (int i = 0; i < num_children; ++i) {
+ assert(children[i] != NULL);
+ visibility |= children[i]->visibility;
+ this->children[i] = children[i];
+ time_from = min(time_from, children[i]->time_from);
+ time_to = max(time_to, children[i]->time_to);
+ }
+ reset_unused_children();
+ }
+
+ /* NOTE: This function is only used during binary BVH builder, and it
+ * supposed to be configured to have 2 children which will be filled-in in a
+ * bit. But this is important to have children reset to NULL. */
+ explicit InnerNode(const BoundBox &bounds) : BVHNode(bounds), num_children_(0)
+ {
+ reset_unused_children();
+ visibility = 0;
+ num_children_ = 2;
+ }
+
+ bool is_leaf() const
+ {
+ return false;
+ }
+ int num_children() const
+ {
+ return num_children_;
+ }
+ BVHNode *get_child(int i) const
+ {
+ assert(i >= 0 && i < num_children_);
+ return children[i];
+ }
+ void print(int depth) const;
+
+ int num_children_;
+ BVHNode *children[kNumMaxChildren];
+
+ protected:
+ void reset_unused_children()
+ {
+ for (int i = num_children_; i < kNumMaxChildren; ++i) {
+ children[i] = NULL;
+ }
+ }
+};
+
+class LeafNode : public BVHNode {
+ public:
+ LeafNode(const BoundBox &bounds, uint visibility, int lo, int hi)
+ : BVHNode(bounds), lo(lo), hi(hi)
+ {
+ this->bounds = bounds;
+ this->visibility = visibility;
+ }
+
+ LeafNode(const LeafNode &other) : BVHNode(other), lo(other.lo), hi(other.hi)
+ {
+ }
+
+ bool is_leaf() const
+ {
+ return true;
+ }
+ int num_children() const
+ {
+ return 0;
+ }
+ BVHNode *get_child(int) const
+ {
+ return NULL;
+ }
+ int num_triangles() const
+ {
+ return hi - lo;
+ }
+ void print(int depth) const;
+
+ int lo;
+ int hi;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_NODE_H__ */
diff --git a/intern/cycles/bvh/optix.cpp b/intern/cycles/bvh/optix.cpp
new file mode 100644
index 00000000000..ebc3fa68b97
--- /dev/null
+++ b/intern/cycles/bvh/optix.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019, NVIDIA Corporation.
+ * Copyright 2019, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_OPTIX
+
+# include "device/device.h"
+
+# include "bvh/optix.h"
+
+CCL_NAMESPACE_BEGIN
+
+BVHOptiX::BVHOptiX(const BVHParams &params_,
+ const vector<Geometry *> &geometry_,
+ const vector<Object *> &objects_,
+ Device *device)
+ : BVH(params_, geometry_, objects_),
+ device(device),
+ traversable_handle(0),
+ as_data(device, params_.top_level ? "optix tlas" : "optix blas", false),
+ motion_transform_data(device, "optix motion transform", false)
+{
+}
+
+BVHOptiX::~BVHOptiX()
+{
+ // Acceleration structure memory is delayed freed on device, since deleting the
+ // BVH may happen while still being used for rendering.
+ device->release_optix_bvh(this);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_OPTIX */
diff --git a/intern/cycles/bvh/optix.h b/intern/cycles/bvh/optix.h
new file mode 100644
index 00000000000..037e54980bd
--- /dev/null
+++ b/intern/cycles/bvh/optix.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019, NVIDIA Corporation.
+ * Copyright 2019, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_OPTIX_H__
+#define __BVH_OPTIX_H__
+
+#ifdef WITH_OPTIX
+
+# include "bvh/bvh.h"
+# include "bvh/params.h"
+
+# include "device/memory.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BVHOptiX : public BVH {
+ public:
+ Device *device;
+ uint64_t traversable_handle;
+ device_only_memory<char> as_data;
+ device_only_memory<char> motion_transform_data;
+
+ protected:
+ friend class BVH;
+ BVHOptiX(const BVHParams &params,
+ const vector<Geometry *> &geometry,
+ const vector<Object *> &objects,
+ Device *device);
+ virtual ~BVHOptiX();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_OPTIX */
+
+#endif /* __BVH_OPTIX_H__ */
diff --git a/intern/cycles/bvh/params.h b/intern/cycles/bvh/params.h
new file mode 100644
index 00000000000..8f185a2640f
--- /dev/null
+++ b/intern/cycles/bvh/params.h
@@ -0,0 +1,335 @@
+/*
+ * Adapted from code copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_PARAMS_H__
+#define __BVH_PARAMS_H__
+
+#include "util/boundbox.h"
+
+#include "kernel/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Layout of BVH tree.
+ *
+ * For example, how wide BVH tree is, in terms of number of children
+ * per node.
+ */
+typedef KernelBVHLayout BVHLayout;
+
+/* Type of BVH, in terms whether it is supported dynamic updates of meshes
+ * or whether modifying geometry requires full BVH rebuild.
+ */
+enum BVHType {
+ /* BVH supports dynamic updates of geometry.
+ *
+ * Faster for updating BVH tree when doing modifications in viewport,
+ * but slower for rendering.
+ */
+ BVH_TYPE_DYNAMIC = 0,
+ /* BVH tree is calculated for specific scene, updates in geometry
+ * requires full tree rebuild.
+ *
+ * Slower to update BVH tree when modifying objects in viewport, also
+ * slower to build final BVH tree but gives best possible render speed.
+ */
+ BVH_TYPE_STATIC = 1,
+
+ BVH_NUM_TYPES,
+};
+
+/* Names bitflag type to denote which BVH layouts are supported by
+ * particular area.
+ *
+ * Bitflags are the BVH_LAYOUT_* values.
+ */
+typedef int BVHLayoutMask;
+
+/* Get human readable name of BVH layout. */
+const char *bvh_layout_name(BVHLayout layout);
+
+/* BVH Parameters */
+
+class BVHParams {
+ public:
+ /* spatial split area threshold */
+ bool use_spatial_split;
+ float spatial_split_alpha;
+
+ /* Unaligned nodes creation threshold */
+ float unaligned_split_threshold;
+
+ /* SAH costs */
+ float sah_node_cost;
+ float sah_primitive_cost;
+
+ /* number of primitives in leaf */
+ int min_leaf_size;
+ int max_triangle_leaf_size;
+ int max_motion_triangle_leaf_size;
+ int max_curve_leaf_size;
+ int max_motion_curve_leaf_size;
+
+ /* object or mesh level bvh */
+ bool top_level;
+
+ /* BVH layout to be built. */
+ BVHLayout bvh_layout;
+
+ /* Use unaligned bounding boxes.
+ * Only used for curves BVH.
+ */
+ bool use_unaligned_nodes;
+
+ /* Split time range to this number of steps and create leaf node for each
+ * of this time steps.
+ *
+ * Speeds up rendering of motion curve primitives in the cost of higher
+ * memory usage.
+ */
+ int num_motion_curve_steps;
+
+ /* Same as above, but for triangle primitives. */
+ int num_motion_triangle_steps;
+
+ /* Same as in SceneParams. */
+ int bvh_type;
+
+ /* These are needed for Embree. */
+ int curve_subdivisions;
+
+ /* fixed parameters */
+ enum { MAX_DEPTH = 64, MAX_SPATIAL_DEPTH = 48, NUM_SPATIAL_BINS = 32 };
+
+ BVHParams()
+ {
+ use_spatial_split = true;
+ spatial_split_alpha = 1e-5f;
+
+ unaligned_split_threshold = 0.7f;
+
+ /* todo: see if splitting up primitive cost to be separate for triangles
+ * and curves can help. so far in tests it doesn't help, but why? */
+ sah_node_cost = 1.0f;
+ sah_primitive_cost = 1.0f;
+
+ min_leaf_size = 1;
+ max_triangle_leaf_size = 8;
+ max_motion_triangle_leaf_size = 8;
+ max_curve_leaf_size = 1;
+ max_motion_curve_leaf_size = 4;
+
+ top_level = false;
+ bvh_layout = BVH_LAYOUT_BVH2;
+ use_unaligned_nodes = false;
+
+ num_motion_curve_steps = 0;
+ num_motion_triangle_steps = 0;
+
+ bvh_type = 0;
+
+ curve_subdivisions = 4;
+ }
+
+ /* SAH costs */
+ __forceinline float cost(int num_nodes, int num_primitives) const
+ {
+ return node_cost(num_nodes) + primitive_cost(num_primitives);
+ }
+
+ __forceinline float primitive_cost(int n) const
+ {
+ return n * sah_primitive_cost;
+ }
+
+ __forceinline float node_cost(int n) const
+ {
+ return n * sah_node_cost;
+ }
+
+ __forceinline bool small_enough_for_leaf(int size, int level)
+ {
+ return (size <= min_leaf_size || level >= MAX_DEPTH);
+ }
+
+ /* Gets best matching BVH.
+ *
+ * If the requested layout is supported by the device, it will be used.
+ * Otherwise, widest supported layout below that will be used.
+ */
+ static BVHLayout best_bvh_layout(BVHLayout requested_layout, BVHLayoutMask supported_layouts);
+};
+
+/* BVH Reference
+ *
+ * Reference to a primitive. Primitive index and object are sneakily packed
+ * into BoundBox to reduce memory usage and align nicely */
+
+class BVHReference {
+ public:
+ __forceinline BVHReference()
+ {
+ }
+
+ __forceinline BVHReference(const BoundBox &bounds_,
+ int prim_index_,
+ int prim_object_,
+ int prim_type,
+ float time_from = 0.0f,
+ float time_to = 1.0f)
+ : rbounds(bounds_), time_from_(time_from), time_to_(time_to)
+ {
+ rbounds.min.w = __int_as_float(prim_index_);
+ rbounds.max.w = __int_as_float(prim_object_);
+ type = prim_type;
+ }
+
+ __forceinline const BoundBox &bounds() const
+ {
+ return rbounds;
+ }
+ __forceinline int prim_index() const
+ {
+ return __float_as_int(rbounds.min.w);
+ }
+ __forceinline int prim_object() const
+ {
+ return __float_as_int(rbounds.max.w);
+ }
+ __forceinline int prim_type() const
+ {
+ return type;
+ }
+ __forceinline float time_from() const
+ {
+ return time_from_;
+ }
+ __forceinline float time_to() const
+ {
+ return time_to_;
+ }
+
+ BVHReference &operator=(const BVHReference &arg)
+ {
+ if (&arg != this) {
+ /* TODO(sergey): Check if it is still faster to memcpy() with
+ * modern compilers.
+ */
+ memcpy((void *)this, &arg, sizeof(BVHReference));
+ }
+ return *this;
+ }
+
+ protected:
+ BoundBox rbounds;
+ uint type;
+ float time_from_, time_to_;
+};
+
+/* BVH Range
+ *
+ * Build range used during construction, to indicate the bounds and place in
+ * the reference array of a subset of primitives Again uses trickery to pack
+ * integers into BoundBox for alignment purposes. */
+
+class BVHRange {
+ public:
+ __forceinline BVHRange()
+ {
+ rbounds.min.w = __int_as_float(0);
+ rbounds.max.w = __int_as_float(0);
+ }
+
+ __forceinline BVHRange(const BoundBox &bounds_, int start_, int size_) : rbounds(bounds_)
+ {
+ rbounds.min.w = __int_as_float(start_);
+ rbounds.max.w = __int_as_float(size_);
+ }
+
+ __forceinline BVHRange(const BoundBox &bounds_, const BoundBox &cbounds_, int start_, int size_)
+ : rbounds(bounds_), cbounds(cbounds_)
+ {
+ rbounds.min.w = __int_as_float(start_);
+ rbounds.max.w = __int_as_float(size_);
+ }
+
+ __forceinline void set_start(int start_)
+ {
+ rbounds.min.w = __int_as_float(start_);
+ }
+
+ __forceinline const BoundBox &bounds() const
+ {
+ return rbounds;
+ }
+ __forceinline const BoundBox &cent_bounds() const
+ {
+ return cbounds;
+ }
+ __forceinline int start() const
+ {
+ return __float_as_int(rbounds.min.w);
+ }
+ __forceinline int size() const
+ {
+ return __float_as_int(rbounds.max.w);
+ }
+ __forceinline int end() const
+ {
+ return start() + size();
+ }
+
+ protected:
+ BoundBox rbounds;
+ BoundBox cbounds;
+};
+
+/* BVH Spatial Bin */
+
+struct BVHSpatialBin {
+ BoundBox bounds;
+ int enter;
+ int exit;
+
+ __forceinline BVHSpatialBin()
+ {
+ }
+};
+
+/* BVH Spatial Storage
+ *
+ * The idea of this storage is have thread-specific storage for the spatial
+ * splitters. We can pre-allocate this storage in advance and avoid heavy memory
+ * operations during split process.
+ */
+
+struct BVHSpatialStorage {
+ /* Accumulated bounds when sweeping from right to left. */
+ vector<BoundBox> right_bounds;
+
+ /* Bins used for histogram when selecting best split plane. */
+ BVHSpatialBin bins[3][BVHParams::NUM_SPATIAL_BINS];
+
+ /* Temporary storage for the new references. Used by spatial split to store
+ * new references in before they're getting inserted into actual array,
+ */
+ vector<BVHReference> new_references;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_PARAMS_H__ */
diff --git a/intern/cycles/bvh/sort.cpp b/intern/cycles/bvh/sort.cpp
new file mode 100644
index 00000000000..a9975ce6bb2
--- /dev/null
+++ b/intern/cycles/bvh/sort.cpp
@@ -0,0 +1,187 @@
+/*
+ * Adapted from code copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bvh/sort.h"
+
+#include "bvh/build.h"
+
+#include "util/algorithm.h"
+#include "util/task.h"
+
+CCL_NAMESPACE_BEGIN
+
+static const int BVH_SORT_THRESHOLD = 4096;
+
+struct BVHReferenceCompare {
+ public:
+ int dim;
+ const BVHUnaligned *unaligned_heuristic;
+ const Transform *aligned_space;
+
+ BVHReferenceCompare(int dim,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
+ : dim(dim), unaligned_heuristic(unaligned_heuristic), aligned_space(aligned_space)
+ {
+ }
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
+ {
+ return (aligned_space != NULL) ?
+ unaligned_heuristic->compute_aligned_prim_boundbox(prim, *aligned_space) :
+ prim.bounds();
+ }
+
+ /* Compare two references.
+ *
+ * Returns value is similar to return value of strcmp().
+ */
+ __forceinline int compare(const BVHReference &ra, const BVHReference &rb) const
+ {
+ BoundBox ra_bounds = get_prim_bounds(ra), rb_bounds = get_prim_bounds(rb);
+ float ca = ra_bounds.min[dim] + ra_bounds.max[dim];
+ float cb = rb_bounds.min[dim] + rb_bounds.max[dim];
+
+ if (ca < cb)
+ return -1;
+ else if (ca > cb)
+ return 1;
+ else if (ra.prim_object() < rb.prim_object())
+ return -1;
+ else if (ra.prim_object() > rb.prim_object())
+ return 1;
+ else if (ra.prim_index() < rb.prim_index())
+ return -1;
+ else if (ra.prim_index() > rb.prim_index())
+ return 1;
+ else if (ra.prim_type() < rb.prim_type())
+ return -1;
+ else if (ra.prim_type() > rb.prim_type())
+ return 1;
+
+ return 0;
+ }
+
+ bool operator()(const BVHReference &ra, const BVHReference &rb)
+ {
+ return (compare(ra, rb) < 0);
+ }
+};
+
+static void bvh_reference_sort_threaded(TaskPool *task_pool,
+ BVHReference *data,
+ const int job_start,
+ const int job_end,
+ const BVHReferenceCompare &compare);
+
+/* Multi-threaded reference sort. */
+static void bvh_reference_sort_threaded(TaskPool *task_pool,
+ BVHReference *data,
+ const int job_start,
+ const int job_end,
+ const BVHReferenceCompare &compare)
+{
+ int start = job_start, end = job_end;
+ bool have_work = (start < end);
+ while (have_work) {
+ const int count = job_end - job_start;
+ if (count < BVH_SORT_THRESHOLD) {
+ /* Number of reference low enough, faster to finish the job
+ * in one thread rather than to spawn more threads.
+ */
+ sort(data + job_start, data + job_end + 1, compare);
+ break;
+ }
+ /* Single QSort step.
+ * Use median-of-three method for the pivot point.
+ */
+ int left = start, right = end;
+ int center = (left + right) >> 1;
+ if (compare.compare(data[left], data[center]) > 0) {
+ swap(data[left], data[center]);
+ }
+ if (compare.compare(data[left], data[right]) > 0) {
+ swap(data[left], data[right]);
+ }
+ if (compare.compare(data[center], data[right]) > 0) {
+ swap(data[center], data[right]);
+ }
+ swap(data[center], data[right - 1]);
+ BVHReference median = data[right - 1];
+ do {
+ while (compare.compare(data[left], median) < 0) {
+ ++left;
+ }
+ while (compare.compare(data[right], median) > 0) {
+ --right;
+ }
+ if (left <= right) {
+ swap(data[left], data[right]);
+ ++left;
+ --right;
+ }
+ } while (left <= right);
+ /* We only create one new task here to reduce downside effects of
+ * latency in TaskScheduler.
+ * So generally current thread keeps working on the left part of the
+ * array, and we create new task for the right side.
+ * However, if there's nothing to be done in the left side of the array
+ * we don't create any tasks and make it so current thread works on the
+ * right side.
+ */
+ have_work = false;
+ if (left < end) {
+ if (start < right) {
+ task_pool->push(
+ function_bind(bvh_reference_sort_threaded, task_pool, data, left, end, compare));
+ }
+ else {
+ start = left;
+ have_work = true;
+ }
+ }
+ if (start < right) {
+ end = right;
+ have_work = true;
+ }
+ }
+}
+
+void bvh_reference_sort(int start,
+ int end,
+ BVHReference *data,
+ int dim,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
+{
+ const int count = end - start;
+ BVHReferenceCompare compare(dim, unaligned_heuristic, aligned_space);
+ if (count < BVH_SORT_THRESHOLD) {
+ /* It is important to not use any mutex if array is small enough,
+ * otherwise we end up in situation when we're going to sleep far
+ * too often.
+ */
+ sort(data + start, data + end, compare);
+ }
+ else {
+ TaskPool task_pool;
+ bvh_reference_sort_threaded(&task_pool, data, start, end - 1, compare);
+ task_pool.wait_work();
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_sort.h b/intern/cycles/bvh/sort.h
index 936401d8607..936401d8607 100644
--- a/intern/cycles/bvh/bvh_sort.h
+++ b/intern/cycles/bvh/sort.h
diff --git a/intern/cycles/bvh/split.cpp b/intern/cycles/bvh/split.cpp
new file mode 100644
index 00000000000..102c50e2979
--- /dev/null
+++ b/intern/cycles/bvh/split.cpp
@@ -0,0 +1,518 @@
+/*
+ * Adapted from code copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bvh/split.h"
+
+#include "bvh/build.h"
+#include "bvh/sort.h"
+
+#include "scene/hair.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+
+#include "util/algorithm.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Object Split */
+
+BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
+ BVHSpatialStorage *storage,
+ const BVHRange &range,
+ vector<BVHReference> &references,
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
+ : sah(FLT_MAX),
+ dim(0),
+ num_left(0),
+ left_bounds(BoundBox::empty),
+ right_bounds(BoundBox::empty),
+ storage_(storage),
+ references_(&references),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
+{
+ const BVHReference *ref_ptr = &references_->at(range.start());
+ float min_sah = FLT_MAX;
+
+ storage_->right_bounds.resize(range.size());
+
+ for (int dim = 0; dim < 3; dim++) {
+ /* Sort references. */
+ bvh_reference_sort(range.start(),
+ range.end(),
+ &references_->at(0),
+ dim,
+ unaligned_heuristic_,
+ aligned_space_);
+
+ /* sweep right to left and determine bounds. */
+ BoundBox right_bounds = BoundBox::empty;
+ for (int i = range.size() - 1; i > 0; i--) {
+ BoundBox prim_bounds = get_prim_bounds(ref_ptr[i]);
+ right_bounds.grow(prim_bounds);
+ storage_->right_bounds[i - 1] = right_bounds;
+ }
+
+ /* sweep left to right and select lowest SAH. */
+ BoundBox left_bounds = BoundBox::empty;
+
+ for (int i = 1; i < range.size(); i++) {
+ BoundBox prim_bounds = get_prim_bounds(ref_ptr[i - 1]);
+ left_bounds.grow(prim_bounds);
+ right_bounds = storage_->right_bounds[i - 1];
+
+ float sah = nodeSAH + left_bounds.safe_area() * builder->params.primitive_cost(i) +
+ right_bounds.safe_area() * builder->params.primitive_cost(range.size() - i);
+
+ if (sah < min_sah) {
+ min_sah = sah;
+
+ this->sah = sah;
+ this->dim = dim;
+ this->num_left = i;
+ this->left_bounds = left_bounds;
+ this->right_bounds = right_bounds;
+ }
+ }
+ }
+}
+
+void BVHObjectSplit::split(BVHRange &left, BVHRange &right, const BVHRange &range)
+{
+ assert(references_->size() > 0);
+ /* sort references according to split */
+ bvh_reference_sort(range.start(),
+ range.end(),
+ &references_->at(0),
+ this->dim,
+ unaligned_heuristic_,
+ aligned_space_);
+
+ BoundBox effective_left_bounds, effective_right_bounds;
+ const int num_right = range.size() - this->num_left;
+ if (aligned_space_ == NULL) {
+ effective_left_bounds = left_bounds;
+ effective_right_bounds = right_bounds;
+ }
+ else {
+ effective_left_bounds = BoundBox::empty;
+ effective_right_bounds = BoundBox::empty;
+ for (int i = 0; i < this->num_left; ++i) {
+ BoundBox prim_boundbox = references_->at(range.start() + i).bounds();
+ effective_left_bounds.grow(prim_boundbox);
+ }
+ for (int i = 0; i < num_right; ++i) {
+ BoundBox prim_boundbox = references_->at(range.start() + this->num_left + i).bounds();
+ effective_right_bounds.grow(prim_boundbox);
+ }
+ }
+
+ /* split node ranges */
+ left = BVHRange(effective_left_bounds, range.start(), this->num_left);
+ right = BVHRange(effective_right_bounds, left.end(), num_right);
+}
+
+/* Spatial Split */
+
+BVHSpatialSplit::BVHSpatialSplit(const BVHBuild &builder,
+ BVHSpatialStorage *storage,
+ const BVHRange &range,
+ vector<BVHReference> &references,
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
+ : sah(FLT_MAX),
+ dim(0),
+ pos(0.0f),
+ storage_(storage),
+ references_(&references),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
+{
+ /* initialize bins. */
+ BoundBox range_bounds;
+ if (aligned_space == NULL) {
+ range_bounds = range.bounds();
+ }
+ else {
+ range_bounds = unaligned_heuristic->compute_aligned_boundbox(
+ range, &references_->at(0), *aligned_space);
+ }
+
+ float3 origin = range_bounds.min;
+ float3 binSize = (range_bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
+ float3 invBinSize = 1.0f / binSize;
+
+ for (int dim = 0; dim < 3; dim++) {
+ for (int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
+ BVHSpatialBin &bin = storage_->bins[dim][i];
+
+ bin.bounds = BoundBox::empty;
+ bin.enter = 0;
+ bin.exit = 0;
+ }
+ }
+
+ /* chop references into bins. */
+ for (unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) {
+ const BVHReference &ref = references_->at(refIdx);
+ BoundBox prim_bounds = get_prim_bounds(ref);
+ float3 firstBinf = (prim_bounds.min - origin) * invBinSize;
+ float3 lastBinf = (prim_bounds.max - origin) * invBinSize;
+ int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
+ int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z);
+
+ firstBin = clamp(firstBin, 0, BVHParams::NUM_SPATIAL_BINS - 1);
+ lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
+
+ for (int dim = 0; dim < 3; dim++) {
+ BVHReference currRef(
+ get_prim_bounds(ref), ref.prim_index(), ref.prim_object(), ref.prim_type());
+
+ for (int i = firstBin[dim]; i < lastBin[dim]; i++) {
+ BVHReference leftRef, rightRef;
+
+ split_reference(
+ builder, leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
+ storage_->bins[dim][i].bounds.grow(leftRef.bounds());
+ currRef = rightRef;
+ }
+
+ storage_->bins[dim][lastBin[dim]].bounds.grow(currRef.bounds());
+ storage_->bins[dim][firstBin[dim]].enter++;
+ storage_->bins[dim][lastBin[dim]].exit++;
+ }
+ }
+
+ /* select best split plane. */
+ storage_->right_bounds.resize(BVHParams::NUM_SPATIAL_BINS);
+ for (int dim = 0; dim < 3; dim++) {
+ /* sweep right to left and determine bounds. */
+ BoundBox right_bounds = BoundBox::empty;
+ for (int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
+ right_bounds.grow(storage_->bins[dim][i].bounds);
+ storage_->right_bounds[i - 1] = right_bounds;
+ }
+
+ /* sweep left to right and select lowest SAH. */
+ BoundBox left_bounds = BoundBox::empty;
+ int leftNum = 0;
+ int rightNum = range.size();
+
+ for (int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
+ left_bounds.grow(storage_->bins[dim][i - 1].bounds);
+ leftNum += storage_->bins[dim][i - 1].enter;
+ rightNum -= storage_->bins[dim][i - 1].exit;
+
+ float sah = nodeSAH + left_bounds.safe_area() * builder.params.primitive_cost(leftNum) +
+ storage_->right_bounds[i - 1].safe_area() *
+ builder.params.primitive_cost(rightNum);
+
+ if (sah < this->sah) {
+ this->sah = sah;
+ this->dim = dim;
+ this->pos = origin[dim] + binSize[dim] * (float)i;
+ }
+ }
+ }
+}
+
+void BVHSpatialSplit::split(BVHBuild *builder,
+ BVHRange &left,
+ BVHRange &right,
+ const BVHRange &range)
+{
+ /* Categorize references and compute bounds.
+ *
+ * Left-hand side: [left_start, left_end[
+ * Uncategorized/split: [left_end, right_start[
+ * Right-hand side: [right_start, refs.size()[ */
+
+ vector<BVHReference> &refs = *references_;
+ int left_start = range.start();
+ int left_end = left_start;
+ int right_start = range.end();
+ int right_end = range.end();
+ BoundBox left_bounds = BoundBox::empty;
+ BoundBox right_bounds = BoundBox::empty;
+
+ for (int i = left_end; i < right_start; i++) {
+ BoundBox prim_bounds = get_prim_bounds(refs[i]);
+ if (prim_bounds.max[this->dim] <= this->pos) {
+ /* entirely on the left-hand side */
+ left_bounds.grow(prim_bounds);
+ swap(refs[i], refs[left_end++]);
+ }
+ else if (prim_bounds.min[this->dim] >= this->pos) {
+ /* entirely on the right-hand side */
+ right_bounds.grow(prim_bounds);
+ swap(refs[i--], refs[--right_start]);
+ }
+ }
+
+ /* Duplicate or unsplit references intersecting both sides.
+ *
+ * Duplication happens into a temporary pre-allocated vector in order to
+ * reduce number of memmove() calls happening in vector.insert().
+ */
+ vector<BVHReference> &new_refs = storage_->new_references;
+ new_refs.clear();
+ new_refs.reserve(right_start - left_end);
+ while (left_end < right_start) {
+ /* split reference. */
+ BVHReference curr_ref(get_prim_bounds(refs[left_end]),
+ refs[left_end].prim_index(),
+ refs[left_end].prim_object(),
+ refs[left_end].prim_type());
+ BVHReference lref, rref;
+ split_reference(*builder, lref, rref, curr_ref, this->dim, this->pos);
+
+ /* compute SAH for duplicate/unsplit candidates. */
+ BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds.
+ BoundBox rub = right_bounds; // Unsplit to right: new right-hand bounds.
+ BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds.
+ BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds.
+
+ lub.grow(curr_ref.bounds());
+ rub.grow(curr_ref.bounds());
+ ldb.grow(lref.bounds());
+ rdb.grow(rref.bounds());
+
+ float lac = builder->params.primitive_cost(left_end - left_start);
+ float rac = builder->params.primitive_cost(right_end - right_start);
+ float lbc = builder->params.primitive_cost(left_end - left_start + 1);
+ float rbc = builder->params.primitive_cost(right_end - right_start + 1);
+
+ float unsplitLeftSAH = lub.safe_area() * lbc + right_bounds.safe_area() * rac;
+ float unsplitRightSAH = left_bounds.safe_area() * lac + rub.safe_area() * rbc;
+ float duplicateSAH = ldb.safe_area() * lbc + rdb.safe_area() * rbc;
+ float minSAH = min(min(unsplitLeftSAH, unsplitRightSAH), duplicateSAH);
+
+ if (minSAH == unsplitLeftSAH) {
+ /* unsplit to left */
+ left_bounds = lub;
+ left_end++;
+ }
+ else if (minSAH == unsplitRightSAH) {
+ /* unsplit to right */
+ right_bounds = rub;
+ swap(refs[left_end], refs[--right_start]);
+ }
+ else {
+ /* duplicate */
+ left_bounds = ldb;
+ right_bounds = rdb;
+ refs[left_end++] = lref;
+ new_refs.push_back(rref);
+ right_end++;
+ }
+ }
+ /* Insert duplicated references into actual array in one go. */
+ if (new_refs.size() != 0) {
+ refs.insert(refs.begin() + (right_end - new_refs.size()), new_refs.begin(), new_refs.end());
+ }
+ if (aligned_space_ != NULL) {
+ left_bounds = right_bounds = BoundBox::empty;
+ for (int i = left_start; i < left_end - left_start; ++i) {
+ BoundBox prim_boundbox = references_->at(i).bounds();
+ left_bounds.grow(prim_boundbox);
+ }
+ for (int i = right_start; i < right_end - right_start; ++i) {
+ BoundBox prim_boundbox = references_->at(i).bounds();
+ right_bounds.grow(prim_boundbox);
+ }
+ }
+ left = BVHRange(left_bounds, left_start, left_end - left_start);
+ right = BVHRange(right_bounds, right_start, right_end - right_start);
+}
+
+void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh,
+ const Transform *tfm,
+ int prim_index,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
+{
+ Mesh::Triangle t = mesh->get_triangle(prim_index);
+ const float3 *verts = &mesh->verts[0];
+ float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]];
+ v1 = get_unaligned_point(v1);
+
+ for (int i = 0; i < 3; i++) {
+ float3 v0 = v1;
+ int vindex = t.v[i];
+ v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex];
+ v1 = get_unaligned_point(v1);
+ float v0p = v0[dim];
+ float v1p = v1[dim];
+
+ /* insert vertex to the boxes it belongs to. */
+ if (v0p <= pos)
+ left_bounds.grow(v0);
+
+ if (v0p >= pos)
+ right_bounds.grow(v0);
+
+ /* edge intersects the plane => insert intersection to both boxes. */
+ if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
+ float3 t = lerp(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
+ left_bounds.grow(t);
+ right_bounds.grow(t);
+ }
+ }
+}
+
+void BVHSpatialSplit::split_curve_primitive(const Hair *hair,
+ const Transform *tfm,
+ int prim_index,
+ int segment_index,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
+{
+ /* curve split: NOTE - Currently ignores curve width and needs to be fixed. */
+ Hair::Curve curve = hair->get_curve(prim_index);
+ const int k0 = curve.first_key + segment_index;
+ const int k1 = k0 + 1;
+ float3 v0 = hair->get_curve_keys()[k0];
+ float3 v1 = hair->get_curve_keys()[k1];
+
+ if (tfm != NULL) {
+ v0 = transform_point(tfm, v0);
+ v1 = transform_point(tfm, v1);
+ }
+ v0 = get_unaligned_point(v0);
+ v1 = get_unaligned_point(v1);
+
+ float v0p = v0[dim];
+ float v1p = v1[dim];
+
+ /* insert vertex to the boxes it belongs to. */
+ if (v0p <= pos)
+ left_bounds.grow(v0);
+
+ if (v0p >= pos)
+ right_bounds.grow(v0);
+
+ if (v1p <= pos)
+ left_bounds.grow(v1);
+
+ if (v1p >= pos)
+ right_bounds.grow(v1);
+
+ /* edge intersects the plane => insert intersection to both boxes. */
+ if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
+ float3 t = lerp(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
+ left_bounds.grow(t);
+ right_bounds.grow(t);
+ }
+}
+
+void BVHSpatialSplit::split_triangle_reference(const BVHReference &ref,
+ const Mesh *mesh,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
+{
+ split_triangle_primitive(mesh, NULL, ref.prim_index(), dim, pos, left_bounds, right_bounds);
+}
+
+void BVHSpatialSplit::split_curve_reference(const BVHReference &ref,
+ const Hair *hair,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
+{
+ split_curve_primitive(hair,
+ NULL,
+ ref.prim_index(),
+ PRIMITIVE_UNPACK_SEGMENT(ref.prim_type()),
+ dim,
+ pos,
+ left_bounds,
+ right_bounds);
+}
+
+void BVHSpatialSplit::split_object_reference(
+ const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
+{
+ Geometry *geom = object->get_geometry();
+
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ for (int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) {
+ split_triangle_primitive(
+ mesh, &object->get_tfm(), tri_idx, dim, pos, left_bounds, right_bounds);
+ }
+ }
+ else if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ for (int curve_idx = 0; curve_idx < hair->num_curves(); ++curve_idx) {
+ Hair::Curve curve = hair->get_curve(curve_idx);
+ for (int segment_idx = 0; segment_idx < curve.num_keys - 1; ++segment_idx) {
+ split_curve_primitive(
+ hair, &object->get_tfm(), curve_idx, segment_idx, dim, pos, left_bounds, right_bounds);
+ }
+ }
+ }
+}
+
+void BVHSpatialSplit::split_reference(const BVHBuild &builder,
+ BVHReference &left,
+ BVHReference &right,
+ const BVHReference &ref,
+ int dim,
+ float pos)
+{
+ /* initialize boundboxes */
+ BoundBox left_bounds = BoundBox::empty;
+ BoundBox right_bounds = BoundBox::empty;
+
+ /* loop over vertices/edges. */
+ const Object *ob = builder.objects[ref.prim_object()];
+
+ if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
+ Mesh *mesh = static_cast<Mesh *>(ob->get_geometry());
+ split_triangle_reference(ref, mesh, dim, pos, left_bounds, right_bounds);
+ }
+ else if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
+ Hair *hair = static_cast<Hair *>(ob->get_geometry());
+ split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds);
+ }
+ else {
+ split_object_reference(ob, dim, pos, left_bounds, right_bounds);
+ }
+
+ /* intersect with original bounds. */
+ left_bounds.max[dim] = pos;
+ right_bounds.min[dim] = pos;
+
+ left_bounds.intersect(ref.bounds());
+ right_bounds.intersect(ref.bounds());
+
+ /* set references */
+ left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
+ right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/split.h b/intern/cycles/bvh/split.h
new file mode 100644
index 00000000000..2650a500ea9
--- /dev/null
+++ b/intern/cycles/bvh/split.h
@@ -0,0 +1,240 @@
+/*
+ * Adapted from code copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_SPLIT_H__
+#define __BVH_SPLIT_H__
+
+#include "bvh/build.h"
+#include "bvh/params.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BVHBuild;
+class Hair;
+class Mesh;
+struct Transform;
+
+/* Object Split */
+
+class BVHObjectSplit {
+ public:
+ float sah;
+ int dim;
+ int num_left;
+ BoundBox left_bounds;
+ BoundBox right_bounds;
+
+ BVHObjectSplit()
+ {
+ }
+ BVHObjectSplit(BVHBuild *builder,
+ BVHSpatialStorage *storage,
+ const BVHRange &range,
+ vector<BVHReference> &references,
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
+
+ void split(BVHRange &left, BVHRange &right, const BVHRange &range);
+
+ protected:
+ BVHSpatialStorage *storage_;
+ vector<BVHReference> *references_;
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
+ {
+ if (aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(prim, *aligned_space_);
+ }
+ }
+};
+
+/* Spatial Split */
+
+class BVHSpatialSplit {
+ public:
+ float sah;
+ int dim;
+ float pos;
+
+ BVHSpatialSplit() : sah(FLT_MAX), dim(0), pos(0.0f), storage_(NULL), references_(NULL)
+ {
+ }
+ BVHSpatialSplit(const BVHBuild &builder,
+ BVHSpatialStorage *storage,
+ const BVHRange &range,
+ vector<BVHReference> &references,
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
+
+ void split(BVHBuild *builder, BVHRange &left, BVHRange &right, const BVHRange &range);
+
+ void split_reference(const BVHBuild &builder,
+ BVHReference &left,
+ BVHReference &right,
+ const BVHReference &ref,
+ int dim,
+ float pos);
+
+ protected:
+ BVHSpatialStorage *storage_;
+ vector<BVHReference> *references_;
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
+
+ /* Lower-level functions which calculates boundaries of left and right nodes
+ * needed for spatial split.
+ *
+ * Operates directly with primitive specified by its index, reused by higher
+ * level splitting functions.
+ */
+ void split_triangle_primitive(const Mesh *mesh,
+ const Transform *tfm,
+ int prim_index,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds);
+ void split_curve_primitive(const Hair *hair,
+ const Transform *tfm,
+ int prim_index,
+ int segment_index,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds);
+
+ /* Lower-level functions which calculates boundaries of left and right nodes
+ * needed for spatial split.
+ *
+ * Operates with BVHReference, internally uses lower level API functions.
+ */
+ void split_triangle_reference(const BVHReference &ref,
+ const Mesh *mesh,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds);
+ void split_curve_reference(const BVHReference &ref,
+ const Hair *hair,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds);
+ void split_object_reference(
+ const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds);
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
+ {
+ if (aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(prim, *aligned_space_);
+ }
+ }
+
+ __forceinline float3 get_unaligned_point(const float3 &point) const
+ {
+ if (aligned_space_ == NULL) {
+ return point;
+ }
+ else {
+ return transform_point(aligned_space_, point);
+ }
+ }
+};
+
+/* Mixed Object-Spatial Split */
+
+class BVHMixedSplit {
+ public:
+ BVHObjectSplit object;
+ BVHSpatialSplit spatial;
+
+ float leafSAH;
+ float nodeSAH;
+ float minSAH;
+
+ bool no_split;
+
+ BoundBox bounds;
+
+ BVHMixedSplit()
+ {
+ }
+
+ __forceinline BVHMixedSplit(BVHBuild *builder,
+ BVHSpatialStorage *storage,
+ const BVHRange &range,
+ vector<BVHReference> &references,
+ int level,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL)
+ {
+ if (aligned_space == NULL) {
+ bounds = range.bounds();
+ }
+ else {
+ bounds = unaligned_heuristic->compute_aligned_boundbox(
+ range, &references.at(0), *aligned_space);
+ }
+ /* find split candidates. */
+ float area = bounds.safe_area();
+
+ leafSAH = area * builder->params.primitive_cost(range.size());
+ nodeSAH = area * builder->params.node_cost(2);
+
+ object = BVHObjectSplit(
+ builder, storage, range, references, nodeSAH, unaligned_heuristic, aligned_space);
+
+ if (builder->params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
+ BoundBox overlap = object.left_bounds;
+ overlap.intersect(object.right_bounds);
+
+ if (overlap.safe_area() >= builder->spatial_min_overlap) {
+ spatial = BVHSpatialSplit(
+ *builder, storage, range, references, nodeSAH, unaligned_heuristic, aligned_space);
+ }
+ }
+
+ /* leaf SAH is the lowest => create leaf. */
+ minSAH = min(min(leafSAH, object.sah), spatial.sah);
+ no_split = (minSAH == leafSAH && builder->range_within_max_leaf_size(range, references));
+ }
+
+ __forceinline void split(BVHBuild *builder,
+ BVHRange &left,
+ BVHRange &right,
+ const BVHRange &range)
+ {
+ if (builder->params.use_spatial_split && minSAH == spatial.sah)
+ spatial.split(builder, left, right, range);
+ if (!left.size() || !right.size())
+ object.split(left, right, range);
+ }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_SPLIT_H__ */
diff --git a/intern/cycles/bvh/unaligned.cpp b/intern/cycles/bvh/unaligned.cpp
new file mode 100644
index 00000000000..3c4a600fe58
--- /dev/null
+++ b/intern/cycles/bvh/unaligned.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bvh/unaligned.h"
+
+#include "scene/hair.h"
+#include "scene/object.h"
+
+#include "bvh/binning.h"
+#include "bvh/params.h"
+
+#include "util/boundbox.h"
+#include "util/transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+BVHUnaligned::BVHUnaligned(const vector<Object *> &objects) : objects_(objects)
+{
+}
+
+Transform BVHUnaligned::compute_aligned_space(const BVHObjectBinning &range,
+ const BVHReference *references) const
+{
+ for (int i = range.start(); i < range.end(); ++i) {
+ const BVHReference &ref = references[i];
+ Transform aligned_space;
+ /* Use first primitive which defines correct direction to define
+ * the orientation space.
+ */
+ if (compute_aligned_space(ref, &aligned_space)) {
+ return aligned_space;
+ }
+ }
+ return transform_identity();
+}
+
+Transform BVHUnaligned::compute_aligned_space(const BVHRange &range,
+ const BVHReference *references) const
+{
+ for (int i = range.start(); i < range.end(); ++i) {
+ const BVHReference &ref = references[i];
+ Transform aligned_space;
+ /* Use first primitive which defines correct direction to define
+ * the orientation space.
+ */
+ if (compute_aligned_space(ref, &aligned_space)) {
+ return aligned_space;
+ }
+ }
+ return transform_identity();
+}
+
+bool BVHUnaligned::compute_aligned_space(const BVHReference &ref, Transform *aligned_space) const
+{
+ const Object *object = objects_[ref.prim_object()];
+ const int packed_type = ref.prim_type();
+ const int type = (packed_type & PRIMITIVE_ALL);
+ /* No motion blur curves here, we can't fit them to aligned boxes well. */
+ if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
+ const int curve_index = ref.prim_index();
+ const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
+ const Hair *hair = static_cast<const Hair *>(object->get_geometry());
+ const Hair::Curve &curve = hair->get_curve(curve_index);
+ const int key = curve.first_key + segment;
+ const float3 v1 = hair->get_curve_keys()[key], v2 = hair->get_curve_keys()[key + 1];
+ float length;
+ const float3 axis = normalize_len(v2 - v1, &length);
+ if (length > 1e-6f) {
+ *aligned_space = make_transform_frame(axis);
+ return true;
+ }
+ }
+ *aligned_space = transform_identity();
+ return false;
+}
+
+BoundBox BVHUnaligned::compute_aligned_prim_boundbox(const BVHReference &prim,
+ const Transform &aligned_space) const
+{
+ BoundBox bounds = BoundBox::empty;
+ const Object *object = objects_[prim.prim_object()];
+ const int packed_type = prim.prim_type();
+ const int type = (packed_type & PRIMITIVE_ALL);
+ /* No motion blur curves here, we can't fit them to aligned boxes well. */
+ if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
+ const int curve_index = prim.prim_index();
+ const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
+ const Hair *hair = static_cast<const Hair *>(object->get_geometry());
+ const Hair::Curve &curve = hair->get_curve(curve_index);
+ curve.bounds_grow(
+ segment, &hair->get_curve_keys()[0], &hair->get_curve_radius()[0], aligned_space, bounds);
+ }
+ else {
+ bounds = prim.bounds().transformed(&aligned_space);
+ }
+ return bounds;
+}
+
+BoundBox BVHUnaligned::compute_aligned_boundbox(const BVHObjectBinning &range,
+ const BVHReference *references,
+ const Transform &aligned_space,
+ BoundBox *cent_bounds) const
+{
+ BoundBox bounds = BoundBox::empty;
+ if (cent_bounds != NULL) {
+ *cent_bounds = BoundBox::empty;
+ }
+ for (int i = range.start(); i < range.end(); ++i) {
+ const BVHReference &ref = references[i];
+ BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
+ bounds.grow(ref_bounds);
+ if (cent_bounds != NULL) {
+ cent_bounds->grow(ref_bounds.center2());
+ }
+ }
+ return bounds;
+}
+
+BoundBox BVHUnaligned::compute_aligned_boundbox(const BVHRange &range,
+ const BVHReference *references,
+ const Transform &aligned_space,
+ BoundBox *cent_bounds) const
+{
+ BoundBox bounds = BoundBox::empty;
+ if (cent_bounds != NULL) {
+ *cent_bounds = BoundBox::empty;
+ }
+ for (int i = range.start(); i < range.end(); ++i) {
+ const BVHReference &ref = references[i];
+ BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
+ bounds.grow(ref_bounds);
+ if (cent_bounds != NULL) {
+ cent_bounds->grow(ref_bounds.center2());
+ }
+ }
+ return bounds;
+}
+
+Transform BVHUnaligned::compute_node_transform(const BoundBox &bounds,
+ const Transform &aligned_space)
+{
+ Transform space = aligned_space;
+ space.x.w -= bounds.min.x;
+ space.y.w -= bounds.min.y;
+ space.z.w -= bounds.min.z;
+ float3 dim = bounds.max - bounds.min;
+ return transform_scale(
+ 1.0f / max(1e-18f, dim.x), 1.0f / max(1e-18f, dim.y), 1.0f / max(1e-18f, dim.z)) *
+ space;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/unaligned.h b/intern/cycles/bvh/unaligned.h
new file mode 100644
index 00000000000..33e584ea8ed
--- /dev/null
+++ b/intern/cycles/bvh/unaligned.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_UNALIGNED_H__
+#define __BVH_UNALIGNED_H__
+
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BoundBox;
+class BVHObjectBinning;
+class BVHRange;
+class BVHReference;
+struct Transform;
+class Object;
+
+/* Helper class to perform calculations needed for unaligned nodes. */
+class BVHUnaligned {
+ public:
+ BVHUnaligned(const vector<Object *> &objects);
+
+ /* Calculate alignment for the oriented node for a given range. */
+ Transform compute_aligned_space(const BVHObjectBinning &range,
+ const BVHReference *references) const;
+ Transform compute_aligned_space(const BVHRange &range, const BVHReference *references) const;
+
+ /* Calculate alignment for the oriented node for a given reference.
+ *
+ * Return true when space was calculated successfully.
+ */
+ bool compute_aligned_space(const BVHReference &ref, Transform *aligned_space) const;
+
+ /* Calculate primitive's bounding box in given space. */
+ BoundBox compute_aligned_prim_boundbox(const BVHReference &prim,
+ const Transform &aligned_space) const;
+
+ /* Calculate bounding box in given space. */
+ BoundBox compute_aligned_boundbox(const BVHObjectBinning &range,
+ const BVHReference *references,
+ const Transform &aligned_space,
+ BoundBox *cent_bounds = NULL) const;
+ BoundBox compute_aligned_boundbox(const BVHRange &range,
+ const BVHReference *references,
+ const Transform &aligned_space,
+ BoundBox *cent_bounds = NULL) const;
+
+ /* Calculate affine transform for node packing.
+ * Bounds will be in the range of 0..1.
+ */
+ static Transform compute_node_transform(const BoundBox &bounds, const Transform &aligned_space);
+
+ protected:
+ /* List of objects BVH is being created for. */
+ const vector<Object *> &objects_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_UNALIGNED_H__ */
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index 6d33a6f107f..99b1fc8135d 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -45,11 +45,11 @@ endif()
set(SRC
device.cpp
- device_denoise.cpp
- device_graphics_interop.cpp
- device_kernel.cpp
- device_memory.cpp
- device_queue.cpp
+ denoise.cpp
+ graphics_interop.cpp
+ kernel.cpp
+ memory.cpp
+ queue.cpp
)
set(SRC_CPU
@@ -116,11 +116,11 @@ set(SRC_OPTIX
set(SRC_HEADERS
device.h
- device_denoise.h
- device_graphics_interop.h
- device_memory.h
- device_kernel.h
- device_queue.h
+ denoise.h
+ graphics_interop.h
+ memory.h
+ kernel.h
+ queue.h
)
set(LIB
@@ -158,9 +158,6 @@ endif()
if(WITH_CYCLES_DEVICE_OPTIX)
add_definitions(-DWITH_OPTIX)
endif()
-if(WITH_CYCLES_DEVICE_MULTI)
- add_definitions(-DWITH_MULTI)
-endif()
if(WITH_OPENIMAGEDENOISE)
list(APPEND LIB
diff --git a/intern/cycles/device/cpu/device.cpp b/intern/cycles/device/cpu/device.cpp
index 68ca8e8bb22..f11b49ef65f 100644
--- a/intern/cycles/device/cpu/device.cpp
+++ b/intern/cycles/device/cpu/device.cpp
@@ -20,7 +20,7 @@
/* Used for `info.denoisers`. */
/* TODO(sergey): The denoisers are probably to be moved completely out of the device into their
* own class. But until then keep API consistent with how it used to work before. */
-#include "util/util_openimagedenoise.h"
+#include "util/openimagedenoise.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/cpu/device.h b/intern/cycles/device/cpu/device.h
index 9cb2e80068d..c53bc338127 100644
--- a/intern/cycles/device/cpu/device.h
+++ b/intern/cycles/device/cpu/device.h
@@ -16,8 +16,8 @@
#pragma once
-#include "util/util_string.h"
-#include "util/util_vector.h"
+#include "util/string.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/cpu/device_impl.cpp b/intern/cycles/device/cpu/device_impl.cpp
index d02c18daee9..dbad332f896 100644
--- a/intern/cycles/device/cpu/device_impl.cpp
+++ b/intern/cycles/device/cpu/device_impl.cpp
@@ -22,7 +22,7 @@
/* So ImathMath is included before our kernel_cpu_compat. */
#ifdef WITH_OSL
/* So no context pollution happens from indirectly included windows.h */
-# include "util/util_windows.h"
+# include "util/windows.h"
# include <OSL/oslexec.h>
#endif
@@ -39,27 +39,27 @@
#include "kernel/device/cpu/compat.h"
#include "kernel/device/cpu/globals.h"
#include "kernel/device/cpu/kernel.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
-#include "kernel/osl/osl_shader.h"
-#include "kernel/osl/osl_globals.h"
+#include "kernel/osl/shader.h"
+#include "kernel/osl/globals.h"
// clang-format on
-#include "bvh/bvh_embree.h"
-
-#include "render/buffers.h"
-
-#include "util/util_debug.h"
-#include "util/util_foreach.h"
-#include "util/util_function.h"
-#include "util/util_logging.h"
-#include "util/util_map.h"
-#include "util/util_openimagedenoise.h"
-#include "util/util_optimization.h"
-#include "util/util_progress.h"
-#include "util/util_system.h"
-#include "util/util_task.h"
-#include "util/util_thread.h"
+#include "bvh/embree.h"
+
+#include "session/buffers.h"
+
+#include "util/debug.h"
+#include "util/foreach.h"
+#include "util/function.h"
+#include "util/log.h"
+#include "util/map.h"
+#include "util/openimagedenoise.h"
+#include "util/optimization.h"
+#include "util/progress.h"
+#include "util/system.h"
+#include "util/task.h"
+#include "util/thread.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/cpu/device_impl.h b/intern/cycles/device/cpu/device_impl.h
index 944c61e29f7..553728ccc3b 100644
--- a/intern/cycles/device/cpu/device_impl.h
+++ b/intern/cycles/device/cpu/device_impl.h
@@ -19,7 +19,7 @@
/* So ImathMath is included before our kernel_cpu_compat. */
#ifdef WITH_OSL
/* So no context pollution happens from indirectly included windows.h */
-# include "util/util_windows.h"
+# include "util/windows.h"
# include <OSL/oslexec.h>
#endif
@@ -29,15 +29,15 @@
#include "device/cpu/kernel.h"
#include "device/device.h"
-#include "device/device_memory.h"
+#include "device/memory.h"
// clang-format off
#include "kernel/device/cpu/compat.h"
#include "kernel/device/cpu/kernel.h"
#include "kernel/device/cpu/globals.h"
-#include "kernel/osl/osl_shader.h"
-#include "kernel/osl/osl_globals.h"
+#include "kernel/osl/shader.h"
+#include "kernel/osl/globals.h"
// clang-format on
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/cpu/kernel.h b/intern/cycles/device/cpu/kernel.h
index 5f9cb85389f..5beeaf148a1 100644
--- a/intern/cycles/device/cpu/kernel.h
+++ b/intern/cycles/device/cpu/kernel.h
@@ -17,7 +17,7 @@
#pragma once
#include "device/cpu/kernel_function.h"
-#include "util/util_types.h"
+#include "util/types.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/cpu/kernel_function.h b/intern/cycles/device/cpu/kernel_function.h
index aa18720cc24..5ff55499d48 100644
--- a/intern/cycles/device/cpu/kernel_function.h
+++ b/intern/cycles/device/cpu/kernel_function.h
@@ -16,8 +16,8 @@
#pragma once
-#include "util/util_debug.h"
-#include "util/util_system.h"
+#include "util/debug.h"
+#include "util/system.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/cpu/kernel_thread_globals.cpp b/intern/cycles/device/cpu/kernel_thread_globals.cpp
index 44735beb88d..739b6460318 100644
--- a/intern/cycles/device/cpu/kernel_thread_globals.cpp
+++ b/intern/cycles/device/cpu/kernel_thread_globals.cpp
@@ -17,11 +17,11 @@
#include "device/cpu/kernel_thread_globals.h"
// clang-format off
-#include "kernel/osl/osl_shader.h"
-#include "kernel/osl/osl_globals.h"
+#include "kernel/osl/shader.h"
+#include "kernel/osl/globals.h"
// clang-format on
-#include "util/util_profiling.h"
+#include "util/profiling.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/cuda/device.cpp b/intern/cycles/device/cuda/device.cpp
index 84becd6d081..af2bdc6e29c 100644
--- a/intern/cycles/device/cuda/device.cpp
+++ b/intern/cycles/device/cuda/device.cpp
@@ -16,14 +16,14 @@
#include "device/cuda/device.h"
-#include "util/util_logging.h"
+#include "util/log.h"
#ifdef WITH_CUDA
# include "device/cuda/device_impl.h"
# include "device/device.h"
-# include "util/util_string.h"
-# include "util/util_windows.h"
+# include "util/string.h"
+# include "util/windows.h"
#endif /* WITH_CUDA */
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/cuda/device.h b/intern/cycles/device/cuda/device.h
index b0484904d1a..7142ad19857 100644
--- a/intern/cycles/device/cuda/device.h
+++ b/intern/cycles/device/cuda/device.h
@@ -16,8 +16,8 @@
#pragma once
-#include "util/util_string.h"
-#include "util/util_vector.h"
+#include "util/string.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/cuda/device_impl.cpp b/intern/cycles/device/cuda/device_impl.cpp
index 1c970096801..2f9a1394ad8 100644
--- a/intern/cycles/device/cuda/device_impl.cpp
+++ b/intern/cycles/device/cuda/device_impl.cpp
@@ -24,19 +24,17 @@
# include "device/cuda/device_impl.h"
-# include "render/buffers.h"
-
-# include "util/util_debug.h"
-# include "util/util_foreach.h"
-# include "util/util_logging.h"
-# include "util/util_map.h"
-# include "util/util_md5.h"
-# include "util/util_path.h"
-# include "util/util_string.h"
-# include "util/util_system.h"
-# include "util/util_time.h"
-# include "util/util_types.h"
-# include "util/util_windows.h"
+# include "util/debug.h"
+# include "util/foreach.h"
+# include "util/log.h"
+# include "util/map.h"
+# include "util/md5.h"
+# include "util/path.h"
+# include "util/string.h"
+# include "util/system.h"
+# include "util/time.h"
+# include "util/types.h"
+# include "util/windows.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/cuda/device_impl.h b/intern/cycles/device/cuda/device_impl.h
index c0316d18ba0..72d4108d1bf 100644
--- a/intern/cycles/device/cuda/device_impl.h
+++ b/intern/cycles/device/cuda/device_impl.h
@@ -21,7 +21,7 @@
# include "device/cuda/util.h"
# include "device/device.h"
-# include "util/util_map.h"
+# include "util/map.h"
# ifdef WITH_CUDA_DYNLOAD
# include "cuew.h"
diff --git a/intern/cycles/device/cuda/graphics_interop.h b/intern/cycles/device/cuda/graphics_interop.h
index ec480f20c86..a00a837efea 100644
--- a/intern/cycles/device/cuda/graphics_interop.h
+++ b/intern/cycles/device/cuda/graphics_interop.h
@@ -16,7 +16,7 @@
#ifdef WITH_CUDA
-# include "device/device_graphics_interop.h"
+# include "device/graphics_interop.h"
# ifdef WITH_CUDA_DYNLOAD
# include "cuew.h"
diff --git a/intern/cycles/device/cuda/kernel.h b/intern/cycles/device/cuda/kernel.h
index b489547a350..e1650ea5b5b 100644
--- a/intern/cycles/device/cuda/kernel.h
+++ b/intern/cycles/device/cuda/kernel.h
@@ -18,7 +18,7 @@
#ifdef WITH_CUDA
-# include "device/device_kernel.h"
+# include "device/kernel.h"
# ifdef WITH_CUDA_DYNLOAD
# include "cuew.h"
diff --git a/intern/cycles/device/cuda/queue.h b/intern/cycles/device/cuda/queue.h
index 4d1995ed69e..28613cda071 100644
--- a/intern/cycles/device/cuda/queue.h
+++ b/intern/cycles/device/cuda/queue.h
@@ -18,9 +18,9 @@
#ifdef WITH_CUDA
-# include "device/device_kernel.h"
-# include "device/device_memory.h"
-# include "device/device_queue.h"
+# include "device/kernel.h"
+# include "device/memory.h"
+# include "device/queue.h"
# include "device/cuda/util.h"
diff --git a/intern/cycles/device/denoise.cpp b/intern/cycles/device/denoise.cpp
new file mode 100644
index 00000000000..c291a7a0adb
--- /dev/null
+++ b/intern/cycles/device/denoise.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device/denoise.h"
+
+CCL_NAMESPACE_BEGIN
+
+const char *denoiserTypeToHumanReadable(DenoiserType type)
+{
+ switch (type) {
+ case DENOISER_OPTIX:
+ return "OptiX";
+ case DENOISER_OPENIMAGEDENOISE:
+ return "OpenImageDenoise";
+
+ case DENOISER_NUM:
+ case DENOISER_NONE:
+ case DENOISER_ALL:
+ return "UNKNOWN";
+ }
+
+ return "UNKNOWN";
+}
+
+const NodeEnum *DenoiseParams::get_type_enum()
+{
+ static NodeEnum type_enum;
+
+ if (type_enum.empty()) {
+ type_enum.insert("optix", DENOISER_OPTIX);
+ type_enum.insert("openimageio", DENOISER_OPENIMAGEDENOISE);
+ }
+
+ return &type_enum;
+}
+
+const NodeEnum *DenoiseParams::get_prefilter_enum()
+{
+ static NodeEnum prefilter_enum;
+
+ if (prefilter_enum.empty()) {
+ prefilter_enum.insert("none", DENOISER_PREFILTER_NONE);
+ prefilter_enum.insert("fast", DENOISER_PREFILTER_FAST);
+ prefilter_enum.insert("accurate", DENOISER_PREFILTER_ACCURATE);
+ }
+
+ return &prefilter_enum;
+}
+
+NODE_DEFINE(DenoiseParams)
+{
+ NodeType *type = NodeType::add("denoise_params", create);
+
+ const NodeEnum *type_enum = get_type_enum();
+ const NodeEnum *prefilter_enum = get_prefilter_enum();
+
+ SOCKET_BOOLEAN(use, "Use", false);
+
+ SOCKET_ENUM(type, "Type", *type_enum, DENOISER_OPENIMAGEDENOISE);
+
+ SOCKET_INT(start_sample, "Start Sample", 0);
+
+ SOCKET_BOOLEAN(use_pass_albedo, "Use Pass Albedo", true);
+ SOCKET_BOOLEAN(use_pass_normal, "Use Pass Normal", false);
+
+ SOCKET_ENUM(prefilter, "Prefilter", *prefilter_enum, DENOISER_PREFILTER_FAST);
+
+ return type;
+}
+
+DenoiseParams::DenoiseParams() : Node(get_node_type())
+{
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/denoise.h b/intern/cycles/device/denoise.h
new file mode 100644
index 00000000000..3f30506ae06
--- /dev/null
+++ b/intern/cycles/device/denoise.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "device/memory.h"
+#include "graph/node.h"
+#include "session/buffers.h"
+
+CCL_NAMESPACE_BEGIN
+
+enum DenoiserType {
+ DENOISER_OPTIX = 2,
+ DENOISER_OPENIMAGEDENOISE = 4,
+ DENOISER_NUM,
+
+ DENOISER_NONE = 0,
+ DENOISER_ALL = ~0,
+};
+
+/* COnstruct human-readable string which denotes the denoiser type. */
+const char *denoiserTypeToHumanReadable(DenoiserType type);
+
+typedef int DenoiserTypeMask;
+
+enum DenoiserPrefilter {
+ /* Best quality of the result without extra processing time, but requires guiding passes to be
+ * noise-free. */
+ DENOISER_PREFILTER_NONE = 1,
+
+ /* Denoise color and guiding passes together.
+ * Improves quality when guiding passes are noisy using least amount of extra processing time. */
+ DENOISER_PREFILTER_FAST = 2,
+
+ /* Prefilter noisy guiding passes before denoising color.
+ * Improves quality when guiding passes are noisy using extra processing time. */
+ DENOISER_PREFILTER_ACCURATE = 3,
+
+ DENOISER_PREFILTER_NUM,
+};
+
+/* NOTE: Is not a real scene node. Using Node API for ease of (de)serialization.
+ * The default values here do not really matter as they are always initialized from the
+ * Integrator node. */
+class DenoiseParams : public Node {
+ public:
+ NODE_DECLARE
+
+ /* Apply denoiser to image. */
+ bool use = false;
+
+ /* Denoiser type. */
+ DenoiserType type = DENOISER_OPENIMAGEDENOISE;
+
+ /* Viewport start sample. */
+ int start_sample = 0;
+
+ /* Auxiliary passes. */
+ bool use_pass_albedo = true;
+ bool use_pass_normal = true;
+
+ DenoiserPrefilter prefilter = DENOISER_PREFILTER_FAST;
+
+ static const NodeEnum *get_type_enum();
+ static const NodeEnum *get_prefilter_enum();
+
+ DenoiseParams();
+
+ bool modified(const DenoiseParams &other) const
+ {
+ return !(use == other.use && type == other.type && start_sample == other.start_sample &&
+ use_pass_albedo == other.use_pass_albedo &&
+ use_pass_normal == other.use_pass_normal && prefilter == other.prefilter);
+ }
+};
+
+/* All the parameters needed to perform buffer denoising on a device.
+ * Is not really a task in its canonical terms (as in, is not an asynchronous running task). Is
+ * more like a wrapper for all the arguments and parameters needed to perform denoising. Is a
+ * single place where they are all listed, so that it's not required to modify all device methods
+ * when these parameters do change. */
+class DeviceDenoiseTask {
+ public:
+ DenoiseParams params;
+
+ int num_samples;
+
+ RenderBuffers *render_buffers;
+ BufferParams buffer_params;
+
+ /* Allow to do in-place modification of the input passes (scaling them down i.e.). This will
+ * lower the memory footprint of the denoiser but will make input passes "invalid" (from path
+ * tracer) point of view. */
+ bool allow_inplace_modification;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index 81574e8b184..69e959b6f7b 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -20,7 +20,7 @@
#include "bvh/bvh2.h"
#include "device/device.h"
-#include "device/device_queue.h"
+#include "device/queue.h"
#include "device/cpu/device.h"
#include "device/cuda/device.h"
@@ -29,15 +29,15 @@
#include "device/multi/device.h"
#include "device/optix/device.h"
-#include "util/util_foreach.h"
-#include "util/util_half.h"
-#include "util/util_logging.h"
-#include "util/util_math.h"
-#include "util/util_string.h"
-#include "util/util_system.h"
-#include "util/util_time.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
+#include "util/foreach.h"
+#include "util/half.h"
+#include "util/log.h"
+#include "util/math.h"
+#include "util/string.h"
+#include "util/system.h"
+#include "util/time.h"
+#include "util/types.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
@@ -71,14 +71,12 @@ void Device::build_bvh(BVH *bvh, Progress &progress, bool refit)
Device *Device::create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
{
-#ifdef WITH_MULTI
if (!info.multi_devices.empty()) {
/* Always create a multi device when info contains multiple devices.
* This is done so that the type can still be e.g. DEVICE_CPU to indicate
* that it is a homogeneous collection of devices, which simplifies checks. */
return device_multi_create(info, stats, profiler);
}
-#endif
Device *device = NULL;
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index c73d74cdccc..3cb177adde7 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -19,21 +19,21 @@
#include <stdlib.h>
-#include "bvh/bvh_params.h"
-
-#include "device/device_denoise.h"
-#include "device/device_memory.h"
-
-#include "util/util_function.h"
-#include "util/util_list.h"
-#include "util/util_logging.h"
-#include "util/util_stats.h"
-#include "util/util_string.h"
-#include "util/util_texture.h"
-#include "util/util_thread.h"
-#include "util/util_types.h"
-#include "util/util_unique_ptr.h"
-#include "util/util_vector.h"
+#include "bvh/params.h"
+
+#include "device/denoise.h"
+#include "device/memory.h"
+
+#include "util/function.h"
+#include "util/list.h"
+#include "util/log.h"
+#include "util/stats.h"
+#include "util/string.h"
+#include "util/texture.h"
+#include "util/thread.h"
+#include "util/types.h"
+#include "util/unique_ptr.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/device_denoise.cpp b/intern/cycles/device/device_denoise.cpp
deleted file mode 100644
index aea7868f65d..00000000000
--- a/intern/cycles/device/device_denoise.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "device/device_denoise.h"
-
-CCL_NAMESPACE_BEGIN
-
-const char *denoiserTypeToHumanReadable(DenoiserType type)
-{
- switch (type) {
- case DENOISER_OPTIX:
- return "OptiX";
- case DENOISER_OPENIMAGEDENOISE:
- return "OpenImageDenoise";
-
- case DENOISER_NUM:
- case DENOISER_NONE:
- case DENOISER_ALL:
- return "UNKNOWN";
- }
-
- return "UNKNOWN";
-}
-
-const NodeEnum *DenoiseParams::get_type_enum()
-{
- static NodeEnum type_enum;
-
- if (type_enum.empty()) {
- type_enum.insert("optix", DENOISER_OPTIX);
- type_enum.insert("openimageio", DENOISER_OPENIMAGEDENOISE);
- }
-
- return &type_enum;
-}
-
-const NodeEnum *DenoiseParams::get_prefilter_enum()
-{
- static NodeEnum prefilter_enum;
-
- if (prefilter_enum.empty()) {
- prefilter_enum.insert("none", DENOISER_PREFILTER_NONE);
- prefilter_enum.insert("fast", DENOISER_PREFILTER_FAST);
- prefilter_enum.insert("accurate", DENOISER_PREFILTER_ACCURATE);
- }
-
- return &prefilter_enum;
-}
-
-NODE_DEFINE(DenoiseParams)
-{
- NodeType *type = NodeType::add("denoise_params", create);
-
- const NodeEnum *type_enum = get_type_enum();
- const NodeEnum *prefilter_enum = get_prefilter_enum();
-
- SOCKET_BOOLEAN(use, "Use", false);
-
- SOCKET_ENUM(type, "Type", *type_enum, DENOISER_OPENIMAGEDENOISE);
-
- SOCKET_INT(start_sample, "Start Sample", 0);
-
- SOCKET_BOOLEAN(use_pass_albedo, "Use Pass Albedo", true);
- SOCKET_BOOLEAN(use_pass_normal, "Use Pass Normal", false);
-
- SOCKET_ENUM(prefilter, "Prefilter", *prefilter_enum, DENOISER_PREFILTER_FAST);
-
- return type;
-}
-
-DenoiseParams::DenoiseParams() : Node(get_node_type())
-{
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_denoise.h b/intern/cycles/device/device_denoise.h
deleted file mode 100644
index dfdc7cc87b3..00000000000
--- a/intern/cycles/device/device_denoise.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "device/device_memory.h"
-#include "graph/node.h"
-#include "render/buffers.h"
-
-CCL_NAMESPACE_BEGIN
-
-enum DenoiserType {
- DENOISER_OPTIX = 2,
- DENOISER_OPENIMAGEDENOISE = 4,
- DENOISER_NUM,
-
- DENOISER_NONE = 0,
- DENOISER_ALL = ~0,
-};
-
-/* COnstruct human-readable string which denotes the denoiser type. */
-const char *denoiserTypeToHumanReadable(DenoiserType type);
-
-typedef int DenoiserTypeMask;
-
-enum DenoiserPrefilter {
- /* Best quality of the result without extra processing time, but requires guiding passes to be
- * noise-free. */
- DENOISER_PREFILTER_NONE = 1,
-
- /* Denoise color and guiding passes together.
- * Improves quality when guiding passes are noisy using least amount of extra processing time. */
- DENOISER_PREFILTER_FAST = 2,
-
- /* Prefilter noisy guiding passes before denoising color.
- * Improves quality when guiding passes are noisy using extra processing time. */
- DENOISER_PREFILTER_ACCURATE = 3,
-
- DENOISER_PREFILTER_NUM,
-};
-
-/* NOTE: Is not a real scene node. Using Node API for ease of (de)serialization.
- * The default values here do not really matter as they are always initialized from the
- * Integrator node. */
-class DenoiseParams : public Node {
- public:
- NODE_DECLARE
-
- /* Apply denoiser to image. */
- bool use = false;
-
- /* Denoiser type. */
- DenoiserType type = DENOISER_OPENIMAGEDENOISE;
-
- /* Viewport start sample. */
- int start_sample = 0;
-
- /* Auxiliary passes. */
- bool use_pass_albedo = true;
- bool use_pass_normal = true;
-
- DenoiserPrefilter prefilter = DENOISER_PREFILTER_FAST;
-
- static const NodeEnum *get_type_enum();
- static const NodeEnum *get_prefilter_enum();
-
- DenoiseParams();
-
- bool modified(const DenoiseParams &other) const
- {
- return !(use == other.use && type == other.type && start_sample == other.start_sample &&
- use_pass_albedo == other.use_pass_albedo &&
- use_pass_normal == other.use_pass_normal && prefilter == other.prefilter);
- }
-};
-
-/* All the parameters needed to perform buffer denoising on a device.
- * Is not really a task in its canonical terms (as in, is not an asynchronous running task). Is
- * more like a wrapper for all the arguments and parameters needed to perform denoising. Is a
- * single place where they are all listed, so that it's not required to modify all device methods
- * when these parameters do change. */
-class DeviceDenoiseTask {
- public:
- DenoiseParams params;
-
- int num_samples;
-
- RenderBuffers *render_buffers;
- BufferParams buffer_params;
-
- /* Allow to do in-place modification of the input passes (scaling them down i.e.). This will
- * lower the memory footprint of the denoiser but will make input passes "invalid" (from path
- * tracer) point of view. */
- bool allow_inplace_modification;
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_graphics_interop.cpp b/intern/cycles/device/device_graphics_interop.cpp
deleted file mode 100644
index a80a236759f..00000000000
--- a/intern/cycles/device/device_graphics_interop.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "device/device_graphics_interop.h"
-
-CCL_NAMESPACE_BEGIN
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_graphics_interop.h b/intern/cycles/device/device_graphics_interop.h
deleted file mode 100644
index eaf76077141..00000000000
--- a/intern/cycles/device/device_graphics_interop.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "render/display_driver.h"
-
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Device-side graphics interoperability support.
- *
- * Takes care of holding all the handlers needed by the device to implement interoperability with
- * the graphics library. */
-class DeviceGraphicsInterop {
- public:
- DeviceGraphicsInterop() = default;
- virtual ~DeviceGraphicsInterop() = default;
-
- /* Update this device-side graphics interoperability object with the given destination resource
- * information. */
- virtual void set_display_interop(const DisplayDriver::GraphicsInterop &display_interop) = 0;
-
- virtual device_ptr map() = 0;
- virtual void unmap() = 0;
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_kernel.cpp b/intern/cycles/device/device_kernel.cpp
deleted file mode 100644
index 1e282aac57e..00000000000
--- a/intern/cycles/device/device_kernel.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "device/device_kernel.h"
-
-#include "util/util_logging.h"
-
-CCL_NAMESPACE_BEGIN
-
-const char *device_kernel_as_string(DeviceKernel kernel)
-{
- switch (kernel) {
- /* Integrator. */
- case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA:
- return "integrator_init_from_camera";
- case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_BAKE:
- return "integrator_init_from_bake";
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
- return "integrator_intersect_closest";
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
- return "integrator_intersect_shadow";
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
- return "integrator_intersect_subsurface";
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
- return "integrator_intersect_volume_stack";
- case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND:
- return "integrator_shade_background";
- case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT:
- return "integrator_shade_light";
- case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
- return "integrator_shade_shadow";
- case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE:
- return "integrator_shade_surface";
- case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
- return "integrator_shade_surface_raytrace";
- case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME:
- return "integrator_shade_volume";
- case DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL:
- return "integrator_megakernel";
- case DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY:
- return "integrator_queued_paths_array";
- case DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY:
- return "integrator_queued_shadow_paths_array";
- case DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY:
- return "integrator_active_paths_array";
- case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY:
- return "integrator_terminated_paths_array";
- case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
- return "integrator_sorted_paths_array";
- case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
- return "integrator_compact_paths_array";
- case DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES:
- return "integrator_compact_states";
- case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY:
- return "integrator_terminated_shadow_paths_array";
- case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
- return "integrator_compact_shadow_paths_array";
- case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_STATES:
- return "integrator_compact_shadow_states";
- case DEVICE_KERNEL_INTEGRATOR_RESET:
- return "integrator_reset";
- case DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS:
- return "integrator_shadow_catcher_count_possible_splits";
-
- /* Shader evaluation. */
- case DEVICE_KERNEL_SHADER_EVAL_DISPLACE:
- return "shader_eval_displace";
- case DEVICE_KERNEL_SHADER_EVAL_BACKGROUND:
- return "shader_eval_background";
- case DEVICE_KERNEL_SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY:
- return "shader_eval_curve_shadow_transparency";
-
- /* Film. */
-
-#define FILM_CONVERT_KERNEL_AS_STRING(variant, variant_lowercase) \
- case DEVICE_KERNEL_FILM_CONVERT_##variant: \
- return "film_convert_" #variant_lowercase; \
- case DEVICE_KERNEL_FILM_CONVERT_##variant##_HALF_RGBA: \
- return "film_convert_" #variant_lowercase "_half_rgba";
-
- FILM_CONVERT_KERNEL_AS_STRING(DEPTH, depth)
- FILM_CONVERT_KERNEL_AS_STRING(MIST, mist)
- FILM_CONVERT_KERNEL_AS_STRING(SAMPLE_COUNT, sample_count)
- FILM_CONVERT_KERNEL_AS_STRING(FLOAT, float)
- FILM_CONVERT_KERNEL_AS_STRING(LIGHT_PATH, light_path)
- FILM_CONVERT_KERNEL_AS_STRING(FLOAT3, float3)
- FILM_CONVERT_KERNEL_AS_STRING(MOTION, motion)
- FILM_CONVERT_KERNEL_AS_STRING(CRYPTOMATTE, cryptomatte)
- FILM_CONVERT_KERNEL_AS_STRING(SHADOW_CATCHER, shadow_catcher)
- FILM_CONVERT_KERNEL_AS_STRING(SHADOW_CATCHER_MATTE_WITH_SHADOW,
- shadow_catcher_matte_with_shadow)
- FILM_CONVERT_KERNEL_AS_STRING(COMBINED, combined)
- FILM_CONVERT_KERNEL_AS_STRING(FLOAT4, float4)
-
-#undef FILM_CONVERT_KERNEL_AS_STRING
-
- /* Adaptive sampling. */
- case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_CHECK:
- return "adaptive_sampling_convergence_check";
- case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_X:
- return "adaptive_sampling_filter_x";
- case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_Y:
- return "adaptive_sampling_filter_y";
-
- /* Denoising. */
- case DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS:
- return "filter_guiding_preprocess";
- case DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO:
- return "filter_guiding_set_fake_albedo";
- case DEVICE_KERNEL_FILTER_COLOR_PREPROCESS:
- return "filter_color_preprocess";
- case DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS:
- return "filter_color_postprocess";
-
- /* Cryptomatte. */
- case DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS:
- return "cryptomatte_postprocess";
-
- /* Generic */
- case DEVICE_KERNEL_PREFIX_SUM:
- return "prefix_sum";
-
- case DEVICE_KERNEL_NUM:
- break;
- };
- LOG(FATAL) << "Unhandled kernel " << static_cast<int>(kernel) << ", should never happen.";
- return "UNKNOWN";
-}
-
-std::ostream &operator<<(std::ostream &os, DeviceKernel kernel)
-{
- os << device_kernel_as_string(kernel);
- return os;
-}
-
-string device_kernel_mask_as_string(DeviceKernelMask mask)
-{
- string str;
-
- for (uint64_t i = 0; i < sizeof(DeviceKernelMask) * 8; i++) {
- if (mask & (uint64_t(1) << i)) {
- if (!str.empty()) {
- str += " ";
- }
- str += device_kernel_as_string((DeviceKernel)i);
- }
- }
-
- return str;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_kernel.h b/intern/cycles/device/device_kernel.h
deleted file mode 100644
index 83d959ca87b..00000000000
--- a/intern/cycles/device/device_kernel.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_types.h"
-
-#include "util/util_string.h"
-
-#include <ostream> // NOLINT
-
-CCL_NAMESPACE_BEGIN
-
-const char *device_kernel_as_string(DeviceKernel kernel);
-std::ostream &operator<<(std::ostream &os, DeviceKernel kernel);
-
-typedef uint64_t DeviceKernelMask;
-string device_kernel_mask_as_string(DeviceKernelMask mask);
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_memory.cpp b/intern/cycles/device/device_memory.cpp
deleted file mode 100644
index c0ab2e17cae..00000000000
--- a/intern/cycles/device/device_memory.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "device/device_memory.h"
-#include "device/device.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Device Memory */
-
-device_memory::device_memory(Device *device, const char *name, MemoryType type)
- : data_type(device_type_traits<uchar>::data_type),
- data_elements(device_type_traits<uchar>::num_elements_cpu),
- data_size(0),
- device_size(0),
- data_width(0),
- data_height(0),
- data_depth(0),
- type(type),
- name(name),
- device(device),
- device_pointer(0),
- host_pointer(0),
- shared_pointer(0),
- shared_counter(0),
- original_device_ptr(0),
- original_device_size(0),
- original_device(0),
- need_realloc_(false),
- modified(false)
-{
-}
-
-device_memory::device_memory(device_memory &&other) noexcept
- : data_type(other.data_type),
- data_elements(other.data_elements),
- data_size(other.data_size),
- device_size(other.device_size),
- data_width(other.data_width),
- data_height(other.data_height),
- data_depth(other.data_depth),
- type(other.type),
- name(other.name),
- device(other.device),
- device_pointer(other.device_pointer),
- host_pointer(other.host_pointer),
- shared_pointer(other.shared_pointer),
- shared_counter(other.shared_counter),
- original_device_ptr(other.original_device_ptr),
- original_device_size(other.original_device_size),
- original_device(other.original_device),
- need_realloc_(other.need_realloc_),
- modified(other.modified)
-{
- other.data_elements = 0;
- other.data_size = 0;
- other.device_size = 0;
- other.data_width = 0;
- other.data_height = 0;
- other.data_depth = 0;
- other.device = 0;
- other.device_pointer = 0;
- other.host_pointer = 0;
- other.shared_pointer = 0;
- other.shared_counter = 0;
- other.original_device_ptr = 0;
- other.original_device_size = 0;
- other.original_device = 0;
- other.need_realloc_ = false;
- other.modified = false;
-}
-
-device_memory::~device_memory()
-{
- assert(shared_pointer == 0);
- assert(shared_counter == 0);
-}
-
-void *device_memory::host_alloc(size_t size)
-{
- if (!size) {
- return 0;
- }
-
- void *ptr = util_aligned_malloc(size, MIN_ALIGNMENT_CPU_DATA_TYPES);
-
- if (ptr) {
- util_guarded_mem_alloc(size);
- }
- else {
- throw std::bad_alloc();
- }
-
- return ptr;
-}
-
-void device_memory::host_free()
-{
- if (host_pointer) {
- util_guarded_mem_free(memory_size());
- util_aligned_free((void *)host_pointer);
- host_pointer = 0;
- }
-}
-
-void device_memory::device_alloc()
-{
- assert(!device_pointer && type != MEM_TEXTURE && type != MEM_GLOBAL);
- device->mem_alloc(*this);
-}
-
-void device_memory::device_free()
-{
- if (device_pointer) {
- device->mem_free(*this);
- }
-}
-
-void device_memory::device_copy_to()
-{
- if (host_pointer) {
- device->mem_copy_to(*this);
- }
-}
-
-void device_memory::device_copy_from(size_t y, size_t w, size_t h, size_t elem)
-{
- assert(type != MEM_TEXTURE && type != MEM_READ_ONLY && type != MEM_GLOBAL);
- device->mem_copy_from(*this, y, w, h, elem);
-}
-
-void device_memory::device_zero()
-{
- if (data_size) {
- device->mem_zero(*this);
- }
-}
-
-bool device_memory::device_is_cpu()
-{
- return (device->info.type == DEVICE_CPU);
-}
-
-void device_memory::swap_device(Device *new_device,
- size_t new_device_size,
- device_ptr new_device_ptr)
-{
- original_device = device;
- original_device_size = device_size;
- original_device_ptr = device_pointer;
-
- device = new_device;
- device_size = new_device_size;
- device_pointer = new_device_ptr;
-}
-
-void device_memory::restore_device()
-{
- device = original_device;
- device_size = original_device_size;
- device_pointer = original_device_ptr;
-}
-
-bool device_memory::is_resident(Device *sub_device) const
-{
- return device->is_resident(device_pointer, sub_device);
-}
-
-/* Device Sub Ptr */
-
-device_sub_ptr::device_sub_ptr(device_memory &mem, size_t offset, size_t size) : device(mem.device)
-{
- ptr = device->mem_alloc_sub_ptr(mem, offset, size);
-}
-
-device_sub_ptr::~device_sub_ptr()
-{
- device->mem_free_sub_ptr(ptr);
-}
-
-/* Device Texture */
-
-device_texture::device_texture(Device *device,
- const char *name,
- const uint slot,
- ImageDataType image_data_type,
- InterpolationType interpolation,
- ExtensionType extension)
- : device_memory(device, name, MEM_TEXTURE), slot(slot)
-{
- switch (image_data_type) {
- case IMAGE_DATA_TYPE_FLOAT4:
- data_type = TYPE_FLOAT;
- data_elements = 4;
- break;
- case IMAGE_DATA_TYPE_FLOAT:
- data_type = TYPE_FLOAT;
- data_elements = 1;
- break;
- case IMAGE_DATA_TYPE_BYTE4:
- data_type = TYPE_UCHAR;
- data_elements = 4;
- break;
- case IMAGE_DATA_TYPE_BYTE:
- case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
- case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
- data_type = TYPE_UCHAR;
- data_elements = 1;
- break;
- case IMAGE_DATA_TYPE_HALF4:
- data_type = TYPE_HALF;
- data_elements = 4;
- break;
- case IMAGE_DATA_TYPE_HALF:
- data_type = TYPE_HALF;
- data_elements = 1;
- break;
- case IMAGE_DATA_TYPE_USHORT4:
- data_type = TYPE_UINT16;
- data_elements = 4;
- break;
- case IMAGE_DATA_TYPE_USHORT:
- data_type = TYPE_UINT16;
- data_elements = 1;
- break;
- case IMAGE_DATA_NUM_TYPES:
- assert(0);
- return;
- }
-
- memset(&info, 0, sizeof(info));
- info.data_type = image_data_type;
- info.interpolation = interpolation;
- info.extension = extension;
-}
-
-device_texture::~device_texture()
-{
- device_free();
- host_free();
-}
-
-/* Host memory allocation. */
-void *device_texture::alloc(const size_t width, const size_t height, const size_t depth)
-{
- const size_t new_size = size(width, height, depth);
-
- if (new_size != data_size) {
- device_free();
- host_free();
- host_pointer = host_alloc(data_elements * datatype_size(data_type) * new_size);
- assert(device_pointer == 0);
- }
-
- data_size = new_size;
- data_width = width;
- data_height = height;
- data_depth = depth;
-
- info.width = width;
- info.height = height;
- info.depth = depth;
-
- return host_pointer;
-}
-
-void device_texture::copy_to_device()
-{
- device_copy_to();
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
deleted file mode 100644
index be6123e09b2..00000000000
--- a/intern/cycles/device/device_memory.h
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __DEVICE_MEMORY_H__
-#define __DEVICE_MEMORY_H__
-
-/* Device Memory
- *
- * Data types for allocating, copying and freeing device memory. */
-
-#include "util/util_array.h"
-#include "util/util_half.h"
-#include "util/util_string.h"
-#include "util/util_texture.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-
-enum MemoryType {
- MEM_READ_ONLY,
- MEM_READ_WRITE,
- MEM_DEVICE_ONLY,
- MEM_GLOBAL,
- MEM_TEXTURE,
-};
-
-/* Supported Data Types */
-
-enum DataType {
- TYPE_UNKNOWN,
- TYPE_UCHAR,
- TYPE_UINT16,
- TYPE_UINT,
- TYPE_INT,
- TYPE_FLOAT,
- TYPE_HALF,
- TYPE_UINT64,
-};
-
-static constexpr size_t datatype_size(DataType datatype)
-{
- switch (datatype) {
- case TYPE_UNKNOWN:
- return 1;
- case TYPE_UCHAR:
- return sizeof(uchar);
- case TYPE_FLOAT:
- return sizeof(float);
- case TYPE_UINT:
- return sizeof(uint);
- case TYPE_UINT16:
- return sizeof(uint16_t);
- case TYPE_INT:
- return sizeof(int);
- case TYPE_HALF:
- return sizeof(half);
- case TYPE_UINT64:
- return sizeof(uint64_t);
- default:
- return 0;
- }
-}
-
-/* Traits for data types */
-
-template<typename T> struct device_type_traits {
- static const DataType data_type = TYPE_UNKNOWN;
- static const size_t num_elements_cpu = sizeof(T);
- static const size_t num_elements_gpu = sizeof(T);
-};
-
-template<> struct device_type_traits<uchar> {
- static const DataType data_type = TYPE_UCHAR;
- static const size_t num_elements_cpu = 1;
- static const size_t num_elements_gpu = 1;
- static_assert(sizeof(uchar) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<uchar2> {
- static const DataType data_type = TYPE_UCHAR;
- static const size_t num_elements_cpu = 2;
- static const size_t num_elements_gpu = 2;
- static_assert(sizeof(uchar2) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<uchar3> {
- static const DataType data_type = TYPE_UCHAR;
- static const size_t num_elements_cpu = 3;
- static const size_t num_elements_gpu = 3;
- static_assert(sizeof(uchar3) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<uchar4> {
- static const DataType data_type = TYPE_UCHAR;
- static const size_t num_elements_cpu = 4;
- static const size_t num_elements_gpu = 4;
- static_assert(sizeof(uchar4) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<uint> {
- static const DataType data_type = TYPE_UINT;
- static const size_t num_elements_cpu = 1;
- static const size_t num_elements_gpu = 1;
- static_assert(sizeof(uint) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<uint2> {
- static const DataType data_type = TYPE_UINT;
- static const size_t num_elements_cpu = 2;
- static const size_t num_elements_gpu = 2;
- static_assert(sizeof(uint2) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<uint3> {
- static const DataType data_type = TYPE_UINT;
- static const size_t num_elements_cpu = 3;
- static const size_t num_elements_gpu = 3;
- static_assert(sizeof(uint3) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<uint4> {
- static const DataType data_type = TYPE_UINT;
- static const size_t num_elements_cpu = 4;
- static const size_t num_elements_gpu = 4;
- static_assert(sizeof(uint4) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<int> {
- static const DataType data_type = TYPE_INT;
- static const size_t num_elements_cpu = 1;
- static const size_t num_elements_gpu = 1;
- static_assert(sizeof(int) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<int2> {
- static const DataType data_type = TYPE_INT;
- static const size_t num_elements_cpu = 2;
- static const size_t num_elements_gpu = 2;
- static_assert(sizeof(int2) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<int3> {
- static const DataType data_type = TYPE_INT;
- static const size_t num_elements_cpu = 4;
- static const size_t num_elements_gpu = 3;
- static_assert(sizeof(int3) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<int4> {
- static const DataType data_type = TYPE_INT;
- static const size_t num_elements_cpu = 4;
- static const size_t num_elements_gpu = 4;
- static_assert(sizeof(int4) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<float> {
- static const DataType data_type = TYPE_FLOAT;
- static const size_t num_elements_cpu = 1;
- static const size_t num_elements_gpu = 1;
- static_assert(sizeof(float) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<float2> {
- static const DataType data_type = TYPE_FLOAT;
- static const size_t num_elements_cpu = 2;
- static const size_t num_elements_gpu = 2;
- static_assert(sizeof(float2) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<float3> {
- static const DataType data_type = TYPE_FLOAT;
- static const size_t num_elements_cpu = 4;
- static const size_t num_elements_gpu = 3;
- static_assert(sizeof(float3) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<float4> {
- static const DataType data_type = TYPE_FLOAT;
- static const size_t num_elements_cpu = 4;
- static const size_t num_elements_gpu = 4;
- static_assert(sizeof(float4) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<half> {
- static const DataType data_type = TYPE_HALF;
- static const size_t num_elements_cpu = 1;
- static const size_t num_elements_gpu = 1;
- static_assert(sizeof(half) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<ushort4> {
- static const DataType data_type = TYPE_UINT16;
- static const size_t num_elements_cpu = 4;
- static const size_t num_elements_gpu = 4;
- static_assert(sizeof(ushort4) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<uint16_t> {
- static const DataType data_type = TYPE_UINT16;
- static const size_t num_elements_cpu = 1;
- static const size_t num_elements_gpu = 1;
- static_assert(sizeof(uint16_t) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<half4> {
- static const DataType data_type = TYPE_HALF;
- static const size_t num_elements_cpu = 4;
- static const size_t num_elements_gpu = 4;
- static_assert(sizeof(half4) == num_elements_cpu * datatype_size(data_type));
-};
-
-template<> struct device_type_traits<uint64_t> {
- static const DataType data_type = TYPE_UINT64;
- static const size_t num_elements_cpu = 1;
- static const size_t num_elements_gpu = 1;
- static_assert(sizeof(uint64_t) == num_elements_cpu * datatype_size(data_type));
-};
-
-/* Device Memory
- *
- * Base class for all device memory. This should not be allocated directly,
- * instead the appropriate subclass can be used. */
-
-class device_memory {
- public:
- size_t memory_size()
- {
- return data_size * data_elements * datatype_size(data_type);
- }
- size_t memory_elements_size(int elements)
- {
- return elements * data_elements * datatype_size(data_type);
- }
-
- /* Data information. */
- DataType data_type;
- int data_elements;
- size_t data_size;
- size_t device_size;
- size_t data_width;
- size_t data_height;
- size_t data_depth;
- MemoryType type;
- const char *name;
-
- /* Pointers. */
- Device *device;
- device_ptr device_pointer;
- void *host_pointer;
- void *shared_pointer;
- /* reference counter for shared_pointer */
- int shared_counter;
-
- virtual ~device_memory();
-
- void swap_device(Device *new_device, size_t new_device_size, device_ptr new_device_ptr);
- void restore_device();
-
- bool is_resident(Device *sub_device) const;
-
- protected:
- friend class CUDADevice;
- friend class OptiXDevice;
- friend class HIPDevice;
-
- /* Only create through subclasses. */
- device_memory(Device *device, const char *name, MemoryType type);
- device_memory(device_memory &&other) noexcept;
-
- /* No copying allowed. */
- device_memory(const device_memory &) = delete;
- device_memory &operator=(const device_memory &) = delete;
-
- /* Host allocation on the device. All host_pointer memory should be
- * allocated with these functions, for devices that support using
- * the same pointer for host and device. */
- void *host_alloc(size_t size);
- void host_free();
-
- /* Device memory allocation and copying. */
- void device_alloc();
- void device_free();
- void device_copy_to();
- void device_copy_from(size_t y, size_t w, size_t h, size_t elem);
- void device_zero();
-
- bool device_is_cpu();
-
- device_ptr original_device_ptr;
- size_t original_device_size;
- Device *original_device;
- bool need_realloc_;
- bool modified;
-};
-
-/* Device Only Memory
- *
- * Working memory only needed by the device, with no corresponding allocation
- * on the host. Only used internally in the device implementations. */
-
-template<typename T> class device_only_memory : public device_memory {
- public:
- device_only_memory(Device *device, const char *name, bool allow_host_memory_fallback = false)
- : device_memory(device, name, allow_host_memory_fallback ? MEM_READ_WRITE : MEM_DEVICE_ONLY)
- {
- data_type = device_type_traits<T>::data_type;
- data_elements = max(device_is_cpu() ? device_type_traits<T>::num_elements_cpu :
- device_type_traits<T>::num_elements_gpu,
- 1);
- }
-
- device_only_memory(device_only_memory &&other) noexcept : device_memory(std::move(other))
- {
- }
-
- virtual ~device_only_memory()
- {
- free();
- }
-
- void alloc_to_device(size_t num, bool shrink_to_fit = true)
- {
- size_t new_size = num;
- bool reallocate;
-
- if (shrink_to_fit) {
- reallocate = (data_size != new_size);
- }
- else {
- reallocate = (data_size < new_size);
- }
-
- if (reallocate) {
- device_free();
- data_size = new_size;
- device_alloc();
- }
- }
-
- void free()
- {
- device_free();
- data_size = 0;
- }
-
- void zero_to_device()
- {
- device_zero();
- }
-};
-
-/* Device Vector
- *
- * Data vector to exchange data between host and device. Memory will be
- * allocated on the host first with alloc() and resize, and then filled
- * in and copied to the device with copy_to_device(). Or alternatively
- * allocated and set to zero on the device with zero_to_device().
- *
- * When using memory type MEM_GLOBAL, a pointer to this memory will be
- * automatically attached to kernel globals, using the provided name
- * matching an entry in kernel_textures.h. */
-
-template<typename T> class device_vector : public device_memory {
- public:
- /* Can only use this for types that have the same size on CPU and GPU. */
- static_assert(device_type_traits<T>::num_elements_cpu ==
- device_type_traits<T>::num_elements_gpu);
-
- device_vector(Device *device, const char *name, MemoryType type)
- : device_memory(device, name, type)
- {
- data_type = device_type_traits<T>::data_type;
- data_elements = device_type_traits<T>::num_elements_cpu;
- modified = true;
- need_realloc_ = true;
-
- assert(data_elements > 0);
- }
-
- virtual ~device_vector()
- {
- free();
- }
-
- /* Host memory allocation. */
- T *alloc(size_t width, size_t height = 0, size_t depth = 0)
- {
- size_t new_size = size(width, height, depth);
-
- if (new_size != data_size) {
- device_free();
- host_free();
- host_pointer = host_alloc(sizeof(T) * new_size);
- modified = true;
- assert(device_pointer == 0);
- }
-
- data_size = new_size;
- data_width = width;
- data_height = height;
- data_depth = depth;
-
- return data();
- }
-
- /* Host memory resize. Only use this if the original data needs to be
- * preserved, it is faster to call alloc() if it can be discarded. */
- T *resize(size_t width, size_t height = 0, size_t depth = 0)
- {
- size_t new_size = size(width, height, depth);
-
- if (new_size != data_size) {
- void *new_ptr = host_alloc(sizeof(T) * new_size);
-
- if (new_size && data_size) {
- size_t min_size = ((new_size < data_size) ? new_size : data_size);
- memcpy((T *)new_ptr, (T *)host_pointer, sizeof(T) * min_size);
- }
-
- device_free();
- host_free();
- host_pointer = new_ptr;
- assert(device_pointer == 0);
- }
-
- data_size = new_size;
- data_width = width;
- data_height = height;
- data_depth = depth;
-
- return data();
- }
-
- /* Take over data from an existing array. */
- void steal_data(array<T> &from)
- {
- device_free();
- host_free();
-
- data_size = from.size();
- data_width = 0;
- data_height = 0;
- data_depth = 0;
- host_pointer = from.steal_pointer();
- assert(device_pointer == 0);
- }
-
- void give_data(array<T> &to)
- {
- device_free();
-
- to.set_data((T *)host_pointer, data_size);
- data_size = 0;
- data_width = 0;
- data_height = 0;
- data_depth = 0;
- host_pointer = 0;
- assert(device_pointer == 0);
- }
-
- /* Free device and host memory. */
- void free()
- {
- device_free();
- host_free();
-
- data_size = 0;
- data_width = 0;
- data_height = 0;
- data_depth = 0;
- host_pointer = 0;
- modified = true;
- need_realloc_ = true;
- assert(device_pointer == 0);
- }
-
- void free_if_need_realloc(bool force_free)
- {
- if (need_realloc_ || force_free) {
- free();
- }
- }
-
- bool is_modified() const
- {
- return modified;
- }
-
- bool need_realloc()
- {
- return need_realloc_;
- }
-
- void tag_modified()
- {
- modified = true;
- }
-
- void tag_realloc()
- {
- need_realloc_ = true;
- tag_modified();
- }
-
- size_t size() const
- {
- return data_size;
- }
-
- T *data()
- {
- return (T *)host_pointer;
- }
-
- const T *data() const
- {
- return (T *)host_pointer;
- }
-
- T &operator[](size_t i)
- {
- assert(i < data_size);
- return data()[i];
- }
-
- void copy_to_device()
- {
- if (data_size != 0) {
- device_copy_to();
- }
- }
-
- void copy_to_device_if_modified()
- {
- if (!modified) {
- return;
- }
-
- copy_to_device();
- }
-
- void clear_modified()
- {
- modified = false;
- need_realloc_ = false;
- }
-
- void copy_from_device()
- {
- device_copy_from(0, data_width, (data_height == 0) ? 1 : data_height, sizeof(T));
- }
-
- void copy_from_device(size_t y, size_t w, size_t h)
- {
- device_copy_from(y, w, h, sizeof(T));
- }
-
- void zero_to_device()
- {
- device_zero();
- }
-
- void move_device(Device *new_device)
- {
- copy_from_device();
- device_free();
- device = new_device;
- copy_to_device();
- }
-
- protected:
- size_t size(size_t width, size_t height, size_t depth)
- {
- return width * ((height == 0) ? 1 : height) * ((depth == 0) ? 1 : depth);
- }
-};
-
-/* Device Sub Memory
- *
- * Pointer into existing memory. It is not allocated separately, but created
- * from an already allocated base memory. It is freed automatically when it
- * goes out of scope, which should happen before base memory is freed.
- *
- * Note: some devices require offset and size of the sub_ptr to be properly
- * aligned to device->mem_address_alingment(). */
-
-class device_sub_ptr {
- public:
- device_sub_ptr(device_memory &mem, size_t offset, size_t size);
- ~device_sub_ptr();
-
- device_ptr operator*() const
- {
- return ptr;
- }
-
- protected:
- /* No copying. */
- device_sub_ptr &operator=(const device_sub_ptr &);
-
- Device *device;
- device_ptr ptr;
-};
-
-/* Device Texture
- *
- * 2D or 3D image texture memory. */
-
-class device_texture : public device_memory {
- public:
- device_texture(Device *device,
- const char *name,
- const uint slot,
- ImageDataType image_data_type,
- InterpolationType interpolation,
- ExtensionType extension);
- ~device_texture();
-
- void *alloc(const size_t width, const size_t height, const size_t depth = 0);
- void copy_to_device();
-
- uint slot;
- TextureInfo info;
-
- protected:
- size_t size(const size_t width, const size_t height, const size_t depth)
- {
- return width * ((height == 0) ? 1 : height) * ((depth == 0) ? 1 : depth);
- }
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __DEVICE_MEMORY_H__ */
diff --git a/intern/cycles/device/device_queue.cpp b/intern/cycles/device/device_queue.cpp
deleted file mode 100644
index f2b2f3496e0..00000000000
--- a/intern/cycles/device/device_queue.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "device/device_queue.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_logging.h"
-#include "util/util_time.h"
-
-#include <iomanip>
-
-CCL_NAMESPACE_BEGIN
-
-DeviceQueue::DeviceQueue(Device *device)
- : device(device), last_kernels_enqueued_(0), last_sync_time_(0.0)
-{
- DCHECK_NE(device, nullptr);
-}
-
-DeviceQueue::~DeviceQueue()
-{
- if (VLOG_IS_ON(3)) {
- /* Print kernel execution times sorted by time. */
- vector<pair<DeviceKernelMask, double>> stats_sorted;
- for (const auto &stat : stats_kernel_time_) {
- stats_sorted.push_back(stat);
- }
-
- sort(stats_sorted.begin(),
- stats_sorted.end(),
- [](const pair<DeviceKernelMask, double> &a, const pair<DeviceKernelMask, double> &b) {
- return a.second > b.second;
- });
-
- VLOG(3) << "GPU queue stats:";
- for (const auto &[mask, time] : stats_sorted) {
- VLOG(3) << " " << std::setfill(' ') << std::setw(10) << std::fixed << std::setprecision(5)
- << std::right << time << "s: " << device_kernel_mask_as_string(mask);
- }
- }
-}
-
-void DeviceQueue::debug_init_execution()
-{
- if (VLOG_IS_ON(3)) {
- last_sync_time_ = time_dt();
- }
-
- last_kernels_enqueued_ = 0;
-}
-
-void DeviceQueue::debug_enqueue(DeviceKernel kernel, const int work_size)
-{
- if (VLOG_IS_ON(3)) {
- VLOG(4) << "GPU queue launch " << device_kernel_as_string(kernel) << ", work_size "
- << work_size;
- }
-
- last_kernels_enqueued_ |= (uint64_t(1) << (uint64_t)kernel);
-}
-
-void DeviceQueue::debug_synchronize()
-{
- if (VLOG_IS_ON(3)) {
- const double new_time = time_dt();
- const double elapsed_time = new_time - last_sync_time_;
- VLOG(4) << "GPU queue synchronize, elapsed " << std::setw(10) << elapsed_time << "s";
-
- stats_kernel_time_[last_kernels_enqueued_] += elapsed_time;
-
- last_sync_time_ = new_time;
- }
-
- last_kernels_enqueued_ = 0;
-}
-
-string DeviceQueue::debug_active_kernels()
-{
- return device_kernel_mask_as_string(last_kernels_enqueued_);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_queue.h b/intern/cycles/device/device_queue.h
deleted file mode 100644
index e6835b787cf..00000000000
--- a/intern/cycles/device/device_queue.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "device/device_kernel.h"
-
-#include "device/device_graphics_interop.h"
-#include "util/util_logging.h"
-#include "util/util_map.h"
-#include "util/util_string.h"
-#include "util/util_unique_ptr.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class device_memory;
-
-struct KernelWorkTile;
-
-/* Abstraction of a command queue for a device.
- * Provides API to schedule kernel execution in a specific queue with minimal possible overhead
- * from driver side.
- *
- * This class encapsulates all properties needed for commands execution. */
-class DeviceQueue {
- public:
- virtual ~DeviceQueue();
-
- /* Number of concurrent states to process for integrator,
- * based on number of cores and/or available memory. */
- virtual int num_concurrent_states(const size_t state_size) const = 0;
-
- /* Number of states which keeps the device occupied with work without loosing performance.
- * The renderer will add more work (when available) when number of active paths falls below this
- * value. */
- virtual int num_concurrent_busy_states() const = 0;
-
- /* Initialize execution of kernels on this queue.
- *
- * Will, for example, load all data required by the kernels from Device to global or path state.
- *
- * Use this method after device synchronization has finished before enqueueing any kernels. */
- virtual void init_execution() = 0;
-
- /* Test if an optional device kernel is available. */
- virtual bool kernel_available(DeviceKernel kernel) const = 0;
-
- /* Enqueue kernel execution.
- *
- * Execute the kernel work_size times on the device.
- * Supported arguments types:
- * - int: pass pointer to the int
- * - device memory: pass pointer to device_memory.device_pointer
- * Return false if there was an error executing this or a previous kernel. */
- virtual bool enqueue(DeviceKernel kernel, const int work_size, void *args[]) = 0;
-
- /* Wait unit all enqueued kernels have finished execution.
- * Return false if there was an error executing any of the enqueued kernels. */
- virtual bool synchronize() = 0;
-
- /* Copy memory to/from device as part of the command queue, to ensure
- * operations are done in order without having to synchronize. */
- virtual void zero_to_device(device_memory &mem) = 0;
- virtual void copy_to_device(device_memory &mem) = 0;
- virtual void copy_from_device(device_memory &mem) = 0;
-
- /* Graphics resources interoperability.
- *
- * The interoperability comes here by the meaning that the device is capable of computing result
- * directly into an OpenGL (or other graphics library) buffer. */
-
- /* Create graphics interoperability context which will be taking care of mapping graphics
- * resource as a buffer writable by kernels of this device. */
- virtual unique_ptr<DeviceGraphicsInterop> graphics_interop_create()
- {
- LOG(FATAL) << "Request of GPU interop of a device which does not support it.";
- return nullptr;
- }
-
- /* Device this queue has been created for. */
- Device *device;
-
- protected:
- /* Hide construction so that allocation via `Device` API is enforced. */
- explicit DeviceQueue(Device *device);
-
- /* Implementations call these from the corresponding methods to generate debugging logs. */
- void debug_init_execution();
- void debug_enqueue(DeviceKernel kernel, const int work_size);
- void debug_synchronize();
- string debug_active_kernels();
-
- /* Combination of kernels enqueued together sync last synchronize. */
- DeviceKernelMask last_kernels_enqueued_;
- /* Time of synchronize call. */
- double last_sync_time_;
- /* Accumulated execution time for combinations of kernels launched together. */
- map<DeviceKernelMask, double> stats_kernel_time_;
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/device/dummy/device.cpp b/intern/cycles/device/dummy/device.cpp
index e3cea272300..64f6b0eb58c 100644
--- a/intern/cycles/device/dummy/device.cpp
+++ b/intern/cycles/device/dummy/device.cpp
@@ -17,7 +17,7 @@
#include "device/dummy/device.h"
#include "device/device.h"
-#include "device/device_queue.h"
+#include "device/queue.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/dummy/device.h b/intern/cycles/device/dummy/device.h
index 832a9568129..c45eb036ca5 100644
--- a/intern/cycles/device/dummy/device.h
+++ b/intern/cycles/device/dummy/device.h
@@ -16,8 +16,8 @@
#pragma once
-#include "util/util_string.h"
-#include "util/util_vector.h"
+#include "util/string.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/graphics_interop.cpp b/intern/cycles/device/graphics_interop.cpp
new file mode 100644
index 00000000000..0b092711b61
--- /dev/null
+++ b/intern/cycles/device/graphics_interop.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device/graphics_interop.h"
+
+CCL_NAMESPACE_BEGIN
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/graphics_interop.h b/intern/cycles/device/graphics_interop.h
new file mode 100644
index 00000000000..f1661146ddd
--- /dev/null
+++ b/intern/cycles/device/graphics_interop.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "session/display_driver.h"
+
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Device-side graphics interoperability support.
+ *
+ * Takes care of holding all the handlers needed by the device to implement interoperability with
+ * the graphics library. */
+class DeviceGraphicsInterop {
+ public:
+ DeviceGraphicsInterop() = default;
+ virtual ~DeviceGraphicsInterop() = default;
+
+ /* Update this device-side graphics interoperability object with the given destination resource
+ * information. */
+ virtual void set_display_interop(const DisplayDriver::GraphicsInterop &display_interop) = 0;
+
+ virtual device_ptr map() = 0;
+ virtual void unmap() = 0;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/hip/device.cpp b/intern/cycles/device/hip/device.cpp
index 90028ac7f10..f71732d14bb 100644
--- a/intern/cycles/device/hip/device.cpp
+++ b/intern/cycles/device/hip/device.cpp
@@ -16,14 +16,14 @@
#include "device/hip/device.h"
-#include "util/util_logging.h"
+#include "util/log.h"
#ifdef WITH_HIP
# include "device/device.h"
# include "device/hip/device_impl.h"
-# include "util/util_string.h"
-# include "util/util_windows.h"
+# include "util/string.h"
+# include "util/windows.h"
#endif /* WITH_HIP */
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/hip/device.h b/intern/cycles/device/hip/device.h
index 965fd9e484b..cdbe364b2b3 100644
--- a/intern/cycles/device/hip/device.h
+++ b/intern/cycles/device/hip/device.h
@@ -16,8 +16,8 @@
#pragma once
-#include "util/util_string.h"
-#include "util/util_vector.h"
+#include "util/string.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/hip/device_impl.cpp b/intern/cycles/device/hip/device_impl.cpp
index 4ae714913ab..31b7b07383b 100644
--- a/intern/cycles/device/hip/device_impl.cpp
+++ b/intern/cycles/device/hip/device_impl.cpp
@@ -24,20 +24,18 @@
# include "device/hip/device_impl.h"
-# include "render/buffers.h"
-
-# include "util/util_debug.h"
-# include "util/util_foreach.h"
-# include "util/util_logging.h"
-# include "util/util_map.h"
-# include "util/util_md5.h"
-# include "util/util_opengl.h"
-# include "util/util_path.h"
-# include "util/util_string.h"
-# include "util/util_system.h"
-# include "util/util_time.h"
-# include "util/util_types.h"
-# include "util/util_windows.h"
+# include "util/debug.h"
+# include "util/foreach.h"
+# include "util/log.h"
+# include "util/map.h"
+# include "util/md5.h"
+# include "util/opengl.h"
+# include "util/path.h"
+# include "util/string.h"
+# include "util/system.h"
+# include "util/time.h"
+# include "util/types.h"
+# include "util/windows.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/hip/device_impl.h b/intern/cycles/device/hip/device_impl.h
index 1d138ee9856..8d81291d15e 100644
--- a/intern/cycles/device/hip/device_impl.h
+++ b/intern/cycles/device/hip/device_impl.h
@@ -21,12 +21,12 @@
# include "device/hip/queue.h"
# include "device/hip/util.h"
-# include "util/util_map.h"
+# include "util/map.h"
# ifdef WITH_HIP_DYNLOAD
# include "hipew.h"
# else
-# include "util/util_opengl.h"
+# include "util/opengl.h"
# endif
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/hip/graphics_interop.h b/intern/cycles/device/hip/graphics_interop.h
index 2b2d287ff6c..8314405e670 100644
--- a/intern/cycles/device/hip/graphics_interop.h
+++ b/intern/cycles/device/hip/graphics_interop.h
@@ -16,7 +16,7 @@
#ifdef WITH_HIP
-# include "device/device_graphics_interop.h"
+# include "device/graphics_interop.h"
# ifdef WITH_HIP_DYNLOAD
# include "hipew.h"
diff --git a/intern/cycles/device/hip/kernel.h b/intern/cycles/device/hip/kernel.h
index 3301731f56e..f1378f8eebf 100644
--- a/intern/cycles/device/hip/kernel.h
+++ b/intern/cycles/device/hip/kernel.h
@@ -18,7 +18,7 @@
#ifdef WITH_HIP
-# include "device/device_kernel.h"
+# include "device/kernel.h"
# ifdef WITH_HIP_DYNLOAD
# include "hipew.h"
diff --git a/intern/cycles/device/hip/queue.h b/intern/cycles/device/hip/queue.h
index b92f7de7e4b..95d1afaff0f 100644
--- a/intern/cycles/device/hip/queue.h
+++ b/intern/cycles/device/hip/queue.h
@@ -18,9 +18,9 @@
#ifdef WITH_HIP
-# include "device/device_kernel.h"
-# include "device/device_memory.h"
-# include "device/device_queue.h"
+# include "device/kernel.h"
+# include "device/memory.h"
+# include "device/queue.h"
# include "device/hip/util.h"
diff --git a/intern/cycles/device/kernel.cpp b/intern/cycles/device/kernel.cpp
new file mode 100644
index 00000000000..1e4f0c48f18
--- /dev/null
+++ b/intern/cycles/device/kernel.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device/kernel.h"
+
+#include "util/log.h"
+
+CCL_NAMESPACE_BEGIN
+
+const char *device_kernel_as_string(DeviceKernel kernel)
+{
+ switch (kernel) {
+ /* Integrator. */
+ case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA:
+ return "integrator_init_from_camera";
+ case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_BAKE:
+ return "integrator_init_from_bake";
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
+ return "integrator_intersect_closest";
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
+ return "integrator_intersect_shadow";
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
+ return "integrator_intersect_subsurface";
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
+ return "integrator_intersect_volume_stack";
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND:
+ return "integrator_shade_background";
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT:
+ return "integrator_shade_light";
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
+ return "integrator_shade_shadow";
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE:
+ return "integrator_shade_surface";
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
+ return "integrator_shade_surface_raytrace";
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME:
+ return "integrator_shade_volume";
+ case DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL:
+ return "integrator_megakernel";
+ case DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY:
+ return "integrator_queued_paths_array";
+ case DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY:
+ return "integrator_queued_shadow_paths_array";
+ case DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY:
+ return "integrator_active_paths_array";
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY:
+ return "integrator_terminated_paths_array";
+ case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
+ return "integrator_sorted_paths_array";
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
+ return "integrator_compact_paths_array";
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES:
+ return "integrator_compact_states";
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY:
+ return "integrator_terminated_shadow_paths_array";
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
+ return "integrator_compact_shadow_paths_array";
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_STATES:
+ return "integrator_compact_shadow_states";
+ case DEVICE_KERNEL_INTEGRATOR_RESET:
+ return "integrator_reset";
+ case DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS:
+ return "integrator_shadow_catcher_count_possible_splits";
+
+ /* Shader evaluation. */
+ case DEVICE_KERNEL_SHADER_EVAL_DISPLACE:
+ return "shader_eval_displace";
+ case DEVICE_KERNEL_SHADER_EVAL_BACKGROUND:
+ return "shader_eval_background";
+ case DEVICE_KERNEL_SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY:
+ return "shader_eval_curve_shadow_transparency";
+
+ /* Film. */
+
+#define FILM_CONVERT_KERNEL_AS_STRING(variant, variant_lowercase) \
+ case DEVICE_KERNEL_FILM_CONVERT_##variant: \
+ return "film_convert_" #variant_lowercase; \
+ case DEVICE_KERNEL_FILM_CONVERT_##variant##_HALF_RGBA: \
+ return "film_convert_" #variant_lowercase "_half_rgba";
+
+ FILM_CONVERT_KERNEL_AS_STRING(DEPTH, depth)
+ FILM_CONVERT_KERNEL_AS_STRING(MIST, mist)
+ FILM_CONVERT_KERNEL_AS_STRING(SAMPLE_COUNT, sample_count)
+ FILM_CONVERT_KERNEL_AS_STRING(FLOAT, float)
+ FILM_CONVERT_KERNEL_AS_STRING(LIGHT_PATH, light_path)
+ FILM_CONVERT_KERNEL_AS_STRING(FLOAT3, float3)
+ FILM_CONVERT_KERNEL_AS_STRING(MOTION, motion)
+ FILM_CONVERT_KERNEL_AS_STRING(CRYPTOMATTE, cryptomatte)
+ FILM_CONVERT_KERNEL_AS_STRING(SHADOW_CATCHER, shadow_catcher)
+ FILM_CONVERT_KERNEL_AS_STRING(SHADOW_CATCHER_MATTE_WITH_SHADOW,
+ shadow_catcher_matte_with_shadow)
+ FILM_CONVERT_KERNEL_AS_STRING(COMBINED, combined)
+ FILM_CONVERT_KERNEL_AS_STRING(FLOAT4, float4)
+
+#undef FILM_CONVERT_KERNEL_AS_STRING
+
+ /* Adaptive sampling. */
+ case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_CHECK:
+ return "adaptive_sampling_convergence_check";
+ case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_X:
+ return "adaptive_sampling_filter_x";
+ case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_Y:
+ return "adaptive_sampling_filter_y";
+
+ /* Denoising. */
+ case DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS:
+ return "filter_guiding_preprocess";
+ case DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO:
+ return "filter_guiding_set_fake_albedo";
+ case DEVICE_KERNEL_FILTER_COLOR_PREPROCESS:
+ return "filter_color_preprocess";
+ case DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS:
+ return "filter_color_postprocess";
+
+ /* Cryptomatte. */
+ case DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS:
+ return "cryptomatte_postprocess";
+
+ /* Generic */
+ case DEVICE_KERNEL_PREFIX_SUM:
+ return "prefix_sum";
+
+ case DEVICE_KERNEL_NUM:
+ break;
+ };
+ LOG(FATAL) << "Unhandled kernel " << static_cast<int>(kernel) << ", should never happen.";
+ return "UNKNOWN";
+}
+
+std::ostream &operator<<(std::ostream &os, DeviceKernel kernel)
+{
+ os << device_kernel_as_string(kernel);
+ return os;
+}
+
+string device_kernel_mask_as_string(DeviceKernelMask mask)
+{
+ string str;
+
+ for (uint64_t i = 0; i < sizeof(DeviceKernelMask) * 8; i++) {
+ if (mask & (uint64_t(1) << i)) {
+ if (!str.empty()) {
+ str += " ";
+ }
+ str += device_kernel_as_string((DeviceKernel)i);
+ }
+ }
+
+ return str;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/kernel.h b/intern/cycles/device/kernel.h
new file mode 100644
index 00000000000..780ead2d28a
--- /dev/null
+++ b/intern/cycles/device/kernel.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/types.h"
+
+#include "util/string.h"
+
+#include <ostream> // NOLINT
+
+CCL_NAMESPACE_BEGIN
+
+const char *device_kernel_as_string(DeviceKernel kernel);
+std::ostream &operator<<(std::ostream &os, DeviceKernel kernel);
+
+typedef uint64_t DeviceKernelMask;
+string device_kernel_mask_as_string(DeviceKernelMask mask);
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/memory.cpp b/intern/cycles/device/memory.cpp
new file mode 100644
index 00000000000..f162b00d9f7
--- /dev/null
+++ b/intern/cycles/device/memory.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device/memory.h"
+#include "device/device.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Device Memory */
+
+device_memory::device_memory(Device *device, const char *name, MemoryType type)
+ : data_type(device_type_traits<uchar>::data_type),
+ data_elements(device_type_traits<uchar>::num_elements_cpu),
+ data_size(0),
+ device_size(0),
+ data_width(0),
+ data_height(0),
+ data_depth(0),
+ type(type),
+ name(name),
+ device(device),
+ device_pointer(0),
+ host_pointer(0),
+ shared_pointer(0),
+ shared_counter(0),
+ original_device_ptr(0),
+ original_device_size(0),
+ original_device(0),
+ need_realloc_(false),
+ modified(false)
+{
+}
+
+device_memory::device_memory(device_memory &&other) noexcept
+ : data_type(other.data_type),
+ data_elements(other.data_elements),
+ data_size(other.data_size),
+ device_size(other.device_size),
+ data_width(other.data_width),
+ data_height(other.data_height),
+ data_depth(other.data_depth),
+ type(other.type),
+ name(other.name),
+ device(other.device),
+ device_pointer(other.device_pointer),
+ host_pointer(other.host_pointer),
+ shared_pointer(other.shared_pointer),
+ shared_counter(other.shared_counter),
+ original_device_ptr(other.original_device_ptr),
+ original_device_size(other.original_device_size),
+ original_device(other.original_device),
+ need_realloc_(other.need_realloc_),
+ modified(other.modified)
+{
+ other.data_elements = 0;
+ other.data_size = 0;
+ other.device_size = 0;
+ other.data_width = 0;
+ other.data_height = 0;
+ other.data_depth = 0;
+ other.device = 0;
+ other.device_pointer = 0;
+ other.host_pointer = 0;
+ other.shared_pointer = 0;
+ other.shared_counter = 0;
+ other.original_device_ptr = 0;
+ other.original_device_size = 0;
+ other.original_device = 0;
+ other.need_realloc_ = false;
+ other.modified = false;
+}
+
+device_memory::~device_memory()
+{
+ assert(shared_pointer == 0);
+ assert(shared_counter == 0);
+}
+
+void *device_memory::host_alloc(size_t size)
+{
+ if (!size) {
+ return 0;
+ }
+
+ void *ptr = util_aligned_malloc(size, MIN_ALIGNMENT_CPU_DATA_TYPES);
+
+ if (ptr) {
+ util_guarded_mem_alloc(size);
+ }
+ else {
+ throw std::bad_alloc();
+ }
+
+ return ptr;
+}
+
+void device_memory::host_free()
+{
+ if (host_pointer) {
+ util_guarded_mem_free(memory_size());
+ util_aligned_free((void *)host_pointer);
+ host_pointer = 0;
+ }
+}
+
+void device_memory::device_alloc()
+{
+ assert(!device_pointer && type != MEM_TEXTURE && type != MEM_GLOBAL);
+ device->mem_alloc(*this);
+}
+
+void device_memory::device_free()
+{
+ if (device_pointer) {
+ device->mem_free(*this);
+ }
+}
+
+void device_memory::device_copy_to()
+{
+ if (host_pointer) {
+ device->mem_copy_to(*this);
+ }
+}
+
+void device_memory::device_copy_from(size_t y, size_t w, size_t h, size_t elem)
+{
+ assert(type != MEM_TEXTURE && type != MEM_READ_ONLY && type != MEM_GLOBAL);
+ device->mem_copy_from(*this, y, w, h, elem);
+}
+
+void device_memory::device_zero()
+{
+ if (data_size) {
+ device->mem_zero(*this);
+ }
+}
+
+bool device_memory::device_is_cpu()
+{
+ return (device->info.type == DEVICE_CPU);
+}
+
+void device_memory::swap_device(Device *new_device,
+ size_t new_device_size,
+ device_ptr new_device_ptr)
+{
+ original_device = device;
+ original_device_size = device_size;
+ original_device_ptr = device_pointer;
+
+ device = new_device;
+ device_size = new_device_size;
+ device_pointer = new_device_ptr;
+}
+
+void device_memory::restore_device()
+{
+ device = original_device;
+ device_size = original_device_size;
+ device_pointer = original_device_ptr;
+}
+
+bool device_memory::is_resident(Device *sub_device) const
+{
+ return device->is_resident(device_pointer, sub_device);
+}
+
+/* Device Sub Ptr */
+
+device_sub_ptr::device_sub_ptr(device_memory &mem, size_t offset, size_t size) : device(mem.device)
+{
+ ptr = device->mem_alloc_sub_ptr(mem, offset, size);
+}
+
+device_sub_ptr::~device_sub_ptr()
+{
+ device->mem_free_sub_ptr(ptr);
+}
+
+/* Device Texture */
+
+device_texture::device_texture(Device *device,
+ const char *name,
+ const uint slot,
+ ImageDataType image_data_type,
+ InterpolationType interpolation,
+ ExtensionType extension)
+ : device_memory(device, name, MEM_TEXTURE), slot(slot)
+{
+ switch (image_data_type) {
+ case IMAGE_DATA_TYPE_FLOAT4:
+ data_type = TYPE_FLOAT;
+ data_elements = 4;
+ break;
+ case IMAGE_DATA_TYPE_FLOAT:
+ data_type = TYPE_FLOAT;
+ data_elements = 1;
+ break;
+ case IMAGE_DATA_TYPE_BYTE4:
+ data_type = TYPE_UCHAR;
+ data_elements = 4;
+ break;
+ case IMAGE_DATA_TYPE_BYTE:
+ case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
+ case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
+ data_type = TYPE_UCHAR;
+ data_elements = 1;
+ break;
+ case IMAGE_DATA_TYPE_HALF4:
+ data_type = TYPE_HALF;
+ data_elements = 4;
+ break;
+ case IMAGE_DATA_TYPE_HALF:
+ data_type = TYPE_HALF;
+ data_elements = 1;
+ break;
+ case IMAGE_DATA_TYPE_USHORT4:
+ data_type = TYPE_UINT16;
+ data_elements = 4;
+ break;
+ case IMAGE_DATA_TYPE_USHORT:
+ data_type = TYPE_UINT16;
+ data_elements = 1;
+ break;
+ case IMAGE_DATA_NUM_TYPES:
+ assert(0);
+ return;
+ }
+
+ memset(&info, 0, sizeof(info));
+ info.data_type = image_data_type;
+ info.interpolation = interpolation;
+ info.extension = extension;
+}
+
+device_texture::~device_texture()
+{
+ device_free();
+ host_free();
+}
+
+/* Host memory allocation. */
+void *device_texture::alloc(const size_t width, const size_t height, const size_t depth)
+{
+ const size_t new_size = size(width, height, depth);
+
+ if (new_size != data_size) {
+ device_free();
+ host_free();
+ host_pointer = host_alloc(data_elements * datatype_size(data_type) * new_size);
+ assert(device_pointer == 0);
+ }
+
+ data_size = new_size;
+ data_width = width;
+ data_height = height;
+ data_depth = depth;
+
+ info.width = width;
+ info.height = height;
+ info.depth = depth;
+
+ return host_pointer;
+}
+
+void device_texture::copy_to_device()
+{
+ device_copy_to();
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/memory.h b/intern/cycles/device/memory.h
new file mode 100644
index 00000000000..281c54cc6a5
--- /dev/null
+++ b/intern/cycles/device/memory.h
@@ -0,0 +1,650 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DEVICE_MEMORY_H__
+#define __DEVICE_MEMORY_H__
+
+/* Device Memory
+ *
+ * Data types for allocating, copying and freeing device memory. */
+
+#include "util/array.h"
+#include "util/half.h"
+#include "util/string.h"
+#include "util/texture.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+
+enum MemoryType {
+ MEM_READ_ONLY,
+ MEM_READ_WRITE,
+ MEM_DEVICE_ONLY,
+ MEM_GLOBAL,
+ MEM_TEXTURE,
+};
+
+/* Supported Data Types */
+
+enum DataType {
+ TYPE_UNKNOWN,
+ TYPE_UCHAR,
+ TYPE_UINT16,
+ TYPE_UINT,
+ TYPE_INT,
+ TYPE_FLOAT,
+ TYPE_HALF,
+ TYPE_UINT64,
+};
+
+static constexpr size_t datatype_size(DataType datatype)
+{
+ switch (datatype) {
+ case TYPE_UNKNOWN:
+ return 1;
+ case TYPE_UCHAR:
+ return sizeof(uchar);
+ case TYPE_FLOAT:
+ return sizeof(float);
+ case TYPE_UINT:
+ return sizeof(uint);
+ case TYPE_UINT16:
+ return sizeof(uint16_t);
+ case TYPE_INT:
+ return sizeof(int);
+ case TYPE_HALF:
+ return sizeof(half);
+ case TYPE_UINT64:
+ return sizeof(uint64_t);
+ default:
+ return 0;
+ }
+}
+
+/* Traits for data types */
+
+template<typename T> struct device_type_traits {
+ static const DataType data_type = TYPE_UNKNOWN;
+ static const size_t num_elements_cpu = sizeof(T);
+ static const size_t num_elements_gpu = sizeof(T);
+};
+
+template<> struct device_type_traits<uchar> {
+ static const DataType data_type = TYPE_UCHAR;
+ static const size_t num_elements_cpu = 1;
+ static const size_t num_elements_gpu = 1;
+ static_assert(sizeof(uchar) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uchar2> {
+ static const DataType data_type = TYPE_UCHAR;
+ static const size_t num_elements_cpu = 2;
+ static const size_t num_elements_gpu = 2;
+ static_assert(sizeof(uchar2) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uchar3> {
+ static const DataType data_type = TYPE_UCHAR;
+ static const size_t num_elements_cpu = 3;
+ static const size_t num_elements_gpu = 3;
+ static_assert(sizeof(uchar3) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uchar4> {
+ static const DataType data_type = TYPE_UCHAR;
+ static const size_t num_elements_cpu = 4;
+ static const size_t num_elements_gpu = 4;
+ static_assert(sizeof(uchar4) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint> {
+ static const DataType data_type = TYPE_UINT;
+ static const size_t num_elements_cpu = 1;
+ static const size_t num_elements_gpu = 1;
+ static_assert(sizeof(uint) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint2> {
+ static const DataType data_type = TYPE_UINT;
+ static const size_t num_elements_cpu = 2;
+ static const size_t num_elements_gpu = 2;
+ static_assert(sizeof(uint2) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint3> {
+ static const DataType data_type = TYPE_UINT;
+ static const size_t num_elements_cpu = 3;
+ static const size_t num_elements_gpu = 3;
+ static_assert(sizeof(uint3) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint4> {
+ static const DataType data_type = TYPE_UINT;
+ static const size_t num_elements_cpu = 4;
+ static const size_t num_elements_gpu = 4;
+ static_assert(sizeof(uint4) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<int> {
+ static const DataType data_type = TYPE_INT;
+ static const size_t num_elements_cpu = 1;
+ static const size_t num_elements_gpu = 1;
+ static_assert(sizeof(int) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<int2> {
+ static const DataType data_type = TYPE_INT;
+ static const size_t num_elements_cpu = 2;
+ static const size_t num_elements_gpu = 2;
+ static_assert(sizeof(int2) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<int3> {
+ static const DataType data_type = TYPE_INT;
+ static const size_t num_elements_cpu = 4;
+ static const size_t num_elements_gpu = 3;
+ static_assert(sizeof(int3) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<int4> {
+ static const DataType data_type = TYPE_INT;
+ static const size_t num_elements_cpu = 4;
+ static const size_t num_elements_gpu = 4;
+ static_assert(sizeof(int4) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<float> {
+ static const DataType data_type = TYPE_FLOAT;
+ static const size_t num_elements_cpu = 1;
+ static const size_t num_elements_gpu = 1;
+ static_assert(sizeof(float) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<float2> {
+ static const DataType data_type = TYPE_FLOAT;
+ static const size_t num_elements_cpu = 2;
+ static const size_t num_elements_gpu = 2;
+ static_assert(sizeof(float2) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<float3> {
+ static const DataType data_type = TYPE_FLOAT;
+ static const size_t num_elements_cpu = 4;
+ static const size_t num_elements_gpu = 3;
+ static_assert(sizeof(float3) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<float4> {
+ static const DataType data_type = TYPE_FLOAT;
+ static const size_t num_elements_cpu = 4;
+ static const size_t num_elements_gpu = 4;
+ static_assert(sizeof(float4) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<half> {
+ static const DataType data_type = TYPE_HALF;
+ static const size_t num_elements_cpu = 1;
+ static const size_t num_elements_gpu = 1;
+ static_assert(sizeof(half) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<ushort4> {
+ static const DataType data_type = TYPE_UINT16;
+ static const size_t num_elements_cpu = 4;
+ static const size_t num_elements_gpu = 4;
+ static_assert(sizeof(ushort4) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint16_t> {
+ static const DataType data_type = TYPE_UINT16;
+ static const size_t num_elements_cpu = 1;
+ static const size_t num_elements_gpu = 1;
+ static_assert(sizeof(uint16_t) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<half4> {
+ static const DataType data_type = TYPE_HALF;
+ static const size_t num_elements_cpu = 4;
+ static const size_t num_elements_gpu = 4;
+ static_assert(sizeof(half4) == num_elements_cpu * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint64_t> {
+ static const DataType data_type = TYPE_UINT64;
+ static const size_t num_elements_cpu = 1;
+ static const size_t num_elements_gpu = 1;
+ static_assert(sizeof(uint64_t) == num_elements_cpu * datatype_size(data_type));
+};
+
+/* Device Memory
+ *
+ * Base class for all device memory. This should not be allocated directly,
+ * instead the appropriate subclass can be used. */
+
+class device_memory {
+ public:
+ size_t memory_size()
+ {
+ return data_size * data_elements * datatype_size(data_type);
+ }
+ size_t memory_elements_size(int elements)
+ {
+ return elements * data_elements * datatype_size(data_type);
+ }
+
+ /* Data information. */
+ DataType data_type;
+ int data_elements;
+ size_t data_size;
+ size_t device_size;
+ size_t data_width;
+ size_t data_height;
+ size_t data_depth;
+ MemoryType type;
+ const char *name;
+
+ /* Pointers. */
+ Device *device;
+ device_ptr device_pointer;
+ void *host_pointer;
+ void *shared_pointer;
+ /* reference counter for shared_pointer */
+ int shared_counter;
+
+ virtual ~device_memory();
+
+ void swap_device(Device *new_device, size_t new_device_size, device_ptr new_device_ptr);
+ void restore_device();
+
+ bool is_resident(Device *sub_device) const;
+
+ protected:
+ friend class CUDADevice;
+ friend class OptiXDevice;
+ friend class HIPDevice;
+
+ /* Only create through subclasses. */
+ device_memory(Device *device, const char *name, MemoryType type);
+ device_memory(device_memory &&other) noexcept;
+
+ /* No copying allowed. */
+ device_memory(const device_memory &) = delete;
+ device_memory &operator=(const device_memory &) = delete;
+
+ /* Host allocation on the device. All host_pointer memory should be
+ * allocated with these functions, for devices that support using
+ * the same pointer for host and device. */
+ void *host_alloc(size_t size);
+ void host_free();
+
+ /* Device memory allocation and copying. */
+ void device_alloc();
+ void device_free();
+ void device_copy_to();
+ void device_copy_from(size_t y, size_t w, size_t h, size_t elem);
+ void device_zero();
+
+ bool device_is_cpu();
+
+ device_ptr original_device_ptr;
+ size_t original_device_size;
+ Device *original_device;
+ bool need_realloc_;
+ bool modified;
+};
+
+/* Device Only Memory
+ *
+ * Working memory only needed by the device, with no corresponding allocation
+ * on the host. Only used internally in the device implementations. */
+
+template<typename T> class device_only_memory : public device_memory {
+ public:
+ device_only_memory(Device *device, const char *name, bool allow_host_memory_fallback = false)
+ : device_memory(device, name, allow_host_memory_fallback ? MEM_READ_WRITE : MEM_DEVICE_ONLY)
+ {
+ data_type = device_type_traits<T>::data_type;
+ data_elements = max(device_is_cpu() ? device_type_traits<T>::num_elements_cpu :
+ device_type_traits<T>::num_elements_gpu,
+ 1);
+ }
+
+ device_only_memory(device_only_memory &&other) noexcept : device_memory(std::move(other))
+ {
+ }
+
+ virtual ~device_only_memory()
+ {
+ free();
+ }
+
+ void alloc_to_device(size_t num, bool shrink_to_fit = true)
+ {
+ size_t new_size = num;
+ bool reallocate;
+
+ if (shrink_to_fit) {
+ reallocate = (data_size != new_size);
+ }
+ else {
+ reallocate = (data_size < new_size);
+ }
+
+ if (reallocate) {
+ device_free();
+ data_size = new_size;
+ device_alloc();
+ }
+ }
+
+ void free()
+ {
+ device_free();
+ data_size = 0;
+ }
+
+ void zero_to_device()
+ {
+ device_zero();
+ }
+};
+
+/* Device Vector
+ *
+ * Data vector to exchange data between host and device. Memory will be
+ * allocated on the host first with alloc() and resize, and then filled
+ * in and copied to the device with copy_to_device(). Or alternatively
+ * allocated and set to zero on the device with zero_to_device().
+ *
+ * When using memory type MEM_GLOBAL, a pointer to this memory will be
+ * automatically attached to kernel globals, using the provided name
+ * matching an entry in kernel_textures.h. */
+
+template<typename T> class device_vector : public device_memory {
+ public:
+ /* Can only use this for types that have the same size on CPU and GPU. */
+ static_assert(device_type_traits<T>::num_elements_cpu ==
+ device_type_traits<T>::num_elements_gpu);
+
+ device_vector(Device *device, const char *name, MemoryType type)
+ : device_memory(device, name, type)
+ {
+ data_type = device_type_traits<T>::data_type;
+ data_elements = device_type_traits<T>::num_elements_cpu;
+ modified = true;
+ need_realloc_ = true;
+
+ assert(data_elements > 0);
+ }
+
+ virtual ~device_vector()
+ {
+ free();
+ }
+
+ /* Host memory allocation. */
+ T *alloc(size_t width, size_t height = 0, size_t depth = 0)
+ {
+ size_t new_size = size(width, height, depth);
+
+ if (new_size != data_size) {
+ device_free();
+ host_free();
+ host_pointer = host_alloc(sizeof(T) * new_size);
+ modified = true;
+ assert(device_pointer == 0);
+ }
+
+ data_size = new_size;
+ data_width = width;
+ data_height = height;
+ data_depth = depth;
+
+ return data();
+ }
+
+ /* Host memory resize. Only use this if the original data needs to be
+ * preserved, it is faster to call alloc() if it can be discarded. */
+ T *resize(size_t width, size_t height = 0, size_t depth = 0)
+ {
+ size_t new_size = size(width, height, depth);
+
+ if (new_size != data_size) {
+ void *new_ptr = host_alloc(sizeof(T) * new_size);
+
+ if (new_size && data_size) {
+ size_t min_size = ((new_size < data_size) ? new_size : data_size);
+ memcpy((T *)new_ptr, (T *)host_pointer, sizeof(T) * min_size);
+ }
+
+ device_free();
+ host_free();
+ host_pointer = new_ptr;
+ assert(device_pointer == 0);
+ }
+
+ data_size = new_size;
+ data_width = width;
+ data_height = height;
+ data_depth = depth;
+
+ return data();
+ }
+
+ /* Take over data from an existing array. */
+ void steal_data(array<T> &from)
+ {
+ device_free();
+ host_free();
+
+ data_size = from.size();
+ data_width = 0;
+ data_height = 0;
+ data_depth = 0;
+ host_pointer = from.steal_pointer();
+ assert(device_pointer == 0);
+ }
+
+ void give_data(array<T> &to)
+ {
+ device_free();
+
+ to.set_data((T *)host_pointer, data_size);
+ data_size = 0;
+ data_width = 0;
+ data_height = 0;
+ data_depth = 0;
+ host_pointer = 0;
+ assert(device_pointer == 0);
+ }
+
+ /* Free device and host memory. */
+ void free()
+ {
+ device_free();
+ host_free();
+
+ data_size = 0;
+ data_width = 0;
+ data_height = 0;
+ data_depth = 0;
+ host_pointer = 0;
+ modified = true;
+ need_realloc_ = true;
+ assert(device_pointer == 0);
+ }
+
+ void free_if_need_realloc(bool force_free)
+ {
+ if (need_realloc_ || force_free) {
+ free();
+ }
+ }
+
+ bool is_modified() const
+ {
+ return modified;
+ }
+
+ bool need_realloc()
+ {
+ return need_realloc_;
+ }
+
+ void tag_modified()
+ {
+ modified = true;
+ }
+
+ void tag_realloc()
+ {
+ need_realloc_ = true;
+ tag_modified();
+ }
+
+ size_t size() const
+ {
+ return data_size;
+ }
+
+ T *data()
+ {
+ return (T *)host_pointer;
+ }
+
+ const T *data() const
+ {
+ return (T *)host_pointer;
+ }
+
+ T &operator[](size_t i)
+ {
+ assert(i < data_size);
+ return data()[i];
+ }
+
+ void copy_to_device()
+ {
+ if (data_size != 0) {
+ device_copy_to();
+ }
+ }
+
+ void copy_to_device_if_modified()
+ {
+ if (!modified) {
+ return;
+ }
+
+ copy_to_device();
+ }
+
+ void clear_modified()
+ {
+ modified = false;
+ need_realloc_ = false;
+ }
+
+ void copy_from_device()
+ {
+ device_copy_from(0, data_width, (data_height == 0) ? 1 : data_height, sizeof(T));
+ }
+
+ void copy_from_device(size_t y, size_t w, size_t h)
+ {
+ device_copy_from(y, w, h, sizeof(T));
+ }
+
+ void zero_to_device()
+ {
+ device_zero();
+ }
+
+ void move_device(Device *new_device)
+ {
+ copy_from_device();
+ device_free();
+ device = new_device;
+ copy_to_device();
+ }
+
+ protected:
+ size_t size(size_t width, size_t height, size_t depth)
+ {
+ return width * ((height == 0) ? 1 : height) * ((depth == 0) ? 1 : depth);
+ }
+};
+
+/* Device Sub Memory
+ *
+ * Pointer into existing memory. It is not allocated separately, but created
+ * from an already allocated base memory. It is freed automatically when it
+ * goes out of scope, which should happen before base memory is freed.
+ *
+ * Note: some devices require offset and size of the sub_ptr to be properly
+ * aligned to device->mem_address_alingment(). */
+
+class device_sub_ptr {
+ public:
+ device_sub_ptr(device_memory &mem, size_t offset, size_t size);
+ ~device_sub_ptr();
+
+ device_ptr operator*() const
+ {
+ return ptr;
+ }
+
+ protected:
+ /* No copying. */
+ device_sub_ptr &operator=(const device_sub_ptr &);
+
+ Device *device;
+ device_ptr ptr;
+};
+
+/* Device Texture
+ *
+ * 2D or 3D image texture memory. */
+
+class device_texture : public device_memory {
+ public:
+ device_texture(Device *device,
+ const char *name,
+ const uint slot,
+ ImageDataType image_data_type,
+ InterpolationType interpolation,
+ ExtensionType extension);
+ ~device_texture();
+
+ void *alloc(const size_t width, const size_t height, const size_t depth = 0);
+ void copy_to_device();
+
+ uint slot;
+ TextureInfo info;
+
+ protected:
+ size_t size(const size_t width, const size_t height, const size_t depth)
+ {
+ return width * ((height == 0) ? 1 : height) * ((depth == 0) ? 1 : depth);
+ }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __DEVICE_MEMORY_H__ */
diff --git a/intern/cycles/device/multi/device.cpp b/intern/cycles/device/multi/device.cpp
index 4f995abf2c4..56efec3e131 100644
--- a/intern/cycles/device/multi/device.cpp
+++ b/intern/cycles/device/multi/device.cpp
@@ -19,19 +19,18 @@
#include <sstream>
#include <stdlib.h>
-#include "bvh/bvh_multi.h"
+#include "bvh/multi.h"
#include "device/device.h"
-#include "device/device_queue.h"
+#include "device/queue.h"
-#include "render/buffers.h"
-#include "render/geometry.h"
+#include "scene/geometry.h"
-#include "util/util_foreach.h"
-#include "util/util_list.h"
-#include "util/util_logging.h"
-#include "util/util_map.h"
-#include "util/util_time.h"
+#include "util/foreach.h"
+#include "util/list.h"
+#include "util/log.h"
+#include "util/map.h"
+#include "util/time.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/multi/device.h b/intern/cycles/device/multi/device.h
index 6e121014a1f..ac77f6574ef 100644
--- a/intern/cycles/device/multi/device.h
+++ b/intern/cycles/device/multi/device.h
@@ -16,8 +16,8 @@
#pragma once
-#include "util/util_string.h"
-#include "util/util_vector.h"
+#include "util/string.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/optix/device.cpp b/intern/cycles/device/optix/device.cpp
index 13f23bd229a..a00169e719f 100644
--- a/intern/cycles/device/optix/device.cpp
+++ b/intern/cycles/device/optix/device.cpp
@@ -19,7 +19,8 @@
#include "device/cuda/device.h"
#include "device/optix/device_impl.h"
-#include "util/util_logging.h"
+
+#include "util/log.h"
#ifdef WITH_OPTIX
# include <optix_function_table_definition.h>
diff --git a/intern/cycles/device/optix/device.h b/intern/cycles/device/optix/device.h
index 29fa729c2e4..dd60a7aa6e2 100644
--- a/intern/cycles/device/optix/device.h
+++ b/intern/cycles/device/optix/device.h
@@ -16,8 +16,8 @@
#pragma once
-#include "util/util_string.h"
-#include "util/util_vector.h"
+#include "util/string.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp
index 29e46be7745..e9164cc0a76 100644
--- a/intern/cycles/device/optix/device_impl.cpp
+++ b/intern/cycles/device/optix/device_impl.cpp
@@ -20,21 +20,22 @@
# include "device/optix/device_impl.h"
# include "bvh/bvh.h"
-# include "bvh/bvh_optix.h"
+# include "bvh/optix.h"
+
# include "integrator/pass_accessor_gpu.h"
-# include "render/buffers.h"
-# include "render/hair.h"
-# include "render/mesh.h"
-# include "render/object.h"
-# include "render/pass.h"
-# include "render/scene.h"
-
-# include "util/util_debug.h"
-# include "util/util_logging.h"
-# include "util/util_md5.h"
-# include "util/util_path.h"
-# include "util/util_progress.h"
-# include "util/util_time.h"
+
+# include "scene/hair.h"
+# include "scene/mesh.h"
+# include "scene/object.h"
+# include "scene/pass.h"
+# include "scene/scene.h"
+
+# include "util/debug.h"
+# include "util/log.h"
+# include "util/md5.h"
+# include "util/path.h"
+# include "util/progress.h"
+# include "util/time.h"
# undef __KERNEL_CPU__
# define __KERNEL_OPTIX__
@@ -1573,7 +1574,7 @@ void OptiXDevice::const_copy_to(const char *name, void *host, size_t size)
return; \
}
KERNEL_TEX(IntegratorStateGPU, __integrator_state)
-# include "kernel/kernel_textures.h"
+# include "kernel/textures.h"
# undef KERNEL_TEX
}
diff --git a/intern/cycles/device/optix/device_impl.h b/intern/cycles/device/optix/device_impl.h
index b20d42f8c61..3ec98098eb7 100644
--- a/intern/cycles/device/optix/device_impl.h
+++ b/intern/cycles/device/optix/device_impl.h
@@ -22,7 +22,7 @@
# include "device/cuda/device_impl.h"
# include "device/optix/queue.h"
# include "device/optix/util.h"
-# include "kernel/kernel_types.h"
+# include "kernel/types.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/device/optix/queue.cpp b/intern/cycles/device/optix/queue.cpp
index 458ed70baa8..f5bfd916ccf 100644
--- a/intern/cycles/device/optix/queue.cpp
+++ b/intern/cycles/device/optix/queue.cpp
@@ -19,7 +19,7 @@
# include "device/optix/queue.h"
# include "device/optix/device_impl.h"
-# include "util/util_time.h"
+# include "util/time.h"
# undef __KERNEL_CPU__
# define __KERNEL_OPTIX__
diff --git a/intern/cycles/device/queue.cpp b/intern/cycles/device/queue.cpp
new file mode 100644
index 00000000000..556dc97f23b
--- /dev/null
+++ b/intern/cycles/device/queue.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device/queue.h"
+
+#include "util/algorithm.h"
+#include "util/log.h"
+#include "util/time.h"
+
+#include <iomanip>
+
+CCL_NAMESPACE_BEGIN
+
+DeviceQueue::DeviceQueue(Device *device)
+ : device(device), last_kernels_enqueued_(0), last_sync_time_(0.0)
+{
+ DCHECK_NE(device, nullptr);
+}
+
+DeviceQueue::~DeviceQueue()
+{
+ if (VLOG_IS_ON(3)) {
+ /* Print kernel execution times sorted by time. */
+ vector<pair<DeviceKernelMask, double>> stats_sorted;
+ for (const auto &stat : stats_kernel_time_) {
+ stats_sorted.push_back(stat);
+ }
+
+ sort(stats_sorted.begin(),
+ stats_sorted.end(),
+ [](const pair<DeviceKernelMask, double> &a, const pair<DeviceKernelMask, double> &b) {
+ return a.second > b.second;
+ });
+
+ VLOG(3) << "GPU queue stats:";
+ for (const auto &[mask, time] : stats_sorted) {
+ VLOG(3) << " " << std::setfill(' ') << std::setw(10) << std::fixed << std::setprecision(5)
+ << std::right << time << "s: " << device_kernel_mask_as_string(mask);
+ }
+ }
+}
+
+void DeviceQueue::debug_init_execution()
+{
+ if (VLOG_IS_ON(3)) {
+ last_sync_time_ = time_dt();
+ }
+
+ last_kernels_enqueued_ = 0;
+}
+
+void DeviceQueue::debug_enqueue(DeviceKernel kernel, const int work_size)
+{
+ if (VLOG_IS_ON(3)) {
+ VLOG(4) << "GPU queue launch " << device_kernel_as_string(kernel) << ", work_size "
+ << work_size;
+ }
+
+ last_kernels_enqueued_ |= (uint64_t(1) << (uint64_t)kernel);
+}
+
+void DeviceQueue::debug_synchronize()
+{
+ if (VLOG_IS_ON(3)) {
+ const double new_time = time_dt();
+ const double elapsed_time = new_time - last_sync_time_;
+ VLOG(4) << "GPU queue synchronize, elapsed " << std::setw(10) << elapsed_time << "s";
+
+ stats_kernel_time_[last_kernels_enqueued_] += elapsed_time;
+
+ last_sync_time_ = new_time;
+ }
+
+ last_kernels_enqueued_ = 0;
+}
+
+string DeviceQueue::debug_active_kernels()
+{
+ return device_kernel_mask_as_string(last_kernels_enqueued_);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/queue.h b/intern/cycles/device/queue.h
new file mode 100644
index 00000000000..188162f4b74
--- /dev/null
+++ b/intern/cycles/device/queue.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "device/kernel.h"
+
+#include "device/graphics_interop.h"
+#include "util/log.h"
+#include "util/map.h"
+#include "util/string.h"
+#include "util/unique_ptr.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class device_memory;
+
+struct KernelWorkTile;
+
+/* Abstraction of a command queue for a device.
+ * Provides API to schedule kernel execution in a specific queue with minimal possible overhead
+ * from driver side.
+ *
+ * This class encapsulates all properties needed for commands execution. */
+class DeviceQueue {
+ public:
+ virtual ~DeviceQueue();
+
+ /* Number of concurrent states to process for integrator,
+ * based on number of cores and/or available memory. */
+ virtual int num_concurrent_states(const size_t state_size) const = 0;
+
+ /* Number of states which keeps the device occupied with work without loosing performance.
+ * The renderer will add more work (when available) when number of active paths falls below this
+ * value. */
+ virtual int num_concurrent_busy_states() const = 0;
+
+ /* Initialize execution of kernels on this queue.
+ *
+ * Will, for example, load all data required by the kernels from Device to global or path state.
+ *
+ * Use this method after device synchronization has finished before enqueueing any kernels. */
+ virtual void init_execution() = 0;
+
+ /* Test if an optional device kernel is available. */
+ virtual bool kernel_available(DeviceKernel kernel) const = 0;
+
+ /* Enqueue kernel execution.
+ *
+ * Execute the kernel work_size times on the device.
+ * Supported arguments types:
+ * - int: pass pointer to the int
+ * - device memory: pass pointer to device_memory.device_pointer
+ * Return false if there was an error executing this or a previous kernel. */
+ virtual bool enqueue(DeviceKernel kernel, const int work_size, void *args[]) = 0;
+
+ /* Wait unit all enqueued kernels have finished execution.
+ * Return false if there was an error executing any of the enqueued kernels. */
+ virtual bool synchronize() = 0;
+
+ /* Copy memory to/from device as part of the command queue, to ensure
+ * operations are done in order without having to synchronize. */
+ virtual void zero_to_device(device_memory &mem) = 0;
+ virtual void copy_to_device(device_memory &mem) = 0;
+ virtual void copy_from_device(device_memory &mem) = 0;
+
+ /* Graphics resources interoperability.
+ *
+ * The interoperability comes here by the meaning that the device is capable of computing result
+ * directly into an OpenGL (or other graphics library) buffer. */
+
+ /* Create graphics interoperability context which will be taking care of mapping graphics
+ * resource as a buffer writable by kernels of this device. */
+ virtual unique_ptr<DeviceGraphicsInterop> graphics_interop_create()
+ {
+ LOG(FATAL) << "Request of GPU interop of a device which does not support it.";
+ return nullptr;
+ }
+
+ /* Device this queue has been created for. */
+ Device *device;
+
+ protected:
+ /* Hide construction so that allocation via `Device` API is enforced. */
+ explicit DeviceQueue(Device *device);
+
+ /* Implementations call these from the corresponding methods to generate debugging logs. */
+ void debug_init_execution();
+ void debug_enqueue(DeviceKernel kernel, const int work_size);
+ void debug_synchronize();
+ string debug_active_kernels();
+
+ /* Combination of kernels enqueued together sync last synchronize. */
+ DeviceKernelMask last_kernels_enqueued_;
+ /* Time of synchronize call. */
+ double last_sync_time_;
+ /* Accumulated execution time for combinations of kernels launched together. */
+ map<DeviceKernelMask, double> stats_kernel_time_;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp
index 8294e716ebe..a3d75e53afd 100644
--- a/intern/cycles/graph/node.cpp
+++ b/intern/cycles/graph/node.cpp
@@ -17,10 +17,10 @@
#include "graph/node.h"
#include "graph/node_type.h"
-#include "util/util_foreach.h"
-#include "util/util_md5.h"
-#include "util/util_param.h"
-#include "util/util_transform.h"
+#include "util/foreach.h"
+#include "util/md5.h"
+#include "util/param.h"
+#include "util/transform.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h
index 8f27a82d37b..a00162a3b9a 100644
--- a/intern/cycles/graph/node.h
+++ b/intern/cycles/graph/node.h
@@ -20,9 +20,9 @@
#include "graph/node_type.h"
-#include "util/util_array.h"
-#include "util/util_map.h"
-#include "util/util_param.h"
+#include "util/array.h"
+#include "util/map.h"
+#include "util/param.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/graph/node_enum.h b/intern/cycles/graph/node_enum.h
index d3ed0928a4f..831c6e4a9c4 100644
--- a/intern/cycles/graph/node_enum.h
+++ b/intern/cycles/graph/node_enum.h
@@ -16,8 +16,8 @@
#pragma once
-#include "util/util_map.h"
-#include "util/util_param.h"
+#include "util/map.h"
+#include "util/param.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp
index 4efbd6725ee..bce98c694e1 100644
--- a/intern/cycles/graph/node_type.cpp
+++ b/intern/cycles/graph/node_type.cpp
@@ -15,8 +15,8 @@
*/
#include "graph/node_type.h"
-#include "util/util_foreach.h"
-#include "util/util_transform.h"
+#include "util/foreach.h"
+#include "util/transform.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h
index 8b37398fa17..71639341617 100644
--- a/intern/cycles/graph/node_type.h
+++ b/intern/cycles/graph/node_type.h
@@ -17,11 +17,11 @@
#pragma once
#include "graph/node_enum.h"
-#include "util/util_array.h"
-#include "util/util_map.h"
-#include "util/util_param.h"
-#include "util/util_string.h"
-#include "util/util_vector.h"
+#include "util/array.h"
+#include "util/map.h"
+#include "util/param.h"
+#include "util/string.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp
index 43462662b6a..b0c863ad4b5 100644
--- a/intern/cycles/graph/node_xml.cpp
+++ b/intern/cycles/graph/node_xml.cpp
@@ -16,9 +16,9 @@
#include "graph/node_xml.h"
-#include "util/util_foreach.h"
-#include "util/util_string.h"
-#include "util/util_transform.h"
+#include "util/foreach.h"
+#include "util/string.h"
+#include "util/transform.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/graph/node_xml.h b/intern/cycles/graph/node_xml.h
index 15bbf5d5621..ddbc5213ab1 100644
--- a/intern/cycles/graph/node_xml.h
+++ b/intern/cycles/graph/node_xml.h
@@ -18,9 +18,9 @@
#include "graph/node.h"
-#include "util/util_map.h"
-#include "util/util_string.h"
-#include "util/util_xml.h"
+#include "util/map.h"
+#include "util/string.h"
+#include "util/xml.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/CMakeLists.txt b/intern/cycles/integrator/CMakeLists.txt
index 949254606b8..dedde513409 100644
--- a/intern/cycles/integrator/CMakeLists.txt
+++ b/intern/cycles/integrator/CMakeLists.txt
@@ -61,9 +61,11 @@ set(SRC_HEADERS
)
set(LIB
+ cycles_device
+
# NOTE: Is required for RenderBuffers access. Might consider moving files around a bit to
# avoid such cyclic dependency.
- cycles_render
+ cycles_session
cycles_util
)
diff --git a/intern/cycles/integrator/adaptive_sampling.cpp b/intern/cycles/integrator/adaptive_sampling.cpp
index 23fbcfea5c2..253879d67e3 100644
--- a/intern/cycles/integrator/adaptive_sampling.cpp
+++ b/intern/cycles/integrator/adaptive_sampling.cpp
@@ -16,7 +16,7 @@
#include "integrator/adaptive_sampling.h"
-#include "util/util_math.h"
+#include "util/math.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/denoiser.cpp b/intern/cycles/integrator/denoiser.cpp
index 598bbd497a5..b6ca96faebf 100644
--- a/intern/cycles/integrator/denoiser.cpp
+++ b/intern/cycles/integrator/denoiser.cpp
@@ -19,9 +19,9 @@
#include "device/device.h"
#include "integrator/denoiser_oidn.h"
#include "integrator/denoiser_optix.h"
-#include "render/buffers.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
+#include "session/buffers.h"
+#include "util/log.h"
+#include "util/progress.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/denoiser.h b/intern/cycles/integrator/denoiser.h
index b02bcbeb046..8d7a644f8d9 100644
--- a/intern/cycles/integrator/denoiser.h
+++ b/intern/cycles/integrator/denoiser.h
@@ -19,10 +19,10 @@
/* TODO(sergey): The integrator folder might not be the best. Is easy to move files around if the
* better place is figured out. */
+#include "device/denoise.h"
#include "device/device.h"
-#include "device/device_denoise.h"
-#include "util/util_function.h"
-#include "util/util_unique_ptr.h"
+#include "util/function.h"
+#include "util/unique_ptr.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/denoiser_device.cpp b/intern/cycles/integrator/denoiser_device.cpp
index e8361c50f2f..2121dee500a 100644
--- a/intern/cycles/integrator/denoiser_device.cpp
+++ b/intern/cycles/integrator/denoiser_device.cpp
@@ -16,13 +16,13 @@
#include "integrator/denoiser_device.h"
+#include "device/denoise.h"
#include "device/device.h"
-#include "device/device_denoise.h"
-#include "device/device_memory.h"
-#include "device/device_queue.h"
-#include "render/buffers.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
+#include "device/memory.h"
+#include "device/queue.h"
+#include "session/buffers.h"
+#include "util/log.h"
+#include "util/progress.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/denoiser_device.h b/intern/cycles/integrator/denoiser_device.h
index 0fd934dba79..2bacecaa2a2 100644
--- a/intern/cycles/integrator/denoiser_device.h
+++ b/intern/cycles/integrator/denoiser_device.h
@@ -17,7 +17,7 @@
#pragma once
#include "integrator/denoiser.h"
-#include "util/util_unique_ptr.h"
+#include "util/unique_ptr.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/denoiser_oidn.cpp b/intern/cycles/integrator/denoiser_oidn.cpp
index cc9a3f51387..b09b95a11b0 100644
--- a/intern/cycles/integrator/denoiser_oidn.cpp
+++ b/intern/cycles/integrator/denoiser_oidn.cpp
@@ -19,12 +19,12 @@
#include <array>
#include "device/device.h"
-#include "device/device_queue.h"
+#include "device/queue.h"
#include "integrator/pass_accessor_cpu.h"
-#include "render/buffers.h"
-#include "util/util_array.h"
-#include "util/util_logging.h"
-#include "util/util_openimagedenoise.h"
+#include "session/buffers.h"
+#include "util/array.h"
+#include "util/log.h"
+#include "util/openimagedenoise.h"
#include "kernel/device/cpu/compat.h"
#include "kernel/device/cpu/kernel.h"
diff --git a/intern/cycles/integrator/denoiser_oidn.h b/intern/cycles/integrator/denoiser_oidn.h
index 566e761ae79..a0ec3e26b9c 100644
--- a/intern/cycles/integrator/denoiser_oidn.h
+++ b/intern/cycles/integrator/denoiser_oidn.h
@@ -17,8 +17,8 @@
#pragma once
#include "integrator/denoiser.h"
-#include "util/util_thread.h"
-#include "util/util_unique_ptr.h"
+#include "util/thread.h"
+#include "util/unique_ptr.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/denoiser_optix.cpp b/intern/cycles/integrator/denoiser_optix.cpp
index 5f9de23bfe6..ebd95d62ae4 100644
--- a/intern/cycles/integrator/denoiser_optix.cpp
+++ b/intern/cycles/integrator/denoiser_optix.cpp
@@ -16,8 +16,8 @@
#include "integrator/denoiser_optix.h"
+#include "device/denoise.h"
#include "device/device.h"
-#include "device/device_denoise.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/pass_accessor.cpp b/intern/cycles/integrator/pass_accessor.cpp
index 1308b03b06c..7e19de51daa 100644
--- a/intern/cycles/integrator/pass_accessor.cpp
+++ b/intern/cycles/integrator/pass_accessor.cpp
@@ -16,12 +16,12 @@
#include "integrator/pass_accessor.h"
-#include "render/buffers.h"
-#include "util/util_logging.h"
+#include "session/buffers.h"
+#include "util/log.h"
// clang-format off
#include "kernel/device/cpu/compat.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
// clang-format on
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/pass_accessor.h b/intern/cycles/integrator/pass_accessor.h
index 624bf7d0b2c..09eae0156c9 100644
--- a/intern/cycles/integrator/pass_accessor.h
+++ b/intern/cycles/integrator/pass_accessor.h
@@ -16,10 +16,10 @@
#pragma once
-#include "render/pass.h"
-#include "util/util_half.h"
-#include "util/util_string.h"
-#include "util/util_types.h"
+#include "scene/pass.h"
+#include "util/half.h"
+#include "util/string.h"
+#include "util/types.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/pass_accessor_cpu.cpp b/intern/cycles/integrator/pass_accessor_cpu.cpp
index e3cb81d31b7..820da757be0 100644
--- a/intern/cycles/integrator/pass_accessor_cpu.cpp
+++ b/intern/cycles/integrator/pass_accessor_cpu.cpp
@@ -16,15 +16,15 @@
#include "integrator/pass_accessor_cpu.h"
-#include "render/buffers.h"
-#include "util/util_logging.h"
-#include "util/util_tbb.h"
+#include "session/buffers.h"
+#include "util/log.h"
+#include "util/tbb.h"
// clang-format off
#include "kernel/device/cpu/compat.h"
#include "kernel/device/cpu/globals.h"
-#include "kernel/kernel_types.h"
-#include "kernel/kernel_film.h"
+#include "kernel/types.h"
+#include "kernel/film/read.h"
// clang-format on
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/pass_accessor_gpu.cpp b/intern/cycles/integrator/pass_accessor_gpu.cpp
index 7b01d061708..c03ef64a2b2 100644
--- a/intern/cycles/integrator/pass_accessor_gpu.cpp
+++ b/intern/cycles/integrator/pass_accessor_gpu.cpp
@@ -16,9 +16,9 @@
#include "integrator/pass_accessor_gpu.h"
-#include "device/device_queue.h"
-#include "render/buffers.h"
-#include "util/util_logging.h"
+#include "device/queue.h"
+#include "session/buffers.h"
+#include "util/log.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/pass_accessor_gpu.h b/intern/cycles/integrator/pass_accessor_gpu.h
index bc37e4387f3..f3442d90013 100644
--- a/intern/cycles/integrator/pass_accessor_gpu.h
+++ b/intern/cycles/integrator/pass_accessor_gpu.h
@@ -17,7 +17,7 @@
#pragma once
#include "integrator/pass_accessor.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp
index 9f3049c6484..daf270d6686 100644
--- a/intern/cycles/integrator/path_trace.cpp
+++ b/intern/cycles/integrator/path_trace.cpp
@@ -22,14 +22,14 @@
#include "integrator/path_trace_display.h"
#include "integrator/path_trace_tile.h"
#include "integrator/render_scheduler.h"
-#include "render/pass.h"
-#include "render/scene.h"
-#include "render/tile.h"
-#include "util/util_algorithm.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
-#include "util/util_tbb.h"
-#include "util/util_time.h"
+#include "scene/pass.h"
+#include "scene/scene.h"
+#include "session/tile.h"
+#include "util/algorithm.h"
+#include "util/log.h"
+#include "util/progress.h"
+#include "util/tbb.h"
+#include "util/time.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/path_trace.h b/intern/cycles/integrator/path_trace.h
index dbb22c204d9..9b079352a63 100644
--- a/intern/cycles/integrator/path_trace.h
+++ b/intern/cycles/integrator/path_trace.h
@@ -20,11 +20,11 @@
#include "integrator/pass_accessor.h"
#include "integrator/path_trace_work.h"
#include "integrator/work_balancer.h"
-#include "render/buffers.h"
-#include "util/util_function.h"
-#include "util/util_thread.h"
-#include "util/util_unique_ptr.h"
-#include "util/util_vector.h"
+#include "session/buffers.h"
+#include "util/function.h"
+#include "util/thread.h"
+#include "util/unique_ptr.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/path_trace_display.cpp b/intern/cycles/integrator/path_trace_display.cpp
index 28f0a7f7745..c1cade923b1 100644
--- a/intern/cycles/integrator/path_trace_display.cpp
+++ b/intern/cycles/integrator/path_trace_display.cpp
@@ -16,9 +16,9 @@
#include "integrator/path_trace_display.h"
-#include "render/buffers.h"
+#include "session/buffers.h"
-#include "util/util_logging.h"
+#include "util/log.h"
CCL_NAMESPACE_BEGIN
@@ -30,29 +30,16 @@ void PathTraceDisplay::reset(const BufferParams &buffer_params)
{
thread_scoped_lock lock(mutex_);
- const DisplayDriver::Params old_params = params_;
-
params_.full_offset = make_int2(buffer_params.full_x, buffer_params.full_y);
params_.full_size = make_int2(buffer_params.full_width, buffer_params.full_height);
params_.size = make_int2(buffer_params.width, buffer_params.height);
- /* If the parameters did change tag texture as unusable. This avoids drawing old texture content
- * in an updated configuration of the viewport. For example, avoids drawing old frame when render
- * border did change.
- * If the parameters did not change, allow drawing the current state of the texture, which will
- * not count as an up-to-date redraw. This will avoid flickering when doping camera navigation by
- * showing a previously rendered frame for until the new one is ready. */
- if (old_params.modified(params_)) {
- texture_state_.is_usable = false;
- }
-
texture_state_.is_outdated = true;
}
void PathTraceDisplay::mark_texture_updated()
{
texture_state_.is_outdated = false;
- texture_state_.is_usable = true;
}
/* --------------------------------------------------------------------
@@ -248,19 +235,15 @@ bool PathTraceDisplay::draw()
* The drawing itself is non-blocking however, for better performance and to avoid
* potential deadlocks due to locks held by the subclass. */
DisplayDriver::Params params;
- bool is_usable;
bool is_outdated;
{
thread_scoped_lock lock(mutex_);
params = params_;
- is_usable = texture_state_.is_usable;
is_outdated = texture_state_.is_outdated;
}
- if (is_usable) {
- driver_->draw(params);
- }
+ driver_->draw(params);
return !is_outdated;
}
diff --git a/intern/cycles/integrator/path_trace_display.h b/intern/cycles/integrator/path_trace_display.h
index 24aaa0df6b1..b69ee85fbbc 100644
--- a/intern/cycles/integrator/path_trace_display.h
+++ b/intern/cycles/integrator/path_trace_display.h
@@ -16,12 +16,12 @@
#pragma once
-#include "render/display_driver.h"
+#include "session/display_driver.h"
-#include "util/util_half.h"
-#include "util/util_thread.h"
-#include "util/util_types.h"
-#include "util/util_unique_ptr.h"
+#include "util/half.h"
+#include "util/thread.h"
+#include "util/types.h"
+#include "util/unique_ptr.h"
CCL_NAMESPACE_BEGIN
@@ -174,15 +174,6 @@ class PathTraceDisplay {
/* State of the texture, which is needed for an integration with render session and interactive
* updates and navigation. */
struct {
- /* Denotes whether possibly existing state of GPU side texture is still usable.
- * It will not be usable in cases like render border did change (in this case we don't want
- * previous texture to be rendered at all).
- *
- * However, if only navigation or object in scene did change, then the outdated state of the
- * texture is still usable for draw, preventing display viewport flickering on navigation and
- * object modifications. */
- bool is_usable = false;
-
/* Texture is considered outdated after `reset()` until the next call of
* `copy_pixels_to_texture()`. */
bool is_outdated = true;
diff --git a/intern/cycles/integrator/path_trace_tile.cpp b/intern/cycles/integrator/path_trace_tile.cpp
index 540f4aa5f68..4834769f476 100644
--- a/intern/cycles/integrator/path_trace_tile.cpp
+++ b/intern/cycles/integrator/path_trace_tile.cpp
@@ -18,10 +18,10 @@
#include "integrator/pass_accessor_cpu.h"
#include "integrator/path_trace.h"
-#include "render/buffers.h"
-#include "render/film.h"
-#include "render/pass.h"
-#include "render/scene.h"
+#include "scene/film.h"
+#include "scene/pass.h"
+#include "scene/scene.h"
+#include "session/buffers.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/path_trace_tile.h b/intern/cycles/integrator/path_trace_tile.h
index fd3e2969f6c..6c7bddf2ca5 100644
--- a/intern/cycles/integrator/path_trace_tile.h
+++ b/intern/cycles/integrator/path_trace_tile.h
@@ -16,7 +16,7 @@
#pragma once
-#include "render/output_driver.h"
+#include "session/output_driver.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/path_trace_work.cpp b/intern/cycles/integrator/path_trace_work.cpp
index d46f095d0d7..b0c40cfe15c 100644
--- a/intern/cycles/integrator/path_trace_work.cpp
+++ b/intern/cycles/integrator/path_trace_work.cpp
@@ -20,11 +20,11 @@
#include "integrator/path_trace_work.h"
#include "integrator/path_trace_work_cpu.h"
#include "integrator/path_trace_work_gpu.h"
-#include "render/buffers.h"
-#include "render/film.h"
-#include "render/scene.h"
+#include "scene/film.h"
+#include "scene/scene.h"
+#include "session/buffers.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/path_trace_work.h b/intern/cycles/integrator/path_trace_work.h
index 404165b7c55..0dc7cd2f896 100644
--- a/intern/cycles/integrator/path_trace_work.h
+++ b/intern/cycles/integrator/path_trace_work.h
@@ -17,10 +17,10 @@
#pragma once
#include "integrator/pass_accessor.h"
-#include "render/buffers.h"
-#include "render/pass.h"
-#include "util/util_types.h"
-#include "util/util_unique_ptr.h"
+#include "scene/pass.h"
+#include "session/buffers.h"
+#include "util/types.h"
+#include "util/unique_ptr.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/path_trace_work_cpu.cpp b/intern/cycles/integrator/path_trace_work_cpu.cpp
index 1cadcd9ec5c..541a7eca02f 100644
--- a/intern/cycles/integrator/path_trace_work_cpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_cpu.cpp
@@ -19,17 +19,17 @@
#include "device/cpu/kernel.h"
#include "device/device.h"
-#include "kernel/kernel_path_state.h"
+#include "kernel/integrator/path_state.h"
#include "integrator/pass_accessor_cpu.h"
#include "integrator/path_trace_display.h"
-#include "render/buffers.h"
-#include "render/scene.h"
+#include "scene/scene.h"
+#include "session/buffers.h"
-#include "util/util_atomic.h"
-#include "util/util_logging.h"
-#include "util/util_tbb.h"
+#include "util/atomic.h"
+#include "util/log.h"
+#include "util/tbb.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/path_trace_work_cpu.h b/intern/cycles/integrator/path_trace_work_cpu.h
index 91c024f4e4a..6e734690811 100644
--- a/intern/cycles/integrator/path_trace_work_cpu.h
+++ b/intern/cycles/integrator/path_trace_work_cpu.h
@@ -16,14 +16,14 @@
#pragma once
-#include "kernel/integrator/integrator_state.h"
+#include "kernel/integrator/state.h"
#include "device/cpu/kernel_thread_globals.h"
-#include "device/device_queue.h"
+#include "device/queue.h"
#include "integrator/path_trace_work.h"
-#include "util/util_vector.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp
index 36f275e1075..251bec0dc8f 100644
--- a/intern/cycles/integrator/path_trace_work_gpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_gpu.cpp
@@ -20,14 +20,14 @@
#include "device/device.h"
#include "integrator/pass_accessor_gpu.h"
-#include "render/buffers.h"
-#include "render/scene.h"
-#include "util/util_logging.h"
-#include "util/util_string.h"
-#include "util/util_tbb.h"
-#include "util/util_time.h"
+#include "scene/scene.h"
+#include "session/buffers.h"
+#include "util/log.h"
+#include "util/string.h"
+#include "util/tbb.h"
+#include "util/time.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
CCL_NAMESPACE_BEGIN
@@ -53,9 +53,9 @@ static size_t estimate_single_state_size()
* rely on this. */
#define KERNEL_STRUCT_VOLUME_STACK_SIZE 4
-#include "kernel/integrator/integrator_state_template.h"
+#include "kernel/integrator/state_template.h"
-#include "kernel/integrator/integrator_shadow_state_template.h"
+#include "kernel/integrator/shadow_state_template.h"
#undef KERNEL_STRUCT_BEGIN
#undef KERNEL_STRUCT_MEMBER
@@ -120,7 +120,7 @@ void PathTraceWorkGPU::alloc_integrator_soa()
* TODO: store float3 in separate XYZ arrays. */
#define KERNEL_STRUCT_BEGIN(name) for (int array_index = 0;; array_index++) {
#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) \
- if ((kernel_features & feature) && (integrator_state_gpu_.parent_struct.name == nullptr)) { \
+ if ((kernel_features & (feature)) && (integrator_state_gpu_.parent_struct.name == nullptr)) { \
device_only_memory<type> *array = new device_only_memory<type>(device_, \
"integrator_state_" #name); \
array->alloc_to_device(max_num_paths_); \
@@ -128,7 +128,7 @@ void PathTraceWorkGPU::alloc_integrator_soa()
integrator_state_gpu_.parent_struct.name = (type *)array->device_pointer; \
}
#define KERNEL_STRUCT_ARRAY_MEMBER(parent_struct, type, name, feature) \
- if ((kernel_features & feature) && \
+ if ((kernel_features & (feature)) && \
(integrator_state_gpu_.parent_struct[array_index].name == nullptr)) { \
device_only_memory<type> *array = new device_only_memory<type>(device_, \
"integrator_state_" #name); \
@@ -146,9 +146,9 @@ void PathTraceWorkGPU::alloc_integrator_soa()
}
#define KERNEL_STRUCT_VOLUME_STACK_SIZE (integrator_state_soa_volume_stack_size_)
-#include "kernel/integrator/integrator_state_template.h"
+#include "kernel/integrator/state_template.h"
-#include "kernel/integrator/integrator_shadow_state_template.h"
+#include "kernel/integrator/shadow_state_template.h"
#undef KERNEL_STRUCT_BEGIN
#undef KERNEL_STRUCT_MEMBER
@@ -258,7 +258,10 @@ void PathTraceWorkGPU::render_samples(RenderStatistics &statistics,
* schedules work in halves of available number of paths. */
work_tile_scheduler_.set_max_num_path_states(max_num_paths_ / 8);
- work_tile_scheduler_.reset(effective_buffer_params_, start_sample, samples_num);
+ work_tile_scheduler_.reset(effective_buffer_params_,
+ start_sample,
+ samples_num,
+ device_scene_->data.integrator.scrambling_distance);
enqueue_reset();
@@ -1082,7 +1085,7 @@ bool PathTraceWorkGPU::kernel_creates_shadow_paths(DeviceKernel kernel)
bool PathTraceWorkGPU::kernel_creates_ao_paths(DeviceKernel kernel)
{
- return (device_scene_->data.film.pass_ao != PASS_UNUSED) &&
+ return (device_scene_->data.kernel_features & KERNEL_FEATURE_AO) &&
(kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE ||
kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE);
}
diff --git a/intern/cycles/integrator/path_trace_work_gpu.h b/intern/cycles/integrator/path_trace_work_gpu.h
index 8734d2c2852..c5e291e72db 100644
--- a/intern/cycles/integrator/path_trace_work_gpu.h
+++ b/intern/cycles/integrator/path_trace_work_gpu.h
@@ -16,16 +16,16 @@
#pragma once
-#include "kernel/integrator/integrator_state.h"
+#include "kernel/integrator/state.h"
-#include "device/device_graphics_interop.h"
-#include "device/device_memory.h"
-#include "device/device_queue.h"
+#include "device/graphics_interop.h"
+#include "device/memory.h"
+#include "device/queue.h"
#include "integrator/path_trace_work.h"
#include "integrator/work_tile_scheduler.h"
-#include "util/util_vector.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/render_scheduler.cpp b/intern/cycles/integrator/render_scheduler.cpp
index 322d3d5f94c..f776d01ef67 100644
--- a/intern/cycles/integrator/render_scheduler.cpp
+++ b/intern/cycles/integrator/render_scheduler.cpp
@@ -16,11 +16,11 @@
#include "integrator/render_scheduler.h"
-#include "render/session.h"
-#include "render/tile.h"
-#include "util/util_logging.h"
-#include "util/util_math.h"
-#include "util/util_time.h"
+#include "session/session.h"
+#include "session/tile.h"
+#include "util/log.h"
+#include "util/math.h"
+#include "util/time.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/render_scheduler.h b/intern/cycles/integrator/render_scheduler.h
index c4ab15e54ba..d7b7413ae31 100644
--- a/intern/cycles/integrator/render_scheduler.h
+++ b/intern/cycles/integrator/render_scheduler.h
@@ -18,8 +18,8 @@
#include "integrator/adaptive_sampling.h"
#include "integrator/denoiser.h" /* For DenoiseParams. */
-#include "render/buffers.h"
-#include "util/util_string.h"
+#include "session/buffers.h"
+#include "util/string.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/shader_eval.cpp b/intern/cycles/integrator/shader_eval.cpp
index 3de7bb6fd16..42cbf87f254 100644
--- a/intern/cycles/integrator/shader_eval.cpp
+++ b/intern/cycles/integrator/shader_eval.cpp
@@ -17,14 +17,14 @@
#include "integrator/shader_eval.h"
#include "device/device.h"
-#include "device/device_queue.h"
+#include "device/queue.h"
#include "device/cpu/kernel.h"
#include "device/cpu/kernel_thread_globals.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
-#include "util/util_tbb.h"
+#include "util/log.h"
+#include "util/progress.h"
+#include "util/tbb.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/shader_eval.h b/intern/cycles/integrator/shader_eval.h
index 43b6b1bdd47..3ae63b84d04 100644
--- a/intern/cycles/integrator/shader_eval.h
+++ b/intern/cycles/integrator/shader_eval.h
@@ -16,11 +16,11 @@
#pragma once
-#include "device/device_memory.h"
+#include "device/memory.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
-#include "util/util_function.h"
+#include "util/function.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/tile.cpp b/intern/cycles/integrator/tile.cpp
index 3387b7bedf1..4a1558cce09 100644
--- a/intern/cycles/integrator/tile.cpp
+++ b/intern/cycles/integrator/tile.cpp
@@ -16,8 +16,8 @@
#include "integrator/tile.h"
-#include "util/util_logging.h"
-#include "util/util_math.h"
+#include "util/log.h"
+#include "util/math.h"
CCL_NAMESPACE_BEGIN
@@ -48,7 +48,8 @@ ccl_device_inline uint round_up_to_power_of_two(uint x)
TileSize tile_calculate_best_size(const int2 &image_size,
const int num_samples,
- const int max_num_path_states)
+ const int max_num_path_states,
+ const float scrambling_distance)
{
if (max_num_path_states == 1) {
/* Simple case: avoid any calculation, which could cause rounding issues. */
@@ -71,17 +72,24 @@ TileSize tile_calculate_best_size(const int2 &image_size,
* - Keep values a power of two, for more integer fit into the maximum number of paths. */
TileSize tile_size;
-
- /* Calculate tile size as if it is the most possible one to fit an entire range of samples.
- * The idea here is to keep tiles as small as possible, and keep device occupied by scheduling
- * multiple tiles with the same coordinates rendering different samples. */
const int num_path_states_per_sample = max_num_path_states / num_samples;
- if (num_path_states_per_sample != 0) {
- tile_size.width = round_down_to_power_of_two(lround(sqrt(num_path_states_per_sample)));
- tile_size.height = tile_size.width;
+ if (scrambling_distance < 0.9f) {
+ /* Prefer large tiles for scrambling distance, bounded by max num path states. */
+ tile_size.width = min(image_size.x, max_num_path_states);
+ tile_size.height = min(image_size.y, max(max_num_path_states / tile_size.width, 1));
}
else {
- tile_size.width = tile_size.height = 1;
+ /* Calculate tile size as if it is the most possible one to fit an entire range of samples.
+ * The idea here is to keep tiles as small as possible, and keep device occupied by scheduling
+ * multiple tiles with the same coordinates rendering different samples. */
+
+ if (num_path_states_per_sample != 0) {
+ tile_size.width = round_down_to_power_of_two(lround(sqrt(num_path_states_per_sample)));
+ tile_size.height = tile_size.width;
+ }
+ else {
+ tile_size.width = tile_size.height = 1;
+ }
}
if (num_samples == 1) {
@@ -93,7 +101,7 @@ TileSize tile_calculate_best_size(const int2 &image_size,
tile_size.num_samples = min(round_up_to_power_of_two(lround(sqrt(num_samples / 2))),
static_cast<uint>(num_samples));
- const int tile_area = tile_size.width / tile_size.height;
+ const int tile_area = tile_size.width * tile_size.height;
tile_size.num_samples = min(tile_size.num_samples, max_num_path_states / tile_area);
}
diff --git a/intern/cycles/integrator/tile.h b/intern/cycles/integrator/tile.h
index d0824843ddb..61f7d736115 100644
--- a/intern/cycles/integrator/tile.h
+++ b/intern/cycles/integrator/tile.h
@@ -18,7 +18,7 @@
#include <ostream>
-#include "util/util_types.h"
+#include "util/types.h"
CCL_NAMESPACE_BEGIN
@@ -51,6 +51,7 @@ std::ostream &operator<<(std::ostream &os, const TileSize &tile_size);
* possible, and have as many threads active for every tile as possible. */
TileSize tile_calculate_best_size(const int2 &image_size,
const int num_samples,
- const int max_num_path_states);
+ const int max_num_path_states,
+ const float scrambling_distance);
CCL_NAMESPACE_END
diff --git a/intern/cycles/integrator/work_balancer.cpp b/intern/cycles/integrator/work_balancer.cpp
index 9f96fe3632b..4c6fa341f35 100644
--- a/intern/cycles/integrator/work_balancer.cpp
+++ b/intern/cycles/integrator/work_balancer.cpp
@@ -16,9 +16,9 @@
#include "integrator/work_balancer.h"
-#include "util/util_math.h"
+#include "util/math.h"
-#include "util/util_logging.h"
+#include "util/log.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/work_balancer.h b/intern/cycles/integrator/work_balancer.h
index fc5e561845e..86ff9335f91 100644
--- a/intern/cycles/integrator/work_balancer.h
+++ b/intern/cycles/integrator/work_balancer.h
@@ -16,7 +16,7 @@
#pragma once
-#include "util/util_vector.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/integrator/work_tile_scheduler.cpp b/intern/cycles/integrator/work_tile_scheduler.cpp
index 234b1fae915..2d1ac07db7f 100644
--- a/intern/cycles/integrator/work_tile_scheduler.cpp
+++ b/intern/cycles/integrator/work_tile_scheduler.cpp
@@ -16,11 +16,11 @@
#include "integrator/work_tile_scheduler.h"
-#include "device/device_queue.h"
+#include "device/queue.h"
#include "integrator/tile.h"
-#include "render/buffers.h"
-#include "util/util_atomic.h"
-#include "util/util_logging.h"
+#include "session/buffers.h"
+#include "util/atomic.h"
+#include "util/log.h"
CCL_NAMESPACE_BEGIN
@@ -33,13 +33,17 @@ void WorkTileScheduler::set_max_num_path_states(int max_num_path_states)
max_num_path_states_ = max_num_path_states;
}
-void WorkTileScheduler::reset(const BufferParams &buffer_params, int sample_start, int samples_num)
+void WorkTileScheduler::reset(const BufferParams &buffer_params,
+ int sample_start,
+ int samples_num,
+ float scrambling_distance)
{
/* Image buffer parameters. */
image_full_offset_px_.x = buffer_params.full_x;
image_full_offset_px_.y = buffer_params.full_y;
image_size_px_ = make_int2(buffer_params.width, buffer_params.height);
+ scrambling_distance_ = scrambling_distance;
offset_ = buffer_params.offset;
stride_ = buffer_params.stride;
@@ -54,7 +58,8 @@ void WorkTileScheduler::reset(const BufferParams &buffer_params, int sample_star
void WorkTileScheduler::reset_scheduler_state()
{
- tile_size_ = tile_calculate_best_size(image_size_px_, samples_num_, max_num_path_states_);
+ tile_size_ = tile_calculate_best_size(
+ image_size_px_, samples_num_, max_num_path_states_, scrambling_distance_);
VLOG(3) << "Will schedule tiles of size " << tile_size_;
diff --git a/intern/cycles/integrator/work_tile_scheduler.h b/intern/cycles/integrator/work_tile_scheduler.h
index 85f11b601c7..d9fa7e84431 100644
--- a/intern/cycles/integrator/work_tile_scheduler.h
+++ b/intern/cycles/integrator/work_tile_scheduler.h
@@ -17,7 +17,7 @@
#pragma once
#include "integrator/tile.h"
-#include "util/util_types.h"
+#include "util/types.h"
CCL_NAMESPACE_BEGIN
@@ -38,7 +38,10 @@ class WorkTileScheduler {
void set_max_num_path_states(int max_num_path_states);
/* Scheduling will happen for pixels within a big tile denotes by its parameters. */
- void reset(const BufferParams &buffer_params, int sample_start, int samples_num);
+ void reset(const BufferParams &buffer_params,
+ int sample_start,
+ int samples_num,
+ float scrambling_distance);
/* Get work for a device.
* Returns true if there is still work to be done and initialize the work tile to all
@@ -68,6 +71,9 @@ class WorkTileScheduler {
* Will be passed over to the KernelWorkTile. */
int offset_, stride_;
+ /* Scrambling Distance requires adapted tile size */
+ float scrambling_distance_;
+
/* Start sample of index and number of samples which are to be rendered.
* The scheduler will cover samples range of [start, start + num] over the entire image
* (splitting into a smaller work tiles). */
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 6d5d386ddea..29ff69df864 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -22,7 +22,7 @@ set(INC_SYS
)
-set(SRC_DEVICE_CPU
+set(SRC_KERNEL_DEVICE_CPU
device/cpu/kernel.cpp
device/cpu/kernel_sse2.cpp
device/cpu/kernel_sse3.cpp
@@ -31,63 +31,20 @@ set(SRC_DEVICE_CPU
device/cpu/kernel_avx2.cpp
)
-set(SRC_DEVICE_CUDA
+set(SRC_KERNEL_DEVICE_CUDA
device/cuda/kernel.cu
)
-set(SRC_DEVICE_HIP
+set(SRC_KERNEL_DEVICE_HIP
device/hip/kernel.cpp
)
-set(SRC_DEVICE_OPTIX
+set(SRC_KERNEL_DEVICE_OPTIX
device/optix/kernel.cu
device/optix/kernel_shader_raytrace.cu
)
-set(SRC_BVH_HEADERS
- bvh/bvh.h
- bvh/bvh_nodes.h
- bvh/bvh_shadow_all.h
- bvh/bvh_local.h
- bvh/bvh_traversal.h
- bvh/bvh_types.h
- bvh/bvh_util.h
- bvh/bvh_volume.h
- bvh/bvh_volume_all.h
- bvh/bvh_embree.h
-)
-
-set(SRC_HEADERS
- kernel_accumulate.h
- kernel_adaptive_sampling.h
- kernel_bake.h
- kernel_camera.h
- kernel_color.h
- kernel_differential.h
- kernel_emission.h
- kernel_film.h
- kernel_id_passes.h
- kernel_jitter.h
- kernel_light.h
- kernel_light_background.h
- kernel_light_common.h
- kernel_lookup_table.h
- kernel_math.h
- kernel_montecarlo.h
- kernel_passes.h
- kernel_path_state.h
- kernel_profiling.h
- kernel_projection.h
- kernel_random.h
- kernel_shader.h
- kernel_shadow_catcher.h
- kernel_textures.h
- kernel_types.h
- kernel_work_stealing.h
- kernel_write_passes.h
-)
-
-set(SRC_DEVICE_CPU_HEADERS
+set(SRC_KERNEL_DEVICE_CPU_HEADERS
device/cpu/compat.h
device/cpu/image.h
device/cpu/globals.h
@@ -95,33 +52,34 @@ set(SRC_DEVICE_CPU_HEADERS
device/cpu/kernel_arch.h
device/cpu/kernel_arch_impl.h
)
-set(SRC_DEVICE_GPU_HEADERS
+set(SRC_KERNEL_DEVICE_GPU_HEADERS
device/gpu/image.h
device/gpu/kernel.h
device/gpu/parallel_active_index.h
device/gpu/parallel_prefix_sum.h
device/gpu/parallel_reduce.h
device/gpu/parallel_sorted_index.h
+ device/gpu/work_stealing.h
)
-set(SRC_DEVICE_CUDA_HEADERS
+set(SRC_KERNEL_DEVICE_CUDA_HEADERS
device/cuda/compat.h
device/cuda/config.h
device/cuda/globals.h
)
-set(SRC_DEVICE_HIP_HEADERS
+set(SRC_KERNEL_DEVICE_HIP_HEADERS
device/hip/compat.h
device/hip/config.h
device/hip/globals.h
)
-set(SRC_DEVICE_OPTIX_HEADERS
+set(SRC_KERNEL_DEVICE_OPTIX_HEADERS
device/optix/compat.h
device/optix/globals.h
)
-set(SRC_CLOSURE_HEADERS
+set(SRC_KERNEL_CLOSURE_HEADERS
closure/alloc.h
closure/bsdf.h
closure/bsdf_ashikhmin_velvet.h
@@ -147,157 +105,233 @@ set(SRC_CLOSURE_HEADERS
closure/bsdf_hair_principled.h
)
-set(SRC_SVM_HEADERS
+set(SRC_KERNEL_SVM_HEADERS
svm/svm.h
- svm/svm_ao.h
- svm/svm_aov.h
- svm/svm_attribute.h
- svm/svm_bevel.h
- svm/svm_blackbody.h
- svm/svm_bump.h
- svm/svm_camera.h
- svm/svm_clamp.h
- svm/svm_closure.h
- svm/svm_convert.h
- svm/svm_checker.h
- svm/svm_color_util.h
- svm/svm_brick.h
- svm/svm_displace.h
- svm/svm_fresnel.h
- svm/svm_wireframe.h
- svm/svm_wavelength.h
- svm/svm_gamma.h
- svm/svm_brightness.h
- svm/svm_geometry.h
- svm/svm_gradient.h
- svm/svm_hsv.h
- svm/svm_ies.h
- svm/svm_image.h
- svm/svm_invert.h
- svm/svm_light_path.h
- svm/svm_magic.h
- svm/svm_map_range.h
- svm/svm_mapping.h
- svm/svm_mapping_util.h
- svm/svm_math.h
- svm/svm_math_util.h
- svm/svm_mix.h
- svm/svm_musgrave.h
- svm/svm_noise.h
- svm/svm_noisetex.h
- svm/svm_normal.h
- svm/svm_ramp.h
- svm/svm_ramp_util.h
- svm/svm_sepcomb_hsv.h
- svm/svm_sepcomb_vector.h
- svm/svm_sky.h
- svm/svm_tex_coord.h
- svm/svm_fractal_noise.h
- svm/svm_types.h
- svm/svm_value.h
- svm/svm_vector_rotate.h
- svm/svm_vector_transform.h
- svm/svm_voronoi.h
- svm/svm_voxel.h
- svm/svm_wave.h
- svm/svm_white_noise.h
- svm/svm_vertex_color.h
+ svm/ao.h
+ svm/aov.h
+ svm/attribute.h
+ svm/bevel.h
+ svm/blackbody.h
+ svm/bump.h
+ svm/camera.h
+ svm/clamp.h
+ svm/closure.h
+ svm/convert.h
+ svm/checker.h
+ svm/color_util.h
+ svm/brick.h
+ svm/displace.h
+ svm/fresnel.h
+ svm/wireframe.h
+ svm/wavelength.h
+ svm/gamma.h
+ svm/brightness.h
+ svm/geometry.h
+ svm/gradient.h
+ svm/hsv.h
+ svm/ies.h
+ svm/image.h
+ svm/invert.h
+ svm/light_path.h
+ svm/magic.h
+ svm/map_range.h
+ svm/mapping.h
+ svm/mapping_util.h
+ svm/math.h
+ svm/math_util.h
+ svm/mix.h
+ svm/musgrave.h
+ svm/noise.h
+ svm/noisetex.h
+ svm/normal.h
+ svm/ramp.h
+ svm/ramp_util.h
+ svm/sepcomb_hsv.h
+ svm/sepcomb_vector.h
+ svm/sky.h
+ svm/tex_coord.h
+ svm/fractal_noise.h
+ svm/types.h
+ svm/value.h
+ svm/vector_rotate.h
+ svm/vector_transform.h
+ svm/voronoi.h
+ svm/voxel.h
+ svm/wave.h
+ svm/white_noise.h
+ svm/vertex_color.h
)
-set(SRC_GEOM_HEADERS
+set(SRC_KERNEL_GEOM_HEADERS
geom/geom.h
- geom/geom_attribute.h
- geom/geom_curve.h
- geom/geom_curve_intersect.h
- geom/geom_motion_curve.h
- geom/geom_motion_triangle.h
- geom/geom_motion_triangle_intersect.h
- geom/geom_motion_triangle_shader.h
- geom/geom_object.h
- geom/geom_patch.h
- geom/geom_primitive.h
- geom/geom_shader_data.h
- geom/geom_subd_triangle.h
- geom/geom_triangle.h
- geom/geom_triangle_intersect.h
- geom/geom_volume.h
+ geom/attribute.h
+ geom/curve.h
+ geom/curve_intersect.h
+ geom/motion_curve.h
+ geom/motion_triangle.h
+ geom/motion_triangle_intersect.h
+ geom/motion_triangle_shader.h
+ geom/object.h
+ geom/patch.h
+ geom/primitive.h
+ geom/shader_data.h
+ geom/subd_triangle.h
+ geom/triangle.h
+ geom/triangle_intersect.h
+ geom/volume.h
+)
+
+set(SRC_KERNEL_BAKE_HEADERS
+ bake/bake.h
+)
+
+set(SRC_KERNEL_BVH_HEADERS
+ bvh/bvh.h
+ bvh/nodes.h
+ bvh/shadow_all.h
+ bvh/local.h
+ bvh/traversal.h
+ bvh/types.h
+ bvh/util.h
+ bvh/volume.h
+ bvh/volume_all.h
+ bvh/embree.h
+)
+
+set(SRC_KERNEL_CAMERA_HEADERS
+ camera/camera.h
+ camera/projection.h
+)
+
+set(SRC_KERNEL_FILM_HEADERS
+ film/accumulate.h
+ film/adaptive_sampling.h
+ film/id_passes.h
+ film/passes.h
+ film/read.h
+ film/write_passes.h
+)
+
+set(SRC_KERNEL_INTEGRATOR_HEADERS
+ integrator/init_from_bake.h
+ integrator/init_from_camera.h
+ integrator/intersect_closest.h
+ integrator/intersect_shadow.h
+ integrator/intersect_subsurface.h
+ integrator/intersect_volume_stack.h
+ integrator/megakernel.h
+ integrator/path_state.h
+ integrator/shade_background.h
+ integrator/shade_light.h
+ integrator/shader_eval.h
+ integrator/shade_shadow.h
+ integrator/shade_surface.h
+ integrator/shade_volume.h
+ integrator/shadow_catcher.h
+ integrator/shadow_state_template.h
+ integrator/state_flow.h
+ integrator/state.h
+ integrator/state_template.h
+ integrator/state_util.h
+ integrator/subsurface_disk.h
+ integrator/subsurface.h
+ integrator/subsurface_random_walk.h
+ integrator/volume_stack.h
+)
+
+set(SRC_KERNEL_LIGHT_HEADERS
+ light/light.h
+ light/background.h
+ light/common.h
+ light/sample.h
+)
+
+set(SRC_KERNEL_SAMPLE_HEADERS
+ sample/jitter.h
+ sample/lcg.h
+ sample/mapping.h
+ sample/mis.h
+ sample/pattern.h
+)
+
+set(SRC_KERNEL_UTIL_HEADERS
+ util/color.h
+ util/differential.h
+ util/lookup_table.h
+ util/profiling.h
+)
+
+set(SRC_KERNEL_TYPES_HEADERS
+ textures.h
+ types.h
)
-set(SRC_INTEGRATOR_HEADERS
- integrator/integrator_init_from_bake.h
- integrator/integrator_init_from_camera.h
- integrator/integrator_intersect_closest.h
- integrator/integrator_intersect_shadow.h
- integrator/integrator_intersect_subsurface.h
- integrator/integrator_intersect_volume_stack.h
- integrator/integrator_megakernel.h
- integrator/integrator_shade_background.h
- integrator/integrator_shade_light.h
- integrator/integrator_shade_shadow.h
- integrator/integrator_shade_surface.h
- integrator/integrator_shade_volume.h
- integrator/integrator_shadow_state_template.h
- integrator/integrator_state.h
- integrator/integrator_state_flow.h
- integrator/integrator_state_template.h
- integrator/integrator_state_util.h
- integrator/integrator_subsurface.h
- integrator/integrator_subsurface_disk.h
- integrator/integrator_subsurface_random_walk.h
- integrator/integrator_volume_stack.h
+set(SRC_KERNEL_HEADERS
+ ${SRC_KERNEL_BAKE_HEADERS}
+ ${SRC_KERNEL_BVH_HEADERS}
+ ${SRC_KERNEL_CAMERA_HEADERS}
+ ${SRC_KERNEL_CLOSURE_HEADERS}
+ ${SRC_KERNEL_FILM_HEADERS}
+ ${SRC_KERNEL_GEOM_HEADERS}
+ ${SRC_KERNEL_INTEGRATOR_HEADERS}
+ ${SRC_KERNEL_LIGHT_HEADERS}
+ ${SRC_KERNEL_SAMPLE_HEADERS}
+ ${SRC_KERNEL_SVM_HEADERS}
+ ${SRC_KERNEL_TYPES_HEADERS}
+ ${SRC_KERNEL_UTIL_HEADERS}
)
set(SRC_UTIL_HEADERS
- ../util/util_atomic.h
- ../util/util_color.h
- ../util/util_defines.h
- ../util/util_half.h
- ../util/util_hash.h
- ../util/util_math.h
- ../util/util_math_fast.h
- ../util/util_math_intersect.h
- ../util/util_math_float2.h
- ../util/util_math_float3.h
- ../util/util_math_float4.h
- ../util/util_math_int2.h
- ../util/util_math_int3.h
- ../util/util_math_int4.h
- ../util/util_math_matrix.h
- ../util/util_projection.h
- ../util/util_rect.h
- ../util/util_static_assert.h
- ../util/util_transform.h
- ../util/util_texture.h
- ../util/util_types.h
- ../util/util_types_float2.h
- ../util/util_types_float2_impl.h
- ../util/util_types_float3.h
- ../util/util_types_float3_impl.h
- ../util/util_types_float4.h
- ../util/util_types_float4_impl.h
- ../util/util_types_float8.h
- ../util/util_types_float8_impl.h
- ../util/util_types_int2.h
- ../util/util_types_int2_impl.h
- ../util/util_types_int3.h
- ../util/util_types_int3_impl.h
- ../util/util_types_int4.h
- ../util/util_types_int4_impl.h
- ../util/util_types_uchar2.h
- ../util/util_types_uchar2_impl.h
- ../util/util_types_uchar3.h
- ../util/util_types_uchar3_impl.h
- ../util/util_types_uchar4.h
- ../util/util_types_uchar4_impl.h
- ../util/util_types_uint2.h
- ../util/util_types_uint2_impl.h
- ../util/util_types_uint3.h
- ../util/util_types_uint3_impl.h
- ../util/util_types_uint4.h
- ../util/util_types_uint4_impl.h
- ../util/util_types_ushort4.h
- ../util/util_types_vector3.h
- ../util/util_types_vector3_impl.h
+ ../util/atomic.h
+ ../util/color.h
+ ../util/defines.h
+ ../util/half.h
+ ../util/hash.h
+ ../util/math.h
+ ../util/math_fast.h
+ ../util/math_intersect.h
+ ../util/math_float2.h
+ ../util/math_float3.h
+ ../util/math_float4.h
+ ../util/math_int2.h
+ ../util/math_int3.h
+ ../util/math_int4.h
+ ../util/math_matrix.h
+ ../util/projection.h
+ ../util/rect.h
+ ../util/static_assert.h
+ ../util/transform.h
+ ../util/texture.h
+ ../util/types.h
+ ../util/types_float2.h
+ ../util/types_float2_impl.h
+ ../util/types_float3.h
+ ../util/types_float3_impl.h
+ ../util/types_float4.h
+ ../util/types_float4_impl.h
+ ../util/types_float8.h
+ ../util/types_float8_impl.h
+ ../util/types_int2.h
+ ../util/types_int2_impl.h
+ ../util/types_int3.h
+ ../util/types_int3_impl.h
+ ../util/types_int4.h
+ ../util/types_int4_impl.h
+ ../util/types_uchar2.h
+ ../util/types_uchar2_impl.h
+ ../util/types_uchar3.h
+ ../util/types_uchar3_impl.h
+ ../util/types_uchar4.h
+ ../util/types_uchar4_impl.h
+ ../util/types_uint2.h
+ ../util/types_uint2_impl.h
+ ../util/types_uint3.h
+ ../util/types_uint3_impl.h
+ ../util/types_uint4.h
+ ../util/types_uint4_impl.h
+ ../util/types_ushort4.h
+ ../util/types_vector3.h
+ ../util/types_vector3_impl.h
)
set(LIB
@@ -331,14 +365,9 @@ if(WITH_CYCLES_CUDA_BINARIES)
# build for each arch
set(cuda_sources device/cuda/kernel.cu
- ${SRC_HEADERS}
- ${SRC_DEVICE_GPU_HEADERS}
- ${SRC_DEVICE_CUDA_HEADERS}
- ${SRC_BVH_HEADERS}
- ${SRC_SVM_HEADERS}
- ${SRC_GEOM_HEADERS}
- ${SRC_INTEGRATOR_HEADERS}
- ${SRC_CLOSURE_HEADERS}
+ ${SRC_KERNEL_HEADERS}
+ ${SRC_KERNEL_DEVICE_GPU_HEADERS}
+ ${SRC_KERNEL_DEVICE_CUDA_HEADERS}
${SRC_UTIL_HEADERS}
)
set(cuda_cubins)
@@ -489,13 +518,9 @@ endif()
if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP)
# build for each arch
set(hip_sources device/hip/kernel.cpp
- ${SRC_HEADERS}
- ${SRC_DEVICE_HIP_HEADERS}
- ${SRC_BVH_HEADERS}
- ${SRC_SVM_HEADERS}
- ${SRC_GEOM_HEADERS}
- ${SRC_INTEGRATOR_HEADERS}
- ${SRC_CLOSURE_HEADERS}
+ ${SRC_KERNEL_HEADERS}
+ ${SRC_KERNEL_DEVICE_GPU_HEADERS}
+ ${SRC_KERNEL_DEVICE_HIP_HEADERS}
${SRC_UTIL_HEADERS}
)
set(hip_fatbins)
@@ -597,15 +622,10 @@ if(WITH_CYCLES_DEVICE_OPTIX AND WITH_CYCLES_CUDA_BINARIES)
OUTPUT ${output}
DEPENDS
${input}
- ${SRC_HEADERS}
- ${SRC_DEVICE_GPU_HEADERS}
- ${SRC_DEVICE_CUDA_HEADERS}
- ${SRC_DEVICE_OPTIX_HEADERS}
- ${SRC_BVH_HEADERS}
- ${SRC_SVM_HEADERS}
- ${SRC_GEOM_HEADERS}
- ${SRC_INTEGRATOR_HEADERS}
- ${SRC_CLOSURE_HEADERS}
+ ${SRC_KERNEL_HEADERS}
+ ${SRC_KERNEL_DEVICE_GPU_HEADERS}
+ ${SRC_KERNEL_DEVICE_CUDA_HEADERS}
+ ${SRC_KERNEL_DEVICE_OPTIX_HEADERS}
${SRC_UTIL_HEADERS}
COMMAND ${CUBIN_CC_ENV}
"$<TARGET_FILE:cycles_cubin_cc>"
@@ -622,15 +642,10 @@ if(WITH_CYCLES_DEVICE_OPTIX AND WITH_CYCLES_CUDA_BINARIES)
${output}
DEPENDS
${input}
- ${SRC_HEADERS}
- ${SRC_DEVICE_GPU_HEADERS}
- ${SRC_DEVICE_CUDA_HEADERS}
- ${SRC_DEVICE_OPTIX_HEADERS}
- ${SRC_BVH_HEADERS}
- ${SRC_SVM_HEADERS}
- ${SRC_GEOM_HEADERS}
- ${SRC_INTEGRATOR_HEADERS}
- ${SRC_CLOSURE_HEADERS}
+ ${SRC_KERNEL_HEADERS}
+ ${SRC_KERNEL_DEVICE_GPU_HEADERS}
+ ${SRC_KERNEL_DEVICE_CUDA_HEADERS}
+ ${SRC_KERNEL_DEVICE_OPTIX_HEADERS}
${SRC_UTIL_HEADERS}
COMMAND
${CUDA_NVCC_EXECUTABLE}
@@ -666,7 +681,7 @@ if(WITH_CYCLES_OSL)
cycles_kernel_osl
)
add_subdirectory(osl)
- add_subdirectory(shaders)
+ add_subdirectory(osl/shaders)
endif()
# CPU module
@@ -704,34 +719,35 @@ if(CXX_HAS_AVX2)
endif()
cycles_add_library(cycles_kernel "${LIB}"
- ${SRC_DEVICE_CPU}
- ${SRC_DEVICE_CUDA}
- ${SRC_DEVICE_HIP}
- ${SRC_DEVICE_OPTIX}
- ${SRC_HEADERS}
- ${SRC_DEVICE_CPU_HEADERS}
- ${SRC_DEVICE_GPU_HEADERS}
- ${SRC_DEVICE_CUDA_HEADERS}
- ${SRC_DEVICE_HIP_HEADERS}
- ${SRC_DEVICE_OPTIX_HEADERS}
- ${SRC_BVH_HEADERS}
- ${SRC_CLOSURE_HEADERS}
- ${SRC_SVM_HEADERS}
- ${SRC_GEOM_HEADERS}
- ${SRC_INTEGRATOR_HEADERS}
+ ${SRC_KERNEL_DEVICE_CPU}
+ ${SRC_KERNEL_DEVICE_CUDA}
+ ${SRC_KERNEL_DEVICE_HIP}
+ ${SRC_KERNEL_DEVICE_OPTIX}
+ ${SRC_KERNEL_HEADERS}
+ ${SRC_KERNEL_DEVICE_CPU_HEADERS}
+ ${SRC_KERNEL_DEVICE_GPU_HEADERS}
+ ${SRC_KERNEL_DEVICE_CUDA_HEADERS}
+ ${SRC_KERNEL_DEVICE_HIP_HEADERS}
+ ${SRC_KERNEL_DEVICE_OPTIX_HEADERS}
)
-source_group("bvh" FILES ${SRC_BVH_HEADERS})
-source_group("closure" FILES ${SRC_CLOSURE_HEADERS})
-source_group("geom" FILES ${SRC_GEOM_HEADERS})
-source_group("integrator" FILES ${SRC_INTEGRATOR_HEADERS})
-source_group("kernel" FILES ${SRC_HEADERS})
-source_group("device\\cpu" FILES ${SRC_DEVICE_CPU} ${SRC_DEVICE_CPU_HEADERS})
-source_group("device\\hip" FILES ${SRC_DEVICE_HIP} ${SRC_DEVICE_HIP_HEADERS})
-source_group("device\\gpu" FILES ${SRC_DEVICE_GPU_HEADERS})
-source_group("device\\cuda" FILES ${SRC_DEVICE_CUDA} ${SRC_DEVICE_CUDA_HEADERS})
-source_group("device\\optix" FILES ${SRC_DEVICE_OPTIX} ${SRC_DEVICE_OPTIX_HEADERS})
-source_group("svm" FILES ${SRC_SVM_HEADERS})
+source_group("bake" FILES ${SRC_KERNEL_BAKE_HEADERS})
+source_group("bvh" FILES ${SRC_KERNEL_BVH_HEADERS})
+source_group("camera" FILES ${SRC_KERNEL_CAMERA_HEADERS})
+source_group("closure" FILES ${SRC_KERNEL_CLOSURE_HEADERS})
+source_group("device\\cpu" FILES ${SRC_KERNEL_DEVICE_CPU} ${SRC_KERNEL_DEVICE_CPU_HEADERS})
+source_group("device\\cuda" FILES ${SRC_KERNEL_DEVICE_CUDA} ${SRC_KERNEL_DEVICE_CUDA_HEADERS})
+source_group("device\\gpu" FILES ${SRC_KERNEL_DEVICE_GPU_HEADERS})
+source_group("device\\hip" FILES ${SRC_KERNEL_DEVICE_HIP} ${SRC_KERNEL_DEVICE_HIP_HEADERS})
+source_group("device\\optix" FILES ${SRC_KERNEL_DEVICE_OPTIX} ${SRC_KERNEL_DEVICE_OPTIX_HEADERS})
+source_group("film" FILES ${SRC_KERNEL_FILM_HEADERS})
+source_group("geom" FILES ${SRC_KERNEL_GEOM_HEADERS})
+source_group("integrator" FILES ${SRC_KERNEL_INTEGRATOR_HEADERS})
+source_group("kernel" FILES ${SRC_KERNEL_TYPES_HEADERS})
+source_group("light" FILES ${SRC_KERNEL_LIGHT_HEADERS})
+source_group("sample" FILES ${SRC_KERNEL_SAMPLE_HEADERS})
+source_group("svm" FILES ${SRC_KERNEL_SVM_HEADERS})
+source_group("util" FILES ${SRC_KERNEL_UTIL_HEADERS})
if(WITH_CYCLES_CUDA)
add_dependencies(cycles_kernel cycles_kernel_cuda)
@@ -745,19 +761,25 @@ endif()
# Install kernel source for runtime compilation
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_DEVICE_CUDA}" ${CYCLES_INSTALL_PATH}/source/kernel/device/cuda)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_DEVICE_HIP}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hip)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_DEVICE_OPTIX}" ${CYCLES_INSTALL_PATH}/source/kernel/device/optix)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_DEVICE_GPU_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/gpu)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_DEVICE_CUDA_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/cuda)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_DEVICE_HIP_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hip)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_DEVICE_OPTIX_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/optix)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_BVH_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/bvh)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/closure)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SVM_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/svm)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_GEOM_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/geom)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_INTEGRATOR_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/integrator)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_BAKE_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/bake)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_BVH_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/bvh)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_CAMERA_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/camera)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/closure)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_CUDA}" ${CYCLES_INSTALL_PATH}/source/kernel/device/cuda)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_CUDA_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/cuda)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_GPU_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/gpu)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_HIP}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hip)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_HIP_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hip)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_OPTIX}" ${CYCLES_INSTALL_PATH}/source/kernel/device/optix)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_OPTIX_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/optix)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_FILM_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/film)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_GEOM_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/geom)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_INTEGRATOR_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/integrator)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_LIGHT_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/light)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_SAMPLE_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/sample)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_SVM_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/svm)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_TYPES_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_UTIL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/util)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_UTIL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/util)
if(WITH_NANOVDB)
diff --git a/intern/cycles/kernel/bake/bake.h b/intern/cycles/kernel/bake/bake.h
new file mode 100644
index 00000000000..0a78a635d75
--- /dev/null
+++ b/intern/cycles/kernel/bake/bake.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/camera/projection.h"
+#include "kernel/integrator/shader_eval.h"
+
+#include "kernel/geom/geom.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device void kernel_displace_evaluate(KernelGlobals kg,
+ ccl_global const KernelShaderEvalInput *input,
+ ccl_global float *output,
+ const int offset)
+{
+ /* Setup shader data. */
+ const KernelShaderEvalInput in = input[offset];
+
+ ShaderData sd;
+ shader_setup_from_displace(kg, &sd, in.object, in.prim, in.u, in.v);
+
+ /* Evaluate displacement shader. */
+ const float3 P = sd.P;
+ shader_eval_displacement(kg, INTEGRATOR_STATE_NULL, &sd);
+ float3 D = sd.P - P;
+
+ object_inverse_dir_transform(kg, &sd, &D);
+
+#ifdef __KERNEL_DEBUG_NAN__
+ if (!isfinite3_safe(D)) {
+ kernel_assert(!"Cycles displacement with non-finite value detected");
+ }
+#endif
+
+ /* Ensure finite displacement, preventing BVH from becoming degenerate and avoiding possible
+ * traversal issues caused by non-finite math. */
+ D = ensure_finite3(D);
+
+ /* Write output. */
+ output[offset * 3 + 0] += D.x;
+ output[offset * 3 + 1] += D.y;
+ output[offset * 3 + 2] += D.z;
+}
+
+ccl_device void kernel_background_evaluate(KernelGlobals kg,
+ ccl_global const KernelShaderEvalInput *input,
+ ccl_global float *output,
+ const int offset)
+{
+ /* Setup ray */
+ const KernelShaderEvalInput in = input[offset];
+ const float3 ray_P = zero_float3();
+ const float3 ray_D = equirectangular_to_direction(in.u, in.v);
+ const float ray_time = 0.5f;
+
+ /* Setup shader data. */
+ ShaderData sd;
+ shader_setup_from_background(kg, &sd, ray_P, ray_D, ray_time);
+
+ /* Evaluate shader.
+ * This is being evaluated for all BSDFs, so path flag does not contain a specific type. */
+ const uint32_t path_flag = PATH_RAY_EMISSION;
+ shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT &
+ ~(KERNEL_FEATURE_NODE_RAYTRACE | KERNEL_FEATURE_NODE_LIGHT_PATH)>(
+ kg, INTEGRATOR_STATE_NULL, &sd, NULL, path_flag);
+ float3 color = shader_background_eval(&sd);
+
+#ifdef __KERNEL_DEBUG_NAN__
+ if (!isfinite3_safe(color)) {
+ kernel_assert(!"Cycles background with non-finite value detected");
+ }
+#endif
+
+ /* Ensure finite color, avoiding possible numerical instabilities in the path tracing kernels. */
+ color = ensure_finite3(color);
+
+ /* Write output. */
+ output[offset * 3 + 0] += color.x;
+ output[offset * 3 + 1] += color.y;
+ output[offset * 3 + 2] += color.z;
+}
+
+ccl_device void kernel_curve_shadow_transparency_evaluate(
+ KernelGlobals kg,
+ ccl_global const KernelShaderEvalInput *input,
+ ccl_global float *output,
+ const int offset)
+{
+ /* Setup shader data. */
+ const KernelShaderEvalInput in = input[offset];
+
+ ShaderData sd;
+ shader_setup_from_curve(kg, &sd, in.object, in.prim, __float_as_int(in.v), in.u);
+
+ /* Evaluate transparency. */
+ shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW &
+ ~(KERNEL_FEATURE_NODE_RAYTRACE | KERNEL_FEATURE_NODE_LIGHT_PATH)>(
+ kg, INTEGRATOR_STATE_NULL, &sd, NULL, PATH_RAY_SHADOW);
+
+ /* Write output. */
+ output[offset] = clamp(average(shader_bsdf_transparency(kg, &sd)), 0.0f, 1.0f);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h
index 813ac15711e..0e083812355 100644
--- a/intern/cycles/kernel/bvh/bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -28,13 +28,13 @@
#pragma once
#ifdef __EMBREE__
-# include "kernel/bvh/bvh_embree.h"
+# include "kernel/bvh/embree.h"
#endif
-#include "kernel/bvh/bvh_types.h"
-#include "kernel/bvh/bvh_util.h"
+#include "kernel/bvh/types.h"
+#include "kernel/bvh/util.h"
-#include "kernel/integrator/integrator_state_util.h"
+#include "kernel/integrator/state_util.h"
CCL_NAMESPACE_BEGIN
@@ -42,28 +42,28 @@ CCL_NAMESPACE_BEGIN
/* Regular BVH traversal */
-# include "kernel/bvh/bvh_nodes.h"
+# include "kernel/bvh/nodes.h"
# define BVH_FUNCTION_NAME bvh_intersect
# define BVH_FUNCTION_FEATURES 0
-# include "kernel/bvh/bvh_traversal.h"
+# include "kernel/bvh/traversal.h"
# if defined(__HAIR__)
# define BVH_FUNCTION_NAME bvh_intersect_hair
# define BVH_FUNCTION_FEATURES BVH_HAIR
-# include "kernel/bvh/bvh_traversal.h"
+# include "kernel/bvh/traversal.h"
# endif
# if defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_motion
# define BVH_FUNCTION_FEATURES BVH_MOTION
-# include "kernel/bvh/bvh_traversal.h"
+# include "kernel/bvh/traversal.h"
# endif
# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_hair_motion
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION
-# include "kernel/bvh/bvh_traversal.h"
+# include "kernel/bvh/traversal.h"
# endif
/* Subsurface scattering BVH traversal */
@@ -71,12 +71,12 @@ CCL_NAMESPACE_BEGIN
# if defined(__BVH_LOCAL__)
# define BVH_FUNCTION_NAME bvh_intersect_local
# define BVH_FUNCTION_FEATURES BVH_HAIR
-# include "kernel/bvh/bvh_local.h"
+# include "kernel/bvh/local.h"
# if defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_local_motion
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
-# include "kernel/bvh/bvh_local.h"
+# include "kernel/bvh/local.h"
# endif
# endif /* __BVH_LOCAL__ */
@@ -85,12 +85,12 @@ CCL_NAMESPACE_BEGIN
# if defined(__VOLUME__)
# define BVH_FUNCTION_NAME bvh_intersect_volume
# define BVH_FUNCTION_FEATURES BVH_HAIR
-# include "kernel/bvh/bvh_volume.h"
+# include "kernel/bvh/volume.h"
# if defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_volume_motion
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
-# include "kernel/bvh/bvh_volume.h"
+# include "kernel/bvh/volume.h"
# endif
# endif /* __VOLUME__ */
@@ -99,24 +99,24 @@ CCL_NAMESPACE_BEGIN
# if defined(__SHADOW_RECORD_ALL__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all
# define BVH_FUNCTION_FEATURES 0
-# include "kernel/bvh/bvh_shadow_all.h"
+# include "kernel/bvh/shadow_all.h"
# if defined(__HAIR__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
# define BVH_FUNCTION_FEATURES BVH_HAIR
-# include "kernel/bvh/bvh_shadow_all.h"
+# include "kernel/bvh/shadow_all.h"
# endif
# if defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
# define BVH_FUNCTION_FEATURES BVH_MOTION
-# include "kernel/bvh/bvh_shadow_all.h"
+# include "kernel/bvh/shadow_all.h"
# endif
# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION
-# include "kernel/bvh/bvh_shadow_all.h"
+# include "kernel/bvh/shadow_all.h"
# endif
# endif /* __SHADOW_RECORD_ALL__ */
@@ -125,12 +125,12 @@ CCL_NAMESPACE_BEGIN
# if defined(__VOLUME_RECORD_ALL__)
# define BVH_FUNCTION_NAME bvh_intersect_volume_all
# define BVH_FUNCTION_FEATURES BVH_HAIR
-# include "kernel/bvh/bvh_volume_all.h"
+# include "kernel/bvh/volume_all.h"
# if defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
-# include "kernel/bvh/bvh_volume_all.h"
+# include "kernel/bvh/volume_all.h"
# endif
# endif /* __VOLUME_RECORD_ALL__ */
diff --git a/intern/cycles/kernel/bvh/bvh_embree.h b/intern/cycles/kernel/bvh/bvh_embree.h
deleted file mode 100644
index 321e0f28dae..00000000000
--- a/intern/cycles/kernel/bvh/bvh_embree.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2018, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <embree3/rtcore_ray.h>
-#include <embree3/rtcore_scene.h>
-
-#include "kernel/device/cpu/compat.h"
-#include "kernel/device/cpu/globals.h"
-
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-struct CCLIntersectContext {
- typedef enum {
- RAY_REGULAR = 0,
- RAY_SHADOW_ALL = 1,
- RAY_LOCAL = 2,
- RAY_SSS = 3,
- RAY_VOLUME_ALL = 4,
- } RayType;
-
- KernelGlobals kg;
- RayType type;
-
- /* for shadow rays */
- Intersection *isect_s;
- uint max_hits;
- uint num_hits;
- uint num_recorded_hits;
- float throughput;
- float max_t;
- bool opaque_hit;
-
- /* for SSS Rays: */
- LocalIntersection *local_isect;
- int local_object_id;
- uint *lcg_state;
-
- CCLIntersectContext(KernelGlobals kg_, RayType type_)
- {
- kg = kg_;
- type = type_;
- max_hits = 1;
- num_hits = 0;
- num_recorded_hits = 0;
- throughput = 1.0f;
- max_t = FLT_MAX;
- opaque_hit = false;
- isect_s = NULL;
- local_isect = NULL;
- local_object_id = -1;
- lcg_state = NULL;
- }
-};
-
-class IntersectContext {
- public:
- IntersectContext(CCLIntersectContext *ctx)
- {
- rtcInitIntersectContext(&context);
- userRayExt = ctx;
- }
- RTCIntersectContext context;
- CCLIntersectContext *userRayExt;
-};
-
-ccl_device_inline void kernel_embree_setup_ray(const Ray &ray,
- RTCRay &rtc_ray,
- const uint visibility)
-{
- rtc_ray.org_x = ray.P.x;
- rtc_ray.org_y = ray.P.y;
- rtc_ray.org_z = ray.P.z;
- rtc_ray.dir_x = ray.D.x;
- rtc_ray.dir_y = ray.D.y;
- rtc_ray.dir_z = ray.D.z;
- rtc_ray.tnear = 0.0f;
- rtc_ray.tfar = ray.t;
- rtc_ray.time = ray.time;
- rtc_ray.mask = visibility;
-}
-
-ccl_device_inline void kernel_embree_setup_rayhit(const Ray &ray,
- RTCRayHit &rayhit,
- const uint visibility)
-{
- kernel_embree_setup_ray(ray, rayhit.ray, visibility);
- rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
- rayhit.hit.primID = RTC_INVALID_GEOMETRY_ID;
-}
-
-ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg,
- const RTCRay *ray,
- const RTCHit *hit,
- Intersection *isect)
-{
- isect->t = ray->tfar;
- if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
- RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
- rtcGetGeometry(kernel_data.bvh.scene, hit->instID[0]));
- isect->prim = hit->primID +
- (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
- isect->object = hit->instID[0] / 2;
- }
- else {
- isect->prim = hit->primID + (intptr_t)rtcGetGeometryUserData(
- rtcGetGeometry(kernel_data.bvh.scene, hit->geomID));
- isect->object = hit->geomID / 2;
- }
-
- const bool is_hair = hit->geomID & 1;
- if (is_hair) {
- const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, isect->prim);
- isect->type = segment.type;
- isect->prim = segment.prim;
- isect->u = hit->u;
- isect->v = hit->v;
- }
- else {
- isect->type = kernel_tex_fetch(__objects, isect->object).primitive_type;
- isect->u = 1.0f - hit->v - hit->u;
- isect->v = hit->u;
- }
-}
-
-ccl_device_inline void kernel_embree_convert_sss_hit(
- KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect, int object)
-{
- isect->u = 1.0f - hit->v - hit->u;
- isect->v = hit->u;
- isect->t = ray->tfar;
- RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
- rtcGetGeometry(kernel_data.bvh.scene, object * 2));
- isect->prim = hit->primID +
- (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
- isect->object = object;
- isect->type = kernel_tex_fetch(__objects, object).primitive_type;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/bvh/embree.h b/intern/cycles/kernel/bvh/embree.h
new file mode 100644
index 00000000000..9edd4f90a7e
--- /dev/null
+++ b/intern/cycles/kernel/bvh/embree.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <embree3/rtcore_ray.h>
+#include <embree3/rtcore_scene.h>
+
+#include "kernel/device/cpu/compat.h"
+#include "kernel/device/cpu/globals.h"
+
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct CCLIntersectContext {
+ typedef enum {
+ RAY_REGULAR = 0,
+ RAY_SHADOW_ALL = 1,
+ RAY_LOCAL = 2,
+ RAY_SSS = 3,
+ RAY_VOLUME_ALL = 4,
+ } RayType;
+
+ KernelGlobals kg;
+ RayType type;
+
+ /* for shadow rays */
+ Intersection *isect_s;
+ uint max_hits;
+ uint num_hits;
+ uint num_recorded_hits;
+ float throughput;
+ float max_t;
+ bool opaque_hit;
+
+ /* for SSS Rays: */
+ LocalIntersection *local_isect;
+ int local_object_id;
+ uint *lcg_state;
+
+ CCLIntersectContext(KernelGlobals kg_, RayType type_)
+ {
+ kg = kg_;
+ type = type_;
+ max_hits = 1;
+ num_hits = 0;
+ num_recorded_hits = 0;
+ throughput = 1.0f;
+ max_t = FLT_MAX;
+ opaque_hit = false;
+ isect_s = NULL;
+ local_isect = NULL;
+ local_object_id = -1;
+ lcg_state = NULL;
+ }
+};
+
+class IntersectContext {
+ public:
+ IntersectContext(CCLIntersectContext *ctx)
+ {
+ rtcInitIntersectContext(&context);
+ userRayExt = ctx;
+ }
+ RTCIntersectContext context;
+ CCLIntersectContext *userRayExt;
+};
+
+ccl_device_inline void kernel_embree_setup_ray(const Ray &ray,
+ RTCRay &rtc_ray,
+ const uint visibility)
+{
+ rtc_ray.org_x = ray.P.x;
+ rtc_ray.org_y = ray.P.y;
+ rtc_ray.org_z = ray.P.z;
+ rtc_ray.dir_x = ray.D.x;
+ rtc_ray.dir_y = ray.D.y;
+ rtc_ray.dir_z = ray.D.z;
+ rtc_ray.tnear = 0.0f;
+ rtc_ray.tfar = ray.t;
+ rtc_ray.time = ray.time;
+ rtc_ray.mask = visibility;
+}
+
+ccl_device_inline void kernel_embree_setup_rayhit(const Ray &ray,
+ RTCRayHit &rayhit,
+ const uint visibility)
+{
+ kernel_embree_setup_ray(ray, rayhit.ray, visibility);
+ rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
+ rayhit.hit.primID = RTC_INVALID_GEOMETRY_ID;
+}
+
+ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg,
+ const RTCRay *ray,
+ const RTCHit *hit,
+ Intersection *isect)
+{
+ isect->t = ray->tfar;
+ if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
+ RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
+ rtcGetGeometry(kernel_data.bvh.scene, hit->instID[0]));
+ isect->prim = hit->primID +
+ (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
+ isect->object = hit->instID[0] / 2;
+ }
+ else {
+ isect->prim = hit->primID + (intptr_t)rtcGetGeometryUserData(
+ rtcGetGeometry(kernel_data.bvh.scene, hit->geomID));
+ isect->object = hit->geomID / 2;
+ }
+
+ const bool is_hair = hit->geomID & 1;
+ if (is_hair) {
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, isect->prim);
+ isect->type = segment.type;
+ isect->prim = segment.prim;
+ isect->u = hit->u;
+ isect->v = hit->v;
+ }
+ else {
+ isect->type = kernel_tex_fetch(__objects, isect->object).primitive_type;
+ isect->u = 1.0f - hit->v - hit->u;
+ isect->v = hit->u;
+ }
+}
+
+ccl_device_inline void kernel_embree_convert_sss_hit(
+ KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect, int object)
+{
+ isect->u = 1.0f - hit->v - hit->u;
+ isect->v = hit->u;
+ isect->t = ray->tfar;
+ RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
+ rtcGetGeometry(kernel_data.bvh.scene, object * 2));
+ isect->prim = hit->primID +
+ (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
+ isect->object = object;
+ isect->type = kernel_tex_fetch(__objects, object).primitive_type;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/bvh/bvh_local.h b/intern/cycles/kernel/bvh/local.h
index 79cde69699e..79cde69699e 100644
--- a/intern/cycles/kernel/bvh/bvh_local.h
+++ b/intern/cycles/kernel/bvh/local.h
diff --git a/intern/cycles/kernel/bvh/bvh_nodes.h b/intern/cycles/kernel/bvh/nodes.h
index 71122085f69..71122085f69 100644
--- a/intern/cycles/kernel/bvh/bvh_nodes.h
+++ b/intern/cycles/kernel/bvh/nodes.h
diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h
index 049c6a03fe0..049c6a03fe0 100644
--- a/intern/cycles/kernel/bvh/bvh_shadow_all.h
+++ b/intern/cycles/kernel/bvh/shadow_all.h
diff --git a/intern/cycles/kernel/bvh/bvh_traversal.h b/intern/cycles/kernel/bvh/traversal.h
index 1c17ebf767f..1c17ebf767f 100644
--- a/intern/cycles/kernel/bvh/bvh_traversal.h
+++ b/intern/cycles/kernel/bvh/traversal.h
diff --git a/intern/cycles/kernel/bvh/bvh_types.h b/intern/cycles/kernel/bvh/types.h
index 6039e707fc3..6039e707fc3 100644
--- a/intern/cycles/kernel/bvh/bvh_types.h
+++ b/intern/cycles/kernel/bvh/types.h
diff --git a/intern/cycles/kernel/bvh/bvh_util.h b/intern/cycles/kernel/bvh/util.h
index 8686f887021..8686f887021 100644
--- a/intern/cycles/kernel/bvh/bvh_util.h
+++ b/intern/cycles/kernel/bvh/util.h
diff --git a/intern/cycles/kernel/bvh/bvh_volume.h b/intern/cycles/kernel/bvh/volume.h
index fa56bd02bef..fa56bd02bef 100644
--- a/intern/cycles/kernel/bvh/bvh_volume.h
+++ b/intern/cycles/kernel/bvh/volume.h
diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/volume_all.h
index 1d7d942e736..1d7d942e736 100644
--- a/intern/cycles/kernel/bvh/bvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/volume_all.h
diff --git a/intern/cycles/kernel/camera/camera.h b/intern/cycles/kernel/camera/camera.h
new file mode 100644
index 00000000000..4f3931583de
--- /dev/null
+++ b/intern/cycles/kernel/camera/camera.h
@@ -0,0 +1,521 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/camera/projection.h"
+#include "kernel/sample/mapping.h"
+#include "kernel/util/differential.h"
+#include "kernel/util/lookup_table.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Perspective Camera */
+
+ccl_device float2 camera_sample_aperture(ccl_constant KernelCamera *cam, float u, float v)
+{
+ float blades = cam->blades;
+ float2 bokeh;
+
+ if (blades == 0.0f) {
+ /* sample disk */
+ bokeh = concentric_sample_disk(u, v);
+ }
+ else {
+ /* sample polygon */
+ float rotation = cam->bladesrotation;
+ bokeh = regular_polygon_sample(blades, rotation, u, v);
+ }
+
+ /* anamorphic lens bokeh */
+ bokeh.x *= cam->inv_aperture_ratio;
+
+ return bokeh;
+}
+
+ccl_device void camera_sample_perspective(KernelGlobals kg,
+ float raster_x,
+ float raster_y,
+ float lens_u,
+ float lens_v,
+ ccl_private Ray *ray)
+{
+ /* create ray form raster position */
+ ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
+ float3 raster = make_float3(raster_x, raster_y, 0.0f);
+ float3 Pcamera = transform_perspective(&rastertocamera, raster);
+
+#ifdef __CAMERA_MOTION__
+ if (kernel_data.cam.have_perspective_motion) {
+ /* TODO(sergey): Currently we interpolate projected coordinate which
+ * gives nice looking result and which is simple, but is in fact a bit
+ * different comparing to constructing projective matrix from an
+ * interpolated field of view.
+ */
+ if (ray->time < 0.5f) {
+ ProjectionTransform rastertocamera_pre = kernel_data.cam.perspective_pre;
+ float3 Pcamera_pre = transform_perspective(&rastertocamera_pre, raster);
+ Pcamera = interp(Pcamera_pre, Pcamera, ray->time * 2.0f);
+ }
+ else {
+ ProjectionTransform rastertocamera_post = kernel_data.cam.perspective_post;
+ float3 Pcamera_post = transform_perspective(&rastertocamera_post, raster);
+ Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f);
+ }
+ }
+#endif
+
+ float3 P = zero_float3();
+ float3 D = Pcamera;
+
+ /* modify ray for depth of field */
+ float aperturesize = kernel_data.cam.aperturesize;
+
+ if (aperturesize > 0.0f) {
+ /* sample point on aperture */
+ float2 lensuv = camera_sample_aperture(&kernel_data.cam, lens_u, lens_v) * aperturesize;
+
+ /* compute point on plane of focus */
+ float ft = kernel_data.cam.focaldistance / D.z;
+ float3 Pfocus = D * ft;
+
+ /* update ray for effect of lens */
+ P = make_float3(lensuv.x, lensuv.y, 0.0f);
+ D = normalize(Pfocus - P);
+ }
+
+ /* transform ray from camera to world */
+ Transform cameratoworld = kernel_data.cam.cameratoworld;
+
+#ifdef __CAMERA_MOTION__
+ if (kernel_data.cam.num_motion_steps) {
+ transform_motion_array_interpolate(&cameratoworld,
+ kernel_tex_array(__camera_motion),
+ kernel_data.cam.num_motion_steps,
+ ray->time);
+ }
+#endif
+
+ P = transform_point(&cameratoworld, P);
+ D = normalize(transform_direction(&cameratoworld, D));
+
+ bool use_stereo = kernel_data.cam.interocular_offset != 0.0f;
+ if (!use_stereo) {
+ /* No stereo */
+ ray->P = P;
+ ray->D = D;
+
+#ifdef __RAY_DIFFERENTIALS__
+ float3 Dcenter = transform_direction(&cameratoworld, Pcamera);
+ float3 Dcenter_normalized = normalize(Dcenter);
+
+ /* TODO: can this be optimized to give compact differentials directly? */
+ ray->dP = differential_zero_compact();
+ differential3 dD;
+ dD.dx = normalize(Dcenter + float4_to_float3(kernel_data.cam.dx)) - Dcenter_normalized;
+ dD.dy = normalize(Dcenter + float4_to_float3(kernel_data.cam.dy)) - Dcenter_normalized;
+ ray->dD = differential_make_compact(dD);
+#endif
+ }
+ else {
+ /* Spherical stereo */
+ spherical_stereo_transform(&kernel_data.cam, &P, &D);
+ ray->P = P;
+ ray->D = D;
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* Ray differentials, computed from scratch using the raster coordinates
+ * because we don't want to be affected by depth of field. We compute
+ * ray origin and direction for the center and two neighboring pixels
+ * and simply take their differences. */
+ float3 Pnostereo = transform_point(&cameratoworld, zero_float3());
+
+ float3 Pcenter = Pnostereo;
+ float3 Dcenter = Pcamera;
+ Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
+ spherical_stereo_transform(&kernel_data.cam, &Pcenter, &Dcenter);
+
+ float3 Px = Pnostereo;
+ float3 Dx = transform_perspective(&rastertocamera,
+ make_float3(raster_x + 1.0f, raster_y, 0.0f));
+ Dx = normalize(transform_direction(&cameratoworld, Dx));
+ spherical_stereo_transform(&kernel_data.cam, &Px, &Dx);
+
+ differential3 dP, dD;
+
+ dP.dx = Px - Pcenter;
+ dD.dx = Dx - Dcenter;
+
+ float3 Py = Pnostereo;
+ float3 Dy = transform_perspective(&rastertocamera,
+ make_float3(raster_x, raster_y + 1.0f, 0.0f));
+ Dy = normalize(transform_direction(&cameratoworld, Dy));
+ spherical_stereo_transform(&kernel_data.cam, &Py, &Dy);
+
+ dP.dy = Py - Pcenter;
+ dD.dy = Dy - Dcenter;
+ ray->dD = differential_make_compact(dD);
+ ray->dP = differential_make_compact(dP);
+#endif
+ }
+
+#ifdef __CAMERA_CLIPPING__
+ /* clipping */
+ float z_inv = 1.0f / normalize(Pcamera).z;
+ float nearclip = kernel_data.cam.nearclip * z_inv;
+ ray->P += nearclip * ray->D;
+ ray->dP += nearclip * ray->dD;
+ ray->t = kernel_data.cam.cliplength * z_inv;
+#else
+ ray->t = FLT_MAX;
+#endif
+}
+
+/* Orthographic Camera */
+ccl_device void camera_sample_orthographic(KernelGlobals kg,
+ float raster_x,
+ float raster_y,
+ float lens_u,
+ float lens_v,
+ ccl_private Ray *ray)
+{
+ /* create ray form raster position */
+ ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
+ float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
+
+ float3 P;
+ float3 D = make_float3(0.0f, 0.0f, 1.0f);
+
+ /* modify ray for depth of field */
+ float aperturesize = kernel_data.cam.aperturesize;
+
+ if (aperturesize > 0.0f) {
+ /* sample point on aperture */
+ float2 lensuv = camera_sample_aperture(&kernel_data.cam, lens_u, lens_v) * aperturesize;
+
+ /* compute point on plane of focus */
+ float3 Pfocus = D * kernel_data.cam.focaldistance;
+
+ /* update ray for effect of lens */
+ float3 lensuvw = make_float3(lensuv.x, lensuv.y, 0.0f);
+ P = Pcamera + lensuvw;
+ D = normalize(Pfocus - lensuvw);
+ }
+ else {
+ P = Pcamera;
+ }
+ /* transform ray from camera to world */
+ Transform cameratoworld = kernel_data.cam.cameratoworld;
+
+#ifdef __CAMERA_MOTION__
+ if (kernel_data.cam.num_motion_steps) {
+ transform_motion_array_interpolate(&cameratoworld,
+ kernel_tex_array(__camera_motion),
+ kernel_data.cam.num_motion_steps,
+ ray->time);
+ }
+#endif
+
+ ray->P = transform_point(&cameratoworld, P);
+ ray->D = normalize(transform_direction(&cameratoworld, D));
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* ray differential */
+ differential3 dP;
+ dP.dx = float4_to_float3(kernel_data.cam.dx);
+ dP.dy = float4_to_float3(kernel_data.cam.dx);
+
+ ray->dP = differential_make_compact(dP);
+ ray->dD = differential_zero_compact();
+#endif
+
+#ifdef __CAMERA_CLIPPING__
+ /* clipping */
+ ray->t = kernel_data.cam.cliplength;
+#else
+ ray->t = FLT_MAX;
+#endif
+}
+
+/* Panorama Camera */
+
+ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
+#ifdef __CAMERA_MOTION__
+ ccl_global const DecomposedTransform *cam_motion,
+#endif
+ float raster_x,
+ float raster_y,
+ float lens_u,
+ float lens_v,
+ ccl_private Ray *ray)
+{
+ ProjectionTransform rastertocamera = cam->rastertocamera;
+ float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
+
+ /* create ray form raster position */
+ float3 P = zero_float3();
+ float3 D = panorama_to_direction(cam, Pcamera.x, Pcamera.y);
+
+ /* indicates ray should not receive any light, outside of the lens */
+ if (is_zero(D)) {
+ ray->t = 0.0f;
+ return;
+ }
+
+ /* modify ray for depth of field */
+ float aperturesize = cam->aperturesize;
+
+ if (aperturesize > 0.0f) {
+ /* sample point on aperture */
+ float2 lensuv = camera_sample_aperture(cam, lens_u, lens_v) * aperturesize;
+
+ /* compute point on plane of focus */
+ float3 Dfocus = normalize(D);
+ float3 Pfocus = Dfocus * cam->focaldistance;
+
+ /* calculate orthonormal coordinates perpendicular to Dfocus */
+ float3 U, V;
+ U = normalize(make_float3(1.0f, 0.0f, 0.0f) - Dfocus.x * Dfocus);
+ V = normalize(cross(Dfocus, U));
+
+ /* update ray for effect of lens */
+ P = U * lensuv.x + V * lensuv.y;
+ D = normalize(Pfocus - P);
+ }
+
+ /* transform ray from camera to world */
+ Transform cameratoworld = cam->cameratoworld;
+
+#ifdef __CAMERA_MOTION__
+ if (cam->num_motion_steps) {
+ transform_motion_array_interpolate(
+ &cameratoworld, cam_motion, cam->num_motion_steps, ray->time);
+ }
+#endif
+
+ /* Stereo transform */
+ bool use_stereo = cam->interocular_offset != 0.0f;
+ if (use_stereo) {
+ spherical_stereo_transform(cam, &P, &D);
+ }
+
+ P = transform_point(&cameratoworld, P);
+ D = normalize(transform_direction(&cameratoworld, D));
+
+ ray->P = P;
+ ray->D = D;
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* Ray differentials, computed from scratch using the raster coordinates
+ * because we don't want to be affected by depth of field. We compute
+ * ray origin and direction for the center and two neighboring pixels
+ * and simply take their differences. */
+ float3 Pcenter = Pcamera;
+ float3 Dcenter = panorama_to_direction(cam, Pcenter.x, Pcenter.y);
+ if (use_stereo) {
+ spherical_stereo_transform(cam, &Pcenter, &Dcenter);
+ }
+ Pcenter = transform_point(&cameratoworld, Pcenter);
+ Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
+
+ float3 Px = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f));
+ float3 Dx = panorama_to_direction(cam, Px.x, Px.y);
+ if (use_stereo) {
+ spherical_stereo_transform(cam, &Px, &Dx);
+ }
+ Px = transform_point(&cameratoworld, Px);
+ Dx = normalize(transform_direction(&cameratoworld, Dx));
+
+ differential3 dP, dD;
+ dP.dx = Px - Pcenter;
+ dD.dx = Dx - Dcenter;
+
+ float3 Py = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f));
+ float3 Dy = panorama_to_direction(cam, Py.x, Py.y);
+ if (use_stereo) {
+ spherical_stereo_transform(cam, &Py, &Dy);
+ }
+ Py = transform_point(&cameratoworld, Py);
+ Dy = normalize(transform_direction(&cameratoworld, Dy));
+
+ dP.dy = Py - Pcenter;
+ dD.dy = Dy - Dcenter;
+ ray->dD = differential_make_compact(dD);
+ ray->dP = differential_make_compact(dP);
+#endif
+
+#ifdef __CAMERA_CLIPPING__
+ /* clipping */
+ float nearclip = cam->nearclip;
+ ray->P += nearclip * ray->D;
+ ray->dP += nearclip * ray->dD;
+ ray->t = cam->cliplength;
+#else
+ ray->t = FLT_MAX;
+#endif
+}
+
+/* Common */
+
+ccl_device_inline void camera_sample(KernelGlobals kg,
+ int x,
+ int y,
+ float filter_u,
+ float filter_v,
+ float lens_u,
+ float lens_v,
+ float time,
+ ccl_private Ray *ray)
+{
+ /* pixel filter */
+ int filter_table_offset = kernel_data.film.filter_table_offset;
+ float raster_x = x + lookup_table_read(kg, filter_u, filter_table_offset, FILTER_TABLE_SIZE);
+ float raster_y = y + lookup_table_read(kg, filter_v, filter_table_offset, FILTER_TABLE_SIZE);
+
+#ifdef __CAMERA_MOTION__
+ /* motion blur */
+ if (kernel_data.cam.shuttertime == -1.0f) {
+ ray->time = 0.5f;
+ }
+ else {
+ /* TODO(sergey): Such lookup is unneeded when there's rolling shutter
+ * effect in use but rolling shutter duration is set to 0.0.
+ */
+ const int shutter_table_offset = kernel_data.cam.shutter_table_offset;
+ ray->time = lookup_table_read(kg, time, shutter_table_offset, SHUTTER_TABLE_SIZE);
+ /* TODO(sergey): Currently single rolling shutter effect type only
+ * where scan-lines are acquired from top to bottom and whole scan-line
+ * is acquired at once (no delay in acquisition happens between pixels
+ * of single scan-line).
+ *
+ * Might want to support more models in the future.
+ */
+ if (kernel_data.cam.rolling_shutter_type) {
+ /* Time corresponding to a fully rolling shutter only effect:
+ * top of the frame is time 0.0, bottom of the frame is time 1.0.
+ */
+ const float time = 1.0f - (float)y / kernel_data.cam.height;
+ const float duration = kernel_data.cam.rolling_shutter_duration;
+ if (duration != 0.0f) {
+ /* This isn't fully physical correct, but lets us to have simple
+ * controls in the interface. The idea here is basically sort of
+ * linear interpolation between how much rolling shutter effect
+ * exist on the frame and how much of it is a motion blur effect.
+ */
+ ray->time = (ray->time - 0.5f) * duration;
+ ray->time += (time - 0.5f) * (1.0f - duration) + 0.5f;
+ }
+ else {
+ ray->time = time;
+ }
+ }
+ }
+#endif
+
+ /* sample */
+ if (kernel_data.cam.type == CAMERA_PERSPECTIVE) {
+ camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray);
+ }
+ else if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
+ camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray);
+ }
+ else {
+#ifdef __CAMERA_MOTION__
+ ccl_global const DecomposedTransform *cam_motion = kernel_tex_array(__camera_motion);
+ camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray);
+#else
+ camera_sample_panorama(&kernel_data.cam, raster_x, raster_y, lens_u, lens_v, ray);
+#endif
+ }
+}
+
+/* Utilities */
+
+ccl_device_inline float3 camera_position(KernelGlobals kg)
+{
+ Transform cameratoworld = kernel_data.cam.cameratoworld;
+ return make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
+}
+
+ccl_device_inline float camera_distance(KernelGlobals kg, float3 P)
+{
+ Transform cameratoworld = kernel_data.cam.cameratoworld;
+ float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
+
+ if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
+ float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z);
+ return fabsf(dot((P - camP), camD));
+ }
+ else {
+ return len(P - camP);
+ }
+}
+
+ccl_device_inline float camera_z_depth(KernelGlobals kg, float3 P)
+{
+ if (kernel_data.cam.type != CAMERA_PANORAMA) {
+ Transform worldtocamera = kernel_data.cam.worldtocamera;
+ return transform_point(&worldtocamera, P).z;
+ }
+ else {
+ Transform cameratoworld = kernel_data.cam.cameratoworld;
+ float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
+ return len(P - camP);
+ }
+}
+
+ccl_device_inline float3 camera_direction_from_point(KernelGlobals kg, float3 P)
+{
+ Transform cameratoworld = kernel_data.cam.cameratoworld;
+
+ if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
+ float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z);
+ return -camD;
+ }
+ else {
+ float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
+ return normalize(camP - P);
+ }
+}
+
+ccl_device_inline float3 camera_world_to_ndc(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ float3 P)
+{
+ if (kernel_data.cam.type != CAMERA_PANORAMA) {
+ /* perspective / ortho */
+ if (sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE)
+ P += camera_position(kg);
+
+ ProjectionTransform tfm = kernel_data.cam.worldtondc;
+ return transform_perspective(&tfm, P);
+ }
+ else {
+ /* panorama */
+ Transform tfm = kernel_data.cam.worldtocamera;
+
+ if (sd->object != OBJECT_NONE)
+ P = normalize(transform_point(&tfm, P));
+ else
+ P = normalize(transform_direction(&tfm, P));
+
+ float2 uv = direction_to_panorama(&kernel_data.cam, P);
+
+ return make_float3(uv.x, uv.y, 0.0f);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_projection.h b/intern/cycles/kernel/camera/projection.h
index 0aea82fa812..0aea82fa812 100644
--- a/intern/cycles/kernel/kernel_projection.h
+++ b/intern/cycles/kernel/camera/projection.h
diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
index c00890be54c..b2a9c9555c3 100644
--- a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
+++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
@@ -32,7 +32,7 @@
#pragma once
-#include "kernel/kernel_montecarlo.h"
+#include "kernel/sample/mapping.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/kernel/closure/bsdf_diffuse.h b/intern/cycles/kernel/closure/bsdf_diffuse.h
index 16c9b428004..3139cb612fa 100644
--- a/intern/cycles/kernel/closure/bsdf_diffuse.h
+++ b/intern/cycles/kernel/closure/bsdf_diffuse.h
@@ -32,6 +32,8 @@
#pragma once
+#include "kernel/sample/mapping.h"
+
CCL_NAMESPACE_BEGIN
typedef struct DiffuseBsdf {
diff --git a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
index 8bff7709a32..fbb82617dad 100644
--- a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
+++ b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
@@ -32,6 +32,8 @@
#pragma once
+#include "kernel/sample/mapping.h"
+
CCL_NAMESPACE_BEGIN
#ifdef __OSL__
diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h
index a474c5661b3..f55ea0f6a2e 100644
--- a/intern/cycles/kernel/closure/bsdf_hair_principled.h
+++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h
@@ -20,7 +20,7 @@
# include <fenv.h>
#endif
-#include "kernel/kernel_color.h"
+#include "kernel/util/color.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index a4e1b7a491c..466ba3e229e 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -32,8 +32,11 @@
#pragma once
-#include "kernel/kernel_lookup_table.h"
-#include "kernel/kernel_random.h"
+#include "kernel/closure/bsdf_util.h"
+
+#include "kernel/sample/pattern.h"
+
+#include "kernel/util/lookup_table.h"
CCL_NAMESPACE_BEGIN
@@ -312,8 +315,8 @@ ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->extra = NULL;
- bsdf->alpha_x = saturate(bsdf->alpha_x);
- bsdf->alpha_y = saturate(bsdf->alpha_y);
+ bsdf->alpha_x = saturatef(bsdf->alpha_x);
+ bsdf->alpha_y = saturatef(bsdf->alpha_y);
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ID;
@@ -333,8 +336,8 @@ ccl_device int bsdf_microfacet_ggx_fresnel_setup(ccl_private MicrofacetBsdf *bsd
{
bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
- bsdf->alpha_x = saturate(bsdf->alpha_x);
- bsdf->alpha_y = saturate(bsdf->alpha_y);
+ bsdf->alpha_x = saturatef(bsdf->alpha_x);
+ bsdf->alpha_y = saturatef(bsdf->alpha_y);
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID;
@@ -348,7 +351,7 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *b
{
bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
- bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_x = saturatef(bsdf->alpha_x);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID;
@@ -362,7 +365,7 @@ ccl_device int bsdf_microfacet_ggx_refraction_setup(ccl_private MicrofacetBsdf *
{
bsdf->extra = NULL;
- bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_x = saturatef(bsdf->alpha_x);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
@@ -780,8 +783,8 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals kg,
ccl_device int bsdf_microfacet_beckmann_setup(ccl_private MicrofacetBsdf *bsdf)
{
- bsdf->alpha_x = saturate(bsdf->alpha_x);
- bsdf->alpha_y = saturate(bsdf->alpha_y);
+ bsdf->alpha_x = saturatef(bsdf->alpha_x);
+ bsdf->alpha_y = saturatef(bsdf->alpha_y);
bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
return SD_BSDF | SD_BSDF_HAS_EVAL;
@@ -797,7 +800,7 @@ ccl_device int bsdf_microfacet_beckmann_isotropic_setup(ccl_private MicrofacetBs
ccl_device int bsdf_microfacet_beckmann_refraction_setup(ccl_private MicrofacetBsdf *bsdf)
{
- bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_x = saturatef(bsdf->alpha_x);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
index b7bd7faaa54..5badbe9aa80 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
@@ -16,6 +16,9 @@
#pragma once
+#include "kernel/sample/lcg.h"
+#include "kernel/sample/mapping.h"
+
CCL_NAMESPACE_BEGIN
/* Most of the code is based on the supplemental implementations from
@@ -217,12 +220,12 @@ ccl_device_forceinline float mf_lambda(const float3 w, const float2 alpha)
/* Height distribution CDF (based on page 4 of the supplemental implementation). */
ccl_device_forceinline float mf_invC1(const float h)
{
- return 2.0f * saturate(h) - 1.0f;
+ return 2.0f * saturatef(h) - 1.0f;
}
ccl_device_forceinline float mf_C1(const float h)
{
- return saturate(0.5f * (h + 1.0f));
+ return saturatef(0.5f * (h + 1.0f));
}
/* Masking function (based on page 16 of the supplemental implementation). */
@@ -281,7 +284,7 @@ ccl_device_forceinline float mf_ggx_albedo(float r)
0.027803f) *
r +
0.00568739f;
- return saturate(albedo);
+ return saturatef(albedo);
}
ccl_device_inline float mf_ggx_transmission_albedo(float a, float ior)
@@ -289,7 +292,7 @@ ccl_device_inline float mf_ggx_transmission_albedo(float a, float ior)
if (ior < 1.0f) {
ior = 1.0f / ior;
}
- a = saturate(a);
+ a = saturatef(a);
ior = clamp(ior, 1.0f, 3.0f);
float I_1 = 0.0476898f * expf(-0.978352f * (ior - 0.65657f) * (ior - 0.65657f)) -
0.033756f * ior + 0.993261f;
@@ -299,7 +302,7 @@ ccl_device_inline float mf_ggx_transmission_albedo(float a, float ior)
float R_2 = ((((5.3725f * a - 24.9307f) * a + 22.7437f) * a - 3.40751f) * a + 0.0986325f) * a +
0.00493504f;
- return saturate(1.0f + I_2 * R_2 * 0.0019127f - (1.0f - I_1) * (1.0f - R_1) * 9.3205f);
+ return saturatef(1.0f + I_2 * R_2 * 0.0019127f - (1.0f - I_1) * (1.0f - R_1) * 9.3205f);
}
ccl_device_forceinline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha)
diff --git a/intern/cycles/kernel/closure/bsdf_oren_nayar.h b/intern/cycles/kernel/closure/bsdf_oren_nayar.h
index 00c2678f0a0..8827309a811 100644
--- a/intern/cycles/kernel/closure/bsdf_oren_nayar.h
+++ b/intern/cycles/kernel/closure/bsdf_oren_nayar.h
@@ -50,7 +50,7 @@ ccl_device int bsdf_oren_nayar_setup(ccl_private OrenNayarBsdf *bsdf)
bsdf->type = CLOSURE_BSDF_OREN_NAYAR_ID;
- sigma = saturate(sigma);
+ sigma = saturatef(sigma);
float div = 1.0f / (M_PI_F + ((3.0f * M_PI_F - 4.0f) / 6.0f) * sigma);
diff --git a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h
index 74390f768a2..69376c1294d 100644
--- a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h
+++ b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h
@@ -27,6 +27,8 @@
#include "kernel/closure/bsdf_util.h"
+#include "kernel/sample/mapping.h"
+
CCL_NAMESPACE_BEGIN
enum PrincipledDiffuseBsdfComponents {
diff --git a/intern/cycles/kernel/closure/bsdf_toon.h b/intern/cycles/kernel/closure/bsdf_toon.h
index 7f20a328b5e..20f3b8f0074 100644
--- a/intern/cycles/kernel/closure/bsdf_toon.h
+++ b/intern/cycles/kernel/closure/bsdf_toon.h
@@ -48,8 +48,8 @@ static_assert(sizeof(ShaderClosure) >= sizeof(ToonBsdf), "ToonBsdf is too large!
ccl_device int bsdf_diffuse_toon_setup(ccl_private ToonBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_DIFFUSE_TOON_ID;
- bsdf->size = saturate(bsdf->size);
- bsdf->smooth = saturate(bsdf->smooth);
+ bsdf->size = saturatef(bsdf->size);
+ bsdf->smooth = saturatef(bsdf->smooth);
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
@@ -146,8 +146,8 @@ ccl_device int bsdf_diffuse_toon_sample(ccl_private const ShaderClosure *sc,
ccl_device int bsdf_glossy_toon_setup(ccl_private ToonBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_GLOSSY_TOON_ID;
- bsdf->size = saturate(bsdf->size);
- bsdf->smooth = saturate(bsdf->smooth);
+ bsdf->size = saturatef(bsdf->size);
+ bsdf->smooth = saturatef(bsdf->smooth);
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h
index 873494c1e03..b1c16a037df 100644
--- a/intern/cycles/kernel/closure/bsdf_util.h
+++ b/intern/cycles/kernel/closure/bsdf_util.h
@@ -148,4 +148,110 @@ interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0
return cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH;
}
+ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N)
+{
+ float3 R = 2 * dot(N, I) * N - I;
+
+ /* Reflection rays may always be at least as shallow as the incoming ray. */
+ float threshold = min(0.9f * dot(Ng, I), 0.01f);
+ if (dot(Ng, R) >= threshold) {
+ return N;
+ }
+
+ /* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane.
+ * The X axis is found by normalizing the component of N that's orthogonal to Ng.
+ * The Y axis isn't actually needed.
+ */
+ float NdotNg = dot(N, Ng);
+ float3 X = normalize(N - NdotNg * Ng);
+
+ /* Keep math expressions. */
+ /* clang-format off */
+ /* Calculate N.z and N.x in the local coordinate system.
+ *
+ * The goal of this computation is to find a N' that is rotated towards Ng just enough
+ * to lift R' above the threshold (here called t), therefore dot(R', Ng) = t.
+ *
+ * According to the standard reflection equation,
+ * this means that we want dot(2*dot(N', I)*N' - I, Ng) = t.
+ *
+ * Since the Z axis of our local coordinate system is Ng, dot(x, Ng) is just x.z, so we get
+ * 2*dot(N', I)*N'.z - I.z = t.
+ *
+ * The rotation is simple to express in the coordinate system we formed -
+ * since N lies in the X-Z-plane, we know that N' will also lie in the X-Z-plane,
+ * so N'.y = 0 and therefore dot(N', I) = N'.x*I.x + N'.z*I.z .
+ *
+ * Furthermore, we want N' to be normalized, so N'.x = sqrt(1 - N'.z^2).
+ *
+ * With these simplifications,
+ * we get the final equation 2*(sqrt(1 - N'.z^2)*I.x + N'.z*I.z)*N'.z - I.z = t.
+ *
+ * The only unknown here is N'.z, so we can solve for that.
+ *
+ * The equation has four solutions in general:
+ *
+ * N'.z = +-sqrt(0.5*(+-sqrt(I.x^2*(I.x^2 + I.z^2 - t^2)) + t*I.z + I.x^2 + I.z^2)/(I.x^2 + I.z^2))
+ * We can simplify this expression a bit by grouping terms:
+ *
+ * a = I.x^2 + I.z^2
+ * b = sqrt(I.x^2 * (a - t^2))
+ * c = I.z*t + a
+ * N'.z = +-sqrt(0.5*(+-b + c)/a)
+ *
+ * Two solutions can immediately be discarded because they're negative so N' would lie in the
+ * lower hemisphere.
+ */
+ /* clang-format on */
+
+ float Ix = dot(I, X), Iz = dot(I, Ng);
+ float Ix2 = sqr(Ix), Iz2 = sqr(Iz);
+ float a = Ix2 + Iz2;
+
+ float b = safe_sqrtf(Ix2 * (a - sqr(threshold)));
+ float c = Iz * threshold + a;
+
+ /* Evaluate both solutions.
+ * In many cases one can be immediately discarded (if N'.z would be imaginary or larger than
+ * one), so check for that first. If no option is viable (might happen in extreme cases like N
+ * being in the wrong hemisphere), give up and return Ng. */
+ float fac = 0.5f / a;
+ float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c);
+ bool valid1 = (N1_z2 > 1e-5f) && (N1_z2 <= (1.0f + 1e-5f));
+ bool valid2 = (N2_z2 > 1e-5f) && (N2_z2 <= (1.0f + 1e-5f));
+
+ float2 N_new;
+ if (valid1 && valid2) {
+ /* If both are possible, do the expensive reflection-based check. */
+ float2 N1 = make_float2(safe_sqrtf(1.0f - N1_z2), safe_sqrtf(N1_z2));
+ float2 N2 = make_float2(safe_sqrtf(1.0f - N2_z2), safe_sqrtf(N2_z2));
+
+ float R1 = 2 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz;
+ float R2 = 2 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz;
+
+ valid1 = (R1 >= 1e-5f);
+ valid2 = (R2 >= 1e-5f);
+ if (valid1 && valid2) {
+ /* If both solutions are valid, return the one with the shallower reflection since it will be
+ * closer to the input (if the original reflection wasn't shallow, we would not be in this
+ * part of the function). */
+ N_new = (R1 < R2) ? N1 : N2;
+ }
+ else {
+ /* If only one reflection is valid (= positive), pick that one. */
+ N_new = (R1 > R2) ? N1 : N2;
+ }
+ }
+ else if (valid1 || valid2) {
+ /* Only one solution passes the N'.z criterium, so pick that one. */
+ float Nz2 = valid1 ? N1_z2 : N2_z2;
+ N_new = make_float2(safe_sqrtf(1.0f - Nz2), safe_sqrtf(Nz2));
+ }
+ else {
+ return Ng;
+ }
+
+ return N_new.x * X + N_new.y * Ng;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/cpu/compat.h b/intern/cycles/kernel/device/cpu/compat.h
index 888c0d5d872..5ccca52255f 100644
--- a/intern/cycles/kernel/device/cpu/compat.h
+++ b/intern/cycles/kernel/device/cpu/compat.h
@@ -26,11 +26,11 @@
# pragma GCC diagnostic ignored "-Wuninitialized"
#endif
-#include "util/util_half.h"
-#include "util/util_math.h"
-#include "util/util_simd.h"
-#include "util/util_texture.h"
-#include "util/util_types.h"
+#include "util/half.h"
+#include "util/math.h"
+#include "util/simd.h"
+#include "util/texture.h"
+#include "util/types.h"
/* On x86_64, versions of glibc < 2.16 have an issue where expf is
* much slower than the double version. This was fixed in glibc 2.16.
diff --git a/intern/cycles/kernel/device/cpu/globals.h b/intern/cycles/kernel/device/cpu/globals.h
index fb9aae38cfc..dd0327b3f94 100644
--- a/intern/cycles/kernel/device/cpu/globals.h
+++ b/intern/cycles/kernel/device/cpu/globals.h
@@ -18,8 +18,8 @@
#pragma once
-#include "kernel/kernel_profiling.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
+#include "kernel/util/profiling.h"
CCL_NAMESPACE_BEGIN
@@ -36,7 +36,7 @@ struct OSLShadingSystem;
typedef struct KernelGlobalsCPU {
#define KERNEL_TEX(type, name) texture<type> name;
-#include "kernel/kernel_textures.h"
+#include "kernel/textures.h"
KernelData __data;
diff --git a/intern/cycles/kernel/device/cpu/kernel.cpp b/intern/cycles/kernel/device/cpu/kernel.cpp
index 8519b77aa08..a16c637d5ac 100644
--- a/intern/cycles/kernel/device/cpu/kernel.cpp
+++ b/intern/cycles/kernel/device/cpu/kernel.cpp
@@ -85,7 +85,7 @@ void kernel_global_memory_copy(KernelGlobalsCPU *kg, const char *name, void *mem
kg->tname.data = (type *)mem; \
kg->tname.width = size; \
}
-#include "kernel/kernel_textures.h"
+#include "kernel/textures.h"
else {
assert(0);
}
diff --git a/intern/cycles/kernel/device/cpu/kernel.h b/intern/cycles/kernel/device/cpu/kernel.h
index 28337a58898..c49d7ca445a 100644
--- a/intern/cycles/kernel/device/cpu/kernel.h
+++ b/intern/cycles/kernel/device/cpu/kernel.h
@@ -18,9 +18,9 @@
/* CPU Kernel Interface */
-#include "util/util_types.h"
+#include "util/types.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/kernel/device/cpu/kernel_arch_impl.h b/intern/cycles/kernel/device/cpu/kernel_arch_impl.h
index ba777062113..6df5d7787fc 100644
--- a/intern/cycles/kernel/device/cpu/kernel_arch_impl.h
+++ b/intern/cycles/kernel/device/cpu/kernel_arch_impl.h
@@ -29,27 +29,28 @@
# include "kernel/device/cpu/globals.h"
# include "kernel/device/cpu/image.h"
-# include "kernel/integrator/integrator_state.h"
-# include "kernel/integrator/integrator_state_flow.h"
-# include "kernel/integrator/integrator_state_util.h"
-
-# include "kernel/integrator/integrator_init_from_camera.h"
-# include "kernel/integrator/integrator_init_from_bake.h"
-# include "kernel/integrator/integrator_intersect_closest.h"
-# include "kernel/integrator/integrator_intersect_shadow.h"
-# include "kernel/integrator/integrator_intersect_subsurface.h"
-# include "kernel/integrator/integrator_intersect_volume_stack.h"
-# include "kernel/integrator/integrator_shade_background.h"
-# include "kernel/integrator/integrator_shade_light.h"
-# include "kernel/integrator/integrator_shade_shadow.h"
-# include "kernel/integrator/integrator_shade_surface.h"
-# include "kernel/integrator/integrator_shade_volume.h"
-# include "kernel/integrator/integrator_megakernel.h"
-
-# include "kernel/kernel_film.h"
-# include "kernel/kernel_adaptive_sampling.h"
-# include "kernel/kernel_bake.h"
-# include "kernel/kernel_id_passes.h"
+# include "kernel/integrator/state.h"
+# include "kernel/integrator/state_flow.h"
+# include "kernel/integrator/state_util.h"
+
+# include "kernel/integrator/init_from_camera.h"
+# include "kernel/integrator/init_from_bake.h"
+# include "kernel/integrator/intersect_closest.h"
+# include "kernel/integrator/intersect_shadow.h"
+# include "kernel/integrator/intersect_subsurface.h"
+# include "kernel/integrator/intersect_volume_stack.h"
+# include "kernel/integrator/shade_background.h"
+# include "kernel/integrator/shade_light.h"
+# include "kernel/integrator/shade_shadow.h"
+# include "kernel/integrator/shade_surface.h"
+# include "kernel/integrator/shade_volume.h"
+# include "kernel/integrator/megakernel.h"
+
+# include "kernel/film/adaptive_sampling.h"
+# include "kernel/film/read.h"
+# include "kernel/film/id_passes.h"
+
+# include "kernel/bake/bake.h"
#else
# define STUB_ASSERT(arch, name) \
diff --git a/intern/cycles/kernel/device/cpu/kernel_avx.cpp b/intern/cycles/kernel/device/cpu/kernel_avx.cpp
index 220768036ab..cece750a255 100644
--- a/intern/cycles/kernel/device/cpu/kernel_avx.cpp
+++ b/intern/cycles/kernel/device/cpu/kernel_avx.cpp
@@ -18,7 +18,7 @@
* optimization flags and nearly all functions inlined, while kernel.cpp
* is compiled without for other CPU's. */
-#include "util/util_optimization.h"
+#include "util/optimization.h"
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
# define KERNEL_STUB
diff --git a/intern/cycles/kernel/device/cpu/kernel_avx2.cpp b/intern/cycles/kernel/device/cpu/kernel_avx2.cpp
index 90c05113cbe..fad4581236e 100644
--- a/intern/cycles/kernel/device/cpu/kernel_avx2.cpp
+++ b/intern/cycles/kernel/device/cpu/kernel_avx2.cpp
@@ -18,7 +18,7 @@
* optimization flags and nearly all functions inlined, while kernel.cpp
* is compiled without for other CPU's. */
-#include "util/util_optimization.h"
+#include "util/optimization.h"
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
# define KERNEL_STUB
diff --git a/intern/cycles/kernel/device/cpu/kernel_sse2.cpp b/intern/cycles/kernel/device/cpu/kernel_sse2.cpp
index fb85ef5b0d0..5fb4849ac08 100644
--- a/intern/cycles/kernel/device/cpu/kernel_sse2.cpp
+++ b/intern/cycles/kernel/device/cpu/kernel_sse2.cpp
@@ -18,7 +18,7 @@
* optimization flags and nearly all functions inlined, while kernel.cpp
* is compiled without for other CPU's. */
-#include "util/util_optimization.h"
+#include "util/optimization.h"
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
# define KERNEL_STUB
diff --git a/intern/cycles/kernel/device/cpu/kernel_sse3.cpp b/intern/cycles/kernel/device/cpu/kernel_sse3.cpp
index 87baf04258a..c9424682fd4 100644
--- a/intern/cycles/kernel/device/cpu/kernel_sse3.cpp
+++ b/intern/cycles/kernel/device/cpu/kernel_sse3.cpp
@@ -18,7 +18,7 @@
* optimization flags and nearly all functions inlined, while kernel.cpp
* is compiled without for other CPU's. */
-#include "util/util_optimization.h"
+#include "util/optimization.h"
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
# define KERNEL_STUB
diff --git a/intern/cycles/kernel/device/cpu/kernel_sse41.cpp b/intern/cycles/kernel/device/cpu/kernel_sse41.cpp
index bb421d58815..849ebf51989 100644
--- a/intern/cycles/kernel/device/cpu/kernel_sse41.cpp
+++ b/intern/cycles/kernel/device/cpu/kernel_sse41.cpp
@@ -18,7 +18,7 @@
* optimization flags and nearly all functions inlined, while kernel.cpp
* is compiled without for other CPU's. */
-#include "util/util_optimization.h"
+#include "util/optimization.h"
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
# define KERNEL_STUB
diff --git a/intern/cycles/kernel/device/cuda/compat.h b/intern/cycles/kernel/device/cuda/compat.h
index 8a50eb1a3d5..1ee82e6eb7c 100644
--- a/intern/cycles/kernel/device/cuda/compat.h
+++ b/intern/cycles/kernel/device/cuda/compat.h
@@ -137,5 +137,5 @@ __device__ float __half2float(const half h)
/* Types */
-#include "util/util_half.h"
-#include "util/util_types.h"
+#include "util/half.h"
+#include "util/types.h"
diff --git a/intern/cycles/kernel/device/cuda/globals.h b/intern/cycles/kernel/device/cuda/globals.h
index 2c187cf8a23..e5023fad40c 100644
--- a/intern/cycles/kernel/device/cuda/globals.h
+++ b/intern/cycles/kernel/device/cuda/globals.h
@@ -18,10 +18,11 @@
#pragma once
-#include "kernel/kernel_profiling.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
-#include "kernel/integrator/integrator_state.h"
+#include "kernel/integrator/state.h"
+
+#include "kernel/util/profiling.h"
CCL_NAMESPACE_BEGIN
@@ -35,7 +36,7 @@ typedef ccl_global const KernelGlobalsGPU *ccl_restrict KernelGlobals;
/* Global scene data and textures */
__constant__ KernelData __data;
#define KERNEL_TEX(type, name) const __constant__ __device__ type *name;
-#include "kernel/kernel_textures.h"
+#include "kernel/textures.h"
/* Integrator state */
__constant__ IntegratorStateGPU __integrator_state;
diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h
index 335cb1ec0c0..f86a8c692aa 100644
--- a/intern/cycles/kernel/device/gpu/kernel.h
+++ b/intern/cycles/kernel/device/gpu/kernel.h
@@ -19,27 +19,28 @@
#include "kernel/device/gpu/parallel_active_index.h"
#include "kernel/device/gpu/parallel_prefix_sum.h"
#include "kernel/device/gpu/parallel_sorted_index.h"
-
-#include "kernel/integrator/integrator_state.h"
-#include "kernel/integrator/integrator_state_flow.h"
-#include "kernel/integrator/integrator_state_util.h"
-
-#include "kernel/integrator/integrator_init_from_bake.h"
-#include "kernel/integrator/integrator_init_from_camera.h"
-#include "kernel/integrator/integrator_intersect_closest.h"
-#include "kernel/integrator/integrator_intersect_shadow.h"
-#include "kernel/integrator/integrator_intersect_subsurface.h"
-#include "kernel/integrator/integrator_intersect_volume_stack.h"
-#include "kernel/integrator/integrator_shade_background.h"
-#include "kernel/integrator/integrator_shade_light.h"
-#include "kernel/integrator/integrator_shade_shadow.h"
-#include "kernel/integrator/integrator_shade_surface.h"
-#include "kernel/integrator/integrator_shade_volume.h"
-
-#include "kernel/kernel_adaptive_sampling.h"
-#include "kernel/kernel_bake.h"
-#include "kernel/kernel_film.h"
-#include "kernel/kernel_work_stealing.h"
+#include "kernel/device/gpu/work_stealing.h"
+
+#include "kernel/integrator/state.h"
+#include "kernel/integrator/state_flow.h"
+#include "kernel/integrator/state_util.h"
+
+#include "kernel/integrator/init_from_bake.h"
+#include "kernel/integrator/init_from_camera.h"
+#include "kernel/integrator/intersect_closest.h"
+#include "kernel/integrator/intersect_shadow.h"
+#include "kernel/integrator/intersect_subsurface.h"
+#include "kernel/integrator/intersect_volume_stack.h"
+#include "kernel/integrator/shade_background.h"
+#include "kernel/integrator/shade_light.h"
+#include "kernel/integrator/shade_shadow.h"
+#include "kernel/integrator/shade_surface.h"
+#include "kernel/integrator/shade_volume.h"
+
+#include "kernel/bake/bake.h"
+
+#include "kernel/film/adaptive_sampling.h"
+#include "kernel/film/read.h"
/* --------------------------------------------------------------------
* Integrator.
diff --git a/intern/cycles/kernel/device/gpu/parallel_active_index.h b/intern/cycles/kernel/device/gpu/parallel_active_index.h
index db4a4bf71e0..d7416beb783 100644
--- a/intern/cycles/kernel/device/gpu/parallel_active_index.h
+++ b/intern/cycles/kernel/device/gpu/parallel_active_index.h
@@ -23,7 +23,7 @@ CCL_NAMESPACE_BEGIN
*
* Shared memory requirement is `sizeof(int) * (number_of_warps + 1)`. */
-#include "util/util_atomic.h"
+#include "util/atomic.h"
#ifdef __HIP__
# define GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE 1024
diff --git a/intern/cycles/kernel/device/gpu/parallel_prefix_sum.h b/intern/cycles/kernel/device/gpu/parallel_prefix_sum.h
index aabe6e2e27a..6de3a022569 100644
--- a/intern/cycles/kernel/device/gpu/parallel_prefix_sum.h
+++ b/intern/cycles/kernel/device/gpu/parallel_prefix_sum.h
@@ -25,7 +25,7 @@ CCL_NAMESPACE_BEGIN
* This is used for an array the size of the number of shaders in the scene
* which is not usually huge, so might not be a significant bottleneck. */
-#include "util/util_atomic.h"
+#include "util/atomic.h"
#ifdef __HIP__
# define GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE 1024
diff --git a/intern/cycles/kernel/device/gpu/parallel_sorted_index.h b/intern/cycles/kernel/device/gpu/parallel_sorted_index.h
index 7570c5a6bbd..c06d7be444f 100644
--- a/intern/cycles/kernel/device/gpu/parallel_sorted_index.h
+++ b/intern/cycles/kernel/device/gpu/parallel_sorted_index.h
@@ -24,7 +24,7 @@ CCL_NAMESPACE_BEGIN
*
* TODO: there may be ways to optimize this to avoid this many atomic ops? */
-#include "util/util_atomic.h"
+#include "util/atomic.h"
#ifdef __HIP__
# define GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE 1024
diff --git a/intern/cycles/kernel/kernel_work_stealing.h b/intern/cycles/kernel/device/gpu/work_stealing.h
index fab0915c38e..fab0915c38e 100644
--- a/intern/cycles/kernel/kernel_work_stealing.h
+++ b/intern/cycles/kernel/device/gpu/work_stealing.h
diff --git a/intern/cycles/kernel/device/hip/compat.h b/intern/cycles/kernel/device/hip/compat.h
index 089976d84e4..282c3eca641 100644
--- a/intern/cycles/kernel/device/hip/compat.h
+++ b/intern/cycles/kernel/device/hip/compat.h
@@ -116,5 +116,5 @@ ccl_device_forceinline T ccl_gpu_tex_object_read_3D(const ccl_gpu_tex_object tex
/* Types */
-#include "util/util_half.h"
-#include "util/util_types.h"
+#include "util/half.h"
+#include "util/types.h"
diff --git a/intern/cycles/kernel/device/hip/globals.h b/intern/cycles/kernel/device/hip/globals.h
index 28e1cc4282f..d9a560d668b 100644
--- a/intern/cycles/kernel/device/hip/globals.h
+++ b/intern/cycles/kernel/device/hip/globals.h
@@ -18,10 +18,11 @@
#pragma once
-#include "kernel/kernel_profiling.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
-#include "kernel/integrator/integrator_state.h"
+#include "kernel/integrator/state.h"
+
+#include "kernel/util/profiling.h"
CCL_NAMESPACE_BEGIN
@@ -35,7 +36,7 @@ typedef ccl_global const KernelGlobalsGPU *ccl_restrict KernelGlobals;
/* Global scene data and textures */
__constant__ KernelData __data;
#define KERNEL_TEX(type, name) __attribute__((used)) const __constant__ __device__ type *name;
-#include "kernel/kernel_textures.h"
+#include "kernel/textures.h"
/* Integrator state */
__constant__ IntegratorStateGPU __integrator_state;
diff --git a/intern/cycles/kernel/device/optix/compat.h b/intern/cycles/kernel/device/optix/compat.h
index d27b7d55475..835e4621d47 100644
--- a/intern/cycles/kernel/device/optix/compat.h
+++ b/intern/cycles/kernel/device/optix/compat.h
@@ -129,5 +129,5 @@ __device__ float __half2float(const half h)
/* Types */
-#include "util/util_half.h"
-#include "util/util_types.h"
+#include "util/half.h"
+#include "util/types.h"
diff --git a/intern/cycles/kernel/device/optix/globals.h b/intern/cycles/kernel/device/optix/globals.h
index 7b8ebfe50e6..e9b72369cd5 100644
--- a/intern/cycles/kernel/device/optix/globals.h
+++ b/intern/cycles/kernel/device/optix/globals.h
@@ -18,10 +18,11 @@
#pragma once
-#include "kernel/kernel_profiling.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
-#include "kernel/integrator/integrator_state.h"
+#include "kernel/integrator/state.h"
+
+#include "kernel/util/profiling.h"
CCL_NAMESPACE_BEGIN
@@ -41,7 +42,7 @@ struct KernelParamsOptiX {
/* Global scene data and textures */
KernelData data;
#define KERNEL_TEX(type, name) const type *name;
-#include "kernel/kernel_textures.h"
+#include "kernel/textures.h"
/* Integrator state */
IntegratorStateGPU __integrator_state;
diff --git a/intern/cycles/kernel/device/optix/kernel.cu b/intern/cycles/kernel/device/optix/kernel.cu
index a3bafb9846c..6989219cd9f 100644
--- a/intern/cycles/kernel/device/optix/kernel.cu
+++ b/intern/cycles/kernel/device/optix/kernel.cu
@@ -21,14 +21,14 @@
#include "kernel/device/gpu/image.h" /* Texture lookup uses normal CUDA intrinsics. */
-#include "kernel/integrator/integrator_state.h"
-#include "kernel/integrator/integrator_state_flow.h"
-#include "kernel/integrator/integrator_state_util.h"
-
-#include "kernel/integrator/integrator_intersect_closest.h"
-#include "kernel/integrator/integrator_intersect_shadow.h"
-#include "kernel/integrator/integrator_intersect_subsurface.h"
-#include "kernel/integrator/integrator_intersect_volume_stack.h"
+#include "kernel/integrator/state.h"
+#include "kernel/integrator/state_flow.h"
+#include "kernel/integrator/state_util.h"
+
+#include "kernel/integrator/intersect_closest.h"
+#include "kernel/integrator/intersect_shadow.h"
+#include "kernel/integrator/intersect_subsurface.h"
+#include "kernel/integrator/intersect_volume_stack.h"
// clang-format on
diff --git a/intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu b/intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu
index bf787e29eaa..071e9deae0b 100644
--- a/intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu
+++ b/intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu
@@ -18,7 +18,8 @@
* much longer to compiler. This is only loaded when needed by the scene. */
#include "kernel/device/optix/kernel.cu"
-#include "kernel/integrator/integrator_shade_surface.h"
+
+#include "kernel/integrator/shade_surface.h"
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_surface_raytrace()
{
diff --git a/intern/cycles/kernel/film/accumulate.h b/intern/cycles/kernel/film/accumulate.h
new file mode 100644
index 00000000000..30e1afea751
--- /dev/null
+++ b/intern/cycles/kernel/film/accumulate.h
@@ -0,0 +1,559 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/film/adaptive_sampling.h"
+#include "kernel/film/write_passes.h"
+
+#include "kernel/integrator/shadow_catcher.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* --------------------------------------------------------------------
+ * BSDF Evaluation
+ *
+ * BSDF evaluation result, split between diffuse and glossy. This is used to
+ * accumulate render passes separately. Note that reflection, transmission
+ * and volume scattering are written to different render passes, but we assume
+ * that only one of those can happen at a bounce, and so do not need to accumulate
+ * them separately. */
+
+ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval,
+ const bool is_diffuse,
+ float3 value)
+{
+ eval->diffuse = zero_float3();
+ eval->glossy = zero_float3();
+
+ if (is_diffuse) {
+ eval->diffuse = value;
+ }
+ else {
+ eval->glossy = value;
+ }
+}
+
+ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval,
+ const bool is_diffuse,
+ float3 value,
+ float mis_weight)
+{
+ value *= mis_weight;
+
+ if (is_diffuse) {
+ eval->diffuse += value;
+ }
+ else {
+ eval->glossy += value;
+ }
+}
+
+ccl_device_inline bool bsdf_eval_is_zero(ccl_private BsdfEval *eval)
+{
+ return is_zero(eval->diffuse) && is_zero(eval->glossy);
+}
+
+ccl_device_inline void bsdf_eval_mul(ccl_private BsdfEval *eval, float value)
+{
+ eval->diffuse *= value;
+ eval->glossy *= value;
+}
+
+ccl_device_inline void bsdf_eval_mul3(ccl_private BsdfEval *eval, float3 value)
+{
+ eval->diffuse *= value;
+ eval->glossy *= value;
+}
+
+ccl_device_inline float3 bsdf_eval_sum(ccl_private const BsdfEval *eval)
+{
+ return eval->diffuse + eval->glossy;
+}
+
+ccl_device_inline float3 bsdf_eval_diffuse_glossy_ratio(ccl_private const BsdfEval *eval)
+{
+ /* Ratio of diffuse and glossy to recover proportions for writing to render pass.
+ * We assume reflection, transmission and volume scatter to be exclusive. */
+ return safe_divide_float3_float3(eval->diffuse, eval->diffuse + eval->glossy);
+}
+
+/* --------------------------------------------------------------------
+ * Clamping
+ *
+ * Clamping is done on a per-contribution basis so that we can write directly
+ * to render buffers instead of using per-thread memory, and to avoid the
+ * impact of clamping on other contributions. */
+
+ccl_device_forceinline void kernel_accum_clamp(KernelGlobals kg, ccl_private float3 *L, int bounce)
+{
+#ifdef __KERNEL_DEBUG_NAN__
+ if (!isfinite3_safe(*L)) {
+ kernel_assert(!"Cycles sample with non-finite value detected");
+ }
+#endif
+ /* Make sure all components are finite, allowing the contribution to be usable by adaptive
+ * sampling convergence check, but also to make it so render result never causes issues with
+ * post-processing. */
+ *L = ensure_finite3(*L);
+
+#ifdef __CLAMP_SAMPLE__
+ float limit = (bounce > 0) ? kernel_data.integrator.sample_clamp_indirect :
+ kernel_data.integrator.sample_clamp_direct;
+ float sum = reduce_add(fabs(*L));
+ if (sum > limit) {
+ *L *= limit / sum;
+ }
+#endif
+}
+
+/* --------------------------------------------------------------------
+ * Pass accumulation utilities.
+ */
+
+/* Get pointer to pixel in render buffer. */
+ccl_device_forceinline ccl_global float *kernel_accum_pixel_render_buffer(
+ KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer)
+{
+ const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
+ const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
+ kernel_data.film.pass_stride;
+ return render_buffer + render_buffer_offset;
+}
+
+/* --------------------------------------------------------------------
+ * Adaptive sampling.
+ */
+
+ccl_device_inline int kernel_accum_sample(KernelGlobals kg,
+ ConstIntegratorState state,
+ ccl_global float *ccl_restrict render_buffer,
+ int sample)
+{
+ if (kernel_data.film.pass_sample_count == PASS_UNUSED) {
+ return sample;
+ }
+
+ ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer);
+
+ return atomic_fetch_and_add_uint32((uint *)(buffer) + kernel_data.film.pass_sample_count, 1);
+}
+
+ccl_device void kernel_accum_adaptive_buffer(KernelGlobals kg,
+ const int sample,
+ const float3 contribution,
+ ccl_global float *ccl_restrict buffer)
+{
+ /* Adaptive Sampling. Fill the additional buffer with the odd samples and calculate our stopping
+ * criteria. This is the heuristic from "A hierarchical automatic stopping condition for Monte
+ * Carlo global illumination" except that here it is applied per pixel and not in hierarchical
+ * tiles. */
+
+ if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) {
+ return;
+ }
+
+ if (sample_is_even(kernel_data.integrator.sampling_pattern, sample)) {
+ kernel_write_pass_float4(
+ buffer + kernel_data.film.pass_adaptive_aux_buffer,
+ make_float4(contribution.x * 2.0f, contribution.y * 2.0f, contribution.z * 2.0f, 0.0f));
+ }
+}
+
+/* --------------------------------------------------------------------
+ * Shadow catcher.
+ */
+
+#ifdef __SHADOW_CATCHER__
+
+/* Accumulate contribution to the Shadow Catcher pass.
+ *
+ * Returns truth if the contribution is fully handled here and is not to be added to the other
+ * passes (like combined, adaptive sampling). */
+
+ccl_device bool kernel_accum_shadow_catcher(KernelGlobals kg,
+ const uint32_t path_flag,
+ const float3 contribution,
+ ccl_global float *ccl_restrict buffer)
+{
+ if (!kernel_data.integrator.has_shadow_catcher) {
+ return false;
+ }
+
+ kernel_assert(kernel_data.film.pass_shadow_catcher != PASS_UNUSED);
+ kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED);
+
+ /* Matte pass. */
+ if (kernel_shadow_catcher_is_matte_path(path_flag)) {
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher_matte, contribution);
+ /* NOTE: Accumulate the combined pass and to the samples count pass, so that the adaptive
+ * sampling is based on how noisy the combined pass is as if there were no catchers in the
+ * scene. */
+ }
+
+ /* Shadow catcher pass. */
+ if (kernel_shadow_catcher_is_object_pass(path_flag)) {
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher, contribution);
+ return true;
+ }
+
+ return false;
+}
+
+ccl_device bool kernel_accum_shadow_catcher_transparent(KernelGlobals kg,
+ const uint32_t path_flag,
+ const float3 contribution,
+ const float transparent,
+ ccl_global float *ccl_restrict buffer)
+{
+ if (!kernel_data.integrator.has_shadow_catcher) {
+ return false;
+ }
+
+ kernel_assert(kernel_data.film.pass_shadow_catcher != PASS_UNUSED);
+ kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED);
+
+ if (path_flag & PATH_RAY_SHADOW_CATCHER_BACKGROUND) {
+ return true;
+ }
+
+ /* Matte pass. */
+ if (kernel_shadow_catcher_is_matte_path(path_flag)) {
+ kernel_write_pass_float4(
+ buffer + kernel_data.film.pass_shadow_catcher_matte,
+ make_float4(contribution.x, contribution.y, contribution.z, transparent));
+ /* NOTE: Accumulate the combined pass and to the samples count pass, so that the adaptive
+ * sampling is based on how noisy the combined pass is as if there were no catchers in the
+ * scene. */
+ }
+
+ /* Shadow catcher pass. */
+ if (kernel_shadow_catcher_is_object_pass(path_flag)) {
+ /* NOTE: The transparency of the shadow catcher pass is ignored. It is not needed for the
+ * calculation and the alpha channel of the pass contains numbers of samples contributed to a
+ * pixel of the pass. */
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher, contribution);
+ return true;
+ }
+
+ return false;
+}
+
+ccl_device void kernel_accum_shadow_catcher_transparent_only(KernelGlobals kg,
+ const uint32_t path_flag,
+ const float transparent,
+ ccl_global float *ccl_restrict buffer)
+{
+ if (!kernel_data.integrator.has_shadow_catcher) {
+ return;
+ }
+
+ kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED);
+
+ /* Matte pass. */
+ if (kernel_shadow_catcher_is_matte_path(path_flag)) {
+ kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3, transparent);
+ }
+}
+
+#endif /* __SHADOW_CATCHER__ */
+
+/* --------------------------------------------------------------------
+ * Render passes.
+ */
+
+/* Write combined pass. */
+ccl_device_inline void kernel_accum_combined_pass(KernelGlobals kg,
+ const uint32_t path_flag,
+ const int sample,
+ const float3 contribution,
+ ccl_global float *ccl_restrict buffer)
+{
+#ifdef __SHADOW_CATCHER__
+ if (kernel_accum_shadow_catcher(kg, path_flag, contribution, buffer)) {
+ return;
+ }
+#endif
+
+ if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) {
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_combined, contribution);
+ }
+
+ kernel_accum_adaptive_buffer(kg, sample, contribution, buffer);
+}
+
+/* Write combined pass with transparency. */
+ccl_device_inline void kernel_accum_combined_transparent_pass(KernelGlobals kg,
+ const uint32_t path_flag,
+ const int sample,
+ const float3 contribution,
+ const float transparent,
+ ccl_global float *ccl_restrict
+ buffer)
+{
+#ifdef __SHADOW_CATCHER__
+ if (kernel_accum_shadow_catcher_transparent(kg, path_flag, contribution, transparent, buffer)) {
+ return;
+ }
+#endif
+
+ if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) {
+ kernel_write_pass_float4(
+ buffer + kernel_data.film.pass_combined,
+ make_float4(contribution.x, contribution.y, contribution.z, transparent));
+ }
+
+ kernel_accum_adaptive_buffer(kg, sample, contribution, buffer);
+}
+
+/* Write background or emission to appropriate pass. */
+ccl_device_inline void kernel_accum_emission_or_background_pass(KernelGlobals kg,
+ ConstIntegratorState state,
+ float3 contribution,
+ ccl_global float *ccl_restrict
+ buffer,
+ const int pass)
+{
+ if (!(kernel_data.film.light_pass_flag & PASS_ANY)) {
+ return;
+ }
+
+#ifdef __PASSES__
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+ int pass_offset = PASS_UNUSED;
+
+ /* Denoising albedo. */
+# ifdef __DENOISING_FEATURES__
+ if (path_flag & PATH_RAY_DENOISING_FEATURES) {
+ if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) {
+ const float3 denoising_feature_throughput = INTEGRATOR_STATE(
+ state, path, denoising_feature_throughput);
+ const float3 denoising_albedo = denoising_feature_throughput * contribution;
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo);
+ }
+ }
+# endif /* __DENOISING_FEATURES__ */
+
+ if (!(path_flag & PATH_RAY_ANY_PASS)) {
+ /* Directly visible, write to emission or background pass. */
+ pass_offset = pass;
+ }
+ else if (path_flag & (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS)) {
+ /* Indirectly visible through reflection. */
+ const int glossy_pass_offset = (path_flag & PATH_RAY_REFLECT_PASS) ?
+ ((INTEGRATOR_STATE(state, path, bounce) == 1) ?
+ kernel_data.film.pass_glossy_direct :
+ kernel_data.film.pass_glossy_indirect) :
+ ((INTEGRATOR_STATE(state, path, bounce) == 1) ?
+ kernel_data.film.pass_transmission_direct :
+ kernel_data.film.pass_transmission_indirect);
+
+ if (glossy_pass_offset != PASS_UNUSED) {
+ /* Glossy is a subset of the throughput, reconstruct it here using the
+ * diffuse-glossy ratio. */
+ const float3 ratio = INTEGRATOR_STATE(state, path, diffuse_glossy_ratio);
+ const float3 glossy_contribution = (one_float3() - ratio) * contribution;
+ kernel_write_pass_float3(buffer + glossy_pass_offset, glossy_contribution);
+ }
+
+ /* Reconstruct diffuse subset of throughput. */
+ pass_offset = (INTEGRATOR_STATE(state, path, bounce) == 1) ?
+ kernel_data.film.pass_diffuse_direct :
+ kernel_data.film.pass_diffuse_indirect;
+ if (pass_offset != PASS_UNUSED) {
+ contribution *= INTEGRATOR_STATE(state, path, diffuse_glossy_ratio);
+ }
+ }
+ else if (path_flag & PATH_RAY_VOLUME_PASS) {
+ /* Indirectly visible through volume. */
+ pass_offset = (INTEGRATOR_STATE(state, path, bounce) == 1) ?
+ kernel_data.film.pass_volume_direct :
+ kernel_data.film.pass_volume_indirect;
+ }
+
+ /* Single write call for GPU coherence. */
+ if (pass_offset != PASS_UNUSED) {
+ kernel_write_pass_float3(buffer + pass_offset, contribution);
+ }
+#endif /* __PASSES__ */
+}
+
+/* Write light contribution to render buffer. */
+ccl_device_inline void kernel_accum_light(KernelGlobals kg,
+ ConstIntegratorShadowState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ /* The throughput for shadow paths already contains the light shader evaluation. */
+ float3 contribution = INTEGRATOR_STATE(state, shadow_path, throughput);
+ kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, shadow_path, bounce));
+
+ const uint32_t render_pixel_index = INTEGRATOR_STATE(state, shadow_path, render_pixel_index);
+ const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
+ kernel_data.film.pass_stride;
+ ccl_global float *buffer = render_buffer + render_buffer_offset;
+
+ const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag);
+ const int sample = INTEGRATOR_STATE(state, shadow_path, sample);
+
+ /* Ambient occlusion. */
+ if (path_flag & PATH_RAY_SHADOW_FOR_AO) {
+ if ((kernel_data.kernel_features & KERNEL_FEATURE_AO_PASS) && (path_flag & PATH_RAY_CAMERA)) {
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_ao, contribution);
+ }
+ if (kernel_data.kernel_features & KERNEL_FEATURE_AO_ADDITIVE) {
+ const float3 ao_weight = INTEGRATOR_STATE(state, shadow_path, unshadowed_throughput);
+ kernel_accum_combined_pass(kg, path_flag, sample, contribution * ao_weight, buffer);
+ }
+ return;
+ }
+
+ /* Direct light shadow. */
+ kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer);
+
+#ifdef __PASSES__
+ if (kernel_data.film.light_pass_flag & PASS_ANY) {
+ const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag);
+ int pass_offset = PASS_UNUSED;
+
+ if (path_flag & (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS)) {
+ /* Indirectly visible through reflection. */
+ const int glossy_pass_offset = (path_flag & PATH_RAY_REFLECT_PASS) ?
+ ((INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ?
+ kernel_data.film.pass_glossy_direct :
+ kernel_data.film.pass_glossy_indirect) :
+ ((INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ?
+ kernel_data.film.pass_transmission_direct :
+ kernel_data.film.pass_transmission_indirect);
+
+ if (glossy_pass_offset != PASS_UNUSED) {
+ /* Glossy is a subset of the throughput, reconstruct it here using the
+ * diffuse-glossy ratio. */
+ const float3 ratio = INTEGRATOR_STATE(state, shadow_path, diffuse_glossy_ratio);
+ const float3 glossy_contribution = (one_float3() - ratio) * contribution;
+ kernel_write_pass_float3(buffer + glossy_pass_offset, glossy_contribution);
+ }
+
+ /* Reconstruct diffuse subset of throughput. */
+ pass_offset = (INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ?
+ kernel_data.film.pass_diffuse_direct :
+ kernel_data.film.pass_diffuse_indirect;
+ if (pass_offset != PASS_UNUSED) {
+ contribution *= INTEGRATOR_STATE(state, shadow_path, diffuse_glossy_ratio);
+ }
+ }
+ else if (path_flag & PATH_RAY_VOLUME_PASS) {
+ /* Indirectly visible through volume. */
+ pass_offset = (INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ?
+ kernel_data.film.pass_volume_direct :
+ kernel_data.film.pass_volume_indirect;
+ }
+
+ /* Single write call for GPU coherence. */
+ if (pass_offset != PASS_UNUSED) {
+ kernel_write_pass_float3(buffer + pass_offset, contribution);
+ }
+
+ /* Write shadow pass. */
+ if (kernel_data.film.pass_shadow != PASS_UNUSED && (path_flag & PATH_RAY_SHADOW_FOR_LIGHT) &&
+ (path_flag & PATH_RAY_CAMERA)) {
+ const float3 unshadowed_throughput = INTEGRATOR_STATE(
+ state, shadow_path, unshadowed_throughput);
+ const float3 shadowed_throughput = INTEGRATOR_STATE(state, shadow_path, throughput);
+ const float3 shadow = safe_divide_float3_float3(shadowed_throughput, unshadowed_throughput) *
+ kernel_data.film.pass_shadow_scale;
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow, shadow);
+ }
+ }
+#endif
+}
+
+/* Write transparency to render buffer.
+ *
+ * Note that we accumulate transparency = 1 - alpha in the render buffer.
+ * Otherwise we'd have to write alpha on path termination, which happens
+ * in many places. */
+ccl_device_inline void kernel_accum_transparent(KernelGlobals kg,
+ ConstIntegratorState state,
+ const uint32_t path_flag,
+ const float transparent,
+ ccl_global float *ccl_restrict buffer)
+{
+ if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) {
+ kernel_write_pass_float(buffer + kernel_data.film.pass_combined + 3, transparent);
+ }
+
+ kernel_accum_shadow_catcher_transparent_only(kg, path_flag, transparent, buffer);
+}
+
+/* Write holdout to render buffer. */
+ccl_device_inline void kernel_accum_holdout(KernelGlobals kg,
+ ConstIntegratorState state,
+ const uint32_t path_flag,
+ const float transparent,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer);
+ kernel_accum_transparent(kg, state, path_flag, transparent, buffer);
+}
+
+/* Write background contribution to render buffer.
+ *
+ * Includes transparency, matching kernel_accum_transparent. */
+ccl_device_inline void kernel_accum_background(KernelGlobals kg,
+ ConstIntegratorState state,
+ const float3 L,
+ const float transparent,
+ const bool is_transparent_background_ray,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ float3 contribution = INTEGRATOR_STATE(state, path, throughput) * L;
+ kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1);
+
+ ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer);
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ if (is_transparent_background_ray) {
+ kernel_accum_transparent(kg, state, path_flag, transparent, buffer);
+ }
+ else {
+ const int sample = INTEGRATOR_STATE(state, path, sample);
+ kernel_accum_combined_transparent_pass(
+ kg, path_flag, sample, contribution, transparent, buffer);
+ }
+ kernel_accum_emission_or_background_pass(
+ kg, state, contribution, buffer, kernel_data.film.pass_background);
+}
+
+/* Write emission to render buffer. */
+ccl_device_inline void kernel_accum_emission(KernelGlobals kg,
+ ConstIntegratorState state,
+ const float3 throughput,
+ const float3 L,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ float3 contribution = throughput * L;
+ kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1);
+
+ ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer);
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+ const int sample = INTEGRATOR_STATE(state, path, sample);
+
+ kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer);
+ kernel_accum_emission_or_background_pass(
+ kg, state, contribution, buffer, kernel_data.film.pass_emission);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/film/adaptive_sampling.h b/intern/cycles/kernel/film/adaptive_sampling.h
new file mode 100644
index 00000000000..468c5d4486e
--- /dev/null
+++ b/intern/cycles/kernel/film/adaptive_sampling.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2019 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/film/write_passes.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Check whether the pixel has converged and should not be sampled anymore. */
+
+ccl_device_forceinline bool kernel_need_sample_pixel(KernelGlobals kg,
+ ConstIntegratorState state,
+ ccl_global float *render_buffer)
+{
+ if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) {
+ return true;
+ }
+
+ const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
+ const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
+ kernel_data.film.pass_stride;
+ ccl_global float *buffer = render_buffer + render_buffer_offset;
+
+ const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
+ return buffer[aux_w_offset] == 0.0f;
+}
+
+/* Determines whether to continue sampling a given pixel or if it has sufficiently converged. */
+
+ccl_device bool kernel_adaptive_sampling_convergence_check(KernelGlobals kg,
+ ccl_global float *render_buffer,
+ int x,
+ int y,
+ float threshold,
+ bool reset,
+ int offset,
+ int stride)
+{
+ kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED);
+ kernel_assert(kernel_data.film.pass_sample_count != PASS_UNUSED);
+
+ const int render_pixel_index = offset + x + y * stride;
+ ccl_global float *buffer = render_buffer +
+ (uint64_t)render_pixel_index * kernel_data.film.pass_stride;
+
+ /* TODO(Stefan): Is this better in linear, sRGB or something else? */
+
+ const float4 A = kernel_read_pass_float4(buffer + kernel_data.film.pass_adaptive_aux_buffer);
+ if (!reset && A.w != 0.0f) {
+ /* If the pixel was considered converged, its state will not change in this kernel. Early
+ * output before doing any math.
+ *
+ * TODO(sergey): On a GPU it might be better to keep thread alive for better coherency? */
+ return true;
+ }
+
+ const float4 I = kernel_read_pass_float4(buffer + kernel_data.film.pass_combined);
+
+ const float sample = __float_as_uint(buffer[kernel_data.film.pass_sample_count]);
+ const float inv_sample = 1.0f / sample;
+
+ /* The per pixel error as seen in section 2.1 of
+ * "A hierarchical automatic stopping condition for Monte Carlo global illumination" */
+ const float error_difference = (fabsf(I.x - A.x) + fabsf(I.y - A.y) + fabsf(I.z - A.z)) *
+ inv_sample;
+ const float error_normalize = sqrtf((I.x + I.y + I.z) * inv_sample);
+ /* A small epsilon is added to the divisor to prevent division by zero. */
+ const float error = error_difference / (0.0001f + error_normalize);
+ const bool did_converge = (error < threshold);
+
+ const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
+ buffer[aux_w_offset] = did_converge;
+
+ return did_converge;
+}
+
+/* This is a simple box filter in two passes.
+ * When a pixel demands more adaptive samples, let its neighboring pixels draw more samples too. */
+
+ccl_device void kernel_adaptive_sampling_filter_x(KernelGlobals kg,
+ ccl_global float *render_buffer,
+ int y,
+ int start_x,
+ int width,
+ int offset,
+ int stride)
+{
+ kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED);
+
+ bool prev = false;
+ for (int x = start_x; x < start_x + width; ++x) {
+ int index = offset + x + y * stride;
+ ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride;
+ const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
+
+ if (buffer[aux_w_offset] == 0.0f) {
+ if (x > start_x && !prev) {
+ index = index - 1;
+ buffer = render_buffer + index * kernel_data.film.pass_stride;
+ buffer[aux_w_offset] = 0.0f;
+ }
+ prev = true;
+ }
+ else {
+ if (prev) {
+ buffer[aux_w_offset] = 0.0f;
+ }
+ prev = false;
+ }
+ }
+}
+
+ccl_device void kernel_adaptive_sampling_filter_y(KernelGlobals kg,
+ ccl_global float *render_buffer,
+ int x,
+ int start_y,
+ int height,
+ int offset,
+ int stride)
+{
+ kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED);
+
+ bool prev = false;
+ for (int y = start_y; y < start_y + height; ++y) {
+ int index = offset + x + y * stride;
+ ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride;
+ const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
+
+ if (buffer[aux_w_offset] == 0.0f) {
+ if (y > start_y && !prev) {
+ index = index - stride;
+ buffer = render_buffer + index * kernel_data.film.pass_stride;
+ buffer[aux_w_offset] = 0.0f;
+ }
+ prev = true;
+ }
+ else {
+ if (prev) {
+ buffer[aux_w_offset] = 0.0f;
+ }
+ prev = false;
+ }
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_id_passes.h b/intern/cycles/kernel/film/id_passes.h
index d5b8c90a828..d5b8c90a828 100644
--- a/intern/cycles/kernel/kernel_id_passes.h
+++ b/intern/cycles/kernel/film/id_passes.h
diff --git a/intern/cycles/kernel/film/passes.h b/intern/cycles/kernel/film/passes.h
new file mode 100644
index 00000000000..22b4b779a17
--- /dev/null
+++ b/intern/cycles/kernel/film/passes.h
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/geom/geom.h"
+
+#include "kernel/film/id_passes.h"
+#include "kernel/film/write_passes.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Get pointer to pixel in render buffer. */
+ccl_device_forceinline ccl_global float *kernel_pass_pixel_render_buffer(
+ KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer)
+{
+ const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
+ const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
+ kernel_data.film.pass_stride;
+ return render_buffer + render_buffer_offset;
+}
+
+#ifdef __DENOISING_FEATURES__
+
+ccl_device_forceinline void kernel_write_denoising_features_surface(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const ShaderData *sd,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_DENOISING_FEATURES)) {
+ return;
+ }
+
+ /* Skip implicitly transparent surfaces. */
+ if (sd->flag & SD_HAS_ONLY_VOLUME) {
+ return;
+ }
+
+ ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer);
+
+ if (kernel_data.film.pass_denoising_depth != PASS_UNUSED) {
+ const float3 denoising_feature_throughput = INTEGRATOR_STATE(
+ state, path, denoising_feature_throughput);
+ const float denoising_depth = ensure_finite(average(denoising_feature_throughput) *
+ sd->ray_length);
+ kernel_write_pass_float(buffer + kernel_data.film.pass_denoising_depth, denoising_depth);
+ }
+
+ float3 normal = zero_float3();
+ float3 diffuse_albedo = zero_float3();
+ float3 specular_albedo = zero_float3();
+ float sum_weight = 0.0f, sum_nonspecular_weight = 0.0f;
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (!CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
+ continue;
+ }
+
+ /* All closures contribute to the normal feature, but only diffuse-like ones to the albedo. */
+ normal += sc->N * sc->sample_weight;
+ sum_weight += sc->sample_weight;
+
+ float3 closure_albedo = sc->weight;
+ /* Closures that include a Fresnel term typically have weights close to 1 even though their
+ * actual contribution is significantly lower.
+ * To account for this, we scale their weight by the average fresnel factor (the same is also
+ * done for the sample weight in the BSDF setup, so we don't need to scale that here). */
+ if (CLOSURE_IS_BSDF_MICROFACET_FRESNEL(sc->type)) {
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc;
+ closure_albedo *= bsdf->extra->fresnel_color;
+ }
+ else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) {
+ ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)sc;
+ closure_albedo *= bsdf->avg_value;
+ }
+ else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
+ closure_albedo *= bsdf_principled_hair_albedo(sc);
+ }
+
+ if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) {
+ diffuse_albedo += closure_albedo;
+ sum_nonspecular_weight += sc->sample_weight;
+ }
+ else {
+ specular_albedo += closure_albedo;
+ }
+ }
+
+ /* Wait for next bounce if 75% or more sample weight belongs to specular-like closures. */
+ if ((sum_weight == 0.0f) || (sum_nonspecular_weight * 4.0f > sum_weight)) {
+ if (sum_weight != 0.0f) {
+ normal /= sum_weight;
+ }
+
+ if (kernel_data.film.pass_denoising_normal != PASS_UNUSED) {
+ /* Transform normal into camera space. */
+ const Transform worldtocamera = kernel_data.cam.worldtocamera;
+ normal = transform_direction(&worldtocamera, normal);
+
+ const float3 denoising_normal = ensure_finite3(normal);
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal);
+ }
+
+ if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) {
+ const float3 denoising_feature_throughput = INTEGRATOR_STATE(
+ state, path, denoising_feature_throughput);
+ const float3 denoising_albedo = ensure_finite3(denoising_feature_throughput *
+ diffuse_albedo);
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo);
+ }
+
+ INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES;
+ }
+ else {
+ INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) *= specular_albedo;
+ }
+}
+
+ccl_device_forceinline void kernel_write_denoising_features_volume(KernelGlobals kg,
+ IntegratorState state,
+ const float3 albedo,
+ const bool scatter,
+ ccl_global float *ccl_restrict
+ render_buffer)
+{
+ ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer);
+ const float3 denoising_feature_throughput = INTEGRATOR_STATE(
+ state, path, denoising_feature_throughput);
+
+ if (scatter && kernel_data.film.pass_denoising_normal != PASS_UNUSED) {
+ /* Assume scatter is sufficiently diffuse to stop writing denoising features. */
+ INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES;
+
+ /* Write view direction as normal. */
+ const float3 denoising_normal = make_float3(0.0f, 0.0f, -1.0f);
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal);
+ }
+
+ if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) {
+ /* Write albedo. */
+ const float3 denoising_albedo = ensure_finite3(denoising_feature_throughput * albedo);
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo);
+ }
+}
+#endif /* __DENOISING_FEATURES__ */
+
+#ifdef __SHADOW_CATCHER__
+
+/* Write shadow catcher passes on a bounce from the shadow catcher object. */
+ccl_device_forceinline void kernel_write_shadow_catcher_bounce_data(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const ShaderData *sd,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ if (!kernel_data.integrator.has_shadow_catcher) {
+ return;
+ }
+
+ kernel_assert(kernel_data.film.pass_shadow_catcher_sample_count != PASS_UNUSED);
+ kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED);
+
+ if (!kernel_shadow_catcher_is_path_split_bounce(kg, state, sd->object_flag)) {
+ return;
+ }
+
+ ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer);
+
+ /* Count sample for the shadow catcher object. */
+ kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_sample_count, 1.0f);
+
+ /* Since the split is done, the sample does not contribute to the matte, so accumulate it as
+ * transparency to the matte. */
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3,
+ average(throughput));
+}
+
+#endif /* __SHADOW_CATCHER__ */
+
+ccl_device_inline size_t kernel_write_id_pass(ccl_global float *ccl_restrict buffer,
+ size_t depth,
+ float id,
+ float matte_weight)
+{
+ kernel_write_id_slots(buffer, depth * 2, id, matte_weight);
+ return depth * 4;
+}
+
+ccl_device_inline void kernel_write_data_passes(KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const ShaderData *sd,
+ ccl_global float *ccl_restrict render_buffer)
+{
+#ifdef __PASSES__
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ if (!(path_flag & PATH_RAY_CAMERA)) {
+ return;
+ }
+
+ const int flag = kernel_data.film.pass_flag;
+
+ if (!(flag & PASS_ANY)) {
+ return;
+ }
+
+ ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer);
+
+ if (!(path_flag & PATH_RAY_SINGLE_PASS_DONE)) {
+ if (!(sd->flag & SD_TRANSPARENT) || kernel_data.film.pass_alpha_threshold == 0.0f ||
+ average(shader_bsdf_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold) {
+ if (INTEGRATOR_STATE(state, path, sample) == 0) {
+ if (flag & PASSMASK(DEPTH)) {
+ const float depth = camera_z_depth(kg, sd->P);
+ kernel_write_pass_float(buffer + kernel_data.film.pass_depth, depth);
+ }
+ if (flag & PASSMASK(OBJECT_ID)) {
+ const float id = object_pass_id(kg, sd->object);
+ kernel_write_pass_float(buffer + kernel_data.film.pass_object_id, id);
+ }
+ if (flag & PASSMASK(MATERIAL_ID)) {
+ const float id = shader_pass_id(kg, sd);
+ kernel_write_pass_float(buffer + kernel_data.film.pass_material_id, id);
+ }
+ if (flag & PASSMASK(POSITION)) {
+ const float3 position = sd->P;
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_position, position);
+ }
+ }
+
+ if (flag & PASSMASK(NORMAL)) {
+ const float3 normal = shader_bsdf_average_normal(kg, sd);
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, normal);
+ }
+ if (flag & PASSMASK(ROUGHNESS)) {
+ const float roughness = shader_bsdf_average_roughness(sd);
+ kernel_write_pass_float(buffer + kernel_data.film.pass_roughness, roughness);
+ }
+ if (flag & PASSMASK(UV)) {
+ const float3 uv = primitive_uv(kg, sd);
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, uv);
+ }
+ if (flag & PASSMASK(MOTION)) {
+ const float4 speed = primitive_motion_vector(kg, sd);
+ kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, speed);
+ kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, 1.0f);
+ }
+
+ INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SINGLE_PASS_DONE;
+ }
+ }
+
+ if (kernel_data.film.cryptomatte_passes) {
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ const float matte_weight = average(throughput) *
+ (1.0f - average(shader_bsdf_transparency(kg, sd)));
+ if (matte_weight > 0.0f) {
+ ccl_global float *cryptomatte_buffer = buffer + kernel_data.film.pass_cryptomatte;
+ if (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) {
+ const float id = object_cryptomatte_id(kg, sd->object);
+ cryptomatte_buffer += kernel_write_id_pass(
+ cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight);
+ }
+ if (kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) {
+ const float id = shader_cryptomatte_id(kg, sd->shader);
+ cryptomatte_buffer += kernel_write_id_pass(
+ cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight);
+ }
+ if (kernel_data.film.cryptomatte_passes & CRYPT_ASSET) {
+ const float id = object_cryptomatte_asset_id(kg, sd->object);
+ cryptomatte_buffer += kernel_write_id_pass(
+ cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight);
+ }
+ }
+ }
+
+ if (flag & PASSMASK(DIFFUSE_COLOR)) {
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_diffuse_color,
+ shader_bsdf_diffuse(kg, sd) * throughput);
+ }
+ if (flag & PASSMASK(GLOSSY_COLOR)) {
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_glossy_color,
+ shader_bsdf_glossy(kg, sd) * throughput);
+ }
+ if (flag & PASSMASK(TRANSMISSION_COLOR)) {
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_transmission_color,
+ shader_bsdf_transmission(kg, sd) * throughput);
+ }
+ if (flag & PASSMASK(MIST)) {
+ /* Bring depth into 0..1 range. */
+ const float mist_start = kernel_data.film.mist_start;
+ const float mist_inv_depth = kernel_data.film.mist_inv_depth;
+
+ const float depth = camera_distance(kg, sd->P);
+ float mist = saturatef((depth - mist_start) * mist_inv_depth);
+
+ /* Falloff */
+ const float mist_falloff = kernel_data.film.mist_falloff;
+
+ if (mist_falloff == 1.0f)
+ ;
+ else if (mist_falloff == 2.0f)
+ mist = mist * mist;
+ else if (mist_falloff == 0.5f)
+ mist = sqrtf(mist);
+ else
+ mist = powf(mist, mist_falloff);
+
+ /* Modulate by transparency */
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ const float3 alpha = shader_bsdf_alpha(kg, sd);
+ const float mist_output = (1.0f - mist) * average(throughput * alpha);
+
+ /* Note that the final value in the render buffer we want is 1 - mist_output,
+ * to avoid having to tracking this in the Integrator state we do the negation
+ * after rendering. */
+ kernel_write_pass_float(buffer + kernel_data.film.pass_mist, mist_output);
+ }
+#endif
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/film/read.h b/intern/cycles/kernel/film/read.h
new file mode 100644
index 00000000000..d308a9818e2
--- /dev/null
+++ b/intern/cycles/kernel/film/read.h
@@ -0,0 +1,532 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* --------------------------------------------------------------------
+ * Common utilities.
+ */
+
+/* The input buffer contains transparency = 1 - alpha, this converts it to
+ * alpha. Also clamp since alpha might end up outside of 0..1 due to Russian
+ * roulette. */
+ccl_device_forceinline float film_transparency_to_alpha(float transparency)
+{
+ return saturatef(1.0f - transparency);
+}
+
+ccl_device_inline float film_get_scale(ccl_global const KernelFilmConvert *ccl_restrict
+ kfilm_convert,
+ ccl_global const float *ccl_restrict buffer)
+{
+ if (kfilm_convert->pass_sample_count == PASS_UNUSED) {
+ return kfilm_convert->scale;
+ }
+
+ if (kfilm_convert->pass_use_filter) {
+ const uint sample_count = *(
+ (ccl_global const uint *)(buffer + kfilm_convert->pass_sample_count));
+ return 1.0f / sample_count;
+ }
+
+ return 1.0f;
+}
+
+ccl_device_inline float film_get_scale_exposure(ccl_global const KernelFilmConvert *ccl_restrict
+ kfilm_convert,
+ ccl_global const float *ccl_restrict buffer)
+{
+ if (kfilm_convert->pass_sample_count == PASS_UNUSED) {
+ return kfilm_convert->scale_exposure;
+ }
+
+ const float scale = film_get_scale(kfilm_convert, buffer);
+
+ if (kfilm_convert->pass_use_exposure) {
+ return scale * kfilm_convert->exposure;
+ }
+
+ return scale;
+}
+
+ccl_device_inline bool film_get_scale_and_scale_exposure(
+ ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict scale,
+ ccl_private float *ccl_restrict scale_exposure)
+{
+ if (kfilm_convert->pass_sample_count == PASS_UNUSED) {
+ *scale = kfilm_convert->scale;
+ *scale_exposure = kfilm_convert->scale_exposure;
+ return true;
+ }
+
+ const uint sample_count = *(
+ (ccl_global const uint *)(buffer + kfilm_convert->pass_sample_count));
+ if (!sample_count) {
+ *scale = 0.0f;
+ *scale_exposure = 0.0f;
+ return false;
+ }
+
+ if (kfilm_convert->pass_use_filter) {
+ *scale = 1.0f / sample_count;
+ }
+ else {
+ *scale = 1.0f;
+ }
+
+ if (kfilm_convert->pass_use_exposure) {
+ *scale_exposure = *scale * kfilm_convert->exposure;
+ }
+ else {
+ *scale_exposure = *scale;
+ }
+
+ return true;
+}
+
+/* --------------------------------------------------------------------
+ * Float (scalar) passes.
+ */
+
+ccl_device_inline void film_get_pass_pixel_depth(ccl_global const KernelFilmConvert *ccl_restrict
+ kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components >= 1);
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+
+ const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer);
+
+ ccl_global const float *in = buffer + kfilm_convert->pass_offset;
+ const float f = *in;
+
+ pixel[0] = (f == 0.0f) ? 1e10f : f * scale_exposure;
+}
+
+ccl_device_inline void film_get_pass_pixel_mist(ccl_global const KernelFilmConvert *ccl_restrict
+ kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components >= 1);
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+
+ const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer);
+
+ ccl_global const float *in = buffer + kfilm_convert->pass_offset;
+ const float f = *in;
+
+ /* Note that we accumulate 1 - mist in the kernel to avoid having to
+ * track the mist values in the integrator state. */
+ pixel[0] = saturatef(1.0f - f * scale_exposure);
+}
+
+ccl_device_inline void film_get_pass_pixel_sample_count(
+ ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ /* TODO(sergey): Consider normalizing into the [0..1] range, so that it is possible to see
+ * meaningful value when adaptive sampler stopped rendering image way before the maximum
+ * number of samples was reached (for examples when number of samples is set to 0 in
+ * viewport). */
+
+ kernel_assert(kfilm_convert->num_components >= 1);
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+
+ ccl_global const float *in = buffer + kfilm_convert->pass_offset;
+ const float f = *in;
+
+ pixel[0] = __float_as_uint(f) * kfilm_convert->scale;
+}
+
+ccl_device_inline void film_get_pass_pixel_float(ccl_global const KernelFilmConvert *ccl_restrict
+ kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components >= 1);
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+
+ const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer);
+
+ ccl_global const float *in = buffer + kfilm_convert->pass_offset;
+ const float f = *in;
+
+ pixel[0] = f * scale_exposure;
+}
+
+/* --------------------------------------------------------------------
+ * Float 3 passes.
+ */
+
+ccl_device_inline void film_get_pass_pixel_light_path(
+ ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components >= 3);
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+
+ /* Read light pass. */
+ ccl_global const float *in = buffer + kfilm_convert->pass_offset;
+ float3 f = make_float3(in[0], in[1], in[2]);
+
+ /* Optionally add indirect light pass. */
+ if (kfilm_convert->pass_indirect != PASS_UNUSED) {
+ ccl_global const float *in_indirect = buffer + kfilm_convert->pass_indirect;
+ const float3 f_indirect = make_float3(in_indirect[0], in_indirect[1], in_indirect[2]);
+ f += f_indirect;
+ }
+
+ /* Optionally divide out color. */
+ if (kfilm_convert->pass_divide != PASS_UNUSED) {
+ ccl_global const float *in_divide = buffer + kfilm_convert->pass_divide;
+ const float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]);
+ f = safe_divide_even_color(f, f_divide);
+
+ /* Exposure only, sample scale cancels out. */
+ f *= kfilm_convert->exposure;
+ }
+ else {
+ /* Sample scale and exposure. */
+ f *= film_get_scale_exposure(kfilm_convert, buffer);
+ }
+
+ pixel[0] = f.x;
+ pixel[1] = f.y;
+ pixel[2] = f.z;
+}
+
+ccl_device_inline void film_get_pass_pixel_float3(ccl_global const KernelFilmConvert *ccl_restrict
+ kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components >= 3);
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+
+ const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer);
+
+ ccl_global const float *in = buffer + kfilm_convert->pass_offset;
+
+ const float3 f = make_float3(in[0], in[1], in[2]) * scale_exposure;
+
+ pixel[0] = f.x;
+ pixel[1] = f.y;
+ pixel[2] = f.z;
+}
+
+/* --------------------------------------------------------------------
+ * Float4 passes.
+ */
+
+ccl_device_inline void film_get_pass_pixel_motion(ccl_global const KernelFilmConvert *ccl_restrict
+ kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components == 4);
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+ kernel_assert(kfilm_convert->pass_motion_weight != PASS_UNUSED);
+
+ ccl_global const float *in = buffer + kfilm_convert->pass_offset;
+ ccl_global const float *in_weight = buffer + kfilm_convert->pass_motion_weight;
+
+ const float weight = in_weight[0];
+ const float weight_inv = (weight > 0.0f) ? 1.0f / weight : 0.0f;
+
+ const float4 motion = make_float4(in[0], in[1], in[2], in[3]) * weight_inv;
+
+ pixel[0] = motion.x;
+ pixel[1] = motion.y;
+ pixel[2] = motion.z;
+ pixel[3] = motion.w;
+}
+
+ccl_device_inline void film_get_pass_pixel_cryptomatte(
+ ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components == 4);
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+
+ const float scale = film_get_scale(kfilm_convert, buffer);
+
+ ccl_global const float *in = buffer + kfilm_convert->pass_offset;
+
+ const float4 f = make_float4(in[0], in[1], in[2], in[3]);
+
+ /* x and z contain integer IDs, don't rescale them.
+ * y and w contain matte weights, they get scaled. */
+ pixel[0] = f.x;
+ pixel[1] = f.y * scale;
+ pixel[2] = f.z;
+ pixel[3] = f.w * scale;
+}
+
+ccl_device_inline void film_get_pass_pixel_float4(ccl_global const KernelFilmConvert *ccl_restrict
+ kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components == 4);
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+
+ float scale, scale_exposure;
+ film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure);
+
+ ccl_global const float *in = buffer + kfilm_convert->pass_offset;
+
+ const float3 color = make_float3(in[0], in[1], in[2]) * scale_exposure;
+ const float alpha = in[3] * scale;
+
+ pixel[0] = color.x;
+ pixel[1] = color.y;
+ pixel[2] = color.z;
+ pixel[3] = alpha;
+}
+
+ccl_device_inline void film_get_pass_pixel_combined(
+ ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components == 4);
+
+ /* 3rd channel contains transparency = 1 - alpha for the combined pass. */
+
+ kernel_assert(kfilm_convert->num_components == 4);
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+
+ float scale, scale_exposure;
+ if (!film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure)) {
+ pixel[0] = 0.0f;
+ pixel[1] = 0.0f;
+ pixel[2] = 0.0f;
+ pixel[3] = 0.0f;
+ return;
+ }
+
+ ccl_global const float *in = buffer + kfilm_convert->pass_offset;
+
+ const float3 color = make_float3(in[0], in[1], in[2]) * scale_exposure;
+ const float alpha = in[3] * scale;
+
+ pixel[0] = color.x;
+ pixel[1] = color.y;
+ pixel[2] = color.z;
+ pixel[3] = film_transparency_to_alpha(alpha);
+}
+
+/* --------------------------------------------------------------------
+ * Shadow catcher.
+ */
+
+ccl_device_inline float3 film_calculate_shadow_catcher_denoised(
+ ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer)
+{
+ kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED);
+
+ float scale, scale_exposure;
+ film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure);
+
+ ccl_global const float *in_catcher = buffer + kfilm_convert->pass_shadow_catcher;
+
+ const float3 pixel = make_float3(in_catcher[0], in_catcher[1], in_catcher[2]) * scale_exposure;
+
+ return pixel;
+}
+
+ccl_device_inline float3 safe_divide_shadow_catcher(float3 a, float3 b)
+{
+ float x, y, z;
+
+ x = (b.x != 0.0f) ? a.x / b.x : 1.0f;
+ y = (b.y != 0.0f) ? a.y / b.y : 1.0f;
+ z = (b.z != 0.0f) ? a.z / b.z : 1.0f;
+
+ return make_float3(x, y, z);
+}
+
+ccl_device_inline float3
+film_calculate_shadow_catcher(ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer)
+{
+ /* For the shadow catcher pass we divide combined pass by the shadow catcher.
+ * Note that denoised shadow catcher pass contains value which only needs ot be scaled (but not
+ * to be calculated as division). */
+
+ if (kfilm_convert->is_denoised) {
+ return film_calculate_shadow_catcher_denoised(kfilm_convert, buffer);
+ }
+
+ kernel_assert(kfilm_convert->pass_shadow_catcher_sample_count != PASS_UNUSED);
+
+ /* If there is no shadow catcher object in this pixel, there is no modification of the light
+ * needed, so return one. */
+ ccl_global const float *in_catcher_sample_count =
+ buffer + kfilm_convert->pass_shadow_catcher_sample_count;
+ const float num_samples = in_catcher_sample_count[0];
+ if (num_samples == 0.0f) {
+ return one_float3();
+ }
+
+ kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED);
+ ccl_global const float *in_catcher = buffer + kfilm_convert->pass_shadow_catcher;
+
+ /* NOTE: It is possible that the Shadow Catcher pass is requested as an output without actual
+ * shadow catcher objects in the scene. In this case there will be no auxiliary passes required
+ * for the decision (to save up memory). So delay the asserts to this point so that the number of
+ * samples check handles such configuration. */
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+ kernel_assert(kfilm_convert->pass_combined != PASS_UNUSED);
+ kernel_assert(kfilm_convert->pass_shadow_catcher_matte != PASS_UNUSED);
+
+ ccl_global const float *in_combined = buffer + kfilm_convert->pass_combined;
+ ccl_global const float *in_matte = buffer + kfilm_convert->pass_shadow_catcher_matte;
+
+ /* No scaling needed. The integration works in way that number of samples in the combined and
+ * shadow catcher passes are the same, and exposure is canceled during the division. */
+ const float3 color_catcher = make_float3(in_catcher[0], in_catcher[1], in_catcher[2]);
+ const float3 color_combined = make_float3(in_combined[0], in_combined[1], in_combined[2]);
+ const float3 color_matte = make_float3(in_matte[0], in_matte[1], in_matte[2]);
+
+ /* Need to ignore contribution of the matte object when doing division (otherwise there will be
+ * artifacts caused by anti-aliasing). Since combined pass is used for adaptive sampling and need
+ * to contain matte objects, we subtract matte objects contribution here. This is the same as if
+ * the matte objects were not accumulated to the combined pass. */
+ const float3 combined_no_matte = color_combined - color_matte;
+
+ const float3 shadow_catcher = safe_divide_shadow_catcher(combined_no_matte, color_catcher);
+
+ const float scale = film_get_scale(kfilm_convert, buffer);
+ const float transparency = in_combined[3] * scale;
+ const float alpha = film_transparency_to_alpha(transparency);
+
+ /* Alpha-over on white using transparency of the combined pass. This allows to eliminate
+ * artifacts which are happening on an edge of a shadow catcher when using transparent film.
+ * Note that we treat shadow catcher as straight alpha here because alpha got canceled out
+ * during the division. */
+ const float3 pixel = (1.0f - alpha) * one_float3() + alpha * shadow_catcher;
+
+ return pixel;
+}
+
+ccl_device_inline float4 film_calculate_shadow_catcher_matte_with_shadow(
+ ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer)
+{
+ /* The approximation of the shadow is 1 - average(shadow_catcher_pass). A better approximation
+ * is possible.
+ *
+ * The matte is alpha-overed onto the shadow (which is kind of alpha-overing shadow onto footage,
+ * and then alpha-overing synthetic objects on top). */
+
+ kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
+ kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED);
+ kernel_assert(kfilm_convert->pass_shadow_catcher_matte != PASS_UNUSED);
+
+ float scale, scale_exposure;
+ if (!film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure)) {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+
+ ccl_global const float *in_matte = buffer + kfilm_convert->pass_shadow_catcher_matte;
+
+ const float3 shadow_catcher = film_calculate_shadow_catcher(kfilm_convert, buffer);
+ const float3 color_matte = make_float3(in_matte[0], in_matte[1], in_matte[2]) * scale_exposure;
+
+ const float transparency = in_matte[3] * scale;
+ const float alpha = saturatef(1.0f - transparency);
+
+ const float alpha_matte = (1.0f - alpha) * (1.0f - average(shadow_catcher)) + alpha;
+
+ if (kfilm_convert->use_approximate_shadow_catcher_background) {
+ kernel_assert(kfilm_convert->pass_background != PASS_UNUSED);
+
+ ccl_global const float *in_background = buffer + kfilm_convert->pass_background;
+ const float3 color_background = make_float3(
+ in_background[0], in_background[1], in_background[2]) *
+ scale_exposure;
+ const float3 alpha_over = color_matte + color_background * (1.0f - alpha_matte);
+ return make_float4(alpha_over.x, alpha_over.y, alpha_over.z, 1.0f);
+ }
+
+ return make_float4(color_matte.x, color_matte.y, color_matte.z, alpha_matte);
+}
+
+ccl_device_inline void film_get_pass_pixel_shadow_catcher(
+ ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components >= 3);
+
+ const float3 pixel_value = film_calculate_shadow_catcher(kfilm_convert, buffer);
+
+ pixel[0] = pixel_value.x;
+ pixel[1] = pixel_value.y;
+ pixel[2] = pixel_value.z;
+}
+
+ccl_device_inline void film_get_pass_pixel_shadow_catcher_matte_with_shadow(
+ ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ kernel_assert(kfilm_convert->num_components == 3 || kfilm_convert->num_components == 4);
+
+ const float4 pixel_value = film_calculate_shadow_catcher_matte_with_shadow(kfilm_convert,
+ buffer);
+
+ pixel[0] = pixel_value.x;
+ pixel[1] = pixel_value.y;
+ pixel[2] = pixel_value.z;
+ if (kfilm_convert->num_components == 4) {
+ pixel[3] = pixel_value.w;
+ }
+}
+
+/* --------------------------------------------------------------------
+ * Compositing and overlays.
+ */
+
+ccl_device_inline void film_apply_pass_pixel_overlays_rgba(
+ ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
+ ccl_global const float *ccl_restrict buffer,
+ ccl_private float *ccl_restrict pixel)
+{
+ if (kfilm_convert->show_active_pixels &&
+ kfilm_convert->pass_adaptive_aux_buffer != PASS_UNUSED) {
+ if (buffer[kfilm_convert->pass_adaptive_aux_buffer + 3] == 0.0f) {
+ const float3 active_rgb = make_float3(1.0f, 0.0f, 0.0f);
+ const float3 mix_rgb = interp(make_float3(pixel[0], pixel[1], pixel[2]), active_rgb, 0.5f);
+ pixel[0] = mix_rgb.x;
+ pixel[1] = mix_rgb.y;
+ pixel[2] = mix_rgb.z;
+ }
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_write_passes.h b/intern/cycles/kernel/film/write_passes.h
index 9d379495629..9d379495629 100644
--- a/intern/cycles/kernel/kernel_write_passes.h
+++ b/intern/cycles/kernel/film/write_passes.h
diff --git a/intern/cycles/kernel/geom/geom_attribute.h b/intern/cycles/kernel/geom/attribute.h
index 848e0430caa..848e0430caa 100644
--- a/intern/cycles/kernel/geom/geom_attribute.h
+++ b/intern/cycles/kernel/geom/attribute.h
diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/curve.h
index 7271193eef8..7271193eef8 100644
--- a/intern/cycles/kernel/geom/geom_curve.h
+++ b/intern/cycles/kernel/geom/curve.h
diff --git a/intern/cycles/kernel/geom/geom_curve_intersect.h b/intern/cycles/kernel/geom/curve_intersect.h
index fb0b80b281f..fb0b80b281f 100644
--- a/intern/cycles/kernel/geom/geom_curve_intersect.h
+++ b/intern/cycles/kernel/geom/curve_intersect.h
diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h
index 4de824cc277..9d023375a35 100644
--- a/intern/cycles/kernel/geom/geom.h
+++ b/intern/cycles/kernel/geom/geom.h
@@ -17,21 +17,21 @@
#pragma once
// clang-format off
-#include "kernel/geom/geom_attribute.h"
-#include "kernel/geom/geom_object.h"
+#include "kernel/geom/attribute.h"
+#include "kernel/geom/object.h"
#ifdef __PATCH_EVAL__
-# include "kernel/geom/geom_patch.h"
+# include "kernel/geom/patch.h"
#endif
-#include "kernel/geom/geom_triangle.h"
-#include "kernel/geom/geom_subd_triangle.h"
-#include "kernel/geom/geom_triangle_intersect.h"
-#include "kernel/geom/geom_motion_triangle.h"
-#include "kernel/geom/geom_motion_triangle_intersect.h"
-#include "kernel/geom/geom_motion_triangle_shader.h"
-#include "kernel/geom/geom_motion_curve.h"
-#include "kernel/geom/geom_curve.h"
-#include "kernel/geom/geom_curve_intersect.h"
-#include "kernel/geom/geom_volume.h"
-#include "kernel/geom/geom_primitive.h"
-#include "kernel/geom/geom_shader_data.h"
+#include "kernel/geom/triangle.h"
+#include "kernel/geom/subd_triangle.h"
+#include "kernel/geom/triangle_intersect.h"
+#include "kernel/geom/motion_triangle.h"
+#include "kernel/geom/motion_triangle_intersect.h"
+#include "kernel/geom/motion_triangle_shader.h"
+#include "kernel/geom/motion_curve.h"
+#include "kernel/geom/curve.h"
+#include "kernel/geom/curve_intersect.h"
+#include "kernel/geom/volume.h"
+#include "kernel/geom/primitive.h"
+#include "kernel/geom/shader_data.h"
// clang-format on
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h
deleted file mode 100644
index 69d15f950ec..00000000000
--- a/intern/cycles/kernel/geom/geom_motion_triangle.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Motion Triangle Primitive
- *
- * These are stored as regular triangles, plus extra positions and normals at
- * times other than the frame center. Computing the triangle vertex positions
- * or normals at a given ray time is a matter of interpolation of the two steps
- * between which the ray time lies.
- *
- * The extra positions and normals are stored as ATTR_STD_MOTION_VERTEX_POSITION
- * and ATTR_STD_MOTION_VERTEX_NORMAL mesh attributes.
- */
-
-#pragma once
-
-#include "kernel/bvh/bvh_util.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Time interpolation of vertex positions and normals */
-
-ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals kg,
- uint4 tri_vindex,
- int offset,
- int numverts,
- int numsteps,
- int step,
- float3 verts[3])
-{
- if (step == numsteps) {
- /* center step: regular vertex location */
- verts[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 0));
- verts[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 1));
- verts[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 2));
- }
- else {
- /* center step not store in this array */
- if (step > numsteps)
- step--;
-
- offset += step * numverts;
-
- verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
- verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
- verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
- }
-}
-
-ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg,
- uint4 tri_vindex,
- int offset,
- int numverts,
- int numsteps,
- int step,
- float3 normals[3])
-{
- if (step == numsteps) {
- /* center step: regular vertex location */
- normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
- normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
- normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
- }
- else {
- /* center step is not stored in this array */
- if (step > numsteps)
- step--;
-
- offset += step * numverts;
-
- normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
- normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
- normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
- }
-}
-
-ccl_device_inline void motion_triangle_vertices(
- KernelGlobals kg, int object, int prim, float time, float3 verts[3])
-{
- /* get motion info */
- int numsteps, numverts;
- object_motion_info(kg, object, &numsteps, &numverts, NULL);
-
- /* figure out which steps we need to fetch and their interpolation factor */
- int maxstep = numsteps * 2;
- int step = min((int)(time * maxstep), maxstep - 1);
- float t = time * maxstep - step;
-
- /* find attribute */
- int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_POSITION);
- kernel_assert(offset != ATTR_STD_NOT_FOUND);
-
- /* fetch vertex coordinates */
- float3 next_verts[3];
- uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
-
- motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
- motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step + 1, next_verts);
-
- /* interpolate between steps */
- verts[0] = (1.0f - t) * verts[0] + t * next_verts[0];
- verts[1] = (1.0f - t) * verts[1] + t * next_verts[1];
- verts[2] = (1.0f - t) * verts[2] + t * next_verts[2];
-}
-
-ccl_device_inline float3 motion_triangle_smooth_normal(
- KernelGlobals kg, float3 Ng, int object, int prim, float u, float v, float time)
-{
- /* get motion info */
- int numsteps, numverts;
- object_motion_info(kg, object, &numsteps, &numverts, NULL);
-
- /* figure out which steps we need to fetch and their interpolation factor */
- int maxstep = numsteps * 2;
- int step = min((int)(time * maxstep), maxstep - 1);
- float t = time * maxstep - step;
-
- /* find attribute */
- int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_NORMAL);
- kernel_assert(offset != ATTR_STD_NOT_FOUND);
-
- /* fetch normals */
- float3 normals[3], next_normals[3];
- uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
-
- motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals);
- motion_triangle_normals_for_step(
- kg, tri_vindex, offset, numverts, numsteps, step + 1, next_normals);
-
- /* interpolate between steps */
- normals[0] = (1.0f - t) * normals[0] + t * next_normals[0];
- normals[1] = (1.0f - t) * normals[1] + t * next_normals[1];
- normals[2] = (1.0f - t) * normals[2] + t * next_normals[2];
-
- /* interpolate between vertices */
- float w = 1.0f - u - v;
- float3 N = safe_normalize(u * normals[0] + v * normals[1] + w * normals[2]);
-
- return is_zero(N) ? Ng : N;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_patch.h b/intern/cycles/kernel/geom/geom_patch.h
deleted file mode 100644
index bd797ef52ab..00000000000
--- a/intern/cycles/kernel/geom/geom_patch.h
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Based on code from OpenSubdiv released under this license:
- *
- * Copyright 2013 Pixar
- *
- * Licensed under the Apache License, Version 2.0 (the "Apache License")
- * with the following modification; you may not use this file except in
- * compliance with the Apache License and the following modification to it:
- * Section 6. Trademarks. is deleted and replaced with:
- *
- * 6. Trademarks. This License does not grant permission to use the trade
- * names, trademarks, service marks, or product names of the Licensor
- * and its affiliates, except as required to comply with Section 4(c) of
- * the License and to reproduce the content of the NOTICE file.
- *
- * You may obtain a copy of the Apache License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the Apache License with the above modification is
- * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the Apache License for the specific
- * language governing permissions and limitations under the Apache License.
- */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-typedef struct PatchHandle {
- int array_index, patch_index, vert_index;
-} PatchHandle;
-
-ccl_device_inline int patch_map_resolve_quadrant(float median,
- ccl_private float *u,
- ccl_private float *v)
-{
- int quadrant = -1;
-
- if (*u < median) {
- if (*v < median) {
- quadrant = 0;
- }
- else {
- quadrant = 1;
- *v -= median;
- }
- }
- else {
- if (*v < median) {
- quadrant = 3;
- }
- else {
- quadrant = 2;
- *v -= median;
- }
- *u -= median;
- }
-
- return quadrant;
-}
-
-/* retrieve PatchHandle from patch coords */
-
-ccl_device_inline PatchHandle
-patch_map_find_patch(KernelGlobals kg, int object, int patch, float u, float v)
-{
- PatchHandle handle;
-
- kernel_assert((u >= 0.0f) && (u <= 1.0f) && (v >= 0.0f) && (v <= 1.0f));
-
- int node = (object_patch_map_offset(kg, object) + patch) / 2;
- float median = 0.5f;
-
- for (int depth = 0; depth < 0xff; depth++) {
- float delta = median * 0.5f;
-
- int quadrant = patch_map_resolve_quadrant(median, &u, &v);
- kernel_assert(quadrant >= 0);
-
- uint child = kernel_tex_fetch(__patches, node + quadrant);
-
- /* is the quadrant a hole? */
- if (!(child & PATCH_MAP_NODE_IS_SET)) {
- handle.array_index = -1;
- return handle;
- }
-
- uint index = child & PATCH_MAP_NODE_INDEX_MASK;
-
- if (child & PATCH_MAP_NODE_IS_LEAF) {
- handle.array_index = kernel_tex_fetch(__patches, index + 0);
- handle.patch_index = kernel_tex_fetch(__patches, index + 1);
- handle.vert_index = kernel_tex_fetch(__patches, index + 2);
-
- return handle;
- }
- else {
- node = index;
- }
-
- median = delta;
- }
-
- /* no leaf found */
- kernel_assert(0);
-
- handle.array_index = -1;
- return handle;
-}
-
-ccl_device_inline void patch_eval_bspline_weights(float t,
- ccl_private float *point,
- ccl_private float *deriv)
-{
- /* The four uniform cubic B-Spline basis functions evaluated at t */
- float inv_6 = 1.0f / 6.0f;
-
- float t2 = t * t;
- float t3 = t * t2;
-
- point[0] = inv_6 * (1.0f - 3.0f * (t - t2) - t3);
- point[1] = inv_6 * (4.0f - 6.0f * t2 + 3.0f * t3);
- point[2] = inv_6 * (1.0f + 3.0f * (t + t2 - t3));
- point[3] = inv_6 * t3;
-
- /* Derivatives of the above four basis functions at t */
- deriv[0] = -0.5f * t2 + t - 0.5f;
- deriv[1] = 1.5f * t2 - 2.0f * t;
- deriv[2] = -1.5f * t2 + t + 0.5f;
- deriv[3] = 0.5f * t2;
-}
-
-ccl_device_inline void patch_eval_adjust_boundary_weights(uint bits,
- ccl_private float *s,
- ccl_private float *t)
-{
- int boundary = ((bits >> 8) & 0xf);
-
- if (boundary & 1) {
- t[2] -= t[0];
- t[1] += 2 * t[0];
- t[0] = 0;
- }
-
- if (boundary & 2) {
- s[1] -= s[3];
- s[2] += 2 * s[3];
- s[3] = 0;
- }
-
- if (boundary & 4) {
- t[1] -= t[3];
- t[2] += 2 * t[3];
- t[3] = 0;
- }
-
- if (boundary & 8) {
- s[2] -= s[0];
- s[1] += 2 * s[0];
- s[0] = 0;
- }
-}
-
-ccl_device_inline int patch_eval_depth(uint patch_bits)
-{
- return (patch_bits & 0xf);
-}
-
-ccl_device_inline float patch_eval_param_fraction(uint patch_bits)
-{
- bool non_quad_root = (patch_bits >> 4) & 0x1;
- int depth = patch_eval_depth(patch_bits);
-
- if (non_quad_root) {
- return 1.0f / (float)(1 << (depth - 1));
- }
- else {
- return 1.0f / (float)(1 << depth);
- }
-}
-
-ccl_device_inline void patch_eval_normalize_coords(uint patch_bits,
- ccl_private float *u,
- ccl_private float *v)
-{
- float frac = patch_eval_param_fraction(patch_bits);
-
- int iu = (patch_bits >> 22) & 0x3ff;
- int iv = (patch_bits >> 12) & 0x3ff;
-
- /* top left corner */
- float pu = (float)iu * frac;
- float pv = (float)iv * frac;
-
- /* normalize uv coordinates */
- *u = (*u - pu) / frac;
- *v = (*v - pv) / frac;
-}
-
-/* retrieve patch control indices */
-
-ccl_device_inline int patch_eval_indices(KernelGlobals kg,
- ccl_private const PatchHandle *handle,
- int channel,
- int indices[PATCH_MAX_CONTROL_VERTS])
-{
- int index_base = kernel_tex_fetch(__patches, handle->array_index + 2) + handle->vert_index;
-
- /* XXX: regular patches only */
- for (int i = 0; i < 16; i++) {
- indices[i] = kernel_tex_fetch(__patches, index_base + i);
- }
-
- return 16;
-}
-
-/* evaluate patch basis functions */
-
-ccl_device_inline void patch_eval_basis(KernelGlobals kg,
- ccl_private const PatchHandle *handle,
- float u,
- float v,
- float weights[PATCH_MAX_CONTROL_VERTS],
- float weights_du[PATCH_MAX_CONTROL_VERTS],
- float weights_dv[PATCH_MAX_CONTROL_VERTS])
-{
- uint patch_bits = kernel_tex_fetch(__patches, handle->patch_index + 1); /* read patch param */
- float d_scale = 1 << patch_eval_depth(patch_bits);
-
- bool non_quad_root = (patch_bits >> 4) & 0x1;
- if (non_quad_root) {
- d_scale *= 0.5f;
- }
-
- patch_eval_normalize_coords(patch_bits, &u, &v);
-
- /* XXX: regular patches only for now. */
-
- float s[4], t[4], ds[4], dt[4];
-
- patch_eval_bspline_weights(u, s, ds);
- patch_eval_bspline_weights(v, t, dt);
-
- patch_eval_adjust_boundary_weights(patch_bits, s, t);
- patch_eval_adjust_boundary_weights(patch_bits, ds, dt);
-
- for (int k = 0; k < 4; k++) {
- for (int l = 0; l < 4; l++) {
- weights[4 * k + l] = s[l] * t[k];
- weights_du[4 * k + l] = ds[l] * t[k] * d_scale;
- weights_dv[4 * k + l] = s[l] * dt[k] * d_scale;
- }
- }
-}
-
-/* generic function for evaluating indices and weights from patch coords */
-
-ccl_device_inline int patch_eval_control_verts(KernelGlobals kg,
- int object,
- int patch,
- float u,
- float v,
- int channel,
- int indices[PATCH_MAX_CONTROL_VERTS],
- float weights[PATCH_MAX_CONTROL_VERTS],
- float weights_du[PATCH_MAX_CONTROL_VERTS],
- float weights_dv[PATCH_MAX_CONTROL_VERTS])
-{
- PatchHandle handle = patch_map_find_patch(kg, object, patch, u, v);
- kernel_assert(handle.array_index >= 0);
-
- int num_control = patch_eval_indices(kg, &handle, channel, indices);
- patch_eval_basis(kg, &handle, u, v, weights, weights_du, weights_dv);
-
- return num_control;
-}
-
-/* functions for evaluating attributes on patches */
-
-ccl_device float patch_eval_float(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- int offset,
- int patch,
- float u,
- float v,
- int channel,
- ccl_private float *du,
- ccl_private float *dv)
-{
- int indices[PATCH_MAX_CONTROL_VERTS];
- float weights[PATCH_MAX_CONTROL_VERTS];
- float weights_du[PATCH_MAX_CONTROL_VERTS];
- float weights_dv[PATCH_MAX_CONTROL_VERTS];
-
- int num_control = patch_eval_control_verts(
- kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
-
- float val = 0.0f;
- if (du)
- *du = 0.0f;
- if (dv)
- *dv = 0.0f;
-
- for (int i = 0; i < num_control; i++) {
- float v = kernel_tex_fetch(__attributes_float, offset + indices[i]);
-
- val += v * weights[i];
- if (du)
- *du += v * weights_du[i];
- if (dv)
- *dv += v * weights_dv[i];
- }
-
- return val;
-}
-
-ccl_device float2 patch_eval_float2(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- int offset,
- int patch,
- float u,
- float v,
- int channel,
- ccl_private float2 *du,
- ccl_private float2 *dv)
-{
- int indices[PATCH_MAX_CONTROL_VERTS];
- float weights[PATCH_MAX_CONTROL_VERTS];
- float weights_du[PATCH_MAX_CONTROL_VERTS];
- float weights_dv[PATCH_MAX_CONTROL_VERTS];
-
- int num_control = patch_eval_control_verts(
- kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
-
- float2 val = make_float2(0.0f, 0.0f);
- if (du)
- *du = make_float2(0.0f, 0.0f);
- if (dv)
- *dv = make_float2(0.0f, 0.0f);
-
- for (int i = 0; i < num_control; i++) {
- float2 v = kernel_tex_fetch(__attributes_float2, offset + indices[i]);
-
- val += v * weights[i];
- if (du)
- *du += v * weights_du[i];
- if (dv)
- *dv += v * weights_dv[i];
- }
-
- return val;
-}
-
-ccl_device float3 patch_eval_float3(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- int offset,
- int patch,
- float u,
- float v,
- int channel,
- ccl_private float3 *du,
- ccl_private float3 *dv)
-{
- int indices[PATCH_MAX_CONTROL_VERTS];
- float weights[PATCH_MAX_CONTROL_VERTS];
- float weights_du[PATCH_MAX_CONTROL_VERTS];
- float weights_dv[PATCH_MAX_CONTROL_VERTS];
-
- int num_control = patch_eval_control_verts(
- kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
-
- float3 val = make_float3(0.0f, 0.0f, 0.0f);
- if (du)
- *du = make_float3(0.0f, 0.0f, 0.0f);
- if (dv)
- *dv = make_float3(0.0f, 0.0f, 0.0f);
-
- for (int i = 0; i < num_control; i++) {
- float3 v = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + indices[i]));
-
- val += v * weights[i];
- if (du)
- *du += v * weights_du[i];
- if (dv)
- *dv += v * weights_dv[i];
- }
-
- return val;
-}
-
-ccl_device float4 patch_eval_float4(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- int offset,
- int patch,
- float u,
- float v,
- int channel,
- ccl_private float4 *du,
- ccl_private float4 *dv)
-{
- int indices[PATCH_MAX_CONTROL_VERTS];
- float weights[PATCH_MAX_CONTROL_VERTS];
- float weights_du[PATCH_MAX_CONTROL_VERTS];
- float weights_dv[PATCH_MAX_CONTROL_VERTS];
-
- int num_control = patch_eval_control_verts(
- kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
-
- float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- if (du)
- *du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- if (dv)
- *dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-
- for (int i = 0; i < num_control; i++) {
- float4 v = kernel_tex_fetch(__attributes_float3, offset + indices[i]);
-
- val += v * weights[i];
- if (du)
- *du += v * weights_du[i];
- if (dv)
- *dv += v * weights_dv[i];
- }
-
- return val;
-}
-
-ccl_device float4 patch_eval_uchar4(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- int offset,
- int patch,
- float u,
- float v,
- int channel,
- ccl_private float4 *du,
- ccl_private float4 *dv)
-{
- int indices[PATCH_MAX_CONTROL_VERTS];
- float weights[PATCH_MAX_CONTROL_VERTS];
- float weights_du[PATCH_MAX_CONTROL_VERTS];
- float weights_dv[PATCH_MAX_CONTROL_VERTS];
-
- int num_control = patch_eval_control_verts(
- kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
-
- float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- if (du)
- *du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- if (dv)
- *dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-
- for (int i = 0; i < num_control; i++) {
- float4 v = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, offset + indices[i])));
-
- val += v * weights[i];
- if (du)
- *du += v * weights_du[i];
- if (dv)
- *dv += v * weights_dv[i];
- }
-
- return val;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h
deleted file mode 100644
index 91b29c7f990..00000000000
--- a/intern/cycles/kernel/geom/geom_primitive.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Primitive Utilities
- *
- * Generic functions to look up mesh, curve and volume primitive attributes for
- * shading and render passes. */
-
-#pragma once
-
-#include "kernel/kernel_projection.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Surface Attributes
- *
- * Read geometry attributes for surface shading. This is distinct from volume
- * attributes for performance, mainly for GPU performance to avoid bringing in
- * heavy volume interpolation code. */
-
-ccl_device_inline float primitive_surface_attribute_float(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc,
- ccl_private float *dx,
- ccl_private float *dy)
-{
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
- if (subd_triangle_patch(kg, sd) == ~0)
- return triangle_attribute_float(kg, sd, desc, dx, dy);
- else
- return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
- }
-#ifdef __HAIR__
- else if (sd->type & PRIMITIVE_ALL_CURVE) {
- return curve_attribute_float(kg, sd, desc, dx, dy);
- }
-#endif
- else {
- if (dx)
- *dx = 0.0f;
- if (dy)
- *dy = 0.0f;
- return 0.0f;
- }
-}
-
-ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc,
- ccl_private float2 *dx,
- ccl_private float2 *dy)
-{
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
- if (subd_triangle_patch(kg, sd) == ~0)
- return triangle_attribute_float2(kg, sd, desc, dx, dy);
- else
- return subd_triangle_attribute_float2(kg, sd, desc, dx, dy);
- }
-#ifdef __HAIR__
- else if (sd->type & PRIMITIVE_ALL_CURVE) {
- return curve_attribute_float2(kg, sd, desc, dx, dy);
- }
-#endif
- else {
- if (dx)
- *dx = make_float2(0.0f, 0.0f);
- if (dy)
- *dy = make_float2(0.0f, 0.0f);
- return make_float2(0.0f, 0.0f);
- }
-}
-
-ccl_device_inline float3 primitive_surface_attribute_float3(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc,
- ccl_private float3 *dx,
- ccl_private float3 *dy)
-{
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
- if (subd_triangle_patch(kg, sd) == ~0)
- return triangle_attribute_float3(kg, sd, desc, dx, dy);
- else
- return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
- }
-#ifdef __HAIR__
- else if (sd->type & PRIMITIVE_ALL_CURVE) {
- return curve_attribute_float3(kg, sd, desc, dx, dy);
- }
-#endif
- else {
- if (dx)
- *dx = make_float3(0.0f, 0.0f, 0.0f);
- if (dy)
- *dy = make_float3(0.0f, 0.0f, 0.0f);
- return make_float3(0.0f, 0.0f, 0.0f);
- }
-}
-
-ccl_device_forceinline float4 primitive_surface_attribute_float4(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc,
- ccl_private float4 *dx,
- ccl_private float4 *dy)
-{
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
- if (subd_triangle_patch(kg, sd) == ~0)
- return triangle_attribute_float4(kg, sd, desc, dx, dy);
- else
- return subd_triangle_attribute_float4(kg, sd, desc, dx, dy);
- }
-#ifdef __HAIR__
- else if (sd->type & PRIMITIVE_ALL_CURVE) {
- return curve_attribute_float4(kg, sd, desc, dx, dy);
- }
-#endif
- else {
- if (dx)
- *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- if (dy)
- *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- }
-}
-
-#ifdef __VOLUME__
-/* Volume Attributes
- *
- * Read geometry attributes for volume shading. This is distinct from surface
- * attributes for performance, mainly for GPU performance to avoid bringing in
- * heavy volume interpolation code. */
-
-ccl_device_inline bool primitive_is_volume_attribute(ccl_private const ShaderData *sd,
- const AttributeDescriptor desc)
-{
- return sd->type == PRIMITIVE_VOLUME;
-}
-
-ccl_device_inline float primitive_volume_attribute_float(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc)
-{
- if (primitive_is_volume_attribute(sd, desc)) {
- return volume_attribute_value_to_float(volume_attribute_float4(kg, sd, desc));
- }
- else {
- return 0.0f;
- }
-}
-
-ccl_device_inline float3 primitive_volume_attribute_float3(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc)
-{
- if (primitive_is_volume_attribute(sd, desc)) {
- return volume_attribute_value_to_float3(volume_attribute_float4(kg, sd, desc));
- }
- else {
- return make_float3(0.0f, 0.0f, 0.0f);
- }
-}
-
-ccl_device_inline float4 primitive_volume_attribute_float4(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc)
-{
- if (primitive_is_volume_attribute(sd, desc)) {
- return volume_attribute_float4(kg, sd, desc);
- }
- else {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- }
-}
-#endif
-
-/* Default UV coordinate */
-
-ccl_device_inline float3 primitive_uv(KernelGlobals kg, ccl_private const ShaderData *sd)
-{
- const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_UV);
-
- if (desc.offset == ATTR_STD_NOT_FOUND)
- return make_float3(0.0f, 0.0f, 0.0f);
-
- float2 uv = primitive_surface_attribute_float2(kg, sd, desc, NULL, NULL);
- return make_float3(uv.x, uv.y, 1.0f);
-}
-
-/* Ptex coordinates */
-
-ccl_device bool primitive_ptex(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float2 *uv,
- ccl_private int *face_id)
-{
- /* storing ptex data as attributes is not memory efficient but simple for tests */
- const AttributeDescriptor desc_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID);
- const AttributeDescriptor desc_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV);
-
- if (desc_face_id.offset == ATTR_STD_NOT_FOUND || desc_uv.offset == ATTR_STD_NOT_FOUND)
- return false;
-
- float3 uv3 = primitive_surface_attribute_float3(kg, sd, desc_uv, NULL, NULL);
- float face_id_f = primitive_surface_attribute_float(kg, sd, desc_face_id, NULL, NULL);
-
- *uv = make_float2(uv3.x, uv3.y);
- *face_id = (int)face_id_f;
-
- return true;
-}
-
-/* Surface tangent */
-
-ccl_device float3 primitive_tangent(KernelGlobals kg, ccl_private ShaderData *sd)
-{
-#ifdef __HAIR__
- if (sd->type & PRIMITIVE_ALL_CURVE)
-# ifdef __DPDU__
- return normalize(sd->dPdu);
-# else
- return make_float3(0.0f, 0.0f, 0.0f);
-# endif
-#endif
-
- /* try to create spherical tangent from generated coordinates */
- const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED);
-
- if (desc.offset != ATTR_STD_NOT_FOUND) {
- float3 data = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
- data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
- object_normal_transform(kg, sd, &data);
- return cross(sd->N, normalize(cross(data, sd->N)));
- }
- else {
- /* otherwise use surface derivatives */
-#ifdef __DPDU__
- return normalize(sd->dPdu);
-#else
- return make_float3(0.0f, 0.0f, 0.0f);
-#endif
- }
-}
-
-/* Motion vector for motion pass */
-
-ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
- ccl_private const ShaderData *sd)
-{
- /* center position */
- float3 center;
-
-#ifdef __HAIR__
- bool is_curve_primitive = sd->type & PRIMITIVE_ALL_CURVE;
- if (is_curve_primitive) {
- center = curve_motion_center_location(kg, sd);
-
- if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- object_position_transform(kg, sd, &center);
- }
- }
- else
-#endif
- center = sd->P;
-
- float3 motion_pre = center, motion_post = center;
-
- /* deformation motion */
- AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION);
-
- if (desc.offset != ATTR_STD_NOT_FOUND) {
- /* get motion info */
- int numverts, numkeys;
- object_motion_info(kg, sd->object, NULL, &numverts, &numkeys);
-
- /* lookup attributes */
- motion_pre = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
-
- desc.offset += (sd->type & PRIMITIVE_ALL_TRIANGLE) ? numverts : numkeys;
- motion_post = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
-
-#ifdef __HAIR__
- if (is_curve_primitive && (sd->object_flag & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
- object_position_transform(kg, sd, &motion_pre);
- object_position_transform(kg, sd, &motion_post);
- }
-#endif
- }
-
- /* object motion. note that depending on the mesh having motion vectors, this
- * transformation was set match the world/object space of motion_pre/post */
- Transform tfm;
-
- tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_PRE);
- motion_pre = transform_point(&tfm, motion_pre);
-
- tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_POST);
- motion_post = transform_point(&tfm, motion_post);
-
- float3 motion_center;
-
- /* camera motion, for perspective/orthographic motion.pre/post will be a
- * world-to-raster matrix, for panorama it's world-to-camera */
- if (kernel_data.cam.type != CAMERA_PANORAMA) {
- ProjectionTransform projection = kernel_data.cam.worldtoraster;
- motion_center = transform_perspective(&projection, center);
-
- projection = kernel_data.cam.perspective_pre;
- motion_pre = transform_perspective(&projection, motion_pre);
-
- projection = kernel_data.cam.perspective_post;
- motion_post = transform_perspective(&projection, motion_post);
- }
- else {
- tfm = kernel_data.cam.worldtocamera;
- motion_center = normalize(transform_point(&tfm, center));
- motion_center = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_center));
- motion_center.x *= kernel_data.cam.width;
- motion_center.y *= kernel_data.cam.height;
-
- tfm = kernel_data.cam.motion_pass_pre;
- motion_pre = normalize(transform_point(&tfm, motion_pre));
- motion_pre = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_pre));
- motion_pre.x *= kernel_data.cam.width;
- motion_pre.y *= kernel_data.cam.height;
-
- tfm = kernel_data.cam.motion_pass_post;
- motion_post = normalize(transform_point(&tfm, motion_post));
- motion_post = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_post));
- motion_post.x *= kernel_data.cam.width;
- motion_post.y *= kernel_data.cam.height;
- }
-
- motion_pre = motion_pre - motion_center;
- motion_post = motion_center - motion_post;
-
- return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h
deleted file mode 100644
index fee629cc75a..00000000000
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright 2014, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Triangle/Ray intersections.
- *
- * For BVH ray intersection we use a precomputed triangle storage to accelerate
- * intersection at the cost of more memory usage.
- */
-
-#pragma once
-
-#include "kernel/kernel_random.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_inline bool triangle_intersect(KernelGlobals kg,
- ccl_private Intersection *isect,
- float3 P,
- float3 dir,
- float tmax,
- uint visibility,
- int object,
- int prim_addr)
-{
- const int prim = kernel_tex_fetch(__prim_index, prim_addr);
- const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const ssef *ssef_verts = (ssef *)&kg->__tri_verts.data[tri_vindex];
-#else
- const float4 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
- tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
- tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
-#endif
- float t, u, v;
- if (ray_triangle_intersect(P,
- dir,
- tmax,
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- ssef_verts,
-#else
- float4_to_float3(tri_a),
- float4_to_float3(tri_b),
- float4_to_float3(tri_c),
-#endif
- &u,
- &v,
- &t)) {
-#ifdef __VISIBILITY_FLAG__
- /* Visibility flag test. we do it here under the assumption
- * that most triangles are culled by node flags.
- */
- if (kernel_tex_fetch(__prim_visibility, prim_addr) & visibility)
-#endif
- {
- isect->object = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, prim_addr) :
- object;
- isect->prim = prim;
- isect->type = PRIMITIVE_TRIANGLE;
- isect->u = u;
- isect->v = v;
- isect->t = t;
- return true;
- }
- }
- return false;
-}
-
-/* Special ray intersection routines for subsurface scattering. In that case we
- * only want to intersect with primitives in the same object, and if case of
- * multiple hits we pick a single random primitive as the intersection point.
- * Returns whether traversal should be stopped.
- */
-
-#ifdef __BVH_LOCAL__
-ccl_device_inline bool triangle_intersect_local(KernelGlobals kg,
- ccl_private LocalIntersection *local_isect,
- float3 P,
- float3 dir,
- int object,
- int local_object,
- int prim_addr,
- float tmax,
- ccl_private uint *lcg_state,
- int max_hits)
-{
- /* Only intersect with matching object, for instanced objects we
- * already know we are only intersecting the right object. */
- if (object == OBJECT_NONE) {
- if (kernel_tex_fetch(__prim_object, prim_addr) != local_object) {
- return false;
- }
- }
-
- const int prim = kernel_tex_fetch(__prim_index, prim_addr);
- const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
-# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const ssef *ssef_verts = (ssef *)&kg->__tri_verts.data[tri_vindex];
-# else
- const float3 tri_a = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 0)),
- tri_b = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 1)),
- tri_c = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 2));
-# endif
- float t, u, v;
- if (!ray_triangle_intersect(P,
- dir,
- tmax,
-# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- ssef_verts,
-# else
- tri_a,
- tri_b,
- tri_c,
-# endif
- &u,
- &v,
- &t)) {
- return false;
- }
-
- /* If no actual hit information is requested, just return here. */
- if (max_hits == 0) {
- return true;
- }
-
- int hit;
- if (lcg_state) {
- /* Record up to max_hits intersections. */
- for (int i = min(max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
- if (local_isect->hits[i].t == t) {
- return false;
- }
- }
-
- local_isect->num_hits++;
-
- if (local_isect->num_hits <= max_hits) {
- hit = local_isect->num_hits - 1;
- }
- else {
- /* reservoir sampling: if we are at the maximum number of
- * hits, randomly replace element or skip it */
- hit = lcg_step_uint(lcg_state) % local_isect->num_hits;
-
- if (hit >= max_hits)
- return false;
- }
- }
- else {
- /* Record closest intersection only. */
- if (local_isect->num_hits && t > local_isect->hits[0].t) {
- return false;
- }
-
- hit = 0;
- local_isect->num_hits = 1;
- }
-
- /* Record intersection. */
- ccl_private Intersection *isect = &local_isect->hits[hit];
- isect->prim = prim;
- isect->object = local_object;
- isect->type = PRIMITIVE_TRIANGLE;
- isect->u = u;
- isect->v = v;
- isect->t = t;
-
- /* Record geometric normal. */
-# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const float3 tri_a = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 0)),
- tri_b = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 1)),
- tri_c = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 2));
-# endif
- local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
-
- return false;
-}
-#endif /* __BVH_LOCAL__ */
-
-/* Refine triangle intersection to more precise hit point. For rays that travel
- * far the precision is often not so good, this reintersects the primitive from
- * a closer distance. */
-
-/* Reintersections uses the paper:
- *
- * Tomas Moeller
- * Fast, minimum storage ray/triangle intersection
- * http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf
- */
-
-ccl_device_inline float3 triangle_refine(KernelGlobals kg,
- ccl_private ShaderData *sd,
- float3 P,
- float3 D,
- float t,
- const int isect_object,
- const int isect_prim)
-{
-#ifdef __INTERSECTION_REFINE__
- if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- if (UNLIKELY(t == 0.0f)) {
- return P;
- }
- const Transform tfm = object_get_inverse_transform(kg, sd);
-
- P = transform_point(&tfm, P);
- D = transform_direction(&tfm, D * t);
- D = normalize_len(D, &t);
- }
-
- P = P + D * t;
-
- const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w;
- const float4 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
- tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
- tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
- float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
- float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
- float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
- float3 qvec = cross(tvec, edge1);
- float3 pvec = cross(D, edge2);
- float det = dot(edge1, pvec);
- if (det != 0.0f) {
- /* If determinant is zero it means ray lies in the plane of
- * the triangle. It is possible in theory due to watertight
- * nature of triangle intersection. For such cases we simply
- * don't refine intersection hoping it'll go all fine.
- */
- float rt = dot(edge2, qvec) / det;
- P = P + D * rt;
- }
-
- if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- const Transform tfm = object_get_transform(kg, sd);
- P = transform_point(&tfm, P);
- }
-
- return P;
-#else
- return P + D * t;
-#endif
-}
-
-/* Same as above, except that t is assumed to be in object space for
- * instancing.
- */
-ccl_device_inline float3 triangle_refine_local(KernelGlobals kg,
- ccl_private ShaderData *sd,
- float3 P,
- float3 D,
- float t,
- const int isect_object,
- const int isect_prim)
-{
-#ifdef __KERNEL_OPTIX__
- /* t is always in world space with OptiX. */
- return triangle_refine(kg, sd, P, D, t, isect_object, isect_prim);
-#else
- if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- const Transform tfm = object_get_inverse_transform(kg, sd);
-
- P = transform_point(&tfm, P);
- D = transform_direction(&tfm, D);
- D = normalize(D);
- }
-
- P = P + D * t;
-
-# ifdef __INTERSECTION_REFINE__
- const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w;
- const float4 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
- tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
- tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
- float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
- float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
- float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
- float3 qvec = cross(tvec, edge1);
- float3 pvec = cross(D, edge2);
- float det = dot(edge1, pvec);
- if (det != 0.0f) {
- /* If determinant is zero it means ray lies in the plane of
- * the triangle. It is possible in theory due to watertight
- * nature of triangle intersection. For such cases we simply
- * don't refine intersection hoping it'll go all fine.
- */
- float rt = dot(edge2, qvec) / det;
- P = P + D * rt;
- }
-# endif /* __INTERSECTION_REFINE__ */
-
- if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- const Transform tfm = object_get_transform(kg, sd);
- P = transform_point(&tfm, P);
- }
-
- return P;
-#endif
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_motion_curve.h b/intern/cycles/kernel/geom/motion_curve.h
index 2dd213d43f6..2dd213d43f6 100644
--- a/intern/cycles/kernel/geom/geom_motion_curve.h
+++ b/intern/cycles/kernel/geom/motion_curve.h
diff --git a/intern/cycles/kernel/geom/motion_triangle.h b/intern/cycles/kernel/geom/motion_triangle.h
new file mode 100644
index 00000000000..43f894938e0
--- /dev/null
+++ b/intern/cycles/kernel/geom/motion_triangle.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Motion Triangle Primitive
+ *
+ * These are stored as regular triangles, plus extra positions and normals at
+ * times other than the frame center. Computing the triangle vertex positions
+ * or normals at a given ray time is a matter of interpolation of the two steps
+ * between which the ray time lies.
+ *
+ * The extra positions and normals are stored as ATTR_STD_MOTION_VERTEX_POSITION
+ * and ATTR_STD_MOTION_VERTEX_NORMAL mesh attributes.
+ */
+
+#pragma once
+
+#include "kernel/bvh/util.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Time interpolation of vertex positions and normals */
+
+ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals kg,
+ uint4 tri_vindex,
+ int offset,
+ int numverts,
+ int numsteps,
+ int step,
+ float3 verts[3])
+{
+ if (step == numsteps) {
+ /* center step: regular vertex location */
+ verts[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 0));
+ verts[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 1));
+ verts[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 2));
+ }
+ else {
+ /* center step not store in this array */
+ if (step > numsteps)
+ step--;
+
+ offset += step * numverts;
+
+ verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
+ verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
+ verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
+ }
+}
+
+ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg,
+ uint4 tri_vindex,
+ int offset,
+ int numverts,
+ int numsteps,
+ int step,
+ float3 normals[3])
+{
+ if (step == numsteps) {
+ /* center step: regular vertex location */
+ normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
+ normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
+ normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
+ }
+ else {
+ /* center step is not stored in this array */
+ if (step > numsteps)
+ step--;
+
+ offset += step * numverts;
+
+ normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
+ normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
+ normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
+ }
+}
+
+ccl_device_inline void motion_triangle_vertices(
+ KernelGlobals kg, int object, int prim, float time, float3 verts[3])
+{
+ /* get motion info */
+ int numsteps, numverts;
+ object_motion_info(kg, object, &numsteps, &numverts, NULL);
+
+ /* figure out which steps we need to fetch and their interpolation factor */
+ int maxstep = numsteps * 2;
+ int step = min((int)(time * maxstep), maxstep - 1);
+ float t = time * maxstep - step;
+
+ /* find attribute */
+ int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_POSITION);
+ kernel_assert(offset != ATTR_STD_NOT_FOUND);
+
+ /* fetch vertex coordinates */
+ float3 next_verts[3];
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+
+ motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
+ motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step + 1, next_verts);
+
+ /* interpolate between steps */
+ verts[0] = (1.0f - t) * verts[0] + t * next_verts[0];
+ verts[1] = (1.0f - t) * verts[1] + t * next_verts[1];
+ verts[2] = (1.0f - t) * verts[2] + t * next_verts[2];
+}
+
+ccl_device_inline float3 motion_triangle_smooth_normal(
+ KernelGlobals kg, float3 Ng, int object, int prim, float u, float v, float time)
+{
+ /* get motion info */
+ int numsteps, numverts;
+ object_motion_info(kg, object, &numsteps, &numverts, NULL);
+
+ /* figure out which steps we need to fetch and their interpolation factor */
+ int maxstep = numsteps * 2;
+ int step = min((int)(time * maxstep), maxstep - 1);
+ float t = time * maxstep - step;
+
+ /* find attribute */
+ int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_NORMAL);
+ kernel_assert(offset != ATTR_STD_NOT_FOUND);
+
+ /* fetch normals */
+ float3 normals[3], next_normals[3];
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+
+ motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals);
+ motion_triangle_normals_for_step(
+ kg, tri_vindex, offset, numverts, numsteps, step + 1, next_normals);
+
+ /* interpolate between steps */
+ normals[0] = (1.0f - t) * normals[0] + t * next_normals[0];
+ normals[1] = (1.0f - t) * normals[1] + t * next_normals[1];
+ normals[2] = (1.0f - t) * normals[2] + t * next_normals[2];
+
+ /* interpolate between vertices */
+ float w = 1.0f - u - v;
+ float3 N = safe_normalize(u * normals[0] + v * normals[1] + w * normals[2]);
+
+ return is_zero(N) ? Ng : N;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h b/intern/cycles/kernel/geom/motion_triangle_intersect.h
index 256e7add21e..256e7add21e 100644
--- a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/motion_triangle_intersect.h
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h b/intern/cycles/kernel/geom/motion_triangle_shader.h
index fc7c181882e..fc7c181882e 100644
--- a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h
+++ b/intern/cycles/kernel/geom/motion_triangle_shader.h
diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/object.h
index 34a9d639d9d..34a9d639d9d 100644
--- a/intern/cycles/kernel/geom/geom_object.h
+++ b/intern/cycles/kernel/geom/object.h
diff --git a/intern/cycles/kernel/geom/patch.h b/intern/cycles/kernel/geom/patch.h
new file mode 100644
index 00000000000..7d24937a41e
--- /dev/null
+++ b/intern/cycles/kernel/geom/patch.h
@@ -0,0 +1,470 @@
+/*
+ * Based on code from OpenSubdiv released under this license:
+ *
+ * Copyright 2013 Pixar
+ *
+ * Licensed under the Apache License, Version 2.0 (the "Apache License")
+ * with the following modification; you may not use this file except in
+ * compliance with the Apache License and the following modification to it:
+ * Section 6. Trademarks. is deleted and replaced with:
+ *
+ * 6. Trademarks. This License does not grant permission to use the trade
+ * names, trademarks, service marks, or product names of the Licensor
+ * and its affiliates, except as required to comply with Section 4(c) of
+ * the License and to reproduce the content of the NOTICE file.
+ *
+ * You may obtain a copy of the Apache License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Apache License with the above modification is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the Apache License for the specific
+ * language governing permissions and limitations under the Apache License.
+ */
+
+#pragma once
+
+#include "util/color.h"
+
+CCL_NAMESPACE_BEGIN
+
+typedef struct PatchHandle {
+ int array_index, patch_index, vert_index;
+} PatchHandle;
+
+ccl_device_inline int patch_map_resolve_quadrant(float median,
+ ccl_private float *u,
+ ccl_private float *v)
+{
+ int quadrant = -1;
+
+ if (*u < median) {
+ if (*v < median) {
+ quadrant = 0;
+ }
+ else {
+ quadrant = 1;
+ *v -= median;
+ }
+ }
+ else {
+ if (*v < median) {
+ quadrant = 3;
+ }
+ else {
+ quadrant = 2;
+ *v -= median;
+ }
+ *u -= median;
+ }
+
+ return quadrant;
+}
+
+/* retrieve PatchHandle from patch coords */
+
+ccl_device_inline PatchHandle
+patch_map_find_patch(KernelGlobals kg, int object, int patch, float u, float v)
+{
+ PatchHandle handle;
+
+ kernel_assert((u >= 0.0f) && (u <= 1.0f) && (v >= 0.0f) && (v <= 1.0f));
+
+ int node = (object_patch_map_offset(kg, object) + patch) / 2;
+ float median = 0.5f;
+
+ for (int depth = 0; depth < 0xff; depth++) {
+ float delta = median * 0.5f;
+
+ int quadrant = patch_map_resolve_quadrant(median, &u, &v);
+ kernel_assert(quadrant >= 0);
+
+ uint child = kernel_tex_fetch(__patches, node + quadrant);
+
+ /* is the quadrant a hole? */
+ if (!(child & PATCH_MAP_NODE_IS_SET)) {
+ handle.array_index = -1;
+ return handle;
+ }
+
+ uint index = child & PATCH_MAP_NODE_INDEX_MASK;
+
+ if (child & PATCH_MAP_NODE_IS_LEAF) {
+ handle.array_index = kernel_tex_fetch(__patches, index + 0);
+ handle.patch_index = kernel_tex_fetch(__patches, index + 1);
+ handle.vert_index = kernel_tex_fetch(__patches, index + 2);
+
+ return handle;
+ }
+ else {
+ node = index;
+ }
+
+ median = delta;
+ }
+
+ /* no leaf found */
+ kernel_assert(0);
+
+ handle.array_index = -1;
+ return handle;
+}
+
+ccl_device_inline void patch_eval_bspline_weights(float t,
+ ccl_private float *point,
+ ccl_private float *deriv)
+{
+ /* The four uniform cubic B-Spline basis functions evaluated at t */
+ float inv_6 = 1.0f / 6.0f;
+
+ float t2 = t * t;
+ float t3 = t * t2;
+
+ point[0] = inv_6 * (1.0f - 3.0f * (t - t2) - t3);
+ point[1] = inv_6 * (4.0f - 6.0f * t2 + 3.0f * t3);
+ point[2] = inv_6 * (1.0f + 3.0f * (t + t2 - t3));
+ point[3] = inv_6 * t3;
+
+ /* Derivatives of the above four basis functions at t */
+ deriv[0] = -0.5f * t2 + t - 0.5f;
+ deriv[1] = 1.5f * t2 - 2.0f * t;
+ deriv[2] = -1.5f * t2 + t + 0.5f;
+ deriv[3] = 0.5f * t2;
+}
+
+ccl_device_inline void patch_eval_adjust_boundary_weights(uint bits,
+ ccl_private float *s,
+ ccl_private float *t)
+{
+ int boundary = ((bits >> 8) & 0xf);
+
+ if (boundary & 1) {
+ t[2] -= t[0];
+ t[1] += 2 * t[0];
+ t[0] = 0;
+ }
+
+ if (boundary & 2) {
+ s[1] -= s[3];
+ s[2] += 2 * s[3];
+ s[3] = 0;
+ }
+
+ if (boundary & 4) {
+ t[1] -= t[3];
+ t[2] += 2 * t[3];
+ t[3] = 0;
+ }
+
+ if (boundary & 8) {
+ s[2] -= s[0];
+ s[1] += 2 * s[0];
+ s[0] = 0;
+ }
+}
+
+ccl_device_inline int patch_eval_depth(uint patch_bits)
+{
+ return (patch_bits & 0xf);
+}
+
+ccl_device_inline float patch_eval_param_fraction(uint patch_bits)
+{
+ bool non_quad_root = (patch_bits >> 4) & 0x1;
+ int depth = patch_eval_depth(patch_bits);
+
+ if (non_quad_root) {
+ return 1.0f / (float)(1 << (depth - 1));
+ }
+ else {
+ return 1.0f / (float)(1 << depth);
+ }
+}
+
+ccl_device_inline void patch_eval_normalize_coords(uint patch_bits,
+ ccl_private float *u,
+ ccl_private float *v)
+{
+ float frac = patch_eval_param_fraction(patch_bits);
+
+ int iu = (patch_bits >> 22) & 0x3ff;
+ int iv = (patch_bits >> 12) & 0x3ff;
+
+ /* top left corner */
+ float pu = (float)iu * frac;
+ float pv = (float)iv * frac;
+
+ /* normalize uv coordinates */
+ *u = (*u - pu) / frac;
+ *v = (*v - pv) / frac;
+}
+
+/* retrieve patch control indices */
+
+ccl_device_inline int patch_eval_indices(KernelGlobals kg,
+ ccl_private const PatchHandle *handle,
+ int channel,
+ int indices[PATCH_MAX_CONTROL_VERTS])
+{
+ int index_base = kernel_tex_fetch(__patches, handle->array_index + 2) + handle->vert_index;
+
+ /* XXX: regular patches only */
+ for (int i = 0; i < 16; i++) {
+ indices[i] = kernel_tex_fetch(__patches, index_base + i);
+ }
+
+ return 16;
+}
+
+/* evaluate patch basis functions */
+
+ccl_device_inline void patch_eval_basis(KernelGlobals kg,
+ ccl_private const PatchHandle *handle,
+ float u,
+ float v,
+ float weights[PATCH_MAX_CONTROL_VERTS],
+ float weights_du[PATCH_MAX_CONTROL_VERTS],
+ float weights_dv[PATCH_MAX_CONTROL_VERTS])
+{
+ uint patch_bits = kernel_tex_fetch(__patches, handle->patch_index + 1); /* read patch param */
+ float d_scale = 1 << patch_eval_depth(patch_bits);
+
+ bool non_quad_root = (patch_bits >> 4) & 0x1;
+ if (non_quad_root) {
+ d_scale *= 0.5f;
+ }
+
+ patch_eval_normalize_coords(patch_bits, &u, &v);
+
+ /* XXX: regular patches only for now. */
+
+ float s[4], t[4], ds[4], dt[4];
+
+ patch_eval_bspline_weights(u, s, ds);
+ patch_eval_bspline_weights(v, t, dt);
+
+ patch_eval_adjust_boundary_weights(patch_bits, s, t);
+ patch_eval_adjust_boundary_weights(patch_bits, ds, dt);
+
+ for (int k = 0; k < 4; k++) {
+ for (int l = 0; l < 4; l++) {
+ weights[4 * k + l] = s[l] * t[k];
+ weights_du[4 * k + l] = ds[l] * t[k] * d_scale;
+ weights_dv[4 * k + l] = s[l] * dt[k] * d_scale;
+ }
+ }
+}
+
+/* generic function for evaluating indices and weights from patch coords */
+
+ccl_device_inline int patch_eval_control_verts(KernelGlobals kg,
+ int object,
+ int patch,
+ float u,
+ float v,
+ int channel,
+ int indices[PATCH_MAX_CONTROL_VERTS],
+ float weights[PATCH_MAX_CONTROL_VERTS],
+ float weights_du[PATCH_MAX_CONTROL_VERTS],
+ float weights_dv[PATCH_MAX_CONTROL_VERTS])
+{
+ PatchHandle handle = patch_map_find_patch(kg, object, patch, u, v);
+ kernel_assert(handle.array_index >= 0);
+
+ int num_control = patch_eval_indices(kg, &handle, channel, indices);
+ patch_eval_basis(kg, &handle, u, v, weights, weights_du, weights_dv);
+
+ return num_control;
+}
+
+/* functions for evaluating attributes on patches */
+
+ccl_device float patch_eval_float(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ int offset,
+ int patch,
+ float u,
+ float v,
+ int channel,
+ ccl_private float *du,
+ ccl_private float *dv)
+{
+ int indices[PATCH_MAX_CONTROL_VERTS];
+ float weights[PATCH_MAX_CONTROL_VERTS];
+ float weights_du[PATCH_MAX_CONTROL_VERTS];
+ float weights_dv[PATCH_MAX_CONTROL_VERTS];
+
+ int num_control = patch_eval_control_verts(
+ kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
+
+ float val = 0.0f;
+ if (du)
+ *du = 0.0f;
+ if (dv)
+ *dv = 0.0f;
+
+ for (int i = 0; i < num_control; i++) {
+ float v = kernel_tex_fetch(__attributes_float, offset + indices[i]);
+
+ val += v * weights[i];
+ if (du)
+ *du += v * weights_du[i];
+ if (dv)
+ *dv += v * weights_dv[i];
+ }
+
+ return val;
+}
+
+ccl_device float2 patch_eval_float2(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ int offset,
+ int patch,
+ float u,
+ float v,
+ int channel,
+ ccl_private float2 *du,
+ ccl_private float2 *dv)
+{
+ int indices[PATCH_MAX_CONTROL_VERTS];
+ float weights[PATCH_MAX_CONTROL_VERTS];
+ float weights_du[PATCH_MAX_CONTROL_VERTS];
+ float weights_dv[PATCH_MAX_CONTROL_VERTS];
+
+ int num_control = patch_eval_control_verts(
+ kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
+
+ float2 val = make_float2(0.0f, 0.0f);
+ if (du)
+ *du = make_float2(0.0f, 0.0f);
+ if (dv)
+ *dv = make_float2(0.0f, 0.0f);
+
+ for (int i = 0; i < num_control; i++) {
+ float2 v = kernel_tex_fetch(__attributes_float2, offset + indices[i]);
+
+ val += v * weights[i];
+ if (du)
+ *du += v * weights_du[i];
+ if (dv)
+ *dv += v * weights_dv[i];
+ }
+
+ return val;
+}
+
+ccl_device float3 patch_eval_float3(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ int offset,
+ int patch,
+ float u,
+ float v,
+ int channel,
+ ccl_private float3 *du,
+ ccl_private float3 *dv)
+{
+ int indices[PATCH_MAX_CONTROL_VERTS];
+ float weights[PATCH_MAX_CONTROL_VERTS];
+ float weights_du[PATCH_MAX_CONTROL_VERTS];
+ float weights_dv[PATCH_MAX_CONTROL_VERTS];
+
+ int num_control = patch_eval_control_verts(
+ kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
+
+ float3 val = make_float3(0.0f, 0.0f, 0.0f);
+ if (du)
+ *du = make_float3(0.0f, 0.0f, 0.0f);
+ if (dv)
+ *dv = make_float3(0.0f, 0.0f, 0.0f);
+
+ for (int i = 0; i < num_control; i++) {
+ float3 v = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + indices[i]));
+
+ val += v * weights[i];
+ if (du)
+ *du += v * weights_du[i];
+ if (dv)
+ *dv += v * weights_dv[i];
+ }
+
+ return val;
+}
+
+ccl_device float4 patch_eval_float4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ int offset,
+ int patch,
+ float u,
+ float v,
+ int channel,
+ ccl_private float4 *du,
+ ccl_private float4 *dv)
+{
+ int indices[PATCH_MAX_CONTROL_VERTS];
+ float weights[PATCH_MAX_CONTROL_VERTS];
+ float weights_du[PATCH_MAX_CONTROL_VERTS];
+ float weights_dv[PATCH_MAX_CONTROL_VERTS];
+
+ int num_control = patch_eval_control_verts(
+ kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
+
+ float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (du)
+ *du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (dv)
+ *dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ for (int i = 0; i < num_control; i++) {
+ float4 v = kernel_tex_fetch(__attributes_float3, offset + indices[i]);
+
+ val += v * weights[i];
+ if (du)
+ *du += v * weights_du[i];
+ if (dv)
+ *dv += v * weights_dv[i];
+ }
+
+ return val;
+}
+
+ccl_device float4 patch_eval_uchar4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ int offset,
+ int patch,
+ float u,
+ float v,
+ int channel,
+ ccl_private float4 *du,
+ ccl_private float4 *dv)
+{
+ int indices[PATCH_MAX_CONTROL_VERTS];
+ float weights[PATCH_MAX_CONTROL_VERTS];
+ float weights_du[PATCH_MAX_CONTROL_VERTS];
+ float weights_dv[PATCH_MAX_CONTROL_VERTS];
+
+ int num_control = patch_eval_control_verts(
+ kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
+
+ float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (du)
+ *du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (dv)
+ *dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ for (int i = 0; i < num_control; i++) {
+ float4 v = color_srgb_to_linear_v4(
+ color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, offset + indices[i])));
+
+ val += v * weights[i];
+ if (du)
+ *du += v * weights_du[i];
+ if (dv)
+ *dv += v * weights_dv[i];
+ }
+
+ return val;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/primitive.h b/intern/cycles/kernel/geom/primitive.h
new file mode 100644
index 00000000000..7a8921b6d6e
--- /dev/null
+++ b/intern/cycles/kernel/geom/primitive.h
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Primitive Utilities
+ *
+ * Generic functions to look up mesh, curve and volume primitive attributes for
+ * shading and render passes. */
+
+#pragma once
+
+#include "kernel/camera/projection.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Surface Attributes
+ *
+ * Read geometry attributes for surface shading. This is distinct from volume
+ * attributes for performance, mainly for GPU performance to avoid bringing in
+ * heavy volume interpolation code. */
+
+ccl_device_inline float primitive_surface_attribute_float(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float *dx,
+ ccl_private float *dy)
+{
+ if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (subd_triangle_patch(kg, sd) == ~0)
+ return triangle_attribute_float(kg, sd, desc, dx, dy);
+ else
+ return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
+ }
+#ifdef __HAIR__
+ else if (sd->type & PRIMITIVE_ALL_CURVE) {
+ return curve_attribute_float(kg, sd, desc, dx, dy);
+ }
+#endif
+ else {
+ if (dx)
+ *dx = 0.0f;
+ if (dy)
+ *dy = 0.0f;
+ return 0.0f;
+ }
+}
+
+ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float2 *dx,
+ ccl_private float2 *dy)
+{
+ if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (subd_triangle_patch(kg, sd) == ~0)
+ return triangle_attribute_float2(kg, sd, desc, dx, dy);
+ else
+ return subd_triangle_attribute_float2(kg, sd, desc, dx, dy);
+ }
+#ifdef __HAIR__
+ else if (sd->type & PRIMITIVE_ALL_CURVE) {
+ return curve_attribute_float2(kg, sd, desc, dx, dy);
+ }
+#endif
+ else {
+ if (dx)
+ *dx = make_float2(0.0f, 0.0f);
+ if (dy)
+ *dy = make_float2(0.0f, 0.0f);
+ return make_float2(0.0f, 0.0f);
+ }
+}
+
+ccl_device_inline float3 primitive_surface_attribute_float3(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float3 *dx,
+ ccl_private float3 *dy)
+{
+ if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (subd_triangle_patch(kg, sd) == ~0)
+ return triangle_attribute_float3(kg, sd, desc, dx, dy);
+ else
+ return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
+ }
+#ifdef __HAIR__
+ else if (sd->type & PRIMITIVE_ALL_CURVE) {
+ return curve_attribute_float3(kg, sd, desc, dx, dy);
+ }
+#endif
+ else {
+ if (dx)
+ *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float3(0.0f, 0.0f, 0.0f);
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+ccl_device_forceinline float4 primitive_surface_attribute_float4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float4 *dx,
+ ccl_private float4 *dy)
+{
+ if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (subd_triangle_patch(kg, sd) == ~0)
+ return triangle_attribute_float4(kg, sd, desc, dx, dy);
+ else
+ return subd_triangle_attribute_float4(kg, sd, desc, dx, dy);
+ }
+#ifdef __HAIR__
+ else if (sd->type & PRIMITIVE_ALL_CURVE) {
+ return curve_attribute_float4(kg, sd, desc, dx, dy);
+ }
+#endif
+ else {
+ if (dx)
+ *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+
+#ifdef __VOLUME__
+/* Volume Attributes
+ *
+ * Read geometry attributes for volume shading. This is distinct from surface
+ * attributes for performance, mainly for GPU performance to avoid bringing in
+ * heavy volume interpolation code. */
+
+ccl_device_inline bool primitive_is_volume_attribute(ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc)
+{
+ return sd->type == PRIMITIVE_VOLUME;
+}
+
+ccl_device_inline float primitive_volume_attribute_float(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc)
+{
+ if (primitive_is_volume_attribute(sd, desc)) {
+ return volume_attribute_value_to_float(volume_attribute_float4(kg, sd, desc));
+ }
+ else {
+ return 0.0f;
+ }
+}
+
+ccl_device_inline float3 primitive_volume_attribute_float3(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc)
+{
+ if (primitive_is_volume_attribute(sd, desc)) {
+ return volume_attribute_value_to_float3(volume_attribute_float4(kg, sd, desc));
+ }
+ else {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+ccl_device_inline float4 primitive_volume_attribute_float4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc)
+{
+ if (primitive_is_volume_attribute(sd, desc)) {
+ return volume_attribute_float4(kg, sd, desc);
+ }
+ else {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+#endif
+
+/* Default UV coordinate */
+
+ccl_device_inline float3 primitive_uv(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_UV);
+
+ if (desc.offset == ATTR_STD_NOT_FOUND)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ float2 uv = primitive_surface_attribute_float2(kg, sd, desc, NULL, NULL);
+ return make_float3(uv.x, uv.y, 1.0f);
+}
+
+/* Ptex coordinates */
+
+ccl_device bool primitive_ptex(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float2 *uv,
+ ccl_private int *face_id)
+{
+ /* storing ptex data as attributes is not memory efficient but simple for tests */
+ const AttributeDescriptor desc_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID);
+ const AttributeDescriptor desc_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV);
+
+ if (desc_face_id.offset == ATTR_STD_NOT_FOUND || desc_uv.offset == ATTR_STD_NOT_FOUND)
+ return false;
+
+ float3 uv3 = primitive_surface_attribute_float3(kg, sd, desc_uv, NULL, NULL);
+ float face_id_f = primitive_surface_attribute_float(kg, sd, desc_face_id, NULL, NULL);
+
+ *uv = make_float2(uv3.x, uv3.y);
+ *face_id = (int)face_id_f;
+
+ return true;
+}
+
+/* Surface tangent */
+
+ccl_device float3 primitive_tangent(KernelGlobals kg, ccl_private ShaderData *sd)
+{
+#ifdef __HAIR__
+ if (sd->type & PRIMITIVE_ALL_CURVE)
+# ifdef __DPDU__
+ return normalize(sd->dPdu);
+# else
+ return make_float3(0.0f, 0.0f, 0.0f);
+# endif
+#endif
+
+ /* try to create spherical tangent from generated coordinates */
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED);
+
+ if (desc.offset != ATTR_STD_NOT_FOUND) {
+ float3 data = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
+ data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
+ object_normal_transform(kg, sd, &data);
+ return cross(sd->N, normalize(cross(data, sd->N)));
+ }
+ else {
+ /* otherwise use surface derivatives */
+#ifdef __DPDU__
+ return normalize(sd->dPdu);
+#else
+ return make_float3(0.0f, 0.0f, 0.0f);
+#endif
+ }
+}
+
+/* Motion vector for motion pass */
+
+ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
+ ccl_private const ShaderData *sd)
+{
+ /* center position */
+ float3 center;
+
+#ifdef __HAIR__
+ bool is_curve_primitive = sd->type & PRIMITIVE_ALL_CURVE;
+ if (is_curve_primitive) {
+ center = curve_motion_center_location(kg, sd);
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ object_position_transform(kg, sd, &center);
+ }
+ }
+ else
+#endif
+ center = sd->P;
+
+ float3 motion_pre = center, motion_post = center;
+
+ /* deformation motion */
+ AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (desc.offset != ATTR_STD_NOT_FOUND) {
+ /* get motion info */
+ int numverts, numkeys;
+ object_motion_info(kg, sd->object, NULL, &numverts, &numkeys);
+
+ /* lookup attributes */
+ motion_pre = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
+
+ desc.offset += (sd->type & PRIMITIVE_ALL_TRIANGLE) ? numverts : numkeys;
+ motion_post = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
+
+#ifdef __HAIR__
+ if (is_curve_primitive && (sd->object_flag & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
+ object_position_transform(kg, sd, &motion_pre);
+ object_position_transform(kg, sd, &motion_post);
+ }
+#endif
+ }
+
+ /* object motion. note that depending on the mesh having motion vectors, this
+ * transformation was set match the world/object space of motion_pre/post */
+ Transform tfm;
+
+ tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_PRE);
+ motion_pre = transform_point(&tfm, motion_pre);
+
+ tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_POST);
+ motion_post = transform_point(&tfm, motion_post);
+
+ float3 motion_center;
+
+ /* camera motion, for perspective/orthographic motion.pre/post will be a
+ * world-to-raster matrix, for panorama it's world-to-camera */
+ if (kernel_data.cam.type != CAMERA_PANORAMA) {
+ ProjectionTransform projection = kernel_data.cam.worldtoraster;
+ motion_center = transform_perspective(&projection, center);
+
+ projection = kernel_data.cam.perspective_pre;
+ motion_pre = transform_perspective(&projection, motion_pre);
+
+ projection = kernel_data.cam.perspective_post;
+ motion_post = transform_perspective(&projection, motion_post);
+ }
+ else {
+ tfm = kernel_data.cam.worldtocamera;
+ motion_center = normalize(transform_point(&tfm, center));
+ motion_center = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_center));
+ motion_center.x *= kernel_data.cam.width;
+ motion_center.y *= kernel_data.cam.height;
+
+ tfm = kernel_data.cam.motion_pass_pre;
+ motion_pre = normalize(transform_point(&tfm, motion_pre));
+ motion_pre = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_pre));
+ motion_pre.x *= kernel_data.cam.width;
+ motion_pre.y *= kernel_data.cam.height;
+
+ tfm = kernel_data.cam.motion_pass_post;
+ motion_post = normalize(transform_point(&tfm, motion_post));
+ motion_post = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_post));
+ motion_post.x *= kernel_data.cam.width;
+ motion_post.y *= kernel_data.cam.height;
+ }
+
+ motion_pre = motion_pre - motion_center;
+ motion_post = motion_center - motion_post;
+
+ return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_shader_data.h b/intern/cycles/kernel/geom/shader_data.h
index 46bda2b656c..46bda2b656c 100644
--- a/intern/cycles/kernel/geom/geom_shader_data.h
+++ b/intern/cycles/kernel/geom/shader_data.h
diff --git a/intern/cycles/kernel/geom/geom_subd_triangle.h b/intern/cycles/kernel/geom/subd_triangle.h
index 8a9a3f71231..8a9a3f71231 100644
--- a/intern/cycles/kernel/geom/geom_subd_triangle.h
+++ b/intern/cycles/kernel/geom/subd_triangle.h
diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/triangle.h
index 233e901c7ca..233e901c7ca 100644
--- a/intern/cycles/kernel/geom/geom_triangle.h
+++ b/intern/cycles/kernel/geom/triangle.h
diff --git a/intern/cycles/kernel/geom/triangle_intersect.h b/intern/cycles/kernel/geom/triangle_intersect.h
new file mode 100644
index 00000000000..faff8a85a93
--- /dev/null
+++ b/intern/cycles/kernel/geom/triangle_intersect.h
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2014, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Triangle/Ray intersections.
+ *
+ * For BVH ray intersection we use a precomputed triangle storage to accelerate
+ * intersection at the cost of more memory usage.
+ */
+
+#pragma once
+
+#include "kernel/sample/lcg.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline bool triangle_intersect(KernelGlobals kg,
+ ccl_private Intersection *isect,
+ float3 P,
+ float3 dir,
+ float tmax,
+ uint visibility,
+ int object,
+ int prim_addr)
+{
+ const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
+#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
+ const ssef *ssef_verts = (ssef *)&kg->__tri_verts.data[tri_vindex];
+#else
+ const float4 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
+ tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
+ tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
+#endif
+ float t, u, v;
+ if (ray_triangle_intersect(P,
+ dir,
+ tmax,
+#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
+ ssef_verts,
+#else
+ float4_to_float3(tri_a),
+ float4_to_float3(tri_b),
+ float4_to_float3(tri_c),
+#endif
+ &u,
+ &v,
+ &t)) {
+#ifdef __VISIBILITY_FLAG__
+ /* Visibility flag test. we do it here under the assumption
+ * that most triangles are culled by node flags.
+ */
+ if (kernel_tex_fetch(__prim_visibility, prim_addr) & visibility)
+#endif
+ {
+ isect->object = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, prim_addr) :
+ object;
+ isect->prim = prim;
+ isect->type = PRIMITIVE_TRIANGLE;
+ isect->u = u;
+ isect->v = v;
+ isect->t = t;
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Special ray intersection routines for subsurface scattering. In that case we
+ * only want to intersect with primitives in the same object, and if case of
+ * multiple hits we pick a single random primitive as the intersection point.
+ * Returns whether traversal should be stopped.
+ */
+
+#ifdef __BVH_LOCAL__
+ccl_device_inline bool triangle_intersect_local(KernelGlobals kg,
+ ccl_private LocalIntersection *local_isect,
+ float3 P,
+ float3 dir,
+ int object,
+ int local_object,
+ int prim_addr,
+ float tmax,
+ ccl_private uint *lcg_state,
+ int max_hits)
+{
+ /* Only intersect with matching object, for instanced objects we
+ * already know we are only intersecting the right object. */
+ if (object == OBJECT_NONE) {
+ if (kernel_tex_fetch(__prim_object, prim_addr) != local_object) {
+ return false;
+ }
+ }
+
+ const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
+# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
+ const ssef *ssef_verts = (ssef *)&kg->__tri_verts.data[tri_vindex];
+# else
+ const float3 tri_a = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 0)),
+ tri_b = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 1)),
+ tri_c = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 2));
+# endif
+ float t, u, v;
+ if (!ray_triangle_intersect(P,
+ dir,
+ tmax,
+# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
+ ssef_verts,
+# else
+ tri_a,
+ tri_b,
+ tri_c,
+# endif
+ &u,
+ &v,
+ &t)) {
+ return false;
+ }
+
+ /* If no actual hit information is requested, just return here. */
+ if (max_hits == 0) {
+ return true;
+ }
+
+ int hit;
+ if (lcg_state) {
+ /* Record up to max_hits intersections. */
+ for (int i = min(max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
+ if (local_isect->hits[i].t == t) {
+ return false;
+ }
+ }
+
+ local_isect->num_hits++;
+
+ if (local_isect->num_hits <= max_hits) {
+ hit = local_isect->num_hits - 1;
+ }
+ else {
+ /* reservoir sampling: if we are at the maximum number of
+ * hits, randomly replace element or skip it */
+ hit = lcg_step_uint(lcg_state) % local_isect->num_hits;
+
+ if (hit >= max_hits)
+ return false;
+ }
+ }
+ else {
+ /* Record closest intersection only. */
+ if (local_isect->num_hits && t > local_isect->hits[0].t) {
+ return false;
+ }
+
+ hit = 0;
+ local_isect->num_hits = 1;
+ }
+
+ /* Record intersection. */
+ ccl_private Intersection *isect = &local_isect->hits[hit];
+ isect->prim = prim;
+ isect->object = local_object;
+ isect->type = PRIMITIVE_TRIANGLE;
+ isect->u = u;
+ isect->v = v;
+ isect->t = t;
+
+ /* Record geometric normal. */
+# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
+ const float3 tri_a = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 0)),
+ tri_b = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 1)),
+ tri_c = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 2));
+# endif
+ local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
+
+ return false;
+}
+#endif /* __BVH_LOCAL__ */
+
+/* Refine triangle intersection to more precise hit point. For rays that travel
+ * far the precision is often not so good, this reintersects the primitive from
+ * a closer distance. */
+
+/* Reintersections uses the paper:
+ *
+ * Tomas Moeller
+ * Fast, minimum storage ray/triangle intersection
+ * http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf
+ */
+
+ccl_device_inline float3 triangle_refine(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ float3 P,
+ float3 D,
+ float t,
+ const int isect_object,
+ const int isect_prim)
+{
+#ifdef __INTERSECTION_REFINE__
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ if (UNLIKELY(t == 0.0f)) {
+ return P;
+ }
+ const Transform tfm = object_get_inverse_transform(kg, sd);
+
+ P = transform_point(&tfm, P);
+ D = transform_direction(&tfm, D * t);
+ D = normalize_len(D, &t);
+ }
+
+ P = P + D * t;
+
+ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w;
+ const float4 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
+ tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
+ tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
+ float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
+ float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
+ float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
+ float3 qvec = cross(tvec, edge1);
+ float3 pvec = cross(D, edge2);
+ float det = dot(edge1, pvec);
+ if (det != 0.0f) {
+ /* If determinant is zero it means ray lies in the plane of
+ * the triangle. It is possible in theory due to watertight
+ * nature of triangle intersection. For such cases we simply
+ * don't refine intersection hoping it'll go all fine.
+ */
+ float rt = dot(edge2, qvec) / det;
+ P = P + D * rt;
+ }
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ const Transform tfm = object_get_transform(kg, sd);
+ P = transform_point(&tfm, P);
+ }
+
+ return P;
+#else
+ return P + D * t;
+#endif
+}
+
+/* Same as above, except that t is assumed to be in object space for
+ * instancing.
+ */
+ccl_device_inline float3 triangle_refine_local(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ float3 P,
+ float3 D,
+ float t,
+ const int isect_object,
+ const int isect_prim)
+{
+#ifdef __KERNEL_OPTIX__
+ /* t is always in world space with OptiX. */
+ return triangle_refine(kg, sd, P, D, t, isect_object, isect_prim);
+#else
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ const Transform tfm = object_get_inverse_transform(kg, sd);
+
+ P = transform_point(&tfm, P);
+ D = transform_direction(&tfm, D);
+ D = normalize(D);
+ }
+
+ P = P + D * t;
+
+# ifdef __INTERSECTION_REFINE__
+ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w;
+ const float4 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
+ tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
+ tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
+ float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
+ float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
+ float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
+ float3 qvec = cross(tvec, edge1);
+ float3 pvec = cross(D, edge2);
+ float det = dot(edge1, pvec);
+ if (det != 0.0f) {
+ /* If determinant is zero it means ray lies in the plane of
+ * the triangle. It is possible in theory due to watertight
+ * nature of triangle intersection. For such cases we simply
+ * don't refine intersection hoping it'll go all fine.
+ */
+ float rt = dot(edge2, qvec) / det;
+ P = P + D * rt;
+ }
+# endif /* __INTERSECTION_REFINE__ */
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ const Transform tfm = object_get_transform(kg, sd);
+ P = transform_point(&tfm, P);
+ }
+
+ return P;
+#endif
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/volume.h
index 4e83ad6acb3..4e83ad6acb3 100644
--- a/intern/cycles/kernel/geom/geom_volume.h
+++ b/intern/cycles/kernel/geom/volume.h
diff --git a/intern/cycles/kernel/integrator/init_from_bake.h b/intern/cycles/kernel/integrator/init_from_bake.h
new file mode 100644
index 00000000000..4e30563e21b
--- /dev/null
+++ b/intern/cycles/kernel/integrator/init_from_bake.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/camera/camera.h"
+
+#include "kernel/film/accumulate.h"
+#include "kernel/film/adaptive_sampling.h"
+
+#include "kernel/integrator/path_state.h"
+
+#include "kernel/sample/pattern.h"
+
+#include "kernel/geom/geom.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* This helps with AA but it's not the real solution as it does not AA the geometry
+ * but it's better than nothing, thus committed. */
+ccl_device_inline float bake_clamp_mirror_repeat(float u, float max)
+{
+ /* use mirror repeat (like opengl texture) so that if the barycentric
+ * coordinate goes past the end of the triangle it is not always clamped
+ * to the same value, gives ugly patterns */
+ u /= max;
+ float fu = floorf(u);
+ u = u - fu;
+
+ return ((((int)fu) & 1) ? 1.0f - u : u) * max;
+}
+
+/* Return false to indicate that this pixel is finished.
+ * Used by CPU implementation to not attempt to sample pixel for multiple samples once its known
+ * that the pixel did converge. */
+ccl_device bool integrator_init_from_bake(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global const KernelWorkTile *ccl_restrict tile,
+ ccl_global float *render_buffer,
+ const int x,
+ const int y,
+ const int scheduled_sample)
+{
+ PROFILING_INIT(kg, PROFILING_RAY_SETUP);
+
+ /* Initialize path state to give basic buffer access and allow early outputs. */
+ path_state_init(state, tile, x, y);
+
+ /* Check whether the pixel has converged and should not be sampled anymore. */
+ if (!kernel_need_sample_pixel(kg, state, render_buffer)) {
+ return false;
+ }
+
+ /* Always count the sample, even if the camera sample will reject the ray. */
+ const int sample = kernel_accum_sample(kg, state, render_buffer, scheduled_sample);
+
+ /* Setup render buffers. */
+ const int index = INTEGRATOR_STATE(state, path, render_pixel_index);
+ const int pass_stride = kernel_data.film.pass_stride;
+ render_buffer += index * pass_stride;
+
+ ccl_global float *primitive = render_buffer + kernel_data.film.pass_bake_primitive;
+ ccl_global float *differential = render_buffer + kernel_data.film.pass_bake_differential;
+
+ const int seed = __float_as_uint(primitive[0]);
+ int prim = __float_as_uint(primitive[1]);
+ if (prim == -1) {
+ return false;
+ }
+
+ prim += kernel_data.bake.tri_offset;
+
+ /* Random number generator. */
+ const uint rng_hash = hash_uint(seed) ^ kernel_data.integrator.seed;
+
+ float filter_x, filter_y;
+ if (sample == 0) {
+ filter_x = filter_y = 0.5f;
+ }
+ else {
+ path_rng_2D(kg, rng_hash, sample, PRNG_FILTER_U, &filter_x, &filter_y);
+ }
+
+ /* Initialize path state for path integration. */
+ path_state_init_integrator(kg, state, sample, rng_hash);
+
+ /* Barycentric UV with sub-pixel offset. */
+ float u = primitive[2];
+ float v = primitive[3];
+
+ float dudx = differential[0];
+ float dudy = differential[1];
+ float dvdx = differential[2];
+ float dvdy = differential[3];
+
+ if (sample > 0) {
+ u = bake_clamp_mirror_repeat(u + dudx * (filter_x - 0.5f) + dudy * (filter_y - 0.5f), 1.0f);
+ v = bake_clamp_mirror_repeat(v + dvdx * (filter_x - 0.5f) + dvdy * (filter_y - 0.5f),
+ 1.0f - u);
+ }
+
+ /* Position and normal on triangle. */
+ const int object = kernel_data.bake.object_index;
+ float3 P, Ng;
+ int shader;
+ triangle_point_normal(kg, object, prim, u, v, &P, &Ng, &shader);
+
+ const int object_flag = kernel_tex_fetch(__object_flag, object);
+ if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ P = transform_point_auto(&tfm, P);
+ }
+
+ if (kernel_data.film.pass_background != PASS_UNUSED) {
+ /* Environment baking. */
+
+ /* Setup and write ray. */
+ Ray ray ccl_optional_struct_init;
+ ray.P = zero_float3();
+ ray.D = normalize(P);
+ ray.t = FLT_MAX;
+ ray.time = 0.5f;
+ ray.dP = differential_zero_compact();
+ ray.dD = differential_zero_compact();
+ integrator_state_write_ray(kg, state, &ray);
+
+ /* Setup next kernel to execute. */
+ INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ }
+ else {
+ /* Surface baking. */
+ float3 N = (shader & SHADER_SMOOTH_NORMAL) ? triangle_smooth_normal(kg, Ng, prim, u, v) : Ng;
+
+ if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ N = normalize(transform_direction_transposed(&itfm, N));
+ Ng = normalize(transform_direction_transposed(&itfm, Ng));
+ }
+
+ /* Setup ray. */
+ Ray ray ccl_optional_struct_init;
+ ray.P = P + N;
+ ray.D = -N;
+ ray.t = FLT_MAX;
+ ray.time = 0.5f;
+
+ /* Setup differentials. */
+ float3 dPdu, dPdv;
+ triangle_dPdudv(kg, prim, &dPdu, &dPdv);
+ if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ dPdu = transform_direction(&tfm, dPdu);
+ dPdv = transform_direction(&tfm, dPdv);
+ }
+
+ differential3 dP;
+ dP.dx = dPdu * dudx + dPdv * dvdx;
+ dP.dy = dPdu * dudy + dPdv * dvdy;
+ ray.dP = differential_make_compact(dP);
+ ray.dD = differential_zero_compact();
+
+ /* Write ray. */
+ integrator_state_write_ray(kg, state, &ray);
+
+ /* Setup and write intersection. */
+ Intersection isect ccl_optional_struct_init;
+ isect.object = kernel_data.bake.object_index;
+ isect.prim = prim;
+ isect.u = u;
+ isect.v = v;
+ isect.t = 1.0f;
+ isect.type = PRIMITIVE_TRIANGLE;
+ integrator_state_write_isect(kg, state, &isect);
+
+ /* Setup next kernel to execute. */
+ const int shader_index = shader & SHADER_MASK;
+ const int shader_flags = kernel_tex_fetch(__shaders, shader_index).flags;
+ if (shader_flags & SD_HAS_RAYTRACE) {
+ INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader_index);
+ }
+ else {
+ INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader_index);
+ }
+ }
+
+ return true;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/init_from_camera.h b/intern/cycles/kernel/integrator/init_from_camera.h
new file mode 100644
index 00000000000..f0ba77bd9a6
--- /dev/null
+++ b/intern/cycles/kernel/integrator/init_from_camera.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/camera/camera.h"
+
+#include "kernel/film/accumulate.h"
+#include "kernel/film/adaptive_sampling.h"
+
+#include "kernel/integrator/path_state.h"
+#include "kernel/integrator/shadow_catcher.h"
+
+#include "kernel/sample/pattern.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline void integrate_camera_sample(KernelGlobals kg,
+ const int sample,
+ const int x,
+ const int y,
+ const uint rng_hash,
+ ccl_private Ray *ray)
+{
+ /* Filter sampling. */
+ float filter_u, filter_v;
+
+ if (sample == 0) {
+ filter_u = 0.5f;
+ filter_v = 0.5f;
+ }
+ else {
+ path_rng_2D(kg, rng_hash, sample, PRNG_FILTER_U, &filter_u, &filter_v);
+ }
+
+ /* Depth of field sampling. */
+ float lens_u = 0.0f, lens_v = 0.0f;
+ if (kernel_data.cam.aperturesize > 0.0f) {
+ path_rng_2D(kg, rng_hash, sample, PRNG_LENS_U, &lens_u, &lens_v);
+ }
+
+ /* Motion blur time sampling. */
+ float time = 0.0f;
+#ifdef __CAMERA_MOTION__
+ if (kernel_data.cam.shuttertime != -1.0f)
+ time = path_rng_1D(kg, rng_hash, sample, PRNG_TIME);
+#endif
+
+ /* Generate camera ray. */
+ camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, time, ray);
+}
+
+/* Return false to indicate that this pixel is finished.
+ * Used by CPU implementation to not attempt to sample pixel for multiple samples once its known
+ * that the pixel did converge. */
+ccl_device bool integrator_init_from_camera(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global const KernelWorkTile *ccl_restrict tile,
+ ccl_global float *render_buffer,
+ const int x,
+ const int y,
+ const int scheduled_sample)
+{
+ PROFILING_INIT(kg, PROFILING_RAY_SETUP);
+
+ /* Initialize path state to give basic buffer access and allow early outputs. */
+ path_state_init(state, tile, x, y);
+
+ /* Check whether the pixel has converged and should not be sampled anymore. */
+ if (!kernel_need_sample_pixel(kg, state, render_buffer)) {
+ return false;
+ }
+
+ /* Count the sample and get an effective sample for this pixel.
+ *
+ * This logic allows to both count actual number of samples per pixel, and to add samples to this
+ * pixel after it was converged and samples were added somewhere else (in which case the
+ * `scheduled_sample` will be different from actual number of samples in this pixel). */
+ const int sample = kernel_accum_sample(kg, state, render_buffer, scheduled_sample);
+
+ /* Initialize random number seed for path. */
+ const uint rng_hash = path_rng_hash_init(kg, sample, x, y);
+
+ {
+ /* Generate camera ray. */
+ Ray ray;
+ integrate_camera_sample(kg, sample, x, y, rng_hash, &ray);
+ if (ray.t == 0.0f) {
+ return true;
+ }
+
+ /* Write camera ray to state. */
+ integrator_state_write_ray(kg, state, &ray);
+ }
+
+ /* Initialize path state for path integration. */
+ path_state_init_integrator(kg, state, sample, rng_hash);
+
+ /* Continue with intersect_closest kernel, optionally initializing volume
+ * stack before that if the camera may be inside a volume. */
+ if (kernel_data.cam.is_inside_volume) {
+ INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
+ }
+ else {
+ INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
+ }
+
+ return true;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_init_from_bake.h b/intern/cycles/kernel/integrator/integrator_init_from_bake.h
deleted file mode 100644
index de916be24e7..00000000000
--- a/intern/cycles/kernel/integrator/integrator_init_from_bake.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_accumulate.h"
-#include "kernel/kernel_adaptive_sampling.h"
-#include "kernel/kernel_camera.h"
-#include "kernel/kernel_path_state.h"
-#include "kernel/kernel_random.h"
-
-#include "kernel/geom/geom.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* This helps with AA but it's not the real solution as it does not AA the geometry
- * but it's better than nothing, thus committed. */
-ccl_device_inline float bake_clamp_mirror_repeat(float u, float max)
-{
- /* use mirror repeat (like opengl texture) so that if the barycentric
- * coordinate goes past the end of the triangle it is not always clamped
- * to the same value, gives ugly patterns */
- u /= max;
- float fu = floorf(u);
- u = u - fu;
-
- return ((((int)fu) & 1) ? 1.0f - u : u) * max;
-}
-
-/* Return false to indicate that this pixel is finished.
- * Used by CPU implementation to not attempt to sample pixel for multiple samples once its known
- * that the pixel did converge. */
-ccl_device bool integrator_init_from_bake(KernelGlobals kg,
- IntegratorState state,
- ccl_global const KernelWorkTile *ccl_restrict tile,
- ccl_global float *render_buffer,
- const int x,
- const int y,
- const int scheduled_sample)
-{
- PROFILING_INIT(kg, PROFILING_RAY_SETUP);
-
- /* Initialize path state to give basic buffer access and allow early outputs. */
- path_state_init(state, tile, x, y);
-
- /* Check whether the pixel has converged and should not be sampled anymore. */
- if (!kernel_need_sample_pixel(kg, state, render_buffer)) {
- return false;
- }
-
- /* Always count the sample, even if the camera sample will reject the ray. */
- const int sample = kernel_accum_sample(kg, state, render_buffer, scheduled_sample);
-
- /* Setup render buffers. */
- const int index = INTEGRATOR_STATE(state, path, render_pixel_index);
- const int pass_stride = kernel_data.film.pass_stride;
- render_buffer += index * pass_stride;
-
- ccl_global float *primitive = render_buffer + kernel_data.film.pass_bake_primitive;
- ccl_global float *differential = render_buffer + kernel_data.film.pass_bake_differential;
-
- const int seed = __float_as_uint(primitive[0]);
- int prim = __float_as_uint(primitive[1]);
- if (prim == -1) {
- return false;
- }
-
- prim += kernel_data.bake.tri_offset;
-
- /* Random number generator. */
- const uint rng_hash = hash_uint(seed) ^ kernel_data.integrator.seed;
-
- float filter_x, filter_y;
- if (sample == 0) {
- filter_x = filter_y = 0.5f;
- }
- else {
- path_rng_2D(kg, rng_hash, sample, PRNG_FILTER_U, &filter_x, &filter_y);
- }
-
- /* Initialize path state for path integration. */
- path_state_init_integrator(kg, state, sample, rng_hash);
-
- /* Barycentric UV with sub-pixel offset. */
- float u = primitive[2];
- float v = primitive[3];
-
- float dudx = differential[0];
- float dudy = differential[1];
- float dvdx = differential[2];
- float dvdy = differential[3];
-
- if (sample > 0) {
- u = bake_clamp_mirror_repeat(u + dudx * (filter_x - 0.5f) + dudy * (filter_y - 0.5f), 1.0f);
- v = bake_clamp_mirror_repeat(v + dvdx * (filter_x - 0.5f) + dvdy * (filter_y - 0.5f),
- 1.0f - u);
- }
-
- /* Position and normal on triangle. */
- const int object = kernel_data.bake.object_index;
- float3 P, Ng;
- int shader;
- triangle_point_normal(kg, object, prim, u, v, &P, &Ng, &shader);
-
- const int object_flag = kernel_tex_fetch(__object_flag, object);
- if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- P = transform_point_auto(&tfm, P);
- }
-
- if (kernel_data.film.pass_background != PASS_UNUSED) {
- /* Environment baking. */
-
- /* Setup and write ray. */
- Ray ray ccl_optional_struct_init;
- ray.P = zero_float3();
- ray.D = normalize(P);
- ray.t = FLT_MAX;
- ray.time = 0.5f;
- ray.dP = differential_zero_compact();
- ray.dD = differential_zero_compact();
- integrator_state_write_ray(kg, state, &ray);
-
- /* Setup next kernel to execute. */
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
- }
- else {
- /* Surface baking. */
- float3 N = (shader & SHADER_SMOOTH_NORMAL) ? triangle_smooth_normal(kg, Ng, prim, u, v) : Ng;
-
- if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
- N = normalize(transform_direction_transposed(&itfm, N));
- Ng = normalize(transform_direction_transposed(&itfm, Ng));
- }
-
- /* Setup ray. */
- Ray ray ccl_optional_struct_init;
- ray.P = P + N;
- ray.D = -N;
- ray.t = FLT_MAX;
- ray.time = 0.5f;
-
- /* Setup differentials. */
- float3 dPdu, dPdv;
- triangle_dPdudv(kg, prim, &dPdu, &dPdv);
- if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- dPdu = transform_direction(&tfm, dPdu);
- dPdv = transform_direction(&tfm, dPdv);
- }
-
- differential3 dP;
- dP.dx = dPdu * dudx + dPdv * dvdx;
- dP.dy = dPdu * dudy + dPdv * dvdy;
- ray.dP = differential_make_compact(dP);
- ray.dD = differential_zero_compact();
-
- /* Write ray. */
- integrator_state_write_ray(kg, state, &ray);
-
- /* Setup and write intersection. */
- Intersection isect ccl_optional_struct_init;
- isect.object = kernel_data.bake.object_index;
- isect.prim = prim;
- isect.u = u;
- isect.v = v;
- isect.t = 1.0f;
- isect.type = PRIMITIVE_TRIANGLE;
- integrator_state_write_isect(kg, state, &isect);
-
- /* Setup next kernel to execute. */
- const int shader_index = shader & SHADER_MASK;
- const int shader_flags = kernel_tex_fetch(__shaders, shader_index).flags;
- if (shader_flags & SD_HAS_RAYTRACE) {
- INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader_index);
- }
- else {
- INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader_index);
- }
- }
-
- return true;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_init_from_camera.h b/intern/cycles/kernel/integrator/integrator_init_from_camera.h
deleted file mode 100644
index 5bab6b2e2fd..00000000000
--- a/intern/cycles/kernel/integrator/integrator_init_from_camera.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_accumulate.h"
-#include "kernel/kernel_adaptive_sampling.h"
-#include "kernel/kernel_camera.h"
-#include "kernel/kernel_path_state.h"
-#include "kernel/kernel_random.h"
-#include "kernel/kernel_shadow_catcher.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_inline void integrate_camera_sample(KernelGlobals kg,
- const int sample,
- const int x,
- const int y,
- const uint rng_hash,
- ccl_private Ray *ray)
-{
- /* Filter sampling. */
- float filter_u, filter_v;
-
- if (sample == 0) {
- filter_u = 0.5f;
- filter_v = 0.5f;
- }
- else {
- path_rng_2D(kg, rng_hash, sample, PRNG_FILTER_U, &filter_u, &filter_v);
- }
-
- /* Depth of field sampling. */
- float lens_u = 0.0f, lens_v = 0.0f;
- if (kernel_data.cam.aperturesize > 0.0f) {
- path_rng_2D(kg, rng_hash, sample, PRNG_LENS_U, &lens_u, &lens_v);
- }
-
- /* Motion blur time sampling. */
- float time = 0.0f;
-#ifdef __CAMERA_MOTION__
- if (kernel_data.cam.shuttertime != -1.0f)
- time = path_rng_1D(kg, rng_hash, sample, PRNG_TIME);
-#endif
-
- /* Generate camera ray. */
- camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, time, ray);
-}
-
-/* Return false to indicate that this pixel is finished.
- * Used by CPU implementation to not attempt to sample pixel for multiple samples once its known
- * that the pixel did converge. */
-ccl_device bool integrator_init_from_camera(KernelGlobals kg,
- IntegratorState state,
- ccl_global const KernelWorkTile *ccl_restrict tile,
- ccl_global float *render_buffer,
- const int x,
- const int y,
- const int scheduled_sample)
-{
- PROFILING_INIT(kg, PROFILING_RAY_SETUP);
-
- /* Initialize path state to give basic buffer access and allow early outputs. */
- path_state_init(state, tile, x, y);
-
- /* Check whether the pixel has converged and should not be sampled anymore. */
- if (!kernel_need_sample_pixel(kg, state, render_buffer)) {
- return false;
- }
-
- /* Count the sample and get an effective sample for this pixel.
- *
- * This logic allows to both count actual number of samples per pixel, and to add samples to this
- * pixel after it was converged and samples were added somewhere else (in which case the
- * `scheduled_sample` will be different from actual number of samples in this pixel). */
- const int sample = kernel_accum_sample(kg, state, render_buffer, scheduled_sample);
-
- /* Initialize random number seed for path. */
- const uint rng_hash = path_rng_hash_init(kg, sample, x, y);
-
- {
- /* Generate camera ray. */
- Ray ray;
- integrate_camera_sample(kg, sample, x, y, rng_hash, &ray);
- if (ray.t == 0.0f) {
- return true;
- }
-
- /* Write camera ray to state. */
- integrator_state_write_ray(kg, state, &ray);
- }
-
- /* Initialize path state for path integration. */
- path_state_init_integrator(kg, state, sample, rng_hash);
-
- /* Continue with intersect_closest kernel, optionally initializing volume
- * stack before that if the camera may be inside a volume. */
- if (kernel_data.cam.is_inside_volume) {
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
- }
- else {
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
- }
-
- return true;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_intersect_closest.h b/intern/cycles/kernel/integrator/integrator_intersect_closest.h
deleted file mode 100644
index c1315d48694..00000000000
--- a/intern/cycles/kernel/integrator/integrator_intersect_closest.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_differential.h"
-#include "kernel/kernel_light.h"
-#include "kernel/kernel_path_state.h"
-#include "kernel/kernel_projection.h"
-#include "kernel/kernel_shadow_catcher.h"
-
-#include "kernel/geom/geom.h"
-
-#include "kernel/bvh/bvh.h"
-
-CCL_NAMESPACE_BEGIN
-
-template<uint32_t current_kernel>
-ccl_device_forceinline bool integrator_intersect_terminate(KernelGlobals kg,
- IntegratorState state,
- const int shader_flags)
-{
-
- /* Optional AO bounce termination.
- * We continue evaluating emissive/transparent surfaces and volumes, similar
- * to direct lighting. Only if we know there are none can we terminate the
- * path immediately. */
- if (path_state_ao_bounce(kg, state)) {
- if (shader_flags & (SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) {
- INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
- }
- else if (!integrator_state_volume_stack_is_empty(kg, state)) {
- INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_AFTER_VOLUME;
- }
- else {
- return true;
- }
- }
-
- /* Load random number state. */
- RNGState rng_state;
- path_state_rng_load(state, &rng_state);
-
- /* We perform path termination in this kernel to avoid launching shade_surface
- * and evaluating the shader when not needed. Only for emission and transparent
- * surfaces in front of emission do we need to evaluate the shader, since we
- * perform MIS as part of indirect rays. */
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
- const float probability = path_state_continuation_probability(kg, state, path_flag);
-
- if (probability != 1.0f) {
- const float terminate = path_state_rng_1D(kg, &rng_state, PRNG_TERMINATE);
-
- if (probability == 0.0f || terminate >= probability) {
- if (shader_flags & SD_HAS_EMISSION) {
- /* Mark path to be terminated right after shader evaluation on the surface. */
- INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE;
- }
- else if (!integrator_state_volume_stack_is_empty(kg, state)) {
- /* TODO: only do this for emissive volumes. */
- INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_IN_NEXT_VOLUME;
- }
- else {
- return true;
- }
- }
- }
-
- return false;
-}
-
-/* Note that current_kernel is a template value since making this a variable
- * leads to poor performance with CUDA atomics. */
-template<uint32_t current_kernel>
-ccl_device_forceinline void integrator_intersect_shader_next_kernel(
- KernelGlobals kg,
- IntegratorState state,
- ccl_private const Intersection *ccl_restrict isect,
- const int shader,
- const int shader_flags)
-{
- /* Note on scheduling.
- *
- * When there is no shadow catcher split the scheduling is simple: schedule surface shading with
- * or without raytrace support, depending on the shader used.
- *
- * When there is a shadow catcher split the general idea is to have the following configuration:
- *
- * - Schedule surface shading kernel (with corresponding raytrace support) for the ray which
- * will trace shadow catcher object.
- *
- * - When no alpha-over of approximate shadow catcher is needed, schedule surface shading for
- * the matte ray.
- *
- * - Otherwise schedule background shading kernel, so that we have a background to alpha-over
- * on. The background kernel will then schedule surface shading for the matte ray.
- *
- * Note that the splitting leaves kernel and sorting counters as-is, so use INIT semantic for
- * the matte path. */
-
- const bool use_raytrace_kernel = (shader_flags & SD_HAS_RAYTRACE);
-
- if (use_raytrace_kernel) {
- INTEGRATOR_PATH_NEXT_SORTED(
- current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
- }
- else {
- INTEGRATOR_PATH_NEXT_SORTED(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
- }
-
-#ifdef __SHADOW_CATCHER__
- const int object_flags = intersection_get_object_flags(kg, isect);
- if (kernel_shadow_catcher_split(kg, state, object_flags)) {
- if (kernel_data.film.pass_background != PASS_UNUSED && !kernel_data.background.transparent) {
- INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SHADOW_CATCHER_BACKGROUND;
-
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
- }
- else if (use_raytrace_kernel) {
- INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
- }
- else {
- INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
- }
- }
-#endif
-}
-
-ccl_device void integrator_intersect_closest(KernelGlobals kg, IntegratorState state)
-{
- PROFILING_INIT(kg, PROFILING_INTERSECT_CLOSEST);
-
- /* Read ray from integrator state into local memory. */
- Ray ray ccl_optional_struct_init;
- integrator_state_read_ray(kg, state, &ray);
- kernel_assert(ray.t != 0.0f);
-
- const uint visibility = path_state_ray_visibility(state);
- const int last_isect_prim = INTEGRATOR_STATE(state, isect, prim);
- const int last_isect_object = INTEGRATOR_STATE(state, isect, object);
-
- /* Trick to use short AO rays to approximate indirect light at the end of the path. */
- if (path_state_ao_bounce(kg, state)) {
- ray.t = kernel_data.integrator.ao_bounces_distance;
-
- const float object_ao_distance = kernel_tex_fetch(__objects, last_isect_object).ao_distance;
- if (object_ao_distance != 0.0f) {
- ray.t = object_ao_distance;
- }
- }
-
- /* Scene Intersection. */
- Intersection isect ccl_optional_struct_init;
- bool hit = scene_intersect(kg, &ray, visibility, &isect);
-
- /* TODO: remove this and do it in the various intersection functions instead. */
- if (!hit) {
- isect.prim = PRIM_NONE;
- }
-
- /* Light intersection for MIS. */
- if (kernel_data.integrator.use_lamp_mis) {
- /* NOTE: if we make lights visible to camera rays, we'll need to initialize
- * these in the path_state_init. */
- const int last_type = INTEGRATOR_STATE(state, isect, type);
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- hit = lights_intersect(
- kg, &ray, &isect, last_isect_prim, last_isect_object, last_type, path_flag) ||
- hit;
- }
-
- /* Write intersection result into global integrator state memory. */
- integrator_state_write_isect(kg, state, &isect);
-
-#ifdef __VOLUME__
- if (!integrator_state_volume_stack_is_empty(kg, state)) {
- const bool hit_surface = hit && !(isect.type & PRIMITIVE_LAMP);
- const int shader = (hit_surface) ? intersection_get_shader(kg, &isect) : SHADER_NONE;
- const int flags = (hit_surface) ? kernel_tex_fetch(__shaders, shader).flags : 0;
-
- if (!integrator_intersect_terminate<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>(
- kg, state, flags)) {
- /* Continue with volume kernel if we are inside a volume, regardless
- * if we hit anything. */
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST,
- DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
- }
- else {
- INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
- }
- return;
- }
-#endif
-
- if (hit) {
- /* Hit a surface, continue with light or surface kernel. */
- if (isect.type & PRIMITIVE_LAMP) {
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST,
- DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
- return;
- }
- else {
- /* Hit a surface, continue with surface kernel unless terminated. */
- const int shader = intersection_get_shader(kg, &isect);
- const int flags = kernel_tex_fetch(__shaders, shader).flags;
-
- if (!integrator_intersect_terminate<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>(
- kg, state, flags)) {
- integrator_intersect_shader_next_kernel<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>(
- kg, state, &isect, shader, flags);
- return;
- }
- else {
- INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
- return;
- }
- }
- }
- else {
- /* Nothing hit, continue with background kernel. */
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST,
- DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
- return;
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_intersect_subsurface.h b/intern/cycles/kernel/integrator/integrator_intersect_subsurface.h
deleted file mode 100644
index b575e7fd1e6..00000000000
--- a/intern/cycles/kernel/integrator/integrator_intersect_subsurface.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/integrator/integrator_subsurface.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device void integrator_intersect_subsurface(KernelGlobals kg, IntegratorState state)
-{
- PROFILING_INIT(kg, PROFILING_INTERSECT_SUBSURFACE);
-
-#ifdef __SUBSURFACE__
- if (subsurface_scatter(kg, state)) {
- return;
- }
-#endif
-
- INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_intersect_volume_stack.h b/intern/cycles/kernel/integrator/integrator_intersect_volume_stack.h
deleted file mode 100644
index 7def3e2f3f3..00000000000
--- a/intern/cycles/kernel/integrator/integrator_intersect_volume_stack.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/bvh/bvh.h"
-#include "kernel/geom/geom.h"
-#include "kernel/integrator/integrator_volume_stack.h"
-#include "kernel/kernel_shader.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg,
- IntegratorState state,
- const float3 from_P,
- const float3 to_P)
-{
- PROFILING_INIT(kg, PROFILING_INTERSECT_VOLUME_STACK);
-
- ShaderDataTinyStorage stack_sd_storage;
- ccl_private ShaderData *stack_sd = AS_SHADER_DATA(&stack_sd_storage);
-
- kernel_assert(kernel_data.integrator.use_volumes);
-
- Ray volume_ray ccl_optional_struct_init;
- volume_ray.P = from_P;
- volume_ray.D = normalize_len(to_P - from_P, &volume_ray.t);
-
- /* Store to avoid global fetches on every intersection step. */
- const uint volume_stack_size = kernel_data.volume_stack_size;
-
-#ifdef __VOLUME_RECORD_ALL__
- Intersection hits[2 * MAX_VOLUME_STACK_SIZE + 1];
- uint num_hits = scene_intersect_volume_all(
- kg, &volume_ray, hits, 2 * volume_stack_size, PATH_RAY_ALL_VISIBILITY);
- if (num_hits > 0) {
- Intersection *isect = hits;
-
- qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
-
- for (uint hit = 0; hit < num_hits; ++hit, ++isect) {
- shader_setup_from_ray(kg, stack_sd, &volume_ray, isect);
- volume_stack_enter_exit(kg, state, stack_sd);
- }
- }
-#else
- Intersection isect;
- int step = 0;
- while (step < 2 * volume_stack_size &&
- scene_intersect_volume(kg, &volume_ray, &isect, PATH_RAY_ALL_VISIBILITY)) {
- shader_setup_from_ray(kg, stack_sd, &volume_ray, &isect);
- volume_stack_enter_exit(kg, state, stack_sd);
-
- /* Move ray forward. */
- volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
- if (volume_ray.t != FLT_MAX) {
- volume_ray.D = normalize_len(to_P - volume_ray.P, &volume_ray.t);
- }
- ++step;
- }
-#endif
-}
-
-ccl_device void integrator_intersect_volume_stack(KernelGlobals kg, IntegratorState state)
-{
- PROFILING_INIT(kg, PROFILING_INTERSECT_VOLUME_STACK);
-
- ShaderDataTinyStorage stack_sd_storage;
- ccl_private ShaderData *stack_sd = AS_SHADER_DATA(&stack_sd_storage);
-
- Ray volume_ray ccl_optional_struct_init;
- integrator_state_read_ray(kg, state, &volume_ray);
- volume_ray.t = FLT_MAX;
-
- const uint visibility = (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_ALL_VISIBILITY);
- int stack_index = 0, enclosed_index = 0;
-
- /* Write background shader. */
- if (kernel_data.background.volume_shader != SHADER_NONE) {
- const VolumeStack new_entry = {OBJECT_NONE, kernel_data.background.volume_shader};
- integrator_state_write_volume_stack(state, stack_index, new_entry);
- stack_index++;
- }
-
- /* Store to avoid global fetches on every intersection step. */
- const uint volume_stack_size = kernel_data.volume_stack_size;
-
-#ifdef __VOLUME_RECORD_ALL__
- Intersection hits[2 * MAX_VOLUME_STACK_SIZE + 1];
- uint num_hits = scene_intersect_volume_all(
- kg, &volume_ray, hits, 2 * volume_stack_size, visibility);
- if (num_hits > 0) {
- int enclosed_volumes[MAX_VOLUME_STACK_SIZE];
- Intersection *isect = hits;
-
- qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
-
- for (uint hit = 0; hit < num_hits; ++hit, ++isect) {
- shader_setup_from_ray(kg, stack_sd, &volume_ray, isect);
- if (stack_sd->flag & SD_BACKFACING) {
- bool need_add = true;
- for (int i = 0; i < enclosed_index && need_add; ++i) {
- /* If ray exited the volume and never entered to that volume
- * it means that camera is inside such a volume.
- */
- if (enclosed_volumes[i] == stack_sd->object) {
- need_add = false;
- }
- }
- for (int i = 0; i < stack_index && need_add; ++i) {
- /* Don't add intersections twice. */
- VolumeStack entry = integrator_state_read_volume_stack(state, i);
- if (entry.object == stack_sd->object) {
- need_add = false;
- break;
- }
- }
- if (need_add && stack_index < volume_stack_size - 1) {
- const VolumeStack new_entry = {stack_sd->object, stack_sd->shader};
- integrator_state_write_volume_stack(state, stack_index, new_entry);
- ++stack_index;
- }
- }
- else {
- /* If ray from camera enters the volume, this volume shouldn't
- * be added to the stack on exit.
- */
- enclosed_volumes[enclosed_index++] = stack_sd->object;
- }
- }
- }
-#else
- /* CUDA does not support definition of a variable size arrays, so use the maximum possible. */
- int enclosed_volumes[MAX_VOLUME_STACK_SIZE];
- int step = 0;
-
- while (stack_index < volume_stack_size - 1 && enclosed_index < volume_stack_size - 1 &&
- step < 2 * volume_stack_size) {
- Intersection isect;
- if (!scene_intersect_volume(kg, &volume_ray, &isect, visibility)) {
- break;
- }
-
- shader_setup_from_ray(kg, stack_sd, &volume_ray, &isect);
- if (stack_sd->flag & SD_BACKFACING) {
- /* If ray exited the volume and never entered to that volume
- * it means that camera is inside such a volume.
- */
- bool need_add = true;
- for (int i = 0; i < enclosed_index && need_add; ++i) {
- /* If ray exited the volume and never entered to that volume
- * it means that camera is inside such a volume.
- */
- if (enclosed_volumes[i] == stack_sd->object) {
- need_add = false;
- }
- }
- for (int i = 0; i < stack_index && need_add; ++i) {
- /* Don't add intersections twice. */
- VolumeStack entry = integrator_state_read_volume_stack(state, i);
- if (entry.object == stack_sd->object) {
- need_add = false;
- break;
- }
- }
- if (need_add) {
- const VolumeStack new_entry = {stack_sd->object, stack_sd->shader};
- integrator_state_write_volume_stack(state, stack_index, new_entry);
- ++stack_index;
- }
- }
- else {
- /* If ray from camera enters the volume, this volume shouldn't
- * be added to the stack on exit.
- */
- enclosed_volumes[enclosed_index++] = stack_sd->object;
- }
-
- /* Move ray forward. */
- volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
- ++step;
- }
-#endif
-
- /* Write terminator. */
- const VolumeStack new_entry = {OBJECT_NONE, SHADER_NONE};
- integrator_state_write_volume_stack(state, stack_index, new_entry);
-
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK,
- DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_megakernel.h b/intern/cycles/kernel/integrator/integrator_megakernel.h
deleted file mode 100644
index 21a483a792b..00000000000
--- a/intern/cycles/kernel/integrator/integrator_megakernel.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/integrator/integrator_init_from_camera.h"
-#include "kernel/integrator/integrator_intersect_closest.h"
-#include "kernel/integrator/integrator_intersect_shadow.h"
-#include "kernel/integrator/integrator_intersect_subsurface.h"
-#include "kernel/integrator/integrator_intersect_volume_stack.h"
-#include "kernel/integrator/integrator_shade_background.h"
-#include "kernel/integrator/integrator_shade_light.h"
-#include "kernel/integrator/integrator_shade_shadow.h"
-#include "kernel/integrator/integrator_shade_surface.h"
-#include "kernel/integrator/integrator_shade_volume.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device void integrator_megakernel(KernelGlobals kg,
- IntegratorState state,
- ccl_global float *ccl_restrict render_buffer)
-{
- /* Each kernel indicates the next kernel to execute, so here we simply
- * have to check what that kernel is and execute it. */
- while (true) {
- /* Handle any shadow paths before we potentially create more shadow paths. */
- const uint32_t shadow_queued_kernel = INTEGRATOR_STATE(
- &state->shadow, shadow_path, queued_kernel);
- if (shadow_queued_kernel) {
- switch (shadow_queued_kernel) {
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
- integrator_intersect_shadow(kg, &state->shadow);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
- integrator_shade_shadow(kg, &state->shadow, render_buffer);
- break;
- default:
- kernel_assert(0);
- break;
- }
- continue;
- }
-
- /* Handle any AO paths before we potentially create more AO paths. */
- const uint32_t ao_queued_kernel = INTEGRATOR_STATE(&state->ao, shadow_path, queued_kernel);
- if (ao_queued_kernel) {
- switch (ao_queued_kernel) {
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
- integrator_intersect_shadow(kg, &state->ao);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
- integrator_shade_shadow(kg, &state->ao, render_buffer);
- break;
- default:
- kernel_assert(0);
- break;
- }
- continue;
- }
-
- /* Then handle regular path kernels. */
- const uint32_t queued_kernel = INTEGRATOR_STATE(state, path, queued_kernel);
- if (queued_kernel) {
- switch (queued_kernel) {
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
- integrator_intersect_closest(kg, state);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND:
- integrator_shade_background(kg, state, render_buffer);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE:
- integrator_shade_surface(kg, state, render_buffer);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME:
- integrator_shade_volume(kg, state, render_buffer);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
- integrator_shade_surface_raytrace(kg, state, render_buffer);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT:
- integrator_shade_light(kg, state, render_buffer);
- break;
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
- integrator_intersect_subsurface(kg, state);
- break;
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
- integrator_intersect_volume_stack(kg, state);
- break;
- default:
- kernel_assert(0);
- break;
- }
- continue;
- }
-
- break;
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_shade_background.h b/intern/cycles/kernel/integrator/integrator_shade_background.h
deleted file mode 100644
index 287c54d7243..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shade_background.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_accumulate.h"
-#include "kernel/kernel_emission.h"
-#include "kernel/kernel_light.h"
-#include "kernel/kernel_shader.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device float3 integrator_eval_background_shader(KernelGlobals kg,
- IntegratorState state,
- ccl_global float *ccl_restrict render_buffer)
-{
-#ifdef __BACKGROUND__
- const int shader = kernel_data.background.surface_shader;
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- /* Use visibility flag to skip lights. */
- if (shader & SHADER_EXCLUDE_ANY) {
- if (((shader & SHADER_EXCLUDE_DIFFUSE) && (path_flag & PATH_RAY_DIFFUSE)) ||
- ((shader & SHADER_EXCLUDE_GLOSSY) && ((path_flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) ==
- (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) ||
- ((shader & SHADER_EXCLUDE_TRANSMIT) && (path_flag & PATH_RAY_TRANSMIT)) ||
- ((shader & SHADER_EXCLUDE_CAMERA) && (path_flag & PATH_RAY_CAMERA)) ||
- ((shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER)))
- return zero_float3();
- }
-
- /* Use fast constant background color if available. */
- float3 L = zero_float3();
- if (!shader_constant_emission_eval(kg, shader, &L)) {
- /* Evaluate background shader. */
-
- /* TODO: does aliasing like this break automatic SoA in CUDA?
- * Should we instead store closures separate from ShaderData? */
- ShaderDataTinyStorage emission_sd_storage;
- ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
-
- PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_LIGHT_SETUP);
- shader_setup_from_background(kg,
- emission_sd,
- INTEGRATOR_STATE(state, ray, P),
- INTEGRATOR_STATE(state, ray, D),
- INTEGRATOR_STATE(state, ray, time));
-
- PROFILING_SHADER(emission_sd->object, emission_sd->shader);
- PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL);
- shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT>(
- kg, state, emission_sd, render_buffer, path_flag | PATH_RAY_EMISSION);
-
- L = shader_background_eval(emission_sd);
- }
-
- /* Background MIS weights. */
-# ifdef __BACKGROUND_MIS__
- /* Check if background light exists or if we should skip pdf. */
- if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_MIS_SKIP) &&
- kernel_data.background.use_mis) {
- const float3 ray_P = INTEGRATOR_STATE(state, ray, P);
- const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
- const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
- const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
-
- /* multiple importance sampling, get background light pdf for ray
- * direction, and compute weight with respect to BSDF pdf */
- const float pdf = background_light_pdf(kg, ray_P - ray_D * mis_ray_t, ray_D);
- const float mis_weight = power_heuristic(mis_ray_pdf, pdf);
-
- L *= mis_weight;
- }
-# endif
-
- return L;
-#else
- return make_float3(0.8f, 0.8f, 0.8f);
-#endif
-}
-
-ccl_device_inline void integrate_background(KernelGlobals kg,
- IntegratorState state,
- ccl_global float *ccl_restrict render_buffer)
-{
- /* Accumulate transparency for transparent background. We can skip background
- * shader evaluation unless a background pass is used. */
- bool eval_background = true;
- float transparent = 0.0f;
-
- const bool is_transparent_background_ray = kernel_data.background.transparent &&
- (INTEGRATOR_STATE(state, path, flag) &
- PATH_RAY_TRANSPARENT_BACKGROUND);
-
- if (is_transparent_background_ray) {
- transparent = average(INTEGRATOR_STATE(state, path, throughput));
-
-#ifdef __PASSES__
- eval_background = (kernel_data.film.light_pass_flag & PASSMASK(BACKGROUND));
-#else
- eval_background = false;
-#endif
- }
-
- /* Evaluate background shader. */
- float3 L = (eval_background) ? integrator_eval_background_shader(kg, state, render_buffer) :
- zero_float3();
-
- /* When using the ao bounces approximation, adjust background
- * shader intensity with ao factor. */
- if (path_state_ao_bounce(kg, state)) {
- L *= kernel_data.integrator.ao_bounces_factor;
- }
-
- /* Write to render buffer. */
- kernel_accum_background(kg, state, L, transparent, is_transparent_background_ray, render_buffer);
-}
-
-ccl_device_inline void integrate_distant_lights(KernelGlobals kg,
- IntegratorState state,
- ccl_global float *ccl_restrict render_buffer)
-{
- const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
- const float ray_time = INTEGRATOR_STATE(state, ray, time);
- LightSample ls ccl_optional_struct_init;
- for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) {
- if (light_sample_from_distant_ray(kg, ray_D, lamp, &ls)) {
- /* Use visibility flag to skip lights. */
-#ifdef __PASSES__
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- if (ls.shader & SHADER_EXCLUDE_ANY) {
- if (((ls.shader & SHADER_EXCLUDE_DIFFUSE) && (path_flag & PATH_RAY_DIFFUSE)) ||
- ((ls.shader & SHADER_EXCLUDE_GLOSSY) &&
- ((path_flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) ==
- (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) ||
- ((ls.shader & SHADER_EXCLUDE_TRANSMIT) && (path_flag & PATH_RAY_TRANSMIT)) ||
- ((ls.shader & SHADER_EXCLUDE_CAMERA) && (path_flag & PATH_RAY_CAMERA)) ||
- ((ls.shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER)))
- return;
- }
-#endif
-
- /* Evaluate light shader. */
- /* TODO: does aliasing like this break automatic SoA in CUDA? */
- ShaderDataTinyStorage emission_sd_storage;
- ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
- float3 light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, ray_time);
- if (is_zero(light_eval)) {
- return;
- }
-
- /* MIS weighting. */
- if (!(path_flag & PATH_RAY_MIS_SKIP)) {
- /* multiple importance sampling, get regular light pdf,
- * and compute weight with respect to BSDF pdf */
- const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
- const float mis_weight = power_heuristic(mis_ray_pdf, ls.pdf);
- light_eval *= mis_weight;
- }
-
- /* Write to render buffer. */
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- kernel_accum_emission(kg, state, throughput, light_eval, render_buffer);
- }
- }
-}
-
-ccl_device void integrator_shade_background(KernelGlobals kg,
- IntegratorState state,
- ccl_global float *ccl_restrict render_buffer)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_LIGHT_SETUP);
-
- /* TODO: unify these in a single loop to only have a single shader evaluation call. */
- integrate_distant_lights(kg, state, render_buffer);
- integrate_background(kg, state, render_buffer);
-
-#ifdef __SHADOW_CATCHER__
- if (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_SHADOW_CATCHER_BACKGROUND) {
- INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_SHADOW_CATCHER_BACKGROUND;
-
- const int isect_prim = INTEGRATOR_STATE(state, isect, prim);
- const int isect_type = INTEGRATOR_STATE(state, isect, type);
- const int shader = intersection_get_shader_from_isect_prim(kg, isect_prim, isect_type);
- const int shader_flags = kernel_tex_fetch(__shaders, shader).flags;
-
- if (shader_flags & SD_HAS_RAYTRACE) {
- INTEGRATOR_PATH_NEXT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND,
- DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE,
- shader);
- }
- else {
- INTEGRATOR_PATH_NEXT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND,
- DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE,
- shader);
- }
- return;
- }
-#endif
-
- INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_shade_light.h b/intern/cycles/kernel/integrator/integrator_shade_light.h
deleted file mode 100644
index 4f0f5a39756..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shade_light.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_accumulate.h"
-#include "kernel/kernel_emission.h"
-#include "kernel/kernel_light.h"
-#include "kernel/kernel_shader.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_inline void integrate_light(KernelGlobals kg,
- IntegratorState state,
- ccl_global float *ccl_restrict render_buffer)
-{
- /* Setup light sample. */
- Intersection isect ccl_optional_struct_init;
- integrator_state_read_isect(kg, state, &isect);
-
- float3 ray_P = INTEGRATOR_STATE(state, ray, P);
- const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
- const float ray_time = INTEGRATOR_STATE(state, ray, time);
-
- /* Advance ray beyond light. */
- /* TODO: can we make this more numerically robust to avoid reintersecting the
- * same light in some cases? */
- const float3 new_ray_P = ray_offset(ray_P + ray_D * isect.t, ray_D);
- INTEGRATOR_STATE_WRITE(state, ray, P) = new_ray_P;
- INTEGRATOR_STATE_WRITE(state, ray, t) -= isect.t;
-
- /* Set position to where the BSDF was sampled, for correct MIS PDF. */
- const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
- ray_P -= ray_D * mis_ray_t;
- isect.t += mis_ray_t;
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = mis_ray_t + isect.t;
-
- LightSample ls ccl_optional_struct_init;
- const bool use_light_sample = light_sample_from_intersection(kg, &isect, ray_P, ray_D, &ls);
-
- if (!use_light_sample) {
- return;
- }
-
- /* Use visibility flag to skip lights. */
-#ifdef __PASSES__
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- if (ls.shader & SHADER_EXCLUDE_ANY) {
- if (((ls.shader & SHADER_EXCLUDE_DIFFUSE) && (path_flag & PATH_RAY_DIFFUSE)) ||
- ((ls.shader & SHADER_EXCLUDE_GLOSSY) &&
- ((path_flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) ==
- (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) ||
- ((ls.shader & SHADER_EXCLUDE_TRANSMIT) && (path_flag & PATH_RAY_TRANSMIT)) ||
- ((ls.shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER)))
- return;
- }
-#endif
-
- /* Evaluate light shader. */
- /* TODO: does aliasing like this break automatic SoA in CUDA? */
- ShaderDataTinyStorage emission_sd_storage;
- ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
- float3 light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, ray_time);
- if (is_zero(light_eval)) {
- return;
- }
-
- /* MIS weighting. */
- if (!(path_flag & PATH_RAY_MIS_SKIP)) {
- /* multiple importance sampling, get regular light pdf,
- * and compute weight with respect to BSDF pdf */
- const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
- const float mis_weight = power_heuristic(mis_ray_pdf, ls.pdf);
- light_eval *= mis_weight;
- }
-
- /* Write to render buffer. */
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- kernel_accum_emission(kg, state, throughput, light_eval, render_buffer);
-}
-
-ccl_device void integrator_shade_light(KernelGlobals kg,
- IntegratorState state,
- ccl_global float *ccl_restrict render_buffer)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_LIGHT_SETUP);
-
- integrate_light(kg, state, render_buffer);
-
- /* TODO: we could get stuck in an infinite loop if there are precision issues
- * and the same light is hit again.
- *
- * As a workaround count this as a transparent bounce. It makes some sense
- * to interpret lights as transparent surfaces (and support making them opaque),
- * but this needs to be revisited. */
- uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce) + 1;
- INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = transparent_bounce;
-
- if (transparent_bounce >= kernel_data.integrator.transparent_max_bounce) {
- INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
- return;
- }
- else {
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT,
- DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
- return;
- }
-
- /* TODO: in some cases we could continue directly to SHADE_BACKGROUND, but
- * probably that optimization is probably not practical if we add lights to
- * scene geometry. */
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_shade_shadow.h b/intern/cycles/kernel/integrator/integrator_shade_shadow.h
deleted file mode 100644
index a82254e1dea..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shade_shadow.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/integrator/integrator_shade_volume.h"
-#include "kernel/integrator/integrator_volume_stack.h"
-
-#include "kernel/kernel_shader.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_inline bool shadow_intersections_has_remaining(const uint num_hits)
-{
- return num_hits >= INTEGRATOR_SHADOW_ISECT_SIZE;
-}
-
-#ifdef __TRANSPARENT_SHADOWS__
-ccl_device_inline float3 integrate_transparent_surface_shadow(KernelGlobals kg,
- IntegratorShadowState state,
- const int hit)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_SHADOW_SURFACE);
-
- /* TODO: does aliasing like this break automatic SoA in CUDA?
- * Should we instead store closures separate from ShaderData?
- *
- * TODO: is it better to declare this outside the loop or keep it local
- * so the compiler can see there is no dependency between iterations? */
- ShaderDataTinyStorage shadow_sd_storage;
- ccl_private ShaderData *shadow_sd = AS_SHADER_DATA(&shadow_sd_storage);
-
- /* Setup shader data at surface. */
- Intersection isect ccl_optional_struct_init;
- integrator_state_read_shadow_isect(state, &isect, hit);
-
- Ray ray ccl_optional_struct_init;
- integrator_state_read_shadow_ray(kg, state, &ray);
-
- shader_setup_from_ray(kg, shadow_sd, &ray, &isect);
-
- /* Evaluate shader. */
- if (!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
- shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW>(
- kg, state, shadow_sd, NULL, PATH_RAY_SHADOW);
- }
-
-# ifdef __VOLUME__
- /* Exit/enter volume. */
- shadow_volume_stack_enter_exit(kg, state, shadow_sd);
-# endif
-
- /* Compute transparency from closures. */
- return shader_bsdf_transparency(kg, shadow_sd);
-}
-
-# ifdef __VOLUME__
-ccl_device_inline void integrate_transparent_volume_shadow(KernelGlobals kg,
- IntegratorShadowState state,
- const int hit,
- const int num_recorded_hits,
- ccl_private float3 *ccl_restrict
- throughput)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_SHADOW_VOLUME);
-
- /* TODO: deduplicate with surface, or does it not matter for memory usage? */
- ShaderDataTinyStorage shadow_sd_storage;
- ccl_private ShaderData *shadow_sd = AS_SHADER_DATA(&shadow_sd_storage);
-
- /* Setup shader data. */
- Ray ray ccl_optional_struct_init;
- integrator_state_read_shadow_ray(kg, state, &ray);
-
- /* Modify ray position and length to match current segment. */
- const float start_t = (hit == 0) ? 0.0f :
- INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit - 1, t);
- const float end_t = (hit < num_recorded_hits) ?
- INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit, t) :
- ray.t;
- ray.P += start_t * ray.D;
- ray.t = end_t - start_t;
-
- shader_setup_from_volume(kg, shadow_sd, &ray);
-
- const float step_size = volume_stack_step_size(
- kg, [=](const int i) { return integrator_state_read_shadow_volume_stack(state, i); });
-
- volume_shadow_heterogeneous(kg, state, &ray, shadow_sd, throughput, step_size);
-}
-# endif
-
-ccl_device_inline bool integrate_transparent_shadow(KernelGlobals kg,
- IntegratorShadowState state,
- const uint num_hits)
-{
- /* Accumulate shadow for transparent surfaces. */
- const uint num_recorded_hits = min(num_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
-
- for (uint hit = 0; hit < num_recorded_hits + 1; hit++) {
- /* Volume shaders. */
- if (hit < num_recorded_hits || !shadow_intersections_has_remaining(num_hits)) {
-# ifdef __VOLUME__
- if (!integrator_state_shadow_volume_stack_is_empty(kg, state)) {
- float3 throughput = INTEGRATOR_STATE(state, shadow_path, throughput);
- integrate_transparent_volume_shadow(kg, state, hit, num_recorded_hits, &throughput);
- if (is_zero(throughput)) {
- return true;
- }
-
- INTEGRATOR_STATE_WRITE(state, shadow_path, throughput) = throughput;
- }
-# endif
- }
-
- /* Surface shaders. */
- if (hit < num_recorded_hits) {
- const float3 shadow = integrate_transparent_surface_shadow(kg, state, hit);
- const float3 throughput = INTEGRATOR_STATE(state, shadow_path, throughput) * shadow;
- if (is_zero(throughput)) {
- return true;
- }
-
- INTEGRATOR_STATE_WRITE(state, shadow_path, throughput) = throughput;
- INTEGRATOR_STATE_WRITE(state, shadow_path, transparent_bounce) += 1;
- INTEGRATOR_STATE_WRITE(state, shadow_path, rng_offset) += PRNG_BOUNCE_NUM;
- }
-
- /* Note we do not need to check max_transparent_bounce here, the number
- * of intersections is already limited and made opaque in the
- * INTERSECT_SHADOW kernel. */
- }
-
- if (shadow_intersections_has_remaining(num_hits)) {
- /* There are more hits that we could not recorded due to memory usage,
- * adjust ray to intersect again from the last hit. */
- const float last_hit_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, num_recorded_hits - 1, t);
- const float3 ray_P = INTEGRATOR_STATE(state, shadow_ray, P);
- const float3 ray_D = INTEGRATOR_STATE(state, shadow_ray, D);
- INTEGRATOR_STATE_WRITE(state, shadow_ray, P) = ray_offset(ray_P + last_hit_t * ray_D, ray_D);
- INTEGRATOR_STATE_WRITE(state, shadow_ray, t) -= last_hit_t;
- }
-
- return false;
-}
-#endif /* __TRANSPARENT_SHADOWS__ */
-
-ccl_device void integrator_shade_shadow(KernelGlobals kg,
- IntegratorShadowState state,
- ccl_global float *ccl_restrict render_buffer)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_SHADOW_SETUP);
- const uint num_hits = INTEGRATOR_STATE(state, shadow_path, num_hits);
-
-#ifdef __TRANSPARENT_SHADOWS__
- /* Evaluate transparent shadows. */
- const bool opaque = integrate_transparent_shadow(kg, state, num_hits);
- if (opaque) {
- INTEGRATOR_SHADOW_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
- return;
- }
-#endif
-
- if (shadow_intersections_has_remaining(num_hits)) {
- /* More intersections to find, continue shadow ray. */
- INTEGRATOR_SHADOW_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW,
- DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
- return;
- }
- else {
- kernel_accum_light(kg, state, render_buffer);
- INTEGRATOR_SHADOW_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
- return;
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_shade_surface.h b/intern/cycles/kernel/integrator/integrator_shade_surface.h
deleted file mode 100644
index 3724b05c6b0..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shade_surface.h
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_accumulate.h"
-#include "kernel/kernel_emission.h"
-#include "kernel/kernel_light.h"
-#include "kernel/kernel_passes.h"
-#include "kernel/kernel_path_state.h"
-#include "kernel/kernel_shader.h"
-
-#include "kernel/integrator/integrator_subsurface.h"
-#include "kernel/integrator/integrator_volume_stack.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_forceinline void integrate_surface_shader_setup(KernelGlobals kg,
- ConstIntegratorState state,
- ccl_private ShaderData *sd)
-{
- Intersection isect ccl_optional_struct_init;
- integrator_state_read_isect(kg, state, &isect);
-
- Ray ray ccl_optional_struct_init;
- integrator_state_read_ray(kg, state, &ray);
-
- shader_setup_from_ray(kg, sd, &ray, &isect);
-}
-
-#ifdef __HOLDOUT__
-ccl_device_forceinline bool integrate_surface_holdout(KernelGlobals kg,
- ConstIntegratorState state,
- ccl_private ShaderData *sd,
- ccl_global float *ccl_restrict render_buffer)
-{
- /* Write holdout transparency to render buffer and stop if fully holdout. */
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- if (((sd->flag & SD_HOLDOUT) || (sd->object_flag & SD_OBJECT_HOLDOUT_MASK)) &&
- (path_flag & PATH_RAY_TRANSPARENT_BACKGROUND)) {
- const float3 holdout_weight = shader_holdout_apply(kg, sd);
- if (kernel_data.background.transparent) {
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- const float transparent = average(holdout_weight * throughput);
- kernel_accum_holdout(kg, state, path_flag, transparent, render_buffer);
- }
- if (isequal_float3(holdout_weight, one_float3())) {
- return false;
- }
- }
-
- return true;
-}
-#endif /* __HOLDOUT__ */
-
-#ifdef __EMISSION__
-ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
- ConstIntegratorState state,
- ccl_private const ShaderData *sd,
- ccl_global float *ccl_restrict
- render_buffer)
-{
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- /* Evaluate emissive closure. */
- float3 L = shader_emissive_eval(sd);
-
-# ifdef __HAIR__
- if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS) &&
- (sd->type & PRIMITIVE_ALL_TRIANGLE))
-# else
- if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS))
-# endif
- {
- const float bsdf_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
- const float t = sd->ray_length + INTEGRATOR_STATE(state, path, mis_ray_t);
-
- /* Multiple importance sampling, get triangle light pdf,
- * and compute weight with respect to BSDF pdf. */
- float pdf = triangle_light_pdf(kg, sd, t);
- float mis_weight = power_heuristic(bsdf_pdf, pdf);
-
- L *= mis_weight;
- }
-
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- kernel_accum_emission(kg, state, throughput, L, render_buffer);
-}
-#endif /* __EMISSION__ */
-
-#ifdef __EMISSION__
-/* Path tracing: sample point on light and evaluate light shader, then
- * queue shadow ray to be traced. */
-ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
- IntegratorState state,
- ccl_private ShaderData *sd,
- ccl_private const RNGState *rng_state)
-{
- /* Test if there is a light or BSDF that needs direct light. */
- if (!(kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL))) {
- return;
- }
-
- /* Sample position on a light. */
- LightSample ls ccl_optional_struct_init;
- {
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
- const uint bounce = INTEGRATOR_STATE(state, path, bounce);
- float light_u, light_v;
- path_state_rng_2D(kg, rng_state, PRNG_LIGHT_U, &light_u, &light_v);
-
- if (!light_distribution_sample_from_position(
- kg, light_u, light_v, sd->time, sd->P, bounce, path_flag, &ls)) {
- return;
- }
- }
-
- kernel_assert(ls.pdf != 0.0f);
-
- /* Evaluate light shader.
- *
- * TODO: can we reuse sd memory? In theory we can move this after
- * integrate_surface_bounce, evaluate the BSDF, and only then evaluate
- * the light shader. This could also move to its own kernel, for
- * non-constant light sources. */
- ShaderDataTinyStorage emission_sd_storage;
- ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
- const float3 light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, sd->time);
- if (is_zero(light_eval)) {
- return;
- }
-
- /* Evaluate BSDF. */
- const bool is_transmission = shader_bsdf_is_transmission(sd, ls.D);
-
- BsdfEval bsdf_eval ccl_optional_struct_init;
- const float bsdf_pdf = shader_bsdf_eval(kg, sd, ls.D, is_transmission, &bsdf_eval, ls.shader);
- bsdf_eval_mul3(&bsdf_eval, light_eval / ls.pdf);
-
- if (ls.shader & SHADER_USE_MIS) {
- const float mis_weight = power_heuristic(ls.pdf, bsdf_pdf);
- bsdf_eval_mul(&bsdf_eval, mis_weight);
- }
-
- /* Path termination. */
- const float terminate = path_state_rng_light_termination(kg, rng_state);
- if (light_sample_terminate(kg, &ls, &bsdf_eval, terminate)) {
- return;
- }
-
- /* Create shadow ray. */
- Ray ray ccl_optional_struct_init;
- light_sample_to_surface_shadow_ray(kg, sd, &ls, &ray);
- const bool is_light = light_sample_is_light(&ls);
-
- /* Branch off shadow kernel. */
- INTEGRATOR_SHADOW_PATH_INIT(
- shadow_state, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, shadow);
-
- /* Copy volume stack and enter/exit volume. */
- integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state);
-
- if (is_transmission) {
-# ifdef __VOLUME__
- shadow_volume_stack_enter_exit(kg, shadow_state, sd);
-# endif
- }
-
- /* Write shadow ray and associated state to global memory. */
- integrator_state_write_shadow_ray(kg, shadow_state, &ray);
-
- /* Copy state from main path to shadow path. */
- const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce);
- const uint16_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce);
- uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag);
- shadow_flag |= (is_light) ? PATH_RAY_SHADOW_FOR_LIGHT : 0;
- shadow_flag |= (is_transmission) ? PATH_RAY_TRANSMISSION_PASS : PATH_RAY_REFLECT_PASS;
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput) * bsdf_eval_sum(&bsdf_eval);
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
- const float3 diffuse_glossy_ratio = (bounce == 0) ?
- bsdf_eval_diffuse_glossy_ratio(&bsdf_eval) :
- INTEGRATOR_STATE(state, path, diffuse_glossy_ratio);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, diffuse_glossy_ratio) = diffuse_glossy_ratio;
- }
-
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, render_pixel_index) = INTEGRATOR_STATE(
- state, path, render_pixel_index);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_offset) = INTEGRATOR_STATE(
- state, path, rng_offset);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_hash) = INTEGRATOR_STATE(
- state, path, rng_hash);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, sample) = INTEGRATOR_STATE(
- state, path, sample);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, flag) = shadow_flag;
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, bounce) = bounce;
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transparent_bounce) = transparent_bounce;
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, diffuse_bounce) = INTEGRATOR_STATE(
- state, path, diffuse_bounce);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, glossy_bounce) = INTEGRATOR_STATE(
- state, path, glossy_bounce);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transmission_bounce) = INTEGRATOR_STATE(
- state, path, transmission_bounce);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput;
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_PASS) {
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unshadowed_throughput) = throughput;
- }
-}
-#endif
-
-/* Path tracing: bounce off or through surface with new direction. */
-ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
- KernelGlobals kg,
- IntegratorState state,
- ccl_private ShaderData *sd,
- ccl_private const RNGState *rng_state)
-{
- /* Sample BSDF or BSSRDF. */
- if (!(sd->flag & (SD_BSDF | SD_BSSRDF))) {
- return LABEL_NONE;
- }
-
- float bsdf_u, bsdf_v;
- path_state_rng_2D(kg, rng_state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
- ccl_private const ShaderClosure *sc = shader_bsdf_bssrdf_pick(sd, &bsdf_u);
-
-#ifdef __SUBSURFACE__
- /* BSSRDF closure, we schedule subsurface intersection kernel. */
- if (CLOSURE_IS_BSSRDF(sc->type)) {
- return subsurface_bounce(kg, state, sd, sc);
- }
-#endif
-
- /* BSDF closure, sample direction. */
- float bsdf_pdf;
- BsdfEval bsdf_eval ccl_optional_struct_init;
- float3 bsdf_omega_in ccl_optional_struct_init;
- differential3 bsdf_domega_in ccl_optional_struct_init;
- int label;
-
- label = shader_bsdf_sample_closure(
- kg, sd, sc, bsdf_u, bsdf_v, &bsdf_eval, &bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
-
- if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
- return LABEL_NONE;
- }
-
- /* Setup ray. Note that clipping works through transparent bounces. */
- INTEGRATOR_STATE_WRITE(state, ray, P) = ray_offset(sd->P,
- (label & LABEL_TRANSMIT) ? -sd->Ng : sd->Ng);
- INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(bsdf_omega_in);
- INTEGRATOR_STATE_WRITE(state, ray, t) = (label & LABEL_TRANSPARENT) ?
- INTEGRATOR_STATE(state, ray, t) - sd->ray_length :
- FLT_MAX;
-
-#ifdef __RAY_DIFFERENTIALS__
- INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
- INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_make_compact(bsdf_domega_in);
-#endif
-
- /* Update throughput. */
- float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- throughput *= bsdf_eval_sum(&bsdf_eval) / bsdf_pdf;
- INTEGRATOR_STATE_WRITE(state, path, throughput) = throughput;
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
- if (INTEGRATOR_STATE(state, path, bounce) == 0) {
- INTEGRATOR_STATE_WRITE(state, path, diffuse_glossy_ratio) = bsdf_eval_diffuse_glossy_ratio(
- &bsdf_eval);
- }
- }
-
- /* Update path state */
- if (label & LABEL_TRANSPARENT) {
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) += sd->ray_length;
- }
- else {
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = bsdf_pdf;
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f;
- INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
- bsdf_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
- }
-
- path_state_next(kg, state, label);
- return label;
-}
-
-#ifdef __VOLUME__
-ccl_device_forceinline bool integrate_surface_volume_only_bounce(IntegratorState state,
- ccl_private ShaderData *sd)
-{
- if (!path_state_volume_next(state)) {
- return LABEL_NONE;
- }
-
- /* Setup ray position, direction stays unchanged. */
- INTEGRATOR_STATE_WRITE(state, ray, P) = ray_offset(sd->P, -sd->Ng);
-
- /* Clipping works through transparent. */
- INTEGRATOR_STATE_WRITE(state, ray, t) -= sd->ray_length;
-
-# ifdef __RAY_DIFFERENTIALS__
- INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
-# endif
-
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) += sd->ray_length;
-
- return LABEL_TRANSMIT | LABEL_TRANSPARENT;
-}
-#endif
-
-#if defined(__AO__)
-ccl_device_forceinline void integrate_surface_ao_pass(
- KernelGlobals kg,
- IntegratorState state,
- ccl_private const ShaderData *ccl_restrict sd,
- ccl_private const RNGState *ccl_restrict rng_state,
- ccl_global float *ccl_restrict render_buffer)
-{
- float bsdf_u, bsdf_v;
- path_state_rng_2D(kg, rng_state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
-
- const float3 ao_N = shader_bsdf_ao_normal(kg, sd);
- float3 ao_D;
- float ao_pdf;
- sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
-
- if (!(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f)) {
- return;
- }
-
- Ray ray ccl_optional_struct_init;
- ray.P = ray_offset(sd->P, sd->Ng);
- ray.D = ao_D;
- ray.t = kernel_data.integrator.ao_bounces_distance;
- ray.time = sd->time;
- ray.dP = differential_zero_compact();
- ray.dD = differential_zero_compact();
-
- /* Branch off shadow kernel. */
- INTEGRATOR_SHADOW_PATH_INIT(shadow_state, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, ao);
-
- /* Copy volume stack and enter/exit volume. */
- integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state);
-
- /* Write shadow ray and associated state to global memory. */
- integrator_state_write_shadow_ray(kg, shadow_state, &ray);
-
- /* Copy state from main path to shadow path. */
- const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce);
- const uint16_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce);
- uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag) | PATH_RAY_SHADOW_FOR_AO;
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput) * shader_bsdf_alpha(kg, sd);
-
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, render_pixel_index) = INTEGRATOR_STATE(
- state, path, render_pixel_index);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_offset) = INTEGRATOR_STATE(
- state, path, rng_offset);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_hash) = INTEGRATOR_STATE(
- state, path, rng_hash);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, sample) = INTEGRATOR_STATE(
- state, path, sample);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, flag) = shadow_flag;
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, bounce) = bounce;
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transparent_bounce) = transparent_bounce;
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput;
-}
-#endif /* defined(__AO__) */
-
-template<uint node_feature_mask>
-ccl_device bool integrate_surface(KernelGlobals kg,
- IntegratorState state,
- ccl_global float *ccl_restrict render_buffer)
-
-{
- PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_SURFACE_SETUP);
-
- /* Setup shader data. */
- ShaderData sd;
- integrate_surface_shader_setup(kg, state, &sd);
- PROFILING_SHADER(sd.object, sd.shader);
-
- int continue_path_label = 0;
-
- /* Skip most work for volume bounding surface. */
-#ifdef __VOLUME__
- if (!(sd.flag & SD_HAS_ONLY_VOLUME)) {
-#endif
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
-#ifdef __SUBSURFACE__
- /* Can skip shader evaluation for BSSRDF exit point without bump mapping. */
- if (!(path_flag & PATH_RAY_SUBSURFACE) || ((sd.flag & SD_HAS_BSSRDF_BUMP)))
-#endif
- {
- /* Evaluate shader. */
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_EVAL);
- shader_eval_surface<node_feature_mask>(kg, state, &sd, render_buffer, path_flag);
-
- /* Initialize additional RNG for BSDFs. */
- if (sd.flag & SD_BSDF_NEEDS_LCG) {
- sd.lcg_state = lcg_state_init(INTEGRATOR_STATE(state, path, rng_hash),
- INTEGRATOR_STATE(state, path, rng_offset),
- INTEGRATOR_STATE(state, path, sample),
- 0xb4bc3953);
- }
- }
-
-#ifdef __SUBSURFACE__
- if (path_flag & PATH_RAY_SUBSURFACE) {
- /* When coming from inside subsurface scattering, setup a diffuse
- * closure to perform lighting at the exit point. */
- subsurface_shader_data_setup(kg, state, &sd, path_flag);
- INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_SUBSURFACE;
- }
-#endif
-
- shader_prepare_surface_closures(kg, state, &sd);
-
-#ifdef __HOLDOUT__
- /* Evaluate holdout. */
- if (!integrate_surface_holdout(kg, state, &sd, render_buffer)) {
- return false;
- }
-#endif
-
-#ifdef __EMISSION__
- /* Write emission. */
- if (sd.flag & SD_EMISSION) {
- integrate_surface_emission(kg, state, &sd, render_buffer);
- }
-#endif
-
-#ifdef __PASSES__
- /* Write render passes. */
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_PASSES);
- kernel_write_data_passes(kg, state, &sd, render_buffer);
-#endif
-
- /* Load random number state. */
- RNGState rng_state;
- path_state_rng_load(state, &rng_state);
-
- /* Perform path termination. Most paths have already been terminated in
- * the intersect_closest kernel, this is just for emission and for dividing
- * throughput by the probability at the right moment.
- *
- * Also ensure we don't do it twice for SSS at both the entry and exit point. */
- if (!(path_flag & PATH_RAY_SUBSURFACE)) {
- const float probability = (path_flag & PATH_RAY_TERMINATE_ON_NEXT_SURFACE) ?
- 0.0f :
- path_state_continuation_probability(kg, state, path_flag);
- if (probability == 0.0f) {
- return false;
- }
- else if (probability != 1.0f) {
- INTEGRATOR_STATE_WRITE(state, path, throughput) /= probability;
- }
- }
-
-#ifdef __DENOISING_FEATURES__
- kernel_write_denoising_features_surface(kg, state, &sd, render_buffer);
-#endif
-
-#ifdef __SHADOW_CATCHER__
- kernel_write_shadow_catcher_bounce_data(kg, state, &sd, render_buffer);
-#endif
-
- /* Direct light. */
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_DIRECT_LIGHT);
- integrate_surface_direct_light(kg, state, &sd, &rng_state);
-
-#if defined(__AO__)
- /* Ambient occlusion pass. */
- if ((kernel_data.film.pass_ao != PASS_UNUSED) &&
- (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_CAMERA)) {
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_AO);
- integrate_surface_ao_pass(kg, state, &sd, &rng_state, render_buffer);
- }
-#endif
-
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_INDIRECT_LIGHT);
- continue_path_label = integrate_surface_bsdf_bssrdf_bounce(kg, state, &sd, &rng_state);
-#ifdef __VOLUME__
- }
- else {
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_INDIRECT_LIGHT);
- continue_path_label = integrate_surface_volume_only_bounce(state, &sd);
- }
-
- if (continue_path_label & LABEL_TRANSMIT) {
- /* Enter/Exit volume. */
- volume_stack_enter_exit(kg, state, &sd);
- }
-#endif
-
- return continue_path_label != 0;
-}
-
-template<uint node_feature_mask = KERNEL_FEATURE_NODE_MASK_SURFACE & ~KERNEL_FEATURE_NODE_RAYTRACE,
- int current_kernel = DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE>
-ccl_device_forceinline void integrator_shade_surface(KernelGlobals kg,
- IntegratorState state,
- ccl_global float *ccl_restrict render_buffer)
-{
- if (integrate_surface<node_feature_mask>(kg, state, render_buffer)) {
- if (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_SUBSURFACE) {
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE);
- }
- else {
- kernel_assert(INTEGRATOR_STATE(state, ray, t) != 0.0f);
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
- }
- }
- else {
- INTEGRATOR_PATH_TERMINATE(current_kernel);
- }
-}
-
-ccl_device_forceinline void integrator_shade_surface_raytrace(
- KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
-{
- integrator_shade_surface<KERNEL_FEATURE_NODE_MASK_SURFACE,
- DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE>(
- kg, state, render_buffer);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_shade_volume.h b/intern/cycles/kernel/integrator/integrator_shade_volume.h
deleted file mode 100644
index d0aabb550c0..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shade_volume.h
+++ /dev/null
@@ -1,1046 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_accumulate.h"
-#include "kernel/kernel_emission.h"
-#include "kernel/kernel_light.h"
-#include "kernel/kernel_passes.h"
-#include "kernel/kernel_path_state.h"
-#include "kernel/kernel_shader.h"
-
-#include "kernel/integrator/integrator_intersect_closest.h"
-#include "kernel/integrator/integrator_volume_stack.h"
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef __VOLUME__
-
-/* Events for probabilistic scattering. */
-
-typedef enum VolumeIntegrateEvent {
- VOLUME_PATH_SCATTERED = 0,
- VOLUME_PATH_ATTENUATED = 1,
- VOLUME_PATH_MISSED = 2
-} VolumeIntegrateEvent;
-
-typedef struct VolumeIntegrateResult {
- /* Throughput and offset for direct light scattering. */
- bool direct_scatter;
- float3 direct_throughput;
- float direct_t;
- ShaderVolumePhases direct_phases;
-
- /* Throughput and offset for indirect light scattering. */
- bool indirect_scatter;
- float3 indirect_throughput;
- float indirect_t;
- ShaderVolumePhases indirect_phases;
-} VolumeIntegrateResult;
-
-/* Ignore paths that have volume throughput below this value, to avoid unnecessary work
- * and precision issues.
- * todo: this value could be tweaked or turned into a probability to avoid unnecessary
- * work in volumes and subsurface scattering. */
-# define VOLUME_THROUGHPUT_EPSILON 1e-6f
-
-/* Volume shader properties
- *
- * extinction coefficient = absorption coefficient + scattering coefficient
- * sigma_t = sigma_a + sigma_s */
-
-typedef struct VolumeShaderCoefficients {
- float3 sigma_t;
- float3 sigma_s;
- float3 emission;
-} VolumeShaderCoefficients;
-
-/* Evaluate shader to get extinction coefficient at P. */
-ccl_device_inline bool shadow_volume_shader_sample(KernelGlobals kg,
- IntegratorShadowState state,
- ccl_private ShaderData *ccl_restrict sd,
- ccl_private float3 *ccl_restrict extinction)
-{
- shader_eval_volume<true>(kg, state, sd, PATH_RAY_SHADOW, [=](const int i) {
- return integrator_state_read_shadow_volume_stack(state, i);
- });
-
- if (!(sd->flag & SD_EXTINCTION)) {
- return false;
- }
-
- const float density = object_volume_density(kg, sd->object);
- *extinction = sd->closure_transparent_extinction * density;
- return true;
-}
-
-/* Evaluate shader to get absorption, scattering and emission at P. */
-ccl_device_inline bool volume_shader_sample(KernelGlobals kg,
- IntegratorState state,
- ccl_private ShaderData *ccl_restrict sd,
- ccl_private VolumeShaderCoefficients *coeff)
-{
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
- shader_eval_volume<false>(kg, state, sd, path_flag, [=](const int i) {
- return integrator_state_read_volume_stack(state, i);
- });
-
- if (!(sd->flag & (SD_EXTINCTION | SD_SCATTER | SD_EMISSION))) {
- return false;
- }
-
- coeff->sigma_s = zero_float3();
- coeff->sigma_t = (sd->flag & SD_EXTINCTION) ? sd->closure_transparent_extinction : zero_float3();
- coeff->emission = (sd->flag & SD_EMISSION) ? sd->closure_emission_background : zero_float3();
-
- if (sd->flag & SD_SCATTER) {
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_VOLUME(sc->type)) {
- coeff->sigma_s += sc->weight;
- }
- }
- }
-
- const float density = object_volume_density(kg, sd->object);
- coeff->sigma_s *= density;
- coeff->sigma_t *= density;
- coeff->emission *= density;
-
- return true;
-}
-
-ccl_device_forceinline void volume_step_init(KernelGlobals kg,
- ccl_private const RNGState *rng_state,
- const float object_step_size,
- float t,
- ccl_private float *step_size,
- ccl_private float *step_shade_offset,
- ccl_private float *steps_offset,
- ccl_private int *max_steps)
-{
- if (object_step_size == FLT_MAX) {
- /* Homogeneous volume. */
- *step_size = t;
- *step_shade_offset = 0.0f;
- *steps_offset = 1.0f;
- *max_steps = 1;
- }
- else {
- /* Heterogeneous volume. */
- *max_steps = kernel_data.integrator.volume_max_steps;
- float step = min(object_step_size, t);
-
- /* compute exact steps in advance for malloc */
- if (t > *max_steps * step) {
- step = t / (float)*max_steps;
- }
-
- *step_size = step;
-
- /* Perform shading at this offset within a step, to integrate over
- * over the entire step segment. */
- *step_shade_offset = path_state_rng_1D_hash(kg, rng_state, 0x1e31d8a4);
-
- /* Shift starting point of all segment by this random amount to avoid
- * banding artifacts from the volume bounding shape. */
- *steps_offset = path_state_rng_1D_hash(kg, rng_state, 0x3d22c7b3);
- }
-}
-
-/* Volume Shadows
- *
- * These functions are used to attenuate shadow rays to lights. Both absorption
- * and scattering will block light, represented by the extinction coefficient. */
-
-# if 0
-/* homogeneous volume: assume shader evaluation at the starts gives
- * the extinction coefficient for the entire line segment */
-ccl_device void volume_shadow_homogeneous(KernelGlobals kg, IntegratorState state,
- ccl_private Ray *ccl_restrict ray,
- ccl_private ShaderData *ccl_restrict sd,
- ccl_global float3 *ccl_restrict throughput)
-{
- float3 sigma_t = zero_float3();
-
- if (shadow_volume_shader_sample(kg, state, sd, &sigma_t)) {
- *throughput *= volume_color_transmittance(sigma_t, ray->t);
- }
-}
-# endif
-
-/* heterogeneous volume: integrate stepping through the volume until we
- * reach the end, get absorbed entirely, or run out of iterations */
-ccl_device void volume_shadow_heterogeneous(KernelGlobals kg,
- IntegratorShadowState state,
- ccl_private Ray *ccl_restrict ray,
- ccl_private ShaderData *ccl_restrict sd,
- ccl_private float3 *ccl_restrict throughput,
- const float object_step_size)
-{
- /* Load random number state. */
- RNGState rng_state;
- shadow_path_state_rng_load(state, &rng_state);
-
- float3 tp = *throughput;
-
- /* Prepare for stepping.
- * For shadows we do not offset all segments, since the starting point is
- * already a random distance inside the volume. It also appears to create
- * banding artifacts for unknown reasons. */
- int max_steps;
- float step_size, step_shade_offset, unused;
- volume_step_init(kg,
- &rng_state,
- object_step_size,
- ray->t,
- &step_size,
- &step_shade_offset,
- &unused,
- &max_steps);
- const float steps_offset = 1.0f;
-
- /* compute extinction at the start */
- float t = 0.0f;
-
- float3 sum = zero_float3();
-
- for (int i = 0; i < max_steps; i++) {
- /* advance to new position */
- float new_t = min(ray->t, (i + steps_offset) * step_size);
- float dt = new_t - t;
-
- float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
- float3 sigma_t = zero_float3();
-
- /* compute attenuation over segment */
- sd->P = new_P;
- if (shadow_volume_shader_sample(kg, state, sd, &sigma_t)) {
- /* Compute `expf()` only for every Nth step, to save some calculations
- * because `exp(a)*exp(b) = exp(a+b)`, also do a quick #VOLUME_THROUGHPUT_EPSILON
- * check then. */
- sum += (-sigma_t * dt);
- if ((i & 0x07) == 0) { /* TODO: Other interval? */
- tp = *throughput * exp3(sum);
-
- /* stop if nearly all light is blocked */
- if (tp.x < VOLUME_THROUGHPUT_EPSILON && tp.y < VOLUME_THROUGHPUT_EPSILON &&
- tp.z < VOLUME_THROUGHPUT_EPSILON)
- break;
- }
- }
-
- /* stop if at the end of the volume */
- t = new_t;
- if (t == ray->t) {
- /* Update throughput in case we haven't done it above */
- tp = *throughput * exp3(sum);
- break;
- }
- }
-
- *throughput = tp;
-}
-
-/* Equi-angular sampling as in:
- * "Importance Sampling Techniques for Path Tracing in Participating Media" */
-
-ccl_device float volume_equiangular_sample(ccl_private const Ray *ccl_restrict ray,
- const float3 light_P,
- const float xi,
- ccl_private float *pdf)
-{
- const float t = ray->t;
- const float delta = dot((light_P - ray->P), ray->D);
- const float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
- if (UNLIKELY(D == 0.0f)) {
- *pdf = 0.0f;
- return 0.0f;
- }
- const float theta_a = -atan2f(delta, D);
- const float theta_b = atan2f(t - delta, D);
- const float t_ = D * tanf((xi * theta_b) + (1 - xi) * theta_a);
- if (UNLIKELY(theta_b == theta_a)) {
- *pdf = 0.0f;
- return 0.0f;
- }
- *pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
-
- return min(t, delta + t_); /* min is only for float precision errors */
-}
-
-ccl_device float volume_equiangular_pdf(ccl_private const Ray *ccl_restrict ray,
- const float3 light_P,
- const float sample_t)
-{
- const float delta = dot((light_P - ray->P), ray->D);
- const float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
- if (UNLIKELY(D == 0.0f)) {
- return 0.0f;
- }
-
- const float t = ray->t;
- const float t_ = sample_t - delta;
-
- const float theta_a = -atan2f(delta, D);
- const float theta_b = atan2f(t - delta, D);
- if (UNLIKELY(theta_b == theta_a)) {
- return 0.0f;
- }
-
- const float pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
-
- return pdf;
-}
-
-ccl_device float volume_equiangular_cdf(ccl_private const Ray *ccl_restrict ray,
- const float3 light_P,
- const float sample_t)
-{
- float delta = dot((light_P - ray->P), ray->D);
- float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
- if (UNLIKELY(D == 0.0f)) {
- return 0.0f;
- }
-
- const float t = ray->t;
- const float t_ = sample_t - delta;
-
- const float theta_a = -atan2f(delta, D);
- const float theta_b = atan2f(t - delta, D);
- if (UNLIKELY(theta_b == theta_a)) {
- return 0.0f;
- }
-
- const float theta_sample = atan2f(t_, D);
- const float cdf = (theta_sample - theta_a) / (theta_b - theta_a);
-
- return cdf;
-}
-
-/* Distance sampling */
-
-ccl_device float volume_distance_sample(float max_t,
- float3 sigma_t,
- int channel,
- float xi,
- ccl_private float3 *transmittance,
- ccl_private float3 *pdf)
-{
- /* xi is [0, 1[ so log(0) should never happen, division by zero is
- * avoided because sample_sigma_t > 0 when SD_SCATTER is set */
- float sample_sigma_t = volume_channel_get(sigma_t, channel);
- float3 full_transmittance = volume_color_transmittance(sigma_t, max_t);
- float sample_transmittance = volume_channel_get(full_transmittance, channel);
-
- float sample_t = min(max_t, -logf(1.0f - xi * (1.0f - sample_transmittance)) / sample_sigma_t);
-
- *transmittance = volume_color_transmittance(sigma_t, sample_t);
- *pdf = safe_divide_color(sigma_t * *transmittance, one_float3() - full_transmittance);
-
- /* todo: optimization: when taken together with hit/miss decision,
- * the full_transmittance cancels out drops out and xi does not
- * need to be remapped */
-
- return sample_t;
-}
-
-ccl_device float3 volume_distance_pdf(float max_t, float3 sigma_t, float sample_t)
-{
- float3 full_transmittance = volume_color_transmittance(sigma_t, max_t);
- float3 transmittance = volume_color_transmittance(sigma_t, sample_t);
-
- return safe_divide_color(sigma_t * transmittance, one_float3() - full_transmittance);
-}
-
-/* Emission */
-
-ccl_device float3 volume_emission_integrate(ccl_private VolumeShaderCoefficients *coeff,
- int closure_flag,
- float3 transmittance,
- float t)
-{
- /* integral E * exp(-sigma_t * t) from 0 to t = E * (1 - exp(-sigma_t * t))/sigma_t
- * this goes to E * t as sigma_t goes to zero
- *
- * todo: we should use an epsilon to avoid precision issues near zero sigma_t */
- float3 emission = coeff->emission;
-
- if (closure_flag & SD_EXTINCTION) {
- float3 sigma_t = coeff->sigma_t;
-
- emission.x *= (sigma_t.x > 0.0f) ? (1.0f - transmittance.x) / sigma_t.x : t;
- emission.y *= (sigma_t.y > 0.0f) ? (1.0f - transmittance.y) / sigma_t.y : t;
- emission.z *= (sigma_t.z > 0.0f) ? (1.0f - transmittance.z) / sigma_t.z : t;
- }
- else
- emission *= t;
-
- return emission;
-}
-
-/* Volume Integration */
-
-typedef struct VolumeIntegrateState {
- /* Volume segment extents. */
- float start_t;
- float end_t;
-
- /* If volume is absorption-only up to this point, and no probabilistic
- * scattering or termination has been used yet. */
- bool absorption_only;
-
- /* Random numbers for scattering. */
- float rscatter;
- float rphase;
-
- /* Multiple importance sampling. */
- VolumeSampleMethod direct_sample_method;
- bool use_mis;
- float distance_pdf;
- float equiangular_pdf;
-} VolumeIntegrateState;
-
-ccl_device_forceinline void volume_integrate_step_scattering(
- ccl_private const ShaderData *sd,
- ccl_private const Ray *ray,
- const float3 equiangular_light_P,
- ccl_private const VolumeShaderCoefficients &ccl_restrict coeff,
- const float3 transmittance,
- ccl_private VolumeIntegrateState &ccl_restrict vstate,
- ccl_private VolumeIntegrateResult &ccl_restrict result)
-{
- /* Pick random color channel, we use the Veach one-sample
- * model with balance heuristic for the channels. */
- const float3 albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t);
- float3 channel_pdf;
- const int channel = volume_sample_channel(
- albedo, result.indirect_throughput, vstate.rphase, &channel_pdf);
-
- /* Equiangular sampling for direct lighting. */
- if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR && !result.direct_scatter) {
- if (result.direct_t >= vstate.start_t && result.direct_t <= vstate.end_t) {
- const float new_dt = result.direct_t - vstate.start_t;
- const float3 new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
-
- result.direct_scatter = true;
- result.direct_throughput *= coeff.sigma_s * new_transmittance / vstate.equiangular_pdf;
- shader_copy_volume_phases(&result.direct_phases, sd);
-
- /* Multiple importance sampling. */
- if (vstate.use_mis) {
- const float distance_pdf = vstate.distance_pdf *
- dot(channel_pdf, coeff.sigma_t * new_transmittance);
- const float mis_weight = 2.0f * power_heuristic(vstate.equiangular_pdf, distance_pdf);
- result.direct_throughput *= mis_weight;
- }
- }
- else {
- result.direct_throughput *= transmittance;
- vstate.distance_pdf *= dot(channel_pdf, transmittance);
- }
- }
-
- /* Distance sampling for indirect and optional direct lighting. */
- if (!result.indirect_scatter) {
- /* decide if we will scatter or continue */
- const float sample_transmittance = volume_channel_get(transmittance, channel);
-
- if (1.0f - vstate.rscatter >= sample_transmittance) {
- /* compute sampling distance */
- const float sample_sigma_t = volume_channel_get(coeff.sigma_t, channel);
- const float new_dt = -logf(1.0f - vstate.rscatter) / sample_sigma_t;
- const float new_t = vstate.start_t + new_dt;
-
- /* transmittance and pdf */
- const float3 new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
- const float distance_pdf = dot(channel_pdf, coeff.sigma_t * new_transmittance);
-
- /* throughput */
- result.indirect_scatter = true;
- result.indirect_t = new_t;
- result.indirect_throughput *= coeff.sigma_s * new_transmittance / distance_pdf;
- shader_copy_volume_phases(&result.indirect_phases, sd);
-
- if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
- /* If using distance sampling for direct light, just copy parameters
- * of indirect light since we scatter at the same point then. */
- result.direct_scatter = true;
- result.direct_t = result.indirect_t;
- result.direct_throughput = result.indirect_throughput;
- shader_copy_volume_phases(&result.direct_phases, sd);
-
- /* Multiple importance sampling. */
- if (vstate.use_mis) {
- const float equiangular_pdf = volume_equiangular_pdf(ray, equiangular_light_P, new_t);
- const float mis_weight = power_heuristic(vstate.distance_pdf * distance_pdf,
- equiangular_pdf);
- result.direct_throughput *= 2.0f * mis_weight;
- }
- }
- }
- else {
- /* throughput */
- const float pdf = dot(channel_pdf, transmittance);
- result.indirect_throughput *= transmittance / pdf;
- if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
- vstate.distance_pdf *= pdf;
- }
-
- /* remap rscatter so we can reuse it and keep thing stratified */
- vstate.rscatter = 1.0f - (1.0f - vstate.rscatter) / sample_transmittance;
- }
- }
-}
-
-/* heterogeneous volume distance sampling: integrate stepping through the
- * volume until we reach the end, get absorbed entirely, or run out of
- * iterations. this does probabilistically scatter or get transmitted through
- * for path tracing where we don't want to branch. */
-ccl_device_forceinline void volume_integrate_heterogeneous(
- KernelGlobals kg,
- IntegratorState state,
- ccl_private Ray *ccl_restrict ray,
- ccl_private ShaderData *ccl_restrict sd,
- ccl_private const RNGState *rng_state,
- ccl_global float *ccl_restrict render_buffer,
- const float object_step_size,
- const VolumeSampleMethod direct_sample_method,
- const float3 equiangular_light_P,
- ccl_private VolumeIntegrateResult &result)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_INTEGRATE);
-
- /* Prepare for stepping.
- * Using a different step offset for the first step avoids banding artifacts. */
- int max_steps;
- float step_size, step_shade_offset, steps_offset;
- volume_step_init(kg,
- rng_state,
- object_step_size,
- ray->t,
- &step_size,
- &step_shade_offset,
- &steps_offset,
- &max_steps);
-
- /* Initialize volume integration state. */
- VolumeIntegrateState vstate ccl_optional_struct_init;
- vstate.start_t = 0.0f;
- vstate.end_t = 0.0f;
- vstate.absorption_only = true;
- vstate.rscatter = path_state_rng_1D(kg, rng_state, PRNG_SCATTER_DISTANCE);
- vstate.rphase = path_state_rng_1D(kg, rng_state, PRNG_PHASE_CHANNEL);
-
- /* Multiple importance sampling: pick between equiangular and distance sampling strategy. */
- vstate.direct_sample_method = direct_sample_method;
- vstate.use_mis = (direct_sample_method == VOLUME_SAMPLE_MIS);
- if (vstate.use_mis) {
- if (vstate.rscatter < 0.5f) {
- vstate.rscatter *= 2.0f;
- vstate.direct_sample_method = VOLUME_SAMPLE_DISTANCE;
- }
- else {
- vstate.rscatter = (vstate.rscatter - 0.5f) * 2.0f;
- vstate.direct_sample_method = VOLUME_SAMPLE_EQUIANGULAR;
- }
- }
- vstate.equiangular_pdf = 0.0f;
- vstate.distance_pdf = 1.0f;
-
- /* Initialize volume integration result. */
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- result.direct_throughput = throughput;
- result.indirect_throughput = throughput;
-
- /* Equiangular sampling: compute distance and PDF in advance. */
- if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
- result.direct_t = volume_equiangular_sample(
- ray, equiangular_light_P, vstate.rscatter, &vstate.equiangular_pdf);
- }
-
-# ifdef __DENOISING_FEATURES__
- const bool write_denoising_features = (INTEGRATOR_STATE(state, path, flag) &
- PATH_RAY_DENOISING_FEATURES);
- float3 accum_albedo = zero_float3();
-# endif
- float3 accum_emission = zero_float3();
-
- for (int i = 0; i < max_steps; i++) {
- /* Advance to new position */
- vstate.end_t = min(ray->t, (i + steps_offset) * step_size);
- const float shade_t = vstate.start_t + (vstate.end_t - vstate.start_t) * step_shade_offset;
- sd->P = ray->P + ray->D * shade_t;
-
- /* compute segment */
- VolumeShaderCoefficients coeff ccl_optional_struct_init;
- if (volume_shader_sample(kg, state, sd, &coeff)) {
- const int closure_flag = sd->flag;
-
- /* Evaluate transmittance over segment. */
- const float dt = (vstate.end_t - vstate.start_t);
- const float3 transmittance = (closure_flag & SD_EXTINCTION) ?
- volume_color_transmittance(coeff.sigma_t, dt) :
- one_float3();
-
- /* Emission. */
- if (closure_flag & SD_EMISSION) {
- /* Only write emission before indirect light scatter position, since we terminate
- * stepping at that point if we have already found a direct light scatter position. */
- if (!result.indirect_scatter) {
- const float3 emission = volume_emission_integrate(
- &coeff, closure_flag, transmittance, dt);
- accum_emission += emission;
- }
- }
-
- if (closure_flag & SD_EXTINCTION) {
- if ((closure_flag & SD_SCATTER) || !vstate.absorption_only) {
-# ifdef __DENOISING_FEATURES__
- /* Accumulate albedo for denoising features. */
- if (write_denoising_features && (closure_flag & SD_SCATTER)) {
- const float3 albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t);
- accum_albedo += result.indirect_throughput * albedo * (one_float3() - transmittance);
- }
-# endif
-
- /* Scattering and absorption. */
- volume_integrate_step_scattering(
- sd, ray, equiangular_light_P, coeff, transmittance, vstate, result);
- }
- else {
- /* Absorption only. */
- result.indirect_throughput *= transmittance;
- result.direct_throughput *= transmittance;
- }
-
- /* Stop if nearly all light blocked. */
- if (!result.indirect_scatter) {
- if (max3(result.indirect_throughput) < VOLUME_THROUGHPUT_EPSILON) {
- result.indirect_throughput = zero_float3();
- break;
- }
- }
- else if (!result.direct_scatter) {
- if (max3(result.direct_throughput) < VOLUME_THROUGHPUT_EPSILON) {
- break;
- }
- }
- }
-
- /* If we have scattering data for both direct and indirect, we're done. */
- if (result.direct_scatter && result.indirect_scatter) {
- break;
- }
- }
-
- /* Stop if at the end of the volume. */
- vstate.start_t = vstate.end_t;
- if (vstate.start_t == ray->t) {
- break;
- }
- }
-
- /* Write accumulated emission. */
- if (!is_zero(accum_emission)) {
- kernel_accum_emission(kg, state, result.indirect_throughput, accum_emission, render_buffer);
- }
-
-# ifdef __DENOISING_FEATURES__
- /* Write denoising features. */
- if (write_denoising_features) {
- kernel_write_denoising_features_volume(
- kg, state, accum_albedo, result.indirect_scatter, render_buffer);
- }
-# endif /* __DENOISING_FEATURES__ */
-}
-
-# ifdef __EMISSION__
-/* Path tracing: sample point on light and evaluate light shader, then
- * queue shadow ray to be traced. */
-ccl_device_forceinline bool integrate_volume_sample_light(
- KernelGlobals kg,
- IntegratorState state,
- ccl_private const ShaderData *ccl_restrict sd,
- ccl_private const RNGState *ccl_restrict rng_state,
- ccl_private LightSample *ccl_restrict ls)
-{
- /* Test if there is a light or BSDF that needs direct light. */
- if (!kernel_data.integrator.use_direct_light) {
- return false;
- }
-
- /* Sample position on a light. */
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
- const uint bounce = INTEGRATOR_STATE(state, path, bounce);
- float light_u, light_v;
- path_state_rng_2D(kg, rng_state, PRNG_LIGHT_U, &light_u, &light_v);
-
- light_distribution_sample_from_volume_segment(
- kg, light_u, light_v, sd->time, sd->P, bounce, path_flag, ls);
-
- if (ls->shader & SHADER_EXCLUDE_SCATTER) {
- return false;
- }
-
- return true;
-}
-
-/* Path tracing: sample point on light and evaluate light shader, then
- * queue shadow ray to be traced. */
-ccl_device_forceinline void integrate_volume_direct_light(
- KernelGlobals kg,
- IntegratorState state,
- ccl_private const ShaderData *ccl_restrict sd,
- ccl_private const RNGState *ccl_restrict rng_state,
- const float3 P,
- ccl_private const ShaderVolumePhases *ccl_restrict phases,
- ccl_private const float3 throughput,
- ccl_private LightSample *ccl_restrict ls)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_DIRECT_LIGHT);
-
- if (!kernel_data.integrator.use_direct_light) {
- return;
- }
-
- /* Sample position on the same light again, now from the shading
- * point where we scattered.
- *
- * TODO: decorrelate random numbers and use light_sample_new_position to
- * avoid resampling the CDF. */
- {
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
- const uint bounce = INTEGRATOR_STATE(state, path, bounce);
- float light_u, light_v;
- path_state_rng_2D(kg, rng_state, PRNG_LIGHT_U, &light_u, &light_v);
-
- if (!light_distribution_sample_from_position(
- kg, light_u, light_v, sd->time, P, bounce, path_flag, ls)) {
- return;
- }
- }
-
- if (ls->shader & SHADER_EXCLUDE_SCATTER) {
- return;
- }
-
- /* Evaluate light shader.
- *
- * TODO: can we reuse sd memory? In theory we can move this after
- * integrate_surface_bounce, evaluate the BSDF, and only then evaluate
- * the light shader. This could also move to its own kernel, for
- * non-constant light sources. */
- ShaderDataTinyStorage emission_sd_storage;
- ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
- const float3 light_eval = light_sample_shader_eval(kg, state, emission_sd, ls, sd->time);
- if (is_zero(light_eval)) {
- return;
- }
-
- /* Evaluate BSDF. */
- BsdfEval phase_eval ccl_optional_struct_init;
- const float phase_pdf = shader_volume_phase_eval(kg, sd, phases, ls->D, &phase_eval);
-
- if (ls->shader & SHADER_USE_MIS) {
- float mis_weight = power_heuristic(ls->pdf, phase_pdf);
- bsdf_eval_mul(&phase_eval, mis_weight);
- }
-
- bsdf_eval_mul3(&phase_eval, light_eval / ls->pdf);
-
- /* Path termination. */
- const float terminate = path_state_rng_light_termination(kg, rng_state);
- if (light_sample_terminate(kg, ls, &phase_eval, terminate)) {
- return;
- }
-
- /* Create shadow ray. */
- Ray ray ccl_optional_struct_init;
- light_sample_to_volume_shadow_ray(kg, sd, ls, P, &ray);
- const bool is_light = light_sample_is_light(ls);
-
- /* Branch off shadow kernel. */
- INTEGRATOR_SHADOW_PATH_INIT(
- shadow_state, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, shadow);
-
- /* Write shadow ray and associated state to global memory. */
- integrator_state_write_shadow_ray(kg, shadow_state, &ray);
-
- /* Copy state from main path to shadow path. */
- const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce);
- const uint16_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce);
- uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag);
- shadow_flag |= (is_light) ? PATH_RAY_SHADOW_FOR_LIGHT : 0;
- shadow_flag |= PATH_RAY_VOLUME_PASS;
- const float3 throughput_phase = throughput * bsdf_eval_sum(&phase_eval);
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
- const float3 diffuse_glossy_ratio = (bounce == 0) ?
- one_float3() :
- INTEGRATOR_STATE(state, path, diffuse_glossy_ratio);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, diffuse_glossy_ratio) = diffuse_glossy_ratio;
- }
-
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, render_pixel_index) = INTEGRATOR_STATE(
- state, path, render_pixel_index);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_offset) = INTEGRATOR_STATE(
- state, path, rng_offset);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_hash) = INTEGRATOR_STATE(
- state, path, rng_hash);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, sample) = INTEGRATOR_STATE(
- state, path, sample);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, flag) = shadow_flag;
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, bounce) = bounce;
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transparent_bounce) = transparent_bounce;
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, diffuse_bounce) = INTEGRATOR_STATE(
- state, path, diffuse_bounce);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, glossy_bounce) = INTEGRATOR_STATE(
- state, path, glossy_bounce);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transmission_bounce) = INTEGRATOR_STATE(
- state, path, transmission_bounce);
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput_phase;
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_PASS) {
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unshadowed_throughput) = throughput;
- }
-
- integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state);
-}
-# endif
-
-/* Path tracing: scatter in new direction using phase function */
-ccl_device_forceinline bool integrate_volume_phase_scatter(
- KernelGlobals kg,
- IntegratorState state,
- ccl_private ShaderData *sd,
- ccl_private const RNGState *rng_state,
- ccl_private const ShaderVolumePhases *phases)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_INDIRECT_LIGHT);
-
- float phase_u, phase_v;
- path_state_rng_2D(kg, rng_state, PRNG_BSDF_U, &phase_u, &phase_v);
-
- /* Phase closure, sample direction. */
- float phase_pdf;
- BsdfEval phase_eval ccl_optional_struct_init;
- float3 phase_omega_in ccl_optional_struct_init;
- differential3 phase_domega_in ccl_optional_struct_init;
-
- const int label = shader_volume_phase_sample(kg,
- sd,
- phases,
- phase_u,
- phase_v,
- &phase_eval,
- &phase_omega_in,
- &phase_domega_in,
- &phase_pdf);
-
- if (phase_pdf == 0.0f || bsdf_eval_is_zero(&phase_eval)) {
- return false;
- }
-
- /* Setup ray. */
- INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
- INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(phase_omega_in);
- INTEGRATOR_STATE_WRITE(state, ray, t) = FLT_MAX;
-
-# ifdef __RAY_DIFFERENTIALS__
- INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
- INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_make_compact(phase_domega_in);
-# endif
-
- /* Update throughput. */
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- const float3 throughput_phase = throughput * bsdf_eval_sum(&phase_eval) / phase_pdf;
- INTEGRATOR_STATE_WRITE(state, path, throughput) = throughput_phase;
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
- INTEGRATOR_STATE_WRITE(state, path, diffuse_glossy_ratio) = one_float3();
- }
-
- /* Update path state */
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = phase_pdf;
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f;
- INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
- phase_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
-
- path_state_next(kg, state, label);
- return true;
-}
-
-/* get the volume attenuation and emission over line segment defined by
- * ray, with the assumption that there are no surfaces blocking light
- * between the endpoints. distance sampling is used to decide if we will
- * scatter or not. */
-ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
- IntegratorState state,
- ccl_private Ray *ccl_restrict ray,
- ccl_global float *ccl_restrict render_buffer)
-{
- ShaderData sd;
- shader_setup_from_volume(kg, &sd, ray);
-
- /* Load random number state. */
- RNGState rng_state;
- path_state_rng_load(state, &rng_state);
-
- /* Sample light ahead of volume stepping, for equiangular sampling. */
- /* TODO: distant lights are ignored now, but could instead use even distribution. */
- LightSample ls ccl_optional_struct_init;
- const bool need_light_sample = !(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_TERMINATE);
- const bool have_equiangular_sample = need_light_sample &&
- integrate_volume_sample_light(
- kg, state, &sd, &rng_state, &ls) &&
- (ls.t != FLT_MAX);
-
- VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ?
- volume_stack_sample_method(kg, state) :
- VOLUME_SAMPLE_DISTANCE;
-
- /* Step through volume. */
- const float step_size = volume_stack_step_size(
- kg, [=](const int i) { return integrator_state_read_volume_stack(state, i); });
-
- /* TODO: expensive to zero closures? */
- VolumeIntegrateResult result = {};
- volume_integrate_heterogeneous(kg,
- state,
- ray,
- &sd,
- &rng_state,
- render_buffer,
- step_size,
- direct_sample_method,
- ls.P,
- result);
-
- /* Perform path termination. The intersect_closest will have already marked this path
- * to be terminated. That will shading evaluating to leave out any scattering closures,
- * but emission and absorption are still handled for multiple importance sampling. */
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
- const float probability = (path_flag & PATH_RAY_TERMINATE_IN_NEXT_VOLUME) ?
- 0.0f :
- path_state_continuation_probability(kg, state, path_flag);
- if (probability == 0.0f) {
- return VOLUME_PATH_MISSED;
- }
-
- /* Direct light. */
- if (result.direct_scatter) {
- const float3 direct_P = ray->P + result.direct_t * ray->D;
- result.direct_throughput /= probability;
- integrate_volume_direct_light(kg,
- state,
- &sd,
- &rng_state,
- direct_P,
- &result.direct_phases,
- result.direct_throughput,
- &ls);
- }
-
- /* Indirect light.
- *
- * Only divide throughput by probability if we scatter. For the attenuation
- * case the next surface will already do this division. */
- if (result.indirect_scatter) {
- result.indirect_throughput /= probability;
- }
- INTEGRATOR_STATE_WRITE(state, path, throughput) = result.indirect_throughput;
-
- if (result.indirect_scatter) {
- sd.P = ray->P + result.indirect_t * ray->D;
-
- if (integrate_volume_phase_scatter(kg, state, &sd, &rng_state, &result.indirect_phases)) {
- return VOLUME_PATH_SCATTERED;
- }
- else {
- return VOLUME_PATH_MISSED;
- }
- }
- else {
- return VOLUME_PATH_ATTENUATED;
- }
-}
-
-#endif
-
-ccl_device void integrator_shade_volume(KernelGlobals kg,
- IntegratorState state,
- ccl_global float *ccl_restrict render_buffer)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_SETUP);
-
-#ifdef __VOLUME__
- /* Setup shader data. */
- Ray ray ccl_optional_struct_init;
- integrator_state_read_ray(kg, state, &ray);
-
- Intersection isect ccl_optional_struct_init;
- integrator_state_read_isect(kg, state, &isect);
-
- /* Set ray length to current segment. */
- ray.t = (isect.prim != PRIM_NONE) ? isect.t : FLT_MAX;
-
- /* Clean volume stack for background rays. */
- if (isect.prim == PRIM_NONE) {
- volume_stack_clean(kg, state);
- }
-
- VolumeIntegrateEvent event = volume_integrate(kg, state, &ray, render_buffer);
-
- if (event == VOLUME_PATH_SCATTERED) {
- /* Queue intersect_closest kernel. */
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
- DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
- return;
- }
- else if (event == VOLUME_PATH_MISSED) {
- /* End path. */
- INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
- return;
- }
- else {
- /* Continue to background, light or surface. */
- if (isect.prim == PRIM_NONE) {
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
- DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
- return;
- }
- else if (isect.type & PRIMITIVE_LAMP) {
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
- DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
- return;
- }
- else {
- /* Hit a surface, continue with surface kernel unless terminated. */
- const int shader = intersection_get_shader(kg, &isect);
- const int flags = kernel_tex_fetch(__shaders, shader).flags;
-
- integrator_intersect_shader_next_kernel<DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME>(
- kg, state, &isect, shader, flags);
- return;
- }
- }
-#endif /* __VOLUME__ */
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_shadow_state_template.h b/intern/cycles/kernel/integrator/integrator_shadow_state_template.h
deleted file mode 100644
index bc35b644ee1..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shadow_state_template.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/********************************* Shadow Path State **************************/
-
-KERNEL_STRUCT_BEGIN(shadow_path)
-/* Index of a pixel within the device render buffer. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint32_t, render_pixel_index, KERNEL_FEATURE_PATH_TRACING)
-/* Current sample number. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, sample, KERNEL_FEATURE_PATH_TRACING)
-/* Random number generator seed. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint32_t, rng_hash, KERNEL_FEATURE_PATH_TRACING)
-/* Random number dimension offset. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, rng_offset, KERNEL_FEATURE_PATH_TRACING)
-/* Current ray bounce depth. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, bounce, KERNEL_FEATURE_PATH_TRACING)
-/* Current transparent ray bounce depth. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, transparent_bounce, KERNEL_FEATURE_PATH_TRACING)
-/* Current diffuse ray bounce depth. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, diffuse_bounce, KERNEL_FEATURE_PATH_TRACING)
-/* Current glossy ray bounce depth. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, glossy_bounce, KERNEL_FEATURE_PATH_TRACING)
-/* Current transmission ray bounce depth. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, transmission_bounce, KERNEL_FEATURE_PATH_TRACING)
-/* DeviceKernel bit indicating queued kernels. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, queued_kernel, KERNEL_FEATURE_PATH_TRACING)
-/* enum PathRayFlag */
-KERNEL_STRUCT_MEMBER(shadow_path, uint32_t, flag, KERNEL_FEATURE_PATH_TRACING)
-/* Throughput. */
-KERNEL_STRUCT_MEMBER(shadow_path, float3, throughput, KERNEL_FEATURE_PATH_TRACING)
-/* Throughput for shadow pass. */
-KERNEL_STRUCT_MEMBER(shadow_path, float3, unshadowed_throughput, KERNEL_FEATURE_SHADOW_PASS)
-/* Ratio of throughput to distinguish diffuse and glossy render passes. */
-KERNEL_STRUCT_MEMBER(shadow_path, float3, diffuse_glossy_ratio, KERNEL_FEATURE_LIGHT_PASSES)
-/* Number of intersections found by ray-tracing. */
-KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, num_hits, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_END(shadow_path)
-
-/********************************** Shadow Ray *******************************/
-
-KERNEL_STRUCT_BEGIN(shadow_ray)
-KERNEL_STRUCT_MEMBER(shadow_ray, float3, P, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(shadow_ray, float3, D, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(shadow_ray, float, t, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(shadow_ray, float, time, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(shadow_ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_END(shadow_ray)
-
-/*********************** Shadow Intersection result **************************/
-
-/* Result from scene intersection. */
-KERNEL_STRUCT_BEGIN(shadow_isect)
-KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, float, t, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, float, u, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, float, v, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, int, prim, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, int, object, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, int, type, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_END_ARRAY(shadow_isect,
- INTEGRATOR_SHADOW_ISECT_SIZE_CPU,
- INTEGRATOR_SHADOW_ISECT_SIZE_GPU)
-
-/**************************** Shadow Volume Stack *****************************/
-
-KERNEL_STRUCT_BEGIN(shadow_volume_stack)
-KERNEL_STRUCT_ARRAY_MEMBER(shadow_volume_stack, int, object, KERNEL_FEATURE_VOLUME)
-KERNEL_STRUCT_ARRAY_MEMBER(shadow_volume_stack, int, shader, KERNEL_FEATURE_VOLUME)
-KERNEL_STRUCT_END_ARRAY(shadow_volume_stack,
- KERNEL_STRUCT_VOLUME_STACK_SIZE,
- KERNEL_STRUCT_VOLUME_STACK_SIZE)
diff --git a/intern/cycles/kernel/integrator/integrator_state.h b/intern/cycles/kernel/integrator/integrator_state.h
deleted file mode 100644
index 09b399ff1b8..00000000000
--- a/intern/cycles/kernel/integrator/integrator_state.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Integrator State
- *
- * This file defines the data structures that define the state of a path. Any state that is
- * preserved and passed between kernel executions is part of this.
- *
- * The size of this state must be kept as small as possible, to reduce cache misses and keep memory
- * usage under control on GPUs that may execute millions of kernels.
- *
- * Memory may be allocated and passed along in different ways depending on the device. There may
- * be a scalar layout, or AoS or SoA layout for batches. The state may be passed along as a pointer
- * to every kernel, or the pointer may exist at program scope or in constant memory. To abstract
- * these differences between devices and experiment with different layouts, macros are used.
- *
- * Use IntegratorState to pass a reference to the integrator state for the current path. These are
- * defined differently on the CPU and GPU. Use ConstIntegratorState instead of const
- * IntegratorState for passing state as read-only, to avoid oddities in typedef behavior.
- *
- * INTEGRATOR_STATE(state, x, y): read nested struct member x.y of IntegratorState
- * INTEGRATOR_STATE_WRITE(state, x, y): write to nested struct member x.y of IntegratorState
- *
- * INTEGRATOR_STATE_ARRAY(state, x, index, y): read x[index].y
- * INTEGRATOR_STATE_ARRAY_WRITE(state, x, index, y): write x[index].y
- *
- * INTEGRATOR_STATE_NULL: use to pass empty state to other functions.
- */
-
-#include "kernel/kernel_types.h"
-
-#include "util/util_types.h"
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* Data structures */
-
-/* Integrator State
- *
- * CPU rendering path state with AoS layout. */
-typedef struct IntegratorShadowStateCPU {
-#define KERNEL_STRUCT_BEGIN(name) struct {
-#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) type name;
-#define KERNEL_STRUCT_ARRAY_MEMBER KERNEL_STRUCT_MEMBER
-#define KERNEL_STRUCT_END(name) \
- } \
- name;
-#define KERNEL_STRUCT_END_ARRAY(name, cpu_size, gpu_size) \
- } \
- name[cpu_size];
-#define KERNEL_STRUCT_VOLUME_STACK_SIZE MAX_VOLUME_STACK_SIZE
-#include "kernel/integrator/integrator_shadow_state_template.h"
-#undef KERNEL_STRUCT_BEGIN
-#undef KERNEL_STRUCT_MEMBER
-#undef KERNEL_STRUCT_ARRAY_MEMBER
-#undef KERNEL_STRUCT_END
-#undef KERNEL_STRUCT_END_ARRAY
-} IntegratorShadowStateCPU;
-
-typedef struct IntegratorStateCPU {
-#define KERNEL_STRUCT_BEGIN(name) struct {
-#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) type name;
-#define KERNEL_STRUCT_ARRAY_MEMBER KERNEL_STRUCT_MEMBER
-#define KERNEL_STRUCT_END(name) \
- } \
- name;
-#define KERNEL_STRUCT_END_ARRAY(name, cpu_size, gpu_size) \
- } \
- name[cpu_size];
-#define KERNEL_STRUCT_VOLUME_STACK_SIZE MAX_VOLUME_STACK_SIZE
-#include "kernel/integrator/integrator_state_template.h"
-#undef KERNEL_STRUCT_BEGIN
-#undef KERNEL_STRUCT_MEMBER
-#undef KERNEL_STRUCT_ARRAY_MEMBER
-#undef KERNEL_STRUCT_END
-#undef KERNEL_STRUCT_END_ARRAY
-#undef KERNEL_STRUCT_VOLUME_STACK_SIZE
-
- IntegratorShadowStateCPU shadow;
- IntegratorShadowStateCPU ao;
-} IntegratorStateCPU;
-
-/* Path Queue
- *
- * Keep track of which kernels are queued to be executed next in the path
- * for GPU rendering. */
-typedef struct IntegratorQueueCounter {
- int num_queued[DEVICE_KERNEL_INTEGRATOR_NUM];
-} IntegratorQueueCounter;
-
-/* Integrator State GPU
- *
- * GPU rendering path state with SoA layout. */
-typedef struct IntegratorStateGPU {
-#define KERNEL_STRUCT_BEGIN(name) struct {
-#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) ccl_global type *name;
-#define KERNEL_STRUCT_ARRAY_MEMBER KERNEL_STRUCT_MEMBER
-#define KERNEL_STRUCT_END(name) \
- } \
- name;
-#define KERNEL_STRUCT_END_ARRAY(name, cpu_size, gpu_size) \
- } \
- name[gpu_size];
-#define KERNEL_STRUCT_VOLUME_STACK_SIZE MAX_VOLUME_STACK_SIZE
-
-#include "kernel/integrator/integrator_state_template.h"
-
-#include "kernel/integrator/integrator_shadow_state_template.h"
-
-#undef KERNEL_STRUCT_BEGIN
-#undef KERNEL_STRUCT_MEMBER
-#undef KERNEL_STRUCT_ARRAY_MEMBER
-#undef KERNEL_STRUCT_END
-#undef KERNEL_STRUCT_END_ARRAY
-#undef KERNEL_STRUCT_VOLUME_STACK_SIZE
-
- /* Count number of queued kernels. */
- ccl_global IntegratorQueueCounter *queue_counter;
-
- /* Count number of kernels queued for specific shaders. */
- ccl_global int *sort_key_counter[DEVICE_KERNEL_INTEGRATOR_NUM];
-
- /* Index of shadow path which will be used by a next shadow path. */
- ccl_global int *next_shadow_path_index;
-
- /* Index of main path which will be used by a next shadow catcher split. */
- ccl_global int *next_main_path_index;
-} IntegratorStateGPU;
-
-/* Abstraction
- *
- * Macros to access data structures on different devices.
- *
- * Note that there is a special access function for the shadow catcher state. This access is to
- * happen from a kernel which operates on a "main" path. Attempt to use shadow catcher accessors
- * from a kernel which operates on a shadow catcher state will cause bad memory access. */
-
-#ifdef __KERNEL_CPU__
-
-/* Scalar access on CPU. */
-
-typedef IntegratorStateCPU *ccl_restrict IntegratorState;
-typedef const IntegratorStateCPU *ccl_restrict ConstIntegratorState;
-typedef IntegratorShadowStateCPU *ccl_restrict IntegratorShadowState;
-typedef const IntegratorShadowStateCPU *ccl_restrict ConstIntegratorShadowState;
-
-# define INTEGRATOR_STATE_NULL nullptr
-
-# define INTEGRATOR_STATE(state, nested_struct, member) ((state)->nested_struct.member)
-# define INTEGRATOR_STATE_WRITE(state, nested_struct, member) ((state)->nested_struct.member)
-
-# define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member) \
- ((state)->nested_struct[array_index].member)
-# define INTEGRATOR_STATE_ARRAY_WRITE(state, nested_struct, array_index, member) \
- ((state)->nested_struct[array_index].member)
-
-#else /* __KERNEL_CPU__ */
-
-/* Array access on GPU with Structure-of-Arrays. */
-
-typedef const int IntegratorState;
-typedef const int ConstIntegratorState;
-typedef const int IntegratorShadowState;
-typedef const int ConstIntegratorShadowState;
-
-# define INTEGRATOR_STATE_NULL -1
-
-# define INTEGRATOR_STATE(state, nested_struct, member) \
- kernel_integrator_state.nested_struct.member[state]
-# define INTEGRATOR_STATE_WRITE(state, nested_struct, member) \
- INTEGRATOR_STATE(state, nested_struct, member)
-
-# define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member) \
- kernel_integrator_state.nested_struct[array_index].member[state]
-# define INTEGRATOR_STATE_ARRAY_WRITE(state, nested_struct, array_index, member) \
- INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member)
-
-#endif /* __KERNEL_CPU__ */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_state_flow.h b/intern/cycles/kernel/integrator/integrator_state_flow.h
deleted file mode 100644
index 1569bf68e24..00000000000
--- a/intern/cycles/kernel/integrator/integrator_state_flow.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_types.h"
-#include "util/util_atomic.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Control Flow
- *
- * Utilities for control flow between kernels. The implementation may differ per device
- * or even be handled on the host side. To abstract such differences, experiment with
- * different implementations and for debugging, this is abstracted using macros.
- *
- * There is a main path for regular path tracing camera for path tracing. Shadows for next
- * event estimation branch off from this into their own path, that may be computed in
- * parallel while the main path continues.
- *
- * Each kernel on the main path must call one of these functions. These may not be called
- * multiple times from the same kernel.
- *
- * INTEGRATOR_PATH_INIT(next_kernel)
- * INTEGRATOR_PATH_NEXT(current_kernel, next_kernel)
- * INTEGRATOR_PATH_TERMINATE(current_kernel)
- *
- * For the shadow path similar functions are used, and again each shadow kernel must call
- * one of them, and only once.
- */
-
-#define INTEGRATOR_PATH_IS_TERMINATED (INTEGRATOR_STATE(state, path, queued_kernel) == 0)
-#define INTEGRATOR_SHADOW_PATH_IS_TERMINATED \
- (INTEGRATOR_STATE(state, shadow_path, queued_kernel) == 0)
-
-#ifdef __KERNEL_GPU__
-
-# define INTEGRATOR_PATH_INIT(next_kernel) \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
- 1); \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
-# define INTEGRATOR_PATH_NEXT(current_kernel, next_kernel) \
- atomic_fetch_and_sub_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
- 1); \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
-# define INTEGRATOR_PATH_TERMINATE(current_kernel) \
- atomic_fetch_and_sub_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0;
-
-# define INTEGRATOR_SHADOW_PATH_INIT(shadow_state, state, next_kernel, shadow_type) \
- IntegratorShadowState shadow_state = atomic_fetch_and_add_uint32( \
- &kernel_integrator_state.next_shadow_path_index[0], 1); \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
- 1); \
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, queued_kernel) = next_kernel;
-# define INTEGRATOR_SHADOW_PATH_NEXT(current_kernel, next_kernel) \
- atomic_fetch_and_sub_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
- 1); \
- INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = next_kernel;
-# define INTEGRATOR_SHADOW_PATH_TERMINATE(current_kernel) \
- atomic_fetch_and_sub_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
- INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0;
-
-# define INTEGRATOR_PATH_INIT_SORTED(next_kernel, key) \
- { \
- const int key_ = key; \
- atomic_fetch_and_add_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[next_kernel], 1); \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
- INTEGRATOR_STATE_WRITE(state, path, shader_sort_key) = key_; \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.sort_key_counter[next_kernel][key_], \
- 1); \
- }
-# define INTEGRATOR_PATH_NEXT_SORTED(current_kernel, next_kernel, key) \
- { \
- const int key_ = key; \
- atomic_fetch_and_sub_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
- atomic_fetch_and_add_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[next_kernel], 1); \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
- INTEGRATOR_STATE_WRITE(state, path, shader_sort_key) = key_; \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.sort_key_counter[next_kernel][key_], \
- 1); \
- }
-
-#else
-
-# define INTEGRATOR_PATH_INIT(next_kernel) \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
-# define INTEGRATOR_PATH_INIT_SORTED(next_kernel, key) \
- { \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
- (void)key; \
- }
-# define INTEGRATOR_PATH_NEXT(current_kernel, next_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
- (void)current_kernel; \
- }
-# define INTEGRATOR_PATH_TERMINATE(current_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0; \
- (void)current_kernel; \
- }
-# define INTEGRATOR_PATH_NEXT_SORTED(current_kernel, next_kernel, key) \
- { \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
- (void)key; \
- (void)current_kernel; \
- }
-
-# define INTEGRATOR_SHADOW_PATH_INIT(shadow_state, state, next_kernel, shadow_type) \
- IntegratorShadowState shadow_state = &state->shadow_type; \
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, queued_kernel) = next_kernel;
-# define INTEGRATOR_SHADOW_PATH_NEXT(current_kernel, next_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = next_kernel; \
- (void)current_kernel; \
- }
-# define INTEGRATOR_SHADOW_PATH_TERMINATE(current_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0; \
- (void)current_kernel; \
- }
-
-#endif
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_state_util.h b/intern/cycles/kernel/integrator/integrator_state_util.h
deleted file mode 100644
index 6e6b7f8a40f..00000000000
--- a/intern/cycles/kernel/integrator/integrator_state_util.h
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/integrator/integrator_state.h"
-#include "kernel/kernel_differential.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Ray */
-
-ccl_device_forceinline void integrator_state_write_ray(KernelGlobals kg,
- IntegratorState state,
- ccl_private const Ray *ccl_restrict ray)
-{
- INTEGRATOR_STATE_WRITE(state, ray, P) = ray->P;
- INTEGRATOR_STATE_WRITE(state, ray, D) = ray->D;
- INTEGRATOR_STATE_WRITE(state, ray, t) = ray->t;
- INTEGRATOR_STATE_WRITE(state, ray, time) = ray->time;
- INTEGRATOR_STATE_WRITE(state, ray, dP) = ray->dP;
- INTEGRATOR_STATE_WRITE(state, ray, dD) = ray->dD;
-}
-
-ccl_device_forceinline void integrator_state_read_ray(KernelGlobals kg,
- ConstIntegratorState state,
- ccl_private Ray *ccl_restrict ray)
-{
- ray->P = INTEGRATOR_STATE(state, ray, P);
- ray->D = INTEGRATOR_STATE(state, ray, D);
- ray->t = INTEGRATOR_STATE(state, ray, t);
- ray->time = INTEGRATOR_STATE(state, ray, time);
- ray->dP = INTEGRATOR_STATE(state, ray, dP);
- ray->dD = INTEGRATOR_STATE(state, ray, dD);
-}
-
-/* Shadow Ray */
-
-ccl_device_forceinline void integrator_state_write_shadow_ray(
- KernelGlobals kg, IntegratorShadowState state, ccl_private const Ray *ccl_restrict ray)
-{
- INTEGRATOR_STATE_WRITE(state, shadow_ray, P) = ray->P;
- INTEGRATOR_STATE_WRITE(state, shadow_ray, D) = ray->D;
- INTEGRATOR_STATE_WRITE(state, shadow_ray, t) = ray->t;
- INTEGRATOR_STATE_WRITE(state, shadow_ray, time) = ray->time;
- INTEGRATOR_STATE_WRITE(state, shadow_ray, dP) = ray->dP;
-}
-
-ccl_device_forceinline void integrator_state_read_shadow_ray(KernelGlobals kg,
- ConstIntegratorShadowState state,
- ccl_private Ray *ccl_restrict ray)
-{
- ray->P = INTEGRATOR_STATE(state, shadow_ray, P);
- ray->D = INTEGRATOR_STATE(state, shadow_ray, D);
- ray->t = INTEGRATOR_STATE(state, shadow_ray, t);
- ray->time = INTEGRATOR_STATE(state, shadow_ray, time);
- ray->dP = INTEGRATOR_STATE(state, shadow_ray, dP);
- ray->dD = differential_zero_compact();
-}
-
-/* Intersection */
-
-ccl_device_forceinline void integrator_state_write_isect(
- KernelGlobals kg, IntegratorState state, ccl_private const Intersection *ccl_restrict isect)
-{
- INTEGRATOR_STATE_WRITE(state, isect, t) = isect->t;
- INTEGRATOR_STATE_WRITE(state, isect, u) = isect->u;
- INTEGRATOR_STATE_WRITE(state, isect, v) = isect->v;
- INTEGRATOR_STATE_WRITE(state, isect, object) = isect->object;
- INTEGRATOR_STATE_WRITE(state, isect, prim) = isect->prim;
- INTEGRATOR_STATE_WRITE(state, isect, type) = isect->type;
-}
-
-ccl_device_forceinline void integrator_state_read_isect(
- KernelGlobals kg, ConstIntegratorState state, ccl_private Intersection *ccl_restrict isect)
-{
- isect->prim = INTEGRATOR_STATE(state, isect, prim);
- isect->object = INTEGRATOR_STATE(state, isect, object);
- isect->type = INTEGRATOR_STATE(state, isect, type);
- isect->u = INTEGRATOR_STATE(state, isect, u);
- isect->v = INTEGRATOR_STATE(state, isect, v);
- isect->t = INTEGRATOR_STATE(state, isect, t);
-}
-
-ccl_device_forceinline VolumeStack integrator_state_read_volume_stack(ConstIntegratorState state,
- int i)
-{
- VolumeStack entry = {INTEGRATOR_STATE_ARRAY(state, volume_stack, i, object),
- INTEGRATOR_STATE_ARRAY(state, volume_stack, i, shader)};
- return entry;
-}
-
-ccl_device_forceinline void integrator_state_write_volume_stack(IntegratorState state,
- int i,
- VolumeStack entry)
-{
- INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, i, object) = entry.object;
- INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, i, shader) = entry.shader;
-}
-
-ccl_device_forceinline bool integrator_state_volume_stack_is_empty(KernelGlobals kg,
- ConstIntegratorState state)
-{
- return (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) ?
- INTEGRATOR_STATE_ARRAY(state, volume_stack, 0, shader) == SHADER_NONE :
- true;
-}
-
-/* Shadow Intersection */
-
-ccl_device_forceinline void integrator_state_write_shadow_isect(
- IntegratorShadowState state,
- ccl_private const Intersection *ccl_restrict isect,
- const int index)
-{
- INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, t) = isect->t;
- INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, u) = isect->u;
- INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, v) = isect->v;
- INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, object) = isect->object;
- INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, prim) = isect->prim;
- INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, type) = isect->type;
-}
-
-ccl_device_forceinline void integrator_state_read_shadow_isect(
- ConstIntegratorShadowState state,
- ccl_private Intersection *ccl_restrict isect,
- const int index)
-{
- isect->prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, prim);
- isect->object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, object);
- isect->type = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, type);
- isect->u = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, u);
- isect->v = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, v);
- isect->t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, t);
-}
-
-ccl_device_forceinline void integrator_state_copy_volume_stack_to_shadow(
- KernelGlobals kg, IntegratorShadowState shadow_state, ConstIntegratorState state)
-{
- if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) {
- int index = 0;
- int shader;
- do {
- shader = INTEGRATOR_STATE_ARRAY(state, volume_stack, index, shader);
-
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_volume_stack, index, object) =
- INTEGRATOR_STATE_ARRAY(state, volume_stack, index, object);
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_volume_stack, index, shader) = shader;
-
- ++index;
- } while (shader != OBJECT_NONE);
- }
-}
-
-ccl_device_forceinline void integrator_state_copy_volume_stack(KernelGlobals kg,
- IntegratorState to_state,
- ConstIntegratorState state)
-{
- if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) {
- int index = 0;
- int shader;
- do {
- shader = INTEGRATOR_STATE_ARRAY(state, volume_stack, index, shader);
-
- INTEGRATOR_STATE_ARRAY_WRITE(to_state, volume_stack, index, object) = INTEGRATOR_STATE_ARRAY(
- state, volume_stack, index, object);
- INTEGRATOR_STATE_ARRAY_WRITE(to_state, volume_stack, index, shader) = shader;
-
- ++index;
- } while (shader != OBJECT_NONE);
- }
-}
-
-ccl_device_forceinline VolumeStack
-integrator_state_read_shadow_volume_stack(ConstIntegratorShadowState state, int i)
-{
- VolumeStack entry = {INTEGRATOR_STATE_ARRAY(state, shadow_volume_stack, i, object),
- INTEGRATOR_STATE_ARRAY(state, shadow_volume_stack, i, shader)};
- return entry;
-}
-
-ccl_device_forceinline bool integrator_state_shadow_volume_stack_is_empty(
- KernelGlobals kg, ConstIntegratorShadowState state)
-{
- return (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) ?
- INTEGRATOR_STATE_ARRAY(state, shadow_volume_stack, 0, shader) == SHADER_NONE :
- true;
-}
-
-ccl_device_forceinline void integrator_state_write_shadow_volume_stack(IntegratorShadowState state,
- int i,
- VolumeStack entry)
-{
- INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_volume_stack, i, object) = entry.object;
- INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_volume_stack, i, shader) = entry.shader;
-}
-
-#if defined(__KERNEL_GPU__)
-ccl_device_inline void integrator_state_copy_only(KernelGlobals kg,
- ConstIntegratorState to_state,
- ConstIntegratorState state)
-{
- int index;
-
- /* Rely on the compiler to optimize out unused assignments and `while(false)`'s. */
-
-# define KERNEL_STRUCT_BEGIN(name) \
- index = 0; \
- do {
-
-# define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) \
- if (kernel_integrator_state.parent_struct.name != nullptr) { \
- kernel_integrator_state.parent_struct.name[to_state] = \
- kernel_integrator_state.parent_struct.name[state]; \
- }
-
-# define KERNEL_STRUCT_ARRAY_MEMBER(parent_struct, type, name, feature) \
- if (kernel_integrator_state.parent_struct[index].name != nullptr) { \
- kernel_integrator_state.parent_struct[index].name[to_state] = \
- kernel_integrator_state.parent_struct[index].name[state]; \
- }
-
-# define KERNEL_STRUCT_END(name) \
- } \
- while (false) \
- ;
-
-# define KERNEL_STRUCT_END_ARRAY(name, cpu_array_size, gpu_array_size) \
- ++index; \
- } \
- while (index < gpu_array_size) \
- ;
-
-# define KERNEL_STRUCT_VOLUME_STACK_SIZE kernel_data.volume_stack_size
-
-# include "kernel/integrator/integrator_state_template.h"
-
-# undef KERNEL_STRUCT_BEGIN
-# undef KERNEL_STRUCT_MEMBER
-# undef KERNEL_STRUCT_ARRAY_MEMBER
-# undef KERNEL_STRUCT_END
-# undef KERNEL_STRUCT_END_ARRAY
-# undef KERNEL_STRUCT_VOLUME_STACK_SIZE
-}
-
-ccl_device_inline void integrator_state_move(KernelGlobals kg,
- ConstIntegratorState to_state,
- ConstIntegratorState state)
-{
- integrator_state_copy_only(kg, to_state, state);
-
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0;
-}
-
-ccl_device_inline void integrator_shadow_state_copy_only(KernelGlobals kg,
- ConstIntegratorShadowState to_state,
- ConstIntegratorShadowState state)
-{
- int index;
-
- /* Rely on the compiler to optimize out unused assignments and `while(false)`'s. */
-
-# define KERNEL_STRUCT_BEGIN(name) \
- index = 0; \
- do {
-
-# define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) \
- if (kernel_integrator_state.parent_struct.name != nullptr) { \
- kernel_integrator_state.parent_struct.name[to_state] = \
- kernel_integrator_state.parent_struct.name[state]; \
- }
-
-# define KERNEL_STRUCT_ARRAY_MEMBER(parent_struct, type, name, feature) \
- if (kernel_integrator_state.parent_struct[index].name != nullptr) { \
- kernel_integrator_state.parent_struct[index].name[to_state] = \
- kernel_integrator_state.parent_struct[index].name[state]; \
- }
-
-# define KERNEL_STRUCT_END(name) \
- } \
- while (false) \
- ;
-
-# define KERNEL_STRUCT_END_ARRAY(name, cpu_array_size, gpu_array_size) \
- ++index; \
- } \
- while (index < gpu_array_size) \
- ;
-
-# define KERNEL_STRUCT_VOLUME_STACK_SIZE kernel_data.volume_stack_size
-
-# include "kernel/integrator/integrator_shadow_state_template.h"
-
-# undef KERNEL_STRUCT_BEGIN
-# undef KERNEL_STRUCT_MEMBER
-# undef KERNEL_STRUCT_ARRAY_MEMBER
-# undef KERNEL_STRUCT_END
-# undef KERNEL_STRUCT_END_ARRAY
-# undef KERNEL_STRUCT_VOLUME_STACK_SIZE
-}
-
-ccl_device_inline void integrator_shadow_state_move(KernelGlobals kg,
- ConstIntegratorState to_state,
- ConstIntegratorState state)
-{
- integrator_shadow_state_copy_only(kg, to_state, state);
-
- INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0;
-}
-
-#endif
-
-/* NOTE: Leaves kernel scheduling information untouched. Use INIT semantic for one of the paths
- * after this function. */
-ccl_device_inline void integrator_state_shadow_catcher_split(KernelGlobals kg,
- IntegratorState state)
-{
-#if defined(__KERNEL_GPU__)
- ConstIntegratorState to_state = atomic_fetch_and_add_uint32(
- &kernel_integrator_state.next_main_path_index[0], 1);
-
- integrator_state_copy_only(kg, to_state, state);
-#else
- IntegratorStateCPU *ccl_restrict to_state = state + 1;
-
- /* Only copy the required subset, since shadow intersections are big and irrelevant here. */
- to_state->path = state->path;
- to_state->ray = state->ray;
- to_state->isect = state->isect;
- integrator_state_copy_volume_stack(kg, to_state, state);
-#endif
-
- INTEGRATOR_STATE_WRITE(to_state, path, flag) |= PATH_RAY_SHADOW_CATCHER_PASS;
-}
-
-#ifdef __KERNEL_CPU__
-ccl_device_inline int integrator_state_bounce(ConstIntegratorState state, const int)
-{
- return INTEGRATOR_STATE(state, path, bounce);
-}
-
-ccl_device_inline int integrator_state_bounce(ConstIntegratorShadowState state, const int)
-{
- return INTEGRATOR_STATE(state, shadow_path, bounce);
-}
-
-ccl_device_inline int integrator_state_diffuse_bounce(ConstIntegratorState state, const int)
-{
- return INTEGRATOR_STATE(state, path, diffuse_bounce);
-}
-
-ccl_device_inline int integrator_state_diffuse_bounce(ConstIntegratorShadowState state, const int)
-{
- return INTEGRATOR_STATE(state, shadow_path, diffuse_bounce);
-}
-
-ccl_device_inline int integrator_state_glossy_bounce(ConstIntegratorState state, const int)
-{
- return INTEGRATOR_STATE(state, path, glossy_bounce);
-}
-
-ccl_device_inline int integrator_state_glossy_bounce(ConstIntegratorShadowState state, const int)
-{
- return INTEGRATOR_STATE(state, shadow_path, glossy_bounce);
-}
-
-ccl_device_inline int integrator_state_transmission_bounce(ConstIntegratorState state, const int)
-{
- return INTEGRATOR_STATE(state, path, transmission_bounce);
-}
-
-ccl_device_inline int integrator_state_transmission_bounce(ConstIntegratorShadowState state,
- const int)
-{
- return INTEGRATOR_STATE(state, shadow_path, transmission_bounce);
-}
-
-ccl_device_inline int integrator_state_transparent_bounce(ConstIntegratorState state, const int)
-{
- return INTEGRATOR_STATE(state, path, transparent_bounce);
-}
-
-ccl_device_inline int integrator_state_transparent_bounce(ConstIntegratorShadowState state,
- const int)
-{
- return INTEGRATOR_STATE(state, shadow_path, transparent_bounce);
-}
-#else
-ccl_device_inline int integrator_state_bounce(ConstIntegratorShadowState state,
- const uint32_t path_flag)
-{
- return (path_flag & PATH_RAY_SHADOW) ? INTEGRATOR_STATE(state, shadow_path, bounce) :
- INTEGRATOR_STATE(state, path, bounce);
-}
-
-ccl_device_inline int integrator_state_diffuse_bounce(ConstIntegratorShadowState state,
- const uint32_t path_flag)
-{
- return (path_flag & PATH_RAY_SHADOW) ? INTEGRATOR_STATE(state, shadow_path, diffuse_bounce) :
- INTEGRATOR_STATE(state, path, diffuse_bounce);
-}
-
-ccl_device_inline int integrator_state_glossy_bounce(ConstIntegratorShadowState state,
- const uint32_t path_flag)
-{
- return (path_flag & PATH_RAY_SHADOW) ? INTEGRATOR_STATE(state, shadow_path, glossy_bounce) :
- INTEGRATOR_STATE(state, path, glossy_bounce);
-}
-
-ccl_device_inline int integrator_state_transmission_bounce(ConstIntegratorShadowState state,
- const uint32_t path_flag)
-{
- return (path_flag & PATH_RAY_SHADOW) ?
- INTEGRATOR_STATE(state, shadow_path, transmission_bounce) :
- INTEGRATOR_STATE(state, path, transmission_bounce);
-}
-
-ccl_device_inline int integrator_state_transparent_bounce(ConstIntegratorShadowState state,
- const uint32_t path_flag)
-{
- return (path_flag & PATH_RAY_SHADOW) ? INTEGRATOR_STATE(state, shadow_path, transparent_bounce) :
- INTEGRATOR_STATE(state, path, transparent_bounce);
-}
-#endif
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_subsurface.h b/intern/cycles/kernel/integrator/integrator_subsurface.h
deleted file mode 100644
index e3bf9db80f7..00000000000
--- a/intern/cycles/kernel/integrator/integrator_subsurface.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_path_state.h"
-#include "kernel/kernel_projection.h"
-#include "kernel/kernel_shader.h"
-
-#include "kernel/bvh/bvh.h"
-
-#include "kernel/closure/alloc.h"
-#include "kernel/closure/bsdf_diffuse.h"
-#include "kernel/closure/bsdf_principled_diffuse.h"
-#include "kernel/closure/bssrdf.h"
-#include "kernel/closure/volume.h"
-
-#include "kernel/integrator/integrator_intersect_volume_stack.h"
-#include "kernel/integrator/integrator_subsurface_disk.h"
-#include "kernel/integrator/integrator_subsurface_random_walk.h"
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef __SUBSURFACE__
-
-ccl_device int subsurface_bounce(KernelGlobals kg,
- IntegratorState state,
- ccl_private ShaderData *sd,
- ccl_private const ShaderClosure *sc)
-{
- /* We should never have two consecutive BSSRDF bounces, the second one should
- * be converted to a diffuse BSDF to avoid this. */
- kernel_assert(!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_DIFFUSE_ANCESTOR));
-
- /* Setup path state for intersect_subsurface kernel. */
- ccl_private const Bssrdf *bssrdf = (ccl_private const Bssrdf *)sc;
-
- /* Setup ray into surface. */
- INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
- INTEGRATOR_STATE_WRITE(state, ray, D) = bssrdf->N;
- INTEGRATOR_STATE_WRITE(state, ray, t) = FLT_MAX;
- INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
- INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_zero_compact();
-
- /* Pass along object info, reusing isect to save memory. */
- INTEGRATOR_STATE_WRITE(state, subsurface, Ng) = sd->Ng;
- INTEGRATOR_STATE_WRITE(state, isect, object) = sd->object;
-
- uint32_t path_flag = (INTEGRATOR_STATE(state, path, flag) & ~PATH_RAY_CAMERA) |
- ((sc->type == CLOSURE_BSSRDF_BURLEY_ID) ? PATH_RAY_SUBSURFACE_DISK :
- PATH_RAY_SUBSURFACE_RANDOM_WALK);
-
- /* Compute weight, optionally including Fresnel from entry point. */
- float3 weight = shader_bssrdf_sample_weight(sd, sc);
-# ifdef __PRINCIPLED__
- if (bssrdf->roughness != FLT_MAX) {
- path_flag |= PATH_RAY_SUBSURFACE_USE_FRESNEL;
- }
-# endif
-
- INTEGRATOR_STATE_WRITE(state, path, throughput) *= weight;
- INTEGRATOR_STATE_WRITE(state, path, flag) = path_flag;
-
- /* Advance random number offset for bounce. */
- INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
- if (INTEGRATOR_STATE(state, path, bounce) == 0) {
- INTEGRATOR_STATE_WRITE(state, path, diffuse_glossy_ratio) = one_float3();
- }
- }
-
- /* Pass BSSRDF parameters. */
- INTEGRATOR_STATE_WRITE(state, subsurface, albedo) = bssrdf->albedo;
- INTEGRATOR_STATE_WRITE(state, subsurface, radius) = bssrdf->radius;
- INTEGRATOR_STATE_WRITE(state, subsurface, anisotropy) = bssrdf->anisotropy;
-
- return LABEL_SUBSURFACE_SCATTER;
-}
-
-ccl_device void subsurface_shader_data_setup(KernelGlobals kg,
- IntegratorState state,
- ccl_private ShaderData *sd,
- const uint32_t path_flag)
-{
- /* Get bump mapped normal from shader evaluation at exit point. */
- float3 N = sd->N;
- if (sd->flag & SD_HAS_BSSRDF_BUMP) {
- N = shader_bssrdf_normal(sd);
- }
-
- /* Setup diffuse BSDF at the exit point. This replaces shader_eval_surface. */
- sd->flag &= ~SD_CLOSURE_FLAGS;
- sd->num_closure = 0;
- sd->num_closure_left = kernel_data.max_closures;
-
- const float3 weight = one_float3();
-
-# ifdef __PRINCIPLED__
- if (path_flag & PATH_RAY_SUBSURFACE_USE_FRESNEL) {
- ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc(
- sd, sizeof(PrincipledDiffuseBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
- bsdf->roughness = FLT_MAX;
- sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_LAMBERT_EXIT);
- }
- }
- else
-# endif /* __PRINCIPLED__ */
- {
- ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc(
- sd, sizeof(DiffuseBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
- sd->flag |= bsdf_diffuse_setup(bsdf);
- }
- }
-}
-
-ccl_device_inline bool subsurface_scatter(KernelGlobals kg, IntegratorState state)
-{
- RNGState rng_state;
- path_state_rng_load(state, &rng_state);
-
- Ray ray ccl_optional_struct_init;
- LocalIntersection ss_isect ccl_optional_struct_init;
-
- if (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_SUBSURFACE_RANDOM_WALK) {
- if (!subsurface_random_walk(kg, state, rng_state, ray, ss_isect)) {
- return false;
- }
- }
- else {
- if (!subsurface_disk(kg, state, rng_state, ray, ss_isect)) {
- return false;
- }
- }
-
-# ifdef __VOLUME__
- /* Update volume stack if needed. */
- if (kernel_data.integrator.use_volumes) {
- const int object = ss_isect.hits[0].object;
- const int object_flag = kernel_tex_fetch(__object_flag, object);
-
- if (object_flag & SD_OBJECT_INTERSECTS_VOLUME) {
- float3 P = INTEGRATOR_STATE(state, ray, P);
- const float3 Ng = INTEGRATOR_STATE(state, subsurface, Ng);
- const float3 offset_P = ray_offset(P, -Ng);
-
- integrator_volume_stack_update_for_subsurface(kg, state, offset_P, ray.P);
- }
- }
-# endif /* __VOLUME__ */
-
- /* Pretend ray is coming from the outside towards the exit point. This ensures
- * correct front/back facing normals.
- * TODO: find a more elegant solution? */
- ray.P += ray.D * ray.t * 2.0f;
- ray.D = -ray.D;
-
- integrator_state_write_isect(kg, state, &ss_isect.hits[0]);
- integrator_state_write_ray(kg, state, &ray);
-
- /* Advance random number offset for bounce. */
- INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
-
- const int shader = intersection_get_shader(kg, &ss_isect.hits[0]);
- const int shader_flags = kernel_tex_fetch(__shaders, shader).flags;
- if (shader_flags & SD_HAS_RAYTRACE) {
- INTEGRATOR_PATH_NEXT_SORTED(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
- DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE,
- shader);
- }
- else {
- INTEGRATOR_PATH_NEXT_SORTED(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
- DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE,
- shader);
- }
-
- return true;
-}
-
-#endif /* __SUBSURFACE__ */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_subsurface_disk.h b/intern/cycles/kernel/integrator/integrator_subsurface_disk.h
deleted file mode 100644
index e1cce13fb30..00000000000
--- a/intern/cycles/kernel/integrator/integrator_subsurface_disk.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* BSSRDF using disk based importance sampling.
- *
- * BSSRDF Importance Sampling, SIGGRAPH 2013
- * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf
- */
-
-ccl_device_inline float3 subsurface_disk_eval(const float3 radius, float disk_r, float r)
-{
- const float3 eval = bssrdf_eval(radius, r);
- const float pdf = bssrdf_pdf(radius, disk_r);
- return (pdf > 0.0f) ? eval / pdf : zero_float3();
-}
-
-/* Subsurface scattering step, from a point on the surface to other
- * nearby points on the same object. */
-ccl_device_inline bool subsurface_disk(KernelGlobals kg,
- IntegratorState state,
- RNGState rng_state,
- ccl_private Ray &ray,
- ccl_private LocalIntersection &ss_isect)
-
-{
- float disk_u, disk_v;
- path_state_rng_2D(kg, &rng_state, PRNG_BSDF_U, &disk_u, &disk_v);
-
- /* Read shading point info from integrator state. */
- const float3 P = INTEGRATOR_STATE(state, ray, P);
- const float ray_dP = INTEGRATOR_STATE(state, ray, dP);
- const float time = INTEGRATOR_STATE(state, ray, time);
- const float3 Ng = INTEGRATOR_STATE(state, subsurface, Ng);
- const int object = INTEGRATOR_STATE(state, isect, object);
-
- /* Read subsurface scattering parameters. */
- const float3 radius = INTEGRATOR_STATE(state, subsurface, radius);
-
- /* Pick random axis in local frame and point on disk. */
- float3 disk_N, disk_T, disk_B;
- float pick_pdf_N, pick_pdf_T, pick_pdf_B;
-
- disk_N = Ng;
- make_orthonormals(disk_N, &disk_T, &disk_B);
-
- if (disk_v < 0.5f) {
- pick_pdf_N = 0.5f;
- pick_pdf_T = 0.25f;
- pick_pdf_B = 0.25f;
- disk_v *= 2.0f;
- }
- else if (disk_v < 0.75f) {
- float3 tmp = disk_N;
- disk_N = disk_T;
- disk_T = tmp;
- pick_pdf_N = 0.25f;
- pick_pdf_T = 0.5f;
- pick_pdf_B = 0.25f;
- disk_v = (disk_v - 0.5f) * 4.0f;
- }
- else {
- float3 tmp = disk_N;
- disk_N = disk_B;
- disk_B = tmp;
- pick_pdf_N = 0.25f;
- pick_pdf_T = 0.25f;
- pick_pdf_B = 0.5f;
- disk_v = (disk_v - 0.75f) * 4.0f;
- }
-
- /* Sample point on disk. */
- float phi = M_2PI_F * disk_v;
- float disk_height, disk_r;
-
- bssrdf_sample(radius, disk_u, &disk_r, &disk_height);
-
- float3 disk_P = (disk_r * cosf(phi)) * disk_T + (disk_r * sinf(phi)) * disk_B;
-
- /* Create ray. */
- ray.P = P + disk_N * disk_height + disk_P;
- ray.D = -disk_N;
- ray.t = 2.0f * disk_height;
- ray.dP = ray_dP;
- ray.dD = differential_zero_compact();
- ray.time = time;
-
- /* Intersect with the same object. if multiple intersections are found it
- * will use at most BSSRDF_MAX_HITS hits, a random subset of all hits. */
- uint lcg_state = lcg_state_init(
- rng_state.rng_hash, rng_state.rng_offset, rng_state.sample, 0x68bc21eb);
- const int max_hits = BSSRDF_MAX_HITS;
-
- scene_intersect_local(kg, &ray, &ss_isect, object, &lcg_state, max_hits);
- const int num_eval_hits = min(ss_isect.num_hits, max_hits);
- if (num_eval_hits == 0) {
- return false;
- }
-
- /* Sort for consistent renders between CPU and GPU, independent of the BVH
- * traversal algorithm. */
- sort_intersections_and_normals(ss_isect.hits, ss_isect.Ng, num_eval_hits);
-
- float3 weights[BSSRDF_MAX_HITS]; /* TODO: zero? */
- float sum_weights = 0.0f;
-
- for (int hit = 0; hit < num_eval_hits; hit++) {
- /* Quickly retrieve P and Ng without setting up ShaderData. */
- const float3 hit_P = ray.P + ray.D * ss_isect.hits[hit].t;
-
- /* Get geometric normal. */
- const int object = ss_isect.hits[hit].object;
- const int object_flag = kernel_tex_fetch(__object_flag, object);
- float3 hit_Ng = ss_isect.Ng[hit];
- if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
- hit_Ng = -hit_Ng;
- }
-
- if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- Transform itfm;
- object_fetch_transform_motion_test(kg, object, time, &itfm);
- hit_Ng = normalize(transform_direction_transposed(&itfm, hit_Ng));
- }
-
- /* Probability densities for local frame axes. */
- const float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng));
- const float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng));
- const float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng));
-
- /* Multiple importance sample between 3 axes, power heuristic
- * found to be slightly better than balance heuristic. pdf_N
- * in the MIS weight and denominator cancelled out. */
- float w = pdf_N / (sqr(pdf_N) + sqr(pdf_T) + sqr(pdf_B));
- if (ss_isect.num_hits > max_hits) {
- w *= ss_isect.num_hits / (float)max_hits;
- }
-
- /* Real distance to sampled point. */
- const float r = len(hit_P - P);
-
- /* Evaluate profiles. */
- const float3 weight = subsurface_disk_eval(radius, disk_r, r) * w;
-
- /* Store result. */
- ss_isect.Ng[hit] = hit_Ng;
- weights[hit] = weight;
- sum_weights += average(fabs(weight));
- }
-
- if (sum_weights == 0.0f) {
- return false;
- }
-
- /* Use importance resampling, sampling one of the hits proportional to weight. */
- const float r = lcg_step_float(&lcg_state) * sum_weights;
- float partial_sum = 0.0f;
-
- for (int hit = 0; hit < num_eval_hits; hit++) {
- const float3 weight = weights[hit];
- const float sample_weight = average(fabs(weight));
- float next_sum = partial_sum + sample_weight;
-
- if (r < next_sum) {
- /* Return exit point. */
- INTEGRATOR_STATE_WRITE(state, path, throughput) *= weight * sum_weights / sample_weight;
-
- ss_isect.hits[0] = ss_isect.hits[hit];
- ss_isect.Ng[0] = ss_isect.Ng[hit];
-
- ray.P = ray.P + ray.D * ss_isect.hits[hit].t;
- ray.D = ss_isect.Ng[hit];
- ray.t = 1.0f;
- return true;
- }
-
- partial_sum = next_sum;
- }
-
- return false;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_subsurface_random_walk.h b/intern/cycles/kernel/integrator/integrator_subsurface_random_walk.h
deleted file mode 100644
index 2ab6d0961e3..00000000000
--- a/intern/cycles/kernel/integrator/integrator_subsurface_random_walk.h
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "kernel/kernel_projection.h"
-
-#include "kernel/bvh/bvh.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Random walk subsurface scattering.
- *
- * "Practical and Controllable Subsurface Scattering for Production Path
- * Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */
-
-/* Support for anisotropy from:
- * "Path Traced Subsurface Scattering using Anisotropic Phase Functions
- * and Non-Exponential Free Flights".
- * Magnus Wrenninge, Ryusuke Villemin, Christophe Hery.
- * https://graphics.pixar.com/library/PathTracedSubsurface/ */
-
-ccl_device void subsurface_random_walk_remap(const float albedo,
- const float d,
- float g,
- ccl_private float *sigma_t,
- ccl_private float *alpha)
-{
- /* Compute attenuation and scattering coefficients from albedo. */
- const float g2 = g * g;
- const float g3 = g2 * g;
- const float g4 = g3 * g;
- const float g5 = g4 * g;
- const float g6 = g5 * g;
- const float g7 = g6 * g;
-
- const float A = 1.8260523782f + -1.28451056436f * g + -1.79904629312f * g2 +
- 9.19393289202f * g3 + -22.8215585862f * g4 + 32.0234874259f * g5 +
- -23.6264803333f * g6 + 7.21067002658f * g7;
- const float B = 4.98511194385f +
- 0.127355959438f *
- expf(31.1491581433f * g + -201.847017512f * g2 + 841.576016723f * g3 +
- -2018.09288505f * g4 + 2731.71560286f * g5 + -1935.41424244f * g6 +
- 559.009054474f * g7);
- const float C = 1.09686102424f + -0.394704063468f * g + 1.05258115941f * g2 +
- -8.83963712726f * g3 + 28.8643230661f * g4 + -46.8802913581f * g5 +
- 38.5402837518f * g6 + -12.7181042538f * g7;
- const float D = 0.496310210422f + 0.360146581622f * g + -2.15139309747f * g2 +
- 17.8896899217f * g3 + -55.2984010333f * g4 + 82.065982243f * g5 +
- -58.5106008578f * g6 + 15.8478295021f * g7;
- const float E = 4.23190299701f +
- 0.00310603949088f *
- expf(76.7316253952f * g + -594.356773233f * g2 + 2448.8834203f * g3 +
- -5576.68528998f * g4 + 7116.60171912f * g5 + -4763.54467887f * g6 +
- 1303.5318055f * g7);
- const float F = 2.40602999408f + -2.51814844609f * g + 9.18494908356f * g2 +
- -79.2191708682f * g3 + 259.082868209f * g4 + -403.613804597f * g5 +
- 302.85712436f * g6 + -87.4370473567f * g7;
-
- const float blend = powf(albedo, 0.25f);
-
- *alpha = (1.0f - blend) * A * powf(atanf(B * albedo), C) +
- blend * D * powf(atanf(E * albedo), F);
- *alpha = clamp(*alpha, 0.0f, 0.999999f); // because of numerical precision
-
- float sigma_t_prime = 1.0f / fmaxf(d, 1e-16f);
- *sigma_t = sigma_t_prime / (1.0f - g);
-}
-
-ccl_device void subsurface_random_walk_coefficients(const float3 albedo,
- const float3 radius,
- const float anisotropy,
- ccl_private float3 *sigma_t,
- ccl_private float3 *alpha,
- ccl_private float3 *throughput)
-{
- float sigma_t_x, sigma_t_y, sigma_t_z;
- float alpha_x, alpha_y, alpha_z;
-
- subsurface_random_walk_remap(albedo.x, radius.x, anisotropy, &sigma_t_x, &alpha_x);
- subsurface_random_walk_remap(albedo.y, radius.y, anisotropy, &sigma_t_y, &alpha_y);
- subsurface_random_walk_remap(albedo.z, radius.z, anisotropy, &sigma_t_z, &alpha_z);
-
- /* Throughput already contains closure weight at this point, which includes the
- * albedo, as well as closure mixing and Fresnel weights. Divide out the albedo
- * which will be added through scattering. */
- *throughput = safe_divide_color(*throughput, albedo);
-
- /* With low albedo values (like 0.025) we get diffusion_length 1.0 and
- * infinite phase functions. To avoid a sharp discontinuity as we go from
- * such values to 0.0, increase alpha and reduce the throughput to compensate. */
- const float min_alpha = 0.2f;
- if (alpha_x < min_alpha) {
- (*throughput).x *= alpha_x / min_alpha;
- alpha_x = min_alpha;
- }
- if (alpha_y < min_alpha) {
- (*throughput).y *= alpha_y / min_alpha;
- alpha_y = min_alpha;
- }
- if (alpha_z < min_alpha) {
- (*throughput).z *= alpha_z / min_alpha;
- alpha_z = min_alpha;
- }
-
- *sigma_t = make_float3(sigma_t_x, sigma_t_y, sigma_t_z);
- *alpha = make_float3(alpha_x, alpha_y, alpha_z);
-}
-
-/* References for Dwivedi sampling:
- *
- * [1] "A Zero-variance-based Sampling Scheme for Monte Carlo Subsurface Scattering"
- * by Jaroslav Křivánek and Eugene d'Eon (SIGGRAPH 2014)
- * https://cgg.mff.cuni.cz/~jaroslav/papers/2014-zerovar/
- *
- * [2] "Improving the Dwivedi Sampling Scheme"
- * by Johannes Meng, Johannes Hanika, and Carsten Dachsbacher (EGSR 2016)
- * https://cg.ivd.kit.edu/1951.php
- *
- * [3] "Zero-Variance Theory for Efficient Subsurface Scattering"
- * by Eugene d'Eon and Jaroslav Křivánek (SIGGRAPH 2020)
- * https://iliyan.com/publications/RenderingCourse2020
- */
-
-ccl_device_forceinline float eval_phase_dwivedi(float v, float phase_log, float cos_theta)
-{
- /* Eq. 9 from [2] using precomputed log((v + 1) / (v - 1)) */
- return 1.0f / ((v - cos_theta) * phase_log);
-}
-
-ccl_device_forceinline float sample_phase_dwivedi(float v, float phase_log, float rand)
-{
- /* Based on Eq. 10 from [2]: `v - (v + 1) * pow((v - 1) / (v + 1), rand)`
- * Since we're already pre-computing `phase_log = log((v + 1) / (v - 1))` for the evaluation,
- * we can implement the power function like this. */
- return v - (v + 1.0f) * expf(-rand * phase_log);
-}
-
-ccl_device_forceinline float diffusion_length_dwivedi(float alpha)
-{
- /* Eq. 67 from [3] */
- return 1.0f / sqrtf(1.0f - powf(alpha, 2.44294f - 0.0215813f * alpha + 0.578637f / alpha));
-}
-
-ccl_device_forceinline float3 direction_from_cosine(float3 D, float cos_theta, float randv)
-{
- float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta);
- float phi = M_2PI_F * randv;
- float3 dir = make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cos_theta);
-
- float3 T, B;
- make_orthonormals(D, &T, &B);
- return dir.x * T + dir.y * B + dir.z * D;
-}
-
-ccl_device_forceinline float3 subsurface_random_walk_pdf(float3 sigma_t,
- float t,
- bool hit,
- ccl_private float3 *transmittance)
-{
- float3 T = volume_color_transmittance(sigma_t, t);
- if (transmittance) {
- *transmittance = T;
- }
- return hit ? T : sigma_t * T;
-}
-
-/* Define the below variable to get the similarity code active,
- * and the value represents the cutoff level */
-#define SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL 9
-
-ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
- IntegratorState state,
- RNGState rng_state,
- ccl_private Ray &ray,
- ccl_private LocalIntersection &ss_isect)
-{
- float bssrdf_u, bssrdf_v;
- path_state_rng_2D(kg, &rng_state, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
-
- const float3 P = INTEGRATOR_STATE(state, ray, P);
- const float3 N = INTEGRATOR_STATE(state, ray, D);
- const float ray_dP = INTEGRATOR_STATE(state, ray, dP);
- const float time = INTEGRATOR_STATE(state, ray, time);
- const float3 Ng = INTEGRATOR_STATE(state, subsurface, Ng);
- const int object = INTEGRATOR_STATE(state, isect, object);
-
- /* Sample diffuse surface scatter into the object. */
- float3 D;
- float pdf;
- sample_cos_hemisphere(-N, bssrdf_u, bssrdf_v, &D, &pdf);
- if (dot(-Ng, D) <= 0.0f) {
- return false;
- }
-
- /* Setup ray. */
- ray.P = ray_offset(P, -Ng);
- ray.D = D;
- ray.t = FLT_MAX;
- ray.time = time;
- ray.dP = ray_dP;
- ray.dD = differential_zero_compact();
-
-#ifndef __KERNEL_OPTIX__
- /* Compute or fetch object transforms. */
- Transform ob_itfm ccl_optional_struct_init;
- Transform ob_tfm = object_fetch_transform_motion_test(kg, object, time, &ob_itfm);
-#endif
-
- /* Convert subsurface to volume coefficients.
- * The single-scattering albedo is named alpha to avoid confusion with the surface albedo. */
- const float3 albedo = INTEGRATOR_STATE(state, subsurface, albedo);
- const float3 radius = INTEGRATOR_STATE(state, subsurface, radius);
- const float anisotropy = INTEGRATOR_STATE(state, subsurface, anisotropy);
-
- float3 sigma_t, alpha;
- float3 throughput = INTEGRATOR_STATE_WRITE(state, path, throughput);
- subsurface_random_walk_coefficients(albedo, radius, anisotropy, &sigma_t, &alpha, &throughput);
- float3 sigma_s = sigma_t * alpha;
-
- /* Theoretically it should be better to use the exact alpha for the channel we're sampling at
- * each bounce, but in practice there doesn't seem to be a noticeable difference in exchange
- * for making the code significantly more complex and slower (if direction sampling depends on
- * the sampled channel, we need to compute its PDF per-channel and consider it for MIS later on).
- *
- * Since the strength of the guided sampling increases as alpha gets lower, using a value that
- * is too low results in fireflies while one that's too high just gives a bit more noise.
- * Therefore, the code here uses the highest of the three albedos to be safe. */
- const float diffusion_length = diffusion_length_dwivedi(max3(alpha));
-
- if (diffusion_length == 1.0f) {
- /* With specific values of alpha the length might become 1, which in asymptotic makes phase to
- * be infinite. After first bounce it will cause throughput to be 0. Do early output, avoiding
- * numerical issues and extra unneeded work. */
- return false;
- }
-
- /* Precompute term for phase sampling. */
- const float phase_log = logf((diffusion_length + 1.0f) / (diffusion_length - 1.0f));
-
- /* Modify state for RNGs, decorrelated from other paths. */
- rng_state.rng_hash = cmj_hash(rng_state.rng_hash + rng_state.rng_offset, 0xdeadbeef);
-
- /* Random walk until we hit the surface again. */
- bool hit = false;
- bool have_opposite_interface = false;
- float opposite_distance = 0.0f;
-
- /* TODO: Disable for `alpha > 0.999` or so? */
- /* Our heuristic, a compromise between guiding and classic. */
- const float guided_fraction = 1.0f - fmaxf(0.5f, powf(fabsf(anisotropy), 0.125f));
-
-#ifdef SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL
- float3 sigma_s_star = sigma_s * (1.0f - anisotropy);
- float3 sigma_t_star = sigma_t - sigma_s + sigma_s_star;
- float3 sigma_t_org = sigma_t;
- float3 sigma_s_org = sigma_s;
- const float anisotropy_org = anisotropy;
- const float guided_fraction_org = guided_fraction;
-#endif
-
- for (int bounce = 0; bounce < BSSRDF_MAX_BOUNCES; bounce++) {
- /* Advance random number offset. */
- rng_state.rng_offset += PRNG_BOUNCE_NUM;
-
-#ifdef SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL
- // shadow with local variables according to depth
- float anisotropy, guided_fraction;
- float3 sigma_s, sigma_t;
- if (bounce <= SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL) {
- anisotropy = anisotropy_org;
- guided_fraction = guided_fraction_org;
- sigma_t = sigma_t_org;
- sigma_s = sigma_s_org;
- }
- else {
- anisotropy = 0.0f;
- guided_fraction = 0.75f; // back to isotropic heuristic from Blender
- sigma_t = sigma_t_star;
- sigma_s = sigma_s_star;
- }
-#endif
-
- /* Sample color channel, use MIS with balance heuristic. */
- float rphase = path_state_rng_1D(kg, &rng_state, PRNG_PHASE_CHANNEL);
- float3 channel_pdf;
- int channel = volume_sample_channel(alpha, throughput, rphase, &channel_pdf);
- float sample_sigma_t = volume_channel_get(sigma_t, channel);
- float randt = path_state_rng_1D(kg, &rng_state, PRNG_SCATTER_DISTANCE);
-
- /* We need the result of the ray-cast to compute the full guided PDF, so just remember the
- * relevant terms to avoid recomputing them later. */
- float backward_fraction = 0.0f;
- float forward_pdf_factor = 0.0f;
- float forward_stretching = 1.0f;
- float backward_pdf_factor = 0.0f;
- float backward_stretching = 1.0f;
-
- /* For the initial ray, we already know the direction, so just do classic distance sampling. */
- if (bounce > 0) {
- /* Decide whether we should use guided or classic sampling. */
- bool guided = (path_state_rng_1D(kg, &rng_state, PRNG_LIGHT_TERMINATE) < guided_fraction);
-
- /* Determine if we want to sample away from the incoming interface.
- * This only happens if we found a nearby opposite interface, and the probability for it
- * depends on how close we are to it already.
- * This probability term comes from the recorded presentation of [3]. */
- bool guide_backward = false;
- if (have_opposite_interface) {
- /* Compute distance of the random walk between the tangent plane at the starting point
- * and the assumed opposite interface (the parallel plane that contains the point we
- * found in our ray query for the opposite side). */
- float x = clamp(dot(ray.P - P, -N), 0.0f, opposite_distance);
- backward_fraction = 1.0f /
- (1.0f + expf((opposite_distance - 2.0f * x) / diffusion_length));
- guide_backward = path_state_rng_1D(kg, &rng_state, PRNG_TERMINATE) < backward_fraction;
- }
-
- /* Sample scattering direction. */
- float scatter_u, scatter_v;
- path_state_rng_2D(kg, &rng_state, PRNG_BSDF_U, &scatter_u, &scatter_v);
- float cos_theta;
- float hg_pdf;
- if (guided) {
- cos_theta = sample_phase_dwivedi(diffusion_length, phase_log, scatter_u);
- /* The backwards guiding distribution is just mirrored along `sd->N`, so swapping the
- * sign here is enough to sample from that instead. */
- if (guide_backward) {
- cos_theta = -cos_theta;
- }
- float3 newD = direction_from_cosine(N, cos_theta, scatter_v);
- hg_pdf = single_peaked_henyey_greenstein(dot(ray.D, newD), anisotropy);
- ray.D = newD;
- }
- else {
- float3 newD = henyey_greenstrein_sample(ray.D, anisotropy, scatter_u, scatter_v, &hg_pdf);
- cos_theta = dot(newD, N);
- ray.D = newD;
- }
-
- /* Compute PDF factor caused by phase sampling (as the ratio of guided / classic).
- * Since phase sampling is channel-independent, we can get away with applying a factor
- * to the guided PDF, which implicitly means pulling out the classic PDF term and letting
- * it cancel with an equivalent term in the numerator of the full estimator.
- * For the backward PDF, we again reuse the same probability distribution with a sign swap.
- */
- forward_pdf_factor = M_1_2PI_F * eval_phase_dwivedi(diffusion_length, phase_log, cos_theta) /
- hg_pdf;
- backward_pdf_factor = M_1_2PI_F *
- eval_phase_dwivedi(diffusion_length, phase_log, -cos_theta) / hg_pdf;
-
- /* Prepare distance sampling.
- * For the backwards case, this also needs the sign swapped since now directions against
- * `sd->N` (and therefore with negative cos_theta) are preferred. */
- forward_stretching = (1.0f - cos_theta / diffusion_length);
- backward_stretching = (1.0f + cos_theta / diffusion_length);
- if (guided) {
- sample_sigma_t *= guide_backward ? backward_stretching : forward_stretching;
- }
- }
-
- /* Sample direction along ray. */
- float t = -logf(1.0f - randt) / sample_sigma_t;
-
- /* On the first bounce, we use the ray-cast to check if the opposite side is nearby.
- * If yes, we will later use backwards guided sampling in order to have a decent
- * chance of connecting to it.
- * TODO: Maybe use less than 10 times the mean free path? */
- ray.t = (bounce == 0) ? max(t, 10.0f / (min3(sigma_t))) : t;
- scene_intersect_local(kg, &ray, &ss_isect, object, NULL, 1);
- hit = (ss_isect.num_hits > 0);
-
- if (hit) {
-#ifdef __KERNEL_OPTIX__
- /* t is always in world space with OptiX. */
- ray.t = ss_isect.hits[0].t;
-#else
- /* Compute world space distance to surface hit. */
- float3 D = transform_direction(&ob_itfm, ray.D);
- D = normalize(D) * ss_isect.hits[0].t;
- ray.t = len(transform_direction(&ob_tfm, D));
-#endif
- }
-
- if (bounce == 0) {
- /* Check if we hit the opposite side. */
- if (hit) {
- have_opposite_interface = true;
- opposite_distance = dot(ray.P + ray.t * ray.D - P, -N);
- }
- /* Apart from the opposite side check, we were supposed to only trace up to distance t,
- * so check if there would have been a hit in that case. */
- hit = ray.t < t;
- }
-
- /* Use the distance to the exit point for the throughput update if we found one. */
- if (hit) {
- t = ray.t;
- }
- else if (bounce == 0) {
- /* Restore original position if nothing was hit after the first bounce,
- * without the ray_offset() that was added to avoid self-intersection.
- * Otherwise if that offset is relatively large compared to the scattering
- * radius, we never go back up high enough to exit the surface. */
- ray.P = P;
- }
-
- /* Advance to new scatter location. */
- ray.P += t * ray.D;
-
- float3 transmittance;
- float3 pdf = subsurface_random_walk_pdf(sigma_t, t, hit, &transmittance);
- if (bounce > 0) {
- /* Compute PDF just like we do for classic sampling, but with the stretched sigma_t. */
- float3 guided_pdf = subsurface_random_walk_pdf(forward_stretching * sigma_t, t, hit, NULL);
-
- if (have_opposite_interface) {
- /* First step of MIS: Depending on geometry we might have two methods for guided
- * sampling, so perform MIS between them. */
- float3 back_pdf = subsurface_random_walk_pdf(backward_stretching * sigma_t, t, hit, NULL);
- guided_pdf = mix(
- guided_pdf * forward_pdf_factor, back_pdf * backward_pdf_factor, backward_fraction);
- }
- else {
- /* Just include phase sampling factor otherwise. */
- guided_pdf *= forward_pdf_factor;
- }
-
- /* Now we apply the MIS balance heuristic between the classic and guided sampling. */
- pdf = mix(pdf, guided_pdf, guided_fraction);
- }
-
- /* Finally, we're applying MIS again to combine the three color channels.
- * Altogether, the MIS computation combines up to nine different estimators:
- * {classic, guided, backward_guided} x {r, g, b} */
- throughput *= (hit ? transmittance : sigma_s * transmittance) / dot(channel_pdf, pdf);
-
- if (hit) {
- /* If we hit the surface, we are done. */
- break;
- }
- else if (throughput.x < VOLUME_THROUGHPUT_EPSILON &&
- throughput.y < VOLUME_THROUGHPUT_EPSILON &&
- throughput.z < VOLUME_THROUGHPUT_EPSILON) {
- /* Avoid unnecessary work and precision issue when throughput gets really small. */
- break;
- }
- }
-
- if (hit) {
- kernel_assert(isfinite3_safe(throughput));
- INTEGRATOR_STATE_WRITE(state, path, throughput) = throughput;
- }
-
- return hit;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/intersect_closest.h b/intern/cycles/kernel/integrator/intersect_closest.h
new file mode 100644
index 00000000000..7fb88fc2804
--- /dev/null
+++ b/intern/cycles/kernel/integrator/intersect_closest.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/camera/projection.h"
+
+#include "kernel/integrator/path_state.h"
+#include "kernel/integrator/shadow_catcher.h"
+
+#include "kernel/light/light.h"
+
+#include "kernel/util/differential.h"
+
+#include "kernel/geom/geom.h"
+
+#include "kernel/bvh/bvh.h"
+
+CCL_NAMESPACE_BEGIN
+
+template<uint32_t current_kernel>
+ccl_device_forceinline bool integrator_intersect_terminate(KernelGlobals kg,
+ IntegratorState state,
+ const int shader_flags)
+{
+
+ /* Optional AO bounce termination.
+ * We continue evaluating emissive/transparent surfaces and volumes, similar
+ * to direct lighting. Only if we know there are none can we terminate the
+ * path immediately. */
+ if (path_state_ao_bounce(kg, state)) {
+ if (shader_flags & (SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) {
+ INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+ else if (!integrator_state_volume_stack_is_empty(kg, state)) {
+ INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_AFTER_VOLUME;
+ }
+ else {
+ return true;
+ }
+ }
+
+ /* Load random number state. */
+ RNGState rng_state;
+ path_state_rng_load(state, &rng_state);
+
+ /* We perform path termination in this kernel to avoid launching shade_surface
+ * and evaluating the shader when not needed. Only for emission and transparent
+ * surfaces in front of emission do we need to evaluate the shader, since we
+ * perform MIS as part of indirect rays. */
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+ const float probability = path_state_continuation_probability(kg, state, path_flag);
+
+ if (probability != 1.0f) {
+ const float terminate = path_state_rng_1D(kg, &rng_state, PRNG_TERMINATE);
+
+ if (probability == 0.0f || terminate >= probability) {
+ if (shader_flags & SD_HAS_EMISSION) {
+ /* Mark path to be terminated right after shader evaluation on the surface. */
+ INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE;
+ }
+ else if (!integrator_state_volume_stack_is_empty(kg, state)) {
+ /* TODO: only do this for emissive volumes. */
+ INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_IN_NEXT_VOLUME;
+ }
+ else {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/* Note that current_kernel is a template value since making this a variable
+ * leads to poor performance with CUDA atomics. */
+template<uint32_t current_kernel>
+ccl_device_forceinline void integrator_intersect_shader_next_kernel(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const Intersection *ccl_restrict isect,
+ const int shader,
+ const int shader_flags)
+{
+ /* Note on scheduling.
+ *
+ * When there is no shadow catcher split the scheduling is simple: schedule surface shading with
+ * or without raytrace support, depending on the shader used.
+ *
+ * When there is a shadow catcher split the general idea is to have the following configuration:
+ *
+ * - Schedule surface shading kernel (with corresponding raytrace support) for the ray which
+ * will trace shadow catcher object.
+ *
+ * - When no alpha-over of approximate shadow catcher is needed, schedule surface shading for
+ * the matte ray.
+ *
+ * - Otherwise schedule background shading kernel, so that we have a background to alpha-over
+ * on. The background kernel will then schedule surface shading for the matte ray.
+ *
+ * Note that the splitting leaves kernel and sorting counters as-is, so use INIT semantic for
+ * the matte path. */
+
+ const bool use_raytrace_kernel = (shader_flags & SD_HAS_RAYTRACE);
+
+ if (use_raytrace_kernel) {
+ INTEGRATOR_PATH_NEXT_SORTED(
+ current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
+ }
+ else {
+ INTEGRATOR_PATH_NEXT_SORTED(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
+ }
+
+#ifdef __SHADOW_CATCHER__
+ const int object_flags = intersection_get_object_flags(kg, isect);
+ if (kernel_shadow_catcher_split(kg, state, object_flags)) {
+ if (kernel_data.film.pass_background != PASS_UNUSED && !kernel_data.background.transparent) {
+ INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SHADOW_CATCHER_BACKGROUND;
+
+ INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ }
+ else if (use_raytrace_kernel) {
+ INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
+ }
+ else {
+ INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
+ }
+ }
+#endif
+}
+
+ccl_device void integrator_intersect_closest(KernelGlobals kg, IntegratorState state)
+{
+ PROFILING_INIT(kg, PROFILING_INTERSECT_CLOSEST);
+
+ /* Read ray from integrator state into local memory. */
+ Ray ray ccl_optional_struct_init;
+ integrator_state_read_ray(kg, state, &ray);
+ kernel_assert(ray.t != 0.0f);
+
+ const uint visibility = path_state_ray_visibility(state);
+ const int last_isect_prim = INTEGRATOR_STATE(state, isect, prim);
+ const int last_isect_object = INTEGRATOR_STATE(state, isect, object);
+
+ /* Trick to use short AO rays to approximate indirect light at the end of the path. */
+ if (path_state_ao_bounce(kg, state)) {
+ ray.t = kernel_data.integrator.ao_bounces_distance;
+
+ if (last_isect_object != OBJECT_NONE) {
+ const float object_ao_distance = kernel_tex_fetch(__objects, last_isect_object).ao_distance;
+ if (object_ao_distance != 0.0f) {
+ ray.t = object_ao_distance;
+ }
+ }
+ }
+
+ /* Scene Intersection. */
+ Intersection isect ccl_optional_struct_init;
+ bool hit = scene_intersect(kg, &ray, visibility, &isect);
+
+ /* TODO: remove this and do it in the various intersection functions instead. */
+ if (!hit) {
+ isect.prim = PRIM_NONE;
+ }
+
+ /* Light intersection for MIS. */
+ if (kernel_data.integrator.use_lamp_mis) {
+ /* NOTE: if we make lights visible to camera rays, we'll need to initialize
+ * these in the path_state_init. */
+ const int last_type = INTEGRATOR_STATE(state, isect, type);
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ hit = lights_intersect(
+ kg, &ray, &isect, last_isect_prim, last_isect_object, last_type, path_flag) ||
+ hit;
+ }
+
+ /* Write intersection result into global integrator state memory. */
+ integrator_state_write_isect(kg, state, &isect);
+
+#ifdef __VOLUME__
+ if (!integrator_state_volume_stack_is_empty(kg, state)) {
+ const bool hit_surface = hit && !(isect.type & PRIMITIVE_LAMP);
+ const int shader = (hit_surface) ? intersection_get_shader(kg, &isect) : SHADER_NONE;
+ const int flags = (hit_surface) ? kernel_tex_fetch(__shaders, shader).flags : 0;
+
+ if (!integrator_intersect_terminate<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>(
+ kg, state, flags)) {
+ /* Continue with volume kernel if we are inside a volume, regardless
+ * if we hit anything. */
+ INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
+ }
+ else {
+ INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
+ }
+ return;
+ }
+#endif
+
+ if (hit) {
+ /* Hit a surface, continue with light or surface kernel. */
+ if (isect.type & PRIMITIVE_LAMP) {
+ INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
+ return;
+ }
+ else {
+ /* Hit a surface, continue with surface kernel unless terminated. */
+ const int shader = intersection_get_shader(kg, &isect);
+ const int flags = kernel_tex_fetch(__shaders, shader).flags;
+
+ if (!integrator_intersect_terminate<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>(
+ kg, state, flags)) {
+ integrator_intersect_shader_next_kernel<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>(
+ kg, state, &isect, shader, flags);
+ return;
+ }
+ else {
+ INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
+ return;
+ }
+ }
+ }
+ else {
+ /* Nothing hit, continue with background kernel. */
+ INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ return;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_intersect_shadow.h b/intern/cycles/kernel/integrator/intersect_shadow.h
index 90422445fad..90422445fad 100644
--- a/intern/cycles/kernel/integrator/integrator_intersect_shadow.h
+++ b/intern/cycles/kernel/integrator/intersect_shadow.h
diff --git a/intern/cycles/kernel/integrator/intersect_subsurface.h b/intern/cycles/kernel/integrator/intersect_subsurface.h
new file mode 100644
index 00000000000..27b8e1e5f5a
--- /dev/null
+++ b/intern/cycles/kernel/integrator/intersect_subsurface.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/integrator/subsurface.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device void integrator_intersect_subsurface(KernelGlobals kg, IntegratorState state)
+{
+ PROFILING_INIT(kg, PROFILING_INTERSECT_SUBSURFACE);
+
+#ifdef __SUBSURFACE__
+ if (subsurface_scatter(kg, state)) {
+ return;
+ }
+#endif
+
+ INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/intersect_volume_stack.h b/intern/cycles/kernel/integrator/intersect_volume_stack.h
new file mode 100644
index 00000000000..1c91318ff9c
--- /dev/null
+++ b/intern/cycles/kernel/integrator/intersect_volume_stack.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/bvh/bvh.h"
+#include "kernel/geom/geom.h"
+#include "kernel/integrator/shader_eval.h"
+#include "kernel/integrator/volume_stack.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg,
+ IntegratorState state,
+ const float3 from_P,
+ const float3 to_P)
+{
+ PROFILING_INIT(kg, PROFILING_INTERSECT_VOLUME_STACK);
+
+ ShaderDataTinyStorage stack_sd_storage;
+ ccl_private ShaderData *stack_sd = AS_SHADER_DATA(&stack_sd_storage);
+
+ kernel_assert(kernel_data.integrator.use_volumes);
+
+ Ray volume_ray ccl_optional_struct_init;
+ volume_ray.P = from_P;
+ volume_ray.D = normalize_len(to_P - from_P, &volume_ray.t);
+
+ /* Store to avoid global fetches on every intersection step. */
+ const uint volume_stack_size = kernel_data.volume_stack_size;
+
+#ifdef __VOLUME_RECORD_ALL__
+ Intersection hits[2 * MAX_VOLUME_STACK_SIZE + 1];
+ uint num_hits = scene_intersect_volume_all(
+ kg, &volume_ray, hits, 2 * volume_stack_size, PATH_RAY_ALL_VISIBILITY);
+ if (num_hits > 0) {
+ Intersection *isect = hits;
+
+ qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
+
+ for (uint hit = 0; hit < num_hits; ++hit, ++isect) {
+ shader_setup_from_ray(kg, stack_sd, &volume_ray, isect);
+ volume_stack_enter_exit(kg, state, stack_sd);
+ }
+ }
+#else
+ Intersection isect;
+ int step = 0;
+ while (step < 2 * volume_stack_size &&
+ scene_intersect_volume(kg, &volume_ray, &isect, PATH_RAY_ALL_VISIBILITY)) {
+ shader_setup_from_ray(kg, stack_sd, &volume_ray, &isect);
+ volume_stack_enter_exit(kg, state, stack_sd);
+
+ /* Move ray forward. */
+ volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
+ if (volume_ray.t != FLT_MAX) {
+ volume_ray.D = normalize_len(to_P - volume_ray.P, &volume_ray.t);
+ }
+ ++step;
+ }
+#endif
+}
+
+ccl_device void integrator_intersect_volume_stack(KernelGlobals kg, IntegratorState state)
+{
+ PROFILING_INIT(kg, PROFILING_INTERSECT_VOLUME_STACK);
+
+ ShaderDataTinyStorage stack_sd_storage;
+ ccl_private ShaderData *stack_sd = AS_SHADER_DATA(&stack_sd_storage);
+
+ Ray volume_ray ccl_optional_struct_init;
+ integrator_state_read_ray(kg, state, &volume_ray);
+ volume_ray.t = FLT_MAX;
+
+ const uint visibility = (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_ALL_VISIBILITY);
+ int stack_index = 0, enclosed_index = 0;
+
+ /* Write background shader. */
+ if (kernel_data.background.volume_shader != SHADER_NONE) {
+ const VolumeStack new_entry = {OBJECT_NONE, kernel_data.background.volume_shader};
+ integrator_state_write_volume_stack(state, stack_index, new_entry);
+ stack_index++;
+ }
+
+ /* Store to avoid global fetches on every intersection step. */
+ const uint volume_stack_size = kernel_data.volume_stack_size;
+
+#ifdef __VOLUME_RECORD_ALL__
+ Intersection hits[2 * MAX_VOLUME_STACK_SIZE + 1];
+ uint num_hits = scene_intersect_volume_all(
+ kg, &volume_ray, hits, 2 * volume_stack_size, visibility);
+ if (num_hits > 0) {
+ int enclosed_volumes[MAX_VOLUME_STACK_SIZE];
+ Intersection *isect = hits;
+
+ qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
+
+ for (uint hit = 0; hit < num_hits; ++hit, ++isect) {
+ shader_setup_from_ray(kg, stack_sd, &volume_ray, isect);
+ if (stack_sd->flag & SD_BACKFACING) {
+ bool need_add = true;
+ for (int i = 0; i < enclosed_index && need_add; ++i) {
+ /* If ray exited the volume and never entered to that volume
+ * it means that camera is inside such a volume.
+ */
+ if (enclosed_volumes[i] == stack_sd->object) {
+ need_add = false;
+ }
+ }
+ for (int i = 0; i < stack_index && need_add; ++i) {
+ /* Don't add intersections twice. */
+ VolumeStack entry = integrator_state_read_volume_stack(state, i);
+ if (entry.object == stack_sd->object) {
+ need_add = false;
+ break;
+ }
+ }
+ if (need_add && stack_index < volume_stack_size - 1) {
+ const VolumeStack new_entry = {stack_sd->object, stack_sd->shader};
+ integrator_state_write_volume_stack(state, stack_index, new_entry);
+ ++stack_index;
+ }
+ }
+ else {
+ /* If ray from camera enters the volume, this volume shouldn't
+ * be added to the stack on exit.
+ */
+ enclosed_volumes[enclosed_index++] = stack_sd->object;
+ }
+ }
+ }
+#else
+ /* CUDA does not support definition of a variable size arrays, so use the maximum possible. */
+ int enclosed_volumes[MAX_VOLUME_STACK_SIZE];
+ int step = 0;
+
+ while (stack_index < volume_stack_size - 1 && enclosed_index < volume_stack_size - 1 &&
+ step < 2 * volume_stack_size) {
+ Intersection isect;
+ if (!scene_intersect_volume(kg, &volume_ray, &isect, visibility)) {
+ break;
+ }
+
+ shader_setup_from_ray(kg, stack_sd, &volume_ray, &isect);
+ if (stack_sd->flag & SD_BACKFACING) {
+ /* If ray exited the volume and never entered to that volume
+ * it means that camera is inside such a volume.
+ */
+ bool need_add = true;
+ for (int i = 0; i < enclosed_index && need_add; ++i) {
+ /* If ray exited the volume and never entered to that volume
+ * it means that camera is inside such a volume.
+ */
+ if (enclosed_volumes[i] == stack_sd->object) {
+ need_add = false;
+ }
+ }
+ for (int i = 0; i < stack_index && need_add; ++i) {
+ /* Don't add intersections twice. */
+ VolumeStack entry = integrator_state_read_volume_stack(state, i);
+ if (entry.object == stack_sd->object) {
+ need_add = false;
+ break;
+ }
+ }
+ if (need_add) {
+ const VolumeStack new_entry = {stack_sd->object, stack_sd->shader};
+ integrator_state_write_volume_stack(state, stack_index, new_entry);
+ ++stack_index;
+ }
+ }
+ else {
+ /* If ray from camera enters the volume, this volume shouldn't
+ * be added to the stack on exit.
+ */
+ enclosed_volumes[enclosed_index++] = stack_sd->object;
+ }
+
+ /* Move ray forward. */
+ volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
+ ++step;
+ }
+#endif
+
+ /* Write terminator. */
+ const VolumeStack new_entry = {OBJECT_NONE, SHADER_NONE};
+ integrator_state_write_volume_stack(state, stack_index, new_entry);
+
+ INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/megakernel.h b/intern/cycles/kernel/integrator/megakernel.h
new file mode 100644
index 00000000000..d8cc794dc7a
--- /dev/null
+++ b/intern/cycles/kernel/integrator/megakernel.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/integrator/init_from_camera.h"
+#include "kernel/integrator/intersect_closest.h"
+#include "kernel/integrator/intersect_shadow.h"
+#include "kernel/integrator/intersect_subsurface.h"
+#include "kernel/integrator/intersect_volume_stack.h"
+#include "kernel/integrator/shade_background.h"
+#include "kernel/integrator/shade_light.h"
+#include "kernel/integrator/shade_shadow.h"
+#include "kernel/integrator/shade_surface.h"
+#include "kernel/integrator/shade_volume.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device void integrator_megakernel(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ /* Each kernel indicates the next kernel to execute, so here we simply
+ * have to check what that kernel is and execute it. */
+ while (true) {
+ /* Handle any shadow paths before we potentially create more shadow paths. */
+ const uint32_t shadow_queued_kernel = INTEGRATOR_STATE(
+ &state->shadow, shadow_path, queued_kernel);
+ if (shadow_queued_kernel) {
+ switch (shadow_queued_kernel) {
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
+ integrator_intersect_shadow(kg, &state->shadow);
+ break;
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
+ integrator_shade_shadow(kg, &state->shadow, render_buffer);
+ break;
+ default:
+ kernel_assert(0);
+ break;
+ }
+ continue;
+ }
+
+ /* Handle any AO paths before we potentially create more AO paths. */
+ const uint32_t ao_queued_kernel = INTEGRATOR_STATE(&state->ao, shadow_path, queued_kernel);
+ if (ao_queued_kernel) {
+ switch (ao_queued_kernel) {
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
+ integrator_intersect_shadow(kg, &state->ao);
+ break;
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
+ integrator_shade_shadow(kg, &state->ao, render_buffer);
+ break;
+ default:
+ kernel_assert(0);
+ break;
+ }
+ continue;
+ }
+
+ /* Then handle regular path kernels. */
+ const uint32_t queued_kernel = INTEGRATOR_STATE(state, path, queued_kernel);
+ if (queued_kernel) {
+ switch (queued_kernel) {
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
+ integrator_intersect_closest(kg, state);
+ break;
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND:
+ integrator_shade_background(kg, state, render_buffer);
+ break;
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE:
+ integrator_shade_surface(kg, state, render_buffer);
+ break;
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME:
+ integrator_shade_volume(kg, state, render_buffer);
+ break;
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
+ integrator_shade_surface_raytrace(kg, state, render_buffer);
+ break;
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT:
+ integrator_shade_light(kg, state, render_buffer);
+ break;
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
+ integrator_intersect_subsurface(kg, state);
+ break;
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
+ integrator_intersect_volume_stack(kg, state);
+ break;
+ default:
+ kernel_assert(0);
+ break;
+ }
+ continue;
+ }
+
+ break;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/path_state.h b/intern/cycles/kernel/integrator/path_state.h
new file mode 100644
index 00000000000..8311b97dedb
--- /dev/null
+++ b/intern/cycles/kernel/integrator/path_state.h
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/sample/pattern.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Initialize queues, so that the this path is considered terminated.
+ * Used for early outputs in the camera ray initialization, as well as initialization of split
+ * states for shadow catcher. */
+ccl_device_inline void path_state_init_queues(IntegratorState state)
+{
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0;
+#ifdef __KERNEL_CPU__
+ INTEGRATOR_STATE_WRITE(&state->shadow, shadow_path, queued_kernel) = 0;
+ INTEGRATOR_STATE_WRITE(&state->ao, shadow_path, queued_kernel) = 0;
+#endif
+}
+
+/* Minimalistic initialization of the path state, which is needed for early outputs in the
+ * integrator initialization to work. */
+ccl_device_inline void path_state_init(IntegratorState state,
+ ccl_global const KernelWorkTile *ccl_restrict tile,
+ const int x,
+ const int y)
+{
+ const uint render_pixel_index = (uint)tile->offset + x + y * tile->stride;
+
+ INTEGRATOR_STATE_WRITE(state, path, render_pixel_index) = render_pixel_index;
+
+ path_state_init_queues(state);
+}
+
+/* Initialize the rest of the path state needed to continue the path integration. */
+ccl_device_inline void path_state_init_integrator(KernelGlobals kg,
+ IntegratorState state,
+ const int sample,
+ const uint rng_hash)
+{
+ INTEGRATOR_STATE_WRITE(state, path, sample) = sample;
+ INTEGRATOR_STATE_WRITE(state, path, bounce) = 0;
+ INTEGRATOR_STATE_WRITE(state, path, diffuse_bounce) = 0;
+ INTEGRATOR_STATE_WRITE(state, path, glossy_bounce) = 0;
+ INTEGRATOR_STATE_WRITE(state, path, transmission_bounce) = 0;
+ INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = 0;
+ INTEGRATOR_STATE_WRITE(state, path, volume_bounce) = 0;
+ INTEGRATOR_STATE_WRITE(state, path, volume_bounds_bounce) = 0;
+ INTEGRATOR_STATE_WRITE(state, path, rng_hash) = rng_hash;
+ INTEGRATOR_STATE_WRITE(state, path, rng_offset) = PRNG_BASE_NUM;
+ INTEGRATOR_STATE_WRITE(state, path, flag) = PATH_RAY_CAMERA | PATH_RAY_MIS_SKIP |
+ PATH_RAY_TRANSPARENT_BACKGROUND;
+ INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = 0.0f;
+ INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f;
+ INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = FLT_MAX;
+ INTEGRATOR_STATE_WRITE(state, path, throughput) = make_float3(1.0f, 1.0f, 1.0f);
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) {
+ INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 0, object) = OBJECT_NONE;
+ INTEGRATOR_STATE_ARRAY_WRITE(
+ state, volume_stack, 0, shader) = kernel_data.background.volume_shader;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 1, object) = OBJECT_NONE;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 1, shader) = SHADER_NONE;
+ }
+
+#ifdef __DENOISING_FEATURES__
+ if (kernel_data.kernel_features & KERNEL_FEATURE_DENOISING) {
+ INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_DENOISING_FEATURES;
+ INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) = one_float3();
+ }
+#endif
+}
+
+ccl_device_inline void path_state_next(KernelGlobals kg, IntegratorState state, int label)
+{
+ uint32_t flag = INTEGRATOR_STATE(state, path, flag);
+
+ /* ray through transparent keeps same flags from previous ray and is
+ * not counted as a regular bounce, transparent has separate max */
+ if (label & LABEL_TRANSPARENT) {
+ uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce) + 1;
+
+ flag |= PATH_RAY_TRANSPARENT;
+ if (transparent_bounce >= kernel_data.integrator.transparent_max_bounce) {
+ flag |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE;
+ }
+
+ if (!kernel_data.integrator.transparent_shadows)
+ flag |= PATH_RAY_MIS_SKIP;
+
+ INTEGRATOR_STATE_WRITE(state, path, flag) = flag;
+ INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = transparent_bounce;
+ /* Random number generator next bounce. */
+ INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
+ return;
+ }
+
+ uint32_t bounce = INTEGRATOR_STATE(state, path, bounce) + 1;
+ if (bounce >= kernel_data.integrator.max_bounce) {
+ flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+
+ flag &= ~(PATH_RAY_ALL_VISIBILITY | PATH_RAY_MIS_SKIP);
+
+#ifdef __VOLUME__
+ if (label & LABEL_VOLUME_SCATTER) {
+ /* volume scatter */
+ flag |= PATH_RAY_VOLUME_SCATTER;
+ flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
+ if (bounce == 1) {
+ flag |= PATH_RAY_VOLUME_PASS;
+ }
+
+ const int volume_bounce = INTEGRATOR_STATE(state, path, volume_bounce) + 1;
+ INTEGRATOR_STATE_WRITE(state, path, volume_bounce) = volume_bounce;
+ if (volume_bounce >= kernel_data.integrator.max_volume_bounce) {
+ flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+ }
+ else
+#endif
+ {
+ /* surface reflection/transmission */
+ if (label & LABEL_REFLECT) {
+ flag |= PATH_RAY_REFLECT;
+ flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
+
+ if (label & LABEL_DIFFUSE) {
+ const int diffuse_bounce = INTEGRATOR_STATE(state, path, diffuse_bounce) + 1;
+ INTEGRATOR_STATE_WRITE(state, path, diffuse_bounce) = diffuse_bounce;
+ if (diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) {
+ flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+ }
+ else {
+ const int glossy_bounce = INTEGRATOR_STATE(state, path, glossy_bounce) + 1;
+ INTEGRATOR_STATE_WRITE(state, path, glossy_bounce) = glossy_bounce;
+ if (glossy_bounce >= kernel_data.integrator.max_glossy_bounce) {
+ flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+ }
+ }
+ else {
+ kernel_assert(label & LABEL_TRANSMIT);
+
+ flag |= PATH_RAY_TRANSMIT;
+
+ if (!(label & LABEL_TRANSMIT_TRANSPARENT)) {
+ flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
+ }
+
+ const int transmission_bounce = INTEGRATOR_STATE(state, path, transmission_bounce) + 1;
+ INTEGRATOR_STATE_WRITE(state, path, transmission_bounce) = transmission_bounce;
+ if (transmission_bounce >= kernel_data.integrator.max_transmission_bounce) {
+ flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+ }
+
+ /* diffuse/glossy/singular */
+ if (label & LABEL_DIFFUSE) {
+ flag |= PATH_RAY_DIFFUSE | PATH_RAY_DIFFUSE_ANCESTOR;
+ }
+ else if (label & LABEL_GLOSSY) {
+ flag |= PATH_RAY_GLOSSY;
+ }
+ else {
+ kernel_assert(label & LABEL_SINGULAR);
+ flag |= PATH_RAY_GLOSSY | PATH_RAY_SINGULAR | PATH_RAY_MIS_SKIP;
+ }
+
+ /* Render pass categories. */
+ if (bounce == 1) {
+ flag |= (label & LABEL_TRANSMIT) ? PATH_RAY_TRANSMISSION_PASS : PATH_RAY_REFLECT_PASS;
+ }
+ }
+
+ INTEGRATOR_STATE_WRITE(state, path, flag) = flag;
+ INTEGRATOR_STATE_WRITE(state, path, bounce) = bounce;
+
+ /* Random number generator next bounce. */
+ INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
+}
+
+#ifdef __VOLUME__
+ccl_device_inline bool path_state_volume_next(IntegratorState state)
+{
+ /* For volume bounding meshes we pass through without counting transparent
+ * bounces, only sanity check in case self intersection gets us stuck. */
+ uint32_t volume_bounds_bounce = INTEGRATOR_STATE(state, path, volume_bounds_bounce) + 1;
+ INTEGRATOR_STATE_WRITE(state, path, volume_bounds_bounce) = volume_bounds_bounce;
+ if (volume_bounds_bounce > VOLUME_BOUNDS_MAX) {
+ return false;
+ }
+
+ /* Random number generator next bounce. */
+ if (volume_bounds_bounce > 1) {
+ INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
+ }
+
+ return true;
+}
+#endif
+
+ccl_device_inline uint path_state_ray_visibility(ConstIntegratorState state)
+{
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ uint32_t visibility = path_flag & PATH_RAY_ALL_VISIBILITY;
+
+ /* For visibility, diffuse/glossy are for reflection only. */
+ if (visibility & PATH_RAY_TRANSMIT) {
+ visibility &= ~(PATH_RAY_DIFFUSE | PATH_RAY_GLOSSY);
+ }
+
+ /* todo: this is not supported as its own ray visibility yet. */
+ if (path_flag & PATH_RAY_VOLUME_SCATTER) {
+ visibility |= PATH_RAY_DIFFUSE;
+ }
+
+ visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility);
+
+ return visibility;
+}
+
+ccl_device_inline float path_state_continuation_probability(KernelGlobals kg,
+ ConstIntegratorState state,
+ const uint32_t path_flag)
+{
+ if (path_flag & PATH_RAY_TRANSPARENT) {
+ const uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce);
+ /* Do at least specified number of bounces without RR. */
+ if (transparent_bounce <= kernel_data.integrator.transparent_min_bounce) {
+ return 1.0f;
+ }
+ }
+ else {
+ const uint32_t bounce = INTEGRATOR_STATE(state, path, bounce);
+ /* Do at least specified number of bounces without RR. */
+ if (bounce <= kernel_data.integrator.min_bounce) {
+ return 1.0f;
+ }
+ }
+
+ /* Probabilistic termination: use sqrt() to roughly match typical view
+ * transform and do path termination a bit later on average. */
+ return min(sqrtf(max3(fabs(INTEGRATOR_STATE(state, path, throughput)))), 1.0f);
+}
+
+ccl_device_inline bool path_state_ao_bounce(KernelGlobals kg, ConstIntegratorState state)
+{
+ if (!kernel_data.integrator.ao_bounces) {
+ return false;
+ }
+
+ const int bounce = INTEGRATOR_STATE(state, path, bounce) -
+ INTEGRATOR_STATE(state, path, transmission_bounce) -
+ (INTEGRATOR_STATE(state, path, glossy_bounce) > 0) + 1;
+ return (bounce > kernel_data.integrator.ao_bounces);
+}
+
+/* Random Number Sampling Utility Functions
+ *
+ * For each random number in each step of the path we must have a unique
+ * dimension to avoid using the same sequence twice.
+ *
+ * For branches in the path we must be careful not to reuse the same number
+ * in a sequence and offset accordingly.
+ */
+
+/* RNG State loaded onto stack. */
+typedef struct RNGState {
+ uint rng_hash;
+ uint rng_offset;
+ int sample;
+} RNGState;
+
+ccl_device_inline void path_state_rng_load(ConstIntegratorState state,
+ ccl_private RNGState *rng_state)
+{
+ rng_state->rng_hash = INTEGRATOR_STATE(state, path, rng_hash);
+ rng_state->rng_offset = INTEGRATOR_STATE(state, path, rng_offset);
+ rng_state->sample = INTEGRATOR_STATE(state, path, sample);
+}
+
+ccl_device_inline void shadow_path_state_rng_load(ConstIntegratorShadowState state,
+ ccl_private RNGState *rng_state)
+{
+ rng_state->rng_hash = INTEGRATOR_STATE(state, shadow_path, rng_hash);
+ rng_state->rng_offset = INTEGRATOR_STATE(state, shadow_path, rng_offset);
+ rng_state->sample = INTEGRATOR_STATE(state, shadow_path, sample);
+}
+
+ccl_device_inline float path_state_rng_1D(KernelGlobals kg,
+ ccl_private const RNGState *rng_state,
+ int dimension)
+{
+ return path_rng_1D(
+ kg, rng_state->rng_hash, rng_state->sample, rng_state->rng_offset + dimension);
+}
+
+ccl_device_inline void path_state_rng_2D(KernelGlobals kg,
+ ccl_private const RNGState *rng_state,
+ int dimension,
+ ccl_private float *fx,
+ ccl_private float *fy)
+{
+ path_rng_2D(
+ kg, rng_state->rng_hash, rng_state->sample, rng_state->rng_offset + dimension, fx, fy);
+}
+
+ccl_device_inline float path_state_rng_1D_hash(KernelGlobals kg,
+ ccl_private const RNGState *rng_state,
+ uint hash)
+{
+ /* Use a hash instead of dimension, this is not great but avoids adding
+ * more dimensions to each bounce which reduces quality of dimensions we
+ * are already using. */
+ return path_rng_1D(
+ kg, cmj_hash_simple(rng_state->rng_hash, hash), rng_state->sample, rng_state->rng_offset);
+}
+
+ccl_device_inline float path_branched_rng_1D(KernelGlobals kg,
+ ccl_private const RNGState *rng_state,
+ int branch,
+ int num_branches,
+ int dimension)
+{
+ return path_rng_1D(kg,
+ rng_state->rng_hash,
+ rng_state->sample * num_branches + branch,
+ rng_state->rng_offset + dimension);
+}
+
+ccl_device_inline void path_branched_rng_2D(KernelGlobals kg,
+ ccl_private const RNGState *rng_state,
+ int branch,
+ int num_branches,
+ int dimension,
+ ccl_private float *fx,
+ ccl_private float *fy)
+{
+ path_rng_2D(kg,
+ rng_state->rng_hash,
+ rng_state->sample * num_branches + branch,
+ rng_state->rng_offset + dimension,
+ fx,
+ fy);
+}
+
+/* Utility functions to get light termination value,
+ * since it might not be needed in many cases.
+ */
+ccl_device_inline float path_state_rng_light_termination(KernelGlobals kg,
+ ccl_private const RNGState *state)
+{
+ if (kernel_data.integrator.light_inv_rr_threshold > 0.0f) {
+ return path_state_rng_1D(kg, state, PRNG_LIGHT_TERMINATE);
+ }
+ return 0.0f;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shade_background.h b/intern/cycles/kernel/integrator/shade_background.h
new file mode 100644
index 00000000000..71a590749bd
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shade_background.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/film/accumulate.h"
+#include "kernel/integrator/shader_eval.h"
+#include "kernel/light/light.h"
+#include "kernel/light/sample.h"
+#include "kernel/sample/mis.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device float3 integrator_eval_background_shader(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+#ifdef __BACKGROUND__
+ const int shader = kernel_data.background.surface_shader;
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ /* Use visibility flag to skip lights. */
+ if (shader & SHADER_EXCLUDE_ANY) {
+ if (((shader & SHADER_EXCLUDE_DIFFUSE) && (path_flag & PATH_RAY_DIFFUSE)) ||
+ ((shader & SHADER_EXCLUDE_GLOSSY) && ((path_flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) ==
+ (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) ||
+ ((shader & SHADER_EXCLUDE_TRANSMIT) && (path_flag & PATH_RAY_TRANSMIT)) ||
+ ((shader & SHADER_EXCLUDE_CAMERA) && (path_flag & PATH_RAY_CAMERA)) ||
+ ((shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER)))
+ return zero_float3();
+ }
+
+ /* Use fast constant background color if available. */
+ float3 L = zero_float3();
+ if (!shader_constant_emission_eval(kg, shader, &L)) {
+ /* Evaluate background shader. */
+
+ /* TODO: does aliasing like this break automatic SoA in CUDA?
+ * Should we instead store closures separate from ShaderData? */
+ ShaderDataTinyStorage emission_sd_storage;
+ ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
+
+ PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_LIGHT_SETUP);
+ shader_setup_from_background(kg,
+ emission_sd,
+ INTEGRATOR_STATE(state, ray, P),
+ INTEGRATOR_STATE(state, ray, D),
+ INTEGRATOR_STATE(state, ray, time));
+
+ PROFILING_SHADER(emission_sd->object, emission_sd->shader);
+ PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL);
+ shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT>(
+ kg, state, emission_sd, render_buffer, path_flag | PATH_RAY_EMISSION);
+
+ L = shader_background_eval(emission_sd);
+ }
+
+ /* Background MIS weights. */
+# ifdef __BACKGROUND_MIS__
+ /* Check if background light exists or if we should skip pdf. */
+ if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_MIS_SKIP) &&
+ kernel_data.background.use_mis) {
+ const float3 ray_P = INTEGRATOR_STATE(state, ray, P);
+ const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
+ const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
+ const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
+
+ /* multiple importance sampling, get background light pdf for ray
+ * direction, and compute weight with respect to BSDF pdf */
+ const float pdf = background_light_pdf(kg, ray_P - ray_D * mis_ray_t, ray_D);
+ const float mis_weight = power_heuristic(mis_ray_pdf, pdf);
+
+ L *= mis_weight;
+ }
+# endif
+
+ return L;
+#else
+ return make_float3(0.8f, 0.8f, 0.8f);
+#endif
+}
+
+ccl_device_inline void integrate_background(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ /* Accumulate transparency for transparent background. We can skip background
+ * shader evaluation unless a background pass is used. */
+ bool eval_background = true;
+ float transparent = 0.0f;
+
+ const bool is_transparent_background_ray = kernel_data.background.transparent &&
+ (INTEGRATOR_STATE(state, path, flag) &
+ PATH_RAY_TRANSPARENT_BACKGROUND);
+
+ if (is_transparent_background_ray) {
+ transparent = average(INTEGRATOR_STATE(state, path, throughput));
+
+#ifdef __PASSES__
+ eval_background = (kernel_data.film.light_pass_flag & PASSMASK(BACKGROUND));
+#else
+ eval_background = false;
+#endif
+ }
+
+ /* Evaluate background shader. */
+ float3 L = (eval_background) ? integrator_eval_background_shader(kg, state, render_buffer) :
+ zero_float3();
+
+ /* When using the ao bounces approximation, adjust background
+ * shader intensity with ao factor. */
+ if (path_state_ao_bounce(kg, state)) {
+ L *= kernel_data.integrator.ao_bounces_factor;
+ }
+
+ /* Write to render buffer. */
+ kernel_accum_background(kg, state, L, transparent, is_transparent_background_ray, render_buffer);
+}
+
+ccl_device_inline void integrate_distant_lights(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
+ const float ray_time = INTEGRATOR_STATE(state, ray, time);
+ LightSample ls ccl_optional_struct_init;
+ for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) {
+ if (light_sample_from_distant_ray(kg, ray_D, lamp, &ls)) {
+ /* Use visibility flag to skip lights. */
+#ifdef __PASSES__
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ if (ls.shader & SHADER_EXCLUDE_ANY) {
+ if (((ls.shader & SHADER_EXCLUDE_DIFFUSE) && (path_flag & PATH_RAY_DIFFUSE)) ||
+ ((ls.shader & SHADER_EXCLUDE_GLOSSY) &&
+ ((path_flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) ==
+ (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) ||
+ ((ls.shader & SHADER_EXCLUDE_TRANSMIT) && (path_flag & PATH_RAY_TRANSMIT)) ||
+ ((ls.shader & SHADER_EXCLUDE_CAMERA) && (path_flag & PATH_RAY_CAMERA)) ||
+ ((ls.shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER)))
+ return;
+ }
+#endif
+
+ /* Evaluate light shader. */
+ /* TODO: does aliasing like this break automatic SoA in CUDA? */
+ ShaderDataTinyStorage emission_sd_storage;
+ ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
+ float3 light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, ray_time);
+ if (is_zero(light_eval)) {
+ return;
+ }
+
+ /* MIS weighting. */
+ if (!(path_flag & PATH_RAY_MIS_SKIP)) {
+ /* multiple importance sampling, get regular light pdf,
+ * and compute weight with respect to BSDF pdf */
+ const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
+ const float mis_weight = power_heuristic(mis_ray_pdf, ls.pdf);
+ light_eval *= mis_weight;
+ }
+
+ /* Write to render buffer. */
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ kernel_accum_emission(kg, state, throughput, light_eval, render_buffer);
+ }
+ }
+}
+
+ccl_device void integrator_shade_background(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ PROFILING_INIT(kg, PROFILING_SHADE_LIGHT_SETUP);
+
+ /* TODO: unify these in a single loop to only have a single shader evaluation call. */
+ integrate_distant_lights(kg, state, render_buffer);
+ integrate_background(kg, state, render_buffer);
+
+#ifdef __SHADOW_CATCHER__
+ if (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_SHADOW_CATCHER_BACKGROUND) {
+ INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_SHADOW_CATCHER_BACKGROUND;
+
+ const int isect_prim = INTEGRATOR_STATE(state, isect, prim);
+ const int isect_type = INTEGRATOR_STATE(state, isect, type);
+ const int shader = intersection_get_shader_from_isect_prim(kg, isect_prim, isect_type);
+ const int shader_flags = kernel_tex_fetch(__shaders, shader).flags;
+
+ if (shader_flags & SD_HAS_RAYTRACE) {
+ INTEGRATOR_PATH_NEXT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE,
+ shader);
+ }
+ else {
+ INTEGRATOR_PATH_NEXT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE,
+ shader);
+ }
+ return;
+ }
+#endif
+
+ INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shade_light.h b/intern/cycles/kernel/integrator/shade_light.h
new file mode 100644
index 00000000000..7dad3b4e49d
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shade_light.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/film/accumulate.h"
+#include "kernel/integrator/shader_eval.h"
+#include "kernel/light/light.h"
+#include "kernel/light/sample.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline void integrate_light(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ /* Setup light sample. */
+ Intersection isect ccl_optional_struct_init;
+ integrator_state_read_isect(kg, state, &isect);
+
+ float3 ray_P = INTEGRATOR_STATE(state, ray, P);
+ const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
+ const float ray_time = INTEGRATOR_STATE(state, ray, time);
+
+ /* Advance ray beyond light. */
+ /* TODO: can we make this more numerically robust to avoid reintersecting the
+ * same light in some cases? */
+ const float3 new_ray_P = ray_offset(ray_P + ray_D * isect.t, ray_D);
+ INTEGRATOR_STATE_WRITE(state, ray, P) = new_ray_P;
+ INTEGRATOR_STATE_WRITE(state, ray, t) -= isect.t;
+
+ /* Set position to where the BSDF was sampled, for correct MIS PDF. */
+ const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
+ ray_P -= ray_D * mis_ray_t;
+ isect.t += mis_ray_t;
+ INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = mis_ray_t + isect.t;
+
+ LightSample ls ccl_optional_struct_init;
+ const bool use_light_sample = light_sample_from_intersection(kg, &isect, ray_P, ray_D, &ls);
+
+ if (!use_light_sample) {
+ return;
+ }
+
+ /* Use visibility flag to skip lights. */
+#ifdef __PASSES__
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ if (ls.shader & SHADER_EXCLUDE_ANY) {
+ if (((ls.shader & SHADER_EXCLUDE_DIFFUSE) && (path_flag & PATH_RAY_DIFFUSE)) ||
+ ((ls.shader & SHADER_EXCLUDE_GLOSSY) &&
+ ((path_flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) ==
+ (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) ||
+ ((ls.shader & SHADER_EXCLUDE_TRANSMIT) && (path_flag & PATH_RAY_TRANSMIT)) ||
+ ((ls.shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER)))
+ return;
+ }
+#endif
+
+ /* Evaluate light shader. */
+ /* TODO: does aliasing like this break automatic SoA in CUDA? */
+ ShaderDataTinyStorage emission_sd_storage;
+ ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
+ float3 light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, ray_time);
+ if (is_zero(light_eval)) {
+ return;
+ }
+
+ /* MIS weighting. */
+ if (!(path_flag & PATH_RAY_MIS_SKIP)) {
+ /* multiple importance sampling, get regular light pdf,
+ * and compute weight with respect to BSDF pdf */
+ const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
+ const float mis_weight = power_heuristic(mis_ray_pdf, ls.pdf);
+ light_eval *= mis_weight;
+ }
+
+ /* Write to render buffer. */
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ kernel_accum_emission(kg, state, throughput, light_eval, render_buffer);
+}
+
+ccl_device void integrator_shade_light(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ PROFILING_INIT(kg, PROFILING_SHADE_LIGHT_SETUP);
+
+ integrate_light(kg, state, render_buffer);
+
+ /* TODO: we could get stuck in an infinite loop if there are precision issues
+ * and the same light is hit again.
+ *
+ * As a workaround count this as a transparent bounce. It makes some sense
+ * to interpret lights as transparent surfaces (and support making them opaque),
+ * but this needs to be revisited. */
+ uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce) + 1;
+ INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = transparent_bounce;
+
+ if (transparent_bounce >= kernel_data.integrator.transparent_max_bounce) {
+ INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
+ return;
+ }
+ else {
+ INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
+ return;
+ }
+
+ /* TODO: in some cases we could continue directly to SHADE_BACKGROUND, but
+ * probably that optimization is probably not practical if we add lights to
+ * scene geometry. */
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shade_shadow.h b/intern/cycles/kernel/integrator/shade_shadow.h
new file mode 100644
index 00000000000..1de890aae29
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shade_shadow.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/integrator/shade_volume.h"
+#include "kernel/integrator/shader_eval.h"
+#include "kernel/integrator/volume_stack.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline bool shadow_intersections_has_remaining(const uint num_hits)
+{
+ return num_hits >= INTEGRATOR_SHADOW_ISECT_SIZE;
+}
+
+#ifdef __TRANSPARENT_SHADOWS__
+ccl_device_inline float3 integrate_transparent_surface_shadow(KernelGlobals kg,
+ IntegratorShadowState state,
+ const int hit)
+{
+ PROFILING_INIT(kg, PROFILING_SHADE_SHADOW_SURFACE);
+
+ /* TODO: does aliasing like this break automatic SoA in CUDA?
+ * Should we instead store closures separate from ShaderData?
+ *
+ * TODO: is it better to declare this outside the loop or keep it local
+ * so the compiler can see there is no dependency between iterations? */
+ ShaderDataTinyStorage shadow_sd_storage;
+ ccl_private ShaderData *shadow_sd = AS_SHADER_DATA(&shadow_sd_storage);
+
+ /* Setup shader data at surface. */
+ Intersection isect ccl_optional_struct_init;
+ integrator_state_read_shadow_isect(state, &isect, hit);
+
+ Ray ray ccl_optional_struct_init;
+ integrator_state_read_shadow_ray(kg, state, &ray);
+
+ shader_setup_from_ray(kg, shadow_sd, &ray, &isect);
+
+ /* Evaluate shader. */
+ if (!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
+ shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW>(
+ kg, state, shadow_sd, NULL, PATH_RAY_SHADOW);
+ }
+
+# ifdef __VOLUME__
+ /* Exit/enter volume. */
+ shadow_volume_stack_enter_exit(kg, state, shadow_sd);
+# endif
+
+ /* Compute transparency from closures. */
+ return shader_bsdf_transparency(kg, shadow_sd);
+}
+
+# ifdef __VOLUME__
+ccl_device_inline void integrate_transparent_volume_shadow(KernelGlobals kg,
+ IntegratorShadowState state,
+ const int hit,
+ const int num_recorded_hits,
+ ccl_private float3 *ccl_restrict
+ throughput)
+{
+ PROFILING_INIT(kg, PROFILING_SHADE_SHADOW_VOLUME);
+
+ /* TODO: deduplicate with surface, or does it not matter for memory usage? */
+ ShaderDataTinyStorage shadow_sd_storage;
+ ccl_private ShaderData *shadow_sd = AS_SHADER_DATA(&shadow_sd_storage);
+
+ /* Setup shader data. */
+ Ray ray ccl_optional_struct_init;
+ integrator_state_read_shadow_ray(kg, state, &ray);
+
+ /* Modify ray position and length to match current segment. */
+ const float start_t = (hit == 0) ? 0.0f :
+ INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit - 1, t);
+ const float end_t = (hit < num_recorded_hits) ?
+ INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit, t) :
+ ray.t;
+ ray.P += start_t * ray.D;
+ ray.t = end_t - start_t;
+
+ shader_setup_from_volume(kg, shadow_sd, &ray);
+
+ const float step_size = volume_stack_step_size(
+ kg, [=](const int i) { return integrator_state_read_shadow_volume_stack(state, i); });
+
+ volume_shadow_heterogeneous(kg, state, &ray, shadow_sd, throughput, step_size);
+}
+# endif
+
+ccl_device_inline bool integrate_transparent_shadow(KernelGlobals kg,
+ IntegratorShadowState state,
+ const uint num_hits)
+{
+ /* Accumulate shadow for transparent surfaces. */
+ const uint num_recorded_hits = min(num_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
+
+ for (uint hit = 0; hit < num_recorded_hits + 1; hit++) {
+ /* Volume shaders. */
+ if (hit < num_recorded_hits || !shadow_intersections_has_remaining(num_hits)) {
+# ifdef __VOLUME__
+ if (!integrator_state_shadow_volume_stack_is_empty(kg, state)) {
+ float3 throughput = INTEGRATOR_STATE(state, shadow_path, throughput);
+ integrate_transparent_volume_shadow(kg, state, hit, num_recorded_hits, &throughput);
+ if (is_zero(throughput)) {
+ return true;
+ }
+
+ INTEGRATOR_STATE_WRITE(state, shadow_path, throughput) = throughput;
+ }
+# endif
+ }
+
+ /* Surface shaders. */
+ if (hit < num_recorded_hits) {
+ const float3 shadow = integrate_transparent_surface_shadow(kg, state, hit);
+ const float3 throughput = INTEGRATOR_STATE(state, shadow_path, throughput) * shadow;
+ if (is_zero(throughput)) {
+ return true;
+ }
+
+ INTEGRATOR_STATE_WRITE(state, shadow_path, throughput) = throughput;
+ INTEGRATOR_STATE_WRITE(state, shadow_path, transparent_bounce) += 1;
+ INTEGRATOR_STATE_WRITE(state, shadow_path, rng_offset) += PRNG_BOUNCE_NUM;
+ }
+
+ /* Note we do not need to check max_transparent_bounce here, the number
+ * of intersections is already limited and made opaque in the
+ * INTERSECT_SHADOW kernel. */
+ }
+
+ if (shadow_intersections_has_remaining(num_hits)) {
+ /* There are more hits that we could not recorded due to memory usage,
+ * adjust ray to intersect again from the last hit. */
+ const float last_hit_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, num_recorded_hits - 1, t);
+ const float3 ray_P = INTEGRATOR_STATE(state, shadow_ray, P);
+ const float3 ray_D = INTEGRATOR_STATE(state, shadow_ray, D);
+ INTEGRATOR_STATE_WRITE(state, shadow_ray, P) = ray_offset(ray_P + last_hit_t * ray_D, ray_D);
+ INTEGRATOR_STATE_WRITE(state, shadow_ray, t) -= last_hit_t;
+ }
+
+ return false;
+}
+#endif /* __TRANSPARENT_SHADOWS__ */
+
+ccl_device void integrator_shade_shadow(KernelGlobals kg,
+ IntegratorShadowState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ PROFILING_INIT(kg, PROFILING_SHADE_SHADOW_SETUP);
+ const uint num_hits = INTEGRATOR_STATE(state, shadow_path, num_hits);
+
+#ifdef __TRANSPARENT_SHADOWS__
+ /* Evaluate transparent shadows. */
+ const bool opaque = integrate_transparent_shadow(kg, state, num_hits);
+ if (opaque) {
+ INTEGRATOR_SHADOW_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
+ return;
+ }
+#endif
+
+ if (shadow_intersections_has_remaining(num_hits)) {
+ /* More intersections to find, continue shadow ray. */
+ INTEGRATOR_SHADOW_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
+ return;
+ }
+ else {
+ kernel_accum_light(kg, state, render_buffer);
+ INTEGRATOR_SHADOW_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
+ return;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h
new file mode 100644
index 00000000000..cce591eb219
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shade_surface.h
@@ -0,0 +1,557 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/film/accumulate.h"
+#include "kernel/film/passes.h"
+
+#include "kernel/integrator/path_state.h"
+#include "kernel/integrator/shader_eval.h"
+#include "kernel/integrator/subsurface.h"
+#include "kernel/integrator/volume_stack.h"
+
+#include "kernel/light/light.h"
+#include "kernel/light/sample.h"
+
+#include "kernel/sample/mis.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_forceinline void integrate_surface_shader_setup(KernelGlobals kg,
+ ConstIntegratorState state,
+ ccl_private ShaderData *sd)
+{
+ Intersection isect ccl_optional_struct_init;
+ integrator_state_read_isect(kg, state, &isect);
+
+ Ray ray ccl_optional_struct_init;
+ integrator_state_read_ray(kg, state, &ray);
+
+ shader_setup_from_ray(kg, sd, &ray, &isect);
+}
+
+#ifdef __HOLDOUT__
+ccl_device_forceinline bool integrate_surface_holdout(KernelGlobals kg,
+ ConstIntegratorState state,
+ ccl_private ShaderData *sd,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ /* Write holdout transparency to render buffer and stop if fully holdout. */
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ if (((sd->flag & SD_HOLDOUT) || (sd->object_flag & SD_OBJECT_HOLDOUT_MASK)) &&
+ (path_flag & PATH_RAY_TRANSPARENT_BACKGROUND)) {
+ const float3 holdout_weight = shader_holdout_apply(kg, sd);
+ if (kernel_data.background.transparent) {
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ const float transparent = average(holdout_weight * throughput);
+ kernel_accum_holdout(kg, state, path_flag, transparent, render_buffer);
+ }
+ if (isequal_float3(holdout_weight, one_float3())) {
+ return false;
+ }
+ }
+
+ return true;
+}
+#endif /* __HOLDOUT__ */
+
+#ifdef __EMISSION__
+ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
+ ConstIntegratorState state,
+ ccl_private const ShaderData *sd,
+ ccl_global float *ccl_restrict
+ render_buffer)
+{
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ /* Evaluate emissive closure. */
+ float3 L = shader_emissive_eval(sd);
+
+# ifdef __HAIR__
+ if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS) &&
+ (sd->type & PRIMITIVE_ALL_TRIANGLE))
+# else
+ if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS))
+# endif
+ {
+ const float bsdf_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
+ const float t = sd->ray_length + INTEGRATOR_STATE(state, path, mis_ray_t);
+
+ /* Multiple importance sampling, get triangle light pdf,
+ * and compute weight with respect to BSDF pdf. */
+ float pdf = triangle_light_pdf(kg, sd, t);
+ float mis_weight = power_heuristic(bsdf_pdf, pdf);
+
+ L *= mis_weight;
+ }
+
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ kernel_accum_emission(kg, state, throughput, L, render_buffer);
+}
+#endif /* __EMISSION__ */
+
+#ifdef __EMISSION__
+/* Path tracing: sample point on light and evaluate light shader, then
+ * queue shadow ray to be traced. */
+ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
+ IntegratorState state,
+ ccl_private ShaderData *sd,
+ ccl_private const RNGState *rng_state)
+{
+ /* Test if there is a light or BSDF that needs direct light. */
+ if (!(kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL))) {
+ return;
+ }
+
+ /* Sample position on a light. */
+ LightSample ls ccl_optional_struct_init;
+ {
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+ const uint bounce = INTEGRATOR_STATE(state, path, bounce);
+ float light_u, light_v;
+ path_state_rng_2D(kg, rng_state, PRNG_LIGHT_U, &light_u, &light_v);
+
+ if (!light_distribution_sample_from_position(
+ kg, light_u, light_v, sd->time, sd->P, bounce, path_flag, &ls)) {
+ return;
+ }
+ }
+
+ kernel_assert(ls.pdf != 0.0f);
+
+ /* Evaluate light shader.
+ *
+ * TODO: can we reuse sd memory? In theory we can move this after
+ * integrate_surface_bounce, evaluate the BSDF, and only then evaluate
+ * the light shader. This could also move to its own kernel, for
+ * non-constant light sources. */
+ ShaderDataTinyStorage emission_sd_storage;
+ ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
+ const float3 light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, sd->time);
+ if (is_zero(light_eval)) {
+ return;
+ }
+
+ /* Evaluate BSDF. */
+ const bool is_transmission = shader_bsdf_is_transmission(sd, ls.D);
+
+ BsdfEval bsdf_eval ccl_optional_struct_init;
+ const float bsdf_pdf = shader_bsdf_eval(kg, sd, ls.D, is_transmission, &bsdf_eval, ls.shader);
+ bsdf_eval_mul3(&bsdf_eval, light_eval / ls.pdf);
+
+ if (ls.shader & SHADER_USE_MIS) {
+ const float mis_weight = power_heuristic(ls.pdf, bsdf_pdf);
+ bsdf_eval_mul(&bsdf_eval, mis_weight);
+ }
+
+ /* Path termination. */
+ const float terminate = path_state_rng_light_termination(kg, rng_state);
+ if (light_sample_terminate(kg, &ls, &bsdf_eval, terminate)) {
+ return;
+ }
+
+ /* Create shadow ray. */
+ Ray ray ccl_optional_struct_init;
+ light_sample_to_surface_shadow_ray(kg, sd, &ls, &ray);
+ const bool is_light = light_sample_is_light(&ls);
+
+ /* Branch off shadow kernel. */
+ INTEGRATOR_SHADOW_PATH_INIT(
+ shadow_state, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, shadow);
+
+ /* Copy volume stack and enter/exit volume. */
+ integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state);
+
+ if (is_transmission) {
+# ifdef __VOLUME__
+ shadow_volume_stack_enter_exit(kg, shadow_state, sd);
+# endif
+ }
+
+ /* Write shadow ray and associated state to global memory. */
+ integrator_state_write_shadow_ray(kg, shadow_state, &ray);
+
+ /* Copy state from main path to shadow path. */
+ const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce);
+ const uint16_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce);
+ uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag);
+ shadow_flag |= (is_light) ? PATH_RAY_SHADOW_FOR_LIGHT : 0;
+ shadow_flag |= (is_transmission) ? PATH_RAY_TRANSMISSION_PASS : PATH_RAY_REFLECT_PASS;
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput) * bsdf_eval_sum(&bsdf_eval);
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
+ const float3 diffuse_glossy_ratio = (bounce == 0) ?
+ bsdf_eval_diffuse_glossy_ratio(&bsdf_eval) :
+ INTEGRATOR_STATE(state, path, diffuse_glossy_ratio);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, diffuse_glossy_ratio) = diffuse_glossy_ratio;
+ }
+
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, render_pixel_index) = INTEGRATOR_STATE(
+ state, path, render_pixel_index);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_offset) = INTEGRATOR_STATE(
+ state, path, rng_offset);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_hash) = INTEGRATOR_STATE(
+ state, path, rng_hash);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, sample) = INTEGRATOR_STATE(
+ state, path, sample);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, flag) = shadow_flag;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, bounce) = bounce;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transparent_bounce) = transparent_bounce;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, diffuse_bounce) = INTEGRATOR_STATE(
+ state, path, diffuse_bounce);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, glossy_bounce) = INTEGRATOR_STATE(
+ state, path, glossy_bounce);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transmission_bounce) = INTEGRATOR_STATE(
+ state, path, transmission_bounce);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput;
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_PASS) {
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unshadowed_throughput) = throughput;
+ }
+}
+#endif
+
+/* Path tracing: bounce off or through surface with new direction. */
+ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private ShaderData *sd,
+ ccl_private const RNGState *rng_state)
+{
+ /* Sample BSDF or BSSRDF. */
+ if (!(sd->flag & (SD_BSDF | SD_BSSRDF))) {
+ return LABEL_NONE;
+ }
+
+ float bsdf_u, bsdf_v;
+ path_state_rng_2D(kg, rng_state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
+ ccl_private const ShaderClosure *sc = shader_bsdf_bssrdf_pick(sd, &bsdf_u);
+
+#ifdef __SUBSURFACE__
+ /* BSSRDF closure, we schedule subsurface intersection kernel. */
+ if (CLOSURE_IS_BSSRDF(sc->type)) {
+ return subsurface_bounce(kg, state, sd, sc);
+ }
+#endif
+
+ /* BSDF closure, sample direction. */
+ float bsdf_pdf;
+ BsdfEval bsdf_eval ccl_optional_struct_init;
+ float3 bsdf_omega_in ccl_optional_struct_init;
+ differential3 bsdf_domega_in ccl_optional_struct_init;
+ int label;
+
+ label = shader_bsdf_sample_closure(
+ kg, sd, sc, bsdf_u, bsdf_v, &bsdf_eval, &bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
+
+ if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
+ return LABEL_NONE;
+ }
+
+ /* Setup ray. Note that clipping works through transparent bounces. */
+ INTEGRATOR_STATE_WRITE(state, ray, P) = ray_offset(sd->P,
+ (label & LABEL_TRANSMIT) ? -sd->Ng : sd->Ng);
+ INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(bsdf_omega_in);
+ INTEGRATOR_STATE_WRITE(state, ray, t) = (label & LABEL_TRANSPARENT) ?
+ INTEGRATOR_STATE(state, ray, t) - sd->ray_length :
+ FLT_MAX;
+
+#ifdef __RAY_DIFFERENTIALS__
+ INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
+ INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_make_compact(bsdf_domega_in);
+#endif
+
+ /* Update throughput. */
+ float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ throughput *= bsdf_eval_sum(&bsdf_eval) / bsdf_pdf;
+ INTEGRATOR_STATE_WRITE(state, path, throughput) = throughput;
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
+ if (INTEGRATOR_STATE(state, path, bounce) == 0) {
+ INTEGRATOR_STATE_WRITE(state, path, diffuse_glossy_ratio) = bsdf_eval_diffuse_glossy_ratio(
+ &bsdf_eval);
+ }
+ }
+
+ /* Update path state */
+ if (label & LABEL_TRANSPARENT) {
+ INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) += sd->ray_length;
+ }
+ else {
+ INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = bsdf_pdf;
+ INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f;
+ INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
+ bsdf_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
+ }
+
+ path_state_next(kg, state, label);
+ return label;
+}
+
+#ifdef __VOLUME__
+ccl_device_forceinline bool integrate_surface_volume_only_bounce(IntegratorState state,
+ ccl_private ShaderData *sd)
+{
+ if (!path_state_volume_next(state)) {
+ return LABEL_NONE;
+ }
+
+ /* Setup ray position, direction stays unchanged. */
+ INTEGRATOR_STATE_WRITE(state, ray, P) = ray_offset(sd->P, -sd->Ng);
+
+ /* Clipping works through transparent. */
+ INTEGRATOR_STATE_WRITE(state, ray, t) -= sd->ray_length;
+
+# ifdef __RAY_DIFFERENTIALS__
+ INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
+# endif
+
+ INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) += sd->ray_length;
+
+ return LABEL_TRANSMIT | LABEL_TRANSPARENT;
+}
+#endif
+
+#if defined(__AO__)
+ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const ShaderData *ccl_restrict sd,
+ ccl_private const RNGState *ccl_restrict
+ rng_state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ if (!(kernel_data.kernel_features & KERNEL_FEATURE_AO_ADDITIVE) &&
+ !(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_CAMERA)) {
+ return;
+ }
+
+ float bsdf_u, bsdf_v;
+ path_state_rng_2D(kg, rng_state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
+
+ float3 ao_N;
+ const float3 ao_weight = shader_bsdf_ao(
+ kg, sd, kernel_data.integrator.ao_additive_factor, &ao_N);
+
+ float3 ao_D;
+ float ao_pdf;
+ sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
+
+ if (!(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f)) {
+ return;
+ }
+
+ Ray ray ccl_optional_struct_init;
+ ray.P = ray_offset(sd->P, sd->Ng);
+ ray.D = ao_D;
+ ray.t = kernel_data.integrator.ao_bounces_distance;
+ ray.time = sd->time;
+ ray.dP = differential_zero_compact();
+ ray.dD = differential_zero_compact();
+
+ /* Branch off shadow kernel. */
+ INTEGRATOR_SHADOW_PATH_INIT(shadow_state, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, ao);
+
+ /* Copy volume stack and enter/exit volume. */
+ integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state);
+
+ /* Write shadow ray and associated state to global memory. */
+ integrator_state_write_shadow_ray(kg, shadow_state, &ray);
+
+ /* Copy state from main path to shadow path. */
+ const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce);
+ const uint16_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce);
+ uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag) | PATH_RAY_SHADOW_FOR_AO;
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput) * shader_bsdf_alpha(kg, sd);
+
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, render_pixel_index) = INTEGRATOR_STATE(
+ state, path, render_pixel_index);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_offset) = INTEGRATOR_STATE(
+ state, path, rng_offset);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_hash) = INTEGRATOR_STATE(
+ state, path, rng_hash);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, sample) = INTEGRATOR_STATE(
+ state, path, sample);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, flag) = shadow_flag;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, bounce) = bounce;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transparent_bounce) = transparent_bounce;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput;
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_AO_ADDITIVE) {
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unshadowed_throughput) = ao_weight;
+ }
+}
+#endif /* defined(__AO__) */
+
+template<uint node_feature_mask>
+ccl_device bool integrate_surface(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+
+{
+ PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_SURFACE_SETUP);
+
+ /* Setup shader data. */
+ ShaderData sd;
+ integrate_surface_shader_setup(kg, state, &sd);
+ PROFILING_SHADER(sd.object, sd.shader);
+
+ int continue_path_label = 0;
+
+ /* Skip most work for volume bounding surface. */
+#ifdef __VOLUME__
+ if (!(sd.flag & SD_HAS_ONLY_VOLUME)) {
+#endif
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+#ifdef __SUBSURFACE__
+ /* Can skip shader evaluation for BSSRDF exit point without bump mapping. */
+ if (!(path_flag & PATH_RAY_SUBSURFACE) || ((sd.flag & SD_HAS_BSSRDF_BUMP)))
+#endif
+ {
+ /* Evaluate shader. */
+ PROFILING_EVENT(PROFILING_SHADE_SURFACE_EVAL);
+ shader_eval_surface<node_feature_mask>(kg, state, &sd, render_buffer, path_flag);
+
+ /* Initialize additional RNG for BSDFs. */
+ if (sd.flag & SD_BSDF_NEEDS_LCG) {
+ sd.lcg_state = lcg_state_init(INTEGRATOR_STATE(state, path, rng_hash),
+ INTEGRATOR_STATE(state, path, rng_offset),
+ INTEGRATOR_STATE(state, path, sample),
+ 0xb4bc3953);
+ }
+ }
+
+#ifdef __SUBSURFACE__
+ if (path_flag & PATH_RAY_SUBSURFACE) {
+ /* When coming from inside subsurface scattering, setup a diffuse
+ * closure to perform lighting at the exit point. */
+ subsurface_shader_data_setup(kg, state, &sd, path_flag);
+ INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_SUBSURFACE;
+ }
+#endif
+
+ shader_prepare_surface_closures(kg, state, &sd);
+
+#ifdef __HOLDOUT__
+ /* Evaluate holdout. */
+ if (!integrate_surface_holdout(kg, state, &sd, render_buffer)) {
+ return false;
+ }
+#endif
+
+#ifdef __EMISSION__
+ /* Write emission. */
+ if (sd.flag & SD_EMISSION) {
+ integrate_surface_emission(kg, state, &sd, render_buffer);
+ }
+#endif
+
+#ifdef __PASSES__
+ /* Write render passes. */
+ PROFILING_EVENT(PROFILING_SHADE_SURFACE_PASSES);
+ kernel_write_data_passes(kg, state, &sd, render_buffer);
+#endif
+
+ /* Load random number state. */
+ RNGState rng_state;
+ path_state_rng_load(state, &rng_state);
+
+ /* Perform path termination. Most paths have already been terminated in
+ * the intersect_closest kernel, this is just for emission and for dividing
+ * throughput by the probability at the right moment.
+ *
+ * Also ensure we don't do it twice for SSS at both the entry and exit point. */
+ if (!(path_flag & PATH_RAY_SUBSURFACE)) {
+ const float probability = (path_flag & PATH_RAY_TERMINATE_ON_NEXT_SURFACE) ?
+ 0.0f :
+ path_state_continuation_probability(kg, state, path_flag);
+ if (probability == 0.0f) {
+ return false;
+ }
+ else if (probability != 1.0f) {
+ INTEGRATOR_STATE_WRITE(state, path, throughput) /= probability;
+ }
+ }
+
+#ifdef __DENOISING_FEATURES__
+ kernel_write_denoising_features_surface(kg, state, &sd, render_buffer);
+#endif
+
+#ifdef __SHADOW_CATCHER__
+ kernel_write_shadow_catcher_bounce_data(kg, state, &sd, render_buffer);
+#endif
+
+ /* Direct light. */
+ PROFILING_EVENT(PROFILING_SHADE_SURFACE_DIRECT_LIGHT);
+ integrate_surface_direct_light(kg, state, &sd, &rng_state);
+
+#if defined(__AO__)
+ /* Ambient occlusion pass. */
+ if (kernel_data.kernel_features & KERNEL_FEATURE_AO) {
+ PROFILING_EVENT(PROFILING_SHADE_SURFACE_AO);
+ integrate_surface_ao(kg, state, &sd, &rng_state, render_buffer);
+ }
+#endif
+
+ PROFILING_EVENT(PROFILING_SHADE_SURFACE_INDIRECT_LIGHT);
+ continue_path_label = integrate_surface_bsdf_bssrdf_bounce(kg, state, &sd, &rng_state);
+#ifdef __VOLUME__
+ }
+ else {
+ PROFILING_EVENT(PROFILING_SHADE_SURFACE_INDIRECT_LIGHT);
+ continue_path_label = integrate_surface_volume_only_bounce(state, &sd);
+ }
+
+ if (continue_path_label & LABEL_TRANSMIT) {
+ /* Enter/Exit volume. */
+ volume_stack_enter_exit(kg, state, &sd);
+ }
+#endif
+
+ return continue_path_label != 0;
+}
+
+template<uint node_feature_mask = KERNEL_FEATURE_NODE_MASK_SURFACE & ~KERNEL_FEATURE_NODE_RAYTRACE,
+ int current_kernel = DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE>
+ccl_device_forceinline void integrator_shade_surface(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ if (integrate_surface<node_feature_mask>(kg, state, render_buffer)) {
+ if (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_SUBSURFACE) {
+ INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE);
+ }
+ else {
+ kernel_assert(INTEGRATOR_STATE(state, ray, t) != 0.0f);
+ INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
+ }
+ }
+ else {
+ INTEGRATOR_PATH_TERMINATE(current_kernel);
+ }
+}
+
+ccl_device_forceinline void integrator_shade_surface_raytrace(
+ KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
+{
+ integrator_shade_surface<KERNEL_FEATURE_NODE_MASK_SURFACE,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE>(
+ kg, state, render_buffer);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h
new file mode 100644
index 00000000000..f455152dcf9
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shade_volume.h
@@ -0,0 +1,1049 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/film/accumulate.h"
+#include "kernel/film/passes.h"
+
+#include "kernel/integrator/intersect_closest.h"
+#include "kernel/integrator/path_state.h"
+#include "kernel/integrator/shader_eval.h"
+#include "kernel/integrator/volume_stack.h"
+
+#include "kernel/light/light.h"
+#include "kernel/light/sample.h"
+
+#include "kernel/sample/mis.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __VOLUME__
+
+/* Events for probabilistic scattering. */
+
+typedef enum VolumeIntegrateEvent {
+ VOLUME_PATH_SCATTERED = 0,
+ VOLUME_PATH_ATTENUATED = 1,
+ VOLUME_PATH_MISSED = 2
+} VolumeIntegrateEvent;
+
+typedef struct VolumeIntegrateResult {
+ /* Throughput and offset for direct light scattering. */
+ bool direct_scatter;
+ float3 direct_throughput;
+ float direct_t;
+ ShaderVolumePhases direct_phases;
+
+ /* Throughput and offset for indirect light scattering. */
+ bool indirect_scatter;
+ float3 indirect_throughput;
+ float indirect_t;
+ ShaderVolumePhases indirect_phases;
+} VolumeIntegrateResult;
+
+/* Ignore paths that have volume throughput below this value, to avoid unnecessary work
+ * and precision issues.
+ * todo: this value could be tweaked or turned into a probability to avoid unnecessary
+ * work in volumes and subsurface scattering. */
+# define VOLUME_THROUGHPUT_EPSILON 1e-6f
+
+/* Volume shader properties
+ *
+ * extinction coefficient = absorption coefficient + scattering coefficient
+ * sigma_t = sigma_a + sigma_s */
+
+typedef struct VolumeShaderCoefficients {
+ float3 sigma_t;
+ float3 sigma_s;
+ float3 emission;
+} VolumeShaderCoefficients;
+
+/* Evaluate shader to get extinction coefficient at P. */
+ccl_device_inline bool shadow_volume_shader_sample(KernelGlobals kg,
+ IntegratorShadowState state,
+ ccl_private ShaderData *ccl_restrict sd,
+ ccl_private float3 *ccl_restrict extinction)
+{
+ shader_eval_volume<true>(kg, state, sd, PATH_RAY_SHADOW, [=](const int i) {
+ return integrator_state_read_shadow_volume_stack(state, i);
+ });
+
+ if (!(sd->flag & SD_EXTINCTION)) {
+ return false;
+ }
+
+ const float density = object_volume_density(kg, sd->object);
+ *extinction = sd->closure_transparent_extinction * density;
+ return true;
+}
+
+/* Evaluate shader to get absorption, scattering and emission at P. */
+ccl_device_inline bool volume_shader_sample(KernelGlobals kg,
+ IntegratorState state,
+ ccl_private ShaderData *ccl_restrict sd,
+ ccl_private VolumeShaderCoefficients *coeff)
+{
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+ shader_eval_volume<false>(kg, state, sd, path_flag, [=](const int i) {
+ return integrator_state_read_volume_stack(state, i);
+ });
+
+ if (!(sd->flag & (SD_EXTINCTION | SD_SCATTER | SD_EMISSION))) {
+ return false;
+ }
+
+ coeff->sigma_s = zero_float3();
+ coeff->sigma_t = (sd->flag & SD_EXTINCTION) ? sd->closure_transparent_extinction : zero_float3();
+ coeff->emission = (sd->flag & SD_EMISSION) ? sd->closure_emission_background : zero_float3();
+
+ if (sd->flag & SD_SCATTER) {
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (CLOSURE_IS_VOLUME(sc->type)) {
+ coeff->sigma_s += sc->weight;
+ }
+ }
+ }
+
+ const float density = object_volume_density(kg, sd->object);
+ coeff->sigma_s *= density;
+ coeff->sigma_t *= density;
+ coeff->emission *= density;
+
+ return true;
+}
+
+ccl_device_forceinline void volume_step_init(KernelGlobals kg,
+ ccl_private const RNGState *rng_state,
+ const float object_step_size,
+ float t,
+ ccl_private float *step_size,
+ ccl_private float *step_shade_offset,
+ ccl_private float *steps_offset,
+ ccl_private int *max_steps)
+{
+ if (object_step_size == FLT_MAX) {
+ /* Homogeneous volume. */
+ *step_size = t;
+ *step_shade_offset = 0.0f;
+ *steps_offset = 1.0f;
+ *max_steps = 1;
+ }
+ else {
+ /* Heterogeneous volume. */
+ *max_steps = kernel_data.integrator.volume_max_steps;
+ float step = min(object_step_size, t);
+
+ /* compute exact steps in advance for malloc */
+ if (t > *max_steps * step) {
+ step = t / (float)*max_steps;
+ }
+
+ *step_size = step;
+
+ /* Perform shading at this offset within a step, to integrate over
+ * over the entire step segment. */
+ *step_shade_offset = path_state_rng_1D_hash(kg, rng_state, 0x1e31d8a4);
+
+ /* Shift starting point of all segment by this random amount to avoid
+ * banding artifacts from the volume bounding shape. */
+ *steps_offset = path_state_rng_1D_hash(kg, rng_state, 0x3d22c7b3);
+ }
+}
+
+/* Volume Shadows
+ *
+ * These functions are used to attenuate shadow rays to lights. Both absorption
+ * and scattering will block light, represented by the extinction coefficient. */
+
+# if 0
+/* homogeneous volume: assume shader evaluation at the starts gives
+ * the extinction coefficient for the entire line segment */
+ccl_device void volume_shadow_homogeneous(KernelGlobals kg, IntegratorState state,
+ ccl_private Ray *ccl_restrict ray,
+ ccl_private ShaderData *ccl_restrict sd,
+ ccl_global float3 *ccl_restrict throughput)
+{
+ float3 sigma_t = zero_float3();
+
+ if (shadow_volume_shader_sample(kg, state, sd, &sigma_t)) {
+ *throughput *= volume_color_transmittance(sigma_t, ray->t);
+ }
+}
+# endif
+
+/* heterogeneous volume: integrate stepping through the volume until we
+ * reach the end, get absorbed entirely, or run out of iterations */
+ccl_device void volume_shadow_heterogeneous(KernelGlobals kg,
+ IntegratorShadowState state,
+ ccl_private Ray *ccl_restrict ray,
+ ccl_private ShaderData *ccl_restrict sd,
+ ccl_private float3 *ccl_restrict throughput,
+ const float object_step_size)
+{
+ /* Load random number state. */
+ RNGState rng_state;
+ shadow_path_state_rng_load(state, &rng_state);
+
+ float3 tp = *throughput;
+
+ /* Prepare for stepping.
+ * For shadows we do not offset all segments, since the starting point is
+ * already a random distance inside the volume. It also appears to create
+ * banding artifacts for unknown reasons. */
+ int max_steps;
+ float step_size, step_shade_offset, unused;
+ volume_step_init(kg,
+ &rng_state,
+ object_step_size,
+ ray->t,
+ &step_size,
+ &step_shade_offset,
+ &unused,
+ &max_steps);
+ const float steps_offset = 1.0f;
+
+ /* compute extinction at the start */
+ float t = 0.0f;
+
+ float3 sum = zero_float3();
+
+ for (int i = 0; i < max_steps; i++) {
+ /* advance to new position */
+ float new_t = min(ray->t, (i + steps_offset) * step_size);
+ float dt = new_t - t;
+
+ float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
+ float3 sigma_t = zero_float3();
+
+ /* compute attenuation over segment */
+ sd->P = new_P;
+ if (shadow_volume_shader_sample(kg, state, sd, &sigma_t)) {
+ /* Compute `expf()` only for every Nth step, to save some calculations
+ * because `exp(a)*exp(b) = exp(a+b)`, also do a quick #VOLUME_THROUGHPUT_EPSILON
+ * check then. */
+ sum += (-sigma_t * dt);
+ if ((i & 0x07) == 0) { /* TODO: Other interval? */
+ tp = *throughput * exp3(sum);
+
+ /* stop if nearly all light is blocked */
+ if (tp.x < VOLUME_THROUGHPUT_EPSILON && tp.y < VOLUME_THROUGHPUT_EPSILON &&
+ tp.z < VOLUME_THROUGHPUT_EPSILON)
+ break;
+ }
+ }
+
+ /* stop if at the end of the volume */
+ t = new_t;
+ if (t == ray->t) {
+ /* Update throughput in case we haven't done it above */
+ tp = *throughput * exp3(sum);
+ break;
+ }
+ }
+
+ *throughput = tp;
+}
+
+/* Equi-angular sampling as in:
+ * "Importance Sampling Techniques for Path Tracing in Participating Media" */
+
+ccl_device float volume_equiangular_sample(ccl_private const Ray *ccl_restrict ray,
+ const float3 light_P,
+ const float xi,
+ ccl_private float *pdf)
+{
+ const float t = ray->t;
+ const float delta = dot((light_P - ray->P), ray->D);
+ const float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
+ if (UNLIKELY(D == 0.0f)) {
+ *pdf = 0.0f;
+ return 0.0f;
+ }
+ const float theta_a = -atan2f(delta, D);
+ const float theta_b = atan2f(t - delta, D);
+ const float t_ = D * tanf((xi * theta_b) + (1 - xi) * theta_a);
+ if (UNLIKELY(theta_b == theta_a)) {
+ *pdf = 0.0f;
+ return 0.0f;
+ }
+ *pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
+
+ return min(t, delta + t_); /* min is only for float precision errors */
+}
+
+ccl_device float volume_equiangular_pdf(ccl_private const Ray *ccl_restrict ray,
+ const float3 light_P,
+ const float sample_t)
+{
+ const float delta = dot((light_P - ray->P), ray->D);
+ const float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
+ if (UNLIKELY(D == 0.0f)) {
+ return 0.0f;
+ }
+
+ const float t = ray->t;
+ const float t_ = sample_t - delta;
+
+ const float theta_a = -atan2f(delta, D);
+ const float theta_b = atan2f(t - delta, D);
+ if (UNLIKELY(theta_b == theta_a)) {
+ return 0.0f;
+ }
+
+ const float pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
+
+ return pdf;
+}
+
+ccl_device float volume_equiangular_cdf(ccl_private const Ray *ccl_restrict ray,
+ const float3 light_P,
+ const float sample_t)
+{
+ float delta = dot((light_P - ray->P), ray->D);
+ float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
+ if (UNLIKELY(D == 0.0f)) {
+ return 0.0f;
+ }
+
+ const float t = ray->t;
+ const float t_ = sample_t - delta;
+
+ const float theta_a = -atan2f(delta, D);
+ const float theta_b = atan2f(t - delta, D);
+ if (UNLIKELY(theta_b == theta_a)) {
+ return 0.0f;
+ }
+
+ const float theta_sample = atan2f(t_, D);
+ const float cdf = (theta_sample - theta_a) / (theta_b - theta_a);
+
+ return cdf;
+}
+
+/* Distance sampling */
+
+ccl_device float volume_distance_sample(float max_t,
+ float3 sigma_t,
+ int channel,
+ float xi,
+ ccl_private float3 *transmittance,
+ ccl_private float3 *pdf)
+{
+ /* xi is [0, 1[ so log(0) should never happen, division by zero is
+ * avoided because sample_sigma_t > 0 when SD_SCATTER is set */
+ float sample_sigma_t = volume_channel_get(sigma_t, channel);
+ float3 full_transmittance = volume_color_transmittance(sigma_t, max_t);
+ float sample_transmittance = volume_channel_get(full_transmittance, channel);
+
+ float sample_t = min(max_t, -logf(1.0f - xi * (1.0f - sample_transmittance)) / sample_sigma_t);
+
+ *transmittance = volume_color_transmittance(sigma_t, sample_t);
+ *pdf = safe_divide_color(sigma_t * *transmittance, one_float3() - full_transmittance);
+
+ /* todo: optimization: when taken together with hit/miss decision,
+ * the full_transmittance cancels out drops out and xi does not
+ * need to be remapped */
+
+ return sample_t;
+}
+
+ccl_device float3 volume_distance_pdf(float max_t, float3 sigma_t, float sample_t)
+{
+ float3 full_transmittance = volume_color_transmittance(sigma_t, max_t);
+ float3 transmittance = volume_color_transmittance(sigma_t, sample_t);
+
+ return safe_divide_color(sigma_t * transmittance, one_float3() - full_transmittance);
+}
+
+/* Emission */
+
+ccl_device float3 volume_emission_integrate(ccl_private VolumeShaderCoefficients *coeff,
+ int closure_flag,
+ float3 transmittance,
+ float t)
+{
+ /* integral E * exp(-sigma_t * t) from 0 to t = E * (1 - exp(-sigma_t * t))/sigma_t
+ * this goes to E * t as sigma_t goes to zero
+ *
+ * todo: we should use an epsilon to avoid precision issues near zero sigma_t */
+ float3 emission = coeff->emission;
+
+ if (closure_flag & SD_EXTINCTION) {
+ float3 sigma_t = coeff->sigma_t;
+
+ emission.x *= (sigma_t.x > 0.0f) ? (1.0f - transmittance.x) / sigma_t.x : t;
+ emission.y *= (sigma_t.y > 0.0f) ? (1.0f - transmittance.y) / sigma_t.y : t;
+ emission.z *= (sigma_t.z > 0.0f) ? (1.0f - transmittance.z) / sigma_t.z : t;
+ }
+ else
+ emission *= t;
+
+ return emission;
+}
+
+/* Volume Integration */
+
+typedef struct VolumeIntegrateState {
+ /* Volume segment extents. */
+ float start_t;
+ float end_t;
+
+ /* If volume is absorption-only up to this point, and no probabilistic
+ * scattering or termination has been used yet. */
+ bool absorption_only;
+
+ /* Random numbers for scattering. */
+ float rscatter;
+ float rphase;
+
+ /* Multiple importance sampling. */
+ VolumeSampleMethod direct_sample_method;
+ bool use_mis;
+ float distance_pdf;
+ float equiangular_pdf;
+} VolumeIntegrateState;
+
+ccl_device_forceinline void volume_integrate_step_scattering(
+ ccl_private const ShaderData *sd,
+ ccl_private const Ray *ray,
+ const float3 equiangular_light_P,
+ ccl_private const VolumeShaderCoefficients &ccl_restrict coeff,
+ const float3 transmittance,
+ ccl_private VolumeIntegrateState &ccl_restrict vstate,
+ ccl_private VolumeIntegrateResult &ccl_restrict result)
+{
+ /* Pick random color channel, we use the Veach one-sample
+ * model with balance heuristic for the channels. */
+ const float3 albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t);
+ float3 channel_pdf;
+ const int channel = volume_sample_channel(
+ albedo, result.indirect_throughput, vstate.rphase, &channel_pdf);
+
+ /* Equiangular sampling for direct lighting. */
+ if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR && !result.direct_scatter) {
+ if (result.direct_t >= vstate.start_t && result.direct_t <= vstate.end_t) {
+ const float new_dt = result.direct_t - vstate.start_t;
+ const float3 new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
+
+ result.direct_scatter = true;
+ result.direct_throughput *= coeff.sigma_s * new_transmittance / vstate.equiangular_pdf;
+ shader_copy_volume_phases(&result.direct_phases, sd);
+
+ /* Multiple importance sampling. */
+ if (vstate.use_mis) {
+ const float distance_pdf = vstate.distance_pdf *
+ dot(channel_pdf, coeff.sigma_t * new_transmittance);
+ const float mis_weight = 2.0f * power_heuristic(vstate.equiangular_pdf, distance_pdf);
+ result.direct_throughput *= mis_weight;
+ }
+ }
+ else {
+ result.direct_throughput *= transmittance;
+ vstate.distance_pdf *= dot(channel_pdf, transmittance);
+ }
+ }
+
+ /* Distance sampling for indirect and optional direct lighting. */
+ if (!result.indirect_scatter) {
+ /* decide if we will scatter or continue */
+ const float sample_transmittance = volume_channel_get(transmittance, channel);
+
+ if (1.0f - vstate.rscatter >= sample_transmittance) {
+ /* compute sampling distance */
+ const float sample_sigma_t = volume_channel_get(coeff.sigma_t, channel);
+ const float new_dt = -logf(1.0f - vstate.rscatter) / sample_sigma_t;
+ const float new_t = vstate.start_t + new_dt;
+
+ /* transmittance and pdf */
+ const float3 new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
+ const float distance_pdf = dot(channel_pdf, coeff.sigma_t * new_transmittance);
+
+ /* throughput */
+ result.indirect_scatter = true;
+ result.indirect_t = new_t;
+ result.indirect_throughput *= coeff.sigma_s * new_transmittance / distance_pdf;
+ shader_copy_volume_phases(&result.indirect_phases, sd);
+
+ if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
+ /* If using distance sampling for direct light, just copy parameters
+ * of indirect light since we scatter at the same point then. */
+ result.direct_scatter = true;
+ result.direct_t = result.indirect_t;
+ result.direct_throughput = result.indirect_throughput;
+ shader_copy_volume_phases(&result.direct_phases, sd);
+
+ /* Multiple importance sampling. */
+ if (vstate.use_mis) {
+ const float equiangular_pdf = volume_equiangular_pdf(ray, equiangular_light_P, new_t);
+ const float mis_weight = power_heuristic(vstate.distance_pdf * distance_pdf,
+ equiangular_pdf);
+ result.direct_throughput *= 2.0f * mis_weight;
+ }
+ }
+ }
+ else {
+ /* throughput */
+ const float pdf = dot(channel_pdf, transmittance);
+ result.indirect_throughput *= transmittance / pdf;
+ if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
+ vstate.distance_pdf *= pdf;
+ }
+
+ /* remap rscatter so we can reuse it and keep thing stratified */
+ vstate.rscatter = 1.0f - (1.0f - vstate.rscatter) / sample_transmittance;
+ }
+ }
+}
+
+/* heterogeneous volume distance sampling: integrate stepping through the
+ * volume until we reach the end, get absorbed entirely, or run out of
+ * iterations. this does probabilistically scatter or get transmitted through
+ * for path tracing where we don't want to branch. */
+ccl_device_forceinline void volume_integrate_heterogeneous(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private Ray *ccl_restrict ray,
+ ccl_private ShaderData *ccl_restrict sd,
+ ccl_private const RNGState *rng_state,
+ ccl_global float *ccl_restrict render_buffer,
+ const float object_step_size,
+ const VolumeSampleMethod direct_sample_method,
+ const float3 equiangular_light_P,
+ ccl_private VolumeIntegrateResult &result)
+{
+ PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_INTEGRATE);
+
+ /* Prepare for stepping.
+ * Using a different step offset for the first step avoids banding artifacts. */
+ int max_steps;
+ float step_size, step_shade_offset, steps_offset;
+ volume_step_init(kg,
+ rng_state,
+ object_step_size,
+ ray->t,
+ &step_size,
+ &step_shade_offset,
+ &steps_offset,
+ &max_steps);
+
+ /* Initialize volume integration state. */
+ VolumeIntegrateState vstate ccl_optional_struct_init;
+ vstate.start_t = 0.0f;
+ vstate.end_t = 0.0f;
+ vstate.absorption_only = true;
+ vstate.rscatter = path_state_rng_1D(kg, rng_state, PRNG_SCATTER_DISTANCE);
+ vstate.rphase = path_state_rng_1D(kg, rng_state, PRNG_PHASE_CHANNEL);
+
+ /* Multiple importance sampling: pick between equiangular and distance sampling strategy. */
+ vstate.direct_sample_method = direct_sample_method;
+ vstate.use_mis = (direct_sample_method == VOLUME_SAMPLE_MIS);
+ if (vstate.use_mis) {
+ if (vstate.rscatter < 0.5f) {
+ vstate.rscatter *= 2.0f;
+ vstate.direct_sample_method = VOLUME_SAMPLE_DISTANCE;
+ }
+ else {
+ vstate.rscatter = (vstate.rscatter - 0.5f) * 2.0f;
+ vstate.direct_sample_method = VOLUME_SAMPLE_EQUIANGULAR;
+ }
+ }
+ vstate.equiangular_pdf = 0.0f;
+ vstate.distance_pdf = 1.0f;
+
+ /* Initialize volume integration result. */
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ result.direct_throughput = throughput;
+ result.indirect_throughput = throughput;
+
+ /* Equiangular sampling: compute distance and PDF in advance. */
+ if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
+ result.direct_t = volume_equiangular_sample(
+ ray, equiangular_light_P, vstate.rscatter, &vstate.equiangular_pdf);
+ }
+
+# ifdef __DENOISING_FEATURES__
+ const bool write_denoising_features = (INTEGRATOR_STATE(state, path, flag) &
+ PATH_RAY_DENOISING_FEATURES);
+ float3 accum_albedo = zero_float3();
+# endif
+ float3 accum_emission = zero_float3();
+
+ for (int i = 0; i < max_steps; i++) {
+ /* Advance to new position */
+ vstate.end_t = min(ray->t, (i + steps_offset) * step_size);
+ const float shade_t = vstate.start_t + (vstate.end_t - vstate.start_t) * step_shade_offset;
+ sd->P = ray->P + ray->D * shade_t;
+
+ /* compute segment */
+ VolumeShaderCoefficients coeff ccl_optional_struct_init;
+ if (volume_shader_sample(kg, state, sd, &coeff)) {
+ const int closure_flag = sd->flag;
+
+ /* Evaluate transmittance over segment. */
+ const float dt = (vstate.end_t - vstate.start_t);
+ const float3 transmittance = (closure_flag & SD_EXTINCTION) ?
+ volume_color_transmittance(coeff.sigma_t, dt) :
+ one_float3();
+
+ /* Emission. */
+ if (closure_flag & SD_EMISSION) {
+ /* Only write emission before indirect light scatter position, since we terminate
+ * stepping at that point if we have already found a direct light scatter position. */
+ if (!result.indirect_scatter) {
+ const float3 emission = volume_emission_integrate(
+ &coeff, closure_flag, transmittance, dt);
+ accum_emission += emission;
+ }
+ }
+
+ if (closure_flag & SD_EXTINCTION) {
+ if ((closure_flag & SD_SCATTER) || !vstate.absorption_only) {
+# ifdef __DENOISING_FEATURES__
+ /* Accumulate albedo for denoising features. */
+ if (write_denoising_features && (closure_flag & SD_SCATTER)) {
+ const float3 albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t);
+ accum_albedo += result.indirect_throughput * albedo * (one_float3() - transmittance);
+ }
+# endif
+
+ /* Scattering and absorption. */
+ volume_integrate_step_scattering(
+ sd, ray, equiangular_light_P, coeff, transmittance, vstate, result);
+ }
+ else {
+ /* Absorption only. */
+ result.indirect_throughput *= transmittance;
+ result.direct_throughput *= transmittance;
+ }
+
+ /* Stop if nearly all light blocked. */
+ if (!result.indirect_scatter) {
+ if (max3(result.indirect_throughput) < VOLUME_THROUGHPUT_EPSILON) {
+ result.indirect_throughput = zero_float3();
+ break;
+ }
+ }
+ else if (!result.direct_scatter) {
+ if (max3(result.direct_throughput) < VOLUME_THROUGHPUT_EPSILON) {
+ break;
+ }
+ }
+ }
+
+ /* If we have scattering data for both direct and indirect, we're done. */
+ if (result.direct_scatter && result.indirect_scatter) {
+ break;
+ }
+ }
+
+ /* Stop if at the end of the volume. */
+ vstate.start_t = vstate.end_t;
+ if (vstate.start_t == ray->t) {
+ break;
+ }
+ }
+
+ /* Write accumulated emission. */
+ if (!is_zero(accum_emission)) {
+ kernel_accum_emission(kg, state, result.indirect_throughput, accum_emission, render_buffer);
+ }
+
+# ifdef __DENOISING_FEATURES__
+ /* Write denoising features. */
+ if (write_denoising_features) {
+ kernel_write_denoising_features_volume(
+ kg, state, accum_albedo, result.indirect_scatter, render_buffer);
+ }
+# endif /* __DENOISING_FEATURES__ */
+}
+
+# ifdef __EMISSION__
+/* Path tracing: sample point on light and evaluate light shader, then
+ * queue shadow ray to be traced. */
+ccl_device_forceinline bool integrate_volume_sample_light(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const ShaderData *ccl_restrict sd,
+ ccl_private const RNGState *ccl_restrict rng_state,
+ ccl_private LightSample *ccl_restrict ls)
+{
+ /* Test if there is a light or BSDF that needs direct light. */
+ if (!kernel_data.integrator.use_direct_light) {
+ return false;
+ }
+
+ /* Sample position on a light. */
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+ const uint bounce = INTEGRATOR_STATE(state, path, bounce);
+ float light_u, light_v;
+ path_state_rng_2D(kg, rng_state, PRNG_LIGHT_U, &light_u, &light_v);
+
+ light_distribution_sample_from_volume_segment(
+ kg, light_u, light_v, sd->time, sd->P, bounce, path_flag, ls);
+
+ if (ls->shader & SHADER_EXCLUDE_SCATTER) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Path tracing: sample point on light and evaluate light shader, then
+ * queue shadow ray to be traced. */
+ccl_device_forceinline void integrate_volume_direct_light(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const ShaderData *ccl_restrict sd,
+ ccl_private const RNGState *ccl_restrict rng_state,
+ const float3 P,
+ ccl_private const ShaderVolumePhases *ccl_restrict phases,
+ ccl_private const float3 throughput,
+ ccl_private LightSample *ccl_restrict ls)
+{
+ PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_DIRECT_LIGHT);
+
+ if (!kernel_data.integrator.use_direct_light) {
+ return;
+ }
+
+ /* Sample position on the same light again, now from the shading
+ * point where we scattered.
+ *
+ * TODO: decorrelate random numbers and use light_sample_new_position to
+ * avoid resampling the CDF. */
+ {
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+ const uint bounce = INTEGRATOR_STATE(state, path, bounce);
+ float light_u, light_v;
+ path_state_rng_2D(kg, rng_state, PRNG_LIGHT_U, &light_u, &light_v);
+
+ if (!light_distribution_sample_from_position(
+ kg, light_u, light_v, sd->time, P, bounce, path_flag, ls)) {
+ return;
+ }
+ }
+
+ if (ls->shader & SHADER_EXCLUDE_SCATTER) {
+ return;
+ }
+
+ /* Evaluate light shader.
+ *
+ * TODO: can we reuse sd memory? In theory we can move this after
+ * integrate_surface_bounce, evaluate the BSDF, and only then evaluate
+ * the light shader. This could also move to its own kernel, for
+ * non-constant light sources. */
+ ShaderDataTinyStorage emission_sd_storage;
+ ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
+ const float3 light_eval = light_sample_shader_eval(kg, state, emission_sd, ls, sd->time);
+ if (is_zero(light_eval)) {
+ return;
+ }
+
+ /* Evaluate BSDF. */
+ BsdfEval phase_eval ccl_optional_struct_init;
+ const float phase_pdf = shader_volume_phase_eval(kg, sd, phases, ls->D, &phase_eval);
+
+ if (ls->shader & SHADER_USE_MIS) {
+ float mis_weight = power_heuristic(ls->pdf, phase_pdf);
+ bsdf_eval_mul(&phase_eval, mis_weight);
+ }
+
+ bsdf_eval_mul3(&phase_eval, light_eval / ls->pdf);
+
+ /* Path termination. */
+ const float terminate = path_state_rng_light_termination(kg, rng_state);
+ if (light_sample_terminate(kg, ls, &phase_eval, terminate)) {
+ return;
+ }
+
+ /* Create shadow ray. */
+ Ray ray ccl_optional_struct_init;
+ light_sample_to_volume_shadow_ray(kg, sd, ls, P, &ray);
+ const bool is_light = light_sample_is_light(ls);
+
+ /* Branch off shadow kernel. */
+ INTEGRATOR_SHADOW_PATH_INIT(
+ shadow_state, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, shadow);
+
+ /* Write shadow ray and associated state to global memory. */
+ integrator_state_write_shadow_ray(kg, shadow_state, &ray);
+
+ /* Copy state from main path to shadow path. */
+ const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce);
+ const uint16_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce);
+ uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag);
+ shadow_flag |= (is_light) ? PATH_RAY_SHADOW_FOR_LIGHT : 0;
+ shadow_flag |= PATH_RAY_VOLUME_PASS;
+ const float3 throughput_phase = throughput * bsdf_eval_sum(&phase_eval);
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
+ const float3 diffuse_glossy_ratio = (bounce == 0) ?
+ one_float3() :
+ INTEGRATOR_STATE(state, path, diffuse_glossy_ratio);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, diffuse_glossy_ratio) = diffuse_glossy_ratio;
+ }
+
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, render_pixel_index) = INTEGRATOR_STATE(
+ state, path, render_pixel_index);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_offset) = INTEGRATOR_STATE(
+ state, path, rng_offset);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_hash) = INTEGRATOR_STATE(
+ state, path, rng_hash);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, sample) = INTEGRATOR_STATE(
+ state, path, sample);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, flag) = shadow_flag;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, bounce) = bounce;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transparent_bounce) = transparent_bounce;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, diffuse_bounce) = INTEGRATOR_STATE(
+ state, path, diffuse_bounce);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, glossy_bounce) = INTEGRATOR_STATE(
+ state, path, glossy_bounce);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transmission_bounce) = INTEGRATOR_STATE(
+ state, path, transmission_bounce);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput_phase;
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_PASS) {
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unshadowed_throughput) = throughput;
+ }
+
+ integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state);
+}
+# endif
+
+/* Path tracing: scatter in new direction using phase function */
+ccl_device_forceinline bool integrate_volume_phase_scatter(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private ShaderData *sd,
+ ccl_private const RNGState *rng_state,
+ ccl_private const ShaderVolumePhases *phases)
+{
+ PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_INDIRECT_LIGHT);
+
+ float phase_u, phase_v;
+ path_state_rng_2D(kg, rng_state, PRNG_BSDF_U, &phase_u, &phase_v);
+
+ /* Phase closure, sample direction. */
+ float phase_pdf;
+ BsdfEval phase_eval ccl_optional_struct_init;
+ float3 phase_omega_in ccl_optional_struct_init;
+ differential3 phase_domega_in ccl_optional_struct_init;
+
+ const int label = shader_volume_phase_sample(kg,
+ sd,
+ phases,
+ phase_u,
+ phase_v,
+ &phase_eval,
+ &phase_omega_in,
+ &phase_domega_in,
+ &phase_pdf);
+
+ if (phase_pdf == 0.0f || bsdf_eval_is_zero(&phase_eval)) {
+ return false;
+ }
+
+ /* Setup ray. */
+ INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
+ INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(phase_omega_in);
+ INTEGRATOR_STATE_WRITE(state, ray, t) = FLT_MAX;
+
+# ifdef __RAY_DIFFERENTIALS__
+ INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
+ INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_make_compact(phase_domega_in);
+# endif
+
+ /* Update throughput. */
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
+ const float3 throughput_phase = throughput * bsdf_eval_sum(&phase_eval) / phase_pdf;
+ INTEGRATOR_STATE_WRITE(state, path, throughput) = throughput_phase;
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
+ INTEGRATOR_STATE_WRITE(state, path, diffuse_glossy_ratio) = one_float3();
+ }
+
+ /* Update path state */
+ INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = phase_pdf;
+ INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f;
+ INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
+ phase_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
+
+ path_state_next(kg, state, label);
+ return true;
+}
+
+/* get the volume attenuation and emission over line segment defined by
+ * ray, with the assumption that there are no surfaces blocking light
+ * between the endpoints. distance sampling is used to decide if we will
+ * scatter or not. */
+ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
+ IntegratorState state,
+ ccl_private Ray *ccl_restrict ray,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ ShaderData sd;
+ shader_setup_from_volume(kg, &sd, ray);
+
+ /* Load random number state. */
+ RNGState rng_state;
+ path_state_rng_load(state, &rng_state);
+
+ /* Sample light ahead of volume stepping, for equiangular sampling. */
+ /* TODO: distant lights are ignored now, but could instead use even distribution. */
+ LightSample ls ccl_optional_struct_init;
+ const bool need_light_sample = !(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_TERMINATE);
+ const bool have_equiangular_sample = need_light_sample &&
+ integrate_volume_sample_light(
+ kg, state, &sd, &rng_state, &ls) &&
+ (ls.t != FLT_MAX);
+
+ VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ?
+ volume_stack_sample_method(kg, state) :
+ VOLUME_SAMPLE_DISTANCE;
+
+ /* Step through volume. */
+ const float step_size = volume_stack_step_size(
+ kg, [=](const int i) { return integrator_state_read_volume_stack(state, i); });
+
+ /* TODO: expensive to zero closures? */
+ VolumeIntegrateResult result = {};
+ volume_integrate_heterogeneous(kg,
+ state,
+ ray,
+ &sd,
+ &rng_state,
+ render_buffer,
+ step_size,
+ direct_sample_method,
+ ls.P,
+ result);
+
+ /* Perform path termination. The intersect_closest will have already marked this path
+ * to be terminated. That will shading evaluating to leave out any scattering closures,
+ * but emission and absorption are still handled for multiple importance sampling. */
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+ const float probability = (path_flag & PATH_RAY_TERMINATE_IN_NEXT_VOLUME) ?
+ 0.0f :
+ path_state_continuation_probability(kg, state, path_flag);
+ if (probability == 0.0f) {
+ return VOLUME_PATH_MISSED;
+ }
+
+ /* Direct light. */
+ if (result.direct_scatter) {
+ const float3 direct_P = ray->P + result.direct_t * ray->D;
+ result.direct_throughput /= probability;
+ integrate_volume_direct_light(kg,
+ state,
+ &sd,
+ &rng_state,
+ direct_P,
+ &result.direct_phases,
+ result.direct_throughput,
+ &ls);
+ }
+
+ /* Indirect light.
+ *
+ * Only divide throughput by probability if we scatter. For the attenuation
+ * case the next surface will already do this division. */
+ if (result.indirect_scatter) {
+ result.indirect_throughput /= probability;
+ }
+ INTEGRATOR_STATE_WRITE(state, path, throughput) = result.indirect_throughput;
+
+ if (result.indirect_scatter) {
+ sd.P = ray->P + result.indirect_t * ray->D;
+
+ if (integrate_volume_phase_scatter(kg, state, &sd, &rng_state, &result.indirect_phases)) {
+ return VOLUME_PATH_SCATTERED;
+ }
+ else {
+ return VOLUME_PATH_MISSED;
+ }
+ }
+ else {
+ return VOLUME_PATH_ATTENUATED;
+ }
+}
+
+#endif
+
+ccl_device void integrator_shade_volume(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_SETUP);
+
+#ifdef __VOLUME__
+ /* Setup shader data. */
+ Ray ray ccl_optional_struct_init;
+ integrator_state_read_ray(kg, state, &ray);
+
+ Intersection isect ccl_optional_struct_init;
+ integrator_state_read_isect(kg, state, &isect);
+
+ /* Set ray length to current segment. */
+ ray.t = (isect.prim != PRIM_NONE) ? isect.t : FLT_MAX;
+
+ /* Clean volume stack for background rays. */
+ if (isect.prim == PRIM_NONE) {
+ volume_stack_clean(kg, state);
+ }
+
+ VolumeIntegrateEvent event = volume_integrate(kg, state, &ray, render_buffer);
+
+ if (event == VOLUME_PATH_SCATTERED) {
+ /* Queue intersect_closest kernel. */
+ INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
+ return;
+ }
+ else if (event == VOLUME_PATH_MISSED) {
+ /* End path. */
+ INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
+ return;
+ }
+ else {
+ /* Continue to background, light or surface. */
+ if (isect.prim == PRIM_NONE) {
+ INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ return;
+ }
+ else if (isect.type & PRIMITIVE_LAMP) {
+ INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
+ return;
+ }
+ else {
+ /* Hit a surface, continue with surface kernel unless terminated. */
+ const int shader = intersection_get_shader(kg, &isect);
+ const int flags = kernel_tex_fetch(__shaders, shader).flags;
+
+ integrator_intersect_shader_next_kernel<DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME>(
+ kg, state, &isect, shader, flags);
+ return;
+ }
+ }
+#endif /* __VOLUME__ */
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shader_eval.h b/intern/cycles/kernel/integrator/shader_eval.h
new file mode 100644
index 00000000000..68f1ef8c118
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shader_eval.h
@@ -0,0 +1,869 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Functions to evaluate shaders and use the resulting shader closures. */
+
+#pragma once
+
+#include "kernel/closure/alloc.h"
+#include "kernel/closure/bsdf.h"
+#include "kernel/closure/bsdf_util.h"
+#include "kernel/closure/emissive.h"
+
+#include "kernel/film/accumulate.h"
+
+#include "kernel/svm/svm.h"
+
+#ifdef __OSL__
+# include "kernel/osl/shader.h"
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* Merging */
+
+#if defined(__VOLUME__)
+ccl_device_inline void shader_merge_volume_closures(ccl_private ShaderData *sd)
+{
+ /* Merge identical closures to save closure space with stacked volumes. */
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private ShaderClosure *sci = &sd->closure[i];
+
+ if (sci->type != CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) {
+ continue;
+ }
+
+ for (int j = i + 1; j < sd->num_closure; j++) {
+ ccl_private ShaderClosure *scj = &sd->closure[j];
+ if (sci->type != scj->type) {
+ continue;
+ }
+
+ ccl_private const HenyeyGreensteinVolume *hgi = (ccl_private const HenyeyGreensteinVolume *)
+ sci;
+ ccl_private const HenyeyGreensteinVolume *hgj = (ccl_private const HenyeyGreensteinVolume *)
+ scj;
+ if (!(hgi->g == hgj->g)) {
+ continue;
+ }
+
+ sci->weight += scj->weight;
+ sci->sample_weight += scj->sample_weight;
+
+ int size = sd->num_closure - (j + 1);
+ if (size > 0) {
+ for (int k = 0; k < size; k++) {
+ scj[k] = scj[k + 1];
+ }
+ }
+
+ sd->num_closure--;
+ kernel_assert(sd->num_closure >= 0);
+ j--;
+ }
+ }
+}
+
+ccl_device_inline void shader_copy_volume_phases(ccl_private ShaderVolumePhases *ccl_restrict
+ phases,
+ ccl_private const ShaderData *ccl_restrict sd)
+{
+ phases->num_closure = 0;
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *from_sc = &sd->closure[i];
+ ccl_private const HenyeyGreensteinVolume *from_hg =
+ (ccl_private const HenyeyGreensteinVolume *)from_sc;
+
+ if (from_sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) {
+ ccl_private ShaderVolumeClosure *to_sc = &phases->closure[phases->num_closure];
+
+ to_sc->weight = from_sc->weight;
+ to_sc->sample_weight = from_sc->sample_weight;
+ to_sc->g = from_hg->g;
+ phases->num_closure++;
+ if (phases->num_closure >= MAX_VOLUME_CLOSURE) {
+ break;
+ }
+ }
+ }
+}
+#endif /* __VOLUME__ */
+
+ccl_device_inline void shader_prepare_surface_closures(KernelGlobals kg,
+ ConstIntegratorState state,
+ ccl_private ShaderData *sd)
+{
+ /* Defensive sampling.
+ *
+ * We can likely also do defensive sampling at deeper bounces, particularly
+ * for cases like a perfect mirror but possibly also others. This will need
+ * a good heuristic. */
+ if (INTEGRATOR_STATE(state, path, bounce) + INTEGRATOR_STATE(state, path, transparent_bounce) ==
+ 0 &&
+ sd->num_closure > 1) {
+ float sum = 0.0f;
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private ShaderClosure *sc = &sd->closure[i];
+ if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
+ sum += sc->sample_weight;
+ }
+ }
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private ShaderClosure *sc = &sd->closure[i];
+ if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
+ sc->sample_weight = max(sc->sample_weight, 0.125f * sum);
+ }
+ }
+ }
+
+ /* Filter glossy.
+ *
+ * Blurring of bsdf after bounces, for rays that have a small likelihood
+ * of following this particular path (diffuse, rough glossy) */
+ if (kernel_data.integrator.filter_glossy != FLT_MAX) {
+ float blur_pdf = kernel_data.integrator.filter_glossy *
+ INTEGRATOR_STATE(state, path, min_ray_pdf);
+
+ if (blur_pdf < 1.0f) {
+ float blur_roughness = sqrtf(1.0f - blur_pdf) * 0.5f;
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private ShaderClosure *sc = &sd->closure[i];
+ if (CLOSURE_IS_BSDF(sc->type)) {
+ bsdf_blur(kg, sc, blur_roughness);
+ }
+ }
+ }
+ }
+}
+
+/* BSDF */
+
+ccl_device_inline bool shader_bsdf_is_transmission(ccl_private const ShaderData *sd,
+ const float3 omega_in)
+{
+ return dot(sd->N, omega_in) < 0.0f;
+}
+
+ccl_device_forceinline bool _shader_bsdf_exclude(ClosureType type, uint light_shader_flags)
+{
+ if (!(light_shader_flags & SHADER_EXCLUDE_ANY)) {
+ return false;
+ }
+ if (light_shader_flags & SHADER_EXCLUDE_DIFFUSE) {
+ if (CLOSURE_IS_BSDF_DIFFUSE(type)) {
+ return true;
+ }
+ }
+ if (light_shader_flags & SHADER_EXCLUDE_GLOSSY) {
+ if (CLOSURE_IS_BSDF_GLOSSY(type)) {
+ return true;
+ }
+ }
+ if (light_shader_flags & SHADER_EXCLUDE_TRANSMIT) {
+ if (CLOSURE_IS_BSDF_TRANSMISSION(type)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+ccl_device_inline float _shader_bsdf_multi_eval(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ const float3 omega_in,
+ const bool is_transmission,
+ ccl_private const ShaderClosure *skip_sc,
+ ccl_private BsdfEval *result_eval,
+ float sum_pdf,
+ float sum_sample_weight,
+ const uint light_shader_flags)
+{
+ /* This is the veach one-sample model with balance heuristic,
+ * some PDF factors drop out when using balance heuristic weighting. */
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (sc == skip_sc) {
+ continue;
+ }
+
+ if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
+ if (CLOSURE_IS_BSDF(sc->type) && !_shader_bsdf_exclude(sc->type, light_shader_flags)) {
+ float bsdf_pdf = 0.0f;
+ float3 eval = bsdf_eval(kg, sd, sc, omega_in, is_transmission, &bsdf_pdf);
+
+ if (bsdf_pdf != 0.0f) {
+ const bool is_diffuse = CLOSURE_IS_BSDF_DIFFUSE(sc->type);
+ bsdf_eval_accum(result_eval, is_diffuse, eval * sc->weight, 1.0f);
+ sum_pdf += bsdf_pdf * sc->sample_weight;
+ }
+ }
+
+ sum_sample_weight += sc->sample_weight;
+ }
+ }
+
+ return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f;
+}
+
+#ifndef __KERNEL_CUDA__
+ccl_device
+#else
+ccl_device_inline
+#endif
+ float
+ shader_bsdf_eval(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ const float3 omega_in,
+ const bool is_transmission,
+ ccl_private BsdfEval *bsdf_eval,
+ const uint light_shader_flags)
+{
+ bsdf_eval_init(bsdf_eval, false, zero_float3());
+
+ return _shader_bsdf_multi_eval(
+ kg, sd, omega_in, is_transmission, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
+}
+
+/* Randomly sample a BSSRDF or BSDF proportional to ShaderClosure.sample_weight. */
+ccl_device_inline ccl_private const ShaderClosure *shader_bsdf_bssrdf_pick(
+ ccl_private const ShaderData *ccl_restrict sd, ccl_private float *randu)
+{
+ int sampled = 0;
+
+ if (sd->num_closure > 1) {
+ /* Pick a BSDF or based on sample weights. */
+ float sum = 0.0f;
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
+ sum += sc->sample_weight;
+ }
+ }
+
+ float r = (*randu) * sum;
+ float partial_sum = 0.0f;
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
+ float next_sum = partial_sum + sc->sample_weight;
+
+ if (r < next_sum) {
+ sampled = i;
+
+ /* Rescale to reuse for direction sample, to better preserve stratification. */
+ *randu = (r - partial_sum) / sc->sample_weight;
+ break;
+ }
+
+ partial_sum = next_sum;
+ }
+ }
+ }
+
+ return &sd->closure[sampled];
+}
+
+/* Return weight for picked BSSRDF. */
+ccl_device_inline float3
+shader_bssrdf_sample_weight(ccl_private const ShaderData *ccl_restrict sd,
+ ccl_private const ShaderClosure *ccl_restrict bssrdf_sc)
+{
+ float3 weight = bssrdf_sc->weight;
+
+ if (sd->num_closure > 1) {
+ float sum = 0.0f;
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
+ sum += sc->sample_weight;
+ }
+ }
+ weight *= sum / bssrdf_sc->sample_weight;
+ }
+
+ return weight;
+}
+
+/* Sample direction for picked BSDF, and return evaluation and pdf for all
+ * BSDFs combined using MIS. */
+ccl_device int shader_bsdf_sample_closure(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private const ShaderClosure *sc,
+ float randu,
+ float randv,
+ ccl_private BsdfEval *bsdf_eval,
+ ccl_private float3 *omega_in,
+ ccl_private differential3 *domega_in,
+ ccl_private float *pdf)
+{
+ /* BSSRDF should already have been handled elsewhere. */
+ kernel_assert(CLOSURE_IS_BSDF(sc->type));
+
+ int label;
+ float3 eval = zero_float3();
+
+ *pdf = 0.0f;
+ label = bsdf_sample(kg, sd, sc, randu, randv, &eval, omega_in, domega_in, pdf);
+
+ if (*pdf != 0.0f) {
+ const bool is_diffuse = CLOSURE_IS_BSDF_DIFFUSE(sc->type);
+ bsdf_eval_init(bsdf_eval, is_diffuse, eval * sc->weight);
+
+ if (sd->num_closure > 1) {
+ const bool is_transmission = shader_bsdf_is_transmission(sd, *omega_in);
+ float sweight = sc->sample_weight;
+ *pdf = _shader_bsdf_multi_eval(
+ kg, sd, *omega_in, is_transmission, sc, bsdf_eval, *pdf * sweight, sweight, 0);
+ }
+ }
+
+ return label;
+}
+
+ccl_device float shader_bsdf_average_roughness(ccl_private const ShaderData *sd)
+{
+ float roughness = 0.0f;
+ float sum_weight = 0.0f;
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (CLOSURE_IS_BSDF(sc->type)) {
+ /* sqrt once to undo the squaring from multiplying roughness on the
+ * two axes, and once for the squared roughness convention. */
+ float weight = fabsf(average(sc->weight));
+ roughness += weight * sqrtf(safe_sqrtf(bsdf_get_roughness_squared(sc)));
+ sum_weight += weight;
+ }
+ }
+
+ return (sum_weight > 0.0f) ? roughness / sum_weight : 0.0f;
+}
+
+ccl_device float3 shader_bsdf_transparency(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ if (sd->flag & SD_HAS_ONLY_VOLUME) {
+ return one_float3();
+ }
+ else if (sd->flag & SD_TRANSPARENT) {
+ return sd->closure_transparent_extinction;
+ }
+ else {
+ return zero_float3();
+ }
+}
+
+ccl_device void shader_bsdf_disable_transparency(KernelGlobals kg, ccl_private ShaderData *sd)
+{
+ if (sd->flag & SD_TRANSPARENT) {
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private ShaderClosure *sc = &sd->closure[i];
+
+ if (sc->type == CLOSURE_BSDF_TRANSPARENT_ID) {
+ sc->sample_weight = 0.0f;
+ sc->weight = zero_float3();
+ }
+ }
+
+ sd->flag &= ~SD_TRANSPARENT;
+ }
+}
+
+ccl_device float3 shader_bsdf_alpha(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ float3 alpha = one_float3() - shader_bsdf_transparency(kg, sd);
+
+ alpha = max(alpha, zero_float3());
+ alpha = min(alpha, one_float3());
+
+ return alpha;
+}
+
+ccl_device float3 shader_bsdf_diffuse(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ float3 eval = zero_float3();
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type))
+ eval += sc->weight;
+ }
+
+ return eval;
+}
+
+ccl_device float3 shader_bsdf_glossy(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ float3 eval = zero_float3();
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (CLOSURE_IS_BSDF_GLOSSY(sc->type))
+ eval += sc->weight;
+ }
+
+ return eval;
+}
+
+ccl_device float3 shader_bsdf_transmission(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ float3 eval = zero_float3();
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type))
+ eval += sc->weight;
+ }
+
+ return eval;
+}
+
+ccl_device float3 shader_bsdf_average_normal(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ float3 N = zero_float3();
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+ if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type))
+ N += sc->N * fabsf(average(sc->weight));
+ }
+
+ return (is_zero(N)) ? sd->N : normalize(N);
+}
+
+ccl_device float3 shader_bsdf_ao(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const float ao_factor,
+ ccl_private float3 *N_)
+{
+ float3 eval = zero_float3();
+ float3 N = zero_float3();
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
+ ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc;
+ eval += sc->weight * ao_factor;
+ N += bsdf->N * fabsf(average(sc->weight));
+ }
+ }
+
+ *N_ = (is_zero(N)) ? sd->N : normalize(N);
+ return eval;
+}
+
+#ifdef __SUBSURFACE__
+ccl_device float3 shader_bssrdf_normal(ccl_private const ShaderData *sd)
+{
+ float3 N = zero_float3();
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+
+ if (CLOSURE_IS_BSSRDF(sc->type)) {
+ ccl_private const Bssrdf *bssrdf = (ccl_private const Bssrdf *)sc;
+ float avg_weight = fabsf(average(sc->weight));
+
+ N += bssrdf->N * avg_weight;
+ }
+ }
+
+ return (is_zero(N)) ? sd->N : normalize(N);
+}
+#endif /* __SUBSURFACE__ */
+
+/* Constant emission optimization */
+
+ccl_device bool shader_constant_emission_eval(KernelGlobals kg,
+ int shader,
+ ccl_private float3 *eval)
+{
+ int shader_index = shader & SHADER_MASK;
+ int shader_flag = kernel_tex_fetch(__shaders, shader_index).flags;
+
+ if (shader_flag & SD_HAS_CONSTANT_EMISSION) {
+ *eval = make_float3(kernel_tex_fetch(__shaders, shader_index).constant_emission[0],
+ kernel_tex_fetch(__shaders, shader_index).constant_emission[1],
+ kernel_tex_fetch(__shaders, shader_index).constant_emission[2]);
+
+ return true;
+ }
+
+ return false;
+}
+
+/* Background */
+
+ccl_device float3 shader_background_eval(ccl_private const ShaderData *sd)
+{
+ if (sd->flag & SD_EMISSION) {
+ return sd->closure_emission_background;
+ }
+ else {
+ return zero_float3();
+ }
+}
+
+/* Emission */
+
+ccl_device float3 shader_emissive_eval(ccl_private const ShaderData *sd)
+{
+ if (sd->flag & SD_EMISSION) {
+ return emissive_simple_eval(sd->Ng, sd->I) * sd->closure_emission_background;
+ }
+ else {
+ return zero_float3();
+ }
+}
+
+/* Holdout */
+
+ccl_device float3 shader_holdout_apply(KernelGlobals kg, ccl_private ShaderData *sd)
+{
+ float3 weight = zero_float3();
+
+ /* For objects marked as holdout, preserve transparency and remove all other
+ * closures, replacing them with a holdout weight. */
+ if (sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
+ if ((sd->flag & SD_TRANSPARENT) && !(sd->flag & SD_HAS_ONLY_VOLUME)) {
+ weight = one_float3() - sd->closure_transparent_extinction;
+
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private ShaderClosure *sc = &sd->closure[i];
+ if (!CLOSURE_IS_BSDF_TRANSPARENT(sc->type)) {
+ sc->type = NBUILTIN_CLOSURES;
+ }
+ }
+
+ sd->flag &= ~(SD_CLOSURE_FLAGS - (SD_TRANSPARENT | SD_BSDF));
+ }
+ else {
+ weight = one_float3();
+ }
+ }
+ else {
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private const ShaderClosure *sc = &sd->closure[i];
+ if (CLOSURE_IS_HOLDOUT(sc->type)) {
+ weight += sc->weight;
+ }
+ }
+ }
+
+ return weight;
+}
+
+/* Surface Evaluation */
+
+template<uint node_feature_mask, typename ConstIntegratorGenericState>
+ccl_device void shader_eval_surface(KernelGlobals kg,
+ ConstIntegratorGenericState state,
+ ccl_private ShaderData *ccl_restrict sd,
+ ccl_global float *ccl_restrict buffer,
+ uint32_t path_flag)
+{
+ /* If path is being terminated, we are tracing a shadow ray or evaluating
+ * emission, then we don't need to store closures. The emission and shadow
+ * shader data also do not have a closure array to save GPU memory. */
+ int max_closures;
+ if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) {
+ max_closures = 0;
+ }
+ else {
+ max_closures = kernel_data.max_closures;
+ }
+
+ sd->num_closure = 0;
+ sd->num_closure_left = max_closures;
+
+#ifdef __OSL__
+ if (kg->osl) {
+ if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) {
+ OSLShader::eval_background(kg, state, sd, path_flag);
+ }
+ else {
+ OSLShader::eval_surface(kg, state, sd, path_flag);
+ }
+ }
+ else
+#endif
+ {
+#ifdef __SVM__
+ svm_eval_nodes<node_feature_mask, SHADER_TYPE_SURFACE>(kg, state, sd, buffer, path_flag);
+#else
+ if (sd->object == OBJECT_NONE) {
+ sd->closure_emission_background = make_float3(0.8f, 0.8f, 0.8f);
+ sd->flag |= SD_EMISSION;
+ }
+ else {
+ ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc(
+ sd, sizeof(DiffuseBsdf), make_float3(0.8f, 0.8f, 0.8f));
+ if (bsdf != NULL) {
+ bsdf->N = sd->N;
+ sd->flag |= bsdf_diffuse_setup(bsdf);
+ }
+ }
+#endif
+ }
+}
+
+/* Volume */
+
+#ifdef __VOLUME__
+
+ccl_device_inline float _shader_volume_phase_multi_eval(
+ ccl_private const ShaderData *sd,
+ ccl_private const ShaderVolumePhases *phases,
+ const float3 omega_in,
+ int skip_phase,
+ ccl_private BsdfEval *result_eval,
+ float sum_pdf,
+ float sum_sample_weight)
+{
+ for (int i = 0; i < phases->num_closure; i++) {
+ if (i == skip_phase)
+ continue;
+
+ ccl_private const ShaderVolumeClosure *svc = &phases->closure[i];
+ float phase_pdf = 0.0f;
+ float3 eval = volume_phase_eval(sd, svc, omega_in, &phase_pdf);
+
+ if (phase_pdf != 0.0f) {
+ bsdf_eval_accum(result_eval, false, eval, 1.0f);
+ sum_pdf += phase_pdf * svc->sample_weight;
+ }
+
+ sum_sample_weight += svc->sample_weight;
+ }
+
+ return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f;
+}
+
+ccl_device float shader_volume_phase_eval(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ ccl_private const ShaderVolumePhases *phases,
+ const float3 omega_in,
+ ccl_private BsdfEval *phase_eval)
+{
+ bsdf_eval_init(phase_eval, false, zero_float3());
+
+ return _shader_volume_phase_multi_eval(sd, phases, omega_in, -1, phase_eval, 0.0f, 0.0f);
+}
+
+ccl_device int shader_volume_phase_sample(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ ccl_private const ShaderVolumePhases *phases,
+ float randu,
+ float randv,
+ ccl_private BsdfEval *phase_eval,
+ ccl_private float3 *omega_in,
+ ccl_private differential3 *domega_in,
+ ccl_private float *pdf)
+{
+ int sampled = 0;
+
+ if (phases->num_closure > 1) {
+ /* pick a phase closure based on sample weights */
+ float sum = 0.0f;
+
+ for (sampled = 0; sampled < phases->num_closure; sampled++) {
+ ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled];
+ sum += svc->sample_weight;
+ }
+
+ float r = randu * sum;
+ float partial_sum = 0.0f;
+
+ for (sampled = 0; sampled < phases->num_closure; sampled++) {
+ ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled];
+ float next_sum = partial_sum + svc->sample_weight;
+
+ if (r <= next_sum) {
+ /* Rescale to reuse for BSDF direction sample. */
+ randu = (r - partial_sum) / svc->sample_weight;
+ break;
+ }
+
+ partial_sum = next_sum;
+ }
+
+ if (sampled == phases->num_closure) {
+ *pdf = 0.0f;
+ return LABEL_NONE;
+ }
+ }
+
+ /* todo: this isn't quite correct, we don't weight anisotropy properly
+ * depending on color channels, even if this is perhaps not a common case */
+ ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled];
+ int label;
+ float3 eval = zero_float3();
+
+ *pdf = 0.0f;
+ label = volume_phase_sample(sd, svc, randu, randv, &eval, omega_in, domega_in, pdf);
+
+ if (*pdf != 0.0f) {
+ bsdf_eval_init(phase_eval, false, eval);
+ }
+
+ return label;
+}
+
+ccl_device int shader_phase_sample_closure(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ ccl_private const ShaderVolumeClosure *sc,
+ float randu,
+ float randv,
+ ccl_private BsdfEval *phase_eval,
+ ccl_private float3 *omega_in,
+ ccl_private differential3 *domega_in,
+ ccl_private float *pdf)
+{
+ int label;
+ float3 eval = zero_float3();
+
+ *pdf = 0.0f;
+ label = volume_phase_sample(sd, sc, randu, randv, &eval, omega_in, domega_in, pdf);
+
+ if (*pdf != 0.0f)
+ bsdf_eval_init(phase_eval, false, eval);
+
+ return label;
+}
+
+/* Volume Evaluation */
+
+template<const bool shadow, typename StackReadOp, typename ConstIntegratorGenericState>
+ccl_device_inline void shader_eval_volume(KernelGlobals kg,
+ ConstIntegratorGenericState state,
+ ccl_private ShaderData *ccl_restrict sd,
+ const uint32_t path_flag,
+ StackReadOp stack_read)
+{
+ /* If path is being terminated, we are tracing a shadow ray or evaluating
+ * emission, then we don't need to store closures. The emission and shadow
+ * shader data also do not have a closure array to save GPU memory. */
+ int max_closures;
+ if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) {
+ max_closures = 0;
+ }
+ else {
+ max_closures = kernel_data.max_closures;
+ }
+
+ /* reset closures once at the start, we will be accumulating the closures
+ * for all volumes in the stack into a single array of closures */
+ sd->num_closure = 0;
+ sd->num_closure_left = max_closures;
+ sd->flag = 0;
+ sd->object_flag = 0;
+
+ for (int i = 0;; i++) {
+ const VolumeStack entry = stack_read(i);
+ if (entry.shader == SHADER_NONE) {
+ break;
+ }
+
+ /* Setup shader-data from stack. it's mostly setup already in
+ * shader_setup_from_volume, this switching should be quick. */
+ sd->object = entry.object;
+ sd->lamp = LAMP_NONE;
+ sd->shader = entry.shader;
+
+ sd->flag &= ~SD_SHADER_FLAGS;
+ sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+ sd->object_flag &= ~SD_OBJECT_FLAGS;
+
+ if (sd->object != OBJECT_NONE) {
+ sd->object_flag |= kernel_tex_fetch(__object_flag, sd->object);
+
+# ifdef __OBJECT_MOTION__
+ /* todo: this is inefficient for motion blur, we should be
+ * caching matrices instead of recomputing them each step */
+ shader_setup_object_transforms(kg, sd, sd->time);
+# endif
+ }
+
+ /* evaluate shader */
+# ifdef __SVM__
+# ifdef __OSL__
+ if (kg->osl) {
+ OSLShader::eval_volume(kg, state, sd, path_flag);
+ }
+ else
+# endif
+ {
+ svm_eval_nodes<KERNEL_FEATURE_NODE_MASK_VOLUME, SHADER_TYPE_VOLUME>(
+ kg, state, sd, NULL, path_flag);
+ }
+# endif
+
+ /* Merge closures to avoid exceeding number of closures limit. */
+ if (!shadow) {
+ if (i > 0) {
+ shader_merge_volume_closures(sd);
+ }
+ }
+ }
+}
+
+#endif /* __VOLUME__ */
+
+/* Displacement Evaluation */
+
+template<typename ConstIntegratorGenericState>
+ccl_device void shader_eval_displacement(KernelGlobals kg,
+ ConstIntegratorGenericState state,
+ ccl_private ShaderData *sd)
+{
+ sd->num_closure = 0;
+ sd->num_closure_left = 0;
+
+ /* this will modify sd->P */
+#ifdef __SVM__
+# ifdef __OSL__
+ if (kg->osl)
+ OSLShader::eval_displacement(kg, state, sd);
+ else
+# endif
+ {
+ svm_eval_nodes<KERNEL_FEATURE_NODE_MASK_DISPLACEMENT, SHADER_TYPE_DISPLACEMENT>(
+ kg, state, sd, NULL, 0);
+ }
+#endif
+}
+
+/* Cryptomatte */
+
+ccl_device float shader_cryptomatte_id(KernelGlobals kg, int shader)
+{
+ return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).cryptomatte_id;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shadow_catcher.h b/intern/cycles/kernel/integrator/shadow_catcher.h
new file mode 100644
index 00000000000..7beae235dbc
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shadow_catcher.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/integrator/path_state.h"
+#include "kernel/integrator/state_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Check whether current surface bounce is where path is to be split for the shadow catcher. */
+ccl_device_inline bool kernel_shadow_catcher_is_path_split_bounce(KernelGlobals kg,
+ IntegratorState state,
+ const int object_flag)
+{
+#ifdef __SHADOW_CATCHER__
+ if (!kernel_data.integrator.has_shadow_catcher) {
+ return false;
+ }
+
+ /* Check the flag first, avoiding fetches form global memory. */
+ if ((object_flag & SD_OBJECT_SHADOW_CATCHER) == 0) {
+ return false;
+ }
+ if (object_flag & SD_OBJECT_HOLDOUT_MASK) {
+ return false;
+ }
+
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ if ((path_flag & PATH_RAY_TRANSPARENT_BACKGROUND) == 0) {
+ /* Split only on primary rays, secondary bounces are to treat shadow catcher as a regular
+ * object. */
+ return false;
+ }
+
+ if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
+ return false;
+ }
+
+ return true;
+#else
+ (void)object_flag;
+ return false;
+#endif
+}
+
+/* Check whether the current path can still split. */
+ccl_device_inline bool kernel_shadow_catcher_path_can_split(KernelGlobals kg,
+ ConstIntegratorState state)
+{
+ if (INTEGRATOR_PATH_IS_TERMINATED) {
+ return false;
+ }
+
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ if (path_flag & PATH_RAY_SHADOW_CATCHER_HIT) {
+ /* Shadow catcher was already hit and the state was split. No further split is allowed. */
+ return false;
+ }
+
+ return (path_flag & PATH_RAY_TRANSPARENT_BACKGROUND) != 0;
+}
+
+/* NOTE: Leaves kernel scheduling information untouched. Use INIT semantic for one of the paths
+ * after this function. */
+ccl_device_inline bool kernel_shadow_catcher_split(KernelGlobals kg,
+ IntegratorState state,
+ const int object_flags)
+{
+#ifdef __SHADOW_CATCHER__
+
+ if (!kernel_shadow_catcher_is_path_split_bounce(kg, state, object_flags)) {
+ return false;
+ }
+
+ /* The split is to be done. Mark the current state as such, so that it stops contributing to the
+ * shadow catcher matte pass, but keeps contributing to the combined pass. */
+ INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SHADOW_CATCHER_HIT;
+
+ /* Split new state from the current one. This new state will only track contribution of shadow
+ * catcher objects ignoring non-catcher objects. */
+ integrator_state_shadow_catcher_split(kg, state);
+
+ return true;
+#else
+ (void)object_flags;
+ return false;
+#endif
+}
+
+#ifdef __SHADOW_CATCHER__
+
+ccl_device_forceinline bool kernel_shadow_catcher_is_matte_path(const uint32_t path_flag)
+{
+ return (path_flag & PATH_RAY_SHADOW_CATCHER_HIT) == 0;
+}
+
+ccl_device_forceinline bool kernel_shadow_catcher_is_object_pass(const uint32_t path_flag)
+{
+ return path_flag & PATH_RAY_SHADOW_CATCHER_PASS;
+}
+
+#endif /* __SHADOW_CATCHER__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shadow_state_template.h b/intern/cycles/kernel/integrator/shadow_state_template.h
new file mode 100644
index 00000000000..1fbadde2642
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shadow_state_template.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/********************************* Shadow Path State **************************/
+
+KERNEL_STRUCT_BEGIN(shadow_path)
+/* Index of a pixel within the device render buffer. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint32_t, render_pixel_index, KERNEL_FEATURE_PATH_TRACING)
+/* Current sample number. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, sample, KERNEL_FEATURE_PATH_TRACING)
+/* Random number generator seed. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint32_t, rng_hash, KERNEL_FEATURE_PATH_TRACING)
+/* Random number dimension offset. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, rng_offset, KERNEL_FEATURE_PATH_TRACING)
+/* Current ray bounce depth. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, bounce, KERNEL_FEATURE_PATH_TRACING)
+/* Current transparent ray bounce depth. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, transparent_bounce, KERNEL_FEATURE_PATH_TRACING)
+/* Current diffuse ray bounce depth. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, diffuse_bounce, KERNEL_FEATURE_PATH_TRACING)
+/* Current glossy ray bounce depth. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, glossy_bounce, KERNEL_FEATURE_PATH_TRACING)
+/* Current transmission ray bounce depth. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, transmission_bounce, KERNEL_FEATURE_PATH_TRACING)
+/* DeviceKernel bit indicating queued kernels. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, queued_kernel, KERNEL_FEATURE_PATH_TRACING)
+/* enum PathRayFlag */
+KERNEL_STRUCT_MEMBER(shadow_path, uint32_t, flag, KERNEL_FEATURE_PATH_TRACING)
+/* Throughput. */
+KERNEL_STRUCT_MEMBER(shadow_path, float3, throughput, KERNEL_FEATURE_PATH_TRACING)
+/* Throughput for shadow pass. */
+KERNEL_STRUCT_MEMBER(shadow_path,
+ float3,
+ unshadowed_throughput,
+ KERNEL_FEATURE_SHADOW_PASS | KERNEL_FEATURE_AO_ADDITIVE)
+/* Ratio of throughput to distinguish diffuse and glossy render passes. */
+KERNEL_STRUCT_MEMBER(shadow_path, float3, diffuse_glossy_ratio, KERNEL_FEATURE_LIGHT_PASSES)
+/* Number of intersections found by ray-tracing. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, num_hits, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_END(shadow_path)
+
+/********************************** Shadow Ray *******************************/
+
+KERNEL_STRUCT_BEGIN(shadow_ray)
+KERNEL_STRUCT_MEMBER(shadow_ray, float3, P, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(shadow_ray, float3, D, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(shadow_ray, float, t, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(shadow_ray, float, time, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(shadow_ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_END(shadow_ray)
+
+/*********************** Shadow Intersection result **************************/
+
+/* Result from scene intersection. */
+KERNEL_STRUCT_BEGIN(shadow_isect)
+KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, float, t, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, float, u, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, float, v, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, int, prim, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, int, object, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, int, type, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_END_ARRAY(shadow_isect,
+ INTEGRATOR_SHADOW_ISECT_SIZE_CPU,
+ INTEGRATOR_SHADOW_ISECT_SIZE_GPU)
+
+/**************************** Shadow Volume Stack *****************************/
+
+KERNEL_STRUCT_BEGIN(shadow_volume_stack)
+KERNEL_STRUCT_ARRAY_MEMBER(shadow_volume_stack, int, object, KERNEL_FEATURE_VOLUME)
+KERNEL_STRUCT_ARRAY_MEMBER(shadow_volume_stack, int, shader, KERNEL_FEATURE_VOLUME)
+KERNEL_STRUCT_END_ARRAY(shadow_volume_stack,
+ KERNEL_STRUCT_VOLUME_STACK_SIZE,
+ KERNEL_STRUCT_VOLUME_STACK_SIZE)
diff --git a/intern/cycles/kernel/integrator/state.h b/intern/cycles/kernel/integrator/state.h
new file mode 100644
index 00000000000..86dac0a65cf
--- /dev/null
+++ b/intern/cycles/kernel/integrator/state.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Integrator State
+ *
+ * This file defines the data structures that define the state of a path. Any state that is
+ * preserved and passed between kernel executions is part of this.
+ *
+ * The size of this state must be kept as small as possible, to reduce cache misses and keep memory
+ * usage under control on GPUs that may execute millions of kernels.
+ *
+ * Memory may be allocated and passed along in different ways depending on the device. There may
+ * be a scalar layout, or AoS or SoA layout for batches. The state may be passed along as a pointer
+ * to every kernel, or the pointer may exist at program scope or in constant memory. To abstract
+ * these differences between devices and experiment with different layouts, macros are used.
+ *
+ * Use IntegratorState to pass a reference to the integrator state for the current path. These are
+ * defined differently on the CPU and GPU. Use ConstIntegratorState instead of const
+ * IntegratorState for passing state as read-only, to avoid oddities in typedef behavior.
+ *
+ * INTEGRATOR_STATE(state, x, y): read nested struct member x.y of IntegratorState
+ * INTEGRATOR_STATE_WRITE(state, x, y): write to nested struct member x.y of IntegratorState
+ *
+ * INTEGRATOR_STATE_ARRAY(state, x, index, y): read x[index].y
+ * INTEGRATOR_STATE_ARRAY_WRITE(state, x, index, y): write x[index].y
+ *
+ * INTEGRATOR_STATE_NULL: use to pass empty state to other functions.
+ */
+
+#include "kernel/types.h"
+
+#include "util/types.h"
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Data structures */
+
+/* Integrator State
+ *
+ * CPU rendering path state with AoS layout. */
+typedef struct IntegratorShadowStateCPU {
+#define KERNEL_STRUCT_BEGIN(name) struct {
+#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) type name;
+#define KERNEL_STRUCT_ARRAY_MEMBER KERNEL_STRUCT_MEMBER
+#define KERNEL_STRUCT_END(name) \
+ } \
+ name;
+#define KERNEL_STRUCT_END_ARRAY(name, cpu_size, gpu_size) \
+ } \
+ name[cpu_size];
+#define KERNEL_STRUCT_VOLUME_STACK_SIZE MAX_VOLUME_STACK_SIZE
+#include "kernel/integrator/shadow_state_template.h"
+#undef KERNEL_STRUCT_BEGIN
+#undef KERNEL_STRUCT_MEMBER
+#undef KERNEL_STRUCT_ARRAY_MEMBER
+#undef KERNEL_STRUCT_END
+#undef KERNEL_STRUCT_END_ARRAY
+} IntegratorShadowStateCPU;
+
+typedef struct IntegratorStateCPU {
+#define KERNEL_STRUCT_BEGIN(name) struct {
+#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) type name;
+#define KERNEL_STRUCT_ARRAY_MEMBER KERNEL_STRUCT_MEMBER
+#define KERNEL_STRUCT_END(name) \
+ } \
+ name;
+#define KERNEL_STRUCT_END_ARRAY(name, cpu_size, gpu_size) \
+ } \
+ name[cpu_size];
+#define KERNEL_STRUCT_VOLUME_STACK_SIZE MAX_VOLUME_STACK_SIZE
+#include "kernel/integrator/state_template.h"
+#undef KERNEL_STRUCT_BEGIN
+#undef KERNEL_STRUCT_MEMBER
+#undef KERNEL_STRUCT_ARRAY_MEMBER
+#undef KERNEL_STRUCT_END
+#undef KERNEL_STRUCT_END_ARRAY
+#undef KERNEL_STRUCT_VOLUME_STACK_SIZE
+
+ IntegratorShadowStateCPU shadow;
+ IntegratorShadowStateCPU ao;
+} IntegratorStateCPU;
+
+/* Path Queue
+ *
+ * Keep track of which kernels are queued to be executed next in the path
+ * for GPU rendering. */
+typedef struct IntegratorQueueCounter {
+ int num_queued[DEVICE_KERNEL_INTEGRATOR_NUM];
+} IntegratorQueueCounter;
+
+/* Integrator State GPU
+ *
+ * GPU rendering path state with SoA layout. */
+typedef struct IntegratorStateGPU {
+#define KERNEL_STRUCT_BEGIN(name) struct {
+#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) ccl_global type *name;
+#define KERNEL_STRUCT_ARRAY_MEMBER KERNEL_STRUCT_MEMBER
+#define KERNEL_STRUCT_END(name) \
+ } \
+ name;
+#define KERNEL_STRUCT_END_ARRAY(name, cpu_size, gpu_size) \
+ } \
+ name[gpu_size];
+#define KERNEL_STRUCT_VOLUME_STACK_SIZE MAX_VOLUME_STACK_SIZE
+
+#include "kernel/integrator/state_template.h"
+
+#include "kernel/integrator/shadow_state_template.h"
+
+#undef KERNEL_STRUCT_BEGIN
+#undef KERNEL_STRUCT_MEMBER
+#undef KERNEL_STRUCT_ARRAY_MEMBER
+#undef KERNEL_STRUCT_END
+#undef KERNEL_STRUCT_END_ARRAY
+#undef KERNEL_STRUCT_VOLUME_STACK_SIZE
+
+ /* Count number of queued kernels. */
+ ccl_global IntegratorQueueCounter *queue_counter;
+
+ /* Count number of kernels queued for specific shaders. */
+ ccl_global int *sort_key_counter[DEVICE_KERNEL_INTEGRATOR_NUM];
+
+ /* Index of shadow path which will be used by a next shadow path. */
+ ccl_global int *next_shadow_path_index;
+
+ /* Index of main path which will be used by a next shadow catcher split. */
+ ccl_global int *next_main_path_index;
+} IntegratorStateGPU;
+
+/* Abstraction
+ *
+ * Macros to access data structures on different devices.
+ *
+ * Note that there is a special access function for the shadow catcher state. This access is to
+ * happen from a kernel which operates on a "main" path. Attempt to use shadow catcher accessors
+ * from a kernel which operates on a shadow catcher state will cause bad memory access. */
+
+#ifdef __KERNEL_CPU__
+
+/* Scalar access on CPU. */
+
+typedef IntegratorStateCPU *ccl_restrict IntegratorState;
+typedef const IntegratorStateCPU *ccl_restrict ConstIntegratorState;
+typedef IntegratorShadowStateCPU *ccl_restrict IntegratorShadowState;
+typedef const IntegratorShadowStateCPU *ccl_restrict ConstIntegratorShadowState;
+
+# define INTEGRATOR_STATE_NULL nullptr
+
+# define INTEGRATOR_STATE(state, nested_struct, member) ((state)->nested_struct.member)
+# define INTEGRATOR_STATE_WRITE(state, nested_struct, member) ((state)->nested_struct.member)
+
+# define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member) \
+ ((state)->nested_struct[array_index].member)
+# define INTEGRATOR_STATE_ARRAY_WRITE(state, nested_struct, array_index, member) \
+ ((state)->nested_struct[array_index].member)
+
+#else /* __KERNEL_CPU__ */
+
+/* Array access on GPU with Structure-of-Arrays. */
+
+typedef const int IntegratorState;
+typedef const int ConstIntegratorState;
+typedef const int IntegratorShadowState;
+typedef const int ConstIntegratorShadowState;
+
+# define INTEGRATOR_STATE_NULL -1
+
+# define INTEGRATOR_STATE(state, nested_struct, member) \
+ kernel_integrator_state.nested_struct.member[state]
+# define INTEGRATOR_STATE_WRITE(state, nested_struct, member) \
+ INTEGRATOR_STATE(state, nested_struct, member)
+
+# define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member) \
+ kernel_integrator_state.nested_struct[array_index].member[state]
+# define INTEGRATOR_STATE_ARRAY_WRITE(state, nested_struct, array_index, member) \
+ INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member)
+
+#endif /* __KERNEL_CPU__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/state_flow.h b/intern/cycles/kernel/integrator/state_flow.h
new file mode 100644
index 00000000000..38a2b396847
--- /dev/null
+++ b/intern/cycles/kernel/integrator/state_flow.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/types.h"
+#include "util/atomic.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Control Flow
+ *
+ * Utilities for control flow between kernels. The implementation may differ per device
+ * or even be handled on the host side. To abstract such differences, experiment with
+ * different implementations and for debugging, this is abstracted using macros.
+ *
+ * There is a main path for regular path tracing camera for path tracing. Shadows for next
+ * event estimation branch off from this into their own path, that may be computed in
+ * parallel while the main path continues.
+ *
+ * Each kernel on the main path must call one of these functions. These may not be called
+ * multiple times from the same kernel.
+ *
+ * INTEGRATOR_PATH_INIT(next_kernel)
+ * INTEGRATOR_PATH_NEXT(current_kernel, next_kernel)
+ * INTEGRATOR_PATH_TERMINATE(current_kernel)
+ *
+ * For the shadow path similar functions are used, and again each shadow kernel must call
+ * one of them, and only once.
+ */
+
+#define INTEGRATOR_PATH_IS_TERMINATED (INTEGRATOR_STATE(state, path, queued_kernel) == 0)
+#define INTEGRATOR_SHADOW_PATH_IS_TERMINATED \
+ (INTEGRATOR_STATE(state, shadow_path, queued_kernel) == 0)
+
+#ifdef __KERNEL_GPU__
+
+# define INTEGRATOR_PATH_INIT(next_kernel) \
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
+ 1); \
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+# define INTEGRATOR_PATH_NEXT(current_kernel, next_kernel) \
+ atomic_fetch_and_sub_uint32( \
+ &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
+ 1); \
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+# define INTEGRATOR_PATH_TERMINATE(current_kernel) \
+ atomic_fetch_and_sub_uint32( \
+ &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0;
+
+# define INTEGRATOR_SHADOW_PATH_INIT(shadow_state, state, next_kernel, shadow_type) \
+ IntegratorShadowState shadow_state = atomic_fetch_and_add_uint32( \
+ &kernel_integrator_state.next_shadow_path_index[0], 1); \
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
+ 1); \
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, queued_kernel) = next_kernel;
+# define INTEGRATOR_SHADOW_PATH_NEXT(current_kernel, next_kernel) \
+ atomic_fetch_and_sub_uint32( \
+ &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
+ 1); \
+ INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = next_kernel;
+# define INTEGRATOR_SHADOW_PATH_TERMINATE(current_kernel) \
+ atomic_fetch_and_sub_uint32( \
+ &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
+ INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0;
+
+# define INTEGRATOR_PATH_INIT_SORTED(next_kernel, key) \
+ { \
+ const int key_ = key; \
+ atomic_fetch_and_add_uint32( \
+ &kernel_integrator_state.queue_counter->num_queued[next_kernel], 1); \
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
+ INTEGRATOR_STATE_WRITE(state, path, shader_sort_key) = key_; \
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.sort_key_counter[next_kernel][key_], \
+ 1); \
+ }
+# define INTEGRATOR_PATH_NEXT_SORTED(current_kernel, next_kernel, key) \
+ { \
+ const int key_ = key; \
+ atomic_fetch_and_sub_uint32( \
+ &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
+ atomic_fetch_and_add_uint32( \
+ &kernel_integrator_state.queue_counter->num_queued[next_kernel], 1); \
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
+ INTEGRATOR_STATE_WRITE(state, path, shader_sort_key) = key_; \
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.sort_key_counter[next_kernel][key_], \
+ 1); \
+ }
+
+#else
+
+# define INTEGRATOR_PATH_INIT(next_kernel) \
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+# define INTEGRATOR_PATH_INIT_SORTED(next_kernel, key) \
+ { \
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
+ (void)key; \
+ }
+# define INTEGRATOR_PATH_NEXT(current_kernel, next_kernel) \
+ { \
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
+ (void)current_kernel; \
+ }
+# define INTEGRATOR_PATH_TERMINATE(current_kernel) \
+ { \
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0; \
+ (void)current_kernel; \
+ }
+# define INTEGRATOR_PATH_NEXT_SORTED(current_kernel, next_kernel, key) \
+ { \
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
+ (void)key; \
+ (void)current_kernel; \
+ }
+
+# define INTEGRATOR_SHADOW_PATH_INIT(shadow_state, state, next_kernel, shadow_type) \
+ IntegratorShadowState shadow_state = &state->shadow_type; \
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, queued_kernel) = next_kernel;
+# define INTEGRATOR_SHADOW_PATH_NEXT(current_kernel, next_kernel) \
+ { \
+ INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = next_kernel; \
+ (void)current_kernel; \
+ }
+# define INTEGRATOR_SHADOW_PATH_TERMINATE(current_kernel) \
+ { \
+ INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0; \
+ (void)current_kernel; \
+ }
+
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_state_template.h b/intern/cycles/kernel/integrator/state_template.h
index b1a6fd36fae..b1a6fd36fae 100644
--- a/intern/cycles/kernel/integrator/integrator_state_template.h
+++ b/intern/cycles/kernel/integrator/state_template.h
diff --git a/intern/cycles/kernel/integrator/state_util.h b/intern/cycles/kernel/integrator/state_util.h
new file mode 100644
index 00000000000..dafe06e7009
--- /dev/null
+++ b/intern/cycles/kernel/integrator/state_util.h
@@ -0,0 +1,440 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/integrator/state.h"
+
+#include "kernel/util/differential.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Ray */
+
+ccl_device_forceinline void integrator_state_write_ray(KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const Ray *ccl_restrict ray)
+{
+ INTEGRATOR_STATE_WRITE(state, ray, P) = ray->P;
+ INTEGRATOR_STATE_WRITE(state, ray, D) = ray->D;
+ INTEGRATOR_STATE_WRITE(state, ray, t) = ray->t;
+ INTEGRATOR_STATE_WRITE(state, ray, time) = ray->time;
+ INTEGRATOR_STATE_WRITE(state, ray, dP) = ray->dP;
+ INTEGRATOR_STATE_WRITE(state, ray, dD) = ray->dD;
+}
+
+ccl_device_forceinline void integrator_state_read_ray(KernelGlobals kg,
+ ConstIntegratorState state,
+ ccl_private Ray *ccl_restrict ray)
+{
+ ray->P = INTEGRATOR_STATE(state, ray, P);
+ ray->D = INTEGRATOR_STATE(state, ray, D);
+ ray->t = INTEGRATOR_STATE(state, ray, t);
+ ray->time = INTEGRATOR_STATE(state, ray, time);
+ ray->dP = INTEGRATOR_STATE(state, ray, dP);
+ ray->dD = INTEGRATOR_STATE(state, ray, dD);
+}
+
+/* Shadow Ray */
+
+ccl_device_forceinline void integrator_state_write_shadow_ray(
+ KernelGlobals kg, IntegratorShadowState state, ccl_private const Ray *ccl_restrict ray)
+{
+ INTEGRATOR_STATE_WRITE(state, shadow_ray, P) = ray->P;
+ INTEGRATOR_STATE_WRITE(state, shadow_ray, D) = ray->D;
+ INTEGRATOR_STATE_WRITE(state, shadow_ray, t) = ray->t;
+ INTEGRATOR_STATE_WRITE(state, shadow_ray, time) = ray->time;
+ INTEGRATOR_STATE_WRITE(state, shadow_ray, dP) = ray->dP;
+}
+
+ccl_device_forceinline void integrator_state_read_shadow_ray(KernelGlobals kg,
+ ConstIntegratorShadowState state,
+ ccl_private Ray *ccl_restrict ray)
+{
+ ray->P = INTEGRATOR_STATE(state, shadow_ray, P);
+ ray->D = INTEGRATOR_STATE(state, shadow_ray, D);
+ ray->t = INTEGRATOR_STATE(state, shadow_ray, t);
+ ray->time = INTEGRATOR_STATE(state, shadow_ray, time);
+ ray->dP = INTEGRATOR_STATE(state, shadow_ray, dP);
+ ray->dD = differential_zero_compact();
+}
+
+/* Intersection */
+
+ccl_device_forceinline void integrator_state_write_isect(
+ KernelGlobals kg, IntegratorState state, ccl_private const Intersection *ccl_restrict isect)
+{
+ INTEGRATOR_STATE_WRITE(state, isect, t) = isect->t;
+ INTEGRATOR_STATE_WRITE(state, isect, u) = isect->u;
+ INTEGRATOR_STATE_WRITE(state, isect, v) = isect->v;
+ INTEGRATOR_STATE_WRITE(state, isect, object) = isect->object;
+ INTEGRATOR_STATE_WRITE(state, isect, prim) = isect->prim;
+ INTEGRATOR_STATE_WRITE(state, isect, type) = isect->type;
+}
+
+ccl_device_forceinline void integrator_state_read_isect(
+ KernelGlobals kg, ConstIntegratorState state, ccl_private Intersection *ccl_restrict isect)
+{
+ isect->prim = INTEGRATOR_STATE(state, isect, prim);
+ isect->object = INTEGRATOR_STATE(state, isect, object);
+ isect->type = INTEGRATOR_STATE(state, isect, type);
+ isect->u = INTEGRATOR_STATE(state, isect, u);
+ isect->v = INTEGRATOR_STATE(state, isect, v);
+ isect->t = INTEGRATOR_STATE(state, isect, t);
+}
+
+ccl_device_forceinline VolumeStack integrator_state_read_volume_stack(ConstIntegratorState state,
+ int i)
+{
+ VolumeStack entry = {INTEGRATOR_STATE_ARRAY(state, volume_stack, i, object),
+ INTEGRATOR_STATE_ARRAY(state, volume_stack, i, shader)};
+ return entry;
+}
+
+ccl_device_forceinline void integrator_state_write_volume_stack(IntegratorState state,
+ int i,
+ VolumeStack entry)
+{
+ INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, i, object) = entry.object;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, i, shader) = entry.shader;
+}
+
+ccl_device_forceinline bool integrator_state_volume_stack_is_empty(KernelGlobals kg,
+ ConstIntegratorState state)
+{
+ return (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) ?
+ INTEGRATOR_STATE_ARRAY(state, volume_stack, 0, shader) == SHADER_NONE :
+ true;
+}
+
+/* Shadow Intersection */
+
+ccl_device_forceinline void integrator_state_write_shadow_isect(
+ IntegratorShadowState state,
+ ccl_private const Intersection *ccl_restrict isect,
+ const int index)
+{
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, t) = isect->t;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, u) = isect->u;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, v) = isect->v;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, object) = isect->object;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, prim) = isect->prim;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, index, type) = isect->type;
+}
+
+ccl_device_forceinline void integrator_state_read_shadow_isect(
+ ConstIntegratorShadowState state,
+ ccl_private Intersection *ccl_restrict isect,
+ const int index)
+{
+ isect->prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, prim);
+ isect->object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, object);
+ isect->type = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, type);
+ isect->u = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, u);
+ isect->v = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, v);
+ isect->t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, index, t);
+}
+
+ccl_device_forceinline void integrator_state_copy_volume_stack_to_shadow(
+ KernelGlobals kg, IntegratorShadowState shadow_state, ConstIntegratorState state)
+{
+ if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) {
+ int index = 0;
+ int shader;
+ do {
+ shader = INTEGRATOR_STATE_ARRAY(state, volume_stack, index, shader);
+
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_volume_stack, index, object) =
+ INTEGRATOR_STATE_ARRAY(state, volume_stack, index, object);
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_volume_stack, index, shader) = shader;
+
+ ++index;
+ } while (shader != OBJECT_NONE);
+ }
+}
+
+ccl_device_forceinline void integrator_state_copy_volume_stack(KernelGlobals kg,
+ IntegratorState to_state,
+ ConstIntegratorState state)
+{
+ if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) {
+ int index = 0;
+ int shader;
+ do {
+ shader = INTEGRATOR_STATE_ARRAY(state, volume_stack, index, shader);
+
+ INTEGRATOR_STATE_ARRAY_WRITE(to_state, volume_stack, index, object) = INTEGRATOR_STATE_ARRAY(
+ state, volume_stack, index, object);
+ INTEGRATOR_STATE_ARRAY_WRITE(to_state, volume_stack, index, shader) = shader;
+
+ ++index;
+ } while (shader != OBJECT_NONE);
+ }
+}
+
+ccl_device_forceinline VolumeStack
+integrator_state_read_shadow_volume_stack(ConstIntegratorShadowState state, int i)
+{
+ VolumeStack entry = {INTEGRATOR_STATE_ARRAY(state, shadow_volume_stack, i, object),
+ INTEGRATOR_STATE_ARRAY(state, shadow_volume_stack, i, shader)};
+ return entry;
+}
+
+ccl_device_forceinline bool integrator_state_shadow_volume_stack_is_empty(
+ KernelGlobals kg, ConstIntegratorShadowState state)
+{
+ return (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) ?
+ INTEGRATOR_STATE_ARRAY(state, shadow_volume_stack, 0, shader) == SHADER_NONE :
+ true;
+}
+
+ccl_device_forceinline void integrator_state_write_shadow_volume_stack(IntegratorShadowState state,
+ int i,
+ VolumeStack entry)
+{
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_volume_stack, i, object) = entry.object;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_volume_stack, i, shader) = entry.shader;
+}
+
+#if defined(__KERNEL_GPU__)
+ccl_device_inline void integrator_state_copy_only(KernelGlobals kg,
+ ConstIntegratorState to_state,
+ ConstIntegratorState state)
+{
+ int index;
+
+ /* Rely on the compiler to optimize out unused assignments and `while(false)`'s. */
+
+# define KERNEL_STRUCT_BEGIN(name) \
+ index = 0; \
+ do {
+
+# define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) \
+ if (kernel_integrator_state.parent_struct.name != nullptr) { \
+ kernel_integrator_state.parent_struct.name[to_state] = \
+ kernel_integrator_state.parent_struct.name[state]; \
+ }
+
+# define KERNEL_STRUCT_ARRAY_MEMBER(parent_struct, type, name, feature) \
+ if (kernel_integrator_state.parent_struct[index].name != nullptr) { \
+ kernel_integrator_state.parent_struct[index].name[to_state] = \
+ kernel_integrator_state.parent_struct[index].name[state]; \
+ }
+
+# define KERNEL_STRUCT_END(name) \
+ } \
+ while (false) \
+ ;
+
+# define KERNEL_STRUCT_END_ARRAY(name, cpu_array_size, gpu_array_size) \
+ ++index; \
+ } \
+ while (index < gpu_array_size) \
+ ;
+
+# define KERNEL_STRUCT_VOLUME_STACK_SIZE kernel_data.volume_stack_size
+
+# include "kernel/integrator/state_template.h"
+
+# undef KERNEL_STRUCT_BEGIN
+# undef KERNEL_STRUCT_MEMBER
+# undef KERNEL_STRUCT_ARRAY_MEMBER
+# undef KERNEL_STRUCT_END
+# undef KERNEL_STRUCT_END_ARRAY
+# undef KERNEL_STRUCT_VOLUME_STACK_SIZE
+}
+
+ccl_device_inline void integrator_state_move(KernelGlobals kg,
+ ConstIntegratorState to_state,
+ ConstIntegratorState state)
+{
+ integrator_state_copy_only(kg, to_state, state);
+
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0;
+}
+
+ccl_device_inline void integrator_shadow_state_copy_only(KernelGlobals kg,
+ ConstIntegratorShadowState to_state,
+ ConstIntegratorShadowState state)
+{
+ int index;
+
+ /* Rely on the compiler to optimize out unused assignments and `while(false)`'s. */
+
+# define KERNEL_STRUCT_BEGIN(name) \
+ index = 0; \
+ do {
+
+# define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) \
+ if (kernel_integrator_state.parent_struct.name != nullptr) { \
+ kernel_integrator_state.parent_struct.name[to_state] = \
+ kernel_integrator_state.parent_struct.name[state]; \
+ }
+
+# define KERNEL_STRUCT_ARRAY_MEMBER(parent_struct, type, name, feature) \
+ if (kernel_integrator_state.parent_struct[index].name != nullptr) { \
+ kernel_integrator_state.parent_struct[index].name[to_state] = \
+ kernel_integrator_state.parent_struct[index].name[state]; \
+ }
+
+# define KERNEL_STRUCT_END(name) \
+ } \
+ while (false) \
+ ;
+
+# define KERNEL_STRUCT_END_ARRAY(name, cpu_array_size, gpu_array_size) \
+ ++index; \
+ } \
+ while (index < gpu_array_size) \
+ ;
+
+# define KERNEL_STRUCT_VOLUME_STACK_SIZE kernel_data.volume_stack_size
+
+# include "kernel/integrator/shadow_state_template.h"
+
+# undef KERNEL_STRUCT_BEGIN
+# undef KERNEL_STRUCT_MEMBER
+# undef KERNEL_STRUCT_ARRAY_MEMBER
+# undef KERNEL_STRUCT_END
+# undef KERNEL_STRUCT_END_ARRAY
+# undef KERNEL_STRUCT_VOLUME_STACK_SIZE
+}
+
+ccl_device_inline void integrator_shadow_state_move(KernelGlobals kg,
+ ConstIntegratorState to_state,
+ ConstIntegratorState state)
+{
+ integrator_shadow_state_copy_only(kg, to_state, state);
+
+ INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0;
+}
+
+#endif
+
+/* NOTE: Leaves kernel scheduling information untouched. Use INIT semantic for one of the paths
+ * after this function. */
+ccl_device_inline void integrator_state_shadow_catcher_split(KernelGlobals kg,
+ IntegratorState state)
+{
+#if defined(__KERNEL_GPU__)
+ ConstIntegratorState to_state = atomic_fetch_and_add_uint32(
+ &kernel_integrator_state.next_main_path_index[0], 1);
+
+ integrator_state_copy_only(kg, to_state, state);
+#else
+ IntegratorStateCPU *ccl_restrict to_state = state + 1;
+
+ /* Only copy the required subset, since shadow intersections are big and irrelevant here. */
+ to_state->path = state->path;
+ to_state->ray = state->ray;
+ to_state->isect = state->isect;
+ integrator_state_copy_volume_stack(kg, to_state, state);
+#endif
+
+ INTEGRATOR_STATE_WRITE(to_state, path, flag) |= PATH_RAY_SHADOW_CATCHER_PASS;
+}
+
+#ifdef __KERNEL_CPU__
+ccl_device_inline int integrator_state_bounce(ConstIntegratorState state, const int)
+{
+ return INTEGRATOR_STATE(state, path, bounce);
+}
+
+ccl_device_inline int integrator_state_bounce(ConstIntegratorShadowState state, const int)
+{
+ return INTEGRATOR_STATE(state, shadow_path, bounce);
+}
+
+ccl_device_inline int integrator_state_diffuse_bounce(ConstIntegratorState state, const int)
+{
+ return INTEGRATOR_STATE(state, path, diffuse_bounce);
+}
+
+ccl_device_inline int integrator_state_diffuse_bounce(ConstIntegratorShadowState state, const int)
+{
+ return INTEGRATOR_STATE(state, shadow_path, diffuse_bounce);
+}
+
+ccl_device_inline int integrator_state_glossy_bounce(ConstIntegratorState state, const int)
+{
+ return INTEGRATOR_STATE(state, path, glossy_bounce);
+}
+
+ccl_device_inline int integrator_state_glossy_bounce(ConstIntegratorShadowState state, const int)
+{
+ return INTEGRATOR_STATE(state, shadow_path, glossy_bounce);
+}
+
+ccl_device_inline int integrator_state_transmission_bounce(ConstIntegratorState state, const int)
+{
+ return INTEGRATOR_STATE(state, path, transmission_bounce);
+}
+
+ccl_device_inline int integrator_state_transmission_bounce(ConstIntegratorShadowState state,
+ const int)
+{
+ return INTEGRATOR_STATE(state, shadow_path, transmission_bounce);
+}
+
+ccl_device_inline int integrator_state_transparent_bounce(ConstIntegratorState state, const int)
+{
+ return INTEGRATOR_STATE(state, path, transparent_bounce);
+}
+
+ccl_device_inline int integrator_state_transparent_bounce(ConstIntegratorShadowState state,
+ const int)
+{
+ return INTEGRATOR_STATE(state, shadow_path, transparent_bounce);
+}
+#else
+ccl_device_inline int integrator_state_bounce(ConstIntegratorShadowState state,
+ const uint32_t path_flag)
+{
+ return (path_flag & PATH_RAY_SHADOW) ? INTEGRATOR_STATE(state, shadow_path, bounce) :
+ INTEGRATOR_STATE(state, path, bounce);
+}
+
+ccl_device_inline int integrator_state_diffuse_bounce(ConstIntegratorShadowState state,
+ const uint32_t path_flag)
+{
+ return (path_flag & PATH_RAY_SHADOW) ? INTEGRATOR_STATE(state, shadow_path, diffuse_bounce) :
+ INTEGRATOR_STATE(state, path, diffuse_bounce);
+}
+
+ccl_device_inline int integrator_state_glossy_bounce(ConstIntegratorShadowState state,
+ const uint32_t path_flag)
+{
+ return (path_flag & PATH_RAY_SHADOW) ? INTEGRATOR_STATE(state, shadow_path, glossy_bounce) :
+ INTEGRATOR_STATE(state, path, glossy_bounce);
+}
+
+ccl_device_inline int integrator_state_transmission_bounce(ConstIntegratorShadowState state,
+ const uint32_t path_flag)
+{
+ return (path_flag & PATH_RAY_SHADOW) ?
+ INTEGRATOR_STATE(state, shadow_path, transmission_bounce) :
+ INTEGRATOR_STATE(state, path, transmission_bounce);
+}
+
+ccl_device_inline int integrator_state_transparent_bounce(ConstIntegratorShadowState state,
+ const uint32_t path_flag)
+{
+ return (path_flag & PATH_RAY_SHADOW) ? INTEGRATOR_STATE(state, shadow_path, transparent_bounce) :
+ INTEGRATOR_STATE(state, path, transparent_bounce);
+}
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/subsurface.h b/intern/cycles/kernel/integrator/subsurface.h
new file mode 100644
index 00000000000..49466112387
--- /dev/null
+++ b/intern/cycles/kernel/integrator/subsurface.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/camera/projection.h"
+
+#include "kernel/bvh/bvh.h"
+
+#include "kernel/closure/alloc.h"
+#include "kernel/closure/bsdf_diffuse.h"
+#include "kernel/closure/bsdf_principled_diffuse.h"
+#include "kernel/closure/bssrdf.h"
+#include "kernel/closure/volume.h"
+
+#include "kernel/integrator/intersect_volume_stack.h"
+#include "kernel/integrator/path_state.h"
+#include "kernel/integrator/shader_eval.h"
+#include "kernel/integrator/subsurface_disk.h"
+#include "kernel/integrator/subsurface_random_walk.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __SUBSURFACE__
+
+ccl_device int subsurface_bounce(KernelGlobals kg,
+ IntegratorState state,
+ ccl_private ShaderData *sd,
+ ccl_private const ShaderClosure *sc)
+{
+ /* We should never have two consecutive BSSRDF bounces, the second one should
+ * be converted to a diffuse BSDF to avoid this. */
+ kernel_assert(!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_DIFFUSE_ANCESTOR));
+
+ /* Setup path state for intersect_subsurface kernel. */
+ ccl_private const Bssrdf *bssrdf = (ccl_private const Bssrdf *)sc;
+
+ /* Setup ray into surface. */
+ INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
+ INTEGRATOR_STATE_WRITE(state, ray, D) = bssrdf->N;
+ INTEGRATOR_STATE_WRITE(state, ray, t) = FLT_MAX;
+ INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
+ INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_zero_compact();
+
+ /* Pass along object info, reusing isect to save memory. */
+ INTEGRATOR_STATE_WRITE(state, subsurface, Ng) = sd->Ng;
+ INTEGRATOR_STATE_WRITE(state, isect, object) = sd->object;
+
+ uint32_t path_flag = (INTEGRATOR_STATE(state, path, flag) & ~PATH_RAY_CAMERA) |
+ ((sc->type == CLOSURE_BSSRDF_BURLEY_ID) ? PATH_RAY_SUBSURFACE_DISK :
+ PATH_RAY_SUBSURFACE_RANDOM_WALK);
+
+ /* Compute weight, optionally including Fresnel from entry point. */
+ float3 weight = shader_bssrdf_sample_weight(sd, sc);
+# ifdef __PRINCIPLED__
+ if (bssrdf->roughness != FLT_MAX) {
+ path_flag |= PATH_RAY_SUBSURFACE_USE_FRESNEL;
+ }
+# endif
+
+ INTEGRATOR_STATE_WRITE(state, path, throughput) *= weight;
+ INTEGRATOR_STATE_WRITE(state, path, flag) = path_flag;
+
+ /* Advance random number offset for bounce. */
+ INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
+ if (INTEGRATOR_STATE(state, path, bounce) == 0) {
+ INTEGRATOR_STATE_WRITE(state, path, diffuse_glossy_ratio) = one_float3();
+ }
+ }
+
+ /* Pass BSSRDF parameters. */
+ INTEGRATOR_STATE_WRITE(state, subsurface, albedo) = bssrdf->albedo;
+ INTEGRATOR_STATE_WRITE(state, subsurface, radius) = bssrdf->radius;
+ INTEGRATOR_STATE_WRITE(state, subsurface, anisotropy) = bssrdf->anisotropy;
+
+ return LABEL_SUBSURFACE_SCATTER;
+}
+
+ccl_device void subsurface_shader_data_setup(KernelGlobals kg,
+ IntegratorState state,
+ ccl_private ShaderData *sd,
+ const uint32_t path_flag)
+{
+ /* Get bump mapped normal from shader evaluation at exit point. */
+ float3 N = sd->N;
+ if (sd->flag & SD_HAS_BSSRDF_BUMP) {
+ N = shader_bssrdf_normal(sd);
+ }
+
+ /* Setup diffuse BSDF at the exit point. This replaces shader_eval_surface. */
+ sd->flag &= ~SD_CLOSURE_FLAGS;
+ sd->num_closure = 0;
+ sd->num_closure_left = kernel_data.max_closures;
+
+ const float3 weight = one_float3();
+
+# ifdef __PRINCIPLED__
+ if (path_flag & PATH_RAY_SUBSURFACE_USE_FRESNEL) {
+ ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc(
+ sd, sizeof(PrincipledDiffuseBsdf), weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+ bsdf->roughness = FLT_MAX;
+ sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_LAMBERT_EXIT);
+ }
+ }
+ else
+# endif /* __PRINCIPLED__ */
+ {
+ ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc(
+ sd, sizeof(DiffuseBsdf), weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+ sd->flag |= bsdf_diffuse_setup(bsdf);
+ }
+ }
+}
+
+ccl_device_inline bool subsurface_scatter(KernelGlobals kg, IntegratorState state)
+{
+ RNGState rng_state;
+ path_state_rng_load(state, &rng_state);
+
+ Ray ray ccl_optional_struct_init;
+ LocalIntersection ss_isect ccl_optional_struct_init;
+
+ if (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_SUBSURFACE_RANDOM_WALK) {
+ if (!subsurface_random_walk(kg, state, rng_state, ray, ss_isect)) {
+ return false;
+ }
+ }
+ else {
+ if (!subsurface_disk(kg, state, rng_state, ray, ss_isect)) {
+ return false;
+ }
+ }
+
+# ifdef __VOLUME__
+ /* Update volume stack if needed. */
+ if (kernel_data.integrator.use_volumes) {
+ const int object = ss_isect.hits[0].object;
+ const int object_flag = kernel_tex_fetch(__object_flag, object);
+
+ if (object_flag & SD_OBJECT_INTERSECTS_VOLUME) {
+ float3 P = INTEGRATOR_STATE(state, ray, P);
+ const float3 Ng = INTEGRATOR_STATE(state, subsurface, Ng);
+ const float3 offset_P = ray_offset(P, -Ng);
+
+ integrator_volume_stack_update_for_subsurface(kg, state, offset_P, ray.P);
+ }
+ }
+# endif /* __VOLUME__ */
+
+ /* Pretend ray is coming from the outside towards the exit point. This ensures
+ * correct front/back facing normals.
+ * TODO: find a more elegant solution? */
+ ray.P += ray.D * ray.t * 2.0f;
+ ray.D = -ray.D;
+
+ integrator_state_write_isect(kg, state, &ss_isect.hits[0]);
+ integrator_state_write_ray(kg, state, &ray);
+
+ /* Advance random number offset for bounce. */
+ INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
+
+ const int shader = intersection_get_shader(kg, &ss_isect.hits[0]);
+ const int shader_flags = kernel_tex_fetch(__shaders, shader).flags;
+ if (shader_flags & SD_HAS_RAYTRACE) {
+ INTEGRATOR_PATH_NEXT_SORTED(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE,
+ shader);
+ }
+ else {
+ INTEGRATOR_PATH_NEXT_SORTED(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE,
+ shader);
+ }
+
+ return true;
+}
+
+#endif /* __SUBSURFACE__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/subsurface_disk.h b/intern/cycles/kernel/integrator/subsurface_disk.h
new file mode 100644
index 00000000000..6146b8c41fc
--- /dev/null
+++ b/intern/cycles/kernel/integrator/subsurface_disk.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* BSSRDF using disk based importance sampling.
+ *
+ * BSSRDF Importance Sampling, SIGGRAPH 2013
+ * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf
+ */
+
+ccl_device_inline float3 subsurface_disk_eval(const float3 radius, float disk_r, float r)
+{
+ const float3 eval = bssrdf_eval(radius, r);
+ const float pdf = bssrdf_pdf(radius, disk_r);
+ return (pdf > 0.0f) ? eval / pdf : zero_float3();
+}
+
+/* Subsurface scattering step, from a point on the surface to other
+ * nearby points on the same object. */
+ccl_device_inline bool subsurface_disk(KernelGlobals kg,
+ IntegratorState state,
+ RNGState rng_state,
+ ccl_private Ray &ray,
+ ccl_private LocalIntersection &ss_isect)
+
+{
+ float disk_u, disk_v;
+ path_state_rng_2D(kg, &rng_state, PRNG_BSDF_U, &disk_u, &disk_v);
+
+ /* Read shading point info from integrator state. */
+ const float3 P = INTEGRATOR_STATE(state, ray, P);
+ const float ray_dP = INTEGRATOR_STATE(state, ray, dP);
+ const float time = INTEGRATOR_STATE(state, ray, time);
+ const float3 Ng = INTEGRATOR_STATE(state, subsurface, Ng);
+ const int object = INTEGRATOR_STATE(state, isect, object);
+
+ /* Read subsurface scattering parameters. */
+ const float3 radius = INTEGRATOR_STATE(state, subsurface, radius);
+
+ /* Pick random axis in local frame and point on disk. */
+ float3 disk_N, disk_T, disk_B;
+ float pick_pdf_N, pick_pdf_T, pick_pdf_B;
+
+ disk_N = Ng;
+ make_orthonormals(disk_N, &disk_T, &disk_B);
+
+ if (disk_v < 0.5f) {
+ pick_pdf_N = 0.5f;
+ pick_pdf_T = 0.25f;
+ pick_pdf_B = 0.25f;
+ disk_v *= 2.0f;
+ }
+ else if (disk_v < 0.75f) {
+ float3 tmp = disk_N;
+ disk_N = disk_T;
+ disk_T = tmp;
+ pick_pdf_N = 0.25f;
+ pick_pdf_T = 0.5f;
+ pick_pdf_B = 0.25f;
+ disk_v = (disk_v - 0.5f) * 4.0f;
+ }
+ else {
+ float3 tmp = disk_N;
+ disk_N = disk_B;
+ disk_B = tmp;
+ pick_pdf_N = 0.25f;
+ pick_pdf_T = 0.25f;
+ pick_pdf_B = 0.5f;
+ disk_v = (disk_v - 0.75f) * 4.0f;
+ }
+
+ /* Sample point on disk. */
+ float phi = M_2PI_F * disk_v;
+ float disk_height, disk_r;
+
+ bssrdf_sample(radius, disk_u, &disk_r, &disk_height);
+
+ float3 disk_P = (disk_r * cosf(phi)) * disk_T + (disk_r * sinf(phi)) * disk_B;
+
+ /* Create ray. */
+ ray.P = P + disk_N * disk_height + disk_P;
+ ray.D = -disk_N;
+ ray.t = 2.0f * disk_height;
+ ray.dP = ray_dP;
+ ray.dD = differential_zero_compact();
+ ray.time = time;
+
+ /* Intersect with the same object. if multiple intersections are found it
+ * will use at most BSSRDF_MAX_HITS hits, a random subset of all hits. */
+ uint lcg_state = lcg_state_init(
+ rng_state.rng_hash, rng_state.rng_offset, rng_state.sample, 0x68bc21eb);
+ const int max_hits = BSSRDF_MAX_HITS;
+
+ scene_intersect_local(kg, &ray, &ss_isect, object, &lcg_state, max_hits);
+ const int num_eval_hits = min(ss_isect.num_hits, max_hits);
+ if (num_eval_hits == 0) {
+ return false;
+ }
+
+ /* Sort for consistent renders between CPU and GPU, independent of the BVH
+ * traversal algorithm. */
+ sort_intersections_and_normals(ss_isect.hits, ss_isect.Ng, num_eval_hits);
+
+ float3 weights[BSSRDF_MAX_HITS]; /* TODO: zero? */
+ float sum_weights = 0.0f;
+
+ for (int hit = 0; hit < num_eval_hits; hit++) {
+ /* Get geometric normal. */
+ const int object = ss_isect.hits[hit].object;
+ const int object_flag = kernel_tex_fetch(__object_flag, object);
+ float3 hit_Ng = ss_isect.Ng[hit];
+ if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+ hit_Ng = -hit_Ng;
+ }
+
+ if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ /* Transform normal to world space. */
+ Transform itfm;
+ Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm);
+ hit_Ng = normalize(transform_direction_transposed(&itfm, hit_Ng));
+
+ /* Transform t to world space, except for OptiX where it already is. */
+#ifdef __KERNEL_OPTIX__
+ (void)tfm;
+#else
+ float3 D = transform_direction(&itfm, ray.D);
+ D = normalize(D) * ss_isect.hits[hit].t;
+ ss_isect.hits[hit].t = len(transform_direction(&tfm, D));
+#endif
+ }
+
+ /* Quickly retrieve P and Ng without setting up ShaderData. */
+ const float3 hit_P = ray.P + ray.D * ss_isect.hits[hit].t;
+
+ /* Probability densities for local frame axes. */
+ const float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng));
+ const float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng));
+ const float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng));
+
+ /* Multiple importance sample between 3 axes, power heuristic
+ * found to be slightly better than balance heuristic. pdf_N
+ * in the MIS weight and denominator cancelled out. */
+ float w = pdf_N / (sqr(pdf_N) + sqr(pdf_T) + sqr(pdf_B));
+ if (ss_isect.num_hits > max_hits) {
+ w *= ss_isect.num_hits / (float)max_hits;
+ }
+
+ /* Real distance to sampled point. */
+ const float r = len(hit_P - P);
+
+ /* Evaluate profiles. */
+ const float3 weight = subsurface_disk_eval(radius, disk_r, r) * w;
+
+ /* Store result. */
+ ss_isect.Ng[hit] = hit_Ng;
+ weights[hit] = weight;
+ sum_weights += average(fabs(weight));
+ }
+
+ if (sum_weights == 0.0f) {
+ return false;
+ }
+
+ /* Use importance resampling, sampling one of the hits proportional to weight. */
+ const float r = lcg_step_float(&lcg_state) * sum_weights;
+ float partial_sum = 0.0f;
+
+ for (int hit = 0; hit < num_eval_hits; hit++) {
+ const float3 weight = weights[hit];
+ const float sample_weight = average(fabs(weight));
+ float next_sum = partial_sum + sample_weight;
+
+ if (r < next_sum) {
+ /* Return exit point. */
+ INTEGRATOR_STATE_WRITE(state, path, throughput) *= weight * sum_weights / sample_weight;
+
+ ss_isect.hits[0] = ss_isect.hits[hit];
+ ss_isect.Ng[0] = ss_isect.Ng[hit];
+
+ ray.P = ray.P + ray.D * ss_isect.hits[hit].t;
+ ray.D = ss_isect.Ng[hit];
+ ray.t = 1.0f;
+ return true;
+ }
+
+ partial_sum = next_sum;
+ }
+
+ return false;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/subsurface_random_walk.h b/intern/cycles/kernel/integrator/subsurface_random_walk.h
new file mode 100644
index 00000000000..f0712758174
--- /dev/null
+++ b/intern/cycles/kernel/integrator/subsurface_random_walk.h
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "kernel/camera/projection.h"
+
+#include "kernel/bvh/bvh.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Random walk subsurface scattering.
+ *
+ * "Practical and Controllable Subsurface Scattering for Production Path
+ * Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */
+
+/* Support for anisotropy from:
+ * "Path Traced Subsurface Scattering using Anisotropic Phase Functions
+ * and Non-Exponential Free Flights".
+ * Magnus Wrenninge, Ryusuke Villemin, Christophe Hery.
+ * https://graphics.pixar.com/library/PathTracedSubsurface/ */
+
+ccl_device void subsurface_random_walk_remap(const float albedo,
+ const float d,
+ float g,
+ ccl_private float *sigma_t,
+ ccl_private float *alpha)
+{
+ /* Compute attenuation and scattering coefficients from albedo. */
+ const float g2 = g * g;
+ const float g3 = g2 * g;
+ const float g4 = g3 * g;
+ const float g5 = g4 * g;
+ const float g6 = g5 * g;
+ const float g7 = g6 * g;
+
+ const float A = 1.8260523782f + -1.28451056436f * g + -1.79904629312f * g2 +
+ 9.19393289202f * g3 + -22.8215585862f * g4 + 32.0234874259f * g5 +
+ -23.6264803333f * g6 + 7.21067002658f * g7;
+ const float B = 4.98511194385f +
+ 0.127355959438f *
+ expf(31.1491581433f * g + -201.847017512f * g2 + 841.576016723f * g3 +
+ -2018.09288505f * g4 + 2731.71560286f * g5 + -1935.41424244f * g6 +
+ 559.009054474f * g7);
+ const float C = 1.09686102424f + -0.394704063468f * g + 1.05258115941f * g2 +
+ -8.83963712726f * g3 + 28.8643230661f * g4 + -46.8802913581f * g5 +
+ 38.5402837518f * g6 + -12.7181042538f * g7;
+ const float D = 0.496310210422f + 0.360146581622f * g + -2.15139309747f * g2 +
+ 17.8896899217f * g3 + -55.2984010333f * g4 + 82.065982243f * g5 +
+ -58.5106008578f * g6 + 15.8478295021f * g7;
+ const float E = 4.23190299701f +
+ 0.00310603949088f *
+ expf(76.7316253952f * g + -594.356773233f * g2 + 2448.8834203f * g3 +
+ -5576.68528998f * g4 + 7116.60171912f * g5 + -4763.54467887f * g6 +
+ 1303.5318055f * g7);
+ const float F = 2.40602999408f + -2.51814844609f * g + 9.18494908356f * g2 +
+ -79.2191708682f * g3 + 259.082868209f * g4 + -403.613804597f * g5 +
+ 302.85712436f * g6 + -87.4370473567f * g7;
+
+ const float blend = powf(albedo, 0.25f);
+
+ *alpha = (1.0f - blend) * A * powf(atanf(B * albedo), C) +
+ blend * D * powf(atanf(E * albedo), F);
+ *alpha = clamp(*alpha, 0.0f, 0.999999f); // because of numerical precision
+
+ float sigma_t_prime = 1.0f / fmaxf(d, 1e-16f);
+ *sigma_t = sigma_t_prime / (1.0f - g);
+}
+
+ccl_device void subsurface_random_walk_coefficients(const float3 albedo,
+ const float3 radius,
+ const float anisotropy,
+ ccl_private float3 *sigma_t,
+ ccl_private float3 *alpha,
+ ccl_private float3 *throughput)
+{
+ float sigma_t_x, sigma_t_y, sigma_t_z;
+ float alpha_x, alpha_y, alpha_z;
+
+ subsurface_random_walk_remap(albedo.x, radius.x, anisotropy, &sigma_t_x, &alpha_x);
+ subsurface_random_walk_remap(albedo.y, radius.y, anisotropy, &sigma_t_y, &alpha_y);
+ subsurface_random_walk_remap(albedo.z, radius.z, anisotropy, &sigma_t_z, &alpha_z);
+
+ /* Throughput already contains closure weight at this point, which includes the
+ * albedo, as well as closure mixing and Fresnel weights. Divide out the albedo
+ * which will be added through scattering. */
+ *throughput = safe_divide_color(*throughput, albedo);
+
+ /* With low albedo values (like 0.025) we get diffusion_length 1.0 and
+ * infinite phase functions. To avoid a sharp discontinuity as we go from
+ * such values to 0.0, increase alpha and reduce the throughput to compensate. */
+ const float min_alpha = 0.2f;
+ if (alpha_x < min_alpha) {
+ (*throughput).x *= alpha_x / min_alpha;
+ alpha_x = min_alpha;
+ }
+ if (alpha_y < min_alpha) {
+ (*throughput).y *= alpha_y / min_alpha;
+ alpha_y = min_alpha;
+ }
+ if (alpha_z < min_alpha) {
+ (*throughput).z *= alpha_z / min_alpha;
+ alpha_z = min_alpha;
+ }
+
+ *sigma_t = make_float3(sigma_t_x, sigma_t_y, sigma_t_z);
+ *alpha = make_float3(alpha_x, alpha_y, alpha_z);
+}
+
+/* References for Dwivedi sampling:
+ *
+ * [1] "A Zero-variance-based Sampling Scheme for Monte Carlo Subsurface Scattering"
+ * by Jaroslav Křivánek and Eugene d'Eon (SIGGRAPH 2014)
+ * https://cgg.mff.cuni.cz/~jaroslav/papers/2014-zerovar/
+ *
+ * [2] "Improving the Dwivedi Sampling Scheme"
+ * by Johannes Meng, Johannes Hanika, and Carsten Dachsbacher (EGSR 2016)
+ * https://cg.ivd.kit.edu/1951.php
+ *
+ * [3] "Zero-Variance Theory for Efficient Subsurface Scattering"
+ * by Eugene d'Eon and Jaroslav Křivánek (SIGGRAPH 2020)
+ * https://iliyan.com/publications/RenderingCourse2020
+ */
+
+ccl_device_forceinline float eval_phase_dwivedi(float v, float phase_log, float cos_theta)
+{
+ /* Eq. 9 from [2] using precomputed log((v + 1) / (v - 1)) */
+ return 1.0f / ((v - cos_theta) * phase_log);
+}
+
+ccl_device_forceinline float sample_phase_dwivedi(float v, float phase_log, float rand)
+{
+ /* Based on Eq. 10 from [2]: `v - (v + 1) * pow((v - 1) / (v + 1), rand)`
+ * Since we're already pre-computing `phase_log = log((v + 1) / (v - 1))` for the evaluation,
+ * we can implement the power function like this. */
+ return v - (v + 1.0f) * expf(-rand * phase_log);
+}
+
+ccl_device_forceinline float diffusion_length_dwivedi(float alpha)
+{
+ /* Eq. 67 from [3] */
+ return 1.0f / sqrtf(1.0f - powf(alpha, 2.44294f - 0.0215813f * alpha + 0.578637f / alpha));
+}
+
+ccl_device_forceinline float3 direction_from_cosine(float3 D, float cos_theta, float randv)
+{
+ float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta);
+ float phi = M_2PI_F * randv;
+ float3 dir = make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cos_theta);
+
+ float3 T, B;
+ make_orthonormals(D, &T, &B);
+ return dir.x * T + dir.y * B + dir.z * D;
+}
+
+ccl_device_forceinline float3 subsurface_random_walk_pdf(float3 sigma_t,
+ float t,
+ bool hit,
+ ccl_private float3 *transmittance)
+{
+ float3 T = volume_color_transmittance(sigma_t, t);
+ if (transmittance) {
+ *transmittance = T;
+ }
+ return hit ? T : sigma_t * T;
+}
+
+/* Define the below variable to get the similarity code active,
+ * and the value represents the cutoff level */
+#define SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL 9
+
+ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
+ IntegratorState state,
+ RNGState rng_state,
+ ccl_private Ray &ray,
+ ccl_private LocalIntersection &ss_isect)
+{
+ float bssrdf_u, bssrdf_v;
+ path_state_rng_2D(kg, &rng_state, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
+
+ const float3 P = INTEGRATOR_STATE(state, ray, P);
+ const float3 N = INTEGRATOR_STATE(state, ray, D);
+ const float ray_dP = INTEGRATOR_STATE(state, ray, dP);
+ const float time = INTEGRATOR_STATE(state, ray, time);
+ const float3 Ng = INTEGRATOR_STATE(state, subsurface, Ng);
+ const int object = INTEGRATOR_STATE(state, isect, object);
+
+ /* Sample diffuse surface scatter into the object. */
+ float3 D;
+ float pdf;
+ sample_cos_hemisphere(-N, bssrdf_u, bssrdf_v, &D, &pdf);
+ if (dot(-Ng, D) <= 0.0f) {
+ return false;
+ }
+
+ /* Setup ray. */
+ ray.P = ray_offset(P, -Ng);
+ ray.D = D;
+ ray.t = FLT_MAX;
+ ray.time = time;
+ ray.dP = ray_dP;
+ ray.dD = differential_zero_compact();
+
+#ifndef __KERNEL_OPTIX__
+ /* Compute or fetch object transforms. */
+ Transform ob_itfm ccl_optional_struct_init;
+ Transform ob_tfm = object_fetch_transform_motion_test(kg, object, time, &ob_itfm);
+#endif
+
+ /* Convert subsurface to volume coefficients.
+ * The single-scattering albedo is named alpha to avoid confusion with the surface albedo. */
+ const float3 albedo = INTEGRATOR_STATE(state, subsurface, albedo);
+ const float3 radius = INTEGRATOR_STATE(state, subsurface, radius);
+ const float anisotropy = INTEGRATOR_STATE(state, subsurface, anisotropy);
+
+ float3 sigma_t, alpha;
+ float3 throughput = INTEGRATOR_STATE_WRITE(state, path, throughput);
+ subsurface_random_walk_coefficients(albedo, radius, anisotropy, &sigma_t, &alpha, &throughput);
+ float3 sigma_s = sigma_t * alpha;
+
+ /* Theoretically it should be better to use the exact alpha for the channel we're sampling at
+ * each bounce, but in practice there doesn't seem to be a noticeable difference in exchange
+ * for making the code significantly more complex and slower (if direction sampling depends on
+ * the sampled channel, we need to compute its PDF per-channel and consider it for MIS later on).
+ *
+ * Since the strength of the guided sampling increases as alpha gets lower, using a value that
+ * is too low results in fireflies while one that's too high just gives a bit more noise.
+ * Therefore, the code here uses the highest of the three albedos to be safe. */
+ const float diffusion_length = diffusion_length_dwivedi(max3(alpha));
+
+ if (diffusion_length == 1.0f) {
+ /* With specific values of alpha the length might become 1, which in asymptotic makes phase to
+ * be infinite. After first bounce it will cause throughput to be 0. Do early output, avoiding
+ * numerical issues and extra unneeded work. */
+ return false;
+ }
+
+ /* Precompute term for phase sampling. */
+ const float phase_log = logf((diffusion_length + 1.0f) / (diffusion_length - 1.0f));
+
+ /* Modify state for RNGs, decorrelated from other paths. */
+ rng_state.rng_hash = cmj_hash(rng_state.rng_hash + rng_state.rng_offset, 0xdeadbeef);
+
+ /* Random walk until we hit the surface again. */
+ bool hit = false;
+ bool have_opposite_interface = false;
+ float opposite_distance = 0.0f;
+
+ /* TODO: Disable for `alpha > 0.999` or so? */
+ /* Our heuristic, a compromise between guiding and classic. */
+ const float guided_fraction = 1.0f - fmaxf(0.5f, powf(fabsf(anisotropy), 0.125f));
+
+#ifdef SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL
+ float3 sigma_s_star = sigma_s * (1.0f - anisotropy);
+ float3 sigma_t_star = sigma_t - sigma_s + sigma_s_star;
+ float3 sigma_t_org = sigma_t;
+ float3 sigma_s_org = sigma_s;
+ const float anisotropy_org = anisotropy;
+ const float guided_fraction_org = guided_fraction;
+#endif
+
+ for (int bounce = 0; bounce < BSSRDF_MAX_BOUNCES; bounce++) {
+ /* Advance random number offset. */
+ rng_state.rng_offset += PRNG_BOUNCE_NUM;
+
+#ifdef SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL
+ // shadow with local variables according to depth
+ float anisotropy, guided_fraction;
+ float3 sigma_s, sigma_t;
+ if (bounce <= SUBSURFACE_RANDOM_WALK_SIMILARITY_LEVEL) {
+ anisotropy = anisotropy_org;
+ guided_fraction = guided_fraction_org;
+ sigma_t = sigma_t_org;
+ sigma_s = sigma_s_org;
+ }
+ else {
+ anisotropy = 0.0f;
+ guided_fraction = 0.75f; // back to isotropic heuristic from Blender
+ sigma_t = sigma_t_star;
+ sigma_s = sigma_s_star;
+ }
+#endif
+
+ /* Sample color channel, use MIS with balance heuristic. */
+ float rphase = path_state_rng_1D(kg, &rng_state, PRNG_PHASE_CHANNEL);
+ float3 channel_pdf;
+ int channel = volume_sample_channel(alpha, throughput, rphase, &channel_pdf);
+ float sample_sigma_t = volume_channel_get(sigma_t, channel);
+ float randt = path_state_rng_1D(kg, &rng_state, PRNG_SCATTER_DISTANCE);
+
+ /* We need the result of the ray-cast to compute the full guided PDF, so just remember the
+ * relevant terms to avoid recomputing them later. */
+ float backward_fraction = 0.0f;
+ float forward_pdf_factor = 0.0f;
+ float forward_stretching = 1.0f;
+ float backward_pdf_factor = 0.0f;
+ float backward_stretching = 1.0f;
+
+ /* For the initial ray, we already know the direction, so just do classic distance sampling. */
+ if (bounce > 0) {
+ /* Decide whether we should use guided or classic sampling. */
+ bool guided = (path_state_rng_1D(kg, &rng_state, PRNG_LIGHT_TERMINATE) < guided_fraction);
+
+ /* Determine if we want to sample away from the incoming interface.
+ * This only happens if we found a nearby opposite interface, and the probability for it
+ * depends on how close we are to it already.
+ * This probability term comes from the recorded presentation of [3]. */
+ bool guide_backward = false;
+ if (have_opposite_interface) {
+ /* Compute distance of the random walk between the tangent plane at the starting point
+ * and the assumed opposite interface (the parallel plane that contains the point we
+ * found in our ray query for the opposite side). */
+ float x = clamp(dot(ray.P - P, -N), 0.0f, opposite_distance);
+ backward_fraction = 1.0f /
+ (1.0f + expf((opposite_distance - 2.0f * x) / diffusion_length));
+ guide_backward = path_state_rng_1D(kg, &rng_state, PRNG_TERMINATE) < backward_fraction;
+ }
+
+ /* Sample scattering direction. */
+ float scatter_u, scatter_v;
+ path_state_rng_2D(kg, &rng_state, PRNG_BSDF_U, &scatter_u, &scatter_v);
+ float cos_theta;
+ float hg_pdf;
+ if (guided) {
+ cos_theta = sample_phase_dwivedi(diffusion_length, phase_log, scatter_u);
+ /* The backwards guiding distribution is just mirrored along `sd->N`, so swapping the
+ * sign here is enough to sample from that instead. */
+ if (guide_backward) {
+ cos_theta = -cos_theta;
+ }
+ float3 newD = direction_from_cosine(N, cos_theta, scatter_v);
+ hg_pdf = single_peaked_henyey_greenstein(dot(ray.D, newD), anisotropy);
+ ray.D = newD;
+ }
+ else {
+ float3 newD = henyey_greenstrein_sample(ray.D, anisotropy, scatter_u, scatter_v, &hg_pdf);
+ cos_theta = dot(newD, N);
+ ray.D = newD;
+ }
+
+ /* Compute PDF factor caused by phase sampling (as the ratio of guided / classic).
+ * Since phase sampling is channel-independent, we can get away with applying a factor
+ * to the guided PDF, which implicitly means pulling out the classic PDF term and letting
+ * it cancel with an equivalent term in the numerator of the full estimator.
+ * For the backward PDF, we again reuse the same probability distribution with a sign swap.
+ */
+ forward_pdf_factor = M_1_2PI_F * eval_phase_dwivedi(diffusion_length, phase_log, cos_theta) /
+ hg_pdf;
+ backward_pdf_factor = M_1_2PI_F *
+ eval_phase_dwivedi(diffusion_length, phase_log, -cos_theta) / hg_pdf;
+
+ /* Prepare distance sampling.
+ * For the backwards case, this also needs the sign swapped since now directions against
+ * `sd->N` (and therefore with negative cos_theta) are preferred. */
+ forward_stretching = (1.0f - cos_theta / diffusion_length);
+ backward_stretching = (1.0f + cos_theta / diffusion_length);
+ if (guided) {
+ sample_sigma_t *= guide_backward ? backward_stretching : forward_stretching;
+ }
+ }
+
+ /* Sample direction along ray. */
+ float t = -logf(1.0f - randt) / sample_sigma_t;
+
+ /* On the first bounce, we use the ray-cast to check if the opposite side is nearby.
+ * If yes, we will later use backwards guided sampling in order to have a decent
+ * chance of connecting to it.
+ * TODO: Maybe use less than 10 times the mean free path? */
+ ray.t = (bounce == 0) ? max(t, 10.0f / (min3(sigma_t))) : t;
+ scene_intersect_local(kg, &ray, &ss_isect, object, NULL, 1);
+ hit = (ss_isect.num_hits > 0);
+
+ if (hit) {
+#ifdef __KERNEL_OPTIX__
+ /* t is always in world space with OptiX. */
+ ray.t = ss_isect.hits[0].t;
+#else
+ /* Compute world space distance to surface hit. */
+ float3 D = transform_direction(&ob_itfm, ray.D);
+ D = normalize(D) * ss_isect.hits[0].t;
+ ray.t = len(transform_direction(&ob_tfm, D));
+#endif
+ }
+
+ if (bounce == 0) {
+ /* Check if we hit the opposite side. */
+ if (hit) {
+ have_opposite_interface = true;
+ opposite_distance = dot(ray.P + ray.t * ray.D - P, -N);
+ }
+ /* Apart from the opposite side check, we were supposed to only trace up to distance t,
+ * so check if there would have been a hit in that case. */
+ hit = ray.t < t;
+ }
+
+ /* Use the distance to the exit point for the throughput update if we found one. */
+ if (hit) {
+ t = ray.t;
+ }
+ else if (bounce == 0) {
+ /* Restore original position if nothing was hit after the first bounce,
+ * without the ray_offset() that was added to avoid self-intersection.
+ * Otherwise if that offset is relatively large compared to the scattering
+ * radius, we never go back up high enough to exit the surface. */
+ ray.P = P;
+ }
+
+ /* Advance to new scatter location. */
+ ray.P += t * ray.D;
+
+ float3 transmittance;
+ float3 pdf = subsurface_random_walk_pdf(sigma_t, t, hit, &transmittance);
+ if (bounce > 0) {
+ /* Compute PDF just like we do for classic sampling, but with the stretched sigma_t. */
+ float3 guided_pdf = subsurface_random_walk_pdf(forward_stretching * sigma_t, t, hit, NULL);
+
+ if (have_opposite_interface) {
+ /* First step of MIS: Depending on geometry we might have two methods for guided
+ * sampling, so perform MIS between them. */
+ float3 back_pdf = subsurface_random_walk_pdf(backward_stretching * sigma_t, t, hit, NULL);
+ guided_pdf = mix(
+ guided_pdf * forward_pdf_factor, back_pdf * backward_pdf_factor, backward_fraction);
+ }
+ else {
+ /* Just include phase sampling factor otherwise. */
+ guided_pdf *= forward_pdf_factor;
+ }
+
+ /* Now we apply the MIS balance heuristic between the classic and guided sampling. */
+ pdf = mix(pdf, guided_pdf, guided_fraction);
+ }
+
+ /* Finally, we're applying MIS again to combine the three color channels.
+ * Altogether, the MIS computation combines up to nine different estimators:
+ * {classic, guided, backward_guided} x {r, g, b} */
+ throughput *= (hit ? transmittance : sigma_s * transmittance) / dot(channel_pdf, pdf);
+
+ if (hit) {
+ /* If we hit the surface, we are done. */
+ break;
+ }
+ else if (throughput.x < VOLUME_THROUGHPUT_EPSILON &&
+ throughput.y < VOLUME_THROUGHPUT_EPSILON &&
+ throughput.z < VOLUME_THROUGHPUT_EPSILON) {
+ /* Avoid unnecessary work and precision issue when throughput gets really small. */
+ break;
+ }
+ }
+
+ if (hit) {
+ kernel_assert(isfinite3_safe(throughput));
+ INTEGRATOR_STATE_WRITE(state, path, throughput) = throughput;
+ }
+
+ return hit;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_volume_stack.h b/intern/cycles/kernel/integrator/volume_stack.h
index cf69826ffff..cf69826ffff 100644
--- a/intern/cycles/kernel/integrator/integrator_volume_stack.h
+++ b/intern/cycles/kernel/integrator/volume_stack.h
diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h
deleted file mode 100644
index 54492bef974..00000000000
--- a/intern/cycles/kernel/kernel_accumulate.h
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel_adaptive_sampling.h"
-#include "kernel_random.h"
-#include "kernel_shadow_catcher.h"
-#include "kernel_write_passes.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* --------------------------------------------------------------------
- * BSDF Evaluation
- *
- * BSDF evaluation result, split between diffuse and glossy. This is used to
- * accumulate render passes separately. Note that reflection, transmission
- * and volume scattering are written to different render passes, but we assume
- * that only one of those can happen at a bounce, and so do not need to accumulate
- * them separately. */
-
-ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval,
- const bool is_diffuse,
- float3 value)
-{
- eval->diffuse = zero_float3();
- eval->glossy = zero_float3();
-
- if (is_diffuse) {
- eval->diffuse = value;
- }
- else {
- eval->glossy = value;
- }
-}
-
-ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval,
- const bool is_diffuse,
- float3 value,
- float mis_weight)
-{
- value *= mis_weight;
-
- if (is_diffuse) {
- eval->diffuse += value;
- }
- else {
- eval->glossy += value;
- }
-}
-
-ccl_device_inline bool bsdf_eval_is_zero(ccl_private BsdfEval *eval)
-{
- return is_zero(eval->diffuse) && is_zero(eval->glossy);
-}
-
-ccl_device_inline void bsdf_eval_mul(ccl_private BsdfEval *eval, float value)
-{
- eval->diffuse *= value;
- eval->glossy *= value;
-}
-
-ccl_device_inline void bsdf_eval_mul3(ccl_private BsdfEval *eval, float3 value)
-{
- eval->diffuse *= value;
- eval->glossy *= value;
-}
-
-ccl_device_inline float3 bsdf_eval_sum(ccl_private const BsdfEval *eval)
-{
- return eval->diffuse + eval->glossy;
-}
-
-ccl_device_inline float3 bsdf_eval_diffuse_glossy_ratio(ccl_private const BsdfEval *eval)
-{
- /* Ratio of diffuse and glossy to recover proportions for writing to render pass.
- * We assume reflection, transmission and volume scatter to be exclusive. */
- return safe_divide_float3_float3(eval->diffuse, eval->diffuse + eval->glossy);
-}
-
-/* --------------------------------------------------------------------
- * Clamping
- *
- * Clamping is done on a per-contribution basis so that we can write directly
- * to render buffers instead of using per-thread memory, and to avoid the
- * impact of clamping on other contributions. */
-
-ccl_device_forceinline void kernel_accum_clamp(KernelGlobals kg, ccl_private float3 *L, int bounce)
-{
-#ifdef __KERNEL_DEBUG_NAN__
- if (!isfinite3_safe(*L)) {
- kernel_assert(!"Cycles sample with non-finite value detected");
- }
-#endif
- /* Make sure all components are finite, allowing the contribution to be usable by adaptive
- * sampling convergence check, but also to make it so render result never causes issues with
- * post-processing. */
- *L = ensure_finite3(*L);
-
-#ifdef __CLAMP_SAMPLE__
- float limit = (bounce > 0) ? kernel_data.integrator.sample_clamp_indirect :
- kernel_data.integrator.sample_clamp_direct;
- float sum = reduce_add(fabs(*L));
- if (sum > limit) {
- *L *= limit / sum;
- }
-#endif
-}
-
-/* --------------------------------------------------------------------
- * Pass accumulation utilities.
- */
-
-/* Get pointer to pixel in render buffer. */
-ccl_device_forceinline ccl_global float *kernel_accum_pixel_render_buffer(
- KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer)
-{
- const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
- const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
- kernel_data.film.pass_stride;
- return render_buffer + render_buffer_offset;
-}
-
-/* --------------------------------------------------------------------
- * Adaptive sampling.
- */
-
-ccl_device_inline int kernel_accum_sample(KernelGlobals kg,
- ConstIntegratorState state,
- ccl_global float *ccl_restrict render_buffer,
- int sample)
-{
- if (kernel_data.film.pass_sample_count == PASS_UNUSED) {
- return sample;
- }
-
- ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer);
-
- return atomic_fetch_and_add_uint32((uint *)(buffer) + kernel_data.film.pass_sample_count, 1);
-}
-
-ccl_device void kernel_accum_adaptive_buffer(KernelGlobals kg,
- const int sample,
- const float3 contribution,
- ccl_global float *ccl_restrict buffer)
-{
- /* Adaptive Sampling. Fill the additional buffer with the odd samples and calculate our stopping
- * criteria. This is the heuristic from "A hierarchical automatic stopping condition for Monte
- * Carlo global illumination" except that here it is applied per pixel and not in hierarchical
- * tiles. */
-
- if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) {
- return;
- }
-
- if (sample_is_even(kernel_data.integrator.sampling_pattern, sample)) {
- kernel_write_pass_float4(
- buffer + kernel_data.film.pass_adaptive_aux_buffer,
- make_float4(contribution.x * 2.0f, contribution.y * 2.0f, contribution.z * 2.0f, 0.0f));
- }
-}
-
-/* --------------------------------------------------------------------
- * Shadow catcher.
- */
-
-#ifdef __SHADOW_CATCHER__
-
-/* Accumulate contribution to the Shadow Catcher pass.
- *
- * Returns truth if the contribution is fully handled here and is not to be added to the other
- * passes (like combined, adaptive sampling). */
-
-ccl_device bool kernel_accum_shadow_catcher(KernelGlobals kg,
- const uint32_t path_flag,
- const float3 contribution,
- ccl_global float *ccl_restrict buffer)
-{
- if (!kernel_data.integrator.has_shadow_catcher) {
- return false;
- }
-
- kernel_assert(kernel_data.film.pass_shadow_catcher != PASS_UNUSED);
- kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED);
-
- /* Matte pass. */
- if (kernel_shadow_catcher_is_matte_path(path_flag)) {
- kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher_matte, contribution);
- /* NOTE: Accumulate the combined pass and to the samples count pass, so that the adaptive
- * sampling is based on how noisy the combined pass is as if there were no catchers in the
- * scene. */
- }
-
- /* Shadow catcher pass. */
- if (kernel_shadow_catcher_is_object_pass(path_flag)) {
- kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher, contribution);
- return true;
- }
-
- return false;
-}
-
-ccl_device bool kernel_accum_shadow_catcher_transparent(KernelGlobals kg,
- const uint32_t path_flag,
- const float3 contribution,
- const float transparent,
- ccl_global float *ccl_restrict buffer)
-{
- if (!kernel_data.integrator.has_shadow_catcher) {
- return false;
- }
-
- kernel_assert(kernel_data.film.pass_shadow_catcher != PASS_UNUSED);
- kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED);
-
- if (path_flag & PATH_RAY_SHADOW_CATCHER_BACKGROUND) {
- return true;
- }
-
- /* Matte pass. */
- if (kernel_shadow_catcher_is_matte_path(path_flag)) {
- kernel_write_pass_float4(
- buffer + kernel_data.film.pass_shadow_catcher_matte,
- make_float4(contribution.x, contribution.y, contribution.z, transparent));
- /* NOTE: Accumulate the combined pass and to the samples count pass, so that the adaptive
- * sampling is based on how noisy the combined pass is as if there were no catchers in the
- * scene. */
- }
-
- /* Shadow catcher pass. */
- if (kernel_shadow_catcher_is_object_pass(path_flag)) {
- /* NOTE: The transparency of the shadow catcher pass is ignored. It is not needed for the
- * calculation and the alpha channel of the pass contains numbers of samples contributed to a
- * pixel of the pass. */
- kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher, contribution);
- return true;
- }
-
- return false;
-}
-
-ccl_device void kernel_accum_shadow_catcher_transparent_only(KernelGlobals kg,
- const uint32_t path_flag,
- const float transparent,
- ccl_global float *ccl_restrict buffer)
-{
- if (!kernel_data.integrator.has_shadow_catcher) {
- return;
- }
-
- kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED);
-
- /* Matte pass. */
- if (kernel_shadow_catcher_is_matte_path(path_flag)) {
- kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3, transparent);
- }
-}
-
-#endif /* __SHADOW_CATCHER__ */
-
-/* --------------------------------------------------------------------
- * Render passes.
- */
-
-/* Write combined pass. */
-ccl_device_inline void kernel_accum_combined_pass(KernelGlobals kg,
- const uint32_t path_flag,
- const int sample,
- const float3 contribution,
- ccl_global float *ccl_restrict buffer)
-{
-#ifdef __SHADOW_CATCHER__
- if (kernel_accum_shadow_catcher(kg, path_flag, contribution, buffer)) {
- return;
- }
-#endif
-
- if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) {
- kernel_write_pass_float3(buffer + kernel_data.film.pass_combined, contribution);
- }
-
- kernel_accum_adaptive_buffer(kg, sample, contribution, buffer);
-}
-
-/* Write combined pass with transparency. */
-ccl_device_inline void kernel_accum_combined_transparent_pass(KernelGlobals kg,
- const uint32_t path_flag,
- const int sample,
- const float3 contribution,
- const float transparent,
- ccl_global float *ccl_restrict
- buffer)
-{
-#ifdef __SHADOW_CATCHER__
- if (kernel_accum_shadow_catcher_transparent(kg, path_flag, contribution, transparent, buffer)) {
- return;
- }
-#endif
-
- if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) {
- kernel_write_pass_float4(
- buffer + kernel_data.film.pass_combined,
- make_float4(contribution.x, contribution.y, contribution.z, transparent));
- }
-
- kernel_accum_adaptive_buffer(kg, sample, contribution, buffer);
-}
-
-/* Write background or emission to appropriate pass. */
-ccl_device_inline void kernel_accum_emission_or_background_pass(KernelGlobals kg,
- ConstIntegratorState state,
- float3 contribution,
- ccl_global float *ccl_restrict
- buffer,
- const int pass)
-{
- if (!(kernel_data.film.light_pass_flag & PASS_ANY)) {
- return;
- }
-
-#ifdef __PASSES__
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
- int pass_offset = PASS_UNUSED;
-
- /* Denoising albedo. */
-# ifdef __DENOISING_FEATURES__
- if (path_flag & PATH_RAY_DENOISING_FEATURES) {
- if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) {
- const float3 denoising_feature_throughput = INTEGRATOR_STATE(
- state, path, denoising_feature_throughput);
- const float3 denoising_albedo = denoising_feature_throughput * contribution;
- kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo);
- }
- }
-# endif /* __DENOISING_FEATURES__ */
-
- if (!(path_flag & PATH_RAY_ANY_PASS)) {
- /* Directly visible, write to emission or background pass. */
- pass_offset = pass;
- }
- else if (path_flag & (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS)) {
- /* Indirectly visible through reflection. */
- const int glossy_pass_offset = (path_flag & PATH_RAY_REFLECT_PASS) ?
- ((INTEGRATOR_STATE(state, path, bounce) == 1) ?
- kernel_data.film.pass_glossy_direct :
- kernel_data.film.pass_glossy_indirect) :
- ((INTEGRATOR_STATE(state, path, bounce) == 1) ?
- kernel_data.film.pass_transmission_direct :
- kernel_data.film.pass_transmission_indirect);
-
- if (glossy_pass_offset != PASS_UNUSED) {
- /* Glossy is a subset of the throughput, reconstruct it here using the
- * diffuse-glossy ratio. */
- const float3 ratio = INTEGRATOR_STATE(state, path, diffuse_glossy_ratio);
- const float3 glossy_contribution = (one_float3() - ratio) * contribution;
- kernel_write_pass_float3(buffer + glossy_pass_offset, glossy_contribution);
- }
-
- /* Reconstruct diffuse subset of throughput. */
- pass_offset = (INTEGRATOR_STATE(state, path, bounce) == 1) ?
- kernel_data.film.pass_diffuse_direct :
- kernel_data.film.pass_diffuse_indirect;
- if (pass_offset != PASS_UNUSED) {
- contribution *= INTEGRATOR_STATE(state, path, diffuse_glossy_ratio);
- }
- }
- else if (path_flag & PATH_RAY_VOLUME_PASS) {
- /* Indirectly visible through volume. */
- pass_offset = (INTEGRATOR_STATE(state, path, bounce) == 1) ?
- kernel_data.film.pass_volume_direct :
- kernel_data.film.pass_volume_indirect;
- }
-
- /* Single write call for GPU coherence. */
- if (pass_offset != PASS_UNUSED) {
- kernel_write_pass_float3(buffer + pass_offset, contribution);
- }
-#endif /* __PASSES__ */
-}
-
-/* Write light contribution to render buffer. */
-ccl_device_inline void kernel_accum_light(KernelGlobals kg,
- ConstIntegratorShadowState state,
- ccl_global float *ccl_restrict render_buffer)
-{
- /* The throughput for shadow paths already contains the light shader evaluation. */
- float3 contribution = INTEGRATOR_STATE(state, shadow_path, throughput);
- kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, shadow_path, bounce));
-
- const uint32_t render_pixel_index = INTEGRATOR_STATE(state, shadow_path, render_pixel_index);
- const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
- kernel_data.film.pass_stride;
- ccl_global float *buffer = render_buffer + render_buffer_offset;
-
- const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag);
- const int sample = INTEGRATOR_STATE(state, shadow_path, sample);
-
- /* Ambient occlusion. */
- if (path_flag & PATH_RAY_SHADOW_FOR_AO) {
- kernel_write_pass_float3(buffer + kernel_data.film.pass_ao, contribution);
- return;
- }
-
- /* Direct light shadow. */
- kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer);
-
-#ifdef __PASSES__
- if (kernel_data.film.light_pass_flag & PASS_ANY) {
- const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag);
- int pass_offset = PASS_UNUSED;
-
- if (path_flag & (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS)) {
- /* Indirectly visible through reflection. */
- const int glossy_pass_offset = (path_flag & PATH_RAY_REFLECT_PASS) ?
- ((INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ?
- kernel_data.film.pass_glossy_direct :
- kernel_data.film.pass_glossy_indirect) :
- ((INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ?
- kernel_data.film.pass_transmission_direct :
- kernel_data.film.pass_transmission_indirect);
-
- if (glossy_pass_offset != PASS_UNUSED) {
- /* Glossy is a subset of the throughput, reconstruct it here using the
- * diffuse-glossy ratio. */
- const float3 ratio = INTEGRATOR_STATE(state, shadow_path, diffuse_glossy_ratio);
- const float3 glossy_contribution = (one_float3() - ratio) * contribution;
- kernel_write_pass_float3(buffer + glossy_pass_offset, glossy_contribution);
- }
-
- /* Reconstruct diffuse subset of throughput. */
- pass_offset = (INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ?
- kernel_data.film.pass_diffuse_direct :
- kernel_data.film.pass_diffuse_indirect;
- if (pass_offset != PASS_UNUSED) {
- contribution *= INTEGRATOR_STATE(state, shadow_path, diffuse_glossy_ratio);
- }
- }
- else if (path_flag & PATH_RAY_VOLUME_PASS) {
- /* Indirectly visible through volume. */
- pass_offset = (INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ?
- kernel_data.film.pass_volume_direct :
- kernel_data.film.pass_volume_indirect;
- }
-
- /* Single write call for GPU coherence. */
- if (pass_offset != PASS_UNUSED) {
- kernel_write_pass_float3(buffer + pass_offset, contribution);
- }
-
- /* Write shadow pass. */
- if (kernel_data.film.pass_shadow != PASS_UNUSED && (path_flag & PATH_RAY_SHADOW_FOR_LIGHT) &&
- (path_flag & PATH_RAY_CAMERA)) {
- const float3 unshadowed_throughput = INTEGRATOR_STATE(
- state, shadow_path, unshadowed_throughput);
- const float3 shadowed_throughput = INTEGRATOR_STATE(state, shadow_path, throughput);
- const float3 shadow = safe_divide_float3_float3(shadowed_throughput, unshadowed_throughput) *
- kernel_data.film.pass_shadow_scale;
- kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow, shadow);
- }
- }
-#endif
-}
-
-/* Write transparency to render buffer.
- *
- * Note that we accumulate transparency = 1 - alpha in the render buffer.
- * Otherwise we'd have to write alpha on path termination, which happens
- * in many places. */
-ccl_device_inline void kernel_accum_transparent(KernelGlobals kg,
- ConstIntegratorState state,
- const uint32_t path_flag,
- const float transparent,
- ccl_global float *ccl_restrict buffer)
-{
- if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) {
- kernel_write_pass_float(buffer + kernel_data.film.pass_combined + 3, transparent);
- }
-
- kernel_accum_shadow_catcher_transparent_only(kg, path_flag, transparent, buffer);
-}
-
-/* Write holdout to render buffer. */
-ccl_device_inline void kernel_accum_holdout(KernelGlobals kg,
- ConstIntegratorState state,
- const uint32_t path_flag,
- const float transparent,
- ccl_global float *ccl_restrict render_buffer)
-{
- ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer);
- kernel_accum_transparent(kg, state, path_flag, transparent, buffer);
-}
-
-/* Write background contribution to render buffer.
- *
- * Includes transparency, matching kernel_accum_transparent. */
-ccl_device_inline void kernel_accum_background(KernelGlobals kg,
- ConstIntegratorState state,
- const float3 L,
- const float transparent,
- const bool is_transparent_background_ray,
- ccl_global float *ccl_restrict render_buffer)
-{
- float3 contribution = INTEGRATOR_STATE(state, path, throughput) * L;
- kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1);
-
- ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer);
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- if (is_transparent_background_ray) {
- kernel_accum_transparent(kg, state, path_flag, transparent, buffer);
- }
- else {
- const int sample = INTEGRATOR_STATE(state, path, sample);
- kernel_accum_combined_transparent_pass(
- kg, path_flag, sample, contribution, transparent, buffer);
- }
- kernel_accum_emission_or_background_pass(
- kg, state, contribution, buffer, kernel_data.film.pass_background);
-}
-
-/* Write emission to render buffer. */
-ccl_device_inline void kernel_accum_emission(KernelGlobals kg,
- ConstIntegratorState state,
- const float3 throughput,
- const float3 L,
- ccl_global float *ccl_restrict render_buffer)
-{
- float3 contribution = throughput * L;
- kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1);
-
- ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer);
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
- const int sample = INTEGRATOR_STATE(state, path, sample);
-
- kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer);
- kernel_accum_emission_or_background_pass(
- kg, state, contribution, buffer, kernel_data.film.pass_emission);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_adaptive_sampling.h b/intern/cycles/kernel/kernel_adaptive_sampling.h
deleted file mode 100644
index b80853fcc51..00000000000
--- a/intern/cycles/kernel/kernel_adaptive_sampling.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2019 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_write_passes.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Check whether the pixel has converged and should not be sampled anymore. */
-
-ccl_device_forceinline bool kernel_need_sample_pixel(KernelGlobals kg,
- ConstIntegratorState state,
- ccl_global float *render_buffer)
-{
- if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) {
- return true;
- }
-
- const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
- const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
- kernel_data.film.pass_stride;
- ccl_global float *buffer = render_buffer + render_buffer_offset;
-
- const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
- return buffer[aux_w_offset] == 0.0f;
-}
-
-/* Determines whether to continue sampling a given pixel or if it has sufficiently converged. */
-
-ccl_device bool kernel_adaptive_sampling_convergence_check(KernelGlobals kg,
- ccl_global float *render_buffer,
- int x,
- int y,
- float threshold,
- bool reset,
- int offset,
- int stride)
-{
- kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED);
- kernel_assert(kernel_data.film.pass_sample_count != PASS_UNUSED);
-
- const int render_pixel_index = offset + x + y * stride;
- ccl_global float *buffer = render_buffer +
- (uint64_t)render_pixel_index * kernel_data.film.pass_stride;
-
- /* TODO(Stefan): Is this better in linear, sRGB or something else? */
-
- const float4 A = kernel_read_pass_float4(buffer + kernel_data.film.pass_adaptive_aux_buffer);
- if (!reset && A.w != 0.0f) {
- /* If the pixel was considered converged, its state will not change in this kernel. Early
- * output before doing any math.
- *
- * TODO(sergey): On a GPU it might be better to keep thread alive for better coherency? */
- return true;
- }
-
- const float4 I = kernel_read_pass_float4(buffer + kernel_data.film.pass_combined);
-
- const float sample = __float_as_uint(buffer[kernel_data.film.pass_sample_count]);
- const float inv_sample = 1.0f / sample;
-
- /* The per pixel error as seen in section 2.1 of
- * "A hierarchical automatic stopping condition for Monte Carlo global illumination" */
- const float error_difference = (fabsf(I.x - A.x) + fabsf(I.y - A.y) + fabsf(I.z - A.z)) *
- inv_sample;
- const float error_normalize = sqrtf((I.x + I.y + I.z) * inv_sample);
- /* A small epsilon is added to the divisor to prevent division by zero. */
- const float error = error_difference / (0.0001f + error_normalize);
- const bool did_converge = (error < threshold);
-
- const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
- buffer[aux_w_offset] = did_converge;
-
- return did_converge;
-}
-
-/* This is a simple box filter in two passes.
- * When a pixel demands more adaptive samples, let its neighboring pixels draw more samples too. */
-
-ccl_device void kernel_adaptive_sampling_filter_x(KernelGlobals kg,
- ccl_global float *render_buffer,
- int y,
- int start_x,
- int width,
- int offset,
- int stride)
-{
- kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED);
-
- bool prev = false;
- for (int x = start_x; x < start_x + width; ++x) {
- int index = offset + x + y * stride;
- ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride;
- const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
-
- if (buffer[aux_w_offset] == 0.0f) {
- if (x > start_x && !prev) {
- index = index - 1;
- buffer = render_buffer + index * kernel_data.film.pass_stride;
- buffer[aux_w_offset] = 0.0f;
- }
- prev = true;
- }
- else {
- if (prev) {
- buffer[aux_w_offset] = 0.0f;
- }
- prev = false;
- }
- }
-}
-
-ccl_device void kernel_adaptive_sampling_filter_y(KernelGlobals kg,
- ccl_global float *render_buffer,
- int x,
- int start_y,
- int height,
- int offset,
- int stride)
-{
- kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED);
-
- bool prev = false;
- for (int y = start_y; y < start_y + height; ++y) {
- int index = offset + x + y * stride;
- ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride;
- const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
-
- if (buffer[aux_w_offset] == 0.0f) {
- if (y > start_y && !prev) {
- index = index - stride;
- buffer = render_buffer + index * kernel_data.film.pass_stride;
- buffer[aux_w_offset] = 0.0f;
- }
- prev = true;
- }
- else {
- if (prev) {
- buffer[aux_w_offset] = 0.0f;
- }
- prev = false;
- }
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
deleted file mode 100644
index 30a41b9d3e3..00000000000
--- a/intern/cycles/kernel/kernel_bake.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_differential.h"
-#include "kernel/kernel_projection.h"
-#include "kernel/kernel_shader.h"
-
-#include "kernel/geom/geom.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device void kernel_displace_evaluate(KernelGlobals kg,
- ccl_global const KernelShaderEvalInput *input,
- ccl_global float *output,
- const int offset)
-{
- /* Setup shader data. */
- const KernelShaderEvalInput in = input[offset];
-
- ShaderData sd;
- shader_setup_from_displace(kg, &sd, in.object, in.prim, in.u, in.v);
-
- /* Evaluate displacement shader. */
- const float3 P = sd.P;
- shader_eval_displacement(kg, INTEGRATOR_STATE_NULL, &sd);
- float3 D = sd.P - P;
-
- object_inverse_dir_transform(kg, &sd, &D);
-
-#ifdef __KERNEL_DEBUG_NAN__
- if (!isfinite3_safe(D)) {
- kernel_assert(!"Cycles displacement with non-finite value detected");
- }
-#endif
-
- /* Ensure finite displacement, preventing BVH from becoming degenerate and avoiding possible
- * traversal issues caused by non-finite math. */
- D = ensure_finite3(D);
-
- /* Write output. */
- output[offset * 3 + 0] += D.x;
- output[offset * 3 + 1] += D.y;
- output[offset * 3 + 2] += D.z;
-}
-
-ccl_device void kernel_background_evaluate(KernelGlobals kg,
- ccl_global const KernelShaderEvalInput *input,
- ccl_global float *output,
- const int offset)
-{
- /* Setup ray */
- const KernelShaderEvalInput in = input[offset];
- const float3 ray_P = zero_float3();
- const float3 ray_D = equirectangular_to_direction(in.u, in.v);
- const float ray_time = 0.5f;
-
- /* Setup shader data. */
- ShaderData sd;
- shader_setup_from_background(kg, &sd, ray_P, ray_D, ray_time);
-
- /* Evaluate shader.
- * This is being evaluated for all BSDFs, so path flag does not contain a specific type. */
- const uint32_t path_flag = PATH_RAY_EMISSION;
- shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT &
- ~(KERNEL_FEATURE_NODE_RAYTRACE | KERNEL_FEATURE_NODE_LIGHT_PATH)>(
- kg, INTEGRATOR_STATE_NULL, &sd, NULL, path_flag);
- float3 color = shader_background_eval(&sd);
-
-#ifdef __KERNEL_DEBUG_NAN__
- if (!isfinite3_safe(color)) {
- kernel_assert(!"Cycles background with non-finite value detected");
- }
-#endif
-
- /* Ensure finite color, avoiding possible numerical instabilities in the path tracing kernels. */
- color = ensure_finite3(color);
-
- /* Write output. */
- output[offset * 3 + 0] += color.x;
- output[offset * 3 + 1] += color.y;
- output[offset * 3 + 2] += color.z;
-}
-
-ccl_device void kernel_curve_shadow_transparency_evaluate(
- KernelGlobals kg,
- ccl_global const KernelShaderEvalInput *input,
- ccl_global float *output,
- const int offset)
-{
- /* Setup shader data. */
- const KernelShaderEvalInput in = input[offset];
-
- ShaderData sd;
- shader_setup_from_curve(kg, &sd, in.object, in.prim, __float_as_int(in.v), in.u);
-
- /* Evaluate transparency. */
- shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW &
- ~(KERNEL_FEATURE_NODE_RAYTRACE | KERNEL_FEATURE_NODE_LIGHT_PATH)>(
- kg, INTEGRATOR_STATE_NULL, &sd, NULL, PATH_RAY_SHADOW);
-
- /* Write output. */
- output[offset] = clamp(average(shader_bsdf_transparency(kg, &sd)), 0.0f, 1.0f);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
deleted file mode 100644
index 58a34668f45..00000000000
--- a/intern/cycles/kernel/kernel_camera.h
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel_differential.h"
-#include "kernel_lookup_table.h"
-#include "kernel_montecarlo.h"
-#include "kernel_projection.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Perspective Camera */
-
-ccl_device float2 camera_sample_aperture(ccl_constant KernelCamera *cam, float u, float v)
-{
- float blades = cam->blades;
- float2 bokeh;
-
- if (blades == 0.0f) {
- /* sample disk */
- bokeh = concentric_sample_disk(u, v);
- }
- else {
- /* sample polygon */
- float rotation = cam->bladesrotation;
- bokeh = regular_polygon_sample(blades, rotation, u, v);
- }
-
- /* anamorphic lens bokeh */
- bokeh.x *= cam->inv_aperture_ratio;
-
- return bokeh;
-}
-
-ccl_device void camera_sample_perspective(KernelGlobals kg,
- float raster_x,
- float raster_y,
- float lens_u,
- float lens_v,
- ccl_private Ray *ray)
-{
- /* create ray form raster position */
- ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
- float3 raster = make_float3(raster_x, raster_y, 0.0f);
- float3 Pcamera = transform_perspective(&rastertocamera, raster);
-
-#ifdef __CAMERA_MOTION__
- if (kernel_data.cam.have_perspective_motion) {
- /* TODO(sergey): Currently we interpolate projected coordinate which
- * gives nice looking result and which is simple, but is in fact a bit
- * different comparing to constructing projective matrix from an
- * interpolated field of view.
- */
- if (ray->time < 0.5f) {
- ProjectionTransform rastertocamera_pre = kernel_data.cam.perspective_pre;
- float3 Pcamera_pre = transform_perspective(&rastertocamera_pre, raster);
- Pcamera = interp(Pcamera_pre, Pcamera, ray->time * 2.0f);
- }
- else {
- ProjectionTransform rastertocamera_post = kernel_data.cam.perspective_post;
- float3 Pcamera_post = transform_perspective(&rastertocamera_post, raster);
- Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f);
- }
- }
-#endif
-
- float3 P = zero_float3();
- float3 D = Pcamera;
-
- /* modify ray for depth of field */
- float aperturesize = kernel_data.cam.aperturesize;
-
- if (aperturesize > 0.0f) {
- /* sample point on aperture */
- float2 lensuv = camera_sample_aperture(&kernel_data.cam, lens_u, lens_v) * aperturesize;
-
- /* compute point on plane of focus */
- float ft = kernel_data.cam.focaldistance / D.z;
- float3 Pfocus = D * ft;
-
- /* update ray for effect of lens */
- P = make_float3(lensuv.x, lensuv.y, 0.0f);
- D = normalize(Pfocus - P);
- }
-
- /* transform ray from camera to world */
- Transform cameratoworld = kernel_data.cam.cameratoworld;
-
-#ifdef __CAMERA_MOTION__
- if (kernel_data.cam.num_motion_steps) {
- transform_motion_array_interpolate(&cameratoworld,
- kernel_tex_array(__camera_motion),
- kernel_data.cam.num_motion_steps,
- ray->time);
- }
-#endif
-
- P = transform_point(&cameratoworld, P);
- D = normalize(transform_direction(&cameratoworld, D));
-
- bool use_stereo = kernel_data.cam.interocular_offset != 0.0f;
- if (!use_stereo) {
- /* No stereo */
- ray->P = P;
- ray->D = D;
-
-#ifdef __RAY_DIFFERENTIALS__
- float3 Dcenter = transform_direction(&cameratoworld, Pcamera);
- float3 Dcenter_normalized = normalize(Dcenter);
-
- /* TODO: can this be optimized to give compact differentials directly? */
- ray->dP = differential_zero_compact();
- differential3 dD;
- dD.dx = normalize(Dcenter + float4_to_float3(kernel_data.cam.dx)) - Dcenter_normalized;
- dD.dy = normalize(Dcenter + float4_to_float3(kernel_data.cam.dy)) - Dcenter_normalized;
- ray->dD = differential_make_compact(dD);
-#endif
- }
- else {
- /* Spherical stereo */
- spherical_stereo_transform(&kernel_data.cam, &P, &D);
- ray->P = P;
- ray->D = D;
-
-#ifdef __RAY_DIFFERENTIALS__
- /* Ray differentials, computed from scratch using the raster coordinates
- * because we don't want to be affected by depth of field. We compute
- * ray origin and direction for the center and two neighboring pixels
- * and simply take their differences. */
- float3 Pnostereo = transform_point(&cameratoworld, zero_float3());
-
- float3 Pcenter = Pnostereo;
- float3 Dcenter = Pcamera;
- Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
- spherical_stereo_transform(&kernel_data.cam, &Pcenter, &Dcenter);
-
- float3 Px = Pnostereo;
- float3 Dx = transform_perspective(&rastertocamera,
- make_float3(raster_x + 1.0f, raster_y, 0.0f));
- Dx = normalize(transform_direction(&cameratoworld, Dx));
- spherical_stereo_transform(&kernel_data.cam, &Px, &Dx);
-
- differential3 dP, dD;
-
- dP.dx = Px - Pcenter;
- dD.dx = Dx - Dcenter;
-
- float3 Py = Pnostereo;
- float3 Dy = transform_perspective(&rastertocamera,
- make_float3(raster_x, raster_y + 1.0f, 0.0f));
- Dy = normalize(transform_direction(&cameratoworld, Dy));
- spherical_stereo_transform(&kernel_data.cam, &Py, &Dy);
-
- dP.dy = Py - Pcenter;
- dD.dy = Dy - Dcenter;
- ray->dD = differential_make_compact(dD);
- ray->dP = differential_make_compact(dP);
-#endif
- }
-
-#ifdef __CAMERA_CLIPPING__
- /* clipping */
- float z_inv = 1.0f / normalize(Pcamera).z;
- float nearclip = kernel_data.cam.nearclip * z_inv;
- ray->P += nearclip * ray->D;
- ray->dP += nearclip * ray->dD;
- ray->t = kernel_data.cam.cliplength * z_inv;
-#else
- ray->t = FLT_MAX;
-#endif
-}
-
-/* Orthographic Camera */
-ccl_device void camera_sample_orthographic(KernelGlobals kg,
- float raster_x,
- float raster_y,
- float lens_u,
- float lens_v,
- ccl_private Ray *ray)
-{
- /* create ray form raster position */
- ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
- float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
-
- float3 P;
- float3 D = make_float3(0.0f, 0.0f, 1.0f);
-
- /* modify ray for depth of field */
- float aperturesize = kernel_data.cam.aperturesize;
-
- if (aperturesize > 0.0f) {
- /* sample point on aperture */
- float2 lensuv = camera_sample_aperture(&kernel_data.cam, lens_u, lens_v) * aperturesize;
-
- /* compute point on plane of focus */
- float3 Pfocus = D * kernel_data.cam.focaldistance;
-
- /* update ray for effect of lens */
- float3 lensuvw = make_float3(lensuv.x, lensuv.y, 0.0f);
- P = Pcamera + lensuvw;
- D = normalize(Pfocus - lensuvw);
- }
- else {
- P = Pcamera;
- }
- /* transform ray from camera to world */
- Transform cameratoworld = kernel_data.cam.cameratoworld;
-
-#ifdef __CAMERA_MOTION__
- if (kernel_data.cam.num_motion_steps) {
- transform_motion_array_interpolate(&cameratoworld,
- kernel_tex_array(__camera_motion),
- kernel_data.cam.num_motion_steps,
- ray->time);
- }
-#endif
-
- ray->P = transform_point(&cameratoworld, P);
- ray->D = normalize(transform_direction(&cameratoworld, D));
-
-#ifdef __RAY_DIFFERENTIALS__
- /* ray differential */
- differential3 dP;
- dP.dx = float4_to_float3(kernel_data.cam.dx);
- dP.dy = float4_to_float3(kernel_data.cam.dx);
-
- ray->dP = differential_make_compact(dP);
- ray->dD = differential_zero_compact();
-#endif
-
-#ifdef __CAMERA_CLIPPING__
- /* clipping */
- ray->t = kernel_data.cam.cliplength;
-#else
- ray->t = FLT_MAX;
-#endif
-}
-
-/* Panorama Camera */
-
-ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
-#ifdef __CAMERA_MOTION__
- ccl_global const DecomposedTransform *cam_motion,
-#endif
- float raster_x,
- float raster_y,
- float lens_u,
- float lens_v,
- ccl_private Ray *ray)
-{
- ProjectionTransform rastertocamera = cam->rastertocamera;
- float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
-
- /* create ray form raster position */
- float3 P = zero_float3();
- float3 D = panorama_to_direction(cam, Pcamera.x, Pcamera.y);
-
- /* indicates ray should not receive any light, outside of the lens */
- if (is_zero(D)) {
- ray->t = 0.0f;
- return;
- }
-
- /* modify ray for depth of field */
- float aperturesize = cam->aperturesize;
-
- if (aperturesize > 0.0f) {
- /* sample point on aperture */
- float2 lensuv = camera_sample_aperture(cam, lens_u, lens_v) * aperturesize;
-
- /* compute point on plane of focus */
- float3 Dfocus = normalize(D);
- float3 Pfocus = Dfocus * cam->focaldistance;
-
- /* calculate orthonormal coordinates perpendicular to Dfocus */
- float3 U, V;
- U = normalize(make_float3(1.0f, 0.0f, 0.0f) - Dfocus.x * Dfocus);
- V = normalize(cross(Dfocus, U));
-
- /* update ray for effect of lens */
- P = U * lensuv.x + V * lensuv.y;
- D = normalize(Pfocus - P);
- }
-
- /* transform ray from camera to world */
- Transform cameratoworld = cam->cameratoworld;
-
-#ifdef __CAMERA_MOTION__
- if (cam->num_motion_steps) {
- transform_motion_array_interpolate(
- &cameratoworld, cam_motion, cam->num_motion_steps, ray->time);
- }
-#endif
-
- P = transform_point(&cameratoworld, P);
- D = normalize(transform_direction(&cameratoworld, D));
-
- /* Stereo transform */
- bool use_stereo = cam->interocular_offset != 0.0f;
- if (use_stereo) {
- spherical_stereo_transform(cam, &P, &D);
- }
-
- ray->P = P;
- ray->D = D;
-
-#ifdef __RAY_DIFFERENTIALS__
- /* Ray differentials, computed from scratch using the raster coordinates
- * because we don't want to be affected by depth of field. We compute
- * ray origin and direction for the center and two neighboring pixels
- * and simply take their differences. */
- float3 Pcenter = Pcamera;
- float3 Dcenter = panorama_to_direction(cam, Pcenter.x, Pcenter.y);
- Pcenter = transform_point(&cameratoworld, Pcenter);
- Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
- if (use_stereo) {
- spherical_stereo_transform(cam, &Pcenter, &Dcenter);
- }
-
- float3 Px = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f));
- float3 Dx = panorama_to_direction(cam, Px.x, Px.y);
- Px = transform_point(&cameratoworld, Px);
- Dx = normalize(transform_direction(&cameratoworld, Dx));
- if (use_stereo) {
- spherical_stereo_transform(cam, &Px, &Dx);
- }
-
- differential3 dP, dD;
- dP.dx = Px - Pcenter;
- dD.dx = Dx - Dcenter;
-
- float3 Py = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f));
- float3 Dy = panorama_to_direction(cam, Py.x, Py.y);
- Py = transform_point(&cameratoworld, Py);
- Dy = normalize(transform_direction(&cameratoworld, Dy));
- if (use_stereo) {
- spherical_stereo_transform(cam, &Py, &Dy);
- }
-
- dP.dy = Py - Pcenter;
- dD.dy = Dy - Dcenter;
- ray->dD = differential_make_compact(dD);
- ray->dP = differential_make_compact(dP);
-#endif
-
-#ifdef __CAMERA_CLIPPING__
- /* clipping */
- float nearclip = cam->nearclip;
- ray->P += nearclip * ray->D;
- ray->dP += nearclip * ray->dD;
- ray->t = cam->cliplength;
-#else
- ray->t = FLT_MAX;
-#endif
-}
-
-/* Common */
-
-ccl_device_inline void camera_sample(KernelGlobals kg,
- int x,
- int y,
- float filter_u,
- float filter_v,
- float lens_u,
- float lens_v,
- float time,
- ccl_private Ray *ray)
-{
- /* pixel filter */
- int filter_table_offset = kernel_data.film.filter_table_offset;
- float raster_x = x + lookup_table_read(kg, filter_u, filter_table_offset, FILTER_TABLE_SIZE);
- float raster_y = y + lookup_table_read(kg, filter_v, filter_table_offset, FILTER_TABLE_SIZE);
-
-#ifdef __CAMERA_MOTION__
- /* motion blur */
- if (kernel_data.cam.shuttertime == -1.0f) {
- ray->time = 0.5f;
- }
- else {
- /* TODO(sergey): Such lookup is unneeded when there's rolling shutter
- * effect in use but rolling shutter duration is set to 0.0.
- */
- const int shutter_table_offset = kernel_data.cam.shutter_table_offset;
- ray->time = lookup_table_read(kg, time, shutter_table_offset, SHUTTER_TABLE_SIZE);
- /* TODO(sergey): Currently single rolling shutter effect type only
- * where scan-lines are acquired from top to bottom and whole scan-line
- * is acquired at once (no delay in acquisition happens between pixels
- * of single scan-line).
- *
- * Might want to support more models in the future.
- */
- if (kernel_data.cam.rolling_shutter_type) {
- /* Time corresponding to a fully rolling shutter only effect:
- * top of the frame is time 0.0, bottom of the frame is time 1.0.
- */
- const float time = 1.0f - (float)y / kernel_data.cam.height;
- const float duration = kernel_data.cam.rolling_shutter_duration;
- if (duration != 0.0f) {
- /* This isn't fully physical correct, but lets us to have simple
- * controls in the interface. The idea here is basically sort of
- * linear interpolation between how much rolling shutter effect
- * exist on the frame and how much of it is a motion blur effect.
- */
- ray->time = (ray->time - 0.5f) * duration;
- ray->time += (time - 0.5f) * (1.0f - duration) + 0.5f;
- }
- else {
- ray->time = time;
- }
- }
- }
-#endif
-
- /* sample */
- if (kernel_data.cam.type == CAMERA_PERSPECTIVE) {
- camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray);
- }
- else if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
- camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray);
- }
- else {
-#ifdef __CAMERA_MOTION__
- ccl_global const DecomposedTransform *cam_motion = kernel_tex_array(__camera_motion);
- camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray);
-#else
- camera_sample_panorama(&kernel_data.cam, raster_x, raster_y, lens_u, lens_v, ray);
-#endif
- }
-}
-
-/* Utilities */
-
-ccl_device_inline float3 camera_position(KernelGlobals kg)
-{
- Transform cameratoworld = kernel_data.cam.cameratoworld;
- return make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
-}
-
-ccl_device_inline float camera_distance(KernelGlobals kg, float3 P)
-{
- Transform cameratoworld = kernel_data.cam.cameratoworld;
- float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
-
- if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
- float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z);
- return fabsf(dot((P - camP), camD));
- }
- else {
- return len(P - camP);
- }
-}
-
-ccl_device_inline float camera_z_depth(KernelGlobals kg, float3 P)
-{
- if (kernel_data.cam.type != CAMERA_PANORAMA) {
- Transform worldtocamera = kernel_data.cam.worldtocamera;
- return transform_point(&worldtocamera, P).z;
- }
- else {
- Transform cameratoworld = kernel_data.cam.cameratoworld;
- float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
- return len(P - camP);
- }
-}
-
-ccl_device_inline float3 camera_direction_from_point(KernelGlobals kg, float3 P)
-{
- Transform cameratoworld = kernel_data.cam.cameratoworld;
-
- if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
- float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z);
- return -camD;
- }
- else {
- float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
- return normalize(camP - P);
- }
-}
-
-ccl_device_inline float3 camera_world_to_ndc(KernelGlobals kg,
- ccl_private ShaderData *sd,
- float3 P)
-{
- if (kernel_data.cam.type != CAMERA_PANORAMA) {
- /* perspective / ortho */
- if (sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE)
- P += camera_position(kg);
-
- ProjectionTransform tfm = kernel_data.cam.worldtondc;
- return transform_perspective(&tfm, P);
- }
- else {
- /* panorama */
- Transform tfm = kernel_data.cam.worldtocamera;
-
- if (sd->object != OBJECT_NONE)
- P = normalize(transform_point(&tfm, P));
- else
- P = normalize(transform_direction(&tfm, P));
-
- float2 uv = direction_to_panorama(&kernel_data.cam, P);
-
- return make_float3(uv.x, uv.y, 0.0f);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_color.h b/intern/cycles/kernel/kernel_color.h
deleted file mode 100644
index 0d7bfecd5f3..00000000000
--- a/intern/cycles/kernel/kernel_color.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "util/util_color.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device float3 xyz_to_rgb(KernelGlobals kg, float3 xyz)
-{
- return make_float3(dot(float4_to_float3(kernel_data.film.xyz_to_r), xyz),
- dot(float4_to_float3(kernel_data.film.xyz_to_g), xyz),
- dot(float4_to_float3(kernel_data.film.xyz_to_b), xyz));
-}
-
-ccl_device float linear_rgb_to_gray(KernelGlobals kg, float3 c)
-{
- return dot(c, float4_to_float3(kernel_data.film.rgb_to_y));
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
deleted file mode 100644
index 8d329b8dac3..00000000000
--- a/intern/cycles/kernel/kernel_emission.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/kernel_light.h"
-#include "kernel/kernel_montecarlo.h"
-#include "kernel/kernel_path_state.h"
-#include "kernel/kernel_shader.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Evaluate shader on light. */
-ccl_device_noinline_cpu float3
-light_sample_shader_eval(KernelGlobals kg,
- IntegratorState state,
- ccl_private ShaderData *ccl_restrict emission_sd,
- ccl_private LightSample *ccl_restrict ls,
- float time)
-{
- /* setup shading at emitter */
- float3 eval = zero_float3();
-
- if (shader_constant_emission_eval(kg, ls->shader, &eval)) {
- if ((ls->prim != PRIM_NONE) && dot(ls->Ng, ls->D) > 0.0f) {
- ls->Ng = -ls->Ng;
- }
- }
- else {
- /* Setup shader data and call shader_eval_surface once, better
- * for GPU coherence and compile times. */
- PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_LIGHT_SETUP);
-#ifdef __BACKGROUND_MIS__
- if (ls->type == LIGHT_BACKGROUND) {
- shader_setup_from_background(kg, emission_sd, ls->P, ls->D, time);
- }
- else
-#endif
- {
- shader_setup_from_sample(kg,
- emission_sd,
- ls->P,
- ls->Ng,
- -ls->D,
- ls->shader,
- ls->object,
- ls->prim,
- ls->u,
- ls->v,
- ls->t,
- time,
- false,
- ls->lamp);
-
- ls->Ng = emission_sd->Ng;
- }
-
- PROFILING_SHADER(emission_sd->object, emission_sd->shader);
- PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL);
-
- /* No proper path flag, we're evaluating this for all closures. that's
- * weak but we'd have to do multiple evaluations otherwise. */
- shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT>(
- kg, state, emission_sd, NULL, PATH_RAY_EMISSION);
-
- /* Evaluate closures. */
-#ifdef __BACKGROUND_MIS__
- if (ls->type == LIGHT_BACKGROUND) {
- eval = shader_background_eval(emission_sd);
- }
- else
-#endif
- {
- eval = shader_emissive_eval(emission_sd);
- }
- }
-
- eval *= ls->eval_fac;
-
- if (ls->lamp != LAMP_NONE) {
- ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, ls->lamp);
- eval *= make_float3(klight->strength[0], klight->strength[1], klight->strength[2]);
- }
-
- return eval;
-}
-
-/* Test if light sample is from a light or emission from geometry. */
-ccl_device_inline bool light_sample_is_light(ccl_private const LightSample *ccl_restrict ls)
-{
- /* return if it's a lamp for shadow pass */
- return (ls->prim == PRIM_NONE && ls->type != LIGHT_BACKGROUND);
-}
-
-/* Early path termination of shadow rays. */
-ccl_device_inline bool light_sample_terminate(KernelGlobals kg,
- ccl_private const LightSample *ccl_restrict ls,
- ccl_private BsdfEval *ccl_restrict eval,
- const float rand_terminate)
-{
- if (bsdf_eval_is_zero(eval)) {
- return true;
- }
-
- if (kernel_data.integrator.light_inv_rr_threshold > 0.0f) {
- float probability = max3(fabs(bsdf_eval_sum(eval))) *
- kernel_data.integrator.light_inv_rr_threshold;
- if (probability < 1.0f) {
- if (rand_terminate >= probability) {
- return true;
- }
- bsdf_eval_mul(eval, 1.0f / probability);
- }
- }
-
- return false;
-}
-
-/* This function should be used to compute a modified ray start position for
- * rays leaving from a surface. The algorithm slightly distorts flat surface
- * of a triangle. Surface is lifted by amount h along normal n in the incident
- * point. */
-
-ccl_device_inline float3 shadow_ray_smooth_surface_offset(
- KernelGlobals kg, ccl_private const ShaderData *ccl_restrict sd, float3 Ng)
-{
- float3 V[3], N[3];
- triangle_vertices_and_normals(kg, sd->prim, V, N);
-
- const float u = sd->u, v = sd->v;
- const float w = 1 - u - v;
- float3 P = V[0] * u + V[1] * v + V[2] * w; /* Local space */
- float3 n = N[0] * u + N[1] * v + N[2] * w; /* We get away without normalization */
-
- object_normal_transform(kg, sd, &n); /* Normal x scale, world space */
-
- /* Parabolic approximation */
- float a = dot(N[2] - N[0], V[0] - V[2]);
- float b = dot(N[2] - N[1], V[1] - V[2]);
- float c = dot(N[1] - N[0], V[1] - V[0]);
- float h = a * u * (u - 1) + (a + b + c) * u * v + b * v * (v - 1);
-
- /* Check flipped normals */
- if (dot(n, Ng) > 0) {
- /* Local linear envelope */
- float h0 = max(max(dot(V[1] - V[0], N[0]), dot(V[2] - V[0], N[0])), 0.0f);
- float h1 = max(max(dot(V[0] - V[1], N[1]), dot(V[2] - V[1], N[1])), 0.0f);
- float h2 = max(max(dot(V[0] - V[2], N[2]), dot(V[1] - V[2], N[2])), 0.0f);
- h0 = max(dot(V[0] - P, N[0]) + h0, 0.0f);
- h1 = max(dot(V[1] - P, N[1]) + h1, 0.0f);
- h2 = max(dot(V[2] - P, N[2]) + h2, 0.0f);
- h = max(min(min(h0, h1), h2), h * 0.5f);
- }
- else {
- float h0 = max(max(dot(V[0] - V[1], N[0]), dot(V[0] - V[2], N[0])), 0.0f);
- float h1 = max(max(dot(V[1] - V[0], N[1]), dot(V[1] - V[2], N[1])), 0.0f);
- float h2 = max(max(dot(V[2] - V[0], N[2]), dot(V[2] - V[1], N[2])), 0.0f);
- h0 = max(dot(P - V[0], N[0]) + h0, 0.0f);
- h1 = max(dot(P - V[1], N[1]) + h1, 0.0f);
- h2 = max(dot(P - V[2], N[2]) + h2, 0.0f);
- h = min(-min(min(h0, h1), h2), h * 0.5f);
- }
-
- return n * h;
-}
-
-/* Ray offset to avoid shadow terminator artifact. */
-
-ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg,
- ccl_private const ShaderData *ccl_restrict sd,
- float3 L)
-{
- float NL = dot(sd->N, L);
- bool transmit = (NL < 0.0f);
- float3 Ng = (transmit ? -sd->Ng : sd->Ng);
- float3 P = ray_offset(sd->P, Ng);
-
- if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
- const float offset_cutoff =
- kernel_tex_fetch(__objects, sd->object).shadow_terminator_geometry_offset;
- /* Do ray offset (heavy stuff) only for close to be terminated triangles:
- * offset_cutoff = 0.1f means that 10-20% of rays will be affected. Also
- * make a smooth transition near the threshold. */
- if (offset_cutoff > 0.0f) {
- float NgL = dot(Ng, L);
- float offset_amount = 0.0f;
- if (NL < offset_cutoff) {
- offset_amount = clamp(2.0f - (NgL + NL) / offset_cutoff, 0.0f, 1.0f);
- }
- else {
- offset_amount = clamp(1.0f - NgL / offset_cutoff, 0.0f, 1.0f);
- }
- if (offset_amount > 0.0f) {
- P += shadow_ray_smooth_surface_offset(kg, sd, Ng) * offset_amount;
- }
- }
- }
-
- return P;
-}
-
-ccl_device_inline void shadow_ray_setup(ccl_private const ShaderData *ccl_restrict sd,
- ccl_private const LightSample *ccl_restrict ls,
- const float3 P,
- ccl_private Ray *ray)
-{
- if (ls->shader & SHADER_CAST_SHADOW) {
- /* setup ray */
- ray->P = P;
-
- if (ls->t == FLT_MAX) {
- /* distant light */
- ray->D = ls->D;
- ray->t = ls->t;
- }
- else {
- /* other lights, avoid self-intersection */
- ray->D = ray_offset(ls->P, ls->Ng) - P;
- ray->D = normalize_len(ray->D, &ray->t);
- }
- }
- else {
- /* signal to not cast shadow ray */
- ray->P = zero_float3();
- ray->D = zero_float3();
- ray->t = 0.0f;
- }
-
- ray->dP = differential_make_compact(sd->dP);
- ray->dD = differential_zero_compact();
- ray->time = sd->time;
-}
-
-/* Create shadow ray towards light sample. */
-ccl_device_inline void light_sample_to_surface_shadow_ray(
- KernelGlobals kg,
- ccl_private const ShaderData *ccl_restrict sd,
- ccl_private const LightSample *ccl_restrict ls,
- ccl_private Ray *ray)
-{
- const float3 P = shadow_ray_offset(kg, sd, ls->D);
- shadow_ray_setup(sd, ls, P, ray);
-}
-
-/* Create shadow ray towards light sample. */
-ccl_device_inline void light_sample_to_volume_shadow_ray(
- KernelGlobals kg,
- ccl_private const ShaderData *ccl_restrict sd,
- ccl_private const LightSample *ccl_restrict ls,
- const float3 P,
- ccl_private Ray *ray)
-{
- shadow_ray_setup(sd, ls, P, ray);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_film.h b/intern/cycles/kernel/kernel_film.h
deleted file mode 100644
index a87eff3832e..00000000000
--- a/intern/cycles/kernel/kernel_film.h
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* --------------------------------------------------------------------
- * Common utilities.
- */
-
-/* The input buffer contains transparency = 1 - alpha, this converts it to
- * alpha. Also clamp since alpha might end up outside of 0..1 due to Russian
- * roulette. */
-ccl_device_forceinline float film_transparency_to_alpha(float transparency)
-{
- return saturate(1.0f - transparency);
-}
-
-ccl_device_inline float film_get_scale(ccl_global const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer)
-{
- if (kfilm_convert->pass_sample_count == PASS_UNUSED) {
- return kfilm_convert->scale;
- }
-
- if (kfilm_convert->pass_use_filter) {
- const uint sample_count = *(
- (ccl_global const uint *)(buffer + kfilm_convert->pass_sample_count));
- return 1.0f / sample_count;
- }
-
- return 1.0f;
-}
-
-ccl_device_inline float film_get_scale_exposure(ccl_global const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer)
-{
- if (kfilm_convert->pass_sample_count == PASS_UNUSED) {
- return kfilm_convert->scale_exposure;
- }
-
- const float scale = film_get_scale(kfilm_convert, buffer);
-
- if (kfilm_convert->pass_use_exposure) {
- return scale * kfilm_convert->exposure;
- }
-
- return scale;
-}
-
-ccl_device_inline bool film_get_scale_and_scale_exposure(
- ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict scale,
- ccl_private float *ccl_restrict scale_exposure)
-{
- if (kfilm_convert->pass_sample_count == PASS_UNUSED) {
- *scale = kfilm_convert->scale;
- *scale_exposure = kfilm_convert->scale_exposure;
- return true;
- }
-
- const uint sample_count = *(
- (ccl_global const uint *)(buffer + kfilm_convert->pass_sample_count));
- if (!sample_count) {
- *scale = 0.0f;
- *scale_exposure = 0.0f;
- return false;
- }
-
- if (kfilm_convert->pass_use_filter) {
- *scale = 1.0f / sample_count;
- }
- else {
- *scale = 1.0f;
- }
-
- if (kfilm_convert->pass_use_exposure) {
- *scale_exposure = *scale * kfilm_convert->exposure;
- }
- else {
- *scale_exposure = *scale;
- }
-
- return true;
-}
-
-/* --------------------------------------------------------------------
- * Float (scalar) passes.
- */
-
-ccl_device_inline void film_get_pass_pixel_depth(ccl_global const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components >= 1);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
-
- const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer);
-
- ccl_global const float *in = buffer + kfilm_convert->pass_offset;
- const float f = *in;
-
- pixel[0] = (f == 0.0f) ? 1e10f : f * scale_exposure;
-}
-
-ccl_device_inline void film_get_pass_pixel_mist(ccl_global const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components >= 1);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
-
- const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer);
-
- ccl_global const float *in = buffer + kfilm_convert->pass_offset;
- const float f = *in;
-
- /* Note that we accumulate 1 - mist in the kernel to avoid having to
- * track the mist values in the integrator state. */
- pixel[0] = saturate(1.0f - f * scale_exposure);
-}
-
-ccl_device_inline void film_get_pass_pixel_sample_count(
- ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- /* TODO(sergey): Consider normalizing into the [0..1] range, so that it is possible to see
- * meaningful value when adaptive sampler stopped rendering image way before the maximum
- * number of samples was reached (for examples when number of samples is set to 0 in
- * viewport). */
-
- kernel_assert(kfilm_convert->num_components >= 1);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
-
- ccl_global const float *in = buffer + kfilm_convert->pass_offset;
- const float f = *in;
-
- pixel[0] = __float_as_uint(f) * kfilm_convert->scale;
-}
-
-ccl_device_inline void film_get_pass_pixel_float(ccl_global const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components >= 1);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
-
- const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer);
-
- ccl_global const float *in = buffer + kfilm_convert->pass_offset;
- const float f = *in;
-
- pixel[0] = f * scale_exposure;
-}
-
-/* --------------------------------------------------------------------
- * Float 3 passes.
- */
-
-ccl_device_inline void film_get_pass_pixel_light_path(
- ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components >= 3);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
-
- /* Read light pass. */
- ccl_global const float *in = buffer + kfilm_convert->pass_offset;
- float3 f = make_float3(in[0], in[1], in[2]);
-
- /* Optionally add indirect light pass. */
- if (kfilm_convert->pass_indirect != PASS_UNUSED) {
- ccl_global const float *in_indirect = buffer + kfilm_convert->pass_indirect;
- const float3 f_indirect = make_float3(in_indirect[0], in_indirect[1], in_indirect[2]);
- f += f_indirect;
- }
-
- /* Optionally divide out color. */
- if (kfilm_convert->pass_divide != PASS_UNUSED) {
- ccl_global const float *in_divide = buffer + kfilm_convert->pass_divide;
- const float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]);
- f = safe_divide_even_color(f, f_divide);
-
- /* Exposure only, sample scale cancels out. */
- f *= kfilm_convert->exposure;
- }
- else {
- /* Sample scale and exposure. */
- f *= film_get_scale_exposure(kfilm_convert, buffer);
- }
-
- pixel[0] = f.x;
- pixel[1] = f.y;
- pixel[2] = f.z;
-}
-
-ccl_device_inline void film_get_pass_pixel_float3(ccl_global const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components >= 3);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
-
- const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer);
-
- ccl_global const float *in = buffer + kfilm_convert->pass_offset;
-
- const float3 f = make_float3(in[0], in[1], in[2]) * scale_exposure;
-
- pixel[0] = f.x;
- pixel[1] = f.y;
- pixel[2] = f.z;
-}
-
-/* --------------------------------------------------------------------
- * Float4 passes.
- */
-
-ccl_device_inline void film_get_pass_pixel_motion(ccl_global const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components == 4);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
- kernel_assert(kfilm_convert->pass_motion_weight != PASS_UNUSED);
-
- ccl_global const float *in = buffer + kfilm_convert->pass_offset;
- ccl_global const float *in_weight = buffer + kfilm_convert->pass_motion_weight;
-
- const float weight = in_weight[0];
- const float weight_inv = (weight > 0.0f) ? 1.0f / weight : 0.0f;
-
- const float4 motion = make_float4(in[0], in[1], in[2], in[3]) * weight_inv;
-
- pixel[0] = motion.x;
- pixel[1] = motion.y;
- pixel[2] = motion.z;
- pixel[3] = motion.w;
-}
-
-ccl_device_inline void film_get_pass_pixel_cryptomatte(
- ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components == 4);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
-
- const float scale = film_get_scale(kfilm_convert, buffer);
-
- ccl_global const float *in = buffer + kfilm_convert->pass_offset;
-
- const float4 f = make_float4(in[0], in[1], in[2], in[3]);
-
- /* x and z contain integer IDs, don't rescale them.
- * y and w contain matte weights, they get scaled. */
- pixel[0] = f.x;
- pixel[1] = f.y * scale;
- pixel[2] = f.z;
- pixel[3] = f.w * scale;
-}
-
-ccl_device_inline void film_get_pass_pixel_float4(ccl_global const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components == 4);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
-
- float scale, scale_exposure;
- film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure);
-
- ccl_global const float *in = buffer + kfilm_convert->pass_offset;
-
- const float3 color = make_float3(in[0], in[1], in[2]) * scale_exposure;
- const float alpha = in[3] * scale;
-
- pixel[0] = color.x;
- pixel[1] = color.y;
- pixel[2] = color.z;
- pixel[3] = alpha;
-}
-
-ccl_device_inline void film_get_pass_pixel_combined(
- ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components == 4);
-
- /* 3rd channel contains transparency = 1 - alpha for the combined pass. */
-
- kernel_assert(kfilm_convert->num_components == 4);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
-
- float scale, scale_exposure;
- if (!film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure)) {
- pixel[0] = 0.0f;
- pixel[1] = 0.0f;
- pixel[2] = 0.0f;
- pixel[3] = 0.0f;
- return;
- }
-
- ccl_global const float *in = buffer + kfilm_convert->pass_offset;
-
- const float3 color = make_float3(in[0], in[1], in[2]) * scale_exposure;
- const float alpha = in[3] * scale;
-
- pixel[0] = color.x;
- pixel[1] = color.y;
- pixel[2] = color.z;
- pixel[3] = film_transparency_to_alpha(alpha);
-}
-
-/* --------------------------------------------------------------------
- * Shadow catcher.
- */
-
-ccl_device_inline float3 film_calculate_shadow_catcher_denoised(
- ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer)
-{
- kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED);
-
- float scale, scale_exposure;
- film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure);
-
- ccl_global const float *in_catcher = buffer + kfilm_convert->pass_shadow_catcher;
-
- const float3 pixel = make_float3(in_catcher[0], in_catcher[1], in_catcher[2]) * scale_exposure;
-
- return pixel;
-}
-
-ccl_device_inline float3 safe_divide_shadow_catcher(float3 a, float3 b)
-{
- float x, y, z;
-
- x = (b.x != 0.0f) ? a.x / b.x : 1.0f;
- y = (b.y != 0.0f) ? a.y / b.y : 1.0f;
- z = (b.z != 0.0f) ? a.z / b.z : 1.0f;
-
- return make_float3(x, y, z);
-}
-
-ccl_device_inline float3
-film_calculate_shadow_catcher(ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer)
-{
- /* For the shadow catcher pass we divide combined pass by the shadow catcher.
- * Note that denoised shadow catcher pass contains value which only needs ot be scaled (but not
- * to be calculated as division). */
-
- if (kfilm_convert->is_denoised) {
- return film_calculate_shadow_catcher_denoised(kfilm_convert, buffer);
- }
-
- kernel_assert(kfilm_convert->pass_shadow_catcher_sample_count != PASS_UNUSED);
-
- /* If there is no shadow catcher object in this pixel, there is no modification of the light
- * needed, so return one. */
- ccl_global const float *in_catcher_sample_count =
- buffer + kfilm_convert->pass_shadow_catcher_sample_count;
- const float num_samples = in_catcher_sample_count[0];
- if (num_samples == 0.0f) {
- return one_float3();
- }
-
- kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED);
- ccl_global const float *in_catcher = buffer + kfilm_convert->pass_shadow_catcher;
-
- /* NOTE: It is possible that the Shadow Catcher pass is requested as an output without actual
- * shadow catcher objects in the scene. In this case there will be no auxiliary passes required
- * for the decision (to save up memory). So delay the asserts to this point so that the number of
- * samples check handles such configuration. */
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
- kernel_assert(kfilm_convert->pass_combined != PASS_UNUSED);
- kernel_assert(kfilm_convert->pass_shadow_catcher_matte != PASS_UNUSED);
-
- ccl_global const float *in_combined = buffer + kfilm_convert->pass_combined;
- ccl_global const float *in_matte = buffer + kfilm_convert->pass_shadow_catcher_matte;
-
- /* No scaling needed. The integration works in way that number of samples in the combined and
- * shadow catcher passes are the same, and exposure is canceled during the division. */
- const float3 color_catcher = make_float3(in_catcher[0], in_catcher[1], in_catcher[2]);
- const float3 color_combined = make_float3(in_combined[0], in_combined[1], in_combined[2]);
- const float3 color_matte = make_float3(in_matte[0], in_matte[1], in_matte[2]);
-
- /* Need to ignore contribution of the matte object when doing division (otherwise there will be
- * artifacts caused by anti-aliasing). Since combined pass is used for adaptive sampling and need
- * to contain matte objects, we subtract matte objects contribution here. This is the same as if
- * the matte objects were not accumulated to the combined pass. */
- const float3 combined_no_matte = color_combined - color_matte;
-
- const float3 shadow_catcher = safe_divide_shadow_catcher(combined_no_matte, color_catcher);
-
- const float scale = film_get_scale(kfilm_convert, buffer);
- const float transparency = in_combined[3] * scale;
- const float alpha = film_transparency_to_alpha(transparency);
-
- /* Alpha-over on white using transparency of the combined pass. This allows to eliminate
- * artifacts which are happening on an edge of a shadow catcher when using transparent film.
- * Note that we treat shadow catcher as straight alpha here because alpha got canceled out
- * during the division. */
- const float3 pixel = (1.0f - alpha) * one_float3() + alpha * shadow_catcher;
-
- return pixel;
-}
-
-ccl_device_inline float4 film_calculate_shadow_catcher_matte_with_shadow(
- ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer)
-{
- /* The approximation of the shadow is 1 - average(shadow_catcher_pass). A better approximation
- * is possible.
- *
- * The matte is alpha-overed onto the shadow (which is kind of alpha-overing shadow onto footage,
- * and then alpha-overing synthetic objects on top). */
-
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
- kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED);
- kernel_assert(kfilm_convert->pass_shadow_catcher_matte != PASS_UNUSED);
-
- float scale, scale_exposure;
- if (!film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure)) {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- }
-
- ccl_global const float *in_matte = buffer + kfilm_convert->pass_shadow_catcher_matte;
-
- const float3 shadow_catcher = film_calculate_shadow_catcher(kfilm_convert, buffer);
- const float3 color_matte = make_float3(in_matte[0], in_matte[1], in_matte[2]) * scale_exposure;
-
- const float transparency = in_matte[3] * scale;
- const float alpha = saturate(1.0f - transparency);
-
- const float alpha_matte = (1.0f - alpha) * (1.0f - average(shadow_catcher)) + alpha;
-
- if (kfilm_convert->use_approximate_shadow_catcher_background) {
- kernel_assert(kfilm_convert->pass_background != PASS_UNUSED);
-
- ccl_global const float *in_background = buffer + kfilm_convert->pass_background;
- const float3 color_background = make_float3(
- in_background[0], in_background[1], in_background[2]) *
- scale_exposure;
- const float3 alpha_over = color_matte + color_background * (1.0f - alpha_matte);
- return make_float4(alpha_over.x, alpha_over.y, alpha_over.z, 1.0f);
- }
-
- return make_float4(color_matte.x, color_matte.y, color_matte.z, alpha_matte);
-}
-
-ccl_device_inline void film_get_pass_pixel_shadow_catcher(
- ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components >= 3);
-
- const float3 pixel_value = film_calculate_shadow_catcher(kfilm_convert, buffer);
-
- pixel[0] = pixel_value.x;
- pixel[1] = pixel_value.y;
- pixel[2] = pixel_value.z;
-}
-
-ccl_device_inline void film_get_pass_pixel_shadow_catcher_matte_with_shadow(
- ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components == 3 || kfilm_convert->num_components == 4);
-
- const float4 pixel_value = film_calculate_shadow_catcher_matte_with_shadow(kfilm_convert,
- buffer);
-
- pixel[0] = pixel_value.x;
- pixel[1] = pixel_value.y;
- pixel[2] = pixel_value.z;
- if (kfilm_convert->num_components == 4) {
- pixel[3] = pixel_value.w;
- }
-}
-
-/* --------------------------------------------------------------------
- * Compositing and overlays.
- */
-
-ccl_device_inline void film_apply_pass_pixel_overlays_rgba(
- ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- ccl_private float *ccl_restrict pixel)
-{
- if (kfilm_convert->show_active_pixels &&
- kfilm_convert->pass_adaptive_aux_buffer != PASS_UNUSED) {
- if (buffer[kfilm_convert->pass_adaptive_aux_buffer + 3] == 0.0f) {
- const float3 active_rgb = make_float3(1.0f, 0.0f, 0.0f);
- const float3 mix_rgb = interp(make_float3(pixel[0], pixel[1], pixel[2]), active_rgb, 0.5f);
- pixel[0] = mix_rgb.x;
- pixel[1] = mix_rgb.y;
- pixel[2] = mix_rgb.z;
- }
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_jitter.h b/intern/cycles/kernel/kernel_jitter.h
deleted file mode 100644
index b62ec7fda42..00000000000
--- a/intern/cycles/kernel/kernel_jitter.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-CCL_NAMESPACE_BEGIN
-
-ccl_device_inline uint32_t laine_karras_permutation(uint32_t x, uint32_t seed)
-{
- x += seed;
- x ^= (x * 0x6c50b47cu);
- x ^= x * 0xb82f1e52u;
- x ^= x * 0xc7afe638u;
- x ^= x * 0x8d22f6e6u;
-
- return x;
-}
-
-ccl_device_inline uint32_t nested_uniform_scramble(uint32_t x, uint32_t seed)
-{
- x = reverse_integer_bits(x);
- x = laine_karras_permutation(x, seed);
- x = reverse_integer_bits(x);
-
- return x;
-}
-
-ccl_device_inline uint cmj_hash(uint i, uint p)
-{
- i ^= p;
- i ^= i >> 17;
- i ^= i >> 10;
- i *= 0xb36534e5;
- i ^= i >> 12;
- i ^= i >> 21;
- i *= 0x93fc4795;
- i ^= 0xdf6e307f;
- i ^= i >> 17;
- i *= 1 | p >> 18;
-
- return i;
-}
-
-ccl_device_inline uint cmj_hash_simple(uint i, uint p)
-{
- i = (i ^ 61) ^ p;
- i += i << 3;
- i ^= i >> 4;
- i *= 0x27d4eb2d;
- return i;
-}
-
-ccl_device_inline float cmj_randfloat(uint i, uint p)
-{
- return cmj_hash(i, p) * (1.0f / 4294967808.0f);
-}
-
-ccl_device_inline float cmj_randfloat_simple(uint i, uint p)
-{
- return cmj_hash_simple(i, p) * (1.0f / (float)0xFFFFFFFF);
-}
-
-ccl_device float pmj_sample_1D(KernelGlobals kg, uint sample, uint rng_hash, uint dimension)
-{
- /* Perform Owen shuffle of the sample number to reorder the samples. */
-#ifdef _SIMPLE_HASH_
- const uint rv = cmj_hash_simple(dimension, rng_hash);
-#else /* Use a _REGULAR_HASH_. */
- const uint rv = cmj_hash(dimension, rng_hash);
-#endif
-#ifdef _XOR_SHUFFLE_
-# warning "Using XOR shuffle."
- const uint s = sample ^ rv;
-#else /* Use _OWEN_SHUFFLE_ for reordering. */
- const uint s = nested_uniform_scramble(sample, rv);
-#endif
-
- /* Based on the sample number a sample pattern is selected and offset by the dimension. */
- const uint sample_set = s / NUM_PMJ_SAMPLES;
- const uint d = (dimension + sample_set);
- const uint dim = d % NUM_PMJ_PATTERNS;
-
- /* The PMJ sample sets contain a sample with (x,y) with NUM_PMJ_SAMPLES so for 1D
- * the x part is used for even dims and the y for odd. */
- int index = 2 * ((dim >> 1) * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES)) + (dim & 1);
-
- float fx = kernel_tex_fetch(__sample_pattern_lut, index);
-
-#ifndef _NO_CRANLEY_PATTERSON_ROTATION_
- /* Use Cranley-Patterson rotation to displace the sample pattern. */
-# ifdef _SIMPLE_HASH_
- float dx = cmj_randfloat_simple(d, rng_hash);
-# else
- float dx = cmj_randfloat(d, rng_hash);
-# endif
- /* Jitter sample locations and map back into [0 1]. */
- fx = fx + dx;
- fx = fx - floorf(fx);
-#else
-# warning "Not using Cranley-Patterson Rotation."
-#endif
-
- return fx;
-}
-
-ccl_device void pmj_sample_2D(KernelGlobals kg,
- uint sample,
- uint rng_hash,
- uint dimension,
- ccl_private float *x,
- ccl_private float *y)
-{
- /* Perform a shuffle on the sample number to reorder the samples. */
-#ifdef _SIMPLE_HASH_
- const uint rv = cmj_hash_simple(dimension, rng_hash);
-#else /* Use a _REGULAR_HASH_. */
- const uint rv = cmj_hash(dimension, rng_hash);
-#endif
-#ifdef _XOR_SHUFFLE_
-# warning "Using XOR shuffle."
- const uint s = sample ^ rv;
-#else /* Use _OWEN_SHUFFLE_ for reordering. */
- const uint s = nested_uniform_scramble(sample, rv);
-#endif
-
- /* Based on the sample number a sample pattern is selected and offset by the dimension. */
- const uint sample_set = s / NUM_PMJ_SAMPLES;
- const uint d = (dimension + sample_set);
- uint dim = d % NUM_PMJ_PATTERNS;
- int index = 2 * (dim * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES));
-
- float fx = kernel_tex_fetch(__sample_pattern_lut, index);
- float fy = kernel_tex_fetch(__sample_pattern_lut, index + 1);
-
-#ifndef _NO_CRANLEY_PATTERSON_ROTATION_
- /* Use Cranley-Patterson rotation to displace the sample pattern. */
-# ifdef _SIMPLE_HASH_
- float dx = cmj_randfloat_simple(d, rng_hash);
- float dy = cmj_randfloat_simple(d + 1, rng_hash);
-# else
- float dx = cmj_randfloat(d, rng_hash);
- float dy = cmj_randfloat(d + 1, rng_hash);
-# endif
- /* Jitter sample locations and map back to the unit square [0 1]x[0 1]. */
- float sx = fx + dx;
- float sy = fy + dy;
- sx = sx - floorf(sx);
- sy = sy - floorf(sy);
-#else
-# warning "Not using Cranley Patterson Rotation."
-#endif
-
- (*x) = sx;
- (*y) = sy;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
deleted file mode 100644
index b3eaed4fcb0..00000000000
--- a/intern/cycles/kernel/kernel_light.h
+++ /dev/null
@@ -1,875 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "geom/geom.h"
-
-#include "kernel_light_background.h"
-#include "kernel_montecarlo.h"
-#include "kernel_projection.h"
-#include "kernel_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Light Sample result */
-
-typedef struct LightSample {
- float3 P; /* position on light, or direction for distant light */
- float3 Ng; /* normal on light */
- float3 D; /* direction from shading point to light */
- float t; /* distance to light (FLT_MAX for distant light) */
- float u, v; /* parametric coordinate on primitive */
- float pdf; /* light sampling probability density function */
- float eval_fac; /* intensity multiplier */
- int object; /* object id for triangle/curve lights */
- int prim; /* primitive id for triangle/curve lights */
- int shader; /* shader id */
- int lamp; /* lamp id */
- LightType type; /* type of light */
-} LightSample;
-
-/* Regular Light */
-
-template<bool in_volume_segment>
-ccl_device_inline bool light_sample(KernelGlobals kg,
- const int lamp,
- const float randu,
- const float randv,
- const float3 P,
- const uint32_t path_flag,
- ccl_private LightSample *ls)
-{
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
- if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
- if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) {
- return false;
- }
- }
-
- LightType type = (LightType)klight->type;
- ls->type = type;
- ls->shader = klight->shader_id;
- ls->object = PRIM_NONE;
- ls->prim = PRIM_NONE;
- ls->lamp = lamp;
- ls->u = randu;
- ls->v = randv;
-
- if (in_volume_segment && (type == LIGHT_DISTANT || type == LIGHT_BACKGROUND)) {
- /* Distant lights in a volume get a dummy sample, position will not actually
- * be used in that case. Only when sampling from a specific scatter position
- * do we actually need to evaluate these. */
- ls->P = zero_float3();
- ls->Ng = zero_float3();
- ls->D = zero_float3();
- ls->pdf = true;
- ls->t = FLT_MAX;
- return true;
- }
-
- if (type == LIGHT_DISTANT) {
- /* distant light */
- float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
- float3 D = lightD;
- float radius = klight->distant.radius;
- float invarea = klight->distant.invarea;
-
- if (radius > 0.0f)
- D = distant_light_sample(D, radius, randu, randv);
-
- ls->P = D;
- ls->Ng = D;
- ls->D = -D;
- ls->t = FLT_MAX;
-
- float costheta = dot(lightD, D);
- ls->pdf = invarea / (costheta * costheta * costheta);
- ls->eval_fac = ls->pdf;
- }
-#ifdef __BACKGROUND_MIS__
- else if (type == LIGHT_BACKGROUND) {
- /* infinite area light (e.g. light dome or env light) */
- float3 D = -background_light_sample(kg, P, randu, randv, &ls->pdf);
-
- ls->P = D;
- ls->Ng = D;
- ls->D = -D;
- ls->t = FLT_MAX;
- ls->eval_fac = 1.0f;
- }
-#endif
- else {
- ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
-
- if (type == LIGHT_POINT || type == LIGHT_SPOT) {
- float radius = klight->spot.radius;
-
- if (radius > 0.0f)
- /* sphere light */
- ls->P += sphere_light_sample(P, ls->P, radius, randu, randv);
-
- ls->D = normalize_len(ls->P - P, &ls->t);
- ls->Ng = -ls->D;
-
- float invarea = klight->spot.invarea;
- ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
- ls->pdf = invarea;
-
- if (type == LIGHT_SPOT) {
- /* spot light attenuation */
- float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
- ls->eval_fac *= spot_light_attenuation(
- dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng);
- if (ls->eval_fac == 0.0f) {
- return false;
- }
- }
- float2 uv = map_to_sphere(ls->Ng);
- ls->u = uv.x;
- ls->v = uv.y;
-
- ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
- }
- else {
- /* area light */
- float3 axisu = make_float3(
- klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
- float3 axisv = make_float3(
- klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
- float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
- float invarea = fabsf(klight->area.invarea);
- bool is_round = (klight->area.invarea < 0.0f);
-
- if (!in_volume_segment) {
- if (dot(ls->P - P, Ng) > 0.0f) {
- return false;
- }
- }
-
- float3 inplane;
-
- if (is_round || in_volume_segment) {
- inplane = ellipse_sample(axisu * 0.5f, axisv * 0.5f, randu, randv);
- ls->P += inplane;
- ls->pdf = invarea;
- }
- else {
- inplane = ls->P;
-
- float3 sample_axisu = axisu;
- float3 sample_axisv = axisv;
-
- if (klight->area.tan_spread > 0.0f) {
- if (!light_spread_clamp_area_light(
- P, Ng, &ls->P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
- return false;
- }
- }
-
- ls->pdf = rect_light_sample(P, &ls->P, sample_axisu, sample_axisv, randu, randv, true);
- inplane = ls->P - inplane;
- }
-
- ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f;
- ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f;
-
- ls->Ng = Ng;
- ls->D = normalize_len(ls->P - P, &ls->t);
-
- ls->eval_fac = 0.25f * invarea;
-
- if (klight->area.tan_spread > 0.0f) {
- /* Area Light spread angle attenuation */
- ls->eval_fac *= light_spread_attenuation(
- ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
- }
-
- if (is_round) {
- ls->pdf *= lamp_light_pdf(kg, Ng, -ls->D, ls->t);
- }
- }
- }
-
- ls->pdf *= kernel_data.integrator.pdf_lights;
-
- return (ls->pdf > 0.0f);
-}
-
-ccl_device bool lights_intersect(KernelGlobals kg,
- ccl_private const Ray *ccl_restrict ray,
- ccl_private Intersection *ccl_restrict isect,
- const int last_prim,
- const int last_object,
- const int last_type,
- const uint32_t path_flag)
-{
- for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) {
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
-
- if (path_flag & PATH_RAY_CAMERA) {
- if (klight->shader_id & SHADER_EXCLUDE_CAMERA) {
- continue;
- }
- }
- else {
- if (!(klight->shader_id & SHADER_USE_MIS)) {
- continue;
- }
- }
-
- if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
- if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) {
- continue;
- }
- }
-
- LightType type = (LightType)klight->type;
- float t = 0.0f, u = 0.0f, v = 0.0f;
-
- if (type == LIGHT_POINT || type == LIGHT_SPOT) {
- /* Sphere light. */
- const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
- const float radius = klight->spot.radius;
- if (radius == 0.0f) {
- continue;
- }
-
- float3 P;
- if (!ray_aligned_disk_intersect(ray->P, ray->D, ray->t, lightP, radius, &P, &t)) {
- continue;
- }
- }
- else if (type == LIGHT_AREA) {
- /* Area light. */
- const float invarea = fabsf(klight->area.invarea);
- const bool is_round = (klight->area.invarea < 0.0f);
- if (invarea == 0.0f) {
- continue;
- }
-
- const float3 axisu = make_float3(
- klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
- const float3 axisv = make_float3(
- klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
- const float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
-
- /* One sided. */
- if (dot(ray->D, Ng) >= 0.0f) {
- continue;
- }
-
- const float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
-
- float3 P;
- if (!ray_quad_intersect(
- ray->P, ray->D, 0.0f, ray->t, light_P, axisu, axisv, Ng, &P, &t, &u, &v, is_round)) {
- continue;
- }
- }
- else {
- continue;
- }
-
- if (t < isect->t &&
- !(last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP)) {
- isect->t = t;
- isect->u = u;
- isect->v = v;
- isect->type = PRIMITIVE_LAMP;
- isect->prim = lamp;
- isect->object = OBJECT_NONE;
- }
- }
-
- return isect->prim != PRIM_NONE;
-}
-
-ccl_device bool light_sample_from_distant_ray(KernelGlobals kg,
- const float3 ray_D,
- const int lamp,
- ccl_private LightSample *ccl_restrict ls)
-{
- ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
- const int shader = klight->shader_id;
- const float radius = klight->distant.radius;
- const LightType type = (LightType)klight->type;
-
- if (type != LIGHT_DISTANT) {
- return false;
- }
- if (!(shader & SHADER_USE_MIS)) {
- return false;
- }
- if (radius == 0.0f) {
- return false;
- }
-
- /* a distant light is infinitely far away, but equivalent to a disk
- * shaped light exactly 1 unit away from the current shading point.
- *
- * radius t^2/cos(theta)
- * <----------> t = sqrt(1^2 + tan(theta)^2)
- * tan(th) area = radius*radius*pi
- * <----->
- * \ | (1 + tan(theta)^2)/cos(theta)
- * \ | (1 + tan(acos(cos(theta)))^2)/cos(theta)
- * t \th| 1 simplifies to
- * \-| 1/(cos(theta)^3)
- * \| magic!
- * P
- */
-
- float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
- float costheta = dot(-lightD, ray_D);
- float cosangle = klight->distant.cosangle;
-
- if (costheta < cosangle)
- return false;
-
- ls->type = type;
- ls->shader = klight->shader_id;
- ls->object = PRIM_NONE;
- ls->prim = PRIM_NONE;
- ls->lamp = lamp;
- /* todo: missing texture coordinates */
- ls->u = 0.0f;
- ls->v = 0.0f;
- ls->t = FLT_MAX;
- ls->P = -ray_D;
- ls->Ng = -ray_D;
- ls->D = ray_D;
-
- /* compute pdf */
- float invarea = klight->distant.invarea;
- ls->pdf = invarea / (costheta * costheta * costheta);
- ls->pdf *= kernel_data.integrator.pdf_lights;
- ls->eval_fac = ls->pdf;
-
- return true;
-}
-
-ccl_device bool light_sample_from_intersection(KernelGlobals kg,
- ccl_private const Intersection *ccl_restrict isect,
- const float3 ray_P,
- const float3 ray_D,
- ccl_private LightSample *ccl_restrict ls)
-{
- const int lamp = isect->prim;
- ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
- LightType type = (LightType)klight->type;
- ls->type = type;
- ls->shader = klight->shader_id;
- ls->object = PRIM_NONE;
- ls->prim = PRIM_NONE;
- ls->lamp = lamp;
- /* todo: missing texture coordinates */
- ls->t = isect->t;
- ls->P = ray_P + ray_D * ls->t;
- ls->D = ray_D;
-
- if (type == LIGHT_POINT || type == LIGHT_SPOT) {
- ls->Ng = -ray_D;
-
- float invarea = klight->spot.invarea;
- ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
- ls->pdf = invarea;
-
- if (type == LIGHT_SPOT) {
- /* spot light attenuation */
- float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
- ls->eval_fac *= spot_light_attenuation(
- dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng);
-
- if (ls->eval_fac == 0.0f) {
- return false;
- }
- }
- float2 uv = map_to_sphere(ls->Ng);
- ls->u = uv.x;
- ls->v = uv.y;
-
- /* compute pdf */
- if (ls->t != FLT_MAX)
- ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
- }
- else if (type == LIGHT_AREA) {
- /* area light */
- float invarea = fabsf(klight->area.invarea);
-
- float3 axisu = make_float3(
- klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
- float3 axisv = make_float3(
- klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
- float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
- float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
-
- ls->u = isect->u;
- ls->v = isect->v;
- ls->D = ray_D;
- ls->Ng = Ng;
-
- const bool is_round = (klight->area.invarea < 0.0f);
- if (is_round) {
- ls->pdf = invarea * lamp_light_pdf(kg, Ng, -ray_D, ls->t);
- }
- else {
- float3 sample_axisu = axisu;
- float3 sample_axisv = axisv;
-
- if (klight->area.tan_spread > 0.0f) {
- if (!light_spread_clamp_area_light(
- ray_P, Ng, &light_P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
- return false;
- }
- }
-
- ls->pdf = rect_light_sample(ray_P, &light_P, sample_axisu, sample_axisv, 0, 0, false);
- }
- ls->eval_fac = 0.25f * invarea;
-
- if (klight->area.tan_spread > 0.0f) {
- /* Area Light spread angle attenuation */
- ls->eval_fac *= light_spread_attenuation(
- ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
- if (ls->eval_fac == 0.0f) {
- return false;
- }
- }
- }
- else {
- kernel_assert(!"Invalid lamp type in light_sample_from_intersection");
- return false;
- }
-
- ls->pdf *= kernel_data.integrator.pdf_lights;
-
- return true;
-}
-
-/* Triangle Light */
-
-/* returns true if the triangle is has motion blur or an instancing transform applied */
-ccl_device_inline bool triangle_world_space_vertices(
- KernelGlobals kg, int object, int prim, float time, float3 V[3])
-{
- bool has_motion = false;
- const int object_flag = kernel_tex_fetch(__object_flag, object);
-
- if (object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) {
- motion_triangle_vertices(kg, object, prim, time, V);
- has_motion = true;
- }
- else {
- triangle_vertices(kg, prim, V);
- }
-
- if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
-#ifdef __OBJECT_MOTION__
- float object_time = (time >= 0.0f) ? time : 0.5f;
- Transform tfm = object_fetch_transform_motion_test(kg, object, object_time, NULL);
-#else
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
-#endif
- V[0] = transform_point(&tfm, V[0]);
- V[1] = transform_point(&tfm, V[1]);
- V[2] = transform_point(&tfm, V[2]);
- has_motion = true;
- }
- return has_motion;
-}
-
-ccl_device_inline float triangle_light_pdf_area(KernelGlobals kg,
- const float3 Ng,
- const float3 I,
- float t)
-{
- float pdf = kernel_data.integrator.pdf_triangles;
- float cos_pi = fabsf(dot(Ng, I));
-
- if (cos_pi == 0.0f)
- return 0.0f;
-
- return t * t * pdf / cos_pi;
-}
-
-ccl_device_forceinline float triangle_light_pdf(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- float t)
-{
- /* A naive heuristic to decide between costly solid angle sampling
- * and simple area sampling, comparing the distance to the triangle plane
- * to the length of the edges of the triangle. */
-
- float3 V[3];
- bool has_motion = triangle_world_space_vertices(kg, sd->object, sd->prim, sd->time, V);
-
- const float3 e0 = V[1] - V[0];
- const float3 e1 = V[2] - V[0];
- const float3 e2 = V[2] - V[1];
- const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2)));
- const float3 N = cross(e0, e1);
- const float distance_to_plane = fabsf(dot(N, sd->I * t)) / dot(N, N);
-
- if (longest_edge_squared > distance_to_plane * distance_to_plane) {
- /* sd contains the point on the light source
- * calculate Px, the point that we're shading */
- const float3 Px = sd->P + sd->I * t;
- const float3 v0_p = V[0] - Px;
- const float3 v1_p = V[1] - Px;
- const float3 v2_p = V[2] - Px;
-
- const float3 u01 = safe_normalize(cross(v0_p, v1_p));
- const float3 u02 = safe_normalize(cross(v0_p, v2_p));
- const float3 u12 = safe_normalize(cross(v1_p, v2_p));
-
- const float alpha = fast_acosf(dot(u02, u01));
- const float beta = fast_acosf(-dot(u01, u12));
- const float gamma = fast_acosf(dot(u02, u12));
- const float solid_angle = alpha + beta + gamma - M_PI_F;
-
- /* pdf_triangles is calculated over triangle area, but we're not sampling over its area */
- if (UNLIKELY(solid_angle == 0.0f)) {
- return 0.0f;
- }
- else {
- float area = 1.0f;
- if (has_motion) {
- /* get the center frame vertices, this is what the PDF was calculated from */
- triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V);
- area = triangle_area(V[0], V[1], V[2]);
- }
- else {
- area = 0.5f * len(N);
- }
- const float pdf = area * kernel_data.integrator.pdf_triangles;
- return pdf / solid_angle;
- }
- }
- else {
- float pdf = triangle_light_pdf_area(kg, sd->Ng, sd->I, t);
- if (has_motion) {
- const float area = 0.5f * len(N);
- if (UNLIKELY(area == 0.0f)) {
- return 0.0f;
- }
- /* scale the PDF.
- * area = the area the sample was taken from
- * area_pre = the are from which pdf_triangles was calculated from */
- triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V);
- const float area_pre = triangle_area(V[0], V[1], V[2]);
- pdf = pdf * area_pre / area;
- }
- return pdf;
- }
-}
-
-template<bool in_volume_segment>
-ccl_device_forceinline void triangle_light_sample(KernelGlobals kg,
- int prim,
- int object,
- float randu,
- float randv,
- float time,
- ccl_private LightSample *ls,
- const float3 P)
-{
- /* A naive heuristic to decide between costly solid angle sampling
- * and simple area sampling, comparing the distance to the triangle plane
- * to the length of the edges of the triangle. */
-
- float3 V[3];
- bool has_motion = triangle_world_space_vertices(kg, object, prim, time, V);
-
- const float3 e0 = V[1] - V[0];
- const float3 e1 = V[2] - V[0];
- const float3 e2 = V[2] - V[1];
- const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2)));
- const float3 N0 = cross(e0, e1);
- float Nl = 0.0f;
- ls->Ng = safe_normalize_len(N0, &Nl);
- float area = 0.5f * Nl;
-
- /* flip normal if necessary */
- const int object_flag = kernel_tex_fetch(__object_flag, object);
- if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
- ls->Ng = -ls->Ng;
- }
- ls->eval_fac = 1.0f;
- ls->shader = kernel_tex_fetch(__tri_shader, prim);
- ls->object = object;
- ls->prim = prim;
- ls->lamp = LAMP_NONE;
- ls->shader |= SHADER_USE_MIS;
- ls->type = LIGHT_TRIANGLE;
-
- float distance_to_plane = fabsf(dot(N0, V[0] - P) / dot(N0, N0));
-
- if (!in_volume_segment && (longest_edge_squared > distance_to_plane * distance_to_plane)) {
- /* see James Arvo, "Stratified Sampling of Spherical Triangles"
- * http://www.graphics.cornell.edu/pubs/1995/Arv95c.pdf */
-
- /* project the triangle to the unit sphere
- * and calculate its edges and angles */
- const float3 v0_p = V[0] - P;
- const float3 v1_p = V[1] - P;
- const float3 v2_p = V[2] - P;
-
- const float3 u01 = safe_normalize(cross(v0_p, v1_p));
- const float3 u02 = safe_normalize(cross(v0_p, v2_p));
- const float3 u12 = safe_normalize(cross(v1_p, v2_p));
-
- const float3 A = safe_normalize(v0_p);
- const float3 B = safe_normalize(v1_p);
- const float3 C = safe_normalize(v2_p);
-
- const float cos_alpha = dot(u02, u01);
- const float cos_beta = -dot(u01, u12);
- const float cos_gamma = dot(u02, u12);
-
- /* calculate dihedral angles */
- const float alpha = fast_acosf(cos_alpha);
- const float beta = fast_acosf(cos_beta);
- const float gamma = fast_acosf(cos_gamma);
- /* the area of the unit spherical triangle = solid angle */
- const float solid_angle = alpha + beta + gamma - M_PI_F;
-
- /* precompute a few things
- * these could be re-used to take several samples
- * as they are independent of randu/randv */
- const float cos_c = dot(A, B);
- const float sin_alpha = fast_sinf(alpha);
- const float product = sin_alpha * cos_c;
-
- /* Select a random sub-area of the spherical triangle
- * and calculate the third vertex C_ of that new triangle */
- const float phi = randu * solid_angle - alpha;
- float s, t;
- fast_sincosf(phi, &s, &t);
- const float u = t - cos_alpha;
- const float v = s + product;
-
- const float3 U = safe_normalize(C - dot(C, A) * A);
-
- float q = 1.0f;
- const float det = ((v * s + u * t) * sin_alpha);
- if (det != 0.0f) {
- q = ((v * t - u * s) * cos_alpha - v) / det;
- }
- const float temp = max(1.0f - q * q, 0.0f);
-
- const float3 C_ = safe_normalize(q * A + sqrtf(temp) * U);
-
- /* Finally, select a random point along the edge of the new triangle
- * That point on the spherical triangle is the sampled ray direction */
- const float z = 1.0f - randv * (1.0f - dot(C_, B));
- ls->D = z * B + safe_sqrtf(1.0f - z * z) * safe_normalize(C_ - dot(C_, B) * B);
-
- /* calculate intersection with the planar triangle */
- if (!ray_triangle_intersect(P,
- ls->D,
- FLT_MAX,
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- (ssef *)V,
-#else
- V[0],
- V[1],
- V[2],
-#endif
- &ls->u,
- &ls->v,
- &ls->t)) {
- ls->pdf = 0.0f;
- return;
- }
-
- ls->P = P + ls->D * ls->t;
-
- /* pdf_triangles is calculated over triangle area, but we're sampling over solid angle */
- if (UNLIKELY(solid_angle == 0.0f)) {
- ls->pdf = 0.0f;
- return;
- }
- else {
- if (has_motion) {
- /* get the center frame vertices, this is what the PDF was calculated from */
- triangle_world_space_vertices(kg, object, prim, -1.0f, V);
- area = triangle_area(V[0], V[1], V[2]);
- }
- const float pdf = area * kernel_data.integrator.pdf_triangles;
- ls->pdf = pdf / solid_angle;
- }
- }
- else {
- /* compute random point in triangle. From Eric Heitz's "A Low-Distortion Map Between Triangle
- * and Square" */
- float u = randu;
- float v = randv;
- if (v > u) {
- u *= 0.5f;
- v -= u;
- }
- else {
- v *= 0.5f;
- u -= v;
- }
-
- const float t = 1.0f - u - v;
- ls->P = u * V[0] + v * V[1] + t * V[2];
- /* compute incoming direction, distance and pdf */
- ls->D = normalize_len(ls->P - P, &ls->t);
- ls->pdf = triangle_light_pdf_area(kg, ls->Ng, -ls->D, ls->t);
- if (has_motion && area != 0.0f) {
- /* scale the PDF.
- * area = the area the sample was taken from
- * area_pre = the are from which pdf_triangles was calculated from */
- triangle_world_space_vertices(kg, object, prim, -1.0f, V);
- const float area_pre = triangle_area(V[0], V[1], V[2]);
- ls->pdf = ls->pdf * area_pre / area;
- }
- ls->u = u;
- ls->v = v;
- }
-}
-
-/* Light Distribution */
-
-ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *randu)
-{
- /* This is basically std::upper_bound as used by PBRT, to find a point light or
- * triangle to emit from, proportional to area. a good improvement would be to
- * also sample proportional to power, though it's not so well defined with
- * arbitrary shaders. */
- int first = 0;
- int len = kernel_data.integrator.num_distribution + 1;
- float r = *randu;
-
- do {
- int half_len = len >> 1;
- int middle = first + half_len;
-
- if (r < kernel_tex_fetch(__light_distribution, middle).totarea) {
- len = half_len;
- }
- else {
- first = middle + 1;
- len = len - half_len - 1;
- }
- } while (len > 0);
-
- /* Clamping should not be needed but float rounding errors seem to
- * make this fail on rare occasions. */
- int index = clamp(first - 1, 0, kernel_data.integrator.num_distribution - 1);
-
- /* Rescale to reuse random number. this helps the 2D samples within
- * each area light be stratified as well. */
- float distr_min = kernel_tex_fetch(__light_distribution, index).totarea;
- float distr_max = kernel_tex_fetch(__light_distribution, index + 1).totarea;
- *randu = (r - distr_min) / (distr_max - distr_min);
-
- return index;
-}
-
-/* Generic Light */
-
-ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals kg, int index, int bounce)
-{
- return (bounce > kernel_tex_fetch(__lights, index).max_bounces);
-}
-
-template<bool in_volume_segment>
-ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
- float randu,
- const float randv,
- const float time,
- const float3 P,
- const int bounce,
- const uint32_t path_flag,
- ccl_private LightSample *ls)
-{
- /* Sample light index from distribution. */
- const int index = light_distribution_sample(kg, &randu);
- ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution,
- index);
- const int prim = kdistribution->prim;
-
- if (prim >= 0) {
- /* Mesh light. */
- const int object = kdistribution->mesh_light.object_id;
-
- /* Exclude synthetic meshes from shadow catcher pass. */
- if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) &&
- !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) {
- return false;
- }
-
- const int shader_flag = kdistribution->mesh_light.shader_flag;
- triangle_light_sample<in_volume_segment>(kg, prim, object, randu, randv, time, ls, P);
- ls->shader |= shader_flag;
- return (ls->pdf > 0.0f);
- }
-
- const int lamp = -prim - 1;
-
- if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
- return false;
- }
-
- return light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls);
-}
-
-ccl_device_inline bool light_distribution_sample_from_volume_segment(KernelGlobals kg,
- float randu,
- const float randv,
- const float time,
- const float3 P,
- const int bounce,
- const uint32_t path_flag,
- ccl_private LightSample *ls)
-{
- return light_distribution_sample<true>(kg, randu, randv, time, P, bounce, path_flag, ls);
-}
-
-ccl_device_inline bool light_distribution_sample_from_position(KernelGlobals kg,
- float randu,
- const float randv,
- const float time,
- const float3 P,
- const int bounce,
- const uint32_t path_flag,
- ccl_private LightSample *ls)
-{
- return light_distribution_sample<false>(kg, randu, randv, time, P, bounce, path_flag, ls);
-}
-
-ccl_device_inline bool light_distribution_sample_new_position(KernelGlobals kg,
- const float randu,
- const float randv,
- const float time,
- const float3 P,
- ccl_private LightSample *ls)
-{
- /* Sample a new position on the same light, for volume sampling. */
- if (ls->type == LIGHT_TRIANGLE) {
- triangle_light_sample<false>(kg, ls->prim, ls->object, randu, randv, time, ls, P);
- return (ls->pdf > 0.0f);
- }
- else {
- return light_sample<false>(kg, ls->lamp, randu, randv, P, 0, ls);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_light_background.h b/intern/cycles/kernel/kernel_light_background.h
deleted file mode 100644
index 2e828b8b765..00000000000
--- a/intern/cycles/kernel/kernel_light_background.h
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel_light_common.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Background Light */
-
-#ifdef __BACKGROUND_MIS__
-
-ccl_device float3 background_map_sample(KernelGlobals kg,
- float randu,
- float randv,
- ccl_private float *pdf)
-{
- /* for the following, the CDF values are actually a pair of floats, with the
- * function value as X and the actual CDF as Y. The last entry's function
- * value is the CDF total. */
- int res_x = kernel_data.background.map_res_x;
- int res_y = kernel_data.background.map_res_y;
- int cdf_width = res_x + 1;
-
- /* This is basically std::lower_bound as used by PBRT. */
- int first = 0;
- int count = res_y;
-
- while (count > 0) {
- int step = count >> 1;
- int middle = first + step;
-
- if (kernel_tex_fetch(__light_background_marginal_cdf, middle).y < randv) {
- first = middle + 1;
- count -= step + 1;
- }
- else
- count = step;
- }
-
- int index_v = max(0, first - 1);
- kernel_assert(index_v >= 0 && index_v < res_y);
-
- float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
- float2 cdf_next_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v + 1);
- float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y);
-
- /* importance-sampled V direction */
- float dv = inverse_lerp(cdf_v.y, cdf_next_v.y, randv);
- float v = (index_v + dv) / res_y;
-
- /* This is basically std::lower_bound as used by PBRT. */
- first = 0;
- count = res_x;
- while (count > 0) {
- int step = count >> 1;
- int middle = first + step;
-
- if (kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_width + middle).y <
- randu) {
- first = middle + 1;
- count -= step + 1;
- }
- else
- count = step;
- }
-
- int index_u = max(0, first - 1);
- kernel_assert(index_u >= 0 && index_u < res_x);
-
- float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf,
- index_v * cdf_width + index_u);
- float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf,
- index_v * cdf_width + index_u + 1);
- float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf,
- index_v * cdf_width + res_x);
-
- /* importance-sampled U direction */
- float du = inverse_lerp(cdf_u.y, cdf_next_u.y, randu);
- float u = (index_u + du) / res_x;
-
- /* compute pdf */
- float sin_theta = sinf(M_PI_F * v);
- float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x;
-
- if (sin_theta == 0.0f || denom == 0.0f)
- *pdf = 0.0f;
- else
- *pdf = (cdf_u.x * cdf_v.x) / denom;
-
- /* compute direction */
- return equirectangular_to_direction(u, v);
-}
-
-/* TODO(sergey): Same as above, after the release we should consider using
- * 'noinline' for all devices.
- */
-ccl_device float background_map_pdf(KernelGlobals kg, float3 direction)
-{
- float2 uv = direction_to_equirectangular(direction);
- int res_x = kernel_data.background.map_res_x;
- int res_y = kernel_data.background.map_res_y;
- int cdf_width = res_x + 1;
-
- float sin_theta = sinf(uv.y * M_PI_F);
-
- if (sin_theta == 0.0f)
- return 0.0f;
-
- int index_u = clamp(float_to_int(uv.x * res_x), 0, res_x - 1);
- int index_v = clamp(float_to_int(uv.y * res_y), 0, res_y - 1);
-
- /* pdfs in V direction */
- float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf,
- index_v * cdf_width + res_x);
- float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y);
-
- float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x;
-
- if (denom == 0.0f)
- return 0.0f;
-
- /* pdfs in U direction */
- float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf,
- index_v * cdf_width + index_u);
- float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
-
- return (cdf_u.x * cdf_v.x) / denom;
-}
-
-ccl_device_inline bool background_portal_data_fetch_and_check_side(
- KernelGlobals kg, float3 P, int index, ccl_private float3 *lightpos, ccl_private float3 *dir)
-{
- int portal = kernel_data.background.portal_offset + index;
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
-
- *lightpos = make_float3(klight->co[0], klight->co[1], klight->co[2]);
- *dir = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
-
- /* Check whether portal is on the right side. */
- if (dot(*dir, P - *lightpos) > 1e-4f)
- return true;
-
- return false;
-}
-
-ccl_device_inline float background_portal_pdf(
- KernelGlobals kg, float3 P, float3 direction, int ignore_portal, ccl_private bool *is_possible)
-{
- float portal_pdf = 0.0f;
-
- int num_possible = 0;
- for (int p = 0; p < kernel_data.background.num_portals; p++) {
- if (p == ignore_portal)
- continue;
-
- float3 lightpos, dir;
- if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
- continue;
-
- /* There's a portal that could be sampled from this position. */
- if (is_possible) {
- *is_possible = true;
- }
- num_possible++;
-
- int portal = kernel_data.background.portal_offset + p;
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
- float3 axisu = make_float3(
- klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
- float3 axisv = make_float3(
- klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
- bool is_round = (klight->area.invarea < 0.0f);
-
- if (!ray_quad_intersect(P,
- direction,
- 1e-4f,
- FLT_MAX,
- lightpos,
- axisu,
- axisv,
- dir,
- NULL,
- NULL,
- NULL,
- NULL,
- is_round))
- continue;
-
- if (is_round) {
- float t;
- float3 D = normalize_len(lightpos - P, &t);
- portal_pdf += fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t);
- }
- else {
- portal_pdf += rect_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false);
- }
- }
-
- if (ignore_portal >= 0) {
- /* We have skipped a portal that could be sampled as well. */
- num_possible++;
- }
-
- return (num_possible > 0) ? portal_pdf / num_possible : 0.0f;
-}
-
-ccl_device int background_num_possible_portals(KernelGlobals kg, float3 P)
-{
- int num_possible_portals = 0;
- for (int p = 0; p < kernel_data.background.num_portals; p++) {
- float3 lightpos, dir;
- if (background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
- num_possible_portals++;
- }
- return num_possible_portals;
-}
-
-ccl_device float3 background_portal_sample(KernelGlobals kg,
- float3 P,
- float randu,
- float randv,
- int num_possible,
- ccl_private int *sampled_portal,
- ccl_private float *pdf)
-{
- /* Pick a portal, then re-normalize randv. */
- randv *= num_possible;
- int portal = (int)randv;
- randv -= portal;
-
- /* TODO(sergey): Some smarter way of finding portal to sample
- * is welcome.
- */
- for (int p = 0; p < kernel_data.background.num_portals; p++) {
- /* Search for the sampled portal. */
- float3 lightpos, dir;
- if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
- continue;
-
- if (portal == 0) {
- /* p is the portal to be sampled. */
- int portal = kernel_data.background.portal_offset + p;
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
- float3 axisu = make_float3(
- klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
- float3 axisv = make_float3(
- klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
- bool is_round = (klight->area.invarea < 0.0f);
-
- float3 D;
- if (is_round) {
- lightpos += ellipse_sample(axisu * 0.5f, axisv * 0.5f, randu, randv);
- float t;
- D = normalize_len(lightpos - P, &t);
- *pdf = fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t);
- }
- else {
- *pdf = rect_light_sample(P, &lightpos, axisu, axisv, randu, randv, true);
- D = normalize(lightpos - P);
- }
-
- *pdf /= num_possible;
- *sampled_portal = p;
- return D;
- }
-
- portal--;
- }
-
- return zero_float3();
-}
-
-ccl_device_inline float3 background_sun_sample(KernelGlobals kg,
- float randu,
- float randv,
- ccl_private float *pdf)
-{
- float3 D;
- const float3 N = float4_to_float3(kernel_data.background.sun);
- const float angle = kernel_data.background.sun.w;
- sample_uniform_cone(N, angle, randu, randv, &D, pdf);
- return D;
-}
-
-ccl_device_inline float background_sun_pdf(KernelGlobals kg, float3 D)
-{
- const float3 N = float4_to_float3(kernel_data.background.sun);
- const float angle = kernel_data.background.sun.w;
- return pdf_uniform_cone(N, D, angle);
-}
-
-ccl_device_inline float3 background_light_sample(
- KernelGlobals kg, float3 P, float randu, float randv, ccl_private float *pdf)
-{
- float portal_method_pdf = kernel_data.background.portal_weight;
- float sun_method_pdf = kernel_data.background.sun_weight;
- float map_method_pdf = kernel_data.background.map_weight;
-
- int num_portals = 0;
- if (portal_method_pdf > 0.0f) {
- /* Check if there are portals in the scene which we can sample. */
- num_portals = background_num_possible_portals(kg, P);
- if (num_portals == 0) {
- portal_method_pdf = 0.0f;
- }
- }
-
- float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf);
- if (pdf_fac == 0.0f) {
- /* Use uniform as a fallback if we can't use any strategy. */
- *pdf = 1.0f / M_4PI_F;
- return sample_uniform_sphere(randu, randv);
- }
-
- pdf_fac = 1.0f / pdf_fac;
- portal_method_pdf *= pdf_fac;
- sun_method_pdf *= pdf_fac;
- map_method_pdf *= pdf_fac;
-
- /* We have 100% in total and split it between the three categories.
- * Therefore, we pick portals if randu is between 0 and portal_method_pdf,
- * sun if randu is between portal_method_pdf and (portal_method_pdf + sun_method_pdf)
- * and map if randu is between (portal_method_pdf + sun_method_pdf) and 1. */
- float sun_method_cdf = portal_method_pdf + sun_method_pdf;
-
- int method = 0;
- float3 D;
- if (randu < portal_method_pdf) {
- method = 0;
- /* Rescale randu. */
- if (portal_method_pdf != 1.0f) {
- randu /= portal_method_pdf;
- }
-
- /* Sample a portal. */
- int portal;
- D = background_portal_sample(kg, P, randu, randv, num_portals, &portal, pdf);
- if (num_portals > 1) {
- /* Ignore the chosen portal, its pdf is already included. */
- *pdf += background_portal_pdf(kg, P, D, portal, NULL);
- }
-
- /* Skip MIS if this is the only method. */
- if (portal_method_pdf == 1.0f) {
- return D;
- }
- *pdf *= portal_method_pdf;
- }
- else if (randu < sun_method_cdf) {
- method = 1;
- /* Rescale randu. */
- if (sun_method_pdf != 1.0f) {
- randu = (randu - portal_method_pdf) / sun_method_pdf;
- }
-
- D = background_sun_sample(kg, randu, randv, pdf);
-
- /* Skip MIS if this is the only method. */
- if (sun_method_pdf == 1.0f) {
- return D;
- }
- *pdf *= sun_method_pdf;
- }
- else {
- method = 2;
- /* Rescale randu. */
- if (map_method_pdf != 1.0f) {
- randu = (randu - sun_method_cdf) / map_method_pdf;
- }
-
- D = background_map_sample(kg, randu, randv, pdf);
-
- /* Skip MIS if this is the only method. */
- if (map_method_pdf == 1.0f) {
- return D;
- }
- *pdf *= map_method_pdf;
- }
-
- /* MIS weighting. */
- if (method != 0 && portal_method_pdf != 0.0f) {
- *pdf += portal_method_pdf * background_portal_pdf(kg, P, D, -1, NULL);
- }
- if (method != 1 && sun_method_pdf != 0.0f) {
- *pdf += sun_method_pdf * background_sun_pdf(kg, D);
- }
- if (method != 2 && map_method_pdf != 0.0f) {
- *pdf += map_method_pdf * background_map_pdf(kg, D);
- }
- return D;
-}
-
-ccl_device float background_light_pdf(KernelGlobals kg, float3 P, float3 direction)
-{
- float portal_method_pdf = kernel_data.background.portal_weight;
- float sun_method_pdf = kernel_data.background.sun_weight;
- float map_method_pdf = kernel_data.background.map_weight;
-
- float portal_pdf = 0.0f;
- /* Portals are a special case here since we need to compute their pdf in order
- * to find out if we can sample them. */
- if (portal_method_pdf > 0.0f) {
- /* Evaluate PDF of sampling this direction by portal sampling. */
- bool is_possible = false;
- portal_pdf = background_portal_pdf(kg, P, direction, -1, &is_possible);
- if (!is_possible) {
- /* Portal sampling is not possible here because all portals point to the wrong side.
- * If other methods can be used instead, do so, otherwise uniform sampling is used as a
- * fallback. */
- portal_method_pdf = 0.0f;
- }
- }
-
- float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf);
- if (pdf_fac == 0.0f) {
- /* Use uniform as a fallback if we can't use any strategy. */
- return kernel_data.integrator.pdf_lights / M_4PI_F;
- }
-
- pdf_fac = 1.0f / pdf_fac;
- portal_method_pdf *= pdf_fac;
- sun_method_pdf *= pdf_fac;
- map_method_pdf *= pdf_fac;
-
- float pdf = portal_pdf * portal_method_pdf;
- if (sun_method_pdf != 0.0f) {
- pdf += background_sun_pdf(kg, direction) * sun_method_pdf;
- }
- if (map_method_pdf != 0.0f) {
- pdf += background_map_pdf(kg, direction) * map_method_pdf;
- }
-
- return pdf * kernel_data.integrator.pdf_lights;
-}
-
-#endif
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_light_common.h b/intern/cycles/kernel/kernel_light_common.h
deleted file mode 100644
index 9e2b738f376..00000000000
--- a/intern/cycles/kernel/kernel_light_common.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel_montecarlo.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Area light sampling */
-
-/* Uses the following paper:
- *
- * Carlos Urena et al.
- * An Area-Preserving Parametrization for Spherical Rectangles.
- *
- * https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf
- *
- * Note: light_p is modified when sample_coord is true.
- */
-ccl_device_inline float rect_light_sample(float3 P,
- ccl_private float3 *light_p,
- float3 axisu,
- float3 axisv,
- float randu,
- float randv,
- bool sample_coord)
-{
- /* In our name system we're using P for the center,
- * which is o in the paper.
- */
-
- float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f;
- float axisu_len, axisv_len;
- /* Compute local reference system R. */
- float3 x = normalize_len(axisu, &axisu_len);
- float3 y = normalize_len(axisv, &axisv_len);
- float3 z = cross(x, y);
- /* Compute rectangle coords in local reference system. */
- float3 dir = corner - P;
- float z0 = dot(dir, z);
- /* Flip 'z' to make it point against Q. */
- if (z0 > 0.0f) {
- z *= -1.0f;
- z0 *= -1.0f;
- }
- float x0 = dot(dir, x);
- float y0 = dot(dir, y);
- float x1 = x0 + axisu_len;
- float y1 = y0 + axisv_len;
- /* Compute internal angles (gamma_i). */
- float4 diff = make_float4(x0, y1, x1, y0) - make_float4(x1, y0, x0, y1);
- float4 nz = make_float4(y0, x1, y1, x0) * diff;
- nz = nz / sqrt(z0 * z0 * diff * diff + nz * nz);
- float g0 = safe_acosf(-nz.x * nz.y);
- float g1 = safe_acosf(-nz.y * nz.z);
- float g2 = safe_acosf(-nz.z * nz.w);
- float g3 = safe_acosf(-nz.w * nz.x);
- /* Compute predefined constants. */
- float b0 = nz.x;
- float b1 = nz.z;
- float b0sq = b0 * b0;
- float k = M_2PI_F - g2 - g3;
- /* Compute solid angle from internal angles. */
- float S = g0 + g1 - k;
-
- if (sample_coord) {
- /* Compute cu. */
- float au = randu * S + k;
- float fu = (cosf(au) * b0 - b1) / sinf(au);
- float cu = 1.0f / sqrtf(fu * fu + b0sq) * (fu > 0.0f ? 1.0f : -1.0f);
- cu = clamp(cu, -1.0f, 1.0f);
- /* Compute xu. */
- float xu = -(cu * z0) / max(sqrtf(1.0f - cu * cu), 1e-7f);
- xu = clamp(xu, x0, x1);
- /* Compute yv. */
- float z0sq = z0 * z0;
- float y0sq = y0 * y0;
- float y1sq = y1 * y1;
- float d = sqrtf(xu * xu + z0sq);
- float h0 = y0 / sqrtf(d * d + y0sq);
- float h1 = y1 / sqrtf(d * d + y1sq);
- float hv = h0 + randv * (h1 - h0), hv2 = hv * hv;
- float yv = (hv2 < 1.0f - 1e-6f) ? (hv * d) / sqrtf(1.0f - hv2) : y1;
-
- /* Transform (xu, yv, z0) to world coords. */
- *light_p = P + xu * x + yv * y + z0 * z;
- }
-
- /* return pdf */
- if (S != 0.0f)
- return 1.0f / S;
- else
- return 0.0f;
-}
-
-ccl_device_inline float3 ellipse_sample(float3 ru, float3 rv, float randu, float randv)
-{
- to_unit_disk(&randu, &randv);
- return ru * randu + rv * randv;
-}
-
-ccl_device float3 disk_light_sample(float3 v, float randu, float randv)
-{
- float3 ru, rv;
-
- make_orthonormals(v, &ru, &rv);
-
- return ellipse_sample(ru, rv, randu, randv);
-}
-
-ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv)
-{
- return normalize(D + disk_light_sample(D, randu, randv) * radius);
-}
-
-ccl_device float3
-sphere_light_sample(float3 P, float3 center, float radius, float randu, float randv)
-{
- return disk_light_sample(normalize(P - center), randu, randv) * radius;
-}
-
-ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, float3 N)
-{
- float attenuation = dot(dir, N);
-
- if (attenuation <= spot_angle) {
- attenuation = 0.0f;
- }
- else {
- float t = attenuation - spot_angle;
-
- if (t < spot_smooth && spot_smooth != 0.0f)
- attenuation *= smoothstepf(t / spot_smooth);
- }
-
- return attenuation;
-}
-
-ccl_device float light_spread_attenuation(const float3 D,
- const float3 lightNg,
- const float tan_spread,
- const float normalize_spread)
-{
- /* Model a soft-box grid, computing the ratio of light not hidden by the
- * slats of the grid at a given angle. (see D10594). */
- const float cos_a = -dot(D, lightNg);
- const float sin_a = safe_sqrtf(1.0f - sqr(cos_a));
- const float tan_a = sin_a / cos_a;
- return max((1.0f - (tan_spread * tan_a)) * normalize_spread, 0.0f);
-}
-
-/* Compute subset of area light that actually has an influence on the shading point, to
- * reduce noise with low spread. */
-ccl_device bool light_spread_clamp_area_light(const float3 P,
- const float3 lightNg,
- ccl_private float3 *lightP,
- ccl_private float3 *axisu,
- ccl_private float3 *axisv,
- const float tan_spread)
-{
- /* Closest point in area light plane and distance to that plane. */
- const float3 closest_P = P - dot(lightNg, P - *lightP) * lightNg;
- const float t = len(closest_P - P);
-
- /* Radius of circle on area light that actually affects the shading point. */
- const float radius = t / tan_spread;
-
- /* TODO: would be faster to store as normalized vector + length, also in rect_light_sample. */
- float len_u, len_v;
- const float3 u = normalize_len(*axisu, &len_u);
- const float3 v = normalize_len(*axisv, &len_v);
-
- /* Local uv coordinates of closest point. */
- const float closest_u = dot(u, closest_P - *lightP);
- const float closest_v = dot(v, closest_P - *lightP);
-
- /* Compute rectangle encompassing the circle that affects the shading point,
- * clamped to the bounds of the area light. */
- const float min_u = max(closest_u - radius, -len_u * 0.5f);
- const float max_u = min(closest_u + radius, len_u * 0.5f);
- const float min_v = max(closest_v - radius, -len_v * 0.5f);
- const float max_v = min(closest_v + radius, len_v * 0.5f);
-
- /* Skip if rectangle is empty. */
- if (min_u >= max_u || min_v >= max_v) {
- return false;
- }
-
- /* Compute new area light center position and axes from rectangle in local
- * uv coordinates. */
- const float new_center_u = 0.5f * (min_u + max_u);
- const float new_center_v = 0.5f * (min_v + max_v);
- const float new_len_u = max_u - min_u;
- const float new_len_v = max_v - min_v;
-
- *lightP = *lightP + new_center_u * u + new_center_v * v;
- *axisu = u * new_len_u;
- *axisv = v * new_len_v;
-
- return true;
-}
-
-ccl_device float lamp_light_pdf(KernelGlobals kg, const float3 Ng, const float3 I, float t)
-{
- float cos_pi = dot(Ng, I);
-
- if (cos_pi <= 0.0f)
- return 0.0f;
-
- return t * t / cos_pi;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_lookup_table.h b/intern/cycles/kernel/kernel_lookup_table.h
deleted file mode 100644
index 2c26e668d7b..00000000000
--- a/intern/cycles/kernel/kernel_lookup_table.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* Interpolated lookup table access */
-
-ccl_device float lookup_table_read(KernelGlobals kg, float x, int offset, int size)
-{
- x = saturate(x) * (size - 1);
-
- int index = min(float_to_int(x), size - 1);
- int nindex = min(index + 1, size - 1);
- float t = x - index;
-
- float data0 = kernel_tex_fetch(__lookup_table, index + offset);
- if (t == 0.0f)
- return data0;
-
- float data1 = kernel_tex_fetch(__lookup_table, nindex + offset);
- return (1.0f - t) * data0 + t * data1;
-}
-
-ccl_device float lookup_table_read_2D(
- KernelGlobals kg, float x, float y, int offset, int xsize, int ysize)
-{
- y = saturate(y) * (ysize - 1);
-
- int index = min(float_to_int(y), ysize - 1);
- int nindex = min(index + 1, ysize - 1);
- float t = y - index;
-
- float data0 = lookup_table_read(kg, x, offset + xsize * index, xsize);
- if (t == 0.0f)
- return data0;
-
- float data1 = lookup_table_read(kg, x, offset + xsize * nindex, xsize);
- return (1.0f - t) * data0 + t * data1;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_math.h b/intern/cycles/kernel/kernel_math.h
deleted file mode 100644
index 3c5ab95bbc8..00000000000
--- a/intern/cycles/kernel/kernel_math.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "util/util_color.h"
-#include "util/util_math.h"
-#include "util/util_math_fast.h"
-#include "util/util_math_intersect.h"
-#include "util/util_projection.h"
-#include "util/util_texture.h"
-#include "util/util_transform.h"
diff --git a/intern/cycles/kernel/kernel_montecarlo.h b/intern/cycles/kernel/kernel_montecarlo.h
deleted file mode 100644
index c931aa45276..00000000000
--- a/intern/cycles/kernel/kernel_montecarlo.h
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Parts adapted from Open Shading Language with this license:
- *
- * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
- * All Rights Reserved.
- *
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Sony Pictures Imageworks nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* distribute uniform xy on [0,1] over unit disk [-1,1] */
-ccl_device void to_unit_disk(ccl_private float *x, ccl_private float *y)
-{
- float phi = M_2PI_F * (*x);
- float r = sqrtf(*y);
-
- *x = r * cosf(phi);
- *y = r * sinf(phi);
-}
-
-/* return an orthogonal tangent and bitangent given a normal and tangent that
- * may not be exactly orthogonal */
-ccl_device void make_orthonormals_tangent(const float3 N,
- const float3 T,
- ccl_private float3 *a,
- ccl_private float3 *b)
-{
- *b = normalize(cross(N, T));
- *a = cross(*b, N);
-}
-
-/* sample direction with cosine weighted distributed in hemisphere */
-ccl_device_inline void sample_cos_hemisphere(
- const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf)
-{
- to_unit_disk(&randu, &randv);
- float costheta = sqrtf(max(1.0f - randu * randu - randv * randv, 0.0f));
- float3 T, B;
- make_orthonormals(N, &T, &B);
- *omega_in = randu * T + randv * B + costheta * N;
- *pdf = costheta * M_1_PI_F;
-}
-
-/* sample direction uniformly distributed in hemisphere */
-ccl_device_inline void sample_uniform_hemisphere(
- const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf)
-{
- float z = randu;
- float r = sqrtf(max(0.0f, 1.0f - z * z));
- float phi = M_2PI_F * randv;
- float x = r * cosf(phi);
- float y = r * sinf(phi);
-
- float3 T, B;
- make_orthonormals(N, &T, &B);
- *omega_in = x * T + y * B + z * N;
- *pdf = 0.5f * M_1_PI_F;
-}
-
-/* sample direction uniformly distributed in cone */
-ccl_device_inline void sample_uniform_cone(const float3 N,
- float angle,
- float randu,
- float randv,
- ccl_private float3 *omega_in,
- ccl_private float *pdf)
-{
- float zMin = cosf(angle);
- float z = zMin - zMin * randu + randu;
- float r = safe_sqrtf(1.0f - sqr(z));
- float phi = M_2PI_F * randv;
- float x = r * cosf(phi);
- float y = r * sinf(phi);
-
- float3 T, B;
- make_orthonormals(N, &T, &B);
- *omega_in = x * T + y * B + z * N;
- *pdf = M_1_2PI_F / (1.0f - zMin);
-}
-
-ccl_device_inline float pdf_uniform_cone(const float3 N, float3 D, float angle)
-{
- float zMin = cosf(angle);
- float z = dot(N, D);
- if (z > zMin) {
- return M_1_2PI_F / (1.0f - zMin);
- }
- return 0.0f;
-}
-
-/* sample uniform point on the surface of a sphere */
-ccl_device float3 sample_uniform_sphere(float u1, float u2)
-{
- float z = 1.0f - 2.0f * u1;
- float r = sqrtf(fmaxf(0.0f, 1.0f - z * z));
- float phi = M_2PI_F * u2;
- float x = r * cosf(phi);
- float y = r * sinf(phi);
-
- return make_float3(x, y, z);
-}
-
-ccl_device float balance_heuristic(float a, float b)
-{
- return (a) / (a + b);
-}
-
-ccl_device float balance_heuristic_3(float a, float b, float c)
-{
- return (a) / (a + b + c);
-}
-
-ccl_device float power_heuristic(float a, float b)
-{
- return (a * a) / (a * a + b * b);
-}
-
-ccl_device float power_heuristic_3(float a, float b, float c)
-{
- return (a * a) / (a * a + b * b + c * c);
-}
-
-ccl_device float max_heuristic(float a, float b)
-{
- return (a > b) ? 1.0f : 0.0f;
-}
-
-/* distribute uniform xy on [0,1] over unit disk [-1,1], with concentric mapping
- * to better preserve stratification for some RNG sequences */
-ccl_device float2 concentric_sample_disk(float u1, float u2)
-{
- float phi, r;
- float a = 2.0f * u1 - 1.0f;
- float b = 2.0f * u2 - 1.0f;
-
- if (a == 0.0f && b == 0.0f) {
- return zero_float2();
- }
- else if (a * a > b * b) {
- r = a;
- phi = M_PI_4_F * (b / a);
- }
- else {
- r = b;
- phi = M_PI_2_F - M_PI_4_F * (a / b);
- }
-
- return make_float2(r * cosf(phi), r * sinf(phi));
-}
-
-/* sample point in unit polygon with given number of corners and rotation */
-ccl_device float2 regular_polygon_sample(float corners, float rotation, float u, float v)
-{
- /* sample corner number and reuse u */
- float corner = floorf(u * corners);
- u = u * corners - corner;
-
- /* uniform sampled triangle weights */
- u = sqrtf(u);
- v = v * u;
- u = 1.0f - u;
-
- /* point in triangle */
- float angle = M_PI_F / corners;
- float2 p = make_float2((u + v) * cosf(angle), (u - v) * sinf(angle));
-
- /* rotate */
- rotation += corner * 2.0f * angle;
-
- float cr = cosf(rotation);
- float sr = sinf(rotation);
-
- return make_float2(cr * p.x - sr * p.y, sr * p.x + cr * p.y);
-}
-
-ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N)
-{
- float3 R = 2 * dot(N, I) * N - I;
-
- /* Reflection rays may always be at least as shallow as the incoming ray. */
- float threshold = min(0.9f * dot(Ng, I), 0.01f);
- if (dot(Ng, R) >= threshold) {
- return N;
- }
-
- /* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane.
- * The X axis is found by normalizing the component of N that's orthogonal to Ng.
- * The Y axis isn't actually needed.
- */
- float NdotNg = dot(N, Ng);
- float3 X = normalize(N - NdotNg * Ng);
-
- /* Keep math expressions. */
- /* clang-format off */
- /* Calculate N.z and N.x in the local coordinate system.
- *
- * The goal of this computation is to find a N' that is rotated towards Ng just enough
- * to lift R' above the threshold (here called t), therefore dot(R', Ng) = t.
- *
- * According to the standard reflection equation,
- * this means that we want dot(2*dot(N', I)*N' - I, Ng) = t.
- *
- * Since the Z axis of our local coordinate system is Ng, dot(x, Ng) is just x.z, so we get
- * 2*dot(N', I)*N'.z - I.z = t.
- *
- * The rotation is simple to express in the coordinate system we formed -
- * since N lies in the X-Z-plane, we know that N' will also lie in the X-Z-plane,
- * so N'.y = 0 and therefore dot(N', I) = N'.x*I.x + N'.z*I.z .
- *
- * Furthermore, we want N' to be normalized, so N'.x = sqrt(1 - N'.z^2).
- *
- * With these simplifications,
- * we get the final equation 2*(sqrt(1 - N'.z^2)*I.x + N'.z*I.z)*N'.z - I.z = t.
- *
- * The only unknown here is N'.z, so we can solve for that.
- *
- * The equation has four solutions in general:
- *
- * N'.z = +-sqrt(0.5*(+-sqrt(I.x^2*(I.x^2 + I.z^2 - t^2)) + t*I.z + I.x^2 + I.z^2)/(I.x^2 + I.z^2))
- * We can simplify this expression a bit by grouping terms:
- *
- * a = I.x^2 + I.z^2
- * b = sqrt(I.x^2 * (a - t^2))
- * c = I.z*t + a
- * N'.z = +-sqrt(0.5*(+-b + c)/a)
- *
- * Two solutions can immediately be discarded because they're negative so N' would lie in the
- * lower hemisphere.
- */
- /* clang-format on */
-
- float Ix = dot(I, X), Iz = dot(I, Ng);
- float Ix2 = sqr(Ix), Iz2 = sqr(Iz);
- float a = Ix2 + Iz2;
-
- float b = safe_sqrtf(Ix2 * (a - sqr(threshold)));
- float c = Iz * threshold + a;
-
- /* Evaluate both solutions.
- * In many cases one can be immediately discarded (if N'.z would be imaginary or larger than
- * one), so check for that first. If no option is viable (might happen in extreme cases like N
- * being in the wrong hemisphere), give up and return Ng. */
- float fac = 0.5f / a;
- float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c);
- bool valid1 = (N1_z2 > 1e-5f) && (N1_z2 <= (1.0f + 1e-5f));
- bool valid2 = (N2_z2 > 1e-5f) && (N2_z2 <= (1.0f + 1e-5f));
-
- float2 N_new;
- if (valid1 && valid2) {
- /* If both are possible, do the expensive reflection-based check. */
- float2 N1 = make_float2(safe_sqrtf(1.0f - N1_z2), safe_sqrtf(N1_z2));
- float2 N2 = make_float2(safe_sqrtf(1.0f - N2_z2), safe_sqrtf(N2_z2));
-
- float R1 = 2 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz;
- float R2 = 2 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz;
-
- valid1 = (R1 >= 1e-5f);
- valid2 = (R2 >= 1e-5f);
- if (valid1 && valid2) {
- /* If both solutions are valid, return the one with the shallower reflection since it will be
- * closer to the input (if the original reflection wasn't shallow, we would not be in this
- * part of the function). */
- N_new = (R1 < R2) ? N1 : N2;
- }
- else {
- /* If only one reflection is valid (= positive), pick that one. */
- N_new = (R1 > R2) ? N1 : N2;
- }
- }
- else if (valid1 || valid2) {
- /* Only one solution passes the N'.z criterium, so pick that one. */
- float Nz2 = valid1 ? N1_z2 : N2_z2;
- N_new = make_float2(safe_sqrtf(1.0f - Nz2), safe_sqrtf(Nz2));
- }
- else {
- return Ng;
- }
-
- return N_new.x * X + N_new.y * Ng;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
deleted file mode 100644
index 4e4ffa68d25..00000000000
--- a/intern/cycles/kernel/kernel_passes.h
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/geom/geom.h"
-
-#include "kernel/kernel_id_passes.h"
-#include "kernel/kernel_write_passes.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Get pointer to pixel in render buffer. */
-ccl_device_forceinline ccl_global float *kernel_pass_pixel_render_buffer(
- KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer)
-{
- const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
- const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
- kernel_data.film.pass_stride;
- return render_buffer + render_buffer_offset;
-}
-
-#ifdef __DENOISING_FEATURES__
-
-ccl_device_forceinline void kernel_write_denoising_features_surface(
- KernelGlobals kg,
- IntegratorState state,
- ccl_private const ShaderData *sd,
- ccl_global float *ccl_restrict render_buffer)
-{
- if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_DENOISING_FEATURES)) {
- return;
- }
-
- /* Skip implicitly transparent surfaces. */
- if (sd->flag & SD_HAS_ONLY_VOLUME) {
- return;
- }
-
- ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer);
-
- float3 normal = zero_float3();
- float3 diffuse_albedo = zero_float3();
- float3 specular_albedo = zero_float3();
- float sum_weight = 0.0f, sum_nonspecular_weight = 0.0f;
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (!CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
- continue;
- }
-
- /* All closures contribute to the normal feature, but only diffuse-like ones to the albedo. */
- normal += sc->N * sc->sample_weight;
- sum_weight += sc->sample_weight;
-
- float3 closure_albedo = sc->weight;
- /* Closures that include a Fresnel term typically have weights close to 1 even though their
- * actual contribution is significantly lower.
- * To account for this, we scale their weight by the average fresnel factor (the same is also
- * done for the sample weight in the BSDF setup, so we don't need to scale that here). */
- if (CLOSURE_IS_BSDF_MICROFACET_FRESNEL(sc->type)) {
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc;
- closure_albedo *= bsdf->extra->fresnel_color;
- }
- else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) {
- ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)sc;
- closure_albedo *= bsdf->avg_value;
- }
- else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
- closure_albedo *= bsdf_principled_hair_albedo(sc);
- }
-
- if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) {
- diffuse_albedo += closure_albedo;
- sum_nonspecular_weight += sc->sample_weight;
- }
- else {
- specular_albedo += closure_albedo;
- }
- }
-
- /* Wait for next bounce if 75% or more sample weight belongs to specular-like closures. */
- if ((sum_weight == 0.0f) || (sum_nonspecular_weight * 4.0f > sum_weight)) {
- if (sum_weight != 0.0f) {
- normal /= sum_weight;
- }
-
- if (kernel_data.film.pass_denoising_normal != PASS_UNUSED) {
- /* Transform normal into camera space. */
- const Transform worldtocamera = kernel_data.cam.worldtocamera;
- normal = transform_direction(&worldtocamera, normal);
-
- const float3 denoising_normal = ensure_finite3(normal);
- kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal);
- }
-
- if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) {
- const float3 denoising_feature_throughput = INTEGRATOR_STATE(
- state, path, denoising_feature_throughput);
- const float3 denoising_albedo = ensure_finite3(denoising_feature_throughput *
- diffuse_albedo);
- kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo);
- }
-
- INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES;
- }
- else {
- INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) *= specular_albedo;
- }
-}
-
-ccl_device_forceinline void kernel_write_denoising_features_volume(KernelGlobals kg,
- IntegratorState state,
- const float3 albedo,
- const bool scatter,
- ccl_global float *ccl_restrict
- render_buffer)
-{
- ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer);
- const float3 denoising_feature_throughput = INTEGRATOR_STATE(
- state, path, denoising_feature_throughput);
-
- if (scatter && kernel_data.film.pass_denoising_normal != PASS_UNUSED) {
- /* Assume scatter is sufficiently diffuse to stop writing denoising features. */
- INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES;
-
- /* Write view direction as normal. */
- const float3 denoising_normal = make_float3(0.0f, 0.0f, -1.0f);
- kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal);
- }
-
- if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) {
- /* Write albedo. */
- const float3 denoising_albedo = ensure_finite3(denoising_feature_throughput * albedo);
- kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo);
- }
-}
-#endif /* __DENOISING_FEATURES__ */
-
-#ifdef __SHADOW_CATCHER__
-
-/* Write shadow catcher passes on a bounce from the shadow catcher object. */
-ccl_device_forceinline void kernel_write_shadow_catcher_bounce_data(
- KernelGlobals kg,
- IntegratorState state,
- ccl_private const ShaderData *sd,
- ccl_global float *ccl_restrict render_buffer)
-{
- if (!kernel_data.integrator.has_shadow_catcher) {
- return;
- }
-
- kernel_assert(kernel_data.film.pass_shadow_catcher_sample_count != PASS_UNUSED);
- kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED);
-
- if (!kernel_shadow_catcher_is_path_split_bounce(kg, state, sd->object_flag)) {
- return;
- }
-
- ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer);
-
- /* Count sample for the shadow catcher object. */
- kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_sample_count, 1.0f);
-
- /* Since the split is done, the sample does not contribute to the matte, so accumulate it as
- * transparency to the matte. */
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3,
- average(throughput));
-}
-
-#endif /* __SHADOW_CATCHER__ */
-
-ccl_device_inline size_t kernel_write_id_pass(ccl_global float *ccl_restrict buffer,
- size_t depth,
- float id,
- float matte_weight)
-{
- kernel_write_id_slots(buffer, depth * 2, id, matte_weight);
- return depth * 4;
-}
-
-ccl_device_inline void kernel_write_data_passes(KernelGlobals kg,
- IntegratorState state,
- ccl_private const ShaderData *sd,
- ccl_global float *ccl_restrict render_buffer)
-{
-#ifdef __PASSES__
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- if (!(path_flag & PATH_RAY_CAMERA)) {
- return;
- }
-
- const int flag = kernel_data.film.pass_flag;
-
- if (!(flag & PASS_ANY)) {
- return;
- }
-
- ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer);
-
- if (!(path_flag & PATH_RAY_SINGLE_PASS_DONE)) {
- if (!(sd->flag & SD_TRANSPARENT) || kernel_data.film.pass_alpha_threshold == 0.0f ||
- average(shader_bsdf_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold) {
- if (INTEGRATOR_STATE(state, path, sample) == 0) {
- if (flag & PASSMASK(DEPTH)) {
- const float depth = camera_z_depth(kg, sd->P);
- kernel_write_pass_float(buffer + kernel_data.film.pass_depth, depth);
- }
- if (flag & PASSMASK(OBJECT_ID)) {
- const float id = object_pass_id(kg, sd->object);
- kernel_write_pass_float(buffer + kernel_data.film.pass_object_id, id);
- }
- if (flag & PASSMASK(MATERIAL_ID)) {
- const float id = shader_pass_id(kg, sd);
- kernel_write_pass_float(buffer + kernel_data.film.pass_material_id, id);
- }
- }
-
- if (flag & PASSMASK(POSITION)) {
- const float3 position = sd->P;
- kernel_write_pass_float3(buffer + kernel_data.film.pass_position, position);
- }
- if (flag & PASSMASK(NORMAL)) {
- const float3 normal = shader_bsdf_average_normal(kg, sd);
- kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, normal);
- }
- if (flag & PASSMASK(ROUGHNESS)) {
- const float roughness = shader_bsdf_average_roughness(sd);
- kernel_write_pass_float(buffer + kernel_data.film.pass_roughness, roughness);
- }
- if (flag & PASSMASK(UV)) {
- const float3 uv = primitive_uv(kg, sd);
- kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, uv);
- }
- if (flag & PASSMASK(MOTION)) {
- const float4 speed = primitive_motion_vector(kg, sd);
- kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, speed);
- kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, 1.0f);
- }
-
- INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SINGLE_PASS_DONE;
- }
- }
-
- if (kernel_data.film.cryptomatte_passes) {
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- const float matte_weight = average(throughput) *
- (1.0f - average(shader_bsdf_transparency(kg, sd)));
- if (matte_weight > 0.0f) {
- ccl_global float *cryptomatte_buffer = buffer + kernel_data.film.pass_cryptomatte;
- if (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) {
- const float id = object_cryptomatte_id(kg, sd->object);
- cryptomatte_buffer += kernel_write_id_pass(
- cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight);
- }
- if (kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) {
- const float id = shader_cryptomatte_id(kg, sd->shader);
- cryptomatte_buffer += kernel_write_id_pass(
- cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight);
- }
- if (kernel_data.film.cryptomatte_passes & CRYPT_ASSET) {
- const float id = object_cryptomatte_asset_id(kg, sd->object);
- cryptomatte_buffer += kernel_write_id_pass(
- cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight);
- }
- }
- }
-
- if (flag & PASSMASK(DIFFUSE_COLOR)) {
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- kernel_write_pass_float3(buffer + kernel_data.film.pass_diffuse_color,
- shader_bsdf_diffuse(kg, sd) * throughput);
- }
- if (flag & PASSMASK(GLOSSY_COLOR)) {
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- kernel_write_pass_float3(buffer + kernel_data.film.pass_glossy_color,
- shader_bsdf_glossy(kg, sd) * throughput);
- }
- if (flag & PASSMASK(TRANSMISSION_COLOR)) {
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- kernel_write_pass_float3(buffer + kernel_data.film.pass_transmission_color,
- shader_bsdf_transmission(kg, sd) * throughput);
- }
- if (flag & PASSMASK(MIST)) {
- /* Bring depth into 0..1 range. */
- const float mist_start = kernel_data.film.mist_start;
- const float mist_inv_depth = kernel_data.film.mist_inv_depth;
-
- const float depth = camera_distance(kg, sd->P);
- float mist = saturate((depth - mist_start) * mist_inv_depth);
-
- /* Falloff */
- const float mist_falloff = kernel_data.film.mist_falloff;
-
- if (mist_falloff == 1.0f)
- ;
- else if (mist_falloff == 2.0f)
- mist = mist * mist;
- else if (mist_falloff == 0.5f)
- mist = sqrtf(mist);
- else
- mist = powf(mist, mist_falloff);
-
- /* Modulate by transparency */
- const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- const float3 alpha = shader_bsdf_alpha(kg, sd);
- const float mist_output = (1.0f - mist) * average(throughput * alpha);
-
- /* Note that the final value in the render buffer we want is 1 - mist_output,
- * to avoid having to tracking this in the Integrator state we do the negation
- * after rendering. */
- kernel_write_pass_float(buffer + kernel_data.film.pass_mist, mist_output);
- }
-#endif
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h
deleted file mode 100644
index a0584f0b219..00000000000
--- a/intern/cycles/kernel/kernel_path_state.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel_random.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Initialize queues, so that the this path is considered terminated.
- * Used for early outputs in the camera ray initialization, as well as initialization of split
- * states for shadow catcher. */
-ccl_device_inline void path_state_init_queues(IntegratorState state)
-{
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0;
-#ifdef __KERNEL_CPU__
- INTEGRATOR_STATE_WRITE(&state->shadow, shadow_path, queued_kernel) = 0;
- INTEGRATOR_STATE_WRITE(&state->ao, shadow_path, queued_kernel) = 0;
-#endif
-}
-
-/* Minimalistic initialization of the path state, which is needed for early outputs in the
- * integrator initialization to work. */
-ccl_device_inline void path_state_init(IntegratorState state,
- ccl_global const KernelWorkTile *ccl_restrict tile,
- const int x,
- const int y)
-{
- const uint render_pixel_index = (uint)tile->offset + x + y * tile->stride;
-
- INTEGRATOR_STATE_WRITE(state, path, render_pixel_index) = render_pixel_index;
-
- path_state_init_queues(state);
-}
-
-/* Initialize the rest of the path state needed to continue the path integration. */
-ccl_device_inline void path_state_init_integrator(KernelGlobals kg,
- IntegratorState state,
- const int sample,
- const uint rng_hash)
-{
- INTEGRATOR_STATE_WRITE(state, path, sample) = sample;
- INTEGRATOR_STATE_WRITE(state, path, bounce) = 0;
- INTEGRATOR_STATE_WRITE(state, path, diffuse_bounce) = 0;
- INTEGRATOR_STATE_WRITE(state, path, glossy_bounce) = 0;
- INTEGRATOR_STATE_WRITE(state, path, transmission_bounce) = 0;
- INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = 0;
- INTEGRATOR_STATE_WRITE(state, path, volume_bounce) = 0;
- INTEGRATOR_STATE_WRITE(state, path, volume_bounds_bounce) = 0;
- INTEGRATOR_STATE_WRITE(state, path, rng_hash) = rng_hash;
- INTEGRATOR_STATE_WRITE(state, path, rng_offset) = PRNG_BASE_NUM;
- INTEGRATOR_STATE_WRITE(state, path, flag) = PATH_RAY_CAMERA | PATH_RAY_MIS_SKIP |
- PATH_RAY_TRANSPARENT_BACKGROUND;
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = 0.0f;
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f;
- INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = FLT_MAX;
- INTEGRATOR_STATE_WRITE(state, path, throughput) = make_float3(1.0f, 1.0f, 1.0f);
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) {
- INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 0, object) = OBJECT_NONE;
- INTEGRATOR_STATE_ARRAY_WRITE(
- state, volume_stack, 0, shader) = kernel_data.background.volume_shader;
- INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 1, object) = OBJECT_NONE;
- INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 1, shader) = SHADER_NONE;
- }
-
-#ifdef __DENOISING_FEATURES__
- if (kernel_data.kernel_features & KERNEL_FEATURE_DENOISING) {
- INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_DENOISING_FEATURES;
- INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) = one_float3();
- }
-#endif
-}
-
-ccl_device_inline void path_state_next(KernelGlobals kg, IntegratorState state, int label)
-{
- uint32_t flag = INTEGRATOR_STATE(state, path, flag);
-
- /* ray through transparent keeps same flags from previous ray and is
- * not counted as a regular bounce, transparent has separate max */
- if (label & LABEL_TRANSPARENT) {
- uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce) + 1;
-
- flag |= PATH_RAY_TRANSPARENT;
- if (transparent_bounce >= kernel_data.integrator.transparent_max_bounce) {
- flag |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE;
- }
-
- if (!kernel_data.integrator.transparent_shadows)
- flag |= PATH_RAY_MIS_SKIP;
-
- INTEGRATOR_STATE_WRITE(state, path, flag) = flag;
- INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = transparent_bounce;
- /* Random number generator next bounce. */
- INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
- return;
- }
-
- uint32_t bounce = INTEGRATOR_STATE(state, path, bounce) + 1;
- if (bounce >= kernel_data.integrator.max_bounce) {
- flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
- }
-
- flag &= ~(PATH_RAY_ALL_VISIBILITY | PATH_RAY_MIS_SKIP);
-
-#ifdef __VOLUME__
- if (label & LABEL_VOLUME_SCATTER) {
- /* volume scatter */
- flag |= PATH_RAY_VOLUME_SCATTER;
- flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
- if (bounce == 1) {
- flag |= PATH_RAY_VOLUME_PASS;
- }
-
- const int volume_bounce = INTEGRATOR_STATE(state, path, volume_bounce) + 1;
- INTEGRATOR_STATE_WRITE(state, path, volume_bounce) = volume_bounce;
- if (volume_bounce >= kernel_data.integrator.max_volume_bounce) {
- flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
- }
- }
- else
-#endif
- {
- /* surface reflection/transmission */
- if (label & LABEL_REFLECT) {
- flag |= PATH_RAY_REFLECT;
- flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
-
- if (label & LABEL_DIFFUSE) {
- const int diffuse_bounce = INTEGRATOR_STATE(state, path, diffuse_bounce) + 1;
- INTEGRATOR_STATE_WRITE(state, path, diffuse_bounce) = diffuse_bounce;
- if (diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) {
- flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
- }
- }
- else {
- const int glossy_bounce = INTEGRATOR_STATE(state, path, glossy_bounce) + 1;
- INTEGRATOR_STATE_WRITE(state, path, glossy_bounce) = glossy_bounce;
- if (glossy_bounce >= kernel_data.integrator.max_glossy_bounce) {
- flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
- }
- }
- }
- else {
- kernel_assert(label & LABEL_TRANSMIT);
-
- flag |= PATH_RAY_TRANSMIT;
-
- if (!(label & LABEL_TRANSMIT_TRANSPARENT)) {
- flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
- }
-
- const int transmission_bounce = INTEGRATOR_STATE(state, path, transmission_bounce) + 1;
- INTEGRATOR_STATE_WRITE(state, path, transmission_bounce) = transmission_bounce;
- if (transmission_bounce >= kernel_data.integrator.max_transmission_bounce) {
- flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
- }
- }
-
- /* diffuse/glossy/singular */
- if (label & LABEL_DIFFUSE) {
- flag |= PATH_RAY_DIFFUSE | PATH_RAY_DIFFUSE_ANCESTOR;
- }
- else if (label & LABEL_GLOSSY) {
- flag |= PATH_RAY_GLOSSY;
- }
- else {
- kernel_assert(label & LABEL_SINGULAR);
- flag |= PATH_RAY_GLOSSY | PATH_RAY_SINGULAR | PATH_RAY_MIS_SKIP;
- }
-
- /* Render pass categories. */
- if (bounce == 1) {
- flag |= (label & LABEL_TRANSMIT) ? PATH_RAY_TRANSMISSION_PASS : PATH_RAY_REFLECT_PASS;
- }
- }
-
- INTEGRATOR_STATE_WRITE(state, path, flag) = flag;
- INTEGRATOR_STATE_WRITE(state, path, bounce) = bounce;
-
- /* Random number generator next bounce. */
- INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
-}
-
-#ifdef __VOLUME__
-ccl_device_inline bool path_state_volume_next(IntegratorState state)
-{
- /* For volume bounding meshes we pass through without counting transparent
- * bounces, only sanity check in case self intersection gets us stuck. */
- uint32_t volume_bounds_bounce = INTEGRATOR_STATE(state, path, volume_bounds_bounce) + 1;
- INTEGRATOR_STATE_WRITE(state, path, volume_bounds_bounce) = volume_bounds_bounce;
- if (volume_bounds_bounce > VOLUME_BOUNDS_MAX) {
- return false;
- }
-
- /* Random number generator next bounce. */
- if (volume_bounds_bounce > 1) {
- INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
- }
-
- return true;
-}
-#endif
-
-ccl_device_inline uint path_state_ray_visibility(ConstIntegratorState state)
-{
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- uint32_t visibility = path_flag & PATH_RAY_ALL_VISIBILITY;
-
- /* For visibility, diffuse/glossy are for reflection only. */
- if (visibility & PATH_RAY_TRANSMIT) {
- visibility &= ~(PATH_RAY_DIFFUSE | PATH_RAY_GLOSSY);
- }
-
- /* todo: this is not supported as its own ray visibility yet. */
- if (path_flag & PATH_RAY_VOLUME_SCATTER) {
- visibility |= PATH_RAY_DIFFUSE;
- }
-
- visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility);
-
- return visibility;
-}
-
-ccl_device_inline float path_state_continuation_probability(KernelGlobals kg,
- ConstIntegratorState state,
- const uint32_t path_flag)
-{
- if (path_flag & PATH_RAY_TRANSPARENT) {
- const uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce);
- /* Do at least specified number of bounces without RR. */
- if (transparent_bounce <= kernel_data.integrator.transparent_min_bounce) {
- return 1.0f;
- }
- }
- else {
- const uint32_t bounce = INTEGRATOR_STATE(state, path, bounce);
- /* Do at least specified number of bounces without RR. */
- if (bounce <= kernel_data.integrator.min_bounce) {
- return 1.0f;
- }
- }
-
- /* Probabilistic termination: use sqrt() to roughly match typical view
- * transform and do path termination a bit later on average. */
- return min(sqrtf(max3(fabs(INTEGRATOR_STATE(state, path, throughput)))), 1.0f);
-}
-
-ccl_device_inline bool path_state_ao_bounce(KernelGlobals kg, ConstIntegratorState state)
-{
- if (!kernel_data.integrator.ao_bounces) {
- return false;
- }
-
- const int bounce = INTEGRATOR_STATE(state, path, bounce) -
- INTEGRATOR_STATE(state, path, transmission_bounce) -
- (INTEGRATOR_STATE(state, path, glossy_bounce) > 0) + 1;
- return (bounce > kernel_data.integrator.ao_bounces);
-}
-
-/* Random Number Sampling Utility Functions
- *
- * For each random number in each step of the path we must have a unique
- * dimension to avoid using the same sequence twice.
- *
- * For branches in the path we must be careful not to reuse the same number
- * in a sequence and offset accordingly.
- */
-
-/* RNG State loaded onto stack. */
-typedef struct RNGState {
- uint rng_hash;
- uint rng_offset;
- int sample;
-} RNGState;
-
-ccl_device_inline void path_state_rng_load(ConstIntegratorState state,
- ccl_private RNGState *rng_state)
-{
- rng_state->rng_hash = INTEGRATOR_STATE(state, path, rng_hash);
- rng_state->rng_offset = INTEGRATOR_STATE(state, path, rng_offset);
- rng_state->sample = INTEGRATOR_STATE(state, path, sample);
-}
-
-ccl_device_inline void shadow_path_state_rng_load(ConstIntegratorShadowState state,
- ccl_private RNGState *rng_state)
-{
- rng_state->rng_hash = INTEGRATOR_STATE(state, shadow_path, rng_hash);
- rng_state->rng_offset = INTEGRATOR_STATE(state, shadow_path, rng_offset);
- rng_state->sample = INTEGRATOR_STATE(state, shadow_path, sample);
-}
-
-ccl_device_inline float path_state_rng_1D(KernelGlobals kg,
- ccl_private const RNGState *rng_state,
- int dimension)
-{
- return path_rng_1D(
- kg, rng_state->rng_hash, rng_state->sample, rng_state->rng_offset + dimension);
-}
-
-ccl_device_inline void path_state_rng_2D(KernelGlobals kg,
- ccl_private const RNGState *rng_state,
- int dimension,
- ccl_private float *fx,
- ccl_private float *fy)
-{
- path_rng_2D(
- kg, rng_state->rng_hash, rng_state->sample, rng_state->rng_offset + dimension, fx, fy);
-}
-
-ccl_device_inline float path_state_rng_1D_hash(KernelGlobals kg,
- ccl_private const RNGState *rng_state,
- uint hash)
-{
- /* Use a hash instead of dimension, this is not great but avoids adding
- * more dimensions to each bounce which reduces quality of dimensions we
- * are already using. */
- return path_rng_1D(
- kg, cmj_hash_simple(rng_state->rng_hash, hash), rng_state->sample, rng_state->rng_offset);
-}
-
-ccl_device_inline float path_branched_rng_1D(KernelGlobals kg,
- ccl_private const RNGState *rng_state,
- int branch,
- int num_branches,
- int dimension)
-{
- return path_rng_1D(kg,
- rng_state->rng_hash,
- rng_state->sample * num_branches + branch,
- rng_state->rng_offset + dimension);
-}
-
-ccl_device_inline void path_branched_rng_2D(KernelGlobals kg,
- ccl_private const RNGState *rng_state,
- int branch,
- int num_branches,
- int dimension,
- ccl_private float *fx,
- ccl_private float *fy)
-{
- path_rng_2D(kg,
- rng_state->rng_hash,
- rng_state->sample * num_branches + branch,
- rng_state->rng_offset + dimension,
- fx,
- fy);
-}
-
-/* Utility functions to get light termination value,
- * since it might not be needed in many cases.
- */
-ccl_device_inline float path_state_rng_light_termination(KernelGlobals kg,
- ccl_private const RNGState *state)
-{
- if (kernel_data.integrator.light_inv_rr_threshold > 0.0f) {
- return path_state_rng_1D(kg, state, PRNG_LIGHT_TERMINATE);
- }
- return 0.0f;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_profiling.h b/intern/cycles/kernel/kernel_profiling.h
deleted file mode 100644
index db8644005ea..00000000000
--- a/intern/cycles/kernel/kernel_profiling.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#ifdef __KERNEL_CPU__
-# include "util/util_profiling.h"
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef __KERNEL_CPU__
-# define PROFILING_INIT(kg, event) \
- ProfilingHelper profiling_helper((ProfilingState *)&kg->profiler, event)
-# define PROFILING_EVENT(event) profiling_helper.set_event(event)
-# define PROFILING_INIT_FOR_SHADER(kg, event) \
- ProfilingWithShaderHelper profiling_helper((ProfilingState *)&kg->profiler, event)
-# define PROFILING_SHADER(object, shader) \
- profiling_helper.set_shader(object, (shader)&SHADER_MASK);
-#else
-# define PROFILING_INIT(kg, event)
-# define PROFILING_EVENT(event)
-# define PROFILING_INIT_FOR_SHADER(kg, event)
-# define PROFILING_SHADER(object, shader)
-#endif /* __KERNEL_CPU__ */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
deleted file mode 100644
index e5e87453611..00000000000
--- a/intern/cycles/kernel/kernel_random.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include "kernel/kernel_jitter.h"
-#include "util/util_hash.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Pseudo random numbers, uncomment this for debugging correlations. Only run
- * this single threaded on a CPU for repeatable results. */
-//#define __DEBUG_CORRELATION__
-
-/* High Dimensional Sobol.
- *
- * Multidimensional sobol with generator matrices. Dimension 0 and 1 are equal
- * to classic Van der Corput and Sobol sequences. */
-
-#ifdef __SOBOL__
-
-/* Skip initial numbers that for some dimensions have clear patterns that
- * don't cover the entire sample space. Ideally we would have a better
- * progressive pattern that doesn't suffer from this problem, because even
- * with this offset some dimensions are quite poor.
- */
-# define SOBOL_SKIP 64
-
-ccl_device uint sobol_dimension(KernelGlobals kg, int index, int dimension)
-{
- uint result = 0;
- uint i = index + SOBOL_SKIP;
- for (int j = 0, x; (x = find_first_set(i)); i >>= x) {
- j += x;
- result ^= __float_as_uint(kernel_tex_fetch(__sample_pattern_lut, 32 * dimension + j - 1));
- }
- return result;
-}
-
-#endif /* __SOBOL__ */
-
-ccl_device_forceinline float path_rng_1D(KernelGlobals kg,
- uint rng_hash,
- int sample,
- int dimension)
-{
-#ifdef __DEBUG_CORRELATION__
- return (float)drand48();
-#endif
-
-#ifdef __SOBOL__
- if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ)
-#endif
- {
- return pmj_sample_1D(kg, sample, rng_hash, dimension);
- }
-
-#ifdef __SOBOL__
- /* Sobol sequence value using direction vectors. */
- uint result = sobol_dimension(kg, sample, dimension);
- float r = (float)result * (1.0f / (float)0xFFFFFFFF);
-
- /* Cranly-Patterson rotation using rng seed */
- float shift;
-
- /* Hash rng with dimension to solve correlation issues.
- * See T38710, T50116.
- */
- uint tmp_rng = cmj_hash_simple(dimension, rng_hash);
- shift = tmp_rng * (1.0f / (float)0xFFFFFFFF);
-
- return r + shift - floorf(r + shift);
-#endif
-}
-
-ccl_device_forceinline void path_rng_2D(KernelGlobals kg,
- uint rng_hash,
- int sample,
- int dimension,
- ccl_private float *fx,
- ccl_private float *fy)
-{
-#ifdef __DEBUG_CORRELATION__
- *fx = (float)drand48();
- *fy = (float)drand48();
- return;
-#endif
-
-#ifdef __SOBOL__
- if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ)
-#endif
- {
- pmj_sample_2D(kg, sample, rng_hash, dimension, fx, fy);
-
- return;
- }
-
-#ifdef __SOBOL__
- /* Sobol. */
- *fx = path_rng_1D(kg, rng_hash, sample, dimension);
- *fy = path_rng_1D(kg, rng_hash, sample, dimension + 1);
-#endif
-}
-
-/**
- * 1D hash recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020
- * See https://www.shadertoy.com/view/4tXyWN and https://www.shadertoy.com/view/XlGcRh
- * http://www.jcgt.org/published/0009/03/02/paper.pdf
- */
-ccl_device_inline uint hash_iqint1(uint n)
-{
- n = (n << 13U) ^ n;
- n = n * (n * n * 15731U + 789221U) + 1376312589U;
-
- return n;
-}
-
-/**
- * 2D hash recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020
- * See https://www.shadertoy.com/view/4tXyWN and https://www.shadertoy.com/view/XlGcRh
- * http://www.jcgt.org/published/0009/03/02/paper.pdf
- */
-ccl_device_inline uint hash_iqnt2d(const uint x, const uint y)
-{
- const uint qx = 1103515245U * ((x >> 1U) ^ (y));
- const uint qy = 1103515245U * ((y >> 1U) ^ (x));
- const uint n = 1103515245U * ((qx) ^ (qy >> 3U));
-
- return n;
-}
-
-ccl_device_inline uint path_rng_hash_init(KernelGlobals kg,
- const int sample,
- const int x,
- const int y)
-{
- const uint rng_hash = hash_iqnt2d(x, y) ^ kernel_data.integrator.seed;
-
-#ifdef __DEBUG_CORRELATION__
- srand48(rng_hash + sample);
-#else
- (void)sample;
-#endif
-
- return rng_hash;
-}
-
-/* Linear Congruential Generator */
-
-ccl_device uint lcg_step_uint(uint *rng)
-{
- /* implicit mod 2^32 */
- *rng = (1103515245 * (*rng) + 12345);
- return *rng;
-}
-
-ccl_device float lcg_step_float(uint *rng)
-{
- /* implicit mod 2^32 */
- *rng = (1103515245 * (*rng) + 12345);
- return (float)*rng * (1.0f / (float)0xFFFFFFFF);
-}
-
-ccl_device uint lcg_init(uint seed)
-{
- uint rng = seed;
- lcg_step_uint(&rng);
- return rng;
-}
-
-ccl_device_inline uint lcg_state_init(const uint rng_hash,
- const uint rng_offset,
- const uint sample,
- const uint scramble)
-{
- return lcg_init(rng_hash + rng_offset + sample * scramble);
-}
-
-ccl_device_inline bool sample_is_even(int pattern, int sample)
-{
- if (pattern == SAMPLING_PATTERN_PMJ) {
- /* See Section 10.2.1, "Progressive Multi-Jittered Sample Sequences", Christensen et al.
- * We can use this to get divide sample sequence into two classes for easier variance
- * estimation. */
-#if defined(__GNUC__) && !defined(__KERNEL_GPU__)
- return __builtin_popcount(sample & 0xaaaaaaaa) & 1;
-#elif defined(__NVCC__)
- return __popc(sample & 0xaaaaaaaa) & 1;
-#else
- /* TODO(Stefan): pop-count intrinsic for Windows with fallback for older CPUs. */
- int i = sample & 0xaaaaaaaa;
- i = i - ((i >> 1) & 0x55555555);
- i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
- i = (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
- return i & 1;
-#endif
- }
- else {
- /* TODO(Stefan): Are there reliable ways of dividing CMJ and Sobol into two classes? */
- return sample & 0x1;
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
deleted file mode 100644
index d25191b72cf..00000000000
--- a/intern/cycles/kernel/kernel_shader.h
+++ /dev/null
@@ -1,863 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Functions to evaluate shaders and use the resulting shader closures. */
-
-#pragma once
-
-// clang-format off
-#include "kernel/closure/alloc.h"
-#include "kernel/closure/bsdf_util.h"
-#include "kernel/closure/bsdf.h"
-#include "kernel/closure/emissive.h"
-// clang-format on
-
-#include "kernel/kernel_accumulate.h"
-#include "kernel/svm/svm.h"
-
-#ifdef __OSL__
-# include "kernel/osl/osl_shader.h"
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/* Merging */
-
-#if defined(__VOLUME__)
-ccl_device_inline void shader_merge_volume_closures(ccl_private ShaderData *sd)
-{
- /* Merge identical closures to save closure space with stacked volumes. */
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private ShaderClosure *sci = &sd->closure[i];
-
- if (sci->type != CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) {
- continue;
- }
-
- for (int j = i + 1; j < sd->num_closure; j++) {
- ccl_private ShaderClosure *scj = &sd->closure[j];
- if (sci->type != scj->type) {
- continue;
- }
-
- ccl_private const HenyeyGreensteinVolume *hgi = (ccl_private const HenyeyGreensteinVolume *)
- sci;
- ccl_private const HenyeyGreensteinVolume *hgj = (ccl_private const HenyeyGreensteinVolume *)
- scj;
- if (!(hgi->g == hgj->g)) {
- continue;
- }
-
- sci->weight += scj->weight;
- sci->sample_weight += scj->sample_weight;
-
- int size = sd->num_closure - (j + 1);
- if (size > 0) {
- for (int k = 0; k < size; k++) {
- scj[k] = scj[k + 1];
- }
- }
-
- sd->num_closure--;
- kernel_assert(sd->num_closure >= 0);
- j--;
- }
- }
-}
-
-ccl_device_inline void shader_copy_volume_phases(ccl_private ShaderVolumePhases *ccl_restrict
- phases,
- ccl_private const ShaderData *ccl_restrict sd)
-{
- phases->num_closure = 0;
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *from_sc = &sd->closure[i];
- ccl_private const HenyeyGreensteinVolume *from_hg =
- (ccl_private const HenyeyGreensteinVolume *)from_sc;
-
- if (from_sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) {
- ccl_private ShaderVolumeClosure *to_sc = &phases->closure[phases->num_closure];
-
- to_sc->weight = from_sc->weight;
- to_sc->sample_weight = from_sc->sample_weight;
- to_sc->g = from_hg->g;
- phases->num_closure++;
- if (phases->num_closure >= MAX_VOLUME_CLOSURE) {
- break;
- }
- }
- }
-}
-#endif /* __VOLUME__ */
-
-ccl_device_inline void shader_prepare_surface_closures(KernelGlobals kg,
- ConstIntegratorState state,
- ccl_private ShaderData *sd)
-{
- /* Defensive sampling.
- *
- * We can likely also do defensive sampling at deeper bounces, particularly
- * for cases like a perfect mirror but possibly also others. This will need
- * a good heuristic. */
- if (INTEGRATOR_STATE(state, path, bounce) + INTEGRATOR_STATE(state, path, transparent_bounce) ==
- 0 &&
- sd->num_closure > 1) {
- float sum = 0.0f;
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private ShaderClosure *sc = &sd->closure[i];
- if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
- sum += sc->sample_weight;
- }
- }
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private ShaderClosure *sc = &sd->closure[i];
- if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
- sc->sample_weight = max(sc->sample_weight, 0.125f * sum);
- }
- }
- }
-
- /* Filter glossy.
- *
- * Blurring of bsdf after bounces, for rays that have a small likelihood
- * of following this particular path (diffuse, rough glossy) */
- if (kernel_data.integrator.filter_glossy != FLT_MAX) {
- float blur_pdf = kernel_data.integrator.filter_glossy *
- INTEGRATOR_STATE(state, path, min_ray_pdf);
-
- if (blur_pdf < 1.0f) {
- float blur_roughness = sqrtf(1.0f - blur_pdf) * 0.5f;
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private ShaderClosure *sc = &sd->closure[i];
- if (CLOSURE_IS_BSDF(sc->type)) {
- bsdf_blur(kg, sc, blur_roughness);
- }
- }
- }
- }
-}
-
-/* BSDF */
-
-ccl_device_inline bool shader_bsdf_is_transmission(ccl_private const ShaderData *sd,
- const float3 omega_in)
-{
- return dot(sd->N, omega_in) < 0.0f;
-}
-
-ccl_device_forceinline bool _shader_bsdf_exclude(ClosureType type, uint light_shader_flags)
-{
- if (!(light_shader_flags & SHADER_EXCLUDE_ANY)) {
- return false;
- }
- if (light_shader_flags & SHADER_EXCLUDE_DIFFUSE) {
- if (CLOSURE_IS_BSDF_DIFFUSE(type)) {
- return true;
- }
- }
- if (light_shader_flags & SHADER_EXCLUDE_GLOSSY) {
- if (CLOSURE_IS_BSDF_GLOSSY(type)) {
- return true;
- }
- }
- if (light_shader_flags & SHADER_EXCLUDE_TRANSMIT) {
- if (CLOSURE_IS_BSDF_TRANSMISSION(type)) {
- return true;
- }
- }
- return false;
-}
-
-ccl_device_inline float _shader_bsdf_multi_eval(KernelGlobals kg,
- ccl_private ShaderData *sd,
- const float3 omega_in,
- const bool is_transmission,
- ccl_private const ShaderClosure *skip_sc,
- ccl_private BsdfEval *result_eval,
- float sum_pdf,
- float sum_sample_weight,
- const uint light_shader_flags)
-{
- /* This is the veach one-sample model with balance heuristic,
- * some PDF factors drop out when using balance heuristic weighting. */
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (sc == skip_sc) {
- continue;
- }
-
- if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
- if (CLOSURE_IS_BSDF(sc->type) && !_shader_bsdf_exclude(sc->type, light_shader_flags)) {
- float bsdf_pdf = 0.0f;
- float3 eval = bsdf_eval(kg, sd, sc, omega_in, is_transmission, &bsdf_pdf);
-
- if (bsdf_pdf != 0.0f) {
- const bool is_diffuse = CLOSURE_IS_BSDF_DIFFUSE(sc->type);
- bsdf_eval_accum(result_eval, is_diffuse, eval * sc->weight, 1.0f);
- sum_pdf += bsdf_pdf * sc->sample_weight;
- }
- }
-
- sum_sample_weight += sc->sample_weight;
- }
- }
-
- return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f;
-}
-
-#ifndef __KERNEL_CUDA__
-ccl_device
-#else
-ccl_device_inline
-#endif
- float
- shader_bsdf_eval(KernelGlobals kg,
- ccl_private ShaderData *sd,
- const float3 omega_in,
- const bool is_transmission,
- ccl_private BsdfEval *bsdf_eval,
- const uint light_shader_flags)
-{
- bsdf_eval_init(bsdf_eval, false, zero_float3());
-
- return _shader_bsdf_multi_eval(
- kg, sd, omega_in, is_transmission, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
-}
-
-/* Randomly sample a BSSRDF or BSDF proportional to ShaderClosure.sample_weight. */
-ccl_device_inline ccl_private const ShaderClosure *shader_bsdf_bssrdf_pick(
- ccl_private const ShaderData *ccl_restrict sd, ccl_private float *randu)
-{
- int sampled = 0;
-
- if (sd->num_closure > 1) {
- /* Pick a BSDF or based on sample weights. */
- float sum = 0.0f;
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
- sum += sc->sample_weight;
- }
- }
-
- float r = (*randu) * sum;
- float partial_sum = 0.0f;
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
- float next_sum = partial_sum + sc->sample_weight;
-
- if (r < next_sum) {
- sampled = i;
-
- /* Rescale to reuse for direction sample, to better preserve stratification. */
- *randu = (r - partial_sum) / sc->sample_weight;
- break;
- }
-
- partial_sum = next_sum;
- }
- }
- }
-
- return &sd->closure[sampled];
-}
-
-/* Return weight for picked BSSRDF. */
-ccl_device_inline float3
-shader_bssrdf_sample_weight(ccl_private const ShaderData *ccl_restrict sd,
- ccl_private const ShaderClosure *ccl_restrict bssrdf_sc)
-{
- float3 weight = bssrdf_sc->weight;
-
- if (sd->num_closure > 1) {
- float sum = 0.0f;
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
- sum += sc->sample_weight;
- }
- }
- weight *= sum / bssrdf_sc->sample_weight;
- }
-
- return weight;
-}
-
-/* Sample direction for picked BSDF, and return evaluation and pdf for all
- * BSDFs combined using MIS. */
-ccl_device int shader_bsdf_sample_closure(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private const ShaderClosure *sc,
- float randu,
- float randv,
- ccl_private BsdfEval *bsdf_eval,
- ccl_private float3 *omega_in,
- ccl_private differential3 *domega_in,
- ccl_private float *pdf)
-{
- /* BSSRDF should already have been handled elsewhere. */
- kernel_assert(CLOSURE_IS_BSDF(sc->type));
-
- int label;
- float3 eval = zero_float3();
-
- *pdf = 0.0f;
- label = bsdf_sample(kg, sd, sc, randu, randv, &eval, omega_in, domega_in, pdf);
-
- if (*pdf != 0.0f) {
- const bool is_diffuse = CLOSURE_IS_BSDF_DIFFUSE(sc->type);
- bsdf_eval_init(bsdf_eval, is_diffuse, eval * sc->weight);
-
- if (sd->num_closure > 1) {
- const bool is_transmission = shader_bsdf_is_transmission(sd, *omega_in);
- float sweight = sc->sample_weight;
- *pdf = _shader_bsdf_multi_eval(
- kg, sd, *omega_in, is_transmission, sc, bsdf_eval, *pdf * sweight, sweight, 0);
- }
- }
-
- return label;
-}
-
-ccl_device float shader_bsdf_average_roughness(ccl_private const ShaderData *sd)
-{
- float roughness = 0.0f;
- float sum_weight = 0.0f;
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSDF(sc->type)) {
- /* sqrt once to undo the squaring from multiplying roughness on the
- * two axes, and once for the squared roughness convention. */
- float weight = fabsf(average(sc->weight));
- roughness += weight * sqrtf(safe_sqrtf(bsdf_get_roughness_squared(sc)));
- sum_weight += weight;
- }
- }
-
- return (sum_weight > 0.0f) ? roughness / sum_weight : 0.0f;
-}
-
-ccl_device float3 shader_bsdf_transparency(KernelGlobals kg, ccl_private const ShaderData *sd)
-{
- if (sd->flag & SD_HAS_ONLY_VOLUME) {
- return one_float3();
- }
- else if (sd->flag & SD_TRANSPARENT) {
- return sd->closure_transparent_extinction;
- }
- else {
- return zero_float3();
- }
-}
-
-ccl_device void shader_bsdf_disable_transparency(KernelGlobals kg, ccl_private ShaderData *sd)
-{
- if (sd->flag & SD_TRANSPARENT) {
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private ShaderClosure *sc = &sd->closure[i];
-
- if (sc->type == CLOSURE_BSDF_TRANSPARENT_ID) {
- sc->sample_weight = 0.0f;
- sc->weight = zero_float3();
- }
- }
-
- sd->flag &= ~SD_TRANSPARENT;
- }
-}
-
-ccl_device float3 shader_bsdf_alpha(KernelGlobals kg, ccl_private const ShaderData *sd)
-{
- float3 alpha = one_float3() - shader_bsdf_transparency(kg, sd);
-
- alpha = max(alpha, zero_float3());
- alpha = min(alpha, one_float3());
-
- return alpha;
-}
-
-ccl_device float3 shader_bsdf_diffuse(KernelGlobals kg, ccl_private const ShaderData *sd)
-{
- float3 eval = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type))
- eval += sc->weight;
- }
-
- return eval;
-}
-
-ccl_device float3 shader_bsdf_glossy(KernelGlobals kg, ccl_private const ShaderData *sd)
-{
- float3 eval = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSDF_GLOSSY(sc->type))
- eval += sc->weight;
- }
-
- return eval;
-}
-
-ccl_device float3 shader_bsdf_transmission(KernelGlobals kg, ccl_private const ShaderData *sd)
-{
- float3 eval = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type))
- eval += sc->weight;
- }
-
- return eval;
-}
-
-ccl_device float3 shader_bsdf_average_normal(KernelGlobals kg, ccl_private const ShaderData *sd)
-{
- float3 N = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
- if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type))
- N += sc->N * fabsf(average(sc->weight));
- }
-
- return (is_zero(N)) ? sd->N : normalize(N);
-}
-
-ccl_device float3 shader_bsdf_ao_normal(KernelGlobals kg, ccl_private const ShaderData *sd)
-{
- float3 N = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
- if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
- ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc;
- N += bsdf->N * fabsf(average(sc->weight));
- }
- }
-
- return (is_zero(N)) ? sd->N : normalize(N);
-}
-
-#ifdef __SUBSURFACE__
-ccl_device float3 shader_bssrdf_normal(ccl_private const ShaderData *sd)
-{
- float3 N = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSSRDF(sc->type)) {
- ccl_private const Bssrdf *bssrdf = (ccl_private const Bssrdf *)sc;
- float avg_weight = fabsf(average(sc->weight));
-
- N += bssrdf->N * avg_weight;
- }
- }
-
- return (is_zero(N)) ? sd->N : normalize(N);
-}
-#endif /* __SUBSURFACE__ */
-
-/* Constant emission optimization */
-
-ccl_device bool shader_constant_emission_eval(KernelGlobals kg,
- int shader,
- ccl_private float3 *eval)
-{
- int shader_index = shader & SHADER_MASK;
- int shader_flag = kernel_tex_fetch(__shaders, shader_index).flags;
-
- if (shader_flag & SD_HAS_CONSTANT_EMISSION) {
- *eval = make_float3(kernel_tex_fetch(__shaders, shader_index).constant_emission[0],
- kernel_tex_fetch(__shaders, shader_index).constant_emission[1],
- kernel_tex_fetch(__shaders, shader_index).constant_emission[2]);
-
- return true;
- }
-
- return false;
-}
-
-/* Background */
-
-ccl_device float3 shader_background_eval(ccl_private const ShaderData *sd)
-{
- if (sd->flag & SD_EMISSION) {
- return sd->closure_emission_background;
- }
- else {
- return zero_float3();
- }
-}
-
-/* Emission */
-
-ccl_device float3 shader_emissive_eval(ccl_private const ShaderData *sd)
-{
- if (sd->flag & SD_EMISSION) {
- return emissive_simple_eval(sd->Ng, sd->I) * sd->closure_emission_background;
- }
- else {
- return zero_float3();
- }
-}
-
-/* Holdout */
-
-ccl_device float3 shader_holdout_apply(KernelGlobals kg, ccl_private ShaderData *sd)
-{
- float3 weight = zero_float3();
-
- /* For objects marked as holdout, preserve transparency and remove all other
- * closures, replacing them with a holdout weight. */
- if (sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
- if ((sd->flag & SD_TRANSPARENT) && !(sd->flag & SD_HAS_ONLY_VOLUME)) {
- weight = one_float3() - sd->closure_transparent_extinction;
-
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private ShaderClosure *sc = &sd->closure[i];
- if (!CLOSURE_IS_BSDF_TRANSPARENT(sc->type)) {
- sc->type = NBUILTIN_CLOSURES;
- }
- }
-
- sd->flag &= ~(SD_CLOSURE_FLAGS - (SD_TRANSPARENT | SD_BSDF));
- }
- else {
- weight = one_float3();
- }
- }
- else {
- for (int i = 0; i < sd->num_closure; i++) {
- ccl_private const ShaderClosure *sc = &sd->closure[i];
- if (CLOSURE_IS_HOLDOUT(sc->type)) {
- weight += sc->weight;
- }
- }
- }
-
- return weight;
-}
-
-/* Surface Evaluation */
-
-template<uint node_feature_mask, typename ConstIntegratorGenericState>
-ccl_device void shader_eval_surface(KernelGlobals kg,
- ConstIntegratorGenericState state,
- ccl_private ShaderData *ccl_restrict sd,
- ccl_global float *ccl_restrict buffer,
- uint32_t path_flag)
-{
- /* If path is being terminated, we are tracing a shadow ray or evaluating
- * emission, then we don't need to store closures. The emission and shadow
- * shader data also do not have a closure array to save GPU memory. */
- int max_closures;
- if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) {
- max_closures = 0;
- }
- else {
- max_closures = kernel_data.max_closures;
- }
-
- sd->num_closure = 0;
- sd->num_closure_left = max_closures;
-
-#ifdef __OSL__
- if (kg->osl) {
- if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) {
- OSLShader::eval_background(kg, state, sd, path_flag);
- }
- else {
- OSLShader::eval_surface(kg, state, sd, path_flag);
- }
- }
- else
-#endif
- {
-#ifdef __SVM__
- svm_eval_nodes<node_feature_mask, SHADER_TYPE_SURFACE>(kg, state, sd, buffer, path_flag);
-#else
- if (sd->object == OBJECT_NONE) {
- sd->closure_emission_background = make_float3(0.8f, 0.8f, 0.8f);
- sd->flag |= SD_EMISSION;
- }
- else {
- ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc(
- sd, sizeof(DiffuseBsdf), make_float3(0.8f, 0.8f, 0.8f));
- if (bsdf != NULL) {
- bsdf->N = sd->N;
- sd->flag |= bsdf_diffuse_setup(bsdf);
- }
- }
-#endif
- }
-}
-
-/* Volume */
-
-#ifdef __VOLUME__
-
-ccl_device_inline float _shader_volume_phase_multi_eval(
- ccl_private const ShaderData *sd,
- ccl_private const ShaderVolumePhases *phases,
- const float3 omega_in,
- int skip_phase,
- ccl_private BsdfEval *result_eval,
- float sum_pdf,
- float sum_sample_weight)
-{
- for (int i = 0; i < phases->num_closure; i++) {
- if (i == skip_phase)
- continue;
-
- ccl_private const ShaderVolumeClosure *svc = &phases->closure[i];
- float phase_pdf = 0.0f;
- float3 eval = volume_phase_eval(sd, svc, omega_in, &phase_pdf);
-
- if (phase_pdf != 0.0f) {
- bsdf_eval_accum(result_eval, false, eval, 1.0f);
- sum_pdf += phase_pdf * svc->sample_weight;
- }
-
- sum_sample_weight += svc->sample_weight;
- }
-
- return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f;
-}
-
-ccl_device float shader_volume_phase_eval(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- ccl_private const ShaderVolumePhases *phases,
- const float3 omega_in,
- ccl_private BsdfEval *phase_eval)
-{
- bsdf_eval_init(phase_eval, false, zero_float3());
-
- return _shader_volume_phase_multi_eval(sd, phases, omega_in, -1, phase_eval, 0.0f, 0.0f);
-}
-
-ccl_device int shader_volume_phase_sample(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- ccl_private const ShaderVolumePhases *phases,
- float randu,
- float randv,
- ccl_private BsdfEval *phase_eval,
- ccl_private float3 *omega_in,
- ccl_private differential3 *domega_in,
- ccl_private float *pdf)
-{
- int sampled = 0;
-
- if (phases->num_closure > 1) {
- /* pick a phase closure based on sample weights */
- float sum = 0.0f;
-
- for (sampled = 0; sampled < phases->num_closure; sampled++) {
- ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled];
- sum += svc->sample_weight;
- }
-
- float r = randu * sum;
- float partial_sum = 0.0f;
-
- for (sampled = 0; sampled < phases->num_closure; sampled++) {
- ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled];
- float next_sum = partial_sum + svc->sample_weight;
-
- if (r <= next_sum) {
- /* Rescale to reuse for BSDF direction sample. */
- randu = (r - partial_sum) / svc->sample_weight;
- break;
- }
-
- partial_sum = next_sum;
- }
-
- if (sampled == phases->num_closure) {
- *pdf = 0.0f;
- return LABEL_NONE;
- }
- }
-
- /* todo: this isn't quite correct, we don't weight anisotropy properly
- * depending on color channels, even if this is perhaps not a common case */
- ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled];
- int label;
- float3 eval = zero_float3();
-
- *pdf = 0.0f;
- label = volume_phase_sample(sd, svc, randu, randv, &eval, omega_in, domega_in, pdf);
-
- if (*pdf != 0.0f) {
- bsdf_eval_init(phase_eval, false, eval);
- }
-
- return label;
-}
-
-ccl_device int shader_phase_sample_closure(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- ccl_private const ShaderVolumeClosure *sc,
- float randu,
- float randv,
- ccl_private BsdfEval *phase_eval,
- ccl_private float3 *omega_in,
- ccl_private differential3 *domega_in,
- ccl_private float *pdf)
-{
- int label;
- float3 eval = zero_float3();
-
- *pdf = 0.0f;
- label = volume_phase_sample(sd, sc, randu, randv, &eval, omega_in, domega_in, pdf);
-
- if (*pdf != 0.0f)
- bsdf_eval_init(phase_eval, false, eval);
-
- return label;
-}
-
-/* Volume Evaluation */
-
-template<const bool shadow, typename StackReadOp, typename ConstIntegratorGenericState>
-ccl_device_inline void shader_eval_volume(KernelGlobals kg,
- ConstIntegratorGenericState state,
- ccl_private ShaderData *ccl_restrict sd,
- const uint32_t path_flag,
- StackReadOp stack_read)
-{
- /* If path is being terminated, we are tracing a shadow ray or evaluating
- * emission, then we don't need to store closures. The emission and shadow
- * shader data also do not have a closure array to save GPU memory. */
- int max_closures;
- if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) {
- max_closures = 0;
- }
- else {
- max_closures = kernel_data.max_closures;
- }
-
- /* reset closures once at the start, we will be accumulating the closures
- * for all volumes in the stack into a single array of closures */
- sd->num_closure = 0;
- sd->num_closure_left = max_closures;
- sd->flag = 0;
- sd->object_flag = 0;
-
- for (int i = 0;; i++) {
- const VolumeStack entry = stack_read(i);
- if (entry.shader == SHADER_NONE) {
- break;
- }
-
- /* Setup shader-data from stack. it's mostly setup already in
- * shader_setup_from_volume, this switching should be quick. */
- sd->object = entry.object;
- sd->lamp = LAMP_NONE;
- sd->shader = entry.shader;
-
- sd->flag &= ~SD_SHADER_FLAGS;
- sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
- sd->object_flag &= ~SD_OBJECT_FLAGS;
-
- if (sd->object != OBJECT_NONE) {
- sd->object_flag |= kernel_tex_fetch(__object_flag, sd->object);
-
-# ifdef __OBJECT_MOTION__
- /* todo: this is inefficient for motion blur, we should be
- * caching matrices instead of recomputing them each step */
- shader_setup_object_transforms(kg, sd, sd->time);
-# endif
- }
-
- /* evaluate shader */
-# ifdef __SVM__
-# ifdef __OSL__
- if (kg->osl) {
- OSLShader::eval_volume(kg, state, sd, path_flag);
- }
- else
-# endif
- {
- svm_eval_nodes<KERNEL_FEATURE_NODE_MASK_VOLUME, SHADER_TYPE_VOLUME>(
- kg, state, sd, NULL, path_flag);
- }
-# endif
-
- /* Merge closures to avoid exceeding number of closures limit. */
- if (!shadow) {
- if (i > 0) {
- shader_merge_volume_closures(sd);
- }
- }
- }
-}
-
-#endif /* __VOLUME__ */
-
-/* Displacement Evaluation */
-
-template<typename ConstIntegratorGenericState>
-ccl_device void shader_eval_displacement(KernelGlobals kg,
- ConstIntegratorGenericState state,
- ccl_private ShaderData *sd)
-{
- sd->num_closure = 0;
- sd->num_closure_left = 0;
-
- /* this will modify sd->P */
-#ifdef __SVM__
-# ifdef __OSL__
- if (kg->osl)
- OSLShader::eval_displacement(kg, state, sd);
- else
-# endif
- {
- svm_eval_nodes<KERNEL_FEATURE_NODE_MASK_DISPLACEMENT, SHADER_TYPE_DISPLACEMENT>(
- kg, state, sd, NULL, 0);
- }
-#endif
-}
-
-/* Cryptomatte */
-
-ccl_device float shader_cryptomatte_id(KernelGlobals kg, int shader)
-{
- return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).cryptomatte_id;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_shadow_catcher.h b/intern/cycles/kernel/kernel_shadow_catcher.h
deleted file mode 100644
index 9bed140b395..00000000000
--- a/intern/cycles/kernel/kernel_shadow_catcher.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "kernel/integrator/integrator_state_util.h"
-#include "kernel/kernel_path_state.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Check whether current surface bounce is where path is to be split for the shadow catcher. */
-ccl_device_inline bool kernel_shadow_catcher_is_path_split_bounce(KernelGlobals kg,
- IntegratorState state,
- const int object_flag)
-{
-#ifdef __SHADOW_CATCHER__
- if (!kernel_data.integrator.has_shadow_catcher) {
- return false;
- }
-
- /* Check the flag first, avoiding fetches form global memory. */
- if ((object_flag & SD_OBJECT_SHADOW_CATCHER) == 0) {
- return false;
- }
- if (object_flag & SD_OBJECT_HOLDOUT_MASK) {
- return false;
- }
-
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- if ((path_flag & PATH_RAY_TRANSPARENT_BACKGROUND) == 0) {
- /* Split only on primary rays, secondary bounces are to treat shadow catcher as a regular
- * object. */
- return false;
- }
-
- if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
- return false;
- }
-
- return true;
-#else
- (void)object_flag;
- return false;
-#endif
-}
-
-/* Check whether the current path can still split. */
-ccl_device_inline bool kernel_shadow_catcher_path_can_split(KernelGlobals kg,
- ConstIntegratorState state)
-{
- if (INTEGRATOR_PATH_IS_TERMINATED) {
- return false;
- }
-
- const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
- if (path_flag & PATH_RAY_SHADOW_CATCHER_HIT) {
- /* Shadow catcher was already hit and the state was split. No further split is allowed. */
- return false;
- }
-
- return (path_flag & PATH_RAY_TRANSPARENT_BACKGROUND) != 0;
-}
-
-/* NOTE: Leaves kernel scheduling information untouched. Use INIT semantic for one of the paths
- * after this function. */
-ccl_device_inline bool kernel_shadow_catcher_split(KernelGlobals kg,
- IntegratorState state,
- const int object_flags)
-{
-#ifdef __SHADOW_CATCHER__
-
- if (!kernel_shadow_catcher_is_path_split_bounce(kg, state, object_flags)) {
- return false;
- }
-
- /* The split is to be done. Mark the current state as such, so that it stops contributing to the
- * shadow catcher matte pass, but keeps contributing to the combined pass. */
- INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SHADOW_CATCHER_HIT;
-
- /* Split new state from the current one. This new state will only track contribution of shadow
- * catcher objects ignoring non-catcher objects. */
- integrator_state_shadow_catcher_split(kg, state);
-
- return true;
-#else
- (void)object_flags;
- return false;
-#endif
-}
-
-#ifdef __SHADOW_CATCHER__
-
-ccl_device_forceinline bool kernel_shadow_catcher_is_matte_path(const uint32_t path_flag)
-{
- return (path_flag & PATH_RAY_SHADOW_CATCHER_HIT) == 0;
-}
-
-ccl_device_forceinline bool kernel_shadow_catcher_is_object_pass(const uint32_t path_flag)
-{
- return path_flag & PATH_RAY_SHADOW_CATCHER_PASS;
-}
-
-#endif /* __SHADOW_CATCHER__ */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
deleted file mode 100644
index 5cbe2939dfc..00000000000
--- a/intern/cycles/kernel/kernel_types.h
+++ /dev/null
@@ -1,1594 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#if !defined(__KERNEL_GPU__) && defined(WITH_EMBREE)
-# include <embree3/rtcore.h>
-# include <embree3/rtcore_scene.h>
-# define __EMBREE__
-#endif
-
-#include "kernel/kernel_math.h"
-#include "kernel/svm/svm_types.h"
-#include "util/util_static_assert.h"
-
-#ifndef __KERNEL_GPU__
-# define __KERNEL_CPU__
-#endif
-
-/* TODO(sergey): This is only to make it possible to include this header
- * from outside of the kernel. but this could be done somewhat cleaner?
- */
-#ifndef ccl_addr_space
-# define ccl_addr_space
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/* Constants */
-#define OBJECT_MOTION_PASS_SIZE 2
-#define FILTER_TABLE_SIZE 1024
-#define RAMP_TABLE_SIZE 256
-#define SHUTTER_TABLE_SIZE 256
-
-#define BSSRDF_MIN_RADIUS 1e-8f
-#define BSSRDF_MAX_HITS 4
-#define BSSRDF_MAX_BOUNCES 256
-#define LOCAL_MAX_HITS 4
-
-#define VOLUME_BOUNDS_MAX 1024
-
-#define BECKMANN_TABLE_SIZE 256
-
-#define SHADER_NONE (~0)
-#define OBJECT_NONE (~0)
-#define PRIM_NONE (~0)
-#define LAMP_NONE (~0)
-#define ID_NONE (0.0f)
-#define PASS_UNUSED (~0)
-
-#define INTEGRATOR_SHADOW_ISECT_SIZE_CPU 1024U
-#define INTEGRATOR_SHADOW_ISECT_SIZE_GPU 4U
-
-#ifdef __KERNEL_CPU__
-# define INTEGRATOR_SHADOW_ISECT_SIZE INTEGRATOR_SHADOW_ISECT_SIZE_CPU
-#else
-# define INTEGRATOR_SHADOW_ISECT_SIZE INTEGRATOR_SHADOW_ISECT_SIZE_GPU
-#endif
-
-/* Kernel features */
-#define __SOBOL__
-#define __DPDU__
-#define __BACKGROUND__
-#define __CAUSTICS_TRICKS__
-#define __VISIBILITY_FLAG__
-#define __RAY_DIFFERENTIALS__
-#define __CAMERA_CLIPPING__
-#define __INTERSECTION_REFINE__
-#define __CLAMP_SAMPLE__
-#define __PATCH_EVAL__
-#define __SHADOW_CATCHER__
-#define __DENOISING_FEATURES__
-#define __SHADER_RAYTRACE__
-#define __AO__
-#define __PASSES__
-#define __HAIR__
-#define __SVM__
-#define __EMISSION__
-#define __HOLDOUT__
-#define __TRANSPARENT_SHADOWS__
-#define __BACKGROUND_MIS__
-#define __LAMP_MIS__
-#define __CAMERA_MOTION__
-#define __OBJECT_MOTION__
-#define __BAKING__
-#define __PRINCIPLED__
-#define __SUBSURFACE__
-#define __VOLUME__
-#define __CMJ__
-#define __SHADOW_RECORD_ALL__
-#define __BRANCHED_PATH__
-
-/* Device specific features */
-#ifdef __KERNEL_CPU__
-# ifdef WITH_OSL
-# define __OSL__
-# endif
-# define __VOLUME_RECORD_ALL__
-#endif /* __KERNEL_CPU__ */
-
-#ifdef __KERNEL_OPTIX__
-# undef __BAKING__
-#endif /* __KERNEL_OPTIX__ */
-
-/* Scene-based selective features compilation. */
-#ifdef __KERNEL_FEATURES__
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_CAMERA_MOTION)
-# undef __CAMERA_MOTION__
-# endif
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_OBJECT_MOTION)
-# undef __OBJECT_MOTION__
-# endif
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_HAIR)
-# undef __HAIR__
-# endif
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_VOLUME)
-# undef __VOLUME__
-# endif
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_SUBSURFACE)
-# undef __SUBSURFACE__
-# endif
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_BAKING)
-# undef __BAKING__
-# endif
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_PATCH_EVALUATION)
-# undef __PATCH_EVAL__
-# endif
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_TRANSPARENT)
-# undef __TRANSPARENT_SHADOWS__
-# endif
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_SHADOW_CATCHER)
-# undef __SHADOW_CATCHER__
-# endif
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_PRINCIPLED)
-# undef __PRINCIPLED__
-# endif
-# if !(__KERNEL_FEATURES & KERNEL_FEATURE_DENOISING)
-# undef __DENOISING_FEATURES__
-# endif
-#endif
-
-#ifdef WITH_CYCLES_DEBUG_NAN
-# define __KERNEL_DEBUG_NAN__
-#endif
-
-/* Features that enable others */
-
-#if defined(__SUBSURFACE__) || defined(__SHADER_RAYTRACE__)
-# define __BVH_LOCAL__
-#endif
-
-/* Path Tracing
- * note we need to keep the u/v pairs at even values */
-
-enum PathTraceDimension {
- PRNG_FILTER_U = 0,
- PRNG_FILTER_V = 1,
- PRNG_LENS_U = 2,
- PRNG_LENS_V = 3,
- PRNG_TIME = 4,
- PRNG_UNUSED_0 = 5,
- PRNG_UNUSED_1 = 6, /* for some reason (6, 7) is a bad sobol pattern */
- PRNG_UNUSED_2 = 7, /* with a low number of samples (< 64) */
- PRNG_BASE_NUM = 10,
-
- PRNG_BSDF_U = 0,
- PRNG_BSDF_V = 1,
- PRNG_LIGHT_U = 2,
- PRNG_LIGHT_V = 3,
- PRNG_LIGHT_TERMINATE = 4,
- PRNG_TERMINATE = 5,
- PRNG_PHASE_CHANNEL = 6,
- PRNG_SCATTER_DISTANCE = 7,
- PRNG_BOUNCE_NUM = 8,
-
- PRNG_BEVEL_U = 6, /* reuse volume dimension, correlation won't harm */
- PRNG_BEVEL_V = 7,
-};
-
-enum SamplingPattern {
- SAMPLING_PATTERN_SOBOL = 0,
- SAMPLING_PATTERN_PMJ = 1,
-
- SAMPLING_NUM_PATTERNS,
-};
-
-/* These flags values correspond to `raytypes` in `osl.cpp`, so keep them in sync! */
-
-enum PathRayFlag {
- /* --------------------------------------------------------------------
- * Ray visibility.
- *
- * NOTE: Recalculated after a surface bounce.
- */
-
- PATH_RAY_CAMERA = (1U << 0U),
- PATH_RAY_REFLECT = (1U << 1U),
- PATH_RAY_TRANSMIT = (1U << 2U),
- PATH_RAY_DIFFUSE = (1U << 3U),
- PATH_RAY_GLOSSY = (1U << 4U),
- PATH_RAY_SINGULAR = (1U << 5U),
- PATH_RAY_TRANSPARENT = (1U << 6U),
- PATH_RAY_VOLUME_SCATTER = (1U << 7U),
-
- /* Shadow ray visibility. */
- PATH_RAY_SHADOW_OPAQUE = (1U << 8U),
- PATH_RAY_SHADOW_TRANSPARENT = (1U << 9U),
- PATH_RAY_SHADOW = (PATH_RAY_SHADOW_OPAQUE | PATH_RAY_SHADOW_TRANSPARENT),
-
- /* Special flag to tag unaligned BVH nodes.
- * Only set and used in BVH nodes to distinguish how to interpret bounding box information stored
- * in the node (either it should be intersected as AABB or as OBBU). */
- PATH_RAY_NODE_UNALIGNED = (1U << 10U),
-
- /* Subset of flags used for ray visibility for intersection.
- *
- * NOTE: SHADOW_CATCHER macros below assume there are no more than
- * 16 visibility bits. */
- PATH_RAY_ALL_VISIBILITY = ((1U << 11U) - 1U),
-
- /* --------------------------------------------------------------------
- * Path flags.
- */
-
- /* Don't apply multiple importance sampling weights to emission from
- * lamp or surface hits, because they were not direct light sampled. */
- PATH_RAY_MIS_SKIP = (1U << 11U),
-
- /* Diffuse bounce earlier in the path, skip SSS to improve performance
- * and avoid branching twice with disk sampling SSS. */
- PATH_RAY_DIFFUSE_ANCESTOR = (1U << 12U),
-
- /* Single pass has been written. */
- PATH_RAY_SINGLE_PASS_DONE = (1U << 13U),
-
- /* Zero background alpha, for camera or transparent glass rays. */
- PATH_RAY_TRANSPARENT_BACKGROUND = (1U << 14U),
-
- /* Terminate ray immediately at next bounce. */
- PATH_RAY_TERMINATE_ON_NEXT_SURFACE = (1U << 15U),
- PATH_RAY_TERMINATE_IN_NEXT_VOLUME = (1U << 16U),
-
- /* Ray is to be terminated, but continue with transparent bounces and
- * emission as long as we encounter them. This is required to make the
- * MIS between direct and indirect light rays match, as shadow rays go
- * through transparent surfaces to reach emission too. */
- PATH_RAY_TERMINATE_AFTER_TRANSPARENT = (1U << 17U),
-
- /* Terminate ray immediately after volume shading. */
- PATH_RAY_TERMINATE_AFTER_VOLUME = (1U << 18U),
-
- /* Ray is to be terminated. */
- PATH_RAY_TERMINATE = (PATH_RAY_TERMINATE_ON_NEXT_SURFACE | PATH_RAY_TERMINATE_IN_NEXT_VOLUME |
- PATH_RAY_TERMINATE_AFTER_TRANSPARENT | PATH_RAY_TERMINATE_AFTER_VOLUME),
-
- /* Path and shader is being evaluated for direct lighting emission. */
- PATH_RAY_EMISSION = (1U << 19U),
-
- /* Perform subsurface scattering. */
- PATH_RAY_SUBSURFACE_RANDOM_WALK = (1U << 20U),
- PATH_RAY_SUBSURFACE_DISK = (1U << 21U),
- PATH_RAY_SUBSURFACE_USE_FRESNEL = (1U << 22U),
- PATH_RAY_SUBSURFACE = (PATH_RAY_SUBSURFACE_RANDOM_WALK | PATH_RAY_SUBSURFACE_DISK |
- PATH_RAY_SUBSURFACE_USE_FRESNEL),
-
- /* Contribute to denoising features. */
- PATH_RAY_DENOISING_FEATURES = (1U << 23U),
-
- /* Render pass categories. */
- PATH_RAY_REFLECT_PASS = (1U << 24U),
- PATH_RAY_TRANSMISSION_PASS = (1U << 25U),
- PATH_RAY_VOLUME_PASS = (1U << 26U),
- PATH_RAY_ANY_PASS = (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS | PATH_RAY_VOLUME_PASS),
-
- /* Shadow ray is for a light or surface, or AO. */
- PATH_RAY_SHADOW_FOR_LIGHT = (1U << 27U),
- PATH_RAY_SHADOW_FOR_AO = (1U << 28U),
-
- /* A shadow catcher object was hit and the path was split into two. */
- PATH_RAY_SHADOW_CATCHER_HIT = (1U << 29U),
-
- /* A shadow catcher object was hit and this path traces only shadow catchers, writing them into
- * their dedicated pass for later division.
- *
- * NOTE: Is not covered with `PATH_RAY_ANY_PASS` because shadow catcher does special handling
- * which is separate from the light passes. */
- PATH_RAY_SHADOW_CATCHER_PASS = (1U << 30U),
-
- /* Path is evaluating background for an approximate shadow catcher with non-transparent film. */
- PATH_RAY_SHADOW_CATCHER_BACKGROUND = (1U << 31U),
-};
-
-/* Configure ray visibility bits for rays and objects respectively,
- * to make shadow catchers work.
- *
- * On shadow catcher paths we want to ignore any intersections with non-catchers,
- * whereas on regular paths we want to intersect all objects. */
-
-#define SHADOW_CATCHER_VISIBILITY_SHIFT(visibility) ((visibility) << 16)
-
-#define SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility) \
- (((path_flag)&PATH_RAY_SHADOW_CATCHER_PASS) ? SHADOW_CATCHER_VISIBILITY_SHIFT(visibility) : \
- (visibility))
-
-#define SHADOW_CATCHER_OBJECT_VISIBILITY(is_shadow_catcher, visibility) \
- (((is_shadow_catcher) ? SHADOW_CATCHER_VISIBILITY_SHIFT(visibility) : 0) | (visibility))
-
-/* Closure Label */
-
-typedef enum ClosureLabel {
- LABEL_NONE = 0,
- LABEL_TRANSMIT = 1,
- LABEL_REFLECT = 2,
- LABEL_DIFFUSE = 4,
- LABEL_GLOSSY = 8,
- LABEL_SINGULAR = 16,
- LABEL_TRANSPARENT = 32,
- LABEL_VOLUME_SCATTER = 64,
- LABEL_TRANSMIT_TRANSPARENT = 128,
- LABEL_SUBSURFACE_SCATTER = 256,
-} ClosureLabel;
-
-/* Render Passes */
-
-#define PASS_NAME_JOIN(a, b) a##_##b
-#define PASSMASK(pass) (1 << ((PASS_NAME_JOIN(PASS, pass)) % 32))
-
-// NOTE: Keep in sync with `Pass::get_type_enum()`.
-typedef enum PassType {
- PASS_NONE = 0,
-
- /* Light Passes */
- PASS_COMBINED = 1,
- PASS_EMISSION,
- PASS_BACKGROUND,
- PASS_AO,
- PASS_SHADOW,
- PASS_DIFFUSE,
- PASS_DIFFUSE_DIRECT,
- PASS_DIFFUSE_INDIRECT,
- PASS_GLOSSY,
- PASS_GLOSSY_DIRECT,
- PASS_GLOSSY_INDIRECT,
- PASS_TRANSMISSION,
- PASS_TRANSMISSION_DIRECT,
- PASS_TRANSMISSION_INDIRECT,
- PASS_VOLUME,
- PASS_VOLUME_DIRECT,
- PASS_VOLUME_INDIRECT,
- PASS_CATEGORY_LIGHT_END = 31,
-
- /* Data passes */
- PASS_DEPTH = 32,
- PASS_POSITION,
- PASS_NORMAL,
- PASS_ROUGHNESS,
- PASS_UV,
- PASS_OBJECT_ID,
- PASS_MATERIAL_ID,
- PASS_MOTION,
- PASS_MOTION_WEIGHT,
- PASS_CRYPTOMATTE,
- PASS_AOV_COLOR,
- PASS_AOV_VALUE,
- PASS_ADAPTIVE_AUX_BUFFER,
- PASS_SAMPLE_COUNT,
- PASS_DIFFUSE_COLOR,
- PASS_GLOSSY_COLOR,
- PASS_TRANSMISSION_COLOR,
- /* No Scatter color since it's tricky to define what it would even mean. */
- PASS_MIST,
- PASS_DENOISING_NORMAL,
- PASS_DENOISING_ALBEDO,
-
- /* PASS_SHADOW_CATCHER accumulates contribution of shadow catcher object which is not affected by
- * any other object. The pass accessor will divide the combined pass by the shadow catcher. The
- * result of this division is then to be multiplied with the backdrop. The alpha channel of this
- * pass contains number of samples which contributed to the color components of the pass.
- *
- * PASS_SHADOW_CATCHER_SAMPLE_COUNT contains number of samples for which the path split
- * happened.
- *
- * PASS_SHADOW_CATCHER_MATTE contains pass which contains non-catcher objects. This pass is to be
- * alpha-overed onto the backdrop (after multiplication). */
- PASS_SHADOW_CATCHER,
- PASS_SHADOW_CATCHER_SAMPLE_COUNT,
- PASS_SHADOW_CATCHER_MATTE,
-
- PASS_CATEGORY_DATA_END = 63,
-
- PASS_BAKE_PRIMITIVE,
- PASS_BAKE_DIFFERENTIAL,
- PASS_CATEGORY_BAKE_END = 95,
-
- PASS_NUM,
-} PassType;
-
-#define PASS_ANY (~0)
-
-typedef enum CryptomatteType {
- CRYPT_NONE = 0,
- CRYPT_OBJECT = (1 << 0),
- CRYPT_MATERIAL = (1 << 1),
- CRYPT_ASSET = (1 << 2),
- CRYPT_ACCURATE = (1 << 3),
-} CryptomatteType;
-
-typedef struct BsdfEval {
- float3 diffuse;
- float3 glossy;
-} BsdfEval;
-
-/* Shader Flag */
-
-typedef enum ShaderFlag {
- SHADER_SMOOTH_NORMAL = (1 << 31),
- SHADER_CAST_SHADOW = (1 << 30),
- SHADER_AREA_LIGHT = (1 << 29),
- SHADER_USE_MIS = (1 << 28),
- SHADER_EXCLUDE_DIFFUSE = (1 << 27),
- SHADER_EXCLUDE_GLOSSY = (1 << 26),
- SHADER_EXCLUDE_TRANSMIT = (1 << 25),
- SHADER_EXCLUDE_CAMERA = (1 << 24),
- SHADER_EXCLUDE_SCATTER = (1 << 23),
- SHADER_EXCLUDE_SHADOW_CATCHER = (1 << 22),
- SHADER_EXCLUDE_ANY = (SHADER_EXCLUDE_DIFFUSE | SHADER_EXCLUDE_GLOSSY | SHADER_EXCLUDE_TRANSMIT |
- SHADER_EXCLUDE_CAMERA | SHADER_EXCLUDE_SCATTER |
- SHADER_EXCLUDE_SHADOW_CATCHER),
-
- SHADER_MASK = ~(SHADER_SMOOTH_NORMAL | SHADER_CAST_SHADOW | SHADER_AREA_LIGHT | SHADER_USE_MIS |
- SHADER_EXCLUDE_ANY)
-} ShaderFlag;
-
-/* Light Type */
-
-typedef enum LightType {
- LIGHT_POINT,
- LIGHT_DISTANT,
- LIGHT_BACKGROUND,
- LIGHT_AREA,
- LIGHT_SPOT,
- LIGHT_TRIANGLE
-} LightType;
-
-/* Camera Type */
-
-enum CameraType { CAMERA_PERSPECTIVE, CAMERA_ORTHOGRAPHIC, CAMERA_PANORAMA };
-
-/* Panorama Type */
-
-enum PanoramaType {
- PANORAMA_EQUIRECTANGULAR = 0,
- PANORAMA_FISHEYE_EQUIDISTANT = 1,
- PANORAMA_FISHEYE_EQUISOLID = 2,
- PANORAMA_MIRRORBALL = 3,
-
- PANORAMA_NUM_TYPES,
-};
-
-/* Differential */
-
-typedef struct differential3 {
- float3 dx;
- float3 dy;
-} differential3;
-
-typedef struct differential {
- float dx;
- float dy;
-} differential;
-
-/* Ray */
-
-typedef struct Ray {
- float3 P; /* origin */
- float3 D; /* direction */
- float t; /* length of the ray */
- float time; /* time (for motion blur) */
-
-#ifdef __RAY_DIFFERENTIALS__
- float dP;
- float dD;
-#endif
-} Ray;
-
-/* Intersection */
-
-typedef struct Intersection {
- float t, u, v;
- int prim;
- int object;
- int type;
-} Intersection;
-
-/* Primitives */
-
-typedef enum PrimitiveType {
- PRIMITIVE_NONE = 0,
- PRIMITIVE_TRIANGLE = (1 << 0),
- PRIMITIVE_MOTION_TRIANGLE = (1 << 1),
- PRIMITIVE_CURVE_THICK = (1 << 2),
- PRIMITIVE_MOTION_CURVE_THICK = (1 << 3),
- PRIMITIVE_CURVE_RIBBON = (1 << 4),
- PRIMITIVE_MOTION_CURVE_RIBBON = (1 << 5),
- PRIMITIVE_VOLUME = (1 << 6),
- PRIMITIVE_LAMP = (1 << 7),
-
- PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION_TRIANGLE),
- PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION_CURVE_THICK |
- PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON),
- PRIMITIVE_ALL_VOLUME = (PRIMITIVE_VOLUME),
- PRIMITIVE_ALL_MOTION = (PRIMITIVE_MOTION_TRIANGLE | PRIMITIVE_MOTION_CURVE_THICK |
- PRIMITIVE_MOTION_CURVE_RIBBON),
- PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE | PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_VOLUME |
- PRIMITIVE_LAMP),
-
- PRIMITIVE_NUM = 8,
-} PrimitiveType;
-
-#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM) | (type))
-#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM)
-
-typedef enum CurveShapeType {
- CURVE_RIBBON = 0,
- CURVE_THICK = 1,
-
- CURVE_NUM_SHAPE_TYPES,
-} CurveShapeType;
-
-/* Attributes */
-
-typedef enum AttributePrimitive {
- ATTR_PRIM_GEOMETRY = 0,
- ATTR_PRIM_SUBD,
-
- ATTR_PRIM_TYPES
-} AttributePrimitive;
-
-typedef enum AttributeElement {
- ATTR_ELEMENT_NONE = 0,
- ATTR_ELEMENT_OBJECT = (1 << 0),
- ATTR_ELEMENT_MESH = (1 << 1),
- ATTR_ELEMENT_FACE = (1 << 2),
- ATTR_ELEMENT_VERTEX = (1 << 3),
- ATTR_ELEMENT_VERTEX_MOTION = (1 << 4),
- ATTR_ELEMENT_CORNER = (1 << 5),
- ATTR_ELEMENT_CORNER_BYTE = (1 << 6),
- ATTR_ELEMENT_CURVE = (1 << 7),
- ATTR_ELEMENT_CURVE_KEY = (1 << 8),
- ATTR_ELEMENT_CURVE_KEY_MOTION = (1 << 9),
- ATTR_ELEMENT_VOXEL = (1 << 10)
-} AttributeElement;
-
-typedef enum AttributeStandard {
- ATTR_STD_NONE = 0,
- ATTR_STD_VERTEX_NORMAL,
- ATTR_STD_FACE_NORMAL,
- ATTR_STD_UV,
- ATTR_STD_UV_TANGENT,
- ATTR_STD_UV_TANGENT_SIGN,
- ATTR_STD_VERTEX_COLOR,
- ATTR_STD_GENERATED,
- ATTR_STD_GENERATED_TRANSFORM,
- ATTR_STD_POSITION_UNDEFORMED,
- ATTR_STD_POSITION_UNDISPLACED,
- ATTR_STD_MOTION_VERTEX_POSITION,
- ATTR_STD_MOTION_VERTEX_NORMAL,
- ATTR_STD_PARTICLE,
- ATTR_STD_CURVE_INTERCEPT,
- ATTR_STD_CURVE_LENGTH,
- ATTR_STD_CURVE_RANDOM,
- ATTR_STD_PTEX_FACE_ID,
- ATTR_STD_PTEX_UV,
- ATTR_STD_VOLUME_DENSITY,
- ATTR_STD_VOLUME_COLOR,
- ATTR_STD_VOLUME_FLAME,
- ATTR_STD_VOLUME_HEAT,
- ATTR_STD_VOLUME_TEMPERATURE,
- ATTR_STD_VOLUME_VELOCITY,
- ATTR_STD_POINTINESS,
- ATTR_STD_RANDOM_PER_ISLAND,
- ATTR_STD_SHADOW_TRANSPARENCY,
- ATTR_STD_NUM,
-
- ATTR_STD_NOT_FOUND = ~0
-} AttributeStandard;
-
-typedef enum AttributeFlag {
- ATTR_FINAL_SIZE = (1 << 0),
- ATTR_SUBDIVIDED = (1 << 1),
-} AttributeFlag;
-
-typedef struct AttributeDescriptor {
- AttributeElement element;
- NodeAttributeType type;
- uint flags; /* see enum AttributeFlag */
- int offset;
-} AttributeDescriptor;
-
-/* Closure data */
-
-#ifndef __MAX_CLOSURE__
-# define MAX_CLOSURE 64
-#else
-# define MAX_CLOSURE __MAX_CLOSURE__
-#endif
-
-#ifndef __MAX_VOLUME_STACK_SIZE__
-# define MAX_VOLUME_STACK_SIZE 32
-#else
-# define MAX_VOLUME_STACK_SIZE __MAX_VOLUME_STACK_SIZE__
-#endif
-
-#define MAX_VOLUME_CLOSURE 8
-
-/* This struct is the base class for all closures. The common members are
- * duplicated in all derived classes since we don't have C++ in the kernel
- * yet, and because it lets us lay out the members to minimize padding. The
- * weight member is located at the beginning of the struct for this reason.
- *
- * ShaderClosure has a fixed size, and any extra space must be allocated
- * with closure_alloc_extra().
- *
- * We pad the struct to align to 16 bytes. All shader closures are assumed
- * to fit in this struct size. CPU sizes are a bit larger because float3 is
- * padded to be 16 bytes, while it's only 12 bytes on the GPU. */
-
-#define SHADER_CLOSURE_BASE \
- float3 weight; \
- ClosureType type; \
- float sample_weight; \
- float3 N
-
-typedef struct ccl_align(16) ShaderClosure
-{
- SHADER_CLOSURE_BASE;
-
-#ifdef __KERNEL_CPU__
- float pad[2];
-#endif
- float data[10];
-}
-ShaderClosure;
-
-/* Shader Data
- *
- * Main shader state at a point on the surface or in a volume. All coordinates
- * are in world space.
- */
-
-enum ShaderDataFlag {
- /* Runtime flags. */
-
- /* Set when ray hits backside of surface. */
- SD_BACKFACING = (1 << 0),
- /* Shader has non-zero emission. */
- SD_EMISSION = (1 << 1),
- /* Shader has BSDF closure. */
- SD_BSDF = (1 << 2),
- /* Shader has non-singular BSDF closure. */
- SD_BSDF_HAS_EVAL = (1 << 3),
- /* Shader has BSSRDF closure. */
- SD_BSSRDF = (1 << 4),
- /* Shader has holdout closure. */
- SD_HOLDOUT = (1 << 5),
- /* Shader has non-zero volume extinction. */
- SD_EXTINCTION = (1 << 6),
- /* Shader has have volume phase (scatter) closure. */
- SD_SCATTER = (1 << 7),
- /* Shader has transparent closure. */
- SD_TRANSPARENT = (1 << 9),
- /* BSDF requires LCG for evaluation. */
- SD_BSDF_NEEDS_LCG = (1 << 10),
-
- SD_CLOSURE_FLAGS = (SD_EMISSION | SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSSRDF | SD_HOLDOUT |
- SD_EXTINCTION | SD_SCATTER | SD_BSDF_NEEDS_LCG),
-
- /* Shader flags. */
-
- /* direct light sample */
- SD_USE_MIS = (1 << 16),
- /* Has transparent shadow. */
- SD_HAS_TRANSPARENT_SHADOW = (1 << 17),
- /* Has volume shader. */
- SD_HAS_VOLUME = (1 << 18),
- /* Has only volume shader, no surface. */
- SD_HAS_ONLY_VOLUME = (1 << 19),
- /* Has heterogeneous volume. */
- SD_HETEROGENEOUS_VOLUME = (1 << 20),
- /* BSSRDF normal uses bump. */
- SD_HAS_BSSRDF_BUMP = (1 << 21),
- /* Use equiangular volume sampling */
- SD_VOLUME_EQUIANGULAR = (1 << 22),
- /* Use multiple importance volume sampling. */
- SD_VOLUME_MIS = (1 << 23),
- /* Use cubic interpolation for voxels. */
- SD_VOLUME_CUBIC = (1 << 24),
- /* Has data connected to the displacement input or uses bump map. */
- SD_HAS_BUMP = (1 << 25),
- /* Has true displacement. */
- SD_HAS_DISPLACEMENT = (1 << 26),
- /* Has constant emission (value stored in __shaders) */
- SD_HAS_CONSTANT_EMISSION = (1 << 27),
- /* Needs to access attributes for volume rendering */
- SD_NEED_VOLUME_ATTRIBUTES = (1 << 28),
- /* Shader has emission */
- SD_HAS_EMISSION = (1 << 29),
- /* Shader has raytracing */
- SD_HAS_RAYTRACE = (1 << 30),
-
- SD_SHADER_FLAGS = (SD_USE_MIS | SD_HAS_TRANSPARENT_SHADOW | SD_HAS_VOLUME | SD_HAS_ONLY_VOLUME |
- SD_HETEROGENEOUS_VOLUME | SD_HAS_BSSRDF_BUMP | SD_VOLUME_EQUIANGULAR |
- SD_VOLUME_MIS | SD_VOLUME_CUBIC | SD_HAS_BUMP | SD_HAS_DISPLACEMENT |
- SD_HAS_CONSTANT_EMISSION | SD_NEED_VOLUME_ATTRIBUTES | SD_HAS_EMISSION |
- SD_HAS_RAYTRACE)
-};
-
-/* Object flags. */
-enum ShaderDataObjectFlag {
- /* Holdout for camera rays. */
- SD_OBJECT_HOLDOUT_MASK = (1 << 0),
- /* Has object motion blur. */
- SD_OBJECT_MOTION = (1 << 1),
- /* Vertices have transform applied. */
- SD_OBJECT_TRANSFORM_APPLIED = (1 << 2),
- /* Vertices have negative scale applied. */
- SD_OBJECT_NEGATIVE_SCALE_APPLIED = (1 << 3),
- /* Object has a volume shader. */
- SD_OBJECT_HAS_VOLUME = (1 << 4),
- /* Object intersects AABB of an object with volume shader. */
- SD_OBJECT_INTERSECTS_VOLUME = (1 << 5),
- /* Has position for motion vertices. */
- SD_OBJECT_HAS_VERTEX_MOTION = (1 << 6),
- /* object is used to catch shadows */
- SD_OBJECT_SHADOW_CATCHER = (1 << 7),
- /* object has volume attributes */
- SD_OBJECT_HAS_VOLUME_ATTRIBUTES = (1 << 8),
-
- SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK | SD_OBJECT_MOTION | SD_OBJECT_TRANSFORM_APPLIED |
- SD_OBJECT_NEGATIVE_SCALE_APPLIED | SD_OBJECT_HAS_VOLUME |
- SD_OBJECT_INTERSECTS_VOLUME | SD_OBJECT_SHADOW_CATCHER |
- SD_OBJECT_HAS_VOLUME_ATTRIBUTES)
-};
-
-typedef struct ccl_align(16) ShaderData
-{
- /* position */
- float3 P;
- /* smooth normal for shading */
- float3 N;
- /* true geometric normal */
- float3 Ng;
- /* view/incoming direction */
- float3 I;
- /* shader id */
- int shader;
- /* booleans describing shader, see ShaderDataFlag */
- int flag;
- /* booleans describing object of the shader, see ShaderDataObjectFlag */
- int object_flag;
-
- /* primitive id if there is one, ~0 otherwise */
- int prim;
-
- /* combined type and curve segment for hair */
- int type;
-
- /* parametric coordinates
- * - barycentric weights for triangles */
- float u;
- float v;
- /* object id if there is one, ~0 otherwise */
- int object;
- /* lamp id if there is one, ~0 otherwise */
- int lamp;
-
- /* motion blur sample time */
- float time;
-
- /* length of the ray being shaded */
- float ray_length;
-
-#ifdef __RAY_DIFFERENTIALS__
- /* differential of P. these are orthogonal to Ng, not N */
- differential3 dP;
- /* differential of I */
- differential3 dI;
- /* differential of u, v */
- differential du;
- differential dv;
-#endif
-#ifdef __DPDU__
- /* differential of P w.r.t. parametric coordinates. note that dPdu is
- * not readily suitable as a tangent for shading on triangles. */
- float3 dPdu;
- float3 dPdv;
-#endif
-
-#ifdef __OBJECT_MOTION__
- /* Object <-> world space transformations for motion blur, cached to avoid
- * re-interpolating them constantly for shading. */
- Transform ob_tfm_motion;
- Transform ob_itfm_motion;
-#endif
-
- /* ray start position, only set for backgrounds */
- float3 ray_P;
- float ray_dP;
-
-#ifdef __OSL__
- const struct KernelGlobalsCPU *osl_globals;
- const struct IntegratorStateCPU *osl_path_state;
- const struct IntegratorShadowStateCPU *osl_shadow_path_state;
-#endif
-
- /* LCG state for closures that require additional random numbers. */
- uint lcg_state;
-
- /* Closure data, we store a fixed array of closures */
- int num_closure;
- int num_closure_left;
- float3 svm_closure_weight;
-
- /* Closure weights summed directly, so we can evaluate
- * emission and shadow transparency with MAX_CLOSURE 0. */
- float3 closure_emission_background;
- float3 closure_transparent_extinction;
-
- /* At the end so we can adjust size in ShaderDataTinyStorage. */
- struct ShaderClosure closure[MAX_CLOSURE];
-}
-ShaderData;
-
-/* ShaderDataTinyStorage needs the same alignment as ShaderData, or else
- * the pointer cast in AS_SHADER_DATA invokes undefined behavior. */
-typedef struct ccl_align(16) ShaderDataTinyStorage
-{
- char pad[sizeof(ShaderData) - sizeof(ShaderClosure) * MAX_CLOSURE];
-}
-ShaderDataTinyStorage;
-#define AS_SHADER_DATA(shader_data_tiny_storage) \
- ((ccl_private ShaderData *)shader_data_tiny_storage)
-
-/* Compact volume closures storage.
- *
- * Used for decoupled direct/indirect light closure storage. */
-
-typedef struct ShaderVolumeClosure {
- float3 weight;
- float sample_weight;
- float g;
-} ShaderVolumeClosure;
-
-typedef struct ShaderVolumePhases {
- ShaderVolumeClosure closure[MAX_VOLUME_CLOSURE];
- int num_closure;
-} ShaderVolumePhases;
-
-/* Volume Stack */
-
-#ifdef __VOLUME__
-typedef struct VolumeStack {
- int object;
- int shader;
-} VolumeStack;
-#endif
-
-/* Struct to gather multiple nearby intersections. */
-typedef struct LocalIntersection {
- int num_hits;
- struct Intersection hits[LOCAL_MAX_HITS];
- float3 Ng[LOCAL_MAX_HITS];
-} LocalIntersection;
-
-/* Constant Kernel Data
- *
- * These structs are passed from CPU to various devices, and the struct layout
- * must match exactly. Structs are padded to ensure 16 byte alignment, and we
- * do not use float3 because its size may not be the same on all devices. */
-
-typedef struct KernelCamera {
- /* type */
- int type;
-
- /* panorama */
- int panorama_type;
- float fisheye_fov;
- float fisheye_lens;
- float4 equirectangular_range;
-
- /* stereo */
- float interocular_offset;
- float convergence_distance;
- float pole_merge_angle_from;
- float pole_merge_angle_to;
-
- /* matrices */
- Transform cameratoworld;
- ProjectionTransform rastertocamera;
-
- /* differentials */
- float4 dx;
- float4 dy;
-
- /* depth of field */
- float aperturesize;
- float blades;
- float bladesrotation;
- float focaldistance;
-
- /* motion blur */
- float shuttertime;
- int num_motion_steps, have_perspective_motion;
-
- /* clipping */
- float nearclip;
- float cliplength;
-
- /* sensor size */
- float sensorwidth;
- float sensorheight;
-
- /* render size */
- float width, height;
- int pad1;
-
- /* anamorphic lens bokeh */
- float inv_aperture_ratio;
-
- int is_inside_volume;
-
- /* more matrices */
- ProjectionTransform screentoworld;
- ProjectionTransform rastertoworld;
- ProjectionTransform ndctoworld;
- ProjectionTransform worldtoscreen;
- ProjectionTransform worldtoraster;
- ProjectionTransform worldtondc;
- Transform worldtocamera;
-
- /* Stores changes in the projection matrix. Use for camera zoom motion
- * blur and motion pass output for perspective camera. */
- ProjectionTransform perspective_pre;
- ProjectionTransform perspective_post;
-
- /* Transforms for motion pass. */
- Transform motion_pass_pre;
- Transform motion_pass_post;
-
- int shutter_table_offset;
-
- /* Rolling shutter */
- int rolling_shutter_type;
- float rolling_shutter_duration;
-
- int pad;
-} KernelCamera;
-static_assert_align(KernelCamera, 16);
-
-typedef struct KernelFilm {
- float exposure;
- int pass_flag;
-
- int light_pass_flag;
- int pass_stride;
-
- int pass_combined;
- int pass_depth;
- int pass_position;
- int pass_normal;
- int pass_roughness;
- int pass_motion;
-
- int pass_motion_weight;
- int pass_uv;
- int pass_object_id;
- int pass_material_id;
-
- int pass_diffuse_color;
- int pass_glossy_color;
- int pass_transmission_color;
-
- int pass_diffuse_indirect;
- int pass_glossy_indirect;
- int pass_transmission_indirect;
- int pass_volume_indirect;
-
- int pass_diffuse_direct;
- int pass_glossy_direct;
- int pass_transmission_direct;
- int pass_volume_direct;
-
- int pass_emission;
- int pass_background;
- int pass_ao;
- float pass_alpha_threshold;
-
- int pass_shadow;
- float pass_shadow_scale;
-
- int pass_shadow_catcher;
- int pass_shadow_catcher_sample_count;
- int pass_shadow_catcher_matte;
-
- int filter_table_offset;
-
- int cryptomatte_passes;
- int cryptomatte_depth;
- int pass_cryptomatte;
-
- int pass_adaptive_aux_buffer;
- int pass_sample_count;
-
- int pass_mist;
- float mist_start;
- float mist_inv_depth;
- float mist_falloff;
-
- int pass_denoising_normal;
- int pass_denoising_albedo;
-
- int pass_aov_color;
- int pass_aov_value;
-
- /* XYZ to rendering color space transform. float4 instead of float3 to
- * ensure consistent padding/alignment across devices. */
- float4 xyz_to_r;
- float4 xyz_to_g;
- float4 xyz_to_b;
- float4 rgb_to_y;
-
- int pass_bake_primitive;
- int pass_bake_differential;
-
- int use_approximate_shadow_catcher;
-
- int pad1, pad2, pad3;
-} KernelFilm;
-static_assert_align(KernelFilm, 16);
-
-typedef struct KernelFilmConvert {
- int pass_offset;
- int pass_stride;
-
- int pass_use_exposure;
- int pass_use_filter;
-
- int pass_divide;
- int pass_indirect;
-
- int pass_combined;
- int pass_sample_count;
- int pass_adaptive_aux_buffer;
- int pass_motion_weight;
- int pass_shadow_catcher;
- int pass_shadow_catcher_sample_count;
- int pass_shadow_catcher_matte;
- int pass_background;
-
- float scale;
- float exposure;
- float scale_exposure;
-
- int use_approximate_shadow_catcher;
- int use_approximate_shadow_catcher_background;
- int show_active_pixels;
-
- /* Number of components to write to. */
- int num_components;
-
- /* Number of floats per pixel. When zero is the same as `num_components`.
- * NOTE: Is ignored for half4 destination. */
- int pixel_stride;
-
- int is_denoised;
-
- /* Padding. */
- int pad1;
-} KernelFilmConvert;
-static_assert_align(KernelFilmConvert, 16);
-
-typedef struct KernelBackground {
- /* only shader index */
- int surface_shader;
- int volume_shader;
- float volume_step_size;
- int transparent;
- float transparent_roughness_squared_threshold;
-
- /* portal sampling */
- float portal_weight;
- int num_portals;
- int portal_offset;
-
- /* sun sampling */
- float sun_weight;
- /* xyz store direction, w the angle. float4 instead of float3 is used
- * to ensure consistent padding/alignment across devices. */
- float4 sun;
-
- /* map sampling */
- float map_weight;
- int map_res_x;
- int map_res_y;
-
- int use_mis;
-
- /* Padding */
- int pad1, pad2, pad3;
-} KernelBackground;
-static_assert_align(KernelBackground, 16);
-
-typedef struct KernelIntegrator {
- /* emission */
- int use_direct_light;
- int num_distribution;
- int num_all_lights;
- float pdf_triangles;
- float pdf_lights;
- float light_inv_rr_threshold;
-
- /* bounces */
- int min_bounce;
- int max_bounce;
-
- int max_diffuse_bounce;
- int max_glossy_bounce;
- int max_transmission_bounce;
- int max_volume_bounce;
-
- /* AO bounces */
- int ao_bounces;
- float ao_bounces_distance;
- float ao_bounces_factor;
-
- /* transparent */
- int transparent_min_bounce;
- int transparent_max_bounce;
- int transparent_shadows;
-
- /* caustics */
- int caustics_reflective;
- int caustics_refractive;
- float filter_glossy;
-
- /* seed */
- int seed;
-
- /* clamp */
- float sample_clamp_direct;
- float sample_clamp_indirect;
-
- /* mis */
- int use_lamp_mis;
-
- /* sampler */
- int sampling_pattern;
-
- /* volume render */
- int use_volumes;
- int volume_max_steps;
- float volume_step_rate;
-
- int has_shadow_catcher;
-
- /* padding */
- int pad1, pad2;
-} KernelIntegrator;
-static_assert_align(KernelIntegrator, 16);
-
-typedef enum KernelBVHLayout {
- BVH_LAYOUT_NONE = 0,
-
- BVH_LAYOUT_BVH2 = (1 << 0),
- BVH_LAYOUT_EMBREE = (1 << 1),
- BVH_LAYOUT_OPTIX = (1 << 2),
- BVH_LAYOUT_MULTI_OPTIX = (1 << 3),
- BVH_LAYOUT_MULTI_OPTIX_EMBREE = (1 << 4),
-
- /* Default BVH layout to use for CPU. */
- BVH_LAYOUT_AUTO = BVH_LAYOUT_EMBREE,
- BVH_LAYOUT_ALL = BVH_LAYOUT_BVH2 | BVH_LAYOUT_EMBREE | BVH_LAYOUT_OPTIX,
-} KernelBVHLayout;
-
-typedef struct KernelBVH {
- /* Own BVH */
- int root;
- int have_motion;
- int have_curves;
- int bvh_layout;
- int use_bvh_steps;
- int curve_subdivisions;
-
- /* Custom BVH */
-#ifdef __KERNEL_OPTIX__
- OptixTraversableHandle scene;
-#else
-# ifdef __EMBREE__
- RTCScene scene;
-# ifndef __KERNEL_64_BIT__
- int pad2;
-# endif
-# else
- int scene, pad2;
-# endif
-#endif
-} KernelBVH;
-static_assert_align(KernelBVH, 16);
-
-typedef struct KernelTables {
- int beckmann_offset;
- int pad1, pad2, pad3;
-} KernelTables;
-static_assert_align(KernelTables, 16);
-
-typedef struct KernelBake {
- int use;
- int object_index;
- int tri_offset;
- int pad1;
-} KernelBake;
-static_assert_align(KernelBake, 16);
-
-typedef struct KernelData {
- uint kernel_features;
- uint max_closures;
- uint max_shaders;
- uint volume_stack_size;
-
- KernelCamera cam;
- KernelFilm film;
- KernelBackground background;
- KernelIntegrator integrator;
- KernelBVH bvh;
- KernelTables tables;
- KernelBake bake;
-} KernelData;
-static_assert_align(KernelData, 16);
-
-/* Kernel data structures. */
-
-typedef struct KernelObject {
- Transform tfm;
- Transform itfm;
-
- float volume_density;
- float pass_id;
- float random_number;
- float color[3];
- int particle_index;
-
- float dupli_generated[3];
- float dupli_uv[2];
-
- int numkeys;
- int numsteps;
- int numverts;
-
- uint patch_map_offset;
- uint attribute_map_offset;
- uint motion_offset;
-
- float cryptomatte_object;
- float cryptomatte_asset;
-
- float shadow_terminator_shading_offset;
- float shadow_terminator_geometry_offset;
-
- float ao_distance;
-
- uint visibility;
- int primitive_type;
-} KernelObject;
-static_assert_align(KernelObject, 16);
-
-typedef struct KernelCurve {
- int shader_id;
- int first_key;
- int num_keys;
- int type;
-} KernelCurve;
-static_assert_align(KernelCurve, 16);
-
-typedef struct KernelCurveSegment {
- int prim;
- int type;
-} KernelCurveSegment;
-static_assert_align(KernelCurveSegment, 8);
-
-typedef struct KernelSpotLight {
- float radius;
- float invarea;
- float spot_angle;
- float spot_smooth;
- float dir[3];
- float pad;
-} KernelSpotLight;
-
-/* PointLight is SpotLight with only radius and invarea being used. */
-
-typedef struct KernelAreaLight {
- float axisu[3];
- float invarea;
- float axisv[3];
- float tan_spread;
- float dir[3];
- float normalize_spread;
-} KernelAreaLight;
-
-typedef struct KernelDistantLight {
- float radius;
- float cosangle;
- float invarea;
- float pad;
-} KernelDistantLight;
-
-typedef struct KernelLight {
- int type;
- float co[3];
- int shader_id;
- float max_bounces;
- float random;
- float strength[3];
- float pad1, pad2;
- Transform tfm;
- Transform itfm;
- union {
- KernelSpotLight spot;
- KernelAreaLight area;
- KernelDistantLight distant;
- };
-} KernelLight;
-static_assert_align(KernelLight, 16);
-
-typedef struct KernelLightDistribution {
- float totarea;
- int prim;
- union {
- struct {
- int shader_flag;
- int object_id;
- } mesh_light;
- struct {
- float pad;
- float size;
- } lamp;
- };
-} KernelLightDistribution;
-static_assert_align(KernelLightDistribution, 16);
-
-typedef struct KernelParticle {
- int index;
- float age;
- float lifetime;
- float size;
- float4 rotation;
- /* Only xyz are used of the following. float4 instead of float3 are used
- * to ensure consistent padding/alignment across devices. */
- float4 location;
- float4 velocity;
- float4 angular_velocity;
-} KernelParticle;
-static_assert_align(KernelParticle, 16);
-
-typedef struct KernelShader {
- float constant_emission[3];
- float cryptomatte_id;
- int flags;
- int pass_id;
- int pad2, pad3;
-} KernelShader;
-static_assert_align(KernelShader, 16);
-
-/* Patches */
-
-#define PATCH_MAX_CONTROL_VERTS 16
-
-/* Patch map node flags */
-
-#define PATCH_MAP_NODE_IS_SET (1 << 30)
-#define PATCH_MAP_NODE_IS_LEAF (1u << 31)
-#define PATCH_MAP_NODE_INDEX_MASK (~(PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF))
-
-/* Work Tiles */
-
-typedef struct KernelWorkTile {
- uint x, y, w, h;
-
- uint start_sample;
- uint num_samples;
-
- int offset;
- uint stride;
-
- /* Precalculated parameters used by init_from_camera kernel on GPU. */
- int path_index_offset;
- int work_size;
-} KernelWorkTile;
-
-/* Shader Evaluation.
- *
- * Position on a primitive on an object at which we want to evaluate the
- * shader for e.g. mesh displacement or light importance map. */
-
-typedef struct KernelShaderEvalInput {
- int object;
- int prim;
- float u, v;
-} KernelShaderEvalInput;
-static_assert_align(KernelShaderEvalInput, 16);
-
-/* Pre-computed sample table sizes for PMJ02 sampler. */
-#define NUM_PMJ_DIVISIONS 32
-#define NUM_PMJ_SAMPLES ((NUM_PMJ_DIVISIONS) * (NUM_PMJ_DIVISIONS))
-#define NUM_PMJ_PATTERNS 1
-
-/* Device kernels.
- *
- * Identifier for kernels that can be executed in device queues.
- *
- * Some implementation details.
- *
- * If the kernel uses shared CUDA memory, `CUDADeviceQueue::enqueue` is to be modified.
- * The path iteration kernels are handled in `PathTraceWorkGPU::enqueue_path_iteration`. */
-
-typedef enum DeviceKernel {
- DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA = 0,
- DEVICE_KERNEL_INTEGRATOR_INIT_FROM_BAKE,
- DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST,
- DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW,
- DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
- DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK,
- DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND,
- DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT,
- DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE,
- DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE,
- DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
- DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW,
- DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL,
-
- DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY,
- DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY,
- DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY,
- DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY,
- DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY,
- DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY,
- DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES,
- DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY,
- DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY,
- DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_STATES,
- DEVICE_KERNEL_INTEGRATOR_RESET,
- DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS,
-
- DEVICE_KERNEL_SHADER_EVAL_DISPLACE,
- DEVICE_KERNEL_SHADER_EVAL_BACKGROUND,
- DEVICE_KERNEL_SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY,
-
-#define DECLARE_FILM_CONVERT_KERNEL(variant) \
- DEVICE_KERNEL_FILM_CONVERT_##variant, DEVICE_KERNEL_FILM_CONVERT_##variant##_HALF_RGBA
-
- DECLARE_FILM_CONVERT_KERNEL(DEPTH),
- DECLARE_FILM_CONVERT_KERNEL(MIST),
- DECLARE_FILM_CONVERT_KERNEL(SAMPLE_COUNT),
- DECLARE_FILM_CONVERT_KERNEL(FLOAT),
- DECLARE_FILM_CONVERT_KERNEL(LIGHT_PATH),
- DECLARE_FILM_CONVERT_KERNEL(FLOAT3),
- DECLARE_FILM_CONVERT_KERNEL(MOTION),
- DECLARE_FILM_CONVERT_KERNEL(CRYPTOMATTE),
- DECLARE_FILM_CONVERT_KERNEL(SHADOW_CATCHER),
- DECLARE_FILM_CONVERT_KERNEL(SHADOW_CATCHER_MATTE_WITH_SHADOW),
- DECLARE_FILM_CONVERT_KERNEL(COMBINED),
- DECLARE_FILM_CONVERT_KERNEL(FLOAT4),
-
-#undef DECLARE_FILM_CONVERT_KERNEL
-
- DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_CHECK,
- DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_X,
- DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_Y,
-
- DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS,
- DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO,
- DEVICE_KERNEL_FILTER_COLOR_PREPROCESS,
- DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS,
-
- DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS,
-
- DEVICE_KERNEL_PREFIX_SUM,
-
- DEVICE_KERNEL_NUM,
-} DeviceKernel;
-
-enum {
- DEVICE_KERNEL_INTEGRATOR_NUM = DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL + 1,
-};
-
-/* Kernel Features */
-
-enum KernelFeatureFlag : unsigned int {
- /* Shader nodes. */
- KERNEL_FEATURE_NODE_BSDF = (1U << 0U),
- KERNEL_FEATURE_NODE_EMISSION = (1U << 1U),
- KERNEL_FEATURE_NODE_VOLUME = (1U << 2U),
- KERNEL_FEATURE_NODE_HAIR = (1U << 3U),
- KERNEL_FEATURE_NODE_BUMP = (1U << 4U),
- KERNEL_FEATURE_NODE_BUMP_STATE = (1U << 5U),
- KERNEL_FEATURE_NODE_VORONOI_EXTRA = (1U << 6U),
- KERNEL_FEATURE_NODE_RAYTRACE = (1U << 7U),
- KERNEL_FEATURE_NODE_AOV = (1U << 8U),
- KERNEL_FEATURE_NODE_LIGHT_PATH = (1U << 9U),
-
- /* Use denoising kernels and output denoising passes. */
- KERNEL_FEATURE_DENOISING = (1U << 10U),
-
- /* Use path tracing kernels. */
- KERNEL_FEATURE_PATH_TRACING = (1U << 11U),
-
- /* BVH/sampling kernel features. */
- KERNEL_FEATURE_HAIR = (1U << 12U),
- KERNEL_FEATURE_HAIR_THICK = (1U << 13U),
- KERNEL_FEATURE_OBJECT_MOTION = (1U << 14U),
- KERNEL_FEATURE_CAMERA_MOTION = (1U << 15U),
-
- /* Denotes whether baking functionality is needed. */
- KERNEL_FEATURE_BAKING = (1U << 16U),
-
- /* Use subsurface scattering materials. */
- KERNEL_FEATURE_SUBSURFACE = (1U << 17U),
-
- /* Use volume materials. */
- KERNEL_FEATURE_VOLUME = (1U << 18U),
-
- /* Use OpenSubdiv patch evaluation */
- KERNEL_FEATURE_PATCH_EVALUATION = (1U << 19U),
-
- /* Use Transparent shadows */
- KERNEL_FEATURE_TRANSPARENT = (1U << 20U),
-
- /* Use shadow catcher. */
- KERNEL_FEATURE_SHADOW_CATCHER = (1U << 21U),
-
- /* Per-uber shader usage flags. */
- KERNEL_FEATURE_PRINCIPLED = (1U << 22U),
-
- /* Light render passes. */
- KERNEL_FEATURE_LIGHT_PASSES = (1U << 23U),
-
- /* Shadow render pass. */
- KERNEL_FEATURE_SHADOW_PASS = (1U << 24U),
-};
-
-/* Shader node feature mask, to specialize shader evaluation for kernels. */
-
-#define KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT \
- (KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VORONOI_EXTRA | \
- KERNEL_FEATURE_NODE_LIGHT_PATH)
-#define KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW \
- (KERNEL_FEATURE_NODE_BSDF | KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VOLUME | \
- KERNEL_FEATURE_NODE_HAIR | KERNEL_FEATURE_NODE_BUMP | KERNEL_FEATURE_NODE_BUMP_STATE | \
- KERNEL_FEATURE_NODE_VORONOI_EXTRA | KERNEL_FEATURE_NODE_LIGHT_PATH)
-#define KERNEL_FEATURE_NODE_MASK_SURFACE \
- (KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW | KERNEL_FEATURE_NODE_RAYTRACE | \
- KERNEL_FEATURE_NODE_AOV | KERNEL_FEATURE_NODE_LIGHT_PATH)
-#define KERNEL_FEATURE_NODE_MASK_VOLUME \
- (KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VOLUME | \
- KERNEL_FEATURE_NODE_VORONOI_EXTRA | KERNEL_FEATURE_NODE_LIGHT_PATH)
-#define KERNEL_FEATURE_NODE_MASK_DISPLACEMENT \
- (KERNEL_FEATURE_NODE_VORONOI_EXTRA | KERNEL_FEATURE_NODE_BUMP | KERNEL_FEATURE_NODE_BUMP_STATE)
-#define KERNEL_FEATURE_NODE_MASK_BUMP KERNEL_FEATURE_NODE_MASK_DISPLACEMENT
-
-/* Must be constexpr on the CPU to avoid compile errors because the state types
- * are different depending on the main, shadow or null path. For GPU we don't have
- * C++17 everywhere so can't use it. */
-#ifdef __KERNEL_CPU__
-# define IF_KERNEL_NODES_FEATURE(feature) \
- if constexpr ((node_feature_mask & (KERNEL_FEATURE_NODE_##feature)) != 0U)
-#else
-# define IF_KERNEL_NODES_FEATURE(feature) \
- if ((node_feature_mask & (KERNEL_FEATURE_NODE_##feature)) != 0U)
-#endif
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/light/background.h b/intern/cycles/kernel/light/background.h
new file mode 100644
index 00000000000..d801cc94393
--- /dev/null
+++ b/intern/cycles/kernel/light/background.h
@@ -0,0 +1,453 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/light/common.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Background Light */
+
+#ifdef __BACKGROUND_MIS__
+
+ccl_device float3 background_map_sample(KernelGlobals kg,
+ float randu,
+ float randv,
+ ccl_private float *pdf)
+{
+ /* for the following, the CDF values are actually a pair of floats, with the
+ * function value as X and the actual CDF as Y. The last entry's function
+ * value is the CDF total. */
+ int res_x = kernel_data.background.map_res_x;
+ int res_y = kernel_data.background.map_res_y;
+ int cdf_width = res_x + 1;
+
+ /* This is basically std::lower_bound as used by PBRT. */
+ int first = 0;
+ int count = res_y;
+
+ while (count > 0) {
+ int step = count >> 1;
+ int middle = first + step;
+
+ if (kernel_tex_fetch(__light_background_marginal_cdf, middle).y < randv) {
+ first = middle + 1;
+ count -= step + 1;
+ }
+ else
+ count = step;
+ }
+
+ int index_v = max(0, first - 1);
+ kernel_assert(index_v >= 0 && index_v < res_y);
+
+ float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
+ float2 cdf_next_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v + 1);
+ float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y);
+
+ /* importance-sampled V direction */
+ float dv = inverse_lerp(cdf_v.y, cdf_next_v.y, randv);
+ float v = (index_v + dv) / res_y;
+
+ /* This is basically std::lower_bound as used by PBRT. */
+ first = 0;
+ count = res_x;
+ while (count > 0) {
+ int step = count >> 1;
+ int middle = first + step;
+
+ if (kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_width + middle).y <
+ randu) {
+ first = middle + 1;
+ count -= step + 1;
+ }
+ else
+ count = step;
+ }
+
+ int index_u = max(0, first - 1);
+ kernel_assert(index_u >= 0 && index_u < res_x);
+
+ float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf,
+ index_v * cdf_width + index_u);
+ float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf,
+ index_v * cdf_width + index_u + 1);
+ float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf,
+ index_v * cdf_width + res_x);
+
+ /* importance-sampled U direction */
+ float du = inverse_lerp(cdf_u.y, cdf_next_u.y, randu);
+ float u = (index_u + du) / res_x;
+
+ /* compute pdf */
+ float sin_theta = sinf(M_PI_F * v);
+ float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x;
+
+ if (sin_theta == 0.0f || denom == 0.0f)
+ *pdf = 0.0f;
+ else
+ *pdf = (cdf_u.x * cdf_v.x) / denom;
+
+ /* compute direction */
+ return equirectangular_to_direction(u, v);
+}
+
+/* TODO(sergey): Same as above, after the release we should consider using
+ * 'noinline' for all devices.
+ */
+ccl_device float background_map_pdf(KernelGlobals kg, float3 direction)
+{
+ float2 uv = direction_to_equirectangular(direction);
+ int res_x = kernel_data.background.map_res_x;
+ int res_y = kernel_data.background.map_res_y;
+ int cdf_width = res_x + 1;
+
+ float sin_theta = sinf(uv.y * M_PI_F);
+
+ if (sin_theta == 0.0f)
+ return 0.0f;
+
+ int index_u = clamp(float_to_int(uv.x * res_x), 0, res_x - 1);
+ int index_v = clamp(float_to_int(uv.y * res_y), 0, res_y - 1);
+
+ /* pdfs in V direction */
+ float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf,
+ index_v * cdf_width + res_x);
+ float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y);
+
+ float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x;
+
+ if (denom == 0.0f)
+ return 0.0f;
+
+ /* pdfs in U direction */
+ float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf,
+ index_v * cdf_width + index_u);
+ float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
+
+ return (cdf_u.x * cdf_v.x) / denom;
+}
+
+ccl_device_inline bool background_portal_data_fetch_and_check_side(
+ KernelGlobals kg, float3 P, int index, ccl_private float3 *lightpos, ccl_private float3 *dir)
+{
+ int portal = kernel_data.background.portal_offset + index;
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+
+ *lightpos = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ *dir = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
+
+ /* Check whether portal is on the right side. */
+ if (dot(*dir, P - *lightpos) > 1e-4f)
+ return true;
+
+ return false;
+}
+
+ccl_device_inline float background_portal_pdf(
+ KernelGlobals kg, float3 P, float3 direction, int ignore_portal, ccl_private bool *is_possible)
+{
+ float portal_pdf = 0.0f;
+
+ int num_possible = 0;
+ for (int p = 0; p < kernel_data.background.num_portals; p++) {
+ if (p == ignore_portal)
+ continue;
+
+ float3 lightpos, dir;
+ if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
+ continue;
+
+ /* There's a portal that could be sampled from this position. */
+ if (is_possible) {
+ *is_possible = true;
+ }
+ num_possible++;
+
+ int portal = kernel_data.background.portal_offset + p;
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+ float3 axisu = make_float3(
+ klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+ float3 axisv = make_float3(
+ klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
+ bool is_round = (klight->area.invarea < 0.0f);
+
+ if (!ray_quad_intersect(P,
+ direction,
+ 1e-4f,
+ FLT_MAX,
+ lightpos,
+ axisu,
+ axisv,
+ dir,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ is_round))
+ continue;
+
+ if (is_round) {
+ float t;
+ float3 D = normalize_len(lightpos - P, &t);
+ portal_pdf += fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t);
+ }
+ else {
+ portal_pdf += rect_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false);
+ }
+ }
+
+ if (ignore_portal >= 0) {
+ /* We have skipped a portal that could be sampled as well. */
+ num_possible++;
+ }
+
+ return (num_possible > 0) ? portal_pdf / num_possible : 0.0f;
+}
+
+ccl_device int background_num_possible_portals(KernelGlobals kg, float3 P)
+{
+ int num_possible_portals = 0;
+ for (int p = 0; p < kernel_data.background.num_portals; p++) {
+ float3 lightpos, dir;
+ if (background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
+ num_possible_portals++;
+ }
+ return num_possible_portals;
+}
+
+ccl_device float3 background_portal_sample(KernelGlobals kg,
+ float3 P,
+ float randu,
+ float randv,
+ int num_possible,
+ ccl_private int *sampled_portal,
+ ccl_private float *pdf)
+{
+ /* Pick a portal, then re-normalize randv. */
+ randv *= num_possible;
+ int portal = (int)randv;
+ randv -= portal;
+
+ /* TODO(sergey): Some smarter way of finding portal to sample
+ * is welcome.
+ */
+ for (int p = 0; p < kernel_data.background.num_portals; p++) {
+ /* Search for the sampled portal. */
+ float3 lightpos, dir;
+ if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
+ continue;
+
+ if (portal == 0) {
+ /* p is the portal to be sampled. */
+ int portal = kernel_data.background.portal_offset + p;
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+ float3 axisu = make_float3(
+ klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+ float3 axisv = make_float3(
+ klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
+ bool is_round = (klight->area.invarea < 0.0f);
+
+ float3 D;
+ if (is_round) {
+ lightpos += ellipse_sample(axisu * 0.5f, axisv * 0.5f, randu, randv);
+ float t;
+ D = normalize_len(lightpos - P, &t);
+ *pdf = fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t);
+ }
+ else {
+ *pdf = rect_light_sample(P, &lightpos, axisu, axisv, randu, randv, true);
+ D = normalize(lightpos - P);
+ }
+
+ *pdf /= num_possible;
+ *sampled_portal = p;
+ return D;
+ }
+
+ portal--;
+ }
+
+ return zero_float3();
+}
+
+ccl_device_inline float3 background_sun_sample(KernelGlobals kg,
+ float randu,
+ float randv,
+ ccl_private float *pdf)
+{
+ float3 D;
+ const float3 N = float4_to_float3(kernel_data.background.sun);
+ const float angle = kernel_data.background.sun.w;
+ sample_uniform_cone(N, angle, randu, randv, &D, pdf);
+ return D;
+}
+
+ccl_device_inline float background_sun_pdf(KernelGlobals kg, float3 D)
+{
+ const float3 N = float4_to_float3(kernel_data.background.sun);
+ const float angle = kernel_data.background.sun.w;
+ return pdf_uniform_cone(N, D, angle);
+}
+
+ccl_device_inline float3 background_light_sample(
+ KernelGlobals kg, float3 P, float randu, float randv, ccl_private float *pdf)
+{
+ float portal_method_pdf = kernel_data.background.portal_weight;
+ float sun_method_pdf = kernel_data.background.sun_weight;
+ float map_method_pdf = kernel_data.background.map_weight;
+
+ int num_portals = 0;
+ if (portal_method_pdf > 0.0f) {
+ /* Check if there are portals in the scene which we can sample. */
+ num_portals = background_num_possible_portals(kg, P);
+ if (num_portals == 0) {
+ portal_method_pdf = 0.0f;
+ }
+ }
+
+ float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf);
+ if (pdf_fac == 0.0f) {
+ /* Use uniform as a fallback if we can't use any strategy. */
+ *pdf = 1.0f / M_4PI_F;
+ return sample_uniform_sphere(randu, randv);
+ }
+
+ pdf_fac = 1.0f / pdf_fac;
+ portal_method_pdf *= pdf_fac;
+ sun_method_pdf *= pdf_fac;
+ map_method_pdf *= pdf_fac;
+
+ /* We have 100% in total and split it between the three categories.
+ * Therefore, we pick portals if randu is between 0 and portal_method_pdf,
+ * sun if randu is between portal_method_pdf and (portal_method_pdf + sun_method_pdf)
+ * and map if randu is between (portal_method_pdf + sun_method_pdf) and 1. */
+ float sun_method_cdf = portal_method_pdf + sun_method_pdf;
+
+ int method = 0;
+ float3 D;
+ if (randu < portal_method_pdf) {
+ method = 0;
+ /* Rescale randu. */
+ if (portal_method_pdf != 1.0f) {
+ randu /= portal_method_pdf;
+ }
+
+ /* Sample a portal. */
+ int portal;
+ D = background_portal_sample(kg, P, randu, randv, num_portals, &portal, pdf);
+ if (num_portals > 1) {
+ /* Ignore the chosen portal, its pdf is already included. */
+ *pdf += background_portal_pdf(kg, P, D, portal, NULL);
+ }
+
+ /* Skip MIS if this is the only method. */
+ if (portal_method_pdf == 1.0f) {
+ return D;
+ }
+ *pdf *= portal_method_pdf;
+ }
+ else if (randu < sun_method_cdf) {
+ method = 1;
+ /* Rescale randu. */
+ if (sun_method_pdf != 1.0f) {
+ randu = (randu - portal_method_pdf) / sun_method_pdf;
+ }
+
+ D = background_sun_sample(kg, randu, randv, pdf);
+
+ /* Skip MIS if this is the only method. */
+ if (sun_method_pdf == 1.0f) {
+ return D;
+ }
+ *pdf *= sun_method_pdf;
+ }
+ else {
+ method = 2;
+ /* Rescale randu. */
+ if (map_method_pdf != 1.0f) {
+ randu = (randu - sun_method_cdf) / map_method_pdf;
+ }
+
+ D = background_map_sample(kg, randu, randv, pdf);
+
+ /* Skip MIS if this is the only method. */
+ if (map_method_pdf == 1.0f) {
+ return D;
+ }
+ *pdf *= map_method_pdf;
+ }
+
+ /* MIS weighting. */
+ if (method != 0 && portal_method_pdf != 0.0f) {
+ *pdf += portal_method_pdf * background_portal_pdf(kg, P, D, -1, NULL);
+ }
+ if (method != 1 && sun_method_pdf != 0.0f) {
+ *pdf += sun_method_pdf * background_sun_pdf(kg, D);
+ }
+ if (method != 2 && map_method_pdf != 0.0f) {
+ *pdf += map_method_pdf * background_map_pdf(kg, D);
+ }
+ return D;
+}
+
+ccl_device float background_light_pdf(KernelGlobals kg, float3 P, float3 direction)
+{
+ float portal_method_pdf = kernel_data.background.portal_weight;
+ float sun_method_pdf = kernel_data.background.sun_weight;
+ float map_method_pdf = kernel_data.background.map_weight;
+
+ float portal_pdf = 0.0f;
+ /* Portals are a special case here since we need to compute their pdf in order
+ * to find out if we can sample them. */
+ if (portal_method_pdf > 0.0f) {
+ /* Evaluate PDF of sampling this direction by portal sampling. */
+ bool is_possible = false;
+ portal_pdf = background_portal_pdf(kg, P, direction, -1, &is_possible);
+ if (!is_possible) {
+ /* Portal sampling is not possible here because all portals point to the wrong side.
+ * If other methods can be used instead, do so, otherwise uniform sampling is used as a
+ * fallback. */
+ portal_method_pdf = 0.0f;
+ }
+ }
+
+ float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf);
+ if (pdf_fac == 0.0f) {
+ /* Use uniform as a fallback if we can't use any strategy. */
+ return kernel_data.integrator.pdf_lights / M_4PI_F;
+ }
+
+ pdf_fac = 1.0f / pdf_fac;
+ portal_method_pdf *= pdf_fac;
+ sun_method_pdf *= pdf_fac;
+ map_method_pdf *= pdf_fac;
+
+ float pdf = portal_pdf * portal_method_pdf;
+ if (sun_method_pdf != 0.0f) {
+ pdf += background_sun_pdf(kg, direction) * sun_method_pdf;
+ }
+ if (map_method_pdf != 0.0f) {
+ pdf += background_map_pdf(kg, direction) * map_method_pdf;
+ }
+
+ return pdf * kernel_data.integrator.pdf_lights;
+}
+
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/light/common.h b/intern/cycles/kernel/light/common.h
new file mode 100644
index 00000000000..75331d32d44
--- /dev/null
+++ b/intern/cycles/kernel/light/common.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/sample/mapping.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Area light sampling */
+
+/* Uses the following paper:
+ *
+ * Carlos Urena et al.
+ * An Area-Preserving Parametrization for Spherical Rectangles.
+ *
+ * https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf
+ *
+ * Note: light_p is modified when sample_coord is true.
+ */
+ccl_device_inline float rect_light_sample(float3 P,
+ ccl_private float3 *light_p,
+ float3 axisu,
+ float3 axisv,
+ float randu,
+ float randv,
+ bool sample_coord)
+{
+ /* In our name system we're using P for the center,
+ * which is o in the paper.
+ */
+
+ float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f;
+ float axisu_len, axisv_len;
+ /* Compute local reference system R. */
+ float3 x = normalize_len(axisu, &axisu_len);
+ float3 y = normalize_len(axisv, &axisv_len);
+ float3 z = cross(x, y);
+ /* Compute rectangle coords in local reference system. */
+ float3 dir = corner - P;
+ float z0 = dot(dir, z);
+ /* Flip 'z' to make it point against Q. */
+ if (z0 > 0.0f) {
+ z *= -1.0f;
+ z0 *= -1.0f;
+ }
+ float x0 = dot(dir, x);
+ float y0 = dot(dir, y);
+ float x1 = x0 + axisu_len;
+ float y1 = y0 + axisv_len;
+ /* Compute internal angles (gamma_i). */
+ float4 diff = make_float4(x0, y1, x1, y0) - make_float4(x1, y0, x0, y1);
+ float4 nz = make_float4(y0, x1, y1, x0) * diff;
+ nz = nz / sqrt(z0 * z0 * diff * diff + nz * nz);
+ float g0 = safe_acosf(-nz.x * nz.y);
+ float g1 = safe_acosf(-nz.y * nz.z);
+ float g2 = safe_acosf(-nz.z * nz.w);
+ float g3 = safe_acosf(-nz.w * nz.x);
+ /* Compute predefined constants. */
+ float b0 = nz.x;
+ float b1 = nz.z;
+ float b0sq = b0 * b0;
+ float k = M_2PI_F - g2 - g3;
+ /* Compute solid angle from internal angles. */
+ float S = g0 + g1 - k;
+
+ if (sample_coord) {
+ /* Compute cu. */
+ float au = randu * S + k;
+ float fu = (cosf(au) * b0 - b1) / sinf(au);
+ float cu = 1.0f / sqrtf(fu * fu + b0sq) * (fu > 0.0f ? 1.0f : -1.0f);
+ cu = clamp(cu, -1.0f, 1.0f);
+ /* Compute xu. */
+ float xu = -(cu * z0) / max(sqrtf(1.0f - cu * cu), 1e-7f);
+ xu = clamp(xu, x0, x1);
+ /* Compute yv. */
+ float z0sq = z0 * z0;
+ float y0sq = y0 * y0;
+ float y1sq = y1 * y1;
+ float d = sqrtf(xu * xu + z0sq);
+ float h0 = y0 / sqrtf(d * d + y0sq);
+ float h1 = y1 / sqrtf(d * d + y1sq);
+ float hv = h0 + randv * (h1 - h0), hv2 = hv * hv;
+ float yv = (hv2 < 1.0f - 1e-6f) ? (hv * d) / sqrtf(1.0f - hv2) : y1;
+
+ /* Transform (xu, yv, z0) to world coords. */
+ *light_p = P + xu * x + yv * y + z0 * z;
+ }
+
+ /* return pdf */
+ if (S != 0.0f)
+ return 1.0f / S;
+ else
+ return 0.0f;
+}
+
+ccl_device_inline float3 ellipse_sample(float3 ru, float3 rv, float randu, float randv)
+{
+ to_unit_disk(&randu, &randv);
+ return ru * randu + rv * randv;
+}
+
+ccl_device float3 disk_light_sample(float3 v, float randu, float randv)
+{
+ float3 ru, rv;
+
+ make_orthonormals(v, &ru, &rv);
+
+ return ellipse_sample(ru, rv, randu, randv);
+}
+
+ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv)
+{
+ return normalize(D + disk_light_sample(D, randu, randv) * radius);
+}
+
+ccl_device float3
+sphere_light_sample(float3 P, float3 center, float radius, float randu, float randv)
+{
+ return disk_light_sample(normalize(P - center), randu, randv) * radius;
+}
+
+ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, float3 N)
+{
+ float attenuation = dot(dir, N);
+
+ if (attenuation <= spot_angle) {
+ attenuation = 0.0f;
+ }
+ else {
+ float t = attenuation - spot_angle;
+
+ if (t < spot_smooth && spot_smooth != 0.0f)
+ attenuation *= smoothstepf(t / spot_smooth);
+ }
+
+ return attenuation;
+}
+
+ccl_device float light_spread_attenuation(const float3 D,
+ const float3 lightNg,
+ const float tan_spread,
+ const float normalize_spread)
+{
+ /* Model a soft-box grid, computing the ratio of light not hidden by the
+ * slats of the grid at a given angle. (see D10594). */
+ const float cos_a = -dot(D, lightNg);
+ const float sin_a = safe_sqrtf(1.0f - sqr(cos_a));
+ const float tan_a = sin_a / cos_a;
+ return max((1.0f - (tan_spread * tan_a)) * normalize_spread, 0.0f);
+}
+
+/* Compute subset of area light that actually has an influence on the shading point, to
+ * reduce noise with low spread. */
+ccl_device bool light_spread_clamp_area_light(const float3 P,
+ const float3 lightNg,
+ ccl_private float3 *lightP,
+ ccl_private float3 *axisu,
+ ccl_private float3 *axisv,
+ const float tan_spread)
+{
+ /* Closest point in area light plane and distance to that plane. */
+ const float3 closest_P = P - dot(lightNg, P - *lightP) * lightNg;
+ const float t = len(closest_P - P);
+
+ /* Radius of circle on area light that actually affects the shading point. */
+ const float radius = t / tan_spread;
+
+ /* TODO: would be faster to store as normalized vector + length, also in rect_light_sample. */
+ float len_u, len_v;
+ const float3 u = normalize_len(*axisu, &len_u);
+ const float3 v = normalize_len(*axisv, &len_v);
+
+ /* Local uv coordinates of closest point. */
+ const float closest_u = dot(u, closest_P - *lightP);
+ const float closest_v = dot(v, closest_P - *lightP);
+
+ /* Compute rectangle encompassing the circle that affects the shading point,
+ * clamped to the bounds of the area light. */
+ const float min_u = max(closest_u - radius, -len_u * 0.5f);
+ const float max_u = min(closest_u + radius, len_u * 0.5f);
+ const float min_v = max(closest_v - radius, -len_v * 0.5f);
+ const float max_v = min(closest_v + radius, len_v * 0.5f);
+
+ /* Skip if rectangle is empty. */
+ if (min_u >= max_u || min_v >= max_v) {
+ return false;
+ }
+
+ /* Compute new area light center position and axes from rectangle in local
+ * uv coordinates. */
+ const float new_center_u = 0.5f * (min_u + max_u);
+ const float new_center_v = 0.5f * (min_v + max_v);
+ const float new_len_u = max_u - min_u;
+ const float new_len_v = max_v - min_v;
+
+ *lightP = *lightP + new_center_u * u + new_center_v * v;
+ *axisu = u * new_len_u;
+ *axisv = v * new_len_v;
+
+ return true;
+}
+
+ccl_device float lamp_light_pdf(KernelGlobals kg, const float3 Ng, const float3 I, float t)
+{
+ float cos_pi = dot(Ng, I);
+
+ if (cos_pi <= 0.0f)
+ return 0.0f;
+
+ return t * t / cos_pi;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h
new file mode 100644
index 00000000000..746c7747569
--- /dev/null
+++ b/intern/cycles/kernel/light/light.h
@@ -0,0 +1,872 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/geom/geom.h"
+#include "kernel/light/background.h"
+#include "kernel/sample/mapping.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Light Sample result */
+
+typedef struct LightSample {
+ float3 P; /* position on light, or direction for distant light */
+ float3 Ng; /* normal on light */
+ float3 D; /* direction from shading point to light */
+ float t; /* distance to light (FLT_MAX for distant light) */
+ float u, v; /* parametric coordinate on primitive */
+ float pdf; /* light sampling probability density function */
+ float eval_fac; /* intensity multiplier */
+ int object; /* object id for triangle/curve lights */
+ int prim; /* primitive id for triangle/curve lights */
+ int shader; /* shader id */
+ int lamp; /* lamp id */
+ LightType type; /* type of light */
+} LightSample;
+
+/* Regular Light */
+
+template<bool in_volume_segment>
+ccl_device_inline bool light_sample(KernelGlobals kg,
+ const int lamp,
+ const float randu,
+ const float randv,
+ const float3 P,
+ const uint32_t path_flag,
+ ccl_private LightSample *ls)
+{
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
+ if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) {
+ return false;
+ }
+ }
+
+ LightType type = (LightType)klight->type;
+ ls->type = type;
+ ls->shader = klight->shader_id;
+ ls->object = PRIM_NONE;
+ ls->prim = PRIM_NONE;
+ ls->lamp = lamp;
+ ls->u = randu;
+ ls->v = randv;
+
+ if (in_volume_segment && (type == LIGHT_DISTANT || type == LIGHT_BACKGROUND)) {
+ /* Distant lights in a volume get a dummy sample, position will not actually
+ * be used in that case. Only when sampling from a specific scatter position
+ * do we actually need to evaluate these. */
+ ls->P = zero_float3();
+ ls->Ng = zero_float3();
+ ls->D = zero_float3();
+ ls->pdf = true;
+ ls->t = FLT_MAX;
+ return true;
+ }
+
+ if (type == LIGHT_DISTANT) {
+ /* distant light */
+ float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ float3 D = lightD;
+ float radius = klight->distant.radius;
+ float invarea = klight->distant.invarea;
+
+ if (radius > 0.0f)
+ D = distant_light_sample(D, radius, randu, randv);
+
+ ls->P = D;
+ ls->Ng = D;
+ ls->D = -D;
+ ls->t = FLT_MAX;
+
+ float costheta = dot(lightD, D);
+ ls->pdf = invarea / (costheta * costheta * costheta);
+ ls->eval_fac = ls->pdf;
+ }
+#ifdef __BACKGROUND_MIS__
+ else if (type == LIGHT_BACKGROUND) {
+ /* infinite area light (e.g. light dome or env light) */
+ float3 D = -background_light_sample(kg, P, randu, randv, &ls->pdf);
+
+ ls->P = D;
+ ls->Ng = D;
+ ls->D = -D;
+ ls->t = FLT_MAX;
+ ls->eval_fac = 1.0f;
+ }
+#endif
+ else {
+ ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+
+ if (type == LIGHT_POINT || type == LIGHT_SPOT) {
+ float radius = klight->spot.radius;
+
+ if (radius > 0.0f)
+ /* sphere light */
+ ls->P += sphere_light_sample(P, ls->P, radius, randu, randv);
+
+ ls->D = normalize_len(ls->P - P, &ls->t);
+ ls->Ng = -ls->D;
+
+ float invarea = klight->spot.invarea;
+ ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
+ ls->pdf = invarea;
+
+ if (type == LIGHT_SPOT) {
+ /* spot light attenuation */
+ float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
+ ls->eval_fac *= spot_light_attenuation(
+ dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng);
+ if (ls->eval_fac == 0.0f) {
+ return false;
+ }
+ }
+ float2 uv = map_to_sphere(ls->Ng);
+ ls->u = uv.x;
+ ls->v = uv.y;
+
+ ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
+ }
+ else {
+ /* area light */
+ float3 axisu = make_float3(
+ klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+ float3 axisv = make_float3(
+ klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
+ float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
+ float invarea = fabsf(klight->area.invarea);
+ bool is_round = (klight->area.invarea < 0.0f);
+
+ if (!in_volume_segment) {
+ if (dot(ls->P - P, Ng) > 0.0f) {
+ return false;
+ }
+ }
+
+ float3 inplane;
+
+ if (is_round || in_volume_segment) {
+ inplane = ellipse_sample(axisu * 0.5f, axisv * 0.5f, randu, randv);
+ ls->P += inplane;
+ ls->pdf = invarea;
+ }
+ else {
+ inplane = ls->P;
+
+ float3 sample_axisu = axisu;
+ float3 sample_axisv = axisv;
+
+ if (klight->area.tan_spread > 0.0f) {
+ if (!light_spread_clamp_area_light(
+ P, Ng, &ls->P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
+ return false;
+ }
+ }
+
+ ls->pdf = rect_light_sample(P, &ls->P, sample_axisu, sample_axisv, randu, randv, true);
+ inplane = ls->P - inplane;
+ }
+
+ ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f;
+ ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f;
+
+ ls->Ng = Ng;
+ ls->D = normalize_len(ls->P - P, &ls->t);
+
+ ls->eval_fac = 0.25f * invarea;
+
+ if (klight->area.tan_spread > 0.0f) {
+ /* Area Light spread angle attenuation */
+ ls->eval_fac *= light_spread_attenuation(
+ ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
+ }
+
+ if (is_round) {
+ ls->pdf *= lamp_light_pdf(kg, Ng, -ls->D, ls->t);
+ }
+ }
+ }
+
+ ls->pdf *= kernel_data.integrator.pdf_lights;
+
+ return (ls->pdf > 0.0f);
+}
+
+ccl_device bool lights_intersect(KernelGlobals kg,
+ ccl_private const Ray *ccl_restrict ray,
+ ccl_private Intersection *ccl_restrict isect,
+ const int last_prim,
+ const int last_object,
+ const int last_type,
+ const uint32_t path_flag)
+{
+ for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) {
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+
+ if (path_flag & PATH_RAY_CAMERA) {
+ if (klight->shader_id & SHADER_EXCLUDE_CAMERA) {
+ continue;
+ }
+ }
+ else {
+ if (!(klight->shader_id & SHADER_USE_MIS)) {
+ continue;
+ }
+ }
+
+ if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
+ if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) {
+ continue;
+ }
+ }
+
+ LightType type = (LightType)klight->type;
+ float t = 0.0f, u = 0.0f, v = 0.0f;
+
+ if (type == LIGHT_POINT || type == LIGHT_SPOT) {
+ /* Sphere light. */
+ const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ const float radius = klight->spot.radius;
+ if (radius == 0.0f) {
+ continue;
+ }
+
+ float3 P;
+ if (!ray_aligned_disk_intersect(ray->P, ray->D, ray->t, lightP, radius, &P, &t)) {
+ continue;
+ }
+ }
+ else if (type == LIGHT_AREA) {
+ /* Area light. */
+ const float invarea = fabsf(klight->area.invarea);
+ const bool is_round = (klight->area.invarea < 0.0f);
+ if (invarea == 0.0f) {
+ continue;
+ }
+
+ const float3 axisu = make_float3(
+ klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+ const float3 axisv = make_float3(
+ klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
+ const float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
+
+ /* One sided. */
+ if (dot(ray->D, Ng) >= 0.0f) {
+ continue;
+ }
+
+ const float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+
+ float3 P;
+ if (!ray_quad_intersect(
+ ray->P, ray->D, 0.0f, ray->t, light_P, axisu, axisv, Ng, &P, &t, &u, &v, is_round)) {
+ continue;
+ }
+ }
+ else {
+ continue;
+ }
+
+ if (t < isect->t &&
+ !(last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP)) {
+ isect->t = t;
+ isect->u = u;
+ isect->v = v;
+ isect->type = PRIMITIVE_LAMP;
+ isect->prim = lamp;
+ isect->object = OBJECT_NONE;
+ }
+ }
+
+ return isect->prim != PRIM_NONE;
+}
+
+ccl_device bool light_sample_from_distant_ray(KernelGlobals kg,
+ const float3 ray_D,
+ const int lamp,
+ ccl_private LightSample *ccl_restrict ls)
+{
+ ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ const int shader = klight->shader_id;
+ const float radius = klight->distant.radius;
+ const LightType type = (LightType)klight->type;
+
+ if (type != LIGHT_DISTANT) {
+ return false;
+ }
+ if (!(shader & SHADER_USE_MIS)) {
+ return false;
+ }
+ if (radius == 0.0f) {
+ return false;
+ }
+
+ /* a distant light is infinitely far away, but equivalent to a disk
+ * shaped light exactly 1 unit away from the current shading point.
+ *
+ * radius t^2/cos(theta)
+ * <----------> t = sqrt(1^2 + tan(theta)^2)
+ * tan(th) area = radius*radius*pi
+ * <----->
+ * \ | (1 + tan(theta)^2)/cos(theta)
+ * \ | (1 + tan(acos(cos(theta)))^2)/cos(theta)
+ * t \th| 1 simplifies to
+ * \-| 1/(cos(theta)^3)
+ * \| magic!
+ * P
+ */
+
+ float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ float costheta = dot(-lightD, ray_D);
+ float cosangle = klight->distant.cosangle;
+
+ if (costheta < cosangle)
+ return false;
+
+ ls->type = type;
+ ls->shader = klight->shader_id;
+ ls->object = PRIM_NONE;
+ ls->prim = PRIM_NONE;
+ ls->lamp = lamp;
+ /* todo: missing texture coordinates */
+ ls->u = 0.0f;
+ ls->v = 0.0f;
+ ls->t = FLT_MAX;
+ ls->P = -ray_D;
+ ls->Ng = -ray_D;
+ ls->D = ray_D;
+
+ /* compute pdf */
+ float invarea = klight->distant.invarea;
+ ls->pdf = invarea / (costheta * costheta * costheta);
+ ls->pdf *= kernel_data.integrator.pdf_lights;
+ ls->eval_fac = ls->pdf;
+
+ return true;
+}
+
+ccl_device bool light_sample_from_intersection(KernelGlobals kg,
+ ccl_private const Intersection *ccl_restrict isect,
+ const float3 ray_P,
+ const float3 ray_D,
+ ccl_private LightSample *ccl_restrict ls)
+{
+ const int lamp = isect->prim;
+ ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ LightType type = (LightType)klight->type;
+ ls->type = type;
+ ls->shader = klight->shader_id;
+ ls->object = PRIM_NONE;
+ ls->prim = PRIM_NONE;
+ ls->lamp = lamp;
+ /* todo: missing texture coordinates */
+ ls->t = isect->t;
+ ls->P = ray_P + ray_D * ls->t;
+ ls->D = ray_D;
+
+ if (type == LIGHT_POINT || type == LIGHT_SPOT) {
+ ls->Ng = -ray_D;
+
+ float invarea = klight->spot.invarea;
+ ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
+ ls->pdf = invarea;
+
+ if (type == LIGHT_SPOT) {
+ /* spot light attenuation */
+ float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
+ ls->eval_fac *= spot_light_attenuation(
+ dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng);
+
+ if (ls->eval_fac == 0.0f) {
+ return false;
+ }
+ }
+ float2 uv = map_to_sphere(ls->Ng);
+ ls->u = uv.x;
+ ls->v = uv.y;
+
+ /* compute pdf */
+ if (ls->t != FLT_MAX)
+ ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
+ }
+ else if (type == LIGHT_AREA) {
+ /* area light */
+ float invarea = fabsf(klight->area.invarea);
+
+ float3 axisu = make_float3(
+ klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+ float3 axisv = make_float3(
+ klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
+ float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
+ float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+
+ ls->u = isect->u;
+ ls->v = isect->v;
+ ls->D = ray_D;
+ ls->Ng = Ng;
+
+ const bool is_round = (klight->area.invarea < 0.0f);
+ if (is_round) {
+ ls->pdf = invarea * lamp_light_pdf(kg, Ng, -ray_D, ls->t);
+ }
+ else {
+ float3 sample_axisu = axisu;
+ float3 sample_axisv = axisv;
+
+ if (klight->area.tan_spread > 0.0f) {
+ if (!light_spread_clamp_area_light(
+ ray_P, Ng, &light_P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
+ return false;
+ }
+ }
+
+ ls->pdf = rect_light_sample(ray_P, &light_P, sample_axisu, sample_axisv, 0, 0, false);
+ }
+ ls->eval_fac = 0.25f * invarea;
+
+ if (klight->area.tan_spread > 0.0f) {
+ /* Area Light spread angle attenuation */
+ ls->eval_fac *= light_spread_attenuation(
+ ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
+ if (ls->eval_fac == 0.0f) {
+ return false;
+ }
+ }
+ }
+ else {
+ kernel_assert(!"Invalid lamp type in light_sample_from_intersection");
+ return false;
+ }
+
+ ls->pdf *= kernel_data.integrator.pdf_lights;
+
+ return true;
+}
+
+/* Triangle Light */
+
+/* returns true if the triangle is has motion blur or an instancing transform applied */
+ccl_device_inline bool triangle_world_space_vertices(
+ KernelGlobals kg, int object, int prim, float time, float3 V[3])
+{
+ bool has_motion = false;
+ const int object_flag = kernel_tex_fetch(__object_flag, object);
+
+ if (object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) {
+ motion_triangle_vertices(kg, object, prim, time, V);
+ has_motion = true;
+ }
+ else {
+ triangle_vertices(kg, prim, V);
+ }
+
+ if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+#ifdef __OBJECT_MOTION__
+ float object_time = (time >= 0.0f) ? time : 0.5f;
+ Transform tfm = object_fetch_transform_motion_test(kg, object, object_time, NULL);
+#else
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+#endif
+ V[0] = transform_point(&tfm, V[0]);
+ V[1] = transform_point(&tfm, V[1]);
+ V[2] = transform_point(&tfm, V[2]);
+ has_motion = true;
+ }
+ return has_motion;
+}
+
+ccl_device_inline float triangle_light_pdf_area(KernelGlobals kg,
+ const float3 Ng,
+ const float3 I,
+ float t)
+{
+ float pdf = kernel_data.integrator.pdf_triangles;
+ float cos_pi = fabsf(dot(Ng, I));
+
+ if (cos_pi == 0.0f)
+ return 0.0f;
+
+ return t * t * pdf / cos_pi;
+}
+
+ccl_device_forceinline float triangle_light_pdf(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ float t)
+{
+ /* A naive heuristic to decide between costly solid angle sampling
+ * and simple area sampling, comparing the distance to the triangle plane
+ * to the length of the edges of the triangle. */
+
+ float3 V[3];
+ bool has_motion = triangle_world_space_vertices(kg, sd->object, sd->prim, sd->time, V);
+
+ const float3 e0 = V[1] - V[0];
+ const float3 e1 = V[2] - V[0];
+ const float3 e2 = V[2] - V[1];
+ const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2)));
+ const float3 N = cross(e0, e1);
+ const float distance_to_plane = fabsf(dot(N, sd->I * t)) / dot(N, N);
+
+ if (longest_edge_squared > distance_to_plane * distance_to_plane) {
+ /* sd contains the point on the light source
+ * calculate Px, the point that we're shading */
+ const float3 Px = sd->P + sd->I * t;
+ const float3 v0_p = V[0] - Px;
+ const float3 v1_p = V[1] - Px;
+ const float3 v2_p = V[2] - Px;
+
+ const float3 u01 = safe_normalize(cross(v0_p, v1_p));
+ const float3 u02 = safe_normalize(cross(v0_p, v2_p));
+ const float3 u12 = safe_normalize(cross(v1_p, v2_p));
+
+ const float alpha = fast_acosf(dot(u02, u01));
+ const float beta = fast_acosf(-dot(u01, u12));
+ const float gamma = fast_acosf(dot(u02, u12));
+ const float solid_angle = alpha + beta + gamma - M_PI_F;
+
+ /* pdf_triangles is calculated over triangle area, but we're not sampling over its area */
+ if (UNLIKELY(solid_angle == 0.0f)) {
+ return 0.0f;
+ }
+ else {
+ float area = 1.0f;
+ if (has_motion) {
+ /* get the center frame vertices, this is what the PDF was calculated from */
+ triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V);
+ area = triangle_area(V[0], V[1], V[2]);
+ }
+ else {
+ area = 0.5f * len(N);
+ }
+ const float pdf = area * kernel_data.integrator.pdf_triangles;
+ return pdf / solid_angle;
+ }
+ }
+ else {
+ float pdf = triangle_light_pdf_area(kg, sd->Ng, sd->I, t);
+ if (has_motion) {
+ const float area = 0.5f * len(N);
+ if (UNLIKELY(area == 0.0f)) {
+ return 0.0f;
+ }
+ /* scale the PDF.
+ * area = the area the sample was taken from
+ * area_pre = the are from which pdf_triangles was calculated from */
+ triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V);
+ const float area_pre = triangle_area(V[0], V[1], V[2]);
+ pdf = pdf * area_pre / area;
+ }
+ return pdf;
+ }
+}
+
+template<bool in_volume_segment>
+ccl_device_forceinline void triangle_light_sample(KernelGlobals kg,
+ int prim,
+ int object,
+ float randu,
+ float randv,
+ float time,
+ ccl_private LightSample *ls,
+ const float3 P)
+{
+ /* A naive heuristic to decide between costly solid angle sampling
+ * and simple area sampling, comparing the distance to the triangle plane
+ * to the length of the edges of the triangle. */
+
+ float3 V[3];
+ bool has_motion = triangle_world_space_vertices(kg, object, prim, time, V);
+
+ const float3 e0 = V[1] - V[0];
+ const float3 e1 = V[2] - V[0];
+ const float3 e2 = V[2] - V[1];
+ const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2)));
+ const float3 N0 = cross(e0, e1);
+ float Nl = 0.0f;
+ ls->Ng = safe_normalize_len(N0, &Nl);
+ float area = 0.5f * Nl;
+
+ /* flip normal if necessary */
+ const int object_flag = kernel_tex_fetch(__object_flag, object);
+ if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+ ls->Ng = -ls->Ng;
+ }
+ ls->eval_fac = 1.0f;
+ ls->shader = kernel_tex_fetch(__tri_shader, prim);
+ ls->object = object;
+ ls->prim = prim;
+ ls->lamp = LAMP_NONE;
+ ls->shader |= SHADER_USE_MIS;
+ ls->type = LIGHT_TRIANGLE;
+
+ float distance_to_plane = fabsf(dot(N0, V[0] - P) / dot(N0, N0));
+
+ if (!in_volume_segment && (longest_edge_squared > distance_to_plane * distance_to_plane)) {
+ /* see James Arvo, "Stratified Sampling of Spherical Triangles"
+ * http://www.graphics.cornell.edu/pubs/1995/Arv95c.pdf */
+
+ /* project the triangle to the unit sphere
+ * and calculate its edges and angles */
+ const float3 v0_p = V[0] - P;
+ const float3 v1_p = V[1] - P;
+ const float3 v2_p = V[2] - P;
+
+ const float3 u01 = safe_normalize(cross(v0_p, v1_p));
+ const float3 u02 = safe_normalize(cross(v0_p, v2_p));
+ const float3 u12 = safe_normalize(cross(v1_p, v2_p));
+
+ const float3 A = safe_normalize(v0_p);
+ const float3 B = safe_normalize(v1_p);
+ const float3 C = safe_normalize(v2_p);
+
+ const float cos_alpha = dot(u02, u01);
+ const float cos_beta = -dot(u01, u12);
+ const float cos_gamma = dot(u02, u12);
+
+ /* calculate dihedral angles */
+ const float alpha = fast_acosf(cos_alpha);
+ const float beta = fast_acosf(cos_beta);
+ const float gamma = fast_acosf(cos_gamma);
+ /* the area of the unit spherical triangle = solid angle */
+ const float solid_angle = alpha + beta + gamma - M_PI_F;
+
+ /* precompute a few things
+ * these could be re-used to take several samples
+ * as they are independent of randu/randv */
+ const float cos_c = dot(A, B);
+ const float sin_alpha = fast_sinf(alpha);
+ const float product = sin_alpha * cos_c;
+
+ /* Select a random sub-area of the spherical triangle
+ * and calculate the third vertex C_ of that new triangle */
+ const float phi = randu * solid_angle - alpha;
+ float s, t;
+ fast_sincosf(phi, &s, &t);
+ const float u = t - cos_alpha;
+ const float v = s + product;
+
+ const float3 U = safe_normalize(C - dot(C, A) * A);
+
+ float q = 1.0f;
+ const float det = ((v * s + u * t) * sin_alpha);
+ if (det != 0.0f) {
+ q = ((v * t - u * s) * cos_alpha - v) / det;
+ }
+ const float temp = max(1.0f - q * q, 0.0f);
+
+ const float3 C_ = safe_normalize(q * A + sqrtf(temp) * U);
+
+ /* Finally, select a random point along the edge of the new triangle
+ * That point on the spherical triangle is the sampled ray direction */
+ const float z = 1.0f - randv * (1.0f - dot(C_, B));
+ ls->D = z * B + safe_sqrtf(1.0f - z * z) * safe_normalize(C_ - dot(C_, B) * B);
+
+ /* calculate intersection with the planar triangle */
+ if (!ray_triangle_intersect(P,
+ ls->D,
+ FLT_MAX,
+#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
+ (ssef *)V,
+#else
+ V[0],
+ V[1],
+ V[2],
+#endif
+ &ls->u,
+ &ls->v,
+ &ls->t)) {
+ ls->pdf = 0.0f;
+ return;
+ }
+
+ ls->P = P + ls->D * ls->t;
+
+ /* pdf_triangles is calculated over triangle area, but we're sampling over solid angle */
+ if (UNLIKELY(solid_angle == 0.0f)) {
+ ls->pdf = 0.0f;
+ return;
+ }
+ else {
+ if (has_motion) {
+ /* get the center frame vertices, this is what the PDF was calculated from */
+ triangle_world_space_vertices(kg, object, prim, -1.0f, V);
+ area = triangle_area(V[0], V[1], V[2]);
+ }
+ const float pdf = area * kernel_data.integrator.pdf_triangles;
+ ls->pdf = pdf / solid_angle;
+ }
+ }
+ else {
+ /* compute random point in triangle. From Eric Heitz's "A Low-Distortion Map Between Triangle
+ * and Square" */
+ float u = randu;
+ float v = randv;
+ if (v > u) {
+ u *= 0.5f;
+ v -= u;
+ }
+ else {
+ v *= 0.5f;
+ u -= v;
+ }
+
+ const float t = 1.0f - u - v;
+ ls->P = u * V[0] + v * V[1] + t * V[2];
+ /* compute incoming direction, distance and pdf */
+ ls->D = normalize_len(ls->P - P, &ls->t);
+ ls->pdf = triangle_light_pdf_area(kg, ls->Ng, -ls->D, ls->t);
+ if (has_motion && area != 0.0f) {
+ /* scale the PDF.
+ * area = the area the sample was taken from
+ * area_pre = the are from which pdf_triangles was calculated from */
+ triangle_world_space_vertices(kg, object, prim, -1.0f, V);
+ const float area_pre = triangle_area(V[0], V[1], V[2]);
+ ls->pdf = ls->pdf * area_pre / area;
+ }
+ ls->u = u;
+ ls->v = v;
+ }
+}
+
+/* Light Distribution */
+
+ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *randu)
+{
+ /* This is basically std::upper_bound as used by PBRT, to find a point light or
+ * triangle to emit from, proportional to area. a good improvement would be to
+ * also sample proportional to power, though it's not so well defined with
+ * arbitrary shaders. */
+ int first = 0;
+ int len = kernel_data.integrator.num_distribution + 1;
+ float r = *randu;
+
+ do {
+ int half_len = len >> 1;
+ int middle = first + half_len;
+
+ if (r < kernel_tex_fetch(__light_distribution, middle).totarea) {
+ len = half_len;
+ }
+ else {
+ first = middle + 1;
+ len = len - half_len - 1;
+ }
+ } while (len > 0);
+
+ /* Clamping should not be needed but float rounding errors seem to
+ * make this fail on rare occasions. */
+ int index = clamp(first - 1, 0, kernel_data.integrator.num_distribution - 1);
+
+ /* Rescale to reuse random number. this helps the 2D samples within
+ * each area light be stratified as well. */
+ float distr_min = kernel_tex_fetch(__light_distribution, index).totarea;
+ float distr_max = kernel_tex_fetch(__light_distribution, index + 1).totarea;
+ *randu = (r - distr_min) / (distr_max - distr_min);
+
+ return index;
+}
+
+/* Generic Light */
+
+ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals kg, int index, int bounce)
+{
+ return (bounce > kernel_tex_fetch(__lights, index).max_bounces);
+}
+
+template<bool in_volume_segment>
+ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
+ float randu,
+ const float randv,
+ const float time,
+ const float3 P,
+ const int bounce,
+ const uint32_t path_flag,
+ ccl_private LightSample *ls)
+{
+ /* Sample light index from distribution. */
+ const int index = light_distribution_sample(kg, &randu);
+ ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution,
+ index);
+ const int prim = kdistribution->prim;
+
+ if (prim >= 0) {
+ /* Mesh light. */
+ const int object = kdistribution->mesh_light.object_id;
+
+ /* Exclude synthetic meshes from shadow catcher pass. */
+ if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) &&
+ !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) {
+ return false;
+ }
+
+ const int shader_flag = kdistribution->mesh_light.shader_flag;
+ triangle_light_sample<in_volume_segment>(kg, prim, object, randu, randv, time, ls, P);
+ ls->shader |= shader_flag;
+ return (ls->pdf > 0.0f);
+ }
+
+ const int lamp = -prim - 1;
+
+ if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
+ return false;
+ }
+
+ return light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls);
+}
+
+ccl_device_inline bool light_distribution_sample_from_volume_segment(KernelGlobals kg,
+ float randu,
+ const float randv,
+ const float time,
+ const float3 P,
+ const int bounce,
+ const uint32_t path_flag,
+ ccl_private LightSample *ls)
+{
+ return light_distribution_sample<true>(kg, randu, randv, time, P, bounce, path_flag, ls);
+}
+
+ccl_device_inline bool light_distribution_sample_from_position(KernelGlobals kg,
+ float randu,
+ const float randv,
+ const float time,
+ const float3 P,
+ const int bounce,
+ const uint32_t path_flag,
+ ccl_private LightSample *ls)
+{
+ return light_distribution_sample<false>(kg, randu, randv, time, P, bounce, path_flag, ls);
+}
+
+ccl_device_inline bool light_distribution_sample_new_position(KernelGlobals kg,
+ const float randu,
+ const float randv,
+ const float time,
+ const float3 P,
+ ccl_private LightSample *ls)
+{
+ /* Sample a new position on the same light, for volume sampling. */
+ if (ls->type == LIGHT_TRIANGLE) {
+ triangle_light_sample<false>(kg, ls->prim, ls->object, randu, randv, time, ls, P);
+ return (ls->pdf > 0.0f);
+ }
+ else {
+ return light_sample<false>(kg, ls->lamp, randu, randv, P, 0, ls);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h
new file mode 100644
index 00000000000..6b643a95250
--- /dev/null
+++ b/intern/cycles/kernel/light/sample.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/integrator/path_state.h"
+#include "kernel/integrator/shader_eval.h"
+
+#include "kernel/light/light.h"
+
+#include "kernel/sample/mapping.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Evaluate shader on light. */
+ccl_device_noinline_cpu float3
+light_sample_shader_eval(KernelGlobals kg,
+ IntegratorState state,
+ ccl_private ShaderData *ccl_restrict emission_sd,
+ ccl_private LightSample *ccl_restrict ls,
+ float time)
+{
+ /* setup shading at emitter */
+ float3 eval = zero_float3();
+
+ if (shader_constant_emission_eval(kg, ls->shader, &eval)) {
+ if ((ls->prim != PRIM_NONE) && dot(ls->Ng, ls->D) > 0.0f) {
+ ls->Ng = -ls->Ng;
+ }
+ }
+ else {
+ /* Setup shader data and call shader_eval_surface once, better
+ * for GPU coherence and compile times. */
+ PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_LIGHT_SETUP);
+#ifdef __BACKGROUND_MIS__
+ if (ls->type == LIGHT_BACKGROUND) {
+ shader_setup_from_background(kg, emission_sd, ls->P, ls->D, time);
+ }
+ else
+#endif
+ {
+ shader_setup_from_sample(kg,
+ emission_sd,
+ ls->P,
+ ls->Ng,
+ -ls->D,
+ ls->shader,
+ ls->object,
+ ls->prim,
+ ls->u,
+ ls->v,
+ ls->t,
+ time,
+ false,
+ ls->lamp);
+
+ ls->Ng = emission_sd->Ng;
+ }
+
+ PROFILING_SHADER(emission_sd->object, emission_sd->shader);
+ PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL);
+
+ /* No proper path flag, we're evaluating this for all closures. that's
+ * weak but we'd have to do multiple evaluations otherwise. */
+ shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT>(
+ kg, state, emission_sd, NULL, PATH_RAY_EMISSION);
+
+ /* Evaluate closures. */
+#ifdef __BACKGROUND_MIS__
+ if (ls->type == LIGHT_BACKGROUND) {
+ eval = shader_background_eval(emission_sd);
+ }
+ else
+#endif
+ {
+ eval = shader_emissive_eval(emission_sd);
+ }
+ }
+
+ eval *= ls->eval_fac;
+
+ if (ls->lamp != LAMP_NONE) {
+ ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, ls->lamp);
+ eval *= make_float3(klight->strength[0], klight->strength[1], klight->strength[2]);
+ }
+
+ return eval;
+}
+
+/* Test if light sample is from a light or emission from geometry. */
+ccl_device_inline bool light_sample_is_light(ccl_private const LightSample *ccl_restrict ls)
+{
+ /* return if it's a lamp for shadow pass */
+ return (ls->prim == PRIM_NONE && ls->type != LIGHT_BACKGROUND);
+}
+
+/* Early path termination of shadow rays. */
+ccl_device_inline bool light_sample_terminate(KernelGlobals kg,
+ ccl_private const LightSample *ccl_restrict ls,
+ ccl_private BsdfEval *ccl_restrict eval,
+ const float rand_terminate)
+{
+ if (bsdf_eval_is_zero(eval)) {
+ return true;
+ }
+
+ if (kernel_data.integrator.light_inv_rr_threshold > 0.0f) {
+ float probability = max3(fabs(bsdf_eval_sum(eval))) *
+ kernel_data.integrator.light_inv_rr_threshold;
+ if (probability < 1.0f) {
+ if (rand_terminate >= probability) {
+ return true;
+ }
+ bsdf_eval_mul(eval, 1.0f / probability);
+ }
+ }
+
+ return false;
+}
+
+/* This function should be used to compute a modified ray start position for
+ * rays leaving from a surface. The algorithm slightly distorts flat surface
+ * of a triangle. Surface is lifted by amount h along normal n in the incident
+ * point. */
+
+ccl_device_inline float3 shadow_ray_smooth_surface_offset(
+ KernelGlobals kg, ccl_private const ShaderData *ccl_restrict sd, float3 Ng)
+{
+ float3 V[3], N[3];
+ triangle_vertices_and_normals(kg, sd->prim, V, N);
+
+ const float u = sd->u, v = sd->v;
+ const float w = 1 - u - v;
+ float3 P = V[0] * u + V[1] * v + V[2] * w; /* Local space */
+ float3 n = N[0] * u + N[1] * v + N[2] * w; /* We get away without normalization */
+
+ object_normal_transform(kg, sd, &n); /* Normal x scale, world space */
+
+ /* Parabolic approximation */
+ float a = dot(N[2] - N[0], V[0] - V[2]);
+ float b = dot(N[2] - N[1], V[1] - V[2]);
+ float c = dot(N[1] - N[0], V[1] - V[0]);
+ float h = a * u * (u - 1) + (a + b + c) * u * v + b * v * (v - 1);
+
+ /* Check flipped normals */
+ if (dot(n, Ng) > 0) {
+ /* Local linear envelope */
+ float h0 = max(max(dot(V[1] - V[0], N[0]), dot(V[2] - V[0], N[0])), 0.0f);
+ float h1 = max(max(dot(V[0] - V[1], N[1]), dot(V[2] - V[1], N[1])), 0.0f);
+ float h2 = max(max(dot(V[0] - V[2], N[2]), dot(V[1] - V[2], N[2])), 0.0f);
+ h0 = max(dot(V[0] - P, N[0]) + h0, 0.0f);
+ h1 = max(dot(V[1] - P, N[1]) + h1, 0.0f);
+ h2 = max(dot(V[2] - P, N[2]) + h2, 0.0f);
+ h = max(min(min(h0, h1), h2), h * 0.5f);
+ }
+ else {
+ float h0 = max(max(dot(V[0] - V[1], N[0]), dot(V[0] - V[2], N[0])), 0.0f);
+ float h1 = max(max(dot(V[1] - V[0], N[1]), dot(V[1] - V[2], N[1])), 0.0f);
+ float h2 = max(max(dot(V[2] - V[0], N[2]), dot(V[2] - V[1], N[2])), 0.0f);
+ h0 = max(dot(P - V[0], N[0]) + h0, 0.0f);
+ h1 = max(dot(P - V[1], N[1]) + h1, 0.0f);
+ h2 = max(dot(P - V[2], N[2]) + h2, 0.0f);
+ h = min(-min(min(h0, h1), h2), h * 0.5f);
+ }
+
+ return n * h;
+}
+
+/* Ray offset to avoid shadow terminator artifact. */
+
+ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg,
+ ccl_private const ShaderData *ccl_restrict sd,
+ float3 L)
+{
+ float NL = dot(sd->N, L);
+ bool transmit = (NL < 0.0f);
+ float3 Ng = (transmit ? -sd->Ng : sd->Ng);
+ float3 P = ray_offset(sd->P, Ng);
+
+ if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
+ const float offset_cutoff =
+ kernel_tex_fetch(__objects, sd->object).shadow_terminator_geometry_offset;
+ /* Do ray offset (heavy stuff) only for close to be terminated triangles:
+ * offset_cutoff = 0.1f means that 10-20% of rays will be affected. Also
+ * make a smooth transition near the threshold. */
+ if (offset_cutoff > 0.0f) {
+ float NgL = dot(Ng, L);
+ float offset_amount = 0.0f;
+ if (NL < offset_cutoff) {
+ offset_amount = clamp(2.0f - (NgL + NL) / offset_cutoff, 0.0f, 1.0f);
+ }
+ else {
+ offset_amount = clamp(1.0f - NgL / offset_cutoff, 0.0f, 1.0f);
+ }
+ if (offset_amount > 0.0f) {
+ P += shadow_ray_smooth_surface_offset(kg, sd, Ng) * offset_amount;
+ }
+ }
+ }
+
+ return P;
+}
+
+ccl_device_inline void shadow_ray_setup(ccl_private const ShaderData *ccl_restrict sd,
+ ccl_private const LightSample *ccl_restrict ls,
+ const float3 P,
+ ccl_private Ray *ray)
+{
+ if (ls->shader & SHADER_CAST_SHADOW) {
+ /* setup ray */
+ ray->P = P;
+
+ if (ls->t == FLT_MAX) {
+ /* distant light */
+ ray->D = ls->D;
+ ray->t = ls->t;
+ }
+ else {
+ /* other lights, avoid self-intersection */
+ ray->D = ray_offset(ls->P, ls->Ng) - P;
+ ray->D = normalize_len(ray->D, &ray->t);
+ }
+ }
+ else {
+ /* signal to not cast shadow ray */
+ ray->P = zero_float3();
+ ray->D = zero_float3();
+ ray->t = 0.0f;
+ }
+
+ ray->dP = differential_make_compact(sd->dP);
+ ray->dD = differential_zero_compact();
+ ray->time = sd->time;
+}
+
+/* Create shadow ray towards light sample. */
+ccl_device_inline void light_sample_to_surface_shadow_ray(
+ KernelGlobals kg,
+ ccl_private const ShaderData *ccl_restrict sd,
+ ccl_private const LightSample *ccl_restrict ls,
+ ccl_private Ray *ray)
+{
+ const float3 P = shadow_ray_offset(kg, sd, ls->D);
+ shadow_ray_setup(sd, ls, P, ray);
+}
+
+/* Create shadow ray towards light sample. */
+ccl_device_inline void light_sample_to_volume_shadow_ray(
+ KernelGlobals kg,
+ ccl_private const ShaderData *ccl_restrict sd,
+ ccl_private const LightSample *ccl_restrict ls,
+ const float3 P,
+ ccl_private Ray *ray)
+{
+ shadow_ray_setup(sd, ls, P, ray);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt
index 6cdc7367fbb..f226c95766f 100644
--- a/intern/cycles/kernel/osl/CMakeLists.txt
+++ b/intern/cycles/kernel/osl/CMakeLists.txt
@@ -25,21 +25,21 @@ set(SRC
bsdf_diffuse_ramp.cpp
bsdf_phong_ramp.cpp
emissive.cpp
- osl_bssrdf.cpp
- osl_closures.cpp
- osl_services.cpp
- osl_shader.cpp
+ bssrdf.cpp
+ closures.cpp
+ services.cpp
+ shader.cpp
)
set(HEADER_SRC
- osl_closures.h
- osl_globals.h
- osl_services.h
- osl_shader.h
+ closures.h
+ globals.h
+ services.h
+ shader.h
)
set(LIB
- cycles_render
+ cycles_scene
${OSL_LIBRARIES}
${OPENIMAGEIO_LIBRARIES}
diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp
index bb290a5ced2..540180f99e8 100644
--- a/intern/cycles/kernel/osl/background.cpp
+++ b/intern/cycles/kernel/osl/background.cpp
@@ -34,7 +34,7 @@
#include <OSL/genclosure.h>
-#include "kernel/osl/osl_closures.h"
+#include "kernel/osl/closures.h"
// clang-format off
#include "kernel/device/cpu/compat.h"
diff --git a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
index 45216f4c74d..768531a0bf9 100644
--- a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
+++ b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
@@ -35,11 +35,10 @@
#include <OSL/genclosure.h>
#include "kernel/device/cpu/compat.h"
-#include "kernel/osl/osl_closures.h"
+#include "kernel/osl/closures.h"
// clang-format off
-#include "kernel/kernel_types.h"
-#include "kernel/kernel_montecarlo.h"
+#include "kernel/types.h"
#include "kernel/closure/alloc.h"
#include "kernel/closure/bsdf_diffuse_ramp.h"
// clang-format on
diff --git a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
index 90160fba962..d34a33216a0 100644
--- a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
+++ b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
@@ -35,10 +35,10 @@
#include <OSL/genclosure.h>
#include "kernel/device/cpu/compat.h"
-#include "kernel/osl/osl_closures.h"
+#include "kernel/osl/closures.h"
// clang-format off
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
#include "kernel/closure/alloc.h"
#include "kernel/closure/bsdf_phong_ramp.h"
// clang-format on
diff --git a/intern/cycles/kernel/osl/bssrdf.cpp b/intern/cycles/kernel/osl/bssrdf.cpp
new file mode 100644
index 00000000000..7c7f1ce157f
--- /dev/null
+++ b/intern/cycles/kernel/osl/bssrdf.cpp
@@ -0,0 +1,122 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OSL/genclosure.h>
+
+#include "kernel/device/cpu/compat.h"
+#include "kernel/osl/closures.h"
+
+// clang-format off
+#include "kernel/types.h"
+
+#include "kernel/closure/alloc.h"
+#include "kernel/closure/bsdf_util.h"
+#include "kernel/closure/bsdf_diffuse.h"
+#include "kernel/closure/bsdf_principled_diffuse.h"
+#include "kernel/closure/bssrdf.h"
+// clang-format on
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+static ustring u_burley("burley");
+static ustring u_random_walk_fixed_radius("random_walk_fixed_radius");
+static ustring u_random_walk("random_walk");
+
+class CBSSRDFClosure : public CClosurePrimitive {
+ public:
+ Bssrdf params;
+ float ior;
+ ustring method;
+
+ CBSSRDFClosure()
+ {
+ params.roughness = FLT_MAX;
+ params.anisotropy = 1.0f;
+ ior = 1.4f;
+ }
+
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ if (method == u_burley) {
+ alloc(sd, path_flag, weight, CLOSURE_BSSRDF_BURLEY_ID);
+ }
+ else if (method == u_random_walk_fixed_radius) {
+ alloc(sd, path_flag, weight, CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
+ }
+ else if (method == u_random_walk) {
+ alloc(sd, path_flag, weight, CLOSURE_BSSRDF_RANDOM_WALK_ID);
+ }
+ }
+
+ void alloc(ShaderData *sd, uint32_t path_flag, float3 weight, ClosureType type)
+ {
+ Bssrdf *bssrdf = bssrdf_alloc(sd, weight);
+
+ if (bssrdf) {
+ /* disable in case of diffuse ancestor, can't see it well then and
+ * adds considerably noise due to probabilities of continuing path
+ * getting lower and lower */
+ if (path_flag & PATH_RAY_DIFFUSE_ANCESTOR) {
+ params.radius = make_float3(0.0f, 0.0f, 0.0f);
+ }
+
+ /* create one closure per color channel */
+ bssrdf->radius = params.radius;
+ bssrdf->albedo = params.albedo;
+ bssrdf->N = params.N;
+ bssrdf->roughness = params.roughness;
+ bssrdf->anisotropy = clamp(params.anisotropy, 0.0f, 0.9f);
+ sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)type, clamp(ior, 1.01f, 3.8f));
+ }
+ }
+};
+
+ClosureParam *closure_bssrdf_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_STRING_PARAM(CBSSRDFClosure, method),
+ CLOSURE_FLOAT3_PARAM(CBSSRDFClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(CBSSRDFClosure, params.radius),
+ CLOSURE_FLOAT3_PARAM(CBSSRDFClosure, params.albedo),
+ CLOSURE_FLOAT_KEYPARAM(CBSSRDFClosure, params.roughness, "roughness"),
+ CLOSURE_FLOAT_KEYPARAM(CBSSRDFClosure, ior, "ior"),
+ CLOSURE_FLOAT_KEYPARAM(CBSSRDFClosure, params.anisotropy, "anisotropy"),
+ CLOSURE_STRING_KEYPARAM(CBSSRDFClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(CBSSRDFClosure)};
+ return params;
+}
+
+CCLOSURE_PREPARE(closure_bssrdf_prepare, CBSSRDFClosure)
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/closures.cpp b/intern/cycles/kernel/osl/closures.cpp
new file mode 100644
index 00000000000..adc0f50aefb
--- /dev/null
+++ b/intern/cycles/kernel/osl/closures.cpp
@@ -0,0 +1,1006 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011-2018, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OSL/genclosure.h>
+#include <OSL/oslclosure.h>
+
+#include "kernel/osl/closures.h"
+#include "kernel/osl/shader.h"
+
+#include "util/math.h"
+#include "util/param.h"
+
+// clang-format off
+#include "kernel/device/cpu/compat.h"
+#include "kernel/device/cpu/globals.h"
+
+#include "kernel/types.h"
+
+#include "kernel/closure/alloc.h"
+#include "kernel/closure/bsdf_util.h"
+#include "kernel/closure/bsdf_ashikhmin_velvet.h"
+#include "kernel/closure/bsdf_diffuse.h"
+#include "kernel/closure/bsdf_microfacet.h"
+#include "kernel/closure/bsdf_microfacet_multi.h"
+#include "kernel/closure/bsdf_oren_nayar.h"
+#include "kernel/closure/bsdf_reflection.h"
+#include "kernel/closure/bsdf_refraction.h"
+#include "kernel/closure/bsdf_transparent.h"
+#include "kernel/closure/bsdf_ashikhmin_shirley.h"
+#include "kernel/closure/bsdf_toon.h"
+#include "kernel/closure/bsdf_hair.h"
+#include "kernel/closure/bsdf_hair_principled.h"
+#include "kernel/closure/bsdf_principled_diffuse.h"
+#include "kernel/closure/bsdf_principled_sheen.h"
+#include "kernel/closure/volume.h"
+// clang-format on
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+/* BSDF class definitions */
+
+BSDF_CLOSURE_CLASS_BEGIN(Diffuse, diffuse, DiffuseBsdf, LABEL_DIFFUSE)
+ BSDF_CLOSURE_FLOAT3_PARAM(DiffuseClosure, params.N)
+BSDF_CLOSURE_CLASS_END(Diffuse, diffuse)
+
+BSDF_CLOSURE_CLASS_BEGIN(Translucent, translucent, DiffuseBsdf, LABEL_DIFFUSE)
+ BSDF_CLOSURE_FLOAT3_PARAM(TranslucentClosure, params.N)
+BSDF_CLOSURE_CLASS_END(Translucent, translucent)
+
+BSDF_CLOSURE_CLASS_BEGIN(OrenNayar, oren_nayar, OrenNayarBsdf, LABEL_DIFFUSE)
+ BSDF_CLOSURE_FLOAT3_PARAM(OrenNayarClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(OrenNayarClosure, params.roughness)
+BSDF_CLOSURE_CLASS_END(OrenNayar, oren_nayar)
+
+BSDF_CLOSURE_CLASS_BEGIN(Reflection, reflection, MicrofacetBsdf, LABEL_SINGULAR)
+ BSDF_CLOSURE_FLOAT3_PARAM(ReflectionClosure, params.N)
+BSDF_CLOSURE_CLASS_END(Reflection, reflection)
+
+BSDF_CLOSURE_CLASS_BEGIN(Refraction, refraction, MicrofacetBsdf, LABEL_SINGULAR)
+ BSDF_CLOSURE_FLOAT3_PARAM(RefractionClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(RefractionClosure, params.ior)
+BSDF_CLOSURE_CLASS_END(Refraction, refraction)
+
+BSDF_CLOSURE_CLASS_BEGIN(AshikhminVelvet, ashikhmin_velvet, VelvetBsdf, LABEL_DIFFUSE)
+ BSDF_CLOSURE_FLOAT3_PARAM(AshikhminVelvetClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(AshikhminVelvetClosure, params.sigma)
+BSDF_CLOSURE_CLASS_END(AshikhminVelvet, ashikhmin_velvet)
+
+BSDF_CLOSURE_CLASS_BEGIN(AshikhminShirley,
+ ashikhmin_shirley,
+ MicrofacetBsdf,
+ LABEL_GLOSSY | LABEL_REFLECT)
+ BSDF_CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, params.N)
+ BSDF_CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, params.T)
+ BSDF_CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, params.alpha_x)
+ BSDF_CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, params.alpha_y)
+BSDF_CLOSURE_CLASS_END(AshikhminShirley, ashikhmin_shirley)
+
+BSDF_CLOSURE_CLASS_BEGIN(DiffuseToon, diffuse_toon, ToonBsdf, LABEL_DIFFUSE)
+ BSDF_CLOSURE_FLOAT3_PARAM(DiffuseToonClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(DiffuseToonClosure, params.size)
+ BSDF_CLOSURE_FLOAT_PARAM(DiffuseToonClosure, params.smooth)
+BSDF_CLOSURE_CLASS_END(DiffuseToon, diffuse_toon)
+
+BSDF_CLOSURE_CLASS_BEGIN(GlossyToon, glossy_toon, ToonBsdf, LABEL_GLOSSY)
+ BSDF_CLOSURE_FLOAT3_PARAM(GlossyToonClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(GlossyToonClosure, params.size)
+ BSDF_CLOSURE_FLOAT_PARAM(GlossyToonClosure, params.smooth)
+BSDF_CLOSURE_CLASS_END(GlossyToon, glossy_toon)
+
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXIsotropic,
+ microfacet_ggx_isotropic,
+ MicrofacetBsdf,
+ LABEL_GLOSSY | LABEL_REFLECT)
+ BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetGGXIsotropicClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(MicrofacetGGXIsotropicClosure, params.alpha_x)
+BSDF_CLOSURE_CLASS_END(MicrofacetGGXIsotropic, microfacet_ggx_isotropic)
+
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGX,
+ microfacet_ggx,
+ MicrofacetBsdf,
+ LABEL_GLOSSY | LABEL_REFLECT)
+ BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetGGXClosure, params.N)
+ BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetGGXClosure, params.T)
+ BSDF_CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure, params.alpha_x)
+ BSDF_CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure, params.alpha_y)
+BSDF_CLOSURE_CLASS_END(MicrofacetGGX, microfacet_ggx)
+
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannIsotropic,
+ microfacet_beckmann_isotropic,
+ MicrofacetBsdf,
+ LABEL_GLOSSY | LABEL_REFLECT)
+ BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannIsotropicClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(MicrofacetBeckmannIsotropicClosure, params.alpha_x)
+BSDF_CLOSURE_CLASS_END(MicrofacetBeckmannIsotropic, microfacet_beckmann_isotropic)
+
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmann,
+ microfacet_beckmann,
+ MicrofacetBsdf,
+ LABEL_GLOSSY | LABEL_REFLECT)
+ BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannClosure, params.N)
+ BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannClosure, params.T)
+ BSDF_CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure, params.alpha_x)
+ BSDF_CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure, params.alpha_y)
+BSDF_CLOSURE_CLASS_END(MicrofacetBeckmann, microfacet_beckmann)
+
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXRefraction,
+ microfacet_ggx_refraction,
+ MicrofacetBsdf,
+ LABEL_GLOSSY | LABEL_TRANSMIT)
+ BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetGGXRefractionClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, params.alpha_x)
+ BSDF_CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, params.ior)
+BSDF_CLOSURE_CLASS_END(MicrofacetGGXRefraction, microfacet_ggx_refraction)
+
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannRefraction,
+ microfacet_beckmann_refraction,
+ MicrofacetBsdf,
+ LABEL_GLOSSY | LABEL_TRANSMIT)
+ BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannRefractionClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, params.alpha_x)
+ BSDF_CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, params.ior)
+BSDF_CLOSURE_CLASS_END(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction)
+
+BSDF_CLOSURE_CLASS_BEGIN(HairReflection, hair_reflection, HairBsdf, LABEL_GLOSSY)
+ BSDF_CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.roughness1)
+ BSDF_CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.roughness2)
+ BSDF_CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.T)
+ BSDF_CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.offset)
+BSDF_CLOSURE_CLASS_END(HairReflection, hair_reflection)
+
+BSDF_CLOSURE_CLASS_BEGIN(HairTransmission, hair_transmission, HairBsdf, LABEL_GLOSSY)
+ BSDF_CLOSURE_FLOAT3_PARAM(HairTransmissionClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(HairTransmissionClosure, params.roughness1)
+ BSDF_CLOSURE_FLOAT_PARAM(HairTransmissionClosure, params.roughness2)
+ BSDF_CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.T)
+ BSDF_CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.offset)
+BSDF_CLOSURE_CLASS_END(HairTransmission, hair_transmission)
+
+BSDF_CLOSURE_CLASS_BEGIN(PrincipledDiffuse,
+ principled_diffuse,
+ PrincipledDiffuseBsdf,
+ LABEL_DIFFUSE)
+ BSDF_CLOSURE_FLOAT3_PARAM(PrincipledDiffuseClosure, params.N)
+ BSDF_CLOSURE_FLOAT_PARAM(PrincipledDiffuseClosure, params.roughness)
+BSDF_CLOSURE_CLASS_END(PrincipledDiffuse, principled_diffuse)
+
+class PrincipledSheenClosure : public CBSDFClosure {
+ public:
+ PrincipledSheenBsdf params;
+
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ if (!skip(sd, path_flag, LABEL_DIFFUSE)) {
+ PrincipledSheenBsdf *bsdf = (PrincipledSheenBsdf *)bsdf_alloc_osl(
+ sd, sizeof(PrincipledSheenBsdf), weight, &params);
+ sd->flag |= (bsdf) ? bsdf_principled_sheen_setup(sd, bsdf) : 0;
+ }
+ }
+};
+
+static ClosureParam *bsdf_principled_sheen_params()
+{
+ static ClosureParam params[] = {CLOSURE_FLOAT3_PARAM(PrincipledSheenClosure, params.N),
+ CLOSURE_STRING_KEYPARAM(PrincipledSheenClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(PrincipledSheenClosure)};
+ return params;
+}
+
+CCLOSURE_PREPARE_STATIC(closure_bsdf_principled_sheen_prepare, PrincipledSheenClosure)
+
+/* PRINCIPLED HAIR BSDF */
+class PrincipledHairClosure : public CBSDFClosure {
+ public:
+ PrincipledHairBSDF params;
+
+ PrincipledHairBSDF *alloc(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)bsdf_alloc_osl(
+ sd, sizeof(PrincipledHairBSDF), weight, &params);
+ if (!bsdf) {
+ return NULL;
+ }
+
+ PrincipledHairExtra *extra = (PrincipledHairExtra *)closure_alloc_extra(
+ sd, sizeof(PrincipledHairExtra));
+ if (!extra) {
+ return NULL;
+ }
+
+ bsdf->extra = extra;
+ return bsdf;
+ }
+
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ if (!skip(sd, path_flag, LABEL_GLOSSY)) {
+ PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)alloc(sd, path_flag, weight);
+ if (!bsdf) {
+ return;
+ }
+
+ sd->flag |= (bsdf) ? bsdf_principled_hair_setup(sd, bsdf) : 0;
+ }
+ }
+};
+
+static ClosureParam *closure_bsdf_principled_hair_params()
+{
+ static ClosureParam params[] = {CLOSURE_FLOAT3_PARAM(PrincipledHairClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(PrincipledHairClosure, params.sigma),
+ CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.v),
+ CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.s),
+ CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.m0_roughness),
+ CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.alpha),
+ CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.eta),
+ CLOSURE_STRING_KEYPARAM(PrincipledHairClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(PrincipledHairClosure)};
+
+ return params;
+}
+
+CCLOSURE_PREPARE(closure_bsdf_principled_hair_prepare, PrincipledHairClosure)
+
+/* DISNEY PRINCIPLED CLEARCOAT */
+class PrincipledClearcoatClosure : public CBSDFClosure {
+ public:
+ MicrofacetBsdf params;
+ float clearcoat, clearcoat_roughness;
+
+ MicrofacetBsdf *alloc(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc_osl(
+ sd, sizeof(MicrofacetBsdf), weight, &params);
+ if (!bsdf) {
+ return NULL;
+ }
+
+ MicrofacetExtra *extra = (MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
+ if (!extra) {
+ return NULL;
+ }
+
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra = extra;
+ bsdf->ior = 1.5f;
+ bsdf->alpha_x = clearcoat_roughness;
+ bsdf->alpha_y = clearcoat_roughness;
+ bsdf->extra->color = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra->cspec0 = make_float3(0.04f, 0.04f, 0.04f);
+ bsdf->extra->clearcoat = clearcoat;
+ return bsdf;
+ }
+
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ if (!bsdf) {
+ return;
+ }
+
+ sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(bsdf, sd);
+ }
+};
+
+ClosureParam *closure_bsdf_principled_clearcoat_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(PrincipledClearcoatClosure, params.N),
+ CLOSURE_FLOAT_PARAM(PrincipledClearcoatClosure, clearcoat),
+ CLOSURE_FLOAT_PARAM(PrincipledClearcoatClosure, clearcoat_roughness),
+ CLOSURE_STRING_KEYPARAM(PrincipledClearcoatClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(PrincipledClearcoatClosure)};
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_principled_clearcoat_prepare, PrincipledClearcoatClosure)
+
+/* Registration */
+
+static void register_closure(OSL::ShadingSystem *ss,
+ const char *name,
+ int id,
+ OSL::ClosureParam *params,
+ OSL::PrepareClosureFunc prepare)
+{
+ /* optimization: it's possible to not use a prepare function at all and
+ * only initialize the actual class when accessing the closure component
+ * data, but then we need to map the id to the class somehow */
+#if OSL_LIBRARY_VERSION_CODE >= 10900
+ ss->register_closure(name, id, params, prepare, NULL);
+#else
+ ss->register_closure(name, id, params, prepare, NULL, 16);
+#endif
+}
+
+void OSLShader::register_closures(OSLShadingSystem *ss_)
+{
+ OSL::ShadingSystem *ss = (OSL::ShadingSystem *)ss_;
+ int id = 0;
+
+ register_closure(ss, "diffuse", id++, bsdf_diffuse_params(), bsdf_diffuse_prepare);
+ register_closure(ss, "oren_nayar", id++, bsdf_oren_nayar_params(), bsdf_oren_nayar_prepare);
+ register_closure(ss, "translucent", id++, bsdf_translucent_params(), bsdf_translucent_prepare);
+ register_closure(ss, "reflection", id++, bsdf_reflection_params(), bsdf_reflection_prepare);
+ register_closure(ss, "refraction", id++, bsdf_refraction_params(), bsdf_refraction_prepare);
+ register_closure(ss,
+ "transparent",
+ id++,
+ closure_bsdf_transparent_params(),
+ closure_bsdf_transparent_prepare);
+
+ register_closure(
+ ss, "microfacet", id++, closure_bsdf_microfacet_params(), closure_bsdf_microfacet_prepare);
+ register_closure(ss,
+ "microfacet_ggx",
+ id++,
+ bsdf_microfacet_ggx_isotropic_params(),
+ bsdf_microfacet_ggx_isotropic_prepare);
+ register_closure(
+ ss, "microfacet_ggx_aniso", id++, bsdf_microfacet_ggx_params(), bsdf_microfacet_ggx_prepare);
+ register_closure(ss,
+ "microfacet_ggx_refraction",
+ id++,
+ bsdf_microfacet_ggx_refraction_params(),
+ bsdf_microfacet_ggx_refraction_prepare);
+ register_closure(ss,
+ "microfacet_multi_ggx",
+ id++,
+ closure_bsdf_microfacet_multi_ggx_params(),
+ closure_bsdf_microfacet_multi_ggx_prepare);
+ register_closure(ss,
+ "microfacet_multi_ggx_glass",
+ id++,
+ closure_bsdf_microfacet_multi_ggx_glass_params(),
+ closure_bsdf_microfacet_multi_ggx_glass_prepare);
+ register_closure(ss,
+ "microfacet_multi_ggx_aniso",
+ id++,
+ closure_bsdf_microfacet_multi_ggx_aniso_params(),
+ closure_bsdf_microfacet_multi_ggx_aniso_prepare);
+ register_closure(ss,
+ "microfacet_ggx_fresnel",
+ id++,
+ closure_bsdf_microfacet_ggx_fresnel_params(),
+ closure_bsdf_microfacet_ggx_fresnel_prepare);
+ register_closure(ss,
+ "microfacet_ggx_aniso_fresnel",
+ id++,
+ closure_bsdf_microfacet_ggx_aniso_fresnel_params(),
+ closure_bsdf_microfacet_ggx_aniso_fresnel_prepare);
+ register_closure(ss,
+ "microfacet_multi_ggx_fresnel",
+ id++,
+ closure_bsdf_microfacet_multi_ggx_fresnel_params(),
+ closure_bsdf_microfacet_multi_ggx_fresnel_prepare);
+ register_closure(ss,
+ "microfacet_multi_ggx_glass_fresnel",
+ id++,
+ closure_bsdf_microfacet_multi_ggx_glass_fresnel_params(),
+ closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare);
+ register_closure(ss,
+ "microfacet_multi_ggx_aniso_fresnel",
+ id++,
+ closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params(),
+ closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare);
+ register_closure(ss,
+ "microfacet_beckmann",
+ id++,
+ bsdf_microfacet_beckmann_isotropic_params(),
+ bsdf_microfacet_beckmann_isotropic_prepare);
+ register_closure(ss,
+ "microfacet_beckmann_aniso",
+ id++,
+ bsdf_microfacet_beckmann_params(),
+ bsdf_microfacet_beckmann_prepare);
+ register_closure(ss,
+ "microfacet_beckmann_refraction",
+ id++,
+ bsdf_microfacet_beckmann_refraction_params(),
+ bsdf_microfacet_beckmann_refraction_prepare);
+ register_closure(ss,
+ "ashikhmin_shirley",
+ id++,
+ bsdf_ashikhmin_shirley_params(),
+ bsdf_ashikhmin_shirley_prepare);
+ register_closure(
+ ss, "ashikhmin_velvet", id++, bsdf_ashikhmin_velvet_params(), bsdf_ashikhmin_velvet_prepare);
+ register_closure(
+ ss, "diffuse_toon", id++, bsdf_diffuse_toon_params(), bsdf_diffuse_toon_prepare);
+ register_closure(ss, "glossy_toon", id++, bsdf_glossy_toon_params(), bsdf_glossy_toon_prepare);
+ register_closure(ss,
+ "principled_diffuse",
+ id++,
+ bsdf_principled_diffuse_params(),
+ bsdf_principled_diffuse_prepare);
+ register_closure(ss,
+ "principled_sheen",
+ id++,
+ bsdf_principled_sheen_params(),
+ closure_bsdf_principled_sheen_prepare);
+ register_closure(ss,
+ "principled_clearcoat",
+ id++,
+ closure_bsdf_principled_clearcoat_params(),
+ closure_bsdf_principled_clearcoat_prepare);
+
+ register_closure(ss, "emission", id++, closure_emission_params(), closure_emission_prepare);
+ register_closure(
+ ss, "background", id++, closure_background_params(), closure_background_prepare);
+ register_closure(ss, "holdout", id++, closure_holdout_params(), closure_holdout_prepare);
+ register_closure(ss,
+ "diffuse_ramp",
+ id++,
+ closure_bsdf_diffuse_ramp_params(),
+ closure_bsdf_diffuse_ramp_prepare);
+ register_closure(
+ ss, "phong_ramp", id++, closure_bsdf_phong_ramp_params(), closure_bsdf_phong_ramp_prepare);
+ register_closure(ss, "bssrdf", id++, closure_bssrdf_params(), closure_bssrdf_prepare);
+
+ register_closure(
+ ss, "hair_reflection", id++, bsdf_hair_reflection_params(), bsdf_hair_reflection_prepare);
+ register_closure(ss,
+ "hair_transmission",
+ id++,
+ bsdf_hair_transmission_params(),
+ bsdf_hair_transmission_prepare);
+
+ register_closure(ss,
+ "principled_hair",
+ id++,
+ closure_bsdf_principled_hair_params(),
+ closure_bsdf_principled_hair_prepare);
+
+ register_closure(ss,
+ "henyey_greenstein",
+ id++,
+ closure_henyey_greenstein_params(),
+ closure_henyey_greenstein_prepare);
+ register_closure(
+ ss, "absorption", id++, closure_absorption_params(), closure_absorption_prepare);
+}
+
+/* BSDF Closure */
+
+bool CBSDFClosure::skip(const ShaderData *sd, uint32_t path_flag, int scattering)
+{
+ /* caustic options */
+ if ((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) {
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+
+ if ((!kernel_data.integrator.caustics_reflective && (scattering & LABEL_REFLECT)) ||
+ (!kernel_data.integrator.caustics_refractive && (scattering & LABEL_TRANSMIT))) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Standard Microfacet Closure */
+
+class MicrofacetClosure : public CBSDFClosure {
+ public:
+ MicrofacetBsdf params;
+ ustring distribution;
+ int refract;
+
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ static ustring u_ggx("ggx");
+ static ustring u_default("default");
+
+ const int label = (refract) ? LABEL_TRANSMIT : LABEL_REFLECT;
+ if (skip(sd, path_flag, LABEL_GLOSSY | label)) {
+ return;
+ }
+
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc_osl(
+ sd, sizeof(MicrofacetBsdf), weight, &params);
+
+ if (!bsdf) {
+ return;
+ }
+
+ /* GGX */
+ if (distribution == u_ggx || distribution == u_default) {
+ if (!refract) {
+ if (params.alpha_x == params.alpha_y) {
+ /* Isotropic */
+ sd->flag |= bsdf_microfacet_ggx_isotropic_setup(bsdf);
+ }
+ else {
+ /* Anisotropic */
+ sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
+ }
+ }
+ else {
+ sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
+ }
+ }
+ /* Beckmann */
+ else {
+ if (!refract) {
+ if (params.alpha_x == params.alpha_y) {
+ /* Isotropic */
+ sd->flag |= bsdf_microfacet_beckmann_isotropic_setup(bsdf);
+ }
+ else {
+ /* Anisotropic */
+ sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
+ }
+ }
+ else {
+ sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
+ }
+ }
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_params()
+{
+ static ClosureParam params[] = {CLOSURE_STRING_PARAM(MicrofacetClosure, distribution),
+ CLOSURE_FLOAT3_PARAM(MicrofacetClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(MicrofacetClosure, params.T),
+ CLOSURE_FLOAT_PARAM(MicrofacetClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetClosure, params.alpha_y),
+ CLOSURE_FLOAT_PARAM(MicrofacetClosure, params.ior),
+ CLOSURE_INT_PARAM(MicrofacetClosure, refract),
+ CLOSURE_STRING_KEYPARAM(MicrofacetClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetClosure)};
+
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_prepare, MicrofacetClosure)
+
+/* GGX closures with Fresnel */
+
+class MicrofacetFresnelClosure : public CBSDFClosure {
+ public:
+ MicrofacetBsdf params;
+ float3 color;
+ float3 cspec0;
+
+ MicrofacetBsdf *alloc(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ /* Technically, the MultiGGX Glass closure may also transmit. However,
+ * since this is set statically and only used for caustic flags, this
+ * is probably as good as it gets. */
+ if (skip(sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
+ return NULL;
+ }
+
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc_osl(
+ sd, sizeof(MicrofacetBsdf), weight, &params);
+ if (!bsdf) {
+ return NULL;
+ }
+
+ MicrofacetExtra *extra = (MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
+ if (!extra) {
+ return NULL;
+ }
+
+ bsdf->extra = extra;
+ bsdf->extra->color = color;
+ bsdf->extra->cspec0 = cspec0;
+ bsdf->extra->clearcoat = 0.0f;
+ return bsdf;
+ }
+};
+
+class MicrofacetGGXFresnelClosure : public MicrofacetFresnelClosure {
+ public:
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ if (!bsdf) {
+ return;
+ }
+
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->alpha_y = bsdf->alpha_x;
+ sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_ggx_fresnel_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.ior),
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, color),
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, cspec0),
+ CLOSURE_STRING_KEYPARAM(MicrofacetGGXFresnelClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetGGXFresnelClosure)};
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_ggx_fresnel_prepare, MicrofacetGGXFresnelClosure);
+
+class MicrofacetGGXAnisoFresnelClosure : public MicrofacetFresnelClosure {
+ public:
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ if (!bsdf) {
+ return;
+ }
+
+ sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_ggx_aniso_fresnel_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.T),
+ CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_y),
+ CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.ior),
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, color),
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, cspec0),
+ CLOSURE_STRING_KEYPARAM(MicrofacetGGXFresnelClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetGGXFresnelClosure)};
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_ggx_aniso_fresnel_prepare,
+ MicrofacetGGXAnisoFresnelClosure);
+
+/* Multiscattering GGX closures */
+
+class MicrofacetMultiClosure : public CBSDFClosure {
+ public:
+ MicrofacetBsdf params;
+ float3 color;
+
+ MicrofacetBsdf *alloc(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ /* Technically, the MultiGGX closure may also transmit. However,
+ * since this is set statically and only used for caustic flags, this
+ * is probably as good as it gets. */
+ if (skip(sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
+ return NULL;
+ }
+
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc_osl(
+ sd, sizeof(MicrofacetBsdf), weight, &params);
+ if (!bsdf) {
+ return NULL;
+ }
+
+ MicrofacetExtra *extra = (MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
+ if (!extra) {
+ return NULL;
+ }
+
+ bsdf->extra = extra;
+ bsdf->extra->color = color;
+ bsdf->extra->cspec0 = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra->clearcoat = 0.0f;
+ return bsdf;
+ }
+};
+
+class MicrofacetMultiGGXClosure : public MicrofacetMultiClosure {
+ public:
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ if (!bsdf) {
+ return;
+ }
+
+ bsdf->ior = 0.0f;
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->alpha_y = bsdf->alpha_x;
+ sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)};
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_prepare, MicrofacetMultiGGXClosure);
+
+class MicrofacetMultiGGXAnisoClosure : public MicrofacetMultiClosure {
+ public:
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ if (!bsdf) {
+ return;
+ }
+
+ bsdf->ior = 0.0f;
+ sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.T),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_y),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)};
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_prepare, MicrofacetMultiGGXAnisoClosure);
+
+class MicrofacetMultiGGXGlassClosure : public MicrofacetMultiClosure {
+ public:
+ MicrofacetMultiGGXGlassClosure() : MicrofacetMultiClosure()
+ {
+ }
+
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ if (!bsdf) {
+ return;
+ }
+
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->alpha_y = bsdf->alpha_x;
+ sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(bsdf);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.ior),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)};
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure);
+
+/* Multiscattering GGX closures with Fresnel */
+
+class MicrofacetMultiFresnelClosure : public CBSDFClosure {
+ public:
+ MicrofacetBsdf params;
+ float3 color;
+ float3 cspec0;
+
+ MicrofacetBsdf *alloc(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ /* Technically, the MultiGGX closure may also transmit. However,
+ * since this is set statically and only used for caustic flags, this
+ * is probably as good as it gets. */
+ if (skip(sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
+ return NULL;
+ }
+
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc_osl(
+ sd, sizeof(MicrofacetBsdf), weight, &params);
+ if (!bsdf) {
+ return NULL;
+ }
+
+ MicrofacetExtra *extra = (MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
+ if (!extra) {
+ return NULL;
+ }
+
+ bsdf->extra = extra;
+ bsdf->extra->color = color;
+ bsdf->extra->cspec0 = cspec0;
+ bsdf->extra->clearcoat = 0.0f;
+ return bsdf;
+ }
+};
+
+class MicrofacetMultiGGXFresnelClosure : public MicrofacetMultiFresnelClosure {
+ public:
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ if (!bsdf) {
+ return;
+ }
+
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->alpha_y = bsdf->alpha_x;
+ sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_fresnel_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure)};
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_fresnel_prepare,
+ MicrofacetMultiGGXFresnelClosure);
+
+class MicrofacetMultiGGXAnisoFresnelClosure : public MicrofacetMultiFresnelClosure {
+ public:
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ if (!bsdf) {
+ return;
+ }
+
+ sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.T),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_y),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure)};
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare,
+ MicrofacetMultiGGXAnisoFresnelClosure);
+
+class MicrofacetMultiGGXGlassFresnelClosure : public MicrofacetMultiFresnelClosure {
+ public:
+ MicrofacetMultiGGXGlassFresnelClosure() : MicrofacetMultiFresnelClosure()
+ {
+ }
+
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ if (!bsdf) {
+ return;
+ }
+
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->alpha_y = bsdf->alpha_x;
+ sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf, sd);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_fresnel_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure)};
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare,
+ MicrofacetMultiGGXGlassFresnelClosure);
+
+/* Transparent */
+
+class TransparentClosure : public CBSDFClosure {
+ public:
+ ShaderClosure params;
+ float3 unused;
+
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ bsdf_transparent_setup(sd, weight, path_flag);
+ }
+};
+
+ClosureParam *closure_bsdf_transparent_params()
+{
+ static ClosureParam params[] = {CLOSURE_STRING_KEYPARAM(TransparentClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(TransparentClosure)};
+ return params;
+}
+
+CCLOSURE_PREPARE(closure_bsdf_transparent_prepare, TransparentClosure)
+
+/* Volume */
+
+class VolumeAbsorptionClosure : public CBSDFClosure {
+ public:
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ volume_extinction_setup(sd, weight);
+ }
+};
+
+ClosureParam *closure_absorption_params()
+{
+ static ClosureParam params[] = {CLOSURE_STRING_KEYPARAM(VolumeAbsorptionClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(VolumeAbsorptionClosure)};
+ return params;
+}
+
+CCLOSURE_PREPARE(closure_absorption_prepare, VolumeAbsorptionClosure)
+
+class VolumeHenyeyGreensteinClosure : public CBSDFClosure {
+ public:
+ HenyeyGreensteinVolume params;
+
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
+ {
+ volume_extinction_setup(sd, weight);
+
+ HenyeyGreensteinVolume *volume = (HenyeyGreensteinVolume *)bsdf_alloc_osl(
+ sd, sizeof(HenyeyGreensteinVolume), weight, &params);
+ if (!volume) {
+ return;
+ }
+
+ sd->flag |= volume_henyey_greenstein_setup(volume);
+ }
+};
+
+ClosureParam *closure_henyey_greenstein_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT_PARAM(VolumeHenyeyGreensteinClosure, params.g),
+ CLOSURE_STRING_KEYPARAM(VolumeHenyeyGreensteinClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(VolumeHenyeyGreensteinClosure)};
+ return params;
+}
+
+CCLOSURE_PREPARE(closure_henyey_greenstein_prepare, VolumeHenyeyGreensteinClosure)
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/closures.h b/intern/cycles/kernel/osl/closures.h
new file mode 100644
index 00000000000..8f573e89734
--- /dev/null
+++ b/intern/cycles/kernel/osl/closures.h
@@ -0,0 +1,164 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OSL_CLOSURES_H__
+#define __OSL_CLOSURES_H__
+
+#include "kernel/types.h"
+#include "util/types.h"
+
+#include <OSL/genclosure.h>
+#include <OSL/oslclosure.h>
+#include <OSL/oslexec.h>
+
+CCL_NAMESPACE_BEGIN
+
+OSL::ClosureParam *closure_emission_params();
+OSL::ClosureParam *closure_background_params();
+OSL::ClosureParam *closure_holdout_params();
+OSL::ClosureParam *closure_bsdf_diffuse_ramp_params();
+OSL::ClosureParam *closure_bsdf_phong_ramp_params();
+OSL::ClosureParam *closure_bsdf_transparent_params();
+OSL::ClosureParam *closure_bssrdf_params();
+OSL::ClosureParam *closure_absorption_params();
+OSL::ClosureParam *closure_henyey_greenstein_params();
+OSL::ClosureParam *closure_bsdf_microfacet_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params();
+OSL::ClosureParam *closure_bsdf_microfacet_ggx_fresnel_params();
+OSL::ClosureParam *closure_bsdf_microfacet_ggx_aniso_fresnel_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_fresnel_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_fresnel_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params();
+OSL::ClosureParam *closure_bsdf_principled_clearcoat_params();
+
+void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
+void closure_background_prepare(OSL::RendererServices *, int id, void *data);
+void closure_holdout_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_diffuse_ramp_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_phong_ramp_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_transparent_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bssrdf_prepare(OSL::RendererServices *, int id, void *data);
+void closure_absorption_prepare(OSL::RendererServices *, int id, void *data);
+void closure_henyey_greenstein_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_multi_ggx_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_multi_ggx_glass_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_multi_ggx_aniso_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_ggx_fresnel_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_ggx_aniso_fresnel_prepare(OSL::RendererServices *,
+ int id,
+ void *data);
+void closure_bsdf_microfacet_multi_ggx_fresnel_prepare(OSL::RendererServices *,
+ int id,
+ void *data);
+void closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare(OSL::RendererServices *,
+ int id,
+ void *data);
+void closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare(OSL::RendererServices *,
+ int id,
+ void *data);
+void closure_bsdf_principled_clearcoat_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_principled_hair_prepare(OSL::RendererServices *, int id, void *data);
+
+#define CCLOSURE_PREPARE(name, classname) \
+ void name(RendererServices *, int id, void *data) \
+ { \
+ memset(data, 0, sizeof(classname)); \
+ new (data) classname(); \
+ }
+
+#define CCLOSURE_PREPARE_STATIC(name, classname) static CCLOSURE_PREPARE(name, classname)
+
+#define CLOSURE_FLOAT3_PARAM(st, fld) \
+ { \
+ TypeDesc::TypeVector, (int)reckless_offsetof(st, fld), NULL, sizeof(OSL::Vec3) \
+ }
+
+#define BSDF_CLOSURE_FLOAT_PARAM(st, fld) CLOSURE_FLOAT_PARAM(st, fld),
+#define BSDF_CLOSURE_FLOAT3_PARAM(st, fld) CLOSURE_FLOAT3_PARAM(st, fld),
+
+#define TO_VEC3(v) OSL::Vec3(v.x, v.y, v.z)
+#define TO_COLOR3(v) OSL::Color3(v.x, v.y, v.z)
+#define TO_FLOAT3(v) make_float3(v[0], v[1], v[2])
+
+/* Closure */
+
+class CClosurePrimitive {
+ public:
+ virtual void setup(ShaderData *sd, uint32_t path_flag, float3 weight) = 0;
+
+ OSL::ustring label;
+};
+
+/* BSDF */
+
+class CBSDFClosure : public CClosurePrimitive {
+ public:
+ bool skip(const ShaderData *sd, uint32_t path_flag, int scattering);
+};
+
+#define BSDF_CLOSURE_CLASS_BEGIN(Upper, lower, structname, TYPE) \
+\
+ class Upper##Closure : public CBSDFClosure { \
+ public: \
+ structname params; \
+ float3 unused; \
+\
+ void setup(ShaderData *sd, uint32_t path_flag, float3 weight) \
+ { \
+ if (!skip(sd, path_flag, TYPE)) { \
+ structname *bsdf = (structname *)bsdf_alloc_osl(sd, sizeof(structname), weight, &params); \
+ sd->flag |= (bsdf) ? bsdf_##lower##_setup(bsdf) : 0; \
+ } \
+ } \
+ }; \
+\
+ static ClosureParam *bsdf_##lower##_params() \
+ { \
+ static ClosureParam params[] = {
+
+/* parameters */
+
+#define BSDF_CLOSURE_CLASS_END(Upper, lower) \
+ CLOSURE_STRING_KEYPARAM(Upper##Closure, label, "label"), CLOSURE_FINISH_PARAM(Upper##Closure) \
+ } \
+ ; \
+ return params; \
+ } \
+\
+ CCLOSURE_PREPARE_STATIC(bsdf_##lower##_prepare, Upper##Closure)
+
+CCL_NAMESPACE_END
+
+#endif /* __OSL_CLOSURES_H__ */
diff --git a/intern/cycles/kernel/osl/emissive.cpp b/intern/cycles/kernel/osl/emissive.cpp
index 5a7fe14b22e..2615e300a92 100644
--- a/intern/cycles/kernel/osl/emissive.cpp
+++ b/intern/cycles/kernel/osl/emissive.cpp
@@ -34,11 +34,11 @@
#include <OSL/genclosure.h>
-#include "kernel/osl/osl_closures.h"
+#include "kernel/osl/closures.h"
// clang-format off
#include "kernel/device/cpu/compat.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
#include "kernel/closure/alloc.h"
#include "kernel/closure/emissive.h"
// clang-format on
diff --git a/intern/cycles/kernel/osl/globals.h b/intern/cycles/kernel/osl/globals.h
new file mode 100644
index 00000000000..126ace0086e
--- /dev/null
+++ b/intern/cycles/kernel/osl/globals.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __OSL_GLOBALS_H__
+#define __OSL_GLOBALS_H__
+
+#ifdef WITH_OSL
+
+# include <OSL/oslexec.h>
+
+# include <OpenImageIO/refcnt.h>
+# include <OpenImageIO/unordered_map_concurrent.h>
+
+# include "util/map.h"
+# include "util/param.h"
+# include "util/thread.h"
+# include "util/unique_ptr.h"
+# include "util/vector.h"
+
+# ifndef WIN32
+using std::isfinite;
+# endif
+
+CCL_NAMESPACE_BEGIN
+
+class OSLRenderServices;
+class ColorSpaceProcessor;
+
+/* OSL Globals
+ *
+ * Data needed by OSL render services, that is global to a rendering session.
+ * This includes all OSL shaders, name to attribute mapping and texture handles.
+ */
+
+struct OSLGlobals {
+ OSLGlobals()
+ {
+ ss = NULL;
+ ts = NULL;
+ services = NULL;
+ use = false;
+ }
+
+ bool use;
+
+ /* shading system */
+ OSL::ShadingSystem *ss;
+ OSL::TextureSystem *ts;
+ OSLRenderServices *services;
+
+ /* shader states */
+ vector<OSL::ShaderGroupRef> surface_state;
+ vector<OSL::ShaderGroupRef> volume_state;
+ vector<OSL::ShaderGroupRef> displacement_state;
+ vector<OSL::ShaderGroupRef> bump_state;
+ OSL::ShaderGroupRef background_state;
+
+ /* attributes */
+ struct Attribute {
+ TypeDesc type;
+ AttributeDescriptor desc;
+ ParamValue value;
+ };
+
+ typedef unordered_map<ustring, Attribute, ustringHash> AttributeMap;
+ typedef unordered_map<ustring, int, ustringHash> ObjectNameMap;
+
+ vector<AttributeMap> attribute_map;
+ ObjectNameMap object_name_map;
+ vector<ustring> object_names;
+};
+
+/* trace() call result */
+struct OSLTraceData {
+ Ray ray;
+ Intersection isect;
+ ShaderData sd;
+ bool setup;
+ bool init;
+ bool hit;
+};
+
+/* thread key for thread specific data lookup */
+struct OSLThreadData {
+ OSL::ShaderGlobals globals;
+ OSL::PerThreadInfo *osl_thread_info;
+ OSLTraceData tracedata;
+ OSL::ShadingContext *context;
+ OIIO::TextureSystem::Perthread *oiio_thread_info;
+};
+
+CCL_NAMESPACE_END
+
+#endif
+
+#endif /* __OSL_GLOBALS_H__ */
diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp
deleted file mode 100644
index 5bf7b604498..00000000000
--- a/intern/cycles/kernel/osl/osl_bssrdf.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Adapted from Open Shading Language with this license:
- *
- * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
- * All Rights Reserved.
- *
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Sony Pictures Imageworks nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <OSL/genclosure.h>
-
-#include "kernel/device/cpu/compat.h"
-#include "kernel/osl/osl_closures.h"
-
-// clang-format off
-#include "kernel/kernel_types.h"
-#include "kernel/kernel_montecarlo.h"
-
-#include "kernel/closure/alloc.h"
-#include "kernel/closure/bsdf_util.h"
-#include "kernel/closure/bsdf_diffuse.h"
-#include "kernel/closure/bsdf_principled_diffuse.h"
-#include "kernel/closure/bssrdf.h"
-// clang-format on
-
-CCL_NAMESPACE_BEGIN
-
-using namespace OSL;
-
-static ustring u_burley("burley");
-static ustring u_random_walk_fixed_radius("random_walk_fixed_radius");
-static ustring u_random_walk("random_walk");
-
-class CBSSRDFClosure : public CClosurePrimitive {
- public:
- Bssrdf params;
- float ior;
- ustring method;
-
- CBSSRDFClosure()
- {
- params.roughness = FLT_MAX;
- params.anisotropy = 1.0f;
- ior = 1.4f;
- }
-
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- if (method == u_burley) {
- alloc(sd, path_flag, weight, CLOSURE_BSSRDF_BURLEY_ID);
- }
- else if (method == u_random_walk_fixed_radius) {
- alloc(sd, path_flag, weight, CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
- }
- else if (method == u_random_walk) {
- alloc(sd, path_flag, weight, CLOSURE_BSSRDF_RANDOM_WALK_ID);
- }
- }
-
- void alloc(ShaderData *sd, uint32_t path_flag, float3 weight, ClosureType type)
- {
- Bssrdf *bssrdf = bssrdf_alloc(sd, weight);
-
- if (bssrdf) {
- /* disable in case of diffuse ancestor, can't see it well then and
- * adds considerably noise due to probabilities of continuing path
- * getting lower and lower */
- if (path_flag & PATH_RAY_DIFFUSE_ANCESTOR) {
- params.radius = make_float3(0.0f, 0.0f, 0.0f);
- }
-
- /* create one closure per color channel */
- bssrdf->radius = params.radius;
- bssrdf->albedo = params.albedo;
- bssrdf->N = params.N;
- bssrdf->roughness = params.roughness;
- bssrdf->anisotropy = clamp(params.anisotropy, 0.0f, 0.9f);
- sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)type, clamp(ior, 1.01f, 3.8f));
- }
- }
-};
-
-ClosureParam *closure_bssrdf_params()
-{
- static ClosureParam params[] = {
- CLOSURE_STRING_PARAM(CBSSRDFClosure, method),
- CLOSURE_FLOAT3_PARAM(CBSSRDFClosure, params.N),
- CLOSURE_FLOAT3_PARAM(CBSSRDFClosure, params.radius),
- CLOSURE_FLOAT3_PARAM(CBSSRDFClosure, params.albedo),
- CLOSURE_FLOAT_KEYPARAM(CBSSRDFClosure, params.roughness, "roughness"),
- CLOSURE_FLOAT_KEYPARAM(CBSSRDFClosure, ior, "ior"),
- CLOSURE_FLOAT_KEYPARAM(CBSSRDFClosure, params.anisotropy, "anisotropy"),
- CLOSURE_STRING_KEYPARAM(CBSSRDFClosure, label, "label"),
- CLOSURE_FINISH_PARAM(CBSSRDFClosure)};
- return params;
-}
-
-CCLOSURE_PREPARE(closure_bssrdf_prepare, CBSSRDFClosure)
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
deleted file mode 100644
index a2062046ae8..00000000000
--- a/intern/cycles/kernel/osl/osl_closures.cpp
+++ /dev/null
@@ -1,1008 +0,0 @@
-/*
- * Adapted from Open Shading Language with this license:
- *
- * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
- * All Rights Reserved.
- *
- * Modifications Copyright 2011-2018, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Sony Pictures Imageworks nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <OSL/genclosure.h>
-#include <OSL/oslclosure.h>
-
-#include "kernel/osl/osl_closures.h"
-#include "kernel/osl/osl_shader.h"
-
-#include "util/util_math.h"
-#include "util/util_param.h"
-
-// clang-format off
-#include "kernel/device/cpu/compat.h"
-#include "kernel/device/cpu/globals.h"
-
-#include "kernel/kernel_types.h"
-#include "kernel/kernel_montecarlo.h"
-#include "kernel/kernel_random.h"
-
-#include "kernel/closure/alloc.h"
-#include "kernel/closure/bsdf_util.h"
-#include "kernel/closure/bsdf_ashikhmin_velvet.h"
-#include "kernel/closure/bsdf_diffuse.h"
-#include "kernel/closure/bsdf_microfacet.h"
-#include "kernel/closure/bsdf_microfacet_multi.h"
-#include "kernel/closure/bsdf_oren_nayar.h"
-#include "kernel/closure/bsdf_reflection.h"
-#include "kernel/closure/bsdf_refraction.h"
-#include "kernel/closure/bsdf_transparent.h"
-#include "kernel/closure/bsdf_ashikhmin_shirley.h"
-#include "kernel/closure/bsdf_toon.h"
-#include "kernel/closure/bsdf_hair.h"
-#include "kernel/closure/bsdf_hair_principled.h"
-#include "kernel/closure/bsdf_principled_diffuse.h"
-#include "kernel/closure/bsdf_principled_sheen.h"
-#include "kernel/closure/volume.h"
-// clang-format on
-
-CCL_NAMESPACE_BEGIN
-
-using namespace OSL;
-
-/* BSDF class definitions */
-
-BSDF_CLOSURE_CLASS_BEGIN(Diffuse, diffuse, DiffuseBsdf, LABEL_DIFFUSE)
- BSDF_CLOSURE_FLOAT3_PARAM(DiffuseClosure, params.N)
-BSDF_CLOSURE_CLASS_END(Diffuse, diffuse)
-
-BSDF_CLOSURE_CLASS_BEGIN(Translucent, translucent, DiffuseBsdf, LABEL_DIFFUSE)
- BSDF_CLOSURE_FLOAT3_PARAM(TranslucentClosure, params.N)
-BSDF_CLOSURE_CLASS_END(Translucent, translucent)
-
-BSDF_CLOSURE_CLASS_BEGIN(OrenNayar, oren_nayar, OrenNayarBsdf, LABEL_DIFFUSE)
- BSDF_CLOSURE_FLOAT3_PARAM(OrenNayarClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(OrenNayarClosure, params.roughness)
-BSDF_CLOSURE_CLASS_END(OrenNayar, oren_nayar)
-
-BSDF_CLOSURE_CLASS_BEGIN(Reflection, reflection, MicrofacetBsdf, LABEL_SINGULAR)
- BSDF_CLOSURE_FLOAT3_PARAM(ReflectionClosure, params.N)
-BSDF_CLOSURE_CLASS_END(Reflection, reflection)
-
-BSDF_CLOSURE_CLASS_BEGIN(Refraction, refraction, MicrofacetBsdf, LABEL_SINGULAR)
- BSDF_CLOSURE_FLOAT3_PARAM(RefractionClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(RefractionClosure, params.ior)
-BSDF_CLOSURE_CLASS_END(Refraction, refraction)
-
-BSDF_CLOSURE_CLASS_BEGIN(AshikhminVelvet, ashikhmin_velvet, VelvetBsdf, LABEL_DIFFUSE)
- BSDF_CLOSURE_FLOAT3_PARAM(AshikhminVelvetClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(AshikhminVelvetClosure, params.sigma)
-BSDF_CLOSURE_CLASS_END(AshikhminVelvet, ashikhmin_velvet)
-
-BSDF_CLOSURE_CLASS_BEGIN(AshikhminShirley,
- ashikhmin_shirley,
- MicrofacetBsdf,
- LABEL_GLOSSY | LABEL_REFLECT)
- BSDF_CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, params.N)
- BSDF_CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, params.T)
- BSDF_CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, params.alpha_x)
- BSDF_CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, params.alpha_y)
-BSDF_CLOSURE_CLASS_END(AshikhminShirley, ashikhmin_shirley)
-
-BSDF_CLOSURE_CLASS_BEGIN(DiffuseToon, diffuse_toon, ToonBsdf, LABEL_DIFFUSE)
- BSDF_CLOSURE_FLOAT3_PARAM(DiffuseToonClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(DiffuseToonClosure, params.size)
- BSDF_CLOSURE_FLOAT_PARAM(DiffuseToonClosure, params.smooth)
-BSDF_CLOSURE_CLASS_END(DiffuseToon, diffuse_toon)
-
-BSDF_CLOSURE_CLASS_BEGIN(GlossyToon, glossy_toon, ToonBsdf, LABEL_GLOSSY)
- BSDF_CLOSURE_FLOAT3_PARAM(GlossyToonClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(GlossyToonClosure, params.size)
- BSDF_CLOSURE_FLOAT_PARAM(GlossyToonClosure, params.smooth)
-BSDF_CLOSURE_CLASS_END(GlossyToon, glossy_toon)
-
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXIsotropic,
- microfacet_ggx_isotropic,
- MicrofacetBsdf,
- LABEL_GLOSSY | LABEL_REFLECT)
- BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetGGXIsotropicClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(MicrofacetGGXIsotropicClosure, params.alpha_x)
-BSDF_CLOSURE_CLASS_END(MicrofacetGGXIsotropic, microfacet_ggx_isotropic)
-
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGX,
- microfacet_ggx,
- MicrofacetBsdf,
- LABEL_GLOSSY | LABEL_REFLECT)
- BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetGGXClosure, params.N)
- BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetGGXClosure, params.T)
- BSDF_CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure, params.alpha_x)
- BSDF_CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure, params.alpha_y)
-BSDF_CLOSURE_CLASS_END(MicrofacetGGX, microfacet_ggx)
-
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannIsotropic,
- microfacet_beckmann_isotropic,
- MicrofacetBsdf,
- LABEL_GLOSSY | LABEL_REFLECT)
- BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannIsotropicClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(MicrofacetBeckmannIsotropicClosure, params.alpha_x)
-BSDF_CLOSURE_CLASS_END(MicrofacetBeckmannIsotropic, microfacet_beckmann_isotropic)
-
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmann,
- microfacet_beckmann,
- MicrofacetBsdf,
- LABEL_GLOSSY | LABEL_REFLECT)
- BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannClosure, params.N)
- BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannClosure, params.T)
- BSDF_CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure, params.alpha_x)
- BSDF_CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure, params.alpha_y)
-BSDF_CLOSURE_CLASS_END(MicrofacetBeckmann, microfacet_beckmann)
-
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXRefraction,
- microfacet_ggx_refraction,
- MicrofacetBsdf,
- LABEL_GLOSSY | LABEL_TRANSMIT)
- BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetGGXRefractionClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, params.alpha_x)
- BSDF_CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, params.ior)
-BSDF_CLOSURE_CLASS_END(MicrofacetGGXRefraction, microfacet_ggx_refraction)
-
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannRefraction,
- microfacet_beckmann_refraction,
- MicrofacetBsdf,
- LABEL_GLOSSY | LABEL_TRANSMIT)
- BSDF_CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannRefractionClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, params.alpha_x)
- BSDF_CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, params.ior)
-BSDF_CLOSURE_CLASS_END(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction)
-
-BSDF_CLOSURE_CLASS_BEGIN(HairReflection, hair_reflection, HairBsdf, LABEL_GLOSSY)
- BSDF_CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.roughness1)
- BSDF_CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.roughness2)
- BSDF_CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.T)
- BSDF_CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.offset)
-BSDF_CLOSURE_CLASS_END(HairReflection, hair_reflection)
-
-BSDF_CLOSURE_CLASS_BEGIN(HairTransmission, hair_transmission, HairBsdf, LABEL_GLOSSY)
- BSDF_CLOSURE_FLOAT3_PARAM(HairTransmissionClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(HairTransmissionClosure, params.roughness1)
- BSDF_CLOSURE_FLOAT_PARAM(HairTransmissionClosure, params.roughness2)
- BSDF_CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.T)
- BSDF_CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.offset)
-BSDF_CLOSURE_CLASS_END(HairTransmission, hair_transmission)
-
-BSDF_CLOSURE_CLASS_BEGIN(PrincipledDiffuse,
- principled_diffuse,
- PrincipledDiffuseBsdf,
- LABEL_DIFFUSE)
- BSDF_CLOSURE_FLOAT3_PARAM(PrincipledDiffuseClosure, params.N)
- BSDF_CLOSURE_FLOAT_PARAM(PrincipledDiffuseClosure, params.roughness)
-BSDF_CLOSURE_CLASS_END(PrincipledDiffuse, principled_diffuse)
-
-class PrincipledSheenClosure : public CBSDFClosure {
- public:
- PrincipledSheenBsdf params;
-
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- if (!skip(sd, path_flag, LABEL_DIFFUSE)) {
- PrincipledSheenBsdf *bsdf = (PrincipledSheenBsdf *)bsdf_alloc_osl(
- sd, sizeof(PrincipledSheenBsdf), weight, &params);
- sd->flag |= (bsdf) ? bsdf_principled_sheen_setup(sd, bsdf) : 0;
- }
- }
-};
-
-static ClosureParam *bsdf_principled_sheen_params()
-{
- static ClosureParam params[] = {CLOSURE_FLOAT3_PARAM(PrincipledSheenClosure, params.N),
- CLOSURE_STRING_KEYPARAM(PrincipledSheenClosure, label, "label"),
- CLOSURE_FINISH_PARAM(PrincipledSheenClosure)};
- return params;
-}
-
-CCLOSURE_PREPARE_STATIC(closure_bsdf_principled_sheen_prepare, PrincipledSheenClosure)
-
-/* PRINCIPLED HAIR BSDF */
-class PrincipledHairClosure : public CBSDFClosure {
- public:
- PrincipledHairBSDF params;
-
- PrincipledHairBSDF *alloc(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)bsdf_alloc_osl(
- sd, sizeof(PrincipledHairBSDF), weight, &params);
- if (!bsdf) {
- return NULL;
- }
-
- PrincipledHairExtra *extra = (PrincipledHairExtra *)closure_alloc_extra(
- sd, sizeof(PrincipledHairExtra));
- if (!extra) {
- return NULL;
- }
-
- bsdf->extra = extra;
- return bsdf;
- }
-
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- if (!skip(sd, path_flag, LABEL_GLOSSY)) {
- PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)alloc(sd, path_flag, weight);
- if (!bsdf) {
- return;
- }
-
- sd->flag |= (bsdf) ? bsdf_principled_hair_setup(sd, bsdf) : 0;
- }
- }
-};
-
-static ClosureParam *closure_bsdf_principled_hair_params()
-{
- static ClosureParam params[] = {CLOSURE_FLOAT3_PARAM(PrincipledHairClosure, params.N),
- CLOSURE_FLOAT3_PARAM(PrincipledHairClosure, params.sigma),
- CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.v),
- CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.s),
- CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.m0_roughness),
- CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.alpha),
- CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.eta),
- CLOSURE_STRING_KEYPARAM(PrincipledHairClosure, label, "label"),
- CLOSURE_FINISH_PARAM(PrincipledHairClosure)};
-
- return params;
-}
-
-CCLOSURE_PREPARE(closure_bsdf_principled_hair_prepare, PrincipledHairClosure)
-
-/* DISNEY PRINCIPLED CLEARCOAT */
-class PrincipledClearcoatClosure : public CBSDFClosure {
- public:
- MicrofacetBsdf params;
- float clearcoat, clearcoat_roughness;
-
- MicrofacetBsdf *alloc(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc_osl(
- sd, sizeof(MicrofacetBsdf), weight, &params);
- if (!bsdf) {
- return NULL;
- }
-
- MicrofacetExtra *extra = (MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
- if (!extra) {
- return NULL;
- }
-
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra = extra;
- bsdf->ior = 1.5f;
- bsdf->alpha_x = clearcoat_roughness;
- bsdf->alpha_y = clearcoat_roughness;
- bsdf->extra->color = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra->cspec0 = make_float3(0.04f, 0.04f, 0.04f);
- bsdf->extra->clearcoat = clearcoat;
- return bsdf;
- }
-
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
- if (!bsdf) {
- return;
- }
-
- sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(bsdf, sd);
- }
-};
-
-ClosureParam *closure_bsdf_principled_clearcoat_params()
-{
- static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(PrincipledClearcoatClosure, params.N),
- CLOSURE_FLOAT_PARAM(PrincipledClearcoatClosure, clearcoat),
- CLOSURE_FLOAT_PARAM(PrincipledClearcoatClosure, clearcoat_roughness),
- CLOSURE_STRING_KEYPARAM(PrincipledClearcoatClosure, label, "label"),
- CLOSURE_FINISH_PARAM(PrincipledClearcoatClosure)};
- return params;
-}
-CCLOSURE_PREPARE(closure_bsdf_principled_clearcoat_prepare, PrincipledClearcoatClosure)
-
-/* Registration */
-
-static void register_closure(OSL::ShadingSystem *ss,
- const char *name,
- int id,
- OSL::ClosureParam *params,
- OSL::PrepareClosureFunc prepare)
-{
- /* optimization: it's possible to not use a prepare function at all and
- * only initialize the actual class when accessing the closure component
- * data, but then we need to map the id to the class somehow */
-#if OSL_LIBRARY_VERSION_CODE >= 10900
- ss->register_closure(name, id, params, prepare, NULL);
-#else
- ss->register_closure(name, id, params, prepare, NULL, 16);
-#endif
-}
-
-void OSLShader::register_closures(OSLShadingSystem *ss_)
-{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)ss_;
- int id = 0;
-
- register_closure(ss, "diffuse", id++, bsdf_diffuse_params(), bsdf_diffuse_prepare);
- register_closure(ss, "oren_nayar", id++, bsdf_oren_nayar_params(), bsdf_oren_nayar_prepare);
- register_closure(ss, "translucent", id++, bsdf_translucent_params(), bsdf_translucent_prepare);
- register_closure(ss, "reflection", id++, bsdf_reflection_params(), bsdf_reflection_prepare);
- register_closure(ss, "refraction", id++, bsdf_refraction_params(), bsdf_refraction_prepare);
- register_closure(ss,
- "transparent",
- id++,
- closure_bsdf_transparent_params(),
- closure_bsdf_transparent_prepare);
-
- register_closure(
- ss, "microfacet", id++, closure_bsdf_microfacet_params(), closure_bsdf_microfacet_prepare);
- register_closure(ss,
- "microfacet_ggx",
- id++,
- bsdf_microfacet_ggx_isotropic_params(),
- bsdf_microfacet_ggx_isotropic_prepare);
- register_closure(
- ss, "microfacet_ggx_aniso", id++, bsdf_microfacet_ggx_params(), bsdf_microfacet_ggx_prepare);
- register_closure(ss,
- "microfacet_ggx_refraction",
- id++,
- bsdf_microfacet_ggx_refraction_params(),
- bsdf_microfacet_ggx_refraction_prepare);
- register_closure(ss,
- "microfacet_multi_ggx",
- id++,
- closure_bsdf_microfacet_multi_ggx_params(),
- closure_bsdf_microfacet_multi_ggx_prepare);
- register_closure(ss,
- "microfacet_multi_ggx_glass",
- id++,
- closure_bsdf_microfacet_multi_ggx_glass_params(),
- closure_bsdf_microfacet_multi_ggx_glass_prepare);
- register_closure(ss,
- "microfacet_multi_ggx_aniso",
- id++,
- closure_bsdf_microfacet_multi_ggx_aniso_params(),
- closure_bsdf_microfacet_multi_ggx_aniso_prepare);
- register_closure(ss,
- "microfacet_ggx_fresnel",
- id++,
- closure_bsdf_microfacet_ggx_fresnel_params(),
- closure_bsdf_microfacet_ggx_fresnel_prepare);
- register_closure(ss,
- "microfacet_ggx_aniso_fresnel",
- id++,
- closure_bsdf_microfacet_ggx_aniso_fresnel_params(),
- closure_bsdf_microfacet_ggx_aniso_fresnel_prepare);
- register_closure(ss,
- "microfacet_multi_ggx_fresnel",
- id++,
- closure_bsdf_microfacet_multi_ggx_fresnel_params(),
- closure_bsdf_microfacet_multi_ggx_fresnel_prepare);
- register_closure(ss,
- "microfacet_multi_ggx_glass_fresnel",
- id++,
- closure_bsdf_microfacet_multi_ggx_glass_fresnel_params(),
- closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare);
- register_closure(ss,
- "microfacet_multi_ggx_aniso_fresnel",
- id++,
- closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params(),
- closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare);
- register_closure(ss,
- "microfacet_beckmann",
- id++,
- bsdf_microfacet_beckmann_isotropic_params(),
- bsdf_microfacet_beckmann_isotropic_prepare);
- register_closure(ss,
- "microfacet_beckmann_aniso",
- id++,
- bsdf_microfacet_beckmann_params(),
- bsdf_microfacet_beckmann_prepare);
- register_closure(ss,
- "microfacet_beckmann_refraction",
- id++,
- bsdf_microfacet_beckmann_refraction_params(),
- bsdf_microfacet_beckmann_refraction_prepare);
- register_closure(ss,
- "ashikhmin_shirley",
- id++,
- bsdf_ashikhmin_shirley_params(),
- bsdf_ashikhmin_shirley_prepare);
- register_closure(
- ss, "ashikhmin_velvet", id++, bsdf_ashikhmin_velvet_params(), bsdf_ashikhmin_velvet_prepare);
- register_closure(
- ss, "diffuse_toon", id++, bsdf_diffuse_toon_params(), bsdf_diffuse_toon_prepare);
- register_closure(ss, "glossy_toon", id++, bsdf_glossy_toon_params(), bsdf_glossy_toon_prepare);
- register_closure(ss,
- "principled_diffuse",
- id++,
- bsdf_principled_diffuse_params(),
- bsdf_principled_diffuse_prepare);
- register_closure(ss,
- "principled_sheen",
- id++,
- bsdf_principled_sheen_params(),
- closure_bsdf_principled_sheen_prepare);
- register_closure(ss,
- "principled_clearcoat",
- id++,
- closure_bsdf_principled_clearcoat_params(),
- closure_bsdf_principled_clearcoat_prepare);
-
- register_closure(ss, "emission", id++, closure_emission_params(), closure_emission_prepare);
- register_closure(
- ss, "background", id++, closure_background_params(), closure_background_prepare);
- register_closure(ss, "holdout", id++, closure_holdout_params(), closure_holdout_prepare);
- register_closure(ss,
- "diffuse_ramp",
- id++,
- closure_bsdf_diffuse_ramp_params(),
- closure_bsdf_diffuse_ramp_prepare);
- register_closure(
- ss, "phong_ramp", id++, closure_bsdf_phong_ramp_params(), closure_bsdf_phong_ramp_prepare);
- register_closure(ss, "bssrdf", id++, closure_bssrdf_params(), closure_bssrdf_prepare);
-
- register_closure(
- ss, "hair_reflection", id++, bsdf_hair_reflection_params(), bsdf_hair_reflection_prepare);
- register_closure(ss,
- "hair_transmission",
- id++,
- bsdf_hair_transmission_params(),
- bsdf_hair_transmission_prepare);
-
- register_closure(ss,
- "principled_hair",
- id++,
- closure_bsdf_principled_hair_params(),
- closure_bsdf_principled_hair_prepare);
-
- register_closure(ss,
- "henyey_greenstein",
- id++,
- closure_henyey_greenstein_params(),
- closure_henyey_greenstein_prepare);
- register_closure(
- ss, "absorption", id++, closure_absorption_params(), closure_absorption_prepare);
-}
-
-/* BSDF Closure */
-
-bool CBSDFClosure::skip(const ShaderData *sd, uint32_t path_flag, int scattering)
-{
- /* caustic options */
- if ((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) {
- const KernelGlobalsCPU *kg = sd->osl_globals;
-
- if ((!kernel_data.integrator.caustics_reflective && (scattering & LABEL_REFLECT)) ||
- (!kernel_data.integrator.caustics_refractive && (scattering & LABEL_TRANSMIT))) {
- return true;
- }
- }
-
- return false;
-}
-
-/* Standard Microfacet Closure */
-
-class MicrofacetClosure : public CBSDFClosure {
- public:
- MicrofacetBsdf params;
- ustring distribution;
- int refract;
-
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- static ustring u_ggx("ggx");
- static ustring u_default("default");
-
- const int label = (refract) ? LABEL_TRANSMIT : LABEL_REFLECT;
- if (skip(sd, path_flag, LABEL_GLOSSY | label)) {
- return;
- }
-
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc_osl(
- sd, sizeof(MicrofacetBsdf), weight, &params);
-
- if (!bsdf) {
- return;
- }
-
- /* GGX */
- if (distribution == u_ggx || distribution == u_default) {
- if (!refract) {
- if (params.alpha_x == params.alpha_y) {
- /* Isotropic */
- sd->flag |= bsdf_microfacet_ggx_isotropic_setup(bsdf);
- }
- else {
- /* Anisotropic */
- sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
- }
- }
- else {
- sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
- }
- }
- /* Beckmann */
- else {
- if (!refract) {
- if (params.alpha_x == params.alpha_y) {
- /* Isotropic */
- sd->flag |= bsdf_microfacet_beckmann_isotropic_setup(bsdf);
- }
- else {
- /* Anisotropic */
- sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
- }
- }
- else {
- sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
- }
- }
- }
-};
-
-ClosureParam *closure_bsdf_microfacet_params()
-{
- static ClosureParam params[] = {CLOSURE_STRING_PARAM(MicrofacetClosure, distribution),
- CLOSURE_FLOAT3_PARAM(MicrofacetClosure, params.N),
- CLOSURE_FLOAT3_PARAM(MicrofacetClosure, params.T),
- CLOSURE_FLOAT_PARAM(MicrofacetClosure, params.alpha_x),
- CLOSURE_FLOAT_PARAM(MicrofacetClosure, params.alpha_y),
- CLOSURE_FLOAT_PARAM(MicrofacetClosure, params.ior),
- CLOSURE_INT_PARAM(MicrofacetClosure, refract),
- CLOSURE_STRING_KEYPARAM(MicrofacetClosure, label, "label"),
- CLOSURE_FINISH_PARAM(MicrofacetClosure)};
-
- return params;
-}
-CCLOSURE_PREPARE(closure_bsdf_microfacet_prepare, MicrofacetClosure)
-
-/* GGX closures with Fresnel */
-
-class MicrofacetFresnelClosure : public CBSDFClosure {
- public:
- MicrofacetBsdf params;
- float3 color;
- float3 cspec0;
-
- MicrofacetBsdf *alloc(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- /* Technically, the MultiGGX Glass closure may also transmit. However,
- * since this is set statically and only used for caustic flags, this
- * is probably as good as it gets. */
- if (skip(sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
- return NULL;
- }
-
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc_osl(
- sd, sizeof(MicrofacetBsdf), weight, &params);
- if (!bsdf) {
- return NULL;
- }
-
- MicrofacetExtra *extra = (MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
- if (!extra) {
- return NULL;
- }
-
- bsdf->extra = extra;
- bsdf->extra->color = color;
- bsdf->extra->cspec0 = cspec0;
- bsdf->extra->clearcoat = 0.0f;
- return bsdf;
- }
-};
-
-class MicrofacetGGXFresnelClosure : public MicrofacetFresnelClosure {
- public:
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
- if (!bsdf) {
- return;
- }
-
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->alpha_y = bsdf->alpha_x;
- sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd);
- }
-};
-
-ClosureParam *closure_bsdf_microfacet_ggx_fresnel_params()
-{
- static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.N),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_x),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.ior),
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, color),
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, cspec0),
- CLOSURE_STRING_KEYPARAM(MicrofacetGGXFresnelClosure, label, "label"),
- CLOSURE_FINISH_PARAM(MicrofacetGGXFresnelClosure)};
- return params;
-}
-CCLOSURE_PREPARE(closure_bsdf_microfacet_ggx_fresnel_prepare, MicrofacetGGXFresnelClosure);
-
-class MicrofacetGGXAnisoFresnelClosure : public MicrofacetFresnelClosure {
- public:
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
- if (!bsdf) {
- return;
- }
-
- sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd);
- }
-};
-
-ClosureParam *closure_bsdf_microfacet_ggx_aniso_fresnel_params()
-{
- static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.N),
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.T),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_x),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_y),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.ior),
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, color),
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, cspec0),
- CLOSURE_STRING_KEYPARAM(MicrofacetGGXFresnelClosure, label, "label"),
- CLOSURE_FINISH_PARAM(MicrofacetGGXFresnelClosure)};
- return params;
-}
-CCLOSURE_PREPARE(closure_bsdf_microfacet_ggx_aniso_fresnel_prepare,
- MicrofacetGGXAnisoFresnelClosure);
-
-/* Multiscattering GGX closures */
-
-class MicrofacetMultiClosure : public CBSDFClosure {
- public:
- MicrofacetBsdf params;
- float3 color;
-
- MicrofacetBsdf *alloc(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- /* Technically, the MultiGGX closure may also transmit. However,
- * since this is set statically and only used for caustic flags, this
- * is probably as good as it gets. */
- if (skip(sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
- return NULL;
- }
-
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc_osl(
- sd, sizeof(MicrofacetBsdf), weight, &params);
- if (!bsdf) {
- return NULL;
- }
-
- MicrofacetExtra *extra = (MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
- if (!extra) {
- return NULL;
- }
-
- bsdf->extra = extra;
- bsdf->extra->color = color;
- bsdf->extra->cspec0 = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra->clearcoat = 0.0f;
- return bsdf;
- }
-};
-
-class MicrofacetMultiGGXClosure : public MicrofacetMultiClosure {
- public:
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
- if (!bsdf) {
- return;
- }
-
- bsdf->ior = 0.0f;
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->alpha_y = bsdf->alpha_x;
- sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf);
- }
-};
-
-ClosureParam *closure_bsdf_microfacet_multi_ggx_params()
-{
- static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
- CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
- CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)};
- return params;
-}
-CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_prepare, MicrofacetMultiGGXClosure);
-
-class MicrofacetMultiGGXAnisoClosure : public MicrofacetMultiClosure {
- public:
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
- if (!bsdf) {
- return;
- }
-
- bsdf->ior = 0.0f;
- sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf);
- }
-};
-
-ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params()
-{
- static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.T),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_y),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
- CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
- CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)};
- return params;
-}
-CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_prepare, MicrofacetMultiGGXAnisoClosure);
-
-class MicrofacetMultiGGXGlassClosure : public MicrofacetMultiClosure {
- public:
- MicrofacetMultiGGXGlassClosure() : MicrofacetMultiClosure()
- {
- }
-
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
- if (!bsdf) {
- return;
- }
-
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->alpha_y = bsdf->alpha_x;
- sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(bsdf);
- }
-};
-
-ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params()
-{
- static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.ior),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
- CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
- CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)};
- return params;
-}
-CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure);
-
-/* Multiscattering GGX closures with Fresnel */
-
-class MicrofacetMultiFresnelClosure : public CBSDFClosure {
- public:
- MicrofacetBsdf params;
- float3 color;
- float3 cspec0;
-
- MicrofacetBsdf *alloc(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- /* Technically, the MultiGGX closure may also transmit. However,
- * since this is set statically and only used for caustic flags, this
- * is probably as good as it gets. */
- if (skip(sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
- return NULL;
- }
-
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc_osl(
- sd, sizeof(MicrofacetBsdf), weight, &params);
- if (!bsdf) {
- return NULL;
- }
-
- MicrofacetExtra *extra = (MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
- if (!extra) {
- return NULL;
- }
-
- bsdf->extra = extra;
- bsdf->extra->color = color;
- bsdf->extra->cspec0 = cspec0;
- bsdf->extra->clearcoat = 0.0f;
- return bsdf;
- }
-};
-
-class MicrofacetMultiGGXFresnelClosure : public MicrofacetMultiFresnelClosure {
- public:
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
- if (!bsdf) {
- return;
- }
-
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->alpha_y = bsdf->alpha_x;
- sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd);
- }
-};
-
-ClosureParam *closure_bsdf_microfacet_multi_ggx_fresnel_params()
-{
- static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0),
- CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"),
- CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure)};
- return params;
-}
-CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_fresnel_prepare,
- MicrofacetMultiGGXFresnelClosure);
-
-class MicrofacetMultiGGXAnisoFresnelClosure : public MicrofacetMultiFresnelClosure {
- public:
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
- if (!bsdf) {
- return;
- }
-
- sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd);
- }
-};
-
-ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params()
-{
- static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.T),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_y),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0),
- CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"),
- CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure)};
- return params;
-}
-CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare,
- MicrofacetMultiGGXAnisoFresnelClosure);
-
-class MicrofacetMultiGGXGlassFresnelClosure : public MicrofacetMultiFresnelClosure {
- public:
- MicrofacetMultiGGXGlassFresnelClosure() : MicrofacetMultiFresnelClosure()
- {
- }
-
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
- if (!bsdf) {
- return;
- }
-
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->alpha_y = bsdf->alpha_x;
- sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf, sd);
- }
-};
-
-ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_fresnel_params()
-{
- static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x),
- CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color),
- CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0),
- CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"),
- CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure)};
- return params;
-}
-CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare,
- MicrofacetMultiGGXGlassFresnelClosure);
-
-/* Transparent */
-
-class TransparentClosure : public CBSDFClosure {
- public:
- ShaderClosure params;
- float3 unused;
-
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- bsdf_transparent_setup(sd, weight, path_flag);
- }
-};
-
-ClosureParam *closure_bsdf_transparent_params()
-{
- static ClosureParam params[] = {CLOSURE_STRING_KEYPARAM(TransparentClosure, label, "label"),
- CLOSURE_FINISH_PARAM(TransparentClosure)};
- return params;
-}
-
-CCLOSURE_PREPARE(closure_bsdf_transparent_prepare, TransparentClosure)
-
-/* Volume */
-
-class VolumeAbsorptionClosure : public CBSDFClosure {
- public:
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- volume_extinction_setup(sd, weight);
- }
-};
-
-ClosureParam *closure_absorption_params()
-{
- static ClosureParam params[] = {CLOSURE_STRING_KEYPARAM(VolumeAbsorptionClosure, label, "label"),
- CLOSURE_FINISH_PARAM(VolumeAbsorptionClosure)};
- return params;
-}
-
-CCLOSURE_PREPARE(closure_absorption_prepare, VolumeAbsorptionClosure)
-
-class VolumeHenyeyGreensteinClosure : public CBSDFClosure {
- public:
- HenyeyGreensteinVolume params;
-
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight)
- {
- volume_extinction_setup(sd, weight);
-
- HenyeyGreensteinVolume *volume = (HenyeyGreensteinVolume *)bsdf_alloc_osl(
- sd, sizeof(HenyeyGreensteinVolume), weight, &params);
- if (!volume) {
- return;
- }
-
- sd->flag |= volume_henyey_greenstein_setup(volume);
- }
-};
-
-ClosureParam *closure_henyey_greenstein_params()
-{
- static ClosureParam params[] = {
- CLOSURE_FLOAT_PARAM(VolumeHenyeyGreensteinClosure, params.g),
- CLOSURE_STRING_KEYPARAM(VolumeHenyeyGreensteinClosure, label, "label"),
- CLOSURE_FINISH_PARAM(VolumeHenyeyGreensteinClosure)};
- return params;
-}
-
-CCLOSURE_PREPARE(closure_henyey_greenstein_prepare, VolumeHenyeyGreensteinClosure)
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h
deleted file mode 100644
index 7869d793737..00000000000
--- a/intern/cycles/kernel/osl/osl_closures.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Adapted from Open Shading Language with this license:
- *
- * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
- * All Rights Reserved.
- *
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Sony Pictures Imageworks nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __OSL_CLOSURES_H__
-#define __OSL_CLOSURES_H__
-
-#include "kernel/kernel_types.h"
-#include "util/util_types.h"
-
-#include <OSL/genclosure.h>
-#include <OSL/oslclosure.h>
-#include <OSL/oslexec.h>
-
-CCL_NAMESPACE_BEGIN
-
-OSL::ClosureParam *closure_emission_params();
-OSL::ClosureParam *closure_background_params();
-OSL::ClosureParam *closure_holdout_params();
-OSL::ClosureParam *closure_bsdf_diffuse_ramp_params();
-OSL::ClosureParam *closure_bsdf_phong_ramp_params();
-OSL::ClosureParam *closure_bsdf_transparent_params();
-OSL::ClosureParam *closure_bssrdf_params();
-OSL::ClosureParam *closure_absorption_params();
-OSL::ClosureParam *closure_henyey_greenstein_params();
-OSL::ClosureParam *closure_bsdf_microfacet_params();
-OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_params();
-OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params();
-OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params();
-OSL::ClosureParam *closure_bsdf_microfacet_ggx_fresnel_params();
-OSL::ClosureParam *closure_bsdf_microfacet_ggx_aniso_fresnel_params();
-OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_fresnel_params();
-OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_fresnel_params();
-OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params();
-OSL::ClosureParam *closure_bsdf_principled_clearcoat_params();
-
-void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
-void closure_background_prepare(OSL::RendererServices *, int id, void *data);
-void closure_holdout_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bsdf_diffuse_ramp_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bsdf_phong_ramp_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bsdf_transparent_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bssrdf_prepare(OSL::RendererServices *, int id, void *data);
-void closure_absorption_prepare(OSL::RendererServices *, int id, void *data);
-void closure_henyey_greenstein_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bsdf_microfacet_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bsdf_microfacet_multi_ggx_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bsdf_microfacet_multi_ggx_glass_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bsdf_microfacet_multi_ggx_aniso_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bsdf_microfacet_ggx_fresnel_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bsdf_microfacet_ggx_aniso_fresnel_prepare(OSL::RendererServices *,
- int id,
- void *data);
-void closure_bsdf_microfacet_multi_ggx_fresnel_prepare(OSL::RendererServices *,
- int id,
- void *data);
-void closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare(OSL::RendererServices *,
- int id,
- void *data);
-void closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare(OSL::RendererServices *,
- int id,
- void *data);
-void closure_bsdf_principled_clearcoat_prepare(OSL::RendererServices *, int id, void *data);
-void closure_bsdf_principled_hair_prepare(OSL::RendererServices *, int id, void *data);
-
-#define CCLOSURE_PREPARE(name, classname) \
- void name(RendererServices *, int id, void *data) \
- { \
- memset(data, 0, sizeof(classname)); \
- new (data) classname(); \
- }
-
-#define CCLOSURE_PREPARE_STATIC(name, classname) static CCLOSURE_PREPARE(name, classname)
-
-#define CLOSURE_FLOAT3_PARAM(st, fld) \
- { \
- TypeDesc::TypeVector, (int)reckless_offsetof(st, fld), NULL, sizeof(OSL::Vec3) \
- }
-
-#define BSDF_CLOSURE_FLOAT_PARAM(st, fld) CLOSURE_FLOAT_PARAM(st, fld),
-#define BSDF_CLOSURE_FLOAT3_PARAM(st, fld) CLOSURE_FLOAT3_PARAM(st, fld),
-
-#define TO_VEC3(v) OSL::Vec3(v.x, v.y, v.z)
-#define TO_COLOR3(v) OSL::Color3(v.x, v.y, v.z)
-#define TO_FLOAT3(v) make_float3(v[0], v[1], v[2])
-
-/* Closure */
-
-class CClosurePrimitive {
- public:
- virtual void setup(ShaderData *sd, uint32_t path_flag, float3 weight) = 0;
-
- OSL::ustring label;
-};
-
-/* BSDF */
-
-class CBSDFClosure : public CClosurePrimitive {
- public:
- bool skip(const ShaderData *sd, uint32_t path_flag, int scattering);
-};
-
-#define BSDF_CLOSURE_CLASS_BEGIN(Upper, lower, structname, TYPE) \
-\
- class Upper##Closure : public CBSDFClosure { \
- public: \
- structname params; \
- float3 unused; \
-\
- void setup(ShaderData *sd, uint32_t path_flag, float3 weight) \
- { \
- if (!skip(sd, path_flag, TYPE)) { \
- structname *bsdf = (structname *)bsdf_alloc_osl(sd, sizeof(structname), weight, &params); \
- sd->flag |= (bsdf) ? bsdf_##lower##_setup(bsdf) : 0; \
- } \
- } \
- }; \
-\
- static ClosureParam *bsdf_##lower##_params() \
- { \
- static ClosureParam params[] = {
-
-/* parameters */
-
-#define BSDF_CLOSURE_CLASS_END(Upper, lower) \
- CLOSURE_STRING_KEYPARAM(Upper##Closure, label, "label"), CLOSURE_FINISH_PARAM(Upper##Closure) \
- } \
- ; \
- return params; \
- } \
-\
- CCLOSURE_PREPARE_STATIC(bsdf_##lower##_prepare, Upper##Closure)
-
-CCL_NAMESPACE_END
-
-#endif /* __OSL_CLOSURES_H__ */
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h
deleted file mode 100644
index f1789f0d7eb..00000000000
--- a/intern/cycles/kernel/osl/osl_globals.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __OSL_GLOBALS_H__
-#define __OSL_GLOBALS_H__
-
-#ifdef WITH_OSL
-
-# include <OSL/oslexec.h>
-
-# include <OpenImageIO/refcnt.h>
-# include <OpenImageIO/unordered_map_concurrent.h>
-
-# include "util/util_map.h"
-# include "util/util_param.h"
-# include "util/util_thread.h"
-# include "util/util_unique_ptr.h"
-# include "util/util_vector.h"
-
-# ifndef WIN32
-using std::isfinite;
-# endif
-
-CCL_NAMESPACE_BEGIN
-
-class OSLRenderServices;
-class ColorSpaceProcessor;
-
-/* OSL Globals
- *
- * Data needed by OSL render services, that is global to a rendering session.
- * This includes all OSL shaders, name to attribute mapping and texture handles.
- */
-
-struct OSLGlobals {
- OSLGlobals()
- {
- ss = NULL;
- ts = NULL;
- services = NULL;
- use = false;
- }
-
- bool use;
-
- /* shading system */
- OSL::ShadingSystem *ss;
- OSL::TextureSystem *ts;
- OSLRenderServices *services;
-
- /* shader states */
- vector<OSL::ShaderGroupRef> surface_state;
- vector<OSL::ShaderGroupRef> volume_state;
- vector<OSL::ShaderGroupRef> displacement_state;
- vector<OSL::ShaderGroupRef> bump_state;
- OSL::ShaderGroupRef background_state;
-
- /* attributes */
- struct Attribute {
- TypeDesc type;
- AttributeDescriptor desc;
- ParamValue value;
- };
-
- typedef unordered_map<ustring, Attribute, ustringHash> AttributeMap;
- typedef unordered_map<ustring, int, ustringHash> ObjectNameMap;
-
- vector<AttributeMap> attribute_map;
- ObjectNameMap object_name_map;
- vector<ustring> object_names;
-};
-
-/* trace() call result */
-struct OSLTraceData {
- Ray ray;
- Intersection isect;
- ShaderData sd;
- bool setup;
- bool init;
- bool hit;
-};
-
-/* thread key for thread specific data lookup */
-struct OSLThreadData {
- OSL::ShaderGlobals globals;
- OSL::PerThreadInfo *osl_thread_info;
- OSLTraceData tracedata;
- OSL::ShadingContext *context;
- OIIO::TextureSystem::Perthread *oiio_thread_info;
-};
-
-CCL_NAMESPACE_END
-
-#endif
-
-#endif /* __OSL_GLOBALS_H__ */
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
deleted file mode 100644
index cbe1bf1bfc0..00000000000
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ /dev/null
@@ -1,1721 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* TODO(sergey): There is a bit of headers dependency hell going on
- * here, so for now we just put here. In the future it might be better
- * to have dedicated file for such tweaks.
- */
-#if (defined(__GNUC__) && !defined(__clang__)) && defined(NDEBUG)
-# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-# pragma GCC diagnostic ignored "-Wuninitialized"
-#endif
-
-#include <string.h>
-
-#include "render/colorspace.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/scene.h"
-
-#include "kernel/osl/osl_closures.h"
-#include "kernel/osl/osl_globals.h"
-#include "kernel/osl/osl_services.h"
-#include "kernel/osl/osl_shader.h"
-
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_string.h"
-
-// clang-format off
-#include "kernel/device/cpu/compat.h"
-#include "kernel/device/cpu/globals.h"
-#include "kernel/device/cpu/image.h"
-
-#include "kernel/kernel_differential.h"
-
-#include "kernel/integrator/integrator_state.h"
-#include "kernel/integrator/integrator_state_flow.h"
-
-#include "kernel/geom/geom.h"
-#include "kernel/bvh/bvh.h"
-
-#include "kernel/kernel_color.h"
-#include "kernel/kernel_camera.h"
-#include "kernel/kernel_path_state.h"
-#include "kernel/kernel_projection.h"
-#include "kernel/kernel_shader.h"
-// clang-format on
-
-CCL_NAMESPACE_BEGIN
-
-/* RenderServices implementation */
-
-static void copy_matrix(OSL::Matrix44 &m, const Transform &tfm)
-{
- ProjectionTransform t = projection_transpose(ProjectionTransform(tfm));
- memcpy((void *)&m, &t, sizeof(m));
-}
-
-static void copy_matrix(OSL::Matrix44 &m, const ProjectionTransform &tfm)
-{
- ProjectionTransform t = projection_transpose(tfm);
- memcpy((void *)&m, &t, sizeof(m));
-}
-
-/* static ustrings */
-ustring OSLRenderServices::u_distance("distance");
-ustring OSLRenderServices::u_index("index");
-ustring OSLRenderServices::u_world("world");
-ustring OSLRenderServices::u_camera("camera");
-ustring OSLRenderServices::u_screen("screen");
-ustring OSLRenderServices::u_raster("raster");
-ustring OSLRenderServices::u_ndc("NDC");
-ustring OSLRenderServices::u_object_location("object:location");
-ustring OSLRenderServices::u_object_color("object:color");
-ustring OSLRenderServices::u_object_index("object:index");
-ustring OSLRenderServices::u_geom_dupli_generated("geom:dupli_generated");
-ustring OSLRenderServices::u_geom_dupli_uv("geom:dupli_uv");
-ustring OSLRenderServices::u_material_index("material:index");
-ustring OSLRenderServices::u_object_random("object:random");
-ustring OSLRenderServices::u_particle_index("particle:index");
-ustring OSLRenderServices::u_particle_random("particle:random");
-ustring OSLRenderServices::u_particle_age("particle:age");
-ustring OSLRenderServices::u_particle_lifetime("particle:lifetime");
-ustring OSLRenderServices::u_particle_location("particle:location");
-ustring OSLRenderServices::u_particle_rotation("particle:rotation");
-ustring OSLRenderServices::u_particle_size("particle:size");
-ustring OSLRenderServices::u_particle_velocity("particle:velocity");
-ustring OSLRenderServices::u_particle_angular_velocity("particle:angular_velocity");
-ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
-ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
-ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
-ustring OSLRenderServices::u_geom_name("geom:name");
-ustring OSLRenderServices::u_geom_undisplaced("geom:undisplaced");
-ustring OSLRenderServices::u_is_smooth("geom:is_smooth");
-ustring OSLRenderServices::u_is_curve("geom:is_curve");
-ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
-ustring OSLRenderServices::u_curve_length("geom:curve_length");
-ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
-ustring OSLRenderServices::u_curve_random("geom:curve_random");
-ustring OSLRenderServices::u_normal_map_normal("geom:normal_map_normal");
-ustring OSLRenderServices::u_path_ray_length("path:ray_length");
-ustring OSLRenderServices::u_path_ray_depth("path:ray_depth");
-ustring OSLRenderServices::u_path_diffuse_depth("path:diffuse_depth");
-ustring OSLRenderServices::u_path_glossy_depth("path:glossy_depth");
-ustring OSLRenderServices::u_path_transparent_depth("path:transparent_depth");
-ustring OSLRenderServices::u_path_transmission_depth("path:transmission_depth");
-ustring OSLRenderServices::u_trace("trace");
-ustring OSLRenderServices::u_hit("hit");
-ustring OSLRenderServices::u_hitdist("hitdist");
-ustring OSLRenderServices::u_N("N");
-ustring OSLRenderServices::u_Ng("Ng");
-ustring OSLRenderServices::u_P("P");
-ustring OSLRenderServices::u_I("I");
-ustring OSLRenderServices::u_u("u");
-ustring OSLRenderServices::u_v("v");
-ustring OSLRenderServices::u_empty;
-
-OSLRenderServices::OSLRenderServices(OSL::TextureSystem *texture_system)
- : texture_system(texture_system)
-{
-}
-
-OSLRenderServices::~OSLRenderServices()
-{
- if (texture_system) {
- VLOG(2) << "OSL texture system stats:\n" << texture_system->getstats();
- }
-}
-
-bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- OSL::TransformationPtr xform,
- float time)
-{
- /* this is only used for shader and object space, we don't really have
- * a concept of shader space, so we just use object space for both. */
- if (xform) {
- const ShaderData *sd = (const ShaderData *)xform;
- const KernelGlobalsCPU *kg = sd->osl_globals;
- int object = sd->object;
-
- if (object != OBJECT_NONE) {
-#ifdef __OBJECT_MOTION__
- Transform tfm;
-
- if (time == sd->time)
- tfm = object_get_transform(kg, sd);
- else
- tfm = object_fetch_transform_motion_test(kg, object, time, NULL);
-#else
- const Transform tfm = object_get_transform(kg, sd);
-#endif
- copy_matrix(result, tfm);
-
- return true;
- }
- else if (sd->type == PRIMITIVE_LAMP) {
- const Transform tfm = lamp_fetch_transform(kg, sd->lamp, false);
- copy_matrix(result, tfm);
-
- return true;
- }
- }
-
- return false;
-}
-
-bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- OSL::TransformationPtr xform,
- float time)
-{
- /* this is only used for shader and object space, we don't really have
- * a concept of shader space, so we just use object space for both. */
- if (xform) {
- const ShaderData *sd = (const ShaderData *)xform;
- const KernelGlobalsCPU *kg = sd->osl_globals;
- int object = sd->object;
-
- if (object != OBJECT_NONE) {
-#ifdef __OBJECT_MOTION__
- Transform itfm;
-
- if (time == sd->time)
- itfm = object_get_inverse_transform(kg, sd);
- else
- object_fetch_transform_motion_test(kg, object, time, &itfm);
-#else
- const Transform itfm = object_get_inverse_transform(kg, sd);
-#endif
- copy_matrix(result, itfm);
-
- return true;
- }
- else if (sd->type == PRIMITIVE_LAMP) {
- const Transform itfm = lamp_fetch_transform(kg, sd->lamp, true);
- copy_matrix(result, itfm);
-
- return true;
- }
- }
-
- return false;
-}
-
-bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- ustring from,
- float time)
-{
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- const KernelGlobalsCPU *kg = sd->osl_globals;
-
- if (from == u_ndc) {
- copy_matrix(result, kernel_data.cam.ndctoworld);
- return true;
- }
- else if (from == u_raster) {
- copy_matrix(result, kernel_data.cam.rastertoworld);
- return true;
- }
- else if (from == u_screen) {
- copy_matrix(result, kernel_data.cam.screentoworld);
- return true;
- }
- else if (from == u_camera) {
- copy_matrix(result, kernel_data.cam.cameratoworld);
- return true;
- }
- else if (from == u_world) {
- result.makeIdentity();
- return true;
- }
-
- return false;
-}
-
-bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- ustring to,
- float time)
-{
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- const KernelGlobalsCPU *kg = sd->osl_globals;
-
- if (to == u_ndc) {
- copy_matrix(result, kernel_data.cam.worldtondc);
- return true;
- }
- else if (to == u_raster) {
- copy_matrix(result, kernel_data.cam.worldtoraster);
- return true;
- }
- else if (to == u_screen) {
- copy_matrix(result, kernel_data.cam.worldtoscreen);
- return true;
- }
- else if (to == u_camera) {
- copy_matrix(result, kernel_data.cam.worldtocamera);
- return true;
- }
- else if (to == u_world) {
- result.makeIdentity();
- return true;
- }
-
- return false;
-}
-
-bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- OSL::TransformationPtr xform)
-{
- /* this is only used for shader and object space, we don't really have
- * a concept of shader space, so we just use object space for both. */
- if (xform) {
- const ShaderData *sd = (const ShaderData *)xform;
- const KernelGlobalsCPU *kg = sd->osl_globals;
- int object = sd->object;
-
- if (object != OBJECT_NONE) {
- const Transform tfm = object_get_transform(kg, sd);
- copy_matrix(result, tfm);
-
- return true;
- }
- else if (sd->type == PRIMITIVE_LAMP) {
- const Transform tfm = lamp_fetch_transform(kg, sd->lamp, false);
- copy_matrix(result, tfm);
-
- return true;
- }
- }
-
- return false;
-}
-
-bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- OSL::TransformationPtr xform)
-{
- /* this is only used for shader and object space, we don't really have
- * a concept of shader space, so we just use object space for both. */
- if (xform) {
- const ShaderData *sd = (const ShaderData *)xform;
- const KernelGlobalsCPU *kg = sd->osl_globals;
- int object = sd->object;
-
- if (object != OBJECT_NONE) {
- const Transform tfm = object_get_inverse_transform(kg, sd);
- copy_matrix(result, tfm);
-
- return true;
- }
- else if (sd->type == PRIMITIVE_LAMP) {
- const Transform itfm = lamp_fetch_transform(kg, sd->lamp, true);
- copy_matrix(result, itfm);
-
- return true;
- }
- }
-
- return false;
-}
-
-bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result, ustring from)
-{
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- const KernelGlobalsCPU *kg = sd->osl_globals;
-
- if (from == u_ndc) {
- copy_matrix(result, kernel_data.cam.ndctoworld);
- return true;
- }
- else if (from == u_raster) {
- copy_matrix(result, kernel_data.cam.rastertoworld);
- return true;
- }
- else if (from == u_screen) {
- copy_matrix(result, kernel_data.cam.screentoworld);
- return true;
- }
- else if (from == u_camera) {
- copy_matrix(result, kernel_data.cam.cameratoworld);
- return true;
- }
-
- return false;
-}
-
-bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- ustring to)
-{
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- const KernelGlobalsCPU *kg = sd->osl_globals;
-
- if (to == u_ndc) {
- copy_matrix(result, kernel_data.cam.worldtondc);
- return true;
- }
- else if (to == u_raster) {
- copy_matrix(result, kernel_data.cam.worldtoraster);
- return true;
- }
- else if (to == u_screen) {
- copy_matrix(result, kernel_data.cam.worldtoscreen);
- return true;
- }
- else if (to == u_camera) {
- copy_matrix(result, kernel_data.cam.worldtocamera);
- return true;
- }
-
- return false;
-}
-
-bool OSLRenderServices::get_array_attribute(OSL::ShaderGlobals *sg,
- bool derivatives,
- ustring object,
- TypeDesc type,
- ustring name,
- int index,
- void *val)
-{
- return false;
-}
-
-static bool set_attribute_float2(float2 f[3], TypeDesc type, bool derivatives, void *val)
-{
- if (type == TypeFloatArray4) {
- float *fval = (float *)val;
- fval[0] = f[0].x;
- fval[1] = f[0].y;
- fval[2] = 0.0f;
- fval[3] = 1.0f;
-
- if (derivatives) {
- fval[4] = f[1].x;
- fval[5] = f[1].y;
- fval[6] = 0.0f;
- fval[7] = 0.0f;
-
- fval[8] = f[2].x;
- fval[9] = f[2].y;
- fval[10] = 0.0f;
- fval[11] = 0.0f;
- }
- return true;
- }
- else if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
- type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
- float *fval = (float *)val;
-
- fval[0] = f[0].x;
- fval[1] = f[0].y;
- fval[2] = 0.0f;
-
- if (derivatives) {
- fval[3] = f[1].x;
- fval[4] = f[1].y;
- fval[5] = 0.0f;
-
- fval[6] = f[2].x;
- fval[7] = f[2].y;
- fval[8] = 0.0f;
- }
-
- return true;
- }
- else if (type == TypeDesc::TypeFloat) {
- float *fval = (float *)val;
- fval[0] = average(f[0]);
-
- if (derivatives) {
- fval[1] = average(f[1]);
- fval[2] = average(f[2]);
- }
-
- return true;
- }
-
- return false;
-}
-
-static bool set_attribute_float2(float2 f, TypeDesc type, bool derivatives, void *val)
-{
- float2 fv[3];
-
- fv[0] = f;
- fv[1] = make_float2(0.0f, 0.0f);
- fv[2] = make_float2(0.0f, 0.0f);
-
- return set_attribute_float2(fv, type, derivatives, val);
-}
-
-static bool set_attribute_float3(float3 f[3], TypeDesc type, bool derivatives, void *val)
-{
- if (type == TypeFloatArray4) {
- float *fval = (float *)val;
- fval[0] = f[0].x;
- fval[1] = f[0].y;
- fval[2] = f[0].z;
- fval[3] = 1.0f;
-
- if (derivatives) {
- fval[4] = f[1].x;
- fval[5] = f[1].y;
- fval[6] = f[1].z;
- fval[7] = 0.0f;
-
- fval[8] = f[2].x;
- fval[9] = f[2].y;
- fval[10] = f[2].z;
- fval[11] = 0.0f;
- }
- return true;
- }
- else if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
- type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
- float *fval = (float *)val;
-
- fval[0] = f[0].x;
- fval[1] = f[0].y;
- fval[2] = f[0].z;
-
- if (derivatives) {
- fval[3] = f[1].x;
- fval[4] = f[1].y;
- fval[5] = f[1].z;
-
- fval[6] = f[2].x;
- fval[7] = f[2].y;
- fval[8] = f[2].z;
- }
-
- return true;
- }
- else if (type == TypeDesc::TypeFloat) {
- float *fval = (float *)val;
- fval[0] = average(f[0]);
-
- if (derivatives) {
- fval[1] = average(f[1]);
- fval[2] = average(f[2]);
- }
-
- return true;
- }
-
- return false;
-}
-
-static bool set_attribute_float3(float3 f, TypeDesc type, bool derivatives, void *val)
-{
- float3 fv[3];
-
- fv[0] = f;
- fv[1] = make_float3(0.0f, 0.0f, 0.0f);
- fv[2] = make_float3(0.0f, 0.0f, 0.0f);
-
- return set_attribute_float3(fv, type, derivatives, val);
-}
-
-/* Attributes with the TypeRGBA type descriptor should be retrieved and stored
- * in a float array of size 4 (e.g. node_vertex_color.osl), this array have
- * a type descriptor TypeFloatArray4. If the storage is not a TypeFloatArray4,
- * we either store the first three components in a vector, store the average of
- * the components in a float, or fail the retrieval and do nothing. We allow
- * this for the correct operation of the Attribute node.
- */
-
-static bool set_attribute_float4(float4 f[3], TypeDesc type, bool derivatives, void *val)
-{
- float *fval = (float *)val;
- if (type == TypeFloatArray4) {
- fval[0] = f[0].x;
- fval[1] = f[0].y;
- fval[2] = f[0].z;
- fval[3] = f[0].w;
-
- if (derivatives) {
- fval[4] = f[1].x;
- fval[5] = f[1].y;
- fval[6] = f[1].z;
- fval[7] = f[1].w;
-
- fval[8] = f[2].x;
- fval[9] = f[2].y;
- fval[10] = f[2].z;
- fval[11] = f[2].w;
- }
- return true;
- }
- else if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
- type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
- fval[0] = f[0].x;
- fval[1] = f[0].y;
- fval[2] = f[0].z;
-
- if (derivatives) {
- fval[3] = f[1].x;
- fval[4] = f[1].y;
- fval[5] = f[1].z;
-
- fval[6] = f[2].x;
- fval[7] = f[2].y;
- fval[8] = f[2].z;
- }
- return true;
- }
- else if (type == TypeDesc::TypeFloat) {
- fval[0] = average(float4_to_float3(f[0]));
-
- if (derivatives) {
- fval[1] = average(float4_to_float3(f[1]));
- fval[2] = average(float4_to_float3(f[2]));
- }
- return true;
- }
- return false;
-}
-
-static bool set_attribute_float4(float4 f, TypeDesc type, bool derivatives, void *val)
-{
- float4 fv[3];
-
- fv[0] = f;
- fv[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- fv[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-
- return set_attribute_float4(fv, type, derivatives, val);
-}
-
-static bool set_attribute_float(float f[3], TypeDesc type, bool derivatives, void *val)
-{
- if (type == TypeFloatArray4) {
- float *fval = (float *)val;
- fval[0] = f[0];
- fval[1] = f[0];
- fval[2] = f[0];
- fval[3] = 1.0f;
-
- if (derivatives) {
- fval[4] = f[1];
- fval[5] = f[1];
- fval[6] = f[1];
- fval[7] = 0.0f;
-
- fval[8] = f[2];
- fval[9] = f[2];
- fval[10] = f[2];
- fval[11] = 0.0f;
- }
- return true;
- }
- else if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
- type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
- float *fval = (float *)val;
- fval[0] = f[0];
- fval[1] = f[0];
- fval[2] = f[0];
-
- if (derivatives) {
- fval[3] = f[1];
- fval[4] = f[1];
- fval[5] = f[1];
-
- fval[6] = f[2];
- fval[7] = f[2];
- fval[8] = f[2];
- }
-
- return true;
- }
- else if (type == TypeDesc::TypeFloat) {
- float *fval = (float *)val;
- fval[0] = f[0];
-
- if (derivatives) {
- fval[1] = f[1];
- fval[2] = f[2];
- }
-
- return true;
- }
-
- return false;
-}
-
-static bool set_attribute_float(float f, TypeDesc type, bool derivatives, void *val)
-{
- float fv[3];
-
- fv[0] = f;
- fv[1] = 0.0f;
- fv[2] = 0.0f;
-
- return set_attribute_float(fv, type, derivatives, val);
-}
-
-static bool set_attribute_int(int i, TypeDesc type, bool derivatives, void *val)
-{
- if (type.basetype == TypeDesc::INT && type.aggregate == TypeDesc::SCALAR && type.arraylen == 0) {
- int *ival = (int *)val;
- ival[0] = i;
-
- if (derivatives) {
- ival[1] = 0;
- ival[2] = 0;
- }
-
- return true;
- }
-
- return false;
-}
-
-static bool set_attribute_string(ustring str, TypeDesc type, bool derivatives, void *val)
-{
- if (type.basetype == TypeDesc::STRING && type.aggregate == TypeDesc::SCALAR &&
- type.arraylen == 0) {
- ustring *sval = (ustring *)val;
- sval[0] = str;
-
- if (derivatives) {
- sval[1] = OSLRenderServices::u_empty;
- sval[2] = OSLRenderServices::u_empty;
- }
-
- return true;
- }
-
- return false;
-}
-
-static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives, void *val)
-{
- if (type.vecsemantics == TypeDesc::POINT && type.arraylen >= 3) {
- float *fval = (float *)val;
-
- fval[0] = P[0].x;
- fval[1] = P[0].y;
- fval[2] = P[0].z;
-
- fval[3] = P[1].x;
- fval[4] = P[1].y;
- fval[5] = P[1].z;
-
- fval[6] = P[2].x;
- fval[7] = P[2].y;
- fval[8] = P[2].z;
-
- if (type.arraylen > 3)
- memset(fval + 3 * 3, 0, sizeof(float) * 3 * (type.arraylen - 3));
- if (derivatives)
- memset(fval + type.arraylen * 3, 0, sizeof(float) * 2 * 3 * type.arraylen);
-
- return true;
- }
-
- return false;
-}
-
-static bool set_attribute_matrix(const Transform &tfm, TypeDesc type, void *val)
-{
- if (type == TypeDesc::TypeMatrix) {
- copy_matrix(*(OSL::Matrix44 *)val, tfm);
- return true;
- }
-
- return false;
-}
-
-static bool get_primitive_attribute(const KernelGlobalsCPU *kg,
- const ShaderData *sd,
- const OSLGlobals::Attribute &attr,
- const TypeDesc &type,
- bool derivatives,
- void *val)
-{
- if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
- attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
- float3 fval[3];
- if (primitive_is_volume_attribute(sd, attr.desc)) {
- fval[0] = primitive_volume_attribute_float3(kg, sd, attr.desc);
- }
- else {
- memset(fval, 0, sizeof(fval));
- fval[0] = primitive_surface_attribute_float3(
- kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
- }
- return set_attribute_float3(fval, type, derivatives, val);
- }
- else if (attr.type == TypeFloat2) {
- if (primitive_is_volume_attribute(sd, attr.desc)) {
- assert(!"Float2 attribute not support for volumes");
- return false;
- }
- else {
- float2 fval[3];
- fval[0] = primitive_surface_attribute_float2(
- kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
- return set_attribute_float2(fval, type, derivatives, val);
- }
- }
- else if (attr.type == TypeDesc::TypeFloat) {
- float fval[3];
- if (primitive_is_volume_attribute(sd, attr.desc)) {
- memset(fval, 0, sizeof(fval));
- fval[0] = primitive_volume_attribute_float(kg, sd, attr.desc);
- }
- else {
- fval[0] = primitive_surface_attribute_float(
- kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
- }
- return set_attribute_float(fval, type, derivatives, val);
- }
- else if (attr.type == TypeDesc::TypeFloat4 || attr.type == TypeRGBA) {
- float4 fval[3];
- if (primitive_is_volume_attribute(sd, attr.desc)) {
- memset(fval, 0, sizeof(fval));
- fval[0] = primitive_volume_attribute_float4(kg, sd, attr.desc);
- }
- else {
- fval[0] = primitive_surface_attribute_float4(
- kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
- }
- return set_attribute_float4(fval, type, derivatives, val);
- }
- else {
- return false;
- }
-}
-
-static bool get_mesh_attribute(const KernelGlobalsCPU *kg,
- const ShaderData *sd,
- const OSLGlobals::Attribute &attr,
- const TypeDesc &type,
- bool derivatives,
- void *val)
-{
- if (attr.type == TypeDesc::TypeMatrix) {
- Transform tfm = primitive_attribute_matrix(kg, sd, attr.desc);
- return set_attribute_matrix(tfm, type, val);
- }
- else {
- return false;
- }
-}
-
-static bool get_object_attribute(const OSLGlobals::Attribute &attr,
- TypeDesc type,
- bool derivatives,
- void *val)
-{
- if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
- attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
- return set_attribute_float3(*(float3 *)attr.value.data(), type, derivatives, val);
- }
- else if (attr.type == TypeFloat2) {
- return set_attribute_float2(*(float2 *)attr.value.data(), type, derivatives, val);
- }
- else if (attr.type == TypeDesc::TypeFloat) {
- return set_attribute_float(*(float *)attr.value.data(), type, derivatives, val);
- }
- else if (attr.type == TypeRGBA || attr.type == TypeDesc::TypeFloat4) {
- return set_attribute_float4(*(float4 *)attr.value.data(), type, derivatives, val);
- }
- else if (attr.type == type) {
- size_t datasize = attr.value.datasize();
-
- memcpy(val, attr.value.data(), datasize);
- if (derivatives) {
- memset((char *)val + datasize, 0, datasize * 2);
- }
-
- return true;
- }
- else {
- return false;
- }
-}
-
-bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg,
- ShaderData *sd,
- ustring name,
- TypeDesc type,
- bool derivatives,
- void *val)
-{
- /* todo: turn this into hash table? */
-
- /* Object Attributes */
- if (name == u_object_location) {
- float3 f = object_location(kg, sd);
- return set_attribute_float3(f, type, derivatives, val);
- }
- else if (name == u_object_color) {
- float3 f = object_color(kg, sd->object);
- return set_attribute_float3(f, type, derivatives, val);
- }
- else if (name == u_object_index) {
- float f = object_pass_id(kg, sd->object);
- return set_attribute_float(f, type, derivatives, val);
- }
- else if (name == u_geom_dupli_generated) {
- float3 f = object_dupli_generated(kg, sd->object);
- return set_attribute_float3(f, type, derivatives, val);
- }
- else if (name == u_geom_dupli_uv) {
- float3 f = object_dupli_uv(kg, sd->object);
- return set_attribute_float3(f, type, derivatives, val);
- }
- else if (name == u_material_index) {
- float f = shader_pass_id(kg, sd);
- return set_attribute_float(f, type, derivatives, val);
- }
- else if (name == u_object_random) {
- float f = object_random_number(kg, sd->object);
- return set_attribute_float(f, type, derivatives, val);
- }
-
- /* Particle Attributes */
- else if (name == u_particle_index) {
- int particle_id = object_particle_id(kg, sd->object);
- float f = particle_index(kg, particle_id);
- return set_attribute_float(f, type, derivatives, val);
- }
- else if (name == u_particle_random) {
- int particle_id = object_particle_id(kg, sd->object);
- float f = hash_uint2_to_float(particle_index(kg, particle_id), 0);
- return set_attribute_float(f, type, derivatives, val);
- }
-
- else if (name == u_particle_age) {
- int particle_id = object_particle_id(kg, sd->object);
- float f = particle_age(kg, particle_id);
- return set_attribute_float(f, type, derivatives, val);
- }
- else if (name == u_particle_lifetime) {
- int particle_id = object_particle_id(kg, sd->object);
- float f = particle_lifetime(kg, particle_id);
- return set_attribute_float(f, type, derivatives, val);
- }
- else if (name == u_particle_location) {
- int particle_id = object_particle_id(kg, sd->object);
- float3 f = particle_location(kg, particle_id);
- return set_attribute_float3(f, type, derivatives, val);
- }
-#if 0 /* unsupported */
- else if (name == u_particle_rotation) {
- int particle_id = object_particle_id(kg, sd->object);
- float4 f = particle_rotation(kg, particle_id);
- return set_attribute_float4(f, type, derivatives, val);
- }
-#endif
- else if (name == u_particle_size) {
- int particle_id = object_particle_id(kg, sd->object);
- float f = particle_size(kg, particle_id);
- return set_attribute_float(f, type, derivatives, val);
- }
- else if (name == u_particle_velocity) {
- int particle_id = object_particle_id(kg, sd->object);
- float3 f = particle_velocity(kg, particle_id);
- return set_attribute_float3(f, type, derivatives, val);
- }
- else if (name == u_particle_angular_velocity) {
- int particle_id = object_particle_id(kg, sd->object);
- float3 f = particle_angular_velocity(kg, particle_id);
- return set_attribute_float3(f, type, derivatives, val);
- }
-
- /* Geometry Attributes */
- else if (name == u_geom_numpolyvertices) {
- return set_attribute_int(3, type, derivatives, val);
- }
- else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices) &&
- sd->type & PRIMITIVE_ALL_TRIANGLE) {
- float3 P[3];
-
- if (sd->type & PRIMITIVE_TRIANGLE)
- triangle_vertices(kg, sd->prim, P);
- else
- motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P);
-
- if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- object_position_transform(kg, sd, &P[0]);
- object_position_transform(kg, sd, &P[1]);
- object_position_transform(kg, sd, &P[2]);
- }
-
- return set_attribute_float3_3(P, type, derivatives, val);
- }
- else if (name == u_geom_name) {
- ustring object_name = kg->osl->object_names[sd->object];
- return set_attribute_string(object_name, type, derivatives, val);
- }
- else if (name == u_is_smooth) {
- float f = ((sd->shader & SHADER_SMOOTH_NORMAL) != 0);
- return set_attribute_float(f, type, derivatives, val);
- }
- /* Hair Attributes */
- else if (name == u_is_curve) {
- float f = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
- return set_attribute_float(f, type, derivatives, val);
- }
- else if (name == u_curve_thickness) {
- float f = curve_thickness(kg, sd);
- return set_attribute_float(f, type, derivatives, val);
- }
- else if (name == u_curve_tangent_normal) {
- float3 f = curve_tangent_normal(kg, sd);
- return set_attribute_float3(f, type, derivatives, val);
- }
- else if (name == u_normal_map_normal) {
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
- float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
- return set_attribute_float3(f, type, derivatives, val);
- }
- else {
- return false;
- }
- }
- else {
- return false;
- }
-}
-
-bool OSLRenderServices::get_background_attribute(const KernelGlobalsCPU *kg,
- ShaderData *sd,
- ustring name,
- TypeDesc type,
- bool derivatives,
- void *val)
-{
- if (name == u_path_ray_length) {
- /* Ray Length */
- float f = sd->ray_length;
- return set_attribute_float(f, type, derivatives, val);
- }
- else if (name == u_path_ray_depth) {
- /* Ray Depth */
- const IntegratorStateCPU *state = sd->osl_path_state;
- const IntegratorShadowStateCPU *shadow_state = sd->osl_shadow_path_state;
- int f = (state) ? state->path.bounce : (shadow_state) ? shadow_state->shadow_path.bounce : 0;
- return set_attribute_int(f, type, derivatives, val);
- }
- else if (name == u_path_diffuse_depth) {
- /* Diffuse Ray Depth */
- const IntegratorStateCPU *state = sd->osl_path_state;
- const IntegratorShadowStateCPU *shadow_state = sd->osl_shadow_path_state;
- int f = (state) ? state->path.diffuse_bounce :
- (shadow_state) ? shadow_state->shadow_path.diffuse_bounce :
- 0;
- return set_attribute_int(f, type, derivatives, val);
- }
- else if (name == u_path_glossy_depth) {
- /* Glossy Ray Depth */
- const IntegratorStateCPU *state = sd->osl_path_state;
- const IntegratorShadowStateCPU *shadow_state = sd->osl_shadow_path_state;
- int f = (state) ? state->path.glossy_bounce :
- (shadow_state) ? shadow_state->shadow_path.glossy_bounce :
- 0;
- return set_attribute_int(f, type, derivatives, val);
- }
- else if (name == u_path_transmission_depth) {
- /* Transmission Ray Depth */
- const IntegratorStateCPU *state = sd->osl_path_state;
- const IntegratorShadowStateCPU *shadow_state = sd->osl_shadow_path_state;
- int f = (state) ? state->path.transmission_bounce :
- (shadow_state) ? shadow_state->shadow_path.transmission_bounce :
- 0;
- return set_attribute_int(f, type, derivatives, val);
- }
- else if (name == u_path_transparent_depth) {
- /* Transparent Ray Depth */
- const IntegratorStateCPU *state = sd->osl_path_state;
- const IntegratorShadowStateCPU *shadow_state = sd->osl_shadow_path_state;
- int f = (state) ? state->path.transparent_bounce :
- (shadow_state) ? shadow_state->shadow_path.transparent_bounce :
- 0;
- return set_attribute_int(f, type, derivatives, val);
- }
- else if (name == u_ndc) {
- /* NDC coordinates with special exception for orthographic projection. */
- OSLThreadData *tdata = kg->osl_tdata;
- OSL::ShaderGlobals *globals = &tdata->globals;
- float3 ndc[3];
-
- if ((globals->raytype & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
- kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
- ndc[0] = camera_world_to_ndc(kg, sd, sd->ray_P);
-
- if (derivatives) {
- ndc[1] = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(sd->ray_dP, 0.0f, 0.0f)) -
- ndc[0];
- ndc[2] = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(0.0f, sd->ray_dP, 0.0f)) -
- ndc[0];
- }
- }
- else {
- ndc[0] = camera_world_to_ndc(kg, sd, sd->P);
-
- if (derivatives) {
- ndc[1] = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dx) - ndc[0];
- ndc[2] = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dy) - ndc[0];
- }
- }
-
- return set_attribute_float3(ndc, type, derivatives, val);
- }
- else
- return false;
-}
-
-bool OSLRenderServices::get_attribute(OSL::ShaderGlobals *sg,
- bool derivatives,
- ustring object_name,
- TypeDesc type,
- ustring name,
- void *val)
-{
- if (sg == NULL || sg->renderstate == NULL)
- return false;
-
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- return get_attribute(sd, derivatives, object_name, type, name, val);
-}
-
-bool OSLRenderServices::get_attribute(
- ShaderData *sd, bool derivatives, ustring object_name, TypeDesc type, ustring name, void *val)
-{
- const KernelGlobalsCPU *kg = sd->osl_globals;
- int prim_type = 0;
- int object;
-
- /* lookup of attribute on another object */
- if (object_name != u_empty) {
- OSLGlobals::ObjectNameMap::iterator it = kg->osl->object_name_map.find(object_name);
-
- if (it == kg->osl->object_name_map.end())
- return false;
-
- object = it->second;
- }
- else {
- object = sd->object;
- prim_type = attribute_primitive_type(kg, sd);
-
- if (object == OBJECT_NONE)
- return get_background_attribute(kg, sd, name, type, derivatives, val);
- }
-
- /* find attribute on object */
- object = object * ATTR_PRIM_TYPES + prim_type;
- OSLGlobals::AttributeMap &attribute_map = kg->osl->attribute_map[object];
- OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
-
- if (it != attribute_map.end()) {
- const OSLGlobals::Attribute &attr = it->second;
-
- if (attr.desc.element != ATTR_ELEMENT_OBJECT) {
- /* triangle and vertex attributes */
- if (get_primitive_attribute(kg, sd, attr, type, derivatives, val))
- return true;
- else
- return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
- }
- else {
- /* object attribute */
- return get_object_attribute(attr, type, derivatives, val);
- }
- }
- else {
- /* not found in attribute, check standard object info */
- bool is_std_object_attribute = get_object_standard_attribute(
- kg, sd, name, type, derivatives, val);
-
- if (is_std_object_attribute)
- return true;
-
- return get_background_attribute(kg, sd, name, type, derivatives, val);
- }
-
- return false;
-}
-
-bool OSLRenderServices::get_userdata(
- bool derivatives, ustring name, TypeDesc type, OSL::ShaderGlobals *sg, void *val)
-{
- return false; /* disabled by lockgeom */
-}
-
-#if OSL_LIBRARY_VERSION_CODE >= 11100
-TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename,
- OSL::ShadingContext *)
-#else
-
-TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename)
-#endif
-{
- OSLTextureHandleMap::iterator it = textures.find(filename);
-
- /* For non-OIIO textures, just return a pointer to our own OSLTextureHandle. */
- if (it != textures.end()) {
- if (it->second->type != OSLTextureHandle::OIIO) {
- return (TextureSystem::TextureHandle *)it->second.get();
- }
- }
-
- /* Get handle from OpenImageIO. */
- OSL::TextureSystem *ts = texture_system;
- TextureSystem::TextureHandle *handle = ts->get_texture_handle(filename);
- if (handle == NULL) {
- return NULL;
- }
-
- /* Insert new OSLTextureHandle if needed. */
- if (it == textures.end()) {
- textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::OIIO));
- it = textures.find(filename);
- }
-
- /* Assign OIIO texture handle and return. */
- it->second->oiio_handle = handle;
- return (TextureSystem::TextureHandle *)it->second.get();
-}
-
-bool OSLRenderServices::good(TextureSystem::TextureHandle *texture_handle)
-{
- OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
-
- if (handle->oiio_handle) {
- OSL::TextureSystem *ts = texture_system;
- return ts->good(handle->oiio_handle);
- }
- else {
- return true;
- }
-}
-
-bool OSLRenderServices::texture(ustring filename,
- TextureHandle *texture_handle,
- TexturePerthread *texture_thread_info,
- TextureOpt &options,
- OSL::ShaderGlobals *sg,
- float s,
- float t,
- float dsdx,
- float dtdx,
- float dsdy,
- float dtdy,
- int nchannels,
- float *result,
- float *dresultds,
- float *dresultdt,
- ustring *errormessage)
-{
- OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
- OSLTextureHandle::Type texture_type = (handle) ? handle->type : OSLTextureHandle::OIIO;
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- KernelGlobals kernel_globals = sd->osl_globals;
- bool status = false;
-
- switch (texture_type) {
- case OSLTextureHandle::BEVEL: {
- /* Bevel shader hack. */
- if (nchannels >= 3) {
- const IntegratorStateCPU *state = sd->osl_path_state;
- if (state) {
- int num_samples = (int)s;
- float radius = t;
- float3 N = svm_bevel(kernel_globals, state, sd, radius, num_samples);
- result[0] = N.x;
- result[1] = N.y;
- result[2] = N.z;
- status = true;
- }
- }
- break;
- }
- case OSLTextureHandle::AO: {
- /* AO shader hack. */
- const IntegratorStateCPU *state = sd->osl_path_state;
- if (state) {
- int num_samples = (int)s;
- float radius = t;
- float3 N = make_float3(dsdx, dtdx, dsdy);
- int flags = 0;
- if ((int)dtdy) {
- flags |= NODE_AO_INSIDE;
- }
- if ((int)options.sblur) {
- flags |= NODE_AO_ONLY_LOCAL;
- }
- if ((int)options.tblur) {
- flags |= NODE_AO_GLOBAL_RADIUS;
- }
- result[0] = svm_ao(kernel_globals, state, sd, N, radius, num_samples, flags);
- status = true;
- }
- break;
- }
- case OSLTextureHandle::SVM: {
- /* Packed texture. */
- float4 rgba = kernel_tex_image_interp(kernel_globals, handle->svm_slot, s, 1.0f - t);
-
- result[0] = rgba[0];
- if (nchannels > 1)
- result[1] = rgba[1];
- if (nchannels > 2)
- result[2] = rgba[2];
- if (nchannels > 3)
- result[3] = rgba[3];
- status = true;
- break;
- }
- case OSLTextureHandle::IES: {
- /* IES light. */
- result[0] = kernel_ies_interp(kernel_globals, handle->svm_slot, s, t);
- status = true;
- break;
- }
- case OSLTextureHandle::OIIO: {
- /* OpenImageIO texture cache. */
- OSL::TextureSystem *ts = texture_system;
-
- if (handle && handle->oiio_handle) {
- if (texture_thread_info == NULL) {
- OSLThreadData *tdata = kernel_globals->osl_tdata;
- texture_thread_info = tdata->oiio_thread_info;
- }
-
- status = ts->texture(handle->oiio_handle,
- texture_thread_info,
- options,
- s,
- t,
- dsdx,
- dtdx,
- dsdy,
- dtdy,
- nchannels,
- result,
- dresultds,
- dresultdt);
- }
- else {
- status = ts->texture(filename,
- options,
- s,
- t,
- dsdx,
- dtdx,
- dsdy,
- dtdy,
- nchannels,
- result,
- dresultds,
- dresultdt);
- }
-
- if (!status) {
- /* This might be slow, but prevents error messages leak and
- * other nasty stuff happening. */
- ts->geterror();
- }
- else if (handle && handle->processor) {
- ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
- }
- break;
- }
- }
-
- if (!status) {
- if (nchannels == 3 || nchannels == 4) {
- result[0] = 1.0f;
- result[1] = 0.0f;
- result[2] = 1.0f;
-
- if (nchannels == 4)
- result[3] = 1.0f;
- }
- }
-
- return status;
-}
-
-bool OSLRenderServices::texture3d(ustring filename,
- TextureHandle *texture_handle,
- TexturePerthread *texture_thread_info,
- TextureOpt &options,
- OSL::ShaderGlobals *sg,
- const OSL::Vec3 &P,
- const OSL::Vec3 &dPdx,
- const OSL::Vec3 &dPdy,
- const OSL::Vec3 &dPdz,
- int nchannels,
- float *result,
- float *dresultds,
- float *dresultdt,
- float *dresultdr,
- ustring *errormessage)
-{
- OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
- OSLTextureHandle::Type texture_type = (handle) ? handle->type : OSLTextureHandle::OIIO;
- bool status = false;
-
- switch (texture_type) {
- case OSLTextureHandle::SVM: {
- /* Packed texture. */
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- KernelGlobals kernel_globals = sd->osl_globals;
- int slot = handle->svm_slot;
- float3 P_float3 = make_float3(P.x, P.y, P.z);
- float4 rgba = kernel_tex_image_interp_3d(kernel_globals, slot, P_float3, INTERPOLATION_NONE);
-
- result[0] = rgba[0];
- if (nchannels > 1)
- result[1] = rgba[1];
- if (nchannels > 2)
- result[2] = rgba[2];
- if (nchannels > 3)
- result[3] = rgba[3];
- status = true;
- break;
- }
- case OSLTextureHandle::OIIO: {
- /* OpenImageIO texture cache. */
- OSL::TextureSystem *ts = texture_system;
-
- if (handle && handle->oiio_handle) {
- if (texture_thread_info == NULL) {
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- KernelGlobals kernel_globals = sd->osl_globals;
- OSLThreadData *tdata = kernel_globals->osl_tdata;
- texture_thread_info = tdata->oiio_thread_info;
- }
-
- status = ts->texture3d(handle->oiio_handle,
- texture_thread_info,
- options,
- P,
- dPdx,
- dPdy,
- dPdz,
- nchannels,
- result,
- dresultds,
- dresultdt,
- dresultdr);
- }
- else {
- status = ts->texture3d(filename,
- options,
- P,
- dPdx,
- dPdy,
- dPdz,
- nchannels,
- result,
- dresultds,
- dresultdt,
- dresultdr);
- }
-
- if (!status) {
- /* This might be slow, but prevents error messages leak and
- * other nasty stuff happening. */
- ts->geterror();
- }
- else if (handle && handle->processor) {
- ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
- }
- break;
- }
- case OSLTextureHandle::IES:
- case OSLTextureHandle::AO:
- case OSLTextureHandle::BEVEL: {
- status = false;
- break;
- }
- }
-
- if (!status) {
- if (nchannels == 3 || nchannels == 4) {
- result[0] = 1.0f;
- result[1] = 0.0f;
- result[2] = 1.0f;
-
- if (nchannels == 4)
- result[3] = 1.0f;
- }
- }
-
- return status;
-}
-
-bool OSLRenderServices::environment(ustring filename,
- TextureHandle *texture_handle,
- TexturePerthread *thread_info,
- TextureOpt &options,
- OSL::ShaderGlobals *sg,
- const OSL::Vec3 &R,
- const OSL::Vec3 &dRdx,
- const OSL::Vec3 &dRdy,
- int nchannels,
- float *result,
- float *dresultds,
- float *dresultdt,
- ustring *errormessage)
-{
- OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
- OSL::TextureSystem *ts = texture_system;
- bool status = false;
-
- if (handle && handle->oiio_handle) {
- if (thread_info == NULL) {
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- KernelGlobals kernel_globals = sd->osl_globals;
- OSLThreadData *tdata = kernel_globals->osl_tdata;
- thread_info = tdata->oiio_thread_info;
- }
-
- status = ts->environment(handle->oiio_handle,
- thread_info,
- options,
- R,
- dRdx,
- dRdy,
- nchannels,
- result,
- dresultds,
- dresultdt);
- }
- else {
- status = ts->environment(
- filename, options, R, dRdx, dRdy, nchannels, result, dresultds, dresultdt);
- }
-
- if (!status) {
- if (nchannels == 3 || nchannels == 4) {
- result[0] = 1.0f;
- result[1] = 0.0f;
- result[2] = 1.0f;
-
- if (nchannels == 4)
- result[3] = 1.0f;
- }
- }
- else if (handle && handle->processor) {
- ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
- }
-
- return status;
-}
-
-#if OSL_LIBRARY_VERSION_CODE >= 11100
-bool OSLRenderServices::get_texture_info(ustring filename,
- TextureHandle *texture_handle,
- TexturePerthread *,
- OSL::ShadingContext *,
- int subimage,
- ustring dataname,
- TypeDesc datatype,
- void *data,
- ustring *)
-#else
-bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg,
- ustring filename,
- TextureHandle *texture_handle,
- int subimage,
- ustring dataname,
- TypeDesc datatype,
- void *data)
-#endif
-{
- OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
-
- /* No texture info for other texture types. */
- if (handle && handle->type != OSLTextureHandle::OIIO) {
- return false;
- }
-
- /* Get texture info from OpenImageIO. */
- OSL::TextureSystem *ts = texture_system;
- return ts->get_texture_info(filename, subimage, dataname, datatype, data);
-}
-
-int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg,
- ustring filename,
- const OSL::Vec3 &center,
- float radius,
- int max_points,
- bool sort,
- size_t *out_indices,
- float *out_distances,
- int derivs_offset)
-{
- return 0;
-}
-
-int OSLRenderServices::pointcloud_get(OSL::ShaderGlobals *sg,
- ustring filename,
- size_t *indices,
- int count,
- ustring attr_name,
- TypeDesc attr_type,
- void *out_data)
-{
- return 0;
-}
-
-bool OSLRenderServices::pointcloud_write(OSL::ShaderGlobals *sg,
- ustring filename,
- const OSL::Vec3 &pos,
- int nattribs,
- const ustring *names,
- const TypeDesc *types,
- const void **data)
-{
- return false;
-}
-
-bool OSLRenderServices::trace(TraceOpt &options,
- OSL::ShaderGlobals *sg,
- const OSL::Vec3 &P,
- const OSL::Vec3 &dPdx,
- const OSL::Vec3 &dPdy,
- const OSL::Vec3 &R,
- const OSL::Vec3 &dRdx,
- const OSL::Vec3 &dRdy)
-{
- /* todo: options.shader support, maybe options.traceset */
- ShaderData *sd = (ShaderData *)(sg->renderstate);
-
- /* setup ray */
- Ray ray;
-
- ray.P = TO_FLOAT3(P);
- ray.D = TO_FLOAT3(R);
- ray.t = (options.maxdist == 1.0e30f) ? FLT_MAX : options.maxdist - options.mindist;
- ray.time = sd->time;
-
- if (options.mindist == 0.0f) {
- /* avoid self-intersections */
- if (ray.P == sd->P) {
- bool transmit = (dot(sd->Ng, ray.D) < 0.0f);
- ray.P = ray_offset(sd->P, (transmit) ? -sd->Ng : sd->Ng);
- }
- }
- else {
- /* offset for minimum distance */
- ray.P += options.mindist * ray.D;
- }
-
- /* ray differentials */
- differential3 dP;
- dP.dx = TO_FLOAT3(dPdx);
- dP.dy = TO_FLOAT3(dPdy);
- ray.dP = differential_make_compact(dP);
- differential3 dD;
- dD.dx = TO_FLOAT3(dRdx);
- dD.dy = TO_FLOAT3(dRdy);
- ray.dD = differential_make_compact(dD);
-
- /* allocate trace data */
- OSLTraceData *tracedata = (OSLTraceData *)sg->tracedata;
- tracedata->ray = ray;
- tracedata->setup = false;
- tracedata->init = true;
- tracedata->hit = false;
- tracedata->sd.osl_globals = sd->osl_globals;
-
- const KernelGlobalsCPU *kg = sd->osl_globals;
-
- /* Can't raytrace from shaders like displacement, before BVH exists. */
- if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
- return false;
- }
-
- /* Raytrace, leaving out shadow opaque to avoid early exit. */
- uint visibility = PATH_RAY_ALL_VISIBILITY - PATH_RAY_SHADOW_OPAQUE;
- tracedata->hit = scene_intersect(kg, &ray, visibility, &tracedata->isect);
- return tracedata->hit;
-}
-
-bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg,
- ustring source,
- ustring name,
- TypeDesc type,
- void *val,
- bool derivatives)
-{
- OSLTraceData *tracedata = (OSLTraceData *)sg->tracedata;
-
- if (source == u_trace && tracedata->init) {
- if (name == u_hit) {
- return set_attribute_int(tracedata->hit, type, derivatives, val);
- }
- else if (tracedata->hit) {
- if (name == u_hitdist) {
- float f[3] = {tracedata->isect.t, 0.0f, 0.0f};
- return set_attribute_float(f, type, derivatives, val);
- }
- else {
- ShaderData *sd = &tracedata->sd;
- const KernelGlobalsCPU *kg = sd->osl_globals;
-
- if (!tracedata->setup) {
- /* lazy shader data setup */
- shader_setup_from_ray(kg, sd, &tracedata->ray, &tracedata->isect);
- tracedata->setup = true;
- }
-
- if (name == u_N) {
- return set_attribute_float3(sd->N, type, derivatives, val);
- }
- else if (name == u_Ng) {
- return set_attribute_float3(sd->Ng, type, derivatives, val);
- }
- else if (name == u_P) {
- float3 f[3] = {sd->P, sd->dP.dx, sd->dP.dy};
- return set_attribute_float3(f, type, derivatives, val);
- }
- else if (name == u_I) {
- float3 f[3] = {sd->I, sd->dI.dx, sd->dI.dy};
- return set_attribute_float3(f, type, derivatives, val);
- }
- else if (name == u_u) {
- float f[3] = {sd->u, sd->du.dx, sd->du.dy};
- return set_attribute_float(f, type, derivatives, val);
- }
- else if (name == u_v) {
- float f[3] = {sd->v, sd->dv.dx, sd->dv.dy};
- return set_attribute_float(f, type, derivatives, val);
- }
-
- return get_attribute(sd, derivatives, u_empty, type, name, val);
- }
- }
- }
-
- return false;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
deleted file mode 100644
index fba207e7230..00000000000
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <OSL/oslexec.h>
-
-// clang-format off
-#include "kernel/device/cpu/compat.h"
-#include "kernel/device/cpu/globals.h"
-
-#include "kernel/kernel_montecarlo.h"
-#include "kernel/kernel_types.h"
-
-#include "kernel/geom/geom_object.h"
-
-#include "kernel/integrator/integrator_state.h"
-
-#include "kernel/osl/osl_closures.h"
-#include "kernel/osl/osl_globals.h"
-#include "kernel/osl/osl_services.h"
-#include "kernel/osl/osl_shader.h"
-// clang-format on
-
-#include "util/util_foreach.h"
-
-#include "render/attribute.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Threads */
-
-void OSLShader::thread_init(KernelGlobalsCPU *kg, OSLGlobals *osl_globals)
-{
- /* no osl used? */
- if (!osl_globals->use) {
- kg->osl = NULL;
- return;
- }
-
- /* Per thread kernel data init. */
- kg->osl = osl_globals;
-
- OSL::ShadingSystem *ss = kg->osl->ss;
- OSLThreadData *tdata = new OSLThreadData();
-
- memset((void *)&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
- tdata->globals.tracedata = &tdata->tracedata;
- tdata->globals.flipHandedness = false;
- tdata->osl_thread_info = ss->create_thread_info();
- tdata->context = ss->get_context(tdata->osl_thread_info);
-
- tdata->oiio_thread_info = osl_globals->ts->get_perthread_info();
-
- kg->osl_ss = (OSLShadingSystem *)ss;
- kg->osl_tdata = tdata;
-}
-
-void OSLShader::thread_free(KernelGlobalsCPU *kg)
-{
- if (!kg->osl)
- return;
-
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
- OSLThreadData *tdata = kg->osl_tdata;
- ss->release_context(tdata->context);
-
- ss->destroy_thread_info(tdata->osl_thread_info);
-
- delete tdata;
-
- kg->osl = NULL;
- kg->osl_ss = NULL;
- kg->osl_tdata = NULL;
-}
-
-/* Globals */
-
-static void shaderdata_to_shaderglobals(const KernelGlobalsCPU *kg,
- ShaderData *sd,
- const void *state,
- uint32_t path_flag,
- OSLThreadData *tdata)
-{
- OSL::ShaderGlobals *globals = &tdata->globals;
-
- /* copy from shader data to shader globals */
- globals->P = TO_VEC3(sd->P);
- globals->dPdx = TO_VEC3(sd->dP.dx);
- globals->dPdy = TO_VEC3(sd->dP.dy);
- globals->I = TO_VEC3(sd->I);
- globals->dIdx = TO_VEC3(sd->dI.dx);
- globals->dIdy = TO_VEC3(sd->dI.dy);
- globals->N = TO_VEC3(sd->N);
- globals->Ng = TO_VEC3(sd->Ng);
- globals->u = sd->u;
- globals->dudx = sd->du.dx;
- globals->dudy = sd->du.dy;
- globals->v = sd->v;
- globals->dvdx = sd->dv.dx;
- globals->dvdy = sd->dv.dy;
- globals->dPdu = TO_VEC3(sd->dPdu);
- globals->dPdv = TO_VEC3(sd->dPdv);
- globals->surfacearea = 1.0f;
- globals->time = sd->time;
-
- /* booleans */
- globals->raytype = path_flag;
- globals->backfacing = (sd->flag & SD_BACKFACING);
-
- /* shader data to be used in services callbacks */
- globals->renderstate = sd;
-
- /* hacky, we leave it to services to fetch actual object matrix */
- globals->shader2common = sd;
- globals->object2common = sd;
-
- /* must be set to NULL before execute */
- globals->Ci = NULL;
-
- /* clear trace data */
- tdata->tracedata.init = false;
-
- /* Used by render-services. */
- sd->osl_globals = kg;
- if (path_flag & PATH_RAY_SHADOW) {
- sd->osl_shadow_path_state = (const IntegratorShadowStateCPU *)state;
- }
- else {
- sd->osl_path_state = (const IntegratorStateCPU *)state;
- }
-}
-
-/* Surface */
-
-static void flatten_surface_closure_tree(ShaderData *sd,
- uint32_t path_flag,
- const OSL::ClosureColor *closure,
- float3 weight = make_float3(1.0f, 1.0f, 1.0f))
-{
- /* OSL gives us a closure tree, we flatten it into arrays per
- * closure type, for evaluation, sampling, etc later on. */
-
- switch (closure->id) {
- case OSL::ClosureColor::MUL: {
- OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
- flatten_surface_closure_tree(sd, path_flag, mul->closure, TO_FLOAT3(mul->weight) * weight);
- break;
- }
- case OSL::ClosureColor::ADD: {
- OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
- flatten_surface_closure_tree(sd, path_flag, add->closureA, weight);
- flatten_surface_closure_tree(sd, path_flag, add->closureB, weight);
- break;
- }
- default: {
- OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
- CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
-
- if (prim) {
-#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
- weight = weight * TO_FLOAT3(comp->w);
-#endif
- prim->setup(sd, path_flag, weight);
- }
- break;
- }
- }
-}
-
-void OSLShader::eval_surface(const KernelGlobalsCPU *kg,
- const void *state,
- ShaderData *sd,
- uint32_t path_flag)
-{
- /* setup shader globals from shader data */
- OSLThreadData *tdata = kg->osl_tdata;
- shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
-
- /* execute shader for this point */
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
- OSL::ShaderGlobals *globals = &tdata->globals;
- OSL::ShadingContext *octx = tdata->context;
- int shader = sd->shader & SHADER_MASK;
-
- /* automatic bump shader */
- if (kg->osl->bump_state[shader]) {
- /* save state */
- float3 P = sd->P;
- float3 dPdx = sd->dP.dx;
- float3 dPdy = sd->dP.dy;
-
- /* set state as if undisplaced */
- if (sd->flag & SD_HAS_DISPLACEMENT) {
- float data[9];
- bool found = kg->osl->services->get_attribute(sd,
- true,
- OSLRenderServices::u_empty,
- TypeDesc::TypeVector,
- OSLRenderServices::u_geom_undisplaced,
- data);
- (void)found;
- assert(found);
-
- memcpy(&sd->P, data, sizeof(float) * 3);
- memcpy(&sd->dP.dx, data + 3, sizeof(float) * 3);
- memcpy(&sd->dP.dy, data + 6, sizeof(float) * 3);
-
- object_position_transform(kg, sd, &sd->P);
- object_dir_transform(kg, sd, &sd->dP.dx);
- object_dir_transform(kg, sd, &sd->dP.dy);
-
- globals->P = TO_VEC3(sd->P);
- globals->dPdx = TO_VEC3(sd->dP.dx);
- globals->dPdy = TO_VEC3(sd->dP.dy);
- }
-
- /* execute bump shader */
- ss->execute(octx, *(kg->osl->bump_state[shader]), *globals);
-
- /* reset state */
- sd->P = P;
- sd->dP.dx = dPdx;
- sd->dP.dy = dPdy;
-
- globals->P = TO_VEC3(P);
- globals->dPdx = TO_VEC3(dPdx);
- globals->dPdy = TO_VEC3(dPdy);
- }
-
- /* surface shader */
- if (kg->osl->surface_state[shader]) {
- ss->execute(octx, *(kg->osl->surface_state[shader]), *globals);
- }
-
- /* flatten closure tree */
- if (globals->Ci)
- flatten_surface_closure_tree(sd, path_flag, globals->Ci);
-}
-
-/* Background */
-
-static void flatten_background_closure_tree(ShaderData *sd,
- const OSL::ClosureColor *closure,
- float3 weight = make_float3(1.0f, 1.0f, 1.0f))
-{
- /* OSL gives us a closure tree, if we are shading for background there
- * is only one supported closure type at the moment, which has no evaluation
- * functions, so we just sum the weights */
-
- switch (closure->id) {
- case OSL::ClosureColor::MUL: {
- OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
- flatten_background_closure_tree(sd, mul->closure, weight * TO_FLOAT3(mul->weight));
- break;
- }
- case OSL::ClosureColor::ADD: {
- OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
-
- flatten_background_closure_tree(sd, add->closureA, weight);
- flatten_background_closure_tree(sd, add->closureB, weight);
- break;
- }
- default: {
- OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
- CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
-
- if (prim) {
-#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
- weight = weight * TO_FLOAT3(comp->w);
-#endif
- prim->setup(sd, 0, weight);
- }
- break;
- }
- }
-}
-
-void OSLShader::eval_background(const KernelGlobalsCPU *kg,
- const void *state,
- ShaderData *sd,
- uint32_t path_flag)
-{
- /* setup shader globals from shader data */
- OSLThreadData *tdata = kg->osl_tdata;
- shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
-
- /* execute shader for this point */
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
- OSL::ShaderGlobals *globals = &tdata->globals;
- OSL::ShadingContext *octx = tdata->context;
-
- if (kg->osl->background_state) {
- ss->execute(octx, *(kg->osl->background_state), *globals);
- }
-
- /* return background color immediately */
- if (globals->Ci)
- flatten_background_closure_tree(sd, globals->Ci);
-}
-
-/* Volume */
-
-static void flatten_volume_closure_tree(ShaderData *sd,
- const OSL::ClosureColor *closure,
- float3 weight = make_float3(1.0f, 1.0f, 1.0f))
-{
- /* OSL gives us a closure tree, we flatten it into arrays per
- * closure type, for evaluation, sampling, etc later on. */
-
- switch (closure->id) {
- case OSL::ClosureColor::MUL: {
- OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
- flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
- break;
- }
- case OSL::ClosureColor::ADD: {
- OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
- flatten_volume_closure_tree(sd, add->closureA, weight);
- flatten_volume_closure_tree(sd, add->closureB, weight);
- break;
- }
- default: {
- OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
- CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
-
- if (prim) {
-#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
- weight = weight * TO_FLOAT3(comp->w);
-#endif
- prim->setup(sd, 0, weight);
- }
- }
- }
-}
-
-void OSLShader::eval_volume(const KernelGlobalsCPU *kg,
- const void *state,
- ShaderData *sd,
- uint32_t path_flag)
-{
- /* setup shader globals from shader data */
- OSLThreadData *tdata = kg->osl_tdata;
- shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
-
- /* execute shader */
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
- OSL::ShaderGlobals *globals = &tdata->globals;
- OSL::ShadingContext *octx = tdata->context;
- int shader = sd->shader & SHADER_MASK;
-
- if (kg->osl->volume_state[shader]) {
- ss->execute(octx, *(kg->osl->volume_state[shader]), *globals);
- }
-
- /* flatten closure tree */
- if (globals->Ci)
- flatten_volume_closure_tree(sd, globals->Ci);
-}
-
-/* Displacement */
-
-void OSLShader::eval_displacement(const KernelGlobalsCPU *kg, const void *state, ShaderData *sd)
-{
- /* setup shader globals from shader data */
- OSLThreadData *tdata = kg->osl_tdata;
-
- shaderdata_to_shaderglobals(kg, sd, state, 0, tdata);
-
- /* execute shader */
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
- OSL::ShaderGlobals *globals = &tdata->globals;
- OSL::ShadingContext *octx = tdata->context;
- int shader = sd->shader & SHADER_MASK;
-
- if (kg->osl->displacement_state[shader]) {
- ss->execute(octx, *(kg->osl->displacement_state[shader]), *globals);
- }
-
- /* get back position */
- sd->P = TO_FLOAT3(globals->P);
-}
-
-/* Attributes */
-
-int OSLShader::find_attribute(const KernelGlobalsCPU *kg,
- const ShaderData *sd,
- uint id,
- AttributeDescriptor *desc)
-{
- /* for OSL, a hash map is used to lookup the attribute by name. */
- int object = sd->object * ATTR_PRIM_TYPES;
-
- OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object];
- ustring stdname(std::string("geom:") +
- std::string(Attribute::standard_name((AttributeStandard)id)));
- OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
-
- if (it != attr_map.end()) {
- const OSLGlobals::Attribute &osl_attr = it->second;
- *desc = osl_attr.desc;
-
- if (sd->prim == PRIM_NONE && (AttributeElement)osl_attr.desc.element != ATTR_ELEMENT_MESH) {
- desc->offset = ATTR_STD_NOT_FOUND;
- return ATTR_STD_NOT_FOUND;
- }
-
- /* return result */
- if (osl_attr.desc.element == ATTR_ELEMENT_NONE) {
- desc->offset = ATTR_STD_NOT_FOUND;
- }
- return desc->offset;
- }
- else {
- desc->offset = ATTR_STD_NOT_FOUND;
- return (int)ATTR_STD_NOT_FOUND;
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h
deleted file mode 100644
index 037a18a1f19..00000000000
--- a/intern/cycles/kernel/osl/osl_shader.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __OSL_SHADER_H__
-#define __OSL_SHADER_H__
-
-#ifdef WITH_OSL
-
-/* OSL Shader Engine
- *
- * Holds all variables to execute and use OSL shaders from the kernel. These
- * are initialized externally by OSLShaderManager before rendering starts.
- *
- * Before/after a thread starts rendering, thread_init/thread_free must be
- * called, which will store any per thread OSL state in thread local storage.
- * This means no thread state must be passed along in the kernel itself.
- */
-
-# include "kernel/kernel_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Scene;
-
-struct ShaderClosure;
-struct ShaderData;
-struct IntegratorStateCPU;
-struct differential3;
-struct KernelGlobalsCPU;
-
-struct OSLGlobals;
-struct OSLShadingSystem;
-
-class OSLShader {
- public:
- /* init */
- static void register_closures(OSLShadingSystem *ss);
-
- /* per thread data */
- static void thread_init(KernelGlobalsCPU *kg, OSLGlobals *osl_globals);
- static void thread_free(KernelGlobalsCPU *kg);
-
- /* eval */
- static void eval_surface(const KernelGlobalsCPU *kg,
- const void *state,
- ShaderData *sd,
- uint32_t path_flag);
- static void eval_background(const KernelGlobalsCPU *kg,
- const void *state,
- ShaderData *sd,
- uint32_t path_flag);
- static void eval_volume(const KernelGlobalsCPU *kg,
- const void *state,
- ShaderData *sd,
- uint32_t path_flag);
- static void eval_displacement(const KernelGlobalsCPU *kg, const void *state, ShaderData *sd);
-
- /* attributes */
- static int find_attribute(const KernelGlobalsCPU *kg,
- const ShaderData *sd,
- uint id,
- AttributeDescriptor *desc);
-};
-
-CCL_NAMESPACE_END
-
-#endif
-
-#endif /* __OSL_SHADER_H__ */
diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp
new file mode 100644
index 00000000000..ca0a5a068b3
--- /dev/null
+++ b/intern/cycles/kernel/osl/services.cpp
@@ -0,0 +1,1724 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* TODO(sergey): There is a bit of headers dependency hell going on
+ * here, so for now we just put here. In the future it might be better
+ * to have dedicated file for such tweaks.
+ */
+#if (defined(__GNUC__) && !defined(__clang__)) && defined(NDEBUG)
+# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+# pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
+
+#include <string.h>
+
+#include "scene/colorspace.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+
+#include "kernel/osl/closures.h"
+#include "kernel/osl/globals.h"
+#include "kernel/osl/services.h"
+#include "kernel/osl/shader.h"
+
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/string.h"
+
+// clang-format off
+#include "kernel/device/cpu/compat.h"
+#include "kernel/device/cpu/globals.h"
+#include "kernel/device/cpu/image.h"
+
+#include "kernel/util/differential.h"
+
+#include "kernel/integrator/state.h"
+#include "kernel/integrator/state_flow.h"
+
+#include "kernel/geom/geom.h"
+
+#include "kernel/bvh/bvh.h"
+
+#include "kernel/camera/camera.h"
+#include "kernel/camera/projection.h"
+
+#include "kernel/integrator/path_state.h"
+#include "kernel/integrator/shader_eval.h"
+
+#include "kernel/util/color.h"
+// clang-format on
+
+CCL_NAMESPACE_BEGIN
+
+/* RenderServices implementation */
+
+static void copy_matrix(OSL::Matrix44 &m, const Transform &tfm)
+{
+ ProjectionTransform t = projection_transpose(ProjectionTransform(tfm));
+ memcpy((void *)&m, &t, sizeof(m));
+}
+
+static void copy_matrix(OSL::Matrix44 &m, const ProjectionTransform &tfm)
+{
+ ProjectionTransform t = projection_transpose(tfm);
+ memcpy((void *)&m, &t, sizeof(m));
+}
+
+/* static ustrings */
+ustring OSLRenderServices::u_distance("distance");
+ustring OSLRenderServices::u_index("index");
+ustring OSLRenderServices::u_world("world");
+ustring OSLRenderServices::u_camera("camera");
+ustring OSLRenderServices::u_screen("screen");
+ustring OSLRenderServices::u_raster("raster");
+ustring OSLRenderServices::u_ndc("NDC");
+ustring OSLRenderServices::u_object_location("object:location");
+ustring OSLRenderServices::u_object_color("object:color");
+ustring OSLRenderServices::u_object_index("object:index");
+ustring OSLRenderServices::u_geom_dupli_generated("geom:dupli_generated");
+ustring OSLRenderServices::u_geom_dupli_uv("geom:dupli_uv");
+ustring OSLRenderServices::u_material_index("material:index");
+ustring OSLRenderServices::u_object_random("object:random");
+ustring OSLRenderServices::u_particle_index("particle:index");
+ustring OSLRenderServices::u_particle_random("particle:random");
+ustring OSLRenderServices::u_particle_age("particle:age");
+ustring OSLRenderServices::u_particle_lifetime("particle:lifetime");
+ustring OSLRenderServices::u_particle_location("particle:location");
+ustring OSLRenderServices::u_particle_rotation("particle:rotation");
+ustring OSLRenderServices::u_particle_size("particle:size");
+ustring OSLRenderServices::u_particle_velocity("particle:velocity");
+ustring OSLRenderServices::u_particle_angular_velocity("particle:angular_velocity");
+ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
+ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
+ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
+ustring OSLRenderServices::u_geom_name("geom:name");
+ustring OSLRenderServices::u_geom_undisplaced("geom:undisplaced");
+ustring OSLRenderServices::u_is_smooth("geom:is_smooth");
+ustring OSLRenderServices::u_is_curve("geom:is_curve");
+ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
+ustring OSLRenderServices::u_curve_length("geom:curve_length");
+ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
+ustring OSLRenderServices::u_curve_random("geom:curve_random");
+ustring OSLRenderServices::u_normal_map_normal("geom:normal_map_normal");
+ustring OSLRenderServices::u_path_ray_length("path:ray_length");
+ustring OSLRenderServices::u_path_ray_depth("path:ray_depth");
+ustring OSLRenderServices::u_path_diffuse_depth("path:diffuse_depth");
+ustring OSLRenderServices::u_path_glossy_depth("path:glossy_depth");
+ustring OSLRenderServices::u_path_transparent_depth("path:transparent_depth");
+ustring OSLRenderServices::u_path_transmission_depth("path:transmission_depth");
+ustring OSLRenderServices::u_trace("trace");
+ustring OSLRenderServices::u_hit("hit");
+ustring OSLRenderServices::u_hitdist("hitdist");
+ustring OSLRenderServices::u_N("N");
+ustring OSLRenderServices::u_Ng("Ng");
+ustring OSLRenderServices::u_P("P");
+ustring OSLRenderServices::u_I("I");
+ustring OSLRenderServices::u_u("u");
+ustring OSLRenderServices::u_v("v");
+ustring OSLRenderServices::u_empty;
+
+OSLRenderServices::OSLRenderServices(OSL::TextureSystem *texture_system)
+ : texture_system(texture_system)
+{
+}
+
+OSLRenderServices::~OSLRenderServices()
+{
+ if (texture_system) {
+ VLOG(2) << "OSL texture system stats:\n" << texture_system->getstats();
+ }
+}
+
+bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ OSL::TransformationPtr xform,
+ float time)
+{
+ /* this is only used for shader and object space, we don't really have
+ * a concept of shader space, so we just use object space for both. */
+ if (xform) {
+ const ShaderData *sd = (const ShaderData *)xform;
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+ int object = sd->object;
+
+ if (object != OBJECT_NONE) {
+#ifdef __OBJECT_MOTION__
+ Transform tfm;
+
+ if (time == sd->time)
+ tfm = object_get_transform(kg, sd);
+ else
+ tfm = object_fetch_transform_motion_test(kg, object, time, NULL);
+#else
+ const Transform tfm = object_get_transform(kg, sd);
+#endif
+ copy_matrix(result, tfm);
+
+ return true;
+ }
+ else if (sd->type == PRIMITIVE_LAMP) {
+ const Transform tfm = lamp_fetch_transform(kg, sd->lamp, false);
+ copy_matrix(result, tfm);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ OSL::TransformationPtr xform,
+ float time)
+{
+ /* this is only used for shader and object space, we don't really have
+ * a concept of shader space, so we just use object space for both. */
+ if (xform) {
+ const ShaderData *sd = (const ShaderData *)xform;
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+ int object = sd->object;
+
+ if (object != OBJECT_NONE) {
+#ifdef __OBJECT_MOTION__
+ Transform itfm;
+
+ if (time == sd->time)
+ itfm = object_get_inverse_transform(kg, sd);
+ else
+ object_fetch_transform_motion_test(kg, object, time, &itfm);
+#else
+ const Transform itfm = object_get_inverse_transform(kg, sd);
+#endif
+ copy_matrix(result, itfm);
+
+ return true;
+ }
+ else if (sd->type == PRIMITIVE_LAMP) {
+ const Transform itfm = lamp_fetch_transform(kg, sd->lamp, true);
+ copy_matrix(result, itfm);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ ustring from,
+ float time)
+{
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+
+ if (from == u_ndc) {
+ copy_matrix(result, kernel_data.cam.ndctoworld);
+ return true;
+ }
+ else if (from == u_raster) {
+ copy_matrix(result, kernel_data.cam.rastertoworld);
+ return true;
+ }
+ else if (from == u_screen) {
+ copy_matrix(result, kernel_data.cam.screentoworld);
+ return true;
+ }
+ else if (from == u_camera) {
+ copy_matrix(result, kernel_data.cam.cameratoworld);
+ return true;
+ }
+ else if (from == u_world) {
+ result.makeIdentity();
+ return true;
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ ustring to,
+ float time)
+{
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+
+ if (to == u_ndc) {
+ copy_matrix(result, kernel_data.cam.worldtondc);
+ return true;
+ }
+ else if (to == u_raster) {
+ copy_matrix(result, kernel_data.cam.worldtoraster);
+ return true;
+ }
+ else if (to == u_screen) {
+ copy_matrix(result, kernel_data.cam.worldtoscreen);
+ return true;
+ }
+ else if (to == u_camera) {
+ copy_matrix(result, kernel_data.cam.worldtocamera);
+ return true;
+ }
+ else if (to == u_world) {
+ result.makeIdentity();
+ return true;
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ OSL::TransformationPtr xform)
+{
+ /* this is only used for shader and object space, we don't really have
+ * a concept of shader space, so we just use object space for both. */
+ if (xform) {
+ const ShaderData *sd = (const ShaderData *)xform;
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+ int object = sd->object;
+
+ if (object != OBJECT_NONE) {
+ const Transform tfm = object_get_transform(kg, sd);
+ copy_matrix(result, tfm);
+
+ return true;
+ }
+ else if (sd->type == PRIMITIVE_LAMP) {
+ const Transform tfm = lamp_fetch_transform(kg, sd->lamp, false);
+ copy_matrix(result, tfm);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ OSL::TransformationPtr xform)
+{
+ /* this is only used for shader and object space, we don't really have
+ * a concept of shader space, so we just use object space for both. */
+ if (xform) {
+ const ShaderData *sd = (const ShaderData *)xform;
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+ int object = sd->object;
+
+ if (object != OBJECT_NONE) {
+ const Transform tfm = object_get_inverse_transform(kg, sd);
+ copy_matrix(result, tfm);
+
+ return true;
+ }
+ else if (sd->type == PRIMITIVE_LAMP) {
+ const Transform itfm = lamp_fetch_transform(kg, sd->lamp, true);
+ copy_matrix(result, itfm);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result, ustring from)
+{
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+
+ if (from == u_ndc) {
+ copy_matrix(result, kernel_data.cam.ndctoworld);
+ return true;
+ }
+ else if (from == u_raster) {
+ copy_matrix(result, kernel_data.cam.rastertoworld);
+ return true;
+ }
+ else if (from == u_screen) {
+ copy_matrix(result, kernel_data.cam.screentoworld);
+ return true;
+ }
+ else if (from == u_camera) {
+ copy_matrix(result, kernel_data.cam.cameratoworld);
+ return true;
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ ustring to)
+{
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+
+ if (to == u_ndc) {
+ copy_matrix(result, kernel_data.cam.worldtondc);
+ return true;
+ }
+ else if (to == u_raster) {
+ copy_matrix(result, kernel_data.cam.worldtoraster);
+ return true;
+ }
+ else if (to == u_screen) {
+ copy_matrix(result, kernel_data.cam.worldtoscreen);
+ return true;
+ }
+ else if (to == u_camera) {
+ copy_matrix(result, kernel_data.cam.worldtocamera);
+ return true;
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_array_attribute(OSL::ShaderGlobals *sg,
+ bool derivatives,
+ ustring object,
+ TypeDesc type,
+ ustring name,
+ int index,
+ void *val)
+{
+ return false;
+}
+
+static bool set_attribute_float2(float2 f[3], TypeDesc type, bool derivatives, void *val)
+{
+ if (type == TypeFloatArray4) {
+ float *fval = (float *)val;
+ fval[0] = f[0].x;
+ fval[1] = f[0].y;
+ fval[2] = 0.0f;
+ fval[3] = 1.0f;
+
+ if (derivatives) {
+ fval[4] = f[1].x;
+ fval[5] = f[1].y;
+ fval[6] = 0.0f;
+ fval[7] = 0.0f;
+
+ fval[8] = f[2].x;
+ fval[9] = f[2].y;
+ fval[10] = 0.0f;
+ fval[11] = 0.0f;
+ }
+ return true;
+ }
+ else if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
+ float *fval = (float *)val;
+
+ fval[0] = f[0].x;
+ fval[1] = f[0].y;
+ fval[2] = 0.0f;
+
+ if (derivatives) {
+ fval[3] = f[1].x;
+ fval[4] = f[1].y;
+ fval[5] = 0.0f;
+
+ fval[6] = f[2].x;
+ fval[7] = f[2].y;
+ fval[8] = 0.0f;
+ }
+
+ return true;
+ }
+ else if (type == TypeDesc::TypeFloat) {
+ float *fval = (float *)val;
+ fval[0] = average(f[0]);
+
+ if (derivatives) {
+ fval[1] = average(f[1]);
+ fval[2] = average(f[2]);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool set_attribute_float2(float2 f, TypeDesc type, bool derivatives, void *val)
+{
+ float2 fv[3];
+
+ fv[0] = f;
+ fv[1] = make_float2(0.0f, 0.0f);
+ fv[2] = make_float2(0.0f, 0.0f);
+
+ return set_attribute_float2(fv, type, derivatives, val);
+}
+
+static bool set_attribute_float3(float3 f[3], TypeDesc type, bool derivatives, void *val)
+{
+ if (type == TypeFloatArray4) {
+ float *fval = (float *)val;
+ fval[0] = f[0].x;
+ fval[1] = f[0].y;
+ fval[2] = f[0].z;
+ fval[3] = 1.0f;
+
+ if (derivatives) {
+ fval[4] = f[1].x;
+ fval[5] = f[1].y;
+ fval[6] = f[1].z;
+ fval[7] = 0.0f;
+
+ fval[8] = f[2].x;
+ fval[9] = f[2].y;
+ fval[10] = f[2].z;
+ fval[11] = 0.0f;
+ }
+ return true;
+ }
+ else if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
+ float *fval = (float *)val;
+
+ fval[0] = f[0].x;
+ fval[1] = f[0].y;
+ fval[2] = f[0].z;
+
+ if (derivatives) {
+ fval[3] = f[1].x;
+ fval[4] = f[1].y;
+ fval[5] = f[1].z;
+
+ fval[6] = f[2].x;
+ fval[7] = f[2].y;
+ fval[8] = f[2].z;
+ }
+
+ return true;
+ }
+ else if (type == TypeDesc::TypeFloat) {
+ float *fval = (float *)val;
+ fval[0] = average(f[0]);
+
+ if (derivatives) {
+ fval[1] = average(f[1]);
+ fval[2] = average(f[2]);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool set_attribute_float3(float3 f, TypeDesc type, bool derivatives, void *val)
+{
+ float3 fv[3];
+
+ fv[0] = f;
+ fv[1] = make_float3(0.0f, 0.0f, 0.0f);
+ fv[2] = make_float3(0.0f, 0.0f, 0.0f);
+
+ return set_attribute_float3(fv, type, derivatives, val);
+}
+
+/* Attributes with the TypeRGBA type descriptor should be retrieved and stored
+ * in a float array of size 4 (e.g. node_vertex_color.osl), this array have
+ * a type descriptor TypeFloatArray4. If the storage is not a TypeFloatArray4,
+ * we either store the first three components in a vector, store the average of
+ * the components in a float, or fail the retrieval and do nothing. We allow
+ * this for the correct operation of the Attribute node.
+ */
+
+static bool set_attribute_float4(float4 f[3], TypeDesc type, bool derivatives, void *val)
+{
+ float *fval = (float *)val;
+ if (type == TypeFloatArray4) {
+ fval[0] = f[0].x;
+ fval[1] = f[0].y;
+ fval[2] = f[0].z;
+ fval[3] = f[0].w;
+
+ if (derivatives) {
+ fval[4] = f[1].x;
+ fval[5] = f[1].y;
+ fval[6] = f[1].z;
+ fval[7] = f[1].w;
+
+ fval[8] = f[2].x;
+ fval[9] = f[2].y;
+ fval[10] = f[2].z;
+ fval[11] = f[2].w;
+ }
+ return true;
+ }
+ else if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
+ fval[0] = f[0].x;
+ fval[1] = f[0].y;
+ fval[2] = f[0].z;
+
+ if (derivatives) {
+ fval[3] = f[1].x;
+ fval[4] = f[1].y;
+ fval[5] = f[1].z;
+
+ fval[6] = f[2].x;
+ fval[7] = f[2].y;
+ fval[8] = f[2].z;
+ }
+ return true;
+ }
+ else if (type == TypeDesc::TypeFloat) {
+ fval[0] = average(float4_to_float3(f[0]));
+
+ if (derivatives) {
+ fval[1] = average(float4_to_float3(f[1]));
+ fval[2] = average(float4_to_float3(f[2]));
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool set_attribute_float4(float4 f, TypeDesc type, bool derivatives, void *val)
+{
+ float4 fv[3];
+
+ fv[0] = f;
+ fv[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ fv[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ return set_attribute_float4(fv, type, derivatives, val);
+}
+
+static bool set_attribute_float(float f[3], TypeDesc type, bool derivatives, void *val)
+{
+ if (type == TypeFloatArray4) {
+ float *fval = (float *)val;
+ fval[0] = f[0];
+ fval[1] = f[0];
+ fval[2] = f[0];
+ fval[3] = 1.0f;
+
+ if (derivatives) {
+ fval[4] = f[1];
+ fval[5] = f[1];
+ fval[6] = f[1];
+ fval[7] = 0.0f;
+
+ fval[8] = f[2];
+ fval[9] = f[2];
+ fval[10] = f[2];
+ fval[11] = 0.0f;
+ }
+ return true;
+ }
+ else if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
+ float *fval = (float *)val;
+ fval[0] = f[0];
+ fval[1] = f[0];
+ fval[2] = f[0];
+
+ if (derivatives) {
+ fval[3] = f[1];
+ fval[4] = f[1];
+ fval[5] = f[1];
+
+ fval[6] = f[2];
+ fval[7] = f[2];
+ fval[8] = f[2];
+ }
+
+ return true;
+ }
+ else if (type == TypeDesc::TypeFloat) {
+ float *fval = (float *)val;
+ fval[0] = f[0];
+
+ if (derivatives) {
+ fval[1] = f[1];
+ fval[2] = f[2];
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool set_attribute_float(float f, TypeDesc type, bool derivatives, void *val)
+{
+ float fv[3];
+
+ fv[0] = f;
+ fv[1] = 0.0f;
+ fv[2] = 0.0f;
+
+ return set_attribute_float(fv, type, derivatives, val);
+}
+
+static bool set_attribute_int(int i, TypeDesc type, bool derivatives, void *val)
+{
+ if (type.basetype == TypeDesc::INT && type.aggregate == TypeDesc::SCALAR && type.arraylen == 0) {
+ int *ival = (int *)val;
+ ival[0] = i;
+
+ if (derivatives) {
+ ival[1] = 0;
+ ival[2] = 0;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool set_attribute_string(ustring str, TypeDesc type, bool derivatives, void *val)
+{
+ if (type.basetype == TypeDesc::STRING && type.aggregate == TypeDesc::SCALAR &&
+ type.arraylen == 0) {
+ ustring *sval = (ustring *)val;
+ sval[0] = str;
+
+ if (derivatives) {
+ sval[1] = OSLRenderServices::u_empty;
+ sval[2] = OSLRenderServices::u_empty;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives, void *val)
+{
+ if (type.vecsemantics == TypeDesc::POINT && type.arraylen >= 3) {
+ float *fval = (float *)val;
+
+ fval[0] = P[0].x;
+ fval[1] = P[0].y;
+ fval[2] = P[0].z;
+
+ fval[3] = P[1].x;
+ fval[4] = P[1].y;
+ fval[5] = P[1].z;
+
+ fval[6] = P[2].x;
+ fval[7] = P[2].y;
+ fval[8] = P[2].z;
+
+ if (type.arraylen > 3)
+ memset(fval + 3 * 3, 0, sizeof(float) * 3 * (type.arraylen - 3));
+ if (derivatives)
+ memset(fval + type.arraylen * 3, 0, sizeof(float) * 2 * 3 * type.arraylen);
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool set_attribute_matrix(const Transform &tfm, TypeDesc type, void *val)
+{
+ if (type == TypeDesc::TypeMatrix) {
+ copy_matrix(*(OSL::Matrix44 *)val, tfm);
+ return true;
+ }
+
+ return false;
+}
+
+static bool get_primitive_attribute(const KernelGlobalsCPU *kg,
+ const ShaderData *sd,
+ const OSLGlobals::Attribute &attr,
+ const TypeDesc &type,
+ bool derivatives,
+ void *val)
+{
+ if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
+ attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
+ float3 fval[3];
+ if (primitive_is_volume_attribute(sd, attr.desc)) {
+ fval[0] = primitive_volume_attribute_float3(kg, sd, attr.desc);
+ }
+ else {
+ memset(fval, 0, sizeof(fval));
+ fval[0] = primitive_surface_attribute_float3(
+ kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
+ }
+ return set_attribute_float3(fval, type, derivatives, val);
+ }
+ else if (attr.type == TypeFloat2) {
+ if (primitive_is_volume_attribute(sd, attr.desc)) {
+ assert(!"Float2 attribute not support for volumes");
+ return false;
+ }
+ else {
+ float2 fval[3];
+ fval[0] = primitive_surface_attribute_float2(
+ kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
+ return set_attribute_float2(fval, type, derivatives, val);
+ }
+ }
+ else if (attr.type == TypeDesc::TypeFloat) {
+ float fval[3];
+ if (primitive_is_volume_attribute(sd, attr.desc)) {
+ memset(fval, 0, sizeof(fval));
+ fval[0] = primitive_volume_attribute_float(kg, sd, attr.desc);
+ }
+ else {
+ fval[0] = primitive_surface_attribute_float(
+ kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
+ }
+ return set_attribute_float(fval, type, derivatives, val);
+ }
+ else if (attr.type == TypeDesc::TypeFloat4 || attr.type == TypeRGBA) {
+ float4 fval[3];
+ if (primitive_is_volume_attribute(sd, attr.desc)) {
+ memset(fval, 0, sizeof(fval));
+ fval[0] = primitive_volume_attribute_float4(kg, sd, attr.desc);
+ }
+ else {
+ fval[0] = primitive_surface_attribute_float4(
+ kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
+ }
+ return set_attribute_float4(fval, type, derivatives, val);
+ }
+ else {
+ return false;
+ }
+}
+
+static bool get_mesh_attribute(const KernelGlobalsCPU *kg,
+ const ShaderData *sd,
+ const OSLGlobals::Attribute &attr,
+ const TypeDesc &type,
+ bool derivatives,
+ void *val)
+{
+ if (attr.type == TypeDesc::TypeMatrix) {
+ Transform tfm = primitive_attribute_matrix(kg, sd, attr.desc);
+ return set_attribute_matrix(tfm, type, val);
+ }
+ else {
+ return false;
+ }
+}
+
+static bool get_object_attribute(const OSLGlobals::Attribute &attr,
+ TypeDesc type,
+ bool derivatives,
+ void *val)
+{
+ if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
+ attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
+ return set_attribute_float3(*(float3 *)attr.value.data(), type, derivatives, val);
+ }
+ else if (attr.type == TypeFloat2) {
+ return set_attribute_float2(*(float2 *)attr.value.data(), type, derivatives, val);
+ }
+ else if (attr.type == TypeDesc::TypeFloat) {
+ return set_attribute_float(*(float *)attr.value.data(), type, derivatives, val);
+ }
+ else if (attr.type == TypeRGBA || attr.type == TypeDesc::TypeFloat4) {
+ return set_attribute_float4(*(float4 *)attr.value.data(), type, derivatives, val);
+ }
+ else if (attr.type == type) {
+ size_t datasize = attr.value.datasize();
+
+ memcpy(val, attr.value.data(), datasize);
+ if (derivatives) {
+ memset((char *)val + datasize, 0, datasize * 2);
+ }
+
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg,
+ ShaderData *sd,
+ ustring name,
+ TypeDesc type,
+ bool derivatives,
+ void *val)
+{
+ /* todo: turn this into hash table? */
+
+ /* Object Attributes */
+ if (name == u_object_location) {
+ float3 f = object_location(kg, sd);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+ else if (name == u_object_color) {
+ float3 f = object_color(kg, sd->object);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+ else if (name == u_object_index) {
+ float f = object_pass_id(kg, sd->object);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_geom_dupli_generated) {
+ float3 f = object_dupli_generated(kg, sd->object);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+ else if (name == u_geom_dupli_uv) {
+ float3 f = object_dupli_uv(kg, sd->object);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+ else if (name == u_material_index) {
+ float f = shader_pass_id(kg, sd);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_object_random) {
+ float f = object_random_number(kg, sd->object);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+
+ /* Particle Attributes */
+ else if (name == u_particle_index) {
+ int particle_id = object_particle_id(kg, sd->object);
+ float f = particle_index(kg, particle_id);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_particle_random) {
+ int particle_id = object_particle_id(kg, sd->object);
+ float f = hash_uint2_to_float(particle_index(kg, particle_id), 0);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+
+ else if (name == u_particle_age) {
+ int particle_id = object_particle_id(kg, sd->object);
+ float f = particle_age(kg, particle_id);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_particle_lifetime) {
+ int particle_id = object_particle_id(kg, sd->object);
+ float f = particle_lifetime(kg, particle_id);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_particle_location) {
+ int particle_id = object_particle_id(kg, sd->object);
+ float3 f = particle_location(kg, particle_id);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+#if 0 /* unsupported */
+ else if (name == u_particle_rotation) {
+ int particle_id = object_particle_id(kg, sd->object);
+ float4 f = particle_rotation(kg, particle_id);
+ return set_attribute_float4(f, type, derivatives, val);
+ }
+#endif
+ else if (name == u_particle_size) {
+ int particle_id = object_particle_id(kg, sd->object);
+ float f = particle_size(kg, particle_id);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_particle_velocity) {
+ int particle_id = object_particle_id(kg, sd->object);
+ float3 f = particle_velocity(kg, particle_id);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+ else if (name == u_particle_angular_velocity) {
+ int particle_id = object_particle_id(kg, sd->object);
+ float3 f = particle_angular_velocity(kg, particle_id);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+
+ /* Geometry Attributes */
+ else if (name == u_geom_numpolyvertices) {
+ return set_attribute_int(3, type, derivatives, val);
+ }
+ else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices) &&
+ sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ float3 P[3];
+
+ if (sd->type & PRIMITIVE_TRIANGLE)
+ triangle_vertices(kg, sd->prim, P);
+ else
+ motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P);
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ object_position_transform(kg, sd, &P[0]);
+ object_position_transform(kg, sd, &P[1]);
+ object_position_transform(kg, sd, &P[2]);
+ }
+
+ return set_attribute_float3_3(P, type, derivatives, val);
+ }
+ else if (name == u_geom_name) {
+ ustring object_name = kg->osl->object_names[sd->object];
+ return set_attribute_string(object_name, type, derivatives, val);
+ }
+ else if (name == u_is_smooth) {
+ float f = ((sd->shader & SHADER_SMOOTH_NORMAL) != 0);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ /* Hair Attributes */
+ else if (name == u_is_curve) {
+ float f = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_curve_thickness) {
+ float f = curve_thickness(kg, sd);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_curve_tangent_normal) {
+ float3 f = curve_tangent_normal(kg, sd);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+ else if (name == u_normal_map_normal) {
+ if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+}
+
+bool OSLRenderServices::get_background_attribute(const KernelGlobalsCPU *kg,
+ ShaderData *sd,
+ ustring name,
+ TypeDesc type,
+ bool derivatives,
+ void *val)
+{
+ if (name == u_path_ray_length) {
+ /* Ray Length */
+ float f = sd->ray_length;
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_path_ray_depth) {
+ /* Ray Depth */
+ const IntegratorStateCPU *state = sd->osl_path_state;
+ const IntegratorShadowStateCPU *shadow_state = sd->osl_shadow_path_state;
+ int f = (state) ? state->path.bounce : (shadow_state) ? shadow_state->shadow_path.bounce : 0;
+ return set_attribute_int(f, type, derivatives, val);
+ }
+ else if (name == u_path_diffuse_depth) {
+ /* Diffuse Ray Depth */
+ const IntegratorStateCPU *state = sd->osl_path_state;
+ const IntegratorShadowStateCPU *shadow_state = sd->osl_shadow_path_state;
+ int f = (state) ? state->path.diffuse_bounce :
+ (shadow_state) ? shadow_state->shadow_path.diffuse_bounce :
+ 0;
+ return set_attribute_int(f, type, derivatives, val);
+ }
+ else if (name == u_path_glossy_depth) {
+ /* Glossy Ray Depth */
+ const IntegratorStateCPU *state = sd->osl_path_state;
+ const IntegratorShadowStateCPU *shadow_state = sd->osl_shadow_path_state;
+ int f = (state) ? state->path.glossy_bounce :
+ (shadow_state) ? shadow_state->shadow_path.glossy_bounce :
+ 0;
+ return set_attribute_int(f, type, derivatives, val);
+ }
+ else if (name == u_path_transmission_depth) {
+ /* Transmission Ray Depth */
+ const IntegratorStateCPU *state = sd->osl_path_state;
+ const IntegratorShadowStateCPU *shadow_state = sd->osl_shadow_path_state;
+ int f = (state) ? state->path.transmission_bounce :
+ (shadow_state) ? shadow_state->shadow_path.transmission_bounce :
+ 0;
+ return set_attribute_int(f, type, derivatives, val);
+ }
+ else if (name == u_path_transparent_depth) {
+ /* Transparent Ray Depth */
+ const IntegratorStateCPU *state = sd->osl_path_state;
+ const IntegratorShadowStateCPU *shadow_state = sd->osl_shadow_path_state;
+ int f = (state) ? state->path.transparent_bounce :
+ (shadow_state) ? shadow_state->shadow_path.transparent_bounce :
+ 0;
+ return set_attribute_int(f, type, derivatives, val);
+ }
+ else if (name == u_ndc) {
+ /* NDC coordinates with special exception for orthographic projection. */
+ OSLThreadData *tdata = kg->osl_tdata;
+ OSL::ShaderGlobals *globals = &tdata->globals;
+ float3 ndc[3];
+
+ if ((globals->raytype & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
+ kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
+ ndc[0] = camera_world_to_ndc(kg, sd, sd->ray_P);
+
+ if (derivatives) {
+ ndc[1] = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(sd->ray_dP, 0.0f, 0.0f)) -
+ ndc[0];
+ ndc[2] = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(0.0f, sd->ray_dP, 0.0f)) -
+ ndc[0];
+ }
+ }
+ else {
+ ndc[0] = camera_world_to_ndc(kg, sd, sd->P);
+
+ if (derivatives) {
+ ndc[1] = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dx) - ndc[0];
+ ndc[2] = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dy) - ndc[0];
+ }
+ }
+
+ return set_attribute_float3(ndc, type, derivatives, val);
+ }
+ else
+ return false;
+}
+
+bool OSLRenderServices::get_attribute(OSL::ShaderGlobals *sg,
+ bool derivatives,
+ ustring object_name,
+ TypeDesc type,
+ ustring name,
+ void *val)
+{
+ if (sg == NULL || sg->renderstate == NULL)
+ return false;
+
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ return get_attribute(sd, derivatives, object_name, type, name, val);
+}
+
+bool OSLRenderServices::get_attribute(
+ ShaderData *sd, bool derivatives, ustring object_name, TypeDesc type, ustring name, void *val)
+{
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+ int prim_type = 0;
+ int object;
+
+ /* lookup of attribute on another object */
+ if (object_name != u_empty) {
+ OSLGlobals::ObjectNameMap::iterator it = kg->osl->object_name_map.find(object_name);
+
+ if (it == kg->osl->object_name_map.end())
+ return false;
+
+ object = it->second;
+ }
+ else {
+ object = sd->object;
+ prim_type = attribute_primitive_type(kg, sd);
+
+ if (object == OBJECT_NONE)
+ return get_background_attribute(kg, sd, name, type, derivatives, val);
+ }
+
+ /* find attribute on object */
+ object = object * ATTR_PRIM_TYPES + prim_type;
+ OSLGlobals::AttributeMap &attribute_map = kg->osl->attribute_map[object];
+ OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
+
+ if (it != attribute_map.end()) {
+ const OSLGlobals::Attribute &attr = it->second;
+
+ if (attr.desc.element != ATTR_ELEMENT_OBJECT) {
+ /* triangle and vertex attributes */
+ if (get_primitive_attribute(kg, sd, attr, type, derivatives, val))
+ return true;
+ else
+ return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
+ }
+ else {
+ /* object attribute */
+ return get_object_attribute(attr, type, derivatives, val);
+ }
+ }
+ else {
+ /* not found in attribute, check standard object info */
+ bool is_std_object_attribute = get_object_standard_attribute(
+ kg, sd, name, type, derivatives, val);
+
+ if (is_std_object_attribute)
+ return true;
+
+ return get_background_attribute(kg, sd, name, type, derivatives, val);
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_userdata(
+ bool derivatives, ustring name, TypeDesc type, OSL::ShaderGlobals *sg, void *val)
+{
+ return false; /* disabled by lockgeom */
+}
+
+#if OSL_LIBRARY_VERSION_CODE >= 11100
+TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename,
+ OSL::ShadingContext *)
+#else
+
+TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename)
+#endif
+{
+ OSLTextureHandleMap::iterator it = textures.find(filename);
+
+ /* For non-OIIO textures, just return a pointer to our own OSLTextureHandle. */
+ if (it != textures.end()) {
+ if (it->second->type != OSLTextureHandle::OIIO) {
+ return (TextureSystem::TextureHandle *)it->second.get();
+ }
+ }
+
+ /* Get handle from OpenImageIO. */
+ OSL::TextureSystem *ts = texture_system;
+ TextureSystem::TextureHandle *handle = ts->get_texture_handle(filename);
+ if (handle == NULL) {
+ return NULL;
+ }
+
+ /* Insert new OSLTextureHandle if needed. */
+ if (it == textures.end()) {
+ textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::OIIO));
+ it = textures.find(filename);
+ }
+
+ /* Assign OIIO texture handle and return. */
+ it->second->oiio_handle = handle;
+ return (TextureSystem::TextureHandle *)it->second.get();
+}
+
+bool OSLRenderServices::good(TextureSystem::TextureHandle *texture_handle)
+{
+ OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
+
+ if (handle->oiio_handle) {
+ OSL::TextureSystem *ts = texture_system;
+ return ts->good(handle->oiio_handle);
+ }
+ else {
+ return true;
+ }
+}
+
+bool OSLRenderServices::texture(ustring filename,
+ TextureHandle *texture_handle,
+ TexturePerthread *texture_thread_info,
+ TextureOpt &options,
+ OSL::ShaderGlobals *sg,
+ float s,
+ float t,
+ float dsdx,
+ float dtdx,
+ float dsdy,
+ float dtdy,
+ int nchannels,
+ float *result,
+ float *dresultds,
+ float *dresultdt,
+ ustring *errormessage)
+{
+ OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
+ OSLTextureHandle::Type texture_type = (handle) ? handle->type : OSLTextureHandle::OIIO;
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals kernel_globals = sd->osl_globals;
+ bool status = false;
+
+ switch (texture_type) {
+ case OSLTextureHandle::BEVEL: {
+ /* Bevel shader hack. */
+ if (nchannels >= 3) {
+ const IntegratorStateCPU *state = sd->osl_path_state;
+ if (state) {
+ int num_samples = (int)s;
+ float radius = t;
+ float3 N = svm_bevel(kernel_globals, state, sd, radius, num_samples);
+ result[0] = N.x;
+ result[1] = N.y;
+ result[2] = N.z;
+ status = true;
+ }
+ }
+ break;
+ }
+ case OSLTextureHandle::AO: {
+ /* AO shader hack. */
+ const IntegratorStateCPU *state = sd->osl_path_state;
+ if (state) {
+ int num_samples = (int)s;
+ float radius = t;
+ float3 N = make_float3(dsdx, dtdx, dsdy);
+ int flags = 0;
+ if ((int)dtdy) {
+ flags |= NODE_AO_INSIDE;
+ }
+ if ((int)options.sblur) {
+ flags |= NODE_AO_ONLY_LOCAL;
+ }
+ if ((int)options.tblur) {
+ flags |= NODE_AO_GLOBAL_RADIUS;
+ }
+ result[0] = svm_ao(kernel_globals, state, sd, N, radius, num_samples, flags);
+ status = true;
+ }
+ break;
+ }
+ case OSLTextureHandle::SVM: {
+ /* Packed texture. */
+ float4 rgba = kernel_tex_image_interp(kernel_globals, handle->svm_slot, s, 1.0f - t);
+
+ result[0] = rgba[0];
+ if (nchannels > 1)
+ result[1] = rgba[1];
+ if (nchannels > 2)
+ result[2] = rgba[2];
+ if (nchannels > 3)
+ result[3] = rgba[3];
+ status = true;
+ break;
+ }
+ case OSLTextureHandle::IES: {
+ /* IES light. */
+ result[0] = kernel_ies_interp(kernel_globals, handle->svm_slot, s, t);
+ status = true;
+ break;
+ }
+ case OSLTextureHandle::OIIO: {
+ /* OpenImageIO texture cache. */
+ OSL::TextureSystem *ts = texture_system;
+
+ if (handle && handle->oiio_handle) {
+ if (texture_thread_info == NULL) {
+ OSLThreadData *tdata = kernel_globals->osl_tdata;
+ texture_thread_info = tdata->oiio_thread_info;
+ }
+
+ status = ts->texture(handle->oiio_handle,
+ texture_thread_info,
+ options,
+ s,
+ t,
+ dsdx,
+ dtdx,
+ dsdy,
+ dtdy,
+ nchannels,
+ result,
+ dresultds,
+ dresultdt);
+ }
+ else {
+ status = ts->texture(filename,
+ options,
+ s,
+ t,
+ dsdx,
+ dtdx,
+ dsdy,
+ dtdy,
+ nchannels,
+ result,
+ dresultds,
+ dresultdt);
+ }
+
+ if (!status) {
+ /* This might be slow, but prevents error messages leak and
+ * other nasty stuff happening. */
+ ts->geterror();
+ }
+ else if (handle && handle->processor) {
+ ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
+ }
+ break;
+ }
+ }
+
+ if (!status) {
+ if (nchannels == 3 || nchannels == 4) {
+ result[0] = 1.0f;
+ result[1] = 0.0f;
+ result[2] = 1.0f;
+
+ if (nchannels == 4)
+ result[3] = 1.0f;
+ }
+ }
+
+ return status;
+}
+
+bool OSLRenderServices::texture3d(ustring filename,
+ TextureHandle *texture_handle,
+ TexturePerthread *texture_thread_info,
+ TextureOpt &options,
+ OSL::ShaderGlobals *sg,
+ const OSL::Vec3 &P,
+ const OSL::Vec3 &dPdx,
+ const OSL::Vec3 &dPdy,
+ const OSL::Vec3 &dPdz,
+ int nchannels,
+ float *result,
+ float *dresultds,
+ float *dresultdt,
+ float *dresultdr,
+ ustring *errormessage)
+{
+ OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
+ OSLTextureHandle::Type texture_type = (handle) ? handle->type : OSLTextureHandle::OIIO;
+ bool status = false;
+
+ switch (texture_type) {
+ case OSLTextureHandle::SVM: {
+ /* Packed texture. */
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals kernel_globals = sd->osl_globals;
+ int slot = handle->svm_slot;
+ float3 P_float3 = make_float3(P.x, P.y, P.z);
+ float4 rgba = kernel_tex_image_interp_3d(kernel_globals, slot, P_float3, INTERPOLATION_NONE);
+
+ result[0] = rgba[0];
+ if (nchannels > 1)
+ result[1] = rgba[1];
+ if (nchannels > 2)
+ result[2] = rgba[2];
+ if (nchannels > 3)
+ result[3] = rgba[3];
+ status = true;
+ break;
+ }
+ case OSLTextureHandle::OIIO: {
+ /* OpenImageIO texture cache. */
+ OSL::TextureSystem *ts = texture_system;
+
+ if (handle && handle->oiio_handle) {
+ if (texture_thread_info == NULL) {
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals kernel_globals = sd->osl_globals;
+ OSLThreadData *tdata = kernel_globals->osl_tdata;
+ texture_thread_info = tdata->oiio_thread_info;
+ }
+
+ status = ts->texture3d(handle->oiio_handle,
+ texture_thread_info,
+ options,
+ P,
+ dPdx,
+ dPdy,
+ dPdz,
+ nchannels,
+ result,
+ dresultds,
+ dresultdt,
+ dresultdr);
+ }
+ else {
+ status = ts->texture3d(filename,
+ options,
+ P,
+ dPdx,
+ dPdy,
+ dPdz,
+ nchannels,
+ result,
+ dresultds,
+ dresultdt,
+ dresultdr);
+ }
+
+ if (!status) {
+ /* This might be slow, but prevents error messages leak and
+ * other nasty stuff happening. */
+ ts->geterror();
+ }
+ else if (handle && handle->processor) {
+ ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
+ }
+ break;
+ }
+ case OSLTextureHandle::IES:
+ case OSLTextureHandle::AO:
+ case OSLTextureHandle::BEVEL: {
+ status = false;
+ break;
+ }
+ }
+
+ if (!status) {
+ if (nchannels == 3 || nchannels == 4) {
+ result[0] = 1.0f;
+ result[1] = 0.0f;
+ result[2] = 1.0f;
+
+ if (nchannels == 4)
+ result[3] = 1.0f;
+ }
+ }
+
+ return status;
+}
+
+bool OSLRenderServices::environment(ustring filename,
+ TextureHandle *texture_handle,
+ TexturePerthread *thread_info,
+ TextureOpt &options,
+ OSL::ShaderGlobals *sg,
+ const OSL::Vec3 &R,
+ const OSL::Vec3 &dRdx,
+ const OSL::Vec3 &dRdy,
+ int nchannels,
+ float *result,
+ float *dresultds,
+ float *dresultdt,
+ ustring *errormessage)
+{
+ OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
+ OSL::TextureSystem *ts = texture_system;
+ bool status = false;
+
+ if (handle && handle->oiio_handle) {
+ if (thread_info == NULL) {
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals kernel_globals = sd->osl_globals;
+ OSLThreadData *tdata = kernel_globals->osl_tdata;
+ thread_info = tdata->oiio_thread_info;
+ }
+
+ status = ts->environment(handle->oiio_handle,
+ thread_info,
+ options,
+ R,
+ dRdx,
+ dRdy,
+ nchannels,
+ result,
+ dresultds,
+ dresultdt);
+ }
+ else {
+ status = ts->environment(
+ filename, options, R, dRdx, dRdy, nchannels, result, dresultds, dresultdt);
+ }
+
+ if (!status) {
+ if (nchannels == 3 || nchannels == 4) {
+ result[0] = 1.0f;
+ result[1] = 0.0f;
+ result[2] = 1.0f;
+
+ if (nchannels == 4)
+ result[3] = 1.0f;
+ }
+ }
+ else if (handle && handle->processor) {
+ ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
+ }
+
+ return status;
+}
+
+#if OSL_LIBRARY_VERSION_CODE >= 11100
+bool OSLRenderServices::get_texture_info(ustring filename,
+ TextureHandle *texture_handle,
+ TexturePerthread *,
+ OSL::ShadingContext *,
+ int subimage,
+ ustring dataname,
+ TypeDesc datatype,
+ void *data,
+ ustring *)
+#else
+bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg,
+ ustring filename,
+ TextureHandle *texture_handle,
+ int subimage,
+ ustring dataname,
+ TypeDesc datatype,
+ void *data)
+#endif
+{
+ OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
+
+ /* No texture info for other texture types. */
+ if (handle && handle->type != OSLTextureHandle::OIIO) {
+ return false;
+ }
+
+ /* Get texture info from OpenImageIO. */
+ OSL::TextureSystem *ts = texture_system;
+ return ts->get_texture_info(filename, subimage, dataname, datatype, data);
+}
+
+int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg,
+ ustring filename,
+ const OSL::Vec3 &center,
+ float radius,
+ int max_points,
+ bool sort,
+ size_t *out_indices,
+ float *out_distances,
+ int derivs_offset)
+{
+ return 0;
+}
+
+int OSLRenderServices::pointcloud_get(OSL::ShaderGlobals *sg,
+ ustring filename,
+ size_t *indices,
+ int count,
+ ustring attr_name,
+ TypeDesc attr_type,
+ void *out_data)
+{
+ return 0;
+}
+
+bool OSLRenderServices::pointcloud_write(OSL::ShaderGlobals *sg,
+ ustring filename,
+ const OSL::Vec3 &pos,
+ int nattribs,
+ const ustring *names,
+ const TypeDesc *types,
+ const void **data)
+{
+ return false;
+}
+
+bool OSLRenderServices::trace(TraceOpt &options,
+ OSL::ShaderGlobals *sg,
+ const OSL::Vec3 &P,
+ const OSL::Vec3 &dPdx,
+ const OSL::Vec3 &dPdy,
+ const OSL::Vec3 &R,
+ const OSL::Vec3 &dRdx,
+ const OSL::Vec3 &dRdy)
+{
+ /* todo: options.shader support, maybe options.traceset */
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+
+ /* setup ray */
+ Ray ray;
+
+ ray.P = TO_FLOAT3(P);
+ ray.D = TO_FLOAT3(R);
+ ray.t = (options.maxdist == 1.0e30f) ? FLT_MAX : options.maxdist - options.mindist;
+ ray.time = sd->time;
+
+ if (options.mindist == 0.0f) {
+ /* avoid self-intersections */
+ if (ray.P == sd->P) {
+ bool transmit = (dot(sd->Ng, ray.D) < 0.0f);
+ ray.P = ray_offset(sd->P, (transmit) ? -sd->Ng : sd->Ng);
+ }
+ }
+ else {
+ /* offset for minimum distance */
+ ray.P += options.mindist * ray.D;
+ }
+
+ /* ray differentials */
+ differential3 dP;
+ dP.dx = TO_FLOAT3(dPdx);
+ dP.dy = TO_FLOAT3(dPdy);
+ ray.dP = differential_make_compact(dP);
+ differential3 dD;
+ dD.dx = TO_FLOAT3(dRdx);
+ dD.dy = TO_FLOAT3(dRdy);
+ ray.dD = differential_make_compact(dD);
+
+ /* allocate trace data */
+ OSLTraceData *tracedata = (OSLTraceData *)sg->tracedata;
+ tracedata->ray = ray;
+ tracedata->setup = false;
+ tracedata->init = true;
+ tracedata->hit = false;
+ tracedata->sd.osl_globals = sd->osl_globals;
+
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+
+ /* Can't raytrace from shaders like displacement, before BVH exists. */
+ if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
+ return false;
+ }
+
+ /* Raytrace, leaving out shadow opaque to avoid early exit. */
+ uint visibility = PATH_RAY_ALL_VISIBILITY - PATH_RAY_SHADOW_OPAQUE;
+ tracedata->hit = scene_intersect(kg, &ray, visibility, &tracedata->isect);
+ return tracedata->hit;
+}
+
+bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg,
+ ustring source,
+ ustring name,
+ TypeDesc type,
+ void *val,
+ bool derivatives)
+{
+ OSLTraceData *tracedata = (OSLTraceData *)sg->tracedata;
+
+ if (source == u_trace && tracedata->init) {
+ if (name == u_hit) {
+ return set_attribute_int(tracedata->hit, type, derivatives, val);
+ }
+ else if (tracedata->hit) {
+ if (name == u_hitdist) {
+ float f[3] = {tracedata->isect.t, 0.0f, 0.0f};
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else {
+ ShaderData *sd = &tracedata->sd;
+ const KernelGlobalsCPU *kg = sd->osl_globals;
+
+ if (!tracedata->setup) {
+ /* lazy shader data setup */
+ shader_setup_from_ray(kg, sd, &tracedata->ray, &tracedata->isect);
+ tracedata->setup = true;
+ }
+
+ if (name == u_N) {
+ return set_attribute_float3(sd->N, type, derivatives, val);
+ }
+ else if (name == u_Ng) {
+ return set_attribute_float3(sd->Ng, type, derivatives, val);
+ }
+ else if (name == u_P) {
+ float3 f[3] = {sd->P, sd->dP.dx, sd->dP.dy};
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+ else if (name == u_I) {
+ float3 f[3] = {sd->I, sd->dI.dx, sd->dI.dy};
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+ else if (name == u_u) {
+ float f[3] = {sd->u, sd->du.dx, sd->du.dy};
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_v) {
+ float f[3] = {sd->v, sd->dv.dx, sd->dv.dy};
+ return set_attribute_float(f, type, derivatives, val);
+ }
+
+ return get_attribute(sd, derivatives, u_empty, type, name, val);
+ }
+ }
+ }
+
+ return false;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/services.h
index d9f57c642ad..d9f57c642ad 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/services.h
diff --git a/intern/cycles/kernel/osl/shader.cpp b/intern/cycles/kernel/osl/shader.cpp
new file mode 100644
index 00000000000..33633c69e29
--- /dev/null
+++ b/intern/cycles/kernel/osl/shader.cpp
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <OSL/oslexec.h>
+
+// clang-format off
+#include "kernel/device/cpu/compat.h"
+#include "kernel/device/cpu/globals.h"
+
+#include "kernel/types.h"
+
+#include "kernel/geom/object.h"
+
+#include "kernel/integrator/state.h"
+
+#include "kernel/osl/closures.h"
+#include "kernel/osl/globals.h"
+#include "kernel/osl/services.h"
+#include "kernel/osl/shader.h"
+// clang-format on
+
+#include "scene/attribute.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Threads */
+
+void OSLShader::thread_init(KernelGlobalsCPU *kg, OSLGlobals *osl_globals)
+{
+ /* no osl used? */
+ if (!osl_globals->use) {
+ kg->osl = NULL;
+ return;
+ }
+
+ /* Per thread kernel data init. */
+ kg->osl = osl_globals;
+
+ OSL::ShadingSystem *ss = kg->osl->ss;
+ OSLThreadData *tdata = new OSLThreadData();
+
+ memset((void *)&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
+ tdata->globals.tracedata = &tdata->tracedata;
+ tdata->globals.flipHandedness = false;
+ tdata->osl_thread_info = ss->create_thread_info();
+ tdata->context = ss->get_context(tdata->osl_thread_info);
+
+ tdata->oiio_thread_info = osl_globals->ts->get_perthread_info();
+
+ kg->osl_ss = (OSLShadingSystem *)ss;
+ kg->osl_tdata = tdata;
+}
+
+void OSLShader::thread_free(KernelGlobalsCPU *kg)
+{
+ if (!kg->osl)
+ return;
+
+ OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
+ OSLThreadData *tdata = kg->osl_tdata;
+ ss->release_context(tdata->context);
+
+ ss->destroy_thread_info(tdata->osl_thread_info);
+
+ delete tdata;
+
+ kg->osl = NULL;
+ kg->osl_ss = NULL;
+ kg->osl_tdata = NULL;
+}
+
+/* Globals */
+
+static void shaderdata_to_shaderglobals(const KernelGlobalsCPU *kg,
+ ShaderData *sd,
+ const void *state,
+ uint32_t path_flag,
+ OSLThreadData *tdata)
+{
+ OSL::ShaderGlobals *globals = &tdata->globals;
+
+ /* copy from shader data to shader globals */
+ globals->P = TO_VEC3(sd->P);
+ globals->dPdx = TO_VEC3(sd->dP.dx);
+ globals->dPdy = TO_VEC3(sd->dP.dy);
+ globals->I = TO_VEC3(sd->I);
+ globals->dIdx = TO_VEC3(sd->dI.dx);
+ globals->dIdy = TO_VEC3(sd->dI.dy);
+ globals->N = TO_VEC3(sd->N);
+ globals->Ng = TO_VEC3(sd->Ng);
+ globals->u = sd->u;
+ globals->dudx = sd->du.dx;
+ globals->dudy = sd->du.dy;
+ globals->v = sd->v;
+ globals->dvdx = sd->dv.dx;
+ globals->dvdy = sd->dv.dy;
+ globals->dPdu = TO_VEC3(sd->dPdu);
+ globals->dPdv = TO_VEC3(sd->dPdv);
+ globals->surfacearea = 1.0f;
+ globals->time = sd->time;
+
+ /* booleans */
+ globals->raytype = path_flag;
+ globals->backfacing = (sd->flag & SD_BACKFACING);
+
+ /* shader data to be used in services callbacks */
+ globals->renderstate = sd;
+
+ /* hacky, we leave it to services to fetch actual object matrix */
+ globals->shader2common = sd;
+ globals->object2common = sd;
+
+ /* must be set to NULL before execute */
+ globals->Ci = NULL;
+
+ /* clear trace data */
+ tdata->tracedata.init = false;
+
+ /* Used by render-services. */
+ sd->osl_globals = kg;
+ if (path_flag & PATH_RAY_SHADOW) {
+ sd->osl_shadow_path_state = (const IntegratorShadowStateCPU *)state;
+ }
+ else {
+ sd->osl_path_state = (const IntegratorStateCPU *)state;
+ }
+}
+
+/* Surface */
+
+static void flatten_surface_closure_tree(ShaderData *sd,
+ uint32_t path_flag,
+ const OSL::ClosureColor *closure,
+ float3 weight = make_float3(1.0f, 1.0f, 1.0f))
+{
+ /* OSL gives us a closure tree, we flatten it into arrays per
+ * closure type, for evaluation, sampling, etc later on. */
+
+ switch (closure->id) {
+ case OSL::ClosureColor::MUL: {
+ OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
+ flatten_surface_closure_tree(sd, path_flag, mul->closure, TO_FLOAT3(mul->weight) * weight);
+ break;
+ }
+ case OSL::ClosureColor::ADD: {
+ OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
+ flatten_surface_closure_tree(sd, path_flag, add->closureA, weight);
+ flatten_surface_closure_tree(sd, path_flag, add->closureB, weight);
+ break;
+ }
+ default: {
+ OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
+ CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
+
+ if (prim) {
+#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
+ weight = weight * TO_FLOAT3(comp->w);
+#endif
+ prim->setup(sd, path_flag, weight);
+ }
+ break;
+ }
+ }
+}
+
+void OSLShader::eval_surface(const KernelGlobalsCPU *kg,
+ const void *state,
+ ShaderData *sd,
+ uint32_t path_flag)
+{
+ /* setup shader globals from shader data */
+ OSLThreadData *tdata = kg->osl_tdata;
+ shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
+
+ /* execute shader for this point */
+ OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
+ OSL::ShaderGlobals *globals = &tdata->globals;
+ OSL::ShadingContext *octx = tdata->context;
+ int shader = sd->shader & SHADER_MASK;
+
+ /* automatic bump shader */
+ if (kg->osl->bump_state[shader]) {
+ /* save state */
+ float3 P = sd->P;
+ float3 dPdx = sd->dP.dx;
+ float3 dPdy = sd->dP.dy;
+
+ /* set state as if undisplaced */
+ if (sd->flag & SD_HAS_DISPLACEMENT) {
+ float data[9];
+ bool found = kg->osl->services->get_attribute(sd,
+ true,
+ OSLRenderServices::u_empty,
+ TypeDesc::TypeVector,
+ OSLRenderServices::u_geom_undisplaced,
+ data);
+ (void)found;
+ assert(found);
+
+ memcpy(&sd->P, data, sizeof(float) * 3);
+ memcpy(&sd->dP.dx, data + 3, sizeof(float) * 3);
+ memcpy(&sd->dP.dy, data + 6, sizeof(float) * 3);
+
+ object_position_transform(kg, sd, &sd->P);
+ object_dir_transform(kg, sd, &sd->dP.dx);
+ object_dir_transform(kg, sd, &sd->dP.dy);
+
+ globals->P = TO_VEC3(sd->P);
+ globals->dPdx = TO_VEC3(sd->dP.dx);
+ globals->dPdy = TO_VEC3(sd->dP.dy);
+ }
+
+ /* execute bump shader */
+ ss->execute(octx, *(kg->osl->bump_state[shader]), *globals);
+
+ /* reset state */
+ sd->P = P;
+ sd->dP.dx = dPdx;
+ sd->dP.dy = dPdy;
+
+ globals->P = TO_VEC3(P);
+ globals->dPdx = TO_VEC3(dPdx);
+ globals->dPdy = TO_VEC3(dPdy);
+ }
+
+ /* surface shader */
+ if (kg->osl->surface_state[shader]) {
+ ss->execute(octx, *(kg->osl->surface_state[shader]), *globals);
+ }
+
+ /* flatten closure tree */
+ if (globals->Ci)
+ flatten_surface_closure_tree(sd, path_flag, globals->Ci);
+}
+
+/* Background */
+
+static void flatten_background_closure_tree(ShaderData *sd,
+ const OSL::ClosureColor *closure,
+ float3 weight = make_float3(1.0f, 1.0f, 1.0f))
+{
+ /* OSL gives us a closure tree, if we are shading for background there
+ * is only one supported closure type at the moment, which has no evaluation
+ * functions, so we just sum the weights */
+
+ switch (closure->id) {
+ case OSL::ClosureColor::MUL: {
+ OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
+ flatten_background_closure_tree(sd, mul->closure, weight * TO_FLOAT3(mul->weight));
+ break;
+ }
+ case OSL::ClosureColor::ADD: {
+ OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
+
+ flatten_background_closure_tree(sd, add->closureA, weight);
+ flatten_background_closure_tree(sd, add->closureB, weight);
+ break;
+ }
+ default: {
+ OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
+ CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
+
+ if (prim) {
+#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
+ weight = weight * TO_FLOAT3(comp->w);
+#endif
+ prim->setup(sd, 0, weight);
+ }
+ break;
+ }
+ }
+}
+
+void OSLShader::eval_background(const KernelGlobalsCPU *kg,
+ const void *state,
+ ShaderData *sd,
+ uint32_t path_flag)
+{
+ /* setup shader globals from shader data */
+ OSLThreadData *tdata = kg->osl_tdata;
+ shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
+
+ /* execute shader for this point */
+ OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
+ OSL::ShaderGlobals *globals = &tdata->globals;
+ OSL::ShadingContext *octx = tdata->context;
+
+ if (kg->osl->background_state) {
+ ss->execute(octx, *(kg->osl->background_state), *globals);
+ }
+
+ /* return background color immediately */
+ if (globals->Ci)
+ flatten_background_closure_tree(sd, globals->Ci);
+}
+
+/* Volume */
+
+static void flatten_volume_closure_tree(ShaderData *sd,
+ const OSL::ClosureColor *closure,
+ float3 weight = make_float3(1.0f, 1.0f, 1.0f))
+{
+ /* OSL gives us a closure tree, we flatten it into arrays per
+ * closure type, for evaluation, sampling, etc later on. */
+
+ switch (closure->id) {
+ case OSL::ClosureColor::MUL: {
+ OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
+ flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
+ break;
+ }
+ case OSL::ClosureColor::ADD: {
+ OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
+ flatten_volume_closure_tree(sd, add->closureA, weight);
+ flatten_volume_closure_tree(sd, add->closureB, weight);
+ break;
+ }
+ default: {
+ OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
+ CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
+
+ if (prim) {
+#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
+ weight = weight * TO_FLOAT3(comp->w);
+#endif
+ prim->setup(sd, 0, weight);
+ }
+ }
+ }
+}
+
+void OSLShader::eval_volume(const KernelGlobalsCPU *kg,
+ const void *state,
+ ShaderData *sd,
+ uint32_t path_flag)
+{
+ /* setup shader globals from shader data */
+ OSLThreadData *tdata = kg->osl_tdata;
+ shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
+
+ /* execute shader */
+ OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
+ OSL::ShaderGlobals *globals = &tdata->globals;
+ OSL::ShadingContext *octx = tdata->context;
+ int shader = sd->shader & SHADER_MASK;
+
+ if (kg->osl->volume_state[shader]) {
+ ss->execute(octx, *(kg->osl->volume_state[shader]), *globals);
+ }
+
+ /* flatten closure tree */
+ if (globals->Ci)
+ flatten_volume_closure_tree(sd, globals->Ci);
+}
+
+/* Displacement */
+
+void OSLShader::eval_displacement(const KernelGlobalsCPU *kg, const void *state, ShaderData *sd)
+{
+ /* setup shader globals from shader data */
+ OSLThreadData *tdata = kg->osl_tdata;
+
+ shaderdata_to_shaderglobals(kg, sd, state, 0, tdata);
+
+ /* execute shader */
+ OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
+ OSL::ShaderGlobals *globals = &tdata->globals;
+ OSL::ShadingContext *octx = tdata->context;
+ int shader = sd->shader & SHADER_MASK;
+
+ if (kg->osl->displacement_state[shader]) {
+ ss->execute(octx, *(kg->osl->displacement_state[shader]), *globals);
+ }
+
+ /* get back position */
+ sd->P = TO_FLOAT3(globals->P);
+}
+
+/* Attributes */
+
+int OSLShader::find_attribute(const KernelGlobalsCPU *kg,
+ const ShaderData *sd,
+ uint id,
+ AttributeDescriptor *desc)
+{
+ /* for OSL, a hash map is used to lookup the attribute by name. */
+ int object = sd->object * ATTR_PRIM_TYPES;
+
+ OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object];
+ ustring stdname(std::string("geom:") +
+ std::string(Attribute::standard_name((AttributeStandard)id)));
+ OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
+
+ if (it != attr_map.end()) {
+ const OSLGlobals::Attribute &osl_attr = it->second;
+ *desc = osl_attr.desc;
+
+ if (sd->prim == PRIM_NONE && (AttributeElement)osl_attr.desc.element != ATTR_ELEMENT_MESH) {
+ desc->offset = ATTR_STD_NOT_FOUND;
+ return ATTR_STD_NOT_FOUND;
+ }
+
+ /* return result */
+ if (osl_attr.desc.element == ATTR_ELEMENT_NONE) {
+ desc->offset = ATTR_STD_NOT_FOUND;
+ }
+ return desc->offset;
+ }
+ else {
+ desc->offset = ATTR_STD_NOT_FOUND;
+ return (int)ATTR_STD_NOT_FOUND;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/shader.h b/intern/cycles/kernel/osl/shader.h
new file mode 100644
index 00000000000..7d68d4eae7f
--- /dev/null
+++ b/intern/cycles/kernel/osl/shader.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __OSL_SHADER_H__
+#define __OSL_SHADER_H__
+
+#ifdef WITH_OSL
+
+/* OSL Shader Engine
+ *
+ * Holds all variables to execute and use OSL shaders from the kernel. These
+ * are initialized externally by OSLShaderManager before rendering starts.
+ *
+ * Before/after a thread starts rendering, thread_init/thread_free must be
+ * called, which will store any per thread OSL state in thread local storage.
+ * This means no thread state must be passed along in the kernel itself.
+ */
+
+# include "kernel/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Scene;
+
+struct ShaderClosure;
+struct ShaderData;
+struct IntegratorStateCPU;
+struct differential3;
+struct KernelGlobalsCPU;
+
+struct OSLGlobals;
+struct OSLShadingSystem;
+
+class OSLShader {
+ public:
+ /* init */
+ static void register_closures(OSLShadingSystem *ss);
+
+ /* per thread data */
+ static void thread_init(KernelGlobalsCPU *kg, OSLGlobals *osl_globals);
+ static void thread_free(KernelGlobalsCPU *kg);
+
+ /* eval */
+ static void eval_surface(const KernelGlobalsCPU *kg,
+ const void *state,
+ ShaderData *sd,
+ uint32_t path_flag);
+ static void eval_background(const KernelGlobalsCPU *kg,
+ const void *state,
+ ShaderData *sd,
+ uint32_t path_flag);
+ static void eval_volume(const KernelGlobalsCPU *kg,
+ const void *state,
+ ShaderData *sd,
+ uint32_t path_flag);
+ static void eval_displacement(const KernelGlobalsCPU *kg, const void *state, ShaderData *sd);
+
+ /* attributes */
+ static int find_attribute(const KernelGlobalsCPU *kg,
+ const ShaderData *sd,
+ uint id,
+ AttributeDescriptor *desc);
+};
+
+CCL_NAMESPACE_END
+
+#endif
+
+#endif /* __OSL_SHADER_H__ */
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
index 6b62e7bb52f..6b62e7bb52f 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
diff --git a/intern/cycles/kernel/shaders/node_absorption_volume.osl b/intern/cycles/kernel/osl/shaders/node_absorption_volume.osl
index 37ccc4c969f..37ccc4c969f 100644
--- a/intern/cycles/kernel/shaders/node_absorption_volume.osl
+++ b/intern/cycles/kernel/osl/shaders/node_absorption_volume.osl
diff --git a/intern/cycles/kernel/shaders/node_add_closure.osl b/intern/cycles/kernel/osl/shaders/node_add_closure.osl
index 27ecc9ef0c2..27ecc9ef0c2 100644
--- a/intern/cycles/kernel/shaders/node_add_closure.osl
+++ b/intern/cycles/kernel/osl/shaders/node_add_closure.osl
diff --git a/intern/cycles/kernel/shaders/node_ambient_occlusion.osl b/intern/cycles/kernel/osl/shaders/node_ambient_occlusion.osl
index 22d245d0698..22d245d0698 100644
--- a/intern/cycles/kernel/shaders/node_ambient_occlusion.osl
+++ b/intern/cycles/kernel/osl/shaders/node_ambient_occlusion.osl
diff --git a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_anisotropic_bsdf.osl
index 739cd375ab2..739cd375ab2 100644
--- a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_anisotropic_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_attribute.osl b/intern/cycles/kernel/osl/shaders/node_attribute.osl
index b7f35956ec7..b7f35956ec7 100644
--- a/intern/cycles/kernel/shaders/node_attribute.osl
+++ b/intern/cycles/kernel/osl/shaders/node_attribute.osl
diff --git a/intern/cycles/kernel/shaders/node_background.osl b/intern/cycles/kernel/osl/shaders/node_background.osl
index 3f45db751b3..3f45db751b3 100644
--- a/intern/cycles/kernel/shaders/node_background.osl
+++ b/intern/cycles/kernel/osl/shaders/node_background.osl
diff --git a/intern/cycles/kernel/shaders/node_bevel.osl b/intern/cycles/kernel/osl/shaders/node_bevel.osl
index e87ddab716d..e87ddab716d 100644
--- a/intern/cycles/kernel/shaders/node_bevel.osl
+++ b/intern/cycles/kernel/osl/shaders/node_bevel.osl
diff --git a/intern/cycles/kernel/shaders/node_blackbody.osl b/intern/cycles/kernel/osl/shaders/node_blackbody.osl
index 741efae755d..741efae755d 100644
--- a/intern/cycles/kernel/shaders/node_blackbody.osl
+++ b/intern/cycles/kernel/osl/shaders/node_blackbody.osl
diff --git a/intern/cycles/kernel/shaders/node_brick_texture.osl b/intern/cycles/kernel/osl/shaders/node_brick_texture.osl
index 075a324c730..075a324c730 100644
--- a/intern/cycles/kernel/shaders/node_brick_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_brick_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_brightness.osl b/intern/cycles/kernel/osl/shaders/node_brightness.osl
index 019edfb79a3..019edfb79a3 100644
--- a/intern/cycles/kernel/shaders/node_brightness.osl
+++ b/intern/cycles/kernel/osl/shaders/node_brightness.osl
diff --git a/intern/cycles/kernel/shaders/node_bump.osl b/intern/cycles/kernel/osl/shaders/node_bump.osl
index 811182f40b5..811182f40b5 100644
--- a/intern/cycles/kernel/shaders/node_bump.osl
+++ b/intern/cycles/kernel/osl/shaders/node_bump.osl
diff --git a/intern/cycles/kernel/shaders/node_camera.osl b/intern/cycles/kernel/osl/shaders/node_camera.osl
index 45ca50c6e1e..45ca50c6e1e 100644
--- a/intern/cycles/kernel/shaders/node_camera.osl
+++ b/intern/cycles/kernel/osl/shaders/node_camera.osl
diff --git a/intern/cycles/kernel/shaders/node_checker_texture.osl b/intern/cycles/kernel/osl/shaders/node_checker_texture.osl
index d6a30dbdb40..d6a30dbdb40 100644
--- a/intern/cycles/kernel/shaders/node_checker_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_checker_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_clamp.osl b/intern/cycles/kernel/osl/shaders/node_clamp.osl
index b600fb7c455..b600fb7c455 100644
--- a/intern/cycles/kernel/shaders/node_clamp.osl
+++ b/intern/cycles/kernel/osl/shaders/node_clamp.osl
diff --git a/intern/cycles/kernel/shaders/node_color.h b/intern/cycles/kernel/osl/shaders/node_color.h
index 276c91843e8..276c91843e8 100644
--- a/intern/cycles/kernel/shaders/node_color.h
+++ b/intern/cycles/kernel/osl/shaders/node_color.h
diff --git a/intern/cycles/kernel/shaders/node_combine_hsv.osl b/intern/cycles/kernel/osl/shaders/node_combine_hsv.osl
index 05e502b5bc1..05e502b5bc1 100644
--- a/intern/cycles/kernel/shaders/node_combine_hsv.osl
+++ b/intern/cycles/kernel/osl/shaders/node_combine_hsv.osl
diff --git a/intern/cycles/kernel/shaders/node_combine_rgb.osl b/intern/cycles/kernel/osl/shaders/node_combine_rgb.osl
index 036f371eb5c..036f371eb5c 100644
--- a/intern/cycles/kernel/shaders/node_combine_rgb.osl
+++ b/intern/cycles/kernel/osl/shaders/node_combine_rgb.osl
diff --git a/intern/cycles/kernel/shaders/node_combine_xyz.osl b/intern/cycles/kernel/osl/shaders/node_combine_xyz.osl
index 4ebd86b605c..4ebd86b605c 100644
--- a/intern/cycles/kernel/shaders/node_combine_xyz.osl
+++ b/intern/cycles/kernel/osl/shaders/node_combine_xyz.osl
diff --git a/intern/cycles/kernel/shaders/node_convert_from_color.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_color.osl
index c3f0e118844..c3f0e118844 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_color.osl
+++ b/intern/cycles/kernel/osl/shaders/node_convert_from_color.osl
diff --git a/intern/cycles/kernel/shaders/node_convert_from_float.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_float.osl
index 61a15a1c2b0..61a15a1c2b0 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_float.osl
+++ b/intern/cycles/kernel/osl/shaders/node_convert_from_float.osl
diff --git a/intern/cycles/kernel/shaders/node_convert_from_int.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_int.osl
index 2e6a99b2765..2e6a99b2765 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_int.osl
+++ b/intern/cycles/kernel/osl/shaders/node_convert_from_int.osl
diff --git a/intern/cycles/kernel/shaders/node_convert_from_normal.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_normal.osl
index 64201d63190..64201d63190 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_normal.osl
+++ b/intern/cycles/kernel/osl/shaders/node_convert_from_normal.osl
diff --git a/intern/cycles/kernel/shaders/node_convert_from_point.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_point.osl
index 11d64f76d6f..11d64f76d6f 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_point.osl
+++ b/intern/cycles/kernel/osl/shaders/node_convert_from_point.osl
diff --git a/intern/cycles/kernel/shaders/node_convert_from_string.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_string.osl
index b496c4e6d05..b496c4e6d05 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_string.osl
+++ b/intern/cycles/kernel/osl/shaders/node_convert_from_string.osl
diff --git a/intern/cycles/kernel/shaders/node_convert_from_vector.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_vector.osl
index 820faabd32b..820faabd32b 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_vector.osl
+++ b/intern/cycles/kernel/osl/shaders/node_convert_from_vector.osl
diff --git a/intern/cycles/kernel/shaders/node_diffuse_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_diffuse_bsdf.osl
index f5886f534eb..f5886f534eb 100644
--- a/intern/cycles/kernel/shaders/node_diffuse_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_diffuse_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_displacement.osl b/intern/cycles/kernel/osl/shaders/node_displacement.osl
index 44a4828d511..44a4828d511 100644
--- a/intern/cycles/kernel/shaders/node_displacement.osl
+++ b/intern/cycles/kernel/osl/shaders/node_displacement.osl
diff --git a/intern/cycles/kernel/shaders/node_emission.osl b/intern/cycles/kernel/osl/shaders/node_emission.osl
index f289a9711d9..f289a9711d9 100644
--- a/intern/cycles/kernel/shaders/node_emission.osl
+++ b/intern/cycles/kernel/osl/shaders/node_emission.osl
diff --git a/intern/cycles/kernel/shaders/node_environment_texture.osl b/intern/cycles/kernel/osl/shaders/node_environment_texture.osl
index d04743eb368..d04743eb368 100644
--- a/intern/cycles/kernel/shaders/node_environment_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_environment_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_float_curve.osl b/intern/cycles/kernel/osl/shaders/node_float_curve.osl
index f1f05fd88a9..f1f05fd88a9 100644
--- a/intern/cycles/kernel/shaders/node_float_curve.osl
+++ b/intern/cycles/kernel/osl/shaders/node_float_curve.osl
diff --git a/intern/cycles/kernel/shaders/node_fresnel.h b/intern/cycles/kernel/osl/shaders/node_fresnel.h
index ade1d4c6207..ade1d4c6207 100644
--- a/intern/cycles/kernel/shaders/node_fresnel.h
+++ b/intern/cycles/kernel/osl/shaders/node_fresnel.h
diff --git a/intern/cycles/kernel/shaders/node_fresnel.osl b/intern/cycles/kernel/osl/shaders/node_fresnel.osl
index cff084c344d..cff084c344d 100644
--- a/intern/cycles/kernel/shaders/node_fresnel.osl
+++ b/intern/cycles/kernel/osl/shaders/node_fresnel.osl
diff --git a/intern/cycles/kernel/shaders/node_gamma.osl b/intern/cycles/kernel/osl/shaders/node_gamma.osl
index 0816df64fe8..0816df64fe8 100644
--- a/intern/cycles/kernel/shaders/node_gamma.osl
+++ b/intern/cycles/kernel/osl/shaders/node_gamma.osl
diff --git a/intern/cycles/kernel/shaders/node_geometry.osl b/intern/cycles/kernel/osl/shaders/node_geometry.osl
index 55cda71db1b..55cda71db1b 100644
--- a/intern/cycles/kernel/shaders/node_geometry.osl
+++ b/intern/cycles/kernel/osl/shaders/node_geometry.osl
diff --git a/intern/cycles/kernel/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_glass_bsdf.osl
index 0042d573f8d..0042d573f8d 100644
--- a/intern/cycles/kernel/shaders/node_glass_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_glass_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl
index c73604d3650..c73604d3650 100644
--- a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_gradient_texture.osl b/intern/cycles/kernel/osl/shaders/node_gradient_texture.osl
index c7faee0d022..c7faee0d022 100644
--- a/intern/cycles/kernel/shaders/node_gradient_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_gradient_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_hair_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_hair_bsdf.osl
index 3e0ac7af2e0..3e0ac7af2e0 100644
--- a/intern/cycles/kernel/shaders/node_hair_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_hair_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_hair_info.osl b/intern/cycles/kernel/osl/shaders/node_hair_info.osl
index ddc2e28b83a..ddc2e28b83a 100644
--- a/intern/cycles/kernel/shaders/node_hair_info.osl
+++ b/intern/cycles/kernel/osl/shaders/node_hair_info.osl
diff --git a/intern/cycles/kernel/shaders/node_hash.h b/intern/cycles/kernel/osl/shaders/node_hash.h
index b42e42ff910..b42e42ff910 100644
--- a/intern/cycles/kernel/shaders/node_hash.h
+++ b/intern/cycles/kernel/osl/shaders/node_hash.h
diff --git a/intern/cycles/kernel/shaders/node_holdout.osl b/intern/cycles/kernel/osl/shaders/node_holdout.osl
index 92e41c92f72..92e41c92f72 100644
--- a/intern/cycles/kernel/shaders/node_holdout.osl
+++ b/intern/cycles/kernel/osl/shaders/node_holdout.osl
diff --git a/intern/cycles/kernel/shaders/node_hsv.osl b/intern/cycles/kernel/osl/shaders/node_hsv.osl
index 4417057b10f..4417057b10f 100644
--- a/intern/cycles/kernel/shaders/node_hsv.osl
+++ b/intern/cycles/kernel/osl/shaders/node_hsv.osl
diff --git a/intern/cycles/kernel/shaders/node_ies_light.osl b/intern/cycles/kernel/osl/shaders/node_ies_light.osl
index 76348b4d758..76348b4d758 100644
--- a/intern/cycles/kernel/shaders/node_ies_light.osl
+++ b/intern/cycles/kernel/osl/shaders/node_ies_light.osl
diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/osl/shaders/node_image_texture.osl
index 56fcc47a011..56fcc47a011 100644
--- a/intern/cycles/kernel/shaders/node_image_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_image_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_invert.osl b/intern/cycles/kernel/osl/shaders/node_invert.osl
index 23c16935ca1..23c16935ca1 100644
--- a/intern/cycles/kernel/shaders/node_invert.osl
+++ b/intern/cycles/kernel/osl/shaders/node_invert.osl
diff --git a/intern/cycles/kernel/shaders/node_layer_weight.osl b/intern/cycles/kernel/osl/shaders/node_layer_weight.osl
index 1662be2cad1..1662be2cad1 100644
--- a/intern/cycles/kernel/shaders/node_layer_weight.osl
+++ b/intern/cycles/kernel/osl/shaders/node_layer_weight.osl
diff --git a/intern/cycles/kernel/shaders/node_light_falloff.osl b/intern/cycles/kernel/osl/shaders/node_light_falloff.osl
index 3f3c9444a5a..3f3c9444a5a 100644
--- a/intern/cycles/kernel/shaders/node_light_falloff.osl
+++ b/intern/cycles/kernel/osl/shaders/node_light_falloff.osl
diff --git a/intern/cycles/kernel/shaders/node_light_path.osl b/intern/cycles/kernel/osl/shaders/node_light_path.osl
index ba268db288c..ba268db288c 100644
--- a/intern/cycles/kernel/shaders/node_light_path.osl
+++ b/intern/cycles/kernel/osl/shaders/node_light_path.osl
diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/osl/shaders/node_magic_texture.osl
index 476c6895f05..476c6895f05 100644
--- a/intern/cycles/kernel/shaders/node_magic_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_magic_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_map_range.osl b/intern/cycles/kernel/osl/shaders/node_map_range.osl
index 2fcc664a80e..2fcc664a80e 100644
--- a/intern/cycles/kernel/shaders/node_map_range.osl
+++ b/intern/cycles/kernel/osl/shaders/node_map_range.osl
diff --git a/intern/cycles/kernel/shaders/node_mapping.osl b/intern/cycles/kernel/osl/shaders/node_mapping.osl
index 131640685bc..131640685bc 100644
--- a/intern/cycles/kernel/shaders/node_mapping.osl
+++ b/intern/cycles/kernel/osl/shaders/node_mapping.osl
diff --git a/intern/cycles/kernel/shaders/node_math.h b/intern/cycles/kernel/osl/shaders/node_math.h
index 2da73b94212..2da73b94212 100644
--- a/intern/cycles/kernel/shaders/node_math.h
+++ b/intern/cycles/kernel/osl/shaders/node_math.h
diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/osl/shaders/node_math.osl
index 66884610561..66884610561 100644
--- a/intern/cycles/kernel/shaders/node_math.osl
+++ b/intern/cycles/kernel/osl/shaders/node_math.osl
diff --git a/intern/cycles/kernel/shaders/node_mix.osl b/intern/cycles/kernel/osl/shaders/node_mix.osl
index dcd9f014f3e..dcd9f014f3e 100644
--- a/intern/cycles/kernel/shaders/node_mix.osl
+++ b/intern/cycles/kernel/osl/shaders/node_mix.osl
diff --git a/intern/cycles/kernel/shaders/node_mix_closure.osl b/intern/cycles/kernel/osl/shaders/node_mix_closure.osl
index 94fc2171c44..94fc2171c44 100644
--- a/intern/cycles/kernel/shaders/node_mix_closure.osl
+++ b/intern/cycles/kernel/osl/shaders/node_mix_closure.osl
diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl
index 0e71ce74c29..0e71ce74c29 100644
--- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_noise.h b/intern/cycles/kernel/osl/shaders/node_noise.h
index ab4cd7792cc..ab4cd7792cc 100644
--- a/intern/cycles/kernel/shaders/node_noise.h
+++ b/intern/cycles/kernel/osl/shaders/node_noise.h
diff --git a/intern/cycles/kernel/shaders/node_noise_texture.osl b/intern/cycles/kernel/osl/shaders/node_noise_texture.osl
index 01196ab633a..01196ab633a 100644
--- a/intern/cycles/kernel/shaders/node_noise_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_noise_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_normal.osl b/intern/cycles/kernel/osl/shaders/node_normal.osl
index a0a88445427..a0a88445427 100644
--- a/intern/cycles/kernel/shaders/node_normal.osl
+++ b/intern/cycles/kernel/osl/shaders/node_normal.osl
diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/osl/shaders/node_normal_map.osl
index 7a94ad8ad1a..7a94ad8ad1a 100644
--- a/intern/cycles/kernel/shaders/node_normal_map.osl
+++ b/intern/cycles/kernel/osl/shaders/node_normal_map.osl
diff --git a/intern/cycles/kernel/shaders/node_object_info.osl b/intern/cycles/kernel/osl/shaders/node_object_info.osl
index 44513d9a1ba..44513d9a1ba 100644
--- a/intern/cycles/kernel/shaders/node_object_info.osl
+++ b/intern/cycles/kernel/osl/shaders/node_object_info.osl
diff --git a/intern/cycles/kernel/shaders/node_output_displacement.osl b/intern/cycles/kernel/osl/shaders/node_output_displacement.osl
index bd60fc2b7e1..bd60fc2b7e1 100644
--- a/intern/cycles/kernel/shaders/node_output_displacement.osl
+++ b/intern/cycles/kernel/osl/shaders/node_output_displacement.osl
diff --git a/intern/cycles/kernel/shaders/node_output_surface.osl b/intern/cycles/kernel/osl/shaders/node_output_surface.osl
index cd746f79c4a..cd746f79c4a 100644
--- a/intern/cycles/kernel/shaders/node_output_surface.osl
+++ b/intern/cycles/kernel/osl/shaders/node_output_surface.osl
diff --git a/intern/cycles/kernel/shaders/node_output_volume.osl b/intern/cycles/kernel/osl/shaders/node_output_volume.osl
index 4cc14cd6699..4cc14cd6699 100644
--- a/intern/cycles/kernel/shaders/node_output_volume.osl
+++ b/intern/cycles/kernel/osl/shaders/node_output_volume.osl
diff --git a/intern/cycles/kernel/shaders/node_particle_info.osl b/intern/cycles/kernel/osl/shaders/node_particle_info.osl
index 2dcdf3d0f3c..2dcdf3d0f3c 100644
--- a/intern/cycles/kernel/shaders/node_particle_info.osl
+++ b/intern/cycles/kernel/osl/shaders/node_particle_info.osl
diff --git a/intern/cycles/kernel/shaders/node_principled_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl
index 55afb892d36..55afb892d36 100644
--- a/intern/cycles/kernel/shaders/node_principled_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_principled_hair_bsdf.osl
index 4cf17e0e703..4cf17e0e703 100644
--- a/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_principled_hair_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_principled_volume.osl b/intern/cycles/kernel/osl/shaders/node_principled_volume.osl
index 0cb4cdebdaa..0cb4cdebdaa 100644
--- a/intern/cycles/kernel/shaders/node_principled_volume.osl
+++ b/intern/cycles/kernel/osl/shaders/node_principled_volume.osl
diff --git a/intern/cycles/kernel/shaders/node_ramp_util.h b/intern/cycles/kernel/osl/shaders/node_ramp_util.h
index f7fb07b257d..f7fb07b257d 100644
--- a/intern/cycles/kernel/shaders/node_ramp_util.h
+++ b/intern/cycles/kernel/osl/shaders/node_ramp_util.h
diff --git a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_refraction_bsdf.osl
index 9e9b31d9a87..9e9b31d9a87 100644
--- a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_refraction_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_rgb_curves.osl b/intern/cycles/kernel/osl/shaders/node_rgb_curves.osl
index 8850040d580..8850040d580 100644
--- a/intern/cycles/kernel/shaders/node_rgb_curves.osl
+++ b/intern/cycles/kernel/osl/shaders/node_rgb_curves.osl
diff --git a/intern/cycles/kernel/shaders/node_rgb_ramp.osl b/intern/cycles/kernel/osl/shaders/node_rgb_ramp.osl
index 2131edb2688..2131edb2688 100644
--- a/intern/cycles/kernel/shaders/node_rgb_ramp.osl
+++ b/intern/cycles/kernel/osl/shaders/node_rgb_ramp.osl
diff --git a/intern/cycles/kernel/shaders/node_rgb_to_bw.osl b/intern/cycles/kernel/osl/shaders/node_rgb_to_bw.osl
index f0a094d5b57..f0a094d5b57 100644
--- a/intern/cycles/kernel/shaders/node_rgb_to_bw.osl
+++ b/intern/cycles/kernel/osl/shaders/node_rgb_to_bw.osl
diff --git a/intern/cycles/kernel/shaders/node_scatter_volume.osl b/intern/cycles/kernel/osl/shaders/node_scatter_volume.osl
index 36ad952dee6..36ad952dee6 100644
--- a/intern/cycles/kernel/shaders/node_scatter_volume.osl
+++ b/intern/cycles/kernel/osl/shaders/node_scatter_volume.osl
diff --git a/intern/cycles/kernel/shaders/node_separate_hsv.osl b/intern/cycles/kernel/osl/shaders/node_separate_hsv.osl
index 2f902b72dbc..2f902b72dbc 100644
--- a/intern/cycles/kernel/shaders/node_separate_hsv.osl
+++ b/intern/cycles/kernel/osl/shaders/node_separate_hsv.osl
diff --git a/intern/cycles/kernel/shaders/node_separate_rgb.osl b/intern/cycles/kernel/osl/shaders/node_separate_rgb.osl
index 62e4aedb879..62e4aedb879 100644
--- a/intern/cycles/kernel/shaders/node_separate_rgb.osl
+++ b/intern/cycles/kernel/osl/shaders/node_separate_rgb.osl
diff --git a/intern/cycles/kernel/shaders/node_separate_xyz.osl b/intern/cycles/kernel/osl/shaders/node_separate_xyz.osl
index acaf3942b6f..acaf3942b6f 100644
--- a/intern/cycles/kernel/shaders/node_separate_xyz.osl
+++ b/intern/cycles/kernel/osl/shaders/node_separate_xyz.osl
diff --git a/intern/cycles/kernel/shaders/node_set_normal.osl b/intern/cycles/kernel/osl/shaders/node_set_normal.osl
index 26a97e2b5d1..26a97e2b5d1 100644
--- a/intern/cycles/kernel/shaders/node_set_normal.osl
+++ b/intern/cycles/kernel/osl/shaders/node_set_normal.osl
diff --git a/intern/cycles/kernel/shaders/node_sky_texture.osl b/intern/cycles/kernel/osl/shaders/node_sky_texture.osl
index 43d7bd36973..43d7bd36973 100644
--- a/intern/cycles/kernel/shaders/node_sky_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_sky_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl b/intern/cycles/kernel/osl/shaders/node_subsurface_scattering.osl
index f55e38c54ff..f55e38c54ff 100644
--- a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl
+++ b/intern/cycles/kernel/osl/shaders/node_subsurface_scattering.osl
diff --git a/intern/cycles/kernel/shaders/node_tangent.osl b/intern/cycles/kernel/osl/shaders/node_tangent.osl
index f086fa079ec..f086fa079ec 100644
--- a/intern/cycles/kernel/shaders/node_tangent.osl
+++ b/intern/cycles/kernel/osl/shaders/node_tangent.osl
diff --git a/intern/cycles/kernel/shaders/node_texture_coordinate.osl b/intern/cycles/kernel/osl/shaders/node_texture_coordinate.osl
index 9cdb925dbfa..9cdb925dbfa 100644
--- a/intern/cycles/kernel/shaders/node_texture_coordinate.osl
+++ b/intern/cycles/kernel/osl/shaders/node_texture_coordinate.osl
diff --git a/intern/cycles/kernel/shaders/node_toon_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_toon_bsdf.osl
index 4a44730c70c..4a44730c70c 100644
--- a/intern/cycles/kernel/shaders/node_toon_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_toon_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_translucent_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_translucent_bsdf.osl
index 23a562bf34d..23a562bf34d 100644
--- a/intern/cycles/kernel/shaders/node_translucent_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_translucent_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_transparent_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_transparent_bsdf.osl
index eb737a05c41..eb737a05c41 100644
--- a/intern/cycles/kernel/shaders/node_transparent_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_transparent_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_uv_map.osl b/intern/cycles/kernel/osl/shaders/node_uv_map.osl
index 88d8c5ba394..88d8c5ba394 100644
--- a/intern/cycles/kernel/shaders/node_uv_map.osl
+++ b/intern/cycles/kernel/osl/shaders/node_uv_map.osl
diff --git a/intern/cycles/kernel/shaders/node_value.osl b/intern/cycles/kernel/osl/shaders/node_value.osl
index 13197b9a27a..13197b9a27a 100644
--- a/intern/cycles/kernel/shaders/node_value.osl
+++ b/intern/cycles/kernel/osl/shaders/node_value.osl
diff --git a/intern/cycles/kernel/shaders/node_vector_curves.osl b/intern/cycles/kernel/osl/shaders/node_vector_curves.osl
index 9d3a2b82b0a..9d3a2b82b0a 100644
--- a/intern/cycles/kernel/shaders/node_vector_curves.osl
+++ b/intern/cycles/kernel/osl/shaders/node_vector_curves.osl
diff --git a/intern/cycles/kernel/shaders/node_vector_displacement.osl b/intern/cycles/kernel/osl/shaders/node_vector_displacement.osl
index 7cd9c2a37f2..7cd9c2a37f2 100644
--- a/intern/cycles/kernel/shaders/node_vector_displacement.osl
+++ b/intern/cycles/kernel/osl/shaders/node_vector_displacement.osl
diff --git a/intern/cycles/kernel/shaders/node_vector_math.osl b/intern/cycles/kernel/osl/shaders/node_vector_math.osl
index c08d75b99ef..c08d75b99ef 100644
--- a/intern/cycles/kernel/shaders/node_vector_math.osl
+++ b/intern/cycles/kernel/osl/shaders/node_vector_math.osl
diff --git a/intern/cycles/kernel/shaders/node_vector_rotate.osl b/intern/cycles/kernel/osl/shaders/node_vector_rotate.osl
index e99bf7d81b0..e99bf7d81b0 100644
--- a/intern/cycles/kernel/shaders/node_vector_rotate.osl
+++ b/intern/cycles/kernel/osl/shaders/node_vector_rotate.osl
diff --git a/intern/cycles/kernel/shaders/node_vector_transform.osl b/intern/cycles/kernel/osl/shaders/node_vector_transform.osl
index b71c6ec4824..b71c6ec4824 100644
--- a/intern/cycles/kernel/shaders/node_vector_transform.osl
+++ b/intern/cycles/kernel/osl/shaders/node_vector_transform.osl
diff --git a/intern/cycles/kernel/shaders/node_velvet_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_velvet_bsdf.osl
index 299acef35ee..299acef35ee 100644
--- a/intern/cycles/kernel/shaders/node_velvet_bsdf.osl
+++ b/intern/cycles/kernel/osl/shaders/node_velvet_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_vertex_color.osl b/intern/cycles/kernel/osl/shaders/node_vertex_color.osl
index ffaf7a2f720..ffaf7a2f720 100644
--- a/intern/cycles/kernel/shaders/node_vertex_color.osl
+++ b/intern/cycles/kernel/osl/shaders/node_vertex_color.osl
diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl
index de6c697fc85..de6c697fc85 100644
--- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_voxel_texture.osl b/intern/cycles/kernel/osl/shaders/node_voxel_texture.osl
index 14489298367..14489298367 100644
--- a/intern/cycles/kernel/shaders/node_voxel_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_voxel_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/osl/shaders/node_wave_texture.osl
index 71d81dff7ec..71d81dff7ec 100644
--- a/intern/cycles/kernel/shaders/node_wave_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_wave_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_wavelength.osl b/intern/cycles/kernel/osl/shaders/node_wavelength.osl
index f484c4b4788..f484c4b4788 100644
--- a/intern/cycles/kernel/shaders/node_wavelength.osl
+++ b/intern/cycles/kernel/osl/shaders/node_wavelength.osl
diff --git a/intern/cycles/kernel/shaders/node_white_noise_texture.osl b/intern/cycles/kernel/osl/shaders/node_white_noise_texture.osl
index 94735a019d5..94735a019d5 100644
--- a/intern/cycles/kernel/shaders/node_white_noise_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_white_noise_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_wireframe.osl b/intern/cycles/kernel/osl/shaders/node_wireframe.osl
index 673a451c928..673a451c928 100644
--- a/intern/cycles/kernel/shaders/node_wireframe.osl
+++ b/intern/cycles/kernel/osl/shaders/node_wireframe.osl
diff --git a/intern/cycles/kernel/shaders/stdcycles.h b/intern/cycles/kernel/osl/shaders/stdcycles.h
index dd604da68ce..dd604da68ce 100644
--- a/intern/cycles/kernel/shaders/stdcycles.h
+++ b/intern/cycles/kernel/osl/shaders/stdcycles.h
diff --git a/intern/cycles/kernel/sample/jitter.h b/intern/cycles/kernel/sample/jitter.h
new file mode 100644
index 00000000000..b76b9b8f23e
--- /dev/null
+++ b/intern/cycles/kernel/sample/jitter.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline uint32_t laine_karras_permutation(uint32_t x, uint32_t seed)
+{
+ x += seed;
+ x ^= (x * 0x6c50b47cu);
+ x ^= x * 0xb82f1e52u;
+ x ^= x * 0xc7afe638u;
+ x ^= x * 0x8d22f6e6u;
+
+ return x;
+}
+
+ccl_device_inline uint32_t nested_uniform_scramble(uint32_t x, uint32_t seed)
+{
+ x = reverse_integer_bits(x);
+ x = laine_karras_permutation(x, seed);
+ x = reverse_integer_bits(x);
+
+ return x;
+}
+
+ccl_device_inline uint cmj_hash(uint i, uint p)
+{
+ i ^= p;
+ i ^= i >> 17;
+ i ^= i >> 10;
+ i *= 0xb36534e5;
+ i ^= i >> 12;
+ i ^= i >> 21;
+ i *= 0x93fc4795;
+ i ^= 0xdf6e307f;
+ i ^= i >> 17;
+ i *= 1 | p >> 18;
+
+ return i;
+}
+
+ccl_device_inline uint cmj_hash_simple(uint i, uint p)
+{
+ i = (i ^ 61) ^ p;
+ i += i << 3;
+ i ^= i >> 4;
+ i *= 0x27d4eb2d;
+ return i;
+}
+
+ccl_device_inline float cmj_randfloat(uint i, uint p)
+{
+ return cmj_hash(i, p) * (1.0f / 4294967808.0f);
+}
+
+ccl_device_inline float cmj_randfloat_simple(uint i, uint p)
+{
+ return cmj_hash_simple(i, p) * (1.0f / (float)0xFFFFFFFF);
+}
+
+ccl_device_inline float cmj_randfloat_simple_dist(uint i, uint p, float d)
+{
+ return cmj_hash_simple(i, p) * (d / (float)0xFFFFFFFF);
+}
+
+ccl_device float pmj_sample_1D(KernelGlobals kg, uint sample, uint rng_hash, uint dimension)
+{
+ uint hash = rng_hash;
+ float jitter_x = 0.0f;
+ if (kernel_data.integrator.scrambling_distance < 1.0f) {
+ hash = kernel_data.integrator.seed;
+
+ jitter_x = cmj_randfloat_simple_dist(
+ dimension, rng_hash, kernel_data.integrator.scrambling_distance);
+ }
+
+ /* Perform Owen shuffle of the sample number to reorder the samples. */
+#ifdef _SIMPLE_HASH_
+ const uint rv = cmj_hash_simple(dimension, hash);
+#else /* Use a _REGULAR_HASH_. */
+ const uint rv = cmj_hash(dimension, hash);
+#endif
+#ifdef _XOR_SHUFFLE_
+# warning "Using XOR shuffle."
+ const uint s = sample ^ rv;
+#else /* Use _OWEN_SHUFFLE_ for reordering. */
+ const uint s = nested_uniform_scramble(sample, rv);
+#endif
+
+ /* Based on the sample number a sample pattern is selected and offset by the dimension. */
+ const uint sample_set = s / NUM_PMJ_SAMPLES;
+ const uint d = (dimension + sample_set);
+ const uint dim = d % NUM_PMJ_PATTERNS;
+
+ /* The PMJ sample sets contain a sample with (x,y) with NUM_PMJ_SAMPLES so for 1D
+ * the x part is used for even dims and the y for odd. */
+ int index = 2 * ((dim >> 1) * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES)) + (dim & 1);
+
+ float fx = kernel_tex_fetch(__sample_pattern_lut, index);
+
+#ifndef _NO_CRANLEY_PATTERSON_ROTATION_
+ /* Use Cranley-Patterson rotation to displace the sample pattern. */
+# ifdef _SIMPLE_HASH_
+ float dx = cmj_randfloat_simple(d, hash);
+# else
+ float dx = cmj_randfloat(d, hash);
+# endif
+ /* Jitter sample locations and map back into [0 1]. */
+ fx = fx + dx + jitter_x;
+ fx = fx - floorf(fx);
+#else
+# warning "Not using Cranley-Patterson Rotation."
+#endif
+
+ return fx;
+}
+
+ccl_device void pmj_sample_2D(KernelGlobals kg,
+ uint sample,
+ uint rng_hash,
+ uint dimension,
+ ccl_private float *x,
+ ccl_private float *y)
+{
+ uint hash = rng_hash;
+ float jitter_x = 0.0f;
+ float jitter_y = 0.0f;
+ if (kernel_data.integrator.scrambling_distance < 1.0f) {
+ hash = kernel_data.integrator.seed;
+
+ jitter_x = cmj_randfloat_simple_dist(
+ dimension, rng_hash, kernel_data.integrator.scrambling_distance);
+ jitter_y = cmj_randfloat_simple_dist(
+ dimension + 1, rng_hash, kernel_data.integrator.scrambling_distance);
+ }
+
+ /* Perform a shuffle on the sample number to reorder the samples. */
+#ifdef _SIMPLE_HASH_
+ const uint rv = cmj_hash_simple(dimension, hash);
+#else /* Use a _REGULAR_HASH_. */
+ const uint rv = cmj_hash(dimension, hash);
+#endif
+#ifdef _XOR_SHUFFLE_
+# warning "Using XOR shuffle."
+ const uint s = sample ^ rv;
+#else /* Use _OWEN_SHUFFLE_ for reordering. */
+ const uint s = nested_uniform_scramble(sample, rv);
+#endif
+
+ /* Based on the sample number a sample pattern is selected and offset by the dimension. */
+ const uint sample_set = s / NUM_PMJ_SAMPLES;
+ const uint d = dimension + sample_set;
+ uint dim = d % NUM_PMJ_PATTERNS;
+ int index = 2 * (dim * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES));
+
+ float fx = kernel_tex_fetch(__sample_pattern_lut, index);
+ float fy = kernel_tex_fetch(__sample_pattern_lut, index + 1);
+
+#ifndef _NO_CRANLEY_PATTERSON_ROTATION_
+ /* Use Cranley-Patterson rotation to displace the sample pattern. */
+# ifdef _SIMPLE_HASH_
+ float dx = cmj_randfloat_simple(d, hash);
+ float dy = cmj_randfloat_simple(d + 1, hash);
+# else
+ float dx = cmj_randfloat(d, hash);
+ float dy = cmj_randfloat(d + 1, hash);
+# endif
+ /* Jitter sample locations and map back to the unit square [0 1]x[0 1]. */
+ float sx = fx + dx + jitter_x;
+ float sy = fy + dy + jitter_y;
+ sx = sx - floorf(sx);
+ sy = sy - floorf(sy);
+#else
+# warning "Not using Cranley Patterson Rotation."
+#endif
+
+ (*x) = sx;
+ (*y) = sy;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/sample/lcg.h b/intern/cycles/kernel/sample/lcg.h
new file mode 100644
index 00000000000..92cfff639b4
--- /dev/null
+++ b/intern/cycles/kernel/sample/lcg.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Linear Congruential Generator */
+
+ccl_device uint lcg_step_uint(uint *rng)
+{
+ /* implicit mod 2^32 */
+ *rng = (1103515245 * (*rng) + 12345);
+ return *rng;
+}
+
+ccl_device float lcg_step_float(uint *rng)
+{
+ /* implicit mod 2^32 */
+ *rng = (1103515245 * (*rng) + 12345);
+ return (float)*rng * (1.0f / (float)0xFFFFFFFF);
+}
+
+ccl_device uint lcg_init(uint seed)
+{
+ uint rng = seed;
+ lcg_step_uint(&rng);
+ return rng;
+}
+
+ccl_device_inline uint lcg_state_init(const uint rng_hash,
+ const uint rng_offset,
+ const uint sample,
+ const uint scramble)
+{
+ return lcg_init(rng_hash + rng_offset + sample * scramble);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/sample/mapping.h b/intern/cycles/kernel/sample/mapping.h
new file mode 100644
index 00000000000..3297aa2a29a
--- /dev/null
+++ b/intern/cycles/kernel/sample/mapping.h
@@ -0,0 +1,177 @@
+/*
+ * Parts adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* distribute uniform xy on [0,1] over unit disk [-1,1] */
+ccl_device void to_unit_disk(ccl_private float *x, ccl_private float *y)
+{
+ float phi = M_2PI_F * (*x);
+ float r = sqrtf(*y);
+
+ *x = r * cosf(phi);
+ *y = r * sinf(phi);
+}
+
+/* return an orthogonal tangent and bitangent given a normal and tangent that
+ * may not be exactly orthogonal */
+ccl_device void make_orthonormals_tangent(const float3 N,
+ const float3 T,
+ ccl_private float3 *a,
+ ccl_private float3 *b)
+{
+ *b = normalize(cross(N, T));
+ *a = cross(*b, N);
+}
+
+/* sample direction with cosine weighted distributed in hemisphere */
+ccl_device_inline void sample_cos_hemisphere(
+ const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf)
+{
+ to_unit_disk(&randu, &randv);
+ float costheta = sqrtf(max(1.0f - randu * randu - randv * randv, 0.0f));
+ float3 T, B;
+ make_orthonormals(N, &T, &B);
+ *omega_in = randu * T + randv * B + costheta * N;
+ *pdf = costheta * M_1_PI_F;
+}
+
+/* sample direction uniformly distributed in hemisphere */
+ccl_device_inline void sample_uniform_hemisphere(
+ const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf)
+{
+ float z = randu;
+ float r = sqrtf(max(0.0f, 1.0f - z * z));
+ float phi = M_2PI_F * randv;
+ float x = r * cosf(phi);
+ float y = r * sinf(phi);
+
+ float3 T, B;
+ make_orthonormals(N, &T, &B);
+ *omega_in = x * T + y * B + z * N;
+ *pdf = 0.5f * M_1_PI_F;
+}
+
+/* sample direction uniformly distributed in cone */
+ccl_device_inline void sample_uniform_cone(const float3 N,
+ float angle,
+ float randu,
+ float randv,
+ ccl_private float3 *omega_in,
+ ccl_private float *pdf)
+{
+ float zMin = cosf(angle);
+ float z = zMin - zMin * randu + randu;
+ float r = safe_sqrtf(1.0f - sqr(z));
+ float phi = M_2PI_F * randv;
+ float x = r * cosf(phi);
+ float y = r * sinf(phi);
+
+ float3 T, B;
+ make_orthonormals(N, &T, &B);
+ *omega_in = x * T + y * B + z * N;
+ *pdf = M_1_2PI_F / (1.0f - zMin);
+}
+
+ccl_device_inline float pdf_uniform_cone(const float3 N, float3 D, float angle)
+{
+ float zMin = cosf(angle);
+ float z = dot(N, D);
+ if (z > zMin) {
+ return M_1_2PI_F / (1.0f - zMin);
+ }
+ return 0.0f;
+}
+
+/* sample uniform point on the surface of a sphere */
+ccl_device float3 sample_uniform_sphere(float u1, float u2)
+{
+ float z = 1.0f - 2.0f * u1;
+ float r = sqrtf(fmaxf(0.0f, 1.0f - z * z));
+ float phi = M_2PI_F * u2;
+ float x = r * cosf(phi);
+ float y = r * sinf(phi);
+
+ return make_float3(x, y, z);
+}
+
+/* distribute uniform xy on [0,1] over unit disk [-1,1], with concentric mapping
+ * to better preserve stratification for some RNG sequences */
+ccl_device float2 concentric_sample_disk(float u1, float u2)
+{
+ float phi, r;
+ float a = 2.0f * u1 - 1.0f;
+ float b = 2.0f * u2 - 1.0f;
+
+ if (a == 0.0f && b == 0.0f) {
+ return zero_float2();
+ }
+ else if (a * a > b * b) {
+ r = a;
+ phi = M_PI_4_F * (b / a);
+ }
+ else {
+ r = b;
+ phi = M_PI_2_F - M_PI_4_F * (a / b);
+ }
+
+ return make_float2(r * cosf(phi), r * sinf(phi));
+}
+
+/* sample point in unit polygon with given number of corners and rotation */
+ccl_device float2 regular_polygon_sample(float corners, float rotation, float u, float v)
+{
+ /* sample corner number and reuse u */
+ float corner = floorf(u * corners);
+ u = u * corners - corner;
+
+ /* uniform sampled triangle weights */
+ u = sqrtf(u);
+ v = v * u;
+ u = 1.0f - u;
+
+ /* point in triangle */
+ float angle = M_PI_F / corners;
+ float2 p = make_float2((u + v) * cosf(angle), (u - v) * sinf(angle));
+
+ /* rotate */
+ rotation += corner * 2.0f * angle;
+
+ float cr = cosf(rotation);
+ float sr = sinf(rotation);
+
+ return make_float2(cr * p.x - sr * p.y, sr * p.x + cr * p.y);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/sample/mis.h b/intern/cycles/kernel/sample/mis.h
new file mode 100644
index 00000000000..0878b3aac36
--- /dev/null
+++ b/intern/cycles/kernel/sample/mis.h
@@ -0,0 +1,64 @@
+/*
+ * Parts adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Multiple importance sampling utilities. */
+
+ccl_device float balance_heuristic(float a, float b)
+{
+ return (a) / (a + b);
+}
+
+ccl_device float balance_heuristic_3(float a, float b, float c)
+{
+ return (a) / (a + b + c);
+}
+
+ccl_device float power_heuristic(float a, float b)
+{
+ return (a * a) / (a * a + b * b);
+}
+
+ccl_device float power_heuristic_3(float a, float b, float c)
+{
+ return (a * a) / (a * a + b * b + c * c);
+}
+
+ccl_device float max_heuristic(float a, float b)
+{
+ return (a > b) ? 1.0f : 0.0f;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/sample/pattern.h b/intern/cycles/kernel/sample/pattern.h
new file mode 100644
index 00000000000..0c27992c7f6
--- /dev/null
+++ b/intern/cycles/kernel/sample/pattern.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "kernel/sample/jitter.h"
+#include "util/hash.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Pseudo random numbers, uncomment this for debugging correlations. Only run
+ * this single threaded on a CPU for repeatable results. */
+//#define __DEBUG_CORRELATION__
+
+/* High Dimensional Sobol.
+ *
+ * Multidimensional sobol with generator matrices. Dimension 0 and 1 are equal
+ * to classic Van der Corput and Sobol sequences. */
+
+#ifdef __SOBOL__
+
+/* Skip initial numbers that for some dimensions have clear patterns that
+ * don't cover the entire sample space. Ideally we would have a better
+ * progressive pattern that doesn't suffer from this problem, because even
+ * with this offset some dimensions are quite poor.
+ */
+# define SOBOL_SKIP 64
+
+ccl_device uint sobol_dimension(KernelGlobals kg, int index, int dimension)
+{
+ uint result = 0;
+ uint i = index + SOBOL_SKIP;
+ for (int j = 0, x; (x = find_first_set(i)); i >>= x) {
+ j += x;
+ result ^= __float_as_uint(kernel_tex_fetch(__sample_pattern_lut, 32 * dimension + j - 1));
+ }
+ return result;
+}
+
+#endif /* __SOBOL__ */
+
+ccl_device_forceinline float path_rng_1D(KernelGlobals kg,
+ uint rng_hash,
+ int sample,
+ int dimension)
+{
+#ifdef __DEBUG_CORRELATION__
+ return (float)drand48();
+#endif
+
+#ifdef __SOBOL__
+ if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ)
+#endif
+ {
+ return pmj_sample_1D(kg, sample, rng_hash, dimension);
+ }
+
+#ifdef __SOBOL__
+ /* Sobol sequence value using direction vectors. */
+ uint result = sobol_dimension(kg, sample, dimension);
+ float r = (float)result * (1.0f / (float)0xFFFFFFFF);
+
+ /* Cranly-Patterson rotation using rng seed */
+ float shift;
+
+ /* Hash rng with dimension to solve correlation issues.
+ * See T38710, T50116.
+ */
+ uint tmp_rng = cmj_hash_simple(dimension, rng_hash);
+ shift = tmp_rng * (kernel_data.integrator.scrambling_distance / (float)0xFFFFFFFF);
+
+ return r + shift - floorf(r + shift);
+#endif
+}
+
+ccl_device_forceinline void path_rng_2D(KernelGlobals kg,
+ uint rng_hash,
+ int sample,
+ int dimension,
+ ccl_private float *fx,
+ ccl_private float *fy)
+{
+#ifdef __DEBUG_CORRELATION__
+ *fx = (float)drand48();
+ *fy = (float)drand48();
+ return;
+#endif
+
+#ifdef __SOBOL__
+ if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ)
+#endif
+ {
+ pmj_sample_2D(kg, sample, rng_hash, dimension, fx, fy);
+
+ return;
+ }
+
+#ifdef __SOBOL__
+ /* Sobol. */
+ *fx = path_rng_1D(kg, rng_hash, sample, dimension);
+ *fy = path_rng_1D(kg, rng_hash, sample, dimension + 1);
+#endif
+}
+
+/**
+ * 1D hash recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020
+ * See https://www.shadertoy.com/view/4tXyWN and https://www.shadertoy.com/view/XlGcRh
+ * http://www.jcgt.org/published/0009/03/02/paper.pdf
+ */
+ccl_device_inline uint hash_iqint1(uint n)
+{
+ n = (n << 13U) ^ n;
+ n = n * (n * n * 15731U + 789221U) + 1376312589U;
+
+ return n;
+}
+
+/**
+ * 2D hash recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020
+ * See https://www.shadertoy.com/view/4tXyWN and https://www.shadertoy.com/view/XlGcRh
+ * http://www.jcgt.org/published/0009/03/02/paper.pdf
+ */
+ccl_device_inline uint hash_iqnt2d(const uint x, const uint y)
+{
+ const uint qx = 1103515245U * ((x >> 1U) ^ (y));
+ const uint qy = 1103515245U * ((y >> 1U) ^ (x));
+ const uint n = 1103515245U * ((qx) ^ (qy >> 3U));
+
+ return n;
+}
+
+ccl_device_inline uint path_rng_hash_init(KernelGlobals kg,
+ const int sample,
+ const int x,
+ const int y)
+{
+ const uint rng_hash = hash_iqnt2d(x, y) ^ kernel_data.integrator.seed;
+
+#ifdef __DEBUG_CORRELATION__
+ srand48(rng_hash + sample);
+#else
+ (void)sample;
+#endif
+
+ return rng_hash;
+}
+
+ccl_device_inline bool sample_is_even(int pattern, int sample)
+{
+ if (pattern == SAMPLING_PATTERN_PMJ) {
+ /* See Section 10.2.1, "Progressive Multi-Jittered Sample Sequences", Christensen et al.
+ * We can use this to get divide sample sequence into two classes for easier variance
+ * estimation. */
+#if defined(__GNUC__) && !defined(__KERNEL_GPU__)
+ return __builtin_popcount(sample & 0xaaaaaaaa) & 1;
+#elif defined(__NVCC__)
+ return __popc(sample & 0xaaaaaaaa) & 1;
+#else
+ /* TODO(Stefan): pop-count intrinsic for Windows with fallback for older CPUs. */
+ int i = sample & 0xaaaaaaaa;
+ i = i - ((i >> 1) & 0x55555555);
+ i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
+ i = (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+ return i & 1;
+#endif
+ }
+ else {
+ /* TODO(Stefan): Are there reliable ways of dividing CMJ and Sobol into two classes? */
+ return sample & 0x1;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/ao.h b/intern/cycles/kernel/svm/ao.h
new file mode 100644
index 00000000000..678f49c8ccd
--- /dev/null
+++ b/intern/cycles/kernel/svm/ao.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/bvh/bvh.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __SHADER_RAYTRACE__
+
+# ifdef __KERNEL_OPTIX__
+extern "C" __device__ float __direct_callable__svm_node_ao(
+# else
+ccl_device float svm_ao(
+# endif
+ KernelGlobals kg,
+ ConstIntegratorState state,
+ ccl_private ShaderData *sd,
+ float3 N,
+ float max_dist,
+ int num_samples,
+ int flags)
+{
+ if (flags & NODE_AO_GLOBAL_RADIUS) {
+ max_dist = kernel_data.integrator.ao_bounces_distance;
+ }
+
+ /* Early out if no sampling needed. */
+ if (max_dist <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) {
+ return 1.0f;
+ }
+
+ /* Can't raytrace from shaders like displacement, before BVH exists. */
+ if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
+ return 1.0f;
+ }
+
+ if (flags & NODE_AO_INSIDE) {
+ N = -N;
+ }
+
+ float3 T, B;
+ make_orthonormals(N, &T, &B);
+
+ /* TODO: support ray-tracing in shadow shader evaluation? */
+ RNGState rng_state;
+ path_state_rng_load(state, &rng_state);
+
+ int unoccluded = 0;
+ for (int sample = 0; sample < num_samples; sample++) {
+ float disk_u, disk_v;
+ path_branched_rng_2D(kg, &rng_state, sample, num_samples, PRNG_BEVEL_U, &disk_u, &disk_v);
+
+ float2 d = concentric_sample_disk(disk_u, disk_v);
+ float3 D = make_float3(d.x, d.y, safe_sqrtf(1.0f - dot(d, d)));
+
+ /* Create ray. */
+ Ray ray;
+ ray.P = ray_offset(sd->P, N);
+ ray.D = D.x * T + D.y * B + D.z * N;
+ ray.t = max_dist;
+ ray.time = sd->time;
+ ray.dP = differential_zero_compact();
+ ray.dD = differential_zero_compact();
+
+ if (flags & NODE_AO_ONLY_LOCAL) {
+ if (!scene_intersect_local(kg, &ray, NULL, sd->object, NULL, 0)) {
+ unoccluded++;
+ }
+ }
+ else {
+ Intersection isect;
+ if (!scene_intersect(kg, &ray, PATH_RAY_SHADOW_OPAQUE, &isect)) {
+ unoccluded++;
+ }
+ }
+ }
+
+ return ((float)unoccluded) / num_samples;
+}
+
+template<uint node_feature_mask, typename ConstIntegratorGenericState>
+# if defined(__KERNEL_OPTIX__)
+ccl_device_inline
+# else
+ccl_device_noinline
+# endif
+ void
+ svm_node_ao(KernelGlobals kg,
+ ConstIntegratorGenericState state,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint flags, dist_offset, normal_offset, out_ao_offset;
+ svm_unpack_node_uchar4(node.y, &flags, &dist_offset, &normal_offset, &out_ao_offset);
+
+ uint color_offset, out_color_offset, samples;
+ svm_unpack_node_uchar3(node.z, &color_offset, &out_color_offset, &samples);
+
+ float ao = 1.0f;
+
+ IF_KERNEL_NODES_FEATURE(RAYTRACE)
+ {
+ float dist = stack_load_float_default(stack, dist_offset, node.w);
+ float3 normal = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N;
+
+# ifdef __KERNEL_OPTIX__
+ ao = optixDirectCall<float>(0, kg, state, sd, normal, dist, samples, flags);
+# else
+ ao = svm_ao(kg, state, sd, normal, dist, samples, flags);
+# endif
+ }
+
+ if (stack_valid(out_ao_offset)) {
+ stack_store_float(stack, out_ao_offset, ao);
+ }
+
+ if (stack_valid(out_color_offset)) {
+ float3 color = stack_load_float3(stack, color_offset);
+ stack_store_float3(stack, out_color_offset, ao * color);
+ }
+}
+
+#endif /* __SHADER_RAYTRACE__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/aov.h b/intern/cycles/kernel/svm/aov.h
new file mode 100644
index 00000000000..21ee7af7639
--- /dev/null
+++ b/intern/cycles/kernel/svm/aov.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/film/write_passes.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline bool svm_node_aov_check(const uint32_t path_flag,
+ ccl_global float *render_buffer)
+{
+ bool is_primary = (path_flag & PATH_RAY_CAMERA) && (!(path_flag & PATH_RAY_SINGLE_PASS_DONE));
+
+ return ((render_buffer != NULL) && is_primary);
+}
+
+template<uint node_feature_mask, typename ConstIntegratorGenericState>
+ccl_device void svm_node_aov_color(KernelGlobals kg,
+ ConstIntegratorGenericState state,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node,
+ ccl_global float *render_buffer)
+{
+ IF_KERNEL_NODES_FEATURE(AOV)
+ {
+ const float3 val = stack_load_float3(stack, node.y);
+ const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
+ const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
+ kernel_data.film.pass_stride;
+ ccl_global float *buffer = render_buffer + render_buffer_offset +
+ (kernel_data.film.pass_aov_color + node.z);
+ kernel_write_pass_float3(buffer, make_float3(val.x, val.y, val.z));
+ }
+}
+
+template<uint node_feature_mask, typename ConstIntegratorGenericState>
+ccl_device void svm_node_aov_value(KernelGlobals kg,
+ ConstIntegratorGenericState state,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node,
+ ccl_global float *render_buffer)
+{
+ IF_KERNEL_NODES_FEATURE(AOV)
+ {
+ const float val = stack_load_float(stack, node.y);
+ const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
+ const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
+ kernel_data.film.pass_stride;
+ ccl_global float *buffer = render_buffer + render_buffer_offset +
+ (kernel_data.film.pass_aov_value + node.z);
+ kernel_write_pass_float(buffer, val);
+ }
+}
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/attribute.h b/intern/cycles/kernel/svm/attribute.h
new file mode 100644
index 00000000000..e9de0164c7a
--- /dev/null
+++ b/intern/cycles/kernel/svm/attribute.h
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Attribute Node */
+
+ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ uint4 node,
+ ccl_private NodeAttributeOutputType *type,
+ ccl_private uint *out_offset)
+{
+ *out_offset = node.z;
+ *type = (NodeAttributeOutputType)node.w;
+
+ AttributeDescriptor desc;
+
+ if (sd->object != OBJECT_NONE) {
+ desc = find_attribute(kg, sd, node.y);
+ if (desc.offset == ATTR_STD_NOT_FOUND) {
+ desc = attribute_not_found();
+ desc.offset = 0;
+ desc.type = (NodeAttributeType)node.w;
+ }
+ }
+ else {
+ /* background */
+ desc = attribute_not_found();
+ desc.offset = 0;
+ desc.type = (NodeAttributeType)node.w;
+ }
+
+ return desc;
+}
+
+template<uint node_feature_mask>
+ccl_device_noinline void svm_node_attr(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
+ uint out_offset = 0;
+ AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
+
+#ifdef __VOLUME__
+ IF_KERNEL_NODES_FEATURE(VOLUME)
+ {
+ /* Volumes
+ * NOTE: moving this into its own node type might help improve performance. */
+ if (primitive_is_volume_attribute(sd, desc)) {
+ const float4 value = volume_attribute_float4(kg, sd, desc);
+
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ const float f = volume_attribute_value_to_float(value);
+ stack_store_float(stack, out_offset, f);
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ const float3 f = volume_attribute_value_to_float3(value);
+ stack_store_float3(stack, out_offset, f);
+ }
+ else {
+ const float f = volume_attribute_value_to_alpha(value);
+ stack_store_float(stack, out_offset, f);
+ }
+ return;
+ }
+ }
+#endif
+
+ if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
+ /* No generated attribute, fall back to object coordinates. */
+ float3 f = sd->P;
+ object_inverse_position_transform(kg, sd, &f);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, average(f));
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, f);
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ return;
+ }
+
+ /* Surface. */
+ if (desc.type == NODE_ATTR_FLOAT) {
+ float f = primitive_surface_attribute_float(kg, sd, desc, NULL, NULL);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, f);
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, make_float3(f, f, f));
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ }
+ else if (desc.type == NODE_ATTR_FLOAT2) {
+ float2 f = primitive_surface_attribute_float2(kg, sd, desc, NULL, NULL);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, f.x);
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, make_float3(f.x, f.y, 0.0f));
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ }
+ else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
+ float4 f = primitive_surface_attribute_float4(kg, sd, desc, NULL, NULL);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, average(float4_to_float3(f)));
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, float4_to_float3(f));
+ }
+ else {
+ stack_store_float(stack, out_offset, f.w);
+ }
+ }
+ else {
+ float3 f = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, average(f));
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, f);
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ }
+}
+
+ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
+ uint out_offset = 0;
+ AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
+
+#ifdef __VOLUME__
+ /* Volume */
+ if (primitive_is_volume_attribute(sd, desc)) {
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, 0.0f);
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f));
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ return;
+ }
+#endif
+
+ if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
+ /* No generated attribute, fall back to object coordinates. */
+ float3 f = sd->P + sd->dP.dx;
+ object_inverse_position_transform(kg, sd, &f);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, average(f));
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, f);
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ return;
+ }
+
+ /* Surface */
+ if (desc.type == NODE_ATTR_FLOAT) {
+ float dx;
+ float f = primitive_surface_attribute_float(kg, sd, desc, &dx, NULL);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, f + dx);
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, make_float3(f + dx, f + dx, f + dx));
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ }
+ else if (desc.type == NODE_ATTR_FLOAT2) {
+ float2 dx;
+ float2 f = primitive_surface_attribute_float2(kg, sd, desc, &dx, NULL);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, f.x + dx.x);
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, make_float3(f.x + dx.x, f.y + dx.y, 0.0f));
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ }
+ else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
+ float4 dx;
+ float4 f = primitive_surface_attribute_float4(kg, sd, desc, &dx, NULL);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, average(float4_to_float3(f + dx)));
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, float4_to_float3(f + dx));
+ }
+ else {
+ stack_store_float(stack, out_offset, f.w + dx.w);
+ }
+ }
+ else {
+ float3 dx;
+ float3 f = primitive_surface_attribute_float3(kg, sd, desc, &dx, NULL);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, average(f + dx));
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, f + dx);
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ }
+}
+
+ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
+ uint out_offset = 0;
+ AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
+
+#ifdef __VOLUME__
+ /* Volume */
+ if (primitive_is_volume_attribute(sd, desc)) {
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, 0.0f);
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f));
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ return;
+ }
+#endif
+
+ if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
+ /* No generated attribute, fall back to object coordinates. */
+ float3 f = sd->P + sd->dP.dy;
+ object_inverse_position_transform(kg, sd, &f);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, average(f));
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, f);
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ return;
+ }
+
+ /* Surface */
+ if (desc.type == NODE_ATTR_FLOAT) {
+ float dy;
+ float f = primitive_surface_attribute_float(kg, sd, desc, NULL, &dy);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, f + dy);
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, make_float3(f + dy, f + dy, f + dy));
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ }
+ else if (desc.type == NODE_ATTR_FLOAT2) {
+ float2 dy;
+ float2 f = primitive_surface_attribute_float2(kg, sd, desc, NULL, &dy);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, f.x + dy.x);
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, make_float3(f.x + dy.x, f.y + dy.y, 0.0f));
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ }
+ else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
+ float4 dy;
+ float4 f = primitive_surface_attribute_float4(kg, sd, desc, NULL, &dy);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, average(float4_to_float3(f + dy)));
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, float4_to_float3(f + dy));
+ }
+ else {
+ stack_store_float(stack, out_offset, f.w + dy.w);
+ }
+ }
+ else {
+ float3 dy;
+ float3 f = primitive_surface_attribute_float3(kg, sd, desc, NULL, &dy);
+ if (type == NODE_ATTR_OUTPUT_FLOAT) {
+ stack_store_float(stack, out_offset, average(f + dy));
+ }
+ else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
+ stack_store_float3(stack, out_offset, f + dy);
+ }
+ else {
+ stack_store_float(stack, out_offset, 1.0f);
+ }
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/bevel.h b/intern/cycles/kernel/svm/bevel.h
new file mode 100644
index 00000000000..6799489514f
--- /dev/null
+++ b/intern/cycles/kernel/svm/bevel.h
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/bvh/bvh.h"
+#include "kernel/sample/mapping.h"
+#include "kernel/sample/pattern.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __SHADER_RAYTRACE__
+
+/* Planar Cubic BSSRDF falloff, reused for bevel.
+ *
+ * This is basically (Rm - x)^3, with some factors to normalize it. For sampling
+ * we integrate 2*pi*x * (Rm - x)^3, which gives us a quintic equation that as
+ * far as I can tell has no closed form solution. So we get an iterative solution
+ * instead with newton-raphson. */
+
+ccl_device float svm_bevel_cubic_eval(const float radius, float r)
+{
+ const float Rm = radius;
+
+ if (r >= Rm)
+ return 0.0f;
+
+ /* integrate (2*pi*r * 10*(R - r)^3)/(pi * R^5) from 0 to R = 1 */
+ const float Rm5 = (Rm * Rm) * (Rm * Rm) * Rm;
+ const float f = Rm - r;
+ const float num = f * f * f;
+
+ return (10.0f * num) / (Rm5 * M_PI_F);
+}
+
+ccl_device float svm_bevel_cubic_pdf(const float radius, float r)
+{
+ return svm_bevel_cubic_eval(radius, r);
+}
+
+/* solve 10x^2 - 20x^3 + 15x^4 - 4x^5 - xi == 0 */
+ccl_device_forceinline float svm_bevel_cubic_quintic_root_find(float xi)
+{
+ /* newton-raphson iteration, usually succeeds in 2-4 iterations, except
+ * outside 0.02 ... 0.98 where it can go up to 10, so overall performance
+ * should not be too bad */
+ const float tolerance = 1e-6f;
+ const int max_iteration_count = 10;
+ float x = 0.25f;
+ int i;
+
+ for (i = 0; i < max_iteration_count; i++) {
+ float x2 = x * x;
+ float x3 = x2 * x;
+ float nx = (1.0f - x);
+
+ float f = 10.0f * x2 - 20.0f * x3 + 15.0f * x2 * x2 - 4.0f * x2 * x3 - xi;
+ float f_ = 20.0f * (x * nx) * (nx * nx);
+
+ if (fabsf(f) < tolerance || f_ == 0.0f)
+ break;
+
+ x = saturatef(x - f / f_);
+ }
+
+ return x;
+}
+
+ccl_device void svm_bevel_cubic_sample(const float radius,
+ float xi,
+ ccl_private float *r,
+ ccl_private float *h)
+{
+ float Rm = radius;
+ float r_ = svm_bevel_cubic_quintic_root_find(xi);
+
+ r_ *= Rm;
+ *r = r_;
+
+ /* h^2 + r^2 = Rm^2 */
+ *h = safe_sqrtf(Rm * Rm - r_ * r_);
+}
+
+/* Bevel shader averaging normals from nearby surfaces.
+ *
+ * Sampling strategy from: BSSRDF Importance Sampling, SIGGRAPH 2013
+ * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf
+ */
+
+# ifdef __KERNEL_OPTIX__
+extern "C" __device__ float3 __direct_callable__svm_node_bevel(
+# else
+ccl_device float3 svm_bevel(
+# endif
+ KernelGlobals kg,
+ ConstIntegratorState state,
+ ccl_private ShaderData *sd,
+ float radius,
+ int num_samples)
+{
+ /* Early out if no sampling needed. */
+ if (radius <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) {
+ return sd->N;
+ }
+
+ /* Can't raytrace from shaders like displacement, before BVH exists. */
+ if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
+ return sd->N;
+ }
+
+ /* Don't bevel for blurry indirect rays. */
+ if (INTEGRATOR_STATE(state, path, min_ray_pdf) < 8.0f) {
+ return sd->N;
+ }
+
+ /* Setup for multi intersection. */
+ LocalIntersection isect;
+ uint lcg_state = lcg_state_init(INTEGRATOR_STATE(state, path, rng_hash),
+ INTEGRATOR_STATE(state, path, rng_offset),
+ INTEGRATOR_STATE(state, path, sample),
+ 0x64c6a40e);
+
+ /* Sample normals from surrounding points on surface. */
+ float3 sum_N = make_float3(0.0f, 0.0f, 0.0f);
+
+ /* TODO: support ray-tracing in shadow shader evaluation? */
+ RNGState rng_state;
+ path_state_rng_load(state, &rng_state);
+
+ for (int sample = 0; sample < num_samples; sample++) {
+ float disk_u, disk_v;
+ path_branched_rng_2D(kg, &rng_state, sample, num_samples, PRNG_BEVEL_U, &disk_u, &disk_v);
+
+ /* Pick random axis in local frame and point on disk. */
+ float3 disk_N, disk_T, disk_B;
+ float pick_pdf_N, pick_pdf_T, pick_pdf_B;
+
+ disk_N = sd->Ng;
+ make_orthonormals(disk_N, &disk_T, &disk_B);
+
+ float axisu = disk_u;
+
+ if (axisu < 0.5f) {
+ pick_pdf_N = 0.5f;
+ pick_pdf_T = 0.25f;
+ pick_pdf_B = 0.25f;
+ disk_u *= 2.0f;
+ }
+ else if (axisu < 0.75f) {
+ float3 tmp = disk_N;
+ disk_N = disk_T;
+ disk_T = tmp;
+ pick_pdf_N = 0.25f;
+ pick_pdf_T = 0.5f;
+ pick_pdf_B = 0.25f;
+ disk_u = (disk_u - 0.5f) * 4.0f;
+ }
+ else {
+ float3 tmp = disk_N;
+ disk_N = disk_B;
+ disk_B = tmp;
+ pick_pdf_N = 0.25f;
+ pick_pdf_T = 0.25f;
+ pick_pdf_B = 0.5f;
+ disk_u = (disk_u - 0.75f) * 4.0f;
+ }
+
+ /* Sample point on disk. */
+ float phi = M_2PI_F * disk_u;
+ float disk_r = disk_v;
+ float disk_height;
+
+ /* Perhaps find something better than Cubic BSSRDF, but happens to work well. */
+ svm_bevel_cubic_sample(radius, disk_r, &disk_r, &disk_height);
+
+ float3 disk_P = (disk_r * cosf(phi)) * disk_T + (disk_r * sinf(phi)) * disk_B;
+
+ /* Create ray. */
+ Ray ray ccl_optional_struct_init;
+ ray.P = sd->P + disk_N * disk_height + disk_P;
+ ray.D = -disk_N;
+ ray.t = 2.0f * disk_height;
+ ray.dP = differential_zero_compact();
+ ray.dD = differential_zero_compact();
+ ray.time = sd->time;
+
+ /* Intersect with the same object. if multiple intersections are found it
+ * will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */
+ scene_intersect_local(kg, &ray, &isect, sd->object, &lcg_state, LOCAL_MAX_HITS);
+
+ int num_eval_hits = min(isect.num_hits, LOCAL_MAX_HITS);
+
+ for (int hit = 0; hit < num_eval_hits; hit++) {
+ /* Quickly retrieve P and Ng without setting up ShaderData. */
+ float3 hit_P;
+ if (sd->type & PRIMITIVE_TRIANGLE) {
+ hit_P = triangle_refine_local(
+ kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim);
+ }
+# ifdef __OBJECT_MOTION__
+ else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
+ float3 verts[3];
+ motion_triangle_vertices(kg, sd->object, isect.hits[hit].prim, sd->time, verts);
+ hit_P = motion_triangle_refine_local(
+ kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim, verts);
+ }
+# endif /* __OBJECT_MOTION__ */
+
+ /* Get geometric normal. */
+ float3 hit_Ng = isect.Ng[hit];
+ int object = isect.hits[hit].object;
+ int object_flag = kernel_tex_fetch(__object_flag, object);
+ if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+ hit_Ng = -hit_Ng;
+ }
+
+ /* Compute smooth normal. */
+ float3 N = hit_Ng;
+ int prim = isect.hits[hit].prim;
+ int shader = kernel_tex_fetch(__tri_shader, prim);
+
+ if (shader & SHADER_SMOOTH_NORMAL) {
+ float u = isect.hits[hit].u;
+ float v = isect.hits[hit].v;
+
+ if (sd->type & PRIMITIVE_TRIANGLE) {
+ N = triangle_smooth_normal(kg, N, prim, u, v);
+ }
+# ifdef __OBJECT_MOTION__
+ else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
+ N = motion_triangle_smooth_normal(kg, N, sd->object, prim, u, v, sd->time);
+ }
+# endif /* __OBJECT_MOTION__ */
+ }
+
+ /* Transform normals to world space. */
+ if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ object_normal_transform(kg, sd, &N);
+ object_normal_transform(kg, sd, &hit_Ng);
+ }
+
+ /* Probability densities for local frame axes. */
+ float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng));
+ float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng));
+ float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng));
+
+ /* Multiple importance sample between 3 axes, power heuristic
+ * found to be slightly better than balance heuristic. pdf_N
+ * in the MIS weight and denominator canceled out. */
+ float w = pdf_N / (sqr(pdf_N) + sqr(pdf_T) + sqr(pdf_B));
+ if (isect.num_hits > LOCAL_MAX_HITS) {
+ w *= isect.num_hits / (float)LOCAL_MAX_HITS;
+ }
+
+ /* Real distance to sampled point. */
+ float r = len(hit_P - sd->P);
+
+ /* Compute weight. */
+ float pdf = svm_bevel_cubic_pdf(radius, r);
+ float disk_pdf = svm_bevel_cubic_pdf(radius, disk_r);
+
+ w *= pdf / disk_pdf;
+
+ /* Sum normal and weight. */
+ sum_N += w * N;
+ }
+ }
+
+ /* Normalize. */
+ float3 N = safe_normalize(sum_N);
+ return is_zero(N) ? sd->N : (sd->flag & SD_BACKFACING) ? -N : N;
+}
+
+template<uint node_feature_mask, typename ConstIntegratorGenericState>
+# if defined(__KERNEL_OPTIX__)
+ccl_device_inline
+# else
+ccl_device_noinline
+# endif
+ void
+ svm_node_bevel(KernelGlobals kg,
+ ConstIntegratorGenericState state,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint num_samples, radius_offset, normal_offset, out_offset;
+ svm_unpack_node_uchar4(node.y, &num_samples, &radius_offset, &normal_offset, &out_offset);
+
+ float3 bevel_N = sd->N;
+
+ IF_KERNEL_NODES_FEATURE(RAYTRACE)
+ {
+ float radius = stack_load_float(stack, radius_offset);
+
+# ifdef __KERNEL_OPTIX__
+ bevel_N = optixDirectCall<float3>(1, kg, state, sd, radius, num_samples);
+# else
+ bevel_N = svm_bevel(kg, state, sd, radius, num_samples);
+# endif
+
+ if (stack_valid(normal_offset)) {
+ /* Preserve input normal. */
+ float3 ref_N = stack_load_float3(stack, normal_offset);
+ bevel_N = normalize(ref_N + (bevel_N - sd->N));
+ }
+ }
+
+ stack_store_float3(stack, out_offset, bevel_N);
+}
+
+#endif /* __SHADER_RAYTRACE__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/blackbody.h b/intern/cycles/kernel/svm/blackbody.h
new file mode 100644
index 00000000000..da15550f918
--- /dev/null
+++ b/intern/cycles/kernel/svm/blackbody.h
@@ -0,0 +1,55 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2013, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "kernel/svm/math_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Blackbody Node */
+
+ccl_device_noinline void svm_node_blackbody(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint temperature_offset,
+ uint col_offset)
+{
+ /* Input */
+ float temperature = stack_load_float(stack, temperature_offset);
+
+ float3 color_rgb = svm_math_blackbody_color(temperature);
+
+ stack_store_float3(stack, col_offset, color_rgb);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/brick.h b/intern/cycles/kernel/svm/brick.h
new file mode 100644
index 00000000000..d8d01766106
--- /dev/null
+++ b/intern/cycles/kernel/svm/brick.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Brick */
+
+ccl_device_inline float brick_noise(uint n) /* fast integer noise */
+{
+ uint nn;
+ n = (n + 1013) & 0x7fffffff;
+ n = (n >> 13) ^ n;
+ nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ return 0.5f * ((float)nn / 1073741824.0f);
+}
+
+ccl_device_noinline_cpu float2 svm_brick(float3 p,
+ float mortar_size,
+ float mortar_smooth,
+ float bias,
+ float brick_width,
+ float row_height,
+ float offset_amount,
+ int offset_frequency,
+ float squash_amount,
+ int squash_frequency)
+{
+ int bricknum, rownum;
+ float offset = 0.0f;
+ float x, y;
+
+ rownum = floor_to_int(p.y / row_height);
+
+ if (offset_frequency && squash_frequency) {
+ brick_width *= (rownum % squash_frequency) ? 1.0f : squash_amount; /* squash */
+ offset = (rownum % offset_frequency) ? 0.0f : (brick_width * offset_amount); /* offset */
+ }
+
+ bricknum = floor_to_int((p.x + offset) / brick_width);
+
+ x = (p.x + offset) - brick_width * bricknum;
+ y = p.y - row_height * rownum;
+
+ float tint = saturatef((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias));
+ float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
+
+ float mortar;
+ if (min_dist >= mortar_size) {
+ mortar = 0.0f;
+ }
+ else if (mortar_smooth == 0.0f) {
+ mortar = 1.0f;
+ }
+ else {
+ min_dist = 1.0f - min_dist / mortar_size;
+ mortar = (min_dist < mortar_smooth) ? smoothstepf(min_dist / mortar_smooth) : 1.0f;
+ }
+
+ return make_float2(tint, mortar);
+}
+
+ccl_device_noinline int svm_node_tex_brick(
+ KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
+{
+ uint4 node2 = read_node(kg, &offset);
+ uint4 node3 = read_node(kg, &offset);
+ uint4 node4 = read_node(kg, &offset);
+
+ /* Input and Output Sockets */
+ uint co_offset, color1_offset, color2_offset, mortar_offset, scale_offset;
+ uint mortar_size_offset, bias_offset, brick_width_offset, row_height_offset;
+ uint color_offset, fac_offset, mortar_smooth_offset;
+
+ /* RNA properties */
+ uint offset_frequency, squash_frequency;
+
+ svm_unpack_node_uchar4(node.y, &co_offset, &color1_offset, &color2_offset, &mortar_offset);
+ svm_unpack_node_uchar4(
+ node.z, &scale_offset, &mortar_size_offset, &bias_offset, &brick_width_offset);
+ svm_unpack_node_uchar4(
+ node.w, &row_height_offset, &color_offset, &fac_offset, &mortar_smooth_offset);
+
+ svm_unpack_node_uchar2(node2.x, &offset_frequency, &squash_frequency);
+
+ float3 co = stack_load_float3(stack, co_offset);
+
+ float3 color1 = stack_load_float3(stack, color1_offset);
+ float3 color2 = stack_load_float3(stack, color2_offset);
+ float3 mortar = stack_load_float3(stack, mortar_offset);
+
+ float scale = stack_load_float_default(stack, scale_offset, node2.y);
+ float mortar_size = stack_load_float_default(stack, mortar_size_offset, node2.z);
+ float mortar_smooth = stack_load_float_default(stack, mortar_smooth_offset, node4.x);
+ float bias = stack_load_float_default(stack, bias_offset, node2.w);
+ float brick_width = stack_load_float_default(stack, brick_width_offset, node3.x);
+ float row_height = stack_load_float_default(stack, row_height_offset, node3.y);
+ float offset_amount = __int_as_float(node3.z);
+ float squash_amount = __int_as_float(node3.w);
+
+ float2 f2 = svm_brick(co * scale,
+ mortar_size,
+ mortar_smooth,
+ bias,
+ brick_width,
+ row_height,
+ offset_amount,
+ offset_frequency,
+ squash_amount,
+ squash_frequency);
+
+ float tint = f2.x;
+ float f = f2.y;
+
+ if (f != 1.0f) {
+ float facm = 1.0f - tint;
+ color1 = facm * color1 + tint * color2;
+ }
+
+ if (stack_valid(color_offset))
+ stack_store_float3(stack, color_offset, color1 * (1.0f - f) + mortar * f);
+ if (stack_valid(fac_offset))
+ stack_store_float(stack, fac_offset, f);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/brightness.h b/intern/cycles/kernel/svm/brightness.h
new file mode 100644
index 00000000000..5c82a4347cd
--- /dev/null
+++ b/intern/cycles/kernel/svm/brightness.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/svm/color_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline void svm_node_brightness(
+ ccl_private ShaderData *sd, ccl_private float *stack, uint in_color, uint out_color, uint node)
+{
+ uint bright_offset, contrast_offset;
+ float3 color = stack_load_float3(stack, in_color);
+
+ svm_unpack_node_uchar2(node, &bright_offset, &contrast_offset);
+ float brightness = stack_load_float(stack, bright_offset);
+ float contrast = stack_load_float(stack, contrast_offset);
+
+ color = svm_brightness_contrast(color, brightness, contrast);
+
+ if (stack_valid(out_color))
+ stack_store_float3(stack, out_color, color);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/bump.h b/intern/cycles/kernel/svm/bump.h
new file mode 100644
index 00000000000..2fae06fa54b
--- /dev/null
+++ b/intern/cycles/kernel/svm/bump.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Bump Eval Nodes */
+
+ccl_device_noinline void svm_node_enter_bump_eval(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint offset)
+{
+ /* save state */
+ stack_store_float3(stack, offset + 0, sd->P);
+ stack_store_float3(stack, offset + 3, sd->dP.dx);
+ stack_store_float3(stack, offset + 6, sd->dP.dy);
+
+ /* set state as if undisplaced */
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_POSITION_UNDISPLACED);
+
+ if (desc.offset != ATTR_STD_NOT_FOUND) {
+ float3 P, dPdx, dPdy;
+ P = primitive_surface_attribute_float3(kg, sd, desc, &dPdx, &dPdy);
+
+ object_position_transform(kg, sd, &P);
+ object_dir_transform(kg, sd, &dPdx);
+ object_dir_transform(kg, sd, &dPdy);
+
+ sd->P = P;
+ sd->dP.dx = dPdx;
+ sd->dP.dy = dPdy;
+ }
+}
+
+ccl_device_noinline void svm_node_leave_bump_eval(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint offset)
+{
+ /* restore state */
+ sd->P = stack_load_float3(stack, offset + 0);
+ sd->dP.dx = stack_load_float3(stack, offset + 3);
+ sd->dP.dy = stack_load_float3(stack, offset + 6);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/camera.h b/intern/cycles/kernel/svm/camera.h
new file mode 100644
index 00000000000..c71c02e6b19
--- /dev/null
+++ b/intern/cycles/kernel/svm/camera.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline void svm_node_camera(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint out_vector,
+ uint out_zdepth,
+ uint out_distance)
+{
+ float distance;
+ float zdepth;
+ float3 vector;
+
+ Transform tfm = kernel_data.cam.worldtocamera;
+ vector = transform_point(&tfm, sd->P);
+ zdepth = vector.z;
+ distance = len(vector);
+
+ if (stack_valid(out_vector))
+ stack_store_float3(stack, out_vector, normalize(vector));
+
+ if (stack_valid(out_zdepth))
+ stack_store_float(stack, out_zdepth, zdepth);
+
+ if (stack_valid(out_distance))
+ stack_store_float(stack, out_distance, distance);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/checker.h b/intern/cycles/kernel/svm/checker.h
new file mode 100644
index 00000000000..a79b1651f44
--- /dev/null
+++ b/intern/cycles/kernel/svm/checker.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Checker */
+
+ccl_device float svm_checker(float3 p)
+{
+ /* avoid precision issues on unit coordinates */
+ p.x = (p.x + 0.000001f) * 0.999999f;
+ p.y = (p.y + 0.000001f) * 0.999999f;
+ p.z = (p.z + 0.000001f) * 0.999999f;
+
+ int xi = abs(float_to_int(floorf(p.x)));
+ int yi = abs(float_to_int(floorf(p.y)));
+ int zi = abs(float_to_int(floorf(p.z)));
+
+ return ((xi % 2 == yi % 2) == (zi % 2)) ? 1.0f : 0.0f;
+}
+
+ccl_device_noinline void svm_node_tex_checker(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint co_offset, color1_offset, color2_offset, scale_offset;
+ uint color_offset, fac_offset;
+
+ svm_unpack_node_uchar4(node.y, &co_offset, &color1_offset, &color2_offset, &scale_offset);
+ svm_unpack_node_uchar2(node.z, &color_offset, &fac_offset);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float3 color1 = stack_load_float3(stack, color1_offset);
+ float3 color2 = stack_load_float3(stack, color2_offset);
+ float scale = stack_load_float_default(stack, scale_offset, node.w);
+
+ float f = svm_checker(co * scale);
+
+ if (stack_valid(color_offset))
+ stack_store_float3(stack, color_offset, (f == 1.0f) ? color1 : color2);
+ if (stack_valid(fac_offset))
+ stack_store_float(stack, fac_offset, f);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/clamp.h b/intern/cycles/kernel/svm/clamp.h
new file mode 100644
index 00000000000..c07c0206d29
--- /dev/null
+++ b/intern/cycles/kernel/svm/clamp.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Clamp Node */
+
+ccl_device_noinline int svm_node_clamp(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint value_stack_offset,
+ uint parameters_stack_offsets,
+ uint result_stack_offset,
+ int offset)
+{
+ uint min_stack_offset, max_stack_offset, type;
+ svm_unpack_node_uchar3(parameters_stack_offsets, &min_stack_offset, &max_stack_offset, &type);
+
+ uint4 defaults = read_node(kg, &offset);
+
+ float value = stack_load_float(stack, value_stack_offset);
+ float min = stack_load_float_default(stack, min_stack_offset, defaults.x);
+ float max = stack_load_float_default(stack, max_stack_offset, defaults.y);
+
+ if (type == NODE_CLAMP_RANGE && (min > max)) {
+ stack_store_float(stack, result_stack_offset, clamp(value, max, min));
+ }
+ else {
+ stack_store_float(stack, result_stack_offset, clamp(value, min, max));
+ }
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h
new file mode 100644
index 00000000000..71952e9e0f8
--- /dev/null
+++ b/intern/cycles/kernel/svm/closure.h
@@ -0,0 +1,1260 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Closure Nodes */
+
+ccl_device void svm_node_glass_setup(ccl_private ShaderData *sd,
+ ccl_private MicrofacetBsdf *bsdf,
+ int type,
+ float eta,
+ float roughness,
+ bool refract)
+{
+ if (type == CLOSURE_BSDF_SHARP_GLASS_ID) {
+ if (refract) {
+ bsdf->alpha_y = 0.0f;
+ bsdf->alpha_x = 0.0f;
+ bsdf->ior = eta;
+ sd->flag |= bsdf_refraction_setup(bsdf);
+ }
+ else {
+ bsdf->alpha_y = 0.0f;
+ bsdf->alpha_x = 0.0f;
+ bsdf->ior = 0.0f;
+ sd->flag |= bsdf_reflection_setup(bsdf);
+ }
+ }
+ else if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID) {
+ bsdf->alpha_x = roughness;
+ bsdf->alpha_y = roughness;
+ bsdf->ior = eta;
+
+ if (refract)
+ sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
+ else
+ sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
+ }
+ else {
+ bsdf->alpha_x = roughness;
+ bsdf->alpha_y = roughness;
+ bsdf->ior = eta;
+
+ if (refract)
+ sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
+ else
+ sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
+ }
+}
+
+ccl_device_inline int svm_node_closure_bsdf_skip(KernelGlobals kg, int offset, uint type)
+{
+ if (type == CLOSURE_BSDF_PRINCIPLED_ID) {
+ /* Read all principled BSDF extra data to get the right offset. */
+ read_node(kg, &offset);
+ read_node(kg, &offset);
+ read_node(kg, &offset);
+ read_node(kg, &offset);
+ }
+
+ return offset;
+}
+
+template<uint node_feature_mask, ShaderType shader_type>
+ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node,
+ uint32_t path_flag,
+ int offset)
+{
+ uint type, param1_offset, param2_offset;
+
+ uint mix_weight_offset;
+ svm_unpack_node_uchar4(node.y, &type, &param1_offset, &param2_offset, &mix_weight_offset);
+ float mix_weight = (stack_valid(mix_weight_offset) ? stack_load_float(stack, mix_weight_offset) :
+ 1.0f);
+
+ /* note we read this extra node before weight check, so offset is added */
+ uint4 data_node = read_node(kg, &offset);
+
+ /* Only compute BSDF for surfaces, transparent variable is shared with volume extinction. */
+ IF_KERNEL_NODES_FEATURE(BSDF)
+ {
+ if ((shader_type != SHADER_TYPE_SURFACE) || mix_weight == 0.0f) {
+ return svm_node_closure_bsdf_skip(kg, offset, type);
+ }
+ }
+ else
+ {
+ return svm_node_closure_bsdf_skip(kg, offset, type);
+ }
+
+ float3 N = stack_valid(data_node.x) ? stack_load_float3(stack, data_node.x) : sd->N;
+ if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
+ N = ensure_valid_reflection(sd->Ng, sd->I, N);
+ }
+
+ float param1 = (stack_valid(param1_offset)) ? stack_load_float(stack, param1_offset) :
+ __uint_as_float(node.z);
+ float param2 = (stack_valid(param2_offset)) ? stack_load_float(stack, param2_offset) :
+ __uint_as_float(node.w);
+
+ switch (type) {
+#ifdef __PRINCIPLED__
+ case CLOSURE_BSDF_PRINCIPLED_ID: {
+ uint specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset,
+ sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset,
+ eta_offset, transmission_offset, anisotropic_rotation_offset,
+ transmission_roughness_offset;
+ uint4 data_node2 = read_node(kg, &offset);
+
+ float3 T = stack_load_float3(stack, data_node.y);
+ svm_unpack_node_uchar4(data_node.z,
+ &specular_offset,
+ &roughness_offset,
+ &specular_tint_offset,
+ &anisotropic_offset);
+ svm_unpack_node_uchar4(data_node.w,
+ &sheen_offset,
+ &sheen_tint_offset,
+ &clearcoat_offset,
+ &clearcoat_roughness_offset);
+ svm_unpack_node_uchar4(data_node2.x,
+ &eta_offset,
+ &transmission_offset,
+ &anisotropic_rotation_offset,
+ &transmission_roughness_offset);
+
+ // get Disney principled parameters
+ float metallic = param1;
+ float subsurface = param2;
+ float specular = stack_load_float(stack, specular_offset);
+ float roughness = stack_load_float(stack, roughness_offset);
+ float specular_tint = stack_load_float(stack, specular_tint_offset);
+ float anisotropic = stack_load_float(stack, anisotropic_offset);
+ float sheen = stack_load_float(stack, sheen_offset);
+ float sheen_tint = stack_load_float(stack, sheen_tint_offset);
+ float clearcoat = stack_load_float(stack, clearcoat_offset);
+ float clearcoat_roughness = stack_load_float(stack, clearcoat_roughness_offset);
+ float transmission = stack_load_float(stack, transmission_offset);
+ float anisotropic_rotation = stack_load_float(stack, anisotropic_rotation_offset);
+ float transmission_roughness = stack_load_float(stack, transmission_roughness_offset);
+ float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f);
+
+ ClosureType distribution = (ClosureType)data_node2.y;
+ ClosureType subsurface_method = (ClosureType)data_node2.z;
+
+ /* rotate tangent */
+ if (anisotropic_rotation != 0.0f)
+ T = rotate_around_axis(T, N, anisotropic_rotation * M_2PI_F);
+
+ /* calculate ior */
+ float ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
+
+ // calculate fresnel for refraction
+ float cosNO = dot(N, sd->I);
+ float fresnel = fresnel_dielectric_cos(cosNO, ior);
+
+ // calculate weights of the diffuse and specular part
+ float diffuse_weight = (1.0f - saturatef(metallic)) * (1.0f - saturatef(transmission));
+
+ float final_transmission = saturatef(transmission) * (1.0f - saturatef(metallic));
+ float specular_weight = (1.0f - final_transmission);
+
+ // get the base color
+ uint4 data_base_color = read_node(kg, &offset);
+ float3 base_color = stack_valid(data_base_color.x) ?
+ stack_load_float3(stack, data_base_color.x) :
+ make_float3(__uint_as_float(data_base_color.y),
+ __uint_as_float(data_base_color.z),
+ __uint_as_float(data_base_color.w));
+
+ // get the additional clearcoat normal and subsurface scattering radius
+ uint4 data_cn_ssr = read_node(kg, &offset);
+ float3 clearcoat_normal = stack_valid(data_cn_ssr.x) ?
+ stack_load_float3(stack, data_cn_ssr.x) :
+ sd->N;
+ if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
+ clearcoat_normal = ensure_valid_reflection(sd->Ng, sd->I, clearcoat_normal);
+ }
+ float3 subsurface_radius = stack_valid(data_cn_ssr.y) ?
+ stack_load_float3(stack, data_cn_ssr.y) :
+ make_float3(1.0f, 1.0f, 1.0f);
+ float subsurface_ior = stack_valid(data_cn_ssr.z) ? stack_load_float(stack, data_cn_ssr.z) :
+ 1.4f;
+ float subsurface_anisotropy = stack_valid(data_cn_ssr.w) ?
+ stack_load_float(stack, data_cn_ssr.w) :
+ 0.0f;
+
+ // get the subsurface color
+ uint4 data_subsurface_color = read_node(kg, &offset);
+ float3 subsurface_color = stack_valid(data_subsurface_color.x) ?
+ stack_load_float3(stack, data_subsurface_color.x) :
+ make_float3(__uint_as_float(data_subsurface_color.y),
+ __uint_as_float(data_subsurface_color.z),
+ __uint_as_float(data_subsurface_color.w));
+
+ float3 weight = sd->svm_closure_weight * mix_weight;
+
+# ifdef __SUBSURFACE__
+ float3 mixed_ss_base_color = subsurface_color * subsurface +
+ base_color * (1.0f - subsurface);
+ float3 subsurf_weight = weight * mixed_ss_base_color * diffuse_weight;
+
+ /* disable in case of diffuse ancestor, can't see it well then and
+ * adds considerably noise due to probabilities of continuing path
+ * getting lower and lower */
+ if (path_flag & PATH_RAY_DIFFUSE_ANCESTOR) {
+ subsurface = 0.0f;
+
+ /* need to set the base color in this case such that the
+ * rays get the correctly mixed color after transmitting
+ * the object */
+ base_color = mixed_ss_base_color;
+ }
+
+ /* diffuse */
+ if (fabsf(average(mixed_ss_base_color)) > CLOSURE_WEIGHT_CUTOFF) {
+ if (subsurface <= CLOSURE_WEIGHT_CUTOFF && diffuse_weight > CLOSURE_WEIGHT_CUTOFF) {
+ float3 diff_weight = weight * base_color * diffuse_weight;
+
+ ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)
+ bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), diff_weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+ bsdf->roughness = roughness;
+
+ /* setup bsdf */
+ sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_FULL);
+ }
+ }
+ else if (subsurface > CLOSURE_WEIGHT_CUTOFF) {
+ ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd, subsurf_weight);
+
+ if (bssrdf) {
+ bssrdf->radius = subsurface_radius * subsurface;
+ bssrdf->albedo = mixed_ss_base_color;
+ bssrdf->N = N;
+ bssrdf->roughness = roughness;
+
+ /* Clamps protecting against bad/extreme and non physical values. */
+ subsurface_ior = clamp(subsurface_ior, 1.01f, 3.8f);
+ bssrdf->anisotropy = clamp(subsurface_anisotropy, 0.0f, 0.9f);
+
+ /* setup bsdf */
+ sd->flag |= bssrdf_setup(sd, bssrdf, subsurface_method, subsurface_ior);
+ }
+ }
+ }
+# else
+ /* diffuse */
+ if (diffuse_weight > CLOSURE_WEIGHT_CUTOFF) {
+ float3 diff_weight = weight * base_color * diffuse_weight;
+
+ ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc(
+ sd, sizeof(PrincipledDiffuseBsdf), diff_weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+ bsdf->roughness = roughness;
+
+ /* setup bsdf */
+ sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_FULL);
+ }
+ }
+# endif
+
+ /* sheen */
+ if (diffuse_weight > CLOSURE_WEIGHT_CUTOFF && sheen > CLOSURE_WEIGHT_CUTOFF) {
+ float m_cdlum = linear_rgb_to_gray(kg, base_color);
+ float3 m_ctint = m_cdlum > 0.0f ?
+ base_color / m_cdlum :
+ make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat
+
+ /* color of the sheen component */
+ float3 sheen_color = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - sheen_tint) +
+ m_ctint * sheen_tint;
+
+ float3 sheen_weight = weight * sheen * sheen_color * diffuse_weight;
+
+ ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)bsdf_alloc(
+ sd, sizeof(PrincipledSheenBsdf), sheen_weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+
+ /* setup bsdf */
+ sd->flag |= bsdf_principled_sheen_setup(sd, bsdf);
+ }
+ }
+
+ /* specular reflection */
+# ifdef __CAUSTICS_TRICKS__
+ if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) {
+# endif
+ if (specular_weight > CLOSURE_WEIGHT_CUTOFF &&
+ (specular > CLOSURE_WEIGHT_CUTOFF || metallic > CLOSURE_WEIGHT_CUTOFF)) {
+ float3 spec_weight = weight * specular_weight;
+
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
+ sd, sizeof(MicrofacetBsdf), spec_weight);
+ ccl_private MicrofacetExtra *extra =
+ (bsdf != NULL) ?
+ (ccl_private MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra)) :
+ NULL;
+
+ if (bsdf && extra) {
+ bsdf->N = N;
+ bsdf->ior = (2.0f / (1.0f - safe_sqrtf(0.08f * specular))) - 1.0f;
+ bsdf->T = T;
+ bsdf->extra = extra;
+
+ float aspect = safe_sqrtf(1.0f - anisotropic * 0.9f);
+ float r2 = roughness * roughness;
+
+ bsdf->alpha_x = r2 / aspect;
+ bsdf->alpha_y = r2 * aspect;
+
+ float m_cdlum = 0.3f * base_color.x + 0.6f * base_color.y +
+ 0.1f * base_color.z; // luminance approx.
+ float3 m_ctint = m_cdlum > 0.0f ?
+ base_color / m_cdlum :
+ make_float3(
+ 1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat
+ float3 tmp_col = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - specular_tint) +
+ m_ctint * specular_tint;
+
+ bsdf->extra->cspec0 = (specular * 0.08f * tmp_col) * (1.0f - metallic) +
+ base_color * metallic;
+ bsdf->extra->color = base_color;
+ bsdf->extra->clearcoat = 0.0f;
+
+ /* setup bsdf */
+ if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID ||
+ roughness <= 0.075f) /* use single-scatter GGX */
+ sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd);
+ else /* use multi-scatter GGX */
+ sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd);
+ }
+ }
+# ifdef __CAUSTICS_TRICKS__
+ }
+# endif
+
+ /* BSDF */
+# ifdef __CAUSTICS_TRICKS__
+ if (kernel_data.integrator.caustics_reflective ||
+ kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) {
+# endif
+ if (final_transmission > CLOSURE_WEIGHT_CUTOFF) {
+ float3 glass_weight = weight * final_transmission;
+ float3 cspec0 = base_color * specular_tint +
+ make_float3(1.0f, 1.0f, 1.0f) * (1.0f - specular_tint);
+
+ if (roughness <= 5e-2f ||
+ distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) { /* use single-scatter GGX */
+ float refl_roughness = roughness;
+
+ /* reflection */
+# ifdef __CAUSTICS_TRICKS__
+ if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0)
+# endif
+ {
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
+ sd, sizeof(MicrofacetBsdf), glass_weight * fresnel);
+ ccl_private MicrofacetExtra *extra =
+ (bsdf != NULL) ? (ccl_private MicrofacetExtra *)closure_alloc_extra(
+ sd, sizeof(MicrofacetExtra)) :
+ NULL;
+
+ if (bsdf && extra) {
+ bsdf->N = N;
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra = extra;
+
+ bsdf->alpha_x = refl_roughness * refl_roughness;
+ bsdf->alpha_y = refl_roughness * refl_roughness;
+ bsdf->ior = ior;
+
+ bsdf->extra->color = base_color;
+ bsdf->extra->cspec0 = cspec0;
+ bsdf->extra->clearcoat = 0.0f;
+
+ /* setup bsdf */
+ sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd);
+ }
+ }
+
+ /* refraction */
+# ifdef __CAUSTICS_TRICKS__
+ if (kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0)
+# endif
+ {
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
+ sd, sizeof(MicrofacetBsdf), base_color * glass_weight * (1.0f - fresnel));
+ if (bsdf) {
+ bsdf->N = N;
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra = NULL;
+
+ if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID)
+ transmission_roughness = 1.0f - (1.0f - refl_roughness) *
+ (1.0f - transmission_roughness);
+ else
+ transmission_roughness = refl_roughness;
+
+ bsdf->alpha_x = transmission_roughness * transmission_roughness;
+ bsdf->alpha_y = transmission_roughness * transmission_roughness;
+ bsdf->ior = ior;
+
+ /* setup bsdf */
+ sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
+ }
+ }
+ }
+ else { /* use multi-scatter GGX */
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
+ sd, sizeof(MicrofacetBsdf), glass_weight);
+ ccl_private MicrofacetExtra *extra =
+ (bsdf != NULL) ? (ccl_private MicrofacetExtra *)closure_alloc_extra(
+ sd, sizeof(MicrofacetExtra)) :
+ NULL;
+
+ if (bsdf && extra) {
+ bsdf->N = N;
+ bsdf->extra = extra;
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+
+ bsdf->alpha_x = roughness * roughness;
+ bsdf->alpha_y = roughness * roughness;
+ bsdf->ior = ior;
+
+ bsdf->extra->color = base_color;
+ bsdf->extra->cspec0 = cspec0;
+ bsdf->extra->clearcoat = 0.0f;
+
+ /* setup bsdf */
+ sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf, sd);
+ }
+ }
+ }
+# ifdef __CAUSTICS_TRICKS__
+ }
+# endif
+
+ /* clearcoat */
+# ifdef __CAUSTICS_TRICKS__
+ if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) {
+# endif
+ if (clearcoat > CLOSURE_WEIGHT_CUTOFF) {
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
+ sd, sizeof(MicrofacetBsdf), weight);
+ ccl_private MicrofacetExtra *extra =
+ (bsdf != NULL) ?
+ (ccl_private MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra)) :
+ NULL;
+
+ if (bsdf && extra) {
+ bsdf->N = clearcoat_normal;
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->ior = 1.5f;
+ bsdf->extra = extra;
+
+ bsdf->alpha_x = clearcoat_roughness * clearcoat_roughness;
+ bsdf->alpha_y = clearcoat_roughness * clearcoat_roughness;
+
+ bsdf->extra->color = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra->cspec0 = make_float3(0.04f, 0.04f, 0.04f);
+ bsdf->extra->clearcoat = clearcoat;
+
+ /* setup bsdf */
+ sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(bsdf, sd);
+ }
+ }
+# ifdef __CAUSTICS_TRICKS__
+ }
+# endif
+
+ break;
+ }
+#endif /* __PRINCIPLED__ */
+ case CLOSURE_BSDF_DIFFUSE_ID: {
+ float3 weight = sd->svm_closure_weight * mix_weight;
+ ccl_private OrenNayarBsdf *bsdf = (ccl_private OrenNayarBsdf *)bsdf_alloc(
+ sd, sizeof(OrenNayarBsdf), weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+
+ float roughness = param1;
+
+ if (roughness == 0.0f) {
+ sd->flag |= bsdf_diffuse_setup((ccl_private DiffuseBsdf *)bsdf);
+ }
+ else {
+ bsdf->roughness = roughness;
+ sd->flag |= bsdf_oren_nayar_setup(bsdf);
+ }
+ }
+ break;
+ }
+ case CLOSURE_BSDF_TRANSLUCENT_ID: {
+ float3 weight = sd->svm_closure_weight * mix_weight;
+ ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc(
+ sd, sizeof(DiffuseBsdf), weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+ sd->flag |= bsdf_translucent_setup(bsdf);
+ }
+ break;
+ }
+ case CLOSURE_BSDF_TRANSPARENT_ID: {
+ float3 weight = sd->svm_closure_weight * mix_weight;
+ bsdf_transparent_setup(sd, weight, path_flag);
+ break;
+ }
+ case CLOSURE_BSDF_REFLECTION_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+ case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: {
+#ifdef __CAUSTICS_TRICKS__
+ if (!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
+ break;
+#endif
+ float3 weight = sd->svm_closure_weight * mix_weight;
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
+ sd, sizeof(MicrofacetBsdf), weight);
+
+ if (!bsdf) {
+ break;
+ }
+
+ float roughness = sqr(param1);
+
+ bsdf->N = N;
+ bsdf->ior = 0.0f;
+ bsdf->extra = NULL;
+
+ if (data_node.y == SVM_STACK_INVALID) {
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->alpha_x = roughness;
+ bsdf->alpha_y = roughness;
+ }
+ else {
+ bsdf->T = stack_load_float3(stack, data_node.y);
+
+ /* rotate tangent */
+ float rotation = stack_load_float(stack, data_node.z);
+ if (rotation != 0.0f)
+ bsdf->T = rotate_around_axis(bsdf->T, bsdf->N, rotation * M_2PI_F);
+
+ /* compute roughness */
+ float anisotropy = clamp(param2, -0.99f, 0.99f);
+ if (anisotropy < 0.0f) {
+ bsdf->alpha_x = roughness / (1.0f + anisotropy);
+ bsdf->alpha_y = roughness * (1.0f + anisotropy);
+ }
+ else {
+ bsdf->alpha_x = roughness * (1.0f - anisotropy);
+ bsdf->alpha_y = roughness / (1.0f - anisotropy);
+ }
+ }
+
+ /* setup bsdf */
+ if (type == CLOSURE_BSDF_REFLECTION_ID)
+ sd->flag |= bsdf_reflection_setup(bsdf);
+ else if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID)
+ sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
+ else if (type == CLOSURE_BSDF_MICROFACET_GGX_ID)
+ sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
+ else if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
+ kernel_assert(stack_valid(data_node.w));
+ bsdf->extra = (ccl_private MicrofacetExtra *)closure_alloc_extra(sd,
+ sizeof(MicrofacetExtra));
+ if (bsdf->extra) {
+ bsdf->extra->color = stack_load_float3(stack, data_node.w);
+ bsdf->extra->cspec0 = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra->clearcoat = 0.0f;
+ sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf);
+ }
+ }
+ else {
+ sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf);
+ }
+
+ break;
+ }
+ case CLOSURE_BSDF_REFRACTION_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: {
+#ifdef __CAUSTICS_TRICKS__
+ if (!kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
+ break;
+#endif
+ float3 weight = sd->svm_closure_weight * mix_weight;
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
+ sd, sizeof(MicrofacetBsdf), weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra = NULL;
+
+ float eta = fmaxf(param2, 1e-5f);
+ eta = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
+
+ /* setup bsdf */
+ if (type == CLOSURE_BSDF_REFRACTION_ID) {
+ bsdf->alpha_x = 0.0f;
+ bsdf->alpha_y = 0.0f;
+ bsdf->ior = eta;
+
+ sd->flag |= bsdf_refraction_setup(bsdf);
+ }
+ else {
+ float roughness = sqr(param1);
+ bsdf->alpha_x = roughness;
+ bsdf->alpha_y = roughness;
+ bsdf->ior = eta;
+
+ if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID)
+ sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
+ else
+ sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
+ }
+ }
+
+ break;
+ }
+ case CLOSURE_BSDF_SHARP_GLASS_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: {
+#ifdef __CAUSTICS_TRICKS__
+ if (!kernel_data.integrator.caustics_reflective &&
+ !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) {
+ break;
+ }
+#endif
+ float3 weight = sd->svm_closure_weight * mix_weight;
+
+ /* index of refraction */
+ float eta = fmaxf(param2, 1e-5f);
+ eta = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
+
+ /* fresnel */
+ float cosNO = dot(N, sd->I);
+ float fresnel = fresnel_dielectric_cos(cosNO, eta);
+ float roughness = sqr(param1);
+
+ /* reflection */
+#ifdef __CAUSTICS_TRICKS__
+ if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0)
+#endif
+ {
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
+ sd, sizeof(MicrofacetBsdf), weight * fresnel);
+
+ if (bsdf) {
+ bsdf->N = N;
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra = NULL;
+ svm_node_glass_setup(sd, bsdf, type, eta, roughness, false);
+ }
+ }
+
+ /* refraction */
+#ifdef __CAUSTICS_TRICKS__
+ if (kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0)
+#endif
+ {
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
+ sd, sizeof(MicrofacetBsdf), weight * (1.0f - fresnel));
+
+ if (bsdf) {
+ bsdf->N = N;
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra = NULL;
+ svm_node_glass_setup(sd, bsdf, type, eta, roughness, true);
+ }
+ }
+
+ break;
+ }
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: {
+#ifdef __CAUSTICS_TRICKS__
+ if (!kernel_data.integrator.caustics_reflective &&
+ !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
+ break;
+#endif
+ float3 weight = sd->svm_closure_weight * mix_weight;
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
+ sd, sizeof(MicrofacetBsdf), weight);
+ if (!bsdf) {
+ break;
+ }
+
+ ccl_private MicrofacetExtra *extra = (ccl_private MicrofacetExtra *)closure_alloc_extra(
+ sd, sizeof(MicrofacetExtra));
+ if (!extra) {
+ break;
+ }
+
+ bsdf->N = N;
+ bsdf->extra = extra;
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
+
+ float roughness = sqr(param1);
+ bsdf->alpha_x = roughness;
+ bsdf->alpha_y = roughness;
+ float eta = fmaxf(param2, 1e-5f);
+ bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
+
+ kernel_assert(stack_valid(data_node.z));
+ bsdf->extra->color = stack_load_float3(stack, data_node.z);
+ bsdf->extra->cspec0 = make_float3(0.0f, 0.0f, 0.0f);
+ bsdf->extra->clearcoat = 0.0f;
+
+ /* setup bsdf */
+ sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(bsdf);
+ break;
+ }
+ case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: {
+ float3 weight = sd->svm_closure_weight * mix_weight;
+ ccl_private VelvetBsdf *bsdf = (ccl_private VelvetBsdf *)bsdf_alloc(
+ sd, sizeof(VelvetBsdf), weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+
+ bsdf->sigma = saturatef(param1);
+ sd->flag |= bsdf_ashikhmin_velvet_setup(bsdf);
+ }
+ break;
+ }
+ case CLOSURE_BSDF_GLOSSY_TOON_ID:
+#ifdef __CAUSTICS_TRICKS__
+ if (!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
+ break;
+ ATTR_FALLTHROUGH;
+#endif
+ case CLOSURE_BSDF_DIFFUSE_TOON_ID: {
+ float3 weight = sd->svm_closure_weight * mix_weight;
+ ccl_private ToonBsdf *bsdf = (ccl_private ToonBsdf *)bsdf_alloc(
+ sd, sizeof(ToonBsdf), weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+ bsdf->size = param1;
+ bsdf->smooth = param2;
+
+ if (type == CLOSURE_BSDF_DIFFUSE_TOON_ID)
+ sd->flag |= bsdf_diffuse_toon_setup(bsdf);
+ else
+ sd->flag |= bsdf_glossy_toon_setup(bsdf);
+ }
+ break;
+ }
+#ifdef __HAIR__
+ case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: {
+ uint4 data_node2 = read_node(kg, &offset);
+ uint4 data_node3 = read_node(kg, &offset);
+ uint4 data_node4 = read_node(kg, &offset);
+
+ float3 weight = sd->svm_closure_weight * mix_weight;
+
+ uint offset_ofs, ior_ofs, color_ofs, parametrization;
+ svm_unpack_node_uchar4(data_node.y, &offset_ofs, &ior_ofs, &color_ofs, &parametrization);
+ float alpha = stack_load_float_default(stack, offset_ofs, data_node.z);
+ float ior = stack_load_float_default(stack, ior_ofs, data_node.w);
+
+ uint coat_ofs, melanin_ofs, melanin_redness_ofs, absorption_coefficient_ofs;
+ svm_unpack_node_uchar4(data_node2.x,
+ &coat_ofs,
+ &melanin_ofs,
+ &melanin_redness_ofs,
+ &absorption_coefficient_ofs);
+
+ uint tint_ofs, random_ofs, random_color_ofs, random_roughness_ofs;
+ svm_unpack_node_uchar4(
+ data_node3.x, &tint_ofs, &random_ofs, &random_color_ofs, &random_roughness_ofs);
+
+ const AttributeDescriptor attr_descr_random = find_attribute(kg, sd, data_node4.y);
+ float random = 0.0f;
+ if (attr_descr_random.offset != ATTR_STD_NOT_FOUND) {
+ random = primitive_surface_attribute_float(kg, sd, attr_descr_random, NULL, NULL);
+ }
+ else {
+ random = stack_load_float_default(stack, random_ofs, data_node3.y);
+ }
+
+ ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)bsdf_alloc(
+ sd, sizeof(PrincipledHairBSDF), weight);
+ if (bsdf) {
+ ccl_private PrincipledHairExtra *extra = (ccl_private PrincipledHairExtra *)
+ closure_alloc_extra(sd, sizeof(PrincipledHairExtra));
+
+ if (!extra)
+ break;
+
+ /* Random factors range: [-randomization/2, +randomization/2]. */
+ float random_roughness = stack_load_float_default(
+ stack, random_roughness_ofs, data_node3.w);
+ float factor_random_roughness = 1.0f + 2.0f * (random - 0.5f) * random_roughness;
+ float roughness = param1 * factor_random_roughness;
+ float radial_roughness = param2 * factor_random_roughness;
+
+ /* Remap Coat value to [0, 100]% of Roughness. */
+ float coat = stack_load_float_default(stack, coat_ofs, data_node2.y);
+ float m0_roughness = 1.0f - clamp(coat, 0.0f, 1.0f);
+
+ bsdf->N = N;
+ bsdf->v = roughness;
+ bsdf->s = radial_roughness;
+ bsdf->m0_roughness = m0_roughness;
+ bsdf->alpha = alpha;
+ bsdf->eta = ior;
+ bsdf->extra = extra;
+
+ switch (parametrization) {
+ case NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION: {
+ float3 absorption_coefficient = stack_load_float3(stack, absorption_coefficient_ofs);
+ bsdf->sigma = absorption_coefficient;
+ break;
+ }
+ case NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION: {
+ float melanin = stack_load_float_default(stack, melanin_ofs, data_node2.z);
+ float melanin_redness = stack_load_float_default(
+ stack, melanin_redness_ofs, data_node2.w);
+
+ /* Randomize melanin. */
+ float random_color = stack_load_float_default(stack, random_color_ofs, data_node3.z);
+ random_color = clamp(random_color, 0.0f, 1.0f);
+ float factor_random_color = 1.0f + 2.0f * (random - 0.5f) * random_color;
+ melanin *= factor_random_color;
+
+ /* Map melanin 0..inf from more perceptually linear 0..1. */
+ melanin = -logf(fmaxf(1.0f - melanin, 0.0001f));
+
+ /* Benedikt Bitterli's melanin ratio remapping. */
+ float eumelanin = melanin * (1.0f - melanin_redness);
+ float pheomelanin = melanin * melanin_redness;
+ float3 melanin_sigma = bsdf_principled_hair_sigma_from_concentration(eumelanin,
+ pheomelanin);
+
+ /* Optional tint. */
+ float3 tint = stack_load_float3(stack, tint_ofs);
+ float3 tint_sigma = bsdf_principled_hair_sigma_from_reflectance(tint,
+ radial_roughness);
+
+ bsdf->sigma = melanin_sigma + tint_sigma;
+ break;
+ }
+ case NODE_PRINCIPLED_HAIR_REFLECTANCE: {
+ float3 color = stack_load_float3(stack, color_ofs);
+ bsdf->sigma = bsdf_principled_hair_sigma_from_reflectance(color, radial_roughness);
+ break;
+ }
+ default: {
+ /* Fallback to brownish hair, same as defaults for melanin. */
+ kernel_assert(!"Invalid Principled Hair parametrization!");
+ bsdf->sigma = bsdf_principled_hair_sigma_from_concentration(0.0f, 0.8054375f);
+ break;
+ }
+ }
+
+ sd->flag |= bsdf_principled_hair_setup(sd, bsdf);
+ }
+ break;
+ }
+ case CLOSURE_BSDF_HAIR_REFLECTION_ID:
+ case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: {
+ float3 weight = sd->svm_closure_weight * mix_weight;
+
+ ccl_private HairBsdf *bsdf = (ccl_private HairBsdf *)bsdf_alloc(
+ sd, sizeof(HairBsdf), weight);
+
+ if (bsdf) {
+ bsdf->N = N;
+ bsdf->roughness1 = param1;
+ bsdf->roughness2 = param2;
+ bsdf->offset = -stack_load_float(stack, data_node.z);
+
+ if (stack_valid(data_node.y)) {
+ bsdf->T = normalize(stack_load_float3(stack, data_node.y));
+ }
+ else if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
+ bsdf->T = normalize(sd->dPdv);
+ bsdf->offset = 0.0f;
+ }
+ else
+ bsdf->T = normalize(sd->dPdu);
+
+ if (type == CLOSURE_BSDF_HAIR_REFLECTION_ID) {
+ sd->flag |= bsdf_hair_reflection_setup(bsdf);
+ }
+ else {
+ sd->flag |= bsdf_hair_transmission_setup(bsdf);
+ }
+ }
+
+ break;
+ }
+#endif /* __HAIR__ */
+
+#ifdef __SUBSURFACE__
+ case CLOSURE_BSSRDF_BURLEY_ID:
+ case CLOSURE_BSSRDF_RANDOM_WALK_ID:
+ case CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID: {
+ float3 weight = sd->svm_closure_weight * mix_weight;
+ ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd, weight);
+
+ if (bssrdf) {
+ /* disable in case of diffuse ancestor, can't see it well then and
+ * adds considerably noise due to probabilities of continuing path
+ * getting lower and lower */
+ if (path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
+ param1 = 0.0f;
+
+ bssrdf->radius = stack_load_float3(stack, data_node.z) * param1;
+ bssrdf->albedo = sd->svm_closure_weight;
+ bssrdf->N = N;
+ bssrdf->roughness = FLT_MAX;
+
+ const float subsurface_ior = clamp(param2, 1.01f, 3.8f);
+ const float subsurface_anisotropy = stack_load_float(stack, data_node.w);
+ bssrdf->anisotropy = clamp(subsurface_anisotropy, 0.0f, 0.9f);
+
+ sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)type, subsurface_ior);
+ }
+
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+
+ return offset;
+}
+
+template<ShaderType shader_type>
+ccl_device_noinline void svm_node_closure_volume(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+#ifdef __VOLUME__
+ /* Only sum extinction for volumes, variable is shared with surface transparency. */
+ if (shader_type != SHADER_TYPE_VOLUME) {
+ return;
+ }
+
+ uint type, density_offset, anisotropy_offset;
+
+ uint mix_weight_offset;
+ svm_unpack_node_uchar4(node.y, &type, &density_offset, &anisotropy_offset, &mix_weight_offset);
+ float mix_weight = (stack_valid(mix_weight_offset) ? stack_load_float(stack, mix_weight_offset) :
+ 1.0f);
+
+ if (mix_weight == 0.0f) {
+ return;
+ }
+
+ float density = (stack_valid(density_offset)) ? stack_load_float(stack, density_offset) :
+ __uint_as_float(node.z);
+ density = mix_weight * fmaxf(density, 0.0f);
+
+ /* Compute scattering coefficient. */
+ float3 weight = sd->svm_closure_weight;
+
+ if (type == CLOSURE_VOLUME_ABSORPTION_ID) {
+ weight = make_float3(1.0f, 1.0f, 1.0f) - weight;
+ }
+
+ weight *= density;
+
+ /* Add closure for volume scattering. */
+ if (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) {
+ ccl_private HenyeyGreensteinVolume *volume = (ccl_private HenyeyGreensteinVolume *)bsdf_alloc(
+ sd, sizeof(HenyeyGreensteinVolume), weight);
+
+ if (volume) {
+ float anisotropy = (stack_valid(anisotropy_offset)) ?
+ stack_load_float(stack, anisotropy_offset) :
+ __uint_as_float(node.w);
+ volume->g = anisotropy; /* g */
+ sd->flag |= volume_henyey_greenstein_setup(volume);
+ }
+ }
+
+ /* Sum total extinction weight. */
+ volume_extinction_setup(sd, weight);
+#endif
+}
+
+template<ShaderType shader_type>
+ccl_device_noinline int svm_node_principled_volume(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node,
+ uint32_t path_flag,
+ int offset)
+{
+#ifdef __VOLUME__
+ uint4 value_node = read_node(kg, &offset);
+ uint4 attr_node = read_node(kg, &offset);
+
+ /* Only sum extinction for volumes, variable is shared with surface transparency. */
+ if (shader_type != SHADER_TYPE_VOLUME) {
+ return offset;
+ }
+
+ uint density_offset, anisotropy_offset, absorption_color_offset, mix_weight_offset;
+ svm_unpack_node_uchar4(
+ node.y, &density_offset, &anisotropy_offset, &absorption_color_offset, &mix_weight_offset);
+ float mix_weight = (stack_valid(mix_weight_offset) ? stack_load_float(stack, mix_weight_offset) :
+ 1.0f);
+
+ if (mix_weight == 0.0f) {
+ return offset;
+ }
+
+ /* Compute density. */
+ float primitive_density = 1.0f;
+ float density = (stack_valid(density_offset)) ? stack_load_float(stack, density_offset) :
+ __uint_as_float(value_node.x);
+ density = mix_weight * fmaxf(density, 0.0f);
+
+ if (density > CLOSURE_WEIGHT_CUTOFF) {
+ /* Density and color attribute lookup if available. */
+ const AttributeDescriptor attr_density = find_attribute(kg, sd, attr_node.x);
+ if (attr_density.offset != ATTR_STD_NOT_FOUND) {
+ primitive_density = primitive_volume_attribute_float(kg, sd, attr_density);
+ density = fmaxf(density * primitive_density, 0.0f);
+ }
+ }
+
+ if (density > CLOSURE_WEIGHT_CUTOFF) {
+ /* Compute scattering color. */
+ float3 color = sd->svm_closure_weight;
+
+ const AttributeDescriptor attr_color = find_attribute(kg, sd, attr_node.y);
+ if (attr_color.offset != ATTR_STD_NOT_FOUND) {
+ color *= primitive_volume_attribute_float3(kg, sd, attr_color);
+ }
+
+ /* Add closure for volume scattering. */
+ ccl_private HenyeyGreensteinVolume *volume = (ccl_private HenyeyGreensteinVolume *)bsdf_alloc(
+ sd, sizeof(HenyeyGreensteinVolume), color * density);
+ if (volume) {
+ float anisotropy = (stack_valid(anisotropy_offset)) ?
+ stack_load_float(stack, anisotropy_offset) :
+ __uint_as_float(value_node.y);
+ volume->g = anisotropy;
+ sd->flag |= volume_henyey_greenstein_setup(volume);
+ }
+
+ /* Add extinction weight. */
+ float3 zero = make_float3(0.0f, 0.0f, 0.0f);
+ float3 one = make_float3(1.0f, 1.0f, 1.0f);
+ float3 absorption_color = max(sqrt(stack_load_float3(stack, absorption_color_offset)), zero);
+ float3 absorption = max(one - color, zero) * max(one - absorption_color, zero);
+ volume_extinction_setup(sd, (color + absorption) * density);
+ }
+
+ /* Compute emission. */
+ if (path_flag & PATH_RAY_SHADOW) {
+ /* Don't need emission for shadows. */
+ return offset;
+ }
+
+ uint emission_offset, emission_color_offset, blackbody_offset, temperature_offset;
+ svm_unpack_node_uchar4(
+ node.z, &emission_offset, &emission_color_offset, &blackbody_offset, &temperature_offset);
+ float emission = (stack_valid(emission_offset)) ? stack_load_float(stack, emission_offset) :
+ __uint_as_float(value_node.z);
+ float blackbody = (stack_valid(blackbody_offset)) ? stack_load_float(stack, blackbody_offset) :
+ __uint_as_float(value_node.w);
+
+ if (emission > CLOSURE_WEIGHT_CUTOFF) {
+ float3 emission_color = stack_load_float3(stack, emission_color_offset);
+ emission_setup(sd, emission * emission_color);
+ }
+
+ if (blackbody > CLOSURE_WEIGHT_CUTOFF) {
+ float T = stack_load_float(stack, temperature_offset);
+
+ /* Add flame temperature from attribute if available. */
+ const AttributeDescriptor attr_temperature = find_attribute(kg, sd, attr_node.z);
+ if (attr_temperature.offset != ATTR_STD_NOT_FOUND) {
+ float temperature = primitive_volume_attribute_float(kg, sd, attr_temperature);
+ T *= fmaxf(temperature, 0.0f);
+ }
+
+ T = fmaxf(T, 0.0f);
+
+ /* Stefan-Boltzmann law. */
+ float T4 = sqr(sqr(T));
+ float sigma = 5.670373e-8f * 1e-6f / M_PI_F;
+ float intensity = sigma * mix(1.0f, T4, blackbody);
+
+ if (intensity > CLOSURE_WEIGHT_CUTOFF) {
+ float3 blackbody_tint = stack_load_float3(stack, node.w);
+ float3 bb = blackbody_tint * intensity * svm_math_blackbody_color(T);
+ emission_setup(sd, bb);
+ }
+ }
+#endif
+ return offset;
+}
+
+ccl_device_noinline void svm_node_closure_emission(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint mix_weight_offset = node.y;
+ float3 weight = sd->svm_closure_weight;
+
+ if (stack_valid(mix_weight_offset)) {
+ float mix_weight = stack_load_float(stack, mix_weight_offset);
+
+ if (mix_weight == 0.0f)
+ return;
+
+ weight *= mix_weight;
+ }
+
+ emission_setup(sd, weight);
+}
+
+ccl_device_noinline void svm_node_closure_background(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint mix_weight_offset = node.y;
+ float3 weight = sd->svm_closure_weight;
+
+ if (stack_valid(mix_weight_offset)) {
+ float mix_weight = stack_load_float(stack, mix_weight_offset);
+
+ if (mix_weight == 0.0f)
+ return;
+
+ weight *= mix_weight;
+ }
+
+ background_setup(sd, weight);
+}
+
+ccl_device_noinline void svm_node_closure_holdout(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint mix_weight_offset = node.y;
+
+ if (stack_valid(mix_weight_offset)) {
+ float mix_weight = stack_load_float(stack, mix_weight_offset);
+
+ if (mix_weight == 0.0f)
+ return;
+
+ closure_alloc(
+ sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, sd->svm_closure_weight * mix_weight);
+ }
+ else
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, sd->svm_closure_weight);
+
+ sd->flag |= SD_HOLDOUT;
+}
+
+/* Closure Nodes */
+
+ccl_device_inline void svm_node_closure_store_weight(ccl_private ShaderData *sd, float3 weight)
+{
+ sd->svm_closure_weight = weight;
+}
+
+ccl_device void svm_node_closure_set_weight(ccl_private ShaderData *sd, uint r, uint g, uint b)
+{
+ float3 weight = make_float3(__uint_as_float(r), __uint_as_float(g), __uint_as_float(b));
+ svm_node_closure_store_weight(sd, weight);
+}
+
+ccl_device void svm_node_closure_weight(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint weight_offset)
+{
+ float3 weight = stack_load_float3(stack, weight_offset);
+ svm_node_closure_store_weight(sd, weight);
+}
+
+ccl_device_noinline void svm_node_emission_weight(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint color_offset = node.y;
+ uint strength_offset = node.z;
+
+ float strength = stack_load_float(stack, strength_offset);
+ float3 weight = stack_load_float3(stack, color_offset) * strength;
+
+ svm_node_closure_store_weight(sd, weight);
+}
+
+ccl_device_noinline void svm_node_mix_closure(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ /* fetch weight from blend input, previous mix closures,
+ * and write to stack to be used by closure nodes later */
+ uint weight_offset, in_weight_offset, weight1_offset, weight2_offset;
+ svm_unpack_node_uchar4(
+ node.y, &weight_offset, &in_weight_offset, &weight1_offset, &weight2_offset);
+
+ float weight = stack_load_float(stack, weight_offset);
+ weight = saturatef(weight);
+
+ float in_weight = (stack_valid(in_weight_offset)) ? stack_load_float(stack, in_weight_offset) :
+ 1.0f;
+
+ if (stack_valid(weight1_offset))
+ stack_store_float(stack, weight1_offset, in_weight * (1.0f - weight));
+ if (stack_valid(weight2_offset))
+ stack_store_float(stack, weight2_offset, in_weight * weight);
+}
+
+/* (Bump) normal */
+
+ccl_device void svm_node_set_normal(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint in_direction,
+ uint out_normal)
+{
+ float3 normal = stack_load_float3(stack, in_direction);
+ sd->N = normal;
+ stack_store_float3(stack, out_normal, normal);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/color_util.h b/intern/cycles/kernel/svm/color_util.h
new file mode 100644
index 00000000000..0c1a510e655
--- /dev/null
+++ b/intern/cycles/kernel/svm/color_util.h
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device float3 svm_mix_blend(float t, float3 col1, float3 col2)
+{
+ return interp(col1, col2, t);
+}
+
+ccl_device float3 svm_mix_add(float t, float3 col1, float3 col2)
+{
+ return interp(col1, col1 + col2, t);
+}
+
+ccl_device float3 svm_mix_mul(float t, float3 col1, float3 col2)
+{
+ return interp(col1, col1 * col2, t);
+}
+
+ccl_device float3 svm_mix_screen(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+ float3 one = make_float3(1.0f, 1.0f, 1.0f);
+ float3 tm3 = make_float3(tm, tm, tm);
+
+ return one - (tm3 + t * (one - col2)) * (one - col1);
+}
+
+ccl_device float3 svm_mix_overlay(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ if (outcol.x < 0.5f)
+ outcol.x *= tm + 2.0f * t * col2.x;
+ else
+ outcol.x = 1.0f - (tm + 2.0f * t * (1.0f - col2.x)) * (1.0f - outcol.x);
+
+ if (outcol.y < 0.5f)
+ outcol.y *= tm + 2.0f * t * col2.y;
+ else
+ outcol.y = 1.0f - (tm + 2.0f * t * (1.0f - col2.y)) * (1.0f - outcol.y);
+
+ if (outcol.z < 0.5f)
+ outcol.z *= tm + 2.0f * t * col2.z;
+ else
+ outcol.z = 1.0f - (tm + 2.0f * t * (1.0f - col2.z)) * (1.0f - outcol.z);
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_sub(float t, float3 col1, float3 col2)
+{
+ return interp(col1, col1 - col2, t);
+}
+
+ccl_device float3 svm_mix_div(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ if (col2.x != 0.0f)
+ outcol.x = tm * outcol.x + t * outcol.x / col2.x;
+ if (col2.y != 0.0f)
+ outcol.y = tm * outcol.y + t * outcol.y / col2.y;
+ if (col2.z != 0.0f)
+ outcol.z = tm * outcol.z + t * outcol.z / col2.z;
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2)
+{
+ return interp(col1, fabs(col1 - col2), t);
+}
+
+ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2)
+{
+ return interp(col1, min(col1, col2), t);
+}
+
+ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2)
+{
+ return interp(col1, max(col1, col2), t);
+}
+
+ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2)
+{
+ float3 outcol = col1;
+
+ if (outcol.x != 0.0f) {
+ float tmp = 1.0f - t * col2.x;
+ if (tmp <= 0.0f)
+ outcol.x = 1.0f;
+ else if ((tmp = outcol.x / tmp) > 1.0f)
+ outcol.x = 1.0f;
+ else
+ outcol.x = tmp;
+ }
+ if (outcol.y != 0.0f) {
+ float tmp = 1.0f - t * col2.y;
+ if (tmp <= 0.0f)
+ outcol.y = 1.0f;
+ else if ((tmp = outcol.y / tmp) > 1.0f)
+ outcol.y = 1.0f;
+ else
+ outcol.y = tmp;
+ }
+ if (outcol.z != 0.0f) {
+ float tmp = 1.0f - t * col2.z;
+ if (tmp <= 0.0f)
+ outcol.z = 1.0f;
+ else if ((tmp = outcol.z / tmp) > 1.0f)
+ outcol.z = 1.0f;
+ else
+ outcol.z = tmp;
+ }
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_burn(float t, float3 col1, float3 col2)
+{
+ float tmp, tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ tmp = tm + t * col2.x;
+ if (tmp <= 0.0f)
+ outcol.x = 0.0f;
+ else if ((tmp = (1.0f - (1.0f - outcol.x) / tmp)) < 0.0f)
+ outcol.x = 0.0f;
+ else if (tmp > 1.0f)
+ outcol.x = 1.0f;
+ else
+ outcol.x = tmp;
+
+ tmp = tm + t * col2.y;
+ if (tmp <= 0.0f)
+ outcol.y = 0.0f;
+ else if ((tmp = (1.0f - (1.0f - outcol.y) / tmp)) < 0.0f)
+ outcol.y = 0.0f;
+ else if (tmp > 1.0f)
+ outcol.y = 1.0f;
+ else
+ outcol.y = tmp;
+
+ tmp = tm + t * col2.z;
+ if (tmp <= 0.0f)
+ outcol.z = 0.0f;
+ else if ((tmp = (1.0f - (1.0f - outcol.z) / tmp)) < 0.0f)
+ outcol.z = 0.0f;
+ else if (tmp > 1.0f)
+ outcol.z = 1.0f;
+ else
+ outcol.z = tmp;
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_hue(float t, float3 col1, float3 col2)
+{
+ float3 outcol = col1;
+
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ if (hsv2.y != 0.0f) {
+ float3 hsv = rgb_to_hsv(outcol);
+ hsv.x = hsv2.x;
+ float3 tmp = hsv_to_rgb(hsv);
+
+ outcol = interp(outcol, tmp, t);
+ }
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_sat(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ float3 hsv = rgb_to_hsv(outcol);
+
+ if (hsv.y != 0.0f) {
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ hsv.y = tm * hsv.y + t * hsv2.y;
+ outcol = hsv_to_rgb(hsv);
+ }
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_val(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 hsv = rgb_to_hsv(col1);
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ hsv.z = tm * hsv.z + t * hsv2.z;
+
+ return hsv_to_rgb(hsv);
+}
+
+ccl_device float3 svm_mix_color(float t, float3 col1, float3 col2)
+{
+ float3 outcol = col1;
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ if (hsv2.y != 0.0f) {
+ float3 hsv = rgb_to_hsv(outcol);
+ hsv.x = hsv2.x;
+ hsv.y = hsv2.y;
+ float3 tmp = hsv_to_rgb(hsv);
+
+ outcol = interp(outcol, tmp, t);
+ }
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_soft(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 one = make_float3(1.0f, 1.0f, 1.0f);
+ float3 scr = one - (one - col2) * (one - col1);
+
+ return tm * col1 + t * ((one - col1) * col2 * col1 + col1 * scr);
+}
+
+ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2)
+{
+ return col1 + t * (2.0f * col2 + make_float3(-1.0f, -1.0f, -1.0f));
+}
+
+ccl_device float3 svm_mix_clamp(float3 col)
+{
+ return saturate3(col);
+}
+
+ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
+{
+ float t = saturatef(fac);
+
+ switch (type) {
+ case NODE_MIX_BLEND:
+ return svm_mix_blend(t, c1, c2);
+ case NODE_MIX_ADD:
+ return svm_mix_add(t, c1, c2);
+ case NODE_MIX_MUL:
+ return svm_mix_mul(t, c1, c2);
+ case NODE_MIX_SCREEN:
+ return svm_mix_screen(t, c1, c2);
+ case NODE_MIX_OVERLAY:
+ return svm_mix_overlay(t, c1, c2);
+ case NODE_MIX_SUB:
+ return svm_mix_sub(t, c1, c2);
+ case NODE_MIX_DIV:
+ return svm_mix_div(t, c1, c2);
+ case NODE_MIX_DIFF:
+ return svm_mix_diff(t, c1, c2);
+ case NODE_MIX_DARK:
+ return svm_mix_dark(t, c1, c2);
+ case NODE_MIX_LIGHT:
+ return svm_mix_light(t, c1, c2);
+ case NODE_MIX_DODGE:
+ return svm_mix_dodge(t, c1, c2);
+ case NODE_MIX_BURN:
+ return svm_mix_burn(t, c1, c2);
+ case NODE_MIX_HUE:
+ return svm_mix_hue(t, c1, c2);
+ case NODE_MIX_SAT:
+ return svm_mix_sat(t, c1, c2);
+ case NODE_MIX_VAL:
+ return svm_mix_val(t, c1, c2);
+ case NODE_MIX_COLOR:
+ return svm_mix_color(t, c1, c2);
+ case NODE_MIX_SOFT:
+ return svm_mix_soft(t, c1, c2);
+ case NODE_MIX_LINEAR:
+ return svm_mix_linear(t, c1, c2);
+ case NODE_MIX_CLAMP:
+ return svm_mix_clamp(c1);
+ }
+
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness, float contrast)
+{
+ float a = 1.0f + contrast;
+ float b = brightness - contrast * 0.5f;
+
+ color.x = max(a * color.x + b, 0.0f);
+ color.y = max(a * color.y + b, 0.0f);
+ color.z = max(a * color.z + b, 0.0f);
+
+ return color;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/convert.h b/intern/cycles/kernel/svm/convert.h
new file mode 100644
index 00000000000..427ffd97f59
--- /dev/null
+++ b/intern/cycles/kernel/svm/convert.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Conversion Nodes */
+
+ccl_device_noinline void svm_node_convert(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint from,
+ uint to)
+{
+ switch (type) {
+ case NODE_CONVERT_FI: {
+ float f = stack_load_float(stack, from);
+ stack_store_int(stack, to, float_to_int(f));
+ break;
+ }
+ case NODE_CONVERT_FV: {
+ float f = stack_load_float(stack, from);
+ stack_store_float3(stack, to, make_float3(f, f, f));
+ break;
+ }
+ case NODE_CONVERT_CF: {
+ float3 f = stack_load_float3(stack, from);
+ float g = linear_rgb_to_gray(kg, f);
+ stack_store_float(stack, to, g);
+ break;
+ }
+ case NODE_CONVERT_CI: {
+ float3 f = stack_load_float3(stack, from);
+ int i = (int)linear_rgb_to_gray(kg, f);
+ stack_store_int(stack, to, i);
+ break;
+ }
+ case NODE_CONVERT_VF: {
+ float3 f = stack_load_float3(stack, from);
+ float g = average(f);
+ stack_store_float(stack, to, g);
+ break;
+ }
+ case NODE_CONVERT_VI: {
+ float3 f = stack_load_float3(stack, from);
+ int i = (int)average(f);
+ stack_store_int(stack, to, i);
+ break;
+ }
+ case NODE_CONVERT_IF: {
+ float f = (float)stack_load_int(stack, from);
+ stack_store_float(stack, to, f);
+ break;
+ }
+ case NODE_CONVERT_IV: {
+ float f = (float)stack_load_int(stack, from);
+ stack_store_float3(stack, to, make_float3(f, f, f));
+ break;
+ }
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/displace.h b/intern/cycles/kernel/svm/displace.h
new file mode 100644
index 00000000000..cea1436f36d
--- /dev/null
+++ b/intern/cycles/kernel/svm/displace.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/sample/mapping.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Bump Node */
+
+ccl_device_noinline void svm_node_set_bump(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+#ifdef __RAY_DIFFERENTIALS__
+ /* get normal input */
+ uint normal_offset, scale_offset, invert, use_object_space;
+ svm_unpack_node_uchar4(node.y, &normal_offset, &scale_offset, &invert, &use_object_space);
+
+ float3 normal_in = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N;
+
+ float3 dPdx = sd->dP.dx;
+ float3 dPdy = sd->dP.dy;
+
+ if (use_object_space) {
+ object_inverse_normal_transform(kg, sd, &normal_in);
+ object_inverse_dir_transform(kg, sd, &dPdx);
+ object_inverse_dir_transform(kg, sd, &dPdy);
+ }
+
+ /* get surface tangents from normal */
+ float3 Rx = cross(dPdy, normal_in);
+ float3 Ry = cross(normal_in, dPdx);
+
+ /* get bump values */
+ uint c_offset, x_offset, y_offset, strength_offset;
+ svm_unpack_node_uchar4(node.z, &c_offset, &x_offset, &y_offset, &strength_offset);
+
+ float h_c = stack_load_float(stack, c_offset);
+ float h_x = stack_load_float(stack, x_offset);
+ float h_y = stack_load_float(stack, y_offset);
+
+ /* compute surface gradient and determinant */
+ float det = dot(dPdx, Rx);
+ float3 surfgrad = (h_x - h_c) * Rx + (h_y - h_c) * Ry;
+
+ float absdet = fabsf(det);
+
+ float strength = stack_load_float(stack, strength_offset);
+ float scale = stack_load_float(stack, scale_offset);
+
+ if (invert)
+ scale *= -1.0f;
+
+ strength = max(strength, 0.0f);
+
+ /* compute and output perturbed normal */
+ float3 normal_out = safe_normalize(absdet * normal_in - scale * signf(det) * surfgrad);
+ if (is_zero(normal_out)) {
+ normal_out = normal_in;
+ }
+ else {
+ normal_out = normalize(strength * normal_out + (1.0f - strength) * normal_in);
+ }
+
+ if (use_object_space) {
+ object_normal_transform(kg, sd, &normal_out);
+ }
+
+ normal_out = ensure_valid_reflection(sd->Ng, sd->I, normal_out);
+
+ stack_store_float3(stack, node.w, normal_out);
+#endif
+}
+
+/* Displacement Node */
+
+ccl_device void svm_node_set_displacement(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint fac_offset)
+{
+ float3 dP = stack_load_float3(stack, fac_offset);
+ sd->P += dP;
+}
+
+ccl_device_noinline void svm_node_displacement(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint height_offset, midlevel_offset, scale_offset, normal_offset;
+ svm_unpack_node_uchar4(node.y, &height_offset, &midlevel_offset, &scale_offset, &normal_offset);
+
+ float height = stack_load_float(stack, height_offset);
+ float midlevel = stack_load_float(stack, midlevel_offset);
+ float scale = stack_load_float(stack, scale_offset);
+ float3 normal = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N;
+ uint space = node.w;
+
+ float3 dP = normal;
+
+ if (space == NODE_NORMAL_MAP_OBJECT) {
+ /* Object space. */
+ object_inverse_normal_transform(kg, sd, &dP);
+ dP *= (height - midlevel) * scale;
+ object_dir_transform(kg, sd, &dP);
+ }
+ else {
+ /* World space. */
+ dP *= (height - midlevel) * scale;
+ }
+
+ stack_store_float3(stack, node.z, dP);
+}
+
+ccl_device_noinline int svm_node_vector_displacement(
+ KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
+{
+ uint4 data_node = read_node(kg, &offset);
+ uint space = data_node.x;
+
+ uint vector_offset, midlevel_offset, scale_offset, displacement_offset;
+ svm_unpack_node_uchar4(
+ node.y, &vector_offset, &midlevel_offset, &scale_offset, &displacement_offset);
+
+ float3 vector = stack_load_float3(stack, vector_offset);
+ float midlevel = stack_load_float(stack, midlevel_offset);
+ float scale = stack_load_float(stack, scale_offset);
+ float3 dP = (vector - make_float3(midlevel, midlevel, midlevel)) * scale;
+
+ if (space == NODE_NORMAL_MAP_TANGENT) {
+ /* Tangent space. */
+ float3 normal = sd->N;
+ object_inverse_normal_transform(kg, sd, &normal);
+
+ const AttributeDescriptor attr = find_attribute(kg, sd, node.z);
+ float3 tangent;
+ if (attr.offset != ATTR_STD_NOT_FOUND) {
+ tangent = primitive_surface_attribute_float3(kg, sd, attr, NULL, NULL);
+ }
+ else {
+ tangent = normalize(sd->dPdu);
+ }
+
+ float3 bitangent = normalize(cross(normal, tangent));
+ const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.w);
+ if (attr_sign.offset != ATTR_STD_NOT_FOUND) {
+ float sign = primitive_surface_attribute_float(kg, sd, attr_sign, NULL, NULL);
+ bitangent *= sign;
+ }
+
+ dP = tangent * dP.x + normal * dP.y + bitangent * dP.z;
+ }
+
+ if (space != NODE_NORMAL_MAP_WORLD) {
+ /* Tangent or object space. */
+ object_dir_transform(kg, sd, &dP);
+ }
+
+ stack_store_float3(stack, displacement_offset, dP);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/fractal_noise.h b/intern/cycles/kernel/svm/fractal_noise.h
new file mode 100644
index 00000000000..b955d626dde
--- /dev/null
+++ b/intern/cycles/kernel/svm/fractal_noise.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/svm/noise.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
+ccl_device_noinline float fractal_noise_1d(float p, float octaves, float roughness)
+{
+ float fscale = 1.0f;
+ float amp = 1.0f;
+ float maxamp = 0.0f;
+ float sum = 0.0f;
+ octaves = clamp(octaves, 0.0f, 16.0f);
+ int n = float_to_int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise_1d(fscale * p);
+ sum += t * amp;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0f, 1.0f);
+ fscale *= 2.0f;
+ }
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float t = noise_1d(fscale * p);
+ float sum2 = sum + t * amp;
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
+ return (1.0f - rmd) * sum + rmd * sum2;
+ }
+ else {
+ return sum / maxamp;
+ }
+}
+
+/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
+ccl_device_noinline float fractal_noise_2d(float2 p, float octaves, float roughness)
+{
+ float fscale = 1.0f;
+ float amp = 1.0f;
+ float maxamp = 0.0f;
+ float sum = 0.0f;
+ octaves = clamp(octaves, 0.0f, 16.0f);
+ int n = float_to_int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise_2d(fscale * p);
+ sum += t * amp;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0f, 1.0f);
+ fscale *= 2.0f;
+ }
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float t = noise_2d(fscale * p);
+ float sum2 = sum + t * amp;
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
+ return (1.0f - rmd) * sum + rmd * sum2;
+ }
+ else {
+ return sum / maxamp;
+ }
+}
+
+/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
+ccl_device_noinline float fractal_noise_3d(float3 p, float octaves, float roughness)
+{
+ float fscale = 1.0f;
+ float amp = 1.0f;
+ float maxamp = 0.0f;
+ float sum = 0.0f;
+ octaves = clamp(octaves, 0.0f, 16.0f);
+ int n = float_to_int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise_3d(fscale * p);
+ sum += t * amp;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0f, 1.0f);
+ fscale *= 2.0f;
+ }
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float t = noise_3d(fscale * p);
+ float sum2 = sum + t * amp;
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
+ return (1.0f - rmd) * sum + rmd * sum2;
+ }
+ else {
+ return sum / maxamp;
+ }
+}
+
+/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
+ccl_device_noinline float fractal_noise_4d(float4 p, float octaves, float roughness)
+{
+ float fscale = 1.0f;
+ float amp = 1.0f;
+ float maxamp = 0.0f;
+ float sum = 0.0f;
+ octaves = clamp(octaves, 0.0f, 16.0f);
+ int n = float_to_int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise_4d(fscale * p);
+ sum += t * amp;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0f, 1.0f);
+ fscale *= 2.0f;
+ }
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float t = noise_4d(fscale * p);
+ float sum2 = sum + t * amp;
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
+ return (1.0f - rmd) * sum + rmd * sum2;
+ }
+ else {
+ return sum / maxamp;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/fresnel.h b/intern/cycles/kernel/svm/fresnel.h
new file mode 100644
index 00000000000..9dd68c3e38f
--- /dev/null
+++ b/intern/cycles/kernel/svm/fresnel.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Fresnel Node */
+
+ccl_device_noinline void svm_node_fresnel(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint ior_offset,
+ uint ior_value,
+ uint node)
+{
+ uint normal_offset, out_offset;
+ svm_unpack_node_uchar2(node, &normal_offset, &out_offset);
+ float eta = (stack_valid(ior_offset)) ? stack_load_float(stack, ior_offset) :
+ __uint_as_float(ior_value);
+ float3 normal_in = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N;
+
+ eta = fmaxf(eta, 1e-5f);
+ eta = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
+
+ float f = fresnel_dielectric_cos(dot(sd->I, normal_in), eta);
+
+ stack_store_float(stack, out_offset, f);
+}
+
+/* Layer Weight Node */
+
+ccl_device_noinline void svm_node_layer_weight(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint blend_offset = node.y;
+ uint blend_value = node.z;
+
+ uint type, normal_offset, out_offset;
+ svm_unpack_node_uchar3(node.w, &type, &normal_offset, &out_offset);
+
+ float blend = (stack_valid(blend_offset)) ? stack_load_float(stack, blend_offset) :
+ __uint_as_float(blend_value);
+ float3 normal_in = (stack_valid(normal_offset)) ? stack_load_float3(stack, normal_offset) :
+ sd->N;
+
+ float f;
+
+ if (type == NODE_LAYER_WEIGHT_FRESNEL) {
+ float eta = fmaxf(1.0f - blend, 1e-5f);
+ eta = (sd->flag & SD_BACKFACING) ? eta : 1.0f / eta;
+
+ f = fresnel_dielectric_cos(dot(sd->I, normal_in), eta);
+ }
+ else {
+ f = fabsf(dot(sd->I, normal_in));
+
+ if (blend != 0.5f) {
+ blend = clamp(blend, 0.0f, 1.0f - 1e-5f);
+ blend = (blend < 0.5f) ? 2.0f * blend : 0.5f / (1.0f - blend);
+
+ f = powf(f, blend);
+ }
+
+ f = 1.0f - f;
+ }
+
+ stack_store_float(stack, out_offset, f);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/gamma.h b/intern/cycles/kernel/svm/gamma.h
new file mode 100644
index 00000000000..9f89e780be9
--- /dev/null
+++ b/intern/cycles/kernel/svm/gamma.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline void svm_node_gamma(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint in_gamma,
+ uint in_color,
+ uint out_color)
+{
+ float3 color = stack_load_float3(stack, in_color);
+ float gamma = stack_load_float(stack, in_gamma);
+
+ color = svm_math_gamma_color(color, gamma);
+
+ if (stack_valid(out_color))
+ stack_store_float3(stack, out_color, color);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/geometry.h b/intern/cycles/kernel/svm/geometry.h
new file mode 100644
index 00000000000..772942e0c08
--- /dev/null
+++ b/intern/cycles/kernel/svm/geometry.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Geometry Node */
+
+ccl_device_noinline void svm_node_geometry(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint out_offset)
+{
+ float3 data;
+
+ switch (type) {
+ case NODE_GEOM_P:
+ data = sd->P;
+ break;
+ case NODE_GEOM_N:
+ data = sd->N;
+ break;
+#ifdef __DPDU__
+ case NODE_GEOM_T:
+ data = primitive_tangent(kg, sd);
+ break;
+#endif
+ case NODE_GEOM_I:
+ data = sd->I;
+ break;
+ case NODE_GEOM_Ng:
+ data = sd->Ng;
+ break;
+ case NODE_GEOM_uv:
+ data = make_float3(sd->u, sd->v, 0.0f);
+ break;
+ default:
+ data = make_float3(0.0f, 0.0f, 0.0f);
+ }
+
+ stack_store_float3(stack, out_offset, data);
+}
+
+ccl_device_noinline void svm_node_geometry_bump_dx(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint out_offset)
+{
+#ifdef __RAY_DIFFERENTIALS__
+ float3 data;
+
+ switch (type) {
+ case NODE_GEOM_P:
+ data = sd->P + sd->dP.dx;
+ break;
+ case NODE_GEOM_uv:
+ data = make_float3(sd->u + sd->du.dx, sd->v + sd->dv.dx, 0.0f);
+ break;
+ default:
+ svm_node_geometry(kg, sd, stack, type, out_offset);
+ return;
+ }
+
+ stack_store_float3(stack, out_offset, data);
+#else
+ svm_node_geometry(kg, sd, stack, type, out_offset);
+#endif
+}
+
+ccl_device_noinline void svm_node_geometry_bump_dy(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint out_offset)
+{
+#ifdef __RAY_DIFFERENTIALS__
+ float3 data;
+
+ switch (type) {
+ case NODE_GEOM_P:
+ data = sd->P + sd->dP.dy;
+ break;
+ case NODE_GEOM_uv:
+ data = make_float3(sd->u + sd->du.dy, sd->v + sd->dv.dy, 0.0f);
+ break;
+ default:
+ svm_node_geometry(kg, sd, stack, type, out_offset);
+ return;
+ }
+
+ stack_store_float3(stack, out_offset, data);
+#else
+ svm_node_geometry(kg, sd, stack, type, out_offset);
+#endif
+}
+
+/* Object Info */
+
+ccl_device_noinline void svm_node_object_info(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint out_offset)
+{
+ float data;
+
+ switch (type) {
+ case NODE_INFO_OB_LOCATION: {
+ stack_store_float3(stack, out_offset, object_location(kg, sd));
+ return;
+ }
+ case NODE_INFO_OB_COLOR: {
+ stack_store_float3(stack, out_offset, object_color(kg, sd->object));
+ return;
+ }
+ case NODE_INFO_OB_INDEX:
+ data = object_pass_id(kg, sd->object);
+ break;
+ case NODE_INFO_MAT_INDEX:
+ data = shader_pass_id(kg, sd);
+ break;
+ case NODE_INFO_OB_RANDOM: {
+ if (sd->lamp != LAMP_NONE) {
+ data = lamp_random_number(kg, sd->lamp);
+ }
+ else {
+ data = object_random_number(kg, sd->object);
+ }
+ break;
+ }
+ default:
+ data = 0.0f;
+ break;
+ }
+
+ stack_store_float(stack, out_offset, data);
+}
+
+/* Particle Info */
+
+ccl_device_noinline void svm_node_particle_info(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint out_offset)
+{
+ switch (type) {
+ case NODE_INFO_PAR_INDEX: {
+ int particle_id = object_particle_id(kg, sd->object);
+ stack_store_float(stack, out_offset, particle_index(kg, particle_id));
+ break;
+ }
+ case NODE_INFO_PAR_RANDOM: {
+ int particle_id = object_particle_id(kg, sd->object);
+ float random = hash_uint2_to_float(particle_index(kg, particle_id), 0);
+ stack_store_float(stack, out_offset, random);
+ break;
+ }
+ case NODE_INFO_PAR_AGE: {
+ int particle_id = object_particle_id(kg, sd->object);
+ stack_store_float(stack, out_offset, particle_age(kg, particle_id));
+ break;
+ }
+ case NODE_INFO_PAR_LIFETIME: {
+ int particle_id = object_particle_id(kg, sd->object);
+ stack_store_float(stack, out_offset, particle_lifetime(kg, particle_id));
+ break;
+ }
+ case NODE_INFO_PAR_LOCATION: {
+ int particle_id = object_particle_id(kg, sd->object);
+ stack_store_float3(stack, out_offset, particle_location(kg, particle_id));
+ break;
+ }
+#if 0 /* XXX float4 currently not supported in SVM stack */
+ case NODE_INFO_PAR_ROTATION: {
+ int particle_id = object_particle_id(kg, sd->object);
+ stack_store_float4(stack, out_offset, particle_rotation(kg, particle_id));
+ break;
+ }
+#endif
+ case NODE_INFO_PAR_SIZE: {
+ int particle_id = object_particle_id(kg, sd->object);
+ stack_store_float(stack, out_offset, particle_size(kg, particle_id));
+ break;
+ }
+ case NODE_INFO_PAR_VELOCITY: {
+ int particle_id = object_particle_id(kg, sd->object);
+ stack_store_float3(stack, out_offset, particle_velocity(kg, particle_id));
+ break;
+ }
+ case NODE_INFO_PAR_ANGULAR_VELOCITY: {
+ int particle_id = object_particle_id(kg, sd->object);
+ stack_store_float3(stack, out_offset, particle_angular_velocity(kg, particle_id));
+ break;
+ }
+ }
+}
+
+#ifdef __HAIR__
+
+/* Hair Info */
+
+ccl_device_noinline void svm_node_hair_info(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint out_offset)
+{
+ float data;
+ float3 data3;
+
+ switch (type) {
+ case NODE_INFO_CURVE_IS_STRAND: {
+ data = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
+ stack_store_float(stack, out_offset, data);
+ break;
+ }
+ case NODE_INFO_CURVE_INTERCEPT:
+ break; /* handled as attribute */
+ case NODE_INFO_CURVE_LENGTH:
+ break; /* handled as attribute */
+ case NODE_INFO_CURVE_RANDOM:
+ break; /* handled as attribute */
+ case NODE_INFO_CURVE_THICKNESS: {
+ data = curve_thickness(kg, sd);
+ stack_store_float(stack, out_offset, data);
+ break;
+ }
+# if 0
+ case NODE_INFO_CURVE_FADE: {
+ data = sd->curve_transparency;
+ stack_store_float(stack, out_offset, data);
+ break;
+ }
+# endif
+ case NODE_INFO_CURVE_TANGENT_NORMAL: {
+ data3 = curve_tangent_normal(kg, sd);
+ stack_store_float3(stack, out_offset, data3);
+ break;
+ }
+ }
+}
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/gradient.h b/intern/cycles/kernel/svm/gradient.h
new file mode 100644
index 00000000000..42d8dbef792
--- /dev/null
+++ b/intern/cycles/kernel/svm/gradient.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Gradient */
+
+ccl_device float svm_gradient(float3 p, NodeGradientType type)
+{
+ float x, y, z;
+
+ x = p.x;
+ y = p.y;
+ z = p.z;
+
+ if (type == NODE_BLEND_LINEAR) {
+ return x;
+ }
+ else if (type == NODE_BLEND_QUADRATIC) {
+ float r = fmaxf(x, 0.0f);
+ return r * r;
+ }
+ else if (type == NODE_BLEND_EASING) {
+ float r = fminf(fmaxf(x, 0.0f), 1.0f);
+ float t = r * r;
+
+ return (3.0f * t - 2.0f * t * r);
+ }
+ else if (type == NODE_BLEND_DIAGONAL) {
+ return (x + y) * 0.5f;
+ }
+ else if (type == NODE_BLEND_RADIAL) {
+ return atan2f(y, x) / M_2PI_F + 0.5f;
+ }
+ else {
+ /* Bias a little bit for the case where p is a unit length vector,
+ * to get exactly zero instead of a small random value depending
+ * on float precision. */
+ float r = fmaxf(0.999999f - sqrtf(x * x + y * y + z * z), 0.0f);
+
+ if (type == NODE_BLEND_QUADRATIC_SPHERE)
+ return r * r;
+ else if (type == NODE_BLEND_SPHERICAL)
+ return r;
+ }
+
+ return 0.0f;
+}
+
+ccl_device_noinline void svm_node_tex_gradient(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint type, co_offset, color_offset, fac_offset;
+
+ svm_unpack_node_uchar4(node.y, &type, &co_offset, &fac_offset, &color_offset);
+
+ float3 co = stack_load_float3(stack, co_offset);
+
+ float f = svm_gradient(co, (NodeGradientType)type);
+ f = saturatef(f);
+
+ if (stack_valid(fac_offset))
+ stack_store_float(stack, fac_offset, f);
+ if (stack_valid(color_offset))
+ stack_store_float3(stack, color_offset, make_float3(f, f, f));
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/hsv.h b/intern/cycles/kernel/svm/hsv.h
new file mode 100644
index 00000000000..fdb266883fa
--- /dev/null
+++ b/intern/cycles/kernel/svm/hsv.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline void svm_node_hsv(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint in_color_offset, fac_offset, out_color_offset;
+ uint hue_offset, sat_offset, val_offset;
+ svm_unpack_node_uchar3(node.y, &in_color_offset, &fac_offset, &out_color_offset);
+ svm_unpack_node_uchar3(node.z, &hue_offset, &sat_offset, &val_offset);
+
+ float fac = stack_load_float(stack, fac_offset);
+ float3 in_color = stack_load_float3(stack, in_color_offset);
+ float3 color = in_color;
+
+ float hue = stack_load_float(stack, hue_offset);
+ float sat = stack_load_float(stack, sat_offset);
+ float val = stack_load_float(stack, val_offset);
+
+ color = rgb_to_hsv(color);
+
+ /* Remember: `fmodf` doesn't work for negative numbers here. */
+ color.x = fmodf(color.x + hue + 0.5f, 1.0f);
+ color.y = saturatef(color.y * sat);
+ color.z *= val;
+
+ color = hsv_to_rgb(color);
+
+ color.x = fac * color.x + (1.0f - fac) * in_color.x;
+ color.y = fac * color.y + (1.0f - fac) * in_color.y;
+ color.z = fac * color.z + (1.0f - fac) * in_color.z;
+
+ /* Clamp color to prevent negative values caused by over saturation. */
+ color.x = max(color.x, 0.0f);
+ color.y = max(color.y, 0.0f);
+ color.z = max(color.z, 0.0f);
+
+ if (stack_valid(out_color_offset))
+ stack_store_float3(stack, out_color_offset, color);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/ies.h b/intern/cycles/kernel/svm/ies.h
new file mode 100644
index 00000000000..f0923720878
--- /dev/null
+++ b/intern/cycles/kernel/svm/ies.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* IES Light */
+
+ccl_device_inline float interpolate_ies_vertical(
+ KernelGlobals kg, int ofs, int v, int v_num, float v_frac, int h)
+{
+ /* Since lookups are performed in spherical coordinates, clamping the coordinates at the low end
+ * of v (corresponding to the north pole) would result in artifacts. The proper way of dealing
+ * with this would be to lookup the corresponding value on the other side of the pole, but since
+ * the horizontal coordinates might be nonuniform, this would require yet another interpolation.
+ * Therefore, the assumption is made that the light is going to be symmetrical, which means that
+ * we can just take the corresponding value at the current horizontal coordinate. */
+
+#define IES_LOOKUP(v) kernel_tex_fetch(__ies, ofs + h * v_num + (v))
+ /* If v is zero, assume symmetry and read at v=1 instead of v=-1. */
+ float a = IES_LOOKUP((v == 0) ? 1 : v - 1);
+ float b = IES_LOOKUP(v);
+ float c = IES_LOOKUP(v + 1);
+ float d = IES_LOOKUP(min(v + 2, v_num - 1));
+#undef IES_LOOKUP
+
+ return cubic_interp(a, b, c, d, v_frac);
+}
+
+ccl_device_inline float kernel_ies_interp(KernelGlobals kg, int slot, float h_angle, float v_angle)
+{
+ /* Find offset of the IES data in the table. */
+ int ofs = __float_as_int(kernel_tex_fetch(__ies, slot));
+ if (ofs == -1) {
+ return 100.0f;
+ }
+
+ int h_num = __float_as_int(kernel_tex_fetch(__ies, ofs++));
+ int v_num = __float_as_int(kernel_tex_fetch(__ies, ofs++));
+
+#define IES_LOOKUP_ANGLE_H(h) kernel_tex_fetch(__ies, ofs + (h))
+#define IES_LOOKUP_ANGLE_V(v) kernel_tex_fetch(__ies, ofs + h_num + (v))
+
+ /* Check whether the angle is within the bounds of the IES texture. */
+ if (v_angle >= IES_LOOKUP_ANGLE_V(v_num - 1)) {
+ return 0.0f;
+ }
+ kernel_assert(v_angle >= IES_LOOKUP_ANGLE_V(0));
+ kernel_assert(h_angle >= IES_LOOKUP_ANGLE_H(0));
+ kernel_assert(h_angle <= IES_LOOKUP_ANGLE_H(h_num - 1));
+
+ /* Lookup the angles to find the table position. */
+ int h_i, v_i;
+ /* TODO(lukas): Consider using bisection.
+ * Probably not worth it for the vast majority of IES files. */
+ for (h_i = 0; IES_LOOKUP_ANGLE_H(h_i + 1) < h_angle; h_i++)
+ ;
+ for (v_i = 0; IES_LOOKUP_ANGLE_V(v_i + 1) < v_angle; v_i++)
+ ;
+
+ float h_frac = inverse_lerp(IES_LOOKUP_ANGLE_H(h_i), IES_LOOKUP_ANGLE_H(h_i + 1), h_angle);
+ float v_frac = inverse_lerp(IES_LOOKUP_ANGLE_V(v_i), IES_LOOKUP_ANGLE_V(v_i + 1), v_angle);
+
+#undef IES_LOOKUP_ANGLE_H
+#undef IES_LOOKUP_ANGLE_V
+
+ /* Skip forward to the actual intensity data. */
+ ofs += h_num + v_num;
+
+ /* Perform cubic interpolation along the horizontal coordinate to get the intensity value.
+ * If h_i is zero, just wrap around since the horizontal angles always go over the full circle.
+ * However, the last entry (360°) equals the first one, so we need to wrap around to the one
+ * before that. */
+ float a = interpolate_ies_vertical(
+ kg, ofs, v_i, v_num, v_frac, (h_i == 0) ? h_num - 2 : h_i - 1);
+ float b = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i);
+ float c = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i + 1);
+ /* Same logic here, wrap around to the second element if necessary. */
+ float d = interpolate_ies_vertical(
+ kg, ofs, v_i, v_num, v_frac, (h_i + 2 == h_num) ? 1 : h_i + 2);
+
+ /* Cubic interpolation can result in negative values, so get rid of them. */
+ return max(cubic_interp(a, b, c, d, h_frac), 0.0f);
+}
+
+ccl_device_noinline void svm_node_ies(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint vector_offset, strength_offset, fac_offset, slot = node.z;
+ svm_unpack_node_uchar3(node.y, &strength_offset, &vector_offset, &fac_offset);
+
+ float3 vector = stack_load_float3(stack, vector_offset);
+ float strength = stack_load_float_default(stack, strength_offset, node.w);
+
+ vector = normalize(vector);
+ float v_angle = safe_acosf(-vector.z);
+ float h_angle = atan2f(vector.x, vector.y) + M_PI_F;
+
+ float fac = strength * kernel_ies_interp(kg, slot, h_angle, v_angle);
+
+ if (stack_valid(fac_offset)) {
+ stack_store_float(stack, fac_offset, fac);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/image.h b/intern/cycles/kernel/svm/image.h
new file mode 100644
index 00000000000..2ebd3d4eb87
--- /dev/null
+++ b/intern/cycles/kernel/svm/image.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device float4 svm_image_texture(KernelGlobals kg, int id, float x, float y, uint flags)
+{
+ if (id == -1) {
+ return make_float4(
+ TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
+ }
+
+ float4 r = kernel_tex_image_interp(kg, id, x, y);
+ const float alpha = r.w;
+
+ if ((flags & NODE_IMAGE_ALPHA_UNASSOCIATE) && alpha != 1.0f && alpha != 0.0f) {
+ r /= alpha;
+ r.w = alpha;
+ }
+
+ if (flags & NODE_IMAGE_COMPRESS_AS_SRGB) {
+ r = color_srgb_to_linear_v4(r);
+ }
+
+ return r;
+}
+
+/* Remap coordinate from 0..1 box to -1..-1 */
+ccl_device_inline float3 texco_remap_square(float3 co)
+{
+ return (co - make_float3(0.5f, 0.5f, 0.5f)) * 2.0f;
+}
+
+ccl_device_noinline int svm_node_tex_image(
+ KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
+{
+ uint co_offset, out_offset, alpha_offset, flags;
+
+ svm_unpack_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &flags);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float2 tex_co;
+ if (node.w == NODE_IMAGE_PROJ_SPHERE) {
+ co = texco_remap_square(co);
+ tex_co = map_to_sphere(co);
+ }
+ else if (node.w == NODE_IMAGE_PROJ_TUBE) {
+ co = texco_remap_square(co);
+ tex_co = map_to_tube(co);
+ }
+ else {
+ tex_co = make_float2(co.x, co.y);
+ }
+
+ /* TODO(lukas): Consider moving tile information out of the SVM node.
+ * TextureInfo seems a reasonable candidate. */
+ int id = -1;
+ int num_nodes = (int)node.y;
+ if (num_nodes > 0) {
+ /* Remember the offset of the node following the tile nodes. */
+ int next_offset = offset + num_nodes;
+
+ /* Find the tile that the UV lies in. */
+ int tx = (int)tex_co.x;
+ int ty = (int)tex_co.y;
+
+ /* Check that we're within a legitimate tile. */
+ if (tx >= 0 && ty >= 0 && tx < 10) {
+ int tile = 1001 + 10 * ty + tx;
+
+ /* Find the index of the tile. */
+ for (int i = 0; i < num_nodes; i++) {
+ uint4 tile_node = read_node(kg, &offset);
+ if (tile_node.x == tile) {
+ id = tile_node.y;
+ break;
+ }
+ if (tile_node.z == tile) {
+ id = tile_node.w;
+ break;
+ }
+ }
+
+ /* If we found the tile, offset the UVs to be relative to it. */
+ if (id != -1) {
+ tex_co.x -= tx;
+ tex_co.y -= ty;
+ }
+ }
+
+ /* Skip over the remaining nodes. */
+ offset = next_offset;
+ }
+ else {
+ id = -num_nodes;
+ }
+
+ float4 f = svm_image_texture(kg, id, tex_co.x, tex_co.y, flags);
+
+ if (stack_valid(out_offset))
+ stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
+ if (stack_valid(alpha_offset))
+ stack_store_float(stack, alpha_offset, f.w);
+ return offset;
+}
+
+ccl_device_noinline void svm_node_tex_image_box(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ /* get object space normal */
+ float3 N = sd->N;
+
+ N = sd->N;
+ object_inverse_normal_transform(kg, sd, &N);
+
+ /* project from direction vector to barycentric coordinates in triangles */
+ float3 signed_N = N;
+
+ N.x = fabsf(N.x);
+ N.y = fabsf(N.y);
+ N.z = fabsf(N.z);
+
+ N /= (N.x + N.y + N.z);
+
+ /* basic idea is to think of this as a triangle, each corner representing
+ * one of the 3 faces of the cube. in the corners we have single textures,
+ * in between we blend between two textures, and in the middle we a blend
+ * between three textures.
+ *
+ * The `Nxyz` values are the barycentric coordinates in an equilateral
+ * triangle, which in case of blending, in the middle has a smaller
+ * equilateral triangle where 3 textures blend. this divides things into
+ * 7 zones, with an if() test for each zone. */
+
+ float3 weight = make_float3(0.0f, 0.0f, 0.0f);
+ float blend = __int_as_float(node.w);
+ float limit = 0.5f * (1.0f + blend);
+
+ /* first test for corners with single texture */
+ if (N.x > limit * (N.x + N.y) && N.x > limit * (N.x + N.z)) {
+ weight.x = 1.0f;
+ }
+ else if (N.y > limit * (N.x + N.y) && N.y > limit * (N.y + N.z)) {
+ weight.y = 1.0f;
+ }
+ else if (N.z > limit * (N.x + N.z) && N.z > limit * (N.y + N.z)) {
+ weight.z = 1.0f;
+ }
+ else if (blend > 0.0f) {
+ /* in case of blending, test for mixes between two textures */
+ if (N.z < (1.0f - limit) * (N.y + N.x)) {
+ weight.x = N.x / (N.x + N.y);
+ weight.x = saturatef((weight.x - 0.5f * (1.0f - blend)) / blend);
+ weight.y = 1.0f - weight.x;
+ }
+ else if (N.x < (1.0f - limit) * (N.y + N.z)) {
+ weight.y = N.y / (N.y + N.z);
+ weight.y = saturatef((weight.y - 0.5f * (1.0f - blend)) / blend);
+ weight.z = 1.0f - weight.y;
+ }
+ else if (N.y < (1.0f - limit) * (N.x + N.z)) {
+ weight.x = N.x / (N.x + N.z);
+ weight.x = saturatef((weight.x - 0.5f * (1.0f - blend)) / blend);
+ weight.z = 1.0f - weight.x;
+ }
+ else {
+ /* last case, we have a mix between three */
+ weight.x = ((2.0f - limit) * N.x + (limit - 1.0f)) / (2.0f * limit - 1.0f);
+ weight.y = ((2.0f - limit) * N.y + (limit - 1.0f)) / (2.0f * limit - 1.0f);
+ weight.z = ((2.0f - limit) * N.z + (limit - 1.0f)) / (2.0f * limit - 1.0f);
+ }
+ }
+ else {
+ /* Desperate mode, no valid choice anyway, fallback to one side. */
+ weight.x = 1.0f;
+ }
+
+ /* now fetch textures */
+ uint co_offset, out_offset, alpha_offset, flags;
+ svm_unpack_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &flags);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ uint id = node.y;
+
+ float4 f = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ /* Map so that no textures are flipped, rotation is somewhat arbitrary. */
+ if (weight.x > 0.0f) {
+ float2 uv = make_float2((signed_N.x < 0.0f) ? 1.0f - co.y : co.y, co.z);
+ f += weight.x * svm_image_texture(kg, id, uv.x, uv.y, flags);
+ }
+ if (weight.y > 0.0f) {
+ float2 uv = make_float2((signed_N.y > 0.0f) ? 1.0f - co.x : co.x, co.z);
+ f += weight.y * svm_image_texture(kg, id, uv.x, uv.y, flags);
+ }
+ if (weight.z > 0.0f) {
+ float2 uv = make_float2((signed_N.z > 0.0f) ? 1.0f - co.y : co.y, co.x);
+ f += weight.z * svm_image_texture(kg, id, uv.x, uv.y, flags);
+ }
+
+ if (stack_valid(out_offset))
+ stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
+ if (stack_valid(alpha_offset))
+ stack_store_float(stack, alpha_offset, f.w);
+}
+
+ccl_device_noinline void svm_node_tex_environment(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint id = node.y;
+ uint co_offset, out_offset, alpha_offset, flags;
+ uint projection = node.w;
+
+ svm_unpack_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &flags);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float2 uv;
+
+ co = safe_normalize(co);
+
+ if (projection == 0)
+ uv = direction_to_equirectangular(co);
+ else
+ uv = direction_to_mirrorball(co);
+
+ float4 f = svm_image_texture(kg, id, uv.x, uv.y, flags);
+
+ if (stack_valid(out_offset))
+ stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
+ if (stack_valid(alpha_offset))
+ stack_store_float(stack, alpha_offset, f.w);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/invert.h b/intern/cycles/kernel/svm/invert.h
new file mode 100644
index 00000000000..5a88e9df2c9
--- /dev/null
+++ b/intern/cycles/kernel/svm/invert.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device float invert(float color, float factor)
+{
+ return factor * (1.0f - color) + (1.0f - factor) * color;
+}
+
+ccl_device_noinline void svm_node_invert(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint in_fac,
+ uint in_color,
+ uint out_color)
+{
+ float factor = stack_load_float(stack, in_fac);
+ float3 color = stack_load_float3(stack, in_color);
+
+ color.x = invert(color.x, factor);
+ color.y = invert(color.y, factor);
+ color.z = invert(color.z, factor);
+
+ if (stack_valid(out_color))
+ stack_store_float3(stack, out_color, color);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/light_path.h b/intern/cycles/kernel/svm/light_path.h
new file mode 100644
index 00000000000..44a35b568fa
--- /dev/null
+++ b/intern/cycles/kernel/svm/light_path.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Light Path Node */
+
+template<uint node_feature_mask, typename ConstIntegratorGenericState>
+ccl_device_noinline void svm_node_light_path(KernelGlobals kg,
+ ConstIntegratorGenericState state,
+ ccl_private const ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint out_offset,
+ uint32_t path_flag)
+{
+ float info = 0.0f;
+
+ switch (type) {
+ case NODE_LP_camera:
+ info = (path_flag & PATH_RAY_CAMERA) ? 1.0f : 0.0f;
+ break;
+ case NODE_LP_shadow:
+ info = (path_flag & PATH_RAY_SHADOW) ? 1.0f : 0.0f;
+ break;
+ case NODE_LP_diffuse:
+ info = (path_flag & PATH_RAY_DIFFUSE) ? 1.0f : 0.0f;
+ break;
+ case NODE_LP_glossy:
+ info = (path_flag & PATH_RAY_GLOSSY) ? 1.0f : 0.0f;
+ break;
+ case NODE_LP_singular:
+ info = (path_flag & PATH_RAY_SINGULAR) ? 1.0f : 0.0f;
+ break;
+ case NODE_LP_reflection:
+ info = (path_flag & PATH_RAY_REFLECT) ? 1.0f : 0.0f;
+ break;
+ case NODE_LP_transmission:
+ info = (path_flag & PATH_RAY_TRANSMIT) ? 1.0f : 0.0f;
+ break;
+ case NODE_LP_volume_scatter:
+ info = (path_flag & PATH_RAY_VOLUME_SCATTER) ? 1.0f : 0.0f;
+ break;
+ case NODE_LP_backfacing:
+ info = (sd->flag & SD_BACKFACING) ? 1.0f : 0.0f;
+ break;
+ case NODE_LP_ray_length:
+ info = sd->ray_length;
+ break;
+ case NODE_LP_ray_depth: {
+ /* Read bounce from difference location depending if this is a shadow
+ * path. It's a bit dubious to have integrate state details leak into
+ * this function but hard to avoid currently. */
+ IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
+ {
+ info = (float)integrator_state_bounce(state, path_flag);
+ }
+
+ /* For background, light emission and shadow evaluation we from a
+ * surface or volume we are effective one bounce further. */
+ if (path_flag & (PATH_RAY_SHADOW | PATH_RAY_EMISSION)) {
+ info += 1.0f;
+ }
+ break;
+ }
+ case NODE_LP_ray_transparent: {
+ IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
+ {
+ info = (float)integrator_state_transparent_bounce(state, path_flag);
+ }
+ break;
+ }
+ case NODE_LP_ray_diffuse:
+ IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
+ {
+ info = (float)integrator_state_diffuse_bounce(state, path_flag);
+ }
+ break;
+ case NODE_LP_ray_glossy:
+ IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
+ {
+ info = (float)integrator_state_glossy_bounce(state, path_flag);
+ }
+ break;
+ case NODE_LP_ray_transmission:
+ IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
+ {
+ info = (float)integrator_state_transmission_bounce(state, path_flag);
+ }
+ break;
+ }
+
+ stack_store_float(stack, out_offset, info);
+}
+
+/* Light Falloff Node */
+
+ccl_device_noinline void svm_node_light_falloff(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint strength_offset, out_offset, smooth_offset;
+
+ svm_unpack_node_uchar3(node.z, &strength_offset, &smooth_offset, &out_offset);
+
+ float strength = stack_load_float(stack, strength_offset);
+ uint type = node.y;
+
+ switch (type) {
+ case NODE_LIGHT_FALLOFF_QUADRATIC:
+ break;
+ case NODE_LIGHT_FALLOFF_LINEAR:
+ strength *= sd->ray_length;
+ break;
+ case NODE_LIGHT_FALLOFF_CONSTANT:
+ strength *= sd->ray_length * sd->ray_length;
+ break;
+ }
+
+ float smooth = stack_load_float(stack, smooth_offset);
+
+ if (smooth > 0.0f) {
+ float squared = sd->ray_length * sd->ray_length;
+ /* Distant lamps set the ray length to FLT_MAX, which causes squared to overflow. */
+ if (isfinite(squared)) {
+ strength *= squared / (smooth + squared);
+ }
+ }
+
+ stack_store_float(stack, out_offset, strength);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/magic.h b/intern/cycles/kernel/svm/magic.h
new file mode 100644
index 00000000000..f103a8eebcc
--- /dev/null
+++ b/intern/cycles/kernel/svm/magic.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Magic */
+
+ccl_device_noinline_cpu float3 svm_magic(float3 p, int n, float distortion)
+{
+ float x = sinf((p.x + p.y + p.z) * 5.0f);
+ float y = cosf((-p.x + p.y - p.z) * 5.0f);
+ float z = -cosf((-p.x - p.y + p.z) * 5.0f);
+
+ if (n > 0) {
+ x *= distortion;
+ y *= distortion;
+ z *= distortion;
+ y = -cosf(x - y + z);
+ y *= distortion;
+
+ if (n > 1) {
+ x = cosf(x - y - z);
+ x *= distortion;
+
+ if (n > 2) {
+ z = sinf(-x - y - z);
+ z *= distortion;
+
+ if (n > 3) {
+ x = -cosf(-x + y - z);
+ x *= distortion;
+
+ if (n > 4) {
+ y = -sinf(-x + y + z);
+ y *= distortion;
+
+ if (n > 5) {
+ y = -cosf(-x + y + z);
+ y *= distortion;
+
+ if (n > 6) {
+ x = cosf(x + y + z);
+ x *= distortion;
+
+ if (n > 7) {
+ z = sinf(x + y - z);
+ z *= distortion;
+
+ if (n > 8) {
+ x = -cosf(-x - y + z);
+ x *= distortion;
+
+ if (n > 9) {
+ y = -sinf(x - y + z);
+ y *= distortion;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (distortion != 0.0f) {
+ distortion *= 2.0f;
+ x /= distortion;
+ y /= distortion;
+ z /= distortion;
+ }
+
+ return make_float3(0.5f - x, 0.5f - y, 0.5f - z);
+}
+
+ccl_device_noinline int svm_node_tex_magic(
+ KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
+{
+ uint depth;
+ uint scale_offset, distortion_offset, co_offset, fac_offset, color_offset;
+
+ svm_unpack_node_uchar3(node.y, &depth, &color_offset, &fac_offset);
+ svm_unpack_node_uchar3(node.z, &co_offset, &scale_offset, &distortion_offset);
+
+ uint4 node2 = read_node(kg, &offset);
+ float3 co = stack_load_float3(stack, co_offset);
+ float scale = stack_load_float_default(stack, scale_offset, node2.x);
+ float distortion = stack_load_float_default(stack, distortion_offset, node2.y);
+
+ float3 color = svm_magic(co * scale, depth, distortion);
+
+ if (stack_valid(fac_offset))
+ stack_store_float(stack, fac_offset, average(color));
+ if (stack_valid(color_offset))
+ stack_store_float3(stack, color_offset, color);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/map_range.h b/intern/cycles/kernel/svm/map_range.h
new file mode 100644
index 00000000000..fdbfc6531c4
--- /dev/null
+++ b/intern/cycles/kernel/svm/map_range.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Map Range Node */
+
+ccl_device_inline float smootherstep(float edge0, float edge1, float x)
+{
+ x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0f, 1.0f);
+ return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f);
+}
+
+ccl_device_noinline int svm_node_map_range(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint value_stack_offset,
+ uint parameters_stack_offsets,
+ uint results_stack_offsets,
+ int offset)
+{
+ uint from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset;
+ uint type_stack_offset, steps_stack_offset, result_stack_offset;
+ svm_unpack_node_uchar4(parameters_stack_offsets,
+ &from_min_stack_offset,
+ &from_max_stack_offset,
+ &to_min_stack_offset,
+ &to_max_stack_offset);
+ svm_unpack_node_uchar3(
+ results_stack_offsets, &type_stack_offset, &steps_stack_offset, &result_stack_offset);
+
+ uint4 defaults = read_node(kg, &offset);
+ uint4 defaults2 = read_node(kg, &offset);
+
+ float value = stack_load_float(stack, value_stack_offset);
+ float from_min = stack_load_float_default(stack, from_min_stack_offset, defaults.x);
+ float from_max = stack_load_float_default(stack, from_max_stack_offset, defaults.y);
+ float to_min = stack_load_float_default(stack, to_min_stack_offset, defaults.z);
+ float to_max = stack_load_float_default(stack, to_max_stack_offset, defaults.w);
+ float steps = stack_load_float_default(stack, steps_stack_offset, defaults2.x);
+
+ float result;
+
+ if (from_max != from_min) {
+ float factor = value;
+ switch (type_stack_offset) {
+ default:
+ case NODE_MAP_RANGE_LINEAR:
+ factor = (value - from_min) / (from_max - from_min);
+ break;
+ case NODE_MAP_RANGE_STEPPED: {
+ factor = (value - from_min) / (from_max - from_min);
+ factor = (steps > 0.0f) ? floorf(factor * (steps + 1.0f)) / steps : 0.0f;
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ factor = (from_min > from_max) ? 1.0f - smoothstep(from_max, from_min, factor) :
+ smoothstep(from_min, from_max, factor);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ factor = (from_min > from_max) ? 1.0f - smootherstep(from_max, from_min, factor) :
+ smootherstep(from_min, from_max, factor);
+ break;
+ }
+ }
+ result = to_min + factor * (to_max - to_min);
+ }
+ else {
+ result = 0.0f;
+ }
+ stack_store_float(stack, result_stack_offset, result);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/mapping.h b/intern/cycles/kernel/svm/mapping.h
new file mode 100644
index 00000000000..19f79471ad2
--- /dev/null
+++ b/intern/cycles/kernel/svm/mapping.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/svm/mapping_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Mapping Node */
+
+ccl_device_noinline void svm_node_mapping(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint inputs_stack_offsets,
+ uint result_stack_offset)
+{
+ uint vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset;
+ svm_unpack_node_uchar4(inputs_stack_offsets,
+ &vector_stack_offset,
+ &location_stack_offset,
+ &rotation_stack_offset,
+ &scale_stack_offset);
+
+ float3 vector = stack_load_float3(stack, vector_stack_offset);
+ float3 location = stack_load_float3(stack, location_stack_offset);
+ float3 rotation = stack_load_float3(stack, rotation_stack_offset);
+ float3 scale = stack_load_float3(stack, scale_stack_offset);
+
+ float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
+ stack_store_float3(stack, result_stack_offset, result);
+}
+
+/* Texture Mapping */
+
+ccl_device_noinline int svm_node_texture_mapping(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint vec_offset,
+ uint out_offset,
+ int offset)
+{
+ float3 v = stack_load_float3(stack, vec_offset);
+
+ Transform tfm;
+ tfm.x = read_node_float(kg, &offset);
+ tfm.y = read_node_float(kg, &offset);
+ tfm.z = read_node_float(kg, &offset);
+
+ float3 r = transform_point(&tfm, v);
+ stack_store_float3(stack, out_offset, r);
+ return offset;
+}
+
+ccl_device_noinline int svm_node_min_max(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint vec_offset,
+ uint out_offset,
+ int offset)
+{
+ float3 v = stack_load_float3(stack, vec_offset);
+
+ float3 mn = float4_to_float3(read_node_float(kg, &offset));
+ float3 mx = float4_to_float3(read_node_float(kg, &offset));
+
+ float3 r = min(max(mn, v), mx);
+ stack_store_float3(stack, out_offset, r);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/mapping_util.h b/intern/cycles/kernel/svm/mapping_util.h
new file mode 100644
index 00000000000..51b13c0c264
--- /dev/null
+++ b/intern/cycles/kernel/svm/mapping_util.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011-2014 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device float3
+svm_mapping(NodeMappingType type, float3 vector, float3 location, float3 rotation, float3 scale)
+{
+ Transform rotationTransform = euler_to_transform(rotation);
+ switch (type) {
+ case NODE_MAPPING_TYPE_POINT:
+ return transform_direction(&rotationTransform, (vector * scale)) + location;
+ case NODE_MAPPING_TYPE_TEXTURE:
+ return safe_divide_float3_float3(
+ transform_direction_transposed(&rotationTransform, (vector - location)), scale);
+ case NODE_MAPPING_TYPE_VECTOR:
+ return transform_direction(&rotationTransform, (vector * scale));
+ case NODE_MAPPING_TYPE_NORMAL:
+ return safe_normalize(
+ transform_direction(&rotationTransform, safe_divide_float3_float3(vector, scale)));
+ default:
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/math.h b/intern/cycles/kernel/svm/math.h
new file mode 100644
index 00000000000..ff0f3683ea3
--- /dev/null
+++ b/intern/cycles/kernel/svm/math.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline void svm_node_math(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint inputs_stack_offsets,
+ uint result_stack_offset)
+{
+ uint a_stack_offset, b_stack_offset, c_stack_offset;
+ svm_unpack_node_uchar3(inputs_stack_offsets, &a_stack_offset, &b_stack_offset, &c_stack_offset);
+
+ float a = stack_load_float(stack, a_stack_offset);
+ float b = stack_load_float(stack, b_stack_offset);
+ float c = stack_load_float(stack, c_stack_offset);
+ float result = svm_math((NodeMathType)type, a, b, c);
+
+ stack_store_float(stack, result_stack_offset, result);
+}
+
+ccl_device_noinline int svm_node_vector_math(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint inputs_stack_offsets,
+ uint outputs_stack_offsets,
+ int offset)
+{
+ uint value_stack_offset, vector_stack_offset;
+ uint a_stack_offset, b_stack_offset, param1_stack_offset;
+ svm_unpack_node_uchar3(
+ inputs_stack_offsets, &a_stack_offset, &b_stack_offset, &param1_stack_offset);
+ svm_unpack_node_uchar2(outputs_stack_offsets, &value_stack_offset, &vector_stack_offset);
+
+ float3 a = stack_load_float3(stack, a_stack_offset);
+ float3 b = stack_load_float3(stack, b_stack_offset);
+ float3 c = make_float3(0.0f, 0.0f, 0.0f);
+ float param1 = stack_load_float(stack, param1_stack_offset);
+
+ float value;
+ float3 vector;
+
+ /* 3 Vector Operators */
+ if (type == NODE_VECTOR_MATH_WRAP || type == NODE_VECTOR_MATH_FACEFORWARD ||
+ type == NODE_VECTOR_MATH_MULTIPLY_ADD) {
+ uint4 extra_node = read_node(kg, &offset);
+ c = stack_load_float3(stack, extra_node.x);
+ }
+
+ svm_vector_math(&value, &vector, (NodeVectorMathType)type, a, b, c, param1);
+
+ if (stack_valid(value_stack_offset))
+ stack_store_float(stack, value_stack_offset, value);
+ if (stack_valid(vector_stack_offset))
+ stack_store_float3(stack, vector_stack_offset, vector);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/math_util.h b/intern/cycles/kernel/svm/math_util.h
new file mode 100644
index 00000000000..b2e539cdd1f
--- /dev/null
+++ b/intern/cycles/kernel/svm/math_util.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2011-2014 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device void svm_vector_math(ccl_private float *value,
+ ccl_private float3 *vector,
+ NodeVectorMathType type,
+ float3 a,
+ float3 b,
+ float3 c,
+ float param1)
+{
+ switch (type) {
+ case NODE_VECTOR_MATH_ADD:
+ *vector = a + b;
+ break;
+ case NODE_VECTOR_MATH_SUBTRACT:
+ *vector = a - b;
+ break;
+ case NODE_VECTOR_MATH_MULTIPLY:
+ *vector = a * b;
+ break;
+ case NODE_VECTOR_MATH_DIVIDE:
+ *vector = safe_divide_float3_float3(a, b);
+ break;
+ case NODE_VECTOR_MATH_CROSS_PRODUCT:
+ *vector = cross(a, b);
+ break;
+ case NODE_VECTOR_MATH_PROJECT:
+ *vector = project(a, b);
+ break;
+ case NODE_VECTOR_MATH_REFLECT:
+ *vector = reflect(a, b);
+ break;
+ case NODE_VECTOR_MATH_REFRACT:
+ *vector = refract(a, normalize(b), param1);
+ break;
+ case NODE_VECTOR_MATH_FACEFORWARD:
+ *vector = faceforward(a, b, c);
+ break;
+ case NODE_VECTOR_MATH_MULTIPLY_ADD:
+ *vector = a * b + c;
+ break;
+ case NODE_VECTOR_MATH_DOT_PRODUCT:
+ *value = dot(a, b);
+ break;
+ case NODE_VECTOR_MATH_DISTANCE:
+ *value = distance(a, b);
+ break;
+ case NODE_VECTOR_MATH_LENGTH:
+ *value = len(a);
+ break;
+ case NODE_VECTOR_MATH_SCALE:
+ *vector = a * param1;
+ break;
+ case NODE_VECTOR_MATH_NORMALIZE:
+ *vector = safe_normalize(a);
+ break;
+ case NODE_VECTOR_MATH_SNAP:
+ *vector = floor(safe_divide_float3_float3(a, b)) * b;
+ break;
+ case NODE_VECTOR_MATH_FLOOR:
+ *vector = floor(a);
+ break;
+ case NODE_VECTOR_MATH_CEIL:
+ *vector = ceil(a);
+ break;
+ case NODE_VECTOR_MATH_MODULO:
+ *vector = make_float3(safe_modulo(a.x, b.x), safe_modulo(a.y, b.y), safe_modulo(a.z, b.z));
+ break;
+ case NODE_VECTOR_MATH_WRAP:
+ *vector = make_float3(wrapf(a.x, b.x, c.x), wrapf(a.y, b.y, c.y), wrapf(a.z, b.z, c.z));
+ break;
+ case NODE_VECTOR_MATH_FRACTION:
+ *vector = a - floor(a);
+ break;
+ case NODE_VECTOR_MATH_ABSOLUTE:
+ *vector = fabs(a);
+ break;
+ case NODE_VECTOR_MATH_MINIMUM:
+ *vector = min(a, b);
+ break;
+ case NODE_VECTOR_MATH_MAXIMUM:
+ *vector = max(a, b);
+ break;
+ case NODE_VECTOR_MATH_SINE:
+ *vector = make_float3(sinf(a.x), sinf(a.y), sinf(a.z));
+ break;
+ case NODE_VECTOR_MATH_COSINE:
+ *vector = make_float3(cosf(a.x), cosf(a.y), cosf(a.z));
+ break;
+ case NODE_VECTOR_MATH_TANGENT:
+ *vector = make_float3(tanf(a.x), tanf(a.y), tanf(a.z));
+ break;
+ default:
+ *vector = zero_float3();
+ *value = 0.0f;
+ }
+}
+
+ccl_device float svm_math(NodeMathType type, float a, float b, float c)
+{
+ switch (type) {
+ case NODE_MATH_ADD:
+ return a + b;
+ case NODE_MATH_SUBTRACT:
+ return a - b;
+ case NODE_MATH_MULTIPLY:
+ return a * b;
+ case NODE_MATH_DIVIDE:
+ return safe_divide(a, b);
+ case NODE_MATH_POWER:
+ return safe_powf(a, b);
+ case NODE_MATH_LOGARITHM:
+ return safe_logf(a, b);
+ case NODE_MATH_SQRT:
+ return safe_sqrtf(a);
+ case NODE_MATH_INV_SQRT:
+ return inversesqrtf(a);
+ case NODE_MATH_ABSOLUTE:
+ return fabsf(a);
+ case NODE_MATH_RADIANS:
+ return a * (M_PI_F / 180.0f);
+ case NODE_MATH_DEGREES:
+ return a * (180.0f / M_PI_F);
+ case NODE_MATH_MINIMUM:
+ return fminf(a, b);
+ case NODE_MATH_MAXIMUM:
+ return fmaxf(a, b);
+ case NODE_MATH_LESS_THAN:
+ return a < b;
+ case NODE_MATH_GREATER_THAN:
+ return a > b;
+ case NODE_MATH_ROUND:
+ return floorf(a + 0.5f);
+ case NODE_MATH_FLOOR:
+ return floorf(a);
+ case NODE_MATH_CEIL:
+ return ceilf(a);
+ case NODE_MATH_FRACTION:
+ return a - floorf(a);
+ case NODE_MATH_MODULO:
+ return safe_modulo(a, b);
+ case NODE_MATH_TRUNC:
+ return a >= 0.0f ? floorf(a) : ceilf(a);
+ case NODE_MATH_SNAP:
+ return floorf(safe_divide(a, b)) * b;
+ case NODE_MATH_WRAP:
+ return wrapf(a, b, c);
+ case NODE_MATH_PINGPONG:
+ return pingpongf(a, b);
+ case NODE_MATH_SINE:
+ return sinf(a);
+ case NODE_MATH_COSINE:
+ return cosf(a);
+ case NODE_MATH_TANGENT:
+ return tanf(a);
+ case NODE_MATH_SINH:
+ return sinhf(a);
+ case NODE_MATH_COSH:
+ return coshf(a);
+ case NODE_MATH_TANH:
+ return tanhf(a);
+ case NODE_MATH_ARCSINE:
+ return safe_asinf(a);
+ case NODE_MATH_ARCCOSINE:
+ return safe_acosf(a);
+ case NODE_MATH_ARCTANGENT:
+ return atanf(a);
+ case NODE_MATH_ARCTAN2:
+ return atan2f(a, b);
+ case NODE_MATH_SIGN:
+ return compatible_signf(a);
+ case NODE_MATH_EXPONENT:
+ return expf(a);
+ case NODE_MATH_COMPARE:
+ return ((a == b) || (fabsf(a - b) <= fmaxf(c, FLT_EPSILON))) ? 1.0f : 0.0f;
+ case NODE_MATH_MULTIPLY_ADD:
+ return a * b + c;
+ case NODE_MATH_SMOOTH_MIN:
+ return smoothminf(a, b, c);
+ case NODE_MATH_SMOOTH_MAX:
+ return -smoothminf(-a, -b, c);
+ default:
+ return 0.0f;
+ }
+}
+
+ccl_device float3 svm_math_blackbody_color(float t)
+{
+ /* TODO(lukas): Reimplement in XYZ. */
+
+ /* Calculate color in range 800..12000 using an approximation
+ * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
+ * Max absolute error for RGB is (0.00095, 0.00077, 0.00057),
+ * which is enough to get the same 8 bit/channel color.
+ */
+
+ const float blackbody_table_r[6][3] = {
+ {2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f},
+ {3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f},
+ {4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f},
+ {4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f},
+ {4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f},
+ {3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f},
+ };
+
+ const float blackbody_table_g[6][3] = {
+ {-7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f},
+ {-1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f},
+ {-1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f},
+ {-1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f},
+ {-1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f},
+ {-5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f},
+ };
+
+ const float blackbody_table_b[6][4] = {
+ {0.0f, 0.0f, 0.0f, 0.0f}, /* zeros should be optimized by compiler */
+ {0.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
+ {-2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f},
+ {-2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f},
+ {6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f},
+ };
+
+ if (t >= 12000.0f) {
+ return make_float3(0.826270103f, 0.994478524f, 1.56626022f);
+ }
+ else if (t < 965.0f) {
+ /* For 800 <= t < 965 color does not change in OSL implementation, so keep color the same */
+ return make_float3(4.70366907f, 0.0f, 0.0f);
+ }
+
+ /* Manually align for readability. */
+ /* clang-format off */
+ int i = (t >= 6365.0f) ? 5 :
+ (t >= 3315.0f) ? 4 :
+ (t >= 1902.0f) ? 3 :
+ (t >= 1449.0f) ? 2 :
+ (t >= 1167.0f) ? 1 :
+ 0;
+ /* clang-format on */
+
+ ccl_constant float *r = blackbody_table_r[i];
+ ccl_constant float *g = blackbody_table_g[i];
+ ccl_constant float *b = blackbody_table_b[i];
+
+ const float t_inv = 1.0f / t;
+ return make_float3(r[0] * t_inv + r[1] * t + r[2],
+ g[0] * t_inv + g[1] * t + g[2],
+ ((b[0] * t + b[1]) * t + b[2]) * t + b[3]);
+}
+
+ccl_device_inline float3 svm_math_gamma_color(float3 color, float gamma)
+{
+ if (gamma == 0.0f)
+ return make_float3(1.0f, 1.0f, 1.0f);
+
+ if (color.x > 0.0f)
+ color.x = powf(color.x, gamma);
+ if (color.y > 0.0f)
+ color.y = powf(color.y, gamma);
+ if (color.z > 0.0f)
+ color.z = powf(color.z, gamma);
+
+ return color;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/mix.h b/intern/cycles/kernel/svm/mix.h
new file mode 100644
index 00000000000..96e5b3f5b5e
--- /dev/null
+++ b/intern/cycles/kernel/svm/mix.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Node */
+
+ccl_device_noinline int svm_node_mix(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint fac_offset,
+ uint c1_offset,
+ uint c2_offset,
+ int offset)
+{
+ /* read extra data */
+ uint4 node1 = read_node(kg, &offset);
+
+ float fac = stack_load_float(stack, fac_offset);
+ float3 c1 = stack_load_float3(stack, c1_offset);
+ float3 c2 = stack_load_float3(stack, c2_offset);
+ float3 result = svm_mix((NodeMix)node1.y, fac, c1, c2);
+
+ stack_store_float3(stack, node1.z, result);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/musgrave.h b/intern/cycles/kernel/svm/musgrave.h
new file mode 100644
index 00000000000..85e32eee638
--- /dev/null
+++ b/intern/cycles/kernel/svm/musgrave.h
@@ -0,0 +1,854 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/svm/noise.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* 1D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_fBm_1d(float co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_1d(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_1d(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_multi_fractal_1d(float co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_1d(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_1d(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_1d(
+ float co, float H, float lacunarity, float octaves, float offset)
+{
+ float p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise_1d(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ float increment = (snoise_1d(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (snoise_1d(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_1d(
+ float co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise_1d(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (snoise_1d(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((snoise_1d(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+/* 1D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_1d(
+ float co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(snoise_1d(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ p *= lacunarity;
+ weight = saturatef(signal * gain);
+ signal = offset - fabsf(snoise_1d(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+/* 2D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_fBm_2d(float2 co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float2 p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_2d(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_2d(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 2D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_multi_fractal_2d(float2 co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float2 p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_2d(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_2d(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+/* 2D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_2d(
+ float2 co, float H, float lacunarity, float octaves, float offset)
+{
+ float2 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise_2d(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ float increment = (snoise_2d(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (snoise_2d(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_2d(
+ float2 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float2 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise_2d(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (snoise_2d(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((snoise_2d(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+/* 2D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_2d(
+ float2 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float2 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(snoise_2d(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ p *= lacunarity;
+ weight = saturatef(signal * gain);
+ signal = offset - fabsf(snoise_2d(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+/* 3D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_fBm_3d(float3 co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float3 p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_3d(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_3d(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 3D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_multi_fractal_3d(float3 co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float3 p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_3d(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_3d(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+/* 3D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_3d(
+ float3 co, float H, float lacunarity, float octaves, float offset)
+{
+ float3 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise_3d(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ float increment = (snoise_3d(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (snoise_3d(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_3d(
+ float3 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float3 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise_3d(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (snoise_3d(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((snoise_3d(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+/* 3D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_3d(
+ float3 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float3 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(snoise_3d(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ p *= lacunarity;
+ weight = saturatef(signal * gain);
+ signal = offset - fabsf(snoise_3d(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+/* 4D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_fBm_4d(float4 co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float4 p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_4d(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_4d(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 4D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_multi_fractal_4d(float4 co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float4 p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_4d(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_4d(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+/* 4D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_4d(
+ float4 co, float H, float lacunarity, float octaves, float offset)
+{
+ float4 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise_4d(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ float increment = (snoise_4d(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (snoise_4d(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_4d(
+ float4 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float4 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise_4d(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (snoise_4d(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((snoise_4d(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+/* 4D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_4d(
+ float4 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float4 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(snoise_4d(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ p *= lacunarity;
+ weight = saturatef(signal * gain);
+ signal = offset - fabsf(snoise_4d(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+ccl_device_noinline int svm_node_tex_musgrave(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint offsets1,
+ uint offsets2,
+ uint offsets3,
+ int offset)
+{
+ uint type, dimensions, co_stack_offset, w_stack_offset;
+ uint scale_stack_offset, detail_stack_offset, dimension_stack_offset, lacunarity_stack_offset;
+ uint offset_stack_offset, gain_stack_offset, fac_stack_offset;
+
+ svm_unpack_node_uchar4(offsets1, &type, &dimensions, &co_stack_offset, &w_stack_offset);
+ svm_unpack_node_uchar4(offsets2,
+ &scale_stack_offset,
+ &detail_stack_offset,
+ &dimension_stack_offset,
+ &lacunarity_stack_offset);
+ svm_unpack_node_uchar3(offsets3, &offset_stack_offset, &gain_stack_offset, &fac_stack_offset);
+
+ uint4 defaults1 = read_node(kg, &offset);
+ uint4 defaults2 = read_node(kg, &offset);
+
+ float3 co = stack_load_float3(stack, co_stack_offset);
+ float w = stack_load_float_default(stack, w_stack_offset, defaults1.x);
+ float scale = stack_load_float_default(stack, scale_stack_offset, defaults1.y);
+ float detail = stack_load_float_default(stack, detail_stack_offset, defaults1.z);
+ float dimension = stack_load_float_default(stack, dimension_stack_offset, defaults1.w);
+ float lacunarity = stack_load_float_default(stack, lacunarity_stack_offset, defaults2.x);
+ float foffset = stack_load_float_default(stack, offset_stack_offset, defaults2.y);
+ float gain = stack_load_float_default(stack, gain_stack_offset, defaults2.z);
+
+ dimension = fmaxf(dimension, 1e-5f);
+ detail = clamp(detail, 0.0f, 16.0f);
+ lacunarity = fmaxf(lacunarity, 1e-5f);
+
+ float fac;
+
+ switch (dimensions) {
+ case 1: {
+ float p = w * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_1d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_1d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_1d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_1d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_1d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ case 2: {
+ float2 p = make_float2(co.x, co.y) * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_2d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_2d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_2d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_2d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_2d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ case 3: {
+ float3 p = co * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_3d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_3d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_3d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_3d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_3d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ case 4: {
+ float4 p = make_float4(co.x, co.y, co.z, w) * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_4d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_4d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_4d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_4d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_4d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ default:
+ fac = 0.0f;
+ }
+
+ stack_store_float(stack, fac_stack_offset, fac);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/noise.h b/intern/cycles/kernel/svm/noise.h
new file mode 100644
index 00000000000..0a1616226db
--- /dev/null
+++ b/intern/cycles/kernel/svm/noise.h
@@ -0,0 +1,744 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* **** Perlin Noise **** */
+
+ccl_device float fade(float t)
+{
+ return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
+}
+
+ccl_device_inline float negate_if(float val, int condition)
+{
+ return (condition) ? -val : val;
+}
+
+ccl_device float grad1(int hash, float x)
+{
+ int h = hash & 15;
+ float g = 1 + (h & 7);
+ return negate_if(g, h & 8) * x;
+}
+
+ccl_device_noinline_cpu float perlin_1d(float x)
+{
+ int X;
+ float fx = floorfrac(x, &X);
+ float u = fade(fx);
+
+ return mix(grad1(hash_uint(X), fx), grad1(hash_uint(X + 1), fx - 1.0f), u);
+}
+
+/* 2D, 3D, and 4D noise can be accelerated using SSE, so we first check if
+ * SSE is supported, that is, if __KERNEL_SSE2__ is defined. If it is not
+ * supported, we do a standard implementation, but if it is supported, we
+ * do an implementation using SSE intrinsics.
+ */
+#if !defined(__KERNEL_SSE2__)
+
+/* ** Standard Implementation ** */
+
+/* Bilinear Interpolation:
+ *
+ * v2 v3
+ * @ + + + + @ y
+ * + + ^
+ * + + |
+ * + + |
+ * @ + + + + @ @------> x
+ * v0 v1
+ *
+ */
+ccl_device float bi_mix(float v0, float v1, float v2, float v3, float x, float y)
+{
+ float x1 = 1.0f - x;
+ return (1.0f - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
+}
+
+/* Trilinear Interpolation:
+ *
+ * v6 v7
+ * @ + + + + + + @
+ * +\ +\
+ * + \ + \
+ * + \ + \
+ * + \ v4 + \ v5
+ * + @ + + + +++ + @ z
+ * + + + + y ^
+ * v2 @ + +++ + + + @ v3 + \ |
+ * \ + \ + \ |
+ * \ + \ + \|
+ * \ + \ + +---------> x
+ * \+ \+
+ * @ + + + + + + @
+ * v0 v1
+ */
+ccl_device float tri_mix(float v0,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6,
+ float v7,
+ float x,
+ float y,
+ float z)
+{
+ float x1 = 1.0f - x;
+ float y1 = 1.0f - y;
+ float z1 = 1.0f - z;
+ return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) +
+ z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x));
+}
+
+ccl_device float quad_mix(float v0,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6,
+ float v7,
+ float v8,
+ float v9,
+ float v10,
+ float v11,
+ float v12,
+ float v13,
+ float v14,
+ float v15,
+ float x,
+ float y,
+ float z,
+ float w)
+{
+ return mix(tri_mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z),
+ tri_mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z),
+ w);
+}
+
+ccl_device float grad2(int hash, float x, float y)
+{
+ int h = hash & 7;
+ float u = h < 4 ? x : y;
+ float v = 2.0f * (h < 4 ? y : x);
+ return negate_if(u, h & 1) + negate_if(v, h & 2);
+}
+
+ccl_device float grad3(int hash, float x, float y, float z)
+{
+ int h = hash & 15;
+ float u = h < 8 ? x : y;
+ float vt = ((h == 12) || (h == 14)) ? x : z;
+ float v = h < 4 ? y : vt;
+ return negate_if(u, h & 1) + negate_if(v, h & 2);
+}
+
+ccl_device float grad4(int hash, float x, float y, float z, float w)
+{
+ int h = hash & 31;
+ float u = h < 24 ? x : y;
+ float v = h < 16 ? y : z;
+ float s = h < 8 ? z : w;
+ return negate_if(u, h & 1) + negate_if(v, h & 2) + negate_if(s, h & 4);
+}
+
+ccl_device_noinline_cpu float perlin_2d(float x, float y)
+{
+ int X;
+ int Y;
+
+ float fx = floorfrac(x, &X);
+ float fy = floorfrac(y, &Y);
+
+ float u = fade(fx);
+ float v = fade(fy);
+
+ float r = bi_mix(grad2(hash_uint2(X, Y), fx, fy),
+ grad2(hash_uint2(X + 1, Y), fx - 1.0f, fy),
+ grad2(hash_uint2(X, Y + 1), fx, fy - 1.0f),
+ grad2(hash_uint2(X + 1, Y + 1), fx - 1.0f, fy - 1.0f),
+ u,
+ v);
+
+ return r;
+}
+
+ccl_device_noinline_cpu float perlin_3d(float x, float y, float z)
+{
+ int X;
+ int Y;
+ int Z;
+
+ float fx = floorfrac(x, &X);
+ float fy = floorfrac(y, &Y);
+ float fz = floorfrac(z, &Z);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float w = fade(fz);
+
+ float r = tri_mix(grad3(hash_uint3(X, Y, Z), fx, fy, fz),
+ grad3(hash_uint3(X + 1, Y, Z), fx - 1.0f, fy, fz),
+ grad3(hash_uint3(X, Y + 1, Z), fx, fy - 1.0f, fz),
+ grad3(hash_uint3(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz),
+ grad3(hash_uint3(X, Y, Z + 1), fx, fy, fz - 1.0f),
+ grad3(hash_uint3(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f),
+ grad3(hash_uint3(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f),
+ grad3(hash_uint3(X + 1, Y + 1, Z + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f),
+ u,
+ v,
+ w);
+ return r;
+}
+
+ccl_device_noinline_cpu float perlin_4d(float x, float y, float z, float w)
+{
+ int X;
+ int Y;
+ int Z;
+ int W;
+
+ float fx = floorfrac(x, &X);
+ float fy = floorfrac(y, &Y);
+ float fz = floorfrac(z, &Z);
+ float fw = floorfrac(w, &W);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float t = fade(fz);
+ float s = fade(fw);
+
+ float r = quad_mix(
+ grad4(hash_uint4(X, Y, Z, W), fx, fy, fz, fw),
+ grad4(hash_uint4(X + 1, Y, Z, W), fx - 1.0f, fy, fz, fw),
+ grad4(hash_uint4(X, Y + 1, Z, W), fx, fy - 1.0f, fz, fw),
+ grad4(hash_uint4(X + 1, Y + 1, Z, W), fx - 1.0f, fy - 1.0f, fz, fw),
+ grad4(hash_uint4(X, Y, Z + 1, W), fx, fy, fz - 1.0f, fw),
+ grad4(hash_uint4(X + 1, Y, Z + 1, W), fx - 1.0f, fy, fz - 1.0f, fw),
+ grad4(hash_uint4(X, Y + 1, Z + 1, W), fx, fy - 1.0f, fz - 1.0f, fw),
+ grad4(hash_uint4(X + 1, Y + 1, Z + 1, W), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw),
+ grad4(hash_uint4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0f),
+ grad4(hash_uint4(X + 1, Y, Z, W + 1), fx - 1.0f, fy, fz, fw - 1.0f),
+ grad4(hash_uint4(X, Y + 1, Z, W + 1), fx, fy - 1.0f, fz, fw - 1.0f),
+ grad4(hash_uint4(X + 1, Y + 1, Z, W + 1), fx - 1.0f, fy - 1.0f, fz, fw - 1.0f),
+ grad4(hash_uint4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0f, fw - 1.0f),
+ grad4(hash_uint4(X + 1, Y, Z + 1, W + 1), fx - 1.0f, fy, fz - 1.0f, fw - 1.0f),
+ grad4(hash_uint4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0f, fz - 1.0f, fw - 1.0f),
+ grad4(hash_uint4(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw - 1.0f),
+ u,
+ v,
+ t,
+ s);
+
+ return r;
+}
+
+#else /* SSE is supported. */
+
+/* ** SSE Implementation ** */
+
+/* SSE Bilinear Interpolation:
+ *
+ * The function takes two ssef inputs:
+ * - p : Contains the values at the points (v0, v1, v2, v3).
+ * - f : Contains the values (x, y, _, _). The third and fourth values are unused.
+ *
+ * The interpolation is done in two steps:
+ * 1. Interpolate (v0, v1) and (v2, v3) along the x axis to get g (g0, g1).
+ * (v2, v3) is generated by moving v2 and v3 to the first and second
+ * places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and
+ * fourth values are unused.
+ * 2. Interpolate g0 and g1 along the y axis to get the final value.
+ * g1 is generated by populating an ssef with the second value of g.
+ * Only the first value is important in the final ssef.
+ *
+ * v1 v3 g1
+ * @ + + + + @ @ y
+ * + + (1) + (2) ^
+ * + + ---> + ---> final |
+ * + + + |
+ * @ + + + + @ @ @------> x
+ * v0 v2 g0
+ *
+ */
+ccl_device_inline ssef bi_mix(ssef p, ssef f)
+{
+ ssef g = mix(p, shuffle<2, 3, 2, 3>(p), shuffle<0>(f));
+ return mix(g, shuffle<1>(g), shuffle<1>(f));
+}
+
+ccl_device_inline ssef fade(const ssef &t)
+{
+ ssef a = madd(t, 6.0f, -15.0f);
+ ssef b = madd(t, a, 10.0f);
+ return (t * t) * (t * b);
+}
+
+/* Negate val if the nth bit of h is 1. */
+# define negate_if_nth_bit(val, h, n) ((val) ^ cast(((h) & (1 << (n))) << (31 - (n))))
+
+ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y)
+{
+ ssei h = hash & 7;
+ ssef u = select(h < 4, x, y);
+ ssef v = 2.0f * select(h < 4, y, x);
+ return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
+}
+
+/* We use SSE to compute and interpolate 4 gradients at once:
+ *
+ * Point Offset from v0
+ * v0 (0, 0)
+ * v1 (0, 1)
+ * v2 (1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(V, V + 1))
+ * v3 (1, 1) ^
+ * | |__________| (0, 0, 1, 1) = shuffle<0, 0, 0, 0>(V, V + 1)
+ * | ^
+ * |__________________________|
+ *
+ */
+ccl_device_noinline_cpu float perlin_2d(float x, float y)
+{
+ ssei XY;
+ ssef fxy = floorfrac(ssef(x, y, 0.0f, 0.0f), &XY);
+ ssef uv = fade(fxy);
+
+ ssei XY1 = XY + 1;
+ ssei X = shuffle<0, 0, 0, 0>(XY, XY1);
+ ssei Y = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(XY, XY1));
+
+ ssei h = hash_ssei2(X, Y);
+
+ ssef fxy1 = fxy - 1.0f;
+ ssef fx = shuffle<0, 0, 0, 0>(fxy, fxy1);
+ ssef fy = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(fxy, fxy1));
+
+ ssef g = grad(h, fx, fy);
+
+ return extract<0>(bi_mix(g, uv));
+}
+
+/* SSE Trilinear Interpolation:
+ *
+ * The function takes three ssef inputs:
+ * - p : Contains the values at the points (v0, v1, v2, v3).
+ * - q : Contains the values at the points (v4, v5, v6, v7).
+ * - f : Contains the values (x, y, z, _). The fourth value is unused.
+ *
+ * The interpolation is done in three steps:
+ * 1. Interpolate p and q along the x axis to get s (s0, s1, s2, s3).
+ * 2. Interpolate (s0, s1) and (s2, s3) along the y axis to get g (g0, g1).
+ * (s2, s3) is generated by moving v2 and v3 to the first and second
+ * places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and
+ * fourth values are unused.
+ * 3. Interpolate g0 and g1 along the z axis to get the final value.
+ * g1 is generated by populating an ssef with the second value of g.
+ * Only the first value is important in the final ssef.
+ *
+ * v3 v7
+ * @ + + + + + + @ s3 @
+ * +\ +\ +\
+ * + \ + \ + \
+ * + \ + \ + \ g1
+ * + \ v1 + \ v5 + \ s1 @
+ * + @ + + + +++ + @ + @ + z
+ * + + + + (1) + + (2) + (3) y ^
+ * v2 @ + +++ + + + @ v6 + ---> s2 @ + ---> + ---> final \ |
+ * \ + \ + \ + + \ |
+ * \ + \ + \ + + \|
+ * \ + \ + \ + @ +---------> x
+ * \+ \+ \+ g0
+ * @ + + + + + + @ @
+ * v0 v4 s0
+ */
+ccl_device_inline ssef tri_mix(ssef p, ssef q, ssef f)
+{
+ ssef s = mix(p, q, shuffle<0>(f));
+ ssef g = mix(s, shuffle<2, 3, 2, 3>(s), shuffle<1>(f));
+ return mix(g, shuffle<1>(g), shuffle<2>(f));
+}
+
+/* 3D and 4D noise can be accelerated using AVX, so we first check if AVX
+ * is supported, that is, if __KERNEL_AVX__ is defined. If it is not
+ * supported, we do an SSE implementation, but if it is supported,
+ * we do an implementation using AVX intrinsics.
+ */
+# if !defined(__KERNEL_AVX__)
+
+ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z)
+{
+ ssei h = hash & 15;
+ ssef u = select(h < 8, x, y);
+ ssef vt = select((h == 12) | (h == 14), x, z);
+ ssef v = select(h < 4, y, vt);
+ return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
+}
+
+ccl_device_inline ssef
+grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z, const ssef &w)
+{
+ ssei h = hash & 31;
+ ssef u = select(h < 24, x, y);
+ ssef v = select(h < 16, y, z);
+ ssef s = select(h < 8, z, w);
+ return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1) + negate_if_nth_bit(s, h, 2);
+}
+
+/* SSE Quadrilinear Interpolation:
+ *
+ * Quadrilinear interpolation is as simple as a linear interpolation
+ * between two trilinear interpolations.
+ *
+ */
+ccl_device_inline ssef quad_mix(ssef p, ssef q, ssef r, ssef s, ssef f)
+{
+ return mix(tri_mix(p, q, f), tri_mix(r, s, f), shuffle<3>(f));
+}
+
+/* We use SSE to compute and interpolate 4 gradients at once. Since we have 8
+ * gradients in 3D, we need to compute two sets of gradients at the points:
+ *
+ * Point Offset from v0
+ * v0 (0, 0, 0)
+ * v1 (0, 0, 1)
+ * v2 (0, 1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
+ * v3 (0, 1, 1) ^
+ * | |__________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
+ * | ^
+ * |__________________________|
+ *
+ * Point Offset from v0
+ * v4 (1, 0, 0)
+ * v5 (1, 0, 1)
+ * v6 (1, 1, 0)
+ * v7 (1, 1, 1)
+ *
+ */
+ccl_device_noinline_cpu float perlin_3d(float x, float y, float z)
+{
+ ssei XYZ;
+ ssef fxyz = floorfrac(ssef(x, y, z, 0.0f), &XYZ);
+ ssef uvw = fade(fxyz);
+
+ ssei XYZ1 = XYZ + 1;
+ ssei Y = shuffle<1, 1, 1, 1>(XYZ, XYZ1);
+ ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ1));
+
+ ssei h1 = hash_ssei3(shuffle<0>(XYZ), Y, Z);
+ ssei h2 = hash_ssei3(shuffle<0>(XYZ1), Y, Z);
+
+ ssef fxyz1 = fxyz - 1.0f;
+ ssef fy = shuffle<1, 1, 1, 1>(fxyz, fxyz1);
+ ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz1));
+
+ ssef g1 = grad(h1, shuffle<0>(fxyz), fy, fz);
+ ssef g2 = grad(h2, shuffle<0>(fxyz1), fy, fz);
+
+ return extract<0>(tri_mix(g1, g2, uvw));
+}
+
+/* We use SSE to compute and interpolate 4 gradients at once. Since we have 16
+ * gradients in 4D, we need to compute four sets of gradients at the points:
+ *
+ * Point Offset from v0
+ * v0 (0, 0, 0, 0)
+ * v1 (0, 0, 1, 0)
+ * v2 (0, 1, 0, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
+ * v3 (0, 1, 1, 0) ^
+ * | |________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
+ * | ^
+ * |_______________________|
+ *
+ * Point Offset from v0
+ * v4 (1, 0, 0, 0)
+ * v5 (1, 0, 1, 0)
+ * v6 (1, 1, 0, 0)
+ * v7 (1, 1, 1, 0)
+ *
+ * Point Offset from v0
+ * v8 (0, 0, 0, 1)
+ * v9 (0, 0, 1, 1)
+ * v10 (0, 1, 0, 1)
+ * v11 (0, 1, 1, 1)
+ *
+ * Point Offset from v0
+ * v12 (1, 0, 0, 1)
+ * v13 (1, 0, 1, 1)
+ * v14 (1, 1, 0, 1)
+ * v15 (1, 1, 1, 1)
+ *
+ */
+ccl_device_noinline_cpu float perlin_4d(float x, float y, float z, float w)
+{
+ ssei XYZW;
+ ssef fxyzw = floorfrac(ssef(x, y, z, w), &XYZW);
+ ssef uvws = fade(fxyzw);
+
+ ssei XYZW1 = XYZW + 1;
+ ssei Y = shuffle<1, 1, 1, 1>(XYZW, XYZW1);
+ ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZW, XYZW1));
+
+ ssei h1 = hash_ssei4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW));
+ ssei h2 = hash_ssei4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW));
+
+ ssei h3 = hash_ssei4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW1));
+ ssei h4 = hash_ssei4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW1));
+
+ ssef fxyzw1 = fxyzw - 1.0f;
+ ssef fy = shuffle<1, 1, 1, 1>(fxyzw, fxyzw1);
+ ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyzw, fxyzw1));
+
+ ssef g1 = grad(h1, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw));
+ ssef g2 = grad(h2, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw));
+
+ ssef g3 = grad(h3, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw1));
+ ssef g4 = grad(h4, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw1));
+
+ return extract<0>(quad_mix(g1, g2, g3, g4, uvws));
+}
+
+# else /* AVX is supported. */
+
+/* AVX Implementation */
+
+ccl_device_inline avxf grad(const avxi &hash, const avxf &x, const avxf &y, const avxf &z)
+{
+ avxi h = hash & 15;
+ avxf u = select(h < 8, x, y);
+ avxf vt = select((h == 12) | (h == 14), x, z);
+ avxf v = select(h < 4, y, vt);
+ return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
+}
+
+ccl_device_inline avxf
+grad(const avxi &hash, const avxf &x, const avxf &y, const avxf &z, const avxf &w)
+{
+ avxi h = hash & 31;
+ avxf u = select(h < 24, x, y);
+ avxf v = select(h < 16, y, z);
+ avxf s = select(h < 8, z, w);
+ return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1) + negate_if_nth_bit(s, h, 2);
+}
+
+/* SSE Quadrilinear Interpolation:
+ *
+ * The interpolation is done in two steps:
+ * 1. Interpolate p and q along the w axis to get s.
+ * 2. Trilinearly interpolate (s0, s1, s2, s3) and (s4, s5, s6, s7) to get the final
+ * value. (s0, s1, s2, s3) and (s4, s5, s6, s7) are generated by extracting the
+ * low and high ssef from s.
+ *
+ */
+ccl_device_inline ssef quad_mix(avxf p, avxf q, ssef f)
+{
+ ssef fv = shuffle<3>(f);
+ avxf s = mix(p, q, avxf(fv, fv));
+ return tri_mix(low(s), high(s), f);
+}
+
+/* We use AVX to compute and interpolate 8 gradients at once.
+ *
+ * Point Offset from v0
+ * v0 (0, 0, 0)
+ * v1 (0, 0, 1) The full AVX type is computed by inserting the following
+ * v2 (0, 1, 0) SSE types into both the low and high parts of the AVX.
+ * v3 (0, 1, 1)
+ * v4 (1, 0, 0)
+ * v5 (1, 0, 1) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
+ * v6 (1, 1, 0) ^
+ * v7 (1, 1, 1) |
+ * | |__________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
+ * | ^
+ * |__________________________|
+ *
+ */
+ccl_device_noinline_cpu float perlin_3d(float x, float y, float z)
+{
+ ssei XYZ;
+ ssef fxyz = floorfrac(ssef(x, y, z, 0.0f), &XYZ);
+ ssef uvw = fade(fxyz);
+
+ ssei XYZ1 = XYZ + 1;
+ ssei X = shuffle<0>(XYZ);
+ ssei X1 = shuffle<0>(XYZ1);
+ ssei Y = shuffle<1, 1, 1, 1>(XYZ, XYZ1);
+ ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ1));
+
+ avxi h = hash_avxi3(avxi(X, X1), avxi(Y, Y), avxi(Z, Z));
+
+ ssef fxyz1 = fxyz - 1.0f;
+ ssef fx = shuffle<0>(fxyz);
+ ssef fx1 = shuffle<0>(fxyz1);
+ ssef fy = shuffle<1, 1, 1, 1>(fxyz, fxyz1);
+ ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz1));
+
+ avxf g = grad(h, avxf(fx, fx1), avxf(fy, fy), avxf(fz, fz));
+
+ return extract<0>(tri_mix(low(g), high(g), uvw));
+}
+
+/* We use AVX to compute and interpolate 8 gradients at once. Since we have 16
+ * gradients in 4D, we need to compute two sets of gradients at the points:
+ *
+ * Point Offset from v0
+ * v0 (0, 0, 0, 0)
+ * v1 (0, 0, 1, 0) The full AVX type is computed by inserting the following
+ * v2 (0, 1, 0, 0) SSE types into both the low and high parts of the AVX.
+ * v3 (0, 1, 1, 0)
+ * v4 (1, 0, 0, 0)
+ * v5 (1, 0, 1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
+ * v6 (1, 1, 0, 0) ^
+ * v7 (1, 1, 1, 0) |
+ * | |________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
+ * | ^
+ * |_______________________|
+ *
+ * Point Offset from v0
+ * v8 (0, 0, 0, 1)
+ * v9 (0, 0, 1, 1)
+ * v10 (0, 1, 0, 1)
+ * v11 (0, 1, 1, 1)
+ * v12 (1, 0, 0, 1)
+ * v13 (1, 0, 1, 1)
+ * v14 (1, 1, 0, 1)
+ * v15 (1, 1, 1, 1)
+ *
+ */
+ccl_device_noinline_cpu float perlin_4d(float x, float y, float z, float w)
+{
+ ssei XYZW;
+ ssef fxyzw = floorfrac(ssef(x, y, z, w), &XYZW);
+ ssef uvws = fade(fxyzw);
+
+ ssei XYZW1 = XYZW + 1;
+ ssei X = shuffle<0>(XYZW);
+ ssei X1 = shuffle<0>(XYZW1);
+ ssei Y = shuffle<1, 1, 1, 1>(XYZW, XYZW1);
+ ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZW, XYZW1));
+ ssei W = shuffle<3>(XYZW);
+ ssei W1 = shuffle<3>(XYZW1);
+
+ avxi h1 = hash_avxi4(avxi(X, X1), avxi(Y, Y), avxi(Z, Z), avxi(W, W));
+ avxi h2 = hash_avxi4(avxi(X, X1), avxi(Y, Y), avxi(Z, Z), avxi(W1, W1));
+
+ ssef fxyzw1 = fxyzw - 1.0f;
+ ssef fx = shuffle<0>(fxyzw);
+ ssef fx1 = shuffle<0>(fxyzw1);
+ ssef fy = shuffle<1, 1, 1, 1>(fxyzw, fxyzw1);
+ ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyzw, fxyzw1));
+ ssef fw = shuffle<3>(fxyzw);
+ ssef fw1 = shuffle<3>(fxyzw1);
+
+ avxf g1 = grad(h1, avxf(fx, fx1), avxf(fy, fy), avxf(fz, fz), avxf(fw, fw));
+ avxf g2 = grad(h2, avxf(fx, fx1), avxf(fy, fy), avxf(fz, fz), avxf(fw1, fw1));
+
+ return extract<0>(quad_mix(g1, g2, uvws));
+}
+# endif
+
+# undef negate_if_nth_bit
+
+#endif
+
+/* Remap the output of noise to a predictable range [-1, 1].
+ * The scale values were computed experimentally by the OSL developers.
+ */
+
+ccl_device_inline float noise_scale1(float result)
+{
+ return 0.2500f * result;
+}
+
+ccl_device_inline float noise_scale2(float result)
+{
+ return 0.6616f * result;
+}
+
+ccl_device_inline float noise_scale3(float result)
+{
+ return 0.9820f * result;
+}
+
+ccl_device_inline float noise_scale4(float result)
+{
+ return 0.8344f * result;
+}
+
+/* Safe Signed And Unsigned Noise */
+
+ccl_device_inline float snoise_1d(float p)
+{
+ return noise_scale1(ensure_finite(perlin_1d(p)));
+}
+
+ccl_device_inline float noise_1d(float p)
+{
+ return 0.5f * snoise_1d(p) + 0.5f;
+}
+
+ccl_device_inline float snoise_2d(float2 p)
+{
+ return noise_scale2(ensure_finite(perlin_2d(p.x, p.y)));
+}
+
+ccl_device_inline float noise_2d(float2 p)
+{
+ return 0.5f * snoise_2d(p) + 0.5f;
+}
+
+ccl_device_inline float snoise_3d(float3 p)
+{
+ return noise_scale3(ensure_finite(perlin_3d(p.x, p.y, p.z)));
+}
+
+ccl_device_inline float noise_3d(float3 p)
+{
+ return 0.5f * snoise_3d(p) + 0.5f;
+}
+
+ccl_device_inline float snoise_4d(float4 p)
+{
+ return noise_scale4(ensure_finite(perlin_4d(p.x, p.y, p.z, p.w)));
+}
+
+ccl_device_inline float noise_4d(float4 p)
+{
+ return 0.5f * snoise_4d(p) + 0.5f;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/noisetex.h b/intern/cycles/kernel/svm/noisetex.h
new file mode 100644
index 00000000000..c43c3b9f9d2
--- /dev/null
+++ b/intern/cycles/kernel/svm/noisetex.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/svm/fractal_noise.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* The following offset functions generate random offsets to be added to texture
+ * coordinates to act as a seed since the noise functions don't have seed values.
+ * A seed value is needed for generating distortion textures and color outputs.
+ * The offset's components are in the range [100, 200], not too high to cause
+ * bad precision and not too small to be noticeable. We use float seed because
+ * OSL only support float hashes.
+ */
+
+ccl_device_inline float random_float_offset(float seed)
+{
+ return 100.0f + hash_float_to_float(seed) * 100.0f;
+}
+
+ccl_device_inline float2 random_float2_offset(float seed)
+{
+ return make_float2(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f);
+}
+
+ccl_device_inline float3 random_float3_offset(float seed)
+{
+ return make_float3(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f);
+}
+
+ccl_device_inline float4 random_float4_offset(float seed)
+{
+ return make_float4(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 3.0f)) * 100.0f);
+}
+
+ccl_device void noise_texture_1d(float co,
+ float detail,
+ float roughness,
+ float distortion,
+ bool color_is_needed,
+ ccl_private float *value,
+ ccl_private float3 *color)
+{
+ float p = co;
+ if (distortion != 0.0f) {
+ p += snoise_1d(p + random_float_offset(0.0f)) * distortion;
+ }
+
+ *value = fractal_noise_1d(p, detail, roughness);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ fractal_noise_1d(p + random_float_offset(1.0f), detail, roughness),
+ fractal_noise_1d(p + random_float_offset(2.0f), detail, roughness));
+ }
+}
+
+ccl_device void noise_texture_2d(float2 co,
+ float detail,
+ float roughness,
+ float distortion,
+ bool color_is_needed,
+ ccl_private float *value,
+ ccl_private float3 *color)
+{
+ float2 p = co;
+ if (distortion != 0.0f) {
+ p += make_float2(snoise_2d(p + random_float2_offset(0.0f)) * distortion,
+ snoise_2d(p + random_float2_offset(1.0f)) * distortion);
+ }
+
+ *value = fractal_noise_2d(p, detail, roughness);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ fractal_noise_2d(p + random_float2_offset(2.0f), detail, roughness),
+ fractal_noise_2d(p + random_float2_offset(3.0f), detail, roughness));
+ }
+}
+
+ccl_device void noise_texture_3d(float3 co,
+ float detail,
+ float roughness,
+ float distortion,
+ bool color_is_needed,
+ ccl_private float *value,
+ ccl_private float3 *color)
+{
+ float3 p = co;
+ if (distortion != 0.0f) {
+ p += make_float3(snoise_3d(p + random_float3_offset(0.0f)) * distortion,
+ snoise_3d(p + random_float3_offset(1.0f)) * distortion,
+ snoise_3d(p + random_float3_offset(2.0f)) * distortion);
+ }
+
+ *value = fractal_noise_3d(p, detail, roughness);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ fractal_noise_3d(p + random_float3_offset(3.0f), detail, roughness),
+ fractal_noise_3d(p + random_float3_offset(4.0f), detail, roughness));
+ }
+}
+
+ccl_device void noise_texture_4d(float4 co,
+ float detail,
+ float roughness,
+ float distortion,
+ bool color_is_needed,
+ ccl_private float *value,
+ ccl_private float3 *color)
+{
+ float4 p = co;
+ if (distortion != 0.0f) {
+ p += make_float4(snoise_4d(p + random_float4_offset(0.0f)) * distortion,
+ snoise_4d(p + random_float4_offset(1.0f)) * distortion,
+ snoise_4d(p + random_float4_offset(2.0f)) * distortion,
+ snoise_4d(p + random_float4_offset(3.0f)) * distortion);
+ }
+
+ *value = fractal_noise_4d(p, detail, roughness);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ fractal_noise_4d(p + random_float4_offset(4.0f), detail, roughness),
+ fractal_noise_4d(p + random_float4_offset(5.0f), detail, roughness));
+ }
+}
+
+ccl_device_noinline int svm_node_tex_noise(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint dimensions,
+ uint offsets1,
+ uint offsets2,
+ int offset)
+{
+ uint vector_stack_offset, w_stack_offset, scale_stack_offset;
+ uint detail_stack_offset, roughness_stack_offset, distortion_stack_offset;
+ uint value_stack_offset, color_stack_offset;
+
+ svm_unpack_node_uchar4(
+ offsets1, &vector_stack_offset, &w_stack_offset, &scale_stack_offset, &detail_stack_offset);
+ svm_unpack_node_uchar4(offsets2,
+ &roughness_stack_offset,
+ &distortion_stack_offset,
+ &value_stack_offset,
+ &color_stack_offset);
+
+ uint4 defaults1 = read_node(kg, &offset);
+ uint4 defaults2 = read_node(kg, &offset);
+
+ float3 vector = stack_load_float3(stack, vector_stack_offset);
+ float w = stack_load_float_default(stack, w_stack_offset, defaults1.x);
+ float scale = stack_load_float_default(stack, scale_stack_offset, defaults1.y);
+ float detail = stack_load_float_default(stack, detail_stack_offset, defaults1.z);
+ float roughness = stack_load_float_default(stack, roughness_stack_offset, defaults1.w);
+ float distortion = stack_load_float_default(stack, distortion_stack_offset, defaults2.x);
+
+ vector *= scale;
+ w *= scale;
+
+ float value;
+ float3 color;
+ switch (dimensions) {
+ case 1:
+ noise_texture_1d(
+ w, detail, roughness, distortion, stack_valid(color_stack_offset), &value, &color);
+ break;
+ case 2:
+ noise_texture_2d(make_float2(vector.x, vector.y),
+ detail,
+ roughness,
+ distortion,
+ stack_valid(color_stack_offset),
+ &value,
+ &color);
+ break;
+ case 3:
+ noise_texture_3d(
+ vector, detail, roughness, distortion, stack_valid(color_stack_offset), &value, &color);
+ break;
+ case 4:
+ noise_texture_4d(make_float4(vector.x, vector.y, vector.z, w),
+ detail,
+ roughness,
+ distortion,
+ stack_valid(color_stack_offset),
+ &value,
+ &color);
+ break;
+ default:
+ kernel_assert(0);
+ }
+
+ if (stack_valid(value_stack_offset)) {
+ stack_store_float(stack, value_stack_offset, value);
+ }
+ if (stack_valid(color_stack_offset)) {
+ stack_store_float3(stack, color_stack_offset, color);
+ }
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/normal.h b/intern/cycles/kernel/svm/normal.h
new file mode 100644
index 00000000000..6a2d88b68a6
--- /dev/null
+++ b/intern/cycles/kernel/svm/normal.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline int svm_node_normal(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint in_normal_offset,
+ uint out_normal_offset,
+ uint out_dot_offset,
+ int offset)
+{
+ /* read extra data */
+ uint4 node1 = read_node(kg, &offset);
+ float3 normal = stack_load_float3(stack, in_normal_offset);
+
+ float3 direction;
+ direction.x = __int_as_float(node1.x);
+ direction.y = __int_as_float(node1.y);
+ direction.z = __int_as_float(node1.z);
+ direction = normalize(direction);
+
+ if (stack_valid(out_normal_offset))
+ stack_store_float3(stack, out_normal_offset, direction);
+
+ if (stack_valid(out_dot_offset))
+ stack_store_float(stack, out_dot_offset, dot(direction, normalize(normal)));
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/ramp.h b/intern/cycles/kernel/svm/ramp.h
new file mode 100644
index 00000000000..61093e0bd82
--- /dev/null
+++ b/intern/cycles/kernel/svm/ramp.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
+
+ccl_device_inline float fetch_float(KernelGlobals kg, int offset)
+{
+ uint4 node = kernel_tex_fetch(__svm_nodes, offset);
+ return __uint_as_float(node.x);
+}
+
+ccl_device_inline float float_ramp_lookup(
+ KernelGlobals kg, int offset, float f, bool interpolate, bool extrapolate, int table_size)
+{
+ if ((f < 0.0f || f > 1.0f) && extrapolate) {
+ float t0, dy;
+ if (f < 0.0f) {
+ t0 = fetch_float(kg, offset);
+ dy = t0 - fetch_float(kg, offset + 1);
+ f = -f;
+ }
+ else {
+ t0 = fetch_float(kg, offset + table_size - 1);
+ dy = t0 - fetch_float(kg, offset + table_size - 2);
+ f = f - 1.0f;
+ }
+ return t0 + dy * f * (table_size - 1);
+ }
+
+ f = saturatef(f) * (table_size - 1);
+
+ /* clamp int as well in case of NaN */
+ int i = clamp(float_to_int(f), 0, table_size - 1);
+ float t = f - (float)i;
+
+ float a = fetch_float(kg, offset + i);
+
+ if (interpolate && t > 0.0f)
+ a = (1.0f - t) * a + t * fetch_float(kg, offset + i + 1);
+
+ return a;
+}
+
+ccl_device_inline float4 rgb_ramp_lookup(
+ KernelGlobals kg, int offset, float f, bool interpolate, bool extrapolate, int table_size)
+{
+ if ((f < 0.0f || f > 1.0f) && extrapolate) {
+ float4 t0, dy;
+ if (f < 0.0f) {
+ t0 = fetch_node_float(kg, offset);
+ dy = t0 - fetch_node_float(kg, offset + 1);
+ f = -f;
+ }
+ else {
+ t0 = fetch_node_float(kg, offset + table_size - 1);
+ dy = t0 - fetch_node_float(kg, offset + table_size - 2);
+ f = f - 1.0f;
+ }
+ return t0 + dy * f * (table_size - 1);
+ }
+
+ f = saturatef(f) * (table_size - 1);
+
+ /* clamp int as well in case of NaN */
+ int i = clamp(float_to_int(f), 0, table_size - 1);
+ float t = f - (float)i;
+
+ float4 a = fetch_node_float(kg, offset + i);
+
+ if (interpolate && t > 0.0f)
+ a = (1.0f - t) * a + t * fetch_node_float(kg, offset + i + 1);
+
+ return a;
+}
+
+ccl_device_noinline int svm_node_rgb_ramp(
+ KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
+{
+ uint fac_offset, color_offset, alpha_offset;
+ uint interpolate = node.z;
+
+ svm_unpack_node_uchar3(node.y, &fac_offset, &color_offset, &alpha_offset);
+
+ uint table_size = read_node(kg, &offset).x;
+
+ float fac = stack_load_float(stack, fac_offset);
+ float4 color = rgb_ramp_lookup(kg, offset, fac, interpolate, false, table_size);
+
+ if (stack_valid(color_offset))
+ stack_store_float3(stack, color_offset, float4_to_float3(color));
+ if (stack_valid(alpha_offset))
+ stack_store_float(stack, alpha_offset, color.w);
+
+ offset += table_size;
+ return offset;
+}
+
+ccl_device_noinline int svm_node_curves(
+ KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
+{
+ uint fac_offset, color_offset, out_offset;
+ svm_unpack_node_uchar3(node.y, &fac_offset, &color_offset, &out_offset);
+
+ uint table_size = read_node(kg, &offset).x;
+
+ float fac = stack_load_float(stack, fac_offset);
+ float3 color = stack_load_float3(stack, color_offset);
+
+ const float min_x = __int_as_float(node.z), max_x = __int_as_float(node.w);
+ const float range_x = max_x - min_x;
+ const float3 relpos = (color - make_float3(min_x, min_x, min_x)) / range_x;
+
+ float r = rgb_ramp_lookup(kg, offset, relpos.x, true, true, table_size).x;
+ float g = rgb_ramp_lookup(kg, offset, relpos.y, true, true, table_size).y;
+ float b = rgb_ramp_lookup(kg, offset, relpos.z, true, true, table_size).z;
+
+ color = (1.0f - fac) * color + fac * make_float3(r, g, b);
+ stack_store_float3(stack, out_offset, color);
+
+ offset += table_size;
+ return offset;
+}
+
+ccl_device_noinline int svm_node_curve(
+ KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
+{
+ uint fac_offset, value_in_offset, out_offset;
+ svm_unpack_node_uchar3(node.y, &fac_offset, &value_in_offset, &out_offset);
+
+ uint table_size = read_node(kg, &offset).x;
+
+ float fac = stack_load_float(stack, fac_offset);
+ float in = stack_load_float(stack, value_in_offset);
+
+ const float min = __int_as_float(node.z), max = __int_as_float(node.w);
+ const float range = max - min;
+ const float relpos = (in - min) / range;
+
+ float v = float_ramp_lookup(kg, offset, relpos, true, true, table_size);
+
+ in = (1.0f - fac) * in + fac * v;
+ stack_store_float(stack, out_offset, in);
+
+ offset += table_size;
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/ramp_util.h b/intern/cycles/kernel/svm/ramp_util.h
new file mode 100644
index 00000000000..f5951f7e283
--- /dev/null
+++ b/intern/cycles/kernel/svm/ramp_util.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
+
+ccl_device_inline float3
+rgb_ramp_lookup(const float3 *ramp, float f, bool interpolate, bool extrapolate, int table_size)
+{
+ if ((f < 0.0f || f > 1.0f) && extrapolate) {
+ float3 t0, dy;
+ if (f < 0.0f) {
+ t0 = ramp[0];
+ dy = t0 - ramp[1], f = -f;
+ }
+ else {
+ t0 = ramp[table_size - 1];
+ dy = t0 - ramp[table_size - 2];
+ f = f - 1.0f;
+ }
+ return t0 + dy * f * (table_size - 1);
+ }
+
+ f = clamp(f, 0.0f, 1.0f) * (table_size - 1);
+
+ /* clamp int as well in case of NaN */
+ int i = clamp(float_to_int(f), 0, table_size - 1);
+ float t = f - (float)i;
+
+ float3 result = ramp[i];
+
+ if (interpolate && t > 0.0f) {
+ result = (1.0f - t) * result + t * ramp[i + 1];
+ }
+
+ return result;
+}
+
+ccl_device float float_ramp_lookup(
+ const float *ramp, float f, bool interpolate, bool extrapolate, int table_size)
+{
+ if ((f < 0.0f || f > 1.0f) && extrapolate) {
+ float t0, dy;
+ if (f < 0.0f) {
+ t0 = ramp[0];
+ dy = t0 - ramp[1], f = -f;
+ }
+ else {
+ t0 = ramp[table_size - 1];
+ dy = t0 - ramp[table_size - 2];
+ f = f - 1.0f;
+ }
+ return t0 + dy * f * (table_size - 1);
+ }
+
+ f = clamp(f, 0.0f, 1.0f) * (table_size - 1);
+
+ /* clamp int as well in case of NaN */
+ int i = clamp(float_to_int(f), 0, table_size - 1);
+ float t = f - (float)i;
+
+ float result = ramp[i];
+
+ if (interpolate && t > 0.0f) {
+ result = (1.0f - t) * result + t * ramp[i + 1];
+ }
+
+ return result;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/sepcomb_hsv.h b/intern/cycles/kernel/svm/sepcomb_hsv.h
new file mode 100644
index 00000000000..941a83e85b3
--- /dev/null
+++ b/intern/cycles/kernel/svm/sepcomb_hsv.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline int svm_node_combine_hsv(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint hue_in,
+ uint saturation_in,
+ uint value_in,
+ int offset)
+{
+ uint4 node1 = read_node(kg, &offset);
+ uint color_out = node1.y;
+
+ float hue = stack_load_float(stack, hue_in);
+ float saturation = stack_load_float(stack, saturation_in);
+ float value = stack_load_float(stack, value_in);
+
+ /* Combine, and convert back to RGB */
+ float3 color = hsv_to_rgb(make_float3(hue, saturation, value));
+
+ if (stack_valid(color_out))
+ stack_store_float3(stack, color_out, color);
+ return offset;
+}
+
+ccl_device_noinline int svm_node_separate_hsv(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint color_in,
+ uint hue_out,
+ uint saturation_out,
+ int offset)
+{
+ uint4 node1 = read_node(kg, &offset);
+ uint value_out = node1.y;
+
+ float3 color = stack_load_float3(stack, color_in);
+
+ /* Convert to HSV */
+ color = rgb_to_hsv(color);
+
+ if (stack_valid(hue_out))
+ stack_store_float(stack, hue_out, color.x);
+ if (stack_valid(saturation_out))
+ stack_store_float(stack, saturation_out, color.y);
+ if (stack_valid(value_out))
+ stack_store_float(stack, value_out, color.z);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/sepcomb_vector.h b/intern/cycles/kernel/svm/sepcomb_vector.h
new file mode 100644
index 00000000000..acdea741aed
--- /dev/null
+++ b/intern/cycles/kernel/svm/sepcomb_vector.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011-2014 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Vector combine / separate, used for the RGB and XYZ nodes */
+
+ccl_device void svm_node_combine_vector(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint in_offset,
+ uint vector_index,
+ uint out_offset)
+{
+ float vector = stack_load_float(stack, in_offset);
+
+ if (stack_valid(out_offset))
+ stack_store_float(stack, out_offset + vector_index, vector);
+}
+
+ccl_device void svm_node_separate_vector(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint ivector_offset,
+ uint vector_index,
+ uint out_offset)
+{
+ float3 vector = stack_load_float3(stack, ivector_offset);
+
+ if (stack_valid(out_offset)) {
+ if (vector_index == 0)
+ stack_store_float(stack, out_offset, vector.x);
+ else if (vector_index == 1)
+ stack_store_float(stack, out_offset, vector.y);
+ else
+ stack_store_float(stack, out_offset, vector.z);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/sky.h b/intern/cycles/kernel/svm/sky.h
new file mode 100644
index 00000000000..867fdfc2a3f
--- /dev/null
+++ b/intern/cycles/kernel/svm/sky.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Sky texture */
+
+ccl_device float sky_angle_between(float thetav, float phiv, float theta, float phi)
+{
+ float cospsi = sinf(thetav) * sinf(theta) * cosf(phi - phiv) + cosf(thetav) * cosf(theta);
+ return safe_acosf(cospsi);
+}
+
+/*
+ * "A Practical Analytic Model for Daylight"
+ * A. J. Preetham, Peter Shirley, Brian Smits
+ */
+ccl_device float sky_perez_function(ccl_private float *lam, float theta, float gamma)
+{
+ float ctheta = cosf(theta);
+ float cgamma = cosf(gamma);
+
+ return (1.0f + lam[0] * expf(lam[1] / ctheta)) *
+ (1.0f + lam[2] * expf(lam[3] * gamma) + lam[4] * cgamma * cgamma);
+}
+
+ccl_device float3 sky_radiance_preetham(KernelGlobals kg,
+ float3 dir,
+ float sunphi,
+ float suntheta,
+ float radiance_x,
+ float radiance_y,
+ float radiance_z,
+ ccl_private float *config_x,
+ ccl_private float *config_y,
+ ccl_private float *config_z)
+{
+ /* convert vector to spherical coordinates */
+ float2 spherical = direction_to_spherical(dir);
+ float theta = spherical.x;
+ float phi = spherical.y;
+
+ /* angle between sun direction and dir */
+ float gamma = sky_angle_between(theta, phi, suntheta, sunphi);
+
+ /* clamp theta to horizon */
+ theta = min(theta, M_PI_2_F - 0.001f);
+
+ /* compute xyY color space values */
+ float x = radiance_y * sky_perez_function(config_y, theta, gamma);
+ float y = radiance_z * sky_perez_function(config_z, theta, gamma);
+ float Y = radiance_x * sky_perez_function(config_x, theta, gamma);
+
+ /* convert to RGB */
+ float3 xyz = xyY_to_xyz(x, y, Y);
+ return xyz_to_rgb(kg, xyz);
+}
+
+/*
+ * "An Analytic Model for Full Spectral Sky-Dome Radiance"
+ * Lukas Hosek, Alexander Wilkie
+ */
+ccl_device float sky_radiance_internal(ccl_private float *configuration, float theta, float gamma)
+{
+ float ctheta = cosf(theta);
+ float cgamma = cosf(gamma);
+
+ float expM = expf(configuration[4] * gamma);
+ float rayM = cgamma * cgamma;
+ float mieM = (1.0f + rayM) / powf((1.0f + configuration[8] * configuration[8] -
+ 2.0f * configuration[8] * cgamma),
+ 1.5f);
+ float zenith = sqrtf(ctheta);
+
+ return (1.0f + configuration[0] * expf(configuration[1] / (ctheta + 0.01f))) *
+ (configuration[2] + configuration[3] * expM + configuration[5] * rayM +
+ configuration[6] * mieM + configuration[7] * zenith);
+}
+
+ccl_device float3 sky_radiance_hosek(KernelGlobals kg,
+ float3 dir,
+ float sunphi,
+ float suntheta,
+ float radiance_x,
+ float radiance_y,
+ float radiance_z,
+ ccl_private float *config_x,
+ ccl_private float *config_y,
+ ccl_private float *config_z)
+{
+ /* convert vector to spherical coordinates */
+ float2 spherical = direction_to_spherical(dir);
+ float theta = spherical.x;
+ float phi = spherical.y;
+
+ /* angle between sun direction and dir */
+ float gamma = sky_angle_between(theta, phi, suntheta, sunphi);
+
+ /* clamp theta to horizon */
+ theta = min(theta, M_PI_2_F - 0.001f);
+
+ /* compute xyz color space values */
+ float x = sky_radiance_internal(config_x, theta, gamma) * radiance_x;
+ float y = sky_radiance_internal(config_y, theta, gamma) * radiance_y;
+ float z = sky_radiance_internal(config_z, theta, gamma) * radiance_z;
+
+ /* convert to RGB and adjust strength */
+ return xyz_to_rgb(kg, make_float3(x, y, z)) * (M_2PI_F / 683);
+}
+
+/* Nishita improved sky model */
+ccl_device float3 geographical_to_direction(float lat, float lon)
+{
+ return make_float3(cos(lat) * cos(lon), cos(lat) * sin(lon), sin(lat));
+}
+
+ccl_device float3 sky_radiance_nishita(KernelGlobals kg,
+ float3 dir,
+ ccl_private float *nishita_data,
+ uint texture_id)
+{
+ /* definitions */
+ float sun_elevation = nishita_data[6];
+ float sun_rotation = nishita_data[7];
+ float angular_diameter = nishita_data[8];
+ float sun_intensity = nishita_data[9];
+ bool sun_disc = (angular_diameter >= 0.0f);
+ float3 xyz;
+ /* convert dir to spherical coordinates */
+ float2 direction = direction_to_spherical(dir);
+
+ /* render above the horizon */
+ if (dir.z >= 0.0f) {
+ /* definitions */
+ float3 sun_dir = geographical_to_direction(sun_elevation, sun_rotation + M_PI_2_F);
+ float sun_dir_angle = precise_angle(dir, sun_dir);
+ float half_angular = angular_diameter / 2.0f;
+ float dir_elevation = M_PI_2_F - direction.x;
+
+ /* if ray inside sun disc render it, otherwise render sky */
+ if (sun_disc && sun_dir_angle < half_angular) {
+ /* get 2 pixels data */
+ float3 pixel_bottom = make_float3(nishita_data[0], nishita_data[1], nishita_data[2]);
+ float3 pixel_top = make_float3(nishita_data[3], nishita_data[4], nishita_data[5]);
+ float y;
+
+ /* sun interpolation */
+ if (sun_elevation - half_angular > 0.0f) {
+ if (sun_elevation + half_angular > 0.0f) {
+ y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f;
+ xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity;
+ }
+ }
+ else {
+ if (sun_elevation + half_angular > 0.0f) {
+ y = dir_elevation / (sun_elevation + half_angular);
+ xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity;
+ }
+ }
+ /* limb darkening, coefficient is 0.6f */
+ float limb_darkening = (1.0f -
+ 0.6f * (1.0f - sqrtf(1.0f - sqr(sun_dir_angle / half_angular))));
+ xyz *= limb_darkening;
+ }
+ /* sky */
+ else {
+ /* sky interpolation */
+ float x = (direction.y + M_PI_F + sun_rotation) / M_2PI_F;
+ /* more pixels toward horizon compensation */
+ float y = safe_sqrtf(dir_elevation / M_PI_2_F);
+ if (x > 1.0f) {
+ x -= 1.0f;
+ }
+ xyz = float4_to_float3(kernel_tex_image_interp(kg, texture_id, x, y));
+ }
+ }
+ /* ground */
+ else {
+ if (dir.z < -0.4f) {
+ xyz = make_float3(0.0f, 0.0f, 0.0f);
+ }
+ else {
+ /* black ground fade */
+ float fade = 1.0f + dir.z * 2.5f;
+ fade = sqr(fade) * fade;
+ /* interpolation */
+ float x = (direction.y + M_PI_F + sun_rotation) / M_2PI_F;
+ if (x > 1.0f) {
+ x -= 1.0f;
+ }
+ xyz = float4_to_float3(kernel_tex_image_interp(kg, texture_id, x, -0.5)) * fade;
+ }
+ }
+
+ /* convert to RGB */
+ return xyz_to_rgb(kg, xyz);
+}
+
+ccl_device_noinline int svm_node_tex_sky(
+ KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
+{
+ /* Load data */
+ uint dir_offset = node.y;
+ uint out_offset = node.z;
+ int sky_model = node.w;
+
+ float3 dir = stack_load_float3(stack, dir_offset);
+ float3 f;
+
+ /* Preetham and Hosek share the same data */
+ if (sky_model == 0 || sky_model == 1) {
+ /* Define variables */
+ float sunphi, suntheta, radiance_x, radiance_y, radiance_z;
+ float config_x[9], config_y[9], config_z[9];
+
+ float4 data = read_node_float(kg, &offset);
+ sunphi = data.x;
+ suntheta = data.y;
+ radiance_x = data.z;
+ radiance_y = data.w;
+
+ data = read_node_float(kg, &offset);
+ radiance_z = data.x;
+ config_x[0] = data.y;
+ config_x[1] = data.z;
+ config_x[2] = data.w;
+
+ data = read_node_float(kg, &offset);
+ config_x[3] = data.x;
+ config_x[4] = data.y;
+ config_x[5] = data.z;
+ config_x[6] = data.w;
+
+ data = read_node_float(kg, &offset);
+ config_x[7] = data.x;
+ config_x[8] = data.y;
+ config_y[0] = data.z;
+ config_y[1] = data.w;
+
+ data = read_node_float(kg, &offset);
+ config_y[2] = data.x;
+ config_y[3] = data.y;
+ config_y[4] = data.z;
+ config_y[5] = data.w;
+
+ data = read_node_float(kg, &offset);
+ config_y[6] = data.x;
+ config_y[7] = data.y;
+ config_y[8] = data.z;
+ config_z[0] = data.w;
+
+ data = read_node_float(kg, &offset);
+ config_z[1] = data.x;
+ config_z[2] = data.y;
+ config_z[3] = data.z;
+ config_z[4] = data.w;
+
+ data = read_node_float(kg, &offset);
+ config_z[5] = data.x;
+ config_z[6] = data.y;
+ config_z[7] = data.z;
+ config_z[8] = data.w;
+
+ /* Compute Sky */
+ if (sky_model == 0) {
+ f = sky_radiance_preetham(kg,
+ dir,
+ sunphi,
+ suntheta,
+ radiance_x,
+ radiance_y,
+ radiance_z,
+ config_x,
+ config_y,
+ config_z);
+ }
+ else {
+ f = sky_radiance_hosek(kg,
+ dir,
+ sunphi,
+ suntheta,
+ radiance_x,
+ radiance_y,
+ radiance_z,
+ config_x,
+ config_y,
+ config_z);
+ }
+ }
+ /* Nishita */
+ else {
+ /* Define variables */
+ float nishita_data[10];
+
+ float4 data = read_node_float(kg, &offset);
+ nishita_data[0] = data.x;
+ nishita_data[1] = data.y;
+ nishita_data[2] = data.z;
+ nishita_data[3] = data.w;
+
+ data = read_node_float(kg, &offset);
+ nishita_data[4] = data.x;
+ nishita_data[5] = data.y;
+ nishita_data[6] = data.z;
+ nishita_data[7] = data.w;
+
+ data = read_node_float(kg, &offset);
+ nishita_data[8] = data.x;
+ nishita_data[9] = data.y;
+ uint texture_id = __float_as_uint(data.z);
+
+ /* Compute Sky */
+ f = sky_radiance_nishita(kg, dir, nishita_data, texture_id);
+ }
+
+ stack_store_float3(stack, out_offset, f);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 472f3517839..62ba5bf04e3 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef __SVM_H__
-#define __SVM_H__
+#pragma once
/* Shader Virtual Machine
*
@@ -38,7 +37,7 @@
* mostly taken care of in the SVM compiler.
*/
-#include "kernel/svm/svm_types.h"
+#include "kernel/svm/types.h"
CCL_NAMESPACE_BEGIN
@@ -165,61 +164,54 @@ CCL_NAMESPACE_END
/* Nodes */
-#include "kernel/svm/svm_noise.h"
-#include "svm_fractal_noise.h"
-
-#include "kernel/svm/svm_color_util.h"
-#include "kernel/svm/svm_mapping_util.h"
-#include "kernel/svm/svm_math_util.h"
-
-#include "kernel/svm/svm_aov.h"
-#include "kernel/svm/svm_attribute.h"
-#include "kernel/svm/svm_blackbody.h"
-#include "kernel/svm/svm_brick.h"
-#include "kernel/svm/svm_brightness.h"
-#include "kernel/svm/svm_bump.h"
-#include "kernel/svm/svm_camera.h"
-#include "kernel/svm/svm_checker.h"
-#include "kernel/svm/svm_clamp.h"
-#include "kernel/svm/svm_closure.h"
-#include "kernel/svm/svm_convert.h"
-#include "kernel/svm/svm_displace.h"
-#include "kernel/svm/svm_fresnel.h"
-#include "kernel/svm/svm_gamma.h"
-#include "kernel/svm/svm_geometry.h"
-#include "kernel/svm/svm_gradient.h"
-#include "kernel/svm/svm_hsv.h"
-#include "kernel/svm/svm_ies.h"
-#include "kernel/svm/svm_image.h"
-#include "kernel/svm/svm_invert.h"
-#include "kernel/svm/svm_light_path.h"
-#include "kernel/svm/svm_magic.h"
-#include "kernel/svm/svm_map_range.h"
-#include "kernel/svm/svm_mapping.h"
-#include "kernel/svm/svm_math.h"
-#include "kernel/svm/svm_mix.h"
-#include "kernel/svm/svm_musgrave.h"
-#include "kernel/svm/svm_noisetex.h"
-#include "kernel/svm/svm_normal.h"
-#include "kernel/svm/svm_ramp.h"
-#include "kernel/svm/svm_sepcomb_hsv.h"
-#include "kernel/svm/svm_sepcomb_vector.h"
-#include "kernel/svm/svm_sky.h"
-#include "kernel/svm/svm_tex_coord.h"
-#include "kernel/svm/svm_value.h"
-#include "kernel/svm/svm_vector_rotate.h"
-#include "kernel/svm/svm_vector_transform.h"
-#include "kernel/svm/svm_vertex_color.h"
-#include "kernel/svm/svm_voronoi.h"
-#include "kernel/svm/svm_voxel.h"
-#include "kernel/svm/svm_wave.h"
-#include "kernel/svm/svm_wavelength.h"
-#include "kernel/svm/svm_white_noise.h"
-#include "kernel/svm/svm_wireframe.h"
+#include "kernel/svm/aov.h"
+#include "kernel/svm/attribute.h"
+#include "kernel/svm/blackbody.h"
+#include "kernel/svm/brick.h"
+#include "kernel/svm/brightness.h"
+#include "kernel/svm/bump.h"
+#include "kernel/svm/camera.h"
+#include "kernel/svm/checker.h"
+#include "kernel/svm/clamp.h"
+#include "kernel/svm/closure.h"
+#include "kernel/svm/convert.h"
+#include "kernel/svm/displace.h"
+#include "kernel/svm/fresnel.h"
+#include "kernel/svm/gamma.h"
+#include "kernel/svm/geometry.h"
+#include "kernel/svm/gradient.h"
+#include "kernel/svm/hsv.h"
+#include "kernel/svm/ies.h"
+#include "kernel/svm/image.h"
+#include "kernel/svm/invert.h"
+#include "kernel/svm/light_path.h"
+#include "kernel/svm/magic.h"
+#include "kernel/svm/map_range.h"
+#include "kernel/svm/mapping.h"
+#include "kernel/svm/math.h"
+#include "kernel/svm/mix.h"
+#include "kernel/svm/musgrave.h"
+#include "kernel/svm/noisetex.h"
+#include "kernel/svm/normal.h"
+#include "kernel/svm/ramp.h"
+#include "kernel/svm/sepcomb_hsv.h"
+#include "kernel/svm/sepcomb_vector.h"
+#include "kernel/svm/sky.h"
+#include "kernel/svm/tex_coord.h"
+#include "kernel/svm/value.h"
+#include "kernel/svm/vector_rotate.h"
+#include "kernel/svm/vector_transform.h"
+#include "kernel/svm/vertex_color.h"
+#include "kernel/svm/voronoi.h"
+#include "kernel/svm/voxel.h"
+#include "kernel/svm/wave.h"
+#include "kernel/svm/wavelength.h"
+#include "kernel/svm/white_noise.h"
+#include "kernel/svm/wireframe.h"
#ifdef __SHADER_RAYTRACE__
-# include "kernel/svm/svm_ao.h"
-# include "kernel/svm/svm_bevel.h"
+# include "kernel/svm/ao.h"
+# include "kernel/svm/bevel.h"
#endif
CCL_NAMESPACE_BEGIN
@@ -607,5 +599,3 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
}
CCL_NAMESPACE_END
-
-#endif /* __SVM_H__ */
diff --git a/intern/cycles/kernel/svm/svm_ao.h b/intern/cycles/kernel/svm/svm_ao.h
deleted file mode 100644
index 4cfef7bc204..00000000000
--- a/intern/cycles/kernel/svm/svm_ao.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "kernel/bvh/bvh.h"
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef __SHADER_RAYTRACE__
-
-# ifdef __KERNEL_OPTIX__
-extern "C" __device__ float __direct_callable__svm_node_ao(
-# else
-ccl_device float svm_ao(
-# endif
- KernelGlobals kg,
- ConstIntegratorState state,
- ccl_private ShaderData *sd,
- float3 N,
- float max_dist,
- int num_samples,
- int flags)
-{
- if (flags & NODE_AO_GLOBAL_RADIUS) {
- max_dist = kernel_data.integrator.ao_bounces_distance;
- }
-
- /* Early out if no sampling needed. */
- if (max_dist <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) {
- return 1.0f;
- }
-
- /* Can't raytrace from shaders like displacement, before BVH exists. */
- if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
- return 1.0f;
- }
-
- if (flags & NODE_AO_INSIDE) {
- N = -N;
- }
-
- float3 T, B;
- make_orthonormals(N, &T, &B);
-
- /* TODO: support ray-tracing in shadow shader evaluation? */
- RNGState rng_state;
- path_state_rng_load(state, &rng_state);
-
- int unoccluded = 0;
- for (int sample = 0; sample < num_samples; sample++) {
- float disk_u, disk_v;
- path_branched_rng_2D(kg, &rng_state, sample, num_samples, PRNG_BEVEL_U, &disk_u, &disk_v);
-
- float2 d = concentric_sample_disk(disk_u, disk_v);
- float3 D = make_float3(d.x, d.y, safe_sqrtf(1.0f - dot(d, d)));
-
- /* Create ray. */
- Ray ray;
- ray.P = ray_offset(sd->P, N);
- ray.D = D.x * T + D.y * B + D.z * N;
- ray.t = max_dist;
- ray.time = sd->time;
- ray.dP = differential_zero_compact();
- ray.dD = differential_zero_compact();
-
- if (flags & NODE_AO_ONLY_LOCAL) {
- if (!scene_intersect_local(kg, &ray, NULL, sd->object, NULL, 0)) {
- unoccluded++;
- }
- }
- else {
- Intersection isect;
- if (!scene_intersect(kg, &ray, PATH_RAY_SHADOW_OPAQUE, &isect)) {
- unoccluded++;
- }
- }
- }
-
- return ((float)unoccluded) / num_samples;
-}
-
-template<uint node_feature_mask, typename ConstIntegratorGenericState>
-# if defined(__KERNEL_OPTIX__)
-ccl_device_inline
-# else
-ccl_device_noinline
-# endif
- void
- svm_node_ao(KernelGlobals kg,
- ConstIntegratorGenericState state,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint flags, dist_offset, normal_offset, out_ao_offset;
- svm_unpack_node_uchar4(node.y, &flags, &dist_offset, &normal_offset, &out_ao_offset);
-
- uint color_offset, out_color_offset, samples;
- svm_unpack_node_uchar3(node.z, &color_offset, &out_color_offset, &samples);
-
- float ao = 1.0f;
-
- IF_KERNEL_NODES_FEATURE(RAYTRACE)
- {
- float dist = stack_load_float_default(stack, dist_offset, node.w);
- float3 normal = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N;
-
-# ifdef __KERNEL_OPTIX__
- ao = optixDirectCall<float>(0, kg, state, sd, normal, dist, samples, flags);
-# else
- ao = svm_ao(kg, state, sd, normal, dist, samples, flags);
-# endif
- }
-
- if (stack_valid(out_ao_offset)) {
- stack_store_float(stack, out_ao_offset, ao);
- }
-
- if (stack_valid(out_color_offset)) {
- float3 color = stack_load_float3(stack, color_offset);
- stack_store_float3(stack, out_color_offset, ao * color);
- }
-}
-
-#endif /* __SHADER_RAYTRACE__ */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_aov.h b/intern/cycles/kernel/svm/svm_aov.h
deleted file mode 100644
index 833a6443b3c..00000000000
--- a/intern/cycles/kernel/svm/svm_aov.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "kernel/kernel_write_passes.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_inline bool svm_node_aov_check(const uint32_t path_flag,
- ccl_global float *render_buffer)
-{
- bool is_primary = (path_flag & PATH_RAY_CAMERA) && (!(path_flag & PATH_RAY_SINGLE_PASS_DONE));
-
- return ((render_buffer != NULL) && is_primary);
-}
-
-template<uint node_feature_mask, typename ConstIntegratorGenericState>
-ccl_device void svm_node_aov_color(KernelGlobals kg,
- ConstIntegratorGenericState state,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node,
- ccl_global float *render_buffer)
-{
- IF_KERNEL_NODES_FEATURE(AOV)
- {
- const float3 val = stack_load_float3(stack, node.y);
- const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
- const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
- kernel_data.film.pass_stride;
- ccl_global float *buffer = render_buffer + render_buffer_offset +
- (kernel_data.film.pass_aov_color + node.z);
- kernel_write_pass_float3(buffer, make_float3(val.x, val.y, val.z));
- }
-}
-
-template<uint node_feature_mask, typename ConstIntegratorGenericState>
-ccl_device void svm_node_aov_value(KernelGlobals kg,
- ConstIntegratorGenericState state,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node,
- ccl_global float *render_buffer)
-{
- IF_KERNEL_NODES_FEATURE(AOV)
- {
- const float val = stack_load_float(stack, node.y);
- const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
- const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
- kernel_data.film.pass_stride;
- ccl_global float *buffer = render_buffer + render_buffer_offset +
- (kernel_data.film.pass_aov_value + node.z);
- kernel_write_pass_float(buffer, val);
- }
-}
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h
deleted file mode 100644
index b3c66d29f5c..00000000000
--- a/intern/cycles/kernel/svm/svm_attribute.h
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Attribute Node */
-
-ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals kg,
- ccl_private ShaderData *sd,
- uint4 node,
- ccl_private NodeAttributeOutputType *type,
- ccl_private uint *out_offset)
-{
- *out_offset = node.z;
- *type = (NodeAttributeOutputType)node.w;
-
- AttributeDescriptor desc;
-
- if (sd->object != OBJECT_NONE) {
- desc = find_attribute(kg, sd, node.y);
- if (desc.offset == ATTR_STD_NOT_FOUND) {
- desc = attribute_not_found();
- desc.offset = 0;
- desc.type = (NodeAttributeType)node.w;
- }
- }
- else {
- /* background */
- desc = attribute_not_found();
- desc.offset = 0;
- desc.type = (NodeAttributeType)node.w;
- }
-
- return desc;
-}
-
-template<uint node_feature_mask>
-ccl_device_noinline void svm_node_attr(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
- uint out_offset = 0;
- AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
-
-#ifdef __VOLUME__
- IF_KERNEL_NODES_FEATURE(VOLUME)
- {
- /* Volumes
- * NOTE: moving this into its own node type might help improve performance. */
- if (primitive_is_volume_attribute(sd, desc)) {
- const float4 value = volume_attribute_float4(kg, sd, desc);
-
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- const float f = volume_attribute_value_to_float(value);
- stack_store_float(stack, out_offset, f);
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- const float3 f = volume_attribute_value_to_float3(value);
- stack_store_float3(stack, out_offset, f);
- }
- else {
- const float f = volume_attribute_value_to_alpha(value);
- stack_store_float(stack, out_offset, f);
- }
- return;
- }
- }
-#endif
-
- if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
- /* No generated attribute, fall back to object coordinates. */
- float3 f = sd->P;
- object_inverse_position_transform(kg, sd, &f);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, average(f));
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, f);
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- return;
- }
-
- /* Surface. */
- if (desc.type == NODE_ATTR_FLOAT) {
- float f = primitive_surface_attribute_float(kg, sd, desc, NULL, NULL);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, f);
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, make_float3(f, f, f));
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- }
- else if (desc.type == NODE_ATTR_FLOAT2) {
- float2 f = primitive_surface_attribute_float2(kg, sd, desc, NULL, NULL);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, f.x);
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, make_float3(f.x, f.y, 0.0f));
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- }
- else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
- float4 f = primitive_surface_attribute_float4(kg, sd, desc, NULL, NULL);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, average(float4_to_float3(f)));
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, float4_to_float3(f));
- }
- else {
- stack_store_float(stack, out_offset, f.w);
- }
- }
- else {
- float3 f = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, average(f));
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, f);
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- }
-}
-
-ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
- uint out_offset = 0;
- AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
-
-#ifdef __VOLUME__
- /* Volume */
- if (primitive_is_volume_attribute(sd, desc)) {
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, 0.0f);
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f));
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- return;
- }
-#endif
-
- if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
- /* No generated attribute, fall back to object coordinates. */
- float3 f = sd->P + sd->dP.dx;
- object_inverse_position_transform(kg, sd, &f);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, average(f));
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, f);
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- return;
- }
-
- /* Surface */
- if (desc.type == NODE_ATTR_FLOAT) {
- float dx;
- float f = primitive_surface_attribute_float(kg, sd, desc, &dx, NULL);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, f + dx);
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, make_float3(f + dx, f + dx, f + dx));
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- }
- else if (desc.type == NODE_ATTR_FLOAT2) {
- float2 dx;
- float2 f = primitive_surface_attribute_float2(kg, sd, desc, &dx, NULL);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, f.x + dx.x);
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, make_float3(f.x + dx.x, f.y + dx.y, 0.0f));
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- }
- else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
- float4 dx;
- float4 f = primitive_surface_attribute_float4(kg, sd, desc, &dx, NULL);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, average(float4_to_float3(f + dx)));
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, float4_to_float3(f + dx));
- }
- else {
- stack_store_float(stack, out_offset, f.w + dx.w);
- }
- }
- else {
- float3 dx;
- float3 f = primitive_surface_attribute_float3(kg, sd, desc, &dx, NULL);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, average(f + dx));
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, f + dx);
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- }
-}
-
-ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
- uint out_offset = 0;
- AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
-
-#ifdef __VOLUME__
- /* Volume */
- if (primitive_is_volume_attribute(sd, desc)) {
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, 0.0f);
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f));
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- return;
- }
-#endif
-
- if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
- /* No generated attribute, fall back to object coordinates. */
- float3 f = sd->P + sd->dP.dy;
- object_inverse_position_transform(kg, sd, &f);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, average(f));
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, f);
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- return;
- }
-
- /* Surface */
- if (desc.type == NODE_ATTR_FLOAT) {
- float dy;
- float f = primitive_surface_attribute_float(kg, sd, desc, NULL, &dy);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, f + dy);
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, make_float3(f + dy, f + dy, f + dy));
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- }
- else if (desc.type == NODE_ATTR_FLOAT2) {
- float2 dy;
- float2 f = primitive_surface_attribute_float2(kg, sd, desc, NULL, &dy);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, f.x + dy.x);
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, make_float3(f.x + dy.x, f.y + dy.y, 0.0f));
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- }
- else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
- float4 dy;
- float4 f = primitive_surface_attribute_float4(kg, sd, desc, NULL, &dy);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, average(float4_to_float3(f + dy)));
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, float4_to_float3(f + dy));
- }
- else {
- stack_store_float(stack, out_offset, f.w + dy.w);
- }
- }
- else {
- float3 dy;
- float3 f = primitive_surface_attribute_float3(kg, sd, desc, NULL, &dy);
- if (type == NODE_ATTR_OUTPUT_FLOAT) {
- stack_store_float(stack, out_offset, average(f + dy));
- }
- else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
- stack_store_float3(stack, out_offset, f + dy);
- }
- else {
- stack_store_float(stack, out_offset, 1.0f);
- }
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_bevel.h b/intern/cycles/kernel/svm/svm_bevel.h
deleted file mode 100644
index 292887beedf..00000000000
--- a/intern/cycles/kernel/svm/svm_bevel.h
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "kernel/bvh/bvh.h"
-#include "kernel/kernel_montecarlo.h"
-#include "kernel/kernel_random.h"
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef __SHADER_RAYTRACE__
-
-/* Planar Cubic BSSRDF falloff, reused for bevel.
- *
- * This is basically (Rm - x)^3, with some factors to normalize it. For sampling
- * we integrate 2*pi*x * (Rm - x)^3, which gives us a quintic equation that as
- * far as I can tell has no closed form solution. So we get an iterative solution
- * instead with newton-raphson. */
-
-ccl_device float svm_bevel_cubic_eval(const float radius, float r)
-{
- const float Rm = radius;
-
- if (r >= Rm)
- return 0.0f;
-
- /* integrate (2*pi*r * 10*(R - r)^3)/(pi * R^5) from 0 to R = 1 */
- const float Rm5 = (Rm * Rm) * (Rm * Rm) * Rm;
- const float f = Rm - r;
- const float num = f * f * f;
-
- return (10.0f * num) / (Rm5 * M_PI_F);
-}
-
-ccl_device float svm_bevel_cubic_pdf(const float radius, float r)
-{
- return svm_bevel_cubic_eval(radius, r);
-}
-
-/* solve 10x^2 - 20x^3 + 15x^4 - 4x^5 - xi == 0 */
-ccl_device_forceinline float svm_bevel_cubic_quintic_root_find(float xi)
-{
- /* newton-raphson iteration, usually succeeds in 2-4 iterations, except
- * outside 0.02 ... 0.98 where it can go up to 10, so overall performance
- * should not be too bad */
- const float tolerance = 1e-6f;
- const int max_iteration_count = 10;
- float x = 0.25f;
- int i;
-
- for (i = 0; i < max_iteration_count; i++) {
- float x2 = x * x;
- float x3 = x2 * x;
- float nx = (1.0f - x);
-
- float f = 10.0f * x2 - 20.0f * x3 + 15.0f * x2 * x2 - 4.0f * x2 * x3 - xi;
- float f_ = 20.0f * (x * nx) * (nx * nx);
-
- if (fabsf(f) < tolerance || f_ == 0.0f)
- break;
-
- x = saturate(x - f / f_);
- }
-
- return x;
-}
-
-ccl_device void svm_bevel_cubic_sample(const float radius,
- float xi,
- ccl_private float *r,
- ccl_private float *h)
-{
- float Rm = radius;
- float r_ = svm_bevel_cubic_quintic_root_find(xi);
-
- r_ *= Rm;
- *r = r_;
-
- /* h^2 + r^2 = Rm^2 */
- *h = safe_sqrtf(Rm * Rm - r_ * r_);
-}
-
-/* Bevel shader averaging normals from nearby surfaces.
- *
- * Sampling strategy from: BSSRDF Importance Sampling, SIGGRAPH 2013
- * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf
- */
-
-# ifdef __KERNEL_OPTIX__
-extern "C" __device__ float3 __direct_callable__svm_node_bevel(
-# else
-ccl_device float3 svm_bevel(
-# endif
- KernelGlobals kg,
- ConstIntegratorState state,
- ccl_private ShaderData *sd,
- float radius,
- int num_samples)
-{
- /* Early out if no sampling needed. */
- if (radius <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) {
- return sd->N;
- }
-
- /* Can't raytrace from shaders like displacement, before BVH exists. */
- if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
- return sd->N;
- }
-
- /* Don't bevel for blurry indirect rays. */
- if (INTEGRATOR_STATE(state, path, min_ray_pdf) < 8.0f) {
- return sd->N;
- }
-
- /* Setup for multi intersection. */
- LocalIntersection isect;
- uint lcg_state = lcg_state_init(INTEGRATOR_STATE(state, path, rng_hash),
- INTEGRATOR_STATE(state, path, rng_offset),
- INTEGRATOR_STATE(state, path, sample),
- 0x64c6a40e);
-
- /* Sample normals from surrounding points on surface. */
- float3 sum_N = make_float3(0.0f, 0.0f, 0.0f);
-
- /* TODO: support ray-tracing in shadow shader evaluation? */
- RNGState rng_state;
- path_state_rng_load(state, &rng_state);
-
- for (int sample = 0; sample < num_samples; sample++) {
- float disk_u, disk_v;
- path_branched_rng_2D(kg, &rng_state, sample, num_samples, PRNG_BEVEL_U, &disk_u, &disk_v);
-
- /* Pick random axis in local frame and point on disk. */
- float3 disk_N, disk_T, disk_B;
- float pick_pdf_N, pick_pdf_T, pick_pdf_B;
-
- disk_N = sd->Ng;
- make_orthonormals(disk_N, &disk_T, &disk_B);
-
- float axisu = disk_u;
-
- if (axisu < 0.5f) {
- pick_pdf_N = 0.5f;
- pick_pdf_T = 0.25f;
- pick_pdf_B = 0.25f;
- disk_u *= 2.0f;
- }
- else if (axisu < 0.75f) {
- float3 tmp = disk_N;
- disk_N = disk_T;
- disk_T = tmp;
- pick_pdf_N = 0.25f;
- pick_pdf_T = 0.5f;
- pick_pdf_B = 0.25f;
- disk_u = (disk_u - 0.5f) * 4.0f;
- }
- else {
- float3 tmp = disk_N;
- disk_N = disk_B;
- disk_B = tmp;
- pick_pdf_N = 0.25f;
- pick_pdf_T = 0.25f;
- pick_pdf_B = 0.5f;
- disk_u = (disk_u - 0.75f) * 4.0f;
- }
-
- /* Sample point on disk. */
- float phi = M_2PI_F * disk_u;
- float disk_r = disk_v;
- float disk_height;
-
- /* Perhaps find something better than Cubic BSSRDF, but happens to work well. */
- svm_bevel_cubic_sample(radius, disk_r, &disk_r, &disk_height);
-
- float3 disk_P = (disk_r * cosf(phi)) * disk_T + (disk_r * sinf(phi)) * disk_B;
-
- /* Create ray. */
- Ray ray ccl_optional_struct_init;
- ray.P = sd->P + disk_N * disk_height + disk_P;
- ray.D = -disk_N;
- ray.t = 2.0f * disk_height;
- ray.dP = differential_zero_compact();
- ray.dD = differential_zero_compact();
- ray.time = sd->time;
-
- /* Intersect with the same object. if multiple intersections are found it
- * will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */
- scene_intersect_local(kg, &ray, &isect, sd->object, &lcg_state, LOCAL_MAX_HITS);
-
- int num_eval_hits = min(isect.num_hits, LOCAL_MAX_HITS);
-
- for (int hit = 0; hit < num_eval_hits; hit++) {
- /* Quickly retrieve P and Ng without setting up ShaderData. */
- float3 hit_P;
- if (sd->type & PRIMITIVE_TRIANGLE) {
- hit_P = triangle_refine_local(
- kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim);
- }
-# ifdef __OBJECT_MOTION__
- else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
- float3 verts[3];
- motion_triangle_vertices(kg, sd->object, isect.hits[hit].prim, sd->time, verts);
- hit_P = motion_triangle_refine_local(
- kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim, verts);
- }
-# endif /* __OBJECT_MOTION__ */
-
- /* Get geometric normal. */
- float3 hit_Ng = isect.Ng[hit];
- int object = isect.hits[hit].object;
- int object_flag = kernel_tex_fetch(__object_flag, object);
- if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
- hit_Ng = -hit_Ng;
- }
-
- /* Compute smooth normal. */
- float3 N = hit_Ng;
- int prim = isect.hits[hit].prim;
- int shader = kernel_tex_fetch(__tri_shader, prim);
-
- if (shader & SHADER_SMOOTH_NORMAL) {
- float u = isect.hits[hit].u;
- float v = isect.hits[hit].v;
-
- if (sd->type & PRIMITIVE_TRIANGLE) {
- N = triangle_smooth_normal(kg, N, prim, u, v);
- }
-# ifdef __OBJECT_MOTION__
- else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
- N = motion_triangle_smooth_normal(kg, N, sd->object, prim, u, v, sd->time);
- }
-# endif /* __OBJECT_MOTION__ */
- }
-
- /* Transform normals to world space. */
- if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- object_normal_transform(kg, sd, &N);
- object_normal_transform(kg, sd, &hit_Ng);
- }
-
- /* Probability densities for local frame axes. */
- float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng));
- float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng));
- float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng));
-
- /* Multiple importance sample between 3 axes, power heuristic
- * found to be slightly better than balance heuristic. pdf_N
- * in the MIS weight and denominator canceled out. */
- float w = pdf_N / (sqr(pdf_N) + sqr(pdf_T) + sqr(pdf_B));
- if (isect.num_hits > LOCAL_MAX_HITS) {
- w *= isect.num_hits / (float)LOCAL_MAX_HITS;
- }
-
- /* Real distance to sampled point. */
- float r = len(hit_P - sd->P);
-
- /* Compute weight. */
- float pdf = svm_bevel_cubic_pdf(radius, r);
- float disk_pdf = svm_bevel_cubic_pdf(radius, disk_r);
-
- w *= pdf / disk_pdf;
-
- /* Sum normal and weight. */
- sum_N += w * N;
- }
- }
-
- /* Normalize. */
- float3 N = safe_normalize(sum_N);
- return is_zero(N) ? sd->N : (sd->flag & SD_BACKFACING) ? -N : N;
-}
-
-template<uint node_feature_mask, typename ConstIntegratorGenericState>
-# if defined(__KERNEL_OPTIX__)
-ccl_device_inline
-# else
-ccl_device_noinline
-# endif
- void
- svm_node_bevel(KernelGlobals kg,
- ConstIntegratorGenericState state,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint num_samples, radius_offset, normal_offset, out_offset;
- svm_unpack_node_uchar4(node.y, &num_samples, &radius_offset, &normal_offset, &out_offset);
-
- float3 bevel_N = sd->N;
-
- IF_KERNEL_NODES_FEATURE(RAYTRACE)
- {
- float radius = stack_load_float(stack, radius_offset);
-
-# ifdef __KERNEL_OPTIX__
- bevel_N = optixDirectCall<float3>(1, kg, state, sd, radius, num_samples);
-# else
- bevel_N = svm_bevel(kg, state, sd, radius, num_samples);
-# endif
-
- if (stack_valid(normal_offset)) {
- /* Preserve input normal. */
- float3 ref_N = stack_load_float3(stack, normal_offset);
- bevel_N = normalize(ref_N + (bevel_N - sd->N));
- }
- }
-
- stack_store_float3(stack, out_offset, bevel_N);
-}
-
-#endif /* __SHADER_RAYTRACE__ */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_blackbody.h b/intern/cycles/kernel/svm/svm_blackbody.h
deleted file mode 100644
index f1adb0e76af..00000000000
--- a/intern/cycles/kernel/svm/svm_blackbody.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Adapted from Open Shading Language with this license:
- *
- * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
- * All Rights Reserved.
- *
- * Modifications Copyright 2013, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Sony Pictures Imageworks nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Blackbody Node */
-
-ccl_device_noinline void svm_node_blackbody(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint temperature_offset,
- uint col_offset)
-{
- /* Input */
- float temperature = stack_load_float(stack, temperature_offset);
-
- float3 color_rgb = svm_math_blackbody_color(temperature);
-
- stack_store_float3(stack, col_offset, color_rgb);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_brick.h b/intern/cycles/kernel/svm/svm_brick.h
deleted file mode 100644
index 9dc31ef37ec..00000000000
--- a/intern/cycles/kernel/svm/svm_brick.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Brick */
-
-ccl_device_inline float brick_noise(uint n) /* fast integer noise */
-{
- uint nn;
- n = (n + 1013) & 0x7fffffff;
- n = (n >> 13) ^ n;
- nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
- return 0.5f * ((float)nn / 1073741824.0f);
-}
-
-ccl_device_noinline_cpu float2 svm_brick(float3 p,
- float mortar_size,
- float mortar_smooth,
- float bias,
- float brick_width,
- float row_height,
- float offset_amount,
- int offset_frequency,
- float squash_amount,
- int squash_frequency)
-{
- int bricknum, rownum;
- float offset = 0.0f;
- float x, y;
-
- rownum = floor_to_int(p.y / row_height);
-
- if (offset_frequency && squash_frequency) {
- brick_width *= (rownum % squash_frequency) ? 1.0f : squash_amount; /* squash */
- offset = (rownum % offset_frequency) ? 0.0f : (brick_width * offset_amount); /* offset */
- }
-
- bricknum = floor_to_int((p.x + offset) / brick_width);
-
- x = (p.x + offset) - brick_width * bricknum;
- y = p.y - row_height * rownum;
-
- float tint = saturate((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias));
- float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
-
- float mortar;
- if (min_dist >= mortar_size) {
- mortar = 0.0f;
- }
- else if (mortar_smooth == 0.0f) {
- mortar = 1.0f;
- }
- else {
- min_dist = 1.0f - min_dist / mortar_size;
- mortar = (min_dist < mortar_smooth) ? smoothstepf(min_dist / mortar_smooth) : 1.0f;
- }
-
- return make_float2(tint, mortar);
-}
-
-ccl_device_noinline int svm_node_tex_brick(
- KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
-{
- uint4 node2 = read_node(kg, &offset);
- uint4 node3 = read_node(kg, &offset);
- uint4 node4 = read_node(kg, &offset);
-
- /* Input and Output Sockets */
- uint co_offset, color1_offset, color2_offset, mortar_offset, scale_offset;
- uint mortar_size_offset, bias_offset, brick_width_offset, row_height_offset;
- uint color_offset, fac_offset, mortar_smooth_offset;
-
- /* RNA properties */
- uint offset_frequency, squash_frequency;
-
- svm_unpack_node_uchar4(node.y, &co_offset, &color1_offset, &color2_offset, &mortar_offset);
- svm_unpack_node_uchar4(
- node.z, &scale_offset, &mortar_size_offset, &bias_offset, &brick_width_offset);
- svm_unpack_node_uchar4(
- node.w, &row_height_offset, &color_offset, &fac_offset, &mortar_smooth_offset);
-
- svm_unpack_node_uchar2(node2.x, &offset_frequency, &squash_frequency);
-
- float3 co = stack_load_float3(stack, co_offset);
-
- float3 color1 = stack_load_float3(stack, color1_offset);
- float3 color2 = stack_load_float3(stack, color2_offset);
- float3 mortar = stack_load_float3(stack, mortar_offset);
-
- float scale = stack_load_float_default(stack, scale_offset, node2.y);
- float mortar_size = stack_load_float_default(stack, mortar_size_offset, node2.z);
- float mortar_smooth = stack_load_float_default(stack, mortar_smooth_offset, node4.x);
- float bias = stack_load_float_default(stack, bias_offset, node2.w);
- float brick_width = stack_load_float_default(stack, brick_width_offset, node3.x);
- float row_height = stack_load_float_default(stack, row_height_offset, node3.y);
- float offset_amount = __int_as_float(node3.z);
- float squash_amount = __int_as_float(node3.w);
-
- float2 f2 = svm_brick(co * scale,
- mortar_size,
- mortar_smooth,
- bias,
- brick_width,
- row_height,
- offset_amount,
- offset_frequency,
- squash_amount,
- squash_frequency);
-
- float tint = f2.x;
- float f = f2.y;
-
- if (f != 1.0f) {
- float facm = 1.0f - tint;
- color1 = facm * color1 + tint * color2;
- }
-
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, color1 * (1.0f - f) + mortar * f);
- if (stack_valid(fac_offset))
- stack_store_float(stack, fac_offset, f);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_brightness.h b/intern/cycles/kernel/svm/svm_brightness.h
deleted file mode 100644
index 0a44ffe6359..00000000000
--- a/intern/cycles/kernel/svm/svm_brightness.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_noinline void svm_node_brightness(
- ccl_private ShaderData *sd, ccl_private float *stack, uint in_color, uint out_color, uint node)
-{
- uint bright_offset, contrast_offset;
- float3 color = stack_load_float3(stack, in_color);
-
- svm_unpack_node_uchar2(node, &bright_offset, &contrast_offset);
- float brightness = stack_load_float(stack, bright_offset);
- float contrast = stack_load_float(stack, contrast_offset);
-
- color = svm_brightness_contrast(color, brightness, contrast);
-
- if (stack_valid(out_color))
- stack_store_float3(stack, out_color, color);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_bump.h b/intern/cycles/kernel/svm/svm_bump.h
deleted file mode 100644
index 66e5b665532..00000000000
--- a/intern/cycles/kernel/svm/svm_bump.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Bump Eval Nodes */
-
-ccl_device_noinline void svm_node_enter_bump_eval(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint offset)
-{
- /* save state */
- stack_store_float3(stack, offset + 0, sd->P);
- stack_store_float3(stack, offset + 3, sd->dP.dx);
- stack_store_float3(stack, offset + 6, sd->dP.dy);
-
- /* set state as if undisplaced */
- const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_POSITION_UNDISPLACED);
-
- if (desc.offset != ATTR_STD_NOT_FOUND) {
- float3 P, dPdx, dPdy;
- P = primitive_surface_attribute_float3(kg, sd, desc, &dPdx, &dPdy);
-
- object_position_transform(kg, sd, &P);
- object_dir_transform(kg, sd, &dPdx);
- object_dir_transform(kg, sd, &dPdy);
-
- sd->P = P;
- sd->dP.dx = dPdx;
- sd->dP.dy = dPdy;
- }
-}
-
-ccl_device_noinline void svm_node_leave_bump_eval(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint offset)
-{
- /* restore state */
- sd->P = stack_load_float3(stack, offset + 0);
- sd->dP.dx = stack_load_float3(stack, offset + 3);
- sd->dP.dy = stack_load_float3(stack, offset + 6);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_camera.h b/intern/cycles/kernel/svm/svm_camera.h
deleted file mode 100644
index 787f11f38b5..00000000000
--- a/intern/cycles/kernel/svm/svm_camera.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_noinline void svm_node_camera(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint out_vector,
- uint out_zdepth,
- uint out_distance)
-{
- float distance;
- float zdepth;
- float3 vector;
-
- Transform tfm = kernel_data.cam.worldtocamera;
- vector = transform_point(&tfm, sd->P);
- zdepth = vector.z;
- distance = len(vector);
-
- if (stack_valid(out_vector))
- stack_store_float3(stack, out_vector, normalize(vector));
-
- if (stack_valid(out_zdepth))
- stack_store_float(stack, out_zdepth, zdepth);
-
- if (stack_valid(out_distance))
- stack_store_float(stack, out_distance, distance);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_checker.h b/intern/cycles/kernel/svm/svm_checker.h
deleted file mode 100644
index 9251d90c0e1..00000000000
--- a/intern/cycles/kernel/svm/svm_checker.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Checker */
-
-ccl_device float svm_checker(float3 p)
-{
- /* avoid precision issues on unit coordinates */
- p.x = (p.x + 0.000001f) * 0.999999f;
- p.y = (p.y + 0.000001f) * 0.999999f;
- p.z = (p.z + 0.000001f) * 0.999999f;
-
- int xi = abs(float_to_int(floorf(p.x)));
- int yi = abs(float_to_int(floorf(p.y)));
- int zi = abs(float_to_int(floorf(p.z)));
-
- return ((xi % 2 == yi % 2) == (zi % 2)) ? 1.0f : 0.0f;
-}
-
-ccl_device_noinline void svm_node_tex_checker(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint co_offset, color1_offset, color2_offset, scale_offset;
- uint color_offset, fac_offset;
-
- svm_unpack_node_uchar4(node.y, &co_offset, &color1_offset, &color2_offset, &scale_offset);
- svm_unpack_node_uchar2(node.z, &color_offset, &fac_offset);
-
- float3 co = stack_load_float3(stack, co_offset);
- float3 color1 = stack_load_float3(stack, color1_offset);
- float3 color2 = stack_load_float3(stack, color2_offset);
- float scale = stack_load_float_default(stack, scale_offset, node.w);
-
- float f = svm_checker(co * scale);
-
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, (f == 1.0f) ? color1 : color2);
- if (stack_valid(fac_offset))
- stack_store_float(stack, fac_offset, f);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_clamp.h b/intern/cycles/kernel/svm/svm_clamp.h
deleted file mode 100644
index 5b5ea784f4a..00000000000
--- a/intern/cycles/kernel/svm/svm_clamp.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Clamp Node */
-
-ccl_device_noinline int svm_node_clamp(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint value_stack_offset,
- uint parameters_stack_offsets,
- uint result_stack_offset,
- int offset)
-{
- uint min_stack_offset, max_stack_offset, type;
- svm_unpack_node_uchar3(parameters_stack_offsets, &min_stack_offset, &max_stack_offset, &type);
-
- uint4 defaults = read_node(kg, &offset);
-
- float value = stack_load_float(stack, value_stack_offset);
- float min = stack_load_float_default(stack, min_stack_offset, defaults.x);
- float max = stack_load_float_default(stack, max_stack_offset, defaults.y);
-
- if (type == NODE_CLAMP_RANGE && (min > max)) {
- stack_store_float(stack, result_stack_offset, clamp(value, max, min));
- }
- else {
- stack_store_float(stack, result_stack_offset, clamp(value, min, max));
- }
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
deleted file mode 100644
index 3378832c233..00000000000
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ /dev/null
@@ -1,1258 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Closure Nodes */
-
-ccl_device void svm_node_glass_setup(ccl_private ShaderData *sd,
- ccl_private MicrofacetBsdf *bsdf,
- int type,
- float eta,
- float roughness,
- bool refract)
-{
- if (type == CLOSURE_BSDF_SHARP_GLASS_ID) {
- if (refract) {
- bsdf->alpha_y = 0.0f;
- bsdf->alpha_x = 0.0f;
- bsdf->ior = eta;
- sd->flag |= bsdf_refraction_setup(bsdf);
- }
- else {
- bsdf->alpha_y = 0.0f;
- bsdf->alpha_x = 0.0f;
- bsdf->ior = 0.0f;
- sd->flag |= bsdf_reflection_setup(bsdf);
- }
- }
- else if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID) {
- bsdf->alpha_x = roughness;
- bsdf->alpha_y = roughness;
- bsdf->ior = eta;
-
- if (refract)
- sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
- else
- sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
- }
- else {
- bsdf->alpha_x = roughness;
- bsdf->alpha_y = roughness;
- bsdf->ior = eta;
-
- if (refract)
- sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
- else
- sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
- }
-}
-
-ccl_device_inline int svm_node_closure_bsdf_skip(KernelGlobals kg, int offset, uint type)
-{
- if (type == CLOSURE_BSDF_PRINCIPLED_ID) {
- /* Read all principled BSDF extra data to get the right offset. */
- read_node(kg, &offset);
- read_node(kg, &offset);
- read_node(kg, &offset);
- read_node(kg, &offset);
- }
-
- return offset;
-}
-
-template<uint node_feature_mask, ShaderType shader_type>
-ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node,
- uint32_t path_flag,
- int offset)
-{
- uint type, param1_offset, param2_offset;
-
- uint mix_weight_offset;
- svm_unpack_node_uchar4(node.y, &type, &param1_offset, &param2_offset, &mix_weight_offset);
- float mix_weight = (stack_valid(mix_weight_offset) ? stack_load_float(stack, mix_weight_offset) :
- 1.0f);
-
- /* note we read this extra node before weight check, so offset is added */
- uint4 data_node = read_node(kg, &offset);
-
- /* Only compute BSDF for surfaces, transparent variable is shared with volume extinction. */
- IF_KERNEL_NODES_FEATURE(BSDF)
- {
- if ((shader_type != SHADER_TYPE_SURFACE) || mix_weight == 0.0f) {
- return svm_node_closure_bsdf_skip(kg, offset, type);
- }
- }
- else
- {
- return svm_node_closure_bsdf_skip(kg, offset, type);
- }
-
- float3 N = stack_valid(data_node.x) ? stack_load_float3(stack, data_node.x) : sd->N;
- if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
- N = ensure_valid_reflection(sd->Ng, sd->I, N);
- }
-
- float param1 = (stack_valid(param1_offset)) ? stack_load_float(stack, param1_offset) :
- __uint_as_float(node.z);
- float param2 = (stack_valid(param2_offset)) ? stack_load_float(stack, param2_offset) :
- __uint_as_float(node.w);
-
- switch (type) {
-#ifdef __PRINCIPLED__
- case CLOSURE_BSDF_PRINCIPLED_ID: {
- uint specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset,
- sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset,
- eta_offset, transmission_offset, anisotropic_rotation_offset,
- transmission_roughness_offset;
- uint4 data_node2 = read_node(kg, &offset);
-
- float3 T = stack_load_float3(stack, data_node.y);
- svm_unpack_node_uchar4(data_node.z,
- &specular_offset,
- &roughness_offset,
- &specular_tint_offset,
- &anisotropic_offset);
- svm_unpack_node_uchar4(data_node.w,
- &sheen_offset,
- &sheen_tint_offset,
- &clearcoat_offset,
- &clearcoat_roughness_offset);
- svm_unpack_node_uchar4(data_node2.x,
- &eta_offset,
- &transmission_offset,
- &anisotropic_rotation_offset,
- &transmission_roughness_offset);
-
- // get Disney principled parameters
- float metallic = param1;
- float subsurface = param2;
- float specular = stack_load_float(stack, specular_offset);
- float roughness = stack_load_float(stack, roughness_offset);
- float specular_tint = stack_load_float(stack, specular_tint_offset);
- float anisotropic = stack_load_float(stack, anisotropic_offset);
- float sheen = stack_load_float(stack, sheen_offset);
- float sheen_tint = stack_load_float(stack, sheen_tint_offset);
- float clearcoat = stack_load_float(stack, clearcoat_offset);
- float clearcoat_roughness = stack_load_float(stack, clearcoat_roughness_offset);
- float transmission = stack_load_float(stack, transmission_offset);
- float anisotropic_rotation = stack_load_float(stack, anisotropic_rotation_offset);
- float transmission_roughness = stack_load_float(stack, transmission_roughness_offset);
- float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f);
-
- ClosureType distribution = (ClosureType)data_node2.y;
- ClosureType subsurface_method = (ClosureType)data_node2.z;
-
- /* rotate tangent */
- if (anisotropic_rotation != 0.0f)
- T = rotate_around_axis(T, N, anisotropic_rotation * M_2PI_F);
-
- /* calculate ior */
- float ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
-
- // calculate fresnel for refraction
- float cosNO = dot(N, sd->I);
- float fresnel = fresnel_dielectric_cos(cosNO, ior);
-
- // calculate weights of the diffuse and specular part
- float diffuse_weight = (1.0f - saturate(metallic)) * (1.0f - saturate(transmission));
-
- float final_transmission = saturate(transmission) * (1.0f - saturate(metallic));
- float specular_weight = (1.0f - final_transmission);
-
- // get the base color
- uint4 data_base_color = read_node(kg, &offset);
- float3 base_color = stack_valid(data_base_color.x) ?
- stack_load_float3(stack, data_base_color.x) :
- make_float3(__uint_as_float(data_base_color.y),
- __uint_as_float(data_base_color.z),
- __uint_as_float(data_base_color.w));
-
- // get the additional clearcoat normal and subsurface scattering radius
- uint4 data_cn_ssr = read_node(kg, &offset);
- float3 clearcoat_normal = stack_valid(data_cn_ssr.x) ?
- stack_load_float3(stack, data_cn_ssr.x) :
- sd->N;
- if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
- clearcoat_normal = ensure_valid_reflection(sd->Ng, sd->I, clearcoat_normal);
- }
- float3 subsurface_radius = stack_valid(data_cn_ssr.y) ?
- stack_load_float3(stack, data_cn_ssr.y) :
- make_float3(1.0f, 1.0f, 1.0f);
- float subsurface_ior = stack_valid(data_cn_ssr.z) ? stack_load_float(stack, data_cn_ssr.z) :
- 1.4f;
- float subsurface_anisotropy = stack_valid(data_cn_ssr.w) ?
- stack_load_float(stack, data_cn_ssr.w) :
- 0.0f;
-
- // get the subsurface color
- uint4 data_subsurface_color = read_node(kg, &offset);
- float3 subsurface_color = stack_valid(data_subsurface_color.x) ?
- stack_load_float3(stack, data_subsurface_color.x) :
- make_float3(__uint_as_float(data_subsurface_color.y),
- __uint_as_float(data_subsurface_color.z),
- __uint_as_float(data_subsurface_color.w));
-
- float3 weight = sd->svm_closure_weight * mix_weight;
-
-# ifdef __SUBSURFACE__
- float3 mixed_ss_base_color = subsurface_color * subsurface +
- base_color * (1.0f - subsurface);
- float3 subsurf_weight = weight * mixed_ss_base_color * diffuse_weight;
-
- /* disable in case of diffuse ancestor, can't see it well then and
- * adds considerably noise due to probabilities of continuing path
- * getting lower and lower */
- if (path_flag & PATH_RAY_DIFFUSE_ANCESTOR) {
- subsurface = 0.0f;
-
- /* need to set the base color in this case such that the
- * rays get the correctly mixed color after transmitting
- * the object */
- base_color = mixed_ss_base_color;
- }
-
- /* diffuse */
- if (fabsf(average(mixed_ss_base_color)) > CLOSURE_WEIGHT_CUTOFF) {
- if (subsurface <= CLOSURE_WEIGHT_CUTOFF && diffuse_weight > CLOSURE_WEIGHT_CUTOFF) {
- float3 diff_weight = weight * base_color * diffuse_weight;
-
- ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)
- bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), diff_weight);
-
- if (bsdf) {
- bsdf->N = N;
- bsdf->roughness = roughness;
-
- /* setup bsdf */
- sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_FULL);
- }
- }
- else if (subsurface > CLOSURE_WEIGHT_CUTOFF) {
- ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd, subsurf_weight);
-
- if (bssrdf) {
- bssrdf->radius = subsurface_radius * subsurface;
- bssrdf->albedo = mixed_ss_base_color;
- bssrdf->N = N;
- bssrdf->roughness = roughness;
-
- /* Clamps protecting against bad/extreme and non physical values. */
- subsurface_ior = clamp(subsurface_ior, 1.01f, 3.8f);
- bssrdf->anisotropy = clamp(subsurface_anisotropy, 0.0f, 0.9f);
-
- /* setup bsdf */
- sd->flag |= bssrdf_setup(sd, bssrdf, subsurface_method, subsurface_ior);
- }
- }
- }
-# else
- /* diffuse */
- if (diffuse_weight > CLOSURE_WEIGHT_CUTOFF) {
- float3 diff_weight = weight * base_color * diffuse_weight;
-
- ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc(
- sd, sizeof(PrincipledDiffuseBsdf), diff_weight);
-
- if (bsdf) {
- bsdf->N = N;
- bsdf->roughness = roughness;
-
- /* setup bsdf */
- sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_FULL);
- }
- }
-# endif
-
- /* sheen */
- if (diffuse_weight > CLOSURE_WEIGHT_CUTOFF && sheen > CLOSURE_WEIGHT_CUTOFF) {
- float m_cdlum = linear_rgb_to_gray(kg, base_color);
- float3 m_ctint = m_cdlum > 0.0f ?
- base_color / m_cdlum :
- make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat
-
- /* color of the sheen component */
- float3 sheen_color = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - sheen_tint) +
- m_ctint * sheen_tint;
-
- float3 sheen_weight = weight * sheen * sheen_color * diffuse_weight;
-
- ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)bsdf_alloc(
- sd, sizeof(PrincipledSheenBsdf), sheen_weight);
-
- if (bsdf) {
- bsdf->N = N;
-
- /* setup bsdf */
- sd->flag |= bsdf_principled_sheen_setup(sd, bsdf);
- }
- }
-
- /* specular reflection */
-# ifdef __CAUSTICS_TRICKS__
- if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) {
-# endif
- if (specular_weight > CLOSURE_WEIGHT_CUTOFF &&
- (specular > CLOSURE_WEIGHT_CUTOFF || metallic > CLOSURE_WEIGHT_CUTOFF)) {
- float3 spec_weight = weight * specular_weight;
-
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), spec_weight);
- ccl_private MicrofacetExtra *extra =
- (bsdf != NULL) ?
- (ccl_private MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra)) :
- NULL;
-
- if (bsdf && extra) {
- bsdf->N = N;
- bsdf->ior = (2.0f / (1.0f - safe_sqrtf(0.08f * specular))) - 1.0f;
- bsdf->T = T;
- bsdf->extra = extra;
-
- float aspect = safe_sqrtf(1.0f - anisotropic * 0.9f);
- float r2 = roughness * roughness;
-
- bsdf->alpha_x = r2 / aspect;
- bsdf->alpha_y = r2 * aspect;
-
- float m_cdlum = 0.3f * base_color.x + 0.6f * base_color.y +
- 0.1f * base_color.z; // luminance approx.
- float3 m_ctint = m_cdlum > 0.0f ?
- base_color / m_cdlum :
- make_float3(
- 1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat
- float3 tmp_col = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - specular_tint) +
- m_ctint * specular_tint;
-
- bsdf->extra->cspec0 = (specular * 0.08f * tmp_col) * (1.0f - metallic) +
- base_color * metallic;
- bsdf->extra->color = base_color;
- bsdf->extra->clearcoat = 0.0f;
-
- /* setup bsdf */
- if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID ||
- roughness <= 0.075f) /* use single-scatter GGX */
- sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd);
- else /* use multi-scatter GGX */
- sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd);
- }
- }
-# ifdef __CAUSTICS_TRICKS__
- }
-# endif
-
- /* BSDF */
-# ifdef __CAUSTICS_TRICKS__
- if (kernel_data.integrator.caustics_reflective ||
- kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) {
-# endif
- if (final_transmission > CLOSURE_WEIGHT_CUTOFF) {
- float3 glass_weight = weight * final_transmission;
- float3 cspec0 = base_color * specular_tint +
- make_float3(1.0f, 1.0f, 1.0f) * (1.0f - specular_tint);
-
- if (roughness <= 5e-2f ||
- distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) { /* use single-scatter GGX */
- float refl_roughness = roughness;
-
- /* reflection */
-# ifdef __CAUSTICS_TRICKS__
- if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0)
-# endif
- {
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), glass_weight * fresnel);
- ccl_private MicrofacetExtra *extra =
- (bsdf != NULL) ? (ccl_private MicrofacetExtra *)closure_alloc_extra(
- sd, sizeof(MicrofacetExtra)) :
- NULL;
-
- if (bsdf && extra) {
- bsdf->N = N;
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra = extra;
-
- bsdf->alpha_x = refl_roughness * refl_roughness;
- bsdf->alpha_y = refl_roughness * refl_roughness;
- bsdf->ior = ior;
-
- bsdf->extra->color = base_color;
- bsdf->extra->cspec0 = cspec0;
- bsdf->extra->clearcoat = 0.0f;
-
- /* setup bsdf */
- sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd);
- }
- }
-
- /* refraction */
-# ifdef __CAUSTICS_TRICKS__
- if (kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0)
-# endif
- {
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), base_color * glass_weight * (1.0f - fresnel));
- if (bsdf) {
- bsdf->N = N;
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra = NULL;
-
- if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID)
- transmission_roughness = 1.0f - (1.0f - refl_roughness) *
- (1.0f - transmission_roughness);
- else
- transmission_roughness = refl_roughness;
-
- bsdf->alpha_x = transmission_roughness * transmission_roughness;
- bsdf->alpha_y = transmission_roughness * transmission_roughness;
- bsdf->ior = ior;
-
- /* setup bsdf */
- sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
- }
- }
- }
- else { /* use multi-scatter GGX */
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), glass_weight);
- ccl_private MicrofacetExtra *extra =
- (bsdf != NULL) ? (ccl_private MicrofacetExtra *)closure_alloc_extra(
- sd, sizeof(MicrofacetExtra)) :
- NULL;
-
- if (bsdf && extra) {
- bsdf->N = N;
- bsdf->extra = extra;
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
-
- bsdf->alpha_x = roughness * roughness;
- bsdf->alpha_y = roughness * roughness;
- bsdf->ior = ior;
-
- bsdf->extra->color = base_color;
- bsdf->extra->cspec0 = cspec0;
- bsdf->extra->clearcoat = 0.0f;
-
- /* setup bsdf */
- sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf, sd);
- }
- }
- }
-# ifdef __CAUSTICS_TRICKS__
- }
-# endif
-
- /* clearcoat */
-# ifdef __CAUSTICS_TRICKS__
- if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) {
-# endif
- if (clearcoat > CLOSURE_WEIGHT_CUTOFF) {
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), weight);
- ccl_private MicrofacetExtra *extra =
- (bsdf != NULL) ?
- (ccl_private MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra)) :
- NULL;
-
- if (bsdf && extra) {
- bsdf->N = clearcoat_normal;
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->ior = 1.5f;
- bsdf->extra = extra;
-
- bsdf->alpha_x = clearcoat_roughness * clearcoat_roughness;
- bsdf->alpha_y = clearcoat_roughness * clearcoat_roughness;
-
- bsdf->extra->color = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra->cspec0 = make_float3(0.04f, 0.04f, 0.04f);
- bsdf->extra->clearcoat = clearcoat;
-
- /* setup bsdf */
- sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(bsdf, sd);
- }
- }
-# ifdef __CAUSTICS_TRICKS__
- }
-# endif
-
- break;
- }
-#endif /* __PRINCIPLED__ */
- case CLOSURE_BSDF_DIFFUSE_ID: {
- float3 weight = sd->svm_closure_weight * mix_weight;
- ccl_private OrenNayarBsdf *bsdf = (ccl_private OrenNayarBsdf *)bsdf_alloc(
- sd, sizeof(OrenNayarBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
-
- float roughness = param1;
-
- if (roughness == 0.0f) {
- sd->flag |= bsdf_diffuse_setup((ccl_private DiffuseBsdf *)bsdf);
- }
- else {
- bsdf->roughness = roughness;
- sd->flag |= bsdf_oren_nayar_setup(bsdf);
- }
- }
- break;
- }
- case CLOSURE_BSDF_TRANSLUCENT_ID: {
- float3 weight = sd->svm_closure_weight * mix_weight;
- ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc(
- sd, sizeof(DiffuseBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
- sd->flag |= bsdf_translucent_setup(bsdf);
- }
- break;
- }
- case CLOSURE_BSDF_TRANSPARENT_ID: {
- float3 weight = sd->svm_closure_weight * mix_weight;
- bsdf_transparent_setup(sd, weight, path_flag);
- break;
- }
- case CLOSURE_BSDF_REFLECTION_ID:
- case CLOSURE_BSDF_MICROFACET_GGX_ID:
- case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
- case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
- case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: {
-#ifdef __CAUSTICS_TRICKS__
- if (!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
- break;
-#endif
- float3 weight = sd->svm_closure_weight * mix_weight;
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), weight);
-
- if (!bsdf) {
- break;
- }
-
- float roughness = sqr(param1);
-
- bsdf->N = N;
- bsdf->ior = 0.0f;
- bsdf->extra = NULL;
-
- if (data_node.y == SVM_STACK_INVALID) {
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->alpha_x = roughness;
- bsdf->alpha_y = roughness;
- }
- else {
- bsdf->T = stack_load_float3(stack, data_node.y);
-
- /* rotate tangent */
- float rotation = stack_load_float(stack, data_node.z);
- if (rotation != 0.0f)
- bsdf->T = rotate_around_axis(bsdf->T, bsdf->N, rotation * M_2PI_F);
-
- /* compute roughness */
- float anisotropy = clamp(param2, -0.99f, 0.99f);
- if (anisotropy < 0.0f) {
- bsdf->alpha_x = roughness / (1.0f + anisotropy);
- bsdf->alpha_y = roughness * (1.0f + anisotropy);
- }
- else {
- bsdf->alpha_x = roughness * (1.0f - anisotropy);
- bsdf->alpha_y = roughness / (1.0f - anisotropy);
- }
- }
-
- /* setup bsdf */
- if (type == CLOSURE_BSDF_REFLECTION_ID)
- sd->flag |= bsdf_reflection_setup(bsdf);
- else if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID)
- sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
- else if (type == CLOSURE_BSDF_MICROFACET_GGX_ID)
- sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
- else if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
- kernel_assert(stack_valid(data_node.w));
- bsdf->extra = (ccl_private MicrofacetExtra *)closure_alloc_extra(sd,
- sizeof(MicrofacetExtra));
- if (bsdf->extra) {
- bsdf->extra->color = stack_load_float3(stack, data_node.w);
- bsdf->extra->cspec0 = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra->clearcoat = 0.0f;
- sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf);
- }
- }
- else {
- sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf);
- }
-
- break;
- }
- case CLOSURE_BSDF_REFRACTION_ID:
- case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
- case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: {
-#ifdef __CAUSTICS_TRICKS__
- if (!kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
- break;
-#endif
- float3 weight = sd->svm_closure_weight * mix_weight;
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra = NULL;
-
- float eta = fmaxf(param2, 1e-5f);
- eta = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
-
- /* setup bsdf */
- if (type == CLOSURE_BSDF_REFRACTION_ID) {
- bsdf->alpha_x = 0.0f;
- bsdf->alpha_y = 0.0f;
- bsdf->ior = eta;
-
- sd->flag |= bsdf_refraction_setup(bsdf);
- }
- else {
- float roughness = sqr(param1);
- bsdf->alpha_x = roughness;
- bsdf->alpha_y = roughness;
- bsdf->ior = eta;
-
- if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID)
- sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
- else
- sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
- }
- }
-
- break;
- }
- case CLOSURE_BSDF_SHARP_GLASS_ID:
- case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:
- case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: {
-#ifdef __CAUSTICS_TRICKS__
- if (!kernel_data.integrator.caustics_reflective &&
- !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) {
- break;
- }
-#endif
- float3 weight = sd->svm_closure_weight * mix_weight;
-
- /* index of refraction */
- float eta = fmaxf(param2, 1e-5f);
- eta = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
-
- /* fresnel */
- float cosNO = dot(N, sd->I);
- float fresnel = fresnel_dielectric_cos(cosNO, eta);
- float roughness = sqr(param1);
-
- /* reflection */
-#ifdef __CAUSTICS_TRICKS__
- if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0)
-#endif
- {
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), weight * fresnel);
-
- if (bsdf) {
- bsdf->N = N;
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra = NULL;
- svm_node_glass_setup(sd, bsdf, type, eta, roughness, false);
- }
- }
-
- /* refraction */
-#ifdef __CAUSTICS_TRICKS__
- if (kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0)
-#endif
- {
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), weight * (1.0f - fresnel));
-
- if (bsdf) {
- bsdf->N = N;
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra = NULL;
- svm_node_glass_setup(sd, bsdf, type, eta, roughness, true);
- }
- }
-
- break;
- }
- case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: {
-#ifdef __CAUSTICS_TRICKS__
- if (!kernel_data.integrator.caustics_reflective &&
- !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
- break;
-#endif
- float3 weight = sd->svm_closure_weight * mix_weight;
- ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), weight);
- if (!bsdf) {
- break;
- }
-
- ccl_private MicrofacetExtra *extra = (ccl_private MicrofacetExtra *)closure_alloc_extra(
- sd, sizeof(MicrofacetExtra));
- if (!extra) {
- break;
- }
-
- bsdf->N = N;
- bsdf->extra = extra;
- bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
-
- float roughness = sqr(param1);
- bsdf->alpha_x = roughness;
- bsdf->alpha_y = roughness;
- float eta = fmaxf(param2, 1e-5f);
- bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
-
- kernel_assert(stack_valid(data_node.z));
- bsdf->extra->color = stack_load_float3(stack, data_node.z);
- bsdf->extra->cspec0 = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->extra->clearcoat = 0.0f;
-
- /* setup bsdf */
- sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(bsdf);
- break;
- }
- case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: {
- float3 weight = sd->svm_closure_weight * mix_weight;
- ccl_private VelvetBsdf *bsdf = (ccl_private VelvetBsdf *)bsdf_alloc(
- sd, sizeof(VelvetBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
-
- bsdf->sigma = saturate(param1);
- sd->flag |= bsdf_ashikhmin_velvet_setup(bsdf);
- }
- break;
- }
- case CLOSURE_BSDF_GLOSSY_TOON_ID:
-#ifdef __CAUSTICS_TRICKS__
- if (!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
- break;
- ATTR_FALLTHROUGH;
-#endif
- case CLOSURE_BSDF_DIFFUSE_TOON_ID: {
- float3 weight = sd->svm_closure_weight * mix_weight;
- ccl_private ToonBsdf *bsdf = (ccl_private ToonBsdf *)bsdf_alloc(
- sd, sizeof(ToonBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
- bsdf->size = param1;
- bsdf->smooth = param2;
-
- if (type == CLOSURE_BSDF_DIFFUSE_TOON_ID)
- sd->flag |= bsdf_diffuse_toon_setup(bsdf);
- else
- sd->flag |= bsdf_glossy_toon_setup(bsdf);
- }
- break;
- }
-#ifdef __HAIR__
- case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: {
- uint4 data_node2 = read_node(kg, &offset);
- uint4 data_node3 = read_node(kg, &offset);
- uint4 data_node4 = read_node(kg, &offset);
-
- float3 weight = sd->svm_closure_weight * mix_weight;
-
- uint offset_ofs, ior_ofs, color_ofs, parametrization;
- svm_unpack_node_uchar4(data_node.y, &offset_ofs, &ior_ofs, &color_ofs, &parametrization);
- float alpha = stack_load_float_default(stack, offset_ofs, data_node.z);
- float ior = stack_load_float_default(stack, ior_ofs, data_node.w);
-
- uint coat_ofs, melanin_ofs, melanin_redness_ofs, absorption_coefficient_ofs;
- svm_unpack_node_uchar4(data_node2.x,
- &coat_ofs,
- &melanin_ofs,
- &melanin_redness_ofs,
- &absorption_coefficient_ofs);
-
- uint tint_ofs, random_ofs, random_color_ofs, random_roughness_ofs;
- svm_unpack_node_uchar4(
- data_node3.x, &tint_ofs, &random_ofs, &random_color_ofs, &random_roughness_ofs);
-
- const AttributeDescriptor attr_descr_random = find_attribute(kg, sd, data_node4.y);
- float random = 0.0f;
- if (attr_descr_random.offset != ATTR_STD_NOT_FOUND) {
- random = primitive_surface_attribute_float(kg, sd, attr_descr_random, NULL, NULL);
- }
- else {
- random = stack_load_float_default(stack, random_ofs, data_node3.y);
- }
-
- ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)bsdf_alloc(
- sd, sizeof(PrincipledHairBSDF), weight);
- if (bsdf) {
- ccl_private PrincipledHairExtra *extra = (ccl_private PrincipledHairExtra *)
- closure_alloc_extra(sd, sizeof(PrincipledHairExtra));
-
- if (!extra)
- break;
-
- /* Random factors range: [-randomization/2, +randomization/2]. */
- float random_roughness = stack_load_float_default(
- stack, random_roughness_ofs, data_node3.w);
- float factor_random_roughness = 1.0f + 2.0f * (random - 0.5f) * random_roughness;
- float roughness = param1 * factor_random_roughness;
- float radial_roughness = param2 * factor_random_roughness;
-
- /* Remap Coat value to [0, 100]% of Roughness. */
- float coat = stack_load_float_default(stack, coat_ofs, data_node2.y);
- float m0_roughness = 1.0f - clamp(coat, 0.0f, 1.0f);
-
- bsdf->N = N;
- bsdf->v = roughness;
- bsdf->s = radial_roughness;
- bsdf->m0_roughness = m0_roughness;
- bsdf->alpha = alpha;
- bsdf->eta = ior;
- bsdf->extra = extra;
-
- switch (parametrization) {
- case NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION: {
- float3 absorption_coefficient = stack_load_float3(stack, absorption_coefficient_ofs);
- bsdf->sigma = absorption_coefficient;
- break;
- }
- case NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION: {
- float melanin = stack_load_float_default(stack, melanin_ofs, data_node2.z);
- float melanin_redness = stack_load_float_default(
- stack, melanin_redness_ofs, data_node2.w);
-
- /* Randomize melanin. */
- float random_color = stack_load_float_default(stack, random_color_ofs, data_node3.z);
- random_color = clamp(random_color, 0.0f, 1.0f);
- float factor_random_color = 1.0f + 2.0f * (random - 0.5f) * random_color;
- melanin *= factor_random_color;
-
- /* Map melanin 0..inf from more perceptually linear 0..1. */
- melanin = -logf(fmaxf(1.0f - melanin, 0.0001f));
-
- /* Benedikt Bitterli's melanin ratio remapping. */
- float eumelanin = melanin * (1.0f - melanin_redness);
- float pheomelanin = melanin * melanin_redness;
- float3 melanin_sigma = bsdf_principled_hair_sigma_from_concentration(eumelanin,
- pheomelanin);
-
- /* Optional tint. */
- float3 tint = stack_load_float3(stack, tint_ofs);
- float3 tint_sigma = bsdf_principled_hair_sigma_from_reflectance(tint,
- radial_roughness);
-
- bsdf->sigma = melanin_sigma + tint_sigma;
- break;
- }
- case NODE_PRINCIPLED_HAIR_REFLECTANCE: {
- float3 color = stack_load_float3(stack, color_ofs);
- bsdf->sigma = bsdf_principled_hair_sigma_from_reflectance(color, radial_roughness);
- break;
- }
- default: {
- /* Fallback to brownish hair, same as defaults for melanin. */
- kernel_assert(!"Invalid Principled Hair parametrization!");
- bsdf->sigma = bsdf_principled_hair_sigma_from_concentration(0.0f, 0.8054375f);
- break;
- }
- }
-
- sd->flag |= bsdf_principled_hair_setup(sd, bsdf);
- }
- break;
- }
- case CLOSURE_BSDF_HAIR_REFLECTION_ID:
- case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: {
- float3 weight = sd->svm_closure_weight * mix_weight;
-
- ccl_private HairBsdf *bsdf = (ccl_private HairBsdf *)bsdf_alloc(
- sd, sizeof(HairBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
- bsdf->roughness1 = param1;
- bsdf->roughness2 = param2;
- bsdf->offset = -stack_load_float(stack, data_node.z);
-
- if (stack_valid(data_node.y)) {
- bsdf->T = normalize(stack_load_float3(stack, data_node.y));
- }
- else if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
- bsdf->T = normalize(sd->dPdv);
- bsdf->offset = 0.0f;
- }
- else
- bsdf->T = normalize(sd->dPdu);
-
- if (type == CLOSURE_BSDF_HAIR_REFLECTION_ID) {
- sd->flag |= bsdf_hair_reflection_setup(bsdf);
- }
- else {
- sd->flag |= bsdf_hair_transmission_setup(bsdf);
- }
- }
-
- break;
- }
-#endif /* __HAIR__ */
-
-#ifdef __SUBSURFACE__
- case CLOSURE_BSSRDF_BURLEY_ID:
- case CLOSURE_BSSRDF_RANDOM_WALK_ID:
- case CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID: {
- float3 weight = sd->svm_closure_weight * mix_weight;
- ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd, weight);
-
- if (bssrdf) {
- /* disable in case of diffuse ancestor, can't see it well then and
- * adds considerably noise due to probabilities of continuing path
- * getting lower and lower */
- if (path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
- param1 = 0.0f;
-
- bssrdf->radius = stack_load_float3(stack, data_node.z) * param1;
- bssrdf->albedo = sd->svm_closure_weight;
- bssrdf->N = N;
- bssrdf->roughness = FLT_MAX;
-
- const float subsurface_ior = clamp(param2, 1.01f, 3.8f);
- const float subsurface_anisotropy = stack_load_float(stack, data_node.w);
- bssrdf->anisotropy = clamp(subsurface_anisotropy, 0.0f, 0.9f);
-
- sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)type, subsurface_ior);
- }
-
- break;
- }
-#endif
- default:
- break;
- }
-
- return offset;
-}
-
-template<ShaderType shader_type>
-ccl_device_noinline void svm_node_closure_volume(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
-#ifdef __VOLUME__
- /* Only sum extinction for volumes, variable is shared with surface transparency. */
- if (shader_type != SHADER_TYPE_VOLUME) {
- return;
- }
-
- uint type, density_offset, anisotropy_offset;
-
- uint mix_weight_offset;
- svm_unpack_node_uchar4(node.y, &type, &density_offset, &anisotropy_offset, &mix_weight_offset);
- float mix_weight = (stack_valid(mix_weight_offset) ? stack_load_float(stack, mix_weight_offset) :
- 1.0f);
-
- if (mix_weight == 0.0f) {
- return;
- }
-
- float density = (stack_valid(density_offset)) ? stack_load_float(stack, density_offset) :
- __uint_as_float(node.z);
- density = mix_weight * fmaxf(density, 0.0f);
-
- /* Compute scattering coefficient. */
- float3 weight = sd->svm_closure_weight;
-
- if (type == CLOSURE_VOLUME_ABSORPTION_ID) {
- weight = make_float3(1.0f, 1.0f, 1.0f) - weight;
- }
-
- weight *= density;
-
- /* Add closure for volume scattering. */
- if (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) {
- ccl_private HenyeyGreensteinVolume *volume = (ccl_private HenyeyGreensteinVolume *)bsdf_alloc(
- sd, sizeof(HenyeyGreensteinVolume), weight);
-
- if (volume) {
- float anisotropy = (stack_valid(anisotropy_offset)) ?
- stack_load_float(stack, anisotropy_offset) :
- __uint_as_float(node.w);
- volume->g = anisotropy; /* g */
- sd->flag |= volume_henyey_greenstein_setup(volume);
- }
- }
-
- /* Sum total extinction weight. */
- volume_extinction_setup(sd, weight);
-#endif
-}
-
-template<ShaderType shader_type>
-ccl_device_noinline int svm_node_principled_volume(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node,
- uint32_t path_flag,
- int offset)
-{
-#ifdef __VOLUME__
- uint4 value_node = read_node(kg, &offset);
- uint4 attr_node = read_node(kg, &offset);
-
- /* Only sum extinction for volumes, variable is shared with surface transparency. */
- if (shader_type != SHADER_TYPE_VOLUME) {
- return offset;
- }
-
- uint density_offset, anisotropy_offset, absorption_color_offset, mix_weight_offset;
- svm_unpack_node_uchar4(
- node.y, &density_offset, &anisotropy_offset, &absorption_color_offset, &mix_weight_offset);
- float mix_weight = (stack_valid(mix_weight_offset) ? stack_load_float(stack, mix_weight_offset) :
- 1.0f);
-
- if (mix_weight == 0.0f) {
- return offset;
- }
-
- /* Compute density. */
- float primitive_density = 1.0f;
- float density = (stack_valid(density_offset)) ? stack_load_float(stack, density_offset) :
- __uint_as_float(value_node.x);
- density = mix_weight * fmaxf(density, 0.0f);
-
- if (density > CLOSURE_WEIGHT_CUTOFF) {
- /* Density and color attribute lookup if available. */
- const AttributeDescriptor attr_density = find_attribute(kg, sd, attr_node.x);
- if (attr_density.offset != ATTR_STD_NOT_FOUND) {
- primitive_density = primitive_volume_attribute_float(kg, sd, attr_density);
- density = fmaxf(density * primitive_density, 0.0f);
- }
- }
-
- if (density > CLOSURE_WEIGHT_CUTOFF) {
- /* Compute scattering color. */
- float3 color = sd->svm_closure_weight;
-
- const AttributeDescriptor attr_color = find_attribute(kg, sd, attr_node.y);
- if (attr_color.offset != ATTR_STD_NOT_FOUND) {
- color *= primitive_volume_attribute_float3(kg, sd, attr_color);
- }
-
- /* Add closure for volume scattering. */
- ccl_private HenyeyGreensteinVolume *volume = (ccl_private HenyeyGreensteinVolume *)bsdf_alloc(
- sd, sizeof(HenyeyGreensteinVolume), color * density);
- if (volume) {
- float anisotropy = (stack_valid(anisotropy_offset)) ?
- stack_load_float(stack, anisotropy_offset) :
- __uint_as_float(value_node.y);
- volume->g = anisotropy;
- sd->flag |= volume_henyey_greenstein_setup(volume);
- }
-
- /* Add extinction weight. */
- float3 zero = make_float3(0.0f, 0.0f, 0.0f);
- float3 one = make_float3(1.0f, 1.0f, 1.0f);
- float3 absorption_color = max(sqrt(stack_load_float3(stack, absorption_color_offset)), zero);
- float3 absorption = max(one - color, zero) * max(one - absorption_color, zero);
- volume_extinction_setup(sd, (color + absorption) * density);
- }
-
- /* Compute emission. */
- if (path_flag & PATH_RAY_SHADOW) {
- /* Don't need emission for shadows. */
- return offset;
- }
-
- uint emission_offset, emission_color_offset, blackbody_offset, temperature_offset;
- svm_unpack_node_uchar4(
- node.z, &emission_offset, &emission_color_offset, &blackbody_offset, &temperature_offset);
- float emission = (stack_valid(emission_offset)) ? stack_load_float(stack, emission_offset) :
- __uint_as_float(value_node.z);
- float blackbody = (stack_valid(blackbody_offset)) ? stack_load_float(stack, blackbody_offset) :
- __uint_as_float(value_node.w);
-
- if (emission > CLOSURE_WEIGHT_CUTOFF) {
- float3 emission_color = stack_load_float3(stack, emission_color_offset);
- emission_setup(sd, emission * emission_color);
- }
-
- if (blackbody > CLOSURE_WEIGHT_CUTOFF) {
- float T = stack_load_float(stack, temperature_offset);
-
- /* Add flame temperature from attribute if available. */
- const AttributeDescriptor attr_temperature = find_attribute(kg, sd, attr_node.z);
- if (attr_temperature.offset != ATTR_STD_NOT_FOUND) {
- float temperature = primitive_volume_attribute_float(kg, sd, attr_temperature);
- T *= fmaxf(temperature, 0.0f);
- }
-
- T = fmaxf(T, 0.0f);
-
- /* Stefan-Boltzmann law. */
- float T4 = sqr(sqr(T));
- float sigma = 5.670373e-8f * 1e-6f / M_PI_F;
- float intensity = sigma * mix(1.0f, T4, blackbody);
-
- if (intensity > CLOSURE_WEIGHT_CUTOFF) {
- float3 blackbody_tint = stack_load_float3(stack, node.w);
- float3 bb = blackbody_tint * intensity * svm_math_blackbody_color(T);
- emission_setup(sd, bb);
- }
- }
-#endif
- return offset;
-}
-
-ccl_device_noinline void svm_node_closure_emission(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint mix_weight_offset = node.y;
- float3 weight = sd->svm_closure_weight;
-
- if (stack_valid(mix_weight_offset)) {
- float mix_weight = stack_load_float(stack, mix_weight_offset);
-
- if (mix_weight == 0.0f)
- return;
-
- weight *= mix_weight;
- }
-
- emission_setup(sd, weight);
-}
-
-ccl_device_noinline void svm_node_closure_background(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint mix_weight_offset = node.y;
- float3 weight = sd->svm_closure_weight;
-
- if (stack_valid(mix_weight_offset)) {
- float mix_weight = stack_load_float(stack, mix_weight_offset);
-
- if (mix_weight == 0.0f)
- return;
-
- weight *= mix_weight;
- }
-
- background_setup(sd, weight);
-}
-
-ccl_device_noinline void svm_node_closure_holdout(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint mix_weight_offset = node.y;
-
- if (stack_valid(mix_weight_offset)) {
- float mix_weight = stack_load_float(stack, mix_weight_offset);
-
- if (mix_weight == 0.0f)
- return;
-
- closure_alloc(
- sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, sd->svm_closure_weight * mix_weight);
- }
- else
- closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, sd->svm_closure_weight);
-
- sd->flag |= SD_HOLDOUT;
-}
-
-/* Closure Nodes */
-
-ccl_device_inline void svm_node_closure_store_weight(ccl_private ShaderData *sd, float3 weight)
-{
- sd->svm_closure_weight = weight;
-}
-
-ccl_device void svm_node_closure_set_weight(ccl_private ShaderData *sd, uint r, uint g, uint b)
-{
- float3 weight = make_float3(__uint_as_float(r), __uint_as_float(g), __uint_as_float(b));
- svm_node_closure_store_weight(sd, weight);
-}
-
-ccl_device void svm_node_closure_weight(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint weight_offset)
-{
- float3 weight = stack_load_float3(stack, weight_offset);
- svm_node_closure_store_weight(sd, weight);
-}
-
-ccl_device_noinline void svm_node_emission_weight(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint color_offset = node.y;
- uint strength_offset = node.z;
-
- float strength = stack_load_float(stack, strength_offset);
- float3 weight = stack_load_float3(stack, color_offset) * strength;
-
- svm_node_closure_store_weight(sd, weight);
-}
-
-ccl_device_noinline void svm_node_mix_closure(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- /* fetch weight from blend input, previous mix closures,
- * and write to stack to be used by closure nodes later */
- uint weight_offset, in_weight_offset, weight1_offset, weight2_offset;
- svm_unpack_node_uchar4(
- node.y, &weight_offset, &in_weight_offset, &weight1_offset, &weight2_offset);
-
- float weight = stack_load_float(stack, weight_offset);
- weight = saturate(weight);
-
- float in_weight = (stack_valid(in_weight_offset)) ? stack_load_float(stack, in_weight_offset) :
- 1.0f;
-
- if (stack_valid(weight1_offset))
- stack_store_float(stack, weight1_offset, in_weight * (1.0f - weight));
- if (stack_valid(weight2_offset))
- stack_store_float(stack, weight2_offset, in_weight * weight);
-}
-
-/* (Bump) normal */
-
-ccl_device void svm_node_set_normal(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint in_direction,
- uint out_normal)
-{
- float3 normal = stack_load_float3(stack, in_direction);
- sd->N = normal;
- stack_store_float3(stack, out_normal, normal);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_color_util.h b/intern/cycles/kernel/svm/svm_color_util.h
deleted file mode 100644
index 1a0fa03305e..00000000000
--- a/intern/cycles/kernel/svm/svm_color_util.h
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device float3 svm_mix_blend(float t, float3 col1, float3 col2)
-{
- return interp(col1, col2, t);
-}
-
-ccl_device float3 svm_mix_add(float t, float3 col1, float3 col2)
-{
- return interp(col1, col1 + col2, t);
-}
-
-ccl_device float3 svm_mix_mul(float t, float3 col1, float3 col2)
-{
- return interp(col1, col1 * col2, t);
-}
-
-ccl_device float3 svm_mix_screen(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
- float3 one = make_float3(1.0f, 1.0f, 1.0f);
- float3 tm3 = make_float3(tm, tm, tm);
-
- return one - (tm3 + t * (one - col2)) * (one - col1);
-}
-
-ccl_device float3 svm_mix_overlay(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
-
- float3 outcol = col1;
-
- if (outcol.x < 0.5f)
- outcol.x *= tm + 2.0f * t * col2.x;
- else
- outcol.x = 1.0f - (tm + 2.0f * t * (1.0f - col2.x)) * (1.0f - outcol.x);
-
- if (outcol.y < 0.5f)
- outcol.y *= tm + 2.0f * t * col2.y;
- else
- outcol.y = 1.0f - (tm + 2.0f * t * (1.0f - col2.y)) * (1.0f - outcol.y);
-
- if (outcol.z < 0.5f)
- outcol.z *= tm + 2.0f * t * col2.z;
- else
- outcol.z = 1.0f - (tm + 2.0f * t * (1.0f - col2.z)) * (1.0f - outcol.z);
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_sub(float t, float3 col1, float3 col2)
-{
- return interp(col1, col1 - col2, t);
-}
-
-ccl_device float3 svm_mix_div(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
-
- float3 outcol = col1;
-
- if (col2.x != 0.0f)
- outcol.x = tm * outcol.x + t * outcol.x / col2.x;
- if (col2.y != 0.0f)
- outcol.y = tm * outcol.y + t * outcol.y / col2.y;
- if (col2.z != 0.0f)
- outcol.z = tm * outcol.z + t * outcol.z / col2.z;
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2)
-{
- return interp(col1, fabs(col1 - col2), t);
-}
-
-ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2)
-{
- return interp(col1, min(col1, col2), t);
-}
-
-ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2)
-{
- return interp(col1, max(col1, col2), t);
-}
-
-ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2)
-{
- float3 outcol = col1;
-
- if (outcol.x != 0.0f) {
- float tmp = 1.0f - t * col2.x;
- if (tmp <= 0.0f)
- outcol.x = 1.0f;
- else if ((tmp = outcol.x / tmp) > 1.0f)
- outcol.x = 1.0f;
- else
- outcol.x = tmp;
- }
- if (outcol.y != 0.0f) {
- float tmp = 1.0f - t * col2.y;
- if (tmp <= 0.0f)
- outcol.y = 1.0f;
- else if ((tmp = outcol.y / tmp) > 1.0f)
- outcol.y = 1.0f;
- else
- outcol.y = tmp;
- }
- if (outcol.z != 0.0f) {
- float tmp = 1.0f - t * col2.z;
- if (tmp <= 0.0f)
- outcol.z = 1.0f;
- else if ((tmp = outcol.z / tmp) > 1.0f)
- outcol.z = 1.0f;
- else
- outcol.z = tmp;
- }
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_burn(float t, float3 col1, float3 col2)
-{
- float tmp, tm = 1.0f - t;
-
- float3 outcol = col1;
-
- tmp = tm + t * col2.x;
- if (tmp <= 0.0f)
- outcol.x = 0.0f;
- else if ((tmp = (1.0f - (1.0f - outcol.x) / tmp)) < 0.0f)
- outcol.x = 0.0f;
- else if (tmp > 1.0f)
- outcol.x = 1.0f;
- else
- outcol.x = tmp;
-
- tmp = tm + t * col2.y;
- if (tmp <= 0.0f)
- outcol.y = 0.0f;
- else if ((tmp = (1.0f - (1.0f - outcol.y) / tmp)) < 0.0f)
- outcol.y = 0.0f;
- else if (tmp > 1.0f)
- outcol.y = 1.0f;
- else
- outcol.y = tmp;
-
- tmp = tm + t * col2.z;
- if (tmp <= 0.0f)
- outcol.z = 0.0f;
- else if ((tmp = (1.0f - (1.0f - outcol.z) / tmp)) < 0.0f)
- outcol.z = 0.0f;
- else if (tmp > 1.0f)
- outcol.z = 1.0f;
- else
- outcol.z = tmp;
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_hue(float t, float3 col1, float3 col2)
-{
- float3 outcol = col1;
-
- float3 hsv2 = rgb_to_hsv(col2);
-
- if (hsv2.y != 0.0f) {
- float3 hsv = rgb_to_hsv(outcol);
- hsv.x = hsv2.x;
- float3 tmp = hsv_to_rgb(hsv);
-
- outcol = interp(outcol, tmp, t);
- }
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_sat(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
-
- float3 outcol = col1;
-
- float3 hsv = rgb_to_hsv(outcol);
-
- if (hsv.y != 0.0f) {
- float3 hsv2 = rgb_to_hsv(col2);
-
- hsv.y = tm * hsv.y + t * hsv2.y;
- outcol = hsv_to_rgb(hsv);
- }
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_val(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
-
- float3 hsv = rgb_to_hsv(col1);
- float3 hsv2 = rgb_to_hsv(col2);
-
- hsv.z = tm * hsv.z + t * hsv2.z;
-
- return hsv_to_rgb(hsv);
-}
-
-ccl_device float3 svm_mix_color(float t, float3 col1, float3 col2)
-{
- float3 outcol = col1;
- float3 hsv2 = rgb_to_hsv(col2);
-
- if (hsv2.y != 0.0f) {
- float3 hsv = rgb_to_hsv(outcol);
- hsv.x = hsv2.x;
- hsv.y = hsv2.y;
- float3 tmp = hsv_to_rgb(hsv);
-
- outcol = interp(outcol, tmp, t);
- }
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_soft(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
-
- float3 one = make_float3(1.0f, 1.0f, 1.0f);
- float3 scr = one - (one - col2) * (one - col1);
-
- return tm * col1 + t * ((one - col1) * col2 * col1 + col1 * scr);
-}
-
-ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2)
-{
- return col1 + t * (2.0f * col2 + make_float3(-1.0f, -1.0f, -1.0f));
-}
-
-ccl_device float3 svm_mix_clamp(float3 col)
-{
- return saturate3(col);
-}
-
-ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
-{
- float t = saturate(fac);
-
- switch (type) {
- case NODE_MIX_BLEND:
- return svm_mix_blend(t, c1, c2);
- case NODE_MIX_ADD:
- return svm_mix_add(t, c1, c2);
- case NODE_MIX_MUL:
- return svm_mix_mul(t, c1, c2);
- case NODE_MIX_SCREEN:
- return svm_mix_screen(t, c1, c2);
- case NODE_MIX_OVERLAY:
- return svm_mix_overlay(t, c1, c2);
- case NODE_MIX_SUB:
- return svm_mix_sub(t, c1, c2);
- case NODE_MIX_DIV:
- return svm_mix_div(t, c1, c2);
- case NODE_MIX_DIFF:
- return svm_mix_diff(t, c1, c2);
- case NODE_MIX_DARK:
- return svm_mix_dark(t, c1, c2);
- case NODE_MIX_LIGHT:
- return svm_mix_light(t, c1, c2);
- case NODE_MIX_DODGE:
- return svm_mix_dodge(t, c1, c2);
- case NODE_MIX_BURN:
- return svm_mix_burn(t, c1, c2);
- case NODE_MIX_HUE:
- return svm_mix_hue(t, c1, c2);
- case NODE_MIX_SAT:
- return svm_mix_sat(t, c1, c2);
- case NODE_MIX_VAL:
- return svm_mix_val(t, c1, c2);
- case NODE_MIX_COLOR:
- return svm_mix_color(t, c1, c2);
- case NODE_MIX_SOFT:
- return svm_mix_soft(t, c1, c2);
- case NODE_MIX_LINEAR:
- return svm_mix_linear(t, c1, c2);
- case NODE_MIX_CLAMP:
- return svm_mix_clamp(c1);
- }
-
- return make_float3(0.0f, 0.0f, 0.0f);
-}
-
-ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness, float contrast)
-{
- float a = 1.0f + contrast;
- float b = brightness - contrast * 0.5f;
-
- color.x = max(a * color.x + b, 0.0f);
- color.y = max(a * color.y + b, 0.0f);
- color.z = max(a * color.z + b, 0.0f);
-
- return color;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_convert.h b/intern/cycles/kernel/svm/svm_convert.h
deleted file mode 100644
index ec5745dc78a..00000000000
--- a/intern/cycles/kernel/svm/svm_convert.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Conversion Nodes */
-
-ccl_device_noinline void svm_node_convert(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint from,
- uint to)
-{
- switch (type) {
- case NODE_CONVERT_FI: {
- float f = stack_load_float(stack, from);
- stack_store_int(stack, to, float_to_int(f));
- break;
- }
- case NODE_CONVERT_FV: {
- float f = stack_load_float(stack, from);
- stack_store_float3(stack, to, make_float3(f, f, f));
- break;
- }
- case NODE_CONVERT_CF: {
- float3 f = stack_load_float3(stack, from);
- float g = linear_rgb_to_gray(kg, f);
- stack_store_float(stack, to, g);
- break;
- }
- case NODE_CONVERT_CI: {
- float3 f = stack_load_float3(stack, from);
- int i = (int)linear_rgb_to_gray(kg, f);
- stack_store_int(stack, to, i);
- break;
- }
- case NODE_CONVERT_VF: {
- float3 f = stack_load_float3(stack, from);
- float g = average(f);
- stack_store_float(stack, to, g);
- break;
- }
- case NODE_CONVERT_VI: {
- float3 f = stack_load_float3(stack, from);
- int i = (int)average(f);
- stack_store_int(stack, to, i);
- break;
- }
- case NODE_CONVERT_IF: {
- float f = (float)stack_load_int(stack, from);
- stack_store_float(stack, to, f);
- break;
- }
- case NODE_CONVERT_IV: {
- float f = (float)stack_load_int(stack, from);
- stack_store_float3(stack, to, make_float3(f, f, f));
- break;
- }
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_displace.h b/intern/cycles/kernel/svm/svm_displace.h
deleted file mode 100644
index f2446c3b3ef..00000000000
--- a/intern/cycles/kernel/svm/svm_displace.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "kernel/kernel_montecarlo.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Bump Node */
-
-ccl_device_noinline void svm_node_set_bump(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
-#ifdef __RAY_DIFFERENTIALS__
- /* get normal input */
- uint normal_offset, scale_offset, invert, use_object_space;
- svm_unpack_node_uchar4(node.y, &normal_offset, &scale_offset, &invert, &use_object_space);
-
- float3 normal_in = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N;
-
- float3 dPdx = sd->dP.dx;
- float3 dPdy = sd->dP.dy;
-
- if (use_object_space) {
- object_inverse_normal_transform(kg, sd, &normal_in);
- object_inverse_dir_transform(kg, sd, &dPdx);
- object_inverse_dir_transform(kg, sd, &dPdy);
- }
-
- /* get surface tangents from normal */
- float3 Rx = cross(dPdy, normal_in);
- float3 Ry = cross(normal_in, dPdx);
-
- /* get bump values */
- uint c_offset, x_offset, y_offset, strength_offset;
- svm_unpack_node_uchar4(node.z, &c_offset, &x_offset, &y_offset, &strength_offset);
-
- float h_c = stack_load_float(stack, c_offset);
- float h_x = stack_load_float(stack, x_offset);
- float h_y = stack_load_float(stack, y_offset);
-
- /* compute surface gradient and determinant */
- float det = dot(dPdx, Rx);
- float3 surfgrad = (h_x - h_c) * Rx + (h_y - h_c) * Ry;
-
- float absdet = fabsf(det);
-
- float strength = stack_load_float(stack, strength_offset);
- float scale = stack_load_float(stack, scale_offset);
-
- if (invert)
- scale *= -1.0f;
-
- strength = max(strength, 0.0f);
-
- /* compute and output perturbed normal */
- float3 normal_out = safe_normalize(absdet * normal_in - scale * signf(det) * surfgrad);
- if (is_zero(normal_out)) {
- normal_out = normal_in;
- }
- else {
- normal_out = normalize(strength * normal_out + (1.0f - strength) * normal_in);
- }
-
- if (use_object_space) {
- object_normal_transform(kg, sd, &normal_out);
- }
-
- normal_out = ensure_valid_reflection(sd->Ng, sd->I, normal_out);
-
- stack_store_float3(stack, node.w, normal_out);
-#endif
-}
-
-/* Displacement Node */
-
-ccl_device void svm_node_set_displacement(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint fac_offset)
-{
- float3 dP = stack_load_float3(stack, fac_offset);
- sd->P += dP;
-}
-
-ccl_device_noinline void svm_node_displacement(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint height_offset, midlevel_offset, scale_offset, normal_offset;
- svm_unpack_node_uchar4(node.y, &height_offset, &midlevel_offset, &scale_offset, &normal_offset);
-
- float height = stack_load_float(stack, height_offset);
- float midlevel = stack_load_float(stack, midlevel_offset);
- float scale = stack_load_float(stack, scale_offset);
- float3 normal = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N;
- uint space = node.w;
-
- float3 dP = normal;
-
- if (space == NODE_NORMAL_MAP_OBJECT) {
- /* Object space. */
- object_inverse_normal_transform(kg, sd, &dP);
- dP *= (height - midlevel) * scale;
- object_dir_transform(kg, sd, &dP);
- }
- else {
- /* World space. */
- dP *= (height - midlevel) * scale;
- }
-
- stack_store_float3(stack, node.z, dP);
-}
-
-ccl_device_noinline int svm_node_vector_displacement(
- KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
-{
- uint4 data_node = read_node(kg, &offset);
- uint space = data_node.x;
-
- uint vector_offset, midlevel_offset, scale_offset, displacement_offset;
- svm_unpack_node_uchar4(
- node.y, &vector_offset, &midlevel_offset, &scale_offset, &displacement_offset);
-
- float3 vector = stack_load_float3(stack, vector_offset);
- float midlevel = stack_load_float(stack, midlevel_offset);
- float scale = stack_load_float(stack, scale_offset);
- float3 dP = (vector - make_float3(midlevel, midlevel, midlevel)) * scale;
-
- if (space == NODE_NORMAL_MAP_TANGENT) {
- /* Tangent space. */
- float3 normal = sd->N;
- object_inverse_normal_transform(kg, sd, &normal);
-
- const AttributeDescriptor attr = find_attribute(kg, sd, node.z);
- float3 tangent;
- if (attr.offset != ATTR_STD_NOT_FOUND) {
- tangent = primitive_surface_attribute_float3(kg, sd, attr, NULL, NULL);
- }
- else {
- tangent = normalize(sd->dPdu);
- }
-
- float3 bitangent = normalize(cross(normal, tangent));
- const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.w);
- if (attr_sign.offset != ATTR_STD_NOT_FOUND) {
- float sign = primitive_surface_attribute_float(kg, sd, attr_sign, NULL, NULL);
- bitangent *= sign;
- }
-
- dP = tangent * dP.x + normal * dP.y + bitangent * dP.z;
- }
-
- if (space != NODE_NORMAL_MAP_WORLD) {
- /* Tangent or object space. */
- object_dir_transform(kg, sd, &dP);
- }
-
- stack_store_float3(stack, displacement_offset, dP);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_fractal_noise.h b/intern/cycles/kernel/svm/svm_fractal_noise.h
deleted file mode 100644
index 57fa8c690ac..00000000000
--- a/intern/cycles/kernel/svm/svm_fractal_noise.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
-ccl_device_noinline float fractal_noise_1d(float p, float octaves, float roughness)
-{
- float fscale = 1.0f;
- float amp = 1.0f;
- float maxamp = 0.0f;
- float sum = 0.0f;
- octaves = clamp(octaves, 0.0f, 16.0f);
- int n = float_to_int(octaves);
- for (int i = 0; i <= n; i++) {
- float t = noise_1d(fscale * p);
- sum += t * amp;
- maxamp += amp;
- amp *= clamp(roughness, 0.0f, 1.0f);
- fscale *= 2.0f;
- }
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- float t = noise_1d(fscale * p);
- float sum2 = sum + t * amp;
- sum /= maxamp;
- sum2 /= maxamp + amp;
- return (1.0f - rmd) * sum + rmd * sum2;
- }
- else {
- return sum / maxamp;
- }
-}
-
-/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
-ccl_device_noinline float fractal_noise_2d(float2 p, float octaves, float roughness)
-{
- float fscale = 1.0f;
- float amp = 1.0f;
- float maxamp = 0.0f;
- float sum = 0.0f;
- octaves = clamp(octaves, 0.0f, 16.0f);
- int n = float_to_int(octaves);
- for (int i = 0; i <= n; i++) {
- float t = noise_2d(fscale * p);
- sum += t * amp;
- maxamp += amp;
- amp *= clamp(roughness, 0.0f, 1.0f);
- fscale *= 2.0f;
- }
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- float t = noise_2d(fscale * p);
- float sum2 = sum + t * amp;
- sum /= maxamp;
- sum2 /= maxamp + amp;
- return (1.0f - rmd) * sum + rmd * sum2;
- }
- else {
- return sum / maxamp;
- }
-}
-
-/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
-ccl_device_noinline float fractal_noise_3d(float3 p, float octaves, float roughness)
-{
- float fscale = 1.0f;
- float amp = 1.0f;
- float maxamp = 0.0f;
- float sum = 0.0f;
- octaves = clamp(octaves, 0.0f, 16.0f);
- int n = float_to_int(octaves);
- for (int i = 0; i <= n; i++) {
- float t = noise_3d(fscale * p);
- sum += t * amp;
- maxamp += amp;
- amp *= clamp(roughness, 0.0f, 1.0f);
- fscale *= 2.0f;
- }
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- float t = noise_3d(fscale * p);
- float sum2 = sum + t * amp;
- sum /= maxamp;
- sum2 /= maxamp + amp;
- return (1.0f - rmd) * sum + rmd * sum2;
- }
- else {
- return sum / maxamp;
- }
-}
-
-/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
-ccl_device_noinline float fractal_noise_4d(float4 p, float octaves, float roughness)
-{
- float fscale = 1.0f;
- float amp = 1.0f;
- float maxamp = 0.0f;
- float sum = 0.0f;
- octaves = clamp(octaves, 0.0f, 16.0f);
- int n = float_to_int(octaves);
- for (int i = 0; i <= n; i++) {
- float t = noise_4d(fscale * p);
- sum += t * amp;
- maxamp += amp;
- amp *= clamp(roughness, 0.0f, 1.0f);
- fscale *= 2.0f;
- }
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- float t = noise_4d(fscale * p);
- float sum2 = sum + t * amp;
- sum /= maxamp;
- sum2 /= maxamp + amp;
- return (1.0f - rmd) * sum + rmd * sum2;
- }
- else {
- return sum / maxamp;
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_fresnel.h b/intern/cycles/kernel/svm/svm_fresnel.h
deleted file mode 100644
index 449ec84370f..00000000000
--- a/intern/cycles/kernel/svm/svm_fresnel.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Fresnel Node */
-
-ccl_device_noinline void svm_node_fresnel(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint ior_offset,
- uint ior_value,
- uint node)
-{
- uint normal_offset, out_offset;
- svm_unpack_node_uchar2(node, &normal_offset, &out_offset);
- float eta = (stack_valid(ior_offset)) ? stack_load_float(stack, ior_offset) :
- __uint_as_float(ior_value);
- float3 normal_in = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N;
-
- eta = fmaxf(eta, 1e-5f);
- eta = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
-
- float f = fresnel_dielectric_cos(dot(sd->I, normal_in), eta);
-
- stack_store_float(stack, out_offset, f);
-}
-
-/* Layer Weight Node */
-
-ccl_device_noinline void svm_node_layer_weight(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint blend_offset = node.y;
- uint blend_value = node.z;
-
- uint type, normal_offset, out_offset;
- svm_unpack_node_uchar3(node.w, &type, &normal_offset, &out_offset);
-
- float blend = (stack_valid(blend_offset)) ? stack_load_float(stack, blend_offset) :
- __uint_as_float(blend_value);
- float3 normal_in = (stack_valid(normal_offset)) ? stack_load_float3(stack, normal_offset) :
- sd->N;
-
- float f;
-
- if (type == NODE_LAYER_WEIGHT_FRESNEL) {
- float eta = fmaxf(1.0f - blend, 1e-5f);
- eta = (sd->flag & SD_BACKFACING) ? eta : 1.0f / eta;
-
- f = fresnel_dielectric_cos(dot(sd->I, normal_in), eta);
- }
- else {
- f = fabsf(dot(sd->I, normal_in));
-
- if (blend != 0.5f) {
- blend = clamp(blend, 0.0f, 1.0f - 1e-5f);
- blend = (blend < 0.5f) ? 2.0f * blend : 0.5f / (1.0f - blend);
-
- f = powf(f, blend);
- }
-
- f = 1.0f - f;
- }
-
- stack_store_float(stack, out_offset, f);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_gamma.h b/intern/cycles/kernel/svm/svm_gamma.h
deleted file mode 100644
index 7ec6c31065d..00000000000
--- a/intern/cycles/kernel/svm/svm_gamma.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_noinline void svm_node_gamma(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint in_gamma,
- uint in_color,
- uint out_color)
-{
- float3 color = stack_load_float3(stack, in_color);
- float gamma = stack_load_float(stack, in_gamma);
-
- color = svm_math_gamma_color(color, gamma);
-
- if (stack_valid(out_color))
- stack_store_float3(stack, out_color, color);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h
deleted file mode 100644
index b29bfdbed07..00000000000
--- a/intern/cycles/kernel/svm/svm_geometry.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Geometry Node */
-
-ccl_device_noinline void svm_node_geometry(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint out_offset)
-{
- float3 data;
-
- switch (type) {
- case NODE_GEOM_P:
- data = sd->P;
- break;
- case NODE_GEOM_N:
- data = sd->N;
- break;
-#ifdef __DPDU__
- case NODE_GEOM_T:
- data = primitive_tangent(kg, sd);
- break;
-#endif
- case NODE_GEOM_I:
- data = sd->I;
- break;
- case NODE_GEOM_Ng:
- data = sd->Ng;
- break;
- case NODE_GEOM_uv:
- data = make_float3(sd->u, sd->v, 0.0f);
- break;
- default:
- data = make_float3(0.0f, 0.0f, 0.0f);
- }
-
- stack_store_float3(stack, out_offset, data);
-}
-
-ccl_device_noinline void svm_node_geometry_bump_dx(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint out_offset)
-{
-#ifdef __RAY_DIFFERENTIALS__
- float3 data;
-
- switch (type) {
- case NODE_GEOM_P:
- data = sd->P + sd->dP.dx;
- break;
- case NODE_GEOM_uv:
- data = make_float3(sd->u + sd->du.dx, sd->v + sd->dv.dx, 0.0f);
- break;
- default:
- svm_node_geometry(kg, sd, stack, type, out_offset);
- return;
- }
-
- stack_store_float3(stack, out_offset, data);
-#else
- svm_node_geometry(kg, sd, stack, type, out_offset);
-#endif
-}
-
-ccl_device_noinline void svm_node_geometry_bump_dy(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint out_offset)
-{
-#ifdef __RAY_DIFFERENTIALS__
- float3 data;
-
- switch (type) {
- case NODE_GEOM_P:
- data = sd->P + sd->dP.dy;
- break;
- case NODE_GEOM_uv:
- data = make_float3(sd->u + sd->du.dy, sd->v + sd->dv.dy, 0.0f);
- break;
- default:
- svm_node_geometry(kg, sd, stack, type, out_offset);
- return;
- }
-
- stack_store_float3(stack, out_offset, data);
-#else
- svm_node_geometry(kg, sd, stack, type, out_offset);
-#endif
-}
-
-/* Object Info */
-
-ccl_device_noinline void svm_node_object_info(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint out_offset)
-{
- float data;
-
- switch (type) {
- case NODE_INFO_OB_LOCATION: {
- stack_store_float3(stack, out_offset, object_location(kg, sd));
- return;
- }
- case NODE_INFO_OB_COLOR: {
- stack_store_float3(stack, out_offset, object_color(kg, sd->object));
- return;
- }
- case NODE_INFO_OB_INDEX:
- data = object_pass_id(kg, sd->object);
- break;
- case NODE_INFO_MAT_INDEX:
- data = shader_pass_id(kg, sd);
- break;
- case NODE_INFO_OB_RANDOM: {
- if (sd->lamp != LAMP_NONE) {
- data = lamp_random_number(kg, sd->lamp);
- }
- else {
- data = object_random_number(kg, sd->object);
- }
- break;
- }
- default:
- data = 0.0f;
- break;
- }
-
- stack_store_float(stack, out_offset, data);
-}
-
-/* Particle Info */
-
-ccl_device_noinline void svm_node_particle_info(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint out_offset)
-{
- switch (type) {
- case NODE_INFO_PAR_INDEX: {
- int particle_id = object_particle_id(kg, sd->object);
- stack_store_float(stack, out_offset, particle_index(kg, particle_id));
- break;
- }
- case NODE_INFO_PAR_RANDOM: {
- int particle_id = object_particle_id(kg, sd->object);
- float random = hash_uint2_to_float(particle_index(kg, particle_id), 0);
- stack_store_float(stack, out_offset, random);
- break;
- }
- case NODE_INFO_PAR_AGE: {
- int particle_id = object_particle_id(kg, sd->object);
- stack_store_float(stack, out_offset, particle_age(kg, particle_id));
- break;
- }
- case NODE_INFO_PAR_LIFETIME: {
- int particle_id = object_particle_id(kg, sd->object);
- stack_store_float(stack, out_offset, particle_lifetime(kg, particle_id));
- break;
- }
- case NODE_INFO_PAR_LOCATION: {
- int particle_id = object_particle_id(kg, sd->object);
- stack_store_float3(stack, out_offset, particle_location(kg, particle_id));
- break;
- }
-#if 0 /* XXX float4 currently not supported in SVM stack */
- case NODE_INFO_PAR_ROTATION: {
- int particle_id = object_particle_id(kg, sd->object);
- stack_store_float4(stack, out_offset, particle_rotation(kg, particle_id));
- break;
- }
-#endif
- case NODE_INFO_PAR_SIZE: {
- int particle_id = object_particle_id(kg, sd->object);
- stack_store_float(stack, out_offset, particle_size(kg, particle_id));
- break;
- }
- case NODE_INFO_PAR_VELOCITY: {
- int particle_id = object_particle_id(kg, sd->object);
- stack_store_float3(stack, out_offset, particle_velocity(kg, particle_id));
- break;
- }
- case NODE_INFO_PAR_ANGULAR_VELOCITY: {
- int particle_id = object_particle_id(kg, sd->object);
- stack_store_float3(stack, out_offset, particle_angular_velocity(kg, particle_id));
- break;
- }
- }
-}
-
-#ifdef __HAIR__
-
-/* Hair Info */
-
-ccl_device_noinline void svm_node_hair_info(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint out_offset)
-{
- float data;
- float3 data3;
-
- switch (type) {
- case NODE_INFO_CURVE_IS_STRAND: {
- data = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
- stack_store_float(stack, out_offset, data);
- break;
- }
- case NODE_INFO_CURVE_INTERCEPT:
- break; /* handled as attribute */
- case NODE_INFO_CURVE_LENGTH:
- break; /* handled as attribute */
- case NODE_INFO_CURVE_RANDOM:
- break; /* handled as attribute */
- case NODE_INFO_CURVE_THICKNESS: {
- data = curve_thickness(kg, sd);
- stack_store_float(stack, out_offset, data);
- break;
- }
-# if 0
- case NODE_INFO_CURVE_FADE: {
- data = sd->curve_transparency;
- stack_store_float(stack, out_offset, data);
- break;
- }
-# endif
- case NODE_INFO_CURVE_TANGENT_NORMAL: {
- data3 = curve_tangent_normal(kg, sd);
- stack_store_float3(stack, out_offset, data3);
- break;
- }
- }
-}
-#endif
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_gradient.h b/intern/cycles/kernel/svm/svm_gradient.h
deleted file mode 100644
index 8cc37be606f..00000000000
--- a/intern/cycles/kernel/svm/svm_gradient.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Gradient */
-
-ccl_device float svm_gradient(float3 p, NodeGradientType type)
-{
- float x, y, z;
-
- x = p.x;
- y = p.y;
- z = p.z;
-
- if (type == NODE_BLEND_LINEAR) {
- return x;
- }
- else if (type == NODE_BLEND_QUADRATIC) {
- float r = fmaxf(x, 0.0f);
- return r * r;
- }
- else if (type == NODE_BLEND_EASING) {
- float r = fminf(fmaxf(x, 0.0f), 1.0f);
- float t = r * r;
-
- return (3.0f * t - 2.0f * t * r);
- }
- else if (type == NODE_BLEND_DIAGONAL) {
- return (x + y) * 0.5f;
- }
- else if (type == NODE_BLEND_RADIAL) {
- return atan2f(y, x) / M_2PI_F + 0.5f;
- }
- else {
- /* Bias a little bit for the case where p is a unit length vector,
- * to get exactly zero instead of a small random value depending
- * on float precision. */
- float r = fmaxf(0.999999f - sqrtf(x * x + y * y + z * z), 0.0f);
-
- if (type == NODE_BLEND_QUADRATIC_SPHERE)
- return r * r;
- else if (type == NODE_BLEND_SPHERICAL)
- return r;
- }
-
- return 0.0f;
-}
-
-ccl_device_noinline void svm_node_tex_gradient(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint type, co_offset, color_offset, fac_offset;
-
- svm_unpack_node_uchar4(node.y, &type, &co_offset, &fac_offset, &color_offset);
-
- float3 co = stack_load_float3(stack, co_offset);
-
- float f = svm_gradient(co, (NodeGradientType)type);
- f = saturate(f);
-
- if (stack_valid(fac_offset))
- stack_store_float(stack, fac_offset, f);
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, make_float3(f, f, f));
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_hsv.h b/intern/cycles/kernel/svm/svm_hsv.h
deleted file mode 100644
index 978c4c2d781..00000000000
--- a/intern/cycles/kernel/svm/svm_hsv.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SVM_HSV_H__
-#define __SVM_HSV_H__
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_noinline void svm_node_hsv(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint in_color_offset, fac_offset, out_color_offset;
- uint hue_offset, sat_offset, val_offset;
- svm_unpack_node_uchar3(node.y, &in_color_offset, &fac_offset, &out_color_offset);
- svm_unpack_node_uchar3(node.z, &hue_offset, &sat_offset, &val_offset);
-
- float fac = stack_load_float(stack, fac_offset);
- float3 in_color = stack_load_float3(stack, in_color_offset);
- float3 color = in_color;
-
- float hue = stack_load_float(stack, hue_offset);
- float sat = stack_load_float(stack, sat_offset);
- float val = stack_load_float(stack, val_offset);
-
- color = rgb_to_hsv(color);
-
- /* Remember: `fmodf` doesn't work for negative numbers here. */
- color.x = fmodf(color.x + hue + 0.5f, 1.0f);
- color.y = saturate(color.y * sat);
- color.z *= val;
-
- color = hsv_to_rgb(color);
-
- color.x = fac * color.x + (1.0f - fac) * in_color.x;
- color.y = fac * color.y + (1.0f - fac) * in_color.y;
- color.z = fac * color.z + (1.0f - fac) * in_color.z;
-
- /* Clamp color to prevent negative values caused by over saturation. */
- color.x = max(color.x, 0.0f);
- color.y = max(color.y, 0.0f);
- color.z = max(color.z, 0.0f);
-
- if (stack_valid(out_color_offset))
- stack_store_float3(stack, out_color_offset, color);
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __SVM_HSV_H__ */
diff --git a/intern/cycles/kernel/svm/svm_ies.h b/intern/cycles/kernel/svm/svm_ies.h
deleted file mode 100644
index 0215670d062..00000000000
--- a/intern/cycles/kernel/svm/svm_ies.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* IES Light */
-
-ccl_device_inline float interpolate_ies_vertical(
- KernelGlobals kg, int ofs, int v, int v_num, float v_frac, int h)
-{
- /* Since lookups are performed in spherical coordinates, clamping the coordinates at the low end
- * of v (corresponding to the north pole) would result in artifacts. The proper way of dealing
- * with this would be to lookup the corresponding value on the other side of the pole, but since
- * the horizontal coordinates might be nonuniform, this would require yet another interpolation.
- * Therefore, the assumption is made that the light is going to be symmetrical, which means that
- * we can just take the corresponding value at the current horizontal coordinate. */
-
-#define IES_LOOKUP(v) kernel_tex_fetch(__ies, ofs + h * v_num + (v))
- /* If v is zero, assume symmetry and read at v=1 instead of v=-1. */
- float a = IES_LOOKUP((v == 0) ? 1 : v - 1);
- float b = IES_LOOKUP(v);
- float c = IES_LOOKUP(v + 1);
- float d = IES_LOOKUP(min(v + 2, v_num - 1));
-#undef IES_LOOKUP
-
- return cubic_interp(a, b, c, d, v_frac);
-}
-
-ccl_device_inline float kernel_ies_interp(KernelGlobals kg, int slot, float h_angle, float v_angle)
-{
- /* Find offset of the IES data in the table. */
- int ofs = __float_as_int(kernel_tex_fetch(__ies, slot));
- if (ofs == -1) {
- return 100.0f;
- }
-
- int h_num = __float_as_int(kernel_tex_fetch(__ies, ofs++));
- int v_num = __float_as_int(kernel_tex_fetch(__ies, ofs++));
-
-#define IES_LOOKUP_ANGLE_H(h) kernel_tex_fetch(__ies, ofs + (h))
-#define IES_LOOKUP_ANGLE_V(v) kernel_tex_fetch(__ies, ofs + h_num + (v))
-
- /* Check whether the angle is within the bounds of the IES texture. */
- if (v_angle >= IES_LOOKUP_ANGLE_V(v_num - 1)) {
- return 0.0f;
- }
- kernel_assert(v_angle >= IES_LOOKUP_ANGLE_V(0));
- kernel_assert(h_angle >= IES_LOOKUP_ANGLE_H(0));
- kernel_assert(h_angle <= IES_LOOKUP_ANGLE_H(h_num - 1));
-
- /* Lookup the angles to find the table position. */
- int h_i, v_i;
- /* TODO(lukas): Consider using bisection.
- * Probably not worth it for the vast majority of IES files. */
- for (h_i = 0; IES_LOOKUP_ANGLE_H(h_i + 1) < h_angle; h_i++)
- ;
- for (v_i = 0; IES_LOOKUP_ANGLE_V(v_i + 1) < v_angle; v_i++)
- ;
-
- float h_frac = inverse_lerp(IES_LOOKUP_ANGLE_H(h_i), IES_LOOKUP_ANGLE_H(h_i + 1), h_angle);
- float v_frac = inverse_lerp(IES_LOOKUP_ANGLE_V(v_i), IES_LOOKUP_ANGLE_V(v_i + 1), v_angle);
-
-#undef IES_LOOKUP_ANGLE_H
-#undef IES_LOOKUP_ANGLE_V
-
- /* Skip forward to the actual intensity data. */
- ofs += h_num + v_num;
-
- /* Perform cubic interpolation along the horizontal coordinate to get the intensity value.
- * If h_i is zero, just wrap around since the horizontal angles always go over the full circle.
- * However, the last entry (360°) equals the first one, so we need to wrap around to the one
- * before that. */
- float a = interpolate_ies_vertical(
- kg, ofs, v_i, v_num, v_frac, (h_i == 0) ? h_num - 2 : h_i - 1);
- float b = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i);
- float c = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i + 1);
- /* Same logic here, wrap around to the second element if necessary. */
- float d = interpolate_ies_vertical(
- kg, ofs, v_i, v_num, v_frac, (h_i + 2 == h_num) ? 1 : h_i + 2);
-
- /* Cubic interpolation can result in negative values, so get rid of them. */
- return max(cubic_interp(a, b, c, d, h_frac), 0.0f);
-}
-
-ccl_device_noinline void svm_node_ies(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint vector_offset, strength_offset, fac_offset, slot = node.z;
- svm_unpack_node_uchar3(node.y, &strength_offset, &vector_offset, &fac_offset);
-
- float3 vector = stack_load_float3(stack, vector_offset);
- float strength = stack_load_float_default(stack, strength_offset, node.w);
-
- vector = normalize(vector);
- float v_angle = safe_acosf(-vector.z);
- float h_angle = atan2f(vector.x, vector.y) + M_PI_F;
-
- float fac = strength * kernel_ies_interp(kg, slot, h_angle, v_angle);
-
- if (stack_valid(fac_offset)) {
- stack_store_float(stack, fac_offset, fac);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
deleted file mode 100644
index 68374fcfb0d..00000000000
--- a/intern/cycles/kernel/svm/svm_image.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device float4 svm_image_texture(KernelGlobals kg, int id, float x, float y, uint flags)
-{
- if (id == -1) {
- return make_float4(
- TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
- }
-
- float4 r = kernel_tex_image_interp(kg, id, x, y);
- const float alpha = r.w;
-
- if ((flags & NODE_IMAGE_ALPHA_UNASSOCIATE) && alpha != 1.0f && alpha != 0.0f) {
- r /= alpha;
- r.w = alpha;
- }
-
- if (flags & NODE_IMAGE_COMPRESS_AS_SRGB) {
- r = color_srgb_to_linear_v4(r);
- }
-
- return r;
-}
-
-/* Remap coordinate from 0..1 box to -1..-1 */
-ccl_device_inline float3 texco_remap_square(float3 co)
-{
- return (co - make_float3(0.5f, 0.5f, 0.5f)) * 2.0f;
-}
-
-ccl_device_noinline int svm_node_tex_image(
- KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
-{
- uint co_offset, out_offset, alpha_offset, flags;
-
- svm_unpack_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &flags);
-
- float3 co = stack_load_float3(stack, co_offset);
- float2 tex_co;
- if (node.w == NODE_IMAGE_PROJ_SPHERE) {
- co = texco_remap_square(co);
- tex_co = map_to_sphere(co);
- }
- else if (node.w == NODE_IMAGE_PROJ_TUBE) {
- co = texco_remap_square(co);
- tex_co = map_to_tube(co);
- }
- else {
- tex_co = make_float2(co.x, co.y);
- }
-
- /* TODO(lukas): Consider moving tile information out of the SVM node.
- * TextureInfo seems a reasonable candidate. */
- int id = -1;
- int num_nodes = (int)node.y;
- if (num_nodes > 0) {
- /* Remember the offset of the node following the tile nodes. */
- int next_offset = offset + num_nodes;
-
- /* Find the tile that the UV lies in. */
- int tx = (int)tex_co.x;
- int ty = (int)tex_co.y;
-
- /* Check that we're within a legitimate tile. */
- if (tx >= 0 && ty >= 0 && tx < 10) {
- int tile = 1001 + 10 * ty + tx;
-
- /* Find the index of the tile. */
- for (int i = 0; i < num_nodes; i++) {
- uint4 tile_node = read_node(kg, &offset);
- if (tile_node.x == tile) {
- id = tile_node.y;
- break;
- }
- if (tile_node.z == tile) {
- id = tile_node.w;
- break;
- }
- }
-
- /* If we found the tile, offset the UVs to be relative to it. */
- if (id != -1) {
- tex_co.x -= tx;
- tex_co.y -= ty;
- }
- }
-
- /* Skip over the remaining nodes. */
- offset = next_offset;
- }
- else {
- id = -num_nodes;
- }
-
- float4 f = svm_image_texture(kg, id, tex_co.x, tex_co.y, flags);
-
- if (stack_valid(out_offset))
- stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
- if (stack_valid(alpha_offset))
- stack_store_float(stack, alpha_offset, f.w);
- return offset;
-}
-
-ccl_device_noinline void svm_node_tex_image_box(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- /* get object space normal */
- float3 N = sd->N;
-
- N = sd->N;
- object_inverse_normal_transform(kg, sd, &N);
-
- /* project from direction vector to barycentric coordinates in triangles */
- float3 signed_N = N;
-
- N.x = fabsf(N.x);
- N.y = fabsf(N.y);
- N.z = fabsf(N.z);
-
- N /= (N.x + N.y + N.z);
-
- /* basic idea is to think of this as a triangle, each corner representing
- * one of the 3 faces of the cube. in the corners we have single textures,
- * in between we blend between two textures, and in the middle we a blend
- * between three textures.
- *
- * The `Nxyz` values are the barycentric coordinates in an equilateral
- * triangle, which in case of blending, in the middle has a smaller
- * equilateral triangle where 3 textures blend. this divides things into
- * 7 zones, with an if() test for each zone. */
-
- float3 weight = make_float3(0.0f, 0.0f, 0.0f);
- float blend = __int_as_float(node.w);
- float limit = 0.5f * (1.0f + blend);
-
- /* first test for corners with single texture */
- if (N.x > limit * (N.x + N.y) && N.x > limit * (N.x + N.z)) {
- weight.x = 1.0f;
- }
- else if (N.y > limit * (N.x + N.y) && N.y > limit * (N.y + N.z)) {
- weight.y = 1.0f;
- }
- else if (N.z > limit * (N.x + N.z) && N.z > limit * (N.y + N.z)) {
- weight.z = 1.0f;
- }
- else if (blend > 0.0f) {
- /* in case of blending, test for mixes between two textures */
- if (N.z < (1.0f - limit) * (N.y + N.x)) {
- weight.x = N.x / (N.x + N.y);
- weight.x = saturate((weight.x - 0.5f * (1.0f - blend)) / blend);
- weight.y = 1.0f - weight.x;
- }
- else if (N.x < (1.0f - limit) * (N.y + N.z)) {
- weight.y = N.y / (N.y + N.z);
- weight.y = saturate((weight.y - 0.5f * (1.0f - blend)) / blend);
- weight.z = 1.0f - weight.y;
- }
- else if (N.y < (1.0f - limit) * (N.x + N.z)) {
- weight.x = N.x / (N.x + N.z);
- weight.x = saturate((weight.x - 0.5f * (1.0f - blend)) / blend);
- weight.z = 1.0f - weight.x;
- }
- else {
- /* last case, we have a mix between three */
- weight.x = ((2.0f - limit) * N.x + (limit - 1.0f)) / (2.0f * limit - 1.0f);
- weight.y = ((2.0f - limit) * N.y + (limit - 1.0f)) / (2.0f * limit - 1.0f);
- weight.z = ((2.0f - limit) * N.z + (limit - 1.0f)) / (2.0f * limit - 1.0f);
- }
- }
- else {
- /* Desperate mode, no valid choice anyway, fallback to one side. */
- weight.x = 1.0f;
- }
-
- /* now fetch textures */
- uint co_offset, out_offset, alpha_offset, flags;
- svm_unpack_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &flags);
-
- float3 co = stack_load_float3(stack, co_offset);
- uint id = node.y;
-
- float4 f = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-
- /* Map so that no textures are flipped, rotation is somewhat arbitrary. */
- if (weight.x > 0.0f) {
- float2 uv = make_float2((signed_N.x < 0.0f) ? 1.0f - co.y : co.y, co.z);
- f += weight.x * svm_image_texture(kg, id, uv.x, uv.y, flags);
- }
- if (weight.y > 0.0f) {
- float2 uv = make_float2((signed_N.y > 0.0f) ? 1.0f - co.x : co.x, co.z);
- f += weight.y * svm_image_texture(kg, id, uv.x, uv.y, flags);
- }
- if (weight.z > 0.0f) {
- float2 uv = make_float2((signed_N.z > 0.0f) ? 1.0f - co.y : co.y, co.x);
- f += weight.z * svm_image_texture(kg, id, uv.x, uv.y, flags);
- }
-
- if (stack_valid(out_offset))
- stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
- if (stack_valid(alpha_offset))
- stack_store_float(stack, alpha_offset, f.w);
-}
-
-ccl_device_noinline void svm_node_tex_environment(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint id = node.y;
- uint co_offset, out_offset, alpha_offset, flags;
- uint projection = node.w;
-
- svm_unpack_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &flags);
-
- float3 co = stack_load_float3(stack, co_offset);
- float2 uv;
-
- co = safe_normalize(co);
-
- if (projection == 0)
- uv = direction_to_equirectangular(co);
- else
- uv = direction_to_mirrorball(co);
-
- float4 f = svm_image_texture(kg, id, uv.x, uv.y, flags);
-
- if (stack_valid(out_offset))
- stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
- if (stack_valid(alpha_offset))
- stack_store_float(stack, alpha_offset, f.w);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_invert.h b/intern/cycles/kernel/svm/svm_invert.h
deleted file mode 100644
index 60668ec00f1..00000000000
--- a/intern/cycles/kernel/svm/svm_invert.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device float invert(float color, float factor)
-{
- return factor * (1.0f - color) + (1.0f - factor) * color;
-}
-
-ccl_device_noinline void svm_node_invert(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint in_fac,
- uint in_color,
- uint out_color)
-{
- float factor = stack_load_float(stack, in_fac);
- float3 color = stack_load_float3(stack, in_color);
-
- color.x = invert(color.x, factor);
- color.y = invert(color.y, factor);
- color.z = invert(color.z, factor);
-
- if (stack_valid(out_color))
- stack_store_float3(stack, out_color, color);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_light_path.h b/intern/cycles/kernel/svm/svm_light_path.h
deleted file mode 100644
index 5e1fc4f671c..00000000000
--- a/intern/cycles/kernel/svm/svm_light_path.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Light Path Node */
-
-template<uint node_feature_mask, typename ConstIntegratorGenericState>
-ccl_device_noinline void svm_node_light_path(KernelGlobals kg,
- ConstIntegratorGenericState state,
- ccl_private const ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint out_offset,
- uint32_t path_flag)
-{
- float info = 0.0f;
-
- switch (type) {
- case NODE_LP_camera:
- info = (path_flag & PATH_RAY_CAMERA) ? 1.0f : 0.0f;
- break;
- case NODE_LP_shadow:
- info = (path_flag & PATH_RAY_SHADOW) ? 1.0f : 0.0f;
- break;
- case NODE_LP_diffuse:
- info = (path_flag & PATH_RAY_DIFFUSE) ? 1.0f : 0.0f;
- break;
- case NODE_LP_glossy:
- info = (path_flag & PATH_RAY_GLOSSY) ? 1.0f : 0.0f;
- break;
- case NODE_LP_singular:
- info = (path_flag & PATH_RAY_SINGULAR) ? 1.0f : 0.0f;
- break;
- case NODE_LP_reflection:
- info = (path_flag & PATH_RAY_REFLECT) ? 1.0f : 0.0f;
- break;
- case NODE_LP_transmission:
- info = (path_flag & PATH_RAY_TRANSMIT) ? 1.0f : 0.0f;
- break;
- case NODE_LP_volume_scatter:
- info = (path_flag & PATH_RAY_VOLUME_SCATTER) ? 1.0f : 0.0f;
- break;
- case NODE_LP_backfacing:
- info = (sd->flag & SD_BACKFACING) ? 1.0f : 0.0f;
- break;
- case NODE_LP_ray_length:
- info = sd->ray_length;
- break;
- case NODE_LP_ray_depth: {
- /* Read bounce from difference location depending if this is a shadow
- * path. It's a bit dubious to have integrate state details leak into
- * this function but hard to avoid currently. */
- IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
- {
- info = (float)integrator_state_bounce(state, path_flag);
- }
-
- /* For background, light emission and shadow evaluation we from a
- * surface or volume we are effective one bounce further. */
- if (path_flag & (PATH_RAY_SHADOW | PATH_RAY_EMISSION)) {
- info += 1.0f;
- }
- break;
- }
- case NODE_LP_ray_transparent: {
- IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
- {
- info = (float)integrator_state_transparent_bounce(state, path_flag);
- }
- break;
- }
- case NODE_LP_ray_diffuse:
- IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
- {
- info = (float)integrator_state_diffuse_bounce(state, path_flag);
- }
- break;
- case NODE_LP_ray_glossy:
- IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
- {
- info = (float)integrator_state_glossy_bounce(state, path_flag);
- }
- break;
- case NODE_LP_ray_transmission:
- IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
- {
- info = (float)integrator_state_transmission_bounce(state, path_flag);
- }
- break;
- }
-
- stack_store_float(stack, out_offset, info);
-}
-
-/* Light Falloff Node */
-
-ccl_device_noinline void svm_node_light_falloff(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint strength_offset, out_offset, smooth_offset;
-
- svm_unpack_node_uchar3(node.z, &strength_offset, &smooth_offset, &out_offset);
-
- float strength = stack_load_float(stack, strength_offset);
- uint type = node.y;
-
- switch (type) {
- case NODE_LIGHT_FALLOFF_QUADRATIC:
- break;
- case NODE_LIGHT_FALLOFF_LINEAR:
- strength *= sd->ray_length;
- break;
- case NODE_LIGHT_FALLOFF_CONSTANT:
- strength *= sd->ray_length * sd->ray_length;
- break;
- }
-
- float smooth = stack_load_float(stack, smooth_offset);
-
- if (smooth > 0.0f) {
- float squared = sd->ray_length * sd->ray_length;
- /* Distant lamps set the ray length to FLT_MAX, which causes squared to overflow. */
- if (isfinite(squared)) {
- strength *= squared / (smooth + squared);
- }
- }
-
- stack_store_float(stack, out_offset, strength);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_magic.h b/intern/cycles/kernel/svm/svm_magic.h
deleted file mode 100644
index d3a429fec56..00000000000
--- a/intern/cycles/kernel/svm/svm_magic.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Magic */
-
-ccl_device_noinline_cpu float3 svm_magic(float3 p, int n, float distortion)
-{
- float x = sinf((p.x + p.y + p.z) * 5.0f);
- float y = cosf((-p.x + p.y - p.z) * 5.0f);
- float z = -cosf((-p.x - p.y + p.z) * 5.0f);
-
- if (n > 0) {
- x *= distortion;
- y *= distortion;
- z *= distortion;
- y = -cosf(x - y + z);
- y *= distortion;
-
- if (n > 1) {
- x = cosf(x - y - z);
- x *= distortion;
-
- if (n > 2) {
- z = sinf(-x - y - z);
- z *= distortion;
-
- if (n > 3) {
- x = -cosf(-x + y - z);
- x *= distortion;
-
- if (n > 4) {
- y = -sinf(-x + y + z);
- y *= distortion;
-
- if (n > 5) {
- y = -cosf(-x + y + z);
- y *= distortion;
-
- if (n > 6) {
- x = cosf(x + y + z);
- x *= distortion;
-
- if (n > 7) {
- z = sinf(x + y - z);
- z *= distortion;
-
- if (n > 8) {
- x = -cosf(-x - y + z);
- x *= distortion;
-
- if (n > 9) {
- y = -sinf(x - y + z);
- y *= distortion;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- if (distortion != 0.0f) {
- distortion *= 2.0f;
- x /= distortion;
- y /= distortion;
- z /= distortion;
- }
-
- return make_float3(0.5f - x, 0.5f - y, 0.5f - z);
-}
-
-ccl_device_noinline int svm_node_tex_magic(
- KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
-{
- uint depth;
- uint scale_offset, distortion_offset, co_offset, fac_offset, color_offset;
-
- svm_unpack_node_uchar3(node.y, &depth, &color_offset, &fac_offset);
- svm_unpack_node_uchar3(node.z, &co_offset, &scale_offset, &distortion_offset);
-
- uint4 node2 = read_node(kg, &offset);
- float3 co = stack_load_float3(stack, co_offset);
- float scale = stack_load_float_default(stack, scale_offset, node2.x);
- float distortion = stack_load_float_default(stack, distortion_offset, node2.y);
-
- float3 color = svm_magic(co * scale, depth, distortion);
-
- if (stack_valid(fac_offset))
- stack_store_float(stack, fac_offset, average(color));
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, color);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_map_range.h b/intern/cycles/kernel/svm/svm_map_range.h
deleted file mode 100644
index 5e89947c6c7..00000000000
--- a/intern/cycles/kernel/svm/svm_map_range.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Map Range Node */
-
-ccl_device_inline float smootherstep(float edge0, float edge1, float x)
-{
- x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0f, 1.0f);
- return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f);
-}
-
-ccl_device_noinline int svm_node_map_range(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint value_stack_offset,
- uint parameters_stack_offsets,
- uint results_stack_offsets,
- int offset)
-{
- uint from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset;
- uint type_stack_offset, steps_stack_offset, result_stack_offset;
- svm_unpack_node_uchar4(parameters_stack_offsets,
- &from_min_stack_offset,
- &from_max_stack_offset,
- &to_min_stack_offset,
- &to_max_stack_offset);
- svm_unpack_node_uchar3(
- results_stack_offsets, &type_stack_offset, &steps_stack_offset, &result_stack_offset);
-
- uint4 defaults = read_node(kg, &offset);
- uint4 defaults2 = read_node(kg, &offset);
-
- float value = stack_load_float(stack, value_stack_offset);
- float from_min = stack_load_float_default(stack, from_min_stack_offset, defaults.x);
- float from_max = stack_load_float_default(stack, from_max_stack_offset, defaults.y);
- float to_min = stack_load_float_default(stack, to_min_stack_offset, defaults.z);
- float to_max = stack_load_float_default(stack, to_max_stack_offset, defaults.w);
- float steps = stack_load_float_default(stack, steps_stack_offset, defaults2.x);
-
- float result;
-
- if (from_max != from_min) {
- float factor = value;
- switch (type_stack_offset) {
- default:
- case NODE_MAP_RANGE_LINEAR:
- factor = (value - from_min) / (from_max - from_min);
- break;
- case NODE_MAP_RANGE_STEPPED: {
- factor = (value - from_min) / (from_max - from_min);
- factor = (steps > 0.0f) ? floorf(factor * (steps + 1.0f)) / steps : 0.0f;
- break;
- }
- case NODE_MAP_RANGE_SMOOTHSTEP: {
- factor = (from_min > from_max) ? 1.0f - smoothstep(from_max, from_min, factor) :
- smoothstep(from_min, from_max, factor);
- break;
- }
- case NODE_MAP_RANGE_SMOOTHERSTEP: {
- factor = (from_min > from_max) ? 1.0f - smootherstep(from_max, from_min, factor) :
- smootherstep(from_min, from_max, factor);
- break;
- }
- }
- result = to_min + factor * (to_max - to_min);
- }
- else {
- result = 0.0f;
- }
- stack_store_float(stack, result_stack_offset, result);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_mapping.h b/intern/cycles/kernel/svm/svm_mapping.h
deleted file mode 100644
index ed420e5bc3d..00000000000
--- a/intern/cycles/kernel/svm/svm_mapping.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Mapping Node */
-
-ccl_device_noinline void svm_node_mapping(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint inputs_stack_offsets,
- uint result_stack_offset)
-{
- uint vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset;
- svm_unpack_node_uchar4(inputs_stack_offsets,
- &vector_stack_offset,
- &location_stack_offset,
- &rotation_stack_offset,
- &scale_stack_offset);
-
- float3 vector = stack_load_float3(stack, vector_stack_offset);
- float3 location = stack_load_float3(stack, location_stack_offset);
- float3 rotation = stack_load_float3(stack, rotation_stack_offset);
- float3 scale = stack_load_float3(stack, scale_stack_offset);
-
- float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
- stack_store_float3(stack, result_stack_offset, result);
-}
-
-/* Texture Mapping */
-
-ccl_device_noinline int svm_node_texture_mapping(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint vec_offset,
- uint out_offset,
- int offset)
-{
- float3 v = stack_load_float3(stack, vec_offset);
-
- Transform tfm;
- tfm.x = read_node_float(kg, &offset);
- tfm.y = read_node_float(kg, &offset);
- tfm.z = read_node_float(kg, &offset);
-
- float3 r = transform_point(&tfm, v);
- stack_store_float3(stack, out_offset, r);
- return offset;
-}
-
-ccl_device_noinline int svm_node_min_max(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint vec_offset,
- uint out_offset,
- int offset)
-{
- float3 v = stack_load_float3(stack, vec_offset);
-
- float3 mn = float4_to_float3(read_node_float(kg, &offset));
- float3 mx = float4_to_float3(read_node_float(kg, &offset));
-
- float3 r = min(max(mn, v), mx);
- stack_store_float3(stack, out_offset, r);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_mapping_util.h b/intern/cycles/kernel/svm/svm_mapping_util.h
deleted file mode 100644
index ec2c84e0791..00000000000
--- a/intern/cycles/kernel/svm/svm_mapping_util.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011-2014 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device float3
-svm_mapping(NodeMappingType type, float3 vector, float3 location, float3 rotation, float3 scale)
-{
- Transform rotationTransform = euler_to_transform(rotation);
- switch (type) {
- case NODE_MAPPING_TYPE_POINT:
- return transform_direction(&rotationTransform, (vector * scale)) + location;
- case NODE_MAPPING_TYPE_TEXTURE:
- return safe_divide_float3_float3(
- transform_direction_transposed(&rotationTransform, (vector - location)), scale);
- case NODE_MAPPING_TYPE_VECTOR:
- return transform_direction(&rotationTransform, (vector * scale));
- case NODE_MAPPING_TYPE_NORMAL:
- return safe_normalize(
- transform_direction(&rotationTransform, safe_divide_float3_float3(vector, scale)));
- default:
- return make_float3(0.0f, 0.0f, 0.0f);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_math.h b/intern/cycles/kernel/svm/svm_math.h
deleted file mode 100644
index 97f7d486c09..00000000000
--- a/intern/cycles/kernel/svm/svm_math.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_noinline void svm_node_math(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint inputs_stack_offsets,
- uint result_stack_offset)
-{
- uint a_stack_offset, b_stack_offset, c_stack_offset;
- svm_unpack_node_uchar3(inputs_stack_offsets, &a_stack_offset, &b_stack_offset, &c_stack_offset);
-
- float a = stack_load_float(stack, a_stack_offset);
- float b = stack_load_float(stack, b_stack_offset);
- float c = stack_load_float(stack, c_stack_offset);
- float result = svm_math((NodeMathType)type, a, b, c);
-
- stack_store_float(stack, result_stack_offset, result);
-}
-
-ccl_device_noinline int svm_node_vector_math(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint type,
- uint inputs_stack_offsets,
- uint outputs_stack_offsets,
- int offset)
-{
- uint value_stack_offset, vector_stack_offset;
- uint a_stack_offset, b_stack_offset, param1_stack_offset;
- svm_unpack_node_uchar3(
- inputs_stack_offsets, &a_stack_offset, &b_stack_offset, &param1_stack_offset);
- svm_unpack_node_uchar2(outputs_stack_offsets, &value_stack_offset, &vector_stack_offset);
-
- float3 a = stack_load_float3(stack, a_stack_offset);
- float3 b = stack_load_float3(stack, b_stack_offset);
- float3 c = make_float3(0.0f, 0.0f, 0.0f);
- float param1 = stack_load_float(stack, param1_stack_offset);
-
- float value;
- float3 vector;
-
- /* 3 Vector Operators */
- if (type == NODE_VECTOR_MATH_WRAP || type == NODE_VECTOR_MATH_FACEFORWARD ||
- type == NODE_VECTOR_MATH_MULTIPLY_ADD) {
- uint4 extra_node = read_node(kg, &offset);
- c = stack_load_float3(stack, extra_node.x);
- }
-
- svm_vector_math(&value, &vector, (NodeVectorMathType)type, a, b, c, param1);
-
- if (stack_valid(value_stack_offset))
- stack_store_float(stack, value_stack_offset, value);
- if (stack_valid(vector_stack_offset))
- stack_store_float3(stack, vector_stack_offset, vector);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h
deleted file mode 100644
index d3225b55ef0..00000000000
--- a/intern/cycles/kernel/svm/svm_math_util.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2011-2014 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device void svm_vector_math(ccl_private float *value,
- ccl_private float3 *vector,
- NodeVectorMathType type,
- float3 a,
- float3 b,
- float3 c,
- float param1)
-{
- switch (type) {
- case NODE_VECTOR_MATH_ADD:
- *vector = a + b;
- break;
- case NODE_VECTOR_MATH_SUBTRACT:
- *vector = a - b;
- break;
- case NODE_VECTOR_MATH_MULTIPLY:
- *vector = a * b;
- break;
- case NODE_VECTOR_MATH_DIVIDE:
- *vector = safe_divide_float3_float3(a, b);
- break;
- case NODE_VECTOR_MATH_CROSS_PRODUCT:
- *vector = cross(a, b);
- break;
- case NODE_VECTOR_MATH_PROJECT:
- *vector = project(a, b);
- break;
- case NODE_VECTOR_MATH_REFLECT:
- *vector = reflect(a, b);
- break;
- case NODE_VECTOR_MATH_REFRACT:
- *vector = refract(a, normalize(b), param1);
- break;
- case NODE_VECTOR_MATH_FACEFORWARD:
- *vector = faceforward(a, b, c);
- break;
- case NODE_VECTOR_MATH_MULTIPLY_ADD:
- *vector = a * b + c;
- break;
- case NODE_VECTOR_MATH_DOT_PRODUCT:
- *value = dot(a, b);
- break;
- case NODE_VECTOR_MATH_DISTANCE:
- *value = distance(a, b);
- break;
- case NODE_VECTOR_MATH_LENGTH:
- *value = len(a);
- break;
- case NODE_VECTOR_MATH_SCALE:
- *vector = a * param1;
- break;
- case NODE_VECTOR_MATH_NORMALIZE:
- *vector = safe_normalize(a);
- break;
- case NODE_VECTOR_MATH_SNAP:
- *vector = floor(safe_divide_float3_float3(a, b)) * b;
- break;
- case NODE_VECTOR_MATH_FLOOR:
- *vector = floor(a);
- break;
- case NODE_VECTOR_MATH_CEIL:
- *vector = ceil(a);
- break;
- case NODE_VECTOR_MATH_MODULO:
- *vector = make_float3(safe_modulo(a.x, b.x), safe_modulo(a.y, b.y), safe_modulo(a.z, b.z));
- break;
- case NODE_VECTOR_MATH_WRAP:
- *vector = make_float3(wrapf(a.x, b.x, c.x), wrapf(a.y, b.y, c.y), wrapf(a.z, b.z, c.z));
- break;
- case NODE_VECTOR_MATH_FRACTION:
- *vector = a - floor(a);
- break;
- case NODE_VECTOR_MATH_ABSOLUTE:
- *vector = fabs(a);
- break;
- case NODE_VECTOR_MATH_MINIMUM:
- *vector = min(a, b);
- break;
- case NODE_VECTOR_MATH_MAXIMUM:
- *vector = max(a, b);
- break;
- case NODE_VECTOR_MATH_SINE:
- *vector = make_float3(sinf(a.x), sinf(a.y), sinf(a.z));
- break;
- case NODE_VECTOR_MATH_COSINE:
- *vector = make_float3(cosf(a.x), cosf(a.y), cosf(a.z));
- break;
- case NODE_VECTOR_MATH_TANGENT:
- *vector = make_float3(tanf(a.x), tanf(a.y), tanf(a.z));
- break;
- default:
- *vector = zero_float3();
- *value = 0.0f;
- }
-}
-
-ccl_device float svm_math(NodeMathType type, float a, float b, float c)
-{
- switch (type) {
- case NODE_MATH_ADD:
- return a + b;
- case NODE_MATH_SUBTRACT:
- return a - b;
- case NODE_MATH_MULTIPLY:
- return a * b;
- case NODE_MATH_DIVIDE:
- return safe_divide(a, b);
- case NODE_MATH_POWER:
- return safe_powf(a, b);
- case NODE_MATH_LOGARITHM:
- return safe_logf(a, b);
- case NODE_MATH_SQRT:
- return safe_sqrtf(a);
- case NODE_MATH_INV_SQRT:
- return inversesqrtf(a);
- case NODE_MATH_ABSOLUTE:
- return fabsf(a);
- case NODE_MATH_RADIANS:
- return a * (M_PI_F / 180.0f);
- case NODE_MATH_DEGREES:
- return a * (180.0f / M_PI_F);
- case NODE_MATH_MINIMUM:
- return fminf(a, b);
- case NODE_MATH_MAXIMUM:
- return fmaxf(a, b);
- case NODE_MATH_LESS_THAN:
- return a < b;
- case NODE_MATH_GREATER_THAN:
- return a > b;
- case NODE_MATH_ROUND:
- return floorf(a + 0.5f);
- case NODE_MATH_FLOOR:
- return floorf(a);
- case NODE_MATH_CEIL:
- return ceilf(a);
- case NODE_MATH_FRACTION:
- return a - floorf(a);
- case NODE_MATH_MODULO:
- return safe_modulo(a, b);
- case NODE_MATH_TRUNC:
- return a >= 0.0f ? floorf(a) : ceilf(a);
- case NODE_MATH_SNAP:
- return floorf(safe_divide(a, b)) * b;
- case NODE_MATH_WRAP:
- return wrapf(a, b, c);
- case NODE_MATH_PINGPONG:
- return pingpongf(a, b);
- case NODE_MATH_SINE:
- return sinf(a);
- case NODE_MATH_COSINE:
- return cosf(a);
- case NODE_MATH_TANGENT:
- return tanf(a);
- case NODE_MATH_SINH:
- return sinhf(a);
- case NODE_MATH_COSH:
- return coshf(a);
- case NODE_MATH_TANH:
- return tanhf(a);
- case NODE_MATH_ARCSINE:
- return safe_asinf(a);
- case NODE_MATH_ARCCOSINE:
- return safe_acosf(a);
- case NODE_MATH_ARCTANGENT:
- return atanf(a);
- case NODE_MATH_ARCTAN2:
- return atan2f(a, b);
- case NODE_MATH_SIGN:
- return compatible_signf(a);
- case NODE_MATH_EXPONENT:
- return expf(a);
- case NODE_MATH_COMPARE:
- return ((a == b) || (fabsf(a - b) <= fmaxf(c, FLT_EPSILON))) ? 1.0f : 0.0f;
- case NODE_MATH_MULTIPLY_ADD:
- return a * b + c;
- case NODE_MATH_SMOOTH_MIN:
- return smoothminf(a, b, c);
- case NODE_MATH_SMOOTH_MAX:
- return -smoothminf(-a, -b, c);
- default:
- return 0.0f;
- }
-}
-
-ccl_device float3 svm_math_blackbody_color(float t)
-{
- /* TODO(lukas): Reimplement in XYZ. */
-
- /* Calculate color in range 800..12000 using an approximation
- * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
- * Max absolute error for RGB is (0.00095, 0.00077, 0.00057),
- * which is enough to get the same 8 bit/channel color.
- */
-
- const float blackbody_table_r[6][3] = {
- {2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f},
- {3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f},
- {4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f},
- {4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f},
- {4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f},
- {3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f},
- };
-
- const float blackbody_table_g[6][3] = {
- {-7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f},
- {-1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f},
- {-1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f},
- {-1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f},
- {-1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f},
- {-5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f},
- };
-
- const float blackbody_table_b[6][4] = {
- {0.0f, 0.0f, 0.0f, 0.0f}, /* zeros should be optimized by compiler */
- {0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
- {-2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f},
- {-2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f},
- {6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f},
- };
-
- if (t >= 12000.0f) {
- return make_float3(0.826270103f, 0.994478524f, 1.56626022f);
- }
- else if (t < 965.0f) {
- /* For 800 <= t < 965 color does not change in OSL implementation, so keep color the same */
- return make_float3(4.70366907f, 0.0f, 0.0f);
- }
-
- /* Manually align for readability. */
- /* clang-format off */
- int i = (t >= 6365.0f) ? 5 :
- (t >= 3315.0f) ? 4 :
- (t >= 1902.0f) ? 3 :
- (t >= 1449.0f) ? 2 :
- (t >= 1167.0f) ? 1 :
- 0;
- /* clang-format on */
-
- ccl_constant float *r = blackbody_table_r[i];
- ccl_constant float *g = blackbody_table_g[i];
- ccl_constant float *b = blackbody_table_b[i];
-
- const float t_inv = 1.0f / t;
- return make_float3(r[0] * t_inv + r[1] * t + r[2],
- g[0] * t_inv + g[1] * t + g[2],
- ((b[0] * t + b[1]) * t + b[2]) * t + b[3]);
-}
-
-ccl_device_inline float3 svm_math_gamma_color(float3 color, float gamma)
-{
- if (gamma == 0.0f)
- return make_float3(1.0f, 1.0f, 1.0f);
-
- if (color.x > 0.0f)
- color.x = powf(color.x, gamma);
- if (color.y > 0.0f)
- color.y = powf(color.y, gamma);
- if (color.z > 0.0f)
- color.z = powf(color.z, gamma);
-
- return color;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_mix.h b/intern/cycles/kernel/svm/svm_mix.h
deleted file mode 100644
index 568dda3dddc..00000000000
--- a/intern/cycles/kernel/svm/svm_mix.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Node */
-
-ccl_device_noinline int svm_node_mix(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint fac_offset,
- uint c1_offset,
- uint c2_offset,
- int offset)
-{
- /* read extra data */
- uint4 node1 = read_node(kg, &offset);
-
- float fac = stack_load_float(stack, fac_offset);
- float3 c1 = stack_load_float3(stack, c1_offset);
- float3 c2 = stack_load_float3(stack, c2_offset);
- float3 result = svm_mix((NodeMix)node1.y, fac, c1, c2);
-
- stack_store_float3(stack, node1.z, result);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_musgrave.h b/intern/cycles/kernel/svm/svm_musgrave.h
deleted file mode 100644
index decd29bbe13..00000000000
--- a/intern/cycles/kernel/svm/svm_musgrave.h
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* 1D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
-ccl_device_noinline_cpu float noise_musgrave_fBm_1d(float co,
- float H,
- float lacunarity,
- float octaves)
-{
- float p = co;
- float value = 0.0f;
- float pwr = 1.0f;
- float pwHL = powf(lacunarity, -H);
-
- for (int i = 0; i < float_to_int(octaves); i++) {
- value += snoise_1d(p) * pwr;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value += rmd * snoise_1d(p) * pwr;
- }
-
- return value;
-}
-
-/* 1D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
-ccl_device_noinline_cpu float noise_musgrave_multi_fractal_1d(float co,
- float H,
- float lacunarity,
- float octaves)
-{
- float p = co;
- float value = 1.0f;
- float pwr = 1.0f;
- float pwHL = powf(lacunarity, -H);
-
- for (int i = 0; i < float_to_int(octaves); i++) {
- value *= (pwr * snoise_1d(p) + 1.0f);
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value *= (rmd * pwr * snoise_1d(p) + 1.0f); /* correct? */
- }
-
- return value;
-}
-
-/* 1D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_1d(
- float co, float H, float lacunarity, float octaves, float offset)
-{
- float p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- /* first unscaled octave of function; later octaves are scaled */
- float value = offset + snoise_1d(p);
- p *= lacunarity;
-
- for (int i = 1; i < float_to_int(octaves); i++) {
- float increment = (snoise_1d(p) + offset) * pwr * value;
- value += increment;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- float increment = (snoise_1d(p) + offset) * pwr * value;
- value += rmd * increment;
- }
-
- return value;
-}
-
-/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_1d(
- float co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- float value = snoise_1d(p) + offset;
- float weight = gain * value;
- p *= lacunarity;
-
- for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
- if (weight > 1.0f) {
- weight = 1.0f;
- }
-
- float signal = (snoise_1d(p) + offset) * pwr;
- pwr *= pwHL;
- value += weight * signal;
- weight *= gain * signal;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value += rmd * ((snoise_1d(p) + offset) * pwr);
- }
-
- return value;
-}
-
-/* 1D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_1d(
- float co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- float signal = offset - fabsf(snoise_1d(p));
- signal *= signal;
- float value = signal;
- float weight = 1.0f;
-
- for (int i = 1; i < float_to_int(octaves); i++) {
- p *= lacunarity;
- weight = saturate(signal * gain);
- signal = offset - fabsf(snoise_1d(p));
- signal *= signal;
- signal *= weight;
- value += signal * pwr;
- pwr *= pwHL;
- }
-
- return value;
-}
-
-/* 2D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
-ccl_device_noinline_cpu float noise_musgrave_fBm_2d(float2 co,
- float H,
- float lacunarity,
- float octaves)
-{
- float2 p = co;
- float value = 0.0f;
- float pwr = 1.0f;
- float pwHL = powf(lacunarity, -H);
-
- for (int i = 0; i < float_to_int(octaves); i++) {
- value += snoise_2d(p) * pwr;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value += rmd * snoise_2d(p) * pwr;
- }
-
- return value;
-}
-
-/* 2D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
-ccl_device_noinline_cpu float noise_musgrave_multi_fractal_2d(float2 co,
- float H,
- float lacunarity,
- float octaves)
-{
- float2 p = co;
- float value = 1.0f;
- float pwr = 1.0f;
- float pwHL = powf(lacunarity, -H);
-
- for (int i = 0; i < float_to_int(octaves); i++) {
- value *= (pwr * snoise_2d(p) + 1.0f);
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value *= (rmd * pwr * snoise_2d(p) + 1.0f); /* correct? */
- }
-
- return value;
-}
-
-/* 2D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_2d(
- float2 co, float H, float lacunarity, float octaves, float offset)
-{
- float2 p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- /* first unscaled octave of function; later octaves are scaled */
- float value = offset + snoise_2d(p);
- p *= lacunarity;
-
- for (int i = 1; i < float_to_int(octaves); i++) {
- float increment = (snoise_2d(p) + offset) * pwr * value;
- value += increment;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- float increment = (snoise_2d(p) + offset) * pwr * value;
- value += rmd * increment;
- }
-
- return value;
-}
-
-/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_2d(
- float2 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float2 p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- float value = snoise_2d(p) + offset;
- float weight = gain * value;
- p *= lacunarity;
-
- for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
- if (weight > 1.0f) {
- weight = 1.0f;
- }
-
- float signal = (snoise_2d(p) + offset) * pwr;
- pwr *= pwHL;
- value += weight * signal;
- weight *= gain * signal;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value += rmd * ((snoise_2d(p) + offset) * pwr);
- }
-
- return value;
-}
-
-/* 2D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_2d(
- float2 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float2 p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- float signal = offset - fabsf(snoise_2d(p));
- signal *= signal;
- float value = signal;
- float weight = 1.0f;
-
- for (int i = 1; i < float_to_int(octaves); i++) {
- p *= lacunarity;
- weight = saturate(signal * gain);
- signal = offset - fabsf(snoise_2d(p));
- signal *= signal;
- signal *= weight;
- value += signal * pwr;
- pwr *= pwHL;
- }
-
- return value;
-}
-
-/* 3D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
-ccl_device_noinline_cpu float noise_musgrave_fBm_3d(float3 co,
- float H,
- float lacunarity,
- float octaves)
-{
- float3 p = co;
- float value = 0.0f;
- float pwr = 1.0f;
- float pwHL = powf(lacunarity, -H);
-
- for (int i = 0; i < float_to_int(octaves); i++) {
- value += snoise_3d(p) * pwr;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value += rmd * snoise_3d(p) * pwr;
- }
-
- return value;
-}
-
-/* 3D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
-ccl_device_noinline_cpu float noise_musgrave_multi_fractal_3d(float3 co,
- float H,
- float lacunarity,
- float octaves)
-{
- float3 p = co;
- float value = 1.0f;
- float pwr = 1.0f;
- float pwHL = powf(lacunarity, -H);
-
- for (int i = 0; i < float_to_int(octaves); i++) {
- value *= (pwr * snoise_3d(p) + 1.0f);
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value *= (rmd * pwr * snoise_3d(p) + 1.0f); /* correct? */
- }
-
- return value;
-}
-
-/* 3D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_3d(
- float3 co, float H, float lacunarity, float octaves, float offset)
-{
- float3 p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- /* first unscaled octave of function; later octaves are scaled */
- float value = offset + snoise_3d(p);
- p *= lacunarity;
-
- for (int i = 1; i < float_to_int(octaves); i++) {
- float increment = (snoise_3d(p) + offset) * pwr * value;
- value += increment;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- float increment = (snoise_3d(p) + offset) * pwr * value;
- value += rmd * increment;
- }
-
- return value;
-}
-
-/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_3d(
- float3 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float3 p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- float value = snoise_3d(p) + offset;
- float weight = gain * value;
- p *= lacunarity;
-
- for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
- if (weight > 1.0f) {
- weight = 1.0f;
- }
-
- float signal = (snoise_3d(p) + offset) * pwr;
- pwr *= pwHL;
- value += weight * signal;
- weight *= gain * signal;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value += rmd * ((snoise_3d(p) + offset) * pwr);
- }
-
- return value;
-}
-
-/* 3D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_3d(
- float3 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float3 p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- float signal = offset - fabsf(snoise_3d(p));
- signal *= signal;
- float value = signal;
- float weight = 1.0f;
-
- for (int i = 1; i < float_to_int(octaves); i++) {
- p *= lacunarity;
- weight = saturate(signal * gain);
- signal = offset - fabsf(snoise_3d(p));
- signal *= signal;
- signal *= weight;
- value += signal * pwr;
- pwr *= pwHL;
- }
-
- return value;
-}
-
-/* 4D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
-ccl_device_noinline_cpu float noise_musgrave_fBm_4d(float4 co,
- float H,
- float lacunarity,
- float octaves)
-{
- float4 p = co;
- float value = 0.0f;
- float pwr = 1.0f;
- float pwHL = powf(lacunarity, -H);
-
- for (int i = 0; i < float_to_int(octaves); i++) {
- value += snoise_4d(p) * pwr;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value += rmd * snoise_4d(p) * pwr;
- }
-
- return value;
-}
-
-/* 4D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
-ccl_device_noinline_cpu float noise_musgrave_multi_fractal_4d(float4 co,
- float H,
- float lacunarity,
- float octaves)
-{
- float4 p = co;
- float value = 1.0f;
- float pwr = 1.0f;
- float pwHL = powf(lacunarity, -H);
-
- for (int i = 0; i < float_to_int(octaves); i++) {
- value *= (pwr * snoise_4d(p) + 1.0f);
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value *= (rmd * pwr * snoise_4d(p) + 1.0f); /* correct? */
- }
-
- return value;
-}
-
-/* 4D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_4d(
- float4 co, float H, float lacunarity, float octaves, float offset)
-{
- float4 p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- /* first unscaled octave of function; later octaves are scaled */
- float value = offset + snoise_4d(p);
- p *= lacunarity;
-
- for (int i = 1; i < float_to_int(octaves); i++) {
- float increment = (snoise_4d(p) + offset) * pwr * value;
- value += increment;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- float increment = (snoise_4d(p) + offset) * pwr * value;
- value += rmd * increment;
- }
-
- return value;
-}
-
-/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_4d(
- float4 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float4 p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- float value = snoise_4d(p) + offset;
- float weight = gain * value;
- p *= lacunarity;
-
- for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
- if (weight > 1.0f) {
- weight = 1.0f;
- }
-
- float signal = (snoise_4d(p) + offset) * pwr;
- pwr *= pwHL;
- value += weight * signal;
- weight *= gain * signal;
- p *= lacunarity;
- }
-
- float rmd = octaves - floorf(octaves);
- if (rmd != 0.0f) {
- value += rmd * ((snoise_4d(p) + offset) * pwr);
- }
-
- return value;
-}
-
-/* 4D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_4d(
- float4 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float4 p = co;
- float pwHL = powf(lacunarity, -H);
- float pwr = pwHL;
-
- float signal = offset - fabsf(snoise_4d(p));
- signal *= signal;
- float value = signal;
- float weight = 1.0f;
-
- for (int i = 1; i < float_to_int(octaves); i++) {
- p *= lacunarity;
- weight = saturate(signal * gain);
- signal = offset - fabsf(snoise_4d(p));
- signal *= signal;
- signal *= weight;
- value += signal * pwr;
- pwr *= pwHL;
- }
-
- return value;
-}
-
-ccl_device_noinline int svm_node_tex_musgrave(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint offsets1,
- uint offsets2,
- uint offsets3,
- int offset)
-{
- uint type, dimensions, co_stack_offset, w_stack_offset;
- uint scale_stack_offset, detail_stack_offset, dimension_stack_offset, lacunarity_stack_offset;
- uint offset_stack_offset, gain_stack_offset, fac_stack_offset;
-
- svm_unpack_node_uchar4(offsets1, &type, &dimensions, &co_stack_offset, &w_stack_offset);
- svm_unpack_node_uchar4(offsets2,
- &scale_stack_offset,
- &detail_stack_offset,
- &dimension_stack_offset,
- &lacunarity_stack_offset);
- svm_unpack_node_uchar3(offsets3, &offset_stack_offset, &gain_stack_offset, &fac_stack_offset);
-
- uint4 defaults1 = read_node(kg, &offset);
- uint4 defaults2 = read_node(kg, &offset);
-
- float3 co = stack_load_float3(stack, co_stack_offset);
- float w = stack_load_float_default(stack, w_stack_offset, defaults1.x);
- float scale = stack_load_float_default(stack, scale_stack_offset, defaults1.y);
- float detail = stack_load_float_default(stack, detail_stack_offset, defaults1.z);
- float dimension = stack_load_float_default(stack, dimension_stack_offset, defaults1.w);
- float lacunarity = stack_load_float_default(stack, lacunarity_stack_offset, defaults2.x);
- float foffset = stack_load_float_default(stack, offset_stack_offset, defaults2.y);
- float gain = stack_load_float_default(stack, gain_stack_offset, defaults2.z);
-
- dimension = fmaxf(dimension, 1e-5f);
- detail = clamp(detail, 0.0f, 16.0f);
- lacunarity = fmaxf(lacunarity, 1e-5f);
-
- float fac;
-
- switch (dimensions) {
- case 1: {
- float p = w * scale;
- switch ((NodeMusgraveType)type) {
- case NODE_MUSGRAVE_MULTIFRACTAL:
- fac = noise_musgrave_multi_fractal_1d(p, dimension, lacunarity, detail);
- break;
- case NODE_MUSGRAVE_FBM:
- fac = noise_musgrave_fBm_1d(p, dimension, lacunarity, detail);
- break;
- case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
- fac = noise_musgrave_hybrid_multi_fractal_1d(
- p, dimension, lacunarity, detail, foffset, gain);
- break;
- case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
- fac = noise_musgrave_ridged_multi_fractal_1d(
- p, dimension, lacunarity, detail, foffset, gain);
- break;
- case NODE_MUSGRAVE_HETERO_TERRAIN:
- fac = noise_musgrave_hetero_terrain_1d(p, dimension, lacunarity, detail, foffset);
- break;
- default:
- fac = 0.0f;
- }
- break;
- }
- case 2: {
- float2 p = make_float2(co.x, co.y) * scale;
- switch ((NodeMusgraveType)type) {
- case NODE_MUSGRAVE_MULTIFRACTAL:
- fac = noise_musgrave_multi_fractal_2d(p, dimension, lacunarity, detail);
- break;
- case NODE_MUSGRAVE_FBM:
- fac = noise_musgrave_fBm_2d(p, dimension, lacunarity, detail);
- break;
- case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
- fac = noise_musgrave_hybrid_multi_fractal_2d(
- p, dimension, lacunarity, detail, foffset, gain);
- break;
- case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
- fac = noise_musgrave_ridged_multi_fractal_2d(
- p, dimension, lacunarity, detail, foffset, gain);
- break;
- case NODE_MUSGRAVE_HETERO_TERRAIN:
- fac = noise_musgrave_hetero_terrain_2d(p, dimension, lacunarity, detail, foffset);
- break;
- default:
- fac = 0.0f;
- }
- break;
- }
- case 3: {
- float3 p = co * scale;
- switch ((NodeMusgraveType)type) {
- case NODE_MUSGRAVE_MULTIFRACTAL:
- fac = noise_musgrave_multi_fractal_3d(p, dimension, lacunarity, detail);
- break;
- case NODE_MUSGRAVE_FBM:
- fac = noise_musgrave_fBm_3d(p, dimension, lacunarity, detail);
- break;
- case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
- fac = noise_musgrave_hybrid_multi_fractal_3d(
- p, dimension, lacunarity, detail, foffset, gain);
- break;
- case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
- fac = noise_musgrave_ridged_multi_fractal_3d(
- p, dimension, lacunarity, detail, foffset, gain);
- break;
- case NODE_MUSGRAVE_HETERO_TERRAIN:
- fac = noise_musgrave_hetero_terrain_3d(p, dimension, lacunarity, detail, foffset);
- break;
- default:
- fac = 0.0f;
- }
- break;
- }
- case 4: {
- float4 p = make_float4(co.x, co.y, co.z, w) * scale;
- switch ((NodeMusgraveType)type) {
- case NODE_MUSGRAVE_MULTIFRACTAL:
- fac = noise_musgrave_multi_fractal_4d(p, dimension, lacunarity, detail);
- break;
- case NODE_MUSGRAVE_FBM:
- fac = noise_musgrave_fBm_4d(p, dimension, lacunarity, detail);
- break;
- case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
- fac = noise_musgrave_hybrid_multi_fractal_4d(
- p, dimension, lacunarity, detail, foffset, gain);
- break;
- case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
- fac = noise_musgrave_ridged_multi_fractal_4d(
- p, dimension, lacunarity, detail, foffset, gain);
- break;
- case NODE_MUSGRAVE_HETERO_TERRAIN:
- fac = noise_musgrave_hetero_terrain_4d(p, dimension, lacunarity, detail, foffset);
- break;
- default:
- fac = 0.0f;
- }
- break;
- }
- default:
- fac = 0.0f;
- }
-
- stack_store_float(stack, fac_stack_offset, fac);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h
deleted file mode 100644
index ecb4df6afdf..00000000000
--- a/intern/cycles/kernel/svm/svm_noise.h
+++ /dev/null
@@ -1,742 +0,0 @@
-/*
- * Adapted from Open Shading Language with this license:
- *
- * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
- * All Rights Reserved.
- *
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Sony Pictures Imageworks nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* **** Perlin Noise **** */
-
-ccl_device float fade(float t)
-{
- return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
-}
-
-ccl_device_inline float negate_if(float val, int condition)
-{
- return (condition) ? -val : val;
-}
-
-ccl_device float grad1(int hash, float x)
-{
- int h = hash & 15;
- float g = 1 + (h & 7);
- return negate_if(g, h & 8) * x;
-}
-
-ccl_device_noinline_cpu float perlin_1d(float x)
-{
- int X;
- float fx = floorfrac(x, &X);
- float u = fade(fx);
-
- return mix(grad1(hash_uint(X), fx), grad1(hash_uint(X + 1), fx - 1.0f), u);
-}
-
-/* 2D, 3D, and 4D noise can be accelerated using SSE, so we first check if
- * SSE is supported, that is, if __KERNEL_SSE2__ is defined. If it is not
- * supported, we do a standard implementation, but if it is supported, we
- * do an implementation using SSE intrinsics.
- */
-#if !defined(__KERNEL_SSE2__)
-
-/* ** Standard Implementation ** */
-
-/* Bilinear Interpolation:
- *
- * v2 v3
- * @ + + + + @ y
- * + + ^
- * + + |
- * + + |
- * @ + + + + @ @------> x
- * v0 v1
- *
- */
-ccl_device float bi_mix(float v0, float v1, float v2, float v3, float x, float y)
-{
- float x1 = 1.0f - x;
- return (1.0f - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
-}
-
-/* Trilinear Interpolation:
- *
- * v6 v7
- * @ + + + + + + @
- * +\ +\
- * + \ + \
- * + \ + \
- * + \ v4 + \ v5
- * + @ + + + +++ + @ z
- * + + + + y ^
- * v2 @ + +++ + + + @ v3 + \ |
- * \ + \ + \ |
- * \ + \ + \|
- * \ + \ + +---------> x
- * \+ \+
- * @ + + + + + + @
- * v0 v1
- */
-ccl_device float tri_mix(float v0,
- float v1,
- float v2,
- float v3,
- float v4,
- float v5,
- float v6,
- float v7,
- float x,
- float y,
- float z)
-{
- float x1 = 1.0f - x;
- float y1 = 1.0f - y;
- float z1 = 1.0f - z;
- return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) +
- z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x));
-}
-
-ccl_device float quad_mix(float v0,
- float v1,
- float v2,
- float v3,
- float v4,
- float v5,
- float v6,
- float v7,
- float v8,
- float v9,
- float v10,
- float v11,
- float v12,
- float v13,
- float v14,
- float v15,
- float x,
- float y,
- float z,
- float w)
-{
- return mix(tri_mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z),
- tri_mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z),
- w);
-}
-
-ccl_device float grad2(int hash, float x, float y)
-{
- int h = hash & 7;
- float u = h < 4 ? x : y;
- float v = 2.0f * (h < 4 ? y : x);
- return negate_if(u, h & 1) + negate_if(v, h & 2);
-}
-
-ccl_device float grad3(int hash, float x, float y, float z)
-{
- int h = hash & 15;
- float u = h < 8 ? x : y;
- float vt = ((h == 12) || (h == 14)) ? x : z;
- float v = h < 4 ? y : vt;
- return negate_if(u, h & 1) + negate_if(v, h & 2);
-}
-
-ccl_device float grad4(int hash, float x, float y, float z, float w)
-{
- int h = hash & 31;
- float u = h < 24 ? x : y;
- float v = h < 16 ? y : z;
- float s = h < 8 ? z : w;
- return negate_if(u, h & 1) + negate_if(v, h & 2) + negate_if(s, h & 4);
-}
-
-ccl_device_noinline_cpu float perlin_2d(float x, float y)
-{
- int X;
- int Y;
-
- float fx = floorfrac(x, &X);
- float fy = floorfrac(y, &Y);
-
- float u = fade(fx);
- float v = fade(fy);
-
- float r = bi_mix(grad2(hash_uint2(X, Y), fx, fy),
- grad2(hash_uint2(X + 1, Y), fx - 1.0f, fy),
- grad2(hash_uint2(X, Y + 1), fx, fy - 1.0f),
- grad2(hash_uint2(X + 1, Y + 1), fx - 1.0f, fy - 1.0f),
- u,
- v);
-
- return r;
-}
-
-ccl_device_noinline_cpu float perlin_3d(float x, float y, float z)
-{
- int X;
- int Y;
- int Z;
-
- float fx = floorfrac(x, &X);
- float fy = floorfrac(y, &Y);
- float fz = floorfrac(z, &Z);
-
- float u = fade(fx);
- float v = fade(fy);
- float w = fade(fz);
-
- float r = tri_mix(grad3(hash_uint3(X, Y, Z), fx, fy, fz),
- grad3(hash_uint3(X + 1, Y, Z), fx - 1.0f, fy, fz),
- grad3(hash_uint3(X, Y + 1, Z), fx, fy - 1.0f, fz),
- grad3(hash_uint3(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz),
- grad3(hash_uint3(X, Y, Z + 1), fx, fy, fz - 1.0f),
- grad3(hash_uint3(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f),
- grad3(hash_uint3(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f),
- grad3(hash_uint3(X + 1, Y + 1, Z + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f),
- u,
- v,
- w);
- return r;
-}
-
-ccl_device_noinline_cpu float perlin_4d(float x, float y, float z, float w)
-{
- int X;
- int Y;
- int Z;
- int W;
-
- float fx = floorfrac(x, &X);
- float fy = floorfrac(y, &Y);
- float fz = floorfrac(z, &Z);
- float fw = floorfrac(w, &W);
-
- float u = fade(fx);
- float v = fade(fy);
- float t = fade(fz);
- float s = fade(fw);
-
- float r = quad_mix(
- grad4(hash_uint4(X, Y, Z, W), fx, fy, fz, fw),
- grad4(hash_uint4(X + 1, Y, Z, W), fx - 1.0f, fy, fz, fw),
- grad4(hash_uint4(X, Y + 1, Z, W), fx, fy - 1.0f, fz, fw),
- grad4(hash_uint4(X + 1, Y + 1, Z, W), fx - 1.0f, fy - 1.0f, fz, fw),
- grad4(hash_uint4(X, Y, Z + 1, W), fx, fy, fz - 1.0f, fw),
- grad4(hash_uint4(X + 1, Y, Z + 1, W), fx - 1.0f, fy, fz - 1.0f, fw),
- grad4(hash_uint4(X, Y + 1, Z + 1, W), fx, fy - 1.0f, fz - 1.0f, fw),
- grad4(hash_uint4(X + 1, Y + 1, Z + 1, W), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw),
- grad4(hash_uint4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0f),
- grad4(hash_uint4(X + 1, Y, Z, W + 1), fx - 1.0f, fy, fz, fw - 1.0f),
- grad4(hash_uint4(X, Y + 1, Z, W + 1), fx, fy - 1.0f, fz, fw - 1.0f),
- grad4(hash_uint4(X + 1, Y + 1, Z, W + 1), fx - 1.0f, fy - 1.0f, fz, fw - 1.0f),
- grad4(hash_uint4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0f, fw - 1.0f),
- grad4(hash_uint4(X + 1, Y, Z + 1, W + 1), fx - 1.0f, fy, fz - 1.0f, fw - 1.0f),
- grad4(hash_uint4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0f, fz - 1.0f, fw - 1.0f),
- grad4(hash_uint4(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw - 1.0f),
- u,
- v,
- t,
- s);
-
- return r;
-}
-
-#else /* SSE is supported. */
-
-/* ** SSE Implementation ** */
-
-/* SSE Bilinear Interpolation:
- *
- * The function takes two ssef inputs:
- * - p : Contains the values at the points (v0, v1, v2, v3).
- * - f : Contains the values (x, y, _, _). The third and fourth values are unused.
- *
- * The interpolation is done in two steps:
- * 1. Interpolate (v0, v1) and (v2, v3) along the x axis to get g (g0, g1).
- * (v2, v3) is generated by moving v2 and v3 to the first and second
- * places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and
- * fourth values are unused.
- * 2. Interpolate g0 and g1 along the y axis to get the final value.
- * g1 is generated by populating an ssef with the second value of g.
- * Only the first value is important in the final ssef.
- *
- * v1 v3 g1
- * @ + + + + @ @ y
- * + + (1) + (2) ^
- * + + ---> + ---> final |
- * + + + |
- * @ + + + + @ @ @------> x
- * v0 v2 g0
- *
- */
-ccl_device_inline ssef bi_mix(ssef p, ssef f)
-{
- ssef g = mix(p, shuffle<2, 3, 2, 3>(p), shuffle<0>(f));
- return mix(g, shuffle<1>(g), shuffle<1>(f));
-}
-
-ccl_device_inline ssef fade(const ssef &t)
-{
- ssef a = madd(t, 6.0f, -15.0f);
- ssef b = madd(t, a, 10.0f);
- return (t * t) * (t * b);
-}
-
-/* Negate val if the nth bit of h is 1. */
-# define negate_if_nth_bit(val, h, n) ((val) ^ cast(((h) & (1 << (n))) << (31 - (n))))
-
-ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y)
-{
- ssei h = hash & 7;
- ssef u = select(h < 4, x, y);
- ssef v = 2.0f * select(h < 4, y, x);
- return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
-}
-
-/* We use SSE to compute and interpolate 4 gradients at once:
- *
- * Point Offset from v0
- * v0 (0, 0)
- * v1 (0, 1)
- * v2 (1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(V, V + 1))
- * v3 (1, 1) ^
- * | |__________| (0, 0, 1, 1) = shuffle<0, 0, 0, 0>(V, V + 1)
- * | ^
- * |__________________________|
- *
- */
-ccl_device_noinline_cpu float perlin_2d(float x, float y)
-{
- ssei XY;
- ssef fxy = floorfrac(ssef(x, y, 0.0f, 0.0f), &XY);
- ssef uv = fade(fxy);
-
- ssei XY1 = XY + 1;
- ssei X = shuffle<0, 0, 0, 0>(XY, XY1);
- ssei Y = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(XY, XY1));
-
- ssei h = hash_ssei2(X, Y);
-
- ssef fxy1 = fxy - 1.0f;
- ssef fx = shuffle<0, 0, 0, 0>(fxy, fxy1);
- ssef fy = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(fxy, fxy1));
-
- ssef g = grad(h, fx, fy);
-
- return extract<0>(bi_mix(g, uv));
-}
-
-/* SSE Trilinear Interpolation:
- *
- * The function takes three ssef inputs:
- * - p : Contains the values at the points (v0, v1, v2, v3).
- * - q : Contains the values at the points (v4, v5, v6, v7).
- * - f : Contains the values (x, y, z, _). The fourth value is unused.
- *
- * The interpolation is done in three steps:
- * 1. Interpolate p and q along the x axis to get s (s0, s1, s2, s3).
- * 2. Interpolate (s0, s1) and (s2, s3) along the y axis to get g (g0, g1).
- * (s2, s3) is generated by moving v2 and v3 to the first and second
- * places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and
- * fourth values are unused.
- * 3. Interpolate g0 and g1 along the z axis to get the final value.
- * g1 is generated by populating an ssef with the second value of g.
- * Only the first value is important in the final ssef.
- *
- * v3 v7
- * @ + + + + + + @ s3 @
- * +\ +\ +\
- * + \ + \ + \
- * + \ + \ + \ g1
- * + \ v1 + \ v5 + \ s1 @
- * + @ + + + +++ + @ + @ + z
- * + + + + (1) + + (2) + (3) y ^
- * v2 @ + +++ + + + @ v6 + ---> s2 @ + ---> + ---> final \ |
- * \ + \ + \ + + \ |
- * \ + \ + \ + + \|
- * \ + \ + \ + @ +---------> x
- * \+ \+ \+ g0
- * @ + + + + + + @ @
- * v0 v4 s0
- */
-ccl_device_inline ssef tri_mix(ssef p, ssef q, ssef f)
-{
- ssef s = mix(p, q, shuffle<0>(f));
- ssef g = mix(s, shuffle<2, 3, 2, 3>(s), shuffle<1>(f));
- return mix(g, shuffle<1>(g), shuffle<2>(f));
-}
-
-/* 3D and 4D noise can be accelerated using AVX, so we first check if AVX
- * is supported, that is, if __KERNEL_AVX__ is defined. If it is not
- * supported, we do an SSE implementation, but if it is supported,
- * we do an implementation using AVX intrinsics.
- */
-# if !defined(__KERNEL_AVX__)
-
-ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z)
-{
- ssei h = hash & 15;
- ssef u = select(h < 8, x, y);
- ssef vt = select((h == 12) | (h == 14), x, z);
- ssef v = select(h < 4, y, vt);
- return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
-}
-
-ccl_device_inline ssef
-grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z, const ssef &w)
-{
- ssei h = hash & 31;
- ssef u = select(h < 24, x, y);
- ssef v = select(h < 16, y, z);
- ssef s = select(h < 8, z, w);
- return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1) + negate_if_nth_bit(s, h, 2);
-}
-
-/* SSE Quadrilinear Interpolation:
- *
- * Quadrilinear interpolation is as simple as a linear interpolation
- * between two trilinear interpolations.
- *
- */
-ccl_device_inline ssef quad_mix(ssef p, ssef q, ssef r, ssef s, ssef f)
-{
- return mix(tri_mix(p, q, f), tri_mix(r, s, f), shuffle<3>(f));
-}
-
-/* We use SSE to compute and interpolate 4 gradients at once. Since we have 8
- * gradients in 3D, we need to compute two sets of gradients at the points:
- *
- * Point Offset from v0
- * v0 (0, 0, 0)
- * v1 (0, 0, 1)
- * v2 (0, 1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
- * v3 (0, 1, 1) ^
- * | |__________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
- * | ^
- * |__________________________|
- *
- * Point Offset from v0
- * v4 (1, 0, 0)
- * v5 (1, 0, 1)
- * v6 (1, 1, 0)
- * v7 (1, 1, 1)
- *
- */
-ccl_device_noinline_cpu float perlin_3d(float x, float y, float z)
-{
- ssei XYZ;
- ssef fxyz = floorfrac(ssef(x, y, z, 0.0f), &XYZ);
- ssef uvw = fade(fxyz);
-
- ssei XYZ1 = XYZ + 1;
- ssei Y = shuffle<1, 1, 1, 1>(XYZ, XYZ1);
- ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ1));
-
- ssei h1 = hash_ssei3(shuffle<0>(XYZ), Y, Z);
- ssei h2 = hash_ssei3(shuffle<0>(XYZ1), Y, Z);
-
- ssef fxyz1 = fxyz - 1.0f;
- ssef fy = shuffle<1, 1, 1, 1>(fxyz, fxyz1);
- ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz1));
-
- ssef g1 = grad(h1, shuffle<0>(fxyz), fy, fz);
- ssef g2 = grad(h2, shuffle<0>(fxyz1), fy, fz);
-
- return extract<0>(tri_mix(g1, g2, uvw));
-}
-
-/* We use SSE to compute and interpolate 4 gradients at once. Since we have 16
- * gradients in 4D, we need to compute four sets of gradients at the points:
- *
- * Point Offset from v0
- * v0 (0, 0, 0, 0)
- * v1 (0, 0, 1, 0)
- * v2 (0, 1, 0, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
- * v3 (0, 1, 1, 0) ^
- * | |________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
- * | ^
- * |_______________________|
- *
- * Point Offset from v0
- * v4 (1, 0, 0, 0)
- * v5 (1, 0, 1, 0)
- * v6 (1, 1, 0, 0)
- * v7 (1, 1, 1, 0)
- *
- * Point Offset from v0
- * v8 (0, 0, 0, 1)
- * v9 (0, 0, 1, 1)
- * v10 (0, 1, 0, 1)
- * v11 (0, 1, 1, 1)
- *
- * Point Offset from v0
- * v12 (1, 0, 0, 1)
- * v13 (1, 0, 1, 1)
- * v14 (1, 1, 0, 1)
- * v15 (1, 1, 1, 1)
- *
- */
-ccl_device_noinline_cpu float perlin_4d(float x, float y, float z, float w)
-{
- ssei XYZW;
- ssef fxyzw = floorfrac(ssef(x, y, z, w), &XYZW);
- ssef uvws = fade(fxyzw);
-
- ssei XYZW1 = XYZW + 1;
- ssei Y = shuffle<1, 1, 1, 1>(XYZW, XYZW1);
- ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZW, XYZW1));
-
- ssei h1 = hash_ssei4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW));
- ssei h2 = hash_ssei4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW));
-
- ssei h3 = hash_ssei4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW1));
- ssei h4 = hash_ssei4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW1));
-
- ssef fxyzw1 = fxyzw - 1.0f;
- ssef fy = shuffle<1, 1, 1, 1>(fxyzw, fxyzw1);
- ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyzw, fxyzw1));
-
- ssef g1 = grad(h1, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw));
- ssef g2 = grad(h2, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw));
-
- ssef g3 = grad(h3, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw1));
- ssef g4 = grad(h4, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw1));
-
- return extract<0>(quad_mix(g1, g2, g3, g4, uvws));
-}
-
-# else /* AVX is supported. */
-
-/* AVX Implementation */
-
-ccl_device_inline avxf grad(const avxi &hash, const avxf &x, const avxf &y, const avxf &z)
-{
- avxi h = hash & 15;
- avxf u = select(h < 8, x, y);
- avxf vt = select((h == 12) | (h == 14), x, z);
- avxf v = select(h < 4, y, vt);
- return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
-}
-
-ccl_device_inline avxf
-grad(const avxi &hash, const avxf &x, const avxf &y, const avxf &z, const avxf &w)
-{
- avxi h = hash & 31;
- avxf u = select(h < 24, x, y);
- avxf v = select(h < 16, y, z);
- avxf s = select(h < 8, z, w);
- return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1) + negate_if_nth_bit(s, h, 2);
-}
-
-/* SSE Quadrilinear Interpolation:
- *
- * The interpolation is done in two steps:
- * 1. Interpolate p and q along the w axis to get s.
- * 2. Trilinearly interpolate (s0, s1, s2, s3) and (s4, s5, s6, s7) to get the final
- * value. (s0, s1, s2, s3) and (s4, s5, s6, s7) are generated by extracting the
- * low and high ssef from s.
- *
- */
-ccl_device_inline ssef quad_mix(avxf p, avxf q, ssef f)
-{
- ssef fv = shuffle<3>(f);
- avxf s = mix(p, q, avxf(fv, fv));
- return tri_mix(low(s), high(s), f);
-}
-
-/* We use AVX to compute and interpolate 8 gradients at once.
- *
- * Point Offset from v0
- * v0 (0, 0, 0)
- * v1 (0, 0, 1) The full AVX type is computed by inserting the following
- * v2 (0, 1, 0) SSE types into both the low and high parts of the AVX.
- * v3 (0, 1, 1)
- * v4 (1, 0, 0)
- * v5 (1, 0, 1) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
- * v6 (1, 1, 0) ^
- * v7 (1, 1, 1) |
- * | |__________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
- * | ^
- * |__________________________|
- *
- */
-ccl_device_noinline_cpu float perlin_3d(float x, float y, float z)
-{
- ssei XYZ;
- ssef fxyz = floorfrac(ssef(x, y, z, 0.0f), &XYZ);
- ssef uvw = fade(fxyz);
-
- ssei XYZ1 = XYZ + 1;
- ssei X = shuffle<0>(XYZ);
- ssei X1 = shuffle<0>(XYZ1);
- ssei Y = shuffle<1, 1, 1, 1>(XYZ, XYZ1);
- ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ1));
-
- avxi h = hash_avxi3(avxi(X, X1), avxi(Y, Y), avxi(Z, Z));
-
- ssef fxyz1 = fxyz - 1.0f;
- ssef fx = shuffle<0>(fxyz);
- ssef fx1 = shuffle<0>(fxyz1);
- ssef fy = shuffle<1, 1, 1, 1>(fxyz, fxyz1);
- ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz1));
-
- avxf g = grad(h, avxf(fx, fx1), avxf(fy, fy), avxf(fz, fz));
-
- return extract<0>(tri_mix(low(g), high(g), uvw));
-}
-
-/* We use AVX to compute and interpolate 8 gradients at once. Since we have 16
- * gradients in 4D, we need to compute two sets of gradients at the points:
- *
- * Point Offset from v0
- * v0 (0, 0, 0, 0)
- * v1 (0, 0, 1, 0) The full AVX type is computed by inserting the following
- * v2 (0, 1, 0, 0) SSE types into both the low and high parts of the AVX.
- * v3 (0, 1, 1, 0)
- * v4 (1, 0, 0, 0)
- * v5 (1, 0, 1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
- * v6 (1, 1, 0, 0) ^
- * v7 (1, 1, 1, 0) |
- * | |________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
- * | ^
- * |_______________________|
- *
- * Point Offset from v0
- * v8 (0, 0, 0, 1)
- * v9 (0, 0, 1, 1)
- * v10 (0, 1, 0, 1)
- * v11 (0, 1, 1, 1)
- * v12 (1, 0, 0, 1)
- * v13 (1, 0, 1, 1)
- * v14 (1, 1, 0, 1)
- * v15 (1, 1, 1, 1)
- *
- */
-ccl_device_noinline_cpu float perlin_4d(float x, float y, float z, float w)
-{
- ssei XYZW;
- ssef fxyzw = floorfrac(ssef(x, y, z, w), &XYZW);
- ssef uvws = fade(fxyzw);
-
- ssei XYZW1 = XYZW + 1;
- ssei X = shuffle<0>(XYZW);
- ssei X1 = shuffle<0>(XYZW1);
- ssei Y = shuffle<1, 1, 1, 1>(XYZW, XYZW1);
- ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZW, XYZW1));
- ssei W = shuffle<3>(XYZW);
- ssei W1 = shuffle<3>(XYZW1);
-
- avxi h1 = hash_avxi4(avxi(X, X1), avxi(Y, Y), avxi(Z, Z), avxi(W, W));
- avxi h2 = hash_avxi4(avxi(X, X1), avxi(Y, Y), avxi(Z, Z), avxi(W1, W1));
-
- ssef fxyzw1 = fxyzw - 1.0f;
- ssef fx = shuffle<0>(fxyzw);
- ssef fx1 = shuffle<0>(fxyzw1);
- ssef fy = shuffle<1, 1, 1, 1>(fxyzw, fxyzw1);
- ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyzw, fxyzw1));
- ssef fw = shuffle<3>(fxyzw);
- ssef fw1 = shuffle<3>(fxyzw1);
-
- avxf g1 = grad(h1, avxf(fx, fx1), avxf(fy, fy), avxf(fz, fz), avxf(fw, fw));
- avxf g2 = grad(h2, avxf(fx, fx1), avxf(fy, fy), avxf(fz, fz), avxf(fw1, fw1));
-
- return extract<0>(quad_mix(g1, g2, uvws));
-}
-# endif
-
-# undef negate_if_nth_bit
-
-#endif
-
-/* Remap the output of noise to a predictable range [-1, 1].
- * The scale values were computed experimentally by the OSL developers.
- */
-
-ccl_device_inline float noise_scale1(float result)
-{
- return 0.2500f * result;
-}
-
-ccl_device_inline float noise_scale2(float result)
-{
- return 0.6616f * result;
-}
-
-ccl_device_inline float noise_scale3(float result)
-{
- return 0.9820f * result;
-}
-
-ccl_device_inline float noise_scale4(float result)
-{
- return 0.8344f * result;
-}
-
-/* Safe Signed And Unsigned Noise */
-
-ccl_device_inline float snoise_1d(float p)
-{
- return noise_scale1(ensure_finite(perlin_1d(p)));
-}
-
-ccl_device_inline float noise_1d(float p)
-{
- return 0.5f * snoise_1d(p) + 0.5f;
-}
-
-ccl_device_inline float snoise_2d(float2 p)
-{
- return noise_scale2(ensure_finite(perlin_2d(p.x, p.y)));
-}
-
-ccl_device_inline float noise_2d(float2 p)
-{
- return 0.5f * snoise_2d(p) + 0.5f;
-}
-
-ccl_device_inline float snoise_3d(float3 p)
-{
- return noise_scale3(ensure_finite(perlin_3d(p.x, p.y, p.z)));
-}
-
-ccl_device_inline float noise_3d(float3 p)
-{
- return 0.5f * snoise_3d(p) + 0.5f;
-}
-
-ccl_device_inline float snoise_4d(float4 p)
-{
- return noise_scale4(ensure_finite(perlin_4d(p.x, p.y, p.z, p.w)));
-}
-
-ccl_device_inline float noise_4d(float4 p)
-{
- return 0.5f * snoise_4d(p) + 0.5f;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_noisetex.h b/intern/cycles/kernel/svm/svm_noisetex.h
deleted file mode 100644
index 3fe33f72b59..00000000000
--- a/intern/cycles/kernel/svm/svm_noisetex.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* The following offset functions generate random offsets to be added to texture
- * coordinates to act as a seed since the noise functions don't have seed values.
- * A seed value is needed for generating distortion textures and color outputs.
- * The offset's components are in the range [100, 200], not too high to cause
- * bad precision and not too small to be noticeable. We use float seed because
- * OSL only support float hashes.
- */
-
-ccl_device_inline float random_float_offset(float seed)
-{
- return 100.0f + hash_float_to_float(seed) * 100.0f;
-}
-
-ccl_device_inline float2 random_float2_offset(float seed)
-{
- return make_float2(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
- 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f);
-}
-
-ccl_device_inline float3 random_float3_offset(float seed)
-{
- return make_float3(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
- 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f,
- 100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f);
-}
-
-ccl_device_inline float4 random_float4_offset(float seed)
-{
- return make_float4(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
- 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f,
- 100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f,
- 100.0f + hash_float2_to_float(make_float2(seed, 3.0f)) * 100.0f);
-}
-
-ccl_device void noise_texture_1d(float co,
- float detail,
- float roughness,
- float distortion,
- bool color_is_needed,
- ccl_private float *value,
- ccl_private float3 *color)
-{
- float p = co;
- if (distortion != 0.0f) {
- p += snoise_1d(p + random_float_offset(0.0f)) * distortion;
- }
-
- *value = fractal_noise_1d(p, detail, roughness);
- if (color_is_needed) {
- *color = make_float3(*value,
- fractal_noise_1d(p + random_float_offset(1.0f), detail, roughness),
- fractal_noise_1d(p + random_float_offset(2.0f), detail, roughness));
- }
-}
-
-ccl_device void noise_texture_2d(float2 co,
- float detail,
- float roughness,
- float distortion,
- bool color_is_needed,
- ccl_private float *value,
- ccl_private float3 *color)
-{
- float2 p = co;
- if (distortion != 0.0f) {
- p += make_float2(snoise_2d(p + random_float2_offset(0.0f)) * distortion,
- snoise_2d(p + random_float2_offset(1.0f)) * distortion);
- }
-
- *value = fractal_noise_2d(p, detail, roughness);
- if (color_is_needed) {
- *color = make_float3(*value,
- fractal_noise_2d(p + random_float2_offset(2.0f), detail, roughness),
- fractal_noise_2d(p + random_float2_offset(3.0f), detail, roughness));
- }
-}
-
-ccl_device void noise_texture_3d(float3 co,
- float detail,
- float roughness,
- float distortion,
- bool color_is_needed,
- ccl_private float *value,
- ccl_private float3 *color)
-{
- float3 p = co;
- if (distortion != 0.0f) {
- p += make_float3(snoise_3d(p + random_float3_offset(0.0f)) * distortion,
- snoise_3d(p + random_float3_offset(1.0f)) * distortion,
- snoise_3d(p + random_float3_offset(2.0f)) * distortion);
- }
-
- *value = fractal_noise_3d(p, detail, roughness);
- if (color_is_needed) {
- *color = make_float3(*value,
- fractal_noise_3d(p + random_float3_offset(3.0f), detail, roughness),
- fractal_noise_3d(p + random_float3_offset(4.0f), detail, roughness));
- }
-}
-
-ccl_device void noise_texture_4d(float4 co,
- float detail,
- float roughness,
- float distortion,
- bool color_is_needed,
- ccl_private float *value,
- ccl_private float3 *color)
-{
- float4 p = co;
- if (distortion != 0.0f) {
- p += make_float4(snoise_4d(p + random_float4_offset(0.0f)) * distortion,
- snoise_4d(p + random_float4_offset(1.0f)) * distortion,
- snoise_4d(p + random_float4_offset(2.0f)) * distortion,
- snoise_4d(p + random_float4_offset(3.0f)) * distortion);
- }
-
- *value = fractal_noise_4d(p, detail, roughness);
- if (color_is_needed) {
- *color = make_float3(*value,
- fractal_noise_4d(p + random_float4_offset(4.0f), detail, roughness),
- fractal_noise_4d(p + random_float4_offset(5.0f), detail, roughness));
- }
-}
-
-ccl_device_noinline int svm_node_tex_noise(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint dimensions,
- uint offsets1,
- uint offsets2,
- int offset)
-{
- uint vector_stack_offset, w_stack_offset, scale_stack_offset;
- uint detail_stack_offset, roughness_stack_offset, distortion_stack_offset;
- uint value_stack_offset, color_stack_offset;
-
- svm_unpack_node_uchar4(
- offsets1, &vector_stack_offset, &w_stack_offset, &scale_stack_offset, &detail_stack_offset);
- svm_unpack_node_uchar4(offsets2,
- &roughness_stack_offset,
- &distortion_stack_offset,
- &value_stack_offset,
- &color_stack_offset);
-
- uint4 defaults1 = read_node(kg, &offset);
- uint4 defaults2 = read_node(kg, &offset);
-
- float3 vector = stack_load_float3(stack, vector_stack_offset);
- float w = stack_load_float_default(stack, w_stack_offset, defaults1.x);
- float scale = stack_load_float_default(stack, scale_stack_offset, defaults1.y);
- float detail = stack_load_float_default(stack, detail_stack_offset, defaults1.z);
- float roughness = stack_load_float_default(stack, roughness_stack_offset, defaults1.w);
- float distortion = stack_load_float_default(stack, distortion_stack_offset, defaults2.x);
-
- vector *= scale;
- w *= scale;
-
- float value;
- float3 color;
- switch (dimensions) {
- case 1:
- noise_texture_1d(
- w, detail, roughness, distortion, stack_valid(color_stack_offset), &value, &color);
- break;
- case 2:
- noise_texture_2d(make_float2(vector.x, vector.y),
- detail,
- roughness,
- distortion,
- stack_valid(color_stack_offset),
- &value,
- &color);
- break;
- case 3:
- noise_texture_3d(
- vector, detail, roughness, distortion, stack_valid(color_stack_offset), &value, &color);
- break;
- case 4:
- noise_texture_4d(make_float4(vector.x, vector.y, vector.z, w),
- detail,
- roughness,
- distortion,
- stack_valid(color_stack_offset),
- &value,
- &color);
- break;
- default:
- kernel_assert(0);
- }
-
- if (stack_valid(value_stack_offset)) {
- stack_store_float(stack, value_stack_offset, value);
- }
- if (stack_valid(color_stack_offset)) {
- stack_store_float3(stack, color_stack_offset, color);
- }
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_normal.h b/intern/cycles/kernel/svm/svm_normal.h
deleted file mode 100644
index 9bf64ed8823..00000000000
--- a/intern/cycles/kernel/svm/svm_normal.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_noinline int svm_node_normal(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint in_normal_offset,
- uint out_normal_offset,
- uint out_dot_offset,
- int offset)
-{
- /* read extra data */
- uint4 node1 = read_node(kg, &offset);
- float3 normal = stack_load_float3(stack, in_normal_offset);
-
- float3 direction;
- direction.x = __int_as_float(node1.x);
- direction.y = __int_as_float(node1.y);
- direction.z = __int_as_float(node1.z);
- direction = normalize(direction);
-
- if (stack_valid(out_normal_offset))
- stack_store_float3(stack, out_normal_offset, direction);
-
- if (stack_valid(out_dot_offset))
- stack_store_float(stack, out_dot_offset, dot(direction, normalize(normal)));
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_ramp.h b/intern/cycles/kernel/svm/svm_ramp.h
deleted file mode 100644
index d2dddf4c6eb..00000000000
--- a/intern/cycles/kernel/svm/svm_ramp.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SVM_RAMP_H__
-#define __SVM_RAMP_H__
-
-CCL_NAMESPACE_BEGIN
-
-/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
-
-ccl_device_inline float fetch_float(KernelGlobals kg, int offset)
-{
- uint4 node = kernel_tex_fetch(__svm_nodes, offset);
- return __uint_as_float(node.x);
-}
-
-ccl_device_inline float float_ramp_lookup(
- KernelGlobals kg, int offset, float f, bool interpolate, bool extrapolate, int table_size)
-{
- if ((f < 0.0f || f > 1.0f) && extrapolate) {
- float t0, dy;
- if (f < 0.0f) {
- t0 = fetch_float(kg, offset);
- dy = t0 - fetch_float(kg, offset + 1);
- f = -f;
- }
- else {
- t0 = fetch_float(kg, offset + table_size - 1);
- dy = t0 - fetch_float(kg, offset + table_size - 2);
- f = f - 1.0f;
- }
- return t0 + dy * f * (table_size - 1);
- }
-
- f = saturate(f) * (table_size - 1);
-
- /* clamp int as well in case of NaN */
- int i = clamp(float_to_int(f), 0, table_size - 1);
- float t = f - (float)i;
-
- float a = fetch_float(kg, offset + i);
-
- if (interpolate && t > 0.0f)
- a = (1.0f - t) * a + t * fetch_float(kg, offset + i + 1);
-
- return a;
-}
-
-ccl_device_inline float4 rgb_ramp_lookup(
- KernelGlobals kg, int offset, float f, bool interpolate, bool extrapolate, int table_size)
-{
- if ((f < 0.0f || f > 1.0f) && extrapolate) {
- float4 t0, dy;
- if (f < 0.0f) {
- t0 = fetch_node_float(kg, offset);
- dy = t0 - fetch_node_float(kg, offset + 1);
- f = -f;
- }
- else {
- t0 = fetch_node_float(kg, offset + table_size - 1);
- dy = t0 - fetch_node_float(kg, offset + table_size - 2);
- f = f - 1.0f;
- }
- return t0 + dy * f * (table_size - 1);
- }
-
- f = saturate(f) * (table_size - 1);
-
- /* clamp int as well in case of NaN */
- int i = clamp(float_to_int(f), 0, table_size - 1);
- float t = f - (float)i;
-
- float4 a = fetch_node_float(kg, offset + i);
-
- if (interpolate && t > 0.0f)
- a = (1.0f - t) * a + t * fetch_node_float(kg, offset + i + 1);
-
- return a;
-}
-
-ccl_device_noinline int svm_node_rgb_ramp(
- KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
-{
- uint fac_offset, color_offset, alpha_offset;
- uint interpolate = node.z;
-
- svm_unpack_node_uchar3(node.y, &fac_offset, &color_offset, &alpha_offset);
-
- uint table_size = read_node(kg, &offset).x;
-
- float fac = stack_load_float(stack, fac_offset);
- float4 color = rgb_ramp_lookup(kg, offset, fac, interpolate, false, table_size);
-
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, float4_to_float3(color));
- if (stack_valid(alpha_offset))
- stack_store_float(stack, alpha_offset, color.w);
-
- offset += table_size;
- return offset;
-}
-
-ccl_device_noinline int svm_node_curves(
- KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
-{
- uint fac_offset, color_offset, out_offset;
- svm_unpack_node_uchar3(node.y, &fac_offset, &color_offset, &out_offset);
-
- uint table_size = read_node(kg, &offset).x;
-
- float fac = stack_load_float(stack, fac_offset);
- float3 color = stack_load_float3(stack, color_offset);
-
- const float min_x = __int_as_float(node.z), max_x = __int_as_float(node.w);
- const float range_x = max_x - min_x;
- const float3 relpos = (color - make_float3(min_x, min_x, min_x)) / range_x;
-
- float r = rgb_ramp_lookup(kg, offset, relpos.x, true, true, table_size).x;
- float g = rgb_ramp_lookup(kg, offset, relpos.y, true, true, table_size).y;
- float b = rgb_ramp_lookup(kg, offset, relpos.z, true, true, table_size).z;
-
- color = (1.0f - fac) * color + fac * make_float3(r, g, b);
- stack_store_float3(stack, out_offset, color);
-
- offset += table_size;
- return offset;
-}
-
-ccl_device_noinline int svm_node_curve(
- KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
-{
- uint fac_offset, value_in_offset, out_offset;
- svm_unpack_node_uchar3(node.y, &fac_offset, &value_in_offset, &out_offset);
-
- uint table_size = read_node(kg, &offset).x;
-
- float fac = stack_load_float(stack, fac_offset);
- float in = stack_load_float(stack, value_in_offset);
-
- const float min = __int_as_float(node.z), max = __int_as_float(node.w);
- const float range = max - min;
- const float relpos = (in - min) / range;
-
- float v = float_ramp_lookup(kg, offset, relpos, true, true, table_size);
-
- in = (1.0f - fac) * in + fac * v;
- stack_store_float(stack, out_offset, in);
-
- offset += table_size;
- return offset;
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __SVM_RAMP_H__ */
diff --git a/intern/cycles/kernel/svm/svm_ramp_util.h b/intern/cycles/kernel/svm/svm_ramp_util.h
deleted file mode 100644
index 202596c1fe3..00000000000
--- a/intern/cycles/kernel/svm/svm_ramp_util.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SVM_RAMP_UTIL_H__
-#define __SVM_RAMP_UTIL_H__
-
-CCL_NAMESPACE_BEGIN
-
-/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
-
-ccl_device_inline float3
-rgb_ramp_lookup(const float3 *ramp, float f, bool interpolate, bool extrapolate, int table_size)
-{
- if ((f < 0.0f || f > 1.0f) && extrapolate) {
- float3 t0, dy;
- if (f < 0.0f) {
- t0 = ramp[0];
- dy = t0 - ramp[1], f = -f;
- }
- else {
- t0 = ramp[table_size - 1];
- dy = t0 - ramp[table_size - 2];
- f = f - 1.0f;
- }
- return t0 + dy * f * (table_size - 1);
- }
-
- f = clamp(f, 0.0f, 1.0f) * (table_size - 1);
-
- /* clamp int as well in case of NaN */
- int i = clamp(float_to_int(f), 0, table_size - 1);
- float t = f - (float)i;
-
- float3 result = ramp[i];
-
- if (interpolate && t > 0.0f) {
- result = (1.0f - t) * result + t * ramp[i + 1];
- }
-
- return result;
-}
-
-ccl_device float float_ramp_lookup(
- const float *ramp, float f, bool interpolate, bool extrapolate, int table_size)
-{
- if ((f < 0.0f || f > 1.0f) && extrapolate) {
- float t0, dy;
- if (f < 0.0f) {
- t0 = ramp[0];
- dy = t0 - ramp[1], f = -f;
- }
- else {
- t0 = ramp[table_size - 1];
- dy = t0 - ramp[table_size - 2];
- f = f - 1.0f;
- }
- return t0 + dy * f * (table_size - 1);
- }
-
- f = clamp(f, 0.0f, 1.0f) * (table_size - 1);
-
- /* clamp int as well in case of NaN */
- int i = clamp(float_to_int(f), 0, table_size - 1);
- float t = f - (float)i;
-
- float result = ramp[i];
-
- if (interpolate && t > 0.0f) {
- result = (1.0f - t) * result + t * ramp[i + 1];
- }
-
- return result;
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __SVM_RAMP_UTIL_H__ */
diff --git a/intern/cycles/kernel/svm/svm_sepcomb_hsv.h b/intern/cycles/kernel/svm/svm_sepcomb_hsv.h
deleted file mode 100644
index bafa0456342..00000000000
--- a/intern/cycles/kernel/svm/svm_sepcomb_hsv.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_noinline int svm_node_combine_hsv(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint hue_in,
- uint saturation_in,
- uint value_in,
- int offset)
-{
- uint4 node1 = read_node(kg, &offset);
- uint color_out = node1.y;
-
- float hue = stack_load_float(stack, hue_in);
- float saturation = stack_load_float(stack, saturation_in);
- float value = stack_load_float(stack, value_in);
-
- /* Combine, and convert back to RGB */
- float3 color = hsv_to_rgb(make_float3(hue, saturation, value));
-
- if (stack_valid(color_out))
- stack_store_float3(stack, color_out, color);
- return offset;
-}
-
-ccl_device_noinline int svm_node_separate_hsv(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint color_in,
- uint hue_out,
- uint saturation_out,
- int offset)
-{
- uint4 node1 = read_node(kg, &offset);
- uint value_out = node1.y;
-
- float3 color = stack_load_float3(stack, color_in);
-
- /* Convert to HSV */
- color = rgb_to_hsv(color);
-
- if (stack_valid(hue_out))
- stack_store_float(stack, hue_out, color.x);
- if (stack_valid(saturation_out))
- stack_store_float(stack, saturation_out, color.y);
- if (stack_valid(value_out))
- stack_store_float(stack, value_out, color.z);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_sepcomb_vector.h b/intern/cycles/kernel/svm/svm_sepcomb_vector.h
deleted file mode 100644
index 11e440f2cbf..00000000000
--- a/intern/cycles/kernel/svm/svm_sepcomb_vector.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2011-2014 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Vector combine / separate, used for the RGB and XYZ nodes */
-
-ccl_device void svm_node_combine_vector(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint in_offset,
- uint vector_index,
- uint out_offset)
-{
- float vector = stack_load_float(stack, in_offset);
-
- if (stack_valid(out_offset))
- stack_store_float(stack, out_offset + vector_index, vector);
-}
-
-ccl_device void svm_node_separate_vector(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint ivector_offset,
- uint vector_index,
- uint out_offset)
-{
- float3 vector = stack_load_float3(stack, ivector_offset);
-
- if (stack_valid(out_offset)) {
- if (vector_index == 0)
- stack_store_float(stack, out_offset, vector.x);
- else if (vector_index == 1)
- stack_store_float(stack, out_offset, vector.y);
- else
- stack_store_float(stack, out_offset, vector.z);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_sky.h b/intern/cycles/kernel/svm/svm_sky.h
deleted file mode 100644
index 3ab7bc89c66..00000000000
--- a/intern/cycles/kernel/svm/svm_sky.h
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Sky texture */
-
-ccl_device float sky_angle_between(float thetav, float phiv, float theta, float phi)
-{
- float cospsi = sinf(thetav) * sinf(theta) * cosf(phi - phiv) + cosf(thetav) * cosf(theta);
- return safe_acosf(cospsi);
-}
-
-/*
- * "A Practical Analytic Model for Daylight"
- * A. J. Preetham, Peter Shirley, Brian Smits
- */
-ccl_device float sky_perez_function(ccl_private float *lam, float theta, float gamma)
-{
- float ctheta = cosf(theta);
- float cgamma = cosf(gamma);
-
- return (1.0f + lam[0] * expf(lam[1] / ctheta)) *
- (1.0f + lam[2] * expf(lam[3] * gamma) + lam[4] * cgamma * cgamma);
-}
-
-ccl_device float3 sky_radiance_preetham(KernelGlobals kg,
- float3 dir,
- float sunphi,
- float suntheta,
- float radiance_x,
- float radiance_y,
- float radiance_z,
- ccl_private float *config_x,
- ccl_private float *config_y,
- ccl_private float *config_z)
-{
- /* convert vector to spherical coordinates */
- float2 spherical = direction_to_spherical(dir);
- float theta = spherical.x;
- float phi = spherical.y;
-
- /* angle between sun direction and dir */
- float gamma = sky_angle_between(theta, phi, suntheta, sunphi);
-
- /* clamp theta to horizon */
- theta = min(theta, M_PI_2_F - 0.001f);
-
- /* compute xyY color space values */
- float x = radiance_y * sky_perez_function(config_y, theta, gamma);
- float y = radiance_z * sky_perez_function(config_z, theta, gamma);
- float Y = radiance_x * sky_perez_function(config_x, theta, gamma);
-
- /* convert to RGB */
- float3 xyz = xyY_to_xyz(x, y, Y);
- return xyz_to_rgb(kg, xyz);
-}
-
-/*
- * "An Analytic Model for Full Spectral Sky-Dome Radiance"
- * Lukas Hosek, Alexander Wilkie
- */
-ccl_device float sky_radiance_internal(ccl_private float *configuration, float theta, float gamma)
-{
- float ctheta = cosf(theta);
- float cgamma = cosf(gamma);
-
- float expM = expf(configuration[4] * gamma);
- float rayM = cgamma * cgamma;
- float mieM = (1.0f + rayM) / powf((1.0f + configuration[8] * configuration[8] -
- 2.0f * configuration[8] * cgamma),
- 1.5f);
- float zenith = sqrtf(ctheta);
-
- return (1.0f + configuration[0] * expf(configuration[1] / (ctheta + 0.01f))) *
- (configuration[2] + configuration[3] * expM + configuration[5] * rayM +
- configuration[6] * mieM + configuration[7] * zenith);
-}
-
-ccl_device float3 sky_radiance_hosek(KernelGlobals kg,
- float3 dir,
- float sunphi,
- float suntheta,
- float radiance_x,
- float radiance_y,
- float radiance_z,
- ccl_private float *config_x,
- ccl_private float *config_y,
- ccl_private float *config_z)
-{
- /* convert vector to spherical coordinates */
- float2 spherical = direction_to_spherical(dir);
- float theta = spherical.x;
- float phi = spherical.y;
-
- /* angle between sun direction and dir */
- float gamma = sky_angle_between(theta, phi, suntheta, sunphi);
-
- /* clamp theta to horizon */
- theta = min(theta, M_PI_2_F - 0.001f);
-
- /* compute xyz color space values */
- float x = sky_radiance_internal(config_x, theta, gamma) * radiance_x;
- float y = sky_radiance_internal(config_y, theta, gamma) * radiance_y;
- float z = sky_radiance_internal(config_z, theta, gamma) * radiance_z;
-
- /* convert to RGB and adjust strength */
- return xyz_to_rgb(kg, make_float3(x, y, z)) * (M_2PI_F / 683);
-}
-
-/* Nishita improved sky model */
-ccl_device float3 geographical_to_direction(float lat, float lon)
-{
- return make_float3(cos(lat) * cos(lon), cos(lat) * sin(lon), sin(lat));
-}
-
-ccl_device float3 sky_radiance_nishita(KernelGlobals kg,
- float3 dir,
- ccl_private float *nishita_data,
- uint texture_id)
-{
- /* definitions */
- float sun_elevation = nishita_data[6];
- float sun_rotation = nishita_data[7];
- float angular_diameter = nishita_data[8];
- float sun_intensity = nishita_data[9];
- bool sun_disc = (angular_diameter >= 0.0f);
- float3 xyz;
- /* convert dir to spherical coordinates */
- float2 direction = direction_to_spherical(dir);
-
- /* render above the horizon */
- if (dir.z >= 0.0f) {
- /* definitions */
- float3 sun_dir = geographical_to_direction(sun_elevation, sun_rotation + M_PI_2_F);
- float sun_dir_angle = precise_angle(dir, sun_dir);
- float half_angular = angular_diameter / 2.0f;
- float dir_elevation = M_PI_2_F - direction.x;
-
- /* if ray inside sun disc render it, otherwise render sky */
- if (sun_disc && sun_dir_angle < half_angular) {
- /* get 2 pixels data */
- float3 pixel_bottom = make_float3(nishita_data[0], nishita_data[1], nishita_data[2]);
- float3 pixel_top = make_float3(nishita_data[3], nishita_data[4], nishita_data[5]);
- float y;
-
- /* sun interpolation */
- if (sun_elevation - half_angular > 0.0f) {
- if (sun_elevation + half_angular > 0.0f) {
- y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f;
- xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity;
- }
- }
- else {
- if (sun_elevation + half_angular > 0.0f) {
- y = dir_elevation / (sun_elevation + half_angular);
- xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity;
- }
- }
- /* limb darkening, coefficient is 0.6f */
- float limb_darkening = (1.0f -
- 0.6f * (1.0f - sqrtf(1.0f - sqr(sun_dir_angle / half_angular))));
- xyz *= limb_darkening;
- }
- /* sky */
- else {
- /* sky interpolation */
- float x = (direction.y + M_PI_F + sun_rotation) / M_2PI_F;
- /* more pixels toward horizon compensation */
- float y = safe_sqrtf(dir_elevation / M_PI_2_F);
- if (x > 1.0f) {
- x -= 1.0f;
- }
- xyz = float4_to_float3(kernel_tex_image_interp(kg, texture_id, x, y));
- }
- }
- /* ground */
- else {
- if (dir.z < -0.4f) {
- xyz = make_float3(0.0f, 0.0f, 0.0f);
- }
- else {
- /* black ground fade */
- float fade = 1.0f + dir.z * 2.5f;
- fade = sqr(fade) * fade;
- /* interpolation */
- float x = (direction.y + M_PI_F + sun_rotation) / M_2PI_F;
- if (x > 1.0f) {
- x -= 1.0f;
- }
- xyz = float4_to_float3(kernel_tex_image_interp(kg, texture_id, x, -0.5)) * fade;
- }
- }
-
- /* convert to RGB */
- return xyz_to_rgb(kg, xyz);
-}
-
-ccl_device_noinline int svm_node_tex_sky(
- KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
-{
- /* Load data */
- uint dir_offset = node.y;
- uint out_offset = node.z;
- int sky_model = node.w;
-
- float3 dir = stack_load_float3(stack, dir_offset);
- float3 f;
-
- /* Preetham and Hosek share the same data */
- if (sky_model == 0 || sky_model == 1) {
- /* Define variables */
- float sunphi, suntheta, radiance_x, radiance_y, radiance_z;
- float config_x[9], config_y[9], config_z[9];
-
- float4 data = read_node_float(kg, &offset);
- sunphi = data.x;
- suntheta = data.y;
- radiance_x = data.z;
- radiance_y = data.w;
-
- data = read_node_float(kg, &offset);
- radiance_z = data.x;
- config_x[0] = data.y;
- config_x[1] = data.z;
- config_x[2] = data.w;
-
- data = read_node_float(kg, &offset);
- config_x[3] = data.x;
- config_x[4] = data.y;
- config_x[5] = data.z;
- config_x[6] = data.w;
-
- data = read_node_float(kg, &offset);
- config_x[7] = data.x;
- config_x[8] = data.y;
- config_y[0] = data.z;
- config_y[1] = data.w;
-
- data = read_node_float(kg, &offset);
- config_y[2] = data.x;
- config_y[3] = data.y;
- config_y[4] = data.z;
- config_y[5] = data.w;
-
- data = read_node_float(kg, &offset);
- config_y[6] = data.x;
- config_y[7] = data.y;
- config_y[8] = data.z;
- config_z[0] = data.w;
-
- data = read_node_float(kg, &offset);
- config_z[1] = data.x;
- config_z[2] = data.y;
- config_z[3] = data.z;
- config_z[4] = data.w;
-
- data = read_node_float(kg, &offset);
- config_z[5] = data.x;
- config_z[6] = data.y;
- config_z[7] = data.z;
- config_z[8] = data.w;
-
- /* Compute Sky */
- if (sky_model == 0) {
- f = sky_radiance_preetham(kg,
- dir,
- sunphi,
- suntheta,
- radiance_x,
- radiance_y,
- radiance_z,
- config_x,
- config_y,
- config_z);
- }
- else {
- f = sky_radiance_hosek(kg,
- dir,
- sunphi,
- suntheta,
- radiance_x,
- radiance_y,
- radiance_z,
- config_x,
- config_y,
- config_z);
- }
- }
- /* Nishita */
- else {
- /* Define variables */
- float nishita_data[10];
-
- float4 data = read_node_float(kg, &offset);
- nishita_data[0] = data.x;
- nishita_data[1] = data.y;
- nishita_data[2] = data.z;
- nishita_data[3] = data.w;
-
- data = read_node_float(kg, &offset);
- nishita_data[4] = data.x;
- nishita_data[5] = data.y;
- nishita_data[6] = data.z;
- nishita_data[7] = data.w;
-
- data = read_node_float(kg, &offset);
- nishita_data[8] = data.x;
- nishita_data[9] = data.y;
- uint texture_id = __float_as_uint(data.z);
-
- /* Compute Sky */
- f = sky_radiance_nishita(kg, dir, nishita_data, texture_id);
- }
-
- stack_store_float3(stack, out_offset, f);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
deleted file mode 100644
index fe777eb34c8..00000000000
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "kernel/geom/geom.h"
-#include "kernel/kernel_camera.h"
-#include "kernel/kernel_montecarlo.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Texture Coordinate Node */
-
-ccl_device_noinline int svm_node_tex_coord(KernelGlobals kg,
- ccl_private ShaderData *sd,
- uint32_t path_flag,
- ccl_private float *stack,
- uint4 node,
- int offset)
-{
- float3 data;
- uint type = node.y;
- uint out_offset = node.z;
-
- switch (type) {
- case NODE_TEXCO_OBJECT: {
- data = sd->P;
- if (node.w == 0) {
- if (sd->object != OBJECT_NONE) {
- object_inverse_position_transform(kg, sd, &data);
- }
- }
- else {
- Transform tfm;
- tfm.x = read_node_float(kg, &offset);
- tfm.y = read_node_float(kg, &offset);
- tfm.z = read_node_float(kg, &offset);
- data = transform_point(&tfm, data);
- }
- break;
- }
- case NODE_TEXCO_NORMAL: {
- data = sd->N;
- object_inverse_normal_transform(kg, sd, &data);
- break;
- }
- case NODE_TEXCO_CAMERA: {
- Transform tfm = kernel_data.cam.worldtocamera;
-
- if (sd->object != OBJECT_NONE)
- data = transform_point(&tfm, sd->P);
- else
- data = transform_point(&tfm, sd->P + camera_position(kg));
- break;
- }
- case NODE_TEXCO_WINDOW: {
- if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
- kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
- data = camera_world_to_ndc(kg, sd, sd->ray_P);
- else
- data = camera_world_to_ndc(kg, sd, sd->P);
- data.z = 0.0f;
- break;
- }
- case NODE_TEXCO_REFLECTION: {
- if (sd->object != OBJECT_NONE)
- data = 2.0f * dot(sd->N, sd->I) * sd->N - sd->I;
- else
- data = sd->I;
- break;
- }
- case NODE_TEXCO_DUPLI_GENERATED: {
- data = object_dupli_generated(kg, sd->object);
- break;
- }
- case NODE_TEXCO_DUPLI_UV: {
- data = object_dupli_uv(kg, sd->object);
- break;
- }
- case NODE_TEXCO_VOLUME_GENERATED: {
- data = sd->P;
-
-#ifdef __VOLUME__
- if (sd->object != OBJECT_NONE)
- data = volume_normalized_position(kg, sd, data);
-#endif
- break;
- }
- }
-
- stack_store_float3(stack, out_offset, data);
- return offset;
-}
-
-ccl_device_noinline int svm_node_tex_coord_bump_dx(KernelGlobals kg,
- ccl_private ShaderData *sd,
- uint32_t path_flag,
- ccl_private float *stack,
- uint4 node,
- int offset)
-{
-#ifdef __RAY_DIFFERENTIALS__
- float3 data;
- uint type = node.y;
- uint out_offset = node.z;
-
- switch (type) {
- case NODE_TEXCO_OBJECT: {
- data = sd->P + sd->dP.dx;
- if (node.w == 0) {
- if (sd->object != OBJECT_NONE) {
- object_inverse_position_transform(kg, sd, &data);
- }
- }
- else {
- Transform tfm;
- tfm.x = read_node_float(kg, &offset);
- tfm.y = read_node_float(kg, &offset);
- tfm.z = read_node_float(kg, &offset);
- data = transform_point(&tfm, data);
- }
- break;
- }
- case NODE_TEXCO_NORMAL: {
- data = sd->N;
- object_inverse_normal_transform(kg, sd, &data);
- break;
- }
- case NODE_TEXCO_CAMERA: {
- Transform tfm = kernel_data.cam.worldtocamera;
-
- if (sd->object != OBJECT_NONE)
- data = transform_point(&tfm, sd->P + sd->dP.dx);
- else
- data = transform_point(&tfm, sd->P + sd->dP.dx + camera_position(kg));
- break;
- }
- case NODE_TEXCO_WINDOW: {
- if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
- kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
- data = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(sd->ray_dP, 0.0f, 0.0f));
- else
- data = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dx);
- data.z = 0.0f;
- break;
- }
- case NODE_TEXCO_REFLECTION: {
- if (sd->object != OBJECT_NONE)
- data = 2.0f * dot(sd->N, sd->I) * sd->N - sd->I;
- else
- data = sd->I;
- break;
- }
- case NODE_TEXCO_DUPLI_GENERATED: {
- data = object_dupli_generated(kg, sd->object);
- break;
- }
- case NODE_TEXCO_DUPLI_UV: {
- data = object_dupli_uv(kg, sd->object);
- break;
- }
- case NODE_TEXCO_VOLUME_GENERATED: {
- data = sd->P + sd->dP.dx;
-
-# ifdef __VOLUME__
- if (sd->object != OBJECT_NONE)
- data = volume_normalized_position(kg, sd, data);
-# endif
- break;
- }
- }
-
- stack_store_float3(stack, out_offset, data);
- return offset;
-#else
- return svm_node_tex_coord(kg, sd, path_flag, stack, node, offset);
-#endif
-}
-
-ccl_device_noinline int svm_node_tex_coord_bump_dy(KernelGlobals kg,
- ccl_private ShaderData *sd,
- uint32_t path_flag,
- ccl_private float *stack,
- uint4 node,
- int offset)
-{
-#ifdef __RAY_DIFFERENTIALS__
- float3 data;
- uint type = node.y;
- uint out_offset = node.z;
-
- switch (type) {
- case NODE_TEXCO_OBJECT: {
- data = sd->P + sd->dP.dy;
- if (node.w == 0) {
- if (sd->object != OBJECT_NONE) {
- object_inverse_position_transform(kg, sd, &data);
- }
- }
- else {
- Transform tfm;
- tfm.x = read_node_float(kg, &offset);
- tfm.y = read_node_float(kg, &offset);
- tfm.z = read_node_float(kg, &offset);
- data = transform_point(&tfm, data);
- }
- break;
- }
- case NODE_TEXCO_NORMAL: {
- data = sd->N;
- object_inverse_normal_transform(kg, sd, &data);
- break;
- }
- case NODE_TEXCO_CAMERA: {
- Transform tfm = kernel_data.cam.worldtocamera;
-
- if (sd->object != OBJECT_NONE)
- data = transform_point(&tfm, sd->P + sd->dP.dy);
- else
- data = transform_point(&tfm, sd->P + sd->dP.dy + camera_position(kg));
- break;
- }
- case NODE_TEXCO_WINDOW: {
- if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
- kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
- data = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(0.0f, sd->ray_dP, 0.0f));
- else
- data = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dy);
- data.z = 0.0f;
- break;
- }
- case NODE_TEXCO_REFLECTION: {
- if (sd->object != OBJECT_NONE)
- data = 2.0f * dot(sd->N, sd->I) * sd->N - sd->I;
- else
- data = sd->I;
- break;
- }
- case NODE_TEXCO_DUPLI_GENERATED: {
- data = object_dupli_generated(kg, sd->object);
- break;
- }
- case NODE_TEXCO_DUPLI_UV: {
- data = object_dupli_uv(kg, sd->object);
- break;
- }
- case NODE_TEXCO_VOLUME_GENERATED: {
- data = sd->P + sd->dP.dy;
-
-# ifdef __VOLUME__
- if (sd->object != OBJECT_NONE)
- data = volume_normalized_position(kg, sd, data);
-# endif
- break;
- }
- }
-
- stack_store_float3(stack, out_offset, data);
- return offset;
-#else
- return svm_node_tex_coord(kg, sd, path_flag, stack, node, offset);
-#endif
-}
-
-ccl_device_noinline void svm_node_normal_map(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint color_offset, strength_offset, normal_offset, space;
- svm_unpack_node_uchar4(node.y, &color_offset, &strength_offset, &normal_offset, &space);
-
- float3 color = stack_load_float3(stack, color_offset);
- color = 2.0f * make_float3(color.x - 0.5f, color.y - 0.5f, color.z - 0.5f);
-
- bool is_backfacing = (sd->flag & SD_BACKFACING) != 0;
- float3 N;
-
- if (space == NODE_NORMAL_MAP_TANGENT) {
- /* tangent space */
- if (sd->object == OBJECT_NONE || (sd->type & PRIMITIVE_ALL_TRIANGLE) == 0) {
- /* Fallback to unperturbed normal. */
- stack_store_float3(stack, normal_offset, sd->N);
- return;
- }
-
- /* first try to get tangent attribute */
- const AttributeDescriptor attr = find_attribute(kg, sd, node.z);
- const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.w);
-
- if (attr.offset == ATTR_STD_NOT_FOUND || attr_sign.offset == ATTR_STD_NOT_FOUND) {
- /* Fallback to unperturbed normal. */
- stack_store_float3(stack, normal_offset, sd->N);
- return;
- }
-
- /* get _unnormalized_ interpolated normal and tangent */
- float3 tangent = primitive_surface_attribute_float3(kg, sd, attr, NULL, NULL);
- float sign = primitive_surface_attribute_float(kg, sd, attr_sign, NULL, NULL);
- float3 normal;
-
- if (sd->shader & SHADER_SMOOTH_NORMAL) {
- normal = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
- }
- else {
- normal = sd->Ng;
-
- /* the normal is already inverted, which is too soon for the math here */
- if (is_backfacing) {
- normal = -normal;
- }
-
- object_inverse_normal_transform(kg, sd, &normal);
- }
-
- /* apply normal map */
- float3 B = sign * cross(normal, tangent);
- N = safe_normalize(color.x * tangent + color.y * B + color.z * normal);
-
- /* transform to world space */
- object_normal_transform(kg, sd, &N);
- }
- else {
- /* strange blender convention */
- if (space == NODE_NORMAL_MAP_BLENDER_OBJECT || space == NODE_NORMAL_MAP_BLENDER_WORLD) {
- color.y = -color.y;
- color.z = -color.z;
- }
-
- /* object, world space */
- N = color;
-
- if (space == NODE_NORMAL_MAP_OBJECT || space == NODE_NORMAL_MAP_BLENDER_OBJECT)
- object_normal_transform(kg, sd, &N);
- else
- N = safe_normalize(N);
- }
-
- /* invert normal for backfacing polygons */
- if (is_backfacing) {
- N = -N;
- }
-
- float strength = stack_load_float(stack, strength_offset);
-
- if (strength != 1.0f) {
- strength = max(strength, 0.0f);
- N = safe_normalize(sd->N + (N - sd->N) * strength);
- }
-
- if (is_zero(N)) {
- N = sd->N;
- }
-
- stack_store_float3(stack, normal_offset, N);
-}
-
-ccl_device_noinline void svm_node_tangent(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint tangent_offset, direction_type, axis;
- svm_unpack_node_uchar3(node.y, &tangent_offset, &direction_type, &axis);
-
- float3 tangent;
- float3 attribute_value;
- const AttributeDescriptor desc = find_attribute(kg, sd, node.z);
- if (desc.offset != ATTR_STD_NOT_FOUND) {
- if (desc.type == NODE_ATTR_FLOAT2) {
- float2 value = primitive_surface_attribute_float2(kg, sd, desc, NULL, NULL);
- attribute_value.x = value.x;
- attribute_value.y = value.y;
- attribute_value.z = 0.0f;
- }
- else {
- attribute_value = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
- }
- }
-
- if (direction_type == NODE_TANGENT_UVMAP) {
- /* UV map */
- if (desc.offset == ATTR_STD_NOT_FOUND) {
- stack_store_float3(stack, tangent_offset, zero_float3());
- return;
- }
- else {
- tangent = attribute_value;
- }
- }
- else {
- /* radial */
- float3 generated;
-
- if (desc.offset == ATTR_STD_NOT_FOUND)
- generated = sd->P;
- else
- generated = attribute_value;
-
- if (axis == NODE_TANGENT_AXIS_X)
- tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f));
- else if (axis == NODE_TANGENT_AXIS_Y)
- tangent = make_float3(-(generated.z - 0.5f), 0.0f, (generated.x - 0.5f));
- else
- tangent = make_float3(-(generated.y - 0.5f), (generated.x - 0.5f), 0.0f);
- }
-
- object_normal_transform(kg, sd, &tangent);
- tangent = cross(sd->N, normalize(cross(tangent, sd->N)));
- stack_store_float3(stack, tangent_offset, tangent);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
deleted file mode 100644
index 6f6c101fb69..00000000000
--- a/intern/cycles/kernel/svm/svm_types.h
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SVM_TYPES_H__
-#define __SVM_TYPES_H__
-
-CCL_NAMESPACE_BEGIN
-
-/* Stack */
-
-/* SVM stack has a fixed size */
-#define SVM_STACK_SIZE 255
-/* SVM stack offsets with this value indicate that it's not on the stack */
-#define SVM_STACK_INVALID 255
-
-#define SVM_BUMP_EVAL_STATE_SIZE 9
-
-/* Nodes */
-
-typedef enum ShaderNodeType {
- NODE_END = 0,
- NODE_SHADER_JUMP,
- NODE_CLOSURE_BSDF,
- NODE_CLOSURE_EMISSION,
- NODE_CLOSURE_BACKGROUND,
- NODE_CLOSURE_SET_WEIGHT,
- NODE_CLOSURE_WEIGHT,
- NODE_EMISSION_WEIGHT,
- NODE_MIX_CLOSURE,
- NODE_JUMP_IF_ZERO,
- NODE_JUMP_IF_ONE,
- NODE_GEOMETRY,
- NODE_CONVERT,
- NODE_TEX_COORD,
- NODE_VALUE_F,
- NODE_VALUE_V,
- NODE_ATTR,
- NODE_VERTEX_COLOR,
- NODE_GEOMETRY_BUMP_DX,
- NODE_GEOMETRY_BUMP_DY,
- NODE_SET_DISPLACEMENT,
- NODE_DISPLACEMENT,
- NODE_VECTOR_DISPLACEMENT,
- NODE_TEX_IMAGE,
- NODE_TEX_IMAGE_BOX,
- NODE_TEX_NOISE,
- NODE_SET_BUMP,
- NODE_ATTR_BUMP_DX,
- NODE_ATTR_BUMP_DY,
- NODE_VERTEX_COLOR_BUMP_DX,
- NODE_VERTEX_COLOR_BUMP_DY,
- NODE_TEX_COORD_BUMP_DX,
- NODE_TEX_COORD_BUMP_DY,
- NODE_CLOSURE_SET_NORMAL,
- NODE_ENTER_BUMP_EVAL,
- NODE_LEAVE_BUMP_EVAL,
- NODE_HSV,
- NODE_CLOSURE_HOLDOUT,
- NODE_FRESNEL,
- NODE_LAYER_WEIGHT,
- NODE_CLOSURE_VOLUME,
- NODE_PRINCIPLED_VOLUME,
- NODE_MATH,
- NODE_VECTOR_MATH,
- NODE_RGB_RAMP,
- NODE_GAMMA,
- NODE_BRIGHTCONTRAST,
- NODE_LIGHT_PATH,
- NODE_OBJECT_INFO,
- NODE_PARTICLE_INFO,
- NODE_HAIR_INFO,
- NODE_TEXTURE_MAPPING,
- NODE_MAPPING,
- NODE_MIN_MAX,
- NODE_CAMERA,
- NODE_TEX_ENVIRONMENT,
- NODE_TEX_SKY,
- NODE_TEX_GRADIENT,
- NODE_TEX_VORONOI,
- NODE_TEX_MUSGRAVE,
- NODE_TEX_WAVE,
- NODE_TEX_MAGIC,
- NODE_TEX_CHECKER,
- NODE_TEX_BRICK,
- NODE_TEX_WHITE_NOISE,
- NODE_NORMAL,
- NODE_LIGHT_FALLOFF,
- NODE_IES,
- NODE_RGB_CURVES,
- NODE_VECTOR_CURVES,
- NODE_TANGENT,
- NODE_NORMAL_MAP,
- NODE_INVERT,
- NODE_MIX,
- NODE_SEPARATE_VECTOR,
- NODE_COMBINE_VECTOR,
- NODE_SEPARATE_HSV,
- NODE_COMBINE_HSV,
- NODE_VECTOR_ROTATE,
- NODE_VECTOR_TRANSFORM,
- NODE_WIREFRAME,
- NODE_WAVELENGTH,
- NODE_BLACKBODY,
- NODE_MAP_RANGE,
- NODE_CLAMP,
- NODE_BEVEL,
- NODE_AMBIENT_OCCLUSION,
- NODE_TEX_VOXEL,
- NODE_AOV_START,
- NODE_AOV_COLOR,
- NODE_AOV_VALUE,
- NODE_FLOAT_CURVE,
- /* NOTE: for best OpenCL performance, item definition in the enum must
- * match the switch case order in svm.h. */
-} ShaderNodeType;
-
-typedef enum NodeAttributeOutputType {
- NODE_ATTR_OUTPUT_FLOAT3 = 0,
- NODE_ATTR_OUTPUT_FLOAT,
- NODE_ATTR_OUTPUT_FLOAT_ALPHA,
-} NodeAttributeOutputType;
-
-typedef enum NodeAttributeType {
- NODE_ATTR_FLOAT = 0,
- NODE_ATTR_FLOAT2,
- NODE_ATTR_FLOAT3,
- NODE_ATTR_FLOAT4,
- NODE_ATTR_RGBA,
- NODE_ATTR_MATRIX
-} NodeAttributeType;
-
-typedef enum NodeGeometry {
- NODE_GEOM_P = 0,
- NODE_GEOM_N,
- NODE_GEOM_T,
- NODE_GEOM_I,
- NODE_GEOM_Ng,
- NODE_GEOM_uv
-} NodeGeometry;
-
-typedef enum NodeObjectInfo {
- NODE_INFO_OB_LOCATION,
- NODE_INFO_OB_COLOR,
- NODE_INFO_OB_INDEX,
- NODE_INFO_MAT_INDEX,
- NODE_INFO_OB_RANDOM
-} NodeObjectInfo;
-
-typedef enum NodeParticleInfo {
- NODE_INFO_PAR_INDEX,
- NODE_INFO_PAR_RANDOM,
- NODE_INFO_PAR_AGE,
- NODE_INFO_PAR_LIFETIME,
- NODE_INFO_PAR_LOCATION,
- NODE_INFO_PAR_ROTATION,
- NODE_INFO_PAR_SIZE,
- NODE_INFO_PAR_VELOCITY,
- NODE_INFO_PAR_ANGULAR_VELOCITY
-} NodeParticleInfo;
-
-typedef enum NodeHairInfo {
- NODE_INFO_CURVE_IS_STRAND,
- NODE_INFO_CURVE_INTERCEPT,
- NODE_INFO_CURVE_LENGTH,
- NODE_INFO_CURVE_THICKNESS,
- /* Fade for minimum hair width transiency. */
- // NODE_INFO_CURVE_FADE,
- NODE_INFO_CURVE_TANGENT_NORMAL,
- NODE_INFO_CURVE_RANDOM,
-} NodeHairInfo;
-
-typedef enum NodeLightPath {
- NODE_LP_camera = 0,
- NODE_LP_shadow,
- NODE_LP_diffuse,
- NODE_LP_glossy,
- NODE_LP_singular,
- NODE_LP_reflection,
- NODE_LP_transmission,
- NODE_LP_volume_scatter,
- NODE_LP_backfacing,
- NODE_LP_ray_length,
- NODE_LP_ray_depth,
- NODE_LP_ray_diffuse,
- NODE_LP_ray_glossy,
- NODE_LP_ray_transparent,
- NODE_LP_ray_transmission,
-} NodeLightPath;
-
-typedef enum NodeLightFalloff {
- NODE_LIGHT_FALLOFF_QUADRATIC,
- NODE_LIGHT_FALLOFF_LINEAR,
- NODE_LIGHT_FALLOFF_CONSTANT
-} NodeLightFalloff;
-
-typedef enum NodeTexCoord {
- NODE_TEXCO_NORMAL,
- NODE_TEXCO_OBJECT,
- NODE_TEXCO_CAMERA,
- NODE_TEXCO_WINDOW,
- NODE_TEXCO_REFLECTION,
- NODE_TEXCO_DUPLI_GENERATED,
- NODE_TEXCO_DUPLI_UV,
- NODE_TEXCO_VOLUME_GENERATED
-} NodeTexCoord;
-
-typedef enum NodeMix {
- NODE_MIX_BLEND = 0,
- NODE_MIX_ADD,
- NODE_MIX_MUL,
- NODE_MIX_SUB,
- NODE_MIX_SCREEN,
- NODE_MIX_DIV,
- NODE_MIX_DIFF,
- NODE_MIX_DARK,
- NODE_MIX_LIGHT,
- NODE_MIX_OVERLAY,
- NODE_MIX_DODGE,
- NODE_MIX_BURN,
- NODE_MIX_HUE,
- NODE_MIX_SAT,
- NODE_MIX_VAL,
- NODE_MIX_COLOR,
- NODE_MIX_SOFT,
- NODE_MIX_LINEAR,
- NODE_MIX_CLAMP /* used for the clamp UI option */
-} NodeMix;
-
-typedef enum NodeMathType {
- NODE_MATH_ADD,
- NODE_MATH_SUBTRACT,
- NODE_MATH_MULTIPLY,
- NODE_MATH_DIVIDE,
- NODE_MATH_SINE,
- NODE_MATH_COSINE,
- NODE_MATH_TANGENT,
- NODE_MATH_ARCSINE,
- NODE_MATH_ARCCOSINE,
- NODE_MATH_ARCTANGENT,
- NODE_MATH_POWER,
- NODE_MATH_LOGARITHM,
- NODE_MATH_MINIMUM,
- NODE_MATH_MAXIMUM,
- NODE_MATH_ROUND,
- NODE_MATH_LESS_THAN,
- NODE_MATH_GREATER_THAN,
- NODE_MATH_MODULO,
- NODE_MATH_ABSOLUTE,
- NODE_MATH_ARCTAN2,
- NODE_MATH_FLOOR,
- NODE_MATH_CEIL,
- NODE_MATH_FRACTION,
- NODE_MATH_SQRT,
- NODE_MATH_INV_SQRT,
- NODE_MATH_SIGN,
- NODE_MATH_EXPONENT,
- NODE_MATH_RADIANS,
- NODE_MATH_DEGREES,
- NODE_MATH_SINH,
- NODE_MATH_COSH,
- NODE_MATH_TANH,
- NODE_MATH_TRUNC,
- NODE_MATH_SNAP,
- NODE_MATH_WRAP,
- NODE_MATH_COMPARE,
- NODE_MATH_MULTIPLY_ADD,
- NODE_MATH_PINGPONG,
- NODE_MATH_SMOOTH_MIN,
- NODE_MATH_SMOOTH_MAX,
-} NodeMathType;
-
-typedef enum NodeVectorMathType {
- NODE_VECTOR_MATH_ADD,
- NODE_VECTOR_MATH_SUBTRACT,
- NODE_VECTOR_MATH_MULTIPLY,
- NODE_VECTOR_MATH_DIVIDE,
-
- NODE_VECTOR_MATH_CROSS_PRODUCT,
- NODE_VECTOR_MATH_PROJECT,
- NODE_VECTOR_MATH_REFLECT,
- NODE_VECTOR_MATH_DOT_PRODUCT,
-
- NODE_VECTOR_MATH_DISTANCE,
- NODE_VECTOR_MATH_LENGTH,
- NODE_VECTOR_MATH_SCALE,
- NODE_VECTOR_MATH_NORMALIZE,
-
- NODE_VECTOR_MATH_SNAP,
- NODE_VECTOR_MATH_FLOOR,
- NODE_VECTOR_MATH_CEIL,
- NODE_VECTOR_MATH_MODULO,
- NODE_VECTOR_MATH_FRACTION,
- NODE_VECTOR_MATH_ABSOLUTE,
- NODE_VECTOR_MATH_MINIMUM,
- NODE_VECTOR_MATH_MAXIMUM,
- NODE_VECTOR_MATH_WRAP,
- NODE_VECTOR_MATH_SINE,
- NODE_VECTOR_MATH_COSINE,
- NODE_VECTOR_MATH_TANGENT,
- NODE_VECTOR_MATH_REFRACT,
- NODE_VECTOR_MATH_FACEFORWARD,
- NODE_VECTOR_MATH_MULTIPLY_ADD,
-} NodeVectorMathType;
-
-typedef enum NodeClampType {
- NODE_CLAMP_MINMAX,
- NODE_CLAMP_RANGE,
-} NodeClampType;
-
-typedef enum NodeMapRangeType {
- NODE_MAP_RANGE_LINEAR,
- NODE_MAP_RANGE_STEPPED,
- NODE_MAP_RANGE_SMOOTHSTEP,
- NODE_MAP_RANGE_SMOOTHERSTEP,
-} NodeMapRangeType;
-
-typedef enum NodeMappingType {
- NODE_MAPPING_TYPE_POINT,
- NODE_MAPPING_TYPE_TEXTURE,
- NODE_MAPPING_TYPE_VECTOR,
- NODE_MAPPING_TYPE_NORMAL
-} NodeMappingType;
-
-typedef enum NodeVectorRotateType {
- NODE_VECTOR_ROTATE_TYPE_AXIS,
- NODE_VECTOR_ROTATE_TYPE_AXIS_X,
- NODE_VECTOR_ROTATE_TYPE_AXIS_Y,
- NODE_VECTOR_ROTATE_TYPE_AXIS_Z,
- NODE_VECTOR_ROTATE_TYPE_EULER_XYZ,
-} NodeVectorRotateType;
-
-typedef enum NodeVectorTransformType {
- NODE_VECTOR_TRANSFORM_TYPE_VECTOR,
- NODE_VECTOR_TRANSFORM_TYPE_POINT,
- NODE_VECTOR_TRANSFORM_TYPE_NORMAL
-} NodeVectorTransformType;
-
-typedef enum NodeVectorTransformConvertSpace {
- NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD,
- NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT,
- NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA
-} NodeVectorTransformConvertSpace;
-
-typedef enum NodeConvert {
- NODE_CONVERT_FV,
- NODE_CONVERT_FI,
- NODE_CONVERT_CF,
- NODE_CONVERT_CI,
- NODE_CONVERT_VF,
- NODE_CONVERT_VI,
- NODE_CONVERT_IF,
- NODE_CONVERT_IV
-} NodeConvert;
-
-typedef enum NodeMusgraveType {
- NODE_MUSGRAVE_MULTIFRACTAL,
- NODE_MUSGRAVE_FBM,
- NODE_MUSGRAVE_HYBRID_MULTIFRACTAL,
- NODE_MUSGRAVE_RIDGED_MULTIFRACTAL,
- NODE_MUSGRAVE_HETERO_TERRAIN
-} NodeMusgraveType;
-
-typedef enum NodeWaveType { NODE_WAVE_BANDS, NODE_WAVE_RINGS } NodeWaveType;
-
-typedef enum NodeWaveBandsDirection {
- NODE_WAVE_BANDS_DIRECTION_X,
- NODE_WAVE_BANDS_DIRECTION_Y,
- NODE_WAVE_BANDS_DIRECTION_Z,
- NODE_WAVE_BANDS_DIRECTION_DIAGONAL
-} NodeWaveBandsDirection;
-
-typedef enum NodeWaveRingsDirection {
- NODE_WAVE_RINGS_DIRECTION_X,
- NODE_WAVE_RINGS_DIRECTION_Y,
- NODE_WAVE_RINGS_DIRECTION_Z,
- NODE_WAVE_RINGS_DIRECTION_SPHERICAL
-} NodeWaveRingsDirection;
-
-typedef enum NodeWaveProfile {
- NODE_WAVE_PROFILE_SIN,
- NODE_WAVE_PROFILE_SAW,
- NODE_WAVE_PROFILE_TRI,
-} NodeWaveProfile;
-
-typedef enum NodeSkyType { NODE_SKY_PREETHAM, NODE_SKY_HOSEK, NODE_SKY_NISHITA } NodeSkyType;
-
-typedef enum NodeGradientType {
- NODE_BLEND_LINEAR,
- NODE_BLEND_QUADRATIC,
- NODE_BLEND_EASING,
- NODE_BLEND_DIAGONAL,
- NODE_BLEND_RADIAL,
- NODE_BLEND_QUADRATIC_SPHERE,
- NODE_BLEND_SPHERICAL
-} NodeGradientType;
-
-typedef enum NodeVoronoiDistanceMetric {
- NODE_VORONOI_EUCLIDEAN,
- NODE_VORONOI_MANHATTAN,
- NODE_VORONOI_CHEBYCHEV,
- NODE_VORONOI_MINKOWSKI,
-} NodeVoronoiDistanceMetric;
-
-typedef enum NodeVoronoiFeature {
- NODE_VORONOI_F1,
- NODE_VORONOI_F2,
- NODE_VORONOI_SMOOTH_F1,
- NODE_VORONOI_DISTANCE_TO_EDGE,
- NODE_VORONOI_N_SPHERE_RADIUS,
-} NodeVoronoiFeature;
-
-typedef enum NodeBlendWeightType {
- NODE_LAYER_WEIGHT_FRESNEL,
- NODE_LAYER_WEIGHT_FACING
-} NodeBlendWeightType;
-
-typedef enum NodeTangentDirectionType {
- NODE_TANGENT_RADIAL,
- NODE_TANGENT_UVMAP
-} NodeTangentDirectionType;
-
-typedef enum NodeTangentAxis {
- NODE_TANGENT_AXIS_X,
- NODE_TANGENT_AXIS_Y,
- NODE_TANGENT_AXIS_Z
-} NodeTangentAxis;
-
-typedef enum NodeNormalMapSpace {
- NODE_NORMAL_MAP_TANGENT,
- NODE_NORMAL_MAP_OBJECT,
- NODE_NORMAL_MAP_WORLD,
- NODE_NORMAL_MAP_BLENDER_OBJECT,
- NODE_NORMAL_MAP_BLENDER_WORLD,
-} NodeNormalMapSpace;
-
-typedef enum NodeImageProjection {
- NODE_IMAGE_PROJ_FLAT = 0,
- NODE_IMAGE_PROJ_BOX = 1,
- NODE_IMAGE_PROJ_SPHERE = 2,
- NODE_IMAGE_PROJ_TUBE = 3,
-} NodeImageProjection;
-
-typedef enum NodeImageFlags {
- NODE_IMAGE_COMPRESS_AS_SRGB = 1,
- NODE_IMAGE_ALPHA_UNASSOCIATE = 2,
-} NodeImageFlags;
-
-typedef enum NodeEnvironmentProjection {
- NODE_ENVIRONMENT_EQUIRECTANGULAR = 0,
- NODE_ENVIRONMENT_MIRROR_BALL = 1,
-} NodeEnvironmentProjection;
-
-typedef enum NodeBumpOffset {
- NODE_BUMP_OFFSET_CENTER,
- NODE_BUMP_OFFSET_DX,
- NODE_BUMP_OFFSET_DY,
-} NodeBumpOffset;
-
-typedef enum NodeTexVoxelSpace {
- NODE_TEX_VOXEL_SPACE_OBJECT = 0,
- NODE_TEX_VOXEL_SPACE_WORLD = 1,
-} NodeTexVoxelSpace;
-
-typedef enum NodeAO {
- NODE_AO_ONLY_LOCAL = (1 << 0),
- NODE_AO_INSIDE = (1 << 1),
- NODE_AO_GLOBAL_RADIUS = (1 << 2),
-} NodeAO;
-
-typedef enum ShaderType {
- SHADER_TYPE_SURFACE,
- SHADER_TYPE_VOLUME,
- SHADER_TYPE_DISPLACEMENT,
- SHADER_TYPE_BUMP,
-} ShaderType;
-
-typedef enum NodePrincipledHairParametrization {
- NODE_PRINCIPLED_HAIR_REFLECTANCE = 0,
- NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION = 1,
- NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION = 2,
- NODE_PRINCIPLED_HAIR_NUM,
-} NodePrincipledHairParametrization;
-
-/* Closure */
-
-typedef enum ClosureType {
- /* Special type, flags generic node as a non-BSDF. */
- CLOSURE_NONE_ID,
-
- CLOSURE_BSDF_ID,
-
- /* Diffuse */
- CLOSURE_BSDF_DIFFUSE_ID,
- CLOSURE_BSDF_OREN_NAYAR_ID,
- CLOSURE_BSDF_DIFFUSE_RAMP_ID,
- CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID,
- CLOSURE_BSDF_PRINCIPLED_SHEEN_ID,
- CLOSURE_BSDF_DIFFUSE_TOON_ID,
- CLOSURE_BSDF_TRANSLUCENT_ID,
-
- /* Glossy */
- CLOSURE_BSDF_REFLECTION_ID,
- CLOSURE_BSDF_MICROFACET_GGX_ID,
- CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID,
- CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID,
- CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
- CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID,
- CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID,
- CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID,
- CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
- CLOSURE_BSDF_PHONG_RAMP_ID,
- CLOSURE_BSDF_GLOSSY_TOON_ID,
- CLOSURE_BSDF_HAIR_REFLECTION_ID,
-
- /* Transmission */
- CLOSURE_BSDF_REFRACTION_ID,
- CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID,
- CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
- CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID,
- CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
- CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
- CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID,
- CLOSURE_BSDF_SHARP_GLASS_ID,
- CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
- CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
-
- /* Special cases */
- CLOSURE_BSDF_TRANSPARENT_ID,
-
- /* BSSRDF */
- CLOSURE_BSSRDF_BURLEY_ID,
- CLOSURE_BSSRDF_RANDOM_WALK_ID,
- CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID,
-
- /* Other */
- CLOSURE_HOLDOUT_ID,
-
- /* Volume */
- CLOSURE_VOLUME_ID,
- CLOSURE_VOLUME_ABSORPTION_ID,
- CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID,
-
- CLOSURE_BSDF_PRINCIPLED_ID,
-
- NBUILTIN_CLOSURES
-} ClosureType;
-
-/* watch this, being lazy with memory usage */
-#define CLOSURE_IS_BSDF(type) (type <= CLOSURE_BSDF_TRANSPARENT_ID)
-#define CLOSURE_IS_BSDF_DIFFUSE(type) \
- (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_TRANSLUCENT_ID)
-#define CLOSURE_IS_BSDF_GLOSSY(type) \
- ((type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID) || \
- (type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID))
-#define CLOSURE_IS_BSDF_TRANSMISSION(type) \
- (type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
-#define CLOSURE_IS_BSDF_SINGULAR(type) \
- (type == CLOSURE_BSDF_REFLECTION_ID || type == CLOSURE_BSDF_REFRACTION_ID || \
- type == CLOSURE_BSDF_TRANSPARENT_ID)
-#define CLOSURE_IS_BSDF_TRANSPARENT(type) (type == CLOSURE_BSDF_TRANSPARENT_ID)
-#define CLOSURE_IS_BSDF_MULTISCATTER(type) \
- (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID || \
- type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
-#define CLOSURE_IS_BSDF_MICROFACET(type) \
- ((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
- (type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
- type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) || \
- (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID))
-#define CLOSURE_IS_BSDF_MICROFACET_FRESNEL(type) \
- (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID || \
- type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID || \
- type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID || \
- type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID)
-#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
-#define CLOSURE_IS_BSSRDF(type) \
- (type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
-#define CLOSURE_IS_VOLUME(type) \
- (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
-#define CLOSURE_IS_VOLUME_SCATTER(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
-#define CLOSURE_IS_VOLUME_ABSORPTION(type) (type == CLOSURE_VOLUME_ABSORPTION_ID)
-#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
-#define CLOSURE_IS_PHASE(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
-#define CLOSURE_IS_GLASS(type) \
- (type >= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID)
-#define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID)
-
-#define CLOSURE_WEIGHT_CUTOFF 1e-5f
-
-CCL_NAMESPACE_END
-
-#endif /* __SVM_TYPES_H__ */
diff --git a/intern/cycles/kernel/svm/svm_value.h b/intern/cycles/kernel/svm/svm_value.h
deleted file mode 100644
index cc72961d0f6..00000000000
--- a/intern/cycles/kernel/svm/svm_value.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Value Nodes */
-
-ccl_device void svm_node_value_f(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint ivalue,
- uint out_offset)
-{
- stack_store_float(stack, out_offset, __uint_as_float(ivalue));
-}
-
-ccl_device int svm_node_value_v(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint out_offset,
- int offset)
-{
- /* read extra data */
- uint4 node1 = read_node(kg, &offset);
- float3 p = make_float3(
- __uint_as_float(node1.y), __uint_as_float(node1.z), __uint_as_float(node1.w));
-
- stack_store_float3(stack, out_offset, p);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_vector_rotate.h b/intern/cycles/kernel/svm/svm_vector_rotate.h
deleted file mode 100644
index c20f9b2556f..00000000000
--- a/intern/cycles/kernel/svm/svm_vector_rotate.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Vector Rotate */
-
-ccl_device_noinline void svm_node_vector_rotate(ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint input_stack_offsets,
- uint axis_stack_offsets,
- uint result_stack_offset)
-{
- uint type, vector_stack_offset, rotation_stack_offset, center_stack_offset, axis_stack_offset,
- angle_stack_offset, invert;
-
- svm_unpack_node_uchar4(
- input_stack_offsets, &type, &vector_stack_offset, &rotation_stack_offset, &invert);
- svm_unpack_node_uchar3(
- axis_stack_offsets, &center_stack_offset, &axis_stack_offset, &angle_stack_offset);
-
- if (stack_valid(result_stack_offset)) {
-
- float3 vector = stack_load_float3(stack, vector_stack_offset);
- float3 center = stack_load_float3(stack, center_stack_offset);
- float3 result = make_float3(0.0f, 0.0f, 0.0f);
-
- if (type == NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
- float3 rotation = stack_load_float3(stack, rotation_stack_offset); // Default XYZ.
- Transform rotationTransform = euler_to_transform(rotation);
- if (invert) {
- result = transform_direction_transposed(&rotationTransform, vector - center) + center;
- }
- else {
- result = transform_direction(&rotationTransform, vector - center) + center;
- }
- }
- else {
- float3 axis;
- float axis_length;
- switch (type) {
- case NODE_VECTOR_ROTATE_TYPE_AXIS_X:
- axis = make_float3(1.0f, 0.0f, 0.0f);
- axis_length = 1.0f;
- break;
- case NODE_VECTOR_ROTATE_TYPE_AXIS_Y:
- axis = make_float3(0.0f, 1.0f, 0.0f);
- axis_length = 1.0f;
- break;
- case NODE_VECTOR_ROTATE_TYPE_AXIS_Z:
- axis = make_float3(0.0f, 0.0f, 1.0f);
- axis_length = 1.0f;
- break;
- default:
- axis = stack_load_float3(stack, axis_stack_offset);
- axis_length = len(axis);
- break;
- }
- float angle = stack_load_float(stack, angle_stack_offset);
- angle = invert ? -angle : angle;
- result = (axis_length != 0.0f) ?
- rotate_around_axis(vector - center, axis / axis_length, angle) + center :
- vector;
- }
-
- stack_store_float3(stack, result_stack_offset, result);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_vector_transform.h b/intern/cycles/kernel/svm/svm_vector_transform.h
deleted file mode 100644
index 4e0d36647da..00000000000
--- a/intern/cycles/kernel/svm/svm_vector_transform.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Vector Transform */
-
-ccl_device_noinline void svm_node_vector_transform(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint itype, ifrom, ito;
- uint vector_in, vector_out;
-
- svm_unpack_node_uchar3(node.y, &itype, &ifrom, &ito);
- svm_unpack_node_uchar2(node.z, &vector_in, &vector_out);
-
- float3 in = stack_load_float3(stack, vector_in);
-
- NodeVectorTransformType type = (NodeVectorTransformType)itype;
- NodeVectorTransformConvertSpace from = (NodeVectorTransformConvertSpace)ifrom;
- NodeVectorTransformConvertSpace to = (NodeVectorTransformConvertSpace)ito;
-
- Transform tfm;
- bool is_object = (sd->object != OBJECT_NONE);
- bool is_direction = (type == NODE_VECTOR_TRANSFORM_TYPE_VECTOR ||
- type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
-
- /* From world */
- if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD) {
- if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
- tfm = kernel_data.cam.worldtocamera;
- if (is_direction)
- in = transform_direction(&tfm, in);
- else
- in = transform_point(&tfm, in);
- }
- else if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT && is_object) {
- if (is_direction)
- object_inverse_dir_transform(kg, sd, &in);
- else
- object_inverse_position_transform(kg, sd, &in);
- }
- }
-
- /* From camera */
- else if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
- if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD ||
- to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT) {
- tfm = kernel_data.cam.cameratoworld;
- if (is_direction)
- in = transform_direction(&tfm, in);
- else
- in = transform_point(&tfm, in);
- }
- if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT && is_object) {
- if (is_direction)
- object_inverse_dir_transform(kg, sd, &in);
- else
- object_inverse_position_transform(kg, sd, &in);
- }
- }
-
- /* From object */
- else if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT) {
- if ((to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD ||
- to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) &&
- is_object) {
- if (is_direction)
- object_dir_transform(kg, sd, &in);
- else
- object_position_transform(kg, sd, &in);
- }
- if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
- tfm = kernel_data.cam.worldtocamera;
- if (is_direction)
- in = transform_direction(&tfm, in);
- else
- in = transform_point(&tfm, in);
- }
- }
-
- /* Normalize Normal */
- if (type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL)
- in = normalize(in);
-
- /* Output */
- if (stack_valid(vector_out)) {
- stack_store_float3(stack, vector_out, in);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_vertex_color.h b/intern/cycles/kernel/svm/svm_vertex_color.h
deleted file mode 100644
index a5fa15ee085..00000000000
--- a/intern/cycles/kernel/svm/svm_vertex_color.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_noinline void svm_node_vertex_color(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint layer_id,
- uint color_offset,
- uint alpha_offset)
-{
- AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
- if (descriptor.offset != ATTR_STD_NOT_FOUND) {
- float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, NULL, NULL);
- stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
- stack_store_float(stack, alpha_offset, vertex_color.w);
- }
- else {
- stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
- stack_store_float(stack, alpha_offset, 0.0f);
- }
-}
-
-ccl_device_noinline void svm_node_vertex_color_bump_dx(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint layer_id,
- uint color_offset,
- uint alpha_offset)
-{
- AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
- if (descriptor.offset != ATTR_STD_NOT_FOUND) {
- float4 dx;
- float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, &dx, NULL);
- vertex_color += dx;
- stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
- stack_store_float(stack, alpha_offset, vertex_color.w);
- }
- else {
- stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
- stack_store_float(stack, alpha_offset, 0.0f);
- }
-}
-
-ccl_device_noinline void svm_node_vertex_color_bump_dy(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint layer_id,
- uint color_offset,
- uint alpha_offset)
-{
- AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
- if (descriptor.offset != ATTR_STD_NOT_FOUND) {
- float4 dy;
- float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, NULL, &dy);
- vertex_color += dy;
- stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
- stack_store_float(stack, alpha_offset, vertex_color.w);
- }
- else {
- stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
- stack_store_float(stack, alpha_offset, 0.0f);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h
deleted file mode 100644
index b8067520770..00000000000
--- a/intern/cycles/kernel/svm/svm_voronoi.h
+++ /dev/null
@@ -1,1162 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/*
- * Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez.
- *
- * Smooth Voronoi:
- *
- * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
- *
- * Distance To Edge based on:
- *
- * - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm
- * - https://www.shadertoy.com/view/ldl3W8
- *
- * With optimization to change -2..2 scan window to -1..1 for better performance,
- * as explained in https://www.shadertoy.com/view/llG3zy.
- */
-
-/* **** 1D Voronoi **** */
-
-ccl_device float voronoi_distance_1d(float a,
- float b,
- NodeVoronoiDistanceMetric metric,
- float exponent)
-{
- return fabsf(b - a);
-}
-
-ccl_device void voronoi_f1_1d(float w,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float *outW)
-{
- float cellPosition = floorf(w);
- float localPosition = w - cellPosition;
-
- float minDistance = 8.0f;
- float targetOffset = 0.0f;
- float targetPosition = 0.0f;
- for (int i = -1; i <= 1; i++) {
- float cellOffset = i;
- float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
- if (distanceToPoint < minDistance) {
- targetOffset = cellOffset;
- minDistance = distanceToPoint;
- targetPosition = pointPosition;
- }
- }
- *outDistance = minDistance;
- *outColor = hash_float_to_float3(cellPosition + targetOffset);
- *outW = targetPosition + cellPosition;
-}
-
-ccl_device void voronoi_smooth_f1_1d(float w,
- float smoothness,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float *outW)
-{
- float cellPosition = floorf(w);
- float localPosition = w - cellPosition;
-
- float smoothDistance = 8.0f;
- float smoothPosition = 0.0f;
- float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
- for (int i = -2; i <= 2; i++) {
- float cellOffset = i;
- float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
- float h = smoothstep(
- 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
- float correctionFactor = smoothness * h * (1.0f - h);
- smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
- correctionFactor /= 1.0f + 3.0f * smoothness;
- float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
- smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
- smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
- }
- *outDistance = smoothDistance;
- *outColor = smoothColor;
- *outW = cellPosition + smoothPosition;
-}
-
-ccl_device void voronoi_f2_1d(float w,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float *outW)
-{
- float cellPosition = floorf(w);
- float localPosition = w - cellPosition;
-
- float distanceF1 = 8.0f;
- float distanceF2 = 8.0f;
- float offsetF1 = 0.0f;
- float positionF1 = 0.0f;
- float offsetF2 = 0.0f;
- float positionF2 = 0.0f;
- for (int i = -1; i <= 1; i++) {
- float cellOffset = i;
- float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
- if (distanceToPoint < distanceF1) {
- distanceF2 = distanceF1;
- distanceF1 = distanceToPoint;
- offsetF2 = offsetF1;
- offsetF1 = cellOffset;
- positionF2 = positionF1;
- positionF1 = pointPosition;
- }
- else if (distanceToPoint < distanceF2) {
- distanceF2 = distanceToPoint;
- offsetF2 = cellOffset;
- positionF2 = pointPosition;
- }
- }
- *outDistance = distanceF2;
- *outColor = hash_float_to_float3(cellPosition + offsetF2);
- *outW = positionF2 + cellPosition;
-}
-
-ccl_device void voronoi_distance_to_edge_1d(float w,
- float randomness,
- ccl_private float *outDistance)
-{
- float cellPosition = floorf(w);
- float localPosition = w - cellPosition;
-
- float midPointPosition = hash_float_to_float(cellPosition) * randomness;
- float leftPointPosition = -1.0f + hash_float_to_float(cellPosition - 1.0f) * randomness;
- float rightPointPosition = 1.0f + hash_float_to_float(cellPosition + 1.0f) * randomness;
- float distanceToMidLeft = fabsf((midPointPosition + leftPointPosition) / 2.0f - localPosition);
- float distanceToMidRight = fabsf((midPointPosition + rightPointPosition) / 2.0f - localPosition);
-
- *outDistance = min(distanceToMidLeft, distanceToMidRight);
-}
-
-ccl_device void voronoi_n_sphere_radius_1d(float w, float randomness, ccl_private float *outRadius)
-{
- float cellPosition = floorf(w);
- float localPosition = w - cellPosition;
-
- float closestPoint = 0.0f;
- float closestPointOffset = 0.0f;
- float minDistance = 8.0f;
- for (int i = -1; i <= 1; i++) {
- float cellOffset = i;
- float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
- float distanceToPoint = fabsf(pointPosition - localPosition);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- closestPoint = pointPosition;
- closestPointOffset = cellOffset;
- }
- }
-
- minDistance = 8.0f;
- float closestPointToClosestPoint = 0.0f;
- for (int i = -1; i <= 1; i++) {
- if (i == 0) {
- continue;
- }
- float cellOffset = i + closestPointOffset;
- float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
- float distanceToPoint = fabsf(closestPoint - pointPosition);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- closestPointToClosestPoint = pointPosition;
- }
- }
- *outRadius = fabsf(closestPointToClosestPoint - closestPoint) / 2.0f;
-}
-
-/* **** 2D Voronoi **** */
-
-ccl_device float voronoi_distance_2d(float2 a,
- float2 b,
- NodeVoronoiDistanceMetric metric,
- float exponent)
-{
- if (metric == NODE_VORONOI_EUCLIDEAN) {
- return distance(a, b);
- }
- else if (metric == NODE_VORONOI_MANHATTAN) {
- return fabsf(a.x - b.x) + fabsf(a.y - b.y);
- }
- else if (metric == NODE_VORONOI_CHEBYCHEV) {
- return max(fabsf(a.x - b.x), fabsf(a.y - b.y));
- }
- else if (metric == NODE_VORONOI_MINKOWSKI) {
- return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent),
- 1.0f / exponent);
- }
- else {
- return 0.0f;
- }
-}
-
-ccl_device void voronoi_f1_2d(float2 coord,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float2 *outPosition)
-{
- float2 cellPosition = floor(coord);
- float2 localPosition = coord - cellPosition;
-
- float minDistance = 8.0f;
- float2 targetOffset = make_float2(0.0f, 0.0f);
- float2 targetPosition = make_float2(0.0f, 0.0f);
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- float2 cellOffset = make_float2(i, j);
- float2 pointPosition = cellOffset +
- hash_float2_to_float2(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
- if (distanceToPoint < minDistance) {
- targetOffset = cellOffset;
- minDistance = distanceToPoint;
- targetPosition = pointPosition;
- }
- }
- }
- *outDistance = minDistance;
- *outColor = hash_float2_to_float3(cellPosition + targetOffset);
- *outPosition = targetPosition + cellPosition;
-}
-
-ccl_device void voronoi_smooth_f1_2d(float2 coord,
- float smoothness,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float2 *outPosition)
-{
- float2 cellPosition = floor(coord);
- float2 localPosition = coord - cellPosition;
-
- float smoothDistance = 8.0f;
- float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
- float2 smoothPosition = make_float2(0.0f, 0.0f);
- for (int j = -2; j <= 2; j++) {
- for (int i = -2; i <= 2; i++) {
- float2 cellOffset = make_float2(i, j);
- float2 pointPosition = cellOffset +
- hash_float2_to_float2(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
- float h = smoothstep(
- 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
- float correctionFactor = smoothness * h * (1.0f - h);
- smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
- correctionFactor /= 1.0f + 3.0f * smoothness;
- float3 cellColor = hash_float2_to_float3(cellPosition + cellOffset);
- smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
- smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
- }
- }
- *outDistance = smoothDistance;
- *outColor = smoothColor;
- *outPosition = cellPosition + smoothPosition;
-}
-
-ccl_device void voronoi_f2_2d(float2 coord,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float2 *outPosition)
-{
- float2 cellPosition = floor(coord);
- float2 localPosition = coord - cellPosition;
-
- float distanceF1 = 8.0f;
- float distanceF2 = 8.0f;
- float2 offsetF1 = make_float2(0.0f, 0.0f);
- float2 positionF1 = make_float2(0.0f, 0.0f);
- float2 offsetF2 = make_float2(0.0f, 0.0f);
- float2 positionF2 = make_float2(0.0f, 0.0f);
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- float2 cellOffset = make_float2(i, j);
- float2 pointPosition = cellOffset +
- hash_float2_to_float2(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
- if (distanceToPoint < distanceF1) {
- distanceF2 = distanceF1;
- distanceF1 = distanceToPoint;
- offsetF2 = offsetF1;
- offsetF1 = cellOffset;
- positionF2 = positionF1;
- positionF1 = pointPosition;
- }
- else if (distanceToPoint < distanceF2) {
- distanceF2 = distanceToPoint;
- offsetF2 = cellOffset;
- positionF2 = pointPosition;
- }
- }
- }
- *outDistance = distanceF2;
- *outColor = hash_float2_to_float3(cellPosition + offsetF2);
- *outPosition = positionF2 + cellPosition;
-}
-
-ccl_device void voronoi_distance_to_edge_2d(float2 coord,
- float randomness,
- ccl_private float *outDistance)
-{
- float2 cellPosition = floor(coord);
- float2 localPosition = coord - cellPosition;
-
- float2 vectorToClosest = make_float2(0.0f, 0.0f);
- float minDistance = 8.0f;
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- float2 cellOffset = make_float2(i, j);
- float2 vectorToPoint = cellOffset +
- hash_float2_to_float2(cellPosition + cellOffset) * randomness -
- localPosition;
- float distanceToPoint = dot(vectorToPoint, vectorToPoint);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- vectorToClosest = vectorToPoint;
- }
- }
- }
-
- minDistance = 8.0f;
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- float2 cellOffset = make_float2(i, j);
- float2 vectorToPoint = cellOffset +
- hash_float2_to_float2(cellPosition + cellOffset) * randomness -
- localPosition;
- float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
- if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
- float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
- normalize(perpendicularToEdge));
- minDistance = min(minDistance, distanceToEdge);
- }
- }
- }
- *outDistance = minDistance;
-}
-
-ccl_device void voronoi_n_sphere_radius_2d(float2 coord,
- float randomness,
- ccl_private float *outRadius)
-{
- float2 cellPosition = floor(coord);
- float2 localPosition = coord - cellPosition;
-
- float2 closestPoint = make_float2(0.0f, 0.0f);
- float2 closestPointOffset = make_float2(0.0f, 0.0f);
- float minDistance = 8.0f;
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- float2 cellOffset = make_float2(i, j);
- float2 pointPosition = cellOffset +
- hash_float2_to_float2(cellPosition + cellOffset) * randomness;
- float distanceToPoint = distance(pointPosition, localPosition);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- closestPoint = pointPosition;
- closestPointOffset = cellOffset;
- }
- }
- }
-
- minDistance = 8.0f;
- float2 closestPointToClosestPoint = make_float2(0.0f, 0.0f);
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- if (i == 0 && j == 0) {
- continue;
- }
- float2 cellOffset = make_float2(i, j) + closestPointOffset;
- float2 pointPosition = cellOffset +
- hash_float2_to_float2(cellPosition + cellOffset) * randomness;
- float distanceToPoint = distance(closestPoint, pointPosition);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- closestPointToClosestPoint = pointPosition;
- }
- }
- }
- *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
-}
-
-/* **** 3D Voronoi **** */
-
-ccl_device float voronoi_distance_3d(float3 a,
- float3 b,
- NodeVoronoiDistanceMetric metric,
- float exponent)
-{
- if (metric == NODE_VORONOI_EUCLIDEAN) {
- return distance(a, b);
- }
- else if (metric == NODE_VORONOI_MANHATTAN) {
- return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z);
- }
- else if (metric == NODE_VORONOI_CHEBYCHEV) {
- return max(fabsf(a.x - b.x), max(fabsf(a.y - b.y), fabsf(a.z - b.z)));
- }
- else if (metric == NODE_VORONOI_MINKOWSKI) {
- return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
- powf(fabsf(a.z - b.z), exponent),
- 1.0f / exponent);
- }
- else {
- return 0.0f;
- }
-}
-
-ccl_device void voronoi_f1_3d(float3 coord,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float3 *outPosition)
-{
- float3 cellPosition = floor(coord);
- float3 localPosition = coord - cellPosition;
-
- float minDistance = 8.0f;
- float3 targetOffset = make_float3(0.0f, 0.0f, 0.0f);
- float3 targetPosition = make_float3(0.0f, 0.0f, 0.0f);
- for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- float3 cellOffset = make_float3(i, j, k);
- float3 pointPosition = cellOffset +
- hash_float3_to_float3(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_3d(
- pointPosition, localPosition, metric, exponent);
- if (distanceToPoint < minDistance) {
- targetOffset = cellOffset;
- minDistance = distanceToPoint;
- targetPosition = pointPosition;
- }
- }
- }
- }
- *outDistance = minDistance;
- *outColor = hash_float3_to_float3(cellPosition + targetOffset);
- *outPosition = targetPosition + cellPosition;
-}
-
-ccl_device void voronoi_smooth_f1_3d(float3 coord,
- float smoothness,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float3 *outPosition)
-{
- float3 cellPosition = floor(coord);
- float3 localPosition = coord - cellPosition;
-
- float smoothDistance = 8.0f;
- float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
- float3 smoothPosition = make_float3(0.0f, 0.0f, 0.0f);
- for (int k = -2; k <= 2; k++) {
- for (int j = -2; j <= 2; j++) {
- for (int i = -2; i <= 2; i++) {
- float3 cellOffset = make_float3(i, j, k);
- float3 pointPosition = cellOffset +
- hash_float3_to_float3(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_3d(
- pointPosition, localPosition, metric, exponent);
- float h = smoothstep(
- 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
- float correctionFactor = smoothness * h * (1.0f - h);
- smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
- correctionFactor /= 1.0f + 3.0f * smoothness;
- float3 cellColor = hash_float3_to_float3(cellPosition + cellOffset);
- smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
- smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
- }
- }
- }
- *outDistance = smoothDistance;
- *outColor = smoothColor;
- *outPosition = cellPosition + smoothPosition;
-}
-
-ccl_device void voronoi_f2_3d(float3 coord,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float3 *outPosition)
-{
- float3 cellPosition = floor(coord);
- float3 localPosition = coord - cellPosition;
-
- float distanceF1 = 8.0f;
- float distanceF2 = 8.0f;
- float3 offsetF1 = make_float3(0.0f, 0.0f, 0.0f);
- float3 positionF1 = make_float3(0.0f, 0.0f, 0.0f);
- float3 offsetF2 = make_float3(0.0f, 0.0f, 0.0f);
- float3 positionF2 = make_float3(0.0f, 0.0f, 0.0f);
- for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- float3 cellOffset = make_float3(i, j, k);
- float3 pointPosition = cellOffset +
- hash_float3_to_float3(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_3d(
- pointPosition, localPosition, metric, exponent);
- if (distanceToPoint < distanceF1) {
- distanceF2 = distanceF1;
- distanceF1 = distanceToPoint;
- offsetF2 = offsetF1;
- offsetF1 = cellOffset;
- positionF2 = positionF1;
- positionF1 = pointPosition;
- }
- else if (distanceToPoint < distanceF2) {
- distanceF2 = distanceToPoint;
- offsetF2 = cellOffset;
- positionF2 = pointPosition;
- }
- }
- }
- }
- *outDistance = distanceF2;
- *outColor = hash_float3_to_float3(cellPosition + offsetF2);
- *outPosition = positionF2 + cellPosition;
-}
-
-ccl_device void voronoi_distance_to_edge_3d(float3 coord,
- float randomness,
- ccl_private float *outDistance)
-{
- float3 cellPosition = floor(coord);
- float3 localPosition = coord - cellPosition;
-
- float3 vectorToClosest = make_float3(0.0f, 0.0f, 0.0f);
- float minDistance = 8.0f;
- for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- float3 cellOffset = make_float3(i, j, k);
- float3 vectorToPoint = cellOffset +
- hash_float3_to_float3(cellPosition + cellOffset) * randomness -
- localPosition;
- float distanceToPoint = dot(vectorToPoint, vectorToPoint);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- vectorToClosest = vectorToPoint;
- }
- }
- }
- }
-
- minDistance = 8.0f;
- for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- float3 cellOffset = make_float3(i, j, k);
- float3 vectorToPoint = cellOffset +
- hash_float3_to_float3(cellPosition + cellOffset) * randomness -
- localPosition;
- float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
- if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
- float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
- normalize(perpendicularToEdge));
- minDistance = min(minDistance, distanceToEdge);
- }
- }
- }
- }
- *outDistance = minDistance;
-}
-
-ccl_device void voronoi_n_sphere_radius_3d(float3 coord,
- float randomness,
- ccl_private float *outRadius)
-{
- float3 cellPosition = floor(coord);
- float3 localPosition = coord - cellPosition;
-
- float3 closestPoint = make_float3(0.0f, 0.0f, 0.0f);
- float3 closestPointOffset = make_float3(0.0f, 0.0f, 0.0f);
- float minDistance = 8.0f;
- for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- float3 cellOffset = make_float3(i, j, k);
- float3 pointPosition = cellOffset +
- hash_float3_to_float3(cellPosition + cellOffset) * randomness;
- float distanceToPoint = distance(pointPosition, localPosition);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- closestPoint = pointPosition;
- closestPointOffset = cellOffset;
- }
- }
- }
- }
-
- minDistance = 8.0f;
- float3 closestPointToClosestPoint = make_float3(0.0f, 0.0f, 0.0f);
- for (int k = -1; k <= 1; k++) {
- for (int j = -1; j <= 1; j++) {
- for (int i = -1; i <= 1; i++) {
- if (i == 0 && j == 0 && k == 0) {
- continue;
- }
- float3 cellOffset = make_float3(i, j, k) + closestPointOffset;
- float3 pointPosition = cellOffset +
- hash_float3_to_float3(cellPosition + cellOffset) * randomness;
- float distanceToPoint = distance(closestPoint, pointPosition);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- closestPointToClosestPoint = pointPosition;
- }
- }
- }
- }
- *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
-}
-
-/* **** 4D Voronoi **** */
-
-ccl_device float voronoi_distance_4d(float4 a,
- float4 b,
- NodeVoronoiDistanceMetric metric,
- float exponent)
-{
- if (metric == NODE_VORONOI_EUCLIDEAN) {
- return distance(a, b);
- }
- else if (metric == NODE_VORONOI_MANHATTAN) {
- return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z) + fabsf(a.w - b.w);
- }
- else if (metric == NODE_VORONOI_CHEBYCHEV) {
- return max(fabsf(a.x - b.x), max(fabsf(a.y - b.y), max(fabsf(a.z - b.z), fabsf(a.w - b.w))));
- }
- else if (metric == NODE_VORONOI_MINKOWSKI) {
- return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
- powf(fabsf(a.z - b.z), exponent) + powf(fabsf(a.w - b.w), exponent),
- 1.0f / exponent);
- }
- else {
- return 0.0f;
- }
-}
-
-ccl_device void voronoi_f1_4d(float4 coord,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float4 *outPosition)
-{
- float4 cellPosition = floor(coord);
- float4 localPosition = coord - cellPosition;
-
- float minDistance = 8.0f;
- float4 targetOffset = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float4 targetPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- for (int u = -1; u <= 1; u++) {
- for (int k = -1; k <= 1; k++) {
- ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
- {
- for (int i = -1; i <= 1; i++) {
- float4 cellOffset = make_float4(i, j, k, u);
- float4 pointPosition = cellOffset +
- hash_float4_to_float4(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_4d(
- pointPosition, localPosition, metric, exponent);
- if (distanceToPoint < minDistance) {
- targetOffset = cellOffset;
- minDistance = distanceToPoint;
- targetPosition = pointPosition;
- }
- }
- }
- }
- }
- *outDistance = minDistance;
- *outColor = hash_float4_to_float3(cellPosition + targetOffset);
- *outPosition = targetPosition + cellPosition;
-}
-
-ccl_device void voronoi_smooth_f1_4d(float4 coord,
- float smoothness,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float4 *outPosition)
-{
- float4 cellPosition = floor(coord);
- float4 localPosition = coord - cellPosition;
-
- float smoothDistance = 8.0f;
- float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
- float4 smoothPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- for (int u = -2; u <= 2; u++) {
- for (int k = -2; k <= 2; k++) {
- ccl_loop_no_unroll for (int j = -2; j <= 2; j++)
- {
- for (int i = -2; i <= 2; i++) {
- float4 cellOffset = make_float4(i, j, k, u);
- float4 pointPosition = cellOffset +
- hash_float4_to_float4(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_4d(
- pointPosition, localPosition, metric, exponent);
- float h = smoothstep(
- 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
- float correctionFactor = smoothness * h * (1.0f - h);
- smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
- correctionFactor /= 1.0f + 3.0f * smoothness;
- float3 cellColor = hash_float4_to_float3(cellPosition + cellOffset);
- smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
- smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
- }
- }
- }
- }
- *outDistance = smoothDistance;
- *outColor = smoothColor;
- *outPosition = cellPosition + smoothPosition;
-}
-
-ccl_device void voronoi_f2_4d(float4 coord,
- float exponent,
- float randomness,
- NodeVoronoiDistanceMetric metric,
- ccl_private float *outDistance,
- ccl_private float3 *outColor,
- ccl_private float4 *outPosition)
-{
- float4 cellPosition = floor(coord);
- float4 localPosition = coord - cellPosition;
-
- float distanceF1 = 8.0f;
- float distanceF2 = 8.0f;
- float4 offsetF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float4 positionF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float4 offsetF2 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float4 positionF2 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- for (int u = -1; u <= 1; u++) {
- for (int k = -1; k <= 1; k++) {
- ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
- {
- for (int i = -1; i <= 1; i++) {
- float4 cellOffset = make_float4(i, j, k, u);
- float4 pointPosition = cellOffset +
- hash_float4_to_float4(cellPosition + cellOffset) * randomness;
- float distanceToPoint = voronoi_distance_4d(
- pointPosition, localPosition, metric, exponent);
- if (distanceToPoint < distanceF1) {
- distanceF2 = distanceF1;
- distanceF1 = distanceToPoint;
- offsetF2 = offsetF1;
- offsetF1 = cellOffset;
- positionF2 = positionF1;
- positionF1 = pointPosition;
- }
- else if (distanceToPoint < distanceF2) {
- distanceF2 = distanceToPoint;
- offsetF2 = cellOffset;
- positionF2 = pointPosition;
- }
- }
- }
- }
- }
- *outDistance = distanceF2;
- *outColor = hash_float4_to_float3(cellPosition + offsetF2);
- *outPosition = positionF2 + cellPosition;
-}
-
-ccl_device void voronoi_distance_to_edge_4d(float4 coord,
- float randomness,
- ccl_private float *outDistance)
-{
- float4 cellPosition = floor(coord);
- float4 localPosition = coord - cellPosition;
-
- float4 vectorToClosest = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float minDistance = 8.0f;
- for (int u = -1; u <= 1; u++) {
- for (int k = -1; k <= 1; k++) {
- ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
- {
- for (int i = -1; i <= 1; i++) {
- float4 cellOffset = make_float4(i, j, k, u);
- float4 vectorToPoint = cellOffset +
- hash_float4_to_float4(cellPosition + cellOffset) * randomness -
- localPosition;
- float distanceToPoint = dot(vectorToPoint, vectorToPoint);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- vectorToClosest = vectorToPoint;
- }
- }
- }
- }
- }
-
- minDistance = 8.0f;
- for (int u = -1; u <= 1; u++) {
- for (int k = -1; k <= 1; k++) {
- ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
- {
- for (int i = -1; i <= 1; i++) {
- float4 cellOffset = make_float4(i, j, k, u);
- float4 vectorToPoint = cellOffset +
- hash_float4_to_float4(cellPosition + cellOffset) * randomness -
- localPosition;
- float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
- if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
- float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
- normalize(perpendicularToEdge));
- minDistance = min(minDistance, distanceToEdge);
- }
- }
- }
- }
- }
- *outDistance = minDistance;
-}
-
-ccl_device void voronoi_n_sphere_radius_4d(float4 coord,
- float randomness,
- ccl_private float *outRadius)
-{
- float4 cellPosition = floor(coord);
- float4 localPosition = coord - cellPosition;
-
- float4 closestPoint = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float4 closestPointOffset = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float minDistance = 8.0f;
- for (int u = -1; u <= 1; u++) {
- for (int k = -1; k <= 1; k++) {
- ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
- {
- for (int i = -1; i <= 1; i++) {
- float4 cellOffset = make_float4(i, j, k, u);
- float4 pointPosition = cellOffset +
- hash_float4_to_float4(cellPosition + cellOffset) * randomness;
- float distanceToPoint = distance(pointPosition, localPosition);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- closestPoint = pointPosition;
- closestPointOffset = cellOffset;
- }
- }
- }
- }
- }
-
- minDistance = 8.0f;
- float4 closestPointToClosestPoint = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- for (int u = -1; u <= 1; u++) {
- for (int k = -1; k <= 1; k++) {
- ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
- {
- for (int i = -1; i <= 1; i++) {
- if (i == 0 && j == 0 && k == 0 && u == 0) {
- continue;
- }
- float4 cellOffset = make_float4(i, j, k, u) + closestPointOffset;
- float4 pointPosition = cellOffset +
- hash_float4_to_float4(cellPosition + cellOffset) * randomness;
- float distanceToPoint = distance(closestPoint, pointPosition);
- if (distanceToPoint < minDistance) {
- minDistance = distanceToPoint;
- closestPointToClosestPoint = pointPosition;
- }
- }
- }
- }
- }
- *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
-}
-
-template<uint node_feature_mask>
-ccl_device_noinline int svm_node_tex_voronoi(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint dimensions,
- uint feature,
- uint metric,
- int offset)
-{
- uint4 stack_offsets = read_node(kg, &offset);
- uint4 defaults = read_node(kg, &offset);
-
- uint coord_stack_offset, w_stack_offset, scale_stack_offset, smoothness_stack_offset;
- uint exponent_stack_offset, randomness_stack_offset, distance_out_stack_offset,
- color_out_stack_offset;
- uint position_out_stack_offset, w_out_stack_offset, radius_out_stack_offset;
-
- svm_unpack_node_uchar4(stack_offsets.x,
- &coord_stack_offset,
- &w_stack_offset,
- &scale_stack_offset,
- &smoothness_stack_offset);
- svm_unpack_node_uchar4(stack_offsets.y,
- &exponent_stack_offset,
- &randomness_stack_offset,
- &distance_out_stack_offset,
- &color_out_stack_offset);
- svm_unpack_node_uchar3(
- stack_offsets.z, &position_out_stack_offset, &w_out_stack_offset, &radius_out_stack_offset);
-
- float3 coord = stack_load_float3(stack, coord_stack_offset);
- float w = stack_load_float_default(stack, w_stack_offset, stack_offsets.w);
- float scale = stack_load_float_default(stack, scale_stack_offset, defaults.x);
- float smoothness = stack_load_float_default(stack, smoothness_stack_offset, defaults.y);
- float exponent = stack_load_float_default(stack, exponent_stack_offset, defaults.z);
- float randomness = stack_load_float_default(stack, randomness_stack_offset, defaults.w);
-
- NodeVoronoiFeature voronoi_feature = (NodeVoronoiFeature)feature;
- NodeVoronoiDistanceMetric voronoi_metric = (NodeVoronoiDistanceMetric)metric;
-
- float distance_out = 0.0f, w_out = 0.0f, radius_out = 0.0f;
- float3 color_out = make_float3(0.0f, 0.0f, 0.0f);
- float3 position_out = make_float3(0.0f, 0.0f, 0.0f);
-
- randomness = clamp(randomness, 0.0f, 1.0f);
- smoothness = clamp(smoothness / 2.0f, 0.0f, 0.5f);
-
- w *= scale;
- coord *= scale;
-
- switch (dimensions) {
- case 1: {
- switch (voronoi_feature) {
- case NODE_VORONOI_F1:
- voronoi_f1_1d(
- w, exponent, randomness, voronoi_metric, &distance_out, &color_out, &w_out);
- break;
- case NODE_VORONOI_SMOOTH_F1:
- voronoi_smooth_f1_1d(w,
- smoothness,
- exponent,
- randomness,
- voronoi_metric,
- &distance_out,
- &color_out,
- &w_out);
- break;
- case NODE_VORONOI_F2:
- voronoi_f2_1d(
- w, exponent, randomness, voronoi_metric, &distance_out, &color_out, &w_out);
- break;
- case NODE_VORONOI_DISTANCE_TO_EDGE:
- voronoi_distance_to_edge_1d(w, randomness, &distance_out);
- break;
- case NODE_VORONOI_N_SPHERE_RADIUS:
- voronoi_n_sphere_radius_1d(w, randomness, &radius_out);
- break;
- default:
- kernel_assert(0);
- }
- w_out = safe_divide(w_out, scale);
- break;
- }
- case 2: {
- float2 coord_2d = make_float2(coord.x, coord.y);
- float2 position_out_2d = zero_float2();
- switch (voronoi_feature) {
- case NODE_VORONOI_F1:
- voronoi_f1_2d(coord_2d,
- exponent,
- randomness,
- voronoi_metric,
- &distance_out,
- &color_out,
- &position_out_2d);
- break;
- case NODE_VORONOI_SMOOTH_F1:
- IF_KERNEL_NODES_FEATURE(VORONOI_EXTRA)
- {
- voronoi_smooth_f1_2d(coord_2d,
- smoothness,
- exponent,
- randomness,
- voronoi_metric,
- &distance_out,
- &color_out,
- &position_out_2d);
- }
- break;
- case NODE_VORONOI_F2:
- voronoi_f2_2d(coord_2d,
- exponent,
- randomness,
- voronoi_metric,
- &distance_out,
- &color_out,
- &position_out_2d);
- break;
- case NODE_VORONOI_DISTANCE_TO_EDGE:
- voronoi_distance_to_edge_2d(coord_2d, randomness, &distance_out);
- break;
- case NODE_VORONOI_N_SPHERE_RADIUS:
- voronoi_n_sphere_radius_2d(coord_2d, randomness, &radius_out);
- break;
- default:
- kernel_assert(0);
- }
- position_out_2d = safe_divide_float2_float(position_out_2d, scale);
- position_out = make_float3(position_out_2d.x, position_out_2d.y, 0.0f);
- break;
- }
- case 3: {
- switch (voronoi_feature) {
- case NODE_VORONOI_F1:
- voronoi_f1_3d(coord,
- exponent,
- randomness,
- voronoi_metric,
- &distance_out,
- &color_out,
- &position_out);
- break;
- case NODE_VORONOI_SMOOTH_F1:
- IF_KERNEL_NODES_FEATURE(VORONOI_EXTRA)
- {
- voronoi_smooth_f1_3d(coord,
- smoothness,
- exponent,
- randomness,
- voronoi_metric,
- &distance_out,
- &color_out,
- &position_out);
- }
- break;
- case NODE_VORONOI_F2:
- voronoi_f2_3d(coord,
- exponent,
- randomness,
- voronoi_metric,
- &distance_out,
- &color_out,
- &position_out);
- break;
- case NODE_VORONOI_DISTANCE_TO_EDGE:
- voronoi_distance_to_edge_3d(coord, randomness, &distance_out);
- break;
- case NODE_VORONOI_N_SPHERE_RADIUS:
- voronoi_n_sphere_radius_3d(coord, randomness, &radius_out);
- break;
- default:
- kernel_assert(0);
- }
- position_out = safe_divide_float3_float(position_out, scale);
- break;
- }
-
- case 4: {
- IF_KERNEL_NODES_FEATURE(VORONOI_EXTRA)
- {
- float4 coord_4d = make_float4(coord.x, coord.y, coord.z, w);
- float4 position_out_4d;
- switch (voronoi_feature) {
- case NODE_VORONOI_F1:
- voronoi_f1_4d(coord_4d,
- exponent,
- randomness,
- voronoi_metric,
- &distance_out,
- &color_out,
- &position_out_4d);
- break;
- case NODE_VORONOI_SMOOTH_F1:
- voronoi_smooth_f1_4d(coord_4d,
- smoothness,
- exponent,
- randomness,
- voronoi_metric,
- &distance_out,
- &color_out,
- &position_out_4d);
- break;
- case NODE_VORONOI_F2:
- voronoi_f2_4d(coord_4d,
- exponent,
- randomness,
- voronoi_metric,
- &distance_out,
- &color_out,
- &position_out_4d);
- break;
- case NODE_VORONOI_DISTANCE_TO_EDGE:
- voronoi_distance_to_edge_4d(coord_4d, randomness, &distance_out);
- break;
- case NODE_VORONOI_N_SPHERE_RADIUS:
- voronoi_n_sphere_radius_4d(coord_4d, randomness, &radius_out);
- break;
- default:
- kernel_assert(0);
- }
- position_out_4d = safe_divide_float4_float(position_out_4d, scale);
- position_out = make_float3(position_out_4d.x, position_out_4d.y, position_out_4d.z);
- w_out = position_out_4d.w;
- }
- break;
- }
- default:
- kernel_assert(0);
- }
-
- if (stack_valid(distance_out_stack_offset))
- stack_store_float(stack, distance_out_stack_offset, distance_out);
- if (stack_valid(color_out_stack_offset))
- stack_store_float3(stack, color_out_stack_offset, color_out);
- if (stack_valid(position_out_stack_offset))
- stack_store_float3(stack, position_out_stack_offset, position_out);
- if (stack_valid(w_out_stack_offset))
- stack_store_float(stack, w_out_stack_offset, w_out);
- if (stack_valid(radius_out_stack_offset))
- stack_store_float(stack, radius_out_stack_offset, radius_out);
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h
deleted file mode 100644
index be4bb315145..00000000000
--- a/intern/cycles/kernel/svm/svm_voxel.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2011-2015 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* TODO(sergey): Think of making it more generic volume-type attribute
- * sampler.
- */
-ccl_device_noinline int svm_node_tex_voxel(
- KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
-{
- uint co_offset, density_out_offset, color_out_offset, space;
- svm_unpack_node_uchar4(node.z, &co_offset, &density_out_offset, &color_out_offset, &space);
-#ifdef __VOLUME__
- int id = node.y;
- float3 co = stack_load_float3(stack, co_offset);
- if (space == NODE_TEX_VOXEL_SPACE_OBJECT) {
- co = volume_normalized_position(kg, sd, co);
- }
- else {
- kernel_assert(space == NODE_TEX_VOXEL_SPACE_WORLD);
- Transform tfm;
- tfm.x = read_node_float(kg, &offset);
- tfm.y = read_node_float(kg, &offset);
- tfm.z = read_node_float(kg, &offset);
- co = transform_point(&tfm, co);
- }
-
- float4 r = kernel_tex_image_interp_3d(kg, id, co, INTERPOLATION_NONE);
-#else
- float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-#endif
- if (stack_valid(density_out_offset))
- stack_store_float(stack, density_out_offset, r.w);
- if (stack_valid(color_out_offset))
- stack_store_float3(stack, color_out_offset, make_float3(r.x, r.y, r.z));
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_wave.h b/intern/cycles/kernel/svm/svm_wave.h
deleted file mode 100644
index d04b7aa3476..00000000000
--- a/intern/cycles/kernel/svm/svm_wave.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Wave */
-
-ccl_device_noinline_cpu float svm_wave(NodeWaveType type,
- NodeWaveBandsDirection bands_dir,
- NodeWaveRingsDirection rings_dir,
- NodeWaveProfile profile,
- float3 p,
- float distortion,
- float detail,
- float dscale,
- float droughness,
- float phase)
-{
- /* Prevent precision issues on unit coordinates. */
- p = (p + 0.000001f) * 0.999999f;
-
- float n;
-
- if (type == NODE_WAVE_BANDS) {
- if (bands_dir == NODE_WAVE_BANDS_DIRECTION_X) {
- n = p.x * 20.0f;
- }
- else if (bands_dir == NODE_WAVE_BANDS_DIRECTION_Y) {
- n = p.y * 20.0f;
- }
- else if (bands_dir == NODE_WAVE_BANDS_DIRECTION_Z) {
- n = p.z * 20.0f;
- }
- else { /* NODE_WAVE_BANDS_DIRECTION_DIAGONAL */
- n = (p.x + p.y + p.z) * 10.0f;
- }
- }
- else { /* NODE_WAVE_RINGS */
- float3 rp = p;
- if (rings_dir == NODE_WAVE_RINGS_DIRECTION_X) {
- rp *= make_float3(0.0f, 1.0f, 1.0f);
- }
- else if (rings_dir == NODE_WAVE_RINGS_DIRECTION_Y) {
- rp *= make_float3(1.0f, 0.0f, 1.0f);
- }
- else if (rings_dir == NODE_WAVE_RINGS_DIRECTION_Z) {
- rp *= make_float3(1.0f, 1.0f, 0.0f);
- }
- /* else: NODE_WAVE_RINGS_DIRECTION_SPHERICAL */
-
- n = len(rp) * 20.0f;
- }
-
- n += phase;
-
- if (distortion != 0.0f)
- n += distortion * (fractal_noise_3d(p * dscale, detail, droughness) * 2.0f - 1.0f);
-
- if (profile == NODE_WAVE_PROFILE_SIN) {
- return 0.5f + 0.5f * sinf(n - M_PI_2_F);
- }
- else if (profile == NODE_WAVE_PROFILE_SAW) {
- n /= M_2PI_F;
- return n - floorf(n);
- }
- else { /* NODE_WAVE_PROFILE_TRI */
- n /= M_2PI_F;
- return fabsf(n - floorf(n + 0.5f)) * 2.0f;
- }
-}
-
-ccl_device_noinline int svm_node_tex_wave(
- KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
-{
- uint4 node2 = read_node(kg, &offset);
- uint4 node3 = read_node(kg, &offset);
-
- /* RNA properties */
- uint type_offset, bands_dir_offset, rings_dir_offset, profile_offset;
- /* Inputs, Outputs */
- uint co_offset, scale_offset, distortion_offset, detail_offset, dscale_offset, droughness_offset,
- phase_offset;
- uint color_offset, fac_offset;
-
- svm_unpack_node_uchar4(
- node.y, &type_offset, &bands_dir_offset, &rings_dir_offset, &profile_offset);
- svm_unpack_node_uchar3(node.z, &co_offset, &scale_offset, &distortion_offset);
- svm_unpack_node_uchar4(
- node.w, &detail_offset, &dscale_offset, &droughness_offset, &phase_offset);
- svm_unpack_node_uchar2(node2.x, &color_offset, &fac_offset);
-
- float3 co = stack_load_float3(stack, co_offset);
- float scale = stack_load_float_default(stack, scale_offset, node2.y);
- float distortion = stack_load_float_default(stack, distortion_offset, node2.z);
- float detail = stack_load_float_default(stack, detail_offset, node2.w);
- float dscale = stack_load_float_default(stack, dscale_offset, node3.x);
- float droughness = stack_load_float_default(stack, droughness_offset, node3.y);
- float phase = stack_load_float_default(stack, phase_offset, node3.z);
-
- float f = svm_wave((NodeWaveType)type_offset,
- (NodeWaveBandsDirection)bands_dir_offset,
- (NodeWaveRingsDirection)rings_dir_offset,
- (NodeWaveProfile)profile_offset,
- co * scale,
- distortion,
- detail,
- dscale,
- droughness,
- phase);
-
- if (stack_valid(fac_offset))
- stack_store_float(stack, fac_offset, f);
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, make_float3(f, f, f));
- return offset;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_wavelength.h b/intern/cycles/kernel/svm/svm_wavelength.h
deleted file mode 100644
index 4ef041f68d5..00000000000
--- a/intern/cycles/kernel/svm/svm_wavelength.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Adapted from Open Shading Language with this license:
- *
- * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
- * All Rights Reserved.
- *
- * Modifications Copyright 2013, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Sony Pictures Imageworks nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Wavelength to RGB */
-
-ccl_device_noinline void svm_node_wavelength(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint wavelength,
- uint color_out)
-{
- // CIE colour matching functions xBar, yBar, and zBar for
- // wavelengths from 380 through 780 nanometers, every 5
- // nanometers. For a wavelength lambda in this range:
- // cie_colour_match[(lambda - 380) / 5][0] = xBar
- // cie_colour_match[(lambda - 380) / 5][1] = yBar
- // cie_colour_match[(lambda - 380) / 5][2] = zBar
- const float cie_colour_match[81][3] = {
- {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
- {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
- {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
- {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
- {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
- {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
- {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
- {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
- {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
- {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
- {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
- {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
- {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
- {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
- {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
- {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
- {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
- {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
- {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
- {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
- {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
- {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
- {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
- {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
- {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
- {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
- {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}};
-
- float lambda_nm = stack_load_float(stack, wavelength);
- float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); // scaled 0..80
- int i = float_to_int(ii);
- float3 color;
-
- if (i < 0 || i >= 80) {
- color = make_float3(0.0f, 0.0f, 0.0f);
- }
- else {
- ii -= i;
- ccl_constant float *c = cie_colour_match[i];
- color = interp(make_float3(c[0], c[1], c[2]), make_float3(c[3], c[4], c[5]), ii);
- }
-
- color = xyz_to_rgb(kg, color);
- color *= 1.0f / 2.52f; // Empirical scale from lg to make all comps <= 1
-
- /* Clamp to zero if values are smaller */
- color = max(color, make_float3(0.0f, 0.0f, 0.0f));
-
- stack_store_float3(stack, color_out, color);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_white_noise.h b/intern/cycles/kernel/svm/svm_white_noise.h
deleted file mode 100644
index 6c2c3d6a683..00000000000
--- a/intern/cycles/kernel/svm/svm_white_noise.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_noinline void svm_node_tex_white_noise(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint dimensions,
- uint inputs_stack_offsets,
- uint ouptuts_stack_offsets)
-{
- uint vector_stack_offset, w_stack_offset, value_stack_offset, color_stack_offset;
- svm_unpack_node_uchar2(inputs_stack_offsets, &vector_stack_offset, &w_stack_offset);
- svm_unpack_node_uchar2(ouptuts_stack_offsets, &value_stack_offset, &color_stack_offset);
-
- float3 vector = stack_load_float3(stack, vector_stack_offset);
- float w = stack_load_float(stack, w_stack_offset);
-
- if (stack_valid(color_stack_offset)) {
- float3 color;
- switch (dimensions) {
- case 1:
- color = hash_float_to_float3(w);
- break;
- case 2:
- color = hash_float2_to_float3(make_float2(vector.x, vector.y));
- break;
- case 3:
- color = hash_float3_to_float3(vector);
- break;
- case 4:
- color = hash_float4_to_float3(make_float4(vector.x, vector.y, vector.z, w));
- break;
- default:
- color = make_float3(1.0f, 0.0f, 1.0f);
- kernel_assert(0);
- break;
- }
- stack_store_float3(stack, color_stack_offset, color);
- }
-
- if (stack_valid(value_stack_offset)) {
- float value;
- switch (dimensions) {
- case 1:
- value = hash_float_to_float(w);
- break;
- case 2:
- value = hash_float2_to_float(make_float2(vector.x, vector.y));
- break;
- case 3:
- value = hash_float3_to_float(vector);
- break;
- case 4:
- value = hash_float4_to_float(make_float4(vector.x, vector.y, vector.z, w));
- break;
- default:
- value = 0.0f;
- kernel_assert(0);
- break;
- }
- stack_store_float(stack, value_stack_offset, value);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_wireframe.h b/intern/cycles/kernel/svm/svm_wireframe.h
deleted file mode 100644
index d75976d23e1..00000000000
--- a/intern/cycles/kernel/svm/svm_wireframe.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Adapted from Open Shading Language with this license:
- *
- * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
- * All Rights Reserved.
- *
- * Modifications Copyright 2013, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Sony Pictures Imageworks nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Wireframe Node */
-
-ccl_device_inline float wireframe(KernelGlobals kg,
- ccl_private ShaderData *sd,
- float size,
- int pixel_size,
- ccl_private float3 *P)
-{
-#ifdef __HAIR__
- if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_ALL_TRIANGLE)
-#else
- if (sd->prim != PRIM_NONE)
-#endif
- {
- float3 Co[3];
- float pixelwidth = 1.0f;
-
- /* Triangles */
- int np = 3;
-
- if (sd->type & PRIMITIVE_TRIANGLE)
- triangle_vertices(kg, sd->prim, Co);
- else
- motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, Co);
-
- if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- object_position_transform(kg, sd, &Co[0]);
- object_position_transform(kg, sd, &Co[1]);
- object_position_transform(kg, sd, &Co[2]);
- }
-
- if (pixel_size) {
- // Project the derivatives of P to the viewing plane defined
- // by I so we have a measure of how big is a pixel at this point
- float pixelwidth_x = len(sd->dP.dx - dot(sd->dP.dx, sd->I) * sd->I);
- float pixelwidth_y = len(sd->dP.dy - dot(sd->dP.dy, sd->I) * sd->I);
- // Take the average of both axis' length
- pixelwidth = (pixelwidth_x + pixelwidth_y) * 0.5f;
- }
-
- // Use half the width as the neighbor face will render the
- // other half. And take the square for fast comparison
- pixelwidth *= 0.5f * size;
- pixelwidth *= pixelwidth;
- for (int i = 0; i < np; i++) {
- int i2 = i ? i - 1 : np - 1;
- float3 dir = *P - Co[i];
- float3 edge = Co[i] - Co[i2];
- float3 crs = cross(edge, dir);
- // At this point dot(crs, crs) / dot(edge, edge) is
- // the square of area / length(edge) == square of the
- // distance to the edge.
- if (dot(crs, crs) < (dot(edge, edge) * pixelwidth))
- return 1.0f;
- }
- }
- return 0.0f;
-}
-
-ccl_device_noinline void svm_node_wireframe(KernelGlobals kg,
- ccl_private ShaderData *sd,
- ccl_private float *stack,
- uint4 node)
-{
- uint in_size = node.y;
- uint out_fac = node.z;
- uint use_pixel_size, bump_offset;
- svm_unpack_node_uchar2(node.w, &use_pixel_size, &bump_offset);
-
- /* Input Data */
- float size = stack_load_float(stack, in_size);
- int pixel_size = (int)use_pixel_size;
-
- /* Calculate wireframe */
- float f = wireframe(kg, sd, size, pixel_size, &sd->P);
-
- /* TODO(sergey): Think of faster way to calculate derivatives. */
- if (bump_offset == NODE_BUMP_OFFSET_DX) {
- float3 Px = sd->P - sd->dP.dx;
- f += (f - wireframe(kg, sd, size, pixel_size, &Px)) / len(sd->dP.dx);
- }
- else if (bump_offset == NODE_BUMP_OFFSET_DY) {
- float3 Py = sd->P - sd->dP.dy;
- f += (f - wireframe(kg, sd, size, pixel_size, &Py)) / len(sd->dP.dy);
- }
-
- if (stack_valid(out_fac))
- stack_store_float(stack, out_fac, f);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/tex_coord.h b/intern/cycles/kernel/svm/tex_coord.h
new file mode 100644
index 00000000000..5e0debc968a
--- /dev/null
+++ b/intern/cycles/kernel/svm/tex_coord.h
@@ -0,0 +1,426 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "kernel/camera/camera.h"
+#include "kernel/geom/geom.h"
+#include "kernel/sample/mapping.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Texture Coordinate Node */
+
+ccl_device_noinline int svm_node_tex_coord(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ uint32_t path_flag,
+ ccl_private float *stack,
+ uint4 node,
+ int offset)
+{
+ float3 data;
+ uint type = node.y;
+ uint out_offset = node.z;
+
+ switch (type) {
+ case NODE_TEXCO_OBJECT: {
+ data = sd->P;
+ if (node.w == 0) {
+ if (sd->object != OBJECT_NONE) {
+ object_inverse_position_transform(kg, sd, &data);
+ }
+ }
+ else {
+ Transform tfm;
+ tfm.x = read_node_float(kg, &offset);
+ tfm.y = read_node_float(kg, &offset);
+ tfm.z = read_node_float(kg, &offset);
+ data = transform_point(&tfm, data);
+ }
+ break;
+ }
+ case NODE_TEXCO_NORMAL: {
+ data = sd->N;
+ object_inverse_normal_transform(kg, sd, &data);
+ break;
+ }
+ case NODE_TEXCO_CAMERA: {
+ Transform tfm = kernel_data.cam.worldtocamera;
+
+ if (sd->object != OBJECT_NONE)
+ data = transform_point(&tfm, sd->P);
+ else
+ data = transform_point(&tfm, sd->P + camera_position(kg));
+ break;
+ }
+ case NODE_TEXCO_WINDOW: {
+ if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
+ kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
+ data = camera_world_to_ndc(kg, sd, sd->ray_P);
+ else
+ data = camera_world_to_ndc(kg, sd, sd->P);
+ data.z = 0.0f;
+ break;
+ }
+ case NODE_TEXCO_REFLECTION: {
+ if (sd->object != OBJECT_NONE)
+ data = 2.0f * dot(sd->N, sd->I) * sd->N - sd->I;
+ else
+ data = sd->I;
+ break;
+ }
+ case NODE_TEXCO_DUPLI_GENERATED: {
+ data = object_dupli_generated(kg, sd->object);
+ break;
+ }
+ case NODE_TEXCO_DUPLI_UV: {
+ data = object_dupli_uv(kg, sd->object);
+ break;
+ }
+ case NODE_TEXCO_VOLUME_GENERATED: {
+ data = sd->P;
+
+#ifdef __VOLUME__
+ if (sd->object != OBJECT_NONE)
+ data = volume_normalized_position(kg, sd, data);
+#endif
+ break;
+ }
+ }
+
+ stack_store_float3(stack, out_offset, data);
+ return offset;
+}
+
+ccl_device_noinline int svm_node_tex_coord_bump_dx(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ uint32_t path_flag,
+ ccl_private float *stack,
+ uint4 node,
+ int offset)
+{
+#ifdef __RAY_DIFFERENTIALS__
+ float3 data;
+ uint type = node.y;
+ uint out_offset = node.z;
+
+ switch (type) {
+ case NODE_TEXCO_OBJECT: {
+ data = sd->P + sd->dP.dx;
+ if (node.w == 0) {
+ if (sd->object != OBJECT_NONE) {
+ object_inverse_position_transform(kg, sd, &data);
+ }
+ }
+ else {
+ Transform tfm;
+ tfm.x = read_node_float(kg, &offset);
+ tfm.y = read_node_float(kg, &offset);
+ tfm.z = read_node_float(kg, &offset);
+ data = transform_point(&tfm, data);
+ }
+ break;
+ }
+ case NODE_TEXCO_NORMAL: {
+ data = sd->N;
+ object_inverse_normal_transform(kg, sd, &data);
+ break;
+ }
+ case NODE_TEXCO_CAMERA: {
+ Transform tfm = kernel_data.cam.worldtocamera;
+
+ if (sd->object != OBJECT_NONE)
+ data = transform_point(&tfm, sd->P + sd->dP.dx);
+ else
+ data = transform_point(&tfm, sd->P + sd->dP.dx + camera_position(kg));
+ break;
+ }
+ case NODE_TEXCO_WINDOW: {
+ if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
+ kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
+ data = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(sd->ray_dP, 0.0f, 0.0f));
+ else
+ data = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dx);
+ data.z = 0.0f;
+ break;
+ }
+ case NODE_TEXCO_REFLECTION: {
+ if (sd->object != OBJECT_NONE)
+ data = 2.0f * dot(sd->N, sd->I) * sd->N - sd->I;
+ else
+ data = sd->I;
+ break;
+ }
+ case NODE_TEXCO_DUPLI_GENERATED: {
+ data = object_dupli_generated(kg, sd->object);
+ break;
+ }
+ case NODE_TEXCO_DUPLI_UV: {
+ data = object_dupli_uv(kg, sd->object);
+ break;
+ }
+ case NODE_TEXCO_VOLUME_GENERATED: {
+ data = sd->P + sd->dP.dx;
+
+# ifdef __VOLUME__
+ if (sd->object != OBJECT_NONE)
+ data = volume_normalized_position(kg, sd, data);
+# endif
+ break;
+ }
+ }
+
+ stack_store_float3(stack, out_offset, data);
+ return offset;
+#else
+ return svm_node_tex_coord(kg, sd, path_flag, stack, node, offset);
+#endif
+}
+
+ccl_device_noinline int svm_node_tex_coord_bump_dy(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ uint32_t path_flag,
+ ccl_private float *stack,
+ uint4 node,
+ int offset)
+{
+#ifdef __RAY_DIFFERENTIALS__
+ float3 data;
+ uint type = node.y;
+ uint out_offset = node.z;
+
+ switch (type) {
+ case NODE_TEXCO_OBJECT: {
+ data = sd->P + sd->dP.dy;
+ if (node.w == 0) {
+ if (sd->object != OBJECT_NONE) {
+ object_inverse_position_transform(kg, sd, &data);
+ }
+ }
+ else {
+ Transform tfm;
+ tfm.x = read_node_float(kg, &offset);
+ tfm.y = read_node_float(kg, &offset);
+ tfm.z = read_node_float(kg, &offset);
+ data = transform_point(&tfm, data);
+ }
+ break;
+ }
+ case NODE_TEXCO_NORMAL: {
+ data = sd->N;
+ object_inverse_normal_transform(kg, sd, &data);
+ break;
+ }
+ case NODE_TEXCO_CAMERA: {
+ Transform tfm = kernel_data.cam.worldtocamera;
+
+ if (sd->object != OBJECT_NONE)
+ data = transform_point(&tfm, sd->P + sd->dP.dy);
+ else
+ data = transform_point(&tfm, sd->P + sd->dP.dy + camera_position(kg));
+ break;
+ }
+ case NODE_TEXCO_WINDOW: {
+ if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
+ kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
+ data = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(0.0f, sd->ray_dP, 0.0f));
+ else
+ data = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dy);
+ data.z = 0.0f;
+ break;
+ }
+ case NODE_TEXCO_REFLECTION: {
+ if (sd->object != OBJECT_NONE)
+ data = 2.0f * dot(sd->N, sd->I) * sd->N - sd->I;
+ else
+ data = sd->I;
+ break;
+ }
+ case NODE_TEXCO_DUPLI_GENERATED: {
+ data = object_dupli_generated(kg, sd->object);
+ break;
+ }
+ case NODE_TEXCO_DUPLI_UV: {
+ data = object_dupli_uv(kg, sd->object);
+ break;
+ }
+ case NODE_TEXCO_VOLUME_GENERATED: {
+ data = sd->P + sd->dP.dy;
+
+# ifdef __VOLUME__
+ if (sd->object != OBJECT_NONE)
+ data = volume_normalized_position(kg, sd, data);
+# endif
+ break;
+ }
+ }
+
+ stack_store_float3(stack, out_offset, data);
+ return offset;
+#else
+ return svm_node_tex_coord(kg, sd, path_flag, stack, node, offset);
+#endif
+}
+
+ccl_device_noinline void svm_node_normal_map(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint color_offset, strength_offset, normal_offset, space;
+ svm_unpack_node_uchar4(node.y, &color_offset, &strength_offset, &normal_offset, &space);
+
+ float3 color = stack_load_float3(stack, color_offset);
+ color = 2.0f * make_float3(color.x - 0.5f, color.y - 0.5f, color.z - 0.5f);
+
+ bool is_backfacing = (sd->flag & SD_BACKFACING) != 0;
+ float3 N;
+
+ if (space == NODE_NORMAL_MAP_TANGENT) {
+ /* tangent space */
+ if (sd->object == OBJECT_NONE || (sd->type & PRIMITIVE_ALL_TRIANGLE) == 0) {
+ /* Fallback to unperturbed normal. */
+ stack_store_float3(stack, normal_offset, sd->N);
+ return;
+ }
+
+ /* first try to get tangent attribute */
+ const AttributeDescriptor attr = find_attribute(kg, sd, node.z);
+ const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.w);
+
+ if (attr.offset == ATTR_STD_NOT_FOUND || attr_sign.offset == ATTR_STD_NOT_FOUND) {
+ /* Fallback to unperturbed normal. */
+ stack_store_float3(stack, normal_offset, sd->N);
+ return;
+ }
+
+ /* get _unnormalized_ interpolated normal and tangent */
+ float3 tangent = primitive_surface_attribute_float3(kg, sd, attr, NULL, NULL);
+ float sign = primitive_surface_attribute_float(kg, sd, attr_sign, NULL, NULL);
+ float3 normal;
+
+ if (sd->shader & SHADER_SMOOTH_NORMAL) {
+ normal = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
+ }
+ else {
+ normal = sd->Ng;
+
+ /* the normal is already inverted, which is too soon for the math here */
+ if (is_backfacing) {
+ normal = -normal;
+ }
+
+ object_inverse_normal_transform(kg, sd, &normal);
+ }
+
+ /* apply normal map */
+ float3 B = sign * cross(normal, tangent);
+ N = safe_normalize(color.x * tangent + color.y * B + color.z * normal);
+
+ /* transform to world space */
+ object_normal_transform(kg, sd, &N);
+ }
+ else {
+ /* strange blender convention */
+ if (space == NODE_NORMAL_MAP_BLENDER_OBJECT || space == NODE_NORMAL_MAP_BLENDER_WORLD) {
+ color.y = -color.y;
+ color.z = -color.z;
+ }
+
+ /* object, world space */
+ N = color;
+
+ if (space == NODE_NORMAL_MAP_OBJECT || space == NODE_NORMAL_MAP_BLENDER_OBJECT)
+ object_normal_transform(kg, sd, &N);
+ else
+ N = safe_normalize(N);
+ }
+
+ /* invert normal for backfacing polygons */
+ if (is_backfacing) {
+ N = -N;
+ }
+
+ float strength = stack_load_float(stack, strength_offset);
+
+ if (strength != 1.0f) {
+ strength = max(strength, 0.0f);
+ N = safe_normalize(sd->N + (N - sd->N) * strength);
+ }
+
+ if (is_zero(N)) {
+ N = sd->N;
+ }
+
+ stack_store_float3(stack, normal_offset, N);
+}
+
+ccl_device_noinline void svm_node_tangent(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint tangent_offset, direction_type, axis;
+ svm_unpack_node_uchar3(node.y, &tangent_offset, &direction_type, &axis);
+
+ float3 tangent;
+ float3 attribute_value;
+ const AttributeDescriptor desc = find_attribute(kg, sd, node.z);
+ if (desc.offset != ATTR_STD_NOT_FOUND) {
+ if (desc.type == NODE_ATTR_FLOAT2) {
+ float2 value = primitive_surface_attribute_float2(kg, sd, desc, NULL, NULL);
+ attribute_value.x = value.x;
+ attribute_value.y = value.y;
+ attribute_value.z = 0.0f;
+ }
+ else {
+ attribute_value = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
+ }
+ }
+
+ if (direction_type == NODE_TANGENT_UVMAP) {
+ /* UV map */
+ if (desc.offset == ATTR_STD_NOT_FOUND) {
+ stack_store_float3(stack, tangent_offset, zero_float3());
+ return;
+ }
+ else {
+ tangent = attribute_value;
+ }
+ }
+ else {
+ /* radial */
+ float3 generated;
+
+ if (desc.offset == ATTR_STD_NOT_FOUND)
+ generated = sd->P;
+ else
+ generated = attribute_value;
+
+ if (axis == NODE_TANGENT_AXIS_X)
+ tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f));
+ else if (axis == NODE_TANGENT_AXIS_Y)
+ tangent = make_float3(-(generated.z - 0.5f), 0.0f, (generated.x - 0.5f));
+ else
+ tangent = make_float3(-(generated.y - 0.5f), (generated.x - 0.5f), 0.0f);
+ }
+
+ object_normal_transform(kg, sd, &tangent);
+ tangent = cross(sd->N, normalize(cross(tangent, sd->N)));
+ stack_store_float3(stack, tangent_offset, tangent);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h
new file mode 100644
index 00000000000..8c95c571815
--- /dev/null
+++ b/intern/cycles/kernel/svm/types.h
@@ -0,0 +1,601 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Stack */
+
+/* SVM stack has a fixed size */
+#define SVM_STACK_SIZE 255
+/* SVM stack offsets with this value indicate that it's not on the stack */
+#define SVM_STACK_INVALID 255
+
+#define SVM_BUMP_EVAL_STATE_SIZE 9
+
+/* Nodes */
+
+typedef enum ShaderNodeType {
+ NODE_END = 0,
+ NODE_SHADER_JUMP,
+ NODE_CLOSURE_BSDF,
+ NODE_CLOSURE_EMISSION,
+ NODE_CLOSURE_BACKGROUND,
+ NODE_CLOSURE_SET_WEIGHT,
+ NODE_CLOSURE_WEIGHT,
+ NODE_EMISSION_WEIGHT,
+ NODE_MIX_CLOSURE,
+ NODE_JUMP_IF_ZERO,
+ NODE_JUMP_IF_ONE,
+ NODE_GEOMETRY,
+ NODE_CONVERT,
+ NODE_TEX_COORD,
+ NODE_VALUE_F,
+ NODE_VALUE_V,
+ NODE_ATTR,
+ NODE_VERTEX_COLOR,
+ NODE_GEOMETRY_BUMP_DX,
+ NODE_GEOMETRY_BUMP_DY,
+ NODE_SET_DISPLACEMENT,
+ NODE_DISPLACEMENT,
+ NODE_VECTOR_DISPLACEMENT,
+ NODE_TEX_IMAGE,
+ NODE_TEX_IMAGE_BOX,
+ NODE_TEX_NOISE,
+ NODE_SET_BUMP,
+ NODE_ATTR_BUMP_DX,
+ NODE_ATTR_BUMP_DY,
+ NODE_VERTEX_COLOR_BUMP_DX,
+ NODE_VERTEX_COLOR_BUMP_DY,
+ NODE_TEX_COORD_BUMP_DX,
+ NODE_TEX_COORD_BUMP_DY,
+ NODE_CLOSURE_SET_NORMAL,
+ NODE_ENTER_BUMP_EVAL,
+ NODE_LEAVE_BUMP_EVAL,
+ NODE_HSV,
+ NODE_CLOSURE_HOLDOUT,
+ NODE_FRESNEL,
+ NODE_LAYER_WEIGHT,
+ NODE_CLOSURE_VOLUME,
+ NODE_PRINCIPLED_VOLUME,
+ NODE_MATH,
+ NODE_VECTOR_MATH,
+ NODE_RGB_RAMP,
+ NODE_GAMMA,
+ NODE_BRIGHTCONTRAST,
+ NODE_LIGHT_PATH,
+ NODE_OBJECT_INFO,
+ NODE_PARTICLE_INFO,
+ NODE_HAIR_INFO,
+ NODE_TEXTURE_MAPPING,
+ NODE_MAPPING,
+ NODE_MIN_MAX,
+ NODE_CAMERA,
+ NODE_TEX_ENVIRONMENT,
+ NODE_TEX_SKY,
+ NODE_TEX_GRADIENT,
+ NODE_TEX_VORONOI,
+ NODE_TEX_MUSGRAVE,
+ NODE_TEX_WAVE,
+ NODE_TEX_MAGIC,
+ NODE_TEX_CHECKER,
+ NODE_TEX_BRICK,
+ NODE_TEX_WHITE_NOISE,
+ NODE_NORMAL,
+ NODE_LIGHT_FALLOFF,
+ NODE_IES,
+ NODE_RGB_CURVES,
+ NODE_VECTOR_CURVES,
+ NODE_TANGENT,
+ NODE_NORMAL_MAP,
+ NODE_INVERT,
+ NODE_MIX,
+ NODE_SEPARATE_VECTOR,
+ NODE_COMBINE_VECTOR,
+ NODE_SEPARATE_HSV,
+ NODE_COMBINE_HSV,
+ NODE_VECTOR_ROTATE,
+ NODE_VECTOR_TRANSFORM,
+ NODE_WIREFRAME,
+ NODE_WAVELENGTH,
+ NODE_BLACKBODY,
+ NODE_MAP_RANGE,
+ NODE_CLAMP,
+ NODE_BEVEL,
+ NODE_AMBIENT_OCCLUSION,
+ NODE_TEX_VOXEL,
+ NODE_AOV_START,
+ NODE_AOV_COLOR,
+ NODE_AOV_VALUE,
+ NODE_FLOAT_CURVE,
+ /* NOTE: for best OpenCL performance, item definition in the enum must
+ * match the switch case order in svm.h. */
+} ShaderNodeType;
+
+typedef enum NodeAttributeOutputType {
+ NODE_ATTR_OUTPUT_FLOAT3 = 0,
+ NODE_ATTR_OUTPUT_FLOAT,
+ NODE_ATTR_OUTPUT_FLOAT_ALPHA,
+} NodeAttributeOutputType;
+
+typedef enum NodeAttributeType {
+ NODE_ATTR_FLOAT = 0,
+ NODE_ATTR_FLOAT2,
+ NODE_ATTR_FLOAT3,
+ NODE_ATTR_FLOAT4,
+ NODE_ATTR_RGBA,
+ NODE_ATTR_MATRIX
+} NodeAttributeType;
+
+typedef enum NodeGeometry {
+ NODE_GEOM_P = 0,
+ NODE_GEOM_N,
+ NODE_GEOM_T,
+ NODE_GEOM_I,
+ NODE_GEOM_Ng,
+ NODE_GEOM_uv
+} NodeGeometry;
+
+typedef enum NodeObjectInfo {
+ NODE_INFO_OB_LOCATION,
+ NODE_INFO_OB_COLOR,
+ NODE_INFO_OB_INDEX,
+ NODE_INFO_MAT_INDEX,
+ NODE_INFO_OB_RANDOM
+} NodeObjectInfo;
+
+typedef enum NodeParticleInfo {
+ NODE_INFO_PAR_INDEX,
+ NODE_INFO_PAR_RANDOM,
+ NODE_INFO_PAR_AGE,
+ NODE_INFO_PAR_LIFETIME,
+ NODE_INFO_PAR_LOCATION,
+ NODE_INFO_PAR_ROTATION,
+ NODE_INFO_PAR_SIZE,
+ NODE_INFO_PAR_VELOCITY,
+ NODE_INFO_PAR_ANGULAR_VELOCITY
+} NodeParticleInfo;
+
+typedef enum NodeHairInfo {
+ NODE_INFO_CURVE_IS_STRAND,
+ NODE_INFO_CURVE_INTERCEPT,
+ NODE_INFO_CURVE_LENGTH,
+ NODE_INFO_CURVE_THICKNESS,
+ /* Fade for minimum hair width transiency. */
+ // NODE_INFO_CURVE_FADE,
+ NODE_INFO_CURVE_TANGENT_NORMAL,
+ NODE_INFO_CURVE_RANDOM,
+} NodeHairInfo;
+
+typedef enum NodeLightPath {
+ NODE_LP_camera = 0,
+ NODE_LP_shadow,
+ NODE_LP_diffuse,
+ NODE_LP_glossy,
+ NODE_LP_singular,
+ NODE_LP_reflection,
+ NODE_LP_transmission,
+ NODE_LP_volume_scatter,
+ NODE_LP_backfacing,
+ NODE_LP_ray_length,
+ NODE_LP_ray_depth,
+ NODE_LP_ray_diffuse,
+ NODE_LP_ray_glossy,
+ NODE_LP_ray_transparent,
+ NODE_LP_ray_transmission,
+} NodeLightPath;
+
+typedef enum NodeLightFalloff {
+ NODE_LIGHT_FALLOFF_QUADRATIC,
+ NODE_LIGHT_FALLOFF_LINEAR,
+ NODE_LIGHT_FALLOFF_CONSTANT
+} NodeLightFalloff;
+
+typedef enum NodeTexCoord {
+ NODE_TEXCO_NORMAL,
+ NODE_TEXCO_OBJECT,
+ NODE_TEXCO_CAMERA,
+ NODE_TEXCO_WINDOW,
+ NODE_TEXCO_REFLECTION,
+ NODE_TEXCO_DUPLI_GENERATED,
+ NODE_TEXCO_DUPLI_UV,
+ NODE_TEXCO_VOLUME_GENERATED
+} NodeTexCoord;
+
+typedef enum NodeMix {
+ NODE_MIX_BLEND = 0,
+ NODE_MIX_ADD,
+ NODE_MIX_MUL,
+ NODE_MIX_SUB,
+ NODE_MIX_SCREEN,
+ NODE_MIX_DIV,
+ NODE_MIX_DIFF,
+ NODE_MIX_DARK,
+ NODE_MIX_LIGHT,
+ NODE_MIX_OVERLAY,
+ NODE_MIX_DODGE,
+ NODE_MIX_BURN,
+ NODE_MIX_HUE,
+ NODE_MIX_SAT,
+ NODE_MIX_VAL,
+ NODE_MIX_COLOR,
+ NODE_MIX_SOFT,
+ NODE_MIX_LINEAR,
+ NODE_MIX_CLAMP /* used for the clamp UI option */
+} NodeMix;
+
+typedef enum NodeMathType {
+ NODE_MATH_ADD,
+ NODE_MATH_SUBTRACT,
+ NODE_MATH_MULTIPLY,
+ NODE_MATH_DIVIDE,
+ NODE_MATH_SINE,
+ NODE_MATH_COSINE,
+ NODE_MATH_TANGENT,
+ NODE_MATH_ARCSINE,
+ NODE_MATH_ARCCOSINE,
+ NODE_MATH_ARCTANGENT,
+ NODE_MATH_POWER,
+ NODE_MATH_LOGARITHM,
+ NODE_MATH_MINIMUM,
+ NODE_MATH_MAXIMUM,
+ NODE_MATH_ROUND,
+ NODE_MATH_LESS_THAN,
+ NODE_MATH_GREATER_THAN,
+ NODE_MATH_MODULO,
+ NODE_MATH_ABSOLUTE,
+ NODE_MATH_ARCTAN2,
+ NODE_MATH_FLOOR,
+ NODE_MATH_CEIL,
+ NODE_MATH_FRACTION,
+ NODE_MATH_SQRT,
+ NODE_MATH_INV_SQRT,
+ NODE_MATH_SIGN,
+ NODE_MATH_EXPONENT,
+ NODE_MATH_RADIANS,
+ NODE_MATH_DEGREES,
+ NODE_MATH_SINH,
+ NODE_MATH_COSH,
+ NODE_MATH_TANH,
+ NODE_MATH_TRUNC,
+ NODE_MATH_SNAP,
+ NODE_MATH_WRAP,
+ NODE_MATH_COMPARE,
+ NODE_MATH_MULTIPLY_ADD,
+ NODE_MATH_PINGPONG,
+ NODE_MATH_SMOOTH_MIN,
+ NODE_MATH_SMOOTH_MAX,
+} NodeMathType;
+
+typedef enum NodeVectorMathType {
+ NODE_VECTOR_MATH_ADD,
+ NODE_VECTOR_MATH_SUBTRACT,
+ NODE_VECTOR_MATH_MULTIPLY,
+ NODE_VECTOR_MATH_DIVIDE,
+
+ NODE_VECTOR_MATH_CROSS_PRODUCT,
+ NODE_VECTOR_MATH_PROJECT,
+ NODE_VECTOR_MATH_REFLECT,
+ NODE_VECTOR_MATH_DOT_PRODUCT,
+
+ NODE_VECTOR_MATH_DISTANCE,
+ NODE_VECTOR_MATH_LENGTH,
+ NODE_VECTOR_MATH_SCALE,
+ NODE_VECTOR_MATH_NORMALIZE,
+
+ NODE_VECTOR_MATH_SNAP,
+ NODE_VECTOR_MATH_FLOOR,
+ NODE_VECTOR_MATH_CEIL,
+ NODE_VECTOR_MATH_MODULO,
+ NODE_VECTOR_MATH_FRACTION,
+ NODE_VECTOR_MATH_ABSOLUTE,
+ NODE_VECTOR_MATH_MINIMUM,
+ NODE_VECTOR_MATH_MAXIMUM,
+ NODE_VECTOR_MATH_WRAP,
+ NODE_VECTOR_MATH_SINE,
+ NODE_VECTOR_MATH_COSINE,
+ NODE_VECTOR_MATH_TANGENT,
+ NODE_VECTOR_MATH_REFRACT,
+ NODE_VECTOR_MATH_FACEFORWARD,
+ NODE_VECTOR_MATH_MULTIPLY_ADD,
+} NodeVectorMathType;
+
+typedef enum NodeClampType {
+ NODE_CLAMP_MINMAX,
+ NODE_CLAMP_RANGE,
+} NodeClampType;
+
+typedef enum NodeMapRangeType {
+ NODE_MAP_RANGE_LINEAR,
+ NODE_MAP_RANGE_STEPPED,
+ NODE_MAP_RANGE_SMOOTHSTEP,
+ NODE_MAP_RANGE_SMOOTHERSTEP,
+} NodeMapRangeType;
+
+typedef enum NodeMappingType {
+ NODE_MAPPING_TYPE_POINT,
+ NODE_MAPPING_TYPE_TEXTURE,
+ NODE_MAPPING_TYPE_VECTOR,
+ NODE_MAPPING_TYPE_NORMAL
+} NodeMappingType;
+
+typedef enum NodeVectorRotateType {
+ NODE_VECTOR_ROTATE_TYPE_AXIS,
+ NODE_VECTOR_ROTATE_TYPE_AXIS_X,
+ NODE_VECTOR_ROTATE_TYPE_AXIS_Y,
+ NODE_VECTOR_ROTATE_TYPE_AXIS_Z,
+ NODE_VECTOR_ROTATE_TYPE_EULER_XYZ,
+} NodeVectorRotateType;
+
+typedef enum NodeVectorTransformType {
+ NODE_VECTOR_TRANSFORM_TYPE_VECTOR,
+ NODE_VECTOR_TRANSFORM_TYPE_POINT,
+ NODE_VECTOR_TRANSFORM_TYPE_NORMAL
+} NodeVectorTransformType;
+
+typedef enum NodeVectorTransformConvertSpace {
+ NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD,
+ NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT,
+ NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA
+} NodeVectorTransformConvertSpace;
+
+typedef enum NodeConvert {
+ NODE_CONVERT_FV,
+ NODE_CONVERT_FI,
+ NODE_CONVERT_CF,
+ NODE_CONVERT_CI,
+ NODE_CONVERT_VF,
+ NODE_CONVERT_VI,
+ NODE_CONVERT_IF,
+ NODE_CONVERT_IV
+} NodeConvert;
+
+typedef enum NodeMusgraveType {
+ NODE_MUSGRAVE_MULTIFRACTAL,
+ NODE_MUSGRAVE_FBM,
+ NODE_MUSGRAVE_HYBRID_MULTIFRACTAL,
+ NODE_MUSGRAVE_RIDGED_MULTIFRACTAL,
+ NODE_MUSGRAVE_HETERO_TERRAIN
+} NodeMusgraveType;
+
+typedef enum NodeWaveType { NODE_WAVE_BANDS, NODE_WAVE_RINGS } NodeWaveType;
+
+typedef enum NodeWaveBandsDirection {
+ NODE_WAVE_BANDS_DIRECTION_X,
+ NODE_WAVE_BANDS_DIRECTION_Y,
+ NODE_WAVE_BANDS_DIRECTION_Z,
+ NODE_WAVE_BANDS_DIRECTION_DIAGONAL
+} NodeWaveBandsDirection;
+
+typedef enum NodeWaveRingsDirection {
+ NODE_WAVE_RINGS_DIRECTION_X,
+ NODE_WAVE_RINGS_DIRECTION_Y,
+ NODE_WAVE_RINGS_DIRECTION_Z,
+ NODE_WAVE_RINGS_DIRECTION_SPHERICAL
+} NodeWaveRingsDirection;
+
+typedef enum NodeWaveProfile {
+ NODE_WAVE_PROFILE_SIN,
+ NODE_WAVE_PROFILE_SAW,
+ NODE_WAVE_PROFILE_TRI,
+} NodeWaveProfile;
+
+typedef enum NodeSkyType { NODE_SKY_PREETHAM, NODE_SKY_HOSEK, NODE_SKY_NISHITA } NodeSkyType;
+
+typedef enum NodeGradientType {
+ NODE_BLEND_LINEAR,
+ NODE_BLEND_QUADRATIC,
+ NODE_BLEND_EASING,
+ NODE_BLEND_DIAGONAL,
+ NODE_BLEND_RADIAL,
+ NODE_BLEND_QUADRATIC_SPHERE,
+ NODE_BLEND_SPHERICAL
+} NodeGradientType;
+
+typedef enum NodeVoronoiDistanceMetric {
+ NODE_VORONOI_EUCLIDEAN,
+ NODE_VORONOI_MANHATTAN,
+ NODE_VORONOI_CHEBYCHEV,
+ NODE_VORONOI_MINKOWSKI,
+} NodeVoronoiDistanceMetric;
+
+typedef enum NodeVoronoiFeature {
+ NODE_VORONOI_F1,
+ NODE_VORONOI_F2,
+ NODE_VORONOI_SMOOTH_F1,
+ NODE_VORONOI_DISTANCE_TO_EDGE,
+ NODE_VORONOI_N_SPHERE_RADIUS,
+} NodeVoronoiFeature;
+
+typedef enum NodeBlendWeightType {
+ NODE_LAYER_WEIGHT_FRESNEL,
+ NODE_LAYER_WEIGHT_FACING
+} NodeBlendWeightType;
+
+typedef enum NodeTangentDirectionType {
+ NODE_TANGENT_RADIAL,
+ NODE_TANGENT_UVMAP
+} NodeTangentDirectionType;
+
+typedef enum NodeTangentAxis {
+ NODE_TANGENT_AXIS_X,
+ NODE_TANGENT_AXIS_Y,
+ NODE_TANGENT_AXIS_Z
+} NodeTangentAxis;
+
+typedef enum NodeNormalMapSpace {
+ NODE_NORMAL_MAP_TANGENT,
+ NODE_NORMAL_MAP_OBJECT,
+ NODE_NORMAL_MAP_WORLD,
+ NODE_NORMAL_MAP_BLENDER_OBJECT,
+ NODE_NORMAL_MAP_BLENDER_WORLD,
+} NodeNormalMapSpace;
+
+typedef enum NodeImageProjection {
+ NODE_IMAGE_PROJ_FLAT = 0,
+ NODE_IMAGE_PROJ_BOX = 1,
+ NODE_IMAGE_PROJ_SPHERE = 2,
+ NODE_IMAGE_PROJ_TUBE = 3,
+} NodeImageProjection;
+
+typedef enum NodeImageFlags {
+ NODE_IMAGE_COMPRESS_AS_SRGB = 1,
+ NODE_IMAGE_ALPHA_UNASSOCIATE = 2,
+} NodeImageFlags;
+
+typedef enum NodeEnvironmentProjection {
+ NODE_ENVIRONMENT_EQUIRECTANGULAR = 0,
+ NODE_ENVIRONMENT_MIRROR_BALL = 1,
+} NodeEnvironmentProjection;
+
+typedef enum NodeBumpOffset {
+ NODE_BUMP_OFFSET_CENTER,
+ NODE_BUMP_OFFSET_DX,
+ NODE_BUMP_OFFSET_DY,
+} NodeBumpOffset;
+
+typedef enum NodeTexVoxelSpace {
+ NODE_TEX_VOXEL_SPACE_OBJECT = 0,
+ NODE_TEX_VOXEL_SPACE_WORLD = 1,
+} NodeTexVoxelSpace;
+
+typedef enum NodeAO {
+ NODE_AO_ONLY_LOCAL = (1 << 0),
+ NODE_AO_INSIDE = (1 << 1),
+ NODE_AO_GLOBAL_RADIUS = (1 << 2),
+} NodeAO;
+
+typedef enum ShaderType {
+ SHADER_TYPE_SURFACE,
+ SHADER_TYPE_VOLUME,
+ SHADER_TYPE_DISPLACEMENT,
+ SHADER_TYPE_BUMP,
+} ShaderType;
+
+typedef enum NodePrincipledHairParametrization {
+ NODE_PRINCIPLED_HAIR_REFLECTANCE = 0,
+ NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION = 1,
+ NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION = 2,
+ NODE_PRINCIPLED_HAIR_NUM,
+} NodePrincipledHairParametrization;
+
+/* Closure */
+
+typedef enum ClosureType {
+ /* Special type, flags generic node as a non-BSDF. */
+ CLOSURE_NONE_ID,
+
+ CLOSURE_BSDF_ID,
+
+ /* Diffuse */
+ CLOSURE_BSDF_DIFFUSE_ID,
+ CLOSURE_BSDF_OREN_NAYAR_ID,
+ CLOSURE_BSDF_DIFFUSE_RAMP_ID,
+ CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID,
+ CLOSURE_BSDF_PRINCIPLED_SHEEN_ID,
+ CLOSURE_BSDF_DIFFUSE_TOON_ID,
+ CLOSURE_BSDF_TRANSLUCENT_ID,
+
+ /* Glossy */
+ CLOSURE_BSDF_REFLECTION_ID,
+ CLOSURE_BSDF_MICROFACET_GGX_ID,
+ CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID,
+ CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID,
+ CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
+ CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID,
+ CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID,
+ CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID,
+ CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
+ CLOSURE_BSDF_PHONG_RAMP_ID,
+ CLOSURE_BSDF_GLOSSY_TOON_ID,
+ CLOSURE_BSDF_HAIR_REFLECTION_ID,
+
+ /* Transmission */
+ CLOSURE_BSDF_REFRACTION_ID,
+ CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID,
+ CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
+ CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID,
+ CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
+ CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
+ CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID,
+ CLOSURE_BSDF_SHARP_GLASS_ID,
+ CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
+ CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
+
+ /* Special cases */
+ CLOSURE_BSDF_TRANSPARENT_ID,
+
+ /* BSSRDF */
+ CLOSURE_BSSRDF_BURLEY_ID,
+ CLOSURE_BSSRDF_RANDOM_WALK_ID,
+ CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID,
+
+ /* Other */
+ CLOSURE_HOLDOUT_ID,
+
+ /* Volume */
+ CLOSURE_VOLUME_ID,
+ CLOSURE_VOLUME_ABSORPTION_ID,
+ CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID,
+
+ CLOSURE_BSDF_PRINCIPLED_ID,
+
+ NBUILTIN_CLOSURES
+} ClosureType;
+
+/* watch this, being lazy with memory usage */
+#define CLOSURE_IS_BSDF(type) (type <= CLOSURE_BSDF_TRANSPARENT_ID)
+#define CLOSURE_IS_BSDF_DIFFUSE(type) \
+ (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_TRANSLUCENT_ID)
+#define CLOSURE_IS_BSDF_GLOSSY(type) \
+ ((type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID) || \
+ (type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID))
+#define CLOSURE_IS_BSDF_TRANSMISSION(type) \
+ (type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
+#define CLOSURE_IS_BSDF_SINGULAR(type) \
+ (type == CLOSURE_BSDF_REFLECTION_ID || type == CLOSURE_BSDF_REFRACTION_ID || \
+ type == CLOSURE_BSDF_TRANSPARENT_ID)
+#define CLOSURE_IS_BSDF_TRANSPARENT(type) (type == CLOSURE_BSDF_TRANSPARENT_ID)
+#define CLOSURE_IS_BSDF_MULTISCATTER(type) \
+ (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID || \
+ type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
+#define CLOSURE_IS_BSDF_MICROFACET(type) \
+ ((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
+ (type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
+ type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) || \
+ (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID))
+#define CLOSURE_IS_BSDF_MICROFACET_FRESNEL(type) \
+ (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID || \
+ type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID || \
+ type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID || \
+ type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID)
+#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
+#define CLOSURE_IS_BSSRDF(type) \
+ (type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
+#define CLOSURE_IS_VOLUME(type) \
+ (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
+#define CLOSURE_IS_VOLUME_SCATTER(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
+#define CLOSURE_IS_VOLUME_ABSORPTION(type) (type == CLOSURE_VOLUME_ABSORPTION_ID)
+#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
+#define CLOSURE_IS_PHASE(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
+#define CLOSURE_IS_GLASS(type) \
+ (type >= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID)
+#define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID)
+
+#define CLOSURE_WEIGHT_CUTOFF 1e-5f
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/value.h b/intern/cycles/kernel/svm/value.h
new file mode 100644
index 00000000000..cc62f1e2a82
--- /dev/null
+++ b/intern/cycles/kernel/svm/value.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Value Nodes */
+
+ccl_device void svm_node_value_f(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint ivalue,
+ uint out_offset)
+{
+ stack_store_float(stack, out_offset, __uint_as_float(ivalue));
+}
+
+ccl_device int svm_node_value_v(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint out_offset,
+ int offset)
+{
+ /* read extra data */
+ uint4 node1 = read_node(kg, &offset);
+ float3 p = make_float3(
+ __uint_as_float(node1.y), __uint_as_float(node1.z), __uint_as_float(node1.w));
+
+ stack_store_float3(stack, out_offset, p);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/vector_rotate.h b/intern/cycles/kernel/svm/vector_rotate.h
new file mode 100644
index 00000000000..2a0d331734c
--- /dev/null
+++ b/intern/cycles/kernel/svm/vector_rotate.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Vector Rotate */
+
+ccl_device_noinline void svm_node_vector_rotate(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint input_stack_offsets,
+ uint axis_stack_offsets,
+ uint result_stack_offset)
+{
+ uint type, vector_stack_offset, rotation_stack_offset, center_stack_offset, axis_stack_offset,
+ angle_stack_offset, invert;
+
+ svm_unpack_node_uchar4(
+ input_stack_offsets, &type, &vector_stack_offset, &rotation_stack_offset, &invert);
+ svm_unpack_node_uchar3(
+ axis_stack_offsets, &center_stack_offset, &axis_stack_offset, &angle_stack_offset);
+
+ if (stack_valid(result_stack_offset)) {
+
+ float3 vector = stack_load_float3(stack, vector_stack_offset);
+ float3 center = stack_load_float3(stack, center_stack_offset);
+ float3 result = make_float3(0.0f, 0.0f, 0.0f);
+
+ if (type == NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
+ float3 rotation = stack_load_float3(stack, rotation_stack_offset); // Default XYZ.
+ Transform rotationTransform = euler_to_transform(rotation);
+ if (invert) {
+ result = transform_direction_transposed(&rotationTransform, vector - center) + center;
+ }
+ else {
+ result = transform_direction(&rotationTransform, vector - center) + center;
+ }
+ }
+ else {
+ float3 axis;
+ float axis_length;
+ switch (type) {
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_X:
+ axis = make_float3(1.0f, 0.0f, 0.0f);
+ axis_length = 1.0f;
+ break;
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_Y:
+ axis = make_float3(0.0f, 1.0f, 0.0f);
+ axis_length = 1.0f;
+ break;
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_Z:
+ axis = make_float3(0.0f, 0.0f, 1.0f);
+ axis_length = 1.0f;
+ break;
+ default:
+ axis = stack_load_float3(stack, axis_stack_offset);
+ axis_length = len(axis);
+ break;
+ }
+ float angle = stack_load_float(stack, angle_stack_offset);
+ angle = invert ? -angle : angle;
+ result = (axis_length != 0.0f) ?
+ rotate_around_axis(vector - center, axis / axis_length, angle) + center :
+ vector;
+ }
+
+ stack_store_float3(stack, result_stack_offset, result);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/vector_transform.h b/intern/cycles/kernel/svm/vector_transform.h
new file mode 100644
index 00000000000..d7a51078cea
--- /dev/null
+++ b/intern/cycles/kernel/svm/vector_transform.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Vector Transform */
+
+ccl_device_noinline void svm_node_vector_transform(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint itype, ifrom, ito;
+ uint vector_in, vector_out;
+
+ svm_unpack_node_uchar3(node.y, &itype, &ifrom, &ito);
+ svm_unpack_node_uchar2(node.z, &vector_in, &vector_out);
+
+ float3 in = stack_load_float3(stack, vector_in);
+
+ NodeVectorTransformType type = (NodeVectorTransformType)itype;
+ NodeVectorTransformConvertSpace from = (NodeVectorTransformConvertSpace)ifrom;
+ NodeVectorTransformConvertSpace to = (NodeVectorTransformConvertSpace)ito;
+
+ Transform tfm;
+ bool is_object = (sd->object != OBJECT_NONE);
+ bool is_direction = (type == NODE_VECTOR_TRANSFORM_TYPE_VECTOR ||
+ type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
+
+ /* From world */
+ if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD) {
+ if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
+ tfm = kernel_data.cam.worldtocamera;
+ if (is_direction)
+ in = transform_direction(&tfm, in);
+ else
+ in = transform_point(&tfm, in);
+ }
+ else if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT && is_object) {
+ if (is_direction)
+ object_inverse_dir_transform(kg, sd, &in);
+ else
+ object_inverse_position_transform(kg, sd, &in);
+ }
+ }
+
+ /* From camera */
+ else if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
+ if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD ||
+ to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT) {
+ tfm = kernel_data.cam.cameratoworld;
+ if (is_direction)
+ in = transform_direction(&tfm, in);
+ else
+ in = transform_point(&tfm, in);
+ }
+ if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT && is_object) {
+ if (is_direction)
+ object_inverse_dir_transform(kg, sd, &in);
+ else
+ object_inverse_position_transform(kg, sd, &in);
+ }
+ }
+
+ /* From object */
+ else if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT) {
+ if ((to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD ||
+ to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) &&
+ is_object) {
+ if (is_direction)
+ object_dir_transform(kg, sd, &in);
+ else
+ object_position_transform(kg, sd, &in);
+ }
+ if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
+ tfm = kernel_data.cam.worldtocamera;
+ if (is_direction)
+ in = transform_direction(&tfm, in);
+ else
+ in = transform_point(&tfm, in);
+ }
+ }
+
+ /* Normalize Normal */
+ if (type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL)
+ in = normalize(in);
+
+ /* Output */
+ if (stack_valid(vector_out)) {
+ stack_store_float3(stack, vector_out, in);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/vertex_color.h b/intern/cycles/kernel/svm/vertex_color.h
new file mode 100644
index 00000000000..b676a28c0e3
--- /dev/null
+++ b/intern/cycles/kernel/svm/vertex_color.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline void svm_node_vertex_color(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint layer_id,
+ uint color_offset,
+ uint alpha_offset)
+{
+ AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
+ if (descriptor.offset != ATTR_STD_NOT_FOUND) {
+ float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, NULL, NULL);
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
+ stack_store_float(stack, alpha_offset, 0.0f);
+ }
+}
+
+ccl_device_noinline void svm_node_vertex_color_bump_dx(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint layer_id,
+ uint color_offset,
+ uint alpha_offset)
+{
+ AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
+ if (descriptor.offset != ATTR_STD_NOT_FOUND) {
+ float4 dx;
+ float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, &dx, NULL);
+ vertex_color += dx;
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
+ stack_store_float(stack, alpha_offset, 0.0f);
+ }
+}
+
+ccl_device_noinline void svm_node_vertex_color_bump_dy(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint layer_id,
+ uint color_offset,
+ uint alpha_offset)
+{
+ AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
+ if (descriptor.offset != ATTR_STD_NOT_FOUND) {
+ float4 dy;
+ float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, NULL, &dy);
+ vertex_color += dy;
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
+ stack_store_float(stack, alpha_offset, 0.0f);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/voronoi.h b/intern/cycles/kernel/svm/voronoi.h
new file mode 100644
index 00000000000..730965b6aed
--- /dev/null
+++ b/intern/cycles/kernel/svm/voronoi.h
@@ -0,0 +1,1164 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/*
+ * Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez.
+ *
+ * Smooth Voronoi:
+ *
+ * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
+ *
+ * Distance To Edge based on:
+ *
+ * - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm
+ * - https://www.shadertoy.com/view/ldl3W8
+ *
+ * With optimization to change -2..2 scan window to -1..1 for better performance,
+ * as explained in https://www.shadertoy.com/view/llG3zy.
+ */
+
+/* **** 1D Voronoi **** */
+
+ccl_device float voronoi_distance_1d(float a,
+ float b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ return fabsf(b - a);
+}
+
+ccl_device void voronoi_f1_1d(float w,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0f;
+ float targetOffset = 0.0f;
+ float targetPosition = 0.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float_to_float3(cellPosition + targetOffset);
+ *outW = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_1d(float w,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float smoothDistance = 8.0f;
+ float smoothPosition = 0.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ for (int i = -2; i <= 2; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outW = cellPosition + smoothPosition;
+}
+
+ccl_device void voronoi_f2_1d(float w,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float offsetF1 = 0.0f;
+ float positionF1 = 0.0f;
+ float offsetF2 = 0.0f;
+ float positionF2 = 0.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float_to_float3(cellPosition + offsetF2);
+ *outW = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_1d(float w,
+ float randomness,
+ ccl_private float *outDistance)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float midPointPosition = hash_float_to_float(cellPosition) * randomness;
+ float leftPointPosition = -1.0f + hash_float_to_float(cellPosition - 1.0f) * randomness;
+ float rightPointPosition = 1.0f + hash_float_to_float(cellPosition + 1.0f) * randomness;
+ float distanceToMidLeft = fabsf((midPointPosition + leftPointPosition) / 2.0f - localPosition);
+ float distanceToMidRight = fabsf((midPointPosition + rightPointPosition) / 2.0f - localPosition);
+
+ *outDistance = min(distanceToMidLeft, distanceToMidRight);
+}
+
+ccl_device void voronoi_n_sphere_radius_1d(float w, float randomness, ccl_private float *outRadius)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float closestPoint = 0.0f;
+ float closestPointOffset = 0.0f;
+ float minDistance = 8.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = fabsf(pointPosition - localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0f;
+ float closestPointToClosestPoint = 0.0f;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0) {
+ continue;
+ }
+ float cellOffset = i + closestPointOffset;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = fabsf(closestPoint - pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ *outRadius = fabsf(closestPointToClosestPoint - closestPoint) / 2.0f;
+}
+
+/* **** 2D Voronoi **** */
+
+ccl_device float voronoi_distance_2d(float2 a,
+ float2 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN) {
+ return distance(a, b);
+ }
+ else if (metric == NODE_VORONOI_MANHATTAN) {
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y);
+ }
+ else if (metric == NODE_VORONOI_CHEBYCHEV) {
+ return max(fabsf(a.x - b.x), fabsf(a.y - b.y));
+ }
+ else if (metric == NODE_VORONOI_MINKOWSKI) {
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent),
+ 1.0f / exponent);
+ }
+ else {
+ return 0.0f;
+ }
+}
+
+ccl_device void voronoi_f1_2d(float2 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float2 targetOffset = make_float2(0.0f, 0.0f);
+ float2 targetPosition = make_float2(0.0f, 0.0f);
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float2_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_2d(float2 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float2 smoothPosition = make_float2(0.0f, 0.0f);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float2_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outPosition = cellPosition + smoothPosition;
+}
+
+ccl_device void voronoi_f2_2d(float2 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float2 offsetF1 = make_float2(0.0f, 0.0f);
+ float2 positionF1 = make_float2(0.0f, 0.0f);
+ float2 offsetF2 = make_float2(0.0f, 0.0f);
+ float2 positionF2 = make_float2(0.0f, 0.0f);
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float2_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_2d(float2 coord,
+ float randomness,
+ ccl_private float *outDistance)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float2 vectorToClosest = make_float2(0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 vectorToPoint = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 vectorToPoint = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_2d(float2 coord,
+ float randomness,
+ ccl_private float *outRadius)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float2 closestPoint = make_float2(0.0f, 0.0f);
+ float2 closestPointOffset = make_float2(0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float2 closestPointToClosestPoint = make_float2(0.0f, 0.0f);
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0) {
+ continue;
+ }
+ float2 cellOffset = make_float2(i, j) + closestPointOffset;
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/* **** 3D Voronoi **** */
+
+ccl_device float voronoi_distance_3d(float3 a,
+ float3 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN) {
+ return distance(a, b);
+ }
+ else if (metric == NODE_VORONOI_MANHATTAN) {
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z);
+ }
+ else if (metric == NODE_VORONOI_CHEBYCHEV) {
+ return max(fabsf(a.x - b.x), max(fabsf(a.y - b.y), fabsf(a.z - b.z)));
+ }
+ else if (metric == NODE_VORONOI_MINKOWSKI) {
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
+ powf(fabsf(a.z - b.z), exponent),
+ 1.0f / exponent);
+ }
+ else {
+ return 0.0f;
+ }
+}
+
+ccl_device void voronoi_f1_3d(float3 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float3 targetOffset = make_float3(0.0f, 0.0f, 0.0f);
+ float3 targetPosition = make_float3(0.0f, 0.0f, 0.0f);
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float3_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_3d(float3 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float3 smoothPosition = make_float3(0.0f, 0.0f, 0.0f);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float3_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outPosition = cellPosition + smoothPosition;
+}
+
+ccl_device void voronoi_f2_3d(float3 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float3 offsetF1 = make_float3(0.0f, 0.0f, 0.0f);
+ float3 positionF1 = make_float3(0.0f, 0.0f, 0.0f);
+ float3 offsetF2 = make_float3(0.0f, 0.0f, 0.0f);
+ float3 positionF2 = make_float3(0.0f, 0.0f, 0.0f);
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float3_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_3d(float3 coord,
+ float randomness,
+ ccl_private float *outDistance)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float3 vectorToClosest = make_float3(0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 vectorToPoint = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 vectorToPoint = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_3d(float3 coord,
+ float randomness,
+ ccl_private float *outRadius)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float3 closestPoint = make_float3(0.0f, 0.0f, 0.0f);
+ float3 closestPointOffset = make_float3(0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float3 closestPointToClosestPoint = make_float3(0.0f, 0.0f, 0.0f);
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0) {
+ continue;
+ }
+ float3 cellOffset = make_float3(i, j, k) + closestPointOffset;
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/* **** 4D Voronoi **** */
+
+ccl_device float voronoi_distance_4d(float4 a,
+ float4 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN) {
+ return distance(a, b);
+ }
+ else if (metric == NODE_VORONOI_MANHATTAN) {
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z) + fabsf(a.w - b.w);
+ }
+ else if (metric == NODE_VORONOI_CHEBYCHEV) {
+ return max(fabsf(a.x - b.x), max(fabsf(a.y - b.y), max(fabsf(a.z - b.z), fabsf(a.w - b.w))));
+ }
+ else if (metric == NODE_VORONOI_MINKOWSKI) {
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
+ powf(fabsf(a.z - b.z), exponent) + powf(fabsf(a.w - b.w), exponent),
+ 1.0f / exponent);
+ }
+ else {
+ return 0.0f;
+ }
+}
+
+ccl_device void voronoi_f1_4d(float4 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float4 targetOffset = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 targetPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float4_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_4d(float4 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float4 smoothPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -2; u <= 2; u++) {
+ for (int k = -2; k <= 2; k++) {
+ ccl_loop_no_unroll for (int j = -2; j <= 2; j++)
+ {
+ for (int i = -2; i <= 2; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float4_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ }
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outPosition = cellPosition + smoothPosition;
+}
+
+ccl_device void voronoi_f2_4d(float4 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ ccl_private float *outDistance,
+ ccl_private float3 *outColor,
+ ccl_private float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float4 offsetF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 positionF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 offsetF2 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 positionF2 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float4_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_4d(float4 coord,
+ float randomness,
+ ccl_private float *outDistance)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float4 vectorToClosest = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 vectorToPoint = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 vectorToPoint = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_4d(float4 coord,
+ float randomness,
+ ccl_private float *outRadius)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float4 closestPoint = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 closestPointOffset = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float4 closestPointToClosestPoint = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
+ {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0 && u == 0) {
+ continue;
+ }
+ float4 cellOffset = make_float4(i, j, k, u) + closestPointOffset;
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+template<uint node_feature_mask>
+ccl_device_noinline int svm_node_tex_voronoi(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint dimensions,
+ uint feature,
+ uint metric,
+ int offset)
+{
+ uint4 stack_offsets = read_node(kg, &offset);
+ uint4 defaults = read_node(kg, &offset);
+
+ uint coord_stack_offset, w_stack_offset, scale_stack_offset, smoothness_stack_offset;
+ uint exponent_stack_offset, randomness_stack_offset, distance_out_stack_offset,
+ color_out_stack_offset;
+ uint position_out_stack_offset, w_out_stack_offset, radius_out_stack_offset;
+
+ svm_unpack_node_uchar4(stack_offsets.x,
+ &coord_stack_offset,
+ &w_stack_offset,
+ &scale_stack_offset,
+ &smoothness_stack_offset);
+ svm_unpack_node_uchar4(stack_offsets.y,
+ &exponent_stack_offset,
+ &randomness_stack_offset,
+ &distance_out_stack_offset,
+ &color_out_stack_offset);
+ svm_unpack_node_uchar3(
+ stack_offsets.z, &position_out_stack_offset, &w_out_stack_offset, &radius_out_stack_offset);
+
+ float3 coord = stack_load_float3(stack, coord_stack_offset);
+ float w = stack_load_float_default(stack, w_stack_offset, stack_offsets.w);
+ float scale = stack_load_float_default(stack, scale_stack_offset, defaults.x);
+ float smoothness = stack_load_float_default(stack, smoothness_stack_offset, defaults.y);
+ float exponent = stack_load_float_default(stack, exponent_stack_offset, defaults.z);
+ float randomness = stack_load_float_default(stack, randomness_stack_offset, defaults.w);
+
+ NodeVoronoiFeature voronoi_feature = (NodeVoronoiFeature)feature;
+ NodeVoronoiDistanceMetric voronoi_metric = (NodeVoronoiDistanceMetric)metric;
+
+ float distance_out = 0.0f, w_out = 0.0f, radius_out = 0.0f;
+ float3 color_out = make_float3(0.0f, 0.0f, 0.0f);
+ float3 position_out = make_float3(0.0f, 0.0f, 0.0f);
+
+ randomness = clamp(randomness, 0.0f, 1.0f);
+ smoothness = clamp(smoothness / 2.0f, 0.0f, 0.5f);
+
+ w *= scale;
+ coord *= scale;
+
+ switch (dimensions) {
+ case 1: {
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_1d(
+ w, exponent, randomness, voronoi_metric, &distance_out, &color_out, &w_out);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_1d(w,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &w_out);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_1d(
+ w, exponent, randomness, voronoi_metric, &distance_out, &color_out, &w_out);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_1d(w, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_1d(w, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ w_out = safe_divide(w_out, scale);
+ break;
+ }
+ case 2: {
+ float2 coord_2d = make_float2(coord.x, coord.y);
+ float2 position_out_2d = zero_float2();
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_2d(coord_2d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ IF_KERNEL_NODES_FEATURE(VORONOI_EXTRA)
+ {
+ voronoi_smooth_f1_2d(coord_2d,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ }
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_2d(coord_2d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_2d(coord_2d, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_2d(coord_2d, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out_2d = safe_divide_float2_float(position_out_2d, scale);
+ position_out = make_float3(position_out_2d.x, position_out_2d.y, 0.0f);
+ break;
+ }
+ case 3: {
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_3d(coord,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ IF_KERNEL_NODES_FEATURE(VORONOI_EXTRA)
+ {
+ voronoi_smooth_f1_3d(coord,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out);
+ }
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_3d(coord,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_3d(coord, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_3d(coord, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out = safe_divide_float3_float(position_out, scale);
+ break;
+ }
+
+ case 4: {
+ IF_KERNEL_NODES_FEATURE(VORONOI_EXTRA)
+ {
+ float4 coord_4d = make_float4(coord.x, coord.y, coord.z, w);
+ float4 position_out_4d;
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_4d(coord_4d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_4d(coord_4d,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_4d(coord_4d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_4d(coord_4d, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_4d(coord_4d, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out_4d = safe_divide_float4_float(position_out_4d, scale);
+ position_out = make_float3(position_out_4d.x, position_out_4d.y, position_out_4d.z);
+ w_out = position_out_4d.w;
+ }
+ break;
+ }
+ default:
+ kernel_assert(0);
+ }
+
+ if (stack_valid(distance_out_stack_offset))
+ stack_store_float(stack, distance_out_stack_offset, distance_out);
+ if (stack_valid(color_out_stack_offset))
+ stack_store_float3(stack, color_out_stack_offset, color_out);
+ if (stack_valid(position_out_stack_offset))
+ stack_store_float3(stack, position_out_stack_offset, position_out);
+ if (stack_valid(w_out_stack_offset))
+ stack_store_float(stack, w_out_stack_offset, w_out);
+ if (stack_valid(radius_out_stack_offset))
+ stack_store_float(stack, radius_out_stack_offset, radius_out);
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/voxel.h b/intern/cycles/kernel/svm/voxel.h
new file mode 100644
index 00000000000..43947fbc54f
--- /dev/null
+++ b/intern/cycles/kernel/svm/voxel.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* TODO(sergey): Think of making it more generic volume-type attribute
+ * sampler.
+ */
+ccl_device_noinline int svm_node_tex_voxel(
+ KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
+{
+ uint co_offset, density_out_offset, color_out_offset, space;
+ svm_unpack_node_uchar4(node.z, &co_offset, &density_out_offset, &color_out_offset, &space);
+#ifdef __VOLUME__
+ int id = node.y;
+ float3 co = stack_load_float3(stack, co_offset);
+ if (space == NODE_TEX_VOXEL_SPACE_OBJECT) {
+ co = volume_normalized_position(kg, sd, co);
+ }
+ else {
+ kernel_assert(space == NODE_TEX_VOXEL_SPACE_WORLD);
+ Transform tfm;
+ tfm.x = read_node_float(kg, &offset);
+ tfm.y = read_node_float(kg, &offset);
+ tfm.z = read_node_float(kg, &offset);
+ co = transform_point(&tfm, co);
+ }
+
+ float4 r = kernel_tex_image_interp_3d(kg, id, co, INTERPOLATION_NONE);
+#else
+ float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+#endif
+ if (stack_valid(density_out_offset))
+ stack_store_float(stack, density_out_offset, r.w);
+ if (stack_valid(color_out_offset))
+ stack_store_float3(stack, color_out_offset, make_float3(r.x, r.y, r.z));
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/wave.h b/intern/cycles/kernel/svm/wave.h
new file mode 100644
index 00000000000..40e71b9d5df
--- /dev/null
+++ b/intern/cycles/kernel/svm/wave.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Wave */
+
+ccl_device_noinline_cpu float svm_wave(NodeWaveType type,
+ NodeWaveBandsDirection bands_dir,
+ NodeWaveRingsDirection rings_dir,
+ NodeWaveProfile profile,
+ float3 p,
+ float distortion,
+ float detail,
+ float dscale,
+ float droughness,
+ float phase)
+{
+ /* Prevent precision issues on unit coordinates. */
+ p = (p + 0.000001f) * 0.999999f;
+
+ float n;
+
+ if (type == NODE_WAVE_BANDS) {
+ if (bands_dir == NODE_WAVE_BANDS_DIRECTION_X) {
+ n = p.x * 20.0f;
+ }
+ else if (bands_dir == NODE_WAVE_BANDS_DIRECTION_Y) {
+ n = p.y * 20.0f;
+ }
+ else if (bands_dir == NODE_WAVE_BANDS_DIRECTION_Z) {
+ n = p.z * 20.0f;
+ }
+ else { /* NODE_WAVE_BANDS_DIRECTION_DIAGONAL */
+ n = (p.x + p.y + p.z) * 10.0f;
+ }
+ }
+ else { /* NODE_WAVE_RINGS */
+ float3 rp = p;
+ if (rings_dir == NODE_WAVE_RINGS_DIRECTION_X) {
+ rp *= make_float3(0.0f, 1.0f, 1.0f);
+ }
+ else if (rings_dir == NODE_WAVE_RINGS_DIRECTION_Y) {
+ rp *= make_float3(1.0f, 0.0f, 1.0f);
+ }
+ else if (rings_dir == NODE_WAVE_RINGS_DIRECTION_Z) {
+ rp *= make_float3(1.0f, 1.0f, 0.0f);
+ }
+ /* else: NODE_WAVE_RINGS_DIRECTION_SPHERICAL */
+
+ n = len(rp) * 20.0f;
+ }
+
+ n += phase;
+
+ if (distortion != 0.0f)
+ n += distortion * (fractal_noise_3d(p * dscale, detail, droughness) * 2.0f - 1.0f);
+
+ if (profile == NODE_WAVE_PROFILE_SIN) {
+ return 0.5f + 0.5f * sinf(n - M_PI_2_F);
+ }
+ else if (profile == NODE_WAVE_PROFILE_SAW) {
+ n /= M_2PI_F;
+ return n - floorf(n);
+ }
+ else { /* NODE_WAVE_PROFILE_TRI */
+ n /= M_2PI_F;
+ return fabsf(n - floorf(n + 0.5f)) * 2.0f;
+ }
+}
+
+ccl_device_noinline int svm_node_tex_wave(
+ KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
+{
+ uint4 node2 = read_node(kg, &offset);
+ uint4 node3 = read_node(kg, &offset);
+
+ /* RNA properties */
+ uint type_offset, bands_dir_offset, rings_dir_offset, profile_offset;
+ /* Inputs, Outputs */
+ uint co_offset, scale_offset, distortion_offset, detail_offset, dscale_offset, droughness_offset,
+ phase_offset;
+ uint color_offset, fac_offset;
+
+ svm_unpack_node_uchar4(
+ node.y, &type_offset, &bands_dir_offset, &rings_dir_offset, &profile_offset);
+ svm_unpack_node_uchar3(node.z, &co_offset, &scale_offset, &distortion_offset);
+ svm_unpack_node_uchar4(
+ node.w, &detail_offset, &dscale_offset, &droughness_offset, &phase_offset);
+ svm_unpack_node_uchar2(node2.x, &color_offset, &fac_offset);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float scale = stack_load_float_default(stack, scale_offset, node2.y);
+ float distortion = stack_load_float_default(stack, distortion_offset, node2.z);
+ float detail = stack_load_float_default(stack, detail_offset, node2.w);
+ float dscale = stack_load_float_default(stack, dscale_offset, node3.x);
+ float droughness = stack_load_float_default(stack, droughness_offset, node3.y);
+ float phase = stack_load_float_default(stack, phase_offset, node3.z);
+
+ float f = svm_wave((NodeWaveType)type_offset,
+ (NodeWaveBandsDirection)bands_dir_offset,
+ (NodeWaveRingsDirection)rings_dir_offset,
+ (NodeWaveProfile)profile_offset,
+ co * scale,
+ distortion,
+ detail,
+ dscale,
+ droughness,
+ phase);
+
+ if (stack_valid(fac_offset))
+ stack_store_float(stack, fac_offset, f);
+ if (stack_valid(color_offset))
+ stack_store_float3(stack, color_offset, make_float3(f, f, f));
+ return offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/wavelength.h b/intern/cycles/kernel/svm/wavelength.h
new file mode 100644
index 00000000000..28fd172abc7
--- /dev/null
+++ b/intern/cycles/kernel/svm/wavelength.h
@@ -0,0 +1,103 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2013, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Wavelength to RGB */
+
+ccl_device_noinline void svm_node_wavelength(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint wavelength,
+ uint color_out)
+{
+ // CIE colour matching functions xBar, yBar, and zBar for
+ // wavelengths from 380 through 780 nanometers, every 5
+ // nanometers. For a wavelength lambda in this range:
+ // cie_colour_match[(lambda - 380) / 5][0] = xBar
+ // cie_colour_match[(lambda - 380) / 5][1] = yBar
+ // cie_colour_match[(lambda - 380) / 5][2] = zBar
+ const float cie_colour_match[81][3] = {
+ {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
+ {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
+ {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
+ {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
+ {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
+ {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
+ {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
+ {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
+ {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
+ {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
+ {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
+ {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
+ {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
+ {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
+ {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
+ {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
+ {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
+ {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
+ {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
+ {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
+ {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
+ {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
+ {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
+ {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
+ {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
+ {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
+ {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}};
+
+ float lambda_nm = stack_load_float(stack, wavelength);
+ float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); // scaled 0..80
+ int i = float_to_int(ii);
+ float3 color;
+
+ if (i < 0 || i >= 80) {
+ color = make_float3(0.0f, 0.0f, 0.0f);
+ }
+ else {
+ ii -= i;
+ ccl_constant float *c = cie_colour_match[i];
+ color = interp(make_float3(c[0], c[1], c[2]), make_float3(c[3], c[4], c[5]), ii);
+ }
+
+ color = xyz_to_rgb(kg, color);
+ color *= 1.0f / 2.52f; // Empirical scale from lg to make all comps <= 1
+
+ /* Clamp to zero if values are smaller */
+ color = max(color, make_float3(0.0f, 0.0f, 0.0f));
+
+ stack_store_float3(stack, color_out, color);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/white_noise.h b/intern/cycles/kernel/svm/white_noise.h
new file mode 100644
index 00000000000..d275a3f7068
--- /dev/null
+++ b/intern/cycles/kernel/svm/white_noise.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline void svm_node_tex_white_noise(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint dimensions,
+ uint inputs_stack_offsets,
+ uint ouptuts_stack_offsets)
+{
+ uint vector_stack_offset, w_stack_offset, value_stack_offset, color_stack_offset;
+ svm_unpack_node_uchar2(inputs_stack_offsets, &vector_stack_offset, &w_stack_offset);
+ svm_unpack_node_uchar2(ouptuts_stack_offsets, &value_stack_offset, &color_stack_offset);
+
+ float3 vector = stack_load_float3(stack, vector_stack_offset);
+ float w = stack_load_float(stack, w_stack_offset);
+
+ if (stack_valid(color_stack_offset)) {
+ float3 color;
+ switch (dimensions) {
+ case 1:
+ color = hash_float_to_float3(w);
+ break;
+ case 2:
+ color = hash_float2_to_float3(make_float2(vector.x, vector.y));
+ break;
+ case 3:
+ color = hash_float3_to_float3(vector);
+ break;
+ case 4:
+ color = hash_float4_to_float3(make_float4(vector.x, vector.y, vector.z, w));
+ break;
+ default:
+ color = make_float3(1.0f, 0.0f, 1.0f);
+ kernel_assert(0);
+ break;
+ }
+ stack_store_float3(stack, color_stack_offset, color);
+ }
+
+ if (stack_valid(value_stack_offset)) {
+ float value;
+ switch (dimensions) {
+ case 1:
+ value = hash_float_to_float(w);
+ break;
+ case 2:
+ value = hash_float2_to_float(make_float2(vector.x, vector.y));
+ break;
+ case 3:
+ value = hash_float3_to_float(vector);
+ break;
+ case 4:
+ value = hash_float4_to_float(make_float4(vector.x, vector.y, vector.z, w));
+ break;
+ default:
+ value = 0.0f;
+ kernel_assert(0);
+ break;
+ }
+ stack_store_float(stack, value_stack_offset, value);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/wireframe.h b/intern/cycles/kernel/svm/wireframe.h
new file mode 100644
index 00000000000..530a9601bce
--- /dev/null
+++ b/intern/cycles/kernel/svm/wireframe.h
@@ -0,0 +1,127 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2013, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Wireframe Node */
+
+ccl_device_inline float wireframe(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ float size,
+ int pixel_size,
+ ccl_private float3 *P)
+{
+#ifdef __HAIR__
+ if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_ALL_TRIANGLE)
+#else
+ if (sd->prim != PRIM_NONE)
+#endif
+ {
+ float3 Co[3];
+ float pixelwidth = 1.0f;
+
+ /* Triangles */
+ int np = 3;
+
+ if (sd->type & PRIMITIVE_TRIANGLE)
+ triangle_vertices(kg, sd->prim, Co);
+ else
+ motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, Co);
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ object_position_transform(kg, sd, &Co[0]);
+ object_position_transform(kg, sd, &Co[1]);
+ object_position_transform(kg, sd, &Co[2]);
+ }
+
+ if (pixel_size) {
+ // Project the derivatives of P to the viewing plane defined
+ // by I so we have a measure of how big is a pixel at this point
+ float pixelwidth_x = len(sd->dP.dx - dot(sd->dP.dx, sd->I) * sd->I);
+ float pixelwidth_y = len(sd->dP.dy - dot(sd->dP.dy, sd->I) * sd->I);
+ // Take the average of both axis' length
+ pixelwidth = (pixelwidth_x + pixelwidth_y) * 0.5f;
+ }
+
+ // Use half the width as the neighbor face will render the
+ // other half. And take the square for fast comparison
+ pixelwidth *= 0.5f * size;
+ pixelwidth *= pixelwidth;
+ for (int i = 0; i < np; i++) {
+ int i2 = i ? i - 1 : np - 1;
+ float3 dir = *P - Co[i];
+ float3 edge = Co[i] - Co[i2];
+ float3 crs = cross(edge, dir);
+ // At this point dot(crs, crs) / dot(edge, edge) is
+ // the square of area / length(edge) == square of the
+ // distance to the edge.
+ if (dot(crs, crs) < (dot(edge, edge) * pixelwidth))
+ return 1.0f;
+ }
+ }
+ return 0.0f;
+}
+
+ccl_device_noinline void svm_node_wireframe(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint4 node)
+{
+ uint in_size = node.y;
+ uint out_fac = node.z;
+ uint use_pixel_size, bump_offset;
+ svm_unpack_node_uchar2(node.w, &use_pixel_size, &bump_offset);
+
+ /* Input Data */
+ float size = stack_load_float(stack, in_size);
+ int pixel_size = (int)use_pixel_size;
+
+ /* Calculate wireframe */
+ float f = wireframe(kg, sd, size, pixel_size, &sd->P);
+
+ /* TODO(sergey): Think of faster way to calculate derivatives. */
+ if (bump_offset == NODE_BUMP_OFFSET_DX) {
+ float3 Px = sd->P - sd->dP.dx;
+ f += (f - wireframe(kg, sd, size, pixel_size, &Px)) / len(sd->dP.dx);
+ }
+ else if (bump_offset == NODE_BUMP_OFFSET_DY) {
+ float3 Py = sd->P - sd->dP.dy;
+ f += (f - wireframe(kg, sd, size, pixel_size, &Py)) / len(sd->dP.dy);
+ }
+
+ if (stack_valid(out_fac))
+ stack_store_float(stack, out_fac, f);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/textures.h
index 464ecb183cb..464ecb183cb 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/textures.h
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
new file mode 100644
index 00000000000..2827139d511
--- /dev/null
+++ b/intern/cycles/kernel/types.h
@@ -0,0 +1,1608 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#if !defined(__KERNEL_GPU__) && defined(WITH_EMBREE)
+# include <embree3/rtcore.h>
+# include <embree3/rtcore_scene.h>
+# define __EMBREE__
+#endif
+
+#include "util/math.h"
+#include "util/math_fast.h"
+#include "util/math_intersect.h"
+#include "util/projection.h"
+#include "util/static_assert.h"
+#include "util/texture.h"
+#include "util/transform.h"
+
+#include "kernel/svm/types.h"
+
+#ifndef __KERNEL_GPU__
+# define __KERNEL_CPU__
+#endif
+
+/* TODO(sergey): This is only to make it possible to include this header
+ * from outside of the kernel. but this could be done somewhat cleaner?
+ */
+#ifndef ccl_addr_space
+# define ccl_addr_space
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* Constants */
+#define OBJECT_MOTION_PASS_SIZE 2
+#define FILTER_TABLE_SIZE 1024
+#define RAMP_TABLE_SIZE 256
+#define SHUTTER_TABLE_SIZE 256
+
+#define BSSRDF_MIN_RADIUS 1e-8f
+#define BSSRDF_MAX_HITS 4
+#define BSSRDF_MAX_BOUNCES 256
+#define LOCAL_MAX_HITS 4
+
+#define VOLUME_BOUNDS_MAX 1024
+
+#define BECKMANN_TABLE_SIZE 256
+
+#define SHADER_NONE (~0)
+#define OBJECT_NONE (~0)
+#define PRIM_NONE (~0)
+#define LAMP_NONE (~0)
+#define ID_NONE (0.0f)
+#define PASS_UNUSED (~0)
+
+#define INTEGRATOR_SHADOW_ISECT_SIZE_CPU 1024U
+#define INTEGRATOR_SHADOW_ISECT_SIZE_GPU 4U
+
+#ifdef __KERNEL_CPU__
+# define INTEGRATOR_SHADOW_ISECT_SIZE INTEGRATOR_SHADOW_ISECT_SIZE_CPU
+#else
+# define INTEGRATOR_SHADOW_ISECT_SIZE INTEGRATOR_SHADOW_ISECT_SIZE_GPU
+#endif
+
+/* Kernel features */
+#define __SOBOL__
+#define __DPDU__
+#define __BACKGROUND__
+#define __CAUSTICS_TRICKS__
+#define __VISIBILITY_FLAG__
+#define __RAY_DIFFERENTIALS__
+#define __CAMERA_CLIPPING__
+#define __INTERSECTION_REFINE__
+#define __CLAMP_SAMPLE__
+#define __PATCH_EVAL__
+#define __SHADOW_CATCHER__
+#define __DENOISING_FEATURES__
+#define __SHADER_RAYTRACE__
+#define __AO__
+#define __PASSES__
+#define __HAIR__
+#define __SVM__
+#define __EMISSION__
+#define __HOLDOUT__
+#define __TRANSPARENT_SHADOWS__
+#define __BACKGROUND_MIS__
+#define __LAMP_MIS__
+#define __CAMERA_MOTION__
+#define __OBJECT_MOTION__
+#define __BAKING__
+#define __PRINCIPLED__
+#define __SUBSURFACE__
+#define __VOLUME__
+#define __CMJ__
+#define __SHADOW_RECORD_ALL__
+#define __BRANCHED_PATH__
+
+/* Device specific features */
+#ifdef __KERNEL_CPU__
+# ifdef WITH_OSL
+# define __OSL__
+# endif
+# define __VOLUME_RECORD_ALL__
+#endif /* __KERNEL_CPU__ */
+
+#ifdef __KERNEL_OPTIX__
+# undef __BAKING__
+#endif /* __KERNEL_OPTIX__ */
+
+/* Scene-based selective features compilation. */
+#ifdef __KERNEL_FEATURES__
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_CAMERA_MOTION)
+# undef __CAMERA_MOTION__
+# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_OBJECT_MOTION)
+# undef __OBJECT_MOTION__
+# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_HAIR)
+# undef __HAIR__
+# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_VOLUME)
+# undef __VOLUME__
+# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_SUBSURFACE)
+# undef __SUBSURFACE__
+# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_BAKING)
+# undef __BAKING__
+# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_PATCH_EVALUATION)
+# undef __PATCH_EVAL__
+# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_TRANSPARENT)
+# undef __TRANSPARENT_SHADOWS__
+# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_SHADOW_CATCHER)
+# undef __SHADOW_CATCHER__
+# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_PRINCIPLED)
+# undef __PRINCIPLED__
+# endif
+# if !(__KERNEL_FEATURES & KERNEL_FEATURE_DENOISING)
+# undef __DENOISING_FEATURES__
+# endif
+#endif
+
+#ifdef WITH_CYCLES_DEBUG_NAN
+# define __KERNEL_DEBUG_NAN__
+#endif
+
+/* Features that enable others */
+
+#if defined(__SUBSURFACE__) || defined(__SHADER_RAYTRACE__)
+# define __BVH_LOCAL__
+#endif
+
+/* Path Tracing
+ * note we need to keep the u/v pairs at even values */
+
+enum PathTraceDimension {
+ PRNG_FILTER_U = 0,
+ PRNG_FILTER_V = 1,
+ PRNG_LENS_U = 2,
+ PRNG_LENS_V = 3,
+ PRNG_TIME = 4,
+ PRNG_UNUSED_0 = 5,
+ PRNG_UNUSED_1 = 6, /* for some reason (6, 7) is a bad sobol pattern */
+ PRNG_UNUSED_2 = 7, /* with a low number of samples (< 64) */
+ PRNG_BASE_NUM = 10,
+
+ PRNG_BSDF_U = 0,
+ PRNG_BSDF_V = 1,
+ PRNG_LIGHT_U = 2,
+ PRNG_LIGHT_V = 3,
+ PRNG_LIGHT_TERMINATE = 4,
+ PRNG_TERMINATE = 5,
+ PRNG_PHASE_CHANNEL = 6,
+ PRNG_SCATTER_DISTANCE = 7,
+ PRNG_BOUNCE_NUM = 8,
+
+ PRNG_BEVEL_U = 6, /* reuse volume dimension, correlation won't harm */
+ PRNG_BEVEL_V = 7,
+};
+
+enum SamplingPattern {
+ SAMPLING_PATTERN_SOBOL = 0,
+ SAMPLING_PATTERN_PMJ = 1,
+
+ SAMPLING_NUM_PATTERNS,
+};
+
+/* These flags values correspond to `raytypes` in `osl.cpp`, so keep them in sync! */
+
+enum PathRayFlag {
+ /* --------------------------------------------------------------------
+ * Ray visibility.
+ *
+ * NOTE: Recalculated after a surface bounce.
+ */
+
+ PATH_RAY_CAMERA = (1U << 0U),
+ PATH_RAY_REFLECT = (1U << 1U),
+ PATH_RAY_TRANSMIT = (1U << 2U),
+ PATH_RAY_DIFFUSE = (1U << 3U),
+ PATH_RAY_GLOSSY = (1U << 4U),
+ PATH_RAY_SINGULAR = (1U << 5U),
+ PATH_RAY_TRANSPARENT = (1U << 6U),
+ PATH_RAY_VOLUME_SCATTER = (1U << 7U),
+
+ /* Shadow ray visibility. */
+ PATH_RAY_SHADOW_OPAQUE = (1U << 8U),
+ PATH_RAY_SHADOW_TRANSPARENT = (1U << 9U),
+ PATH_RAY_SHADOW = (PATH_RAY_SHADOW_OPAQUE | PATH_RAY_SHADOW_TRANSPARENT),
+
+ /* Special flag to tag unaligned BVH nodes.
+ * Only set and used in BVH nodes to distinguish how to interpret bounding box information stored
+ * in the node (either it should be intersected as AABB or as OBBU). */
+ PATH_RAY_NODE_UNALIGNED = (1U << 10U),
+
+ /* Subset of flags used for ray visibility for intersection.
+ *
+ * NOTE: SHADOW_CATCHER macros below assume there are no more than
+ * 16 visibility bits. */
+ PATH_RAY_ALL_VISIBILITY = ((1U << 11U) - 1U),
+
+ /* --------------------------------------------------------------------
+ * Path flags.
+ */
+
+ /* Don't apply multiple importance sampling weights to emission from
+ * lamp or surface hits, because they were not direct light sampled. */
+ PATH_RAY_MIS_SKIP = (1U << 11U),
+
+ /* Diffuse bounce earlier in the path, skip SSS to improve performance
+ * and avoid branching twice with disk sampling SSS. */
+ PATH_RAY_DIFFUSE_ANCESTOR = (1U << 12U),
+
+ /* Single pass has been written. */
+ PATH_RAY_SINGLE_PASS_DONE = (1U << 13U),
+
+ /* Zero background alpha, for camera or transparent glass rays. */
+ PATH_RAY_TRANSPARENT_BACKGROUND = (1U << 14U),
+
+ /* Terminate ray immediately at next bounce. */
+ PATH_RAY_TERMINATE_ON_NEXT_SURFACE = (1U << 15U),
+ PATH_RAY_TERMINATE_IN_NEXT_VOLUME = (1U << 16U),
+
+ /* Ray is to be terminated, but continue with transparent bounces and
+ * emission as long as we encounter them. This is required to make the
+ * MIS between direct and indirect light rays match, as shadow rays go
+ * through transparent surfaces to reach emission too. */
+ PATH_RAY_TERMINATE_AFTER_TRANSPARENT = (1U << 17U),
+
+ /* Terminate ray immediately after volume shading. */
+ PATH_RAY_TERMINATE_AFTER_VOLUME = (1U << 18U),
+
+ /* Ray is to be terminated. */
+ PATH_RAY_TERMINATE = (PATH_RAY_TERMINATE_ON_NEXT_SURFACE | PATH_RAY_TERMINATE_IN_NEXT_VOLUME |
+ PATH_RAY_TERMINATE_AFTER_TRANSPARENT | PATH_RAY_TERMINATE_AFTER_VOLUME),
+
+ /* Path and shader is being evaluated for direct lighting emission. */
+ PATH_RAY_EMISSION = (1U << 19U),
+
+ /* Perform subsurface scattering. */
+ PATH_RAY_SUBSURFACE_RANDOM_WALK = (1U << 20U),
+ PATH_RAY_SUBSURFACE_DISK = (1U << 21U),
+ PATH_RAY_SUBSURFACE_USE_FRESNEL = (1U << 22U),
+ PATH_RAY_SUBSURFACE = (PATH_RAY_SUBSURFACE_RANDOM_WALK | PATH_RAY_SUBSURFACE_DISK |
+ PATH_RAY_SUBSURFACE_USE_FRESNEL),
+
+ /* Contribute to denoising features. */
+ PATH_RAY_DENOISING_FEATURES = (1U << 23U),
+
+ /* Render pass categories. */
+ PATH_RAY_REFLECT_PASS = (1U << 24U),
+ PATH_RAY_TRANSMISSION_PASS = (1U << 25U),
+ PATH_RAY_VOLUME_PASS = (1U << 26U),
+ PATH_RAY_ANY_PASS = (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS | PATH_RAY_VOLUME_PASS),
+
+ /* Shadow ray is for a light or surface, or AO. */
+ PATH_RAY_SHADOW_FOR_LIGHT = (1U << 27U),
+ PATH_RAY_SHADOW_FOR_AO = (1U << 28U),
+
+ /* A shadow catcher object was hit and the path was split into two. */
+ PATH_RAY_SHADOW_CATCHER_HIT = (1U << 29U),
+
+ /* A shadow catcher object was hit and this path traces only shadow catchers, writing them into
+ * their dedicated pass for later division.
+ *
+ * NOTE: Is not covered with `PATH_RAY_ANY_PASS` because shadow catcher does special handling
+ * which is separate from the light passes. */
+ PATH_RAY_SHADOW_CATCHER_PASS = (1U << 30U),
+
+ /* Path is evaluating background for an approximate shadow catcher with non-transparent film. */
+ PATH_RAY_SHADOW_CATCHER_BACKGROUND = (1U << 31U),
+};
+
+/* Configure ray visibility bits for rays and objects respectively,
+ * to make shadow catchers work.
+ *
+ * On shadow catcher paths we want to ignore any intersections with non-catchers,
+ * whereas on regular paths we want to intersect all objects. */
+
+#define SHADOW_CATCHER_VISIBILITY_SHIFT(visibility) ((visibility) << 16)
+
+#define SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility) \
+ (((path_flag)&PATH_RAY_SHADOW_CATCHER_PASS) ? SHADOW_CATCHER_VISIBILITY_SHIFT(visibility) : \
+ (visibility))
+
+#define SHADOW_CATCHER_OBJECT_VISIBILITY(is_shadow_catcher, visibility) \
+ (((is_shadow_catcher) ? SHADOW_CATCHER_VISIBILITY_SHIFT(visibility) : 0) | (visibility))
+
+/* Closure Label */
+
+typedef enum ClosureLabel {
+ LABEL_NONE = 0,
+ LABEL_TRANSMIT = 1,
+ LABEL_REFLECT = 2,
+ LABEL_DIFFUSE = 4,
+ LABEL_GLOSSY = 8,
+ LABEL_SINGULAR = 16,
+ LABEL_TRANSPARENT = 32,
+ LABEL_VOLUME_SCATTER = 64,
+ LABEL_TRANSMIT_TRANSPARENT = 128,
+ LABEL_SUBSURFACE_SCATTER = 256,
+} ClosureLabel;
+
+/* Render Passes */
+
+#define PASS_NAME_JOIN(a, b) a##_##b
+#define PASSMASK(pass) (1 << ((PASS_NAME_JOIN(PASS, pass)) % 32))
+
+// NOTE: Keep in sync with `Pass::get_type_enum()`.
+typedef enum PassType {
+ PASS_NONE = 0,
+
+ /* Light Passes */
+ PASS_COMBINED = 1,
+ PASS_EMISSION,
+ PASS_BACKGROUND,
+ PASS_AO,
+ PASS_SHADOW,
+ PASS_DIFFUSE,
+ PASS_DIFFUSE_DIRECT,
+ PASS_DIFFUSE_INDIRECT,
+ PASS_GLOSSY,
+ PASS_GLOSSY_DIRECT,
+ PASS_GLOSSY_INDIRECT,
+ PASS_TRANSMISSION,
+ PASS_TRANSMISSION_DIRECT,
+ PASS_TRANSMISSION_INDIRECT,
+ PASS_VOLUME,
+ PASS_VOLUME_DIRECT,
+ PASS_VOLUME_INDIRECT,
+ PASS_CATEGORY_LIGHT_END = 31,
+
+ /* Data passes */
+ PASS_DEPTH = 32,
+ PASS_POSITION,
+ PASS_NORMAL,
+ PASS_ROUGHNESS,
+ PASS_UV,
+ PASS_OBJECT_ID,
+ PASS_MATERIAL_ID,
+ PASS_MOTION,
+ PASS_MOTION_WEIGHT,
+ PASS_CRYPTOMATTE,
+ PASS_AOV_COLOR,
+ PASS_AOV_VALUE,
+ PASS_ADAPTIVE_AUX_BUFFER,
+ PASS_SAMPLE_COUNT,
+ PASS_DIFFUSE_COLOR,
+ PASS_GLOSSY_COLOR,
+ PASS_TRANSMISSION_COLOR,
+ /* No Scatter color since it's tricky to define what it would even mean. */
+ PASS_MIST,
+ PASS_DENOISING_NORMAL,
+ PASS_DENOISING_ALBEDO,
+ PASS_DENOISING_DEPTH,
+
+ /* PASS_SHADOW_CATCHER accumulates contribution of shadow catcher object which is not affected by
+ * any other object. The pass accessor will divide the combined pass by the shadow catcher. The
+ * result of this division is then to be multiplied with the backdrop. The alpha channel of this
+ * pass contains number of samples which contributed to the color components of the pass.
+ *
+ * PASS_SHADOW_CATCHER_SAMPLE_COUNT contains number of samples for which the path split
+ * happened.
+ *
+ * PASS_SHADOW_CATCHER_MATTE contains pass which contains non-catcher objects. This pass is to be
+ * alpha-overed onto the backdrop (after multiplication). */
+ PASS_SHADOW_CATCHER,
+ PASS_SHADOW_CATCHER_SAMPLE_COUNT,
+ PASS_SHADOW_CATCHER_MATTE,
+
+ PASS_CATEGORY_DATA_END = 63,
+
+ PASS_BAKE_PRIMITIVE,
+ PASS_BAKE_DIFFERENTIAL,
+ PASS_CATEGORY_BAKE_END = 95,
+
+ PASS_NUM,
+} PassType;
+
+#define PASS_ANY (~0)
+
+typedef enum CryptomatteType {
+ CRYPT_NONE = 0,
+ CRYPT_OBJECT = (1 << 0),
+ CRYPT_MATERIAL = (1 << 1),
+ CRYPT_ASSET = (1 << 2),
+ CRYPT_ACCURATE = (1 << 3),
+} CryptomatteType;
+
+typedef struct BsdfEval {
+ float3 diffuse;
+ float3 glossy;
+} BsdfEval;
+
+/* Shader Flag */
+
+typedef enum ShaderFlag {
+ SHADER_SMOOTH_NORMAL = (1 << 31),
+ SHADER_CAST_SHADOW = (1 << 30),
+ SHADER_AREA_LIGHT = (1 << 29),
+ SHADER_USE_MIS = (1 << 28),
+ SHADER_EXCLUDE_DIFFUSE = (1 << 27),
+ SHADER_EXCLUDE_GLOSSY = (1 << 26),
+ SHADER_EXCLUDE_TRANSMIT = (1 << 25),
+ SHADER_EXCLUDE_CAMERA = (1 << 24),
+ SHADER_EXCLUDE_SCATTER = (1 << 23),
+ SHADER_EXCLUDE_SHADOW_CATCHER = (1 << 22),
+ SHADER_EXCLUDE_ANY = (SHADER_EXCLUDE_DIFFUSE | SHADER_EXCLUDE_GLOSSY | SHADER_EXCLUDE_TRANSMIT |
+ SHADER_EXCLUDE_CAMERA | SHADER_EXCLUDE_SCATTER |
+ SHADER_EXCLUDE_SHADOW_CATCHER),
+
+ SHADER_MASK = ~(SHADER_SMOOTH_NORMAL | SHADER_CAST_SHADOW | SHADER_AREA_LIGHT | SHADER_USE_MIS |
+ SHADER_EXCLUDE_ANY)
+} ShaderFlag;
+
+/* Light Type */
+
+typedef enum LightType {
+ LIGHT_POINT,
+ LIGHT_DISTANT,
+ LIGHT_BACKGROUND,
+ LIGHT_AREA,
+ LIGHT_SPOT,
+ LIGHT_TRIANGLE
+} LightType;
+
+/* Camera Type */
+
+enum CameraType { CAMERA_PERSPECTIVE, CAMERA_ORTHOGRAPHIC, CAMERA_PANORAMA };
+
+/* Panorama Type */
+
+enum PanoramaType {
+ PANORAMA_EQUIRECTANGULAR = 0,
+ PANORAMA_FISHEYE_EQUIDISTANT = 1,
+ PANORAMA_FISHEYE_EQUISOLID = 2,
+ PANORAMA_MIRRORBALL = 3,
+
+ PANORAMA_NUM_TYPES,
+};
+
+/* Differential */
+
+typedef struct differential3 {
+ float3 dx;
+ float3 dy;
+} differential3;
+
+typedef struct differential {
+ float dx;
+ float dy;
+} differential;
+
+/* Ray */
+
+typedef struct Ray {
+ float3 P; /* origin */
+ float3 D; /* direction */
+ float t; /* length of the ray */
+ float time; /* time (for motion blur) */
+
+#ifdef __RAY_DIFFERENTIALS__
+ float dP;
+ float dD;
+#endif
+} Ray;
+
+/* Intersection */
+
+typedef struct Intersection {
+ float t, u, v;
+ int prim;
+ int object;
+ int type;
+} Intersection;
+
+/* Primitives */
+
+typedef enum PrimitiveType {
+ PRIMITIVE_NONE = 0,
+ PRIMITIVE_TRIANGLE = (1 << 0),
+ PRIMITIVE_MOTION_TRIANGLE = (1 << 1),
+ PRIMITIVE_CURVE_THICK = (1 << 2),
+ PRIMITIVE_MOTION_CURVE_THICK = (1 << 3),
+ PRIMITIVE_CURVE_RIBBON = (1 << 4),
+ PRIMITIVE_MOTION_CURVE_RIBBON = (1 << 5),
+ PRIMITIVE_VOLUME = (1 << 6),
+ PRIMITIVE_LAMP = (1 << 7),
+
+ PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION_TRIANGLE),
+ PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION_CURVE_THICK |
+ PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON),
+ PRIMITIVE_ALL_VOLUME = (PRIMITIVE_VOLUME),
+ PRIMITIVE_ALL_MOTION = (PRIMITIVE_MOTION_TRIANGLE | PRIMITIVE_MOTION_CURVE_THICK |
+ PRIMITIVE_MOTION_CURVE_RIBBON),
+ PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE | PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_VOLUME |
+ PRIMITIVE_LAMP),
+
+ PRIMITIVE_NUM = 8,
+} PrimitiveType;
+
+#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM) | (type))
+#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM)
+
+typedef enum CurveShapeType {
+ CURVE_RIBBON = 0,
+ CURVE_THICK = 1,
+
+ CURVE_NUM_SHAPE_TYPES,
+} CurveShapeType;
+
+/* Attributes */
+
+typedef enum AttributePrimitive {
+ ATTR_PRIM_GEOMETRY = 0,
+ ATTR_PRIM_SUBD,
+
+ ATTR_PRIM_TYPES
+} AttributePrimitive;
+
+typedef enum AttributeElement {
+ ATTR_ELEMENT_NONE = 0,
+ ATTR_ELEMENT_OBJECT = (1 << 0),
+ ATTR_ELEMENT_MESH = (1 << 1),
+ ATTR_ELEMENT_FACE = (1 << 2),
+ ATTR_ELEMENT_VERTEX = (1 << 3),
+ ATTR_ELEMENT_VERTEX_MOTION = (1 << 4),
+ ATTR_ELEMENT_CORNER = (1 << 5),
+ ATTR_ELEMENT_CORNER_BYTE = (1 << 6),
+ ATTR_ELEMENT_CURVE = (1 << 7),
+ ATTR_ELEMENT_CURVE_KEY = (1 << 8),
+ ATTR_ELEMENT_CURVE_KEY_MOTION = (1 << 9),
+ ATTR_ELEMENT_VOXEL = (1 << 10)
+} AttributeElement;
+
+typedef enum AttributeStandard {
+ ATTR_STD_NONE = 0,
+ ATTR_STD_VERTEX_NORMAL,
+ ATTR_STD_FACE_NORMAL,
+ ATTR_STD_UV,
+ ATTR_STD_UV_TANGENT,
+ ATTR_STD_UV_TANGENT_SIGN,
+ ATTR_STD_VERTEX_COLOR,
+ ATTR_STD_GENERATED,
+ ATTR_STD_GENERATED_TRANSFORM,
+ ATTR_STD_POSITION_UNDEFORMED,
+ ATTR_STD_POSITION_UNDISPLACED,
+ ATTR_STD_MOTION_VERTEX_POSITION,
+ ATTR_STD_MOTION_VERTEX_NORMAL,
+ ATTR_STD_PARTICLE,
+ ATTR_STD_CURVE_INTERCEPT,
+ ATTR_STD_CURVE_LENGTH,
+ ATTR_STD_CURVE_RANDOM,
+ ATTR_STD_PTEX_FACE_ID,
+ ATTR_STD_PTEX_UV,
+ ATTR_STD_VOLUME_DENSITY,
+ ATTR_STD_VOLUME_COLOR,
+ ATTR_STD_VOLUME_FLAME,
+ ATTR_STD_VOLUME_HEAT,
+ ATTR_STD_VOLUME_TEMPERATURE,
+ ATTR_STD_VOLUME_VELOCITY,
+ ATTR_STD_POINTINESS,
+ ATTR_STD_RANDOM_PER_ISLAND,
+ ATTR_STD_SHADOW_TRANSPARENCY,
+ ATTR_STD_NUM,
+
+ ATTR_STD_NOT_FOUND = ~0
+} AttributeStandard;
+
+typedef enum AttributeFlag {
+ ATTR_FINAL_SIZE = (1 << 0),
+ ATTR_SUBDIVIDED = (1 << 1),
+} AttributeFlag;
+
+typedef struct AttributeDescriptor {
+ AttributeElement element;
+ NodeAttributeType type;
+ uint flags; /* see enum AttributeFlag */
+ int offset;
+} AttributeDescriptor;
+
+/* Closure data */
+
+#ifndef __MAX_CLOSURE__
+# define MAX_CLOSURE 64
+#else
+# define MAX_CLOSURE __MAX_CLOSURE__
+#endif
+
+#ifndef __MAX_VOLUME_STACK_SIZE__
+# define MAX_VOLUME_STACK_SIZE 32
+#else
+# define MAX_VOLUME_STACK_SIZE __MAX_VOLUME_STACK_SIZE__
+#endif
+
+#define MAX_VOLUME_CLOSURE 8
+
+/* This struct is the base class for all closures. The common members are
+ * duplicated in all derived classes since we don't have C++ in the kernel
+ * yet, and because it lets us lay out the members to minimize padding. The
+ * weight member is located at the beginning of the struct for this reason.
+ *
+ * ShaderClosure has a fixed size, and any extra space must be allocated
+ * with closure_alloc_extra().
+ *
+ * We pad the struct to align to 16 bytes. All shader closures are assumed
+ * to fit in this struct size. CPU sizes are a bit larger because float3 is
+ * padded to be 16 bytes, while it's only 12 bytes on the GPU. */
+
+#define SHADER_CLOSURE_BASE \
+ float3 weight; \
+ ClosureType type; \
+ float sample_weight; \
+ float3 N
+
+typedef struct ccl_align(16) ShaderClosure
+{
+ SHADER_CLOSURE_BASE;
+
+#ifdef __KERNEL_CPU__
+ float pad[2];
+#endif
+ float data[10];
+}
+ShaderClosure;
+
+/* Shader Data
+ *
+ * Main shader state at a point on the surface or in a volume. All coordinates
+ * are in world space.
+ */
+
+enum ShaderDataFlag {
+ /* Runtime flags. */
+
+ /* Set when ray hits backside of surface. */
+ SD_BACKFACING = (1 << 0),
+ /* Shader has non-zero emission. */
+ SD_EMISSION = (1 << 1),
+ /* Shader has BSDF closure. */
+ SD_BSDF = (1 << 2),
+ /* Shader has non-singular BSDF closure. */
+ SD_BSDF_HAS_EVAL = (1 << 3),
+ /* Shader has BSSRDF closure. */
+ SD_BSSRDF = (1 << 4),
+ /* Shader has holdout closure. */
+ SD_HOLDOUT = (1 << 5),
+ /* Shader has non-zero volume extinction. */
+ SD_EXTINCTION = (1 << 6),
+ /* Shader has have volume phase (scatter) closure. */
+ SD_SCATTER = (1 << 7),
+ /* Shader has transparent closure. */
+ SD_TRANSPARENT = (1 << 9),
+ /* BSDF requires LCG for evaluation. */
+ SD_BSDF_NEEDS_LCG = (1 << 10),
+
+ SD_CLOSURE_FLAGS = (SD_EMISSION | SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSSRDF | SD_HOLDOUT |
+ SD_EXTINCTION | SD_SCATTER | SD_BSDF_NEEDS_LCG),
+
+ /* Shader flags. */
+
+ /* direct light sample */
+ SD_USE_MIS = (1 << 16),
+ /* Has transparent shadow. */
+ SD_HAS_TRANSPARENT_SHADOW = (1 << 17),
+ /* Has volume shader. */
+ SD_HAS_VOLUME = (1 << 18),
+ /* Has only volume shader, no surface. */
+ SD_HAS_ONLY_VOLUME = (1 << 19),
+ /* Has heterogeneous volume. */
+ SD_HETEROGENEOUS_VOLUME = (1 << 20),
+ /* BSSRDF normal uses bump. */
+ SD_HAS_BSSRDF_BUMP = (1 << 21),
+ /* Use equiangular volume sampling */
+ SD_VOLUME_EQUIANGULAR = (1 << 22),
+ /* Use multiple importance volume sampling. */
+ SD_VOLUME_MIS = (1 << 23),
+ /* Use cubic interpolation for voxels. */
+ SD_VOLUME_CUBIC = (1 << 24),
+ /* Has data connected to the displacement input or uses bump map. */
+ SD_HAS_BUMP = (1 << 25),
+ /* Has true displacement. */
+ SD_HAS_DISPLACEMENT = (1 << 26),
+ /* Has constant emission (value stored in __shaders) */
+ SD_HAS_CONSTANT_EMISSION = (1 << 27),
+ /* Needs to access attributes for volume rendering */
+ SD_NEED_VOLUME_ATTRIBUTES = (1 << 28),
+ /* Shader has emission */
+ SD_HAS_EMISSION = (1 << 29),
+ /* Shader has raytracing */
+ SD_HAS_RAYTRACE = (1 << 30),
+
+ SD_SHADER_FLAGS = (SD_USE_MIS | SD_HAS_TRANSPARENT_SHADOW | SD_HAS_VOLUME | SD_HAS_ONLY_VOLUME |
+ SD_HETEROGENEOUS_VOLUME | SD_HAS_BSSRDF_BUMP | SD_VOLUME_EQUIANGULAR |
+ SD_VOLUME_MIS | SD_VOLUME_CUBIC | SD_HAS_BUMP | SD_HAS_DISPLACEMENT |
+ SD_HAS_CONSTANT_EMISSION | SD_NEED_VOLUME_ATTRIBUTES | SD_HAS_EMISSION |
+ SD_HAS_RAYTRACE)
+};
+
+/* Object flags. */
+enum ShaderDataObjectFlag {
+ /* Holdout for camera rays. */
+ SD_OBJECT_HOLDOUT_MASK = (1 << 0),
+ /* Has object motion blur. */
+ SD_OBJECT_MOTION = (1 << 1),
+ /* Vertices have transform applied. */
+ SD_OBJECT_TRANSFORM_APPLIED = (1 << 2),
+ /* Vertices have negative scale applied. */
+ SD_OBJECT_NEGATIVE_SCALE_APPLIED = (1 << 3),
+ /* Object has a volume shader. */
+ SD_OBJECT_HAS_VOLUME = (1 << 4),
+ /* Object intersects AABB of an object with volume shader. */
+ SD_OBJECT_INTERSECTS_VOLUME = (1 << 5),
+ /* Has position for motion vertices. */
+ SD_OBJECT_HAS_VERTEX_MOTION = (1 << 6),
+ /* object is used to catch shadows */
+ SD_OBJECT_SHADOW_CATCHER = (1 << 7),
+ /* object has volume attributes */
+ SD_OBJECT_HAS_VOLUME_ATTRIBUTES = (1 << 8),
+
+ SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK | SD_OBJECT_MOTION | SD_OBJECT_TRANSFORM_APPLIED |
+ SD_OBJECT_NEGATIVE_SCALE_APPLIED | SD_OBJECT_HAS_VOLUME |
+ SD_OBJECT_INTERSECTS_VOLUME | SD_OBJECT_SHADOW_CATCHER |
+ SD_OBJECT_HAS_VOLUME_ATTRIBUTES)
+};
+
+typedef struct ccl_align(16) ShaderData
+{
+ /* position */
+ float3 P;
+ /* smooth normal for shading */
+ float3 N;
+ /* true geometric normal */
+ float3 Ng;
+ /* view/incoming direction */
+ float3 I;
+ /* shader id */
+ int shader;
+ /* booleans describing shader, see ShaderDataFlag */
+ int flag;
+ /* booleans describing object of the shader, see ShaderDataObjectFlag */
+ int object_flag;
+
+ /* primitive id if there is one, ~0 otherwise */
+ int prim;
+
+ /* combined type and curve segment for hair */
+ int type;
+
+ /* parametric coordinates
+ * - barycentric weights for triangles */
+ float u;
+ float v;
+ /* object id if there is one, ~0 otherwise */
+ int object;
+ /* lamp id if there is one, ~0 otherwise */
+ int lamp;
+
+ /* motion blur sample time */
+ float time;
+
+ /* length of the ray being shaded */
+ float ray_length;
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* differential of P. these are orthogonal to Ng, not N */
+ differential3 dP;
+ /* differential of I */
+ differential3 dI;
+ /* differential of u, v */
+ differential du;
+ differential dv;
+#endif
+#ifdef __DPDU__
+ /* differential of P w.r.t. parametric coordinates. note that dPdu is
+ * not readily suitable as a tangent for shading on triangles. */
+ float3 dPdu;
+ float3 dPdv;
+#endif
+
+#ifdef __OBJECT_MOTION__
+ /* Object <-> world space transformations for motion blur, cached to avoid
+ * re-interpolating them constantly for shading. */
+ Transform ob_tfm_motion;
+ Transform ob_itfm_motion;
+#endif
+
+ /* ray start position, only set for backgrounds */
+ float3 ray_P;
+ float ray_dP;
+
+#ifdef __OSL__
+ const struct KernelGlobalsCPU *osl_globals;
+ const struct IntegratorStateCPU *osl_path_state;
+ const struct IntegratorShadowStateCPU *osl_shadow_path_state;
+#endif
+
+ /* LCG state for closures that require additional random numbers. */
+ uint lcg_state;
+
+ /* Closure data, we store a fixed array of closures */
+ int num_closure;
+ int num_closure_left;
+ float3 svm_closure_weight;
+
+ /* Closure weights summed directly, so we can evaluate
+ * emission and shadow transparency with MAX_CLOSURE 0. */
+ float3 closure_emission_background;
+ float3 closure_transparent_extinction;
+
+ /* At the end so we can adjust size in ShaderDataTinyStorage. */
+ struct ShaderClosure closure[MAX_CLOSURE];
+}
+ShaderData;
+
+/* ShaderDataTinyStorage needs the same alignment as ShaderData, or else
+ * the pointer cast in AS_SHADER_DATA invokes undefined behavior. */
+typedef struct ccl_align(16) ShaderDataTinyStorage
+{
+ char pad[sizeof(ShaderData) - sizeof(ShaderClosure) * MAX_CLOSURE];
+}
+ShaderDataTinyStorage;
+#define AS_SHADER_DATA(shader_data_tiny_storage) \
+ ((ccl_private ShaderData *)shader_data_tiny_storage)
+
+/* Compact volume closures storage.
+ *
+ * Used for decoupled direct/indirect light closure storage. */
+
+typedef struct ShaderVolumeClosure {
+ float3 weight;
+ float sample_weight;
+ float g;
+} ShaderVolumeClosure;
+
+typedef struct ShaderVolumePhases {
+ ShaderVolumeClosure closure[MAX_VOLUME_CLOSURE];
+ int num_closure;
+} ShaderVolumePhases;
+
+/* Volume Stack */
+
+#ifdef __VOLUME__
+typedef struct VolumeStack {
+ int object;
+ int shader;
+} VolumeStack;
+#endif
+
+/* Struct to gather multiple nearby intersections. */
+typedef struct LocalIntersection {
+ int num_hits;
+ struct Intersection hits[LOCAL_MAX_HITS];
+ float3 Ng[LOCAL_MAX_HITS];
+} LocalIntersection;
+
+/* Constant Kernel Data
+ *
+ * These structs are passed from CPU to various devices, and the struct layout
+ * must match exactly. Structs are padded to ensure 16 byte alignment, and we
+ * do not use float3 because its size may not be the same on all devices. */
+
+typedef struct KernelCamera {
+ /* type */
+ int type;
+
+ /* panorama */
+ int panorama_type;
+ float fisheye_fov;
+ float fisheye_lens;
+ float4 equirectangular_range;
+
+ /* stereo */
+ float interocular_offset;
+ float convergence_distance;
+ float pole_merge_angle_from;
+ float pole_merge_angle_to;
+
+ /* matrices */
+ Transform cameratoworld;
+ ProjectionTransform rastertocamera;
+
+ /* differentials */
+ float4 dx;
+ float4 dy;
+
+ /* depth of field */
+ float aperturesize;
+ float blades;
+ float bladesrotation;
+ float focaldistance;
+
+ /* motion blur */
+ float shuttertime;
+ int num_motion_steps, have_perspective_motion;
+
+ /* clipping */
+ float nearclip;
+ float cliplength;
+
+ /* sensor size */
+ float sensorwidth;
+ float sensorheight;
+
+ /* render size */
+ float width, height;
+ int pad1;
+
+ /* anamorphic lens bokeh */
+ float inv_aperture_ratio;
+
+ int is_inside_volume;
+
+ /* more matrices */
+ ProjectionTransform screentoworld;
+ ProjectionTransform rastertoworld;
+ ProjectionTransform ndctoworld;
+ ProjectionTransform worldtoscreen;
+ ProjectionTransform worldtoraster;
+ ProjectionTransform worldtondc;
+ Transform worldtocamera;
+
+ /* Stores changes in the projection matrix. Use for camera zoom motion
+ * blur and motion pass output for perspective camera. */
+ ProjectionTransform perspective_pre;
+ ProjectionTransform perspective_post;
+
+ /* Transforms for motion pass. */
+ Transform motion_pass_pre;
+ Transform motion_pass_post;
+
+ int shutter_table_offset;
+
+ /* Rolling shutter */
+ int rolling_shutter_type;
+ float rolling_shutter_duration;
+
+ int pad;
+} KernelCamera;
+static_assert_align(KernelCamera, 16);
+
+typedef struct KernelFilm {
+ float exposure;
+ int pass_flag;
+
+ int light_pass_flag;
+ int pass_stride;
+
+ int pass_combined;
+ int pass_depth;
+ int pass_position;
+ int pass_normal;
+ int pass_roughness;
+ int pass_motion;
+
+ int pass_motion_weight;
+ int pass_uv;
+ int pass_object_id;
+ int pass_material_id;
+
+ int pass_diffuse_color;
+ int pass_glossy_color;
+ int pass_transmission_color;
+
+ int pass_diffuse_indirect;
+ int pass_glossy_indirect;
+ int pass_transmission_indirect;
+ int pass_volume_indirect;
+
+ int pass_diffuse_direct;
+ int pass_glossy_direct;
+ int pass_transmission_direct;
+ int pass_volume_direct;
+
+ int pass_emission;
+ int pass_background;
+ int pass_ao;
+ float pass_alpha_threshold;
+
+ int pass_shadow;
+ float pass_shadow_scale;
+
+ int pass_shadow_catcher;
+ int pass_shadow_catcher_sample_count;
+ int pass_shadow_catcher_matte;
+
+ int filter_table_offset;
+
+ int cryptomatte_passes;
+ int cryptomatte_depth;
+ int pass_cryptomatte;
+
+ int pass_adaptive_aux_buffer;
+ int pass_sample_count;
+
+ int pass_mist;
+ float mist_start;
+ float mist_inv_depth;
+ float mist_falloff;
+
+ int pass_denoising_normal;
+ int pass_denoising_albedo;
+ int pass_denoising_depth;
+
+ int pass_aov_color;
+ int pass_aov_value;
+
+ /* XYZ to rendering color space transform. float4 instead of float3 to
+ * ensure consistent padding/alignment across devices. */
+ float4 xyz_to_r;
+ float4 xyz_to_g;
+ float4 xyz_to_b;
+ float4 rgb_to_y;
+
+ int pass_bake_primitive;
+ int pass_bake_differential;
+
+ int use_approximate_shadow_catcher;
+
+ int pad1, pad2;
+} KernelFilm;
+static_assert_align(KernelFilm, 16);
+
+typedef struct KernelFilmConvert {
+ int pass_offset;
+ int pass_stride;
+
+ int pass_use_exposure;
+ int pass_use_filter;
+
+ int pass_divide;
+ int pass_indirect;
+
+ int pass_combined;
+ int pass_sample_count;
+ int pass_adaptive_aux_buffer;
+ int pass_motion_weight;
+ int pass_shadow_catcher;
+ int pass_shadow_catcher_sample_count;
+ int pass_shadow_catcher_matte;
+ int pass_background;
+
+ float scale;
+ float exposure;
+ float scale_exposure;
+
+ int use_approximate_shadow_catcher;
+ int use_approximate_shadow_catcher_background;
+ int show_active_pixels;
+
+ /* Number of components to write to. */
+ int num_components;
+
+ /* Number of floats per pixel. When zero is the same as `num_components`.
+ * NOTE: Is ignored for half4 destination. */
+ int pixel_stride;
+
+ int is_denoised;
+
+ /* Padding. */
+ int pad1;
+} KernelFilmConvert;
+static_assert_align(KernelFilmConvert, 16);
+
+typedef struct KernelBackground {
+ /* only shader index */
+ int surface_shader;
+ int volume_shader;
+ float volume_step_size;
+ int transparent;
+ float transparent_roughness_squared_threshold;
+
+ /* portal sampling */
+ float portal_weight;
+ int num_portals;
+ int portal_offset;
+
+ /* sun sampling */
+ float sun_weight;
+ /* xyz store direction, w the angle. float4 instead of float3 is used
+ * to ensure consistent padding/alignment across devices. */
+ float4 sun;
+
+ /* map sampling */
+ float map_weight;
+ int map_res_x;
+ int map_res_y;
+
+ int use_mis;
+
+ /* Padding */
+ int pad1, pad2, pad3;
+} KernelBackground;
+static_assert_align(KernelBackground, 16);
+
+typedef struct KernelIntegrator {
+ /* emission */
+ int use_direct_light;
+ int num_distribution;
+ int num_all_lights;
+ float pdf_triangles;
+ float pdf_lights;
+ float light_inv_rr_threshold;
+
+ /* bounces */
+ int min_bounce;
+ int max_bounce;
+
+ int max_diffuse_bounce;
+ int max_glossy_bounce;
+ int max_transmission_bounce;
+ int max_volume_bounce;
+
+ /* AO bounces */
+ int ao_bounces;
+ float ao_bounces_distance;
+ float ao_bounces_factor;
+ float ao_additive_factor;
+
+ /* transparent */
+ int transparent_min_bounce;
+ int transparent_max_bounce;
+ int transparent_shadows;
+
+ /* caustics */
+ int caustics_reflective;
+ int caustics_refractive;
+ float filter_glossy;
+
+ /* seed */
+ int seed;
+
+ /* clamp */
+ float sample_clamp_direct;
+ float sample_clamp_indirect;
+
+ /* mis */
+ int use_lamp_mis;
+
+ /* sampler */
+ int sampling_pattern;
+
+ /* volume render */
+ int use_volumes;
+ int volume_max_steps;
+ float volume_step_rate;
+
+ int has_shadow_catcher;
+ float scrambling_distance;
+
+ /* padding */
+} KernelIntegrator;
+static_assert_align(KernelIntegrator, 16);
+
+typedef enum KernelBVHLayout {
+ BVH_LAYOUT_NONE = 0,
+
+ BVH_LAYOUT_BVH2 = (1 << 0),
+ BVH_LAYOUT_EMBREE = (1 << 1),
+ BVH_LAYOUT_OPTIX = (1 << 2),
+ BVH_LAYOUT_MULTI_OPTIX = (1 << 3),
+ BVH_LAYOUT_MULTI_OPTIX_EMBREE = (1 << 4),
+
+ /* Default BVH layout to use for CPU. */
+ BVH_LAYOUT_AUTO = BVH_LAYOUT_EMBREE,
+ BVH_LAYOUT_ALL = BVH_LAYOUT_BVH2 | BVH_LAYOUT_EMBREE | BVH_LAYOUT_OPTIX,
+} KernelBVHLayout;
+
+typedef struct KernelBVH {
+ /* Own BVH */
+ int root;
+ int have_motion;
+ int have_curves;
+ int bvh_layout;
+ int use_bvh_steps;
+ int curve_subdivisions;
+
+ /* Custom BVH */
+#ifdef __KERNEL_OPTIX__
+ OptixTraversableHandle scene;
+#else
+# ifdef __EMBREE__
+ RTCScene scene;
+# ifndef __KERNEL_64_BIT__
+ int pad2;
+# endif
+# else
+ int scene, pad2;
+# endif
+#endif
+} KernelBVH;
+static_assert_align(KernelBVH, 16);
+
+typedef struct KernelTables {
+ int beckmann_offset;
+ int pad1, pad2, pad3;
+} KernelTables;
+static_assert_align(KernelTables, 16);
+
+typedef struct KernelBake {
+ int use;
+ int object_index;
+ int tri_offset;
+ int pad1;
+} KernelBake;
+static_assert_align(KernelBake, 16);
+
+typedef struct KernelData {
+ uint kernel_features;
+ uint max_closures;
+ uint max_shaders;
+ uint volume_stack_size;
+
+ KernelCamera cam;
+ KernelFilm film;
+ KernelBackground background;
+ KernelIntegrator integrator;
+ KernelBVH bvh;
+ KernelTables tables;
+ KernelBake bake;
+} KernelData;
+static_assert_align(KernelData, 16);
+
+/* Kernel data structures. */
+
+typedef struct KernelObject {
+ Transform tfm;
+ Transform itfm;
+
+ float volume_density;
+ float pass_id;
+ float random_number;
+ float color[3];
+ int particle_index;
+
+ float dupli_generated[3];
+ float dupli_uv[2];
+
+ int numkeys;
+ int numsteps;
+ int numverts;
+
+ uint patch_map_offset;
+ uint attribute_map_offset;
+ uint motion_offset;
+
+ float cryptomatte_object;
+ float cryptomatte_asset;
+
+ float shadow_terminator_shading_offset;
+ float shadow_terminator_geometry_offset;
+
+ float ao_distance;
+
+ uint visibility;
+ int primitive_type;
+} KernelObject;
+static_assert_align(KernelObject, 16);
+
+typedef struct KernelCurve {
+ int shader_id;
+ int first_key;
+ int num_keys;
+ int type;
+} KernelCurve;
+static_assert_align(KernelCurve, 16);
+
+typedef struct KernelCurveSegment {
+ int prim;
+ int type;
+} KernelCurveSegment;
+static_assert_align(KernelCurveSegment, 8);
+
+typedef struct KernelSpotLight {
+ float radius;
+ float invarea;
+ float spot_angle;
+ float spot_smooth;
+ float dir[3];
+ float pad;
+} KernelSpotLight;
+
+/* PointLight is SpotLight with only radius and invarea being used. */
+
+typedef struct KernelAreaLight {
+ float axisu[3];
+ float invarea;
+ float axisv[3];
+ float tan_spread;
+ float dir[3];
+ float normalize_spread;
+} KernelAreaLight;
+
+typedef struct KernelDistantLight {
+ float radius;
+ float cosangle;
+ float invarea;
+ float pad;
+} KernelDistantLight;
+
+typedef struct KernelLight {
+ int type;
+ float co[3];
+ int shader_id;
+ float max_bounces;
+ float random;
+ float strength[3];
+ float pad1, pad2;
+ Transform tfm;
+ Transform itfm;
+ union {
+ KernelSpotLight spot;
+ KernelAreaLight area;
+ KernelDistantLight distant;
+ };
+} KernelLight;
+static_assert_align(KernelLight, 16);
+
+typedef struct KernelLightDistribution {
+ float totarea;
+ int prim;
+ union {
+ struct {
+ int shader_flag;
+ int object_id;
+ } mesh_light;
+ struct {
+ float pad;
+ float size;
+ } lamp;
+ };
+} KernelLightDistribution;
+static_assert_align(KernelLightDistribution, 16);
+
+typedef struct KernelParticle {
+ int index;
+ float age;
+ float lifetime;
+ float size;
+ float4 rotation;
+ /* Only xyz are used of the following. float4 instead of float3 are used
+ * to ensure consistent padding/alignment across devices. */
+ float4 location;
+ float4 velocity;
+ float4 angular_velocity;
+} KernelParticle;
+static_assert_align(KernelParticle, 16);
+
+typedef struct KernelShader {
+ float constant_emission[3];
+ float cryptomatte_id;
+ int flags;
+ int pass_id;
+ int pad2, pad3;
+} KernelShader;
+static_assert_align(KernelShader, 16);
+
+/* Patches */
+
+#define PATCH_MAX_CONTROL_VERTS 16
+
+/* Patch map node flags */
+
+#define PATCH_MAP_NODE_IS_SET (1 << 30)
+#define PATCH_MAP_NODE_IS_LEAF (1u << 31)
+#define PATCH_MAP_NODE_INDEX_MASK (~(PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF))
+
+/* Work Tiles */
+
+typedef struct KernelWorkTile {
+ uint x, y, w, h;
+
+ uint start_sample;
+ uint num_samples;
+
+ int offset;
+ uint stride;
+
+ /* Precalculated parameters used by init_from_camera kernel on GPU. */
+ int path_index_offset;
+ int work_size;
+} KernelWorkTile;
+
+/* Shader Evaluation.
+ *
+ * Position on a primitive on an object at which we want to evaluate the
+ * shader for e.g. mesh displacement or light importance map. */
+
+typedef struct KernelShaderEvalInput {
+ int object;
+ int prim;
+ float u, v;
+} KernelShaderEvalInput;
+static_assert_align(KernelShaderEvalInput, 16);
+
+/* Pre-computed sample table sizes for PMJ02 sampler. */
+#define NUM_PMJ_DIVISIONS 32
+#define NUM_PMJ_SAMPLES ((NUM_PMJ_DIVISIONS) * (NUM_PMJ_DIVISIONS))
+#define NUM_PMJ_PATTERNS 1
+
+/* Device kernels.
+ *
+ * Identifier for kernels that can be executed in device queues.
+ *
+ * Some implementation details.
+ *
+ * If the kernel uses shared CUDA memory, `CUDADeviceQueue::enqueue` is to be modified.
+ * The path iteration kernels are handled in `PathTraceWorkGPU::enqueue_path_iteration`. */
+
+typedef enum DeviceKernel {
+ DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA = 0,
+ DEVICE_KERNEL_INTEGRATOR_INIT_FROM_BAKE,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW,
+ DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL,
+
+ DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES,
+ DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_STATES,
+ DEVICE_KERNEL_INTEGRATOR_RESET,
+ DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS,
+
+ DEVICE_KERNEL_SHADER_EVAL_DISPLACE,
+ DEVICE_KERNEL_SHADER_EVAL_BACKGROUND,
+ DEVICE_KERNEL_SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY,
+
+#define DECLARE_FILM_CONVERT_KERNEL(variant) \
+ DEVICE_KERNEL_FILM_CONVERT_##variant, DEVICE_KERNEL_FILM_CONVERT_##variant##_HALF_RGBA
+
+ DECLARE_FILM_CONVERT_KERNEL(DEPTH),
+ DECLARE_FILM_CONVERT_KERNEL(MIST),
+ DECLARE_FILM_CONVERT_KERNEL(SAMPLE_COUNT),
+ DECLARE_FILM_CONVERT_KERNEL(FLOAT),
+ DECLARE_FILM_CONVERT_KERNEL(LIGHT_PATH),
+ DECLARE_FILM_CONVERT_KERNEL(FLOAT3),
+ DECLARE_FILM_CONVERT_KERNEL(MOTION),
+ DECLARE_FILM_CONVERT_KERNEL(CRYPTOMATTE),
+ DECLARE_FILM_CONVERT_KERNEL(SHADOW_CATCHER),
+ DECLARE_FILM_CONVERT_KERNEL(SHADOW_CATCHER_MATTE_WITH_SHADOW),
+ DECLARE_FILM_CONVERT_KERNEL(COMBINED),
+ DECLARE_FILM_CONVERT_KERNEL(FLOAT4),
+
+#undef DECLARE_FILM_CONVERT_KERNEL
+
+ DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_CHECK,
+ DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_X,
+ DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_Y,
+
+ DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS,
+ DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO,
+ DEVICE_KERNEL_FILTER_COLOR_PREPROCESS,
+ DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS,
+
+ DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS,
+
+ DEVICE_KERNEL_PREFIX_SUM,
+
+ DEVICE_KERNEL_NUM,
+} DeviceKernel;
+
+enum {
+ DEVICE_KERNEL_INTEGRATOR_NUM = DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL + 1,
+};
+
+/* Kernel Features */
+
+enum KernelFeatureFlag : unsigned int {
+ /* Shader nodes. */
+ KERNEL_FEATURE_NODE_BSDF = (1U << 0U),
+ KERNEL_FEATURE_NODE_EMISSION = (1U << 1U),
+ KERNEL_FEATURE_NODE_VOLUME = (1U << 2U),
+ KERNEL_FEATURE_NODE_HAIR = (1U << 3U),
+ KERNEL_FEATURE_NODE_BUMP = (1U << 4U),
+ KERNEL_FEATURE_NODE_BUMP_STATE = (1U << 5U),
+ KERNEL_FEATURE_NODE_VORONOI_EXTRA = (1U << 6U),
+ KERNEL_FEATURE_NODE_RAYTRACE = (1U << 7U),
+ KERNEL_FEATURE_NODE_AOV = (1U << 8U),
+ KERNEL_FEATURE_NODE_LIGHT_PATH = (1U << 9U),
+
+ /* Use denoising kernels and output denoising passes. */
+ KERNEL_FEATURE_DENOISING = (1U << 10U),
+
+ /* Use path tracing kernels. */
+ KERNEL_FEATURE_PATH_TRACING = (1U << 11U),
+
+ /* BVH/sampling kernel features. */
+ KERNEL_FEATURE_HAIR = (1U << 12U),
+ KERNEL_FEATURE_HAIR_THICK = (1U << 13U),
+ KERNEL_FEATURE_OBJECT_MOTION = (1U << 14U),
+ KERNEL_FEATURE_CAMERA_MOTION = (1U << 15U),
+
+ /* Denotes whether baking functionality is needed. */
+ KERNEL_FEATURE_BAKING = (1U << 16U),
+
+ /* Use subsurface scattering materials. */
+ KERNEL_FEATURE_SUBSURFACE = (1U << 17U),
+
+ /* Use volume materials. */
+ KERNEL_FEATURE_VOLUME = (1U << 18U),
+
+ /* Use OpenSubdiv patch evaluation */
+ KERNEL_FEATURE_PATCH_EVALUATION = (1U << 19U),
+
+ /* Use Transparent shadows */
+ KERNEL_FEATURE_TRANSPARENT = (1U << 20U),
+
+ /* Use shadow catcher. */
+ KERNEL_FEATURE_SHADOW_CATCHER = (1U << 21U),
+
+ /* Per-uber shader usage flags. */
+ KERNEL_FEATURE_PRINCIPLED = (1U << 22U),
+
+ /* Light render passes. */
+ KERNEL_FEATURE_LIGHT_PASSES = (1U << 23U),
+
+ /* Shadow render pass. */
+ KERNEL_FEATURE_SHADOW_PASS = (1U << 24U),
+
+ /* AO. */
+ KERNEL_FEATURE_AO_PASS = (1U << 25U),
+ KERNEL_FEATURE_AO_ADDITIVE = (1U << 26U),
+ KERNEL_FEATURE_AO = (KERNEL_FEATURE_AO_PASS | KERNEL_FEATURE_AO_ADDITIVE),
+};
+
+/* Shader node feature mask, to specialize shader evaluation for kernels. */
+
+#define KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT \
+ (KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VORONOI_EXTRA | \
+ KERNEL_FEATURE_NODE_LIGHT_PATH)
+#define KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW \
+ (KERNEL_FEATURE_NODE_BSDF | KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VOLUME | \
+ KERNEL_FEATURE_NODE_HAIR | KERNEL_FEATURE_NODE_BUMP | KERNEL_FEATURE_NODE_BUMP_STATE | \
+ KERNEL_FEATURE_NODE_VORONOI_EXTRA | KERNEL_FEATURE_NODE_LIGHT_PATH)
+#define KERNEL_FEATURE_NODE_MASK_SURFACE \
+ (KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW | KERNEL_FEATURE_NODE_RAYTRACE | \
+ KERNEL_FEATURE_NODE_AOV | KERNEL_FEATURE_NODE_LIGHT_PATH)
+#define KERNEL_FEATURE_NODE_MASK_VOLUME \
+ (KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VOLUME | \
+ KERNEL_FEATURE_NODE_VORONOI_EXTRA | KERNEL_FEATURE_NODE_LIGHT_PATH)
+#define KERNEL_FEATURE_NODE_MASK_DISPLACEMENT \
+ (KERNEL_FEATURE_NODE_VORONOI_EXTRA | KERNEL_FEATURE_NODE_BUMP | KERNEL_FEATURE_NODE_BUMP_STATE)
+#define KERNEL_FEATURE_NODE_MASK_BUMP KERNEL_FEATURE_NODE_MASK_DISPLACEMENT
+
+/* Must be constexpr on the CPU to avoid compile errors because the state types
+ * are different depending on the main, shadow or null path. For GPU we don't have
+ * C++17 everywhere so can't use it. */
+#ifdef __KERNEL_CPU__
+# define IF_KERNEL_NODES_FEATURE(feature) \
+ if constexpr ((node_feature_mask & (KERNEL_FEATURE_NODE_##feature)) != 0U)
+#else
+# define IF_KERNEL_NODES_FEATURE(feature) \
+ if ((node_feature_mask & (KERNEL_FEATURE_NODE_##feature)) != 0U)
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/util/color.h b/intern/cycles/kernel/util/color.h
new file mode 100644
index 00000000000..6d17647c9f8
--- /dev/null
+++ b/intern/cycles/kernel/util/color.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "util/color.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device float3 xyz_to_rgb(KernelGlobals kg, float3 xyz)
+{
+ return make_float3(dot(float4_to_float3(kernel_data.film.xyz_to_r), xyz),
+ dot(float4_to_float3(kernel_data.film.xyz_to_g), xyz),
+ dot(float4_to_float3(kernel_data.film.xyz_to_b), xyz));
+}
+
+ccl_device float linear_rgb_to_gray(KernelGlobals kg, float3 c)
+{
+ return dot(c, float4_to_float3(kernel_data.film.rgb_to_y));
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_differential.h b/intern/cycles/kernel/util/differential.h
index 17187083019..17187083019 100644
--- a/intern/cycles/kernel/kernel_differential.h
+++ b/intern/cycles/kernel/util/differential.h
diff --git a/intern/cycles/kernel/util/lookup_table.h b/intern/cycles/kernel/util/lookup_table.h
new file mode 100644
index 00000000000..3ffbb4856da
--- /dev/null
+++ b/intern/cycles/kernel/util/lookup_table.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Interpolated lookup table access */
+
+ccl_device float lookup_table_read(KernelGlobals kg, float x, int offset, int size)
+{
+ x = saturatef(x) * (size - 1);
+
+ int index = min(float_to_int(x), size - 1);
+ int nindex = min(index + 1, size - 1);
+ float t = x - index;
+
+ float data0 = kernel_tex_fetch(__lookup_table, index + offset);
+ if (t == 0.0f)
+ return data0;
+
+ float data1 = kernel_tex_fetch(__lookup_table, nindex + offset);
+ return (1.0f - t) * data0 + t * data1;
+}
+
+ccl_device float lookup_table_read_2D(
+ KernelGlobals kg, float x, float y, int offset, int xsize, int ysize)
+{
+ y = saturatef(y) * (ysize - 1);
+
+ int index = min(float_to_int(y), ysize - 1);
+ int nindex = min(index + 1, ysize - 1);
+ float t = y - index;
+
+ float data0 = lookup_table_read(kg, x, offset + xsize * index, xsize);
+ if (t == 0.0f)
+ return data0;
+
+ float data1 = lookup_table_read(kg, x, offset + xsize * nindex, xsize);
+ return (1.0f - t) * data0 + t * data1;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/util/profiling.h b/intern/cycles/kernel/util/profiling.h
new file mode 100644
index 00000000000..12ce441ccbf
--- /dev/null
+++ b/intern/cycles/kernel/util/profiling.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifdef __KERNEL_CPU__
+# include "util/profiling.h"
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __KERNEL_CPU__
+# define PROFILING_INIT(kg, event) \
+ ProfilingHelper profiling_helper((ProfilingState *)&kg->profiler, event)
+# define PROFILING_EVENT(event) profiling_helper.set_event(event)
+# define PROFILING_INIT_FOR_SHADER(kg, event) \
+ ProfilingWithShaderHelper profiling_helper((ProfilingState *)&kg->profiler, event)
+# define PROFILING_SHADER(object, shader) \
+ profiling_helper.set_shader(object, (shader)&SHADER_MASK);
+#else
+# define PROFILING_INIT(kg, event)
+# define PROFILING_EVENT(event)
+# define PROFILING_INIT_FOR_SHADER(kg, event)
+# define PROFILING_SHADER(object, shader)
+#endif /* __KERNEL_CPU__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
deleted file mode 100644
index 323222b8c85..00000000000
--- a/intern/cycles/render/CMakeLists.txt
+++ /dev/null
@@ -1,180 +0,0 @@
-# Copyright 2011-2020 Blender Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set(INC
- ..
- ../../glew-mx
- ../../sky/include
-)
-
-set(INC_SYS
- ${GLEW_INCLUDE_DIR}
-)
-
-set(SRC
- alembic.cpp
- alembic_read.cpp
- attribute.cpp
- background.cpp
- bake.cpp
- buffers.cpp
- camera.cpp
- colorspace.cpp
- constant_fold.cpp
- denoising.cpp
- film.cpp
- geometry.cpp
- graph.cpp
- hair.cpp
- image.cpp
- image_oiio.cpp
- image_sky.cpp
- image_vdb.cpp
- integrator.cpp
- jitter.cpp
- light.cpp
- merge.cpp
- mesh.cpp
- mesh_displace.cpp
- mesh_subdivision.cpp
- nodes.cpp
- procedural.cpp
- object.cpp
- osl.cpp
- particles.cpp
- pass.cpp
- curves.cpp
- scene.cpp
- session.cpp
- shader.cpp
- sobol.cpp
- stats.cpp
- svm.cpp
- tables.cpp
- tile.cpp
- volume.cpp
-)
-
-set(SRC_HEADERS
- alembic.h
- alembic_read.h
- attribute.h
- bake.h
- background.h
- buffers.h
- camera.h
- colorspace.h
- constant_fold.h
- denoising.h
- display_driver.h
- output_driver.h
- film.h
- geometry.h
- graph.h
- hair.h
- image.h
- image_oiio.h
- image_sky.h
- image_vdb.h
- integrator.h
- light.h
- jitter.h
- merge.h
- mesh.h
- nodes.h
- object.h
- osl.h
- particles.h
- pass.h
- procedural.h
- curves.h
- scene.h
- session.h
- shader.h
- sobol.h
- stats.h
- svm.h
- tables.h
- tile.h
- volume.h
-)
-
-set(LIB
- cycles_bvh
- cycles_device
- cycles_integrator
- cycles_subd
- cycles_util
-)
-
-if(CYCLES_STANDALONE_REPOSITORY)
- list(APPEND LIB extern_sky)
-else()
- list(APPEND LIB bf_intern_sky)
-endif()
-
-if(WITH_CYCLES_OSL)
- list(APPEND LIB
- cycles_kernel_osl
- )
-
- SET_PROPERTY(SOURCE osl.cpp PROPERTY COMPILE_FLAGS ${RTTI_DISABLE_FLAGS})
-endif()
-
-if(WITH_OPENCOLORIO)
- add_definitions(-DWITH_OCIO)
- include_directories(
- SYSTEM
- ${OPENCOLORIO_INCLUDE_DIRS}
- )
- list(APPEND LIB
- ${OPENCOLORIO_LIBRARIES}
- )
- if(WIN32)
- add_definitions(-DOpenColorIO_SKIP_IMPORTS)
- endif()
-endif()
-
-if(WITH_OPENVDB)
- add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
- list(APPEND INC_SYS
- ${OPENVDB_INCLUDE_DIRS}
- )
- list(APPEND LIB
- ${OPENVDB_LIBRARIES}
- )
-endif()
-
-if(WITH_ALEMBIC)
- add_definitions(-DWITH_ALEMBIC)
- list(APPEND INC_SYS
- ${ALEMBIC_INCLUDE_DIRS}
- )
- list(APPEND LIB
- ${ALEMBIC_LIBRARIES}
- )
-endif()
-
-if(WITH_NANOVDB)
- list(APPEND INC_SYS
- ${NANOVDB_INCLUDE_DIRS}
- )
-endif()
-
-include_directories(${INC})
-include_directories(SYSTEM ${INC_SYS})
-
-add_definitions(${GL_DEFINITIONS})
-
-cycles_add_library(cycles_render "${LIB}" ${SRC} ${SRC_HEADERS})
diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp
deleted file mode 100644
index 69bc0712674..00000000000
--- a/intern/cycles/render/alembic.cpp
+++ /dev/null
@@ -1,1431 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/alembic.h"
-
-#include "render/alembic_read.h"
-#include "render/camera.h"
-#include "render/curves.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/scene.h"
-#include "render/shader.h"
-
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
-#include "util/util_transform.h"
-#include "util/util_vector.h"
-
-#ifdef WITH_ALEMBIC
-
-using namespace Alembic::AbcGeom;
-
-CCL_NAMESPACE_BEGIN
-
-/* TODO(kevindietrich): motion blur support. */
-
-template<typename SchemaType>
-static vector<FaceSetShaderIndexPair> parse_face_sets_for_shader_assignment(
- SchemaType &schema, const array<Node *> &used_shaders)
-{
- vector<FaceSetShaderIndexPair> result;
-
- std::vector<std::string> face_set_names;
- schema.getFaceSetNames(face_set_names);
-
- if (face_set_names.empty()) {
- return result;
- }
-
- for (const std::string &face_set_name : face_set_names) {
- int shader_index = 0;
-
- for (Node *node : used_shaders) {
- if (node->name == face_set_name) {
- break;
- }
-
- ++shader_index;
- }
-
- if (shader_index >= used_shaders.size()) {
- /* use the first shader instead if none was found */
- shader_index = 0;
- }
-
- const Alembic::AbcGeom::IFaceSet face_set = schema.getFaceSet(face_set_name);
-
- if (!face_set.valid()) {
- continue;
- }
-
- result.push_back({face_set, shader_index});
- }
-
- return result;
-}
-
-void CachedData::clear()
-{
- attributes.clear();
- curve_first_key.clear();
- curve_keys.clear();
- curve_radius.clear();
- curve_shader.clear();
- num_ngons.clear();
- shader.clear();
- subd_creases_edge.clear();
- subd_creases_weight.clear();
- subd_face_corners.clear();
- subd_num_corners.clear();
- subd_ptex_offset.clear();
- subd_smooth.clear();
- subd_start_corner.clear();
- transforms.clear();
- triangles.clear();
- uv_loops.clear();
- vertices.clear();
-
- for (CachedAttribute &attr : attributes) {
- attr.data.clear();
- }
-
- attributes.clear();
-}
-
-CachedData::CachedAttribute &CachedData::add_attribute(const ustring &name,
- const TimeSampling &time_sampling)
-{
- for (auto &attr : attributes) {
- if (attr.name == name) {
- return attr;
- }
- }
-
- CachedAttribute &attr = attributes.emplace_back();
- attr.name = name;
- attr.data.set_time_sampling(time_sampling);
- return attr;
-}
-
-bool CachedData::is_constant() const
-{
-# define CHECK_IF_CONSTANT(data) \
- if (!data.is_constant()) { \
- return false; \
- }
-
- CHECK_IF_CONSTANT(curve_first_key)
- CHECK_IF_CONSTANT(curve_keys)
- CHECK_IF_CONSTANT(curve_radius)
- CHECK_IF_CONSTANT(curve_shader)
- CHECK_IF_CONSTANT(num_ngons)
- CHECK_IF_CONSTANT(shader)
- CHECK_IF_CONSTANT(subd_creases_edge)
- CHECK_IF_CONSTANT(subd_creases_weight)
- CHECK_IF_CONSTANT(subd_face_corners)
- CHECK_IF_CONSTANT(subd_num_corners)
- CHECK_IF_CONSTANT(subd_ptex_offset)
- CHECK_IF_CONSTANT(subd_smooth)
- CHECK_IF_CONSTANT(subd_start_corner)
- CHECK_IF_CONSTANT(transforms)
- CHECK_IF_CONSTANT(triangles)
- CHECK_IF_CONSTANT(uv_loops)
- CHECK_IF_CONSTANT(vertices)
-
- for (const CachedAttribute &attr : attributes) {
- if (!attr.data.is_constant()) {
- return false;
- }
- }
-
- return true;
-
-# undef CHECK_IF_CONSTANT
-}
-
-void CachedData::invalidate_last_loaded_time(bool attributes_only)
-{
- if (attributes_only) {
- for (CachedAttribute &attr : attributes) {
- attr.data.invalidate_last_loaded_time();
- }
-
- return;
- }
-
- curve_first_key.invalidate_last_loaded_time();
- curve_keys.invalidate_last_loaded_time();
- curve_radius.invalidate_last_loaded_time();
- curve_shader.invalidate_last_loaded_time();
- num_ngons.invalidate_last_loaded_time();
- shader.invalidate_last_loaded_time();
- subd_creases_edge.invalidate_last_loaded_time();
- subd_creases_weight.invalidate_last_loaded_time();
- subd_face_corners.invalidate_last_loaded_time();
- subd_num_corners.invalidate_last_loaded_time();
- subd_ptex_offset.invalidate_last_loaded_time();
- subd_smooth.invalidate_last_loaded_time();
- subd_start_corner.invalidate_last_loaded_time();
- transforms.invalidate_last_loaded_time();
- triangles.invalidate_last_loaded_time();
- uv_loops.invalidate_last_loaded_time();
- vertices.invalidate_last_loaded_time();
-}
-
-void CachedData::set_time_sampling(TimeSampling time_sampling)
-{
- curve_first_key.set_time_sampling(time_sampling);
- curve_keys.set_time_sampling(time_sampling);
- curve_radius.set_time_sampling(time_sampling);
- curve_shader.set_time_sampling(time_sampling);
- num_ngons.set_time_sampling(time_sampling);
- shader.set_time_sampling(time_sampling);
- subd_creases_edge.set_time_sampling(time_sampling);
- subd_creases_weight.set_time_sampling(time_sampling);
- subd_face_corners.set_time_sampling(time_sampling);
- subd_num_corners.set_time_sampling(time_sampling);
- subd_ptex_offset.set_time_sampling(time_sampling);
- subd_smooth.set_time_sampling(time_sampling);
- subd_start_corner.set_time_sampling(time_sampling);
- transforms.set_time_sampling(time_sampling);
- triangles.set_time_sampling(time_sampling);
- uv_loops.set_time_sampling(time_sampling);
- vertices.set_time_sampling(time_sampling);
-
- for (CachedAttribute &attr : attributes) {
- attr.data.set_time_sampling(time_sampling);
- }
-}
-
-size_t CachedData::memory_used() const
-{
- size_t mem_used = 0;
-
- mem_used += curve_first_key.memory_used();
- mem_used += curve_keys.memory_used();
- mem_used += curve_radius.memory_used();
- mem_used += curve_shader.memory_used();
- mem_used += num_ngons.memory_used();
- mem_used += shader.memory_used();
- mem_used += subd_creases_edge.memory_used();
- mem_used += subd_creases_weight.memory_used();
- mem_used += subd_face_corners.memory_used();
- mem_used += subd_num_corners.memory_used();
- mem_used += subd_ptex_offset.memory_used();
- mem_used += subd_smooth.memory_used();
- mem_used += subd_start_corner.memory_used();
- mem_used += transforms.memory_used();
- mem_used += triangles.memory_used();
- mem_used += uv_loops.memory_used();
- mem_used += vertices.memory_used();
-
- for (const CachedAttribute &attr : attributes) {
- mem_used += attr.data.memory_used();
- }
-
- return mem_used;
-}
-
-static M44d convert_yup_zup(const M44d &mtx, float scale_mult)
-{
- V3d scale, shear, rotation, translation;
- extractSHRT(mtx,
- scale,
- shear,
- rotation,
- translation,
- true,
- IMATH_INTERNAL_NAMESPACE::Euler<double>::XZY);
-
- M44d rot_mat, scale_mat, trans_mat;
- rot_mat.setEulerAngles(V3d(rotation.x, -rotation.z, rotation.y));
- scale_mat.setScale(V3d(scale.x, scale.z, scale.y));
- trans_mat.setTranslation(V3d(translation.x, -translation.z, translation.y));
-
- M44d temp_mat = scale_mat * rot_mat * trans_mat;
-
- scale_mat.setScale(static_cast<double>(scale_mult));
-
- return temp_mat * scale_mat;
-}
-
-static void transform_decompose(
- const M44d &mat, V3d &scale, V3d &shear, Quatd &rotation, V3d &translation)
-{
- M44d mat_remainder(mat);
-
- /* extract scale and shear */
- Imath::extractAndRemoveScalingAndShear(mat_remainder, scale, shear);
-
- /* extract translation */
- translation.x = mat_remainder[3][0];
- translation.y = mat_remainder[3][1];
- translation.z = mat_remainder[3][2];
-
- /* extract rotation */
- rotation = extractQuat(mat_remainder);
-}
-
-static M44d transform_compose(const V3d &scale,
- const V3d &shear,
- const Quatd &rotation,
- const V3d &translation)
-{
- M44d scale_mat, shear_mat, rot_mat, trans_mat;
-
- scale_mat.setScale(scale);
- shear_mat.setShear(shear);
- rot_mat = rotation.toMatrix44();
- trans_mat.setTranslation(translation);
-
- return scale_mat * shear_mat * rot_mat * trans_mat;
-}
-
-/* get the matrix for the specified time, or return the identity matrix if there is no exact match
- */
-static M44d get_matrix_for_time(const MatrixSampleMap &samples, chrono_t time)
-{
- MatrixSampleMap::const_iterator iter = samples.find(time);
- if (iter != samples.end()) {
- return iter->second;
- }
-
- return M44d();
-}
-
-/* get the matrix for the specified time, or interpolate between samples if there is no exact match
- */
-static M44d get_interpolated_matrix_for_time(const MatrixSampleMap &samples, chrono_t time)
-{
- if (samples.empty()) {
- return M44d();
- }
-
- /* see if exact match */
- MatrixSampleMap::const_iterator iter = samples.find(time);
- if (iter != samples.end()) {
- return iter->second;
- }
-
- if (samples.size() == 1) {
- return samples.begin()->second;
- }
-
- if (time <= samples.begin()->first) {
- return samples.begin()->second;
- }
-
- if (time >= samples.rbegin()->first) {
- return samples.rbegin()->second;
- }
-
- /* find previous and next time sample to interpolate */
- chrono_t prev_time = samples.begin()->first;
- chrono_t next_time = samples.rbegin()->first;
-
- for (MatrixSampleMap::const_iterator I = samples.begin(); I != samples.end(); ++I) {
- chrono_t current_time = (*I).first;
-
- if (current_time > prev_time && current_time <= time) {
- prev_time = current_time;
- }
-
- if (current_time > next_time && current_time >= time) {
- next_time = current_time;
- }
- }
-
- const M44d prev_mat = get_matrix_for_time(samples, prev_time);
- const M44d next_mat = get_matrix_for_time(samples, next_time);
-
- V3d prev_scale, next_scale;
- V3d prev_shear, next_shear;
- V3d prev_translation, next_translation;
- Quatd prev_rotation, next_rotation;
-
- transform_decompose(prev_mat, prev_scale, prev_shear, prev_rotation, prev_translation);
- transform_decompose(next_mat, next_scale, next_shear, next_rotation, next_translation);
-
- chrono_t t = (time - prev_time) / (next_time - prev_time);
-
- /* Ensure rotation around the shortest angle. */
- if ((prev_rotation ^ next_rotation) < 0) {
- next_rotation = -next_rotation;
- }
-
- return transform_compose(Imath::lerp(prev_scale, next_scale, t),
- Imath::lerp(prev_shear, next_shear, t),
- Imath::slerp(prev_rotation, next_rotation, t),
- Imath::lerp(prev_translation, next_translation, t));
-}
-
-static void concatenate_xform_samples(const MatrixSampleMap &parent_samples,
- const MatrixSampleMap &local_samples,
- MatrixSampleMap &output_samples)
-{
- set<chrono_t> union_of_samples;
-
- for (const std::pair<chrono_t, M44d> pair : parent_samples) {
- union_of_samples.insert(pair.first);
- }
-
- for (const std::pair<chrono_t, M44d> pair : local_samples) {
- union_of_samples.insert(pair.first);
- }
-
- foreach (chrono_t time, union_of_samples) {
- M44d parent_matrix = get_interpolated_matrix_for_time(parent_samples, time);
- M44d local_matrix = get_interpolated_matrix_for_time(local_samples, time);
-
- output_samples[time] = local_matrix * parent_matrix;
- }
-}
-
-static Transform make_transform(const M44d &a, float scale)
-{
- M44d m = convert_yup_zup(a, scale);
- Transform trans;
- for (int j = 0; j < 3; j++) {
- for (int i = 0; i < 4; i++) {
- trans[j][i] = static_cast<float>(m[i][j]);
- }
- }
- return trans;
-}
-
-NODE_DEFINE(AlembicObject)
-{
- NodeType *type = NodeType::add("alembic_object", create);
-
- SOCKET_STRING(path, "Alembic Path", ustring());
- SOCKET_NODE_ARRAY(used_shaders, "Used Shaders", Shader::get_node_type());
-
- SOCKET_BOOLEAN(ignore_subdivision, "Ignore Subdivision", true);
-
- SOCKET_INT(subd_max_level, "Max Subdivision Level", 1);
- SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 1.0f);
-
- SOCKET_FLOAT(radius_scale, "Radius Scale", 1.0f);
-
- return type;
-}
-
-AlembicObject::AlembicObject() : Node(get_node_type())
-{
- schema_type = INVALID;
-}
-
-AlembicObject::~AlembicObject()
-{
-}
-
-void AlembicObject::set_object(Object *object_)
-{
- object = object_;
-}
-
-Object *AlembicObject::get_object()
-{
- return object;
-}
-
-bool AlembicObject::has_data_loaded() const
-{
- return data_loaded;
-}
-
-void AlembicObject::load_data_in_cache(CachedData &cached_data,
- AlembicProcedural *proc,
- IPolyMeshSchema &schema,
- Progress &progress)
-{
- /* Only load data for the original Geometry. */
- if (instance_of) {
- return;
- }
-
- cached_data.clear();
-
- PolyMeshSchemaData data;
- data.topology_variance = schema.getTopologyVariance();
- data.time_sampling = schema.getTimeSampling();
- data.positions = schema.getPositionsProperty();
- data.face_counts = schema.getFaceCountsProperty();
- data.face_indices = schema.getFaceIndicesProperty();
- data.normals = schema.getNormalsParam();
- data.num_samples = schema.getNumSamples();
- data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders());
-
- read_geometry_data(proc, cached_data, data, progress);
-
- if (progress.get_cancel()) {
- return;
- }
-
- /* Use the schema as the base compound property to also be able to look for top level properties.
- */
- read_attributes(
- proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
-
- if (progress.get_cancel()) {
- return;
- }
-
- cached_data.invalidate_last_loaded_time(true);
- data_loaded = true;
-}
-
-void AlembicObject::load_data_in_cache(CachedData &cached_data,
- AlembicProcedural *proc,
- ISubDSchema &schema,
- Progress &progress)
-{
- /* Only load data for the original Geometry. */
- if (instance_of) {
- return;
- }
-
- cached_data.clear();
-
- if (this->get_ignore_subdivision()) {
- PolyMeshSchemaData data;
- data.topology_variance = schema.getTopologyVariance();
- data.time_sampling = schema.getTimeSampling();
- data.positions = schema.getPositionsProperty();
- data.face_counts = schema.getFaceCountsProperty();
- data.face_indices = schema.getFaceIndicesProperty();
- data.num_samples = schema.getNumSamples();
- data.velocities = schema.getVelocitiesProperty();
- data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders());
-
- read_geometry_data(proc, cached_data, data, progress);
-
- if (progress.get_cancel()) {
- return;
- }
-
- /* Use the schema as the base compound property to also be able to look for top level
- * properties. */
- read_attributes(
- proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
-
- cached_data.invalidate_last_loaded_time(true);
- data_loaded = true;
- return;
- }
-
- SubDSchemaData data;
- data.time_sampling = schema.getTimeSampling();
- data.num_samples = schema.getNumSamples();
- data.topology_variance = schema.getTopologyVariance();
- data.face_counts = schema.getFaceCountsProperty();
- data.face_indices = schema.getFaceIndicesProperty();
- data.positions = schema.getPositionsProperty();
- data.face_varying_interpolate_boundary = schema.getFaceVaryingInterpolateBoundaryProperty();
- data.face_varying_propagate_corners = schema.getFaceVaryingPropagateCornersProperty();
- data.interpolate_boundary = schema.getInterpolateBoundaryProperty();
- data.crease_indices = schema.getCreaseIndicesProperty();
- data.crease_lengths = schema.getCreaseLengthsProperty();
- data.crease_sharpnesses = schema.getCreaseSharpnessesProperty();
- data.corner_indices = schema.getCornerIndicesProperty();
- data.corner_sharpnesses = schema.getCornerSharpnessesProperty();
- data.holes = schema.getHolesProperty();
- data.subdivision_scheme = schema.getSubdivisionSchemeProperty();
- data.velocities = schema.getVelocitiesProperty();
- data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders());
-
- read_geometry_data(proc, cached_data, data, progress);
-
- if (progress.get_cancel()) {
- return;
- }
-
- /* Use the schema as the base compound property to also be able to look for top level properties.
- */
- read_attributes(
- proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
-
- cached_data.invalidate_last_loaded_time(true);
- data_loaded = true;
-}
-
-void AlembicObject::load_data_in_cache(CachedData &cached_data,
- AlembicProcedural *proc,
- const ICurvesSchema &schema,
- Progress &progress)
-{
- /* Only load data for the original Geometry. */
- if (instance_of) {
- return;
- }
-
- cached_data.clear();
-
- CurvesSchemaData data;
- data.positions = schema.getPositionsProperty();
- data.position_weights = schema.getPositionWeightsProperty();
- data.normals = schema.getNormalsParam();
- data.knots = schema.getKnotsProperty();
- data.orders = schema.getOrdersProperty();
- data.widths = schema.getWidthsParam();
- data.velocities = schema.getVelocitiesProperty();
- data.time_sampling = schema.getTimeSampling();
- data.topology_variance = schema.getTopologyVariance();
- data.num_samples = schema.getNumSamples();
- data.num_vertices = schema.getNumVerticesProperty();
- data.default_radius = proc->get_default_radius();
- data.radius_scale = get_radius_scale();
-
- read_geometry_data(proc, cached_data, data, progress);
-
- if (progress.get_cancel()) {
- return;
- }
-
- /* Use the schema as the base compound property to also be able to look for top level properties.
- */
- read_attributes(
- proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
-
- cached_data.invalidate_last_loaded_time(true);
- data_loaded = true;
-}
-
-void AlembicObject::setup_transform_cache(CachedData &cached_data, float scale)
-{
- cached_data.transforms.clear();
- cached_data.transforms.invalidate_last_loaded_time();
-
- if (scale == 0.0f) {
- scale = 1.0f;
- }
-
- if (xform_time_sampling) {
- cached_data.transforms.set_time_sampling(*xform_time_sampling);
- }
-
- if (xform_samples.size() == 0) {
- Transform tfm = transform_scale(make_float3(scale));
- cached_data.transforms.add_data(tfm, 0.0);
- }
- else {
- /* It is possible for a leaf node of the hierarchy to have multiple samples for its transforms
- * if a sibling has animated transforms. So check if we indeed have animated transformations.
- */
- M44d first_matrix = xform_samples.begin()->first;
- bool has_animation = false;
- for (const std::pair<chrono_t, M44d> pair : xform_samples) {
- if (pair.second != first_matrix) {
- has_animation = true;
- break;
- }
- }
-
- if (!has_animation) {
- Transform tfm = make_transform(first_matrix, scale);
- cached_data.transforms.add_data(tfm, 0.0);
- }
- else {
- for (const std::pair<chrono_t, M44d> pair : xform_samples) {
- Transform tfm = make_transform(pair.second, scale);
- cached_data.transforms.add_data(tfm, pair.first);
- }
- }
- }
-}
-
-AttributeRequestSet AlembicObject::get_requested_attributes()
-{
- AttributeRequestSet requested_attributes;
-
- Geometry *geometry = object->get_geometry();
- assert(geometry);
-
- foreach (Node *node, geometry->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
-
- foreach (const AttributeRequest &attr, shader->attributes.requests) {
- if (attr.name != "") {
- requested_attributes.add(attr.name);
- }
- }
- }
-
- return requested_attributes;
-}
-
-/* Update existing attributes and remove any attribute not in the cached_data, those attributes
- * were added by Cycles (e.g. face normals) */
-static void update_attributes(AttributeSet &attributes, CachedData &cached_data, double frame_time)
-{
- set<Attribute *> cached_attributes;
-
- for (CachedData::CachedAttribute &attribute : cached_data.attributes) {
- const CacheLookupResult<array<char>> result = attribute.data.data_for_time(frame_time);
-
- if (result.has_no_data_for_time()) {
- continue;
- }
-
- Attribute *attr = nullptr;
- if (attribute.std != ATTR_STD_NONE) {
- attr = attributes.add(attribute.std, attribute.name);
- }
- else {
- attr = attributes.add(attribute.name, attribute.type_desc, attribute.element);
- }
- assert(attr);
-
- cached_attributes.insert(attr);
-
- if (!result.has_new_data()) {
- continue;
- }
-
- const ccl::array<char> &attr_data = result.get_data();
-
- /* weak way of detecting if the topology has changed
- * todo: reuse code from device_update patch */
- if (attr->buffer.size() != attr_data.size()) {
- attr->buffer.resize(attr_data.size());
- }
-
- memcpy(attr->data(), attr_data.data(), attr_data.size());
- attr->modified = true;
- }
-
- /* remove any attributes not in cached_attributes */
- list<Attribute>::iterator it;
- for (it = attributes.attributes.begin(); it != attributes.attributes.end();) {
- if (cached_attributes.find(&(*it)) == cached_attributes.end()) {
- attributes.remove(it++);
- continue;
- }
-
- it++;
- }
-}
-
-NODE_DEFINE(AlembicProcedural)
-{
- NodeType *type = NodeType::add("alembic", create);
-
- SOCKET_STRING(filepath, "Filename", ustring());
- SOCKET_FLOAT(frame, "Frame", 1.0f);
- SOCKET_FLOAT(start_frame, "Start Frame", 1.0f);
- SOCKET_FLOAT(end_frame, "End Frame", 1.0f);
- SOCKET_FLOAT(frame_rate, "Frame Rate", 24.0f);
- SOCKET_FLOAT(frame_offset, "Frame Offset", 0.0f);
- SOCKET_FLOAT(default_radius, "Default Radius", 0.01f);
- SOCKET_FLOAT(scale, "Scale", 1.0f);
-
- SOCKET_NODE_ARRAY(objects, "Objects", AlembicObject::get_node_type());
-
- SOCKET_BOOLEAN(use_prefetch, "Use Prefetch", true);
- SOCKET_INT(prefetch_cache_size, "Prefetch Cache Size", 4096);
-
- return type;
-}
-
-AlembicProcedural::AlembicProcedural() : Procedural(get_node_type())
-{
- objects_loaded = false;
- scene_ = nullptr;
-}
-
-AlembicProcedural::~AlembicProcedural()
-{
- ccl::set<Geometry *> geometries_set;
- ccl::set<Object *> objects_set;
- ccl::set<AlembicObject *> abc_objects_set;
-
- foreach (Node *node, objects) {
- AlembicObject *abc_object = static_cast<AlembicObject *>(node);
-
- if (abc_object->get_object()) {
- objects_set.insert(abc_object->get_object());
-
- if (abc_object->get_object()->get_geometry()) {
- geometries_set.insert(abc_object->get_object()->get_geometry());
- }
- }
-
- delete_node(abc_object);
- }
-
- /* We may delete a Procedural before rendering started, so scene_ can be null. */
- if (!scene_) {
- assert(geometries_set.empty());
- assert(objects_set.empty());
- return;
- }
-
- scene_->delete_nodes(geometries_set, this);
- scene_->delete_nodes(objects_set, this);
-}
-
-void AlembicProcedural::generate(Scene *scene, Progress &progress)
-{
- assert(scene_ == nullptr || scene_ == scene);
- scene_ = scene;
-
- if (frame < start_frame || frame > end_frame) {
- clear_modified();
- return;
- }
-
- bool need_shader_updates = false;
- bool need_data_updates = false;
-
- foreach (Node *object_node, objects) {
- AlembicObject *object = static_cast<AlembicObject *>(object_node);
-
- if (object->is_modified()) {
- need_data_updates = true;
- }
-
- /* Check if the shaders were modified. */
- if (object->used_shaders_is_modified() && object->get_object() &&
- object->get_object()->get_geometry()) {
- Geometry *geometry = object->get_object()->get_geometry();
- array<Node *> used_shaders = object->get_used_shaders();
- geometry->set_used_shaders(used_shaders);
- need_shader_updates = true;
- }
-
- /* Check for changes in shaders (e.g. newly requested attributes). */
- foreach (Node *shader_node, object->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(shader_node);
-
- if (shader->need_update_geometry()) {
- object->need_shader_update = true;
- need_shader_updates = true;
- }
- }
- }
-
- if (!is_modified() && !need_shader_updates && !need_data_updates) {
- return;
- }
-
- if (!archive.valid()) {
- Alembic::AbcCoreFactory::IFactory factory;
- factory.setPolicy(Alembic::Abc::ErrorHandler::kQuietNoopPolicy);
- archive = factory.getArchive(filepath.c_str());
-
- if (!archive.valid()) {
- /* avoid potential infinite update loops in viewport synchronization */
- filepath.clear();
- clear_modified();
- return;
- }
- }
-
- if (!objects_loaded || objects_is_modified()) {
- load_objects(progress);
- objects_loaded = true;
- }
-
- const chrono_t frame_time = (chrono_t)((frame - frame_offset) / frame_rate);
-
- /* Clear the subdivision caches as the data is stored differently. */
- for (Node *node : objects) {
- AlembicObject *object = static_cast<AlembicObject *>(node);
-
- if (object->schema_type != AlembicObject::SUBD) {
- continue;
- }
-
- if (object->ignore_subdivision_is_modified()) {
- object->clear_cache();
- }
- }
-
- if (use_prefetch_is_modified()) {
- if (!use_prefetch) {
- for (Node *node : objects) {
- AlembicObject *object = static_cast<AlembicObject *>(node);
- object->clear_cache();
- }
- }
- }
-
- if (prefetch_cache_size_is_modified()) {
- /* Check whether the current memory usage fits in the new requested size,
- * abort the render if it is any higher. */
- size_t memory_used = 0ul;
- for (Node *node : objects) {
- AlembicObject *object = static_cast<AlembicObject *>(node);
- memory_used += object->get_cached_data().memory_used();
- }
-
- if (memory_used > get_prefetch_cache_size_in_bytes()) {
- progress.set_error("Error: Alembic Procedural memory limit reached");
- return;
- }
- }
-
- build_caches(progress);
-
- foreach (Node *node, objects) {
- AlembicObject *object = static_cast<AlembicObject *>(node);
-
- if (progress.get_cancel()) {
- return;
- }
-
- /* skip constant objects */
- if (object->is_constant() && !object->is_modified() && !object->need_shader_update &&
- !scale_is_modified()) {
- continue;
- }
-
- if (object->schema_type == AlembicObject::POLY_MESH) {
- read_mesh(object, frame_time);
- }
- else if (object->schema_type == AlembicObject::CURVES) {
- read_curves(object, frame_time);
- }
- else if (object->schema_type == AlembicObject::SUBD) {
- read_subd(object, frame_time);
- }
-
- object->need_shader_update = false;
- object->clear_modified();
- }
-
- clear_modified();
-}
-
-void AlembicProcedural::add_object(AlembicObject *object)
-{
- objects.push_back_slow(object);
- tag_objects_modified();
-}
-
-void AlembicProcedural::tag_update(Scene *scene)
-{
- scene->procedural_manager->tag_update();
-}
-
-AlembicObject *AlembicProcedural::get_or_create_object(const ustring &path)
-{
- foreach (Node *node, objects) {
- AlembicObject *object = static_cast<AlembicObject *>(node);
-
- if (object->get_path() == path) {
- return object;
- }
- }
-
- AlembicObject *object = create_node<AlembicObject>();
- object->set_path(path);
-
- add_object(object);
-
- return object;
-}
-
-void AlembicProcedural::load_objects(Progress &progress)
-{
- unordered_map<string, AlembicObject *> object_map;
-
- foreach (Node *node, objects) {
- AlembicObject *object = static_cast<AlembicObject *>(node);
-
- /* only consider newly added objects */
- if (object->get_object() == nullptr) {
- object_map.insert({object->get_path().c_str(), object});
- }
- }
-
- IObject root = archive.getTop();
-
- for (size_t i = 0; i < root.getNumChildren(); ++i) {
- walk_hierarchy(root, root.getChildHeader(i), {}, object_map, progress);
- }
-
- /* Create nodes in the scene. */
- for (std::pair<string, AlembicObject *> pair : object_map) {
- AlembicObject *abc_object = pair.second;
-
- Geometry *geometry = nullptr;
-
- if (!abc_object->instance_of) {
- if (abc_object->schema_type == AlembicObject::CURVES) {
- geometry = scene_->create_node<Hair>();
- }
- else if (abc_object->schema_type == AlembicObject::POLY_MESH ||
- abc_object->schema_type == AlembicObject::SUBD) {
- geometry = scene_->create_node<Mesh>();
- }
- else {
- continue;
- }
-
- geometry->set_owner(this);
- geometry->name = abc_object->iobject.getName();
-
- array<Node *> used_shaders = abc_object->get_used_shaders();
- geometry->set_used_shaders(used_shaders);
- }
-
- Object *object = scene_->create_node<Object>();
- object->set_owner(this);
- object->set_geometry(geometry);
- object->name = abc_object->iobject.getName();
-
- abc_object->set_object(object);
- }
-
- /* Share geometries between instances. */
- foreach (Node *node, objects) {
- AlembicObject *abc_object = static_cast<AlembicObject *>(node);
-
- if (abc_object->instance_of) {
- abc_object->get_object()->set_geometry(
- abc_object->instance_of->get_object()->get_geometry());
- abc_object->schema_type = abc_object->instance_of->schema_type;
- }
- }
-}
-
-void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame_time)
-{
- CachedData &cached_data = abc_object->get_cached_data();
-
- /* update sockets */
-
- Object *object = abc_object->get_object();
- cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
-
- if (object->is_modified()) {
- object->tag_update(scene_);
- }
-
- /* Only update sockets for the original Geometry. */
- if (abc_object->instance_of) {
- return;
- }
-
- Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
-
- /* Make sure shader ids are also updated. */
- if (mesh->used_shaders_is_modified()) {
- mesh->tag_shader_modified();
- }
-
- cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
-
- cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_shader_socket());
-
- array<int3> *triangle_data = cached_data.triangles.data_for_time(frame_time).get_data_or_null();
- if (triangle_data) {
- array<int> triangles;
- array<bool> smooth;
-
- triangles.reserve(triangle_data->size() * 3);
- smooth.reserve(triangle_data->size());
-
- for (size_t i = 0; i < triangle_data->size(); ++i) {
- int3 tri = (*triangle_data)[i];
- triangles.push_back_reserved(tri.x);
- triangles.push_back_reserved(tri.y);
- triangles.push_back_reserved(tri.z);
- smooth.push_back_reserved(1);
- }
-
- mesh->set_triangles(triangles);
- mesh->set_smooth(smooth);
- }
-
- /* update attributes */
-
- update_attributes(mesh->attributes, cached_data, frame_time);
-
- if (mesh->is_modified()) {
- bool need_rebuild = mesh->triangles_is_modified();
- mesh->tag_update(scene_, need_rebuild);
- }
-}
-
-void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame_time)
-{
- if (abc_object->get_ignore_subdivision()) {
- read_mesh(abc_object, frame_time);
- return;
- }
-
- CachedData &cached_data = abc_object->get_cached_data();
-
- /* Update sockets. */
-
- Object *object = abc_object->get_object();
- cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
-
- if (object->is_modified()) {
- object->tag_update(scene_);
- }
-
- /* Only update sockets for the original Geometry. */
- if (abc_object->instance_of) {
- return;
- }
-
- if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) {
- /* need to reset the current data is something changed */
- cached_data.invalidate_last_loaded_time();
- }
-
- Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
-
- /* Make sure shader ids are also updated. */
- if (mesh->used_shaders_is_modified()) {
- mesh->tag_shader_modified();
- }
-
- /* Cycles overwrites the original triangles when computing displacement, so we always have to
- * repass the data if something is animated (vertices most likely) to avoid buffer overflows. */
- if (!cached_data.is_constant()) {
- cached_data.invalidate_last_loaded_time();
-
- /* remove previous triangles, if any */
- array<int> triangles;
- mesh->set_triangles(triangles);
- }
-
- mesh->clear_non_sockets();
-
- /* Alembic is OpenSubDiv compliant, there is no option to set another subdivision type. */
- mesh->set_subdivision_type(Mesh::SubdivisionType::SUBDIVISION_CATMULL_CLARK);
- mesh->set_subd_max_level(abc_object->get_subd_max_level());
- mesh->set_subd_dicing_rate(abc_object->get_subd_dicing_rate());
-
- cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
-
- /* cached_data.shader is also used for subd_shader */
- cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_subd_shader_socket());
-
- cached_data.subd_start_corner.copy_to_socket(
- frame_time, mesh, mesh->get_subd_start_corner_socket());
-
- cached_data.subd_num_corners.copy_to_socket(
- frame_time, mesh, mesh->get_subd_num_corners_socket());
-
- cached_data.subd_smooth.copy_to_socket(frame_time, mesh, mesh->get_subd_smooth_socket());
-
- cached_data.subd_ptex_offset.copy_to_socket(
- frame_time, mesh, mesh->get_subd_ptex_offset_socket());
-
- cached_data.subd_face_corners.copy_to_socket(
- frame_time, mesh, mesh->get_subd_face_corners_socket());
-
- cached_data.num_ngons.copy_to_socket(frame_time, mesh, mesh->get_num_ngons_socket());
-
- cached_data.subd_creases_edge.copy_to_socket(
- frame_time, mesh, mesh->get_subd_creases_edge_socket());
-
- cached_data.subd_creases_weight.copy_to_socket(
- frame_time, mesh, mesh->get_subd_creases_weight_socket());
-
- mesh->set_num_subd_faces(mesh->get_subd_shader().size());
-
- /* Update attributes. */
-
- update_attributes(mesh->subd_attributes, cached_data, frame_time);
-
- if (mesh->is_modified()) {
- bool need_rebuild = (mesh->triangles_is_modified()) ||
- (mesh->subd_num_corners_is_modified()) ||
- (mesh->subd_shader_is_modified()) || (mesh->subd_smooth_is_modified()) ||
- (mesh->subd_ptex_offset_is_modified()) ||
- (mesh->subd_start_corner_is_modified()) ||
- (mesh->subd_face_corners_is_modified());
-
- mesh->tag_update(scene_, need_rebuild);
- }
-}
-
-void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t frame_time)
-{
- CachedData &cached_data = abc_object->get_cached_data();
-
- /* update sockets */
-
- Object *object = abc_object->get_object();
- cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
-
- if (object->is_modified()) {
- object->tag_update(scene_);
- }
-
- /* Only update sockets for the original Geometry. */
- if (abc_object->instance_of) {
- return;
- }
-
- Hair *hair = static_cast<Hair *>(object->get_geometry());
-
- /* Make sure shader ids are also updated. */
- if (hair->used_shaders_is_modified()) {
- hair->tag_curve_shader_modified();
- }
-
- cached_data.curve_keys.copy_to_socket(frame_time, hair, hair->get_curve_keys_socket());
-
- cached_data.curve_radius.copy_to_socket(frame_time, hair, hair->get_curve_radius_socket());
-
- cached_data.curve_shader.copy_to_socket(frame_time, hair, hair->get_curve_shader_socket());
-
- cached_data.curve_first_key.copy_to_socket(frame_time, hair, hair->get_curve_first_key_socket());
-
- /* update attributes */
-
- update_attributes(hair->attributes, cached_data, frame_time);
-
- const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
- hair->tag_update(scene_, rebuild);
-}
-
-void AlembicProcedural::walk_hierarchy(
- IObject parent,
- const ObjectHeader &header,
- MatrixSamplesData matrix_samples_data,
- const unordered_map<std::string, AlembicObject *> &object_map,
- Progress &progress)
-{
- if (progress.get_cancel()) {
- return;
- }
-
- IObject next_object;
-
- MatrixSampleMap concatenated_xform_samples;
-
- if (IXform::matches(header)) {
- IXform xform(parent, header.getName());
-
- IXformSchema &xs = xform.getSchema();
-
- if (xs.getNumOps() > 0) {
- TimeSamplingPtr ts = xs.getTimeSampling();
- MatrixSampleMap local_xform_samples;
-
- MatrixSampleMap *temp_xform_samples = nullptr;
- if (matrix_samples_data.samples == nullptr) {
- /* If there is no parent transforms, fill the map directly. */
- temp_xform_samples = &concatenated_xform_samples;
- }
- else {
- /* use a temporary map */
- temp_xform_samples = &local_xform_samples;
- }
-
- for (size_t i = 0; i < xs.getNumSamples(); ++i) {
- chrono_t sample_time = ts->getSampleTime(index_t(i));
- XformSample sample = xs.getValue(ISampleSelector(sample_time));
- temp_xform_samples->insert({sample_time, sample.getMatrix()});
- }
-
- if (matrix_samples_data.samples != nullptr) {
- concatenate_xform_samples(
- *matrix_samples_data.samples, local_xform_samples, concatenated_xform_samples);
- }
-
- matrix_samples_data.samples = &concatenated_xform_samples;
- matrix_samples_data.time_sampling = ts;
- }
-
- next_object = xform;
- }
- else if (ISubD::matches(header)) {
- ISubD subd(parent, header.getName());
-
- unordered_map<std::string, AlembicObject *>::const_iterator iter;
- iter = object_map.find(subd.getFullName());
-
- if (iter != object_map.end()) {
- AlembicObject *abc_object = iter->second;
- abc_object->iobject = subd;
- abc_object->schema_type = AlembicObject::SUBD;
-
- if (matrix_samples_data.samples) {
- abc_object->xform_samples = *matrix_samples_data.samples;
- abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
- }
- }
-
- next_object = subd;
- }
- else if (IPolyMesh::matches(header)) {
- IPolyMesh mesh(parent, header.getName());
-
- unordered_map<std::string, AlembicObject *>::const_iterator iter;
- iter = object_map.find(mesh.getFullName());
-
- if (iter != object_map.end()) {
- AlembicObject *abc_object = iter->second;
- abc_object->iobject = mesh;
- abc_object->schema_type = AlembicObject::POLY_MESH;
-
- if (matrix_samples_data.samples) {
- abc_object->xform_samples = *matrix_samples_data.samples;
- abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
- }
- }
-
- next_object = mesh;
- }
- else if (ICurves::matches(header)) {
- ICurves curves(parent, header.getName());
-
- unordered_map<std::string, AlembicObject *>::const_iterator iter;
- iter = object_map.find(curves.getFullName());
-
- if (iter != object_map.end()) {
- AlembicObject *abc_object = iter->second;
- abc_object->iobject = curves;
- abc_object->schema_type = AlembicObject::CURVES;
-
- if (matrix_samples_data.samples) {
- abc_object->xform_samples = *matrix_samples_data.samples;
- abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
- }
- }
-
- next_object = curves;
- }
- else if (IFaceSet::matches(header)) {
- // ignore the face set, it will be read along with the data
- }
- else if (IPoints::matches(header)) {
- // unsupported for now
- }
- else if (INuPatch::matches(header)) {
- // unsupported for now
- }
- else {
- next_object = parent.getChild(header.getName());
-
- if (next_object.isInstanceRoot()) {
- unordered_map<std::string, AlembicObject *>::const_iterator iter;
-
- /* Was this object asked to be rendered? */
- iter = object_map.find(next_object.getFullName());
-
- if (iter != object_map.end()) {
- AlembicObject *abc_object = iter->second;
-
- /* Only try to render an instance if the original object is also rendered. */
- iter = object_map.find(next_object.instanceSourcePath());
-
- if (iter != object_map.end()) {
- abc_object->iobject = next_object;
- abc_object->instance_of = iter->second;
-
- if (matrix_samples_data.samples) {
- abc_object->xform_samples = *matrix_samples_data.samples;
- abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
- }
- }
- }
- }
- }
-
- if (next_object.valid()) {
- for (size_t i = 0; i < next_object.getNumChildren(); ++i) {
- walk_hierarchy(
- next_object, next_object.getChildHeader(i), matrix_samples_data, object_map, progress);
- }
- }
-}
-
-void AlembicProcedural::build_caches(Progress &progress)
-{
- size_t memory_used = 0;
-
- for (Node *node : objects) {
- AlembicObject *object = static_cast<AlembicObject *>(node);
-
- if (progress.get_cancel()) {
- return;
- }
-
- if (object->schema_type == AlembicObject::POLY_MESH) {
- if (!object->has_data_loaded()) {
- IPolyMesh polymesh(object->iobject, Alembic::Abc::kWrapExisting);
- IPolyMeshSchema schema = polymesh.getSchema();
- object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
- }
- else if (object->need_shader_update) {
- IPolyMesh polymesh(object->iobject, Alembic::Abc::kWrapExisting);
- IPolyMeshSchema schema = polymesh.getSchema();
- read_attributes(this,
- object->get_cached_data(),
- schema,
- schema.getUVsParam(),
- object->get_requested_attributes(),
- progress);
- }
- }
- else if (object->schema_type == AlembicObject::CURVES) {
- if (!object->has_data_loaded() || default_radius_is_modified() ||
- object->radius_scale_is_modified()) {
- ICurves curves(object->iobject, Alembic::Abc::kWrapExisting);
- ICurvesSchema schema = curves.getSchema();
- object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
- }
- }
- else if (object->schema_type == AlembicObject::SUBD) {
- if (!object->has_data_loaded()) {
- ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting);
- ISubDSchema schema = subd_mesh.getSchema();
- object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
- }
- else if (object->need_shader_update) {
- ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting);
- ISubDSchema schema = subd_mesh.getSchema();
- read_attributes(this,
- object->get_cached_data(),
- schema,
- schema.getUVsParam(),
- object->get_requested_attributes(),
- progress);
- }
- }
-
- if (scale_is_modified() || object->get_cached_data().transforms.size() == 0) {
- object->setup_transform_cache(object->get_cached_data(), scale);
- }
-
- memory_used += object->get_cached_data().memory_used();
-
- if (use_prefetch) {
- if (memory_used > get_prefetch_cache_size_in_bytes()) {
- progress.set_error("Error: Alembic Procedural memory limit reached");
- return;
- }
- }
- }
-
- VLOG(1) << "AlembicProcedural memory usage : " << string_human_readable_size(memory_used);
-}
-
-CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h
deleted file mode 100644
index 8e166a5ab04..00000000000
--- a/intern/cycles/render/alembic.h
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "graph/node.h"
-#include "render/attribute.h"
-#include "render/procedural.h"
-#include "util/util_set.h"
-#include "util/util_transform.h"
-#include "util/util_vector.h"
-
-#ifdef WITH_ALEMBIC
-
-# include <Alembic/AbcCoreFactory/All.h>
-# include <Alembic/AbcGeom/All.h>
-
-CCL_NAMESPACE_BEGIN
-
-class AlembicProcedural;
-class Geometry;
-class Object;
-class Progress;
-class Shader;
-
-using MatrixSampleMap = std::map<Alembic::Abc::chrono_t, Alembic::Abc::M44d>;
-
-struct MatrixSamplesData {
- MatrixSampleMap *samples = nullptr;
- Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling;
-};
-
-/* Helpers to detect if some type is a `ccl::array`. */
-template<typename> struct is_array : public std::false_type {
-};
-
-template<typename T> struct is_array<array<T>> : public std::true_type {
-};
-
-/* Holds the data for a cache lookup at a given time, as well as information to
- * help disambiguate successes or failures to get data from the cache. */
-template<typename T> class CacheLookupResult {
- enum class State {
- NEW_DATA,
- ALREADY_LOADED,
- NO_DATA_FOR_TIME,
- };
-
- T *data;
- State state;
-
- protected:
- /* Prevent default construction outside of the class: for a valid result, we
- * should use the static functions below. */
- CacheLookupResult() = default;
-
- public:
- static CacheLookupResult new_data(T *data_)
- {
- CacheLookupResult result;
- result.data = data_;
- result.state = State::NEW_DATA;
- return result;
- }
-
- static CacheLookupResult no_data_found_for_time()
- {
- CacheLookupResult result;
- result.data = nullptr;
- result.state = State::NO_DATA_FOR_TIME;
- return result;
- }
-
- static CacheLookupResult already_loaded()
- {
- CacheLookupResult result;
- result.data = nullptr;
- result.state = State::ALREADY_LOADED;
- return result;
- }
-
- /* This should only be call if new data is available. */
- const T &get_data() const
- {
- assert(state == State::NEW_DATA);
- assert(data != nullptr);
- return *data;
- }
-
- T *get_data_or_null() const
- {
- // data_ should already be null if there is no new data so no need to check
- return data;
- }
-
- bool has_new_data() const
- {
- return state == State::NEW_DATA;
- }
-
- bool has_already_loaded() const
- {
- return state == State::ALREADY_LOADED;
- }
-
- bool has_no_data_for_time() const
- {
- return state == State::NO_DATA_FOR_TIME;
- }
-};
-
-/* Store the data set for an animation at every time points, or at the beginning of the animation
- * for constant data.
- *
- * The data is supposed to be stored in chronological order, and is looked up using the current
- * animation time in seconds using the TimeSampling from the Alembic property. */
-template<typename T> class DataStore {
- /* Holds information to map a cache entry for a given time to an index into the data array. */
- struct TimeIndexPair {
- /* Frame time for this entry. */
- double time = 0;
- /* Frame time for the data pointed to by `index`. */
- double source_time = 0;
- /* Index into the data array. */
- size_t index = 0;
- };
-
- /* This is the actual data that is stored. We deduplicate data across frames to avoid storing
- * values if they have not changed yet (e.g. the triangles for a building before fracturing, or a
- * fluid simulation before a break or splash) */
- vector<T> data{};
-
- /* This is used to map they entry for a given time to an index into the data array, multiple
- * frames can point to the same index. */
- vector<TimeIndexPair> index_data_map{};
-
- Alembic::AbcCoreAbstract::TimeSampling time_sampling{};
-
- double last_loaded_time = std::numeric_limits<double>::max();
-
- public:
- /* Keys used to compare values. */
- Alembic::AbcCoreAbstract::ArraySample::Key key1;
- Alembic::AbcCoreAbstract::ArraySample::Key key2;
-
- void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling_)
- {
- time_sampling = time_sampling_;
- }
-
- Alembic::AbcCoreAbstract::TimeSampling get_time_sampling() const
- {
- return time_sampling;
- }
-
- /* Get the data for the specified time.
- * Return nullptr if there is no data or if the data for this time was already loaded. */
- CacheLookupResult<T> data_for_time(double time)
- {
- if (size() == 0) {
- return CacheLookupResult<T>::no_data_found_for_time();
- }
-
- const TimeIndexPair &index = get_index_for_time(time);
-
- if (index.index == -1ul) {
- return CacheLookupResult<T>::no_data_found_for_time();
- }
-
- if (last_loaded_time == index.time || last_loaded_time == index.source_time) {
- return CacheLookupResult<T>::already_loaded();
- }
-
- last_loaded_time = index.source_time;
-
- assert(index.index < data.size());
-
- return CacheLookupResult<T>::new_data(&data[index.index]);
- }
-
- /* get the data for the specified time, but do not check if the data was already loaded for this
- * time return nullptr if there is no data */
- CacheLookupResult<T> data_for_time_no_check(double time)
- {
- if (size() == 0) {
- return CacheLookupResult<T>::no_data_found_for_time();
- }
-
- const TimeIndexPair &index = get_index_for_time(time);
-
- if (index.index == -1ul) {
- return CacheLookupResult<T>::no_data_found_for_time();
- }
-
- assert(index.index < data.size());
-
- return CacheLookupResult<T>::new_data(&data[index.index]);
- }
-
- void add_data(T &data_, double time)
- {
- index_data_map.push_back({time, time, data.size()});
-
- if constexpr (is_array<T>::value) {
- data.emplace_back();
- data.back().steal_data(data_);
- return;
- }
-
- data.push_back(data_);
- }
-
- void reuse_data_for_last_time(double time)
- {
- const TimeIndexPair &data_index = index_data_map.back();
- index_data_map.push_back({time, data_index.source_time, data_index.index});
- }
-
- void add_no_data(double time)
- {
- index_data_map.push_back({time, time, -1ul});
- }
-
- bool is_constant() const
- {
- return data.size() <= 1;
- }
-
- size_t size() const
- {
- return data.size();
- }
-
- void clear()
- {
- invalidate_last_loaded_time();
- data.clear();
- index_data_map.clear();
- }
-
- void invalidate_last_loaded_time()
- {
- last_loaded_time = std::numeric_limits<double>::max();
- }
-
- /* Copy the data for the specified time to the node's socket. If there is no
- * data for this time or it was already loaded, do nothing. */
- void copy_to_socket(double time, Node *node, const SocketType *socket)
- {
- CacheLookupResult<T> result = data_for_time(time);
-
- if (!result.has_new_data()) {
- return;
- }
-
- /* TODO(kevindietrich): arrays are emptied when passed to the sockets, so for now we copy the
- * arrays to avoid reloading the data */
- T value = result.get_data();
- node->set(*socket, value);
- }
-
- size_t memory_used() const
- {
- if constexpr (is_array<T>::value) {
- size_t mem_used = 0;
-
- for (const T &array : data) {
- mem_used += array.size() * sizeof(array[0]);
- }
-
- return mem_used;
- }
-
- return data.size() * sizeof(T);
- }
-
- private:
- const TimeIndexPair &get_index_for_time(double time) const
- {
- std::pair<size_t, Alembic::Abc::chrono_t> index_pair;
- index_pair = time_sampling.getNearIndex(time, index_data_map.size());
- return index_data_map[index_pair.first];
- }
-};
-
-/* Actual cache for the stored data.
- * This caches the topological, transformation, and attribute data for a Mesh node or a Hair node
- * inside of DataStores.
- */
-struct CachedData {
- DataStore<Transform> transforms{};
-
- /* mesh data */
- DataStore<array<float3>> vertices;
- DataStore<array<int3>> triangles{};
- /* triangle "loops" are the polygons' vertices indices used for indexing face varying attributes
- * (like UVs) */
- DataStore<array<int>> uv_loops{};
- DataStore<array<int>> shader{};
-
- /* subd data */
- DataStore<array<int>> subd_start_corner;
- DataStore<array<int>> subd_num_corners;
- DataStore<array<bool>> subd_smooth;
- DataStore<array<int>> subd_ptex_offset;
- DataStore<array<int>> subd_face_corners;
- DataStore<int> num_ngons;
- DataStore<array<int>> subd_creases_edge;
- DataStore<array<float>> subd_creases_weight;
-
- /* hair data */
- DataStore<array<float3>> curve_keys;
- DataStore<array<float>> curve_radius;
- DataStore<array<int>> curve_first_key;
- DataStore<array<int>> curve_shader;
-
- struct CachedAttribute {
- AttributeStandard std;
- AttributeElement element;
- TypeDesc type_desc;
- ustring name;
- DataStore<array<char>> data{};
- };
-
- vector<CachedAttribute> attributes{};
-
- void clear();
-
- CachedAttribute &add_attribute(const ustring &name,
- const Alembic::Abc::TimeSampling &time_sampling);
-
- bool is_constant() const;
-
- void invalidate_last_loaded_time(bool attributes_only = false);
-
- void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling);
-
- size_t memory_used() const;
-};
-
-/* Representation of an Alembic object for the AlembicProcedural.
- *
- * The AlembicObject holds the path to the Alembic IObject inside of the archive that is desired
- * for rendering, as well as the list of shaders that it is using.
- *
- * The names of the shaders should correspond to the names of the FaceSets inside of the Alembic
- * archive for per-triangle shader association. If there is no FaceSets, or the names do not
- * match, the first shader is used for rendering for all triangles.
- */
-class AlembicObject : public Node {
- public:
- NODE_DECLARE
-
- /* Path to the IObject inside of the archive. */
- NODE_SOCKET_API(ustring, path)
-
- /* Shaders used for rendering. */
- NODE_SOCKET_API_ARRAY(array<Node *>, used_shaders)
-
- /* Treat this subdivision object as a regular polygon mesh, so no subdivision will be performed.
- */
- NODE_SOCKET_API(bool, ignore_subdivision)
-
- /* Maximum number of subdivisions for ISubD objects. */
- NODE_SOCKET_API(int, subd_max_level)
-
- /* Finest level of detail (in pixels) for the subdivision. */
- NODE_SOCKET_API(float, subd_dicing_rate)
-
- /* Scale the radius of points and curves. */
- NODE_SOCKET_API(float, radius_scale)
-
- AlembicObject();
- ~AlembicObject();
-
- private:
- friend class AlembicProcedural;
-
- void set_object(Object *object);
- Object *get_object();
-
- void load_data_in_cache(CachedData &cached_data,
- AlembicProcedural *proc,
- Alembic::AbcGeom::IPolyMeshSchema &schema,
- Progress &progress);
- void load_data_in_cache(CachedData &cached_data,
- AlembicProcedural *proc,
- Alembic::AbcGeom::ISubDSchema &schema,
- Progress &progress);
- void load_data_in_cache(CachedData &cached_data,
- AlembicProcedural *proc,
- const Alembic::AbcGeom::ICurvesSchema &schema,
- Progress &progress);
-
- bool has_data_loaded() const;
-
- /* Enumeration used to speed up the discrimination of an IObject as IObject::matches() methods
- * are too expensive and show up in profiles. */
- enum AbcSchemaType {
- INVALID,
- POLY_MESH,
- SUBD,
- CURVES,
- };
-
- bool need_shader_update = true;
-
- AlembicObject *instance_of = nullptr;
-
- Alembic::AbcCoreAbstract::TimeSamplingPtr xform_time_sampling;
- MatrixSampleMap xform_samples;
- Alembic::AbcGeom::IObject iobject;
-
- /* Set if the path points to a valid IObject whose type is supported. */
- AbcSchemaType schema_type;
-
- CachedData &get_cached_data()
- {
- return cached_data_;
- }
-
- bool is_constant() const
- {
- return cached_data_.is_constant();
- }
-
- void clear_cache()
- {
- cached_data_.clear();
- }
-
- Object *object = nullptr;
-
- bool data_loaded = false;
-
- CachedData cached_data_;
-
- void setup_transform_cache(CachedData &cached_data, float scale);
-
- AttributeRequestSet get_requested_attributes();
-};
-
-/* Procedural to render objects from a single Alembic archive.
- *
- * Every object desired to be rendered should be passed as an AlembicObject through the objects
- * socket.
- *
- * This procedural will load the data set for the entire animation in memory on the first frame,
- * and directly set the data for the new frames on the created Nodes if needed. This allows for
- * faster updates between frames as it avoids reseeking the data on disk.
- */
-class AlembicProcedural : public Procedural {
- Alembic::AbcGeom::IArchive archive;
- bool objects_loaded;
- Scene *scene_;
-
- public:
- NODE_DECLARE
-
- /* The file path to the Alembic archive */
- NODE_SOCKET_API(ustring, filepath)
-
- /* The current frame to render. */
- NODE_SOCKET_API(float, frame)
-
- /* The first frame to load data for. */
- NODE_SOCKET_API(float, start_frame)
-
- /* The last frame to load data for. */
- NODE_SOCKET_API(float, end_frame)
-
- /* Subtracted to the current frame. */
- NODE_SOCKET_API(float, frame_offset)
-
- /* The frame rate used for rendering in units of frames per second. */
- NODE_SOCKET_API(float, frame_rate)
-
- /* List of AlembicObjects to render. */
- NODE_SOCKET_API_ARRAY(array<Node *>, objects)
-
- /* Set the default radius to use for curves when the Alembic Curves Schemas do not have radius
- * information. */
- NODE_SOCKET_API(float, default_radius)
-
- /* Multiplier to account for differences in default units for measuring objects in various
- * software. */
- NODE_SOCKET_API(float, scale)
-
- /* Cache controls */
- NODE_SOCKET_API(bool, use_prefetch)
-
- /* Memory limit for the cache, if the data does not fit within this limit, rendering is aborted.
- */
- NODE_SOCKET_API(int, prefetch_cache_size)
-
- AlembicProcedural();
- ~AlembicProcedural();
-
- /* Populates the Cycles scene with Nodes for every contained AlembicObject on the first
- * invocation, and updates the data on subsequent invocations if the frame changed. */
- void generate(Scene *scene, Progress &progress);
-
- /* Tag for an update only if something was modified. */
- void tag_update(Scene *scene);
-
- /* This should be called by scene exporters to request the rendering of an object located
- * in the Alembic archive at the given path.
- *
- * Since we lazily load object, the function does not validate the existence of the object
- * in the archive. If no objects with such path if found in the archive during the next call
- * to `generate`, it will be ignored.
- *
- * Returns a pointer to an existing or a newly created AlembicObject for the given path. */
- AlembicObject *get_or_create_object(const ustring &path);
-
- private:
- /* Add an object to our list of objects, and tag the socket as modified. */
- void add_object(AlembicObject *object);
-
- /* Load the data for all the objects whose data has not yet been loaded. */
- void load_objects(Progress &progress);
-
- /* Traverse the Alembic hierarchy to lookup the IObjects for the AlembicObjects that were
- * specified in our objects socket, and accumulate all of the transformations samples along the
- * way for each IObject. */
- void walk_hierarchy(Alembic::AbcGeom::IObject parent,
- const Alembic::AbcGeom::ObjectHeader &ohead,
- MatrixSamplesData matrix_samples_data,
- const unordered_map<string, AlembicObject *> &object_map,
- Progress &progress);
-
- /* Read the data for an IPolyMesh at the specified frame_time. Creates corresponding Geometry and
- * Object Nodes in the Cycles scene if none exist yet. */
- void read_mesh(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
-
- /* Read the data for an ICurves at the specified frame_time. Creates corresponding Geometry and
- * Object Nodes in the Cycles scene if none exist yet. */
- void read_curves(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
-
- /* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and
- * Object Nodes in the Cycles scene if none exist yet. */
- void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
-
- void build_caches(Progress &progress);
-
- size_t get_prefetch_cache_size_in_bytes() const
- {
- /* prefetch_cache_size is in megabytes, so convert to bytes. */
- return static_cast<size_t>(prefetch_cache_size) * 1024 * 1024;
- }
-};
-
-CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/render/alembic_read.cpp b/intern/cycles/render/alembic_read.cpp
deleted file mode 100644
index b105af63b44..00000000000
--- a/intern/cycles/render/alembic_read.cpp
+++ /dev/null
@@ -1,1037 +0,0 @@
-/*
- * Copyright 2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/alembic_read.h"
-
-#include "render/alembic.h"
-#include "render/mesh.h"
-
-#include "util/util_progress.h"
-
-#ifdef WITH_ALEMBIC
-
-using namespace Alembic::AbcGeom;
-
-CCL_NAMESPACE_BEGIN
-
-static float3 make_float3_from_yup(const V3f &v)
-{
- return make_float3(v.x, -v.z, v.y);
-}
-
-/* get the sample times to load data for the given the start and end frame of the procedural */
-static set<chrono_t> get_relevant_sample_times(AlembicProcedural *proc,
- const TimeSampling &time_sampling,
- size_t num_samples)
-{
- set<chrono_t> result;
-
- if (num_samples < 2) {
- result.insert(0.0);
- return result;
- }
-
- double start_frame;
- double end_frame;
-
- if (proc->get_use_prefetch()) {
- // load the data for the entire animation
- start_frame = static_cast<double>(proc->get_start_frame());
- end_frame = static_cast<double>(proc->get_end_frame());
- }
- else {
- // load the data for the current frame
- start_frame = static_cast<double>(proc->get_frame());
- end_frame = start_frame;
- }
-
- const double frame_rate = static_cast<double>(proc->get_frame_rate());
- const double start_time = start_frame / frame_rate;
- const double end_time = (end_frame + 1) / frame_rate;
-
- const size_t start_index = time_sampling.getFloorIndex(start_time, num_samples).first;
- const size_t end_index = time_sampling.getCeilIndex(end_time, num_samples).first;
-
- for (size_t i = start_index; i < end_index; ++i) {
- result.insert(time_sampling.getSampleTime(i));
- }
-
- return result;
-}
-
-/* Main function to read data, this will iterate over all the relevant sample times for the
- * duration of the requested animation, and call the DataReadingFunc for each of those sample time.
- */
-template<typename Params, typename DataReadingFunc>
-static void read_data_loop(AlembicProcedural *proc,
- CachedData &cached_data,
- const Params &params,
- DataReadingFunc &&func,
- Progress &progress)
-{
- const std::set<chrono_t> times = get_relevant_sample_times(
- proc, *params.time_sampling, params.num_samples);
-
- cached_data.set_time_sampling(*params.time_sampling);
-
- for (chrono_t time : times) {
- if (progress.get_cancel()) {
- return;
- }
-
- func(cached_data, params, time);
- }
-}
-
-/* Polygon Mesh Geometries. */
-
-/* Compute the vertex normals in case none are present in the IPolyMeshSchema, this is mostly used
- * to avoid computing them in the GeometryManager in order to speed up data updates. */
-static void compute_vertex_normals(CachedData &cache, double current_time)
-{
- if (cache.vertices.size() == 0) {
- return;
- }
-
- CachedData::CachedAttribute &attr_normal = cache.add_attribute(
- ustring("N"), cache.vertices.get_time_sampling());
- attr_normal.std = ATTR_STD_VERTEX_NORMAL;
- attr_normal.element = ATTR_ELEMENT_VERTEX;
- attr_normal.type_desc = TypeNormal;
-
- const array<float3> *vertices =
- cache.vertices.data_for_time_no_check(current_time).get_data_or_null();
- const array<int3> *triangles =
- cache.triangles.data_for_time_no_check(current_time).get_data_or_null();
-
- if (!vertices || !triangles) {
- attr_normal.data.add_no_data(current_time);
- return;
- }
-
- array<char> attr_data(vertices->size() * sizeof(float3));
- float3 *attr_ptr = reinterpret_cast<float3 *>(attr_data.data());
- memset(attr_ptr, 0, vertices->size() * sizeof(float3));
-
- for (size_t t = 0; t < triangles->size(); ++t) {
- const int3 tri_int3 = triangles->data()[t];
- Mesh::Triangle tri{};
- tri.v[0] = tri_int3[0];
- tri.v[1] = tri_int3[1];
- tri.v[2] = tri_int3[2];
-
- const float3 tri_N = tri.compute_normal(vertices->data());
-
- for (int v = 0; v < 3; ++v) {
- attr_ptr[tri_int3[v]] += tri_N;
- }
- }
-
- for (size_t v = 0; v < vertices->size(); ++v) {
- attr_ptr[v] = normalize(attr_ptr[v]);
- }
-
- attr_normal.data.add_data(attr_data, current_time);
-}
-
-static void add_normals(const Int32ArraySamplePtr face_indices,
- const IN3fGeomParam &normals,
- double time,
- CachedData &cached_data)
-{
- switch (normals.getScope()) {
- case kFacevaryingScope: {
- const ISampleSelector iss = ISampleSelector(time);
- const IN3fGeomParam::Sample sample = normals.getExpandedValue(iss);
-
- if (!sample.valid()) {
- return;
- }
-
- CachedData::CachedAttribute &attr = cached_data.add_attribute(ustring(normals.getName()),
- *normals.getTimeSampling());
- attr.std = ATTR_STD_VERTEX_NORMAL;
-
- const array<float3> *vertices =
- cached_data.vertices.data_for_time_no_check(time).get_data_or_null();
-
- if (!vertices) {
- return;
- }
-
- array<char> data;
- data.resize(vertices->size() * sizeof(float3));
-
- float3 *data_float3 = reinterpret_cast<float3 *>(data.data());
-
- const int *face_indices_array = face_indices->get();
- const N3fArraySamplePtr values = sample.getVals();
-
- for (size_t i = 0; i < face_indices->size(); ++i) {
- int point_index = face_indices_array[i];
- data_float3[point_index] = make_float3_from_yup(values->get()[i]);
- }
-
- attr.data.add_data(data, time);
- break;
- }
- case kVaryingScope:
- case kVertexScope: {
- const ISampleSelector iss = ISampleSelector(time);
- const IN3fGeomParam::Sample sample = normals.getExpandedValue(iss);
-
- if (!sample.valid()) {
- return;
- }
-
- CachedData::CachedAttribute &attr = cached_data.add_attribute(ustring(normals.getName()),
- *normals.getTimeSampling());
- attr.std = ATTR_STD_VERTEX_NORMAL;
-
- const array<float3> *vertices =
- cached_data.vertices.data_for_time_no_check(time).get_data_or_null();
-
- if (!vertices) {
- return;
- }
-
- array<char> data;
- data.resize(vertices->size() * sizeof(float3));
-
- float3 *data_float3 = reinterpret_cast<float3 *>(data.data());
-
- const Imath::V3f *values = sample.getVals()->get();
-
- for (size_t i = 0; i < vertices->size(); ++i) {
- data_float3[i] = make_float3_from_yup(values[i]);
- }
-
- attr.data.add_data(data, time);
-
- break;
- }
- default: {
- break;
- }
- }
-}
-
-static void add_positions(const P3fArraySamplePtr positions, double time, CachedData &cached_data)
-{
- if (!positions) {
- return;
- }
-
- array<float3> vertices;
- vertices.reserve(positions->size());
-
- for (size_t i = 0; i < positions->size(); i++) {
- V3f f = positions->get()[i];
- vertices.push_back_reserved(make_float3_from_yup(f));
- }
-
- cached_data.vertices.add_data(vertices, time);
-}
-
-static void add_triangles(const Int32ArraySamplePtr face_counts,
- const Int32ArraySamplePtr face_indices,
- double time,
- CachedData &cached_data,
- const array<int> &polygon_to_shader)
-{
- if (!face_counts || !face_indices) {
- return;
- }
-
- const size_t num_faces = face_counts->size();
- const int *face_counts_array = face_counts->get();
- const int *face_indices_array = face_indices->get();
-
- size_t num_triangles = 0;
- for (size_t i = 0; i < face_counts->size(); i++) {
- num_triangles += face_counts_array[i] - 2;
- }
-
- array<int> shader;
- array<int3> triangles;
- array<int> uv_loops;
- shader.reserve(num_triangles);
- triangles.reserve(num_triangles);
- uv_loops.reserve(num_triangles * 3);
- int index_offset = 0;
-
- for (size_t i = 0; i < num_faces; i++) {
- int current_shader = 0;
-
- if (!polygon_to_shader.empty()) {
- current_shader = polygon_to_shader[i];
- }
-
- for (int j = 0; j < face_counts_array[i] - 2; j++) {
- int v0 = face_indices_array[index_offset];
- int v1 = face_indices_array[index_offset + j + 1];
- int v2 = face_indices_array[index_offset + j + 2];
-
- shader.push_back_reserved(current_shader);
-
- /* Alembic orders the loops following the RenderMan convention, so need to go in reverse. */
- triangles.push_back_reserved(make_int3(v2, v1, v0));
- uv_loops.push_back_reserved(index_offset + j + 2);
- uv_loops.push_back_reserved(index_offset + j + 1);
- uv_loops.push_back_reserved(index_offset);
- }
-
- index_offset += face_counts_array[i];
- }
-
- cached_data.triangles.add_data(triangles, time);
- cached_data.uv_loops.add_data(uv_loops, time);
- cached_data.shader.add_data(shader, time);
-}
-
-static array<int> compute_polygon_to_shader_map(
- const Int32ArraySamplePtr &face_counts,
- const vector<FaceSetShaderIndexPair> &face_set_shader_index,
- ISampleSelector sample_sel)
-{
- if (face_set_shader_index.empty()) {
- return {};
- }
-
- if (!face_counts) {
- return {};
- }
-
- if (face_counts->size() == 0) {
- return {};
- }
-
- array<int> polygon_to_shader(face_counts->size());
-
- for (const FaceSetShaderIndexPair &pair : face_set_shader_index) {
- const IFaceSet &face_set = pair.face_set;
- const IFaceSetSchema face_schem = face_set.getSchema();
- const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel);
- const Int32ArraySamplePtr group_faces = face_sample.getFaces();
- const size_t num_group_faces = group_faces->size();
-
- for (size_t l = 0; l < num_group_faces; l++) {
- size_t pos = (*group_faces)[l];
-
- if (pos >= polygon_to_shader.size()) {
- continue;
- }
-
- polygon_to_shader[pos] = pair.shader_index;
- }
- }
-
- return polygon_to_shader;
-}
-
-static void read_poly_mesh_geometry(CachedData &cached_data,
- const PolyMeshSchemaData &data,
- chrono_t time)
-{
- const ISampleSelector iss = ISampleSelector(time);
-
- add_positions(data.positions.getValue(iss), time, cached_data);
-
- const Int32ArraySamplePtr face_counts = data.face_counts.getValue(iss);
- const Int32ArraySamplePtr face_indices = data.face_indices.getValue(iss);
-
- /* Only copy triangles for other frames if the topology is changing over time as well. */
- if (data.topology_variance != kHomogeneousTopology || cached_data.triangles.size() == 0) {
- bool do_triangles = true;
-
- /* Compare key with last one to check whether the topology changed. */
- if (cached_data.triangles.size() > 0) {
- const ArraySample::Key key = face_indices->getKey();
-
- if (key == cached_data.triangles.key1) {
- do_triangles = false;
- }
-
- cached_data.triangles.key1 = key;
- }
-
- if (do_triangles) {
- const array<int> polygon_to_shader = compute_polygon_to_shader_map(
- face_counts, data.shader_face_sets, iss);
- add_triangles(face_counts, face_indices, time, cached_data, polygon_to_shader);
- }
- else {
- cached_data.triangles.reuse_data_for_last_time(time);
- cached_data.uv_loops.reuse_data_for_last_time(time);
- cached_data.shader.reuse_data_for_last_time(time);
- }
-
- /* Initialize the first key. */
- if (data.topology_variance != kHomogeneousTopology && cached_data.triangles.size() == 1) {
- cached_data.triangles.key1 = face_indices->getKey();
- }
- }
-
- if (data.normals.valid()) {
- add_normals(face_indices, data.normals, time, cached_data);
- }
- else {
- compute_vertex_normals(cached_data, time);
- }
-}
-
-void read_geometry_data(AlembicProcedural *proc,
- CachedData &cached_data,
- const PolyMeshSchemaData &data,
- Progress &progress)
-{
- read_data_loop(proc, cached_data, data, read_poly_mesh_geometry, progress);
-}
-
-/* Subdivision Geometries */
-
-static void add_subd_polygons(CachedData &cached_data, const SubDSchemaData &data, chrono_t time)
-{
- const ISampleSelector iss = ISampleSelector(time);
-
- const Int32ArraySamplePtr face_counts = data.face_counts.getValue(iss);
- const Int32ArraySamplePtr face_indices = data.face_indices.getValue(iss);
-
- array<int> subd_start_corner;
- array<int> shader;
- array<int> subd_num_corners;
- array<bool> subd_smooth;
- array<int> subd_ptex_offset;
- array<int> subd_face_corners;
- array<int> uv_loops;
-
- const size_t num_faces = face_counts->size();
- const int *face_counts_array = face_counts->get();
- const int *face_indices_array = face_indices->get();
-
- int num_ngons = 0;
- int num_corners = 0;
- for (size_t i = 0; i < face_counts->size(); i++) {
- num_ngons += (face_counts_array[i] == 4 ? 0 : 1);
- num_corners += face_counts_array[i];
- }
-
- subd_start_corner.reserve(num_faces);
- subd_num_corners.reserve(num_faces);
- subd_smooth.reserve(num_faces);
- subd_ptex_offset.reserve(num_faces);
- shader.reserve(num_faces);
- subd_face_corners.reserve(num_corners);
- uv_loops.reserve(num_corners);
-
- int start_corner = 0;
- int current_shader = 0;
- int ptex_offset = 0;
-
- const array<int> polygon_to_shader = compute_polygon_to_shader_map(
- face_counts, data.shader_face_sets, iss);
-
- for (size_t i = 0; i < face_counts->size(); i++) {
- num_corners = face_counts_array[i];
-
- if (!polygon_to_shader.empty()) {
- current_shader = polygon_to_shader[i];
- }
-
- subd_start_corner.push_back_reserved(start_corner);
- subd_num_corners.push_back_reserved(num_corners);
-
- for (int j = 0; j < num_corners; ++j) {
- subd_face_corners.push_back_reserved(face_indices_array[start_corner + j]);
- uv_loops.push_back_reserved(start_corner + j);
- }
-
- shader.push_back_reserved(current_shader);
- subd_smooth.push_back_reserved(1);
- subd_ptex_offset.push_back_reserved(ptex_offset);
-
- ptex_offset += (num_corners == 4 ? 1 : num_corners);
-
- start_corner += num_corners;
- }
-
- cached_data.shader.add_data(shader, time);
- cached_data.subd_start_corner.add_data(subd_start_corner, time);
- cached_data.subd_num_corners.add_data(subd_num_corners, time);
- cached_data.subd_smooth.add_data(subd_smooth, time);
- cached_data.subd_ptex_offset.add_data(subd_ptex_offset, time);
- cached_data.subd_face_corners.add_data(subd_face_corners, time);
- cached_data.num_ngons.add_data(num_ngons, time);
- cached_data.uv_loops.add_data(uv_loops, time);
-}
-
-static void add_subd_creases(CachedData &cached_data, const SubDSchemaData &data, chrono_t time)
-{
- if (!(data.crease_indices.valid() && data.crease_indices.valid() &&
- data.crease_sharpnesses.valid())) {
- return;
- }
-
- const ISampleSelector iss = ISampleSelector(time);
-
- const Int32ArraySamplePtr creases_length = data.crease_lengths.getValue(iss);
- const Int32ArraySamplePtr creases_indices = data.crease_indices.getValue(iss);
- const FloatArraySamplePtr creases_sharpnesses = data.crease_sharpnesses.getValue(iss);
-
- if (creases_length && creases_indices && creases_sharpnesses) {
- array<int> creases_edge;
- array<float> creases_weight;
-
- creases_edge.reserve(creases_sharpnesses->size() * 2);
- creases_weight.reserve(creases_sharpnesses->size());
-
- int length_offset = 0;
- int weight_offset = 0;
- for (size_t c = 0; c < creases_length->size(); ++c) {
- const int crease_length = creases_length->get()[c];
-
- for (size_t j = 0; j < crease_length - 1; ++j) {
- creases_edge.push_back_reserved(creases_indices->get()[length_offset + j]);
- creases_edge.push_back_reserved(creases_indices->get()[length_offset + j + 1]);
- creases_weight.push_back_reserved(creases_sharpnesses->get()[weight_offset++]);
- }
-
- length_offset += crease_length;
- }
-
- cached_data.subd_creases_edge.add_data(creases_edge, time);
- cached_data.subd_creases_weight.add_data(creases_weight, time);
- }
-}
-
-static void read_subd_geometry(CachedData &cached_data, const SubDSchemaData &data, chrono_t time)
-{
- const ISampleSelector iss = ISampleSelector(time);
-
- add_positions(data.positions.getValue(iss), time, cached_data);
-
- if (data.topology_variance != kHomogenousTopology || cached_data.shader.size() == 0) {
- add_subd_polygons(cached_data, data, time);
- add_subd_creases(cached_data, data, time);
- }
-}
-
-void read_geometry_data(AlembicProcedural *proc,
- CachedData &cached_data,
- const SubDSchemaData &data,
- Progress &progress)
-{
- read_data_loop(proc, cached_data, data, read_subd_geometry, progress);
-}
-
-/* Curve Geometries. */
-
-static void read_curves_data(CachedData &cached_data, const CurvesSchemaData &data, chrono_t time)
-{
- const ISampleSelector iss = ISampleSelector(time);
-
- const Int32ArraySamplePtr curves_num_vertices = data.num_vertices.getValue(iss);
- const P3fArraySamplePtr position = data.positions.getValue(iss);
-
- FloatArraySamplePtr radiuses;
-
- if (data.widths.valid()) {
- IFloatGeomParam::Sample wsample = data.widths.getExpandedValue(iss);
- radiuses = wsample.getVals();
- }
-
- const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
- float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : data.default_radius;
-
- array<float3> curve_keys;
- array<float> curve_radius;
- array<int> curve_first_key;
- array<int> curve_shader;
-
- const bool is_homogenous = data.topology_variance == kHomogenousTopology;
-
- curve_keys.reserve(position->size());
- curve_radius.reserve(position->size());
- curve_first_key.reserve(curves_num_vertices->size());
- curve_shader.reserve(curves_num_vertices->size());
-
- int offset = 0;
- for (size_t i = 0; i < curves_num_vertices->size(); i++) {
- const int num_vertices = curves_num_vertices->get()[i];
-
- for (int j = 0; j < num_vertices; j++) {
- const V3f &f = position->get()[offset + j];
- // todo(@kevindietrich): we are reading too much data?
- curve_keys.push_back_slow(make_float3_from_yup(f));
-
- if (do_radius) {
- radius = (*radiuses)[offset + j];
- }
-
- curve_radius.push_back_slow(radius * data.radius_scale);
- }
-
- if (!is_homogenous || cached_data.curve_first_key.size() == 0) {
- curve_first_key.push_back_reserved(offset);
- curve_shader.push_back_reserved(0);
- }
-
- offset += num_vertices;
- }
-
- cached_data.curve_keys.add_data(curve_keys, time);
- cached_data.curve_radius.add_data(curve_radius, time);
-
- if (!is_homogenous || cached_data.curve_first_key.size() == 0) {
- cached_data.curve_first_key.add_data(curve_first_key, time);
- cached_data.curve_shader.add_data(curve_shader, time);
- }
-}
-
-void read_geometry_data(AlembicProcedural *proc,
- CachedData &cached_data,
- const CurvesSchemaData &data,
- Progress &progress)
-{
- read_data_loop(proc, cached_data, data, read_curves_data, progress);
-}
-
-/* Attributes conversions. */
-
-/* Type traits for converting between Alembic and Cycles types.
- */
-
-template<typename T> struct value_type_converter {
- using cycles_type = float;
- /* Use `TypeDesc::FLOAT` instead of `TypeFloat` to work around a compiler bug in gcc 11. */
- static constexpr TypeDesc type_desc = TypeDesc::FLOAT;
- static constexpr const char *type_name = "float (default)";
-
- static cycles_type convert_value(T value)
- {
- return static_cast<float>(value);
- }
-};
-
-template<> struct value_type_converter<Imath::V2f> {
- using cycles_type = float2;
- static constexpr TypeDesc type_desc = TypeFloat2;
- static constexpr const char *type_name = "float2";
-
- static cycles_type convert_value(Imath::V2f value)
- {
- return make_float2(value.x, value.y);
- }
-};
-
-template<> struct value_type_converter<Imath::V3f> {
- using cycles_type = float3;
- static constexpr TypeDesc type_desc = TypeVector;
- static constexpr const char *type_name = "float3";
-
- static cycles_type convert_value(Imath::V3f value)
- {
- return make_float3_from_yup(value);
- }
-};
-
-template<> struct value_type_converter<Imath::C3f> {
- using cycles_type = uchar4;
- static constexpr TypeDesc type_desc = TypeRGBA;
- static constexpr const char *type_name = "rgb";
-
- static cycles_type convert_value(Imath::C3f value)
- {
- return color_float_to_byte(make_float3(value.x, value.y, value.z));
- }
-};
-
-template<> struct value_type_converter<Imath::C4f> {
- using cycles_type = uchar4;
- static constexpr TypeDesc type_desc = TypeRGBA;
- static constexpr const char *type_name = "rgba";
-
- static cycles_type convert_value(Imath::C4f value)
- {
- return color_float4_to_uchar4(make_float4(value.r, value.g, value.b, value.a));
- }
-};
-
-/* Main function used to read attributes of any type. */
-template<typename TRAIT>
-static void process_attribute(CachedData &cache,
- CachedData::CachedAttribute &attribute,
- GeometryScope scope,
- const typename ITypedGeomParam<TRAIT>::Sample &sample,
- double time)
-{
- using abc_type = typename TRAIT::value_type;
- using cycles_type = typename value_type_converter<abc_type>::cycles_type;
-
- const TypedArraySample<TRAIT> &values = *sample.getVals();
-
- switch (scope) {
- case kConstantScope:
- case kVertexScope: {
- const array<float3> *vertices =
- cache.vertices.data_for_time_no_check(time).get_data_or_null();
-
- if (!vertices) {
- attribute.data.add_no_data(time);
- return;
- }
-
- if (vertices->size() != values.size()) {
- attribute.data.add_no_data(time);
- return;
- }
-
- array<char> data(vertices->size() * sizeof(cycles_type));
-
- cycles_type *pod_typed_data = reinterpret_cast<cycles_type *>(data.data());
-
- for (size_t i = 0; i < values.size(); ++i) {
- *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[i]);
- }
-
- attribute.data.add_data(data, time);
- break;
- }
- case kVaryingScope: {
- const array<int3> *triangles =
- cache.triangles.data_for_time_no_check(time).get_data_or_null();
-
- if (!triangles) {
- attribute.data.add_no_data(time);
- return;
- }
-
- array<char> data(triangles->size() * 3 * sizeof(cycles_type));
-
- cycles_type *pod_typed_data = reinterpret_cast<cycles_type *>(data.data());
-
- for (const int3 &tri : *triangles) {
- *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[tri.x]);
- *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[tri.y]);
- *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[tri.z]);
- }
-
- attribute.data.add_data(data, time);
- break;
- }
- default: {
- break;
- }
- }
-}
-
-/* UVs are processed separately as their indexing is based on loops, instead of vertices or
- * corners. */
-static void process_uvs(CachedData &cache,
- CachedData::CachedAttribute &attribute,
- GeometryScope scope,
- const IV2fGeomParam::Sample &sample,
- double time)
-{
- if (scope != kFacevaryingScope && scope != kVaryingScope && scope != kVertexScope) {
- return;
- }
-
- const array<int> *uv_loops = cache.uv_loops.data_for_time_no_check(time).get_data_or_null();
-
- /* It's ok to not have loop indices, as long as the scope is not face-varying. */
- if (!uv_loops && scope == kFacevaryingScope) {
- return;
- }
-
- const array<int3> *triangles = cache.triangles.data_for_time_no_check(time).get_data_or_null();
- const array<int> *corners =
- cache.subd_face_corners.data_for_time_no_check(time).get_data_or_null();
-
- array<char> data;
- if (triangles) {
- data.resize(triangles->size() * 3 * sizeof(float2));
- }
- else if (corners) {
- data.resize(corners->size() * sizeof(float2));
- }
- else {
- return;
- }
-
- float2 *data_float2 = reinterpret_cast<float2 *>(data.data());
-
- const uint32_t *indices = sample.getIndices()->get();
- const V2f *values = sample.getVals()->get();
-
- if (scope == kFacevaryingScope) {
- for (const int uv_loop_index : *uv_loops) {
- const uint32_t index = indices[uv_loop_index];
- *data_float2++ = make_float2(values[index][0], values[index][1]);
- }
- }
- else if (scope == kVaryingScope || scope == kVertexScope) {
- if (triangles) {
- for (size_t i = 0; i < triangles->size(); i++) {
- const int3 t = (*triangles)[i];
- *data_float2++ = make_float2(values[t.x][0], values[t.x][1]);
- *data_float2++ = make_float2(values[t.y][0], values[t.y][1]);
- *data_float2++ = make_float2(values[t.z][0], values[t.z][1]);
- }
- }
- else if (corners) {
- for (size_t i = 0; i < corners->size(); i++) {
- const int c = (*corners)[i];
- *data_float2++ = make_float2(values[c][0], values[c][1]);
- }
- }
- }
-
- attribute.data.add_data(data, time);
-}
-
-/* Type of the function used to parse one time worth of data, either process_uvs or
- * process_attribute_generic. */
-template<typename TRAIT>
-using process_callback_type = void (*)(CachedData &,
- CachedData::CachedAttribute &,
- GeometryScope,
- const typename ITypedGeomParam<TRAIT>::Sample &,
- double);
-
-/* Main loop to process the attributes, this will look at the given param's TimeSampling and
- * extract data based on which frame time is requested by the procedural and execute the callback
- * for each of those requested time. */
-template<typename TRAIT>
-static void read_attribute_loop(AlembicProcedural *proc,
- CachedData &cache,
- const ITypedGeomParam<TRAIT> &param,
- process_callback_type<TRAIT> callback,
- Progress &progress,
- AttributeStandard std = ATTR_STD_NONE)
-{
- const std::set<chrono_t> times = get_relevant_sample_times(
- proc, *param.getTimeSampling(), param.getNumSamples());
-
- if (times.empty()) {
- return;
- }
-
- std::string name = param.getName();
-
- if (std == ATTR_STD_UV) {
- std::string uv_source_name = Alembic::Abc::GetSourceName(param.getMetaData());
-
- /* According to the convention, primary UVs should have had their name
- * set using Alembic::Abc::SetSourceName, but you can't expect everyone
- * to follow it! :) */
- if (!uv_source_name.empty()) {
- name = uv_source_name;
- }
- }
-
- CachedData::CachedAttribute &attribute = cache.add_attribute(ustring(name),
- *param.getTimeSampling());
-
- using abc_type = typename TRAIT::value_type;
-
- attribute.data.set_time_sampling(*param.getTimeSampling());
- attribute.std = std;
- attribute.type_desc = value_type_converter<abc_type>::type_desc;
-
- if (attribute.type_desc == TypeRGBA) {
- attribute.element = ATTR_ELEMENT_CORNER_BYTE;
- }
- else {
- if (param.getScope() == kVaryingScope || param.getScope() == kFacevaryingScope) {
- attribute.element = ATTR_ELEMENT_CORNER;
- }
- else {
- attribute.element = ATTR_ELEMENT_VERTEX;
- }
- }
-
- for (const chrono_t time : times) {
- if (progress.get_cancel()) {
- return;
- }
-
- ISampleSelector iss = ISampleSelector(time);
- typename ITypedGeomParam<TRAIT>::Sample sample;
- param.getIndexed(sample, iss);
-
- if (!sample.valid()) {
- continue;
- }
-
- if (!sample.getVals()) {
- attribute.data.add_no_data(time);
- continue;
- }
-
- /* Check whether we already loaded constant data. */
- if (attribute.data.size() != 0) {
- if (param.isConstant()) {
- return;
- }
-
- const ArraySample::Key indices_key = sample.getIndices()->getKey();
- const ArraySample::Key values_key = sample.getVals()->getKey();
-
- const bool is_same_as_last_time = (indices_key == attribute.data.key1 &&
- values_key == attribute.data.key2);
-
- attribute.data.key1 = indices_key;
- attribute.data.key2 = values_key;
-
- if (is_same_as_last_time) {
- attribute.data.reuse_data_for_last_time(time);
- continue;
- }
- }
-
- callback(cache, attribute, param.getScope(), sample, time);
- }
-}
-
-/* Attributes requests. */
-
-/* This structure is used to tell which ICoumpoundProperty the PropertyHeader comes from, as we
- * need the parent when downcasting to the proper type. */
-struct PropHeaderAndParent {
- const PropertyHeader *prop;
- ICompoundProperty parent;
-};
-
-/* Parse the ICompoundProperty to look for properties whose names appear in the
- * AttributeRequestSet. This also looks into any child ICompoundProperty of the given
- * ICompoundProperty. If no property of the given name is found, let it be that way, Cycles will
- * use a zero value for the missing attribute. */
-static void parse_requested_attributes_recursive(const AttributeRequestSet &requested_attributes,
- const ICompoundProperty &arb_geom_params,
- vector<PropHeaderAndParent> &requested_properties)
-{
- if (!arb_geom_params.valid()) {
- return;
- }
-
- for (const AttributeRequest &req : requested_attributes.requests) {
- const PropertyHeader *property_header = arb_geom_params.getPropertyHeader(req.name.c_str());
-
- if (!property_header) {
- continue;
- }
-
- requested_properties.push_back({property_header, arb_geom_params});
- }
-
- /* Look into children compound properties. */
- for (size_t i = 0; i < arb_geom_params.getNumProperties(); ++i) {
- const PropertyHeader &property_header = arb_geom_params.getPropertyHeader(i);
-
- if (property_header.isCompound()) {
- ICompoundProperty compound_property = ICompoundProperty(arb_geom_params,
- property_header.getName());
- parse_requested_attributes_recursive(
- requested_attributes, compound_property, requested_properties);
- }
- }
-}
-
-/* Main entry point for parsing requested attributes from an ICompoundProperty, this exists so that
- * we can simply return the list of properties instead of allocating it on the stack and passing it
- * as a parameter. */
-static vector<PropHeaderAndParent> parse_requested_attributes(
- const AttributeRequestSet &requested_attributes, const ICompoundProperty &arb_geom_params)
-{
- vector<PropHeaderAndParent> requested_properties;
- parse_requested_attributes_recursive(
- requested_attributes, arb_geom_params, requested_properties);
- return requested_properties;
-}
-
-/* Read the attributes requested by the shaders from the archive. This will recursively find named
- * attributes from the AttributeRequestSet in the ICompoundProperty and any of its compound child.
- * The attributes are added to the CachedData's attribute list. For each attribute we will try to
- * deduplicate data across consecutive frames. */
-void read_attributes(AlembicProcedural *proc,
- CachedData &cache,
- const ICompoundProperty &arb_geom_params,
- const IV2fGeomParam &default_uvs_param,
- const AttributeRequestSet &requested_attributes,
- Progress &progress)
-{
- if (default_uvs_param.valid()) {
- /* Only the default UVs should be treated as the standard UV attribute. */
- read_attribute_loop(proc, cache, default_uvs_param, process_uvs, progress, ATTR_STD_UV);
- }
-
- vector<PropHeaderAndParent> requested_properties = parse_requested_attributes(
- requested_attributes, arb_geom_params);
-
- for (const PropHeaderAndParent &prop_and_parent : requested_properties) {
- if (progress.get_cancel()) {
- return;
- }
-
- const PropertyHeader *prop = prop_and_parent.prop;
- const ICompoundProperty &parent = prop_and_parent.parent;
-
- if (IBoolGeomParam::matches(*prop)) {
- const IBoolGeomParam &param = IBoolGeomParam(parent, prop->getName());
- read_attribute_loop(proc, cache, param, process_attribute<BooleanTPTraits>, progress);
- }
- else if (IInt32GeomParam::matches(*prop)) {
- const IInt32GeomParam &param = IInt32GeomParam(parent, prop->getName());
- read_attribute_loop(proc, cache, param, process_attribute<Int32TPTraits>, progress);
- }
- else if (IFloatGeomParam::matches(*prop)) {
- const IFloatGeomParam &param = IFloatGeomParam(parent, prop->getName());
- read_attribute_loop(proc, cache, param, process_attribute<Float32TPTraits>, progress);
- }
- else if (IV2fGeomParam::matches(*prop)) {
- const IV2fGeomParam &param = IV2fGeomParam(parent, prop->getName());
- if (Alembic::AbcGeom::isUV(*prop)) {
- read_attribute_loop(proc, cache, param, process_uvs, progress);
- }
- else {
- read_attribute_loop(proc, cache, param, process_attribute<V2fTPTraits>, progress);
- }
- }
- else if (IV3fGeomParam::matches(*prop)) {
- const IV3fGeomParam &param = IV3fGeomParam(parent, prop->getName());
- read_attribute_loop(proc, cache, param, process_attribute<V3fTPTraits>, progress);
- }
- else if (IN3fGeomParam::matches(*prop)) {
- const IN3fGeomParam &param = IN3fGeomParam(parent, prop->getName());
- read_attribute_loop(proc, cache, param, process_attribute<N3fTPTraits>, progress);
- }
- else if (IC3fGeomParam::matches(*prop)) {
- const IC3fGeomParam &param = IC3fGeomParam(parent, prop->getName());
- read_attribute_loop(proc, cache, param, process_attribute<C3fTPTraits>, progress);
- }
- else if (IC4fGeomParam::matches(*prop)) {
- const IC4fGeomParam &param = IC4fGeomParam(parent, prop->getName());
- read_attribute_loop(proc, cache, param, process_attribute<C4fTPTraits>, progress);
- }
- }
-
- cache.invalidate_last_loaded_time(true);
-}
-
-CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/render/alembic_read.h b/intern/cycles/render/alembic_read.h
deleted file mode 100644
index 9cc8622a1ba..00000000000
--- a/intern/cycles/render/alembic_read.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#ifdef WITH_ALEMBIC
-
-# include <Alembic/AbcCoreFactory/All.h>
-# include <Alembic/AbcGeom/All.h>
-
-# include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class AlembicProcedural;
-class AttributeRequestSet;
-class Progress;
-struct CachedData;
-
-/* Maps a FaceSet whose name matches that of a Shader to the index of said shader in the Geometry's
- * used_shaders list. */
-struct FaceSetShaderIndexPair {
- Alembic::AbcGeom::IFaceSet face_set;
- int shader_index;
-};
-
-/* Data of an IPolyMeshSchema that we need to read. */
-struct PolyMeshSchemaData {
- Alembic::AbcGeom::TimeSamplingPtr time_sampling;
- size_t num_samples;
- Alembic::AbcGeom::MeshTopologyVariance topology_variance;
-
- Alembic::AbcGeom::IP3fArrayProperty positions;
- Alembic::AbcGeom::IInt32ArrayProperty face_indices;
- Alembic::AbcGeom::IInt32ArrayProperty face_counts;
-
- Alembic::AbcGeom::IN3fGeomParam normals;
-
- vector<FaceSetShaderIndexPair> shader_face_sets;
-
- // Unsupported for now.
- Alembic::AbcGeom::IV3fArrayProperty velocities;
-};
-
-void read_geometry_data(AlembicProcedural *proc,
- CachedData &cached_data,
- const PolyMeshSchemaData &data,
- Progress &progress);
-
-/* Data of an ISubDSchema that we need to read. */
-struct SubDSchemaData {
- Alembic::AbcGeom::TimeSamplingPtr time_sampling;
- size_t num_samples;
- Alembic::AbcGeom::MeshTopologyVariance topology_variance;
-
- Alembic::AbcGeom::IInt32ArrayProperty face_counts;
- Alembic::AbcGeom::IInt32ArrayProperty face_indices;
- Alembic::AbcGeom::IP3fArrayProperty positions;
-
- Alembic::AbcGeom::IInt32ArrayProperty crease_indices;
- Alembic::AbcGeom::IInt32ArrayProperty crease_lengths;
- Alembic::AbcGeom::IFloatArrayProperty crease_sharpnesses;
-
- vector<FaceSetShaderIndexPair> shader_face_sets;
-
- // Those are unsupported for now.
- Alembic::AbcGeom::IInt32ArrayProperty corner_indices;
- Alembic::AbcGeom::IFloatArrayProperty corner_sharpnesses;
- Alembic::AbcGeom::IInt32Property face_varying_interpolate_boundary;
- Alembic::AbcGeom::IInt32Property face_varying_propagate_corners;
- Alembic::AbcGeom::IInt32Property interpolate_boundary;
- Alembic::AbcGeom::IInt32ArrayProperty holes;
- Alembic::AbcGeom::IStringProperty subdivision_scheme;
- Alembic::AbcGeom::IV3fArrayProperty velocities;
-};
-
-void read_geometry_data(AlembicProcedural *proc,
- CachedData &cached_data,
- const SubDSchemaData &data,
- Progress &progress);
-
-/* Data of a ICurvesSchema that we need to read. */
-struct CurvesSchemaData {
- Alembic::AbcGeom::TimeSamplingPtr time_sampling;
- size_t num_samples;
- Alembic::AbcGeom::MeshTopologyVariance topology_variance;
-
- Alembic::AbcGeom::IP3fArrayProperty positions;
-
- Alembic::AbcGeom::IInt32ArrayProperty num_vertices;
-
- float default_radius;
- float radius_scale;
-
- // Those are unsupported for now.
- Alembic::AbcGeom::IV3fArrayProperty velocities;
- // if this property is invalid then the weight for every point is 1
- Alembic::AbcGeom::IFloatArrayProperty position_weights;
- Alembic::AbcGeom::IN3fGeomParam normals;
- Alembic::AbcGeom::IFloatGeomParam widths;
- Alembic::AbcGeom::IUcharArrayProperty orders;
- Alembic::AbcGeom::IFloatArrayProperty knots;
-
- // TODO(@kevindietrich): type, basis, wrap
-};
-
-void read_geometry_data(AlembicProcedural *proc,
- CachedData &cached_data,
- const CurvesSchemaData &data,
- Progress &progress);
-
-void read_attributes(AlembicProcedural *proc,
- CachedData &cache,
- const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
- const Alembic::AbcGeom::IV2fGeomParam &default_uvs_param,
- const AttributeRequestSet &requested_attributes,
- Progress &progress);
-
-CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
deleted file mode 100644
index d7e6939cd80..00000000000
--- a/intern/cycles/render/attribute.cpp
+++ /dev/null
@@ -1,896 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/attribute.h"
-#include "render/hair.h"
-#include "render/image.h"
-#include "render/mesh.h"
-
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_transform.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Attribute */
-
-Attribute::Attribute(
- ustring name, TypeDesc type, AttributeElement element, Geometry *geom, AttributePrimitive prim)
- : name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0), modified(true)
-{
- /* string and matrix not supported! */
- assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
- type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
- type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix || type == TypeFloat2 ||
- type == TypeFloat4 || type == TypeRGBA);
-
- if (element == ATTR_ELEMENT_VOXEL) {
- buffer.resize(sizeof(ImageHandle));
- new (buffer.data()) ImageHandle();
- }
- else {
- resize(geom, prim, false);
- }
-}
-
-Attribute::~Attribute()
-{
- /* For voxel data, we need to free the image handle. */
- if (element == ATTR_ELEMENT_VOXEL && buffer.size()) {
- ImageHandle &handle = data_voxel();
- handle.~ImageHandle();
- }
-}
-
-void Attribute::resize(Geometry *geom, AttributePrimitive prim, bool reserve_only)
-{
- if (element != ATTR_ELEMENT_VOXEL) {
- if (reserve_only) {
- buffer.reserve(buffer_size(geom, prim));
- }
- else {
- buffer.resize(buffer_size(geom, prim), 0);
- }
- }
-}
-
-void Attribute::resize(size_t num_elements)
-{
- if (element != ATTR_ELEMENT_VOXEL) {
- buffer.resize(num_elements * data_sizeof(), 0);
- }
-}
-
-void Attribute::add(const float &f)
-{
- assert(data_sizeof() == sizeof(float));
-
- char *data = (char *)&f;
- size_t size = sizeof(f);
-
- for (size_t i = 0; i < size; i++)
- buffer.push_back(data[i]);
-
- modified = true;
-}
-
-void Attribute::add(const uchar4 &f)
-{
- assert(data_sizeof() == sizeof(uchar4));
-
- char *data = (char *)&f;
- size_t size = sizeof(f);
-
- for (size_t i = 0; i < size; i++)
- buffer.push_back(data[i]);
-
- modified = true;
-}
-
-void Attribute::add(const float2 &f)
-{
- assert(data_sizeof() == sizeof(float2));
-
- char *data = (char *)&f;
- size_t size = sizeof(f);
-
- for (size_t i = 0; i < size; i++)
- buffer.push_back(data[i]);
-
- modified = true;
-}
-
-void Attribute::add(const float3 &f)
-{
- assert(data_sizeof() == sizeof(float3));
-
- char *data = (char *)&f;
- size_t size = sizeof(f);
-
- for (size_t i = 0; i < size; i++)
- buffer.push_back(data[i]);
-
- modified = true;
-}
-
-void Attribute::add(const Transform &f)
-{
- assert(data_sizeof() == sizeof(Transform));
-
- char *data = (char *)&f;
- size_t size = sizeof(f);
-
- for (size_t i = 0; i < size; i++)
- buffer.push_back(data[i]);
-
- modified = true;
-}
-
-void Attribute::add(const char *data)
-{
- size_t size = data_sizeof();
-
- for (size_t i = 0; i < size; i++)
- buffer.push_back(data[i]);
-
- modified = true;
-}
-
-void Attribute::set_data_from(Attribute &&other)
-{
- assert(other.std == std);
- assert(other.type == type);
- assert(other.element == element);
-
- this->flags = other.flags;
-
- if (this->buffer.size() != other.buffer.size()) {
- this->buffer = std::move(other.buffer);
- modified = true;
- }
- else if (memcmp(this->data(), other.data(), other.buffer.size()) != 0) {
- this->buffer = std::move(other.buffer);
- modified = true;
- }
-}
-
-size_t Attribute::data_sizeof() const
-{
- if (element == ATTR_ELEMENT_VOXEL)
- return sizeof(ImageHandle);
- else if (element == ATTR_ELEMENT_CORNER_BYTE)
- return sizeof(uchar4);
- else if (type == TypeDesc::TypeFloat)
- return sizeof(float);
- else if (type == TypeFloat2)
- return sizeof(float2);
- else if (type == TypeDesc::TypeMatrix)
- return sizeof(Transform);
- else
- return sizeof(float3);
-}
-
-size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
-{
- if (flags & ATTR_FINAL_SIZE) {
- return buffer.size() / data_sizeof();
- }
-
- size_t size = 0;
-
- switch (element) {
- case ATTR_ELEMENT_OBJECT:
- case ATTR_ELEMENT_MESH:
- case ATTR_ELEMENT_VOXEL:
- size = 1;
- break;
- case ATTR_ELEMENT_VERTEX:
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- size = mesh->get_verts().size() + mesh->get_num_ngons();
- if (prim == ATTR_PRIM_SUBD) {
- size -= mesh->get_num_subd_verts();
- }
- }
- break;
- case ATTR_ELEMENT_VERTEX_MOTION:
- if (geom->geometry_type == Geometry::MESH) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- DCHECK_GT(mesh->get_motion_steps(), 0);
- size = (mesh->get_verts().size() + mesh->get_num_ngons()) * (mesh->get_motion_steps() - 1);
- if (prim == ATTR_PRIM_SUBD) {
- size -= mesh->get_num_subd_verts() * (mesh->get_motion_steps() - 1);
- }
- }
- break;
- case ATTR_ELEMENT_FACE:
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (prim == ATTR_PRIM_GEOMETRY) {
- size = mesh->num_triangles();
- }
- else {
- size = mesh->get_num_subd_faces() + mesh->get_num_ngons();
- }
- }
- break;
- case ATTR_ELEMENT_CORNER:
- case ATTR_ELEMENT_CORNER_BYTE:
- if (geom->geometry_type == Geometry::MESH) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (prim == ATTR_PRIM_GEOMETRY) {
- size = mesh->num_triangles() * 3;
- }
- else {
- size = mesh->get_subd_face_corners().size() + mesh->get_num_ngons();
- }
- }
- break;
- case ATTR_ELEMENT_CURVE:
- if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- size = hair->num_curves();
- }
- break;
- case ATTR_ELEMENT_CURVE_KEY:
- if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- size = hair->get_curve_keys().size();
- }
- break;
- case ATTR_ELEMENT_CURVE_KEY_MOTION:
- if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- DCHECK_GT(hair->get_motion_steps(), 0);
- size = hair->get_curve_keys().size() * (hair->get_motion_steps() - 1);
- }
- break;
- default:
- break;
- }
-
- return size;
-}
-
-size_t Attribute::buffer_size(Geometry *geom, AttributePrimitive prim) const
-{
- return element_size(geom, prim) * data_sizeof();
-}
-
-bool Attribute::same_storage(TypeDesc a, TypeDesc b)
-{
- if (a == b)
- return true;
-
- if (a == TypeDesc::TypeColor || a == TypeDesc::TypePoint || a == TypeDesc::TypeVector ||
- a == TypeDesc::TypeNormal) {
- if (b == TypeDesc::TypeColor || b == TypeDesc::TypePoint || b == TypeDesc::TypeVector ||
- b == TypeDesc::TypeNormal) {
- return true;
- }
- }
- return false;
-}
-
-void Attribute::zero_data(void *dst)
-{
- memset(dst, 0, data_sizeof());
-}
-
-void Attribute::add_with_weight(void *dst, void *src, float weight)
-{
- if (element == ATTR_ELEMENT_CORNER_BYTE) {
- for (int i = 0; i < 4; i++) {
- ((uchar *)dst)[i] += uchar(((uchar *)src)[i] * weight);
- }
- }
- else if (same_storage(type, TypeDesc::TypeFloat)) {
- *((float *)dst) += *((float *)src) * weight;
- }
- else if (same_storage(type, TypeFloat2)) {
- *((float2 *)dst) += *((float2 *)src) * weight;
- }
- else if (same_storage(type, TypeDesc::TypeVector)) {
- *((float4 *)dst) += *((float4 *)src) * weight;
- }
- else {
- assert(!"not implemented for this type");
- }
-}
-
-const char *Attribute::standard_name(AttributeStandard std)
-{
- switch (std) {
- case ATTR_STD_VERTEX_NORMAL:
- return "N";
- case ATTR_STD_FACE_NORMAL:
- return "Ng";
- case ATTR_STD_UV:
- return "uv";
- case ATTR_STD_GENERATED:
- return "generated";
- case ATTR_STD_GENERATED_TRANSFORM:
- return "generated_transform";
- case ATTR_STD_UV_TANGENT:
- return "tangent";
- case ATTR_STD_UV_TANGENT_SIGN:
- return "tangent_sign";
- case ATTR_STD_VERTEX_COLOR:
- return "vertex_color";
- case ATTR_STD_POSITION_UNDEFORMED:
- return "undeformed";
- case ATTR_STD_POSITION_UNDISPLACED:
- return "undisplaced";
- case ATTR_STD_MOTION_VERTEX_POSITION:
- return "motion_P";
- case ATTR_STD_MOTION_VERTEX_NORMAL:
- return "motion_N";
- case ATTR_STD_PARTICLE:
- return "particle";
- case ATTR_STD_CURVE_INTERCEPT:
- return "curve_intercept";
- case ATTR_STD_CURVE_LENGTH:
- return "curve_length";
- case ATTR_STD_CURVE_RANDOM:
- return "curve_random";
- case ATTR_STD_PTEX_FACE_ID:
- return "ptex_face_id";
- case ATTR_STD_PTEX_UV:
- return "ptex_uv";
- case ATTR_STD_VOLUME_DENSITY:
- return "density";
- case ATTR_STD_VOLUME_COLOR:
- return "color";
- case ATTR_STD_VOLUME_FLAME:
- return "flame";
- case ATTR_STD_VOLUME_HEAT:
- return "heat";
- case ATTR_STD_VOLUME_TEMPERATURE:
- return "temperature";
- case ATTR_STD_VOLUME_VELOCITY:
- return "velocity";
- case ATTR_STD_POINTINESS:
- return "pointiness";
- case ATTR_STD_RANDOM_PER_ISLAND:
- return "random_per_island";
- case ATTR_STD_SHADOW_TRANSPARENCY:
- return "shadow_transparency";
- case ATTR_STD_NOT_FOUND:
- case ATTR_STD_NONE:
- case ATTR_STD_NUM:
- return "";
- }
-
- return "";
-}
-
-AttributeStandard Attribute::name_standard(const char *name)
-{
- if (name) {
- for (int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) {
- if (strcmp(name, Attribute::standard_name((AttributeStandard)std)) == 0) {
- return (AttributeStandard)std;
- }
- }
- }
-
- return ATTR_STD_NONE;
-}
-
-AttrKernelDataType Attribute::kernel_type(const Attribute &attr)
-{
- if (attr.element == ATTR_ELEMENT_CORNER) {
- return AttrKernelDataType::UCHAR4;
- }
-
- if (attr.type == TypeDesc::TypeFloat) {
- return AttrKernelDataType::FLOAT;
- }
-
- if (attr.type == TypeFloat2) {
- return AttrKernelDataType::FLOAT2;
- }
-
- return AttrKernelDataType::FLOAT3;
-}
-
-void Attribute::get_uv_tiles(Geometry *geom,
- AttributePrimitive prim,
- unordered_set<int> &tiles) const
-{
- if (type != TypeFloat2) {
- return;
- }
-
- const int num = element_size(geom, prim);
- const float2 *uv = data_float2();
- for (int i = 0; i < num; i++, uv++) {
- float u = uv->x, v = uv->y;
- int x = (int)u, y = (int)v;
-
- if (x < 0 || y < 0 || x >= 10) {
- continue;
- }
-
- /* Be conservative in corners - precisely touching the right or upper edge of a tile
- * should not load its right/upper neighbor as well. */
- if (x > 0 && (u < x + 1e-6f)) {
- x--;
- }
- if (y > 0 && (v < y + 1e-6f)) {
- y--;
- }
-
- tiles.insert(1001 + 10 * y + x);
- }
-}
-
-/* Attribute Set */
-
-AttributeSet::AttributeSet(Geometry *geometry, AttributePrimitive prim)
- : modified_flag(~0u), geometry(geometry), prim(prim)
-{
-}
-
-AttributeSet::~AttributeSet()
-{
-}
-
-Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element)
-{
- Attribute *attr = find(name);
-
- if (attr) {
- /* return if same already exists */
- if (attr->type == type && attr->element == element)
- return attr;
-
- /* overwrite attribute with same name but different type/element */
- remove(name);
- }
-
- Attribute new_attr(name, type, element, geometry, prim);
- attributes.emplace_back(std::move(new_attr));
- tag_modified(attributes.back());
- return &attributes.back();
-}
-
-Attribute *AttributeSet::find(ustring name) const
-{
- foreach (const Attribute &attr, attributes)
- if (attr.name == name)
- return (Attribute *)&attr;
-
- return NULL;
-}
-
-void AttributeSet::remove(ustring name)
-{
- Attribute *attr = find(name);
-
- if (attr) {
- list<Attribute>::iterator it;
-
- for (it = attributes.begin(); it != attributes.end(); it++) {
- if (&*it == attr) {
- remove(it);
- return;
- }
- }
- }
-}
-
-Attribute *AttributeSet::add(AttributeStandard std, ustring name)
-{
- Attribute *attr = NULL;
-
- if (name == ustring())
- name = Attribute::standard_name(std);
-
- if (geometry->geometry_type == Geometry::MESH) {
- switch (std) {
- case ATTR_STD_VERTEX_NORMAL:
- attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
- break;
- case ATTR_STD_FACE_NORMAL:
- attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE);
- break;
- case ATTR_STD_UV:
- attr = add(name, TypeFloat2, ATTR_ELEMENT_CORNER);
- break;
- case ATTR_STD_UV_TANGENT:
- attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
- break;
- case ATTR_STD_UV_TANGENT_SIGN:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
- break;
- case ATTR_STD_VERTEX_COLOR:
- attr = add(name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
- break;
- case ATTR_STD_GENERATED:
- case ATTR_STD_POSITION_UNDEFORMED:
- case ATTR_STD_POSITION_UNDISPLACED:
- attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
- break;
- case ATTR_STD_MOTION_VERTEX_POSITION:
- attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX_MOTION);
- break;
- case ATTR_STD_MOTION_VERTEX_NORMAL:
- attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX_MOTION);
- break;
- case ATTR_STD_PTEX_FACE_ID:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE);
- break;
- case ATTR_STD_PTEX_UV:
- attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
- break;
- case ATTR_STD_GENERATED_TRANSFORM:
- attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH);
- break;
- case ATTR_STD_POINTINESS:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
- break;
- case ATTR_STD_RANDOM_PER_ISLAND:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE);
- break;
- default:
- assert(0);
- break;
- }
- }
- else if (geometry->geometry_type == Geometry::VOLUME) {
- switch (std) {
- case ATTR_STD_VERTEX_NORMAL:
- attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
- break;
- case ATTR_STD_FACE_NORMAL:
- attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE);
- break;
- case ATTR_STD_VOLUME_DENSITY:
- case ATTR_STD_VOLUME_FLAME:
- case ATTR_STD_VOLUME_HEAT:
- case ATTR_STD_VOLUME_TEMPERATURE:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL);
- break;
- case ATTR_STD_VOLUME_COLOR:
- attr = add(name, TypeDesc::TypeColor, ATTR_ELEMENT_VOXEL);
- break;
- case ATTR_STD_VOLUME_VELOCITY:
- attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_VOXEL);
- break;
- default:
- assert(0);
- break;
- }
- }
- else if (geometry->geometry_type == Geometry::HAIR) {
- switch (std) {
- case ATTR_STD_UV:
- attr = add(name, TypeFloat2, ATTR_ELEMENT_CURVE);
- break;
- case ATTR_STD_GENERATED:
- attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
- break;
- case ATTR_STD_MOTION_VERTEX_POSITION:
- attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY_MOTION);
- break;
- case ATTR_STD_CURVE_INTERCEPT:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY);
- break;
- case ATTR_STD_CURVE_LENGTH:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE);
- break;
- case ATTR_STD_CURVE_RANDOM:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE);
- break;
- case ATTR_STD_GENERATED_TRANSFORM:
- attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH);
- break;
- case ATTR_STD_POINTINESS:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
- break;
- case ATTR_STD_RANDOM_PER_ISLAND:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE);
- break;
- case ATTR_STD_SHADOW_TRANSPARENCY:
- attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY);
- break;
- default:
- assert(0);
- break;
- }
- }
-
- attr->std = std;
-
- return attr;
-}
-
-Attribute *AttributeSet::find(AttributeStandard std) const
-{
- foreach (const Attribute &attr, attributes)
- if (attr.std == std)
- return (Attribute *)&attr;
-
- return NULL;
-}
-
-void AttributeSet::remove(AttributeStandard std)
-{
- Attribute *attr = find(std);
-
- if (attr) {
- list<Attribute>::iterator it;
-
- for (it = attributes.begin(); it != attributes.end(); it++) {
- if (&*it == attr) {
- remove(it);
- return;
- }
- }
- }
-}
-
-Attribute *AttributeSet::find(AttributeRequest &req)
-{
- if (req.std == ATTR_STD_NONE)
- return find(req.name);
- else
- return find(req.std);
-}
-
-void AttributeSet::remove(Attribute *attribute)
-{
- if (attribute->std == ATTR_STD_NONE) {
- remove(attribute->name);
- }
- else {
- remove(attribute->std);
- }
-}
-
-void AttributeSet::remove(list<Attribute>::iterator it)
-{
- tag_modified(*it);
- attributes.erase(it);
-}
-
-void AttributeSet::resize(bool reserve_only)
-{
- foreach (Attribute &attr, attributes) {
- attr.resize(geometry, prim, reserve_only);
- }
-}
-
-void AttributeSet::clear(bool preserve_voxel_data)
-{
- if (preserve_voxel_data) {
- list<Attribute>::iterator it;
-
- for (it = attributes.begin(); it != attributes.end();) {
- if (it->element == ATTR_ELEMENT_VOXEL || it->std == ATTR_STD_GENERATED_TRANSFORM) {
- it++;
- }
- else {
- attributes.erase(it++);
- }
- }
- }
- else {
- attributes.clear();
- }
-}
-
-void AttributeSet::update(AttributeSet &&new_attributes)
-{
- /* add or update old_attributes based on the new_attributes */
- foreach (Attribute &attr, new_attributes.attributes) {
- Attribute *nattr = add(attr.name, attr.type, attr.element);
- nattr->std = attr.std;
- nattr->set_data_from(std::move(attr));
- }
-
- /* remove any attributes not on new_attributes */
- list<Attribute>::iterator it;
- for (it = attributes.begin(); it != attributes.end();) {
- if (it->std != ATTR_STD_NONE) {
- if (new_attributes.find(it->std) == nullptr) {
- remove(it++);
- continue;
- }
- }
- else if (it->name != "") {
- if (new_attributes.find(it->name) == nullptr) {
- remove(it++);
- continue;
- }
- }
-
- it++;
- }
-
- /* If all attributes were replaced, transform is no longer applied. */
- geometry->transform_applied = false;
-}
-
-void AttributeSet::clear_modified()
-{
- foreach (Attribute &attr, attributes) {
- attr.modified = false;
- }
-
- modified_flag = 0;
-}
-
-void AttributeSet::tag_modified(const Attribute &attr)
-{
- /* Some attributes are not stored in the various kernel attribute arrays
- * (DeviceScene::attribute_*), so the modified flags are only set if the associated standard
- * corresponds to an attribute which will be stored in the kernel's attribute arrays. */
- const bool modifies_device_array = (attr.std != ATTR_STD_FACE_NORMAL &&
- attr.std != ATTR_STD_VERTEX_NORMAL);
-
- if (modifies_device_array) {
- AttrKernelDataType kernel_type = Attribute::kernel_type(attr);
- modified_flag |= (1u << kernel_type);
- }
-}
-
-bool AttributeSet::modified(AttrKernelDataType kernel_type) const
-{
- return (modified_flag & (1u << kernel_type)) != 0;
-}
-
-/* AttributeRequest */
-
-AttributeRequest::AttributeRequest(ustring name_)
-{
- name = name_;
- std = ATTR_STD_NONE;
-
- type = TypeDesc::TypeFloat;
- desc.element = ATTR_ELEMENT_NONE;
- desc.offset = 0;
- desc.type = NODE_ATTR_FLOAT;
-
- subd_type = TypeDesc::TypeFloat;
- subd_desc.element = ATTR_ELEMENT_NONE;
- subd_desc.offset = 0;
- subd_desc.type = NODE_ATTR_FLOAT;
-}
-
-AttributeRequest::AttributeRequest(AttributeStandard std_)
-{
- name = ustring();
- std = std_;
-
- type = TypeDesc::TypeFloat;
- desc.element = ATTR_ELEMENT_NONE;
- desc.offset = 0;
- desc.type = NODE_ATTR_FLOAT;
-
- subd_type = TypeDesc::TypeFloat;
- subd_desc.element = ATTR_ELEMENT_NONE;
- subd_desc.offset = 0;
- subd_desc.type = NODE_ATTR_FLOAT;
-}
-
-/* AttributeRequestSet */
-
-AttributeRequestSet::AttributeRequestSet()
-{
-}
-
-AttributeRequestSet::~AttributeRequestSet()
-{
-}
-
-bool AttributeRequestSet::modified(const AttributeRequestSet &other)
-{
- if (requests.size() != other.requests.size())
- return true;
-
- for (size_t i = 0; i < requests.size(); i++) {
- bool found = false;
-
- for (size_t j = 0; j < requests.size() && !found; j++)
- if (requests[i].name == other.requests[j].name && requests[i].std == other.requests[j].std) {
- found = true;
- }
-
- if (!found) {
- return true;
- }
- }
-
- return false;
-}
-
-void AttributeRequestSet::add(ustring name)
-{
- foreach (AttributeRequest &req, requests) {
- if (req.name == name) {
- return;
- }
- }
-
- requests.push_back(AttributeRequest(name));
-}
-
-void AttributeRequestSet::add(AttributeStandard std)
-{
- foreach (AttributeRequest &req, requests)
- if (req.std == std)
- return;
-
- requests.push_back(AttributeRequest(std));
-}
-
-void AttributeRequestSet::add(AttributeRequestSet &reqs)
-{
- foreach (AttributeRequest &req, reqs.requests) {
- if (req.std == ATTR_STD_NONE)
- add(req.name);
- else
- add(req.std);
- }
-}
-
-void AttributeRequestSet::add_standard(ustring name)
-{
- if (name.empty()) {
- return;
- }
-
- AttributeStandard std = Attribute::name_standard(name.c_str());
-
- if (std) {
- add(std);
- }
- else {
- add(name);
- }
-}
-
-bool AttributeRequestSet::find(ustring name)
-{
- foreach (AttributeRequest &req, requests)
- if (req.name == name)
- return true;
-
- return false;
-}
-
-bool AttributeRequestSet::find(AttributeStandard std)
-{
- foreach (AttributeRequest &req, requests)
- if (req.std == std)
- return true;
-
- return false;
-}
-
-size_t AttributeRequestSet::size()
-{
- return requests.size();
-}
-
-void AttributeRequestSet::clear()
-{
- requests.clear();
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
deleted file mode 100644
index 004c267cabc..00000000000
--- a/intern/cycles/render/attribute.h
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __ATTRIBUTE_H__
-#define __ATTRIBUTE_H__
-
-#include "render/image.h"
-
-#include "kernel/kernel_types.h"
-
-#include "util/util_list.h"
-#include "util/util_param.h"
-#include "util/util_set.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Attribute;
-class AttributeRequest;
-class AttributeRequestSet;
-class AttributeSet;
-class ImageHandle;
-class Geometry;
-class Hair;
-class Mesh;
-struct Transform;
-
-/* AttrKernelDataType.
- *
- * The data type of the device arrays storing the attribute's data. Those data types are different
- * than the ones for attributes as some attribute types are stored in the same array, e.g. Point,
- * Vector, and Transform are all stored as float3 in the kernel.
- *
- * The values of this enumeration are also used as flags to detect changes in AttributeSet. */
-
-enum AttrKernelDataType {
- FLOAT = 0,
- FLOAT2 = 1,
- FLOAT3 = 2,
- UCHAR4 = 3,
-};
-
-/* Attribute
- *
- * Arbitrary data layers on meshes.
- * Supported types: Float, Color, Vector, Normal, Point */
-
-class Attribute {
- public:
- ustring name;
- AttributeStandard std;
-
- TypeDesc type;
- vector<char> buffer;
- AttributeElement element;
- uint flags; /* enum AttributeFlag */
-
- bool modified;
-
- Attribute(ustring name,
- TypeDesc type,
- AttributeElement element,
- Geometry *geom,
- AttributePrimitive prim);
- Attribute(Attribute &&other) = default;
- Attribute(const Attribute &other) = delete;
- Attribute &operator=(const Attribute &other) = delete;
- ~Attribute();
-
- void set(ustring name, TypeDesc type, AttributeElement element);
- void resize(Geometry *geom, AttributePrimitive prim, bool reserve_only);
- void resize(size_t num_elements);
-
- size_t data_sizeof() const;
- size_t element_size(Geometry *geom, AttributePrimitive prim) const;
- size_t buffer_size(Geometry *geom, AttributePrimitive prim) const;
-
- char *data()
- {
- return (buffer.size()) ? &buffer[0] : NULL;
- }
- float2 *data_float2()
- {
- assert(data_sizeof() == sizeof(float2));
- return (float2 *)data();
- }
- float3 *data_float3()
- {
- assert(data_sizeof() == sizeof(float3));
- return (float3 *)data();
- }
- float4 *data_float4()
- {
- assert(data_sizeof() == sizeof(float4));
- return (float4 *)data();
- }
- float *data_float()
- {
- assert(data_sizeof() == sizeof(float));
- return (float *)data();
- }
- uchar4 *data_uchar4()
- {
- assert(data_sizeof() == sizeof(uchar4));
- return (uchar4 *)data();
- }
- Transform *data_transform()
- {
- assert(data_sizeof() == sizeof(Transform));
- return (Transform *)data();
- }
-
- /* Attributes for voxels are images */
- ImageHandle &data_voxel()
- {
- assert(data_sizeof() == sizeof(ImageHandle));
- return *(ImageHandle *)data();
- }
-
- const char *data() const
- {
- return (buffer.size()) ? &buffer[0] : NULL;
- }
- const float2 *data_float2() const
- {
- assert(data_sizeof() == sizeof(float2));
- return (const float2 *)data();
- }
- const float3 *data_float3() const
- {
- assert(data_sizeof() == sizeof(float3));
- return (const float3 *)data();
- }
- const float4 *data_float4() const
- {
- assert(data_sizeof() == sizeof(float4));
- return (const float4 *)data();
- }
- const float *data_float() const
- {
- assert(data_sizeof() == sizeof(float));
- return (const float *)data();
- }
- const Transform *data_transform() const
- {
- assert(data_sizeof() == sizeof(Transform));
- return (const Transform *)data();
- }
- const ImageHandle &data_voxel() const
- {
- assert(data_sizeof() == sizeof(ImageHandle));
- return *(const ImageHandle *)data();
- }
-
- void zero_data(void *dst);
- void add_with_weight(void *dst, void *src, float weight);
-
- void add(const float &f);
- void add(const float2 &f);
- void add(const float3 &f);
- void add(const uchar4 &f);
- void add(const Transform &tfm);
- void add(const char *data);
-
- void set_data_from(Attribute &&other);
-
- static bool same_storage(TypeDesc a, TypeDesc b);
- static const char *standard_name(AttributeStandard std);
- static AttributeStandard name_standard(const char *name);
-
- static AttrKernelDataType kernel_type(const Attribute &attr);
-
- void get_uv_tiles(Geometry *geom, AttributePrimitive prim, unordered_set<int> &tiles) const;
-};
-
-/* Attribute Set
- *
- * Set of attributes on a mesh. */
-
-class AttributeSet {
- uint32_t modified_flag;
-
- public:
- Geometry *geometry;
- AttributePrimitive prim;
- list<Attribute> attributes;
-
- AttributeSet(Geometry *geometry, AttributePrimitive prim);
- AttributeSet(AttributeSet &&) = default;
- ~AttributeSet();
-
- Attribute *add(ustring name, TypeDesc type, AttributeElement element);
- Attribute *find(ustring name) const;
- void remove(ustring name);
-
- Attribute *add(AttributeStandard std, ustring name = ustring());
- Attribute *find(AttributeStandard std) const;
- void remove(AttributeStandard std);
-
- Attribute *find(AttributeRequest &req);
-
- void remove(Attribute *attribute);
-
- void remove(list<Attribute>::iterator it);
-
- void resize(bool reserve_only = false);
- void clear(bool preserve_voxel_data = false);
-
- /* Update the attributes in this AttributeSet with the ones from the new set,
- * and remove any attribute not found on the new set from this. */
- void update(AttributeSet &&new_attributes);
-
- /* Return whether the attributes of the given kernel_type are modified, where "modified" means
- * that some attributes of the given type were added or removed from this AttributeSet. This does
- * not mean that the data of the remaining attributes in this AttributeSet were also modified. To
- * check this, use Attribute.modified. */
- bool modified(AttrKernelDataType kernel_type) const;
-
- void clear_modified();
-
- private:
- /* Set the relevant modified flag for the attribute. Only attributes that are stored in device
- * arrays will be considered for tagging this AttributeSet as modified. */
- void tag_modified(const Attribute &attr);
-};
-
-/* AttributeRequest
- *
- * Request from a shader to use a certain attribute, so we can figure out
- * which ones we need to export from the host app end store for the kernel.
- * The attribute is found either by name or by standard attribute type. */
-
-class AttributeRequest {
- public:
- ustring name;
- AttributeStandard std;
-
- /* temporary variables used by GeometryManager */
- TypeDesc type, subd_type;
- AttributeDescriptor desc, subd_desc;
-
- explicit AttributeRequest(ustring name_);
- explicit AttributeRequest(AttributeStandard std);
-};
-
-/* AttributeRequestSet
- *
- * Set of attributes requested by a shader. */
-
-class AttributeRequestSet {
- public:
- vector<AttributeRequest> requests;
-
- AttributeRequestSet();
- ~AttributeRequestSet();
-
- void add(ustring name);
- void add(AttributeStandard std);
- void add(AttributeRequestSet &reqs);
- void add_standard(ustring name);
-
- bool find(ustring name);
- bool find(AttributeStandard std);
-
- size_t size();
- void clear();
-
- bool modified(const AttributeRequestSet &other);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __ATTRIBUTE_H__ */
diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp
deleted file mode 100644
index ae6290ac27b..00000000000
--- a/intern/cycles/render/background.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/background.h"
-#include "device/device.h"
-#include "render/graph.h"
-#include "render/integrator.h"
-#include "render/nodes.h"
-#include "render/scene.h"
-#include "render/shader.h"
-#include "render/stats.h"
-
-#include "util/util_foreach.h"
-#include "util/util_math.h"
-#include "util/util_time.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-NODE_DEFINE(Background)
-{
- NodeType *type = NodeType::add("background", create);
-
- SOCKET_BOOLEAN(use_shader, "Use Shader", true);
- SOCKET_UINT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY);
-
- SOCKET_BOOLEAN(transparent, "Transparent", false);
- SOCKET_BOOLEAN(transparent_glass, "Transparent Glass", false);
- SOCKET_FLOAT(transparent_roughness_threshold, "Transparent Roughness Threshold", 0.0f);
-
- SOCKET_FLOAT(volume_step_size, "Volume Step Size", 0.1f);
-
- SOCKET_NODE(shader, "Shader", Shader::get_node_type());
-
- return type;
-}
-
-Background::Background() : Node(get_node_type())
-{
- shader = NULL;
-}
-
-Background::~Background()
-{
- dereference_all_used_nodes();
-}
-
-void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene)
-{
- if (!is_modified())
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->background.times.add_entry({"device_update", time});
- }
- });
-
- device_free(device, dscene);
-
- Shader *bg_shader = get_shader(scene);
-
- /* set shader index and transparent option */
- KernelBackground *kbackground = &dscene->data.background;
-
- kbackground->transparent = transparent;
- kbackground->surface_shader = scene->shader_manager->get_shader_id(bg_shader);
-
- if (transparent && transparent_glass) {
- /* Square twice, once for principled BSDF convention, and once for
- * faster comparison in kernel with anisotropic roughness. */
- kbackground->transparent_roughness_squared_threshold = sqr(
- sqr(transparent_roughness_threshold));
- }
- else {
- kbackground->transparent_roughness_squared_threshold = -1.0f;
- }
-
- if (bg_shader->has_volume)
- kbackground->volume_shader = kbackground->surface_shader;
- else
- kbackground->volume_shader = SHADER_NONE;
-
- kbackground->volume_step_size = volume_step_size * scene->integrator->get_volume_step_rate();
-
- /* No background node, make world shader invisible to all rays, to skip evaluation in kernel. */
- if (bg_shader->graph->nodes.size() <= 1) {
- kbackground->surface_shader |= SHADER_EXCLUDE_ANY;
- }
- /* Background present, check visibilities */
- else {
- if (!(visibility & PATH_RAY_DIFFUSE))
- kbackground->surface_shader |= SHADER_EXCLUDE_DIFFUSE;
- if (!(visibility & PATH_RAY_GLOSSY))
- kbackground->surface_shader |= SHADER_EXCLUDE_GLOSSY;
- if (!(visibility & PATH_RAY_TRANSMIT))
- kbackground->surface_shader |= SHADER_EXCLUDE_TRANSMIT;
- if (!(visibility & PATH_RAY_VOLUME_SCATTER))
- kbackground->surface_shader |= SHADER_EXCLUDE_SCATTER;
- if (!(visibility & PATH_RAY_CAMERA))
- kbackground->surface_shader |= SHADER_EXCLUDE_CAMERA;
- }
-
- clear_modified();
-}
-
-void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
-{
-}
-
-void Background::tag_update(Scene *scene)
-{
- Shader *bg_shader = get_shader(scene);
- if (bg_shader && bg_shader->is_modified()) {
- /* Tag as modified to update the KernelBackground visibility information.
- * We only tag the use_shader socket as modified as it is related to the shader
- * and to avoid doing unnecessary updates anywhere else. */
- tag_use_shader_modified();
- }
-}
-
-Shader *Background::get_shader(const Scene *scene)
-{
- return (use_shader) ? ((shader) ? shader : scene->default_background) : scene->default_empty;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h
deleted file mode 100644
index 2f7ef0f7737..00000000000
--- a/intern/cycles/render/background.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BACKGROUND_H__
-#define __BACKGROUND_H__
-
-#include "graph/node.h"
-
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class Scene;
-class Shader;
-
-class Background : public Node {
- public:
- NODE_DECLARE
-
- NODE_SOCKET_API(bool, use_shader)
-
- NODE_SOCKET_API(uint, visibility)
- NODE_SOCKET_API(Shader *, shader)
-
- NODE_SOCKET_API(bool, transparent)
- NODE_SOCKET_API(bool, transparent_glass)
- NODE_SOCKET_API(float, transparent_roughness_threshold)
-
- NODE_SOCKET_API(float, volume_step_size)
-
- Background();
- ~Background();
-
- void device_update(Device *device, DeviceScene *dscene, Scene *scene);
- void device_free(Device *device, DeviceScene *dscene);
-
- void tag_update(Scene *scene);
-
- Shader *get_shader(const Scene *scene);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BACKGROUND_H__ */
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
deleted file mode 100644
index 54e496caed6..00000000000
--- a/intern/cycles/render/bake.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2011-2014 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/bake.h"
-#include "render/buffers.h"
-#include "render/integrator.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/shader.h"
-#include "render/stats.h"
-
-#include "util/util_foreach.h"
-
-CCL_NAMESPACE_BEGIN
-
-BakeManager::BakeManager()
-{
- need_update_ = true;
-}
-
-BakeManager::~BakeManager()
-{
-}
-
-bool BakeManager::get_baking() const
-{
- return !object_name.empty();
-}
-
-void BakeManager::set(Scene *scene, const std::string &object_name_)
-{
- object_name = object_name_;
-
- /* create device and update scene */
- scene->film->tag_modified();
- scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
-
- need_update_ = true;
-}
-
-void BakeManager::device_update(Device * /*device*/,
- DeviceScene *dscene,
- Scene *scene,
- Progress & /* progress */)
-{
- if (!need_update())
- return;
-
- KernelBake *kbake = &dscene->data.bake;
- memset(kbake, 0, sizeof(*kbake));
-
- if (!object_name.empty()) {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->bake.times.add_entry({"device_update", time});
- }
- });
-
- kbake->use = true;
-
- int object_index = 0;
- foreach (Object *object, scene->objects) {
- const Geometry *geom = object->get_geometry();
- if (object->name == object_name && geom->geometry_type == Geometry::MESH) {
- kbake->object_index = object_index;
- kbake->tri_offset = geom->prim_offset;
- break;
- }
-
- object_index++;
- }
- }
-
- need_update_ = false;
-}
-
-void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
-{
-}
-
-void BakeManager::tag_update()
-{
- need_update_ = true;
-}
-
-bool BakeManager::need_update() const
-{
- return need_update_;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h
deleted file mode 100644
index 39e504490c2..00000000000
--- a/intern/cycles/render/bake.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011-2014 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BAKE_H__
-#define __BAKE_H__
-
-#include "device/device.h"
-#include "render/scene.h"
-
-#include "util/util_progress.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BakeManager {
- public:
- BakeManager();
- ~BakeManager();
-
- void set(Scene *scene, const std::string &object_name);
- bool get_baking() const;
-
- void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
- void device_free(Device *device, DeviceScene *dscene);
-
- void tag_update();
-
- bool need_update() const;
-
- private:
- bool need_update_;
- std::string object_name;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __BAKE_H__ */
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
deleted file mode 100644
index 00b4284c22b..00000000000
--- a/intern/cycles/render/buffers.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-
-#include "device/device.h"
-#include "render/buffers.h"
-
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-#include "util/util_math.h"
-#include "util/util_time.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* --------------------------------------------------------------------
- * Convert part information to an index of `BufferParams::pass_offset_`.
- */
-
-static int pass_type_mode_to_index(PassType pass_type, PassMode mode)
-{
- int index = static_cast<int>(pass_type) * 2;
-
- if (mode == PassMode::DENOISED) {
- ++index;
- }
-
- return index;
-}
-
-static int pass_to_index(const BufferPass &pass)
-{
- return pass_type_mode_to_index(pass.type, pass.mode);
-}
-
-/* --------------------------------------------------------------------
- * Buffer pass.
- */
-
-NODE_DEFINE(BufferPass)
-{
- NodeType *type = NodeType::add("buffer_pass", create);
-
- const NodeEnum *pass_type_enum = Pass::get_type_enum();
- const NodeEnum *pass_mode_enum = Pass::get_mode_enum();
-
- SOCKET_ENUM(type, "Type", *pass_type_enum, PASS_COMBINED);
- SOCKET_ENUM(mode, "Mode", *pass_mode_enum, static_cast<int>(PassMode::DENOISED));
- SOCKET_STRING(name, "Name", ustring());
- SOCKET_BOOLEAN(include_albedo, "Include Albedo", false);
-
- SOCKET_INT(offset, "Offset", -1);
-
- return type;
-}
-
-BufferPass::BufferPass() : Node(get_node_type())
-{
-}
-
-BufferPass::BufferPass(const Pass *scene_pass)
- : Node(get_node_type()),
- type(scene_pass->get_type()),
- mode(scene_pass->get_mode()),
- name(scene_pass->get_name()),
- include_albedo(scene_pass->get_include_albedo())
-{
-}
-
-PassInfo BufferPass::get_info() const
-{
- return Pass::get_info(type, include_albedo);
-}
-
-/* --------------------------------------------------------------------
- * Buffer Params.
- */
-
-NODE_DEFINE(BufferParams)
-{
- NodeType *type = NodeType::add("buffer_params", create);
-
- SOCKET_INT(width, "Width", 0);
- SOCKET_INT(height, "Height", 0);
-
- SOCKET_INT(window_x, "Window X", 0);
- SOCKET_INT(window_y, "Window Y", 0);
- SOCKET_INT(window_width, "Window Width", 0);
- SOCKET_INT(window_height, "Window Height", 0);
-
- SOCKET_INT(full_x, "Full X", 0);
- SOCKET_INT(full_y, "Full Y", 0);
- SOCKET_INT(full_width, "Full Width", 0);
- SOCKET_INT(full_height, "Full Height", 0);
-
- SOCKET_STRING(layer, "Layer", ustring());
- SOCKET_STRING(view, "View", ustring());
- SOCKET_INT(samples, "Samples", 0);
- SOCKET_FLOAT(exposure, "Exposure", 1.0f);
- SOCKET_BOOLEAN(use_approximate_shadow_catcher, "Use Approximate Shadow Catcher", false);
- SOCKET_BOOLEAN(use_transparent_background, "Transparent Background", false);
-
- /* Notes:
- * - Skip passes since they do not follow typical container socket definition.
- * Might look into covering those as a socket in the future.
- *
- * - Skip offset, stride, and pass stride since those can be delivered from the passes and
- * rest of the sockets. */
-
- return type;
-}
-
-BufferParams::BufferParams() : Node(get_node_type())
-{
- reset_pass_offset();
-}
-
-void BufferParams::update_passes()
-{
- update_offset_stride();
- reset_pass_offset();
-
- pass_stride = 0;
- for (const BufferPass &pass : passes) {
- if (pass.offset != PASS_UNUSED) {
- const int index = pass_to_index(pass);
- if (pass_offset_[index] == PASS_UNUSED) {
- pass_offset_[index] = pass_stride;
- }
-
- pass_stride += pass.get_info().num_components;
- }
- }
-}
-
-void BufferParams::update_passes(const vector<Pass *> &scene_passes)
-{
- passes.clear();
-
- pass_stride = 0;
- for (const Pass *scene_pass : scene_passes) {
- BufferPass buffer_pass(scene_pass);
-
- if (scene_pass->is_written()) {
- buffer_pass.offset = pass_stride;
- pass_stride += scene_pass->get_info().num_components;
- }
- else {
- buffer_pass.offset = PASS_UNUSED;
- }
-
- passes.emplace_back(std::move(buffer_pass));
- }
-
- update_passes();
-}
-
-void BufferParams::reset_pass_offset()
-{
- for (int i = 0; i < kNumPassOffsets; ++i) {
- pass_offset_[i] = PASS_UNUSED;
- }
-}
-
-int BufferParams::get_pass_offset(PassType pass_type, PassMode mode) const
-{
- if (pass_type == PASS_NONE || pass_type == PASS_UNUSED) {
- return PASS_UNUSED;
- }
-
- const int index = pass_type_mode_to_index(pass_type, mode);
- return pass_offset_[index];
-}
-
-const BufferPass *BufferParams::find_pass(string_view name) const
-{
- for (const BufferPass &pass : passes) {
- if (pass.name == name) {
- return &pass;
- }
- }
-
- return nullptr;
-}
-
-const BufferPass *BufferParams::find_pass(PassType type, PassMode mode) const
-{
- for (const BufferPass &pass : passes) {
- if (pass.type == type && pass.mode == mode) {
- return &pass;
- }
- }
-
- return nullptr;
-}
-
-const BufferPass *BufferParams::get_actual_display_pass(PassType type, PassMode mode) const
-{
- const BufferPass *pass = find_pass(type, mode);
- return get_actual_display_pass(pass);
-}
-
-const BufferPass *BufferParams::get_actual_display_pass(const BufferPass *pass) const
-{
- if (!pass) {
- return nullptr;
- }
-
- if (pass->type == PASS_COMBINED) {
- const BufferPass *shadow_catcher_matte_pass = find_pass(PASS_SHADOW_CATCHER_MATTE, pass->mode);
- if (shadow_catcher_matte_pass) {
- pass = shadow_catcher_matte_pass;
- }
- }
-
- return pass;
-}
-
-void BufferParams::update_offset_stride()
-{
- offset = -(full_x + full_y * width);
- stride = width;
-}
-
-bool BufferParams::modified(const BufferParams &other) const
-{
- if (width != other.width || height != other.height) {
- return true;
- }
-
- if (full_x != other.full_x || full_y != other.full_y || full_width != other.full_width ||
- full_height != other.full_height) {
- return true;
- }
-
- if (window_x != other.window_x || window_y != other.window_y ||
- window_width != other.window_width || window_height != other.window_height) {
- return true;
- }
-
- if (offset != other.offset || stride != other.stride || pass_stride != other.pass_stride) {
- return true;
- }
-
- if (layer != other.layer || view != other.view) {
- return false;
- }
-
- if (exposure != other.exposure ||
- use_approximate_shadow_catcher != other.use_approximate_shadow_catcher ||
- use_transparent_background != other.use_transparent_background) {
- return true;
- }
-
- return !(passes == other.passes);
-}
-
-/* --------------------------------------------------------------------
- * Render Buffers.
- */
-
-RenderBuffers::RenderBuffers(Device *device) : buffer(device, "RenderBuffers", MEM_READ_WRITE)
-{
-}
-
-RenderBuffers::~RenderBuffers()
-{
- buffer.free();
-}
-
-void RenderBuffers::reset(const BufferParams &params_)
-{
- DCHECK(params_.pass_stride != -1);
-
- params = params_;
-
- /* re-allocate buffer */
- buffer.alloc(params.width * params.pass_stride, params.height);
-}
-
-void RenderBuffers::zero()
-{
- buffer.zero_to_device();
-}
-
-bool RenderBuffers::copy_from_device()
-{
- DCHECK(params.pass_stride != -1);
-
- if (!buffer.device_pointer)
- return false;
-
- buffer.copy_from_device(0, params.width * params.pass_stride, params.height);
-
- return true;
-}
-
-void RenderBuffers::copy_to_device()
-{
- buffer.copy_to_device();
-}
-
-void render_buffers_host_copy_denoised(RenderBuffers *dst,
- const BufferParams &dst_params,
- const RenderBuffers *src,
- const BufferParams &src_params,
- const size_t src_offset)
-{
- DCHECK_EQ(dst_params.width, src_params.width);
- /* TODO(sergey): More sanity checks to avoid buffer overrun. */
-
- /* Create a map of pass offsets to be copied.
- * Assume offsets are different to allow copying passes between buffers with different set of
- * passes. */
-
- struct {
- int dst_offset;
- int src_offset;
- } pass_offsets[PASS_NUM];
-
- int num_passes = 0;
-
- for (int i = 0; i < PASS_NUM; ++i) {
- const PassType pass_type = static_cast<PassType>(i);
-
- const int dst_pass_offset = dst_params.get_pass_offset(pass_type, PassMode::DENOISED);
- if (dst_pass_offset == PASS_UNUSED) {
- continue;
- }
-
- const int src_pass_offset = src_params.get_pass_offset(pass_type, PassMode::DENOISED);
- if (src_pass_offset == PASS_UNUSED) {
- continue;
- }
-
- pass_offsets[num_passes].dst_offset = dst_pass_offset;
- pass_offsets[num_passes].src_offset = src_pass_offset;
- ++num_passes;
- }
-
- /* Copy passes. */
- /* TODO(sergey): Make it more reusable, allowing implement copy of noisy passes. */
-
- const int64_t dst_width = dst_params.width;
- const int64_t dst_height = dst_params.height;
- const int64_t dst_pass_stride = dst_params.pass_stride;
- const int64_t dst_num_pixels = dst_width * dst_height;
-
- const int64_t src_pass_stride = src_params.pass_stride;
- const int64_t src_offset_in_floats = src_offset * src_pass_stride;
-
- const float *src_pixel = src->buffer.data() + src_offset_in_floats;
- float *dst_pixel = dst->buffer.data();
-
- for (int i = 0; i < dst_num_pixels;
- ++i, src_pixel += src_pass_stride, dst_pixel += dst_pass_stride) {
- for (int pass_offset_idx = 0; pass_offset_idx < num_passes; ++pass_offset_idx) {
- const int dst_pass_offset = pass_offsets[pass_offset_idx].dst_offset;
- const int src_pass_offset = pass_offsets[pass_offset_idx].src_offset;
-
- /* TODO(sergey): Support non-RGBA passes. */
- dst_pixel[dst_pass_offset + 0] = src_pixel[src_pass_offset + 0];
- dst_pixel[dst_pass_offset + 1] = src_pixel[src_pass_offset + 1];
- dst_pixel[dst_pass_offset + 2] = src_pixel[src_pass_offset + 2];
- dst_pixel[dst_pass_offset + 3] = src_pixel[src_pass_offset + 3];
- }
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h
deleted file mode 100644
index 3cf826f14d6..00000000000
--- a/intern/cycles/render/buffers.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __BUFFERS_H__
-#define __BUFFERS_H__
-
-#include "device/device_memory.h"
-#include "graph/node.h"
-#include "render/pass.h"
-
-#include "kernel/kernel_types.h"
-
-#include "util/util_half.h"
-#include "util/util_string.h"
-#include "util/util_thread.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-struct DeviceDrawParams;
-struct float4;
-
-/* NOTE: Is not a real scene node. Using Node API for ease of (de)serialization. */
-class BufferPass : public Node {
- public:
- NODE_DECLARE
-
- PassType type = PASS_NONE;
- PassMode mode = PassMode::NOISY;
- ustring name;
- bool include_albedo = false;
-
- int offset = -1;
-
- BufferPass();
- explicit BufferPass(const Pass *scene_pass);
-
- BufferPass(BufferPass &&other) noexcept = default;
- BufferPass(const BufferPass &other) = default;
-
- BufferPass &operator=(BufferPass &&other) = default;
- BufferPass &operator=(const BufferPass &other) = default;
-
- ~BufferPass() = default;
-
- PassInfo get_info() const;
-
- inline bool operator==(const BufferPass &other) const
- {
- return type == other.type && mode == other.mode && name == other.name &&
- include_albedo == other.include_albedo && offset == other.offset;
- }
- inline bool operator!=(const BufferPass &other) const
- {
- return !(*this == other);
- }
-};
-
-/* Buffer Parameters
- * Size of render buffer and how it fits in the full image (border render). */
-
-/* NOTE: Is not a real scene node. Using Node API for ease of (de)serialization. */
-class BufferParams : public Node {
- public:
- NODE_DECLARE
-
- /* Width/height of the physical buffer. */
- int width = 0;
- int height = 0;
-
- /* Windows defines which part of the buffers is visible. The part outside of the window is
- * considered an "overscan".
- *
- * Window X and Y are relative to the position of the buffer in the full buffer. */
- int window_x = 0;
- int window_y = 0;
- int window_width = 0;
- int window_height = 0;
-
- /* Offset into and width/height of the full buffer. */
- int full_x = 0;
- int full_y = 0;
- int full_width = 0;
- int full_height = 0;
-
- /* Runtime fields, only valid after `update_passes()` or `update_offset_stride()`. */
- int offset = -1, stride = -1;
-
- /* Runtime fields, only valid after `update_passes()`. */
- int pass_stride = -1;
-
- /* Properties which are used for accessing buffer pixels outside of scene graph. */
- vector<BufferPass> passes;
- ustring layer;
- ustring view;
- int samples = 0;
- float exposure = 1.0f;
- bool use_approximate_shadow_catcher = false;
- bool use_transparent_background = false;
-
- BufferParams();
-
- BufferParams(BufferParams &&other) noexcept = default;
- BufferParams(const BufferParams &other) = default;
-
- BufferParams &operator=(BufferParams &&other) = default;
- BufferParams &operator=(const BufferParams &other) = default;
-
- ~BufferParams() = default;
-
- /* Pre-calculate all fields which depends on the passes.
- *
- * When the scene passes are given, the buffer passes will be created from them and stored in
- * this params, and then params are updated for those passes.
- * The `update_passes()` without parameters updates offsets and strides which are stored outside
- * of the passes. */
- void update_passes();
- void update_passes(const vector<Pass *> &scene_passes);
-
- /* Returns PASS_UNUSED if there is no such pass in the buffer. */
- int get_pass_offset(PassType type, PassMode mode = PassMode::NOISY) const;
-
- /* Returns nullptr if pass with given name does not exist. */
- const BufferPass *find_pass(string_view name) const;
- const BufferPass *find_pass(PassType type, PassMode mode = PassMode::NOISY) const;
-
- /* Get display pass from its name.
- * Will do special logic to replace combined pass with shadow catcher matte. */
- const BufferPass *get_actual_display_pass(PassType type, PassMode mode = PassMode::NOISY) const;
- const BufferPass *get_actual_display_pass(const BufferPass *pass) const;
-
- void update_offset_stride();
-
- bool modified(const BufferParams &other) const;
-
- protected:
- void reset_pass_offset();
-
- /* Multiplied by 2 to be able to store noisy and denoised pass types. */
- static constexpr int kNumPassOffsets = PASS_NUM * 2;
-
- /* Indexed by an index derived from pass type and mode, indicates offset of the corresponding
- * pass in the buffer.
- * If there are multiple passes with same type and mode contains lowest offset of all of them. */
- int pass_offset_[kNumPassOffsets];
-};
-
-/* Render Buffers */
-
-class RenderBuffers {
- public:
- /* buffer parameters */
- BufferParams params;
-
- /* float buffer */
- device_vector<float> buffer;
-
- explicit RenderBuffers(Device *device);
- ~RenderBuffers();
-
- void reset(const BufferParams &params);
- void zero();
-
- bool copy_from_device();
- void copy_to_device();
-};
-
-/* Copy denoised passes form source to destination.
- *
- * Buffer parameters are provided explicitly, allowing to copy pixels between render buffers which
- * content corresponds to a render result at a non-unit resolution divider.
- *
- * `src_offset` allows to offset source pixel index which is used when a fraction of the source
- * buffer is to be copied.
- *
- * Copy happens of the number of pixels in the destination. */
-void render_buffers_host_copy_denoised(RenderBuffers *dst,
- const BufferParams &dst_params,
- const RenderBuffers *src,
- const BufferParams &src_params,
- const size_t src_offset = 0);
-
-CCL_NAMESPACE_END
-
-#endif /* __BUFFERS_H__ */
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
deleted file mode 100644
index 8b69c971991..00000000000
--- a/intern/cycles/render/camera.cpp
+++ /dev/null
@@ -1,819 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/camera.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/scene.h"
-#include "render/stats.h"
-#include "render/tables.h"
-
-#include "device/device.h"
-
-#include "util/util_foreach.h"
-#include "util/util_function.h"
-#include "util/util_logging.h"
-#include "util/util_math_cdf.h"
-#include "util/util_task.h"
-#include "util/util_time.h"
-#include "util/util_vector.h"
-
-/* needed for calculating differentials */
-// clang-format off
-#include "kernel/device/cpu/compat.h"
-#include "kernel/device/cpu/globals.h"
-
-#include "kernel/kernel_projection.h"
-#include "kernel/kernel_differential.h"
-#include "kernel/kernel_montecarlo.h"
-#include "kernel/kernel_camera.h"
-// clang-format on
-
-CCL_NAMESPACE_BEGIN
-
-static float shutter_curve_eval(float x, array<float> &shutter_curve)
-{
- if (shutter_curve.size() == 0) {
- return 1.0f;
- }
-
- x *= shutter_curve.size();
- int index = (int)x;
- float frac = x - index;
- if (index < shutter_curve.size() - 1) {
- return lerp(shutter_curve[index], shutter_curve[index + 1], frac);
- }
- else {
- return shutter_curve[shutter_curve.size() - 1];
- }
-}
-
-NODE_DEFINE(Camera)
-{
- NodeType *type = NodeType::add("camera", create);
-
- SOCKET_FLOAT(shuttertime, "Shutter Time", 1.0f);
-
- static NodeEnum motion_position_enum;
- motion_position_enum.insert("start", MOTION_POSITION_START);
- motion_position_enum.insert("center", MOTION_POSITION_CENTER);
- motion_position_enum.insert("end", MOTION_POSITION_END);
- SOCKET_ENUM(motion_position, "Motion Position", motion_position_enum, MOTION_POSITION_CENTER);
-
- static NodeEnum rolling_shutter_type_enum;
- rolling_shutter_type_enum.insert("none", ROLLING_SHUTTER_NONE);
- rolling_shutter_type_enum.insert("top", ROLLING_SHUTTER_TOP);
- SOCKET_ENUM(rolling_shutter_type,
- "Rolling Shutter Type",
- rolling_shutter_type_enum,
- ROLLING_SHUTTER_NONE);
- SOCKET_FLOAT(rolling_shutter_duration, "Rolling Shutter Duration", 0.1f);
-
- SOCKET_FLOAT_ARRAY(shutter_curve, "Shutter Curve", array<float>());
-
- SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f);
- SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f);
- SOCKET_UINT(blades, "Blades", 0);
- SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f);
-
- SOCKET_TRANSFORM(matrix, "Matrix", transform_identity());
- SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
-
- SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f);
-
- static NodeEnum type_enum;
- type_enum.insert("perspective", CAMERA_PERSPECTIVE);
- type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC);
- type_enum.insert("panorama", CAMERA_PANORAMA);
- SOCKET_ENUM(camera_type, "Type", type_enum, CAMERA_PERSPECTIVE);
-
- static NodeEnum panorama_type_enum;
- panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR);
- panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL);
- panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT);
- panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID);
- SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR);
-
- SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F);
- SOCKET_FLOAT(fisheye_lens, "Fisheye Lens", 10.5f);
- SOCKET_FLOAT(latitude_min, "Latitude Min", -M_PI_2_F);
- SOCKET_FLOAT(latitude_max, "Latitude Max", M_PI_2_F);
- SOCKET_FLOAT(longitude_min, "Longitude Min", -M_PI_F);
- SOCKET_FLOAT(longitude_max, "Longitude Max", M_PI_F);
- SOCKET_FLOAT(fov, "FOV", M_PI_4_F);
- SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F);
- SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F);
-
- static NodeEnum stereo_eye_enum;
- stereo_eye_enum.insert("none", STEREO_NONE);
- stereo_eye_enum.insert("left", STEREO_LEFT);
- stereo_eye_enum.insert("right", STEREO_RIGHT);
- SOCKET_ENUM(stereo_eye, "Stereo Eye", stereo_eye_enum, STEREO_NONE);
-
- SOCKET_BOOLEAN(use_spherical_stereo, "Use Spherical Stereo", false);
-
- SOCKET_FLOAT(interocular_distance, "Interocular Distance", 0.065f);
- SOCKET_FLOAT(convergence_distance, "Convergence Distance", 30.0f * 0.065f);
-
- SOCKET_BOOLEAN(use_pole_merge, "Use Pole Merge", false);
- SOCKET_FLOAT(pole_merge_angle_from, "Pole Merge Angle From", 60.0f * M_PI_F / 180.0f);
- SOCKET_FLOAT(pole_merge_angle_to, "Pole Merge Angle To", 75.0f * M_PI_F / 180.0f);
-
- SOCKET_FLOAT(sensorwidth, "Sensor Width", 0.036f);
- SOCKET_FLOAT(sensorheight, "Sensor Height", 0.024f);
-
- SOCKET_FLOAT(nearclip, "Near Clip", 1e-5f);
- SOCKET_FLOAT(farclip, "Far Clip", 1e5f);
-
- SOCKET_FLOAT(viewplane.left, "Viewplane Left", 0);
- SOCKET_FLOAT(viewplane.right, "Viewplane Right", 0);
- SOCKET_FLOAT(viewplane.bottom, "Viewplane Bottom", 0);
- SOCKET_FLOAT(viewplane.top, "Viewplane Top", 0);
-
- SOCKET_FLOAT(border.left, "Border Left", 0);
- SOCKET_FLOAT(border.right, "Border Right", 0);
- SOCKET_FLOAT(border.bottom, "Border Bottom", 0);
- SOCKET_FLOAT(border.top, "Border Top", 0);
-
- SOCKET_FLOAT(viewport_camera_border.left, "Viewport Border Left", 0);
- SOCKET_FLOAT(viewport_camera_border.right, "Viewport Border Right", 0);
- SOCKET_FLOAT(viewport_camera_border.bottom, "Viewport Border Bottom", 0);
- SOCKET_FLOAT(viewport_camera_border.top, "Viewport Border Top", 0);
-
- SOCKET_FLOAT(offscreen_dicing_scale, "Offscreen Dicing Scale", 1.0f);
-
- SOCKET_INT(full_width, "Full Width", 1024);
- SOCKET_INT(full_height, "Full Height", 512);
-
- SOCKET_BOOLEAN(use_perspective_motion, "Use Perspective Motion", false);
-
- return type;
-}
-
-Camera::Camera() : Node(get_node_type())
-{
- shutter_table_offset = TABLE_OFFSET_INVALID;
-
- width = 1024;
- height = 512;
-
- use_perspective_motion = false;
-
- shutter_curve.resize(RAMP_TABLE_SIZE);
- for (int i = 0; i < shutter_curve.size(); ++i) {
- shutter_curve[i] = 1.0f;
- }
-
- compute_auto_viewplane();
-
- screentoworld = projection_identity();
- rastertoworld = projection_identity();
- ndctoworld = projection_identity();
- rastertocamera = projection_identity();
- cameratoworld = transform_identity();
- worldtoraster = projection_identity();
-
- full_rastertocamera = projection_identity();
-
- dx = zero_float3();
- dy = zero_float3();
-
- need_device_update = true;
- need_flags_update = true;
- previous_need_motion = -1;
-
- memset((void *)&kernel_camera, 0, sizeof(kernel_camera));
-}
-
-Camera::~Camera()
-{
-}
-
-void Camera::compute_auto_viewplane()
-{
- if (camera_type == CAMERA_PANORAMA) {
- viewplane.left = 0.0f;
- viewplane.right = 1.0f;
- viewplane.bottom = 0.0f;
- viewplane.top = 1.0f;
- }
- else {
- float aspect = (float)full_width / (float)full_height;
- if (full_width >= full_height) {
- viewplane.left = -aspect;
- viewplane.right = aspect;
- viewplane.bottom = -1.0f;
- viewplane.top = 1.0f;
- }
- else {
- viewplane.left = -1.0f;
- viewplane.right = 1.0f;
- viewplane.bottom = -1.0f / aspect;
- viewplane.top = 1.0f / aspect;
- }
- }
-}
-
-void Camera::update(Scene *scene)
-{
- Scene::MotionType need_motion = scene->need_motion();
-
- if (previous_need_motion != need_motion) {
- /* scene's motion model could have been changed since previous device
- * camera update this could happen for example in case when one render
- * layer has got motion pass and another not */
- need_device_update = true;
- }
-
- if (!is_modified())
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->camera.times.add_entry({"update", time});
- }
- });
-
- /* Full viewport to camera border in the viewport. */
- Transform fulltoborder = transform_from_viewplane(viewport_camera_border);
- Transform bordertofull = transform_inverse(fulltoborder);
-
- /* NDC to raster. */
- Transform ndctoraster = transform_scale(width, height, 1.0f) * bordertofull;
- Transform full_ndctoraster = transform_scale(full_width, full_height, 1.0f) * bordertofull;
-
- /* Raster to screen. */
- Transform screentondc = fulltoborder * transform_from_viewplane(viewplane);
-
- Transform screentoraster = ndctoraster * screentondc;
- Transform rastertoscreen = transform_inverse(screentoraster);
- Transform full_screentoraster = full_ndctoraster * screentondc;
- Transform full_rastertoscreen = transform_inverse(full_screentoraster);
-
- /* Screen to camera. */
- ProjectionTransform cameratoscreen;
- if (camera_type == CAMERA_PERSPECTIVE)
- cameratoscreen = projection_perspective(fov, nearclip, farclip);
- else if (camera_type == CAMERA_ORTHOGRAPHIC)
- cameratoscreen = projection_orthographic(nearclip, farclip);
- else
- cameratoscreen = projection_identity();
-
- ProjectionTransform screentocamera = projection_inverse(cameratoscreen);
-
- rastertocamera = screentocamera * rastertoscreen;
- full_rastertocamera = screentocamera * full_rastertoscreen;
- cameratoraster = screentoraster * cameratoscreen;
-
- cameratoworld = matrix;
- screentoworld = cameratoworld * screentocamera;
- rastertoworld = cameratoworld * rastertocamera;
- ndctoworld = rastertoworld * ndctoraster;
-
- /* note we recompose matrices instead of taking inverses of the above, this
- * is needed to avoid inverting near degenerate matrices that happen due to
- * precision issues with large scenes */
- worldtocamera = transform_inverse(matrix);
- worldtoscreen = cameratoscreen * worldtocamera;
- worldtondc = screentondc * worldtoscreen;
- worldtoraster = ndctoraster * worldtondc;
-
- /* differentials */
- if (camera_type == CAMERA_ORTHOGRAPHIC) {
- dx = transform_perspective_direction(&rastertocamera, make_float3(1, 0, 0));
- dy = transform_perspective_direction(&rastertocamera, make_float3(0, 1, 0));
- full_dx = transform_perspective_direction(&full_rastertocamera, make_float3(1, 0, 0));
- full_dy = transform_perspective_direction(&full_rastertocamera, make_float3(0, 1, 0));
- }
- else if (camera_type == CAMERA_PERSPECTIVE) {
- dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
- transform_perspective(&rastertocamera, make_float3(0, 0, 0));
- dy = transform_perspective(&rastertocamera, make_float3(0, 1, 0)) -
- transform_perspective(&rastertocamera, make_float3(0, 0, 0));
- full_dx = transform_perspective(&full_rastertocamera, make_float3(1, 0, 0)) -
- transform_perspective(&full_rastertocamera, make_float3(0, 0, 0));
- full_dy = transform_perspective(&full_rastertocamera, make_float3(0, 1, 0)) -
- transform_perspective(&full_rastertocamera, make_float3(0, 0, 0));
- }
- else {
- dx = zero_float3();
- dy = zero_float3();
- }
-
- dx = transform_direction(&cameratoworld, dx);
- dy = transform_direction(&cameratoworld, dy);
- full_dx = transform_direction(&cameratoworld, full_dx);
- full_dy = transform_direction(&cameratoworld, full_dy);
-
- if (camera_type == CAMERA_PERSPECTIVE) {
- float3 v = transform_perspective(&full_rastertocamera,
- make_float3(full_width, full_height, 1.0f));
- frustum_right_normal = normalize(make_float3(v.z, 0.0f, -v.x));
- frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y));
-
- v = transform_perspective(&full_rastertocamera, make_float3(0.0f, 0.0f, 1.0f));
- frustum_left_normal = normalize(make_float3(-v.z, 0.0f, v.x));
- frustum_bottom_normal = normalize(make_float3(0.0f, -v.z, v.y));
- }
-
- /* Compute kernel camera data. */
- KernelCamera *kcam = &kernel_camera;
-
- /* store matrices */
- kcam->screentoworld = screentoworld;
- kcam->rastertoworld = rastertoworld;
- kcam->rastertocamera = rastertocamera;
- kcam->cameratoworld = cameratoworld;
- kcam->worldtocamera = worldtocamera;
- kcam->worldtoscreen = worldtoscreen;
- kcam->worldtoraster = worldtoraster;
- kcam->worldtondc = worldtondc;
- kcam->ndctoworld = ndctoworld;
-
- /* camera motion */
- kcam->num_motion_steps = 0;
- kcam->have_perspective_motion = 0;
- kernel_camera_motion.clear();
-
- /* Test if any of the transforms are actually different. */
- bool have_motion = false;
- for (size_t i = 0; i < motion.size(); i++) {
- have_motion = have_motion || motion[i] != matrix;
- }
-
- if (need_motion == Scene::MOTION_PASS) {
- /* TODO(sergey): Support perspective (zoom, fov) motion. */
- if (camera_type == CAMERA_PANORAMA) {
- if (have_motion) {
- kcam->motion_pass_pre = transform_inverse(motion[0]);
- kcam->motion_pass_post = transform_inverse(motion[motion.size() - 1]);
- }
- else {
- kcam->motion_pass_pre = kcam->worldtocamera;
- kcam->motion_pass_post = kcam->worldtocamera;
- }
- }
- else {
- if (have_motion) {
- kcam->perspective_pre = cameratoraster * transform_inverse(motion[0]);
- kcam->perspective_post = cameratoraster * transform_inverse(motion[motion.size() - 1]);
- }
- else {
- kcam->perspective_pre = worldtoraster;
- kcam->perspective_post = worldtoraster;
- }
- }
- }
- else if (need_motion == Scene::MOTION_BLUR) {
- if (have_motion) {
- kernel_camera_motion.resize(motion.size());
- transform_motion_decompose(kernel_camera_motion.data(), motion.data(), motion.size());
- kcam->num_motion_steps = motion.size();
- }
-
- /* TODO(sergey): Support other types of camera. */
- if (use_perspective_motion && camera_type == CAMERA_PERSPECTIVE) {
- /* TODO(sergey): Move to an utility function and de-duplicate with
- * calculation above.
- */
- ProjectionTransform screentocamera_pre = projection_inverse(
- projection_perspective(fov_pre, nearclip, farclip));
- ProjectionTransform screentocamera_post = projection_inverse(
- projection_perspective(fov_post, nearclip, farclip));
-
- kcam->perspective_pre = screentocamera_pre * rastertoscreen;
- kcam->perspective_post = screentocamera_post * rastertoscreen;
- kcam->have_perspective_motion = 1;
- }
- }
-
- /* depth of field */
- kcam->aperturesize = aperturesize;
- kcam->focaldistance = focaldistance;
- kcam->blades = (blades < 3) ? 0.0f : blades;
- kcam->bladesrotation = bladesrotation;
-
- /* motion blur */
- kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime : -1.0f;
-
- /* type */
- kcam->type = camera_type;
-
- /* anamorphic lens bokeh */
- kcam->inv_aperture_ratio = 1.0f / aperture_ratio;
-
- /* panorama */
- kcam->panorama_type = panorama_type;
- kcam->fisheye_fov = fisheye_fov;
- kcam->fisheye_lens = fisheye_lens;
- kcam->equirectangular_range = make_float4(longitude_min - longitude_max,
- -longitude_min,
- latitude_min - latitude_max,
- -latitude_min + M_PI_2_F);
-
- switch (stereo_eye) {
- case STEREO_LEFT:
- kcam->interocular_offset = -interocular_distance * 0.5f;
- break;
- case STEREO_RIGHT:
- kcam->interocular_offset = interocular_distance * 0.5f;
- break;
- case STEREO_NONE:
- default:
- kcam->interocular_offset = 0.0f;
- break;
- }
-
- kcam->convergence_distance = convergence_distance;
- if (use_pole_merge) {
- kcam->pole_merge_angle_from = pole_merge_angle_from;
- kcam->pole_merge_angle_to = pole_merge_angle_to;
- }
- else {
- kcam->pole_merge_angle_from = -1.0f;
- kcam->pole_merge_angle_to = -1.0f;
- }
-
- /* sensor size */
- kcam->sensorwidth = sensorwidth;
- kcam->sensorheight = sensorheight;
-
- /* render size */
- kcam->width = width;
- kcam->height = height;
-
- /* store differentials */
- kcam->dx = float3_to_float4(dx);
- kcam->dy = float3_to_float4(dy);
-
- /* clipping */
- kcam->nearclip = nearclip;
- kcam->cliplength = (farclip == FLT_MAX) ? FLT_MAX : farclip - nearclip;
-
- /* Camera in volume. */
- kcam->is_inside_volume = 0;
-
- /* Rolling shutter effect */
- kcam->rolling_shutter_type = rolling_shutter_type;
- kcam->rolling_shutter_duration = rolling_shutter_duration;
-
- /* Set further update flags */
- clear_modified();
- need_device_update = true;
- need_flags_update = true;
- previous_need_motion = need_motion;
-}
-
-void Camera::device_update(Device * /* device */, DeviceScene *dscene, Scene *scene)
-{
- update(scene);
-
- if (!need_device_update)
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->camera.times.add_entry({"device_update", time});
- }
- });
-
- scene->lookup_tables->remove_table(&shutter_table_offset);
- if (kernel_camera.shuttertime != -1.0f) {
- vector<float> shutter_table;
- util_cdf_inverted(SHUTTER_TABLE_SIZE,
- 0.0f,
- 1.0f,
- function_bind(shutter_curve_eval, _1, shutter_curve),
- false,
- shutter_table);
- shutter_table_offset = scene->lookup_tables->add_table(dscene, shutter_table);
- kernel_camera.shutter_table_offset = (int)shutter_table_offset;
- }
-
- dscene->data.cam = kernel_camera;
-
- size_t num_motion_steps = kernel_camera_motion.size();
- if (num_motion_steps) {
- DecomposedTransform *camera_motion = dscene->camera_motion.alloc(num_motion_steps);
- memcpy(camera_motion, kernel_camera_motion.data(), sizeof(*camera_motion) * num_motion_steps);
- dscene->camera_motion.copy_to_device();
- }
- else {
- dscene->camera_motion.free();
- }
-}
-
-void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scene *scene)
-{
- if (!need_device_update && !need_flags_update) {
- return;
- }
-
- KernelIntegrator *kintegrator = &dscene->data.integrator;
- if (kintegrator->use_volumes) {
- KernelCamera *kcam = &dscene->data.cam;
- BoundBox viewplane_boundbox = viewplane_bounds_get();
-
- /* Parallel object update, with grain size to avoid too much threading overhead
- * for individual objects. */
- static const int OBJECTS_PER_TASK = 32;
- parallel_for(blocked_range<size_t>(0, scene->objects.size(), OBJECTS_PER_TASK),
- [&](const blocked_range<size_t> &r) {
- for (size_t i = r.begin(); i != r.end(); i++) {
- Object *object = scene->objects[i];
- if (object->get_geometry()->has_volume &&
- viewplane_boundbox.intersects(object->bounds)) {
- /* TODO(sergey): Consider adding more grained check. */
- VLOG(1) << "Detected camera inside volume.";
- kcam->is_inside_volume = 1;
- parallel_for_cancel();
- break;
- }
- }
- });
-
- if (!kcam->is_inside_volume) {
- VLOG(1) << "Camera is outside of the volume.";
- }
- }
-
- need_device_update = false;
- need_flags_update = false;
-}
-
-void Camera::device_free(Device * /*device*/, DeviceScene *dscene, Scene *scene)
-{
- scene->lookup_tables->remove_table(&shutter_table_offset);
- dscene->camera_motion.free();
-}
-
-float3 Camera::transform_raster_to_world(float raster_x, float raster_y)
-{
- float3 D, P;
- if (camera_type == CAMERA_PERSPECTIVE) {
- D = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
- float3 Pclip = normalize(D);
- P = zero_float3();
- /* TODO(sergey): Aperture support? */
- P = transform_point(&cameratoworld, P);
- D = normalize(transform_direction(&cameratoworld, D));
- /* TODO(sergey): Clipping is conditional in kernel, and hence it could
- * be mistakes in here, currently leading to wrong camera-in-volume
- * detection.
- */
- P += nearclip * D / Pclip.z;
- }
- else if (camera_type == CAMERA_ORTHOGRAPHIC) {
- D = make_float3(0.0f, 0.0f, 1.0f);
- /* TODO(sergey): Aperture support? */
- P = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
- P = transform_point(&cameratoworld, P);
- D = normalize(transform_direction(&cameratoworld, D));
- }
- else {
- assert(!"unsupported camera type");
- }
- return P;
-}
-
-BoundBox Camera::viewplane_bounds_get()
-{
- /* TODO(sergey): This is all rather stupid, but is there a way to perform
- * checks we need in a more clear and smart fashion? */
- BoundBox bounds = BoundBox::empty;
-
- if (camera_type == CAMERA_PANORAMA) {
- if (use_spherical_stereo == false) {
- bounds.grow(make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w));
- }
- else {
- float half_eye_distance = interocular_distance * 0.5f;
-
- bounds.grow(make_float3(
- cameratoworld.x.w + half_eye_distance, cameratoworld.y.w, cameratoworld.z.w));
-
- bounds.grow(make_float3(
- cameratoworld.z.w, cameratoworld.y.w + half_eye_distance, cameratoworld.z.w));
-
- bounds.grow(make_float3(
- cameratoworld.x.w - half_eye_distance, cameratoworld.y.w, cameratoworld.z.w));
-
- bounds.grow(make_float3(
- cameratoworld.x.w, cameratoworld.y.w - half_eye_distance, cameratoworld.z.w));
- }
- }
- else {
- bounds.grow(transform_raster_to_world(0.0f, 0.0f));
- bounds.grow(transform_raster_to_world(0.0f, (float)height));
- bounds.grow(transform_raster_to_world((float)width, (float)height));
- bounds.grow(transform_raster_to_world((float)width, 0.0f));
- if (camera_type == CAMERA_PERSPECTIVE) {
- /* Center point has the most distance in local Z axis,
- * use it to construct bounding box/
- */
- bounds.grow(transform_raster_to_world(0.5f * width, 0.5f * height));
- }
- }
- return bounds;
-}
-
-float Camera::world_to_raster_size(float3 P)
-{
- float res = 1.0f;
-
- if (camera_type == CAMERA_ORTHOGRAPHIC) {
- res = min(len(full_dx), len(full_dy));
-
- if (offscreen_dicing_scale > 1.0f) {
- float3 p = transform_point(&worldtocamera, P);
- float3 v1 = transform_perspective(&full_rastertocamera,
- make_float3(full_width, full_height, 0.0f));
- float3 v2 = transform_perspective(&full_rastertocamera, zero_float3());
-
- /* Create point clamped to frustum */
- float3 c;
- c.x = max(v2.x, min(v1.x, p.x));
- c.y = max(v2.y, min(v1.y, p.y));
- c.z = max(0.0f, p.z);
-
- /* Check right side */
- float f_dist = len(p - c) / sqrtf((v1.x * v1.x + v1.y * v1.y) * 0.5f);
- if (f_dist < 0.0f) {
- /* Check left side */
- f_dist = len(p - c) / sqrtf((v2.x * v2.x + v2.y * v2.y) * 0.5f);
- }
- if (f_dist > 0.0f) {
- res += res * f_dist * (offscreen_dicing_scale - 1.0f);
- }
- }
- }
- else if (camera_type == CAMERA_PERSPECTIVE) {
- /* Calculate as if point is directly ahead of the camera. */
- float3 raster = make_float3(0.5f * full_width, 0.5f * full_height, 0.0f);
- float3 Pcamera = transform_perspective(&full_rastertocamera, raster);
-
- /* dDdx */
- float3 Ddiff = transform_direction(&cameratoworld, Pcamera);
- float3 dx = len_squared(full_dx) < len_squared(full_dy) ? full_dx : full_dy;
- float3 dDdx = normalize(Ddiff + dx) - normalize(Ddiff);
-
- /* dPdx */
- float dist = len(transform_point(&worldtocamera, P));
- float3 D = normalize(Ddiff);
- res = len(dist * dDdx - dot(dist * dDdx, D) * D);
-
- /* Decent approx distance to frustum
- * (doesn't handle corners correctly, but not that big of a deal) */
- float f_dist = 0.0f;
-
- if (offscreen_dicing_scale > 1.0f) {
- float3 p = transform_point(&worldtocamera, P);
-
- /* Distance from the four planes */
- float r = dot(p, frustum_right_normal);
- float t = dot(p, frustum_top_normal);
- float l = dot(p, frustum_left_normal);
- float b = dot(p, frustum_bottom_normal);
-
- if (r <= 0.0f && l <= 0.0f && t <= 0.0f && b <= 0.0f) {
- /* Point is inside frustum */
- f_dist = 0.0f;
- }
- else if (r > 0.0f && l > 0.0f && t > 0.0f && b > 0.0f) {
- /* Point is behind frustum */
- f_dist = len(p);
- }
- else {
- /* Point may be behind or off to the side, need to check */
- float3 along_right = make_float3(-frustum_right_normal.z, 0.0f, frustum_right_normal.x);
- float3 along_left = make_float3(frustum_left_normal.z, 0.0f, -frustum_left_normal.x);
- float3 along_top = make_float3(0.0f, -frustum_top_normal.z, frustum_top_normal.y);
- float3 along_bottom = make_float3(0.0f, frustum_bottom_normal.z, -frustum_bottom_normal.y);
-
- float dist[] = {r, l, t, b};
- float3 along[] = {along_right, along_left, along_top, along_bottom};
-
- bool test_o = false;
-
- float *d = dist;
- float3 *a = along;
- for (int i = 0; i < 4; i++, d++, a++) {
- /* Test if we should check this side at all */
- if (*d > 0.0f) {
- if (dot(p, *a) >= 0.0f) {
- /* We are in front of the back edge of this side of the frustum */
- f_dist = max(f_dist, *d);
- }
- else {
- /* Possibly far enough behind the frustum to use distance to origin instead of edge
- */
- test_o = true;
- }
- }
- }
-
- if (test_o) {
- f_dist = (f_dist > 0) ? min(f_dist, len(p)) : len(p);
- }
- }
-
- if (f_dist > 0.0f) {
- res += len(dDdx - dot(dDdx, D) * D) * f_dist * (offscreen_dicing_scale - 1.0f);
- }
- }
- }
- else if (camera_type == CAMERA_PANORAMA) {
- float3 D = transform_point(&worldtocamera, P);
- float dist = len(D);
-
- Ray ray;
- memset(&ray, 0, sizeof(ray));
-
- /* Distortion can become so great that the results become meaningless, there
- * may be a better way to do this, but calculating differentials from the
- * point directly ahead seems to produce good enough results. */
-#if 0
- float2 dir = direction_to_panorama(&kernel_camera, kernel_camera_motion.data(), normalize(D));
- float3 raster = transform_perspective(&full_cameratoraster, make_float3(dir.x, dir.y, 0.0f));
-
- ray.t = 1.0f;
- camera_sample_panorama(
- &kernel_camera, kernel_camera_motion.data(), raster.x, raster.y, 0.0f, 0.0f, &ray);
- if (ray.t == 0.0f) {
- /* No differentials, just use from directly ahead. */
- camera_sample_panorama(&kernel_camera,
- kernel_camera_motion.data(),
- 0.5f * full_width,
- 0.5f * full_height,
- 0.0f,
- 0.0f,
- &ray);
- }
-#else
- camera_sample_panorama(&kernel_camera,
-# ifdef __CAMERA_MOTION__
- kernel_camera_motion.data(),
-# endif
- 0.5f * full_width,
- 0.5f * full_height,
- 0.0f,
- 0.0f,
- &ray);
-#endif
-
- /* TODO: would it help to use more accurate differentials here? */
- differential3 dP;
- differential_transfer_compact(&dP, ray.dP, ray.D, ray.dD, ray.D, dist);
-
- return max(len(dP.dx), len(dP.dy));
- }
-
- return res;
-}
-
-bool Camera::use_motion() const
-{
- return motion.size() > 1;
-}
-
-void Camera::set_screen_size(int width_, int height_)
-{
- if (width_ != width || height_ != height) {
- width = width_;
- height = height_;
- tag_modified();
- }
-}
-
-float Camera::motion_time(int step) const
-{
- return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
-}
-
-int Camera::motion_step(float time) const
-{
- if (use_motion()) {
- for (int step = 0; step < motion.size(); step++) {
- if (time == motion_time(step)) {
- return step;
- }
- }
- }
-
- return -1;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
deleted file mode 100644
index cb8ecac1a7e..00000000000
--- a/intern/cycles/render/camera.h
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __CAMERA_H__
-#define __CAMERA_H__
-
-#include "kernel/kernel_types.h"
-
-#include "graph/node.h"
-
-#include "util/util_array.h"
-#include "util/util_boundbox.h"
-#include "util/util_projection.h"
-#include "util/util_transform.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class Scene;
-
-/* Camera
- *
- * The camera parameters are quite standard, tested to be both compatible with
- * Renderman, and Blender after remapping.
- */
-
-class Camera : public Node {
- public:
- NODE_DECLARE
-
- /* Specifies an offset for the shutter's time interval. */
- enum MotionPosition {
- /* Shutter opens at the current frame. */
- MOTION_POSITION_START = 0,
- /* Shutter is fully open at the current frame. */
- MOTION_POSITION_CENTER = 1,
- /* Shutter closes at the current frame. */
- MOTION_POSITION_END = 2,
-
- MOTION_NUM_POSITIONS,
- };
-
- /* Specifies rolling shutter effect. */
- enum RollingShutterType {
- /* No rolling shutter effect. */
- ROLLING_SHUTTER_NONE = 0,
- /* Sensor is being scanned vertically from top to bottom. */
- ROLLING_SHUTTER_TOP = 1,
-
- ROLLING_SHUTTER_NUM_TYPES,
- };
-
- /* Stereo Type */
- enum StereoEye {
- STEREO_NONE,
- STEREO_LEFT,
- STEREO_RIGHT,
- };
-
- /* motion blur */
- NODE_SOCKET_API(float, shuttertime)
- NODE_SOCKET_API(MotionPosition, motion_position)
- NODE_SOCKET_API_ARRAY(array<float>, shutter_curve)
- size_t shutter_table_offset;
-
- /* ** Rolling shutter effect. ** */
- /* Defines rolling shutter effect type. */
- NODE_SOCKET_API(RollingShutterType, rolling_shutter_type)
- /* Specifies exposure time of scan-lines when using
- * rolling shutter effect.
- */
- NODE_SOCKET_API(float, rolling_shutter_duration)
-
- /* depth of field */
- NODE_SOCKET_API(float, focaldistance)
- NODE_SOCKET_API(float, aperturesize)
- NODE_SOCKET_API(uint, blades)
- NODE_SOCKET_API(float, bladesrotation)
-
- /* type */
- NODE_SOCKET_API(CameraType, camera_type)
- NODE_SOCKET_API(float, fov)
-
- /* panorama */
- NODE_SOCKET_API(PanoramaType, panorama_type)
- NODE_SOCKET_API(float, fisheye_fov)
- NODE_SOCKET_API(float, fisheye_lens)
- NODE_SOCKET_API(float, latitude_min)
- NODE_SOCKET_API(float, latitude_max)
- NODE_SOCKET_API(float, longitude_min)
- NODE_SOCKET_API(float, longitude_max)
-
- /* panorama stereo */
- NODE_SOCKET_API(StereoEye, stereo_eye)
- NODE_SOCKET_API(bool, use_spherical_stereo)
- NODE_SOCKET_API(float, interocular_distance)
- NODE_SOCKET_API(float, convergence_distance)
- NODE_SOCKET_API(bool, use_pole_merge)
- NODE_SOCKET_API(float, pole_merge_angle_from)
- NODE_SOCKET_API(float, pole_merge_angle_to)
-
- /* anamorphic lens bokeh */
- NODE_SOCKET_API(float, aperture_ratio)
-
- /* sensor */
- NODE_SOCKET_API(float, sensorwidth)
- NODE_SOCKET_API(float, sensorheight)
-
- /* clipping */
- NODE_SOCKET_API(float, nearclip)
- NODE_SOCKET_API(float, farclip)
-
- /* screen */
- BoundBox2D viewplane;
- NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, left)
- NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, right)
- NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, bottom)
- NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, top)
-
- /* width and height change during preview, so we need these for calculating dice rates. */
- NODE_SOCKET_API(int, full_width)
- NODE_SOCKET_API(int, full_height)
- /* controls how fast the dicing rate falls off for geometry out side of view */
- NODE_SOCKET_API(float, offscreen_dicing_scale)
-
- /* border */
- BoundBox2D border;
- NODE_SOCKET_API_STRUCT_MEMBER(float, border, left)
- NODE_SOCKET_API_STRUCT_MEMBER(float, border, right)
- NODE_SOCKET_API_STRUCT_MEMBER(float, border, bottom)
- NODE_SOCKET_API_STRUCT_MEMBER(float, border, top)
-
- BoundBox2D viewport_camera_border;
- NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, left)
- NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, right)
- NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, bottom)
- NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, top)
-
- /* transformation */
- NODE_SOCKET_API(Transform, matrix)
-
- /* motion */
- NODE_SOCKET_API_ARRAY(array<Transform>, motion)
- NODE_SOCKET_API(bool, use_perspective_motion)
- NODE_SOCKET_API(float, fov_pre)
- NODE_SOCKET_API(float, fov_post)
-
- /* computed camera parameters */
- ProjectionTransform screentoworld;
- ProjectionTransform rastertoworld;
- ProjectionTransform ndctoworld;
- Transform cameratoworld;
-
- ProjectionTransform worldtoraster;
- ProjectionTransform worldtoscreen;
- ProjectionTransform worldtondc;
- Transform worldtocamera;
-
- ProjectionTransform rastertocamera;
- ProjectionTransform cameratoraster;
-
- ProjectionTransform full_rastertocamera;
-
- float3 dx;
- float3 dy;
-
- float3 full_dx;
- float3 full_dy;
-
- float3 frustum_right_normal;
- float3 frustum_top_normal;
- float3 frustum_left_normal;
- float3 frustum_bottom_normal;
-
- /* update */
- bool need_device_update;
- bool need_flags_update;
- int previous_need_motion;
-
- /* Kernel camera data, copied here for dicing. */
- KernelCamera kernel_camera;
- array<DecomposedTransform> kernel_camera_motion;
-
- private:
- int width;
- int height;
-
- public:
- /* functions */
- Camera();
- ~Camera();
-
- void compute_auto_viewplane();
-
- void update(Scene *scene);
-
- void device_update(Device *device, DeviceScene *dscene, Scene *scene);
- void device_update_volume(Device *device, DeviceScene *dscene, Scene *scene);
- void device_free(Device *device, DeviceScene *dscene, Scene *scene);
-
- /* Public utility functions. */
- BoundBox viewplane_bounds_get();
-
- /* Calculates the width of a pixel at point in world space. */
- float world_to_raster_size(float3 P);
-
- /* Motion blur. */
- float motion_time(int step) const;
- int motion_step(float time) const;
- bool use_motion() const;
-
- void set_screen_size(int width_, int height_);
-
- private:
- /* Private utility functions. */
- float3 transform_raster_to_world(float raster_x, float raster_y);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __CAMERA_H__ */
diff --git a/intern/cycles/render/colorspace.cpp b/intern/cycles/render/colorspace.cpp
deleted file mode 100644
index 3842f8e4726..00000000000
--- a/intern/cycles/render/colorspace.cpp
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/colorspace.h"
-
-#include "util/util_color.h"
-#include "util/util_half.h"
-#include "util/util_image.h"
-#include "util/util_logging.h"
-#include "util/util_math.h"
-#include "util/util_thread.h"
-#include "util/util_vector.h"
-
-#ifdef WITH_OCIO
-# include <OpenColorIO/OpenColorIO.h>
-namespace OCIO = OCIO_NAMESPACE;
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/* Builtin colorspaces. */
-ustring u_colorspace_auto;
-ustring u_colorspace_raw("__builtin_raw");
-ustring u_colorspace_srgb("__builtin_srgb");
-
-/* Cached data. */
-#ifdef WITH_OCIO
-static thread_mutex cache_colorspaces_mutex;
-static thread_mutex cache_processors_mutex;
-static unordered_map<ustring, ustring, ustringHash> cached_colorspaces;
-static unordered_map<ustring, OCIO::ConstProcessorRcPtr, ustringHash> cached_processors;
-#endif
-
-ColorSpaceProcessor *ColorSpaceManager::get_processor(ustring colorspace)
-{
-#ifdef WITH_OCIO
- /* Only use this for OpenColorIO color spaces, not the builtin ones. */
- assert(colorspace != u_colorspace_srgb && colorspace != u_colorspace_auto);
-
- if (colorspace == u_colorspace_raw) {
- return NULL;
- }
-
- OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
- if (!config) {
- return NULL;
- }
-
- /* Cache processor until free_memory(), memory overhead is expected to be
- * small and the processor is likely to be reused. */
- thread_scoped_lock cache_processors_lock(cache_processors_mutex);
- if (cached_processors.find(colorspace) == cached_processors.end()) {
- try {
- cached_processors[colorspace] = config->getProcessor(colorspace.c_str(), "scene_linear");
- }
- catch (OCIO::Exception &exception) {
- cached_processors[colorspace] = OCIO::ConstProcessorRcPtr();
- VLOG(1) << "Colorspace " << colorspace.c_str()
- << " can't be converted to scene_linear: " << exception.what();
- }
- }
-
- const OCIO::Processor *processor = cached_processors[colorspace].get();
- return (ColorSpaceProcessor *)processor;
-#else
- /* No OpenColorIO. */
- (void)colorspace;
- return NULL;
-#endif
-}
-
-bool ColorSpaceManager::colorspace_is_data(ustring colorspace)
-{
- if (colorspace == u_colorspace_auto || colorspace == u_colorspace_raw ||
- colorspace == u_colorspace_srgb) {
- return false;
- }
-
-#ifdef WITH_OCIO
- OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
- if (!config) {
- return false;
- }
-
- try {
- OCIO::ConstColorSpaceRcPtr space = config->getColorSpace(colorspace.c_str());
- return space && space->isData();
- }
- catch (OCIO::Exception &) {
- return false;
- }
-#else
- return false;
-#endif
-}
-
-ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace,
- const char *file_format,
- bool is_float)
-{
- if (colorspace == u_colorspace_auto) {
- /* Auto detect sRGB or raw if none specified. */
- if (is_float) {
- bool srgb = (colorspace == "sRGB" || colorspace == "GammaCorrected" ||
- (colorspace.empty() &&
- (strcmp(file_format, "png") == 0 || strcmp(file_format, "tiff") == 0 ||
- strcmp(file_format, "dpx") == 0 || strcmp(file_format, "jpeg2000") == 0)));
- return srgb ? u_colorspace_srgb : u_colorspace_raw;
- }
- else {
- return u_colorspace_srgb;
- }
- }
- else if (colorspace == u_colorspace_srgb || colorspace == u_colorspace_raw) {
- /* Builtin colorspaces. */
- return colorspace;
- }
- else {
- /* Use OpenColorIO. */
-#ifdef WITH_OCIO
- {
- thread_scoped_lock cache_lock(cache_colorspaces_mutex);
- /* Cached lookup. */
- if (cached_colorspaces.find(colorspace) != cached_colorspaces.end()) {
- return cached_colorspaces[colorspace];
- }
- }
-
- /* Detect if it matches a simple builtin colorspace. */
- bool is_scene_linear, is_srgb;
- is_builtin_colorspace(colorspace, is_scene_linear, is_srgb);
-
- thread_scoped_lock cache_lock(cache_colorspaces_mutex);
- if (is_scene_linear) {
- VLOG(1) << "Colorspace " << colorspace.string() << " is no-op";
- cached_colorspaces[colorspace] = u_colorspace_raw;
- return u_colorspace_raw;
- }
- else if (is_srgb) {
- VLOG(1) << "Colorspace " << colorspace.string() << " is sRGB";
- cached_colorspaces[colorspace] = u_colorspace_srgb;
- return u_colorspace_srgb;
- }
-
- /* Verify if we can convert from the requested color space. */
- if (!get_processor(colorspace)) {
- OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
- if (!config || !config->getColorSpace(colorspace.c_str())) {
- VLOG(1) << "Colorspace " << colorspace.c_str() << " not found, using raw instead";
- }
- else {
- VLOG(1) << "Colorspace " << colorspace.c_str()
- << " can't be converted to scene_linear, using raw instead";
- }
- cached_colorspaces[colorspace] = u_colorspace_raw;
- return u_colorspace_raw;
- }
-
- /* Convert to/from colorspace with OpenColorIO. */
- VLOG(1) << "Colorspace " << colorspace.string() << " handled through OpenColorIO";
- cached_colorspaces[colorspace] = colorspace;
- return colorspace;
-#else
- VLOG(1) << "Colorspace " << colorspace.c_str() << " not available, built without OpenColorIO";
- return u_colorspace_raw;
-#endif
- }
-}
-
-void ColorSpaceManager::is_builtin_colorspace(ustring colorspace,
- bool &is_scene_linear,
- bool &is_srgb)
-{
-#ifdef WITH_OCIO
- const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace);
- if (!processor) {
- is_scene_linear = false;
- is_srgb = false;
- return;
- }
-
- OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
- is_scene_linear = true;
- is_srgb = true;
- for (int i = 0; i < 256; i++) {
- float v = i / 255.0f;
-
- float cR[3] = {v, 0, 0};
- float cG[3] = {0, v, 0};
- float cB[3] = {0, 0, v};
- float cW[3] = {v, v, v};
- device_processor->applyRGB(cR);
- device_processor->applyRGB(cG);
- device_processor->applyRGB(cB);
- device_processor->applyRGB(cW);
-
- /* Make sure that there is no channel crosstalk. */
- if (fabsf(cR[1]) > 1e-5f || fabsf(cR[2]) > 1e-5f || fabsf(cG[0]) > 1e-5f ||
- fabsf(cG[2]) > 1e-5f || fabsf(cB[0]) > 1e-5f || fabsf(cB[1]) > 1e-5f) {
- is_scene_linear = false;
- is_srgb = false;
- break;
- }
- /* Make sure that the three primaries combine linearly. */
- if (!compare_floats(cR[0], cW[0], 1e-6f, 64) || !compare_floats(cG[1], cW[1], 1e-6f, 64) ||
- !compare_floats(cB[2], cW[2], 1e-6f, 64)) {
- is_scene_linear = false;
- is_srgb = false;
- break;
- }
- /* Make sure that the three channels behave identically. */
- if (!compare_floats(cW[0], cW[1], 1e-6f, 64) || !compare_floats(cW[1], cW[2], 1e-6f, 64)) {
- is_scene_linear = false;
- is_srgb = false;
- break;
- }
-
- float out_v = average(make_float3(cW[0], cW[1], cW[2]));
- if (!compare_floats(v, out_v, 1e-6f, 64)) {
- is_scene_linear = false;
- }
- if (!compare_floats(color_srgb_to_linear(v), out_v, 1e-6f, 64)) {
- is_srgb = false;
- }
- }
-#else
- (void)colorspace;
- is_scene_linear = false;
- is_srgb = false;
-#endif
-}
-
-#ifdef WITH_OCIO
-
-template<typename T> inline float4 cast_to_float4(T *data)
-{
- return make_float4(util_image_cast_to_float(data[0]),
- util_image_cast_to_float(data[1]),
- util_image_cast_to_float(data[2]),
- util_image_cast_to_float(data[3]));
-}
-
-template<typename T> inline void cast_from_float4(T *data, float4 value)
-{
- data[0] = util_image_cast_from_float<T>(value.x);
- data[1] = util_image_cast_from_float<T>(value.y);
- data[2] = util_image_cast_from_float<T>(value.z);
- data[3] = util_image_cast_from_float<T>(value.w);
-}
-
-/* Slower versions for other all data types, which needs to convert to float and back. */
-template<typename T, bool compress_as_srgb = false>
-inline void processor_apply_pixels(const OCIO::Processor *processor, T *pixels, size_t num_pixels)
-{
- /* TODO: implement faster version for when we know the conversion
- * is a simple matrix transform between linear spaces. In that case
- * un-premultiply is not needed. */
- OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
-
- /* Process large images in chunks to keep temporary memory requirement down. */
- const size_t chunk_size = std::min((size_t)(16 * 1024 * 1024), num_pixels);
- vector<float4> float_pixels(chunk_size);
-
- for (size_t j = 0; j < num_pixels; j += chunk_size) {
- size_t width = std::min(chunk_size, num_pixels - j);
-
- for (size_t i = 0; i < width; i++) {
- float4 value = cast_to_float4(pixels + 4 * (j + i));
-
- if (!(value.w <= 0.0f || value.w == 1.0f)) {
- float inv_alpha = 1.0f / value.w;
- value.x *= inv_alpha;
- value.y *= inv_alpha;
- value.z *= inv_alpha;
- }
-
- float_pixels[i] = value;
- }
-
- OCIO::PackedImageDesc desc((float *)float_pixels.data(), width, 1, 4);
- device_processor->apply(desc);
-
- for (size_t i = 0; i < width; i++) {
- float4 value = float_pixels[i];
-
- if (compress_as_srgb) {
- value = color_linear_to_srgb_v4(value);
- }
-
- if (!(value.w <= 0.0f || value.w == 1.0f)) {
- value.x *= value.w;
- value.y *= value.w;
- value.z *= value.w;
- }
-
- cast_from_float4(pixels + 4 * (j + i), value);
- }
- }
-}
-#endif
-
-template<typename T>
-void ColorSpaceManager::to_scene_linear(ustring colorspace,
- T *pixels,
- size_t num_pixels,
- bool compress_as_srgb)
-{
-#ifdef WITH_OCIO
- const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace);
-
- if (processor) {
- if (compress_as_srgb) {
- /* Compress output as sRGB. */
- processor_apply_pixels<T, true>(processor, pixels, num_pixels);
- }
- else {
- /* Write output as scene linear directly. */
- processor_apply_pixels<T>(processor, pixels, num_pixels);
- }
- }
-#else
- (void)colorspace;
- (void)pixels;
- (void)num_pixels;
- (void)compress_as_srgb;
-#endif
-}
-
-void ColorSpaceManager::to_scene_linear(ColorSpaceProcessor *processor_,
- float *pixel,
- int channels)
-{
-#ifdef WITH_OCIO
- const OCIO::Processor *processor = (const OCIO::Processor *)processor_;
-
- if (processor) {
- OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
- if (channels == 3) {
- device_processor->applyRGB(pixel);
- }
- else if (channels == 4) {
- if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
- /* Fast path for RGBA. */
- device_processor->applyRGB(pixel);
- }
- else {
- /* Un-associate and associate alpha since color management should not
- * be affected by transparency. */
- float alpha = pixel[3];
- float inv_alpha = 1.0f / alpha;
-
- pixel[0] *= inv_alpha;
- pixel[1] *= inv_alpha;
- pixel[2] *= inv_alpha;
-
- device_processor->applyRGB(pixel);
-
- pixel[0] *= alpha;
- pixel[1] *= alpha;
- pixel[2] *= alpha;
- }
- }
- }
-#else
- (void)processor_;
- (void)pixel;
- (void)channels;
-#endif
-}
-
-void ColorSpaceManager::free_memory()
-{
-#ifdef WITH_OCIO
- map_free_memory(cached_colorspaces);
- map_free_memory(cached_processors);
-#endif
-}
-
-/* Template instantiations so we don't have to inline functions. */
-template void ColorSpaceManager::to_scene_linear(ustring, uchar *, size_t, bool);
-template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, bool);
-template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, bool);
-template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, bool);
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/colorspace.h b/intern/cycles/render/colorspace.h
deleted file mode 100644
index 51d0b121cc0..00000000000
--- a/intern/cycles/render/colorspace.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __COLORSPACE_H__
-#define __COLORSPACE_H__
-
-#include "util/util_map.h"
-#include "util/util_param.h"
-
-CCL_NAMESPACE_BEGIN
-
-extern ustring u_colorspace_auto;
-extern ustring u_colorspace_raw;
-extern ustring u_colorspace_srgb;
-
-class ColorSpaceProcessor;
-
-class ColorSpaceManager {
- public:
- /* Convert used specified colorspace to a colorspace that we are able to
- * convert to and from. If the colorspace is u_colorspace_auto, we auto
- * detect a colospace. */
- static ustring detect_known_colorspace(ustring colorspace,
- const char *file_format,
- bool is_float);
-
- /* Test if colorspace is for non-color data. */
- static bool colorspace_is_data(ustring colorspace);
-
- /* Convert pixels in the specified colorspace to scene linear color for
- * rendering. Must be a colorspace returned from detect_known_colorspace. */
- template<typename T>
- static void to_scene_linear(ustring colorspace,
- T *pixels,
- size_t num_pixels,
- bool compress_as_srgb);
-
- /* Efficiently convert pixels to scene linear colorspace at render time,
- * for OSL where the image texture cache contains original pixels. The
- * handle is valid for the lifetime of the application. */
- static ColorSpaceProcessor *get_processor(ustring colorspace);
- static void to_scene_linear(ColorSpaceProcessor *processor, float *pixel, int channels);
-
- /* Clear memory when the application exits. Invalidates all processors. */
- static void free_memory();
-
- private:
- static void is_builtin_colorspace(ustring colorspace, bool &is_no_op, bool &is_srgb);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __COLORSPACE_H__ */
diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp
deleted file mode 100644
index a4d40ae8183..00000000000
--- a/intern/cycles/render/constant_fold.cpp
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/constant_fold.h"
-#include "render/graph.h"
-
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-
-CCL_NAMESPACE_BEGIN
-
-ConstantFolder::ConstantFolder(ShaderGraph *graph,
- ShaderNode *node,
- ShaderOutput *output,
- Scene *scene)
- : graph(graph), node(node), output(output), scene(scene)
-{
-}
-
-bool ConstantFolder::all_inputs_constant() const
-{
- foreach (ShaderInput *input, node->inputs) {
- if (input->link) {
- return false;
- }
- }
-
- return true;
-}
-
-void ConstantFolder::make_constant(float value) const
-{
- VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant (" << value
- << ").";
-
- foreach (ShaderInput *sock, output->links) {
- sock->set(value);
- sock->constant_folded_in = true;
- }
-
- graph->disconnect(output);
-}
-
-void ConstantFolder::make_constant(float3 value) const
-{
- VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant " << value << ".";
-
- foreach (ShaderInput *sock, output->links) {
- sock->set(value);
- sock->constant_folded_in = true;
- }
-
- graph->disconnect(output);
-}
-
-void ConstantFolder::make_constant_clamp(float value, bool clamp) const
-{
- make_constant(clamp ? saturate(value) : value);
-}
-
-void ConstantFolder::make_constant_clamp(float3 value, bool clamp) const
-{
- if (clamp) {
- value.x = saturate(value.x);
- value.y = saturate(value.y);
- value.z = saturate(value.z);
- }
-
- make_constant(value);
-}
-
-void ConstantFolder::make_zero() const
-{
- if (output->type() == SocketType::FLOAT) {
- make_constant(0.0f);
- }
- else if (SocketType::is_float3(output->type())) {
- make_constant(zero_float3());
- }
- else {
- assert(0);
- }
-}
-
-void ConstantFolder::make_one() const
-{
- if (output->type() == SocketType::FLOAT) {
- make_constant(1.0f);
- }
- else if (SocketType::is_float3(output->type())) {
- make_constant(one_float3());
- }
- else {
- assert(0);
- }
-}
-
-void ConstantFolder::bypass(ShaderOutput *new_output) const
-{
- assert(new_output);
-
- VLOG(1) << "Folding " << node->name << "::" << output->name() << " to socket "
- << new_output->parent->name << "::" << new_output->name() << ".";
-
- /* Remove all outgoing links from socket and connect them to new_output instead.
- * The graph->relink method affects node inputs, so it's not safe to use in constant
- * folding if the node has multiple outputs and will thus be folded multiple times. */
- vector<ShaderInput *> outputs = output->links;
-
- graph->disconnect(output);
-
- foreach (ShaderInput *sock, outputs) {
- graph->connect(new_output, sock);
- }
-}
-
-void ConstantFolder::discard() const
-{
- assert(output->type() == SocketType::CLOSURE);
-
- VLOG(1) << "Discarding closure " << node->name << ".";
-
- graph->disconnect(output);
-}
-
-void ConstantFolder::bypass_or_discard(ShaderInput *input) const
-{
- assert(input->type() == SocketType::CLOSURE);
-
- if (input->link) {
- bypass(input->link);
- }
- else {
- discard();
- }
-}
-
-bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, bool clamp) const
-{
- if (input->type() != output->type()) {
- return false;
- }
- else if (!input->link) {
- if (input->type() == SocketType::FLOAT) {
- make_constant_clamp(node->get_float(input->socket_type), clamp);
- return true;
- }
- else if (SocketType::is_float3(input->type())) {
- make_constant_clamp(node->get_float3(input->socket_type), clamp);
- return true;
- }
- }
- else if (!clamp) {
- bypass(input->link);
- return true;
- }
- else {
- /* disconnect other inputs if we can't fully bypass due to clamp */
- foreach (ShaderInput *other, node->inputs) {
- if (other != input && other->link) {
- graph->disconnect(other);
- }
- }
- }
-
- return false;
-}
-
-bool ConstantFolder::is_zero(ShaderInput *input) const
-{
- if (!input->link) {
- if (input->type() == SocketType::FLOAT) {
- return node->get_float(input->socket_type) == 0.0f;
- }
- else if (SocketType::is_float3(input->type())) {
- return node->get_float3(input->socket_type) == zero_float3();
- }
- }
-
- return false;
-}
-
-bool ConstantFolder::is_one(ShaderInput *input) const
-{
- if (!input->link) {
- if (input->type() == SocketType::FLOAT) {
- return node->get_float(input->socket_type) == 1.0f;
- }
- else if (SocketType::is_float3(input->type())) {
- return node->get_float3(input->socket_type) == one_float3();
- }
- }
-
- return false;
-}
-
-/* Specific nodes */
-
-void ConstantFolder::fold_mix(NodeMix type, bool clamp) const
-{
- ShaderInput *fac_in = node->input("Fac");
- ShaderInput *color1_in = node->input("Color1");
- ShaderInput *color2_in = node->input("Color2");
-
- float fac = saturate(node->get_float(fac_in->socket_type));
- bool fac_is_zero = !fac_in->link && fac == 0.0f;
- bool fac_is_one = !fac_in->link && fac == 1.0f;
-
- /* remove no-op node when factor is 0.0 */
- if (fac_is_zero) {
- /* note that some of the modes will clamp out of bounds values even without use_clamp */
- if (!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) {
- if (try_bypass_or_make_constant(color1_in, clamp)) {
- return;
- }
- }
- }
-
- switch (type) {
- case NODE_MIX_BLEND:
- /* remove useless mix colors nodes */
- if (color1_in->link && color2_in->link) {
- if (color1_in->link == color2_in->link) {
- try_bypass_or_make_constant(color1_in, clamp);
- break;
- }
- }
- else if (!color1_in->link && !color2_in->link) {
- float3 color1 = node->get_float3(color1_in->socket_type);
- float3 color2 = node->get_float3(color2_in->socket_type);
- if (color1 == color2) {
- try_bypass_or_make_constant(color1_in, clamp);
- break;
- }
- }
- /* remove no-op mix color node when factor is 1.0 */
- if (fac_is_one) {
- try_bypass_or_make_constant(color2_in, clamp);
- break;
- }
- break;
- case NODE_MIX_ADD:
- /* 0 + X (fac 1) == X */
- if (is_zero(color1_in) && fac_is_one) {
- try_bypass_or_make_constant(color2_in, clamp);
- }
- /* X + 0 (fac ?) == X */
- else if (is_zero(color2_in)) {
- try_bypass_or_make_constant(color1_in, clamp);
- }
- break;
- case NODE_MIX_SUB:
- /* X - 0 (fac ?) == X */
- if (is_zero(color2_in)) {
- try_bypass_or_make_constant(color1_in, clamp);
- }
- /* X - X (fac 1) == 0 */
- else if (color1_in->link && color1_in->link == color2_in->link && fac_is_one) {
- make_zero();
- }
- break;
- case NODE_MIX_MUL:
- /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */
- if (is_one(color1_in) && fac_is_one) {
- try_bypass_or_make_constant(color2_in, clamp);
- }
- else if (is_one(color2_in)) {
- try_bypass_or_make_constant(color1_in, clamp);
- }
- /* 0 * ? (fac ?) == 0, ? * 0 (fac 1) == 0 */
- else if (is_zero(color1_in)) {
- make_zero();
- }
- else if (is_zero(color2_in) && fac_is_one) {
- make_zero();
- }
- break;
- case NODE_MIX_DIV:
- /* X / 1 (fac ?) == X */
- if (is_one(color2_in)) {
- try_bypass_or_make_constant(color1_in, clamp);
- }
- /* 0 / ? (fac ?) == 0 */
- else if (is_zero(color1_in)) {
- make_zero();
- }
- break;
- default:
- break;
- }
-}
-
-void ConstantFolder::fold_math(NodeMathType type) const
-{
- ShaderInput *value1_in = node->input("Value1");
- ShaderInput *value2_in = node->input("Value2");
-
- switch (type) {
- case NODE_MATH_ADD:
- /* X + 0 == 0 + X == X */
- if (is_zero(value1_in)) {
- try_bypass_or_make_constant(value2_in);
- }
- else if (is_zero(value2_in)) {
- try_bypass_or_make_constant(value1_in);
- }
- break;
- case NODE_MATH_SUBTRACT:
- /* X - 0 == X */
- if (is_zero(value2_in)) {
- try_bypass_or_make_constant(value1_in);
- }
- break;
- case NODE_MATH_MULTIPLY:
- /* X * 1 == 1 * X == X */
- if (is_one(value1_in)) {
- try_bypass_or_make_constant(value2_in);
- }
- else if (is_one(value2_in)) {
- try_bypass_or_make_constant(value1_in);
- }
- /* X * 0 == 0 * X == 0 */
- else if (is_zero(value1_in) || is_zero(value2_in)) {
- make_zero();
- }
- break;
- case NODE_MATH_DIVIDE:
- /* X / 1 == X */
- if (is_one(value2_in)) {
- try_bypass_or_make_constant(value1_in);
- }
- /* 0 / X == 0 */
- else if (is_zero(value1_in)) {
- make_zero();
- }
- break;
- case NODE_MATH_POWER:
- /* 1 ^ X == X ^ 0 == 1 */
- if (is_one(value1_in) || is_zero(value2_in)) {
- make_one();
- }
- /* X ^ 1 == X */
- else if (is_one(value2_in)) {
- try_bypass_or_make_constant(value1_in);
- }
- default:
- break;
- }
-}
-
-void ConstantFolder::fold_vector_math(NodeVectorMathType type) const
-{
- ShaderInput *vector1_in = node->input("Vector1");
- ShaderInput *vector2_in = node->input("Vector2");
- ShaderInput *scale_in = node->input("Scale");
-
- switch (type) {
- case NODE_VECTOR_MATH_ADD:
- /* X + 0 == 0 + X == X */
- if (is_zero(vector1_in)) {
- try_bypass_or_make_constant(vector2_in);
- }
- else if (is_zero(vector2_in)) {
- try_bypass_or_make_constant(vector1_in);
- }
- break;
- case NODE_VECTOR_MATH_SUBTRACT:
- /* X - 0 == X */
- if (is_zero(vector2_in)) {
- try_bypass_or_make_constant(vector1_in);
- }
- break;
- case NODE_VECTOR_MATH_MULTIPLY:
- /* X * 0 == 0 * X == 0 */
- if (is_zero(vector1_in) || is_zero(vector2_in)) {
- make_zero();
- } /* X * 1 == 1 * X == X */
- else if (is_one(vector1_in)) {
- try_bypass_or_make_constant(vector2_in);
- }
- else if (is_one(vector2_in)) {
- try_bypass_or_make_constant(vector1_in);
- }
- break;
- case NODE_VECTOR_MATH_DIVIDE:
- /* X / 0 == 0 / X == 0 */
- if (is_zero(vector1_in) || is_zero(vector2_in)) {
- make_zero();
- } /* X / 1 == X */
- else if (is_one(vector2_in)) {
- try_bypass_or_make_constant(vector1_in);
- }
- break;
- case NODE_VECTOR_MATH_DOT_PRODUCT:
- case NODE_VECTOR_MATH_CROSS_PRODUCT:
- /* X * 0 == 0 * X == 0 */
- if (is_zero(vector1_in) || is_zero(vector2_in)) {
- make_zero();
- }
- break;
- case NODE_VECTOR_MATH_LENGTH:
- case NODE_VECTOR_MATH_ABSOLUTE:
- if (is_zero(vector1_in)) {
- make_zero();
- }
- break;
- case NODE_VECTOR_MATH_SCALE:
- /* X * 0 == 0 * X == 0 */
- if (is_zero(vector1_in) || is_zero(scale_in)) {
- make_zero();
- } /* X * 1 == X */
- else if (is_one(scale_in)) {
- try_bypass_or_make_constant(vector1_in);
- }
- break;
- default:
- break;
- }
-}
-
-void ConstantFolder::fold_mapping(NodeMappingType type) const
-{
- ShaderInput *vector_in = node->input("Vector");
- ShaderInput *location_in = node->input("Location");
- ShaderInput *rotation_in = node->input("Rotation");
- ShaderInput *scale_in = node->input("Scale");
-
- if (is_zero(scale_in)) {
- make_zero();
- }
- else if ((is_zero(location_in) || type == NODE_MAPPING_TYPE_VECTOR ||
- type == NODE_MAPPING_TYPE_NORMAL) &&
- is_zero(rotation_in) && is_one(scale_in)) {
- try_bypass_or_make_constant(vector_in);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h
deleted file mode 100644
index fec4123c361..00000000000
--- a/intern/cycles/render/constant_fold.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __CONSTANT_FOLD_H__
-#define __CONSTANT_FOLD_H__
-
-#include "kernel/svm/svm_types.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Scene;
-class ShaderGraph;
-class ShaderInput;
-class ShaderNode;
-class ShaderOutput;
-
-class ConstantFolder {
- public:
- ShaderGraph *const graph;
- ShaderNode *const node;
- ShaderOutput *const output;
-
- Scene *scene;
-
- ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output, Scene *scene);
-
- bool all_inputs_constant() const;
-
- /* Constant folding helpers */
- void make_constant(float value) const;
- void make_constant(float3 value) const;
- void make_constant_clamp(float value, bool clamp) const;
- void make_constant_clamp(float3 value, bool clamp) const;
- void make_zero() const;
- void make_one() const;
-
- /* Bypass node, relinking to another output socket. */
- void bypass(ShaderOutput *output) const;
-
- /* For closure nodes, discard node entirely or bypass to one of its inputs. */
- void discard() const;
- void bypass_or_discard(ShaderInput *input) const;
-
- /* Bypass or make constant, unless we can't due to clamp being true. */
- bool try_bypass_or_make_constant(ShaderInput *input, bool clamp = false) const;
-
- /* Test if shader inputs of the current nodes have fixed values. */
- bool is_zero(ShaderInput *input) const;
- bool is_one(ShaderInput *input) const;
-
- /* Specific nodes. */
- void fold_mix(NodeMix type, bool clamp) const;
- void fold_math(NodeMathType type) const;
- void fold_vector_math(NodeVectorMathType type) const;
- void fold_mapping(NodeMappingType type) const;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __CONSTANT_FOLD_H__ */
diff --git a/intern/cycles/render/curves.cpp b/intern/cycles/render/curves.cpp
deleted file mode 100644
index db48d8b6430..00000000000
--- a/intern/cycles/render/curves.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/curves.h"
-#include "device/device.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/scene.h"
-
-#include "util/util_foreach.h"
-#include "util/util_map.h"
-#include "util/util_progress.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Curve functions */
-
-void curvebounds(float *lower, float *upper, float3 *p, int dim)
-{
- float *p0 = &p[0].x;
- float *p1 = &p[1].x;
- float *p2 = &p[2].x;
- float *p3 = &p[3].x;
-
- /* Catmull-Rom weights. */
- float curve_coef[4];
- curve_coef[0] = p1[dim];
- curve_coef[1] = 0.5f * (-p0[dim] + p2[dim]);
- curve_coef[2] = 0.5f * (2 * p0[dim] - 5 * p1[dim] + 4 * p2[dim] - p3[dim]);
- curve_coef[3] = 0.5f * (-p0[dim] + 3 * p1[dim] - 3 * p2[dim] + p3[dim]);
-
- float discroot = curve_coef[2] * curve_coef[2] - 3 * curve_coef[3] * curve_coef[1];
- float ta = -1.0f;
- float tb = -1.0f;
-
- if (discroot >= 0) {
- discroot = sqrtf(discroot);
- ta = (-curve_coef[2] - discroot) / (3 * curve_coef[3]);
- tb = (-curve_coef[2] + discroot) / (3 * curve_coef[3]);
- ta = (ta > 1.0f || ta < 0.0f) ? -1.0f : ta;
- tb = (tb > 1.0f || tb < 0.0f) ? -1.0f : tb;
- }
-
- *upper = max(p1[dim], p2[dim]);
- *lower = min(p1[dim], p2[dim]);
-
- float exa = p1[dim];
- float exb = p2[dim];
-
- if (ta >= 0.0f) {
- float t2 = ta * ta;
- float t3 = t2 * ta;
- exa = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * ta + curve_coef[0];
- }
- if (tb >= 0.0f) {
- float t2 = tb * tb;
- float t3 = t2 * tb;
- exb = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * tb + curve_coef[0];
- }
-
- *upper = max(*upper, max(exa, exb));
- *lower = min(*lower, min(exa, exb));
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h
deleted file mode 100644
index c52fcb9c882..00000000000
--- a/intern/cycles/render/curves.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __CURVES_H__
-#define __CURVES_H__
-
-#include "util/util_array.h"
-#include "util/util_types.h"
-
-#include "render/hair.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class Progress;
-class Scene;
-
-void curvebounds(float *lower, float *upper, float3 *p, int dim);
-
-class ParticleCurveData {
-
- public:
- ParticleCurveData();
- ~ParticleCurveData();
-
- array<int> psys_firstcurve;
- array<int> psys_curvenum;
- array<int> psys_shader;
-
- array<float> psys_rootradius;
- array<float> psys_tipradius;
- array<float> psys_shape;
- array<bool> psys_closetip;
-
- array<int> curve_firstkey;
- array<int> curve_keynum;
- array<float> curve_length;
- array<float2> curve_uv;
- array<float4> curve_vcol;
-
- array<float3> curvekey_co;
- array<float> curvekey_time;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __CURVES_H__ */
diff --git a/intern/cycles/render/denoising.cpp b/intern/cycles/render/denoising.cpp
deleted file mode 100644
index bcf8d3fa204..00000000000
--- a/intern/cycles/render/denoising.cpp
+++ /dev/null
@@ -1,934 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/denoising.h"
-
-#if 0
-
-# include "kernel/filter/filter_defines.h"
-
-# include "util/util_foreach.h"
-# include "util/util_map.h"
-# include "util/util_system.h"
-# include "util/util_task.h"
-# include "util/util_time.h"
-
-# include <OpenImageIO/filesystem.h>
-
-CCL_NAMESPACE_BEGIN
-
-/* Utility Functions */
-
-static void print_progress(int num, int total, int frame, int num_frames)
-{
- const char *label = "Denoise Frame ";
- int cols = system_console_width();
-
- cols -= strlen(label);
-
- int len = 1;
- for (int x = total; x > 9; x /= 10) {
- len++;
- }
-
- int bars = cols - 2 * len - 6;
-
- printf("\r%s", label);
-
- if (num_frames > 1) {
- int frame_len = 1;
- for (int x = num_frames - 1; x > 9; x /= 10) {
- frame_len++;
- }
- bars -= frame_len + 2;
- printf("%*d ", frame_len, frame);
- }
-
- int v = int(float(num) * bars / total);
- printf("[");
- for (int i = 0; i < v; i++) {
- printf("=");
- }
- if (v < bars) {
- printf(">");
- }
- for (int i = v + 1; i < bars; i++) {
- printf(" ");
- }
- printf(string_printf("] %%%dd / %d", len, total).c_str(), num);
- fflush(stdout);
-}
-
-/* Splits in at its last dot, setting suffix to the part after the dot and in to the part before
- * it. Returns whether a dot was found. */
-static bool split_last_dot(string &in, string &suffix)
-{
- size_t pos = in.rfind(".");
- if (pos == string::npos) {
- return false;
- }
- suffix = in.substr(pos + 1);
- in = in.substr(0, pos);
- return true;
-}
-
-/* Separate channel names as generated by Blender.
- * If views is true:
- * Inputs are expected in the form RenderLayer.Pass.View.Channel, sets renderlayer to
- * "RenderLayer.View" Otherwise: Inputs are expected in the form RenderLayer.Pass.Channel */
-static bool parse_channel_name(
- string name, string &renderlayer, string &pass, string &channel, bool multiview_channels)
-{
- if (!split_last_dot(name, channel)) {
- return false;
- }
- string view;
- if (multiview_channels && !split_last_dot(name, view)) {
- return false;
- }
- if (!split_last_dot(name, pass)) {
- return false;
- }
- renderlayer = name;
-
- if (multiview_channels) {
- renderlayer += "." + view;
- }
-
- return true;
-}
-
-/* Channel Mapping */
-
-struct ChannelMapping {
- int channel;
- string name;
-};
-
-static void fill_mapping(vector<ChannelMapping> &map, int pos, string name, string channels)
-{
- for (const char *chan = channels.c_str(); *chan; chan++) {
- map.push_back({pos++, name + "." + *chan});
- }
-}
-
-static const int INPUT_NUM_CHANNELS = 15;
-static const int INPUT_DENOISING_DEPTH = 0;
-static const int INPUT_DENOISING_NORMAL = 1;
-static const int INPUT_DENOISING_SHADOWING = 4;
-static const int INPUT_DENOISING_ALBEDO = 5;
-static const int INPUT_NOISY_IMAGE = 8;
-static const int INPUT_DENOISING_VARIANCE = 11;
-static const int INPUT_DENOISING_INTENSITY = 14;
-static vector<ChannelMapping> input_channels()
-{
- vector<ChannelMapping> map;
- fill_mapping(map, INPUT_DENOISING_DEPTH, "Denoising Depth", "Z");
- fill_mapping(map, INPUT_DENOISING_NORMAL, "Denoising Normal", "XYZ");
- fill_mapping(map, INPUT_DENOISING_SHADOWING, "Denoising Shadowing", "X");
- fill_mapping(map, INPUT_DENOISING_ALBEDO, "Denoising Albedo", "RGB");
- fill_mapping(map, INPUT_NOISY_IMAGE, "Noisy Image", "RGB");
- fill_mapping(map, INPUT_DENOISING_VARIANCE, "Denoising Variance", "RGB");
- fill_mapping(map, INPUT_DENOISING_INTENSITY, "Denoising Intensity", "X");
- return map;
-}
-
-static const int OUTPUT_NUM_CHANNELS = 3;
-static vector<ChannelMapping> output_channels()
-{
- vector<ChannelMapping> map;
- fill_mapping(map, 0, "Combined", "RGB");
- return map;
-}
-
-/* Renderlayer Handling */
-
-bool DenoiseImageLayer::detect_denoising_channels()
-{
- /* Map device input to image channels. */
- input_to_image_channel.clear();
- input_to_image_channel.resize(INPUT_NUM_CHANNELS, -1);
-
- foreach (const ChannelMapping &mapping, input_channels()) {
- vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name);
- if (i == channels.end()) {
- return false;
- }
-
- size_t input_channel = mapping.channel;
- size_t layer_channel = i - channels.begin();
- input_to_image_channel[input_channel] = layer_to_image_channel[layer_channel];
- }
-
- /* Map device output to image channels. */
- output_to_image_channel.clear();
- output_to_image_channel.resize(OUTPUT_NUM_CHANNELS, -1);
-
- foreach (const ChannelMapping &mapping, output_channels()) {
- vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name);
- if (i == channels.end()) {
- return false;
- }
-
- size_t output_channel = mapping.channel;
- size_t layer_channel = i - channels.begin();
- output_to_image_channel[output_channel] = layer_to_image_channel[layer_channel];
- }
-
- /* Check that all buffer channels are correctly set. */
- for (int i = 0; i < INPUT_NUM_CHANNELS; i++) {
- assert(input_to_image_channel[i] >= 0);
- }
- for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
- assert(output_to_image_channel[i] >= 0);
- }
-
- return true;
-}
-
-bool DenoiseImageLayer::match_channels(int neighbor,
- const std::vector<string> &channelnames,
- const std::vector<string> &neighbor_channelnames)
-{
- neighbor_input_to_image_channel.resize(neighbor + 1);
- vector<int> &mapping = neighbor_input_to_image_channel[neighbor];
-
- assert(mapping.size() == 0);
- mapping.resize(input_to_image_channel.size(), -1);
-
- for (int i = 0; i < input_to_image_channel.size(); i++) {
- const string &channel = channelnames[input_to_image_channel[i]];
- std::vector<string>::const_iterator frame_channel = find(
- neighbor_channelnames.begin(), neighbor_channelnames.end(), channel);
-
- if (frame_channel == neighbor_channelnames.end()) {
- return false;
- }
-
- mapping[i] = frame_channel - neighbor_channelnames.begin();
- }
-
- return true;
-}
-
-/* Denoise Task */
-
-DenoiseTask::DenoiseTask(Device *device,
- DenoiserPipeline *denoiser,
- int frame,
- const vector<int> &neighbor_frames)
- : denoiser(denoiser),
- device(device),
- frame(frame),
- neighbor_frames(neighbor_frames),
- current_layer(0),
- input_pixels(device, "filter input buffer", MEM_READ_ONLY),
- num_tiles(0)
-{
- image.samples = denoiser->samples_override;
-}
-
-DenoiseTask::~DenoiseTask()
-{
- free();
-}
-
-/* Device callbacks */
-
-bool DenoiseTask::acquire_tile(Device *device, Device *tile_device, RenderTile &tile)
-{
- thread_scoped_lock tile_lock(tiles_mutex);
-
- if (tiles.empty()) {
- return false;
- }
-
- tile = tiles.front();
- tiles.pop_front();
-
- device->map_tile(tile_device, tile);
-
- print_progress(num_tiles - tiles.size(), num_tiles, frame, denoiser->num_frames);
-
- return true;
-}
-
-/* Mapping tiles is required for regular rendering since each tile has its separate memory
- * which may be allocated on a different device.
- * For standalone denoising, there is a single memory that is present on all devices, so the only
- * thing that needs to be done here is to specify the surrounding tile geometry.
- *
- * However, since there is only one large memory, the denoised result has to be written to
- * a different buffer to avoid having to copy an entire horizontal slice of the image. */
-void DenoiseTask::map_neighboring_tiles(RenderTileNeighbors &neighbors, Device *tile_device)
-{
- RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
- RenderTile &target_tile = neighbors.target;
-
- /* Fill tile information. */
- for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
- if (i == RenderTileNeighbors::CENTER) {
- continue;
- }
-
- RenderTile &tile = neighbors.tiles[i];
- int dx = (i % 3) - 1;
- int dy = (i / 3) - 1;
- tile.x = clamp(center_tile.x + dx * denoiser->tile_size.x, 0, image.width);
- tile.w = clamp(center_tile.x + (dx + 1) * denoiser->tile_size.x, 0, image.width) - tile.x;
- tile.y = clamp(center_tile.y + dy * denoiser->tile_size.y, 0, image.height);
- tile.h = clamp(center_tile.y + (dy + 1) * denoiser->tile_size.y, 0, image.height) - tile.y;
-
- tile.buffer = center_tile.buffer;
- tile.offset = center_tile.offset;
- tile.stride = image.width;
- }
-
- /* Allocate output buffer. */
- device_vector<float> *output_mem = new device_vector<float>(
- tile_device, "denoising_output", MEM_READ_WRITE);
- output_mem->alloc(OUTPUT_NUM_CHANNELS * center_tile.w * center_tile.h);
-
- /* Fill output buffer with noisy image, assumed by kernel_filter_finalize
- * when skipping denoising of some pixels. */
- float *result = output_mem->data();
- float *in = &image.pixels[image.num_channels * (center_tile.y * image.width + center_tile.x)];
-
- const DenoiseImageLayer &layer = image.layers[current_layer];
- const int *input_to_image_channel = layer.input_to_image_channel.data();
-
- for (int y = 0; y < center_tile.h; y++) {
- for (int x = 0; x < center_tile.w; x++, result += OUTPUT_NUM_CHANNELS) {
- for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
- result[i] = in[image.num_channels * x + input_to_image_channel[INPUT_NOISY_IMAGE + i]];
- }
- }
- in += image.num_channels * image.width;
- }
-
- output_mem->copy_to_device();
-
- /* Fill output tile info. */
- target_tile = center_tile;
- target_tile.buffer = output_mem->device_pointer;
- target_tile.stride = target_tile.w;
- target_tile.offset -= target_tile.x + target_tile.y * target_tile.stride;
-
- thread_scoped_lock output_lock(output_mutex);
- assert(output_pixels.count(center_tile.tile_index) == 0);
- output_pixels[target_tile.tile_index] = output_mem;
-}
-
-void DenoiseTask::unmap_neighboring_tiles(RenderTileNeighbors &neighbors)
-{
- RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
- RenderTile &target_tile = neighbors.target;
-
- thread_scoped_lock output_lock(output_mutex);
- assert(output_pixels.count(center_tile.tile_index) == 1);
- device_vector<float> *output_mem = output_pixels[target_tile.tile_index];
- output_pixels.erase(center_tile.tile_index);
- output_lock.unlock();
-
- /* Copy denoised pixels from device. */
- output_mem->copy_from_device(0, OUTPUT_NUM_CHANNELS * target_tile.w, target_tile.h);
-
- float *result = output_mem->data();
- float *out = &image.pixels[image.num_channels * (target_tile.y * image.width + target_tile.x)];
-
- const DenoiseImageLayer &layer = image.layers[current_layer];
- const int *output_to_image_channel = layer.output_to_image_channel.data();
-
- for (int y = 0; y < target_tile.h; y++) {
- for (int x = 0; x < target_tile.w; x++, result += OUTPUT_NUM_CHANNELS) {
- for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
- out[image.num_channels * x + output_to_image_channel[i]] = result[i];
- }
- }
- out += image.num_channels * image.width;
- }
-
- /* Free device buffer. */
- output_mem->free();
- delete output_mem;
-}
-
-void DenoiseTask::release_tile()
-{
-}
-
-bool DenoiseTask::get_cancel()
-{
- return false;
-}
-
-void DenoiseTask::create_task(DeviceTask &task)
-{
- /* Callback functions. */
- task.acquire_tile = function_bind(&DenoiseTask::acquire_tile, this, device, _1, _2);
- task.map_neighbor_tiles = function_bind(&DenoiseTask::map_neighboring_tiles, this, _1, _2);
- task.unmap_neighbor_tiles = function_bind(&DenoiseTask::unmap_neighboring_tiles, this, _1);
- task.release_tile = function_bind(&DenoiseTask::release_tile, this);
- task.get_cancel = function_bind(&DenoiseTask::get_cancel, this);
-
- /* Denoising parameters. */
- task.denoising = denoiser->params;
- task.denoising.type = DENOISER_NLM;
- task.denoising.use = true;
- task.denoising_from_render = false;
-
- task.denoising_frames.resize(neighbor_frames.size());
- for (int i = 0; i < neighbor_frames.size(); i++) {
- task.denoising_frames[i] = neighbor_frames[i] - frame;
- }
-
- /* Buffer parameters. */
- task.pass_stride = INPUT_NUM_CHANNELS;
- task.target_pass_stride = OUTPUT_NUM_CHANNELS;
- task.pass_denoising_data = 0;
- task.pass_denoising_clean = -1;
- task.frame_stride = image.width * image.height * INPUT_NUM_CHANNELS;
-
- /* Create tiles. */
- thread_scoped_lock tile_lock(tiles_mutex);
- thread_scoped_lock output_lock(output_mutex);
-
- tiles.clear();
- assert(output_pixels.empty());
- output_pixels.clear();
-
- int tiles_x = divide_up(image.width, denoiser->tile_size.x);
- int tiles_y = divide_up(image.height, denoiser->tile_size.y);
-
- for (int ty = 0; ty < tiles_y; ty++) {
- for (int tx = 0; tx < tiles_x; tx++) {
- RenderTile tile;
- tile.x = tx * denoiser->tile_size.x;
- tile.y = ty * denoiser->tile_size.y;
- tile.w = min(image.width - tile.x, denoiser->tile_size.x);
- tile.h = min(image.height - tile.y, denoiser->tile_size.y);
- tile.start_sample = 0;
- tile.num_samples = image.layers[current_layer].samples;
- tile.sample = 0;
- tile.offset = 0;
- tile.stride = image.width;
- tile.tile_index = ty * tiles_x + tx;
- tile.task = RenderTile::DENOISE;
- tile.buffers = NULL;
- tile.buffer = input_pixels.device_pointer;
- tiles.push_back(tile);
- }
- }
-
- num_tiles = tiles.size();
-}
-
-/* Denoiser Operations */
-
-bool DenoiseTask::load_input_pixels(int layer)
-{
- int w = image.width;
- int h = image.height;
- int num_pixels = image.width * image.height;
- int frame_stride = num_pixels * INPUT_NUM_CHANNELS;
-
- /* Load center image */
- DenoiseImageLayer &image_layer = image.layers[layer];
-
- float *buffer_data = input_pixels.data();
- image.read_pixels(image_layer, buffer_data);
- buffer_data += frame_stride;
-
- /* Load neighbor images */
- for (int i = 0; i < image.in_neighbors.size(); i++) {
- if (!image.read_neighbor_pixels(i, image_layer, buffer_data)) {
- error = "Failed to read neighbor frame pixels";
- return false;
- }
- buffer_data += frame_stride;
- }
-
- /* Preprocess */
- buffer_data = input_pixels.data();
- for (int neighbor = 0; neighbor < image.in_neighbors.size() + 1; neighbor++) {
- /* Clamp */
- if (denoiser->params.clamp_input) {
- for (int i = 0; i < num_pixels * INPUT_NUM_CHANNELS; i++) {
- buffer_data[i] = clamp(buffer_data[i], -1e8f, 1e8f);
- }
- }
-
- /* Box blur */
- int r = 5 * denoiser->params.radius;
- float *data = buffer_data + 14;
- array<float> temp(num_pixels);
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int n = 0;
- float sum = 0.0f;
- for (int dx = max(x - r, 0); dx < min(x + r + 1, w); dx++, n++) {
- sum += data[INPUT_NUM_CHANNELS * (y * w + dx)];
- }
- temp[y * w + x] = sum / n;
- }
- }
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int n = 0;
- float sum = 0.0f;
-
- for (int dy = max(y - r, 0); dy < min(y + r + 1, h); dy++, n++) {
- sum += temp[dy * w + x];
- }
-
- data[INPUT_NUM_CHANNELS * (y * w + x)] = sum / n;
- }
- }
-
- /* Highlight compression */
- data = buffer_data + 8;
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int idx = INPUT_NUM_CHANNELS * (y * w + x);
- float3 color = make_float3(data[idx], data[idx + 1], data[idx + 2]);
- color = color_highlight_compress(color, NULL);
- data[idx] = color.x;
- data[idx + 1] = color.y;
- data[idx + 2] = color.z;
- }
- }
-
- buffer_data += frame_stride;
- }
-
- /* Copy to device */
- input_pixels.copy_to_device();
-
- return true;
-}
-
-/* Task stages */
-
-bool DenoiseTask::load()
-{
- string center_filepath = denoiser->input[frame];
- if (!image.load(center_filepath, error)) {
- return false;
- }
-
- if (!image.load_neighbors(denoiser->input, neighbor_frames, error)) {
- return false;
- }
-
- if (image.layers.empty()) {
- error = "No image layers found to denoise in " + center_filepath;
- return false;
- }
-
- /* Allocate device buffer. */
- int num_frames = image.in_neighbors.size() + 1;
- input_pixels.alloc(image.width * INPUT_NUM_CHANNELS, image.height * num_frames);
- input_pixels.zero_to_device();
-
- /* Read pixels for first layer. */
- current_layer = 0;
- if (!load_input_pixels(current_layer)) {
- return false;
- }
-
- return true;
-}
-
-bool DenoiseTask::exec()
-{
- for (current_layer = 0; current_layer < image.layers.size(); current_layer++) {
- /* Read pixels for secondary layers, first was already loaded. */
- if (current_layer > 0) {
- if (!load_input_pixels(current_layer)) {
- return false;
- }
- }
-
- /* Run task on device. */
- DeviceTask task(DeviceTask::RENDER);
- create_task(task);
- device->task_add(task);
- device->task_wait();
-
- printf("\n");
- }
-
- return true;
-}
-
-bool DenoiseTask::save()
-{
- bool ok = image.save_output(denoiser->output[frame], error);
- free();
- return ok;
-}
-
-void DenoiseTask::free()
-{
- image.free();
- input_pixels.free();
- assert(output_pixels.empty());
-}
-
-/* Denoise Image Storage */
-
-DenoiseImage::DenoiseImage()
-{
- width = 0;
- height = 0;
- num_channels = 0;
- samples = 0;
-}
-
-DenoiseImage::~DenoiseImage()
-{
- free();
-}
-
-void DenoiseImage::close_input()
-{
- in_neighbors.clear();
-}
-
-void DenoiseImage::free()
-{
- close_input();
- pixels.clear();
-}
-
-bool DenoiseImage::parse_channels(const ImageSpec &in_spec, string &error)
-{
- const std::vector<string> &channels = in_spec.channelnames;
- const ParamValue *multiview = in_spec.find_attribute("multiView");
- const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING &&
- multiview->type().arraylen >= 2);
-
- layers.clear();
-
- /* Loop over all the channels in the file, parse their name and sort them
- * by RenderLayer.
- * Channels that can't be parsed are directly passed through to the output. */
- map<string, DenoiseImageLayer> file_layers;
- for (int i = 0; i < channels.size(); i++) {
- string layer, pass, channel;
- if (parse_channel_name(channels[i], layer, pass, channel, multiview_channels)) {
- file_layers[layer].channels.push_back(pass + "." + channel);
- file_layers[layer].layer_to_image_channel.push_back(i);
- }
- }
-
- /* Loop over all detected RenderLayers, check whether they contain a full set of input channels.
- * Any channels that won't be processed internally are also passed through. */
- for (map<string, DenoiseImageLayer>::iterator i = file_layers.begin(); i != file_layers.end();
- ++i) {
- const string &name = i->first;
- DenoiseImageLayer &layer = i->second;
-
- /* Check for full pass set. */
- if (!layer.detect_denoising_channels()) {
- continue;
- }
-
- layer.name = name;
- layer.samples = samples;
-
- /* If the sample value isn't set yet, check if there is a layer-specific one in the input file.
- */
- if (layer.samples < 1) {
- string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", "");
- if (sample_string != "") {
- if (!sscanf(sample_string.c_str(), "%d", &layer.samples)) {
- error = "Failed to parse samples metadata: " + sample_string;
- return false;
- }
- }
- }
-
- if (layer.samples < 1) {
- error = string_printf(
- "No sample number specified in the file for layer %s or on the command line",
- name.c_str());
- return false;
- }
-
- layers.push_back(layer);
- }
-
- return true;
-}
-
-void DenoiseImage::read_pixels(const DenoiseImageLayer &layer, float *input_pixels)
-{
- /* Pixels from center file have already been loaded into pixels.
- * We copy a subset into the device input buffer with channels reshuffled. */
- const int *input_to_image_channel = layer.input_to_image_channel.data();
-
- for (int i = 0; i < width * height; i++) {
- for (int j = 0; j < INPUT_NUM_CHANNELS; j++) {
- int image_channel = input_to_image_channel[j];
- input_pixels[i * INPUT_NUM_CHANNELS + j] =
- pixels[((size_t)i) * num_channels + image_channel];
- }
- }
-}
-
-bool DenoiseImage::read_neighbor_pixels(int neighbor,
- const DenoiseImageLayer &layer,
- float *input_pixels)
-{
- /* Load pixels from neighboring frames, and copy them into device buffer
- * with channels reshuffled. */
- size_t num_pixels = (size_t)width * (size_t)height;
- array<float> neighbor_pixels(num_pixels * num_channels);
- if (!in_neighbors[neighbor]->read_image(TypeDesc::FLOAT, neighbor_pixels.data())) {
- return false;
- }
-
- const int *input_to_image_channel = layer.neighbor_input_to_image_channel[neighbor].data();
-
- for (int i = 0; i < width * height; i++) {
- for (int j = 0; j < INPUT_NUM_CHANNELS; j++) {
- int image_channel = input_to_image_channel[j];
- input_pixels[i * INPUT_NUM_CHANNELS + j] =
- neighbor_pixels[((size_t)i) * num_channels + image_channel];
- }
- }
-
- return true;
-}
-
-bool DenoiseImage::load(const string &in_filepath, string &error)
-{
- if (!Filesystem::is_regular(in_filepath)) {
- error = "Couldn't find file: " + in_filepath;
- return false;
- }
-
- unique_ptr<ImageInput> in(ImageInput::open(in_filepath));
- if (!in) {
- error = "Couldn't open file: " + in_filepath;
- return false;
- }
-
- in_spec = in->spec();
- width = in_spec.width;
- height = in_spec.height;
- num_channels = in_spec.nchannels;
-
- if (!parse_channels(in_spec, error)) {
- return false;
- }
-
- if (layers.size() == 0) {
- error = "Could not find a render layer containing denoising info";
- return false;
- }
-
- size_t num_pixels = (size_t)width * (size_t)height;
- pixels.resize(num_pixels * num_channels);
-
- /* Read all channels into buffer. Reading all channels at once is faster
- * than individually due to interleaved EXR channel storage. */
- if (!in->read_image(TypeDesc::FLOAT, pixels.data())) {
- error = "Failed to read image: " + in_filepath;
- return false;
- }
-
- return true;
-}
-
-bool DenoiseImage::load_neighbors(const vector<string> &filepaths,
- const vector<int> &frames,
- string &error)
-{
- if (frames.size() > DENOISE_MAX_FRAMES - 1) {
- error = string_printf("Maximum number of neighbors (%d) exceeded\n", DENOISE_MAX_FRAMES - 1);
- return false;
- }
-
- for (int neighbor = 0; neighbor < frames.size(); neighbor++) {
- int frame = frames[neighbor];
- const string &filepath = filepaths[frame];
-
- if (!Filesystem::is_regular(filepath)) {
- error = "Couldn't find neighbor frame: " + filepath;
- return false;
- }
-
- unique_ptr<ImageInput> in_neighbor(ImageInput::open(filepath));
- if (!in_neighbor) {
- error = "Couldn't open neighbor frame: " + filepath;
- return false;
- }
-
- const ImageSpec &neighbor_spec = in_neighbor->spec();
- if (neighbor_spec.width != width || neighbor_spec.height != height) {
- error = "Neighbor frame has different dimensions: " + filepath;
- return false;
- }
-
- foreach (DenoiseImageLayer &layer, layers) {
- if (!layer.match_channels(neighbor, in_spec.channelnames, neighbor_spec.channelnames)) {
- error = "Neighbor frame misses denoising data passes: " + filepath;
- return false;
- }
- }
-
- in_neighbors.push_back(std::move(in_neighbor));
- }
-
- return true;
-}
-
-bool DenoiseImage::save_output(const string &out_filepath, string &error)
-{
- /* Save image with identical dimensions, channels and metadata. */
- ImageSpec out_spec = in_spec;
-
- /* Ensure that the output frame contains sample information even if the input didn't. */
- for (int i = 0; i < layers.size(); i++) {
- string name = "cycles." + layers[i].name + ".samples";
- if (!out_spec.find_attribute(name, TypeDesc::STRING)) {
- out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", layers[i].samples));
- }
- }
-
- /* We don't need input anymore at this point, and will possibly
- * overwrite the same file. */
- close_input();
-
- /* Write to temporary file path, so we denoise images in place and don't
- * risk destroying files when something goes wrong in file saving. */
- string extension = OIIO::Filesystem::extension(out_filepath);
- string unique_name = ".denoise-tmp-" + OIIO::Filesystem::unique_path();
- string tmp_filepath = out_filepath + unique_name + extension;
- unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath));
-
- if (!out) {
- error = "Failed to open temporary file " + tmp_filepath + " for writing";
- return false;
- }
-
- /* Open temporary file and write image buffers. */
- if (!out->open(tmp_filepath, out_spec)) {
- error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror();
- return false;
- }
-
- bool ok = true;
- if (!out->write_image(TypeDesc::FLOAT, pixels.data())) {
- error = "Failed to write to file " + tmp_filepath + ": " + out->geterror();
- ok = false;
- }
-
- if (!out->close()) {
- error = "Failed to save to file " + tmp_filepath + ": " + out->geterror();
- ok = false;
- }
-
- out.reset();
-
- /* Copy temporary file to output filepath. */
- string rename_error;
- if (ok && !OIIO::Filesystem::rename(tmp_filepath, out_filepath, rename_error)) {
- error = "Failed to move denoised image to " + out_filepath + ": " + rename_error;
- ok = false;
- }
-
- if (!ok) {
- OIIO::Filesystem::remove(tmp_filepath);
- }
-
- return ok;
-}
-
-/* File pattern handling and outer loop over frames */
-
-DenoiserPipeline::DenoiserPipeline(DeviceInfo &device_info)
-{
- samples_override = 0;
- tile_size = make_int2(64, 64);
-
- num_frames = 0;
-
- /* Initialize task scheduler. */
- TaskScheduler::init();
-
- /* Initialize device. */
- device = Device::create(device_info, stats, profiler, true);
-
- device->load_kernels(KERNEL_FEATURE_DENOISING);
-}
-
-DenoiserPipeline::~DenoiserPipeline()
-{
- delete device;
- TaskScheduler::exit();
-}
-
-bool DenoiserPipeline::run()
-{
- assert(input.size() == output.size());
-
- num_frames = output.size();
-
- for (int frame = 0; frame < num_frames; frame++) {
- /* Skip empty output paths. */
- if (output[frame].empty()) {
- continue;
- }
-
- /* Determine neighbor frame numbers that should be used for filtering. */
- vector<int> neighbor_frames;
- for (int f = frame - params.neighbor_frames; f <= frame + params.neighbor_frames; f++) {
- if (f >= 0 && f < num_frames && f != frame) {
- neighbor_frames.push_back(f);
- }
- }
-
- /* Execute task. */
- DenoiseTask task(device, this, frame, neighbor_frames);
- if (!task.load()) {
- error = task.error;
- return false;
- }
-
- if (!task.exec()) {
- error = task.error;
- return false;
- }
-
- if (!task.save()) {
- error = task.error;
- return false;
- }
-
- task.free();
- }
-
- return true;
-}
-
-CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/render/display_driver.h b/intern/cycles/render/display_driver.h
deleted file mode 100644
index 85f305034d7..00000000000
--- a/intern/cycles/render/display_driver.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "util/util_half.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Display driver for efficient interactive display of renders.
- *
- * Host applications implement this interface for viewport rendering. For best performance, we
- * recommend:
- * - Allocating a texture on the GPU to be interactively updated
- * - Using the graphics interop mechanism to avoid CPU-GPU copying overhead
- * - Using a dedicated or thread-safe graphics API context for updates, to avoid
- * blocking the host application.
- */
-class DisplayDriver {
- public:
- DisplayDriver() = default;
- virtual ~DisplayDriver() = default;
-
- /* Render buffer parameters. */
- struct Params {
- public:
- /* Render resolution, ignoring progressive resolution changes.
- * The texture buffer should be allocated with this size. */
- int2 size = make_int2(0, 0);
-
- /* For border rendering, the full resolution of the render, and the offset within that larger
- * render. */
- int2 full_size = make_int2(0, 0);
- int2 full_offset = make_int2(0, 0);
-
- bool modified(const Params &other) const
- {
- return !(full_offset == other.full_offset && full_size == other.full_size &&
- size == other.size);
- }
- };
-
- /* Update the render from the rendering thread.
- *
- * Cycles periodically updates the render to be displayed. For multithreaded updates with
- * potentially multiple rendering devices, it will call these methods as follows.
- *
- * if (driver.update_begin(params, width, height)) {
- * parallel_for_each(rendering_device) {
- * buffer = driver.map_texture_buffer();
- * if (buffer) {
- * fill(buffer);
- * driver.unmap_texture_buffer();
- * }
- * }
- * driver.update_end();
- * }
- *
- * The parameters may dynamically change due to camera changes in the scene, and resources should
- * be re-allocated accordingly.
- *
- * The width and height passed to update_begin() are the effective render resolution taking into
- * account progressive resolution changes, which may be equal to or smaller than the params.size.
- * For efficiency, changes in this resolution should be handled without re-allocating resources,
- * but rather by using a subset of the full resolution buffer. */
- virtual bool update_begin(const Params &params, int width, int height) = 0;
- virtual void update_end() = 0;
-
- virtual half4 *map_texture_buffer() = 0;
- virtual void unmap_texture_buffer() = 0;
-
- /* Optionally return a handle to a native graphics API texture buffer. If supported,
- * the rendering device may write directly to this buffer instead of calling
- * map_texture_buffer() and unmap_texture_buffer(). */
- class GraphicsInterop {
- public:
- /* Dimensions of the buffer, in pixels. */
- int buffer_width = 0;
- int buffer_height = 0;
-
- /* OpenGL pixel buffer object. */
- int opengl_pbo_id = 0;
-
- /* Clear the entire buffer before doing partial write to it. */
- bool need_clear = false;
- };
-
- virtual GraphicsInterop graphics_interop_get()
- {
- return GraphicsInterop();
- }
-
- /* (De)activate graphics context required for editing or deleting the graphics interop
- * object.
- *
- * For example, destruction of the CUDA object associated with an OpenGL requires the
- * OpenGL context to be active. */
- virtual void graphics_interop_activate(){};
- virtual void graphics_interop_deactivate(){};
-
- /* Clear the display buffer by filling it with zeros. */
- virtual void clear() = 0;
-
- /* Draw the render using the native graphics API.
- *
- * Note that this may be called in parallel to updates. The implementation is responsible for
- * mutex locking or other mechanisms to avoid conflicts.
- *
- * The parameters may have changed since the last update. The implementation is responsible for
- * deciding to skip or adjust render display for such changes.
- *
- * Host application drawing the render buffer should use Session.draw(), which will
- * call this method. */
- virtual void draw(const Params &params) = 0;
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
deleted file mode 100644
index 381f794545a..00000000000
--- a/intern/cycles/render/film.cpp
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/film.h"
-#include "device/device.h"
-#include "render/background.h"
-#include "render/bake.h"
-#include "render/camera.h"
-#include "render/integrator.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/scene.h"
-#include "render/stats.h"
-#include "render/tables.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_foreach.h"
-#include "util/util_math.h"
-#include "util/util_math_cdf.h"
-#include "util/util_time.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Pixel Filter */
-
-static float filter_func_box(float /*v*/, float /*width*/)
-{
- return 1.0f;
-}
-
-static float filter_func_gaussian(float v, float width)
-{
- v *= 6.0f / width;
- return expf(-2.0f * v * v);
-}
-
-static float filter_func_blackman_harris(float v, float width)
-{
- v = M_2PI_F * (v / width + 0.5f);
- return 0.35875f - 0.48829f * cosf(v) + 0.14128f * cosf(2.0f * v) - 0.01168f * cosf(3.0f * v);
-}
-
-static vector<float> filter_table(FilterType type, float width)
-{
- vector<float> filter_table(FILTER_TABLE_SIZE);
- float (*filter_func)(float, float) = NULL;
-
- switch (type) {
- case FILTER_BOX:
- filter_func = filter_func_box;
- break;
- case FILTER_GAUSSIAN:
- filter_func = filter_func_gaussian;
- width *= 3.0f;
- break;
- case FILTER_BLACKMAN_HARRIS:
- filter_func = filter_func_blackman_harris;
- width *= 2.0f;
- break;
- default:
- assert(0);
- }
-
- /* Create importance sampling table. */
-
- /* TODO(sergey): With the even filter table size resolution we can not
- * really make it nice symmetric importance map without sampling full range
- * (meaning, we would need to sample full filter range and not use the
- * make_symmetric argument).
- *
- * Current code matches exactly initial filter table code, but we should
- * consider either making FILTER_TABLE_SIZE odd value or sample full filter.
- */
-
- util_cdf_inverted(FILTER_TABLE_SIZE,
- 0.0f,
- width * 0.5f,
- function_bind(filter_func, _1, width),
- true,
- filter_table);
-
- return filter_table;
-}
-
-/* Film */
-
-NODE_DEFINE(Film)
-{
- NodeType *type = NodeType::add("film", create);
-
- SOCKET_FLOAT(exposure, "Exposure", 0.8f);
- SOCKET_FLOAT(pass_alpha_threshold, "Pass Alpha Threshold", 0.0f);
-
- static NodeEnum filter_enum;
- filter_enum.insert("box", FILTER_BOX);
- filter_enum.insert("gaussian", FILTER_GAUSSIAN);
- filter_enum.insert("blackman_harris", FILTER_BLACKMAN_HARRIS);
-
- SOCKET_ENUM(filter_type, "Filter Type", filter_enum, FILTER_BOX);
- SOCKET_FLOAT(filter_width, "Filter Width", 1.0f);
-
- SOCKET_FLOAT(mist_start, "Mist Start", 0.0f);
- SOCKET_FLOAT(mist_depth, "Mist Depth", 100.0f);
- SOCKET_FLOAT(mist_falloff, "Mist Falloff", 1.0f);
-
- const NodeEnum *pass_type_enum = Pass::get_type_enum();
- SOCKET_ENUM(display_pass, "Display Pass", *pass_type_enum, PASS_COMBINED);
-
- SOCKET_BOOLEAN(show_active_pixels, "Show Active Pixels", false);
-
- static NodeEnum cryptomatte_passes_enum;
- cryptomatte_passes_enum.insert("none", CRYPT_NONE);
- cryptomatte_passes_enum.insert("object", CRYPT_OBJECT);
- cryptomatte_passes_enum.insert("material", CRYPT_MATERIAL);
- cryptomatte_passes_enum.insert("asset", CRYPT_ASSET);
- cryptomatte_passes_enum.insert("accurate", CRYPT_ACCURATE);
- SOCKET_ENUM(cryptomatte_passes, "Cryptomatte Passes", cryptomatte_passes_enum, CRYPT_NONE);
-
- SOCKET_INT(cryptomatte_depth, "Cryptomatte Depth", 0);
-
- SOCKET_BOOLEAN(use_approximate_shadow_catcher, "Use Approximate Shadow Catcher", false);
-
- return type;
-}
-
-Film::Film() : Node(get_node_type()), filter_table_offset_(TABLE_OFFSET_INVALID)
-{
-}
-
-Film::~Film()
-{
-}
-
-void Film::add_default(Scene *scene)
-{
- Pass *pass = scene->create_node<Pass>();
- pass->set_type(PASS_COMBINED);
-}
-
-void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
-{
- if (!is_modified())
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->film.times.add_entry({"update", time});
- }
- });
-
- device_free(device, dscene, scene);
-
- KernelFilm *kfilm = &dscene->data.film;
-
- /* update __data */
- kfilm->exposure = exposure;
- kfilm->pass_alpha_threshold = pass_alpha_threshold;
- kfilm->pass_flag = 0;
-
- kfilm->use_approximate_shadow_catcher = get_use_approximate_shadow_catcher();
-
- kfilm->light_pass_flag = 0;
- kfilm->pass_stride = 0;
-
- /* Mark with PASS_UNUSED to avoid mask test in the kernel. */
- kfilm->pass_background = PASS_UNUSED;
- kfilm->pass_emission = PASS_UNUSED;
- kfilm->pass_ao = PASS_UNUSED;
- kfilm->pass_diffuse_direct = PASS_UNUSED;
- kfilm->pass_diffuse_indirect = PASS_UNUSED;
- kfilm->pass_glossy_direct = PASS_UNUSED;
- kfilm->pass_glossy_indirect = PASS_UNUSED;
- kfilm->pass_transmission_direct = PASS_UNUSED;
- kfilm->pass_transmission_indirect = PASS_UNUSED;
- kfilm->pass_volume_direct = PASS_UNUSED;
- kfilm->pass_volume_indirect = PASS_UNUSED;
- kfilm->pass_volume_direct = PASS_UNUSED;
- kfilm->pass_volume_indirect = PASS_UNUSED;
- kfilm->pass_shadow = PASS_UNUSED;
-
- /* Mark passes as unused so that the kernel knows the pass is inaccessible. */
- kfilm->pass_denoising_normal = PASS_UNUSED;
- kfilm->pass_denoising_albedo = PASS_UNUSED;
- kfilm->pass_sample_count = PASS_UNUSED;
- kfilm->pass_adaptive_aux_buffer = PASS_UNUSED;
- kfilm->pass_shadow_catcher = PASS_UNUSED;
- kfilm->pass_shadow_catcher_sample_count = PASS_UNUSED;
- kfilm->pass_shadow_catcher_matte = PASS_UNUSED;
-
- bool have_cryptomatte = false;
- bool have_aov_color = false;
- bool have_aov_value = false;
-
- for (size_t i = 0; i < scene->passes.size(); i++) {
- const Pass *pass = scene->passes[i];
-
- if (pass->get_type() == PASS_NONE || !pass->is_written()) {
- continue;
- }
-
- if (pass->get_mode() == PassMode::DENOISED) {
- /* Generally we only storing offsets of the noisy passes. The display pass is an exception
- * since it is a read operation and not a write. */
- kfilm->pass_stride += pass->get_info().num_components;
- continue;
- }
-
- /* Can't do motion pass if no motion vectors are available. */
- if (pass->get_type() == PASS_MOTION || pass->get_type() == PASS_MOTION_WEIGHT) {
- if (scene->need_motion() != Scene::MOTION_PASS) {
- kfilm->pass_stride += pass->get_info().num_components;
- continue;
- }
- }
-
- const int pass_flag = (1 << (pass->get_type() % 32));
- if (pass->get_type() <= PASS_CATEGORY_LIGHT_END) {
- kfilm->light_pass_flag |= pass_flag;
- }
- else if (pass->get_type() <= PASS_CATEGORY_DATA_END) {
- kfilm->pass_flag |= pass_flag;
- }
- else {
- assert(pass->get_type() <= PASS_CATEGORY_BAKE_END);
- }
-
- switch (pass->get_type()) {
- case PASS_COMBINED:
- kfilm->pass_combined = kfilm->pass_stride;
- break;
- case PASS_DEPTH:
- kfilm->pass_depth = kfilm->pass_stride;
- break;
- case PASS_NORMAL:
- kfilm->pass_normal = kfilm->pass_stride;
- break;
- case PASS_POSITION:
- kfilm->pass_position = kfilm->pass_stride;
- break;
- case PASS_ROUGHNESS:
- kfilm->pass_roughness = kfilm->pass_stride;
- break;
- case PASS_UV:
- kfilm->pass_uv = kfilm->pass_stride;
- break;
- case PASS_MOTION:
- kfilm->pass_motion = kfilm->pass_stride;
- break;
- case PASS_MOTION_WEIGHT:
- kfilm->pass_motion_weight = kfilm->pass_stride;
- break;
- case PASS_OBJECT_ID:
- kfilm->pass_object_id = kfilm->pass_stride;
- break;
- case PASS_MATERIAL_ID:
- kfilm->pass_material_id = kfilm->pass_stride;
- break;
-
- case PASS_MIST:
- kfilm->pass_mist = kfilm->pass_stride;
- break;
- case PASS_EMISSION:
- kfilm->pass_emission = kfilm->pass_stride;
- break;
- case PASS_BACKGROUND:
- kfilm->pass_background = kfilm->pass_stride;
- break;
- case PASS_AO:
- kfilm->pass_ao = kfilm->pass_stride;
- break;
- case PASS_SHADOW:
- kfilm->pass_shadow = kfilm->pass_stride;
- break;
-
- case PASS_DIFFUSE_COLOR:
- kfilm->pass_diffuse_color = kfilm->pass_stride;
- break;
- case PASS_GLOSSY_COLOR:
- kfilm->pass_glossy_color = kfilm->pass_stride;
- break;
- case PASS_TRANSMISSION_COLOR:
- kfilm->pass_transmission_color = kfilm->pass_stride;
- break;
- case PASS_DIFFUSE_INDIRECT:
- kfilm->pass_diffuse_indirect = kfilm->pass_stride;
- break;
- case PASS_GLOSSY_INDIRECT:
- kfilm->pass_glossy_indirect = kfilm->pass_stride;
- break;
- case PASS_TRANSMISSION_INDIRECT:
- kfilm->pass_transmission_indirect = kfilm->pass_stride;
- break;
- case PASS_VOLUME_INDIRECT:
- kfilm->pass_volume_indirect = kfilm->pass_stride;
- break;
- case PASS_DIFFUSE_DIRECT:
- kfilm->pass_diffuse_direct = kfilm->pass_stride;
- break;
- case PASS_GLOSSY_DIRECT:
- kfilm->pass_glossy_direct = kfilm->pass_stride;
- break;
- case PASS_TRANSMISSION_DIRECT:
- kfilm->pass_transmission_direct = kfilm->pass_stride;
- break;
- case PASS_VOLUME_DIRECT:
- kfilm->pass_volume_direct = kfilm->pass_stride;
- break;
-
- case PASS_BAKE_PRIMITIVE:
- kfilm->pass_bake_primitive = kfilm->pass_stride;
- break;
- case PASS_BAKE_DIFFERENTIAL:
- kfilm->pass_bake_differential = kfilm->pass_stride;
- break;
-
- case PASS_CRYPTOMATTE:
- kfilm->pass_cryptomatte = have_cryptomatte ?
- min(kfilm->pass_cryptomatte, kfilm->pass_stride) :
- kfilm->pass_stride;
- have_cryptomatte = true;
- break;
-
- case PASS_DENOISING_NORMAL:
- kfilm->pass_denoising_normal = kfilm->pass_stride;
- break;
- case PASS_DENOISING_ALBEDO:
- kfilm->pass_denoising_albedo = kfilm->pass_stride;
- break;
-
- case PASS_SHADOW_CATCHER:
- kfilm->pass_shadow_catcher = kfilm->pass_stride;
- break;
- case PASS_SHADOW_CATCHER_SAMPLE_COUNT:
- kfilm->pass_shadow_catcher_sample_count = kfilm->pass_stride;
- break;
- case PASS_SHADOW_CATCHER_MATTE:
- kfilm->pass_shadow_catcher_matte = kfilm->pass_stride;
- break;
-
- case PASS_ADAPTIVE_AUX_BUFFER:
- kfilm->pass_adaptive_aux_buffer = kfilm->pass_stride;
- break;
- case PASS_SAMPLE_COUNT:
- kfilm->pass_sample_count = kfilm->pass_stride;
- break;
-
- case PASS_AOV_COLOR:
- if (!have_aov_color) {
- kfilm->pass_aov_color = kfilm->pass_stride;
- have_aov_color = true;
- }
- break;
- case PASS_AOV_VALUE:
- if (!have_aov_value) {
- kfilm->pass_aov_value = kfilm->pass_stride;
- have_aov_value = true;
- }
- break;
- default:
- assert(false);
- break;
- }
-
- kfilm->pass_stride += pass->get_info().num_components;
- }
-
- /* update filter table */
- vector<float> table = filter_table(filter_type, filter_width);
- scene->lookup_tables->remove_table(&filter_table_offset_);
- filter_table_offset_ = scene->lookup_tables->add_table(dscene, table);
- kfilm->filter_table_offset = (int)filter_table_offset_;
-
- /* mist pass parameters */
- kfilm->mist_start = mist_start;
- kfilm->mist_inv_depth = (mist_depth > 0.0f) ? 1.0f / mist_depth : 0.0f;
- kfilm->mist_falloff = mist_falloff;
-
- kfilm->cryptomatte_passes = cryptomatte_passes;
- kfilm->cryptomatte_depth = cryptomatte_depth;
-
- clear_modified();
-}
-
-void Film::device_free(Device * /*device*/, DeviceScene * /*dscene*/, Scene *scene)
-{
- scene->lookup_tables->remove_table(&filter_table_offset_);
-}
-
-int Film::get_aov_offset(Scene *scene, string name, bool &is_color)
-{
- int offset_color = 0, offset_value = 0;
- foreach (const Pass *pass, scene->passes) {
- if (pass->get_name() == name) {
- if (pass->get_type() == PASS_AOV_VALUE) {
- is_color = false;
- return offset_value;
- }
- else if (pass->get_type() == PASS_AOV_COLOR) {
- is_color = true;
- return offset_color;
- }
- }
-
- if (pass->get_type() == PASS_AOV_VALUE) {
- offset_value += pass->get_info().num_components;
- }
- else if (pass->get_type() == PASS_AOV_COLOR) {
- offset_color += pass->get_info().num_components;
- }
- }
-
- return -1;
-}
-
-void Film::update_passes(Scene *scene, bool add_sample_count_pass)
-{
- const Background *background = scene->background;
- const BakeManager *bake_manager = scene->bake_manager;
- const ObjectManager *object_manager = scene->object_manager;
- Integrator *integrator = scene->integrator;
-
- if (!is_modified() && !object_manager->need_update() && !integrator->is_modified() &&
- !background->is_modified()) {
- return;
- }
-
- /* Remove auto generated passes and recreate them. */
- remove_auto_passes(scene);
-
- /* Display pass for viewport. */
- const PassType display_pass = get_display_pass();
- add_auto_pass(scene, display_pass);
-
- /* Assumption is that a combined pass always exists for now, for example
- * adaptive sampling is always based on a combined pass. But we should
- * try to lift this limitation in the future for faster rendering of
- * individual passes. */
- if (display_pass != PASS_COMBINED) {
- add_auto_pass(scene, PASS_COMBINED);
- }
-
- /* Create passes needed for adaptive sampling. */
- const AdaptiveSampling adaptive_sampling = integrator->get_adaptive_sampling();
- if (adaptive_sampling.use) {
- add_auto_pass(scene, PASS_SAMPLE_COUNT);
- add_auto_pass(scene, PASS_ADAPTIVE_AUX_BUFFER);
- }
-
- /* Create passes needed for denoising. */
- const bool use_denoise = integrator->get_use_denoise();
- if (use_denoise) {
- if (integrator->get_use_denoise_pass_normal()) {
- add_auto_pass(scene, PASS_DENOISING_NORMAL);
- }
- if (integrator->get_use_denoise_pass_albedo()) {
- add_auto_pass(scene, PASS_DENOISING_ALBEDO);
- }
- }
-
- /* Create passes for shadow catcher. */
- if (scene->has_shadow_catcher()) {
- const bool need_background = get_use_approximate_shadow_catcher() &&
- !background->get_transparent();
-
- add_auto_pass(scene, PASS_SHADOW_CATCHER);
- add_auto_pass(scene, PASS_SHADOW_CATCHER_SAMPLE_COUNT);
- add_auto_pass(scene, PASS_SHADOW_CATCHER_MATTE);
-
- if (need_background) {
- add_auto_pass(scene, PASS_BACKGROUND);
- }
- }
- else if (Pass::contains(scene->passes, PASS_SHADOW_CATCHER)) {
- add_auto_pass(scene, PASS_SHADOW_CATCHER);
- add_auto_pass(scene, PASS_SHADOW_CATCHER_SAMPLE_COUNT);
- }
-
- const vector<Pass *> passes_immutable = scene->passes;
- for (const Pass *pass : passes_immutable) {
- const PassInfo info = pass->get_info();
- /* Add utility passes needed to generate some light passes. */
- if (info.divide_type != PASS_NONE) {
- add_auto_pass(scene, info.divide_type);
- }
- if (info.direct_type != PASS_NONE) {
- add_auto_pass(scene, info.direct_type);
- }
- if (info.indirect_type != PASS_NONE) {
- add_auto_pass(scene, info.indirect_type);
- }
-
- /* NOTE: Enable all denoised passes when storage is requested.
- * This way it is possible to tweak denoiser parameters later on. */
- if (info.support_denoise && use_denoise) {
- add_auto_pass(scene, pass->get_type(), PassMode::DENOISED);
- }
- }
-
- if (bake_manager->get_baking()) {
- add_auto_pass(scene, PASS_BAKE_PRIMITIVE, "BakePrimitive");
- add_auto_pass(scene, PASS_BAKE_DIFFERENTIAL, "BakeDifferential");
- }
-
- if (add_sample_count_pass) {
- if (!Pass::contains(scene->passes, PASS_SAMPLE_COUNT)) {
- add_auto_pass(scene, PASS_SAMPLE_COUNT);
- }
- }
-
- /* Remove duplicates and initialize internal pass info. */
- finalize_passes(scene, use_denoise);
-
- /* Flush scene updates. */
- const bool have_uv_pass = Pass::contains(scene->passes, PASS_UV);
- const bool have_motion_pass = Pass::contains(scene->passes, PASS_MOTION);
- const bool have_ao_pass = Pass::contains(scene->passes, PASS_AO);
-
- if (have_uv_pass != prev_have_uv_pass) {
- scene->geometry_manager->tag_update(scene, GeometryManager::UV_PASS_NEEDED);
- foreach (Shader *shader, scene->shaders)
- shader->need_update_uvs = true;
- }
- if (have_motion_pass != prev_have_motion_pass) {
- scene->geometry_manager->tag_update(scene, GeometryManager::MOTION_PASS_NEEDED);
- }
- if (have_ao_pass != prev_have_ao_pass) {
- scene->integrator->tag_update(scene, Integrator::AO_PASS_MODIFIED);
- }
-
- prev_have_uv_pass = have_uv_pass;
- prev_have_motion_pass = have_motion_pass;
- prev_have_ao_pass = have_ao_pass;
-
- tag_modified();
-
- /* Debug logging. */
- if (VLOG_IS_ON(2)) {
- VLOG(2) << "Effective scene passes:";
- for (const Pass *pass : scene->passes) {
- VLOG(2) << "- " << *pass;
- }
- }
-}
-
-void Film::add_auto_pass(Scene *scene, PassType type, const char *name)
-{
- add_auto_pass(scene, type, PassMode::NOISY, name);
-}
-
-void Film::add_auto_pass(Scene *scene, PassType type, PassMode mode, const char *name)
-{
- Pass *pass = new Pass();
- pass->set_type(type);
- pass->set_mode(mode);
- pass->set_name(ustring((name) ? name : ""));
- pass->is_auto_ = true;
-
- pass->set_owner(scene);
- scene->passes.push_back(pass);
-}
-
-void Film::remove_auto_passes(Scene *scene)
-{
- /* Remove all passes which were automatically created. */
- vector<Pass *> new_passes;
-
- for (Pass *pass : scene->passes) {
- if (!pass->is_auto_) {
- new_passes.push_back(pass);
- }
- else {
- delete pass;
- }
- }
-
- scene->passes = new_passes;
-}
-
-static bool compare_pass_order(const Pass *a, const Pass *b)
-{
- const int num_components_a = a->get_info().num_components;
- const int num_components_b = b->get_info().num_components;
-
- if (num_components_a == num_components_b) {
- return (a->get_type() < b->get_type());
- }
-
- return num_components_a > num_components_b;
-}
-
-void Film::finalize_passes(Scene *scene, const bool use_denoise)
-{
- /* Remove duplicate passes. */
- vector<Pass *> new_passes;
-
- for (Pass *pass : scene->passes) {
- /* Disable denoising on passes if denoising is disabled, or if the
- * pass does not support it. */
- pass->set_mode((use_denoise && pass->get_info().support_denoise) ? pass->get_mode() :
- PassMode::NOISY);
-
- /* Merge duplicate passes. */
- bool duplicate_found = false;
- for (Pass *new_pass : new_passes) {
- /* If different type or denoising, don't merge. */
- if (new_pass->get_type() != pass->get_type() || new_pass->get_mode() != pass->get_mode()) {
- continue;
- }
-
- /* If both passes have a name and the names are different, don't merge.
- * If either pass has a name, we'll use that name. */
- if (!pass->get_name().empty() && !new_pass->get_name().empty() &&
- pass->get_name() != new_pass->get_name()) {
- continue;
- }
-
- if (!pass->get_name().empty() && new_pass->get_name().empty()) {
- new_pass->set_name(pass->get_name());
- }
-
- new_pass->is_auto_ &= pass->is_auto_;
- duplicate_found = true;
- break;
- }
-
- if (!duplicate_found) {
- new_passes.push_back(pass);
- }
- else {
- delete pass;
- }
- }
-
- /* Order from by components and type, This is required to for AOVs and cryptomatte passes,
- * which the kernel assumes to be in order. Note this must use stable sort so cryptomatte
- * passes remain in the right order. */
- stable_sort(new_passes.begin(), new_passes.end(), compare_pass_order);
-
- scene->passes = new_passes;
-}
-
-uint Film::get_kernel_features(const Scene *scene) const
-{
- uint kernel_features = 0;
-
- for (const Pass *pass : scene->passes) {
- if (!pass->is_written()) {
- continue;
- }
-
- const PassType pass_type = pass->get_type();
- const PassMode pass_mode = pass->get_mode();
-
- if (pass_mode == PassMode::DENOISED || pass_type == PASS_DENOISING_NORMAL ||
- pass_type == PASS_DENOISING_ALBEDO) {
- kernel_features |= KERNEL_FEATURE_DENOISING;
- }
-
- if (pass_type != PASS_NONE && pass_type != PASS_COMBINED &&
- pass_type <= PASS_CATEGORY_LIGHT_END) {
- kernel_features |= KERNEL_FEATURE_LIGHT_PASSES;
-
- if (pass_type == PASS_SHADOW) {
- kernel_features |= KERNEL_FEATURE_SHADOW_PASS;
- }
- }
- }
-
- return kernel_features;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/film.h b/intern/cycles/render/film.h
deleted file mode 100644
index 5d327353361..00000000000
--- a/intern/cycles/render/film.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __FILM_H__
-#define __FILM_H__
-
-#include "render/pass.h"
-#include "util/util_string.h"
-#include "util/util_vector.h"
-
-#include "kernel/kernel_types.h"
-
-#include "graph/node.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class Scene;
-
-typedef enum FilterType {
- FILTER_BOX,
- FILTER_GAUSSIAN,
- FILTER_BLACKMAN_HARRIS,
-
- FILTER_NUM_TYPES,
-} FilterType;
-
-class Film : public Node {
- public:
- NODE_DECLARE
-
- NODE_SOCKET_API(float, exposure)
- NODE_SOCKET_API(float, pass_alpha_threshold)
-
- NODE_SOCKET_API(PassType, display_pass)
- NODE_SOCKET_API(bool, show_active_pixels)
-
- NODE_SOCKET_API(FilterType, filter_type)
- NODE_SOCKET_API(float, filter_width)
-
- NODE_SOCKET_API(float, mist_start)
- NODE_SOCKET_API(float, mist_depth)
- NODE_SOCKET_API(float, mist_falloff)
-
- NODE_SOCKET_API(CryptomatteType, cryptomatte_passes)
- NODE_SOCKET_API(int, cryptomatte_depth)
-
- /* Approximate shadow catcher pass into its matte pass, so that both artificial objects and
- * shadows can be alpha-overed onto a backdrop. */
- NODE_SOCKET_API(bool, use_approximate_shadow_catcher)
-
- private:
- size_t filter_table_offset_;
- bool prev_have_uv_pass = false;
- bool prev_have_motion_pass = false;
- bool prev_have_ao_pass = false;
-
- public:
- Film();
- ~Film();
-
- /* add default passes to scene */
- static void add_default(Scene *scene);
-
- void device_update(Device *device, DeviceScene *dscene, Scene *scene);
- void device_free(Device *device, DeviceScene *dscene, Scene *scene);
-
- int get_aov_offset(Scene *scene, string name, bool &is_color);
-
- /* Update passes so that they contain all passes required for the configured functionality.
- *
- * If `add_sample_count_pass` is true then the SAMPLE_COUNT pass is ensured to be added. */
- void update_passes(Scene *scene, bool add_sample_count_pass);
-
- uint get_kernel_features(const Scene *scene) const;
-
- private:
- void add_auto_pass(Scene *scene, PassType type, const char *name = nullptr);
- void add_auto_pass(Scene *scene, PassType type, PassMode mode, const char *name = nullptr);
- void remove_auto_passes(Scene *scene);
- void finalize_passes(Scene *scene, const bool use_denoise);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __FILM_H__ */
diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp
deleted file mode 100644
index 5cedab24ceb..00000000000
--- a/intern/cycles/render/geometry.cpp
+++ /dev/null
@@ -1,2074 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bvh/bvh.h"
-#include "bvh/bvh2.h"
-
-#include "device/device.h"
-
-#include "render/attribute.h"
-#include "render/camera.h"
-#include "render/geometry.h"
-#include "render/hair.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/nodes.h"
-#include "render/object.h"
-#include "render/scene.h"
-#include "render/shader.h"
-#include "render/stats.h"
-#include "render/volume.h"
-
-#include "subd/subd_patch_table.h"
-#include "subd/subd_split.h"
-
-#include "kernel/osl/osl_globals.h"
-
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
-#include "util/util_task.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Geometry */
-
-NODE_ABSTRACT_DEFINE(Geometry)
-{
- NodeType *type = NodeType::add("geometry_base", NULL);
-
- SOCKET_UINT(motion_steps, "Motion Steps", 3);
- SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false);
- SOCKET_NODE_ARRAY(used_shaders, "Shaders", Shader::get_node_type());
-
- return type;
-}
-
-Geometry::Geometry(const NodeType *node_type, const Type type)
- : Node(node_type), geometry_type(type), attributes(this, ATTR_PRIM_GEOMETRY)
-{
- need_update_rebuild = false;
- need_update_bvh_for_offset = false;
-
- transform_applied = false;
- transform_negative_scaled = false;
- transform_normal = transform_identity();
- bounds = BoundBox::empty;
-
- has_volume = false;
- has_surface_bssrdf = false;
-
- bvh = NULL;
- attr_map_offset = 0;
- prim_offset = 0;
-}
-
-Geometry::~Geometry()
-{
- dereference_all_used_nodes();
- delete bvh;
-}
-
-void Geometry::clear(bool preserve_shaders)
-{
- if (!preserve_shaders)
- used_shaders.clear();
-
- transform_applied = false;
- transform_negative_scaled = false;
- transform_normal = transform_identity();
- tag_modified();
-}
-
-bool Geometry::need_attribute(Scene *scene, AttributeStandard std)
-{
- if (std == ATTR_STD_NONE)
- return false;
-
- if (scene->need_global_attribute(std))
- return true;
-
- foreach (Node *node, used_shaders) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->attributes.find(std))
- return true;
- }
-
- return false;
-}
-
-bool Geometry::need_attribute(Scene * /*scene*/, ustring name)
-{
- if (name == ustring())
- return false;
-
- foreach (Node *node, used_shaders) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->attributes.find(name))
- return true;
- }
-
- return false;
-}
-
-AttributeRequestSet Geometry::needed_attributes()
-{
- AttributeRequestSet result;
-
- foreach (Node *node, used_shaders) {
- Shader *shader = static_cast<Shader *>(node);
- result.add(shader->attributes);
- }
-
- return result;
-}
-
-float Geometry::motion_time(int step) const
-{
- return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f;
-}
-
-int Geometry::motion_step(float time) const
-{
- if (motion_steps > 1) {
- int attr_step = 0;
-
- for (int step = 0; step < motion_steps; step++) {
- float step_time = motion_time(step);
- if (step_time == time) {
- return attr_step;
- }
-
- /* Center step is stored in a separate attribute. */
- if (step != motion_steps / 2) {
- attr_step++;
- }
- }
- }
-
- return -1;
-}
-
-bool Geometry::need_build_bvh(BVHLayout layout) const
-{
- return is_instanced() || layout == BVH_LAYOUT_OPTIX || layout == BVH_LAYOUT_MULTI_OPTIX ||
- layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE;
-}
-
-bool Geometry::is_instanced() const
-{
- /* Currently we treat subsurface objects as instanced.
- *
- * While it might be not very optimal for ray traversal, it avoids having
- * duplicated BVH in the memory, saving quite some space.
- */
- return !transform_applied || has_surface_bssrdf;
-}
-
-bool Geometry::has_true_displacement() const
-{
- foreach (Node *node, used_shaders) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->has_displacement && shader->get_displacement_method() != DISPLACE_BUMP) {
- return true;
- }
- }
-
- return false;
-}
-
-void Geometry::compute_bvh(
- Device *device, DeviceScene *dscene, SceneParams *params, Progress *progress, int n, int total)
-{
- if (progress->get_cancel())
- return;
-
- compute_bounds();
-
- const BVHLayout bvh_layout = BVHParams::best_bvh_layout(params->bvh_layout,
- device->get_bvh_layout_mask());
- if (need_build_bvh(bvh_layout)) {
- string msg = "Updating Geometry BVH ";
- if (name.empty())
- msg += string_printf("%u/%u", (uint)(n + 1), (uint)total);
- else
- msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total);
-
- Object object;
-
- /* Ensure all visibility bits are set at the geometry level BVH. In
- * the object level BVH is where actual visibility is tested. */
- object.set_is_shadow_catcher(true);
- object.set_visibility(~0);
-
- object.set_geometry(this);
-
- vector<Geometry *> geometry;
- geometry.push_back(this);
- vector<Object *> objects;
- objects.push_back(&object);
-
- if (bvh && !need_update_rebuild) {
- progress->set_status(msg, "Refitting BVH");
-
- bvh->geometry = geometry;
- bvh->objects = objects;
-
- device->build_bvh(bvh, *progress, true);
- }
- else {
- progress->set_status(msg, "Building BVH");
-
- BVHParams bparams;
- bparams.use_spatial_split = params->use_bvh_spatial_split;
- bparams.bvh_layout = bvh_layout;
- bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
- params->use_bvh_unaligned_nodes;
- bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
- bparams.num_motion_curve_steps = params->num_bvh_time_steps;
- bparams.bvh_type = params->bvh_type;
- bparams.curve_subdivisions = params->curve_subdivisions();
-
- delete bvh;
- bvh = BVH::create(bparams, geometry, objects, device);
- MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false);
- }
- }
-
- need_update_rebuild = false;
- need_update_bvh_for_offset = false;
-}
-
-bool Geometry::has_motion_blur() const
-{
- return (use_motion_blur && attributes.find(ATTR_STD_MOTION_VERTEX_POSITION));
-}
-
-bool Geometry::has_voxel_attributes() const
-{
- foreach (const Attribute &attr, attributes.attributes) {
- if (attr.element == ATTR_ELEMENT_VOXEL) {
- return true;
- }
- }
-
- return false;
-}
-
-void Geometry::tag_update(Scene *scene, bool rebuild)
-{
- if (rebuild) {
- need_update_rebuild = true;
- scene->light_manager->tag_update(scene, LightManager::MESH_NEED_REBUILD);
- }
- else {
- foreach (Node *node, used_shaders) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->has_surface_emission) {
- scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED);
- break;
- }
- }
- }
-
- scene->geometry_manager->tag_update(scene, GeometryManager::GEOMETRY_MODIFIED);
-}
-
-void Geometry::tag_bvh_update(bool rebuild)
-{
- tag_modified();
-
- if (rebuild) {
- need_update_rebuild = true;
- }
-}
-
-/* Geometry Manager */
-
-GeometryManager::GeometryManager()
-{
- update_flags = UPDATE_ALL;
- need_flags_update = true;
-}
-
-GeometryManager::~GeometryManager()
-{
-}
-
-void GeometryManager::update_osl_attributes(Device *device,
- Scene *scene,
- vector<AttributeRequestSet> &geom_attributes)
-{
-#ifdef WITH_OSL
- /* for OSL, a hash map is used to lookup the attribute by name. */
- OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
-
- og->object_name_map.clear();
- og->attribute_map.clear();
- og->object_names.clear();
-
- og->attribute_map.resize(scene->objects.size() * ATTR_PRIM_TYPES);
-
- for (size_t i = 0; i < scene->objects.size(); i++) {
- /* set object name to object index map */
- Object *object = scene->objects[i];
- og->object_name_map[object->name] = i;
- og->object_names.push_back(object->name);
-
- /* set object attributes */
- foreach (ParamValue &attr, object->attributes) {
- OSLGlobals::Attribute osl_attr;
-
- osl_attr.type = attr.type();
- osl_attr.desc.element = ATTR_ELEMENT_OBJECT;
- osl_attr.value = attr;
- osl_attr.desc.offset = 0;
- osl_attr.desc.flags = 0;
-
- og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_GEOMETRY][attr.name()] = osl_attr;
- og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][attr.name()] = osl_attr;
- }
-
- /* find geometry attributes */
- size_t j = object->geometry->index;
- assert(j < scene->geometry.size() && scene->geometry[j] == object->geometry);
-
- AttributeRequestSet &attributes = geom_attributes[j];
-
- /* set mesh attributes */
- foreach (AttributeRequest &req, attributes.requests) {
- OSLGlobals::Attribute osl_attr;
-
- if (req.desc.element != ATTR_ELEMENT_NONE) {
- osl_attr.desc = req.desc;
-
- if (req.type == TypeDesc::TypeFloat)
- osl_attr.type = TypeDesc::TypeFloat;
- else if (req.type == TypeDesc::TypeMatrix)
- osl_attr.type = TypeDesc::TypeMatrix;
- else if (req.type == TypeFloat2)
- osl_attr.type = TypeFloat2;
- else if (req.type == TypeRGBA)
- osl_attr.type = TypeRGBA;
- else
- osl_attr.type = TypeDesc::TypeColor;
-
- if (req.std != ATTR_STD_NONE) {
- /* if standard attribute, add lookup by geom: name convention */
- ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
- og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_GEOMETRY][stdname] = osl_attr;
- }
- else if (req.name != ustring()) {
- /* add lookup by geometry attribute name */
- og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_GEOMETRY][req.name] = osl_attr;
- }
- }
-
- if (req.subd_desc.element != ATTR_ELEMENT_NONE) {
- osl_attr.desc = req.subd_desc;
-
- if (req.subd_type == TypeDesc::TypeFloat)
- osl_attr.type = TypeDesc::TypeFloat;
- else if (req.subd_type == TypeDesc::TypeMatrix)
- osl_attr.type = TypeDesc::TypeMatrix;
- else if (req.subd_type == TypeFloat2)
- osl_attr.type = TypeFloat2;
- else if (req.subd_type == TypeRGBA)
- osl_attr.type = TypeRGBA;
- else
- osl_attr.type = TypeDesc::TypeColor;
-
- if (req.std != ATTR_STD_NONE) {
- /* if standard attribute, add lookup by geom: name convention */
- ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
- og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][stdname] = osl_attr;
- }
- else if (req.name != ustring()) {
- /* add lookup by geometry attribute name */
- og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][req.name] = osl_attr;
- }
- }
- }
- }
-#else
- (void)device;
- (void)scene;
- (void)geom_attributes;
-#endif
-}
-
-/* Generate a normal attribute map entry from an attribute descriptor. */
-static void emit_attribute_map_entry(
- uint4 *attr_map, int index, uint id, TypeDesc type, const AttributeDescriptor &desc)
-{
- attr_map[index].x = id;
- attr_map[index].y = desc.element;
- attr_map[index].z = as_uint(desc.offset);
-
- if (type == TypeDesc::TypeFloat)
- attr_map[index].w = NODE_ATTR_FLOAT;
- else if (type == TypeDesc::TypeMatrix)
- attr_map[index].w = NODE_ATTR_MATRIX;
- else if (type == TypeFloat2)
- attr_map[index].w = NODE_ATTR_FLOAT2;
- else if (type == TypeFloat4)
- attr_map[index].w = NODE_ATTR_FLOAT4;
- else if (type == TypeRGBA)
- attr_map[index].w = NODE_ATTR_RGBA;
- else
- attr_map[index].w = NODE_ATTR_FLOAT3;
-
- attr_map[index].w |= desc.flags << 8;
-}
-
-/* Generate an attribute map end marker, optionally including a link to another map.
- * Links are used to connect object attribute maps to mesh attribute maps. */
-static void emit_attribute_map_terminator(uint4 *attr_map, int index, bool chain, uint chain_link)
-{
- for (int j = 0; j < ATTR_PRIM_TYPES; j++) {
- attr_map[index + j].x = ATTR_STD_NONE;
- attr_map[index + j].y = chain; /* link is valid flag */
- attr_map[index + j].z = chain ? chain_link + j : 0; /* link to the correct sub-entry */
- attr_map[index + j].w = 0;
- }
-}
-
-/* Generate all necessary attribute map entries from the attribute request. */
-static void emit_attribute_mapping(
- uint4 *attr_map, int index, Scene *scene, AttributeRequest &req, Geometry *geom)
-{
- uint id;
-
- if (req.std == ATTR_STD_NONE)
- id = scene->shader_manager->get_attribute_id(req.name);
- else
- id = scene->shader_manager->get_attribute_id(req.std);
-
- emit_attribute_map_entry(attr_map, index, id, req.type, req.desc);
-
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (mesh->get_num_subd_faces()) {
- emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc);
- }
- }
-}
-
-void GeometryManager::update_svm_attributes(Device *,
- DeviceScene *dscene,
- Scene *scene,
- vector<AttributeRequestSet> &geom_attributes,
- vector<AttributeRequestSet> &object_attributes)
-{
- /* for SVM, the attributes_map table is used to lookup the offset of an
- * attribute, based on a unique shader attribute id. */
-
- /* compute array stride */
- int attr_map_size = 0;
-
- for (size_t i = 0; i < scene->geometry.size(); i++) {
- Geometry *geom = scene->geometry[i];
- geom->attr_map_offset = attr_map_size;
- attr_map_size += (geom_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
- }
-
- for (size_t i = 0; i < scene->objects.size(); i++) {
- Object *object = scene->objects[i];
-
- /* only allocate a table for the object if it actually has attributes */
- if (object_attributes[i].size() == 0) {
- object->attr_map_offset = 0;
- }
- else {
- object->attr_map_offset = attr_map_size;
- attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
- }
- }
-
- if (attr_map_size == 0)
- return;
-
- if (!dscene->attributes_map.need_realloc()) {
- return;
- }
-
- /* create attribute map */
- uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size);
- memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint));
-
- for (size_t i = 0; i < scene->geometry.size(); i++) {
- Geometry *geom = scene->geometry[i];
- AttributeRequestSet &attributes = geom_attributes[i];
-
- /* set geometry attributes */
- int index = geom->attr_map_offset;
-
- foreach (AttributeRequest &req, attributes.requests) {
- emit_attribute_mapping(attr_map, index, scene, req, geom);
- index += ATTR_PRIM_TYPES;
- }
-
- emit_attribute_map_terminator(attr_map, index, false, 0);
- }
-
- for (size_t i = 0; i < scene->objects.size(); i++) {
- Object *object = scene->objects[i];
- AttributeRequestSet &attributes = object_attributes[i];
-
- /* set object attributes */
- if (attributes.size() > 0) {
- int index = object->attr_map_offset;
-
- foreach (AttributeRequest &req, attributes.requests) {
- emit_attribute_mapping(attr_map, index, scene, req, object->geometry);
- index += ATTR_PRIM_TYPES;
- }
-
- emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset);
- }
- }
-
- /* copy to device */
- dscene->attributes_map.copy_to_device();
-}
-
-static void update_attribute_element_size(Geometry *geom,
- Attribute *mattr,
- AttributePrimitive prim,
- size_t *attr_float_size,
- size_t *attr_float2_size,
- size_t *attr_float3_size,
- size_t *attr_uchar4_size)
-{
- if (mattr) {
- size_t size = mattr->element_size(geom, prim);
-
- if (mattr->element == ATTR_ELEMENT_VOXEL) {
- /* pass */
- }
- else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
- *attr_uchar4_size += size;
- }
- else if (mattr->type == TypeDesc::TypeFloat) {
- *attr_float_size += size;
- }
- else if (mattr->type == TypeFloat2) {
- *attr_float2_size += size;
- }
- else if (mattr->type == TypeDesc::TypeMatrix) {
- *attr_float3_size += size * 4;
- }
- else {
- *attr_float3_size += size;
- }
- }
-}
-
-void GeometryManager::update_attribute_element_offset(Geometry *geom,
- device_vector<float> &attr_float,
- size_t &attr_float_offset,
- device_vector<float2> &attr_float2,
- size_t &attr_float2_offset,
- device_vector<float4> &attr_float3,
- size_t &attr_float3_offset,
- device_vector<uchar4> &attr_uchar4,
- size_t &attr_uchar4_offset,
- Attribute *mattr,
- AttributePrimitive prim,
- TypeDesc &type,
- AttributeDescriptor &desc)
-{
- if (mattr) {
- /* store element and type */
- desc.element = mattr->element;
- desc.flags = mattr->flags;
- type = mattr->type;
-
- /* store attribute data in arrays */
- size_t size = mattr->element_size(geom, prim);
-
- AttributeElement &element = desc.element;
- int &offset = desc.offset;
-
- if (mattr->element == ATTR_ELEMENT_VOXEL) {
- /* store slot in offset value */
- ImageHandle &handle = mattr->data_voxel();
- offset = handle.svm_slot();
- }
- else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
- uchar4 *data = mattr->data_uchar4();
- offset = attr_uchar4_offset;
-
- assert(attr_uchar4.size() >= offset + size);
- if (mattr->modified) {
- for (size_t k = 0; k < size; k++) {
- attr_uchar4[offset + k] = data[k];
- }
- }
- attr_uchar4_offset += size;
- }
- else if (mattr->type == TypeDesc::TypeFloat) {
- float *data = mattr->data_float();
- offset = attr_float_offset;
-
- assert(attr_float.size() >= offset + size);
- if (mattr->modified) {
- for (size_t k = 0; k < size; k++) {
- attr_float[offset + k] = data[k];
- }
- }
- attr_float_offset += size;
- }
- else if (mattr->type == TypeFloat2) {
- float2 *data = mattr->data_float2();
- offset = attr_float2_offset;
-
- assert(attr_float2.size() >= offset + size);
- if (mattr->modified) {
- for (size_t k = 0; k < size; k++) {
- attr_float2[offset + k] = data[k];
- }
- }
- attr_float2_offset += size;
- }
- else if (mattr->type == TypeDesc::TypeMatrix) {
- Transform *tfm = mattr->data_transform();
- offset = attr_float3_offset;
-
- assert(attr_float3.size() >= offset + size * 3);
- if (mattr->modified) {
- for (size_t k = 0; k < size * 3; k++) {
- attr_float3[offset + k] = (&tfm->x)[k];
- }
- }
- attr_float3_offset += size * 3;
- }
- else {
- float4 *data = mattr->data_float4();
- offset = attr_float3_offset;
-
- assert(attr_float3.size() >= offset + size);
- if (mattr->modified) {
- for (size_t k = 0; k < size; k++) {
- attr_float3[offset + k] = data[k];
- }
- }
- attr_float3_offset += size;
- }
-
- /* mesh vertex/curve index is global, not per object, so we sneak
- * a correction for that in here */
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK &&
- desc.flags & ATTR_SUBDIVIDED) {
- /* Indices for subdivided attributes are retrieved
- * from patch table so no need for correction here. */
- }
- else if (element == ATTR_ELEMENT_VERTEX)
- offset -= mesh->vert_offset;
- else if (element == ATTR_ELEMENT_VERTEX_MOTION)
- offset -= mesh->vert_offset;
- else if (element == ATTR_ELEMENT_FACE) {
- if (prim == ATTR_PRIM_GEOMETRY)
- offset -= mesh->prim_offset;
- else
- offset -= mesh->face_offset;
- }
- else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) {
- if (prim == ATTR_PRIM_GEOMETRY)
- offset -= 3 * mesh->prim_offset;
- else
- offset -= mesh->corner_offset;
- }
- }
- else if (geom->is_hair()) {
- Hair *hair = static_cast<Hair *>(geom);
- if (element == ATTR_ELEMENT_CURVE)
- offset -= hair->prim_offset;
- else if (element == ATTR_ELEMENT_CURVE_KEY)
- offset -= hair->curve_key_offset;
- else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION)
- offset -= hair->curve_key_offset;
- }
- }
- else {
- /* attribute not found */
- desc.element = ATTR_ELEMENT_NONE;
- desc.offset = 0;
- }
-}
-
-void GeometryManager::device_update_attributes(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- progress.set_status("Updating Mesh", "Computing attributes");
-
- /* gather per mesh requested attributes. as meshes may have multiple
- * shaders assigned, this merges the requested attributes that have
- * been set per shader by the shader manager */
- vector<AttributeRequestSet> geom_attributes(scene->geometry.size());
-
- for (size_t i = 0; i < scene->geometry.size(); i++) {
- Geometry *geom = scene->geometry[i];
-
- geom->index = i;
- scene->need_global_attributes(geom_attributes[i]);
-
- foreach (Node *node, geom->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
- geom_attributes[i].add(shader->attributes);
- }
-
- if (geom->is_hair() && static_cast<Hair *>(geom)->need_shadow_transparency()) {
- geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY);
- }
- }
-
- /* convert object attributes to use the same data structures as geometry ones */
- vector<AttributeRequestSet> object_attributes(scene->objects.size());
- vector<AttributeSet> object_attribute_values;
-
- object_attribute_values.reserve(scene->objects.size());
-
- for (size_t i = 0; i < scene->objects.size(); i++) {
- Object *object = scene->objects[i];
- Geometry *geom = object->geometry;
- size_t geom_idx = geom->index;
-
- assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom);
-
- object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY));
-
- AttributeRequestSet &geom_requests = geom_attributes[geom_idx];
- AttributeRequestSet &attributes = object_attributes[i];
- AttributeSet &values = object_attribute_values[i];
-
- for (size_t j = 0; j < object->attributes.size(); j++) {
- ParamValue &param = object->attributes[j];
-
- /* add attributes that are requested and not already handled by the mesh */
- if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) {
- attributes.add(param.name());
-
- Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT);
- assert(param.datasize() == attr->buffer.size());
- memcpy(attr->buffer.data(), param.data(), param.datasize());
- }
- }
- }
-
- /* mesh attribute are stored in a single array per data type. here we fill
- * those arrays, and set the offset and element type to create attribute
- * maps next */
-
- /* Pre-allocate attributes to avoid arrays re-allocation which would
- * take 2x of overall attribute memory usage.
- */
- size_t attr_float_size = 0;
- size_t attr_float2_size = 0;
- size_t attr_float3_size = 0;
- size_t attr_uchar4_size = 0;
-
- for (size_t i = 0; i < scene->geometry.size(); i++) {
- Geometry *geom = scene->geometry[i];
- AttributeRequestSet &attributes = geom_attributes[i];
- foreach (AttributeRequest &req, attributes.requests) {
- Attribute *attr = geom->attributes.find(req);
-
- update_attribute_element_size(geom,
- attr,
- ATTR_PRIM_GEOMETRY,
- &attr_float_size,
- &attr_float2_size,
- &attr_float3_size,
- &attr_uchar4_size);
-
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- Attribute *subd_attr = mesh->subd_attributes.find(req);
-
- update_attribute_element_size(mesh,
- subd_attr,
- ATTR_PRIM_SUBD,
- &attr_float_size,
- &attr_float2_size,
- &attr_float3_size,
- &attr_uchar4_size);
- }
- }
- }
-
- for (size_t i = 0; i < scene->objects.size(); i++) {
- Object *object = scene->objects[i];
-
- foreach (Attribute &attr, object_attribute_values[i].attributes) {
- update_attribute_element_size(object->geometry,
- &attr,
- ATTR_PRIM_GEOMETRY,
- &attr_float_size,
- &attr_float2_size,
- &attr_float3_size,
- &attr_uchar4_size);
- }
- }
-
- dscene->attributes_float.alloc(attr_float_size);
- dscene->attributes_float2.alloc(attr_float2_size);
- dscene->attributes_float3.alloc(attr_float3_size);
- dscene->attributes_uchar4.alloc(attr_uchar4_size);
-
- /* The order of those flags needs to match that of AttrKernelDataType. */
- const bool attributes_need_realloc[4] = {
- dscene->attributes_float.need_realloc(),
- dscene->attributes_float2.need_realloc(),
- dscene->attributes_float3.need_realloc(),
- dscene->attributes_uchar4.need_realloc(),
- };
-
- size_t attr_float_offset = 0;
- size_t attr_float2_offset = 0;
- size_t attr_float3_offset = 0;
- size_t attr_uchar4_offset = 0;
-
- /* Fill in attributes. */
- for (size_t i = 0; i < scene->geometry.size(); i++) {
- Geometry *geom = scene->geometry[i];
- AttributeRequestSet &attributes = geom_attributes[i];
-
- /* todo: we now store std and name attributes from requests even if
- * they actually refer to the same mesh attributes, optimize */
- foreach (AttributeRequest &req, attributes.requests) {
- Attribute *attr = geom->attributes.find(req);
-
- if (attr) {
- /* force a copy if we need to reallocate all the data */
- attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
- }
-
- update_attribute_element_offset(geom,
- dscene->attributes_float,
- attr_float_offset,
- dscene->attributes_float2,
- attr_float2_offset,
- dscene->attributes_float3,
- attr_float3_offset,
- dscene->attributes_uchar4,
- attr_uchar4_offset,
- attr,
- ATTR_PRIM_GEOMETRY,
- req.type,
- req.desc);
-
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- Attribute *subd_attr = mesh->subd_attributes.find(req);
-
- if (subd_attr) {
- /* force a copy if we need to reallocate all the data */
- subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)];
- }
-
- update_attribute_element_offset(mesh,
- dscene->attributes_float,
- attr_float_offset,
- dscene->attributes_float2,
- attr_float2_offset,
- dscene->attributes_float3,
- attr_float3_offset,
- dscene->attributes_uchar4,
- attr_uchar4_offset,
- subd_attr,
- ATTR_PRIM_SUBD,
- req.subd_type,
- req.subd_desc);
- }
-
- if (progress.get_cancel())
- return;
- }
- }
-
- for (size_t i = 0; i < scene->objects.size(); i++) {
- Object *object = scene->objects[i];
- AttributeRequestSet &attributes = object_attributes[i];
- AttributeSet &values = object_attribute_values[i];
-
- foreach (AttributeRequest &req, attributes.requests) {
- Attribute *attr = values.find(req);
-
- if (attr) {
- attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
- }
-
- update_attribute_element_offset(object->geometry,
- dscene->attributes_float,
- attr_float_offset,
- dscene->attributes_float2,
- attr_float2_offset,
- dscene->attributes_float3,
- attr_float3_offset,
- dscene->attributes_uchar4,
- attr_uchar4_offset,
- attr,
- ATTR_PRIM_GEOMETRY,
- req.type,
- req.desc);
-
- /* object attributes don't care about subdivision */
- req.subd_type = req.type;
- req.subd_desc = req.desc;
-
- if (progress.get_cancel())
- return;
- }
- }
-
- /* create attribute lookup maps */
- if (scene->shader_manager->use_osl())
- update_osl_attributes(device, scene, geom_attributes);
-
- update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes);
-
- if (progress.get_cancel())
- return;
-
- /* copy to device */
- progress.set_status("Updating Mesh", "Copying Attributes to device");
-
- dscene->attributes_float.copy_to_device_if_modified();
- dscene->attributes_float2.copy_to_device_if_modified();
- dscene->attributes_float3.copy_to_device_if_modified();
- dscene->attributes_uchar4.copy_to_device_if_modified();
-
- if (progress.get_cancel())
- return;
-
- /* After mesh attributes and patch tables have been copied to device memory,
- * we need to update offsets in the objects. */
- scene->object_manager->device_update_mesh_offsets(device, dscene, scene);
-}
-
-void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout)
-{
- size_t vert_size = 0;
- size_t tri_size = 0;
-
- size_t curve_size = 0;
- size_t curve_key_size = 0;
- size_t curve_segment_size = 0;
-
- size_t patch_size = 0;
- size_t face_size = 0;
- size_t corner_size = 0;
-
- foreach (Geometry *geom, scene->geometry) {
- bool prim_offset_changed = false;
-
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
-
- prim_offset_changed = (mesh->prim_offset != tri_size);
-
- mesh->vert_offset = vert_size;
- mesh->prim_offset = tri_size;
-
- mesh->patch_offset = patch_size;
- mesh->face_offset = face_size;
- mesh->corner_offset = corner_size;
-
- vert_size += mesh->verts.size();
- tri_size += mesh->num_triangles();
-
- if (mesh->get_num_subd_faces()) {
- Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1);
- patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
-
- /* patch tables are stored in same array so include them in patch_size */
- if (mesh->patch_table) {
- mesh->patch_table_offset = patch_size;
- patch_size += mesh->patch_table->total_size();
- }
- }
-
- face_size += mesh->get_num_subd_faces();
- corner_size += mesh->subd_face_corners.size();
- }
- else if (geom->is_hair()) {
- Hair *hair = static_cast<Hair *>(geom);
-
- prim_offset_changed = (hair->curve_segment_offset != curve_segment_size);
- hair->curve_key_offset = curve_key_size;
- hair->curve_segment_offset = curve_segment_size;
- hair->prim_offset = curve_size;
-
- curve_size += hair->num_curves();
- curve_key_size += hair->get_curve_keys().size();
- curve_segment_size += hair->num_segments();
- }
-
- if (prim_offset_changed) {
- /* Need to rebuild BVH in OptiX, since refit only allows modified mesh data there */
- const bool has_optix_bvh = bvh_layout == BVH_LAYOUT_OPTIX ||
- bvh_layout == BVH_LAYOUT_MULTI_OPTIX ||
- bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE;
- geom->need_update_rebuild |= has_optix_bvh;
- geom->need_update_bvh_for_offset = true;
- }
- }
-}
-
-void GeometryManager::device_update_mesh(Device *,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- /* Count. */
- size_t vert_size = 0;
- size_t tri_size = 0;
-
- size_t curve_key_size = 0;
- size_t curve_size = 0;
- size_t curve_segment_size = 0;
-
- size_t patch_size = 0;
-
- foreach (Geometry *geom, scene->geometry) {
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
-
- vert_size += mesh->verts.size();
- tri_size += mesh->num_triangles();
-
- if (mesh->get_num_subd_faces()) {
- Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1);
- patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
-
- /* patch tables are stored in same array so include them in patch_size */
- if (mesh->patch_table) {
- mesh->patch_table_offset = patch_size;
- patch_size += mesh->patch_table->total_size();
- }
- }
- }
- else if (geom->is_hair()) {
- Hair *hair = static_cast<Hair *>(geom);
-
- curve_key_size += hair->get_curve_keys().size();
- curve_size += hair->num_curves();
- curve_segment_size += hair->num_segments();
- }
- }
-
- /* Fill in all the arrays. */
- if (tri_size != 0) {
- /* normals */
- progress.set_status("Updating Mesh", "Computing normals");
-
- float4 *tri_verts = dscene->tri_verts.alloc(tri_size * 3);
- uint *tri_shader = dscene->tri_shader.alloc(tri_size);
- float4 *vnormal = dscene->tri_vnormal.alloc(vert_size);
- uint4 *tri_vindex = dscene->tri_vindex.alloc(tri_size);
- uint *tri_patch = dscene->tri_patch.alloc(tri_size);
- float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
-
- const bool copy_all_data = dscene->tri_shader.need_realloc() ||
- dscene->tri_vindex.need_realloc() ||
- dscene->tri_vnormal.need_realloc() ||
- dscene->tri_patch.need_realloc() ||
- dscene->tri_patch_uv.need_realloc();
-
- foreach (Geometry *geom, scene->geometry) {
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
-
- if (mesh->shader_is_modified() || mesh->smooth_is_modified() ||
- mesh->triangles_is_modified() || copy_all_data) {
- mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
- }
-
- if (mesh->verts_is_modified() || copy_all_data) {
- mesh->pack_normals(&vnormal[mesh->vert_offset]);
- }
-
- if (mesh->verts_is_modified() || mesh->triangles_is_modified() ||
- mesh->vert_patch_uv_is_modified() || copy_all_data) {
- mesh->pack_verts(&tri_verts[mesh->prim_offset * 3],
- &tri_vindex[mesh->prim_offset],
- &tri_patch[mesh->prim_offset],
- &tri_patch_uv[mesh->vert_offset]);
- }
-
- if (progress.get_cancel())
- return;
- }
- }
-
- /* vertex coordinates */
- progress.set_status("Updating Mesh", "Copying Mesh to device");
-
- dscene->tri_verts.copy_to_device_if_modified();
- dscene->tri_shader.copy_to_device_if_modified();
- dscene->tri_vnormal.copy_to_device_if_modified();
- dscene->tri_vindex.copy_to_device_if_modified();
- dscene->tri_patch.copy_to_device_if_modified();
- dscene->tri_patch_uv.copy_to_device_if_modified();
- }
-
- if (curve_segment_size != 0) {
- progress.set_status("Updating Mesh", "Copying Curves to device");
-
- float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size);
- KernelCurve *curves = dscene->curves.alloc(curve_size);
- KernelCurveSegment *curve_segments = dscene->curve_segments.alloc(curve_segment_size);
-
- const bool copy_all_data = dscene->curve_keys.need_realloc() ||
- dscene->curves.need_realloc() ||
- dscene->curve_segments.need_realloc();
-
- foreach (Geometry *geom, scene->geometry) {
- if (geom->is_hair()) {
- Hair *hair = static_cast<Hair *>(geom);
-
- bool curve_keys_co_modified = hair->curve_radius_is_modified() ||
- hair->curve_keys_is_modified();
- bool curve_data_modified = hair->curve_shader_is_modified() ||
- hair->curve_first_key_is_modified();
-
- if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) {
- continue;
- }
-
- hair->pack_curves(scene,
- &curve_keys[hair->curve_key_offset],
- &curves[hair->prim_offset],
- &curve_segments[hair->curve_segment_offset]);
- if (progress.get_cancel())
- return;
- }
- }
-
- dscene->curve_keys.copy_to_device_if_modified();
- dscene->curves.copy_to_device_if_modified();
- dscene->curve_segments.copy_to_device_if_modified();
- }
-
- if (patch_size != 0 && dscene->patches.need_realloc()) {
- progress.set_status("Updating Mesh", "Copying Patches to device");
-
- uint *patch_data = dscene->patches.alloc(patch_size);
-
- foreach (Geometry *geom, scene->geometry) {
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- mesh->pack_patches(&patch_data[mesh->patch_offset]);
-
- if (mesh->patch_table) {
- mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset],
- mesh->patch_table_offset);
- }
-
- if (progress.get_cancel())
- return;
- }
- }
-
- dscene->patches.copy_to_device();
- }
-}
-
-void GeometryManager::device_update_bvh(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- /* bvh build */
- progress.set_status("Updating Scene BVH", "Building");
-
- BVHParams bparams;
- bparams.top_level = true;
- bparams.bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
- device->get_bvh_layout_mask());
- bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
- bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
- scene->params.use_bvh_unaligned_nodes;
- bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps;
- bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps;
- bparams.bvh_type = scene->params.bvh_type;
- bparams.curve_subdivisions = scene->params.curve_subdivisions();
-
- VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
-
- const bool can_refit = scene->bvh != nullptr &&
- (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX);
-
- BVH *bvh = scene->bvh;
- if (!scene->bvh) {
- bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
- }
-
- device->build_bvh(bvh, progress, can_refit);
-
- if (progress.get_cancel()) {
- return;
- }
-
- const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2);
-
- PackedBVH pack;
- if (has_bvh2_layout) {
- pack = std::move(static_cast<BVH2 *>(bvh)->pack);
- }
- else {
- pack.root_index = -1;
- }
-
- /* copy to device */
- progress.set_status("Updating Scene BVH", "Copying BVH to device");
-
- /* When using BVH2, we always have to copy/update the data as its layout is dependent on the
- * BVH's leaf nodes which may be different when the objects or vertices move. */
-
- if (pack.nodes.size()) {
- dscene->bvh_nodes.steal_data(pack.nodes);
- dscene->bvh_nodes.copy_to_device();
- }
- if (pack.leaf_nodes.size()) {
- dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes);
- dscene->bvh_leaf_nodes.copy_to_device();
- }
- if (pack.object_node.size()) {
- dscene->object_node.steal_data(pack.object_node);
- dscene->object_node.copy_to_device();
- }
- if (pack.prim_type.size()) {
- dscene->prim_type.steal_data(pack.prim_type);
- dscene->prim_type.copy_to_device();
- }
- if (pack.prim_visibility.size()) {
- dscene->prim_visibility.steal_data(pack.prim_visibility);
- dscene->prim_visibility.copy_to_device();
- }
- if (pack.prim_index.size()) {
- dscene->prim_index.steal_data(pack.prim_index);
- dscene->prim_index.copy_to_device();
- }
- if (pack.prim_object.size()) {
- dscene->prim_object.steal_data(pack.prim_object);
- dscene->prim_object.copy_to_device();
- }
- if (pack.prim_time.size()) {
- dscene->prim_time.steal_data(pack.prim_time);
- dscene->prim_time.copy_to_device();
- }
-
- dscene->data.bvh.root = pack.root_index;
- dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
- dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions();
- /* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */
- dscene->data.bvh.scene = 0;
-}
-
-/* Set of flags used to help determining what data has been modified or needs reallocation, so we
- * can decide which device data to free or update. */
-enum {
- DEVICE_CURVE_DATA_MODIFIED = (1 << 0),
- DEVICE_MESH_DATA_MODIFIED = (1 << 1),
-
- ATTR_FLOAT_MODIFIED = (1 << 2),
- ATTR_FLOAT2_MODIFIED = (1 << 3),
- ATTR_FLOAT3_MODIFIED = (1 << 4),
- ATTR_UCHAR4_MODIFIED = (1 << 5),
-
- CURVE_DATA_NEED_REALLOC = (1 << 6),
- MESH_DATA_NEED_REALLOC = (1 << 7),
-
- ATTR_FLOAT_NEEDS_REALLOC = (1 << 8),
- ATTR_FLOAT2_NEEDS_REALLOC = (1 << 9),
- ATTR_FLOAT3_NEEDS_REALLOC = (1 << 10),
- ATTR_UCHAR4_NEEDS_REALLOC = (1 << 11),
-
- ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
- ATTR_FLOAT3_NEEDS_REALLOC | ATTR_UCHAR4_NEEDS_REALLOC),
- DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
- DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
-};
-
-static void update_device_flags_attribute(uint32_t &device_update_flags,
- const AttributeSet &attributes)
-{
- foreach (const Attribute &attr, attributes.attributes) {
- if (!attr.modified) {
- continue;
- }
-
- AttrKernelDataType kernel_type = Attribute::kernel_type(attr);
-
- switch (kernel_type) {
- case AttrKernelDataType::FLOAT: {
- device_update_flags |= ATTR_FLOAT_MODIFIED;
- break;
- }
- case AttrKernelDataType::FLOAT2: {
- device_update_flags |= ATTR_FLOAT2_MODIFIED;
- break;
- }
- case AttrKernelDataType::FLOAT3: {
- device_update_flags |= ATTR_FLOAT3_MODIFIED;
- break;
- }
- case AttrKernelDataType::UCHAR4: {
- device_update_flags |= ATTR_UCHAR4_MODIFIED;
- break;
- }
- }
- }
-}
-
-static void update_attribute_realloc_flags(uint32_t &device_update_flags,
- const AttributeSet &attributes)
-{
- if (attributes.modified(AttrKernelDataType::FLOAT)) {
- device_update_flags |= ATTR_FLOAT_NEEDS_REALLOC;
- }
- if (attributes.modified(AttrKernelDataType::FLOAT2)) {
- device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC;
- }
- if (attributes.modified(AttrKernelDataType::FLOAT3)) {
- device_update_flags |= ATTR_FLOAT3_NEEDS_REALLOC;
- }
- if (attributes.modified(AttrKernelDataType::UCHAR4)) {
- device_update_flags |= ATTR_UCHAR4_NEEDS_REALLOC;
- }
-}
-
-void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress)
-{
- if (!need_update() && !need_flags_update) {
- return;
- }
-
- uint32_t device_update_flags = 0;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry({"device_update_preprocess", time});
- }
- });
-
- progress.set_status("Updating Meshes Flags");
-
- /* Update flags. */
- bool volume_images_updated = false;
-
- foreach (Geometry *geom, scene->geometry) {
- geom->has_volume = false;
-
- update_attribute_realloc_flags(device_update_flags, geom->attributes);
-
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- update_attribute_realloc_flags(device_update_flags, mesh->subd_attributes);
- }
-
- foreach (Node *node, geom->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->has_volume) {
- geom->has_volume = true;
- }
-
- if (shader->has_surface_bssrdf) {
- geom->has_surface_bssrdf = true;
- }
-
- if (shader->need_update_uvs) {
- device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC;
-
- /* Attributes might need to be tessellated if added. */
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (mesh->need_tesselation()) {
- mesh->tag_modified();
- }
- }
- }
-
- if (shader->need_update_attribute) {
- device_update_flags |= ATTRS_NEED_REALLOC;
-
- /* Attributes might need to be tessellated if added. */
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (mesh->need_tesselation()) {
- mesh->tag_modified();
- }
- }
- }
-
- if (shader->need_update_displacement) {
- /* tag displacement related sockets as modified */
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- mesh->tag_verts_modified();
- mesh->tag_subd_dicing_rate_modified();
- mesh->tag_subd_max_level_modified();
- mesh->tag_subd_objecttoworld_modified();
-
- device_update_flags |= ATTRS_NEED_REALLOC;
- }
- }
- }
-
- /* only check for modified attributes if we do not need to reallocate them already */
- if ((device_update_flags & ATTRS_NEED_REALLOC) == 0) {
- update_device_flags_attribute(device_update_flags, geom->attributes);
- /* don't check for subd_attributes, as if they were modified, we would need to reallocate
- * anyway */
- }
-
- /* Re-create volume mesh if we will rebuild or refit the BVH. Note we
- * should only do it in that case, otherwise the BVH and mesh can go
- * out of sync. */
- if (geom->is_modified() && geom->geometry_type == Geometry::VOLUME) {
- /* Create volume meshes if there is voxel data. */
- if (!volume_images_updated) {
- progress.set_status("Updating Meshes Volume Bounds");
- device_update_volume_images(device, scene, progress);
- volume_images_updated = true;
- }
-
- Volume *volume = static_cast<Volume *>(geom);
- create_volume_mesh(volume, progress);
-
- /* always reallocate when we have a volume, as we need to rebuild the BVH */
- device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
- }
-
- if (geom->is_hair()) {
- /* Set curve shape, still a global scene setting for now. */
- Hair *hair = static_cast<Hair *>(geom);
- hair->curve_shape = scene->params.hair_shape;
-
- if (hair->need_update_rebuild) {
- device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
- }
- else if (hair->is_modified()) {
- device_update_flags |= DEVICE_CURVE_DATA_MODIFIED;
- }
- }
-
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
-
- if (mesh->need_update_rebuild) {
- device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
- }
- else if (mesh->is_modified()) {
- device_update_flags |= DEVICE_MESH_DATA_MODIFIED;
- }
- }
- }
-
- if (update_flags & (MESH_ADDED | MESH_REMOVED)) {
- device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
- }
-
- if (update_flags & (HAIR_ADDED | HAIR_REMOVED)) {
- device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
- }
-
- /* tag the device arrays for reallocation or modification */
- DeviceScene *dscene = &scene->dscene;
-
- if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC)) {
- delete scene->bvh;
- scene->bvh = nullptr;
-
- dscene->bvh_nodes.tag_realloc();
- dscene->bvh_leaf_nodes.tag_realloc();
- dscene->object_node.tag_realloc();
- dscene->prim_type.tag_realloc();
- dscene->prim_visibility.tag_realloc();
- dscene->prim_index.tag_realloc();
- dscene->prim_object.tag_realloc();
- dscene->prim_time.tag_realloc();
-
- if (device_update_flags & DEVICE_MESH_DATA_NEEDS_REALLOC) {
- dscene->tri_verts.tag_realloc();
- dscene->tri_vnormal.tag_realloc();
- dscene->tri_vindex.tag_realloc();
- dscene->tri_patch.tag_realloc();
- dscene->tri_patch_uv.tag_realloc();
- dscene->tri_shader.tag_realloc();
- dscene->patches.tag_realloc();
- }
-
- if (device_update_flags & DEVICE_CURVE_DATA_NEEDS_REALLOC) {
- dscene->curves.tag_realloc();
- dscene->curve_keys.tag_realloc();
- dscene->curve_segments.tag_realloc();
- }
- }
-
- if ((update_flags & VISIBILITY_MODIFIED) != 0) {
- dscene->prim_visibility.tag_modified();
- }
-
- if (device_update_flags & ATTR_FLOAT_NEEDS_REALLOC) {
- dscene->attributes_map.tag_realloc();
- dscene->attributes_float.tag_realloc();
- }
- else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
- dscene->attributes_float.tag_modified();
- }
-
- if (device_update_flags & ATTR_FLOAT2_NEEDS_REALLOC) {
- dscene->attributes_map.tag_realloc();
- dscene->attributes_float2.tag_realloc();
- }
- else if (device_update_flags & ATTR_FLOAT2_MODIFIED) {
- dscene->attributes_float2.tag_modified();
- }
-
- if (device_update_flags & ATTR_FLOAT3_NEEDS_REALLOC) {
- dscene->attributes_map.tag_realloc();
- dscene->attributes_float3.tag_realloc();
- }
- else if (device_update_flags & ATTR_FLOAT3_MODIFIED) {
- dscene->attributes_float3.tag_modified();
- }
-
- if (device_update_flags & ATTR_UCHAR4_NEEDS_REALLOC) {
- dscene->attributes_map.tag_realloc();
- dscene->attributes_uchar4.tag_realloc();
- }
- else if (device_update_flags & ATTR_UCHAR4_MODIFIED) {
- dscene->attributes_uchar4.tag_modified();
- }
-
- if (device_update_flags & DEVICE_MESH_DATA_MODIFIED) {
- /* if anything else than vertices or shaders are modified, we would need to reallocate, so
- * these are the only arrays that can be updated */
- dscene->tri_verts.tag_modified();
- dscene->tri_vnormal.tag_modified();
- dscene->tri_shader.tag_modified();
- }
-
- if (device_update_flags & DEVICE_CURVE_DATA_MODIFIED) {
- dscene->curve_keys.tag_modified();
- dscene->curves.tag_modified();
- dscene->curve_segments.tag_modified();
- }
-
- need_flags_update = false;
-}
-
-void GeometryManager::device_update_displacement_images(Device *device,
- Scene *scene,
- Progress &progress)
-{
- progress.set_status("Updating Displacement Images");
- TaskPool pool;
- ImageManager *image_manager = scene->image_manager;
- set<int> bump_images;
- foreach (Geometry *geom, scene->geometry) {
- if (geom->is_modified()) {
- foreach (Node *node, geom->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
- if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
- continue;
- }
- foreach (ShaderNode *node, shader->graph->nodes) {
- if (node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) {
- continue;
- }
-
- ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode *>(node);
- for (int i = 0; i < image_node->handle.num_tiles(); i++) {
- const int slot = image_node->handle.svm_slot(i);
- if (slot != -1) {
- bump_images.insert(slot);
- }
- }
- }
- }
- }
- }
- foreach (int slot, bump_images) {
- pool.push(function_bind(
- &ImageManager::device_update_slot, image_manager, device, scene, slot, &progress));
- }
- pool.wait_work();
-}
-
-void GeometryManager::device_update_volume_images(Device *device, Scene *scene, Progress &progress)
-{
- progress.set_status("Updating Volume Images");
- TaskPool pool;
- ImageManager *image_manager = scene->image_manager;
- set<int> volume_images;
-
- foreach (Geometry *geom, scene->geometry) {
- if (!geom->is_modified()) {
- continue;
- }
-
- foreach (Attribute &attr, geom->attributes.attributes) {
- if (attr.element != ATTR_ELEMENT_VOXEL) {
- continue;
- }
-
- ImageHandle &handle = attr.data_voxel();
- /* We can build directly from OpenVDB data structures, no need to
- * load such images early. */
- if (!handle.vdb_loader()) {
- const int slot = handle.svm_slot();
- if (slot != -1) {
- volume_images.insert(slot);
- }
- }
- }
- }
-
- foreach (int slot, volume_images) {
- pool.push(function_bind(
- &ImageManager::device_update_slot, image_manager, device, scene, slot, &progress));
- }
- pool.wait_work();
-}
-
-void GeometryManager::device_update(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- if (!need_update())
- return;
-
- VLOG(1) << "Total " << scene->geometry.size() << " meshes.";
-
- bool true_displacement_used = false;
- bool curve_shadow_transparency_used = false;
- size_t total_tess_needed = 0;
-
- {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry({"device_update (normals)", time});
- }
- });
-
- foreach (Geometry *geom, scene->geometry) {
- if (geom->is_modified()) {
- if ((geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME)) {
- Mesh *mesh = static_cast<Mesh *>(geom);
-
- /* Update normals. */
- mesh->add_face_normals();
- mesh->add_vertex_normals();
-
- if (mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) {
- mesh->add_undisplaced();
- }
-
- /* Test if we need tessellation. */
- if (mesh->need_tesselation()) {
- total_tess_needed++;
- }
-
- /* Test if we need displacement. */
- if (mesh->has_true_displacement()) {
- true_displacement_used = true;
- }
- }
- else if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- if (hair->need_shadow_transparency()) {
- curve_shadow_transparency_used = true;
- }
- }
-
- if (progress.get_cancel()) {
- return;
- }
- }
- }
- }
-
- if (progress.get_cancel()) {
- return;
- }
-
- /* Tessellate meshes that are using subdivision */
- if (total_tess_needed) {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry(
- {"device_update (adaptive subdivision)", time});
- }
- });
-
- Camera *dicing_camera = scene->dicing_camera;
- dicing_camera->set_screen_size(dicing_camera->get_full_width(),
- dicing_camera->get_full_height());
- dicing_camera->update(scene);
-
- size_t i = 0;
- foreach (Geometry *geom, scene->geometry) {
- if (!(geom->is_modified() && geom->is_mesh())) {
- continue;
- }
-
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (mesh->need_tesselation()) {
- string msg = "Tessellating ";
- if (mesh->name == "")
- msg += string_printf("%u/%u", (uint)(i + 1), (uint)total_tess_needed);
- else
- msg += string_printf(
- "%s %u/%u", mesh->name.c_str(), (uint)(i + 1), (uint)total_tess_needed);
-
- progress.set_status("Updating Mesh", msg);
-
- mesh->subd_params->camera = dicing_camera;
- DiagSplit dsplit(*mesh->subd_params);
- mesh->tessellate(&dsplit);
-
- i++;
-
- if (progress.get_cancel()) {
- return;
- }
- }
- }
-
- if (progress.get_cancel()) {
- return;
- }
- }
-
- /* Update images needed for true displacement. */
- bool old_need_object_flags_update = false;
- if (true_displacement_used || curve_shadow_transparency_used) {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry(
- {"device_update (displacement: load images)", time});
- }
- });
- device_update_displacement_images(device, scene, progress);
- old_need_object_flags_update = scene->object_manager->need_flags_update;
- scene->object_manager->device_update_flags(device, dscene, scene, progress, false);
- }
-
- /* Device update. */
- device_free(device, dscene, false);
-
- const BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
- device->get_bvh_layout_mask());
- mesh_calc_offset(scene, bvh_layout);
- if (true_displacement_used || curve_shadow_transparency_used) {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry(
- {"device_update (displacement: copy meshes to device)", time});
- }
- });
- device_update_mesh(device, dscene, scene, progress);
- }
- if (progress.get_cancel()) {
- return;
- }
-
- {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry({"device_update (attributes)", time});
- }
- });
- device_update_attributes(device, dscene, scene, progress);
- if (progress.get_cancel()) {
- return;
- }
- }
-
- /* Update displacement and hair shadow transparency. */
- bool displacement_done = false;
- bool curve_shadow_transparency_done = false;
- size_t num_bvh = 0;
-
- {
- /* Copy constant data needed by shader evaluation. */
- device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry({"device_update (displacement)", time});
- }
- });
-
- foreach (Geometry *geom, scene->geometry) {
- if (geom->is_modified()) {
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (displace(device, scene, mesh, progress)) {
- displacement_done = true;
- }
- }
- else if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- if (hair->update_shadow_transparency(device, scene, progress)) {
- curve_shadow_transparency_done = true;
- }
- }
- }
-
- if (geom->is_modified() || geom->need_update_bvh_for_offset) {
- if (geom->need_build_bvh(bvh_layout)) {
- num_bvh++;
- }
- }
-
- if (progress.get_cancel()) {
- return;
- }
- }
- }
-
- if (progress.get_cancel()) {
- return;
- }
-
- /* Device re-update after displacement. */
- if (displacement_done || curve_shadow_transparency_done) {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry(
- {"device_update (displacement: attributes)", time});
- }
- });
- device_free(device, dscene, false);
-
- device_update_attributes(device, dscene, scene, progress);
- if (progress.get_cancel()) {
- return;
- }
- }
-
- /* Update the BVH even when there is no geometry so the kernel's BVH data is still valid,
- * especially when removing all of the objects during interactive renders.
- * Also update the BVH if the transformations change, we cannot rely on tagging the Geometry
- * as modified in this case, as we may accumulate displacement if the vertices do not also
- * change. */
- bool need_update_scene_bvh = (scene->bvh == nullptr ||
- (update_flags & (TRANSFORM_MODIFIED | VISIBILITY_MODIFIED)) != 0);
- {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry({"device_update (build object BVHs)", time});
- }
- });
- TaskPool pool;
-
- size_t i = 0;
- foreach (Geometry *geom, scene->geometry) {
- if (geom->is_modified() || geom->need_update_bvh_for_offset) {
- need_update_scene_bvh = true;
- pool.push(function_bind(
- &Geometry::compute_bvh, geom, device, dscene, &scene->params, &progress, i, num_bvh));
- if (geom->need_build_bvh(bvh_layout)) {
- i++;
- }
- }
- }
-
- TaskPool::Summary summary;
- pool.wait_work(&summary);
- VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report();
- }
-
- foreach (Shader *shader, scene->shaders) {
- shader->need_update_uvs = false;
- shader->need_update_attribute = false;
- shader->need_update_displacement = false;
- }
-
- Scene::MotionType need_motion = scene->need_motion();
- bool motion_blur = need_motion == Scene::MOTION_BLUR;
-
- /* Update objects. */
- {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry({"device_update (compute bounds)", time});
- }
- });
- foreach (Object *object, scene->objects) {
- object->compute_bounds(motion_blur);
- }
- }
-
- if (progress.get_cancel()) {
- return;
- }
-
- if (need_update_scene_bvh) {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry({"device_update (build scene BVH)", time});
- }
- });
- device_update_bvh(device, dscene, scene, progress);
- if (progress.get_cancel()) {
- return;
- }
- }
-
- /* Always set BVH layout again after displacement where it was set to none,
- * to avoid ray-tracing at that stage. */
- dscene->data.bvh.bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
- device->get_bvh_layout_mask());
-
- {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->geometry.times.add_entry(
- {"device_update (copy meshes to device)", time});
- }
- });
- device_update_mesh(device, dscene, scene, progress);
- if (progress.get_cancel()) {
- return;
- }
- }
-
- if (true_displacement_used) {
- /* Re-tag flags for update, so they're re-evaluated
- * for meshes with correct bounding boxes.
- *
- * This wouldn't cause wrong results, just true
- * displacement might be less optimal to calculate.
- */
- scene->object_manager->need_flags_update = old_need_object_flags_update;
- }
-
- /* unset flags */
-
- foreach (Geometry *geom, scene->geometry) {
- geom->clear_modified();
- geom->attributes.clear_modified();
-
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- mesh->subd_attributes.clear_modified();
- }
- }
-
- update_flags = UPDATE_NONE;
-
- dscene->bvh_nodes.clear_modified();
- dscene->bvh_leaf_nodes.clear_modified();
- dscene->object_node.clear_modified();
- dscene->prim_type.clear_modified();
- dscene->prim_visibility.clear_modified();
- dscene->prim_index.clear_modified();
- dscene->prim_object.clear_modified();
- dscene->prim_time.clear_modified();
- dscene->tri_verts.clear_modified();
- dscene->tri_shader.clear_modified();
- dscene->tri_vindex.clear_modified();
- dscene->tri_patch.clear_modified();
- dscene->tri_vnormal.clear_modified();
- dscene->tri_patch_uv.clear_modified();
- dscene->curves.clear_modified();
- dscene->curve_keys.clear_modified();
- dscene->curve_segments.clear_modified();
- dscene->patches.clear_modified();
- dscene->attributes_map.clear_modified();
- dscene->attributes_float.clear_modified();
- dscene->attributes_float2.clear_modified();
- dscene->attributes_float3.clear_modified();
- dscene->attributes_uchar4.clear_modified();
-}
-
-void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool force_free)
-{
- dscene->bvh_nodes.free_if_need_realloc(force_free);
- dscene->bvh_leaf_nodes.free_if_need_realloc(force_free);
- dscene->object_node.free_if_need_realloc(force_free);
- dscene->prim_type.free_if_need_realloc(force_free);
- dscene->prim_visibility.free_if_need_realloc(force_free);
- dscene->prim_index.free_if_need_realloc(force_free);
- dscene->prim_object.free_if_need_realloc(force_free);
- dscene->prim_time.free_if_need_realloc(force_free);
- dscene->tri_verts.free_if_need_realloc(force_free);
- dscene->tri_shader.free_if_need_realloc(force_free);
- dscene->tri_vnormal.free_if_need_realloc(force_free);
- dscene->tri_vindex.free_if_need_realloc(force_free);
- dscene->tri_patch.free_if_need_realloc(force_free);
- dscene->tri_patch_uv.free_if_need_realloc(force_free);
- dscene->curves.free_if_need_realloc(force_free);
- dscene->curve_keys.free_if_need_realloc(force_free);
- dscene->curve_segments.free_if_need_realloc(force_free);
- dscene->patches.free_if_need_realloc(force_free);
- dscene->attributes_map.free_if_need_realloc(force_free);
- dscene->attributes_float.free_if_need_realloc(force_free);
- dscene->attributes_float2.free_if_need_realloc(force_free);
- dscene->attributes_float3.free_if_need_realloc(force_free);
- dscene->attributes_uchar4.free_if_need_realloc(force_free);
-
- /* Signal for shaders like displacement not to do ray tracing. */
- dscene->data.bvh.bvh_layout = BVH_LAYOUT_NONE;
-
-#ifdef WITH_OSL
- OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
-
- if (og) {
- og->object_name_map.clear();
- og->attribute_map.clear();
- og->object_names.clear();
- }
-#else
- (void)device;
-#endif
-}
-
-void GeometryManager::tag_update(Scene *scene, uint32_t flag)
-{
- update_flags |= flag;
-
- /* do not tag the object manager for an update if it is the one who tagged us */
- if ((flag & OBJECT_MANAGER) == 0) {
- scene->object_manager->tag_update(scene, ObjectManager::GEOMETRY_MANAGER);
- }
-}
-
-bool GeometryManager::need_update() const
-{
- return update_flags != UPDATE_NONE;
-}
-
-void GeometryManager::collect_statistics(const Scene *scene, RenderStats *stats)
-{
- foreach (Geometry *geometry, scene->geometry) {
- stats->mesh.geometry.add_entry(
- NamedSizeEntry(string(geometry->name.c_str()), geometry->get_total_size_in_bytes()));
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/geometry.h b/intern/cycles/render/geometry.h
deleted file mode 100644
index 5c45754ad90..00000000000
--- a/intern/cycles/render/geometry.h
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __GEOMETRY_H__
-#define __GEOMETRY_H__
-
-#include "graph/node.h"
-
-#include "bvh/bvh_params.h"
-
-#include "render/attribute.h"
-
-#include "util/util_boundbox.h"
-#include "util/util_set.h"
-#include "util/util_transform.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BVH;
-class Device;
-class DeviceScene;
-class Mesh;
-class Progress;
-class RenderStats;
-class Scene;
-class SceneParams;
-class Shader;
-class Volume;
-struct PackedBVH;
-
-/* Geometry
- *
- * Base class for geometric types like Mesh and Hair. */
-
-class Geometry : public Node {
- public:
- NODE_ABSTRACT_DECLARE
-
- enum Type {
- MESH,
- HAIR,
- VOLUME,
- };
-
- Type geometry_type;
-
- /* Attributes */
- AttributeSet attributes;
-
- /* Shaders */
- NODE_SOCKET_API_ARRAY(array<Node *>, used_shaders)
-
- /* Transform */
- BoundBox bounds;
- bool transform_applied;
- bool transform_negative_scaled;
- Transform transform_normal;
-
- /* Motion Blur */
- NODE_SOCKET_API(uint, motion_steps)
- NODE_SOCKET_API(bool, use_motion_blur)
-
- /* Maximum number of motion steps supported (due to Embree). */
- static const uint MAX_MOTION_STEPS = 129;
-
- /* BVH */
- BVH *bvh;
- size_t attr_map_offset;
- size_t prim_offset;
-
- /* Shader Properties */
- bool has_volume; /* Set in the device_update_flags(). */
- bool has_surface_bssrdf; /* Set in the device_update_flags(). */
-
- /* Update Flags */
- bool need_update_rebuild;
- bool need_update_bvh_for_offset;
-
- /* Index into scene->geometry (only valid during update) */
- size_t index;
-
- /* Constructor/Destructor */
- explicit Geometry(const NodeType *node_type, const Type type);
- virtual ~Geometry();
-
- /* Geometry */
- virtual void clear(bool preserve_shaders = false);
- virtual void compute_bounds() = 0;
- virtual void apply_transform(const Transform &tfm, const bool apply_to_motion) = 0;
-
- /* Attribute Requests */
- bool need_attribute(Scene *scene, AttributeStandard std);
- bool need_attribute(Scene *scene, ustring name);
-
- AttributeRequestSet needed_attributes();
-
- /* UDIM */
- virtual void get_uv_tiles(ustring map, unordered_set<int> &tiles) = 0;
-
- /* Convert between normalized -1..1 motion time and index in the
- * VERTEX_MOTION attribute. */
- float motion_time(int step) const;
- int motion_step(float time) const;
-
- /* BVH */
- void compute_bvh(Device *device,
- DeviceScene *dscene,
- SceneParams *params,
- Progress *progress,
- int n,
- int total);
-
- virtual PrimitiveType primitive_type() const = 0;
-
- /* Check whether the geometry should have own BVH built separately. Briefly,
- * own BVH is needed for geometry, if:
- *
- * - It is instanced multiple times, so each instance object should share the
- * same BVH tree.
- * - Special ray intersection is needed, for example to limit subsurface rays
- * to only the geometry itself.
- * - The BVH layout requires the top level to only contain instances.
- */
- bool need_build_bvh(BVHLayout layout) const;
-
- /* Test if the geometry should be treated as instanced. */
- bool is_instanced() const;
-
- bool has_true_displacement() const;
- bool has_motion_blur() const;
- bool has_voxel_attributes() const;
-
- bool is_mesh() const
- {
- return geometry_type == MESH;
- }
-
- bool is_hair() const
- {
- return geometry_type == HAIR;
- }
-
- bool is_volume() const
- {
- return geometry_type == VOLUME;
- }
-
- /* Updates */
- void tag_update(Scene *scene, bool rebuild);
-
- void tag_bvh_update(bool rebuild);
-};
-
-/* Geometry Manager */
-
-class GeometryManager {
- uint32_t update_flags;
-
- public:
- enum : uint32_t {
- UV_PASS_NEEDED = (1 << 0),
- MOTION_PASS_NEEDED = (1 << 1),
- GEOMETRY_MODIFIED = (1 << 2),
- OBJECT_MANAGER = (1 << 3),
- MESH_ADDED = (1 << 4),
- MESH_REMOVED = (1 << 5),
- HAIR_ADDED = (1 << 6),
- HAIR_REMOVED = (1 << 7),
-
- SHADER_ATTRIBUTE_MODIFIED = (1 << 8),
- SHADER_DISPLACEMENT_MODIFIED = (1 << 9),
-
- GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED,
- GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED,
-
- TRANSFORM_MODIFIED = (1 << 10),
-
- VISIBILITY_MODIFIED = (1 << 11),
-
- /* tag everything in the manager for an update */
- UPDATE_ALL = ~0u,
-
- UPDATE_NONE = 0u,
- };
-
- /* Update Flags */
- bool need_flags_update;
-
- /* Constructor/Destructor */
- GeometryManager();
- ~GeometryManager();
-
- /* Device Updates */
- void device_update_preprocess(Device *device, Scene *scene, Progress &progress);
- void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
- void device_free(Device *device, DeviceScene *dscene, bool force_free);
-
- /* Updates */
- void tag_update(Scene *scene, uint32_t flag);
-
- bool need_update() const;
-
- /* Statistics */
- void collect_statistics(const Scene *scene, RenderStats *stats);
-
- protected:
- bool displace(Device *device, Scene *scene, Mesh *mesh, Progress &progress);
-
- void create_volume_mesh(Volume *volume, Progress &progress);
-
- /* Attributes */
- void update_osl_attributes(Device *device,
- Scene *scene,
- vector<AttributeRequestSet> &geom_attributes);
- void update_svm_attributes(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- vector<AttributeRequestSet> &geom_attributes,
- vector<AttributeRequestSet> &object_attributes);
-
- /* Compute verts/triangles/curves offsets in global arrays. */
- void mesh_calc_offset(Scene *scene, BVHLayout bvh_layout);
-
- void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
-
- void device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
-
- void device_update_attributes(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress);
-
- void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
-
- void device_update_displacement_images(Device *device, Scene *scene, Progress &progress);
-
- void device_update_volume_images(Device *device, Scene *scene, Progress &progress);
-
- private:
- static void update_attribute_element_offset(Geometry *geom,
- device_vector<float> &attr_float,
- size_t &attr_float_offset,
- device_vector<float2> &attr_float2,
- size_t &attr_float2_offset,
- device_vector<float4> &attr_float3,
- size_t &attr_float3_offset,
- device_vector<uchar4> &attr_uchar4,
- size_t &attr_uchar4_offset,
- Attribute *mattr,
- AttributePrimitive prim,
- TypeDesc &type,
- AttributeDescriptor &desc);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __GEOMETRY_H__ */
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
deleted file mode 100644
index ee1a6e68bcf..00000000000
--- a/intern/cycles/render/graph.cpp
+++ /dev/null
@@ -1,1239 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/graph.h"
-#include "render/attribute.h"
-#include "render/constant_fold.h"
-#include "render/nodes.h"
-#include "render/scene.h"
-#include "render/shader.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_md5.h"
-#include "util/util_queue.h"
-
-CCL_NAMESPACE_BEGIN
-
-namespace {
-
-bool check_node_inputs_has_links(const ShaderNode *node)
-{
- foreach (const ShaderInput *in, node->inputs) {
- if (in->link) {
- return true;
- }
- }
- return false;
-}
-
-bool check_node_inputs_traversed(const ShaderNode *node, const ShaderNodeSet &done)
-{
- foreach (const ShaderInput *in, node->inputs) {
- if (in->link) {
- if (done.find(in->link->parent) == done.end()) {
- return false;
- }
- }
- }
- return true;
-}
-
-} /* namespace */
-
-/* Sockets */
-
-void ShaderInput::disconnect()
-{
- if (link) {
- link->links.erase(remove(link->links.begin(), link->links.end(), this), link->links.end());
- }
- link = NULL;
-}
-
-void ShaderOutput::disconnect()
-{
- foreach (ShaderInput *sock, links) {
- sock->link = NULL;
- }
-
- links.clear();
-}
-
-/* Node */
-
-ShaderNode::ShaderNode(const NodeType *type) : Node(type)
-{
- name = type->name;
- id = -1;
- bump = SHADER_BUMP_NONE;
- special_type = SHADER_SPECIAL_TYPE_NONE;
-
- create_inputs_outputs(type);
-}
-
-ShaderNode::~ShaderNode()
-{
- foreach (ShaderInput *socket, inputs)
- delete socket;
-
- foreach (ShaderOutput *socket, outputs)
- delete socket;
-}
-
-void ShaderNode::create_inputs_outputs(const NodeType *type)
-{
- foreach (const SocketType &socket, type->inputs) {
- if (socket.flags & SocketType::LINKABLE) {
- inputs.push_back(new ShaderInput(socket, this));
- }
- }
-
- foreach (const SocketType &socket, type->outputs) {
- outputs.push_back(new ShaderOutput(socket, this));
- }
-}
-
-ShaderInput *ShaderNode::input(const char *name)
-{
- foreach (ShaderInput *socket, inputs) {
- if (socket->name() == name)
- return socket;
- }
-
- return NULL;
-}
-
-ShaderOutput *ShaderNode::output(const char *name)
-{
- foreach (ShaderOutput *socket, outputs)
- if (socket->name() == name)
- return socket;
-
- return NULL;
-}
-
-ShaderInput *ShaderNode::input(ustring name)
-{
- foreach (ShaderInput *socket, inputs) {
- if (socket->name() == name)
- return socket;
- }
-
- return NULL;
-}
-
-ShaderOutput *ShaderNode::output(ustring name)
-{
- foreach (ShaderOutput *socket, outputs)
- if (socket->name() == name)
- return socket;
-
- return NULL;
-}
-
-void ShaderNode::remove_input(ShaderInput *input)
-{
- assert(input->link == NULL);
- delete input;
- inputs.erase(remove(inputs.begin(), inputs.end(), input), inputs.end());
-}
-
-void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- foreach (ShaderInput *input, inputs) {
- if (!input->link) {
- if (input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
- if (shader->has_surface_link())
- attributes->add(ATTR_STD_GENERATED);
- if (shader->has_volume)
- attributes->add(ATTR_STD_GENERATED_TRANSFORM);
- }
- else if (input->flags() & SocketType::LINK_TEXTURE_UV) {
- if (shader->has_surface_link())
- attributes->add(ATTR_STD_UV);
- }
- }
- }
-}
-
-bool ShaderNode::equals(const ShaderNode &other)
-{
- if (type != other.type || bump != other.bump) {
- return false;
- }
-
- assert(inputs.size() == other.inputs.size());
-
- /* Compare unlinkable sockets */
- foreach (const SocketType &socket, type->inputs) {
- if (!(socket.flags & SocketType::LINKABLE)) {
- if (!Node::equals_value(other, socket)) {
- return false;
- }
- }
- }
-
- /* Compare linkable input sockets */
- for (int i = 0; i < inputs.size(); ++i) {
- ShaderInput *input_a = inputs[i], *input_b = other.inputs[i];
- if (input_a->link == NULL && input_b->link == NULL) {
- /* Unconnected inputs are expected to have the same value. */
- if (!Node::equals_value(other, input_a->socket_type)) {
- return false;
- }
- }
- else if (input_a->link != NULL && input_b->link != NULL) {
- /* Expect links are to come from the same exact socket. */
- if (input_a->link != input_b->link) {
- return false;
- }
- }
- else {
- /* One socket has a link and another has not, inputs can't be
- * considered equal.
- */
- return false;
- }
- }
-
- return true;
-}
-
-/* Graph */
-
-ShaderGraph::ShaderGraph()
-{
- finalized = false;
- simplified = false;
- num_node_ids = 0;
- add(create_node<OutputNode>());
-}
-
-ShaderGraph::~ShaderGraph()
-{
- clear_nodes();
-}
-
-ShaderNode *ShaderGraph::add(ShaderNode *node)
-{
- assert(!finalized);
- simplified = false;
-
- node->id = num_node_ids++;
- nodes.push_back(node);
- return node;
-}
-
-OutputNode *ShaderGraph::output()
-{
- return (OutputNode *)nodes.front();
-}
-
-void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
-{
- assert(!finalized);
- assert(from && to);
-
- if (to->link) {
- fprintf(stderr, "Cycles shader graph connect: input already connected.\n");
- return;
- }
-
- if (from->type() != to->type()) {
- /* can't do automatic conversion from closure */
- if (from->type() == SocketType::CLOSURE) {
- fprintf(stderr,
- "Cycles shader graph connect: can only connect closure to closure "
- "(%s.%s to %s.%s).\n",
- from->parent->name.c_str(),
- from->name().c_str(),
- to->parent->name.c_str(),
- to->name().c_str());
- return;
- }
-
- /* add automatic conversion node in case of type mismatch */
- ShaderNode *convert;
- ShaderInput *convert_in;
-
- if (to->type() == SocketType::CLOSURE) {
- EmissionNode *emission = create_node<EmissionNode>();
- emission->set_color(one_float3());
- emission->set_strength(1.0f);
- convert = add(emission);
- /* Connect float inputs to Strength to save an additional Value->Color conversion. */
- if (from->type() == SocketType::FLOAT) {
- convert_in = convert->input("Strength");
- }
- else {
- convert_in = convert->input("Color");
- }
- }
- else {
- convert = add(create_node<ConvertNode>(from->type(), to->type(), true));
- convert_in = convert->inputs[0];
- }
-
- connect(from, convert_in);
- connect(convert->outputs[0], to);
- }
- else {
- /* types match, just connect */
- to->link = from;
- from->links.push_back(to);
- }
-}
-
-void ShaderGraph::disconnect(ShaderOutput *from)
-{
- assert(!finalized);
- simplified = false;
-
- from->disconnect();
-}
-
-void ShaderGraph::disconnect(ShaderInput *to)
-{
- assert(!finalized);
- assert(to->link);
- simplified = false;
-
- to->disconnect();
-}
-
-void ShaderGraph::relink(ShaderInput *from, ShaderInput *to)
-{
- ShaderOutput *out = from->link;
- if (out) {
- disconnect(from);
- connect(out, to);
- }
- to->parent->copy_value(to->socket_type, *(from->parent), from->socket_type);
-}
-
-void ShaderGraph::relink(ShaderOutput *from, ShaderOutput *to)
-{
- /* Copy because disconnect modifies this list. */
- vector<ShaderInput *> outputs = from->links;
-
- foreach (ShaderInput *sock, outputs) {
- disconnect(sock);
- if (to)
- connect(to, sock);
- }
-}
-
-void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to)
-{
- simplified = false;
-
- /* Copy because disconnect modifies this list */
- vector<ShaderInput *> outputs = from->links;
-
- /* Bypass node by moving all links from "from" to "to" */
- foreach (ShaderInput *sock, node->inputs) {
- if (sock->link)
- disconnect(sock);
- }
-
- foreach (ShaderInput *sock, outputs) {
- disconnect(sock);
- if (to)
- connect(to, sock);
- }
-}
-
-void ShaderGraph::simplify(Scene *scene)
-{
- if (!simplified) {
- expand();
- default_inputs(scene->shader_manager->use_osl());
- clean(scene);
- refine_bump_nodes();
-
- simplified = true;
- }
-}
-
-void ShaderGraph::finalize(Scene *scene, bool do_bump, bool do_simplify, bool bump_in_object_space)
-{
- /* before compiling, the shader graph may undergo a number of modifications.
- * currently we set default geometry shader inputs, and create automatic bump
- * from displacement. a graph can be finalized only once, and should not be
- * modified afterwards. */
-
- if (!finalized) {
- simplify(scene);
-
- if (do_bump)
- bump_from_displacement(bump_in_object_space);
-
- ShaderInput *surface_in = output()->input("Surface");
- ShaderInput *volume_in = output()->input("Volume");
-
- /* todo: make this work when surface and volume closures are tangled up */
-
- if (surface_in->link)
- transform_multi_closure(surface_in->link->parent, NULL, false);
- if (volume_in->link)
- transform_multi_closure(volume_in->link->parent, NULL, true);
-
- finalized = true;
- }
- else if (do_simplify) {
- simplify_settings(scene);
- }
-}
-
-void ShaderGraph::find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input)
-{
- /* find all nodes that this input depends on directly and indirectly */
- ShaderNode *node = (input->link) ? input->link->parent : NULL;
-
- if (node != NULL && dependencies.find(node) == dependencies.end()) {
- foreach (ShaderInput *in, node->inputs)
- find_dependencies(dependencies, in);
-
- dependencies.insert(node);
- }
-}
-
-void ShaderGraph::clear_nodes()
-{
- foreach (ShaderNode *node, nodes) {
- delete_node(node);
- }
- nodes.clear();
-}
-
-void ShaderGraph::copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap)
-{
- /* copy a set of nodes, and the links between them. the assumption is
- * made that all nodes that inputs are linked to are in the set too. */
-
- /* copy nodes */
- foreach (ShaderNode *node, nodes) {
- ShaderNode *nnode = node->clone(this);
- nnodemap[node] = nnode;
-
- /* create new inputs and outputs to recreate links and ensure
- * that we still point to valid SocketType if the NodeType
- * changed in cloning, as it does for OSL nodes */
- nnode->inputs.clear();
- nnode->outputs.clear();
- nnode->create_inputs_outputs(nnode->type);
- }
-
- /* recreate links */
- foreach (ShaderNode *node, nodes) {
- foreach (ShaderInput *input, node->inputs) {
- if (input->link) {
- /* find new input and output */
- ShaderNode *nfrom = nnodemap[input->link->parent];
- ShaderNode *nto = nnodemap[input->parent];
- ShaderOutput *noutput = nfrom->output(input->link->name());
- ShaderInput *ninput = nto->input(input->name());
-
- /* connect */
- connect(noutput, ninput);
- }
- }
- }
-}
-
-/* Graph simplification */
-/* ******************** */
-
-/* Remove proxy nodes.
- *
- * These only exists temporarily when exporting groups, and we must remove them
- * early so that node->attributes() and default links do not see them.
- */
-void ShaderGraph::remove_proxy_nodes()
-{
- vector<bool> removed(num_node_ids, false);
- bool any_node_removed = false;
-
- foreach (ShaderNode *node, nodes) {
- if (node->special_type == SHADER_SPECIAL_TYPE_PROXY) {
- ConvertNode *proxy = static_cast<ConvertNode *>(node);
- ShaderInput *input = proxy->inputs[0];
- ShaderOutput *output = proxy->outputs[0];
-
- /* bypass the proxy node */
- if (input->link) {
- relink(proxy, output, input->link);
- }
- else {
- /* Copy because disconnect modifies this list */
- vector<ShaderInput *> links(output->links);
-
- foreach (ShaderInput *to, links) {
- /* Remove any auto-convert nodes too if they lead to
- * sockets with an automatically set default value. */
- ShaderNode *tonode = to->parent;
-
- if (tonode->special_type == SHADER_SPECIAL_TYPE_AUTOCONVERT) {
- bool all_links_removed = true;
- vector<ShaderInput *> links = tonode->outputs[0]->links;
-
- foreach (ShaderInput *autoin, links) {
- if (autoin->flags() & SocketType::DEFAULT_LINK_MASK)
- disconnect(autoin);
- else
- all_links_removed = false;
- }
-
- if (all_links_removed)
- removed[tonode->id] = true;
- }
-
- disconnect(to);
-
- /* transfer the default input value to the target socket */
- tonode->copy_value(to->socket_type, *proxy, input->socket_type);
- }
- }
-
- removed[proxy->id] = true;
- any_node_removed = true;
- }
- }
-
- /* remove nodes */
- if (any_node_removed) {
- list<ShaderNode *> newnodes;
-
- foreach (ShaderNode *node, nodes) {
- if (!removed[node->id])
- newnodes.push_back(node);
- else
- delete_node(node);
- }
-
- nodes = newnodes;
- }
-}
-
-/* Constant folding.
- *
- * Try to constant fold some nodes, and pipe result directly to
- * the input socket of connected nodes.
- */
-void ShaderGraph::constant_fold(Scene *scene)
-{
- ShaderNodeSet done, scheduled;
- queue<ShaderNode *> traverse_queue;
-
- bool has_displacement = (output()->input("Displacement")->link != NULL);
-
- /* Schedule nodes which doesn't have any dependencies. */
- foreach (ShaderNode *node, nodes) {
- if (!check_node_inputs_has_links(node)) {
- traverse_queue.push(node);
- scheduled.insert(node);
- }
- }
-
- while (!traverse_queue.empty()) {
- ShaderNode *node = traverse_queue.front();
- traverse_queue.pop();
- done.insert(node);
- foreach (ShaderOutput *output, node->outputs) {
- if (output->links.size() == 0) {
- continue;
- }
- /* Schedule node which was depending on the value,
- * when possible. Do it before disconnect.
- */
- foreach (ShaderInput *input, output->links) {
- if (scheduled.find(input->parent) != scheduled.end()) {
- /* Node might not be optimized yet but scheduled already
- * by other dependencies. No need to re-schedule it.
- */
- continue;
- }
- /* Schedule node if its inputs are fully done. */
- if (check_node_inputs_traversed(input->parent, done)) {
- traverse_queue.push(input->parent);
- scheduled.insert(input->parent);
- }
- }
- /* Optimize current node. */
- ConstantFolder folder(this, node, output, scene);
- node->constant_fold(folder);
- }
- }
-
- /* Folding might have removed all nodes connected to the displacement output
- * even tho there is displacement to be applied, so add in a value node if
- * that happens to ensure there is still a valid graph for displacement.
- */
- if (has_displacement && !output()->input("Displacement")->link) {
- ColorNode *value = (ColorNode *)add(create_node<ColorNode>());
- value->set_value(output()->get_displacement());
-
- connect(value->output("Color"), output()->input("Displacement"));
- }
-}
-
-/* Simplification. */
-void ShaderGraph::simplify_settings(Scene *scene)
-{
- foreach (ShaderNode *node, nodes) {
- node->simplify_settings(scene);
- }
-}
-
-/* Deduplicate nodes with same settings. */
-void ShaderGraph::deduplicate_nodes()
-{
- /* NOTES:
- * - Deduplication happens for nodes which has same exact settings and same
- * exact input links configuration (either connected to same output or has
- * the same exact default value).
- * - Deduplication happens in the bottom-top manner, so we know for fact that
- * all traversed nodes are either can not be deduplicated at all or were
- * already deduplicated.
- */
-
- ShaderNodeSet scheduled, done;
- map<ustring, ShaderNodeSet> candidates;
- queue<ShaderNode *> traverse_queue;
- int num_deduplicated = 0;
-
- /* Schedule nodes which doesn't have any dependencies. */
- foreach (ShaderNode *node, nodes) {
- if (!check_node_inputs_has_links(node)) {
- traverse_queue.push(node);
- scheduled.insert(node);
- }
- }
-
- while (!traverse_queue.empty()) {
- ShaderNode *node = traverse_queue.front();
- traverse_queue.pop();
- done.insert(node);
- /* Schedule the nodes which were depending on the current node. */
- bool has_output_links = false;
- foreach (ShaderOutput *output, node->outputs) {
- foreach (ShaderInput *input, output->links) {
- has_output_links = true;
- if (scheduled.find(input->parent) != scheduled.end()) {
- /* Node might not be optimized yet but scheduled already
- * by other dependencies. No need to re-schedule it.
- */
- continue;
- }
- /* Schedule node if its inputs are fully done. */
- if (check_node_inputs_traversed(input->parent, done)) {
- traverse_queue.push(input->parent);
- scheduled.insert(input->parent);
- }
- }
- }
- /* Only need to care about nodes that are actually used */
- if (!has_output_links) {
- continue;
- }
- /* Try to merge this node with another one. */
- ShaderNode *merge_with = NULL;
- foreach (ShaderNode *other_node, candidates[node->type->name]) {
- if (node != other_node && node->equals(*other_node)) {
- merge_with = other_node;
- break;
- }
- }
- /* If found an equivalent, merge; otherwise keep node for later merges */
- if (merge_with != NULL) {
- for (int i = 0; i < node->outputs.size(); ++i) {
- relink(node, node->outputs[i], merge_with->outputs[i]);
- }
- num_deduplicated++;
- }
- else {
- candidates[node->type->name].insert(node);
- }
- }
-
- if (num_deduplicated > 0) {
- VLOG(1) << "Deduplicated " << num_deduplicated << " nodes.";
- }
-}
-
-/* Check whether volume output has meaningful nodes, otherwise
- * disconnect the output.
- */
-void ShaderGraph::verify_volume_output()
-{
- /* Check whether we can optimize the whole volume graph out. */
- ShaderInput *volume_in = output()->input("Volume");
- if (volume_in->link == NULL) {
- return;
- }
- bool has_valid_volume = false;
- ShaderNodeSet scheduled;
- queue<ShaderNode *> traverse_queue;
- /* Schedule volume output. */
- traverse_queue.push(volume_in->link->parent);
- scheduled.insert(volume_in->link->parent);
- /* Traverse down the tree. */
- while (!traverse_queue.empty()) {
- ShaderNode *node = traverse_queue.front();
- traverse_queue.pop();
- /* Node is fully valid for volume, can't optimize anything out. */
- if (node->has_volume_support()) {
- has_valid_volume = true;
- break;
- }
- foreach (ShaderInput *input, node->inputs) {
- if (input->link == NULL) {
- continue;
- }
- if (scheduled.find(input->link->parent) != scheduled.end()) {
- continue;
- }
- traverse_queue.push(input->link->parent);
- scheduled.insert(input->link->parent);
- }
- }
- if (!has_valid_volume) {
- VLOG(1) << "Disconnect meaningless volume output.";
- disconnect(volume_in->link);
- }
-}
-
-void ShaderGraph::break_cycles(ShaderNode *node, vector<bool> &visited, vector<bool> &on_stack)
-{
- visited[node->id] = true;
- on_stack[node->id] = true;
-
- foreach (ShaderInput *input, node->inputs) {
- if (input->link) {
- ShaderNode *depnode = input->link->parent;
-
- if (on_stack[depnode->id]) {
- /* break cycle */
- disconnect(input);
- fprintf(stderr, "Cycles shader graph: detected cycle in graph, connection removed.\n");
- }
- else if (!visited[depnode->id]) {
- /* visit dependencies */
- break_cycles(depnode, visited, on_stack);
- }
- }
- }
-
- on_stack[node->id] = false;
-}
-
-void ShaderGraph::compute_displacement_hash()
-{
- /* Compute hash of all nodes linked to displacement, to detect if we need
- * to recompute displacement when shader nodes change. */
- ShaderInput *displacement_in = output()->input("Displacement");
-
- if (!displacement_in->link) {
- displacement_hash = "";
- return;
- }
-
- ShaderNodeSet nodes_displace;
- find_dependencies(nodes_displace, displacement_in);
-
- MD5Hash md5;
- foreach (ShaderNode *node, nodes_displace) {
- node->hash(md5);
- foreach (ShaderInput *input, node->inputs) {
- int link_id = (input->link) ? input->link->parent->id : 0;
- md5.append((uint8_t *)&link_id, sizeof(link_id));
- md5.append((input->link) ? input->link->name().c_str() : "");
- }
-
- if (node->special_type == SHADER_SPECIAL_TYPE_OSL) {
- /* Hash takes into account socket values, to detect changes
- * in the code of the node we need an exception. */
- OSLNode *oslnode = static_cast<OSLNode *>(node);
- md5.append(oslnode->bytecode_hash);
- }
- }
-
- displacement_hash = md5.get_hex();
-}
-
-void ShaderGraph::clean(Scene *scene)
-{
- /* Graph simplification */
-
- /* NOTE: Remove proxy nodes was already done. */
- constant_fold(scene);
- simplify_settings(scene);
- deduplicate_nodes();
- verify_volume_output();
-
- /* we do two things here: find cycles and break them, and remove unused
- * nodes that don't feed into the output. how cycles are broken is
- * undefined, they are invalid input, the important thing is to not crash */
-
- vector<bool> visited(num_node_ids, false);
- vector<bool> on_stack(num_node_ids, false);
-
- /* break cycles */
- break_cycles(output(), visited, on_stack);
- foreach (ShaderNode *node, nodes) {
- if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
- break_cycles(node, visited, on_stack);
- }
- }
-
- /* disconnect unused nodes */
- foreach (ShaderNode *node, nodes) {
- if (!visited[node->id]) {
- foreach (ShaderInput *to, node->inputs) {
- ShaderOutput *from = to->link;
-
- if (from) {
- to->link = NULL;
- from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
- }
- }
- }
- }
-
- /* remove unused nodes */
- list<ShaderNode *> newnodes;
-
- foreach (ShaderNode *node, nodes) {
- if (visited[node->id])
- newnodes.push_back(node);
- else
- delete_node(node);
- }
-
- nodes = newnodes;
-}
-
-void ShaderGraph::expand()
-{
- /* Call expand on all nodes, to generate additional nodes. */
- foreach (ShaderNode *node, nodes) {
- node->expand(this);
- }
-}
-
-void ShaderGraph::default_inputs(bool do_osl)
-{
- /* nodes can specify default texture coordinates, for now we give
- * everything the position by default, except for the sky texture */
-
- ShaderNode *geom = NULL;
- ShaderNode *texco = NULL;
-
- foreach (ShaderNode *node, nodes) {
- foreach (ShaderInput *input, node->inputs) {
- if (!input->link && (!(input->flags() & SocketType::OSL_INTERNAL) || do_osl)) {
- if (input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
- if (!texco)
- texco = create_node<TextureCoordinateNode>();
-
- connect(texco->output("Generated"), input);
- }
- if (input->flags() & SocketType::LINK_TEXTURE_NORMAL) {
- if (!texco)
- texco = create_node<TextureCoordinateNode>();
-
- connect(texco->output("Normal"), input);
- }
- else if (input->flags() & SocketType::LINK_TEXTURE_UV) {
- if (!texco)
- texco = create_node<TextureCoordinateNode>();
-
- connect(texco->output("UV"), input);
- }
- else if (input->flags() & SocketType::LINK_INCOMING) {
- if (!geom)
- geom = create_node<GeometryNode>();
-
- connect(geom->output("Incoming"), input);
- }
- else if (input->flags() & SocketType::LINK_NORMAL) {
- if (!geom)
- geom = create_node<GeometryNode>();
-
- connect(geom->output("Normal"), input);
- }
- else if (input->flags() & SocketType::LINK_POSITION) {
- if (!geom)
- geom = create_node<GeometryNode>();
-
- connect(geom->output("Position"), input);
- }
- else if (input->flags() & SocketType::LINK_TANGENT) {
- if (!geom)
- geom = create_node<GeometryNode>();
-
- connect(geom->output("Tangent"), input);
- }
- }
- }
- }
-
- if (geom)
- add(geom);
- if (texco)
- add(texco);
-}
-
-void ShaderGraph::refine_bump_nodes()
-{
- /* we transverse the node graph looking for bump nodes, when we find them,
- * like in bump_from_displacement(), we copy the sub-graph defined from "bump"
- * input to the inputs "center","dx" and "dy" What is in "bump" input is moved
- * to "center" input. */
-
- foreach (ShaderNode *node, nodes) {
- if (node->special_type == SHADER_SPECIAL_TYPE_BUMP && node->input("Height")->link) {
- ShaderInput *bump_input = node->input("Height");
- ShaderNodeSet nodes_bump;
-
- /* make 2 extra copies of the subgraph defined in Bump input */
- ShaderNodeMap nodes_dx;
- ShaderNodeMap nodes_dy;
-
- /* find dependencies for the given input */
- find_dependencies(nodes_bump, bump_input);
-
- copy_nodes(nodes_bump, nodes_dx);
- copy_nodes(nodes_bump, nodes_dy);
-
- /* mark nodes to indicate they are use for bump computation, so
- that any texture coordinates are shifted by dx/dy when sampling */
- foreach (ShaderNode *node, nodes_bump)
- node->bump = SHADER_BUMP_CENTER;
- foreach (NodePair &pair, nodes_dx)
- pair.second->bump = SHADER_BUMP_DX;
- foreach (NodePair &pair, nodes_dy)
- pair.second->bump = SHADER_BUMP_DY;
-
- ShaderOutput *out = bump_input->link;
- ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
- ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
-
- connect(out_dx, node->input("SampleX"));
- connect(out_dy, node->input("SampleY"));
-
- /* add generated nodes */
- foreach (NodePair &pair, nodes_dx)
- add(pair.second);
- foreach (NodePair &pair, nodes_dy)
- add(pair.second);
-
- /* Connect what is connected is bump to sample-center input. */
- connect(out, node->input("SampleCenter"));
-
- /* Bump input is just for connectivity purpose for the graph input,
- * we re-connected this input to sample-center, so lets disconnect it
- * from bump input. */
- disconnect(bump_input);
- }
- }
-}
-
-void ShaderGraph::bump_from_displacement(bool use_object_space)
-{
- /* generate bump mapping automatically from displacement. bump mapping is
- * done using a 3-tap filter, computing the displacement at the center,
- * and two other positions shifted by ray differentials.
- *
- * since the input to displacement is a node graph, we need to ensure that
- * all texture coordinates use are shift by the ray differentials. for this
- * reason we make 3 copies of the node subgraph defining the displacement,
- * with each different geometry and texture coordinate nodes that generate
- * different shifted coordinates.
- *
- * these 3 displacement values are then fed into the bump node, which will
- * output the perturbed normal. */
-
- ShaderInput *displacement_in = output()->input("Displacement");
-
- if (!displacement_in->link)
- return;
-
- /* find dependencies for the given input */
- ShaderNodeSet nodes_displace;
- find_dependencies(nodes_displace, displacement_in);
-
- /* copy nodes for 3 bump samples */
- ShaderNodeMap nodes_center;
- ShaderNodeMap nodes_dx;
- ShaderNodeMap nodes_dy;
-
- copy_nodes(nodes_displace, nodes_center);
- copy_nodes(nodes_displace, nodes_dx);
- copy_nodes(nodes_displace, nodes_dy);
-
- /* mark nodes to indicate they are use for bump computation, so
- * that any texture coordinates are shifted by dx/dy when sampling */
- foreach (NodePair &pair, nodes_center)
- pair.second->bump = SHADER_BUMP_CENTER;
- foreach (NodePair &pair, nodes_dx)
- pair.second->bump = SHADER_BUMP_DX;
- foreach (NodePair &pair, nodes_dy)
- pair.second->bump = SHADER_BUMP_DY;
-
- /* add set normal node and connect the bump normal output to the set normal
- * output, so it can finally set the shader normal, note we are only doing
- * this for bump from displacement, this will be the only bump allowed to
- * overwrite the shader normal */
- ShaderNode *set_normal = add(create_node<SetNormalNode>());
-
- /* add bump node and connect copied graphs to it */
- BumpNode *bump = (BumpNode *)add(create_node<BumpNode>());
- bump->set_use_object_space(use_object_space);
- bump->set_distance(1.0f);
-
- ShaderOutput *out = displacement_in->link;
- ShaderOutput *out_center = nodes_center[out->parent]->output(out->name());
- ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
- ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
-
- /* convert displacement vector to height */
- VectorMathNode *dot_center = (VectorMathNode *)add(create_node<VectorMathNode>());
- VectorMathNode *dot_dx = (VectorMathNode *)add(create_node<VectorMathNode>());
- VectorMathNode *dot_dy = (VectorMathNode *)add(create_node<VectorMathNode>());
-
- dot_center->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
- dot_dx->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
- dot_dy->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
-
- GeometryNode *geom = (GeometryNode *)add(create_node<GeometryNode>());
- connect(geom->output("Normal"), dot_center->input("Vector2"));
- connect(geom->output("Normal"), dot_dx->input("Vector2"));
- connect(geom->output("Normal"), dot_dy->input("Vector2"));
-
- connect(out_center, dot_center->input("Vector1"));
- connect(out_dx, dot_dx->input("Vector1"));
- connect(out_dy, dot_dy->input("Vector1"));
-
- connect(dot_center->output("Value"), bump->input("SampleCenter"));
- connect(dot_dx->output("Value"), bump->input("SampleX"));
- connect(dot_dy->output("Value"), bump->input("SampleY"));
-
- /* connect the bump out to the set normal in: */
- connect(bump->output("Normal"), set_normal->input("Direction"));
-
- /* connect to output node */
- connect(set_normal->output("Normal"), output()->input("Normal"));
-
- /* finally, add the copied nodes to the graph. we can't do this earlier
- * because we would create dependency cycles in the above loop */
- foreach (NodePair &pair, nodes_center)
- add(pair.second);
- foreach (NodePair &pair, nodes_dx)
- add(pair.second);
- foreach (NodePair &pair, nodes_dy)
- add(pair.second);
-}
-
-void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume)
-{
- /* for SVM in multi closure mode, this transforms the shader mix/add part of
- * the graph into nodes that feed weights into closure nodes. this is too
- * avoid building a closure tree and then flattening it, and instead write it
- * directly to an array */
-
- if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) {
- ShaderInput *fin = node->input("Fac");
- ShaderInput *cl1in = node->input("Closure1");
- ShaderInput *cl2in = node->input("Closure2");
- ShaderOutput *weight1_out, *weight2_out;
-
- if (fin) {
- /* mix closure: add node to mix closure weights */
- MixClosureWeightNode *mix_node = create_node<MixClosureWeightNode>();
- add(mix_node);
- ShaderInput *fac_in = mix_node->input("Fac");
- ShaderInput *weight_in = mix_node->input("Weight");
-
- if (fin->link)
- connect(fin->link, fac_in);
- else
- mix_node->set_fac(node->get_float(fin->socket_type));
-
- if (weight_out)
- connect(weight_out, weight_in);
-
- weight1_out = mix_node->output("Weight1");
- weight2_out = mix_node->output("Weight2");
- }
- else {
- /* add closure: just pass on any weights */
- weight1_out = weight_out;
- weight2_out = weight_out;
- }
-
- if (cl1in->link)
- transform_multi_closure(cl1in->link->parent, weight1_out, volume);
- if (cl2in->link)
- transform_multi_closure(cl2in->link->parent, weight2_out, volume);
- }
- else {
- ShaderInput *weight_in = node->input((volume) ? "VolumeMixWeight" : "SurfaceMixWeight");
-
- /* not a closure node? */
- if (!weight_in)
- return;
-
- /* already has a weight connected to it? add weights */
- float weight_value = node->get_float(weight_in->socket_type);
- if (weight_in->link || weight_value != 0.0f) {
- MathNode *math_node = create_node<MathNode>();
- add(math_node);
-
- if (weight_in->link)
- connect(weight_in->link, math_node->input("Value1"));
- else
- math_node->set_value1(weight_value);
-
- if (weight_out)
- connect(weight_out, math_node->input("Value2"));
- else
- math_node->set_value2(1.0f);
-
- weight_out = math_node->output("Value");
- if (weight_in->link)
- disconnect(weight_in);
- }
-
- /* connected to closure mix weight */
- if (weight_out)
- connect(weight_out, weight_in);
- else
- node->set(weight_in->socket_type, weight_value + 1.0f);
- }
-}
-
-int ShaderGraph::get_num_closures()
-{
- int num_closures = 0;
- foreach (ShaderNode *node, nodes) {
- ClosureType closure_type = node->get_closure_type();
- if (closure_type == CLOSURE_NONE_ID) {
- continue;
- }
- else if (CLOSURE_IS_BSSRDF(closure_type)) {
- num_closures += 3;
- }
- else if (CLOSURE_IS_GLASS(closure_type)) {
- num_closures += 2;
- }
- else if (CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) {
- num_closures += 2;
- }
- else if (CLOSURE_IS_PRINCIPLED(closure_type)) {
- num_closures += 8;
- }
- else if (CLOSURE_IS_VOLUME(closure_type)) {
- /* TODO(sergey): Verify this is still needed, since we have special minimized volume storage
- * for the volume steps. */
- num_closures += MAX_VOLUME_STACK_SIZE;
- }
- else if (closure_type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
- num_closures += 4;
- }
- else {
- ++num_closures;
- }
- }
- return num_closures;
-}
-
-void ShaderGraph::dump_graph(const char *filename)
-{
- FILE *fd = fopen(filename, "w");
-
- if (fd == NULL) {
- printf("Error opening file for dumping the graph: %s\n", filename);
- return;
- }
-
- fprintf(fd, "digraph shader_graph {\n");
- fprintf(fd, "ranksep=1.5\n");
- fprintf(fd, "rankdir=LR\n");
- fprintf(fd, "splines=false\n");
-
- foreach (ShaderNode *node, nodes) {
- fprintf(fd, "// NODE: %p\n", node);
- fprintf(fd, "\"%p\" [shape=record,label=\"{", node);
- if (node->inputs.size()) {
- fprintf(fd, "{");
- foreach (ShaderInput *socket, node->inputs) {
- if (socket != node->inputs[0]) {
- fprintf(fd, "|");
- }
- fprintf(fd, "<IN_%p>%s", socket, socket->name().c_str());
- }
- fprintf(fd, "}|");
- }
- fprintf(fd, "%s", node->name.c_str());
- if (node->bump == SHADER_BUMP_CENTER) {
- fprintf(fd, " (bump:center)");
- }
- else if (node->bump == SHADER_BUMP_DX) {
- fprintf(fd, " (bump:dx)");
- }
- else if (node->bump == SHADER_BUMP_DY) {
- fprintf(fd, " (bump:dy)");
- }
- if (node->outputs.size()) {
- fprintf(fd, "|{");
- foreach (ShaderOutput *socket, node->outputs) {
- if (socket != node->outputs[0]) {
- fprintf(fd, "|");
- }
- fprintf(fd, "<OUT_%p>%s", socket, socket->name().c_str());
- }
- fprintf(fd, "}");
- }
- fprintf(fd, "}\"]");
- }
-
- foreach (ShaderNode *node, nodes) {
- foreach (ShaderOutput *output, node->outputs) {
- foreach (ShaderInput *input, output->links) {
- fprintf(fd,
- "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n",
- output,
- input,
- output->name().c_str(),
- input->name().c_str());
- fprintf(fd,
- "\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n",
- output->parent,
- output,
- input->parent,
- input);
- }
- }
- }
-
- fprintf(fd, "}\n");
- fclose(fd);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
deleted file mode 100644
index 3584754fad1..00000000000
--- a/intern/cycles/render/graph.h
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __GRAPH_H__
-#define __GRAPH_H__
-
-#include "graph/node.h"
-#include "graph/node_type.h"
-
-#include "kernel/kernel_types.h"
-
-#include "util/util_list.h"
-#include "util/util_map.h"
-#include "util/util_param.h"
-#include "util/util_set.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class AttributeRequestSet;
-class Scene;
-class Shader;
-class ShaderInput;
-class ShaderOutput;
-class ShaderNode;
-class ShaderGraph;
-class SVMCompiler;
-class OSLCompiler;
-class OutputNode;
-class ConstantFolder;
-class MD5Hash;
-
-/* Bump
- *
- * For bump mapping, a node may be evaluated multiple times, using different
- * samples to reconstruct the normal, this indicates the sample position */
-
-enum ShaderBump { SHADER_BUMP_NONE, SHADER_BUMP_CENTER, SHADER_BUMP_DX, SHADER_BUMP_DY };
-
-/* Identifiers for some special node types.
- *
- * The graph needs to identify these in the clean function.
- * Cannot use dynamic_cast, as this is disabled for OSL. */
-
-enum ShaderNodeSpecialType {
- SHADER_SPECIAL_TYPE_NONE,
- SHADER_SPECIAL_TYPE_PROXY,
- SHADER_SPECIAL_TYPE_AUTOCONVERT,
- SHADER_SPECIAL_TYPE_GEOMETRY,
- SHADER_SPECIAL_TYPE_OSL,
- SHADER_SPECIAL_TYPE_IMAGE_SLOT,
- SHADER_SPECIAL_TYPE_CLOSURE,
- SHADER_SPECIAL_TYPE_COMBINE_CLOSURE,
- SHADER_SPECIAL_TYPE_OUTPUT,
- SHADER_SPECIAL_TYPE_BUMP,
- SHADER_SPECIAL_TYPE_OUTPUT_AOV,
-};
-
-/* Input
- *
- * Input socket for a shader node. May be linked to an output or not. If not
- * linked, it will either get a fixed default value, or e.g. a texture
- * coordinate. */
-
-class ShaderInput {
- public:
- ShaderInput(const SocketType &socket_type_, ShaderNode *parent_)
- : socket_type(socket_type_),
- parent(parent_),
- link(NULL),
- stack_offset(SVM_STACK_INVALID),
- constant_folded_in(false)
- {
- }
-
- ustring name()
- {
- return socket_type.ui_name;
- }
- int flags()
- {
- return socket_type.flags;
- }
- SocketType::Type type()
- {
- return socket_type.type;
- }
-
- void set(float f)
- {
- ((Node *)parent)->set(socket_type, f);
- }
- void set(float3 f)
- {
- ((Node *)parent)->set(socket_type, f);
- }
-
- void disconnect();
-
- const SocketType &socket_type;
- ShaderNode *parent;
- ShaderOutput *link;
- int stack_offset; /* for SVM compiler */
-
- /* Keeps track of whether a constant was folded in this socket, to avoid over-optimizing when the
- * link is null. */
- bool constant_folded_in;
-};
-
-/* Output
- *
- * Output socket for a shader node. */
-
-class ShaderOutput {
- public:
- ShaderOutput(const SocketType &socket_type_, ShaderNode *parent_)
- : socket_type(socket_type_), parent(parent_), stack_offset(SVM_STACK_INVALID)
- {
- }
-
- ustring name()
- {
- return socket_type.ui_name;
- }
- SocketType::Type type()
- {
- return socket_type.type;
- }
-
- void disconnect();
-
- const SocketType &socket_type;
- ShaderNode *parent;
- vector<ShaderInput *> links;
- int stack_offset; /* for SVM compiler */
-};
-
-/* Node
- *
- * Shader node in graph, with input and output sockets. This is the virtual
- * base class for all node types. */
-
-class ShaderNode : public Node {
- public:
- explicit ShaderNode(const NodeType *type);
- virtual ~ShaderNode();
-
- void create_inputs_outputs(const NodeType *type);
- void remove_input(ShaderInput *input);
-
- ShaderInput *input(const char *name);
- ShaderOutput *output(const char *name);
- ShaderInput *input(ustring name);
- ShaderOutput *output(ustring name);
-
- virtual ShaderNode *clone(ShaderGraph *graph) const = 0;
- virtual void attributes(Shader *shader, AttributeRequestSet *attributes);
- virtual void compile(SVMCompiler &compiler) = 0;
- virtual void compile(OSLCompiler &compiler) = 0;
-
- /* Expand node into additional nodes. */
- virtual void expand(ShaderGraph * /* graph */)
- {
- }
-
- /* ** Node optimization ** */
- /* Check whether the node can be replaced with single constant. */
- virtual void constant_fold(const ConstantFolder & /*folder*/)
- {
- }
-
- /* Simplify settings used by artists to the ones which are simpler to
- * evaluate in the kernel but keep the final result unchanged.
- */
- virtual void simplify_settings(Scene * /*scene*/){};
-
- virtual bool has_surface_emission()
- {
- return false;
- }
- virtual bool has_surface_transparent()
- {
- return false;
- }
- virtual bool has_surface_bssrdf()
- {
- return false;
- }
- virtual bool has_bump()
- {
- return false;
- }
- virtual bool has_bssrdf_bump()
- {
- return false;
- }
- virtual bool has_spatial_varying()
- {
- return false;
- }
- virtual bool has_attribute_dependency()
- {
- return false;
- }
- virtual bool has_integrator_dependency()
- {
- return false;
- }
- virtual bool has_volume_support()
- {
- return false;
- }
- vector<ShaderInput *> inputs;
- vector<ShaderOutput *> outputs;
-
- int id; /* index in graph node array */
- ShaderBump bump; /* for bump mapping utility */
-
- ShaderNodeSpecialType special_type; /* special node type */
-
- /* ** Selective nodes compilation ** */
-
- /* TODO(sergey): More explicitly mention in the function names
- * that those functions are for selective compilation only?
- */
-
- /* Node feature are used to disable huge nodes inside the group,
- * so it's possible to disable huge nodes inside of the required
- * nodes group.
- */
- virtual int get_feature()
- {
- return bump == SHADER_BUMP_NONE ? 0 : KERNEL_FEATURE_NODE_BUMP;
- }
-
- /* Get closure ID to which the node compiles into. */
- virtual ClosureType get_closure_type()
- {
- return CLOSURE_NONE_ID;
- }
-
- /* Check whether settings of the node equals to another one.
- *
- * This is mainly used to check whether two nodes can be merged
- * together. Meaning, runtime stuff like node id and unbound slots
- * will be ignored for comparison.
- *
- * NOTE: If some node can't be de-duplicated for whatever reason it
- * is to be handled in the subclass.
- */
- virtual bool equals(const ShaderNode &other);
-};
-
-/* Node definition utility macros */
-
-#define SHADER_NODE_CLASS(type) \
- NODE_DECLARE \
- type(); \
- virtual ShaderNode *clone(ShaderGraph *graph) const \
- { \
- return graph->create_node<type>(*this); \
- } \
- virtual void compile(SVMCompiler &compiler); \
- virtual void compile(OSLCompiler &compiler);
-
-#define SHADER_NODE_NO_CLONE_CLASS(type) \
- NODE_DECLARE \
- type(); \
- virtual void compile(SVMCompiler &compiler); \
- virtual void compile(OSLCompiler &compiler);
-
-#define SHADER_NODE_BASE_CLASS(type) \
- virtual ShaderNode *clone(ShaderGraph *graph) const \
- { \
- return graph->create_node<type>(*this); \
- } \
- virtual void compile(SVMCompiler &compiler); \
- virtual void compile(OSLCompiler &compiler);
-
-class ShaderNodeIDComparator {
- public:
- bool operator()(const ShaderNode *n1, const ShaderNode *n2) const
- {
- return n1->id < n2->id;
- }
-};
-
-typedef set<ShaderNode *, ShaderNodeIDComparator> ShaderNodeSet;
-typedef map<ShaderNode *, ShaderNode *, ShaderNodeIDComparator> ShaderNodeMap;
-
-/* Graph
- *
- * Shader graph of nodes. Also does graph manipulations for default inputs,
- * bump mapping from displacement, and possibly other things in the future. */
-
-class ShaderGraph : public NodeOwner {
- public:
- list<ShaderNode *> nodes;
- size_t num_node_ids;
- bool finalized;
- bool simplified;
- string displacement_hash;
-
- ShaderGraph();
- ~ShaderGraph();
-
- ShaderNode *add(ShaderNode *node);
- OutputNode *output();
-
- void connect(ShaderOutput *from, ShaderInput *to);
- void disconnect(ShaderOutput *from);
- void disconnect(ShaderInput *to);
- void relink(ShaderInput *from, ShaderInput *to);
- void relink(ShaderOutput *from, ShaderOutput *to);
- void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to);
-
- void remove_proxy_nodes();
- void compute_displacement_hash();
- void simplify(Scene *scene);
- void finalize(Scene *scene,
- bool do_bump = false,
- bool do_simplify = false,
- bool bump_in_object_space = false);
-
- int get_num_closures();
-
- void dump_graph(const char *filename);
-
- /* This function is used to create a node of a specified type instead of
- * calling 'new', and sets the graph as the owner of the node.
- */
- template<typename T, typename... Args> T *create_node(Args &&...args)
- {
- T *node = new T(args...);
- node->set_owner(this);
- return node;
- }
-
- /* This function is used to delete a node created and owned by the graph.
- */
- template<typename T> void delete_node(T *node)
- {
- assert(node->get_owner() == this);
- delete node;
- }
-
- protected:
- typedef pair<ShaderNode *const, ShaderNode *> NodePair;
-
- void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input);
- void clear_nodes();
- void copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap);
-
- void break_cycles(ShaderNode *node, vector<bool> &visited, vector<bool> &on_stack);
- void bump_from_displacement(bool use_object_space);
- void refine_bump_nodes();
- void expand();
- void default_inputs(bool do_osl);
- void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume);
-
- /* Graph simplification routines. */
- void clean(Scene *scene);
- void constant_fold(Scene *scene);
- void simplify_settings(Scene *scene);
- void deduplicate_nodes();
- void verify_volume_output();
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __GRAPH_H__ */
diff --git a/intern/cycles/render/hair.cpp b/intern/cycles/render/hair.cpp
deleted file mode 100644
index 4656148119a..00000000000
--- a/intern/cycles/render/hair.cpp
+++ /dev/null
@@ -1,632 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bvh/bvh.h"
-
-#include "render/curves.h"
-#include "render/hair.h"
-#include "render/object.h"
-#include "render/scene.h"
-
-#include "integrator/shader_eval.h"
-
-#include "util/util_progress.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Hair Curve */
-
-void Hair::Curve::bounds_grow(const int k,
- const float3 *curve_keys,
- const float *curve_radius,
- BoundBox &bounds) const
-{
- float3 P[4];
-
- P[0] = curve_keys[max(first_key + k - 1, first_key)];
- P[1] = curve_keys[first_key + k];
- P[2] = curve_keys[first_key + k + 1];
- P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)];
-
- float3 lower;
- float3 upper;
-
- curvebounds(&lower.x, &upper.x, P, 0);
- curvebounds(&lower.y, &upper.y, P, 1);
- curvebounds(&lower.z, &upper.z, P, 2);
-
- float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]);
-
- bounds.grow(lower, mr);
- bounds.grow(upper, mr);
-}
-
-void Hair::Curve::bounds_grow(const int k,
- const float3 *curve_keys,
- const float *curve_radius,
- const Transform &aligned_space,
- BoundBox &bounds) const
-{
- float3 P[4];
-
- P[0] = curve_keys[max(first_key + k - 1, first_key)];
- P[1] = curve_keys[first_key + k];
- P[2] = curve_keys[first_key + k + 1];
- P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)];
-
- P[0] = transform_point(&aligned_space, P[0]);
- P[1] = transform_point(&aligned_space, P[1]);
- P[2] = transform_point(&aligned_space, P[2]);
- P[3] = transform_point(&aligned_space, P[3]);
-
- float3 lower;
- float3 upper;
-
- curvebounds(&lower.x, &upper.x, P, 0);
- curvebounds(&lower.y, &upper.y, P, 1);
- curvebounds(&lower.z, &upper.z, P, 2);
-
- float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]);
-
- bounds.grow(lower, mr);
- bounds.grow(upper, mr);
-}
-
-void Hair::Curve::bounds_grow(float4 keys[4], BoundBox &bounds) const
-{
- float3 P[4] = {
- float4_to_float3(keys[0]),
- float4_to_float3(keys[1]),
- float4_to_float3(keys[2]),
- float4_to_float3(keys[3]),
- };
-
- float3 lower;
- float3 upper;
-
- curvebounds(&lower.x, &upper.x, P, 0);
- curvebounds(&lower.y, &upper.y, P, 1);
- curvebounds(&lower.z, &upper.z, P, 2);
-
- float mr = max(keys[1].w, keys[2].w);
-
- bounds.grow(lower, mr);
- bounds.grow(upper, mr);
-}
-
-void Hair::Curve::motion_keys(const float3 *curve_keys,
- const float *curve_radius,
- const float3 *key_steps,
- size_t num_curve_keys,
- size_t num_steps,
- float time,
- size_t k0,
- size_t k1,
- float4 r_keys[2]) const
-{
- /* Figure out which steps we need to fetch and their interpolation factor. */
- const size_t max_step = num_steps - 1;
- const size_t step = min((int)(time * max_step), max_step - 1);
- const float t = time * max_step - step;
- /* Fetch vertex coordinates. */
- float4 curr_keys[2];
- float4 next_keys[2];
- keys_for_step(
- curve_keys, curve_radius, key_steps, num_curve_keys, num_steps, step, k0, k1, curr_keys);
- keys_for_step(
- curve_keys, curve_radius, key_steps, num_curve_keys, num_steps, step + 1, k0, k1, next_keys);
- /* Interpolate between steps. */
- r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0];
- r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1];
-}
-
-void Hair::Curve::cardinal_motion_keys(const float3 *curve_keys,
- const float *curve_radius,
- const float3 *key_steps,
- size_t num_curve_keys,
- size_t num_steps,
- float time,
- size_t k0,
- size_t k1,
- size_t k2,
- size_t k3,
- float4 r_keys[4]) const
-{
- /* Figure out which steps we need to fetch and their interpolation factor. */
- const size_t max_step = num_steps - 1;
- const size_t step = min((int)(time * max_step), max_step - 1);
- const float t = time * max_step - step;
- /* Fetch vertex coordinates. */
- float4 curr_keys[4];
- float4 next_keys[4];
- cardinal_keys_for_step(curve_keys,
- curve_radius,
- key_steps,
- num_curve_keys,
- num_steps,
- step,
- k0,
- k1,
- k2,
- k3,
- curr_keys);
- cardinal_keys_for_step(curve_keys,
- curve_radius,
- key_steps,
- num_curve_keys,
- num_steps,
- step + 1,
- k0,
- k1,
- k2,
- k3,
- next_keys);
- /* Interpolate between steps. */
- r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0];
- r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1];
- r_keys[2] = (1.0f - t) * curr_keys[2] + t * next_keys[2];
- r_keys[3] = (1.0f - t) * curr_keys[3] + t * next_keys[3];
-}
-
-void Hair::Curve::keys_for_step(const float3 *curve_keys,
- const float *curve_radius,
- const float3 *key_steps,
- size_t num_curve_keys,
- size_t num_steps,
- size_t step,
- size_t k0,
- size_t k1,
- float4 r_keys[2]) const
-{
- k0 = max(k0, 0);
- k1 = min(k1, num_keys - 1);
- const size_t center_step = ((num_steps - 1) / 2);
- if (step == center_step) {
- /* Center step: regular key location. */
- /* TODO(sergey): Consider adding make_float4(float3, float)
- * function.
- */
- r_keys[0] = make_float4(curve_keys[first_key + k0].x,
- curve_keys[first_key + k0].y,
- curve_keys[first_key + k0].z,
- curve_radius[first_key + k0]);
- r_keys[1] = make_float4(curve_keys[first_key + k1].x,
- curve_keys[first_key + k1].y,
- curve_keys[first_key + k1].z,
- curve_radius[first_key + k1]);
- }
- else {
- /* Center step is not stored in this array. */
- if (step > center_step) {
- step--;
- }
- const size_t offset = first_key + step * num_curve_keys;
- r_keys[0] = make_float4(key_steps[offset + k0].x,
- key_steps[offset + k0].y,
- key_steps[offset + k0].z,
- curve_radius[first_key + k0]);
- r_keys[1] = make_float4(key_steps[offset + k1].x,
- key_steps[offset + k1].y,
- key_steps[offset + k1].z,
- curve_radius[first_key + k1]);
- }
-}
-
-void Hair::Curve::cardinal_keys_for_step(const float3 *curve_keys,
- const float *curve_radius,
- const float3 *key_steps,
- size_t num_curve_keys,
- size_t num_steps,
- size_t step,
- size_t k0,
- size_t k1,
- size_t k2,
- size_t k3,
- float4 r_keys[4]) const
-{
- k0 = max(k0, 0);
- k3 = min(k3, num_keys - 1);
- const size_t center_step = ((num_steps - 1) / 2);
- if (step == center_step) {
- /* Center step: regular key location. */
- r_keys[0] = make_float4(curve_keys[first_key + k0].x,
- curve_keys[first_key + k0].y,
- curve_keys[first_key + k0].z,
- curve_radius[first_key + k0]);
- r_keys[1] = make_float4(curve_keys[first_key + k1].x,
- curve_keys[first_key + k1].y,
- curve_keys[first_key + k1].z,
- curve_radius[first_key + k1]);
- r_keys[2] = make_float4(curve_keys[first_key + k2].x,
- curve_keys[first_key + k2].y,
- curve_keys[first_key + k2].z,
- curve_radius[first_key + k2]);
- r_keys[3] = make_float4(curve_keys[first_key + k3].x,
- curve_keys[first_key + k3].y,
- curve_keys[first_key + k3].z,
- curve_radius[first_key + k3]);
- }
- else {
- /* Center step is not stored in this array. */
- if (step > center_step) {
- step--;
- }
- const size_t offset = first_key + step * num_curve_keys;
- r_keys[0] = make_float4(key_steps[offset + k0].x,
- key_steps[offset + k0].y,
- key_steps[offset + k0].z,
- curve_radius[first_key + k0]);
- r_keys[1] = make_float4(key_steps[offset + k1].x,
- key_steps[offset + k1].y,
- key_steps[offset + k1].z,
- curve_radius[first_key + k1]);
- r_keys[2] = make_float4(key_steps[offset + k2].x,
- key_steps[offset + k2].y,
- key_steps[offset + k2].z,
- curve_radius[first_key + k2]);
- r_keys[3] = make_float4(key_steps[offset + k3].x,
- key_steps[offset + k3].y,
- key_steps[offset + k3].z,
- curve_radius[first_key + k3]);
- }
-}
-
-/* Hair */
-
-NODE_DEFINE(Hair)
-{
- NodeType *type = NodeType::add("hair", create, NodeType::NONE, Geometry::get_node_base_type());
-
- SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>());
- SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>());
- SOCKET_INT_ARRAY(curve_first_key, "Curve First Key", array<int>());
- SOCKET_INT_ARRAY(curve_shader, "Curve Shader", array<int>());
-
- return type;
-}
-
-Hair::Hair() : Geometry(get_node_type(), Geometry::HAIR)
-{
- curve_key_offset = 0;
- curve_segment_offset = 0;
- curve_shape = CURVE_RIBBON;
-}
-
-Hair::~Hair()
-{
-}
-
-void Hair::resize_curves(int numcurves, int numkeys)
-{
- curve_keys.resize(numkeys);
- curve_radius.resize(numkeys);
- curve_first_key.resize(numcurves);
- curve_shader.resize(numcurves);
-
- attributes.resize();
-}
-
-void Hair::reserve_curves(int numcurves, int numkeys)
-{
- curve_keys.reserve(numkeys);
- curve_radius.reserve(numkeys);
- curve_first_key.reserve(numcurves);
- curve_shader.reserve(numcurves);
-
- attributes.resize(true);
-}
-
-void Hair::clear(bool preserve_shaders)
-{
- Geometry::clear(preserve_shaders);
-
- curve_keys.clear();
- curve_radius.clear();
- curve_first_key.clear();
- curve_shader.clear();
-
- attributes.clear();
-}
-
-void Hair::add_curve_key(float3 co, float radius)
-{
- curve_keys.push_back_reserved(co);
- curve_radius.push_back_reserved(radius);
-
- tag_curve_keys_modified();
- tag_curve_radius_modified();
-}
-
-void Hair::add_curve(int first_key, int shader)
-{
- curve_first_key.push_back_reserved(first_key);
- curve_shader.push_back_reserved(shader);
-
- tag_curve_first_key_modified();
- tag_curve_shader_modified();
-}
-
-void Hair::copy_center_to_motion_step(const int motion_step)
-{
- Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (attr_mP) {
- float3 *keys = &curve_keys[0];
- size_t numkeys = curve_keys.size();
- memcpy(attr_mP->data_float3() + motion_step * numkeys, keys, sizeof(float3) * numkeys);
- }
-}
-
-void Hair::get_uv_tiles(ustring map, unordered_set<int> &tiles)
-{
- Attribute *attr;
-
- if (map.empty()) {
- attr = attributes.find(ATTR_STD_UV);
- }
- else {
- attr = attributes.find(map);
- }
-
- if (attr) {
- attr->get_uv_tiles(this, ATTR_PRIM_GEOMETRY, tiles);
- }
-}
-
-void Hair::compute_bounds()
-{
- BoundBox bnds = BoundBox::empty;
- size_t curve_keys_size = curve_keys.size();
-
- if (curve_keys_size > 0) {
- for (size_t i = 0; i < curve_keys_size; i++)
- bnds.grow(curve_keys[i], curve_radius[i]);
-
- Attribute *curve_attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (use_motion_blur && curve_attr) {
- size_t steps_size = curve_keys.size() * (motion_steps - 1);
- float3 *key_steps = curve_attr->data_float3();
-
- for (size_t i = 0; i < steps_size; i++)
- bnds.grow(key_steps[i]);
- }
-
- if (!bnds.valid()) {
- bnds = BoundBox::empty;
-
- /* skip nan or inf coordinates */
- for (size_t i = 0; i < curve_keys_size; i++)
- bnds.grow_safe(curve_keys[i], curve_radius[i]);
-
- if (use_motion_blur && curve_attr) {
- size_t steps_size = curve_keys.size() * (motion_steps - 1);
- float3 *key_steps = curve_attr->data_float3();
-
- for (size_t i = 0; i < steps_size; i++)
- bnds.grow_safe(key_steps[i]);
- }
- }
- }
-
- if (!bnds.valid()) {
- /* empty mesh */
- bnds.grow(zero_float3());
- }
-
- bounds = bnds;
-}
-
-void Hair::apply_transform(const Transform &tfm, const bool apply_to_motion)
-{
- /* compute uniform scale */
- float3 c0 = transform_get_column(&tfm, 0);
- float3 c1 = transform_get_column(&tfm, 1);
- float3 c2 = transform_get_column(&tfm, 2);
- float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f / 3.0f);
-
- /* apply transform to curve keys */
- for (size_t i = 0; i < curve_keys.size(); i++) {
- float3 co = transform_point(&tfm, curve_keys[i]);
- float radius = curve_radius[i] * scalar;
-
- /* scale for curve radius is only correct for uniform scale */
- curve_keys[i] = co;
- curve_radius[i] = radius;
- }
-
- tag_curve_keys_modified();
- tag_curve_radius_modified();
-
- if (apply_to_motion) {
- Attribute *curve_attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if (curve_attr) {
- /* apply transform to motion curve keys */
- size_t steps_size = curve_keys.size() * (motion_steps - 1);
- float4 *key_steps = curve_attr->data_float4();
-
- for (size_t i = 0; i < steps_size; i++) {
- float3 co = transform_point(&tfm, float4_to_float3(key_steps[i]));
- float radius = key_steps[i].w * scalar;
-
- /* scale for curve radius is only correct for uniform scale */
- key_steps[i] = float3_to_float4(co);
- key_steps[i].w = radius;
- }
- }
- }
-}
-
-void Hair::pack_curves(Scene *scene,
- float4 *curve_key_co,
- KernelCurve *curves,
- KernelCurveSegment *curve_segments)
-{
- size_t curve_keys_size = curve_keys.size();
-
- /* pack curve keys */
- if (curve_keys_size) {
- float3 *keys_ptr = curve_keys.data();
- float *radius_ptr = curve_radius.data();
-
- for (size_t i = 0; i < curve_keys_size; i++)
- curve_key_co[i] = make_float4(keys_ptr[i].x, keys_ptr[i].y, keys_ptr[i].z, radius_ptr[i]);
- }
-
- /* pack curve segments */
- const PrimitiveType type = primitive_type();
-
- size_t curve_num = num_curves();
- size_t index = 0;
-
- for (size_t i = 0; i < curve_num; i++) {
- Curve curve = get_curve(i);
- int shader_id = curve_shader[i];
- Shader *shader = (shader_id < used_shaders.size()) ?
- static_cast<Shader *>(used_shaders[shader_id]) :
- scene->default_surface;
- shader_id = scene->shader_manager->get_shader_id(shader, false);
-
- curves[i].shader_id = shader_id;
- curves[i].first_key = curve_key_offset + curve.first_key;
- curves[i].num_keys = curve.num_keys;
- curves[i].type = type;
-
- for (int k = 0; k < curve.num_segments(); ++k, ++index) {
- curve_segments[index].prim = prim_offset + i;
- curve_segments[index].type = PRIMITIVE_PACK_SEGMENT(type, k);
- }
- }
-}
-
-PrimitiveType Hair::primitive_type() const
-{
- return has_motion_blur() ?
- ((curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
- PRIMITIVE_MOTION_CURVE_THICK) :
- ((curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK);
-}
-
-/* Fill in coordinates for curve transparency shader evaluation on device. */
-static int fill_shader_input(const Hair *hair,
- const int object_index,
- device_vector<KernelShaderEvalInput> &d_input)
-{
- int d_input_size = 0;
- KernelShaderEvalInput *d_input_data = d_input.data();
-
- const int num_curves = hair->num_curves();
- for (int i = 0; i < num_curves; i++) {
- const Hair::Curve curve = hair->get_curve(i);
- const int num_segments = curve.num_segments();
-
- for (int j = 0; j < num_segments + 1; j++) {
- KernelShaderEvalInput in;
- in.object = object_index;
- in.prim = hair->prim_offset + i;
- in.u = (j < num_segments) ? 0.0f : 1.0f;
- in.v = (j < num_segments) ? __int_as_float(j) : __int_as_float(j - 1);
- d_input_data[d_input_size++] = in;
- }
- }
-
- return d_input_size;
-}
-
-/* Read back curve transparency shader output. */
-static void read_shader_output(float *shadow_transparency,
- bool &is_fully_opaque,
- const device_vector<float> &d_output)
-{
- const int num_keys = d_output.size();
- const float *output_data = d_output.data();
- bool is_opaque = true;
-
- for (int i = 0; i < num_keys; i++) {
- shadow_transparency[i] = output_data[i];
- if (shadow_transparency[i] > 0.0f) {
- is_opaque = false;
- }
- }
-
- is_fully_opaque = is_opaque;
-}
-
-bool Hair::need_shadow_transparency()
-{
- for (const Node *node : used_shaders) {
- const Shader *shader = static_cast<const Shader *>(node);
- if (shader->has_surface_transparent && shader->get_use_transparent_shadow()) {
- return true;
- }
- }
-
- return false;
-}
-
-bool Hair::update_shadow_transparency(Device *device, Scene *scene, Progress &progress)
-{
- if (!need_shadow_transparency()) {
- /* If no shaders with shadow transparency, remove attribute. */
- Attribute *attr = attributes.find(ATTR_STD_SHADOW_TRANSPARENCY);
- if (attr) {
- attributes.remove(attr);
- return true;
- }
- else {
- return false;
- }
- }
-
- string msg = string_printf("Computing Shadow Transparency %s", name.c_str());
- progress.set_status("Updating Hair", msg);
-
- /* Create shadow transparency attribute. */
- Attribute *attr = attributes.find(ATTR_STD_SHADOW_TRANSPARENCY);
- const bool attribute_exists = (attr != nullptr);
- if (!attribute_exists) {
- attr = attributes.add(ATTR_STD_SHADOW_TRANSPARENCY);
- }
-
- float *attr_data = attr->data_float();
-
- /* Find object index. */
- size_t object_index = OBJECT_NONE;
-
- for (size_t i = 0; i < scene->objects.size(); i++) {
- if (scene->objects[i]->get_geometry() == this) {
- object_index = i;
- break;
- }
- }
-
- /* Evaluate shader on device. */
- ShaderEval shader_eval(device, progress);
- bool is_fully_opaque = false;
- shader_eval.eval(SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY,
- num_keys(),
- 1,
- function_bind(&fill_shader_input, this, object_index, _1),
- function_bind(&read_shader_output, attr_data, is_fully_opaque, _1));
-
- if (is_fully_opaque) {
- attributes.remove(attr);
- return attribute_exists;
- }
-
- return true;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/hair.h b/intern/cycles/render/hair.h
deleted file mode 100644
index 3e91fc3dcbb..00000000000
--- a/intern/cycles/render/hair.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __HAIR_H__
-#define __HAIR_H__
-
-#include "render/geometry.h"
-
-CCL_NAMESPACE_BEGIN
-
-struct KernelCurveSegment;
-
-class Hair : public Geometry {
- public:
- NODE_DECLARE
-
- /* Hair Curve */
- struct Curve {
- int first_key;
- int num_keys;
-
- int num_segments() const
- {
- return num_keys - 1;
- }
-
- void bounds_grow(const int k,
- const float3 *curve_keys,
- const float *curve_radius,
- BoundBox &bounds) const;
- void bounds_grow(float4 keys[4], BoundBox &bounds) const;
- void bounds_grow(const int k,
- const float3 *curve_keys,
- const float *curve_radius,
- const Transform &aligned_space,
- BoundBox &bounds) const;
-
- void motion_keys(const float3 *curve_keys,
- const float *curve_radius,
- const float3 *key_steps,
- size_t num_curve_keys,
- size_t num_steps,
- float time,
- size_t k0,
- size_t k1,
- float4 r_keys[2]) const;
- void cardinal_motion_keys(const float3 *curve_keys,
- const float *curve_radius,
- const float3 *key_steps,
- size_t num_curve_keys,
- size_t num_steps,
- float time,
- size_t k0,
- size_t k1,
- size_t k2,
- size_t k3,
- float4 r_keys[4]) const;
-
- void keys_for_step(const float3 *curve_keys,
- const float *curve_radius,
- const float3 *key_steps,
- size_t num_curve_keys,
- size_t num_steps,
- size_t step,
- size_t k0,
- size_t k1,
- float4 r_keys[2]) const;
- void cardinal_keys_for_step(const float3 *curve_keys,
- const float *curve_radius,
- const float3 *key_steps,
- size_t num_curve_keys,
- size_t num_steps,
- size_t step,
- size_t k0,
- size_t k1,
- size_t k2,
- size_t k3,
- float4 r_keys[4]) const;
- };
-
- NODE_SOCKET_API_ARRAY(array<float3>, curve_keys)
- NODE_SOCKET_API_ARRAY(array<float>, curve_radius)
- NODE_SOCKET_API_ARRAY(array<int>, curve_first_key)
- NODE_SOCKET_API_ARRAY(array<int>, curve_shader)
-
- /* BVH */
- size_t curve_key_offset;
- size_t curve_segment_offset;
- CurveShapeType curve_shape;
-
- /* Constructor/Destructor */
- Hair();
- ~Hair();
-
- /* Geometry */
- void clear(bool preserve_shaders = false) override;
-
- void resize_curves(int numcurves, int numkeys);
- void reserve_curves(int numcurves, int numkeys);
- void add_curve_key(float3 loc, float radius);
- void add_curve(int first_key, int shader);
-
- void copy_center_to_motion_step(const int motion_step);
-
- void compute_bounds() override;
- void apply_transform(const Transform &tfm, const bool apply_to_motion) override;
-
- /* Curves */
- Curve get_curve(size_t i) const
- {
- int first = curve_first_key[i];
- int next_first = (i + 1 < curve_first_key.size()) ? curve_first_key[i + 1] : curve_keys.size();
-
- Curve curve = {first, next_first - first};
- return curve;
- }
-
- size_t num_keys() const
- {
- return curve_keys.size();
- }
-
- size_t num_curves() const
- {
- return curve_first_key.size();
- }
-
- size_t num_segments() const
- {
- return curve_keys.size() - curve_first_key.size();
- }
-
- /* UDIM */
- void get_uv_tiles(ustring map, unordered_set<int> &tiles) override;
-
- /* BVH */
- void pack_curves(Scene *scene,
- float4 *curve_key_co,
- KernelCurve *curve,
- KernelCurveSegment *curve_segments);
-
- PrimitiveType primitive_type() const override;
-
- /* Attributes */
- bool need_shadow_transparency();
- bool update_shadow_transparency(Device *device, Scene *scene, Progress &progress);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __HAIR_H__ */
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
deleted file mode 100644
index 27f9b7df1dd..00000000000
--- a/intern/cycles/render/image.cpp
+++ /dev/null
@@ -1,905 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/image.h"
-#include "device/device.h"
-#include "render/colorspace.h"
-#include "render/image_oiio.h"
-#include "render/image_vdb.h"
-#include "render/scene.h"
-#include "render/stats.h"
-
-#include "util/util_foreach.h"
-#include "util/util_image.h"
-#include "util/util_image_impl.h"
-#include "util/util_logging.h"
-#include "util/util_path.h"
-#include "util/util_progress.h"
-#include "util/util_task.h"
-#include "util/util_texture.h"
-#include "util/util_unique_ptr.h"
-
-#ifdef WITH_OSL
-# include <OSL/oslexec.h>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-namespace {
-
-/* Some helpers to silence warning in templated function. */
-bool isfinite(uchar /*value*/)
-{
- return true;
-}
-bool isfinite(half /*value*/)
-{
- return true;
-}
-bool isfinite(uint16_t /*value*/)
-{
- return true;
-}
-
-const char *name_from_type(ImageDataType type)
-{
- switch (type) {
- case IMAGE_DATA_TYPE_FLOAT4:
- return "float4";
- case IMAGE_DATA_TYPE_BYTE4:
- return "byte4";
- case IMAGE_DATA_TYPE_HALF4:
- return "half4";
- case IMAGE_DATA_TYPE_FLOAT:
- return "float";
- case IMAGE_DATA_TYPE_BYTE:
- return "byte";
- case IMAGE_DATA_TYPE_HALF:
- return "half";
- case IMAGE_DATA_TYPE_USHORT4:
- return "ushort4";
- case IMAGE_DATA_TYPE_USHORT:
- return "ushort";
- case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
- return "nanovdb_float";
- case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
- return "nanovdb_float3";
- case IMAGE_DATA_NUM_TYPES:
- assert(!"System enumerator type, should never be used");
- return "";
- }
- assert(!"Unhandled image data type");
- return "";
-}
-
-} // namespace
-
-/* Image Handle */
-
-ImageHandle::ImageHandle() : manager(NULL)
-{
-}
-
-ImageHandle::ImageHandle(const ImageHandle &other)
- : tile_slots(other.tile_slots), manager(other.manager)
-{
- /* Increase image user count. */
- foreach (const int slot, tile_slots) {
- manager->add_image_user(slot);
- }
-}
-
-ImageHandle &ImageHandle::operator=(const ImageHandle &other)
-{
- clear();
- manager = other.manager;
- tile_slots = other.tile_slots;
-
- foreach (const int slot, tile_slots) {
- manager->add_image_user(slot);
- }
-
- return *this;
-}
-
-ImageHandle::~ImageHandle()
-{
- clear();
-}
-
-void ImageHandle::clear()
-{
- foreach (const int slot, tile_slots) {
- manager->remove_image_user(slot);
- }
-
- tile_slots.clear();
- manager = NULL;
-}
-
-bool ImageHandle::empty()
-{
- return tile_slots.empty();
-}
-
-int ImageHandle::num_tiles()
-{
- return tile_slots.size();
-}
-
-ImageMetaData ImageHandle::metadata()
-{
- if (tile_slots.empty()) {
- return ImageMetaData();
- }
-
- ImageManager::Image *img = manager->images[tile_slots.front()];
- manager->load_image_metadata(img);
- return img->metadata;
-}
-
-int ImageHandle::svm_slot(const int tile_index) const
-{
- if (tile_index >= tile_slots.size()) {
- return -1;
- }
-
- if (manager->osl_texture_system) {
- ImageManager::Image *img = manager->images[tile_slots[tile_index]];
- if (!img->loader->osl_filepath().empty()) {
- return -1;
- }
- }
-
- return tile_slots[tile_index];
-}
-
-device_texture *ImageHandle::image_memory(const int tile_index) const
-{
- if (tile_index >= tile_slots.size()) {
- return NULL;
- }
-
- ImageManager::Image *img = manager->images[tile_slots[tile_index]];
- return img ? img->mem : NULL;
-}
-
-VDBImageLoader *ImageHandle::vdb_loader(const int tile_index) const
-{
- if (tile_index >= tile_slots.size()) {
- return NULL;
- }
-
- ImageManager::Image *img = manager->images[tile_slots[tile_index]];
-
- if (img == NULL) {
- return NULL;
- }
-
- ImageLoader *loader = img->loader;
-
- if (loader == NULL) {
- return NULL;
- }
-
- if (loader->is_vdb_loader()) {
- return dynamic_cast<VDBImageLoader *>(loader);
- }
-
- return NULL;
-}
-
-bool ImageHandle::operator==(const ImageHandle &other) const
-{
- return manager == other.manager && tile_slots == other.tile_slots;
-}
-
-/* Image MetaData */
-
-ImageMetaData::ImageMetaData()
- : channels(0),
- width(0),
- height(0),
- depth(0),
- byte_size(0),
- type(IMAGE_DATA_NUM_TYPES),
- colorspace(u_colorspace_raw),
- colorspace_file_format(""),
- use_transform_3d(false),
- compress_as_srgb(false)
-{
-}
-
-bool ImageMetaData::operator==(const ImageMetaData &other) const
-{
- return channels == other.channels && width == other.width && height == other.height &&
- depth == other.depth && use_transform_3d == other.use_transform_3d &&
- (!use_transform_3d || transform_3d == other.transform_3d) && type == other.type &&
- colorspace == other.colorspace && compress_as_srgb == other.compress_as_srgb;
-}
-
-bool ImageMetaData::is_float() const
-{
- return (type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4 ||
- type == IMAGE_DATA_TYPE_HALF || type == IMAGE_DATA_TYPE_HALF4);
-}
-
-void ImageMetaData::detect_colorspace()
-{
- /* Convert used specified color spaces to one we know how to handle. */
- colorspace = ColorSpaceManager::detect_known_colorspace(
- colorspace, colorspace_file_format, is_float());
-
- if (colorspace == u_colorspace_raw) {
- /* Nothing to do. */
- }
- else if (colorspace == u_colorspace_srgb) {
- /* Keep sRGB colorspace stored as sRGB, to save memory and/or loading time
- * for the common case of 8bit sRGB images like PNG. */
- compress_as_srgb = true;
- }
- else {
- /* Always compress non-raw 8bit images as scene linear + sRGB, as a
- * heuristic to keep memory usage the same without too much data loss
- * due to quantization in common cases. */
- compress_as_srgb = (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_BYTE4);
-
- /* If colorspace conversion needed, use half instead of short so we can
- * represent HDR values that might result from conversion. */
- if (type == IMAGE_DATA_TYPE_USHORT) {
- type = IMAGE_DATA_TYPE_HALF;
- }
- else if (type == IMAGE_DATA_TYPE_USHORT4) {
- type = IMAGE_DATA_TYPE_HALF4;
- }
- }
-}
-
-/* Image Loader */
-
-ImageLoader::ImageLoader()
-{
-}
-
-ustring ImageLoader::osl_filepath() const
-{
- return ustring();
-}
-
-bool ImageLoader::equals(const ImageLoader *a, const ImageLoader *b)
-{
- if (a == NULL && b == NULL) {
- return true;
- }
- else {
- return (a && b && typeid(*a) == typeid(*b) && a->equals(*b));
- }
-}
-
-bool ImageLoader::is_vdb_loader() const
-{
- return false;
-}
-
-/* Image Manager */
-
-ImageManager::ImageManager(const DeviceInfo &info)
-{
- need_update_ = true;
- osl_texture_system = NULL;
- animation_frame = 0;
-
- /* Set image limits */
- features.has_half_float = info.has_half_images;
- features.has_nanovdb = info.has_nanovdb;
-}
-
-ImageManager::~ImageManager()
-{
- for (size_t slot = 0; slot < images.size(); slot++)
- assert(!images[slot]);
-}
-
-void ImageManager::set_osl_texture_system(void *texture_system)
-{
- osl_texture_system = texture_system;
-}
-
-bool ImageManager::set_animation_frame_update(int frame)
-{
- if (frame != animation_frame) {
- thread_scoped_lock device_lock(images_mutex);
- animation_frame = frame;
-
- for (size_t slot = 0; slot < images.size(); slot++) {
- if (images[slot] && images[slot]->params.animated)
- return true;
- }
- }
-
- return false;
-}
-
-void ImageManager::load_image_metadata(Image *img)
-{
- if (!img->need_metadata) {
- return;
- }
-
- thread_scoped_lock image_lock(img->mutex);
- if (!img->need_metadata) {
- return;
- }
-
- ImageMetaData &metadata = img->metadata;
- metadata = ImageMetaData();
- metadata.colorspace = img->params.colorspace;
-
- if (img->loader->load_metadata(features, metadata)) {
- assert(metadata.type != IMAGE_DATA_NUM_TYPES);
- }
- else {
- metadata.type = IMAGE_DATA_TYPE_BYTE4;
- }
-
- metadata.detect_colorspace();
-
- assert(features.has_half_float ||
- (metadata.type != IMAGE_DATA_TYPE_HALF4 && metadata.type != IMAGE_DATA_TYPE_HALF));
- assert(features.has_nanovdb || (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT ||
- metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3));
-
- img->need_metadata = false;
-}
-
-ImageHandle ImageManager::add_image(const string &filename, const ImageParams &params)
-{
- const int slot = add_image_slot(new OIIOImageLoader(filename), params, false);
-
- ImageHandle handle;
- handle.tile_slots.push_back(slot);
- handle.manager = this;
- return handle;
-}
-
-ImageHandle ImageManager::add_image(const string &filename,
- const ImageParams &params,
- const array<int> &tiles)
-{
- ImageHandle handle;
- handle.manager = this;
-
- foreach (int tile, tiles) {
- string tile_filename = filename;
- if (tile != 0) {
- string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile));
- }
- const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false);
- handle.tile_slots.push_back(slot);
- }
-
- return handle;
-}
-
-ImageHandle ImageManager::add_image(ImageLoader *loader,
- const ImageParams &params,
- const bool builtin)
-{
- const int slot = add_image_slot(loader, params, builtin);
-
- ImageHandle handle;
- handle.tile_slots.push_back(slot);
- handle.manager = this;
- return handle;
-}
-
-int ImageManager::add_image_slot(ImageLoader *loader,
- const ImageParams &params,
- const bool builtin)
-{
- Image *img;
- size_t slot;
-
- thread_scoped_lock device_lock(images_mutex);
-
- /* Find existing image. */
- for (slot = 0; slot < images.size(); slot++) {
- img = images[slot];
- if (img && ImageLoader::equals(img->loader, loader) && img->params == params) {
- img->users++;
- delete loader;
- return slot;
- }
- }
-
- /* Find free slot. */
- for (slot = 0; slot < images.size(); slot++) {
- if (!images[slot])
- break;
- }
-
- if (slot == images.size()) {
- images.resize(images.size() + 1);
- }
-
- /* Add new image. */
- img = new Image();
- img->params = params;
- img->loader = loader;
- img->need_metadata = true;
- img->need_load = !(osl_texture_system && !img->loader->osl_filepath().empty());
- img->builtin = builtin;
- img->users = 1;
- img->mem = NULL;
-
- images[slot] = img;
-
- need_update_ = true;
-
- return slot;
-}
-
-void ImageManager::add_image_user(int slot)
-{
- thread_scoped_lock device_lock(images_mutex);
- Image *image = images[slot];
- assert(image && image->users >= 1);
-
- image->users++;
-}
-
-void ImageManager::remove_image_user(int slot)
-{
- thread_scoped_lock device_lock(images_mutex);
- Image *image = images[slot];
- assert(image && image->users >= 1);
-
- /* decrement user count */
- image->users--;
-
- /* don't remove immediately, rather do it all together later on. one of
- * the reasons for this is that on shader changes we add and remove nodes
- * that use them, but we do not want to reload the image all the time. */
- if (image->users == 0)
- need_update_ = true;
-}
-
-static bool image_associate_alpha(ImageManager::Image *img)
-{
- /* For typical RGBA images we let OIIO convert to associated alpha,
- * but some types we want to leave the RGB channels untouched. */
- return !(ColorSpaceManager::colorspace_is_data(img->params.colorspace) ||
- img->params.alpha_type == IMAGE_ALPHA_IGNORE ||
- img->params.alpha_type == IMAGE_ALPHA_CHANNEL_PACKED);
-}
-
-template<TypeDesc::BASETYPE FileFormat, typename StorageType>
-bool ImageManager::file_load_image(Image *img, int texture_limit)
-{
- /* Ignore empty images. */
- if (!(img->metadata.channels > 0)) {
- return false;
- }
-
- /* Get metadata. */
- int width = img->metadata.width;
- int height = img->metadata.height;
- int depth = img->metadata.depth;
- int components = img->metadata.channels;
-
- /* Read pixels. */
- vector<StorageType> pixels_storage;
- StorageType *pixels;
- const size_t max_size = max(max(width, height), depth);
- if (max_size == 0) {
- /* Don't bother with empty images. */
- return false;
- }
-
- /* Allocate memory as needed, may be smaller to resize down. */
- if (texture_limit > 0 && max_size > texture_limit) {
- pixels_storage.resize(((size_t)width) * height * depth * 4);
- pixels = &pixels_storage[0];
- }
- else {
- thread_scoped_lock device_lock(device_mutex);
- pixels = (StorageType *)img->mem->alloc(width, height, depth);
- }
-
- if (pixels == NULL) {
- /* Could be that we've run out of memory. */
- return false;
- }
-
- const size_t num_pixels = ((size_t)width) * height * depth;
- img->loader->load_pixels(
- img->metadata, pixels, num_pixels * components, image_associate_alpha(img));
-
- /* The kernel can handle 1 and 4 channel images. Anything that is not a single
- * channel image is converted to RGBA format. */
- bool is_rgba = (img->metadata.type == IMAGE_DATA_TYPE_FLOAT4 ||
- img->metadata.type == IMAGE_DATA_TYPE_HALF4 ||
- img->metadata.type == IMAGE_DATA_TYPE_BYTE4 ||
- img->metadata.type == IMAGE_DATA_TYPE_USHORT4);
-
- if (is_rgba) {
- const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
-
- if (components == 2) {
- /* Grayscale + alpha to RGBA. */
- for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i * 4 + 3] = pixels[i * 2 + 1];
- pixels[i * 4 + 2] = pixels[i * 2 + 0];
- pixels[i * 4 + 1] = pixels[i * 2 + 0];
- pixels[i * 4 + 0] = pixels[i * 2 + 0];
- }
- }
- else if (components == 3) {
- /* RGB to RGBA. */
- for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i * 4 + 3] = one;
- pixels[i * 4 + 2] = pixels[i * 3 + 2];
- pixels[i * 4 + 1] = pixels[i * 3 + 1];
- pixels[i * 4 + 0] = pixels[i * 3 + 0];
- }
- }
- else if (components == 1) {
- /* Grayscale to RGBA. */
- for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i * 4 + 3] = one;
- pixels[i * 4 + 2] = pixels[i];
- pixels[i * 4 + 1] = pixels[i];
- pixels[i * 4 + 0] = pixels[i];
- }
- }
-
- /* Disable alpha if requested by the user. */
- if (img->params.alpha_type == IMAGE_ALPHA_IGNORE) {
- for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i * 4 + 3] = one;
- }
- }
-
- if (img->metadata.colorspace != u_colorspace_raw &&
- img->metadata.colorspace != u_colorspace_srgb) {
- /* Convert to scene linear. */
- ColorSpaceManager::to_scene_linear(
- img->metadata.colorspace, pixels, num_pixels, img->metadata.compress_as_srgb);
- }
- }
-
- /* Make sure we don't have buggy values. */
- if (FileFormat == TypeDesc::FLOAT) {
- /* For RGBA buffers we put all channels to 0 if either of them is not
- * finite. This way we avoid possible artifacts caused by fully changed
- * hue. */
- if (is_rgba) {
- for (size_t i = 0; i < num_pixels; i += 4) {
- StorageType *pixel = &pixels[i * 4];
- if (!isfinite(pixel[0]) || !isfinite(pixel[1]) || !isfinite(pixel[2]) ||
- !isfinite(pixel[3])) {
- pixel[0] = 0;
- pixel[1] = 0;
- pixel[2] = 0;
- pixel[3] = 0;
- }
- }
- }
- else {
- for (size_t i = 0; i < num_pixels; ++i) {
- StorageType *pixel = &pixels[i];
- if (!isfinite(pixel[0])) {
- pixel[0] = 0;
- }
- }
- }
- }
-
- /* Scale image down if needed. */
- if (pixels_storage.size() > 0) {
- float scale_factor = 1.0f;
- while (max_size * scale_factor > texture_limit) {
- scale_factor *= 0.5f;
- }
- VLOG(1) << "Scaling image " << img->loader->name() << " by a factor of " << scale_factor
- << ".";
- vector<StorageType> scaled_pixels;
- size_t scaled_width, scaled_height, scaled_depth;
- util_image_resize_pixels(pixels_storage,
- width,
- height,
- depth,
- is_rgba ? 4 : 1,
- scale_factor,
- &scaled_pixels,
- &scaled_width,
- &scaled_height,
- &scaled_depth);
-
- StorageType *texture_pixels;
-
- {
- thread_scoped_lock device_lock(device_mutex);
- texture_pixels = (StorageType *)img->mem->alloc(scaled_width, scaled_height, scaled_depth);
- }
-
- memcpy(texture_pixels, &scaled_pixels[0], scaled_pixels.size() * sizeof(StorageType));
- }
-
- return true;
-}
-
-void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Progress *progress)
-{
- if (progress->get_cancel()) {
- return;
- }
-
- Image *img = images[slot];
-
- progress->set_status("Updating Images", "Loading " + img->loader->name());
-
- const int texture_limit = scene->params.texture_limit;
-
- load_image_metadata(img);
- ImageDataType type = img->metadata.type;
-
- /* Name for debugging. */
- img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type), slot);
-
- /* Free previous texture in slot. */
- if (img->mem) {
- thread_scoped_lock device_lock(device_mutex);
- delete img->mem;
- img->mem = NULL;
- }
-
- img->mem = new device_texture(
- device, img->mem_name.c_str(), slot, type, img->params.interpolation, img->params.extension);
- img->mem->info.use_transform_3d = img->metadata.use_transform_3d;
- img->mem->info.transform_3d = img->metadata.transform_3d;
-
- /* Create new texture. */
- if (type == IMAGE_DATA_TYPE_FLOAT4) {
- if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit)) {
- /* on failure to load, we set a 1x1 pixels pink image */
- thread_scoped_lock device_lock(device_mutex);
- float *pixels = (float *)img->mem->alloc(1, 1);
-
- pixels[0] = TEX_IMAGE_MISSING_R;
- pixels[1] = TEX_IMAGE_MISSING_G;
- pixels[2] = TEX_IMAGE_MISSING_B;
- pixels[3] = TEX_IMAGE_MISSING_A;
- }
- }
- else if (type == IMAGE_DATA_TYPE_FLOAT) {
- if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit)) {
- /* on failure to load, we set a 1x1 pixels pink image */
- thread_scoped_lock device_lock(device_mutex);
- float *pixels = (float *)img->mem->alloc(1, 1);
-
- pixels[0] = TEX_IMAGE_MISSING_R;
- }
- }
- else if (type == IMAGE_DATA_TYPE_BYTE4) {
- if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit)) {
- /* on failure to load, we set a 1x1 pixels pink image */
- thread_scoped_lock device_lock(device_mutex);
- uchar *pixels = (uchar *)img->mem->alloc(1, 1);
-
- pixels[0] = (TEX_IMAGE_MISSING_R * 255);
- pixels[1] = (TEX_IMAGE_MISSING_G * 255);
- pixels[2] = (TEX_IMAGE_MISSING_B * 255);
- pixels[3] = (TEX_IMAGE_MISSING_A * 255);
- }
- }
- else if (type == IMAGE_DATA_TYPE_BYTE) {
- if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit)) {
- /* on failure to load, we set a 1x1 pixels pink image */
- thread_scoped_lock device_lock(device_mutex);
- uchar *pixels = (uchar *)img->mem->alloc(1, 1);
-
- pixels[0] = (TEX_IMAGE_MISSING_R * 255);
- }
- }
- else if (type == IMAGE_DATA_TYPE_HALF4) {
- if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit)) {
- /* on failure to load, we set a 1x1 pixels pink image */
- thread_scoped_lock device_lock(device_mutex);
- half *pixels = (half *)img->mem->alloc(1, 1);
-
- pixels[0] = TEX_IMAGE_MISSING_R;
- pixels[1] = TEX_IMAGE_MISSING_G;
- pixels[2] = TEX_IMAGE_MISSING_B;
- pixels[3] = TEX_IMAGE_MISSING_A;
- }
- }
- else if (type == IMAGE_DATA_TYPE_USHORT) {
- if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit)) {
- /* on failure to load, we set a 1x1 pixels pink image */
- thread_scoped_lock device_lock(device_mutex);
- uint16_t *pixels = (uint16_t *)img->mem->alloc(1, 1);
-
- pixels[0] = (TEX_IMAGE_MISSING_R * 65535);
- }
- }
- else if (type == IMAGE_DATA_TYPE_USHORT4) {
- if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit)) {
- /* on failure to load, we set a 1x1 pixels pink image */
- thread_scoped_lock device_lock(device_mutex);
- uint16_t *pixels = (uint16_t *)img->mem->alloc(1, 1);
-
- pixels[0] = (TEX_IMAGE_MISSING_R * 65535);
- pixels[1] = (TEX_IMAGE_MISSING_G * 65535);
- pixels[2] = (TEX_IMAGE_MISSING_B * 65535);
- pixels[3] = (TEX_IMAGE_MISSING_A * 65535);
- }
- }
- else if (type == IMAGE_DATA_TYPE_HALF) {
- if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit)) {
- /* on failure to load, we set a 1x1 pixels pink image */
- thread_scoped_lock device_lock(device_mutex);
- half *pixels = (half *)img->mem->alloc(1, 1);
-
- pixels[0] = TEX_IMAGE_MISSING_R;
- }
- }
-#ifdef WITH_NANOVDB
- else if (type == IMAGE_DATA_TYPE_NANOVDB_FLOAT || type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
- thread_scoped_lock device_lock(device_mutex);
- void *pixels = img->mem->alloc(img->metadata.byte_size, 0);
-
- if (pixels != NULL) {
- img->loader->load_pixels(img->metadata, pixels, img->metadata.byte_size, false);
- }
- }
-#endif
-
- {
- thread_scoped_lock device_lock(device_mutex);
- img->mem->copy_to_device();
- }
-
- /* Cleanup memory in image loader. */
- img->loader->cleanup();
- img->need_load = false;
-}
-
-void ImageManager::device_free_image(Device *, int slot)
-{
- Image *img = images[slot];
- if (img == NULL) {
- return;
- }
-
- if (osl_texture_system) {
-#ifdef WITH_OSL
- ustring filepath = img->loader->osl_filepath();
- if (!filepath.empty()) {
- ((OSL::TextureSystem *)osl_texture_system)->invalidate(filepath);
- }
-#endif
- }
-
- if (img->mem) {
- thread_scoped_lock device_lock(device_mutex);
- delete img->mem;
- }
-
- delete img->loader;
- delete img;
- images[slot] = NULL;
-}
-
-void ImageManager::device_update(Device *device, Scene *scene, Progress &progress)
-{
- if (!need_update()) {
- return;
- }
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->image.times.add_entry({"device_update", time});
- }
- });
-
- TaskPool pool;
- for (size_t slot = 0; slot < images.size(); slot++) {
- Image *img = images[slot];
- if (img && img->users == 0) {
- device_free_image(device, slot);
- }
- else if (img && img->need_load) {
- pool.push(
- function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress));
- }
- }
-
- pool.wait_work();
-
- need_update_ = false;
-}
-
-void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress)
-{
- Image *img = images[slot];
- assert(img != NULL);
-
- if (img->users == 0) {
- device_free_image(device, slot);
- }
- else if (img->need_load) {
- device_load_image(device, scene, slot, progress);
- }
-}
-
-void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &progress)
-{
- /* Load only builtin images, Blender needs this to load evaluated
- * scene data from depsgraph before it is freed. */
- if (!need_update()) {
- return;
- }
-
- TaskPool pool;
- for (size_t slot = 0; slot < images.size(); slot++) {
- Image *img = images[slot];
- if (img && img->need_load && img->builtin) {
- pool.push(
- function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress));
- }
- }
-
- pool.wait_work();
-}
-
-void ImageManager::device_free_builtin(Device *device)
-{
- for (size_t slot = 0; slot < images.size(); slot++) {
- Image *img = images[slot];
- if (img && img->builtin) {
- device_free_image(device, slot);
- }
- }
-}
-
-void ImageManager::device_free(Device *device)
-{
- for (size_t slot = 0; slot < images.size(); slot++) {
- device_free_image(device, slot);
- }
- images.clear();
-}
-
-void ImageManager::collect_statistics(RenderStats *stats)
-{
- foreach (const Image *image, images) {
- stats->image.textures.add_entry(
- NamedSizeEntry(image->loader->name(), image->mem->memory_size()));
- }
-}
-
-void ImageManager::tag_update()
-{
- need_update_ = true;
-}
-
-bool ImageManager::need_update() const
-{
- return need_update_;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
deleted file mode 100644
index dede9513d5f..00000000000
--- a/intern/cycles/render/image.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __IMAGE_H__
-#define __IMAGE_H__
-
-#include "device/device_memory.h"
-
-#include "render/colorspace.h"
-
-#include "util/util_string.h"
-#include "util/util_thread.h"
-#include "util/util_transform.h"
-#include "util/util_unique_ptr.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceInfo;
-class ImageHandle;
-class ImageKey;
-class ImageMetaData;
-class ImageManager;
-class Progress;
-class RenderStats;
-class Scene;
-class ColorSpaceProcessor;
-class VDBImageLoader;
-
-/* Image Parameters */
-class ImageParams {
- public:
- bool animated;
- InterpolationType interpolation;
- ExtensionType extension;
- ImageAlphaType alpha_type;
- ustring colorspace;
- float frame;
-
- ImageParams()
- : animated(false),
- interpolation(INTERPOLATION_LINEAR),
- extension(EXTENSION_CLIP),
- alpha_type(IMAGE_ALPHA_AUTO),
- colorspace(u_colorspace_raw),
- frame(0.0f)
- {
- }
-
- bool operator==(const ImageParams &other) const
- {
- return (animated == other.animated && interpolation == other.interpolation &&
- extension == other.extension && alpha_type == other.alpha_type &&
- colorspace == other.colorspace && frame == other.frame);
- }
-};
-
-/* Image MetaData
- *
- * Information about the image that is available before the image pixels are loaded. */
-class ImageMetaData {
- public:
- /* Set by ImageLoader.load_metadata(). */
- int channels;
- size_t width, height, depth;
- size_t byte_size;
- ImageDataType type;
-
- /* Optional color space, defaults to raw. */
- ustring colorspace;
- const char *colorspace_file_format;
-
- /* Optional transform for 3D images. */
- bool use_transform_3d;
- Transform transform_3d;
-
- /* Automatically set. */
- bool compress_as_srgb;
-
- ImageMetaData();
- bool operator==(const ImageMetaData &other) const;
- bool is_float() const;
- void detect_colorspace();
-};
-
-/* Information about supported features that Image loaders can use. */
-class ImageDeviceFeatures {
- public:
- bool has_half_float;
- bool has_nanovdb;
-};
-
-/* Image loader base class, that can be subclassed to load image data
- * from custom sources (file, memory, procedurally generated, etc). */
-class ImageLoader {
- public:
- ImageLoader();
- virtual ~ImageLoader(){};
-
- /* Load metadata without actual image yet, should be fast. */
- virtual bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) = 0;
-
- /* Load actual image contents. */
- virtual bool load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t pixels_size,
- const bool associate_alpha) = 0;
-
- /* Name for logs and stats. */
- virtual string name() const = 0;
-
- /* Optional for OSL texture cache. */
- virtual ustring osl_filepath() const;
-
- /* Free any memory used for loading metadata and pixels. */
- virtual void cleanup(){};
-
- /* Compare avoid loading the same image multiple times. */
- virtual bool equals(const ImageLoader &other) const = 0;
- static bool equals(const ImageLoader *a, const ImageLoader *b);
-
- virtual bool is_vdb_loader() const;
-
- /* Work around for no RTTI. */
-};
-
-/* Image Handle
- *
- * Access handle for image in the image manager. Multiple shader nodes may
- * share the same image, and this class handles reference counting for that. */
-class ImageHandle {
- public:
- ImageHandle();
- ImageHandle(const ImageHandle &other);
- ImageHandle &operator=(const ImageHandle &other);
- ~ImageHandle();
-
- bool operator==(const ImageHandle &other) const;
-
- void clear();
-
- bool empty();
- int num_tiles();
-
- ImageMetaData metadata();
- int svm_slot(const int tile_index = 0) const;
- device_texture *image_memory(const int tile_index = 0) const;
-
- VDBImageLoader *vdb_loader(const int tile_index = 0) const;
-
- protected:
- vector<int> tile_slots;
- ImageManager *manager;
-
- friend class ImageManager;
-};
-
-/* Image Manager
- *
- * Handles loading and storage of all images in the scene. This includes 2D
- * texture images and 3D volume images. */
-class ImageManager {
- public:
- explicit ImageManager(const DeviceInfo &info);
- ~ImageManager();
-
- ImageHandle add_image(const string &filename, const ImageParams &params);
- ImageHandle add_image(const string &filename,
- const ImageParams &params,
- const array<int> &tiles);
- ImageHandle add_image(ImageLoader *loader, const ImageParams &params, const bool builtin = true);
-
- void device_update(Device *device, Scene *scene, Progress &progress);
- void device_update_slot(Device *device, Scene *scene, int slot, Progress *progress);
- void device_free(Device *device);
-
- void device_load_builtin(Device *device, Scene *scene, Progress &progress);
- void device_free_builtin(Device *device);
-
- void set_osl_texture_system(void *texture_system);
- bool set_animation_frame_update(int frame);
-
- void collect_statistics(RenderStats *stats);
-
- void tag_update();
-
- bool need_update() const;
-
- struct Image {
- ImageParams params;
- ImageMetaData metadata;
- ImageLoader *loader;
-
- float frame;
- bool need_metadata;
- bool need_load;
- bool builtin;
-
- string mem_name;
- device_texture *mem;
-
- int users;
- thread_mutex mutex;
- };
-
- private:
- bool need_update_;
-
- ImageDeviceFeatures features;
-
- thread_mutex device_mutex;
- thread_mutex images_mutex;
- int animation_frame;
-
- vector<Image *> images;
- void *osl_texture_system;
-
- int add_image_slot(ImageLoader *loader, const ImageParams &params, const bool builtin);
- void add_image_user(int slot);
- void remove_image_user(int slot);
-
- void load_image_metadata(Image *img);
-
- template<TypeDesc::BASETYPE FileFormat, typename StorageType>
- bool file_load_image(Image *img, int texture_limit);
-
- void device_load_image(Device *device, Scene *scene, int slot, Progress *progress);
- void device_free_image(Device *device, int slot);
-
- friend class ImageHandle;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __IMAGE_H__ */
diff --git a/intern/cycles/render/image_oiio.cpp b/intern/cycles/render/image_oiio.cpp
deleted file mode 100644
index 4867efe6ac0..00000000000
--- a/intern/cycles/render/image_oiio.cpp
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/image_oiio.h"
-
-#include "util/util_image.h"
-#include "util/util_logging.h"
-#include "util/util_path.h"
-
-CCL_NAMESPACE_BEGIN
-
-OIIOImageLoader::OIIOImageLoader(const string &filepath) : filepath(filepath)
-{
-}
-
-OIIOImageLoader::~OIIOImageLoader()
-{
-}
-
-bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata)
-{
- /* Perform preliminary checks, with meaningful logging. */
- if (!path_exists(filepath.string())) {
- VLOG(1) << "File '" << filepath.string() << "' does not exist.";
- return false;
- }
- if (path_is_directory(filepath.string())) {
- VLOG(1) << "File '" << filepath.string() << "' is a directory, can't use as image.";
- return false;
- }
-
- unique_ptr<ImageInput> in(ImageInput::create(filepath.string()));
-
- if (!in) {
- return false;
- }
-
- ImageSpec spec;
- if (!in->open(filepath.string(), spec)) {
- return false;
- }
-
- metadata.width = spec.width;
- metadata.height = spec.height;
- metadata.depth = spec.depth;
- metadata.compress_as_srgb = false;
-
- /* Check the main format, and channel formats. */
- size_t channel_size = spec.format.basesize();
-
- bool is_float = false;
- bool is_half = false;
-
- if (spec.format.is_floating_point()) {
- is_float = true;
- }
-
- for (size_t channel = 0; channel < spec.channelformats.size(); channel++) {
- channel_size = max(channel_size, spec.channelformats[channel].basesize());
- if (spec.channelformats[channel].is_floating_point()) {
- is_float = true;
- }
- }
-
- /* check if it's half float */
- if (spec.format == TypeDesc::HALF && features.has_half_float) {
- is_half = true;
- }
-
- /* set type and channels */
- metadata.channels = spec.nchannels;
-
- if (is_half) {
- metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF;
- }
- else if (is_float) {
- metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
- }
- else if (spec.format == TypeDesc::USHORT) {
- metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT;
- }
- else {
- metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
- }
-
- metadata.colorspace_file_format = in->format_name();
-
- in->close();
-
- return true;
-}
-
-template<TypeDesc::BASETYPE FileFormat, typename StorageType>
-static void oiio_load_pixels(const ImageMetaData &metadata,
- const unique_ptr<ImageInput> &in,
- StorageType *pixels)
-{
- const int width = metadata.width;
- const int height = metadata.height;
- const int depth = metadata.depth;
- const int components = metadata.channels;
-
- /* Read pixels through OpenImageIO. */
- StorageType *readpixels = pixels;
- vector<StorageType> tmppixels;
- if (components > 4) {
- tmppixels.resize(((size_t)width) * height * components);
- readpixels = &tmppixels[0];
- }
-
- if (depth <= 1) {
- size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType);
- in->read_image(FileFormat,
- (uchar *)readpixels + (height - 1) * scanlinesize,
- AutoStride,
- -scanlinesize,
- AutoStride);
- }
- else {
- in->read_image(FileFormat, (uchar *)readpixels);
- }
-
- if (components > 4) {
- size_t dimensions = ((size_t)width) * height;
- for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
- pixels[i * 4 + 3] = tmppixels[i * components + 3];
- pixels[i * 4 + 2] = tmppixels[i * components + 2];
- pixels[i * 4 + 1] = tmppixels[i * components + 1];
- pixels[i * 4 + 0] = tmppixels[i * components + 0];
- }
- tmppixels.clear();
- }
-
- /* CMYK to RGBA. */
- const bool cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4;
- if (cmyk) {
- const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
-
- const size_t num_pixels = ((size_t)width) * height * depth;
- for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- float c = util_image_cast_to_float(pixels[i * 4 + 0]);
- float m = util_image_cast_to_float(pixels[i * 4 + 1]);
- float y = util_image_cast_to_float(pixels[i * 4 + 2]);
- float k = util_image_cast_to_float(pixels[i * 4 + 3]);
- pixels[i * 4 + 0] = util_image_cast_from_float<StorageType>((1.0f - c) * (1.0f - k));
- pixels[i * 4 + 1] = util_image_cast_from_float<StorageType>((1.0f - m) * (1.0f - k));
- pixels[i * 4 + 2] = util_image_cast_from_float<StorageType>((1.0f - y) * (1.0f - k));
- pixels[i * 4 + 3] = one;
- }
- }
-}
-
-bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t,
- const bool associate_alpha)
-{
- unique_ptr<ImageInput> in = NULL;
-
- /* NOTE: Error logging is done in meta data acquisition. */
- if (!path_exists(filepath.string()) || path_is_directory(filepath.string())) {
- return false;
- }
-
- /* load image from file through OIIO */
- in = unique_ptr<ImageInput>(ImageInput::create(filepath.string()));
- if (!in) {
- return false;
- }
-
- ImageSpec spec = ImageSpec();
- ImageSpec config = ImageSpec();
-
- if (!associate_alpha) {
- config.attribute("oiio:UnassociatedAlpha", 1);
- }
-
- if (!in->open(filepath.string(), spec, config)) {
- return false;
- }
-
- switch (metadata.type) {
- case IMAGE_DATA_TYPE_BYTE:
- case IMAGE_DATA_TYPE_BYTE4:
- oiio_load_pixels<TypeDesc::UINT8, uchar>(metadata, in, (uchar *)pixels);
- break;
- case IMAGE_DATA_TYPE_USHORT:
- case IMAGE_DATA_TYPE_USHORT4:
- oiio_load_pixels<TypeDesc::USHORT, uint16_t>(metadata, in, (uint16_t *)pixels);
- break;
- case IMAGE_DATA_TYPE_HALF:
- case IMAGE_DATA_TYPE_HALF4:
- oiio_load_pixels<TypeDesc::HALF, half>(metadata, in, (half *)pixels);
- break;
- case IMAGE_DATA_TYPE_FLOAT:
- case IMAGE_DATA_TYPE_FLOAT4:
- oiio_load_pixels<TypeDesc::FLOAT, float>(metadata, in, (float *)pixels);
- break;
- case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
- case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
- case IMAGE_DATA_NUM_TYPES:
- break;
- }
-
- in->close();
- return true;
-}
-
-string OIIOImageLoader::name() const
-{
- return path_filename(filepath.string());
-}
-
-ustring OIIOImageLoader::osl_filepath() const
-{
- return filepath;
-}
-
-bool OIIOImageLoader::equals(const ImageLoader &other) const
-{
- const OIIOImageLoader &other_loader = (const OIIOImageLoader &)other;
- return filepath == other_loader.filepath;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image_oiio.h b/intern/cycles/render/image_oiio.h
deleted file mode 100644
index a6dbb168b65..00000000000
--- a/intern/cycles/render/image_oiio.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __IMAGE_OIIO__
-#define __IMAGE_OIIO__
-
-#include "render/image.h"
-
-CCL_NAMESPACE_BEGIN
-
-class OIIOImageLoader : public ImageLoader {
- public:
- OIIOImageLoader(const string &filepath);
- ~OIIOImageLoader();
-
- bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
-
- bool load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t pixels_size,
- const bool associate_alpha) override;
-
- string name() const override;
-
- ustring osl_filepath() const override;
-
- bool equals(const ImageLoader &other) const override;
-
- protected:
- ustring filepath;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __IMAGE_OIIO__ */
diff --git a/intern/cycles/render/image_sky.cpp b/intern/cycles/render/image_sky.cpp
deleted file mode 100644
index 7f9b85836f8..00000000000
--- a/intern/cycles/render/image_sky.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/image_sky.h"
-
-#include "sky_model.h"
-
-#include "util/util_image.h"
-#include "util/util_logging.h"
-#include "util/util_path.h"
-#include "util/util_task.h"
-
-CCL_NAMESPACE_BEGIN
-
-SkyLoader::SkyLoader(float sun_elevation,
- float altitude,
- float air_density,
- float dust_density,
- float ozone_density)
- : sun_elevation(sun_elevation),
- altitude(altitude),
- air_density(air_density),
- dust_density(dust_density),
- ozone_density(ozone_density)
-{
-}
-
-SkyLoader::~SkyLoader(){};
-
-bool SkyLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
-{
- metadata.width = 512;
- metadata.height = 128;
- metadata.channels = 3;
- metadata.depth = 1;
- metadata.type = IMAGE_DATA_TYPE_FLOAT4;
- metadata.compress_as_srgb = false;
- return true;
-}
-
-bool SkyLoader::load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t /*pixels_size*/,
- const bool /*associate_alpha*/)
-{
- /* definitions */
- int width = metadata.width;
- int height = metadata.height;
- float *pixel_data = (float *)pixels;
-
- /* precompute sky texture */
- const int rows_per_task = divide_up(1024, width);
- parallel_for(blocked_range<size_t>(0, height, rows_per_task),
- [&](const blocked_range<size_t> &r) {
- SKY_nishita_skymodel_precompute_texture(pixel_data,
- metadata.channels,
- r.begin(),
- r.end(),
- width,
- height,
- sun_elevation,
- altitude,
- air_density,
- dust_density,
- ozone_density);
- });
-
- return true;
-}
-
-string SkyLoader::name() const
-{
- return "sky_nishita";
-}
-
-bool SkyLoader::equals(const ImageLoader & /*other*/) const
-{
- return false;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image_sky.h b/intern/cycles/render/image_sky.h
deleted file mode 100644
index 89ff586e7fd..00000000000
--- a/intern/cycles/render/image_sky.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/image.h"
-
-CCL_NAMESPACE_BEGIN
-
-class SkyLoader : public ImageLoader {
- private:
- float sun_elevation;
- float altitude;
- float air_density;
- float dust_density;
- float ozone_density;
-
- public:
- SkyLoader(float sun_elevation,
- float altitude,
- float air_density,
- float dust_density,
- float ozone_density);
- ~SkyLoader();
-
- bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
-
- bool load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t /*pixels_size*/,
- const bool /*associate_alpha*/) override;
-
- string name() const override;
-
- bool equals(const ImageLoader & /*other*/) const override;
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image_vdb.cpp b/intern/cycles/render/image_vdb.cpp
deleted file mode 100644
index 4da11c8a140..00000000000
--- a/intern/cycles/render/image_vdb.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/image_vdb.h"
-
-#include "util/util_logging.h"
-#include "util/util_openvdb.h"
-
-#ifdef WITH_OPENVDB
-# include <openvdb/tools/Dense.h>
-#endif
-#ifdef WITH_NANOVDB
-# include <nanovdb/util/OpenToNanoVDB.h>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef WITH_OPENVDB
-struct NumChannelsOp {
- int num_channels = 0;
-
- template<typename GridType, typename FloatGridType, typename FloatDataType, int channels>
- bool operator()(const openvdb::GridBase::ConstPtr &)
- {
- num_channels = channels;
- return true;
- }
-};
-
-struct ToDenseOp {
- openvdb::CoordBBox bbox;
- void *pixels;
-
- template<typename GridType, typename FloatGridType, typename FloatDataType, int channels>
- bool operator()(const openvdb::GridBase::ConstPtr &grid)
- {
- openvdb::tools::Dense<FloatDataType, openvdb::tools::LayoutXYZ> dense(bbox,
- (FloatDataType *)pixels);
- openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<GridType>(grid), dense);
- return true;
- }
-};
-
-# ifdef WITH_NANOVDB
-struct ToNanoOp {
- nanovdb::GridHandle<> nanogrid;
-
- template<typename GridType, typename FloatGridType, typename FloatDataType, int channels>
- bool operator()(const openvdb::GridBase::ConstPtr &grid)
- {
- if constexpr (!std::is_same_v<GridType, openvdb::MaskGrid>) {
- try {
- nanogrid = nanovdb::openToNanoVDB(
- FloatGridType(*openvdb::gridConstPtrCast<GridType>(grid)));
- }
- catch (const std::exception &e) {
- VLOG(1) << "Error converting OpenVDB to NanoVDB grid: " << e.what();
- }
- return true;
- }
- else {
- return false;
- }
- }
-};
-# endif
-#endif
-
-VDBImageLoader::VDBImageLoader(const string &grid_name) : grid_name(grid_name)
-{
-}
-
-VDBImageLoader::~VDBImageLoader()
-{
-}
-
-bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata)
-{
-#ifdef WITH_OPENVDB
- if (!grid) {
- return false;
- }
-
- /* Get number of channels from type. */
- NumChannelsOp op;
- if (!openvdb::grid_type_operation(grid, op)) {
- return false;
- }
-
- metadata.channels = op.num_channels;
-
- /* Set data type. */
-# ifdef WITH_NANOVDB
- if (features.has_nanovdb) {
- /* NanoVDB expects no inactive leaf nodes. */
- /*openvdb::FloatGrid &pruned_grid = *openvdb::gridPtrCast<openvdb::FloatGrid>(grid);
- openvdb::tools::pruneInactive(pruned_grid.tree());
- nanogrid = nanovdb::openToNanoVDB(pruned_grid);*/
- ToNanoOp op;
- if (!openvdb::grid_type_operation(grid, op)) {
- return false;
- }
- nanogrid = std::move(op.nanogrid);
- }
-# endif
-
- /* Set dimensions. */
- bbox = grid->evalActiveVoxelBoundingBox();
- if (bbox.empty()) {
- return false;
- }
-
- openvdb::Coord dim = bbox.dim();
- metadata.width = dim.x();
- metadata.height = dim.y();
- metadata.depth = dim.z();
-
-# ifdef WITH_NANOVDB
- if (nanogrid) {
- metadata.byte_size = nanogrid.size();
- if (metadata.channels == 1) {
- metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT;
- }
- else {
- metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT3;
- }
- }
- else
-# endif
- {
- if (metadata.channels == 1) {
- metadata.type = IMAGE_DATA_TYPE_FLOAT;
- }
- else {
- metadata.type = IMAGE_DATA_TYPE_FLOAT4;
- }
- }
-
- /* Set transform from object space to voxel index. */
- openvdb::math::Mat4f grid_matrix = grid->transform().baseMap()->getAffineMap()->getMat4();
- Transform index_to_object;
- for (int col = 0; col < 4; col++) {
- for (int row = 0; row < 3; row++) {
- index_to_object[row][col] = (float)grid_matrix[col][row];
- }
- }
-
- Transform texture_to_index;
-# ifdef WITH_NANOVDB
- if (nanogrid) {
- texture_to_index = transform_identity();
- }
- else
-# endif
- {
- openvdb::Coord min = bbox.min();
- texture_to_index = transform_translate(min.x(), min.y(), min.z()) *
- transform_scale(dim.x(), dim.y(), dim.z());
- }
-
- metadata.transform_3d = transform_inverse(index_to_object * texture_to_index);
- metadata.use_transform_3d = true;
-
-# ifndef WITH_NANOVDB
- (void)features;
-# endif
- return true;
-#else
- (void)metadata;
- (void)features;
- return false;
-#endif
-}
-
-bool VDBImageLoader::load_pixels(const ImageMetaData &, void *pixels, const size_t, const bool)
-{
-#ifdef WITH_OPENVDB
-# ifdef WITH_NANOVDB
- if (nanogrid) {
- memcpy(pixels, nanogrid.data(), nanogrid.size());
- }
- else
-# endif
- {
- ToDenseOp op;
- op.pixels = pixels;
- op.bbox = bbox;
- openvdb::grid_type_operation(grid, op);
- }
- return true;
-#else
- (void)pixels;
- return false;
-#endif
-}
-
-string VDBImageLoader::name() const
-{
- return grid_name;
-}
-
-bool VDBImageLoader::equals(const ImageLoader &other) const
-{
-#ifdef WITH_OPENVDB
- const VDBImageLoader &other_loader = (const VDBImageLoader &)other;
- return grid == other_loader.grid;
-#else
- (void)other;
- return true;
-#endif
-}
-
-void VDBImageLoader::cleanup()
-{
-#ifdef WITH_OPENVDB
- /* Free OpenVDB grid memory as soon as we can. */
- grid.reset();
-#endif
-#ifdef WITH_NANOVDB
- nanogrid.reset();
-#endif
-}
-
-bool VDBImageLoader::is_vdb_loader() const
-{
- return true;
-}
-
-#ifdef WITH_OPENVDB
-openvdb::GridBase::ConstPtr VDBImageLoader::get_grid()
-{
- return grid;
-}
-#endif
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image_vdb.h b/intern/cycles/render/image_vdb.h
deleted file mode 100644
index 763196f2a15..00000000000
--- a/intern/cycles/render/image_vdb.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __IMAGE_VDB__
-#define __IMAGE_VDB__
-
-#ifdef WITH_OPENVDB
-# include <openvdb/openvdb.h>
-#endif
-#ifdef WITH_NANOVDB
-# include <nanovdb/util/GridHandle.h>
-#endif
-
-#include "render/image.h"
-
-CCL_NAMESPACE_BEGIN
-
-class VDBImageLoader : public ImageLoader {
- public:
- VDBImageLoader(const string &grid_name);
- ~VDBImageLoader();
-
- virtual bool load_metadata(const ImageDeviceFeatures &features,
- ImageMetaData &metadata) override;
-
- virtual bool load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t pixels_size,
- const bool associate_alpha) override;
-
- virtual string name() const override;
-
- virtual bool equals(const ImageLoader &other) const override;
-
- virtual void cleanup() override;
-
- virtual bool is_vdb_loader() const override;
-
-#ifdef WITH_OPENVDB
- openvdb::GridBase::ConstPtr get_grid();
-#endif
-
- protected:
- string grid_name;
-#ifdef WITH_OPENVDB
- openvdb::GridBase::ConstPtr grid;
- openvdb::CoordBBox bbox;
-#endif
-#ifdef WITH_NANOVDB
- nanovdb::GridHandle<> nanogrid;
-#endif
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __IMAGE_VDB__ */
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
deleted file mode 100644
index d74d14242bb..00000000000
--- a/intern/cycles/render/integrator.cpp
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/integrator.h"
-#include "device/device.h"
-#include "render/background.h"
-#include "render/camera.h"
-#include "render/film.h"
-#include "render/jitter.h"
-#include "render/light.h"
-#include "render/object.h"
-#include "render/scene.h"
-#include "render/shader.h"
-#include "render/sobol.h"
-#include "render/stats.h"
-
-#include "kernel/kernel_types.h"
-
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-#include "util/util_logging.h"
-#include "util/util_task.h"
-#include "util/util_time.h"
-
-CCL_NAMESPACE_BEGIN
-
-NODE_DEFINE(Integrator)
-{
- NodeType *type = NodeType::add("integrator", create);
-
- SOCKET_INT(min_bounce, "Min Bounce", 0);
- SOCKET_INT(max_bounce, "Max Bounce", 7);
-
- SOCKET_INT(max_diffuse_bounce, "Max Diffuse Bounce", 7);
- SOCKET_INT(max_glossy_bounce, "Max Glossy Bounce", 7);
- SOCKET_INT(max_transmission_bounce, "Max Transmission Bounce", 7);
- SOCKET_INT(max_volume_bounce, "Max Volume Bounce", 7);
-
- SOCKET_INT(transparent_min_bounce, "Transparent Min Bounce", 0);
- SOCKET_INT(transparent_max_bounce, "Transparent Max Bounce", 7);
-
- SOCKET_INT(ao_bounces, "AO Bounces", 0);
- SOCKET_FLOAT(ao_factor, "AO Factor", 0.0f);
- SOCKET_FLOAT(ao_distance, "AO Distance", FLT_MAX);
-
- SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024);
- SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
-
- SOCKET_BOOLEAN(caustics_reflective, "Reflective Caustics", true);
- SOCKET_BOOLEAN(caustics_refractive, "Refractive Caustics", true);
- SOCKET_FLOAT(filter_glossy, "Filter Glossy", 0.0f);
- SOCKET_INT(seed, "Seed", 0);
- SOCKET_FLOAT(sample_clamp_direct, "Sample Clamp Direct", 0.0f);
- SOCKET_FLOAT(sample_clamp_indirect, "Sample Clamp Indirect", 0.0f);
- SOCKET_BOOLEAN(motion_blur, "Motion Blur", false);
-
- SOCKET_INT(aa_samples, "AA Samples", 0);
- SOCKET_INT(start_sample, "Start Sample", 0);
-
- SOCKET_BOOLEAN(use_adaptive_sampling, "Use Adaptive Sampling", false);
- SOCKET_FLOAT(adaptive_threshold, "Adaptive Threshold", 0.0f);
- SOCKET_INT(adaptive_min_samples, "Adaptive Min Samples", 0);
-
- SOCKET_FLOAT(light_sampling_threshold, "Light Sampling Threshold", 0.05f);
-
- static NodeEnum sampling_pattern_enum;
- sampling_pattern_enum.insert("sobol", SAMPLING_PATTERN_SOBOL);
- sampling_pattern_enum.insert("pmj", SAMPLING_PATTERN_PMJ);
- SOCKET_ENUM(sampling_pattern, "Sampling Pattern", sampling_pattern_enum, SAMPLING_PATTERN_SOBOL);
-
- static NodeEnum denoiser_type_enum;
- denoiser_type_enum.insert("optix", DENOISER_OPTIX);
- denoiser_type_enum.insert("openimagedenoise", DENOISER_OPENIMAGEDENOISE);
-
- static NodeEnum denoiser_prefilter_enum;
- denoiser_prefilter_enum.insert("none", DENOISER_PREFILTER_NONE);
- denoiser_prefilter_enum.insert("fast", DENOISER_PREFILTER_FAST);
- denoiser_prefilter_enum.insert("accurate", DENOISER_PREFILTER_ACCURATE);
-
- /* Default to accurate denoising with OpenImageDenoise. For interactive viewport
- * it's best use OptiX and disable the normal pass since it does not always have
- * the desired effect for that denoiser. */
- SOCKET_BOOLEAN(use_denoise, "Use Denoiser", false);
- SOCKET_ENUM(denoiser_type, "Denoiser Type", denoiser_type_enum, DENOISER_OPENIMAGEDENOISE);
- SOCKET_INT(denoise_start_sample, "Start Sample to Denoise", 0);
- SOCKET_BOOLEAN(use_denoise_pass_albedo, "Use Albedo Pass for Denoiser", true);
- SOCKET_BOOLEAN(use_denoise_pass_normal, "Use Normal Pass for Denoiser", true);
- SOCKET_ENUM(
- denoiser_prefilter, "Denoiser Type", denoiser_prefilter_enum, DENOISER_PREFILTER_ACCURATE);
-
- return type;
-}
-
-Integrator::Integrator() : Node(get_node_type())
-{
-}
-
-Integrator::~Integrator()
-{
-}
-
-void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene)
-{
- if (!is_modified())
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->integrator.times.add_entry({"device_update", time});
- }
- });
-
- KernelIntegrator *kintegrator = &dscene->data.integrator;
-
- /* Adaptive sampling requires PMJ samples.
- *
- * This also makes detection of sampling pattern a bit more involved: can not rely on the changed
- * state of socket, since its value might be different from the effective value used here. So
- * instead compare with previous value in the KernelIntegrator. Only do it if the device was
- * updated once (in which case the `sample_pattern_lut` will be allocated to a non-zero size). */
- const SamplingPattern new_sampling_pattern = (use_adaptive_sampling) ? SAMPLING_PATTERN_PMJ :
- sampling_pattern;
-
- const bool need_update_lut = max_bounce_is_modified() || max_transmission_bounce_is_modified() ||
- dscene->sample_pattern_lut.size() == 0 ||
- kintegrator->sampling_pattern != new_sampling_pattern;
-
- if (need_update_lut) {
- dscene->sample_pattern_lut.tag_realloc();
- }
-
- device_free(device, dscene);
-
- /* integrator parameters */
- kintegrator->min_bounce = min_bounce + 1;
- kintegrator->max_bounce = max_bounce + 1;
-
- kintegrator->max_diffuse_bounce = max_diffuse_bounce + 1;
- kintegrator->max_glossy_bounce = max_glossy_bounce + 1;
- kintegrator->max_transmission_bounce = max_transmission_bounce + 1;
- kintegrator->max_volume_bounce = max_volume_bounce + 1;
-
- kintegrator->transparent_min_bounce = transparent_min_bounce + 1;
- kintegrator->transparent_max_bounce = transparent_max_bounce + 1;
-
- kintegrator->ao_bounces = ao_bounces;
- kintegrator->ao_bounces_distance = ao_distance;
- kintegrator->ao_bounces_factor = ao_factor;
-
- /* Transparent Shadows
- * We only need to enable transparent shadows, if we actually have
- * transparent shaders in the scene. Otherwise we can disable it
- * to improve performance a bit. */
- kintegrator->transparent_shadows = false;
- foreach (Shader *shader, scene->shaders) {
- /* keep this in sync with SD_HAS_TRANSPARENT_SHADOW in shader.cpp */
- if ((shader->has_surface_transparent && shader->get_use_transparent_shadow()) ||
- shader->has_volume) {
- kintegrator->transparent_shadows = true;
- break;
- }
- }
-
- kintegrator->volume_max_steps = volume_max_steps;
- kintegrator->volume_step_rate = volume_step_rate;
-
- kintegrator->caustics_reflective = caustics_reflective;
- kintegrator->caustics_refractive = caustics_refractive;
- kintegrator->filter_glossy = (filter_glossy == 0.0f) ? FLT_MAX : 1.0f / filter_glossy;
-
- kintegrator->seed = seed;
-
- kintegrator->sample_clamp_direct = (sample_clamp_direct == 0.0f) ? FLT_MAX :
- sample_clamp_direct * 3.0f;
- kintegrator->sample_clamp_indirect = (sample_clamp_indirect == 0.0f) ?
- FLT_MAX :
- sample_clamp_indirect * 3.0f;
-
- kintegrator->sampling_pattern = new_sampling_pattern;
-
- if (light_sampling_threshold > 0.0f) {
- kintegrator->light_inv_rr_threshold = 1.0f / light_sampling_threshold;
- }
- else {
- kintegrator->light_inv_rr_threshold = 0.0f;
- }
-
- /* sobol directions table */
- int max_samples = max_bounce + transparent_max_bounce + 3 + VOLUME_BOUNDS_MAX +
- max(BSSRDF_MAX_HITS, BSSRDF_MAX_BOUNCES);
-
- int dimensions = PRNG_BASE_NUM + max_samples * PRNG_BOUNCE_NUM;
- dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS);
-
- if (need_update_lut) {
- if (kintegrator->sampling_pattern == SAMPLING_PATTERN_SOBOL) {
- uint *directions = (uint *)dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions);
-
- sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
-
- dscene->sample_pattern_lut.copy_to_device();
- }
- else {
- constexpr int sequence_size = NUM_PMJ_SAMPLES;
- constexpr int num_sequences = NUM_PMJ_PATTERNS;
- float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size *
- num_sequences * 2);
- TaskPool pool;
- for (int j = 0; j < num_sequences; ++j) {
- float2 *sequence = directions + j * sequence_size;
- pool.push(
- function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j));
- }
- pool.wait_work();
-
- dscene->sample_pattern_lut.copy_to_device();
- }
- }
-
- kintegrator->has_shadow_catcher = scene->has_shadow_catcher();
-
- dscene->sample_pattern_lut.clear_modified();
- clear_modified();
-}
-
-void Integrator::device_free(Device *, DeviceScene *dscene, bool force_free)
-{
- dscene->sample_pattern_lut.free_if_need_realloc(force_free);
-}
-
-void Integrator::tag_update(Scene *scene, uint32_t flag)
-{
- if (flag & UPDATE_ALL) {
- tag_modified();
- }
-
- if (flag & AO_PASS_MODIFIED) {
- /* tag only the ao_bounces socket as modified so we avoid updating sample_pattern_lut
- * unnecessarily */
- tag_ao_bounces_modified();
- }
-
- if (filter_glossy_is_modified()) {
- foreach (Shader *shader, scene->shaders) {
- if (shader->has_integrator_dependency) {
- scene->shader_manager->tag_update(scene, ShaderManager::INTEGRATOR_MODIFIED);
- break;
- }
- }
- }
-
- if (motion_blur_is_modified()) {
- scene->object_manager->tag_update(scene, ObjectManager::MOTION_BLUR_MODIFIED);
- scene->camera->tag_modified();
- }
-}
-
-AdaptiveSampling Integrator::get_adaptive_sampling() const
-{
- AdaptiveSampling adaptive_sampling;
-
- adaptive_sampling.use = use_adaptive_sampling;
-
- if (!adaptive_sampling.use) {
- return adaptive_sampling;
- }
-
- if (aa_samples > 0 && adaptive_threshold == 0.0f) {
- adaptive_sampling.threshold = max(0.001f, 1.0f / (float)aa_samples);
- VLOG(1) << "Cycles adaptive sampling: automatic threshold = " << adaptive_sampling.threshold;
- }
- else {
- adaptive_sampling.threshold = adaptive_threshold;
- }
-
- if (adaptive_sampling.threshold > 0 && adaptive_min_samples == 0) {
- /* Threshold 0.1 -> 32, 0.01 -> 64, 0.001 -> 128.
- * This is highly scene dependent, we make a guess that seemed to work well
- * in various test scenes. */
- const int min_samples = (int)ceilf(16.0f / powf(adaptive_sampling.threshold, 0.3f));
- adaptive_sampling.min_samples = max(4, min_samples);
- VLOG(1) << "Cycles adaptive sampling: automatic min samples = "
- << adaptive_sampling.min_samples;
- }
- else {
- adaptive_sampling.min_samples = max(4, adaptive_min_samples);
- }
-
- /* Arbitrary factor that makes the threshold more similar to what is was before,
- * and gives arguably more intuitive values. */
- adaptive_sampling.threshold *= 5.0f;
-
- adaptive_sampling.adaptive_step = 16;
-
- DCHECK(is_power_of_two(adaptive_sampling.adaptive_step))
- << "Adaptive step must be a power of two for bitwise operations to work";
-
- return adaptive_sampling;
-}
-
-DenoiseParams Integrator::get_denoise_params() const
-{
- DenoiseParams denoise_params;
-
- denoise_params.use = use_denoise;
-
- denoise_params.type = denoiser_type;
-
- denoise_params.start_sample = denoise_start_sample;
-
- denoise_params.use_pass_albedo = use_denoise_pass_albedo;
- denoise_params.use_pass_normal = use_denoise_pass_normal;
-
- denoise_params.prefilter = denoiser_prefilter;
-
- return denoise_params;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h
deleted file mode 100644
index 5ad419e02ca..00000000000
--- a/intern/cycles/render/integrator.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __INTEGRATOR_H__
-#define __INTEGRATOR_H__
-
-#include "kernel/kernel_types.h"
-
-#include "device/device_denoise.h" /* For the parameters and type enum. */
-#include "graph/node.h"
-#include "integrator/adaptive_sampling.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class Scene;
-
-class Integrator : public Node {
- public:
- NODE_DECLARE
-
- NODE_SOCKET_API(int, min_bounce)
- NODE_SOCKET_API(int, max_bounce)
-
- NODE_SOCKET_API(int, max_diffuse_bounce)
- NODE_SOCKET_API(int, max_glossy_bounce)
- NODE_SOCKET_API(int, max_transmission_bounce)
- NODE_SOCKET_API(int, max_volume_bounce)
-
- NODE_SOCKET_API(int, transparent_min_bounce)
- NODE_SOCKET_API(int, transparent_max_bounce)
-
- NODE_SOCKET_API(int, ao_bounces)
- NODE_SOCKET_API(float, ao_factor)
- NODE_SOCKET_API(float, ao_distance)
-
- NODE_SOCKET_API(int, volume_max_steps)
- NODE_SOCKET_API(float, volume_step_rate)
-
- NODE_SOCKET_API(bool, caustics_reflective)
- NODE_SOCKET_API(bool, caustics_refractive)
- NODE_SOCKET_API(float, filter_glossy)
-
- NODE_SOCKET_API(int, seed)
-
- NODE_SOCKET_API(float, sample_clamp_direct)
- NODE_SOCKET_API(float, sample_clamp_indirect)
- NODE_SOCKET_API(bool, motion_blur)
-
- /* Maximum number of samples, beyond which we are likely to run into
- * precision issues for sampling patterns. */
- static const int MAX_SAMPLES = (1 << 24);
-
- NODE_SOCKET_API(int, aa_samples)
- NODE_SOCKET_API(int, start_sample)
-
- NODE_SOCKET_API(float, light_sampling_threshold)
-
- NODE_SOCKET_API(bool, use_adaptive_sampling)
- NODE_SOCKET_API(int, adaptive_min_samples)
- NODE_SOCKET_API(float, adaptive_threshold)
-
- NODE_SOCKET_API(SamplingPattern, sampling_pattern)
-
- NODE_SOCKET_API(bool, use_denoise);
- NODE_SOCKET_API(DenoiserType, denoiser_type);
- NODE_SOCKET_API(int, denoise_start_sample);
- NODE_SOCKET_API(bool, use_denoise_pass_albedo);
- NODE_SOCKET_API(bool, use_denoise_pass_normal);
- NODE_SOCKET_API(DenoiserPrefilter, denoiser_prefilter);
-
- enum : uint32_t {
- AO_PASS_MODIFIED = (1 << 0),
- OBJECT_MANAGER = (1 << 1),
-
- /* tag everything in the manager for an update */
- UPDATE_ALL = ~0u,
-
- UPDATE_NONE = 0u,
- };
-
- Integrator();
- ~Integrator();
-
- void device_update(Device *device, DeviceScene *dscene, Scene *scene);
- void device_free(Device *device, DeviceScene *dscene, bool force_free = false);
-
- void tag_update(Scene *scene, uint32_t flag);
-
- AdaptiveSampling get_adaptive_sampling() const;
- DenoiseParams get_denoise_params() const;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __INTEGRATOR_H__ */
diff --git a/intern/cycles/render/jitter.cpp b/intern/cycles/render/jitter.cpp
deleted file mode 100644
index e31f8abd446..00000000000
--- a/intern/cycles/render/jitter.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright 2019 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* This file is based on "Progressive Multi-Jittered Sample Sequences"
- * by Per Christensen, Andrew Kensler and Charlie Kilpatrick.
- * http://graphics.pixar.com/library/ProgressiveMultiJitteredSampling/paper.pdf
- *
- * Performance can be improved in the future by implementing the new
- * algorithm from Matt Pharr in http://jcgt.org/published/0008/01/04/
- * "Efficient Generation of Points that Satisfy Two-Dimensional Elementary Intervals"
- */
-
-#include "render/jitter.h"
-
-#include <math.h>
-#include <vector>
-
-CCL_NAMESPACE_BEGIN
-
-static uint cmj_hash(uint i, uint p)
-{
- i ^= p;
- i ^= i >> 17;
- i ^= i >> 10;
- i *= 0xb36534e5;
- i ^= i >> 12;
- i ^= i >> 21;
- i *= 0x93fc4795;
- i ^= 0xdf6e307f;
- i ^= i >> 17;
- i *= 1 | p >> 18;
-
- return i;
-}
-
-static float cmj_randfloat(uint i, uint p)
-{
- return cmj_hash(i, p) * (1.0f / 4294967808.0f);
-}
-
-class PMJ_Generator {
- public:
- static void generate_2D(float2 points[], int size, int rng_seed_in)
- {
- PMJ_Generator g(rng_seed_in);
- points[0].x = g.rnd();
- points[0].y = g.rnd();
- int N = 1;
- while (N < size) {
- g.extend_sequence_even(points, N);
- g.extend_sequence_odd(points, 2 * N);
- N = 4 * N;
- }
- }
-
- protected:
- PMJ_Generator(int rnd_seed_in) : num_samples(1), rnd_index(2), rnd_seed(rnd_seed_in)
- {
- }
-
- float rnd()
- {
- return cmj_randfloat(++rnd_index, rnd_seed);
- }
-
- virtual void mark_occupied_strata(float2 points[], int N)
- {
- int NN = 2 * N;
- for (int s = 0; s < NN; ++s) {
- occupied1Dx[s] = occupied1Dy[s] = false;
- }
- for (int s = 0; s < N; ++s) {
- int xstratum = (int)(NN * points[s].x);
- int ystratum = (int)(NN * points[s].y);
- occupied1Dx[xstratum] = true;
- occupied1Dy[ystratum] = true;
- }
- }
-
- virtual void generate_sample_point(
- float2 points[], float i, float j, float xhalf, float yhalf, int n, int N)
- {
- int NN = 2 * N;
- float2 pt;
- int xstratum, ystratum;
- do {
- pt.x = (i + 0.5f * (xhalf + rnd())) / n;
- xstratum = (int)(NN * pt.x);
- } while (occupied1Dx[xstratum]);
- do {
- pt.y = (j + 0.5f * (yhalf + rnd())) / n;
- ystratum = (int)(NN * pt.y);
- } while (occupied1Dy[ystratum]);
- occupied1Dx[xstratum] = true;
- occupied1Dy[ystratum] = true;
- points[num_samples] = pt;
- ++num_samples;
- }
-
- void extend_sequence_even(float2 points[], int N)
- {
- int n = (int)sqrtf(N);
- occupied1Dx.resize(2 * N);
- occupied1Dy.resize(2 * N);
- mark_occupied_strata(points, N);
- for (int s = 0; s < N; ++s) {
- float2 oldpt = points[s];
- float i = floorf(n * oldpt.x);
- float j = floorf(n * oldpt.y);
- float xhalf = floorf(2.0f * (n * oldpt.x - i));
- float yhalf = floorf(2.0f * (n * oldpt.y - j));
- xhalf = 1.0f - xhalf;
- yhalf = 1.0f - yhalf;
- generate_sample_point(points, i, j, xhalf, yhalf, n, N);
- }
- }
-
- void extend_sequence_odd(float2 points[], int N)
- {
- int n = (int)sqrtf(N / 2);
- occupied1Dx.resize(2 * N);
- occupied1Dy.resize(2 * N);
- mark_occupied_strata(points, N);
- std::vector<float> xhalves(N / 2);
- std::vector<float> yhalves(N / 2);
- for (int s = 0; s < N / 2; ++s) {
- float2 oldpt = points[s];
- float i = floorf(n * oldpt.x);
- float j = floorf(n * oldpt.y);
- float xhalf = floorf(2.0f * (n * oldpt.x - i));
- float yhalf = floorf(2.0f * (n * oldpt.y - j));
- if (rnd() > 0.5f) {
- xhalf = 1.0f - xhalf;
- }
- else {
- yhalf = 1.0f - yhalf;
- }
- xhalves[s] = xhalf;
- yhalves[s] = yhalf;
- generate_sample_point(points, i, j, xhalf, yhalf, n, N);
- }
- for (int s = 0; s < N / 2; ++s) {
- float2 oldpt = points[s];
- float i = floorf(n * oldpt.x);
- float j = floorf(n * oldpt.y);
- float xhalf = 1.0f - xhalves[s];
- float yhalf = 1.0f - yhalves[s];
- generate_sample_point(points, i, j, xhalf, yhalf, n, N);
- }
- }
-
- std::vector<bool> occupied1Dx, occupied1Dy;
- int num_samples;
- int rnd_index, rnd_seed;
-};
-
-class PMJ02_Generator : public PMJ_Generator {
- protected:
- void generate_sample_point(
- float2 points[], float i, float j, float xhalf, float yhalf, int n, int N) override
- {
- int NN = 2 * N;
- float2 pt;
- do {
- pt.x = (i + 0.5f * (xhalf + rnd())) / n;
- pt.y = (j + 0.5f * (yhalf + rnd())) / n;
- } while (is_occupied(pt, NN));
- mark_occupied_strata1(pt, NN);
- points[num_samples] = pt;
- ++num_samples;
- }
-
- void mark_occupied_strata(float2 points[], int N) override
- {
- int NN = 2 * N;
- int num_shapes = (int)log2f(NN) + 1;
- occupiedStrata.resize(num_shapes);
- for (int shape = 0; shape < num_shapes; ++shape) {
- occupiedStrata[shape].resize(NN);
- for (int n = 0; n < NN; ++n) {
- occupiedStrata[shape][n] = false;
- }
- }
- for (int s = 0; s < N; ++s) {
- mark_occupied_strata1(points[s], NN);
- }
- }
-
- void mark_occupied_strata1(float2 pt, int NN)
- {
- int shape = 0;
- int xdivs = NN;
- int ydivs = 1;
- do {
- int xstratum = (int)(xdivs * pt.x);
- int ystratum = (int)(ydivs * pt.y);
- size_t index = ystratum * xdivs + xstratum;
- assert(index < NN);
- occupiedStrata[shape][index] = true;
- shape = shape + 1;
- xdivs = xdivs / 2;
- ydivs = ydivs * 2;
- } while (xdivs > 0);
- }
-
- bool is_occupied(float2 pt, int NN)
- {
- int shape = 0;
- int xdivs = NN;
- int ydivs = 1;
- do {
- int xstratum = (int)(xdivs * pt.x);
- int ystratum = (int)(ydivs * pt.y);
- size_t index = ystratum * xdivs + xstratum;
- assert(index < NN);
- if (occupiedStrata[shape][index]) {
- return true;
- }
- shape = shape + 1;
- xdivs = xdivs / 2;
- ydivs = ydivs * 2;
- } while (xdivs > 0);
- return false;
- }
-
- private:
- std::vector<std::vector<bool>> occupiedStrata;
-};
-
-static void shuffle(float2 points[], int size, int rng_seed)
-{
- if (rng_seed == 0) {
- return;
- }
-
- constexpr int odd[8] = {0, 1, 4, 5, 10, 11, 14, 15};
- constexpr int even[8] = {2, 3, 6, 7, 8, 9, 12, 13};
-
- int rng_index = 0;
- for (int yy = 0; yy < size / 16; ++yy) {
- for (int xx = 0; xx < 8; ++xx) {
- int other = (int)(cmj_randfloat(++rng_index, rng_seed) * (8.0f - xx) + xx);
- float2 tmp = points[odd[other] + yy * 16];
- points[odd[other] + yy * 16] = points[odd[xx] + yy * 16];
- points[odd[xx] + yy * 16] = tmp;
- }
- for (int xx = 0; xx < 8; ++xx) {
- int other = (int)(cmj_randfloat(++rng_index, rng_seed) * (8.0f - xx) + xx);
- float2 tmp = points[even[other] + yy * 16];
- points[even[other] + yy * 16] = points[even[xx] + yy * 16];
- points[even[xx] + yy * 16] = tmp;
- }
- }
-}
-
-void progressive_multi_jitter_generate_2D(float2 points[], int size, int rng_seed)
-{
- PMJ_Generator::generate_2D(points, size, rng_seed);
- shuffle(points, size, rng_seed);
-}
-
-void progressive_multi_jitter_02_generate_2D(float2 points[], int size, int rng_seed)
-{
- PMJ02_Generator::generate_2D(points, size, rng_seed);
- shuffle(points, size, rng_seed);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/jitter.h b/intern/cycles/render/jitter.h
deleted file mode 100644
index ed34c7a4f4d..00000000000
--- a/intern/cycles/render/jitter.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2019 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __JITTER_H__
-#define __JITTER_H__
-
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-void progressive_multi_jitter_generate_2D(float2 points[], int size, int rng_seed);
-void progressive_multi_jitter_02_generate_2D(float2 points[], int size, int rng_seed);
-
-CCL_NAMESPACE_END
-
-#endif /* __JITTER_H__ */
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
deleted file mode 100644
index 400ed0802a6..00000000000
--- a/intern/cycles/render/light.cpp
+++ /dev/null
@@ -1,1150 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "device/device.h"
-
-#include "render/background.h"
-#include "render/film.h"
-#include "render/graph.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/nodes.h"
-#include "render/object.h"
-#include "render/scene.h"
-#include "render/shader.h"
-#include "render/stats.h"
-
-#include "integrator/shader_eval.h"
-
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-#include "util/util_logging.h"
-#include "util/util_path.h"
-#include "util/util_progress.h"
-#include "util/util_task.h"
-
-CCL_NAMESPACE_BEGIN
-
-static void shade_background_pixels(Device *device,
- DeviceScene *dscene,
- int width,
- int height,
- vector<float3> &pixels,
- Progress &progress)
-{
- /* Needs to be up to data for attribute access. */
- device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
-
- const int size = width * height;
- const int num_channels = 3;
- pixels.resize(size);
-
- /* Evaluate shader on device. */
- ShaderEval shader_eval(device, progress);
- shader_eval.eval(
- SHADER_EVAL_BACKGROUND,
- size,
- num_channels,
- [&](device_vector<KernelShaderEvalInput> &d_input) {
- /* Fill coordinates for shading. */
- KernelShaderEvalInput *d_input_data = d_input.data();
-
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- float u = (x + 0.5f) / width;
- float v = (y + 0.5f) / height;
-
- KernelShaderEvalInput in;
- in.object = OBJECT_NONE;
- in.prim = PRIM_NONE;
- in.u = u;
- in.v = v;
- d_input_data[x + y * width] = in;
- }
- }
-
- return size;
- },
- [&](device_vector<float> &d_output) {
- /* Copy output to pixel buffer. */
- float *d_output_data = d_output.data();
-
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- pixels[y * width + x].x = d_output_data[(y * width + x) * num_channels + 0];
- pixels[y * width + x].y = d_output_data[(y * width + x) * num_channels + 1];
- pixels[y * width + x].z = d_output_data[(y * width + x) * num_channels + 2];
- }
- }
- });
-}
-
-/* Light */
-
-NODE_DEFINE(Light)
-{
- NodeType *type = NodeType::add("light", create);
-
- static NodeEnum type_enum;
- type_enum.insert("point", LIGHT_POINT);
- type_enum.insert("distant", LIGHT_DISTANT);
- type_enum.insert("background", LIGHT_BACKGROUND);
- type_enum.insert("area", LIGHT_AREA);
- type_enum.insert("spot", LIGHT_SPOT);
- SOCKET_ENUM(light_type, "Type", type_enum, LIGHT_POINT);
-
- SOCKET_COLOR(strength, "Strength", one_float3());
-
- SOCKET_POINT(co, "Co", zero_float3());
-
- SOCKET_VECTOR(dir, "Dir", zero_float3());
- SOCKET_FLOAT(size, "Size", 0.0f);
- SOCKET_FLOAT(angle, "Angle", 0.0f);
-
- SOCKET_VECTOR(axisu, "Axis U", zero_float3());
- SOCKET_FLOAT(sizeu, "Size U", 1.0f);
- SOCKET_VECTOR(axisv, "Axis V", zero_float3());
- SOCKET_FLOAT(sizev, "Size V", 1.0f);
- SOCKET_BOOLEAN(round, "Round", false);
- SOCKET_FLOAT(spread, "Spread", M_PI_F);
-
- SOCKET_INT(map_resolution, "Map Resolution", 0);
-
- SOCKET_FLOAT(spot_angle, "Spot Angle", M_PI_4_F);
- SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f);
-
- SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
-
- SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true);
- SOCKET_BOOLEAN(use_mis, "Use Mis", false);
- SOCKET_BOOLEAN(use_camera, "Use Camera", true);
- SOCKET_BOOLEAN(use_diffuse, "Use Diffuse", true);
- SOCKET_BOOLEAN(use_glossy, "Use Glossy", true);
- SOCKET_BOOLEAN(use_transmission, "Use Transmission", true);
- SOCKET_BOOLEAN(use_scatter, "Use Scatter", true);
-
- SOCKET_INT(max_bounces, "Max Bounces", 1024);
- SOCKET_UINT(random_id, "Random ID", 0);
-
- SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", true);
- SOCKET_BOOLEAN(is_portal, "Is Portal", false);
- SOCKET_BOOLEAN(is_enabled, "Is Enabled", true);
-
- SOCKET_NODE(shader, "Shader", Shader::get_node_type());
-
- return type;
-}
-
-Light::Light() : Node(get_node_type())
-{
- dereference_all_used_nodes();
-}
-
-void Light::tag_update(Scene *scene)
-{
- if (is_modified()) {
- scene->light_manager->tag_update(scene, LightManager::LIGHT_MODIFIED);
- }
-}
-
-bool Light::has_contribution(Scene *scene)
-{
- if (strength == zero_float3()) {
- return false;
- }
- if (is_portal) {
- return false;
- }
- if (light_type == LIGHT_BACKGROUND) {
- return true;
- }
- return (shader) ? shader->has_surface_emission : scene->default_light->has_surface_emission;
-}
-
-/* Light Manager */
-
-LightManager::LightManager()
-{
- update_flags = UPDATE_ALL;
- need_update_background = true;
- last_background_enabled = false;
- last_background_resolution = 0;
-}
-
-LightManager::~LightManager()
-{
- foreach (IESSlot *slot, ies_slots) {
- delete slot;
- }
-}
-
-bool LightManager::has_background_light(Scene *scene)
-{
- foreach (Light *light, scene->lights) {
- if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) {
- return true;
- }
- }
- return false;
-}
-
-void LightManager::test_enabled_lights(Scene *scene)
-{
- /* Make all lights enabled by default, and perform some preliminary checks
- * needed for finer-tuning of settings (for example, check whether we've
- * got portals or not).
- */
- bool has_portal = false, has_background = false;
- foreach (Light *light, scene->lights) {
- light->is_enabled = light->has_contribution(scene);
- has_portal |= light->is_portal;
- has_background |= light->light_type == LIGHT_BACKGROUND;
- }
-
- bool background_enabled = false;
- int background_resolution = 0;
-
- if (has_background) {
- /* Ignore background light if:
- * - If unsupported on a device
- * - If we don't need it (no HDRs etc.)
- */
- Shader *shader = scene->background->get_shader(scene);
- const bool disable_mis = !(has_portal || shader->has_surface_spatial_varying);
- VLOG_IF(1, disable_mis) << "Background MIS has been disabled.\n";
- foreach (Light *light, scene->lights) {
- if (light->light_type == LIGHT_BACKGROUND) {
- light->is_enabled = !disable_mis;
- background_enabled = !disable_mis;
- background_resolution = light->map_resolution;
- }
- }
- }
-
- if (last_background_enabled != background_enabled ||
- last_background_resolution != background_resolution) {
- last_background_enabled = background_enabled;
- last_background_resolution = background_resolution;
- need_update_background = true;
- }
-}
-
-bool LightManager::object_usable_as_light(Object *object)
-{
- Geometry *geom = object->get_geometry();
- if (geom->geometry_type != Geometry::MESH && geom->geometry_type != Geometry::VOLUME) {
- return false;
- }
- /* Skip objects with NaNs */
- if (!object->bounds.valid()) {
- return false;
- }
- /* Skip if we are not visible for BSDFs. */
- if (!(object->get_visibility() & (PATH_RAY_DIFFUSE | PATH_RAY_GLOSSY | PATH_RAY_TRANSMIT))) {
- return false;
- }
- /* Skip if we have no emission shaders. */
- /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll
- * iterate all geometry shaders twice (when counting and when calculating
- * triangle area.
- */
- foreach (Node *node, geom->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->get_use_mis() && shader->has_surface_emission) {
- return true;
- }
- }
- return false;
-}
-
-void LightManager::device_update_distribution(Device *,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- progress.set_status("Updating Lights", "Computing distribution");
-
- /* count */
- size_t num_lights = 0;
- size_t num_portals = 0;
- size_t num_background_lights = 0;
- size_t num_triangles = 0;
-
- bool background_mis = false;
-
- foreach (Light *light, scene->lights) {
- if (light->is_enabled) {
- num_lights++;
- }
- if (light->is_portal) {
- num_portals++;
- }
- }
-
- foreach (Object *object, scene->objects) {
- if (progress.get_cancel())
- return;
-
- if (!object_usable_as_light(object)) {
- continue;
- }
-
- /* Count triangles. */
- Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
- size_t mesh_num_triangles = mesh->num_triangles();
- for (size_t i = 0; i < mesh_num_triangles; i++) {
- int shader_index = mesh->get_shader()[i];
- Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
- static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
- scene->default_surface;
-
- if (shader->get_use_mis() && shader->has_surface_emission) {
- num_triangles++;
- }
- }
- }
-
- size_t num_distribution = num_triangles + num_lights;
- VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
-
- /* emission area */
- KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
- float totarea = 0.0f;
-
- /* triangles */
- size_t offset = 0;
- int j = 0;
-
- foreach (Object *object, scene->objects) {
- if (progress.get_cancel())
- return;
-
- if (!object_usable_as_light(object)) {
- j++;
- continue;
- }
- /* Sum area. */
- Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
- bool transform_applied = mesh->transform_applied;
- Transform tfm = object->get_tfm();
- int object_id = j;
- int shader_flag = 0;
-
- if (!(object->get_visibility() & PATH_RAY_CAMERA)) {
- shader_flag |= SHADER_EXCLUDE_CAMERA;
- }
- if (!(object->get_visibility() & PATH_RAY_DIFFUSE)) {
- shader_flag |= SHADER_EXCLUDE_DIFFUSE;
- }
- if (!(object->get_visibility() & PATH_RAY_GLOSSY)) {
- shader_flag |= SHADER_EXCLUDE_GLOSSY;
- }
- if (!(object->get_visibility() & PATH_RAY_TRANSMIT)) {
- shader_flag |= SHADER_EXCLUDE_TRANSMIT;
- }
- if (!(object->get_visibility() & PATH_RAY_VOLUME_SCATTER)) {
- shader_flag |= SHADER_EXCLUDE_SCATTER;
- }
- if (!(object->get_is_shadow_catcher())) {
- shader_flag |= SHADER_EXCLUDE_SHADOW_CATCHER;
- }
-
- size_t mesh_num_triangles = mesh->num_triangles();
- for (size_t i = 0; i < mesh_num_triangles; i++) {
- int shader_index = mesh->get_shader()[i];
- Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
- static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
- scene->default_surface;
-
- if (shader->get_use_mis() && shader->has_surface_emission) {
- distribution[offset].totarea = totarea;
- distribution[offset].prim = i + mesh->prim_offset;
- distribution[offset].mesh_light.shader_flag = shader_flag;
- distribution[offset].mesh_light.object_id = object_id;
- offset++;
-
- Mesh::Triangle t = mesh->get_triangle(i);
- if (!t.valid(&mesh->get_verts()[0])) {
- continue;
- }
- float3 p1 = mesh->get_verts()[t.v[0]];
- float3 p2 = mesh->get_verts()[t.v[1]];
- float3 p3 = mesh->get_verts()[t.v[2]];
-
- if (!transform_applied) {
- p1 = transform_point(&tfm, p1);
- p2 = transform_point(&tfm, p2);
- p3 = transform_point(&tfm, p3);
- }
-
- totarea += triangle_area(p1, p2, p3);
- }
- }
-
- j++;
- }
-
- float trianglearea = totarea;
- /* point lights */
- bool use_lamp_mis = false;
- int light_index = 0;
-
- if (num_lights > 0) {
- float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
- foreach (Light *light, scene->lights) {
- if (!light->is_enabled)
- continue;
-
- distribution[offset].totarea = totarea;
- distribution[offset].prim = ~light_index;
- distribution[offset].lamp.pad = 1.0f;
- distribution[offset].lamp.size = light->size;
- totarea += lightarea;
-
- if (light->light_type == LIGHT_DISTANT) {
- use_lamp_mis |= (light->angle > 0.0f && light->use_mis);
- }
- else if (light->light_type == LIGHT_POINT || light->light_type == LIGHT_SPOT) {
- use_lamp_mis |= (light->size > 0.0f && light->use_mis);
- }
- else if (light->light_type == LIGHT_AREA) {
- use_lamp_mis |= light->use_mis;
- }
- else if (light->light_type == LIGHT_BACKGROUND) {
- num_background_lights++;
- background_mis |= light->use_mis;
- }
-
- light_index++;
- offset++;
- }
- }
-
- /* normalize cumulative distribution functions */
- distribution[num_distribution].totarea = totarea;
- distribution[num_distribution].prim = 0.0f;
- distribution[num_distribution].lamp.pad = 0.0f;
- distribution[num_distribution].lamp.size = 0.0f;
-
- if (totarea > 0.0f) {
- for (size_t i = 0; i < num_distribution; i++)
- distribution[i].totarea /= totarea;
- distribution[num_distribution].totarea = 1.0f;
- }
-
- if (progress.get_cancel())
- return;
-
- /* update device */
- KernelIntegrator *kintegrator = &dscene->data.integrator;
- KernelBackground *kbackground = &dscene->data.background;
- KernelFilm *kfilm = &dscene->data.film;
- kintegrator->use_direct_light = (totarea > 0.0f);
-
- if (kintegrator->use_direct_light) {
- /* number of emissives */
- kintegrator->num_distribution = num_distribution;
-
- /* precompute pdfs */
- kintegrator->pdf_triangles = 0.0f;
- kintegrator->pdf_lights = 0.0f;
-
- /* sample one, with 0.5 probability of light or triangle */
- kintegrator->num_all_lights = num_lights;
-
- if (trianglearea > 0.0f) {
- kintegrator->pdf_triangles = 1.0f / trianglearea;
- if (num_lights)
- kintegrator->pdf_triangles *= 0.5f;
- }
-
- if (num_lights) {
- kintegrator->pdf_lights = 1.0f / num_lights;
- if (trianglearea > 0.0f)
- kintegrator->pdf_lights *= 0.5f;
- }
-
- kintegrator->use_lamp_mis = use_lamp_mis;
-
- /* bit of an ugly hack to compensate for emitting triangles influencing
- * amount of samples we get for this pass */
- kfilm->pass_shadow_scale = 1.0f;
-
- if (kintegrator->pdf_triangles != 0.0f)
- kfilm->pass_shadow_scale /= 0.5f;
-
- if (num_background_lights < num_lights)
- kfilm->pass_shadow_scale /= (float)(num_lights - num_background_lights) / (float)num_lights;
-
- /* CDF */
- dscene->light_distribution.copy_to_device();
-
- /* Portals */
- if (num_portals > 0) {
- kbackground->portal_offset = light_index;
- kbackground->num_portals = num_portals;
- kbackground->portal_weight = 1.0f;
- }
- else {
- kbackground->num_portals = 0;
- kbackground->portal_offset = 0;
- kbackground->portal_weight = 0.0f;
- }
-
- /* Map */
- kbackground->map_weight = background_mis ? 1.0f : 0.0f;
- }
- else {
- dscene->light_distribution.free();
-
- kintegrator->num_distribution = 0;
- kintegrator->num_all_lights = 0;
- kintegrator->pdf_triangles = 0.0f;
- kintegrator->pdf_lights = 0.0f;
- kintegrator->use_lamp_mis = false;
-
- kbackground->num_portals = 0;
- kbackground->portal_offset = 0;
- kbackground->portal_weight = 0.0f;
- kbackground->sun_weight = 0.0f;
- kbackground->map_weight = 0.0f;
-
- kfilm->pass_shadow_scale = 1.0f;
- }
-}
-
-static void background_cdf(
- int start, int end, int res_x, int res_y, const vector<float3> *pixels, float2 *cond_cdf)
-{
- int cdf_width = res_x + 1;
- /* Conditional CDFs (rows, U direction). */
- for (int i = start; i < end; i++) {
- float sin_theta = sinf(M_PI_F * (i + 0.5f) / res_y);
- float3 env_color = (*pixels)[i * res_x];
- float ave_luminance = average(env_color);
-
- cond_cdf[i * cdf_width].x = ave_luminance * sin_theta;
- cond_cdf[i * cdf_width].y = 0.0f;
-
- for (int j = 1; j < res_x; j++) {
- env_color = (*pixels)[i * res_x + j];
- ave_luminance = average(env_color);
-
- cond_cdf[i * cdf_width + j].x = ave_luminance * sin_theta;
- cond_cdf[i * cdf_width + j].y = cond_cdf[i * cdf_width + j - 1].y +
- cond_cdf[i * cdf_width + j - 1].x / res_x;
- }
-
- const float cdf_total = cond_cdf[i * cdf_width + res_x - 1].y +
- cond_cdf[i * cdf_width + res_x - 1].x / res_x;
-
- /* stuff the total into the brightness value for the last entry, because
- * we are going to normalize the CDFs to 0.0 to 1.0 afterwards */
- cond_cdf[i * cdf_width + res_x].x = cdf_total;
-
- if (cdf_total > 0.0f) {
- const float cdf_total_inv = 1.0f / cdf_total;
- for (int j = 1; j < res_x; j++) {
- cond_cdf[i * cdf_width + j].y *= cdf_total_inv;
- }
- }
-
- cond_cdf[i * cdf_width + res_x].y = 1.0f;
- }
-}
-
-void LightManager::device_update_background(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- KernelBackground *kbackground = &dscene->data.background;
- Light *background_light = NULL;
-
- /* find background light */
- foreach (Light *light, scene->lights) {
- if (light->light_type == LIGHT_BACKGROUND) {
- background_light = light;
- break;
- }
- }
-
- /* no background light found, signal renderer to skip sampling */
- if (!background_light || !background_light->is_enabled) {
- kbackground->map_res_x = 0;
- kbackground->map_res_y = 0;
- kbackground->map_weight = 0.0f;
- kbackground->sun_weight = 0.0f;
- kbackground->use_mis = (kbackground->portal_weight > 0.0f);
- return;
- }
-
- progress.set_status("Updating Lights", "Importance map");
-
- assert(dscene->data.integrator.use_direct_light);
-
- int2 environment_res = make_int2(0, 0);
- Shader *shader = scene->background->get_shader(scene);
- int num_suns = 0;
- foreach (ShaderNode *node, shader->graph->nodes) {
- if (node->type == EnvironmentTextureNode::get_node_type()) {
- EnvironmentTextureNode *env = (EnvironmentTextureNode *)node;
- ImageMetaData metadata;
- if (!env->handle.empty()) {
- ImageMetaData metadata = env->handle.metadata();
- environment_res.x = max(environment_res.x, metadata.width);
- environment_res.y = max(environment_res.y, metadata.height);
- }
- }
- if (node->type == SkyTextureNode::get_node_type()) {
- SkyTextureNode *sky = (SkyTextureNode *)node;
- if (sky->get_sky_type() == NODE_SKY_NISHITA && sky->get_sun_disc()) {
- /* Ensure that the input coordinates aren't transformed before they reach the node.
- * If that is the case, the logic used for sampling the sun's location does not work
- * and we have to fall back to map-based sampling. */
- const ShaderInput *vec_in = sky->input("Vector");
- if (vec_in && vec_in->link && vec_in->link->parent) {
- ShaderNode *vec_src = vec_in->link->parent;
- if ((vec_src->type != TextureCoordinateNode::get_node_type()) ||
- (vec_in->link != vec_src->output("Generated"))) {
- environment_res.x = max(environment_res.x, 4096);
- environment_res.y = max(environment_res.y, 2048);
- continue;
- }
- }
-
- /* Determine sun direction from lat/long and texture mapping. */
- float latitude = sky->get_sun_elevation();
- float longitude = M_2PI_F - sky->get_sun_rotation() + M_PI_2_F;
- float3 sun_direction = make_float3(
- cosf(latitude) * cosf(longitude), cosf(latitude) * sinf(longitude), sinf(latitude));
- Transform sky_transform = transform_inverse(sky->tex_mapping.compute_transform());
- sun_direction = transform_direction(&sky_transform, sun_direction);
-
- /* Pack sun direction and size. */
- float half_angle = sky->get_sun_size() * 0.5f;
- kbackground->sun = make_float4(
- sun_direction.x, sun_direction.y, sun_direction.z, half_angle);
-
- kbackground->sun_weight = 4.0f;
- environment_res.x = max(environment_res.x, 512);
- environment_res.y = max(environment_res.y, 256);
- num_suns++;
- }
- }
- }
-
- /* If there's more than one sun, fall back to map sampling instead. */
- if (num_suns != 1) {
- kbackground->sun_weight = 0.0f;
- environment_res.x = max(environment_res.x, 4096);
- environment_res.y = max(environment_res.y, 2048);
- }
-
- /* Enable MIS for background sampling if any strategy is active. */
- kbackground->use_mis = (kbackground->portal_weight + kbackground->map_weight +
- kbackground->sun_weight) > 0.0f;
-
- /* get the resolution from the light's size (we stuff it in there) */
- int2 res = make_int2(background_light->map_resolution, background_light->map_resolution / 2);
- /* If the resolution isn't set manually, try to find an environment texture. */
- if (res.x == 0) {
- res = environment_res;
- if (res.x > 0 && res.y > 0) {
- VLOG(2) << "Automatically set World MIS resolution to " << res.x << " by " << res.y << "\n";
- }
- }
- /* If it's still unknown, just use the default. */
- if (res.x == 0 || res.y == 0) {
- res = make_int2(1024, 512);
- VLOG(2) << "Setting World MIS resolution to default\n";
- }
- kbackground->map_res_x = res.x;
- kbackground->map_res_y = res.y;
-
- vector<float3> pixels;
- shade_background_pixels(device, dscene, res.x, res.y, pixels, progress);
-
- if (progress.get_cancel())
- return;
-
- /* build row distributions and column distribution for the infinite area environment light */
- int cdf_width = res.x + 1;
- float2 *marg_cdf = dscene->light_background_marginal_cdf.alloc(res.y + 1);
- float2 *cond_cdf = dscene->light_background_conditional_cdf.alloc(cdf_width * res.y);
-
- double time_start = time_dt();
-
- /* Create CDF in parallel. */
- const int rows_per_task = divide_up(10240, res.x);
- parallel_for(blocked_range<size_t>(0, res.y, rows_per_task),
- [&](const blocked_range<size_t> &r) {
- background_cdf(r.begin(), r.end(), res.x, res.y, &pixels, cond_cdf);
- });
-
- /* marginal CDFs (column, V direction, sum of rows) */
- marg_cdf[0].x = cond_cdf[res.x].x;
- marg_cdf[0].y = 0.0f;
-
- for (int i = 1; i < res.y; i++) {
- marg_cdf[i].x = cond_cdf[i * cdf_width + res.x].x;
- marg_cdf[i].y = marg_cdf[i - 1].y + marg_cdf[i - 1].x / res.y;
- }
-
- float cdf_total = marg_cdf[res.y - 1].y + marg_cdf[res.y - 1].x / res.y;
- marg_cdf[res.y].x = cdf_total;
-
- if (cdf_total > 0.0f)
- for (int i = 1; i < res.y; i++)
- marg_cdf[i].y /= cdf_total;
-
- marg_cdf[res.y].y = 1.0f;
-
- VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n";
-
- /* update device */
- dscene->light_background_marginal_cdf.copy_to_device();
- dscene->light_background_conditional_cdf.copy_to_device();
-}
-
-void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *scene)
-{
- int num_scene_lights = scene->lights.size();
-
- int num_lights = 0;
- foreach (Light *light, scene->lights) {
- if (light->is_enabled || light->is_portal) {
- num_lights++;
- }
- }
-
- KernelLight *klights = dscene->lights.alloc(num_lights);
-
- if (num_lights == 0) {
- VLOG(1) << "No effective light, ignoring points update.";
- return;
- }
-
- int light_index = 0;
-
- foreach (Light *light, scene->lights) {
- if (!light->is_enabled) {
- continue;
- }
-
- float3 co = light->co;
- Shader *shader = (light->shader) ? light->shader : scene->default_light;
- int shader_id = scene->shader_manager->get_shader_id(shader);
- int max_bounces = light->max_bounces;
- float random = (float)light->random_id * (1.0f / (float)0xFFFFFFFF);
-
- if (!light->cast_shadow)
- shader_id &= ~SHADER_CAST_SHADOW;
-
- if (!light->use_camera) {
- shader_id |= SHADER_EXCLUDE_CAMERA;
- }
- if (!light->use_diffuse) {
- shader_id |= SHADER_EXCLUDE_DIFFUSE;
- }
- if (!light->use_glossy) {
- shader_id |= SHADER_EXCLUDE_GLOSSY;
- }
- if (!light->use_transmission) {
- shader_id |= SHADER_EXCLUDE_TRANSMIT;
- }
- if (!light->use_scatter) {
- shader_id |= SHADER_EXCLUDE_SCATTER;
- }
- if (!light->is_shadow_catcher) {
- shader_id |= SHADER_EXCLUDE_SHADOW_CATCHER;
- }
-
- klights[light_index].type = light->light_type;
- klights[light_index].strength[0] = light->strength.x;
- klights[light_index].strength[1] = light->strength.y;
- klights[light_index].strength[2] = light->strength.z;
-
- if (light->light_type == LIGHT_POINT) {
- shader_id &= ~SHADER_AREA_LIGHT;
-
- float radius = light->size;
- float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f;
-
- if (light->use_mis && radius > 0.0f)
- shader_id |= SHADER_USE_MIS;
-
- klights[light_index].co[0] = co.x;
- klights[light_index].co[1] = co.y;
- klights[light_index].co[2] = co.z;
-
- klights[light_index].spot.radius = radius;
- klights[light_index].spot.invarea = invarea;
- }
- else if (light->light_type == LIGHT_DISTANT) {
- shader_id &= ~SHADER_AREA_LIGHT;
-
- float angle = light->angle / 2.0f;
- float radius = tanf(angle);
- float cosangle = cosf(angle);
- float area = M_PI_F * radius * radius;
- float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
- float3 dir = light->dir;
-
- dir = safe_normalize(dir);
-
- if (light->use_mis && area > 0.0f)
- shader_id |= SHADER_USE_MIS;
-
- klights[light_index].co[0] = dir.x;
- klights[light_index].co[1] = dir.y;
- klights[light_index].co[2] = dir.z;
-
- klights[light_index].distant.invarea = invarea;
- klights[light_index].distant.radius = radius;
- klights[light_index].distant.cosangle = cosangle;
- }
- else if (light->light_type == LIGHT_BACKGROUND) {
- uint visibility = scene->background->get_visibility();
-
- shader_id &= ~SHADER_AREA_LIGHT;
- shader_id |= SHADER_USE_MIS;
-
- if (!(visibility & PATH_RAY_DIFFUSE)) {
- shader_id |= SHADER_EXCLUDE_DIFFUSE;
- }
- if (!(visibility & PATH_RAY_GLOSSY)) {
- shader_id |= SHADER_EXCLUDE_GLOSSY;
- }
- if (!(visibility & PATH_RAY_TRANSMIT)) {
- shader_id |= SHADER_EXCLUDE_TRANSMIT;
- }
- if (!(visibility & PATH_RAY_VOLUME_SCATTER)) {
- shader_id |= SHADER_EXCLUDE_SCATTER;
- }
- }
- else if (light->light_type == LIGHT_AREA) {
- float3 axisu = light->axisu * (light->sizeu * light->size);
- float3 axisv = light->axisv * (light->sizev * light->size);
- float area = len(axisu) * len(axisv);
- if (light->round) {
- area *= -M_PI_4_F;
- }
- float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
- float3 dir = light->dir;
-
- /* Convert from spread angle 0..180 to 90..0, clamping to a minimum
- * angle to avoid excessive noise. */
- const float min_spread_angle = 1.0f * M_PI_F / 180.0f;
- const float spread_angle = 0.5f * (M_PI_F - max(light->spread, min_spread_angle));
- /* Normalization computed using:
- * integrate cos(x) * (1 - tan(x) * tan(a)) * sin(x) from x = 0 to pi/2 - a. */
- const float tan_spread = tanf(spread_angle);
- const float normalize_spread = 2.0f / (2.0f + (2.0f * spread_angle - M_PI_F) * tan_spread);
-
- dir = safe_normalize(dir);
-
- if (light->use_mis && area != 0.0f)
- shader_id |= SHADER_USE_MIS;
-
- klights[light_index].co[0] = co.x;
- klights[light_index].co[1] = co.y;
- klights[light_index].co[2] = co.z;
-
- klights[light_index].area.axisu[0] = axisu.x;
- klights[light_index].area.axisu[1] = axisu.y;
- klights[light_index].area.axisu[2] = axisu.z;
- klights[light_index].area.axisv[0] = axisv.x;
- klights[light_index].area.axisv[1] = axisv.y;
- klights[light_index].area.axisv[2] = axisv.z;
- klights[light_index].area.invarea = invarea;
- klights[light_index].area.dir[0] = dir.x;
- klights[light_index].area.dir[1] = dir.y;
- klights[light_index].area.dir[2] = dir.z;
- klights[light_index].area.tan_spread = tan_spread;
- klights[light_index].area.normalize_spread = normalize_spread;
- }
- else if (light->light_type == LIGHT_SPOT) {
- shader_id &= ~SHADER_AREA_LIGHT;
-
- float radius = light->size;
- float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f;
- float spot_angle = cosf(light->spot_angle * 0.5f);
- float spot_smooth = (1.0f - spot_angle) * light->spot_smooth;
- float3 dir = light->dir;
-
- dir = safe_normalize(dir);
-
- if (light->use_mis && radius > 0.0f)
- shader_id |= SHADER_USE_MIS;
-
- klights[light_index].co[0] = co.x;
- klights[light_index].co[1] = co.y;
- klights[light_index].co[2] = co.z;
-
- klights[light_index].spot.radius = radius;
- klights[light_index].spot.invarea = invarea;
- klights[light_index].spot.spot_angle = spot_angle;
- klights[light_index].spot.spot_smooth = spot_smooth;
- klights[light_index].spot.dir[0] = dir.x;
- klights[light_index].spot.dir[1] = dir.y;
- klights[light_index].spot.dir[2] = dir.z;
- }
-
- klights[light_index].shader_id = shader_id;
-
- klights[light_index].max_bounces = max_bounces;
- klights[light_index].random = random;
-
- klights[light_index].tfm = light->tfm;
- klights[light_index].itfm = transform_inverse(light->tfm);
-
- light_index++;
- }
-
- /* TODO(sergey): Consider moving portals update to their own function
- * keeping this one more manageable.
- */
- foreach (Light *light, scene->lights) {
- if (!light->is_portal)
- continue;
- assert(light->light_type == LIGHT_AREA);
-
- float3 co = light->co;
- float3 axisu = light->axisu * (light->sizeu * light->size);
- float3 axisv = light->axisv * (light->sizev * light->size);
- float area = len(axisu) * len(axisv);
- if (light->round) {
- area *= -M_PI_4_F;
- }
- float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
- float3 dir = light->dir;
-
- dir = safe_normalize(dir);
-
- klights[light_index].co[0] = co.x;
- klights[light_index].co[1] = co.y;
- klights[light_index].co[2] = co.z;
-
- klights[light_index].area.axisu[0] = axisu.x;
- klights[light_index].area.axisu[1] = axisu.y;
- klights[light_index].area.axisu[2] = axisu.z;
- klights[light_index].area.axisv[0] = axisv.x;
- klights[light_index].area.axisv[1] = axisv.y;
- klights[light_index].area.axisv[2] = axisv.z;
- klights[light_index].area.invarea = invarea;
- klights[light_index].area.dir[0] = dir.x;
- klights[light_index].area.dir[1] = dir.y;
- klights[light_index].area.dir[2] = dir.z;
- klights[light_index].tfm = light->tfm;
- klights[light_index].itfm = transform_inverse(light->tfm);
-
- light_index++;
- }
-
- VLOG(1) << "Number of lights sent to the device: " << light_index;
-
- VLOG(1) << "Number of lights without contribution: " << num_scene_lights - light_index;
-
- dscene->lights.copy_to_device();
-}
-
-void LightManager::device_update(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- if (!need_update())
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->light.times.add_entry({"device_update", time});
- }
- });
-
- VLOG(1) << "Total " << scene->lights.size() << " lights.";
-
- /* Detect which lights are enabled, also determines if we need to update the background. */
- test_enabled_lights(scene);
-
- device_free(device, dscene, need_update_background);
-
- device_update_points(device, dscene, scene);
- if (progress.get_cancel())
- return;
-
- device_update_distribution(device, dscene, scene, progress);
- if (progress.get_cancel())
- return;
-
- if (need_update_background) {
- device_update_background(device, dscene, scene, progress);
- if (progress.get_cancel())
- return;
- }
-
- device_update_ies(dscene);
- if (progress.get_cancel())
- return;
-
- update_flags = UPDATE_NONE;
- need_update_background = false;
-}
-
-void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_background)
-{
- dscene->light_distribution.free();
- dscene->lights.free();
- if (free_background) {
- dscene->light_background_marginal_cdf.free();
- dscene->light_background_conditional_cdf.free();
- }
- dscene->ies_lights.free();
-}
-
-void LightManager::tag_update(Scene * /*scene*/, uint32_t flag)
-{
- update_flags |= flag;
-}
-
-bool LightManager::need_update() const
-{
- return update_flags != UPDATE_NONE;
-}
-
-int LightManager::add_ies_from_file(const string &filename)
-{
- string content;
-
- /* If the file can't be opened, call with an empty line */
- if (filename.empty() || !path_read_text(filename.c_str(), content)) {
- content = "\n";
- }
-
- return add_ies(content);
-}
-
-int LightManager::add_ies(const string &content)
-{
- uint hash = hash_string(content.c_str());
-
- thread_scoped_lock ies_lock(ies_mutex);
-
- /* Check whether this IES already has a slot. */
- size_t slot;
- for (slot = 0; slot < ies_slots.size(); slot++) {
- if (ies_slots[slot]->hash == hash) {
- ies_slots[slot]->users++;
- return slot;
- }
- }
-
- /* Try to find an empty slot for the new IES. */
- for (slot = 0; slot < ies_slots.size(); slot++) {
- if (ies_slots[slot]->users == 0 && ies_slots[slot]->hash == 0) {
- break;
- }
- }
-
- /* If there's no free slot, add one. */
- if (slot == ies_slots.size()) {
- ies_slots.push_back(new IESSlot());
- }
-
- ies_slots[slot]->ies.load(content);
- ies_slots[slot]->users = 1;
- ies_slots[slot]->hash = hash;
-
- update_flags = UPDATE_ALL;
- need_update_background = true;
-
- return slot;
-}
-
-void LightManager::remove_ies(int slot)
-{
- thread_scoped_lock ies_lock(ies_mutex);
-
- if (slot < 0 || slot >= ies_slots.size()) {
- assert(false);
- return;
- }
-
- assert(ies_slots[slot]->users > 0);
- ies_slots[slot]->users--;
-
- /* If the slot has no more users, update the device to remove it. */
- if (ies_slots[slot]->users == 0) {
- update_flags |= UPDATE_ALL;
- need_update_background = true;
- }
-}
-
-void LightManager::device_update_ies(DeviceScene *dscene)
-{
- /* Clear empty slots. */
- foreach (IESSlot *slot, ies_slots) {
- if (slot->users == 0) {
- slot->hash = 0;
- slot->ies.clear();
- }
- }
-
- /* Shrink the slot table by removing empty slots at the end. */
- int slot_end;
- for (slot_end = ies_slots.size(); slot_end; slot_end--) {
- if (ies_slots[slot_end - 1]->users > 0) {
- /* If the preceding slot has users, we found the new end of the table. */
- break;
- }
- else {
- /* The slot will be past the new end of the table, so free it. */
- delete ies_slots[slot_end - 1];
- }
- }
- ies_slots.resize(slot_end);
-
- if (ies_slots.size() > 0) {
- int packed_size = 0;
- foreach (IESSlot *slot, ies_slots) {
- packed_size += slot->ies.packed_size();
- }
-
- /* ies_lights starts with an offset table that contains the offset of every slot,
- * or -1 if the slot is invalid.
- * Following that table, the packed valid IES lights are stored. */
- float *data = dscene->ies_lights.alloc(ies_slots.size() + packed_size);
-
- int offset = ies_slots.size();
- for (int i = 0; i < ies_slots.size(); i++) {
- int size = ies_slots[i]->ies.packed_size();
- if (size > 0) {
- data[i] = __int_as_float(offset);
- ies_slots[i]->ies.pack(data + offset);
- offset += size;
- }
- else {
- data[i] = __int_as_float(-1);
- }
- }
-
- dscene->ies_lights.copy_to_device();
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
deleted file mode 100644
index 7f86237c8b3..00000000000
--- a/intern/cycles/render/light.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __LIGHT_H__
-#define __LIGHT_H__
-
-#include "kernel/kernel_types.h"
-
-#include "graph/node.h"
-
-/* included as Light::set_shader defined through NODE_SOCKET_API does not select
- * the right Node::set overload as it does not know that Shader is a Node */
-#include "render/shader.h"
-
-#include "util/util_ies.h"
-#include "util/util_thread.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class Object;
-class Progress;
-class Scene;
-class Shader;
-
-class Light : public Node {
- public:
- NODE_DECLARE;
-
- Light();
-
- NODE_SOCKET_API(LightType, light_type)
- NODE_SOCKET_API(float3, strength)
- NODE_SOCKET_API(float3, co)
-
- NODE_SOCKET_API(float3, dir)
- NODE_SOCKET_API(float, size)
- NODE_SOCKET_API(float, angle)
-
- NODE_SOCKET_API(float3, axisu)
- NODE_SOCKET_API(float, sizeu)
- NODE_SOCKET_API(float3, axisv)
- NODE_SOCKET_API(float, sizev)
- NODE_SOCKET_API(bool, round)
- NODE_SOCKET_API(float, spread)
-
- NODE_SOCKET_API(Transform, tfm)
-
- NODE_SOCKET_API(int, map_resolution)
-
- NODE_SOCKET_API(float, spot_angle)
- NODE_SOCKET_API(float, spot_smooth)
-
- NODE_SOCKET_API(bool, cast_shadow)
- NODE_SOCKET_API(bool, use_mis)
- NODE_SOCKET_API(bool, use_camera)
- NODE_SOCKET_API(bool, use_diffuse)
- NODE_SOCKET_API(bool, use_glossy)
- NODE_SOCKET_API(bool, use_transmission)
- NODE_SOCKET_API(bool, use_scatter)
-
- NODE_SOCKET_API(bool, is_shadow_catcher)
- NODE_SOCKET_API(bool, is_portal)
- NODE_SOCKET_API(bool, is_enabled)
-
- NODE_SOCKET_API(Shader *, shader)
- NODE_SOCKET_API(int, max_bounces)
- NODE_SOCKET_API(uint, random_id)
-
- void tag_update(Scene *scene);
-
- /* Check whether the light has contribution the scene. */
- bool has_contribution(Scene *scene);
-
- friend class LightManager;
-};
-
-class LightManager {
- public:
- enum : uint32_t {
- MESH_NEED_REBUILD = (1 << 0),
- EMISSIVE_MESH_MODIFIED = (1 << 1),
- LIGHT_MODIFIED = (1 << 2),
- LIGHT_ADDED = (1 << 3),
- LIGHT_REMOVED = (1 << 4),
- OBJECT_MANAGER = (1 << 5),
- SHADER_COMPILED = (1 << 6),
- SHADER_MODIFIED = (1 << 7),
-
- /* tag everything in the manager for an update */
- UPDATE_ALL = ~0u,
-
- UPDATE_NONE = 0u,
- };
-
- /* Need to update background (including multiple importance map) */
- bool need_update_background;
-
- LightManager();
- ~LightManager();
-
- /* IES texture management */
- int add_ies(const string &ies);
- int add_ies_from_file(const string &filename);
- void remove_ies(int slot);
-
- void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
- void device_free(Device *device, DeviceScene *dscene, const bool free_background = true);
-
- void tag_update(Scene *scene, uint32_t flag);
-
- bool need_update() const;
-
- /* Check whether there is a background light. */
- bool has_background_light(Scene *scene);
-
- protected:
- /* Optimization: disable light which is either unsupported or
- * which doesn't contribute to the scene or which is only used for MIS
- * and scene doesn't need MIS.
- */
- void test_enabled_lights(Scene *scene);
-
- void device_update_points(Device *device, DeviceScene *dscene, Scene *scene);
- void device_update_distribution(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress);
- void device_update_background(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress);
- void device_update_ies(DeviceScene *dscene);
-
- /* Check whether light manager can use the object as a light-emissive. */
- bool object_usable_as_light(Object *object);
-
- struct IESSlot {
- IESFile ies;
- uint hash;
- int users;
- };
-
- vector<IESSlot *> ies_slots;
- thread_mutex ies_mutex;
-
- bool last_background_enabled;
- int last_background_resolution;
-
- uint32_t update_flags;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __LIGHT_H__ */
diff --git a/intern/cycles/render/merge.cpp b/intern/cycles/render/merge.cpp
deleted file mode 100644
index 8a58c827e82..00000000000
--- a/intern/cycles/render/merge.cpp
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright 2011-2019 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/merge.h"
-
-#include "util/util_array.h"
-#include "util/util_map.h"
-#include "util/util_system.h"
-#include "util/util_time.h"
-#include "util/util_unique_ptr.h"
-
-#include <OpenImageIO/filesystem.h>
-#include <OpenImageIO/imageio.h>
-
-OIIO_NAMESPACE_USING
-
-CCL_NAMESPACE_BEGIN
-
-/* Merge Image Layer */
-
-enum MergeChannelOp {
- MERGE_CHANNEL_NOP,
- MERGE_CHANNEL_COPY,
- MERGE_CHANNEL_SUM,
- MERGE_CHANNEL_AVERAGE
-};
-
-struct MergeImagePass {
- /* Full channel name. */
- string channel_name;
- /* Channel format in the file. */
- TypeDesc format;
- /* Type of operation to perform when merging. */
- MergeChannelOp op;
- /* Offset of layer channels in input image. */
- int offset;
- /* Offset of layer channels in merged image. */
- int merge_offset;
-};
-
-struct MergeImageLayer {
- /* Layer name. */
- string name;
- /* Passes. */
- vector<MergeImagePass> passes;
- /* Sample amount that was used for rendering this layer. */
- int samples;
-};
-
-/* Merge Image */
-
-struct MergeImage {
- /* OIIO file handle. */
- unique_ptr<ImageInput> in;
- /* Image file path. */
- string filepath;
- /* Render layers. */
- vector<MergeImageLayer> layers;
-};
-
-/* Channel Parsing */
-
-static MergeChannelOp parse_channel_operation(const string &pass_name)
-{
- if (pass_name == "Depth" || pass_name == "IndexMA" || pass_name == "IndexOB" ||
- string_startswith(pass_name, "Crypto")) {
- return MERGE_CHANNEL_COPY;
- }
- else if (string_startswith(pass_name, "Debug BVH") ||
- string_startswith(pass_name, "Debug Ray") ||
- string_startswith(pass_name, "Debug Render Time")) {
- return MERGE_CHANNEL_SUM;
- }
- else {
- return MERGE_CHANNEL_AVERAGE;
- }
-}
-
-/* Splits in at its last dot, setting suffix to the part after the dot and
- * into the part before it. Returns whether a dot was found. */
-static bool split_last_dot(string &in, string &suffix)
-{
- size_t pos = in.rfind(".");
- if (pos == string::npos) {
- return false;
- }
- suffix = in.substr(pos + 1);
- in = in.substr(0, pos);
- return true;
-}
-
-/* Separate channel names as generated by Blender.
- * Multiview format: RenderLayer.Pass.View.Channel
- * Otherwise: RenderLayer.Pass.Channel */
-static bool parse_channel_name(
- string name, string &renderlayer, string &pass, string &channel, bool multiview_channels)
-{
- if (!split_last_dot(name, channel)) {
- return false;
- }
- string view;
- if (multiview_channels && !split_last_dot(name, view)) {
- return false;
- }
- if (!split_last_dot(name, pass)) {
- return false;
- }
- renderlayer = name;
-
- if (multiview_channels) {
- renderlayer += "." + view;
- }
-
- return true;
-}
-
-static bool parse_channels(const ImageSpec &in_spec,
- vector<MergeImageLayer> &layers,
- string &error)
-{
- const ParamValue *multiview = in_spec.find_attribute("multiView");
- const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING &&
- multiview->type().arraylen >= 2);
-
- layers.clear();
-
- /* Loop over all the channels in the file, parse their name and sort them
- * by RenderLayer.
- * Channels that can't be parsed are directly passed through to the output. */
- map<string, MergeImageLayer> file_layers;
- for (int i = 0; i < in_spec.nchannels; i++) {
- MergeImagePass pass;
- pass.channel_name = in_spec.channelnames[i];
- pass.format = (in_spec.channelformats.size() > 0) ? in_spec.channelformats[i] : in_spec.format;
- pass.offset = i;
- pass.merge_offset = i;
-
- string layername, passname, channelname;
- if (parse_channel_name(
- pass.channel_name, layername, passname, channelname, multiview_channels)) {
- /* Channel part of a render layer. */
- pass.op = parse_channel_operation(passname);
- }
- else {
- /* Other channels are added in unnamed layer. */
- layername = "";
- pass.op = parse_channel_operation(pass.channel_name);
- }
-
- file_layers[layername].passes.push_back(pass);
- }
-
- /* Loop over all detected render-layers, check whether they contain a full set of input channels.
- * Any channels that won't be processed internally are also passed through. */
- for (auto &i : file_layers) {
- const string &name = i.first;
- MergeImageLayer &layer = i.second;
-
- layer.name = name;
- layer.samples = 0;
-
- /* Determine number of samples from metadata. */
- if (layer.name == "") {
- layer.samples = 1;
- }
- else if (layer.samples < 1) {
- string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", "");
- if (sample_string != "") {
- if (!sscanf(sample_string.c_str(), "%d", &layer.samples)) {
- error = "Failed to parse samples metadata: " + sample_string;
- return false;
- }
- }
- }
-
- if (layer.samples < 1) {
- error = string_printf(
- "No sample number specified in the file for layer %s or on the command line",
- name.c_str());
- return false;
- }
-
- layers.push_back(layer);
- }
-
- return true;
-}
-
-static bool open_images(const vector<string> &filepaths, vector<MergeImage> &images, string &error)
-{
- for (const string &filepath : filepaths) {
- unique_ptr<ImageInput> in(ImageInput::open(filepath));
- if (!in) {
- error = "Couldn't open file: " + filepath;
- return false;
- }
-
- MergeImage image;
- image.in = std::move(in);
- image.filepath = filepath;
- if (!parse_channels(image.in->spec(), image.layers, error)) {
- return false;
- }
-
- if (image.layers.size() == 0) {
- error = "Could not find a render layer for merging";
- return false;
- }
-
- if (image.in->spec().deep) {
- error = "Merging deep images not supported.";
- return false;
- }
-
- if (images.size() > 0) {
- const ImageSpec &base_spec = images[0].in->spec();
- const ImageSpec &spec = image.in->spec();
-
- if (base_spec.width != spec.width || base_spec.height != spec.height ||
- base_spec.depth != spec.depth || base_spec.format != spec.format ||
- base_spec.deep != spec.deep) {
- error = "Images do not have matching size and data layout.";
- return false;
- }
- }
-
- images.push_back(std::move(image));
- }
-
- return true;
-}
-
-static void merge_render_time(ImageSpec &spec,
- const vector<MergeImage> &images,
- const string &name,
- const bool average)
-{
- double time = 0.0;
-
- for (const MergeImage &image : images) {
- string time_str = image.in->spec().get_string_attribute(name, "");
- time += time_human_readable_to_seconds(time_str);
- }
-
- if (average) {
- time /= images.size();
- }
-
- spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time));
-}
-
-static void merge_layer_render_time(ImageSpec &spec,
- const vector<MergeImage> &images,
- const string &layer_name,
- const string &time_name,
- const bool average)
-{
- string name = "cycles." + layer_name + "." + time_name;
- double time = 0.0;
-
- for (const MergeImage &image : images) {
- string time_str = image.in->spec().get_string_attribute(name, "");
- time += time_human_readable_to_seconds(time_str);
- }
-
- if (average) {
- time /= images.size();
- }
-
- spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time));
-}
-
-static void merge_channels_metadata(vector<MergeImage> &images,
- ImageSpec &out_spec,
- vector<int> &channel_total_samples)
-{
- /* Based on first image. */
- out_spec = images[0].in->spec();
-
- /* Merge channels and compute offsets. */
- out_spec.nchannels = 0;
- out_spec.channelformats.clear();
- out_spec.channelnames.clear();
-
- for (MergeImage &image : images) {
- for (MergeImageLayer &layer : image.layers) {
- for (MergeImagePass &pass : layer.passes) {
- /* Test if matching channel already exists in merged image. */
- bool found = false;
-
- for (size_t i = 0; i < out_spec.nchannels; i++) {
- if (pass.channel_name == out_spec.channelnames[i]) {
- pass.merge_offset = i;
- channel_total_samples[i] += layer.samples;
- /* First image wins for channels that can't be averaged or summed. */
- if (pass.op == MERGE_CHANNEL_COPY) {
- pass.op = MERGE_CHANNEL_NOP;
- }
- found = true;
- break;
- }
- }
-
- if (!found) {
- /* Add new channel. */
- pass.merge_offset = out_spec.nchannels;
- channel_total_samples.push_back(layer.samples);
-
- out_spec.channelnames.push_back(pass.channel_name);
- out_spec.channelformats.push_back(pass.format);
- out_spec.nchannels++;
- }
- }
- }
- }
-
- /* Merge metadata. */
- merge_render_time(out_spec, images, "RenderTime", false);
-
- map<string, int> layer_num_samples;
- for (MergeImage &image : images) {
- for (MergeImageLayer &layer : image.layers) {
- if (layer.name != "") {
- layer_num_samples[layer.name] += layer.samples;
- }
- }
- }
-
- for (const auto &i : layer_num_samples) {
- string name = "cycles." + i.first + ".samples";
- out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", i.second));
-
- merge_layer_render_time(out_spec, images, i.first, "total_time", false);
- merge_layer_render_time(out_spec, images, i.first, "render_time", false);
- merge_layer_render_time(out_spec, images, i.first, "synchronization_time", true);
- }
-}
-
-static void alloc_pixels(const ImageSpec &spec, array<float> &pixels)
-{
- const size_t width = spec.width;
- const size_t height = spec.height;
- const size_t num_channels = spec.nchannels;
-
- const size_t num_pixels = (size_t)width * (size_t)height;
- pixels.resize(num_pixels * num_channels);
-}
-
-static bool merge_pixels(const vector<MergeImage> &images,
- const ImageSpec &out_spec,
- const vector<int> &channel_total_samples,
- array<float> &out_pixels,
- string &error)
-{
- alloc_pixels(out_spec, out_pixels);
- memset(out_pixels.data(), 0, out_pixels.size() * sizeof(float));
-
- for (const MergeImage &image : images) {
- /* Read all channels into buffer. Reading all channels at once is
- * faster than individually due to interleaved EXR channel storage. */
- array<float> pixels;
- alloc_pixels(image.in->spec(), pixels);
-
- if (!image.in->read_image(TypeDesc::FLOAT, pixels.data())) {
- error = "Failed to read image: " + image.filepath;
- return false;
- }
-
- for (size_t li = 0; li < image.layers.size(); li++) {
- const MergeImageLayer &layer = image.layers[li];
-
- const size_t stride = image.in->spec().nchannels;
- const size_t out_stride = out_spec.nchannels;
- const size_t num_pixels = pixels.size();
-
- for (const MergeImagePass &pass : layer.passes) {
- size_t offset = pass.offset;
- size_t out_offset = pass.merge_offset;
-
- switch (pass.op) {
- case MERGE_CHANNEL_NOP:
- break;
- case MERGE_CHANNEL_COPY:
- for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
- out_pixels[out_offset] = pixels[offset];
- }
- break;
- case MERGE_CHANNEL_SUM:
- for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
- out_pixels[out_offset] += pixels[offset];
- }
- break;
- case MERGE_CHANNEL_AVERAGE:
- /* Weights based on sample metadata. Per channel since not
- * all files are guaranteed to have the same channels. */
- const int total_samples = channel_total_samples[out_offset];
- const float t = (float)layer.samples / (float)total_samples;
-
- for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
- out_pixels[out_offset] += t * pixels[offset];
- }
- break;
- }
- }
- }
- }
-
- return true;
-}
-
-static bool save_output(const string &filepath,
- const ImageSpec &spec,
- const array<float> &pixels,
- string &error)
-{
- /* Write to temporary file path, so we merge images in place and don't
- * risk destroying files when something goes wrong in file saving. */
- string extension = OIIO::Filesystem::extension(filepath);
- string unique_name = ".merge-tmp-" + OIIO::Filesystem::unique_path();
- string tmp_filepath = filepath + unique_name + extension;
- unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath));
-
- if (!out) {
- error = "Failed to open temporary file " + tmp_filepath + " for writing";
- return false;
- }
-
- /* Open temporary file and write image buffers. */
- if (!out->open(tmp_filepath, spec)) {
- error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror();
- return false;
- }
-
- bool ok = true;
- if (!out->write_image(TypeDesc::FLOAT, pixels.data())) {
- error = "Failed to write to file " + tmp_filepath + ": " + out->geterror();
- ok = false;
- }
-
- if (!out->close()) {
- error = "Failed to save to file " + tmp_filepath + ": " + out->geterror();
- ok = false;
- }
-
- out.reset();
-
- /* Copy temporary file to output filepath. */
- string rename_error;
- if (ok && !OIIO::Filesystem::rename(tmp_filepath, filepath, rename_error)) {
- error = "Failed to move merged image to " + filepath + ": " + rename_error;
- ok = false;
- }
-
- if (!ok) {
- OIIO::Filesystem::remove(tmp_filepath);
- }
-
- return ok;
-}
-
-/* Image Merger */
-
-ImageMerger::ImageMerger()
-{
-}
-
-bool ImageMerger::run()
-{
- if (input.empty()) {
- error = "No input file paths specified.";
- return false;
- }
- if (output.empty()) {
- error = "No output file path specified.";
- return false;
- }
-
- /* Open images and verify they have matching layout. */
- vector<MergeImage> images;
- if (!open_images(input, images, error)) {
- return false;
- }
-
- /* Merge metadata and setup channels and offsets. */
- ImageSpec out_spec;
- vector<int> channel_total_samples;
- merge_channels_metadata(images, out_spec, channel_total_samples);
-
- /* Merge pixels. */
- array<float> out_pixels;
- if (!merge_pixels(images, out_spec, channel_total_samples, out_pixels, error)) {
- return false;
- }
-
- /* We don't need input anymore at this point, and will possibly
- * overwrite the same file. */
- images.clear();
-
- /* Save output file. */
- return save_output(output, out_spec, out_pixels, error);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/merge.h b/intern/cycles/render/merge.h
deleted file mode 100644
index 87e5d2d4723..00000000000
--- a/intern/cycles/render/merge.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2011-2019 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __MERGE_H__
-#define __MERGE_H__
-
-#include "util/util_string.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Merge OpenEXR multilayer renders. */
-
-class ImageMerger {
- public:
- ImageMerger();
- bool run();
-
- /* Error message after running, in case of failure. */
- string error;
-
- /* List of image filepaths to merge. */
- vector<string> input;
- /* Output filepath. */
- string output;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __MERGE_H__ */
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
deleted file mode 100644
index 9c93f6f881c..00000000000
--- a/intern/cycles/render/mesh.cpp
+++ /dev/null
@@ -1,812 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bvh/bvh.h"
-#include "bvh/bvh_build.h"
-
-#include "device/device.h"
-
-#include "render/graph.h"
-#include "render/hair.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/scene.h"
-
-#include "subd/subd_patch_table.h"
-#include "subd/subd_split.h"
-
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
-#include "util/util_set.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Triangle */
-
-void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox &bounds) const
-{
- bounds.grow(verts[v[0]]);
- bounds.grow(verts[v[1]]);
- bounds.grow(verts[v[2]]);
-}
-
-void Mesh::Triangle::motion_verts(const float3 *verts,
- const float3 *vert_steps,
- size_t num_verts,
- size_t num_steps,
- float time,
- float3 r_verts[3]) const
-{
- /* Figure out which steps we need to fetch and their interpolation factor. */
- const size_t max_step = num_steps - 1;
- const size_t step = min((int)(time * max_step), max_step - 1);
- const float t = time * max_step - step;
- /* Fetch vertex coordinates. */
- float3 curr_verts[3];
- float3 next_verts[3];
- verts_for_step(verts, vert_steps, num_verts, num_steps, step, curr_verts);
- verts_for_step(verts, vert_steps, num_verts, num_steps, step + 1, next_verts);
- /* Interpolate between steps. */
- r_verts[0] = (1.0f - t) * curr_verts[0] + t * next_verts[0];
- r_verts[1] = (1.0f - t) * curr_verts[1] + t * next_verts[1];
- r_verts[2] = (1.0f - t) * curr_verts[2] + t * next_verts[2];
-}
-
-void Mesh::Triangle::verts_for_step(const float3 *verts,
- const float3 *vert_steps,
- size_t num_verts,
- size_t num_steps,
- size_t step,
- float3 r_verts[3]) const
-{
- const size_t center_step = ((num_steps - 1) / 2);
- if (step == center_step) {
- /* Center step: regular vertex location. */
- r_verts[0] = verts[v[0]];
- r_verts[1] = verts[v[1]];
- r_verts[2] = verts[v[2]];
- }
- else {
- /* Center step not stored in the attribute array array. */
- if (step > center_step) {
- step--;
- }
- size_t offset = step * num_verts;
- r_verts[0] = vert_steps[offset + v[0]];
- r_verts[1] = vert_steps[offset + v[1]];
- r_verts[2] = vert_steps[offset + v[2]];
- }
-}
-
-float3 Mesh::Triangle::compute_normal(const float3 *verts) const
-{
- const float3 &v0 = verts[v[0]];
- const float3 &v1 = verts[v[1]];
- const float3 &v2 = verts[v[2]];
- const float3 norm = cross(v1 - v0, v2 - v0);
- const float normlen = len(norm);
- if (normlen == 0.0f) {
- return make_float3(1.0f, 0.0f, 0.0f);
- }
- return norm / normlen;
-}
-
-bool Mesh::Triangle::valid(const float3 *verts) const
-{
- return isfinite3_safe(verts[v[0]]) && isfinite3_safe(verts[v[1]]) && isfinite3_safe(verts[v[2]]);
-}
-
-/* SubdFace */
-
-float3 Mesh::SubdFace::normal(const Mesh *mesh) const
-{
- float3 v0 = mesh->verts[mesh->subd_face_corners[start_corner + 0]];
- float3 v1 = mesh->verts[mesh->subd_face_corners[start_corner + 1]];
- float3 v2 = mesh->verts[mesh->subd_face_corners[start_corner + 2]];
-
- return safe_normalize(cross(v1 - v0, v2 - v0));
-}
-
-/* Mesh */
-
-NODE_DEFINE(Mesh)
-{
- NodeType *type = NodeType::add("mesh", create, NodeType::NONE, Geometry::get_node_base_type());
-
- SOCKET_INT_ARRAY(triangles, "Triangles", array<int>());
- SOCKET_POINT_ARRAY(verts, "Vertices", array<float3>());
- SOCKET_INT_ARRAY(shader, "Shader", array<int>());
- SOCKET_BOOLEAN_ARRAY(smooth, "Smooth", array<bool>());
-
- SOCKET_INT_ARRAY(triangle_patch, "Triangle Patch", array<int>());
- SOCKET_POINT2_ARRAY(vert_patch_uv, "Patch UVs", array<float2>());
-
- static NodeEnum subdivision_type_enum;
- subdivision_type_enum.insert("none", SUBDIVISION_NONE);
- subdivision_type_enum.insert("linear", SUBDIVISION_LINEAR);
- subdivision_type_enum.insert("catmull_clark", SUBDIVISION_CATMULL_CLARK);
- SOCKET_ENUM(subdivision_type, "Subdivision Type", subdivision_type_enum, SUBDIVISION_NONE);
-
- SOCKET_INT_ARRAY(subd_creases_edge, "Subdivision Crease Edges", array<int>());
- SOCKET_FLOAT_ARRAY(subd_creases_weight, "Subdivision Crease Weights", array<float>());
- SOCKET_INT_ARRAY(subd_face_corners, "Subdivision Face Corners", array<int>());
- SOCKET_INT_ARRAY(subd_start_corner, "Subdivision Face Start Corner", array<int>());
- SOCKET_INT_ARRAY(subd_num_corners, "Subdivision Face Corner Count", array<int>());
- SOCKET_INT_ARRAY(subd_shader, "Subdivision Face Shader", array<int>());
- SOCKET_BOOLEAN_ARRAY(subd_smooth, "Subdivision Face Smooth", array<bool>());
- SOCKET_INT_ARRAY(subd_ptex_offset, "Subdivision Face PTex Offset", array<int>());
- SOCKET_INT(num_ngons, "NGons Number", 0);
-
- /* Subdivisions parameters */
- SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 0.0f)
- SOCKET_INT(subd_max_level, "Subdivision Dicing Rate", 0);
- SOCKET_TRANSFORM(subd_objecttoworld, "Subdivision Object Transform", transform_identity());
-
- return type;
-}
-
-SubdParams *Mesh::get_subd_params()
-{
- if (subdivision_type == SubdivisionType::SUBDIVISION_NONE) {
- return nullptr;
- }
-
- if (!subd_params) {
- subd_params = new SubdParams(this);
- }
-
- subd_params->dicing_rate = subd_dicing_rate;
- subd_params->max_level = subd_max_level;
- subd_params->objecttoworld = subd_objecttoworld;
-
- return subd_params;
-}
-
-bool Mesh::need_tesselation()
-{
- return get_subd_params() && (verts_is_modified() || subd_dicing_rate_is_modified() ||
- subd_objecttoworld_is_modified() || subd_max_level_is_modified());
-}
-
-Mesh::Mesh(const NodeType *node_type, Type geom_type_)
- : Geometry(node_type, geom_type_), subd_attributes(this, ATTR_PRIM_SUBD)
-{
- vert_offset = 0;
-
- patch_offset = 0;
- face_offset = 0;
- corner_offset = 0;
-
- num_subd_verts = 0;
- num_subd_faces = 0;
-
- num_ngons = 0;
-
- subdivision_type = SUBDIVISION_NONE;
- subd_params = NULL;
-
- patch_table = NULL;
-}
-
-Mesh::Mesh() : Mesh(get_node_type(), Geometry::MESH)
-{
-}
-
-Mesh::~Mesh()
-{
- delete patch_table;
- delete subd_params;
-}
-
-void Mesh::resize_mesh(int numverts, int numtris)
-{
- verts.resize(numverts);
- triangles.resize(numtris * 3);
- shader.resize(numtris);
- smooth.resize(numtris);
-
- if (get_num_subd_faces()) {
- triangle_patch.resize(numtris);
- vert_patch_uv.resize(numverts);
- }
-
- attributes.resize();
-}
-
-void Mesh::reserve_mesh(int numverts, int numtris)
-{
- /* reserve space to add verts and triangles later */
- verts.reserve(numverts);
- triangles.reserve(numtris * 3);
- shader.reserve(numtris);
- smooth.reserve(numtris);
-
- if (get_num_subd_faces()) {
- triangle_patch.reserve(numtris);
- vert_patch_uv.reserve(numverts);
- }
-
- attributes.resize(true);
-}
-
-void Mesh::resize_subd_faces(int numfaces, int num_ngons_, int numcorners)
-{
- subd_start_corner.resize(numfaces);
- subd_num_corners.resize(numfaces);
- subd_shader.resize(numfaces);
- subd_smooth.resize(numfaces);
- subd_ptex_offset.resize(numfaces);
- subd_face_corners.resize(numcorners);
- num_ngons = num_ngons_;
- num_subd_faces = numfaces;
-
- subd_attributes.resize();
-}
-
-void Mesh::reserve_subd_faces(int numfaces, int num_ngons_, int numcorners)
-{
- subd_start_corner.reserve(numfaces);
- subd_num_corners.reserve(numfaces);
- subd_shader.reserve(numfaces);
- subd_smooth.reserve(numfaces);
- subd_ptex_offset.reserve(numfaces);
- subd_face_corners.reserve(numcorners);
- num_ngons = num_ngons_;
- num_subd_faces = numfaces;
-
- subd_attributes.resize(true);
-}
-
-void Mesh::reserve_subd_creases(size_t num_creases)
-{
- subd_creases_edge.reserve(num_creases * 2);
- subd_creases_weight.reserve(num_creases);
-}
-
-void Mesh::clear_non_sockets()
-{
- Geometry::clear(true);
-
- num_subd_verts = 0;
- num_subd_faces = 0;
-
- vert_to_stitching_key_map.clear();
- vert_stitching_map.clear();
-
- delete patch_table;
- patch_table = NULL;
-}
-
-void Mesh::clear(bool preserve_shaders, bool preserve_voxel_data)
-{
- Geometry::clear(preserve_shaders);
-
- /* clear all verts and triangles */
- verts.clear();
- triangles.clear();
- shader.clear();
- smooth.clear();
-
- triangle_patch.clear();
- vert_patch_uv.clear();
-
- subd_start_corner.clear();
- subd_num_corners.clear();
- subd_shader.clear();
- subd_smooth.clear();
- subd_ptex_offset.clear();
- subd_face_corners.clear();
-
- subd_creases_edge.clear();
- subd_creases_weight.clear();
-
- subd_attributes.clear();
- attributes.clear(preserve_voxel_data);
-
- subdivision_type = SubdivisionType::SUBDIVISION_NONE;
-
- clear_non_sockets();
-}
-
-void Mesh::clear(bool preserve_shaders)
-{
- clear(preserve_shaders, false);
-}
-
-void Mesh::add_vertex(float3 P)
-{
- verts.push_back_reserved(P);
- tag_verts_modified();
-
- if (get_num_subd_faces()) {
- vert_patch_uv.push_back_reserved(zero_float2());
- tag_vert_patch_uv_modified();
- }
-}
-
-void Mesh::add_vertex_slow(float3 P)
-{
- verts.push_back_slow(P);
- tag_verts_modified();
-
- if (get_num_subd_faces()) {
- vert_patch_uv.push_back_slow(zero_float2());
- tag_vert_patch_uv_modified();
- }
-}
-
-void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
-{
- triangles.push_back_reserved(v0);
- triangles.push_back_reserved(v1);
- triangles.push_back_reserved(v2);
- shader.push_back_reserved(shader_);
- smooth.push_back_reserved(smooth_);
-
- tag_triangles_modified();
- tag_shader_modified();
- tag_smooth_modified();
-
- if (get_num_subd_faces()) {
- triangle_patch.push_back_reserved(-1);
- tag_triangle_patch_modified();
- }
-}
-
-void Mesh::add_subd_face(int *corners, int num_corners, int shader_, bool smooth_)
-{
- int start_corner = subd_face_corners.size();
-
- for (int i = 0; i < num_corners; i++) {
- subd_face_corners.push_back_reserved(corners[i]);
- }
-
- int ptex_offset = 0;
- // cannot use get_num_subd_faces here as it holds the total number of subd_faces, but we do not
- // have the total amount of data yet
- if (subd_shader.size()) {
- SubdFace s = get_subd_face(subd_shader.size() - 1);
- ptex_offset = s.ptex_offset + s.num_ptex_faces();
- }
-
- subd_start_corner.push_back_reserved(start_corner);
- subd_num_corners.push_back_reserved(num_corners);
- subd_shader.push_back_reserved(shader_);
- subd_smooth.push_back_reserved(smooth_);
- subd_ptex_offset.push_back_reserved(ptex_offset);
-
- tag_subd_face_corners_modified();
- tag_subd_start_corner_modified();
- tag_subd_num_corners_modified();
- tag_subd_shader_modified();
- tag_subd_smooth_modified();
- tag_subd_ptex_offset_modified();
-}
-
-Mesh::SubdFace Mesh::get_subd_face(size_t index) const
-{
- Mesh::SubdFace s;
- s.shader = subd_shader[index];
- s.num_corners = subd_num_corners[index];
- s.smooth = subd_smooth[index];
- s.ptex_offset = subd_ptex_offset[index];
- s.start_corner = subd_start_corner[index];
- return s;
-}
-
-void Mesh::add_crease(int v0, int v1, float weight)
-{
- subd_creases_edge.push_back_slow(v0);
- subd_creases_edge.push_back_slow(v1);
- subd_creases_weight.push_back_slow(weight);
-
- tag_subd_creases_edge_modified();
- tag_subd_creases_edge_modified();
- tag_subd_creases_weight_modified();
-}
-
-void Mesh::copy_center_to_motion_step(const int motion_step)
-{
- Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if (attr_mP) {
- Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
- Attribute *attr_N = attributes.find(ATTR_STD_VERTEX_NORMAL);
- float3 *P = &verts[0];
- float3 *N = (attr_N) ? attr_N->data_float3() : NULL;
- size_t numverts = verts.size();
-
- memcpy(attr_mP->data_float3() + motion_step * numverts, P, sizeof(float3) * numverts);
- if (attr_mN)
- memcpy(attr_mN->data_float3() + motion_step * numverts, N, sizeof(float3) * numverts);
- }
-}
-
-void Mesh::get_uv_tiles(ustring map, unordered_set<int> &tiles)
-{
- Attribute *attr, *subd_attr;
-
- if (map.empty()) {
- attr = attributes.find(ATTR_STD_UV);
- subd_attr = subd_attributes.find(ATTR_STD_UV);
- }
- else {
- attr = attributes.find(map);
- subd_attr = subd_attributes.find(map);
- }
-
- if (attr) {
- attr->get_uv_tiles(this, ATTR_PRIM_GEOMETRY, tiles);
- }
- if (subd_attr) {
- subd_attr->get_uv_tiles(this, ATTR_PRIM_SUBD, tiles);
- }
-}
-
-void Mesh::compute_bounds()
-{
- BoundBox bnds = BoundBox::empty;
- size_t verts_size = verts.size();
-
- if (verts_size > 0) {
- for (size_t i = 0; i < verts_size; i++)
- bnds.grow(verts[i]);
-
- Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (use_motion_blur && attr) {
- size_t steps_size = verts.size() * (motion_steps - 1);
- float3 *vert_steps = attr->data_float3();
-
- for (size_t i = 0; i < steps_size; i++)
- bnds.grow(vert_steps[i]);
- }
-
- if (!bnds.valid()) {
- bnds = BoundBox::empty;
-
- /* skip nan or inf coordinates */
- for (size_t i = 0; i < verts_size; i++)
- bnds.grow_safe(verts[i]);
-
- if (use_motion_blur && attr) {
- size_t steps_size = verts.size() * (motion_steps - 1);
- float3 *vert_steps = attr->data_float3();
-
- for (size_t i = 0; i < steps_size; i++)
- bnds.grow_safe(vert_steps[i]);
- }
- }
- }
-
- if (!bnds.valid()) {
- /* empty mesh */
- bnds.grow(zero_float3());
- }
-
- bounds = bnds;
-}
-
-void Mesh::apply_transform(const Transform &tfm, const bool apply_to_motion)
-{
- transform_normal = transform_transposed_inverse(tfm);
-
- /* apply to mesh vertices */
- for (size_t i = 0; i < verts.size(); i++)
- verts[i] = transform_point(&tfm, verts[i]);
-
- tag_verts_modified();
-
- if (apply_to_motion) {
- Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if (attr) {
- size_t steps_size = verts.size() * (motion_steps - 1);
- float3 *vert_steps = attr->data_float3();
-
- for (size_t i = 0; i < steps_size; i++)
- vert_steps[i] = transform_point(&tfm, vert_steps[i]);
- }
-
- Attribute *attr_N = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
-
- if (attr_N) {
- Transform ntfm = transform_normal;
- size_t steps_size = verts.size() * (motion_steps - 1);
- float3 *normal_steps = attr_N->data_float3();
-
- for (size_t i = 0; i < steps_size; i++)
- normal_steps[i] = normalize(transform_direction(&ntfm, normal_steps[i]));
- }
- }
-}
-
-void Mesh::add_face_normals()
-{
- /* don't compute if already there */
- if (attributes.find(ATTR_STD_FACE_NORMAL))
- return;
-
- /* get attributes */
- Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL);
- float3 *fN = attr_fN->data_float3();
-
- /* compute face normals */
- size_t triangles_size = num_triangles();
-
- if (triangles_size) {
- float3 *verts_ptr = verts.data();
-
- for (size_t i = 0; i < triangles_size; i++) {
- fN[i] = get_triangle(i).compute_normal(verts_ptr);
- }
- }
-
- /* expected to be in local space */
- if (transform_applied) {
- Transform ntfm = transform_inverse(transform_normal);
-
- for (size_t i = 0; i < triangles_size; i++)
- fN[i] = normalize(transform_direction(&ntfm, fN[i]));
- }
-}
-
-void Mesh::add_vertex_normals()
-{
- bool flip = transform_negative_scaled;
- size_t verts_size = verts.size();
- size_t triangles_size = num_triangles();
-
- /* static vertex normals */
- if (!attributes.find(ATTR_STD_VERTEX_NORMAL) && triangles_size) {
- /* get attributes */
- Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
- Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL);
-
- float3 *fN = attr_fN->data_float3();
- float3 *vN = attr_vN->data_float3();
-
- /* compute vertex normals */
- memset(vN, 0, verts.size() * sizeof(float3));
-
- for (size_t i = 0; i < triangles_size; i++) {
- for (size_t j = 0; j < 3; j++) {
- vN[get_triangle(i).v[j]] += fN[i];
- }
- }
-
- for (size_t i = 0; i < verts_size; i++) {
- vN[i] = normalize(vN[i]);
- if (flip) {
- vN[i] = -vN[i];
- }
- }
- }
-
- /* motion vertex normals */
- Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
-
- if (has_motion_blur() && attr_mP && !attr_mN && triangles_size) {
- /* create attribute */
- attr_mN = attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
-
- for (int step = 0; step < motion_steps - 1; step++) {
- float3 *mP = attr_mP->data_float3() + step * verts.size();
- float3 *mN = attr_mN->data_float3() + step * verts.size();
-
- /* compute */
- memset(mN, 0, verts.size() * sizeof(float3));
-
- for (size_t i = 0; i < triangles_size; i++) {
- for (size_t j = 0; j < 3; j++) {
- float3 fN = get_triangle(i).compute_normal(mP);
- mN[get_triangle(i).v[j]] += fN;
- }
- }
-
- for (size_t i = 0; i < verts_size; i++) {
- mN[i] = normalize(mN[i]);
- if (flip) {
- mN[i] = -mN[i];
- }
- }
- }
- }
-
- /* subd vertex normals */
- if (!subd_attributes.find(ATTR_STD_VERTEX_NORMAL) && get_num_subd_faces()) {
- /* get attributes */
- Attribute *attr_vN = subd_attributes.add(ATTR_STD_VERTEX_NORMAL);
- float3 *vN = attr_vN->data_float3();
-
- /* compute vertex normals */
- memset(vN, 0, verts.size() * sizeof(float3));
-
- for (size_t i = 0; i < get_num_subd_faces(); i++) {
- SubdFace face = get_subd_face(i);
- float3 fN = face.normal(this);
-
- for (size_t j = 0; j < face.num_corners; j++) {
- size_t corner = subd_face_corners[face.start_corner + j];
- vN[corner] += fN;
- }
- }
-
- for (size_t i = 0; i < verts_size; i++) {
- vN[i] = normalize(vN[i]);
- if (flip) {
- vN[i] = -vN[i];
- }
- }
- }
-}
-
-void Mesh::add_undisplaced()
-{
- AttributeSet &attrs = (subdivision_type == SUBDIVISION_NONE) ? attributes : subd_attributes;
-
- /* don't compute if already there */
- if (attrs.find(ATTR_STD_POSITION_UNDISPLACED)) {
- return;
- }
-
- /* get attribute */
- Attribute *attr = attrs.add(ATTR_STD_POSITION_UNDISPLACED);
- attr->flags |= ATTR_SUBDIVIDED;
-
- float3 *data = attr->data_float3();
-
- /* copy verts */
- size_t size = attr->buffer_size(this, ATTR_PRIM_GEOMETRY);
-
- /* Center points for ngons aren't stored in Mesh::verts but are included in size since they will
- * be calculated later, we subtract them from size here so we don't have an overflow while
- * copying.
- */
- size -= num_ngons * attr->data_sizeof();
-
- if (size) {
- memcpy(data, verts.data(), size);
- }
-}
-
-void Mesh::pack_shaders(Scene *scene, uint *tri_shader)
-{
- uint shader_id = 0;
- uint last_shader = -1;
- bool last_smooth = false;
-
- size_t triangles_size = num_triangles();
- int *shader_ptr = shader.data();
-
- for (size_t i = 0; i < triangles_size; i++) {
- if (shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
- last_shader = shader_ptr[i];
- last_smooth = smooth[i];
- Shader *shader = (last_shader < used_shaders.size()) ?
- static_cast<Shader *>(used_shaders[last_shader]) :
- scene->default_surface;
- shader_id = scene->shader_manager->get_shader_id(shader, last_smooth);
- }
-
- tri_shader[i] = shader_id;
- }
-}
-
-void Mesh::pack_normals(float4 *vnormal)
-{
- Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
- if (attr_vN == NULL) {
- /* Happens on objects with just hair. */
- return;
- }
-
- bool do_transform = transform_applied;
- Transform ntfm = transform_normal;
-
- float3 *vN = attr_vN->data_float3();
- size_t verts_size = verts.size();
-
- for (size_t i = 0; i < verts_size; i++) {
- float3 vNi = vN[i];
-
- if (do_transform)
- vNi = safe_normalize(transform_direction(&ntfm, vNi));
-
- vnormal[i] = make_float4(vNi.x, vNi.y, vNi.z, 0.0f);
- }
-}
-
-void Mesh::pack_verts(float4 *tri_verts, uint4 *tri_vindex, uint *tri_patch, float2 *tri_patch_uv)
-{
- size_t verts_size = verts.size();
-
- if (verts_size && get_num_subd_faces()) {
- float2 *vert_patch_uv_ptr = vert_patch_uv.data();
-
- for (size_t i = 0; i < verts_size; i++) {
- tri_patch_uv[i] = vert_patch_uv_ptr[i];
- }
- }
-
- size_t triangles_size = num_triangles();
-
- for (size_t i = 0; i < triangles_size; i++) {
- const Triangle t = get_triangle(i);
- tri_vindex[i] = make_uint4(
- t.v[0] + vert_offset, t.v[1] + vert_offset, t.v[2] + vert_offset, 3 * (prim_offset + i));
-
- tri_patch[i] = (!get_num_subd_faces()) ? -1 : (triangle_patch[i] * 8 + patch_offset);
-
- tri_verts[i * 3] = float3_to_float4(verts[t.v[0]]);
- tri_verts[i * 3 + 1] = float3_to_float4(verts[t.v[1]]);
- tri_verts[i * 3 + 2] = float3_to_float4(verts[t.v[2]]);
- }
-}
-
-void Mesh::pack_patches(uint *patch_data)
-{
- size_t num_faces = get_num_subd_faces();
- int ngons = 0;
-
- for (size_t f = 0; f < num_faces; f++) {
- SubdFace face = get_subd_face(f);
-
- if (face.is_quad()) {
- int c[4];
- memcpy(c, &subd_face_corners[face.start_corner], sizeof(int) * 4);
-
- *(patch_data++) = c[0] + vert_offset;
- *(patch_data++) = c[1] + vert_offset;
- *(patch_data++) = c[2] + vert_offset;
- *(patch_data++) = c[3] + vert_offset;
-
- *(patch_data++) = f + face_offset;
- *(patch_data++) = face.num_corners;
- *(patch_data++) = face.start_corner + corner_offset;
- *(patch_data++) = 0;
- }
- else {
- for (int i = 0; i < face.num_corners; i++) {
- int c[4];
- c[0] = subd_face_corners[face.start_corner + mod(i + 0, face.num_corners)];
- c[1] = subd_face_corners[face.start_corner + mod(i + 1, face.num_corners)];
- c[2] = verts.size() - num_subd_verts + ngons;
- c[3] = subd_face_corners[face.start_corner + mod(i - 1, face.num_corners)];
-
- *(patch_data++) = c[0] + vert_offset;
- *(patch_data++) = c[1] + vert_offset;
- *(patch_data++) = c[2] + vert_offset;
- *(patch_data++) = c[3] + vert_offset;
-
- *(patch_data++) = f + face_offset;
- *(patch_data++) = face.num_corners | (i << 16);
- *(patch_data++) = face.start_corner + corner_offset;
- *(patch_data++) = subd_face_corners.size() + ngons + corner_offset;
- }
-
- ngons++;
- }
- }
-}
-
-PrimitiveType Mesh::primitive_type() const
-{
- return has_motion_blur() ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
deleted file mode 100644
index 8258c18ddd1..00000000000
--- a/intern/cycles/render/mesh.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __MESH_H__
-#define __MESH_H__
-
-#include "graph/node.h"
-
-#include "bvh/bvh_params.h"
-#include "render/attribute.h"
-#include "render/geometry.h"
-#include "render/shader.h"
-
-#include "util/util_array.h"
-#include "util/util_boundbox.h"
-#include "util/util_list.h"
-#include "util/util_map.h"
-#include "util/util_param.h"
-#include "util/util_set.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Attribute;
-class BVH;
-class Device;
-class DeviceScene;
-class Mesh;
-class Progress;
-class RenderStats;
-class Scene;
-class SceneParams;
-class AttributeRequest;
-struct SubdParams;
-class DiagSplit;
-struct PackedPatchTable;
-
-/* Mesh */
-
-class Mesh : public Geometry {
- protected:
- Mesh(const NodeType *node_type_, Type geom_type_);
-
- public:
- NODE_DECLARE
-
- /* Mesh Triangle */
- struct Triangle {
- int v[3];
-
- void bounds_grow(const float3 *verts, BoundBox &bounds) const;
-
- void motion_verts(const float3 *verts,
- const float3 *vert_steps,
- size_t num_verts,
- size_t num_steps,
- float time,
- float3 r_verts[3]) const;
-
- void verts_for_step(const float3 *verts,
- const float3 *vert_steps,
- size_t num_verts,
- size_t num_steps,
- size_t step,
- float3 r_verts[3]) const;
-
- float3 compute_normal(const float3 *verts) const;
-
- bool valid(const float3 *verts) const;
- };
-
- Triangle get_triangle(size_t i) const
- {
- Triangle tri = {{triangles[i * 3 + 0], triangles[i * 3 + 1], triangles[i * 3 + 2]}};
- return tri;
- }
-
- size_t num_triangles() const
- {
- return triangles.size() / 3;
- }
-
- /* Mesh SubdFace */
- struct SubdFace {
- int start_corner;
- int num_corners;
- int shader;
- bool smooth;
- int ptex_offset;
-
- bool is_quad()
- {
- return num_corners == 4;
- }
- float3 normal(const Mesh *mesh) const;
- int num_ptex_faces() const
- {
- return num_corners == 4 ? 1 : num_corners;
- }
- };
-
- struct SubdEdgeCrease {
- int v[2];
- float crease;
- };
-
- SubdEdgeCrease get_subd_crease(size_t i) const
- {
- SubdEdgeCrease s;
- s.v[0] = subd_creases_edge[i * 2];
- s.v[1] = subd_creases_edge[i * 2 + 1];
- s.crease = subd_creases_weight[i];
- return s;
- }
-
- bool need_tesselation();
-
- enum SubdivisionType {
- SUBDIVISION_NONE,
- SUBDIVISION_LINEAR,
- SUBDIVISION_CATMULL_CLARK,
- };
-
- NODE_SOCKET_API(SubdivisionType, subdivision_type)
-
- /* Mesh Data */
- NODE_SOCKET_API_ARRAY(array<int>, triangles)
- NODE_SOCKET_API_ARRAY(array<float3>, verts)
- NODE_SOCKET_API_ARRAY(array<int>, shader)
- NODE_SOCKET_API_ARRAY(array<bool>, smooth)
-
- /* used for storing patch info for subd triangles, only allocated if there are patches */
- NODE_SOCKET_API_ARRAY(array<int>, triangle_patch) /* must be < 0 for non subd triangles */
- NODE_SOCKET_API_ARRAY(array<float2>, vert_patch_uv)
-
- /* SubdFaces */
- NODE_SOCKET_API_ARRAY(array<int>, subd_start_corner)
- NODE_SOCKET_API_ARRAY(array<int>, subd_num_corners)
- NODE_SOCKET_API_ARRAY(array<int>, subd_shader)
- NODE_SOCKET_API_ARRAY(array<bool>, subd_smooth)
- NODE_SOCKET_API_ARRAY(array<int>, subd_ptex_offset)
-
- NODE_SOCKET_API_ARRAY(array<int>, subd_face_corners)
- NODE_SOCKET_API(int, num_ngons)
-
- NODE_SOCKET_API_ARRAY(array<int>, subd_creases_edge)
- NODE_SOCKET_API_ARRAY(array<float>, subd_creases_weight)
-
- /* Subdivisions parameters */
- NODE_SOCKET_API(float, subd_dicing_rate)
- NODE_SOCKET_API(int, subd_max_level)
- NODE_SOCKET_API(Transform, subd_objecttoworld)
-
- AttributeSet subd_attributes;
-
- private:
- PackedPatchTable *patch_table;
- /* BVH */
- size_t vert_offset;
-
- size_t patch_offset;
- size_t patch_table_offset;
- size_t face_offset;
- size_t corner_offset;
-
- size_t num_subd_verts;
- size_t num_subd_faces;
-
- unordered_map<int, int> vert_to_stitching_key_map; /* real vert index -> stitching index */
- unordered_multimap<int, int>
- vert_stitching_map; /* stitching index -> multiple real vert indices */
-
- friend class BVH2;
- friend class BVHBuild;
- friend class BVHSpatialSplit;
- friend class DiagSplit;
- friend class EdgeDice;
- friend class GeometryManager;
- friend class ObjectManager;
-
- SubdParams *subd_params = nullptr;
-
- public:
- /* Functions */
- Mesh();
- ~Mesh();
-
- void resize_mesh(int numverts, int numfaces);
- void reserve_mesh(int numverts, int numfaces);
- void resize_subd_faces(int numfaces, int num_ngons, int numcorners);
- void reserve_subd_faces(int numfaces, int num_ngons, int numcorners);
- void reserve_subd_creases(size_t num_creases);
- void clear_non_sockets();
- void clear(bool preserve_shaders = false) override;
- void add_vertex(float3 P);
- void add_vertex_slow(float3 P);
- void add_triangle(int v0, int v1, int v2, int shader, bool smooth);
- void add_subd_face(int *corners, int num_corners, int shader_, bool smooth_);
- void add_crease(int v0, int v1, float weight);
-
- void copy_center_to_motion_step(const int motion_step);
-
- void compute_bounds() override;
- void apply_transform(const Transform &tfm, const bool apply_to_motion) override;
- void add_face_normals();
- void add_vertex_normals();
- void add_undisplaced();
-
- void get_uv_tiles(ustring map, unordered_set<int> &tiles) override;
-
- void pack_shaders(Scene *scene, uint *shader);
- void pack_normals(float4 *vnormal);
- void pack_verts(float4 *tri_verts, uint4 *tri_vindex, uint *tri_patch, float2 *tri_patch_uv);
- void pack_patches(uint *patch_data);
-
- PrimitiveType primitive_type() const override;
-
- void tessellate(DiagSplit *split);
-
- SubdFace get_subd_face(size_t index) const;
-
- SubdParams *get_subd_params();
-
- size_t get_num_subd_faces() const
- {
- return num_subd_faces;
- }
-
- void set_num_subd_faces(size_t num_subd_faces_)
- {
- num_subd_faces = num_subd_faces_;
- }
-
- size_t get_num_subd_verts()
- {
- return num_subd_verts;
- }
-
- protected:
- void clear(bool preserve_shaders, bool preserve_voxel_data);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __MESH_H__ */
diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp
deleted file mode 100644
index 3a11f39d977..00000000000
--- a/intern/cycles/render/mesh_displace.cpp
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "device/device.h"
-
-#include "integrator/shader_eval.h"
-
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/scene.h"
-#include "render/shader.h"
-
-#include "util/util_foreach.h"
-#include "util/util_map.h"
-#include "util/util_progress.h"
-#include "util/util_set.h"
-
-CCL_NAMESPACE_BEGIN
-
-static float3 compute_face_normal(const Mesh::Triangle &t, float3 *verts)
-{
- float3 v0 = verts[t.v[0]];
- float3 v1 = verts[t.v[1]];
- float3 v2 = verts[t.v[2]];
-
- float3 norm = cross(v1 - v0, v2 - v0);
- float normlen = len(norm);
-
- if (normlen == 0.0f)
- return make_float3(1.0f, 0.0f, 0.0f);
-
- return norm / normlen;
-}
-
-/* Fill in coordinates for mesh displacement shader evaluation on device. */
-static int fill_shader_input(const Scene *scene,
- const Mesh *mesh,
- const int object_index,
- device_vector<KernelShaderEvalInput> &d_input)
-{
- int d_input_size = 0;
- KernelShaderEvalInput *d_input_data = d_input.data();
-
- const array<int> &mesh_shaders = mesh->get_shader();
- const array<Node *> &mesh_used_shaders = mesh->get_used_shaders();
- const array<float3> &mesh_verts = mesh->get_verts();
-
- const int num_verts = mesh_verts.size();
- vector<bool> done(num_verts, false);
-
- int num_triangles = mesh->num_triangles();
- for (int i = 0; i < num_triangles; i++) {
- Mesh::Triangle t = mesh->get_triangle(i);
- int shader_index = mesh_shaders[i];
- Shader *shader = (shader_index < mesh_used_shaders.size()) ?
- static_cast<Shader *>(mesh_used_shaders[shader_index]) :
- scene->default_surface;
-
- if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
- continue;
- }
-
- for (int j = 0; j < 3; j++) {
- if (done[t.v[j]])
- continue;
-
- done[t.v[j]] = true;
-
- /* set up object, primitive and barycentric coordinates */
- int object = object_index;
- int prim = mesh->prim_offset + i;
- float u, v;
-
- switch (j) {
- case 0:
- u = 1.0f;
- v = 0.0f;
- break;
- case 1:
- u = 0.0f;
- v = 1.0f;
- break;
- default:
- u = 0.0f;
- v = 0.0f;
- break;
- }
-
- /* back */
- KernelShaderEvalInput in;
- in.object = object;
- in.prim = prim;
- in.u = u;
- in.v = v;
- d_input_data[d_input_size++] = in;
- }
- }
-
- return d_input_size;
-}
-
-/* Read back mesh displacement shader output. */
-static void read_shader_output(const Scene *scene,
- Mesh *mesh,
- const device_vector<float> &d_output)
-{
- const array<int> &mesh_shaders = mesh->get_shader();
- const array<Node *> &mesh_used_shaders = mesh->get_used_shaders();
- array<float3> &mesh_verts = mesh->get_verts();
-
- const int num_verts = mesh_verts.size();
- const int num_motion_steps = mesh->get_motion_steps();
- vector<bool> done(num_verts, false);
-
- const float *d_output_data = d_output.data();
- int d_output_index = 0;
-
- Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- int num_triangles = mesh->num_triangles();
- for (int i = 0; i < num_triangles; i++) {
- Mesh::Triangle t = mesh->get_triangle(i);
- int shader_index = mesh_shaders[i];
- Shader *shader = (shader_index < mesh_used_shaders.size()) ?
- static_cast<Shader *>(mesh_used_shaders[shader_index]) :
- scene->default_surface;
-
- if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
- continue;
- }
-
- for (int j = 0; j < 3; j++) {
- if (!done[t.v[j]]) {
- done[t.v[j]] = true;
- float3 off = make_float3(d_output_data[d_output_index + 0],
- d_output_data[d_output_index + 1],
- d_output_data[d_output_index + 2]);
- d_output_index += 3;
-
- /* Avoid illegal vertex coordinates. */
- off = ensure_finite3(off);
- mesh_verts[t.v[j]] += off;
- if (attr_mP != NULL) {
- for (int step = 0; step < num_motion_steps - 1; step++) {
- float3 *mP = attr_mP->data_float3() + step * num_verts;
- mP[t.v[j]] += off;
- }
- }
- }
- }
- }
-}
-
-bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress &progress)
-{
- /* verify if we have a displacement shader */
- if (!mesh->has_true_displacement()) {
- return false;
- }
-
- const size_t num_verts = mesh->verts.size();
- const size_t num_triangles = mesh->num_triangles();
-
- if (num_triangles == 0) {
- return false;
- }
-
- string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
- progress.set_status("Updating Mesh", msg);
-
- /* find object index. todo: is arbitrary */
- size_t object_index = OBJECT_NONE;
-
- for (size_t i = 0; i < scene->objects.size(); i++) {
- if (scene->objects[i]->get_geometry() == mesh) {
- object_index = i;
- break;
- }
- }
-
- /* Evaluate shader on device. */
- ShaderEval shader_eval(device, progress);
- if (!shader_eval.eval(SHADER_EVAL_DISPLACE,
- num_verts,
- 3,
- function_bind(&fill_shader_input, scene, mesh, object_index, _1),
- function_bind(&read_shader_output, scene, mesh, _1))) {
- return false;
- }
-
- /* stitch */
- unordered_set<int> stitch_keys;
- for (pair<int, int> i : mesh->vert_to_stitching_key_map) {
- stitch_keys.insert(i.second); /* stitching index */
- }
-
- typedef unordered_multimap<int, int>::iterator map_it_t;
-
- for (int key : stitch_keys) {
- pair<map_it_t, map_it_t> verts = mesh->vert_stitching_map.equal_range(key);
-
- float3 pos = zero_float3();
- int num = 0;
-
- for (map_it_t v = verts.first; v != verts.second; ++v) {
- int vert = v->second;
-
- pos += mesh->verts[vert];
- num++;
- }
-
- if (num <= 1) {
- continue;
- }
-
- pos *= 1.0f / num;
-
- for (map_it_t v = verts.first; v != verts.second; ++v) {
- mesh->verts[v->second] = pos;
- }
- }
-
- /* for displacement method both, we only need to recompute the face
- * normals, as bump mapping in the shader will already alter the
- * vertex normal, so we start from the non-displaced vertex normals
- * to avoid applying the perturbation twice. */
- mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
- mesh->add_face_normals();
-
- bool need_recompute_vertex_normals = false;
-
- foreach (Node *node, mesh->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->has_displacement && shader->get_displacement_method() == DISPLACE_TRUE) {
- need_recompute_vertex_normals = true;
- break;
- }
- }
-
- if (need_recompute_vertex_normals) {
- bool flip = mesh->transform_negative_scaled;
- vector<bool> tri_has_true_disp(num_triangles, false);
-
- for (size_t i = 0; i < num_triangles; i++) {
- int shader_index = mesh->shader[i];
- Shader *shader = (shader_index < mesh->used_shaders.size()) ?
- static_cast<Shader *>(mesh->used_shaders[shader_index]) :
- scene->default_surface;
-
- tri_has_true_disp[i] = shader->has_displacement &&
- shader->get_displacement_method() == DISPLACE_TRUE;
- }
-
- /* static vertex normals */
-
- /* get attributes */
- Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
- Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
-
- float3 *fN = attr_fN->data_float3();
- float3 *vN = attr_vN->data_float3();
-
- /* compute vertex normals */
-
- /* zero vertex normals on triangles with true displacement */
- for (size_t i = 0; i < num_triangles; i++) {
- if (tri_has_true_disp[i]) {
- for (size_t j = 0; j < 3; j++) {
- vN[mesh->get_triangle(i).v[j]] = zero_float3();
- }
- }
- }
-
- /* add face normals to vertex normals */
- for (size_t i = 0; i < num_triangles; i++) {
- if (tri_has_true_disp[i]) {
- for (size_t j = 0; j < 3; j++) {
- int vert = mesh->get_triangle(i).v[j];
- vN[vert] += fN[i];
-
- /* add face normals to stitched vertices */
- if (stitch_keys.size()) {
- map_it_t key = mesh->vert_to_stitching_key_map.find(vert);
-
- if (key != mesh->vert_to_stitching_key_map.end()) {
- pair<map_it_t, map_it_t> verts = mesh->vert_stitching_map.equal_range(key->second);
-
- for (map_it_t v = verts.first; v != verts.second; ++v) {
- if (v->second == vert) {
- continue;
- }
-
- vN[v->second] += fN[i];
- }
- }
- }
- }
- }
- }
-
- /* normalize vertex normals */
- vector<bool> done(num_verts, false);
-
- for (size_t i = 0; i < num_triangles; i++) {
- if (tri_has_true_disp[i]) {
- for (size_t j = 0; j < 3; j++) {
- int vert = mesh->get_triangle(i).v[j];
-
- if (done[vert]) {
- continue;
- }
-
- vN[vert] = normalize(vN[vert]);
- if (flip)
- vN[vert] = -vN[vert];
-
- done[vert] = true;
- }
- }
- }
-
- /* motion vertex normals */
- Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
-
- if (mesh->has_motion_blur() && attr_mP && attr_mN) {
- for (int step = 0; step < mesh->motion_steps - 1; step++) {
- float3 *mP = attr_mP->data_float3() + step * mesh->verts.size();
- float3 *mN = attr_mN->data_float3() + step * mesh->verts.size();
-
- /* compute */
-
- /* zero vertex normals on triangles with true displacement */
- for (size_t i = 0; i < num_triangles; i++) {
- if (tri_has_true_disp[i]) {
- for (size_t j = 0; j < 3; j++) {
- mN[mesh->get_triangle(i).v[j]] = zero_float3();
- }
- }
- }
-
- /* add face normals to vertex normals */
- for (size_t i = 0; i < num_triangles; i++) {
- if (tri_has_true_disp[i]) {
- for (size_t j = 0; j < 3; j++) {
- int vert = mesh->get_triangle(i).v[j];
- float3 fN = compute_face_normal(mesh->get_triangle(i), mP);
- mN[vert] += fN;
-
- /* add face normals to stitched vertices */
- if (stitch_keys.size()) {
- map_it_t key = mesh->vert_to_stitching_key_map.find(vert);
-
- if (key != mesh->vert_to_stitching_key_map.end()) {
- pair<map_it_t, map_it_t> verts = mesh->vert_stitching_map.equal_range(
- key->second);
-
- for (map_it_t v = verts.first; v != verts.second; ++v) {
- if (v->second == vert) {
- continue;
- }
-
- mN[v->second] += fN;
- }
- }
- }
- }
- }
- }
-
- /* normalize vertex normals */
- vector<bool> done(num_verts, false);
-
- for (size_t i = 0; i < num_triangles; i++) {
- if (tri_has_true_disp[i]) {
- for (size_t j = 0; j < 3; j++) {
- int vert = mesh->get_triangle(i).v[j];
-
- if (done[vert]) {
- continue;
- }
-
- mN[vert] = normalize(mN[vert]);
- if (flip)
- mN[vert] = -mN[vert];
-
- done[vert] = true;
- }
- }
- }
- }
- }
- }
-
- return true;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp
deleted file mode 100644
index 575dbef8ec2..00000000000
--- a/intern/cycles/render/mesh_subdivision.cpp
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/attribute.h"
-#include "render/camera.h"
-#include "render/mesh.h"
-
-#include "subd/subd_patch.h"
-#include "subd/subd_patch_table.h"
-#include "subd/subd_split.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef WITH_OPENSUBDIV
-
-CCL_NAMESPACE_END
-
-# include <opensubdiv/far/patchMap.h>
-# include <opensubdiv/far/patchTableFactory.h>
-# include <opensubdiv/far/primvarRefiner.h>
-# include <opensubdiv/far/topologyRefinerFactory.h>
-
-/* specializations of TopologyRefinerFactory for ccl::Mesh */
-
-namespace OpenSubdiv {
-namespace OPENSUBDIV_VERSION {
-namespace Far {
-template<>
-bool TopologyRefinerFactory<ccl::Mesh>::resizeComponentTopology(TopologyRefiner &refiner,
- ccl::Mesh const &mesh)
-{
- setNumBaseVertices(refiner, mesh.get_verts().size());
- setNumBaseFaces(refiner, mesh.get_num_subd_faces());
-
- for (int i = 0; i < mesh.get_num_subd_faces(); i++) {
- setNumBaseFaceVertices(refiner, i, mesh.get_subd_num_corners()[i]);
- }
-
- return true;
-}
-
-template<>
-bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTopology(TopologyRefiner &refiner,
- ccl::Mesh const &mesh)
-{
- const ccl::array<int> &subd_face_corners = mesh.get_subd_face_corners();
- const ccl::array<int> &subd_start_corner = mesh.get_subd_start_corner();
- const ccl::array<int> &subd_num_corners = mesh.get_subd_num_corners();
-
- for (int i = 0; i < mesh.get_num_subd_faces(); i++) {
- IndexArray face_verts = getBaseFaceVertices(refiner, i);
-
- int start_corner = subd_start_corner[i];
- int *corner = &subd_face_corners[start_corner];
-
- for (int j = 0; j < subd_num_corners[i]; j++, corner++) {
- face_verts[j] = *corner;
- }
- }
-
- return true;
-}
-
-template<>
-bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner &refiner,
- ccl::Mesh const &mesh)
-{
- size_t num_creases = mesh.get_subd_creases_weight().size();
-
- for (int i = 0; i < num_creases; i++) {
- ccl::Mesh::SubdEdgeCrease crease = mesh.get_subd_crease(i);
- Index edge = findBaseEdge(refiner, crease.v[0], crease.v[1]);
-
- if (edge != INDEX_INVALID) {
- setBaseEdgeSharpness(refiner, edge, crease.crease * 10.0f);
- }
- }
-
- for (int i = 0; i < mesh.get_verts().size(); i++) {
- ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i);
-
- if (vert_edges.size() == 2) {
- float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]);
- sharpness = ccl::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1]));
-
- setBaseVertexSharpness(refiner, i, sharpness);
- }
- }
-
- return true;
-}
-
-template<>
-bool TopologyRefinerFactory<ccl::Mesh>::assignFaceVaryingTopology(TopologyRefiner & /*refiner*/,
- ccl::Mesh const & /*mesh*/)
-{
- return true;
-}
-
-template<>
-void TopologyRefinerFactory<ccl::Mesh>::reportInvalidTopology(TopologyError /*err_code*/,
- char const * /*msg*/,
- ccl::Mesh const & /*mesh*/)
-{
-}
-} /* namespace Far */
-} /* namespace OPENSUBDIV_VERSION */
-} /* namespace OpenSubdiv */
-
-CCL_NAMESPACE_BEGIN
-
-using namespace OpenSubdiv;
-
-/* struct that implements OpenSubdiv's vertex interface */
-
-template<typename T> struct OsdValue {
- T value;
-
- OsdValue()
- {
- }
-
- void Clear(void * = 0)
- {
- memset(&value, 0, sizeof(T));
- }
-
- void AddWithWeight(OsdValue<T> const &src, float weight)
- {
- value += src.value * weight;
- }
-};
-
-template<> void OsdValue<uchar4>::AddWithWeight(OsdValue<uchar4> const &src, float weight)
-{
- for (int i = 0; i < 4; i++) {
- value[i] += (uchar)(src.value[i] * weight);
- }
-}
-
-/* class for holding OpenSubdiv data used during tessellation */
-
-class OsdData {
- Mesh *mesh;
- vector<OsdValue<float3>> verts;
- Far::TopologyRefiner *refiner;
- Far::PatchTable *patch_table;
- Far::PatchMap *patch_map;
-
- public:
- OsdData() : mesh(NULL), refiner(NULL), patch_table(NULL), patch_map(NULL)
- {
- }
-
- ~OsdData()
- {
- delete refiner;
- delete patch_table;
- delete patch_map;
- }
-
- void build_from_mesh(Mesh *mesh_)
- {
- mesh = mesh_;
-
- /* type and options */
- Sdc::SchemeType type = Sdc::SCHEME_CATMARK;
-
- Sdc::Options options;
- options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
-
- /* create refiner */
- refiner = Far::TopologyRefinerFactory<Mesh>::Create(
- *mesh, Far::TopologyRefinerFactory<Mesh>::Options(type, options));
-
- /* adaptive refinement */
- int max_isolation = calculate_max_isolation();
- refiner->RefineAdaptive(Far::TopologyRefiner::AdaptiveOptions(max_isolation));
-
- /* create patch table */
- Far::PatchTableFactory::Options patch_options;
- patch_options.endCapType = Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
-
- patch_table = Far::PatchTableFactory::Create(*refiner, patch_options);
-
- /* interpolate verts */
- int num_refiner_verts = refiner->GetNumVerticesTotal();
- int num_local_points = patch_table->GetNumLocalPoints();
-
- verts.resize(num_refiner_verts + num_local_points);
- for (int i = 0; i < mesh->get_verts().size(); i++) {
- verts[i].value = mesh->get_verts()[i];
- }
-
- OsdValue<float3> *src = verts.data();
- for (int i = 0; i < refiner->GetMaxLevel(); i++) {
- OsdValue<float3> *dest = src + refiner->GetLevel(i).GetNumVertices();
- Far::PrimvarRefiner(*refiner).Interpolate(i + 1, src, dest);
- src = dest;
- }
-
- if (num_local_points) {
- patch_table->ComputeLocalPointValues(&verts[0], &verts[num_refiner_verts]);
- }
-
- /* create patch map */
- patch_map = new Far::PatchMap(*patch_table);
- }
-
- void subdivide_attribute(Attribute &attr)
- {
- Far::PrimvarRefiner primvar_refiner(*refiner);
-
- if (attr.element == ATTR_ELEMENT_VERTEX) {
- int num_refiner_verts = refiner->GetNumVerticesTotal();
- int num_local_points = patch_table->GetNumLocalPoints();
-
- attr.resize(num_refiner_verts + num_local_points);
- attr.flags |= ATTR_FINAL_SIZE;
-
- char *src = attr.buffer.data();
-
- for (int i = 0; i < refiner->GetMaxLevel(); i++) {
- char *dest = src + refiner->GetLevel(i).GetNumVertices() * attr.data_sizeof();
-
- if (attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
- primvar_refiner.Interpolate(i + 1, (OsdValue<float> *)src, (OsdValue<float> *&)dest);
- }
- else if (attr.same_storage(attr.type, TypeFloat2)) {
- primvar_refiner.Interpolate(i + 1, (OsdValue<float2> *)src, (OsdValue<float2> *&)dest);
- }
- else {
- primvar_refiner.Interpolate(i + 1, (OsdValue<float4> *)src, (OsdValue<float4> *&)dest);
- }
-
- src = dest;
- }
-
- if (num_local_points) {
- if (attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
- patch_table->ComputeLocalPointValues(
- (OsdValue<float> *)&attr.buffer[0],
- (OsdValue<float> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
- }
- else if (attr.same_storage(attr.type, TypeFloat2)) {
- patch_table->ComputeLocalPointValues(
- (OsdValue<float2> *)&attr.buffer[0],
- (OsdValue<float2> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
- }
- else {
- patch_table->ComputeLocalPointValues(
- (OsdValue<float4> *)&attr.buffer[0],
- (OsdValue<float4> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
- }
- }
- }
- else if (attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
- // TODO(mai): fvar interpolation
- }
- }
-
- int calculate_max_isolation()
- {
- /* loop over all edges to find longest in screen space */
- const Far::TopologyLevel &level = refiner->GetLevel(0);
- const SubdParams *subd_params = mesh->get_subd_params();
- Transform objecttoworld = subd_params->objecttoworld;
- Camera *cam = subd_params->camera;
-
- float longest_edge = 0.0f;
-
- for (size_t i = 0; i < level.GetNumEdges(); i++) {
- Far::ConstIndexArray verts = level.GetEdgeVertices(i);
-
- float3 a = mesh->get_verts()[verts[0]];
- float3 b = mesh->get_verts()[verts[1]];
-
- float edge_len;
-
- if (cam) {
- a = transform_point(&objecttoworld, a);
- b = transform_point(&objecttoworld, b);
-
- edge_len = len(a - b) / cam->world_to_raster_size((a + b) * 0.5f);
- }
- else {
- edge_len = len(a - b);
- }
-
- longest_edge = max(longest_edge, edge_len);
- }
-
- /* calculate isolation level */
- int isolation = (int)(log2f(max(longest_edge / subd_params->dicing_rate, 1.0f)) + 1.0f);
-
- return min(isolation, 10);
- }
-
- friend struct OsdPatch;
- friend class Mesh;
-};
-
-/* ccl::Patch implementation that uses OpenSubdiv for eval */
-
-struct OsdPatch : Patch {
- OsdData *osd_data;
-
- OsdPatch()
- {
- }
- OsdPatch(OsdData *data) : osd_data(data)
- {
- }
-
- void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
- {
- const Far::PatchTable::PatchHandle *handle = osd_data->patch_map->FindPatch(patch_index, u, v);
- assert(handle);
-
- float p_weights[20], du_weights[20], dv_weights[20];
- osd_data->patch_table->EvaluateBasis(*handle, u, v, p_weights, du_weights, dv_weights);
-
- Far::ConstIndexArray cv = osd_data->patch_table->GetPatchVertices(*handle);
-
- float3 du, dv;
- if (P)
- *P = zero_float3();
- du = zero_float3();
- dv = zero_float3();
-
- for (int i = 0; i < cv.size(); i++) {
- float3 p = osd_data->verts[cv[i]].value;
-
- if (P)
- *P += p * p_weights[i];
- du += p * du_weights[i];
- dv += p * dv_weights[i];
- }
-
- if (dPdu)
- *dPdu = du;
- if (dPdv)
- *dPdv = dv;
- if (N) {
- *N = cross(du, dv);
-
- float t = len(*N);
- *N = (t != 0.0f) ? *N / t : make_float3(0.0f, 0.0f, 1.0f);
- }
- }
-};
-
-#endif
-
-void Mesh::tessellate(DiagSplit *split)
-{
- /* reset the number of subdivision vertices, in case the Mesh was not cleared
- * between calls or data updates */
- num_subd_verts = 0;
-
-#ifdef WITH_OPENSUBDIV
- OsdData osd_data;
- bool need_packed_patch_table = false;
-
- if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
- if (get_num_subd_faces()) {
- osd_data.build_from_mesh(this);
- }
- }
- else
-#endif
- {
- /* force linear subdivision if OpenSubdiv is unavailable to avoid
- * falling into catmull-clark code paths by accident
- */
- subdivision_type = SUBDIVISION_LINEAR;
-
- /* force disable attribute subdivision for same reason as above */
- foreach (Attribute &attr, subd_attributes.attributes) {
- attr.flags &= ~ATTR_SUBDIVIDED;
- }
- }
-
- int num_faces = get_num_subd_faces();
-
- Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL);
- float3 *vN = (attr_vN) ? attr_vN->data_float3() : NULL;
-
- /* count patches */
- int num_patches = 0;
- for (int f = 0; f < num_faces; f++) {
- SubdFace face = get_subd_face(f);
-
- if (face.is_quad()) {
- num_patches++;
- }
- else {
- num_patches += face.num_corners;
- }
- }
-
- /* build patches from faces */
-#ifdef WITH_OPENSUBDIV
- if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
- vector<OsdPatch> osd_patches(num_patches, &osd_data);
- OsdPatch *patch = osd_patches.data();
-
- for (int f = 0; f < num_faces; f++) {
- SubdFace face = get_subd_face(f);
-
- if (face.is_quad()) {
- patch->patch_index = face.ptex_offset;
- patch->from_ngon = false;
- patch->shader = face.shader;
- patch++;
- }
- else {
- for (int corner = 0; corner < face.num_corners; corner++) {
- patch->patch_index = face.ptex_offset + corner;
- patch->from_ngon = true;
- patch->shader = face.shader;
- patch++;
- }
- }
- }
-
- /* split patches */
- split->split_patches(osd_patches.data(), sizeof(OsdPatch));
- }
- else
-#endif
- {
- vector<LinearQuadPatch> linear_patches(num_patches);
- LinearQuadPatch *patch = linear_patches.data();
-
- for (int f = 0; f < num_faces; f++) {
- SubdFace face = get_subd_face(f);
-
- if (face.is_quad()) {
- float3 *hull = patch->hull;
- float3 *normals = patch->normals;
-
- patch->patch_index = face.ptex_offset;
- patch->from_ngon = false;
-
- for (int i = 0; i < 4; i++) {
- hull[i] = verts[subd_face_corners[face.start_corner + i]];
- }
-
- if (face.smooth) {
- for (int i = 0; i < 4; i++) {
- normals[i] = vN[subd_face_corners[face.start_corner + i]];
- }
- }
- else {
- float3 N = face.normal(this);
- for (int i = 0; i < 4; i++) {
- normals[i] = N;
- }
- }
-
- swap(hull[2], hull[3]);
- swap(normals[2], normals[3]);
-
- patch->shader = face.shader;
- patch++;
- }
- else {
- /* ngon */
- float3 center_vert = zero_float3();
- float3 center_normal = zero_float3();
-
- float inv_num_corners = 1.0f / float(face.num_corners);
- for (int corner = 0; corner < face.num_corners; corner++) {
- center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
- center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
- }
-
- for (int corner = 0; corner < face.num_corners; corner++) {
- float3 *hull = patch->hull;
- float3 *normals = patch->normals;
-
- patch->patch_index = face.ptex_offset + corner;
- patch->from_ngon = true;
-
- patch->shader = face.shader;
-
- hull[0] =
- verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
- hull[1] =
- verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
- hull[2] =
- verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
- hull[3] = center_vert;
-
- hull[1] = (hull[1] + hull[0]) * 0.5;
- hull[2] = (hull[2] + hull[0]) * 0.5;
-
- if (face.smooth) {
- normals[0] =
- vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
- normals[1] =
- vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
- normals[2] =
- vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
- normals[3] = center_normal;
-
- normals[1] = (normals[1] + normals[0]) * 0.5;
- normals[2] = (normals[2] + normals[0]) * 0.5;
- }
- else {
- float3 N = face.normal(this);
- for (int i = 0; i < 4; i++) {
- normals[i] = N;
- }
- }
-
- patch++;
- }
- }
- }
-
- /* split patches */
- split->split_patches(linear_patches.data(), sizeof(LinearQuadPatch));
- }
-
- /* interpolate center points for attributes */
- foreach (Attribute &attr, subd_attributes.attributes) {
-#ifdef WITH_OPENSUBDIV
- if (subdivision_type == SUBDIVISION_CATMULL_CLARK && attr.flags & ATTR_SUBDIVIDED) {
- if (attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
- /* keep subdivision for corner attributes disabled for now */
- attr.flags &= ~ATTR_SUBDIVIDED;
- }
- else if (get_num_subd_faces()) {
- osd_data.subdivide_attribute(attr);
-
- need_packed_patch_table = true;
- continue;
- }
- }
-#endif
-
- char *data = attr.data();
- size_t stride = attr.data_sizeof();
- int ngons = 0;
-
- switch (attr.element) {
- case ATTR_ELEMENT_VERTEX: {
- for (int f = 0; f < num_faces; f++) {
- SubdFace face = get_subd_face(f);
-
- if (!face.is_quad()) {
- char *center = data + (verts.size() - num_subd_verts + ngons) * stride;
- attr.zero_data(center);
-
- float inv_num_corners = 1.0f / float(face.num_corners);
-
- for (int corner = 0; corner < face.num_corners; corner++) {
- attr.add_with_weight(center,
- data + subd_face_corners[face.start_corner + corner] * stride,
- inv_num_corners);
- }
-
- ngons++;
- }
- }
- } break;
- case ATTR_ELEMENT_VERTEX_MOTION: {
- // TODO(mai): implement
- } break;
- case ATTR_ELEMENT_CORNER: {
- for (int f = 0; f < num_faces; f++) {
- SubdFace face = get_subd_face(f);
-
- if (!face.is_quad()) {
- char *center = data + (subd_face_corners.size() + ngons) * stride;
- attr.zero_data(center);
-
- float inv_num_corners = 1.0f / float(face.num_corners);
-
- for (int corner = 0; corner < face.num_corners; corner++) {
- attr.add_with_weight(
- center, data + (face.start_corner + corner) * stride, inv_num_corners);
- }
-
- ngons++;
- }
- }
- } break;
- case ATTR_ELEMENT_CORNER_BYTE: {
- for (int f = 0; f < num_faces; f++) {
- SubdFace face = get_subd_face(f);
-
- if (!face.is_quad()) {
- uchar *center = (uchar *)data + (subd_face_corners.size() + ngons) * stride;
-
- float inv_num_corners = 1.0f / float(face.num_corners);
- float4 val = zero_float4();
-
- for (int corner = 0; corner < face.num_corners; corner++) {
- for (int i = 0; i < 4; i++) {
- val[i] += float(*(data + (face.start_corner + corner) * stride + i)) *
- inv_num_corners;
- }
- }
-
- for (int i = 0; i < 4; i++) {
- center[i] = uchar(min(max(val[i], 0.0f), 255.0f));
- }
-
- ngons++;
- }
- }
- } break;
- default:
- break;
- }
- }
-
-#ifdef WITH_OPENSUBDIV
- /* pack patch tables */
- if (need_packed_patch_table) {
- delete patch_table;
- patch_table = new PackedPatchTable;
- patch_table->pack(osd_data.patch_table);
- }
-#endif
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
deleted file mode 100644
index d775859d24d..00000000000
--- a/intern/cycles/render/nodes.cpp
+++ /dev/null
@@ -1,7170 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/nodes.h"
-#include "render/colorspace.h"
-#include "render/constant_fold.h"
-#include "render/film.h"
-#include "render/image.h"
-#include "render/image_sky.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/osl.h"
-#include "render/scene.h"
-#include "render/svm.h"
-
-#include "sky_model.h"
-
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_transform.h"
-
-#include "kernel/svm/svm_color_util.h"
-#include "kernel/svm/svm_mapping_util.h"
-#include "kernel/svm/svm_math_util.h"
-#include "kernel/svm/svm_ramp_util.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Texture Mapping */
-
-#define TEXTURE_MAPPING_DEFINE(TextureNode) \
- SOCKET_POINT(tex_mapping.translation, "Translation", zero_float3()); \
- SOCKET_VECTOR(tex_mapping.rotation, "Rotation", zero_float3()); \
- SOCKET_VECTOR(tex_mapping.scale, "Scale", one_float3()); \
-\
- SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \
- SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \
- SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \
-\
- static NodeEnum mapping_axis_enum; \
- mapping_axis_enum.insert("none", TextureMapping::NONE); \
- mapping_axis_enum.insert("x", TextureMapping::X); \
- mapping_axis_enum.insert("y", TextureMapping::Y); \
- mapping_axis_enum.insert("z", TextureMapping::Z); \
- SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \
- SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \
- SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \
-\
- static NodeEnum mapping_type_enum; \
- mapping_type_enum.insert("point", TextureMapping::POINT); \
- mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \
- mapping_type_enum.insert("vector", TextureMapping::VECTOR); \
- mapping_type_enum.insert("normal", TextureMapping::NORMAL); \
- SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \
-\
- static NodeEnum mapping_projection_enum; \
- mapping_projection_enum.insert("flat", TextureMapping::FLAT); \
- mapping_projection_enum.insert("cube", TextureMapping::CUBE); \
- mapping_projection_enum.insert("tube", TextureMapping::TUBE); \
- mapping_projection_enum.insert("sphere", TextureMapping::SPHERE); \
- SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT);
-
-TextureMapping::TextureMapping()
-{
-}
-
-Transform TextureMapping::compute_transform()
-{
- Transform mmat = transform_scale(zero_float3());
-
- if (x_mapping != NONE)
- mmat[0][x_mapping - 1] = 1.0f;
- if (y_mapping != NONE)
- mmat[1][y_mapping - 1] = 1.0f;
- if (z_mapping != NONE)
- mmat[2][z_mapping - 1] = 1.0f;
-
- float3 scale_clamped = scale;
-
- if (type == TEXTURE || type == NORMAL) {
- /* keep matrix invertible */
- if (fabsf(scale.x) < 1e-5f)
- scale_clamped.x = signf(scale.x) * 1e-5f;
- if (fabsf(scale.y) < 1e-5f)
- scale_clamped.y = signf(scale.y) * 1e-5f;
- if (fabsf(scale.z) < 1e-5f)
- scale_clamped.z = signf(scale.z) * 1e-5f;
- }
-
- Transform smat = transform_scale(scale_clamped);
- Transform rmat = transform_euler(rotation);
- Transform tmat = transform_translate(translation);
-
- Transform mat;
-
- switch (type) {
- case TEXTURE:
- /* inverse transform on texture coordinate gives
- * forward transform on texture */
- mat = tmat * rmat * smat;
- mat = transform_inverse(mat);
- break;
- case POINT:
- /* full transform */
- mat = tmat * rmat * smat;
- break;
- case VECTOR:
- /* no translation for vectors */
- mat = rmat * smat;
- break;
- case NORMAL:
- /* no translation for normals, and inverse transpose */
- mat = rmat * smat;
- mat = transform_transposed_inverse(mat);
- break;
- }
-
- /* projection last */
- mat = mat * mmat;
-
- return mat;
-}
-
-bool TextureMapping::skip()
-{
- if (translation != zero_float3())
- return false;
- if (rotation != zero_float3())
- return false;
- if (scale != one_float3())
- return false;
-
- if (x_mapping != X || y_mapping != Y || z_mapping != Z)
- return false;
- if (use_minmax)
- return false;
-
- return true;
-}
-
-void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_out)
-{
- compiler.add_node(NODE_TEXTURE_MAPPING, offset_in, offset_out);
-
- Transform tfm = compute_transform();
- compiler.add_node(tfm.x);
- compiler.add_node(tfm.y);
- compiler.add_node(tfm.z);
-
- if (use_minmax) {
- compiler.add_node(NODE_MIN_MAX, offset_out, offset_out);
- compiler.add_node(float3_to_float4(min));
- compiler.add_node(float3_to_float4(max));
- }
-
- if (type == NORMAL) {
- compiler.add_node(NODE_VECTOR_MATH,
- NODE_VECTOR_MATH_NORMALIZE,
- compiler.encode_uchar4(offset_out, offset_out, offset_out),
- compiler.encode_uchar4(SVM_STACK_INVALID, offset_out));
- }
-}
-
-/* Convenience function for texture nodes, allocating stack space to output
- * a modified vector and returning its offset */
-int TextureMapping::compile_begin(SVMCompiler &compiler, ShaderInput *vector_in)
-{
- if (!skip()) {
- int offset_in = compiler.stack_assign(vector_in);
- int offset_out = compiler.stack_find_offset(SocketType::VECTOR);
-
- compile(compiler, offset_in, offset_out);
-
- return offset_out;
- }
-
- return compiler.stack_assign(vector_in);
-}
-
-void TextureMapping::compile_end(SVMCompiler &compiler, ShaderInput *vector_in, int vector_offset)
-{
- if (!skip()) {
- compiler.stack_clear_offset(vector_in->type(), vector_offset);
- }
-}
-
-void TextureMapping::compile(OSLCompiler &compiler)
-{
- if (!skip()) {
- compiler.parameter("mapping", compute_transform());
- compiler.parameter("use_mapping", 1);
- }
-}
-
-/* Image Texture */
-
-NODE_DEFINE(ImageTextureNode)
-{
- NodeType *type = NodeType::add("image_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(ImageTextureNode);
-
- SOCKET_STRING(filename, "Filename", ustring());
- SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
-
- static NodeEnum alpha_type_enum;
- alpha_type_enum.insert("auto", IMAGE_ALPHA_AUTO);
- alpha_type_enum.insert("unassociated", IMAGE_ALPHA_UNASSOCIATED);
- alpha_type_enum.insert("associated", IMAGE_ALPHA_ASSOCIATED);
- alpha_type_enum.insert("channel_packed", IMAGE_ALPHA_CHANNEL_PACKED);
- alpha_type_enum.insert("ignore", IMAGE_ALPHA_IGNORE);
- SOCKET_ENUM(alpha_type, "Alpha Type", alpha_type_enum, IMAGE_ALPHA_AUTO);
-
- static NodeEnum interpolation_enum;
- interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
- interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
- interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
- interpolation_enum.insert("smart", INTERPOLATION_SMART);
- SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
-
- static NodeEnum extension_enum;
- extension_enum.insert("periodic", EXTENSION_REPEAT);
- extension_enum.insert("clamp", EXTENSION_EXTEND);
- extension_enum.insert("black", EXTENSION_CLIP);
- SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT);
-
- static NodeEnum projection_enum;
- projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT);
- projection_enum.insert("box", NODE_IMAGE_PROJ_BOX);
- projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE);
- projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE);
- SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT);
-
- SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f);
-
- SOCKET_INT_ARRAY(tiles, "Tiles", array<int>());
- SOCKET_BOOLEAN(animated, "Animated", false);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_UV);
-
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(alpha, "Alpha");
-
- return type;
-}
-
-ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(get_node_type())
-{
- colorspace = u_colorspace_raw;
- animated = false;
- tiles.push_back_slow(1001);
-}
-
-ShaderNode *ImageTextureNode::clone(ShaderGraph *graph) const
-{
- ImageTextureNode *node = graph->create_node<ImageTextureNode>(*this);
- node->handle = handle;
- return node;
-}
-
-ImageParams ImageTextureNode::image_params() const
-{
- ImageParams params;
- params.animated = animated;
- params.interpolation = interpolation;
- params.extension = extension;
- params.alpha_type = alpha_type;
- params.colorspace = colorspace;
- return params;
-}
-
-void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph)
-{
- /* Box projection computes its own UVs that always lie in the
- * 1001 tile, so there's no point in loading any others. */
- if (projection == NODE_IMAGE_PROJ_BOX) {
- tiles.clear();
- tiles.push_back_slow(1001);
- return;
- }
-
- if (!scene->params.background) {
- /* During interactive renders, all tiles are loaded.
- * While we could support updating this when UVs change, that could lead
- * to annoying interruptions when loading images while editing UVs. */
- return;
- }
-
- /* Only check UVs for tile culling if there are multiple tiles. */
- if (tiles.size() < 2) {
- return;
- }
-
- ShaderInput *vector_in = input("Vector");
- ustring attribute;
- if (vector_in->link) {
- ShaderNode *node = vector_in->link->parent;
- if (node->type == UVMapNode::get_node_type()) {
- UVMapNode *uvmap = (UVMapNode *)node;
- attribute = uvmap->get_attribute();
- }
- else if (node->type == TextureCoordinateNode::get_node_type()) {
- if (vector_in->link != node->output("UV")) {
- return;
- }
- }
- else {
- return;
- }
- }
-
- unordered_set<int> used_tiles;
- /* TODO(lukas): This is quite inefficient. A fairly simple improvement would
- * be to have a cache in each mesh that is indexed by attribute.
- * Additionally, building a graph-to-meshes list once could help. */
- foreach (Geometry *geom, scene->geometry) {
- foreach (Node *node, geom->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->graph == graph) {
- geom->get_uv_tiles(attribute, used_tiles);
- }
- }
- }
-
- array<int> new_tiles;
- foreach (int tile, tiles) {
- if (used_tiles.count(tile)) {
- new_tiles.push_back_slow(tile);
- }
- }
- tiles.steal_data(new_tiles);
-}
-
-void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
-#ifdef WITH_PTEX
- /* todo: avoid loading other texture coordinates when using ptex,
- * and hide texture coordinate socket in the UI */
- if (shader->has_surface_link() && string_endswith(filename, ".ptx")) {
- /* ptex */
- attributes->add(ATTR_STD_PTEX_FACE_ID);
- attributes->add(ATTR_STD_PTEX_UV);
- }
-#endif
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void ImageTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderOutput *color_out = output("Color");
- ShaderOutput *alpha_out = output("Alpha");
-
- if (handle.empty()) {
- cull_tiles(compiler.scene, compiler.current_graph);
- ImageManager *image_manager = compiler.scene->image_manager;
- handle = image_manager->add_image(filename.string(), image_params(), tiles);
- }
-
- /* All tiles have the same metadata. */
- const ImageMetaData metadata = handle.metadata();
- const bool compress_as_srgb = metadata.compress_as_srgb;
- const ustring known_colorspace = metadata.colorspace;
-
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
- uint flags = 0;
-
- if (compress_as_srgb) {
- flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
- }
- if (!alpha_out->links.empty()) {
- const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
- alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
- alpha_type == IMAGE_ALPHA_IGNORE);
-
- if (unassociate_alpha) {
- flags |= NODE_IMAGE_ALPHA_UNASSOCIATE;
- }
- }
-
- if (projection != NODE_IMAGE_PROJ_BOX) {
- /* If there only is one image (a very common case), we encode it as a negative value. */
- int num_nodes;
- if (handle.num_tiles() == 1) {
- num_nodes = -handle.svm_slot();
- }
- else {
- num_nodes = divide_up(handle.num_tiles(), 2);
- }
-
- compiler.add_node(NODE_TEX_IMAGE,
- num_nodes,
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(alpha_out),
- flags),
- projection);
-
- if (num_nodes > 0) {
- for (int i = 0; i < num_nodes; i++) {
- int4 node;
- node.x = tiles[2 * i];
- node.y = handle.svm_slot(2 * i);
- if (2 * i + 1 < tiles.size()) {
- node.z = tiles[2 * i + 1];
- node.w = handle.svm_slot(2 * i + 1);
- }
- else {
- node.z = -1;
- node.w = -1;
- }
- compiler.add_node(node.x, node.y, node.z, node.w);
- }
- }
- }
- else {
- assert(handle.num_tiles() == 1);
- compiler.add_node(NODE_TEX_IMAGE_BOX,
- handle.svm_slot(),
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(alpha_out),
- flags),
- __float_as_int(projection_blend));
- }
-
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
-}
-
-void ImageTextureNode::compile(OSLCompiler &compiler)
-{
- ShaderOutput *alpha_out = output("Alpha");
-
- tex_mapping.compile(compiler);
-
- if (handle.empty()) {
- ImageManager *image_manager = compiler.scene->image_manager;
- handle = image_manager->add_image(filename.string(), image_params());
- }
-
- const ImageMetaData metadata = handle.metadata();
- const bool is_float = metadata.is_float();
- const bool compress_as_srgb = metadata.compress_as_srgb;
- const ustring known_colorspace = metadata.colorspace;
-
- if (handle.svm_slot() == -1) {
- compiler.parameter_texture(
- "filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
- }
- else {
- compiler.parameter_texture("filename", handle.svm_slot());
- }
-
- const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
- alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
- alpha_type == IMAGE_ALPHA_IGNORE);
- const bool is_tiled = (filename.find("<UDIM>") != string::npos);
-
- compiler.parameter(this, "projection");
- compiler.parameter(this, "projection_blend");
- compiler.parameter("compress_as_srgb", compress_as_srgb);
- compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
- compiler.parameter("unassociate_alpha", !alpha_out->links.empty() && unassociate_alpha);
- compiler.parameter("is_float", is_float);
- compiler.parameter("is_tiled", is_tiled);
- compiler.parameter(this, "interpolation");
- compiler.parameter(this, "extension");
-
- compiler.add(this, "node_image_texture");
-}
-
-/* Environment Texture */
-
-NODE_DEFINE(EnvironmentTextureNode)
-{
- NodeType *type = NodeType::add("environment_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
-
- SOCKET_STRING(filename, "Filename", ustring());
- SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
-
- static NodeEnum alpha_type_enum;
- alpha_type_enum.insert("auto", IMAGE_ALPHA_AUTO);
- alpha_type_enum.insert("unassociated", IMAGE_ALPHA_UNASSOCIATED);
- alpha_type_enum.insert("associated", IMAGE_ALPHA_ASSOCIATED);
- alpha_type_enum.insert("channel_packed", IMAGE_ALPHA_CHANNEL_PACKED);
- alpha_type_enum.insert("ignore", IMAGE_ALPHA_IGNORE);
- SOCKET_ENUM(alpha_type, "Alpha Type", alpha_type_enum, IMAGE_ALPHA_AUTO);
-
- static NodeEnum interpolation_enum;
- interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
- interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
- interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
- interpolation_enum.insert("smart", INTERPOLATION_SMART);
- SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
-
- static NodeEnum projection_enum;
- projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR);
- projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL);
- SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR);
-
- SOCKET_BOOLEAN(animated, "Animated", false);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_POSITION);
-
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(alpha, "Alpha");
-
- return type;
-}
-
-EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(get_node_type())
-{
- colorspace = u_colorspace_raw;
- animated = false;
-}
-
-ShaderNode *EnvironmentTextureNode::clone(ShaderGraph *graph) const
-{
- EnvironmentTextureNode *node = graph->create_node<EnvironmentTextureNode>(*this);
- node->handle = handle;
- return node;
-}
-
-ImageParams EnvironmentTextureNode::image_params() const
-{
- ImageParams params;
- params.animated = animated;
- params.interpolation = interpolation;
- params.extension = EXTENSION_REPEAT;
- params.alpha_type = alpha_type;
- params.colorspace = colorspace;
- return params;
-}
-
-void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
-#ifdef WITH_PTEX
- if (shader->has_surface_link() && string_endswith(filename, ".ptx")) {
- /* ptex */
- attributes->add(ATTR_STD_PTEX_FACE_ID);
- attributes->add(ATTR_STD_PTEX_UV);
- }
-#endif
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void EnvironmentTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderOutput *color_out = output("Color");
- ShaderOutput *alpha_out = output("Alpha");
-
- if (handle.empty()) {
- ImageManager *image_manager = compiler.scene->image_manager;
- handle = image_manager->add_image(filename.string(), image_params());
- }
-
- const ImageMetaData metadata = handle.metadata();
- const bool compress_as_srgb = metadata.compress_as_srgb;
- const ustring known_colorspace = metadata.colorspace;
-
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
- uint flags = 0;
-
- if (compress_as_srgb) {
- flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
- }
-
- compiler.add_node(NODE_TEX_ENVIRONMENT,
- handle.svm_slot(),
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(alpha_out),
- flags),
- projection);
-
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
-}
-
-void EnvironmentTextureNode::compile(OSLCompiler &compiler)
-{
- if (handle.empty()) {
- ImageManager *image_manager = compiler.scene->image_manager;
- handle = image_manager->add_image(filename.string(), image_params());
- }
-
- tex_mapping.compile(compiler);
-
- const ImageMetaData metadata = handle.metadata();
- const bool is_float = metadata.is_float();
- const bool compress_as_srgb = metadata.compress_as_srgb;
- const ustring known_colorspace = metadata.colorspace;
-
- if (handle.svm_slot() == -1) {
- compiler.parameter_texture(
- "filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
- }
- else {
- compiler.parameter_texture("filename", handle.svm_slot());
- }
-
- compiler.parameter(this, "projection");
- compiler.parameter(this, "interpolation");
- compiler.parameter("compress_as_srgb", compress_as_srgb);
- compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
- compiler.parameter("is_float", is_float);
- compiler.add(this, "node_environment_texture");
-}
-
-/* Sky Texture */
-
-static float2 sky_spherical_coordinates(float3 dir)
-{
- return make_float2(acosf(dir.z), atan2f(dir.x, dir.y));
-}
-
-typedef struct SunSky {
- /* sun direction in spherical and cartesian */
- float theta, phi;
-
- /* Parameter */
- float radiance_x, radiance_y, radiance_z;
- float config_x[9], config_y[9], config_z[9], nishita_data[10];
-} SunSky;
-
-/* Preetham model */
-static float sky_perez_function(float lam[6], float theta, float gamma)
-{
- return (1.0f + lam[0] * expf(lam[1] / cosf(theta))) *
- (1.0f + lam[2] * expf(lam[3] * gamma) + lam[4] * cosf(gamma) * cosf(gamma));
-}
-
-static void sky_texture_precompute_preetham(SunSky *sunsky, float3 dir, float turbidity)
-{
- /*
- * We re-use the SunSky struct of the new model, to avoid extra variables
- * zenith_Y/x/y is now radiance_x/y/z
- * perez_Y/x/y is now config_x/y/z
- */
-
- float2 spherical = sky_spherical_coordinates(dir);
- float theta = spherical.x;
- float phi = spherical.y;
-
- sunsky->theta = theta;
- sunsky->phi = phi;
-
- float theta2 = theta * theta;
- float theta3 = theta2 * theta;
- float T = turbidity;
- float T2 = T * T;
-
- float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI_F - 2.0f * theta);
- sunsky->radiance_x = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
- sunsky->radiance_x *= 0.06f;
-
- sunsky->radiance_y = (0.00166f * theta3 - 0.00375f * theta2 + 0.00209f * theta) * T2 +
- (-0.02903f * theta3 + 0.06377f * theta2 - 0.03202f * theta + 0.00394f) * T +
- (0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * theta + 0.25886f);
-
- sunsky->radiance_z = (0.00275f * theta3 - 0.00610f * theta2 + 0.00317f * theta) * T2 +
- (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * theta + 0.00516f) * T +
- (0.15346f * theta3 - 0.26756f * theta2 + 0.06670f * theta + 0.26688f);
-
- sunsky->config_x[0] = (0.1787f * T - 1.4630f);
- sunsky->config_x[1] = (-0.3554f * T + 0.4275f);
- sunsky->config_x[2] = (-0.0227f * T + 5.3251f);
- sunsky->config_x[3] = (0.1206f * T - 2.5771f);
- sunsky->config_x[4] = (-0.0670f * T + 0.3703f);
-
- sunsky->config_y[0] = (-0.0193f * T - 0.2592f);
- sunsky->config_y[1] = (-0.0665f * T + 0.0008f);
- sunsky->config_y[2] = (-0.0004f * T + 0.2125f);
- sunsky->config_y[3] = (-0.0641f * T - 0.8989f);
- sunsky->config_y[4] = (-0.0033f * T + 0.0452f);
-
- sunsky->config_z[0] = (-0.0167f * T - 0.2608f);
- sunsky->config_z[1] = (-0.0950f * T + 0.0092f);
- sunsky->config_z[2] = (-0.0079f * T + 0.2102f);
- sunsky->config_z[3] = (-0.0441f * T - 1.6537f);
- sunsky->config_z[4] = (-0.0109f * T + 0.0529f);
-
- /* unused for old sky model */
- for (int i = 5; i < 9; i++) {
- sunsky->config_x[i] = 0.0f;
- sunsky->config_y[i] = 0.0f;
- sunsky->config_z[i] = 0.0f;
- }
-
- sunsky->radiance_x /= sky_perez_function(sunsky->config_x, 0, theta);
- sunsky->radiance_y /= sky_perez_function(sunsky->config_y, 0, theta);
- sunsky->radiance_z /= sky_perez_function(sunsky->config_z, 0, theta);
-}
-
-/* Hosek / Wilkie */
-static void sky_texture_precompute_hosek(SunSky *sunsky,
- float3 dir,
- float turbidity,
- float ground_albedo)
-{
- /* Calculate Sun Direction and save coordinates */
- float2 spherical = sky_spherical_coordinates(dir);
- float theta = spherical.x;
- float phi = spherical.y;
-
- /* Clamp Turbidity */
- turbidity = clamp(turbidity, 0.0f, 10.0f);
-
- /* Clamp to Horizon */
- theta = clamp(theta, 0.0f, M_PI_2_F);
-
- sunsky->theta = theta;
- sunsky->phi = phi;
-
- float solarElevation = M_PI_2_F - theta;
-
- /* Initialize Sky Model */
- SKY_ArHosekSkyModelState *sky_state;
- sky_state = SKY_arhosek_xyz_skymodelstate_alloc_init(
- (double)turbidity, (double)ground_albedo, (double)solarElevation);
-
- /* Copy values from sky_state to SunSky */
- for (int i = 0; i < 9; ++i) {
- sunsky->config_x[i] = (float)sky_state->configs[0][i];
- sunsky->config_y[i] = (float)sky_state->configs[1][i];
- sunsky->config_z[i] = (float)sky_state->configs[2][i];
- }
- sunsky->radiance_x = (float)sky_state->radiances[0];
- sunsky->radiance_y = (float)sky_state->radiances[1];
- sunsky->radiance_z = (float)sky_state->radiances[2];
-
- /* Free sky_state */
- SKY_arhosekskymodelstate_free(sky_state);
-}
-
-/* Nishita improved */
-static void sky_texture_precompute_nishita(SunSky *sunsky,
- bool sun_disc,
- float sun_size,
- float sun_intensity,
- float sun_elevation,
- float sun_rotation,
- float altitude,
- float air_density,
- float dust_density)
-{
- /* sample 2 sun pixels */
- float pixel_bottom[3];
- float pixel_top[3];
- SKY_nishita_skymodel_precompute_sun(
- sun_elevation, sun_size, altitude, air_density, dust_density, pixel_bottom, pixel_top);
- /* limit sun rotation between 0 and 360 degrees */
- sun_rotation = fmodf(sun_rotation, M_2PI_F);
- if (sun_rotation < 0.0f) {
- sun_rotation += M_2PI_F;
- }
- sun_rotation = M_2PI_F - sun_rotation;
- /* send data to svm_sky */
- sunsky->nishita_data[0] = pixel_bottom[0];
- sunsky->nishita_data[1] = pixel_bottom[1];
- sunsky->nishita_data[2] = pixel_bottom[2];
- sunsky->nishita_data[3] = pixel_top[0];
- sunsky->nishita_data[4] = pixel_top[1];
- sunsky->nishita_data[5] = pixel_top[2];
- sunsky->nishita_data[6] = sun_elevation;
- sunsky->nishita_data[7] = sun_rotation;
- sunsky->nishita_data[8] = sun_disc ? sun_size : -1.0f;
- sunsky->nishita_data[9] = sun_intensity;
-}
-
-NODE_DEFINE(SkyTextureNode)
-{
- NodeType *type = NodeType::add("sky_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(SkyTextureNode);
-
- static NodeEnum type_enum;
- type_enum.insert("preetham", NODE_SKY_PREETHAM);
- type_enum.insert("hosek_wilkie", NODE_SKY_HOSEK);
- type_enum.insert("nishita_improved", NODE_SKY_NISHITA);
- SOCKET_ENUM(sky_type, "Type", type_enum, NODE_SKY_NISHITA);
-
- SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f));
- SOCKET_FLOAT(turbidity, "Turbidity", 2.2f);
- SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f);
- SOCKET_BOOLEAN(sun_disc, "Sun Disc", true);
- SOCKET_FLOAT(sun_size, "Sun Size", 0.009512f);
- SOCKET_FLOAT(sun_intensity, "Sun Intensity", 1.0f);
- SOCKET_FLOAT(sun_elevation, "Sun Elevation", 15.0f * M_PI_F / 180.0f);
- SOCKET_FLOAT(sun_rotation, "Sun Rotation", 0.0f);
- SOCKET_FLOAT(altitude, "Altitude", 1.0f);
- SOCKET_FLOAT(air_density, "Air", 1.0f);
- SOCKET_FLOAT(dust_density, "Dust", 1.0f);
- SOCKET_FLOAT(ozone_density, "Ozone", 1.0f);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
-
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-SkyTextureNode::SkyTextureNode() : TextureNode(get_node_type())
-{
-}
-
-void SkyTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderOutput *color_out = output("Color");
-
- SunSky sunsky;
- if (sky_type == NODE_SKY_PREETHAM)
- sky_texture_precompute_preetham(&sunsky, sun_direction, turbidity);
- else if (sky_type == NODE_SKY_HOSEK)
- sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
- else if (sky_type == NODE_SKY_NISHITA) {
- /* Clamp altitude to reasonable values.
- * Below 1m causes numerical issues and above 60km is space. */
- float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
-
- sky_texture_precompute_nishita(&sunsky,
- sun_disc,
- get_sun_size(),
- sun_intensity,
- sun_elevation,
- sun_rotation,
- clamped_altitude,
- air_density,
- dust_density);
- /* precomputed texture image parameters */
- ImageManager *image_manager = compiler.scene->image_manager;
- ImageParams impar;
- impar.interpolation = INTERPOLATION_LINEAR;
- impar.extension = EXTENSION_EXTEND;
-
- /* precompute sky texture */
- if (handle.empty()) {
- SkyLoader *loader = new SkyLoader(
- sun_elevation, clamped_altitude, air_density, dust_density, ozone_density);
- handle = image_manager->add_image(loader, impar);
- }
- }
- else
- assert(false);
-
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
-
- compiler.stack_assign(color_out);
- compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_type);
- /* nishita doesn't need this data */
- if (sky_type != NODE_SKY_NISHITA) {
- compiler.add_node(__float_as_uint(sunsky.phi),
- __float_as_uint(sunsky.theta),
- __float_as_uint(sunsky.radiance_x),
- __float_as_uint(sunsky.radiance_y));
- compiler.add_node(__float_as_uint(sunsky.radiance_z),
- __float_as_uint(sunsky.config_x[0]),
- __float_as_uint(sunsky.config_x[1]),
- __float_as_uint(sunsky.config_x[2]));
- compiler.add_node(__float_as_uint(sunsky.config_x[3]),
- __float_as_uint(sunsky.config_x[4]),
- __float_as_uint(sunsky.config_x[5]),
- __float_as_uint(sunsky.config_x[6]));
- compiler.add_node(__float_as_uint(sunsky.config_x[7]),
- __float_as_uint(sunsky.config_x[8]),
- __float_as_uint(sunsky.config_y[0]),
- __float_as_uint(sunsky.config_y[1]));
- compiler.add_node(__float_as_uint(sunsky.config_y[2]),
- __float_as_uint(sunsky.config_y[3]),
- __float_as_uint(sunsky.config_y[4]),
- __float_as_uint(sunsky.config_y[5]));
- compiler.add_node(__float_as_uint(sunsky.config_y[6]),
- __float_as_uint(sunsky.config_y[7]),
- __float_as_uint(sunsky.config_y[8]),
- __float_as_uint(sunsky.config_z[0]));
- compiler.add_node(__float_as_uint(sunsky.config_z[1]),
- __float_as_uint(sunsky.config_z[2]),
- __float_as_uint(sunsky.config_z[3]),
- __float_as_uint(sunsky.config_z[4]));
- compiler.add_node(__float_as_uint(sunsky.config_z[5]),
- __float_as_uint(sunsky.config_z[6]),
- __float_as_uint(sunsky.config_z[7]),
- __float_as_uint(sunsky.config_z[8]));
- }
- else {
- compiler.add_node(__float_as_uint(sunsky.nishita_data[0]),
- __float_as_uint(sunsky.nishita_data[1]),
- __float_as_uint(sunsky.nishita_data[2]),
- __float_as_uint(sunsky.nishita_data[3]));
- compiler.add_node(__float_as_uint(sunsky.nishita_data[4]),
- __float_as_uint(sunsky.nishita_data[5]),
- __float_as_uint(sunsky.nishita_data[6]),
- __float_as_uint(sunsky.nishita_data[7]));
- compiler.add_node(__float_as_uint(sunsky.nishita_data[8]),
- __float_as_uint(sunsky.nishita_data[9]),
- handle.svm_slot(),
- 0);
- }
-
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
-}
-
-void SkyTextureNode::compile(OSLCompiler &compiler)
-{
- tex_mapping.compile(compiler);
-
- SunSky sunsky;
- if (sky_type == NODE_SKY_PREETHAM)
- sky_texture_precompute_preetham(&sunsky, sun_direction, turbidity);
- else if (sky_type == NODE_SKY_HOSEK)
- sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
- else if (sky_type == NODE_SKY_NISHITA) {
- /* Clamp altitude to reasonable values.
- * Below 1m causes numerical issues and above 60km is space. */
- float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
-
- sky_texture_precompute_nishita(&sunsky,
- sun_disc,
- get_sun_size(),
- sun_intensity,
- sun_elevation,
- sun_rotation,
- clamped_altitude,
- air_density,
- dust_density);
- /* precomputed texture image parameters */
- ImageManager *image_manager = compiler.scene->image_manager;
- ImageParams impar;
- impar.interpolation = INTERPOLATION_LINEAR;
- impar.extension = EXTENSION_EXTEND;
-
- /* precompute sky texture */
- if (handle.empty()) {
- SkyLoader *loader = new SkyLoader(
- sun_elevation, clamped_altitude, air_density, dust_density, ozone_density);
- handle = image_manager->add_image(loader, impar);
- }
- }
- else
- assert(false);
-
- compiler.parameter(this, "sky_type");
- compiler.parameter("theta", sunsky.theta);
- compiler.parameter("phi", sunsky.phi);
- compiler.parameter_color("radiance",
- make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z));
- compiler.parameter_array("config_x", sunsky.config_x, 9);
- compiler.parameter_array("config_y", sunsky.config_y, 9);
- compiler.parameter_array("config_z", sunsky.config_z, 9);
- compiler.parameter_array("nishita_data", sunsky.nishita_data, 10);
- /* nishita texture */
- if (sky_type == NODE_SKY_NISHITA) {
- compiler.parameter_texture("filename", handle.svm_slot());
- }
- compiler.add(this, "node_sky_texture");
-}
-
-/* Gradient Texture */
-
-NODE_DEFINE(GradientTextureNode)
-{
- NodeType *type = NodeType::add("gradient_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(GradientTextureNode);
-
- static NodeEnum type_enum;
- type_enum.insert("linear", NODE_BLEND_LINEAR);
- type_enum.insert("quadratic", NODE_BLEND_QUADRATIC);
- type_enum.insert("easing", NODE_BLEND_EASING);
- type_enum.insert("diagonal", NODE_BLEND_DIAGONAL);
- type_enum.insert("radial", NODE_BLEND_RADIAL);
- type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE);
- type_enum.insert("spherical", NODE_BLEND_SPHERICAL);
- SOCKET_ENUM(gradient_type, "Type", type_enum, NODE_BLEND_LINEAR);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
-
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(fac, "Fac");
-
- return type;
-}
-
-GradientTextureNode::GradientTextureNode() : TextureNode(get_node_type())
-{
-}
-
-void GradientTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderOutput *color_out = output("Color");
- ShaderOutput *fac_out = output("Fac");
-
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
-
- compiler.add_node(NODE_TEX_GRADIENT,
- compiler.encode_uchar4(gradient_type,
- vector_offset,
- compiler.stack_assign_if_linked(fac_out),
- compiler.stack_assign_if_linked(color_out)));
-
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
-}
-
-void GradientTextureNode::compile(OSLCompiler &compiler)
-{
- tex_mapping.compile(compiler);
-
- compiler.parameter(this, "gradient_type");
- compiler.add(this, "node_gradient_texture");
-}
-
-/* Noise Texture */
-
-NODE_DEFINE(NoiseTextureNode)
-{
- NodeType *type = NodeType::add("noise_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(NoiseTextureNode);
-
- static NodeEnum dimensions_enum;
- dimensions_enum.insert("1D", 1);
- dimensions_enum.insert("2D", 2);
- dimensions_enum.insert("3D", 3);
- dimensions_enum.insert("4D", 4);
- SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
- SOCKET_IN_FLOAT(w, "W", 0.0f);
- SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
- SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
- SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
- SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
-
- SOCKET_OUT_FLOAT(fac, "Fac");
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-NoiseTextureNode::NoiseTextureNode() : TextureNode(get_node_type())
-{
-}
-
-void NoiseTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *w_in = input("W");
- ShaderInput *scale_in = input("Scale");
- ShaderInput *detail_in = input("Detail");
- ShaderInput *roughness_in = input("Roughness");
- ShaderInput *distortion_in = input("Distortion");
- ShaderOutput *fac_out = output("Fac");
- ShaderOutput *color_out = output("Color");
-
- int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
- int w_stack_offset = compiler.stack_assign_if_linked(w_in);
- int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
- int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
- int roughness_stack_offset = compiler.stack_assign_if_linked(roughness_in);
- int distortion_stack_offset = compiler.stack_assign_if_linked(distortion_in);
- int fac_stack_offset = compiler.stack_assign_if_linked(fac_out);
- int color_stack_offset = compiler.stack_assign_if_linked(color_out);
-
- compiler.add_node(
- NODE_TEX_NOISE,
- dimensions,
- compiler.encode_uchar4(
- vector_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset),
- compiler.encode_uchar4(
- roughness_stack_offset, distortion_stack_offset, fac_stack_offset, color_stack_offset));
- compiler.add_node(
- __float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(roughness));
-
- compiler.add_node(
- __float_as_int(distortion), SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID);
-
- tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
-}
-
-void NoiseTextureNode::compile(OSLCompiler &compiler)
-{
- tex_mapping.compile(compiler);
- compiler.parameter(this, "dimensions");
- compiler.add(this, "node_noise_texture");
-}
-
-/* Voronoi Texture */
-
-NODE_DEFINE(VoronoiTextureNode)
-{
- NodeType *type = NodeType::add("voronoi_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
-
- static NodeEnum dimensions_enum;
- dimensions_enum.insert("1D", 1);
- dimensions_enum.insert("2D", 2);
- dimensions_enum.insert("3D", 3);
- dimensions_enum.insert("4D", 4);
- SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
-
- static NodeEnum metric_enum;
- metric_enum.insert("euclidean", NODE_VORONOI_EUCLIDEAN);
- metric_enum.insert("manhattan", NODE_VORONOI_MANHATTAN);
- metric_enum.insert("chebychev", NODE_VORONOI_CHEBYCHEV);
- metric_enum.insert("minkowski", NODE_VORONOI_MINKOWSKI);
- SOCKET_ENUM(metric, "Distance Metric", metric_enum, NODE_VORONOI_EUCLIDEAN);
-
- static NodeEnum feature_enum;
- feature_enum.insert("f1", NODE_VORONOI_F1);
- feature_enum.insert("f2", NODE_VORONOI_F2);
- feature_enum.insert("smooth_f1", NODE_VORONOI_SMOOTH_F1);
- feature_enum.insert("distance_to_edge", NODE_VORONOI_DISTANCE_TO_EDGE);
- feature_enum.insert("n_sphere_radius", NODE_VORONOI_N_SPHERE_RADIUS);
- SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_F1);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
- SOCKET_IN_FLOAT(w, "W", 0.0f);
- SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
- SOCKET_IN_FLOAT(smoothness, "Smoothness", 5.0f);
- SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
- SOCKET_IN_FLOAT(randomness, "Randomness", 1.0f);
-
- SOCKET_OUT_FLOAT(distance, "Distance");
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_POINT(position, "Position");
- SOCKET_OUT_FLOAT(w, "W");
- SOCKET_OUT_FLOAT(radius, "Radius");
-
- return type;
-}
-
-VoronoiTextureNode::VoronoiTextureNode() : TextureNode(get_node_type())
-{
-}
-
-void VoronoiTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *w_in = input("W");
- ShaderInput *scale_in = input("Scale");
- ShaderInput *smoothness_in = input("Smoothness");
- ShaderInput *exponent_in = input("Exponent");
- ShaderInput *randomness_in = input("Randomness");
-
- ShaderOutput *distance_out = output("Distance");
- ShaderOutput *color_out = output("Color");
- ShaderOutput *position_out = output("Position");
- ShaderOutput *w_out = output("W");
- ShaderOutput *radius_out = output("Radius");
-
- int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
- int w_in_stack_offset = compiler.stack_assign_if_linked(w_in);
- int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
- int smoothness_stack_offset = compiler.stack_assign_if_linked(smoothness_in);
- int exponent_stack_offset = compiler.stack_assign_if_linked(exponent_in);
- int randomness_stack_offset = compiler.stack_assign_if_linked(randomness_in);
- int distance_stack_offset = compiler.stack_assign_if_linked(distance_out);
- int color_stack_offset = compiler.stack_assign_if_linked(color_out);
- int position_stack_offset = compiler.stack_assign_if_linked(position_out);
- int w_out_stack_offset = compiler.stack_assign_if_linked(w_out);
- int radius_stack_offset = compiler.stack_assign_if_linked(radius_out);
-
- compiler.add_node(NODE_TEX_VORONOI, dimensions, feature, metric);
- compiler.add_node(
- compiler.encode_uchar4(
- vector_stack_offset, w_in_stack_offset, scale_stack_offset, smoothness_stack_offset),
- compiler.encode_uchar4(exponent_stack_offset,
- randomness_stack_offset,
- distance_stack_offset,
- color_stack_offset),
- compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset),
- __float_as_int(w));
-
- compiler.add_node(__float_as_int(scale),
- __float_as_int(smoothness),
- __float_as_int(exponent),
- __float_as_int(randomness));
-
- tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
-}
-
-void VoronoiTextureNode::compile(OSLCompiler &compiler)
-{
- tex_mapping.compile(compiler);
-
- compiler.parameter(this, "dimensions");
- compiler.parameter(this, "feature");
- compiler.parameter(this, "metric");
- compiler.add(this, "node_voronoi_texture");
-}
-
-/* IES Light */
-
-NODE_DEFINE(IESLightNode)
-{
- NodeType *type = NodeType::add("ies_light", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(IESLightNode);
-
- SOCKET_STRING(ies, "IES", ustring());
- SOCKET_STRING(filename, "File Name", ustring());
-
- SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_NORMAL);
-
- SOCKET_OUT_FLOAT(fac, "Fac");
-
- return type;
-}
-
-IESLightNode::IESLightNode() : TextureNode(get_node_type())
-{
- light_manager = NULL;
- slot = -1;
-}
-
-ShaderNode *IESLightNode::clone(ShaderGraph *graph) const
-{
- IESLightNode *node = graph->create_node<IESLightNode>(*this);
-
- node->light_manager = NULL;
- node->slot = -1;
-
- return node;
-}
-
-IESLightNode::~IESLightNode()
-{
- if (light_manager) {
- light_manager->remove_ies(slot);
- }
-}
-
-void IESLightNode::get_slot()
-{
- assert(light_manager);
-
- if (slot == -1) {
- if (ies.empty()) {
- slot = light_manager->add_ies_from_file(filename.string());
- }
- else {
- slot = light_manager->add_ies(ies.string());
- }
- }
-}
-
-void IESLightNode::compile(SVMCompiler &compiler)
-{
- light_manager = compiler.scene->light_manager;
- get_slot();
-
- ShaderInput *strength_in = input("Strength");
- ShaderInput *vector_in = input("Vector");
- ShaderOutput *fac_out = output("Fac");
-
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
-
- compiler.add_node(NODE_IES,
- compiler.encode_uchar4(compiler.stack_assign_if_linked(strength_in),
- vector_offset,
- compiler.stack_assign(fac_out),
- 0),
- slot,
- __float_as_int(strength));
-
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
-}
-
-void IESLightNode::compile(OSLCompiler &compiler)
-{
- light_manager = compiler.scene->light_manager;
- get_slot();
-
- tex_mapping.compile(compiler);
-
- compiler.parameter_texture_ies("filename", slot);
- compiler.add(this, "node_ies_light");
-}
-
-/* White Noise Texture */
-
-NODE_DEFINE(WhiteNoiseTextureNode)
-{
- NodeType *type = NodeType::add("white_noise_texture", create, NodeType::SHADER);
-
- static NodeEnum dimensions_enum;
- dimensions_enum.insert("1D", 1);
- dimensions_enum.insert("2D", 2);
- dimensions_enum.insert("3D", 3);
- dimensions_enum.insert("4D", 4);
- SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3());
- SOCKET_IN_FLOAT(w, "W", 0.0f);
-
- SOCKET_OUT_FLOAT(value, "Value");
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-WhiteNoiseTextureNode::WhiteNoiseTextureNode() : ShaderNode(get_node_type())
-{
-}
-
-void WhiteNoiseTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *w_in = input("W");
- ShaderOutput *value_out = output("Value");
- ShaderOutput *color_out = output("Color");
-
- int vector_stack_offset = compiler.stack_assign(vector_in);
- int w_stack_offset = compiler.stack_assign(w_in);
- int value_stack_offset = compiler.stack_assign(value_out);
- int color_stack_offset = compiler.stack_assign(color_out);
-
- compiler.add_node(NODE_TEX_WHITE_NOISE,
- dimensions,
- compiler.encode_uchar4(vector_stack_offset, w_stack_offset),
- compiler.encode_uchar4(value_stack_offset, color_stack_offset));
-}
-
-void WhiteNoiseTextureNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "dimensions");
- compiler.add(this, "node_white_noise_texture");
-}
-
-/* Musgrave Texture */
-
-NODE_DEFINE(MusgraveTextureNode)
-{
- NodeType *type = NodeType::add("musgrave_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(MusgraveTextureNode);
-
- static NodeEnum dimensions_enum;
- dimensions_enum.insert("1D", 1);
- dimensions_enum.insert("2D", 2);
- dimensions_enum.insert("3D", 3);
- dimensions_enum.insert("4D", 4);
- SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
-
- static NodeEnum type_enum;
- type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
- type_enum.insert("fBM", NODE_MUSGRAVE_FBM);
- type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL);
- type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL);
- type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
- SOCKET_ENUM(musgrave_type, "Type", type_enum, NODE_MUSGRAVE_FBM);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
- SOCKET_IN_FLOAT(w, "W", 0.0f);
- SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
- SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
- SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f);
- SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 2.0f);
- SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
- SOCKET_IN_FLOAT(gain, "Gain", 1.0f);
-
- SOCKET_OUT_FLOAT(fac, "Fac");
-
- return type;
-}
-
-MusgraveTextureNode::MusgraveTextureNode() : TextureNode(get_node_type())
-{
-}
-
-void MusgraveTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *w_in = input("W");
- ShaderInput *scale_in = input("Scale");
- ShaderInput *detail_in = input("Detail");
- ShaderInput *dimension_in = input("Dimension");
- ShaderInput *lacunarity_in = input("Lacunarity");
- ShaderInput *offset_in = input("Offset");
- ShaderInput *gain_in = input("Gain");
- ShaderOutput *fac_out = output("Fac");
-
- int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
- int w_stack_offset = compiler.stack_assign_if_linked(w_in);
- int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
- int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
- int dimension_stack_offset = compiler.stack_assign_if_linked(dimension_in);
- int lacunarity_stack_offset = compiler.stack_assign_if_linked(lacunarity_in);
- int offset_stack_offset = compiler.stack_assign_if_linked(offset_in);
- int gain_stack_offset = compiler.stack_assign_if_linked(gain_in);
- int fac_stack_offset = compiler.stack_assign(fac_out);
-
- compiler.add_node(
- NODE_TEX_MUSGRAVE,
- compiler.encode_uchar4(musgrave_type, dimensions, vector_stack_offset, w_stack_offset),
- compiler.encode_uchar4(scale_stack_offset,
- detail_stack_offset,
- dimension_stack_offset,
- lacunarity_stack_offset),
- compiler.encode_uchar4(offset_stack_offset, gain_stack_offset, fac_stack_offset));
- compiler.add_node(
- __float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(dimension));
- compiler.add_node(__float_as_int(lacunarity), __float_as_int(offset), __float_as_int(gain));
-
- tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
-}
-
-void MusgraveTextureNode::compile(OSLCompiler &compiler)
-{
- tex_mapping.compile(compiler);
-
- compiler.parameter(this, "musgrave_type");
- compiler.parameter(this, "dimensions");
- compiler.add(this, "node_musgrave_texture");
-}
-
-/* Wave Texture */
-
-NODE_DEFINE(WaveTextureNode)
-{
- NodeType *type = NodeType::add("wave_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(WaveTextureNode);
-
- static NodeEnum type_enum;
- type_enum.insert("bands", NODE_WAVE_BANDS);
- type_enum.insert("rings", NODE_WAVE_RINGS);
- SOCKET_ENUM(wave_type, "Type", type_enum, NODE_WAVE_BANDS);
-
- static NodeEnum bands_direction_enum;
- bands_direction_enum.insert("x", NODE_WAVE_BANDS_DIRECTION_X);
- bands_direction_enum.insert("y", NODE_WAVE_BANDS_DIRECTION_Y);
- bands_direction_enum.insert("z", NODE_WAVE_BANDS_DIRECTION_Z);
- bands_direction_enum.insert("diagonal", NODE_WAVE_BANDS_DIRECTION_DIAGONAL);
- SOCKET_ENUM(
- bands_direction, "Bands Direction", bands_direction_enum, NODE_WAVE_BANDS_DIRECTION_X);
-
- static NodeEnum rings_direction_enum;
- rings_direction_enum.insert("x", NODE_WAVE_RINGS_DIRECTION_X);
- rings_direction_enum.insert("y", NODE_WAVE_RINGS_DIRECTION_Y);
- rings_direction_enum.insert("z", NODE_WAVE_RINGS_DIRECTION_Z);
- rings_direction_enum.insert("spherical", NODE_WAVE_RINGS_DIRECTION_SPHERICAL);
- SOCKET_ENUM(
- rings_direction, "Rings Direction", rings_direction_enum, NODE_WAVE_BANDS_DIRECTION_X);
-
- static NodeEnum profile_enum;
- profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN);
- profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW);
- profile_enum.insert("tri", NODE_WAVE_PROFILE_TRI);
- SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
- SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
- SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
- SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
- SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f);
- SOCKET_IN_FLOAT(detail_roughness, "Detail Roughness", 0.5f);
- SOCKET_IN_FLOAT(phase, "Phase Offset", 0.0f);
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(fac, "Fac");
-
- return type;
-}
-
-WaveTextureNode::WaveTextureNode() : TextureNode(get_node_type())
-{
-}
-
-void WaveTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *scale_in = input("Scale");
- ShaderInput *distortion_in = input("Distortion");
- ShaderInput *detail_in = input("Detail");
- ShaderInput *dscale_in = input("Detail Scale");
- ShaderInput *droughness_in = input("Detail Roughness");
- ShaderInput *phase_in = input("Phase Offset");
- ShaderOutput *color_out = output("Color");
- ShaderOutput *fac_out = output("Fac");
-
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
-
- compiler.add_node(NODE_TEX_WAVE,
- compiler.encode_uchar4(wave_type, bands_direction, rings_direction, profile),
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign_if_linked(scale_in),
- compiler.stack_assign_if_linked(distortion_in)),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(detail_in),
- compiler.stack_assign_if_linked(dscale_in),
- compiler.stack_assign_if_linked(droughness_in),
- compiler.stack_assign_if_linked(phase_in)));
-
- compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(fac_out)),
- __float_as_int(scale),
- __float_as_int(distortion),
- __float_as_int(detail));
-
- compiler.add_node(__float_as_int(detail_scale),
- __float_as_int(detail_roughness),
- __float_as_int(phase),
- SVM_STACK_INVALID);
-
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
-}
-
-void WaveTextureNode::compile(OSLCompiler &compiler)
-{
- tex_mapping.compile(compiler);
-
- compiler.parameter(this, "wave_type");
- compiler.parameter(this, "bands_direction");
- compiler.parameter(this, "rings_direction");
- compiler.parameter(this, "profile");
-
- compiler.add(this, "node_wave_texture");
-}
-
-/* Magic Texture */
-
-NODE_DEFINE(MagicTextureNode)
-{
- NodeType *type = NodeType::add("magic_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(MagicTextureNode);
-
- SOCKET_INT(depth, "Depth", 2);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
- SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
- SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f);
-
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(fac, "Fac");
-
- return type;
-}
-
-MagicTextureNode::MagicTextureNode() : TextureNode(get_node_type())
-{
-}
-
-void MagicTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *scale_in = input("Scale");
- ShaderInput *distortion_in = input("Distortion");
- ShaderOutput *color_out = output("Color");
- ShaderOutput *fac_out = output("Fac");
-
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
-
- compiler.add_node(NODE_TEX_MAGIC,
- compiler.encode_uchar4(depth,
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(fac_out)),
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign_if_linked(scale_in),
- compiler.stack_assign_if_linked(distortion_in)));
- compiler.add_node(__float_as_int(scale), __float_as_int(distortion));
-
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
-}
-
-void MagicTextureNode::compile(OSLCompiler &compiler)
-{
- tex_mapping.compile(compiler);
-
- compiler.parameter(this, "depth");
- compiler.add(this, "node_magic_texture");
-}
-
-/* Checker Texture */
-
-NODE_DEFINE(CheckerTextureNode)
-{
- NodeType *type = NodeType::add("checker_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(CheckerTextureNode);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
- SOCKET_IN_COLOR(color1, "Color1", zero_float3());
- SOCKET_IN_COLOR(color2, "Color2", zero_float3());
- SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
-
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(fac, "Fac");
-
- return type;
-}
-
-CheckerTextureNode::CheckerTextureNode() : TextureNode(get_node_type())
-{
-}
-
-void CheckerTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *color1_in = input("Color1");
- ShaderInput *color2_in = input("Color2");
- ShaderInput *scale_in = input("Scale");
-
- ShaderOutput *color_out = output("Color");
- ShaderOutput *fac_out = output("Fac");
-
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
-
- compiler.add_node(NODE_TEX_CHECKER,
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign(color1_in),
- compiler.stack_assign(color2_in),
- compiler.stack_assign_if_linked(scale_in)),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(fac_out)),
- __float_as_int(scale));
-
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
-}
-
-void CheckerTextureNode::compile(OSLCompiler &compiler)
-{
- tex_mapping.compile(compiler);
-
- compiler.add(this, "node_checker_texture");
-}
-
-/* Brick Texture */
-
-NODE_DEFINE(BrickTextureNode)
-{
- NodeType *type = NodeType::add("brick_texture", create, NodeType::SHADER);
-
- TEXTURE_MAPPING_DEFINE(BrickTextureNode);
-
- SOCKET_FLOAT(offset, "Offset", 0.5f);
- SOCKET_INT(offset_frequency, "Offset Frequency", 2);
- SOCKET_FLOAT(squash, "Squash", 1.0f);
- SOCKET_INT(squash_frequency, "Squash Frequency", 2);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
-
- SOCKET_IN_COLOR(color1, "Color1", zero_float3());
- SOCKET_IN_COLOR(color2, "Color2", zero_float3());
- SOCKET_IN_COLOR(mortar, "Mortar", zero_float3());
- SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
- SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f);
- SOCKET_IN_FLOAT(mortar_smooth, "Mortar Smooth", 0.0f);
- SOCKET_IN_FLOAT(bias, "Bias", 0.0f);
- SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f);
- SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f);
-
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(fac, "Fac");
-
- return type;
-}
-
-BrickTextureNode::BrickTextureNode() : TextureNode(get_node_type())
-{
-}
-
-void BrickTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *color1_in = input("Color1");
- ShaderInput *color2_in = input("Color2");
- ShaderInput *mortar_in = input("Mortar");
- ShaderInput *scale_in = input("Scale");
- ShaderInput *mortar_size_in = input("Mortar Size");
- ShaderInput *mortar_smooth_in = input("Mortar Smooth");
- ShaderInput *bias_in = input("Bias");
- ShaderInput *brick_width_in = input("Brick Width");
- ShaderInput *row_height_in = input("Row Height");
-
- ShaderOutput *color_out = output("Color");
- ShaderOutput *fac_out = output("Fac");
-
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
-
- compiler.add_node(NODE_TEX_BRICK,
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign(color1_in),
- compiler.stack_assign(color2_in),
- compiler.stack_assign(mortar_in)),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(scale_in),
- compiler.stack_assign_if_linked(mortar_size_in),
- compiler.stack_assign_if_linked(bias_in),
- compiler.stack_assign_if_linked(brick_width_in)),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(row_height_in),
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(fac_out),
- compiler.stack_assign_if_linked(mortar_smooth_in)));
-
- compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
- __float_as_int(scale),
- __float_as_int(mortar_size),
- __float_as_int(bias));
-
- compiler.add_node(__float_as_int(brick_width),
- __float_as_int(row_height),
- __float_as_int(offset),
- __float_as_int(squash));
-
- compiler.add_node(
- __float_as_int(mortar_smooth), SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID);
-
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
-}
-
-void BrickTextureNode::compile(OSLCompiler &compiler)
-{
- tex_mapping.compile(compiler);
-
- compiler.parameter(this, "offset");
- compiler.parameter(this, "offset_frequency");
- compiler.parameter(this, "squash");
- compiler.parameter(this, "squash_frequency");
- compiler.add(this, "node_brick_texture");
-}
-
-/* Point Density Texture */
-
-NODE_DEFINE(PointDensityTextureNode)
-{
- NodeType *type = NodeType::add("point_density_texture", create, NodeType::SHADER);
-
- SOCKET_STRING(filename, "Filename", ustring());
-
- static NodeEnum space_enum;
- space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT);
- space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD);
- SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT);
-
- static NodeEnum interpolation_enum;
- interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
- interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
- interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
- interpolation_enum.insert("smart", INTERPOLATION_SMART);
- SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
-
- SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_POSITION);
-
- SOCKET_OUT_FLOAT(density, "Density");
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-PointDensityTextureNode::PointDensityTextureNode() : ShaderNode(get_node_type())
-{
-}
-
-PointDensityTextureNode::~PointDensityTextureNode()
-{
-}
-
-ShaderNode *PointDensityTextureNode::clone(ShaderGraph *graph) const
-{
- /* Increase image user count for new node. We need to ensure to not call
- * add_image again, to work around access of freed data on the Blender
- * side. A better solution should be found to avoid this. */
- PointDensityTextureNode *node = graph->create_node<PointDensityTextureNode>(*this);
- node->handle = handle; /* TODO: not needed? */
- return node;
-}
-
-void PointDensityTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_volume)
- attributes->add(ATTR_STD_GENERATED_TRANSFORM);
-
- ShaderNode::attributes(shader, attributes);
-}
-
-ImageParams PointDensityTextureNode::image_params() const
-{
- ImageParams params;
- params.interpolation = interpolation;
- return params;
-}
-
-void PointDensityTextureNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderOutput *density_out = output("Density");
- ShaderOutput *color_out = output("Color");
-
- const bool use_density = !density_out->links.empty();
- const bool use_color = !color_out->links.empty();
-
- if (use_density || use_color) {
- if (handle.empty()) {
- ImageManager *image_manager = compiler.scene->image_manager;
- handle = image_manager->add_image(filename.string(), image_params());
- }
-
- const int slot = handle.svm_slot();
- if (slot != -1) {
- compiler.stack_assign(vector_in);
- compiler.add_node(NODE_TEX_VOXEL,
- slot,
- compiler.encode_uchar4(compiler.stack_assign(vector_in),
- compiler.stack_assign_if_linked(density_out),
- compiler.stack_assign_if_linked(color_out),
- space));
- if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
- compiler.add_node(tfm.x);
- compiler.add_node(tfm.y);
- compiler.add_node(tfm.z);
- }
- }
- else {
- if (use_density) {
- compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(density_out));
- }
- if (use_color) {
- compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
- compiler.add_node(
- NODE_VALUE_V,
- make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B));
- }
- }
- }
-}
-
-void PointDensityTextureNode::compile(OSLCompiler &compiler)
-{
- ShaderOutput *density_out = output("Density");
- ShaderOutput *color_out = output("Color");
-
- const bool use_density = !density_out->links.empty();
- const bool use_color = !color_out->links.empty();
-
- if (use_density || use_color) {
- if (handle.empty()) {
- ImageManager *image_manager = compiler.scene->image_manager;
- handle = image_manager->add_image(filename.string(), image_params());
- }
-
- compiler.parameter_texture("filename", handle.svm_slot());
- if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
- compiler.parameter("mapping", tfm);
- compiler.parameter("use_mapping", 1);
- }
- compiler.parameter(this, "interpolation");
- compiler.add(this, "node_voxel_texture");
- }
-}
-
-/* Normal */
-
-NODE_DEFINE(NormalNode)
-{
- NodeType *type = NodeType::add("normal", create, NodeType::SHADER);
-
- SOCKET_VECTOR(direction, "direction", zero_float3());
-
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3());
-
- SOCKET_OUT_NORMAL(normal, "Normal");
- SOCKET_OUT_FLOAT(dot, "Dot");
-
- return type;
-}
-
-NormalNode::NormalNode() : ShaderNode(get_node_type())
-{
-}
-
-void NormalNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *normal_in = input("Normal");
- ShaderOutput *normal_out = output("Normal");
- ShaderOutput *dot_out = output("Dot");
-
- compiler.add_node(NODE_NORMAL,
- compiler.stack_assign(normal_in),
- compiler.stack_assign(normal_out),
- compiler.stack_assign(dot_out));
- compiler.add_node(
- __float_as_int(direction.x), __float_as_int(direction.y), __float_as_int(direction.z));
-}
-
-void NormalNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "direction");
- compiler.add(this, "node_normal");
-}
-
-/* Mapping */
-
-NODE_DEFINE(MappingNode)
-{
- NodeType *type = NodeType::add("mapping", create, NodeType::SHADER);
-
- static NodeEnum type_enum;
- type_enum.insert("point", NODE_MAPPING_TYPE_POINT);
- type_enum.insert("texture", NODE_MAPPING_TYPE_TEXTURE);
- type_enum.insert("vector", NODE_MAPPING_TYPE_VECTOR);
- type_enum.insert("normal", NODE_MAPPING_TYPE_NORMAL);
- SOCKET_ENUM(mapping_type, "Type", type_enum, NODE_MAPPING_TYPE_POINT);
-
- SOCKET_IN_POINT(vector, "Vector", zero_float3());
- SOCKET_IN_POINT(location, "Location", zero_float3());
- SOCKET_IN_POINT(rotation, "Rotation", zero_float3());
- SOCKET_IN_POINT(scale, "Scale", one_float3());
-
- SOCKET_OUT_POINT(vector, "Vector");
-
- return type;
-}
-
-MappingNode::MappingNode() : ShaderNode(get_node_type())
-{
-}
-
-void MappingNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- float3 result = svm_mapping((NodeMappingType)mapping_type, vector, location, rotation, scale);
- folder.make_constant(result);
- }
- else {
- folder.fold_mapping((NodeMappingType)mapping_type);
- }
-}
-
-void MappingNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *location_in = input("Location");
- ShaderInput *rotation_in = input("Rotation");
- ShaderInput *scale_in = input("Scale");
- ShaderOutput *vector_out = output("Vector");
-
- int vector_stack_offset = compiler.stack_assign(vector_in);
- int location_stack_offset = compiler.stack_assign(location_in);
- int rotation_stack_offset = compiler.stack_assign(rotation_in);
- int scale_stack_offset = compiler.stack_assign(scale_in);
- int result_stack_offset = compiler.stack_assign(vector_out);
-
- compiler.add_node(
- NODE_MAPPING,
- mapping_type,
- compiler.encode_uchar4(
- vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset),
- result_stack_offset);
-}
-
-void MappingNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "mapping_type");
- compiler.add(this, "node_mapping");
-}
-
-/* RGBToBW */
-
-NODE_DEFINE(RGBToBWNode)
-{
- NodeType *type = NodeType::add("rgb_to_bw", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", zero_float3());
- SOCKET_OUT_FLOAT(val, "Val");
-
- return type;
-}
-
-RGBToBWNode::RGBToBWNode() : ShaderNode(get_node_type())
-{
-}
-
-void RGBToBWNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- float val = folder.scene->shader_manager->linear_rgb_to_gray(color);
- folder.make_constant(val);
- }
-}
-
-void RGBToBWNode::compile(SVMCompiler &compiler)
-{
- compiler.add_node(NODE_CONVERT,
- NODE_CONVERT_CF,
- compiler.stack_assign(inputs[0]),
- compiler.stack_assign(outputs[0]));
-}
-
-void RGBToBWNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_rgb_to_bw");
-}
-
-/* Convert */
-
-const NodeType *ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE];
-bool ConvertNode::initialized = ConvertNode::register_types();
-
-Node *ConvertNode::create(const NodeType *type)
-{
- return new ConvertNode(type->inputs[0].type, type->outputs[0].type);
-}
-
-bool ConvertNode::register_types()
-{
- const int num_types = 8;
- SocketType::Type types[num_types] = {SocketType::FLOAT,
- SocketType::INT,
- SocketType::COLOR,
- SocketType::VECTOR,
- SocketType::POINT,
- SocketType::NORMAL,
- SocketType::STRING,
- SocketType::CLOSURE};
-
- for (size_t i = 0; i < num_types; i++) {
- SocketType::Type from = types[i];
- ustring from_name(SocketType::type_name(from));
- ustring from_value_name("value_" + from_name.string());
-
- for (size_t j = 0; j < num_types; j++) {
- SocketType::Type to = types[j];
- ustring to_name(SocketType::type_name(to));
- ustring to_value_name("value_" + to_name.string());
-
- string node_name = "convert_" + from_name.string() + "_to_" + to_name.string();
- NodeType *type = NodeType::add(node_name.c_str(), create, NodeType::SHADER);
-
- type->register_input(from_value_name,
- from_value_name,
- from,
- SOCKET_OFFSETOF(ConvertNode, value_float),
- SocketType::zero_default_value(),
- NULL,
- NULL,
- SocketType::LINKABLE);
- type->register_output(to_value_name, to_value_name, to);
-
- assert(from < MAX_TYPE);
- assert(to < MAX_TYPE);
-
- node_types[from][to] = type;
- }
- }
-
- return true;
-}
-
-ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert)
- : ShaderNode(node_types[from_][to_])
-{
- from = from_;
- to = to_;
-
- if (from == to)
- special_type = SHADER_SPECIAL_TYPE_PROXY;
- else if (autoconvert)
- special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
-}
-
-/* Union usage requires a manual copy constructor. */
-ConvertNode::ConvertNode(const ConvertNode &other)
- : ShaderNode(other),
- from(other.from),
- to(other.to),
- value_color(other.value_color),
- value_string(other.value_string)
-{
-}
-
-void ConvertNode::constant_fold(const ConstantFolder &folder)
-{
- /* proxy nodes should have been removed at this point */
- assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
-
- /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
-
- if (folder.all_inputs_constant()) {
- if (from == SocketType::FLOAT) {
- if (SocketType::is_float3(to)) {
- folder.make_constant(make_float3(value_float, value_float, value_float));
- }
- }
- else if (SocketType::is_float3(from)) {
- if (to == SocketType::FLOAT) {
- if (from == SocketType::COLOR) {
- /* color to float */
- float val = folder.scene->shader_manager->linear_rgb_to_gray(value_color);
- folder.make_constant(val);
- }
- else {
- /* vector/point/normal to float */
- folder.make_constant(average(value_vector));
- }
- }
- else if (SocketType::is_float3(to)) {
- folder.make_constant(value_color);
- }
- }
- }
- else {
- ShaderInput *in = inputs[0];
- ShaderNode *prev = in->link->parent;
-
- /* no-op conversion of A to B to A */
- if (prev->type == node_types[to][from]) {
- ShaderInput *prev_in = prev->inputs[0];
-
- if (SocketType::is_float3(from) && (to == SocketType::FLOAT || SocketType::is_float3(to)) &&
- prev_in->link) {
- folder.bypass(prev_in->link);
- }
- }
- }
-}
-
-void ConvertNode::compile(SVMCompiler &compiler)
-{
- /* proxy nodes should have been removed at this point */
- assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
-
- ShaderInput *in = inputs[0];
- ShaderOutput *out = outputs[0];
-
- if (from == SocketType::FLOAT) {
- if (to == SocketType::INT)
- /* float to int */
- compiler.add_node(
- NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out));
- else
- /* float to float3 */
- compiler.add_node(
- NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out));
- }
- else if (from == SocketType::INT) {
- if (to == SocketType::FLOAT)
- /* int to float */
- compiler.add_node(
- NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out));
- else
- /* int to vector/point/normal */
- compiler.add_node(
- NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out));
- }
- else if (to == SocketType::FLOAT) {
- if (from == SocketType::COLOR)
- /* color to float */
- compiler.add_node(
- NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out));
- else
- /* vector/point/normal to float */
- compiler.add_node(
- NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out));
- }
- else if (to == SocketType::INT) {
- if (from == SocketType::COLOR)
- /* color to int */
- compiler.add_node(
- NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out));
- else
- /* vector/point/normal to int */
- compiler.add_node(
- NODE_CONVERT, NODE_CONVERT_VI, compiler.stack_assign(in), compiler.stack_assign(out));
- }
- else {
- /* float3 to float3 */
- if (in->link) {
- /* no op in SVM */
- compiler.stack_link(in, out);
- }
- else {
- /* set 0,0,0 value */
- compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out));
- compiler.add_node(NODE_VALUE_V, value_color);
- }
- }
-}
-
-void ConvertNode::compile(OSLCompiler &compiler)
-{
- /* proxy nodes should have been removed at this point */
- assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
-
- if (from == SocketType::FLOAT)
- compiler.add(this, "node_convert_from_float");
- else if (from == SocketType::INT)
- compiler.add(this, "node_convert_from_int");
- else if (from == SocketType::COLOR)
- compiler.add(this, "node_convert_from_color");
- else if (from == SocketType::VECTOR)
- compiler.add(this, "node_convert_from_vector");
- else if (from == SocketType::POINT)
- compiler.add(this, "node_convert_from_point");
- else if (from == SocketType::NORMAL)
- compiler.add(this, "node_convert_from_normal");
- else
- assert(0);
-}
-
-/* Base type for all closure-type nodes */
-
-BsdfBaseNode::BsdfBaseNode(const NodeType *node_type) : ShaderNode(node_type)
-{
- special_type = SHADER_SPECIAL_TYPE_CLOSURE;
-}
-
-bool BsdfBaseNode::has_bump()
-{
- /* detect if anything is plugged into the normal input besides the default */
- ShaderInput *normal_in = input("Normal");
- return (normal_in && normal_in->link &&
- normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY);
-}
-
-/* BSDF Closure */
-
-BsdfNode::BsdfNode(const NodeType *node_type) : BsdfBaseNode(node_type)
-{
-}
-
-void BsdfNode::compile(SVMCompiler &compiler,
- ShaderInput *param1,
- ShaderInput *param2,
- ShaderInput *param3,
- ShaderInput *param4)
-{
- ShaderInput *color_in = input("Color");
- ShaderInput *normal_in = input("Normal");
- ShaderInput *tangent_in = input("Tangent");
-
- if (color_in->link)
- compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
- else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
-
- int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID;
- int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) :
- SVM_STACK_INVALID;
- int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID;
- int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID;
-
- compiler.add_node(
- NODE_CLOSURE_BSDF,
- compiler.encode_uchar4(closure,
- (param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID,
- (param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID,
- compiler.closure_mix_weight_offset()),
- __float_as_int((param1) ? get_float(param1->socket_type) : 0.0f),
- __float_as_int((param2) ? get_float(param2->socket_type) : 0.0f));
-
- compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset);
-}
-
-void BsdfNode::compile(SVMCompiler &compiler)
-{
- compile(compiler, NULL, NULL);
-}
-
-void BsdfNode::compile(OSLCompiler & /*compiler*/)
-{
- assert(0);
-}
-
-/* Anisotropic BSDF Closure */
-
-NODE_DEFINE(AnisotropicBsdfNode)
-{
- NodeType *type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- static NodeEnum distribution_enum;
- distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
- distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
- distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
- distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
- SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
-
- SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
-
- SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
- SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f);
- SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-AnisotropicBsdfNode::AnisotropicBsdfNode() : BsdfNode(get_node_type())
-{
- closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
-}
-
-void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_surface_link()) {
- ShaderInput *tangent_in = input("Tangent");
-
- if (!tangent_in->link)
- attributes->add(ATTR_STD_GENERATED);
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void AnisotropicBsdfNode::compile(SVMCompiler &compiler)
-{
- closure = distribution;
-
- if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
- BsdfNode::compile(
- compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
- else
- BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
-}
-
-void AnisotropicBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "distribution");
- compiler.add(this, "node_anisotropic_bsdf");
-}
-
-/* Glossy BSDF Closure */
-
-NODE_DEFINE(GlossyBsdfNode)
-{
- NodeType *type = NodeType::add("glossy_bsdf", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- static NodeEnum distribution_enum;
- distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID);
- distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
- distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
- distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
- distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
- SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
- SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-GlossyBsdfNode::GlossyBsdfNode() : BsdfNode(get_node_type())
-{
- closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
- distribution_orig = NBUILTIN_CLOSURES;
-}
-
-void GlossyBsdfNode::simplify_settings(Scene *scene)
-{
- if (distribution_orig == NBUILTIN_CLOSURES) {
- roughness_orig = roughness;
- distribution_orig = distribution;
- }
- else {
- /* By default we use original values, so we don't worry about restoring
- * defaults later one and can only do override when needed.
- */
- roughness = roughness_orig;
- distribution = distribution_orig;
- }
- Integrator *integrator = scene->integrator;
- ShaderInput *roughness_input = input("Roughness");
- if (integrator->get_filter_glossy() == 0.0f) {
- /* Fallback to Sharp closure for Roughness close to 0.
- * Note: Keep the epsilon in sync with kernel!
- */
- if (!roughness_input->link && roughness <= 1e-4f) {
- VLOG(1) << "Using sharp glossy BSDF.";
- distribution = CLOSURE_BSDF_REFLECTION_ID;
- }
- }
- else {
- /* If filter glossy is used we replace Sharp glossy with GGX so we can
- * benefit from closure blur to remove unwanted noise.
- */
- if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFLECTION_ID) {
- VLOG(1) << "Using GGX glossy with filter glossy.";
- distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
- roughness = 0.0f;
- }
- }
- closure = distribution;
-}
-
-bool GlossyBsdfNode::has_integrator_dependency()
-{
- ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link &&
- (distribution == CLOSURE_BSDF_REFLECTION_ID || roughness <= 1e-4f);
-}
-
-void GlossyBsdfNode::compile(SVMCompiler &compiler)
-{
- closure = distribution;
-
- if (closure == CLOSURE_BSDF_REFLECTION_ID)
- BsdfNode::compile(compiler, NULL, NULL);
- else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
- BsdfNode::compile(compiler, input("Roughness"), NULL, NULL, input("Color"));
- else
- BsdfNode::compile(compiler, input("Roughness"), NULL);
-}
-
-void GlossyBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "distribution");
- compiler.add(this, "node_glossy_bsdf");
-}
-
-/* Glass BSDF Closure */
-
-NODE_DEFINE(GlassBsdfNode)
-{
- NodeType *type = NodeType::add("glass_bsdf", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- static NodeEnum distribution_enum;
- distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
- distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
- distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
- distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
- SOCKET_ENUM(
- distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
- SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
- SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-GlassBsdfNode::GlassBsdfNode() : BsdfNode(get_node_type())
-{
- closure = CLOSURE_BSDF_SHARP_GLASS_ID;
- distribution_orig = NBUILTIN_CLOSURES;
-}
-
-void GlassBsdfNode::simplify_settings(Scene *scene)
-{
- if (distribution_orig == NBUILTIN_CLOSURES) {
- roughness_orig = roughness;
- distribution_orig = distribution;
- }
- else {
- /* By default we use original values, so we don't worry about restoring
- * defaults later one and can only do override when needed.
- */
- roughness = roughness_orig;
- distribution = distribution_orig;
- }
- Integrator *integrator = scene->integrator;
- ShaderInput *roughness_input = input("Roughness");
- if (integrator->get_filter_glossy() == 0.0f) {
- /* Fallback to Sharp closure for Roughness close to 0.
- * Note: Keep the epsilon in sync with kernel!
- */
- if (!roughness_input->link && roughness <= 1e-4f) {
- VLOG(1) << "Using sharp glass BSDF.";
- distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
- }
- }
- else {
- /* If filter glossy is used we replace Sharp glossy with GGX so we can
- * benefit from closure blur to remove unwanted noise.
- */
- if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_SHARP_GLASS_ID) {
- VLOG(1) << "Using GGX glass with filter glossy.";
- distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
- roughness = 0.0f;
- }
- }
- closure = distribution;
-}
-
-bool GlassBsdfNode::has_integrator_dependency()
-{
- ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link &&
- (distribution == CLOSURE_BSDF_SHARP_GLASS_ID || roughness <= 1e-4f);
-}
-
-void GlassBsdfNode::compile(SVMCompiler &compiler)
-{
- closure = distribution;
-
- if (closure == CLOSURE_BSDF_SHARP_GLASS_ID)
- BsdfNode::compile(compiler, NULL, input("IOR"));
- else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
- BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color"));
- else
- BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
-}
-
-void GlassBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "distribution");
- compiler.add(this, "node_glass_bsdf");
-}
-
-/* Refraction BSDF Closure */
-
-NODE_DEFINE(RefractionBsdfNode)
-{
- NodeType *type = NodeType::add("refraction_bsdf", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- static NodeEnum distribution_enum;
- distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID);
- distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
- distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
- SOCKET_ENUM(
- distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
-
- SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
- SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-RefractionBsdfNode::RefractionBsdfNode() : BsdfNode(get_node_type())
-{
- closure = CLOSURE_BSDF_REFRACTION_ID;
- distribution_orig = NBUILTIN_CLOSURES;
-}
-
-void RefractionBsdfNode::simplify_settings(Scene *scene)
-{
- if (distribution_orig == NBUILTIN_CLOSURES) {
- roughness_orig = roughness;
- distribution_orig = distribution;
- }
- else {
- /* By default we use original values, so we don't worry about restoring
- * defaults later one and can only do override when needed.
- */
- roughness = roughness_orig;
- distribution = distribution_orig;
- }
- Integrator *integrator = scene->integrator;
- ShaderInput *roughness_input = input("Roughness");
- if (integrator->get_filter_glossy() == 0.0f) {
- /* Fallback to Sharp closure for Roughness close to 0.
- * Note: Keep the epsilon in sync with kernel!
- */
- if (!roughness_input->link && roughness <= 1e-4f) {
- VLOG(1) << "Using sharp refraction BSDF.";
- distribution = CLOSURE_BSDF_REFRACTION_ID;
- }
- }
- else {
- /* If filter glossy is used we replace Sharp glossy with GGX so we can
- * benefit from closure blur to remove unwanted noise.
- */
- if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFRACTION_ID) {
- VLOG(1) << "Using GGX refraction with filter glossy.";
- distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
- roughness = 0.0f;
- }
- }
- closure = distribution;
-}
-
-bool RefractionBsdfNode::has_integrator_dependency()
-{
- ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link &&
- (distribution == CLOSURE_BSDF_REFRACTION_ID || roughness <= 1e-4f);
-}
-
-void RefractionBsdfNode::compile(SVMCompiler &compiler)
-{
- closure = distribution;
-
- if (closure == CLOSURE_BSDF_REFRACTION_ID)
- BsdfNode::compile(compiler, NULL, input("IOR"));
- else
- BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
-}
-
-void RefractionBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "distribution");
- compiler.add(this, "node_refraction_bsdf");
-}
-
-/* Toon BSDF Closure */
-
-NODE_DEFINE(ToonBsdfNode)
-{
- NodeType *type = NodeType::add("toon_bsdf", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- static NodeEnum component_enum;
- component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
- component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
- SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID);
- SOCKET_IN_FLOAT(size, "Size", 0.5f);
- SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-ToonBsdfNode::ToonBsdfNode() : BsdfNode(get_node_type())
-{
- closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
-}
-
-void ToonBsdfNode::compile(SVMCompiler &compiler)
-{
- closure = component;
-
- BsdfNode::compile(compiler, input("Size"), input("Smooth"));
-}
-
-void ToonBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "component");
- compiler.add(this, "node_toon_bsdf");
-}
-
-/* Velvet BSDF Closure */
-
-NODE_DEFINE(VelvetBsdfNode)
-{
- NodeType *type = NodeType::add("velvet_bsdf", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- SOCKET_IN_FLOAT(sigma, "Sigma", 1.0f);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-VelvetBsdfNode::VelvetBsdfNode() : BsdfNode(get_node_type())
-{
- closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
-}
-
-void VelvetBsdfNode::compile(SVMCompiler &compiler)
-{
- BsdfNode::compile(compiler, input("Sigma"), NULL);
-}
-
-void VelvetBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_velvet_bsdf");
-}
-
-/* Diffuse BSDF Closure */
-
-NODE_DEFINE(DiffuseBsdfNode)
-{
- NodeType *type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-DiffuseBsdfNode::DiffuseBsdfNode() : BsdfNode(get_node_type())
-{
- closure = CLOSURE_BSDF_DIFFUSE_ID;
-}
-
-void DiffuseBsdfNode::compile(SVMCompiler &compiler)
-{
- BsdfNode::compile(compiler, input("Roughness"), NULL);
-}
-
-void DiffuseBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_diffuse_bsdf");
-}
-
-/* Disney principled BSDF Closure */
-NODE_DEFINE(PrincipledBsdfNode)
-{
- NodeType *type = NodeType::add("principled_bsdf", create, NodeType::SHADER);
-
- static NodeEnum distribution_enum;
- distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
- distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
- SOCKET_ENUM(
- distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
-
- static NodeEnum subsurface_method_enum;
- subsurface_method_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
- subsurface_method_enum.insert("random_walk_fixed_radius",
- CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
- subsurface_method_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID);
- SOCKET_ENUM(subsurface_method,
- "Subsurface Method",
- subsurface_method_enum,
- CLOSURE_BSSRDF_RANDOM_WALK_ID);
-
- SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_COLOR(subsurface_color, "Subsurface Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f);
- SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f);
- SOCKET_IN_VECTOR(subsurface_radius, "Subsurface Radius", make_float3(0.1f, 0.1f, 0.1f));
- SOCKET_IN_FLOAT(subsurface_ior, "Subsurface IOR", 1.4f);
- SOCKET_IN_FLOAT(subsurface_anisotropy, "Subsurface Anisotropy", 0.0f);
- SOCKET_IN_FLOAT(specular, "Specular", 0.0f);
- SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
- SOCKET_IN_FLOAT(specular_tint, "Specular Tint", 0.0f);
- SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f);
- SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f);
- SOCKET_IN_FLOAT(sheen_tint, "Sheen Tint", 0.0f);
- SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f);
- SOCKET_IN_FLOAT(clearcoat_roughness, "Clearcoat Roughness", 0.03f);
- SOCKET_IN_FLOAT(ior, "IOR", 0.0f);
- SOCKET_IN_FLOAT(transmission, "Transmission", 0.0f);
- SOCKET_IN_FLOAT(transmission_roughness, "Transmission Roughness", 0.0f);
- SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f);
- SOCKET_IN_COLOR(emission, "Emission", zero_float3());
- SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 1.0f);
- SOCKET_IN_FLOAT(alpha, "Alpha", 1.0f);
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_NORMAL(clearcoat_normal, "Clearcoat Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_NORMAL(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(get_node_type())
-{
- closure = CLOSURE_BSDF_PRINCIPLED_ID;
- distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
- distribution_orig = NBUILTIN_CLOSURES;
-}
-
-void PrincipledBsdfNode::expand(ShaderGraph *graph)
-{
- ShaderOutput *principled_out = output("BSDF");
-
- ShaderInput *emission_in = input("Emission");
- ShaderInput *emission_strength_in = input("Emission Strength");
- if ((emission_in->link || emission != zero_float3()) &&
- (emission_strength_in->link || emission_strength != 0.0f)) {
- /* Create add closure and emission, and relink inputs. */
- AddClosureNode *add = graph->create_node<AddClosureNode>();
- EmissionNode *emission_node = graph->create_node<EmissionNode>();
- ShaderOutput *new_out = add->output("Closure");
-
- graph->add(add);
- graph->add(emission_node);
-
- graph->relink(emission_strength_in, emission_node->input("Strength"));
- graph->relink(emission_in, emission_node->input("Color"));
- graph->relink(principled_out, new_out);
- graph->connect(emission_node->output("Emission"), add->input("Closure1"));
- graph->connect(principled_out, add->input("Closure2"));
-
- principled_out = new_out;
- }
- else {
- /* Disconnect unused links if the other value is zero, required before
- * we remove the input from the node entirely. */
- if (emission_in->link) {
- emission_in->disconnect();
- }
- if (emission_strength_in->link) {
- emission_strength_in->disconnect();
- }
- }
-
- ShaderInput *alpha_in = input("Alpha");
- if (alpha_in->link || alpha != 1.0f) {
- /* Create mix and transparent BSDF for alpha transparency. */
- MixClosureNode *mix = graph->create_node<MixClosureNode>();
- TransparentBsdfNode *transparent = graph->create_node<TransparentBsdfNode>();
-
- graph->add(mix);
- graph->add(transparent);
-
- graph->relink(alpha_in, mix->input("Fac"));
- graph->relink(principled_out, mix->output("Closure"));
- graph->connect(transparent->output("BSDF"), mix->input("Closure1"));
- graph->connect(principled_out, mix->input("Closure2"));
- }
-
- remove_input(emission_in);
- remove_input(emission_strength_in);
- remove_input(alpha_in);
-}
-
-bool PrincipledBsdfNode::has_surface_bssrdf()
-{
- ShaderInput *subsurface_in = input("Subsurface");
- return (subsurface_in->link != NULL || subsurface > CLOSURE_WEIGHT_CUTOFF);
-}
-
-void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_surface_link()) {
- ShaderInput *tangent_in = input("Tangent");
-
- if (!tangent_in->link)
- attributes->add(ATTR_STD_GENERATED);
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void PrincipledBsdfNode::compile(SVMCompiler &compiler,
- ShaderInput *p_metallic,
- ShaderInput *p_subsurface,
- ShaderInput *p_subsurface_radius,
- ShaderInput *p_subsurface_ior,
- ShaderInput *p_subsurface_anisotropy,
- ShaderInput *p_specular,
- ShaderInput *p_roughness,
- ShaderInput *p_specular_tint,
- ShaderInput *p_anisotropic,
- ShaderInput *p_sheen,
- ShaderInput *p_sheen_tint,
- ShaderInput *p_clearcoat,
- ShaderInput *p_clearcoat_roughness,
- ShaderInput *p_ior,
- ShaderInput *p_transmission,
- ShaderInput *p_anisotropic_rotation,
- ShaderInput *p_transmission_roughness)
-{
- ShaderInput *base_color_in = input("Base Color");
- ShaderInput *subsurface_color_in = input("Subsurface Color");
- ShaderInput *normal_in = input("Normal");
- ShaderInput *clearcoat_normal_in = input("Clearcoat Normal");
- ShaderInput *tangent_in = input("Tangent");
-
- float3 weight = one_float3();
-
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight);
-
- int normal_offset = compiler.stack_assign_if_linked(normal_in);
- int clearcoat_normal_offset = compiler.stack_assign_if_linked(clearcoat_normal_in);
- int tangent_offset = compiler.stack_assign_if_linked(tangent_in);
- int specular_offset = compiler.stack_assign(p_specular);
- int roughness_offset = compiler.stack_assign(p_roughness);
- int specular_tint_offset = compiler.stack_assign(p_specular_tint);
- int anisotropic_offset = compiler.stack_assign(p_anisotropic);
- int sheen_offset = compiler.stack_assign(p_sheen);
- int sheen_tint_offset = compiler.stack_assign(p_sheen_tint);
- int clearcoat_offset = compiler.stack_assign(p_clearcoat);
- int clearcoat_roughness_offset = compiler.stack_assign(p_clearcoat_roughness);
- int ior_offset = compiler.stack_assign(p_ior);
- int transmission_offset = compiler.stack_assign(p_transmission);
- int transmission_roughness_offset = compiler.stack_assign(p_transmission_roughness);
- int anisotropic_rotation_offset = compiler.stack_assign(p_anisotropic_rotation);
- int subsurface_radius_offset = compiler.stack_assign(p_subsurface_radius);
- int subsurface_ior_offset = compiler.stack_assign(p_subsurface_ior);
- int subsurface_anisotropy_offset = compiler.stack_assign(p_subsurface_anisotropy);
-
- compiler.add_node(NODE_CLOSURE_BSDF,
- compiler.encode_uchar4(closure,
- compiler.stack_assign(p_metallic),
- compiler.stack_assign(p_subsurface),
- compiler.closure_mix_weight_offset()),
- __float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f),
- __float_as_int((p_subsurface) ? get_float(p_subsurface->socket_type) : 0.0f));
-
- compiler.add_node(
- normal_offset,
- tangent_offset,
- compiler.encode_uchar4(
- specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset),
- compiler.encode_uchar4(
- sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset));
-
- compiler.add_node(compiler.encode_uchar4(ior_offset,
- transmission_offset,
- anisotropic_rotation_offset,
- transmission_roughness_offset),
- distribution,
- subsurface_method,
- SVM_STACK_INVALID);
-
- float3 bc_default = get_float3(base_color_in->socket_type);
-
- compiler.add_node(
- ((base_color_in->link) ? compiler.stack_assign(base_color_in) : SVM_STACK_INVALID),
- __float_as_int(bc_default.x),
- __float_as_int(bc_default.y),
- __float_as_int(bc_default.z));
-
- compiler.add_node(clearcoat_normal_offset,
- subsurface_radius_offset,
- subsurface_ior_offset,
- subsurface_anisotropy_offset);
-
- float3 ss_default = get_float3(subsurface_color_in->socket_type);
-
- compiler.add_node(((subsurface_color_in->link) ? compiler.stack_assign(subsurface_color_in) :
- SVM_STACK_INVALID),
- __float_as_int(ss_default.x),
- __float_as_int(ss_default.y),
- __float_as_int(ss_default.z));
-}
-
-bool PrincipledBsdfNode::has_integrator_dependency()
-{
- ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link && roughness <= 1e-4f;
-}
-
-void PrincipledBsdfNode::compile(SVMCompiler &compiler)
-{
- compile(compiler,
- input("Metallic"),
- input("Subsurface"),
- input("Subsurface Radius"),
- input("Subsurface IOR"),
- input("Subsurface Anisotropy"),
- input("Specular"),
- input("Roughness"),
- input("Specular Tint"),
- input("Anisotropic"),
- input("Sheen"),
- input("Sheen Tint"),
- input("Clearcoat"),
- input("Clearcoat Roughness"),
- input("IOR"),
- input("Transmission"),
- input("Anisotropic Rotation"),
- input("Transmission Roughness"));
-}
-
-void PrincipledBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "distribution");
- compiler.parameter(this, "subsurface_method");
- compiler.add(this, "node_principled_bsdf");
-}
-
-bool PrincipledBsdfNode::has_bssrdf_bump()
-{
- return has_surface_bssrdf() && has_bump();
-}
-
-/* Translucent BSDF Closure */
-
-NODE_DEFINE(TranslucentBsdfNode)
-{
- NodeType *type = NodeType::add("translucent_bsdf", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-TranslucentBsdfNode::TranslucentBsdfNode() : BsdfNode(get_node_type())
-{
- closure = CLOSURE_BSDF_TRANSLUCENT_ID;
-}
-
-void TranslucentBsdfNode::compile(SVMCompiler &compiler)
-{
- BsdfNode::compile(compiler, NULL, NULL);
-}
-
-void TranslucentBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_translucent_bsdf");
-}
-
-/* Transparent BSDF Closure */
-
-NODE_DEFINE(TransparentBsdfNode)
-{
- NodeType *type = NodeType::add("transparent_bsdf", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", one_float3());
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-TransparentBsdfNode::TransparentBsdfNode() : BsdfNode(get_node_type())
-{
- closure = CLOSURE_BSDF_TRANSPARENT_ID;
-}
-
-void TransparentBsdfNode::compile(SVMCompiler &compiler)
-{
- BsdfNode::compile(compiler, NULL, NULL);
-}
-
-void TransparentBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_transparent_bsdf");
-}
-
-/* Subsurface Scattering Closure */
-
-NODE_DEFINE(SubsurfaceScatteringNode)
-{
- NodeType *type = NodeType::add("subsurface_scattering", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- static NodeEnum method_enum;
- method_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
- method_enum.insert("random_walk_fixed_radius", CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
- method_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID);
- SOCKET_ENUM(method, "Method", method_enum, CLOSURE_BSSRDF_RANDOM_WALK_ID);
-
- SOCKET_IN_FLOAT(scale, "Scale", 0.01f);
- SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f));
-
- SOCKET_IN_FLOAT(subsurface_ior, "IOR", 1.4f);
- SOCKET_IN_FLOAT(subsurface_anisotropy, "Anisotropy", 0.0f);
-
- SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF");
-
- return type;
-}
-
-SubsurfaceScatteringNode::SubsurfaceScatteringNode() : BsdfNode(get_node_type())
-{
- closure = method;
-}
-
-void SubsurfaceScatteringNode::compile(SVMCompiler &compiler)
-{
- closure = method;
- BsdfNode::compile(compiler, input("Scale"), input("IOR"), input("Radius"), input("Anisotropy"));
-}
-
-void SubsurfaceScatteringNode::compile(OSLCompiler &compiler)
-{
- closure = method;
- compiler.parameter(this, "method");
- compiler.add(this, "node_subsurface_scattering");
-}
-
-bool SubsurfaceScatteringNode::has_bssrdf_bump()
-{
- /* detect if anything is plugged into the normal input besides the default */
- ShaderInput *normal_in = input("Normal");
- return (normal_in->link &&
- normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY);
-}
-
-/* Emissive Closure */
-
-NODE_DEFINE(EmissionNode)
-{
- NodeType *type = NodeType::add("emission", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_FLOAT(strength, "Strength", 10.0f);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- SOCKET_OUT_CLOSURE(emission, "Emission");
-
- return type;
-}
-
-EmissionNode::EmissionNode() : ShaderNode(get_node_type())
-{
-}
-
-void EmissionNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *color_in = input("Color");
- ShaderInput *strength_in = input("Strength");
-
- if (color_in->link || strength_in->link) {
- compiler.add_node(
- NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), compiler.stack_assign(strength_in));
- }
- else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
-
- compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
-}
-
-void EmissionNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_emission");
-}
-
-void EmissionNode::constant_fold(const ConstantFolder &folder)
-{
- ShaderInput *color_in = input("Color");
- ShaderInput *strength_in = input("Strength");
-
- if ((!color_in->link && color == zero_float3()) || (!strength_in->link && strength == 0.0f)) {
- folder.discard();
- }
-}
-
-/* Background Closure */
-
-NODE_DEFINE(BackgroundNode)
-{
- NodeType *type = NodeType::add("background_shader", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- SOCKET_OUT_CLOSURE(background, "Background");
-
- return type;
-}
-
-BackgroundNode::BackgroundNode() : ShaderNode(get_node_type())
-{
-}
-
-void BackgroundNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *color_in = input("Color");
- ShaderInput *strength_in = input("Strength");
-
- if (color_in->link || strength_in->link) {
- compiler.add_node(
- NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), compiler.stack_assign(strength_in));
- }
- else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
-
- compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset());
-}
-
-void BackgroundNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_background");
-}
-
-void BackgroundNode::constant_fold(const ConstantFolder &folder)
-{
- ShaderInput *color_in = input("Color");
- ShaderInput *strength_in = input("Strength");
-
- if ((!color_in->link && color == zero_float3()) || (!strength_in->link && strength == 0.0f)) {
- folder.discard();
- }
-}
-
-/* Holdout Closure */
-
-NODE_DEFINE(HoldoutNode)
-{
- NodeType *type = NodeType::add("holdout", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- SOCKET_OUT_CLOSURE(holdout, "Holdout");
-
- return type;
-}
-
-HoldoutNode::HoldoutNode() : ShaderNode(get_node_type())
-{
-}
-
-void HoldoutNode::compile(SVMCompiler &compiler)
-{
- float3 value = one_float3();
-
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, value);
- compiler.add_node(NODE_CLOSURE_HOLDOUT, compiler.closure_mix_weight_offset());
-}
-
-void HoldoutNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_holdout");
-}
-
-/* Ambient Occlusion */
-
-NODE_DEFINE(AmbientOcclusionNode)
-{
- NodeType *type = NodeType::add("ambient_occlusion", create, NodeType::SHADER);
-
- SOCKET_INT(samples, "Samples", 16);
-
- SOCKET_IN_COLOR(color, "Color", one_float3());
- SOCKET_IN_FLOAT(distance, "Distance", 1.0f);
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
-
- SOCKET_BOOLEAN(inside, "Inside", false);
- SOCKET_BOOLEAN(only_local, "Only Local", false);
-
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(ao, "AO");
-
- return type;
-}
-
-AmbientOcclusionNode::AmbientOcclusionNode() : ShaderNode(get_node_type())
-{
-}
-
-void AmbientOcclusionNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *color_in = input("Color");
- ShaderInput *distance_in = input("Distance");
- ShaderInput *normal_in = input("Normal");
- ShaderOutput *color_out = output("Color");
- ShaderOutput *ao_out = output("AO");
-
- int flags = (inside ? NODE_AO_INSIDE : 0) | (only_local ? NODE_AO_ONLY_LOCAL : 0);
-
- if (!distance_in->link && distance == 0.0f) {
- flags |= NODE_AO_GLOBAL_RADIUS;
- }
-
- compiler.add_node(NODE_AMBIENT_OCCLUSION,
- compiler.encode_uchar4(flags,
- compiler.stack_assign_if_linked(distance_in),
- compiler.stack_assign_if_linked(normal_in),
- compiler.stack_assign(ao_out)),
- compiler.encode_uchar4(compiler.stack_assign(color_in),
- compiler.stack_assign(color_out),
- samples),
- __float_as_uint(distance));
-}
-
-void AmbientOcclusionNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "samples");
- compiler.parameter(this, "inside");
- compiler.parameter(this, "only_local");
- compiler.add(this, "node_ambient_occlusion");
-}
-
-/* Volume Closure */
-
-VolumeNode::VolumeNode(const NodeType *node_type) : ShaderNode(node_type)
-{
- closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
-}
-
-void VolumeNode::compile(SVMCompiler &compiler, ShaderInput *param1, ShaderInput *param2)
-{
- ShaderInput *color_in = input("Color");
-
- if (color_in->link)
- compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
- else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
-
- compiler.add_node(
- NODE_CLOSURE_VOLUME,
- compiler.encode_uchar4(closure,
- (param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID,
- (param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID,
- compiler.closure_mix_weight_offset()),
- __float_as_int((param1) ? get_float(param1->socket_type) : 0.0f),
- __float_as_int((param2) ? get_float(param2->socket_type) : 0.0f));
-}
-
-void VolumeNode::compile(SVMCompiler &compiler)
-{
- compile(compiler, NULL, NULL);
-}
-
-void VolumeNode::compile(OSLCompiler & /*compiler*/)
-{
- assert(0);
-}
-
-/* Absorption Volume Closure */
-
-NODE_DEFINE(AbsorptionVolumeNode)
-{
- NodeType *type = NodeType::add("absorption_volume", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_FLOAT(density, "Density", 1.0f);
- SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- SOCKET_OUT_CLOSURE(volume, "Volume");
-
- return type;
-}
-
-AbsorptionVolumeNode::AbsorptionVolumeNode() : VolumeNode(get_node_type())
-{
- closure = CLOSURE_VOLUME_ABSORPTION_ID;
-}
-
-void AbsorptionVolumeNode::compile(SVMCompiler &compiler)
-{
- VolumeNode::compile(compiler, input("Density"), NULL);
-}
-
-void AbsorptionVolumeNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_absorption_volume");
-}
-
-/* Scatter Volume Closure */
-
-NODE_DEFINE(ScatterVolumeNode)
-{
- NodeType *type = NodeType::add("scatter_volume", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_FLOAT(density, "Density", 1.0f);
- SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
- SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- SOCKET_OUT_CLOSURE(volume, "Volume");
-
- return type;
-}
-
-ScatterVolumeNode::ScatterVolumeNode() : VolumeNode(get_node_type())
-{
- closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
-}
-
-void ScatterVolumeNode::compile(SVMCompiler &compiler)
-{
- VolumeNode::compile(compiler, input("Density"), input("Anisotropy"));
-}
-
-void ScatterVolumeNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_scatter_volume");
-}
-
-/* Principled Volume Closure */
-
-NODE_DEFINE(PrincipledVolumeNode)
-{
- NodeType *type = NodeType::add("principled_volume", create, NodeType::SHADER);
-
- SOCKET_IN_STRING(density_attribute, "Density Attribute", ustring());
- SOCKET_IN_STRING(color_attribute, "Color Attribute", ustring());
- SOCKET_IN_STRING(temperature_attribute, "Temperature Attribute", ustring());
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 0.5f));
- SOCKET_IN_FLOAT(density, "Density", 1.0f);
- SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
- SOCKET_IN_COLOR(absorption_color, "Absorption Color", zero_float3());
- SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f);
- SOCKET_IN_COLOR(emission_color, "Emission Color", one_float3());
- SOCKET_IN_FLOAT(blackbody_intensity, "Blackbody Intensity", 0.0f);
- SOCKET_IN_COLOR(blackbody_tint, "Blackbody Tint", one_float3());
- SOCKET_IN_FLOAT(temperature, "Temperature", 1000.0f);
- SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- SOCKET_OUT_CLOSURE(volume, "Volume");
-
- return type;
-}
-
-PrincipledVolumeNode::PrincipledVolumeNode() : VolumeNode(get_node_type())
-{
- closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
- density_attribute = ustring("density");
- temperature_attribute = ustring("temperature");
-}
-
-void PrincipledVolumeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_volume) {
- ShaderInput *density_in = input("Density");
- ShaderInput *blackbody_in = input("Blackbody Intensity");
-
- if (density_in->link || density > 0.0f) {
- attributes->add_standard(density_attribute);
- attributes->add_standard(color_attribute);
- }
-
- if (blackbody_in->link || blackbody_intensity > 0.0f) {
- attributes->add_standard(temperature_attribute);
- }
-
- attributes->add(ATTR_STD_GENERATED_TRANSFORM);
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void PrincipledVolumeNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *color_in = input("Color");
- ShaderInput *density_in = input("Density");
- ShaderInput *anisotropy_in = input("Anisotropy");
- ShaderInput *absorption_color_in = input("Absorption Color");
- ShaderInput *emission_in = input("Emission Strength");
- ShaderInput *emission_color_in = input("Emission Color");
- ShaderInput *blackbody_in = input("Blackbody Intensity");
- ShaderInput *blackbody_tint_in = input("Blackbody Tint");
- ShaderInput *temperature_in = input("Temperature");
-
- if (color_in->link)
- compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
- else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
-
- compiler.add_node(NODE_PRINCIPLED_VOLUME,
- compiler.encode_uchar4(compiler.stack_assign_if_linked(density_in),
- compiler.stack_assign_if_linked(anisotropy_in),
- compiler.stack_assign(absorption_color_in),
- compiler.closure_mix_weight_offset()),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(emission_in),
- compiler.stack_assign(emission_color_in),
- compiler.stack_assign_if_linked(blackbody_in),
- compiler.stack_assign(temperature_in)),
- compiler.stack_assign(blackbody_tint_in));
-
- int attr_density = compiler.attribute_standard(density_attribute);
- int attr_color = compiler.attribute_standard(color_attribute);
- int attr_temperature = compiler.attribute_standard(temperature_attribute);
-
- compiler.add_node(__float_as_int(density),
- __float_as_int(anisotropy),
- __float_as_int(emission_strength),
- __float_as_int(blackbody_intensity));
-
- compiler.add_node(attr_density, attr_color, attr_temperature);
-}
-
-void PrincipledVolumeNode::compile(OSLCompiler &compiler)
-{
- if (Attribute::name_standard(density_attribute.c_str())) {
- density_attribute = ustring("geom:" + density_attribute.string());
- }
- if (Attribute::name_standard(color_attribute.c_str())) {
- color_attribute = ustring("geom:" + color_attribute.string());
- }
- if (Attribute::name_standard(temperature_attribute.c_str())) {
- temperature_attribute = ustring("geom:" + temperature_attribute.string());
- }
-
- compiler.add(this, "node_principled_volume");
-}
-
-/* Principled Hair BSDF Closure */
-
-NODE_DEFINE(PrincipledHairBsdfNode)
-{
- NodeType *type = NodeType::add("principled_hair_bsdf", create, NodeType::SHADER);
-
- /* Color parametrization specified as enum. */
- static NodeEnum parametrization_enum;
- parametrization_enum.insert("Direct coloring", NODE_PRINCIPLED_HAIR_REFLECTANCE);
- parametrization_enum.insert("Melanin concentration", NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
- parametrization_enum.insert("Absorption coefficient", NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION);
- SOCKET_ENUM(
- parametrization, "Parametrization", parametrization_enum, NODE_PRINCIPLED_HAIR_REFLECTANCE);
-
- /* Initialize sockets to their default values. */
- SOCKET_IN_COLOR(color, "Color", make_float3(0.017513f, 0.005763f, 0.002059f));
- SOCKET_IN_FLOAT(melanin, "Melanin", 0.8f);
- SOCKET_IN_FLOAT(melanin_redness, "Melanin Redness", 1.0f);
- SOCKET_IN_COLOR(tint, "Tint", make_float3(1.f, 1.f, 1.f));
- SOCKET_IN_VECTOR(absorption_coefficient,
- "Absorption Coefficient",
- make_float3(0.245531f, 0.52f, 1.365f),
- SocketType::VECTOR);
-
- SOCKET_IN_FLOAT(offset, "Offset", 2.f * M_PI_F / 180.f);
- SOCKET_IN_FLOAT(roughness, "Roughness", 0.3f);
- SOCKET_IN_FLOAT(radial_roughness, "Radial Roughness", 0.3f);
- SOCKET_IN_FLOAT(coat, "Coat", 0.0f);
- SOCKET_IN_FLOAT(ior, "IOR", 1.55f);
-
- SOCKET_IN_FLOAT(random_roughness, "Random Roughness", 0.0f);
- SOCKET_IN_FLOAT(random_color, "Random Color", 0.0f);
- SOCKET_IN_FLOAT(random, "Random", 0.0f);
-
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-PrincipledHairBsdfNode::PrincipledHairBsdfNode() : BsdfBaseNode(get_node_type())
-{
- closure = CLOSURE_BSDF_HAIR_PRINCIPLED_ID;
-}
-
-/* Enable retrieving Hair Info -> Random if Random isn't linked. */
-void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (!input("Random")->link) {
- attributes->add(ATTR_STD_CURVE_RANDOM);
- }
- ShaderNode::attributes(shader, attributes);
-}
-
-/* Prepares the input data for the SVM shader. */
-void PrincipledHairBsdfNode::compile(SVMCompiler &compiler)
-{
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, one_float3());
-
- ShaderInput *roughness_in = input("Roughness");
- ShaderInput *radial_roughness_in = input("Radial Roughness");
- ShaderInput *random_roughness_in = input("Random Roughness");
- ShaderInput *offset_in = input("Offset");
- ShaderInput *coat_in = input("Coat");
- ShaderInput *ior_in = input("IOR");
- ShaderInput *melanin_in = input("Melanin");
- ShaderInput *melanin_redness_in = input("Melanin Redness");
- ShaderInput *random_color_in = input("Random Color");
-
- int color_ofs = compiler.stack_assign(input("Color"));
- int tint_ofs = compiler.stack_assign(input("Tint"));
- int absorption_coefficient_ofs = compiler.stack_assign(input("Absorption Coefficient"));
-
- ShaderInput *random_in = input("Random");
- int attr_random = random_in->link ? SVM_STACK_INVALID :
- compiler.attribute(ATTR_STD_CURVE_RANDOM);
-
- /* Encode all parameters into data nodes. */
- compiler.add_node(NODE_CLOSURE_BSDF,
- /* Socket IDs can be packed 4 at a time into a single data packet */
- compiler.encode_uchar4(closure,
- compiler.stack_assign_if_linked(roughness_in),
- compiler.stack_assign_if_linked(radial_roughness_in),
- compiler.closure_mix_weight_offset()),
- /* The rest are stored as unsigned integers */
- __float_as_uint(roughness),
- __float_as_uint(radial_roughness));
-
- compiler.add_node(compiler.stack_assign_if_linked(input("Normal")),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(offset_in),
- compiler.stack_assign_if_linked(ior_in),
- color_ofs,
- parametrization),
- __float_as_uint(offset),
- __float_as_uint(ior));
-
- compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(coat_in),
- compiler.stack_assign_if_linked(melanin_in),
- compiler.stack_assign_if_linked(melanin_redness_in),
- absorption_coefficient_ofs),
- __float_as_uint(coat),
- __float_as_uint(melanin),
- __float_as_uint(melanin_redness));
-
- compiler.add_node(compiler.encode_uchar4(tint_ofs,
- compiler.stack_assign_if_linked(random_in),
- compiler.stack_assign_if_linked(random_color_in),
- compiler.stack_assign_if_linked(random_roughness_in)),
- __float_as_uint(random),
- __float_as_uint(random_color),
- __float_as_uint(random_roughness));
-
- compiler.add_node(
- compiler.encode_uchar4(
- SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID),
- attr_random,
- SVM_STACK_INVALID,
- SVM_STACK_INVALID);
-}
-
-/* Prepares the input data for the OSL shader. */
-void PrincipledHairBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "parametrization");
- compiler.add(this, "node_principled_hair_bsdf");
-}
-
-/* Hair BSDF Closure */
-
-NODE_DEFINE(HairBsdfNode)
-{
- NodeType *type = NodeType::add("hair_bsdf", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
-
- static NodeEnum component_enum;
- component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
- component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
- SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID);
- SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
- SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f);
- SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f);
- SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3());
-
- SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-
- return type;
-}
-
-HairBsdfNode::HairBsdfNode() : BsdfNode(get_node_type())
-{
- closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
-}
-
-void HairBsdfNode::compile(SVMCompiler &compiler)
-{
- closure = component;
-
- BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
-}
-
-void HairBsdfNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "component");
- compiler.add(this, "node_hair_bsdf");
-}
-
-/* Geometry */
-
-NODE_DEFINE(GeometryNode)
-{
- NodeType *type = NodeType::add("geometry", create, NodeType::SHADER);
-
- SOCKET_IN_NORMAL(
- normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
-
- SOCKET_OUT_POINT(position, "Position");
- SOCKET_OUT_NORMAL(normal, "Normal");
- SOCKET_OUT_NORMAL(tangent, "Tangent");
- SOCKET_OUT_NORMAL(true_normal, "True Normal");
- SOCKET_OUT_VECTOR(incoming, "Incoming");
- SOCKET_OUT_POINT(parametric, "Parametric");
- SOCKET_OUT_FLOAT(backfacing, "Backfacing");
- SOCKET_OUT_FLOAT(pointiness, "Pointiness");
- SOCKET_OUT_FLOAT(random_per_island, "Random Per Island");
-
- return type;
-}
-
-GeometryNode::GeometryNode() : ShaderNode(get_node_type())
-{
- special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
-}
-
-void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_surface_link()) {
- if (!output("Tangent")->links.empty()) {
- attributes->add(ATTR_STD_GENERATED);
- }
- if (!output("Pointiness")->links.empty()) {
- attributes->add(ATTR_STD_POINTINESS);
- }
- if (!output("Random Per Island")->links.empty()) {
- attributes->add(ATTR_STD_RANDOM_PER_ISLAND);
- }
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void GeometryNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *out;
- ShaderNodeType geom_node = NODE_GEOMETRY;
- ShaderNodeType attr_node = NODE_ATTR;
-
- if (bump == SHADER_BUMP_DX) {
- geom_node = NODE_GEOMETRY_BUMP_DX;
- attr_node = NODE_ATTR_BUMP_DX;
- }
- else if (bump == SHADER_BUMP_DY) {
- geom_node = NODE_GEOMETRY_BUMP_DY;
- attr_node = NODE_ATTR_BUMP_DY;
- }
-
- out = output("Position");
- if (!out->links.empty()) {
- compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
- }
-
- out = output("Normal");
- if (!out->links.empty()) {
- compiler.add_node(geom_node, NODE_GEOM_N, compiler.stack_assign(out));
- }
-
- out = output("Tangent");
- if (!out->links.empty()) {
- compiler.add_node(geom_node, NODE_GEOM_T, compiler.stack_assign(out));
- }
-
- out = output("True Normal");
- if (!out->links.empty()) {
- compiler.add_node(geom_node, NODE_GEOM_Ng, compiler.stack_assign(out));
- }
-
- out = output("Incoming");
- if (!out->links.empty()) {
- compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
- }
-
- out = output("Parametric");
- if (!out->links.empty()) {
- compiler.add_node(geom_node, NODE_GEOM_uv, compiler.stack_assign(out));
- }
-
- out = output("Backfacing");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, compiler.stack_assign(out));
- }
-
- out = output("Pointiness");
- if (!out->links.empty()) {
- if (compiler.output_type() != SHADER_TYPE_VOLUME) {
- compiler.add_node(
- attr_node, ATTR_STD_POINTINESS, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
- }
- else {
- compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
- }
- }
-
- out = output("Random Per Island");
- if (!out->links.empty()) {
- if (compiler.output_type() != SHADER_TYPE_VOLUME) {
- compiler.add_node(attr_node,
- ATTR_STD_RANDOM_PER_ISLAND,
- compiler.stack_assign(out),
- NODE_ATTR_OUTPUT_FLOAT);
- }
- else {
- compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
- }
- }
-}
-
-void GeometryNode::compile(OSLCompiler &compiler)
-{
- if (bump == SHADER_BUMP_DX)
- compiler.parameter("bump_offset", "dx");
- else if (bump == SHADER_BUMP_DY)
- compiler.parameter("bump_offset", "dy");
- else
- compiler.parameter("bump_offset", "center");
-
- compiler.add(this, "node_geometry");
-}
-
-/* TextureCoordinate */
-
-NODE_DEFINE(TextureCoordinateNode)
-{
- NodeType *type = NodeType::add("texture_coordinate", create, NodeType::SHADER);
-
- SOCKET_BOOLEAN(from_dupli, "From Dupli", false);
- SOCKET_BOOLEAN(use_transform, "Use Transform", false);
- SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity());
-
- SOCKET_IN_NORMAL(
- normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
-
- SOCKET_OUT_POINT(generated, "Generated");
- SOCKET_OUT_NORMAL(normal, "Normal");
- SOCKET_OUT_POINT(UV, "UV");
- SOCKET_OUT_POINT(object, "Object");
- SOCKET_OUT_POINT(camera, "Camera");
- SOCKET_OUT_POINT(window, "Window");
- SOCKET_OUT_NORMAL(reflection, "Reflection");
-
- return type;
-}
-
-TextureCoordinateNode::TextureCoordinateNode() : ShaderNode(get_node_type())
-{
-}
-
-void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_surface_link()) {
- if (!from_dupli) {
- if (!output("Generated")->links.empty())
- attributes->add(ATTR_STD_GENERATED);
- if (!output("UV")->links.empty())
- attributes->add(ATTR_STD_UV);
- }
- }
-
- if (shader->has_volume) {
- if (!from_dupli) {
- if (!output("Generated")->links.empty()) {
- attributes->add(ATTR_STD_GENERATED_TRANSFORM);
- }
- }
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void TextureCoordinateNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *out;
- ShaderNodeType texco_node = NODE_TEX_COORD;
- ShaderNodeType attr_node = NODE_ATTR;
- ShaderNodeType geom_node = NODE_GEOMETRY;
-
- if (bump == SHADER_BUMP_DX) {
- texco_node = NODE_TEX_COORD_BUMP_DX;
- attr_node = NODE_ATTR_BUMP_DX;
- geom_node = NODE_GEOMETRY_BUMP_DX;
- }
- else if (bump == SHADER_BUMP_DY) {
- texco_node = NODE_TEX_COORD_BUMP_DY;
- attr_node = NODE_ATTR_BUMP_DY;
- geom_node = NODE_GEOMETRY_BUMP_DY;
- }
-
- out = output("Generated");
- if (!out->links.empty()) {
- if (compiler.background) {
- compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
- }
- else {
- if (from_dupli) {
- compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, compiler.stack_assign(out));
- }
- else if (compiler.output_type() == SHADER_TYPE_VOLUME) {
- compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, compiler.stack_assign(out));
- }
- else {
- int attr = compiler.attribute(ATTR_STD_GENERATED);
- compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
- }
- }
- }
-
- out = output("Normal");
- if (!out->links.empty()) {
- compiler.add_node(texco_node, NODE_TEXCO_NORMAL, compiler.stack_assign(out));
- }
-
- out = output("UV");
- if (!out->links.empty()) {
- if (from_dupli) {
- compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
- }
- else {
- int attr = compiler.attribute(ATTR_STD_UV);
- compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
- }
- }
-
- out = output("Object");
- if (!out->links.empty()) {
- compiler.add_node(texco_node, NODE_TEXCO_OBJECT, compiler.stack_assign(out), use_transform);
- if (use_transform) {
- Transform ob_itfm = transform_inverse(ob_tfm);
- compiler.add_node(ob_itfm.x);
- compiler.add_node(ob_itfm.y);
- compiler.add_node(ob_itfm.z);
- }
- }
-
- out = output("Camera");
- if (!out->links.empty()) {
- compiler.add_node(texco_node, NODE_TEXCO_CAMERA, compiler.stack_assign(out));
- }
-
- out = output("Window");
- if (!out->links.empty()) {
- compiler.add_node(texco_node, NODE_TEXCO_WINDOW, compiler.stack_assign(out));
- }
-
- out = output("Reflection");
- if (!out->links.empty()) {
- if (compiler.background) {
- compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
- }
- else {
- compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, compiler.stack_assign(out));
- }
- }
-}
-
-void TextureCoordinateNode::compile(OSLCompiler &compiler)
-{
- if (bump == SHADER_BUMP_DX)
- compiler.parameter("bump_offset", "dx");
- else if (bump == SHADER_BUMP_DY)
- compiler.parameter("bump_offset", "dy");
- else
- compiler.parameter("bump_offset", "center");
-
- if (compiler.background)
- compiler.parameter("is_background", true);
- if (compiler.output_type() == SHADER_TYPE_VOLUME)
- compiler.parameter("is_volume", true);
- compiler.parameter(this, "use_transform");
- Transform ob_itfm = transform_inverse(ob_tfm);
- compiler.parameter("object_itfm", ob_itfm);
-
- compiler.parameter(this, "from_dupli");
-
- compiler.add(this, "node_texture_coordinate");
-}
-
-/* UV Map */
-
-NODE_DEFINE(UVMapNode)
-{
- NodeType *type = NodeType::add("uvmap", create, NodeType::SHADER);
-
- SOCKET_STRING(attribute, "attribute", ustring());
- SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false);
-
- SOCKET_OUT_POINT(UV, "UV");
-
- return type;
-}
-
-UVMapNode::UVMapNode() : ShaderNode(get_node_type())
-{
-}
-
-void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_surface) {
- if (!from_dupli) {
- if (!output("UV")->links.empty()) {
- if (attribute != "")
- attributes->add(attribute);
- else
- attributes->add(ATTR_STD_UV);
- }
- }
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void UVMapNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *out = output("UV");
- ShaderNodeType texco_node = NODE_TEX_COORD;
- ShaderNodeType attr_node = NODE_ATTR;
- int attr;
-
- if (bump == SHADER_BUMP_DX) {
- texco_node = NODE_TEX_COORD_BUMP_DX;
- attr_node = NODE_ATTR_BUMP_DX;
- }
- else if (bump == SHADER_BUMP_DY) {
- texco_node = NODE_TEX_COORD_BUMP_DY;
- attr_node = NODE_ATTR_BUMP_DY;
- }
-
- if (!out->links.empty()) {
- if (from_dupli) {
- compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
- }
- else {
- if (attribute != "")
- attr = compiler.attribute(attribute);
- else
- attr = compiler.attribute(ATTR_STD_UV);
-
- compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
- }
- }
-}
-
-void UVMapNode::compile(OSLCompiler &compiler)
-{
- if (bump == SHADER_BUMP_DX)
- compiler.parameter("bump_offset", "dx");
- else if (bump == SHADER_BUMP_DY)
- compiler.parameter("bump_offset", "dy");
- else
- compiler.parameter("bump_offset", "center");
-
- compiler.parameter(this, "from_dupli");
- compiler.parameter(this, "attribute");
- compiler.add(this, "node_uv_map");
-}
-
-/* Light Path */
-
-NODE_DEFINE(LightPathNode)
-{
- NodeType *type = NodeType::add("light_path", create, NodeType::SHADER);
-
- SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray");
- SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray");
- SOCKET_OUT_FLOAT(is_diffuse_ray, "Is Diffuse Ray");
- SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray");
- SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray");
- SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray");
- SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray");
- SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray");
- SOCKET_OUT_FLOAT(ray_length, "Ray Length");
- SOCKET_OUT_FLOAT(ray_depth, "Ray Depth");
- SOCKET_OUT_FLOAT(diffuse_depth, "Diffuse Depth");
- SOCKET_OUT_FLOAT(glossy_depth, "Glossy Depth");
- SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth");
- SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth");
-
- return type;
-}
-
-LightPathNode::LightPathNode() : ShaderNode(get_node_type())
-{
-}
-
-void LightPathNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *out;
-
- out = output("Is Camera Ray");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_camera, compiler.stack_assign(out));
- }
-
- out = output("Is Shadow Ray");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_shadow, compiler.stack_assign(out));
- }
-
- out = output("Is Diffuse Ray");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_diffuse, compiler.stack_assign(out));
- }
-
- out = output("Is Glossy Ray");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, compiler.stack_assign(out));
- }
-
- out = output("Is Singular Ray");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_singular, compiler.stack_assign(out));
- }
-
- out = output("Is Reflection Ray");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, compiler.stack_assign(out));
- }
-
- out = output("Is Transmission Ray");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, compiler.stack_assign(out));
- }
-
- out = output("Is Volume Scatter Ray");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_volume_scatter, compiler.stack_assign(out));
- }
-
- out = output("Ray Length");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, compiler.stack_assign(out));
- }
-
- out = output("Ray Depth");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, compiler.stack_assign(out));
- }
-
- out = output("Diffuse Depth");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_diffuse, compiler.stack_assign(out));
- }
-
- out = output("Glossy Depth");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_glossy, compiler.stack_assign(out));
- }
-
- out = output("Transparent Depth");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, compiler.stack_assign(out));
- }
-
- out = output("Transmission Depth");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transmission, compiler.stack_assign(out));
- }
-}
-
-void LightPathNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_light_path");
-}
-
-/* Light Falloff */
-
-NODE_DEFINE(LightFalloffNode)
-{
- NodeType *type = NodeType::add("light_falloff", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(strength, "Strength", 100.0f);
- SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
-
- SOCKET_OUT_FLOAT(quadratic, "Quadratic");
- SOCKET_OUT_FLOAT(linear, "Linear");
- SOCKET_OUT_FLOAT(constant, "Constant");
-
- return type;
-}
-
-LightFalloffNode::LightFalloffNode() : ShaderNode(get_node_type())
-{
-}
-
-void LightFalloffNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *strength_in = input("Strength");
- ShaderInput *smooth_in = input("Smooth");
-
- ShaderOutput *out = output("Quadratic");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_FALLOFF,
- NODE_LIGHT_FALLOFF_QUADRATIC,
- compiler.encode_uchar4(compiler.stack_assign(strength_in),
- compiler.stack_assign(smooth_in),
- compiler.stack_assign(out)));
- }
-
- out = output("Linear");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_FALLOFF,
- NODE_LIGHT_FALLOFF_LINEAR,
- compiler.encode_uchar4(compiler.stack_assign(strength_in),
- compiler.stack_assign(smooth_in),
- compiler.stack_assign(out)));
- }
-
- out = output("Constant");
- if (!out->links.empty()) {
- compiler.add_node(NODE_LIGHT_FALLOFF,
- NODE_LIGHT_FALLOFF_CONSTANT,
- compiler.encode_uchar4(compiler.stack_assign(strength_in),
- compiler.stack_assign(smooth_in),
- compiler.stack_assign(out)));
- }
-}
-
-void LightFalloffNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_light_falloff");
-}
-
-/* Object Info */
-
-NODE_DEFINE(ObjectInfoNode)
-{
- NodeType *type = NodeType::add("object_info", create, NodeType::SHADER);
-
- SOCKET_OUT_VECTOR(location, "Location");
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(object_index, "Object Index");
- SOCKET_OUT_FLOAT(material_index, "Material Index");
- SOCKET_OUT_FLOAT(random, "Random");
-
- return type;
-}
-
-ObjectInfoNode::ObjectInfoNode() : ShaderNode(get_node_type())
-{
-}
-
-void ObjectInfoNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *out = output("Location");
- if (!out->links.empty()) {
- compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, compiler.stack_assign(out));
- }
-
- out = output("Color");
- if (!out->links.empty()) {
- compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_COLOR, compiler.stack_assign(out));
- }
-
- out = output("Object Index");
- if (!out->links.empty()) {
- compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, compiler.stack_assign(out));
- }
-
- out = output("Material Index");
- if (!out->links.empty()) {
- compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_MAT_INDEX, compiler.stack_assign(out));
- }
-
- out = output("Random");
- if (!out->links.empty()) {
- compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_RANDOM, compiler.stack_assign(out));
- }
-}
-
-void ObjectInfoNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_object_info");
-}
-
-/* Particle Info */
-
-NODE_DEFINE(ParticleInfoNode)
-{
- NodeType *type = NodeType::add("particle_info", create, NodeType::SHADER);
-
- SOCKET_OUT_FLOAT(index, "Index");
- SOCKET_OUT_FLOAT(random, "Random");
- SOCKET_OUT_FLOAT(age, "Age");
- SOCKET_OUT_FLOAT(lifetime, "Lifetime");
- SOCKET_OUT_POINT(location, "Location");
-#if 0 /* not yet supported */
- SOCKET_OUT_QUATERNION(rotation, "Rotation");
-#endif
- SOCKET_OUT_FLOAT(size, "Size");
- SOCKET_OUT_VECTOR(velocity, "Velocity");
- SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity");
-
- return type;
-}
-
-ParticleInfoNode::ParticleInfoNode() : ShaderNode(get_node_type())
-{
-}
-
-void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (!output("Index")->links.empty())
- attributes->add(ATTR_STD_PARTICLE);
- if (!output("Random")->links.empty())
- attributes->add(ATTR_STD_PARTICLE);
- if (!output("Age")->links.empty())
- attributes->add(ATTR_STD_PARTICLE);
- if (!output("Lifetime")->links.empty())
- attributes->add(ATTR_STD_PARTICLE);
- if (!output("Location")->links.empty())
- attributes->add(ATTR_STD_PARTICLE);
-#if 0 /* not yet supported */
- if (!output("Rotation")->links.empty())
- attributes->add(ATTR_STD_PARTICLE);
-#endif
- if (!output("Size")->links.empty())
- attributes->add(ATTR_STD_PARTICLE);
- if (!output("Velocity")->links.empty())
- attributes->add(ATTR_STD_PARTICLE);
- if (!output("Angular Velocity")->links.empty())
- attributes->add(ATTR_STD_PARTICLE);
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void ParticleInfoNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *out;
-
- out = output("Index");
- if (!out->links.empty()) {
- compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_INDEX, compiler.stack_assign(out));
- }
-
- out = output("Random");
- if (!out->links.empty()) {
- compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_RANDOM, compiler.stack_assign(out));
- }
-
- out = output("Age");
- if (!out->links.empty()) {
- compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_AGE, compiler.stack_assign(out));
- }
-
- out = output("Lifetime");
- if (!out->links.empty()) {
- compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LIFETIME, compiler.stack_assign(out));
- }
-
- out = output("Location");
- if (!out->links.empty()) {
- compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LOCATION, compiler.stack_assign(out));
- }
-
- /* quaternion data is not yet supported by Cycles */
-#if 0
- out = output("Rotation");
- if (!out->links.empty()) {
- compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ROTATION, compiler.stack_assign(out));
- }
-#endif
-
- out = output("Size");
- if (!out->links.empty()) {
- compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_SIZE, compiler.stack_assign(out));
- }
-
- out = output("Velocity");
- if (!out->links.empty()) {
- compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_VELOCITY, compiler.stack_assign(out));
- }
-
- out = output("Angular Velocity");
- if (!out->links.empty()) {
- compiler.add_node(
- NODE_PARTICLE_INFO, NODE_INFO_PAR_ANGULAR_VELOCITY, compiler.stack_assign(out));
- }
-}
-
-void ParticleInfoNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_particle_info");
-}
-
-/* Hair Info */
-
-NODE_DEFINE(HairInfoNode)
-{
- NodeType *type = NodeType::add("hair_info", create, NodeType::SHADER);
-
- SOCKET_OUT_FLOAT(is_strand, "Is Strand");
- SOCKET_OUT_FLOAT(intercept, "Intercept");
- SOCKET_OUT_FLOAT(size, "Length");
- SOCKET_OUT_FLOAT(thickness, "Thickness");
- SOCKET_OUT_NORMAL(tangent_normal, "Tangent Normal");
-#if 0 /* Output for minimum hair width transparency - deactivated. */
- SOCKET_OUT_FLOAT(fade, "Fade");
-#endif
- SOCKET_OUT_FLOAT(index, "Random");
-
- return type;
-}
-
-HairInfoNode::HairInfoNode() : ShaderNode(get_node_type())
-{
-}
-
-void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_surface_link()) {
- ShaderOutput *intercept_out = output("Intercept");
-
- if (!intercept_out->links.empty())
- attributes->add(ATTR_STD_CURVE_INTERCEPT);
-
- if (!output("Length")->links.empty())
- attributes->add(ATTR_STD_CURVE_LENGTH);
-
- if (!output("Random")->links.empty())
- attributes->add(ATTR_STD_CURVE_RANDOM);
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void HairInfoNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *out;
-
- out = output("Is Strand");
- if (!out->links.empty()) {
- compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, compiler.stack_assign(out));
- }
-
- out = output("Intercept");
- if (!out->links.empty()) {
- int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT);
- compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
- }
-
- out = output("Length");
- if (!out->links.empty()) {
- int attr = compiler.attribute(ATTR_STD_CURVE_LENGTH);
- compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
- }
-
- out = output("Thickness");
- if (!out->links.empty()) {
- compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, compiler.stack_assign(out));
- }
-
- out = output("Tangent Normal");
- if (!out->links.empty()) {
- compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, compiler.stack_assign(out));
- }
-#if 0
- out = output("Fade");
- if(!out->links.empty()) {
- compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_FADE, compiler.stack_assign(out));
- }
-#endif
- out = output("Random");
- if (!out->links.empty()) {
- int attr = compiler.attribute(ATTR_STD_CURVE_RANDOM);
- compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
- }
-}
-
-void HairInfoNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_hair_info");
-}
-
-/* Volume Info */
-
-NODE_DEFINE(VolumeInfoNode)
-{
- NodeType *type = NodeType::add("volume_info", create, NodeType::SHADER);
-
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(density, "Density");
- SOCKET_OUT_FLOAT(flame, "Flame");
- SOCKET_OUT_FLOAT(temperature, "Temperature");
-
- return type;
-}
-
-VolumeInfoNode::VolumeInfoNode() : ShaderNode(get_node_type())
-{
-}
-
-/* The requested attributes are not updated after node expansion.
- * So we explicitly request the required attributes.
- */
-void VolumeInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_volume) {
- if (!output("Color")->links.empty()) {
- attributes->add(ATTR_STD_VOLUME_COLOR);
- }
- if (!output("Density")->links.empty()) {
- attributes->add(ATTR_STD_VOLUME_DENSITY);
- }
- if (!output("Flame")->links.empty()) {
- attributes->add(ATTR_STD_VOLUME_FLAME);
- }
- if (!output("Temperature")->links.empty()) {
- attributes->add(ATTR_STD_VOLUME_TEMPERATURE);
- }
- attributes->add(ATTR_STD_GENERATED_TRANSFORM);
- }
- ShaderNode::attributes(shader, attributes);
-}
-
-void VolumeInfoNode::expand(ShaderGraph *graph)
-{
- ShaderOutput *color_out = output("Color");
- if (!color_out->links.empty()) {
- AttributeNode *attr = graph->create_node<AttributeNode>();
- attr->set_attribute(ustring("color"));
- graph->add(attr);
- graph->relink(color_out, attr->output("Color"));
- }
-
- ShaderOutput *density_out = output("Density");
- if (!density_out->links.empty()) {
- AttributeNode *attr = graph->create_node<AttributeNode>();
- attr->set_attribute(ustring("density"));
- graph->add(attr);
- graph->relink(density_out, attr->output("Fac"));
- }
-
- ShaderOutput *flame_out = output("Flame");
- if (!flame_out->links.empty()) {
- AttributeNode *attr = graph->create_node<AttributeNode>();
- attr->set_attribute(ustring("flame"));
- graph->add(attr);
- graph->relink(flame_out, attr->output("Fac"));
- }
-
- ShaderOutput *temperature_out = output("Temperature");
- if (!temperature_out->links.empty()) {
- AttributeNode *attr = graph->create_node<AttributeNode>();
- attr->set_attribute(ustring("temperature"));
- graph->add(attr);
- graph->relink(temperature_out, attr->output("Fac"));
- }
-}
-
-void VolumeInfoNode::compile(SVMCompiler &)
-{
-}
-
-void VolumeInfoNode::compile(OSLCompiler &)
-{
-}
-
-NODE_DEFINE(VertexColorNode)
-{
- NodeType *type = NodeType::add("vertex_color", create, NodeType::SHADER);
-
- SOCKET_STRING(layer_name, "Layer Name", ustring());
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(alpha, "Alpha");
-
- return type;
-}
-
-VertexColorNode::VertexColorNode() : ShaderNode(get_node_type())
-{
-}
-
-void VertexColorNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (!(output("Color")->links.empty() && output("Alpha")->links.empty())) {
- if (layer_name != "")
- attributes->add_standard(layer_name);
- else
- attributes->add(ATTR_STD_VERTEX_COLOR);
- }
- ShaderNode::attributes(shader, attributes);
-}
-
-void VertexColorNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *color_out = output("Color");
- ShaderOutput *alpha_out = output("Alpha");
- int layer_id = 0;
-
- if (layer_name != "") {
- layer_id = compiler.attribute(layer_name);
- }
- else {
- layer_id = compiler.attribute(ATTR_STD_VERTEX_COLOR);
- }
-
- ShaderNodeType node;
-
- if (bump == SHADER_BUMP_DX)
- node = NODE_VERTEX_COLOR_BUMP_DX;
- else if (bump == SHADER_BUMP_DY)
- node = NODE_VERTEX_COLOR_BUMP_DY;
- else {
- node = NODE_VERTEX_COLOR;
- }
-
- compiler.add_node(
- node, layer_id, compiler.stack_assign(color_out), compiler.stack_assign(alpha_out));
-}
-
-void VertexColorNode::compile(OSLCompiler &compiler)
-{
- if (bump == SHADER_BUMP_DX) {
- compiler.parameter("bump_offset", "dx");
- }
- else if (bump == SHADER_BUMP_DY) {
- compiler.parameter("bump_offset", "dy");
- }
- else {
- compiler.parameter("bump_offset", "center");
- }
-
- if (layer_name.empty()) {
- compiler.parameter("layer_name", ustring("geom:vertex_color"));
- }
- else {
- if (Attribute::name_standard(layer_name.c_str()) != ATTR_STD_NONE) {
- compiler.parameter("name", (string("geom:") + layer_name.c_str()).c_str());
- }
- else {
- compiler.parameter("layer_name", layer_name.c_str());
- }
- }
-
- compiler.add(this, "node_vertex_color");
-}
-
-/* Value */
-
-NODE_DEFINE(ValueNode)
-{
- NodeType *type = NodeType::add("value", create, NodeType::SHADER);
-
- SOCKET_FLOAT(value, "Value", 0.0f);
- SOCKET_OUT_FLOAT(value, "Value");
-
- return type;
-}
-
-ValueNode::ValueNode() : ShaderNode(get_node_type())
-{
-}
-
-void ValueNode::constant_fold(const ConstantFolder &folder)
-{
- folder.make_constant(value);
-}
-
-void ValueNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *val_out = output("Value");
-
- compiler.add_node(NODE_VALUE_F, __float_as_int(value), compiler.stack_assign(val_out));
-}
-
-void ValueNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter("value_value", value);
- compiler.add(this, "node_value");
-}
-
-/* Color */
-
-NODE_DEFINE(ColorNode)
-{
- NodeType *type = NodeType::add("color", create, NodeType::SHADER);
-
- SOCKET_COLOR(value, "Value", zero_float3());
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-ColorNode::ColorNode() : ShaderNode(get_node_type())
-{
-}
-
-void ColorNode::constant_fold(const ConstantFolder &folder)
-{
- folder.make_constant(value);
-}
-
-void ColorNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *color_out = output("Color");
-
- if (!color_out->links.empty()) {
- compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
- compiler.add_node(NODE_VALUE_V, value);
- }
-}
-
-void ColorNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter_color("color_value", value);
-
- compiler.add(this, "node_value");
-}
-
-/* Add Closure */
-
-NODE_DEFINE(AddClosureNode)
-{
- NodeType *type = NodeType::add("add_closure", create, NodeType::SHADER);
-
- SOCKET_IN_CLOSURE(closure1, "Closure1");
- SOCKET_IN_CLOSURE(closure2, "Closure2");
- SOCKET_OUT_CLOSURE(closure, "Closure");
-
- return type;
-}
-
-AddClosureNode::AddClosureNode() : ShaderNode(get_node_type())
-{
- special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
-}
-
-void AddClosureNode::compile(SVMCompiler & /*compiler*/)
-{
- /* handled in the SVM compiler */
-}
-
-void AddClosureNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_add_closure");
-}
-
-void AddClosureNode::constant_fold(const ConstantFolder &folder)
-{
- ShaderInput *closure1_in = input("Closure1");
- ShaderInput *closure2_in = input("Closure2");
-
- /* remove useless add closures nodes */
- if (!closure1_in->link) {
- folder.bypass_or_discard(closure2_in);
- }
- else if (!closure2_in->link) {
- folder.bypass_or_discard(closure1_in);
- }
-}
-
-/* Mix Closure */
-
-NODE_DEFINE(MixClosureNode)
-{
- NodeType *type = NodeType::add("mix_closure", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
- SOCKET_IN_CLOSURE(closure1, "Closure1");
- SOCKET_IN_CLOSURE(closure2, "Closure2");
-
- SOCKET_OUT_CLOSURE(closure, "Closure");
-
- return type;
-}
-
-MixClosureNode::MixClosureNode() : ShaderNode(get_node_type())
-{
- special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
-}
-
-void MixClosureNode::compile(SVMCompiler & /*compiler*/)
-{
- /* handled in the SVM compiler */
-}
-
-void MixClosureNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_mix_closure");
-}
-
-void MixClosureNode::constant_fold(const ConstantFolder &folder)
-{
- ShaderInput *fac_in = input("Fac");
- ShaderInput *closure1_in = input("Closure1");
- ShaderInput *closure2_in = input("Closure2");
-
- /* remove useless mix closures nodes */
- if (closure1_in->link == closure2_in->link) {
- folder.bypass_or_discard(closure1_in);
- }
- /* remove unused mix closure input when factor is 0.0 or 1.0
- * check for closure links and make sure factor link is disconnected */
- else if (!fac_in->link) {
- /* factor 0.0 */
- if (fac <= 0.0f) {
- folder.bypass_or_discard(closure1_in);
- }
- /* factor 1.0 */
- else if (fac >= 1.0f) {
- folder.bypass_or_discard(closure2_in);
- }
- }
-}
-
-/* Mix Closure */
-
-NODE_DEFINE(MixClosureWeightNode)
-{
- NodeType *type = NodeType::add("mix_closure_weight", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(weight, "Weight", 1.0f);
- SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
-
- SOCKET_OUT_FLOAT(weight1, "Weight1");
- SOCKET_OUT_FLOAT(weight2, "Weight2");
-
- return type;
-}
-
-MixClosureWeightNode::MixClosureWeightNode() : ShaderNode(get_node_type())
-{
-}
-
-void MixClosureWeightNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *weight_in = input("Weight");
- ShaderInput *fac_in = input("Fac");
- ShaderOutput *weight1_out = output("Weight1");
- ShaderOutput *weight2_out = output("Weight2");
-
- compiler.add_node(NODE_MIX_CLOSURE,
- compiler.encode_uchar4(compiler.stack_assign(fac_in),
- compiler.stack_assign(weight_in),
- compiler.stack_assign(weight1_out),
- compiler.stack_assign(weight2_out)));
-}
-
-void MixClosureWeightNode::compile(OSLCompiler & /*compiler*/)
-{
- assert(0);
-}
-
-/* Invert */
-
-NODE_DEFINE(InvertNode)
-{
- NodeType *type = NodeType::add("invert", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
- SOCKET_IN_COLOR(color, "Color", zero_float3());
-
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-InvertNode::InvertNode() : ShaderNode(get_node_type())
-{
-}
-
-void InvertNode::constant_fold(const ConstantFolder &folder)
-{
- ShaderInput *fac_in = input("Fac");
- ShaderInput *color_in = input("Color");
-
- if (!fac_in->link) {
- /* evaluate fully constant node */
- if (!color_in->link) {
- folder.make_constant(interp(color, one_float3() - color, fac));
- }
- /* remove no-op node */
- else if (fac == 0.0f) {
- folder.bypass(color_in->link);
- }
- }
-}
-
-void InvertNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *fac_in = input("Fac");
- ShaderInput *color_in = input("Color");
- ShaderOutput *color_out = output("Color");
-
- compiler.add_node(NODE_INVERT,
- compiler.stack_assign(fac_in),
- compiler.stack_assign(color_in),
- compiler.stack_assign(color_out));
-}
-
-void InvertNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_invert");
-}
-
-/* Mix */
-
-NODE_DEFINE(MixNode)
-{
- NodeType *type = NodeType::add("mix", create, NodeType::SHADER);
-
- static NodeEnum type_enum;
- type_enum.insert("mix", NODE_MIX_BLEND);
- type_enum.insert("add", NODE_MIX_ADD);
- type_enum.insert("multiply", NODE_MIX_MUL);
- type_enum.insert("screen", NODE_MIX_SCREEN);
- type_enum.insert("overlay", NODE_MIX_OVERLAY);
- type_enum.insert("subtract", NODE_MIX_SUB);
- type_enum.insert("divide", NODE_MIX_DIV);
- type_enum.insert("difference", NODE_MIX_DIFF);
- type_enum.insert("darken", NODE_MIX_DARK);
- type_enum.insert("lighten", NODE_MIX_LIGHT);
- type_enum.insert("dodge", NODE_MIX_DODGE);
- type_enum.insert("burn", NODE_MIX_BURN);
- type_enum.insert("hue", NODE_MIX_HUE);
- type_enum.insert("saturation", NODE_MIX_SAT);
- type_enum.insert("value", NODE_MIX_VAL);
- type_enum.insert("color", NODE_MIX_COLOR);
- type_enum.insert("soft_light", NODE_MIX_SOFT);
- type_enum.insert("linear_light", NODE_MIX_LINEAR);
- SOCKET_ENUM(mix_type, "Type", type_enum, NODE_MIX_BLEND);
-
- SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
-
- SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
- SOCKET_IN_COLOR(color1, "Color1", zero_float3());
- SOCKET_IN_COLOR(color2, "Color2", zero_float3());
-
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-MixNode::MixNode() : ShaderNode(get_node_type())
-{
-}
-
-void MixNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *fac_in = input("Fac");
- ShaderInput *color1_in = input("Color1");
- ShaderInput *color2_in = input("Color2");
- ShaderOutput *color_out = output("Color");
-
- compiler.add_node(NODE_MIX,
- compiler.stack_assign(fac_in),
- compiler.stack_assign(color1_in),
- compiler.stack_assign(color2_in));
- compiler.add_node(NODE_MIX, mix_type, compiler.stack_assign(color_out));
-
- if (use_clamp) {
- compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out));
- compiler.add_node(NODE_MIX, NODE_MIX_CLAMP, compiler.stack_assign(color_out));
- }
-}
-
-void MixNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "mix_type");
- compiler.parameter(this, "use_clamp");
- compiler.add(this, "node_mix");
-}
-
-void MixNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- folder.make_constant_clamp(svm_mix(mix_type, fac, color1, color2), use_clamp);
- }
- else {
- folder.fold_mix(mix_type, use_clamp);
- }
-}
-
-/* Combine RGB */
-
-NODE_DEFINE(CombineRGBNode)
-{
- NodeType *type = NodeType::add("combine_rgb", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(r, "R", 0.0f);
- SOCKET_IN_FLOAT(g, "G", 0.0f);
- SOCKET_IN_FLOAT(b, "B", 0.0f);
-
- SOCKET_OUT_COLOR(image, "Image");
-
- return type;
-}
-
-CombineRGBNode::CombineRGBNode() : ShaderNode(get_node_type())
-{
-}
-
-void CombineRGBNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- folder.make_constant(make_float3(r, g, b));
- }
-}
-
-void CombineRGBNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *red_in = input("R");
- ShaderInput *green_in = input("G");
- ShaderInput *blue_in = input("B");
- ShaderOutput *color_out = output("Image");
-
- compiler.add_node(
- NODE_COMBINE_VECTOR, compiler.stack_assign(red_in), 0, compiler.stack_assign(color_out));
-
- compiler.add_node(
- NODE_COMBINE_VECTOR, compiler.stack_assign(green_in), 1, compiler.stack_assign(color_out));
-
- compiler.add_node(
- NODE_COMBINE_VECTOR, compiler.stack_assign(blue_in), 2, compiler.stack_assign(color_out));
-}
-
-void CombineRGBNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_combine_rgb");
-}
-
-/* Combine XYZ */
-
-NODE_DEFINE(CombineXYZNode)
-{
- NodeType *type = NodeType::add("combine_xyz", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(x, "X", 0.0f);
- SOCKET_IN_FLOAT(y, "Y", 0.0f);
- SOCKET_IN_FLOAT(z, "Z", 0.0f);
-
- SOCKET_OUT_VECTOR(vector, "Vector");
-
- return type;
-}
-
-CombineXYZNode::CombineXYZNode() : ShaderNode(get_node_type())
-{
-}
-
-void CombineXYZNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- folder.make_constant(make_float3(x, y, z));
- }
-}
-
-void CombineXYZNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *x_in = input("X");
- ShaderInput *y_in = input("Y");
- ShaderInput *z_in = input("Z");
- ShaderOutput *vector_out = output("Vector");
-
- compiler.add_node(
- NODE_COMBINE_VECTOR, compiler.stack_assign(x_in), 0, compiler.stack_assign(vector_out));
-
- compiler.add_node(
- NODE_COMBINE_VECTOR, compiler.stack_assign(y_in), 1, compiler.stack_assign(vector_out));
-
- compiler.add_node(
- NODE_COMBINE_VECTOR, compiler.stack_assign(z_in), 2, compiler.stack_assign(vector_out));
-}
-
-void CombineXYZNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_combine_xyz");
-}
-
-/* Combine HSV */
-
-NODE_DEFINE(CombineHSVNode)
-{
- NodeType *type = NodeType::add("combine_hsv", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(h, "H", 0.0f);
- SOCKET_IN_FLOAT(s, "S", 0.0f);
- SOCKET_IN_FLOAT(v, "V", 0.0f);
-
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-CombineHSVNode::CombineHSVNode() : ShaderNode(get_node_type())
-{
-}
-
-void CombineHSVNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- folder.make_constant(hsv_to_rgb(make_float3(h, s, v)));
- }
-}
-
-void CombineHSVNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *hue_in = input("H");
- ShaderInput *saturation_in = input("S");
- ShaderInput *value_in = input("V");
- ShaderOutput *color_out = output("Color");
-
- compiler.add_node(NODE_COMBINE_HSV,
- compiler.stack_assign(hue_in),
- compiler.stack_assign(saturation_in),
- compiler.stack_assign(value_in));
- compiler.add_node(NODE_COMBINE_HSV, compiler.stack_assign(color_out));
-}
-
-void CombineHSVNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_combine_hsv");
-}
-
-/* Gamma */
-
-NODE_DEFINE(GammaNode)
-{
- NodeType *type = NodeType::add("gamma", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", zero_float3());
- SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f);
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-GammaNode::GammaNode() : ShaderNode(get_node_type())
-{
-}
-
-void GammaNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- folder.make_constant(svm_math_gamma_color(color, gamma));
- }
- else {
- ShaderInput *color_in = input("Color");
- ShaderInput *gamma_in = input("Gamma");
-
- /* 1 ^ X == X ^ 0 == 1 */
- if (folder.is_one(color_in) || folder.is_zero(gamma_in)) {
- folder.make_one();
- }
- /* X ^ 1 == X */
- else if (folder.is_one(gamma_in)) {
- folder.try_bypass_or_make_constant(color_in, false);
- }
- }
-}
-
-void GammaNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *color_in = input("Color");
- ShaderInput *gamma_in = input("Gamma");
- ShaderOutput *color_out = output("Color");
-
- compiler.add_node(NODE_GAMMA,
- compiler.stack_assign(gamma_in),
- compiler.stack_assign(color_in),
- compiler.stack_assign(color_out));
-}
-
-void GammaNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_gamma");
-}
-
-/* Bright Contrast */
-
-NODE_DEFINE(BrightContrastNode)
-{
- NodeType *type = NodeType::add("brightness_contrast", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", zero_float3());
- SOCKET_IN_FLOAT(bright, "Bright", 0.0f);
- SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f);
-
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-BrightContrastNode::BrightContrastNode() : ShaderNode(get_node_type())
-{
-}
-
-void BrightContrastNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- folder.make_constant(svm_brightness_contrast(color, bright, contrast));
- }
-}
-
-void BrightContrastNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *color_in = input("Color");
- ShaderInput *bright_in = input("Bright");
- ShaderInput *contrast_in = input("Contrast");
- ShaderOutput *color_out = output("Color");
-
- compiler.add_node(NODE_BRIGHTCONTRAST,
- compiler.stack_assign(color_in),
- compiler.stack_assign(color_out),
- compiler.encode_uchar4(compiler.stack_assign(bright_in),
- compiler.stack_assign(contrast_in)));
-}
-
-void BrightContrastNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_brightness");
-}
-
-/* Separate RGB */
-
-NODE_DEFINE(SeparateRGBNode)
-{
- NodeType *type = NodeType::add("separate_rgb", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Image", zero_float3());
-
- SOCKET_OUT_FLOAT(r, "R");
- SOCKET_OUT_FLOAT(g, "G");
- SOCKET_OUT_FLOAT(b, "B");
-
- return type;
-}
-
-SeparateRGBNode::SeparateRGBNode() : ShaderNode(get_node_type())
-{
-}
-
-void SeparateRGBNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- for (int channel = 0; channel < 3; channel++) {
- if (outputs[channel] == folder.output) {
- folder.make_constant(color[channel]);
- return;
- }
- }
- }
-}
-
-void SeparateRGBNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *color_in = input("Image");
- ShaderOutput *red_out = output("R");
- ShaderOutput *green_out = output("G");
- ShaderOutput *blue_out = output("B");
-
- compiler.add_node(
- NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 0, compiler.stack_assign(red_out));
-
- compiler.add_node(
- NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 1, compiler.stack_assign(green_out));
-
- compiler.add_node(
- NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 2, compiler.stack_assign(blue_out));
-}
-
-void SeparateRGBNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_separate_rgb");
-}
-
-/* Separate XYZ */
-
-NODE_DEFINE(SeparateXYZNode)
-{
- NodeType *type = NodeType::add("separate_xyz", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(vector, "Vector", zero_float3());
-
- SOCKET_OUT_FLOAT(x, "X");
- SOCKET_OUT_FLOAT(y, "Y");
- SOCKET_OUT_FLOAT(z, "Z");
-
- return type;
-}
-
-SeparateXYZNode::SeparateXYZNode() : ShaderNode(get_node_type())
-{
-}
-
-void SeparateXYZNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- for (int channel = 0; channel < 3; channel++) {
- if (outputs[channel] == folder.output) {
- folder.make_constant(vector[channel]);
- return;
- }
- }
- }
-}
-
-void SeparateXYZNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderOutput *x_out = output("X");
- ShaderOutput *y_out = output("Y");
- ShaderOutput *z_out = output("Z");
-
- compiler.add_node(
- NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 0, compiler.stack_assign(x_out));
-
- compiler.add_node(
- NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 1, compiler.stack_assign(y_out));
-
- compiler.add_node(
- NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 2, compiler.stack_assign(z_out));
-}
-
-void SeparateXYZNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_separate_xyz");
-}
-
-/* Separate HSV */
-
-NODE_DEFINE(SeparateHSVNode)
-{
- NodeType *type = NodeType::add("separate_hsv", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", zero_float3());
-
- SOCKET_OUT_FLOAT(h, "H");
- SOCKET_OUT_FLOAT(s, "S");
- SOCKET_OUT_FLOAT(v, "V");
-
- return type;
-}
-
-SeparateHSVNode::SeparateHSVNode() : ShaderNode(get_node_type())
-{
-}
-
-void SeparateHSVNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- float3 hsv = rgb_to_hsv(color);
-
- for (int channel = 0; channel < 3; channel++) {
- if (outputs[channel] == folder.output) {
- folder.make_constant(hsv[channel]);
- return;
- }
- }
- }
-}
-
-void SeparateHSVNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *color_in = input("Color");
- ShaderOutput *hue_out = output("H");
- ShaderOutput *saturation_out = output("S");
- ShaderOutput *value_out = output("V");
-
- compiler.add_node(NODE_SEPARATE_HSV,
- compiler.stack_assign(color_in),
- compiler.stack_assign(hue_out),
- compiler.stack_assign(saturation_out));
- compiler.add_node(NODE_SEPARATE_HSV, compiler.stack_assign(value_out));
-}
-
-void SeparateHSVNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_separate_hsv");
-}
-
-/* Hue Saturation Value */
-
-NODE_DEFINE(HSVNode)
-{
- NodeType *type = NodeType::add("hsv", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(hue, "Hue", 0.5f);
- SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f);
- SOCKET_IN_FLOAT(value, "Value", 1.0f);
- SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
- SOCKET_IN_COLOR(color, "Color", zero_float3());
-
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-HSVNode::HSVNode() : ShaderNode(get_node_type())
-{
-}
-
-void HSVNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *hue_in = input("Hue");
- ShaderInput *saturation_in = input("Saturation");
- ShaderInput *value_in = input("Value");
- ShaderInput *fac_in = input("Fac");
- ShaderInput *color_in = input("Color");
- ShaderOutput *color_out = output("Color");
-
- compiler.add_node(NODE_HSV,
- compiler.encode_uchar4(compiler.stack_assign(color_in),
- compiler.stack_assign(fac_in),
- compiler.stack_assign(color_out)),
- compiler.encode_uchar4(compiler.stack_assign(hue_in),
- compiler.stack_assign(saturation_in),
- compiler.stack_assign(value_in)));
-}
-
-void HSVNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_hsv");
-}
-
-/* Attribute */
-
-NODE_DEFINE(AttributeNode)
-{
- NodeType *type = NodeType::add("attribute", create, NodeType::SHADER);
-
- SOCKET_STRING(attribute, "Attribute", ustring());
-
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_VECTOR(vector, "Vector");
- SOCKET_OUT_FLOAT(fac, "Fac");
- SOCKET_OUT_FLOAT(alpha, "Alpha");
-
- return type;
-}
-
-AttributeNode::AttributeNode() : ShaderNode(get_node_type())
-{
-}
-
-void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- ShaderOutput *color_out = output("Color");
- ShaderOutput *vector_out = output("Vector");
- ShaderOutput *fac_out = output("Fac");
- ShaderOutput *alpha_out = output("Alpha");
-
- if (!color_out->links.empty() || !vector_out->links.empty() || !fac_out->links.empty() ||
- !alpha_out->links.empty()) {
- attributes->add_standard(attribute);
- }
-
- if (shader->has_volume) {
- attributes->add(ATTR_STD_GENERATED_TRANSFORM);
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void AttributeNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *color_out = output("Color");
- ShaderOutput *vector_out = output("Vector");
- ShaderOutput *fac_out = output("Fac");
- ShaderOutput *alpha_out = output("Alpha");
- ShaderNodeType attr_node = NODE_ATTR;
- int attr = compiler.attribute_standard(attribute);
-
- if (bump == SHADER_BUMP_DX)
- attr_node = NODE_ATTR_BUMP_DX;
- else if (bump == SHADER_BUMP_DY)
- attr_node = NODE_ATTR_BUMP_DY;
-
- if (!color_out->links.empty() || !vector_out->links.empty()) {
- if (!color_out->links.empty()) {
- compiler.add_node(
- attr_node, attr, compiler.stack_assign(color_out), NODE_ATTR_OUTPUT_FLOAT3);
- }
- if (!vector_out->links.empty()) {
- compiler.add_node(
- attr_node, attr, compiler.stack_assign(vector_out), NODE_ATTR_OUTPUT_FLOAT3);
- }
- }
-
- if (!fac_out->links.empty()) {
- compiler.add_node(attr_node, attr, compiler.stack_assign(fac_out), NODE_ATTR_OUTPUT_FLOAT);
- }
-
- if (!alpha_out->links.empty()) {
- compiler.add_node(
- attr_node, attr, compiler.stack_assign(alpha_out), NODE_ATTR_OUTPUT_FLOAT_ALPHA);
- }
-}
-
-void AttributeNode::compile(OSLCompiler &compiler)
-{
- if (bump == SHADER_BUMP_DX)
- compiler.parameter("bump_offset", "dx");
- else if (bump == SHADER_BUMP_DY)
- compiler.parameter("bump_offset", "dy");
- else
- compiler.parameter("bump_offset", "center");
-
- if (Attribute::name_standard(attribute.c_str()) != ATTR_STD_NONE)
- compiler.parameter("name", (string("geom:") + attribute.c_str()).c_str());
- else
- compiler.parameter("name", attribute.c_str());
-
- compiler.add(this, "node_attribute");
-}
-
-/* Camera */
-
-NODE_DEFINE(CameraNode)
-{
- NodeType *type = NodeType::add("camera_info", create, NodeType::SHADER);
-
- SOCKET_OUT_VECTOR(view_vector, "View Vector");
- SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth");
- SOCKET_OUT_FLOAT(view_distance, "View Distance");
-
- return type;
-}
-
-CameraNode::CameraNode() : ShaderNode(get_node_type())
-{
-}
-
-void CameraNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *vector_out = output("View Vector");
- ShaderOutput *z_depth_out = output("View Z Depth");
- ShaderOutput *distance_out = output("View Distance");
-
- compiler.add_node(NODE_CAMERA,
- compiler.stack_assign(vector_out),
- compiler.stack_assign(z_depth_out),
- compiler.stack_assign(distance_out));
-}
-
-void CameraNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_camera");
-}
-
-/* Fresnel */
-
-NODE_DEFINE(FresnelNode)
-{
- NodeType *type = NodeType::add("fresnel", create, NodeType::SHADER);
-
- SOCKET_IN_NORMAL(
- normal, "Normal", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
- SOCKET_IN_FLOAT(IOR, "IOR", 1.45f);
-
- SOCKET_OUT_FLOAT(fac, "Fac");
-
- return type;
-}
-
-FresnelNode::FresnelNode() : ShaderNode(get_node_type())
-{
-}
-
-void FresnelNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *normal_in = input("Normal");
- ShaderInput *IOR_in = input("IOR");
- ShaderOutput *fac_out = output("Fac");
-
- compiler.add_node(NODE_FRESNEL,
- compiler.stack_assign(IOR_in),
- __float_as_int(IOR),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(normal_in),
- compiler.stack_assign(fac_out)));
-}
-
-void FresnelNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_fresnel");
-}
-
-/* Layer Weight */
-
-NODE_DEFINE(LayerWeightNode)
-{
- NodeType *type = NodeType::add("layer_weight", create, NodeType::SHADER);
-
- SOCKET_IN_NORMAL(
- normal, "Normal", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
- SOCKET_IN_FLOAT(blend, "Blend", 0.5f);
-
- SOCKET_OUT_FLOAT(fresnel, "Fresnel");
- SOCKET_OUT_FLOAT(facing, "Facing");
-
- return type;
-}
-
-LayerWeightNode::LayerWeightNode() : ShaderNode(get_node_type())
-{
-}
-
-void LayerWeightNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *normal_in = input("Normal");
- ShaderInput *blend_in = input("Blend");
- ShaderOutput *fresnel_out = output("Fresnel");
- ShaderOutput *facing_out = output("Facing");
-
- if (!fresnel_out->links.empty()) {
- compiler.add_node(NODE_LAYER_WEIGHT,
- compiler.stack_assign_if_linked(blend_in),
- __float_as_int(blend),
- compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL,
- compiler.stack_assign_if_linked(normal_in),
- compiler.stack_assign(fresnel_out)));
- }
-
- if (!facing_out->links.empty()) {
- compiler.add_node(NODE_LAYER_WEIGHT,
- compiler.stack_assign_if_linked(blend_in),
- __float_as_int(blend),
- compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING,
- compiler.stack_assign_if_linked(normal_in),
- compiler.stack_assign(facing_out)));
- }
-}
-
-void LayerWeightNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_layer_weight");
-}
-
-/* Wireframe */
-
-NODE_DEFINE(WireframeNode)
-{
- NodeType *type = NodeType::add("wireframe", create, NodeType::SHADER);
-
- SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false);
- SOCKET_IN_FLOAT(size, "Size", 0.01f);
- SOCKET_OUT_FLOAT(fac, "Fac");
-
- return type;
-}
-
-WireframeNode::WireframeNode() : ShaderNode(get_node_type())
-{
-}
-
-void WireframeNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *size_in = input("Size");
- ShaderOutput *fac_out = output("Fac");
- NodeBumpOffset bump_offset = NODE_BUMP_OFFSET_CENTER;
- if (bump == SHADER_BUMP_DX) {
- bump_offset = NODE_BUMP_OFFSET_DX;
- }
- else if (bump == SHADER_BUMP_DY) {
- bump_offset = NODE_BUMP_OFFSET_DY;
- }
- compiler.add_node(NODE_WIREFRAME,
- compiler.stack_assign(size_in),
- compiler.stack_assign(fac_out),
- compiler.encode_uchar4(use_pixel_size, bump_offset, 0, 0));
-}
-
-void WireframeNode::compile(OSLCompiler &compiler)
-{
- if (bump == SHADER_BUMP_DX) {
- compiler.parameter("bump_offset", "dx");
- }
- else if (bump == SHADER_BUMP_DY) {
- compiler.parameter("bump_offset", "dy");
- }
- else {
- compiler.parameter("bump_offset", "center");
- }
- compiler.parameter(this, "use_pixel_size");
- compiler.add(this, "node_wireframe");
-}
-
-/* Wavelength */
-
-NODE_DEFINE(WavelengthNode)
-{
- NodeType *type = NodeType::add("wavelength", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f);
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-WavelengthNode::WavelengthNode() : ShaderNode(get_node_type())
-{
-}
-
-void WavelengthNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *wavelength_in = input("Wavelength");
- ShaderOutput *color_out = output("Color");
-
- compiler.add_node(
- NODE_WAVELENGTH, compiler.stack_assign(wavelength_in), compiler.stack_assign(color_out));
-}
-
-void WavelengthNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_wavelength");
-}
-
-/* Blackbody */
-
-NODE_DEFINE(BlackbodyNode)
-{
- NodeType *type = NodeType::add("blackbody", create, NodeType::SHADER);
-
- SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f);
- SOCKET_OUT_COLOR(color, "Color");
-
- return type;
-}
-
-BlackbodyNode::BlackbodyNode() : ShaderNode(get_node_type())
-{
-}
-
-void BlackbodyNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- folder.make_constant(svm_math_blackbody_color(temperature));
- }
-}
-
-void BlackbodyNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *temperature_in = input("Temperature");
- ShaderOutput *color_out = output("Color");
-
- compiler.add_node(
- NODE_BLACKBODY, compiler.stack_assign(temperature_in), compiler.stack_assign(color_out));
-}
-
-void BlackbodyNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_blackbody");
-}
-
-/* Output */
-
-NODE_DEFINE(OutputNode)
-{
- NodeType *type = NodeType::add("output", create, NodeType::SHADER);
-
- SOCKET_IN_CLOSURE(surface, "Surface");
- SOCKET_IN_CLOSURE(volume, "Volume");
- SOCKET_IN_VECTOR(displacement, "Displacement", zero_float3());
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3());
-
- return type;
-}
-
-OutputNode::OutputNode() : ShaderNode(get_node_type())
-{
- special_type = SHADER_SPECIAL_TYPE_OUTPUT;
-}
-
-void OutputNode::compile(SVMCompiler &compiler)
-{
- if (compiler.output_type() == SHADER_TYPE_DISPLACEMENT) {
- ShaderInput *displacement_in = input("Displacement");
-
- if (displacement_in->link) {
- compiler.add_node(NODE_SET_DISPLACEMENT, compiler.stack_assign(displacement_in));
- }
- }
-}
-
-void OutputNode::compile(OSLCompiler &compiler)
-{
- if (compiler.output_type() == SHADER_TYPE_SURFACE)
- compiler.add(this, "node_output_surface");
- else if (compiler.output_type() == SHADER_TYPE_VOLUME)
- compiler.add(this, "node_output_volume");
- else if (compiler.output_type() == SHADER_TYPE_DISPLACEMENT)
- compiler.add(this, "node_output_displacement");
-}
-
-/* Map Range Node */
-
-NODE_DEFINE(MapRangeNode)
-{
- NodeType *type = NodeType::add("map_range", create, NodeType::SHADER);
-
- static NodeEnum type_enum;
- type_enum.insert("linear", NODE_MAP_RANGE_LINEAR);
- type_enum.insert("stepped", NODE_MAP_RANGE_STEPPED);
- type_enum.insert("smoothstep", NODE_MAP_RANGE_SMOOTHSTEP);
- type_enum.insert("smootherstep", NODE_MAP_RANGE_SMOOTHERSTEP);
- SOCKET_ENUM(range_type, "Type", type_enum, NODE_MAP_RANGE_LINEAR);
-
- SOCKET_IN_FLOAT(value, "Value", 1.0f);
- SOCKET_IN_FLOAT(from_min, "From Min", 0.0f);
- SOCKET_IN_FLOAT(from_max, "From Max", 1.0f);
- SOCKET_IN_FLOAT(to_min, "To Min", 0.0f);
- SOCKET_IN_FLOAT(to_max, "To Max", 1.0f);
- SOCKET_IN_FLOAT(steps, "Steps", 4.0f);
- SOCKET_IN_BOOLEAN(clamp, "Clamp", false);
-
- SOCKET_OUT_FLOAT(result, "Result");
-
- return type;
-}
-
-MapRangeNode::MapRangeNode() : ShaderNode(get_node_type())
-{
-}
-
-void MapRangeNode::expand(ShaderGraph *graph)
-{
- if (clamp) {
- ShaderOutput *result_out = output("Result");
- if (!result_out->links.empty()) {
- ClampNode *clamp_node = graph->create_node<ClampNode>();
- clamp_node->set_clamp_type(NODE_CLAMP_RANGE);
- graph->add(clamp_node);
- graph->relink(result_out, clamp_node->output("Result"));
- graph->connect(result_out, clamp_node->input("Value"));
- if (input("To Min")->link) {
- graph->connect(input("To Min")->link, clamp_node->input("Min"));
- }
- else {
- clamp_node->set_min(to_min);
- }
- if (input("To Max")->link) {
- graph->connect(input("To Max")->link, clamp_node->input("Max"));
- }
- else {
- clamp_node->set_max(to_max);
- }
- }
- }
-}
-
-void MapRangeNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *value_in = input("Value");
- ShaderInput *from_min_in = input("From Min");
- ShaderInput *from_max_in = input("From Max");
- ShaderInput *to_min_in = input("To Min");
- ShaderInput *to_max_in = input("To Max");
- ShaderInput *steps_in = input("Steps");
- ShaderOutput *result_out = output("Result");
-
- int value_stack_offset = compiler.stack_assign(value_in);
- int from_min_stack_offset = compiler.stack_assign_if_linked(from_min_in);
- int from_max_stack_offset = compiler.stack_assign_if_linked(from_max_in);
- int to_min_stack_offset = compiler.stack_assign_if_linked(to_min_in);
- int to_max_stack_offset = compiler.stack_assign_if_linked(to_max_in);
- int steps_stack_offset = compiler.stack_assign(steps_in);
- int result_stack_offset = compiler.stack_assign(result_out);
-
- compiler.add_node(
- NODE_MAP_RANGE,
- value_stack_offset,
- compiler.encode_uchar4(
- from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset),
- compiler.encode_uchar4(range_type, steps_stack_offset, result_stack_offset));
-
- compiler.add_node(__float_as_int(from_min),
- __float_as_int(from_max),
- __float_as_int(to_min),
- __float_as_int(to_max));
- compiler.add_node(__float_as_int(steps));
-}
-
-void MapRangeNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "range_type");
- compiler.add(this, "node_map_range");
-}
-
-/* Clamp Node */
-
-NODE_DEFINE(ClampNode)
-{
- NodeType *type = NodeType::add("clamp", create, NodeType::SHADER);
-
- static NodeEnum type_enum;
- type_enum.insert("minmax", NODE_CLAMP_MINMAX);
- type_enum.insert("range", NODE_CLAMP_RANGE);
- SOCKET_ENUM(clamp_type, "Type", type_enum, NODE_CLAMP_MINMAX);
-
- SOCKET_IN_FLOAT(value, "Value", 1.0f);
- SOCKET_IN_FLOAT(min, "Min", 0.0f);
- SOCKET_IN_FLOAT(max, "Max", 1.0f);
-
- SOCKET_OUT_FLOAT(result, "Result");
-
- return type;
-}
-
-ClampNode::ClampNode() : ShaderNode(get_node_type())
-{
-}
-
-void ClampNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- if (clamp_type == NODE_CLAMP_RANGE && (min > max)) {
- folder.make_constant(clamp(value, max, min));
- }
- else {
- folder.make_constant(clamp(value, min, max));
- }
- }
-}
-
-void ClampNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *value_in = input("Value");
- ShaderInput *min_in = input("Min");
- ShaderInput *max_in = input("Max");
- ShaderOutput *result_out = output("Result");
-
- int value_stack_offset = compiler.stack_assign(value_in);
- int min_stack_offset = compiler.stack_assign(min_in);
- int max_stack_offset = compiler.stack_assign(max_in);
- int result_stack_offset = compiler.stack_assign(result_out);
-
- compiler.add_node(NODE_CLAMP,
- value_stack_offset,
- compiler.encode_uchar4(min_stack_offset, max_stack_offset, clamp_type),
- result_stack_offset);
- compiler.add_node(__float_as_int(min), __float_as_int(max));
-}
-
-void ClampNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "clamp_type");
- compiler.add(this, "node_clamp");
-}
-
-/* AOV Output */
-
-NODE_DEFINE(OutputAOVNode)
-{
- NodeType *type = NodeType::add("aov_output", create, NodeType::SHADER);
-
- SOCKET_IN_COLOR(color, "Color", zero_float3());
- SOCKET_IN_FLOAT(value, "Value", 0.0f);
-
- SOCKET_STRING(name, "AOV Name", ustring(""));
-
- return type;
-}
-
-OutputAOVNode::OutputAOVNode() : ShaderNode(get_node_type())
-{
- special_type = SHADER_SPECIAL_TYPE_OUTPUT_AOV;
- offset = -1;
-}
-
-void OutputAOVNode::simplify_settings(Scene *scene)
-{
- offset = scene->film->get_aov_offset(scene, name.string(), is_color);
- if (offset == -1) {
- offset = scene->film->get_aov_offset(scene, name.string(), is_color);
- }
-
- if (offset == -1 || is_color) {
- input("Value")->disconnect();
- }
- if (offset == -1 || !is_color) {
- input("Color")->disconnect();
- }
-}
-
-void OutputAOVNode::compile(SVMCompiler &compiler)
-{
- assert(offset >= 0);
-
- if (is_color) {
- compiler.add_node(NODE_AOV_COLOR, compiler.stack_assign(input("Color")), offset);
- }
- else {
- compiler.add_node(NODE_AOV_VALUE, compiler.stack_assign(input("Value")), offset);
- }
-}
-
-void OutputAOVNode::compile(OSLCompiler & /*compiler*/)
-{
- /* TODO */
-}
-
-/* Math */
-
-NODE_DEFINE(MathNode)
-{
- NodeType *type = NodeType::add("math", create, NodeType::SHADER);
-
- static NodeEnum type_enum;
- type_enum.insert("add", NODE_MATH_ADD);
- type_enum.insert("subtract", NODE_MATH_SUBTRACT);
- type_enum.insert("multiply", NODE_MATH_MULTIPLY);
- type_enum.insert("divide", NODE_MATH_DIVIDE);
- type_enum.insert("multiply_add", NODE_MATH_MULTIPLY_ADD);
- type_enum.insert("sine", NODE_MATH_SINE);
- type_enum.insert("cosine", NODE_MATH_COSINE);
- type_enum.insert("tangent", NODE_MATH_TANGENT);
- type_enum.insert("sinh", NODE_MATH_SINH);
- type_enum.insert("cosh", NODE_MATH_COSH);
- type_enum.insert("tanh", NODE_MATH_TANH);
- type_enum.insert("arcsine", NODE_MATH_ARCSINE);
- type_enum.insert("arccosine", NODE_MATH_ARCCOSINE);
- type_enum.insert("arctangent", NODE_MATH_ARCTANGENT);
- type_enum.insert("power", NODE_MATH_POWER);
- type_enum.insert("logarithm", NODE_MATH_LOGARITHM);
- type_enum.insert("minimum", NODE_MATH_MINIMUM);
- type_enum.insert("maximum", NODE_MATH_MAXIMUM);
- type_enum.insert("round", NODE_MATH_ROUND);
- type_enum.insert("less_than", NODE_MATH_LESS_THAN);
- type_enum.insert("greater_than", NODE_MATH_GREATER_THAN);
- type_enum.insert("modulo", NODE_MATH_MODULO);
- type_enum.insert("absolute", NODE_MATH_ABSOLUTE);
- type_enum.insert("arctan2", NODE_MATH_ARCTAN2);
- type_enum.insert("floor", NODE_MATH_FLOOR);
- type_enum.insert("ceil", NODE_MATH_CEIL);
- type_enum.insert("fraction", NODE_MATH_FRACTION);
- type_enum.insert("trunc", NODE_MATH_TRUNC);
- type_enum.insert("snap", NODE_MATH_SNAP);
- type_enum.insert("wrap", NODE_MATH_WRAP);
- type_enum.insert("pingpong", NODE_MATH_PINGPONG);
- type_enum.insert("sqrt", NODE_MATH_SQRT);
- type_enum.insert("inversesqrt", NODE_MATH_INV_SQRT);
- type_enum.insert("sign", NODE_MATH_SIGN);
- type_enum.insert("exponent", NODE_MATH_EXPONENT);
- type_enum.insert("radians", NODE_MATH_RADIANS);
- type_enum.insert("degrees", NODE_MATH_DEGREES);
- type_enum.insert("smoothmin", NODE_MATH_SMOOTH_MIN);
- type_enum.insert("smoothmax", NODE_MATH_SMOOTH_MAX);
- type_enum.insert("compare", NODE_MATH_COMPARE);
- SOCKET_ENUM(math_type, "Type", type_enum, NODE_MATH_ADD);
-
- SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
-
- SOCKET_IN_FLOAT(value1, "Value1", 0.5f);
- SOCKET_IN_FLOAT(value2, "Value2", 0.5f);
- SOCKET_IN_FLOAT(value3, "Value3", 0.0f);
-
- SOCKET_OUT_FLOAT(value, "Value");
-
- return type;
-}
-
-MathNode::MathNode() : ShaderNode(get_node_type())
-{
-}
-
-void MathNode::expand(ShaderGraph *graph)
-{
- if (use_clamp) {
- ShaderOutput *result_out = output("Value");
- if (!result_out->links.empty()) {
- ClampNode *clamp_node = graph->create_node<ClampNode>();
- clamp_node->set_clamp_type(NODE_CLAMP_MINMAX);
- clamp_node->set_min(0.0f);
- clamp_node->set_max(1.0f);
- graph->add(clamp_node);
- graph->relink(result_out, clamp_node->output("Result"));
- graph->connect(result_out, clamp_node->input("Value"));
- }
- }
-}
-
-void MathNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- folder.make_constant(svm_math(math_type, value1, value2, value3));
- }
- else {
- folder.fold_math(math_type);
- }
-}
-
-void MathNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *value1_in = input("Value1");
- ShaderInput *value2_in = input("Value2");
- ShaderInput *value3_in = input("Value3");
- ShaderOutput *value_out = output("Value");
-
- int value1_stack_offset = compiler.stack_assign(value1_in);
- int value2_stack_offset = compiler.stack_assign(value2_in);
- int value3_stack_offset = compiler.stack_assign(value3_in);
- int value_stack_offset = compiler.stack_assign(value_out);
-
- compiler.add_node(
- NODE_MATH,
- math_type,
- compiler.encode_uchar4(value1_stack_offset, value2_stack_offset, value3_stack_offset),
- value_stack_offset);
-}
-
-void MathNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "math_type");
- compiler.add(this, "node_math");
-}
-
-/* VectorMath */
-
-NODE_DEFINE(VectorMathNode)
-{
- NodeType *type = NodeType::add("vector_math", create, NodeType::SHADER);
-
- static NodeEnum type_enum;
- type_enum.insert("add", NODE_VECTOR_MATH_ADD);
- type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT);
- type_enum.insert("multiply", NODE_VECTOR_MATH_MULTIPLY);
- type_enum.insert("divide", NODE_VECTOR_MATH_DIVIDE);
-
- type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT);
- type_enum.insert("project", NODE_VECTOR_MATH_PROJECT);
- type_enum.insert("reflect", NODE_VECTOR_MATH_REFLECT);
- type_enum.insert("refract", NODE_VECTOR_MATH_REFRACT);
- type_enum.insert("faceforward", NODE_VECTOR_MATH_FACEFORWARD);
- type_enum.insert("multiply_add", NODE_VECTOR_MATH_MULTIPLY_ADD);
-
- type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
-
- type_enum.insert("distance", NODE_VECTOR_MATH_DISTANCE);
- type_enum.insert("length", NODE_VECTOR_MATH_LENGTH);
- type_enum.insert("scale", NODE_VECTOR_MATH_SCALE);
- type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE);
-
- type_enum.insert("snap", NODE_VECTOR_MATH_SNAP);
- type_enum.insert("floor", NODE_VECTOR_MATH_FLOOR);
- type_enum.insert("ceil", NODE_VECTOR_MATH_CEIL);
- type_enum.insert("modulo", NODE_VECTOR_MATH_MODULO);
- type_enum.insert("wrap", NODE_VECTOR_MATH_WRAP);
- type_enum.insert("fraction", NODE_VECTOR_MATH_FRACTION);
- type_enum.insert("absolute", NODE_VECTOR_MATH_ABSOLUTE);
- type_enum.insert("minimum", NODE_VECTOR_MATH_MINIMUM);
- type_enum.insert("maximum", NODE_VECTOR_MATH_MAXIMUM);
-
- type_enum.insert("sine", NODE_VECTOR_MATH_SINE);
- type_enum.insert("cosine", NODE_VECTOR_MATH_COSINE);
- type_enum.insert("tangent", NODE_VECTOR_MATH_TANGENT);
- SOCKET_ENUM(math_type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
-
- SOCKET_IN_VECTOR(vector1, "Vector1", zero_float3());
- SOCKET_IN_VECTOR(vector2, "Vector2", zero_float3());
- SOCKET_IN_VECTOR(vector3, "Vector3", zero_float3());
- SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
-
- SOCKET_OUT_FLOAT(value, "Value");
- SOCKET_OUT_VECTOR(vector, "Vector");
-
- return type;
-}
-
-VectorMathNode::VectorMathNode() : ShaderNode(get_node_type())
-{
-}
-
-void VectorMathNode::constant_fold(const ConstantFolder &folder)
-{
- float value = 0.0f;
- float3 vector = zero_float3();
-
- if (folder.all_inputs_constant()) {
- svm_vector_math(&value, &vector, math_type, vector1, vector2, vector3, scale);
- if (folder.output == output("Value")) {
- folder.make_constant(value);
- }
- else if (folder.output == output("Vector")) {
- folder.make_constant(vector);
- }
- }
- else {
- folder.fold_vector_math(math_type);
- }
-}
-
-void VectorMathNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector1_in = input("Vector1");
- ShaderInput *vector2_in = input("Vector2");
- ShaderInput *param1_in = input("Scale");
- ShaderOutput *value_out = output("Value");
- ShaderOutput *vector_out = output("Vector");
-
- int vector1_stack_offset = compiler.stack_assign(vector1_in);
- int vector2_stack_offset = compiler.stack_assign(vector2_in);
- int param1_stack_offset = compiler.stack_assign(param1_in);
- int value_stack_offset = compiler.stack_assign_if_linked(value_out);
- int vector_stack_offset = compiler.stack_assign_if_linked(vector_out);
-
- /* 3 Vector Operators */
- if (math_type == NODE_VECTOR_MATH_WRAP || math_type == NODE_VECTOR_MATH_FACEFORWARD ||
- math_type == NODE_VECTOR_MATH_MULTIPLY_ADD) {
- ShaderInput *vector3_in = input("Vector3");
- int vector3_stack_offset = compiler.stack_assign(vector3_in);
- compiler.add_node(
- NODE_VECTOR_MATH,
- math_type,
- compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, param1_stack_offset),
- compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
- compiler.add_node(vector3_stack_offset);
- }
- else {
- compiler.add_node(
- NODE_VECTOR_MATH,
- math_type,
- compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, param1_stack_offset),
- compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
- }
-}
-
-void VectorMathNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "math_type");
- compiler.add(this, "node_vector_math");
-}
-
-/* Vector Rotate */
-
-NODE_DEFINE(VectorRotateNode)
-{
- NodeType *type = NodeType::add("vector_rotate", create, NodeType::SHADER);
-
- static NodeEnum type_enum;
- type_enum.insert("axis", NODE_VECTOR_ROTATE_TYPE_AXIS);
- type_enum.insert("x_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_X);
- type_enum.insert("y_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_Y);
- type_enum.insert("z_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_Z);
- type_enum.insert("euler_xyz", NODE_VECTOR_ROTATE_TYPE_EULER_XYZ);
- SOCKET_ENUM(rotate_type, "Type", type_enum, NODE_VECTOR_ROTATE_TYPE_AXIS);
-
- SOCKET_BOOLEAN(invert, "Invert", false);
-
- SOCKET_IN_VECTOR(vector, "Vector", zero_float3());
- SOCKET_IN_POINT(rotation, "Rotation", zero_float3());
- SOCKET_IN_POINT(center, "Center", zero_float3());
- SOCKET_IN_VECTOR(axis, "Axis", make_float3(0.0f, 0.0f, 1.0f));
- SOCKET_IN_FLOAT(angle, "Angle", 0.0f);
- SOCKET_OUT_VECTOR(vector, "Vector");
-
- return type;
-}
-
-VectorRotateNode::VectorRotateNode() : ShaderNode(get_node_type())
-{
-}
-
-void VectorRotateNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *rotation_in = input("Rotation");
- ShaderInput *center_in = input("Center");
- ShaderInput *axis_in = input("Axis");
- ShaderInput *angle_in = input("Angle");
- ShaderOutput *vector_out = output("Vector");
-
- compiler.add_node(NODE_VECTOR_ROTATE,
- compiler.encode_uchar4(rotate_type,
- compiler.stack_assign(vector_in),
- compiler.stack_assign(rotation_in),
- invert),
- compiler.encode_uchar4(compiler.stack_assign(center_in),
- compiler.stack_assign(axis_in),
- compiler.stack_assign(angle_in)),
- compiler.stack_assign(vector_out));
-}
-
-void VectorRotateNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "rotate_type");
- compiler.parameter(this, "invert");
- compiler.add(this, "node_vector_rotate");
-}
-
-/* VectorTransform */
-
-NODE_DEFINE(VectorTransformNode)
-{
- NodeType *type = NodeType::add("vector_transform", create, NodeType::SHADER);
-
- static NodeEnum type_enum;
- type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
- type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
- type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
- SOCKET_ENUM(transform_type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
-
- static NodeEnum space_enum;
- space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
- space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
- space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA);
- SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
- SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
-
- SOCKET_IN_VECTOR(vector, "Vector", zero_float3());
- SOCKET_OUT_VECTOR(vector, "Vector");
-
- return type;
-}
-
-VectorTransformNode::VectorTransformNode() : ShaderNode(get_node_type())
-{
-}
-
-void VectorTransformNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderOutput *vector_out = output("Vector");
-
- compiler.add_node(
- NODE_VECTOR_TRANSFORM,
- compiler.encode_uchar4(transform_type, convert_from, convert_to),
- compiler.encode_uchar4(compiler.stack_assign(vector_in), compiler.stack_assign(vector_out)));
-}
-
-void VectorTransformNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "transform_type");
- compiler.parameter(this, "convert_from");
- compiler.parameter(this, "convert_to");
- compiler.add(this, "node_vector_transform");
-}
-
-/* BumpNode */
-
-NODE_DEFINE(BumpNode)
-{
- NodeType *type = NodeType::add("bump", create, NodeType::SHADER);
-
- SOCKET_BOOLEAN(invert, "Invert", false);
- SOCKET_BOOLEAN(use_object_space, "UseObjectSpace", false);
-
- /* this input is used by the user, but after graph transform it is no longer
- * used and moved to sampler center/x/y instead */
- SOCKET_IN_FLOAT(height, "Height", 1.0f);
-
- SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f);
- SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f);
- SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f);
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
- SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
- SOCKET_IN_FLOAT(distance, "Distance", 0.1f);
-
- SOCKET_OUT_NORMAL(normal, "Normal");
-
- return type;
-}
-
-BumpNode::BumpNode() : ShaderNode(get_node_type())
-{
- special_type = SHADER_SPECIAL_TYPE_BUMP;
-}
-
-void BumpNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *center_in = input("SampleCenter");
- ShaderInput *dx_in = input("SampleX");
- ShaderInput *dy_in = input("SampleY");
- ShaderInput *normal_in = input("Normal");
- ShaderInput *strength_in = input("Strength");
- ShaderInput *distance_in = input("Distance");
- ShaderOutput *normal_out = output("Normal");
-
- /* pack all parameters in the node */
- compiler.add_node(NODE_SET_BUMP,
- compiler.encode_uchar4(compiler.stack_assign_if_linked(normal_in),
- compiler.stack_assign(distance_in),
- invert,
- use_object_space),
- compiler.encode_uchar4(compiler.stack_assign(center_in),
- compiler.stack_assign(dx_in),
- compiler.stack_assign(dy_in),
- compiler.stack_assign(strength_in)),
- compiler.stack_assign(normal_out));
-}
-
-void BumpNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "invert");
- compiler.parameter(this, "use_object_space");
- compiler.add(this, "node_bump");
-}
-
-void BumpNode::constant_fold(const ConstantFolder &folder)
-{
- ShaderInput *height_in = input("Height");
- ShaderInput *normal_in = input("Normal");
-
- if (height_in->link == NULL) {
- if (normal_in->link == NULL) {
- GeometryNode *geom = folder.graph->create_node<GeometryNode>();
- folder.graph->add(geom);
- folder.bypass(geom->output("Normal"));
- }
- else {
- folder.bypass(normal_in->link);
- }
- }
-
- /* TODO(sergey): Ignore bump with zero strength. */
-}
-
-/* Curves node */
-
-CurvesNode::CurvesNode(const NodeType *node_type) : ShaderNode(node_type)
-{
-}
-
-void CurvesNode::constant_fold(const ConstantFolder &folder, ShaderInput *value_in)
-{
- ShaderInput *fac_in = input("Fac");
-
- /* evaluate fully constant node */
- if (folder.all_inputs_constant()) {
- if (curves.size() == 0) {
- return;
- }
-
- float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x);
- float3 result;
-
- result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x;
- result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y;
- result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z;
-
- folder.make_constant(interp(value, result, fac));
- }
- /* remove no-op node */
- else if (!fac_in->link && fac == 0.0f) {
- /* link is not null because otherwise all inputs are constant */
- folder.bypass(value_in->link);
- }
-}
-
-void CurvesNode::compile(SVMCompiler &compiler,
- int type,
- ShaderInput *value_in,
- ShaderOutput *value_out)
-{
- if (curves.size() == 0)
- return;
-
- ShaderInput *fac_in = input("Fac");
-
- compiler.add_node(type,
- compiler.encode_uchar4(compiler.stack_assign(fac_in),
- compiler.stack_assign(value_in),
- compiler.stack_assign(value_out)),
- __float_as_int(min_x),
- __float_as_int(max_x));
-
- compiler.add_node(curves.size());
- for (int i = 0; i < curves.size(); i++)
- compiler.add_node(float3_to_float4(curves[i]));
-}
-
-void CurvesNode::compile(OSLCompiler &compiler, const char *name)
-{
- if (curves.size() == 0)
- return;
-
- compiler.parameter_color_array("ramp", curves);
- compiler.parameter(this, "min_x");
- compiler.parameter(this, "max_x");
- compiler.add(this, name);
-}
-
-void CurvesNode::compile(SVMCompiler & /*compiler*/)
-{
- assert(0);
-}
-
-void CurvesNode::compile(OSLCompiler & /*compiler*/)
-{
- assert(0);
-}
-
-/* RGBCurvesNode */
-
-NODE_DEFINE(RGBCurvesNode)
-{
- NodeType *type = NodeType::add("rgb_curves", create, NodeType::SHADER);
-
- SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>());
- SOCKET_FLOAT(min_x, "Min X", 0.0f);
- SOCKET_FLOAT(max_x, "Max X", 1.0f);
-
- SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
- SOCKET_IN_COLOR(value, "Color", zero_float3());
-
- SOCKET_OUT_COLOR(value, "Color");
-
- return type;
-}
-
-RGBCurvesNode::RGBCurvesNode() : CurvesNode(get_node_type())
-{
-}
-
-void RGBCurvesNode::constant_fold(const ConstantFolder &folder)
-{
- CurvesNode::constant_fold(folder, input("Color"));
-}
-
-void RGBCurvesNode::compile(SVMCompiler &compiler)
-{
- CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color"));
-}
-
-void RGBCurvesNode::compile(OSLCompiler &compiler)
-{
- CurvesNode::compile(compiler, "node_rgb_curves");
-}
-
-/* VectorCurvesNode */
-
-NODE_DEFINE(VectorCurvesNode)
-{
- NodeType *type = NodeType::add("vector_curves", create, NodeType::SHADER);
-
- SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>());
- SOCKET_FLOAT(min_x, "Min X", 0.0f);
- SOCKET_FLOAT(max_x, "Max X", 1.0f);
-
- SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
- SOCKET_IN_VECTOR(value, "Vector", zero_float3());
-
- SOCKET_OUT_VECTOR(value, "Vector");
-
- return type;
-}
-
-VectorCurvesNode::VectorCurvesNode() : CurvesNode(get_node_type())
-{
-}
-
-void VectorCurvesNode::constant_fold(const ConstantFolder &folder)
-{
- CurvesNode::constant_fold(folder, input("Vector"));
-}
-
-void VectorCurvesNode::compile(SVMCompiler &compiler)
-{
- CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector"));
-}
-
-void VectorCurvesNode::compile(OSLCompiler &compiler)
-{
- CurvesNode::compile(compiler, "node_vector_curves");
-}
-
-/* FloatCurveNode */
-
-NODE_DEFINE(FloatCurveNode)
-{
- NodeType *type = NodeType::add("float_curve", create, NodeType::SHADER);
-
- SOCKET_FLOAT_ARRAY(curve, "Curve", array<float>());
- SOCKET_FLOAT(min_x, "Min X", 0.0f);
- SOCKET_FLOAT(max_x, "Max X", 1.0f);
-
- SOCKET_IN_FLOAT(fac, "Factor", 0.0f);
- SOCKET_IN_FLOAT(value, "Value", 0.0f);
-
- SOCKET_OUT_FLOAT(value, "Value");
-
- return type;
-}
-
-FloatCurveNode::FloatCurveNode() : ShaderNode(get_node_type())
-{
-}
-
-void FloatCurveNode::constant_fold(const ConstantFolder &folder)
-{
- ShaderInput *value_in = input("Value");
- ShaderInput *fac_in = input("Factor");
-
- /* evaluate fully constant node */
- if (folder.all_inputs_constant()) {
- if (curve.size() == 0) {
- return;
- }
-
- float pos = (value - min_x) / (max_x - min_x);
- float result = float_ramp_lookup(curve.data(), pos, true, true, curve.size());
-
- folder.make_constant(value + fac * (result - value));
- }
- /* remove no-op node */
- else if (!fac_in->link && fac == 0.0f) {
- /* link is not null because otherwise all inputs are constant */
- folder.bypass(value_in->link);
- }
-}
-
-void FloatCurveNode::compile(SVMCompiler &compiler)
-{
- if (curve.size() == 0)
- return;
-
- ShaderInput *value_in = input("Value");
- ShaderInput *fac_in = input("Factor");
- ShaderOutput *value_out = output("Value");
-
- compiler.add_node(NODE_FLOAT_CURVE,
- compiler.encode_uchar4(compiler.stack_assign(fac_in),
- compiler.stack_assign(value_in),
- compiler.stack_assign(value_out)),
- __float_as_int(min_x),
- __float_as_int(max_x));
-
- compiler.add_node(curve.size());
- for (int i = 0; i < curve.size(); i++)
- compiler.add_node(make_float4(curve[i]));
-}
-
-void FloatCurveNode::compile(OSLCompiler &compiler)
-{
- if (curve.size() == 0)
- return;
-
- compiler.parameter_array("ramp", curve.data(), curve.size());
- compiler.parameter(this, "min_x");
- compiler.parameter(this, "max_x");
- compiler.add(this, "node_float_curve");
-}
-
-/* RGBRampNode */
-
-NODE_DEFINE(RGBRampNode)
-{
- NodeType *type = NodeType::add("rgb_ramp", create, NodeType::SHADER);
-
- SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>());
- SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>());
- SOCKET_BOOLEAN(interpolate, "Interpolate", true);
-
- SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
-
- SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(alpha, "Alpha");
-
- return type;
-}
-
-RGBRampNode::RGBRampNode() : ShaderNode(get_node_type())
-{
-}
-
-void RGBRampNode::constant_fold(const ConstantFolder &folder)
-{
- if (ramp.size() == 0 || ramp.size() != ramp_alpha.size())
- return;
-
- if (folder.all_inputs_constant()) {
- float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1);
-
- /* clamp int as well in case of NaN */
- int i = clamp((int)f, 0, ramp.size() - 1);
- float t = f - (float)i;
-
- bool use_lerp = interpolate && t > 0.0f;
-
- if (folder.output == output("Color")) {
- float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size());
- folder.make_constant(color);
- }
- else if (folder.output == output("Alpha")) {
- float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size());
- folder.make_constant(alpha);
- }
- }
-}
-
-void RGBRampNode::compile(SVMCompiler &compiler)
-{
- if (ramp.size() == 0 || ramp.size() != ramp_alpha.size())
- return;
-
- ShaderInput *fac_in = input("Fac");
- ShaderOutput *color_out = output("Color");
- ShaderOutput *alpha_out = output("Alpha");
-
- compiler.add_node(NODE_RGB_RAMP,
- compiler.encode_uchar4(compiler.stack_assign(fac_in),
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(alpha_out)),
- interpolate);
-
- compiler.add_node(ramp.size());
- for (int i = 0; i < ramp.size(); i++)
- compiler.add_node(make_float4(ramp[i].x, ramp[i].y, ramp[i].z, ramp_alpha[i]));
-}
-
-void RGBRampNode::compile(OSLCompiler &compiler)
-{
- if (ramp.size() == 0 || ramp.size() != ramp_alpha.size())
- return;
-
- compiler.parameter_color_array("ramp_color", ramp);
- compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size());
- compiler.parameter(this, "interpolate");
-
- compiler.add(this, "node_rgb_ramp");
-}
-
-/* Set Normal Node */
-
-NODE_DEFINE(SetNormalNode)
-{
- NodeType *type = NodeType::add("set_normal", create, NodeType::SHADER);
-
- SOCKET_IN_VECTOR(direction, "Direction", zero_float3());
- SOCKET_OUT_NORMAL(normal, "Normal");
-
- return type;
-}
-
-SetNormalNode::SetNormalNode() : ShaderNode(get_node_type())
-{
-}
-
-void SetNormalNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *direction_in = input("Direction");
- ShaderOutput *normal_out = output("Normal");
-
- compiler.add_node(NODE_CLOSURE_SET_NORMAL,
- compiler.stack_assign(direction_in),
- compiler.stack_assign(normal_out));
-}
-
-void SetNormalNode::compile(OSLCompiler &compiler)
-{
- compiler.add(this, "node_set_normal");
-}
-
-/* OSLNode */
-
-OSLNode::OSLNode() : ShaderNode(new NodeType(NodeType::SHADER))
-{
- special_type = SHADER_SPECIAL_TYPE_OSL;
-}
-
-OSLNode::~OSLNode()
-{
- delete type;
-}
-
-ShaderNode *OSLNode::clone(ShaderGraph *graph) const
-{
- return OSLNode::create(graph, this->inputs.size(), this);
-}
-
-OSLNode *OSLNode::create(ShaderGraph *graph, size_t num_inputs, const OSLNode *from)
-{
- /* allocate space for the node itself and parameters, aligned to 16 bytes
- * assuming that's the most parameter types need */
- size_t node_size = align_up(sizeof(OSLNode), 16);
- size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
-
- char *node_memory = (char *)operator new(node_size + inputs_size);
- memset(node_memory, 0, node_size + inputs_size);
-
- if (!from) {
- OSLNode *node = new (node_memory) OSLNode();
- node->set_owner(graph);
- return node;
- }
- else {
- /* copy input default values and node type for cloning */
- memcpy(node_memory + node_size, (char *)from + node_size, inputs_size);
-
- OSLNode *node = new (node_memory) OSLNode(*from);
- node->type = new NodeType(*(from->type));
- node->set_owner(from->owner);
- return node;
- }
-}
-
-char *OSLNode::input_default_value()
-{
- /* pointer to default value storage, which is the same as our actual value */
- size_t num_inputs = type->inputs.size();
- size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
- return (char *)this + align_up(sizeof(OSLNode), 16) + inputs_size;
-}
-
-void OSLNode::add_input(ustring name, SocketType::Type socket_type)
-{
- char *memory = input_default_value();
- size_t offset = memory - (char *)this;
- const_cast<NodeType *>(type)->register_input(
- name, name, socket_type, offset, memory, NULL, NULL, SocketType::LINKABLE);
-}
-
-void OSLNode::add_output(ustring name, SocketType::Type socket_type)
-{
- const_cast<NodeType *>(type)->register_output(name, name, socket_type);
-}
-
-void OSLNode::compile(SVMCompiler &)
-{
- /* doesn't work for SVM, obviously ... */
-}
-
-void OSLNode::compile(OSLCompiler &compiler)
-{
- if (!filepath.empty())
- compiler.add(this, filepath.c_str(), true);
- else
- compiler.add(this, bytecode_hash.c_str(), false);
-}
-
-/* Normal Map */
-
-NODE_DEFINE(NormalMapNode)
-{
- NodeType *type = NodeType::add("normal_map", create, NodeType::SHADER);
-
- static NodeEnum space_enum;
- space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
- space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
- space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
- space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT);
- space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD);
- SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT);
-
- SOCKET_STRING(attribute, "Attribute", ustring());
-
- SOCKET_IN_NORMAL(
- normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
- SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
- SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f));
-
- SOCKET_OUT_NORMAL(normal, "Normal");
-
- return type;
-}
-
-NormalMapNode::NormalMapNode() : ShaderNode(get_node_type())
-{
-}
-
-void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) {
- if (attribute.empty()) {
- attributes->add(ATTR_STD_UV_TANGENT);
- attributes->add(ATTR_STD_UV_TANGENT_SIGN);
- }
- else {
- attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
- attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
- }
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void NormalMapNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *color_in = input("Color");
- ShaderInput *strength_in = input("Strength");
- ShaderOutput *normal_out = output("Normal");
- int attr = 0, attr_sign = 0;
-
- if (space == NODE_NORMAL_MAP_TANGENT) {
- if (attribute.empty()) {
- attr = compiler.attribute(ATTR_STD_UV_TANGENT);
- attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
- }
- else {
- attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
- attr_sign = compiler.attribute(
- ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
- }
- }
-
- compiler.add_node(NODE_NORMAL_MAP,
- compiler.encode_uchar4(compiler.stack_assign(color_in),
- compiler.stack_assign(strength_in),
- compiler.stack_assign(normal_out),
- space),
- attr,
- attr_sign);
-}
-
-void NormalMapNode::compile(OSLCompiler &compiler)
-{
- if (space == NODE_NORMAL_MAP_TANGENT) {
- if (attribute.empty()) {
- compiler.parameter("attr_name", ustring("geom:tangent"));
- compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
- }
- else {
- compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
- compiler.parameter("attr_sign_name",
- ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
- }
- }
-
- compiler.parameter(this, "space");
- compiler.add(this, "node_normal_map");
-}
-
-/* Tangent */
-
-NODE_DEFINE(TangentNode)
-{
- NodeType *type = NodeType::add("tangent", create, NodeType::SHADER);
-
- static NodeEnum direction_type_enum;
- direction_type_enum.insert("radial", NODE_TANGENT_RADIAL);
- direction_type_enum.insert("uv_map", NODE_TANGENT_UVMAP);
- SOCKET_ENUM(direction_type, "Direction Type", direction_type_enum, NODE_TANGENT_RADIAL);
-
- static NodeEnum axis_enum;
- axis_enum.insert("x", NODE_TANGENT_AXIS_X);
- axis_enum.insert("y", NODE_TANGENT_AXIS_Y);
- axis_enum.insert("z", NODE_TANGENT_AXIS_Z);
- SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X);
-
- SOCKET_STRING(attribute, "Attribute", ustring());
-
- SOCKET_IN_NORMAL(
- normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
- SOCKET_OUT_NORMAL(tangent, "Tangent");
-
- return type;
-}
-
-TangentNode::TangentNode() : ShaderNode(get_node_type())
-{
-}
-
-void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_surface_link()) {
- if (direction_type == NODE_TANGENT_UVMAP) {
- if (attribute.empty())
- attributes->add(ATTR_STD_UV_TANGENT);
- else
- attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
- }
- else
- attributes->add(ATTR_STD_GENERATED);
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void TangentNode::compile(SVMCompiler &compiler)
-{
- ShaderOutput *tangent_out = output("Tangent");
- int attr;
-
- if (direction_type == NODE_TANGENT_UVMAP) {
- if (attribute.empty())
- attr = compiler.attribute(ATTR_STD_UV_TANGENT);
- else
- attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
- }
- else
- attr = compiler.attribute(ATTR_STD_GENERATED);
-
- compiler.add_node(
- NODE_TANGENT,
- compiler.encode_uchar4(compiler.stack_assign(tangent_out), direction_type, axis),
- attr);
-}
-
-void TangentNode::compile(OSLCompiler &compiler)
-{
- if (direction_type == NODE_TANGENT_UVMAP) {
- if (attribute.empty())
- compiler.parameter("attr_name", ustring("geom:tangent"));
- else
- compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
- }
-
- compiler.parameter(this, "direction_type");
- compiler.parameter(this, "axis");
- compiler.add(this, "node_tangent");
-}
-
-/* Bevel */
-
-NODE_DEFINE(BevelNode)
-{
- NodeType *type = NodeType::add("bevel", create, NodeType::SHADER);
-
- SOCKET_INT(samples, "Samples", 4);
-
- SOCKET_IN_FLOAT(radius, "Radius", 0.05f);
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
-
- SOCKET_OUT_NORMAL(bevel, "Normal");
-
- return type;
-}
-
-BevelNode::BevelNode() : ShaderNode(get_node_type())
-{
-}
-
-void BevelNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *radius_in = input("Radius");
- ShaderInput *normal_in = input("Normal");
- ShaderOutput *normal_out = output("Normal");
-
- compiler.add_node(NODE_BEVEL,
- compiler.encode_uchar4(samples,
- compiler.stack_assign(radius_in),
- compiler.stack_assign_if_linked(normal_in),
- compiler.stack_assign(normal_out)));
-}
-
-void BevelNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "samples");
- compiler.add(this, "node_bevel");
-}
-
-/* Displacement */
-
-NODE_DEFINE(DisplacementNode)
-{
- NodeType *type = NodeType::add("displacement", create, NodeType::SHADER);
-
- static NodeEnum space_enum;
- space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
- space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
-
- SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_OBJECT);
-
- SOCKET_IN_FLOAT(height, "Height", 0.0f);
- SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.5f);
- SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
- SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
-
- SOCKET_OUT_VECTOR(displacement, "Displacement");
-
- return type;
-}
-
-DisplacementNode::DisplacementNode() : ShaderNode(get_node_type())
-{
-}
-
-void DisplacementNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- if ((height - midlevel == 0.0f) || (scale == 0.0f)) {
- folder.make_zero();
- }
- }
-}
-
-void DisplacementNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *height_in = input("Height");
- ShaderInput *midlevel_in = input("Midlevel");
- ShaderInput *scale_in = input("Scale");
- ShaderInput *normal_in = input("Normal");
- ShaderOutput *displacement_out = output("Displacement");
-
- compiler.add_node(NODE_DISPLACEMENT,
- compiler.encode_uchar4(compiler.stack_assign(height_in),
- compiler.stack_assign(midlevel_in),
- compiler.stack_assign(scale_in),
- compiler.stack_assign_if_linked(normal_in)),
- compiler.stack_assign(displacement_out),
- space);
-}
-
-void DisplacementNode::compile(OSLCompiler &compiler)
-{
- compiler.parameter(this, "space");
- compiler.add(this, "node_displacement");
-}
-
-/* Vector Displacement */
-
-NODE_DEFINE(VectorDisplacementNode)
-{
- NodeType *type = NodeType::add("vector_displacement", create, NodeType::SHADER);
-
- static NodeEnum space_enum;
- space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
- space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
- space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
-
- SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT);
- SOCKET_STRING(attribute, "Attribute", ustring());
-
- SOCKET_IN_COLOR(vector, "Vector", zero_float3());
- SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.0f);
- SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
-
- SOCKET_OUT_VECTOR(displacement, "Displacement");
-
- return type;
-}
-
-VectorDisplacementNode::VectorDisplacementNode() : ShaderNode(get_node_type())
-{
-}
-
-void VectorDisplacementNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- if ((vector == zero_float3() && midlevel == 0.0f) || (scale == 0.0f)) {
- folder.make_zero();
- }
- }
-}
-
-void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *attributes)
-{
- if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) {
- if (attribute.empty()) {
- attributes->add(ATTR_STD_UV_TANGENT);
- attributes->add(ATTR_STD_UV_TANGENT_SIGN);
- }
- else {
- attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
- attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
- }
- }
-
- ShaderNode::attributes(shader, attributes);
-}
-
-void VectorDisplacementNode::compile(SVMCompiler &compiler)
-{
- ShaderInput *vector_in = input("Vector");
- ShaderInput *midlevel_in = input("Midlevel");
- ShaderInput *scale_in = input("Scale");
- ShaderOutput *displacement_out = output("Displacement");
- int attr = 0, attr_sign = 0;
-
- if (space == NODE_NORMAL_MAP_TANGENT) {
- if (attribute.empty()) {
- attr = compiler.attribute(ATTR_STD_UV_TANGENT);
- attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
- }
- else {
- attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
- attr_sign = compiler.attribute(
- ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
- }
- }
-
- compiler.add_node(NODE_VECTOR_DISPLACEMENT,
- compiler.encode_uchar4(compiler.stack_assign(vector_in),
- compiler.stack_assign(midlevel_in),
- compiler.stack_assign(scale_in),
- compiler.stack_assign(displacement_out)),
- attr,
- attr_sign);
-
- compiler.add_node(space);
-}
-
-void VectorDisplacementNode::compile(OSLCompiler &compiler)
-{
- if (space == NODE_NORMAL_MAP_TANGENT) {
- if (attribute.empty()) {
- compiler.parameter("attr_name", ustring("geom:tangent"));
- compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
- }
- else {
- compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
- compiler.parameter("attr_sign_name",
- ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
- }
- }
-
- compiler.parameter(this, "space");
- compiler.add(this, "node_vector_displacement");
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
deleted file mode 100644
index 5ac72835ac5..00000000000
--- a/intern/cycles/render/nodes.h
+++ /dev/null
@@ -1,1569 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __NODES_H__
-#define __NODES_H__
-
-#include "graph/node.h"
-#include "render/graph.h"
-#include "render/image.h"
-
-#include "util/util_array.h"
-#include "util/util_string.h"
-
-CCL_NAMESPACE_BEGIN
-
-class ImageManager;
-class LightManager;
-class Scene;
-class Shader;
-
-/* Texture Mapping */
-
-class TextureMapping {
- public:
- TextureMapping();
- Transform compute_transform();
- bool skip();
- void compile(SVMCompiler &compiler, int offset_in, int offset_out);
- int compile(SVMCompiler &compiler, ShaderInput *vector_in);
- void compile(OSLCompiler &compiler);
-
- int compile_begin(SVMCompiler &compiler, ShaderInput *vector_in);
- void compile_end(SVMCompiler &compiler, ShaderInput *vector_in, int vector_offset);
-
- float3 translation;
- float3 rotation;
- float3 scale;
-
- float3 min, max;
- bool use_minmax;
-
- enum Type { POINT = 0, TEXTURE = 1, VECTOR = 2, NORMAL = 3 };
- Type type;
-
- enum Mapping { NONE = 0, X = 1, Y = 2, Z = 3 };
- Mapping x_mapping, y_mapping, z_mapping;
-
- enum Projection { FLAT, CUBE, TUBE, SPHERE };
- Projection projection;
-};
-
-/* Nodes */
-
-class TextureNode : public ShaderNode {
- public:
- explicit TextureNode(const NodeType *node_type) : ShaderNode(node_type)
- {
- }
- TextureMapping tex_mapping;
- NODE_SOCKET_API_STRUCT_MEMBER(float3, tex_mapping, translation)
- NODE_SOCKET_API_STRUCT_MEMBER(float3, tex_mapping, rotation)
- NODE_SOCKET_API_STRUCT_MEMBER(float3, tex_mapping, scale)
- NODE_SOCKET_API_STRUCT_MEMBER(float3, tex_mapping, min)
- NODE_SOCKET_API_STRUCT_MEMBER(float3, tex_mapping, max)
- NODE_SOCKET_API_STRUCT_MEMBER(bool, tex_mapping, use_minmax)
- NODE_SOCKET_API_STRUCT_MEMBER(TextureMapping::Type, tex_mapping, type)
- NODE_SOCKET_API_STRUCT_MEMBER(TextureMapping::Mapping, tex_mapping, x_mapping)
- NODE_SOCKET_API_STRUCT_MEMBER(TextureMapping::Mapping, tex_mapping, y_mapping)
- NODE_SOCKET_API_STRUCT_MEMBER(TextureMapping::Mapping, tex_mapping, z_mapping)
- NODE_SOCKET_API_STRUCT_MEMBER(TextureMapping::Projection, tex_mapping, projection)
-};
-
-/* Any node which uses image manager's slot should be a subclass of this one. */
-class ImageSlotTextureNode : public TextureNode {
- public:
- explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type)
- {
- special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
- }
-
- virtual bool equals(const ShaderNode &other)
- {
- const ImageSlotTextureNode &other_node = (const ImageSlotTextureNode &)other;
- return TextureNode::equals(other) && handle == other_node.handle;
- }
-
- ImageHandle handle;
-};
-
-class ImageTextureNode : public ImageSlotTextureNode {
- public:
- SHADER_NODE_NO_CLONE_CLASS(ImageTextureNode)
- ShaderNode *clone(ShaderGraph *graph) const;
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
-
- virtual bool equals(const ShaderNode &other)
- {
- const ImageTextureNode &other_node = (const ImageTextureNode &)other;
- return ImageSlotTextureNode::equals(other) && animated == other_node.animated;
- }
-
- ImageParams image_params() const;
-
- /* Parameters. */
- NODE_SOCKET_API(ustring, filename)
- NODE_SOCKET_API(ustring, colorspace)
- NODE_SOCKET_API(ImageAlphaType, alpha_type)
- NODE_SOCKET_API(NodeImageProjection, projection)
- NODE_SOCKET_API(InterpolationType, interpolation)
- NODE_SOCKET_API(ExtensionType, extension)
- NODE_SOCKET_API(float, projection_blend)
- NODE_SOCKET_API(bool, animated)
- NODE_SOCKET_API(float3, vector)
- NODE_SOCKET_API_ARRAY(array<int>, tiles)
-
- protected:
- void cull_tiles(Scene *scene, ShaderGraph *graph);
-};
-
-class EnvironmentTextureNode : public ImageSlotTextureNode {
- public:
- SHADER_NODE_NO_CLONE_CLASS(EnvironmentTextureNode)
- ShaderNode *clone(ShaderGraph *graph) const;
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
-
- virtual bool equals(const ShaderNode &other)
- {
- const EnvironmentTextureNode &other_node = (const EnvironmentTextureNode &)other;
- return ImageSlotTextureNode::equals(other) && animated == other_node.animated;
- }
-
- ImageParams image_params() const;
-
- /* Parameters. */
- NODE_SOCKET_API(ustring, filename)
- NODE_SOCKET_API(ustring, colorspace)
- NODE_SOCKET_API(ImageAlphaType, alpha_type)
- NODE_SOCKET_API(NodeEnvironmentProjection, projection)
- NODE_SOCKET_API(InterpolationType, interpolation)
- NODE_SOCKET_API(bool, animated)
- NODE_SOCKET_API(float3, vector)
-};
-
-class SkyTextureNode : public TextureNode {
- public:
- SHADER_NODE_CLASS(SkyTextureNode)
-
- NODE_SOCKET_API(NodeSkyType, sky_type)
- NODE_SOCKET_API(float3, sun_direction)
- NODE_SOCKET_API(float, turbidity)
- NODE_SOCKET_API(float, ground_albedo)
- NODE_SOCKET_API(bool, sun_disc)
- NODE_SOCKET_API(float, sun_size)
- NODE_SOCKET_API(float, sun_intensity)
- NODE_SOCKET_API(float, sun_elevation)
- NODE_SOCKET_API(float, sun_rotation)
- NODE_SOCKET_API(float, altitude)
- NODE_SOCKET_API(float, air_density)
- NODE_SOCKET_API(float, dust_density)
- NODE_SOCKET_API(float, ozone_density)
- NODE_SOCKET_API(float3, vector)
- ImageHandle handle;
-
- float get_sun_size()
- {
- /* Clamping for numerical precision. */
- return fmaxf(sun_size, 0.0005f);
- }
-};
-
-class OutputNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(OutputNode)
-
- NODE_SOCKET_API(Node *, surface)
- NODE_SOCKET_API(Node *, volume)
- NODE_SOCKET_API(float3, displacement)
- NODE_SOCKET_API(float3, normal)
-
- /* Don't allow output node de-duplication. */
- virtual bool equals(const ShaderNode & /*other*/)
- {
- return false;
- }
-};
-
-class OutputAOVNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(OutputAOVNode)
- virtual void simplify_settings(Scene *scene);
-
- NODE_SOCKET_API(float, value)
- NODE_SOCKET_API(float3, color)
-
- NODE_SOCKET_API(ustring, name)
-
- /* Don't allow output node de-duplication. */
- virtual bool equals(const ShaderNode & /*other*/)
- {
- return false;
- }
-
- int offset;
- bool is_color;
-};
-
-class GradientTextureNode : public TextureNode {
- public:
- SHADER_NODE_CLASS(GradientTextureNode)
-
- NODE_SOCKET_API(NodeGradientType, gradient_type)
- NODE_SOCKET_API(float3, vector)
-};
-
-class NoiseTextureNode : public TextureNode {
- public:
- SHADER_NODE_CLASS(NoiseTextureNode)
-
- NODE_SOCKET_API(int, dimensions)
- NODE_SOCKET_API(float, w)
- NODE_SOCKET_API(float, scale)
- NODE_SOCKET_API(float, detail)
- NODE_SOCKET_API(float, roughness)
- NODE_SOCKET_API(float, distortion)
- NODE_SOCKET_API(float3, vector)
-};
-
-class VoronoiTextureNode : public TextureNode {
- public:
- SHADER_NODE_CLASS(VoronoiTextureNode)
-
- virtual int get_feature()
- {
- int result = ShaderNode::get_feature();
- if (dimensions == 4) {
- result |= KERNEL_FEATURE_NODE_VORONOI_EXTRA;
- }
- else if (dimensions >= 2 && feature == NODE_VORONOI_SMOOTH_F1) {
- result |= KERNEL_FEATURE_NODE_VORONOI_EXTRA;
- }
- return result;
- }
-
- NODE_SOCKET_API(int, dimensions)
- NODE_SOCKET_API(NodeVoronoiDistanceMetric, metric)
- NODE_SOCKET_API(NodeVoronoiFeature, feature)
- NODE_SOCKET_API(float, w)
- NODE_SOCKET_API(float, scale)
- NODE_SOCKET_API(float, exponent)
- NODE_SOCKET_API(float, smoothness)
- NODE_SOCKET_API(float, randomness)
- NODE_SOCKET_API(float3, vector)
-};
-
-class MusgraveTextureNode : public TextureNode {
- public:
- SHADER_NODE_CLASS(MusgraveTextureNode)
-
- NODE_SOCKET_API(int, dimensions)
- NODE_SOCKET_API(NodeMusgraveType, musgrave_type)
- NODE_SOCKET_API(float, w)
- NODE_SOCKET_API(float, scale)
- NODE_SOCKET_API(float, detail)
- NODE_SOCKET_API(float, dimension)
- NODE_SOCKET_API(float, lacunarity)
- NODE_SOCKET_API(float, offset)
- NODE_SOCKET_API(float, gain)
- NODE_SOCKET_API(float3, vector)
-};
-
-class WaveTextureNode : public TextureNode {
- public:
- SHADER_NODE_CLASS(WaveTextureNode)
-
- NODE_SOCKET_API(NodeWaveType, wave_type)
- NODE_SOCKET_API(NodeWaveBandsDirection, bands_direction)
- NODE_SOCKET_API(NodeWaveRingsDirection, rings_direction)
- NODE_SOCKET_API(NodeWaveProfile, profile)
-
- NODE_SOCKET_API(float, scale)
- NODE_SOCKET_API(float, distortion)
- NODE_SOCKET_API(float, detail)
- NODE_SOCKET_API(float, detail_scale)
- NODE_SOCKET_API(float, detail_roughness)
- NODE_SOCKET_API(float, phase)
- NODE_SOCKET_API(float3, vector)
-};
-
-class MagicTextureNode : public TextureNode {
- public:
- SHADER_NODE_CLASS(MagicTextureNode)
-
- NODE_SOCKET_API(int, depth)
- NODE_SOCKET_API(float3, vector)
- NODE_SOCKET_API(float, scale)
- NODE_SOCKET_API(float, distortion)
-};
-
-class CheckerTextureNode : public TextureNode {
- public:
- SHADER_NODE_CLASS(CheckerTextureNode)
-
- NODE_SOCKET_API(float3, vector)
- NODE_SOCKET_API(float3, color1)
- NODE_SOCKET_API(float3, color2)
- NODE_SOCKET_API(float, scale)
-};
-
-class BrickTextureNode : public TextureNode {
- public:
- SHADER_NODE_CLASS(BrickTextureNode)
-
- NODE_SOCKET_API(float, offset)
- NODE_SOCKET_API(float, squash)
- NODE_SOCKET_API(int, offset_frequency)
- NODE_SOCKET_API(int, squash_frequency)
-
- NODE_SOCKET_API(float3, color1)
- NODE_SOCKET_API(float3, color2)
- NODE_SOCKET_API(float3, mortar)
- NODE_SOCKET_API(float, scale)
- NODE_SOCKET_API(float, mortar_size)
- NODE_SOCKET_API(float, mortar_smooth)
- NODE_SOCKET_API(float, bias)
- NODE_SOCKET_API(float, brick_width)
- NODE_SOCKET_API(float, row_height)
- NODE_SOCKET_API(float3, vector)
-};
-
-class PointDensityTextureNode : public ShaderNode {
- public:
- SHADER_NODE_NO_CLONE_CLASS(PointDensityTextureNode)
-
- ~PointDensityTextureNode();
- ShaderNode *clone(ShaderGraph *graph) const;
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
-
- bool has_spatial_varying()
- {
- return true;
- }
-
- /* Parameters. */
- NODE_SOCKET_API(ustring, filename)
- NODE_SOCKET_API(NodeTexVoxelSpace, space)
- NODE_SOCKET_API(InterpolationType, interpolation)
- NODE_SOCKET_API(Transform, tfm)
- NODE_SOCKET_API(float3, vector)
-
- /* Runtime. */
- ImageHandle handle;
-
- ImageParams image_params() const;
-
- virtual bool equals(const ShaderNode &other)
- {
- const PointDensityTextureNode &other_node = (const PointDensityTextureNode &)other;
- return ShaderNode::equals(other) && handle == other_node.handle;
- }
-};
-
-class IESLightNode : public TextureNode {
- public:
- SHADER_NODE_NO_CLONE_CLASS(IESLightNode)
-
- ~IESLightNode();
- ShaderNode *clone(ShaderGraph *graph) const;
-
- NODE_SOCKET_API(ustring, filename)
- NODE_SOCKET_API(ustring, ies)
-
- NODE_SOCKET_API(float, strength)
- NODE_SOCKET_API(float3, vector)
-
- private:
- LightManager *light_manager;
- int slot;
-
- void get_slot();
-};
-
-class WhiteNoiseTextureNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(WhiteNoiseTextureNode)
-
- NODE_SOCKET_API(int, dimensions)
- NODE_SOCKET_API(float3, vector)
- NODE_SOCKET_API(float, w)
-};
-
-class MappingNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(MappingNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float3, vector)
- NODE_SOCKET_API(float3, location)
- NODE_SOCKET_API(float3, rotation)
- NODE_SOCKET_API(float3, scale)
- NODE_SOCKET_API(NodeMappingType, mapping_type)
-};
-
-class RGBToBWNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(RGBToBWNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float3, color)
-};
-
-class ConvertNode : public ShaderNode {
- public:
- ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false);
- ConvertNode(const ConvertNode &other);
- SHADER_NODE_BASE_CLASS(ConvertNode)
-
- void constant_fold(const ConstantFolder &folder);
-
- private:
- SocketType::Type from, to;
-
- union {
- float value_float;
- int value_int;
- float3 value_color;
- float3 value_vector;
- float3 value_point;
- float3 value_normal;
- };
- ustring value_string;
-
- static const int MAX_TYPE = 12;
- static bool register_types();
- static Node *create(const NodeType *type);
- static const NodeType *node_types[MAX_TYPE][MAX_TYPE];
- static bool initialized;
-};
-
-class BsdfBaseNode : public ShaderNode {
- public:
- BsdfBaseNode(const NodeType *node_type);
-
- bool has_spatial_varying()
- {
- return true;
- }
- virtual ClosureType get_closure_type()
- {
- return closure;
- }
- virtual bool has_bump();
-
- virtual bool equals(const ShaderNode & /*other*/)
- {
- /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */
- return false;
- }
-
- virtual int get_feature()
- {
- return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_BSDF;
- }
-
- protected:
- ClosureType closure;
-};
-
-class BsdfNode : public BsdfBaseNode {
- public:
- explicit BsdfNode(const NodeType *node_type);
- SHADER_NODE_BASE_CLASS(BsdfNode)
-
- void compile(SVMCompiler &compiler,
- ShaderInput *param1,
- ShaderInput *param2,
- ShaderInput *param3 = NULL,
- ShaderInput *param4 = NULL);
-
- NODE_SOCKET_API(float3, color)
- NODE_SOCKET_API(float3, normal)
- NODE_SOCKET_API(float, surface_mix_weight)
-};
-
-class AnisotropicBsdfNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(AnisotropicBsdfNode)
-
- NODE_SOCKET_API(float3, tangent)
- NODE_SOCKET_API(float, roughness)
- NODE_SOCKET_API(float, anisotropy)
- NODE_SOCKET_API(float, rotation)
- NODE_SOCKET_API(ClosureType, distribution)
-
- ClosureType get_closure_type()
- {
- return distribution;
- }
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
-};
-
-class DiffuseBsdfNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(DiffuseBsdfNode)
-
- NODE_SOCKET_API(float, roughness)
-};
-
-/* Disney principled BRDF */
-class PrincipledBsdfNode : public BsdfBaseNode {
- public:
- SHADER_NODE_CLASS(PrincipledBsdfNode)
-
- void expand(ShaderGraph *graph);
- bool has_surface_bssrdf();
- bool has_bssrdf_bump();
- void compile(SVMCompiler &compiler,
- ShaderInput *metallic,
- ShaderInput *subsurface,
- ShaderInput *subsurface_radius,
- ShaderInput *subsurface_ior,
- ShaderInput *subsurface_anisotropy,
- ShaderInput *specular,
- ShaderInput *roughness,
- ShaderInput *specular_tint,
- ShaderInput *anisotropic,
- ShaderInput *sheen,
- ShaderInput *sheen_tint,
- ShaderInput *clearcoat,
- ShaderInput *clearcoat_roughness,
- ShaderInput *ior,
- ShaderInput *transmission,
- ShaderInput *anisotropic_rotation,
- ShaderInput *transmission_roughness);
-
- NODE_SOCKET_API(float3, base_color)
- NODE_SOCKET_API(float3, subsurface_color)
- NODE_SOCKET_API(float3, subsurface_radius)
- NODE_SOCKET_API(float, subsurface_ior)
- NODE_SOCKET_API(float, subsurface_anisotropy)
- NODE_SOCKET_API(float, metallic)
- NODE_SOCKET_API(float, subsurface)
- NODE_SOCKET_API(float, specular)
- NODE_SOCKET_API(float, roughness)
- NODE_SOCKET_API(float, specular_tint)
- NODE_SOCKET_API(float, anisotropic)
- NODE_SOCKET_API(float, sheen)
- NODE_SOCKET_API(float, sheen_tint)
- NODE_SOCKET_API(float, clearcoat)
- NODE_SOCKET_API(float, clearcoat_roughness)
- NODE_SOCKET_API(float, ior)
- NODE_SOCKET_API(float, transmission)
- NODE_SOCKET_API(float, anisotropic_rotation)
- NODE_SOCKET_API(float, transmission_roughness)
- NODE_SOCKET_API(float3, normal)
- NODE_SOCKET_API(float3, clearcoat_normal)
- NODE_SOCKET_API(float3, tangent)
- NODE_SOCKET_API(float, surface_mix_weight)
- NODE_SOCKET_API(ClosureType, distribution)
- NODE_SOCKET_API(ClosureType, subsurface_method)
- NODE_SOCKET_API(float3, emission)
- NODE_SOCKET_API(float, emission_strength)
- NODE_SOCKET_API(float, alpha)
-
- private:
- ClosureType distribution_orig;
-
- public:
- bool has_integrator_dependency();
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
-};
-
-class TranslucentBsdfNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(TranslucentBsdfNode)
-};
-
-class TransparentBsdfNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(TransparentBsdfNode)
-
- bool has_surface_transparent()
- {
- return true;
- }
-};
-
-class VelvetBsdfNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(VelvetBsdfNode)
-
- NODE_SOCKET_API(float, sigma)
-};
-
-class GlossyBsdfNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(GlossyBsdfNode)
-
- void simplify_settings(Scene *scene);
- bool has_integrator_dependency();
- ClosureType get_closure_type()
- {
- return distribution;
- }
-
- NODE_SOCKET_API(float, roughness)
- NODE_SOCKET_API(ClosureType, distribution)
-
- private:
- float roughness_orig;
- ClosureType distribution_orig;
-};
-
-class GlassBsdfNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(GlassBsdfNode)
-
- void simplify_settings(Scene *scene);
- bool has_integrator_dependency();
- ClosureType get_closure_type()
- {
- return distribution;
- }
-
- NODE_SOCKET_API(float, roughness)
- NODE_SOCKET_API(float, IOR)
- NODE_SOCKET_API(ClosureType, distribution)
-
- private:
- float roughness_orig;
- ClosureType distribution_orig;
-};
-
-class RefractionBsdfNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(RefractionBsdfNode)
-
- void simplify_settings(Scene *scene);
- bool has_integrator_dependency();
- ClosureType get_closure_type()
- {
- return distribution;
- }
-
- NODE_SOCKET_API(float, roughness)
- NODE_SOCKET_API(float, IOR)
- NODE_SOCKET_API(ClosureType, distribution)
-
- private:
- float roughness_orig;
- ClosureType distribution_orig;
-};
-
-class ToonBsdfNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(ToonBsdfNode)
-
- NODE_SOCKET_API(float, smooth)
- NODE_SOCKET_API(float, size)
- NODE_SOCKET_API(ClosureType, component)
-};
-
-class SubsurfaceScatteringNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(SubsurfaceScatteringNode)
- bool has_surface_bssrdf()
- {
- return true;
- }
- bool has_bssrdf_bump();
- ClosureType get_closure_type()
- {
- return method;
- }
-
- NODE_SOCKET_API(float, scale)
- NODE_SOCKET_API(float3, radius)
- NODE_SOCKET_API(float, subsurface_ior)
- NODE_SOCKET_API(float, subsurface_anisotropy)
- NODE_SOCKET_API(ClosureType, method)
-};
-
-class EmissionNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(EmissionNode)
- void constant_fold(const ConstantFolder &folder);
-
- bool has_surface_emission()
- {
- return true;
- }
- bool has_volume_support()
- {
- return true;
- }
-
- virtual int get_feature()
- {
- return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_EMISSION;
- }
-
- NODE_SOCKET_API(float3, color)
- NODE_SOCKET_API(float, strength)
- NODE_SOCKET_API(float, surface_mix_weight)
-};
-
-class BackgroundNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(BackgroundNode)
- void constant_fold(const ConstantFolder &folder);
-
- virtual int get_feature()
- {
- return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_EMISSION;
- }
-
- NODE_SOCKET_API(float3, color)
- NODE_SOCKET_API(float, strength)
- NODE_SOCKET_API(float, surface_mix_weight)
-};
-
-class HoldoutNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(HoldoutNode)
- virtual ClosureType get_closure_type()
- {
- return CLOSURE_HOLDOUT_ID;
- }
-
- NODE_SOCKET_API(float, surface_mix_weight)
- NODE_SOCKET_API(float, volume_mix_weight)
-};
-
-class AmbientOcclusionNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(AmbientOcclusionNode)
-
- bool has_spatial_varying()
- {
- return true;
- }
- virtual int get_feature()
- {
- return KERNEL_FEATURE_NODE_RAYTRACE;
- }
-
- NODE_SOCKET_API(float3, color)
- NODE_SOCKET_API(float, distance)
- NODE_SOCKET_API(float3, normal)
- NODE_SOCKET_API(int, samples)
-
- NODE_SOCKET_API(bool, only_local)
- NODE_SOCKET_API(bool, inside)
-};
-
-class VolumeNode : public ShaderNode {
- public:
- VolumeNode(const NodeType *node_type);
- SHADER_NODE_BASE_CLASS(VolumeNode)
-
- void compile(SVMCompiler &compiler, ShaderInput *param1, ShaderInput *param2);
- virtual int get_feature()
- {
- return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_VOLUME;
- }
- virtual ClosureType get_closure_type()
- {
- return closure;
- }
- virtual bool has_volume_support()
- {
- return true;
- }
-
- NODE_SOCKET_API(float3, color)
- NODE_SOCKET_API(float, density)
- NODE_SOCKET_API(float, volume_mix_weight)
-
- protected:
- ClosureType closure;
-
- public:
- virtual bool equals(const ShaderNode & /*other*/)
- {
- /* TODO(sergey): With some care Volume nodes can be de-duplicated. */
- return false;
- }
-};
-
-class AbsorptionVolumeNode : public VolumeNode {
- public:
- SHADER_NODE_CLASS(AbsorptionVolumeNode)
-};
-
-class ScatterVolumeNode : public VolumeNode {
- public:
- SHADER_NODE_CLASS(ScatterVolumeNode)
-
- NODE_SOCKET_API(float, anisotropy)
-};
-
-class PrincipledVolumeNode : public VolumeNode {
- public:
- SHADER_NODE_CLASS(PrincipledVolumeNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
-
- NODE_SOCKET_API(ustring, density_attribute)
- NODE_SOCKET_API(ustring, color_attribute)
- NODE_SOCKET_API(ustring, temperature_attribute)
-
- NODE_SOCKET_API(float, anisotropy)
- NODE_SOCKET_API(float3, absorption_color)
- NODE_SOCKET_API(float, emission_strength)
- NODE_SOCKET_API(float3, emission_color)
- NODE_SOCKET_API(float, blackbody_intensity)
- NODE_SOCKET_API(float3, blackbody_tint)
- NODE_SOCKET_API(float, temperature)
-};
-
-/* Interface between the I/O sockets and the SVM/OSL backend. */
-class PrincipledHairBsdfNode : public BsdfBaseNode {
- public:
- SHADER_NODE_CLASS(PrincipledHairBsdfNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
-
- /* Longitudinal roughness. */
- NODE_SOCKET_API(float, roughness)
- /* Azimuthal roughness. */
- NODE_SOCKET_API(float, radial_roughness)
- /* Randomization factor for roughnesses. */
- NODE_SOCKET_API(float, random_roughness)
- /* Longitudinal roughness factor for only the diffuse bounce (shiny undercoat). */
- NODE_SOCKET_API(float, coat)
- /* Index of reflection. */
- NODE_SOCKET_API(float, ior)
- /* Cuticle tilt angle. */
- NODE_SOCKET_API(float, offset)
- /* Direct coloring's color. */
- NODE_SOCKET_API(float3, color)
- /* Melanin concentration. */
- NODE_SOCKET_API(float, melanin)
- /* Melanin redness ratio. */
- NODE_SOCKET_API(float, melanin_redness)
- /* Dye color. */
- NODE_SOCKET_API(float3, tint)
- /* Randomization factor for melanin quantities. */
- NODE_SOCKET_API(float, random_color)
- /* Absorption coefficient (unfiltered). */
- NODE_SOCKET_API(float3, absorption_coefficient)
-
- NODE_SOCKET_API(float3, normal)
- NODE_SOCKET_API(float, surface_mix_weight)
- /* If linked, here will be the given random number. */
- NODE_SOCKET_API(float, random)
- /* Selected coloring parametrization. */
- NODE_SOCKET_API(NodePrincipledHairParametrization, parametrization)
-};
-
-class HairBsdfNode : public BsdfNode {
- public:
- SHADER_NODE_CLASS(HairBsdfNode)
- ClosureType get_closure_type()
- {
- return component;
- }
-
- NODE_SOCKET_API(ClosureType, component)
- NODE_SOCKET_API(float, offset)
- NODE_SOCKET_API(float, roughness_u)
- NODE_SOCKET_API(float, roughness_v)
- NODE_SOCKET_API(float3, tangent)
-};
-
-class GeometryNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(GeometryNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
- bool has_spatial_varying()
- {
- return true;
- }
- int get_group();
-
- NODE_SOCKET_API(float3, normal_osl)
-};
-
-class TextureCoordinateNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(TextureCoordinateNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
- bool has_spatial_varying()
- {
- return true;
- }
-
- NODE_SOCKET_API(float3, normal_osl)
- NODE_SOCKET_API(bool, from_dupli)
- NODE_SOCKET_API(bool, use_transform)
- NODE_SOCKET_API(Transform, ob_tfm)
-};
-
-class UVMapNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(UVMapNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
- bool has_spatial_varying()
- {
- return true;
- }
-
- NODE_SOCKET_API(ustring, attribute)
- NODE_SOCKET_API(bool, from_dupli)
-};
-
-class LightPathNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(LightPathNode)
-};
-
-class LightFalloffNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(LightFalloffNode)
- bool has_spatial_varying()
- {
- return true;
- }
-
- NODE_SOCKET_API(float, strength)
- NODE_SOCKET_API(float, smooth)
-};
-
-class ObjectInfoNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(ObjectInfoNode)
-};
-
-class ParticleInfoNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(ParticleInfoNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
-};
-
-class HairInfoNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(HairInfoNode)
-
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
- bool has_spatial_varying()
- {
- return true;
- }
- virtual int get_feature()
- {
- return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_HAIR;
- }
-};
-
-class VolumeInfoNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(VolumeInfoNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
- bool has_spatial_varying()
- {
- return true;
- }
- void expand(ShaderGraph *graph);
-};
-
-class VertexColorNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(VertexColorNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
- bool has_spatial_varying()
- {
- return true;
- }
-
- NODE_SOCKET_API(ustring, layer_name)
-};
-
-class ValueNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(ValueNode)
-
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float, value)
-};
-
-class ColorNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(ColorNode)
-
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float3, value)
-};
-
-class AddClosureNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(AddClosureNode)
- void constant_fold(const ConstantFolder &folder);
-};
-
-class MixClosureNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(MixClosureNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float, fac)
-};
-
-class MixClosureWeightNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(MixClosureWeightNode)
-
- NODE_SOCKET_API(float, weight)
- NODE_SOCKET_API(float, fac)
-};
-
-class InvertNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(InvertNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float, fac)
- NODE_SOCKET_API(float3, color)
-};
-
-class MixNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(MixNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(NodeMix, mix_type)
- NODE_SOCKET_API(bool, use_clamp)
- NODE_SOCKET_API(float3, color1)
- NODE_SOCKET_API(float3, color2)
- NODE_SOCKET_API(float, fac)
-};
-
-class CombineRGBNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(CombineRGBNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float, r)
- NODE_SOCKET_API(float, g)
- NODE_SOCKET_API(float, b)
-};
-
-class CombineHSVNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(CombineHSVNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float, h)
- NODE_SOCKET_API(float, s)
- NODE_SOCKET_API(float, v)
-};
-
-class CombineXYZNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(CombineXYZNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float, x)
- NODE_SOCKET_API(float, y)
- NODE_SOCKET_API(float, z)
-};
-
-class GammaNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(GammaNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float3, color)
- NODE_SOCKET_API(float, gamma)
-};
-
-class BrightContrastNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(BrightContrastNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float3, color)
- NODE_SOCKET_API(float, bright)
- NODE_SOCKET_API(float, contrast)
-};
-
-class SeparateRGBNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(SeparateRGBNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float3, color)
-};
-
-class SeparateHSVNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(SeparateHSVNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float3, color)
-};
-
-class SeparateXYZNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(SeparateXYZNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float3, vector)
-};
-
-class HSVNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(HSVNode)
-
- NODE_SOCKET_API(float, hue)
- NODE_SOCKET_API(float, saturation)
- NODE_SOCKET_API(float, value)
- NODE_SOCKET_API(float, fac)
- NODE_SOCKET_API(float3, color)
-};
-
-class AttributeNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(AttributeNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
- bool has_spatial_varying()
- {
- return true;
- }
-
- NODE_SOCKET_API(ustring, attribute)
-};
-
-class CameraNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(CameraNode)
- bool has_spatial_varying()
- {
- return true;
- }
-};
-
-class FresnelNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(FresnelNode)
- bool has_spatial_varying()
- {
- return true;
- }
-
- NODE_SOCKET_API(float3, normal)
- NODE_SOCKET_API(float, IOR)
-};
-
-class LayerWeightNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(LayerWeightNode)
- bool has_spatial_varying()
- {
- return true;
- }
-
- NODE_SOCKET_API(float3, normal)
- NODE_SOCKET_API(float, blend)
-};
-
-class WireframeNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(WireframeNode)
- bool has_spatial_varying()
- {
- return true;
- }
-
- NODE_SOCKET_API(float, size)
- NODE_SOCKET_API(bool, use_pixel_size)
-};
-
-class WavelengthNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(WavelengthNode)
-
- NODE_SOCKET_API(float, wavelength)
-};
-
-class BlackbodyNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(BlackbodyNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float, temperature)
-};
-
-class MapRangeNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(MapRangeNode)
- void expand(ShaderGraph *graph);
-
- NODE_SOCKET_API(float, value)
- NODE_SOCKET_API(float, from_min)
- NODE_SOCKET_API(float, from_max)
- NODE_SOCKET_API(float, to_min)
- NODE_SOCKET_API(float, to_max)
- NODE_SOCKET_API(float, steps)
- NODE_SOCKET_API(NodeMapRangeType, range_type)
- NODE_SOCKET_API(bool, clamp)
-};
-
-class ClampNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(ClampNode)
- void constant_fold(const ConstantFolder &folder);
- NODE_SOCKET_API(float, value)
- NODE_SOCKET_API(float, min)
- NODE_SOCKET_API(float, max)
- NODE_SOCKET_API(NodeClampType, clamp_type)
-};
-
-class MathNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(MathNode)
- void expand(ShaderGraph *graph);
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float, value1)
- NODE_SOCKET_API(float, value2)
- NODE_SOCKET_API(float, value3)
- NODE_SOCKET_API(NodeMathType, math_type)
- NODE_SOCKET_API(bool, use_clamp)
-};
-
-class NormalNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(NormalNode)
-
- NODE_SOCKET_API(float3, direction)
- NODE_SOCKET_API(float3, normal)
-};
-
-class VectorMathNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(VectorMathNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API(float3, vector1)
- NODE_SOCKET_API(float3, vector2)
- NODE_SOCKET_API(float3, vector3)
- NODE_SOCKET_API(float, scale)
- NODE_SOCKET_API(NodeVectorMathType, math_type)
-};
-
-class VectorRotateNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(VectorRotateNode)
-
- NODE_SOCKET_API(NodeVectorRotateType, rotate_type)
- NODE_SOCKET_API(bool, invert)
- NODE_SOCKET_API(float3, vector)
- NODE_SOCKET_API(float3, center)
- NODE_SOCKET_API(float3, axis)
- NODE_SOCKET_API(float, angle)
- NODE_SOCKET_API(float3, rotation)
-};
-
-class VectorTransformNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(VectorTransformNode)
-
- NODE_SOCKET_API(NodeVectorTransformType, transform_type)
- NODE_SOCKET_API(NodeVectorTransformConvertSpace, convert_from)
- NODE_SOCKET_API(NodeVectorTransformConvertSpace, convert_to)
- NODE_SOCKET_API(float3, vector)
-};
-
-class BumpNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(BumpNode)
- void constant_fold(const ConstantFolder &folder);
- bool has_spatial_varying()
- {
- return true;
- }
- virtual int get_feature()
- {
- return KERNEL_FEATURE_NODE_BUMP;
- }
-
- NODE_SOCKET_API(bool, invert)
- NODE_SOCKET_API(bool, use_object_space)
- NODE_SOCKET_API(float, height)
- NODE_SOCKET_API(float, sample_center)
- NODE_SOCKET_API(float, sample_x)
- NODE_SOCKET_API(float, sample_y)
- NODE_SOCKET_API(float3, normal)
- NODE_SOCKET_API(float, strength)
- NODE_SOCKET_API(float, distance)
-};
-
-class CurvesNode : public ShaderNode {
- public:
- explicit CurvesNode(const NodeType *node_type);
- SHADER_NODE_BASE_CLASS(CurvesNode)
-
- NODE_SOCKET_API_ARRAY(array<float3>, curves)
- NODE_SOCKET_API(float, min_x)
- NODE_SOCKET_API(float, max_x)
- NODE_SOCKET_API(float, fac)
- NODE_SOCKET_API(float3, value)
-
- protected:
- using ShaderNode::constant_fold;
- void constant_fold(const ConstantFolder &folder, ShaderInput *value_in);
- void compile(SVMCompiler &compiler, int type, ShaderInput *value_in, ShaderOutput *value_out);
- void compile(OSLCompiler &compiler, const char *name);
-};
-
-class RGBCurvesNode : public CurvesNode {
- public:
- SHADER_NODE_CLASS(RGBCurvesNode)
- void constant_fold(const ConstantFolder &folder);
-};
-
-class VectorCurvesNode : public CurvesNode {
- public:
- SHADER_NODE_CLASS(VectorCurvesNode)
- void constant_fold(const ConstantFolder &folder);
-};
-
-class FloatCurveNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(FloatCurveNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API_ARRAY(array<float>, curve)
- NODE_SOCKET_API(float, min_x)
- NODE_SOCKET_API(float, max_x)
- NODE_SOCKET_API(float, fac)
- NODE_SOCKET_API(float, value)
-};
-
-class RGBRampNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(RGBRampNode)
- void constant_fold(const ConstantFolder &folder);
-
- NODE_SOCKET_API_ARRAY(array<float3>, ramp)
- NODE_SOCKET_API_ARRAY(array<float>, ramp_alpha)
- NODE_SOCKET_API(float, fac)
- NODE_SOCKET_API(bool, interpolate)
-};
-
-class SetNormalNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(SetNormalNode)
- NODE_SOCKET_API(float3, direction)
-};
-
-class OSLNode final : public ShaderNode {
- public:
- static OSLNode *create(ShaderGraph *graph, size_t num_inputs, const OSLNode *from = NULL);
- ~OSLNode();
-
- static void operator delete(void *ptr)
- {
- /* Override delete operator to silence new-delete-type-mismatch ASAN warnings
- * regarding size mismatch in the destructor. This is intentional as we allocate
- * extra space at the end of the node. */
- ::operator delete(ptr);
- }
- static void operator delete(void *, void *)
- {
- /* Deliberately empty placement delete operator, to avoid MSVC warning C4291. */
- }
-
- ShaderNode *clone(ShaderGraph *graph) const;
-
- char *input_default_value();
- void add_input(ustring name, SocketType::Type type);
- void add_output(ustring name, SocketType::Type type);
-
- SHADER_NODE_NO_CLONE_CLASS(OSLNode)
-
- /* Ideally we could better detect this, but we can't query this now. */
- bool has_spatial_varying()
- {
- return true;
- }
- bool has_volume_support()
- {
- return true;
- }
-
- virtual bool equals(const ShaderNode & /*other*/)
- {
- return false;
- }
-
- string filepath;
- string bytecode_hash;
-};
-
-class NormalMapNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(NormalMapNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
- bool has_spatial_varying()
- {
- return true;
- }
-
- NODE_SOCKET_API(NodeNormalMapSpace, space)
- NODE_SOCKET_API(ustring, attribute)
- NODE_SOCKET_API(float, strength)
- NODE_SOCKET_API(float3, color)
- NODE_SOCKET_API(float3, normal_osl)
-};
-
-class TangentNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(TangentNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
- bool has_spatial_varying()
- {
- return true;
- }
-
- NODE_SOCKET_API(NodeTangentDirectionType, direction_type)
- NODE_SOCKET_API(NodeTangentAxis, axis)
- NODE_SOCKET_API(ustring, attribute)
- NODE_SOCKET_API(float3, normal_osl)
-};
-
-class BevelNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(BevelNode)
- bool has_spatial_varying()
- {
- return true;
- }
- virtual int get_feature()
- {
- return KERNEL_FEATURE_NODE_RAYTRACE;
- }
-
- NODE_SOCKET_API(float, radius)
- NODE_SOCKET_API(float3, normal)
- NODE_SOCKET_API(int, samples)
-};
-
-class DisplacementNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(DisplacementNode)
- void constant_fold(const ConstantFolder &folder);
- virtual int get_feature()
- {
- return KERNEL_FEATURE_NODE_BUMP;
- }
-
- NODE_SOCKET_API(NodeNormalMapSpace, space)
- NODE_SOCKET_API(float, height)
- NODE_SOCKET_API(float, midlevel)
- NODE_SOCKET_API(float, scale)
- NODE_SOCKET_API(float3, normal)
-};
-
-class VectorDisplacementNode : public ShaderNode {
- public:
- SHADER_NODE_CLASS(VectorDisplacementNode)
- void attributes(Shader *shader, AttributeRequestSet *attributes);
- bool has_attribute_dependency()
- {
- return true;
- }
- void constant_fold(const ConstantFolder &folder);
- virtual int get_feature()
- {
- return KERNEL_FEATURE_NODE_BUMP;
- }
-
- NODE_SOCKET_API(NodeNormalMapSpace, space)
- NODE_SOCKET_API(ustring, attribute)
- NODE_SOCKET_API(float3, vector)
- NODE_SOCKET_API(float, midlevel)
- NODE_SOCKET_API(float, scale)
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __NODES_H__ */
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
deleted file mode 100644
index 6d5c537e33d..00000000000
--- a/intern/cycles/render/object.cpp
+++ /dev/null
@@ -1,997 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/object.h"
-#include "device/device.h"
-#include "render/camera.h"
-#include "render/curves.h"
-#include "render/hair.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/particles.h"
-#include "render/scene.h"
-#include "render/stats.h"
-#include "render/volume.h"
-
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_map.h"
-#include "util/util_murmurhash.h"
-#include "util/util_progress.h"
-#include "util/util_set.h"
-#include "util/util_task.h"
-#include "util/util_vector.h"
-
-#include "subd/subd_patch_table.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Global state of object transform update. */
-
-struct UpdateObjectTransformState {
- /* Global state used by device_update_object_transform().
- * Common for both threaded and non-threaded update.
- */
-
- /* Type of the motion required by the scene settings. */
- Scene::MotionType need_motion;
-
- /* Mapping from particle system to a index in packed particle array.
- * Only used for read.
- */
- map<ParticleSystem *, int> particle_offset;
-
- /* Motion offsets for each object. */
- array<uint> motion_offset;
-
- /* Packed object arrays. Those will be filled in. */
- uint *object_flag;
- uint *object_visibility;
- KernelObject *objects;
- Transform *object_motion_pass;
- DecomposedTransform *object_motion;
- float *object_volume_step;
-
- /* Flags which will be synchronized to Integrator. */
- bool have_motion;
- bool have_curves;
-
- /* ** Scheduling queue. ** */
- Scene *scene;
-
- /* First unused object index in the queue. */
- int queue_start_object;
-};
-
-/* Object */
-
-NODE_DEFINE(Object)
-{
- NodeType *type = NodeType::add("object", create);
-
- SOCKET_NODE(geometry, "Geometry", Geometry::get_node_base_type());
- SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
- SOCKET_UINT(visibility, "Visibility", ~0);
- SOCKET_COLOR(color, "Color", zero_float3());
- SOCKET_UINT(random_id, "Random ID", 0);
- SOCKET_INT(pass_id, "Pass ID", 0);
- SOCKET_BOOLEAN(use_holdout, "Use Holdout", false);
- SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false);
- SOCKET_POINT(dupli_generated, "Dupli Generated", zero_float3());
- SOCKET_POINT2(dupli_uv, "Dupli UV", zero_float2());
- SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
- SOCKET_FLOAT(shadow_terminator_shading_offset, "Shadow Terminator Shading Offset", 0.0f);
- SOCKET_FLOAT(shadow_terminator_geometry_offset, "Shadow Terminator Geometry Offset", 0.1f);
- SOCKET_STRING(asset_name, "Asset Name", ustring());
-
- SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);
-
- SOCKET_NODE(particle_system, "Particle System", ParticleSystem::get_node_type());
- SOCKET_INT(particle_index, "Particle Index", 0);
-
- SOCKET_FLOAT(ao_distance, "AO Distance", 0.0f);
-
- return type;
-}
-
-Object::Object() : Node(get_node_type())
-{
- particle_system = NULL;
- particle_index = 0;
- attr_map_offset = 0;
- bounds = BoundBox::empty;
-}
-
-Object::~Object()
-{
-}
-
-void Object::update_motion()
-{
- if (!use_motion()) {
- return;
- }
-
- bool have_motion = false;
-
- for (size_t i = 0; i < motion.size(); i++) {
- if (motion[i] == transform_empty()) {
- if (hide_on_missing_motion) {
- /* Hide objects that have no valid previous or next
- * transform, for example particle that stop existing. It
- * would be better to handle this in the kernel and make
- * objects invisible outside certain motion steps. */
- tfm = transform_empty();
- motion.clear();
- return;
- }
- else {
- /* Otherwise just copy center motion. */
- motion[i] = tfm;
- }
- }
-
- /* Test if any of the transforms are actually different. */
- have_motion = have_motion || motion[i] != tfm;
- }
-
- /* Clear motion array if there is no actual motion. */
- if (!have_motion) {
- motion.clear();
- }
-}
-
-void Object::compute_bounds(bool motion_blur)
-{
- BoundBox mbounds = geometry->bounds;
-
- if (motion_blur && use_motion()) {
- array<DecomposedTransform> decomp(motion.size());
- transform_motion_decompose(decomp.data(), motion.data(), motion.size());
-
- bounds = BoundBox::empty;
-
- /* TODO: this is really terrible. according to PBRT there is a better
- * way to find this iteratively, but did not find implementation yet
- * or try to implement myself */
- for (float t = 0.0f; t < 1.0f; t += (1.0f / 128.0f)) {
- Transform ttfm;
-
- transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t);
- bounds.grow(mbounds.transformed(&ttfm));
- }
- }
- else {
- /* No motion blur case. */
- if (geometry->transform_applied) {
- bounds = mbounds;
- }
- else {
- bounds = mbounds.transformed(&tfm);
- }
- }
-}
-
-void Object::apply_transform(bool apply_to_motion)
-{
- if (!geometry || tfm == transform_identity())
- return;
-
- geometry->apply_transform(tfm, apply_to_motion);
-
- /* we keep normals pointing in same direction on negative scale, notify
- * geometry about this in it (re)calculates normals */
- if (transform_negative_scale(tfm))
- geometry->transform_negative_scaled = true;
-
- if (bounds.valid()) {
- geometry->compute_bounds();
- compute_bounds(false);
- }
-
- /* tfm is not reset to identity, all code that uses it needs to check the
- * transform_applied boolean */
-}
-
-void Object::tag_update(Scene *scene)
-{
- uint32_t flag = ObjectManager::UPDATE_NONE;
-
- if (is_modified()) {
- flag |= ObjectManager::OBJECT_MODIFIED;
-
- if (use_holdout_is_modified()) {
- flag |= ObjectManager::HOLDOUT_MODIFIED;
- }
-
- if (is_shadow_catcher_is_modified()) {
- scene->tag_shadow_catcher_modified();
- }
- }
-
- if (geometry) {
- if (tfm_is_modified()) {
- flag |= ObjectManager::TRANSFORM_MODIFIED;
- }
-
- if (visibility_is_modified()) {
- flag |= ObjectManager::VISIBILITY_MODIFIED;
- }
-
- foreach (Node *node, geometry->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->get_use_mis() && shader->has_surface_emission)
- scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED);
- }
- }
-
- scene->camera->need_flags_update = true;
- scene->object_manager->tag_update(scene, flag);
-}
-
-bool Object::use_motion() const
-{
- return (motion.size() > 1);
-}
-
-float Object::motion_time(int step) const
-{
- return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
-}
-
-int Object::motion_step(float time) const
-{
- if (use_motion()) {
- for (size_t step = 0; step < motion.size(); step++) {
- if (time == motion_time(step)) {
- return step;
- }
- }
- }
-
- return -1;
-}
-
-bool Object::is_traceable() const
-{
- /* Mesh itself can be empty,can skip all such objects. */
- if (!bounds.valid() || bounds.size() == zero_float3()) {
- return false;
- }
- /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */
- return true;
-}
-
-uint Object::visibility_for_tracing() const
-{
- return SHADOW_CATCHER_OBJECT_VISIBILITY(is_shadow_catcher, visibility & PATH_RAY_ALL_VISIBILITY);
-}
-
-float Object::compute_volume_step_size() const
-{
- if (geometry->geometry_type != Geometry::MESH && geometry->geometry_type != Geometry::VOLUME) {
- return FLT_MAX;
- }
-
- Mesh *mesh = static_cast<Mesh *>(geometry);
-
- if (!mesh->has_volume) {
- return FLT_MAX;
- }
-
- /* Compute step rate from shaders. */
- float step_rate = FLT_MAX;
-
- foreach (Node *node, mesh->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
- if (shader->has_volume) {
- if ((shader->get_heterogeneous_volume() && shader->has_volume_spatial_varying) ||
- (shader->has_volume_attribute_dependency)) {
- step_rate = fminf(shader->get_volume_step_rate(), step_rate);
- }
- }
- }
-
- if (step_rate == FLT_MAX) {
- return FLT_MAX;
- }
-
- /* Compute step size from voxel grids. */
- float step_size = FLT_MAX;
-
- if (geometry->geometry_type == Geometry::VOLUME) {
- Volume *volume = static_cast<Volume *>(geometry);
-
- foreach (Attribute &attr, volume->attributes.attributes) {
- if (attr.element == ATTR_ELEMENT_VOXEL) {
- ImageHandle &handle = attr.data_voxel();
- const ImageMetaData &metadata = handle.metadata();
- if (metadata.width == 0 || metadata.height == 0 || metadata.depth == 0) {
- continue;
- }
-
- /* User specified step size. */
- float voxel_step_size = volume->get_step_size();
-
- if (voxel_step_size == 0.0f) {
- /* Auto detect step size. */
- float3 size = one_float3();
-#ifdef WITH_NANOVDB
- /* Dimensions were not applied to image transform with NanOVDB (see image_vdb.cpp) */
- if (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
- metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3)
-#endif
- size /= make_float3(metadata.width, metadata.height, metadata.depth);
-
- /* Step size is transformed from voxel to world space. */
- Transform voxel_tfm = tfm;
- if (metadata.use_transform_3d) {
- voxel_tfm = tfm * transform_inverse(metadata.transform_3d);
- }
- voxel_step_size = min3(fabs(transform_direction(&voxel_tfm, size)));
- }
- else if (volume->get_object_space()) {
- /* User specified step size in object space. */
- float3 size = make_float3(voxel_step_size, voxel_step_size, voxel_step_size);
- voxel_step_size = min3(fabs(transform_direction(&tfm, size)));
- }
-
- if (voxel_step_size > 0.0f) {
- step_size = fminf(voxel_step_size, step_size);
- }
- }
- }
- }
-
- if (step_size == FLT_MAX) {
- /* Fall back to 1/10th of bounds for procedural volumes. */
- step_size = 0.1f * average(bounds.size());
- }
-
- step_size *= step_rate;
-
- return step_size;
-}
-
-bool Object::check_is_volume() const
-{
- if (geometry->geometry_type == Geometry::VOLUME) {
- return true;
- }
-
- for (Node *node : get_geometry()->get_used_shaders()) {
- const Shader *shader = static_cast<const Shader *>(node);
- if (shader->has_volume) {
- return true;
- }
- }
-
- return false;
-}
-
-int Object::get_device_index() const
-{
- return index;
-}
-
-/* Object Manager */
-
-ObjectManager::ObjectManager()
-{
- update_flags = UPDATE_ALL;
- need_flags_update = true;
-}
-
-ObjectManager::~ObjectManager()
-{
-}
-
-static float object_volume_density(const Transform &tfm, Geometry *geom)
-{
- if (geom->geometry_type == Geometry::VOLUME) {
- /* Volume density automatically adjust to object scale. */
- if (static_cast<Volume *>(geom)->get_object_space()) {
- const float3 unit = normalize(one_float3());
- return 1.0f / len(transform_direction(&tfm, unit));
- }
- }
-
- return 1.0f;
-}
-
-void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state,
- Object *ob,
- bool update_all)
-{
- KernelObject &kobject = state->objects[ob->index];
- Transform *object_motion_pass = state->object_motion_pass;
-
- Geometry *geom = ob->geometry;
- uint flag = 0;
-
- /* Compute transformations. */
- Transform tfm = ob->tfm;
- Transform itfm = transform_inverse(tfm);
-
- float3 color = ob->color;
- float pass_id = ob->pass_id;
- float random_number = (float)ob->random_id * (1.0f / (float)0xFFFFFFFF);
- int particle_index = (ob->particle_system) ?
- ob->particle_index + state->particle_offset[ob->particle_system] :
- 0;
-
- kobject.tfm = tfm;
- kobject.itfm = itfm;
- kobject.volume_density = object_volume_density(tfm, geom);
- kobject.color[0] = color.x;
- kobject.color[1] = color.y;
- kobject.color[2] = color.z;
- kobject.pass_id = pass_id;
- kobject.random_number = random_number;
- kobject.particle_index = particle_index;
- kobject.motion_offset = 0;
- kobject.ao_distance = ob->ao_distance;
-
- if (geom->get_use_motion_blur()) {
- state->have_motion = true;
- }
-
- if (geom->geometry_type == Geometry::MESH) {
- /* TODO: why only mesh? */
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
- flag |= SD_OBJECT_HAS_VERTEX_MOTION;
- }
- }
-
- if (state->need_motion == Scene::MOTION_PASS) {
- /* Clear motion array if there is no actual motion. */
- ob->update_motion();
-
- /* Compute motion transforms. */
- Transform tfm_pre, tfm_post;
- if (ob->use_motion()) {
- tfm_pre = ob->motion[0];
- tfm_post = ob->motion[ob->motion.size() - 1];
- }
- else {
- tfm_pre = tfm;
- tfm_post = tfm;
- }
-
- /* Motion transformations, is world/object space depending if mesh
- * comes with deformed position in object space, or if we transform
- * the shading point in world space. */
- if (!(flag & SD_OBJECT_HAS_VERTEX_MOTION)) {
- tfm_pre = tfm_pre * itfm;
- tfm_post = tfm_post * itfm;
- }
-
- int motion_pass_offset = ob->index * OBJECT_MOTION_PASS_SIZE;
- object_motion_pass[motion_pass_offset + 0] = tfm_pre;
- object_motion_pass[motion_pass_offset + 1] = tfm_post;
- }
- else if (state->need_motion == Scene::MOTION_BLUR) {
- if (ob->use_motion()) {
- kobject.motion_offset = state->motion_offset[ob->index];
-
- /* Decompose transforms for interpolation. */
- if (ob->tfm_is_modified() || update_all) {
- DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
- transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
- }
-
- flag |= SD_OBJECT_MOTION;
- state->have_motion = true;
- }
- }
-
- /* Dupli object coords and motion info. */
- kobject.dupli_generated[0] = ob->dupli_generated[0];
- kobject.dupli_generated[1] = ob->dupli_generated[1];
- kobject.dupli_generated[2] = ob->dupli_generated[2];
- kobject.numkeys = (geom->geometry_type == Geometry::HAIR) ?
- static_cast<Hair *>(geom)->get_curve_keys().size() :
- 0;
- kobject.dupli_uv[0] = ob->dupli_uv[0];
- kobject.dupli_uv[1] = ob->dupli_uv[1];
- int totalsteps = geom->get_motion_steps();
- kobject.numsteps = (totalsteps - 1) / 2;
- kobject.numverts = (geom->geometry_type == Geometry::MESH ||
- geom->geometry_type == Geometry::VOLUME) ?
- static_cast<Mesh *>(geom)->get_verts().size() :
- 0;
- kobject.patch_map_offset = 0;
- kobject.attribute_map_offset = 0;
-
- if (ob->asset_name_is_modified() || update_all) {
- uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0);
- uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
- kobject.cryptomatte_object = util_hash_to_float(hash_name);
- kobject.cryptomatte_asset = util_hash_to_float(hash_asset);
- }
-
- kobject.shadow_terminator_shading_offset = 1.0f /
- (1.0f - 0.5f * ob->shadow_terminator_shading_offset);
- kobject.shadow_terminator_geometry_offset = ob->shadow_terminator_geometry_offset;
-
- kobject.visibility = ob->visibility_for_tracing();
- kobject.primitive_type = geom->primitive_type();
-
- /* Object flag. */
- if (ob->use_holdout) {
- flag |= SD_OBJECT_HOLDOUT_MASK;
- }
- state->object_flag[ob->index] = flag;
- state->object_volume_step[ob->index] = FLT_MAX;
-
- /* Have curves. */
- if (geom->geometry_type == Geometry::HAIR) {
- state->have_curves = true;
- }
-}
-
-void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress)
-{
- UpdateObjectTransformState state;
- state.need_motion = scene->need_motion();
- state.have_motion = false;
- state.have_curves = false;
- state.scene = scene;
- state.queue_start_object = 0;
-
- state.objects = dscene->objects.alloc(scene->objects.size());
- state.object_flag = dscene->object_flag.alloc(scene->objects.size());
- state.object_volume_step = dscene->object_volume_step.alloc(scene->objects.size());
- state.object_motion = NULL;
- state.object_motion_pass = NULL;
-
- if (state.need_motion == Scene::MOTION_PASS) {
- state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE *
- scene->objects.size());
- }
- else if (state.need_motion == Scene::MOTION_BLUR) {
- /* Set object offsets into global object motion array. */
- uint *motion_offsets = state.motion_offset.resize(scene->objects.size());
- uint motion_offset = 0;
-
- foreach (Object *ob, scene->objects) {
- *motion_offsets = motion_offset;
- motion_offsets++;
-
- /* Clear motion array if there is no actual motion. */
- ob->update_motion();
- motion_offset += ob->motion.size();
- }
-
- state.object_motion = dscene->object_motion.alloc(motion_offset);
- }
-
- /* Particle system device offsets
- * 0 is dummy particle, index starts at 1.
- */
- int numparticles = 1;
- foreach (ParticleSystem *psys, scene->particle_systems) {
- state.particle_offset[psys] = numparticles;
- numparticles += psys->particles.size();
- }
-
- /* as all the arrays are the same size, checking only dscene.objects is sufficient */
- const bool update_all = dscene->objects.need_realloc();
-
- /* Parallel object update, with grain size to avoid too much threading overhead
- * for individual objects. */
- static const int OBJECTS_PER_TASK = 32;
- parallel_for(blocked_range<size_t>(0, scene->objects.size(), OBJECTS_PER_TASK),
- [&](const blocked_range<size_t> &r) {
- for (size_t i = r.begin(); i != r.end(); i++) {
- Object *ob = state.scene->objects[i];
- device_update_object_transform(&state, ob, update_all);
- }
- });
-
- if (progress.get_cancel()) {
- return;
- }
-
- dscene->objects.copy_to_device_if_modified();
- if (state.need_motion == Scene::MOTION_PASS) {
- dscene->object_motion_pass.copy_to_device();
- }
- else if (state.need_motion == Scene::MOTION_BLUR) {
- dscene->object_motion.copy_to_device();
- }
-
- dscene->data.bvh.have_motion = state.have_motion;
- dscene->data.bvh.have_curves = state.have_curves;
-
- dscene->objects.clear_modified();
- dscene->object_motion_pass.clear_modified();
- dscene->object_motion.clear_modified();
-}
-
-void ObjectManager::device_update(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- if (!need_update())
- return;
-
- if (update_flags & (OBJECT_ADDED | OBJECT_REMOVED)) {
- dscene->objects.tag_realloc();
- dscene->object_motion_pass.tag_realloc();
- dscene->object_motion.tag_realloc();
- dscene->object_flag.tag_realloc();
- dscene->object_volume_step.tag_realloc();
- }
-
- if (update_flags & HOLDOUT_MODIFIED) {
- dscene->object_flag.tag_modified();
- }
-
- if (update_flags & PARTICLE_MODIFIED) {
- dscene->objects.tag_modified();
- }
-
- VLOG(1) << "Total " << scene->objects.size() << " objects.";
-
- device_free(device, dscene, false);
-
- if (scene->objects.size() == 0)
- return;
-
- {
- /* Assign object IDs. */
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->object.times.add_entry({"device_update (assign index)", time});
- }
- });
-
- int index = 0;
- foreach (Object *object, scene->objects) {
- object->index = index++;
-
- /* this is a bit too broad, however a bigger refactor might be needed to properly separate
- * update each type of data (transform, flags, etc.) */
- if (object->is_modified()) {
- dscene->objects.tag_modified();
- dscene->object_motion_pass.tag_modified();
- dscene->object_motion.tag_modified();
- dscene->object_flag.tag_modified();
- dscene->object_volume_step.tag_modified();
- }
- }
- }
-
- {
- /* set object transform matrices, before applying static transforms */
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->object.times.add_entry(
- {"device_update (copy objects to device)", time});
- }
- });
-
- progress.set_status("Updating Objects", "Copying Transformations to device");
- device_update_transforms(dscene, scene, progress);
- }
-
- if (progress.get_cancel())
- return;
-
- /* prepare for static BVH building */
- /* todo: do before to support getting object level coords? */
- if (scene->params.bvh_type == BVH_TYPE_STATIC) {
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->object.times.add_entry(
- {"device_update (apply static transforms)", time});
- }
- });
-
- progress.set_status("Updating Objects", "Applying Static Transformations");
- apply_static_transforms(dscene, scene, progress);
- }
-
- foreach (Object *object, scene->objects) {
- object->clear_modified();
- }
-}
-
-void ObjectManager::device_update_flags(
- Device *, DeviceScene *dscene, Scene *scene, Progress & /*progress*/, bool bounds_valid)
-{
- if (!need_update() && !need_flags_update)
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->object.times.add_entry({"device_update_flags", time});
- }
- });
-
- update_flags = UPDATE_NONE;
- need_flags_update = false;
-
- if (scene->objects.size() == 0)
- return;
-
- /* Object info flag. */
- uint *object_flag = dscene->object_flag.data();
- float *object_volume_step = dscene->object_volume_step.data();
-
- /* Object volume intersection. */
- vector<Object *> volume_objects;
- bool has_volume_objects = false;
- foreach (Object *object, scene->objects) {
- if (object->geometry->has_volume) {
- if (bounds_valid) {
- volume_objects.push_back(object);
- }
- has_volume_objects = true;
- object_volume_step[object->index] = object->compute_volume_step_size();
- }
- else {
- object_volume_step[object->index] = FLT_MAX;
- }
- }
-
- foreach (Object *object, scene->objects) {
- if (object->geometry->has_volume) {
- object_flag[object->index] |= SD_OBJECT_HAS_VOLUME;
- object_flag[object->index] &= ~SD_OBJECT_HAS_VOLUME_ATTRIBUTES;
-
- foreach (Attribute &attr, object->geometry->attributes.attributes) {
- if (attr.element == ATTR_ELEMENT_VOXEL) {
- object_flag[object->index] |= SD_OBJECT_HAS_VOLUME_ATTRIBUTES;
- }
- }
- }
- else {
- object_flag[object->index] &= ~(SD_OBJECT_HAS_VOLUME | SD_OBJECT_HAS_VOLUME_ATTRIBUTES);
- }
-
- if (object->is_shadow_catcher) {
- object_flag[object->index] |= SD_OBJECT_SHADOW_CATCHER;
- }
- else {
- object_flag[object->index] &= ~SD_OBJECT_SHADOW_CATCHER;
- }
-
- if (bounds_valid) {
- foreach (Object *volume_object, volume_objects) {
- if (object == volume_object) {
- continue;
- }
- if (object->bounds.intersects(volume_object->bounds)) {
- object_flag[object->index] |= SD_OBJECT_INTERSECTS_VOLUME;
- break;
- }
- }
- }
- else if (has_volume_objects) {
- /* Not really valid, but can't make more reliable in the case
- * of bounds not being up to date.
- */
- object_flag[object->index] |= SD_OBJECT_INTERSECTS_VOLUME;
- }
- }
-
- /* Copy object flag. */
- dscene->object_flag.copy_to_device();
- dscene->object_volume_step.copy_to_device();
-
- dscene->object_flag.clear_modified();
- dscene->object_volume_step.clear_modified();
-}
-
-void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene)
-{
- if (dscene->objects.size() == 0) {
- return;
- }
-
- KernelObject *kobjects = dscene->objects.data();
-
- bool update = false;
-
- foreach (Object *object, scene->objects) {
- Geometry *geom = object->geometry;
-
- if (geom->geometry_type == Geometry::MESH) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- if (mesh->patch_table) {
- uint patch_map_offset = 2 * (mesh->patch_table_offset + mesh->patch_table->total_size() -
- mesh->patch_table->num_nodes * PATCH_NODE_SIZE) -
- mesh->patch_offset;
-
- if (kobjects[object->index].patch_map_offset != patch_map_offset) {
- kobjects[object->index].patch_map_offset = patch_map_offset;
- update = true;
- }
- }
- }
-
- size_t attr_map_offset = object->attr_map_offset;
-
- /* An object attribute map cannot have a zero offset because mesh maps come first. */
- if (attr_map_offset == 0) {
- attr_map_offset = geom->attr_map_offset;
- }
-
- if (kobjects[object->index].attribute_map_offset != attr_map_offset) {
- kobjects[object->index].attribute_map_offset = attr_map_offset;
- update = true;
- }
- }
-
- if (update) {
- dscene->objects.copy_to_device();
- }
-}
-
-void ObjectManager::device_free(Device *, DeviceScene *dscene, bool force_free)
-{
- dscene->objects.free_if_need_realloc(force_free);
- dscene->object_motion_pass.free_if_need_realloc(force_free);
- dscene->object_motion.free_if_need_realloc(force_free);
- dscene->object_flag.free_if_need_realloc(force_free);
- dscene->object_volume_step.free_if_need_realloc(force_free);
-}
-
-void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress)
-{
- /* todo: normals and displacement should be done before applying transform! */
- /* todo: create objects/geometry in right order! */
-
- /* counter geometry users */
- map<Geometry *, int> geometry_users;
- Scene::MotionType need_motion = scene->need_motion();
- bool motion_blur = need_motion == Scene::MOTION_BLUR;
- bool apply_to_motion = need_motion != Scene::MOTION_PASS;
- int i = 0;
-
- foreach (Object *object, scene->objects) {
- map<Geometry *, int>::iterator it = geometry_users.find(object->geometry);
-
- if (it == geometry_users.end())
- geometry_users[object->geometry] = 1;
- else
- it->second++;
- }
-
- if (progress.get_cancel())
- return;
-
- uint *object_flag = dscene->object_flag.data();
-
- /* apply transforms for objects with single user geometry */
- foreach (Object *object, scene->objects) {
- /* Annoying feedback loop here: we can't use is_instanced() because
- * it'll use uninitialized transform_applied flag.
- *
- * Could be solved by moving reference counter to Geometry.
- */
- Geometry *geom = object->geometry;
- bool apply = (geometry_users[geom] == 1) && !geom->has_surface_bssrdf &&
- !geom->has_true_displacement();
-
- if (geom->geometry_type == Geometry::MESH) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- apply = apply && mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE;
- }
- else if (geom->geometry_type == Geometry::HAIR) {
- /* Can't apply non-uniform scale to curves, this can't be represented by
- * control points and radius alone. */
- float scale;
- apply = apply && transform_uniform_scale(object->tfm, scale);
- }
-
- if (apply) {
- if (!(motion_blur && object->use_motion())) {
- if (!geom->transform_applied) {
- object->apply_transform(apply_to_motion);
- geom->transform_applied = true;
-
- if (progress.get_cancel())
- return;
- }
-
- object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED;
- if (geom->transform_negative_scaled)
- object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED;
- }
- }
-
- i++;
- }
-}
-
-void ObjectManager::tag_update(Scene *scene, uint32_t flag)
-{
- update_flags |= flag;
-
- /* avoid infinite loops if the geometry manager tagged us for an update */
- if ((flag & GEOMETRY_MANAGER) == 0) {
- uint32_t geometry_flag = GeometryManager::OBJECT_MANAGER;
-
- /* Also notify in case added or removed objects were instances, as no Geometry might have been
- * added or removed, but the BVH still needs to updated. */
- if ((flag & (OBJECT_ADDED | OBJECT_REMOVED)) != 0) {
- geometry_flag |= (GeometryManager::GEOMETRY_ADDED | GeometryManager::GEOMETRY_REMOVED);
- }
-
- if ((flag & TRANSFORM_MODIFIED) != 0) {
- geometry_flag |= GeometryManager::TRANSFORM_MODIFIED;
- }
-
- if ((flag & VISIBILITY_MODIFIED) != 0) {
- geometry_flag |= GeometryManager::VISIBILITY_MODIFIED;
- }
-
- scene->geometry_manager->tag_update(scene, geometry_flag);
- }
-
- scene->light_manager->tag_update(scene, LightManager::OBJECT_MANAGER);
-
- /* Integrator's shadow catcher settings depends on object visibility settings. */
- if (flag & (OBJECT_ADDED | OBJECT_REMOVED | OBJECT_MODIFIED)) {
- scene->integrator->tag_update(scene, Integrator::OBJECT_MANAGER);
- }
-}
-
-bool ObjectManager::need_update() const
-{
- return update_flags != UPDATE_NONE;
-}
-
-string ObjectManager::get_cryptomatte_objects(Scene *scene)
-{
- string manifest = "{";
-
- unordered_set<ustring, ustringHash> objects;
- foreach (Object *object, scene->objects) {
- if (objects.count(object->name)) {
- continue;
- }
- objects.insert(object->name);
- uint32_t hash_name = util_murmur_hash3(object->name.c_str(), object->name.length(), 0);
- manifest += string_printf("\"%s\":\"%08x\",", object->name.c_str(), hash_name);
- }
- manifest[manifest.size() - 1] = '}';
- return manifest;
-}
-
-string ObjectManager::get_cryptomatte_assets(Scene *scene)
-{
- string manifest = "{";
- unordered_set<ustring, ustringHash> assets;
- foreach (Object *ob, scene->objects) {
- if (assets.count(ob->asset_name)) {
- continue;
- }
- assets.insert(ob->asset_name);
- uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
- manifest += string_printf("\"%s\":\"%08x\",", ob->asset_name.c_str(), hash_asset);
- }
- manifest[manifest.size() - 1] = '}';
- return manifest;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
deleted file mode 100644
index 6920f2c1f1c..00000000000
--- a/intern/cycles/render/object.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __OBJECT_H__
-#define __OBJECT_H__
-
-#include "graph/node.h"
-
-/* included as Object::set_particle_system defined through NODE_SOCKET_API does
- * not select the right Node::set overload as it does not know that ParticleSystem
- * is a Node */
-#include "render/particles.h"
-#include "render/scene.h"
-
-#include "util/util_array.h"
-#include "util/util_boundbox.h"
-#include "util/util_param.h"
-#include "util/util_thread.h"
-#include "util/util_transform.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class Geometry;
-class ParticleSystem;
-class Progress;
-class Scene;
-struct Transform;
-struct UpdateObjectTransformState;
-class ObjectManager;
-
-/* Object */
-
-class Object : public Node {
- public:
- NODE_DECLARE
-
- NODE_SOCKET_API(Geometry *, geometry)
- NODE_SOCKET_API(Transform, tfm)
- BoundBox bounds;
- NODE_SOCKET_API(uint, random_id)
- NODE_SOCKET_API(int, pass_id)
- NODE_SOCKET_API(float3, color)
- NODE_SOCKET_API(ustring, asset_name)
- vector<ParamValue> attributes;
- NODE_SOCKET_API(uint, visibility)
- NODE_SOCKET_API_ARRAY(array<Transform>, motion)
- NODE_SOCKET_API(bool, hide_on_missing_motion)
- NODE_SOCKET_API(bool, use_holdout)
- NODE_SOCKET_API(bool, is_shadow_catcher)
- NODE_SOCKET_API(float, shadow_terminator_shading_offset)
- NODE_SOCKET_API(float, shadow_terminator_geometry_offset)
-
- NODE_SOCKET_API(float3, dupli_generated)
- NODE_SOCKET_API(float2, dupli_uv)
-
- NODE_SOCKET_API(ParticleSystem *, particle_system);
- NODE_SOCKET_API(int, particle_index);
-
- NODE_SOCKET_API(float, ao_distance)
-
- Object();
- ~Object();
-
- void tag_update(Scene *scene);
-
- void compute_bounds(bool motion_blur);
- void apply_transform(bool apply_to_motion);
-
- /* Convert between normalized -1..1 motion time and index
- * in the motion array. */
- bool use_motion() const;
- float motion_time(int step) const;
- int motion_step(float time) const;
- void update_motion();
-
- /* Maximum number of motion steps supported (due to Embree). */
- static const uint MAX_MOTION_STEPS = 129;
-
- /* Check whether object is traceable and it worth adding it to
- * kernel scene.
- */
- bool is_traceable() const;
-
- /* Combine object's visibility with all possible internal run-time
- * determined flags which denotes trace-time visibility.
- */
- uint visibility_for_tracing() const;
-
- /* Returns the index that is used in the kernel for this object. */
- int get_device_index() const;
-
- /* Compute step size from attributes, shaders, transforms. */
- float compute_volume_step_size() const;
-
- /* Check whether this object requires volume sampling (and hence might require space in the
- * volume stack).
- *
- * Note that this is a naive iteration over shaders, which allows to access information prior
- * to `scene_update()`. */
- bool check_is_volume() const;
-
- protected:
- /* Specifies the position of the object in scene->objects and
- * in the device vectors. Gets set in device_update. */
- int index;
-
- /* Reference to the attribute map with object attributes,
- * or 0 if none. Set in update_svm_attributes. */
- size_t attr_map_offset;
-
- friend class ObjectManager;
- friend class GeometryManager;
-};
-
-/* Object Manager */
-
-class ObjectManager {
- uint32_t update_flags;
-
- public:
- enum : uint32_t {
- PARTICLE_MODIFIED = (1 << 0),
- GEOMETRY_MANAGER = (1 << 1),
- MOTION_BLUR_MODIFIED = (1 << 2),
- OBJECT_ADDED = (1 << 3),
- OBJECT_REMOVED = (1 << 4),
- OBJECT_MODIFIED = (1 << 5),
- HOLDOUT_MODIFIED = (1 << 6),
- TRANSFORM_MODIFIED = (1 << 7),
- VISIBILITY_MODIFIED = (1 << 8),
-
- /* tag everything in the manager for an update */
- UPDATE_ALL = ~0u,
-
- UPDATE_NONE = 0u,
- };
-
- bool need_flags_update;
-
- ObjectManager();
- ~ObjectManager();
-
- void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
- void device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress);
-
- void device_update_flags(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress,
- bool bounds_valid = true);
- void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene);
-
- void device_free(Device *device, DeviceScene *dscene, bool force_free);
-
- void tag_update(Scene *scene, uint32_t flag);
-
- bool need_update() const;
-
- void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress);
-
- string get_cryptomatte_objects(Scene *scene);
- string get_cryptomatte_assets(Scene *scene);
-
- protected:
- void device_update_object_transform(UpdateObjectTransformState *state,
- Object *ob,
- bool update_all);
- void device_update_object_transform_task(UpdateObjectTransformState *state);
- bool device_update_object_transform_pop_work(UpdateObjectTransformState *state,
- int *start_index,
- int *num_objects);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __OBJECT_H__ */
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
deleted file mode 100644
index dd8f1b31177..00000000000
--- a/intern/cycles/render/osl.cpp
+++ /dev/null
@@ -1,1324 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "device/device.h"
-
-#include "render/background.h"
-#include "render/colorspace.h"
-#include "render/graph.h"
-#include "render/light.h"
-#include "render/nodes.h"
-#include "render/osl.h"
-#include "render/scene.h"
-#include "render/shader.h"
-#include "render/stats.h"
-
-#ifdef WITH_OSL
-
-# include "kernel/osl/osl_globals.h"
-# include "kernel/osl/osl_services.h"
-# include "kernel/osl/osl_shader.h"
-
-# include "util/util_aligned_malloc.h"
-# include "util/util_foreach.h"
-# include "util/util_logging.h"
-# include "util/util_md5.h"
-# include "util/util_path.h"
-# include "util/util_progress.h"
-# include "util/util_projection.h"
-
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef WITH_OSL
-
-/* Shared Texture and Shading System */
-
-OSL::TextureSystem *OSLShaderManager::ts_shared = NULL;
-int OSLShaderManager::ts_shared_users = 0;
-thread_mutex OSLShaderManager::ts_shared_mutex;
-
-OSL::ShadingSystem *OSLShaderManager::ss_shared = NULL;
-OSLRenderServices *OSLShaderManager::services_shared = NULL;
-int OSLShaderManager::ss_shared_users = 0;
-thread_mutex OSLShaderManager::ss_shared_mutex;
-thread_mutex OSLShaderManager::ss_mutex;
-int OSLCompiler::texture_shared_unique_id = 0;
-
-/* Shader Manager */
-
-OSLShaderManager::OSLShaderManager()
-{
- texture_system_init();
- shading_system_init();
-}
-
-OSLShaderManager::~OSLShaderManager()
-{
- shading_system_free();
- texture_system_free();
-}
-
-void OSLShaderManager::free_memory()
-{
-# ifdef OSL_HAS_BLENDER_CLEANUP_FIX
- /* There is a problem with LLVM+OSL: The order global destructors across
- * different compilation units run cannot be guaranteed, on windows this means
- * that the LLVM destructors run before the osl destructors, causing a crash
- * when the process exits. the OSL in svn has a special cleanup hack to
- * sidestep this behavior */
- OSL::pvt::LLVM_Util::Cleanup();
-# endif
-}
-
-void OSLShaderManager::reset(Scene * /*scene*/)
-{
- shading_system_free();
- shading_system_init();
-}
-
-void OSLShaderManager::host_update_specific(Scene *scene, Progress &progress)
-{
- if (!need_update()) {
- return;
- }
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->osl.times.add_entry({"host_update", time});
- }
- });
-
- VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
-
- /* set texture system */
- scene->image_manager->set_osl_texture_system((void *)ts);
-
- /* create shaders */
- Shader *background_shader = scene->background->get_shader(scene);
-
- for (Shader *shader : scene->shaders) {
- assert(shader->graph);
-
- if (progress.get_cancel()) {
- return;
- }
-
- /* we can only compile one shader at the time as the OSL ShadingSystem
- * has a single state, but we put the lock here so different renders can
- * compile shaders alternating */
- thread_scoped_lock lock(ss_mutex);
-
- OSLCompiler compiler(this, services, ss, scene);
- compiler.background = (shader == background_shader);
- compiler.compile(shader);
-
- if (shader->get_use_mis() && shader->has_surface_emission) {
- scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
- }
- }
-
- /* add special builtin texture types */
- services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
- services->textures.insert(ustring("@bevel"), new OSLTextureHandle(OSLTextureHandle::BEVEL));
-
- {
- /* Perform greedyjit optimization.
- *
- * This might waste time on optimizing groups which are never actually
- * used, but this prevents OSL from allocating data on TLS at render
- * time.
- *
- * This is much better for us because this way we aren't required to
- * stop task scheduler threads to make sure all TLS is clean and don't
- * have issues with TLS data free accessing freed memory if task scheduler
- * is being freed after the Session is freed.
- */
- thread_scoped_lock lock(ss_shared_mutex);
- ss->optimize_all_groups();
- }
-}
-
-void OSLShaderManager::device_update_specific(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- if (!need_update())
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->osl.times.add_entry({"device_update", time});
- }
- });
-
- device_free(device, dscene, scene);
-
- OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
- Shader *background_shader = scene->background->get_shader(scene);
-
- /* Setup shader engine. */
- og->ss = ss;
- og->ts = ts;
- og->services = services;
-
- for (Shader *shader : scene->shaders) {
- /* push state to array for lookup */
- og->surface_state.push_back(shader->osl_surface_ref);
- og->volume_state.push_back(shader->osl_volume_ref);
- og->displacement_state.push_back(shader->osl_displacement_ref);
- og->bump_state.push_back(shader->osl_surface_bump_ref);
-
- shader->clear_modified();
- }
-
- const int background_id = scene->shader_manager->get_shader_id(background_shader);
- const int background_state_index = (background_id & SHADER_MASK);
- DCHECK_LT(background_state_index, og->surface_state.size());
- og->background_state = og->surface_state[background_state_index];
- og->use = true;
-
- update_flags = UPDATE_NONE;
-
- device_update_common(device, dscene, scene, progress);
-}
-
-void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
-{
- OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
-
- device_free_common(device, dscene, scene);
-
- /* clear shader engine */
- og->use = false;
- og->ss = NULL;
- og->ts = NULL;
-
- og->surface_state.clear();
- og->volume_state.clear();
- og->displacement_state.clear();
- og->bump_state.clear();
- og->background_state.reset();
-}
-
-void OSLShaderManager::texture_system_init()
-{
- /* create texture system, shared between different renders to reduce memory usage */
- thread_scoped_lock lock(ts_shared_mutex);
-
- if (ts_shared_users == 0) {
- ts_shared = TextureSystem::create(true);
-
- ts_shared->attribute("automip", 1);
- ts_shared->attribute("autotile", 64);
- ts_shared->attribute("gray_to_rgb", 1);
-
- /* effectively unlimited for now, until we support proper mipmap lookups */
- ts_shared->attribute("max_memory_MB", 16384);
- }
-
- ts = ts_shared;
- ts_shared_users++;
-}
-
-void OSLShaderManager::texture_system_free()
-{
- /* shared texture system decrease users and destroy if no longer used */
- thread_scoped_lock lock(ts_shared_mutex);
- ts_shared_users--;
-
- if (ts_shared_users == 0) {
- ts_shared->invalidate_all(true);
- OSL::TextureSystem::destroy(ts_shared);
- ts_shared = NULL;
- }
-
- ts = NULL;
-}
-
-void OSLShaderManager::shading_system_init()
-{
- /* create shading system, shared between different renders to reduce memory usage */
- thread_scoped_lock lock(ss_shared_mutex);
-
- if (ss_shared_users == 0) {
- /* Must use aligned new due to concurrent hash map. */
- services_shared = util_aligned_new<OSLRenderServices>(ts_shared);
-
- string shader_path = path_get("shader");
-# ifdef _WIN32
- /* Annoying thing, Cycles stores paths in UTF-8 codepage, so it can
- * operate with file paths with any character. This requires to use wide
- * char functions, but OSL uses old fashioned ANSI functions which means:
- *
- * - We have to convert our paths to ANSI before passing to OSL
- * - OSL can't be used when there's a multi-byte character in the path
- * to the shaders folder.
- */
- shader_path = string_to_ansi(shader_path);
-# endif
-
- ss_shared = new OSL::ShadingSystem(services_shared, ts_shared, &errhandler);
- ss_shared->attribute("lockgeom", 1);
- ss_shared->attribute("commonspace", "world");
- ss_shared->attribute("searchpath:shader", shader_path);
- ss_shared->attribute("greedyjit", 1);
-
- VLOG(1) << "Using shader search path: " << shader_path;
-
- /* our own ray types */
- static const char *raytypes[] = {
- "camera", /* PATH_RAY_CAMERA */
- "reflection", /* PATH_RAY_REFLECT */
- "refraction", /* PATH_RAY_TRANSMIT */
- "diffuse", /* PATH_RAY_DIFFUSE */
- "glossy", /* PATH_RAY_GLOSSY */
- "singular", /* PATH_RAY_SINGULAR */
- "transparent", /* PATH_RAY_TRANSPARENT */
- "volume_scatter", /* PATH_RAY_VOLUME_SCATTER */
-
- "shadow", /* PATH_RAY_SHADOW_OPAQUE */
- "shadow", /* PATH_RAY_SHADOW_TRANSPARENT */
-
- "__unused__", /* PATH_RAY_NODE_UNALIGNED */
- "__unused__", /* PATH_RAY_MIS_SKIP */
-
- "diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */
-
- "__unused__", /* PATH_RAY_SINGLE_PASS_DONE */
- "__unused__", /* PATH_RAY_TRANSPARENT_BACKGROUND */
- "__unused__", /* PATH_RAY_TERMINATE_IMMEDIATE */
- "__unused__", /* PATH_RAY_TERMINATE_AFTER_TRANSPARENT */
- "__unused__", /* PATH_RAY_EMISSION */
- "__unused__", /* PATH_RAY_SUBSURFACE */
- "__unused__", /* PATH_RAY_DENOISING_FEATURES */
- "__unused__", /* PATH_RAY_REFLECT_PASS */
- "__unused__", /* PATH_RAY_TRANSMISSION_PASS */
- "__unused__", /* PATH_RAY_VOLUME_PASS */
- "__unused__", /* PATH_RAY_SHADOW_FOR_LIGHT */
- "__unused__", /* PATH_RAY_SHADOW_CATCHER_HIT */
- "__unused__", /* PATH_RAY_SHADOW_CATCHER_PASS */
- };
-
- const int nraytypes = sizeof(raytypes) / sizeof(raytypes[0]);
- ss_shared->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes);
-
- OSLShader::register_closures((OSLShadingSystem *)ss_shared);
-
- loaded_shaders.clear();
- }
-
- ss = ss_shared;
- services = services_shared;
- ss_shared_users++;
-}
-
-void OSLShaderManager::shading_system_free()
-{
- /* shared shading system decrease users and destroy if no longer used */
- thread_scoped_lock lock(ss_shared_mutex);
- ss_shared_users--;
-
- if (ss_shared_users == 0) {
- delete ss_shared;
- ss_shared = NULL;
-
- util_aligned_delete(services_shared);
- services_shared = NULL;
- }
-
- ss = NULL;
- services = NULL;
-}
-
-bool OSLShaderManager::osl_compile(const string &inputfile, const string &outputfile)
-{
- vector<string> options;
- string stdosl_path;
- string shader_path = path_get("shader");
-
- /* specify output file name */
- options.push_back("-o");
- options.push_back(outputfile);
-
- /* specify standard include path */
- string include_path_arg = string("-I") + shader_path;
- options.push_back(include_path_arg);
-
- stdosl_path = path_join(shader_path, "stdcycles.h");
-
- /* compile */
- OSL::OSLCompiler *compiler = new OSL::OSLCompiler(&OSL::ErrorHandler::default_handler());
- bool ok = compiler->compile(string_view(inputfile), options, string_view(stdosl_path));
- delete compiler;
-
- return ok;
-}
-
-bool OSLShaderManager::osl_query(OSL::OSLQuery &query, const string &filepath)
-{
- string searchpath = path_user_get("shaders");
- return query.open(filepath, searchpath);
-}
-
-static string shader_filepath_hash(const string &filepath, uint64_t modified_time)
-{
- /* compute a hash from filepath and modified time to detect changes */
- MD5Hash md5;
- md5.append((const uint8_t *)filepath.c_str(), filepath.size());
- md5.append((const uint8_t *)&modified_time, sizeof(modified_time));
-
- return md5.get_hex();
-}
-
-const char *OSLShaderManager::shader_test_loaded(const string &hash)
-{
- map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
- return (it == loaded_shaders.end()) ? NULL : it->first.c_str();
-}
-
-OSLShaderInfo *OSLShaderManager::shader_loaded_info(const string &hash)
-{
- map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
- return (it == loaded_shaders.end()) ? NULL : &it->second;
-}
-
-const char *OSLShaderManager::shader_load_filepath(string filepath)
-{
- size_t len = filepath.size();
- string extension = filepath.substr(len - 4);
- uint64_t modified_time = path_modified_time(filepath);
-
- if (extension == ".osl") {
- /* .OSL File */
- string osopath = filepath.substr(0, len - 4) + ".oso";
- uint64_t oso_modified_time = path_modified_time(osopath);
-
- /* test if we have loaded the corresponding .OSO already */
- if (oso_modified_time != 0) {
- const char *hash = shader_test_loaded(shader_filepath_hash(osopath, oso_modified_time));
-
- if (hash)
- return hash;
- }
-
- /* Auto-compile .OSL to .OSO if needed. */
- if (oso_modified_time == 0 || (oso_modified_time < modified_time)) {
- OSLShaderManager::osl_compile(filepath, osopath);
- modified_time = path_modified_time(osopath);
- }
- else
- modified_time = oso_modified_time;
-
- filepath = osopath;
- }
- else {
- if (extension == ".oso") {
- /* .OSO File, nothing to do */
- }
- else if (path_dirname(filepath) == "") {
- /* .OSO File in search path */
- filepath = path_join(path_user_get("shaders"), filepath + ".oso");
- }
- else {
- /* unknown file */
- return NULL;
- }
-
- /* test if we have loaded this .OSO already */
- const char *hash = shader_test_loaded(shader_filepath_hash(filepath, modified_time));
-
- if (hash)
- return hash;
- }
-
- /* read oso bytecode from file */
- string bytecode_hash = shader_filepath_hash(filepath, modified_time);
- string bytecode;
-
- if (!path_read_text(filepath, bytecode)) {
- fprintf(stderr, "Cycles shader graph: failed to read file %s\n", filepath.c_str());
- OSLShaderInfo info;
- loaded_shaders[bytecode_hash] = info; /* to avoid repeat tries */
- return NULL;
- }
-
- return shader_load_bytecode(bytecode_hash, bytecode);
-}
-
-const char *OSLShaderManager::shader_load_bytecode(const string &hash, const string &bytecode)
-{
- ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str());
-
- OSLShaderInfo info;
-
- if (!info.query.open_bytecode(bytecode)) {
- fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str());
- }
-
- /* this is a bit weak, but works */
- info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
- info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
- info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
-
- loaded_shaders[hash] = info;
-
- return loaded_shaders.find(hash)->first.c_str();
-}
-
-/* This is a static function to avoid RTTI link errors with only this
- * file being compiled without RTTI to match OSL and LLVM libraries. */
-OSLNode *OSLShaderManager::osl_node(ShaderGraph *graph,
- ShaderManager *manager,
- const std::string &filepath,
- const std::string &bytecode_hash,
- const std::string &bytecode)
-{
- if (!manager->use_osl()) {
- return NULL;
- }
-
- /* create query */
- OSLShaderManager *osl_manager = static_cast<OSLShaderManager *>(manager);
- const char *hash;
-
- if (!filepath.empty()) {
- hash = osl_manager->shader_load_filepath(filepath);
- }
- else {
- hash = osl_manager->shader_test_loaded(bytecode_hash);
- if (!hash)
- hash = osl_manager->shader_load_bytecode(bytecode_hash, bytecode);
- }
-
- if (!hash) {
- return NULL;
- }
-
- OSLShaderInfo *info = osl_manager->shader_loaded_info(hash);
-
- /* count number of inputs */
- size_t num_inputs = 0;
-
- for (int i = 0; i < info->query.nparams(); i++) {
- const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
-
- /* skip unsupported types */
- if (param->varlenarray || param->isstruct || param->type.arraylen > 1)
- continue;
-
- if (!param->isoutput)
- num_inputs++;
- }
-
- /* create node */
- OSLNode *node = OSLNode::create(graph, num_inputs);
-
- /* add new sockets from parameters */
- set<void *> used_sockets;
-
- for (int i = 0; i < info->query.nparams(); i++) {
- const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
-
- /* skip unsupported types */
- if (param->varlenarray || param->isstruct || param->type.arraylen > 1)
- continue;
-
- SocketType::Type socket_type;
-
- if (param->isclosure) {
- socket_type = SocketType::CLOSURE;
- }
- else if (param->type.vecsemantics != TypeDesc::NOSEMANTICS) {
- if (param->type.vecsemantics == TypeDesc::COLOR)
- socket_type = SocketType::COLOR;
- else if (param->type.vecsemantics == TypeDesc::POINT)
- socket_type = SocketType::POINT;
- else if (param->type.vecsemantics == TypeDesc::VECTOR)
- socket_type = SocketType::VECTOR;
- else if (param->type.vecsemantics == TypeDesc::NORMAL)
- socket_type = SocketType::NORMAL;
- else
- continue;
-
- if (!param->isoutput && param->validdefault) {
- float3 *default_value = (float3 *)node->input_default_value();
- default_value->x = param->fdefault[0];
- default_value->y = param->fdefault[1];
- default_value->z = param->fdefault[2];
- }
- }
- else if (param->type.aggregate == TypeDesc::SCALAR) {
- if (param->type.basetype == TypeDesc::INT) {
- socket_type = SocketType::INT;
-
- if (!param->isoutput && param->validdefault) {
- *(int *)node->input_default_value() = param->idefault[0];
- }
- }
- else if (param->type.basetype == TypeDesc::FLOAT) {
- socket_type = SocketType::FLOAT;
-
- if (!param->isoutput && param->validdefault) {
- *(float *)node->input_default_value() = param->fdefault[0];
- }
- }
- else if (param->type.basetype == TypeDesc::STRING) {
- socket_type = SocketType::STRING;
-
- if (!param->isoutput && param->validdefault) {
- *(ustring *)node->input_default_value() = param->sdefault[0];
- }
- }
- else
- continue;
- }
- else
- continue;
-
- if (param->isoutput) {
- node->add_output(param->name, socket_type);
- }
- else {
- node->add_input(param->name, socket_type);
- }
- }
-
- /* Set byte-code hash or file-path. */
- if (!bytecode_hash.empty()) {
- node->bytecode_hash = bytecode_hash;
- }
- else {
- node->filepath = filepath;
- }
-
- /* Generate inputs and outputs */
- node->create_inputs_outputs(node->type);
-
- return node;
-}
-
-/* Graph Compiler */
-
-OSLCompiler::OSLCompiler(OSLShaderManager *manager,
- OSLRenderServices *services,
- OSL::ShadingSystem *ss,
- Scene *scene)
- : scene(scene), manager(manager), services(services), ss(ss)
-{
- current_type = SHADER_TYPE_SURFACE;
- current_shader = NULL;
- background = false;
-}
-
-string OSLCompiler::id(ShaderNode *node)
-{
- /* assign layer unique name based on pointer address + bump mode */
- stringstream stream;
- stream << "node_" << node->type->name << "_" << node;
-
- return stream.str();
-}
-
-string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
-{
- string sname(input->name().string());
- size_t i;
-
- /* Strip white-space. */
- while ((i = sname.find(" ")) != string::npos)
- sname.replace(i, 1, "");
-
- /* if output exists with the same name, add "In" suffix */
- foreach (ShaderOutput *output, node->outputs) {
- if (input->name() == output->name()) {
- sname += "In";
- break;
- }
- }
-
- return sname;
-}
-
-string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
-{
- string sname(output->name().string());
- size_t i;
-
- /* Strip white-space. */
- while ((i = sname.find(" ")) != string::npos)
- sname.replace(i, 1, "");
-
- /* if input exists with the same name, add "Out" suffix */
- foreach (ShaderInput *input, node->inputs) {
- if (input->name() == output->name()) {
- sname += "Out";
- break;
- }
- }
-
- return sname;
-}
-
-bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
-{
- /* exception for output node, only one input is actually used
- * depending on the current shader type */
-
- if (input->flags() & SocketType::SVM_INTERNAL)
- return true;
-
- if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) {
- if (input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE)
- return true;
- if (input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME)
- return true;
- if (input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT)
- return true;
- if (input->name() == "Normal" && current_type != SHADER_TYPE_BUMP)
- return true;
- }
- else if (node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
- if (input->name() == "Height")
- return true;
- }
- else if (current_type == SHADER_TYPE_DISPLACEMENT && input->link &&
- input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
- return true;
-
- return false;
-}
-
-void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
-{
- /* load filepath */
- if (isfilepath) {
- name = manager->shader_load_filepath(name);
-
- if (name == NULL)
- return;
- }
-
- /* pass in fixed parameter values */
- foreach (ShaderInput *input, node->inputs) {
- if (!input->link) {
- /* checks to untangle graphs */
- if (node_skip_input(node, input))
- continue;
-
- string param_name = compatible_name(node, input);
- const SocketType &socket = input->socket_type;
- switch (input->type()) {
- case SocketType::COLOR:
- parameter_color(param_name.c_str(), node->get_float3(socket));
- break;
- case SocketType::POINT:
- parameter_point(param_name.c_str(), node->get_float3(socket));
- break;
- case SocketType::VECTOR:
- parameter_vector(param_name.c_str(), node->get_float3(socket));
- break;
- case SocketType::NORMAL:
- parameter_normal(param_name.c_str(), node->get_float3(socket));
- break;
- case SocketType::FLOAT:
- parameter(param_name.c_str(), node->get_float(socket));
- break;
- case SocketType::INT:
- parameter(param_name.c_str(), node->get_int(socket));
- break;
- case SocketType::STRING:
- parameter(param_name.c_str(), node->get_string(socket));
- break;
- case SocketType::CLOSURE:
- case SocketType::UNDEFINED:
- default:
- break;
- }
- }
- }
-
- /* Create shader of the appropriate type. OSL only distinguishes between "surface"
- * and "displacement" at the moment. */
- if (current_type == SHADER_TYPE_SURFACE)
- ss->Shader("surface", name, id(node).c_str());
- else if (current_type == SHADER_TYPE_VOLUME)
- ss->Shader("surface", name, id(node).c_str());
- else if (current_type == SHADER_TYPE_DISPLACEMENT)
- ss->Shader("displacement", name, id(node).c_str());
- else if (current_type == SHADER_TYPE_BUMP)
- ss->Shader("displacement", name, id(node).c_str());
- else
- assert(0);
-
- /* link inputs to other nodes */
- foreach (ShaderInput *input, node->inputs) {
- if (input->link) {
- if (node_skip_input(node, input))
- continue;
-
- /* connect shaders */
- string id_from = id(input->link->parent);
- string id_to = id(node);
- string param_from = compatible_name(input->link->parent, input->link);
- string param_to = compatible_name(node, input);
-
- ss->ConnectShaders(id_from.c_str(), param_from.c_str(), id_to.c_str(), param_to.c_str());
- }
- }
-
- /* test if we shader contains specific closures */
- OSLShaderInfo *info = manager->shader_loaded_info(name);
-
- if (current_type == SHADER_TYPE_SURFACE) {
- if (info) {
- if (info->has_surface_emission)
- current_shader->has_surface_emission = true;
- if (info->has_surface_transparent)
- current_shader->has_surface_transparent = true;
- if (info->has_surface_bssrdf) {
- current_shader->has_surface_bssrdf = true;
- current_shader->has_bssrdf_bump = true; /* can't detect yet */
- }
- current_shader->has_bump = true; /* can't detect yet */
- current_shader->has_surface_raytrace = true; /* can't detect yet */
- }
-
- if (node->has_spatial_varying()) {
- current_shader->has_surface_spatial_varying = true;
- }
- }
- else if (current_type == SHADER_TYPE_VOLUME) {
- if (node->has_spatial_varying())
- current_shader->has_volume_spatial_varying = true;
- if (node->has_attribute_dependency())
- current_shader->has_volume_attribute_dependency = true;
- }
-
- if (node->has_integrator_dependency()) {
- current_shader->has_integrator_dependency = true;
- }
-}
-
-static TypeDesc array_typedesc(TypeDesc typedesc, int arraylength)
-{
- return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype,
- (TypeDesc::AGGREGATE)typedesc.aggregate,
- (TypeDesc::VECSEMANTICS)typedesc.vecsemantics,
- arraylength);
-}
-
-void OSLCompiler::parameter(ShaderNode *node, const char *name)
-{
- ustring uname = ustring(name);
- const SocketType &socket = *(node->type->find_input(uname));
-
- switch (socket.type) {
- case SocketType::BOOLEAN: {
- int value = node->get_bool(socket);
- ss->Parameter(name, TypeDesc::TypeInt, &value);
- break;
- }
- case SocketType::FLOAT: {
- float value = node->get_float(socket);
- ss->Parameter(uname, TypeDesc::TypeFloat, &value);
- break;
- }
- case SocketType::INT: {
- int value = node->get_int(socket);
- ss->Parameter(uname, TypeDesc::TypeInt, &value);
- break;
- }
- case SocketType::COLOR: {
- float3 value = node->get_float3(socket);
- ss->Parameter(uname, TypeDesc::TypeColor, &value);
- break;
- }
- case SocketType::VECTOR: {
- float3 value = node->get_float3(socket);
- ss->Parameter(uname, TypeDesc::TypeVector, &value);
- break;
- }
- case SocketType::POINT: {
- float3 value = node->get_float3(socket);
- ss->Parameter(uname, TypeDesc::TypePoint, &value);
- break;
- }
- case SocketType::NORMAL: {
- float3 value = node->get_float3(socket);
- ss->Parameter(uname, TypeDesc::TypeNormal, &value);
- break;
- }
- case SocketType::POINT2: {
- float2 value = node->get_float2(socket);
- ss->Parameter(uname, TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), &value);
- break;
- }
- case SocketType::STRING: {
- ustring value = node->get_string(socket);
- ss->Parameter(uname, TypeDesc::TypeString, &value);
- break;
- }
- case SocketType::ENUM: {
- ustring value = node->get_string(socket);
- ss->Parameter(uname, TypeDesc::TypeString, &value);
- break;
- }
- case SocketType::TRANSFORM: {
- Transform value = node->get_transform(socket);
- ProjectionTransform projection(value);
- projection = projection_transpose(projection);
- ss->Parameter(uname, TypeDesc::TypeMatrix, &projection);
- break;
- }
- case SocketType::BOOLEAN_ARRAY: {
- // OSL does not support booleans, so convert to int
- const array<bool> &value = node->get_bool_array(socket);
- array<int> intvalue(value.size());
- for (size_t i = 0; i < value.size(); i++)
- intvalue[i] = value[i];
- ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), intvalue.data());
- break;
- }
- case SocketType::FLOAT_ARRAY: {
- const array<float> &value = node->get_float_array(socket);
- ss->Parameter(uname, array_typedesc(TypeDesc::TypeFloat, value.size()), value.data());
- break;
- }
- case SocketType::INT_ARRAY: {
- const array<int> &value = node->get_int_array(socket);
- ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), value.data());
- break;
- }
- case SocketType::COLOR_ARRAY:
- case SocketType::VECTOR_ARRAY:
- case SocketType::POINT_ARRAY:
- case SocketType::NORMAL_ARRAY: {
- TypeDesc typedesc;
-
- switch (socket.type) {
- case SocketType::COLOR_ARRAY:
- typedesc = TypeDesc::TypeColor;
- break;
- case SocketType::VECTOR_ARRAY:
- typedesc = TypeDesc::TypeVector;
- break;
- case SocketType::POINT_ARRAY:
- typedesc = TypeDesc::TypePoint;
- break;
- case SocketType::NORMAL_ARRAY:
- typedesc = TypeDesc::TypeNormal;
- break;
- default:
- assert(0);
- break;
- }
-
- // convert to tightly packed array since float3 has padding
- const array<float3> &value = node->get_float3_array(socket);
- array<float> fvalue(value.size() * 3);
- for (size_t i = 0, j = 0; i < value.size(); i++) {
- fvalue[j++] = value[i].x;
- fvalue[j++] = value[i].y;
- fvalue[j++] = value[i].z;
- }
-
- ss->Parameter(uname, array_typedesc(typedesc, value.size()), fvalue.data());
- break;
- }
- case SocketType::POINT2_ARRAY: {
- const array<float2> &value = node->get_float2_array(socket);
- ss->Parameter(
- uname,
- array_typedesc(TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), value.size()),
- value.data());
- break;
- }
- case SocketType::STRING_ARRAY: {
- const array<ustring> &value = node->get_string_array(socket);
- ss->Parameter(uname, array_typedesc(TypeDesc::TypeString, value.size()), value.data());
- break;
- }
- case SocketType::TRANSFORM_ARRAY: {
- const array<Transform> &value = node->get_transform_array(socket);
- array<ProjectionTransform> fvalue(value.size());
- for (size_t i = 0; i < value.size(); i++) {
- fvalue[i] = projection_transpose(ProjectionTransform(value[i]));
- }
- ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, fvalue.size()), fvalue.data());
- break;
- }
- case SocketType::CLOSURE:
- case SocketType::NODE:
- case SocketType::NODE_ARRAY:
- case SocketType::UNDEFINED:
- case SocketType::UINT: {
- assert(0);
- break;
- }
- }
-}
-
-void OSLCompiler::parameter(const char *name, float f)
-{
- ss->Parameter(name, TypeDesc::TypeFloat, &f);
-}
-
-void OSLCompiler::parameter_color(const char *name, float3 f)
-{
- ss->Parameter(name, TypeDesc::TypeColor, &f);
-}
-
-void OSLCompiler::parameter_point(const char *name, float3 f)
-{
- ss->Parameter(name, TypeDesc::TypePoint, &f);
-}
-
-void OSLCompiler::parameter_normal(const char *name, float3 f)
-{
- ss->Parameter(name, TypeDesc::TypeNormal, &f);
-}
-
-void OSLCompiler::parameter_vector(const char *name, float3 f)
-{
- ss->Parameter(name, TypeDesc::TypeVector, &f);
-}
-
-void OSLCompiler::parameter(const char *name, int f)
-{
- ss->Parameter(name, TypeDesc::TypeInt, &f);
-}
-
-void OSLCompiler::parameter(const char *name, const char *s)
-{
- ss->Parameter(name, TypeDesc::TypeString, &s);
-}
-
-void OSLCompiler::parameter(const char *name, ustring s)
-{
- const char *str = s.c_str();
- ss->Parameter(name, TypeDesc::TypeString, &str);
-}
-
-void OSLCompiler::parameter(const char *name, const Transform &tfm)
-{
- ProjectionTransform projection(tfm);
- projection = projection_transpose(projection);
- ss->Parameter(name, TypeDesc::TypeMatrix, (float *)&projection);
-}
-
-void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
-{
- TypeDesc type = TypeDesc::TypeFloat;
- type.arraylen = arraylen;
- ss->Parameter(name, type, f);
-}
-
-void OSLCompiler::parameter_color_array(const char *name, const array<float3> &f)
-{
- /* NOTE: cycles float3 type is actually 4 floats! need to use an explicit array. */
- array<float[3]> table(f.size());
-
- for (int i = 0; i < f.size(); ++i) {
- table[i][0] = f[i].x;
- table[i][1] = f[i].y;
- table[i][2] = f[i].z;
- }
-
- TypeDesc type = TypeDesc::TypeColor;
- type.arraylen = table.size();
- ss->Parameter(name, type, table.data());
-}
-
-void OSLCompiler::parameter_attribute(const char *name, ustring s)
-{
- if (Attribute::name_standard(s.c_str()))
- parameter(name, (string("geom:") + s.c_str()).c_str());
- else
- parameter(name, s.c_str());
-}
-
-void OSLCompiler::find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input)
-{
- ShaderNode *node = (input->link) ? input->link->parent : NULL;
-
- if (node != NULL && dependencies.find(node) == dependencies.end()) {
- foreach (ShaderInput *in, node->inputs)
- if (!node_skip_input(node, in))
- find_dependencies(dependencies, in);
-
- dependencies.insert(node);
- }
-}
-
-void OSLCompiler::generate_nodes(const ShaderNodeSet &nodes)
-{
- ShaderNodeSet done;
- bool nodes_done;
-
- do {
- nodes_done = true;
-
- foreach (ShaderNode *node, nodes) {
- if (done.find(node) == done.end()) {
- bool inputs_done = true;
-
- foreach (ShaderInput *input, node->inputs)
- if (!node_skip_input(node, input))
- if (input->link && done.find(input->link->parent) == done.end())
- inputs_done = false;
-
- if (inputs_done) {
- node->compile(*this);
- done.insert(node);
-
- if (current_type == SHADER_TYPE_SURFACE) {
- if (node->has_surface_emission())
- current_shader->has_surface_emission = true;
- if (node->has_surface_transparent())
- current_shader->has_surface_transparent = true;
- if (node->get_feature() & KERNEL_FEATURE_NODE_RAYTRACE)
- current_shader->has_surface_raytrace = true;
- if (node->has_spatial_varying())
- current_shader->has_surface_spatial_varying = true;
- if (node->has_surface_bssrdf()) {
- current_shader->has_surface_bssrdf = true;
- if (node->has_bssrdf_bump())
- current_shader->has_bssrdf_bump = true;
- }
- if (node->has_bump()) {
- current_shader->has_bump = true;
- }
- }
- else if (current_type == SHADER_TYPE_VOLUME) {
- if (node->has_spatial_varying())
- current_shader->has_volume_spatial_varying = true;
- }
- }
- else
- nodes_done = false;
- }
- }
- } while (!nodes_done);
-}
-
-OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
-{
- current_type = type;
-
- OSL::ShaderGroupRef group = ss->ShaderGroupBegin(shader->name.c_str());
-
- ShaderNode *output = graph->output();
- ShaderNodeSet dependencies;
-
- if (type == SHADER_TYPE_SURFACE) {
- /* generate surface shader */
- find_dependencies(dependencies, output->input("Surface"));
- generate_nodes(dependencies);
- output->compile(*this);
- }
- else if (type == SHADER_TYPE_BUMP) {
- /* generate bump shader */
- find_dependencies(dependencies, output->input("Normal"));
- generate_nodes(dependencies);
- output->compile(*this);
- }
- else if (type == SHADER_TYPE_VOLUME) {
- /* generate volume shader */
- find_dependencies(dependencies, output->input("Volume"));
- generate_nodes(dependencies);
- output->compile(*this);
- }
- else if (type == SHADER_TYPE_DISPLACEMENT) {
- /* generate displacement shader */
- find_dependencies(dependencies, output->input("Displacement"));
- generate_nodes(dependencies);
- output->compile(*this);
- }
- else
- assert(0);
-
- ss->ShaderGroupEnd();
-
- return group;
-}
-
-void OSLCompiler::compile(Shader *shader)
-{
- if (shader->is_modified()) {
- ShaderGraph *graph = shader->graph;
- ShaderNode *output = (graph) ? graph->output() : NULL;
-
- bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) &&
- output->input("Surface")->link && output->input("Displacement")->link;
-
- /* finalize */
- shader->graph->finalize(scene,
- has_bump,
- shader->has_integrator_dependency,
- shader->get_displacement_method() == DISPLACE_BOTH);
-
- current_shader = shader;
-
- shader->has_surface = false;
- shader->has_surface_emission = false;
- shader->has_surface_transparent = false;
- shader->has_surface_bssrdf = false;
- shader->has_bump = has_bump;
- shader->has_bssrdf_bump = has_bump;
- shader->has_volume = false;
- shader->has_displacement = false;
- shader->has_surface_spatial_varying = false;
- shader->has_volume_spatial_varying = false;
- shader->has_volume_attribute_dependency = false;
- shader->has_integrator_dependency = false;
-
- /* generate surface shader */
- if (shader->reference_count() && graph && output->input("Surface")->link) {
- shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
-
- if (has_bump)
- shader->osl_surface_bump_ref = compile_type(shader, shader->graph, SHADER_TYPE_BUMP);
- else
- shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
-
- shader->has_surface = true;
- }
- else {
- shader->osl_surface_ref = OSL::ShaderGroupRef();
- shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
- }
-
- /* generate volume shader */
- if (shader->reference_count() && graph && output->input("Volume")->link) {
- shader->osl_volume_ref = compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
- shader->has_volume = true;
- }
- else
- shader->osl_volume_ref = OSL::ShaderGroupRef();
-
- /* generate displacement shader */
- if (shader->reference_count() && graph && output->input("Displacement")->link) {
- shader->osl_displacement_ref = compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
- shader->has_displacement = true;
- }
- else
- shader->osl_displacement_ref = OSL::ShaderGroupRef();
- }
-}
-
-void OSLCompiler::parameter_texture(const char *name, ustring filename, ustring colorspace)
-{
- /* Textured loaded through the OpenImageIO texture cache. For this
- * case we need to do runtime color space conversion. */
- OSLTextureHandle *handle = new OSLTextureHandle(OSLTextureHandle::OIIO);
- handle->processor = ColorSpaceManager::get_processor(colorspace);
- services->textures.insert(filename, handle);
- parameter(name, filename);
-}
-
-void OSLCompiler::parameter_texture(const char *name, int svm_slot)
-{
- /* Texture loaded through SVM image texture system. We generate a unique
- * name, which ends up being used in OSLRenderServices::get_texture_handle
- * to get handle again. Note that this name must be unique between multiple
- * render sessions as the render services are shared. */
- ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
- services->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::SVM, svm_slot));
- parameter(name, filename);
-}
-
-void OSLCompiler::parameter_texture_ies(const char *name, int svm_slot)
-{
- /* IES light textures stored in SVM. */
- ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
- services->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::IES, svm_slot));
- parameter(name, filename);
-}
-
-#else
-
-void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfilepath*/)
-{
-}
-
-void OSLCompiler::parameter(ShaderNode * /*node*/, const char * /*name*/)
-{
-}
-
-void OSLCompiler::parameter(const char * /*name*/, float /*f*/)
-{
-}
-
-void OSLCompiler::parameter_color(const char * /*name*/, float3 /*f*/)
-{
-}
-
-void OSLCompiler::parameter_vector(const char * /*name*/, float3 /*f*/)
-{
-}
-
-void OSLCompiler::parameter_point(const char * /*name*/, float3 /*f*/)
-{
-}
-
-void OSLCompiler::parameter_normal(const char * /*name*/, float3 /*f*/)
-{
-}
-
-void OSLCompiler::parameter(const char * /*name*/, int /*f*/)
-{
-}
-
-void OSLCompiler::parameter(const char * /*name*/, const char * /*s*/)
-{
-}
-
-void OSLCompiler::parameter(const char * /*name*/, ustring /*s*/)
-{
-}
-
-void OSLCompiler::parameter(const char * /*name*/, const Transform & /*tfm*/)
-{
-}
-
-void OSLCompiler::parameter_array(const char * /*name*/, const float /*f*/[], int /*arraylen*/)
-{
-}
-
-void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float3> & /*f*/)
-{
-}
-
-void OSLCompiler::parameter_texture(const char * /* name */,
- ustring /* filename */,
- ustring /* colorspace */)
-{
-}
-
-void OSLCompiler::parameter_texture(const char * /* name */, int /* svm_slot */)
-{
-}
-
-void OSLCompiler::parameter_texture_ies(const char * /* name */, int /* svm_slot */)
-{
-}
-
-#endif /* WITH_OSL */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
deleted file mode 100644
index 1da8d8d0026..00000000000
--- a/intern/cycles/render/osl.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __OSL_H__
-#define __OSL_H__
-
-#include "util/util_array.h"
-#include "util/util_set.h"
-#include "util/util_string.h"
-#include "util/util_thread.h"
-
-#include "render/graph.h"
-#include "render/nodes.h"
-#include "render/shader.h"
-
-#ifdef WITH_OSL
-# include <OSL/llvm_util.h>
-# include <OSL/oslcomp.h>
-# include <OSL/oslexec.h>
-# include <OSL/oslquery.h>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class ImageManager;
-class OSLRenderServices;
-struct OSLGlobals;
-class Scene;
-class ShaderGraph;
-class ShaderNode;
-class ShaderInput;
-class ShaderOutput;
-
-#ifdef WITH_OSL
-
-/* OSL Shader Info
- * to auto detect closures in the shader for MIS and transparent shadows */
-
-struct OSLShaderInfo {
- OSLShaderInfo()
- : has_surface_emission(false), has_surface_transparent(false), has_surface_bssrdf(false)
- {
- }
-
- OSL::OSLQuery query;
- bool has_surface_emission;
- bool has_surface_transparent;
- bool has_surface_bssrdf;
-};
-
-/* Shader Manage */
-
-class OSLShaderManager : public ShaderManager {
- public:
- OSLShaderManager();
- ~OSLShaderManager();
-
- static void free_memory();
-
- void reset(Scene *scene) override;
-
- bool use_osl() override
- {
- return true;
- }
-
- void host_update_specific(Scene *scene, Progress &progress) override;
-
- void device_update_specific(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress) override;
- void device_free(Device *device, DeviceScene *dscene, Scene *scene) override;
-
- /* osl compile and query */
- static bool osl_compile(const string &inputfile, const string &outputfile);
- static bool osl_query(OSL::OSLQuery &query, const string &filepath);
-
- /* shader file loading, all functions return pointer to hash string if found */
- const char *shader_test_loaded(const string &hash);
- const char *shader_load_bytecode(const string &hash, const string &bytecode);
- const char *shader_load_filepath(string filepath);
- OSLShaderInfo *shader_loaded_info(const string &hash);
-
- /* create OSL node using OSLQuery */
- static OSLNode *osl_node(ShaderGraph *graph,
- ShaderManager *manager,
- const std::string &filepath,
- const std::string &bytecode_hash = "",
- const std::string &bytecode = "");
-
- protected:
- void texture_system_init();
- void texture_system_free();
-
- void shading_system_init();
- void shading_system_free();
-
- OSL::ShadingSystem *ss;
- OSL::TextureSystem *ts;
- OSLRenderServices *services;
- OSL::ErrorHandler errhandler;
- map<string, OSLShaderInfo> loaded_shaders;
-
- static OSL::TextureSystem *ts_shared;
- static thread_mutex ts_shared_mutex;
- static int ts_shared_users;
-
- static OSL::ShadingSystem *ss_shared;
- static OSLRenderServices *services_shared;
- static thread_mutex ss_shared_mutex;
- static thread_mutex ss_mutex;
- static int ss_shared_users;
-};
-
-#endif
-
-/* Graph Compiler */
-
-class OSLCompiler {
- public:
-#ifdef WITH_OSL
- OSLCompiler(OSLShaderManager *manager,
- OSLRenderServices *services,
- OSL::ShadingSystem *shadingsys,
- Scene *scene);
-#endif
- void compile(Shader *shader);
-
- void add(ShaderNode *node, const char *name, bool isfilepath = false);
-
- void parameter(ShaderNode *node, const char *name);
-
- void parameter(const char *name, float f);
- void parameter_color(const char *name, float3 f);
- void parameter_vector(const char *name, float3 f);
- void parameter_normal(const char *name, float3 f);
- void parameter_point(const char *name, float3 f);
- void parameter(const char *name, int f);
- void parameter(const char *name, const char *s);
- void parameter(const char *name, ustring str);
- void parameter(const char *name, const Transform &tfm);
-
- void parameter_array(const char *name, const float f[], int arraylen);
- void parameter_color_array(const char *name, const array<float3> &f);
-
- void parameter_attribute(const char *name, ustring s);
-
- void parameter_texture(const char *name, ustring filename, ustring colorspace);
- void parameter_texture(const char *name, int svm_slot);
- void parameter_texture_ies(const char *name, int svm_slot);
-
- ShaderType output_type()
- {
- return current_type;
- }
-
- bool background;
- Scene *scene;
-
- private:
-#ifdef WITH_OSL
- string id(ShaderNode *node);
- OSL::ShaderGroupRef compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
- bool node_skip_input(ShaderNode *node, ShaderInput *input);
- string compatible_name(ShaderNode *node, ShaderInput *input);
- string compatible_name(ShaderNode *node, ShaderOutput *output);
-
- void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input);
- void generate_nodes(const ShaderNodeSet &nodes);
-
- OSLShaderManager *manager;
- OSLRenderServices *services;
- OSL::ShadingSystem *ss;
-#endif
-
- ShaderType current_type;
- Shader *current_shader;
-
- static int texture_shared_unique_id;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __OSL_H__ */
diff --git a/intern/cycles/render/output_driver.h b/intern/cycles/render/output_driver.h
deleted file mode 100644
index b7e980d71d4..00000000000
--- a/intern/cycles/render/output_driver.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "util/util_math.h"
-#include "util/util_string.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Output driver for reading render buffers.
- *
- * Host applications implement this interface for outputting render buffers for offline rendering.
- * Drivers can be used to copy the buffers into the host application or write them directly to
- * disk. This interface may also be used for interactive display, however the DisplayDriver is more
- * efficient for that purpose.
- */
-class OutputDriver {
- public:
- OutputDriver() = default;
- virtual ~OutputDriver() = default;
-
- class Tile {
- public:
- Tile(const int2 offset,
- const int2 size,
- const int2 full_size,
- const string_view layer,
- const string_view view)
- : offset(offset), size(size), full_size(full_size), layer(layer), view(view)
- {
- }
- virtual ~Tile() = default;
-
- const int2 offset;
- const int2 size;
- const int2 full_size;
- const string layer;
- const string view;
-
- virtual bool get_pass_pixels(const string_view pass_name,
- const int num_channels,
- float *pixels) const = 0;
- virtual bool set_pass_pixels(const string_view pass_name,
- const int num_channels,
- const float *pixels) const = 0;
- };
-
- /* Write tile once it has finished rendering. */
- virtual void write_render_tile(const Tile &tile) = 0;
-
- /* Update tile while rendering is in progress. Return true if any update
- * was performed. */
- virtual bool update_render_tile(const Tile & /* tile */)
- {
- return false;
- }
-
- /* For baking, read render pass PASS_BAKE_PRIMITIVE and PASS_BAKE_DIFFERENTIAL
- * to determine which shading points to use for baking at each pixel. Return
- * true if any data was read. */
- virtual bool read_render_tile(const Tile & /* tile */)
- {
- return false;
- }
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp
deleted file mode 100644
index 02dd1359b18..00000000000
--- a/intern/cycles/render/particles.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/particles.h"
-#include "device/device.h"
-#include "render/scene.h"
-#include "render/stats.h"
-
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-#include "util/util_logging.h"
-#include "util/util_map.h"
-#include "util/util_progress.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Particle System */
-
-NODE_DEFINE(ParticleSystem)
-{
- NodeType *type = NodeType::add("particle_system", create);
- return type;
-}
-
-ParticleSystem::ParticleSystem() : Node(get_node_type())
-{
-}
-
-ParticleSystem::~ParticleSystem()
-{
-}
-
-void ParticleSystem::tag_update(Scene *scene)
-{
- scene->particle_system_manager->tag_update(scene);
-}
-
-/* Particle System Manager */
-
-ParticleSystemManager::ParticleSystemManager()
-{
- need_update_ = true;
-}
-
-ParticleSystemManager::~ParticleSystemManager()
-{
-}
-
-void ParticleSystemManager::device_update_particles(Device *,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- /* count particles.
- * adds one dummy particle at the beginning to avoid invalid lookups,
- * in case a shader uses particle info without actual particle data. */
- int num_particles = 1;
- for (size_t j = 0; j < scene->particle_systems.size(); j++)
- num_particles += scene->particle_systems[j]->particles.size();
-
- KernelParticle *kparticles = dscene->particles.alloc(num_particles);
-
- /* dummy particle */
- memset(kparticles, 0, sizeof(KernelParticle));
-
- int i = 1;
- for (size_t j = 0; j < scene->particle_systems.size(); j++) {
- ParticleSystem *psys = scene->particle_systems[j];
-
- for (size_t k = 0; k < psys->particles.size(); k++) {
- /* pack in texture */
- Particle &pa = psys->particles[k];
-
- kparticles[i].index = pa.index;
- kparticles[i].age = pa.age;
- kparticles[i].lifetime = pa.lifetime;
- kparticles[i].size = pa.size;
- kparticles[i].rotation = pa.rotation;
- kparticles[i].location = float3_to_float4(pa.location);
- kparticles[i].velocity = float3_to_float4(pa.velocity);
- kparticles[i].angular_velocity = float3_to_float4(pa.angular_velocity);
-
- i++;
-
- if (progress.get_cancel())
- return;
- }
- }
-
- dscene->particles.copy_to_device();
-}
-
-void ParticleSystemManager::device_update(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- if (!need_update())
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->particles.times.add_entry({"device_update", time});
- }
- });
-
- VLOG(1) << "Total " << scene->particle_systems.size() << " particle systems.";
-
- device_free(device, dscene);
-
- progress.set_status("Updating Particle Systems", "Copying Particles to device");
- device_update_particles(device, dscene, scene, progress);
-
- if (progress.get_cancel())
- return;
-
- need_update_ = false;
-}
-
-void ParticleSystemManager::device_free(Device *, DeviceScene *dscene)
-{
- dscene->particles.free();
-}
-
-void ParticleSystemManager::tag_update(Scene * /*scene*/)
-{
- need_update_ = true;
-}
-
-bool ParticleSystemManager::need_update() const
-{
- return need_update_;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/particles.h b/intern/cycles/render/particles.h
deleted file mode 100644
index 8b59756f148..00000000000
--- a/intern/cycles/render/particles.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __PARTICLES_H__
-#define __PARTICLES_H__
-
-#include "util/util_array.h"
-#include "util/util_types.h"
-
-#include "graph/node.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class Progress;
-class Scene;
-
-/* Particle System */
-
-struct Particle {
- int index;
- float age;
- float lifetime;
- float3 location;
- float4 rotation;
- float size;
- float3 velocity;
- float3 angular_velocity;
-};
-
-class ParticleSystem : public Node {
- public:
- NODE_DECLARE
-
- ParticleSystem();
- ~ParticleSystem();
-
- void tag_update(Scene *scene);
-
- array<Particle> particles;
-};
-
-/* ParticleSystem Manager */
-
-class ParticleSystemManager {
- bool need_update_;
-
- public:
- ParticleSystemManager();
- ~ParticleSystemManager();
-
- void device_update_particles(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress);
- void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
- void device_free(Device *device, DeviceScene *dscene);
-
- void tag_update(Scene *scene);
-
- bool need_update() const;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __PARTICLES_H__ */
diff --git a/intern/cycles/render/pass.cpp b/intern/cycles/render/pass.cpp
deleted file mode 100644
index 472c9fc0a82..00000000000
--- a/intern/cycles/render/pass.cpp
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/pass.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_logging.h"
-
-CCL_NAMESPACE_BEGIN
-
-const char *pass_type_as_string(const PassType type)
-{
- const int type_int = static_cast<int>(type);
-
- const NodeEnum *type_enum = Pass::get_type_enum();
-
- if (!type_enum->exists(type_int)) {
- LOG(DFATAL) << "Unhandled pass type " << static_cast<int>(type) << ", not supposed to happen.";
- return "UNKNOWN";
- }
-
- return (*type_enum)[type_int].c_str();
-}
-
-const char *pass_mode_as_string(PassMode mode)
-{
- switch (mode) {
- case PassMode::NOISY:
- return "NOISY";
- case PassMode::DENOISED:
- return "DENOISED";
- }
-
- LOG(DFATAL) << "Unhandled pass mode " << static_cast<int>(mode) << ", should never happen.";
- return "UNKNOWN";
-}
-
-std::ostream &operator<<(std::ostream &os, PassMode mode)
-{
- os << pass_mode_as_string(mode);
- return os;
-}
-
-const NodeEnum *Pass::get_type_enum()
-{
- static NodeEnum pass_type_enum;
-
- if (pass_type_enum.empty()) {
-
- /* Light Passes. */
- pass_type_enum.insert("combined", PASS_COMBINED);
- pass_type_enum.insert("emission", PASS_EMISSION);
- pass_type_enum.insert("background", PASS_BACKGROUND);
- pass_type_enum.insert("ao", PASS_AO);
- pass_type_enum.insert("shadow", PASS_SHADOW);
- pass_type_enum.insert("diffuse", PASS_DIFFUSE);
- pass_type_enum.insert("diffuse_direct", PASS_DIFFUSE_DIRECT);
- pass_type_enum.insert("diffuse_indirect", PASS_DIFFUSE_INDIRECT);
- pass_type_enum.insert("glossy", PASS_GLOSSY);
- pass_type_enum.insert("glossy_direct", PASS_GLOSSY_DIRECT);
- pass_type_enum.insert("glossy_indirect", PASS_GLOSSY_INDIRECT);
- pass_type_enum.insert("transmission", PASS_TRANSMISSION);
- pass_type_enum.insert("transmission_direct", PASS_TRANSMISSION_DIRECT);
- pass_type_enum.insert("transmission_indirect", PASS_TRANSMISSION_INDIRECT);
- pass_type_enum.insert("volume", PASS_VOLUME);
- pass_type_enum.insert("volume_direct", PASS_VOLUME_DIRECT);
- pass_type_enum.insert("volume_indirect", PASS_VOLUME_INDIRECT);
-
- /* Data passes. */
- pass_type_enum.insert("depth", PASS_DEPTH);
- pass_type_enum.insert("position", PASS_POSITION);
- pass_type_enum.insert("normal", PASS_NORMAL);
- pass_type_enum.insert("roughness", PASS_ROUGHNESS);
- pass_type_enum.insert("uv", PASS_UV);
- pass_type_enum.insert("object_id", PASS_OBJECT_ID);
- pass_type_enum.insert("material_id", PASS_MATERIAL_ID);
- pass_type_enum.insert("motion", PASS_MOTION);
- pass_type_enum.insert("motion_weight", PASS_MOTION_WEIGHT);
- pass_type_enum.insert("cryptomatte", PASS_CRYPTOMATTE);
- pass_type_enum.insert("aov_color", PASS_AOV_COLOR);
- pass_type_enum.insert("aov_value", PASS_AOV_VALUE);
- pass_type_enum.insert("adaptive_aux_buffer", PASS_ADAPTIVE_AUX_BUFFER);
- pass_type_enum.insert("sample_count", PASS_SAMPLE_COUNT);
- pass_type_enum.insert("diffuse_color", PASS_DIFFUSE_COLOR);
- pass_type_enum.insert("glossy_color", PASS_GLOSSY_COLOR);
- pass_type_enum.insert("transmission_color", PASS_TRANSMISSION_COLOR);
- pass_type_enum.insert("mist", PASS_MIST);
- pass_type_enum.insert("denoising_normal", PASS_DENOISING_NORMAL);
- pass_type_enum.insert("denoising_albedo", PASS_DENOISING_ALBEDO);
-
- pass_type_enum.insert("shadow_catcher", PASS_SHADOW_CATCHER);
- pass_type_enum.insert("shadow_catcher_sample_count", PASS_SHADOW_CATCHER_SAMPLE_COUNT);
- pass_type_enum.insert("shadow_catcher_matte", PASS_SHADOW_CATCHER_MATTE);
-
- pass_type_enum.insert("bake_primitive", PASS_BAKE_PRIMITIVE);
- pass_type_enum.insert("bake_differential", PASS_BAKE_DIFFERENTIAL);
- }
-
- return &pass_type_enum;
-}
-
-const NodeEnum *Pass::get_mode_enum()
-{
- static NodeEnum pass_mode_enum;
-
- if (pass_mode_enum.empty()) {
- pass_mode_enum.insert("noisy", static_cast<int>(PassMode::NOISY));
- pass_mode_enum.insert("denoised", static_cast<int>(PassMode::DENOISED));
- }
-
- return &pass_mode_enum;
-}
-
-NODE_DEFINE(Pass)
-{
- NodeType *type = NodeType::add("pass", create);
-
- const NodeEnum *pass_type_enum = get_type_enum();
- const NodeEnum *pass_mode_enum = get_mode_enum();
-
- SOCKET_ENUM(type, "Type", *pass_type_enum, PASS_COMBINED);
- SOCKET_ENUM(mode, "Mode", *pass_mode_enum, static_cast<int>(PassMode::DENOISED));
- SOCKET_STRING(name, "Name", ustring());
- SOCKET_BOOLEAN(include_albedo, "Include Albedo", false);
-
- return type;
-}
-
-Pass::Pass() : Node(get_node_type()), is_auto_(false)
-{
-}
-
-PassInfo Pass::get_info() const
-{
- return get_info(type, include_albedo);
-}
-
-bool Pass::is_written() const
-{
- return get_info().is_written;
-}
-
-PassInfo Pass::get_info(const PassType type, const bool include_albedo)
-{
- PassInfo pass_info;
-
- pass_info.use_filter = true;
- pass_info.use_exposure = false;
- pass_info.divide_type = PASS_NONE;
- pass_info.use_compositing = false;
- pass_info.use_denoising_albedo = true;
-
- switch (type) {
- case PASS_NONE:
- pass_info.num_components = 0;
- break;
- case PASS_COMBINED:
- pass_info.num_components = 4;
- pass_info.use_exposure = true;
- pass_info.support_denoise = true;
- break;
- case PASS_DEPTH:
- pass_info.num_components = 1;
- pass_info.use_filter = false;
- break;
- case PASS_MIST:
- pass_info.num_components = 1;
- break;
- case PASS_POSITION:
- pass_info.num_components = 3;
- break;
- case PASS_NORMAL:
- pass_info.num_components = 3;
- break;
- case PASS_ROUGHNESS:
- pass_info.num_components = 1;
- break;
- case PASS_UV:
- pass_info.num_components = 3;
- break;
- case PASS_MOTION:
- pass_info.num_components = 4;
- pass_info.divide_type = PASS_MOTION_WEIGHT;
- break;
- case PASS_MOTION_WEIGHT:
- pass_info.num_components = 1;
- break;
- case PASS_OBJECT_ID:
- case PASS_MATERIAL_ID:
- pass_info.num_components = 1;
- pass_info.use_filter = false;
- break;
-
- case PASS_EMISSION:
- case PASS_BACKGROUND:
- pass_info.num_components = 3;
- pass_info.use_exposure = true;
- break;
- case PASS_AO:
- pass_info.num_components = 3;
- break;
- case PASS_SHADOW:
- pass_info.num_components = 3;
- pass_info.use_exposure = false;
- break;
-
- case PASS_DIFFUSE_COLOR:
- case PASS_GLOSSY_COLOR:
- case PASS_TRANSMISSION_COLOR:
- pass_info.num_components = 3;
- break;
- case PASS_DIFFUSE:
- pass_info.num_components = 3;
- pass_info.use_exposure = true;
- pass_info.direct_type = PASS_DIFFUSE_DIRECT;
- pass_info.indirect_type = PASS_DIFFUSE_INDIRECT;
- pass_info.divide_type = (!include_albedo) ? PASS_DIFFUSE_COLOR : PASS_NONE;
- pass_info.use_compositing = true;
- pass_info.is_written = false;
- break;
- case PASS_DIFFUSE_DIRECT:
- case PASS_DIFFUSE_INDIRECT:
- pass_info.num_components = 3;
- pass_info.use_exposure = true;
- pass_info.divide_type = (!include_albedo) ? PASS_DIFFUSE_COLOR : PASS_NONE;
- pass_info.use_compositing = true;
- break;
- case PASS_GLOSSY:
- pass_info.num_components = 3;
- pass_info.use_exposure = true;
- pass_info.direct_type = PASS_GLOSSY_DIRECT;
- pass_info.indirect_type = PASS_GLOSSY_INDIRECT;
- pass_info.divide_type = (!include_albedo) ? PASS_GLOSSY_COLOR : PASS_NONE;
- pass_info.use_compositing = true;
- pass_info.is_written = false;
- break;
- case PASS_GLOSSY_DIRECT:
- case PASS_GLOSSY_INDIRECT:
- pass_info.num_components = 3;
- pass_info.use_exposure = true;
- pass_info.divide_type = (!include_albedo) ? PASS_GLOSSY_COLOR : PASS_NONE;
- pass_info.use_compositing = true;
- break;
- case PASS_TRANSMISSION:
- pass_info.num_components = 3;
- pass_info.use_exposure = true;
- pass_info.direct_type = PASS_TRANSMISSION_DIRECT;
- pass_info.indirect_type = PASS_TRANSMISSION_INDIRECT;
- pass_info.divide_type = (!include_albedo) ? PASS_TRANSMISSION_COLOR : PASS_NONE;
- pass_info.use_compositing = true;
- pass_info.is_written = false;
- break;
- case PASS_TRANSMISSION_DIRECT:
- case PASS_TRANSMISSION_INDIRECT:
- pass_info.num_components = 3;
- pass_info.use_exposure = true;
- pass_info.divide_type = (!include_albedo) ? PASS_TRANSMISSION_COLOR : PASS_NONE;
- pass_info.use_compositing = true;
- break;
- case PASS_VOLUME:
- pass_info.num_components = 3;
- pass_info.use_exposure = true;
- pass_info.direct_type = PASS_VOLUME_DIRECT;
- pass_info.indirect_type = PASS_VOLUME_INDIRECT;
- pass_info.use_compositing = true;
- pass_info.is_written = false;
- break;
- case PASS_VOLUME_DIRECT:
- case PASS_VOLUME_INDIRECT:
- pass_info.num_components = 3;
- pass_info.use_exposure = true;
- break;
-
- case PASS_CRYPTOMATTE:
- pass_info.num_components = 4;
- break;
-
- case PASS_DENOISING_NORMAL:
- pass_info.num_components = 3;
- break;
- case PASS_DENOISING_ALBEDO:
- pass_info.num_components = 3;
- break;
-
- case PASS_SHADOW_CATCHER:
- pass_info.num_components = 3;
- pass_info.use_exposure = true;
- pass_info.use_compositing = true;
- pass_info.use_denoising_albedo = false;
- pass_info.support_denoise = true;
- break;
- case PASS_SHADOW_CATCHER_SAMPLE_COUNT:
- pass_info.num_components = 1;
- break;
- case PASS_SHADOW_CATCHER_MATTE:
- pass_info.num_components = 4;
- pass_info.use_exposure = true;
- pass_info.support_denoise = true;
- /* Without shadow catcher approximation compositing is not needed.
- * Since we don't know here whether approximation is used or not, leave the decision up to
- * the caller which will know that. */
- break;
-
- case PASS_ADAPTIVE_AUX_BUFFER:
- pass_info.num_components = 4;
- break;
- case PASS_SAMPLE_COUNT:
- pass_info.num_components = 1;
- pass_info.use_exposure = false;
- break;
-
- case PASS_AOV_COLOR:
- pass_info.num_components = 3;
- break;
- case PASS_AOV_VALUE:
- pass_info.num_components = 1;
- break;
-
- case PASS_BAKE_PRIMITIVE:
- case PASS_BAKE_DIFFERENTIAL:
- pass_info.num_components = 4;
- pass_info.use_exposure = false;
- pass_info.use_filter = false;
- break;
-
- case PASS_CATEGORY_LIGHT_END:
- case PASS_CATEGORY_DATA_END:
- case PASS_CATEGORY_BAKE_END:
- case PASS_NUM:
- LOG(DFATAL) << "Unexpected pass type is used " << type;
- pass_info.num_components = 0;
- break;
- }
-
- return pass_info;
-}
-
-bool Pass::contains(const vector<Pass *> &passes, PassType type)
-{
- for (const Pass *pass : passes) {
- if (pass->get_type() != type) {
- continue;
- }
-
- return true;
- }
-
- return false;
-}
-
-const Pass *Pass::find(const vector<Pass *> &passes, const string &name)
-{
- for (const Pass *pass : passes) {
- if (pass->get_name() == name) {
- return pass;
- }
- }
-
- return nullptr;
-}
-
-const Pass *Pass::find(const vector<Pass *> &passes, PassType type, PassMode mode)
-{
- for (const Pass *pass : passes) {
- if (pass->get_type() != type || pass->get_mode() != mode) {
- continue;
- }
-
- return pass;
- }
-
- return nullptr;
-}
-
-int Pass::get_offset(const vector<Pass *> &passes, const Pass *pass)
-{
- int pass_offset = 0;
-
- for (const Pass *current_pass : passes) {
- /* Note that pass name is allowed to be empty. This is why we check for type and mode. */
- if (current_pass->get_type() == pass->get_type() &&
- current_pass->get_mode() == pass->get_mode() &&
- current_pass->get_name() == pass->get_name()) {
- if (current_pass->is_written()) {
- return pass_offset;
- }
- else {
- return PASS_UNUSED;
- }
- }
- if (current_pass->is_written()) {
- pass_offset += current_pass->get_info().num_components;
- }
- }
-
- return PASS_UNUSED;
-}
-
-std::ostream &operator<<(std::ostream &os, const Pass &pass)
-{
- os << "type: " << pass_type_as_string(pass.get_type());
- os << ", name: \"" << pass.get_name() << "\"";
- os << ", mode: " << pass.get_mode();
- os << ", is_written: " << string_from_bool(pass.is_written());
-
- return os;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/pass.h b/intern/cycles/render/pass.h
deleted file mode 100644
index 82230c62cb0..00000000000
--- a/intern/cycles/render/pass.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2011-2021 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <ostream> // NOLINT
-
-#include "util/util_string.h"
-#include "util/util_vector.h"
-
-#include "kernel/kernel_types.h"
-
-#include "graph/node.h"
-
-CCL_NAMESPACE_BEGIN
-
-const char *pass_type_as_string(const PassType type);
-
-enum class PassMode {
- NOISY,
- DENOISED,
-};
-const char *pass_mode_as_string(PassMode mode);
-std::ostream &operator<<(std::ostream &os, PassMode mode);
-
-struct PassInfo {
- int num_components = -1;
- bool use_filter = false;
- bool use_exposure = false;
- bool is_written = true;
- PassType divide_type = PASS_NONE;
- PassType direct_type = PASS_NONE;
- PassType indirect_type = PASS_NONE;
-
- /* Pass access for read can not happen directly and needs some sort of compositing (for example,
- * light passes due to divide_type, or shadow catcher pass. */
- bool use_compositing = false;
-
- /* Used to disable albedo pass for denoising.
- * Light and shadow catcher passes should not have discontinuity in the denoised result based on
- * the underlying albedo. */
- bool use_denoising_albedo = true;
-
- /* Pass supports denoising. */
- bool support_denoise = false;
-};
-
-class Pass : public Node {
- public:
- NODE_DECLARE
-
- NODE_SOCKET_API(PassType, type)
- NODE_SOCKET_API(PassMode, mode)
- NODE_SOCKET_API(ustring, name)
- NODE_SOCKET_API(bool, include_albedo)
-
- Pass();
-
- PassInfo get_info() const;
-
- /* The pass is written by the render pipeline (kernel or denoiser). If the pass is written it
- * will have pixels allocated in a RenderBuffer. Passes which are not written do not have their
- * pixels allocated to save memory. */
- bool is_written() const;
-
- protected:
- /* The has been created automatically as a requirement to various rendering functionality (such
- * as adaptive sampling). */
- bool is_auto_;
-
- public:
- static const NodeEnum *get_type_enum();
- static const NodeEnum *get_mode_enum();
-
- static PassInfo get_info(PassType type, const bool include_albedo = false);
-
- static bool contains(const vector<Pass *> &passes, PassType type);
-
- /* Returns nullptr if there is no pass with the given name or type+mode. */
- static const Pass *find(const vector<Pass *> &passes, const string &name);
- static const Pass *find(const vector<Pass *> &passes,
- PassType type,
- PassMode mode = PassMode::NOISY);
-
- /* Returns PASS_UNUSED if there is no corresponding pass. */
- static int get_offset(const vector<Pass *> &passes, const Pass *pass);
-
- friend class Film;
-};
-
-std::ostream &operator<<(std::ostream &os, const Pass &pass);
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/procedural.cpp b/intern/cycles/render/procedural.cpp
deleted file mode 100644
index 1307a35dcf2..00000000000
--- a/intern/cycles/render/procedural.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "procedural.h"
-
-#include "render/scene.h"
-#include "render/stats.h"
-
-#include "util/util_foreach.h"
-#include "util/util_progress.h"
-
-CCL_NAMESPACE_BEGIN
-
-NODE_ABSTRACT_DEFINE(Procedural)
-{
- NodeType *type = NodeType::add("procedural_base", NULL);
- return type;
-}
-
-Procedural::Procedural(const NodeType *type) : Node(type)
-{
-}
-
-Procedural::~Procedural()
-{
-}
-
-ProceduralManager::ProceduralManager()
-{
- need_update_ = true;
-}
-
-ProceduralManager::~ProceduralManager()
-{
-}
-
-void ProceduralManager::update(Scene *scene, Progress &progress)
-{
- if (!need_update()) {
- return;
- }
-
- progress.set_status("Updating Procedurals");
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->procedurals.times.add_entry({"update", time});
- }
- });
-
- foreach (Procedural *procedural, scene->procedurals) {
- if (progress.get_cancel()) {
- return;
- }
-
- procedural->generate(scene, progress);
- }
-
- if (progress.get_cancel()) {
- return;
- }
-
- need_update_ = false;
-}
-
-void ProceduralManager::tag_update()
-{
- need_update_ = true;
-}
-
-bool ProceduralManager::need_update() const
-{
- return need_update_;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
deleted file mode 100644
index 6d79536061e..00000000000
--- a/intern/cycles/render/scene.cpp
+++ /dev/null
@@ -1,959 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-
-#include "bvh/bvh.h"
-#include "device/device.h"
-#include "render/alembic.h"
-#include "render/background.h"
-#include "render/bake.h"
-#include "render/camera.h"
-#include "render/curves.h"
-#include "render/film.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/osl.h"
-#include "render/particles.h"
-#include "render/procedural.h"
-#include "render/scene.h"
-#include "render/session.h"
-#include "render/shader.h"
-#include "render/svm.h"
-#include "render/tables.h"
-#include "render/volume.h"
-
-#include "util/util_foreach.h"
-#include "util/util_guarded_allocator.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
-
-CCL_NAMESPACE_BEGIN
-
-DeviceScene::DeviceScene(Device *device)
- : bvh_nodes(device, "__bvh_nodes", MEM_GLOBAL),
- bvh_leaf_nodes(device, "__bvh_leaf_nodes", MEM_GLOBAL),
- object_node(device, "__object_node", MEM_GLOBAL),
- prim_type(device, "__prim_type", MEM_GLOBAL),
- prim_visibility(device, "__prim_visibility", MEM_GLOBAL),
- prim_index(device, "__prim_index", MEM_GLOBAL),
- prim_object(device, "__prim_object", MEM_GLOBAL),
- prim_time(device, "__prim_time", MEM_GLOBAL),
- tri_verts(device, "__tri_verts", MEM_GLOBAL),
- tri_shader(device, "__tri_shader", MEM_GLOBAL),
- tri_vnormal(device, "__tri_vnormal", MEM_GLOBAL),
- tri_vindex(device, "__tri_vindex", MEM_GLOBAL),
- tri_patch(device, "__tri_patch", MEM_GLOBAL),
- tri_patch_uv(device, "__tri_patch_uv", MEM_GLOBAL),
- curves(device, "__curves", MEM_GLOBAL),
- curve_keys(device, "__curve_keys", MEM_GLOBAL),
- curve_segments(device, "__curve_segments", MEM_GLOBAL),
- patches(device, "__patches", MEM_GLOBAL),
- objects(device, "__objects", MEM_GLOBAL),
- object_motion_pass(device, "__object_motion_pass", MEM_GLOBAL),
- object_motion(device, "__object_motion", MEM_GLOBAL),
- object_flag(device, "__object_flag", MEM_GLOBAL),
- object_volume_step(device, "__object_volume_step", MEM_GLOBAL),
- camera_motion(device, "__camera_motion", MEM_GLOBAL),
- attributes_map(device, "__attributes_map", MEM_GLOBAL),
- attributes_float(device, "__attributes_float", MEM_GLOBAL),
- attributes_float2(device, "__attributes_float2", MEM_GLOBAL),
- attributes_float3(device, "__attributes_float3", MEM_GLOBAL),
- attributes_uchar4(device, "__attributes_uchar4", MEM_GLOBAL),
- light_distribution(device, "__light_distribution", MEM_GLOBAL),
- lights(device, "__lights", MEM_GLOBAL),
- light_background_marginal_cdf(device, "__light_background_marginal_cdf", MEM_GLOBAL),
- light_background_conditional_cdf(device, "__light_background_conditional_cdf", MEM_GLOBAL),
- particles(device, "__particles", MEM_GLOBAL),
- svm_nodes(device, "__svm_nodes", MEM_GLOBAL),
- shaders(device, "__shaders", MEM_GLOBAL),
- lookup_table(device, "__lookup_table", MEM_GLOBAL),
- sample_pattern_lut(device, "__sample_pattern_lut", MEM_GLOBAL),
- ies_lights(device, "__ies", MEM_GLOBAL)
-{
- memset((void *)&data, 0, sizeof(data));
-}
-
-Scene::Scene(const SceneParams &params_, Device *device)
- : name("Scene"),
- bvh(NULL),
- default_surface(NULL),
- default_volume(NULL),
- default_light(NULL),
- default_background(NULL),
- default_empty(NULL),
- device(device),
- dscene(device),
- params(params_),
- update_stats(NULL),
- kernels_loaded(false),
- /* TODO(sergey): Check if it's indeed optimal value for the split kernel. */
- max_closure_global(1)
-{
- memset((void *)&dscene.data, 0, sizeof(dscene.data));
-
- /* OSL only works on the CPU */
- if (device->info.has_osl)
- shader_manager = ShaderManager::create(params.shadingsystem);
- else
- shader_manager = ShaderManager::create(SHADINGSYSTEM_SVM);
-
- light_manager = new LightManager();
- geometry_manager = new GeometryManager();
- object_manager = new ObjectManager();
- image_manager = new ImageManager(device->info);
- particle_system_manager = new ParticleSystemManager();
- bake_manager = new BakeManager();
- procedural_manager = new ProceduralManager();
-
- /* Create nodes after managers, since create_node() can tag the managers. */
- camera = create_node<Camera>();
- dicing_camera = create_node<Camera>();
- lookup_tables = new LookupTables();
- film = create_node<Film>();
- background = create_node<Background>();
- integrator = create_node<Integrator>();
-
- film->add_default(this);
- shader_manager->add_default(this);
-}
-
-Scene::~Scene()
-{
- free_memory(true);
-}
-
-void Scene::free_memory(bool final)
-{
- delete bvh;
- bvh = NULL;
-
- /* The order of deletion is important to make sure data is freed based on possible dependencies
- * as the Nodes' reference counts are decremented in the destructors:
- *
- * - Procedurals can create and hold pointers to any other types.
- * - Objects can hold pointers to Geometries and ParticleSystems
- * - Lights and Geometries can hold pointers to Shaders.
- *
- * Similarly, we first delete all nodes and their associated device data, and then the managers
- * and their associated device data.
- */
- foreach (Procedural *p, procedurals)
- delete p;
- foreach (Object *o, objects)
- delete o;
- foreach (Geometry *g, geometry)
- delete g;
- foreach (ParticleSystem *p, particle_systems)
- delete p;
- foreach (Light *l, lights)
- delete l;
- foreach (Pass *p, passes)
- delete p;
-
- geometry.clear();
- objects.clear();
- lights.clear();
- particle_systems.clear();
- procedurals.clear();
- passes.clear();
-
- if (device) {
- camera->device_free(device, &dscene, this);
- film->device_free(device, &dscene, this);
- background->device_free(device, &dscene);
- integrator->device_free(device, &dscene, true);
- }
-
- if (final) {
- delete camera;
- delete dicing_camera;
- delete film;
- delete background;
- delete integrator;
- }
-
- /* Delete Shaders after every other nodes to ensure that we do not try to decrement the reference
- * count on some dangling pointer. */
- foreach (Shader *s, shaders)
- delete s;
-
- shaders.clear();
-
- /* Now that all nodes have been deleted, we can safely delete managers and device data. */
- if (device) {
- object_manager->device_free(device, &dscene, true);
- geometry_manager->device_free(device, &dscene, true);
- shader_manager->device_free(device, &dscene, this);
- light_manager->device_free(device, &dscene);
-
- particle_system_manager->device_free(device, &dscene);
-
- bake_manager->device_free(device, &dscene);
-
- if (final)
- image_manager->device_free(device);
- else
- image_manager->device_free_builtin(device);
-
- lookup_tables->device_free(device, &dscene);
- }
-
- if (final) {
- delete lookup_tables;
- delete object_manager;
- delete geometry_manager;
- delete shader_manager;
- delete light_manager;
- delete particle_system_manager;
- delete image_manager;
- delete bake_manager;
- delete update_stats;
- delete procedural_manager;
- }
-}
-
-void Scene::host_update(Progress &progress)
-{
- if (update_stats) {
- update_stats->clear();
- }
-
- scoped_callback_timer timer([this](double time) {
- if (update_stats) {
- update_stats->scene.times.add_entry({"host_update", time});
- }
- });
-
- progress.set_status("Updating Shaders");
- shader_manager->host_update(this, progress);
-}
-
-void Scene::device_update(Device *device_, Progress &progress)
-{
- if (!device)
- device = device_;
-
- bool print_stats = need_data_update();
-
- scoped_callback_timer timer([this, print_stats](double time) {
- if (update_stats) {
- update_stats->scene.times.add_entry({"device_update", time});
-
- if (print_stats) {
- printf("Update statistics:\n%s\n", update_stats->full_report().c_str());
- }
- }
- });
-
- /* The order of updates is important, because there's dependencies between
- * the different managers, using data computed by previous managers.
- *
- * - Image manager uploads images used by shaders.
- * - Camera may be used for adaptive subdivision.
- * - Displacement shader must have all shader data available.
- * - Light manager needs lookup tables and final mesh data to compute emission CDF.
- * - Lookup tables are done a second time to handle film tables
- */
-
- progress.set_status("Updating Shaders");
- shader_manager->device_update(device, &dscene, this, progress);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- procedural_manager->update(this, progress);
-
- if (progress.get_cancel())
- return;
-
- progress.set_status("Updating Background");
- background->device_update(device, &dscene, this);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Camera");
- camera->device_update(device, &dscene, this);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- geometry_manager->device_update_preprocess(device, this, progress);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Objects");
- object_manager->device_update(device, &dscene, this, progress);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Particle Systems");
- particle_system_manager->device_update(device, &dscene, this, progress);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Meshes");
- geometry_manager->device_update(device, &dscene, this, progress);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Objects Flags");
- object_manager->device_update_flags(device, &dscene, this, progress);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Images");
- image_manager->device_update(device, this, progress);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Camera Volume");
- camera->device_update_volume(device, &dscene, this);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Lookup Tables");
- lookup_tables->device_update(device, &dscene, this);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Lights");
- light_manager->device_update(device, &dscene, this, progress);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Integrator");
- integrator->device_update(device, &dscene, this);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Film");
- film->device_update(device, &dscene, this);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Lookup Tables");
- lookup_tables->device_update(device, &dscene, this);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- progress.set_status("Updating Baking");
- bake_manager->device_update(device, &dscene, this, progress);
-
- if (progress.get_cancel() || device->have_error())
- return;
-
- if (device->have_error() == false) {
- progress.set_status("Updating Device", "Writing constant memory");
- device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
- }
-
- if (print_stats) {
- size_t mem_used = util_guarded_get_mem_used();
- size_t mem_peak = util_guarded_get_mem_peak();
-
- VLOG(1) << "System memory statistics after full device sync:\n"
- << " Usage: " << string_human_readable_number(mem_used) << " ("
- << string_human_readable_size(mem_used) << ")\n"
- << " Peak: " << string_human_readable_number(mem_peak) << " ("
- << string_human_readable_size(mem_peak) << ")";
- }
-}
-
-Scene::MotionType Scene::need_motion()
-{
- if (integrator->get_motion_blur())
- return MOTION_BLUR;
- else if (Pass::contains(passes, PASS_MOTION))
- return MOTION_PASS;
- else
- return MOTION_NONE;
-}
-
-float Scene::motion_shutter_time()
-{
- if (need_motion() == Scene::MOTION_PASS)
- return 2.0f;
- else
- return camera->get_shuttertime();
-}
-
-bool Scene::need_global_attribute(AttributeStandard std)
-{
- if (std == ATTR_STD_UV)
- return Pass::contains(passes, PASS_UV);
- else if (std == ATTR_STD_MOTION_VERTEX_POSITION)
- return need_motion() != MOTION_NONE;
- else if (std == ATTR_STD_MOTION_VERTEX_NORMAL)
- return need_motion() == MOTION_BLUR;
-
- return false;
-}
-
-void Scene::need_global_attributes(AttributeRequestSet &attributes)
-{
- for (int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++)
- if (need_global_attribute((AttributeStandard)std))
- attributes.add((AttributeStandard)std);
-}
-
-bool Scene::need_update()
-{
- return (need_reset() || film->is_modified());
-}
-
-bool Scene::need_data_update()
-{
- return (background->is_modified() || image_manager->need_update() ||
- object_manager->need_update() || geometry_manager->need_update() ||
- light_manager->need_update() || lookup_tables->need_update() ||
- integrator->is_modified() || shader_manager->need_update() ||
- particle_system_manager->need_update() || bake_manager->need_update() ||
- film->is_modified() || procedural_manager->need_update());
-}
-
-bool Scene::need_reset()
-{
- return need_data_update() || camera->is_modified();
-}
-
-void Scene::reset()
-{
- shader_manager->reset(this);
- shader_manager->add_default(this);
-
- /* ensure all objects are updated */
- camera->tag_modified();
- dicing_camera->tag_modified();
- film->tag_modified();
- background->tag_modified();
-
- background->tag_update(this);
- integrator->tag_update(this, Integrator::UPDATE_ALL);
- object_manager->tag_update(this, ObjectManager::UPDATE_ALL);
- geometry_manager->tag_update(this, GeometryManager::UPDATE_ALL);
- light_manager->tag_update(this, LightManager::UPDATE_ALL);
- particle_system_manager->tag_update(this);
- procedural_manager->tag_update();
-}
-
-void Scene::device_free()
-{
- free_memory(false);
-}
-
-void Scene::collect_statistics(RenderStats *stats)
-{
- geometry_manager->collect_statistics(this, stats);
- image_manager->collect_statistics(stats);
-}
-
-void Scene::enable_update_stats()
-{
- if (!update_stats) {
- update_stats = new SceneUpdateStats();
- }
-}
-
-void Scene::update_kernel_features()
-{
- if (!need_update()) {
- return;
- }
-
- /* These features are not being tweaked as often as shaders,
- * so could be done selective magic for the viewport as well. */
- uint kernel_features = shader_manager->get_kernel_features(this);
-
- bool use_motion = need_motion() == Scene::MotionType::MOTION_BLUR;
- kernel_features |= KERNEL_FEATURE_PATH_TRACING;
- if (params.hair_shape == CURVE_THICK) {
- kernel_features |= KERNEL_FEATURE_HAIR_THICK;
- }
- if (use_motion && camera->use_motion()) {
- kernel_features |= KERNEL_FEATURE_CAMERA_MOTION;
- }
- foreach (Object *object, objects) {
- Geometry *geom = object->get_geometry();
- if (use_motion) {
- if (object->use_motion() || geom->get_use_motion_blur()) {
- kernel_features |= KERNEL_FEATURE_OBJECT_MOTION;
- }
- if (geom->get_use_motion_blur()) {
- kernel_features |= KERNEL_FEATURE_CAMERA_MOTION;
- }
- }
- if (object->get_is_shadow_catcher()) {
- kernel_features |= KERNEL_FEATURE_SHADOW_CATCHER;
- }
- if (geom->is_mesh()) {
- Mesh *mesh = static_cast<Mesh *>(geom);
-#ifdef WITH_OPENSUBDIV
- if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
- kernel_features |= KERNEL_FEATURE_PATCH_EVALUATION;
- }
-#endif
- }
- else if (geom->is_hair()) {
- kernel_features |= KERNEL_FEATURE_HAIR;
- }
- }
-
- if (bake_manager->get_baking()) {
- kernel_features |= KERNEL_FEATURE_BAKING;
- }
-
- kernel_features |= film->get_kernel_features(this);
-
- dscene.data.kernel_features = kernel_features;
-
- /* Currently viewport render is faster with higher max_closures, needs investigating. */
- const uint max_closures = (params.background) ? get_max_closure_count() : MAX_CLOSURE;
- dscene.data.max_closures = max_closures;
- dscene.data.max_shaders = shaders.size();
-
- dscene.data.volume_stack_size = get_volume_stack_size();
-}
-
-bool Scene::update(Progress &progress)
-{
- if (!need_update()) {
- return false;
- }
-
- /* Update scene data on the host side.
- * Only updates which do not depend on the kernel (including kernel features). */
- progress.set_status("Updating Scene");
- MEM_GUARDED_CALL(&progress, host_update, progress);
-
- /* Load render kernels. After host scene update so that the required kernel features are known.
- */
- load_kernels(progress, false);
-
- /* Upload scene data to the device. */
- progress.set_status("Updating Scene Device");
- MEM_GUARDED_CALL(&progress, device_update, device, progress);
-
- return true;
-}
-
-static void log_kernel_features(const uint features)
-{
- VLOG(2) << "Requested features:\n";
- VLOG(2) << "Use BSDF " << string_from_bool(features & KERNEL_FEATURE_NODE_BSDF) << "\n";
- VLOG(2) << "Use Principled BSDF " << string_from_bool(features & KERNEL_FEATURE_PRINCIPLED)
- << "\n";
- VLOG(2) << "Use Emission " << string_from_bool(features & KERNEL_FEATURE_NODE_EMISSION) << "\n";
- VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_NODE_VOLUME) << "\n";
- VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_NODE_HAIR) << "\n";
- VLOG(2) << "Use Bump " << string_from_bool(features & KERNEL_FEATURE_NODE_BUMP) << "\n";
- VLOG(2) << "Use Voronoi " << string_from_bool(features & KERNEL_FEATURE_NODE_VORONOI_EXTRA)
- << "\n";
- VLOG(2) << "Use Shader Raytrace " << string_from_bool(features & KERNEL_FEATURE_NODE_RAYTRACE)
- << "\n";
- VLOG(2) << "Use Transparent " << string_from_bool(features & KERNEL_FEATURE_TRANSPARENT) << "\n";
- VLOG(2) << "Use Denoising " << string_from_bool(features & KERNEL_FEATURE_DENOISING) << "\n";
- VLOG(2) << "Use Path Tracing " << string_from_bool(features & KERNEL_FEATURE_PATH_TRACING)
- << "\n";
- VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_HAIR) << "\n";
- VLOG(2) << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION)
- << "\n";
- VLOG(2) << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION)
- << "\n";
- VLOG(2) << "Use Baking " << string_from_bool(features & KERNEL_FEATURE_BAKING) << "\n";
- VLOG(2) << "Use Subsurface " << string_from_bool(features & KERNEL_FEATURE_SUBSURFACE) << "\n";
- VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_VOLUME) << "\n";
- VLOG(2) << "Use Patch Evaluation "
- << string_from_bool(features & KERNEL_FEATURE_PATCH_EVALUATION) << "\n";
- VLOG(2) << "Use Shadow Catcher " << string_from_bool(features & KERNEL_FEATURE_SHADOW_CATCHER)
- << "\n";
-}
-
-bool Scene::load_kernels(Progress &progress, bool lock_scene)
-{
- thread_scoped_lock scene_lock;
- if (lock_scene) {
- scene_lock = thread_scoped_lock(mutex);
- }
-
- const uint kernel_features = dscene.data.kernel_features;
-
- if (!kernels_loaded || loaded_kernel_features != kernel_features) {
- progress.set_status("Loading render kernels (may take a few minutes the first time)");
-
- scoped_timer timer;
-
- log_kernel_features(kernel_features);
- if (!device->load_kernels(kernel_features)) {
- string message = device->error_message();
- if (message.empty())
- message = "Failed loading render kernel, see console for errors";
-
- progress.set_error(message);
- progress.set_status(message);
- progress.set_update();
- return false;
- }
-
- kernels_loaded = true;
- loaded_kernel_features = kernel_features;
- return true;
- }
- return false;
-}
-
-int Scene::get_max_closure_count()
-{
- if (shader_manager->use_osl()) {
- /* OSL always needs the maximum as we can't predict the
- * number of closures a shader might generate. */
- return MAX_CLOSURE;
- }
-
- int max_closures = 0;
- for (int i = 0; i < shaders.size(); i++) {
- Shader *shader = shaders[i];
- if (shader->reference_count()) {
- int num_closures = shader->graph->get_num_closures();
- max_closures = max(max_closures, num_closures);
- }
- }
- max_closure_global = max(max_closure_global, max_closures);
-
- if (max_closure_global > MAX_CLOSURE) {
- /* This is usually harmless as more complex shader tend to get many
- * closures discarded due to mixing or low weights. We need to limit
- * to MAX_CLOSURE as this is hardcoded in CPU/mega kernels, and it
- * avoids excessive memory usage for split kernels. */
- VLOG(2) << "Maximum number of closures exceeded: " << max_closure_global << " > "
- << MAX_CLOSURE;
-
- max_closure_global = MAX_CLOSURE;
- }
-
- return max_closure_global;
-}
-
-int Scene::get_volume_stack_size() const
-{
- int volume_stack_size = 0;
-
- /* Space for background volume and terminator.
- * Don't do optional here because camera ray initialization expects that there is space for
- * at least those elements (avoiding extra condition to check if there is actual volume or not).
- */
- volume_stack_size += 2;
-
- /* Quick non-expensive check. Can over-estimate maximum possible nested level, but does not
- * require expensive calculation during pre-processing. */
- for (const Object *object : objects) {
- if (object->check_is_volume()) {
- ++volume_stack_size;
- }
-
- if (volume_stack_size == MAX_VOLUME_STACK_SIZE) {
- break;
- }
- }
-
- volume_stack_size = min(volume_stack_size, MAX_VOLUME_STACK_SIZE);
-
- return volume_stack_size;
-}
-
-bool Scene::has_shadow_catcher()
-{
- if (shadow_catcher_modified_) {
- has_shadow_catcher_ = false;
- for (Object *object : objects) {
- if (object->get_is_shadow_catcher()) {
- has_shadow_catcher_ = true;
- break;
- }
- }
-
- shadow_catcher_modified_ = false;
- }
-
- return has_shadow_catcher_;
-}
-
-void Scene::tag_shadow_catcher_modified()
-{
- shadow_catcher_modified_ = true;
-}
-
-template<> Light *Scene::create_node<Light>()
-{
- Light *node = new Light();
- node->set_owner(this);
- lights.push_back(node);
- light_manager->tag_update(this, LightManager::LIGHT_ADDED);
- return node;
-}
-
-template<> Mesh *Scene::create_node<Mesh>()
-{
- Mesh *node = new Mesh();
- node->set_owner(this);
- geometry.push_back(node);
- geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
- return node;
-}
-
-template<> Hair *Scene::create_node<Hair>()
-{
- Hair *node = new Hair();
- node->set_owner(this);
- geometry.push_back(node);
- geometry_manager->tag_update(this, GeometryManager::HAIR_ADDED);
- return node;
-}
-
-template<> Volume *Scene::create_node<Volume>()
-{
- Volume *node = new Volume();
- node->set_owner(this);
- geometry.push_back(node);
- geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
- return node;
-}
-
-template<> Object *Scene::create_node<Object>()
-{
- Object *node = new Object();
- node->set_owner(this);
- objects.push_back(node);
- object_manager->tag_update(this, ObjectManager::OBJECT_ADDED);
- return node;
-}
-
-template<> ParticleSystem *Scene::create_node<ParticleSystem>()
-{
- ParticleSystem *node = new ParticleSystem();
- node->set_owner(this);
- particle_systems.push_back(node);
- particle_system_manager->tag_update(this);
- return node;
-}
-
-template<> Shader *Scene::create_node<Shader>()
-{
- Shader *node = new Shader();
- node->set_owner(this);
- shaders.push_back(node);
- shader_manager->tag_update(this, ShaderManager::SHADER_ADDED);
- return node;
-}
-
-template<> AlembicProcedural *Scene::create_node<AlembicProcedural>()
-{
-#ifdef WITH_ALEMBIC
- AlembicProcedural *node = new AlembicProcedural();
- node->set_owner(this);
- procedurals.push_back(node);
- procedural_manager->tag_update();
- return node;
-#else
- return nullptr;
-#endif
-}
-
-template<> Pass *Scene::create_node<Pass>()
-{
- Pass *node = new Pass();
- node->set_owner(this);
- passes.push_back(node);
- film->tag_modified();
- return node;
-}
-
-template<typename T> void delete_node_from_array(vector<T> &nodes, T node)
-{
- for (size_t i = 0; i < nodes.size(); ++i) {
- if (nodes[i] == node) {
- std::swap(nodes[i], nodes[nodes.size() - 1]);
- break;
- }
- }
-
- nodes.resize(nodes.size() - 1);
-
- delete node;
-}
-
-template<> void Scene::delete_node_impl(Light *node)
-{
- delete_node_from_array(lights, node);
- light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
-}
-
-template<> void Scene::delete_node_impl(Mesh *node)
-{
- delete_node_from_array(geometry, static_cast<Geometry *>(node));
- geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
-}
-
-template<> void Scene::delete_node_impl(Hair *node)
-{
- delete_node_from_array(geometry, static_cast<Geometry *>(node));
- geometry_manager->tag_update(this, GeometryManager::HAIR_REMOVED);
-}
-
-template<> void Scene::delete_node_impl(Volume *node)
-{
- delete_node_from_array(geometry, static_cast<Geometry *>(node));
- geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
-}
-
-template<> void Scene::delete_node_impl(Geometry *node)
-{
- uint flag;
- if (node->is_hair()) {
- flag = GeometryManager::HAIR_REMOVED;
- }
- else {
- flag = GeometryManager::MESH_REMOVED;
- }
-
- delete_node_from_array(geometry, node);
- geometry_manager->tag_update(this, flag);
-}
-
-template<> void Scene::delete_node_impl(Object *node)
-{
- delete_node_from_array(objects, node);
- object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
-}
-
-template<> void Scene::delete_node_impl(ParticleSystem *node)
-{
- delete_node_from_array(particle_systems, node);
- particle_system_manager->tag_update(this);
-}
-
-template<> void Scene::delete_node_impl(Shader *shader)
-{
- /* don't delete unused shaders, not supported */
- shader->clear_reference_count();
-}
-
-template<> void Scene::delete_node_impl(Procedural *node)
-{
- delete_node_from_array(procedurals, node);
- procedural_manager->tag_update();
-}
-
-template<> void Scene::delete_node_impl(AlembicProcedural *node)
-{
-#ifdef WITH_ALEMBIC
- delete_node_impl(static_cast<Procedural *>(node));
-#else
- (void)node;
-#endif
-}
-
-template<> void Scene::delete_node_impl(Pass *node)
-{
- delete_node_from_array(passes, node);
- film->tag_modified();
-}
-
-template<typename T>
-static void remove_nodes_in_set(const set<T *> &nodes_set,
- vector<T *> &nodes_array,
- const NodeOwner *owner)
-{
- size_t new_size = nodes_array.size();
-
- for (size_t i = 0; i < new_size; ++i) {
- T *node = nodes_array[i];
-
- if (nodes_set.find(node) != nodes_set.end()) {
- std::swap(nodes_array[i], nodes_array[new_size - 1]);
-
- assert(node->get_owner() == owner);
- delete node;
-
- i -= 1;
- new_size -= 1;
- }
- }
-
- nodes_array.resize(new_size);
- (void)owner;
-}
-
-template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner)
-{
- remove_nodes_in_set(nodes, lights, owner);
- light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
-}
-
-template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner)
-{
- remove_nodes_in_set(nodes, geometry, owner);
- geometry_manager->tag_update(this, GeometryManager::GEOMETRY_REMOVED);
-}
-
-template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner)
-{
- remove_nodes_in_set(nodes, objects, owner);
- object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
-}
-
-template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner)
-{
- remove_nodes_in_set(nodes, particle_systems, owner);
- particle_system_manager->tag_update(this);
-}
-
-template<> void Scene::delete_nodes(const set<Shader *> &nodes, const NodeOwner * /*owner*/)
-{
- /* don't delete unused shaders, not supported */
- for (Shader *shader : nodes) {
- shader->clear_reference_count();
- }
-}
-
-template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner)
-{
- remove_nodes_in_set(nodes, procedurals, owner);
- procedural_manager->tag_update();
-}
-
-template<> void Scene::delete_nodes(const set<Pass *> &nodes, const NodeOwner *owner)
-{
- remove_nodes_in_set(nodes, passes, owner);
- film->tag_modified();
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
deleted file mode 100644
index 87fbc872c0a..00000000000
--- a/intern/cycles/render/scene.h
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SCENE_H__
-#define __SCENE_H__
-
-#include "bvh/bvh_params.h"
-
-#include "render/film.h"
-#include "render/image.h"
-#include "render/shader.h"
-
-#include "device/device.h"
-#include "device/device_memory.h"
-
-#include "util/util_param.h"
-#include "util/util_string.h"
-#include "util/util_system.h"
-#include "util/util_texture.h"
-#include "util/util_thread.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class AlembicProcedural;
-class AttributeRequestSet;
-class Background;
-class BVH;
-class Camera;
-class Device;
-class DeviceInfo;
-class Film;
-class Integrator;
-class Light;
-class LightManager;
-class LookupTables;
-class Geometry;
-class GeometryManager;
-class Object;
-class ObjectManager;
-class ParticleSystemManager;
-class ParticleSystem;
-class Procedural;
-class ProceduralManager;
-class CurveSystemManager;
-class Shader;
-class ShaderManager;
-class Progress;
-class BakeManager;
-class BakeData;
-class RenderStats;
-class SceneUpdateStats;
-class Volume;
-
-/* Scene Device Data */
-
-class DeviceScene {
- public:
- /* BVH */
- device_vector<int4> bvh_nodes;
- device_vector<int4> bvh_leaf_nodes;
- device_vector<int> object_node;
- device_vector<int> prim_type;
- device_vector<uint> prim_visibility;
- device_vector<int> prim_index;
- device_vector<int> prim_object;
- device_vector<float2> prim_time;
-
- /* mesh */
- device_vector<float4> tri_verts;
- device_vector<uint> tri_shader;
- device_vector<float4> tri_vnormal;
- device_vector<uint4> tri_vindex;
- device_vector<uint> tri_patch;
- device_vector<float2> tri_patch_uv;
-
- device_vector<KernelCurve> curves;
- device_vector<float4> curve_keys;
- device_vector<KernelCurveSegment> curve_segments;
-
- device_vector<uint> patches;
-
- /* objects */
- device_vector<KernelObject> objects;
- device_vector<Transform> object_motion_pass;
- device_vector<DecomposedTransform> object_motion;
- device_vector<uint> object_flag;
- device_vector<float> object_volume_step;
-
- /* cameras */
- device_vector<DecomposedTransform> camera_motion;
-
- /* attributes */
- device_vector<uint4> attributes_map;
- device_vector<float> attributes_float;
- device_vector<float2> attributes_float2;
- device_vector<float4> attributes_float3;
- device_vector<uchar4> attributes_uchar4;
-
- /* lights */
- device_vector<KernelLightDistribution> light_distribution;
- device_vector<KernelLight> lights;
- device_vector<float2> light_background_marginal_cdf;
- device_vector<float2> light_background_conditional_cdf;
-
- /* particles */
- device_vector<KernelParticle> particles;
-
- /* shaders */
- device_vector<int4> svm_nodes;
- device_vector<KernelShader> shaders;
-
- /* lookup tables */
- device_vector<float> lookup_table;
-
- /* integrator */
- device_vector<float> sample_pattern_lut;
-
- /* ies lights */
- device_vector<float> ies_lights;
-
- KernelData data;
-
- DeviceScene(Device *device);
-};
-
-/* Scene Parameters */
-
-class SceneParams {
- public:
- ShadingSystem shadingsystem;
-
- /* Requested BVH layout.
- *
- * If it's not supported by the device, the widest one from supported ones
- * will be used, but BVH wider than this one will never be used.
- */
- BVHLayout bvh_layout;
-
- BVHType bvh_type;
- bool use_bvh_spatial_split;
- bool use_bvh_unaligned_nodes;
- int num_bvh_time_steps;
- int hair_subdivisions;
- CurveShapeType hair_shape;
- int texture_limit;
-
- bool background;
-
- SceneParams()
- {
- shadingsystem = SHADINGSYSTEM_SVM;
- bvh_layout = BVH_LAYOUT_BVH2;
- bvh_type = BVH_TYPE_DYNAMIC;
- use_bvh_spatial_split = false;
- use_bvh_unaligned_nodes = true;
- num_bvh_time_steps = 0;
- hair_subdivisions = 3;
- hair_shape = CURVE_RIBBON;
- texture_limit = 0;
- background = true;
- }
-
- bool modified(const SceneParams &params) const
- {
- return !(shadingsystem == params.shadingsystem && bvh_layout == params.bvh_layout &&
- bvh_type == params.bvh_type &&
- use_bvh_spatial_split == params.use_bvh_spatial_split &&
- use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes &&
- num_bvh_time_steps == params.num_bvh_time_steps &&
- hair_subdivisions == params.hair_subdivisions && hair_shape == params.hair_shape &&
- texture_limit == params.texture_limit);
- }
-
- int curve_subdivisions()
- {
- /* Matching the tessellation rate limit in Embree. */
- return clamp(1 << hair_subdivisions, 1, 16);
- }
-};
-
-/* Scene */
-
-class Scene : public NodeOwner {
- public:
- /* Optional name. Is used for logging and reporting. */
- string name;
-
- /* data */
- BVH *bvh;
- Camera *camera;
- Camera *dicing_camera;
- LookupTables *lookup_tables;
- Film *film;
- Background *background;
- Integrator *integrator;
-
- /* data lists */
- vector<Object *> objects;
- vector<Geometry *> geometry;
- vector<Shader *> shaders;
- vector<Light *> lights;
- vector<ParticleSystem *> particle_systems;
- vector<Pass *> passes;
- vector<Procedural *> procedurals;
-
- /* data managers */
- ImageManager *image_manager;
- LightManager *light_manager;
- ShaderManager *shader_manager;
- GeometryManager *geometry_manager;
- ObjectManager *object_manager;
- ParticleSystemManager *particle_system_manager;
- BakeManager *bake_manager;
- ProceduralManager *procedural_manager;
-
- /* default shaders */
- Shader *default_surface;
- Shader *default_volume;
- Shader *default_light;
- Shader *default_background;
- Shader *default_empty;
-
- /* device */
- Device *device;
- DeviceScene dscene;
-
- /* parameters */
- SceneParams params;
-
- /* mutex must be locked manually by callers */
- thread_mutex mutex;
-
- /* scene update statistics */
- SceneUpdateStats *update_stats;
-
- Scene(const SceneParams &params, Device *device);
- ~Scene();
-
- void host_update(Progress &progress);
-
- void device_update(Device *device, Progress &progress);
-
- bool need_global_attribute(AttributeStandard std);
- void need_global_attributes(AttributeRequestSet &attributes);
-
- enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR };
- MotionType need_motion();
- float motion_shutter_time();
-
- bool need_update();
- bool need_reset();
-
- void reset();
- void device_free();
-
- void collect_statistics(RenderStats *stats);
-
- void enable_update_stats();
-
- void update_kernel_features();
- bool update(Progress &progress);
-
- bool has_shadow_catcher();
- void tag_shadow_catcher_modified();
-
- /* This function is used to create a node of a specified type instead of
- * calling 'new', and sets the scene as the owner of the node.
- * The function has overloads that will also add the created node to the right
- * node array (e.g. Scene::geometry for Geometry nodes) and tag the appropriate
- * manager for an update.
- */
- template<typename T, typename... Args> T *create_node(Args &&...args)
- {
- T *node = new T(args...);
- node->set_owner(this);
- return node;
- }
-
- /* This function is used to delete a node from the scene instead of calling 'delete'
- * and manually removing the node from the data array. It also tags the
- * appropriate manager for an update, if any, and checks that the scene is indeed
- * the owner of the node. Calling this function on a node not owned by the scene
- * will likely cause a crash which we want in order to detect such cases.
- */
- template<typename T> void delete_node(T *node)
- {
- assert(node->get_owner() == this);
- delete_node_impl(node);
- }
-
- /* Same as above, but specify the actual owner.
- */
- template<typename T> void delete_node(T *node, const NodeOwner *owner)
- {
- assert(node->get_owner() == owner);
- delete_node_impl(node);
- (void)owner;
- }
-
- /* Remove all nodes in the set from the appropriate data arrays, and tag the
- * specific managers for an update. This assumes that the scene owns the nodes.
- */
- template<typename T> void delete_nodes(const set<T *> &nodes)
- {
- delete_nodes(nodes, this);
- }
-
- /* Same as above, but specify the actual owner of all the nodes in the set.
- */
- template<typename T> void delete_nodes(const set<T *> &nodes, const NodeOwner *owner);
-
- protected:
- /* Check if some heavy data worth logging was updated.
- * Mainly used to suppress extra annoying logging.
- */
- bool need_data_update();
-
- void free_memory(bool final);
-
- bool kernels_loaded;
- uint loaded_kernel_features;
-
- bool load_kernels(Progress &progress, bool lock_scene = true);
-
- bool has_shadow_catcher_ = false;
- bool shadow_catcher_modified_ = true;
-
- /* Maximum number of closure during session lifetime. */
- int max_closure_global;
-
- /* Get maximum number of closures to be used in kernel. */
- int get_max_closure_count();
-
- /* Get size of a volume stack needed to render this scene. */
- int get_volume_stack_size() const;
-
- template<typename T> void delete_node_impl(T *node)
- {
- delete node;
- }
-};
-
-template<> Light *Scene::create_node<Light>();
-
-template<> Mesh *Scene::create_node<Mesh>();
-
-template<> Object *Scene::create_node<Object>();
-
-template<> Hair *Scene::create_node<Hair>();
-
-template<> Volume *Scene::create_node<Volume>();
-
-template<> ParticleSystem *Scene::create_node<ParticleSystem>();
-
-template<> Shader *Scene::create_node<Shader>();
-
-template<> AlembicProcedural *Scene::create_node<AlembicProcedural>();
-
-template<> Pass *Scene::create_node<Pass>();
-
-template<> void Scene::delete_node_impl(Light *node);
-
-template<> void Scene::delete_node_impl(Mesh *node);
-
-template<> void Scene::delete_node_impl(Volume *node);
-
-template<> void Scene::delete_node_impl(Hair *node);
-
-template<> void Scene::delete_node_impl(Geometry *node);
-
-template<> void Scene::delete_node_impl(Object *node);
-
-template<> void Scene::delete_node_impl(ParticleSystem *node);
-
-template<> void Scene::delete_node_impl(Shader *node);
-
-template<> void Scene::delete_node_impl(Procedural *node);
-
-template<> void Scene::delete_node_impl(AlembicProcedural *node);
-
-template<> void Scene::delete_node_impl(Pass *node);
-
-template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner);
-
-template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner);
-
-template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner);
-
-template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner);
-
-template<> void Scene::delete_nodes(const set<Shader *> &nodes, const NodeOwner *owner);
-
-template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner);
-
-template<> void Scene::delete_nodes(const set<Pass *> &nodes, const NodeOwner *owner);
-
-CCL_NAMESPACE_END
-
-#endif /* __SCENE_H__ */
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
deleted file mode 100644
index a18c61599c2..00000000000
--- a/intern/cycles/render/session.cpp
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <limits.h>
-#include <string.h>
-
-#include "device/cpu/device.h"
-#include "device/device.h"
-#include "integrator/pass_accessor_cpu.h"
-#include "integrator/path_trace.h"
-#include "render/background.h"
-#include "render/bake.h"
-#include "render/buffers.h"
-#include "render/camera.h"
-#include "render/display_driver.h"
-#include "render/graph.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/object.h"
-#include "render/output_driver.h"
-#include "render/scene.h"
-#include "render/session.h"
-
-#include "util/util_foreach.h"
-#include "util/util_function.h"
-#include "util/util_logging.h"
-#include "util/util_math.h"
-#include "util/util_task.h"
-#include "util/util_time.h"
-
-CCL_NAMESPACE_BEGIN
-
-Session::Session(const SessionParams &params_, const SceneParams &scene_params)
- : params(params_), render_scheduler_(tile_manager_, params)
-{
- TaskScheduler::init(params.threads);
-
- session_thread_ = nullptr;
-
- delayed_reset_.do_reset = false;
-
- pause_ = false;
- cancel_ = false;
- new_work_added_ = false;
-
- device = Device::create(params.device, stats, profiler);
-
- scene = new Scene(scene_params, device);
-
- /* Configure path tracer. */
- path_trace_ = make_unique<PathTrace>(
- device, scene->film, &scene->dscene, render_scheduler_, tile_manager_);
- path_trace_->set_progress(&progress);
- path_trace_->progress_update_cb = [&]() { update_status_time(); };
-
- tile_manager_.full_buffer_written_cb = [&](string_view filename) {
- if (!full_buffer_written_cb) {
- return;
- }
- full_buffer_written_cb(filename);
- };
-}
-
-Session::~Session()
-{
- cancel();
-
- /* Make sure path tracer is destroyed before the device. This is needed because destruction might
- * need to access device for device memory free. */
- /* TODO(sergey): Convert device to be unique_ptr, and rely on C++ to destruct objects in the
- * pre-defined order. */
- path_trace_.reset();
-
- delete scene;
- delete device;
-
- TaskScheduler::exit();
-}
-
-void Session::start()
-{
- if (!session_thread_) {
- session_thread_ = new thread(function_bind(&Session::run, this));
- }
-}
-
-void Session::cancel(bool quick)
-{
- if (quick && path_trace_) {
- path_trace_->cancel();
- }
-
- if (session_thread_) {
- /* wait for session thread to end */
- progress.set_cancel("Exiting");
-
- {
- thread_scoped_lock pause_lock(pause_mutex_);
- pause_ = false;
- cancel_ = true;
- }
- pause_cond_.notify_all();
-
- wait();
- }
-}
-
-bool Session::ready_to_reset()
-{
- return path_trace_->ready_to_reset();
-}
-
-void Session::run_main_render_loop()
-{
- path_trace_->clear_display();
-
- while (true) {
- RenderWork render_work = run_update_for_next_iteration();
-
- if (!render_work) {
- if (VLOG_IS_ON(2)) {
- double total_time, render_time;
- progress.get_time(total_time, render_time);
- VLOG(2) << "Rendering in main loop is done in " << render_time << " seconds.";
- VLOG(2) << path_trace_->full_report();
- }
-
- if (params.background) {
- /* if no work left and in background mode, we can stop immediately. */
- progress.set_status("Finished");
- break;
- }
- }
-
- const bool did_cancel = progress.get_cancel();
- if (did_cancel) {
- render_scheduler_.render_work_reschedule_on_cancel(render_work);
- if (!render_work) {
- break;
- }
- }
- else if (run_wait_for_work(render_work)) {
- continue;
- }
-
- /* Stop rendering if error happened during scene update or other step of preparing scene
- * for render. */
- if (device->have_error()) {
- progress.set_error(device->error_message());
- break;
- }
-
- {
- /* buffers mutex is locked entirely while rendering each
- * sample, and released/reacquired on each iteration to allow
- * reset and draw in between */
- thread_scoped_lock buffers_lock(buffers_mutex_);
-
- /* update status and timing */
- update_status_time();
-
- /* render */
- path_trace_->render(render_work);
-
- /* update status and timing */
- update_status_time();
-
- /* Stop rendering if error happened during path tracing. */
- if (device->have_error()) {
- progress.set_error(device->error_message());
- break;
- }
- }
-
- progress.set_update();
-
- if (did_cancel) {
- break;
- }
- }
-}
-
-void Session::run()
-{
- if (params.use_profiling && (params.device.type == DEVICE_CPU)) {
- profiler.start();
- }
-
- /* session thread loop */
- progress.set_status("Waiting for render to start");
-
- /* run */
- if (!progress.get_cancel()) {
- /* reset number of rendered samples */
- progress.reset_sample();
-
- run_main_render_loop();
- }
-
- profiler.stop();
-
- /* progress update */
- if (progress.get_cancel())
- progress.set_status(progress.get_cancel_message());
- else
- progress.set_update();
-}
-
-RenderWork Session::run_update_for_next_iteration()
-{
- RenderWork render_work;
-
- thread_scoped_lock scene_lock(scene->mutex);
- thread_scoped_lock reset_lock(delayed_reset_.mutex);
-
- bool have_tiles = true;
- bool switched_to_new_tile = false;
-
- const bool did_reset = delayed_reset_.do_reset;
- if (delayed_reset_.do_reset) {
- thread_scoped_lock buffers_lock(buffers_mutex_);
- do_delayed_reset();
-
- /* After reset make sure the tile manager is at the first big tile. */
- have_tiles = tile_manager_.next();
- switched_to_new_tile = true;
- }
-
- /* Update number of samples in the integrator.
- * Ideally this would need to happen once in `Session::set_samples()`, but the issue there is
- * the initial configuration when Session is created where the `set_samples()` is not used.
- *
- * NOTE: Unless reset was requested only allow increasing number of samples. */
- if (did_reset || scene->integrator->get_aa_samples() < params.samples) {
- scene->integrator->set_aa_samples(params.samples);
- }
-
- /* Update denoiser settings. */
- {
- const DenoiseParams denoise_params = scene->integrator->get_denoise_params();
- path_trace_->set_denoiser_params(denoise_params);
- }
-
- /* Update adaptive sampling. */
- {
- const AdaptiveSampling adaptive_sampling = scene->integrator->get_adaptive_sampling();
- path_trace_->set_adaptive_sampling(adaptive_sampling);
- }
-
- render_scheduler_.set_num_samples(params.samples);
- render_scheduler_.set_time_limit(params.time_limit);
-
- while (have_tiles) {
- render_work = render_scheduler_.get_render_work();
- if (render_work) {
- break;
- }
-
- progress.add_finished_tile(false);
-
- have_tiles = tile_manager_.next();
- if (have_tiles) {
- render_scheduler_.reset_for_next_tile();
- switched_to_new_tile = true;
- }
- }
-
- if (render_work) {
- scoped_timer update_timer;
-
- if (switched_to_new_tile) {
- BufferParams tile_params = buffer_params_;
-
- const Tile &tile = tile_manager_.get_current_tile();
-
- tile_params.width = tile.width;
- tile_params.height = tile.height;
-
- tile_params.window_x = tile.window_x;
- tile_params.window_y = tile.window_y;
- tile_params.window_width = tile.window_width;
- tile_params.window_height = tile.window_height;
-
- tile_params.full_x = tile.x + buffer_params_.full_x;
- tile_params.full_y = tile.y + buffer_params_.full_y;
- tile_params.full_width = buffer_params_.full_width;
- tile_params.full_height = buffer_params_.full_height;
-
- tile_params.update_offset_stride();
-
- path_trace_->reset(buffer_params_, tile_params);
- }
-
- const int resolution = render_work.resolution_divider;
- const int width = max(1, buffer_params_.full_width / resolution);
- const int height = max(1, buffer_params_.full_height / resolution);
-
- if (update_scene(width, height)) {
- profiler.reset(scene->shaders.size(), scene->objects.size());
- }
- progress.add_skip_time(update_timer, params.background);
- }
-
- return render_work;
-}
-
-bool Session::run_wait_for_work(const RenderWork &render_work)
-{
- /* In an offline rendering there is no pause, and no tiles will mean the job is fully done. */
- if (params.background) {
- return false;
- }
-
- thread_scoped_lock pause_lock(pause_mutex_);
-
- if (!pause_ && render_work) {
- /* Rendering is not paused and there is work to be done. No need to wait for anything. */
- return false;
- }
-
- const bool no_work = !render_work;
- update_status_time(pause_, no_work);
-
- /* Only leave the loop when rendering is not paused. But even if the current render is un-paused
- * but there is nothing to render keep waiting until new work is added. */
- while (!cancel_) {
- scoped_timer pause_timer;
-
- if (!pause_ && (render_work || new_work_added_ || delayed_reset_.do_reset)) {
- break;
- }
-
- /* Wait for either pause state changed, or extra samples added to render. */
- pause_cond_.wait(pause_lock);
-
- if (pause_) {
- progress.add_skip_time(pause_timer, params.background);
- }
-
- update_status_time(pause_, no_work);
- progress.set_update();
- }
-
- new_work_added_ = false;
-
- return no_work;
-}
-
-void Session::draw()
-{
- path_trace_->draw();
-}
-
-int2 Session::get_effective_tile_size() const
-{
- /* No support yet for baking with tiles. */
- if (!params.use_auto_tile || scene->bake_manager->get_baking()) {
- return make_int2(buffer_params_.width, buffer_params_.height);
- }
-
- /* TODO(sergey): Take available memory into account, and if there is enough memory do not tile
- * and prefer optimal performance. */
- const int tile_size = tile_manager_.compute_render_tile_size(params.tile_size);
- return make_int2(tile_size, tile_size);
-}
-
-void Session::do_delayed_reset()
-{
- if (!delayed_reset_.do_reset) {
- return;
- }
- delayed_reset_.do_reset = false;
-
- params = delayed_reset_.session_params;
- buffer_params_ = delayed_reset_.buffer_params;
-
- /* Store parameters used for buffers access outside of scene graph. */
- buffer_params_.samples = params.samples;
- buffer_params_.exposure = scene->film->get_exposure();
- buffer_params_.use_approximate_shadow_catcher =
- scene->film->get_use_approximate_shadow_catcher();
- buffer_params_.use_transparent_background = scene->background->get_transparent();
-
- /* Tile and work scheduling. */
- tile_manager_.reset_scheduling(buffer_params_, get_effective_tile_size());
- render_scheduler_.reset(buffer_params_, params.samples);
-
- /* Passes. */
- /* When multiple tiles are used SAMPLE_COUNT pass is used to keep track of possible partial
- * tile results. It is safe to use generic update function here which checks for changes since
- * changes in tile settings re-creates session, which ensures film is fully updated on tile
- * changes. */
- scene->film->update_passes(scene, tile_manager_.has_multiple_tiles());
-
- /* Update for new state of scene and passes. */
- buffer_params_.update_passes(scene->passes);
- tile_manager_.update(buffer_params_, scene);
-
- /* Progress. */
- progress.reset_sample();
- progress.set_total_pixel_samples(static_cast<uint64_t>(buffer_params_.width) *
- buffer_params_.height * params.samples);
-
- if (!params.background) {
- progress.set_start_time();
- }
- progress.set_render_start_time();
-}
-
-void Session::reset(const SessionParams &session_params, const BufferParams &buffer_params)
-{
- {
- thread_scoped_lock reset_lock(delayed_reset_.mutex);
- thread_scoped_lock pause_lock(pause_mutex_);
-
- delayed_reset_.do_reset = true;
- delayed_reset_.session_params = session_params;
- delayed_reset_.buffer_params = buffer_params;
-
- path_trace_->cancel();
- }
-
- pause_cond_.notify_all();
-}
-
-void Session::set_samples(int samples)
-{
- if (samples == params.samples) {
- return;
- }
-
- params.samples = samples;
-
- {
- thread_scoped_lock pause_lock(pause_mutex_);
- new_work_added_ = true;
- }
-
- pause_cond_.notify_all();
-}
-
-void Session::set_time_limit(double time_limit)
-{
- if (time_limit == params.time_limit) {
- return;
- }
-
- params.time_limit = time_limit;
-
- {
- thread_scoped_lock pause_lock(pause_mutex_);
- new_work_added_ = true;
- }
-
- pause_cond_.notify_all();
-}
-
-void Session::set_pause(bool pause)
-{
- bool notify = false;
-
- {
- thread_scoped_lock pause_lock(pause_mutex_);
-
- if (pause != pause_) {
- pause_ = pause;
- notify = true;
- }
- }
-
- if (session_thread_) {
- if (notify) {
- pause_cond_.notify_all();
- }
- }
- else if (pause_) {
- update_status_time(pause_);
- }
-}
-
-void Session::set_output_driver(unique_ptr<OutputDriver> driver)
-{
- path_trace_->set_output_driver(move(driver));
-}
-
-void Session::set_display_driver(unique_ptr<DisplayDriver> driver)
-{
- path_trace_->set_display_driver(move(driver));
-}
-
-double Session::get_estimated_remaining_time() const
-{
- const float completed = progress.get_progress();
- if (completed == 0.0f) {
- return 0.0;
- }
-
- double total_time, render_time;
- progress.get_time(total_time, render_time);
- double remaining = (1.0 - (double)completed) * (render_time / (double)completed);
-
- const double time_limit = render_scheduler_.get_time_limit();
- if (time_limit != 0.0) {
- remaining = min(remaining, max(time_limit - render_time, 0.0));
- }
-
- return remaining;
-}
-
-void Session::wait()
-{
- if (session_thread_) {
- session_thread_->join();
- delete session_thread_;
- }
-
- session_thread_ = nullptr;
-}
-
-bool Session::update_scene(int width, int height)
-{
- /* Update camera if dimensions changed for progressive render. the camera
- * knows nothing about progressive or cropped rendering, it just gets the
- * image dimensions passed in. */
- Camera *cam = scene->camera;
- cam->set_screen_size(width, height);
-
- /* First detect which kernel features are used and allocate working memory.
- * This helps estimate how may device memory is available for the scene and
- * how much we need to allocate on the host instead. */
- scene->update_kernel_features();
-
- path_trace_->load_kernels();
- path_trace_->alloc_work_memory();
-
- if (scene->update(progress)) {
- return true;
- }
-
- return false;
-}
-
-static string status_append(const string &status, const string &suffix)
-{
- string prefix = status;
- if (!prefix.empty()) {
- prefix += ", ";
- }
- return prefix + suffix;
-}
-
-void Session::update_status_time(bool show_pause, bool show_done)
-{
- string status, substatus;
-
- const int current_tile = progress.get_rendered_tiles();
- const int num_tiles = tile_manager_.get_num_tiles();
-
- const int current_sample = progress.get_current_sample();
- const int num_samples = render_scheduler_.get_num_samples();
-
- /* TIle. */
- if (tile_manager_.has_multiple_tiles()) {
- substatus = status_append(substatus,
- string_printf("Rendered %d/%d Tiles", current_tile, num_tiles));
- }
-
- /* Sample. */
- if (num_samples == Integrator::MAX_SAMPLES) {
- substatus = status_append(substatus, string_printf("Sample %d", current_sample));
- }
- else {
- substatus = status_append(substatus,
- string_printf("Sample %d/%d", current_sample, num_samples));
- }
-
- /* TODO(sergey): Denoising status from the path trace. */
-
- if (show_pause) {
- status = "Rendering Paused";
- }
- else if (show_done) {
- status = "Rendering Done";
- progress.set_end_time(); /* Save end time so that further calls to get_time are accurate. */
- }
- else {
- status = substatus;
- substatus.clear();
- }
-
- progress.set_status(status, substatus);
-}
-
-void Session::device_free()
-{
- scene->device_free();
- path_trace_->device_free();
-}
-
-void Session::collect_statistics(RenderStats *render_stats)
-{
- scene->collect_statistics(render_stats);
- if (params.use_profiling && (params.device.type == DEVICE_CPU)) {
- render_stats->collect_profiling(scene, profiler);
- }
-}
-
-/* --------------------------------------------------------------------
- * Full-frame on-disk storage.
- */
-
-void Session::process_full_buffer_from_disk(string_view filename)
-{
- path_trace_->process_full_buffer_from_disk(filename);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
deleted file mode 100644
index 46c964bc98c..00000000000
--- a/intern/cycles/render/session.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SESSION_H__
-#define __SESSION_H__
-
-#include "device/device.h"
-#include "integrator/render_scheduler.h"
-#include "render/buffers.h"
-#include "render/shader.h"
-#include "render/stats.h"
-#include "render/tile.h"
-
-#include "util/util_progress.h"
-#include "util/util_stats.h"
-#include "util/util_thread.h"
-#include "util/util_unique_ptr.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BufferParams;
-class Device;
-class DeviceScene;
-class DisplayDriver;
-class OutputDriver;
-class PathTrace;
-class Progress;
-class RenderBuffers;
-class Scene;
-class SceneParams;
-
-/* Session Parameters */
-
-class SessionParams {
- public:
- DeviceInfo device;
-
- bool headless;
- bool background;
-
- bool experimental;
- int samples;
- int pixel_size;
- int threads;
-
- /* Limit in seconds for how long path tracing is allowed to happen.
- * Zero means no limit is applied. */
- double time_limit;
-
- bool use_profiling;
-
- bool use_auto_tile;
- int tile_size;
-
- ShadingSystem shadingsystem;
-
- SessionParams()
- {
- headless = false;
- background = false;
-
- experimental = false;
- samples = 1024;
- pixel_size = 1;
- threads = 0;
- time_limit = 0.0;
-
- use_profiling = false;
-
- use_auto_tile = true;
- tile_size = 2048;
-
- shadingsystem = SHADINGSYSTEM_SVM;
- }
-
- bool modified(const SessionParams &params) const
- {
- /* Modified means we have to recreate the session, any parameter changes
- * that can be handled by an existing Session are omitted. */
- return !(device == params.device && headless == params.headless &&
- background == params.background && experimental == params.experimental &&
- pixel_size == params.pixel_size && threads == params.threads &&
- use_profiling == params.use_profiling && shadingsystem == params.shadingsystem &&
- use_auto_tile == params.use_auto_tile && tile_size == params.tile_size);
- }
-};
-
-/* Session
- *
- * This is the class that contains the session thread, running the render
- * control loop and dispatching tasks. */
-
-class Session {
- public:
- Device *device;
- Scene *scene;
- Progress progress;
- SessionParams params;
- Stats stats;
- Profiler profiler;
-
- /* Callback is invoked by tile manager whenever on-dist tiles storage file is closed after
- * writing. Allows an engine integration to keep track of those files without worry about
- * transferring the information when it needs to re-create session during rendering. */
- function<void(string_view)> full_buffer_written_cb;
-
- explicit Session(const SessionParams &params, const SceneParams &scene_params);
- ~Session();
-
- void start();
-
- /* When quick cancel is requested path tracing is cancels as soon as possible, without waiting
- * for the buffer to be uniformly sampled. */
- void cancel(bool quick = false);
-
- void draw();
- void wait();
-
- bool ready_to_reset();
- void reset(const SessionParams &session_params, const BufferParams &buffer_params);
-
- void set_pause(bool pause);
-
- void set_samples(int samples);
- void set_time_limit(double time_limit);
-
- void set_output_driver(unique_ptr<OutputDriver> driver);
- void set_display_driver(unique_ptr<DisplayDriver> driver);
-
- double get_estimated_remaining_time() const;
-
- void device_free();
-
- /* Returns the rendering progress or 0 if no progress can be determined
- * (for example, when rendering with unlimited samples). */
- float get_progress();
-
- void collect_statistics(RenderStats *stats);
-
- /* --------------------------------------------------------------------
- * Full-frame on-disk storage.
- */
-
- /* Read given full-frame file from disk, perform needed processing and write it to the software
- * via the write callback. */
- void process_full_buffer_from_disk(string_view filename);
-
- protected:
- struct DelayedReset {
- thread_mutex mutex;
- bool do_reset;
- SessionParams session_params;
- BufferParams buffer_params;
- } delayed_reset_;
-
- void run();
-
- /* Update for the new iteration of the main loop in run implementation (run_cpu and run_gpu).
- *
- * Will take care of the following things:
- * - Delayed reset
- * - Scene update
- * - Tile manager advance
- * - Render scheduler work request
- *
- * The updates are done in a proper order with proper locking around them, which guarantees
- * that the device side of scene and render buffers are always in a consistent state.
- *
- * Returns render work which is to be rendered next. */
- RenderWork run_update_for_next_iteration();
-
- /* Wait for rendering to be unpaused, or for new tiles for render to arrive.
- * Returns true if new main render loop iteration is required after this function call.
- *
- * The `render_work` is the work which was scheduled by the render scheduler right before
- * checking the pause. */
- bool run_wait_for_work(const RenderWork &render_work);
-
- void run_main_render_loop();
-
- bool update_scene(int width, int height);
-
- void update_status_time(bool show_pause = false, bool show_done = false);
-
- void do_delayed_reset();
-
- int2 get_effective_tile_size() const;
-
- thread *session_thread_;
-
- bool pause_ = false;
- bool cancel_ = false;
- bool new_work_added_ = false;
-
- thread_condition_variable pause_cond_;
- thread_mutex pause_mutex_;
- thread_mutex tile_mutex_;
- thread_mutex buffers_mutex_;
-
- TileManager tile_manager_;
- BufferParams buffer_params_;
-
- /* Render scheduler is used to get work to be rendered with the current big tile. */
- RenderScheduler render_scheduler_;
-
- /* Path tracer object.
- *
- * Is a single full-frame path tracer for interactive viewport rendering.
- * A path tracer for the current big-tile for an offline rendering. */
- unique_ptr<PathTrace> path_trace_;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __SESSION_H__ */
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
deleted file mode 100644
index 171cbb89549..00000000000
--- a/intern/cycles/render/shader.cpp
+++ /dev/null
@@ -1,885 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "device/device.h"
-
-#include "render/background.h"
-#include "render/camera.h"
-#include "render/colorspace.h"
-#include "render/graph.h"
-#include "render/integrator.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/nodes.h"
-#include "render/object.h"
-#include "render/osl.h"
-#include "render/procedural.h"
-#include "render/scene.h"
-#include "render/shader.h"
-#include "render/svm.h"
-#include "render/tables.h"
-
-#include "util/util_foreach.h"
-#include "util/util_murmurhash.h"
-#include "util/util_task.h"
-#include "util/util_transform.h"
-
-#ifdef WITH_OCIO
-# include <OpenColorIO/OpenColorIO.h>
-namespace OCIO = OCIO_NAMESPACE;
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-thread_mutex ShaderManager::lookup_table_mutex;
-vector<float> ShaderManager::beckmann_table;
-bool ShaderManager::beckmann_table_ready = false;
-
-/* Beckmann sampling precomputed table, see bsdf_microfacet.h */
-
-/* 2D slope distribution (alpha = 1.0) */
-static float beckmann_table_P22(const float slope_x, const float slope_y)
-{
- return expf(-(slope_x * slope_x + slope_y * slope_y));
-}
-
-/* maximal slope amplitude (range that contains 99.99% of the distribution) */
-static float beckmann_table_slope_max()
-{
- return 6.0;
-}
-
-/* MSVC 2015 needs this ugly hack to prevent a codegen bug on x86
- * see T50176 for details
- */
-#if defined(_MSC_VER) && (_MSC_VER == 1900)
-# define MSVC_VOLATILE volatile
-#else
-# define MSVC_VOLATILE
-#endif
-
-/* Paper used: Importance Sampling Microfacet-Based BSDFs with the
- * Distribution of Visible Normals. Supplemental Material 2/2.
- *
- * http://hal.inria.fr/docs/01/00/66/20/ANNEX/supplemental2.pdf
- */
-static void beckmann_table_rows(float *table, int row_from, int row_to)
-{
- /* allocate temporary data */
- const int DATA_TMP_SIZE = 512;
- vector<double> slope_x(DATA_TMP_SIZE);
- vector<double> CDF_P22_omega_i(DATA_TMP_SIZE);
-
- /* loop over incident directions */
- for (int index_theta = row_from; index_theta < row_to; index_theta++) {
- /* incident vector */
- const float cos_theta = index_theta / (BECKMANN_TABLE_SIZE - 1.0f);
- const float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta);
-
- /* for a given incident vector
- * integrate P22_{omega_i}(x_slope, 1, 1), Eq. (10) */
- slope_x[0] = (double)-beckmann_table_slope_max();
- CDF_P22_omega_i[0] = 0;
-
- for (MSVC_VOLATILE int index_slope_x = 1; index_slope_x < DATA_TMP_SIZE; ++index_slope_x) {
- /* slope_x */
- slope_x[index_slope_x] = (double)(-beckmann_table_slope_max() +
- 2.0f * beckmann_table_slope_max() * index_slope_x /
- (DATA_TMP_SIZE - 1.0f));
-
- /* dot product with incident vector */
- float dot_product = fmaxf(0.0f, -(float)slope_x[index_slope_x] * sin_theta + cos_theta);
- /* marginalize P22_{omega_i}(x_slope, 1, 1), Eq. (10) */
- float P22_omega_i = 0.0f;
-
- for (int j = 0; j < 100; ++j) {
- float slope_y = -beckmann_table_slope_max() +
- 2.0f * beckmann_table_slope_max() * j * (1.0f / 99.0f);
- P22_omega_i += dot_product * beckmann_table_P22((float)slope_x[index_slope_x], slope_y);
- }
-
- /* CDF of P22_{omega_i}(x_slope, 1, 1), Eq. (10) */
- CDF_P22_omega_i[index_slope_x] = CDF_P22_omega_i[index_slope_x - 1] + (double)P22_omega_i;
- }
-
- /* renormalize CDF_P22_omega_i */
- for (int index_slope_x = 1; index_slope_x < DATA_TMP_SIZE; ++index_slope_x)
- CDF_P22_omega_i[index_slope_x] /= CDF_P22_omega_i[DATA_TMP_SIZE - 1];
-
- /* loop over random number U1 */
- int index_slope_x = 0;
-
- for (int index_U = 0; index_U < BECKMANN_TABLE_SIZE; ++index_U) {
- const double U = 0.0000001 + 0.9999998 * index_U / (double)(BECKMANN_TABLE_SIZE - 1);
-
- /* inverse CDF_P22_omega_i, solve Eq.(11) */
- while (CDF_P22_omega_i[index_slope_x] <= U)
- ++index_slope_x;
-
- const double interp = (CDF_P22_omega_i[index_slope_x] - U) /
- (CDF_P22_omega_i[index_slope_x] - CDF_P22_omega_i[index_slope_x - 1]);
-
- /* store value */
- table[index_U + index_theta * BECKMANN_TABLE_SIZE] =
- (float)(interp * slope_x[index_slope_x - 1] + (1.0 - interp) * slope_x[index_slope_x]);
- }
- }
-}
-
-#undef MSVC_VOLATILE
-
-static void beckmann_table_build(vector<float> &table)
-{
- table.resize(BECKMANN_TABLE_SIZE * BECKMANN_TABLE_SIZE);
-
- /* multithreaded build */
- TaskPool pool;
-
- for (int i = 0; i < BECKMANN_TABLE_SIZE; i += 8)
- pool.push(function_bind(&beckmann_table_rows, &table[0], i, i + 8));
-
- pool.wait_work();
-}
-
-/* Shader */
-
-NODE_DEFINE(Shader)
-{
- NodeType *type = NodeType::add("shader", create);
-
- SOCKET_BOOLEAN(use_mis, "Use MIS", true);
- SOCKET_BOOLEAN(use_transparent_shadow, "Use Transparent Shadow", true);
- SOCKET_BOOLEAN(heterogeneous_volume, "Heterogeneous Volume", true);
-
- static NodeEnum volume_sampling_method_enum;
- volume_sampling_method_enum.insert("distance", VOLUME_SAMPLING_DISTANCE);
- volume_sampling_method_enum.insert("equiangular", VOLUME_SAMPLING_EQUIANGULAR);
- volume_sampling_method_enum.insert("multiple_importance", VOLUME_SAMPLING_MULTIPLE_IMPORTANCE);
- SOCKET_ENUM(volume_sampling_method,
- "Volume Sampling Method",
- volume_sampling_method_enum,
- VOLUME_SAMPLING_MULTIPLE_IMPORTANCE);
-
- static NodeEnum volume_interpolation_method_enum;
- volume_interpolation_method_enum.insert("linear", VOLUME_INTERPOLATION_LINEAR);
- volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC);
- SOCKET_ENUM(volume_interpolation_method,
- "Volume Interpolation Method",
- volume_interpolation_method_enum,
- VOLUME_INTERPOLATION_LINEAR);
-
- SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
-
- static NodeEnum displacement_method_enum;
- displacement_method_enum.insert("bump", DISPLACE_BUMP);
- displacement_method_enum.insert("true", DISPLACE_TRUE);
- displacement_method_enum.insert("both", DISPLACE_BOTH);
- SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
-
- SOCKET_INT(pass_id, "Pass ID", 0);
-
- return type;
-}
-
-Shader::Shader() : Node(get_node_type())
-{
- pass_id = 0;
-
- graph = NULL;
-
- has_surface = false;
- has_surface_transparent = false;
- has_surface_emission = false;
- has_surface_raytrace = false;
- has_surface_bssrdf = false;
- has_volume = false;
- has_displacement = false;
- has_bump = false;
- has_bssrdf_bump = false;
- has_surface_spatial_varying = false;
- has_volume_spatial_varying = false;
- has_volume_attribute_dependency = false;
- has_integrator_dependency = false;
- has_volume_connected = false;
- prev_volume_step_rate = 0.0f;
-
- displacement_method = DISPLACE_BUMP;
-
- id = -1;
-
- need_update_uvs = true;
- need_update_attribute = true;
- need_update_displacement = true;
-}
-
-Shader::~Shader()
-{
- delete graph;
-}
-
-bool Shader::is_constant_emission(float3 *emission)
-{
- /* If the shader has AOVs, they need to be evaluated, so we can't skip the shader. */
- foreach (ShaderNode *node, graph->nodes) {
- if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
- return false;
- }
- }
-
- ShaderInput *surf = graph->output()->input("Surface");
-
- if (surf->link == NULL) {
- return false;
- }
-
- if (surf->link->parent->type == EmissionNode::get_node_type()) {
- EmissionNode *node = (EmissionNode *)surf->link->parent;
-
- assert(node->input("Color"));
- assert(node->input("Strength"));
-
- if (node->input("Color")->link || node->input("Strength")->link) {
- return false;
- }
-
- *emission = node->get_color() * node->get_strength();
- }
- else if (surf->link->parent->type == BackgroundNode::get_node_type()) {
- BackgroundNode *node = (BackgroundNode *)surf->link->parent;
-
- assert(node->input("Color"));
- assert(node->input("Strength"));
-
- if (node->input("Color")->link || node->input("Strength")->link) {
- return false;
- }
-
- *emission = node->get_color() * node->get_strength();
- }
- else {
- return false;
- }
-
- return true;
-}
-
-void Shader::set_graph(ShaderGraph *graph_)
-{
- /* do this here already so that we can detect if mesh or object attributes
- * are needed, since the node attribute callbacks check if their sockets
- * are connected but proxy nodes should not count */
- if (graph_) {
- graph_->remove_proxy_nodes();
-
- if (displacement_method != DISPLACE_BUMP) {
- graph_->compute_displacement_hash();
- }
- }
-
- /* update geometry if displacement changed */
- if (displacement_method != DISPLACE_BUMP) {
- const char *old_hash = (graph) ? graph->displacement_hash.c_str() : "";
- const char *new_hash = (graph_) ? graph_->displacement_hash.c_str() : "";
-
- if (strcmp(old_hash, new_hash) != 0) {
- need_update_displacement = true;
- }
- }
-
- /* assign graph */
- delete graph;
- graph = graph_;
-
- /* Store info here before graph optimization to make sure that
- * nodes that get optimized away still count. */
- has_volume_connected = (graph->output()->input("Volume")->link != NULL);
-}
-
-void Shader::tag_update(Scene *scene)
-{
- /* update tag */
- tag_modified();
-
- scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
-
- /* if the shader previously was emissive, update light distribution,
- * if the new shader is emissive, a light manager update tag will be
- * done in the shader manager device update. */
- if (use_mis && has_surface_emission)
- scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
-
- /* Special handle of background MIS light for now: for some reason it
- * has use_mis set to false. We are quite close to release now, so
- * better to be safe.
- */
- if (this == scene->background->get_shader(scene)) {
- scene->light_manager->need_update_background = true;
- if (scene->light_manager->has_background_light(scene)) {
- scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
- }
- }
-
- /* quick detection of which kind of shaders we have to avoid loading
- * e.g. surface attributes when there is only a volume shader. this could
- * be more fine grained but it's better than nothing */
- OutputNode *output = graph->output();
- bool prev_has_volume = has_volume;
- has_surface = has_surface || output->input("Surface")->link;
- has_volume = has_volume || output->input("Volume")->link;
- has_displacement = has_displacement || output->input("Displacement")->link;
-
- /* get requested attributes. this could be optimized by pruning unused
- * nodes here already, but that's the job of the shader manager currently,
- * and may not be so great for interactive rendering where you temporarily
- * disconnect a node */
-
- AttributeRequestSet prev_attributes = attributes;
-
- attributes.clear();
- foreach (ShaderNode *node, graph->nodes)
- node->attributes(this, &attributes);
-
- if (has_displacement) {
- if (displacement_method == DISPLACE_BOTH) {
- attributes.add(ATTR_STD_POSITION_UNDISPLACED);
- }
- if (displacement_method_is_modified()) {
- need_update_displacement = true;
- scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_DISPLACEMENT_MODIFIED);
- scene->object_manager->need_flags_update = true;
- }
- }
-
- /* compare if the attributes changed, mesh manager will check
- * need_update_attribute, update the relevant meshes and clear it. */
- if (attributes.modified(prev_attributes)) {
- need_update_attribute = true;
- scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_ATTRIBUTE_MODIFIED);
- scene->procedural_manager->tag_update();
- }
-
- if (has_volume != prev_has_volume || volume_step_rate != prev_volume_step_rate) {
- scene->geometry_manager->need_flags_update = true;
- scene->object_manager->need_flags_update = true;
- prev_volume_step_rate = volume_step_rate;
- }
-}
-
-void Shader::tag_used(Scene *scene)
-{
- /* if an unused shader suddenly gets used somewhere, it needs to be
- * recompiled because it was skipped for compilation before */
- if (!reference_count()) {
- tag_modified();
- /* We do not reference here as the shader will be referenced when added to a socket. */
- scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
- }
-}
-
-bool Shader::need_update_geometry() const
-{
- return need_update_uvs || need_update_attribute || need_update_displacement;
-}
-
-/* Shader Manager */
-
-ShaderManager::ShaderManager()
-{
- update_flags = UPDATE_ALL;
- beckmann_table_offset = TABLE_OFFSET_INVALID;
-
- init_xyz_transforms();
-}
-
-ShaderManager::~ShaderManager()
-{
-}
-
-ShaderManager *ShaderManager::create(int shadingsystem)
-{
- ShaderManager *manager;
-
- (void)shadingsystem; /* Ignored when built without OSL. */
-
-#ifdef WITH_OSL
- if (shadingsystem == SHADINGSYSTEM_OSL) {
- manager = new OSLShaderManager();
- }
- else
-#endif
- {
- manager = new SVMShaderManager();
- }
-
- return manager;
-}
-
-uint ShaderManager::get_attribute_id(ustring name)
-{
- thread_scoped_spin_lock lock(attribute_lock_);
-
- /* get a unique id for each name, for SVM attribute lookup */
- AttributeIDMap::iterator it = unique_attribute_id.find(name);
-
- if (it != unique_attribute_id.end())
- return it->second;
-
- uint id = (uint)ATTR_STD_NUM + unique_attribute_id.size();
- unique_attribute_id[name] = id;
- return id;
-}
-
-uint ShaderManager::get_attribute_id(AttributeStandard std)
-{
- return (uint)std;
-}
-
-int ShaderManager::get_shader_id(Shader *shader, bool smooth)
-{
- /* get a shader id to pass to the kernel */
- int id = shader->id;
-
- /* smooth flag */
- if (smooth)
- id |= SHADER_SMOOTH_NORMAL;
-
- /* default flags */
- id |= SHADER_CAST_SHADOW | SHADER_AREA_LIGHT;
-
- return id;
-}
-
-void ShaderManager::host_update(Scene *scene, Progress &progress)
-{
- if (!need_update()) {
- return;
- }
-
- uint id = 0;
- foreach (Shader *shader, scene->shaders) {
- shader->id = id++;
- }
-
- /* Those shaders should always be compiled as they are used as fallback if a shader cannot be
- * found, e.g. bad shader index for the triangle shaders on a Mesh. */
- assert(scene->default_surface->reference_count() != 0);
- assert(scene->default_light->reference_count() != 0);
- assert(scene->default_background->reference_count() != 0);
- assert(scene->default_empty->reference_count() != 0);
-
- host_update_specific(scene, progress);
-}
-
-void ShaderManager::device_update(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- if (!need_update()) {
- return;
- }
-
- device_update_specific(device, dscene, scene, progress);
-}
-
-void ShaderManager::device_update_common(Device * /*device*/,
- DeviceScene *dscene,
- Scene *scene,
- Progress & /*progress*/)
-{
- dscene->shaders.free();
-
- if (scene->shaders.size() == 0)
- return;
-
- KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size());
- bool has_volumes = false;
- bool has_transparent_shadow = false;
-
- foreach (Shader *shader, scene->shaders) {
- uint flag = 0;
-
- if (shader->get_use_mis())
- flag |= SD_USE_MIS;
- if (shader->has_surface_emission)
- flag |= SD_HAS_EMISSION;
- if (shader->has_surface_transparent && shader->get_use_transparent_shadow())
- flag |= SD_HAS_TRANSPARENT_SHADOW;
- if (shader->has_surface_raytrace)
- flag |= SD_HAS_RAYTRACE;
- if (shader->has_volume) {
- flag |= SD_HAS_VOLUME;
- has_volumes = true;
-
- /* todo: this could check more fine grained, to skip useless volumes
- * enclosed inside an opaque bsdf.
- */
- flag |= SD_HAS_TRANSPARENT_SHADOW;
- }
- /* in this case we can assume transparent surface */
- if (shader->has_volume_connected && !shader->has_surface)
- flag |= SD_HAS_ONLY_VOLUME;
- if (shader->has_volume) {
- if (shader->get_heterogeneous_volume() && shader->has_volume_spatial_varying)
- flag |= SD_HETEROGENEOUS_VOLUME;
- }
- if (shader->has_volume_attribute_dependency)
- flag |= SD_NEED_VOLUME_ATTRIBUTES;
- if (shader->has_bssrdf_bump)
- flag |= SD_HAS_BSSRDF_BUMP;
- if (shader->get_volume_sampling_method() == VOLUME_SAMPLING_EQUIANGULAR)
- flag |= SD_VOLUME_EQUIANGULAR;
- if (shader->get_volume_sampling_method() == VOLUME_SAMPLING_MULTIPLE_IMPORTANCE)
- flag |= SD_VOLUME_MIS;
- if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC)
- flag |= SD_VOLUME_CUBIC;
- if (shader->has_bump)
- flag |= SD_HAS_BUMP;
- if (shader->get_displacement_method() != DISPLACE_BUMP)
- flag |= SD_HAS_DISPLACEMENT;
-
- /* constant emission check */
- float3 constant_emission = zero_float3();
- if (shader->is_constant_emission(&constant_emission))
- flag |= SD_HAS_CONSTANT_EMISSION;
-
- uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0);
-
- /* regular shader */
- kshader->flags = flag;
- kshader->pass_id = shader->get_pass_id();
- kshader->constant_emission[0] = constant_emission.x;
- kshader->constant_emission[1] = constant_emission.y;
- kshader->constant_emission[2] = constant_emission.z;
- kshader->cryptomatte_id = util_hash_to_float(cryptomatte_id);
- kshader++;
-
- has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
- }
-
- dscene->shaders.copy_to_device();
-
- /* lookup tables */
- KernelTables *ktables = &dscene->data.tables;
-
- /* beckmann lookup table */
- if (beckmann_table_offset == TABLE_OFFSET_INVALID) {
- if (!beckmann_table_ready) {
- thread_scoped_lock lock(lookup_table_mutex);
- if (!beckmann_table_ready) {
- beckmann_table_build(beckmann_table);
- beckmann_table_ready = true;
- }
- }
- beckmann_table_offset = scene->lookup_tables->add_table(dscene, beckmann_table);
- }
- ktables->beckmann_offset = (int)beckmann_table_offset;
-
- /* integrator */
- KernelIntegrator *kintegrator = &dscene->data.integrator;
- kintegrator->use_volumes = has_volumes;
- /* TODO(sergey): De-duplicate with flags set in integrator.cpp. */
- kintegrator->transparent_shadows = has_transparent_shadow;
-
- /* film */
- KernelFilm *kfilm = &dscene->data.film;
- /* color space, needs to be here because e.g. displacement shaders could depend on it */
- kfilm->xyz_to_r = float3_to_float4(xyz_to_r);
- kfilm->xyz_to_g = float3_to_float4(xyz_to_g);
- kfilm->xyz_to_b = float3_to_float4(xyz_to_b);
- kfilm->rgb_to_y = float3_to_float4(rgb_to_y);
-}
-
-void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *scene)
-{
- scene->lookup_tables->remove_table(&beckmann_table_offset);
-
- dscene->shaders.free();
-}
-
-void ShaderManager::add_default(Scene *scene)
-{
- /* default surface */
- {
- ShaderGraph *graph = new ShaderGraph();
-
- DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
- diffuse->set_color(make_float3(0.8f, 0.8f, 0.8f));
- graph->add(diffuse);
-
- graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface"));
-
- Shader *shader = scene->create_node<Shader>();
- shader->name = "default_surface";
- shader->set_graph(graph);
- shader->reference();
- scene->default_surface = shader;
- shader->tag_update(scene);
- }
-
- /* default volume */
- {
- ShaderGraph *graph = new ShaderGraph();
-
- PrincipledVolumeNode *principled = graph->create_node<PrincipledVolumeNode>();
- graph->add(principled);
-
- graph->connect(principled->output("Volume"), graph->output()->input("Volume"));
-
- Shader *shader = scene->create_node<Shader>();
- shader->name = "default_volume";
- shader->set_graph(graph);
- scene->default_volume = shader;
- shader->tag_update(scene);
- /* No default reference for the volume to avoid compiling volume kernels if there are no actual
- * volumes in the scene */
- }
-
- /* default light */
- {
- ShaderGraph *graph = new ShaderGraph();
-
- EmissionNode *emission = graph->create_node<EmissionNode>();
- emission->set_color(make_float3(0.8f, 0.8f, 0.8f));
- emission->set_strength(0.0f);
- graph->add(emission);
-
- graph->connect(emission->output("Emission"), graph->output()->input("Surface"));
-
- Shader *shader = scene->create_node<Shader>();
- shader->name = "default_light";
- shader->set_graph(graph);
- shader->reference();
- scene->default_light = shader;
- shader->tag_update(scene);
- }
-
- /* default background */
- {
- ShaderGraph *graph = new ShaderGraph();
-
- Shader *shader = scene->create_node<Shader>();
- shader->name = "default_background";
- shader->set_graph(graph);
- shader->reference();
- scene->default_background = shader;
- shader->tag_update(scene);
- }
-
- /* default empty */
- {
- ShaderGraph *graph = new ShaderGraph();
-
- Shader *shader = scene->create_node<Shader>();
- shader->name = "default_empty";
- shader->set_graph(graph);
- shader->reference();
- scene->default_empty = shader;
- shader->tag_update(scene);
- }
-}
-
-uint ShaderManager::get_graph_kernel_features(ShaderGraph *graph)
-{
- uint kernel_features = 0;
-
- foreach (ShaderNode *node, graph->nodes) {
- kernel_features |= node->get_feature();
- if (node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) {
- BsdfBaseNode *bsdf_node = static_cast<BsdfBaseNode *>(node);
- if (CLOSURE_IS_VOLUME(bsdf_node->get_closure_type())) {
- kernel_features |= KERNEL_FEATURE_NODE_VOLUME;
- }
- else if (CLOSURE_IS_PRINCIPLED(bsdf_node->get_closure_type())) {
- kernel_features |= KERNEL_FEATURE_PRINCIPLED;
- }
- }
- if (node->has_surface_bssrdf()) {
- kernel_features |= KERNEL_FEATURE_SUBSURFACE;
- }
- if (node->has_surface_transparent()) {
- kernel_features |= KERNEL_FEATURE_TRANSPARENT;
- }
- }
-
- return kernel_features;
-}
-
-uint ShaderManager::get_kernel_features(Scene *scene)
-{
- uint kernel_features = KERNEL_FEATURE_NODE_BSDF | KERNEL_FEATURE_NODE_EMISSION;
- for (int i = 0; i < scene->shaders.size(); i++) {
- Shader *shader = scene->shaders[i];
- if (!shader->reference_count()) {
- continue;
- }
-
- /* Gather requested features from all the nodes from the graph nodes. */
- kernel_features |= get_graph_kernel_features(shader->graph);
- ShaderNode *output_node = shader->graph->output();
- if (output_node->input("Displacement")->link != NULL) {
- kernel_features |= KERNEL_FEATURE_NODE_BUMP;
- if (shader->get_displacement_method() == DISPLACE_BOTH) {
- kernel_features |= KERNEL_FEATURE_NODE_BUMP_STATE;
- }
- }
- /* On top of volume nodes, also check if we need volume sampling because
- * e.g. an Emission node would slip through the KERNEL_FEATURE_NODE_VOLUME check */
- if (shader->has_volume_connected) {
- kernel_features |= KERNEL_FEATURE_VOLUME;
- }
- }
-
- return kernel_features;
-}
-
-void ShaderManager::free_memory()
-{
- beckmann_table.free_memory();
-
-#ifdef WITH_OSL
- OSLShaderManager::free_memory();
-#endif
-
- ColorSpaceManager::free_memory();
-}
-
-float ShaderManager::linear_rgb_to_gray(float3 c)
-{
- return dot(c, rgb_to_y);
-}
-
-string ShaderManager::get_cryptomatte_materials(Scene *scene)
-{
- string manifest = "{";
- unordered_set<ustring, ustringHash> materials;
- foreach (Shader *shader, scene->shaders) {
- if (materials.count(shader->name)) {
- continue;
- }
- materials.insert(shader->name);
- uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0);
- manifest += string_printf("\"%s\":\"%08x\",", shader->name.c_str(), cryptomatte_id);
- }
- manifest[manifest.size() - 1] = '}';
- return manifest;
-}
-
-void ShaderManager::tag_update(Scene * /*scene*/, uint32_t /*flag*/)
-{
- /* update everything for now */
- update_flags = ShaderManager::UPDATE_ALL;
-}
-
-bool ShaderManager::need_update() const
-{
- return update_flags != UPDATE_NONE;
-}
-
-#ifdef WITH_OCIO
-static bool to_scene_linear_transform(OCIO::ConstConfigRcPtr &config,
- const char *colorspace,
- Transform &to_scene_linear)
-{
- OCIO::ConstProcessorRcPtr processor;
- try {
- processor = config->getProcessor(OCIO::ROLE_SCENE_LINEAR, colorspace);
- }
- catch (OCIO::Exception &) {
- return false;
- }
-
- if (!processor) {
- return false;
- }
-
- OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
- if (!device_processor) {
- return false;
- }
-
- to_scene_linear = transform_identity();
- device_processor->applyRGB(&to_scene_linear.x.x);
- device_processor->applyRGB(&to_scene_linear.y.x);
- device_processor->applyRGB(&to_scene_linear.z.x);
- to_scene_linear = transform_transposed_inverse(to_scene_linear);
- return true;
-}
-#endif
-
-void ShaderManager::init_xyz_transforms()
-{
- /* Default to ITU-BT.709 in case no appropriate transform found.
- * Note XYZ here is defined as having a D65 white point. */
- xyz_to_r = make_float3(3.2404542f, -1.5371385f, -0.4985314f);
- xyz_to_g = make_float3(-0.9692660f, 1.8760108f, 0.0415560f);
- xyz_to_b = make_float3(0.0556434f, -0.2040259f, 1.0572252f);
- rgb_to_y = make_float3(0.2126729f, 0.7151522f, 0.0721750f);
-
-#ifdef WITH_OCIO
- /* Get from OpenColorO config if it has the required roles. */
- OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
- if (!(config && config->hasRole(OCIO::ROLE_SCENE_LINEAR))) {
- return;
- }
-
- Transform xyz_to_rgb;
-
- if (config->hasRole("aces_interchange")) {
- /* Standard OpenColorIO role, defined as ACES2065-1. */
- const Transform xyz_E_to_aces = make_transform(1.0498110175f,
- 0.0f,
- -0.0000974845f,
- 0.0f,
- -0.4959030231f,
- 1.3733130458f,
- 0.0982400361f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.9912520182f,
- 0.0f);
- const Transform xyz_D65_to_E = make_transform(
- 1.0521111f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.9184170f, 0.0f);
-
- Transform aces_to_rgb;
- if (!to_scene_linear_transform(config, "aces_interchange", aces_to_rgb)) {
- return;
- }
-
- xyz_to_rgb = aces_to_rgb * xyz_E_to_aces * xyz_D65_to_E;
- }
- else if (config->hasRole("XYZ")) {
- /* Custom role used before the standard existed. */
- if (!to_scene_linear_transform(config, "XYZ", xyz_to_rgb)) {
- return;
- }
- }
- else {
- /* No reference role found to determine XYZ. */
- return;
- }
-
- xyz_to_r = float4_to_float3(xyz_to_rgb.x);
- xyz_to_g = float4_to_float3(xyz_to_rgb.y);
- xyz_to_b = float4_to_float3(xyz_to_rgb.z);
-
- const Transform rgb_to_xyz = transform_inverse(xyz_to_rgb);
- rgb_to_y = float4_to_float3(rgb_to_xyz.y);
-#endif
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h
deleted file mode 100644
index 44d88ac0e93..00000000000
--- a/intern/cycles/render/shader.h
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SHADER_H__
-#define __SHADER_H__
-
-#ifdef WITH_OSL
-/* So no context pollution happens from indirectly included windows.h */
-# include "util/util_windows.h"
-# include <OSL/oslexec.h>
-#endif
-
-#include "kernel/kernel_types.h"
-#include "render/attribute.h"
-
-#include "graph/node.h"
-
-#include "util/util_map.h"
-#include "util/util_param.h"
-#include "util/util_string.h"
-#include "util/util_thread.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class Mesh;
-class Progress;
-class Scene;
-class ShaderGraph;
-struct float3;
-
-enum ShadingSystem { SHADINGSYSTEM_OSL, SHADINGSYSTEM_SVM };
-
-/* Keep those in sync with the python-defined enum. */
-enum VolumeSampling {
- VOLUME_SAMPLING_DISTANCE = 0,
- VOLUME_SAMPLING_EQUIANGULAR = 1,
- VOLUME_SAMPLING_MULTIPLE_IMPORTANCE = 2,
-
- VOLUME_NUM_SAMPLING,
-};
-
-enum VolumeInterpolation {
- VOLUME_INTERPOLATION_LINEAR = 0,
- VOLUME_INTERPOLATION_CUBIC = 1,
-
- VOLUME_NUM_INTERPOLATION,
-};
-
-enum DisplacementMethod {
- DISPLACE_BUMP = 0,
- DISPLACE_TRUE = 1,
- DISPLACE_BOTH = 2,
-
- DISPLACE_NUM_METHODS,
-};
-
-/* Shader describing the appearance of a Mesh, Light or Background.
- *
- * While there is only a single shader graph, it has three outputs: surface,
- * volume and displacement, that the shader manager will compile and execute
- * separately. */
-
-class Shader : public Node {
- public:
- NODE_DECLARE
-
- /* shader graph */
- ShaderGraph *graph;
-
- NODE_SOCKET_API(int, pass_id)
-
- /* sampling */
- NODE_SOCKET_API(bool, use_mis)
- NODE_SOCKET_API(bool, use_transparent_shadow)
- NODE_SOCKET_API(bool, heterogeneous_volume)
- NODE_SOCKET_API(VolumeSampling, volume_sampling_method)
- NODE_SOCKET_API(int, volume_interpolation_method)
- NODE_SOCKET_API(float, volume_step_rate)
-
- /* displacement */
- NODE_SOCKET_API(DisplacementMethod, displacement_method)
-
- float prev_volume_step_rate;
-
- /* synchronization */
- bool need_update_uvs;
- bool need_update_attribute;
- bool need_update_displacement;
-
- /* If the shader has only volume components, the surface is assumed to
- * be transparent.
- * However, graph optimization might remove the volume subgraph, but
- * since the user connected something to the volume output the surface
- * should still be transparent.
- * Therefore, has_volume_connected stores whether some volume sub-tree
- * was connected before optimization. */
- bool has_volume_connected;
-
- /* information about shader after compiling */
- bool has_surface;
- bool has_surface_emission;
- bool has_surface_transparent;
- bool has_surface_raytrace;
- bool has_volume;
- bool has_displacement;
- bool has_surface_bssrdf;
- bool has_bump;
- bool has_bssrdf_bump;
- bool has_surface_spatial_varying;
- bool has_volume_spatial_varying;
- bool has_volume_attribute_dependency;
- bool has_integrator_dependency;
-
- /* requested mesh attributes */
- AttributeRequestSet attributes;
-
- /* determined before compiling */
- uint id;
-
-#ifdef WITH_OSL
- /* osl shading state references */
- OSL::ShaderGroupRef osl_surface_ref;
- OSL::ShaderGroupRef osl_surface_bump_ref;
- OSL::ShaderGroupRef osl_volume_ref;
- OSL::ShaderGroupRef osl_displacement_ref;
-#endif
-
- Shader();
- ~Shader();
-
- /* Checks whether the shader consists of just a emission node with fixed inputs that's connected
- * directly to the output.
- * If yes, it sets the content of emission to the constant value (color * strength), which is
- * then used for speeding up light evaluation. */
- bool is_constant_emission(float3 *emission);
-
- void set_graph(ShaderGraph *graph);
- void tag_update(Scene *scene);
- void tag_used(Scene *scene);
-
- /* Return true when either of the surface or displacement socket of the output node is linked.
- * This should be used to ensure that surface attributes are also requested even when only the
- * displacement socket is linked. */
- bool has_surface_link() const
- {
- return has_surface || has_displacement;
- }
-
- bool need_update_geometry() const;
-};
-
-/* Shader Manager virtual base class
- *
- * From this the SVM and OSL shader managers are derived, that do the actual
- * shader compiling and device updating. */
-
-class ShaderManager {
- public:
- enum : uint32_t {
- SHADER_ADDED = (1 << 0),
- SHADER_MODIFIED = (1 << 2),
- INTEGRATOR_MODIFIED = (1 << 3),
-
- /* tag everything in the manager for an update */
- UPDATE_ALL = ~0u,
-
- UPDATE_NONE = 0u,
- };
-
- static ShaderManager *create(int shadingsystem);
- virtual ~ShaderManager();
-
- virtual void reset(Scene *scene) = 0;
-
- virtual bool use_osl()
- {
- return false;
- }
-
- void host_update(Scene *scene, Progress &progress);
- virtual void host_update_specific(Scene *scene, Progress &progress) = 0;
-
- /* device update */
- void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
- virtual void device_update_specific(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress) = 0;
- virtual void device_free(Device *device, DeviceScene *dscene, Scene *scene) = 0;
-
- void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
- void device_free_common(Device *device, DeviceScene *dscene, Scene *scene);
-
- /* get globally unique id for a type of attribute */
- uint get_attribute_id(ustring name);
- uint get_attribute_id(AttributeStandard std);
-
- /* get shader id for mesh faces */
- int get_shader_id(Shader *shader, bool smooth = false);
-
- /* add default shaders to scene, to use as default for things that don't
- * have any shader assigned explicitly */
- static void add_default(Scene *scene);
-
- /* Selective nodes compilation. */
- uint get_kernel_features(Scene *scene);
-
- static void free_memory();
-
- float linear_rgb_to_gray(float3 c);
-
- string get_cryptomatte_materials(Scene *scene);
-
- void tag_update(Scene *scene, uint32_t flag);
-
- bool need_update() const;
-
- void init_xyz_transforms();
-
- protected:
- ShaderManager();
-
- uint32_t update_flags;
-
- typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap;
- AttributeIDMap unique_attribute_id;
-
- static thread_mutex lookup_table_mutex;
- static vector<float> beckmann_table;
- static bool beckmann_table_ready;
-
- size_t beckmann_table_offset;
-
- uint get_graph_kernel_features(ShaderGraph *graph);
-
- thread_spin_lock attribute_lock_;
-
- float3 xyz_to_r;
- float3 xyz_to_g;
- float3 xyz_to_b;
- float3 rgb_to_y;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __SHADER_H__ */
diff --git a/intern/cycles/render/sobol.cpp b/intern/cycles/render/sobol.cpp
deleted file mode 100644
index c821249b239..00000000000
--- a/intern/cycles/render/sobol.cpp
+++ /dev/null
@@ -1,21307 +0,0 @@
-/*
- * Sobol sequence direction vectors.
- *
- * This file contains code to create direction vectors for generating sobol
- * sequences in high dimensions. It is adapted from code on this webpage:
- *
- * http://web.maths.unsw.edu.au/~fkuo/sobol/
- *
- * From these papers:
- *
- * S. Joe and F. Y. Kuo, Remark on Algorithm 659: Implementing Sobol's quasirandom
- * sequence generator, ACM Trans. Math. Softw. 29, 49-57 (2003)
- *
- * S. Joe and F. Y. Kuo, Constructing Sobol sequences with better two-dimensional
- * projections, SIAM J. Sci. Comput. 30, 2635-2654 (2008)
- */
-
-/* Copyright (c) 2008, Frances Y. Kuo and Stephen Joe
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the names of the copyright holders nor the names of the
- * University of New South Wales and the University of Waikato
- * and its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "util/util_types.h"
-
-#include "render/sobol.h"
-
-CCL_NAMESPACE_BEGIN
-
-#define SOBOL_MAX_NUMBER 32
-
-typedef struct SobolDirectionNumbers {
- uint d, s, a;
- uint m[SOBOL_MAX_NUMBER];
-} SobolDirectionNumbers;
-
-/* Note: this file is skipped by clang-format. */
-
-/* Keep simple alignment. */
-/* clang-format off */
-static const SobolDirectionNumbers SOBOL_NUMBERS[SOBOL_MAX_DIMENSIONS - 1] = {
-{2, 1, 0, {1}},
-{3, 2, 1, {1, 3}},
-{4, 3, 1, {1, 3, 1}},
-{5, 3, 2, {1, 1, 1}},
-{6, 4, 1, {1, 1, 3, 3}},
-{7, 4, 4, {1, 3, 5, 13}},
-{8, 5, 2, {1, 1, 5, 5, 17}},
-{9, 5, 4, {1, 1, 5, 5, 5}},
-{10, 5, 7, {1, 1, 7, 11, 19}},
-{11, 5, 11, {1, 1, 5, 1, 1}},
-{12, 5, 13, {1, 1, 1, 3, 11}},
-{13, 5, 14, {1, 3, 5, 5, 31}},
-{14, 6, 1, {1, 3, 3, 9, 7, 49}},
-{15, 6, 13, {1, 1, 1, 15, 21, 21}},
-{16, 6, 16, {1, 3, 1, 13, 27, 49}},
-{17, 6, 19, {1, 1, 1, 15, 7, 5}},
-{18, 6, 22, {1, 3, 1, 15, 13, 25}},
-{19, 6, 25, {1, 1, 5, 5, 19, 61}},
-{20, 7, 1, {1, 3, 7, 11, 23, 15, 103}},
-{21, 7, 4, {1, 3, 7, 13, 13, 15, 69}},
-{22, 7, 7, {1, 1, 3, 13, 7, 35, 63}},
-{23, 7, 8, {1, 3, 5, 9, 1, 25, 53}},
-{24, 7, 14, {1, 3, 1, 13, 9, 35, 107}},
-{25, 7, 19, {1, 3, 1, 5, 27, 61, 31}},
-{26, 7, 21, {1, 1, 5, 11, 19, 41, 61}},
-{27, 7, 28, {1, 3, 5, 3, 3, 13, 69}},
-{28, 7, 31, {1, 1, 7, 13, 1, 19, 1}},
-{29, 7, 32, {1, 3, 7, 5, 13, 19, 59}},
-{30, 7, 37, {1, 1, 3, 9, 25, 29, 41}},
-{31, 7, 41, {1, 3, 5, 13, 23, 1, 55}},
-{32, 7, 42, {1, 3, 7, 3, 13, 59, 17}},
-{33, 7, 50, {1, 3, 1, 3, 5, 53, 69}},
-{34, 7, 55, {1, 1, 5, 5, 23, 33, 13}},
-{35, 7, 56, {1, 1, 7, 7, 1, 61, 123}},
-{36, 7, 59, {1, 1, 7, 9, 13, 61, 49}},
-{37, 7, 62, {1, 3, 3, 5, 3, 55, 33}},
-{38, 8, 14, {1, 3, 1, 15, 31, 13, 49, 245}},
-{39, 8, 21, {1, 3, 5, 15, 31, 59, 63, 97}},
-{40, 8, 22, {1, 3, 1, 11, 11, 11, 77, 249}},
-{41, 8, 38, {1, 3, 1, 11, 27, 43, 71, 9}},
-{42, 8, 47, {1, 1, 7, 15, 21, 11, 81, 45}},
-{43, 8, 49, {1, 3, 7, 3, 25, 31, 65, 79}},
-{44, 8, 50, {1, 3, 1, 1, 19, 11, 3, 205}},
-{45, 8, 52, {1, 1, 5, 9, 19, 21, 29, 157}},
-{46, 8, 56, {1, 3, 7, 11, 1, 33, 89, 185}},
-{47, 8, 67, {1, 3, 3, 3, 15, 9, 79, 71}},
-{48, 8, 70, {1, 3, 7, 11, 15, 39, 119, 27}},
-{49, 8, 84, {1, 1, 3, 1, 11, 31, 97, 225}},
-{50, 8, 97, {1, 1, 1, 3, 23, 43, 57, 177}},
-{51, 8, 103, {1, 3, 7, 7, 17, 17, 37, 71}},
-{52, 8, 115, {1, 3, 1, 5, 27, 63, 123, 213}},
-{53, 8, 122, {1, 1, 3, 5, 11, 43, 53, 133}},
-{54, 9, 8, {1, 3, 5, 5, 29, 17, 47, 173, 479}},
-{55, 9, 13, {1, 3, 3, 11, 3, 1, 109, 9, 69}},
-{56, 9, 16, {1, 1, 1, 5, 17, 39, 23, 5, 343}},
-{57, 9, 22, {1, 3, 1, 5, 25, 15, 31, 103, 499}},
-{58, 9, 25, {1, 1, 1, 11, 11, 17, 63, 105, 183}},
-{59, 9, 44, {1, 1, 5, 11, 9, 29, 97, 231, 363}},
-{60, 9, 47, {1, 1, 5, 15, 19, 45, 41, 7, 383}},
-{61, 9, 52, {1, 3, 7, 7, 31, 19, 83, 137, 221}},
-{62, 9, 55, {1, 1, 1, 3, 23, 15, 111, 223, 83}},
-{63, 9, 59, {1, 1, 5, 13, 31, 15, 55, 25, 161}},
-{64, 9, 62, {1, 1, 3, 13, 25, 47, 39, 87, 257}},
-{65, 9, 67, {1, 1, 1, 11, 21, 53, 125, 249, 293}},
-{66, 9, 74, {1, 1, 7, 11, 11, 7, 57, 79, 323}},
-{67, 9, 81, {1, 1, 5, 5, 17, 13, 81, 3, 131}},
-{68, 9, 82, {1, 1, 7, 13, 23, 7, 65, 251, 475}},
-{69, 9, 87, {1, 3, 5, 1, 9, 43, 3, 149, 11}},
-{70, 9, 91, {1, 1, 3, 13, 31, 13, 13, 255, 487}},
-{71, 9, 94, {1, 3, 3, 1, 5, 63, 89, 91, 127}},
-{72, 9, 103, {1, 1, 3, 3, 1, 19, 123, 127, 237}},
-{73, 9, 104, {1, 1, 5, 7, 23, 31, 37, 243, 289}},
-{74, 9, 109, {1, 1, 5, 11, 17, 53, 117, 183, 491}},
-{75, 9, 122, {1, 1, 1, 5, 1, 13, 13, 209, 345}},
-{76, 9, 124, {1, 1, 3, 15, 1, 57, 115, 7, 33}},
-{77, 9, 137, {1, 3, 1, 11, 7, 43, 81, 207, 175}},
-{78, 9, 138, {1, 3, 1, 1, 15, 27, 63, 255, 49}},
-{79, 9, 143, {1, 3, 5, 3, 27, 61, 105, 171, 305}},
-{80, 9, 145, {1, 1, 5, 3, 1, 3, 57, 249, 149}},
-{81, 9, 152, {1, 1, 3, 5, 5, 57, 15, 13, 159}},
-{82, 9, 157, {1, 1, 1, 11, 7, 11, 105, 141, 225}},
-{83, 9, 167, {1, 3, 3, 5, 27, 59, 121, 101, 271}},
-{84, 9, 173, {1, 3, 5, 9, 11, 49, 51, 59, 115}},
-{85, 9, 176, {1, 1, 7, 1, 23, 45, 125, 71, 419}},
-{86, 9, 181, {1, 1, 3, 5, 23, 5, 105, 109, 75}},
-{87, 9, 182, {1, 1, 7, 15, 7, 11, 67, 121, 453}},
-{88, 9, 185, {1, 3, 7, 3, 9, 13, 31, 27, 449}},
-{89, 9, 191, {1, 3, 1, 15, 19, 39, 39, 89, 15}},
-{90, 9, 194, {1, 1, 1, 1, 1, 33, 73, 145, 379}},
-{91, 9, 199, {1, 3, 1, 15, 15, 43, 29, 13, 483}},
-{92, 9, 218, {1, 1, 7, 3, 19, 27, 85, 131, 431}},
-{93, 9, 220, {1, 3, 3, 3, 5, 35, 23, 195, 349}},
-{94, 9, 227, {1, 3, 3, 7, 9, 27, 39, 59, 297}},
-{95, 9, 229, {1, 1, 3, 9, 11, 17, 13, 241, 157}},
-{96, 9, 230, {1, 3, 7, 15, 25, 57, 33, 189, 213}},
-{97, 9, 234, {1, 1, 7, 1, 9, 55, 73, 83, 217}},
-{98, 9, 236, {1, 3, 3, 13, 19, 27, 23, 113, 249}},
-{99, 9, 241, {1, 3, 5, 3, 23, 43, 3, 253, 479}},
-{100, 9, 244, {1, 1, 5, 5, 11, 5, 45, 117, 217}},
-{101, 9, 253, {1, 3, 3, 7, 29, 37, 33, 123, 147}},
-{102, 10, 4, {1, 3, 1, 15, 5, 5, 37, 227, 223, 459}},
-{103, 10, 13, {1, 1, 7, 5, 5, 39, 63, 255, 135, 487}},
-{104, 10, 19, {1, 3, 1, 7, 9, 7, 87, 249, 217, 599}},
-{105, 10, 22, {1, 1, 3, 13, 9, 47, 7, 225, 363, 247}},
-{106, 10, 50, {1, 3, 7, 13, 19, 13, 9, 67, 9, 737}},
-{107, 10, 55, {1, 3, 5, 5, 19, 59, 7, 41, 319, 677}},
-{108, 10, 64, {1, 1, 5, 3, 31, 63, 15, 43, 207, 789}},
-{109, 10, 69, {1, 1, 7, 9, 13, 39, 3, 47, 497, 169}},
-{110, 10, 98, {1, 3, 1, 7, 21, 17, 97, 19, 415, 905}},
-{111, 10, 107, {1, 3, 7, 1, 3, 31, 71, 111, 165, 127}},
-{112, 10, 115, {1, 1, 5, 11, 1, 61, 83, 119, 203, 847}},
-{113, 10, 121, {1, 3, 3, 13, 9, 61, 19, 97, 47, 35}},
-{114, 10, 127, {1, 1, 7, 7, 15, 29, 63, 95, 417, 469}},
-{115, 10, 134, {1, 3, 1, 9, 25, 9, 71, 57, 213, 385}},
-{116, 10, 140, {1, 3, 5, 13, 31, 47, 101, 57, 39, 341}},
-{117, 10, 145, {1, 1, 3, 3, 31, 57, 125, 173, 365, 551}},
-{118, 10, 152, {1, 3, 7, 1, 13, 57, 67, 157, 451, 707}},
-{119, 10, 158, {1, 1, 1, 7, 21, 13, 105, 89, 429, 965}},
-{120, 10, 161, {1, 1, 5, 9, 17, 51, 45, 119, 157, 141}},
-{121, 10, 171, {1, 3, 7, 7, 13, 45, 91, 9, 129, 741}},
-{122, 10, 181, {1, 3, 7, 1, 23, 57, 67, 141, 151, 571}},
-{123, 10, 194, {1, 1, 3, 11, 17, 47, 93, 107, 375, 157}},
-{124, 10, 199, {1, 3, 3, 5, 11, 21, 43, 51, 169, 915}},
-{125, 10, 203, {1, 1, 5, 3, 15, 55, 101, 67, 455, 625}},
-{126, 10, 208, {1, 3, 5, 9, 1, 23, 29, 47, 345, 595}},
-{127, 10, 227, {1, 3, 7, 7, 5, 49, 29, 155, 323, 589}},
-{128, 10, 242, {1, 3, 3, 7, 5, 41, 127, 61, 261, 717}},
-{129, 10, 251, {1, 3, 7, 7, 17, 23, 117, 67, 129, 1009}},
-{130, 10, 253, {1, 1, 3, 13, 11, 39, 21, 207, 123, 305}},
-{131, 10, 265, {1, 1, 3, 9, 29, 3, 95, 47, 231, 73}},
-{132, 10, 266, {1, 3, 1, 9, 1, 29, 117, 21, 441, 259}},
-{133, 10, 274, {1, 3, 1, 13, 21, 39, 125, 211, 439, 723}},
-{134, 10, 283, {1, 1, 7, 3, 17, 63, 115, 89, 49, 773}},
-{135, 10, 289, {1, 3, 7, 13, 11, 33, 101, 107, 63, 73}},
-{136, 10, 295, {1, 1, 5, 5, 13, 57, 63, 135, 437, 177}},
-{137, 10, 301, {1, 1, 3, 7, 27, 63, 93, 47, 417, 483}},
-{138, 10, 316, {1, 1, 3, 1, 23, 29, 1, 191, 49, 23}},
-{139, 10, 319, {1, 1, 3, 15, 25, 55, 9, 101, 219, 607}},
-{140, 10, 324, {1, 3, 1, 7, 7, 19, 51, 251, 393, 307}},
-{141, 10, 346, {1, 3, 3, 3, 25, 55, 17, 75, 337, 3}},
-{142, 10, 352, {1, 1, 1, 13, 25, 17, 65, 45, 479, 413}},
-{143, 10, 361, {1, 1, 7, 7, 27, 49, 99, 161, 213, 727}},
-{144, 10, 367, {1, 3, 5, 1, 23, 5, 43, 41, 251, 857}},
-{145, 10, 382, {1, 3, 3, 7, 11, 61, 39, 87, 383, 835}},
-{146, 10, 395, {1, 1, 3, 15, 13, 7, 29, 7, 505, 923}},
-{147, 10, 398, {1, 3, 7, 1, 5, 31, 47, 157, 445, 501}},
-{148, 10, 400, {1, 1, 3, 7, 1, 43, 9, 147, 115, 605}},
-{149, 10, 412, {1, 3, 3, 13, 5, 1, 119, 211, 455, 1001}},
-{150, 10, 419, {1, 1, 3, 5, 13, 19, 3, 243, 75, 843}},
-{151, 10, 422, {1, 3, 7, 7, 1, 19, 91, 249, 357, 589}},
-{152, 10, 426, {1, 1, 1, 9, 1, 25, 109, 197, 279, 411}},
-{153, 10, 428, {1, 3, 1, 15, 23, 57, 59, 135, 191, 75}},
-{154, 10, 433, {1, 1, 5, 15, 29, 21, 39, 253, 383, 349}},
-{155, 10, 446, {1, 3, 3, 5, 19, 45, 61, 151, 199, 981}},
-{156, 10, 454, {1, 3, 5, 13, 9, 61, 107, 141, 141, 1}},
-{157, 10, 457, {1, 3, 1, 11, 27, 25, 85, 105, 309, 979}},
-{158, 10, 472, {1, 3, 3, 11, 19, 7, 115, 223, 349, 43}},
-{159, 10, 493, {1, 1, 7, 9, 21, 39, 123, 21, 275, 927}},
-{160, 10, 505, {1, 1, 7, 13, 15, 41, 47, 243, 303, 437}},
-{161, 10, 508, {1, 1, 1, 7, 7, 3, 15, 99, 409, 719}},
-{162, 11, 2, {1, 3, 3, 15, 27, 49, 113, 123, 113, 67, 469}},
-{163, 11, 11, {1, 3, 7, 11, 3, 23, 87, 169, 119, 483, 199}},
-{164, 11, 21, {1, 1, 5, 15, 7, 17, 109, 229, 179, 213, 741}},
-{165, 11, 22, {1, 1, 5, 13, 11, 17, 25, 135, 403, 557, 1433}},
-{166, 11, 35, {1, 3, 1, 1, 1, 61, 67, 215, 189, 945, 1243}},
-{167, 11, 49, {1, 1, 7, 13, 17, 33, 9, 221, 429, 217, 1679}},
-{168, 11, 50, {1, 1, 3, 11, 27, 3, 15, 93, 93, 865, 1049}},
-{169, 11, 56, {1, 3, 7, 7, 25, 41, 121, 35, 373, 379, 1547}},
-{170, 11, 61, {1, 3, 3, 9, 11, 35, 45, 205, 241, 9, 59}},
-{171, 11, 70, {1, 3, 1, 7, 3, 51, 7, 177, 53, 975, 89}},
-{172, 11, 74, {1, 1, 3, 5, 27, 1, 113, 231, 299, 759, 861}},
-{173, 11, 79, {1, 3, 3, 15, 25, 29, 5, 255, 139, 891, 2031}},
-{174, 11, 84, {1, 3, 1, 1, 13, 9, 109, 193, 419, 95, 17}},
-{175, 11, 88, {1, 1, 7, 9, 3, 7, 29, 41, 135, 839, 867}},
-{176, 11, 103, {1, 1, 7, 9, 25, 49, 123, 217, 113, 909, 215}},
-{177, 11, 104, {1, 1, 7, 3, 23, 15, 43, 133, 217, 327, 901}},
-{178, 11, 112, {1, 1, 3, 3, 13, 53, 63, 123, 477, 711, 1387}},
-{179, 11, 115, {1, 1, 3, 15, 7, 29, 75, 119, 181, 957, 247}},
-{180, 11, 117, {1, 1, 1, 11, 27, 25, 109, 151, 267, 99, 1461}},
-{181, 11, 122, {1, 3, 7, 15, 5, 5, 53, 145, 11, 725, 1501}},
-{182, 11, 134, {1, 3, 7, 1, 9, 43, 71, 229, 157, 607, 1835}},
-{183, 11, 137, {1, 3, 3, 13, 25, 1, 5, 27, 471, 349, 127}},
-{184, 11, 146, {1, 1, 1, 1, 23, 37, 9, 221, 269, 897, 1685}},
-{185, 11, 148, {1, 1, 3, 3, 31, 29, 51, 19, 311, 553, 1969}},
-{186, 11, 157, {1, 3, 7, 5, 5, 55, 17, 39, 475, 671, 1529}},
-{187, 11, 158, {1, 1, 7, 1, 1, 35, 47, 27, 437, 395, 1635}},
-{188, 11, 162, {1, 1, 7, 3, 13, 23, 43, 135, 327, 139, 389}},
-{189, 11, 164, {1, 3, 7, 3, 9, 25, 91, 25, 429, 219, 513}},
-{190, 11, 168, {1, 1, 3, 5, 13, 29, 119, 201, 277, 157, 2043}},
-{191, 11, 173, {1, 3, 5, 3, 29, 57, 13, 17, 167, 739, 1031}},
-{192, 11, 185, {1, 3, 3, 5, 29, 21, 95, 27, 255, 679, 1531}},
-{193, 11, 186, {1, 3, 7, 15, 9, 5, 21, 71, 61, 961, 1201}},
-{194, 11, 191, {1, 3, 5, 13, 15, 57, 33, 93, 459, 867, 223}},
-{195, 11, 193, {1, 1, 1, 15, 17, 43, 127, 191, 67, 177, 1073}},
-{196, 11, 199, {1, 1, 1, 15, 23, 7, 21, 199, 75, 293, 1611}},
-{197, 11, 213, {1, 3, 7, 13, 15, 39, 21, 149, 65, 741, 319}},
-{198, 11, 214, {1, 3, 7, 11, 23, 13, 101, 89, 277, 519, 711}},
-{199, 11, 220, {1, 3, 7, 15, 19, 27, 85, 203, 441, 97, 1895}},
-{200, 11, 227, {1, 3, 1, 3, 29, 25, 21, 155, 11, 191, 197}},
-{201, 11, 236, {1, 1, 7, 5, 27, 11, 81, 101, 457, 675, 1687}},
-{202, 11, 242, {1, 3, 1, 5, 25, 5, 65, 193, 41, 567, 781}},
-{203, 11, 251, {1, 3, 1, 5, 11, 15, 113, 77, 411, 695, 1111}},
-{204, 11, 256, {1, 1, 3, 9, 11, 53, 119, 171, 55, 297, 509}},
-{205, 11, 259, {1, 1, 1, 1, 11, 39, 113, 139, 165, 347, 595}},
-{206, 11, 265, {1, 3, 7, 11, 9, 17, 101, 13, 81, 325, 1733}},
-{207, 11, 266, {1, 3, 1, 1, 21, 43, 115, 9, 113, 907, 645}},
-{208, 11, 276, {1, 1, 7, 3, 9, 25, 117, 197, 159, 471, 475}},
-{209, 11, 292, {1, 3, 1, 9, 11, 21, 57, 207, 485, 613, 1661}},
-{210, 11, 304, {1, 1, 7, 7, 27, 55, 49, 223, 89, 85, 1523}},
-{211, 11, 310, {1, 1, 5, 3, 19, 41, 45, 51, 447, 299, 1355}},
-{212, 11, 316, {1, 3, 1, 13, 1, 33, 117, 143, 313, 187, 1073}},
-{213, 11, 319, {1, 1, 7, 7, 5, 11, 65, 97, 377, 377, 1501}},
-{214, 11, 322, {1, 3, 1, 1, 21, 35, 95, 65, 99, 23, 1239}},
-{215, 11, 328, {1, 1, 5, 9, 3, 37, 95, 167, 115, 425, 867}},
-{216, 11, 334, {1, 3, 3, 13, 1, 37, 27, 189, 81, 679, 773}},
-{217, 11, 339, {1, 1, 3, 11, 1, 61, 99, 233, 429, 969, 49}},
-{218, 11, 341, {1, 1, 1, 7, 25, 63, 99, 165, 245, 793, 1143}},
-{219, 11, 345, {1, 1, 5, 11, 11, 43, 55, 65, 71, 283, 273}},
-{220, 11, 346, {1, 1, 5, 5, 9, 3, 101, 251, 355, 379, 1611}},
-{221, 11, 362, {1, 1, 1, 15, 21, 63, 85, 99, 49, 749, 1335}},
-{222, 11, 367, {1, 1, 5, 13, 27, 9, 121, 43, 255, 715, 289}},
-{223, 11, 372, {1, 3, 1, 5, 27, 19, 17, 223, 77, 571, 1415}},
-{224, 11, 375, {1, 1, 5, 3, 13, 59, 125, 251, 195, 551, 1737}},
-{225, 11, 376, {1, 3, 3, 15, 13, 27, 49, 105, 389, 971, 755}},
-{226, 11, 381, {1, 3, 5, 15, 23, 43, 35, 107, 447, 763, 253}},
-{227, 11, 385, {1, 3, 5, 11, 21, 3, 17, 39, 497, 407, 611}},
-{228, 11, 388, {1, 1, 7, 13, 15, 31, 113, 17, 23, 507, 1995}},
-{229, 11, 392, {1, 1, 7, 15, 3, 15, 31, 153, 423, 79, 503}},
-{230, 11, 409, {1, 1, 7, 9, 19, 25, 23, 171, 505, 923, 1989}},
-{231, 11, 415, {1, 1, 5, 9, 21, 27, 121, 223, 133, 87, 697}},
-{232, 11, 416, {1, 1, 5, 5, 9, 19, 107, 99, 319, 765, 1461}},
-{233, 11, 421, {1, 1, 3, 3, 19, 25, 3, 101, 171, 729, 187}},
-{234, 11, 428, {1, 1, 3, 1, 13, 23, 85, 93, 291, 209, 37}},
-{235, 11, 431, {1, 1, 1, 15, 25, 25, 77, 253, 333, 947, 1073}},
-{236, 11, 434, {1, 1, 3, 9, 17, 29, 55, 47, 255, 305, 2037}},
-{237, 11, 439, {1, 3, 3, 9, 29, 63, 9, 103, 489, 939, 1523}},
-{238, 11, 446, {1, 3, 7, 15, 7, 31, 89, 175, 369, 339, 595}},
-{239, 11, 451, {1, 3, 7, 13, 25, 5, 71, 207, 251, 367, 665}},
-{240, 11, 453, {1, 3, 3, 3, 21, 25, 75, 35, 31, 321, 1603}},
-{241, 11, 457, {1, 1, 1, 9, 11, 1, 65, 5, 11, 329, 535}},
-{242, 11, 458, {1, 1, 5, 3, 19, 13, 17, 43, 379, 485, 383}},
-{243, 11, 471, {1, 3, 5, 13, 13, 9, 85, 147, 489, 787, 1133}},
-{244, 11, 475, {1, 3, 1, 1, 5, 51, 37, 129, 195, 297, 1783}},
-{245, 11, 478, {1, 1, 3, 15, 19, 57, 59, 181, 455, 697, 2033}},
-{246, 11, 484, {1, 3, 7, 1, 27, 9, 65, 145, 325, 189, 201}},
-{247, 11, 493, {1, 3, 1, 15, 31, 23, 19, 5, 485, 581, 539}},
-{248, 11, 494, {1, 1, 7, 13, 11, 15, 65, 83, 185, 847, 831}},
-{249, 11, 499, {1, 3, 5, 7, 7, 55, 73, 15, 303, 511, 1905}},
-{250, 11, 502, {1, 3, 5, 9, 7, 21, 45, 15, 397, 385, 597}},
-{251, 11, 517, {1, 3, 7, 3, 23, 13, 73, 221, 511, 883, 1265}},
-{252, 11, 518, {1, 1, 3, 11, 1, 51, 73, 185, 33, 975, 1441}},
-{253, 11, 524, {1, 3, 3, 9, 19, 59, 21, 39, 339, 37, 143}},
-{254, 11, 527, {1, 1, 7, 1, 31, 33, 19, 167, 117, 635, 639}},
-{255, 11, 555, {1, 1, 1, 3, 5, 13, 59, 83, 355, 349, 1967}},
-{256, 11, 560, {1, 1, 1, 5, 19, 3, 53, 133, 97, 863, 983}},
-{257, 11, 565, {1, 3, 1, 13, 9, 41, 91, 105, 173, 97, 625}},
-{258, 11, 569, {1, 1, 5, 3, 7, 49, 115, 133, 71, 231, 1063}},
-{259, 11, 578, {1, 1, 7, 5, 17, 43, 47, 45, 497, 547, 757}},
-{260, 11, 580, {1, 3, 5, 15, 21, 61, 123, 191, 249, 31, 631}},
-{261, 11, 587, {1, 3, 7, 9, 17, 7, 11, 185, 127, 169, 1951}},
-{262, 11, 589, {1, 1, 5, 13, 11, 11, 9, 49, 29, 125, 791}},
-{263, 11, 590, {1, 1, 1, 15, 31, 41, 13, 167, 273, 429, 57}},
-{264, 11, 601, {1, 3, 5, 3, 27, 7, 35, 209, 65, 265, 1393}},
-{265, 11, 607, {1, 3, 1, 13, 31, 19, 53, 143, 135, 9, 1021}},
-{266, 11, 611, {1, 1, 7, 13, 31, 5, 115, 153, 143, 957, 623}},
-{267, 11, 614, {1, 1, 5, 11, 25, 19, 29, 31, 297, 943, 443}},
-{268, 11, 617, {1, 3, 3, 5, 21, 11, 127, 81, 479, 25, 699}},
-{269, 11, 618, {1, 1, 3, 11, 25, 31, 97, 19, 195, 781, 705}},
-{270, 11, 625, {1, 1, 5, 5, 31, 11, 75, 207, 197, 885, 2037}},
-{271, 11, 628, {1, 1, 1, 11, 9, 23, 29, 231, 307, 17, 1497}},
-{272, 11, 635, {1, 1, 5, 11, 11, 43, 111, 233, 307, 523, 1259}},
-{273, 11, 641, {1, 1, 7, 5, 1, 21, 107, 229, 343, 933, 217}},
-{274, 11, 647, {1, 1, 1, 11, 3, 21, 125, 131, 405, 599, 1469}},
-{275, 11, 654, {1, 3, 5, 5, 9, 39, 33, 81, 389, 151, 811}},
-{276, 11, 659, {1, 1, 7, 7, 7, 1, 59, 223, 265, 529, 2021}},
-{277, 11, 662, {1, 3, 1, 3, 9, 23, 85, 181, 47, 265, 49}},
-{278, 11, 672, {1, 3, 5, 11, 19, 23, 9, 7, 157, 299, 1983}},
-{279, 11, 675, {1, 3, 1, 5, 15, 5, 21, 105, 29, 339, 1041}},
-{280, 11, 682, {1, 1, 1, 1, 5, 33, 65, 85, 111, 705, 479}},
-{281, 11, 684, {1, 1, 1, 7, 9, 35, 77, 87, 151, 321, 101}},
-{282, 11, 689, {1, 1, 5, 7, 17, 1, 51, 197, 175, 811, 1229}},
-{283, 11, 695, {1, 3, 3, 15, 23, 37, 85, 185, 239, 543, 731}},
-{284, 11, 696, {1, 3, 1, 7, 7, 55, 111, 109, 289, 439, 243}},
-{285, 11, 713, {1, 1, 7, 11, 17, 53, 35, 217, 259, 853, 1667}},
-{286, 11, 719, {1, 3, 1, 9, 1, 63, 87, 17, 73, 565, 1091}},
-{287, 11, 724, {1, 1, 3, 3, 11, 41, 1, 57, 295, 263, 1029}},
-{288, 11, 733, {1, 1, 5, 1, 27, 45, 109, 161, 411, 421, 1395}},
-{289, 11, 734, {1, 3, 5, 11, 25, 35, 47, 191, 339, 417, 1727}},
-{290, 11, 740, {1, 1, 5, 15, 21, 1, 93, 251, 351, 217, 1767}},
-{291, 11, 747, {1, 3, 3, 11, 3, 7, 75, 155, 313, 211, 491}},
-{292, 11, 749, {1, 3, 3, 5, 11, 9, 101, 161, 453, 913, 1067}},
-{293, 11, 752, {1, 1, 3, 1, 15, 45, 127, 141, 163, 727, 1597}},
-{294, 11, 755, {1, 3, 3, 7, 1, 33, 63, 73, 73, 341, 1691}},
-{295, 11, 762, {1, 3, 5, 13, 15, 39, 53, 235, 77, 99, 949}},
-{296, 11, 770, {1, 1, 5, 13, 31, 17, 97, 13, 215, 301, 1927}},
-{297, 11, 782, {1, 1, 7, 1, 1, 37, 91, 93, 441, 251, 1131}},
-{298, 11, 784, {1, 3, 7, 9, 25, 5, 105, 69, 81, 943, 1459}},
-{299, 11, 787, {1, 3, 7, 11, 31, 43, 13, 209, 27, 1017, 501}},
-{300, 11, 789, {1, 1, 7, 15, 1, 33, 31, 233, 161, 507, 387}},
-{301, 11, 793, {1, 3, 3, 5, 5, 53, 33, 177, 503, 627, 1927}},
-{302, 11, 796, {1, 1, 7, 11, 7, 61, 119, 31, 457, 229, 1875}},
-{303, 11, 803, {1, 1, 5, 15, 19, 5, 53, 201, 157, 885, 1057}},
-{304, 11, 805, {1, 3, 7, 9, 1, 35, 51, 113, 249, 425, 1009}},
-{305, 11, 810, {1, 3, 5, 7, 21, 53, 37, 155, 119, 345, 631}},
-{306, 11, 815, {1, 3, 5, 7, 15, 31, 109, 69, 503, 595, 1879}},
-{307, 11, 824, {1, 3, 3, 1, 25, 35, 65, 131, 403, 705, 503}},
-{308, 11, 829, {1, 3, 7, 7, 19, 33, 11, 153, 45, 633, 499}},
-{309, 11, 830, {1, 3, 3, 5, 11, 3, 29, 93, 487, 33, 703}},
-{310, 11, 832, {1, 1, 3, 15, 21, 53, 107, 179, 387, 927, 1757}},
-{311, 11, 841, {1, 1, 3, 7, 21, 45, 51, 147, 175, 317, 361}},
-{312, 11, 847, {1, 1, 1, 7, 7, 13, 15, 243, 269, 795, 1965}},
-{313, 11, 849, {1, 1, 3, 5, 19, 33, 57, 115, 443, 537, 627}},
-{314, 11, 861, {1, 3, 3, 9, 3, 39, 25, 61, 185, 717, 1049}},
-{315, 11, 871, {1, 3, 7, 3, 7, 37, 107, 153, 7, 269, 1581}},
-{316, 11, 878, {1, 1, 7, 3, 7, 41, 91, 41, 145, 489, 1245}},
-{317, 11, 889, {1, 1, 5, 9, 7, 7, 105, 81, 403, 407, 283}},
-{318, 11, 892, {1, 1, 7, 9, 27, 55, 29, 77, 193, 963, 949}},
-{319, 11, 901, {1, 1, 5, 3, 25, 51, 107, 63, 403, 917, 815}},
-{320, 11, 908, {1, 1, 7, 3, 7, 61, 19, 51, 457, 599, 535}},
-{321, 11, 920, {1, 3, 7, 1, 23, 51, 105, 153, 239, 215, 1847}},
-{322, 11, 923, {1, 1, 3, 5, 27, 23, 79, 49, 495, 45, 1935}},
-{323, 11, 942, {1, 1, 1, 11, 11, 47, 55, 133, 495, 999, 1461}},
-{324, 11, 949, {1, 1, 3, 15, 27, 51, 93, 17, 355, 763, 1675}},
-{325, 11, 950, {1, 3, 1, 3, 1, 3, 79, 119, 499, 17, 995}},
-{326, 11, 954, {1, 1, 1, 1, 15, 43, 45, 17, 167, 973, 799}},
-{327, 11, 961, {1, 1, 1, 3, 27, 49, 89, 29, 483, 913, 2023}},
-{328, 11, 968, {1, 1, 3, 3, 5, 11, 75, 7, 41, 851, 611}},
-{329, 11, 971, {1, 3, 1, 3, 7, 57, 39, 123, 257, 283, 507}},
-{330, 11, 973, {1, 3, 3, 11, 27, 23, 113, 229, 187, 299, 133}},
-{331, 11, 979, {1, 1, 3, 13, 9, 63, 101, 77, 451, 169, 337}},
-{332, 11, 982, {1, 3, 7, 3, 3, 59, 45, 195, 229, 415, 409}},
-{333, 11, 986, {1, 3, 5, 3, 11, 19, 71, 93, 43, 857, 369}},
-{334, 11, 998, {1, 3, 7, 9, 19, 33, 115, 19, 241, 703, 247}},
-{335, 11, 1001, {1, 3, 5, 11, 5, 35, 21, 155, 463, 1005, 1073}},
-{336, 11, 1010, {1, 3, 7, 3, 25, 15, 109, 83, 93, 69, 1189}},
-{337, 11, 1012, {1, 3, 5, 7, 5, 21, 93, 133, 135, 167, 903}},
-{338, 12, 41, {1, 1, 7, 7, 3, 59, 121, 161, 285, 815, 1769, 3705}},
-{339, 12, 52, {1, 3, 1, 1, 3, 47, 103, 171, 381, 609, 185, 373}},
-{340, 12, 61, {1, 3, 3, 15, 23, 33, 107, 131, 441, 445, 689, 2059}},
-{341, 12, 62, {1, 3, 3, 11, 7, 53, 101, 167, 435, 803, 1255, 3781}},
-{342, 12, 76, {1, 1, 5, 11, 15, 59, 41, 19, 135, 835, 1263, 505}},
-{343, 12, 104, {1, 1, 7, 11, 21, 49, 23, 219, 127, 961, 1065, 385}},
-{344, 12, 117, {1, 3, 5, 15, 7, 47, 117, 217, 45, 731, 1639, 733}},
-{345, 12, 131, {1, 1, 7, 11, 27, 57, 91, 87, 81, 35, 1269, 1007}},
-{346, 12, 143, {1, 1, 3, 11, 15, 37, 53, 219, 193, 937, 1899, 3733}},
-{347, 12, 145, {1, 3, 5, 3, 13, 11, 27, 19, 199, 393, 965, 2195}},
-{348, 12, 157, {1, 3, 1, 3, 5, 1, 37, 173, 413, 1023, 553, 409}},
-{349, 12, 167, {1, 3, 1, 7, 15, 29, 123, 95, 255, 373, 1799, 3841}},
-{350, 12, 171, {1, 3, 5, 13, 21, 57, 51, 17, 511, 195, 1157, 1831}},
-{351, 12, 176, {1, 1, 1, 15, 29, 19, 7, 73, 295, 519, 587, 3523}},
-{352, 12, 181, {1, 1, 5, 13, 13, 35, 115, 191, 123, 535, 717, 1661}},
-{353, 12, 194, {1, 3, 3, 5, 23, 21, 47, 251, 379, 921, 1119, 297}},
-{354, 12, 217, {1, 3, 3, 9, 29, 53, 121, 201, 135, 193, 523, 2943}},
-{355, 12, 236, {1, 1, 1, 7, 29, 45, 125, 9, 99, 867, 425, 601}},
-{356, 12, 239, {1, 3, 1, 9, 13, 15, 67, 181, 109, 293, 1305, 3079}},
-{357, 12, 262, {1, 3, 3, 9, 5, 35, 15, 209, 305, 87, 767, 2795}},
-{358, 12, 283, {1, 3, 3, 11, 27, 57, 113, 123, 179, 643, 149, 523}},
-{359, 12, 286, {1, 1, 3, 15, 11, 17, 67, 223, 63, 657, 335, 3309}},
-{360, 12, 307, {1, 1, 1, 9, 25, 29, 109, 159, 39, 513, 571, 1761}},
-{361, 12, 313, {1, 1, 3, 1, 5, 63, 75, 19, 455, 601, 123, 691}},
-{362, 12, 319, {1, 1, 1, 3, 21, 5, 45, 169, 377, 513, 1951, 2565}},
-{363, 12, 348, {1, 1, 3, 11, 3, 33, 119, 69, 253, 907, 805, 1449}},
-{364, 12, 352, {1, 1, 5, 13, 31, 15, 17, 7, 499, 61, 687, 1867}},
-{365, 12, 357, {1, 3, 7, 11, 17, 33, 73, 77, 299, 243, 641, 2345}},
-{366, 12, 391, {1, 1, 7, 11, 9, 35, 31, 235, 359, 647, 379, 1161}},
-{367, 12, 398, {1, 3, 3, 15, 31, 25, 5, 67, 33, 45, 437, 4067}},
-{368, 12, 400, {1, 1, 3, 11, 7, 17, 37, 87, 333, 253, 1517, 2921}},
-{369, 12, 412, {1, 1, 7, 15, 7, 15, 107, 189, 153, 769, 1521, 3427}},
-{370, 12, 415, {1, 3, 5, 13, 5, 61, 113, 37, 293, 393, 113, 43}},
-{371, 12, 422, {1, 1, 1, 15, 29, 43, 107, 31, 167, 147, 301, 1021}},
-{372, 12, 440, {1, 1, 1, 13, 3, 1, 35, 93, 195, 181, 2027, 1491}},
-{373, 12, 460, {1, 3, 3, 3, 13, 33, 77, 199, 153, 221, 1699, 3671}},
-{374, 12, 465, {1, 3, 5, 13, 7, 49, 123, 155, 495, 681, 819, 809}},
-{375, 12, 468, {1, 3, 5, 15, 27, 61, 117, 189, 183, 887, 617, 4053}},
-{376, 12, 515, {1, 1, 1, 7, 31, 59, 125, 235, 389, 369, 447, 1039}},
-{377, 12, 536, {1, 3, 5, 1, 5, 39, 115, 89, 249, 377, 431, 3747}},
-{378, 12, 539, {1, 1, 1, 5, 7, 47, 59, 157, 77, 445, 699, 3439}},
-{379, 12, 551, {1, 1, 3, 5, 11, 21, 19, 75, 11, 599, 1575, 735}},
-{380, 12, 558, {1, 3, 5, 3, 19, 13, 41, 69, 199, 143, 1761, 3215}},
-{381, 12, 563, {1, 3, 5, 7, 19, 43, 25, 41, 41, 11, 1647, 2783}},
-{382, 12, 570, {1, 3, 1, 9, 19, 45, 111, 97, 405, 399, 457, 3219}},
-{383, 12, 595, {1, 1, 3, 1, 23, 15, 65, 121, 59, 985, 829, 2259}},
-{384, 12, 598, {1, 1, 3, 7, 17, 13, 107, 229, 75, 551, 1299, 2363}},
-{385, 12, 617, {1, 1, 5, 5, 21, 57, 23, 199, 509, 139, 2007, 3875}},
-{386, 12, 647, {1, 3, 1, 11, 19, 53, 15, 229, 215, 741, 695, 823}},
-{387, 12, 654, {1, 3, 7, 1, 29, 3, 17, 163, 417, 559, 549, 319}},
-{388, 12, 678, {1, 3, 1, 13, 17, 9, 47, 133, 365, 7, 1937, 1071}},
-{389, 12, 713, {1, 3, 5, 7, 19, 37, 55, 163, 301, 249, 689, 2327}},
-{390, 12, 738, {1, 3, 5, 13, 11, 23, 61, 205, 257, 377, 615, 1457}},
-{391, 12, 747, {1, 3, 5, 1, 23, 37, 13, 75, 331, 495, 579, 3367}},
-{392, 12, 750, {1, 1, 1, 9, 1, 23, 49, 129, 475, 543, 883, 2531}},
-{393, 12, 757, {1, 3, 1, 5, 23, 59, 51, 35, 343, 695, 219, 369}},
-{394, 12, 772, {1, 3, 3, 1, 27, 17, 63, 97, 71, 507, 1929, 613}},
-{395, 12, 803, {1, 1, 5, 1, 21, 31, 11, 109, 247, 409, 1817, 2173}},
-{396, 12, 810, {1, 1, 3, 15, 23, 9, 7, 209, 301, 23, 147, 1691}},
-{397, 12, 812, {1, 1, 7, 5, 5, 19, 37, 229, 249, 277, 1115, 2309}},
-{398, 12, 850, {1, 1, 1, 5, 5, 63, 5, 249, 285, 431, 343, 2467}},
-{399, 12, 862, {1, 1, 1, 11, 7, 45, 35, 75, 505, 537, 29, 2919}},
-{400, 12, 906, {1, 3, 5, 15, 11, 39, 15, 63, 263, 9, 199, 445}},
-{401, 12, 908, {1, 3, 3, 3, 27, 63, 53, 171, 227, 63, 1049, 827}},
-{402, 12, 929, {1, 1, 3, 13, 7, 11, 115, 183, 179, 937, 1785, 381}},
-{403, 12, 930, {1, 3, 1, 11, 13, 15, 107, 81, 53, 295, 1785, 3757}},
-{404, 12, 954, {1, 3, 3, 13, 11, 5, 109, 243, 3, 505, 323, 1373}},
-{405, 12, 964, {1, 3, 3, 11, 21, 51, 17, 177, 381, 937, 1263, 3889}},
-{406, 12, 982, {1, 3, 5, 9, 27, 25, 85, 193, 143, 573, 1189, 2995}},
-{407, 12, 985, {1, 3, 5, 11, 13, 9, 81, 21, 159, 953, 91, 1751}},
-{408, 12, 991, {1, 1, 3, 3, 27, 61, 11, 253, 391, 333, 1105, 635}},
-{409, 12, 992, {1, 3, 3, 15, 9, 57, 95, 81, 419, 735, 251, 1141}},
-{410, 12, 1067, {1, 1, 5, 9, 31, 39, 59, 13, 319, 807, 1241, 2433}},
-{411, 12, 1070, {1, 3, 3, 5, 27, 13, 107, 141, 423, 937, 2027, 3233}},
-{412, 12, 1096, {1, 3, 3, 9, 9, 25, 125, 23, 443, 835, 1245, 847}},
-{413, 12, 1099, {1, 1, 7, 15, 17, 17, 83, 107, 411, 285, 847, 1571}},
-{414, 12, 1116, {1, 1, 3, 13, 29, 61, 37, 81, 349, 727, 1453, 1957}},
-{415, 12, 1143, {1, 3, 7, 11, 31, 13, 59, 77, 273, 591, 1265, 1533}},
-{416, 12, 1165, {1, 1, 7, 7, 13, 17, 25, 25, 187, 329, 347, 1473}},
-{417, 12, 1178, {1, 3, 7, 7, 5, 51, 37, 99, 221, 153, 503, 2583}},
-{418, 12, 1184, {1, 3, 1, 13, 19, 27, 11, 69, 181, 479, 1183, 3229}},
-{419, 12, 1202, {1, 3, 3, 13, 23, 21, 103, 147, 323, 909, 947, 315}},
-{420, 12, 1213, {1, 3, 1, 3, 23, 1, 31, 59, 93, 513, 45, 2271}},
-{421, 12, 1221, {1, 3, 5, 1, 7, 43, 109, 59, 231, 41, 1515, 2385}},
-{422, 12, 1240, {1, 3, 1, 5, 31, 57, 49, 223, 283, 1013, 11, 701}},
-{423, 12, 1246, {1, 1, 5, 1, 19, 53, 55, 31, 31, 299, 495, 693}},
-{424, 12, 1252, {1, 3, 3, 9, 5, 33, 77, 253, 427, 791, 731, 1019}},
-{425, 12, 1255, {1, 3, 7, 11, 1, 9, 119, 203, 53, 877, 1707, 3499}},
-{426, 12, 1267, {1, 1, 3, 7, 13, 39, 55, 159, 423, 113, 1653, 3455}},
-{427, 12, 1293, {1, 1, 3, 5, 21, 47, 51, 59, 55, 411, 931, 251}},
-{428, 12, 1301, {1, 3, 7, 3, 31, 25, 81, 115, 405, 239, 741, 455}},
-{429, 12, 1305, {1, 1, 5, 1, 31, 3, 101, 83, 479, 491, 1779, 2225}},
-{430, 12, 1332, {1, 3, 3, 3, 9, 37, 107, 161, 203, 503, 767, 3435}},
-{431, 12, 1349, {1, 3, 7, 9, 1, 27, 61, 119, 233, 39, 1375, 4089}},
-{432, 12, 1384, {1, 1, 5, 9, 1, 31, 45, 51, 369, 587, 383, 2813}},
-{433, 12, 1392, {1, 3, 7, 5, 31, 7, 49, 119, 487, 591, 1627, 53}},
-{434, 12, 1402, {1, 1, 7, 1, 9, 47, 1, 223, 369, 711, 1603, 1917}},
-{435, 12, 1413, {1, 3, 5, 3, 21, 37, 111, 17, 483, 739, 1193, 2775}},
-{436, 12, 1417, {1, 3, 3, 7, 17, 11, 51, 117, 455, 191, 1493, 3821}},
-{437, 12, 1423, {1, 1, 5, 9, 23, 39, 99, 181, 343, 485, 99, 1931}},
-{438, 12, 1451, {1, 3, 1, 7, 29, 49, 31, 71, 489, 527, 1763, 2909}},
-{439, 12, 1480, {1, 1, 5, 11, 5, 5, 73, 189, 321, 57, 1191, 3685}},
-{440, 12, 1491, {1, 1, 5, 15, 13, 45, 125, 207, 371, 415, 315, 983}},
-{441, 12, 1503, {1, 3, 3, 5, 25, 59, 33, 31, 239, 919, 1859, 2709}},
-{442, 12, 1504, {1, 3, 5, 13, 27, 61, 23, 115, 61, 413, 1275, 3559}},
-{443, 12, 1513, {1, 3, 7, 15, 5, 59, 101, 81, 47, 967, 809, 3189}},
-{444, 12, 1538, {1, 1, 5, 11, 31, 15, 39, 25, 173, 505, 809, 2677}},
-{445, 12, 1544, {1, 1, 5, 9, 19, 13, 95, 89, 511, 127, 1395, 2935}},
-{446, 12, 1547, {1, 1, 5, 5, 31, 45, 9, 57, 91, 303, 1295, 3215}},
-{447, 12, 1555, {1, 3, 3, 3, 19, 15, 113, 187, 217, 489, 1285, 1803}},
-{448, 12, 1574, {1, 1, 3, 1, 13, 29, 57, 139, 255, 197, 537, 2183}},
-{449, 12, 1603, {1, 3, 1, 15, 11, 7, 53, 255, 467, 9, 757, 3167}},
-{450, 12, 1615, {1, 3, 3, 15, 21, 13, 9, 189, 359, 323, 49, 333}},
-{451, 12, 1618, {1, 3, 7, 11, 7, 37, 21, 119, 401, 157, 1659, 1069}},
-{452, 12, 1629, {1, 1, 5, 7, 17, 33, 115, 229, 149, 151, 2027, 279}},
-{453, 12, 1634, {1, 1, 5, 15, 5, 49, 77, 155, 383, 385, 1985, 945}},
-{454, 12, 1636, {1, 3, 7, 3, 7, 55, 85, 41, 357, 527, 1715, 1619}},
-{455, 12, 1639, {1, 1, 3, 1, 21, 45, 115, 21, 199, 967, 1581, 3807}},
-{456, 12, 1657, {1, 1, 3, 7, 21, 39, 117, 191, 169, 73, 413, 3417}},
-{457, 12, 1667, {1, 1, 1, 13, 1, 31, 57, 195, 231, 321, 367, 1027}},
-{458, 12, 1681, {1, 3, 7, 3, 11, 29, 47, 161, 71, 419, 1721, 437}},
-{459, 12, 1697, {1, 1, 7, 3, 11, 9, 43, 65, 157, 1, 1851, 823}},
-{460, 12, 1704, {1, 1, 1, 5, 21, 15, 31, 101, 293, 299, 127, 1321}},
-{461, 12, 1709, {1, 1, 7, 1, 27, 1, 11, 229, 241, 705, 43, 1475}},
-{462, 12, 1722, {1, 3, 7, 1, 5, 15, 73, 183, 193, 55, 1345, 49}},
-{463, 12, 1730, {1, 3, 3, 3, 19, 3, 55, 21, 169, 663, 1675, 137}},
-{464, 12, 1732, {1, 1, 1, 13, 7, 21, 69, 67, 373, 965, 1273, 2279}},
-{465, 12, 1802, {1, 1, 7, 7, 21, 23, 17, 43, 341, 845, 465, 3355}},
-{466, 12, 1804, {1, 3, 5, 5, 25, 5, 81, 101, 233, 139, 359, 2057}},
-{467, 12, 1815, {1, 1, 3, 11, 15, 39, 55, 3, 471, 765, 1143, 3941}},
-{468, 12, 1826, {1, 1, 7, 15, 9, 57, 81, 79, 215, 433, 333, 3855}},
-{469, 12, 1832, {1, 1, 5, 5, 19, 45, 83, 31, 209, 363, 701, 1303}},
-{470, 12, 1843, {1, 3, 7, 5, 1, 13, 55, 163, 435, 807, 287, 2031}},
-{471, 12, 1849, {1, 3, 3, 7, 3, 3, 17, 197, 39, 169, 489, 1769}},
-{472, 12, 1863, {1, 1, 3, 5, 29, 43, 87, 161, 289, 339, 1233, 2353}},
-{473, 12, 1905, {1, 3, 3, 9, 21, 9, 77, 1, 453, 167, 1643, 2227}},
-{474, 12, 1928, {1, 1, 7, 1, 15, 7, 67, 33, 193, 241, 1031, 2339}},
-{475, 12, 1933, {1, 3, 1, 11, 1, 63, 45, 65, 265, 661, 849, 1979}},
-{476, 12, 1939, {1, 3, 1, 13, 19, 49, 3, 11, 159, 213, 659, 2839}},
-{477, 12, 1976, {1, 3, 5, 11, 9, 29, 27, 227, 253, 449, 1403, 3427}},
-{478, 12, 1996, {1, 1, 3, 1, 7, 3, 77, 143, 277, 779, 1499, 475}},
-{479, 12, 2013, {1, 1, 1, 5, 11, 23, 87, 131, 393, 849, 193, 3189}},
-{480, 12, 2014, {1, 3, 5, 11, 3, 3, 89, 9, 449, 243, 1501, 1739}},
-{481, 12, 2020, {1, 3, 1, 9, 29, 29, 113, 15, 65, 611, 135, 3687}},
-{482, 13, 13, {1, 1, 1, 9, 21, 19, 39, 151, 395, 501, 1339, 959, 2725}},
-{483, 13, 19, {1, 3, 7, 1, 7, 35, 45, 33, 119, 225, 1631, 1695, 1459}},
-{484, 13, 26, {1, 1, 1, 3, 25, 55, 37, 79, 167, 907, 1075, 271, 4059}},
-{485, 13, 41, {1, 3, 5, 13, 5, 13, 53, 165, 437, 67, 1705, 3177, 8095}},
-{486, 13, 50, {1, 3, 3, 13, 27, 57, 95, 55, 443, 245, 1945, 1725, 1929}},
-{487, 13, 55, {1, 3, 1, 9, 5, 33, 109, 35, 99, 827, 341, 2401, 2411}},
-{488, 13, 69, {1, 1, 5, 9, 7, 33, 43, 39, 87, 799, 635, 3481, 7159}},
-{489, 13, 70, {1, 3, 1, 1, 31, 15, 45, 27, 337, 113, 987, 2065, 2529}},
-{490, 13, 79, {1, 1, 5, 9, 5, 15, 105, 123, 479, 289, 1609, 2177, 4629}},
-{491, 13, 82, {1, 3, 5, 11, 31, 47, 97, 87, 385, 195, 1041, 651, 3271}},
-{492, 13, 87, {1, 1, 3, 7, 17, 3, 101, 55, 87, 629, 1687, 1387, 2745}},
-{493, 13, 93, {1, 3, 5, 5, 7, 21, 9, 237, 313, 549, 1107, 117, 6183}},
-{494, 13, 94, {1, 1, 3, 9, 9, 5, 55, 201, 487, 851, 1103, 2993, 4055}},
-{495, 13, 97, {1, 1, 5, 9, 31, 19, 59, 7, 363, 381, 1167, 2057, 5715}},
-{496, 13, 100, {1, 3, 3, 15, 23, 63, 19, 227, 387, 827, 487, 1049, 7471}},
-{497, 13, 112, {1, 3, 1, 5, 23, 25, 61, 245, 363, 863, 963, 3583, 6475}},
-{498, 13, 121, {1, 1, 5, 1, 5, 27, 81, 85, 275, 49, 235, 3291, 1195}},
-{499, 13, 134, {1, 1, 5, 7, 23, 53, 85, 107, 511, 779, 1265, 1093, 7859}},
-{500, 13, 138, {1, 3, 3, 1, 9, 21, 75, 219, 59, 485, 1739, 3845, 1109}},
-{501, 13, 148, {1, 3, 5, 1, 13, 41, 19, 143, 293, 391, 2023, 1791, 4399}},
-{502, 13, 151, {1, 3, 7, 15, 21, 13, 21, 195, 215, 413, 523, 2099, 2341}},
-{503, 13, 157, {1, 1, 1, 3, 29, 51, 47, 57, 135, 575, 943, 1673, 541}},
-{504, 13, 161, {1, 3, 5, 1, 9, 13, 113, 175, 447, 115, 657, 4077, 5973}},
-{505, 13, 179, {1, 1, 1, 11, 17, 41, 37, 95, 297, 579, 911, 2207, 2387}},
-{506, 13, 181, {1, 3, 5, 3, 23, 11, 23, 231, 93, 667, 711, 1563, 7961}},
-{507, 13, 188, {1, 1, 7, 3, 17, 59, 13, 181, 141, 991, 1817, 457, 1711}},
-{508, 13, 196, {1, 3, 3, 5, 31, 59, 81, 205, 245, 537, 1049, 997, 1815}},
-{509, 13, 203, {1, 3, 7, 5, 17, 13, 9, 79, 17, 185, 5, 2211, 6263}},
-{510, 13, 206, {1, 3, 7, 13, 7, 53, 61, 145, 13, 285, 1203, 947, 2933}},
-{511, 13, 223, {1, 1, 7, 3, 31, 19, 69, 217, 47, 441, 1893, 673, 4451}},
-{512, 13, 224, {1, 1, 1, 1, 25, 9, 23, 225, 385, 629, 603, 3747, 4241}},
-{513, 13, 227, {1, 3, 1, 9, 5, 37, 31, 237, 431, 79, 1521, 459, 2523}},
-{514, 13, 230, {1, 3, 7, 3, 9, 43, 105, 179, 5, 225, 799, 1777, 4893}},
-{515, 13, 239, {1, 1, 3, 1, 29, 45, 29, 159, 267, 247, 455, 847, 3909}},
-{516, 13, 241, {1, 1, 3, 7, 25, 21, 121, 57, 467, 275, 719, 1521, 7319}},
-{517, 13, 248, {1, 3, 1, 3, 11, 35, 119, 123, 81, 979, 1187, 3623, 4293}},
-{518, 13, 253, {1, 1, 1, 7, 15, 25, 121, 235, 25, 487, 873, 1787, 1977}},
-{519, 13, 268, {1, 1, 1, 11, 3, 7, 17, 135, 345, 353, 383, 4011, 2573}},
-{520, 13, 274, {1, 3, 7, 15, 27, 13, 97, 123, 65, 675, 951, 1285, 6559}},
-{521, 13, 283, {1, 3, 7, 3, 7, 1, 71, 19, 325, 765, 337, 1197, 2697}},
-{522, 13, 286, {1, 3, 5, 1, 31, 37, 11, 71, 169, 283, 83, 3801, 7083}},
-{523, 13, 289, {1, 1, 3, 15, 17, 29, 83, 65, 275, 679, 1749, 4007, 7749}},
-{524, 13, 301, {1, 1, 3, 1, 21, 11, 41, 95, 237, 361, 1819, 2783, 2383}},
-{525, 13, 302, {1, 3, 7, 11, 29, 57, 111, 187, 465, 145, 605, 1987, 8109}},
-{526, 13, 316, {1, 1, 3, 3, 19, 15, 55, 83, 357, 1001, 643, 1517, 6529}},
-{527, 13, 319, {1, 3, 1, 5, 29, 35, 73, 23, 77, 619, 1523, 1725, 8145}},
-{528, 13, 324, {1, 1, 5, 5, 19, 23, 7, 197, 449, 337, 717, 2921, 315}},
-{529, 13, 331, {1, 3, 5, 9, 7, 63, 117, 97, 97, 813, 1925, 2817, 1579}},
-{530, 13, 333, {1, 1, 1, 11, 31, 7, 25, 235, 231, 133, 1007, 1371, 1553}},
-{531, 13, 345, {1, 1, 7, 5, 19, 7, 47, 171, 267, 243, 1331, 567, 6033}},
-{532, 13, 351, {1, 1, 5, 1, 7, 49, 55, 89, 109, 735, 1455, 3193, 6239}},
-{533, 13, 358, {1, 1, 1, 7, 1, 61, 9, 103, 3, 929, 1481, 2927, 2957}},
-{534, 13, 375, {1, 1, 5, 13, 17, 21, 75, 49, 255, 1019, 1161, 2133, 1177}},
-{535, 13, 379, {1, 3, 1, 3, 13, 15, 41, 247, 211, 409, 1163, 523, 2635}},
-{536, 13, 381, {1, 3, 7, 7, 21, 59, 91, 149, 479, 391, 681, 2311, 6249}},
-{537, 13, 386, {1, 1, 5, 11, 27, 53, 21, 211, 197, 815, 719, 1605, 255}},
-{538, 13, 403, {1, 1, 3, 3, 9, 33, 59, 3, 323, 1, 101, 1135, 8105}},
-{539, 13, 405, {1, 3, 3, 1, 29, 5, 17, 141, 51, 991, 841, 327, 3859}},
-{540, 13, 419, {1, 3, 1, 5, 11, 19, 23, 89, 175, 173, 165, 2881, 1881}},
-{541, 13, 426, {1, 1, 1, 15, 13, 51, 87, 39, 495, 611, 1341, 1531, 7029}},
-{542, 13, 428, {1, 1, 3, 11, 13, 55, 75, 185, 57, 61, 1917, 2051, 5965}},
-{543, 13, 439, {1, 1, 5, 5, 7, 53, 11, 217, 213, 933, 921, 3607, 5175}},
-{544, 13, 440, {1, 3, 3, 5, 17, 53, 103, 251, 369, 781, 1319, 3717, 4439}},
-{545, 13, 446, {1, 3, 5, 13, 1, 39, 25, 235, 321, 773, 251, 3111, 6397}},
-{546, 13, 451, {1, 1, 7, 3, 31, 5, 25, 29, 325, 385, 1313, 127, 4705}},
-{547, 13, 454, {1, 1, 5, 15, 15, 27, 15, 85, 239, 243, 1633, 3473, 2621}},
-{548, 13, 458, {1, 3, 3, 3, 9, 19, 113, 13, 137, 165, 25, 2957, 7549}},
-{549, 13, 465, {1, 3, 1, 3, 11, 21, 3, 97, 417, 183, 1205, 1437, 247}},
-{550, 13, 468, {1, 1, 7, 3, 17, 21, 125, 55, 67, 387, 385, 2323, 887}},
-{551, 13, 472, {1, 3, 5, 5, 29, 11, 103, 223, 233, 641, 133, 415, 1297}},
-{552, 13, 475, {1, 3, 3, 11, 1, 9, 5, 189, 235, 1007, 1363, 3985, 889}},
-{553, 13, 477, {1, 3, 7, 9, 23, 19, 19, 183, 269, 403, 1643, 3559, 5189}},
-{554, 13, 496, {1, 3, 7, 3, 29, 45, 17, 69, 475, 149, 1291, 2689, 7625}},
-{555, 13, 502, {1, 3, 7, 3, 27, 37, 41, 73, 253, 1001, 431, 1111, 7887}},
-{556, 13, 508, {1, 1, 7, 5, 3, 7, 87, 143, 289, 495, 631, 3011, 6151}},
-{557, 13, 517, {1, 1, 1, 13, 5, 45, 17, 167, 23, 975, 801, 1975, 6833}},
-{558, 13, 521, {1, 3, 1, 11, 7, 21, 39, 23, 213, 429, 1301, 2059, 197}},
-{559, 13, 527, {1, 3, 3, 15, 3, 57, 121, 133, 29, 711, 1961, 2497, 189}},
-{560, 13, 530, {1, 1, 3, 5, 11, 55, 115, 137, 233, 673, 985, 2849, 5911}},
-{561, 13, 532, {1, 1, 7, 15, 29, 45, 1, 241, 329, 323, 925, 2821, 3331}},
-{562, 13, 542, {1, 1, 5, 7, 13, 31, 81, 105, 199, 145, 195, 1365, 5119}},
-{563, 13, 552, {1, 3, 7, 11, 3, 55, 11, 31, 117, 343, 1265, 1837, 2451}},
-{564, 13, 555, {1, 1, 3, 7, 29, 57, 61, 179, 429, 591, 177, 1945, 2159}},
-{565, 13, 560, {1, 3, 5, 11, 23, 49, 101, 137, 339, 323, 1035, 1749, 7737}},
-{566, 13, 566, {1, 3, 1, 13, 21, 35, 55, 79, 19, 269, 1055, 2651, 7083}},
-{567, 13, 575, {1, 3, 3, 11, 9, 9, 95, 167, 437, 361, 1185, 4083, 603}},
-{568, 13, 577, {1, 1, 1, 7, 31, 61, 77, 65, 489, 657, 691, 2423, 4147}},
-{569, 13, 589, {1, 3, 5, 7, 21, 37, 87, 191, 311, 453, 2013, 829, 2619}},
-{570, 13, 590, {1, 1, 5, 9, 17, 47, 35, 101, 5, 813, 1157, 1279, 7365}},
-{571, 13, 602, {1, 1, 5, 3, 11, 35, 113, 199, 369, 721, 901, 1471, 7801}},
-{572, 13, 607, {1, 3, 1, 5, 9, 61, 83, 157, 391, 739, 1957, 2123, 4341}},
-{573, 13, 608, {1, 3, 5, 11, 19, 19, 111, 225, 383, 219, 997, 717, 7505}},
-{574, 13, 611, {1, 3, 1, 11, 13, 63, 35, 127, 209, 831, 501, 3017, 3507}},
-{575, 13, 613, {1, 3, 7, 9, 29, 7, 11, 163, 81, 563, 1445, 3215, 6377}},
-{576, 13, 625, {1, 3, 7, 11, 25, 3, 39, 195, 491, 45, 839, 4021, 4899}},
-{577, 13, 644, {1, 3, 7, 15, 13, 5, 67, 143, 117, 505, 1281, 3679, 5695}},
-{578, 13, 651, {1, 3, 7, 9, 9, 19, 21, 221, 147, 763, 683, 2211, 589}},
-{579, 13, 654, {1, 1, 3, 5, 21, 47, 53, 109, 299, 807, 1153, 1209, 7961}},
-{580, 13, 656, {1, 3, 7, 11, 9, 31, 45, 43, 505, 647, 1127, 2681, 4917}},
-{581, 13, 662, {1, 1, 5, 15, 31, 41, 63, 113, 399, 727, 673, 2587, 5259}},
-{582, 13, 668, {1, 1, 1, 13, 17, 53, 35, 99, 57, 243, 1447, 1919, 2831}},
-{583, 13, 681, {1, 3, 7, 11, 23, 51, 13, 9, 49, 449, 997, 3073, 4407}},
-{584, 13, 682, {1, 3, 5, 7, 23, 33, 89, 41, 415, 53, 697, 1113, 1489}},
-{585, 13, 689, {1, 1, 3, 7, 1, 13, 29, 13, 255, 749, 77, 3463, 1761}},
-{586, 13, 696, {1, 3, 3, 7, 13, 15, 93, 191, 309, 869, 739, 1041, 3053}},
-{587, 13, 699, {1, 3, 5, 13, 5, 19, 109, 211, 347, 839, 893, 2947, 7735}},
-{588, 13, 707, {1, 3, 1, 13, 27, 3, 119, 157, 485, 99, 1703, 3895, 573}},
-{589, 13, 709, {1, 3, 7, 11, 1, 23, 123, 105, 31, 359, 275, 1775, 3685}},
-{590, 13, 714, {1, 3, 3, 5, 27, 11, 125, 3, 413, 199, 2043, 2895, 2945}},
-{591, 13, 716, {1, 3, 3, 3, 15, 49, 121, 159, 233, 543, 193, 4007, 321}},
-{592, 13, 719, {1, 1, 3, 5, 9, 47, 87, 1, 51, 1011, 1595, 2239, 6467}},
-{593, 13, 727, {1, 3, 7, 9, 1, 33, 87, 137, 469, 749, 1413, 805, 6817}},
-{594, 13, 734, {1, 3, 1, 13, 19, 45, 95, 227, 29, 677, 1275, 3395, 4451}},
-{595, 13, 738, {1, 1, 7, 5, 7, 63, 33, 71, 443, 561, 1311, 3069, 6943}},
-{596, 13, 743, {1, 1, 1, 13, 9, 37, 23, 69, 13, 415, 1479, 1197, 861}},
-{597, 13, 747, {1, 3, 3, 13, 27, 21, 13, 233, 105, 777, 345, 2443, 1105}},
-{598, 13, 757, {1, 1, 7, 11, 23, 13, 21, 147, 221, 549, 73, 2729, 6279}},
-{599, 13, 769, {1, 1, 7, 7, 25, 27, 15, 45, 227, 39, 75, 1191, 3563}},
-{600, 13, 770, {1, 1, 5, 7, 13, 49, 99, 167, 227, 13, 353, 1047, 8075}},
-{601, 13, 776, {1, 1, 3, 13, 31, 9, 27, 7, 461, 737, 1559, 3243, 53}},
-{602, 13, 790, {1, 3, 1, 1, 21, 41, 97, 165, 171, 821, 587, 2137, 2293}},
-{603, 13, 799, {1, 3, 1, 11, 17, 41, 29, 187, 87, 599, 1467, 1395, 5931}},
-{604, 13, 805, {1, 1, 1, 9, 9, 49, 89, 205, 409, 453, 61, 1923, 1257}},
-{605, 13, 809, {1, 3, 7, 3, 9, 43, 89, 143, 431, 83, 1243, 1795, 3599}},
-{606, 13, 812, {1, 3, 5, 13, 3, 25, 59, 219, 43, 223, 797, 2651, 6015}},
-{607, 13, 820, {1, 1, 5, 15, 7, 55, 65, 207, 213, 311, 1287, 1269, 6467}},
-{608, 13, 827, {1, 3, 7, 11, 21, 57, 31, 183, 351, 857, 911, 1683, 7155}},
-{609, 13, 829, {1, 3, 5, 11, 27, 1, 21, 47, 387, 383, 1593, 115, 3805}},
-{610, 13, 835, {1, 3, 1, 1, 13, 23, 87, 173, 181, 619, 1653, 3931, 6073}},
-{611, 13, 841, {1, 1, 7, 5, 17, 43, 37, 61, 307, 621, 1785, 55, 115}},
-{612, 13, 844, {1, 3, 7, 15, 25, 61, 123, 15, 237, 671, 1473, 467, 1907}},
-{613, 13, 856, {1, 1, 7, 5, 29, 57, 75, 237, 85, 699, 159, 3577, 4771}},
-{614, 13, 859, {1, 1, 1, 11, 25, 19, 51, 1, 147, 31, 895, 2617, 625}},
-{615, 13, 862, {1, 3, 7, 5, 29, 15, 115, 175, 395, 391, 1141, 1827, 1181}},
-{616, 13, 865, {1, 3, 5, 7, 17, 7, 11, 193, 89, 243, 561, 3787, 4551}},
-{617, 13, 885, {1, 3, 1, 11, 7, 57, 7, 125, 403, 947, 1261, 409, 8083}},
-{618, 13, 890, {1, 1, 5, 13, 21, 63, 115, 233, 231, 921, 1747, 3635, 2519}},
-{619, 13, 905, {1, 1, 5, 11, 3, 27, 15, 91, 505, 591, 1451, 3881, 2997}},
-{620, 13, 916, {1, 1, 3, 11, 21, 9, 109, 153, 317, 533, 593, 3967, 2797}},
-{621, 13, 925, {1, 3, 3, 13, 9, 57, 121, 245, 219, 867, 967, 791, 7095}},
-{622, 13, 935, {1, 1, 1, 9, 29, 21, 99, 35, 375, 959, 329, 4087, 7171}},
-{623, 13, 939, {1, 1, 1, 9, 11, 17, 17, 97, 89, 135, 631, 3809, 3253}},
-{624, 13, 942, {1, 1, 1, 15, 21, 51, 91, 249, 459, 801, 757, 2353, 2033}},
-{625, 13, 949, {1, 3, 5, 9, 23, 29, 77, 53, 399, 767, 1817, 2171, 1629}},
-{626, 13, 953, {1, 1, 3, 5, 29, 5, 43, 121, 17, 859, 1479, 3785, 6641}},
-{627, 13, 956, {1, 1, 3, 7, 7, 61, 45, 109, 371, 833, 91, 153, 4553}},
-{628, 13, 961, {1, 1, 3, 11, 7, 55, 81, 123, 389, 139, 1933, 891, 1789}},
-{629, 13, 968, {1, 3, 7, 15, 25, 17, 93, 165, 503, 717, 1553, 1475, 1627}},
-{630, 13, 976, {1, 1, 1, 13, 13, 63, 13, 225, 357, 571, 33, 4073, 3795}},
-{631, 13, 988, {1, 1, 3, 11, 1, 31, 107, 145, 407, 961, 501, 2987, 103}},
-{632, 13, 995, {1, 1, 7, 1, 23, 63, 49, 193, 173, 281, 25, 2465, 5927}},
-{633, 13, 997, {1, 1, 7, 1, 1, 1, 85, 77, 273, 693, 349, 1239, 4503}},
-{634, 13, 1007, {1, 1, 5, 11, 7, 61, 9, 121, 25, 357, 1443, 405, 7827}},
-{635, 13, 1015, {1, 1, 7, 13, 11, 53, 11, 207, 145, 211, 1703, 1081, 2117}},
-{636, 13, 1016, {1, 1, 3, 11, 27, 23, 19, 9, 297, 279, 1481, 2273, 6387}},
-{637, 13, 1027, {1, 3, 3, 5, 15, 45, 3, 41, 305, 87, 1815, 3461, 5349}},
-{638, 13, 1036, {1, 3, 3, 13, 9, 37, 79, 125, 259, 561, 1087, 4091, 793}},
-{639, 13, 1039, {1, 3, 5, 7, 31, 55, 7, 145, 347, 929, 589, 2783, 5905}},
-{640, 13, 1041, {1, 1, 7, 15, 3, 25, 1, 181, 13, 243, 653, 2235, 7445}},
-{641, 13, 1048, {1, 3, 5, 5, 17, 53, 65, 7, 33, 583, 1363, 1313, 2319}},
-{642, 13, 1053, {1, 3, 3, 7, 27, 47, 97, 201, 187, 321, 63, 1515, 7917}},
-{643, 13, 1054, {1, 1, 3, 5, 23, 9, 3, 165, 61, 19, 1789, 3783, 3037}},
-{644, 13, 1058, {1, 3, 1, 13, 15, 43, 125, 191, 67, 273, 1551, 2227, 5253}},
-{645, 13, 1075, {1, 1, 1, 13, 25, 53, 107, 33, 299, 249, 1475, 2233, 907}},
-{646, 13, 1082, {1, 3, 5, 1, 23, 37, 85, 17, 207, 643, 665, 2933, 5199}},
-{647, 13, 1090, {1, 1, 7, 7, 25, 57, 59, 41, 15, 751, 751, 1749, 7053}},
-{648, 13, 1109, {1, 3, 3, 1, 13, 25, 127, 93, 281, 613, 875, 2223, 6345}},
-{649, 13, 1110, {1, 1, 5, 3, 29, 55, 79, 249, 43, 317, 533, 995, 1991}},
-{650, 13, 1119, {1, 3, 3, 15, 17, 49, 79, 31, 193, 233, 1437, 2615, 819}},
-{651, 13, 1126, {1, 1, 5, 15, 25, 3, 123, 145, 377, 9, 455, 1191, 3953}},
-{652, 13, 1130, {1, 3, 5, 3, 15, 19, 41, 231, 81, 393, 3, 19, 2409}},
-{653, 13, 1135, {1, 1, 3, 1, 27, 43, 113, 179, 7, 853, 947, 2731, 297}},
-{654, 13, 1137, {1, 1, 1, 11, 29, 39, 53, 191, 443, 689, 529, 3329, 7431}},
-{655, 13, 1140, {1, 3, 7, 5, 3, 29, 19, 67, 441, 113, 949, 2769, 4169}},
-{656, 13, 1149, {1, 3, 5, 11, 11, 55, 85, 169, 215, 815, 803, 2345, 3967}},
-{657, 13, 1156, {1, 1, 7, 9, 5, 45, 111, 5, 419, 375, 303, 1725, 4489}},
-{658, 13, 1159, {1, 3, 5, 15, 29, 43, 79, 19, 23, 417, 381, 541, 4923}},
-{659, 13, 1160, {1, 1, 3, 15, 3, 31, 117, 39, 117, 305, 1227, 1223, 143}},
-{660, 13, 1165, {1, 1, 5, 9, 5, 47, 87, 239, 181, 353, 1561, 3313, 1921}},
-{661, 13, 1173, {1, 3, 3, 1, 3, 15, 53, 221, 441, 987, 1997, 2529, 8059}},
-{662, 13, 1178, {1, 1, 7, 11, 15, 57, 111, 139, 137, 883, 1881, 2823, 5661}},
-{663, 13, 1183, {1, 3, 5, 5, 21, 11, 5, 13, 27, 973, 587, 1331, 1373}},
-{664, 13, 1184, {1, 1, 7, 11, 29, 51, 93, 29, 217, 221, 55, 2477, 1979}},
-{665, 13, 1189, {1, 3, 3, 13, 3, 11, 49, 75, 379, 371, 1441, 793, 7633}},
-{666, 13, 1194, {1, 1, 1, 13, 19, 45, 89, 249, 91, 649, 1695, 915, 5619}},
-{667, 13, 1211, {1, 3, 1, 7, 7, 29, 1, 77, 313, 895, 519, 771, 295}},
-{668, 13, 1214, {1, 3, 1, 15, 5, 3, 1, 57, 331, 109, 485, 2853, 6831}},
-{669, 13, 1216, {1, 1, 1, 15, 17, 3, 35, 99, 245, 971, 839, 2509, 2803}},
-{670, 13, 1225, {1, 3, 3, 3, 9, 37, 57, 251, 325, 317, 529, 1313, 6379}},
-{671, 13, 1231, {1, 1, 1, 15, 25, 59, 1, 119, 95, 15, 795, 2375, 6463}},
-{672, 13, 1239, {1, 3, 1, 5, 1, 49, 117, 21, 47, 179, 863, 85, 1669}},
-{673, 13, 1243, {1, 3, 7, 3, 9, 37, 19, 221, 455, 973, 571, 1427, 817}},
-{674, 13, 1246, {1, 1, 1, 15, 17, 9, 67, 213, 127, 887, 1299, 2913, 7451}},
-{675, 13, 1249, {1, 3, 1, 13, 27, 27, 41, 43, 171, 623, 691, 391, 4885}},
-{676, 13, 1259, {1, 3, 1, 13, 17, 17, 123, 239, 143, 227, 1151, 519, 6543}},
-{677, 13, 1273, {1, 3, 7, 5, 7, 63, 97, 39, 101, 555, 1057, 381, 7891}},
-{678, 13, 1274, {1, 3, 5, 1, 3, 27, 85, 129, 161, 875, 1945, 3541, 695}},
-{679, 13, 1281, {1, 3, 3, 5, 21, 59, 25, 183, 35, 25, 987, 1459, 181}},
-{680, 13, 1287, {1, 3, 5, 13, 1, 15, 127, 237, 349, 337, 1491, 2383, 7811}},
-{681, 13, 1294, {1, 3, 5, 5, 31, 5, 109, 51, 409, 733, 1395, 3207, 6049}},
-{682, 13, 1296, {1, 1, 5, 7, 13, 35, 113, 25, 263, 389, 299, 2521, 1783}},
-{683, 13, 1305, {1, 3, 7, 11, 15, 47, 97, 73, 55, 75, 113, 2695, 1023}},
-{684, 13, 1306, {1, 3, 1, 1, 3, 13, 69, 211, 289, 483, 1335, 787, 677}},
-{685, 13, 1318, {1, 1, 3, 3, 17, 7, 37, 77, 505, 137, 1113, 345, 2975}},
-{686, 13, 1332, {1, 1, 1, 13, 3, 11, 95, 199, 453, 109, 479, 3725, 239}},
-{687, 13, 1335, {1, 1, 7, 15, 19, 53, 3, 145, 359, 863, 347, 3833, 3043}},
-{688, 13, 1336, {1, 1, 7, 15, 25, 63, 127, 129, 125, 195, 155, 2211, 8153}},
-{689, 13, 1341, {1, 1, 7, 13, 9, 49, 121, 115, 73, 119, 1851, 727, 47}},
-{690, 13, 1342, {1, 3, 3, 13, 13, 11, 71, 7, 45, 591, 133, 2407, 5563}},
-{691, 13, 1362, {1, 1, 1, 13, 23, 29, 87, 89, 501, 71, 1759, 1119, 687}},
-{692, 13, 1364, {1, 1, 7, 7, 13, 7, 13, 183, 53, 951, 1877, 3991, 6771}},
-{693, 13, 1368, {1, 3, 7, 11, 7, 1, 27, 47, 61, 21, 919, 961, 1091}},
-{694, 13, 1378, {1, 3, 5, 5, 1, 27, 1, 5, 63, 157, 1297, 1049, 5893}},
-{695, 13, 1387, {1, 3, 7, 9, 19, 33, 17, 133, 425, 797, 1721, 153, 119}},
-{696, 13, 1389, {1, 3, 3, 7, 13, 37, 1, 215, 509, 1003, 61, 2353, 7511}},
-{697, 13, 1397, {1, 1, 7, 1, 29, 19, 31, 79, 199, 555, 1209, 1603, 6089}},
-{698, 13, 1401, {1, 3, 1, 1, 5, 31, 111, 127, 333, 429, 1863, 3925, 5411}},
-{699, 13, 1408, {1, 1, 7, 5, 5, 5, 123, 191, 47, 993, 269, 4051, 2111}},
-{700, 13, 1418, {1, 1, 5, 15, 1, 9, 87, 5, 47, 463, 865, 1813, 7357}},
-{701, 13, 1425, {1, 3, 1, 3, 23, 63, 123, 83, 511, 777, 63, 1285, 4537}},
-{702, 13, 1426, {1, 3, 3, 7, 27, 25, 31, 65, 441, 529, 1815, 1893, 323}},
-{703, 13, 1431, {1, 3, 7, 5, 11, 19, 7, 5, 397, 811, 755, 2883, 4217}},
-{704, 13, 1435, {1, 3, 1, 13, 9, 21, 13, 7, 271, 539, 1769, 3243, 5325}},
-{705, 13, 1441, {1, 1, 7, 1, 31, 13, 47, 131, 181, 457, 1559, 2663, 6653}},
-{706, 13, 1444, {1, 3, 3, 7, 29, 55, 25, 203, 419, 91, 437, 1159, 5691}},
-{707, 13, 1462, {1, 1, 3, 13, 29, 19, 71, 217, 337, 329, 501, 939, 2205}},
-{708, 13, 1471, {1, 1, 3, 1, 1, 27, 17, 201, 97, 285, 1269, 4043, 2207}},
-{709, 13, 1474, {1, 1, 1, 1, 3, 41, 13, 199, 141, 129, 1515, 3129, 5969}},
-{710, 13, 1483, {1, 3, 3, 9, 3, 17, 119, 41, 271, 933, 877, 701, 2197}},
-{711, 13, 1485, {1, 1, 1, 7, 15, 47, 3, 195, 115, 821, 725, 843, 6071}},
-{712, 13, 1494, {1, 3, 5, 15, 17, 33, 85, 65, 297, 571, 1123, 2743, 5727}},
-{713, 13, 1497, {1, 1, 5, 11, 27, 15, 37, 235, 415, 293, 1439, 2739, 4171}},
-{714, 13, 1516, {1, 3, 7, 7, 1, 55, 71, 35, 307, 11, 401, 1881, 933}},
-{715, 13, 1522, {1, 3, 1, 11, 21, 37, 3, 177, 119, 339, 559, 3991, 3437}},
-{716, 13, 1534, {1, 3, 3, 9, 17, 17, 97, 119, 301, 169, 157, 3267, 2261}},
-{717, 13, 1543, {1, 3, 3, 9, 29, 3, 111, 101, 355, 869, 375, 2609, 7377}},
-{718, 13, 1552, {1, 3, 5, 9, 7, 21, 123, 99, 343, 693, 1927, 1605, 4923}},
-{719, 13, 1557, {1, 1, 3, 5, 13, 31, 99, 17, 75, 385, 1539, 1553, 7077}},
-{720, 13, 1558, {1, 3, 3, 5, 31, 35, 107, 11, 407, 1019, 1317, 3593, 7203}},
-{721, 13, 1567, {1, 3, 3, 13, 17, 33, 99, 245, 401, 957, 157, 1949, 1571}},
-{722, 13, 1568, {1, 3, 1, 11, 27, 15, 11, 109, 429, 307, 1911, 2701, 861}},
-{723, 13, 1574, {1, 1, 5, 13, 13, 35, 55, 255, 311, 957, 1803, 2673, 5195}},
-{724, 13, 1592, {1, 1, 1, 11, 19, 3, 89, 37, 211, 783, 1355, 3567, 7135}},
-{725, 13, 1605, {1, 1, 5, 5, 21, 49, 79, 17, 509, 331, 183, 3831, 855}},
-{726, 13, 1606, {1, 3, 7, 5, 29, 19, 85, 109, 105, 523, 845, 3385, 7477}},
-{727, 13, 1610, {1, 1, 1, 7, 25, 17, 125, 131, 53, 757, 253, 2989, 2939}},
-{728, 13, 1617, {1, 3, 3, 9, 19, 23, 105, 39, 351, 677, 211, 401, 8103}},
-{729, 13, 1623, {1, 3, 5, 1, 5, 11, 17, 3, 405, 469, 1569, 2865, 3133}},
-{730, 13, 1630, {1, 1, 3, 13, 15, 5, 117, 179, 139, 145, 477, 1137, 2537}},
-{731, 13, 1634, {1, 1, 7, 9, 5, 21, 9, 93, 211, 963, 1207, 3343, 4911}},
-{732, 13, 1640, {1, 1, 1, 9, 13, 43, 17, 53, 81, 793, 1571, 2523, 3683}},
-{733, 13, 1643, {1, 3, 3, 13, 25, 21, 5, 59, 489, 987, 1941, 171, 6009}},
-{734, 13, 1648, {1, 3, 3, 7, 1, 39, 89, 171, 403, 467, 1767, 3423, 2791}},
-{735, 13, 1651, {1, 1, 3, 9, 19, 49, 91, 125, 163, 1013, 89, 2849, 6785}},
-{736, 13, 1653, {1, 1, 5, 9, 9, 11, 15, 241, 43, 297, 1719, 1541, 1821}},
-{737, 13, 1670, {1, 3, 7, 15, 29, 23, 103, 239, 191, 33, 1043, 3649, 6579}},
-{738, 13, 1676, {1, 3, 3, 9, 21, 51, 123, 55, 223, 645, 1463, 4021, 5891}},
-{739, 13, 1684, {1, 1, 5, 7, 3, 41, 27, 235, 391, 303, 2021, 3187, 7607}},
-{740, 13, 1687, {1, 1, 1, 9, 5, 49, 49, 29, 377, 251, 1887, 1017, 1301}},
-{741, 13, 1691, {1, 1, 3, 3, 13, 41, 27, 47, 223, 23, 517, 3227, 6731}},
-{742, 13, 1693, {1, 1, 7, 1, 31, 25, 47, 9, 511, 623, 2047, 1263, 1511}},
-{743, 13, 1698, {1, 1, 3, 15, 15, 23, 53, 1, 261, 595, 85, 241, 7047}},
-{744, 13, 1709, {1, 3, 3, 11, 17, 5, 81, 73, 149, 781, 2035, 3163, 4247}},
-{745, 13, 1715, {1, 3, 7, 7, 29, 59, 49, 79, 397, 901, 1105, 2191, 6277}},
-{746, 13, 1722, {1, 3, 3, 11, 13, 27, 25, 173, 107, 73, 1265, 585, 5251}},
-{747, 13, 1732, {1, 1, 7, 15, 29, 23, 73, 229, 235, 887, 1469, 4073, 2591}},
-{748, 13, 1735, {1, 1, 3, 9, 17, 15, 83, 173, 207, 879, 1701, 1509, 11}},
-{749, 13, 1747, {1, 1, 3, 5, 5, 37, 65, 161, 39, 421, 1153, 2007, 5355}},
-{750, 13, 1749, {1, 1, 7, 11, 23, 37, 5, 11, 9, 499, 17, 157, 5747}},
-{751, 13, 1754, {1, 3, 7, 13, 25, 9, 49, 7, 39, 945, 1349, 1759, 1441}},
-{752, 13, 1777, {1, 1, 5, 3, 21, 15, 113, 81, 265, 837, 333, 3625, 6133}},
-{753, 13, 1784, {1, 3, 1, 11, 13, 27, 73, 109, 297, 327, 299, 3253, 6957}},
-{754, 13, 1790, {1, 1, 3, 13, 19, 39, 123, 73, 65, 5, 1061, 2187, 5055}},
-{755, 13, 1795, {1, 1, 3, 1, 11, 31, 21, 115, 453, 857, 711, 495, 549}},
-{756, 13, 1801, {1, 3, 7, 7, 15, 29, 79, 103, 47, 713, 1735, 3121, 6321}},
-{757, 13, 1802, {1, 1, 5, 5, 29, 9, 97, 33, 471, 705, 329, 1501, 1349}},
-{758, 13, 1812, {1, 3, 3, 1, 21, 9, 111, 209, 71, 47, 491, 2143, 1797}},
-{759, 13, 1828, {1, 3, 3, 3, 11, 39, 21, 135, 445, 259, 607, 3811, 5449}},
-{760, 13, 1831, {1, 1, 7, 9, 11, 25, 113, 251, 395, 317, 317, 91, 1979}},
-{761, 13, 1837, {1, 3, 1, 9, 3, 21, 103, 133, 389, 943, 1235, 1749, 7063}},
-{762, 13, 1838, {1, 1, 3, 7, 1, 11, 5, 15, 497, 477, 479, 3079, 6969}},
-{763, 13, 1840, {1, 1, 3, 3, 15, 39, 105, 131, 475, 465, 181, 865, 3813}},
-{764, 13, 1845, {1, 1, 7, 9, 19, 63, 123, 131, 415, 525, 457, 2471, 3135}},
-{765, 13, 1863, {1, 3, 7, 15, 25, 35, 123, 45, 341, 805, 485, 4049, 7065}},
-{766, 13, 1864, {1, 1, 1, 5, 29, 9, 47, 227, 51, 867, 1873, 1593, 2271}},
-{767, 13, 1867, {1, 1, 7, 15, 31, 9, 71, 117, 285, 711, 837, 1435, 6275}},
-{768, 13, 1870, {1, 3, 1, 1, 5, 19, 79, 25, 301, 415, 1871, 645, 3251}},
-{769, 13, 1877, {1, 3, 1, 3, 17, 51, 99, 185, 447, 43, 523, 219, 429}},
-{770, 13, 1881, {1, 3, 1, 13, 29, 13, 51, 93, 7, 995, 757, 3017, 6865}},
-{771, 13, 1884, {1, 1, 3, 15, 7, 25, 75, 17, 155, 981, 1231, 1229, 1995}},
-{772, 13, 1903, {1, 3, 5, 3, 27, 45, 71, 73, 225, 763, 377, 1139, 2863}},
-{773, 13, 1917, {1, 1, 3, 1, 1, 39, 69, 113, 29, 371, 1051, 793, 3749}},
-{774, 13, 1918, {1, 1, 3, 13, 23, 61, 27, 183, 307, 431, 1345, 2757, 4031}},
-{775, 13, 1922, {1, 3, 7, 5, 5, 59, 117, 197, 303, 721, 877, 723, 1601}},
-{776, 13, 1924, {1, 3, 5, 1, 27, 33, 99, 237, 485, 711, 665, 3077, 5105}},
-{777, 13, 1928, {1, 1, 3, 1, 13, 9, 103, 201, 23, 951, 2029, 165, 2093}},
-{778, 13, 1931, {1, 3, 5, 13, 5, 29, 55, 85, 221, 677, 611, 3613, 4567}},
-{779, 13, 1951, {1, 1, 1, 1, 7, 61, 9, 233, 261, 561, 953, 4023, 2443}},
-{780, 13, 1952, {1, 3, 3, 13, 1, 17, 103, 71, 223, 213, 833, 1747, 6999}},
-{781, 13, 1957, {1, 3, 5, 15, 25, 53, 57, 187, 25, 695, 1207, 4089, 2877}},
-{782, 13, 1958, {1, 1, 7, 1, 7, 31, 87, 129, 493, 519, 1555, 1155, 4637}},
-{783, 13, 1964, {1, 1, 1, 15, 21, 17, 23, 29, 19, 255, 927, 1791, 3093}},
-{784, 13, 1967, {1, 1, 3, 9, 17, 33, 95, 129, 175, 461, 287, 2633, 2325}},
-{785, 13, 1970, {1, 3, 5, 7, 23, 19, 63, 209, 249, 583, 1373, 2039, 2225}},
-{786, 13, 1972, {1, 3, 3, 5, 5, 19, 79, 241, 459, 355, 1455, 3313, 3639}},
-{787, 13, 1994, {1, 1, 7, 9, 21, 41, 97, 119, 129, 769, 1541, 3495, 7741}},
-{788, 13, 2002, {1, 1, 7, 11, 9, 29, 35, 255, 141, 937, 1763, 41, 1393}},
-{789, 13, 2007, {1, 3, 7, 1, 13, 51, 61, 157, 177, 847, 1829, 3539, 285}},
-{790, 13, 2008, {1, 1, 1, 15, 21, 13, 9, 55, 397, 19, 1495, 1255, 7235}},
-{791, 13, 2023, {1, 1, 7, 7, 25, 37, 53, 237, 319, 197, 269, 1205, 1485}},
-{792, 13, 2030, {1, 1, 5, 15, 23, 17, 35, 247, 323, 807, 233, 3681, 4407}},
-{793, 13, 2035, {1, 1, 3, 7, 9, 59, 85, 105, 493, 763, 1639, 391, 1451}},
-{794, 13, 2038, {1, 3, 3, 9, 15, 33, 5, 253, 129, 625, 1527, 2793, 6057}},
-{795, 13, 2042, {1, 3, 1, 1, 7, 47, 21, 161, 235, 83, 397, 3563, 5953}},
-{796, 13, 2047, {1, 3, 7, 11, 3, 41, 25, 117, 375, 779, 1297, 3715, 8117}},
-{797, 13, 2051, {1, 1, 3, 7, 31, 19, 103, 173, 475, 189, 2035, 2921, 1107}},
-{798, 13, 2058, {1, 1, 7, 3, 25, 7, 93, 255, 307, 113, 1893, 2233, 6919}},
-{799, 13, 2060, {1, 3, 5, 15, 9, 57, 79, 143, 165, 5, 1389, 193, 693}},
-{800, 13, 2071, {1, 3, 5, 1, 29, 45, 91, 49, 189, 461, 439, 1283, 7835}},
-{801, 13, 2084, {1, 1, 3, 13, 11, 61, 41, 231, 373, 695, 395, 915, 5393}},
-{802, 13, 2087, {1, 3, 7, 11, 5, 51, 67, 53, 483, 95, 1943, 247, 5653}},
-{803, 13, 2099, {1, 3, 7, 5, 5, 57, 45, 235, 137, 793, 1069, 1661, 1557}},
-{804, 13, 2108, {1, 3, 5, 3, 25, 55, 103, 177, 81, 861, 1151, 143, 7655}},
-{805, 13, 2111, {1, 1, 3, 1, 21, 41, 67, 131, 253, 431, 1269, 3181, 3429}},
-{806, 13, 2120, {1, 3, 1, 1, 21, 7, 77, 221, 257, 663, 71, 2949, 2481}},
-{807, 13, 2128, {1, 3, 5, 3, 3, 23, 45, 107, 299, 739, 1013, 3, 3165}},
-{808, 13, 2138, {1, 1, 5, 1, 3, 37, 109, 37, 243, 983, 1221, 1691, 3869}},
-{809, 13, 2143, {1, 1, 5, 5, 31, 7, 5, 193, 397, 867, 1495, 3435, 7441}},
-{810, 13, 2144, {1, 1, 1, 1, 17, 59, 97, 233, 389, 597, 1013, 1631, 483}},
-{811, 13, 2153, {1, 1, 1, 11, 7, 41, 107, 53, 111, 125, 1513, 1921, 7647}},
-{812, 13, 2156, {1, 3, 3, 3, 31, 29, 117, 3, 365, 971, 1139, 2123, 5913}},
-{813, 13, 2162, {1, 1, 1, 13, 23, 3, 1, 167, 475, 639, 1811, 3841, 3081}},
-{814, 13, 2167, {1, 1, 5, 3, 5, 47, 65, 123, 275, 783, 95, 119, 7591}},
-{815, 13, 2178, {1, 3, 1, 15, 13, 33, 93, 237, 467, 431, 705, 4013, 4035}},
-{816, 13, 2183, {1, 3, 5, 1, 19, 7, 101, 231, 155, 737, 1381, 3343, 2051}},
-{817, 13, 2202, {1, 1, 5, 9, 15, 49, 45, 163, 433, 765, 2031, 201, 2589}},
-{818, 13, 2211, {1, 3, 7, 9, 19, 41, 31, 89, 93, 623, 105, 745, 4409}},
-{819, 13, 2214, {1, 1, 5, 1, 11, 45, 127, 85, 389, 439, 829, 477, 7965}},
-{820, 13, 2223, {1, 3, 3, 15, 13, 41, 1, 207, 435, 585, 311, 1725, 2737}},
-{821, 13, 2225, {1, 3, 3, 3, 13, 49, 21, 31, 197, 799, 1411, 2959, 7133}},
-{822, 13, 2232, {1, 3, 1, 3, 7, 43, 9, 141, 133, 579, 1059, 93, 957}},
-{823, 13, 2237, {1, 3, 7, 1, 15, 51, 23, 213, 381, 851, 699, 2261, 3419}},
-{824, 13, 2257, {1, 3, 5, 9, 25, 35, 67, 141, 35, 409, 1423, 365, 1645}},
-{825, 13, 2260, {1, 3, 3, 11, 15, 33, 27, 181, 93, 87, 1761, 3511, 1353}},
-{826, 13, 2267, {1, 3, 5, 3, 25, 63, 111, 137, 321, 819, 705, 1547, 7271}},
-{827, 13, 2274, {1, 3, 1, 1, 5, 57, 99, 59, 411, 757, 1371, 3953, 3695}},
-{828, 13, 2276, {1, 3, 5, 11, 11, 21, 25, 147, 239, 455, 709, 953, 7175}},
-{829, 13, 2285, {1, 3, 3, 15, 5, 53, 91, 205, 341, 63, 723, 1565, 7135}},
-{830, 13, 2288, {1, 1, 7, 15, 11, 21, 99, 79, 63, 593, 2007, 3629, 5271}},
-{831, 13, 2293, {1, 3, 3, 1, 9, 21, 45, 175, 453, 435, 1855, 2649, 6959}},
-{832, 13, 2294, {1, 1, 3, 15, 15, 33, 121, 121, 251, 431, 1127, 3305, 4199}},
-{833, 13, 2297, {1, 1, 1, 9, 31, 15, 71, 29, 345, 391, 1159, 2809, 345}},
-{834, 13, 2303, {1, 3, 7, 1, 23, 29, 95, 151, 327, 727, 647, 1623, 2971}},
-{835, 13, 2308, {1, 1, 7, 7, 9, 29, 79, 91, 127, 909, 1293, 1315, 5315}},
-{836, 13, 2311, {1, 1, 5, 11, 13, 37, 89, 73, 149, 477, 1909, 3343, 525}},
-{837, 13, 2318, {1, 3, 5, 7, 5, 59, 55, 255, 223, 459, 2027, 237, 4205}},
-{838, 13, 2323, {1, 1, 1, 7, 27, 11, 95, 65, 325, 835, 907, 3801, 3787}},
-{839, 13, 2332, {1, 1, 1, 11, 27, 33, 99, 175, 51, 913, 331, 1851, 4133}},
-{840, 13, 2341, {1, 3, 5, 5, 13, 37, 31, 99, 273, 409, 1827, 3845, 5491}},
-{841, 13, 2345, {1, 1, 3, 7, 23, 19, 107, 85, 283, 523, 509, 451, 421}},
-{842, 13, 2348, {1, 3, 5, 7, 13, 9, 51, 81, 87, 619, 61, 2803, 5271}},
-{843, 13, 2354, {1, 1, 1, 15, 9, 45, 35, 219, 401, 271, 953, 649, 6847}},
-{844, 13, 2368, {1, 1, 7, 11, 9, 45, 17, 219, 169, 837, 1483, 1605, 2901}},
-{845, 13, 2377, {1, 1, 7, 7, 21, 43, 37, 33, 291, 359, 71, 2899, 7037}},
-{846, 13, 2380, {1, 3, 3, 13, 31, 53, 37, 15, 149, 949, 551, 3445, 5455}},
-{847, 13, 2383, {1, 3, 1, 5, 19, 45, 81, 223, 193, 439, 2047, 3879, 789}},
-{848, 13, 2388, {1, 1, 7, 3, 11, 63, 35, 61, 255, 563, 459, 2991, 3359}},
-{849, 13, 2395, {1, 1, 5, 9, 13, 49, 47, 185, 239, 221, 1533, 3635, 2045}},
-{850, 13, 2397, {1, 3, 7, 3, 25, 37, 127, 223, 51, 357, 483, 3837, 6873}},
-{851, 13, 2401, {1, 1, 7, 9, 31, 37, 113, 31, 387, 833, 1243, 1543, 5535}},
-{852, 13, 2411, {1, 3, 1, 9, 23, 59, 119, 221, 73, 185, 2007, 2885, 2563}},
-{853, 13, 2413, {1, 1, 1, 13, 7, 33, 53, 179, 67, 185, 1541, 1807, 4659}},
-{854, 13, 2419, {1, 3, 1, 11, 31, 37, 23, 215, 269, 357, 207, 645, 4219}},
-{855, 13, 2435, {1, 3, 3, 13, 19, 27, 107, 55, 91, 71, 1695, 1815, 89}},
-{856, 13, 2442, {1, 1, 3, 15, 3, 19, 35, 247, 49, 529, 1523, 3317, 6151}},
-{857, 13, 2455, {1, 1, 7, 7, 23, 25, 107, 139, 483, 503, 1277, 243, 7879}},
-{858, 13, 2472, {1, 3, 3, 13, 3, 15, 11, 197, 135, 839, 985, 275, 5527}},
-{859, 13, 2478, {1, 3, 5, 3, 25, 47, 95, 21, 113, 307, 1001, 3065, 295}},
-{860, 13, 2490, {1, 1, 3, 9, 19, 19, 99, 213, 363, 449, 735, 2851, 2521}},
-{861, 13, 2507, {1, 1, 3, 9, 5, 49, 63, 61, 157, 857, 497, 2801, 6987}},
-{862, 13, 2509, {1, 1, 1, 9, 1, 41, 109, 119, 499, 939, 867, 3675, 8023}},
-{863, 13, 2517, {1, 3, 1, 1, 13, 33, 109, 123, 289, 3, 1271, 2773, 4265}},
-{864, 13, 2524, {1, 3, 1, 11, 9, 57, 83, 221, 95, 43, 1189, 457, 7133}},
-{865, 13, 2528, {1, 1, 7, 3, 11, 49, 33, 219, 229, 289, 685, 3359, 4495}},
-{866, 13, 2531, {1, 3, 1, 3, 19, 43, 67, 193, 41, 771, 407, 81, 3891}},
-{867, 13, 2538, {1, 1, 7, 11, 5, 29, 51, 175, 297, 539, 1, 2245, 6439}},
-{868, 13, 2545, {1, 3, 7, 15, 21, 33, 117, 183, 511, 489, 1283, 3281, 5979}},
-{869, 13, 2546, {1, 3, 7, 5, 9, 3, 125, 147, 359, 549, 369, 3049, 2405}},
-{870, 13, 2555, {1, 3, 5, 7, 19, 5, 65, 97, 483, 377, 1523, 1457, 2995}},
-{871, 13, 2557, {1, 1, 5, 1, 11, 21, 41, 113, 277, 131, 1475, 1043, 2367}},
-{872, 13, 2564, {1, 3, 3, 1, 15, 17, 101, 69, 443, 865, 817, 1421, 5231}},
-{873, 13, 2573, {1, 1, 3, 3, 3, 55, 95, 99, 75, 195, 1929, 3931, 5855}},
-{874, 13, 2579, {1, 3, 1, 3, 19, 23, 93, 213, 241, 551, 1307, 585, 7729}},
-{875, 13, 2592, {1, 3, 1, 11, 23, 15, 53, 249, 467, 519, 95, 741, 409}},
-{876, 13, 2598, {1, 1, 1, 15, 29, 37, 43, 203, 233, 877, 77, 1933, 2729}},
-{877, 13, 2607, {1, 3, 7, 11, 27, 39, 43, 161, 255, 15, 1463, 833, 495}},
-{878, 13, 2612, {1, 1, 7, 11, 3, 53, 81, 67, 375, 823, 1903, 3061, 395}},
-{879, 13, 2619, {1, 1, 1, 1, 15, 37, 93, 233, 247, 501, 1321, 3275, 5409}},
-{880, 13, 2621, {1, 3, 3, 7, 7, 11, 5, 105, 139, 983, 1239, 531, 3881}},
-{881, 13, 2627, {1, 1, 5, 3, 19, 49, 107, 227, 361, 101, 355, 2649, 7383}},
-{882, 13, 2633, {1, 1, 7, 5, 25, 41, 101, 121, 209, 293, 1937, 2259, 5557}},
-{883, 13, 2636, {1, 1, 3, 7, 7, 1, 9, 13, 463, 1019, 995, 3159, 107}},
-{884, 13, 2642, {1, 3, 5, 11, 5, 35, 127, 97, 261, 789, 807, 807, 6257}},
-{885, 13, 2654, {1, 1, 7, 5, 11, 13, 45, 91, 417, 101, 1973, 3645, 2107}},
-{886, 13, 2660, {1, 1, 3, 7, 5, 63, 57, 49, 203, 157, 115, 1393, 8117}},
-{887, 13, 2669, {1, 3, 5, 5, 3, 43, 15, 155, 127, 489, 1165, 3701, 4867}},
-{888, 13, 2675, {1, 1, 7, 7, 29, 29, 69, 215, 415, 367, 371, 1901, 6075}},
-{889, 13, 2684, {1, 1, 1, 3, 11, 33, 89, 149, 433, 705, 1437, 1597, 505}},
-{890, 13, 2694, {1, 3, 5, 1, 13, 37, 19, 119, 5, 581, 2037, 1633, 2099}},
-{891, 13, 2703, {1, 3, 7, 13, 5, 49, 103, 245, 215, 515, 133, 2007, 1933}},
-{892, 13, 2706, {1, 3, 1, 9, 1, 3, 25, 197, 253, 387, 1683, 2267, 221}},
-{893, 13, 2712, {1, 3, 5, 15, 21, 9, 73, 201, 405, 999, 437, 3877, 6045}},
-{894, 13, 2715, {1, 1, 3, 1, 31, 55, 25, 83, 421, 395, 1807, 2129, 7797}},
-{895, 13, 2722, {1, 1, 3, 1, 23, 21, 121, 183, 125, 347, 143, 3685, 4317}},
-{896, 13, 2727, {1, 3, 3, 3, 17, 45, 17, 223, 267, 795, 1815, 1309, 155}},
-{897, 13, 2734, {1, 1, 1, 15, 17, 59, 5, 133, 15, 715, 1503, 153, 2887}},
-{898, 13, 2742, {1, 1, 1, 1, 27, 13, 119, 77, 243, 995, 1851, 3719, 4695}},
-{899, 13, 2745, {1, 3, 1, 5, 31, 49, 43, 165, 49, 609, 1265, 1141, 505}},
-{900, 13, 2751, {1, 1, 7, 13, 11, 63, 21, 253, 229, 585, 1543, 3719, 4141}},
-{901, 13, 2766, {1, 3, 7, 11, 23, 27, 17, 131, 295, 895, 1493, 1411, 3247}},
-{902, 13, 2768, {1, 1, 5, 9, 29, 7, 97, 15, 113, 445, 859, 1483, 1121}},
-{903, 13, 2780, {1, 3, 1, 9, 13, 49, 99, 107, 323, 201, 681, 3071, 5281}},
-{904, 13, 2790, {1, 1, 1, 15, 9, 19, 61, 161, 7, 87, 587, 2199, 2811}},
-{905, 13, 2794, {1, 3, 3, 15, 15, 19, 95, 45, 299, 829, 981, 3479, 487}},
-{906, 13, 2796, {1, 1, 1, 9, 3, 37, 7, 19, 227, 13, 397, 513, 1257}},
-{907, 13, 2801, {1, 1, 5, 15, 15, 13, 17, 111, 135, 929, 1145, 811, 1801}},
-{908, 13, 2804, {1, 3, 1, 3, 27, 57, 31, 19, 279, 103, 693, 631, 3409}},
-{909, 13, 2807, {1, 1, 1, 1, 15, 13, 67, 83, 23, 799, 1735, 2063, 3363}},
-{910, 13, 2816, {1, 3, 3, 7, 3, 1, 61, 31, 41, 533, 2025, 4067, 6963}},
-{911, 13, 2821, {1, 1, 5, 7, 17, 27, 81, 79, 107, 205, 29, 97, 4883}},
-{912, 13, 2831, {1, 1, 1, 5, 19, 49, 91, 201, 283, 949, 651, 3819, 5073}},
-{913, 13, 2834, {1, 1, 7, 9, 11, 13, 73, 197, 37, 219, 1931, 3369, 6017}},
-{914, 13, 2839, {1, 1, 7, 15, 11, 7, 75, 205, 7, 819, 399, 661, 6487}},
-{915, 13, 2845, {1, 3, 3, 3, 27, 37, 95, 41, 307, 165, 1077, 3485, 563}},
-{916, 13, 2852, {1, 3, 5, 3, 21, 49, 57, 179, 109, 627, 1789, 431, 2941}},
-{917, 13, 2856, {1, 1, 7, 5, 11, 19, 43, 137, 149, 679, 1543, 245, 1381}},
-{918, 13, 2861, {1, 3, 5, 5, 15, 3, 69, 81, 135, 159, 1363, 3401, 6355}},
-{919, 13, 2873, {1, 3, 5, 1, 9, 61, 49, 53, 319, 25, 1647, 1297, 615}},
-{920, 13, 2874, {1, 3, 5, 11, 31, 43, 9, 101, 71, 919, 335, 3147, 5823}},
-{921, 13, 2888, {1, 3, 1, 1, 15, 5, 29, 109, 511, 945, 867, 3677, 6915}},
-{922, 13, 2893, {1, 3, 3, 15, 17, 49, 91, 111, 215, 29, 1879, 97, 2505}},
-{923, 13, 2894, {1, 3, 1, 13, 19, 61, 11, 111, 163, 777, 533, 1113, 5339}},
-{924, 13, 2902, {1, 1, 7, 9, 17, 55, 117, 91, 455, 289, 557, 913, 4455}},
-{925, 13, 2917, {1, 3, 1, 7, 25, 19, 123, 37, 1, 277, 717, 2965, 4469}},
-{926, 13, 2921, {1, 3, 7, 3, 19, 23, 87, 235, 209, 457, 2041, 2893, 1805}},
-{927, 13, 2922, {1, 3, 3, 5, 5, 43, 23, 61, 351, 791, 59, 2009, 2909}},
-{928, 13, 2929, {1, 1, 3, 7, 5, 1, 27, 231, 385, 257, 1261, 2701, 1807}},
-{929, 13, 2935, {1, 3, 1, 1, 27, 19, 87, 253, 131, 685, 1743, 3983, 2651}},
-{930, 13, 2946, {1, 3, 7, 11, 21, 17, 11, 81, 191, 641, 1821, 3005, 7251}},
-{931, 13, 2951, {1, 3, 3, 5, 15, 31, 41, 213, 55, 931, 1953, 49, 6037}},
-{932, 13, 2957, {1, 1, 7, 15, 7, 27, 65, 223, 113, 79, 1875, 911, 5445}},
-{933, 13, 2960, {1, 3, 7, 7, 23, 55, 51, 167, 495, 25, 1585, 3447, 799}},
-{934, 13, 2966, {1, 1, 3, 7, 27, 15, 95, 193, 337, 415, 975, 3085, 967}},
-{935, 13, 2972, {1, 1, 7, 15, 19, 7, 93, 41, 433, 551, 401, 3169, 3971}},
-{936, 13, 2976, {1, 1, 7, 11, 13, 15, 53, 69, 433, 59, 1117, 3359, 6231}},
-{937, 13, 2979, {1, 1, 7, 3, 23, 5, 115, 201, 225, 109, 1903, 3897, 6265}},
-{938, 13, 2985, {1, 1, 1, 11, 17, 1, 39, 143, 361, 659, 1105, 23, 4923}},
-{939, 13, 3000, {1, 1, 1, 9, 27, 57, 85, 227, 261, 119, 1881, 3965, 6999}},
-{940, 13, 3003, {1, 3, 7, 7, 15, 7, 107, 17, 315, 49, 1591, 905, 7789}},
-{941, 13, 3013, {1, 3, 1, 7, 29, 3, 47, 237, 157, 769, 839, 3199, 3195}},
-{942, 13, 3018, {1, 1, 3, 15, 25, 39, 63, 15, 111, 857, 881, 1505, 7671}},
-{943, 13, 3020, {1, 1, 7, 1, 3, 35, 41, 215, 99, 895, 1025, 1483, 4707}},
-{944, 13, 3025, {1, 3, 5, 1, 1, 31, 25, 247, 113, 841, 397, 1825, 6969}},
-{945, 13, 3042, {1, 1, 3, 5, 19, 41, 49, 243, 225, 973, 241, 175, 1041}},
-{946, 13, 3047, {1, 1, 1, 7, 15, 15, 105, 141, 83, 75, 1675, 3523, 5219}},
-{947, 13, 3048, {1, 1, 7, 5, 13, 27, 47, 199, 445, 841, 959, 1157, 2209}},
-{948, 13, 3051, {1, 3, 5, 15, 23, 31, 31, 81, 85, 33, 785, 2639, 7799}},
-{949, 13, 3054, {1, 1, 5, 13, 21, 3, 47, 99, 235, 943, 1731, 2467, 7891}},
-{950, 13, 3056, {1, 1, 1, 3, 17, 53, 85, 219, 73, 131, 1339, 875, 1191}},
-{951, 13, 3065, {1, 1, 5, 7, 17, 63, 113, 7, 185, 557, 749, 3563, 4973}},
-{952, 13, 3073, {1, 3, 3, 15, 15, 21, 43, 111, 155, 689, 345, 423, 3597}},
-{953, 13, 3074, {1, 1, 5, 1, 15, 29, 93, 5, 361, 713, 695, 3937, 425}},
-{954, 13, 3083, {1, 3, 7, 7, 13, 41, 115, 175, 315, 937, 123, 2841, 4457}},
-{955, 13, 3086, {1, 1, 3, 11, 25, 5, 103, 53, 423, 811, 657, 399, 7257}},
-{956, 13, 3091, {1, 1, 1, 1, 1, 13, 101, 211, 383, 325, 97, 1703, 4429}},
-{957, 13, 3097, {1, 3, 7, 9, 31, 45, 83, 157, 509, 701, 841, 1105, 3643}},
-{958, 13, 3109, {1, 1, 1, 7, 1, 9, 69, 17, 129, 281, 1161, 2945, 7693}},
-{959, 13, 3116, {1, 3, 7, 1, 11, 29, 51, 143, 77, 433, 1723, 2317, 5641}},
-{960, 13, 3124, {1, 1, 1, 1, 21, 43, 13, 67, 177, 505, 1629, 1267, 4885}},
-{961, 13, 3128, {1, 1, 3, 11, 27, 63, 111, 47, 233, 781, 453, 1679, 3209}},
-{962, 13, 3153, {1, 1, 3, 13, 29, 27, 119, 141, 493, 971, 461, 1159, 633}},
-{963, 13, 3160, {1, 1, 3, 15, 23, 5, 79, 215, 163, 149, 1805, 2399, 61}},
-{964, 13, 3165, {1, 3, 5, 13, 19, 5, 1, 39, 409, 561, 709, 829, 1357}},
-{965, 13, 3172, {1, 3, 3, 13, 19, 43, 9, 177, 449, 447, 73, 2107, 5669}},
-{966, 13, 3175, {1, 3, 5, 1, 23, 13, 63, 109, 203, 593, 829, 4017, 6881}},
-{967, 13, 3184, {1, 1, 5, 7, 3, 9, 53, 175, 391, 169, 1283, 3793, 4451}},
-{968, 13, 3193, {1, 1, 5, 7, 29, 43, 9, 5, 209, 77, 927, 2941, 8145}},
-{969, 13, 3196, {1, 3, 5, 15, 17, 49, 5, 143, 131, 771, 1685, 925, 2175}},
-{970, 13, 3200, {1, 1, 3, 11, 27, 27, 27, 159, 161, 1015, 1587, 4049, 1983}},
-{971, 13, 3203, {1, 3, 1, 3, 23, 57, 119, 67, 481, 577, 389, 3319, 5325}},
-{972, 13, 3205, {1, 3, 5, 1, 19, 39, 87, 61, 329, 657, 1773, 31, 1707}},
-{973, 13, 3209, {1, 1, 3, 1, 5, 25, 15, 241, 131, 815, 1751, 3029, 8039}},
-{974, 13, 3224, {1, 3, 3, 13, 27, 13, 77, 87, 437, 57, 621, 1031, 7891}},
-{975, 13, 3239, {1, 3, 1, 13, 23, 51, 117, 37, 331, 745, 605, 3179, 4713}},
-{976, 13, 3251, {1, 1, 5, 5, 19, 17, 99, 167, 87, 721, 737, 789, 2165}},
-{977, 13, 3254, {1, 3, 5, 13, 1, 51, 119, 211, 165, 299, 1327, 3053, 3343}},
-{978, 13, 3265, {1, 1, 5, 15, 29, 45, 17, 129, 67, 345, 1553, 2705, 7369}},
-{979, 13, 3266, {1, 1, 1, 9, 23, 7, 13, 209, 7, 407, 317, 3077, 7287}},
-{980, 13, 3275, {1, 1, 1, 5, 9, 59, 89, 3, 487, 451, 505, 2499, 7563}},
-{981, 13, 3280, {1, 3, 1, 7, 21, 1, 21, 203, 101, 417, 1389, 2751, 1397}},
-{982, 13, 3283, {1, 3, 7, 13, 7, 31, 3, 247, 349, 485, 1259, 549, 6321}},
-{983, 13, 3286, {1, 1, 7, 7, 27, 33, 107, 197, 293, 729, 1753, 2571, 103}},
-{984, 13, 3301, {1, 3, 5, 9, 25, 35, 5, 253, 137, 213, 2041, 3387, 1809}},
-{985, 13, 3302, {1, 1, 7, 13, 15, 35, 67, 83, 295, 175, 839, 2831, 839}},
-{986, 13, 3305, {1, 3, 3, 11, 3, 17, 55, 141, 247, 991, 117, 3799, 1221}},
-{987, 13, 3319, {1, 1, 5, 1, 11, 37, 87, 233, 457, 653, 899, 2933, 3105}},
-{988, 13, 3323, {1, 1, 3, 15, 3, 31, 67, 167, 437, 9, 651, 1109, 1139}},
-{989, 13, 3326, {1, 1, 3, 1, 7, 63, 67, 17, 11, 883, 1855, 1941, 4751}},
-{990, 13, 3331, {1, 3, 7, 9, 19, 33, 113, 117, 495, 39, 1795, 2561, 5519}},
-{991, 13, 3348, {1, 1, 7, 5, 1, 3, 103, 37, 201, 223, 1101, 877, 6483}},
-{992, 13, 3351, {1, 1, 5, 9, 29, 49, 51, 33, 439, 917, 861, 1321, 2135}},
-{993, 13, 3358, {1, 1, 3, 3, 1, 5, 17, 93, 217, 619, 613, 1357, 6095}},
-{994, 13, 3368, {1, 3, 1, 11, 3, 21, 5, 41, 15, 175, 843, 2937, 6849}},
-{995, 13, 3374, {1, 3, 3, 7, 9, 57, 55, 127, 79, 287, 445, 2205, 7989}},
-{996, 13, 3376, {1, 1, 7, 13, 23, 17, 93, 129, 157, 135, 1747, 1813, 4183}},
-{997, 13, 3379, {1, 1, 1, 5, 31, 59, 99, 33, 425, 329, 887, 367, 1761}},
-{998, 13, 3385, {1, 1, 7, 9, 17, 53, 77, 139, 435, 387, 49, 3649, 1773}},
-{999, 13, 3386, {1, 3, 3, 15, 21, 57, 45, 161, 331, 719, 273, 3479, 4173}},
-{1000, 13, 3396, {1, 1, 3, 9, 3, 3, 105, 201, 373, 877, 919, 1263, 6649}},
-{1001, 13, 3420, {1, 3, 1, 15, 13, 43, 13, 99, 73, 163, 353, 3569, 5601}},
-{1002, 13, 3423, {1, 3, 7, 3, 5, 9, 69, 177, 449, 47, 781, 1125, 4245}},
-{1003, 13, 3430, {1, 1, 1, 5, 3, 45, 1, 123, 409, 903, 205, 2057, 7637}},
-{1004, 13, 3433, {1, 3, 5, 9, 19, 47, 87, 135, 481, 799, 101, 3409, 2241}},
-{1005, 13, 3434, {1, 3, 1, 13, 3, 25, 15, 27, 181, 967, 669, 2577, 7249}},
-{1006, 13, 3439, {1, 1, 7, 3, 31, 5, 103, 53, 1, 911, 1209, 3697, 6685}},
-{1007, 13, 3442, {1, 1, 3, 1, 5, 5, 49, 135, 281, 747, 761, 2973, 7963}},
-{1008, 13, 3444, {1, 3, 3, 5, 19, 61, 125, 199, 299, 515, 1365, 369, 7027}},
-{1009, 13, 3453, {1, 3, 1, 7, 5, 41, 63, 229, 283, 571, 147, 447, 657}},
-{1010, 13, 3464, {1, 3, 1, 11, 5, 15, 55, 7, 259, 61, 27, 1429, 5631}},
-{1011, 13, 3477, {1, 1, 5, 1, 3, 53, 51, 253, 155, 553, 1293, 3735, 6567}},
-{1012, 13, 3478, {1, 3, 5, 9, 5, 41, 21, 159, 101, 785, 1981, 3799, 7693}},
-{1013, 13, 3482, {1, 3, 7, 7, 9, 3, 95, 105, 129, 213, 1215, 1027, 5699}},
-{1014, 13, 3487, {1, 1, 3, 3, 29, 13, 9, 253, 449, 321, 341, 2879, 171}},
-{1015, 13, 3497, {1, 3, 7, 11, 21, 11, 75, 35, 43, 965, 675, 2217, 7175}},
-{1016, 13, 3500, {1, 1, 5, 15, 31, 5, 29, 137, 311, 751, 47, 1367, 5921}},
-{1017, 13, 3505, {1, 1, 3, 15, 17, 1, 45, 69, 55, 649, 835, 569, 7615}},
-{1018, 13, 3506, {1, 3, 1, 13, 31, 7, 23, 15, 391, 145, 1845, 1825, 1403}},
-{1019, 13, 3511, {1, 1, 3, 15, 5, 9, 79, 77, 105, 399, 1933, 2503, 4781}},
-{1020, 13, 3512, {1, 3, 1, 3, 17, 47, 19, 13, 107, 475, 759, 2933, 3761}},
-{1021, 13, 3515, {1, 1, 7, 11, 3, 7, 121, 209, 397, 877, 293, 847, 7039}},
-{1022, 13, 3525, {1, 1, 1, 15, 29, 45, 5, 109, 335, 461, 143, 931, 4045}},
-{1023, 13, 3532, {1, 3, 1, 7, 11, 57, 73, 89, 201, 173, 803, 3953, 5205}},
-{1024, 13, 3538, {1, 1, 5, 11, 11, 33, 37, 29, 263, 1019, 657, 1453, 7807}},
-{1025, 13, 3540, {1, 3, 3, 13, 31, 25, 37, 47, 261, 607, 1703, 2603, 417}},
-{1026, 13, 3547, {1, 1, 1, 1, 31, 61, 45, 115, 275, 239, 1989, 1897, 4329}},
-{1027, 13, 3549, {1, 3, 5, 3, 31, 3, 11, 173, 335, 579, 1193, 2219, 7875}},
-{1028, 13, 3560, {1, 1, 7, 9, 29, 45, 13, 67, 399, 177, 1293, 3865, 2225}},
-{1029, 13, 3571, {1, 1, 7, 11, 11, 51, 121, 227, 469, 905, 929, 2635, 4165}},
-{1030, 13, 3577, {1, 3, 7, 9, 13, 39, 55, 167, 23, 147, 1603, 2083, 4645}},
-{1031, 13, 3583, {1, 1, 3, 15, 27, 53, 11, 155, 157, 629, 259, 3009, 4605}},
-{1032, 13, 3590, {1, 3, 1, 7, 15, 47, 51, 1, 259, 603, 887, 2833, 6581}},
-{1033, 13, 3593, {1, 3, 5, 3, 1, 47, 91, 43, 361, 571, 29, 1453, 4269}},
-{1034, 13, 3594, {1, 1, 3, 9, 11, 51, 55, 23, 415, 277, 1423, 3475, 1527}},
-{1035, 13, 3599, {1, 1, 3, 11, 29, 49, 101, 75, 299, 709, 805, 4037, 4389}},
-{1036, 13, 3601, {1, 1, 7, 3, 23, 1, 37, 51, 379, 771, 1301, 3717, 6673}},
-{1037, 13, 3602, {1, 1, 5, 3, 23, 11, 125, 177, 375, 665, 951, 1577, 2603}},
-{1038, 13, 3613, {1, 1, 1, 1, 1, 5, 71, 255, 21, 459, 467, 2083, 5415}},
-{1039, 13, 3623, {1, 1, 5, 13, 23, 29, 109, 157, 363, 971, 549, 647, 1177}},
-{1040, 13, 3630, {1, 1, 3, 9, 7, 15, 101, 3, 365, 213, 745, 1155, 6099}},
-{1041, 13, 3638, {1, 3, 5, 15, 15, 19, 47, 179, 303, 521, 1279, 219, 2415}},
-{1042, 13, 3649, {1, 3, 3, 13, 27, 11, 83, 165, 369, 989, 261, 3933, 4809}},
-{1043, 13, 3655, {1, 1, 3, 11, 31, 59, 1, 185, 53, 703, 1471, 2935, 1107}},
-{1044, 13, 3662, {1, 3, 3, 7, 25, 3, 81, 27, 93, 521, 433, 2859, 5861}},
-{1045, 13, 3667, {1, 3, 3, 11, 29, 15, 49, 167, 315, 927, 543, 3473, 4307}},
-{1046, 13, 3669, {1, 3, 1, 3, 29, 33, 53, 15, 183, 691, 703, 1311, 3393}},
-{1047, 13, 3676, {1, 3, 5, 13, 23, 49, 3, 11, 1, 357, 1407, 415, 7211}},
-{1048, 13, 3683, {1, 3, 7, 15, 1, 25, 91, 113, 323, 371, 189, 925, 1181}},
-{1049, 13, 3700, {1, 3, 3, 3, 17, 59, 119, 199, 115, 223, 877, 2193, 193}},
-{1050, 13, 3709, {1, 1, 1, 5, 5, 35, 31, 59, 437, 411, 37, 2405, 3797}},
-{1051, 13, 3710, {1, 3, 1, 13, 9, 37, 1, 241, 59, 157, 1785, 1223, 563}},
-{1052, 13, 3713, {1, 3, 5, 13, 3, 21, 25, 95, 15, 745, 85, 701, 5361}},
-{1053, 13, 3723, {1, 3, 7, 1, 31, 33, 111, 195, 35, 913, 2013, 2951, 6611}},
-{1054, 13, 3725, {1, 3, 5, 1, 19, 3, 75, 119, 111, 409, 951, 1457, 4957}},
-{1055, 13, 3728, {1, 3, 1, 15, 19, 59, 3, 155, 237, 657, 1967, 3323, 6235}},
-{1056, 13, 3734, {1, 1, 5, 1, 3, 19, 45, 105, 377, 881, 167, 2255, 4483}},
-{1057, 13, 3737, {1, 1, 7, 7, 13, 13, 99, 89, 201, 279, 161, 2483, 6001}},
-{1058, 13, 3738, {1, 1, 7, 3, 13, 17, 97, 129, 137, 377, 1519, 183, 3725}},
-{1059, 13, 3744, {1, 1, 7, 9, 9, 5, 45, 135, 115, 181, 1685, 3505, 4387}},
-{1060, 13, 3750, {1, 1, 1, 1, 19, 35, 69, 113, 305, 419, 949, 2969, 247}},
-{1061, 13, 3762, {1, 1, 5, 13, 23, 61, 13, 139, 501, 811, 67, 1501, 6493}},
-{1062, 13, 3764, {1, 1, 3, 13, 15, 41, 27, 217, 293, 13, 145, 2631, 6991}},
-{1063, 13, 3774, {1, 3, 3, 13, 15, 37, 71, 123, 285, 49, 627, 1283, 5993}},
-{1064, 13, 3776, {1, 3, 3, 11, 9, 25, 11, 1, 203, 353, 1347, 1999, 2799}},
-{1065, 13, 3786, {1, 3, 5, 1, 7, 49, 101, 231, 499, 63, 1977, 2207, 7829}},
-{1066, 13, 3800, {1, 1, 7, 1, 17, 15, 115, 139, 381, 943, 623, 4037, 2971}},
-{1067, 13, 3803, {1, 1, 3, 5, 13, 55, 23, 87, 139, 795, 1669, 1375, 1185}},
-{1068, 13, 3809, {1, 3, 3, 5, 5, 45, 97, 253, 241, 333, 645, 555, 7867}},
-{1069, 13, 3816, {1, 3, 5, 1, 1, 1, 89, 27, 407, 509, 1433, 609, 2355}},
-{1070, 13, 3821, {1, 3, 7, 1, 27, 29, 5, 157, 495, 811, 1293, 1143, 827}},
-{1071, 13, 3827, {1, 1, 3, 3, 25, 49, 127, 111, 191, 3, 845, 1383, 2521}},
-{1072, 13, 3829, {1, 1, 5, 7, 5, 51, 101, 155, 237, 461, 831, 3091, 3851}},
-{1073, 13, 3836, {1, 3, 7, 1, 29, 35, 105, 91, 285, 705, 131, 395, 6011}},
-{1074, 13, 3842, {1, 3, 5, 3, 13, 21, 83, 173, 221, 827, 1775, 1931, 6727}},
-{1075, 13, 3844, {1, 1, 3, 5, 3, 25, 95, 115, 205, 569, 1447, 933, 6425}},
-{1076, 13, 3847, {1, 1, 7, 9, 31, 3, 17, 175, 145, 447, 1321, 1069, 6527}},
-{1077, 13, 3853, {1, 1, 3, 3, 23, 1, 79, 51, 421, 419, 873, 3939, 1801}},
-{1078, 13, 3861, {1, 1, 5, 1, 3, 39, 15, 85, 169, 669, 919, 397, 5579}},
-{1079, 13, 3871, {1, 3, 5, 1, 21, 61, 87, 217, 251, 619, 1091, 4009, 229}},
-{1080, 13, 3872, {1, 1, 1, 11, 23, 55, 85, 121, 363, 867, 315, 447, 3373}},
-{1081, 13, 3881, {1, 3, 3, 13, 29, 19, 89, 85, 137, 469, 1873, 2765, 3975}},
-{1082, 13, 3890, {1, 3, 7, 13, 19, 63, 61, 77, 67, 361, 11, 1787, 4703}},
-{1083, 13, 3892, {1, 1, 3, 11, 7, 15, 127, 105, 179, 857, 1671, 3647, 3389}},
-{1084, 13, 3909, {1, 1, 1, 7, 19, 21, 99, 161, 499, 519, 1287, 2973, 479}},
-{1085, 13, 3921, {1, 1, 3, 13, 29, 51, 95, 251, 55, 519, 1955, 2881, 5951}},
-{1086, 13, 3934, {1, 1, 3, 11, 23, 63, 121, 237, 175, 311, 701, 1539, 2383}},
-{1087, 13, 3938, {1, 1, 7, 5, 5, 45, 73, 97, 5, 153, 715, 2037, 3353}},
-{1088, 13, 3947, {1, 1, 1, 3, 13, 7, 67, 173, 425, 843, 1497, 2729, 5193}},
-{1089, 13, 3950, {1, 1, 7, 1, 23, 3, 119, 11, 77, 141, 1905, 2269, 4269}},
-{1090, 13, 3952, {1, 1, 7, 15, 1, 23, 79, 251, 439, 603, 405, 2449, 6383}},
-{1091, 13, 3964, {1, 3, 7, 11, 29, 27, 47, 255, 47, 661, 1967, 1007, 3689}},
-{1092, 13, 3974, {1, 3, 7, 5, 19, 39, 35, 115, 417, 373, 291, 329, 603}},
-{1093, 13, 3980, {1, 3, 1, 9, 11, 33, 27, 193, 207, 423, 1311, 1369, 7307}},
-{1094, 13, 3983, {1, 1, 3, 11, 9, 29, 83, 17, 497, 493, 329, 3141, 5935}},
-{1095, 13, 3986, {1, 3, 1, 5, 31, 51, 29, 171, 51, 493, 1621, 3501, 4091}},
-{1096, 13, 3995, {1, 1, 5, 9, 21, 43, 105, 207, 245, 363, 1191, 699, 1139}},
-{1097, 13, 3998, {1, 1, 3, 11, 19, 5, 81, 119, 247, 169, 1337, 45, 6565}},
-{1098, 13, 4001, {1, 3, 1, 11, 3, 51, 3, 101, 159, 11, 253, 299, 5043}},
-{1099, 13, 4002, {1, 3, 1, 5, 11, 53, 85, 39, 57, 645, 2007, 1039, 3627}},
-{1100, 13, 4004, {1, 3, 5, 3, 17, 61, 97, 165, 415, 357, 283, 601, 5505}},
-{1101, 13, 4008, {1, 3, 7, 3, 9, 51, 49, 85, 3, 227, 137, 309, 243}},
-{1102, 13, 4011, {1, 1, 5, 3, 11, 59, 11, 131, 409, 703, 455, 123, 6727}},
-{1103, 13, 4016, {1, 3, 7, 9, 25, 49, 21, 171, 287, 379, 667, 313, 713}},
-{1104, 13, 4033, {1, 1, 3, 9, 7, 35, 47, 3, 367, 581, 1627, 1665, 3905}},
-{1105, 13, 4036, {1, 3, 1, 1, 29, 57, 35, 55, 255, 653, 823, 2197, 6179}},
-{1106, 13, 4040, {1, 3, 7, 15, 17, 15, 117, 83, 359, 163, 115, 2999, 5373}},
-{1107, 13, 4053, {1, 1, 5, 3, 21, 61, 35, 97, 71, 687, 207, 2917, 1049}},
-{1108, 13, 4058, {1, 1, 1, 15, 13, 15, 125, 81, 263, 661, 417, 3243, 1669}},
-{1109, 13, 4081, {1, 1, 7, 3, 3, 19, 111, 193, 443, 339, 659, 1211, 1557}},
-{1110, 13, 4091, {1, 3, 1, 3, 27, 3, 3, 173, 391, 213, 803, 3281, 3207}},
-{1111, 13, 4094, {1, 1, 5, 15, 19, 1, 7, 211, 157, 603, 403, 1387, 1583}},
-{1112, 14, 21, {1, 3, 5, 13, 17, 53, 125, 13, 339, 723, 521, 413, 5801, 10451}},
-{1113, 14, 28, {1, 1, 3, 13, 29, 9, 99, 77, 141, 609, 1533, 983, 2039, 51}},
-{1114, 14, 41, {1, 1, 3, 11, 21, 55, 5, 51, 423, 309, 525, 3715, 3025, 15055}},
-{1115, 14, 47, {1, 1, 3, 7, 9, 21, 77, 171, 239, 341, 1653, 1093, 2273, 10723}},
-{1116, 14, 61, {1, 1, 1, 15, 31, 15, 23, 35, 317, 869, 1917, 1415, 4313, 3687}},
-{1117, 14, 84, {1, 1, 1, 5, 21, 25, 99, 167, 439, 453, 473, 431, 6665, 4989}},
-{1118, 14, 87, {1, 1, 7, 9, 31, 47, 81, 83, 345, 43, 1363, 1885, 3155, 3185}},
-{1119, 14, 93, {1, 3, 7, 1, 31, 17, 61, 185, 341, 129, 547, 717, 2071, 9991}},
-{1120, 14, 94, {1, 3, 1, 13, 23, 61, 77, 217, 455, 77, 1263, 1601, 3501, 14953}},
-{1121, 14, 103, {1, 1, 7, 7, 19, 19, 1, 229, 431, 943, 1069, 1949, 1289, 15729}},
-{1122, 14, 117, {1, 1, 3, 5, 1, 35, 97, 251, 487, 459, 1265, 1739, 165, 10365}},
-{1123, 14, 121, {1, 3, 5, 3, 11, 25, 79, 175, 383, 545, 187, 197, 4329, 3363}},
-{1124, 14, 134, {1, 1, 3, 3, 29, 9, 63, 55, 175, 277, 431, 2549, 2629, 6409}},
-{1125, 14, 137, {1, 1, 3, 15, 17, 21, 79, 139, 99, 135, 1763, 1805, 3471, 5439}},
-{1126, 14, 157, {1, 1, 3, 9, 9, 15, 35, 119, 289, 835, 769, 3843, 4119, 4421}},
-{1127, 14, 161, {1, 1, 1, 5, 19, 19, 67, 199, 307, 815, 1367, 1231, 3927, 6593}},
-{1128, 14, 205, {1, 1, 3, 1, 29, 51, 121, 209, 431, 47, 1115, 907, 2535, 9755}},
-{1129, 14, 206, {1, 1, 3, 5, 17, 1, 5, 119, 121, 223, 1719, 1291, 3947, 15891}},
-{1130, 14, 211, {1, 3, 1, 15, 29, 25, 3, 131, 373, 307, 645, 3513, 1289, 1987}},
-{1131, 14, 214, {1, 3, 3, 11, 29, 45, 105, 179, 331, 465, 891, 1315, 403, 3057}},
-{1132, 14, 218, {1, 1, 5, 13, 17, 59, 77, 127, 485, 855, 1147, 3093, 891, 9869}},
-{1133, 14, 234, {1, 1, 1, 7, 23, 27, 31, 203, 285, 463, 827, 685, 1349, 15051}},
-{1134, 14, 236, {1, 1, 1, 5, 29, 5, 107, 195, 31, 425, 19, 2865, 3869, 11153}},
-{1135, 14, 248, {1, 1, 7, 5, 7, 47, 1, 73, 307, 347, 393, 2205, 7709, 15121}},
-{1136, 14, 262, {1, 1, 1, 13, 15, 61, 25, 131, 113, 369, 1995, 2527, 4475, 1745}},
-{1137, 14, 299, {1, 1, 1, 1, 31, 63, 21, 253, 307, 281, 859, 3319, 6721, 2891}},
-{1138, 14, 304, {1, 1, 3, 11, 1, 17, 5, 183, 301, 979, 651, 1685, 6343, 10067}},
-{1139, 14, 319, {1, 1, 5, 15, 23, 45, 99, 145, 263, 507, 1381, 3425, 2215, 1815}},
-{1140, 14, 322, {1, 3, 1, 5, 11, 63, 85, 203, 411, 881, 1369, 1237, 4657, 6541}},
-{1141, 14, 334, {1, 3, 3, 13, 17, 53, 121, 201, 269, 983, 215, 3187, 7121, 6111}},
-{1142, 14, 355, {1, 3, 5, 15, 15, 5, 13, 143, 3, 313, 1677, 1093, 3295, 3387}},
-{1143, 14, 357, {1, 1, 3, 13, 3, 23, 73, 17, 257, 965, 239, 1271, 2803, 7327}},
-{1144, 14, 358, {1, 3, 5, 13, 9, 57, 115, 37, 41, 467, 135, 1403, 3811, 4741}},
-{1145, 14, 369, {1, 3, 7, 15, 9, 33, 39, 203, 351, 367, 1355, 1403, 3685, 4757}},
-{1146, 14, 372, {1, 3, 5, 11, 31, 3, 113, 123, 203, 421, 1821, 3151, 2375, 4419}},
-{1147, 14, 375, {1, 1, 1, 7, 21, 63, 99, 23, 133, 79, 991, 1755, 4989, 4709}},
-{1148, 14, 388, {1, 3, 5, 1, 25, 63, 113, 239, 49, 443, 173, 1261, 3201, 10599}},
-{1149, 14, 400, {1, 3, 3, 13, 3, 25, 101, 169, 23, 585, 327, 1327, 111, 10059}},
-{1150, 14, 415, {1, 3, 3, 5, 19, 1, 33, 89, 437, 213, 1933, 1741, 2603, 5625}},
-{1151, 14, 446, {1, 3, 1, 3, 15, 15, 25, 139, 73, 335, 237, 2461, 3101, 14951}},
-{1152, 14, 451, {1, 3, 5, 1, 31, 15, 31, 187, 177, 659, 1339, 3767, 4975, 7123}},
-{1153, 14, 458, {1, 3, 1, 3, 25, 19, 47, 89, 107, 107, 649, 683, 3123, 11085}},
-{1154, 14, 471, {1, 3, 7, 9, 15, 21, 101, 25, 11, 625, 1555, 675, 3893, 5805}},
-{1155, 14, 484, {1, 1, 1, 5, 7, 49, 123, 21, 439, 369, 207, 535, 4619, 14665}},
-{1156, 14, 501, {1, 1, 5, 7, 1, 25, 103, 185, 99, 239, 1093, 1561, 6177, 4039}},
-{1157, 14, 502, {1, 3, 7, 5, 29, 21, 43, 103, 343, 973, 1561, 2975, 7467, 7947}},
-{1158, 14, 517, {1, 1, 7, 9, 19, 3, 13, 23, 461, 813, 1191, 985, 559, 3317}},
-{1159, 14, 545, {1, 3, 5, 5, 27, 31, 79, 15, 365, 901, 1949, 117, 3619, 13311}},
-{1160, 14, 569, {1, 3, 5, 7, 5, 33, 67, 199, 425, 189, 1691, 3099, 815, 1677}},
-{1161, 14, 617, {1, 1, 7, 11, 13, 29, 73, 137, 265, 601, 445, 3893, 2511, 8047}},
-{1162, 14, 618, {1, 1, 3, 1, 13, 5, 57, 101, 357, 391, 335, 601, 1359, 1065}},
-{1163, 14, 623, {1, 1, 1, 1, 25, 57, 27, 115, 31, 873, 611, 2125, 447, 13585}},
-{1164, 14, 625, {1, 3, 3, 13, 27, 17, 73, 11, 359, 33, 1153, 271, 4537, 15141}},
-{1165, 14, 637, {1, 3, 7, 3, 11, 63, 103, 61, 59, 629, 1629, 3279, 3919, 3177}},
-{1166, 14, 661, {1, 1, 5, 15, 3, 63, 85, 193, 381, 165, 175, 3247, 2501, 4209}},
-{1167, 14, 668, {1, 1, 5, 15, 1, 33, 59, 219, 487, 193, 1557, 703, 2907, 7953}},
-{1168, 14, 684, {1, 1, 7, 3, 9, 3, 105, 95, 389, 991, 21, 3841, 6983, 285}},
-{1169, 14, 695, {1, 1, 1, 1, 1, 31, 25, 137, 117, 67, 1283, 1963, 6591, 15541}},
-{1170, 14, 716, {1, 3, 5, 11, 7, 15, 127, 89, 453, 777, 1827, 2311, 7661, 11833}},
-{1171, 14, 719, {1, 1, 7, 13, 19, 29, 79, 165, 223, 453, 2039, 3961, 6467, 5481}},
-{1172, 14, 722, {1, 3, 3, 7, 17, 41, 43, 157, 323, 3, 1001, 2109, 4513, 12127}},
-{1173, 14, 731, {1, 1, 5, 9, 31, 57, 3, 217, 113, 271, 1663, 1367, 6949, 8165}},
-{1174, 14, 738, {1, 1, 7, 15, 27, 35, 81, 235, 61, 205, 525, 311, 6357, 2527}},
-{1175, 14, 747, {1, 3, 1, 9, 19, 29, 71, 207, 321, 1011, 1615, 1333, 3459, 6681}},
-{1176, 14, 755, {1, 3, 7, 7, 3, 57, 41, 19, 25, 397, 565, 1837, 7625, 11813}},
-{1177, 14, 761, {1, 3, 3, 1, 27, 47, 31, 79, 441, 961, 1255, 423, 2405, 913}},
-{1178, 14, 767, {1, 3, 3, 13, 3, 29, 69, 227, 85, 201, 395, 3199, 3869, 13099}},
-{1179, 14, 775, {1, 3, 3, 7, 29, 61, 99, 7, 27, 227, 945, 873, 475, 4363}},
-{1180, 14, 782, {1, 3, 5, 13, 19, 21, 57, 149, 217, 443, 565, 453, 5487, 10981}},
-{1181, 14, 787, {1, 3, 3, 1, 9, 27, 47, 191, 35, 395, 1429, 4079, 6871, 8013}},
-{1182, 14, 794, {1, 3, 5, 15, 5, 43, 9, 79, 279, 563, 1125, 985, 8117, 4099}},
-{1183, 14, 803, {1, 3, 5, 1, 13, 41, 21, 117, 287, 667, 701, 1483, 8167, 13283}},
-{1184, 14, 812, {1, 3, 1, 3, 15, 15, 59, 5, 383, 509, 1657, 3977, 7697, 10941}},
-{1185, 14, 817, {1, 3, 1, 1, 17, 29, 19, 23, 377, 45, 981, 1631, 3557, 6749}},
-{1186, 14, 824, {1, 3, 3, 9, 9, 51, 9, 193, 345, 361, 1679, 3333, 713, 5387}},
-{1187, 14, 829, {1, 3, 5, 5, 17, 45, 97, 17, 385, 349, 105, 2245, 7295, 14393}},
-{1188, 14, 850, {1, 3, 7, 3, 19, 51, 35, 99, 79, 301, 1563, 399, 5879, 14675}},
-{1189, 14, 866, {1, 1, 7, 15, 13, 53, 55, 203, 417, 161, 2033, 1845, 6763, 3585}},
-{1190, 14, 871, {1, 1, 3, 3, 7, 23, 11, 43, 241, 309, 1453, 3147, 2619, 3163}},
-{1191, 14, 877, {1, 1, 1, 11, 17, 1, 17, 137, 443, 465, 993, 3217, 7879, 14607}},
-{1192, 14, 920, {1, 1, 7, 13, 29, 49, 71, 217, 291, 793, 135, 21, 2503, 11091}},
-{1193, 14, 935, {1, 3, 1, 11, 31, 51, 121, 227, 377, 157, 1457, 1317, 5625, 6217}},
-{1194, 14, 959, {1, 1, 3, 7, 23, 61, 47, 93, 79, 617, 1805, 2403, 5513, 16335}},
-{1195, 14, 979, {1, 3, 5, 11, 23, 25, 41, 11, 495, 587, 1223, 3107, 1469, 15223}},
-{1196, 14, 992, {1, 3, 7, 7, 9, 1, 1, 49, 23, 723, 1761, 3717, 7375, 10875}},
-{1197, 14, 1010, {1, 3, 3, 11, 25, 37, 57, 63, 309, 603, 183, 285, 1663, 5627}},
-{1198, 14, 1012, {1, 3, 7, 11, 19, 25, 25, 201, 391, 257, 529, 1645, 1, 15111}},
-{1199, 14, 1015, {1, 3, 3, 9, 11, 43, 91, 65, 5, 959, 301, 1015, 6343, 3453}},
-{1200, 14, 1033, {1, 3, 3, 11, 17, 17, 103, 37, 77, 973, 575, 439, 49, 3639}},
-{1201, 14, 1036, {1, 1, 5, 7, 1, 15, 107, 237, 231, 967, 923, 1101, 6715, 1713}},
-{1202, 14, 1053, {1, 3, 1, 15, 9, 33, 29, 211, 245, 601, 1783, 887, 1209, 11785}},
-{1203, 14, 1057, {1, 3, 3, 7, 21, 43, 27, 89, 27, 141, 865, 367, 1379, 4063}},
-{1204, 14, 1069, {1, 3, 7, 7, 15, 17, 15, 15, 131, 649, 1955, 3289, 3983, 10689}},
-{1205, 14, 1072, {1, 3, 1, 5, 17, 7, 125, 69, 359, 981, 1345, 933, 5281, 7113}},
-{1206, 14, 1075, {1, 1, 5, 9, 17, 7, 41, 207, 497, 1015, 493, 891, 3563, 3541}},
-{1207, 14, 1087, {1, 3, 5, 11, 27, 3, 47, 31, 303, 1007, 2047, 2203, 6257, 8369}},
-{1208, 14, 1089, {1, 1, 1, 15, 25, 15, 89, 51, 217, 357, 1133, 1917, 213, 3365}},
-{1209, 14, 1137, {1, 1, 5, 13, 29, 23, 123, 207, 429, 805, 819, 2357, 6313, 11019}},
-{1210, 14, 1166, {1, 1, 3, 7, 19, 15, 41, 73, 279, 11, 1089, 3107, 7737, 15953}},
-{1211, 14, 1174, {1, 3, 5, 7, 7, 15, 41, 73, 493, 457, 1731, 1139, 2513, 12373}},
-{1212, 14, 1180, {1, 3, 5, 9, 17, 5, 55, 155, 173, 1005, 529, 3175, 7667, 4747}},
-{1213, 14, 1204, {1, 1, 7, 7, 5, 21, 105, 31, 205, 847, 1033, 3167, 2347, 8499}},
-{1214, 14, 1211, {1, 3, 5, 3, 11, 17, 59, 189, 179, 1007, 33, 3287, 4813, 8177}},
-{1215, 14, 1219, {1, 3, 3, 13, 27, 47, 47, 171, 413, 875, 1081, 1259, 7139, 8645}},
-{1216, 14, 1236, {1, 3, 5, 7, 25, 21, 51, 29, 361, 293, 51, 1119, 1453, 5283}},
-{1217, 14, 1255, {1, 3, 7, 7, 29, 55, 103, 199, 511, 341, 1957, 3987, 2855, 1279}},
-{1218, 14, 1264, {1, 1, 1, 9, 23, 51, 61, 63, 391, 37, 55, 3771, 6517, 15913}},
-{1219, 14, 1306, {1, 1, 1, 9, 3, 19, 13, 147, 453, 855, 1321, 189, 5043, 11215}},
-{1220, 14, 1330, {1, 3, 3, 13, 23, 3, 87, 155, 401, 981, 607, 3413, 995, 6473}},
-{1221, 14, 1341, {1, 3, 1, 9, 29, 47, 95, 123, 421, 353, 1867, 2609, 2569, 14083}},
-{1222, 14, 1344, {1, 1, 5, 13, 25, 39, 29, 111, 125, 545, 1493, 2371, 6361, 6307}},
-{1223, 14, 1347, {1, 3, 3, 11, 13, 31, 87, 75, 27, 393, 921, 3655, 3343, 16349}},
-{1224, 14, 1349, {1, 1, 5, 9, 19, 19, 7, 129, 223, 715, 433, 1627, 4463, 2951}},
-{1225, 14, 1361, {1, 1, 7, 1, 31, 13, 49, 33, 89, 43, 1529, 725, 3809, 3427}},
-{1226, 14, 1380, {1, 1, 7, 3, 1, 27, 45, 9, 309, 875, 659, 2661, 553, 7069}},
-{1227, 14, 1390, {1, 1, 7, 15, 13, 37, 61, 19, 125, 683, 1227, 2255, 1455, 9339}},
-{1228, 14, 1404, {1, 3, 5, 7, 19, 7, 71, 21, 465, 645, 1885, 873, 7405, 1913}},
-{1229, 14, 1435, {1, 3, 1, 11, 11, 35, 79, 61, 79, 57, 1603, 3719, 6323, 16371}},
-{1230, 14, 1444, {1, 1, 7, 1, 29, 57, 85, 21, 205, 37, 2045, 683, 4901, 8223}},
-{1231, 14, 1453, {1, 1, 5, 13, 31, 31, 65, 131, 259, 535, 967, 3943, 2605, 2089}},
-{1232, 14, 1461, {1, 1, 7, 9, 27, 61, 39, 243, 207, 41, 1909, 3279, 1331, 4635}},
-{1233, 14, 1462, {1, 3, 3, 5, 11, 63, 105, 19, 169, 95, 773, 3175, 1869, 1797}},
-{1234, 14, 1465, {1, 3, 3, 15, 13, 33, 107, 197, 153, 795, 1477, 105, 4965, 991}},
-{1235, 14, 1468, {1, 3, 7, 11, 11, 37, 23, 149, 197, 3, 1035, 3857, 553, 1059}},
-{1236, 14, 1474, {1, 3, 1, 3, 17, 29, 89, 189, 193, 59, 1477, 3517, 2565, 7739}},
-{1237, 14, 1483, {1, 1, 1, 9, 23, 3, 25, 163, 469, 305, 1791, 3393, 6141, 8119}},
-{1238, 14, 1488, {1, 3, 5, 7, 7, 41, 19, 101, 179, 487, 1071, 2761, 8043, 5103}},
-{1239, 14, 1493, {1, 1, 7, 9, 1, 21, 101, 103, 349, 85, 1841, 1033, 4473, 3563}},
-{1240, 14, 1500, {1, 1, 3, 13, 23, 61, 39, 27, 479, 13, 45, 1371, 7897, 10637}},
-{1241, 14, 1509, {1, 1, 5, 9, 17, 61, 71, 55, 355, 99, 1695, 3053, 839, 959}},
-{1242, 14, 1510, {1, 1, 3, 1, 7, 27, 87, 221, 327, 241, 461, 3177, 5933, 8299}},
-{1243, 14, 1514, {1, 3, 7, 9, 5, 41, 111, 245, 447, 263, 1363, 1767, 6331, 3355}},
-{1244, 14, 1519, {1, 3, 3, 13, 15, 11, 15, 169, 429, 149, 1965, 2477, 7733, 2499}},
-{1245, 14, 1528, {1, 1, 5, 15, 15, 47, 25, 33, 469, 701, 773, 2747, 1533, 14633}},
-{1246, 14, 1533, {1, 3, 1, 5, 19, 57, 37, 75, 423, 11, 685, 2487, 1779, 8797}},
-{1247, 14, 1540, {1, 3, 1, 5, 19, 41, 67, 99, 333, 991, 953, 3221, 939, 4197}},
-{1248, 14, 1550, {1, 3, 1, 15, 11, 39, 25, 1, 159, 679, 465, 1611, 5799, 2537}},
-{1249, 14, 1567, {1, 1, 5, 11, 5, 37, 37, 7, 101, 703, 235, 23, 2209, 12799}},
-{1250, 14, 1571, {1, 1, 7, 3, 11, 23, 71, 215, 45, 269, 1539, 3625, 5773, 6889}},
-{1251, 14, 1573, {1, 3, 5, 15, 27, 33, 105, 109, 205, 653, 821, 435, 1087, 2495}},
-{1252, 14, 1578, {1, 1, 3, 5, 11, 39, 53, 213, 41, 385, 1425, 25, 5553, 12523}},
-{1253, 14, 1598, {1, 3, 5, 15, 29, 49, 13, 253, 505, 407, 985, 2569, 6727, 4761}},
-{1254, 14, 1606, {1, 1, 1, 3, 29, 17, 69, 47, 25, 819, 1145, 2479, 1183, 3343}},
-{1255, 14, 1618, {1, 3, 1, 15, 25, 61, 43, 55, 279, 579, 361, 355, 6101, 3143}},
-{1256, 14, 1630, {1, 3, 5, 11, 3, 59, 125, 101, 451, 495, 1711, 3443, 3625, 15579}},
-{1257, 14, 1634, {1, 3, 1, 11, 25, 61, 49, 219, 23, 795, 481, 3609, 3691, 15419}},
-{1258, 14, 1640, {1, 3, 7, 5, 9, 59, 49, 233, 345, 143, 181, 3587, 3041, 1219}},
-{1259, 14, 1643, {1, 3, 7, 13, 9, 31, 39, 137, 261, 919, 1367, 3145, 4659, 5875}},
-{1260, 14, 1654, {1, 1, 3, 3, 27, 43, 95, 65, 301, 915, 31, 451, 7743, 7277}},
-{1261, 14, 1679, {1, 3, 1, 5, 23, 37, 53, 31, 203, 453, 71, 1585, 6011, 16369}},
-{1262, 14, 1688, {1, 1, 5, 1, 15, 47, 91, 227, 297, 45, 1415, 3647, 7811, 14015}},
-{1263, 14, 1698, {1, 1, 1, 1, 29, 27, 93, 121, 169, 69, 1361, 2907, 1867, 7017}},
-{1264, 14, 1703, {1, 3, 1, 7, 23, 53, 77, 41, 25, 873, 1333, 3889, 3239, 1771}},
-{1265, 14, 1704, {1, 1, 1, 7, 31, 27, 87, 81, 167, 343, 1981, 2499, 7749, 15747}},
-{1266, 14, 1722, {1, 3, 5, 13, 1, 17, 97, 37, 81, 645, 1167, 3547, 7769, 10731}},
-{1267, 14, 1735, {1, 1, 7, 5, 9, 17, 31, 55, 151, 463, 1041, 2303, 4015, 3737}},
-{1268, 14, 1750, {1, 1, 3, 11, 31, 9, 81, 213, 95, 215, 2031, 2129, 4299, 3021}},
-{1269, 14, 1753, {1, 1, 1, 3, 25, 25, 115, 229, 101, 441, 783, 1729, 7905, 2375}},
-{1270, 14, 1760, {1, 1, 5, 9, 3, 19, 73, 35, 379, 493, 1333, 1647, 13, 197}},
-{1271, 14, 1789, {1, 1, 7, 9, 3, 55, 99, 43, 281, 9, 73, 2477, 8183, 11055}},
-{1272, 14, 1792, {1, 3, 7, 13, 25, 19, 27, 195, 469, 175, 355, 1861, 7255, 15377}},
-{1273, 14, 1802, {1, 1, 3, 11, 15, 19, 115, 31, 413, 835, 697, 879, 6515, 13465}},
-{1274, 14, 1819, {1, 3, 3, 15, 3, 61, 105, 201, 151, 739, 49, 3963, 2573, 3303}},
-{1275, 14, 1825, {1, 3, 5, 7, 23, 5, 11, 215, 19, 591, 509, 2887, 1631, 4391}},
-{1276, 14, 1828, {1, 3, 3, 3, 25, 1, 109, 5, 363, 545, 1745, 503, 827, 4677}},
-{1277, 14, 1832, {1, 1, 3, 15, 1, 45, 121, 141, 497, 745, 1825, 2041, 2561, 8153}},
-{1278, 14, 1845, {1, 3, 1, 11, 29, 7, 71, 241, 7, 39, 1379, 2479, 7483, 7195}},
-{1279, 14, 1846, {1, 1, 7, 11, 3, 27, 39, 97, 339, 217, 1409, 1569, 4761, 1567}},
-{1280, 14, 1857, {1, 1, 5, 15, 11, 53, 87, 213, 297, 923, 393, 717, 3297, 16123}},
-{1281, 14, 1869, {1, 1, 1, 11, 27, 41, 121, 49, 225, 379, 1305, 319, 2461, 5445}},
-{1282, 14, 1897, {1, 1, 5, 5, 25, 3, 121, 23, 47, 843, 1679, 1427, 6393, 4199}},
-{1283, 14, 1906, {1, 1, 5, 13, 17, 3, 17, 25, 161, 487, 121, 361, 1375, 10745}},
-{1284, 14, 1908, {1, 1, 7, 3, 3, 37, 7, 245, 107, 107, 745, 2415, 2131, 11419}},
-{1285, 14, 1911, {1, 1, 5, 3, 3, 23, 67, 91, 281, 387, 465, 905, 883, 9775}},
-{1286, 14, 1934, {1, 3, 7, 15, 25, 55, 123, 49, 23, 983, 1903, 2589, 2073, 7823}},
-{1287, 14, 1962, {1, 1, 5, 11, 25, 17, 63, 229, 267, 175, 1759, 1947, 479, 11089}},
-{1288, 14, 1967, {1, 3, 7, 3, 11, 37, 83, 95, 415, 1003, 1175, 2361, 2117, 9809}},
-{1289, 14, 1972, {1, 3, 1, 9, 5, 39, 51, 129, 249, 161, 1981, 2755, 8057, 13641}},
-{1290, 14, 1975, {1, 1, 7, 1, 15, 47, 9, 197, 199, 549, 1091, 2853, 2331, 4535}},
-{1291, 14, 1999, {1, 3, 3, 13, 15, 21, 23, 111, 463, 719, 1667, 377, 5039, 10723}},
-{1292, 14, 2004, {1, 1, 3, 7, 23, 47, 39, 47, 307, 949, 1651, 2525, 5835, 1425}},
-{1293, 14, 2011, {1, 3, 3, 9, 23, 47, 111, 39, 251, 1001, 179, 3985, 535, 15435}},
-{1294, 14, 2013, {1, 1, 3, 13, 5, 45, 51, 123, 205, 651, 1583, 1691, 1631, 11975}},
-{1295, 14, 2037, {1, 1, 7, 9, 1, 29, 59, 27, 389, 497, 1459, 1633, 521, 14037}},
-{1296, 14, 2051, {1, 1, 3, 3, 3, 23, 35, 247, 371, 729, 931, 681, 1777, 8353}},
-{1297, 14, 2063, {1, 3, 3, 1, 19, 15, 17, 191, 495, 643, 319, 37, 5691, 7049}},
-{1298, 14, 2066, {1, 3, 5, 11, 5, 31, 123, 243, 335, 573, 113, 209, 4825, 7783}},
-{1299, 14, 2094, {1, 3, 7, 7, 29, 19, 25, 191, 89, 515, 55, 3013, 4523, 12913}},
-{1300, 14, 2128, {1, 1, 3, 3, 15, 3, 35, 37, 339, 7, 697, 359, 4553, 1431}},
-{1301, 14, 2154, {1, 3, 1, 1, 9, 15, 33, 77, 161, 13, 255, 1187, 6587, 11715}},
-{1302, 14, 2164, {1, 3, 7, 7, 25, 57, 61, 171, 231, 43, 1219, 903, 5623, 4781}},
-{1303, 14, 2198, {1, 1, 5, 15, 29, 47, 117, 23, 213, 907, 1423, 369, 4529, 9651}},
-{1304, 14, 2217, {1, 1, 5, 7, 15, 55, 105, 249, 401, 37, 1885, 3779, 3441, 9057}},
-{1305, 14, 2220, {1, 1, 5, 3, 3, 27, 49, 89, 335, 561, 1235, 3251, 2731, 12711}},
-{1306, 14, 2223, {1, 1, 1, 15, 29, 49, 37, 173, 25, 743, 1321, 821, 5899, 9213}},
-{1307, 14, 2238, {1, 1, 7, 3, 1, 41, 61, 209, 275, 925, 521, 3029, 1569, 9277}},
-{1308, 14, 2245, {1, 3, 5, 13, 17, 1, 11, 171, 441, 119, 1589, 299, 157, 11439}},
-{1309, 14, 2252, {1, 1, 5, 9, 13, 33, 27, 77, 363, 939, 1103, 2135, 1759, 5429}},
-{1310, 14, 2258, {1, 3, 7, 1, 17, 39, 49, 201, 49, 803, 2003, 1193, 7415, 13847}},
-{1311, 14, 2264, {1, 1, 5, 5, 17, 49, 39, 19, 311, 801, 1441, 3263, 7973, 14181}},
-{1312, 14, 2280, {1, 1, 3, 9, 9, 27, 59, 89, 81, 473, 1369, 3121, 7929, 10905}},
-{1313, 14, 2285, {1, 3, 3, 5, 17, 35, 35, 239, 379, 431, 501, 3561, 2059, 9679}},
-{1314, 14, 2293, {1, 3, 5, 15, 25, 29, 113, 179, 269, 891, 301, 2017, 7513, 9379}},
-{1315, 14, 2294, {1, 3, 1, 11, 17, 35, 49, 149, 135, 661, 1691, 3169, 3765, 9003}},
-{1316, 14, 2298, {1, 3, 7, 15, 5, 21, 53, 241, 475, 271, 683, 2351, 2181, 6333}},
-{1317, 14, 2303, {1, 1, 7, 13, 25, 33, 71, 153, 221, 507, 2017, 2401, 7545, 8489}},
-{1318, 14, 2306, {1, 1, 7, 5, 1, 49, 87, 1, 179, 331, 1597, 3713, 809, 11109}},
-{1319, 14, 2311, {1, 3, 1, 5, 5, 61, 93, 39, 479, 977, 1099, 1291, 7049, 2797}},
-{1320, 14, 2326, {1, 3, 1, 13, 19, 41, 57, 77, 5, 117, 125, 115, 3969, 1345}},
-{1321, 14, 2354, {1, 1, 1, 9, 15, 9, 57, 7, 219, 41, 767, 23, 5771, 14175}},
-{1322, 14, 2373, {1, 3, 7, 9, 17, 61, 1, 59, 227, 349, 63, 189, 3871, 7919}},
-{1323, 14, 2380, {1, 3, 5, 5, 9, 29, 33, 203, 413, 701, 1129, 2103, 1889, 8377}},
-{1324, 14, 2385, {1, 1, 3, 1, 9, 17, 69, 115, 123, 1001, 1, 2893, 3957, 8593}},
-{1325, 14, 2392, {1, 1, 3, 1, 31, 41, 83, 91, 113, 195, 1121, 2665, 6815, 1189}},
-{1326, 14, 2401, {1, 1, 1, 13, 3, 59, 13, 123, 95, 103, 1689, 2809, 5049, 4055}},
-{1327, 14, 2402, {1, 1, 1, 15, 21, 41, 11, 167, 375, 589, 207, 1631, 1597, 8091}},
-{1328, 14, 2408, {1, 3, 5, 5, 1, 33, 57, 89, 157, 921, 1353, 2777, 461, 14567}},
-{1329, 14, 2419, {1, 1, 5, 1, 25, 5, 51, 247, 1, 577, 463, 3741, 303, 16059}},
-{1330, 14, 2450, {1, 1, 7, 5, 13, 7, 17, 87, 51, 987, 835, 93, 5203, 3973}},
-{1331, 14, 2452, {1, 1, 7, 7, 3, 27, 7, 1, 135, 171, 231, 3349, 4459, 2925}},
-{1332, 14, 2477, {1, 1, 5, 5, 9, 51, 71, 153, 115, 315, 265, 2207, 4127, 12631}},
-{1333, 14, 2509, {1, 1, 3, 15, 23, 59, 35, 121, 425, 921, 1255, 2123, 5811, 15937}},
-{1334, 14, 2510, {1, 3, 7, 7, 11, 21, 45, 57, 269, 395, 555, 783, 6677, 2889}},
-{1335, 14, 2515, {1, 3, 5, 7, 31, 19, 73, 35, 465, 349, 1429, 863, 4707, 6121}},
-{1336, 14, 2524, {1, 3, 3, 9, 25, 27, 119, 159, 195, 949, 19, 73, 4511, 15711}},
-{1337, 14, 2527, {1, 3, 3, 7, 9, 59, 47, 57, 91, 749, 1579, 1297, 2445, 5167}},
-{1338, 14, 2531, {1, 3, 3, 3, 31, 57, 19, 203, 61, 927, 1477, 2863, 1305, 11673}},
-{1339, 14, 2552, {1, 3, 7, 11, 29, 13, 3, 111, 351, 79, 1863, 2213, 3273, 7049}},
-{1340, 14, 2561, {1, 3, 3, 9, 7, 23, 47, 237, 121, 877, 441, 119, 2723, 3989}},
-{1341, 14, 2567, {1, 3, 3, 11, 17, 23, 63, 177, 231, 363, 1451, 33, 2169, 7251}},
-{1342, 14, 2571, {1, 1, 5, 11, 31, 41, 93, 229, 39, 1009, 1061, 433, 2393, 15401}},
-{1343, 14, 2586, {1, 1, 5, 15, 31, 37, 25, 135, 135, 897, 33, 3713, 7663, 8079}},
-{1344, 14, 2588, {1, 1, 5, 7, 17, 49, 43, 89, 411, 731, 1431, 3893, 1635, 7063}},
-{1345, 14, 2595, {1, 1, 1, 13, 29, 27, 5, 77, 283, 913, 789, 817, 3309, 475}},
-{1346, 14, 2607, {1, 1, 3, 1, 19, 21, 67, 77, 423, 551, 5, 1057, 5469, 7859}},
-{1347, 14, 2621, {1, 1, 5, 1, 1, 21, 99, 237, 215, 759, 1505, 1983, 1517, 8923}},
-{1348, 14, 2630, {1, 3, 5, 7, 19, 61, 73, 215, 165, 127, 205, 259, 7755, 15395}},
-{1349, 14, 2639, {1, 1, 5, 9, 15, 23, 17, 111, 471, 751, 1923, 775, 6901, 13095}},
-{1350, 14, 2653, {1, 1, 7, 1, 25, 5, 63, 141, 461, 687, 1589, 1559, 7719, 11349}},
-{1351, 14, 2670, {1, 1, 1, 3, 11, 63, 11, 27, 253, 439, 297, 1315, 829, 3765}},
-{1352, 14, 2672, {1, 3, 1, 1, 9, 47, 127, 179, 173, 809, 241, 35, 7355, 5049}},
-{1353, 14, 2700, {1, 3, 1, 11, 19, 63, 93, 1, 205, 977, 303, 3409, 6529, 10927}},
-{1354, 14, 2711, {1, 3, 7, 9, 31, 63, 41, 79, 477, 91, 1801, 3487, 6885, 13341}},
-{1355, 14, 2715, {1, 1, 3, 7, 15, 59, 9, 101, 459, 247, 549, 2855, 5765, 7785}},
-{1356, 14, 2748, {1, 1, 7, 3, 13, 59, 71, 123, 93, 517, 1453, 2389, 4429, 5053}},
-{1357, 14, 2751, {1, 1, 5, 3, 19, 21, 77, 53, 81, 879, 1653, 1637, 3667, 2623}},
-{1358, 14, 2753, {1, 1, 1, 15, 17, 57, 65, 53, 407, 765, 417, 497, 5009, 2175}},
-{1359, 14, 2754, {1, 3, 3, 7, 31, 13, 5, 203, 263, 17, 119, 1607, 6773, 11195}},
-{1360, 14, 2760, {1, 3, 3, 13, 19, 13, 13, 147, 93, 735, 689, 781, 655, 6853}},
-{1361, 14, 2774, {1, 1, 1, 1, 1, 25, 63, 159, 493, 987, 71, 1249, 5859, 11717}},
-{1362, 14, 2784, {1, 1, 1, 15, 13, 23, 61, 61, 5, 947, 1853, 3331, 467, 8081}},
-{1363, 14, 2793, {1, 1, 3, 9, 19, 61, 65, 189, 95, 309, 283, 1725, 5683, 15463}},
-{1364, 14, 2804, {1, 1, 7, 5, 9, 33, 35, 75, 475, 831, 1445, 1485, 5047, 9631}},
-{1365, 14, 2811, {1, 1, 3, 15, 11, 23, 59, 87, 433, 221, 685, 3113, 4095, 13819}},
-{1366, 14, 2822, {1, 1, 7, 15, 25, 29, 67, 17, 349, 353, 1321, 563, 57, 533}},
-{1367, 14, 2826, {1, 3, 3, 3, 5, 43, 109, 217, 15, 185, 1895, 1015, 1831, 10623}},
-{1368, 14, 2836, {1, 1, 7, 1, 1, 47, 81, 185, 59, 691, 191, 3709, 1535, 13347}},
-{1369, 14, 2839, {1, 1, 5, 1, 23, 57, 83, 217, 457, 771, 1877, 2789, 8143, 4797}},
-{1370, 14, 2840, {1, 1, 3, 7, 23, 35, 79, 49, 227, 205, 1523, 3873, 4843, 10505}},
-{1371, 14, 2893, {1, 1, 1, 1, 17, 43, 121, 95, 205, 35, 189, 2061, 1693, 13273}},
-{1372, 14, 2901, {1, 1, 1, 15, 31, 49, 83, 249, 433, 497, 1949, 1845, 5215, 5971}},
-{1373, 14, 2902, {1, 3, 1, 1, 21, 53, 73, 211, 265, 929, 923, 279, 3621, 9469}},
-{1374, 14, 2905, {1, 3, 7, 7, 1, 57, 13, 45, 467, 705, 371, 1345, 1647, 3411}},
-{1375, 14, 2912, {1, 3, 1, 11, 27, 29, 117, 163, 143, 669, 489, 3913, 7891, 9031}},
-{1376, 14, 2915, {1, 3, 7, 15, 27, 15, 77, 217, 107, 839, 1517, 1543, 357, 10365}},
-{1377, 14, 2918, {1, 1, 1, 5, 31, 17, 107, 245, 345, 939, 1453, 3645, 6865, 16173}},
-{1378, 14, 2939, {1, 3, 5, 5, 9, 61, 43, 97, 453, 917, 945, 2143, 5473, 5611}},
-{1379, 14, 2965, {1, 1, 5, 11, 3, 33, 71, 97, 137, 549, 1605, 3839, 4883, 2677}},
-{1380, 14, 2966, {1, 3, 1, 11, 29, 23, 85, 47, 225, 633, 1613, 1297, 1415, 15813}},
-{1381, 14, 2975, {1, 1, 3, 3, 9, 19, 57, 107, 79, 449, 1951, 753, 6317, 10377}},
-{1382, 14, 2988, {1, 1, 1, 5, 21, 3, 39, 187, 299, 517, 1313, 741, 7259, 4197}},
-{1383, 14, 2993, {1, 1, 5, 13, 1, 39, 39, 41, 381, 123, 1257, 3185, 493, 3723}},
-{1384, 14, 3006, {1, 3, 7, 7, 3, 37, 15, 161, 129, 169, 555, 3605, 4287, 15831}},
-{1385, 14, 3017, {1, 3, 7, 15, 15, 23, 81, 163, 257, 791, 505, 1903, 2703, 11919}},
-{1386, 14, 3031, {1, 3, 7, 7, 27, 63, 17, 147, 111, 851, 1533, 1365, 5359, 3315}},
-{1387, 14, 3038, {1, 3, 7, 1, 15, 5, 61, 143, 385, 261, 1019, 1705, 1737, 14485}},
-{1388, 14, 3041, {1, 3, 5, 5, 25, 17, 49, 229, 431, 567, 1613, 3431, 2139, 2981}},
-{1389, 14, 3042, {1, 3, 5, 11, 17, 57, 71, 241, 31, 1007, 1695, 2965, 149, 14125}},
-{1390, 14, 3051, {1, 1, 3, 11, 7, 49, 39, 101, 5, 501, 1491, 3061, 225, 12255}},
-{1391, 14, 3073, {1, 3, 5, 7, 17, 35, 37, 97, 415, 15, 1349, 997, 2949, 4511}},
-{1392, 14, 3088, {1, 3, 1, 5, 25, 35, 99, 183, 161, 59, 1363, 515, 3767, 3641}},
-{1393, 14, 3097, {1, 1, 7, 15, 7, 15, 127, 137, 281, 67, 139, 2315, 3517, 13371}},
-{1394, 14, 3098, {1, 1, 5, 15, 23, 49, 19, 79, 425, 805, 1035, 429, 7707, 14195}},
-{1395, 14, 3103, {1, 3, 5, 3, 21, 25, 123, 11, 425, 475, 961, 2995, 7405, 5449}},
-{1396, 14, 3104, {1, 1, 7, 1, 21, 1, 75, 231, 451, 595, 719, 2369, 5907, 1227}},
-{1397, 14, 3146, {1, 1, 1, 9, 21, 57, 45, 255, 19, 79, 481, 3363, 3451, 8399}},
-{1398, 14, 3148, {1, 1, 7, 13, 31, 49, 95, 69, 483, 427, 37, 4047, 7057, 9111}},
-{1399, 14, 3153, {1, 3, 3, 11, 3, 61, 87, 79, 499, 91, 771, 1987, 2017, 3381}},
-{1400, 14, 3159, {1, 3, 1, 7, 5, 57, 1, 121, 155, 225, 501, 477, 6555, 9863}},
-{1401, 14, 3182, {1, 3, 7, 11, 27, 49, 83, 213, 61, 283, 1599, 3205, 2525, 8553}},
-{1402, 14, 3187, {1, 1, 1, 9, 9, 49, 3, 51, 141, 33, 301, 2167, 587, 15067}},
-{1403, 14, 3189, {1, 1, 1, 11, 7, 55, 99, 81, 191, 553, 953, 3753, 6731, 1093}},
-{1404, 14, 3199, {1, 1, 3, 3, 11, 59, 57, 235, 297, 197, 853, 1411, 3799, 7527}},
-{1405, 14, 3239, {1, 3, 5, 3, 7, 7, 5, 201, 393, 95, 91, 3273, 6285, 10661}},
-{1406, 14, 3263, {1, 1, 5, 7, 17, 57, 87, 3, 413, 915, 659, 369, 3593, 14429}},
-{1407, 14, 3271, {1, 3, 7, 1, 31, 31, 45, 115, 417, 427, 745, 4087, 953, 1119}},
-{1408, 14, 3275, {1, 3, 7, 3, 29, 43, 45, 221, 41, 641, 451, 173, 2999, 12103}},
-{1409, 14, 3278, {1, 1, 3, 11, 25, 57, 117, 201, 135, 787, 1525, 3879, 3247, 8907}},
-{1410, 14, 3280, {1, 1, 7, 11, 3, 35, 69, 157, 331, 615, 573, 2169, 3575, 289}},
-{1411, 14, 3283, {1, 3, 3, 13, 15, 51, 67, 127, 265, 495, 103, 3145, 2685, 15919}},
-{1412, 14, 3290, {1, 3, 5, 11, 31, 27, 65, 57, 153, 465, 1163, 467, 4103, 4713}},
-{1413, 14, 3311, {1, 3, 7, 3, 23, 31, 9, 51, 239, 417, 1597, 229, 2865, 15199}},
-{1414, 14, 3316, {1, 3, 5, 3, 11, 45, 123, 217, 31, 765, 1009, 2001, 3645, 9407}},
-{1415, 14, 3343, {1, 3, 3, 9, 5, 23, 117, 83, 237, 1017, 251, 1187, 2631, 5151}},
-{1416, 14, 3346, {1, 1, 1, 7, 23, 55, 97, 141, 501, 305, 467, 4061, 2369, 15973}},
-{1417, 14, 3357, {1, 1, 7, 5, 31, 51, 125, 191, 219, 495, 37, 3337, 813, 241}},
-{1418, 14, 3358, {1, 3, 1, 1, 11, 39, 93, 109, 285, 147, 1297, 737, 4051, 7223}},
-{1419, 14, 3361, {1, 3, 1, 15, 13, 17, 57, 171, 463, 163, 609, 1681, 7583, 9231}},
-{1420, 14, 3362, {1, 3, 1, 1, 23, 5, 51, 5, 205, 415, 419, 989, 4239, 10943}},
-{1421, 14, 3364, {1, 1, 3, 15, 3, 13, 65, 145, 387, 59, 395, 1067, 4143, 5649}},
-{1422, 14, 3386, {1, 3, 1, 13, 9, 59, 121, 127, 95, 71, 1541, 1423, 1753, 8041}},
-{1423, 14, 3418, {1, 1, 3, 15, 7, 5, 69, 167, 181, 991, 1189, 4017, 5935, 6669}},
-{1424, 14, 3424, {1, 3, 5, 7, 23, 41, 53, 21, 47, 261, 1231, 2011, 133, 2247}},
-{1425, 14, 3433, {1, 1, 1, 5, 17, 47, 77, 19, 331, 609, 1893, 3965, 3123, 9093}},
-{1426, 14, 3434, {1, 3, 1, 3, 9, 39, 103, 231, 249, 75, 373, 107, 1823, 10801}},
-{1427, 14, 3436, {1, 3, 3, 7, 1, 51, 35, 111, 137, 879, 1221, 225, 4285, 2287}},
-{1428, 14, 3463, {1, 1, 7, 9, 23, 17, 75, 245, 409, 163, 395, 3731, 7111, 6845}},
-{1429, 14, 3467, {1, 1, 3, 13, 29, 47, 75, 153, 497, 621, 1691, 3187, 2125, 10533}},
-{1430, 14, 3477, {1, 1, 7, 7, 9, 7, 55, 159, 255, 417, 1335, 643, 3843, 3733}},
-{1431, 14, 3484, {1, 3, 3, 1, 21, 41, 7, 21, 5, 679, 1655, 95, 5699, 5785}},
-{1432, 14, 3505, {1, 1, 1, 13, 19, 7, 85, 7, 195, 357, 1097, 2893, 2913, 9635}},
-{1433, 14, 3508, {1, 1, 5, 9, 25, 33, 41, 155, 39, 655, 1993, 3117, 3639, 7977}},
-{1434, 14, 3515, {1, 1, 1, 13, 3, 63, 121, 247, 151, 673, 609, 285, 2299, 7663}},
-{1435, 14, 3532, {1, 3, 7, 11, 17, 13, 49, 253, 245, 21, 273, 993, 911, 863}},
-{1436, 14, 3553, {1, 1, 5, 5, 23, 1, 121, 95, 225, 9, 1237, 1183, 6461, 559}},
-{1437, 14, 3554, {1, 3, 7, 13, 3, 7, 121, 151, 233, 561, 281, 3583, 897, 1767}},
-{1438, 14, 3568, {1, 1, 7, 7, 9, 47, 107, 41, 25, 569, 1697, 2299, 6231, 12209}},
-{1439, 14, 3573, {1, 3, 7, 7, 27, 43, 59, 37, 31, 51, 503, 149, 4043, 11847}},
-{1440, 14, 3587, {1, 3, 3, 11, 5, 1, 119, 181, 47, 641, 685, 4017, 637, 16251}},
-{1441, 14, 3589, {1, 3, 3, 7, 11, 1, 101, 7, 239, 747, 307, 1721, 5979, 4367}},
-{1442, 14, 3596, {1, 3, 5, 7, 1, 63, 19, 151, 469, 333, 1587, 2453, 897, 4711}},
-{1443, 14, 3608, {1, 3, 1, 5, 11, 61, 21, 253, 91, 993, 1347, 1993, 5607, 13031}},
-{1444, 14, 3620, {1, 3, 5, 5, 1, 39, 65, 71, 189, 389, 1437, 1055, 6439, 3989}},
-{1445, 14, 3630, {1, 1, 3, 3, 19, 15, 93, 3, 339, 165, 1675, 3953, 2145, 12113}},
-{1446, 14, 3644, {1, 1, 3, 13, 13, 45, 5, 175, 211, 993, 705, 2761, 3023, 13633}},
-{1447, 14, 3649, {1, 1, 3, 1, 19, 39, 121, 29, 287, 87, 281, 3491, 7107, 13007}},
-{1448, 14, 3664, {1, 1, 7, 1, 29, 49, 103, 187, 39, 923, 51, 1533, 3249, 4399}},
-{1449, 14, 3679, {1, 1, 5, 5, 5, 43, 25, 107, 453, 955, 115, 57, 4589, 14573}},
-{1450, 14, 3680, {1, 1, 3, 5, 21, 45, 103, 99, 183, 987, 1207, 1697, 8033, 13703}},
-{1451, 14, 3685, {1, 1, 5, 7, 11, 23, 9, 17, 261, 749, 1957, 935, 6283, 8625}},
-{1452, 14, 3686, {1, 1, 1, 9, 9, 51, 69, 225, 265, 323, 1161, 2993, 7305, 2249}},
-{1453, 14, 3698, {1, 3, 1, 9, 23, 19, 57, 205, 503, 489, 1499, 3277, 817, 11931}},
-{1454, 14, 3714, {1, 3, 3, 5, 1, 7, 49, 1, 313, 123, 643, 2027, 1469, 3585}},
-{1455, 14, 3726, {1, 3, 7, 11, 27, 47, 95, 111, 27, 213, 465, 3693, 3661, 7531}},
-{1456, 14, 3737, {1, 1, 7, 9, 3, 37, 115, 189, 31, 613, 1393, 1229, 4767, 12425}},
-{1457, 14, 3767, {1, 1, 3, 3, 25, 17, 99, 47, 161, 931, 959, 1293, 7095, 8325}},
-{1458, 14, 3782, {1, 1, 1, 7, 23, 9, 11, 51, 205, 419, 479, 1497, 2493, 13921}},
-{1459, 14, 3786, {1, 3, 1, 9, 17, 29, 51, 79, 159, 435, 477, 413, 3815, 5589}},
-{1460, 14, 3793, {1, 3, 7, 5, 7, 23, 99, 43, 169, 665, 403, 1163, 4337, 1335}},
-{1461, 14, 3796, {1, 3, 1, 5, 25, 27, 125, 249, 421, 267, 1259, 4089, 59, 9377}},
-{1462, 14, 3805, {1, 3, 3, 1, 27, 37, 91, 17, 123, 597, 1749, 3449, 6503, 11043}},
-{1463, 14, 3815, {1, 3, 7, 7, 23, 41, 19, 245, 109, 569, 547, 1917, 7943, 2697}},
-{1464, 14, 3841, {1, 3, 7, 7, 9, 1, 123, 105, 329, 435, 2013, 2745, 347, 11045}},
-{1465, 14, 3847, {1, 1, 1, 13, 29, 53, 51, 67, 105, 89, 1887, 3543, 963, 8159}},
-{1466, 14, 3853, {1, 1, 5, 3, 5, 27, 41, 67, 67, 883, 973, 1785, 901, 14969}},
-{1467, 14, 3862, {1, 3, 3, 13, 17, 11, 117, 115, 163, 939, 79, 641, 4365, 2267}},
-{1468, 14, 3875, {1, 1, 3, 3, 9, 5, 41, 123, 149, 9, 1533, 3939, 5995, 12701}},
-{1469, 14, 3902, {1, 1, 1, 15, 31, 1, 101, 229, 191, 965, 61, 2671, 4177, 15779}},
-{1470, 14, 3904, {1, 1, 5, 15, 1, 25, 49, 185, 33, 697, 1043, 2639, 7819, 3171}},
-{1471, 14, 3916, {1, 3, 5, 13, 19, 9, 111, 49, 47, 847, 1865, 717, 5287, 13417}},
-{1472, 14, 3947, {1, 3, 7, 11, 5, 61, 63, 111, 171, 735, 2003, 73, 5701, 647}},
-{1473, 14, 3949, {1, 3, 1, 11, 1, 49, 121, 79, 431, 671, 1241, 1161, 2057, 263}},
-{1474, 14, 3955, {1, 3, 3, 1, 1, 23, 75, 15, 117, 641, 313, 1525, 2041, 1409}},
-{1475, 14, 3962, {1, 3, 5, 11, 15, 57, 13, 67, 139, 131, 1339, 2419, 7945, 11877}},
-{1476, 14, 3971, {1, 3, 1, 1, 19, 39, 97, 83, 297, 595, 1611, 5, 4753, 3435}},
-{1477, 14, 3980, {1, 3, 1, 9, 7, 49, 125, 101, 383, 717, 63, 2295, 3873, 13461}},
-{1478, 14, 3985, {1, 1, 3, 3, 15, 29, 89, 77, 269, 689, 229, 1207, 7311, 8663}},
-{1479, 14, 3998, {1, 1, 1, 1, 1, 61, 25, 255, 203, 233, 271, 987, 2277, 8735}},
-{1480, 14, 4001, {1, 1, 5, 7, 21, 27, 63, 79, 337, 133, 1453, 3633, 6157, 15875}},
-{1481, 14, 4002, {1, 3, 1, 7, 7, 55, 31, 81, 203, 709, 1743, 1677, 4247, 11411}},
-{1482, 14, 4016, {1, 1, 3, 3, 29, 51, 37, 17, 487, 325, 1393, 1433, 3467, 2851}},
-{1483, 14, 4021, {1, 1, 7, 9, 3, 41, 99, 177, 241, 869, 739, 2729, 4585, 14801}},
-{1484, 14, 4026, {1, 1, 3, 1, 9, 43, 97, 65, 99, 295, 1693, 2083, 3241, 4073}},
-{1485, 14, 4043, {1, 1, 1, 9, 5, 39, 67, 119, 235, 543, 795, 2773, 3195, 6273}},
-{1486, 14, 4079, {1, 1, 5, 5, 21, 41, 89, 1, 85, 81, 57, 2951, 1531, 10101}},
-{1487, 14, 4102, {1, 1, 1, 7, 3, 35, 127, 69, 39, 265, 1643, 2973, 267, 12365}},
-{1488, 14, 4106, {1, 3, 1, 1, 21, 57, 99, 205, 119, 477, 1771, 1989, 2761, 12573}},
-{1489, 14, 4119, {1, 1, 3, 13, 1, 59, 93, 125, 279, 935, 1877, 2061, 4845, 7835}},
-{1490, 14, 4126, {1, 1, 7, 9, 7, 45, 69, 99, 273, 35, 1579, 2137, 7175, 6999}},
-{1491, 14, 4147, {1, 1, 7, 7, 29, 21, 127, 91, 9, 383, 787, 1783, 601, 5047}},
-{1492, 14, 4149, {1, 1, 7, 13, 7, 29, 35, 219, 43, 581, 2043, 2211, 6169, 12173}},
-{1493, 14, 4164, {1, 3, 5, 13, 29, 29, 39, 63, 411, 645, 415, 2383, 1989, 11411}},
-{1494, 14, 4174, {1, 1, 7, 9, 15, 9, 87, 95, 321, 709, 543, 3831, 2453, 4167}},
-{1495, 14, 4181, {1, 3, 1, 5, 31, 25, 5, 85, 239, 487, 1613, 3937, 4661, 3535}},
-{1496, 14, 4185, {1, 3, 5, 11, 27, 41, 3, 201, 39, 91, 1997, 237, 5639, 14703}},
-{1497, 14, 4188, {1, 1, 7, 3, 27, 49, 87, 71, 473, 247, 1007, 47, 475, 5413}},
-{1498, 14, 4202, {1, 3, 7, 15, 9, 57, 81, 149, 287, 333, 1911, 3417, 1081, 8995}},
-{1499, 14, 4228, {1, 1, 5, 1, 3, 63, 43, 151, 97, 431, 961, 1019, 5153, 2407}},
-{1500, 14, 4232, {1, 1, 5, 5, 27, 21, 127, 161, 507, 311, 129, 3489, 1133, 3241}},
-{1501, 14, 4246, {1, 3, 7, 15, 21, 33, 117, 83, 497, 667, 1399, 931, 1695, 8171}},
-{1502, 14, 4252, {1, 1, 1, 13, 3, 39, 53, 27, 193, 993, 671, 1871, 7579, 11457}},
-{1503, 14, 4256, {1, 1, 5, 11, 7, 39, 81, 107, 195, 387, 849, 395, 1317, 6487}},
-{1504, 14, 4286, {1, 3, 3, 3, 3, 15, 45, 127, 279, 111, 331, 357, 4637, 4697}},
-{1505, 14, 4303, {1, 1, 3, 9, 21, 49, 47, 97, 61, 101, 181, 1867, 1201, 14099}},
-{1506, 14, 4306, {1, 1, 5, 11, 25, 19, 51, 51, 101, 451, 545, 101, 7497, 9141}},
-{1507, 14, 4311, {1, 1, 1, 3, 13, 53, 119, 81, 377, 245, 765, 251, 3757, 16045}},
-{1508, 14, 4317, {1, 1, 1, 3, 5, 61, 65, 37, 331, 925, 1439, 3219, 2843, 11397}},
-{1509, 14, 4342, {1, 3, 5, 9, 23, 31, 95, 155, 83, 641, 1129, 135, 477, 1623}},
-{1510, 14, 4346, {1, 1, 3, 9, 9, 61, 93, 11, 331, 585, 799, 1417, 1533, 463}},
-{1511, 14, 4377, {1, 1, 7, 7, 21, 51, 61, 29, 467, 935, 11, 3357, 1087, 12337}},
-{1512, 14, 4401, {1, 3, 3, 11, 1, 39, 103, 153, 351, 893, 1823, 835, 2149, 4203}},
-{1513, 14, 4407, {1, 1, 1, 9, 31, 13, 61, 235, 369, 359, 835, 2067, 2697, 15289}},
-{1514, 14, 4414, {1, 1, 7, 1, 15, 1, 107, 27, 201, 451, 1521, 313, 3195, 3847}},
-{1515, 14, 4422, {1, 1, 5, 13, 1, 27, 63, 137, 355, 489, 2039, 1015, 2519, 13797}},
-{1516, 14, 4431, {1, 1, 7, 9, 29, 33, 23, 197, 49, 555, 1087, 3447, 7299, 15513}},
-{1517, 14, 4434, {1, 3, 5, 11, 7, 37, 55, 63, 443, 573, 1715, 631, 3405, 6155}},
-{1518, 14, 4436, {1, 3, 3, 3, 31, 35, 51, 167, 225, 617, 2007, 2555, 6819, 12709}},
-{1519, 14, 4443, {1, 1, 1, 13, 15, 5, 73, 85, 109, 43, 1067, 3941, 1125, 10269}},
-{1520, 14, 4459, {1, 1, 7, 11, 17, 3, 127, 145, 279, 19, 1007, 3287, 4751, 12507}},
-{1521, 14, 4461, {1, 3, 7, 3, 19, 1, 117, 111, 193, 435, 47, 1801, 529, 8547}},
-{1522, 14, 4462, {1, 3, 3, 13, 1, 19, 101, 19, 469, 187, 207, 1243, 8153, 3273}},
-{1523, 14, 4473, {1, 3, 1, 5, 11, 51, 69, 189, 453, 775, 241, 3331, 4067, 14759}},
-{1524, 14, 4497, {1, 1, 1, 1, 23, 55, 113, 133, 497, 731, 391, 2777, 3529, 955}},
-{1525, 14, 4504, {1, 3, 1, 11, 5, 49, 59, 35, 261, 949, 325, 3595, 7433, 11099}},
-{1526, 14, 4507, {1, 3, 5, 9, 13, 37, 103, 219, 329, 865, 1787, 2497, 7249, 9877}},
-{1527, 14, 4525, {1, 3, 7, 9, 11, 33, 19, 255, 191, 935, 1115, 1901, 1577, 9623}},
-{1528, 14, 4534, {1, 1, 5, 7, 29, 23, 77, 43, 283, 143, 1211, 73, 2835, 10235}},
-{1529, 14, 4538, {1, 1, 7, 3, 3, 27, 35, 173, 453, 425, 1225, 3023, 2159, 8433}},
-{1530, 14, 4548, {1, 1, 1, 5, 27, 21, 35, 25, 71, 145, 1545, 523, 4527, 7655}},
-{1531, 14, 4552, {1, 1, 5, 3, 13, 49, 61, 157, 113, 775, 763, 1785, 225, 11851}},
-{1532, 14, 4560, {1, 1, 3, 1, 31, 57, 97, 229, 291, 777, 213, 4067, 921, 8203}},
-{1533, 14, 4575, {1, 1, 5, 1, 25, 13, 125, 123, 263, 207, 119, 3111, 3841, 843}},
-{1534, 14, 4599, {1, 1, 7, 7, 25, 57, 81, 129, 31, 133, 1869, 2949, 5563, 14965}},
-{1535, 14, 4612, {1, 3, 3, 7, 3, 51, 33, 127, 281, 425, 1253, 405, 7941, 8799}},
-{1536, 14, 4619, {1, 1, 3, 9, 3, 63, 93, 173, 255, 609, 49, 111, 7785, 15865}},
-{1537, 14, 4640, {1, 1, 1, 3, 17, 59, 113, 55, 155, 789, 1335, 177, 3071, 1851}},
-{1538, 14, 4643, {1, 3, 7, 15, 15, 23, 35, 35, 131, 623, 47, 437, 1337, 9891}},
-{1539, 14, 4677, {1, 3, 7, 5, 29, 57, 39, 31, 111, 271, 59, 1473, 949, 3899}},
-{1540, 14, 4687, {1, 1, 3, 11, 17, 19, 41, 229, 259, 691, 1455, 3023, 7455, 9711}},
-{1541, 14, 4723, {1, 3, 5, 11, 29, 13, 9, 165, 499, 355, 1415, 1395, 7595, 15571}},
-{1542, 14, 4730, {1, 3, 1, 9, 5, 5, 25, 247, 185, 241, 1325, 3133, 7471, 2649}},
-{1543, 14, 4736, {1, 3, 3, 11, 17, 29, 57, 61, 51, 203, 993, 1837, 3785, 15163}},
-{1544, 14, 4741, {1, 1, 7, 7, 21, 57, 79, 165, 277, 133, 93, 1055, 7169, 15685}},
-{1545, 14, 4763, {1, 1, 5, 3, 5, 17, 25, 177, 95, 323, 367, 1359, 4915, 6409}},
-{1546, 14, 4765, {1, 1, 1, 1, 11, 25, 115, 45, 373, 221, 1483, 591, 6561, 4527}},
-{1547, 14, 4770, {1, 3, 5, 3, 5, 23, 69, 77, 313, 473, 1037, 4045, 3969, 5445}},
-{1548, 14, 4781, {1, 3, 1, 5, 1, 15, 73, 83, 439, 463, 203, 361, 6835, 1061}},
-{1549, 14, 4808, {1, 1, 3, 11, 21, 5, 89, 233, 405, 253, 773, 3901, 6085, 5677}},
-{1550, 14, 4822, {1, 1, 3, 9, 15, 53, 71, 29, 101, 599, 1073, 705, 4507, 12779}},
-{1551, 14, 4828, {1, 1, 3, 1, 3, 9, 27, 97, 207, 859, 417, 735, 2179, 5071}},
-{1552, 14, 4831, {1, 1, 1, 3, 13, 63, 65, 125, 195, 611, 649, 2221, 3143, 143}},
-{1553, 14, 4842, {1, 3, 3, 15, 17, 57, 99, 119, 243, 407, 1229, 813, 5245, 1893}},
-{1554, 14, 4855, {1, 1, 1, 5, 27, 27, 49, 13, 313, 287, 473, 2629, 3509, 11371}},
-{1555, 14, 4859, {1, 1, 7, 7, 23, 3, 75, 59, 245, 689, 1215, 2375, 3325, 1593}},
-{1556, 14, 4867, {1, 3, 1, 5, 21, 51, 43, 107, 91, 611, 1405, 677, 2087, 9565}},
-{1557, 14, 4870, {1, 3, 7, 11, 9, 27, 81, 101, 449, 201, 1507, 2217, 6767, 8059}},
-{1558, 14, 4881, {1, 1, 3, 9, 13, 41, 21, 195, 421, 315, 347, 2621, 2359, 9247}},
-{1559, 14, 4893, {1, 1, 5, 7, 31, 45, 77, 229, 455, 575, 1087, 1147, 2273, 13773}},
-{1560, 14, 4910, {1, 1, 1, 1, 9, 5, 87, 19, 207, 545, 1435, 495, 1299, 4947}},
-{1561, 14, 4917, {1, 1, 3, 3, 15, 9, 63, 67, 219, 735, 1911, 2361, 6503, 11977}},
-{1562, 14, 4929, {1, 3, 1, 9, 31, 27, 103, 153, 81, 939, 461, 2753, 697, 537}},
-{1563, 14, 4939, {1, 3, 3, 9, 21, 53, 49, 211, 415, 817, 321, 3775, 2921, 9473}},
-{1564, 14, 4947, {1, 1, 7, 3, 23, 55, 15, 51, 435, 1013, 73, 3967, 4575, 13099}},
-{1565, 14, 4949, {1, 1, 3, 7, 5, 27, 43, 225, 267, 21, 1261, 603, 6913, 4421}},
-{1566, 14, 4954, {1, 1, 7, 13, 25, 31, 101, 109, 237, 91, 1587, 1987, 2795, 6991}},
-{1567, 14, 4972, {1, 1, 3, 13, 23, 51, 91, 89, 287, 39, 1513, 463, 6135, 10469}},
-{1568, 14, 4975, {1, 3, 3, 1, 9, 43, 125, 157, 369, 495, 1849, 785, 6357, 6557}},
-{1569, 14, 5000, {1, 3, 1, 13, 5, 25, 107, 139, 367, 239, 1671, 1239, 7027, 5291}},
-{1570, 14, 5005, {1, 3, 5, 13, 11, 13, 35, 177, 45, 939, 251, 59, 333, 13105}},
-{1571, 14, 5029, {1, 3, 5, 7, 29, 57, 109, 227, 435, 739, 423, 1941, 3345, 12731}},
-{1572, 14, 5039, {1, 3, 3, 9, 23, 51, 19, 207, 69, 99, 955, 519, 7305, 2415}},
-{1573, 14, 5044, {1, 1, 5, 13, 17, 1, 67, 201, 61, 403, 1059, 2915, 2419, 12773}},
-{1574, 14, 5051, {1, 3, 1, 11, 17, 19, 25, 27, 207, 299, 143, 1955, 5669, 2301}},
-{1575, 14, 5056, {1, 1, 5, 3, 25, 57, 45, 255, 489, 1011, 1699, 2637, 5279, 12211}},
-{1576, 14, 5073, {1, 3, 3, 15, 7, 47, 113, 33, 511, 907, 1815, 1741, 2091, 13857}},
-{1577, 14, 5096, {1, 3, 3, 5, 5, 27, 95, 3, 353, 253, 947, 393, 1815, 14551}},
-{1578, 14, 5128, {1, 1, 5, 11, 29, 19, 63, 117, 293, 861, 2039, 9, 5999, 6909}},
-{1579, 14, 5134, {1, 3, 7, 3, 15, 63, 107, 173, 509, 817, 99, 2825, 131, 7917}},
-{1580, 14, 5161, {1, 3, 1, 1, 29, 49, 33, 153, 119, 777, 1315, 3581, 5675, 4043}},
-{1581, 14, 5179, {1, 3, 5, 15, 13, 11, 17, 147, 327, 305, 367, 3237, 5423, 13757}},
-{1582, 14, 5193, {1, 1, 5, 13, 1, 39, 35, 29, 25, 751, 1365, 2243, 8181, 7063}},
-{1583, 14, 5199, {1, 3, 7, 11, 25, 53, 11, 111, 289, 755, 1201, 691, 3679, 3725}},
-{1584, 14, 5202, {1, 1, 1, 11, 11, 37, 33, 211, 395, 691, 1817, 861, 6485, 12077}},
-{1585, 14, 5204, {1, 3, 3, 11, 21, 3, 111, 171, 305, 561, 1501, 2011, 7841, 10931}},
-{1586, 14, 5218, {1, 3, 7, 9, 9, 59, 109, 113, 31, 915, 103, 1861, 2779, 10619}},
-{1587, 14, 5247, {1, 1, 1, 1, 7, 25, 61, 97, 103, 723, 1145, 3105, 371, 339}},
-{1588, 14, 5260, {1, 1, 7, 13, 17, 9, 113, 51, 233, 209, 1117, 211, 6969, 2347}},
-{1589, 14, 5271, {1, 1, 5, 9, 25, 43, 21, 217, 327, 735, 197, 1063, 799, 801}},
-{1590, 14, 5301, {1, 1, 7, 13, 9, 13, 73, 33, 415, 923, 863, 1999, 5383, 8119}},
-{1591, 14, 5305, {1, 3, 1, 5, 7, 33, 51, 185, 289, 967, 1277, 1011, 767, 15505}},
-{1592, 14, 5319, {1, 3, 3, 13, 21, 11, 105, 235, 343, 1021, 2009, 2251, 3865, 6923}},
-{1593, 14, 5326, {1, 3, 5, 9, 29, 11, 33, 17, 149, 155, 1739, 3039, 7015, 2401}},
-{1594, 14, 5328, {1, 3, 7, 7, 17, 13, 89, 177, 297, 267, 545, 3861, 329, 13267}},
-{1595, 14, 5333, {1, 3, 5, 15, 27, 33, 1, 231, 181, 557, 447, 379, 7845, 1295}},
-{1596, 14, 5364, {1, 1, 5, 13, 3, 63, 59, 33, 263, 877, 1867, 1383, 641, 7139}},
-{1597, 14, 5376, {1, 3, 7, 5, 13, 51, 9, 113, 223, 605, 1189, 4063, 6925, 9563}},
-{1598, 14, 5399, {1, 1, 1, 13, 5, 35, 83, 107, 295, 231, 265, 5, 4087, 6407}},
-{1599, 14, 5416, {1, 1, 5, 1, 7, 25, 95, 137, 97, 987, 1753, 2781, 1369, 6903}},
-{1600, 14, 5421, {1, 1, 5, 13, 19, 61, 77, 229, 193, 165, 811, 249, 79, 10719}},
-{1601, 14, 5427, {1, 3, 7, 7, 27, 9, 119, 193, 459, 43, 1989, 2959, 3595, 6341}},
-{1602, 14, 5429, {1, 1, 5, 11, 5, 43, 35, 33, 25, 581, 897, 351, 4201, 3971}},
-{1603, 14, 5430, {1, 1, 7, 11, 21, 29, 53, 45, 359, 197, 313, 3825, 6717, 4077}},
-{1604, 14, 5434, {1, 1, 1, 15, 3, 45, 99, 133, 357, 315, 1159, 241, 2463, 11253}},
-{1605, 14, 5441, {1, 1, 7, 11, 9, 33, 111, 85, 443, 601, 447, 337, 6471, 7029}},
-{1606, 14, 5451, {1, 3, 7, 9, 13, 33, 25, 31, 9, 729, 1763, 4077, 7575, 7877}},
-{1607, 14, 5465, {1, 3, 5, 13, 13, 37, 29, 103, 53, 229, 591, 1073, 1323, 14405}},
-{1608, 14, 5466, {1, 1, 5, 1, 17, 33, 15, 183, 473, 297, 2003, 93, 4955, 1787}},
-{1609, 14, 5471, {1, 1, 5, 13, 5, 29, 113, 161, 267, 451, 1193, 149, 273, 11809}},
-{1610, 14, 5477, {1, 1, 1, 9, 17, 39, 47, 233, 165, 373, 955, 2891, 7523, 7235}},
-{1611, 14, 5492, {1, 1, 1, 3, 7, 21, 115, 205, 153, 449, 339, 2073, 1077, 5749}},
-{1612, 14, 5495, {1, 1, 7, 13, 9, 39, 117, 187, 37, 753, 227, 3519, 7391, 5751}},
-{1613, 14, 5505, {1, 1, 1, 9, 5, 19, 41, 161, 141, 195, 1719, 3321, 5, 12877}},
-{1614, 14, 5515, {1, 3, 7, 11, 21, 13, 83, 55, 299, 75, 1905, 3765, 4685, 12297}},
-{1615, 14, 5525, {1, 1, 7, 3, 3, 23, 111, 243, 187, 297, 1061, 2515, 977, 9555}},
-{1616, 14, 5529, {1, 3, 7, 3, 29, 11, 103, 177, 225, 875, 1649, 1401, 6383, 8309}},
-{1617, 14, 5532, {1, 3, 5, 3, 3, 41, 71, 3, 373, 757, 701, 2825, 1521, 13217}},
-{1618, 14, 5539, {1, 1, 5, 3, 11, 5, 103, 227, 209, 723, 1543, 3895, 6345, 7901}},
-{1619, 14, 5541, {1, 1, 5, 1, 9, 51, 77, 67, 359, 937, 557, 993, 3871, 3577}},
-{1620, 14, 5556, {1, 3, 7, 1, 1, 15, 121, 239, 29, 113, 1123, 3877, 6941, 14129}},
-{1621, 14, 5566, {1, 1, 5, 1, 27, 61, 83, 113, 185, 601, 947, 3933, 381, 13869}},
-{1622, 14, 5568, {1, 1, 5, 3, 5, 37, 97, 31, 81, 367, 747, 1811, 5313, 14151}},
-{1623, 14, 5574, {1, 3, 5, 9, 27, 61, 87, 31, 185, 521, 837, 959, 5001, 3957}},
-{1624, 14, 5595, {1, 3, 5, 3, 11, 61, 37, 19, 107, 749, 1345, 3829, 6701, 4315}},
-{1625, 14, 5602, {1, 3, 1, 15, 13, 45, 101, 113, 243, 963, 1861, 3283, 1419, 12131}},
-{1626, 14, 5611, {1, 1, 7, 1, 11, 63, 17, 117, 271, 819, 677, 669, 1991, 12511}},
-{1627, 14, 5616, {1, 1, 1, 13, 13, 33, 41, 73, 187, 537, 993, 3147, 1013, 16063}},
-{1628, 14, 5622, {1, 3, 1, 1, 25, 21, 107, 81, 117, 917, 113, 349, 4475, 9149}},
-{1629, 14, 5628, {1, 1, 1, 11, 21, 21, 29, 251, 125, 681, 141, 2893, 5843, 14359}},
-{1630, 14, 5655, {1, 3, 3, 1, 5, 41, 85, 163, 387, 29, 1593, 221, 2769, 10809}},
-{1631, 14, 5662, {1, 3, 5, 11, 1, 17, 69, 127, 273, 449, 1855, 2971, 7031, 10583}},
-{1632, 14, 5675, {1, 1, 5, 7, 1, 61, 9, 211, 123, 563, 111, 1883, 5801, 2191}},
-{1633, 14, 5689, {1, 1, 3, 11, 11, 51, 1, 81, 405, 803, 2017, 161, 5429, 731}},
-{1634, 14, 5722, {1, 1, 7, 9, 15, 55, 65, 51, 459, 485, 1539, 3135, 2929, 7867}},
-{1635, 14, 5724, {1, 1, 7, 11, 3, 45, 15, 7, 331, 417, 1813, 4009, 1341, 10965}},
-{1636, 14, 5728, {1, 1, 1, 5, 9, 29, 89, 121, 277, 509, 1989, 1293, 4787, 16097}},
-{1637, 14, 5731, {1, 1, 3, 9, 17, 45, 97, 197, 339, 943, 1377, 2947, 5833, 7}},
-{1638, 14, 5746, {1, 1, 7, 9, 15, 61, 75, 233, 401, 705, 825, 2521, 3787, 14387}},
-{1639, 14, 5764, {1, 1, 7, 15, 25, 57, 3, 43, 361, 459, 1551, 1859, 6787, 2293}},
-{1640, 14, 5771, {1, 3, 3, 11, 11, 35, 91, 65, 43, 509, 1829, 1149, 4801, 4109}},
-{1641, 14, 5781, {1, 3, 5, 9, 15, 3, 81, 109, 231, 481, 417, 2505, 315, 6693}},
-{1642, 14, 5801, {1, 1, 3, 9, 3, 7, 107, 221, 297, 543, 149, 579, 927, 79}},
-{1643, 14, 5809, {1, 3, 1, 11, 17, 3, 81, 137, 157, 587, 741, 1277, 2631, 3953}},
-{1644, 14, 5810, {1, 1, 7, 5, 13, 43, 117, 19, 495, 185, 1105, 605, 5249, 11099}},
-{1645, 14, 5812, {1, 1, 7, 9, 23, 55, 91, 213, 21, 779, 857, 2047, 7813, 10053}},
-{1646, 14, 5841, {1, 1, 1, 1, 27, 7, 39, 181, 63, 519, 1073, 3147, 4111, 363}},
-{1647, 14, 5848, {1, 3, 7, 9, 15, 61, 7, 139, 495, 805, 1545, 3789, 2411, 3989}},
-{1648, 14, 5853, {1, 1, 3, 1, 25, 11, 23, 241, 167, 607, 479, 153, 7787, 13929}},
-{1649, 14, 5854, {1, 3, 5, 15, 29, 35, 45, 71, 457, 297, 883, 3021, 5361, 15427}},
-{1650, 14, 5858, {1, 3, 1, 7, 29, 27, 93, 241, 427, 89, 1185, 37, 3863, 14095}},
-{1651, 14, 5892, {1, 3, 1, 5, 5, 45, 51, 15, 235, 889, 1649, 2331, 2713, 10943}},
-{1652, 14, 5907, {1, 1, 3, 11, 11, 15, 71, 85, 135, 163, 139, 1147, 1043, 3195}},
-{1653, 14, 5910, {1, 3, 5, 13, 3, 43, 71, 131, 473, 933, 569, 2491, 7751, 1865}},
-{1654, 14, 5913, {1, 1, 7, 9, 21, 37, 105, 227, 329, 509, 1319, 307, 1557, 14625}},
-{1655, 14, 5920, {1, 1, 3, 13, 15, 1, 25, 93, 335, 953, 769, 4039, 369, 10727}},
-{1656, 14, 5929, {1, 3, 7, 5, 17, 21, 59, 89, 437, 679, 437, 1543, 7663, 5005}},
-{1657, 14, 5949, {1, 1, 7, 15, 27, 49, 125, 13, 397, 877, 1087, 2191, 4711, 9065}},
-{1658, 14, 5952, {1, 1, 7, 5, 15, 47, 115, 125, 187, 31, 1003, 2575, 5397, 3883}},
-{1659, 14, 5955, {1, 1, 7, 11, 15, 1, 127, 207, 383, 707, 183, 1053, 3123, 14071}},
-{1660, 14, 5962, {1, 3, 3, 1, 31, 53, 15, 19, 477, 245, 777, 1613, 5813, 7443}},
-{1661, 14, 5975, {1, 3, 1, 11, 23, 59, 65, 23, 493, 157, 1389, 2833, 4535, 3907}},
-{1662, 14, 5985, {1, 1, 7, 1, 19, 7, 51, 135, 327, 441, 1841, 3091, 3451, 14381}},
-{1663, 14, 5997, {1, 1, 7, 7, 3, 37, 29, 249, 437, 319, 1693, 945, 7639, 5923}},
-{1664, 14, 5998, {1, 3, 7, 15, 7, 61, 81, 127, 383, 99, 23, 3833, 3973, 7651}},
-{1665, 14, 6012, {1, 3, 1, 7, 7, 21, 119, 185, 243, 619, 1363, 2033, 4835, 5089}},
-{1666, 14, 6016, {1, 3, 1, 1, 3, 27, 63, 145, 271, 735, 695, 3981, 3049, 5433}},
-{1667, 14, 6026, {1, 3, 3, 1, 3, 29, 79, 211, 279, 819, 501, 3665, 1455, 10455}},
-{1668, 14, 6036, {1, 1, 3, 3, 31, 61, 113, 5, 411, 91, 489, 3257, 5939, 6715}},
-{1669, 14, 6040, {1, 1, 5, 1, 23, 11, 103, 89, 377, 441, 43, 967, 3383, 8717}},
-{1670, 14, 6045, {1, 1, 5, 13, 29, 39, 97, 189, 197, 621, 1755, 333, 6783, 9711}},
-{1671, 14, 6055, {1, 1, 5, 13, 27, 17, 97, 197, 351, 799, 335, 765, 5329, 12549}},
-{1672, 14, 6059, {1, 1, 5, 11, 29, 17, 9, 211, 127, 633, 1187, 3965, 4145, 12667}},
-{1673, 14, 6088, {1, 1, 7, 5, 27, 29, 65, 115, 287, 325, 461, 5, 899, 2027}},
-{1674, 14, 6115, {1, 1, 1, 5, 27, 17, 31, 13, 231, 627, 1163, 649, 1693, 9975}},
-{1675, 14, 6124, {1, 3, 1, 15, 7, 49, 113, 123, 427, 603, 347, 2785, 7129, 4645}},
-{1676, 14, 6127, {1, 1, 3, 7, 1, 33, 113, 105, 411, 939, 205, 3965, 4361, 4649}},
-{1677, 14, 6132, {1, 1, 1, 1, 5, 21, 35, 159, 275, 929, 1193, 3205, 4787, 3515}},
-{1678, 14, 6146, {1, 1, 1, 5, 1, 21, 29, 191, 275, 233, 1239, 515, 4349, 14989}},
-{1679, 14, 6158, {1, 1, 5, 11, 27, 43, 111, 83, 153, 577, 1537, 149, 231, 839}},
-{1680, 14, 6169, {1, 3, 5, 13, 21, 19, 57, 69, 87, 163, 271, 3535, 1057, 8517}},
-{1681, 14, 6206, {1, 3, 3, 13, 17, 49, 65, 45, 457, 241, 391, 2033, 2507, 7771}},
-{1682, 14, 6228, {1, 1, 5, 7, 11, 19, 79, 133, 341, 761, 27, 3905, 4137, 14363}},
-{1683, 14, 6237, {1, 3, 3, 13, 19, 1, 11, 139, 249, 245, 1393, 2151, 2857, 1665}},
-{1684, 14, 6244, {1, 1, 3, 15, 11, 7, 127, 47, 385, 1007, 713, 2235, 5489, 8755}},
-{1685, 14, 6247, {1, 3, 5, 13, 19, 21, 21, 167, 405, 655, 1653, 889, 7367, 4177}},
-{1686, 14, 6256, {1, 1, 5, 3, 19, 63, 99, 39, 89, 415, 951, 2863, 6569, 3797}},
-{1687, 14, 6281, {1, 1, 1, 13, 31, 29, 119, 35, 311, 839, 1749, 941, 7487, 2385}},
-{1688, 14, 6282, {1, 3, 7, 3, 17, 3, 97, 143, 465, 345, 1457, 2201, 5329, 359}},
-{1689, 14, 6284, {1, 3, 7, 11, 1, 15, 3, 115, 335, 567, 1749, 1811, 3491, 15939}},
-{1690, 14, 6296, {1, 1, 3, 13, 3, 21, 7, 141, 149, 571, 1877, 473, 2143, 9569}},
-{1691, 14, 6299, {1, 3, 3, 11, 23, 61, 47, 179, 297, 453, 181, 3405, 2981, 13409}},
-{1692, 14, 6302, {1, 3, 1, 13, 1, 43, 5, 201, 371, 1003, 367, 2709, 7675, 14973}},
-{1693, 14, 6325, {1, 3, 3, 15, 29, 17, 19, 241, 495, 317, 1135, 2227, 6457, 4783}},
-{1694, 14, 6349, {1, 3, 3, 7, 29, 9, 57, 95, 261, 531, 1717, 3389, 7991, 3793}},
-{1695, 14, 6352, {1, 1, 1, 5, 31, 43, 73, 119, 499, 589, 1529, 3337, 4097, 15641}},
-{1696, 14, 6362, {1, 1, 7, 9, 29, 43, 127, 91, 243, 979, 1325, 2835, 2787, 9445}},
-{1697, 14, 6383, {1, 1, 7, 5, 9, 3, 115, 199, 219, 901, 747, 1077, 3197, 2443}},
-{1698, 14, 6386, {1, 3, 5, 1, 3, 43, 7, 117, 297, 313, 1043, 1579, 5099, 13289}},
-{1699, 14, 6395, {1, 1, 7, 11, 29, 33, 15, 121, 131, 579, 317, 1871, 1121, 11653}},
-{1700, 14, 6397, {1, 1, 5, 9, 25, 25, 43, 89, 355, 1011, 1385, 2901, 6387, 1653}},
-{1701, 14, 6415, {1, 1, 1, 9, 5, 47, 61, 165, 85, 757, 1397, 1177, 1657, 4899}},
-{1702, 14, 6424, {1, 1, 3, 9, 11, 49, 15, 139, 261, 613, 931, 1299, 2777, 2835}},
-{1703, 14, 6429, {1, 1, 1, 5, 3, 55, 83, 227, 125, 581, 1607, 1171, 6681, 14463}},
-{1704, 14, 6439, {1, 3, 5, 13, 5, 55, 3, 247, 493, 155, 1073, 3743, 5719, 4019}},
-{1705, 14, 6451, {1, 1, 7, 1, 11, 23, 13, 75, 399, 847, 499, 1643, 6977, 3699}},
-{1706, 14, 6489, {1, 3, 1, 9, 11, 41, 47, 131, 313, 627, 481, 2469, 3281, 979}},
-{1707, 14, 6496, {1, 3, 5, 13, 29, 3, 65, 101, 11, 29, 1807, 153, 1487, 16109}},
-{1708, 14, 6502, {1, 1, 5, 9, 13, 31, 83, 195, 351, 355, 467, 3871, 3085, 4441}},
-{1709, 14, 6511, {1, 3, 5, 3, 19, 21, 111, 179, 143, 361, 1619, 1547, 3409, 6905}},
-{1710, 14, 6514, {1, 1, 5, 9, 31, 1, 93, 199, 491, 135, 1627, 2559, 1389, 14561}},
-{1711, 14, 6520, {1, 3, 3, 9, 25, 53, 3, 105, 39, 445, 259, 1045, 1129, 9153}},
-{1712, 14, 6523, {1, 1, 5, 9, 19, 63, 71, 9, 73, 435, 1377, 4015, 1821, 6453}},
-{1713, 14, 6529, {1, 3, 7, 13, 19, 13, 37, 247, 391, 23, 1491, 1257, 6395, 237}},
-{1714, 14, 6532, {1, 1, 3, 3, 19, 55, 109, 23, 227, 747, 729, 2221, 727, 2209}},
-{1715, 14, 6547, {1, 1, 5, 11, 25, 21, 75, 37, 219, 355, 1005, 1895, 7039, 5225}},
-{1716, 14, 6549, {1, 3, 5, 13, 11, 43, 9, 67, 87, 797, 1077, 245, 4521, 11845}},
-{1717, 14, 6598, {1, 3, 5, 3, 15, 29, 127, 237, 277, 373, 1859, 3083, 587, 1123}},
-{1718, 14, 6601, {1, 1, 7, 15, 13, 7, 103, 53, 13, 965, 1497, 775, 3439, 1501}},
-{1719, 14, 6610, {1, 3, 3, 15, 17, 13, 97, 169, 67, 953, 189, 2739, 1459, 10543}},
-{1720, 14, 6622, {1, 1, 5, 1, 17, 39, 15, 127, 327, 989, 1471, 3235, 2801, 15311}},
-{1721, 14, 6632, {1, 1, 1, 15, 5, 37, 55, 155, 47, 463, 1851, 3467, 2765, 9359}},
-{1722, 14, 6655, {1, 3, 3, 15, 1, 13, 93, 239, 291, 115, 365, 61, 395, 15853}},
-{1723, 14, 6665, {1, 1, 5, 1, 19, 27, 61, 95, 105, 369, 1557, 961, 6917, 3621}},
-{1724, 14, 6666, {1, 3, 3, 9, 7, 35, 115, 53, 111, 345, 1145, 1687, 3401, 12107}},
-{1725, 14, 6695, {1, 1, 1, 5, 7, 31, 63, 19, 373, 79, 1369, 3037, 2835, 4439}},
-{1726, 14, 6701, {1, 3, 7, 9, 11, 17, 29, 33, 331, 447, 1981, 3333, 6535, 6557}},
-{1727, 14, 6709, {1, 3, 3, 5, 11, 41, 29, 43, 365, 279, 1919, 945, 179, 1987}},
-{1728, 14, 6710, {1, 3, 1, 13, 7, 7, 25, 33, 103, 367, 1267, 763, 5691, 8643}},
-{1729, 14, 6741, {1, 3, 1, 5, 11, 15, 3, 213, 511, 211, 1069, 4047, 3335, 12729}},
-{1730, 14, 6745, {1, 1, 3, 1, 5, 11, 27, 201, 361, 537, 679, 3709, 293, 2997}},
-{1731, 14, 6758, {1, 1, 3, 1, 25, 15, 19, 185, 369, 577, 1625, 655, 2363, 3861}},
-{1732, 14, 6767, {1, 1, 5, 5, 1, 47, 61, 45, 411, 597, 955, 1007, 3775, 5809}},
-{1733, 14, 6772, {1, 1, 5, 3, 27, 51, 101, 167, 429, 333, 1703, 3541, 2947, 3695}},
-{1734, 14, 6782, {1, 3, 5, 5, 1, 53, 17, 63, 141, 215, 1223, 3129, 635, 15919}},
-{1735, 14, 6797, {1, 3, 3, 1, 23, 31, 25, 11, 195, 241, 995, 3941, 573, 13855}},
-{1736, 14, 6800, {1, 3, 3, 7, 17, 13, 71, 203, 465, 479, 1857, 1493, 8067, 7113}},
-{1737, 14, 6843, {1, 1, 5, 3, 11, 57, 9, 59, 225, 691, 425, 2423, 6031, 6631}},
-{1738, 14, 6845, {1, 3, 7, 1, 29, 57, 103, 123, 401, 807, 471, 2759, 5113, 15937}},
-{1739, 14, 6860, {1, 3, 1, 1, 3, 1, 67, 123, 157, 655, 519, 323, 1853, 15041}},
-{1740, 14, 6865, {1, 1, 7, 5, 11, 11, 105, 135, 247, 689, 1141, 2347, 7113, 9347}},
-{1741, 14, 6878, {1, 1, 3, 11, 15, 37, 87, 3, 209, 575, 1521, 3863, 3893, 211}},
-{1742, 14, 6887, {1, 3, 1, 3, 29, 55, 115, 31, 19, 195, 985, 3275, 363, 9801}},
-{1743, 14, 6888, {1, 1, 3, 9, 13, 31, 57, 251, 201, 275, 1751, 389, 1463, 13159}},
-{1744, 14, 6901, {1, 3, 5, 15, 19, 51, 127, 255, 397, 243, 29, 3007, 7845, 4687}},
-{1745, 14, 6906, {1, 1, 7, 15, 9, 37, 39, 217, 509, 137, 1123, 3361, 6323, 5323}},
-{1746, 14, 6940, {1, 3, 7, 5, 25, 3, 93, 203, 345, 581, 261, 2811, 4829, 6977}},
-{1747, 14, 6947, {1, 1, 7, 1, 15, 41, 51, 227, 447, 893, 1209, 3865, 5229, 4277}},
-{1748, 14, 6953, {1, 1, 1, 5, 31, 19, 23, 195, 359, 853, 595, 337, 2503, 16371}},
-{1749, 14, 6954, {1, 3, 7, 5, 5, 13, 89, 157, 351, 777, 151, 3565, 4219, 7423}},
-{1750, 14, 6959, {1, 1, 1, 5, 7, 1, 9, 89, 175, 909, 1523, 2295, 7949, 6739}},
-{1751, 14, 6961, {1, 3, 5, 15, 27, 17, 11, 235, 19, 105, 457, 465, 3819, 11335}},
-{1752, 14, 6964, {1, 3, 1, 13, 3, 41, 85, 221, 451, 613, 543, 2265, 6831, 1725}},
-{1753, 14, 6991, {1, 1, 7, 7, 3, 29, 9, 197, 455, 665, 343, 1811, 5395, 393}},
-{1754, 14, 6993, {1, 1, 3, 13, 29, 55, 71, 95, 475, 615, 2029, 123, 413, 16127}},
-{1755, 14, 6999, {1, 1, 5, 9, 15, 61, 9, 51, 105, 271, 511, 2801, 693, 11839}},
-{1756, 14, 7016, {1, 1, 7, 13, 29, 9, 105, 59, 377, 635, 717, 4033, 6963, 10541}},
-{1757, 14, 7029, {1, 1, 1, 13, 7, 13, 59, 17, 335, 355, 77, 3665, 7003, 9521}},
-{1758, 14, 7036, {1, 3, 1, 1, 23, 43, 51, 209, 151, 365, 1021, 2859, 3937, 2899}},
-{1759, 14, 7045, {1, 1, 3, 3, 31, 41, 111, 107, 171, 433, 1233, 505, 2971, 6927}},
-{1760, 14, 7076, {1, 3, 7, 13, 17, 25, 127, 195, 257, 551, 1867, 2145, 3695, 14567}},
-{1761, 14, 7083, {1, 1, 5, 13, 13, 45, 39, 195, 55, 991, 1981, 1043, 5875, 581}},
-{1762, 14, 7094, {1, 3, 3, 11, 25, 31, 91, 153, 415, 449, 1301, 563, 7755, 10671}},
-{1763, 14, 7097, {1, 1, 3, 5, 31, 63, 1, 157, 229, 949, 971, 137, 6589, 8387}},
-{1764, 14, 7123, {1, 3, 7, 15, 25, 7, 89, 133, 73, 497, 1361, 613, 455, 1005}},
-{1765, 14, 7130, {1, 3, 3, 1, 13, 5, 119, 93, 175, 511, 1923, 763, 7573, 7545}},
-{1766, 14, 7139, {1, 1, 3, 15, 27, 59, 49, 205, 497, 485, 117, 2523, 4495, 15153}},
-{1767, 14, 7145, {1, 3, 7, 9, 15, 47, 111, 31, 363, 11, 475, 2931, 6813, 1259}},
-{1768, 14, 7146, {1, 1, 5, 5, 1, 35, 95, 225, 17, 991, 809, 2601, 6455, 13803}},
-{1769, 14, 7178, {1, 1, 5, 5, 15, 1, 1, 171, 433, 887, 1813, 3431, 2471, 7803}},
-{1770, 14, 7186, {1, 3, 3, 15, 1, 15, 43, 179, 15, 949, 1881, 1027, 6989, 8955}},
-{1771, 14, 7192, {1, 3, 7, 13, 1, 3, 49, 183, 373, 175, 1733, 913, 929, 1065}},
-{1772, 14, 7198, {1, 3, 5, 7, 15, 51, 107, 115, 323, 357, 167, 2069, 7541, 9601}},
-{1773, 14, 7222, {1, 1, 3, 5, 5, 21, 31, 107, 21, 299, 1937, 43, 3673, 8155}},
-{1774, 14, 7269, {1, 3, 5, 11, 9, 55, 35, 113, 29, 99, 161, 1607, 8141, 4951}},
-{1775, 14, 7270, {1, 3, 7, 15, 25, 7, 113, 179, 213, 19, 1717, 1027, 2021, 11263}},
-{1776, 14, 7276, {1, 1, 5, 1, 31, 33, 85, 111, 67, 95, 2013, 2217, 871, 5329}},
-{1777, 14, 7287, {1, 1, 1, 7, 7, 63, 67, 145, 495, 419, 1945, 3437, 6255, 151}},
-{1778, 14, 7307, {1, 3, 5, 7, 17, 37, 97, 187, 215, 399, 1603, 2195, 5923, 769}},
-{1779, 14, 7315, {1, 1, 3, 9, 25, 1, 119, 193, 385, 861, 2005, 2769, 675, 767}},
-{1780, 14, 7334, {1, 3, 1, 15, 19, 7, 5, 227, 173, 383, 289, 461, 579, 3689}},
-{1781, 14, 7340, {1, 3, 1, 11, 1, 37, 93, 239, 465, 891, 1479, 921, 4439, 15265}},
-{1782, 14, 7351, {1, 1, 1, 13, 27, 61, 99, 69, 279, 655, 1853, 1593, 6319, 9003}},
-{1783, 14, 7352, {1, 1, 1, 11, 5, 7, 19, 7, 387, 303, 321, 931, 5809, 16029}},
-{1784, 14, 7357, {1, 1, 1, 15, 21, 55, 43, 107, 217, 687, 19, 3225, 3419, 9991}},
-{1785, 14, 7360, {1, 1, 7, 5, 7, 55, 79, 41, 317, 357, 859, 1205, 191, 9395}},
-{1786, 14, 7363, {1, 1, 3, 11, 3, 43, 7, 133, 115, 995, 1205, 1055, 4153, 10481}},
-{1787, 14, 7384, {1, 1, 7, 11, 31, 57, 53, 9, 459, 223, 1969, 3513, 7033, 8505}},
-{1788, 14, 7396, {1, 1, 3, 7, 17, 11, 115, 255, 281, 97, 1685, 2039, 2845, 11637}},
-{1789, 14, 7403, {1, 3, 7, 1, 23, 41, 69, 199, 53, 105, 657, 1453, 4429, 1101}},
-{1790, 14, 7406, {1, 3, 1, 5, 11, 33, 91, 131, 191, 73, 823, 117, 1053, 127}},
-{1791, 14, 7425, {1, 3, 7, 11, 7, 3, 21, 65, 187, 103, 1393, 1797, 6673, 1409}},
-{1792, 14, 7437, {1, 3, 7, 1, 31, 25, 25, 161, 299, 275, 417, 2267, 6861, 1255}},
-{1793, 14, 7445, {1, 3, 5, 13, 5, 11, 61, 155, 115, 1001, 747, 889, 3235, 5709}},
-{1794, 14, 7450, {1, 3, 7, 7, 7, 1, 97, 177, 507, 273, 1781, 3455, 5123, 15607}},
-{1795, 14, 7455, {1, 1, 7, 5, 1, 7, 59, 49, 147, 343, 97, 3517, 5611, 8705}},
-{1796, 14, 7461, {1, 1, 5, 13, 21, 29, 13, 21, 503, 515, 1217, 3905, 5513, 15849}},
-{1797, 14, 7466, {1, 3, 1, 9, 9, 39, 65, 111, 385, 757, 583, 2225, 2039, 2817}},
-{1798, 14, 7488, {1, 3, 3, 15, 23, 17, 63, 169, 503, 949, 849, 461, 6799, 669}},
-{1799, 14, 7494, {1, 1, 1, 3, 1, 41, 63, 159, 251, 457, 521, 1653, 623, 3287}},
-{1800, 14, 7515, {1, 1, 7, 3, 9, 1, 41, 37, 441, 921, 1415, 2955, 5841, 1451}},
-{1801, 14, 7517, {1, 1, 5, 11, 23, 29, 89, 185, 413, 357, 1131, 2369, 3835, 6233}},
-{1802, 14, 7521, {1, 1, 5, 15, 27, 35, 17, 73, 315, 911, 1761, 797, 5349, 3219}},
-{1803, 14, 7536, {1, 3, 7, 11, 21, 9, 119, 233, 249, 901, 189, 3625, 2691, 16201}},
-{1804, 14, 7546, {1, 3, 3, 13, 29, 61, 105, 145, 187, 79, 609, 321, 4289, 3933}},
-{1805, 14, 7569, {1, 3, 1, 15, 19, 63, 13, 185, 115, 219, 1021, 1205, 4273, 11521}},
-{1806, 14, 7591, {1, 1, 3, 3, 23, 31, 93, 153, 87, 947, 1039, 469, 4047, 8869}},
-{1807, 14, 7592, {1, 1, 1, 1, 9, 1, 85, 3, 15, 995, 455, 2769, 6781, 16203}},
-{1808, 14, 7598, {1, 1, 3, 3, 13, 7, 55, 215, 185, 367, 765, 441, 4497, 1521}},
-{1809, 14, 7612, {1, 1, 1, 5, 1, 31, 13, 95, 417, 735, 975, 3407, 4871, 16133}},
-{1810, 14, 7623, {1, 1, 3, 3, 5, 43, 111, 107, 419, 515, 1075, 3597, 1187, 4143}},
-{1811, 14, 7632, {1, 1, 3, 13, 31, 51, 83, 163, 489, 887, 863, 599, 9, 13861}},
-{1812, 14, 7637, {1, 3, 3, 3, 19, 27, 91, 115, 103, 969, 593, 3667, 1867, 15433}},
-{1813, 14, 7644, {1, 3, 3, 13, 7, 25, 47, 141, 57, 553, 1785, 1709, 7453, 2209}},
-{1814, 14, 7657, {1, 3, 1, 13, 11, 13, 71, 219, 5, 451, 2043, 1605, 6439, 12203}},
-{1815, 14, 7665, {1, 3, 1, 13, 5, 57, 61, 223, 401, 413, 321, 1365, 619, 12477}},
-{1816, 14, 7672, {1, 3, 1, 5, 25, 57, 89, 211, 195, 455, 1165, 3979, 6313, 5751}},
-{1817, 14, 7682, {1, 1, 1, 9, 31, 23, 71, 145, 89, 285, 1593, 1171, 5685, 15459}},
-{1818, 14, 7699, {1, 3, 7, 7, 9, 41, 65, 251, 65, 137, 1577, 3027, 5555, 2865}},
-{1819, 14, 7702, {1, 1, 5, 13, 27, 5, 125, 21, 171, 647, 983, 2921, 6623, 5695}},
-{1820, 14, 7724, {1, 1, 1, 13, 15, 9, 117, 197, 123, 953, 1191, 3657, 5757, 15957}},
-{1821, 14, 7749, {1, 1, 3, 7, 29, 13, 5, 175, 395, 127, 679, 255, 6055, 7639}},
-{1822, 14, 7753, {1, 3, 7, 15, 15, 51, 77, 147, 319, 147, 1775, 3983, 3175, 5723}},
-{1823, 14, 7754, {1, 3, 3, 3, 7, 11, 119, 41, 43, 153, 975, 679, 3081, 10359}},
-{1824, 14, 7761, {1, 1, 5, 13, 3, 7, 65, 67, 63, 399, 1561, 2789, 2083, 12289}},
-{1825, 14, 7771, {1, 1, 7, 3, 19, 53, 103, 67, 35, 865, 161, 93, 2533, 3851}},
-{1826, 14, 7777, {1, 1, 1, 11, 31, 9, 29, 189, 199, 817, 1571, 395, 345, 3777}},
-{1827, 14, 7784, {1, 3, 5, 11, 31, 3, 9, 67, 277, 735, 181, 2777, 3009, 7233}},
-{1828, 14, 7804, {1, 1, 3, 3, 17, 7, 17, 3, 375, 933, 237, 3919, 5409, 3355}},
-{1829, 14, 7807, {1, 3, 3, 5, 9, 27, 19, 77, 221, 3, 1965, 309, 3001, 15977}},
-{1830, 14, 7808, {1, 1, 5, 1, 3, 33, 35, 133, 37, 709, 627, 1705, 2525, 4307}},
-{1831, 14, 7818, {1, 1, 7, 3, 25, 21, 105, 55, 375, 681, 881, 1299, 5879, 459}},
-{1832, 14, 7835, {1, 3, 7, 1, 13, 7, 113, 103, 313, 515, 1041, 3683, 4619, 5093}},
-{1833, 14, 7842, {1, 1, 3, 7, 19, 43, 83, 37, 39, 133, 1759, 1171, 1521, 13717}},
-{1834, 14, 7865, {1, 1, 7, 13, 7, 35, 15, 155, 293, 1001, 157, 3883, 405, 1797}},
-{1835, 14, 7868, {1, 1, 3, 3, 13, 19, 125, 49, 333, 387, 339, 1815, 4503, 7359}},
-{1836, 14, 7880, {1, 1, 3, 13, 19, 19, 105, 225, 151, 27, 1251, 885, 4815, 7863}},
-{1837, 14, 7883, {1, 1, 1, 5, 7, 59, 17, 145, 77, 117, 1355, 1429, 2301, 16177}},
-{1838, 14, 7891, {1, 3, 3, 13, 5, 31, 119, 167, 459, 727, 1799, 2537, 695, 13637}},
-{1839, 14, 7897, {1, 3, 3, 3, 27, 51, 107, 85, 267, 57, 1279, 823, 6247, 3603}},
-{1840, 14, 7907, {1, 1, 7, 15, 29, 17, 67, 197, 215, 465, 109, 3461, 5269, 15287}},
-{1841, 14, 7910, {1, 1, 3, 5, 11, 15, 123, 53, 293, 797, 1105, 1777, 6509, 217}},
-{1842, 14, 7924, {1, 3, 3, 13, 3, 5, 109, 53, 203, 693, 871, 135, 369, 11149}},
-{1843, 14, 7933, {1, 3, 5, 15, 17, 43, 81, 235, 119, 817, 1777, 261, 8049, 4251}},
-{1844, 14, 7934, {1, 1, 3, 7, 7, 13, 87, 99, 481, 931, 1507, 651, 5267, 8281}},
-{1845, 14, 7942, {1, 3, 1, 13, 27, 43, 77, 225, 341, 163, 933, 429, 4943, 7781}},
-{1846, 14, 7948, {1, 1, 7, 1, 1, 49, 85, 211, 449, 479, 1395, 787, 5653, 14891}},
-{1847, 14, 7959, {1, 1, 5, 9, 25, 13, 49, 85, 125, 85, 1281, 3365, 4305, 11791}},
-{1848, 14, 7984, {1, 3, 1, 13, 3, 31, 117, 39, 43, 151, 663, 669, 1571, 5207}},
-{1849, 14, 7994, {1, 3, 7, 15, 17, 7, 79, 163, 37, 841, 1799, 1787, 4501, 3785}},
-{1850, 14, 7999, {1, 1, 3, 9, 1, 23, 67, 191, 449, 931, 1521, 2705, 887, 7037}},
-{1851, 14, 8014, {1, 1, 1, 1, 5, 13, 55, 161, 419, 577, 1703, 2589, 2651, 2873}},
-{1852, 14, 8021, {1, 3, 3, 3, 5, 19, 37, 169, 69, 1003, 1755, 3101, 1469, 8583}},
-{1853, 14, 8041, {1, 1, 1, 1, 11, 33, 105, 79, 283, 91, 299, 835, 3193, 5593}},
-{1854, 14, 8049, {1, 3, 3, 13, 25, 21, 81, 213, 465, 475, 331, 457, 61, 9511}},
-{1855, 14, 8050, {1, 1, 3, 11, 1, 11, 77, 95, 455, 949, 1999, 1833, 1275, 5631}},
-{1856, 14, 8068, {1, 1, 1, 1, 15, 25, 51, 137, 275, 451, 1179, 3595, 5177, 7105}},
-{1857, 14, 8080, {1, 3, 3, 3, 3, 59, 79, 143, 393, 583, 349, 3039, 7079, 14245}},
-{1858, 14, 8095, {1, 1, 7, 9, 21, 11, 123, 105, 53, 297, 803, 4025, 5421, 14527}},
-{1859, 14, 8102, {1, 3, 7, 11, 21, 15, 103, 109, 311, 321, 1217, 2777, 5457, 1823}},
-{1860, 14, 8106, {1, 3, 5, 11, 19, 31, 79, 89, 295, 413, 817, 499, 3699, 14411}},
-{1861, 14, 8120, {1, 1, 1, 5, 11, 3, 81, 13, 315, 841, 1543, 411, 6883, 6347}},
-{1862, 14, 8133, {1, 3, 3, 11, 23, 43, 23, 131, 17, 517, 995, 2687, 7443, 15085}},
-{1863, 14, 8134, {1, 1, 1, 1, 11, 57, 73, 9, 123, 905, 1763, 1789, 3701, 7131}},
-{1864, 14, 8143, {1, 1, 3, 5, 9, 53, 99, 229, 43, 207, 625, 1583, 6727, 15249}},
-{1865, 14, 8162, {1, 1, 7, 7, 17, 39, 91, 1, 297, 711, 225, 513, 7391, 291}},
-{1866, 14, 8168, {1, 1, 7, 11, 7, 55, 111, 129, 423, 521, 1807, 3015, 1449, 12321}},
-{1867, 14, 8179, {1, 3, 7, 3, 13, 9, 125, 187, 11, 485, 647, 275, 3495, 11989}},
-{1868, 15, 1, {1, 1, 3, 11, 11, 25, 49, 33, 361, 105, 271, 3841, 4837, 2437, 30181}},
-{1869, 15, 8, {1, 3, 5, 1, 27, 15, 119, 35, 159, 273, 1489, 3157, 5433, 3337, 26859}},
-{1870, 15, 11, {1, 3, 5, 13, 23, 31, 97, 145, 41, 605, 1455, 59, 5389, 5527, 14447}},
-{1871, 15, 22, {1, 1, 7, 9, 7, 41, 61, 193, 353, 879, 1805, 581, 5447, 11177, 7331}},
-{1872, 15, 26, {1, 1, 7, 11, 29, 19, 55, 207, 361, 759, 63, 2255, 2119, 14671, 21783}},
-{1873, 15, 47, {1, 3, 1, 13, 17, 7, 73, 179, 103, 23, 917, 1205, 4925, 1691, 5419}},
-{1874, 15, 59, {1, 3, 5, 3, 15, 3, 9, 109, 227, 861, 867, 3529, 1535, 489, 22873}},
-{1875, 15, 64, {1, 3, 3, 9, 15, 15, 95, 193, 385, 997, 1525, 1865, 1425, 4079, 14771}},
-{1876, 15, 67, {1, 1, 3, 5, 5, 29, 49, 171, 171, 623, 1167, 3743, 1809, 12009, 7043}},
-{1877, 15, 73, {1, 3, 7, 5, 23, 11, 87, 183, 299, 555, 1857, 489, 3505, 9161, 28763}},
-{1878, 15, 82, {1, 3, 5, 9, 19, 21, 85, 127, 337, 439, 1183, 1891, 1877, 4373, 10451}},
-{1879, 15, 97, {1, 3, 7, 13, 27, 17, 29, 83, 463, 385, 1167, 3453, 4523, 4759, 9321}},
-{1880, 15, 103, {1, 1, 3, 7, 21, 59, 65, 83, 177, 763, 317, 2913, 7527, 5967, 17167}},
-{1881, 15, 110, {1, 1, 7, 15, 13, 27, 49, 35, 253, 101, 1699, 355, 2181, 10859, 24221}},
-{1882, 15, 115, {1, 1, 5, 1, 17, 17, 81, 91, 349, 655, 1373, 2225, 945, 899, 31801}},
-{1883, 15, 122, {1, 3, 7, 11, 5, 1, 81, 53, 215, 587, 167, 4045, 5671, 5597, 13529}},
-{1884, 15, 128, {1, 3, 5, 15, 1, 9, 59, 235, 315, 195, 909, 2237, 505, 10415, 28145}},
-{1885, 15, 138, {1, 1, 1, 3, 9, 31, 41, 43, 275, 921, 25, 671, 5737, 11241, 4193}},
-{1886, 15, 146, {1, 3, 3, 13, 29, 13, 95, 213, 317, 995, 1489, 3779, 3043, 8569, 28823}},
-{1887, 15, 171, {1, 1, 7, 5, 9, 49, 125, 241, 87, 153, 1673, 3849, 7253, 1715, 11627}},
-{1888, 15, 174, {1, 1, 3, 9, 27, 27, 19, 223, 63, 463, 1095, 1395, 6643, 11589, 2145}},
-{1889, 15, 176, {1, 1, 3, 15, 21, 17, 45, 23, 357, 11, 1307, 1791, 2481, 2123, 24341}},
-{1890, 15, 182, {1, 3, 5, 15, 31, 53, 117, 51, 433, 193, 1239, 3329, 2403, 12745, 32219}},
-{1891, 15, 194, {1, 1, 5, 9, 7, 27, 9, 115, 417, 579, 83, 173, 4717, 15665, 27463}},
-{1892, 15, 208, {1, 3, 5, 7, 9, 9, 31, 35, 249, 567, 331, 905, 5101, 14817, 14255}},
-{1893, 15, 211, {1, 3, 7, 3, 1, 61, 29, 129, 119, 421, 1597, 2987, 3041, 7629, 23451}},
-{1894, 15, 220, {1, 1, 7, 9, 13, 1, 99, 105, 107, 509, 989, 2259, 1009, 6827, 8903}},
-{1895, 15, 229, {1, 3, 5, 15, 11, 29, 85, 29, 265, 105, 2035, 3349, 3543, 13903, 10213}},
-{1896, 15, 230, {1, 3, 1, 1, 25, 19, 53, 139, 467, 485, 491, 3067, 7353, 13861, 25819}},
-{1897, 15, 239, {1, 1, 5, 3, 3, 43, 41, 185, 45, 463, 351, 2823, 2519, 6705, 11395}},
-{1898, 15, 254, {1, 3, 7, 13, 11, 15, 87, 221, 427, 673, 1631, 599, 3259, 10691, 31283}},
-{1899, 15, 265, {1, 3, 5, 11, 9, 9, 15, 49, 275, 335, 1613, 3587, 5309, 14849, 26475}},
-{1900, 15, 285, {1, 3, 7, 9, 29, 13, 79, 225, 381, 781, 1411, 2761, 7157, 14983, 19717}},
-{1901, 15, 290, {1, 1, 7, 11, 29, 25, 117, 183, 101, 651, 653, 3157, 445, 14389, 23293}},
-{1902, 15, 319, {1, 1, 1, 3, 5, 33, 73, 155, 473, 387, 591, 2045, 5965, 16299, 31499}},
-{1903, 15, 324, {1, 3, 1, 7, 11, 33, 29, 21, 491, 937, 729, 4075, 975, 2461, 18991}},
-{1904, 15, 327, {1, 3, 7, 15, 29, 39, 105, 111, 173, 943, 69, 295, 8175, 13037, 26131}},
-{1905, 15, 333, {1, 1, 5, 15, 7, 5, 97, 147, 105, 887, 443, 2595, 5889, 10753, 1619}},
-{1906, 15, 357, {1, 3, 3, 15, 11, 45, 87, 207, 353, 909, 1847, 323, 2283, 12885, 16415}},
-{1907, 15, 364, {1, 1, 5, 3, 19, 33, 43, 79, 115, 653, 359, 2873, 4609, 12439, 6339}},
-{1908, 15, 395, {1, 3, 7, 9, 17, 61, 49, 227, 291, 69, 1753, 3899, 483, 3187, 29041}},
-{1909, 15, 397, {1, 3, 5, 3, 25, 35, 61, 211, 393, 199, 691, 1779, 6295, 13371, 15817}},
-{1910, 15, 405, {1, 3, 7, 5, 7, 23, 37, 91, 245, 915, 579, 867, 6193, 1063, 17363}},
-{1911, 15, 409, {1, 3, 7, 7, 23, 51, 41, 63, 375, 3, 159, 1889, 4419, 1687, 17977}},
-{1912, 15, 419, {1, 1, 1, 7, 13, 11, 53, 43, 317, 325, 1749, 2423, 4123, 8595, 20773}},
-{1913, 15, 422, {1, 1, 7, 7, 9, 9, 61, 113, 437, 213, 1407, 645, 4345, 807, 30411}},
-{1914, 15, 431, {1, 3, 3, 11, 17, 39, 17, 113, 391, 385, 581, 2023, 7449, 10153, 22033}},
-{1915, 15, 433, {1, 1, 3, 5, 29, 31, 101, 215, 379, 377, 1113, 2855, 7147, 14377, 25515}},
-{1916, 15, 436, {1, 3, 5, 5, 13, 3, 121, 125, 227, 969, 11, 1115, 5657, 9209, 6117}},
-{1917, 15, 440, {1, 3, 7, 15, 29, 17, 33, 123, 317, 301, 749, 1365, 5619, 605, 1613}},
-{1918, 15, 453, {1, 3, 1, 15, 7, 53, 125, 249, 219, 655, 105, 2825, 1649, 12783, 19777}},
-{1919, 15, 460, {1, 1, 7, 1, 25, 53, 19, 53, 157, 373, 1855, 495, 5065, 9465, 2313}},
-{1920, 15, 471, {1, 3, 5, 13, 3, 57, 57, 161, 431, 415, 1859, 1033, 6349, 1577, 31579}},
-{1921, 15, 478, {1, 1, 7, 5, 23, 63, 29, 221, 13, 965, 1997, 2265, 1583, 10491, 9551}},
-{1922, 15, 482, {1, 1, 3, 13, 31, 25, 23, 61, 285, 5, 2005, 879, 795, 13299, 19685}},
-{1923, 15, 488, {1, 1, 7, 1, 21, 45, 121, 89, 263, 543, 1333, 2711, 219, 10823, 26139}},
-{1924, 15, 524, {1, 1, 3, 3, 27, 13, 19, 117, 161, 457, 1541, 295, 4953, 12125, 14503}},
-{1925, 15, 529, {1, 3, 5, 3, 7, 63, 13, 247, 439, 681, 977, 2537, 6923, 10323, 7349}},
-{1926, 15, 535, {1, 3, 5, 9, 3, 51, 81, 251, 349, 983, 581, 2515, 2281, 2849, 31915}},
-{1927, 15, 536, {1, 3, 5, 3, 11, 63, 47, 137, 303, 627, 91, 2269, 7097, 2145, 31059}},
-{1928, 15, 539, {1, 1, 3, 15, 13, 17, 53, 27, 133, 13, 117, 1837, 4103, 5843, 29153}},
-{1929, 15, 563, {1, 1, 5, 13, 21, 33, 37, 253, 465, 209, 309, 49, 3209, 15677, 14569}},
-{1930, 15, 566, {1, 1, 7, 15, 13, 21, 33, 203, 499, 141, 1155, 3893, 1663, 2115, 27459}},
-{1931, 15, 572, {1, 3, 5, 11, 21, 9, 39, 157, 257, 273, 1257, 1831, 515, 7969, 20133}},
-{1932, 15, 577, {1, 1, 3, 13, 19, 29, 15, 189, 103, 219, 1395, 517, 7425, 6585, 15865}},
-{1933, 15, 587, {1, 1, 5, 11, 21, 31, 49, 151, 39, 537, 1783, 3449, 6915, 223, 11587}},
-{1934, 15, 592, {1, 3, 3, 11, 7, 63, 69, 31, 27, 911, 1903, 2821, 7977, 12949, 32257}},
-{1935, 15, 602, {1, 1, 7, 9, 25, 45, 23, 233, 511, 595, 1383, 1721, 6789, 12055, 21179}},
-{1936, 15, 623, {1, 1, 7, 13, 1, 27, 123, 49, 439, 683, 501, 641, 1947, 6111, 25423}},
-{1937, 15, 635, {1, 3, 3, 5, 1, 23, 57, 241, 243, 593, 2039, 1617, 2209, 5171, 9675}},
-{1938, 15, 638, {1, 1, 1, 7, 5, 19, 83, 55, 481, 125, 177, 1021, 1139, 11403, 23099}},
-{1939, 15, 654, {1, 1, 3, 5, 29, 39, 33, 217, 461, 907, 733, 3795, 4811, 12939, 27715}},
-{1940, 15, 656, {1, 3, 7, 3, 7, 11, 39, 165, 495, 147, 999, 1827, 817, 603, 9293}},
-{1941, 15, 659, {1, 3, 7, 15, 25, 53, 35, 15, 431, 733, 1213, 2907, 8087, 3939, 27363}},
-{1942, 15, 665, {1, 3, 7, 13, 13, 9, 33, 27, 485, 183, 455, 3341, 2555, 4985, 8793}},
-{1943, 15, 675, {1, 1, 1, 15, 25, 47, 75, 21, 205, 15, 1639, 3067, 1295, 11693, 16903}},
-{1944, 15, 677, {1, 1, 1, 15, 3, 31, 93, 57, 43, 185, 251, 1899, 7885, 10829, 3609}},
-{1945, 15, 687, {1, 1, 3, 1, 29, 9, 69, 223, 221, 537, 365, 3411, 5771, 15279, 5309}},
-{1946, 15, 696, {1, 1, 7, 5, 1, 5, 125, 243, 213, 1003, 1571, 3355, 3981, 8781, 25993}},
-{1947, 15, 701, {1, 1, 1, 13, 7, 19, 53, 243, 301, 75, 1183, 2723, 6687, 13, 16581}},
-{1948, 15, 704, {1, 3, 1, 13, 17, 51, 91, 239, 437, 191, 1065, 2495, 5755, 3405, 8299}},
-{1949, 15, 710, {1, 1, 5, 5, 11, 59, 21, 169, 299, 123, 1845, 2199, 2157, 14461, 10327}},
-{1950, 15, 721, {1, 3, 7, 7, 19, 47, 51, 179, 41, 19, 1347, 2325, 8063, 5993, 15653}},
-{1951, 15, 728, {1, 1, 1, 9, 25, 27, 7, 133, 223, 533, 719, 353, 7093, 8285, 10375}},
-{1952, 15, 738, {1, 3, 5, 15, 31, 5, 67, 39, 441, 495, 977, 3699, 1435, 11385, 14567}},
-{1953, 15, 740, {1, 1, 3, 15, 15, 39, 25, 33, 91, 523, 249, 4035, 769, 5181, 9691}},
-{1954, 15, 749, {1, 1, 3, 3, 3, 57, 83, 187, 423, 165, 161, 3453, 2241, 981, 8429}},
-{1955, 15, 758, {1, 1, 7, 15, 1, 17, 57, 189, 283, 11, 823, 3505, 7025, 11879, 15441}},
-{1956, 15, 761, {1, 1, 3, 11, 1, 41, 7, 255, 385, 339, 607, 1405, 1473, 13697, 9491}},
-{1957, 15, 772, {1, 1, 7, 15, 5, 9, 91, 99, 211, 233, 51, 2663, 1165, 9283, 18495}},
-{1958, 15, 776, {1, 1, 3, 7, 21, 37, 13, 91, 39, 27, 1021, 2813, 5937, 6645, 3403}},
-{1959, 15, 782, {1, 3, 1, 1, 29, 29, 5, 69, 399, 665, 1407, 3921, 2653, 11753, 18925}},
-{1960, 15, 789, {1, 3, 7, 15, 13, 41, 39, 1, 437, 549, 161, 2315, 5631, 8335, 22661}},
-{1961, 15, 810, {1, 1, 3, 1, 7, 17, 115, 61, 69, 955, 475, 3763, 8035, 927, 17893}},
-{1962, 15, 812, {1, 3, 1, 13, 21, 59, 81, 145, 463, 145, 1941, 2777, 7453, 14229, 11281}},
-{1963, 15, 818, {1, 1, 1, 15, 15, 11, 27, 165, 461, 395, 1645, 3611, 7463, 12379, 26787}},
-{1964, 15, 830, {1, 1, 7, 9, 29, 19, 27, 123, 21, 149, 1643, 4001, 7207, 6769, 4647}},
-{1965, 15, 832, {1, 1, 1, 11, 13, 9, 103, 139, 185, 587, 591, 1113, 2223, 11667, 32671}},
-{1966, 15, 852, {1, 3, 1, 1, 31, 13, 19, 93, 229, 125, 1471, 2369, 3055, 10277, 28563}},
-{1967, 15, 855, {1, 3, 7, 5, 7, 53, 99, 175, 161, 851, 617, 4027, 2357, 11199, 1931}},
-{1968, 15, 859, {1, 3, 5, 11, 3, 31, 111, 179, 237, 845, 539, 1057, 259, 3417, 26637}},
-{1969, 15, 865, {1, 1, 5, 3, 21, 49, 125, 119, 463, 403, 737, 1811, 3941, 13015, 29081}},
-{1970, 15, 877, {1, 3, 5, 13, 5, 29, 69, 251, 313, 357, 663, 1097, 3307, 12845, 28495}},
-{1971, 15, 895, {1, 3, 3, 5, 29, 17, 89, 15, 411, 409, 2013, 757, 4085, 12521, 11131}},
-{1972, 15, 901, {1, 1, 1, 15, 7, 51, 3, 193, 493, 133, 381, 2027, 227, 6635, 12931}},
-{1973, 15, 902, {1, 1, 1, 15, 7, 23, 99, 203, 323, 1007, 1465, 2887, 2215, 1787, 22069}},
-{1974, 15, 906, {1, 1, 5, 9, 29, 59, 77, 151, 509, 313, 415, 3977, 5431, 8019, 8571}},
-{1975, 15, 916, {1, 3, 1, 15, 19, 13, 57, 217, 87, 119, 25, 1149, 5667, 3765, 6959}},
-{1976, 15, 920, {1, 3, 7, 13, 19, 31, 119, 3, 457, 117, 905, 361, 1483, 12405, 27005}},
-{1977, 15, 949, {1, 3, 5, 11, 15, 35, 61, 77, 119, 51, 1753, 2765, 1091, 10573, 23595}},
-{1978, 15, 962, {1, 3, 3, 7, 1, 35, 17, 93, 197, 511, 1253, 3031, 2739, 15127, 15147}},
-{1979, 15, 964, {1, 3, 3, 1, 11, 55, 55, 107, 161, 75, 129, 2195, 2023, 4877, 25797}},
-{1980, 15, 967, {1, 3, 5, 7, 23, 19, 113, 167, 167, 271, 1303, 125, 5057, 1323, 5165}},
-{1981, 15, 981, {1, 1, 5, 3, 21, 31, 11, 119, 215, 483, 1535, 407, 6485, 15401, 30297}},
-{1982, 15, 982, {1, 3, 5, 9, 21, 5, 77, 95, 443, 247, 913, 605, 365, 7465, 19707}},
-{1983, 15, 985, {1, 3, 1, 7, 17, 59, 9, 35, 391, 767, 1493, 475, 4725, 7529, 31579}},
-{1984, 15, 991, {1, 3, 3, 7, 31, 21, 61, 31, 421, 179, 273, 771, 5745, 10575, 32765}},
-{1985, 15, 1007, {1, 3, 5, 15, 27, 13, 125, 55, 423, 1021, 497, 3521, 6903, 15111, 8285}},
-{1986, 15, 1016, {1, 1, 5, 9, 13, 31, 105, 93, 421, 709, 643, 1079, 1533, 9149, 10799}},
-{1987, 15, 1024, {1, 3, 1, 11, 19, 29, 53, 199, 319, 247, 655, 3039, 6411, 12267, 14245}},
-{1988, 15, 1051, {1, 3, 1, 11, 9, 57, 5, 91, 469, 149, 259, 329, 5433, 6941, 15093}},
-{1989, 15, 1060, {1, 3, 1, 5, 5, 51, 59, 25, 455, 367, 1623, 441, 3155, 11695, 20767}},
-{1990, 15, 1070, {1, 3, 7, 7, 11, 49, 113, 95, 91, 389, 605, 1973, 2051, 2315, 22229}},
-{1991, 15, 1072, {1, 3, 5, 3, 19, 11, 99, 135, 433, 781, 1473, 885, 1105, 3573, 3739}},
-{1992, 15, 1084, {1, 3, 1, 11, 3, 25, 9, 227, 433, 723, 317, 139, 6627, 8067, 28439}},
-{1993, 15, 1089, {1, 1, 1, 9, 9, 9, 5, 63, 241, 215, 1991, 2949, 3943, 775, 31511}},
-{1994, 15, 1095, {1, 1, 3, 7, 17, 49, 35, 167, 131, 107, 1295, 2465, 4577, 11147, 29833}},
-{1995, 15, 1114, {1, 1, 5, 1, 5, 25, 119, 129, 391, 743, 1069, 2957, 349, 6891, 13635}},
-{1996, 15, 1123, {1, 3, 1, 7, 9, 31, 63, 253, 215, 51, 1347, 2361, 3125, 13049, 28461}},
-{1997, 15, 1132, {1, 1, 7, 9, 3, 31, 21, 163, 255, 47, 259, 535, 5461, 3349, 30649}},
-{1998, 15, 1154, {1, 3, 3, 13, 17, 33, 87, 47, 243, 709, 929, 3943, 3107, 3421, 13721}},
-{1999, 15, 1156, {1, 3, 5, 11, 25, 61, 61, 173, 397, 735, 2005, 3355, 8121, 11593, 27697}},
-{2000, 15, 1163, {1, 3, 5, 15, 17, 43, 63, 231, 275, 311, 1277, 2669, 7307, 2099, 9755}},
-{2001, 15, 1171, {1, 3, 5, 3, 25, 43, 71, 191, 9, 121, 1873, 3747, 7491, 14055, 24293}},
-{2002, 15, 1202, {1, 3, 5, 13, 17, 35, 113, 113, 385, 941, 39, 2705, 1225, 5167, 1373}},
-{2003, 15, 1228, {1, 3, 5, 5, 7, 35, 19, 105, 487, 71, 139, 627, 4187, 3183, 713}},
-{2004, 15, 1239, {1, 1, 5, 13, 29, 29, 103, 5, 157, 869, 1675, 423, 6689, 10697, 5303}},
-{2005, 15, 1255, {1, 1, 5, 1, 29, 31, 61, 111, 473, 963, 685, 1483, 2383, 8109, 8495}},
-{2006, 15, 1256, {1, 1, 5, 3, 19, 13, 95, 113, 217, 59, 1353, 1647, 3617, 3271, 2321}},
-{2007, 15, 1262, {1, 3, 5, 7, 25, 35, 59, 131, 309, 445, 415, 93, 1453, 8789, 30201}},
-{2008, 15, 1270, {1, 1, 5, 1, 5, 43, 71, 241, 123, 189, 831, 3469, 8093, 6187, 32721}},
-{2009, 15, 1279, {1, 3, 7, 5, 25, 31, 123, 171, 319, 379, 889, 2365, 4881, 12225, 16609}},
-{2010, 15, 1308, {1, 3, 1, 11, 27, 43, 121, 63, 291, 591, 811, 1995, 4777, 2083, 31385}},
-{2011, 15, 1322, {1, 1, 5, 11, 27, 53, 85, 187, 461, 823, 703, 399, 6925, 11517, 28697}},
-{2012, 15, 1329, {1, 1, 3, 5, 13, 11, 33, 121, 93, 717, 1275, 3877, 4247, 5845, 26909}},
-{2013, 15, 1330, {1, 3, 1, 9, 7, 5, 47, 199, 367, 561, 185, 2855, 5997, 2699, 7581}},
-{2014, 15, 1336, {1, 1, 5, 9, 23, 11, 71, 201, 61, 729, 1011, 3529, 663, 1413, 25675}},
-{2015, 15, 1341, {1, 3, 7, 13, 27, 21, 11, 127, 281, 487, 1217, 3129, 5541, 3129, 17783}},
-{2016, 15, 1347, {1, 1, 5, 9, 1, 29, 85, 193, 213, 743, 1473, 611, 391, 9405, 21137}},
-{2017, 15, 1349, {1, 3, 3, 3, 31, 63, 37, 147, 39, 351, 79, 3069, 2441, 8901, 8777}},
-{2018, 15, 1359, {1, 1, 7, 7, 25, 49, 55, 47, 441, 343, 1267, 1123, 5917, 14395, 10579}},
-{2019, 15, 1367, {1, 1, 7, 1, 13, 55, 55, 123, 103, 773, 125, 2145, 4743, 13347, 2589}},
-{2020, 15, 1368, {1, 3, 7, 3, 9, 33, 25, 183, 469, 213, 291, 75, 6725, 6847, 26745}},
-{2021, 15, 1390, {1, 3, 3, 7, 15, 43, 7, 79, 171, 21, 1767, 2537, 4285, 12007, 24039}},
-{2022, 15, 1413, {1, 3, 7, 13, 9, 61, 125, 23, 227, 879, 215, 1635, 2835, 883, 15939}},
-{2023, 15, 1414, {1, 1, 5, 13, 25, 45, 63, 43, 183, 829, 149, 989, 987, 3819, 12181}},
-{2024, 15, 1437, {1, 1, 3, 7, 19, 27, 35, 83, 135, 459, 785, 131, 2655, 3329, 3009}},
-{2025, 15, 1441, {1, 1, 7, 5, 11, 41, 9, 219, 475, 985, 1329, 3787, 1975, 4679, 8627}},
-{2026, 15, 1462, {1, 1, 7, 3, 1, 17, 91, 155, 3, 763, 1879, 233, 215, 2955, 25993}},
-{2027, 15, 1465, {1, 1, 1, 11, 25, 11, 23, 227, 453, 775, 1935, 3833, 4583, 269, 705}},
-{2028, 15, 1480, {1, 3, 3, 11, 7, 25, 105, 21, 449, 555, 1275, 3475, 5503, 15617, 813}},
-{2029, 15, 1486, {1, 3, 7, 13, 31, 37, 25, 255, 233, 663, 1155, 1563, 4775, 7449, 29949}},
-{2030, 15, 1504, {1, 1, 3, 1, 23, 51, 51, 137, 63, 809, 349, 2789, 6953, 10605, 18959}},
-{2031, 15, 1509, {1, 3, 3, 13, 21, 45, 15, 161, 393, 229, 437, 2967, 4019, 3893, 21305}},
-{2032, 15, 1514, {1, 1, 3, 7, 5, 11, 15, 211, 287, 131, 1847, 2569, 7881, 15669, 31037}},
-{2033, 15, 1522, {1, 3, 3, 15, 27, 19, 85, 251, 221, 639, 665, 3729, 5771, 7873, 28005}},
-{2034, 15, 1528, {1, 3, 7, 15, 15, 47, 93, 215, 343, 85, 1401, 1375, 2949, 13661, 25453}},
-{2035, 15, 1552, {1, 1, 1, 9, 7, 51, 53, 217, 471, 389, 551, 1141, 1767, 2237, 17797}},
-{2036, 15, 1555, {1, 1, 7, 9, 3, 29, 65, 29, 223, 591, 1719, 1049, 7643, 3853, 29867}},
-{2037, 15, 1571, {1, 1, 1, 11, 13, 41, 85, 29, 451, 387, 1783, 3733, 8033, 4711, 31643}},
-{2038, 15, 1578, {1, 3, 1, 11, 11, 57, 75, 153, 7, 373, 2011, 271, 469, 3267, 18969}},
-{2039, 15, 1585, {1, 1, 5, 3, 19, 43, 7, 243, 385, 293, 923, 843, 4895, 469, 8421}},
-{2040, 15, 1588, {1, 3, 1, 15, 29, 47, 17, 125, 471, 927, 349, 3859, 3059, 11483, 14791}},
-{2041, 15, 1603, {1, 3, 1, 11, 17, 17, 111, 109, 9, 213, 1313, 3903, 4411, 4329, 28277}},
-{2042, 15, 1609, {1, 3, 3, 15, 1, 55, 47, 69, 143, 789, 1149, 3833, 5053, 6949, 10569}},
-{2043, 15, 1617, {1, 3, 5, 7, 11, 15, 79, 83, 123, 937, 1115, 2775, 3041, 11869, 21167}},
-{2044, 15, 1620, {1, 3, 7, 13, 9, 47, 45, 221, 139, 923, 1661, 1379, 2485, 7233, 6035}},
-{2045, 15, 1629, {1, 1, 3, 3, 11, 55, 77, 3, 87, 693, 1991, 1145, 2783, 16207, 24569}},
-{2046, 15, 1636, {1, 1, 5, 11, 3, 35, 91, 9, 391, 927, 101, 1839, 3755, 10345, 16907}},
-{2047, 15, 1648, {1, 3, 5, 3, 5, 49, 79, 91, 205, 443, 1369, 197, 2537, 11219, 17765}},
-{2048, 15, 1667, {1, 1, 3, 15, 9, 7, 25, 25, 357, 247, 477, 421, 7679, 5987, 30079}},
-{2049, 15, 1669, {1, 1, 5, 3, 29, 5, 89, 117, 481, 491, 371, 389, 7101, 2253, 23617}},
-{2050, 15, 1682, {1, 1, 5, 13, 29, 59, 17, 181, 511, 291, 1991, 3499, 8177, 5559, 30045}},
-{2051, 15, 1697, {1, 3, 3, 11, 23, 31, 117, 217, 241, 115, 749, 945, 1897, 12253, 8473}},
-{2052, 15, 1704, {1, 1, 7, 15, 25, 47, 31, 1, 165, 311, 635, 3629, 1593, 8305, 30033}},
-{2053, 15, 1709, {1, 3, 5, 9, 3, 17, 101, 237, 379, 503, 49, 929, 1687, 3865, 26723}},
-{2054, 15, 1727, {1, 3, 5, 5, 15, 41, 1, 239, 53, 215, 1733, 827, 579, 4089, 6579}},
-{2055, 15, 1730, {1, 3, 1, 15, 15, 21, 35, 21, 403, 257, 1475, 2403, 4705, 11553, 203}},
-{2056, 15, 1732, {1, 3, 5, 11, 9, 53, 113, 9, 447, 511, 543, 3141, 7389, 11249, 431}},
-{2057, 15, 1741, {1, 3, 5, 9, 9, 11, 55, 93, 325, 411, 305, 2573, 6871, 12339, 6435}},
-{2058, 15, 1744, {1, 3, 3, 7, 31, 27, 21, 113, 99, 853, 365, 589, 3731, 10875, 12767}},
-{2059, 15, 1759, {1, 3, 1, 7, 15, 27, 31, 17, 275, 93, 1161, 2619, 1329, 7307, 587}},
-{2060, 15, 1765, {1, 3, 5, 9, 17, 47, 49, 237, 27, 193, 1237, 591, 5151, 5521, 31583}},
-{2061, 15, 1766, {1, 3, 5, 3, 13, 1, 27, 87, 43, 977, 305, 3293, 2475, 14571, 18321}},
-{2062, 15, 1778, {1, 1, 5, 7, 15, 13, 101, 1, 291, 807, 1711, 2277, 5573, 11051, 13133}},
-{2063, 15, 1780, {1, 3, 3, 1, 9, 3, 65, 81, 415, 733, 1527, 2747, 6069, 159, 7095}},
-{2064, 15, 1783, {1, 3, 3, 15, 27, 1, 71, 49, 231, 851, 2039, 613, 1899, 2537, 14511}},
-{2065, 15, 1797, {1, 1, 1, 11, 3, 41, 55, 23, 247, 1011, 581, 2363, 2745, 1337, 20931}},
-{2066, 15, 1807, {1, 1, 3, 11, 17, 61, 67, 255, 143, 357, 945, 3407, 5817, 4155, 23851}},
-{2067, 15, 1821, {1, 3, 5, 3, 23, 1, 75, 247, 265, 413, 1899, 2565, 6629, 15655, 16117}},
-{2068, 15, 1832, {1, 1, 1, 9, 11, 49, 11, 189, 223, 177, 1457, 1931, 163, 15905, 17297}},
-{2069, 15, 1835, {1, 3, 7, 13, 17, 1, 111, 189, 343, 961, 427, 2507, 2393, 8653, 6353}},
-{2070, 15, 1849, {1, 3, 7, 13, 23, 61, 59, 51, 313, 963, 791, 3681, 5637, 3965, 9263}},
-{2071, 15, 1850, {1, 3, 7, 7, 21, 53, 127, 141, 499, 859, 337, 2835, 3195, 4351, 32369}},
-{2072, 15, 1863, {1, 1, 7, 5, 1, 5, 53, 63, 497, 535, 35, 305, 4395, 9757, 13193}},
-{2073, 15, 1867, {1, 1, 5, 13, 13, 31, 59, 229, 211, 745, 1453, 3677, 3005, 7703, 23907}},
-{2074, 15, 1869, {1, 3, 5, 5, 7, 63, 17, 197, 493, 861, 499, 3015, 6349, 1815, 7437}},
-{2075, 15, 1872, {1, 1, 1, 13, 13, 37, 29, 189, 253, 1017, 321, 3145, 407, 7547, 17099}},
-{2076, 15, 1887, {1, 3, 3, 3, 23, 53, 69, 77, 175, 17, 1831, 841, 3851, 1295, 32107}},
-{2077, 15, 1888, {1, 3, 7, 13, 13, 39, 107, 237, 389, 729, 635, 3717, 3041, 3169, 14987}},
-{2078, 15, 1897, {1, 1, 3, 1, 25, 7, 69, 35, 495, 49, 659, 2783, 6051, 13875, 23927}},
-{2079, 15, 1906, {1, 3, 7, 5, 5, 25, 49, 7, 193, 493, 93, 657, 1515, 13975, 14155}},
-{2080, 15, 1917, {1, 3, 1, 1, 11, 15, 113, 45, 21, 595, 731, 3397, 4117, 9711, 16625}},
-{2081, 15, 1927, {1, 3, 3, 9, 19, 19, 59, 7, 105, 579, 599, 2859, 97, 14717, 15361}},
-{2082, 15, 1939, {1, 1, 1, 5, 27, 49, 113, 5, 367, 563, 1397, 2805, 3021, 3111, 20671}},
-{2083, 15, 1941, {1, 3, 3, 15, 27, 51, 99, 167, 109, 365, 1959, 1523, 6959, 14405, 18191}},
-{2084, 15, 1948, {1, 3, 1, 5, 21, 51, 125, 67, 123, 45, 1657, 51, 4825, 14081, 31049}},
-{2085, 15, 1970, {1, 1, 5, 7, 21, 59, 21, 249, 77, 793, 1687, 2561, 2241, 4321, 7477}},
-{2086, 15, 1979, {1, 1, 1, 7, 15, 35, 71, 29, 267, 611, 1813, 1823, 7039, 3299, 9919}},
-{2087, 15, 1982, {1, 3, 7, 11, 21, 59, 109, 213, 371, 785, 659, 1687, 4827, 6017, 19619}},
-{2088, 15, 2002, {1, 1, 3, 11, 27, 17, 1, 55, 367, 939, 333, 127, 5105, 2405, 28139}},
-{2089, 15, 2020, {1, 1, 7, 13, 5, 35, 59, 133, 509, 573, 625, 3857, 7935, 5279, 3727}},
-{2090, 15, 2024, {1, 1, 1, 7, 11, 47, 127, 157, 19, 403, 151, 1143, 7407, 8985, 32521}},
-{2091, 15, 2032, {1, 3, 1, 1, 5, 13, 105, 123, 63, 139, 1569, 1983, 563, 7175, 27705}},
-{2092, 15, 2053, {1, 1, 3, 13, 9, 35, 105, 227, 145, 21, 1369, 57, 393, 2921, 18511}},
-{2093, 15, 2060, {1, 3, 1, 7, 17, 61, 99, 187, 261, 281, 437, 2219, 5999, 1857, 18001}},
-{2094, 15, 2063, {1, 3, 3, 5, 1, 59, 67, 45, 451, 439, 2005, 3607, 3, 7167, 14227}},
-{2095, 15, 2066, {1, 3, 3, 3, 29, 19, 25, 251, 275, 733, 1749, 4021, 871, 3227, 13701}},
-{2096, 15, 2075, {1, 3, 3, 13, 27, 53, 57, 243, 491, 521, 1921, 1037, 5013, 5703, 15261}},
-{2097, 15, 2078, {1, 3, 1, 11, 13, 57, 1, 15, 123, 533, 785, 335, 1423, 14269, 3483}},
-{2098, 15, 2081, {1, 3, 7, 13, 15, 55, 5, 139, 385, 47, 1981, 1291, 7397, 12925, 29445}},
-{2099, 15, 2091, {1, 1, 7, 1, 23, 23, 59, 93, 117, 57, 63, 3047, 4849, 11637, 25311}},
-{2100, 15, 2096, {1, 1, 7, 13, 19, 37, 25, 203, 477, 447, 1345, 3485, 2099, 13347, 11621}},
-{2101, 15, 2102, {1, 1, 7, 3, 11, 23, 81, 17, 41, 735, 1149, 3253, 7665, 8291, 22293}},
-{2102, 15, 2106, {1, 1, 5, 3, 15, 9, 57, 167, 463, 493, 747, 1947, 6471, 1111, 31619}},
-{2103, 15, 2116, {1, 1, 5, 15, 7, 15, 107, 205, 325, 167, 1749, 927, 3589, 6127, 7617}},
-{2104, 15, 2120, {1, 1, 1, 13, 21, 25, 83, 147, 411, 399, 1423, 2279, 3661, 7591, 17429}},
-{2105, 15, 2125, {1, 1, 1, 9, 5, 17, 69, 205, 243, 647, 473, 1717, 1977, 10725, 2913}},
-{2106, 15, 2134, {1, 1, 3, 5, 5, 37, 103, 15, 485, 641, 1761, 3755, 6997, 10985, 11773}},
-{2107, 15, 2178, {1, 1, 5, 13, 9, 51, 87, 195, 97, 807, 1801, 961, 6341, 4307, 29105}},
-{2108, 15, 2180, {1, 3, 1, 13, 9, 35, 83, 61, 387, 817, 951, 3993, 7831, 8479, 23941}},
-{2109, 15, 2187, {1, 1, 7, 11, 19, 47, 75, 37, 91, 337, 953, 1169, 163, 2259, 24713}},
-{2110, 15, 2189, {1, 1, 1, 11, 13, 15, 83, 171, 159, 87, 619, 2973, 2653, 13725, 12499}},
-{2111, 15, 2190, {1, 3, 5, 3, 5, 63, 119, 25, 343, 269, 553, 2183, 959, 3825, 22189}},
-{2112, 15, 2208, {1, 1, 5, 15, 5, 37, 89, 109, 497, 1013, 265, 669, 1859, 2647, 3445}},
-{2113, 15, 2214, {1, 3, 3, 9, 21, 21, 15, 245, 107, 649, 367, 1601, 7279, 15783, 4943}},
-{2114, 15, 2237, {1, 3, 3, 15, 5, 41, 125, 113, 159, 161, 1191, 3491, 3531, 55, 20857}},
-{2115, 15, 2252, {1, 3, 5, 9, 21, 57, 21, 195, 99, 193, 1915, 2923, 6349, 15085, 24929}},
-{2116, 15, 2257, {1, 1, 1, 11, 31, 11, 73, 141, 361, 621, 1021, 2067, 5115, 12665, 26845}},
-{2117, 15, 2260, {1, 1, 1, 3, 29, 11, 43, 61, 209, 923, 1753, 1937, 843, 205, 8367}},
-{2118, 15, 2264, {1, 1, 1, 5, 15, 33, 119, 209, 215, 973, 1775, 815, 6693, 7957, 14517}},
-{2119, 15, 2270, {1, 1, 1, 5, 17, 57, 27, 147, 489, 59, 1439, 2279, 445, 11791, 19739}},
-{2120, 15, 2279, {1, 3, 1, 7, 11, 55, 1, 83, 305, 17, 1909, 405, 2325, 5293, 28559}},
-{2121, 15, 2288, {1, 3, 3, 7, 11, 27, 103, 157, 455, 1005, 2033, 3145, 1919, 15723, 25197}},
-{2122, 15, 2305, {1, 1, 5, 11, 15, 51, 37, 131, 503, 1007, 1795, 2421, 1335, 7413, 21741}},
-{2123, 15, 2312, {1, 1, 3, 1, 23, 63, 69, 83, 419, 283, 583, 123, 7725, 2243, 8403}},
-{2124, 15, 2317, {1, 1, 5, 5, 27, 45, 109, 17, 299, 65, 351, 947, 1165, 10723, 2053}},
-{2125, 15, 2323, {1, 1, 3, 3, 23, 61, 115, 253, 1, 931, 1481, 3187, 441, 14735, 27207}},
-{2126, 15, 2329, {1, 1, 5, 3, 25, 11, 83, 141, 359, 343, 901, 1629, 731, 12841, 14357}},
-{2127, 15, 2335, {1, 1, 3, 9, 7, 45, 97, 3, 299, 217, 663, 1527, 6379, 4527, 26147}},
-{2128, 15, 2342, {1, 1, 7, 9, 11, 53, 9, 203, 337, 713, 1517, 719, 4587, 11443, 26905}},
-{2129, 15, 2345, {1, 1, 7, 9, 11, 41, 125, 213, 237, 377, 361, 3231, 4223, 3263, 12655}},
-{2130, 15, 2365, {1, 3, 7, 7, 7, 33, 99, 19, 117, 273, 985, 107, 3831, 10135, 19423}},
-{2131, 15, 2371, {1, 1, 5, 15, 25, 41, 13, 125, 449, 169, 1149, 4021, 5663, 3077, 19163}},
-{2132, 15, 2378, {1, 3, 5, 9, 25, 57, 47, 103, 269, 51, 1805, 2503, 6687, 8065, 12045}},
-{2133, 15, 2385, {1, 3, 5, 7, 3, 35, 87, 225, 189, 229, 931, 3293, 1347, 1427, 3269}},
-{2134, 15, 2395, {1, 1, 1, 3, 5, 31, 61, 19, 247, 9, 1667, 343, 559, 2703, 3763}},
-{2135, 15, 2404, {1, 3, 5, 15, 31, 19, 57, 187, 109, 121, 1287, 2269, 659, 16235, 1273}},
-{2136, 15, 2414, {1, 1, 1, 3, 5, 47, 59, 243, 255, 97, 1959, 1723, 1347, 3019, 26989}},
-{2137, 15, 2426, {1, 3, 3, 15, 29, 35, 75, 67, 497, 731, 193, 3307, 3579, 12005, 7209}},
-{2138, 15, 2428, {1, 1, 5, 9, 13, 35, 79, 213, 51, 983, 1927, 1793, 5037, 5463, 965}},
-{2139, 15, 2441, {1, 1, 7, 11, 5, 41, 7, 83, 15, 411, 1775, 3515, 6755, 3249, 16425}},
-{2140, 15, 2456, {1, 3, 5, 1, 19, 61, 3, 19, 395, 819, 1331, 179, 5225, 5333, 3601}},
-{2141, 15, 2466, {1, 1, 3, 9, 7, 5, 87, 15, 387, 609, 1465, 277, 987, 8377, 903}},
-{2142, 15, 2468, {1, 1, 1, 3, 15, 11, 123, 107, 355, 333, 285, 1801, 6989, 1549, 25791}},
-{2143, 15, 2475, {1, 1, 7, 13, 27, 13, 73, 111, 481, 227, 1091, 365, 5713, 5087, 27217}},
-{2144, 15, 2489, {1, 3, 3, 15, 1, 55, 95, 213, 377, 405, 139, 1867, 2175, 4217, 28813}},
-{2145, 15, 2495, {1, 3, 5, 11, 21, 43, 109, 155, 181, 901, 1951, 507, 4389, 10815, 3141}},
-{2146, 15, 2497, {1, 1, 1, 15, 17, 11, 43, 215, 501, 19, 259, 3479, 6381, 6927, 31247}},
-{2147, 15, 2510, {1, 3, 5, 15, 19, 61, 75, 41, 391, 95, 865, 1441, 7993, 13979, 24663}},
-{2148, 15, 2512, {1, 3, 1, 3, 21, 15, 115, 213, 1, 645, 777, 1517, 2543, 11223, 3633}},
-{2149, 15, 2522, {1, 3, 5, 3, 9, 57, 39, 211, 407, 65, 1795, 2805, 2799, 8691, 1987}},
-{2150, 15, 2533, {1, 1, 3, 13, 17, 55, 47, 113, 29, 139, 1301, 3303, 1129, 13947, 29821}},
-{2151, 15, 2543, {1, 1, 3, 13, 5, 35, 97, 151, 477, 409, 1397, 3399, 4421, 15929, 6163}},
-{2152, 15, 2551, {1, 3, 1, 9, 21, 51, 99, 133, 149, 763, 623, 173, 4311, 11081, 1095}},
-{2153, 15, 2552, {1, 3, 7, 15, 13, 3, 99, 3, 195, 907, 1335, 1355, 7977, 5773, 32383}},
-{2154, 15, 2557, {1, 1, 3, 9, 17, 43, 43, 217, 475, 917, 1373, 1677, 4871, 9619, 16657}},
-{2155, 15, 2567, {1, 3, 3, 7, 31, 31, 55, 11, 73, 693, 25, 417, 1195, 6225, 32279}},
-{2156, 15, 2581, {1, 3, 5, 9, 21, 57, 127, 149, 79, 379, 1609, 2543, 6473, 16033, 27191}},
-{2157, 15, 2586, {1, 1, 5, 1, 13, 9, 81, 153, 297, 789, 1749, 2819, 3961, 11231, 24927}},
-{2158, 15, 2597, {1, 3, 5, 3, 23, 61, 45, 43, 43, 133, 1481, 1543, 2991, 13739, 10287}},
-{2159, 15, 2601, {1, 1, 3, 9, 25, 43, 31, 177, 337, 193, 1083, 1, 991, 9725, 8379}},
-{2160, 15, 2622, {1, 3, 5, 11, 13, 33, 65, 83, 421, 149, 409, 2443, 7423, 8847, 29599}},
-{2161, 15, 2633, {1, 1, 5, 11, 11, 1, 23, 225, 77, 585, 1505, 2525, 739, 10915, 25733}},
-{2162, 15, 2636, {1, 3, 7, 13, 7, 55, 3, 223, 415, 521, 1865, 2349, 5663, 7455, 16569}},
-{2163, 15, 2642, {1, 1, 7, 13, 1, 45, 121, 49, 463, 99, 1061, 2559, 5087, 13389, 11035}},
-{2164, 15, 2644, {1, 3, 7, 11, 31, 51, 35, 235, 385, 1023, 1771, 2013, 5437, 4877, 22119}},
-{2165, 15, 2653, {1, 3, 3, 11, 21, 3, 11, 119, 81, 737, 1093, 2377, 4055, 1121, 15767}},
-{2166, 15, 2667, {1, 1, 5, 13, 9, 3, 83, 217, 387, 249, 1047, 1861, 4103, 15367, 24545}},
-{2167, 15, 2669, {1, 3, 3, 1, 5, 37, 43, 183, 383, 463, 937, 1165, 1481, 959, 17047}},
-{2168, 15, 2672, {1, 1, 3, 5, 7, 43, 127, 243, 81, 1021, 165, 753, 4711, 12965, 22049}},
-{2169, 15, 2675, {1, 1, 5, 5, 3, 61, 65, 53, 425, 89, 5, 1467, 1395, 9579, 8961}},
-{2170, 15, 2682, {1, 3, 7, 13, 11, 35, 123, 21, 83, 689, 667, 1203, 5959, 15697, 26885}},
-{2171, 15, 2687, {1, 1, 5, 13, 9, 49, 41, 101, 291, 339, 1067, 657, 4453, 1137, 21131}},
-{2172, 15, 2691, {1, 3, 3, 3, 17, 61, 11, 213, 27, 805, 1691, 1057, 6011, 11941, 18883}},
-{2173, 15, 2698, {1, 3, 1, 7, 3, 51, 5, 63, 121, 3, 245, 2631, 3737, 16121, 26803}},
-{2174, 15, 2708, {1, 3, 1, 1, 23, 51, 79, 19, 161, 107, 609, 3489, 3389, 4035, 2427}},
-{2175, 15, 2712, {1, 3, 1, 1, 17, 11, 101, 101, 373, 63, 1641, 285, 1333, 165, 14025}},
-{2176, 15, 2718, {1, 1, 1, 5, 1, 51, 83, 137, 45, 1019, 821, 867, 6055, 10443, 9857}},
-{2177, 15, 2722, {1, 3, 1, 5, 17, 23, 25, 181, 429, 495, 317, 3219, 5963, 13945, 9969}},
-{2178, 15, 2736, {1, 3, 7, 3, 3, 15, 123, 191, 369, 177, 1697, 2113, 3889, 5201, 21839}},
-{2179, 15, 2741, {1, 3, 1, 11, 21, 39, 51, 139, 271, 605, 1007, 3513, 3365, 3781, 6799}},
-{2180, 15, 2756, {1, 1, 7, 5, 13, 19, 47, 165, 249, 405, 255, 1295, 4513, 14395, 5587}},
-{2181, 15, 2765, {1, 1, 3, 7, 5, 17, 99, 1, 393, 31, 621, 797, 6113, 16003, 32043}},
-{2182, 15, 2774, {1, 3, 5, 13, 11, 21, 65, 81, 147, 443, 775, 3671, 7029, 11749, 3339}},
-{2183, 15, 2799, {1, 3, 7, 1, 23, 33, 99, 177, 161, 577, 1729, 617, 3465, 11787, 17577}},
-{2184, 15, 2804, {1, 1, 5, 7, 15, 15, 53, 193, 97, 255, 1223, 545, 5153, 873, 24525}},
-{2185, 15, 2825, {1, 3, 5, 1, 7, 57, 47, 121, 383, 835, 1709, 2363, 4731, 12163, 7001}},
-{2186, 15, 2826, {1, 3, 3, 11, 19, 33, 63, 99, 387, 95, 783, 1009, 6373, 4021, 7685}},
-{2187, 15, 2840, {1, 1, 1, 15, 25, 33, 73, 135, 335, 785, 935, 1927, 5847, 10501, 7719}},
-{2188, 15, 2843, {1, 1, 5, 3, 27, 45, 71, 215, 489, 157, 1189, 2577, 6901, 10219, 3025}},
-{2189, 15, 2846, {1, 1, 7, 7, 21, 3, 97, 225, 101, 159, 293, 2789, 7955, 14829, 1209}},
-{2190, 15, 2849, {1, 3, 1, 5, 23, 41, 83, 63, 361, 195, 1707, 2081, 5363, 6327, 179}},
-{2191, 15, 2867, {1, 1, 3, 1, 21, 51, 59, 67, 175, 363, 825, 2971, 3321, 8837, 11805}},
-{2192, 15, 2876, {1, 3, 7, 1, 19, 3, 15, 21, 429, 675, 1589, 2615, 2575, 1537, 7139}},
-{2193, 15, 2891, {1, 3, 3, 5, 21, 29, 17, 115, 345, 397, 523, 1699, 7043, 11173, 3023}},
-{2194, 15, 2902, {1, 1, 5, 7, 19, 63, 99, 175, 91, 433, 153, 3749, 517, 13667, 7423}},
-{2195, 15, 2912, {1, 3, 7, 3, 25, 23, 53, 149, 65, 551, 1231, 365, 6637, 15137, 16319}},
-{2196, 15, 2917, {1, 3, 7, 13, 5, 45, 11, 151, 323, 31, 1749, 409, 6753, 10503, 14991}},
-{2197, 15, 2927, {1, 3, 7, 3, 5, 21, 29, 117, 321, 341, 1811, 3619, 4337, 12255, 8629}},
-{2198, 15, 2941, {1, 3, 7, 3, 7, 3, 5, 221, 407, 671, 1763, 3669, 2353, 8175, 23489}},
-{2199, 15, 2965, {1, 1, 3, 7, 11, 55, 53, 185, 247, 35, 1823, 513, 1379, 11827, 20069}},
-{2200, 15, 2970, {1, 3, 3, 5, 29, 51, 73, 191, 185, 961, 881, 2019, 5651, 1019, 15587}},
-{2201, 15, 2982, {1, 3, 7, 13, 7, 55, 59, 5, 417, 829, 453, 2339, 587, 13283, 797}},
-{2202, 15, 2993, {1, 3, 7, 3, 11, 41, 75, 85, 65, 149, 1583, 529, 2707, 11479, 7109}},
-{2203, 15, 3018, {1, 3, 7, 9, 13, 57, 37, 243, 91, 613, 665, 171, 1631, 13737, 2377}},
-{2204, 15, 3023, {1, 1, 3, 7, 5, 43, 97, 53, 477, 793, 999, 3647, 2555, 7371, 19295}},
-{2205, 15, 3025, {1, 1, 7, 1, 1, 9, 99, 253, 317, 817, 1559, 2081, 2529, 14611, 15997}},
-{2206, 15, 3026, {1, 3, 3, 1, 5, 41, 57, 121, 387, 441, 709, 1511, 7045, 8409, 13297}},
-{2207, 15, 3028, {1, 1, 1, 13, 29, 57, 63, 183, 327, 473, 1943, 213, 3973, 16289, 2739}},
-{2208, 15, 3032, {1, 3, 7, 9, 25, 15, 75, 185, 335, 881, 1041, 3339, 4471, 6823, 21121}},
-{2209, 15, 3053, {1, 3, 3, 13, 23, 3, 57, 117, 511, 927, 771, 3229, 949, 15487, 11963}},
-{2210, 15, 3054, {1, 1, 3, 7, 27, 19, 55, 207, 331, 705, 1945, 797, 7125, 10493, 16585}},
-{2211, 15, 3065, {1, 3, 1, 1, 29, 7, 91, 93, 459, 93, 1501, 1927, 6415, 16255, 9823}},
-{2212, 15, 3071, {1, 1, 5, 5, 31, 11, 97, 179, 505, 807, 877, 4003, 4377, 8851, 4239}},
-{2213, 15, 3076, {1, 1, 3, 5, 11, 25, 17, 131, 23, 95, 311, 1429, 2029, 13091, 23739}},
-{2214, 15, 3088, {1, 1, 3, 11, 13, 27, 33, 127, 481, 117, 1127, 1619, 6493, 8507, 6615}},
-{2215, 15, 3107, {1, 3, 1, 13, 19, 27, 89, 101, 27, 235, 1579, 1701, 4421, 16037, 16239}},
-{2216, 15, 3146, {1, 3, 1, 15, 1, 15, 3, 117, 317, 475, 1691, 2423, 5519, 1703, 2969}},
-{2217, 15, 3148, {1, 1, 3, 1, 13, 15, 19, 37, 237, 467, 1321, 453, 2169, 13313, 31499}},
-{2218, 15, 3159, {1, 1, 3, 15, 29, 55, 31, 199, 85, 285, 967, 367, 3941, 151, 20587}},
-{2219, 15, 3165, {1, 3, 7, 15, 7, 13, 31, 35, 117, 543, 1179, 3441, 3039, 11225, 30229}},
-{2220, 15, 3170, {1, 1, 3, 15, 3, 43, 1, 63, 353, 395, 1775, 3493, 5175, 13193, 25343}},
-{2221, 15, 3179, {1, 3, 3, 15, 17, 25, 57, 205, 411, 83, 1877, 2093, 5599, 12115, 8751}},
-{2222, 15, 3182, {1, 1, 1, 11, 15, 9, 115, 99, 85, 887, 987, 4015, 7077, 3739, 21505}},
-{2223, 15, 3205, {1, 3, 1, 11, 25, 39, 127, 37, 329, 273, 1531, 3211, 7115, 15501, 26575}},
-{2224, 15, 3212, {1, 1, 5, 13, 15, 3, 3, 101, 431, 645, 493, 723, 8083, 1423, 14879}},
-{2225, 15, 3218, {1, 3, 3, 5, 31, 35, 37, 131, 259, 849, 325, 3403, 3627, 3295, 30885}},
-{2226, 15, 3220, {1, 3, 7, 1, 9, 3, 31, 201, 379, 907, 1005, 3333, 7457, 2533, 30357}},
-{2227, 15, 3223, {1, 3, 1, 9, 7, 7, 95, 103, 121, 157, 895, 2683, 5839, 12403, 14327}},
-{2228, 15, 3227, {1, 3, 7, 3, 13, 5, 55, 233, 3, 855, 859, 1115, 3883, 8041, 3353}},
-{2229, 15, 3233, {1, 1, 5, 9, 3, 55, 99, 79, 263, 831, 1579, 205, 5673, 1999, 14879}},
-{2230, 15, 3234, {1, 3, 1, 5, 17, 25, 85, 19, 189, 141, 877, 667, 4461, 11915, 23247}},
-{2231, 15, 3254, {1, 1, 5, 5, 1, 35, 15, 219, 469, 725, 1793, 3683, 3661, 15627, 30197}},
-{2232, 15, 3263, {1, 1, 7, 5, 27, 3, 41, 153, 431, 487, 759, 1345, 6735, 9937, 26277}},
-{2233, 15, 3268, {1, 1, 1, 11, 11, 13, 41, 121, 265, 465, 1447, 5, 3407, 1907, 10037}},
-{2234, 15, 3272, {1, 3, 5, 9, 15, 63, 5, 7, 407, 83, 365, 3687, 7721, 6973, 16967}},
-{2235, 15, 3277, {1, 1, 7, 7, 5, 41, 75, 155, 417, 565, 1199, 1111, 2823, 10703, 22561}},
-{2236, 15, 3292, {1, 3, 7, 5, 7, 43, 39, 185, 105, 327, 1977, 1137, 3261, 10583, 11661}},
-{2237, 15, 3295, {1, 3, 7, 7, 19, 19, 103, 137, 169, 273, 1357, 3413, 7647, 10531, 32489}},
-{2238, 15, 3296, {1, 1, 3, 13, 13, 3, 81, 23, 161, 295, 735, 2031, 1027, 15513, 20165}},
-{2239, 15, 3301, {1, 1, 5, 1, 15, 1, 91, 35, 375, 207, 1417, 1115, 2237, 11749, 8509}},
-{2240, 15, 3306, {1, 3, 7, 3, 25, 51, 49, 219, 195, 417, 1523, 3953, 5739, 7499, 27071}},
-{2241, 15, 3313, {1, 1, 3, 11, 23, 29, 19, 81, 421, 633, 513, 547, 7545, 29, 11909}},
-{2242, 15, 3346, {1, 1, 1, 7, 13, 61, 33, 243, 221, 231, 111, 879, 2861, 1795, 27531}},
-{2243, 15, 3367, {1, 3, 7, 3, 19, 21, 1, 141, 159, 605, 969, 3013, 6583, 2447, 19919}},
-{2244, 15, 3371, {1, 3, 7, 3, 31, 9, 91, 83, 29, 873, 929, 43, 2253, 12539, 23951}},
-{2245, 15, 3373, {1, 1, 5, 3, 31, 15, 87, 105, 319, 973, 1489, 3417, 3377, 15749, 2357}},
-{2246, 15, 3374, {1, 1, 3, 15, 7, 23, 3, 81, 383, 419, 713, 997, 6873, 593, 285}},
-{2247, 15, 3376, {1, 3, 3, 1, 29, 13, 29, 101, 441, 693, 2039, 2951, 5921, 12129, 12053}},
-{2248, 15, 3382, {1, 1, 3, 15, 9, 29, 97, 117, 421, 433, 1017, 125, 3607, 9415, 6843}},
-{2249, 15, 3388, {1, 3, 5, 9, 11, 13, 75, 155, 413, 75, 109, 1599, 6161, 16115, 12621}},
-{2250, 15, 3391, {1, 3, 3, 3, 11, 13, 49, 225, 401, 599, 1815, 1643, 7853, 13305, 25195}},
-{2251, 15, 3403, {1, 3, 7, 5, 15, 11, 27, 95, 387, 931, 549, 2179, 3397, 15883, 16563}},
-{2252, 15, 3406, {1, 1, 7, 3, 9, 39, 121, 5, 453, 27, 1747, 657, 2593, 1289, 12577}},
-{2253, 15, 3413, {1, 3, 7, 5, 25, 25, 109, 49, 185, 985, 631, 803, 3865, 8955, 17901}},
-{2254, 15, 3420, {1, 1, 3, 13, 3, 59, 47, 49, 139, 275, 1471, 2995, 5593, 14011, 18741}},
-{2255, 15, 3427, {1, 1, 5, 15, 29, 11, 97, 225, 245, 291, 1873, 2365, 767, 3419, 14943}},
-{2256, 15, 3441, {1, 3, 3, 5, 15, 17, 19, 209, 359, 891, 1375, 2003, 7247, 5299, 28841}},
-{2257, 15, 3453, {1, 3, 7, 7, 9, 55, 105, 35, 77, 47, 1023, 13, 2901, 847, 10265}},
-{2258, 15, 3464, {1, 3, 7, 7, 7, 5, 65, 233, 141, 277, 1333, 2357, 443, 7257, 21979}},
-{2259, 15, 3469, {1, 3, 5, 11, 13, 63, 41, 87, 193, 737, 1085, 2317, 7869, 10149, 12163}},
-{2260, 15, 3481, {1, 3, 1, 1, 7, 57, 75, 235, 461, 857, 155, 2679, 5925, 2565, 10881}},
-{2261, 15, 3488, {1, 1, 7, 15, 13, 41, 63, 135, 433, 387, 1943, 2249, 5469, 11679, 28661}},
-{2262, 15, 3497, {1, 3, 3, 13, 5, 3, 103, 161, 367, 649, 789, 1179, 4163, 5699, 16787}},
-{2263, 15, 3503, {1, 3, 7, 7, 31, 13, 45, 141, 113, 769, 1035, 457, 6709, 14989, 27311}},
-{2264, 15, 3511, {1, 1, 3, 1, 1, 43, 119, 145, 111, 593, 1139, 417, 637, 4437, 17285}},
-{2265, 15, 3515, {1, 3, 5, 9, 9, 33, 19, 99, 201, 685, 1793, 2621, 6857, 8769, 5623}},
-{2266, 15, 3525, {1, 3, 5, 5, 23, 43, 27, 189, 325, 415, 215, 1253, 3599, 1215, 10093}},
-{2267, 15, 3529, {1, 1, 3, 13, 11, 35, 113, 173, 503, 19, 1459, 503, 5363, 3967, 13945}},
-{2268, 15, 3547, {1, 1, 5, 11, 31, 49, 13, 173, 199, 623, 1231, 2495, 6581, 7957, 25321}},
-{2269, 15, 3550, {1, 3, 1, 9, 23, 3, 79, 149, 505, 937, 1839, 3701, 1673, 8589, 8031}},
-{2270, 15, 3573, {1, 3, 3, 5, 21, 27, 107, 11, 505, 407, 177, 3593, 4729, 12773, 11685}},
-{2271, 15, 3583, {1, 3, 1, 11, 29, 49, 79, 53, 61, 895, 2035, 563, 5613, 6065, 6207}},
-{2272, 15, 3594, {1, 1, 3, 7, 1, 53, 3, 215, 99, 865, 1749, 3533, 4305, 1243, 28463}},
-{2273, 15, 3607, {1, 1, 1, 13, 31, 59, 115, 53, 403, 909, 847, 103, 4967, 10623, 30073}},
-{2274, 15, 3613, {1, 1, 7, 5, 27, 1, 119, 83, 457, 81, 395, 811, 6221, 14337, 541}},
-{2275, 15, 3624, {1, 1, 5, 5, 5, 53, 83, 117, 269, 327, 875, 101, 3343, 715, 26339}},
-{2276, 15, 3630, {1, 1, 1, 11, 31, 39, 121, 147, 305, 383, 1211, 1897, 7647, 11687, 18907}},
-{2277, 15, 3635, {1, 3, 3, 15, 23, 53, 17, 85, 395, 503, 61, 1745, 4713, 4641, 13787}},
-{2278, 15, 3642, {1, 1, 7, 7, 27, 1, 105, 29, 287, 37, 959, 975, 4427, 4705, 10175}},
-{2279, 15, 3644, {1, 3, 3, 5, 7, 63, 57, 199, 27, 107, 1095, 3923, 6969, 713, 11619}},
-{2280, 15, 3650, {1, 3, 5, 1, 5, 49, 85, 45, 449, 45, 49, 3419, 1109, 455, 15917}},
-{2281, 15, 3679, {1, 1, 1, 5, 13, 15, 39, 27, 467, 85, 1537, 3055, 1977, 8829, 25231}},
-{2282, 15, 3690, {1, 1, 1, 15, 1, 47, 23, 121, 147, 547, 1865, 1491, 779, 3515, 12667}},
-{2283, 15, 3698, {1, 3, 3, 1, 19, 5, 77, 101, 1, 721, 1149, 2967, 4925, 11889, 16655}},
-{2284, 15, 3704, {1, 1, 1, 7, 1, 35, 95, 239, 127, 855, 1031, 455, 7631, 6039, 21983}},
-{2285, 15, 3707, {1, 3, 7, 9, 23, 43, 75, 105, 335, 223, 1825, 3217, 413, 7473, 30005}},
-{2286, 15, 3713, {1, 1, 5, 15, 29, 9, 43, 145, 223, 523, 511, 323, 5955, 11141, 22533}},
-{2287, 15, 3754, {1, 1, 3, 1, 13, 61, 93, 133, 461, 233, 383, 693, 7347, 3165, 27493}},
-{2288, 15, 3756, {1, 3, 7, 1, 13, 45, 113, 207, 53, 1007, 815, 1145, 2937, 289, 22195}},
-{2289, 15, 3761, {1, 3, 5, 5, 19, 17, 113, 89, 19, 1023, 1625, 3277, 697, 5187, 15433}},
-{2290, 15, 3776, {1, 1, 3, 13, 21, 15, 15, 197, 409, 391, 1993, 2475, 3189, 4431, 29585}},
-{2291, 15, 3781, {1, 1, 5, 5, 31, 7, 111, 231, 187, 543, 45, 3863, 3811, 4573, 4437}},
-{2292, 15, 3788, {1, 3, 3, 7, 19, 7, 123, 23, 79, 513, 189, 3663, 1291, 13257, 8949}},
-{2293, 15, 3791, {1, 1, 5, 13, 3, 53, 109, 133, 157, 223, 651, 3059, 6055, 14455, 26903}},
-{2294, 15, 3794, {1, 1, 7, 1, 23, 63, 59, 229, 17, 199, 643, 637, 7631, 13647, 7399}},
-{2295, 15, 3806, {1, 1, 1, 3, 1, 51, 119, 67, 335, 543, 913, 3565, 4795, 13405, 7463}},
-{2296, 15, 3841, {1, 1, 5, 3, 31, 5, 91, 97, 23, 223, 837, 1353, 1929, 12043, 10039}},
-{2297, 15, 3848, {1, 3, 5, 7, 19, 3, 79, 171, 301, 687, 1545, 355, 4709, 12965, 16797}},
-{2298, 15, 3851, {1, 3, 5, 11, 11, 49, 111, 123, 251, 569, 1605, 401, 5439, 13519, 8847}},
-{2299, 15, 3856, {1, 3, 1, 3, 3, 53, 7, 55, 369, 633, 181, 4037, 2993, 15815, 8661}},
-{2300, 15, 3868, {1, 1, 1, 13, 31, 29, 75, 167, 279, 597, 539, 1791, 8013, 4387, 9717}},
-{2301, 15, 3875, {1, 1, 5, 7, 17, 15, 99, 183, 211, 49, 225, 3143, 4537, 13141, 23375}},
-{2302, 15, 3882, {1, 1, 3, 5, 3, 59, 25, 149, 467, 69, 1939, 1007, 2765, 4693, 29815}},
-{2303, 15, 3884, {1, 3, 1, 3, 17, 33, 119, 189, 447, 251, 879, 177, 5395, 13487, 9587}},
-{2304, 15, 3889, {1, 3, 3, 7, 15, 31, 115, 3, 21, 817, 475, 1849, 6041, 12541, 18701}},
-{2305, 15, 3892, {1, 1, 5, 13, 31, 33, 7, 115, 361, 587, 1919, 1007, 3537, 7493, 19357}},
-{2306, 15, 3919, {1, 3, 7, 13, 23, 35, 15, 111, 123, 633, 805, 1983, 2109, 14477, 4985}},
-{2307, 15, 3921, {1, 3, 3, 11, 25, 13, 11, 205, 97, 893, 927, 1291, 4007, 13593, 29693}},
-{2308, 15, 3958, {1, 3, 5, 15, 9, 13, 121, 89, 215, 823, 1389, 1581, 8095, 4707, 16061}},
-{2309, 15, 3961, {1, 3, 1, 3, 23, 39, 83, 23, 47, 941, 1419, 2389, 5699, 7519, 5829}},
-{2310, 15, 3973, {1, 3, 1, 9, 23, 43, 79, 237, 93, 203, 695, 225, 5645, 3591, 16775}},
-{2311, 15, 3977, {1, 3, 5, 3, 15, 19, 89, 129, 375, 125, 225, 1323, 2267, 11607, 17937}},
-{2312, 15, 3985, {1, 3, 3, 1, 31, 37, 93, 133, 377, 959, 707, 621, 7179, 15493, 30287}},
-{2313, 15, 3991, {1, 3, 7, 13, 5, 13, 15, 1, 37, 525, 1641, 2829, 6139, 4069, 19187}},
-{2314, 15, 4004, {1, 3, 3, 9, 17, 3, 67, 97, 375, 845, 403, 973, 3919, 2275, 31627}},
-{2315, 15, 4007, {1, 1, 3, 3, 25, 7, 91, 67, 271, 465, 481, 3477, 5229, 241, 8411}},
-{2316, 15, 4019, {1, 1, 1, 11, 1, 41, 109, 115, 75, 787, 309, 2887, 179, 9073, 13895}},
-{2317, 15, 4045, {1, 3, 3, 15, 11, 31, 113, 91, 303, 907, 1933, 2167, 7799, 11821, 20659}},
-{2318, 15, 4054, {1, 3, 1, 15, 27, 17, 21, 41, 99, 137, 1397, 929, 5819, 11977, 6201}},
-{2319, 15, 4057, {1, 1, 7, 13, 21, 29, 47, 239, 287, 305, 899, 2711, 1723, 3315, 199}},
-{2320, 15, 4058, {1, 1, 1, 3, 31, 21, 101, 149, 107, 761, 1197, 1703, 4803, 8411, 10649}},
-{2321, 15, 4070, {1, 1, 5, 15, 23, 45, 109, 221, 85, 619, 169, 1013, 3305, 9451, 26189}},
-{2322, 15, 4101, {1, 3, 5, 13, 7, 57, 19, 153, 231, 627, 565, 1595, 6309, 5037, 25505}},
-{2323, 15, 4113, {1, 1, 7, 7, 1, 45, 43, 79, 271, 59, 219, 2255, 1785, 7919, 24061}},
-{2324, 15, 4114, {1, 3, 7, 5, 31, 57, 57, 231, 33, 227, 531, 679, 1141, 85, 19777}},
-{2325, 15, 4119, {1, 1, 3, 15, 11, 59, 59, 169, 459, 693, 907, 1191, 3783, 12809, 6263}},
-{2326, 15, 4129, {1, 1, 7, 13, 19, 21, 105, 65, 267, 141, 1547, 781, 7295, 13565, 17775}},
-{2327, 15, 4141, {1, 3, 3, 5, 31, 63, 97, 155, 477, 661, 329, 797, 2539, 4061, 10537}},
-{2328, 15, 4142, {1, 3, 3, 7, 11, 17, 119, 89, 71, 103, 1043, 413, 6035, 12829, 11559}},
-{2329, 15, 4147, {1, 3, 1, 9, 5, 19, 53, 185, 103, 629, 2015, 1257, 5163, 10581, 13449}},
-{2330, 15, 4149, {1, 1, 1, 5, 23, 35, 25, 129, 179, 959, 677, 2249, 6315, 12151, 3459}},
-{2331, 15, 4150, {1, 1, 1, 1, 9, 47, 93, 45, 35, 45, 265, 2065, 6225, 25, 27135}},
-{2332, 15, 4164, {1, 3, 1, 11, 21, 53, 127, 163, 311, 667, 597, 1561, 4515, 23, 9551}},
-{2333, 15, 4168, {1, 1, 3, 3, 7, 47, 105, 211, 241, 95, 389, 899, 6001, 8129, 19889}},
-{2334, 15, 4186, {1, 1, 3, 15, 29, 45, 9, 27, 483, 799, 269, 1811, 4493, 7109, 22149}},
-{2335, 15, 4198, {1, 1, 3, 3, 29, 5, 57, 205, 187, 615, 1677, 3987, 4577, 8799, 16311}},
-{2336, 15, 4207, {1, 1, 5, 3, 15, 5, 91, 101, 319, 445, 1261, 2039, 4071, 8249, 11611}},
-{2337, 15, 4221, {1, 3, 7, 11, 19, 17, 1, 185, 153, 579, 1001, 2031, 2295, 16335, 24771}},
-{2338, 15, 4225, {1, 3, 3, 15, 13, 45, 93, 185, 319, 667, 1085, 93, 577, 11551, 11355}},
-{2339, 15, 4231, {1, 1, 7, 13, 3, 61, 45, 191, 51, 981, 1151, 2715, 2503, 4147, 4587}},
-{2340, 15, 4238, {1, 1, 3, 3, 27, 17, 71, 141, 57, 981, 1033, 333, 4639, 15885, 1039}},
-{2341, 15, 4243, {1, 3, 3, 15, 21, 55, 33, 123, 357, 893, 829, 4045, 5027, 11727, 13357}},
-{2342, 15, 4249, {1, 1, 1, 9, 31, 47, 27, 223, 311, 205, 179, 3411, 4019, 10997, 28115}},
-{2343, 15, 4250, {1, 3, 5, 1, 3, 39, 15, 7, 501, 641, 735, 295, 2005, 12641, 19779}},
-{2344, 15, 4252, {1, 3, 3, 1, 15, 1, 75, 243, 329, 267, 1323, 2285, 5389, 11881, 15737}},
-{2345, 15, 4259, {1, 1, 3, 3, 13, 17, 101, 99, 209, 939, 1147, 3221, 5159, 3435, 183}},
-{2346, 15, 4279, {1, 1, 1, 1, 27, 43, 29, 179, 179, 659, 807, 313, 4165, 963, 11317}},
-{2347, 15, 4285, {1, 1, 3, 13, 9, 51, 125, 245, 381, 555, 1383, 3887, 2045, 12829, 12029}},
-{2348, 15, 4288, {1, 1, 1, 9, 29, 39, 55, 127, 235, 617, 1553, 3133, 7735, 14725, 16733}},
-{2349, 15, 4303, {1, 1, 3, 5, 15, 9, 47, 217, 89, 987, 1083, 1045, 4745, 12915, 13719}},
-{2350, 15, 4312, {1, 3, 3, 7, 23, 3, 35, 79, 45, 435, 1549, 2645, 2831, 10359, 10041}},
-{2351, 15, 4322, {1, 1, 7, 15, 31, 61, 25, 223, 511, 319, 487, 1677, 739, 7097, 18417}},
-{2352, 15, 4327, {1, 1, 7, 5, 19, 21, 123, 237, 299, 367, 1341, 1449, 2949, 8629, 11051}},
-{2353, 15, 4336, {1, 3, 7, 7, 31, 53, 125, 33, 257, 719, 1297, 895, 5095, 10237, 12309}},
-{2354, 15, 4359, {1, 3, 1, 5, 31, 59, 73, 211, 97, 209, 1289, 4033, 6143, 14275, 7997}},
-{2355, 15, 4384, {1, 1, 5, 7, 31, 5, 75, 105, 389, 985, 9, 4033, 1185, 7821, 19083}},
-{2356, 15, 4387, {1, 1, 1, 15, 11, 39, 73, 253, 275, 813, 25, 3441, 2493, 5873, 3739}},
-{2357, 15, 4401, {1, 3, 7, 1, 31, 19, 119, 5, 109, 397, 1329, 3347, 5941, 12449, 2533}},
-{2358, 15, 4407, {1, 1, 1, 1, 5, 59, 61, 175, 435, 985, 65, 3781, 5425, 15073, 16361}},
-{2359, 15, 4428, {1, 3, 5, 7, 31, 13, 53, 87, 69, 305, 1455, 273, 2197, 4277, 24423}},
-{2360, 15, 4436, {1, 3, 3, 15, 13, 13, 91, 171, 71, 583, 15, 3599, 6801, 10041, 26097}},
-{2361, 15, 4450, {1, 3, 3, 5, 5, 13, 91, 225, 63, 69, 1795, 341, 461, 5015, 9471}},
-{2362, 15, 4452, {1, 3, 7, 5, 21, 55, 109, 39, 459, 925, 229, 2855, 5807, 2117, 31739}},
-{2363, 15, 4459, {1, 1, 3, 3, 1, 5, 17, 177, 401, 727, 1555, 3097, 1243, 5933, 14579}},
-{2364, 15, 4461, {1, 1, 7, 3, 19, 19, 37, 87, 105, 73, 197, 4067, 6237, 10553, 9207}},
-{2365, 15, 4470, {1, 1, 3, 15, 1, 55, 119, 115, 441, 3, 1003, 1631, 197, 12929, 25385}},
-{2366, 15, 4483, {1, 3, 7, 11, 31, 1, 119, 49, 467, 647, 685, 2771, 3689, 11049, 26787}},
-{2367, 15, 4485, {1, 1, 1, 11, 19, 19, 21, 73, 459, 935, 615, 371, 1099, 14407, 10375}},
-{2368, 15, 4486, {1, 3, 5, 13, 15, 3, 107, 179, 259, 677, 1101, 315, 7673, 14639, 11241}},
-{2369, 15, 4492, {1, 1, 7, 9, 15, 21, 93, 25, 349, 23, 1087, 27, 5691, 12997, 29301}},
-{2370, 15, 4497, {1, 3, 3, 5, 7, 43, 1, 195, 69, 753, 1315, 2629, 3259, 5595, 19439}},
-{2371, 15, 4514, {1, 3, 5, 5, 31, 9, 75, 217, 217, 197, 1925, 2033, 3585, 15219, 20251}},
-{2372, 15, 4533, {1, 1, 5, 11, 17, 31, 3, 209, 315, 49, 949, 2267, 4611, 4375, 16431}},
-{2373, 15, 4537, {1, 1, 7, 9, 17, 35, 13, 115, 119, 553, 1527, 2857, 3599, 391, 25101}},
-{2374, 15, 4546, {1, 3, 3, 15, 13, 59, 17, 177, 301, 719, 909, 1663, 5033, 1129, 529}},
-{2375, 15, 4551, {1, 1, 7, 5, 15, 13, 99, 157, 379, 975, 1019, 2251, 3807, 10621, 351}},
-{2376, 15, 4555, {1, 3, 3, 13, 5, 57, 5, 31, 361, 981, 883, 3723, 2259, 5151, 11783}},
-{2377, 15, 4560, {1, 1, 1, 13, 1, 43, 125, 19, 77, 509, 1817, 3795, 1863, 8401, 27253}},
-{2378, 15, 4569, {1, 1, 5, 7, 19, 41, 21, 151, 89, 189, 769, 1937, 4497, 13607, 24691}},
-{2379, 15, 4576, {1, 1, 1, 9, 21, 9, 1, 195, 31, 907, 1719, 1549, 809, 13629, 16597}},
-{2380, 15, 4582, {1, 1, 1, 3, 21, 61, 103, 219, 311, 849, 523, 21, 4533, 6367, 3935}},
-{2381, 15, 4586, {1, 1, 7, 9, 7, 33, 77, 19, 489, 933, 1729, 1813, 6741, 10701, 7}},
-{2382, 15, 4609, {1, 1, 1, 5, 23, 53, 43, 63, 453, 209, 1313, 2847, 2641, 13783, 14983}},
-{2383, 15, 4610, {1, 3, 7, 7, 15, 45, 83, 241, 509, 659, 213, 221, 5205, 6019, 18945}},
-{2384, 15, 4612, {1, 1, 5, 9, 25, 43, 37, 9, 191, 505, 765, 295, 953, 1045, 11203}},
-{2385, 15, 4649, {1, 3, 7, 11, 5, 49, 45, 177, 379, 695, 355, 1711, 7747, 497, 7597}},
-{2386, 15, 4652, {1, 1, 5, 13, 23, 47, 101, 145, 301, 207, 195, 2225, 8093, 15345, 14097}},
-{2387, 15, 4672, {1, 3, 7, 13, 9, 9, 55, 223, 343, 921, 1825, 3281, 2627, 855, 27651}},
-{2388, 15, 4677, {1, 1, 7, 1, 21, 1, 67, 149, 433, 111, 577, 3675, 495, 9043, 23613}},
-{2389, 15, 4684, {1, 3, 1, 13, 9, 39, 37, 73, 117, 559, 1131, 2511, 7599, 8393, 24747}},
-{2390, 15, 4690, {1, 3, 3, 7, 11, 15, 85, 229, 7, 21, 1649, 739, 375, 13991, 27053}},
-{2391, 15, 4695, {1, 1, 5, 5, 15, 41, 49, 117, 173, 825, 1343, 377, 1789, 12519, 30667}},
-{2392, 15, 4696, {1, 1, 7, 15, 9, 11, 97, 99, 347, 729, 9, 1703, 1177, 5189, 9061}},
-{2393, 15, 4702, {1, 1, 5, 11, 15, 25, 99, 63, 89, 675, 561, 215, 8111, 3955, 24635}},
-{2394, 15, 4705, {1, 1, 1, 1, 7, 53, 99, 193, 233, 731, 733, 1883, 7783, 14413, 14003}},
-{2395, 15, 4717, {1, 3, 5, 7, 31, 23, 45, 153, 337, 293, 443, 2301, 5135, 7455, 13123}},
-{2396, 15, 4726, {1, 3, 1, 3, 23, 53, 23, 165, 53, 875, 1543, 1035, 4247, 5101, 28445}},
-{2397, 15, 4736, {1, 1, 1, 15, 13, 41, 77, 93, 205, 743, 1101, 1413, 2371, 7183, 12337}},
-{2398, 15, 4753, {1, 1, 3, 15, 17, 63, 25, 101, 147, 149, 1207, 3525, 2661, 9539, 11145}},
-{2399, 15, 4754, {1, 3, 1, 9, 17, 5, 3, 35, 389, 909, 1017, 2803, 5243, 13025, 8851}},
-{2400, 15, 4756, {1, 1, 7, 15, 19, 27, 69, 91, 71, 547, 1421, 831, 6969, 5517, 28233}},
-{2401, 15, 4775, {1, 1, 3, 3, 17, 45, 55, 63, 263, 819, 1211, 2739, 655, 13269, 22281}},
-{2402, 15, 4801, {1, 3, 1, 5, 23, 13, 81, 251, 83, 551, 491, 1029, 3561, 357, 23393}},
-{2403, 15, 4819, {1, 3, 1, 13, 25, 27, 93, 143, 407, 403, 1395, 1733, 3187, 1917, 31453}},
-{2404, 15, 4828, {1, 1, 7, 13, 3, 21, 85, 113, 483, 461, 1343, 561, 2081, 10857, 24253}},
-{2405, 15, 4838, {1, 1, 1, 1, 11, 11, 53, 135, 25, 163, 1729, 617, 1533, 10881, 16041}},
-{2406, 15, 4852, {1, 1, 5, 1, 3, 49, 125, 139, 77, 891, 815, 3431, 4875, 12513, 4595}},
-{2407, 15, 4856, {1, 1, 1, 1, 27, 63, 111, 109, 421, 425, 345, 1613, 5447, 1357, 32413}},
-{2408, 15, 4873, {1, 3, 5, 3, 17, 5, 37, 171, 259, 281, 1003, 2901, 3241, 15557, 21415}},
-{2409, 15, 4887, {1, 1, 5, 11, 15, 55, 75, 199, 493, 215, 1625, 2345, 7873, 2325, 11003}},
-{2410, 15, 4891, {1, 3, 7, 1, 21, 33, 23, 5, 495, 941, 1185, 475, 5799, 15161, 10677}},
-{2411, 15, 4904, {1, 1, 5, 9, 31, 37, 37, 29, 217, 389, 297, 3097, 7319, 2601, 15307}},
-{2412, 15, 4912, {1, 3, 7, 5, 7, 45, 111, 167, 297, 275, 1669, 2489, 1511, 15753, 1289}},
-{2413, 15, 4921, {1, 3, 1, 7, 3, 45, 19, 11, 189, 199, 1227, 2647, 1897, 9077, 17189}},
-{2414, 15, 4936, {1, 1, 1, 13, 15, 39, 19, 179, 147, 341, 283, 3029, 7599, 8937, 18761}},
-{2415, 15, 4941, {1, 3, 3, 9, 3, 11, 41, 255, 365, 835, 921, 389, 919, 15223, 14541}},
-{2416, 15, 4942, {1, 1, 3, 3, 5, 37, 29, 203, 313, 271, 1207, 487, 3711, 3811, 26757}},
-{2417, 15, 4963, {1, 3, 7, 9, 19, 53, 49, 139, 351, 537, 1681, 1595, 5399, 13839, 28685}},
-{2418, 15, 4984, {1, 3, 1, 1, 15, 35, 21, 37, 247, 891, 1855, 1243, 3137, 10381, 30379}},
-{2419, 15, 4990, {1, 3, 7, 5, 9, 47, 91, 25, 479, 337, 781, 3545, 1045, 9491, 22853}},
-{2420, 15, 5005, {1, 1, 5, 15, 19, 31, 81, 5, 117, 923, 565, 2443, 7383, 1795, 11685}},
-{2421, 15, 5013, {1, 3, 3, 5, 17, 15, 21, 245, 489, 889, 2047, 2737, 7445, 14785, 13401}},
-{2422, 15, 5020, {1, 1, 1, 15, 19, 45, 67, 117, 299, 607, 953, 743, 6863, 12123, 6701}},
-{2423, 15, 5039, {1, 1, 3, 1, 1, 43, 19, 129, 345, 861, 209, 2387, 7205, 7131, 8235}},
-{2424, 15, 5048, {1, 3, 5, 1, 1, 13, 75, 99, 333, 157, 23, 1217, 1857, 15479, 16031}},
-{2425, 15, 5062, {1, 3, 3, 11, 7, 61, 119, 89, 491, 401, 227, 1739, 3807, 16003, 2875}},
-{2426, 15, 5080, {1, 3, 7, 15, 13, 55, 3, 159, 405, 593, 975, 361, 2563, 6061, 28087}},
-{2427, 15, 5085, {1, 1, 3, 13, 19, 5, 5, 9, 119, 41, 33, 1111, 4443, 4663, 28841}},
-{2428, 15, 5086, {1, 1, 7, 7, 25, 59, 125, 255, 49, 947, 1673, 2947, 6369, 2267, 8813}},
-{2429, 15, 5095, {1, 1, 5, 15, 25, 25, 111, 193, 217, 193, 821, 2779, 69, 2957, 27043}},
-{2430, 15, 5096, {1, 3, 5, 7, 21, 19, 51, 157, 203, 487, 1745, 1875, 911, 14071, 7557}},
-{2431, 15, 5102, {1, 1, 5, 9, 3, 15, 55, 73, 313, 245, 1061, 1929, 3035, 607, 11563}},
-{2432, 15, 5107, {1, 1, 5, 7, 3, 57, 105, 121, 461, 43, 803, 1801, 4059, 2157, 17547}},
-{2433, 15, 5141, {1, 3, 7, 7, 19, 11, 1, 121, 499, 841, 601, 3515, 2969, 13697, 8917}},
-{2434, 15, 5145, {1, 3, 3, 3, 13, 35, 113, 231, 391, 689, 697, 2871, 7387, 715, 27005}},
-{2435, 15, 5148, {1, 1, 1, 13, 19, 5, 17, 43, 175, 291, 987, 1917, 7635, 15655, 10689}},
-{2436, 15, 5157, {1, 1, 7, 15, 19, 37, 121, 243, 125, 623, 1231, 29, 2325, 5147, 21435}},
-{2437, 15, 5158, {1, 3, 5, 15, 25, 27, 57, 187, 77, 401, 1489, 2977, 5415, 3381, 2551}},
-{2438, 15, 5162, {1, 1, 1, 7, 1, 1, 85, 27, 115, 559, 9, 2365, 711, 5733, 2819}},
-{2439, 15, 5172, {1, 3, 1, 15, 9, 29, 61, 113, 169, 349, 591, 1061, 6041, 7613, 23691}},
-{2440, 15, 5182, {1, 1, 5, 1, 13, 45, 49, 227, 345, 563, 87, 3597, 3961, 7205, 8441}},
-{2441, 15, 5184, {1, 1, 1, 5, 3, 21, 121, 183, 463, 83, 1365, 539, 1485, 10063, 24867}},
-{2442, 15, 5193, {1, 3, 5, 5, 3, 61, 101, 237, 41, 147, 1907, 3049, 7583, 8283, 6099}},
-{2443, 15, 5199, {1, 3, 1, 15, 31, 57, 19, 155, 445, 805, 1793, 207, 1975, 3357, 14281}},
-{2444, 15, 5201, {1, 1, 7, 13, 9, 39, 27, 73, 165, 345, 543, 4095, 133, 10469, 11573}},
-{2445, 15, 5204, {1, 1, 7, 15, 17, 57, 99, 81, 359, 367, 1057, 1173, 4225, 15127, 2615}},
-{2446, 15, 5211, {1, 3, 5, 3, 31, 23, 113, 111, 495, 947, 1625, 1195, 2053, 1509, 1347}},
-{2447, 15, 5223, {1, 1, 5, 5, 9, 47, 25, 63, 455, 107, 771, 3815, 3827, 16287, 11615}},
-{2448, 15, 5230, {1, 1, 7, 9, 17, 61, 51, 215, 63, 123, 1253, 3927, 721, 9647, 3283}},
-{2449, 15, 5232, {1, 1, 5, 15, 11, 17, 83, 255, 473, 107, 681, 763, 7855, 8043, 31503}},
-{2450, 15, 5253, {1, 3, 1, 7, 7, 31, 37, 5, 253, 155, 2017, 609, 1421, 14927, 25241}},
-{2451, 15, 5257, {1, 3, 3, 13, 31, 25, 21, 241, 431, 193, 681, 2265, 5091, 11479, 21443}},
-{2452, 15, 5260, {1, 3, 5, 5, 15, 9, 49, 255, 157, 995, 631, 1995, 3605, 9085, 24245}},
-{2453, 15, 5284, {1, 3, 3, 7, 19, 31, 85, 153, 493, 951, 451, 1587, 6609, 3681, 13205}},
-{2454, 15, 5306, {1, 1, 5, 1, 17, 41, 107, 231, 307, 361, 575, 3239, 3443, 16159, 20625}},
-{2455, 15, 5331, {1, 1, 7, 9, 31, 49, 93, 79, 181, 117, 1241, 3645, 4901, 12599, 13247}},
-{2456, 15, 5334, {1, 3, 3, 9, 7, 31, 127, 201, 11, 199, 1851, 23, 5667, 8159, 20951}},
-{2457, 15, 5364, {1, 3, 3, 7, 3, 37, 29, 189, 65, 461, 769, 321, 6577, 16223, 16865}},
-{2458, 15, 5367, {1, 1, 5, 11, 1, 13, 91, 167, 33, 111, 1445, 1047, 2479, 12623, 22893}},
-{2459, 15, 5371, {1, 1, 3, 1, 3, 1, 47, 185, 329, 903, 1651, 3005, 907, 1255, 8303}},
-{2460, 15, 5382, {1, 3, 5, 13, 19, 31, 5, 233, 265, 769, 1303, 2503, 2229, 14019, 20257}},
-{2461, 15, 5386, {1, 3, 7, 3, 27, 11, 67, 195, 5, 661, 125, 3761, 7211, 16043, 7267}},
-{2462, 15, 5399, {1, 1, 1, 3, 27, 13, 115, 25, 473, 417, 1751, 2223, 2099, 5913, 14273}},
-{2463, 15, 5400, {1, 3, 7, 15, 13, 53, 99, 115, 225, 737, 1621, 539, 4131, 471, 31865}},
-{2464, 15, 5409, {1, 1, 5, 5, 25, 19, 39, 207, 153, 569, 1755, 2477, 3065, 7383, 29919}},
-{2465, 15, 5415, {1, 3, 5, 11, 13, 59, 33, 3, 435, 273, 701, 3819, 7291, 11803, 26111}},
-{2466, 15, 5416, {1, 1, 3, 9, 29, 19, 71, 59, 93, 1019, 887, 83, 4675, 7541, 26821}},
-{2467, 15, 5424, {1, 3, 1, 3, 21, 53, 71, 73, 43, 321, 1581, 1399, 4043, 12995, 16825}},
-{2468, 15, 5436, {1, 3, 7, 15, 3, 13, 37, 11, 93, 873, 1193, 3481, 451, 15869, 17879}},
-{2469, 15, 5454, {1, 3, 1, 11, 31, 19, 101, 57, 129, 753, 853, 463, 6757, 11083, 8667}},
-{2470, 15, 5462, {1, 3, 5, 15, 25, 41, 25, 197, 235, 609, 905, 993, 3233, 1935, 24661}},
-{2471, 15, 5468, {1, 3, 1, 5, 21, 7, 53, 107, 473, 77, 1135, 1045, 4933, 5615, 15931}},
-{2472, 15, 5481, {1, 3, 7, 11, 3, 9, 105, 183, 151, 527, 425, 975, 4073, 913, 2793}},
-{2473, 15, 5505, {1, 1, 7, 13, 19, 61, 81, 9, 413, 851, 1723, 1113, 1453, 8635, 3353}},
-{2474, 15, 5511, {1, 3, 7, 15, 19, 53, 83, 31, 441, 343, 575, 935, 4543, 1303, 12567}},
-{2475, 15, 5518, {1, 1, 1, 5, 29, 19, 119, 75, 3, 591, 845, 649, 1717, 13695, 26905}},
-{2476, 15, 5530, {1, 1, 7, 9, 5, 53, 127, 191, 15, 773, 1433, 2899, 21, 4977, 17839}},
-{2477, 15, 5532, {1, 1, 5, 9, 21, 9, 99, 115, 397, 99, 725, 3835, 973, 1219, 21159}},
-{2478, 15, 5539, {1, 3, 5, 3, 7, 39, 29, 93, 303, 913, 981, 3549, 5225, 10907, 393}},
-{2479, 15, 5553, {1, 3, 3, 11, 9, 25, 105, 101, 1, 867, 389, 2241, 773, 14123, 10015}},
-{2480, 15, 5573, {1, 1, 5, 1, 1, 37, 117, 213, 391, 779, 1851, 1485, 1277, 5607, 819}},
-{2481, 15, 5580, {1, 3, 7, 1, 3, 5, 43, 47, 483, 367, 749, 1693, 4961, 15257, 3775}},
-{2482, 15, 5597, {1, 3, 3, 1, 27, 11, 21, 83, 437, 379, 1041, 393, 5611, 2421, 31739}},
-{2483, 15, 5602, {1, 3, 5, 7, 19, 1, 79, 63, 53, 201, 1159, 2501, 6327, 11317, 9537}},
-{2484, 15, 5608, {1, 3, 5, 13, 9, 37, 61, 217, 427, 913, 1311, 3503, 5473, 10583, 19723}},
-{2485, 15, 5611, {1, 1, 3, 9, 11, 29, 121, 175, 141, 515, 925, 837, 6011, 10419, 32157}},
-{2486, 15, 5613, {1, 3, 5, 9, 27, 57, 97, 175, 365, 367, 1737, 3845, 1257, 12243, 2201}},
-{2487, 15, 5625, {1, 3, 3, 9, 23, 1, 53, 123, 127, 333, 1335, 707, 5747, 6541, 9809}},
-{2488, 15, 5632, {1, 3, 1, 9, 17, 37, 101, 41, 91, 61, 433, 979, 4345, 12351, 10829}},
-{2489, 15, 5635, {1, 3, 3, 13, 3, 21, 15, 49, 257, 99, 1793, 2987, 5233, 11625, 28069}},
-{2490, 15, 5638, {1, 1, 7, 11, 21, 13, 89, 11, 135, 153, 783, 2893, 6815, 12007, 15605}},
-{2491, 15, 5652, {1, 3, 7, 13, 5, 61, 73, 5, 269, 699, 925, 2925, 5919, 5841, 24875}},
-{2492, 15, 5659, {1, 3, 5, 5, 25, 45, 43, 93, 15, 927, 1253, 319, 1173, 14559, 20221}},
-{2493, 15, 5677, {1, 1, 3, 3, 27, 45, 9, 103, 447, 627, 1239, 3869, 2169, 49, 17917}},
-{2494, 15, 5686, {1, 3, 7, 7, 11, 9, 1, 1, 1, 527, 825, 3295, 623, 2095, 10537}},
-{2495, 15, 5689, {1, 3, 3, 11, 21, 11, 59, 165, 33, 743, 1461, 1535, 6393, 1301, 17823}},
-{2496, 15, 5698, {1, 1, 7, 3, 19, 43, 47, 245, 469, 551, 1447, 1963, 169, 1481, 31925}},
-{2497, 15, 5703, {1, 1, 3, 1, 11, 21, 51, 7, 251, 199, 1153, 767, 6417, 3417, 30171}},
-{2498, 15, 5707, {1, 3, 7, 1, 31, 5, 41, 103, 447, 263, 211, 2029, 8021, 4705, 10579}},
-{2499, 15, 5731, {1, 1, 3, 5, 17, 25, 55, 75, 393, 107, 2017, 2389, 1685, 14021, 9161}},
-{2500, 15, 5738, {1, 1, 1, 9, 13, 1, 75, 237, 205, 461, 689, 2531, 2839, 13925, 23351}},
-{2501, 15, 5743, {1, 3, 7, 1, 23, 39, 33, 189, 157, 571, 239, 1053, 1559, 1685, 23059}},
-{2502, 15, 5748, {1, 3, 3, 3, 27, 61, 71, 121, 49, 157, 1341, 1707, 2417, 11689, 26507}},
-{2503, 15, 5758, {1, 3, 7, 7, 19, 63, 47, 53, 95, 791, 1467, 1273, 2045, 755, 8555}},
-{2504, 15, 5762, {1, 1, 3, 15, 27, 33, 21, 253, 317, 153, 1509, 1765, 3809, 601, 5907}},
-{2505, 15, 5768, {1, 3, 5, 15, 11, 17, 97, 91, 165, 199, 1751, 2135, 1315, 3077, 29995}},
-{2506, 15, 5773, {1, 3, 1, 5, 3, 33, 93, 49, 39, 743, 341, 2549, 7603, 3369, 30889}},
-{2507, 15, 5776, {1, 1, 3, 13, 3, 5, 87, 63, 293, 785, 1591, 675, 3915, 2209, 18201}},
-{2508, 15, 5815, {1, 3, 3, 11, 3, 15, 69, 231, 241, 127, 429, 2201, 8173, 12549, 25745}},
-{2509, 15, 5841, {1, 1, 5, 11, 15, 39, 3, 29, 125, 685, 643, 1385, 829, 7347, 28793}},
-{2510, 15, 5847, {1, 1, 7, 15, 27, 15, 59, 237, 299, 773, 1097, 3875, 6503, 7129, 28495}},
-{2511, 15, 5860, {1, 3, 5, 13, 9, 17, 31, 227, 69, 443, 1633, 525, 1659, 14681, 15209}},
-{2512, 15, 5870, {1, 3, 5, 5, 13, 51, 69, 173, 111, 433, 279, 2145, 2091, 9741, 24881}},
-{2513, 15, 5875, {1, 3, 1, 7, 7, 35, 55, 51, 357, 99, 1789, 333, 2073, 10151, 14527}},
-{2514, 15, 5877, {1, 3, 3, 7, 13, 41, 101, 87, 425, 701, 1143, 2733, 6473, 8667, 17419}},
-{2515, 15, 5884, {1, 1, 5, 5, 25, 29, 63, 31, 385, 537, 563, 607, 6723, 9251, 6531}},
-{2516, 15, 5892, {1, 3, 5, 5, 9, 63, 111, 131, 239, 723, 705, 2805, 6579, 12691, 17521}},
-{2517, 15, 5902, {1, 3, 1, 7, 31, 55, 101, 225, 477, 271, 611, 3179, 7859, 9835, 2165}},
-{2518, 15, 5910, {1, 1, 3, 3, 5, 15, 81, 127, 391, 333, 419, 1091, 5997, 12315, 31521}},
-{2519, 15, 5916, {1, 3, 5, 15, 23, 7, 35, 109, 181, 295, 825, 419, 969, 15753, 9365}},
-{2520, 15, 5919, {1, 3, 5, 5, 25, 23, 69, 177, 325, 359, 1577, 619, 6233, 11753, 8103}},
-{2521, 15, 5935, {1, 3, 5, 11, 31, 13, 79, 61, 241, 1011, 1961, 949, 6211, 497, 7099}},
-{2522, 15, 5937, {1, 3, 5, 3, 25, 19, 67, 235, 337, 1015, 1485, 355, 3653, 12735, 14503}},
-{2523, 15, 5944, {1, 3, 5, 7, 31, 23, 35, 231, 147, 15, 263, 1995, 431, 5941, 18931}},
-{2524, 15, 5947, {1, 3, 3, 7, 1, 35, 37, 7, 85, 443, 715, 743, 2189, 12537, 17427}},
-{2525, 15, 5958, {1, 1, 3, 1, 7, 41, 1, 209, 121, 929, 661, 3999, 955, 5123, 31115}},
-{2526, 15, 5962, {1, 1, 3, 5, 11, 43, 127, 125, 107, 293, 273, 2071, 3003, 11631, 7769}},
-{2527, 15, 5969, {1, 1, 1, 13, 13, 29, 39, 217, 111, 779, 1287, 1675, 4201, 4869, 20403}},
-{2528, 15, 5981, {1, 1, 3, 15, 25, 53, 25, 135, 389, 925, 1971, 663, 7545, 2673, 7725}},
-{2529, 15, 5995, {1, 1, 5, 13, 3, 59, 97, 91, 357, 45, 947, 3031, 8095, 6269, 13975}},
-{2530, 15, 5998, {1, 1, 5, 15, 25, 31, 1, 171, 375, 939, 507, 3591, 1089, 13605, 2813}},
-{2531, 15, 6003, {1, 1, 3, 7, 25, 21, 41, 131, 147, 737, 9, 1603, 1859, 11573, 28397}},
-{2532, 15, 6010, {1, 3, 3, 9, 21, 9, 59, 27, 169, 875, 711, 1389, 2899, 7937, 4173}},
-{2533, 15, 6016, {1, 1, 5, 9, 13, 29, 71, 39, 51, 337, 1067, 2661, 1203, 5967, 19249}},
-{2534, 15, 6025, {1, 3, 7, 1, 17, 21, 43, 79, 181, 741, 1901, 3445, 7171, 2109, 1589}},
-{2535, 15, 6031, {1, 1, 3, 9, 23, 37, 105, 51, 227, 775, 1265, 2987, 2197, 13903, 28891}},
-{2536, 15, 6036, {1, 1, 1, 13, 23, 47, 111, 41, 93, 261, 75, 2155, 4301, 11517, 16101}},
-{2537, 15, 6039, {1, 1, 3, 3, 27, 27, 123, 125, 501, 775, 413, 1065, 7607, 15065, 26013}},
-{2538, 15, 6045, {1, 3, 7, 3, 27, 11, 59, 87, 207, 743, 1765, 2969, 913, 8101, 11583}},
-{2539, 15, 6049, {1, 3, 3, 1, 23, 7, 113, 17, 285, 993, 695, 2399, 5019, 4779, 28917}},
-{2540, 15, 6052, {1, 3, 1, 5, 11, 51, 49, 139, 213, 435, 1475, 2209, 6695, 12981, 9851}},
-{2541, 15, 6067, {1, 3, 5, 7, 1, 63, 31, 151, 173, 767, 1453, 1497, 6911, 9597, 25551}},
-{2542, 15, 6074, {1, 1, 7, 7, 21, 53, 39, 159, 389, 231, 309, 359, 7701, 14819, 5175}},
-{2543, 15, 6087, {1, 1, 1, 1, 11, 47, 83, 29, 247, 89, 369, 2727, 3103, 14421, 17369}},
-{2544, 15, 6101, {1, 3, 1, 5, 25, 25, 111, 245, 239, 755, 113, 1765, 3583, 917, 403}},
-{2545, 15, 6121, {1, 3, 3, 3, 5, 59, 85, 151, 463, 591, 743, 3767, 121, 2927, 11031}},
-{2546, 15, 6129, {1, 3, 5, 9, 11, 39, 77, 161, 275, 233, 1991, 2683, 6545, 2423, 32113}},
-{2547, 15, 6142, {1, 3, 5, 11, 5, 57, 13, 229, 329, 757, 1863, 3959, 4243, 7265, 15599}},
-{2548, 15, 6151, {1, 1, 1, 1, 1, 23, 19, 67, 453, 593, 2011, 1813, 4695, 8903, 9623}},
-{2549, 15, 6157, {1, 3, 3, 7, 1, 29, 103, 255, 493, 647, 1709, 4065, 4199, 949, 28829}},
-{2550, 15, 6166, {1, 1, 7, 9, 3, 55, 53, 33, 5, 223, 423, 3347, 7647, 7211, 25157}},
-{2551, 15, 6170, {1, 3, 5, 13, 3, 43, 79, 255, 471, 573, 1007, 2119, 6731, 10047, 23179}},
-{2552, 15, 6175, {1, 1, 1, 3, 7, 39, 55, 61, 53, 377, 435, 401, 3307, 12621, 14299}},
-{2553, 15, 6186, {1, 3, 3, 7, 21, 31, 67, 17, 243, 425, 747, 2995, 1389, 2557, 18415}},
-{2554, 15, 6203, {1, 3, 1, 3, 3, 39, 75, 11, 447, 249, 1135, 1011, 1657, 10767, 19501}},
-{2555, 15, 6217, {1, 3, 1, 11, 17, 51, 117, 129, 17, 143, 785, 103, 5049, 14703, 28479}},
-{2556, 15, 6231, {1, 3, 7, 5, 13, 17, 75, 255, 75, 661, 1175, 477, 1811, 1479, 15783}},
-{2557, 15, 6241, {1, 3, 7, 9, 11, 57, 101, 77, 431, 247, 997, 3657, 5117, 6815, 3841}},
-{2558, 15, 6242, {1, 1, 5, 1, 17, 21, 101, 183, 209, 69, 299, 1585, 6381, 12983, 10053}},
-{2559, 15, 6248, {1, 1, 7, 3, 5, 13, 21, 63, 83, 857, 749, 1251, 5363, 9629, 16563}},
-{2560, 15, 6256, {1, 3, 3, 9, 3, 59, 9, 45, 55, 489, 137, 2423, 2661, 12111, 4375}},
-{2561, 15, 6265, {1, 1, 5, 9, 23, 9, 41, 177, 447, 671, 1631, 3115, 4215, 14435, 8743}},
-{2562, 15, 6275, {1, 3, 7, 11, 19, 23, 15, 221, 413, 783, 1247, 2343, 4397, 3145, 32043}},
-{2563, 15, 6277, {1, 3, 3, 1, 31, 55, 31, 87, 333, 849, 1777, 343, 5199, 1507, 11621}},
-{2564, 15, 6302, {1, 3, 7, 3, 17, 57, 63, 63, 111, 977, 631, 3019, 2953, 14273, 29209}},
-{2565, 15, 6315, {1, 3, 1, 13, 9, 39, 87, 15, 397, 185, 701, 1487, 3807, 13727, 19883}},
-{2566, 15, 6318, {1, 3, 7, 1, 17, 57, 57, 157, 119, 181, 899, 353, 3603, 15041, 7421}},
-{2567, 15, 6330, {1, 1, 7, 3, 29, 13, 29, 191, 105, 373, 961, 1991, 5531, 6793, 29497}},
-{2568, 15, 6343, {1, 3, 3, 11, 7, 61, 65, 39, 215, 187, 191, 1651, 2481, 3951, 24965}},
-{2569, 15, 6347, {1, 1, 7, 5, 25, 11, 105, 23, 257, 771, 1359, 2837, 7821, 12223, 28033}},
-{2570, 15, 6350, {1, 3, 5, 11, 3, 3, 23, 139, 407, 885, 1679, 2979, 8149, 14281, 12487}},
-{2571, 15, 6352, {1, 3, 7, 3, 21, 45, 13, 85, 249, 1015, 2023, 1429, 965, 7091, 31721}},
-{2572, 15, 6371, {1, 1, 1, 13, 19, 5, 119, 47, 91, 285, 211, 2607, 4287, 9197, 455}},
-{2573, 15, 6383, {1, 3, 1, 1, 9, 59, 25, 137, 121, 287, 577, 3325, 2365, 8823, 5033}},
-{2574, 15, 6386, {1, 3, 3, 13, 25, 63, 99, 43, 15, 855, 245, 3189, 59, 5181, 21299}},
-{2575, 15, 6405, {1, 3, 5, 11, 7, 9, 41, 157, 359, 773, 1347, 2049, 4589, 13731, 32133}},
-{2576, 15, 6409, {1, 1, 7, 11, 31, 37, 83, 105, 183, 375, 79, 1821, 1989, 15199, 22207}},
-{2577, 15, 6410, {1, 1, 5, 3, 23, 37, 127, 9, 467, 651, 993, 69, 6943, 4093, 20871}},
-{2578, 15, 6433, {1, 1, 3, 15, 31, 49, 123, 149, 211, 371, 1825, 3011, 485, 1251, 17343}},
-{2579, 15, 6436, {1, 1, 1, 15, 11, 33, 127, 251, 89, 317, 1869, 219, 2275, 14201, 27063}},
-{2580, 15, 6439, {1, 1, 5, 5, 19, 5, 81, 35, 233, 95, 9, 863, 725, 11095, 16217}},
-{2581, 15, 6463, {1, 1, 1, 15, 23, 47, 51, 43, 169, 637, 865, 57, 1509, 1683, 7587}},
-{2582, 15, 6468, {1, 3, 1, 3, 7, 7, 117, 187, 273, 303, 717, 3091, 2083, 3315, 647}},
-{2583, 15, 6477, {1, 1, 5, 15, 13, 27, 23, 227, 145, 547, 1783, 987, 6895, 7135, 11023}},
-{2584, 15, 6496, {1, 1, 5, 11, 21, 39, 57, 203, 477, 17, 985, 1729, 4297, 7483, 13263}},
-{2585, 15, 6511, {1, 3, 7, 9, 3, 49, 71, 45, 143, 967, 39, 583, 2123, 5165, 17437}},
-{2586, 15, 6516, {1, 1, 1, 9, 21, 51, 71, 163, 441, 709, 397, 445, 6167, 7753, 11513}},
-{2587, 15, 6519, {1, 1, 7, 7, 27, 35, 5, 181, 449, 53, 621, 3401, 5263, 4557, 9141}},
-{2588, 15, 6523, {1, 1, 5, 7, 7, 37, 83, 111, 485, 881, 465, 3371, 5603, 371, 29393}},
-{2589, 15, 6530, {1, 3, 1, 15, 7, 47, 41, 245, 377, 823, 309, 3929, 2159, 13917, 13365}},
-{2590, 15, 6539, {1, 3, 7, 7, 7, 29, 25, 141, 19, 611, 79, 2689, 109, 12321, 8345}},
-{2591, 15, 6547, {1, 1, 1, 13, 3, 53, 113, 151, 381, 791, 137, 3185, 3567, 211, 597}},
-{2592, 15, 6589, {1, 1, 3, 9, 7, 53, 87, 89, 491, 861, 467, 3763, 2025, 4187, 9637}},
-{2593, 15, 6592, {1, 1, 7, 1, 27, 33, 71, 41, 63, 1011, 741, 1135, 175, 3739, 21493}},
-{2594, 15, 6601, {1, 3, 3, 5, 9, 19, 55, 175, 325, 55, 1193, 1423, 2049, 9633, 17515}},
-{2595, 15, 6610, {1, 1, 3, 1, 27, 55, 69, 103, 401, 707, 825, 399, 6799, 13199, 6295}},
-{2596, 15, 6616, {1, 3, 7, 3, 19, 63, 25, 151, 17, 159, 1673, 615, 6317, 13261, 26267}},
-{2597, 15, 6619, {1, 3, 7, 9, 27, 1, 77, 129, 423, 647, 707, 2579, 3525, 6723, 31615}},
-{2598, 15, 6626, {1, 3, 3, 7, 7, 31, 35, 241, 309, 369, 895, 3683, 4795, 11319, 451}},
-{2599, 15, 6635, {1, 3, 5, 7, 17, 7, 117, 141, 267, 713, 569, 1915, 4369, 7793, 30853}},
-{2600, 15, 6637, {1, 3, 7, 1, 29, 61, 81, 73, 413, 13, 1977, 3229, 5853, 8451, 15539}},
-{2601, 15, 6638, {1, 3, 7, 1, 5, 45, 109, 21, 431, 487, 2019, 2647, 927, 16015, 10711}},
-{2602, 15, 6652, {1, 3, 1, 3, 11, 19, 37, 183, 451, 377, 269, 3993, 3229, 4899, 26561}},
-{2603, 15, 6656, {1, 3, 1, 11, 5, 19, 121, 55, 57, 117, 687, 83, 3047, 1367, 17595}},
-{2604, 15, 6662, {1, 3, 1, 7, 17, 31, 41, 219, 239, 963, 199, 2895, 5599, 7639, 17201}},
-{2605, 15, 6689, {1, 3, 3, 5, 27, 53, 71, 183, 509, 771, 1809, 1539, 2229, 4893, 17115}},
-{2606, 15, 6699, {1, 1, 3, 9, 9, 9, 13, 49, 265, 643, 1929, 859, 497, 9797, 27771}},
-{2607, 15, 6710, {1, 3, 7, 11, 19, 39, 115, 139, 207, 903, 963, 1849, 4403, 6229, 10021}},
-{2608, 15, 6714, {1, 3, 7, 13, 3, 57, 99, 223, 503, 423, 1755, 807, 1885, 213, 18723}},
-{2609, 15, 6719, {1, 3, 7, 15, 11, 15, 111, 193, 243, 599, 593, 3385, 5393, 15073, 17777}},
-{2610, 15, 6739, {1, 1, 5, 3, 19, 63, 121, 207, 99, 435, 1961, 2747, 6405, 3971, 23481}},
-{2611, 15, 6751, {1, 3, 5, 13, 9, 29, 79, 131, 415, 49, 229, 1003, 3263, 12975, 15987}},
-{2612, 15, 6775, {1, 1, 3, 7, 1, 41, 127, 155, 29, 73, 963, 659, 2741, 3465, 2595}},
-{2613, 15, 6779, {1, 1, 3, 5, 23, 23, 93, 233, 113, 521, 427, 1557, 6917, 12953, 22441}},
-{2614, 15, 6788, {1, 1, 5, 13, 5, 25, 85, 191, 387, 69, 955, 243, 4473, 9813, 21711}},
-{2615, 15, 6798, {1, 3, 3, 7, 1, 53, 95, 65, 231, 995, 539, 2103, 5513, 14087, 28655}},
-{2616, 15, 6815, {1, 3, 5, 3, 17, 13, 19, 227, 197, 91, 1437, 1121, 3307, 6903, 3297}},
-{2617, 15, 6819, {1, 1, 5, 11, 31, 29, 109, 171, 257, 783, 861, 9, 4895, 1859, 10909}},
-{2618, 15, 6825, {1, 1, 7, 13, 5, 47, 61, 5, 363, 351, 1525, 823, 2883, 12435, 17629}},
-{2619, 15, 6826, {1, 1, 5, 11, 9, 3, 69, 159, 371, 477, 1223, 1973, 2757, 413, 31223}},
-{2620, 15, 6836, {1, 1, 3, 5, 23, 45, 43, 195, 423, 829, 1673, 1563, 6633, 14775, 21097}},
-{2621, 15, 6843, {1, 1, 3, 3, 13, 9, 107, 209, 49, 609, 1047, 3691, 7483, 4269, 7557}},
-{2622, 15, 6845, {1, 1, 3, 15, 3, 43, 73, 161, 53, 813, 325, 3439, 7009, 8691, 11711}},
-{2623, 15, 6858, {1, 1, 3, 3, 23, 45, 99, 61, 407, 15, 1515, 1557, 953, 8567, 13729}},
-{2624, 15, 6868, {1, 1, 5, 9, 31, 35, 117, 57, 227, 923, 1373, 1811, 3405, 11979, 10149}},
-{2625, 15, 6877, {1, 1, 3, 9, 15, 53, 105, 209, 153, 67, 1477, 667, 3077, 4911, 3871}},
-{2626, 15, 6881, {1, 1, 3, 3, 21, 53, 93, 101, 183, 1023, 3, 3041, 5815, 9043, 5801}},
-{2627, 15, 6891, {1, 3, 3, 5, 17, 49, 127, 161, 321, 869, 1369, 923, 3235, 711, 30007}},
-{2628, 15, 6896, {1, 1, 3, 3, 15, 17, 97, 229, 389, 159, 1075, 2001, 7905, 15191, 14693}},
-{2629, 15, 6899, {1, 1, 5, 11, 5, 5, 121, 173, 95, 173, 1883, 3915, 1439, 9981, 24375}},
-{2630, 15, 6901, {1, 3, 3, 1, 31, 53, 29, 189, 37, 623, 217, 949, 3959, 7189, 25427}},
-{2631, 15, 6908, {1, 3, 5, 9, 21, 45, 101, 23, 355, 729, 797, 2317, 2931, 7433, 29175}},
-{2632, 15, 6914, {1, 3, 7, 1, 1, 63, 63, 155, 237, 865, 1169, 43, 7335, 6445, 7979}},
-{2633, 15, 6916, {1, 3, 7, 7, 11, 51, 37, 199, 503, 991, 319, 3013, 7885, 12837, 32419}},
-{2634, 15, 6923, {1, 3, 7, 7, 27, 31, 101, 243, 37, 811, 1909, 109, 6455, 7903, 11821}},
-{2635, 15, 6925, {1, 1, 3, 13, 23, 21, 89, 99, 243, 605, 1017, 1871, 1101, 12825, 8227}},
-{2636, 15, 6928, {1, 3, 3, 13, 19, 3, 51, 59, 501, 605, 385, 2189, 3229, 7981, 31407}},
-{2637, 15, 6931, {1, 1, 1, 1, 25, 11, 127, 215, 295, 237, 1245, 3657, 7803, 3897, 655}},
-{2638, 15, 6934, {1, 1, 7, 7, 5, 9, 63, 129, 143, 417, 795, 3409, 2847, 5887, 3093}},
-{2639, 15, 6937, {1, 3, 3, 13, 7, 57, 67, 57, 5, 847, 1185, 3349, 4841, 11457, 8857}},
-{2640, 15, 6938, {1, 1, 3, 3, 9, 53, 51, 43, 85, 437, 13, 2543, 3651, 15493, 767}},
-{2641, 15, 6949, {1, 1, 7, 9, 1, 49, 97, 115, 133, 1011, 1399, 2653, 7765, 13999, 12097}},
-{2642, 15, 6956, {1, 1, 5, 1, 3, 27, 123, 107, 389, 401, 1759, 1333, 1371, 5277, 14865}},
-{2643, 15, 6973, {1, 1, 5, 1, 13, 23, 3, 123, 137, 821, 399, 1671, 3095, 3121, 31387}},
-{2644, 15, 6976, {1, 1, 5, 3, 7, 35, 57, 237, 509, 753, 1783, 2815, 6495, 13283, 7091}},
-{2645, 15, 6981, {1, 1, 7, 11, 5, 37, 77, 109, 7, 969, 1087, 3705, 1695, 14223, 28959}},
-{2646, 15, 6988, {1, 3, 1, 11, 25, 5, 25, 163, 179, 185, 671, 1031, 4537, 11601, 9323}},
-{2647, 15, 6999, {1, 1, 3, 7, 17, 25, 49, 221, 183, 619, 1953, 343, 4523, 14883, 6833}},
-{2648, 15, 7016, {1, 3, 7, 5, 27, 19, 59, 153, 11, 807, 513, 3019, 6875, 5307, 8405}},
-{2649, 15, 7027, {1, 1, 1, 13, 25, 41, 21, 109, 321, 135, 497, 1235, 5177, 5167, 18609}},
-{2650, 15, 7029, {1, 1, 7, 5, 21, 53, 25, 197, 411, 503, 1009, 1921, 4305, 2633, 31415}},
-{2651, 15, 7055, {1, 3, 5, 1, 25, 45, 27, 227, 271, 903, 639, 3805, 657, 8683, 29585}},
-{2652, 15, 7058, {1, 1, 5, 3, 9, 49, 37, 35, 351, 491, 851, 2983, 31, 5619, 6919}},
-{2653, 15, 7074, {1, 1, 5, 3, 11, 49, 33, 153, 393, 1017, 1561, 2795, 4435, 12589, 22349}},
-{2654, 15, 7083, {1, 1, 1, 15, 17, 29, 49, 245, 217, 359, 1133, 393, 3317, 415, 16407}},
-{2655, 15, 7093, {1, 1, 3, 5, 3, 9, 95, 63, 319, 319, 1009, 19, 6453, 16279, 6975}},
-{2656, 15, 7100, {1, 1, 5, 9, 3, 25, 67, 95, 369, 237, 285, 2409, 671, 5143, 121}},
-{2657, 15, 7105, {1, 1, 3, 1, 9, 49, 35, 87, 317, 185, 445, 2263, 7923, 10183, 26615}},
-{2658, 15, 7112, {1, 3, 3, 11, 9, 59, 29, 135, 129, 477, 353, 3571, 1057, 16329, 23523}},
-{2659, 15, 7118, {1, 1, 1, 15, 13, 11, 19, 5, 133, 827, 1799, 1893, 1939, 1101, 12147}},
-{2660, 15, 7120, {1, 1, 3, 3, 15, 49, 33, 185, 511, 1013, 41, 3499, 6235, 7643, 16725}},
-{2661, 15, 7129, {1, 1, 5, 11, 27, 45, 89, 157, 63, 137, 2047, 1275, 4995, 625, 6111}},
-{2662, 15, 7166, {1, 3, 7, 11, 3, 1, 121, 1, 341, 33, 1895, 3033, 3929, 10257, 21037}},
-{2663, 15, 7207, {1, 3, 3, 11, 7, 11, 117, 5, 115, 287, 335, 3415, 5397, 15065, 19121}},
-{2664, 15, 7216, {1, 3, 3, 13, 21, 25, 15, 125, 277, 125, 801, 3761, 2623, 11333, 16867}},
-{2665, 15, 7226, {1, 3, 5, 11, 19, 33, 21, 71, 499, 747, 1515, 185, 1759, 14623, 895}},
-{2666, 15, 7234, {1, 3, 7, 1, 29, 35, 9, 203, 277, 299, 1509, 2017, 2897, 14175, 1643}},
-{2667, 15, 7236, {1, 3, 5, 11, 7, 47, 111, 197, 459, 941, 1619, 2119, 2191, 11049, 6811}},
-{2668, 15, 7246, {1, 1, 5, 9, 7, 43, 103, 115, 87, 269, 1235, 77, 5887, 1611, 29041}},
-{2669, 15, 7248, {1, 1, 5, 7, 1, 61, 83, 225, 179, 81, 1145, 2403, 1485, 8967, 20607}},
-{2670, 15, 7254, {1, 3, 3, 1, 25, 47, 27, 157, 359, 803, 1683, 1995, 6445, 13113, 17899}},
-{2671, 15, 7263, {1, 3, 1, 7, 21, 37, 43, 119, 245, 49, 1581, 2275, 3311, 4087, 29765}},
-{2672, 15, 7273, {1, 1, 3, 13, 5, 33, 49, 191, 455, 105, 665, 3855, 3207, 2671, 32203}},
-{2673, 15, 7274, {1, 3, 1, 1, 25, 63, 19, 217, 17, 353, 947, 1951, 4097, 9041, 11921}},
-{2674, 15, 7293, {1, 3, 1, 7, 21, 31, 113, 97, 347, 993, 1799, 3831, 3711, 6193, 1235}},
-{2675, 15, 7297, {1, 1, 1, 5, 3, 63, 11, 203, 425, 445, 1361, 531, 1265, 1755, 11685}},
-{2676, 15, 7310, {1, 3, 1, 7, 13, 29, 23, 85, 57, 467, 1835, 133, 7961, 4175, 2445}},
-{2677, 15, 7315, {1, 1, 1, 15, 23, 27, 37, 5, 123, 913, 1293, 1633, 3113, 5413, 26407}},
-{2678, 15, 7317, {1, 1, 5, 13, 27, 1, 121, 151, 303, 931, 375, 3679, 1863, 12301, 30907}},
-{2679, 15, 7331, {1, 3, 1, 9, 31, 9, 49, 203, 177, 937, 1503, 933, 5867, 12533, 13621}},
-{2680, 15, 7338, {1, 3, 3, 15, 1, 41, 23, 191, 191, 931, 837, 3553, 2611, 4735, 18105}},
-{2681, 15, 7340, {1, 1, 5, 7, 27, 49, 51, 111, 435, 195, 1229, 711, 7145, 14571, 31707}},
-{2682, 15, 7346, {1, 1, 7, 7, 3, 41, 59, 203, 291, 903, 1727, 2757, 1463, 6287, 31535}},
-{2683, 15, 7355, {1, 1, 7, 13, 23, 5, 75, 3, 207, 525, 411, 2133, 2231, 477, 7155}},
-{2684, 15, 7366, {1, 3, 5, 7, 13, 19, 111, 225, 489, 83, 1177, 4077, 4617, 14413, 7133}},
-{2685, 15, 7383, {1, 3, 1, 7, 9, 59, 3, 113, 379, 803, 1289, 3347, 4127, 6669, 14867}},
-{2686, 15, 7389, {1, 3, 7, 3, 31, 37, 87, 79, 399, 749, 995, 1611, 3137, 12543, 31955}},
-{2687, 15, 7393, {1, 1, 5, 7, 21, 59, 49, 45, 511, 639, 1033, 2169, 3265, 15001, 10745}},
-{2688, 15, 7396, {1, 1, 5, 1, 25, 19, 23, 203, 11, 883, 1031, 4087, 5059, 11321, 21675}},
-{2689, 15, 7400, {1, 3, 7, 5, 11, 27, 33, 205, 163, 289, 501, 3505, 1515, 1895, 15889}},
-{2690, 15, 7414, {1, 3, 1, 1, 23, 7, 39, 239, 29, 119, 1499, 2071, 6495, 12107, 5339}},
-{2691, 15, 7417, {1, 3, 1, 1, 23, 29, 55, 181, 327, 905, 427, 1033, 427, 3687, 5367}},
-{2692, 15, 7426, {1, 3, 3, 7, 21, 27, 115, 127, 393, 855, 1291, 2121, 381, 9995, 29757}},
-{2693, 15, 7432, {1, 3, 5, 1, 25, 13, 15, 183, 269, 1005, 1531, 3451, 3975, 9479, 23695}},
-{2694, 15, 7452, {1, 3, 7, 7, 19, 31, 111, 97, 33, 179, 1343, 2069, 977, 5043, 9129}},
-{2695, 15, 7468, {1, 3, 1, 5, 17, 57, 99, 129, 379, 829, 837, 1845, 3613, 7351, 19291}},
-{2696, 15, 7488, {1, 3, 3, 5, 31, 23, 119, 229, 135, 389, 9, 705, 6697, 15441, 5303}},
-{2697, 15, 7491, {1, 1, 1, 11, 25, 31, 105, 95, 5, 931, 789, 375, 7543, 9957, 28627}},
-{2698, 15, 7494, {1, 1, 7, 15, 21, 17, 19, 103, 389, 545, 1725, 2867, 4251, 3829, 6907}},
-{2699, 15, 7497, {1, 3, 7, 7, 15, 37, 97, 65, 337, 409, 1649, 2869, 7929, 8905, 21989}},
-{2700, 15, 7515, {1, 3, 5, 3, 11, 15, 69, 29, 353, 207, 233, 411, 2047, 10303, 31655}},
-{2701, 15, 7531, {1, 3, 3, 7, 27, 43, 125, 107, 69, 981, 215, 1955, 3589, 597, 12703}},
-{2702, 15, 7552, {1, 1, 7, 9, 25, 13, 109, 73, 227, 663, 1115, 285, 471, 3359, 15787}},
-{2703, 15, 7562, {1, 3, 7, 5, 1, 45, 7, 79, 441, 149, 701, 1457, 6595, 14829, 20865}},
-{2704, 15, 7564, {1, 3, 7, 15, 15, 47, 83, 239, 295, 23, 1085, 813, 1209, 3573, 2855}},
-{2705, 15, 7569, {1, 1, 3, 15, 13, 7, 59, 67, 255, 537, 1841, 3857, 6821, 15175, 13997}},
-{2706, 15, 7582, {1, 3, 1, 1, 9, 57, 59, 21, 21, 41, 1693, 2805, 7953, 1389, 14105}},
-{2707, 15, 7585, {1, 3, 5, 15, 19, 49, 107, 117, 99, 607, 145, 53, 1863, 9383, 12029}},
-{2708, 15, 7588, {1, 3, 3, 13, 1, 39, 5, 141, 503, 265, 281, 1785, 2673, 6597, 6333}},
-{2709, 15, 7592, {1, 1, 5, 3, 3, 19, 3, 181, 169, 269, 955, 2399, 3157, 11053, 8563}},
-{2710, 15, 7597, {1, 3, 3, 13, 11, 1, 95, 43, 179, 507, 443, 209, 3239, 14239, 21829}},
-{2711, 15, 7603, {1, 1, 7, 9, 3, 17, 99, 179, 445, 479, 1897, 1507, 5753, 4757, 2135}},
-{2712, 15, 7610, {1, 3, 3, 1, 9, 51, 29, 13, 295, 291, 927, 85, 5707, 7447, 32319}},
-{2713, 15, 7624, {1, 1, 1, 3, 13, 11, 21, 157, 213, 327, 1071, 591, 2639, 15405, 6617}},
-{2714, 15, 7642, {1, 3, 5, 1, 7, 25, 55, 47, 495, 681, 727, 2707, 2955, 705, 7489}},
-{2715, 15, 7647, {1, 1, 3, 9, 17, 3, 73, 67, 465, 367, 1473, 3195, 7825, 5299, 1817}},
-{2716, 15, 7653, {1, 1, 1, 1, 19, 31, 77, 253, 71, 599, 1601, 871, 2243, 6699, 13013}},
-{2717, 15, 7654, {1, 1, 7, 9, 21, 1, 71, 115, 5, 65, 767, 925, 7901, 10761, 19431}},
-{2718, 15, 7666, {1, 3, 1, 7, 23, 31, 31, 15, 105, 391, 585, 2995, 2635, 10607, 24951}},
-{2719, 15, 7668, {1, 3, 3, 1, 19, 25, 71, 211, 41, 197, 787, 225, 6781, 813, 10117}},
-{2720, 15, 7684, {1, 3, 3, 3, 17, 29, 3, 153, 231, 643, 1151, 447, 3699, 9625, 26677}},
-{2721, 15, 7705, {1, 1, 5, 9, 1, 25, 71, 21, 395, 297, 557, 3841, 233, 1877, 4569}},
-{2722, 15, 7732, {1, 1, 3, 13, 1, 45, 115, 61, 5, 937, 173, 2109, 2927, 9599, 9155}},
-{2723, 15, 7741, {1, 1, 3, 3, 15, 21, 61, 121, 253, 285, 1083, 3545, 5537, 6773, 2629}},
-{2724, 15, 7749, {1, 3, 3, 15, 13, 63, 33, 77, 49, 849, 1795, 2771, 5481, 9833, 603}},
-{2725, 15, 7750, {1, 1, 7, 5, 1, 39, 113, 237, 225, 1005, 1687, 2297, 3213, 2605, 14669}},
-{2726, 15, 7759, {1, 1, 3, 1, 11, 1, 39, 23, 67, 441, 1235, 2545, 3139, 15901, 29243}},
-{2727, 15, 7764, {1, 3, 1, 3, 15, 49, 39, 57, 311, 345, 525, 223, 4923, 6311, 25275}},
-{2728, 15, 7777, {1, 1, 5, 7, 9, 13, 69, 11, 349, 423, 1773, 1055, 1001, 9359, 17025}},
-{2729, 15, 7790, {1, 1, 1, 13, 15, 63, 89, 207, 335, 591, 1223, 2701, 55, 12471, 13127}},
-{2730, 15, 7817, {1, 1, 3, 5, 15, 19, 83, 67, 407, 113, 1961, 779, 5803, 12417, 21751}},
-{2731, 15, 7826, {1, 3, 3, 1, 21, 53, 81, 95, 405, 427, 1047, 2443, 4153, 5843, 22511}},
-{2732, 15, 7831, {1, 1, 7, 7, 7, 25, 115, 155, 453, 537, 741, 2379, 2343, 16035, 19587}},
-{2733, 15, 7859, {1, 3, 3, 11, 27, 21, 111, 121, 503, 437, 803, 3399, 5303, 10163, 18199}},
-{2734, 15, 7871, {1, 1, 5, 13, 19, 27, 7, 81, 259, 545, 965, 743, 4533, 8813, 21253}},
-{2735, 15, 7873, {1, 1, 5, 5, 1, 59, 37, 11, 105, 343, 75, 1319, 6317, 9593, 1699}},
-{2736, 15, 7876, {1, 3, 1, 9, 13, 9, 115, 131, 387, 1023, 253, 693, 5191, 12777, 10565}},
-{2737, 15, 7900, {1, 3, 1, 15, 7, 35, 111, 195, 287, 305, 533, 1901, 3363, 10085, 30791}},
-{2738, 15, 7904, {1, 1, 3, 9, 27, 51, 21, 77, 413, 925, 717, 791, 4147, 585, 5649}},
-{2739, 15, 7913, {1, 3, 3, 5, 25, 59, 79, 249, 185, 567, 71, 1997, 7373, 2327, 18637}},
-{2740, 15, 7916, {1, 3, 3, 11, 15, 21, 97, 99, 391, 57, 1973, 29, 7451, 2529, 25737}},
-{2741, 15, 7922, {1, 3, 7, 5, 7, 59, 93, 5, 287, 469, 1639, 3637, 5465, 14431, 32265}},
-{2742, 15, 7946, {1, 1, 3, 11, 3, 1, 71, 75, 427, 299, 811, 3697, 3529, 5433, 26957}},
-{2743, 15, 7953, {1, 3, 1, 9, 19, 59, 37, 255, 165, 1005, 19, 2851, 4309, 455, 9485}},
-{2744, 15, 7956, {1, 1, 1, 5, 1, 55, 15, 233, 133, 47, 1831, 713, 2601, 1017, 3201}},
-{2745, 15, 7963, {1, 1, 5, 5, 21, 55, 127, 69, 377, 41, 25, 2295, 7595, 4733, 11615}},
-{2746, 15, 7979, {1, 1, 5, 3, 23, 5, 7, 181, 161, 775, 1095, 2271, 6637, 14489, 6873}},
-{2747, 15, 7981, {1, 3, 5, 9, 9, 15, 5, 133, 357, 21, 127, 2685, 6299, 4363, 17573}},
-{2748, 15, 7984, {1, 3, 3, 9, 13, 39, 51, 223, 201, 401, 1839, 2461, 7633, 6039, 10445}},
-{2749, 15, 7989, {1, 1, 5, 1, 9, 21, 19, 249, 227, 359, 255, 2895, 4117, 2073, 27687}},
-{2750, 15, 7999, {1, 1, 5, 15, 5, 61, 113, 161, 95, 3, 877, 2775, 293, 6655, 4023}},
-{2751, 15, 8001, {1, 3, 7, 1, 7, 55, 73, 39, 295, 403, 985, 2315, 1667, 13525, 1453}},
-{2752, 15, 8021, {1, 1, 5, 1, 27, 1, 85, 195, 11, 713, 1841, 3895, 3131, 2193, 17607}},
-{2753, 15, 8056, {1, 3, 5, 13, 25, 1, 119, 97, 239, 167, 1393, 1753, 6989, 12155, 12509}},
-{2754, 15, 8080, {1, 1, 7, 15, 31, 21, 41, 255, 425, 445, 165, 2097, 5627, 4971, 13207}},
-{2755, 15, 8083, {1, 1, 1, 15, 13, 33, 81, 105, 453, 197, 13, 1547, 7381, 8709, 15103}},
-{2756, 15, 8089, {1, 1, 3, 11, 11, 33, 107, 123, 483, 367, 121, 995, 1911, 8205, 22577}},
-{2757, 15, 8090, {1, 1, 1, 9, 9, 43, 71, 49, 273, 431, 1705, 3313, 4259, 16291, 14345}},
-{2758, 15, 8114, {1, 1, 1, 7, 3, 1, 43, 213, 97, 547, 1559, 1149, 2791, 3751, 887}},
-{2759, 15, 8128, {1, 1, 3, 15, 25, 47, 49, 251, 425, 35, 295, 3767, 6305, 9633, 5045}},
-{2760, 15, 8133, {1, 3, 3, 1, 5, 55, 91, 245, 27, 981, 331, 555, 6553, 11017, 15289}},
-{2761, 15, 8145, {1, 1, 3, 7, 1, 23, 23, 155, 223, 565, 1005, 3211, 3847, 7479, 3643}},
-{2762, 15, 8155, {1, 1, 5, 1, 17, 7, 47, 95, 35, 779, 1685, 2099, 7505, 15425, 18089}},
-{2763, 15, 8161, {1, 3, 3, 7, 3, 63, 83, 151, 211, 147, 611, 1171, 1681, 7687, 13423}},
-{2764, 15, 8182, {1, 3, 3, 1, 3, 27, 107, 117, 497, 537, 195, 3075, 2753, 1665, 19399}},
-{2765, 15, 8186, {1, 1, 1, 7, 23, 5, 103, 209, 117, 845, 1243, 1283, 4253, 9723, 20937}},
-{2766, 15, 8191, {1, 3, 1, 1, 5, 49, 7, 13, 419, 125, 287, 1599, 8161, 1275, 24661}},
-{2767, 15, 8192, {1, 3, 3, 3, 13, 63, 23, 183, 39, 979, 1301, 2349, 905, 15805, 30151}},
-{2768, 15, 8195, {1, 1, 3, 9, 17, 11, 97, 189, 189, 511, 1779, 2077, 6891, 11623, 23949}},
-{2769, 15, 8201, {1, 1, 7, 11, 13, 45, 15, 37, 11, 853, 915, 1569, 6103, 10633, 3137}},
-{2770, 15, 8207, {1, 3, 3, 5, 15, 61, 91, 255, 131, 821, 1755, 1501, 2663, 1747, 941}},
-{2771, 15, 8210, {1, 1, 3, 7, 19, 19, 65, 95, 499, 239, 2023, 3185, 4649, 3861, 3767}},
-{2772, 15, 8228, {1, 3, 5, 15, 15, 63, 55, 93, 127, 303, 171, 1763, 4991, 9479, 9917}},
-{2773, 15, 8249, {1, 3, 7, 5, 31, 53, 111, 35, 433, 163, 1903, 3991, 3585, 643, 21941}},
-{2774, 15, 8252, {1, 3, 1, 9, 27, 39, 67, 89, 487, 349, 587, 1723, 4311, 11321, 25785}},
-{2775, 15, 8258, {1, 3, 5, 7, 1, 63, 23, 237, 507, 689, 1341, 441, 1721, 843, 20335}},
-{2776, 15, 8267, {1, 1, 3, 3, 31, 63, 83, 103, 25, 799, 1379, 1817, 3809, 12285, 16673}},
-{2777, 15, 8270, {1, 1, 5, 3, 25, 29, 99, 193, 21, 549, 33, 3109, 4135, 10071, 32355}},
-{2778, 15, 8275, {1, 3, 1, 7, 13, 27, 83, 189, 121, 167, 379, 1503, 7955, 13189, 313}},
-{2779, 15, 8284, {1, 3, 5, 15, 25, 19, 83, 87, 257, 237, 709, 1169, 1561, 7117, 4785}},
-{2780, 15, 8293, {1, 1, 1, 7, 9, 55, 21, 5, 439, 367, 403, 2311, 6243, 8349, 13127}},
-{2781, 15, 8298, {1, 3, 7, 3, 5, 35, 51, 67, 453, 767, 29, 3293, 6665, 11459, 2799}},
-{2782, 15, 8305, {1, 3, 3, 3, 5, 19, 59, 7, 367, 683, 783, 1317, 7119, 6129, 19525}},
-{2783, 15, 8317, {1, 1, 5, 5, 5, 19, 61, 67, 381, 291, 875, 2179, 2481, 9325, 11253}},
-{2784, 15, 8328, {1, 3, 5, 5, 7, 47, 107, 9, 141, 667, 1989, 821, 3909, 1733, 10187}},
-{2785, 15, 8336, {1, 1, 7, 7, 31, 61, 1, 71, 477, 689, 1539, 3617, 8105, 6535, 3293}},
-{2786, 15, 8345, {1, 1, 5, 5, 23, 9, 103, 197, 241, 249, 297, 3607, 6217, 1673, 30103}},
-{2787, 15, 8351, {1, 3, 1, 5, 23, 15, 115, 105, 365, 51, 825, 2687, 359, 16325, 15083}},
-{2788, 15, 8367, {1, 1, 3, 11, 29, 45, 65, 251, 169, 189, 1243, 2345, 1345, 14471, 25631}},
-{2789, 15, 8379, {1, 1, 5, 9, 7, 63, 81, 167, 309, 539, 1169, 3949, 4193, 12047, 1491}},
-{2790, 15, 8381, {1, 3, 1, 9, 29, 33, 89, 167, 67, 73, 1885, 477, 5745, 13365, 6819}},
-{2791, 15, 8382, {1, 3, 7, 9, 9, 49, 95, 13, 157, 997, 1725, 935, 7543, 6349, 18277}},
-{2792, 15, 8393, {1, 1, 5, 5, 11, 59, 97, 17, 303, 469, 93, 2761, 7395, 9021, 24299}},
-{2793, 15, 8402, {1, 1, 7, 3, 27, 63, 71, 99, 407, 139, 711, 2589, 4715, 5405, 3277}},
-{2794, 15, 8414, {1, 3, 7, 3, 11, 15, 49, 57, 271, 493, 1165, 2839, 8191, 2609, 14759}},
-{2795, 15, 8417, {1, 1, 1, 7, 21, 15, 71, 245, 413, 473, 1321, 1165, 1027, 6983, 12867}},
-{2796, 15, 8420, {1, 1, 5, 3, 15, 21, 19, 197, 401, 627, 2047, 2761, 5807, 5751, 28025}},
-{2797, 15, 8429, {1, 1, 3, 3, 5, 57, 19, 209, 341, 165, 489, 455, 231, 14385, 12457}},
-{2798, 15, 8435, {1, 3, 3, 11, 13, 63, 79, 129, 17, 315, 1881, 1069, 177, 12013, 29567}},
-{2799, 15, 8438, {1, 1, 3, 7, 31, 29, 51, 235, 475, 375, 617, 437, 6379, 8505, 23079}},
-{2800, 15, 8450, {1, 1, 3, 7, 27, 3, 3, 137, 203, 959, 363, 371, 2899, 13491, 22979}},
-{2801, 15, 8452, {1, 3, 3, 3, 9, 1, 57, 7, 363, 537, 713, 2417, 509, 7747, 22135}},
-{2802, 15, 8459, {1, 3, 3, 3, 13, 21, 79, 121, 487, 921, 113, 281, 2853, 14855, 19747}},
-{2803, 15, 8470, {1, 1, 1, 11, 3, 53, 89, 123, 307, 585, 567, 1925, 505, 15935, 20419}},
-{2804, 15, 8486, {1, 1, 3, 3, 15, 45, 77, 197, 499, 683, 1405, 3573, 981, 14135, 19763}},
-{2805, 15, 8490, {1, 1, 1, 11, 27, 31, 61, 191, 29, 601, 373, 2011, 6193, 3599, 4387}},
-{2806, 15, 8500, {1, 3, 5, 9, 7, 13, 1, 193, 469, 603, 1315, 3329, 3761, 8355, 10425}},
-{2807, 15, 8524, {1, 1, 3, 9, 29, 61, 103, 17, 117, 251, 2029, 2963, 3763, 16117, 6627}},
-{2808, 15, 8536, {1, 3, 1, 3, 7, 51, 91, 145, 497, 657, 871, 3707, 5905, 10449, 14901}},
-{2809, 15, 8552, {1, 1, 3, 1, 3, 53, 23, 149, 461, 333, 1809, 1315, 1815, 8223, 13297}},
-{2810, 15, 8558, {1, 1, 1, 7, 15, 31, 3, 47, 443, 829, 1305, 893, 4191, 9681, 32661}},
-{2811, 15, 8570, {1, 3, 1, 3, 27, 43, 51, 221, 295, 825, 649, 2953, 6203, 8237, 20253}},
-{2812, 15, 8576, {1, 3, 1, 3, 9, 35, 41, 195, 249, 225, 387, 3789, 1499, 2559, 28413}},
-{2813, 15, 8582, {1, 1, 5, 15, 19, 29, 13, 115, 333, 787, 787, 723, 2987, 6227, 10865}},
-{2814, 15, 8594, {1, 3, 5, 13, 5, 59, 5, 251, 79, 387, 11, 3167, 6619, 13317, 18979}},
-{2815, 15, 8606, {1, 1, 7, 11, 31, 51, 43, 1, 189, 519, 1945, 2129, 4365, 14059, 3139}},
-{2816, 15, 8619, {1, 1, 7, 5, 31, 9, 43, 19, 151, 533, 1061, 3849, 6871, 6941, 14935}},
-{2817, 15, 8621, {1, 3, 7, 5, 19, 57, 7, 129, 25, 353, 17, 1739, 6513, 399, 28835}},
-{2818, 15, 8624, {1, 3, 5, 15, 25, 15, 37, 125, 39, 239, 271, 65, 2189, 10449, 11815}},
-{2819, 15, 8633, {1, 3, 7, 15, 19, 57, 47, 245, 509, 945, 385, 3987, 3585, 14711, 9655}},
-{2820, 15, 8641, {1, 1, 3, 13, 21, 31, 13, 81, 9, 489, 1321, 63, 1363, 2219, 19541}},
-{2821, 15, 8653, {1, 1, 5, 7, 3, 57, 25, 147, 23, 553, 889, 307, 6429, 15807, 12861}},
-{2822, 15, 8654, {1, 1, 3, 15, 29, 21, 99, 237, 151, 881, 675, 3625, 1159, 11759, 21347}},
-{2823, 15, 8662, {1, 1, 7, 1, 9, 13, 111, 239, 235, 609, 1569, 3271, 2837, 13807, 7301}},
-{2824, 15, 8675, {1, 3, 1, 15, 7, 59, 27, 81, 129, 9, 647, 3595, 1877, 1067, 1859}},
-{2825, 15, 8689, {1, 3, 7, 1, 3, 25, 119, 57, 145, 441, 1045, 789, 215, 1265, 9369}},
-{2826, 15, 8695, {1, 3, 7, 3, 17, 25, 87, 211, 441, 229, 223, 2795, 7241, 7007, 20575}},
-{2827, 15, 8702, {1, 1, 3, 1, 13, 1, 55, 227, 389, 141, 1097, 2487, 7603, 4161, 5025}},
-{2828, 15, 8706, {1, 1, 3, 5, 15, 29, 29, 145, 233, 209, 891, 89, 8097, 2897, 26685}},
-{2829, 15, 8720, {1, 1, 3, 1, 29, 53, 19, 95, 161, 359, 435, 3313, 4955, 7965, 21015}},
-{2830, 15, 8729, {1, 3, 5, 9, 19, 3, 109, 77, 29, 937, 1663, 125, 2453, 1069, 20639}},
-{2831, 15, 8739, {1, 3, 7, 13, 5, 23, 43, 231, 347, 591, 1963, 2491, 4045, 16029, 8149}},
-{2832, 15, 8741, {1, 1, 5, 1, 13, 3, 75, 211, 419, 929, 901, 3453, 8121, 799, 8897}},
-{2833, 15, 8751, {1, 1, 7, 15, 11, 11, 123, 111, 309, 415, 1071, 975, 2009, 12945, 19617}},
-{2834, 15, 8759, {1, 1, 1, 7, 31, 35, 81, 255, 89, 643, 451, 513, 497, 11751, 24215}},
-{2835, 15, 8766, {1, 3, 5, 5, 25, 17, 5, 165, 139, 929, 1927, 1353, 7427, 9719, 17087}},
-{2836, 15, 8777, {1, 3, 5, 1, 21, 55, 79, 85, 333, 847, 1305, 851, 5057, 8361, 18269}},
-{2837, 15, 8783, {1, 3, 7, 15, 27, 17, 55, 125, 395, 223, 271, 781, 1639, 10569, 11143}},
-{2838, 15, 8786, {1, 1, 7, 9, 7, 33, 127, 85, 209, 339, 483, 241, 2523, 14951, 6855}},
-{2839, 15, 8795, {1, 1, 3, 9, 5, 19, 9, 183, 435, 343, 1105, 3139, 7617, 1311, 267}},
-{2840, 15, 8802, {1, 1, 5, 1, 15, 53, 11, 63, 113, 241, 855, 3123, 4777, 3495, 23345}},
-{2841, 15, 8814, {1, 3, 1, 5, 19, 29, 119, 205, 167, 683, 289, 1629, 4977, 8981, 6867}},
-{2842, 15, 8821, {1, 3, 1, 1, 31, 63, 95, 159, 267, 231, 863, 3385, 5315, 7267, 13757}},
-{2843, 15, 8828, {1, 3, 5, 11, 19, 21, 53, 41, 125, 179, 533, 1279, 3759, 7073, 13905}},
-{2844, 15, 8831, {1, 3, 5, 9, 17, 7, 27, 67, 97, 809, 1423, 2743, 2859, 16121, 329}},
-{2845, 15, 8837, {1, 3, 1, 15, 1, 41, 59, 155, 509, 51, 1827, 3739, 3879, 13369, 30821}},
-{2846, 15, 8842, {1, 3, 3, 7, 21, 31, 7, 13, 347, 919, 1225, 497, 5051, 3769, 20211}},
-{2847, 15, 8855, {1, 3, 7, 13, 31, 9, 127, 195, 123, 387, 3, 3593, 6623, 9827, 29319}},
-{2848, 15, 8856, {1, 1, 3, 9, 7, 27, 95, 211, 287, 189, 1683, 1999, 7641, 14983, 4699}},
-{2849, 15, 8868, {1, 1, 5, 3, 7, 21, 29, 189, 101, 423, 885, 3275, 6569, 11023, 22265}},
-{2850, 15, 8877, {1, 3, 5, 3, 9, 33, 79, 75, 327, 975, 287, 3025, 2157, 7301, 24447}},
-{2851, 15, 8890, {1, 3, 3, 15, 31, 27, 63, 1, 71, 119, 1151, 517, 6131, 11055, 179}},
-{2852, 15, 8892, {1, 3, 7, 11, 23, 15, 101, 247, 349, 735, 673, 997, 6451, 229, 32103}},
-{2853, 15, 8900, {1, 3, 5, 15, 7, 1, 51, 135, 207, 741, 1831, 1235, 4747, 11915, 22009}},
-{2854, 15, 8909, {1, 3, 1, 13, 9, 31, 19, 221, 465, 681, 627, 2595, 5617, 14201, 30355}},
-{2855, 15, 8912, {1, 1, 3, 1, 13, 49, 55, 155, 11, 885, 1275, 3591, 2217, 6659, 30885}},
-{2856, 15, 8921, {1, 1, 7, 11, 27, 57, 93, 95, 243, 63, 1405, 2049, 7689, 15943, 18503}},
-{2857, 15, 8922, {1, 1, 7, 7, 5, 11, 47, 189, 467, 631, 1665, 2717, 4285, 2087, 1435}},
-{2858, 15, 8927, {1, 1, 3, 11, 7, 27, 127, 3, 231, 757, 435, 2545, 3537, 9127, 19915}},
-{2859, 15, 8943, {1, 1, 5, 13, 5, 29, 85, 127, 339, 875, 497, 1573, 6553, 11983, 18029}},
-{2860, 15, 8948, {1, 3, 1, 1, 21, 3, 15, 91, 231, 683, 1529, 2651, 4147, 13437, 23861}},
-{2861, 15, 8951, {1, 3, 1, 7, 27, 17, 19, 179, 243, 223, 1037, 1501, 5935, 2259, 25185}},
-{2862, 15, 8958, {1, 1, 3, 15, 11, 19, 127, 27, 483, 219, 583, 2555, 531, 3451, 17875}},
-{2863, 15, 8984, {1, 1, 1, 13, 31, 39, 89, 149, 363, 741, 1355, 4067, 3171, 6783, 1799}},
-{2864, 15, 8994, {1, 1, 3, 11, 25, 51, 45, 235, 379, 123, 1701, 725, 1991, 7471, 9833}},
-{2865, 15, 9000, {1, 1, 5, 13, 15, 47, 13, 201, 263, 57, 375, 2963, 7475, 15929, 13775}},
-{2866, 15, 9013, {1, 1, 3, 1, 29, 29, 11, 161, 345, 253, 97, 255, 7267, 2379, 3933}},
-{2867, 15, 9018, {1, 3, 1, 15, 3, 47, 11, 69, 347, 747, 795, 2401, 3367, 2383, 6125}},
-{2868, 15, 9020, {1, 1, 7, 3, 1, 49, 101, 47, 71, 761, 1503, 2619, 191, 8895, 873}},
-{2869, 15, 9031, {1, 3, 3, 5, 25, 41, 93, 85, 427, 109, 1675, 2409, 4317, 9233, 30283}},
-{2870, 15, 9035, {1, 1, 3, 9, 11, 3, 67, 159, 425, 751, 887, 1415, 403, 15977, 10739}},
-{2871, 15, 9045, {1, 1, 5, 13, 9, 1, 9, 103, 481, 601, 931, 1957, 5763, 7095, 27141}},
-{2872, 15, 9052, {1, 1, 3, 15, 29, 13, 43, 33, 297, 269, 1041, 1411, 3461, 12043, 10045}},
-{2873, 15, 9056, {1, 3, 5, 3, 3, 3, 5, 7, 185, 753, 133, 1561, 5595, 13777, 25795}},
-{2874, 15, 9059, {1, 3, 5, 5, 1, 19, 29, 145, 163, 149, 619, 2603, 7757, 10035, 10189}},
-{2875, 15, 9066, {1, 3, 7, 15, 27, 15, 111, 173, 135, 117, 157, 2601, 7919, 12111, 22795}},
-{2876, 15, 9076, {1, 3, 1, 1, 29, 27, 65, 31, 101, 715, 289, 3643, 2335, 6789, 23397}},
-{2877, 15, 9089, {1, 3, 1, 3, 11, 45, 71, 109, 321, 423, 1695, 169, 3075, 12423, 11391}},
-{2878, 15, 9129, {1, 1, 3, 9, 13, 51, 35, 121, 203, 279, 433, 2725, 7951, 2105, 27333}},
-{2879, 15, 9132, {1, 1, 1, 15, 23, 31, 25, 105, 501, 441, 1511, 3133, 2811, 10595, 21779}},
-{2880, 15, 9147, {1, 1, 5, 13, 7, 1, 97, 193, 121, 993, 1347, 1903, 1883, 6583, 24535}},
-{2881, 15, 9164, {1, 1, 7, 9, 7, 29, 17, 41, 101, 447, 1289, 387, 1891, 2723, 26091}},
-{2882, 15, 9167, {1, 1, 3, 3, 3, 53, 81, 81, 177, 165, 195, 3413, 8177, 3817, 8453}},
-{2883, 15, 9185, {1, 3, 7, 15, 15, 31, 23, 31, 337, 439, 1773, 63, 5351, 5491, 1767}},
-{2884, 15, 9195, {1, 3, 1, 11, 5, 15, 23, 75, 437, 553, 429, 2705, 3625, 13851, 19865}},
-{2885, 15, 9197, {1, 3, 3, 9, 13, 15, 33, 235, 215, 415, 1737, 1409, 2101, 14623, 14717}},
-{2886, 15, 9210, {1, 3, 7, 7, 13, 51, 101, 217, 175, 813, 1639, 4009, 1625, 4991, 17525}},
-{2887, 15, 9217, {1, 1, 5, 13, 23, 33, 29, 175, 39, 673, 557, 3239, 5129, 11049, 27227}},
-{2888, 15, 9229, {1, 3, 7, 13, 1, 37, 33, 139, 493, 891, 1883, 2525, 5741, 15795, 5875}},
-{2889, 15, 9248, {1, 3, 1, 15, 15, 27, 127, 111, 147, 363, 725, 3077, 4341, 9131, 24635}},
-{2890, 15, 9254, {1, 1, 7, 3, 17, 25, 59, 135, 177, 635, 73, 3455, 3083, 6009, 13033}},
-{2891, 15, 9263, {1, 1, 1, 5, 15, 53, 93, 161, 215, 459, 1087, 179, 2235, 8885, 15309}},
-{2892, 15, 9266, {1, 1, 7, 13, 7, 17, 75, 173, 449, 855, 103, 2739, 3421, 11811, 18805}},
-{2893, 15, 9268, {1, 1, 7, 9, 5, 11, 53, 75, 247, 249, 1201, 953, 2455, 4589, 6027}},
-{2894, 15, 9290, {1, 1, 5, 13, 27, 51, 119, 39, 137, 11, 1435, 3773, 3889, 6081, 11829}},
-{2895, 15, 9310, {1, 1, 5, 5, 5, 35, 1, 197, 501, 185, 1039, 1563, 6421, 14373, 25655}},
-{2896, 15, 9316, {1, 1, 3, 13, 31, 55, 115, 183, 483, 655, 1351, 3203, 725, 3299, 22579}},
-{2897, 15, 9338, {1, 3, 5, 11, 31, 31, 83, 59, 395, 21, 1881, 2821, 2251, 11781, 26265}},
-{2898, 15, 9340, {1, 3, 7, 13, 21, 19, 103, 21, 403, 443, 1951, 55, 985, 15983, 15087}},
-{2899, 15, 9343, {1, 1, 5, 15, 29, 11, 51, 53, 255, 183, 1475, 1491, 259, 387, 10303}},
-{2900, 15, 9344, {1, 3, 5, 7, 21, 37, 45, 39, 479, 637, 1325, 3753, 3319, 7403, 31759}},
-{2901, 15, 9350, {1, 1, 3, 5, 7, 43, 89, 53, 269, 187, 995, 141, 119, 8139, 29699}},
-{2902, 15, 9354, {1, 1, 1, 5, 1, 53, 3, 23, 379, 223, 1889, 4035, 1437, 12425, 9051}},
-{2903, 15, 9359, {1, 3, 1, 13, 3, 31, 61, 43, 249, 449, 901, 1921, 3495, 8599, 5263}},
-{2904, 15, 9361, {1, 1, 3, 5, 3, 25, 35, 133, 25, 597, 915, 3663, 5147, 11831, 24269}},
-{2905, 15, 9364, {1, 1, 1, 9, 21, 27, 93, 93, 217, 299, 1881, 3647, 4825, 7989, 24121}},
-{2906, 15, 9368, {1, 3, 1, 15, 5, 15, 49, 129, 315, 631, 2037, 1567, 4043, 15589, 30905}},
-{2907, 15, 9371, {1, 3, 3, 7, 25, 5, 123, 51, 47, 471, 1563, 3947, 7975, 3681, 9611}},
-{2908, 15, 9373, {1, 3, 7, 15, 1, 17, 73, 245, 465, 95, 95, 1159, 1319, 4675, 8841}},
-{2909, 15, 9389, {1, 1, 3, 15, 5, 51, 35, 71, 423, 651, 753, 173, 2131, 15799, 29601}},
-{2910, 15, 9390, {1, 1, 1, 1, 3, 53, 83, 187, 445, 827, 1549, 979, 5363, 1701, 2149}},
-{2911, 15, 9409, {1, 1, 7, 9, 3, 15, 65, 161, 37, 233, 771, 3749, 727, 6857, 17175}},
-{2912, 15, 9443, {1, 1, 7, 7, 27, 29, 107, 247, 249, 353, 773, 3677, 7273, 5419, 29397}},
-{2913, 15, 9445, {1, 3, 3, 7, 31, 49, 87, 159, 145, 497, 1715, 2115, 5035, 6431, 7245}},
-{2914, 15, 9446, {1, 3, 3, 5, 7, 31, 51, 117, 101, 617, 557, 2551, 6589, 13295, 31975}},
-{2915, 15, 9452, {1, 1, 3, 3, 15, 27, 125, 163, 169, 893, 1771, 25, 5787, 10267, 10297}},
-{2916, 15, 9490, {1, 1, 1, 5, 9, 47, 85, 65, 289, 783, 1105, 4035, 4111, 2589, 24575}},
-{2917, 15, 9492, {1, 3, 3, 13, 23, 33, 7, 49, 301, 531, 1713, 2755, 5543, 8153, 24099}},
-{2918, 15, 9495, {1, 1, 5, 9, 7, 39, 101, 67, 417, 923, 757, 1537, 5553, 12233, 20881}},
-{2919, 15, 9508, {1, 1, 5, 1, 19, 7, 25, 123, 125, 183, 573, 3317, 6867, 871, 17631}},
-{2920, 15, 9523, {1, 1, 3, 15, 19, 13, 117, 41, 129, 715, 1525, 2257, 2179, 10807, 23271}},
-{2921, 15, 9543, {1, 3, 1, 5, 25, 53, 19, 169, 289, 569, 1135, 1967, 7001, 15883, 15113}},
-{2922, 15, 9558, {1, 3, 7, 15, 7, 37, 127, 147, 415, 313, 1541, 1889, 3763, 16199, 12681}},
-{2923, 15, 9567, {1, 1, 3, 9, 1, 35, 95, 137, 237, 951, 899, 3177, 6073, 10655, 31687}},
-{2924, 15, 9580, {1, 1, 5, 5, 29, 57, 45, 253, 297, 529, 1553, 467, 8035, 15675, 21691}},
-{2925, 15, 9585, {1, 3, 7, 15, 25, 41, 59, 81, 87, 985, 1001, 2369, 661, 7551, 11829}},
-{2926, 15, 9591, {1, 1, 7, 9, 27, 21, 7, 233, 309, 67, 701, 2737, 4261, 2467, 15691}},
-{2927, 15, 9611, {1, 3, 7, 1, 19, 55, 47, 155, 333, 101, 517, 1991, 4619, 10435, 27241}},
-{2928, 15, 9613, {1, 1, 7, 3, 23, 35, 7, 125, 157, 537, 933, 3281, 4975, 8969, 27581}},
-{2929, 15, 9614, {1, 1, 3, 7, 19, 53, 81, 103, 461, 435, 777, 335, 5261, 12249, 9695}},
-{2930, 15, 9621, {1, 3, 1, 7, 19, 9, 75, 245, 355, 37, 1855, 1339, 3107, 7251, 16543}},
-{2931, 15, 9631, {1, 1, 1, 3, 5, 35, 39, 223, 113, 423, 1423, 713, 6113, 349, 24147}},
-{2932, 15, 9642, {1, 3, 1, 1, 15, 31, 11, 75, 499, 345, 1253, 2629, 2551, 7483, 25395}},
-{2933, 15, 9656, {1, 1, 3, 11, 25, 25, 3, 211, 185, 45, 1865, 1805, 3303, 11091, 529}},
-{2934, 15, 9661, {1, 3, 1, 1, 9, 21, 7, 165, 107, 641, 1083, 2805, 2099, 5855, 18477}},
-{2935, 15, 9667, {1, 3, 5, 3, 9, 21, 77, 103, 505, 277, 335, 797, 3869, 2957, 1979}},
-{2936, 15, 9694, {1, 3, 5, 15, 31, 23, 77, 247, 303, 891, 1261, 3233, 3495, 13111, 13185}},
-{2937, 15, 9715, {1, 3, 5, 11, 11, 35, 49, 229, 149, 931, 881, 775, 2949, 3141, 29157}},
-{2938, 15, 9722, {1, 1, 3, 5, 19, 57, 23, 95, 347, 221, 195, 3561, 1481, 2063, 3979}},
-{2939, 15, 9738, {1, 3, 5, 3, 13, 1, 23, 173, 431, 29, 421, 3235, 2751, 4447, 28283}},
-{2940, 15, 9745, {1, 1, 5, 13, 23, 3, 1, 9, 327, 855, 1251, 2997, 6129, 4223, 11555}},
-{2941, 15, 9758, {1, 3, 7, 13, 29, 21, 37, 229, 217, 353, 1239, 3955, 491, 12183, 14777}},
-{2942, 15, 9764, {1, 1, 5, 5, 1, 33, 103, 187, 183, 939, 1873, 2633, 6143, 15405, 17353}},
-{2943, 15, 9782, {1, 1, 1, 9, 21, 27, 71, 129, 499, 279, 1181, 4053, 2485, 1961, 30603}},
-{2944, 15, 9791, {1, 1, 3, 15, 21, 37, 45, 201, 221, 187, 727, 1241, 6171, 1383, 22277}},
-{2945, 15, 9793, {1, 3, 7, 5, 21, 17, 67, 177, 323, 601, 633, 865, 6131, 10329, 8689}},
-{2946, 15, 9794, {1, 3, 5, 9, 15, 45, 71, 43, 359, 651, 103, 403, 3249, 11769, 6567}},
-{2947, 15, 9805, {1, 3, 3, 13, 3, 23, 101, 145, 367, 999, 1489, 3673, 2959, 10855, 16029}},
-{2948, 15, 9808, {1, 3, 7, 3, 13, 43, 123, 87, 55, 1015, 141, 2917, 6567, 16025, 25555}},
-{2949, 15, 9811, {1, 3, 1, 3, 17, 7, 21, 161, 41, 889, 1315, 1897, 639, 15451, 3049}},
-{2950, 15, 9817, {1, 3, 5, 15, 27, 33, 55, 17, 81, 431, 325, 909, 3547, 10121, 17815}},
-{2951, 15, 9824, {1, 1, 3, 1, 15, 37, 43, 137, 203, 191, 1129, 1585, 435, 3177, 769}},
-{2952, 15, 9836, {1, 3, 7, 11, 21, 23, 125, 41, 17, 951, 465, 3691, 3465, 13247, 13779}},
-{2953, 15, 9851, {1, 3, 3, 1, 31, 23, 43, 101, 405, 739, 1061, 2955, 5643, 16137, 8763}},
-{2954, 15, 9853, {1, 1, 5, 1, 19, 33, 99, 109, 203, 65, 395, 2775, 1373, 2557, 5875}},
-{2955, 15, 9854, {1, 3, 3, 3, 27, 51, 79, 63, 331, 365, 1071, 1661, 4549, 8561, 1719}},
-{2956, 15, 9877, {1, 3, 3, 9, 3, 17, 53, 161, 141, 489, 1325, 1709, 1381, 5093, 171}},
-{2957, 15, 9881, {1, 1, 7, 15, 9, 3, 95, 237, 197, 949, 7, 1837, 729, 10111, 6637}},
-{2958, 15, 9923, {1, 1, 3, 3, 19, 31, 57, 173, 483, 861, 1001, 1919, 3389, 11777, 20693}},
-{2959, 15, 9935, {1, 3, 1, 9, 27, 13, 113, 177, 75, 925, 949, 119, 4759, 7775, 23033}},
-{2960, 15, 9937, {1, 1, 7, 15, 23, 15, 65, 61, 137, 653, 1843, 323, 379, 15157, 29885}},
-{2961, 15, 9954, {1, 3, 3, 7, 29, 3, 11, 205, 347, 745, 1477, 3929, 5749, 4735, 29435}},
-{2962, 15, 9959, {1, 3, 5, 9, 1, 11, 111, 15, 7, 69, 45, 3607, 1099, 9203, 21301}},
-{2963, 15, 9963, {1, 3, 3, 3, 23, 3, 83, 173, 73, 485, 681, 1867, 3839, 11823, 13339}},
-{2964, 15, 9968, {1, 1, 3, 11, 31, 43, 107, 127, 465, 389, 1595, 427, 1571, 5885, 29569}},
-{2965, 15, 9973, {1, 1, 7, 9, 27, 25, 117, 27, 287, 391, 279, 3247, 35, 12973, 5483}},
-{2966, 15, 9974, {1, 3, 7, 11, 19, 55, 45, 127, 245, 945, 305, 3907, 2455, 3163, 31}},
-{2967, 15, 9980, {1, 1, 7, 11, 15, 17, 65, 15, 37, 207, 1447, 3027, 2281, 6557, 16717}},
-{2968, 15, 9983, {1, 1, 1, 13, 5, 27, 33, 213, 29, 603, 1171, 3235, 2255, 2017, 30999}},
-{2969, 15, 9985, {1, 3, 1, 5, 11, 1, 73, 233, 69, 125, 397, 297, 3337, 6191, 31055}},
-{2970, 15, 10003, {1, 1, 1, 15, 1, 1, 65, 145, 201, 917, 1891, 2999, 4069, 10413, 15819}},
-{2971, 15, 10010, {1, 3, 5, 13, 15, 51, 115, 167, 311, 375, 1069, 2595, 3337, 753, 11903}},
-{2972, 15, 10034, {1, 1, 3, 1, 1, 23, 69, 125, 147, 915, 1945, 411, 979, 13863, 30443}},
-{2973, 15, 10040, {1, 3, 1, 11, 5, 1, 93, 23, 135, 93, 1689, 23, 3519, 4491, 24673}},
-{2974, 15, 10063, {1, 1, 7, 3, 11, 59, 93, 153, 487, 475, 1191, 1455, 5963, 8259, 18811}},
-{2975, 15, 10077, {1, 1, 3, 1, 13, 15, 55, 71, 433, 33, 491, 1835, 5695, 10509, 347}},
-{2976, 15, 10081, {1, 1, 1, 15, 19, 1, 23, 47, 235, 101, 1057, 901, 5477, 7079, 30885}},
-{2977, 15, 10082, {1, 1, 5, 13, 11, 43, 119, 77, 441, 121, 783, 827, 1757, 12751, 31593}},
-{2978, 15, 10084, {1, 3, 7, 11, 19, 17, 37, 225, 329, 231, 515, 1541, 7371, 6355, 10905}},
-{2979, 15, 10088, {1, 1, 5, 13, 7, 11, 35, 215, 345, 577, 147, 2803, 3291, 4631, 5329}},
-{2980, 15, 10091, {1, 1, 3, 9, 21, 55, 113, 251, 25, 221, 1445, 3385, 1589, 4109, 29897}},
-{2981, 15, 10105, {1, 1, 5, 7, 9, 45, 5, 33, 331, 285, 1101, 3131, 2713, 5653, 3823}},
-{2982, 15, 10111, {1, 3, 7, 7, 5, 39, 43, 167, 481, 629, 777, 1827, 4653, 403, 4781}},
-{2983, 15, 10118, {1, 3, 3, 7, 31, 33, 31, 159, 313, 673, 1425, 663, 5819, 1297, 26627}},
-{2984, 15, 10127, {1, 3, 3, 1, 19, 61, 117, 93, 373, 491, 1031, 757, 4185, 771, 7265}},
-{2985, 15, 10135, {1, 1, 7, 9, 3, 45, 65, 223, 437, 41, 1139, 2733, 5963, 2709, 25429}},
-{2986, 15, 10169, {1, 3, 5, 11, 21, 27, 31, 127, 255, 761, 1865, 1319, 6583, 9235, 10717}},
-{2987, 15, 10172, {1, 1, 1, 5, 21, 1, 63, 43, 413, 557, 567, 2893, 8017, 2307, 29525}},
-{2988, 15, 10183, {1, 1, 7, 3, 31, 1, 15, 235, 215, 395, 1971, 469, 5275, 431, 5349}},
-{2989, 15, 10190, {1, 1, 1, 13, 25, 59, 71, 245, 389, 279, 1293, 89, 6551, 10285, 14495}},
-{2990, 15, 10192, {1, 1, 5, 5, 9, 63, 17, 229, 425, 939, 877, 3689, 7229, 6707, 30771}},
-{2991, 15, 10211, {1, 3, 7, 7, 11, 29, 43, 41, 25, 237, 1585, 3735, 2617, 7541, 26243}},
-{2992, 15, 10218, {1, 1, 7, 9, 21, 5, 69, 231, 361, 39, 1695, 3043, 2973, 5487, 12857}},
-{2993, 15, 10228, {1, 1, 5, 3, 17, 63, 91, 217, 407, 133, 1373, 4021, 1737, 10043, 4561}},
-{2994, 15, 10235, {1, 3, 7, 9, 31, 13, 101, 231, 175, 457, 89, 2167, 2725, 8505, 375}},
-{2995, 15, 10242, {1, 1, 3, 15, 31, 11, 27, 211, 347, 291, 1881, 3091, 3307, 5117, 13341}},
-{2996, 15, 10244, {1, 3, 5, 5, 13, 25, 5, 197, 237, 135, 635, 1175, 5085, 14737, 10807}},
-{2997, 15, 10271, {1, 3, 3, 9, 7, 63, 107, 127, 147, 477, 1813, 2619, 8089, 2651, 26549}},
-{2998, 15, 10278, {1, 1, 5, 11, 15, 45, 27, 133, 45, 621, 707, 2679, 5929, 19, 9599}},
-{2999, 15, 10296, {1, 3, 7, 9, 21, 37, 41, 255, 69, 1009, 1999, 367, 6177, 10017, 3549}},
-{3000, 15, 10299, {1, 1, 1, 15, 19, 55, 73, 189, 423, 983, 1811, 2551, 4765, 12077, 18205}},
-{3001, 15, 10307, {1, 1, 5, 7, 17, 13, 25, 225, 463, 471, 631, 1811, 5797, 3235, 32253}},
-{3002, 15, 10309, {1, 3, 7, 1, 29, 7, 123, 187, 331, 735, 1757, 1115, 2077, 15725, 2183}},
-{3003, 15, 10310, {1, 3, 7, 9, 17, 61, 111, 93, 21, 1003, 1905, 3719, 2111, 11845, 6427}},
-{3004, 15, 10314, {1, 3, 7, 7, 17, 21, 51, 59, 115, 723, 2039, 2833, 5969, 5737, 18407}},
-{3005, 15, 10316, {1, 3, 3, 13, 9, 47, 95, 233, 13, 281, 1049, 619, 405, 16205, 20097}},
-{3006, 15, 10321, {1, 3, 7, 13, 9, 41, 11, 171, 453, 713, 587, 1669, 2489, 10277, 18599}},
-{3007, 15, 10328, {1, 3, 3, 13, 21, 41, 123, 173, 511, 399, 859, 1515, 5773, 12535, 26289}},
-{3008, 15, 10338, {1, 1, 7, 15, 11, 3, 113, 111, 73, 7, 1191, 2573, 7713, 465, 27615}},
-{3009, 15, 10343, {1, 1, 7, 15, 5, 5, 39, 11, 489, 13, 1041, 1639, 7879, 11899, 6899}},
-{3010, 15, 10344, {1, 1, 5, 9, 27, 31, 15, 237, 401, 795, 1675, 2361, 7333, 12507, 14627}},
-{3011, 15, 10347, {1, 3, 1, 7, 21, 53, 31, 81, 189, 683, 1283, 419, 7585, 9207, 15053}},
-{3012, 15, 10352, {1, 3, 5, 11, 21, 1, 49, 251, 403, 489, 1235, 429, 4855, 4081, 17575}},
-{3013, 15, 10364, {1, 3, 1, 15, 29, 33, 77, 53, 105, 731, 749, 2677, 3967, 7967, 18723}},
-{3014, 15, 10373, {1, 3, 3, 11, 9, 47, 11, 95, 137, 923, 599, 1585, 1969, 9625, 19171}},
-{3015, 15, 10386, {1, 1, 1, 5, 7, 7, 85, 49, 339, 883, 261, 2125, 3831, 9797, 16395}},
-{3016, 15, 10391, {1, 3, 3, 3, 5, 9, 33, 99, 75, 889, 101, 2099, 6635, 11511, 21573}},
-{3017, 15, 10398, {1, 1, 5, 11, 1, 11, 79, 49, 7, 131, 471, 1235, 3287, 14777, 12053}},
-{3018, 15, 10408, {1, 1, 5, 15, 9, 9, 83, 15, 21, 899, 1785, 2349, 3471, 6723, 1405}},
-{3019, 15, 10413, {1, 3, 5, 11, 1, 7, 121, 223, 509, 859, 1037, 491, 5529, 481, 17029}},
-{3020, 15, 10422, {1, 1, 7, 5, 17, 35, 91, 171, 113, 65, 423, 2371, 5105, 12827, 31087}},
-{3021, 15, 10445, {1, 1, 3, 3, 21, 47, 55, 11, 159, 51, 263, 2113, 661, 9147, 28929}},
-{3022, 15, 10460, {1, 1, 1, 9, 19, 7, 43, 223, 207, 787, 543, 2141, 4247, 7369, 29031}},
-{3023, 15, 10463, {1, 1, 7, 11, 11, 51, 121, 9, 211, 905, 687, 889, 1827, 13395, 3507}},
-{3024, 15, 10464, {1, 3, 1, 7, 15, 23, 5, 139, 469, 569, 33, 3477, 5391, 13665, 17011}},
-{3025, 15, 10474, {1, 1, 1, 15, 29, 29, 29, 201, 63, 1019, 97, 1671, 9, 4617, 19833}},
-{3026, 15, 10476, {1, 1, 5, 15, 25, 5, 67, 225, 189, 919, 1471, 1451, 5017, 16189, 31555}},
-{3027, 15, 10487, {1, 3, 5, 5, 15, 51, 89, 221, 149, 863, 43, 2381, 1767, 8037, 5319}},
-{3028, 15, 10494, {1, 3, 3, 1, 15, 17, 5, 77, 69, 27, 1883, 63, 5987, 1497, 3723}},
-{3029, 15, 10499, {1, 3, 7, 11, 7, 5, 113, 229, 123, 709, 1531, 641, 6655, 14923, 22947}},
-{3030, 15, 10506, {1, 3, 1, 13, 21, 15, 45, 175, 81, 499, 1113, 587, 7573, 11689, 15651}},
-{3031, 15, 10513, {1, 3, 1, 1, 29, 43, 101, 37, 131, 757, 465, 743, 2737, 8063, 23967}},
-{3032, 15, 10516, {1, 1, 7, 13, 9, 21, 39, 177, 51, 691, 2047, 1519, 6137, 5271, 8703}},
-{3033, 15, 10523, {1, 1, 3, 3, 5, 55, 63, 21, 3, 317, 461, 527, 2673, 16211, 6721}},
-{3034, 15, 10539, {1, 3, 5, 5, 5, 47, 7, 241, 387, 589, 323, 203, 7241, 14761, 13287}},
-{3035, 15, 10549, {1, 3, 5, 3, 23, 63, 55, 61, 231, 1023, 1315, 1181, 243, 7389, 25639}},
-{3036, 15, 10550, {1, 1, 7, 13, 31, 43, 41, 81, 127, 887, 1513, 4055, 1361, 2443, 6963}},
-{3037, 15, 10567, {1, 1, 1, 5, 7, 43, 43, 33, 323, 911, 1373, 3053, 6503, 513, 6457}},
-{3038, 15, 10576, {1, 1, 7, 11, 25, 61, 21, 149, 205, 349, 1433, 1587, 149, 7275, 5465}},
-{3039, 15, 10625, {1, 3, 5, 5, 11, 9, 31, 217, 119, 511, 209, 3325, 2023, 2877, 463}},
-{3040, 15, 10635, {1, 3, 5, 15, 21, 47, 89, 41, 347, 849, 1375, 3311, 807, 11443, 27643}},
-{3041, 15, 10643, {1, 1, 5, 7, 29, 43, 123, 191, 321, 373, 447, 2145, 1221, 2071, 12689}},
-{3042, 15, 10656, {1, 3, 5, 15, 1, 21, 43, 141, 461, 779, 1109, 2915, 909, 8585, 19859}},
-{3043, 15, 10671, {1, 3, 3, 11, 5, 17, 57, 13, 393, 661, 1761, 2455, 43, 8593, 20505}},
-{3044, 15, 10676, {1, 3, 5, 1, 31, 47, 65, 249, 77, 513, 851, 2381, 3447, 693, 7729}},
-{3045, 15, 10683, {1, 3, 5, 15, 31, 19, 83, 47, 369, 697, 1815, 819, 7573, 9245, 8013}},
-{3046, 15, 10685, {1, 3, 5, 5, 11, 25, 27, 151, 107, 339, 299, 3869, 3393, 5661, 2947}},
-{3047, 15, 10688, {1, 1, 3, 1, 1, 59, 85, 57, 175, 465, 239, 3115, 7157, 7035, 11463}},
-{3048, 15, 10697, {1, 1, 7, 5, 31, 41, 53, 149, 121, 743, 189, 159, 5289, 2945, 1179}},
-{3049, 15, 10700, {1, 3, 3, 15, 23, 51, 83, 25, 159, 163, 61, 713, 4529, 5253, 1603}},
-{3050, 15, 10712, {1, 3, 5, 11, 7, 29, 15, 177, 507, 695, 1305, 1863, 7525, 3063, 27433}},
-{3051, 15, 10724, {1, 1, 3, 11, 5, 41, 115, 227, 409, 951, 591, 4003, 7717, 4369, 15637}},
-{3052, 15, 10728, {1, 1, 7, 11, 23, 55, 71, 135, 51, 411, 2003, 2375, 6823, 1711, 4443}},
-{3053, 15, 10734, {1, 3, 1, 3, 31, 47, 31, 233, 243, 3, 313, 1649, 6955, 13679, 32327}},
-{3054, 15, 10739, {1, 1, 3, 11, 29, 9, 1, 79, 247, 677, 685, 3107, 5987, 9675, 29523}},
-{3055, 15, 10762, {1, 1, 1, 7, 25, 31, 39, 241, 483, 839, 1143, 437, 2317, 2437, 173}},
-{3056, 15, 10772, {1, 1, 5, 1, 17, 19, 83, 57, 39, 479, 715, 1911, 1091, 10937, 22145}},
-{3057, 15, 10781, {1, 1, 7, 1, 27, 45, 35, 55, 477, 719, 217, 3349, 7717, 6853, 9699}},
-{3058, 15, 10800, {1, 3, 1, 11, 9, 39, 25, 223, 303, 713, 151, 2611, 4629, 5855, 31729}},
-{3059, 15, 10805, {1, 1, 1, 11, 13, 35, 53, 39, 167, 779, 1673, 1221, 6281, 15113, 32027}},
-{3060, 15, 10827, {1, 1, 5, 9, 19, 63, 89, 113, 199, 107, 1015, 835, 2879, 9499, 25597}},
-{3061, 15, 10830, {1, 1, 7, 3, 19, 37, 15, 23, 449, 641, 1811, 3407, 6775, 6283, 31157}},
-{3062, 15, 10837, {1, 1, 3, 1, 19, 15, 31, 99, 511, 897, 1693, 2093, 955, 15897, 26693}},
-{3063, 15, 10841, {1, 1, 5, 1, 5, 15, 47, 19, 441, 541, 1621, 3877, 6407, 15991, 1931}},
-{3064, 15, 10847, {1, 3, 5, 9, 21, 61, 15, 77, 265, 351, 879, 3835, 6555, 2349, 23235}},
-{3065, 15, 10848, {1, 1, 5, 11, 25, 37, 29, 181, 341, 641, 1213, 1319, 6359, 6231, 32573}},
-{3066, 15, 10857, {1, 1, 1, 7, 1, 37, 87, 123, 33, 913, 111, 2613, 4895, 12595, 26633}},
-{3067, 15, 10866, {1, 3, 5, 3, 27, 11, 45, 89, 183, 241, 1355, 783, 3343, 239, 8643}},
-{3068, 15, 10868, {1, 3, 7, 7, 9, 35, 67, 187, 233, 577, 1445, 3063, 6039, 16233, 1453}},
-{3069, 15, 10872, {1, 1, 3, 13, 27, 11, 23, 15, 95, 63, 1931, 911, 8149, 6833, 3051}},
-{3070, 15, 10887, {1, 3, 3, 5, 29, 49, 125, 117, 47, 143, 423, 3215, 3605, 3677, 17155}},
-{3071, 15, 10899, {1, 3, 1, 1, 31, 1, 123, 195, 83, 893, 1947, 339, 2927, 7183, 15443}},
-{3072, 15, 10901, {1, 1, 7, 13, 31, 15, 91, 207, 39, 275, 439, 2617, 3093, 11041, 24997}},
-{3073, 15, 10915, {1, 1, 5, 3, 3, 41, 13, 67, 361, 497, 25, 3807, 3551, 9681, 21043}},
-{3074, 15, 10924, {1, 3, 3, 3, 11, 27, 103, 59, 427, 327, 1705, 29, 8127, 1641, 20847}},
-{3075, 15, 10929, {1, 3, 7, 5, 3, 37, 81, 137, 225, 101, 187, 3067, 2491, 12687, 16227}},
-{3076, 15, 10942, {1, 3, 5, 15, 15, 33, 69, 223, 225, 771, 1917, 2293, 2889, 12083, 23971}},
-{3077, 15, 10971, {1, 1, 3, 5, 11, 9, 121, 81, 203, 425, 1189, 2011, 3041, 3247, 739}},
-{3078, 15, 10992, {1, 3, 1, 1, 13, 9, 39, 169, 437, 571, 1481, 3355, 3895, 8975, 31031}},
-{3079, 15, 10995, {1, 3, 1, 11, 1, 43, 35, 35, 293, 11, 657, 1415, 5021, 14463, 17945}},
-{3080, 15, 11002, {1, 1, 5, 5, 13, 47, 91, 15, 159, 23, 971, 3575, 757, 13477, 31757}},
-{3081, 15, 11010, {1, 1, 7, 1, 5, 63, 69, 27, 71, 129, 123, 3767, 89, 7865, 1189}},
-{3082, 15, 11027, {1, 3, 3, 5, 23, 1, 83, 3, 487, 491, 217, 2583, 3889, 15009, 9227}},
-{3083, 15, 11029, {1, 3, 5, 15, 25, 1, 73, 107, 245, 191, 1449, 571, 1403, 6953, 17457}},
-{3084, 15, 11045, {1, 3, 3, 3, 27, 19, 25, 105, 207, 857, 1161, 3657, 2107, 7955, 517}},
-{3085, 15, 11057, {1, 3, 3, 9, 21, 29, 5, 103, 219, 35, 3, 1635, 4815, 15797, 29839}},
-{3086, 15, 11070, {1, 1, 7, 7, 3, 63, 75, 77, 13, 57, 603, 2333, 7761, 14397, 10875}},
-{3087, 15, 11092, {1, 3, 7, 13, 3, 11, 5, 255, 1, 947, 1695, 1927, 7447, 7407, 20797}},
-{3088, 15, 11099, {1, 1, 5, 1, 1, 21, 105, 73, 429, 973, 1801, 3943, 6161, 1309, 3359}},
-{3089, 15, 11106, {1, 1, 3, 15, 27, 9, 9, 129, 117, 545, 9, 1983, 6351, 10925, 27337}},
-{3090, 15, 11115, {1, 3, 3, 5, 5, 5, 13, 155, 503, 875, 1243, 2259, 3445, 11953, 6517}},
-{3091, 15, 11120, {1, 1, 7, 3, 29, 21, 121, 147, 413, 423, 1887, 2429, 2765, 16335, 3071}},
-{3092, 15, 11126, {1, 1, 7, 9, 5, 53, 41, 137, 463, 583, 1627, 1731, 6675, 3703, 8177}},
-{3093, 15, 11153, {1, 3, 5, 11, 31, 29, 67, 159, 425, 25, 1457, 139, 5019, 701, 7357}},
-{3094, 15, 11190, {1, 3, 1, 5, 25, 15, 123, 123, 245, 859, 249, 2175, 2137, 5765, 4873}},
-{3095, 15, 11199, {1, 1, 3, 5, 23, 1, 111, 111, 111, 469, 1473, 1777, 3579, 13503, 2569}},
-{3096, 15, 11222, {1, 1, 7, 3, 17, 23, 51, 23, 499, 135, 713, 3317, 807, 9589, 11349}},
-{3097, 15, 11225, {1, 1, 1, 15, 9, 51, 75, 159, 359, 773, 1521, 2913, 5901, 3047, 14649}},
-{3098, 15, 11226, {1, 1, 3, 1, 13, 61, 117, 195, 49, 267, 57, 1769, 3621, 9415, 29443}},
-{3099, 15, 11231, {1, 3, 7, 11, 3, 25, 33, 31, 315, 191, 359, 3399, 2481, 13831, 20205}},
-{3100, 15, 11244, {1, 3, 3, 5, 31, 43, 35, 125, 291, 51, 1469, 3857, 1707, 2641, 32137}},
-{3101, 15, 11259, {1, 3, 5, 1, 25, 11, 113, 137, 211, 159, 1667, 939, 6439, 5337, 32059}},
-{3102, 15, 11261, {1, 3, 3, 11, 31, 61, 99, 49, 383, 343, 395, 51, 6931, 16039, 5901}},
-{3103, 15, 11270, {1, 1, 3, 5, 9, 63, 63, 49, 405, 915, 1505, 2141, 6749, 7799, 17313}},
-{3104, 15, 11273, {1, 3, 7, 11, 15, 11, 49, 161, 155, 869, 121, 301, 6561, 4279, 15233}},
-{3105, 15, 11300, {1, 1, 5, 13, 19, 13, 103, 59, 503, 293, 701, 2527, 5327, 13927, 5025}},
-{3106, 15, 11307, {1, 1, 7, 1, 1, 37, 55, 155, 485, 399, 855, 2677, 5927, 9657, 2795}},
-{3107, 15, 11318, {1, 1, 1, 5, 19, 15, 121, 69, 385, 75, 1567, 2649, 5601, 12981, 15903}},
-{3108, 15, 11332, {1, 1, 1, 11, 19, 21, 45, 59, 505, 737, 15, 1383, 1177, 8375, 15557}},
-{3109, 15, 11335, {1, 1, 7, 13, 29, 19, 123, 127, 469, 773, 733, 3289, 8087, 5803, 27897}},
-{3110, 15, 11341, {1, 3, 3, 11, 19, 55, 101, 67, 485, 939, 607, 1521, 6161, 12235, 16499}},
-{3111, 15, 11347, {1, 3, 5, 13, 29, 31, 31, 9, 453, 151, 1055, 3873, 405, 12877, 29829}},
-{3112, 15, 11354, {1, 3, 5, 1, 17, 1, 17, 131, 107, 1003, 1749, 1849, 6207, 2153, 21275}},
-{3113, 15, 11360, {1, 3, 7, 15, 7, 25, 51, 143, 51, 517, 1841, 1771, 5389, 4633, 11123}},
-{3114, 15, 11369, {1, 3, 7, 11, 23, 7, 89, 95, 403, 361, 835, 585, 2783, 8091, 5141}},
-{3115, 15, 11372, {1, 3, 1, 9, 1, 53, 115, 11, 493, 587, 305, 3605, 1711, 4169, 20013}},
-{3116, 15, 11378, {1, 3, 7, 3, 17, 59, 55, 251, 49, 759, 1227, 3685, 7765, 1445, 20385}},
-{3117, 15, 11396, {1, 1, 5, 7, 29, 55, 19, 157, 129, 927, 893, 1235, 1955, 8153, 2865}},
-{3118, 15, 11405, {1, 3, 1, 15, 21, 35, 81, 53, 175, 939, 1635, 3597, 747, 14011, 12867}},
-{3119, 15, 11417, {1, 3, 7, 1, 27, 61, 91, 73, 405, 677, 603, 2715, 7099, 941, 24523}},
-{3120, 15, 11424, {1, 3, 5, 9, 13, 45, 35, 167, 57, 483, 735, 2777, 7847, 6257, 13109}},
-{3121, 15, 11427, {1, 3, 5, 7, 1, 3, 97, 13, 159, 533, 1791, 1061, 981, 10795, 26165}},
-{3122, 15, 11430, {1, 1, 5, 13, 27, 5, 125, 25, 251, 221, 1909, 197, 6987, 11537, 15287}},
-{3123, 15, 11439, {1, 3, 5, 5, 27, 15, 1, 131, 375, 923, 81, 3153, 6071, 2515, 23729}},
-{3124, 15, 11442, {1, 3, 3, 9, 9, 23, 71, 13, 465, 261, 937, 1549, 5993, 11325, 15065}},
-{3125, 15, 11448, {1, 3, 1, 3, 7, 63, 17, 129, 435, 23, 215, 2251, 1561, 9703, 26483}},
-{3126, 15, 11461, {1, 1, 3, 1, 5, 53, 77, 109, 9, 605, 371, 2081, 6023, 7145, 15837}},
-{3127, 15, 11468, {1, 3, 7, 11, 27, 39, 115, 47, 259, 337, 1857, 3465, 1549, 7747, 8525}},
-{3128, 15, 11471, {1, 3, 7, 7, 29, 29, 75, 77, 29, 661, 899, 3137, 2661, 15271, 28093}},
-{3129, 15, 11473, {1, 1, 1, 3, 3, 3, 11, 219, 39, 757, 1465, 249, 7445, 7013, 15187}},
-{3130, 15, 11476, {1, 3, 7, 15, 15, 1, 39, 245, 427, 1003, 1493, 1913, 6435, 14787, 13481}},
-{3131, 15, 11480, {1, 1, 7, 3, 3, 37, 5, 97, 343, 833, 1379, 1551, 5403, 1843, 5877}},
-{3132, 15, 11489, {1, 3, 1, 1, 3, 17, 17, 163, 339, 691, 1707, 1845, 5941, 4259, 24531}},
-{3133, 15, 11499, {1, 1, 1, 1, 27, 21, 85, 221, 71, 949, 1753, 391, 6349, 15901, 20811}},
-{3134, 15, 11516, {1, 1, 1, 5, 31, 19, 45, 99, 469, 783, 1747, 3807, 5889, 9485, 13715}},
-{3135, 15, 11522, {1, 3, 1, 9, 23, 21, 39, 25, 421, 713, 461, 2857, 5023, 5341, 6409}},
-{3136, 15, 11531, {1, 3, 7, 5, 25, 19, 59, 147, 387, 857, 375, 3103, 1261, 13697, 25675}},
-{3137, 15, 11539, {1, 3, 5, 5, 31, 21, 49, 251, 463, 441, 473, 3487, 3915, 11151, 17721}},
-{3138, 15, 11546, {1, 1, 3, 9, 15, 47, 81, 219, 143, 141, 81, 1705, 5847, 3437, 30521}},
-{3139, 15, 11551, {1, 1, 7, 3, 25, 19, 97, 41, 77, 105, 1337, 695, 7589, 8587, 7509}},
-{3140, 15, 11564, {1, 1, 5, 13, 3, 11, 61, 19, 139, 667, 963, 1567, 5715, 7079, 15967}},
-{3141, 15, 11582, {1, 1, 5, 5, 5, 29, 67, 57, 477, 173, 1163, 727, 823, 15635, 17705}},
-{3142, 15, 11589, {1, 3, 7, 11, 13, 39, 57, 193, 73, 617, 535, 1623, 4581, 4451, 2589}},
-{3143, 15, 11593, {1, 1, 5, 5, 9, 27, 75, 127, 325, 413, 1669, 1749, 8045, 16199, 12237}},
-{3144, 15, 11601, {1, 1, 3, 1, 17, 23, 27, 189, 319, 953, 347, 909, 4401, 12791, 25077}},
-{3145, 15, 11608, {1, 1, 3, 3, 17, 51, 37, 79, 301, 607, 885, 1169, 3275, 3327, 20013}},
-{3146, 15, 11617, {1, 3, 5, 3, 21, 9, 99, 213, 387, 889, 575, 3591, 5377, 2981, 23989}},
-{3147, 15, 11630, {1, 3, 3, 13, 11, 7, 23, 255, 279, 853, 453, 2377, 8123, 15393, 9669}},
-{3148, 15, 11663, {1, 3, 1, 7, 11, 9, 109, 35, 405, 449, 1967, 2943, 3485, 5031, 14273}},
-{3149, 15, 11666, {1, 3, 3, 1, 25, 27, 43, 115, 435, 675, 1937, 1477, 4831, 9417, 7017}},
-{3150, 15, 11668, {1, 1, 7, 13, 19, 45, 83, 241, 487, 215, 1453, 209, 4061, 1765, 15623}},
-{3151, 15, 11677, {1, 1, 7, 7, 21, 31, 95, 9, 287, 1005, 1933, 3405, 6913, 7733, 18975}},
-{3152, 15, 11682, {1, 1, 1, 11, 13, 11, 25, 39, 283, 57, 255, 2809, 5767, 6127, 6705}},
-{3153, 15, 11687, {1, 3, 1, 11, 1, 51, 73, 181, 261, 215, 385, 2777, 5169, 12431, 23563}},
-{3154, 15, 11696, {1, 3, 3, 9, 9, 39, 123, 197, 501, 679, 109, 3369, 4817, 8855, 7997}},
-{3155, 15, 11713, {1, 1, 5, 1, 29, 61, 15, 183, 453, 999, 1211, 3217, 8035, 5153, 19975}},
-{3156, 15, 11728, {1, 3, 7, 11, 11, 21, 51, 45, 379, 793, 289, 309, 1229, 7159, 581}},
-{3157, 15, 11747, {1, 1, 3, 9, 17, 11, 75, 67, 289, 191, 1083, 2949, 6063, 6611, 21595}},
-{3158, 15, 11750, {1, 3, 7, 3, 27, 45, 59, 193, 485, 277, 27, 1219, 2389, 15875, 6273}},
-{3159, 15, 11754, {1, 1, 5, 3, 31, 29, 65, 197, 115, 163, 9, 783, 5573, 2833, 12603}},
-{3160, 15, 11759, {1, 1, 3, 7, 5, 53, 115, 181, 175, 749, 1335, 1151, 2131, 12467, 15811}},
-{3161, 15, 11761, {1, 1, 1, 9, 27, 39, 11, 1, 443, 677, 777, 1857, 7459, 3177, 3875}},
-{3162, 15, 11764, {1, 1, 7, 7, 17, 3, 23, 161, 105, 603, 1991, 3845, 465, 11467, 2077}},
-{3163, 15, 11767, {1, 1, 3, 13, 5, 23, 39, 35, 399, 795, 265, 207, 1823, 15069, 31839}},
-{3164, 15, 11797, {1, 1, 1, 1, 29, 61, 89, 193, 41, 99, 315, 1021, 6109, 12507, 19973}},
-{3165, 15, 11804, {1, 1, 5, 3, 13, 57, 119, 251, 215, 695, 1521, 4081, 2481, 657, 855}},
-{3166, 15, 11808, {1, 1, 7, 3, 25, 5, 3, 133, 111, 385, 773, 1027, 4327, 3031, 3537}},
-{3167, 15, 11831, {1, 3, 7, 5, 5, 27, 43, 117, 479, 83, 1421, 2791, 6551, 6231, 10353}},
-{3168, 15, 11832, {1, 1, 1, 13, 3, 29, 35, 71, 85, 821, 1671, 3057, 797, 13683, 7025}},
-{3169, 15, 11849, {1, 3, 7, 1, 1, 47, 117, 233, 141, 993, 1381, 2551, 1031, 11765, 18429}},
-{3170, 15, 11855, {1, 3, 1, 3, 13, 3, 77, 29, 35, 807, 1109, 695, 5605, 5477, 449}},
-{3171, 15, 11863, {1, 1, 1, 15, 21, 37, 117, 105, 273, 311, 1287, 1415, 1221, 1847, 19487}},
-{3172, 15, 11880, {1, 3, 1, 11, 21, 61, 107, 225, 335, 501, 1995, 2399, 5475, 12613, 18877}},
-{3173, 15, 11883, {1, 3, 3, 1, 31, 41, 27, 205, 103, 837, 639, 2007, 2759, 12471, 1457}},
-{3174, 15, 11885, {1, 1, 7, 13, 29, 39, 71, 245, 105, 235, 1277, 1515, 6129, 15947, 26653}},
-{3175, 15, 11898, {1, 1, 7, 5, 7, 13, 87, 251, 315, 1017, 587, 2917, 5911, 2919, 29715}},
-{3176, 15, 11916, {1, 1, 1, 3, 7, 19, 81, 243, 177, 917, 2023, 2365, 7465, 4901, 29841}},
-{3177, 15, 11924, {1, 3, 5, 15, 1, 31, 15, 147, 285, 1003, 1757, 47, 6925, 1197, 19633}},
-{3178, 15, 11928, {1, 1, 5, 7, 27, 25, 47, 209, 85, 403, 1399, 2331, 3663, 595, 13407}},
-{3179, 15, 11947, {1, 3, 5, 9, 7, 25, 7, 139, 389, 817, 1153, 1421, 5735, 9577, 10269}},
-{3180, 15, 11955, {1, 1, 1, 9, 5, 61, 49, 117, 389, 541, 433, 1405, 2575, 223, 7265}},
-{3181, 15, 11961, {1, 1, 5, 7, 15, 1, 81, 207, 435, 843, 835, 3797, 7637, 5333, 31115}},
-{3182, 15, 11962, {1, 3, 7, 11, 13, 3, 47, 249, 301, 715, 2015, 3049, 8155, 10989, 26051}},
-{3183, 15, 11982, {1, 1, 7, 7, 3, 33, 119, 113, 381, 575, 367, 41, 3317, 11727, 4351}},
-{3184, 15, 11990, {1, 3, 3, 13, 9, 3, 51, 37, 173, 137, 533, 1827, 631, 10047, 6267}},
-{3185, 15, 12010, {1, 3, 3, 11, 17, 39, 61, 245, 13, 139, 1281, 1319, 1233, 13629, 32269}},
-{3186, 15, 12018, {1, 1, 1, 7, 15, 17, 91, 109, 163, 609, 11, 3251, 7653, 14035, 31755}},
-{3187, 15, 12027, {1, 3, 3, 15, 13, 21, 55, 231, 385, 133, 1833, 2637, 6935, 14303, 26745}},
-{3188, 15, 12029, {1, 1, 1, 7, 17, 41, 125, 141, 89, 823, 1411, 3637, 6211, 13323, 6111}},
-{3189, 15, 12035, {1, 1, 1, 11, 1, 21, 9, 43, 97, 685, 1223, 1491, 121, 1793, 2397}},
-{3190, 15, 12055, {1, 3, 5, 5, 17, 17, 5, 223, 129, 865, 1839, 1137, 6391, 4377, 9233}},
-{3191, 15, 12062, {1, 3, 7, 15, 21, 55, 5, 77, 341, 637, 1853, 1435, 1195, 9283, 21257}},
-{3192, 15, 12068, {1, 3, 5, 1, 9, 49, 43, 211, 127, 655, 1397, 1235, 5279, 2351, 24229}},
-{3193, 15, 12071, {1, 3, 5, 3, 25, 29, 13, 229, 25, 675, 837, 2753, 2125, 9863, 11293}},
-{3194, 15, 12072, {1, 3, 5, 7, 23, 43, 127, 1, 163, 237, 337, 3019, 7747, 16227, 2881}},
-{3195, 15, 12086, {1, 3, 5, 5, 25, 9, 43, 171, 421, 521, 1885, 337, 7873, 6347, 13181}},
-{3196, 15, 12097, {1, 3, 5, 5, 7, 47, 107, 173, 163, 191, 625, 3389, 2833, 7945, 24787}},
-{3197, 15, 12098, {1, 1, 7, 3, 27, 57, 27, 209, 253, 815, 301, 1633, 3945, 5051, 28851}},
-{3198, 15, 12100, {1, 3, 7, 9, 9, 51, 103, 213, 437, 189, 1857, 1331, 5551, 10641, 27405}},
-{3199, 15, 12112, {1, 1, 5, 5, 15, 1, 25, 105, 117, 347, 161, 3369, 3589, 12903, 23559}},
-{3200, 15, 12118, {1, 1, 1, 5, 3, 61, 93, 51, 81, 281, 1383, 745, 4137, 2005, 3635}},
-{3201, 15, 12133, {1, 3, 7, 5, 13, 57, 111, 211, 303, 477, 359, 4019, 6779, 5129, 22035}},
-{3202, 15, 12134, {1, 1, 1, 7, 17, 29, 113, 113, 201, 531, 749, 739, 2879, 3315, 18733}},
-{3203, 15, 12137, {1, 3, 7, 13, 21, 55, 21, 183, 359, 75, 377, 2211, 4281, 14317, 28307}},
-{3204, 15, 12161, {1, 3, 7, 1, 21, 1, 49, 213, 317, 75, 113, 1741, 7963, 12785, 11571}},
-{3205, 15, 12162, {1, 3, 7, 9, 11, 31, 29, 101, 261, 141, 715, 2727, 8187, 2075, 32433}},
-{3206, 15, 12171, {1, 3, 7, 3, 23, 9, 17, 143, 385, 211, 593, 241, 6567, 10777, 6677}},
-{3207, 15, 12174, {1, 1, 3, 15, 3, 17, 117, 99, 91, 793, 989, 2421, 5643, 16103, 9759}},
-{3208, 15, 12185, {1, 3, 7, 11, 23, 43, 107, 35, 421, 431, 743, 853, 7939, 12169, 4199}},
-{3209, 15, 12204, {1, 1, 1, 11, 21, 53, 17, 203, 123, 395, 59, 929, 255, 7585, 10945}},
-{3210, 15, 12212, {1, 3, 3, 15, 17, 57, 57, 133, 67, 71, 1685, 903, 4079, 15423, 26495}},
-{3211, 15, 12215, {1, 1, 1, 15, 3, 47, 95, 39, 405, 407, 1557, 3001, 6225, 15187, 5663}},
-{3212, 15, 12216, {1, 3, 5, 5, 13, 47, 33, 61, 375, 1023, 1981, 2773, 2375, 11321, 17731}},
-{3213, 15, 12253, {1, 3, 5, 9, 17, 59, 117, 95, 493, 149, 1269, 2865, 369, 2109, 24601}},
-{3214, 15, 12260, {1, 3, 5, 13, 17, 63, 67, 247, 95, 721, 67, 305, 6179, 15399, 32559}},
-{3215, 15, 12277, {1, 1, 5, 1, 3, 21, 41, 15, 453, 475, 2017, 3193, 5903, 897, 4237}},
-{3216, 15, 12289, {1, 1, 5, 3, 15, 41, 1, 141, 441, 575, 155, 3791, 7711, 11231, 24611}},
-{3217, 15, 12295, {1, 3, 7, 1, 17, 53, 27, 169, 31, 437, 963, 1793, 7777, 1917, 29311}},
-{3218, 15, 12314, {1, 3, 3, 13, 9, 27, 77, 87, 329, 885, 749, 1713, 6013, 6921, 629}},
-{3219, 15, 12323, {1, 3, 5, 13, 3, 7, 53, 27, 353, 267, 925, 2141, 439, 15175, 30851}},
-{3220, 15, 12325, {1, 3, 3, 13, 17, 57, 35, 101, 265, 901, 1825, 2159, 6149, 5967, 24023}},
-{3221, 15, 12335, {1, 1, 5, 11, 13, 51, 99, 111, 193, 415, 1541, 2929, 5045, 3147, 12587}},
-{3222, 15, 12349, {1, 3, 7, 11, 15, 9, 33, 17, 511, 815, 299, 1077, 6171, 10451, 15039}},
-{3223, 15, 12358, {1, 1, 1, 15, 25, 63, 51, 137, 449, 951, 1051, 1101, 4725, 2463, 7355}},
-{3224, 15, 12372, {1, 1, 1, 7, 27, 63, 29, 179, 317, 521, 1459, 827, 6599, 13459, 15439}},
-{3225, 15, 12376, {1, 3, 3, 15, 17, 31, 37, 191, 229, 245, 181, 941, 5761, 1849, 31599}},
-{3226, 15, 12379, {1, 1, 1, 9, 27, 45, 67, 239, 481, 615, 1667, 3751, 8141, 10013, 2125}},
-{3227, 15, 12386, {1, 1, 1, 1, 13, 51, 117, 135, 73, 151, 1291, 2541, 1411, 3767, 26949}},
-{3228, 15, 12395, {1, 3, 1, 9, 7, 11, 21, 187, 243, 857, 1951, 865, 7273, 2041, 8155}},
-{3229, 15, 12416, {1, 1, 3, 3, 19, 33, 89, 115, 455, 137, 707, 1867, 4221, 2433, 9119}},
-{3230, 15, 12421, {1, 1, 3, 11, 5, 3, 121, 1, 71, 951, 603, 3873, 723, 3285, 19289}},
-{3231, 15, 12440, {1, 3, 7, 15, 21, 1, 117, 17, 455, 519, 731, 3003, 5741, 9557, 29163}},
-{3232, 15, 12452, {1, 1, 3, 13, 25, 5, 43, 147, 209, 895, 255, 1231, 241, 487, 15593}},
-{3233, 15, 12455, {1, 1, 3, 13, 7, 1, 89, 187, 217, 927, 2029, 3521, 2777, 8103, 22819}},
-{3234, 15, 12456, {1, 1, 7, 11, 7, 33, 3, 73, 5, 489, 227, 2259, 7031, 6425, 26135}},
-{3235, 15, 12462, {1, 3, 3, 7, 31, 19, 97, 201, 455, 819, 945, 2771, 8083, 8711, 2835}},
-{3236, 15, 12467, {1, 1, 1, 5, 15, 45, 43, 157, 245, 967, 877, 2289, 4499, 9891, 18827}},
-{3237, 15, 12479, {1, 3, 1, 7, 21, 59, 123, 63, 231, 485, 1781, 1211, 4597, 5269, 1607}},
-{3238, 15, 12505, {1, 1, 1, 13, 23, 39, 105, 55, 249, 991, 1625, 3089, 3825, 4275, 29139}},
-{3239, 15, 12521, {1, 3, 3, 1, 29, 29, 55, 169, 13, 895, 1355, 1101, 6063, 12935, 23215}},
-{3240, 15, 12535, {1, 1, 5, 5, 31, 49, 99, 137, 209, 1017, 1179, 3931, 637, 14131, 19285}},
-{3241, 15, 12547, {1, 1, 1, 1, 3, 11, 119, 11, 215, 337, 243, 3883, 3807, 7335, 11901}},
-{3242, 15, 12556, {1, 3, 7, 3, 7, 27, 71, 225, 219, 367, 1213, 2739, 1185, 10175, 21313}},
-{3243, 15, 12561, {1, 3, 7, 13, 7, 49, 23, 223, 61, 1011, 797, 1335, 6711, 5961, 5605}},
-{3244, 15, 12568, {1, 3, 3, 11, 19, 37, 1, 149, 39, 661, 929, 2125, 2299, 5181, 28083}},
-{3245, 15, 12578, {1, 3, 3, 13, 13, 9, 67, 21, 463, 279, 529, 523, 6705, 11011, 31695}},
-{3246, 15, 12583, {1, 3, 1, 5, 13, 1, 123, 3, 291, 625, 1949, 2713, 5917, 10343, 13627}},
-{3247, 15, 12595, {1, 1, 3, 9, 27, 41, 3, 207, 103, 265, 811, 549, 6109, 313, 8889}},
-{3248, 15, 12604, {1, 3, 3, 13, 23, 43, 99, 33, 279, 463, 955, 793, 4113, 10615, 16957}},
-{3249, 15, 12610, {1, 1, 5, 7, 11, 49, 79, 45, 17, 937, 359, 1037, 1099, 3003, 31561}},
-{3250, 15, 12621, {1, 1, 1, 7, 3, 45, 111, 35, 109, 983, 53, 4057, 7349, 3599, 2209}},
-{3251, 15, 12622, {1, 3, 7, 11, 9, 43, 27, 9, 85, 529, 1497, 347, 759, 12449, 11373}},
-{3252, 15, 12624, {1, 1, 3, 9, 17, 1, 49, 31, 367, 813, 1385, 2025, 773, 4679, 4543}},
-{3253, 15, 12629, {1, 1, 5, 15, 15, 9, 43, 97, 239, 995, 1037, 841, 4167, 12113, 23765}},
-{3254, 15, 12630, {1, 3, 5, 9, 29, 53, 123, 49, 221, 113, 1157, 73, 6087, 1363, 11029}},
-{3255, 15, 12639, {1, 3, 1, 13, 3, 15, 69, 199, 279, 919, 5, 161, 4817, 15031, 121}},
-{3256, 15, 12640, {1, 3, 1, 9, 3, 31, 117, 77, 393, 241, 645, 3181, 1067, 15879, 2037}},
-{3257, 15, 12650, {1, 3, 3, 15, 3, 63, 57, 33, 117, 789, 941, 1301, 5865, 12693, 3523}},
-{3258, 15, 12679, {1, 1, 5, 13, 3, 61, 51, 151, 175, 305, 95, 1557, 6567, 7841, 13903}},
-{3259, 15, 12680, {1, 3, 3, 5, 15, 25, 127, 79, 245, 767, 645, 3933, 1357, 12579, 4067}},
-{3260, 15, 12698, {1, 3, 5, 11, 21, 31, 13, 251, 127, 231, 1795, 2627, 1191, 3363, 23543}},
-{3261, 15, 12716, {1, 1, 3, 5, 7, 49, 121, 57, 131, 481, 1879, 525, 5225, 337, 1957}},
-{3262, 15, 12721, {1, 1, 5, 13, 9, 55, 27, 37, 211, 125, 119, 3373, 251, 12357, 13975}},
-{3263, 15, 12722, {1, 3, 3, 15, 1, 51, 91, 119, 233, 993, 203, 1635, 1167, 6327, 29119}},
-{3264, 15, 12731, {1, 1, 7, 1, 13, 5, 23, 253, 121, 989, 1105, 3321, 3221, 6073, 21185}},
-{3265, 15, 12742, {1, 1, 3, 15, 13, 49, 121, 247, 247, 133, 485, 1067, 7875, 411, 7647}},
-{3266, 15, 12745, {1, 3, 7, 13, 31, 37, 127, 241, 145, 133, 53, 267, 2029, 3703, 16123}},
-{3267, 15, 12751, {1, 3, 1, 15, 15, 9, 15, 89, 35, 367, 401, 61, 1953, 7873, 17861}},
-{3268, 15, 12759, {1, 1, 1, 1, 1, 41, 71, 249, 213, 779, 1385, 1767, 999, 15151, 16647}},
-{3269, 15, 12763, {1, 3, 7, 13, 31, 23, 123, 235, 343, 949, 309, 3777, 3587, 853, 19779}},
-{3270, 15, 12769, {1, 1, 3, 13, 29, 35, 5, 37, 63, 757, 303, 1579, 3443, 243, 11873}},
-{3271, 15, 12781, {1, 3, 1, 9, 19, 49, 81, 53, 11, 901, 1857, 147, 3103, 14019, 21}},
-{3272, 15, 12793, {1, 3, 7, 13, 3, 39, 99, 99, 45, 91, 1567, 551, 3129, 4809, 29057}},
-{3273, 15, 12799, {1, 3, 7, 3, 3, 27, 17, 231, 377, 381, 1479, 2525, 2595, 2799, 25737}},
-{3274, 15, 12815, {1, 3, 5, 15, 15, 25, 103, 215, 301, 59, 1417, 981, 7579, 12731, 22329}},
-{3275, 15, 12824, {1, 1, 1, 13, 5, 31, 61, 31, 349, 925, 1301, 685, 435, 11567, 10715}},
-{3276, 15, 12836, {1, 1, 7, 9, 19, 57, 109, 1, 37, 377, 1015, 2273, 6741, 3191, 15949}},
-{3277, 15, 12845, {1, 3, 3, 13, 3, 23, 103, 127, 11, 59, 1847, 1175, 425, 3423, 20643}},
-{3278, 15, 12853, {1, 3, 3, 7, 3, 11, 105, 141, 55, 217, 1427, 477, 667, 9403, 11905}},
-{3279, 15, 12854, {1, 3, 3, 5, 3, 27, 11, 187, 495, 907, 1925, 445, 6639, 8159, 15225}},
-{3280, 15, 12857, {1, 3, 1, 5, 27, 31, 77, 213, 73, 343, 1123, 3609, 2431, 15329, 32165}},
-{3281, 15, 12866, {1, 1, 7, 5, 1, 11, 105, 139, 485, 1007, 709, 3509, 5231, 11717, 31433}},
-{3282, 15, 12872, {1, 1, 3, 15, 23, 49, 95, 169, 399, 1019, 19, 2013, 5311, 7951, 22609}},
-{3283, 15, 12875, {1, 3, 1, 7, 13, 3, 29, 203, 209, 701, 1791, 2615, 5351, 4237, 12565}},
-{3284, 15, 12878, {1, 3, 1, 15, 27, 11, 91, 31, 205, 205, 1683, 901, 5129, 6049, 11865}},
-{3285, 15, 12880, {1, 1, 7, 7, 27, 59, 21, 3, 209, 79, 769, 4013, 2041, 2645, 11561}},
-{3286, 15, 12885, {1, 3, 7, 11, 5, 45, 39, 243, 185, 871, 795, 1845, 8043, 6285, 20991}},
-{3287, 15, 12901, {1, 1, 5, 7, 13, 7, 15, 165, 349, 179, 789, 1269, 3787, 5429, 26567}},
-{3288, 15, 12902, {1, 3, 3, 13, 31, 23, 75, 41, 177, 735, 1889, 4039, 3519, 15003, 965}},
-{3289, 15, 12920, {1, 3, 1, 7, 15, 57, 15, 139, 27, 469, 1003, 691, 7893, 9643, 30983}},
-{3290, 15, 12926, {1, 3, 1, 13, 23, 27, 3, 237, 233, 875, 99, 883, 6167, 5463, 6245}},
-{3291, 15, 12929, {1, 1, 5, 13, 25, 57, 79, 51, 147, 619, 1147, 279, 6583, 1939, 477}},
-{3292, 15, 12939, {1, 3, 5, 5, 31, 61, 125, 163, 213, 699, 583, 3865, 615, 9707, 11651}},
-{3293, 15, 12941, {1, 1, 5, 1, 5, 21, 93, 239, 31, 641, 777, 27, 5247, 8993, 21053}},
-{3294, 15, 12950, {1, 3, 7, 9, 1, 13, 61, 57, 503, 453, 83, 3271, 2845, 1121, 18639}},
-{3295, 15, 12953, {1, 1, 7, 5, 29, 53, 13, 219, 379, 441, 821, 3179, 4877, 2535, 7557}},
-{3296, 15, 12992, {1, 1, 7, 13, 9, 53, 17, 183, 265, 393, 587, 2753, 6453, 7135, 24737}},
-{3297, 15, 13002, {1, 1, 1, 13, 11, 23, 73, 109, 393, 1013, 559, 755, 7291, 6631, 26509}},
-{3298, 15, 13010, {1, 3, 1, 5, 5, 15, 107, 103, 355, 307, 1559, 837, 5413, 5285, 17489}},
-{3299, 15, 13058, {1, 1, 5, 7, 17, 21, 21, 23, 109, 709, 1947, 3585, 3629, 4669, 949}},
-{3300, 15, 13072, {1, 3, 7, 1, 9, 33, 85, 147, 467, 259, 1913, 199, 7399, 9551, 22387}},
-{3301, 15, 13084, {1, 3, 5, 11, 15, 53, 23, 41, 249, 515, 1161, 2467, 1299, 7449, 2613}},
-{3302, 15, 13087, {1, 1, 5, 5, 5, 29, 91, 139, 487, 545, 321, 3035, 4545, 6747, 21673}},
-{3303, 15, 13091, {1, 1, 3, 13, 23, 49, 95, 103, 25, 119, 469, 2515, 2551, 841, 25089}},
-{3304, 15, 13097, {1, 1, 5, 7, 11, 31, 31, 197, 245, 715, 257, 4043, 8099, 11531, 5617}},
-{3305, 15, 13108, {1, 1, 3, 3, 19, 7, 9, 179, 103, 995, 191, 179, 3843, 5215, 27639}},
-{3306, 15, 13123, {1, 3, 1, 7, 23, 59, 25, 65, 399, 211, 1453, 3511, 7203, 16015, 32197}},
-{3307, 15, 13149, {1, 3, 3, 5, 9, 35, 109, 67, 197, 449, 643, 519, 5751, 15551, 11331}},
-{3308, 15, 13150, {1, 3, 5, 3, 1, 17, 53, 201, 265, 351, 467, 911, 1117, 7183, 20371}},
-{3309, 15, 13163, {1, 1, 7, 7, 27, 17, 93, 81, 227, 619, 1191, 735, 815, 12615, 2719}},
-{3310, 15, 13166, {1, 3, 1, 15, 19, 3, 83, 75, 343, 297, 1019, 3469, 4383, 13299, 29755}},
-{3311, 15, 13178, {1, 1, 5, 3, 13, 55, 119, 169, 85, 595, 299, 2469, 5625, 2877, 16117}},
-{3312, 15, 13180, {1, 1, 3, 5, 15, 17, 61, 161, 47, 393, 143, 867, 5517, 9495, 12795}},
-{3313, 15, 13184, {1, 3, 5, 1, 27, 31, 113, 125, 251, 687, 969, 1473, 2245, 6355, 13655}},
-{3314, 15, 13204, {1, 1, 1, 5, 5, 37, 29, 133, 443, 899, 277, 2353, 7223, 4459, 19159}},
-{3315, 15, 13238, {1, 1, 3, 9, 19, 27, 53, 145, 195, 167, 2045, 447, 1803, 1895, 8431}},
-{3316, 15, 13242, {1, 1, 3, 9, 5, 27, 91, 147, 233, 451, 475, 27, 4629, 16181, 16437}},
-{3317, 15, 13249, {1, 3, 5, 3, 29, 17, 53, 167, 433, 689, 1131, 2985, 1553, 11697, 6993}},
-{3318, 15, 13255, {1, 3, 3, 13, 21, 43, 69, 229, 399, 525, 179, 237, 7017, 5703, 17653}},
-{3319, 15, 13269, {1, 1, 3, 15, 13, 39, 75, 163, 229, 875, 197, 477, 3667, 15501, 15801}},
-{3320, 15, 13270, {1, 1, 7, 15, 15, 51, 81, 187, 487, 673, 865, 1915, 1009, 5935, 8097}},
-{3321, 15, 13274, {1, 3, 5, 5, 7, 3, 63, 77, 495, 815, 391, 2321, 1007, 15661, 30715}},
-{3322, 15, 13285, {1, 1, 7, 3, 17, 25, 83, 173, 173, 911, 1373, 2957, 4549, 15977, 17695}},
-{3323, 15, 13289, {1, 1, 7, 13, 13, 23, 77, 147, 497, 1003, 1687, 1795, 1393, 1881, 8479}},
-{3324, 15, 13298, {1, 3, 7, 11, 27, 43, 97, 25, 61, 457, 203, 2573, 5943, 15021, 4003}},
-{3325, 15, 13307, {1, 3, 3, 13, 9, 37, 37, 25, 219, 889, 1535, 2791, 4531, 13679, 12663}},
-{3326, 15, 13312, {1, 1, 3, 1, 17, 7, 51, 123, 89, 887, 1467, 1645, 3767, 6383, 30837}},
-{3327, 15, 13335, {1, 3, 3, 1, 21, 47, 5, 151, 83, 257, 569, 2711, 637, 12569, 16893}},
-{3328, 15, 13345, {1, 3, 7, 1, 31, 37, 73, 3, 115, 919, 1817, 2483, 4811, 15245, 4375}},
-{3329, 15, 13357, {1, 1, 1, 5, 1, 39, 39, 231, 9, 733, 455, 3383, 4777, 7235, 12631}},
-{3330, 15, 13366, {1, 1, 7, 9, 13, 25, 55, 25, 73, 59, 1699, 929, 755, 1279, 5583}},
-{3331, 15, 13372, {1, 3, 5, 3, 9, 49, 79, 55, 479, 179, 1159, 4079, 3503, 11603, 12361}},
-{3332, 15, 13380, {1, 1, 5, 9, 21, 45, 31, 163, 377, 817, 219, 147, 2581, 12769, 30783}},
-{3333, 15, 13384, {1, 3, 1, 7, 15, 27, 39, 189, 493, 259, 1663, 1213, 961, 11089, 16079}},
-{3334, 15, 13395, {1, 1, 5, 9, 5, 41, 13, 153, 313, 337, 1027, 1267, 4249, 13071, 27043}},
-{3335, 15, 13407, {1, 3, 7, 3, 13, 11, 23, 255, 51, 527, 317, 3217, 5037, 12723, 17411}},
-{3336, 15, 13408, {1, 1, 5, 1, 25, 57, 83, 97, 233, 513, 1283, 2675, 4111, 4111, 32141}},
-{3337, 15, 13413, {1, 3, 3, 15, 25, 33, 103, 81, 155, 189, 139, 1179, 2691, 15119, 13959}},
-{3338, 15, 13414, {1, 3, 3, 1, 25, 55, 67, 19, 19, 9, 437, 579, 4273, 10733, 7125}},
-{3339, 15, 13417, {1, 1, 1, 7, 23, 41, 47, 5, 435, 749, 595, 199, 3941, 7199, 4795}},
-{3340, 15, 13437, {1, 3, 1, 15, 5, 49, 35, 9, 199, 703, 1769, 3269, 5689, 13063, 22771}},
-{3341, 15, 13441, {1, 1, 5, 5, 21, 55, 125, 55, 63, 149, 1167, 3577, 1051, 3921, 20545}},
-{3342, 15, 13447, {1, 3, 7, 13, 29, 53, 107, 193, 163, 339, 1335, 1573, 5809, 5681, 29487}},
-{3343, 15, 13456, {1, 1, 1, 9, 17, 9, 91, 177, 211, 453, 1807, 1881, 6051, 225, 6021}},
-{3344, 15, 13459, {1, 1, 1, 13, 15, 1, 29, 43, 181, 105, 1945, 2313, 6429, 2901, 6221}},
-{3345, 15, 13461, {1, 3, 5, 11, 29, 55, 115, 115, 187, 1013, 697, 1885, 121, 12387, 32443}},
-{3346, 15, 13466, {1, 1, 1, 7, 19, 51, 21, 107, 55, 125, 1655, 2281, 3293, 15749, 27521}},
-{3347, 15, 13484, {1, 1, 7, 9, 19, 9, 81, 93, 139, 401, 193, 73, 5159, 9323, 6019}},
-{3348, 15, 13487, {1, 1, 7, 9, 15, 51, 115, 69, 247, 599, 1163, 2251, 1211, 8827, 15581}},
-{3349, 15, 13489, {1, 1, 7, 9, 5, 39, 75, 185, 321, 911, 849, 843, 6791, 10407, 10513}},
-{3350, 15, 13492, {1, 1, 5, 5, 15, 9, 21, 47, 459, 681, 2001, 1545, 5939, 7073, 29043}},
-{3351, 15, 13496, {1, 3, 1, 11, 13, 25, 53, 97, 487, 797, 567, 3757, 5597, 6313, 18531}},
-{3352, 15, 13510, {1, 1, 3, 3, 29, 55, 11, 219, 325, 591, 2015, 383, 2595, 11855, 22501}},
-{3353, 15, 13531, {1, 1, 1, 5, 15, 57, 33, 125, 323, 749, 1843, 4019, 2075, 6673, 6957}},
-{3354, 15, 13538, {1, 1, 5, 7, 19, 7, 47, 239, 51, 107, 1081, 467, 5493, 7617, 10355}},
-{3355, 15, 13543, {1, 3, 1, 1, 11, 3, 67, 199, 175, 421, 935, 309, 4449, 6363, 9183}},
-{3356, 15, 13547, {1, 1, 1, 7, 9, 33, 3, 219, 481, 513, 417, 1267, 2863, 765, 18431}},
-{3357, 15, 13572, {1, 3, 1, 1, 19, 1, 89, 109, 415, 105, 487, 3241, 7465, 9233, 16307}},
-{3358, 15, 13581, {1, 1, 3, 13, 9, 43, 25, 231, 383, 789, 1855, 691, 3465, 2387, 11715}},
-{3359, 15, 13590, {1, 3, 3, 3, 13, 39, 63, 107, 33, 265, 437, 117, 3179, 5543, 28179}},
-{3360, 15, 13605, {1, 3, 3, 13, 21, 5, 31, 111, 321, 425, 253, 3501, 3209, 15429, 18383}},
-{3361, 15, 13612, {1, 3, 5, 9, 1, 27, 117, 187, 433, 459, 1999, 1069, 4857, 8591, 26343}},
-{3362, 15, 13624, {1, 1, 7, 3, 15, 43, 11, 193, 391, 341, 1203, 1259, 7265, 1783, 13161}},
-{3363, 15, 13630, {1, 1, 7, 1, 5, 15, 45, 143, 193, 985, 1105, 3483, 2421, 9687, 22347}},
-{3364, 15, 13632, {1, 3, 7, 13, 21, 17, 79, 231, 487, 663, 1101, 1025, 5779, 14681, 29181}},
-{3365, 15, 13638, {1, 1, 3, 9, 15, 19, 55, 219, 27, 963, 1513, 1017, 3907, 12279, 32655}},
-{3366, 15, 13661, {1, 3, 7, 3, 31, 27, 17, 1, 51, 861, 529, 1225, 6395, 15787, 5231}},
-{3367, 15, 13665, {1, 3, 3, 11, 27, 7, 101, 143, 21, 191, 1437, 2393, 4097, 14319, 6977}},
-{3368, 15, 13668, {1, 3, 3, 3, 25, 35, 105, 141, 433, 269, 1469, 2939, 5387, 7373, 7863}},
-{3369, 15, 13686, {1, 3, 7, 5, 5, 21, 23, 11, 217, 357, 1847, 101, 1161, 5297, 14879}},
-{3370, 15, 13699, {1, 3, 1, 3, 25, 23, 81, 217, 505, 161, 1667, 1343, 1751, 2463, 26431}},
-{3371, 15, 13701, {1, 1, 3, 1, 17, 51, 125, 205, 385, 351, 731, 2911, 2749, 2689, 27031}},
-{3372, 15, 13708, {1, 1, 5, 5, 5, 17, 31, 171, 477, 671, 167, 1797, 8047, 10123, 4325}},
-{3373, 15, 13716, {1, 1, 7, 1, 11, 23, 123, 161, 99, 1007, 765, 1965, 5395, 16193, 17751}},
-{3374, 15, 13725, {1, 3, 1, 9, 13, 11, 111, 217, 31, 753, 377, 2267, 7893, 7195, 24999}},
-{3375, 15, 13730, {1, 3, 1, 9, 21, 53, 127, 121, 151, 395, 1447, 1411, 5179, 12043, 27607}},
-{3376, 15, 13742, {1, 1, 5, 3, 11, 37, 97, 139, 113, 835, 229, 3741, 827, 5527, 5779}},
-{3377, 15, 13747, {1, 1, 7, 7, 27, 55, 11, 55, 429, 269, 1179, 233, 1053, 10225, 16703}},
-{3378, 15, 13749, {1, 1, 1, 3, 15, 9, 67, 119, 95, 753, 511, 2507, 3953, 6403, 27635}},
-{3379, 15, 13753, {1, 3, 3, 7, 27, 57, 25, 27, 249, 515, 193, 4043, 2017, 751, 10949}},
-{3380, 15, 13754, {1, 3, 1, 9, 31, 57, 67, 21, 177, 573, 1835, 2015, 6201, 2383, 31087}},
-{3381, 15, 13771, {1, 1, 5, 1, 19, 3, 89, 243, 69, 387, 1905, 3465, 2775, 7713, 30081}},
-{3382, 15, 13773, {1, 1, 3, 3, 9, 59, 15, 89, 85, 605, 881, 263, 2551, 797, 16541}},
-{3383, 15, 13782, {1, 3, 7, 11, 25, 41, 59, 139, 405, 571, 1147, 2963, 4175, 12901, 6309}},
-{3384, 15, 13785, {1, 3, 1, 5, 29, 29, 11, 243, 183, 281, 807, 1, 7079, 10079, 13865}},
-{3385, 15, 13798, {1, 3, 7, 5, 5, 1, 89, 55, 423, 157, 675, 1849, 241, 6467, 15459}},
-{3386, 15, 13802, {1, 1, 7, 11, 15, 63, 89, 109, 501, 549, 317, 3043, 1151, 3895, 19851}},
-{3387, 15, 13809, {1, 3, 1, 15, 7, 23, 97, 97, 225, 737, 1117, 3325, 209, 14169, 10813}},
-{3388, 15, 13828, {1, 3, 7, 13, 13, 39, 91, 153, 395, 879, 1041, 3753, 5577, 1985, 25247}},
-{3389, 15, 13832, {1, 1, 1, 3, 17, 15, 113, 143, 101, 901, 1119, 1819, 3577, 3441, 31511}},
-{3390, 15, 13840, {1, 3, 1, 11, 15, 27, 21, 37, 287, 121, 451, 1353, 2173, 299, 18791}},
-{3391, 15, 13850, {1, 3, 3, 5, 23, 1, 49, 145, 315, 769, 99, 1385, 5961, 9121, 1465}},
-{3392, 15, 13861, {1, 3, 3, 13, 21, 39, 39, 233, 271, 113, 615, 2257, 3765, 5921, 313}},
-{3393, 15, 13874, {1, 3, 7, 7, 25, 45, 11, 237, 83, 203, 929, 1819, 2679, 11583, 30091}},
-{3394, 15, 13876, {1, 1, 1, 7, 21, 63, 85, 251, 133, 991, 1515, 2547, 6051, 7279, 3569}},
-{3395, 15, 13886, {1, 3, 7, 15, 11, 19, 87, 17, 313, 283, 1021, 2743, 4855, 13741, 17955}},
-{3396, 15, 13897, {1, 1, 7, 13, 29, 13, 61, 93, 81, 91, 995, 907, 4847, 2599, 20041}},
-{3397, 15, 13900, {1, 1, 3, 11, 13, 45, 103, 33, 243, 109, 2029, 121, 231, 16179, 13741}},
-{3398, 15, 13915, {1, 3, 5, 9, 9, 5, 73, 225, 199, 723, 611, 1909, 2345, 10257, 9909}},
-{3399, 15, 13927, {1, 1, 3, 11, 7, 5, 33, 89, 431, 899, 803, 3173, 6131, 16097, 20561}},
-{3400, 15, 13951, {1, 3, 3, 7, 7, 47, 23, 47, 411, 69, 239, 661, 5591, 10457, 24245}},
-{3401, 15, 13955, {1, 1, 5, 15, 25, 35, 87, 23, 115, 939, 1579, 119, 4001, 13791, 9729}},
-{3402, 15, 13962, {1, 3, 5, 11, 25, 45, 29, 195, 369, 237, 735, 155, 123, 4415, 32255}},
-{3403, 15, 13969, {1, 3, 3, 9, 13, 53, 15, 77, 313, 75, 529, 925, 5679, 14585, 19889}},
-{3404, 15, 13979, {1, 1, 7, 15, 15, 27, 105, 13, 31, 669, 563, 1809, 4321, 7797, 4177}},
-{3405, 15, 13988, {1, 1, 5, 9, 3, 29, 111, 177, 33, 235, 1951, 1561, 141, 4803, 16327}},
-{3406, 15, 13998, {1, 1, 1, 7, 9, 41, 1, 149, 95, 933, 115, 1619, 771, 8189, 8781}},
-{3407, 15, 14000, {1, 1, 5, 3, 13, 41, 33, 159, 355, 159, 1243, 1439, 6571, 14397, 31321}},
-{3408, 15, 14005, {1, 1, 7, 11, 9, 15, 91, 145, 457, 255, 1449, 611, 1449, 2521, 28949}},
-{3409, 15, 14027, {1, 3, 7, 5, 27, 57, 35, 99, 447, 287, 743, 1163, 4379, 7361, 3831}},
-{3410, 15, 14037, {1, 3, 3, 7, 15, 53, 41, 83, 133, 571, 1739, 531, 2921, 11527, 21941}},
-{3411, 15, 14051, {1, 1, 1, 13, 9, 27, 39, 113, 429, 447, 595, 3171, 5245, 4095, 14847}},
-{3412, 15, 14054, {1, 1, 3, 7, 19, 19, 21, 101, 489, 1011, 265, 3899, 3225, 11701, 5193}},
-{3413, 15, 14060, {1, 3, 7, 3, 15, 25, 103, 213, 441, 215, 1483, 263, 3561, 7915, 7969}},
-{3414, 15, 14063, {1, 3, 3, 3, 11, 47, 97, 29, 489, 867, 1347, 2155, 4871, 8001, 18305}},
-{3415, 15, 14071, {1, 3, 1, 9, 25, 15, 61, 17, 343, 775, 1765, 3803, 4577, 8437, 12605}},
-{3416, 15, 14078, {1, 1, 5, 3, 11, 39, 69, 23, 23, 65, 1967, 2429, 1703, 6671, 14981}},
-{3417, 15, 14080, {1, 1, 5, 15, 23, 59, 125, 51, 225, 439, 2019, 2589, 7781, 13111, 2911}},
-{3418, 15, 14085, {1, 1, 1, 3, 1, 31, 37, 245, 203, 305, 821, 367, 5211, 9791, 21777}},
-{3419, 15, 14086, {1, 1, 5, 9, 9, 31, 97, 25, 271, 83, 343, 2461, 1805, 14383, 10059}},
-{3420, 15, 14095, {1, 1, 5, 13, 15, 33, 127, 109, 137, 963, 961, 1647, 7881, 8133, 22359}},
-{3421, 15, 14138, {1, 1, 3, 7, 25, 31, 123, 241, 283, 1, 1781, 23, 971, 6485, 127}},
-{3422, 15, 14145, {1, 1, 5, 15, 15, 27, 25, 145, 395, 679, 979, 571, 1585, 14787, 7465}},
-{3423, 15, 14158, {1, 1, 5, 7, 13, 11, 7, 131, 511, 597, 379, 1513, 6267, 16039, 1503}},
-{3424, 15, 14166, {1, 1, 1, 13, 15, 49, 73, 217, 353, 577, 1913, 1127, 961, 11557, 24993}},
-{3425, 15, 14179, {1, 3, 3, 9, 7, 3, 105, 141, 377, 687, 1917, 485, 983, 11149, 23303}},
-{3426, 15, 14181, {1, 1, 3, 15, 11, 7, 117, 179, 505, 67, 1817, 913, 5757, 1981, 1637}},
-{3427, 15, 14188, {1, 1, 1, 7, 5, 29, 3, 43, 223, 295, 1895, 3425, 5355, 5155, 17197}},
-{3428, 15, 14193, {1, 1, 7, 9, 21, 59, 121, 245, 73, 233, 1527, 869, 4145, 7995, 6473}},
-{3429, 15, 14200, {1, 1, 5, 13, 17, 21, 89, 179, 495, 669, 453, 2603, 5969, 6161, 4743}},
-{3430, 15, 14203, {1, 1, 7, 11, 25, 21, 103, 131, 391, 249, 1633, 2603, 2207, 8987, 15487}},
-{3431, 15, 14215, {1, 3, 7, 9, 13, 45, 99, 251, 115, 597, 1505, 2421, 1231, 10015, 24295}},
-{3432, 15, 14224, {1, 1, 5, 5, 31, 49, 17, 67, 463, 813, 1491, 3309, 7881, 8109, 7289}},
-{3433, 15, 14230, {1, 3, 1, 15, 23, 35, 123, 21, 169, 499, 95, 603, 1829, 7865, 26313}},
-{3434, 15, 14233, {1, 1, 7, 1, 9, 29, 45, 65, 95, 97, 673, 3673, 2969, 2317, 22209}},
-{3435, 15, 14236, {1, 1, 3, 7, 29, 33, 121, 17, 331, 487, 1901, 1951, 5383, 9375, 4029}},
-{3436, 15, 14246, {1, 3, 7, 9, 25, 43, 91, 147, 141, 401, 1647, 2697, 4645, 7179, 31857}},
-{3437, 15, 14267, {1, 3, 5, 11, 9, 31, 127, 105, 39, 883, 1635, 919, 5069, 2875, 24519}},
-{3438, 15, 14282, {1, 1, 5, 9, 1, 63, 73, 135, 95, 503, 385, 3903, 545, 12635, 27569}},
-{3439, 15, 14287, {1, 1, 3, 11, 27, 31, 47, 173, 55, 339, 1255, 1947, 793, 14133, 13963}},
-{3440, 15, 14301, {1, 1, 3, 15, 17, 33, 113, 249, 401, 743, 1307, 3123, 627, 1253, 13285}},
-{3441, 15, 14323, {1, 1, 3, 1, 9, 7, 39, 65, 281, 107, 833, 193, 2987, 12267, 31335}},
-{3442, 15, 14325, {1, 1, 7, 3, 15, 21, 99, 211, 39, 179, 587, 1169, 6455, 8225, 2049}},
-{3443, 15, 14329, {1, 3, 5, 13, 5, 13, 123, 1, 223, 273, 731, 2967, 4793, 4229, 26031}},
-{3444, 15, 14339, {1, 1, 1, 1, 3, 17, 7, 23, 225, 757, 743, 1257, 2047, 12509, 25467}},
-{3445, 15, 14342, {1, 1, 7, 15, 29, 3, 15, 113, 227, 675, 1295, 2777, 2921, 5485, 2577}},
-{3446, 15, 14351, {1, 3, 7, 13, 19, 21, 85, 129, 45, 599, 317, 1513, 4953, 10383, 25253}},
-{3447, 15, 14356, {1, 1, 7, 11, 13, 47, 127, 67, 219, 131, 905, 2005, 851, 15243, 5777}},
-{3448, 15, 14359, {1, 1, 5, 3, 23, 57, 57, 189, 153, 37, 955, 2049, 1295, 15119, 27213}},
-{3449, 15, 14370, {1, 3, 7, 11, 13, 61, 3, 241, 269, 789, 1595, 2369, 4843, 11347, 21543}},
-{3450, 15, 14402, {1, 1, 5, 5, 25, 21, 19, 237, 3, 605, 1343, 3965, 3511, 7889, 27759}},
-{3451, 15, 14411, {1, 3, 1, 15, 21, 15, 123, 5, 345, 945, 283, 1313, 335, 2085, 19505}},
-{3452, 15, 14421, {1, 1, 3, 3, 5, 21, 123, 89, 67, 11, 1247, 1155, 287, 13455, 5693}},
-{3453, 15, 14431, {1, 3, 3, 13, 1, 53, 101, 27, 387, 379, 19, 751, 2445, 11737, 975}},
-{3454, 15, 14435, {1, 3, 3, 3, 9, 29, 81, 117, 443, 145, 1619, 1813, 8125, 5829, 28617}},
-{3455, 15, 14442, {1, 1, 5, 15, 27, 15, 83, 83, 61, 715, 1655, 1631, 3457, 2727, 2163}},
-{3456, 15, 14447, {1, 3, 1, 5, 11, 11, 121, 7, 135, 883, 927, 1817, 6839, 12361, 24119}},
-{3457, 15, 14456, {1, 3, 7, 11, 23, 59, 39, 165, 109, 355, 1303, 381, 5697, 275, 3771}},
-{3458, 15, 14459, {1, 3, 5, 11, 11, 5, 81, 157, 55, 435, 613, 127, 4087, 3791, 21627}},
-{3459, 15, 14472, {1, 3, 7, 15, 13, 37, 83, 195, 207, 771, 51, 3685, 6389, 1229, 11101}},
-{3460, 15, 14477, {1, 3, 7, 13, 31, 3, 9, 13, 487, 95, 77, 809, 5809, 12887, 29933}},
-{3461, 15, 14490, {1, 1, 3, 7, 25, 9, 13, 29, 353, 659, 1785, 3825, 3729, 13109, 12973}},
-{3462, 15, 14496, {1, 1, 1, 5, 21, 3, 97, 1, 245, 917, 29, 1429, 8141, 7569, 32493}},
-{3463, 15, 14501, {1, 3, 1, 9, 19, 13, 13, 109, 377, 1007, 1737, 1939, 1419, 1145, 5065}},
-{3464, 15, 14505, {1, 1, 7, 9, 27, 57, 53, 69, 423, 43, 1629, 1003, 1473, 10809, 5659}},
-{3465, 15, 14513, {1, 1, 1, 9, 1, 45, 11, 231, 351, 155, 663, 2783, 3491, 5725, 25207}},
-{3466, 15, 14520, {1, 1, 1, 3, 15, 25, 77, 89, 231, 813, 657, 2603, 4885, 1383, 14499}},
-{3467, 15, 14534, {1, 3, 5, 5, 9, 21, 101, 181, 449, 491, 737, 803, 659, 11771, 545}},
-{3468, 15, 14562, {1, 3, 7, 9, 7, 19, 27, 199, 265, 329, 1031, 1235, 3191, 10071, 16281}},
-{3469, 15, 14576, {1, 1, 7, 11, 27, 55, 3, 127, 503, 1003, 1041, 1953, 5835, 4851, 13485}},
-{3470, 15, 14579, {1, 1, 7, 15, 5, 45, 97, 61, 221, 497, 1949, 3163, 4707, 8441, 1437}},
-{3471, 15, 14585, {1, 3, 5, 1, 3, 35, 107, 9, 473, 971, 227, 2225, 3999, 3095, 18879}},
-{3472, 15, 14586, {1, 1, 1, 9, 21, 59, 21, 1, 41, 435, 575, 491, 1839, 1095, 9727}},
-{3473, 15, 14606, {1, 3, 5, 9, 13, 29, 123, 251, 465, 701, 1105, 829, 573, 11503, 11861}},
-{3474, 15, 14627, {1, 3, 3, 13, 27, 59, 29, 111, 225, 973, 561, 1481, 835, 9261, 13831}},
-{3475, 15, 14630, {1, 1, 1, 7, 17, 3, 97, 211, 333, 315, 571, 3523, 7305, 6461, 20139}},
-{3476, 15, 14634, {1, 3, 7, 11, 31, 21, 105, 247, 113, 863, 1767, 381, 4623, 8935, 7911}},
-{3477, 15, 14636, {1, 1, 5, 7, 29, 45, 17, 155, 69, 17, 655, 1983, 6385, 6177, 7961}},
-{3478, 15, 14647, {1, 3, 3, 15, 31, 15, 63, 81, 309, 115, 393, 3445, 689, 13963, 18887}},
-{3479, 15, 14653, {1, 1, 5, 1, 19, 39, 127, 61, 357, 53, 195, 2745, 7853, 5753, 3669}},
-{3480, 15, 14659, {1, 3, 7, 7, 17, 51, 57, 145, 451, 365, 1517, 909, 4265, 10737, 9579}},
-{3481, 15, 14671, {1, 1, 3, 13, 3, 37, 121, 103, 257, 47, 1685, 2951, 5753, 15379, 8899}},
-{3482, 15, 14674, {1, 1, 5, 7, 31, 63, 61, 197, 97, 773, 133, 1517, 3093, 14879, 22941}},
-{3483, 15, 14701, {1, 1, 5, 1, 3, 9, 27, 53, 97, 663, 1915, 409, 471, 1391, 24853}},
-{3484, 15, 14716, {1, 1, 1, 7, 21, 53, 69, 5, 187, 571, 2023, 997, 323, 12059, 7071}},
-{3485, 15, 14719, {1, 3, 3, 1, 7, 59, 55, 157, 101, 123, 1301, 3709, 4673, 3897, 28791}},
-{3486, 15, 14720, {1, 3, 7, 5, 5, 23, 39, 139, 365, 415, 1481, 3415, 6323, 11109, 5719}},
-{3487, 15, 14725, {1, 3, 5, 3, 5, 11, 23, 143, 243, 229, 183, 3367, 3187, 8151, 28351}},
-{3488, 15, 14730, {1, 3, 7, 9, 5, 37, 29, 23, 437, 827, 985, 2879, 7611, 1391, 19087}},
-{3489, 15, 14743, {1, 3, 3, 5, 7, 9, 5, 143, 217, 757, 1697, 2459, 453, 8679, 4513}},
-{3490, 15, 14747, {1, 3, 5, 5, 11, 33, 3, 143, 293, 921, 185, 2461, 5547, 12247, 28591}},
-{3491, 15, 14786, {1, 3, 7, 5, 3, 53, 43, 179, 235, 417, 1307, 1367, 3695, 12809, 1807}},
-{3492, 15, 14788, {1, 3, 1, 11, 15, 43, 115, 229, 157, 25, 687, 3347, 271, 5777, 8557}},
-{3493, 15, 14792, {1, 3, 7, 5, 27, 37, 55, 135, 209, 47, 1603, 957, 5785, 11141, 10407}},
-{3494, 15, 14795, {1, 1, 1, 15, 17, 17, 103, 29, 489, 493, 119, 1707, 3463, 1815, 32055}},
-{3495, 15, 14809, {1, 3, 7, 11, 17, 13, 115, 145, 77, 515, 1911, 477, 5997, 8731, 3143}},
-{3496, 15, 14831, {1, 3, 1, 13, 31, 41, 73, 91, 231, 1, 455, 2023, 4691, 3613, 16329}},
-{3497, 15, 14834, {1, 1, 5, 15, 15, 39, 17, 117, 131, 657, 1939, 2245, 2575, 195, 25209}},
-{3498, 15, 14850, {1, 3, 7, 15, 5, 51, 69, 141, 499, 931, 1165, 2119, 1703, 10867, 28443}},
-{3499, 15, 14855, {1, 1, 1, 15, 13, 45, 45, 103, 115, 177, 651, 2545, 1417, 5349, 3385}},
-{3500, 15, 14859, {1, 3, 3, 1, 1, 41, 117, 15, 225, 861, 843, 2775, 4543, 6275, 14671}},
-{3501, 15, 14864, {1, 3, 5, 15, 5, 35, 87, 193, 341, 55, 1131, 945, 6865, 11271, 18705}},
-{3502, 15, 14876, {1, 3, 5, 9, 13, 35, 71, 197, 79, 351, 3, 3939, 1105, 12455, 28921}},
-{3503, 15, 14889, {1, 3, 1, 13, 9, 23, 89, 165, 59, 257, 1369, 161, 6255, 2997, 19175}},
-{3504, 15, 14890, {1, 3, 5, 3, 5, 41, 107, 231, 111, 207, 1865, 2079, 5891, 2487, 5863}},
-{3505, 15, 14898, {1, 3, 7, 15, 3, 3, 105, 235, 263, 991, 367, 1885, 1769, 7805, 11909}},
-{3506, 15, 14909, {1, 3, 3, 5, 15, 59, 67, 247, 77, 367, 1641, 1959, 1921, 5939, 17355}},
-{3507, 15, 14917, {1, 1, 7, 1, 3, 53, 37, 5, 221, 779, 1353, 1633, 2769, 6355, 8505}},
-{3508, 15, 14924, {1, 1, 7, 13, 11, 13, 73, 227, 115, 523, 355, 3127, 7545, 8409, 22335}},
-{3509, 15, 14929, {1, 1, 5, 11, 21, 15, 91, 115, 427, 683, 461, 2433, 6313, 4595, 24401}},
-{3510, 15, 14942, {1, 3, 7, 5, 29, 21, 57, 215, 423, 717, 1455, 705, 6835, 4503, 26077}},
-{3511, 15, 14951, {1, 1, 1, 15, 3, 33, 25, 227, 381, 477, 1023, 2751, 2229, 631, 16903}},
-{3512, 15, 14969, {1, 3, 1, 11, 9, 17, 59, 73, 53, 671, 251, 1729, 7593, 12473, 22533}},
-{3513, 15, 14970, {1, 3, 3, 1, 3, 35, 37, 173, 459, 143, 135, 3871, 2689, 8007, 4379}},
-{3514, 15, 14972, {1, 3, 5, 9, 23, 19, 43, 45, 493, 509, 1851, 1615, 5675, 13793, 6973}},
-{3515, 15, 14982, {1, 3, 3, 15, 5, 17, 77, 85, 451, 753, 579, 1057, 4851, 6017, 4195}},
-{3516, 15, 14988, {1, 3, 3, 5, 31, 29, 81, 159, 103, 391, 15, 899, 4623, 5957, 31961}},
-{3517, 15, 14994, {1, 1, 1, 7, 17, 57, 81, 17, 177, 633, 49, 2793, 5229, 5995, 9491}},
-{3518, 15, 15005, {1, 1, 7, 15, 17, 19, 65, 57, 189, 239, 1229, 929, 2681, 12845, 29311}},
-{3519, 15, 15016, {1, 3, 1, 11, 13, 47, 61, 203, 383, 875, 943, 139, 4217, 8279, 1047}},
-{3520, 15, 15024, {1, 3, 7, 13, 23, 7, 1, 69, 47, 537, 1325, 3101, 685, 14057, 19953}},
-{3521, 15, 15030, {1, 3, 3, 1, 1, 7, 39, 77, 47, 755, 527, 2985, 5433, 15095, 27741}},
-{3522, 15, 15048, {1, 1, 7, 5, 23, 57, 79, 155, 81, 937, 1071, 3929, 1655, 3831, 17351}},
-{3523, 15, 15054, {1, 3, 7, 1, 3, 41, 13, 235, 207, 487, 1883, 2247, 1231, 2751, 15615}},
-{3524, 15, 15066, {1, 1, 7, 1, 21, 57, 95, 191, 119, 483, 283, 2221, 5665, 14819, 26097}},
-{3525, 15, 15071, {1, 3, 1, 1, 9, 59, 27, 51, 393, 31, 925, 715, 7705, 14885, 28767}},
-{3526, 15, 15072, {1, 1, 3, 3, 3, 61, 109, 131, 113, 249, 1331, 2521, 2973, 6375, 20093}},
-{3527, 15, 15075, {1, 3, 7, 9, 31, 37, 125, 245, 237, 245, 111, 379, 7495, 15531, 2325}},
-{3528, 15, 15119, {1, 3, 7, 13, 21, 21, 57, 21, 449, 969, 417, 2999, 509, 639, 7797}},
-{3529, 15, 15121, {1, 3, 7, 7, 7, 29, 11, 175, 55, 705, 891, 863, 3021, 10071, 10267}},
-{3530, 15, 15133, {1, 1, 3, 13, 19, 17, 127, 57, 449, 579, 337, 899, 1235, 11269, 4245}},
-{3531, 15, 15138, {1, 1, 1, 11, 29, 61, 35, 75, 249, 683, 287, 45, 3277, 7521, 2073}},
-{3532, 15, 15143, {1, 3, 5, 5, 15, 25, 77, 63, 63, 801, 1387, 1533, 2185, 10899, 28381}},
-{3533, 15, 15170, {1, 3, 1, 1, 21, 49, 3, 249, 419, 575, 87, 3749, 2523, 16125, 9483}},
-{3534, 15, 15194, {1, 1, 1, 11, 21, 43, 85, 211, 449, 439, 1495, 1841, 4765, 15253, 1467}},
-{3535, 15, 15212, {1, 3, 3, 15, 3, 37, 31, 243, 187, 995, 1103, 2723, 1523, 15967, 28649}},
-{3536, 15, 15223, {1, 1, 5, 11, 9, 11, 17, 87, 335, 125, 1079, 1657, 1237, 8059, 29833}},
-{3537, 15, 15229, {1, 3, 1, 3, 3, 41, 35, 37, 33, 61, 505, 3203, 5, 101, 8571}},
-{3538, 15, 15254, {1, 1, 3, 11, 9, 11, 85, 235, 261, 473, 109, 2127, 5745, 6389, 7431}},
-{3539, 15, 15263, {1, 1, 5, 15, 3, 55, 77, 97, 17, 193, 1267, 3063, 6531, 9797, 8639}},
-{3540, 15, 15270, {1, 1, 5, 5, 25, 41, 79, 83, 485, 697, 149, 1023, 89, 6115, 15227}},
-{3541, 15, 15273, {1, 1, 3, 15, 1, 9, 73, 251, 33, 599, 1017, 353, 4305, 16033, 29663}},
-{3542, 15, 15287, {1, 3, 7, 15, 3, 1, 89, 39, 125, 337, 1445, 3131, 3685, 9849, 25829}},
-{3543, 15, 15299, {1, 3, 7, 3, 19, 1, 63, 179, 349, 135, 185, 2977, 2527, 15087, 18133}},
-{3544, 15, 15301, {1, 1, 3, 3, 23, 7, 91, 221, 325, 723, 345, 81, 8077, 5501, 8453}},
-{3545, 15, 15306, {1, 1, 3, 9, 7, 3, 13, 173, 479, 161, 1989, 3255, 2069, 6717, 559}},
-{3546, 15, 15313, {1, 3, 3, 5, 9, 61, 93, 203, 277, 367, 1141, 981, 4745, 12625, 21003}},
-{3547, 15, 15320, {1, 3, 5, 5, 27, 17, 5, 211, 403, 701, 5, 3091, 4611, 5615, 23667}},
-{3548, 15, 15323, {1, 1, 3, 1, 21, 61, 125, 77, 57, 463, 1499, 791, 2087, 2805, 18829}},
-{3549, 15, 15329, {1, 3, 5, 3, 11, 41, 125, 231, 119, 837, 831, 1331, 7439, 2381, 3759}},
-{3550, 15, 15332, {1, 3, 1, 11, 19, 59, 117, 107, 443, 699, 315, 1491, 2581, 15871, 17159}},
-{3551, 15, 15341, {1, 3, 5, 11, 5, 9, 121, 35, 209, 877, 527, 3493, 4657, 16093, 17589}},
-{3552, 15, 15359, {1, 1, 7, 15, 9, 43, 119, 29, 381, 479, 1443, 3171, 5053, 9625, 21161}},
-{3553, 15, 15361, {1, 1, 3, 5, 15, 21, 31, 223, 83, 399, 1529, 3605, 6343, 10469, 10099}},
-{3554, 15, 15364, {1, 1, 3, 5, 5, 45, 23, 123, 353, 971, 85, 3069, 3245, 6569, 13241}},
-{3555, 15, 15367, {1, 1, 1, 3, 25, 49, 5, 77, 491, 881, 993, 1195, 7677, 5709, 10807}},
-{3556, 15, 15379, {1, 3, 3, 3, 5, 49, 127, 255, 183, 583, 1599, 987, 7281, 7149, 28507}},
-{3557, 15, 15391, {1, 1, 5, 1, 13, 55, 55, 157, 197, 25, 1971, 3161, 3903, 8919, 13563}},
-{3558, 15, 15415, {1, 3, 7, 9, 3, 37, 79, 193, 25, 103, 843, 2651, 6341, 2653, 24337}},
-{3559, 15, 15416, {1, 1, 7, 3, 25, 49, 99, 139, 45, 211, 2033, 2331, 7037, 7177, 1755}},
-{3560, 15, 15419, {1, 3, 7, 3, 5, 19, 127, 135, 403, 221, 141, 1065, 3935, 2745, 25979}},
-{3561, 15, 15433, {1, 1, 3, 3, 31, 23, 111, 37, 261, 7, 835, 2379, 7927, 8181, 23751}},
-{3562, 15, 15469, {1, 3, 7, 15, 1, 39, 79, 3, 103, 427, 1917, 809, 5039, 689, 1939}},
-{3563, 15, 15478, {1, 1, 1, 15, 29, 37, 39, 243, 149, 353, 763, 3405, 5751, 9441, 6653}},
-{3564, 15, 15481, {1, 3, 3, 11, 1, 57, 125, 151, 445, 423, 841, 2265, 5017, 15863, 13057}},
-{3565, 15, 15482, {1, 3, 5, 13, 11, 49, 61, 159, 211, 917, 561, 1903, 3985, 11117, 28969}},
-{3566, 15, 15498, {1, 3, 5, 13, 29, 5, 35, 51, 91, 291, 9, 3713, 3341, 4551, 12085}},
-{3567, 15, 15505, {1, 3, 3, 1, 1, 39, 111, 141, 319, 179, 1709, 1605, 5063, 13279, 10003}},
-{3568, 15, 15517, {1, 1, 3, 9, 7, 59, 91, 41, 343, 475, 1669, 2311, 5141, 12661, 25847}},
-{3569, 15, 15518, {1, 3, 5, 9, 9, 11, 49, 221, 1, 243, 791, 229, 503, 373, 19189}},
-{3570, 15, 15527, {1, 1, 5, 11, 17, 13, 45, 57, 215, 491, 1601, 2183, 3713, 429, 22007}},
-{3571, 15, 15528, {1, 1, 3, 11, 31, 61, 23, 237, 261, 955, 1085, 1541, 2601, 909, 7749}},
-{3572, 15, 15545, {1, 1, 3, 9, 13, 11, 121, 173, 177, 551, 1757, 2745, 2265, 4611, 743}},
-{3573, 15, 15548, {1, 1, 3, 15, 23, 43, 107, 239, 463, 369, 1857, 1073, 1247, 1029, 22557}},
-{3574, 15, 15554, {1, 1, 3, 11, 23, 35, 89, 93, 41, 941, 1141, 2339, 1423, 8007, 28685}},
-{3575, 15, 15565, {1, 3, 5, 13, 29, 7, 79, 15, 59, 145, 1237, 2215, 1257, 12621, 31101}},
-{3576, 15, 15577, {1, 1, 3, 7, 13, 55, 57, 229, 205, 1009, 341, 3901, 5189, 957, 32587}},
-{3577, 15, 15580, {1, 3, 7, 11, 1, 1, 41, 7, 365, 407, 1609, 1423, 6483, 5171, 32519}},
-{3578, 15, 15587, {1, 3, 7, 3, 17, 31, 125, 27, 125, 335, 1395, 2639, 329, 2549, 14449}},
-{3579, 15, 15601, {1, 3, 3, 7, 19, 45, 11, 73, 123, 179, 1685, 3385, 2379, 3387, 16793}},
-{3580, 15, 15604, {1, 3, 7, 5, 31, 25, 47, 153, 121, 453, 935, 3953, 2081, 12145, 24979}},
-{3581, 15, 15611, {1, 1, 7, 13, 25, 11, 65, 3, 277, 237, 1129, 1801, 4165, 9065, 18747}},
-{3582, 15, 15616, {1, 1, 7, 7, 13, 5, 37, 253, 507, 645, 1355, 3401, 6707, 6329, 11237}},
-{3583, 15, 15619, {1, 1, 3, 15, 17, 49, 3, 233, 407, 451, 69, 3859, 3171, 12303, 21031}},
-{3584, 15, 15625, {1, 1, 3, 3, 9, 53, 119, 117, 401, 903, 1449, 3639, 4083, 2095, 22085}},
-{3585, 15, 15633, {1, 3, 7, 15, 5, 61, 117, 193, 137, 431, 195, 4019, 3047, 5049, 14281}},
-{3586, 15, 15674, {1, 1, 1, 15, 17, 19, 29, 83, 449, 257, 1105, 1949, 1749, 3459, 6343}},
-{3587, 15, 15681, {1, 1, 1, 15, 23, 39, 61, 219, 109, 365, 863, 1813, 6673, 15999, 5101}},
-{3588, 15, 15691, {1, 1, 5, 5, 13, 11, 37, 151, 365, 719, 1233, 2425, 1285, 1721, 1205}},
-{3589, 15, 15693, {1, 3, 3, 3, 7, 53, 109, 153, 45, 425, 1741, 1229, 4405, 8071, 25155}},
-{3590, 15, 15696, {1, 3, 1, 1, 1, 13, 39, 49, 413, 77, 1367, 2553, 5563, 7659, 3467}},
-{3591, 15, 15712, {1, 1, 5, 9, 3, 49, 23, 11, 445, 121, 1505, 877, 4137, 1809, 2429}},
-{3592, 15, 15717, {1, 1, 1, 11, 21, 13, 93, 33, 493, 805, 775, 2939, 2961, 13625, 31879}},
-{3593, 15, 15724, {1, 1, 7, 5, 1, 59, 63, 131, 373, 23, 337, 2107, 5315, 4889, 22851}},
-{3594, 15, 15727, {1, 1, 3, 13, 21, 47, 15, 131, 353, 793, 1891, 1757, 5793, 1147, 23697}},
-{3595, 15, 15730, {1, 3, 5, 13, 7, 59, 25, 135, 259, 109, 1835, 429, 8153, 7355, 145}},
-{3596, 15, 15746, {1, 3, 3, 13, 9, 47, 121, 89, 89, 635, 1079, 2353, 4803, 11369, 12653}},
-{3597, 15, 15751, {1, 3, 5, 9, 23, 39, 49, 231, 105, 603, 613, 2021, 6073, 11819, 10595}},
-{3598, 15, 15760, {1, 3, 7, 7, 7, 19, 19, 155, 347, 387, 1459, 3793, 619, 14437, 2455}},
-{3599, 15, 15770, {1, 1, 1, 15, 21, 35, 19, 185, 483, 425, 479, 3429, 5403, 10791, 14219}},
-{3600, 15, 15782, {1, 1, 3, 11, 5, 51, 105, 63, 493, 677, 1457, 2865, 5619, 9321, 19583}},
-{3601, 15, 15791, {1, 1, 3, 3, 23, 1, 77, 177, 263, 289, 1567, 3837, 5359, 3269, 16023}},
-{3602, 15, 15796, {1, 1, 7, 3, 13, 61, 79, 77, 51, 953, 1417, 795, 4467, 2981, 25131}},
-{3603, 15, 15808, {1, 1, 5, 13, 23, 13, 29, 185, 337, 7, 149, 3609, 8119, 9545, 16579}},
-{3604, 15, 15814, {1, 3, 1, 5, 23, 9, 123, 15, 99, 55, 1021, 3709, 1521, 15189, 22193}},
-{3605, 15, 15825, {1, 3, 7, 9, 13, 41, 39, 45, 49, 181, 1587, 3213, 1037, 14775, 3333}},
-{3606, 15, 15828, {1, 1, 1, 7, 29, 55, 59, 31, 411, 601, 191, 283, 3211, 7951, 7919}},
-{3607, 15, 15835, {1, 1, 7, 7, 21, 47, 7, 193, 343, 831, 1267, 3289, 1015, 13093, 2717}},
-{3608, 15, 15844, {1, 3, 7, 1, 17, 9, 97, 19, 279, 827, 1699, 3573, 3137, 3535, 17791}},
-{3609, 15, 15847, {1, 1, 5, 11, 27, 15, 103, 135, 35, 625, 1575, 97, 7013, 13353, 19333}},
-{3610, 15, 15853, {1, 3, 3, 7, 17, 13, 49, 135, 435, 743, 1799, 2655, 4839, 2893, 31153}},
-{3611, 15, 15856, {1, 1, 5, 1, 3, 41, 1, 195, 53, 803, 1575, 2939, 3873, 10495, 5211}},
-{3612, 15, 15877, {1, 3, 1, 15, 19, 19, 37, 59, 355, 483, 685, 3899, 4645, 15127, 3479}},
-{3613, 15, 15878, {1, 1, 5, 3, 25, 9, 9, 229, 101, 631, 1165, 4091, 3723, 10655, 9463}},
-{3614, 15, 15887, {1, 3, 5, 15, 5, 13, 91, 61, 19, 469, 1675, 3331, 3121, 3435, 4111}},
-{3615, 15, 15908, {1, 1, 7, 1, 31, 61, 23, 83, 165, 551, 1097, 3825, 5385, 4723, 3635}},
-{3616, 15, 15917, {1, 3, 7, 15, 9, 31, 11, 121, 503, 855, 561, 1647, 1229, 1147, 15997}},
-{3617, 15, 15923, {1, 3, 7, 13, 21, 47, 41, 195, 197, 719, 1263, 3609, 7515, 2659, 30713}},
-{3618, 15, 15930, {1, 1, 1, 7, 31, 61, 101, 101, 479, 571, 605, 301, 6633, 15587, 23665}},
-{3619, 15, 15937, {1, 3, 7, 3, 25, 39, 35, 225, 135, 463, 53, 709, 5129, 4135, 10421}},
-{3620, 15, 15958, {1, 1, 5, 13, 19, 55, 107, 15, 163, 287, 673, 899, 5197, 4619, 3465}},
-{3621, 15, 15977, {1, 3, 3, 5, 21, 49, 15, 105, 283, 877, 1875, 1079, 3431, 13053, 26599}},
-{3622, 15, 15991, {1, 1, 7, 1, 1, 1, 95, 113, 119, 575, 1159, 2325, 6895, 12177, 4369}},
-{3623, 15, 16007, {1, 1, 1, 11, 25, 25, 83, 207, 301, 729, 1947, 2321, 3621, 15707, 11303}},
-{3624, 15, 16011, {1, 1, 5, 5, 7, 63, 83, 105, 211, 175, 1817, 2883, 5385, 7437, 24865}},
-{3625, 15, 16014, {1, 3, 7, 5, 23, 39, 19, 211, 151, 295, 573, 223, 5065, 6345, 23187}},
-{3626, 15, 16021, {1, 1, 7, 11, 15, 31, 89, 123, 57, 695, 685, 1799, 659, 9929, 22933}},
-{3627, 15, 16022, {1, 1, 7, 7, 19, 17, 27, 137, 117, 141, 1481, 869, 7061, 3073, 19671}},
-{3628, 15, 16028, {1, 3, 3, 11, 9, 19, 123, 93, 39, 517, 883, 3769, 2267, 8089, 6617}},
-{3629, 15, 16035, {1, 3, 1, 7, 9, 61, 51, 241, 319, 853, 1239, 899, 105, 1677, 29351}},
-{3630, 15, 16041, {1, 1, 7, 15, 13, 59, 85, 175, 223, 87, 905, 3175, 3405, 3489, 18475}},
-{3631, 15, 16056, {1, 1, 1, 15, 1, 55, 79, 97, 315, 605, 851, 4015, 3689, 9371, 31523}},
-{3632, 15, 16069, {1, 1, 5, 15, 1, 39, 91, 27, 211, 881, 1375, 2307, 5791, 10185, 23093}},
-{3633, 15, 16076, {1, 3, 1, 5, 3, 17, 59, 219, 105, 623, 21, 2843, 3427, 4799, 3793}},
-{3634, 15, 16081, {1, 3, 3, 7, 21, 55, 17, 29, 397, 93, 1981, 4047, 935, 5971, 14589}},
-{3635, 15, 16087, {1, 1, 3, 9, 5, 57, 63, 27, 373, 815, 167, 205, 367, 4945, 30041}},
-{3636, 15, 16088, {1, 1, 5, 9, 7, 3, 69, 35, 197, 309, 1729, 3735, 1523, 10427, 26253}},
-{3637, 15, 16110, {1, 1, 3, 7, 7, 49, 35, 189, 297, 311, 2025, 305, 3863, 14393, 2533}},
-{3638, 15, 16112, {1, 3, 3, 9, 17, 31, 5, 17, 167, 601, 909, 3149, 2533, 12123, 25325}},
-{3639, 15, 16117, {1, 3, 5, 3, 11, 41, 69, 199, 79, 611, 133, 3519, 5955, 4609, 27403}},
-{3640, 15, 16150, {1, 3, 3, 13, 3, 17, 53, 165, 361, 797, 1447, 869, 6707, 6541, 32249}},
-{3641, 15, 16153, {1, 3, 1, 1, 29, 47, 17, 45, 473, 199, 1595, 3095, 3635, 6965, 21859}},
-{3642, 15, 16160, {1, 1, 3, 9, 1, 15, 59, 163, 91, 811, 1087, 1707, 6743, 12643, 29901}},
-{3643, 15, 16166, {1, 1, 1, 3, 19, 21, 7, 209, 121, 821, 709, 1085, 5333, 7689, 28355}},
-{3644, 15, 16172, {1, 3, 1, 15, 5, 27, 115, 31, 37, 79, 1347, 155, 3709, 13251, 32151}},
-{3645, 15, 16190, {1, 3, 7, 15, 27, 27, 127, 231, 137, 205, 1665, 1461, 299, 2797, 879}},
-{3646, 15, 16195, {1, 1, 1, 7, 13, 3, 127, 13, 253, 481, 1435, 1895, 2665, 7611, 17761}},
-{3647, 15, 16204, {1, 1, 3, 7, 7, 21, 71, 247, 301, 183, 1785, 331, 4835, 2251, 4493}},
-{3648, 15, 16216, {1, 3, 7, 9, 9, 1, 77, 169, 103, 647, 1959, 1847, 5803, 3421, 15915}},
-{3649, 15, 16222, {1, 3, 1, 7, 19, 17, 81, 45, 263, 549, 1607, 2177, 1117, 14427, 16451}},
-{3650, 15, 16228, {1, 1, 7, 15, 27, 25, 27, 27, 33, 813, 1667, 253, 2749, 927, 29707}},
-{3651, 15, 16245, {1, 1, 7, 3, 17, 29, 13, 67, 417, 303, 19, 3809, 7225, 12775, 3933}},
-{3652, 15, 16255, {1, 1, 1, 11, 13, 41, 77, 217, 281, 659, 1099, 3047, 1619, 525, 4313}},
-{3653, 15, 16265, {1, 3, 3, 9, 23, 47, 5, 33, 219, 531, 77, 2307, 1893, 8335, 8281}},
-{3654, 15, 16273, {1, 3, 7, 3, 3, 35, 27, 249, 159, 495, 431, 3001, 1475, 11505, 15693}},
-{3655, 15, 16276, {1, 1, 5, 9, 21, 49, 43, 159, 465, 959, 179, 993, 121, 11569, 21027}},
-{3656, 15, 16283, {1, 3, 1, 5, 1, 61, 9, 221, 231, 55, 191, 2829, 3331, 8911, 15109}},
-{3657, 15, 16295, {1, 1, 7, 1, 7, 35, 67, 97, 159, 191, 935, 3151, 6397, 10751, 1835}},
-{3658, 15, 16304, {1, 1, 1, 7, 15, 39, 127, 163, 437, 333, 829, 753, 8151, 13239, 523}},
-{3659, 15, 16313, {1, 1, 3, 13, 9, 25, 73, 155, 445, 239, 2035, 15, 5243, 15531, 1733}},
-{3660, 15, 16319, {1, 3, 7, 15, 5, 25, 3, 55, 117, 57, 783, 1509, 7043, 13159, 8557}},
-{3661, 15, 16328, {1, 3, 5, 1, 21, 55, 89, 119, 199, 79, 161, 1597, 3263, 3335, 5757}},
-{3662, 15, 16345, {1, 3, 7, 5, 27, 23, 85, 113, 111, 211, 389, 1513, 2759, 7945, 931}},
-{3663, 15, 16355, {1, 1, 1, 7, 1, 5, 17, 177, 357, 619, 5, 2583, 621, 2973, 28845}},
-{3664, 15, 16364, {1, 3, 7, 13, 11, 21, 47, 99, 421, 279, 1541, 1305, 4571, 6127, 20735}},
-{3665, 15, 16372, {1, 3, 5, 5, 23, 43, 19, 137, 425, 409, 1625, 2671, 4385, 3197, 25753}},
-{3666, 15, 16375, {1, 1, 7, 5, 27, 17, 57, 15, 383, 181, 951, 2115, 5237, 1495, 9671}},
-{3667, 15, 16382, {1, 3, 3, 11, 9, 1, 53, 127, 375, 499, 1487, 121, 1465, 3175, 24337}},
-{3668, 16, 22, {1, 3, 7, 11, 29, 35, 67, 129, 221, 439, 1159, 3501, 7741, 8885, 11381, 20707}},
-{3669, 16, 28, {1, 3, 5, 11, 29, 59, 23, 117, 343, 637, 1825, 1687, 2823, 11641, 3311, 23603}},
-{3670, 16, 31, {1, 1, 5, 11, 1, 35, 103, 155, 233, 575, 1761, 503, 4175, 6105, 29737, 32681}},
-{3671, 16, 41, {1, 3, 3, 1, 5, 63, 27, 71, 245, 433, 1779, 2475, 5479, 4705, 10795, 34247}},
-{3672, 16, 94, {1, 3, 5, 7, 29, 45, 117, 5, 393, 849, 843, 3131, 6995, 9979, 28907, 30115}},
-{3673, 16, 107, {1, 3, 5, 9, 27, 29, 69, 5, 395, 561, 1531, 409, 2779, 8785, 16405, 27315}},
-{3674, 16, 151, {1, 3, 1, 9, 15, 29, 85, 3, 331, 19, 1941, 567, 6957, 747, 1627, 11347}},
-{3675, 16, 158, {1, 1, 3, 9, 27, 45, 47, 127, 133, 921, 1817, 2231, 6333, 14371, 12799, 9831}},
-{3676, 16, 167, {1, 1, 5, 15, 31, 7, 125, 13, 455, 159, 331, 3629, 4705, 11261, 3657, 36307}},
-{3677, 16, 174, {1, 1, 5, 9, 11, 53, 51, 35, 87, 885, 1975, 3899, 1013, 7667, 32385, 33635}},
-{3678, 16, 203, {1, 1, 1, 3, 7, 45, 107, 177, 193, 765, 731, 139, 5563, 623, 16485, 54999}},
-{3679, 16, 208, {1, 1, 5, 9, 17, 53, 117, 69, 385, 587, 1483, 149, 2769, 3013, 18183, 10173}},
-{3680, 16, 214, {1, 1, 5, 11, 5, 3, 25, 153, 351, 749, 801, 3077, 3209, 11189, 25241, 14115}},
-{3681, 16, 223, {1, 1, 7, 9, 1, 47, 41, 247, 135, 163, 899, 1517, 5647, 10595, 32531, 12497}},
-{3682, 16, 227, {1, 3, 5, 11, 5, 61, 111, 215, 251, 279, 825, 2155, 3527, 173, 10973, 59257}},
-{3683, 16, 266, {1, 3, 5, 11, 25, 15, 71, 83, 135, 231, 1415, 3761, 7513, 8337, 28979, 43615}},
-{3684, 16, 268, {1, 3, 5, 13, 19, 5, 55, 165, 141, 119, 1891, 2255, 4735, 16217, 26195, 50527}},
-{3685, 16, 274, {1, 1, 7, 15, 23, 59, 59, 191, 1, 855, 453, 2619, 5013, 14749, 24335, 44339}},
-{3686, 16, 279, {1, 1, 1, 13, 15, 41, 51, 147, 229, 495, 1191, 867, 1525, 581, 29713, 26391}},
-{3687, 16, 302, {1, 1, 1, 9, 29, 5, 59, 127, 105, 417, 301, 2249, 6335, 3513, 17373, 52977}},
-{3688, 16, 310, {1, 1, 3, 7, 21, 27, 109, 143, 63, 347, 1429, 2889, 2597, 10243, 9913, 22687}},
-{3689, 16, 322, {1, 3, 5, 5, 7, 3, 125, 147, 313, 351, 1163, 415, 5615, 5571, 7089, 55621}},
-{3690, 16, 328, {1, 3, 3, 3, 31, 43, 101, 93, 9, 671, 135, 333, 2169, 11169, 7403, 50707}},
-{3691, 16, 336, {1, 1, 7, 13, 15, 33, 125, 155, 227, 827, 1047, 2441, 3007, 10881, 19969, 63805}},
-{3692, 16, 370, {1, 3, 3, 5, 31, 33, 29, 249, 159, 797, 1475, 841, 6933, 6417, 25629, 61865}},
-{3693, 16, 398, {1, 3, 3, 15, 11, 55, 11, 117, 149, 911, 1589, 3133, 6477, 6123, 10471, 41099}},
-{3694, 16, 421, {1, 3, 3, 9, 27, 37, 1, 119, 509, 969, 831, 3771, 2093, 13621, 31737, 43269}},
-{3695, 16, 436, {1, 1, 1, 1, 9, 23, 119, 109, 487, 753, 1673, 2163, 3349, 4741, 29971, 3407}},
-{3696, 16, 440, {1, 3, 3, 7, 25, 7, 67, 9, 461, 631, 651, 2271, 5663, 2621, 3953, 20975}},
-{3697, 16, 451, {1, 1, 5, 11, 13, 31, 29, 255, 371, 517, 845, 3649, 1187, 10061, 22887, 58417}},
-{3698, 16, 454, {1, 3, 5, 13, 29, 1, 11, 137, 151, 249, 167, 1243, 997, 11023, 11875, 42315}},
-{3699, 16, 463, {1, 1, 5, 5, 5, 55, 103, 71, 255, 1023, 209, 1005, 2147, 11527, 17863, 6661}},
-{3700, 16, 465, {1, 1, 3, 3, 31, 39, 7, 151, 353, 775, 1313, 1257, 4197, 2625, 9571, 27269}},
-{3701, 16, 494, {1, 1, 1, 3, 7, 17, 3, 127, 501, 503, 1879, 2329, 3049, 10603, 2111, 33189}},
-{3702, 16, 508, {1, 3, 3, 7, 13, 59, 93, 13, 375, 483, 1991, 2257, 3003, 1699, 4339, 51827}},
-{3703, 16, 532, {1, 3, 7, 15, 27, 41, 59, 225, 405, 807, 1545, 2581, 1173, 14137, 3413, 39299}},
-{3704, 16, 555, {1, 1, 1, 3, 9, 23, 37, 123, 465, 1023, 1065, 1455, 5107, 3839, 20451, 11461}},
-{3705, 16, 563, {1, 1, 1, 11, 19, 55, 91, 121, 317, 199, 215, 3031, 7223, 11891, 21463, 64921}},
-{3706, 16, 577, {1, 3, 7, 11, 19, 5, 5, 115, 399, 219, 71, 1465, 281, 14451, 26807, 42541}},
-{3707, 16, 580, {1, 3, 5, 13, 3, 33, 75, 35, 19, 559, 761, 947, 7479, 15325, 31453, 20561}},
-{3708, 16, 584, {1, 3, 3, 13, 23, 47, 99, 73, 331, 353, 401, 1737, 6235, 13781, 5547, 56443}},
-{3709, 16, 607, {1, 3, 3, 13, 21, 37, 41, 205, 87, 399, 51, 3175, 7403, 12875, 21129, 7079}},
-{3710, 16, 608, {1, 3, 5, 11, 15, 47, 33, 39, 465, 871, 277, 2351, 695, 1953, 24293, 20595}},
-{3711, 16, 665, {1, 1, 7, 11, 13, 15, 115, 59, 469, 715, 191, 1927, 905, 13463, 29005, 46789}},
-{3712, 16, 675, {1, 3, 5, 9, 13, 55, 79, 17, 265, 887, 905, 3985, 6907, 3379, 20055, 58569}},
-{3713, 16, 692, {1, 1, 7, 11, 21, 29, 23, 109, 17, 427, 1623, 2219, 3857, 3709, 25033, 63823}},
-{3714, 16, 707, {1, 3, 5, 15, 19, 27, 113, 15, 25, 63, 1885, 2693, 5301, 9385, 14137, 26097}},
-{3715, 16, 737, {1, 3, 3, 11, 17, 5, 73, 143, 79, 957, 461, 1709, 4909, 2285, 18113, 8401}},
-{3716, 16, 750, {1, 1, 3, 7, 9, 9, 101, 127, 137, 755, 1359, 1965, 83, 13335, 27763, 7941}},
-{3717, 16, 757, {1, 1, 1, 3, 13, 61, 95, 61, 295, 615, 555, 2163, 8155, 14043, 21465, 46741}},
-{3718, 16, 800, {1, 1, 1, 13, 29, 19, 111, 17, 373, 153, 1703, 2199, 7209, 15845, 1879, 7493}},
-{3719, 16, 805, {1, 3, 1, 13, 21, 51, 49, 51, 255, 151, 207, 1915, 7629, 2705, 8739, 7467}},
-{3720, 16, 809, {1, 3, 7, 5, 21, 21, 23, 193, 467, 739, 519, 2315, 2953, 10633, 9163, 6007}},
-{3721, 16, 837, {1, 3, 1, 5, 23, 19, 23, 247, 93, 297, 1089, 2349, 4683, 13609, 7615, 18647}},
-{3722, 16, 865, {1, 1, 3, 3, 21, 39, 19, 71, 93, 1, 133, 3531, 7503, 2819, 24211, 1739}},
-{3723, 16, 949, {1, 3, 5, 13, 9, 43, 31, 111, 493, 739, 705, 2715, 3613, 11877, 27945, 46053}},
-{3724, 16, 950, {1, 1, 7, 13, 27, 59, 103, 129, 53, 531, 1379, 1441, 5341, 14937, 5079, 39881}},
-{3725, 16, 956, {1, 1, 3, 3, 11, 63, 91, 95, 433, 393, 715, 809, 591, 4141, 17417, 54107}},
-{3726, 16, 961, {1, 3, 5, 1, 7, 25, 25, 175, 205, 803, 183, 1441, 1279, 2753, 20001, 56677}},
-{3727, 16, 1016, {1, 1, 5, 3, 13, 23, 77, 25, 133, 137, 1907, 1313, 2463, 14339, 13, 57757}},
-{3728, 16, 1030, {1, 1, 5, 9, 23, 35, 1, 119, 111, 61, 403, 1815, 1985, 5651, 10883, 55943}},
-{3729, 16, 1072, {1, 3, 1, 7, 21, 43, 115, 7, 107, 719, 759, 1521, 467, 8735, 29785, 63821}},
-{3730, 16, 1119, {1, 1, 3, 13, 19, 17, 51, 141, 399, 569, 703, 2221, 2809, 13355, 1907, 15837}},
-{3731, 16, 1130, {1, 1, 5, 15, 15, 53, 57, 31, 481, 69, 1439, 4049, 6727, 11307, 20683, 63517}},
-{3732, 16, 1135, {1, 1, 1, 3, 13, 27, 9, 255, 363, 131, 1745, 2489, 6451, 6585, 12873, 35405}},
-{3733, 16, 1137, {1, 3, 5, 1, 17, 31, 113, 135, 449, 915, 1017, 2317, 6821, 5483, 30707, 45279}},
-{3734, 16, 1144, {1, 3, 5, 1, 13, 47, 25, 53, 413, 545, 1777, 3049, 7527, 9689, 25935, 9919}},
-{3735, 16, 1149, {1, 3, 7, 11, 17, 39, 13, 131, 295, 517, 1755, 2977, 6267, 12351, 8957, 17765}},
-{3736, 16, 1180, {1, 1, 7, 5, 27, 57, 47, 21, 125, 429, 1169, 1717, 5455, 16359, 29065, 6671}},
-{3737, 16, 1214, {1, 1, 5, 5, 21, 15, 79, 241, 83, 515, 859, 2351, 3125, 7465, 30475, 19759}},
-{3738, 16, 1221, {1, 3, 1, 9, 11, 5, 81, 11, 7, 221, 141, 3329, 3435, 323, 18999, 54735}},
-{3739, 16, 1234, {1, 1, 1, 15, 7, 57, 87, 251, 63, 561, 929, 1367, 2511, 14527, 9335, 38775}},
-{3740, 16, 1239, {1, 3, 3, 9, 23, 37, 59, 105, 179, 515, 235, 2445, 433, 13039, 27005, 48829}},
-{3741, 16, 1249, {1, 1, 1, 1, 23, 37, 103, 31, 89, 921, 1687, 831, 387, 10237, 1241, 19295}},
-{3742, 16, 1250, {1, 3, 3, 7, 25, 23, 57, 251, 309, 579, 603, 807, 7383, 8579, 4025, 16757}},
-{3743, 16, 1267, {1, 1, 3, 15, 23, 59, 29, 33, 467, 641, 1271, 2915, 2549, 14767, 26557, 43483}},
-{3744, 16, 1273, {1, 1, 7, 13, 1, 57, 23, 129, 321, 75, 189, 4087, 5011, 4355, 25759, 37153}},
-{3745, 16, 1342, {1, 1, 5, 1, 21, 57, 25, 183, 37, 669, 259, 1381, 877, 10245, 16643, 61035}},
-{3746, 16, 1344, {1, 1, 7, 5, 11, 11, 85, 141, 393, 957, 1745, 2243, 1681, 5583, 16527, 12017}},
-{3747, 16, 1373, {1, 1, 5, 15, 23, 31, 5, 169, 287, 527, 1831, 2937, 7533, 9739, 24305, 2239}},
-{3748, 16, 1378, {1, 1, 7, 1, 7, 13, 3, 243, 189, 309, 607, 3659, 6369, 7649, 24255, 55373}},
-{3749, 16, 1408, {1, 1, 1, 3, 3, 59, 103, 209, 287, 913, 1223, 1063, 7715, 6073, 26697, 25671}},
-{3750, 16, 1417, {1, 3, 7, 5, 19, 19, 117, 191, 275, 637, 991, 2199, 2921, 10553, 21211, 25981}},
-{3751, 16, 1418, {1, 3, 3, 5, 29, 59, 17, 13, 127, 57, 1405, 3181, 2237, 1795, 21419, 43421}},
-{3752, 16, 1448, {1, 1, 1, 15, 25, 41, 11, 117, 463, 425, 305, 1441, 4307, 7967, 17529, 4043}},
-{3753, 16, 1454, {1, 3, 5, 5, 19, 53, 69, 73, 453, 611, 1583, 1721, 6303, 10561, 18527, 48973}},
-{3754, 16, 1510, {1, 1, 7, 11, 15, 61, 87, 69, 463, 771, 819, 469, 8165, 8897, 29657, 55161}},
-{3755, 16, 1513, {1, 1, 5, 1, 15, 25, 23, 47, 287, 457, 1219, 473, 4127, 3349, 9425, 41541}},
-{3756, 16, 1522, {1, 3, 7, 5, 17, 17, 33, 161, 239, 231, 241, 1297, 4879, 12761, 20939, 65261}},
-{3757, 16, 1543, {1, 3, 3, 9, 19, 53, 95, 89, 117, 333, 1815, 2217, 7779, 8213, 4667, 58395}},
-{3758, 16, 1550, {1, 3, 3, 9, 17, 7, 41, 99, 371, 797, 729, 2851, 2003, 4463, 20793, 54315}},
-{3759, 16, 1552, {1, 3, 5, 5, 23, 39, 19, 235, 163, 365, 141, 791, 455, 2761, 9115, 53351}},
-{3760, 16, 1588, {1, 3, 3, 3, 9, 27, 29, 139, 165, 867, 2023, 1333, 3771, 10451, 9141, 41177}},
-{3761, 16, 1592, {1, 1, 3, 7, 3, 11, 125, 157, 355, 519, 187, 3381, 1151, 1629, 25247, 42797}},
-{3762, 16, 1597, {1, 3, 3, 3, 21, 25, 37, 155, 257, 311, 961, 1945, 1383, 5679, 7857, 7183}},
-{3763, 16, 1606, {1, 3, 3, 5, 29, 11, 49, 125, 171, 605, 1923, 2781, 2555, 5063, 5075, 43301}},
-{3764, 16, 1610, {1, 3, 5, 9, 27, 1, 27, 149, 253, 205, 1299, 2901, 2891, 975, 7641, 8115}},
-{3765, 16, 1617, {1, 3, 5, 3, 31, 7, 49, 215, 81, 791, 1485, 837, 5051, 1947, 7521, 25723}},
-{3766, 16, 1623, {1, 3, 5, 7, 23, 25, 69, 13, 3, 859, 441, 3577, 1687, 6559, 8687, 46757}},
-{3767, 16, 1657, {1, 1, 1, 9, 1, 59, 3, 31, 251, 187, 617, 2607, 4635, 6121, 8565, 8871}},
-{3768, 16, 1697, {1, 3, 3, 9, 29, 37, 127, 87, 153, 633, 1691, 2729, 3167, 3219, 21237, 25573}},
-{3769, 16, 1729, {1, 1, 5, 13, 19, 63, 93, 235, 299, 621, 405, 663, 6639, 12265, 9303, 42719}},
-{3770, 16, 1735, {1, 1, 3, 9, 25, 11, 9, 231, 101, 335, 1793, 1497, 7069, 4171, 30199, 63}},
-{3771, 16, 1769, {1, 1, 1, 1, 5, 19, 17, 217, 165, 413, 925, 1409, 6559, 14537, 22057, 44331}},
-{3772, 16, 1778, {1, 1, 3, 7, 11, 51, 45, 217, 57, 795, 951, 2933, 6705, 137, 30525, 9679}},
-{3773, 16, 1826, {1, 1, 3, 15, 27, 47, 35, 125, 363, 619, 1027, 2861, 3923, 10459, 16789, 27277}},
-{3774, 16, 1858, {1, 1, 7, 7, 13, 37, 33, 29, 385, 851, 143, 119, 7345, 4251, 25121, 31609}},
-{3775, 16, 1870, {1, 3, 1, 1, 17, 25, 119, 7, 365, 397, 601, 2087, 6903, 15345, 14671, 37889}},
-{3776, 16, 1875, {1, 3, 1, 13, 19, 51, 41, 139, 133, 723, 25, 2621, 1257, 7037, 9527, 50037}},
-{3777, 16, 1922, {1, 1, 5, 11, 5, 59, 119, 75, 397, 545, 1095, 585, 3271, 1049, 123, 33029}},
-{3778, 16, 1924, {1, 1, 7, 11, 9, 27, 21, 197, 177, 31, 453, 2457, 2733, 7787, 1923, 24639}},
-{3779, 16, 1933, {1, 1, 7, 13, 29, 13, 91, 91, 243, 279, 601, 1699, 7169, 4727, 7815, 29099}},
-{3780, 16, 1972, {1, 3, 7, 5, 1, 35, 27, 235, 163, 913, 1479, 769, 7179, 1983, 25977, 55373}},
-{3781, 16, 1979, {1, 3, 5, 11, 9, 33, 99, 141, 301, 109, 1785, 129, 1707, 5181, 4797, 9979}},
-{3782, 16, 1987, {1, 1, 1, 13, 3, 47, 89, 43, 293, 87, 1689, 3885, 7747, 5607, 477, 31887}},
-{3783, 16, 1994, {1, 1, 5, 1, 9, 21, 73, 37, 45, 621, 1855, 3691, 4899, 2191, 13459, 23543}},
-{3784, 16, 2008, {1, 1, 1, 1, 7, 39, 61, 125, 341, 905, 213, 1755, 241, 13407, 8791, 10165}},
-{3785, 16, 2023, {1, 1, 1, 1, 19, 31, 79, 19, 55, 875, 1017, 1787, 4879, 533, 15029, 52295}},
-{3786, 16, 2029, {1, 3, 1, 1, 9, 59, 113, 71, 113, 649, 561, 71, 5253, 783, 7389, 19361}},
-{3787, 16, 2053, {1, 1, 1, 11, 5, 39, 61, 225, 291, 907, 795, 1099, 597, 11829, 15137, 42865}},
-{3788, 16, 2081, {1, 3, 1, 5, 25, 11, 71, 155, 271, 309, 1981, 1253, 463, 1133, 20833, 48625}},
-{3789, 16, 2087, {1, 3, 5, 9, 7, 41, 87, 241, 457, 899, 1493, 3675, 3025, 10607, 22569, 52813}},
-{3790, 16, 2094, {1, 3, 7, 13, 7, 37, 37, 103, 281, 915, 1259, 4049, 559, 173, 4123, 63767}},
-{3791, 16, 2111, {1, 3, 7, 15, 13, 57, 9, 51, 39, 549, 1431, 2887, 1081, 4643, 16331, 14221}},
-{3792, 16, 2113, {1, 3, 5, 7, 13, 1, 101, 125, 25, 713, 1423, 513, 3323, 9951, 7163, 20969}},
-{3793, 16, 2114, {1, 1, 7, 15, 11, 25, 25, 3, 47, 531, 1529, 471, 6191, 10051, 29671, 49085}},
-{3794, 16, 2123, {1, 1, 3, 5, 23, 51, 117, 141, 55, 275, 761, 1923, 6267, 2291, 3701, 26615}},
-{3795, 16, 2190, {1, 1, 7, 9, 15, 19, 111, 65, 137, 373, 1753, 3591, 1137, 11639, 28591, 27265}},
-{3796, 16, 2231, {1, 3, 1, 15, 29, 5, 67, 13, 425, 961, 453, 2481, 1407, 3479, 23303, 30407}},
-{3797, 16, 2276, {1, 1, 5, 3, 19, 39, 39, 123, 351, 77, 1339, 1765, 3767, 1907, 13627, 23877}},
-{3798, 16, 2285, {1, 3, 5, 9, 23, 7, 103, 177, 221, 197, 561, 2121, 7231, 12053, 30127, 29849}},
-{3799, 16, 2297, {1, 1, 5, 7, 15, 1, 3, 123, 197, 493, 171, 2425, 3865, 4061, 31883, 2491}},
-{3800, 16, 2336, {1, 1, 3, 13, 29, 33, 99, 67, 327, 969, 1793, 1871, 1839, 13059, 7605, 16797}},
-{3801, 16, 2345, {1, 3, 5, 11, 25, 53, 25, 93, 303, 623, 1889, 1471, 1213, 14459, 8527, 25095}},
-{3802, 16, 2353, {1, 1, 1, 13, 15, 3, 115, 3, 289, 743, 1855, 359, 2375, 13765, 19711, 40765}},
-{3803, 16, 2363, {1, 1, 7, 11, 27, 51, 85, 163, 219, 871, 637, 2011, 5981, 587, 17521, 17333}},
-{3804, 16, 2368, {1, 3, 5, 1, 21, 59, 49, 39, 305, 513, 2017, 285, 5817, 13123, 27765, 46741}},
-{3805, 16, 2373, {1, 3, 3, 7, 21, 39, 71, 163, 423, 845, 783, 397, 7319, 10677, 13407, 47471}},
-{3806, 16, 2391, {1, 3, 7, 5, 21, 59, 99, 179, 473, 687, 1393, 723, 2245, 2933, 25943, 7769}},
-{3807, 16, 2402, {1, 1, 5, 9, 5, 45, 71, 189, 165, 555, 643, 2289, 3133, 12319, 22209, 1533}},
-{3808, 16, 2413, {1, 1, 3, 9, 7, 43, 1, 155, 323, 169, 339, 2561, 4049, 4953, 5289, 8783}},
-{3809, 16, 2422, {1, 3, 1, 11, 15, 5, 25, 201, 267, 891, 561, 501, 575, 15147, 1743, 45237}},
-{3810, 16, 2425, {1, 3, 5, 13, 25, 27, 105, 205, 165, 795, 975, 943, 7413, 10299, 14839, 54895}},
-{3811, 16, 2461, {1, 1, 5, 1, 17, 43, 69, 103, 449, 917, 103, 945, 513, 709, 11647, 28065}},
-{3812, 16, 2462, {1, 1, 3, 15, 23, 51, 23, 7, 159, 743, 177, 3457, 415, 1775, 25353, 36385}},
-{3813, 16, 2490, {1, 3, 5, 13, 9, 63, 121, 19, 165, 449, 1523, 1959, 6901, 12281, 29149, 45999}},
-{3814, 16, 2492, {1, 3, 7, 11, 17, 19, 9, 155, 373, 753, 1313, 2205, 3571, 16317, 16151, 15325}},
-{3815, 16, 2510, {1, 3, 3, 7, 15, 43, 65, 183, 407, 123, 1151, 375, 3461, 6673, 12985, 21005}},
-{3816, 16, 2564, {1, 3, 7, 7, 9, 1, 87, 247, 489, 123, 1677, 1947, 7961, 13497, 27919, 28993}},
-{3817, 16, 2573, {1, 3, 3, 7, 19, 21, 95, 227, 217, 133, 69, 1535, 699, 3521, 29255, 34733}},
-{3818, 16, 2598, {1, 3, 5, 3, 7, 57, 45, 251, 407, 81, 1259, 2425, 2217, 13097, 12773, 14643}},
-{3819, 16, 2627, {1, 1, 1, 11, 23, 37, 13, 229, 467, 591, 1521, 469, 3763, 2289, 14233, 24053}},
-{3820, 16, 2633, {1, 3, 5, 1, 27, 53, 105, 5, 85, 765, 1973, 2597, 5725, 1063, 18145, 961}},
-{3821, 16, 2647, {1, 3, 7, 1, 21, 47, 115, 95, 403, 3, 1593, 3379, 7371, 15553, 12503, 57979}},
-{3822, 16, 2660, {1, 1, 3, 1, 1, 35, 121, 29, 379, 245, 919, 2673, 3503, 14197, 31193, 8355}},
-{3823, 16, 2664, {1, 3, 5, 11, 19, 49, 97, 7, 195, 1013, 1671, 3415, 2009, 13389, 4837, 27453}},
-{3824, 16, 2678, {1, 1, 5, 13, 9, 15, 115, 97, 463, 449, 303, 2681, 1215, 12559, 15685, 21321}},
-{3825, 16, 2684, {1, 3, 5, 13, 23, 5, 113, 193, 419, 301, 1121, 317, 5503, 4683, 25519, 65}},
-{3826, 16, 2691, {1, 3, 3, 7, 15, 29, 45, 97, 323, 475, 143, 1173, 4033, 8939, 31849, 3575}},
-{3827, 16, 2759, {1, 1, 7, 7, 21, 1, 101, 143, 197, 409, 855, 1753, 5211, 3763, 11139, 37309}},
-{3828, 16, 2768, {1, 1, 3, 13, 25, 33, 55, 45, 381, 349, 991, 535, 4823, 3701, 31629, 48037}},
-{3829, 16, 2773, {1, 3, 1, 11, 17, 51, 27, 57, 409, 551, 949, 365, 8093, 10831, 19697, 39437}},
-{3830, 16, 2794, {1, 3, 5, 3, 31, 33, 81, 49, 91, 865, 469, 2115, 377, 8237, 31907, 38239}},
-{3831, 16, 2813, {1, 1, 3, 7, 29, 59, 57, 17, 121, 889, 1557, 1797, 5001, 14209, 21355, 59739}},
-{3832, 16, 2831, {1, 1, 5, 9, 11, 45, 89, 87, 397, 785, 525, 1593, 5251, 12449, 23579, 54265}},
-{3833, 16, 2843, {1, 3, 5, 11, 5, 31, 19, 47, 207, 331, 91, 1691, 5171, 53, 15945, 33349}},
-{3834, 16, 2846, {1, 1, 1, 15, 11, 41, 91, 177, 505, 871, 815, 3673, 5631, 9915, 1133, 37861}},
-{3835, 16, 2849, {1, 3, 5, 5, 25, 63, 53, 231, 55, 51, 481, 303, 1859, 11973, 28557, 22045}},
-{3836, 16, 2856, {1, 1, 5, 3, 27, 11, 37, 91, 363, 411, 1131, 3369, 377, 6585, 7353, 42949}},
-{3837, 16, 2893, {1, 3, 1, 9, 31, 63, 83, 23, 405, 941, 119, 1471, 2509, 15507, 29239, 49613}},
-{3838, 16, 2901, {1, 1, 5, 1, 11, 63, 117, 237, 407, 231, 1425, 71, 8005, 4023, 9029, 59819}},
-{3839, 16, 2924, {1, 1, 5, 7, 1, 9, 43, 87, 351, 63, 1075, 3381, 5447, 2437, 24983, 26905}},
-{3840, 16, 2942, {1, 3, 7, 5, 5, 35, 33, 89, 251, 819, 1735, 2625, 6363, 6837, 27603, 26669}},
-{3841, 16, 2975, {1, 3, 7, 13, 29, 63, 51, 245, 371, 791, 907, 3499, 3033, 8443, 20023, 1805}},
-{3842, 16, 2979, {1, 1, 5, 7, 13, 15, 109, 197, 451, 709, 929, 3193, 5727, 11185, 29479, 1671}},
-{3843, 16, 2985, {1, 1, 7, 13, 19, 23, 97, 9, 359, 635, 777, 39, 893, 2531, 13563, 19295}},
-{3844, 16, 3020, {1, 1, 5, 1, 31, 63, 55, 7, 157, 877, 991, 1317, 1595, 2019, 21435, 52255}},
-{3845, 16, 3025, {1, 1, 5, 3, 19, 37, 23, 13, 335, 431, 483, 615, 2431, 505, 26245, 63323}},
-{3846, 16, 3028, {1, 3, 7, 5, 5, 9, 37, 65, 303, 423, 1907, 2661, 7213, 2975, 29045, 16243}},
-{3847, 16, 3051, {1, 3, 1, 5, 13, 37, 115, 217, 227, 159, 707, 1387, 943, 4935, 5503, 35171}},
-{3848, 16, 3127, {1, 3, 7, 9, 19, 15, 87, 233, 453, 159, 169, 1077, 2129, 413, 19773, 629}},
-{3849, 16, 3142, {1, 1, 5, 15, 29, 39, 37, 243, 233, 365, 1843, 2219, 1255, 15287, 603, 13511}},
-{3850, 16, 3145, {1, 1, 3, 3, 31, 53, 33, 125, 497, 597, 127, 1829, 3905, 2611, 4263, 40971}},
-{3851, 16, 3156, {1, 3, 5, 9, 11, 47, 71, 215, 383, 321, 1445, 135, 5953, 8791, 22073, 16537}},
-{3852, 16, 3165, {1, 3, 3, 13, 15, 7, 7, 133, 401, 459, 1117, 3165, 4105, 11943, 22431, 56821}},
-{3853, 16, 3196, {1, 1, 7, 9, 31, 39, 19, 7, 19, 401, 79, 3641, 6815, 1489, 7537, 49467}},
-{3854, 16, 3199, {1, 3, 7, 7, 17, 11, 91, 205, 251, 321, 515, 3521, 311, 3169, 271, 34749}},
-{3855, 16, 3217, {1, 3, 3, 7, 29, 15, 5, 153, 83, 603, 1373, 997, 4939, 9811, 243, 5375}},
-{3856, 16, 3218, {1, 1, 3, 11, 21, 47, 25, 221, 237, 177, 535, 2819, 6213, 7877, 26795, 36609}},
-{3857, 16, 3253, {1, 3, 7, 3, 31, 1, 69, 73, 47, 653, 139, 1649, 7183, 1293, 26507, 38415}},
-{3858, 16, 3258, {1, 1, 1, 13, 17, 41, 23, 73, 115, 509, 787, 3733, 1871, 171, 29967, 39941}},
-{3859, 16, 3260, {1, 3, 5, 1, 9, 7, 61, 23, 105, 381, 1421, 2887, 3717, 643, 26375, 57991}},
-{3860, 16, 3289, {1, 3, 3, 3, 19, 3, 101, 117, 393, 83, 1255, 3331, 6481, 8661, 20855, 28875}},
-{3861, 16, 3314, {1, 3, 5, 11, 21, 13, 111, 193, 51, 899, 159, 1989, 7931, 10511, 3933, 447}},
-{3862, 16, 3326, {1, 1, 5, 15, 23, 35, 49, 139, 397, 145, 597, 1847, 7077, 715, 20227, 42183}},
-{3863, 16, 3331, {1, 3, 3, 3, 17, 3, 87, 233, 35, 317, 337, 237, 6901, 3439, 20033, 10307}},
-{3864, 16, 3371, {1, 3, 5, 3, 11, 35, 13, 171, 7, 963, 1443, 1501, 7617, 963, 25453, 62589}},
-{3865, 16, 3381, {1, 1, 1, 5, 11, 9, 39, 175, 409, 411, 1407, 2743, 4255, 989, 15823, 1707}},
-{3866, 16, 3396, {1, 1, 7, 13, 27, 55, 63, 239, 355, 417, 2007, 2299, 2921, 1637, 10687, 60615}},
-{3867, 16, 3441, {1, 1, 7, 9, 5, 61, 57, 73, 263, 307, 2003, 1763, 639, 5885, 14709, 16985}},
-{3868, 16, 3442, {1, 1, 3, 3, 21, 55, 19, 249, 509, 533, 1361, 1397, 2777, 15523, 4389, 13339}},
-{3869, 16, 3460, {1, 3, 5, 15, 9, 3, 91, 237, 451, 299, 1541, 4083, 879, 7859, 21585, 14833}},
-{3870, 16, 3477, {1, 1, 7, 3, 31, 47, 49, 231, 123, 391, 1633, 2567, 5577, 1631, 27951, 22913}},
-{3871, 16, 3491, {1, 3, 7, 13, 11, 13, 1, 111, 183, 87, 839, 1915, 5523, 3677, 13065, 38225}},
-{3872, 16, 3493, {1, 1, 3, 7, 15, 15, 63, 241, 167, 345, 653, 701, 4725, 12911, 11545, 24475}},
-{3873, 16, 3543, {1, 1, 3, 7, 25, 15, 49, 235, 331, 639, 965, 1117, 7147, 3789, 3309, 20255}},
-{3874, 16, 3549, {1, 3, 5, 7, 7, 63, 93, 241, 253, 31, 951, 3723, 3359, 7303, 191, 36427}},
-{3875, 16, 3550, {1, 3, 7, 9, 9, 59, 5, 107, 181, 413, 1269, 3121, 1929, 11921, 8931, 47459}},
-{3876, 16, 3553, {1, 3, 1, 15, 25, 27, 13, 47, 295, 111, 1287, 2551, 4887, 4145, 17063, 42037}},
-{3877, 16, 3563, {1, 3, 3, 13, 17, 17, 21, 17, 491, 845, 1463, 1305, 1375, 16149, 19331, 25043}},
-{3878, 16, 3568, {1, 3, 5, 1, 27, 5, 93, 139, 283, 711, 1141, 1743, 5001, 8851, 19351, 12275}},
-{3879, 16, 3604, {1, 1, 1, 1, 23, 25, 51, 63, 429, 735, 201, 3785, 6677, 16375, 19681, 17857}},
-{3880, 16, 3632, {1, 3, 3, 3, 9, 63, 71, 147, 463, 465, 1163, 1045, 6967, 12537, 31853, 38391}},
-{3881, 16, 3650, {1, 3, 7, 1, 5, 51, 79, 239, 389, 3, 601, 3787, 7635, 16295, 1681, 63971}},
-{3882, 16, 3662, {1, 3, 1, 3, 5, 31, 103, 89, 321, 971, 783, 3685, 1155, 10353, 2167, 35423}},
-{3883, 16, 3674, {1, 1, 5, 15, 25, 19, 93, 59, 361, 217, 1141, 597, 5877, 15961, 1593, 22925}},
-{3884, 16, 3685, {1, 3, 1, 9, 25, 59, 69, 89, 477, 89, 487, 237, 5625, 9579, 30421, 21883}},
-{3885, 16, 3686, {1, 1, 3, 7, 1, 5, 13, 225, 9, 981, 1081, 1407, 6855, 15215, 21713, 62313}},
-{3886, 16, 3700, {1, 1, 7, 15, 11, 13, 119, 109, 151, 245, 1195, 3741, 755, 8047, 15431, 21001}},
-{3887, 16, 3703, {1, 3, 7, 3, 17, 47, 107, 137, 99, 255, 1597, 3281, 5779, 13487, 15061, 19199}},
-{3888, 16, 3704, {1, 1, 3, 3, 9, 39, 77, 227, 511, 839, 1375, 3887, 25, 14763, 13259, 217}},
-{3889, 16, 3723, {1, 3, 5, 7, 17, 3, 87, 61, 439, 287, 709, 4085, 4251, 8945, 28203, 24011}},
-{3890, 16, 3743, {1, 3, 1, 1, 29, 25, 49, 101, 209, 359, 285, 1593, 4161, 2943, 23225, 6381}},
-{3891, 16, 3753, {1, 1, 3, 13, 1, 45, 87, 7, 491, 399, 905, 1403, 4791, 7419, 14355, 47767}},
-{3892, 16, 3756, {1, 1, 7, 15, 13, 25, 111, 197, 297, 301, 499, 4007, 2235, 7681, 4641, 32447}},
-{3893, 16, 3759, {1, 1, 3, 3, 27, 41, 97, 83, 405, 353, 1609, 201, 1503, 10673, 29377, 20445}},
-{3894, 16, 3762, {1, 1, 7, 3, 9, 47, 65, 191, 207, 545, 377, 3011, 7361, 3467, 14073, 46769}},
-{3895, 16, 3771, {1, 1, 7, 5, 7, 39, 9, 91, 187, 949, 1829, 161, 3689, 4145, 32675, 23263}},
-{3896, 16, 3776, {1, 1, 5, 9, 29, 9, 83, 113, 77, 673, 613, 3645, 6671, 8583, 27701, 18615}},
-{3897, 16, 3779, {1, 3, 5, 9, 29, 13, 127, 247, 285, 845, 463, 539, 4441, 1867, 12469, 16213}},
-{3898, 16, 3839, {1, 3, 7, 15, 1, 29, 47, 157, 239, 595, 563, 1103, 3431, 2849, 28125, 19969}},
-{3899, 16, 3856, {1, 1, 1, 15, 25, 13, 1, 131, 57, 257, 2021, 169, 7603, 10721, 21675, 63171}},
-{3900, 16, 3871, {1, 3, 5, 3, 5, 19, 31, 57, 275, 381, 775, 681, 1145, 12237, 5141, 29375}},
-{3901, 16, 3887, {1, 3, 5, 13, 27, 13, 47, 201, 267, 581, 1563, 3845, 951, 7209, 27253, 19755}},
-{3902, 16, 3896, {1, 3, 5, 15, 19, 35, 57, 17, 61, 273, 967, 3029, 1747, 1753, 31321, 23711}},
-{3903, 16, 3901, {1, 1, 1, 5, 13, 13, 7, 177, 335, 393, 1401, 1411, 4703, 8259, 1281, 39835}},
-{3904, 16, 3916, {1, 1, 3, 15, 25, 27, 27, 121, 183, 105, 663, 1375, 6987, 7151, 13763, 39323}},
-{3905, 16, 3919, {1, 3, 7, 5, 15, 1, 81, 129, 455, 163, 675, 81, 3735, 14409, 7269, 16425}},
-{3906, 16, 3937, {1, 3, 3, 11, 13, 7, 79, 157, 165, 663, 229, 3539, 1837, 6485, 30729, 42157}},
-{3907, 16, 3943, {1, 1, 5, 15, 9, 9, 9, 47, 133, 863, 43, 1461, 511, 13991, 24781, 19221}},
-{3908, 16, 3955, {1, 3, 1, 7, 31, 33, 103, 13, 159, 689, 1353, 4025, 6051, 7683, 1741, 30047}},
-{3909, 16, 3961, {1, 1, 3, 11, 5, 45, 71, 219, 475, 585, 1207, 3163, 4661, 4713, 12729, 30445}},
-{3910, 16, 3988, {1, 3, 7, 5, 5, 53, 101, 227, 129, 521, 91, 1129, 4683, 11235, 24697, 45055}},
-{3911, 16, 3997, {1, 1, 3, 13, 1, 43, 7, 1, 73, 857, 1713, 185, 1685, 2369, 24187, 40419}},
-{3912, 16, 4011, {1, 1, 7, 7, 21, 7, 13, 177, 503, 1003, 1091, 2411, 1433, 9063, 13901, 3329}},
-{3913, 16, 4026, {1, 1, 7, 1, 7, 41, 99, 203, 325, 249, 1763, 545, 2981, 14125, 7815, 11385}},
-{3914, 16, 4033, {1, 3, 7, 11, 3, 11, 95, 137, 325, 701, 1177, 1631, 4483, 2955, 30229, 25577}},
-{3915, 16, 4045, {1, 1, 7, 7, 17, 45, 77, 103, 143, 97, 1963, 3635, 1539, 10491, 23483, 22767}},
-{3916, 16, 4060, {1, 1, 7, 15, 7, 5, 81, 63, 243, 55, 39, 207, 2315, 8285, 8155, 11631}},
-{3917, 16, 4063, {1, 3, 5, 15, 23, 19, 115, 9, 125, 851, 161, 3767, 3513, 1855, 11139, 1719}},
-{3918, 16, 4064, {1, 3, 7, 11, 11, 23, 15, 13, 235, 5, 1039, 1425, 6485, 5539, 8967, 64809}},
-{3919, 16, 4126, {1, 3, 5, 7, 19, 11, 83, 135, 45, 905, 1081, 1857, 3185, 13555, 21365, 38143}},
-{3920, 16, 4136, {1, 1, 5, 1, 25, 27, 119, 109, 167, 847, 1539, 2653, 797, 11185, 23501, 22389}},
-{3921, 16, 4167, {1, 1, 7, 7, 11, 3, 51, 97, 277, 557, 207, 3645, 825, 8521, 26653, 60071}},
-{3922, 16, 4173, {1, 3, 3, 15, 17, 35, 57, 7, 267, 549, 97, 243, 1137, 10311, 6737, 19077}},
-{3923, 16, 4188, {1, 1, 1, 15, 23, 33, 27, 203, 415, 1023, 1145, 1881, 7715, 4413, 3727, 5185}},
-{3924, 16, 4195, {1, 1, 3, 3, 13, 47, 63, 13, 75, 505, 595, 2911, 4029, 14187, 23151, 42877}},
-{3925, 16, 4226, {1, 1, 5, 15, 23, 5, 11, 65, 147, 675, 1961, 2177, 727, 15077, 23759, 10195}},
-{3926, 16, 4291, {1, 3, 5, 9, 9, 39, 69, 229, 341, 627, 1331, 3139, 3921, 9219, 14887, 4659}},
-{3927, 16, 4298, {1, 1, 7, 3, 1, 35, 49, 71, 165, 83, 719, 2771, 6475, 7821, 16709, 4449}},
-{3928, 16, 4308, {1, 3, 5, 5, 23, 15, 3, 57, 465, 77, 121, 3767, 6841, 13601, 12035, 14075}},
-{3929, 16, 4312, {1, 1, 7, 3, 3, 23, 45, 131, 287, 941, 713, 415, 6865, 14209, 29555, 55493}},
-{3930, 16, 4336, {1, 3, 5, 11, 29, 35, 55, 75, 225, 779, 569, 1795, 1377, 12765, 19081, 47287}},
-{3931, 16, 4371, {1, 3, 7, 3, 31, 47, 127, 89, 157, 737, 1395, 3615, 7923, 14731, 15797, 40061}},
-{3932, 16, 4378, {1, 1, 1, 11, 21, 37, 21, 59, 9, 141, 193, 3095, 3435, 12371, 26931, 61861}},
-{3933, 16, 4384, {1, 1, 3, 7, 13, 51, 15, 153, 77, 1013, 651, 3949, 6229, 14297, 1039, 46139}},
-{3934, 16, 4393, {1, 3, 3, 13, 7, 43, 95, 61, 217, 3, 549, 739, 123, 3661, 15375, 13919}},
-{3935, 16, 4421, {1, 3, 5, 9, 13, 37, 101, 89, 55, 413, 1089, 775, 7575, 13063, 31393, 29583}},
-{3936, 16, 4425, {1, 1, 3, 9, 25, 63, 119, 143, 499, 145, 603, 2067, 4713, 13457, 14053, 117}},
-{3937, 16, 4439, {1, 1, 5, 9, 7, 23, 57, 253, 115, 591, 2003, 63, 7615, 11493, 28519, 47087}},
-{3938, 16, 4440, {1, 1, 7, 3, 7, 53, 121, 33, 233, 645, 1093, 1697, 7213, 2603, 10743, 51303}},
-{3939, 16, 4500, {1, 3, 5, 7, 13, 31, 17, 125, 93, 969, 159, 1529, 7165, 7371, 8707, 56953}},
-{3940, 16, 4514, {1, 3, 3, 1, 13, 9, 91, 25, 171, 843, 1635, 2043, 1043, 15893, 11409, 53689}},
-{3941, 16, 4523, {1, 3, 5, 7, 13, 19, 89, 97, 203, 923, 1109, 2061, 463, 11703, 8925, 56015}},
-{3942, 16, 4534, {1, 3, 5, 11, 5, 21, 79, 237, 195, 649, 717, 211, 919, 12855, 3045, 39659}},
-{3943, 16, 4593, {1, 1, 1, 15, 13, 19, 21, 69, 393, 257, 1263, 309, 3209, 8403, 24467, 6467}},
-{3944, 16, 4615, {1, 1, 1, 11, 7, 27, 59, 117, 379, 353, 943, 2513, 3869, 4567, 12989, 13139}},
-{3945, 16, 4630, {1, 1, 1, 3, 13, 43, 11, 15, 149, 237, 1555, 71, 2357, 15773, 21419, 40571}},
-{3946, 16, 4636, {1, 3, 1, 9, 19, 23, 59, 215, 15, 921, 1729, 249, 3785, 7171, 1233, 3449}},
-{3947, 16, 4645, {1, 1, 1, 7, 7, 37, 63, 205, 75, 599, 951, 2513, 3347, 2497, 8019, 5433}},
-{3948, 16, 4684, {1, 3, 3, 15, 27, 17, 25, 201, 23, 699, 1525, 465, 1115, 12299, 14747, 40363}},
-{3949, 16, 4687, {1, 1, 1, 3, 29, 59, 115, 233, 107, 815, 291, 3821, 7325, 7381, 21445, 33917}},
-{3950, 16, 4723, {1, 3, 1, 11, 11, 33, 107, 171, 421, 893, 587, 3373, 4101, 3885, 25383, 12035}},
-{3951, 16, 4735, {1, 3, 3, 7, 5, 23, 43, 51, 357, 77, 1327, 2995, 1321, 1571, 26419, 23603}},
-{3952, 16, 4746, {1, 3, 7, 9, 27, 57, 101, 51, 215, 215, 469, 303, 723, 2903, 30569, 42631}},
-{3953, 16, 4779, {1, 3, 3, 13, 1, 7, 63, 205, 143, 321, 1439, 253, 2667, 1271, 11761, 55631}},
-{3954, 16, 4782, {1, 1, 7, 9, 3, 7, 7, 15, 503, 875, 1619, 1715, 5047, 5665, 5503, 17745}},
-{3955, 16, 4793, {1, 1, 7, 15, 19, 49, 65, 31, 245, 371, 377, 2963, 6185, 5519, 10743, 33231}},
-{3956, 16, 4796, {1, 1, 7, 3, 25, 27, 115, 51, 299, 451, 285, 1709, 6153, 14881, 17861, 22071}},
-{3957, 16, 4813, {1, 3, 1, 5, 21, 21, 127, 185, 325, 995, 213, 3279, 4769, 15943, 2589, 29567}},
-{3958, 16, 4850, {1, 3, 7, 5, 21, 9, 63, 59, 159, 743, 663, 2965, 97, 8993, 25633, 29033}},
-{3959, 16, 4867, {1, 3, 7, 13, 3, 35, 59, 101, 21, 659, 1531, 3995, 795, 2143, 21749, 52715}},
-{3960, 16, 4874, {1, 3, 3, 15, 27, 29, 95, 1, 501, 425, 417, 2351, 7877, 4127, 3633, 23347}},
-{3961, 16, 4881, {1, 3, 5, 7, 7, 49, 55, 19, 329, 467, 425, 1609, 6987, 16123, 26879, 42883}},
-{3962, 16, 4894, {1, 1, 1, 15, 17, 21, 13, 13, 85, 7, 677, 3739, 5491, 6299, 29957, 55765}},
-{3963, 16, 4904, {1, 1, 1, 7, 31, 21, 1, 5, 193, 659, 979, 3409, 3151, 6615, 7445, 8151}},
-{3964, 16, 4927, {1, 3, 1, 1, 11, 61, 27, 205, 263, 805, 955, 3469, 1233, 1609, 15329, 13353}},
-{3965, 16, 4929, {1, 3, 3, 9, 3, 29, 59, 75, 149, 557, 663, 3887, 3369, 3397, 10611, 9511}},
-{3966, 16, 4989, {1, 1, 7, 13, 29, 21, 101, 139, 99, 411, 569, 2343, 6901, 1685, 20599, 49543}},
-{3967, 16, 5000, {1, 3, 3, 15, 11, 3, 87, 89, 5, 293, 291, 1405, 1489, 9877, 32505, 32263}},
-{3968, 16, 5020, {1, 1, 5, 5, 19, 45, 89, 5, 381, 253, 1339, 707, 4645, 14177, 29441, 8965}},
-{3969, 16, 5036, {1, 3, 7, 15, 27, 45, 25, 177, 81, 229, 1339, 2143, 6547, 6841, 23449, 14813}},
-{3970, 16, 5041, {1, 1, 1, 3, 27, 23, 81, 157, 53, 513, 1435, 277, 2353, 3545, 21461, 51479}},
-{3971, 16, 5059, {1, 3, 1, 3, 3, 17, 75, 139, 283, 881, 1157, 2081, 937, 14549, 10215, 13053}},
-{3972, 16, 5074, {1, 1, 7, 9, 25, 27, 27, 133, 21, 559, 225, 613, 6931, 11785, 23413, 35757}},
-{3973, 16, 5090, {1, 1, 3, 13, 19, 9, 65, 49, 453, 779, 621, 1151, 1807, 13269, 6515, 17113}},
-{3974, 16, 5110, {1, 1, 1, 13, 21, 49, 39, 79, 119, 401, 903, 493, 3779, 7389, 29425, 28091}},
-{3975, 16, 5134, {1, 3, 1, 3, 23, 57, 59, 213, 463, 839, 1201, 1951, 5197, 13035, 29657, 35517}},
-{3976, 16, 5152, {1, 3, 7, 7, 3, 49, 29, 181, 367, 101, 1277, 3329, 3563, 10373, 29757, 62555}},
-{3977, 16, 5176, {1, 3, 1, 7, 31, 31, 117, 213, 373, 57, 1095, 2733, 3431, 3915, 7665, 44459}},
-{3978, 16, 5181, {1, 1, 7, 5, 9, 25, 47, 117, 355, 495, 1367, 2579, 5617, 787, 27655, 18885}},
-{3979, 16, 5204, {1, 1, 1, 3, 9, 39, 113, 87, 107, 477, 891, 2273, 4239, 7521, 147, 1737}},
-{3980, 16, 5218, {1, 1, 1, 3, 13, 61, 81, 225, 113, 441, 889, 1915, 3897, 15179, 4053, 5925}},
-{3981, 16, 5242, {1, 1, 5, 3, 15, 47, 59, 187, 475, 197, 1381, 33, 4605, 1487, 14359, 33769}},
-{3982, 16, 5253, {1, 3, 7, 15, 23, 45, 53, 215, 129, 465, 795, 53, 7077, 9517, 2663, 55397}},
-{3983, 16, 5260, {1, 1, 7, 13, 25, 49, 105, 255, 245, 153, 1093, 2123, 2823, 5125, 17483, 49003}},
-{3984, 16, 5281, {1, 1, 1, 13, 31, 5, 7, 243, 255, 231, 1663, 1007, 7573, 405, 29183, 11367}},
-{3985, 16, 5282, {1, 1, 5, 13, 15, 15, 115, 91, 63, 1013, 1713, 1945, 6397, 14213, 24417, 40807}},
-{3986, 16, 5313, {1, 1, 5, 3, 19, 49, 91, 25, 43, 601, 25, 2405, 1973, 629, 497, 12625}},
-{3987, 16, 5316, {1, 1, 3, 5, 13, 45, 11, 81, 251, 545, 1155, 1409, 7187, 847, 2835, 32909}},
-{3988, 16, 5326, {1, 3, 1, 13, 27, 57, 1, 103, 465, 809, 1727, 3721, 3347, 3791, 17247, 8377}},
-{3989, 16, 5340, {1, 3, 3, 15, 25, 31, 91, 91, 119, 205, 1431, 703, 5327, 7323, 30415, 61955}},
-{3990, 16, 5347, {1, 3, 5, 11, 19, 39, 79, 243, 109, 463, 1869, 2133, 4139, 10461, 14793, 24025}},
-{3991, 16, 5354, {1, 3, 5, 7, 23, 41, 5, 7, 249, 3, 1743, 489, 4921, 397, 30955, 22207}},
-{3992, 16, 5368, {1, 3, 5, 15, 3, 7, 115, 19, 217, 231, 1183, 3723, 5055, 12967, 7855, 5067}},
-{3993, 16, 5394, {1, 3, 3, 3, 11, 31, 113, 41, 429, 797, 557, 1199, 1819, 1933, 9917, 32229}},
-{3994, 16, 5396, {1, 1, 5, 3, 13, 63, 31, 183, 465, 915, 723, 3227, 4125, 2813, 26313, 34287}},
-{3995, 16, 5400, {1, 1, 7, 5, 31, 55, 117, 243, 37, 885, 85, 1067, 3895, 15655, 28527, 32109}},
-{3996, 16, 5405, {1, 3, 7, 15, 17, 43, 43, 173, 119, 187, 1161, 599, 4595, 1681, 11981, 681}},
-{3997, 16, 5439, {1, 1, 7, 7, 29, 47, 25, 93, 411, 103, 783, 1029, 1927, 3569, 27647, 8281}},
-{3998, 16, 5442, {1, 3, 3, 9, 19, 57, 31, 183, 141, 889, 157, 2267, 5701, 6273, 25739, 34039}},
-{3999, 16, 5459, {1, 3, 5, 1, 29, 35, 105, 165, 505, 299, 1149, 2397, 2013, 11591, 15917, 4791}},
-{4000, 16, 5478, {1, 3, 3, 9, 7, 35, 47, 77, 69, 335, 585, 1131, 531, 8597, 307, 55985}},
-{4001, 16, 5484, {1, 3, 7, 1, 29, 9, 25, 155, 149, 845, 567, 3735, 3501, 9365, 12025, 19131}},
-{4002, 16, 5508, {1, 3, 5, 3, 11, 31, 25, 9, 411, 519, 1611, 1441, 1487, 10049, 14373, 24605}},
-{4003, 16, 5523, {1, 3, 3, 5, 3, 7, 101, 107, 339, 155, 1843, 2529, 443, 8177, 28655, 8151}},
-{4004, 16, 5545, {1, 1, 7, 5, 29, 37, 73, 131, 125, 451, 947, 797, 5053, 10155, 30801, 27235}},
-{4005, 16, 5565, {1, 1, 7, 13, 19, 47, 101, 45, 495, 457, 1293, 1971, 5495, 12737, 17687, 26123}},
-{4006, 16, 5566, {1, 1, 7, 7, 11, 11, 75, 177, 251, 553, 1883, 3379, 1429, 12227, 10301, 16467}},
-{4007, 16, 5580, {1, 3, 3, 9, 3, 61, 95, 35, 97, 551, 233, 2045, 4873, 9109, 10019, 64523}},
-{4008, 16, 5608, {1, 3, 1, 5, 11, 3, 15, 177, 301, 573, 2029, 191, 5551, 12083, 27287, 57235}},
-{4009, 16, 5613, {1, 3, 5, 1, 21, 9, 121, 169, 347, 187, 57, 3163, 5609, 1921, 17581, 28351}},
-{4010, 16, 5647, {1, 3, 3, 1, 31, 51, 15, 45, 429, 245, 573, 1595, 5343, 7519, 17009, 1299}},
-{4011, 16, 5661, {1, 1, 7, 3, 13, 47, 109, 65, 389, 867, 963, 145, 1089, 9749, 19625, 43121}},
-{4012, 16, 5671, {1, 3, 1, 7, 21, 61, 77, 67, 143, 579, 625, 2007, 6343, 4259, 21233, 237}},
-{4013, 16, 5678, {1, 3, 5, 9, 27, 15, 107, 91, 399, 895, 645, 2301, 439, 6789, 18299, 47285}},
-{4014, 16, 5680, {1, 3, 3, 5, 13, 11, 43, 199, 505, 409, 25, 2057, 479, 6031, 9561, 51613}},
-{4015, 16, 5685, {1, 1, 7, 13, 15, 55, 105, 53, 171, 925, 1849, 2881, 6951, 13069, 865, 41019}},
-{4016, 16, 5689, {1, 3, 1, 9, 17, 31, 45, 23, 411, 185, 189, 2123, 2583, 12713, 12681, 2231}},
-{4017, 16, 5692, {1, 3, 7, 9, 3, 63, 11, 253, 177, 127, 545, 3293, 4449, 15995, 10223, 33529}},
-{4018, 16, 5724, {1, 1, 5, 11, 13, 7, 53, 161, 421, 551, 697, 627, 3879, 1639, 24419, 3337}},
-{4019, 16, 5745, {1, 1, 7, 7, 27, 7, 37, 205, 429, 407, 1133, 3563, 2921, 6173, 11173, 3009}},
-{4020, 16, 5755, {1, 3, 3, 15, 31, 39, 117, 81, 337, 729, 567, 2299, 1481, 3189, 1795, 40299}},
-{4021, 16, 5757, {1, 3, 5, 15, 15, 47, 91, 127, 275, 55, 951, 3423, 2879, 6115, 1549, 2287}},
-{4022, 16, 5786, {1, 3, 3, 11, 17, 3, 127, 207, 141, 889, 185, 1095, 4567, 1371, 30545, 54445}},
-{4023, 16, 5792, {1, 1, 7, 3, 25, 11, 11, 139, 43, 1, 1977, 397, 5775, 6913, 13249, 46767}},
-{4024, 16, 5810, {1, 1, 7, 7, 27, 13, 31, 251, 191, 1015, 161, 3719, 5321, 13013, 25187, 51881}},
-{4025, 16, 5824, {1, 1, 1, 1, 3, 3, 13, 19, 423, 349, 1955, 2103, 6395, 3315, 23809, 25925}},
-{4026, 16, 5869, {1, 3, 5, 13, 3, 59, 41, 167, 423, 93, 1299, 2623, 5829, 8537, 8701, 43757}},
-{4027, 16, 5872, {1, 3, 5, 11, 9, 19, 127, 119, 329, 819, 7, 3809, 5305, 3643, 27369, 61827}},
-{4028, 16, 5895, {1, 3, 1, 15, 25, 43, 55, 159, 205, 911, 983, 2825, 3751, 7845, 12023, 18431}},
-{4029, 16, 5923, {1, 3, 3, 13, 11, 1, 65, 133, 479, 181, 679, 981, 3317, 6241, 11693, 9619}},
-{4030, 16, 5925, {1, 3, 3, 3, 21, 25, 117, 183, 127, 73, 703, 1469, 257, 11229, 10167, 50847}},
-{4031, 16, 5926, {1, 1, 5, 13, 5, 5, 113, 15, 231, 269, 989, 465, 3267, 15239, 29503, 42855}},
-{4032, 16, 5944, {1, 3, 3, 15, 9, 63, 79, 27, 21, 709, 1969, 3761, 1015, 13619, 4205, 40591}},
-{4033, 16, 5986, {1, 1, 7, 11, 29, 3, 5, 45, 107, 131, 1287, 3551, 849, 2003, 27451, 47103}},
-{4034, 16, 6012, {1, 3, 5, 11, 3, 47, 59, 53, 369, 249, 915, 2475, 7539, 763, 7063, 63971}},
-{4035, 16, 6015, {1, 1, 5, 1, 7, 53, 45, 127, 321, 341, 635, 2277, 1383, 10951, 29055, 45087}},
-{4036, 16, 6046, {1, 3, 7, 3, 5, 1, 119, 79, 487, 93, 25, 491, 4085, 6403, 27779, 8753}},
-{4037, 16, 6049, {1, 1, 1, 3, 9, 59, 49, 141, 323, 703, 1175, 423, 4323, 10083, 4289, 28931}},
-{4038, 16, 6061, {1, 3, 3, 15, 31, 31, 73, 15, 187, 653, 91, 1707, 1431, 9861, 19071, 8137}},
-{4039, 16, 6067, {1, 1, 1, 5, 27, 63, 93, 1, 329, 353, 863, 473, 7681, 10653, 15819, 8495}},
-{4040, 16, 6099, {1, 1, 1, 5, 25, 57, 119, 167, 219, 319, 231, 1065, 6217, 5131, 1513, 49281}},
-{4041, 16, 6121, {1, 3, 7, 3, 17, 3, 113, 91, 201, 179, 1907, 3423, 821, 12927, 24827, 49403}},
-{4042, 16, 6155, {1, 1, 5, 7, 19, 63, 75, 151, 387, 489, 777, 2049, 1151, 1351, 25687, 4143}},
-{4043, 16, 6163, {1, 3, 5, 7, 9, 37, 9, 3, 87, 385, 1667, 2139, 7527, 16133, 30023, 28783}},
-{4044, 16, 6203, {1, 1, 5, 9, 11, 55, 95, 73, 413, 867, 589, 2901, 3021, 413, 5955, 38921}},
-{4045, 16, 6208, {1, 3, 5, 15, 1, 17, 17, 7, 485, 323, 519, 2325, 2255, 4211, 20661, 28931}},
-{4046, 16, 6231, {1, 1, 5, 13, 21, 19, 85, 189, 167, 645, 1475, 3095, 7123, 3351, 7961, 20967}},
-{4047, 16, 6241, {1, 1, 7, 13, 3, 47, 13, 213, 237, 291, 285, 1465, 1765, 12361, 32651, 54205}},
-{4048, 16, 6254, {1, 3, 7, 13, 13, 27, 71, 35, 67, 117, 647, 2359, 3295, 8445, 24761, 29379}},
-{4049, 16, 6262, {1, 1, 1, 3, 3, 19, 23, 37, 5, 1019, 5, 1605, 2291, 14015, 9311, 39751}},
-{4050, 16, 6266, {1, 3, 3, 3, 31, 1, 65, 159, 221, 675, 1061, 971, 2333, 8265, 14361, 3263}},
-{4051, 16, 6275, {1, 1, 3, 7, 3, 5, 81, 17, 101, 991, 753, 2883, 4977, 4409, 1757, 26803}},
-{4052, 16, 6278, {1, 1, 5, 9, 13, 25, 45, 43, 199, 967, 829, 713, 4547, 7223, 6497, 53895}},
-{4053, 16, 6292, {1, 1, 7, 5, 23, 15, 89, 179, 509, 147, 315, 133, 111, 15577, 23427, 5229}},
-{4054, 16, 6329, {1, 3, 3, 7, 27, 7, 113, 65, 315, 135, 1309, 1179, 5755, 7513, 6815, 5137}},
-{4055, 16, 6355, {1, 1, 3, 7, 1, 13, 29, 155, 477, 721, 71, 865, 3897, 3331, 30641, 65471}},
-{4056, 16, 6357, {1, 1, 7, 3, 29, 45, 83, 3, 461, 109, 1545, 1365, 6633, 16137, 23859, 5995}},
-{4057, 16, 6374, {1, 3, 1, 1, 3, 33, 77, 83, 459, 187, 879, 3731, 6939, 6707, 23409, 24245}},
-{4058, 16, 6380, {1, 3, 5, 5, 13, 43, 127, 41, 29, 735, 1391, 2947, 4873, 4627, 15, 41719}},
-{4059, 16, 6423, {1, 3, 1, 3, 17, 17, 51, 93, 189, 227, 449, 2809, 825, 2009, 9563, 41435}},
-{4060, 16, 6427, {1, 3, 3, 11, 25, 47, 113, 173, 141, 919, 677, 117, 5293, 815, 23749, 19789}},
-{4061, 16, 6430, {1, 1, 1, 13, 15, 61, 121, 223, 53, 389, 489, 1527, 4771, 8975, 8005, 14275}},
-{4062, 16, 6436, {1, 1, 3, 15, 31, 57, 111, 145, 279, 991, 489, 3239, 7647, 473, 31279, 33447}},
-{4063, 16, 6443, {1, 1, 7, 5, 31, 13, 75, 185, 395, 611, 609, 159, 7931, 9887, 4115, 53121}},
-{4064, 16, 6445, {1, 3, 5, 5, 13, 39, 103, 237, 77, 913, 511, 1583, 6763, 14523, 4247, 63403}},
-{4065, 16, 6458, {1, 1, 1, 15, 11, 5, 43, 43, 297, 827, 747, 5, 3785, 15021, 11291, 36743}},
-{4066, 16, 6478, {1, 1, 7, 9, 9, 53, 113, 95, 403, 53, 1335, 4033, 8147, 11963, 6523, 23675}},
-{4067, 16, 6490, {1, 1, 5, 9, 27, 29, 69, 79, 327, 409, 1147, 1579, 2625, 12227, 30933, 9057}},
-{4068, 16, 6508, {1, 1, 1, 7, 1, 33, 29, 173, 5, 517, 437, 2035, 57, 12825, 22095, 65519}},
-{4069, 16, 6519, {1, 1, 3, 7, 27, 29, 53, 79, 429, 707, 589, 2605, 339, 7039, 19319, 17649}},
-{4070, 16, 6520, {1, 3, 3, 11, 9, 57, 43, 117, 39, 193, 1427, 2553, 6877, 7653, 29041, 44865}},
-{4071, 16, 6530, {1, 3, 3, 7, 23, 45, 29, 151, 265, 739, 365, 3565, 6447, 9761, 24021, 679}},
-{4072, 16, 6541, {1, 3, 5, 1, 1, 43, 73, 55, 131, 175, 959, 659, 7315, 15145, 18301, 14865}},
-{4073, 16, 6556, {1, 1, 3, 5, 15, 15, 91, 113, 359, 241, 1627, 1069, 1761, 211, 32671, 58833}},
-{4074, 16, 6607, {1, 3, 3, 7, 29, 27, 79, 53, 409, 81, 693, 3137, 7385, 11007, 28459, 28621}},
-{4075, 16, 6612, {1, 1, 7, 5, 29, 7, 67, 195, 77, 773, 1361, 2153, 4459, 7301, 5129, 17797}},
-{4076, 16, 6626, {1, 3, 3, 7, 25, 27, 91, 223, 115, 91, 1645, 2167, 1955, 9601, 22127, 13055}},
-{4077, 16, 6632, {1, 3, 7, 3, 27, 53, 67, 249, 51, 151, 663, 3231, 895, 6777, 3037, 56755}},
-{4078, 16, 6649, {1, 1, 5, 1, 25, 63, 71, 179, 375, 301, 1127, 2125, 783, 14481, 7293, 47883}},
-{4079, 16, 6666, {1, 1, 3, 9, 25, 3, 39, 69, 1, 85, 1271, 1571, 1953, 5077, 20369, 44827}},
-{4080, 16, 6674, {1, 3, 1, 13, 11, 61, 77, 59, 127, 475, 1609, 3553, 2553, 15589, 9351, 59787}},
-{4081, 16, 6733, {1, 3, 1, 5, 21, 7, 61, 27, 199, 653, 1243, 2481, 5369, 12903, 30229, 39453}},
-{4082, 16, 6782, {1, 3, 7, 3, 13, 15, 107, 153, 501, 573, 863, 3179, 6019, 15177, 16075, 43767}},
-{4083, 16, 6786, {1, 1, 7, 1, 23, 55, 17, 35, 5, 137, 1707, 1377, 6857, 15361, 27299, 61871}},
-{4084, 16, 6798, {1, 3, 5, 7, 27, 17, 87, 213, 95, 125, 1239, 3923, 4193, 11049, 12783, 45017}},
-{4085, 16, 6821, {1, 1, 5, 15, 9, 55, 11, 217, 7, 249, 369, 205, 4251, 13785, 24781, 48929}},
-{4086, 16, 6840, {1, 3, 7, 1, 15, 35, 33, 107, 503, 563, 1591, 3487, 7495, 1767, 24791, 31281}},
-{4087, 16, 6846, {1, 3, 1, 11, 3, 15, 47, 193, 289, 253, 909, 1105, 5119, 1415, 7737, 4341}},
-{4088, 16, 6865, {1, 1, 1, 3, 23, 33, 53, 187, 469, 573, 835, 2049, 791, 1177, 31051, 30955}},
-{4089, 16, 6884, {1, 3, 3, 11, 15, 51, 77, 143, 369, 991, 1103, 1293, 6019, 6361, 26301, 20741}},
-{4090, 16, 6891, {1, 1, 1, 5, 17, 19, 85, 135, 113, 593, 579, 1063, 7173, 2491, 9355, 19223}},
-{4091, 16, 6925, {1, 1, 5, 15, 25, 51, 107, 193, 31, 1, 1693, 125, 6223, 14619, 22683, 26321}},
-{4092, 16, 6938, {1, 1, 7, 1, 17, 45, 87, 39, 87, 499, 1185, 2763, 3989, 2863, 24555, 33817}},
-{4093, 16, 6967, {1, 3, 1, 11, 31, 5, 121, 231, 185, 793, 255, 2785, 5261, 3687, 21711, 3941}},
-{4094, 16, 6988, {1, 3, 7, 15, 5, 59, 73, 227, 365, 937, 893, 2155, 4385, 14345, 6813, 28461}},
-{4095, 16, 6996, {1, 1, 5, 7, 7, 23, 7, 239, 431, 45, 1015, 1663, 1893, 5035, 24075, 2119}},
-{4096, 16, 7009, {1, 3, 5, 1, 3, 15, 63, 103, 119, 801, 1681, 3463, 6083, 6453, 11379, 8205}},
-{4097, 16, 7016, {1, 3, 7, 9, 21, 61, 9, 9, 433, 541, 603, 3905, 3787, 10187, 3643, 21319}},
-{4098, 16, 7030, {1, 3, 5, 3, 11, 1, 101, 243, 363, 559, 561, 1163, 455, 4657, 1147, 39961}},
-{4099, 16, 7043, {1, 3, 5, 13, 17, 37, 57, 47, 483, 571, 1579, 1137, 8125, 12271, 23279, 1615}},
-{4100, 16, 7045, {1, 3, 5, 1, 21, 5, 13, 155, 75, 705, 389, 2855, 6345, 2279, 12627, 49451}},
-{4101, 16, 7052, {1, 1, 3, 9, 15, 51, 73, 99, 445, 227, 1705, 2175, 8111, 9381, 31555, 48491}},
-{4102, 16, 7073, {1, 3, 3, 5, 9, 63, 107, 51, 461, 979, 1033, 421, 4807, 11707, 13261, 26015}},
-{4103, 16, 7142, {1, 1, 5, 3, 13, 53, 117, 249, 57, 851, 1391, 3245, 35, 16043, 24399, 63667}},
-{4104, 16, 7153, {1, 3, 1, 11, 23, 33, 57, 125, 385, 495, 871, 199, 4269, 2269, 22897, 23597}},
-{4105, 16, 7168, {1, 3, 5, 15, 29, 11, 77, 21, 479, 369, 723, 3721, 1121, 9463, 19775, 54525}},
-{4106, 16, 7174, {1, 3, 5, 7, 7, 45, 29, 153, 395, 223, 1917, 3713, 5087, 10827, 1383, 36823}},
-{4107, 16, 7183, {1, 3, 1, 3, 31, 19, 111, 55, 275, 923, 917, 2925, 673, 6579, 18783, 5137}},
-{4108, 16, 7195, {1, 3, 1, 15, 25, 31, 59, 255, 31, 697, 1751, 381, 299, 295, 14037, 40953}},
-{4109, 16, 7204, {1, 3, 1, 7, 15, 23, 69, 219, 351, 183, 1083, 2227, 6249, 9385, 13167, 2901}},
-{4110, 16, 7214, {1, 3, 7, 1, 5, 61, 117, 13, 67, 521, 41, 2929, 3937, 1215, 25593, 32627}},
-{4111, 16, 7222, {1, 3, 5, 1, 9, 47, 63, 39, 371, 657, 491, 2243, 4049, 10517, 12409, 40597}},
-{4112, 16, 7267, {1, 3, 7, 15, 17, 3, 77, 13, 275, 225, 487, 2055, 1293, 15927, 31773, 18275}},
-{4113, 16, 7269, {1, 1, 5, 13, 11, 57, 113, 27, 191, 363, 1341, 3487, 8031, 13801, 7563, 40675}},
-{4114, 16, 7279, {1, 1, 3, 3, 27, 31, 103, 143, 271, 305, 2033, 3623, 4219, 9307, 7501, 8959}},
-{4115, 16, 7293, {1, 1, 1, 13, 1, 3, 27, 97, 475, 143, 333, 2997, 1807, 4231, 27437, 59717}},
-{4116, 16, 7312, {1, 3, 7, 5, 5, 3, 69, 233, 309, 511, 1429, 1887, 2745, 4969, 17595, 5451}},
-{4117, 16, 7327, {1, 1, 7, 3, 23, 17, 115, 89, 265, 467, 257, 2027, 5331, 1195, 4451, 8621}},
-{4118, 16, 7334, {1, 1, 7, 13, 29, 35, 117, 155, 99, 327, 853, 3595, 2997, 10745, 21619, 26549}},
-{4119, 16, 7337, {1, 3, 3, 13, 1, 13, 75, 151, 67, 271, 1609, 1117, 4293, 4645, 12005, 55983}},
-{4120, 16, 7343, {1, 1, 1, 13, 1, 61, 101, 63, 161, 261, 1759, 567, 665, 2339, 9157, 55603}},
-{4121, 16, 7346, {1, 1, 7, 11, 25, 19, 71, 27, 255, 435, 227, 4087, 4309, 14903, 14513, 30207}},
-{4122, 16, 7372, {1, 3, 3, 3, 11, 41, 1, 67, 383, 403, 45, 1521, 1535, 3353, 27361, 7549}},
-{4123, 16, 7387, {1, 1, 1, 1, 13, 51, 31, 137, 147, 907, 19, 3639, 3739, 877, 15005, 60357}},
-{4124, 16, 7390, {1, 1, 3, 11, 11, 23, 29, 173, 105, 873, 1727, 2761, 2015, 7491, 17491, 41065}},
-{4125, 16, 7396, {1, 1, 5, 3, 31, 1, 119, 53, 11, 731, 393, 4031, 4421, 15715, 6431, 18089}},
-{4126, 16, 7423, {1, 1, 3, 5, 15, 37, 55, 147, 307, 521, 711, 3085, 5989, 8081, 23351, 35259}},
-{4127, 16, 7428, {1, 3, 5, 13, 21, 19, 47, 107, 447, 713, 1655, 2809, 4741, 2105, 9255, 103}},
-{4128, 16, 7437, {1, 3, 1, 3, 17, 47, 63, 125, 343, 763, 1777, 607, 5625, 9517, 7221, 27257}},
-{4129, 16, 7466, {1, 1, 7, 5, 31, 13, 67, 255, 41, 947, 99, 721, 7367, 11427, 1357, 12383}},
-{4130, 16, 7474, {1, 1, 7, 3, 23, 27, 73, 185, 189, 545, 1877, 3169, 5419, 15873, 29059, 23983}},
-{4131, 16, 7476, {1, 1, 3, 1, 5, 13, 81, 45, 79, 717, 819, 3539, 7561, 7319, 5113, 27273}},
-{4132, 16, 7483, {1, 3, 7, 9, 21, 25, 71, 247, 41, 583, 771, 3745, 1883, 5717, 755, 14549}},
-{4133, 16, 7518, {1, 1, 3, 7, 23, 25, 87, 143, 499, 515, 1753, 1229, 173, 10629, 30579, 29643}},
-{4134, 16, 7527, {1, 3, 1, 13, 29, 33, 31, 69, 503, 117, 1717, 101, 7647, 1567, 28677, 3079}},
-{4135, 16, 7545, {1, 3, 1, 15, 29, 45, 57, 81, 171, 813, 505, 3647, 3913, 5557, 2477, 42429}},
-{4136, 16, 7572, {1, 1, 5, 13, 21, 13, 81, 5, 471, 221, 1563, 1741, 7269, 16327, 22687, 5291}},
-{4137, 16, 7586, {1, 3, 5, 3, 23, 41, 107, 61, 95, 79, 467, 1533, 739, 6791, 26911, 20309}},
-{4138, 16, 7597, {1, 3, 7, 7, 3, 53, 71, 163, 459, 975, 687, 1115, 5241, 299, 26361, 38583}},
-{4139, 16, 7630, {1, 3, 1, 9, 3, 63, 7, 133, 421, 325, 823, 1175, 6201, 5707, 31539, 34645}},
-{4140, 16, 7653, {1, 3, 7, 5, 27, 27, 107, 239, 247, 257, 1367, 3685, 7839, 11693, 3237, 13085}},
-{4141, 16, 7657, {1, 1, 1, 3, 27, 41, 51, 69, 271, 809, 1453, 519, 1301, 2367, 637, 5267}},
-{4142, 16, 7671, {1, 3, 7, 13, 19, 17, 3, 69, 369, 447, 1685, 4075, 6143, 11387, 5411, 29825}},
-{4143, 16, 7672, {1, 1, 3, 1, 25, 61, 79, 163, 1, 905, 1969, 2735, 7709, 16121, 20441, 4543}},
-{4144, 16, 7715, {1, 3, 7, 5, 15, 29, 7, 245, 343, 803, 1719, 3993, 983, 2925, 10393, 6053}},
-{4145, 16, 7717, {1, 3, 1, 7, 17, 55, 63, 29, 441, 387, 885, 3269, 1977, 1927, 3657, 47043}},
-{4146, 16, 7732, {1, 1, 3, 1, 17, 59, 51, 9, 173, 327, 1185, 3241, 3785, 10907, 19429, 22209}},
-{4147, 16, 7735, {1, 1, 3, 13, 21, 57, 125, 5, 359, 437, 1231, 2441, 5813, 9991, 283, 52555}},
-{4148, 16, 7753, {1, 3, 1, 7, 15, 19, 39, 125, 405, 381, 1757, 4075, 5565, 2065, 295, 8867}},
-{4149, 16, 7811, {1, 3, 3, 11, 7, 33, 95, 19, 253, 141, 1093, 1787, 7495, 5229, 15923, 44157}},
-{4150, 16, 7817, {1, 3, 7, 15, 1, 49, 69, 163, 85, 345, 901, 2329, 8003, 9915, 2209, 33979}},
-{4151, 16, 7825, {1, 1, 1, 9, 23, 51, 125, 163, 257, 681, 565, 945, 6375, 8679, 5985, 28919}},
-{4152, 16, 7832, {1, 3, 5, 7, 11, 23, 123, 231, 377, 121, 1519, 2061, 2957, 14537, 17625, 37773}},
-{4153, 16, 7838, {1, 3, 5, 1, 17, 43, 89, 119, 455, 279, 1857, 3405, 5225, 13035, 6055, 30861}},
-{4154, 16, 7841, {1, 3, 7, 15, 31, 63, 25, 225, 3, 527, 355, 1435, 5763, 15203, 26579, 45659}},
-{4155, 16, 7844, {1, 1, 1, 3, 27, 43, 71, 193, 135, 5, 683, 925, 7023, 7711, 2807, 56003}},
-{4156, 16, 7859, {1, 1, 1, 11, 3, 3, 109, 29, 109, 683, 419, 3295, 1961, 5953, 8887, 1523}},
-{4157, 16, 7861, {1, 3, 3, 11, 17, 39, 19, 225, 103, 249, 81, 3875, 4515, 3969, 24745, 60031}},
-{4158, 16, 7873, {1, 1, 3, 3, 3, 23, 15, 149, 305, 399, 1347, 1001, 597, 10003, 22123, 29919}},
-{4159, 16, 7880, {1, 3, 5, 1, 23, 35, 123, 7, 283, 283, 759, 3061, 2011, 7771, 32201, 40667}},
-{4160, 16, 7897, {1, 3, 7, 15, 23, 5, 81, 51, 357, 79, 133, 285, 425, 7743, 13499, 18983}},
-{4161, 16, 7904, {1, 3, 3, 5, 17, 37, 75, 221, 473, 111, 335, 683, 7353, 2283, 13457, 61171}},
-{4162, 16, 7910, {1, 3, 1, 7, 13, 45, 13, 223, 149, 209, 727, 3553, 2573, 177, 855, 44139}},
-{4163, 16, 7960, {1, 1, 3, 15, 23, 5, 103, 139, 17, 29, 1961, 3021, 5745, 12963, 30669, 44171}},
-{4164, 16, 7969, {1, 3, 1, 1, 3, 33, 67, 203, 29, 785, 71, 1693, 4487, 10221, 24523, 51223}},
-{4165, 16, 7970, {1, 1, 5, 7, 7, 27, 17, 183, 229, 669, 1675, 3751, 3233, 10677, 7509, 52313}},
-{4166, 16, 7976, {1, 1, 5, 5, 25, 35, 21, 163, 483, 399, 195, 3465, 6349, 545, 18861, 31759}},
-{4167, 16, 7979, {1, 3, 1, 5, 15, 39, 13, 157, 71, 841, 447, 3625, 53, 12745, 2719, 27617}},
-{4168, 16, 8007, {1, 1, 5, 5, 3, 45, 113, 121, 263, 887, 709, 2189, 3811, 1409, 10451, 48777}},
-{4169, 16, 8041, {1, 1, 5, 15, 9, 41, 31, 95, 377, 215, 437, 3633, 433, 11935, 15283, 55451}},
-{4170, 16, 8047, {1, 1, 7, 7, 13, 23, 79, 3, 451, 409, 1103, 1771, 553, 3175, 28703, 49357}},
-{4171, 16, 8052, {1, 3, 1, 1, 13, 33, 95, 133, 419, 851, 955, 3985, 5869, 14219, 253, 46883}},
-{4172, 16, 8061, {1, 3, 3, 3, 23, 55, 91, 207, 281, 355, 361, 261, 6837, 4401, 25455, 25313}},
-{4173, 16, 8078, {1, 3, 5, 9, 27, 9, 107, 51, 69, 555, 835, 3541, 1827, 5737, 31225, 55619}},
-{4174, 16, 8128, {1, 1, 1, 11, 27, 51, 79, 85, 447, 447, 9, 2803, 377, 4347, 2183, 61257}},
-{4175, 16, 8146, {1, 1, 1, 3, 23, 21, 51, 217, 297, 135, 573, 689, 4947, 14143, 26247, 43061}},
-{4176, 16, 8162, {1, 3, 1, 7, 15, 13, 27, 151, 463, 707, 43, 3641, 4999, 3783, 9083, 22085}},
-{4177, 16, 8250, {1, 3, 3, 5, 3, 1, 15, 119, 343, 605, 105, 2939, 2259, 889, 21759, 34073}},
-{4178, 16, 8270, {1, 1, 1, 7, 3, 63, 103, 1, 235, 317, 263, 2701, 7331, 15921, 17295, 613}},
-{4179, 16, 8294, {1, 1, 7, 3, 19, 3, 5, 17, 105, 491, 755, 233, 5397, 12365, 16325, 59377}},
-{4180, 16, 8324, {1, 3, 3, 15, 15, 27, 37, 151, 481, 949, 1473, 233, 1925, 15471, 24957, 3241}},
-{4181, 16, 8351, {1, 1, 7, 5, 9, 61, 49, 91, 169, 179, 701, 3957, 473, 15087, 6109, 25083}},
-{4182, 16, 8357, {1, 3, 3, 11, 27, 43, 5, 33, 69, 705, 733, 2675, 2677, 4235, 11109, 15557}},
-{4183, 16, 8361, {1, 3, 1, 3, 17, 19, 101, 119, 289, 341, 1395, 563, 6859, 10359, 10077, 26905}},
-{4184, 16, 8364, {1, 1, 1, 15, 21, 47, 41, 145, 439, 583, 1755, 1977, 5235, 15961, 21315, 60577}},
-{4185, 16, 8393, {1, 1, 5, 3, 9, 59, 71, 143, 27, 1007, 313, 1567, 1685, 11063, 28889, 44253}},
-{4186, 16, 8396, {1, 1, 5, 5, 29, 29, 43, 127, 13, 585, 1245, 187, 2697, 8791, 19561, 6463}},
-{4187, 16, 8407, {1, 1, 3, 11, 29, 39, 127, 75, 23, 521, 421, 3115, 139, 5429, 23341, 58035}},
-{4188, 16, 8413, {1, 1, 3, 1, 27, 35, 27, 9, 185, 653, 887, 2715, 3775, 1753, 22105, 62095}},
-{4189, 16, 8414, {1, 1, 5, 5, 5, 63, 23, 31, 317, 1001, 1751, 1185, 7933, 525, 30501, 15565}},
-{4190, 16, 8432, {1, 1, 1, 5, 9, 27, 79, 91, 453, 995, 1041, 3213, 8027, 5855, 7435, 64079}},
-{4191, 16, 8435, {1, 1, 3, 11, 1, 51, 27, 195, 139, 41, 1891, 1437, 1033, 11671, 3235, 35083}},
-{4192, 16, 8441, {1, 3, 1, 3, 11, 25, 33, 249, 373, 497, 1631, 293, 3657, 10741, 15831, 59545}},
-{4193, 16, 8447, {1, 1, 1, 1, 15, 63, 13, 165, 113, 559, 1615, 3579, 1993, 1907, 22335, 47791}},
-{4194, 16, 8449, {1, 1, 3, 15, 13, 49, 63, 235, 31, 811, 1729, 221, 5143, 11547, 30029, 52003}},
-{4195, 16, 8456, {1, 1, 5, 13, 29, 61, 25, 221, 421, 221, 583, 373, 2341, 7493, 13981, 54141}},
-{4196, 16, 8485, {1, 1, 5, 11, 21, 49, 71, 249, 237, 369, 1273, 1067, 4411, 409, 7219, 52933}},
-{4197, 16, 8504, {1, 3, 1, 1, 13, 23, 53, 15, 137, 553, 401, 2247, 5591, 14021, 445, 20433}},
-{4198, 16, 8512, {1, 1, 7, 7, 7, 23, 19, 189, 119, 643, 847, 2123, 5343, 11839, 4575, 60461}},
-{4199, 16, 8532, {1, 1, 5, 5, 11, 19, 111, 219, 185, 499, 595, 723, 3519, 10891, 27603, 29261}},
-{4200, 16, 8551, {1, 3, 3, 1, 9, 13, 95, 227, 459, 133, 1535, 3481, 7187, 14797, 16511, 6737}},
-{4201, 16, 8560, {1, 1, 7, 7, 19, 57, 117, 7, 455, 941, 455, 797, 6313, 10071, 18651, 25013}},
-{4202, 16, 8566, {1, 3, 7, 3, 25, 25, 79, 19, 383, 971, 1625, 2803, 2461, 633, 32317, 48407}},
-{4203, 16, 8581, {1, 1, 7, 7, 25, 43, 93, 135, 155, 685, 2001, 3007, 7315, 15555, 30401, 36291}},
-{4204, 16, 8609, {1, 1, 1, 5, 13, 33, 123, 221, 341, 105, 1075, 3125, 5323, 14293, 29875, 52215}},
-{4205, 16, 8639, {1, 1, 3, 9, 29, 51, 25, 59, 171, 563, 1695, 2845, 6067, 10671, 2909, 33977}},
-{4206, 16, 8641, {1, 3, 3, 7, 25, 21, 39, 65, 485, 949, 1773, 2775, 6019, 14587, 6715, 54793}},
-{4207, 16, 8671, {1, 1, 7, 11, 17, 57, 125, 17, 111, 167, 289, 3939, 7357, 2289, 1717, 45225}},
-{4208, 16, 8695, {1, 1, 7, 7, 21, 55, 3, 139, 471, 747, 1437, 1353, 7657, 13133, 14193, 38191}},
-{4209, 16, 8701, {1, 3, 5, 7, 25, 57, 55, 17, 315, 159, 437, 933, 7493, 6025, 2775, 24287}},
-{4210, 16, 8711, {1, 1, 7, 1, 15, 45, 67, 191, 355, 681, 1763, 1237, 105, 1425, 26089, 42879}},
-{4211, 16, 8739, {1, 1, 5, 13, 13, 53, 25, 127, 103, 155, 935, 2561, 475, 4341, 30541, 43835}},
-{4212, 16, 8763, {1, 1, 5, 15, 27, 59, 99, 173, 189, 41, 105, 3287, 4071, 15005, 18301, 34487}},
-{4213, 16, 8778, {1, 1, 5, 11, 21, 9, 57, 115, 495, 561, 579, 397, 3049, 2007, 5041, 37345}},
-{4214, 16, 8783, {1, 1, 5, 11, 15, 11, 101, 241, 69, 483, 1007, 4069, 5221, 5323, 20177, 24397}},
-{4215, 16, 8785, {1, 1, 1, 7, 29, 15, 119, 161, 21, 517, 847, 2217, 4487, 4817, 24053, 21683}},
-{4216, 16, 8797, {1, 3, 1, 3, 3, 51, 85, 63, 345, 799, 1699, 3961, 7109, 3931, 28173, 46851}},
-{4217, 16, 8802, {1, 1, 5, 7, 15, 25, 97, 139, 331, 969, 1129, 2451, 3107, 12235, 12949, 29837}},
-{4218, 16, 8816, {1, 3, 7, 1, 19, 21, 51, 155, 295, 565, 29, 2107, 341, 14611, 15281, 50727}},
-{4219, 16, 8828, {1, 3, 1, 11, 3, 37, 13, 217, 429, 217, 301, 1217, 5655, 13845, 32465, 23559}},
-{4220, 16, 8837, {1, 3, 3, 9, 9, 57, 79, 231, 433, 703, 699, 3813, 7035, 5885, 19185, 52551}},
-{4221, 16, 8852, {1, 1, 1, 5, 19, 17, 31, 209, 49, 515, 279, 909, 5881, 2673, 23635, 23101}},
-{4222, 16, 8859, {1, 1, 5, 7, 3, 3, 119, 139, 245, 775, 1009, 1157, 1405, 9737, 17671, 62981}},
-{4223, 16, 8889, {1, 3, 7, 11, 17, 21, 105, 21, 67, 871, 233, 3607, 571, 9141, 9751, 28093}},
-{4224, 16, 8900, {1, 1, 3, 13, 5, 53, 91, 181, 143, 375, 1113, 705, 837, 10505, 11459, 57753}},
-{4225, 16, 8903, {1, 3, 5, 11, 9, 19, 107, 229, 305, 107, 1027, 691, 4677, 8987, 7931, 951}},
-{4226, 16, 8909, {1, 1, 7, 9, 9, 17, 39, 195, 103, 315, 517, 123, 7167, 7039, 3571, 40469}},
-{4227, 16, 8910, {1, 1, 1, 5, 1, 21, 121, 53, 427, 111, 717, 1065, 2843, 5873, 28411, 42443}},
-{4228, 16, 8922, {1, 1, 3, 11, 27, 7, 37, 255, 429, 363, 997, 2429, 6871, 1271, 29375, 62897}},
-{4229, 16, 8924, {1, 3, 3, 13, 23, 23, 123, 119, 213, 51, 771, 1603, 1621, 1497, 23667, 13443}},
-{4230, 16, 8955, {1, 1, 3, 13, 17, 21, 81, 17, 211, 815, 1751, 3875, 4001, 3927, 6185, 28753}},
-{4231, 16, 8958, {1, 3, 1, 5, 13, 41, 23, 187, 475, 353, 1307, 543, 5077, 3459, 20553, 29119}},
-{4232, 16, 8980, {1, 1, 1, 7, 1, 39, 3, 247, 375, 101, 81, 1515, 1079, 15307, 18865, 63115}},
-{4233, 16, 8994, {1, 1, 5, 9, 23, 7, 61, 45, 379, 553, 435, 1805, 4147, 2289, 22081, 40041}},
-{4234, 16, 9006, {1, 1, 7, 3, 17, 13, 107, 169, 119, 981, 1825, 3329, 7779, 12245, 28367, 6749}},
-{4235, 16, 9017, {1, 3, 3, 13, 29, 13, 93, 155, 331, 507, 1073, 279, 6615, 14077, 3005, 10171}},
-{4236, 16, 9032, {1, 1, 5, 7, 29, 23, 81, 181, 321, 921, 1531, 2607, 7291, 1255, 29889, 30095}},
-{4237, 16, 9040, {1, 1, 1, 5, 7, 1, 9, 231, 203, 559, 243, 3999, 3649, 7939, 14729, 34771}},
-{4238, 16, 9061, {1, 3, 7, 3, 17, 29, 79, 251, 305, 641, 1125, 1155, 7139, 6721, 43, 34927}},
-{4239, 16, 9066, {1, 1, 5, 13, 21, 39, 55, 103, 143, 487, 849, 1111, 1105, 8483, 5417, 10521}},
-{4240, 16, 9071, {1, 1, 5, 5, 19, 5, 111, 49, 95, 917, 843, 2539, 6831, 9019, 16045, 59363}},
-{4241, 16, 9076, {1, 3, 3, 11, 7, 45, 87, 51, 49, 615, 603, 1623, 5351, 11939, 21945, 40539}},
-{4242, 16, 9086, {1, 1, 5, 9, 9, 33, 113, 37, 163, 853, 1313, 4021, 965, 11465, 8573, 24425}},
-{4243, 16, 9104, {1, 3, 3, 9, 17, 19, 121, 95, 93, 441, 1951, 3335, 6279, 16087, 14763, 60771}},
-{4244, 16, 9150, {1, 3, 3, 9, 13, 15, 19, 129, 257, 641, 533, 1667, 5959, 2259, 10439, 29745}},
-{4245, 16, 9161, {1, 1, 7, 7, 11, 31, 45, 247, 233, 101, 899, 2033, 7803, 11423, 30645, 7723}},
-{4246, 16, 9164, {1, 3, 5, 11, 23, 3, 69, 79, 319, 125, 1463, 2047, 7311, 5819, 445, 13725}},
-{4247, 16, 9185, {1, 1, 1, 3, 7, 43, 83, 89, 467, 709, 1993, 3773, 7805, 305, 15701, 51101}},
-{4248, 16, 9188, {1, 1, 7, 5, 19, 53, 77, 237, 27, 853, 1003, 2041, 5739, 4663, 9783, 23761}},
-{4249, 16, 9212, {1, 1, 3, 7, 19, 31, 71, 33, 479, 693, 1503, 9, 2779, 1481, 9413, 36227}},
-{4250, 16, 9230, {1, 3, 1, 11, 9, 23, 1, 99, 247, 33, 1987, 1577, 8029, 7785, 29947, 38751}},
-{4251, 16, 9242, {1, 1, 1, 3, 15, 57, 23, 53, 431, 553, 1433, 2447, 1871, 10701, 30961, 12281}},
-{4252, 16, 9247, {1, 3, 5, 9, 11, 49, 123, 91, 87, 155, 301, 3339, 6183, 15895, 17309, 45927}},
-{4253, 16, 9260, {1, 1, 1, 9, 9, 41, 79, 123, 261, 547, 1931, 2553, 7405, 14431, 24079, 20769}},
-{4254, 16, 9280, {1, 3, 1, 3, 31, 17, 17, 137, 419, 591, 1693, 3977, 861, 16025, 189, 60995}},
-{4255, 16, 9300, {1, 3, 7, 11, 19, 47, 107, 243, 87, 135, 507, 189, 1397, 3841, 22999, 50781}},
-{4256, 16, 9313, {1, 3, 5, 5, 15, 11, 19, 239, 133, 295, 673, 2389, 4753, 4363, 21669, 25579}},
-{4257, 16, 9325, {1, 3, 5, 7, 19, 43, 55, 129, 239, 89, 1731, 1381, 5483, 11773, 9201, 17745}},
-{4258, 16, 9343, {1, 3, 1, 13, 3, 15, 77, 131, 417, 845, 1953, 2871, 1789, 10343, 11363, 20699}},
-{4259, 16, 9349, {1, 3, 7, 1, 9, 43, 55, 223, 239, 317, 1951, 2725, 209, 3853, 2201, 6839}},
-{4260, 16, 9354, {1, 3, 1, 3, 7, 35, 29, 21, 149, 779, 467, 65, 811, 4859, 14021, 38429}},
-{4261, 16, 9367, {1, 3, 7, 1, 19, 31, 97, 9, 11, 415, 689, 1513, 2475, 5039, 5669, 65103}},
-{4262, 16, 9368, {1, 3, 3, 3, 11, 25, 37, 247, 189, 911, 429, 2395, 3653, 79, 28115, 23513}},
-{4263, 16, 9455, {1, 1, 5, 5, 5, 27, 25, 45, 291, 455, 741, 2259, 8131, 11779, 14693, 58729}},
-{4264, 16, 9458, {1, 3, 3, 7, 21, 33, 67, 49, 153, 491, 1811, 1955, 925, 15555, 13801, 48717}},
-{4265, 16, 9469, {1, 3, 1, 3, 11, 53, 105, 129, 457, 225, 497, 1123, 973, 2901, 26655, 3643}},
-{4266, 16, 9481, {1, 1, 7, 13, 29, 49, 71, 37, 321, 865, 735, 357, 7629, 6011, 28221, 39041}},
-{4267, 16, 9482, {1, 3, 5, 3, 19, 59, 65, 199, 69, 391, 1735, 3075, 287, 16213, 3211, 22425}},
-{4268, 16, 9495, {1, 1, 1, 5, 15, 61, 67, 255, 5, 689, 759, 155, 7245, 5881, 21685, 3863}},
-{4269, 16, 9526, {1, 1, 3, 11, 23, 63, 69, 241, 359, 735, 371, 603, 2707, 15833, 31795, 14901}},
-{4270, 16, 9530, {1, 1, 1, 7, 19, 33, 83, 19, 13, 667, 317, 3891, 5497, 8213, 4913, 22387}},
-{4271, 16, 9558, {1, 3, 5, 9, 13, 21, 11, 187, 249, 647, 349, 605, 2199, 5033, 29773, 48953}},
-{4272, 16, 9562, {1, 3, 3, 11, 3, 3, 93, 235, 441, 933, 383, 2007, 4015, 4175, 3937, 20623}},
-{4273, 16, 9573, {1, 3, 7, 13, 3, 61, 87, 219, 263, 651, 1343, 2709, 31, 16249, 4749, 28909}},
-{4274, 16, 9583, {1, 3, 1, 1, 17, 19, 101, 107, 499, 127, 13, 2123, 5597, 3751, 14527, 12009}},
-{4275, 16, 9595, {1, 3, 5, 13, 27, 57, 1, 195, 107, 947, 1475, 2831, 6449, 16117, 20555, 61513}},
-{4276, 16, 9597, {1, 3, 1, 9, 9, 47, 89, 187, 401, 299, 637, 197, 1235, 12655, 25025, 24443}},
-{4277, 16, 9616, {1, 1, 3, 5, 9, 57, 33, 41, 451, 983, 391, 2707, 705, 13913, 28843, 34091}},
-{4278, 16, 9638, {1, 3, 5, 3, 29, 19, 61, 31, 349, 253, 1267, 3345, 2151, 11309, 19623, 62407}},
-{4279, 16, 9649, {1, 1, 1, 3, 11, 37, 31, 59, 1, 253, 103, 2811, 1871, 4239, 26311, 32507}},
-{4280, 16, 9662, {1, 1, 5, 7, 7, 7, 69, 63, 281, 901, 1785, 2131, 4265, 253, 13997, 30177}},
-{4281, 16, 9691, {1, 3, 1, 11, 3, 27, 111, 67, 411, 751, 241, 293, 6271, 4187, 22119, 63737}},
-{4282, 16, 9700, {1, 3, 5, 5, 27, 19, 45, 203, 81, 59, 1839, 935, 4847, 1869, 12037, 30971}},
-{4283, 16, 9703, {1, 1, 3, 9, 19, 25, 9, 27, 373, 875, 1735, 689, 2957, 7873, 29771, 4093}},
-{4284, 16, 9710, {1, 1, 7, 11, 13, 39, 11, 129, 53, 433, 1731, 899, 5855, 10221, 24165, 50205}},
-{4285, 16, 9721, {1, 3, 1, 15, 25, 31, 85, 49, 325, 299, 183, 287, 2425, 15353, 25999, 59129}},
-{4286, 16, 9724, {1, 1, 5, 5, 17, 25, 23, 5, 287, 677, 591, 981, 429, 15297, 14573, 61095}},
-{4287, 16, 9727, {1, 1, 5, 15, 5, 15, 67, 195, 209, 341, 1621, 1379, 3031, 5469, 31563, 49291}},
-{4288, 16, 9743, {1, 1, 1, 1, 25, 33, 61, 201, 15, 125, 969, 1965, 2021, 10253, 23801, 28165}},
-{4289, 16, 9779, {1, 1, 5, 5, 13, 17, 5, 245, 11, 133, 287, 1929, 4331, 15919, 29663, 10243}},
-{4290, 16, 9785, {1, 1, 7, 9, 19, 33, 39, 191, 489, 631, 69, 1883, 2183, 14993, 32715, 62217}},
-{4291, 16, 9811, {1, 3, 3, 13, 23, 61, 103, 193, 501, 431, 437, 417, 6557, 11701, 27577, 42943}},
-{4292, 16, 9820, {1, 3, 3, 9, 9, 27, 69, 247, 469, 841, 733, 813, 2673, 7145, 5385, 44917}},
-{4293, 16, 9827, {1, 1, 7, 9, 5, 13, 19, 71, 323, 923, 1885, 3031, 4507, 13787, 14149, 1483}},
-{4294, 16, 9851, {1, 3, 1, 5, 1, 15, 89, 229, 301, 733, 1343, 2415, 6463, 1875, 9293, 6037}},
-{4295, 16, 9854, {1, 3, 1, 5, 29, 57, 67, 121, 311, 441, 1079, 1963, 7137, 6745, 9893, 22811}},
-{4296, 16, 9863, {1, 1, 7, 7, 25, 13, 27, 61, 331, 361, 481, 3783, 3061, 7827, 18885, 27583}},
-{4297, 16, 9884, {1, 3, 1, 5, 17, 47, 19, 83, 309, 65, 1573, 3437, 5623, 12691, 21075, 27789}},
-{4298, 16, 9894, {1, 1, 7, 9, 13, 51, 7, 209, 131, 111, 1143, 53, 7277, 9297, 20869, 33121}},
-{4299, 16, 9903, {1, 1, 3, 9, 13, 17, 57, 89, 239, 281, 775, 333, 5631, 2805, 10195, 9665}},
-{4300, 16, 9908, {1, 1, 3, 7, 19, 39, 71, 79, 63, 551, 103, 3169, 2761, 13929, 20751, 18951}},
-{4301, 16, 9912, {1, 1, 7, 11, 5, 23, 7, 249, 447, 483, 433, 3117, 1421, 14991, 5397, 19813}},
-{4302, 16, 9925, {1, 3, 1, 13, 3, 9, 109, 241, 181, 33, 853, 3939, 3751, 2151, 28375, 64443}},
-{4303, 16, 9926, {1, 1, 7, 7, 3, 33, 65, 211, 251, 631, 1819, 3913, 3353, 12975, 19117, 51515}},
-{4304, 16, 9971, {1, 1, 1, 13, 3, 21, 9, 203, 223, 229, 1399, 117, 6297, 11535, 16383, 12541}},
-{4305, 16, 9973, {1, 1, 5, 7, 25, 9, 53, 27, 497, 103, 1915, 2179, 3679, 11375, 18907, 63385}},
-{4306, 16, 9977, {1, 3, 1, 5, 1, 53, 91, 169, 87, 387, 377, 1121, 7241, 5133, 1949, 13433}},
-{4307, 16, 10021, {1, 1, 1, 3, 27, 35, 61, 189, 241, 445, 287, 325, 127, 2363, 30663, 43557}},
-{4308, 16, 10039, {1, 3, 1, 3, 17, 47, 59, 237, 213, 979, 807, 85, 4621, 9915, 13631, 55657}},
-{4309, 16, 10048, {1, 3, 5, 7, 27, 5, 101, 89, 495, 675, 1181, 2295, 1913, 3731, 32639, 58297}},
-{4310, 16, 10051, {1, 3, 3, 11, 5, 41, 49, 229, 93, 659, 927, 3425, 4083, 11859, 10603, 20631}},
-{4311, 16, 10065, {1, 3, 5, 11, 31, 51, 67, 69, 253, 497, 1665, 1985, 5439, 15999, 4175, 62175}},
-{4312, 16, 10071, {1, 1, 7, 11, 1, 21, 95, 19, 205, 513, 1329, 1821, 1251, 2381, 32623, 23923}},
-{4313, 16, 10072, {1, 1, 5, 13, 3, 1, 29, 175, 315, 865, 599, 1695, 1391, 2313, 31035, 19159}},
-{4314, 16, 10101, {1, 3, 3, 1, 3, 45, 109, 93, 481, 285, 869, 3441, 3715, 1355, 9581, 50173}},
-{4315, 16, 10106, {1, 3, 7, 7, 15, 35, 107, 107, 315, 213, 281, 2073, 4689, 5877, 31, 40967}},
-{4316, 16, 10130, {1, 1, 3, 11, 11, 3, 73, 41, 79, 37, 481, 1993, 931, 7677, 11321, 45735}},
-{4317, 16, 10136, {1, 1, 7, 1, 15, 21, 65, 237, 263, 849, 863, 4039, 3171, 13381, 30373, 51639}},
-{4318, 16, 10148, {1, 1, 1, 3, 21, 57, 113, 3, 487, 41, 1277, 633, 2839, 4977, 14537, 31749}},
-{4319, 16, 10155, {1, 1, 5, 1, 1, 55, 71, 181, 147, 895, 1839, 2157, 3187, 6403, 30367, 48915}},
-{4320, 16, 10157, {1, 1, 5, 3, 9, 17, 19, 127, 115, 875, 831, 2439, 7475, 1921, 18657, 27709}},
-{4321, 16, 10160, {1, 3, 3, 13, 29, 11, 35, 81, 291, 483, 625, 3957, 6017, 12543, 18773, 2471}},
-{4322, 16, 10166, {1, 3, 3, 13, 11, 39, 7, 85, 493, 209, 819, 3277, 4275, 8997, 22943, 33199}},
-{4323, 16, 10183, {1, 1, 1, 7, 11, 25, 1, 57, 505, 135, 1713, 3051, 5893, 10711, 10681, 12235}},
-{4324, 16, 10192, {1, 3, 5, 11, 23, 33, 13, 107, 289, 251, 235, 1747, 4097, 12237, 17559, 5063}},
-{4325, 16, 10225, {1, 3, 3, 9, 19, 17, 23, 45, 297, 147, 1301, 2057, 7871, 9971, 1965, 62449}},
-{4326, 16, 10241, {1, 1, 7, 3, 17, 21, 19, 203, 289, 897, 1967, 3519, 3261, 8199, 24181, 23273}},
-{4327, 16, 10247, {1, 1, 7, 11, 1, 17, 25, 63, 509, 969, 47, 1329, 701, 5227, 419, 14839}},
-{4328, 16, 10284, {1, 3, 5, 11, 1, 41, 81, 157, 395, 97, 1919, 3043, 6015, 15, 23733, 55485}},
-{4329, 16, 10304, {1, 1, 3, 11, 17, 37, 17, 181, 179, 297, 1007, 1559, 6275, 11645, 7535, 28941}},
-{4330, 16, 10322, {1, 3, 7, 15, 5, 47, 31, 237, 215, 563, 207, 1867, 6635, 6857, 11837, 22865}},
-{4331, 16, 10331, {1, 3, 1, 7, 7, 39, 51, 179, 57, 987, 893, 2715, 1045, 5799, 19805, 54275}},
-{4332, 16, 10333, {1, 1, 7, 15, 25, 9, 127, 243, 323, 1013, 929, 2891, 7549, 1071, 17663, 15247}},
-{4333, 16, 10340, {1, 1, 1, 5, 25, 23, 101, 9, 371, 89, 1749, 3559, 8071, 13887, 14807, 42825}},
-{4334, 16, 10347, {1, 3, 3, 11, 21, 41, 3, 77, 3, 709, 1745, 3615, 4141, 5275, 28329, 59739}},
-{4335, 16, 10357, {1, 1, 7, 13, 1, 11, 73, 183, 363, 241, 863, 3983, 3235, 293, 649, 441}},
-{4336, 16, 10371, {1, 1, 5, 3, 13, 27, 13, 191, 57, 639, 1803, 2353, 3143, 12763, 5771, 36155}},
-{4337, 16, 10386, {1, 1, 5, 3, 1, 53, 85, 45, 283, 823, 1213, 3261, 4599, 13267, 4613, 12657}},
-{4338, 16, 10404, {1, 3, 5, 15, 27, 49, 59, 123, 357, 527, 337, 2751, 3999, 8525, 12501, 40621}},
-{4339, 16, 10414, {1, 1, 1, 7, 1, 55, 85, 17, 447, 599, 1315, 2313, 1649, 907, 25647, 3251}},
-{4340, 16, 10422, {1, 3, 5, 13, 9, 1, 37, 121, 143, 1, 631, 2273, 1673, 3649, 27533, 28731}},
-{4341, 16, 10448, {1, 1, 7, 13, 9, 31, 57, 249, 397, 815, 501, 895, 1217, 11387, 8635, 65193}},
-{4342, 16, 10451, {1, 1, 5, 5, 9, 35, 95, 193, 133, 513, 1929, 3841, 3063, 2383, 24413, 51185}},
-{4343, 16, 10473, {1, 1, 1, 13, 3, 49, 45, 191, 15, 181, 1819, 3741, 1227, 12775, 9461, 44951}},
-{4344, 16, 10479, {1, 1, 1, 1, 3, 45, 121, 19, 269, 829, 517, 3913, 183, 11019, 24969, 21973}},
-{4345, 16, 10501, {1, 1, 5, 11, 31, 39, 125, 189, 401, 57, 1557, 1727, 1415, 4025, 30353, 36589}},
-{4346, 16, 10530, {1, 1, 3, 9, 3, 55, 125, 187, 409, 499, 1853, 2781, 4323, 16159, 16345, 34659}},
-{4347, 16, 10542, {1, 3, 5, 11, 31, 5, 125, 137, 197, 475, 2003, 617, 1289, 8365, 28981, 57537}},
-{4348, 16, 10544, {1, 1, 1, 5, 19, 29, 83, 127, 311, 177, 1635, 2187, 5377, 12841, 7591, 6095}},
-{4349, 16, 10571, {1, 3, 5, 5, 21, 39, 65, 197, 115, 411, 1457, 3011, 7021, 14119, 61, 21107}},
-{4350, 16, 10628, {1, 3, 3, 9, 19, 57, 99, 23, 451, 507, 973, 415, 7123, 11367, 29767, 23763}},
-{4351, 16, 10643, {1, 1, 5, 7, 29, 23, 47, 11, 267, 873, 591, 373, 7097, 3783, 23289, 5547}},
-{4352, 16, 10673, {1, 1, 5, 15, 7, 7, 7, 91, 389, 841, 1995, 459, 7013, 3109, 23615, 21519}},
-{4353, 16, 10683, {1, 3, 1, 1, 13, 25, 87, 235, 193, 201, 713, 1633, 3117, 13609, 17211, 573}},
-{4354, 16, 10736, {1, 1, 1, 9, 27, 53, 105, 39, 217, 781, 997, 661, 6243, 6427, 17739, 62239}},
-{4355, 16, 10795, {1, 1, 7, 3, 3, 49, 75, 125, 239, 195, 215, 2983, 1185, 4743, 12069, 55509}},
-{4356, 16, 10797, {1, 1, 5, 15, 31, 11, 9, 91, 253, 361, 571, 1589, 2425, 4279, 3765, 46519}},
-{4357, 16, 10815, {1, 1, 3, 3, 21, 49, 49, 213, 399, 253, 1565, 2447, 453, 7957, 24799, 58503}},
-{4358, 16, 10817, {1, 1, 7, 1, 5, 59, 81, 97, 209, 477, 17, 3085, 3655, 599, 24011, 14981}},
-{4359, 16, 10842, {1, 3, 3, 13, 19, 49, 7, 35, 111, 169, 629, 1587, 5345, 13699, 21187, 30199}},
-{4360, 16, 10844, {1, 1, 3, 13, 19, 59, 73, 127, 475, 509, 9, 2661, 711, 15835, 31429, 33885}},
-{4361, 16, 10863, {1, 3, 5, 3, 31, 15, 43, 185, 29, 897, 1041, 1057, 6285, 13925, 4023, 25741}},
-{4362, 16, 10899, {1, 3, 5, 11, 1, 33, 63, 155, 175, 501, 1147, 3395, 3285, 16237, 22315, 50945}},
-{4363, 16, 10902, {1, 3, 3, 3, 5, 13, 77, 227, 85, 139, 139, 1, 7147, 2023, 32705, 38753}},
-{4364, 16, 10917, {1, 3, 5, 11, 31, 59, 35, 179, 489, 537, 1537, 2877, 4937, 10825, 2445, 34907}},
-{4365, 16, 10953, {1, 3, 7, 11, 17, 17, 95, 223, 165, 925, 829, 3971, 1, 7393, 8825, 25705}},
-{4366, 16, 10967, {1, 1, 1, 1, 25, 17, 25, 143, 385, 907, 1381, 1823, 3819, 8475, 5321, 12037}},
-{4367, 16, 11002, {1, 1, 5, 11, 7, 47, 97, 85, 105, 23, 263, 1329, 1905, 12121, 29635, 41249}},
-{4368, 16, 11024, {1, 1, 7, 11, 1, 51, 13, 13, 5, 143, 83, 3831, 959, 6083, 16997, 59887}},
-{4369, 16, 11029, {1, 3, 3, 13, 25, 9, 31, 5, 215, 791, 767, 1733, 2715, 14283, 25795, 54249}},
-{4370, 16, 11030, {1, 3, 7, 5, 11, 19, 125, 81, 71, 131, 1869, 1111, 6763, 5275, 23095, 1139}},
-{4371, 16, 11043, {1, 3, 3, 9, 25, 43, 119, 49, 133, 217, 521, 1367, 5867, 6829, 29871, 60383}},
-{4372, 16, 11087, {1, 1, 7, 9, 5, 11, 59, 157, 279, 301, 481, 3273, 7943, 3273, 27783, 17271}},
-{4373, 16, 11106, {1, 3, 3, 13, 11, 57, 13, 5, 435, 169, 541, 517, 2359, 9121, 27911, 15679}},
-{4374, 16, 11130, {1, 1, 3, 9, 9, 55, 65, 113, 21, 807, 373, 2825, 1527, 15565, 8339, 7227}},
-{4375, 16, 11156, {1, 3, 5, 9, 1, 1, 49, 255, 477, 821, 1647, 713, 6841, 3187, 22649, 51469}},
-{4376, 16, 11176, {1, 3, 3, 11, 13, 43, 63, 139, 71, 809, 993, 2429, 833, 6545, 10987, 39567}},
-{4377, 16, 11221, {1, 1, 1, 9, 19, 23, 47, 199, 191, 827, 391, 837, 1209, 2493, 24071, 46589}},
-{4378, 16, 11267, {1, 1, 5, 13, 25, 51, 39, 43, 103, 899, 1729, 2389, 2965, 189, 3063, 50609}},
-{4379, 16, 11282, {1, 1, 3, 1, 5, 29, 105, 201, 503, 199, 507, 205, 2389, 695, 15233, 50353}},
-{4380, 16, 11294, {1, 3, 1, 7, 19, 53, 45, 21, 89, 545, 1885, 765, 6673, 13485, 9987, 2609}},
-{4381, 16, 11332, {1, 3, 7, 13, 17, 7, 59, 23, 159, 309, 1407, 2483, 1807, 15733, 5603, 52989}},
-{4382, 16, 11353, {1, 1, 1, 11, 13, 19, 123, 185, 413, 745, 361, 2391, 6697, 2281, 11999, 13175}},
-{4383, 16, 11369, {1, 3, 5, 5, 11, 49, 123, 173, 325, 667, 895, 1067, 8121, 10577, 30561, 17391}},
-{4384, 16, 11372, {1, 1, 5, 5, 23, 21, 77, 223, 281, 161, 141, 345, 3879, 11393, 26907, 53805}},
-{4385, 16, 11375, {1, 3, 3, 5, 3, 47, 17, 109, 185, 139, 957, 1417, 4553, 6101, 29537, 34821}},
-{4386, 16, 11413, {1, 1, 5, 3, 29, 49, 89, 61, 45, 593, 269, 1483, 2971, 991, 21239, 29301}},
-{4387, 16, 11429, {1, 1, 3, 13, 29, 45, 33, 253, 291, 783, 737, 2363, 2651, 8627, 21785, 58419}},
-{4388, 16, 11430, {1, 3, 7, 15, 29, 15, 81, 185, 363, 681, 1737, 3789, 4365, 3295, 23205, 4457}},
-{4389, 16, 11444, {1, 3, 3, 11, 15, 39, 67, 167, 197, 357, 871, 2201, 5377, 6299, 20873, 59283}},
-{4390, 16, 11462, {1, 3, 3, 5, 9, 15, 127, 49, 21, 719, 357, 425, 5507, 9639, 275, 47503}},
-{4391, 16, 11465, {1, 1, 7, 1, 13, 63, 111, 121, 21, 481, 247, 3147, 5783, 8947, 20809, 42039}},
-{4392, 16, 11471, {1, 1, 3, 3, 31, 33, 9, 69, 187, 517, 2029, 2205, 7661, 4757, 27525, 9665}},
-{4393, 16, 11473, {1, 1, 1, 13, 7, 41, 103, 161, 233, 221, 693, 213, 4609, 7771, 28703, 17407}},
-{4394, 16, 11495, {1, 3, 7, 15, 31, 47, 27, 111, 479, 1003, 1687, 347, 2179, 11861, 8169, 31941}},
-{4395, 16, 11499, {1, 1, 3, 5, 5, 63, 25, 125, 199, 147, 589, 3565, 3449, 8331, 8923, 31207}},
-{4396, 16, 11519, {1, 1, 3, 11, 19, 25, 77, 99, 299, 19, 1641, 2193, 4299, 3635, 20621, 267}},
-{4397, 16, 11562, {1, 3, 7, 11, 9, 59, 7, 167, 1, 775, 29, 1935, 3723, 11835, 2887, 65285}},
-{4398, 16, 11576, {1, 1, 7, 13, 5, 47, 101, 155, 235, 93, 465, 3581, 1837, 7675, 10789, 45167}},
-{4399, 16, 11582, {1, 1, 3, 5, 9, 59, 121, 109, 59, 821, 1625, 343, 1591, 3875, 13729, 56381}},
-{4400, 16, 11596, {1, 1, 1, 9, 27, 53, 93, 215, 133, 561, 39, 2591, 1041, 11913, 24493, 37921}},
-{4401, 16, 11602, {1, 1, 1, 7, 23, 7, 81, 107, 219, 943, 563, 1083, 5803, 5687, 32559, 62727}},
-{4402, 16, 11611, {1, 3, 7, 7, 21, 53, 3, 5, 231, 601, 1561, 103, 3837, 2675, 5263, 23375}},
-{4403, 16, 11627, {1, 1, 3, 13, 15, 27, 89, 7, 251, 887, 951, 3001, 5687, 4921, 5091, 59337}},
-{4404, 16, 11682, {1, 3, 7, 15, 25, 53, 19, 155, 185, 503, 547, 1917, 7633, 15167, 14177, 46761}},
-{4405, 16, 11687, {1, 3, 5, 15, 21, 49, 13, 163, 471, 281, 1141, 3013, 6847, 9261, 15955, 9397}},
-{4406, 16, 11691, {1, 3, 3, 3, 1, 21, 19, 239, 479, 609, 65, 2735, 5337, 6293, 19351, 34135}},
-{4407, 16, 11733, {1, 1, 7, 1, 9, 1, 119, 23, 411, 535, 101, 1597, 2379, 2421, 31471, 36473}},
-{4408, 16, 11747, {1, 3, 1, 11, 31, 63, 17, 225, 45, 409, 59, 3943, 8043, 11759, 10667, 58793}},
-{4409, 16, 11759, {1, 1, 3, 3, 9, 49, 61, 239, 245, 765, 1945, 3567, 5355, 14799, 7141, 59511}},
-{4410, 16, 11778, {1, 3, 7, 9, 3, 33, 103, 99, 35, 799, 1347, 2253, 8189, 14177, 13479, 13749}},
-{4411, 16, 11852, {1, 3, 1, 15, 15, 51, 7, 179, 471, 265, 1571, 2983, 701, 15133, 7885, 29977}},
-{4412, 16, 11857, {1, 1, 5, 9, 15, 37, 49, 213, 113, 729, 1115, 2727, 2635, 8433, 11145, 46779}},
-{4413, 16, 11858, {1, 3, 5, 11, 7, 3, 115, 151, 133, 723, 7, 4063, 5807, 9845, 25829, 29315}},
-{4414, 16, 11893, {1, 3, 5, 9, 25, 55, 17, 135, 145, 379, 1603, 3459, 5773, 6545, 17509, 25847}},
-{4415, 16, 11907, {1, 1, 7, 11, 1, 61, 113, 147, 489, 775, 1347, 2199, 299, 9589, 19931, 1335}},
-{4416, 16, 11928, {1, 3, 1, 3, 1, 7, 27, 243, 355, 425, 1215, 3723, 3489, 9285, 12739, 24797}},
-{4417, 16, 11931, {1, 3, 5, 11, 15, 25, 57, 221, 247, 647, 259, 1665, 7055, 2835, 16411, 42999}},
-{4418, 16, 11933, {1, 1, 3, 7, 9, 25, 61, 233, 73, 235, 1539, 1865, 5671, 1329, 5767, 43039}},
-{4419, 16, 11967, {1, 1, 7, 9, 21, 11, 123, 7, 41, 407, 1485, 1723, 585, 10597, 16215, 63403}},
-{4420, 16, 11976, {1, 1, 5, 7, 27, 9, 123, 101, 273, 673, 1141, 3841, 4041, 13169, 8221, 12915}},
-{4421, 16, 11989, {1, 3, 1, 13, 3, 17, 105, 17, 237, 321, 855, 2821, 2467, 3503, 15187, 1689}},
-{4422, 16, 12003, {1, 1, 5, 5, 19, 23, 9, 205, 87, 153, 1543, 1193, 6619, 6845, 8459, 37533}},
-{4423, 16, 12024, {1, 1, 7, 15, 13, 29, 79, 9, 203, 211, 239, 2349, 3447, 7797, 19311, 58071}},
-{4424, 16, 12030, {1, 3, 5, 11, 5, 49, 71, 151, 333, 895, 1095, 2471, 2477, 14493, 16711, 14393}},
-{4425, 16, 12037, {1, 1, 5, 13, 17, 19, 25, 149, 111, 631, 763, 2535, 3631, 1809, 8163, 18037}},
-{4426, 16, 12044, {1, 3, 3, 13, 23, 61, 25, 179, 351, 247, 1021, 2413, 2585, 3731, 5435, 52723}},
-{4427, 16, 12052, {1, 1, 5, 11, 1, 39, 65, 59, 21, 927, 1989, 2823, 4857, 15521, 30495, 16067}},
-{4428, 16, 12059, {1, 3, 3, 7, 17, 5, 17, 125, 379, 875, 1565, 2435, 933, 6809, 20129, 26339}},
-{4429, 16, 12075, {1, 1, 7, 5, 3, 57, 51, 213, 455, 663, 2007, 3995, 4889, 9527, 23507, 3261}},
-{4430, 16, 12083, {1, 3, 7, 5, 1, 29, 85, 151, 165, 123, 1425, 2851, 4427, 7683, 21085, 28925}},
-{4431, 16, 12117, {1, 1, 5, 3, 11, 33, 127, 3, 41, 591, 1539, 3823, 125, 421, 9051, 55025}},
-{4432, 16, 12138, {1, 3, 1, 5, 7, 9, 69, 35, 59, 477, 1207, 1245, 6423, 11329, 26535, 37621}},
-{4433, 16, 12146, {1, 3, 1, 1, 15, 35, 17, 123, 303, 193, 1489, 2587, 1883, 4063, 1921, 60413}},
-{4434, 16, 12202, {1, 1, 5, 1, 7, 61, 39, 247, 139, 1015, 757, 823, 4757, 9307, 32287, 37241}},
-{4435, 16, 12230, {1, 1, 7, 15, 3, 5, 85, 93, 457, 999, 1331, 919, 5271, 11687, 24233, 38803}},
-{4436, 16, 12254, {1, 3, 3, 9, 5, 43, 37, 13, 505, 603, 1857, 2675, 2017, 9481, 10873, 54755}},
-{4437, 16, 12304, {1, 1, 5, 15, 13, 3, 7, 239, 471, 835, 553, 413, 4029, 8613, 15533, 58987}},
-{4438, 16, 12316, {1, 3, 1, 5, 19, 27, 21, 43, 57, 755, 1245, 2805, 3799, 2013, 21145, 10317}},
-{4439, 16, 12337, {1, 3, 5, 13, 9, 23, 35, 5, 315, 169, 399, 2641, 1525, 10561, 11917, 33009}},
-{4440, 16, 12347, {1, 3, 5, 7, 23, 53, 101, 105, 451, 207, 1271, 3067, 6725, 15525, 7951, 1283}},
-{4441, 16, 12367, {1, 1, 5, 5, 27, 21, 77, 143, 213, 443, 149, 2667, 5269, 10359, 25287, 5843}},
-{4442, 16, 12398, {1, 3, 5, 5, 25, 27, 109, 157, 459, 767, 765, 2667, 1833, 3781, 9077, 64321}},
-{4443, 16, 12421, {1, 3, 3, 13, 31, 25, 97, 237, 279, 431, 1713, 809, 1989, 10431, 5867, 42197}},
-{4444, 16, 12428, {1, 3, 7, 3, 9, 5, 5, 191, 73, 521, 787, 903, 3073, 2067, 24741, 57029}},
-{4445, 16, 12446, {1, 3, 3, 1, 3, 41, 125, 53, 125, 781, 865, 3677, 6279, 357, 10667, 1127}},
-{4446, 16, 12449, {1, 1, 5, 11, 25, 19, 99, 121, 359, 73, 607, 2149, 5739, 15669, 29457, 57549}},
-{4447, 16, 12467, {1, 1, 5, 3, 23, 5, 35, 55, 369, 239, 329, 3057, 3757, 12523, 5017, 52185}},
-{4448, 16, 12479, {1, 3, 3, 13, 17, 61, 69, 165, 267, 323, 2007, 2025, 4423, 15975, 31897, 37013}},
-{4449, 16, 12502, {1, 3, 7, 13, 19, 19, 87, 111, 389, 611, 1523, 963, 4671, 12569, 21839, 10919}},
-{4450, 16, 12521, {1, 1, 1, 3, 1, 27, 13, 227, 29, 457, 221, 127, 5335, 16247, 19559, 19185}},
-{4451, 16, 12553, {1, 3, 5, 7, 29, 21, 23, 157, 197, 87, 1591, 1829, 407, 15885, 14933, 1997}},
-{4452, 16, 12568, {1, 1, 1, 9, 3, 35, 43, 187, 195, 325, 197, 2905, 7323, 1563, 7659, 45185}},
-{4453, 16, 12573, {1, 1, 1, 15, 3, 23, 105, 33, 73, 495, 1409, 2583, 1099, 1041, 28955, 60293}},
-{4454, 16, 12592, {1, 3, 7, 13, 25, 19, 99, 137, 139, 719, 529, 1147, 5813, 11551, 30183, 14593}},
-{4455, 16, 12597, {1, 3, 3, 5, 17, 25, 73, 193, 309, 887, 1655, 1641, 2091, 12087, 21881, 1145}},
-{4456, 16, 12601, {1, 3, 1, 1, 27, 41, 13, 151, 83, 645, 327, 1795, 2717, 12433, 22751, 9823}},
-{4457, 16, 12615, {1, 1, 3, 7, 1, 43, 77, 229, 59, 499, 1883, 135, 3461, 9821, 219, 6111}},
-{4458, 16, 12619, {1, 3, 3, 3, 23, 7, 17, 67, 361, 565, 1621, 3253, 7973, 281, 3209, 48215}},
-{4459, 16, 12694, {1, 1, 3, 7, 31, 15, 97, 141, 197, 883, 1689, 269, 7487, 10403, 18903, 58147}},
-{4460, 16, 12697, {1, 3, 3, 3, 23, 9, 87, 125, 359, 527, 1251, 637, 1145, 12721, 14693, 6021}},
-{4461, 16, 12698, {1, 1, 3, 5, 13, 43, 105, 173, 205, 859, 1237, 1227, 1409, 15513, 25317, 30745}},
-{4462, 16, 12713, {1, 3, 3, 15, 31, 43, 125, 149, 145, 109, 975, 1167, 7629, 8373, 5923, 64117}},
-{4463, 16, 12722, {1, 3, 1, 15, 3, 33, 89, 173, 379, 615, 1401, 1567, 4453, 7461, 32555, 64369}},
-{4464, 16, 12733, {1, 3, 7, 11, 27, 23, 45, 7, 15, 21, 1663, 3327, 5611, 8535, 27669, 25525}},
-{4465, 16, 12736, {1, 1, 3, 15, 15, 61, 127, 145, 151, 41, 629, 767, 5801, 3395, 1157, 30033}},
-{4466, 16, 12790, {1, 1, 1, 5, 9, 63, 73, 9, 299, 237, 369, 1295, 4869, 6821, 19961, 32129}},
-{4467, 16, 12794, {1, 1, 5, 13, 19, 7, 119, 35, 319, 405, 1255, 1299, 4311, 14999, 24567, 4001}},
-{4468, 16, 12803, {1, 1, 1, 13, 9, 39, 13, 207, 355, 691, 37, 3137, 6073, 16179, 28661, 41}},
-{4469, 16, 12815, {1, 1, 3, 7, 21, 3, 123, 27, 187, 183, 769, 2367, 2957, 7065, 17855, 60805}},
-{4470, 16, 12829, {1, 1, 1, 1, 19, 31, 71, 85, 303, 617, 1007, 283, 8087, 11079, 11463, 65295}},
-{4471, 16, 12833, {1, 1, 3, 13, 25, 63, 61, 187, 401, 465, 1485, 801, 3649, 7763, 8495, 54479}},
-{4472, 16, 12840, {1, 3, 7, 3, 13, 51, 41, 119, 311, 699, 1113, 3631, 1981, 3259, 25871, 45659}},
-{4473, 16, 12875, {1, 3, 7, 13, 31, 27, 57, 181, 325, 107, 1745, 635, 3941, 3305, 14563, 29855}},
-{4474, 16, 12877, {1, 3, 7, 15, 5, 55, 5, 147, 365, 485, 1841, 3673, 6513, 11121, 5725, 18027}},
-{4475, 16, 12916, {1, 3, 5, 11, 13, 45, 35, 79, 109, 683, 1171, 3015, 2163, 4823, 4365, 42931}},
-{4476, 16, 12923, {1, 1, 7, 7, 13, 45, 57, 39, 297, 985, 1559, 487, 5071, 2657, 9401, 41889}},
-{4477, 16, 12935, {1, 1, 5, 9, 29, 33, 79, 237, 509, 537, 549, 3657, 7141, 15189, 30853, 36089}},
-{4478, 16, 12949, {1, 3, 5, 7, 31, 15, 75, 73, 237, 273, 865, 743, 2607, 7611, 18441, 12703}},
-{4479, 16, 12954, {1, 1, 1, 9, 27, 9, 35, 137, 265, 181, 1341, 1945, 5615, 161, 18369, 4791}},
-{4480, 16, 12956, {1, 3, 7, 11, 27, 29, 29, 43, 489, 177, 1489, 2927, 623, 14571, 22447, 46905}},
-{4481, 16, 12959, {1, 3, 3, 3, 19, 41, 107, 53, 239, 263, 1433, 1655, 7991, 7405, 2735, 25519}},
-{4482, 16, 12978, {1, 3, 5, 7, 19, 37, 73, 243, 215, 445, 1781, 3223, 187, 8443, 18185, 45093}},
-{4483, 16, 13001, {1, 1, 3, 13, 9, 57, 111, 111, 221, 505, 1261, 3045, 1655, 16247, 21033, 17993}},
-{4484, 16, 13010, {1, 1, 7, 5, 7, 55, 77, 5, 131, 969, 1481, 2883, 2645, 3003, 5601, 37063}},
-{4485, 16, 13043, {1, 1, 5, 15, 29, 55, 39, 197, 349, 29, 341, 67, 1977, 425, 4063, 42705}},
-{4486, 16, 13049, {1, 1, 7, 13, 1, 57, 81, 81, 129, 681, 1407, 2465, 3627, 2325, 31649, 18449}},
-{4487, 16, 13058, {1, 3, 5, 5, 23, 59, 35, 217, 393, 155, 1315, 105, 2285, 5167, 27997, 55193}},
-{4488, 16, 13112, {1, 1, 7, 3, 11, 59, 53, 179, 319, 819, 947, 3881, 765, 4219, 16405, 48055}},
-{4489, 16, 13140, {1, 1, 3, 9, 23, 9, 67, 67, 137, 523, 1585, 2441, 167, 5217, 12031, 14297}},
-{4490, 16, 13149, {1, 1, 5, 13, 31, 63, 121, 91, 439, 917, 203, 1519, 4363, 2391, 25755, 26677}},
-{4491, 16, 13163, {1, 1, 3, 5, 25, 31, 11, 95, 339, 817, 35, 3923, 7365, 10537, 5521, 54579}},
-{4492, 16, 13187, {1, 3, 7, 1, 3, 33, 47, 13, 139, 445, 1357, 3907, 7495, 8789, 26589, 43479}},
-{4493, 16, 13196, {1, 1, 1, 11, 5, 45, 61, 13, 167, 287, 931, 881, 5713, 12937, 12951, 21597}},
-{4494, 16, 13237, {1, 3, 5, 1, 29, 23, 7, 117, 503, 897, 733, 1113, 7205, 11507, 561, 34011}},
-{4495, 16, 13244, {1, 3, 5, 7, 3, 51, 21, 147, 35, 259, 689, 3801, 2481, 9673, 4065, 595}},
-{4496, 16, 13264, {1, 3, 3, 9, 9, 29, 5, 191, 393, 979, 1627, 937, 75, 2339, 24007, 30555}},
-{4497, 16, 13279, {1, 1, 5, 7, 9, 35, 111, 23, 113, 563, 1689, 1575, 6127, 9919, 2555, 52261}},
-{4498, 16, 13292, {1, 3, 1, 5, 31, 21, 117, 159, 473, 279, 1281, 311, 159, 3343, 27761, 59989}},
-{4499, 16, 13295, {1, 1, 5, 1, 23, 31, 67, 241, 401, 69, 933, 777, 267, 12411, 23767, 9047}},
-{4500, 16, 13307, {1, 1, 5, 1, 15, 49, 99, 15, 267, 913, 1581, 3713, 651, 14275, 10103, 57619}},
-{4501, 16, 13312, {1, 3, 5, 9, 19, 23, 95, 5, 449, 153, 1195, 1315, 2347, 12683, 10865, 50703}},
-{4502, 16, 13317, {1, 1, 1, 13, 17, 17, 115, 31, 135, 725, 795, 1695, 6199, 4179, 5223, 48457}},
-{4503, 16, 13327, {1, 3, 5, 15, 31, 15, 3, 247, 385, 269, 1665, 581, 2809, 6333, 7459, 14815}},
-{4504, 16, 13348, {1, 3, 7, 5, 15, 35, 117, 85, 11, 621, 1523, 981, 511, 14113, 4673, 22683}},
-{4505, 16, 13390, {1, 1, 7, 1, 27, 61, 119, 249, 431, 147, 173, 423, 1353, 4747, 12761, 32947}},
-{4506, 16, 13413, {1, 3, 7, 1, 23, 39, 15, 153, 219, 359, 1233, 169, 2817, 11043, 12435, 30135}},
-{4507, 16, 13417, {1, 1, 5, 1, 1, 55, 39, 1, 151, 865, 125, 2351, 6315, 1165, 20163, 43991}},
-{4508, 16, 13418, {1, 1, 3, 9, 25, 41, 115, 221, 129, 265, 1887, 4057, 7523, 13591, 5735, 59645}},
-{4509, 16, 13451, {1, 1, 5, 5, 19, 15, 9, 77, 511, 627, 153, 2015, 247, 15949, 9715, 45411}},
-{4510, 16, 13475, {1, 1, 7, 7, 17, 17, 107, 183, 39, 647, 1339, 3915, 4937, 537, 27011, 58937}},
-{4511, 16, 13482, {1, 3, 3, 13, 3, 3, 69, 201, 431, 65, 683, 121, 7017, 2791, 16713, 62555}},
-{4512, 16, 13510, {1, 3, 7, 3, 7, 41, 117, 237, 23, 757, 545, 3899, 1837, 5555, 7891, 29151}},
-{4513, 16, 13527, {1, 1, 1, 3, 27, 15, 39, 195, 353, 299, 1431, 2279, 1795, 13773, 24915, 49701}},
-{4514, 16, 13543, {1, 1, 5, 5, 7, 7, 125, 5, 401, 523, 1967, 2471, 7279, 7559, 12025, 60599}},
-{4515, 16, 13547, {1, 1, 1, 13, 13, 59, 13, 249, 465, 847, 1483, 975, 7729, 2773, 15745, 51237}},
-{4516, 16, 13627, {1, 1, 7, 9, 31, 41, 115, 141, 247, 355, 1109, 3239, 6495, 4515, 30145, 47705}},
-{4517, 16, 13650, {1, 1, 3, 13, 29, 41, 69, 179, 45, 271, 1909, 3095, 7199, 14049, 9903, 33383}},
-{4518, 16, 13683, {1, 1, 3, 13, 7, 45, 105, 105, 243, 121, 67, 3169, 237, 137, 4175, 54325}},
-{4519, 16, 13696, {1, 3, 3, 11, 19, 51, 93, 155, 79, 579, 1621, 1251, 7639, 15875, 25815, 56063}},
-{4520, 16, 13702, {1, 3, 3, 9, 27, 27, 77, 45, 217, 965, 1045, 875, 4515, 11261, 27859, 757}},
-{4521, 16, 13713, {1, 1, 3, 11, 17, 7, 81, 37, 299, 765, 977, 3371, 3163, 13267, 18345, 9239}},
-{4522, 16, 13739, {1, 1, 1, 3, 15, 23, 115, 11, 183, 511, 557, 3253, 153, 8465, 22659, 42143}},
-{4523, 16, 13749, {1, 1, 5, 13, 17, 61, 127, 219, 225, 981, 615, 731, 4069, 12637, 11601, 38257}},
-{4524, 16, 13767, {1, 1, 5, 3, 29, 3, 73, 79, 393, 779, 823, 2473, 3811, 4417, 9399, 50011}},
-{4525, 16, 13774, {1, 3, 3, 9, 21, 35, 61, 99, 115, 657, 629, 1129, 2355, 12665, 459, 40831}},
-{4526, 16, 13781, {1, 3, 1, 7, 25, 61, 53, 249, 15, 649, 665, 595, 1441, 8035, 5381, 7147}},
-{4527, 16, 13795, {1, 3, 1, 7, 19, 9, 27, 207, 205, 461, 1069, 4039, 6549, 2333, 29, 50067}},
-{4528, 16, 13821, {1, 1, 5, 3, 15, 7, 115, 205, 71, 73, 53, 71, 6049, 15293, 17041, 20313}},
-{4529, 16, 13825, {1, 1, 7, 7, 9, 7, 119, 99, 357, 729, 2041, 3355, 5333, 1263, 30521, 64867}},
-{4530, 16, 13838, {1, 1, 1, 7, 31, 63, 63, 159, 281, 295, 913, 2161, 8033, 13789, 17711, 14915}},
-{4531, 16, 13852, {1, 1, 7, 9, 29, 55, 69, 129, 453, 361, 1883, 17, 1765, 111, 10311, 55019}},
-{4532, 16, 13879, {1, 1, 5, 9, 21, 15, 31, 57, 291, 915, 945, 1775, 5905, 9073, 3271, 15571}},
-{4533, 16, 13888, {1, 1, 1, 7, 21, 11, 1, 9, 167, 143, 1535, 1267, 6675, 13037, 19513, 52027}},
-{4534, 16, 13897, {1, 3, 3, 7, 31, 45, 57, 105, 63, 121, 631, 679, 3873, 16333, 32069, 64725}},
-{4535, 16, 13906, {1, 1, 1, 9, 23, 41, 29, 207, 489, 319, 905, 3147, 4195, 2697, 5281, 1771}},
-{4536, 16, 13939, {1, 1, 1, 9, 25, 33, 57, 201, 405, 111, 407, 3489, 449, 8601, 1273, 42105}},
-{4537, 16, 13962, {1, 1, 1, 3, 19, 45, 123, 159, 237, 173, 781, 787, 7537, 15453, 25567, 53729}},
-{4538, 16, 13981, {1, 1, 7, 3, 29, 9, 89, 207, 345, 685, 1701, 2859, 8065, 9289, 2459, 28367}},
-{4539, 16, 13985, {1, 3, 1, 3, 31, 41, 55, 241, 81, 1001, 595, 1725, 853, 11427, 20617, 1717}},
-{4540, 16, 14020, {1, 1, 3, 3, 9, 45, 121, 69, 177, 1017, 211, 2753, 6923, 1387, 32063, 45337}},
-{4541, 16, 14030, {1, 1, 5, 15, 21, 23, 95, 61, 485, 403, 619, 3035, 4881, 13423, 17815, 35221}},
-{4542, 16, 14041, {1, 1, 3, 3, 3, 59, 23, 69, 77, 309, 227, 2877, 3739, 3539, 20083, 23415}},
-{4543, 16, 14047, {1, 3, 7, 3, 17, 43, 95, 239, 223, 353, 1237, 3239, 1369, 7245, 32401, 63889}},
-{4544, 16, 14048, {1, 1, 1, 5, 25, 63, 123, 3, 291, 819, 793, 241, 5619, 8871, 18341, 2757}},
-{4545, 16, 14066, {1, 3, 7, 15, 3, 21, 17, 97, 395, 333, 909, 3783, 3635, 751, 24227, 44281}},
-{4546, 16, 14092, {1, 3, 7, 13, 29, 49, 123, 195, 191, 159, 211, 1887, 3047, 4871, 2607, 32425}},
-{4547, 16, 14120, {1, 1, 7, 7, 15, 57, 91, 255, 267, 897, 441, 1581, 953, 6951, 17275, 50229}},
-{4548, 16, 14126, {1, 3, 7, 15, 1, 35, 91, 219, 7, 117, 119, 2687, 1215, 9517, 10849, 28347}},
-{4549, 16, 14131, {1, 1, 1, 1, 21, 55, 67, 221, 503, 883, 1037, 2965, 1485, 8557, 28091, 25459}},
-{4550, 16, 14143, {1, 3, 5, 9, 19, 3, 73, 123, 95, 307, 1339, 3669, 5077, 12049, 523, 21457}},
-{4551, 16, 14146, {1, 3, 1, 13, 3, 1, 111, 97, 371, 697, 1989, 3715, 7875, 6841, 7009, 17809}},
-{4552, 16, 14152, {1, 1, 1, 9, 25, 21, 19, 43, 329, 531, 491, 1147, 1469, 12841, 29651, 29517}},
-{4553, 16, 14155, {1, 1, 5, 1, 15, 63, 101, 197, 477, 245, 341, 61, 3803, 10001, 5519, 19083}},
-{4554, 16, 14157, {1, 3, 7, 5, 13, 43, 7, 143, 291, 531, 1727, 871, 7091, 5737, 24285, 51017}},
-{4555, 16, 14188, {1, 3, 5, 1, 17, 13, 15, 85, 361, 153, 989, 1367, 4705, 3599, 4441, 52471}},
-{4556, 16, 14206, {1, 1, 7, 13, 21, 43, 111, 29, 299, 439, 1929, 283, 5901, 14113, 3929, 55843}},
-{4557, 16, 14243, {1, 3, 3, 9, 31, 59, 63, 43, 91, 171, 733, 1359, 425, 8505, 19777, 54723}},
-{4558, 16, 14278, {1, 1, 5, 7, 31, 1, 97, 253, 331, 307, 1749, 2115, 2535, 9945, 11013, 14231}},
-{4559, 16, 14308, {1, 1, 5, 11, 13, 7, 109, 237, 301, 383, 683, 1603, 6393, 2437, 12101, 1767}},
-{4560, 16, 14317, {1, 1, 3, 11, 15, 61, 119, 199, 109, 265, 1431, 1729, 3409, 10129, 16945, 34681}},
-{4561, 16, 14335, {1, 3, 7, 9, 13, 59, 121, 73, 29, 513, 279, 457, 7985, 15199, 10185, 33621}},
-{4562, 16, 14354, {1, 3, 7, 7, 23, 17, 27, 65, 387, 487, 1803, 2789, 461, 11201, 7001, 40229}},
-{4563, 16, 14356, {1, 1, 3, 15, 9, 13, 55, 127, 33, 513, 1055, 643, 505, 3005, 6121, 64147}},
-{4564, 16, 14379, {1, 3, 5, 15, 5, 11, 77, 233, 175, 691, 171, 2491, 6915, 14195, 7845, 36499}},
-{4565, 16, 14381, {1, 1, 5, 11, 19, 45, 103, 207, 99, 645, 1739, 1517, 5907, 16035, 14559, 44007}},
-{4566, 16, 14384, {1, 3, 7, 15, 21, 27, 53, 107, 89, 291, 983, 3527, 1025, 2985, 13747, 32715}},
-{4567, 16, 14389, {1, 1, 3, 15, 23, 17, 27, 209, 77, 959, 813, 3597, 5809, 693, 10325, 16855}},
-{4568, 16, 14390, {1, 1, 7, 11, 23, 53, 123, 99, 211, 935, 1371, 1657, 4699, 2683, 27933, 21451}},
-{4569, 16, 14414, {1, 3, 3, 3, 17, 21, 93, 201, 423, 351, 1639, 227, 5719, 13111, 5993, 44615}},
-{4570, 16, 14425, {1, 1, 7, 3, 13, 49, 59, 255, 213, 147, 1441, 3593, 6419, 15657, 1947, 62713}},
-{4571, 16, 14462, {1, 3, 1, 7, 7, 41, 79, 135, 275, 585, 925, 3139, 4351, 1827, 23533, 63031}},
-{4572, 16, 14472, {1, 1, 7, 3, 11, 1, 13, 149, 29, 897, 1043, 2393, 3931, 6741, 19973, 46303}},
-{4573, 16, 14508, {1, 1, 1, 13, 13, 57, 9, 253, 149, 67, 1531, 4049, 3013, 13947, 3371, 35317}},
-{4574, 16, 14511, {1, 3, 1, 1, 15, 19, 11, 125, 179, 383, 1273, 1551, 6441, 6579, 19659, 31005}},
-{4575, 16, 14519, {1, 1, 3, 15, 29, 37, 11, 199, 273, 663, 549, 3167, 2049, 8815, 30719, 47905}},
-{4576, 16, 14528, {1, 1, 1, 15, 7, 9, 113, 231, 155, 27, 419, 1303, 4493, 5633, 5743, 51335}},
-{4577, 16, 14561, {1, 3, 5, 13, 21, 35, 7, 63, 391, 637, 2011, 841, 5933, 10563, 7593, 34767}},
-{4578, 16, 14574, {1, 3, 1, 15, 19, 13, 89, 127, 507, 715, 1305, 2989, 7551, 1953, 26101, 54913}},
-{4579, 16, 14588, {1, 1, 5, 1, 1, 33, 101, 211, 173, 761, 177, 2721, 6949, 15801, 6639, 21405}},
-{4580, 16, 14594, {1, 3, 1, 13, 15, 23, 113, 177, 43, 743, 57, 3875, 7833, 13619, 17637, 5547}},
-{4581, 16, 14606, {1, 1, 3, 13, 21, 7, 123, 83, 391, 731, 597, 2595, 1949, 14619, 17141, 60595}},
-{4582, 16, 14614, {1, 3, 7, 13, 31, 55, 15, 43, 17, 855, 233, 1411, 1063, 12977, 22159, 59185}},
-{4583, 16, 14639, {1, 3, 7, 7, 17, 53, 67, 37, 245, 941, 1213, 1965, 6635, 10189, 12979, 63503}},
-{4584, 16, 14641, {1, 1, 5, 15, 31, 23, 15, 175, 177, 643, 1705, 3541, 2009, 12005, 27281, 16821}},
-{4585, 16, 14648, {1, 3, 1, 13, 27, 37, 1, 171, 255, 445, 171, 3555, 8169, 399, 20975, 36195}},
-{4586, 16, 14668, {1, 3, 7, 11, 13, 15, 123, 65, 173, 317, 1991, 2093, 8073, 12831, 15455, 30175}},
-{4587, 16, 14673, {1, 3, 1, 7, 5, 53, 59, 219, 407, 501, 875, 2627, 1335, 14387, 25523, 28337}},
-{4588, 16, 14679, {1, 3, 3, 13, 13, 41, 93, 125, 41, 461, 887, 1085, 3393, 11945, 16329, 43531}},
-{4589, 16, 14695, {1, 3, 1, 11, 21, 39, 1, 185, 429, 285, 443, 1165, 451, 10903, 31511, 50555}},
-{4590, 16, 14702, {1, 1, 7, 5, 11, 25, 61, 171, 493, 733, 215, 1871, 7783, 14113, 2061, 58961}},
-{4591, 16, 14704, {1, 1, 7, 7, 27, 23, 53, 45, 131, 301, 275, 3855, 4883, 6303, 25269, 12697}},
-{4592, 16, 14740, {1, 3, 5, 7, 11, 15, 71, 101, 377, 803, 1369, 3741, 633, 10571, 30659, 31101}},
-{4593, 16, 14754, {1, 1, 5, 15, 19, 53, 3, 153, 411, 685, 1405, 109, 5755, 13311, 3713, 24579}},
-{4594, 16, 14774, {1, 1, 3, 3, 27, 7, 89, 39, 5, 853, 1757, 2927, 2889, 9735, 17959, 39301}},
-{4595, 16, 14792, {1, 3, 1, 3, 13, 41, 57, 71, 187, 285, 825, 1807, 7261, 2645, 21861, 1839}},
-{4596, 16, 14797, {1, 3, 3, 5, 15, 21, 23, 7, 341, 981, 891, 721, 7221, 3137, 28725, 54993}},
-{4597, 16, 14806, {1, 1, 5, 3, 3, 61, 59, 97, 205, 359, 185, 3361, 7637, 15473, 6351, 62097}},
-{4598, 16, 14812, {1, 1, 1, 9, 13, 11, 123, 71, 199, 251, 535, 371, 1605, 12107, 13833, 2019}},
-{4599, 16, 14856, {1, 1, 7, 13, 27, 1, 43, 73, 409, 601, 1481, 649, 3293, 12257, 23377, 17225}},
-{4600, 16, 14876, {1, 1, 7, 11, 15, 55, 99, 45, 261, 461, 1507, 3575, 4425, 9895, 20191, 61863}},
-{4601, 16, 14900, {1, 3, 7, 1, 3, 7, 19, 85, 139, 691, 1685, 137, 7547, 16143, 14193, 52479}},
-{4602, 16, 14910, {1, 3, 5, 9, 17, 61, 7, 189, 31, 641, 1381, 3999, 4909, 8463, 31761, 54493}},
-{4603, 16, 14912, {1, 1, 5, 15, 17, 15, 69, 111, 55, 1011, 1859, 2643, 6043, 5125, 15875, 611}},
-{4604, 16, 14915, {1, 1, 3, 5, 3, 33, 73, 227, 327, 369, 189, 1841, 5625, 1179, 18651, 34951}},
-{4605, 16, 14922, {1, 3, 7, 13, 1, 17, 109, 149, 89, 889, 799, 3423, 2599, 14525, 12763, 23855}},
-{4606, 16, 14939, {1, 1, 3, 15, 5, 63, 87, 7, 63, 171, 1215, 557, 3009, 16305, 23517, 40101}},
-{4607, 16, 14946, {1, 1, 3, 3, 29, 31, 79, 183, 401, 813, 41, 1111, 5669, 15697, 7813, 10215}},
-{4608, 16, 14955, {1, 1, 5, 7, 9, 25, 25, 57, 343, 375, 535, 3405, 1909, 3201, 2417, 52285}},
-{4609, 16, 14966, {1, 1, 5, 9, 25, 19, 33, 183, 29, 991, 1045, 2249, 2933, 12525, 13943, 10423}},
-{4610, 16, 14976, {1, 3, 1, 7, 3, 45, 49, 37, 429, 67, 821, 1289, 7311, 16165, 25861, 57715}},
-{4611, 16, 14986, {1, 1, 7, 3, 19, 3, 33, 153, 505, 683, 611, 1691, 6421, 15517, 19161, 49013}},
-{4612, 16, 14993, {1, 3, 7, 7, 21, 21, 85, 55, 293, 199, 1671, 1881, 7147, 8241, 16173, 51873}},
-{4613, 16, 15012, {1, 3, 1, 15, 3, 61, 97, 191, 435, 511, 1599, 2705, 1897, 2607, 1801, 48583}},
-{4614, 16, 15041, {1, 1, 5, 3, 9, 23, 23, 185, 401, 947, 33, 385, 7491, 14129, 14561, 13759}},
-{4615, 16, 15053, {1, 3, 5, 15, 19, 21, 37, 233, 149, 673, 29, 1315, 3487, 6705, 28283, 43135}},
-{4616, 16, 15056, {1, 1, 1, 11, 9, 35, 101, 255, 345, 829, 689, 2747, 2145, 2101, 24863, 35529}},
-{4617, 16, 15059, {1, 3, 7, 9, 5, 5, 53, 247, 157, 729, 1621, 129, 2485, 5371, 11115, 47771}},
-{4618, 16, 15110, {1, 1, 3, 9, 29, 29, 13, 229, 87, 281, 1119, 1085, 4423, 1667, 27067, 50397}},
-{4619, 16, 15116, {1, 1, 3, 7, 11, 29, 77, 85, 121, 495, 501, 3209, 3531, 2307, 11367, 34135}},
-{4620, 16, 15133, {1, 1, 7, 9, 3, 37, 33, 209, 493, 869, 367, 3221, 1643, 3353, 22851, 4313}},
-{4621, 16, 15134, {1, 1, 1, 7, 15, 53, 27, 17, 29, 345, 821, 1831, 1963, 10089, 5101, 32689}},
-{4622, 16, 15137, {1, 1, 3, 9, 9, 61, 31, 215, 497, 591, 1301, 157, 3329, 13877, 9017, 34673}},
-{4623, 16, 15147, {1, 1, 5, 1, 29, 49, 93, 139, 279, 167, 143, 279, 6145, 6247, 519, 8869}},
-{4624, 16, 15182, {1, 3, 3, 1, 25, 41, 81, 219, 505, 335, 1941, 2963, 413, 775, 4181, 55269}},
-{4625, 16, 15203, {1, 1, 1, 11, 27, 23, 91, 9, 497, 811, 1469, 1999, 5377, 2943, 17635, 11151}},
-{4626, 16, 15215, {1, 1, 5, 15, 17, 23, 15, 235, 271, 749, 1873, 3805, 5405, 7421, 24339, 14351}},
-{4627, 16, 15245, {1, 3, 7, 1, 5, 61, 81, 9, 269, 43, 1391, 2711, 6973, 11299, 2263, 8715}},
-{4628, 16, 15246, {1, 1, 5, 13, 11, 1, 69, 235, 25, 227, 63, 2591, 913, 12555, 6263, 38981}},
-{4629, 16, 15264, {1, 3, 1, 7, 17, 7, 97, 251, 149, 959, 1895, 1179, 4031, 15975, 20313, 64067}},
-{4630, 16, 15269, {1, 3, 7, 15, 3, 17, 85, 229, 149, 925, 585, 3755, 2359, 13131, 12665, 28861}},
-{4631, 16, 15296, {1, 3, 3, 9, 5, 31, 107, 93, 347, 851, 1249, 2161, 6095, 8315, 20259, 39527}},
-{4632, 16, 15314, {1, 3, 7, 7, 21, 63, 85, 241, 501, 627, 1211, 1713, 6907, 4229, 7557, 55719}},
-{4633, 16, 15323, {1, 1, 1, 13, 19, 43, 21, 177, 13, 353, 679, 511, 5565, 993, 25345, 25087}},
-{4634, 16, 15364, {1, 3, 3, 15, 21, 15, 87, 83, 381, 547, 1429, 2417, 2425, 2097, 20889, 12353}},
-{4635, 16, 15386, {1, 3, 1, 11, 23, 21, 69, 147, 427, 271, 1829, 525, 2951, 10773, 32425, 17685}},
-{4636, 16, 15391, {1, 3, 1, 7, 15, 55, 21, 131, 195, 927, 635, 3505, 3817, 14883, 1149, 10079}},
-{4637, 16, 15436, {1, 3, 3, 9, 23, 15, 45, 147, 249, 87, 377, 1551, 4343, 15373, 2895, 44973}},
-{4638, 16, 15460, {1, 3, 1, 7, 31, 63, 67, 107, 109, 1019, 815, 231, 8135, 559, 8175, 21735}},
-{4639, 16, 15464, {1, 1, 5, 7, 7, 63, 103, 133, 167, 883, 1647, 2827, 6015, 8541, 16963, 37129}},
-{4640, 16, 15469, {1, 3, 5, 9, 27, 25, 59, 147, 29, 943, 865, 1233, 2165, 15259, 2235, 25831}},
-{4641, 16, 15470, {1, 1, 5, 7, 25, 5, 67, 89, 493, 111, 359, 1115, 7963, 6545, 7749, 29179}},
-{4642, 16, 15477, {1, 3, 7, 5, 19, 17, 89, 195, 337, 115, 1417, 3837, 4761, 1959, 16205, 61597}},
-{4643, 16, 15488, {1, 1, 5, 11, 25, 43, 3, 111, 491, 897, 1541, 909, 4751, 739, 7827, 64485}},
-{4644, 16, 15494, {1, 1, 5, 15, 19, 61, 39, 111, 451, 419, 1657, 2427, 4589, 5577, 23967, 19259}},
-{4645, 16, 15548, {1, 3, 3, 1, 31, 15, 7, 131, 329, 847, 537, 1775, 3833, 5683, 17267, 16389}},
-{4646, 16, 15551, {1, 1, 7, 1, 9, 29, 13, 25, 409, 513, 1695, 2175, 5099, 727, 5723, 43547}},
-{4647, 16, 15560, {1, 1, 5, 7, 13, 11, 29, 123, 127, 193, 1647, 3157, 2149, 16209, 19909, 14473}},
-{4648, 16, 15563, {1, 1, 1, 15, 15, 37, 125, 157, 487, 143, 1891, 2895, 4397, 10685, 1463, 55027}},
-{4649, 16, 15604, {1, 3, 7, 1, 1, 15, 115, 105, 479, 529, 1095, 2687, 4483, 15027, 15487, 7113}},
-{4650, 16, 15607, {1, 1, 3, 9, 23, 63, 113, 211, 155, 931, 175, 3037, 2359, 10413, 24561, 21099}},
-{4651, 16, 15616, {1, 3, 3, 11, 5, 15, 13, 37, 257, 447, 203, 545, 2467, 9979, 17543, 62703}},
-{4652, 16, 15631, {1, 1, 3, 7, 17, 31, 83, 91, 79, 265, 1415, 2347, 5337, 7615, 27739, 33841}},
-{4653, 16, 15699, {1, 3, 5, 7, 17, 63, 37, 153, 347, 909, 1945, 7, 2071, 15195, 32083, 26713}},
-{4654, 16, 15701, {1, 1, 3, 11, 19, 51, 69, 21, 323, 635, 443, 1685, 6275, 13787, 20921, 45553}},
-{4655, 16, 15708, {1, 3, 3, 7, 15, 35, 67, 247, 257, 429, 2029, 523, 3219, 3893, 26677, 53273}},
-{4656, 16, 15739, {1, 1, 7, 9, 9, 3, 119, 121, 445, 149, 1539, 1887, 2995, 14867, 809, 48065}},
-{4657, 16, 15746, {1, 3, 5, 13, 15, 27, 75, 9, 217, 35, 1363, 2383, 4357, 1153, 20565, 62277}},
-{4658, 16, 15772, {1, 1, 7, 1, 21, 1, 11, 53, 331, 765, 407, 453, 2725, 11199, 645, 14915}},
-{4659, 16, 15793, {1, 1, 5, 1, 29, 11, 5, 159, 395, 53, 323, 1347, 5529, 8525, 24003, 20535}},
-{4660, 16, 15832, {1, 3, 3, 15, 9, 19, 87, 181, 391, 639, 703, 611, 997, 359, 2471, 58465}},
-{4661, 16, 15837, {1, 3, 5, 9, 27, 9, 117, 47, 223, 509, 1537, 1235, 3885, 6767, 17131, 63421}},
-{4662, 16, 15866, {1, 1, 5, 1, 15, 15, 113, 67, 477, 597, 1795, 3065, 4565, 3609, 16419, 19667}},
-{4663, 16, 15899, {1, 1, 7, 11, 1, 63, 33, 211, 271, 773, 499, 2309, 1303, 14015, 30377, 53195}},
-{4664, 16, 15911, {1, 1, 7, 11, 5, 23, 17, 183, 321, 315, 203, 3371, 907, 9331, 21031, 33765}},
-{4665, 16, 15918, {1, 3, 3, 7, 7, 53, 111, 69, 441, 283, 195, 2415, 7293, 7659, 2731, 5417}},
-{4666, 16, 15952, {1, 3, 5, 15, 3, 61, 5, 241, 427, 463, 1729, 653, 7671, 10979, 7247, 36931}},
-{4667, 16, 15962, {1, 3, 1, 9, 3, 5, 105, 117, 465, 853, 2005, 3925, 4419, 4441, 3701, 50747}},
-{4668, 16, 15967, {1, 1, 3, 7, 1, 3, 3, 149, 65, 405, 299, 99, 481, 14323, 11565, 6227}},
-{4669, 16, 15973, {1, 3, 7, 5, 29, 3, 19, 3, 253, 895, 879, 2435, 2151, 10673, 11013, 43055}},
-{4670, 16, 15977, {1, 3, 1, 11, 15, 57, 127, 197, 319, 913, 1039, 811, 7767, 5791, 31725, 8733}},
-{4671, 16, 16016, {1, 1, 7, 3, 13, 25, 25, 81, 229, 185, 39, 2789, 579, 4973, 28617, 60871}},
-{4672, 16, 16035, {1, 1, 7, 3, 25, 17, 41, 7, 103, 269, 55, 2651, 7579, 10935, 8917, 14323}},
-{4673, 16, 16044, {1, 3, 7, 7, 13, 7, 99, 205, 293, 877, 1893, 3013, 2389, 6021, 2645, 18175}},
-{4674, 16, 16067, {1, 1, 3, 7, 9, 39, 59, 187, 191, 761, 339, 3381, 2921, 5197, 16963, 43019}},
-{4675, 16, 16082, {1, 3, 3, 13, 7, 23, 41, 203, 311, 981, 323, 1675, 6689, 579, 3885, 64475}},
-{4676, 16, 16084, {1, 3, 5, 15, 21, 39, 35, 193, 167, 1009, 493, 829, 6571, 1299, 13061, 1163}},
-{4677, 16, 16098, {1, 1, 3, 5, 3, 19, 123, 123, 111, 599, 193, 3419, 7173, 5595, 12449, 52247}},
-{4678, 16, 16107, {1, 3, 5, 11, 9, 25, 65, 49, 239, 953, 481, 3455, 4335, 305, 22469, 11949}},
-{4679, 16, 16142, {1, 1, 3, 7, 15, 1, 13, 77, 147, 49, 1445, 931, 3405, 15951, 15215, 26451}},
-{4680, 16, 16149, {1, 3, 1, 1, 21, 53, 17, 7, 247, 243, 805, 795, 489, 13351, 13493, 30937}},
-{4681, 16, 16165, {1, 3, 7, 5, 5, 13, 39, 115, 397, 757, 423, 2559, 1677, 9449, 24563, 869}},
-{4682, 16, 16172, {1, 1, 3, 11, 23, 9, 27, 233, 165, 853, 1721, 599, 551, 11657, 27623, 40119}},
-{4683, 16, 16178, {1, 1, 3, 1, 3, 47, 75, 207, 113, 417, 1317, 2215, 2395, 1841, 23125, 50401}},
-{4684, 16, 16197, {1, 3, 3, 1, 13, 55, 103, 55, 351, 785, 1665, 3603, 7705, 4811, 21129, 38115}},
-{4685, 16, 16201, {1, 1, 1, 5, 5, 49, 93, 189, 317, 701, 1545, 1017, 4133, 7655, 19827, 52155}},
-{4686, 16, 16215, {1, 3, 3, 13, 17, 37, 7, 249, 139, 529, 235, 3801, 7871, 459, 15127, 13231}},
-{4687, 16, 16221, {1, 3, 7, 5, 7, 63, 99, 241, 131, 455, 1287, 3539, 8029, 12661, 23313, 54029}},
-{4688, 16, 16226, {1, 3, 1, 3, 29, 63, 51, 227, 497, 685, 1351, 449, 7851, 10815, 17379, 62097}},
-{4689, 16, 16232, {1, 3, 1, 11, 25, 61, 73, 29, 467, 533, 855, 853, 5557, 10953, 18307, 27135}},
-{4690, 16, 16246, {1, 1, 7, 3, 13, 49, 63, 171, 177, 283, 1365, 3087, 5445, 15109, 12523, 25193}},
-{4691, 16, 16261, {1, 3, 5, 15, 9, 39, 95, 81, 417, 199, 1653, 3673, 2663, 8101, 12199, 22759}},
-{4692, 16, 16279, {1, 1, 3, 9, 29, 15, 29, 215, 21, 721, 245, 1197, 7251, 5721, 6735, 7751}},
-{4693, 16, 16280, {1, 3, 5, 5, 21, 7, 81, 61, 157, 707, 819, 1689, 4203, 5559, 25483, 43325}},
-{4694, 16, 16290, {1, 1, 7, 13, 15, 51, 47, 197, 269, 921, 353, 2865, 6227, 537, 20015, 53823}},
-{4695, 16, 16314, {1, 1, 3, 5, 13, 25, 91, 221, 111, 587, 1119, 2343, 4651, 4641, 15915, 36323}},
-{4696, 16, 16345, {1, 1, 7, 11, 1, 45, 7, 215, 483, 545, 731, 3041, 3121, 8681, 20651, 4069}},
-{4697, 16, 16355, {1, 3, 7, 13, 13, 27, 109, 65, 103, 805, 299, 2069, 6017, 14565, 20505, 16161}},
-{4698, 16, 16361, {1, 1, 7, 5, 11, 33, 105, 213, 237, 583, 1033, 2333, 845, 6493, 505, 2563}},
-{4699, 16, 16393, {1, 1, 5, 7, 3, 5, 11, 173, 373, 341, 269, 177, 3175, 9413, 601, 13591}},
-{4700, 16, 16394, {1, 1, 5, 13, 7, 57, 61, 187, 121, 405, 665, 111, 7535, 3355, 14051, 511}},
-{4701, 16, 16438, {1, 1, 1, 3, 3, 29, 15, 253, 227, 123, 333, 1343, 7313, 1955, 17741, 30831}},
-{4702, 16, 16450, {1, 3, 5, 1, 5, 47, 65, 183, 199, 839, 925, 2711, 4609, 201, 15177, 29817}},
-{4703, 16, 16507, {1, 3, 7, 9, 21, 63, 5, 163, 265, 581, 1795, 3937, 4641, 2073, 32225, 60831}},
-{4704, 16, 16523, {1, 1, 1, 5, 7, 47, 125, 203, 511, 841, 1937, 3431, 1495, 12827, 5893, 19265}},
-{4705, 16, 16533, {1, 1, 5, 5, 9, 49, 17, 247, 391, 241, 3, 2253, 6319, 89, 4449, 6371}},
-{4706, 16, 16603, {1, 3, 1, 1, 31, 7, 51, 61, 461, 391, 273, 1609, 5825, 16029, 3851, 39213}},
-{4707, 16, 16648, {1, 3, 3, 7, 29, 21, 65, 75, 317, 925, 1319, 3827, 965, 5685, 17007, 64365}},
-{4708, 16, 16653, {1, 3, 1, 5, 23, 23, 109, 59, 31, 659, 635, 2209, 857, 9847, 2507, 18325}},
-{4709, 16, 16672, {1, 1, 1, 1, 17, 51, 53, 77, 461, 147, 229, 2821, 2405, 1259, 1121, 17429}},
-{4710, 16, 16682, {1, 3, 5, 3, 31, 3, 57, 157, 321, 731, 1609, 2139, 899, 12599, 19803, 51083}},
-{4711, 16, 16709, {1, 1, 3, 11, 27, 43, 73, 209, 431, 587, 1247, 2803, 3593, 1351, 18701, 33423}},
-{4712, 16, 16713, {1, 3, 5, 13, 27, 19, 67, 245, 339, 879, 2035, 1801, 5845, 3883, 22057, 15771}},
-{4713, 16, 16719, {1, 1, 3, 11, 11, 55, 93, 51, 57, 127, 1325, 3975, 3989, 2347, 18831, 2979}},
-{4714, 16, 16733, {1, 1, 1, 13, 17, 1, 17, 103, 303, 777, 1973, 2943, 7439, 8953, 27227, 10229}},
-{4715, 16, 16740, {1, 3, 3, 15, 1, 41, 53, 219, 415, 399, 995, 205, 7719, 10937, 31879, 755}},
-{4716, 16, 16761, {1, 3, 7, 9, 13, 7, 99, 93, 419, 1019, 1605, 161, 3831, 9147, 7877, 1333}},
-{4717, 16, 16767, {1, 3, 7, 15, 5, 51, 37, 115, 259, 549, 353, 2067, 7657, 1283, 20333, 2325}},
-{4718, 16, 16771, {1, 1, 3, 3, 23, 33, 63, 233, 363, 719, 1099, 471, 3079, 10577, 19063, 31535}},
-{4719, 16, 16788, {1, 3, 7, 15, 23, 19, 109, 105, 497, 881, 1055, 537, 4607, 239, 22785, 60201}},
-{4720, 16, 16811, {1, 3, 3, 5, 19, 11, 1, 207, 163, 437, 713, 667, 1427, 7505, 28055, 43101}},
-{4721, 16, 16814, {1, 3, 5, 5, 25, 45, 75, 9, 109, 545, 573, 2685, 1013, 2973, 18619, 55945}},
-{4722, 16, 16816, {1, 1, 1, 3, 27, 27, 39, 33, 285, 453, 613, 2707, 2155, 4355, 21105, 7969}},
-{4723, 16, 16828, {1, 3, 3, 9, 1, 31, 71, 101, 491, 409, 65, 1479, 5743, 525, 2863, 53657}},
-{4724, 16, 16834, {1, 1, 3, 1, 17, 63, 55, 11, 125, 447, 275, 2243, 6827, 5753, 32401, 13819}},
-{4725, 16, 16863, {1, 1, 3, 9, 21, 47, 5, 127, 285, 471, 1681, 945, 6141, 5651, 10273, 30811}},
-{4726, 16, 16864, {1, 3, 3, 1, 13, 53, 91, 3, 255, 429, 107, 2937, 2971, 10251, 15009, 37477}},
-{4727, 16, 16879, {1, 1, 7, 13, 21, 63, 73, 3, 63, 491, 101, 1981, 7457, 879, 6243, 22275}},
-{4728, 16, 16888, {1, 3, 1, 1, 11, 43, 121, 101, 293, 639, 645, 2723, 2075, 3629, 22105, 18199}},
-{4729, 16, 16904, {1, 1, 3, 1, 31, 9, 69, 97, 511, 663, 1147, 1237, 389, 255, 8661, 38533}},
-{4730, 16, 16909, {1, 3, 3, 7, 3, 13, 23, 71, 197, 439, 2003, 1771, 8073, 1549, 29089, 5409}},
-{4731, 16, 16921, {1, 3, 1, 1, 9, 23, 1, 221, 159, 699, 593, 3385, 3869, 10105, 22097, 34753}},
-{4732, 16, 16934, {1, 1, 7, 1, 29, 47, 41, 137, 333, 357, 325, 3151, 6641, 3823, 8763, 28327}},
-{4733, 16, 16951, {1, 3, 1, 7, 19, 19, 39, 225, 477, 619, 583, 229, 6177, 9615, 1203, 13711}},
-{4734, 16, 16983, {1, 1, 3, 13, 9, 41, 127, 147, 13, 301, 861, 2019, 3517, 1147, 21587, 42387}},
-{4735, 16, 16999, {1, 1, 5, 11, 9, 63, 11, 121, 251, 199, 483, 2287, 4667, 3887, 10611, 6019}},
-{4736, 16, 17000, {1, 1, 3, 13, 23, 19, 89, 73, 355, 399, 749, 687, 5707, 11443, 817, 38967}},
-{4737, 16, 17006, {1, 3, 5, 9, 3, 23, 115, 207, 373, 541, 73, 1285, 7245, 12505, 5787, 61207}},
-{4738, 16, 17020, {1, 3, 5, 15, 27, 37, 115, 203, 195, 793, 1577, 1283, 7299, 4025, 5319, 5375}},
-{4739, 16, 17030, {1, 1, 7, 15, 25, 19, 61, 11, 215, 771, 1057, 451, 1965, 13693, 25617, 42657}},
-{4740, 16, 17033, {1, 3, 3, 7, 1, 19, 23, 217, 175, 901, 2009, 2989, 5111, 5027, 4805, 37843}},
-{4741, 16, 17044, {1, 3, 1, 11, 11, 37, 3, 131, 459, 769, 201, 3979, 3009, 8691, 27005, 32175}},
-{4742, 16, 17051, {1, 3, 5, 7, 27, 27, 117, 23, 403, 1003, 1501, 785, 6313, 10187, 5085, 30751}},
-{4743, 16, 17072, {1, 1, 7, 3, 11, 41, 73, 151, 19, 657, 131, 1901, 3879, 14995, 24085, 56621}},
-{4744, 16, 17078, {1, 3, 7, 15, 23, 3, 61, 199, 67, 483, 1961, 3583, 5937, 5749, 16685, 11831}},
-{4745, 16, 17084, {1, 1, 3, 15, 25, 15, 97, 9, 299, 641, 883, 2901, 123, 1523, 7055, 15609}},
-{4746, 16, 17087, {1, 3, 5, 5, 31, 55, 19, 45, 239, 543, 2005, 1041, 1711, 11059, 19927, 17475}},
-{4747, 16, 17090, {1, 1, 3, 9, 5, 59, 105, 209, 323, 613, 1963, 2227, 2947, 11761, 21375, 13265}},
-{4748, 16, 17123, {1, 3, 3, 15, 1, 5, 117, 37, 93, 243, 305, 2299, 5163, 9205, 28761, 35987}},
-{4749, 16, 17132, {1, 1, 1, 5, 5, 29, 13, 147, 457, 187, 1729, 1547, 7745, 13155, 7833, 57449}},
-{4750, 16, 17140, {1, 3, 3, 13, 1, 51, 49, 253, 23, 389, 1611, 3045, 5909, 3947, 25105, 3327}},
-{4751, 16, 17149, {1, 3, 1, 11, 15, 47, 19, 15, 231, 57, 763, 1879, 1765, 14861, 22893, 19437}},
-{4752, 16, 17157, {1, 1, 3, 15, 1, 19, 85, 65, 139, 629, 361, 3513, 3807, 799, 8349, 29247}},
-{4753, 16, 17164, {1, 3, 3, 13, 9, 11, 65, 201, 471, 89, 355, 121, 3947, 10775, 3599, 6041}},
-{4754, 16, 17170, {1, 3, 7, 3, 5, 53, 33, 167, 431, 129, 1449, 3263, 7691, 12569, 7551, 41101}},
-{4755, 16, 17179, {1, 1, 3, 15, 9, 41, 5, 239, 361, 773, 955, 3663, 6051, 12889, 5841, 59615}},
-{4756, 16, 17237, {1, 1, 7, 5, 5, 33, 97, 9, 495, 845, 1953, 3533, 5715, 15055, 25211, 9351}},
-{4757, 16, 17248, {1, 3, 1, 11, 25, 37, 83, 153, 289, 739, 353, 1121, 7641, 2081, 28439, 38085}},
-{4758, 16, 17260, {1, 3, 1, 1, 27, 9, 63, 135, 395, 641, 1759, 3727, 4371, 5193, 2783, 12389}},
-{4759, 16, 17272, {1, 3, 3, 15, 3, 9, 5, 153, 111, 675, 1957, 3817, 4269, 10787, 3413, 34199}},
-{4760, 16, 17275, {1, 3, 5, 9, 23, 23, 97, 137, 255, 249, 333, 2329, 1055, 13769, 13109, 33443}},
-{4761, 16, 17287, {1, 1, 1, 15, 7, 37, 99, 219, 483, 755, 263, 3523, 6179, 4817, 29873, 12771}},
-{4762, 16, 17294, {1, 1, 3, 5, 23, 7, 77, 97, 105, 631, 175, 1911, 7271, 1009, 24081, 61207}},
-{4763, 16, 17296, {1, 3, 5, 3, 1, 31, 71, 91, 265, 669, 1839, 3989, 8127, 15001, 1419, 8895}},
-{4764, 16, 17305, {1, 3, 1, 13, 27, 51, 93, 155, 49, 991, 653, 203, 3863, 5363, 31969, 36083}},
-{4765, 16, 17312, {1, 3, 3, 7, 31, 27, 21, 73, 21, 675, 407, 1215, 2963, 6799, 15259, 13125}},
-{4766, 16, 17321, {1, 3, 5, 13, 5, 53, 19, 215, 243, 487, 689, 2519, 6393, 3987, 30847, 37919}},
-{4767, 16, 17367, {1, 3, 3, 7, 5, 31, 115, 231, 255, 955, 2023, 1487, 6575, 9873, 22585, 29951}},
-{4768, 16, 17368, {1, 3, 5, 11, 11, 57, 109, 203, 417, 29, 1311, 893, 1047, 2413, 9305, 38219}},
-{4769, 16, 17378, {1, 3, 1, 7, 23, 51, 113, 3, 105, 915, 1145, 3431, 7331, 3323, 31669, 21485}},
-{4770, 16, 17433, {1, 1, 7, 13, 9, 29, 119, 205, 403, 1023, 257, 863, 2983, 1895, 16539, 23385}},
-{4771, 16, 17455, {1, 1, 7, 13, 27, 21, 47, 139, 341, 509, 1107, 2197, 3649, 14301, 30789, 48783}},
-{4772, 16, 17457, {1, 3, 3, 7, 25, 19, 99, 11, 309, 919, 1809, 3015, 1587, 3779, 1289, 30207}},
-{4773, 16, 17508, {1, 3, 5, 11, 9, 43, 57, 171, 9, 151, 173, 2301, 7723, 2083, 319, 52883}},
-{4774, 16, 17559, {1, 1, 3, 1, 3, 13, 63, 11, 231, 117, 1257, 237, 581, 13871, 15501, 8741}},
-{4775, 16, 17560, {1, 3, 5, 9, 13, 63, 55, 155, 291, 721, 123, 929, 3351, 11651, 12513, 1779}},
-{4776, 16, 17582, {1, 3, 7, 3, 31, 5, 61, 81, 465, 639, 1363, 3157, 2401, 9513, 32559, 34477}},
-{4777, 16, 17596, {1, 3, 1, 15, 27, 25, 3, 117, 277, 13, 707, 3825, 7287, 10181, 30127, 57247}},
-{4778, 16, 17599, {1, 1, 7, 11, 21, 21, 53, 17, 407, 851, 1191, 285, 6815, 1595, 25507, 8099}},
-{4779, 16, 17613, {1, 3, 5, 9, 9, 61, 83, 61, 65, 671, 63, 311, 6897, 15327, 29809, 4899}},
-{4780, 16, 17619, {1, 1, 7, 1, 21, 45, 99, 235, 477, 461, 1119, 4087, 2057, 14861, 31969, 24357}},
-{4781, 16, 17622, {1, 1, 7, 9, 31, 9, 65, 123, 281, 273, 1059, 1625, 6265, 9635, 11563, 45053}},
-{4782, 16, 17655, {1, 3, 3, 7, 1, 41, 15, 23, 43, 727, 1271, 1741, 765, 13265, 4145, 1335}},
-{4783, 16, 17661, {1, 1, 3, 7, 17, 55, 107, 231, 263, 197, 659, 3621, 2789, 5171, 28635, 13595}},
-{4784, 16, 17698, {1, 1, 5, 1, 27, 23, 13, 83, 431, 507, 1571, 1573, 1733, 12171, 8181, 30843}},
-{4785, 16, 17712, {1, 3, 7, 11, 1, 53, 107, 39, 497, 579, 453, 1339, 1415, 10317, 2741, 34599}},
-{4786, 16, 17715, {1, 3, 3, 5, 31, 41, 49, 41, 33, 665, 1783, 87, 317, 6603, 22603, 22879}},
-{4787, 16, 17721, {1, 3, 1, 15, 5, 47, 41, 87, 231, 853, 1615, 2299, 4643, 9249, 15641, 14323}},
-{4788, 16, 17722, {1, 3, 7, 9, 5, 45, 55, 153, 31, 247, 67, 2335, 6057, 4379, 27579, 38437}},
-{4789, 16, 17742, {1, 1, 5, 7, 9, 3, 73, 81, 479, 909, 1097, 3945, 4485, 7815, 22855, 20825}},
-{4790, 16, 17778, {1, 3, 1, 15, 19, 43, 97, 57, 339, 167, 135, 1777, 7681, 9715, 13863, 6347}},
-{4791, 16, 17818, {1, 1, 1, 1, 5, 53, 33, 123, 449, 165, 1283, 2977, 5919, 12929, 32073, 61851}},
-{4792, 16, 17836, {1, 1, 5, 15, 27, 27, 19, 157, 267, 651, 1319, 3841, 7739, 9947, 16801, 41325}},
-{4793, 16, 17841, {1, 3, 7, 9, 19, 7, 83, 95, 401, 293, 437, 1983, 119, 7553, 11097, 11925}},
-{4794, 16, 17856, {1, 1, 3, 5, 21, 1, 53, 201, 385, 843, 1801, 99, 2697, 9659, 28789, 31417}},
-{4795, 16, 17883, {1, 1, 5, 5, 29, 57, 103, 89, 77, 597, 1849, 3433, 4267, 11167, 3841, 44023}},
-{4796, 16, 17896, {1, 1, 7, 1, 21, 47, 113, 253, 249, 431, 1899, 2859, 7345, 5725, 14805, 19999}},
-{4797, 16, 17901, {1, 3, 3, 5, 1, 11, 77, 213, 359, 665, 1855, 2743, 2407, 14677, 17957, 63257}},
-{4798, 16, 17926, {1, 3, 7, 13, 23, 29, 127, 183, 275, 849, 1005, 3159, 3867, 13029, 7527, 13035}},
-{4799, 16, 17937, {1, 1, 1, 15, 29, 47, 81, 225, 77, 879, 1279, 1929, 1457, 2025, 32229, 2847}},
-{4800, 16, 17992, {1, 1, 1, 3, 29, 45, 37, 189, 217, 53, 281, 1785, 1929, 763, 5875, 34303}},
-{4801, 16, 17995, {1, 3, 1, 9, 21, 61, 21, 149, 215, 13, 1221, 5, 7153, 14089, 3119, 33115}},
-{4802, 16, 17998, {1, 3, 7, 11, 7, 57, 89, 185, 485, 649, 1765, 747, 2983, 6791, 25015, 13627}},
-{4803, 16, 18021, {1, 1, 1, 9, 11, 53, 77, 203, 425, 237, 487, 2317, 1047, 8277, 23405, 30445}},
-{4804, 16, 18039, {1, 1, 3, 5, 7, 29, 39, 195, 109, 381, 655, 931, 4469, 16215, 10627, 64171}},
-{4805, 16, 18067, {1, 3, 1, 3, 5, 9, 89, 131, 509, 275, 489, 3161, 3701, 11951, 6579, 42839}},
-{4806, 16, 18122, {1, 3, 7, 13, 15, 37, 65, 91, 305, 433, 1815, 169, 3117, 47, 30331, 34863}},
-{4807, 16, 18129, {1, 3, 3, 9, 21, 3, 21, 113, 25, 833, 1579, 4021, 3481, 55, 20833, 46277}},
-{4808, 16, 18130, {1, 1, 1, 5, 19, 37, 61, 229, 61, 363, 817, 1235, 6235, 7261, 29917, 43057}},
-{4809, 16, 18142, {1, 3, 1, 9, 7, 59, 119, 189, 341, 945, 633, 3683, 2589, 15453, 4989, 40055}},
-{4810, 16, 18148, {1, 1, 1, 5, 25, 63, 61, 73, 207, 205, 1011, 2857, 8137, 2121, 26731, 46011}},
-{4811, 16, 18163, {1, 3, 7, 11, 13, 59, 107, 57, 49, 555, 441, 1771, 4939, 12107, 8263, 16243}},
-{4812, 16, 18192, {1, 3, 5, 13, 15, 49, 89, 217, 83, 225, 2001, 2727, 4651, 619, 16473, 47525}},
-{4813, 16, 18211, {1, 3, 5, 9, 5, 63, 115, 91, 337, 757, 703, 559, 1683, 14875, 30769, 30331}},
-{4814, 16, 18228, {1, 3, 1, 15, 3, 3, 119, 79, 487, 519, 523, 1177, 7105, 12343, 24671, 31711}},
-{4815, 16, 18264, {1, 1, 7, 15, 25, 63, 87, 23, 59, 277, 849, 953, 4567, 11309, 26181, 749}},
-{4816, 16, 18347, {1, 3, 7, 15, 5, 33, 21, 127, 3, 239, 839, 997, 7253, 8183, 19779, 4185}},
-{4817, 16, 18372, {1, 1, 5, 15, 25, 37, 99, 51, 465, 137, 1339, 541, 4319, 9883, 17425, 30743}},
-{4818, 16, 18409, {1, 3, 3, 5, 13, 7, 3, 249, 365, 749, 527, 3675, 3005, 12905, 9621, 899}},
-{4819, 16, 18412, {1, 3, 3, 7, 29, 31, 69, 21, 365, 1021, 1329, 2623, 3549, 5491, 21293, 63771}},
-{4820, 16, 18418, {1, 1, 5, 9, 5, 35, 53, 247, 193, 17, 227, 381, 5233, 821, 3991, 4439}},
-{4821, 16, 18423, {1, 1, 7, 15, 5, 59, 27, 167, 489, 335, 1565, 2999, 1777, 5009, 519, 57967}},
-{4822, 16, 18433, {1, 1, 1, 11, 25, 47, 23, 155, 419, 863, 1905, 355, 1089, 5871, 10149, 53341}},
-{4823, 16, 18439, {1, 1, 7, 7, 29, 55, 127, 83, 33, 309, 2017, 1021, 5987, 1101, 13657, 60587}},
-{4824, 16, 18445, {1, 1, 1, 7, 3, 1, 9, 75, 257, 407, 659, 529, 2087, 14759, 14483, 36425}},
-{4825, 16, 18451, {1, 3, 7, 3, 11, 29, 113, 255, 301, 799, 1171, 3721, 135, 3467, 7109, 50339}},
-{4826, 16, 18467, {1, 1, 1, 7, 21, 25, 15, 31, 61, 491, 57, 189, 2033, 4363, 31295, 16313}},
-{4827, 16, 18502, {1, 1, 5, 1, 5, 17, 33, 77, 483, 469, 355, 2245, 4165, 459, 30411, 29507}},
-{4828, 16, 18514, {1, 1, 3, 13, 1, 27, 29, 85, 491, 787, 1157, 1299, 4743, 14795, 32587, 12807}},
-{4829, 16, 18547, {1, 3, 3, 1, 23, 45, 35, 129, 3, 55, 969, 2387, 3929, 10397, 19879, 2723}},
-{4830, 16, 18575, {1, 1, 1, 7, 19, 3, 9, 23, 497, 347, 2039, 913, 5925, 7965, 5789, 40949}},
-{4831, 16, 18593, {1, 1, 7, 1, 29, 61, 89, 3, 133, 647, 1585, 2661, 1875, 1859, 3937, 12707}},
-{4832, 16, 18613, {1, 3, 3, 7, 25, 11, 41, 149, 427, 463, 901, 2433, 2617, 13511, 3443, 39867}},
-{4833, 16, 18620, {1, 1, 1, 5, 27, 33, 103, 251, 201, 1023, 1979, 3745, 6365, 14945, 22153, 55535}},
-{4834, 16, 18637, {1, 3, 1, 15, 23, 25, 57, 215, 111, 181, 385, 1123, 3095, 7085, 31863, 37393}},
-{4835, 16, 18640, {1, 3, 5, 13, 17, 35, 27, 159, 255, 241, 413, 1823, 5329, 1825, 28489, 58763}},
-{4836, 16, 18712, {1, 3, 1, 15, 3, 33, 97, 27, 409, 889, 409, 2315, 4743, 14827, 3037, 57149}},
-{4837, 16, 18728, {1, 1, 3, 5, 19, 63, 93, 51, 233, 715, 1571, 1101, 2751, 14805, 25683, 13323}},
-{4838, 16, 18742, {1, 3, 7, 3, 21, 15, 117, 179, 263, 229, 199, 2597, 3999, 3037, 3801, 4775}},
-{4839, 16, 18748, {1, 3, 3, 15, 1, 15, 49, 91, 383, 21, 1955, 773, 1213, 5971, 19525, 8699}},
-{4840, 16, 18753, {1, 3, 1, 15, 29, 49, 11, 101, 261, 761, 709, 3811, 4055, 15675, 32305, 15173}},
-{4841, 16, 18756, {1, 1, 1, 3, 9, 41, 127, 23, 413, 461, 237, 1595, 2257, 2971, 31845, 61485}},
-{4842, 16, 18771, {1, 1, 1, 11, 23, 13, 63, 21, 23, 209, 1317, 1071, 3619, 7275, 9343, 21455}},
-{4843, 16, 18814, {1, 1, 5, 9, 31, 35, 41, 249, 477, 569, 1175, 1571, 4679, 10337, 3507, 23415}},
-{4844, 16, 18818, {1, 3, 5, 11, 29, 3, 117, 65, 301, 913, 1709, 1765, 1801, 15513, 31495, 38131}},
-{4845, 16, 18827, {1, 3, 5, 11, 27, 3, 71, 195, 81, 313, 505, 3941, 3797, 2031, 24151, 65085}},
-{4846, 16, 18835, {1, 1, 1, 5, 13, 17, 59, 151, 191, 489, 1267, 3207, 4495, 15145, 12789, 46313}},
-{4847, 16, 18842, {1, 3, 1, 7, 29, 9, 25, 31, 33, 527, 1939, 4089, 333, 757, 8895, 25331}},
-{4848, 16, 18854, {1, 1, 1, 1, 9, 27, 11, 205, 211, 141, 1171, 1881, 4029, 10587, 30103, 39661}},
-{4849, 16, 18858, {1, 1, 3, 3, 23, 3, 23, 175, 355, 753, 183, 1331, 6403, 3369, 29891, 11109}},
-{4850, 16, 18895, {1, 3, 7, 3, 17, 25, 95, 145, 135, 525, 1073, 1841, 3951, 2027, 23053, 19699}},
-{4851, 16, 18914, {1, 1, 5, 3, 11, 43, 117, 67, 299, 885, 1095, 2777, 8185, 14331, 29543, 655}},
-{4852, 16, 18925, {1, 3, 7, 7, 3, 59, 127, 147, 323, 713, 99, 1179, 6395, 1821, 12673, 35587}},
-{4853, 16, 18933, {1, 3, 5, 3, 7, 11, 33, 87, 99, 967, 1443, 1585, 6215, 15125, 30747, 21513}},
-{4854, 16, 18937, {1, 3, 7, 11, 23, 5, 91, 171, 229, 601, 833, 3157, 1691, 15081, 20607, 7643}},
-{4855, 16, 18944, {1, 1, 3, 1, 5, 1, 39, 59, 157, 7, 601, 2079, 3045, 3693, 26511, 13245}},
-{4856, 16, 18973, {1, 3, 5, 9, 9, 27, 83, 135, 185, 379, 2027, 1407, 7409, 7363, 26471, 35907}},
-{4857, 16, 19001, {1, 3, 7, 15, 29, 49, 1, 69, 383, 915, 183, 3809, 4511, 8751, 4715, 7033}},
-{4858, 16, 19012, {1, 3, 3, 3, 1, 17, 71, 233, 243, 933, 1165, 3089, 3565, 6521, 13203, 13065}},
-{4859, 16, 19016, {1, 1, 5, 9, 9, 55, 53, 129, 331, 943, 587, 2573, 2247, 15101, 4987, 62983}},
-{4860, 16, 19027, {1, 3, 1, 13, 11, 43, 45, 127, 129, 857, 669, 321, 3915, 4477, 26973, 19911}},
-{4861, 16, 19040, {1, 3, 1, 13, 15, 3, 83, 23, 13, 441, 953, 2373, 3539, 4895, 26327, 61961}},
-{4862, 16, 19074, {1, 1, 5, 13, 23, 11, 125, 83, 339, 901, 1809, 2691, 3789, 15007, 10569, 65399}},
-{4863, 16, 19085, {1, 3, 1, 1, 17, 27, 105, 199, 435, 245, 1227, 3029, 3911, 1021, 2931, 24957}},
-{4864, 16, 19093, {1, 3, 1, 11, 17, 5, 123, 39, 413, 627, 1149, 3925, 6635, 8959, 31387, 65047}},
-{4865, 16, 19100, {1, 3, 5, 1, 23, 41, 93, 217, 21, 115, 1311, 3901, 2559, 2925, 30755, 7575}},
-{4866, 16, 19107, {1, 1, 3, 9, 13, 11, 63, 171, 135, 983, 1679, 395, 7349, 5153, 26405, 40589}},
-{4867, 16, 19128, {1, 3, 7, 13, 27, 47, 53, 169, 85, 871, 1087, 619, 7399, 9719, 6349, 59211}},
-{4868, 16, 19141, {1, 3, 3, 15, 31, 45, 3, 33, 11, 879, 929, 1977, 1939, 1049, 16159, 41515}},
-{4869, 16, 19142, {1, 3, 5, 11, 9, 27, 13, 23, 127, 747, 1121, 2497, 8141, 8601, 12431, 3243}},
-{4870, 16, 19156, {1, 3, 7, 15, 23, 43, 23, 225, 283, 13, 1837, 2089, 6435, 10121, 22307, 58767}},
-{4871, 16, 19169, {1, 1, 5, 11, 17, 3, 41, 221, 143, 669, 261, 1367, 7813, 15265, 32751, 62007}},
-{4872, 16, 19176, {1, 1, 1, 1, 5, 45, 41, 161, 327, 185, 1403, 485, 2831, 10025, 12555, 47661}},
-{4873, 16, 19222, {1, 3, 7, 1, 31, 55, 87, 83, 439, 929, 653, 4095, 5443, 7361, 27801, 12979}},
-{4874, 16, 19226, {1, 3, 1, 7, 1, 57, 11, 145, 55, 269, 711, 1889, 8023, 7171, 3247, 35691}},
-{4875, 16, 19247, {1, 1, 1, 3, 15, 1, 15, 131, 479, 797, 815, 2343, 1603, 10775, 21341, 20825}},
-{4876, 16, 19259, {1, 3, 5, 9, 3, 27, 31, 117, 441, 177, 215, 3991, 3197, 8397, 19195, 3883}},
-{4877, 16, 19262, {1, 1, 5, 13, 1, 19, 13, 27, 157, 1001, 43, 251, 7997, 7495, 16515, 44287}},
-{4878, 16, 19291, {1, 1, 3, 5, 17, 57, 117, 53, 413, 905, 551, 149, 7531, 14885, 32493, 34961}},
-{4879, 16, 19309, {1, 3, 3, 7, 27, 1, 7, 13, 259, 21, 189, 451, 6171, 3603, 12053, 45619}},
-{4880, 16, 19324, {1, 1, 7, 11, 5, 41, 59, 119, 419, 93, 1399, 629, 1269, 3789, 17035, 61583}},
-{4881, 16, 19334, {1, 3, 5, 11, 1, 11, 59, 83, 473, 273, 839, 3111, 3081, 10159, 6143, 16297}},
-{4882, 16, 19338, {1, 1, 5, 15, 25, 15, 17, 63, 275, 927, 189, 89, 6595, 4399, 27201, 57205}},
-{4883, 16, 19343, {1, 1, 7, 3, 31, 17, 63, 203, 321, 655, 1751, 2985, 3291, 11567, 15135, 49747}},
-{4884, 16, 19376, {1, 3, 5, 13, 27, 25, 89, 39, 299, 833, 1269, 271, 6481, 3045, 7203, 20279}},
-{4885, 16, 19408, {1, 3, 1, 1, 29, 13, 13, 37, 33, 563, 1825, 3257, 3153, 963, 25801, 15861}},
-{4886, 16, 19413, {1, 3, 5, 11, 15, 7, 49, 117, 479, 221, 579, 2995, 1673, 14927, 2869, 35547}},
-{4887, 16, 19420, {1, 3, 1, 11, 31, 11, 77, 161, 183, 187, 1967, 3037, 4441, 10547, 1443, 8619}},
-{4888, 16, 19441, {1, 1, 3, 11, 27, 41, 83, 179, 293, 421, 1395, 1673, 6375, 9801, 14265, 18117}},
-{4889, 16, 19444, {1, 1, 3, 7, 9, 19, 55, 235, 499, 637, 1121, 3583, 8007, 3749, 20903, 6179}},
-{4890, 16, 19454, {1, 3, 7, 13, 9, 55, 125, 77, 395, 9, 2005, 2247, 1609, 6805, 13099, 26367}},
-{4891, 16, 19461, {1, 3, 5, 13, 9, 41, 49, 133, 443, 995, 209, 341, 8013, 11037, 29663, 21161}},
-{4892, 16, 19473, {1, 3, 1, 1, 1, 47, 45, 243, 161, 433, 129, 39, 4885, 8777, 6395, 16953}},
-{4893, 16, 19479, {1, 3, 3, 15, 11, 13, 41, 113, 279, 657, 763, 2411, 7115, 463, 10759, 50493}},
-{4894, 16, 19489, {1, 1, 5, 5, 31, 5, 25, 181, 385, 445, 625, 313, 4983, 11763, 6065, 63835}},
-{4895, 16, 19591, {1, 3, 3, 15, 13, 25, 103, 5, 205, 223, 1327, 73, 677, 6751, 2071, 24963}},
-{4896, 16, 19605, {1, 1, 7, 15, 21, 61, 21, 11, 47, 775, 113, 991, 1943, 1459, 18049, 45025}},
-{4897, 16, 19616, {1, 3, 3, 1, 11, 43, 27, 89, 49, 711, 173, 181, 1261, 2751, 21321, 5467}},
-{4898, 16, 19619, {1, 3, 3, 7, 17, 7, 57, 61, 87, 973, 985, 1849, 559, 7319, 11457, 46071}},
-{4899, 16, 19653, {1, 1, 1, 1, 9, 37, 99, 157, 423, 189, 1355, 3983, 6357, 10825, 26517, 45815}},
-{4900, 16, 19654, {1, 1, 3, 11, 23, 33, 57, 55, 59, 831, 339, 725, 359, 14859, 17523, 36149}},
-{4901, 16, 19681, {1, 1, 5, 5, 27, 29, 47, 147, 153, 801, 1737, 3617, 5447, 8011, 30631, 7921}},
-{4902, 16, 19711, {1, 1, 5, 1, 11, 43, 35, 105, 69, 453, 1023, 875, 6755, 6015, 12449, 50235}},
-{4903, 16, 19719, {1, 3, 1, 5, 29, 31, 43, 89, 369, 891, 1447, 353, 8103, 2555, 1197, 64005}},
-{4904, 16, 19726, {1, 3, 3, 9, 21, 33, 117, 205, 473, 289, 1699, 2361, 7083, 13001, 24127, 48611}},
-{4905, 16, 19738, {1, 3, 3, 15, 3, 23, 79, 139, 475, 511, 181, 1331, 6137, 2653, 14071, 16947}},
-{4906, 16, 19767, {1, 3, 3, 1, 11, 47, 51, 217, 305, 599, 1609, 237, 4537, 5377, 717, 13269}},
-{4907, 16, 19819, {1, 1, 7, 3, 19, 31, 1, 173, 509, 817, 785, 1223, 5585, 8911, 643, 44575}},
-{4908, 16, 19864, {1, 1, 3, 11, 5, 11, 31, 129, 269, 369, 1833, 2885, 441, 11517, 2323, 26735}},
-{4909, 16, 19867, {1, 1, 5, 9, 7, 51, 31, 21, 5, 157, 541, 2939, 4569, 1679, 17467, 27995}},
-{4910, 16, 19885, {1, 1, 7, 3, 21, 33, 85, 213, 41, 851, 1947, 3205, 5065, 6079, 30789, 63677}},
-{4911, 16, 19894, {1, 1, 5, 3, 9, 53, 3, 179, 157, 407, 537, 1193, 4645, 13791, 28153, 11349}},
-{4912, 16, 19900, {1, 1, 7, 13, 25, 61, 9, 151, 263, 143, 1583, 2859, 6617, 8861, 4163, 40695}},
-{4913, 16, 19903, {1, 1, 1, 1, 7, 25, 19, 207, 335, 1019, 1919, 3893, 831, 12421, 4667, 38967}},
-{4914, 16, 19941, {1, 3, 5, 3, 5, 51, 81, 9, 425, 333, 451, 2569, 2771, 12145, 26065, 14385}},
-{4915, 16, 19951, {1, 1, 3, 7, 3, 49, 17, 147, 327, 331, 1197, 7, 3703, 15247, 9723, 52819}},
-{4916, 16, 19959, {1, 3, 3, 7, 27, 21, 117, 229, 255, 603, 195, 1049, 6243, 13593, 14553, 8267}},
-{4917, 16, 19966, {1, 1, 5, 15, 9, 53, 1, 187, 79, 151, 321, 1883, 6105, 13879, 8201, 53213}},
-{4918, 16, 20009, {1, 1, 1, 7, 21, 27, 103, 147, 351, 901, 1927, 2145, 2685, 453, 15173, 7371}},
-{4919, 16, 20018, {1, 1, 3, 5, 21, 27, 125, 77, 395, 27, 827, 3617, 6033, 1511, 29461, 18907}},
-{4920, 16, 20020, {1, 3, 5, 3, 3, 27, 75, 129, 441, 831, 1213, 2499, 5829, 12181, 7991, 58167}},
-{4921, 16, 20038, {1, 1, 1, 9, 3, 33, 85, 135, 45, 405, 1731, 551, 1251, 7895, 3975, 41621}},
-{4922, 16, 20049, {1, 3, 5, 7, 19, 19, 25, 7, 477, 569, 1089, 2705, 6157, 10279, 14029, 36229}},
-{4923, 16, 20066, {1, 3, 7, 3, 5, 19, 99, 137, 67, 361, 2021, 2891, 1957, 14961, 22673, 45707}},
-{4924, 16, 20108, {1, 3, 7, 1, 21, 11, 81, 225, 151, 235, 1761, 3875, 7427, 11213, 27023, 17945}},
-{4925, 16, 20130, {1, 1, 7, 1, 3, 1, 3, 123, 39, 769, 1467, 1907, 7833, 2099, 19, 54653}},
-{4926, 16, 20132, {1, 1, 1, 3, 25, 35, 33, 111, 407, 497, 1527, 3999, 3083, 6221, 8319, 56959}},
-{4927, 16, 20167, {1, 1, 3, 15, 21, 49, 113, 11, 191, 801, 1835, 3413, 3379, 13129, 3655, 23885}},
-{4928, 16, 20219, {1, 3, 1, 5, 21, 57, 87, 133, 409, 325, 569, 2099, 8143, 315, 23287, 21905}},
-{4929, 16, 20227, {1, 1, 5, 5, 21, 43, 25, 169, 265, 123, 81, 2683, 6137, 7341, 16383, 26435}},
-{4930, 16, 20263, {1, 3, 1, 5, 23, 17, 125, 173, 3, 829, 693, 751, 8021, 3701, 32643, 35405}},
-{4931, 16, 20267, {1, 1, 3, 1, 31, 13, 1, 195, 435, 487, 961, 1681, 1233, 6001, 3113, 29515}},
-{4932, 16, 20272, {1, 1, 7, 5, 9, 41, 81, 137, 257, 337, 1837, 145, 4191, 6313, 9991, 25541}},
-{4933, 16, 20289, {1, 1, 5, 13, 29, 13, 1, 117, 501, 991, 571, 793, 1433, 6005, 19, 61135}},
-{4934, 16, 20296, {1, 1, 7, 1, 9, 43, 65, 69, 297, 331, 1777, 1843, 6477, 13943, 1301, 51001}},
-{4935, 16, 20307, {1, 1, 1, 3, 7, 35, 23, 211, 33, 649, 255, 1831, 635, 9965, 16679, 14531}},
-{4936, 16, 20316, {1, 1, 1, 13, 23, 57, 113, 247, 321, 401, 1761, 4001, 1823, 14457, 5251, 4965}},
-{4937, 16, 20323, {1, 1, 5, 5, 31, 5, 53, 103, 297, 575, 1577, 2217, 977, 14415, 16953, 14793}},
-{4938, 16, 20335, {1, 1, 5, 7, 9, 19, 25, 29, 121, 563, 1707, 901, 6167, 10799, 11897, 31187}},
-{4939, 16, 20344, {1, 1, 5, 9, 17, 39, 89, 29, 251, 259, 411, 819, 6037, 4601, 11481, 46141}},
-{4940, 16, 20354, {1, 1, 1, 15, 23, 9, 65, 95, 189, 93, 1485, 2417, 5183, 5513, 26623, 42637}},
-{4941, 16, 20360, {1, 1, 5, 5, 3, 3, 113, 161, 463, 225, 1089, 2023, 2341, 14931, 28097, 56365}},
-{4942, 16, 20368, {1, 1, 5, 9, 9, 3, 109, 141, 27, 473, 107, 4023, 3279, 7595, 13289, 35649}},
-{4943, 16, 20390, {1, 1, 5, 3, 9, 37, 73, 153, 487, 57, 2035, 3583, 239, 2183, 10903, 171}},
-{4944, 16, 20402, {1, 3, 3, 15, 23, 39, 87, 217, 451, 597, 1817, 2883, 145, 11341, 16015, 16765}},
-{4945, 16, 20413, {1, 1, 7, 5, 19, 61, 45, 37, 473, 883, 277, 2801, 13, 7021, 3851, 53223}},
-{4946, 16, 20425, {1, 3, 3, 9, 1, 35, 97, 237, 279, 541, 1911, 661, 7603, 8183, 22071, 37317}},
-{4947, 16, 20428, {1, 3, 3, 11, 11, 63, 101, 71, 227, 259, 1545, 2779, 3859, 4859, 18957, 31749}},
-{4948, 16, 20434, {1, 3, 3, 1, 27, 29, 91, 215, 381, 607, 1701, 1709, 247, 12403, 29943, 59533}},
-{4949, 16, 20443, {1, 1, 7, 1, 11, 23, 47, 141, 37, 881, 1443, 3921, 3281, 7417, 1549, 50653}},
-{4950, 16, 20488, {1, 1, 7, 11, 23, 61, 17, 39, 373, 871, 1107, 1875, 1419, 3981, 1333, 11485}},
-{4951, 16, 20502, {1, 1, 7, 11, 21, 51, 127, 145, 129, 425, 1263, 1989, 699, 7317, 24827, 15049}},
-{4952, 16, 20505, {1, 1, 1, 11, 9, 59, 59, 67, 329, 841, 905, 467, 1905, 895, 29711, 25585}},
-{4953, 16, 20535, {1, 1, 1, 15, 3, 39, 11, 205, 297, 383, 445, 2139, 2935, 2399, 22237, 20355}},
-{4954, 16, 20541, {1, 3, 7, 7, 17, 9, 17, 205, 369, 1019, 1703, 755, 5507, 14749, 16461, 14519}},
-{4955, 16, 20554, {1, 3, 7, 3, 5, 31, 97, 35, 43, 249, 773, 4033, 6085, 1241, 24743, 22415}},
-{4956, 16, 20577, {1, 3, 7, 3, 17, 11, 45, 203, 251, 669, 1463, 1897, 7913, 2315, 30307, 15431}},
-{4957, 16, 20583, {1, 1, 5, 5, 7, 53, 83, 13, 1, 841, 423, 1059, 3951, 14209, 11113, 13931}},
-{4958, 16, 20602, {1, 3, 3, 5, 5, 15, 11, 71, 237, 553, 829, 3653, 4991, 1003, 8353, 52173}},
-{4959, 16, 20611, {1, 3, 3, 9, 27, 39, 83, 137, 315, 883, 1155, 3541, 3815, 10633, 13277, 20269}},
-{4960, 16, 20614, {1, 3, 3, 15, 13, 55, 43, 19, 345, 351, 1117, 1747, 1949, 3195, 12241, 52441}},
-{4961, 16, 20626, {1, 1, 3, 5, 1, 11, 113, 117, 37, 103, 1681, 3269, 1659, 14779, 30479, 31123}},
-{4962, 16, 20628, {1, 3, 7, 13, 1, 63, 9, 63, 65, 737, 785, 1713, 8123, 10053, 29871, 17647}},
-{4963, 16, 20635, {1, 1, 3, 5, 17, 45, 71, 37, 283, 145, 1927, 75, 7355, 4681, 2777, 31465}},
-{4964, 16, 20642, {1, 1, 3, 7, 21, 19, 113, 89, 67, 751, 99, 421, 201, 6345, 9473, 39849}},
-{4965, 16, 20674, {1, 1, 5, 11, 31, 57, 75, 79, 393, 745, 1435, 3039, 1175, 983, 923, 42867}},
-{4966, 16, 20716, {1, 1, 5, 9, 31, 47, 31, 61, 85, 651, 1733, 3973, 1979, 7223, 13817, 30593}},
-{4967, 16, 20734, {1, 1, 1, 11, 31, 21, 23, 177, 401, 55, 537, 3775, 3241, 15157, 11849, 15629}},
-{4968, 16, 20765, {1, 1, 1, 13, 31, 53, 79, 57, 35, 617, 61, 89, 6917, 6045, 23879, 45485}},
-{4969, 16, 20801, {1, 3, 7, 7, 3, 43, 57, 243, 107, 321, 273, 2171, 2069, 6171, 29181, 8281}},
-{4970, 16, 20804, {1, 1, 1, 11, 3, 27, 51, 57, 81, 795, 1673, 2601, 7335, 16243, 863, 20663}},
-{4971, 16, 20808, {1, 1, 5, 9, 7, 19, 31, 87, 509, 899, 1133, 1609, 2163, 7595, 10523, 43181}},
-{4972, 16, 20831, {1, 1, 1, 7, 21, 53, 103, 43, 507, 317, 685, 1329, 7057, 7275, 2277, 28271}},
-{4973, 16, 20832, {1, 1, 7, 7, 3, 35, 81, 81, 261, 587, 1571, 2771, 4653, 6517, 25101, 56753}},
-{4974, 16, 20862, {1, 3, 1, 11, 17, 61, 29, 137, 7, 929, 393, 2513, 2423, 5457, 6285, 12525}},
-{4975, 16, 20877, {1, 3, 1, 9, 25, 63, 17, 45, 439, 591, 273, 877, 7741, 8381, 32277, 24635}},
-{4976, 16, 20880, {1, 3, 1, 5, 19, 11, 17, 175, 297, 77, 961, 3331, 5193, 14347, 12713, 32067}},
-{4977, 16, 20885, {1, 1, 5, 11, 3, 17, 13, 21, 219, 653, 1279, 1657, 7659, 14459, 27661, 38093}},
-{4978, 16, 20889, {1, 3, 7, 7, 29, 17, 67, 35, 451, 91, 919, 3163, 7459, 14971, 4317, 42503}},
-{4979, 16, 20905, {1, 3, 3, 15, 7, 61, 69, 211, 349, 97, 911, 503, 3903, 12327, 11049, 29387}},
-{4980, 16, 20914, {1, 1, 7, 3, 5, 7, 63, 237, 387, 931, 693, 1143, 6545, 8529, 25217, 53087}},
-{4981, 16, 20967, {1, 1, 5, 7, 1, 13, 21, 169, 259, 289, 437, 649, 4905, 15261, 29997, 34043}},
-{4982, 16, 21028, {1, 1, 1, 9, 25, 13, 19, 229, 29, 213, 1941, 1501, 3463, 15761, 15635, 39687}},
-{4983, 16, 21031, {1, 1, 5, 7, 13, 29, 101, 57, 483, 913, 1025, 2139, 4327, 7847, 12455, 41797}},
-{4984, 16, 21043, {1, 1, 3, 11, 17, 27, 97, 79, 411, 9, 1797, 3721, 5291, 859, 8889, 6151}},
-{4985, 16, 21052, {1, 1, 1, 5, 17, 61, 45, 187, 157, 301, 1017, 1507, 6031, 4271, 32593, 23739}},
-{4986, 16, 21058, {1, 1, 3, 11, 31, 39, 7, 169, 15, 799, 1585, 2055, 4683, 13247, 23743, 50399}},
-{4987, 16, 21087, {1, 1, 1, 9, 25, 37, 15, 39, 339, 383, 1153, 1211, 5745, 15249, 26021, 39871}},
-{4988, 16, 21088, {1, 1, 3, 13, 17, 51, 27, 137, 231, 877, 309, 3633, 2575, 12259, 2743, 14781}},
-{4989, 16, 21093, {1, 1, 5, 7, 5, 33, 95, 19, 37, 829, 1489, 3525, 3887, 8277, 21867, 3581}},
-{4990, 16, 21106, {1, 1, 1, 15, 11, 33, 99, 213, 365, 549, 1603, 777, 3787, 12209, 14999, 50607}},
-{4991, 16, 21108, {1, 3, 1, 9, 23, 25, 57, 147, 73, 285, 1229, 1763, 4579, 14771, 4003, 38197}},
-{4992, 16, 21118, {1, 1, 5, 1, 15, 55, 25, 209, 135, 895, 311, 139, 2445, 6903, 12129, 27907}},
-{4993, 16, 21122, {1, 1, 5, 7, 23, 29, 33, 135, 325, 517, 2021, 1721, 4235, 2363, 12905, 18811}},
-{4994, 16, 21131, {1, 1, 1, 9, 3, 19, 69, 29, 157, 787, 1969, 3711, 8179, 5691, 4059, 25541}},
-{4995, 16, 21139, {1, 1, 5, 15, 1, 61, 11, 195, 317, 13, 923, 2149, 4001, 12843, 27109, 30625}},
-{4996, 16, 21141, {1, 3, 1, 7, 3, 13, 45, 187, 445, 859, 53, 3227, 4381, 8273, 32699, 48719}},
-{4997, 16, 21146, {1, 1, 7, 7, 21, 19, 47, 101, 119, 311, 577, 3309, 4585, 12109, 15153, 22915}},
-{4998, 16, 21162, {1, 3, 5, 15, 21, 39, 15, 211, 349, 237, 1873, 3333, 7837, 12811, 14321, 20227}},
-{4999, 16, 21164, {1, 1, 5, 5, 19, 47, 15, 239, 23, 763, 537, 1477, 2231, 10885, 19487, 47385}},
-{5000, 16, 21184, {1, 1, 3, 1, 19, 37, 67, 85, 11, 817, 869, 2249, 4111, 12411, 10405, 20055}},
-{5001, 16, 21208, {1, 1, 3, 3, 1, 41, 85, 137, 91, 369, 1863, 759, 303, 15859, 8063, 12811}},
-{5002, 16, 21211, {1, 3, 1, 11, 23, 1, 11, 219, 201, 573, 1573, 619, 2959, 6485, 7483, 46099}},
-{5003, 16, 21213, {1, 3, 3, 9, 13, 9, 9, 255, 47, 375, 409, 1435, 1665, 14967, 3247, 18193}},
-{5004, 16, 21230, {1, 1, 1, 5, 9, 61, 121, 173, 51, 415, 1621, 3947, 1379, 847, 23187, 39259}},
-{5005, 16, 21270, {1, 1, 1, 7, 3, 19, 95, 59, 187, 453, 1533, 445, 2699, 4817, 25983, 50925}},
-{5006, 16, 21276, {1, 3, 5, 13, 25, 25, 33, 5, 497, 1, 535, 1653, 6541, 10939, 17721, 43829}},
-{5007, 16, 21285, {1, 3, 7, 11, 9, 59, 115, 127, 85, 505, 541, 3243, 5853, 12673, 25275, 39577}},
-{5008, 16, 21297, {1, 3, 7, 1, 17, 25, 83, 127, 225, 295, 1823, 2051, 847, 4249, 13763, 5723}},
-{5009, 16, 21304, {1, 1, 1, 5, 3, 63, 39, 131, 191, 983, 119, 3287, 3335, 7969, 31347, 39439}},
-{5010, 16, 21310, {1, 3, 7, 9, 19, 31, 19, 91, 35, 677, 1229, 1371, 6497, 3315, 15239, 54235}},
-{5011, 16, 21330, {1, 1, 1, 15, 3, 49, 113, 199, 135, 35, 709, 385, 7923, 3711, 18351, 12711}},
-{5012, 16, 21339, {1, 1, 3, 15, 31, 13, 41, 1, 183, 95, 1625, 1675, 7881, 6607, 4165, 27151}},
-{5013, 16, 21346, {1, 3, 3, 15, 21, 57, 81, 49, 5, 297, 131, 883, 1113, 2497, 32129, 39139}},
-{5014, 16, 21391, {1, 3, 5, 7, 29, 47, 101, 173, 299, 879, 143, 3341, 3929, 6797, 8753, 47963}},
-{5015, 16, 21427, {1, 3, 3, 13, 11, 39, 27, 187, 27, 763, 1515, 1903, 5897, 10061, 14595, 12713}},
-{5016, 16, 21451, {1, 3, 5, 11, 27, 35, 37, 213, 45, 867, 1591, 3083, 8123, 5045, 31703, 61487}},
-{5017, 16, 21465, {1, 1, 3, 5, 3, 31, 23, 89, 369, 371, 1165, 3673, 6821, 333, 10881, 4153}},
-{5018, 16, 21468, {1, 1, 7, 13, 1, 33, 49, 195, 223, 197, 1799, 2427, 6171, 493, 13503, 23619}},
-{5019, 16, 21471, {1, 1, 3, 9, 5, 59, 105, 215, 449, 527, 1661, 2643, 309, 11239, 11633, 63459}},
-{5020, 16, 21533, {1, 1, 3, 11, 13, 11, 15, 99, 409, 807, 1911, 883, 1323, 9037, 6401, 545}},
-{5021, 16, 21610, {1, 1, 5, 7, 7, 7, 1, 167, 353, 923, 1403, 3109, 4981, 3877, 25451, 4667}},
-{5022, 16, 21615, {1, 1, 5, 11, 11, 25, 121, 153, 111, 785, 1301, 1497, 6267, 14919, 24125, 52029}},
-{5023, 16, 21630, {1, 3, 3, 5, 29, 55, 63, 177, 305, 41, 111, 1065, 1127, 113, 2815, 12979}},
-{5024, 16, 21633, {1, 3, 5, 7, 23, 39, 17, 179, 267, 917, 511, 3923, 915, 14173, 10689, 50749}},
-{5025, 16, 21657, {1, 1, 5, 3, 9, 45, 15, 157, 495, 625, 407, 2769, 3267, 7593, 17957, 54597}},
-{5026, 16, 21658, {1, 3, 3, 11, 21, 13, 5, 207, 107, 965, 1803, 1541, 3487, 3483, 109, 26923}},
-{5027, 16, 21669, {1, 1, 5, 11, 25, 49, 99, 135, 109, 371, 1307, 1815, 1095, 2329, 27101, 52269}},
-{5028, 16, 21670, {1, 3, 5, 5, 13, 9, 109, 79, 151, 47, 311, 3873, 3645, 3773, 1083, 31599}},
-{5029, 16, 21673, {1, 3, 5, 15, 1, 9, 87, 21, 145, 583, 159, 2435, 587, 10123, 24803, 19993}},
-{5030, 16, 21701, {1, 3, 1, 1, 23, 11, 5, 45, 373, 1011, 1353, 277, 7051, 3845, 12391, 25313}},
-{5031, 16, 21719, {1, 1, 1, 9, 13, 13, 109, 251, 97, 483, 1723, 2555, 813, 9345, 11351, 44705}},
-{5032, 16, 21720, {1, 3, 5, 7, 21, 49, 63, 13, 119, 813, 1559, 983, 499, 15159, 24163, 59903}},
-{5033, 16, 21747, {1, 1, 3, 5, 27, 33, 27, 165, 207, 693, 1401, 1357, 7637, 337, 10163, 43273}},
-{5034, 16, 21819, {1, 1, 5, 13, 29, 7, 71, 187, 1, 655, 1829, 2645, 6969, 5435, 28415, 33199}},
-{5035, 16, 21839, {1, 1, 1, 13, 17, 21, 13, 141, 41, 267, 1165, 1893, 3455, 10737, 16693, 33065}},
-{5036, 16, 21854, {1, 1, 5, 1, 7, 27, 7, 67, 107, 11, 763, 2529, 3023, 15745, 17023, 51911}},
-{5037, 16, 21857, {1, 3, 3, 3, 7, 57, 123, 249, 309, 511, 1655, 1379, 725, 7325, 20261, 65039}},
-{5038, 16, 21864, {1, 1, 5, 11, 3, 27, 23, 27, 285, 771, 2017, 1727, 4847, 2665, 30655, 47625}},
-{5039, 16, 21882, {1, 3, 7, 7, 17, 3, 93, 133, 427, 1021, 1135, 341, 6711, 11713, 24157, 1561}},
-{5040, 16, 21900, {1, 1, 3, 7, 15, 55, 11, 247, 65, 115, 1967, 535, 841, 15131, 28381, 31337}},
-{5041, 16, 21903, {1, 3, 1, 7, 9, 45, 73, 151, 127, 125, 767, 2003, 6893, 3875, 451, 30275}},
-{5042, 16, 21928, {1, 1, 7, 3, 5, 55, 127, 123, 163, 763, 1165, 1637, 6267, 7215, 23403, 20961}},
-{5043, 16, 21931, {1, 1, 1, 13, 1, 21, 65, 141, 369, 413, 1675, 27, 7357, 6929, 18083, 829}},
-{5044, 16, 21946, {1, 3, 5, 13, 1, 17, 97, 107, 249, 931, 47, 3537, 2245, 9827, 13673, 23217}},
-{5045, 16, 21971, {1, 1, 1, 11, 13, 19, 43, 31, 51, 727, 1001, 927, 771, 11853, 5761, 60537}},
-{5046, 16, 21974, {1, 3, 1, 7, 23, 27, 115, 5, 201, 431, 1021, 585, 6069, 12511, 6129, 2105}},
-{5047, 16, 21978, {1, 1, 3, 11, 3, 25, 75, 129, 389, 131, 223, 2263, 5377, 5561, 15633, 39527}},
-{5048, 16, 21993, {1, 3, 3, 1, 27, 43, 101, 55, 319, 549, 1971, 2255, 353, 93, 25661, 59077}},
-{5049, 16, 21994, {1, 1, 5, 11, 29, 57, 27, 135, 341, 913, 1637, 1781, 457, 11293, 1013, 53863}},
-{5050, 16, 22030, {1, 1, 1, 11, 3, 51, 79, 251, 443, 651, 393, 3635, 7397, 5443, 4225, 991}},
-{5051, 16, 22035, {1, 3, 7, 13, 31, 9, 3, 109, 427, 735, 891, 2789, 2169, 6459, 355, 43177}},
-{5052, 16, 22063, {1, 3, 3, 3, 13, 7, 93, 195, 293, 37, 75, 2467, 933, 8017, 9925, 61397}},
-{5053, 16, 22068, {1, 1, 5, 7, 25, 15, 69, 199, 161, 769, 387, 1491, 4553, 4173, 25631, 37089}},
-{5054, 16, 22086, {1, 3, 1, 3, 7, 59, 53, 93, 103, 413, 531, 887, 6149, 2901, 22611, 27135}},
-{5055, 16, 22104, {1, 1, 1, 13, 31, 39, 71, 215, 385, 821, 1603, 3043, 4967, 10953, 11543, 64433}},
-{5056, 16, 22119, {1, 3, 1, 7, 7, 63, 5, 143, 1, 339, 1165, 3809, 4257, 12879, 21581, 21307}},
-{5057, 16, 22153, {1, 1, 1, 15, 1, 35, 67, 227, 277, 879, 513, 3423, 6153, 11573, 12809, 34335}},
-{5058, 16, 22168, {1, 3, 7, 9, 9, 39, 47, 17, 101, 179, 631, 1307, 481, 871, 16807, 39811}},
-{5059, 16, 22183, {1, 3, 1, 1, 13, 25, 53, 179, 285, 267, 407, 3781, 3267, 3545, 525, 15733}},
-{5060, 16, 22189, {1, 1, 1, 13, 11, 35, 45, 181, 319, 767, 283, 3021, 5405, 403, 3587, 7291}},
-{5061, 16, 22204, {1, 1, 7, 3, 5, 9, 67, 129, 101, 117, 267, 1925, 1209, 13095, 7123, 62941}},
-{5062, 16, 22230, {1, 1, 7, 3, 5, 63, 109, 199, 95, 421, 193, 3519, 6551, 955, 1679, 16627}},
-{5063, 16, 22240, {1, 1, 5, 13, 1, 47, 71, 157, 343, 653, 981, 1335, 3737, 7185, 28861, 22883}},
-{5064, 16, 22246, {1, 1, 3, 15, 7, 63, 7, 81, 481, 5, 1159, 1361, 4167, 2575, 7437, 16917}},
-{5065, 16, 22269, {1, 3, 7, 1, 27, 17, 61, 193, 317, 841, 1149, 955, 5161, 4275, 1955, 15665}},
-{5066, 16, 22282, {1, 1, 1, 7, 19, 63, 77, 57, 367, 237, 579, 3701, 5763, 4951, 24151, 45215}},
-{5067, 16, 22302, {1, 1, 5, 11, 29, 7, 119, 155, 431, 999, 757, 2433, 5811, 3709, 29573, 23639}},
-{5068, 16, 22330, {1, 3, 3, 3, 15, 35, 125, 13, 275, 507, 1719, 1537, 2349, 12909, 8107, 9845}},
-{5069, 16, 22347, {1, 3, 1, 13, 27, 27, 11, 69, 15, 1017, 207, 625, 809, 2921, 8939, 30293}},
-{5070, 16, 22349, {1, 1, 7, 11, 31, 51, 113, 193, 69, 845, 73, 919, 3523, 3987, 23665, 36527}},
-{5071, 16, 22383, {1, 3, 7, 11, 21, 31, 103, 29, 5, 81, 1081, 3847, 4697, 8857, 30769, 40053}},
-{5072, 16, 22386, {1, 1, 1, 1, 5, 11, 5, 169, 13, 899, 769, 3823, 5405, 5991, 3821, 27767}},
-{5073, 16, 22432, {1, 1, 3, 15, 1, 35, 9, 83, 23, 701, 1807, 1681, 4009, 127, 31751, 38059}},
-{5074, 16, 22450, {1, 3, 3, 7, 9, 61, 73, 111, 193, 607, 2001, 413, 3751, 16337, 16597, 23959}},
-{5075, 16, 22473, {1, 1, 7, 7, 21, 29, 53, 253, 187, 507, 1191, 3521, 463, 2167, 23785, 19867}},
-{5076, 16, 22487, {1, 3, 5, 3, 19, 43, 101, 93, 257, 61, 1589, 3883, 1975, 7283, 5253, 23257}},
-{5077, 16, 22527, {1, 3, 1, 9, 1, 63, 25, 101, 377, 571, 1701, 3385, 243, 12051, 32619, 10459}},
-{5078, 16, 22537, {1, 1, 1, 5, 17, 11, 37, 197, 205, 879, 625, 959, 7389, 7857, 20615, 20405}},
-{5079, 16, 22557, {1, 3, 5, 5, 27, 41, 9, 109, 197, 623, 1045, 63, 7977, 11355, 28613, 5131}},
-{5080, 16, 22561, {1, 1, 5, 11, 5, 29, 27, 85, 131, 247, 433, 3981, 2677, 15415, 869, 6045}},
-{5081, 16, 22568, {1, 3, 1, 13, 9, 49, 25, 79, 135, 719, 93, 631, 2149, 5929, 29833, 38673}},
-{5082, 16, 22573, {1, 3, 7, 11, 15, 13, 37, 233, 227, 205, 1579, 65, 1429, 13499, 26355, 63821}},
-{5083, 16, 22591, {1, 1, 5, 11, 21, 19, 7, 183, 409, 275, 899, 3665, 6207, 849, 24339, 1617}},
-{5084, 16, 22593, {1, 3, 1, 3, 21, 61, 23, 125, 463, 489, 1265, 2975, 3907, 11881, 7533, 43331}},
-{5085, 16, 22605, {1, 3, 1, 15, 15, 51, 83, 31, 175, 47, 1791, 3651, 6735, 5013, 723, 24141}},
-{5086, 16, 22620, {1, 3, 1, 9, 17, 41, 57, 43, 469, 911, 1251, 2105, 3133, 3437, 10097, 26687}},
-{5087, 16, 22627, {1, 1, 3, 3, 9, 9, 125, 201, 141, 943, 1509, 1239, 6575, 8707, 363, 23309}},
-{5088, 16, 22636, {1, 1, 5, 3, 19, 37, 43, 141, 413, 149, 1449, 1003, 4473, 12395, 4101, 61201}},
-{5089, 16, 22647, {1, 1, 5, 11, 17, 37, 41, 33, 57, 627, 325, 1895, 1773, 1339, 24859, 587}},
-{5090, 16, 22697, {1, 1, 1, 3, 5, 49, 127, 109, 361, 853, 1437, 3451, 4031, 5379, 27463, 47425}},
-{5091, 16, 22715, {1, 3, 5, 7, 9, 57, 71, 219, 347, 791, 797, 73, 6241, 12717, 24429, 40977}},
-{5092, 16, 22725, {1, 1, 5, 9, 27, 43, 43, 227, 433, 413, 1109, 2589, 4535, 8947, 8121, 43479}},
-{5093, 16, 22732, {1, 3, 7, 1, 9, 21, 81, 23, 157, 313, 197, 2845, 8059, 15957, 28657, 28093}},
-{5094, 16, 22749, {1, 3, 1, 11, 15, 17, 115, 27, 421, 743, 1885, 2089, 5011, 7137, 7395, 36853}},
-{5095, 16, 22766, {1, 1, 5, 15, 5, 53, 69, 255, 63, 29, 1011, 3201, 1467, 15441, 26255, 62895}},
-{5096, 16, 22768, {1, 3, 1, 11, 3, 47, 35, 195, 149, 849, 1317, 439, 3539, 845, 15295, 42183}},
-{5097, 16, 22771, {1, 1, 5, 15, 15, 37, 67, 105, 495, 985, 1777, 3137, 8039, 11795, 29771, 35045}},
-{5098, 16, 22788, {1, 1, 3, 1, 25, 17, 67, 227, 229, 419, 1319, 3325, 1293, 8585, 28425, 34013}},
-{5099, 16, 22797, {1, 1, 5, 1, 27, 51, 71, 197, 375, 407, 259, 4005, 3309, 5475, 13421, 60065}},
-{5100, 16, 22822, {1, 3, 1, 5, 11, 17, 89, 45, 311, 425, 1629, 773, 7267, 8699, 27547, 37081}},
-{5101, 16, 22828, {1, 3, 1, 7, 9, 25, 101, 105, 489, 217, 103, 1959, 4049, 5793, 31201, 11947}},
-{5102, 16, 22851, {1, 1, 5, 5, 19, 3, 63, 55, 431, 49, 273, 3253, 5357, 13801, 9735, 21883}},
-{5103, 16, 22888, {1, 1, 1, 11, 13, 3, 75, 201, 477, 201, 1875, 657, 6217, 8651, 2207, 16421}},
-{5104, 16, 22893, {1, 1, 5, 13, 5, 31, 75, 113, 25, 171, 1147, 3089, 7095, 4405, 26155, 42323}},
-{5105, 16, 22901, {1, 3, 5, 5, 5, 49, 99, 171, 445, 1023, 1793, 3159, 5809, 12509, 31723, 60411}},
-{5106, 16, 22902, {1, 3, 7, 3, 23, 51, 111, 27, 103, 159, 433, 293, 1741, 3599, 4067, 40667}},
-{5107, 16, 22921, {1, 3, 3, 13, 11, 9, 11, 21, 453, 35, 1649, 1261, 3539, 14081, 5581, 57105}},
-{5108, 16, 22929, {1, 3, 3, 13, 7, 9, 113, 87, 391, 647, 223, 1345, 4481, 9855, 20129, 10807}},
-{5109, 16, 22946, {1, 3, 7, 15, 3, 61, 15, 117, 97, 495, 985, 819, 181, 1363, 13111, 35857}},
-{5110, 16, 22948, {1, 3, 1, 9, 3, 27, 125, 151, 217, 961, 707, 2647, 5307, 621, 12581, 13941}},
-{5111, 16, 22951, {1, 3, 1, 11, 17, 37, 35, 211, 179, 29, 627, 3623, 6429, 16237, 24699, 14385}},
-{5112, 16, 22958, {1, 3, 3, 9, 3, 57, 35, 3, 85, 1017, 1739, 2241, 7297, 15637, 27085, 41237}},
-{5113, 16, 22975, {1, 1, 3, 7, 7, 13, 5, 85, 505, 51, 409, 867, 677, 12451, 13633, 47883}},
-{5114, 16, 22983, {1, 3, 5, 13, 5, 51, 37, 79, 237, 133, 1331, 3263, 349, 4971, 16067, 62485}},
-{5115, 16, 22990, {1, 1, 7, 11, 29, 41, 101, 219, 391, 1023, 1681, 3163, 4071, 14665, 11041, 14523}},
-{5116, 16, 23032, {1, 1, 3, 3, 13, 55, 37, 119, 471, 665, 1315, 3071, 5993, 12005, 13549, 63425}},
-{5117, 16, 23047, {1, 3, 5, 7, 5, 25, 59, 71, 77, 841, 91, 1841, 6997, 1139, 11843, 52209}},
-{5118, 16, 23053, {1, 3, 7, 15, 17, 25, 85, 173, 373, 459, 1713, 1055, 5337, 9921, 15213, 44235}},
-{5119, 16, 23054, {1, 1, 1, 15, 7, 11, 89, 237, 131, 565, 745, 457, 4447, 5581, 11053, 43819}},
-{5120, 16, 23082, {1, 3, 5, 1, 29, 21, 11, 7, 125, 851, 2023, 3321, 1885, 67, 8809, 43291}},
-{5121, 16, 23095, {1, 3, 5, 11, 11, 43, 41, 97, 353, 813, 85, 2453, 769, 11709, 4697, 2849}},
-{5122, 16, 23116, {1, 1, 5, 5, 21, 29, 87, 179, 157, 981, 129, 2139, 6841, 5479, 27111, 20749}},
-{5123, 16, 23197, {1, 1, 3, 9, 31, 59, 61, 15, 423, 33, 467, 1817, 6535, 7341, 31061, 20937}},
-{5124, 16, 23221, {1, 1, 7, 3, 1, 21, 127, 135, 321, 699, 727, 3079, 753, 3971, 5611, 28345}},
-{5125, 16, 23257, {1, 3, 7, 11, 27, 3, 39, 63, 389, 433, 43, 1443, 6241, 10769, 20485, 58823}},
-{5126, 16, 23260, {1, 1, 1, 11, 3, 13, 5, 57, 503, 707, 677, 3355, 6691, 8841, 20041, 11867}},
-{5127, 16, 23263, {1, 1, 3, 11, 31, 39, 107, 221, 81, 125, 1439, 2429, 2109, 3931, 31007, 10915}},
-{5128, 16, 23267, {1, 3, 3, 9, 17, 53, 13, 121, 127, 15, 1825, 1909, 5951, 13503, 31565, 56163}},
-{5129, 16, 23282, {1, 1, 1, 1, 19, 55, 3, 153, 385, 277, 1297, 3655, 6027, 3057, 11341, 46989}},
-{5130, 16, 23284, {1, 1, 5, 9, 3, 55, 37, 223, 353, 141, 1917, 3827, 2255, 7617, 10971, 10641}},
-{5131, 16, 23314, {1, 3, 7, 9, 29, 41, 71, 19, 137, 243, 2047, 395, 6981, 15887, 9479, 60199}},
-{5132, 16, 23326, {1, 1, 1, 9, 17, 43, 51, 191, 405, 727, 485, 987, 1855, 15801, 22529, 10165}},
-{5133, 16, 23335, {1, 3, 1, 7, 27, 31, 69, 255, 153, 793, 1353, 1981, 83, 11387, 6747, 23379}},
-{5134, 16, 23368, {1, 1, 5, 5, 31, 49, 83, 157, 63, 647, 1367, 3995, 5899, 8429, 18317, 3471}},
-{5135, 16, 23373, {1, 3, 5, 13, 19, 15, 99, 13, 143, 887, 529, 2855, 573, 9799, 13585, 59263}},
-{5136, 16, 23401, {1, 3, 5, 3, 13, 47, 103, 87, 11, 381, 397, 899, 71, 15539, 13005, 38297}},
-{5137, 16, 23415, {1, 1, 1, 3, 1, 53, 45, 141, 1, 941, 261, 3291, 5177, 9843, 6309, 62799}},
-{5138, 16, 23432, {1, 1, 5, 9, 29, 31, 107, 57, 135, 229, 1147, 247, 265, 12757, 21365, 7219}},
-{5139, 16, 23476, {1, 1, 1, 3, 1, 49, 55, 247, 495, 449, 141, 1349, 7393, 2589, 23587, 1097}},
-{5140, 16, 23479, {1, 3, 5, 1, 9, 11, 73, 153, 89, 575, 1805, 137, 435, 3687, 32169, 24275}},
-{5141, 16, 23497, {1, 1, 7, 15, 25, 61, 51, 21, 109, 139, 611, 3907, 6721, 5081, 6665, 51463}},
-{5142, 16, 23505, {1, 1, 1, 9, 13, 23, 59, 203, 33, 1013, 1533, 291, 6171, 15463, 8581, 9497}},
-{5143, 16, 23508, {1, 3, 3, 9, 7, 25, 51, 189, 49, 265, 1163, 1141, 2467, 7839, 7083, 65527}},
-{5144, 16, 23531, {1, 1, 3, 9, 19, 33, 77, 9, 181, 919, 623, 1521, 7853, 2199, 24115, 60607}},
-{5145, 16, 23536, {1, 1, 3, 11, 9, 11, 27, 57, 355, 313, 151, 3391, 4869, 12541, 30031, 29455}},
-{5146, 16, 23542, {1, 3, 5, 9, 17, 13, 91, 123, 235, 841, 1113, 1451, 501, 3863, 32483, 9445}},
-{5147, 16, 23565, {1, 3, 7, 3, 13, 25, 87, 243, 449, 293, 1279, 3571, 2693, 13459, 5895, 38127}},
-{5148, 16, 23573, {1, 1, 3, 15, 27, 61, 7, 57, 255, 971, 131, 2585, 2187, 7191, 17779, 34587}},
-{5149, 16, 23590, {1, 3, 3, 7, 23, 29, 55, 41, 463, 873, 1781, 2851, 4731, 9819, 25587, 32199}},
-{5150, 16, 23593, {1, 1, 1, 9, 29, 39, 25, 143, 171, 141, 223, 467, 4417, 9575, 23159, 33819}},
-{5151, 16, 23604, {1, 1, 5, 13, 19, 61, 19, 75, 25, 361, 585, 1627, 2231, 1831, 24885, 37917}},
-{5152, 16, 23621, {1, 3, 7, 7, 23, 19, 59, 55, 323, 55, 143, 131, 27, 15363, 26423, 43963}},
-{5153, 16, 23622, {1, 1, 5, 5, 25, 9, 33, 17, 427, 481, 315, 3999, 4757, 4545, 7695, 56733}},
-{5154, 16, 23636, {1, 3, 5, 13, 5, 59, 45, 117, 115, 263, 1441, 3307, 1085, 3875, 25869, 19725}},
-{5155, 16, 23662, {1, 3, 3, 15, 13, 39, 31, 243, 293, 345, 343, 1911, 6123, 12577, 32081, 59993}},
-{5156, 16, 23667, {1, 3, 5, 13, 17, 37, 105, 201, 205, 929, 435, 1467, 8063, 6963, 13709, 53275}},
-{5157, 16, 23703, {1, 3, 7, 15, 31, 3, 65, 221, 191, 413, 427, 2579, 377, 2793, 26943, 61299}},
-{5158, 16, 23725, {1, 3, 5, 3, 11, 61, 75, 107, 53, 689, 1845, 859, 333, 889, 27607, 48795}},
-{5159, 16, 23734, {1, 1, 5, 7, 1, 11, 37, 181, 323, 187, 1511, 25, 5517, 11957, 7093, 429}},
-{5160, 16, 23738, {1, 3, 3, 1, 25, 31, 125, 139, 433, 583, 683, 587, 5389, 1225, 26047, 18717}},
-{5161, 16, 23752, {1, 3, 1, 15, 23, 33, 23, 147, 279, 513, 157, 4023, 2669, 7543, 2111, 9191}},
-{5162, 16, 23800, {1, 3, 1, 1, 5, 39, 55, 127, 257, 649, 347, 3001, 2215, 15579, 29665, 10337}},
-{5163, 16, 23803, {1, 1, 1, 15, 19, 55, 105, 183, 505, 1003, 1311, 2253, 1861, 3561, 19581, 46183}},
-{5164, 16, 23818, {1, 3, 1, 9, 23, 5, 127, 215, 195, 817, 719, 1285, 919, 8627, 20427, 2723}},
-{5165, 16, 23832, {1, 1, 1, 5, 15, 31, 43, 131, 377, 57, 1531, 915, 2871, 1805, 19765, 60529}},
-{5166, 16, 23842, {1, 3, 3, 3, 15, 1, 93, 55, 477, 221, 643, 1319, 959, 475, 14015, 48823}},
-{5167, 16, 23851, {1, 3, 3, 7, 19, 13, 13, 191, 421, 751, 1103, 2129, 1973, 14935, 26485, 41269}},
-{5168, 16, 23873, {1, 1, 5, 13, 17, 43, 81, 83, 67, 643, 1799, 1157, 4365, 2815, 29871, 5351}},
-{5169, 16, 23883, {1, 3, 1, 9, 21, 31, 87, 177, 25, 403, 1357, 4047, 959, 5133, 7307, 4333}},
-{5170, 16, 23888, {1, 1, 7, 7, 29, 39, 27, 139, 159, 529, 1323, 3823, 4569, 12711, 30263, 10961}},
-{5171, 16, 23910, {1, 3, 1, 13, 27, 15, 59, 1, 107, 723, 497, 43, 143, 16119, 29177, 5653}},
-{5172, 16, 23934, {1, 1, 5, 9, 15, 41, 23, 109, 101, 639, 277, 1687, 1311, 1995, 5403, 6867}},
-{5173, 16, 23938, {1, 1, 5, 3, 13, 1, 95, 177, 379, 545, 789, 3479, 4135, 445, 5869, 38923}},
-{5174, 16, 23949, {1, 1, 3, 9, 21, 31, 23, 65, 209, 383, 271, 367, 6605, 1169, 27267, 9331}},
-{5175, 16, 23955, {1, 1, 1, 1, 27, 39, 121, 29, 155, 465, 947, 2675, 6753, 11647, 29781, 30251}},
-{5176, 16, 23967, {1, 3, 1, 5, 7, 45, 7, 21, 223, 363, 1021, 751, 2257, 14423, 19629, 64867}},
-{5177, 16, 23973, {1, 3, 1, 9, 31, 53, 13, 99, 49, 389, 867, 327, 4145, 3265, 15423, 14985}},
-{5178, 16, 23991, {1, 1, 1, 15, 11, 11, 27, 41, 333, 161, 1343, 2023, 3789, 13563, 16957, 26849}},
-{5179, 16, 24024, {1, 3, 7, 1, 7, 51, 7, 163, 239, 393, 231, 3985, 309, 875, 837, 24791}},
-{5180, 16, 24030, {1, 1, 1, 7, 1, 43, 105, 7, 351, 755, 1781, 1925, 4961, 2961, 13427, 44317}},
-{5181, 16, 24039, {1, 3, 1, 9, 17, 39, 81, 75, 201, 931, 1547, 1857, 7251, 11687, 14437, 12603}},
-{5182, 16, 24067, {1, 3, 3, 15, 15, 23, 95, 7, 193, 9, 1749, 809, 5083, 14645, 24893, 35979}},
-{5183, 16, 24069, {1, 1, 7, 1, 9, 9, 127, 149, 433, 985, 1347, 3379, 2881, 681, 20777, 30703}},
-{5184, 16, 24084, {1, 3, 1, 11, 1, 27, 121, 111, 251, 45, 1341, 1709, 3733, 11297, 29063, 57119}},
-{5185, 16, 24112, {1, 3, 3, 1, 19, 3, 77, 127, 187, 831, 1125, 3119, 4665, 9857, 5301, 36755}},
-{5186, 16, 24115, {1, 3, 3, 3, 29, 29, 61, 225, 257, 635, 665, 1279, 3019, 2401, 8253, 40251}},
-{5187, 16, 24184, {1, 1, 7, 9, 29, 43, 47, 95, 221, 823, 257, 1485, 5183, 225, 27675, 60479}},
-{5188, 16, 24187, {1, 1, 5, 3, 15, 49, 25, 69, 101, 393, 901, 305, 4917, 13479, 30209, 9199}},
-{5189, 16, 24262, {1, 1, 3, 15, 1, 9, 47, 243, 403, 341, 143, 1365, 1817, 6017, 3853, 58625}},
-{5190, 16, 24276, {1, 3, 3, 11, 9, 49, 93, 149, 39, 177, 1863, 1027, 659, 9253, 2131, 26943}},
-{5191, 16, 24279, {1, 3, 1, 3, 25, 1, 43, 255, 217, 353, 957, 39, 4607, 15761, 24291, 33619}},
-{5192, 16, 24313, {1, 1, 1, 7, 29, 51, 71, 237, 1, 703, 19, 213, 6429, 11783, 22049, 30597}},
-{5193, 16, 24331, {1, 3, 1, 7, 31, 63, 105, 203, 473, 731, 257, 91, 5749, 4099, 30125, 40171}},
-{5194, 16, 24336, {1, 3, 7, 9, 7, 29, 119, 181, 225, 743, 1031, 55, 3997, 16221, 11663, 14847}},
-{5195, 16, 24348, {1, 3, 3, 11, 5, 21, 43, 17, 473, 981, 125, 2077, 6141, 4757, 7585, 29207}},
-{5196, 16, 24367, {1, 1, 7, 1, 27, 61, 27, 45, 267, 483, 119, 767, 957, 3411, 2653, 53967}},
-{5197, 16, 24372, {1, 1, 1, 3, 9, 41, 43, 17, 485, 253, 825, 3605, 5919, 9285, 1815, 6095}},
-{5198, 16, 24402, {1, 1, 1, 11, 7, 5, 53, 107, 309, 609, 1389, 2035, 861, 15565, 9375, 42363}},
-{5199, 16, 24420, {1, 3, 5, 3, 27, 57, 7, 177, 183, 227, 865, 183, 2903, 6325, 4393, 5257}},
-{5200, 16, 24444, {1, 3, 1, 5, 21, 29, 79, 107, 365, 427, 813, 3563, 7713, 3865, 4289, 28555}},
-{5201, 16, 24465, {1, 3, 5, 7, 11, 27, 1, 197, 425, 769, 1737, 3627, 1273, 4469, 11967, 823}},
-{5202, 16, 24466, {1, 1, 1, 13, 3, 31, 127, 159, 471, 367, 2047, 949, 1591, 12429, 21497, 27153}},
-{5203, 16, 24471, {1, 3, 1, 3, 3, 31, 31, 87, 243, 413, 1777, 1361, 4575, 1147, 17451, 33985}},
-{5204, 16, 24475, {1, 3, 3, 5, 13, 47, 45, 3, 165, 329, 743, 397, 2479, 4999, 12921, 26689}},
-{5205, 16, 24481, {1, 1, 5, 7, 17, 59, 25, 117, 217, 601, 235, 2691, 5569, 7853, 31063, 28281}},
-{5206, 16, 24488, {1, 3, 1, 11, 11, 39, 71, 77, 481, 39, 363, 1921, 3263, 12849, 13325, 41803}},
-{5207, 16, 24501, {1, 3, 7, 5, 19, 1, 59, 197, 239, 787, 1657, 1449, 4245, 1317, 19609, 53583}},
-{5208, 16, 24514, {1, 1, 7, 1, 13, 33, 81, 53, 223, 323, 477, 2421, 4045, 1855, 5823, 9661}},
-{5209, 16, 24531, {1, 3, 1, 7, 1, 3, 121, 19, 329, 569, 481, 3443, 499, 12407, 19625, 4627}},
-{5210, 16, 24534, {1, 1, 1, 7, 3, 33, 91, 241, 69, 581, 1635, 1025, 4677, 14651, 5229, 19555}},
-{5211, 16, 24559, {1, 3, 1, 15, 9, 11, 99, 47, 489, 755, 601, 1221, 4251, 4377, 20567, 33839}},
-{5212, 16, 24602, {1, 3, 3, 5, 21, 21, 127, 151, 499, 971, 1627, 609, 2365, 3183, 7413, 697}},
-{5213, 16, 24614, {1, 3, 7, 13, 5, 35, 61, 121, 51, 297, 29, 1825, 495, 1299, 12741, 3253}},
-{5214, 16, 24637, {1, 1, 1, 1, 13, 15, 49, 205, 235, 9, 849, 1101, 4533, 10221, 32419, 50151}},
-{5215, 16, 24664, {1, 1, 3, 13, 29, 31, 57, 77, 217, 195, 1951, 189, 981, 6169, 22677, 64415}},
-{5216, 16, 24676, {1, 3, 1, 5, 15, 37, 25, 233, 43, 843, 1205, 153, 6339, 3767, 16725, 32699}},
-{5217, 16, 24679, {1, 3, 3, 1, 19, 37, 11, 217, 461, 897, 1181, 2815, 295, 15153, 25351, 57211}},
-{5218, 16, 24697, {1, 3, 5, 11, 15, 9, 5, 179, 353, 769, 1457, 2919, 1201, 14871, 29549, 52265}},
-{5219, 16, 24709, {1, 1, 3, 3, 5, 51, 127, 221, 329, 543, 1537, 2701, 2709, 9311, 2715, 42669}},
-{5220, 16, 24714, {1, 3, 5, 15, 5, 41, 79, 233, 445, 265, 2001, 935, 3133, 3977, 3601, 21389}},
-{5221, 16, 24716, {1, 3, 5, 11, 3, 7, 115, 45, 311, 827, 1897, 3399, 4251, 5341, 22621, 25519}},
-{5222, 16, 24731, {1, 3, 7, 1, 11, 57, 117, 103, 401, 505, 1683, 2161, 4363, 11189, 20263, 13065}},
-{5223, 16, 24744, {1, 1, 1, 7, 23, 29, 31, 77, 63, 179, 195, 2747, 579, 11701, 5101, 11497}},
-{5224, 16, 24762, {1, 3, 7, 3, 9, 33, 81, 165, 433, 545, 1893, 3709, 3813, 6615, 1485, 6395}},
-{5225, 16, 24764, {1, 3, 1, 15, 9, 5, 27, 157, 389, 683, 1919, 509, 455, 3865, 2303, 6993}},
-{5226, 16, 24769, {1, 3, 3, 9, 5, 5, 3, 5, 299, 59, 539, 1199, 2443, 10821, 3359, 44345}},
-{5227, 16, 24806, {1, 3, 5, 9, 21, 37, 87, 35, 501, 943, 1313, 3929, 351, 9851, 22971, 35659}},
-{5228, 16, 24812, {1, 3, 7, 11, 11, 33, 77, 175, 411, 315, 1797, 2731, 4611, 1809, 22027, 50595}},
-{5229, 16, 24872, {1, 3, 7, 13, 15, 11, 13, 189, 209, 1015, 1869, 1593, 6887, 8571, 7217, 2641}},
-{5230, 16, 24878, {1, 1, 3, 13, 29, 15, 119, 127, 329, 275, 865, 1693, 225, 15735, 11071, 37127}},
-{5231, 16, 24883, {1, 3, 7, 13, 9, 31, 85, 25, 281, 401, 1923, 2391, 3875, 2079, 2055, 53275}},
-{5232, 16, 24909, {1, 3, 1, 5, 23, 57, 79, 127, 209, 901, 315, 1165, 3393, 15095, 1981, 34993}},
-{5233, 16, 24943, {1, 3, 7, 7, 25, 13, 15, 223, 157, 335, 1061, 395, 6895, 6283, 18375, 4887}},
-{5234, 16, 24946, {1, 3, 7, 13, 9, 15, 99, 201, 105, 643, 117, 3027, 641, 13353, 4343, 11875}},
-{5235, 16, 24964, {1, 1, 3, 11, 5, 51, 5, 77, 281, 207, 1201, 1187, 8107, 6625, 7517, 34377}},
-{5236, 16, 24992, {1, 1, 1, 5, 29, 61, 3, 181, 297, 151, 565, 2713, 6611, 8665, 32425, 50399}},
-{5237, 16, 25016, {1, 3, 1, 5, 1, 61, 41, 245, 95, 647, 49, 2195, 5927, 15531, 28547, 51075}},
-{5238, 16, 25022, {1, 3, 3, 15, 15, 63, 123, 63, 77, 813, 423, 715, 91, 3793, 20901, 54927}},
-{5239, 16, 25024, {1, 3, 7, 9, 15, 35, 31, 161, 127, 13, 1667, 1225, 5279, 15487, 18769, 24887}},
-{5240, 16, 25039, {1, 1, 3, 5, 27, 25, 61, 21, 447, 175, 1419, 2691, 1993, 13059, 30809, 38325}},
-{5241, 16, 25051, {1, 3, 1, 3, 15, 21, 15, 193, 233, 435, 1993, 4003, 4581, 13837, 16535, 43781}},
-{5242, 16, 25060, {1, 1, 1, 5, 1, 11, 21, 253, 59, 59, 497, 77, 2165, 8197, 5933, 25743}},
-{5243, 16, 25072, {1, 1, 3, 9, 25, 61, 29, 217, 95, 269, 799, 409, 801, 421, 19065, 53443}},
-{5244, 16, 25097, {1, 1, 7, 1, 1, 41, 71, 59, 191, 867, 223, 1467, 6679, 16031, 4451, 15313}},
-{5245, 16, 25122, {1, 1, 1, 11, 13, 27, 7, 241, 167, 969, 1267, 2953, 3769, 2415, 30065, 39483}},
-{5246, 16, 25148, {1, 1, 1, 3, 25, 61, 103, 23, 53, 799, 989, 3859, 7299, 13613, 12007, 37535}},
-{5247, 16, 25194, {1, 1, 7, 1, 29, 19, 121, 57, 355, 663, 643, 3723, 1775, 10363, 1389, 16039}},
-{5248, 16, 25201, {1, 3, 7, 3, 21, 55, 51, 67, 363, 843, 1187, 1983, 7757, 5413, 26575, 53329}},
-{5249, 16, 25204, {1, 3, 1, 3, 31, 55, 73, 55, 75, 533, 197, 1463, 2933, 6033, 24397, 41579}},
-{5250, 16, 25238, {1, 3, 1, 11, 9, 15, 107, 141, 473, 825, 901, 937, 7433, 13119, 20047, 6695}},
-{5251, 16, 25241, {1, 3, 5, 7, 19, 27, 3, 149, 507, 137, 1025, 1841, 33, 3113, 15101, 28187}},
-{5252, 16, 25248, {1, 3, 5, 7, 31, 27, 53, 45, 177, 129, 1241, 1525, 991, 4141, 17681, 39435}},
-{5253, 16, 25257, {1, 1, 1, 15, 31, 57, 29, 137, 395, 563, 101, 3367, 1277, 5431, 1169, 44321}},
-{5254, 16, 25275, {1, 3, 5, 7, 21, 15, 123, 181, 113, 313, 1763, 1429, 2985, 715, 26129, 549}},
-{5255, 16, 25278, {1, 3, 3, 1, 15, 27, 27, 139, 507, 79, 1999, 2505, 485, 7011, 13369, 7159}},
-{5256, 16, 25304, {1, 3, 3, 11, 27, 53, 109, 179, 399, 657, 697, 421, 5467, 4273, 7837, 11631}},
-{5257, 16, 25307, {1, 1, 1, 15, 1, 57, 91, 199, 443, 569, 1945, 2531, 6349, 4851, 3931, 20537}},
-{5258, 16, 25320, {1, 1, 3, 13, 3, 3, 107, 237, 261, 377, 135, 2809, 7239, 1613, 24035, 26053}},
-{5259, 16, 25334, {1, 3, 3, 5, 3, 59, 65, 197, 411, 363, 1729, 967, 3963, 4535, 111, 7273}},
-{5260, 16, 25348, {1, 1, 7, 3, 13, 39, 105, 235, 203, 1015, 1031, 3127, 1209, 10817, 22177, 44117}},
-{5261, 16, 25357, {1, 3, 3, 13, 19, 21, 123, 31, 59, 185, 1007, 1115, 1965, 13087, 18489, 34063}},
-{5262, 16, 25372, {1, 1, 7, 5, 27, 7, 33, 159, 245, 57, 2003, 3229, 2095, 4939, 31355, 23121}},
-{5263, 16, 25394, {1, 3, 3, 9, 9, 41, 49, 203, 397, 915, 821, 3685, 2269, 11159, 25441, 46377}},
-{5264, 16, 25454, {1, 3, 7, 5, 29, 33, 29, 227, 361, 961, 1905, 1149, 2799, 8115, 28235, 25685}},
-{5265, 16, 25465, {1, 3, 1, 1, 19, 13, 73, 103, 11, 183, 853, 2425, 3809, 2391, 18615, 32735}},
-{5266, 16, 25472, {1, 1, 3, 3, 21, 57, 47, 57, 157, 43, 1085, 3319, 461, 11499, 6809, 10435}},
-{5267, 16, 25492, {1, 1, 5, 5, 17, 21, 55, 17, 421, 865, 159, 1643, 4523, 1485, 11937, 8287}},
-{5268, 16, 25505, {1, 1, 3, 11, 7, 43, 39, 37, 187, 797, 1273, 1227, 2683, 1249, 3375, 44499}},
-{5269, 16, 25517, {1, 1, 5, 11, 17, 35, 27, 73, 97, 59, 921, 2171, 7577, 2847, 93, 35911}},
-{5270, 16, 25530, {1, 1, 5, 1, 5, 17, 117, 189, 357, 581, 1945, 2141, 1679, 12019, 11249, 6809}},
-{5271, 16, 25558, {1, 1, 5, 7, 15, 53, 9, 191, 153, 257, 533, 493, 2389, 4657, 20757, 57275}},
-{5272, 16, 25562, {1, 1, 1, 11, 13, 35, 85, 37, 501, 525, 543, 4057, 2001, 6183, 949, 18465}},
-{5273, 16, 25598, {1, 1, 1, 3, 15, 7, 39, 169, 359, 671, 731, 1523, 211, 1233, 29515, 57787}},
-{5274, 16, 25609, {1, 1, 3, 7, 27, 7, 41, 15, 71, 733, 1919, 401, 1915, 4815, 10571, 839}},
-{5275, 16, 25612, {1, 1, 7, 13, 27, 61, 5, 25, 293, 779, 477, 1537, 6695, 7435, 1281, 64369}},
-{5276, 16, 25627, {1, 1, 7, 7, 19, 11, 101, 45, 449, 883, 1181, 3521, 6019, 16305, 23429, 43789}},
-{5277, 16, 25651, {1, 1, 7, 5, 1, 49, 121, 89, 275, 367, 461, 1717, 2733, 4403, 9123, 35217}},
-{5278, 16, 25653, {1, 1, 7, 1, 1, 37, 41, 221, 281, 531, 357, 3783, 3561, 8135, 18405, 56045}},
-{5279, 16, 25668, {1, 3, 5, 7, 29, 9, 127, 37, 13, 519, 1059, 3973, 7253, 15159, 19337, 57103}},
-{5280, 16, 25711, {1, 3, 3, 15, 3, 41, 91, 7, 63, 747, 1649, 3367, 5945, 3603, 28465, 511}},
-{5281, 16, 25765, {1, 3, 3, 15, 27, 19, 67, 179, 505, 131, 149, 1753, 3603, 1135, 15811, 5305}},
-{5282, 16, 25770, {1, 1, 1, 5, 5, 63, 71, 235, 151, 651, 1383, 249, 3223, 14559, 26809, 4551}},
-{5283, 16, 25775, {1, 3, 3, 9, 29, 41, 67, 111, 175, 515, 1123, 1707, 6653, 8233, 22775, 61029}},
-{5284, 16, 25777, {1, 3, 3, 9, 23, 1, 75, 145, 159, 785, 537, 1995, 2241, 8641, 30709, 41373}},
-{5285, 16, 25783, {1, 1, 5, 9, 21, 1, 87, 233, 401, 643, 197, 3437, 8163, 6363, 6537, 17283}},
-{5286, 16, 25801, {1, 3, 5, 3, 23, 19, 55, 243, 405, 369, 1221, 1959, 5455, 11729, 26117, 9097}},
-{5287, 16, 25802, {1, 1, 3, 13, 3, 57, 71, 235, 125, 263, 873, 1079, 2627, 1343, 1979, 49519}},
-{5288, 16, 25812, {1, 3, 1, 11, 21, 15, 27, 7, 425, 935, 305, 2593, 4437, 9517, 26207, 4229}},
-{5289, 16, 25821, {1, 1, 3, 13, 11, 53, 1, 149, 97, 939, 147, 3365, 5023, 607, 2083, 8715}},
-{5290, 16, 25897, {1, 1, 5, 3, 13, 13, 113, 51, 263, 837, 1145, 3621, 5697, 2867, 7975, 22839}},
-{5291, 16, 25906, {1, 1, 3, 15, 31, 9, 91, 231, 399, 295, 1935, 4021, 7669, 3867, 28015, 9865}},
-{5292, 16, 25929, {1, 1, 1, 1, 13, 59, 51, 35, 407, 733, 1629, 2429, 291, 11923, 32129, 28847}},
-{5293, 16, 25940, {1, 3, 3, 11, 25, 21, 13, 117, 31, 547, 327, 2801, 2247, 4051, 27523, 4257}},
-{5294, 16, 25950, {1, 1, 7, 7, 15, 33, 15, 17, 255, 363, 1013, 1463, 7537, 14093, 21883, 35389}},
-{5295, 16, 25968, {1, 1, 5, 9, 11, 61, 7, 161, 121, 413, 515, 413, 4439, 15405, 30265, 23939}},
-{5296, 16, 25971, {1, 3, 7, 7, 11, 15, 5, 181, 315, 231, 1567, 2985, 1653, 12251, 269, 37317}},
-{5297, 16, 25977, {1, 3, 1, 11, 3, 15, 91, 45, 489, 571, 11, 1239, 7705, 4303, 12535, 21359}},
-{5298, 16, 25994, {1, 1, 7, 15, 29, 43, 81, 63, 483, 851, 389, 1719, 6111, 15293, 2513, 44397}},
-{5299, 16, 25996, {1, 1, 5, 15, 25, 33, 97, 131, 183, 269, 1903, 2733, 7197, 4507, 24471, 36871}},
-{5300, 16, 25999, {1, 3, 3, 13, 17, 33, 73, 83, 247, 207, 79, 1139, 581, 12147, 3539, 45423}},
-{5301, 16, 26001, {1, 1, 1, 15, 29, 49, 79, 151, 267, 393, 1995, 105, 2873, 3981, 19147, 53987}},
-{5302, 16, 26030, {1, 1, 5, 1, 31, 25, 39, 203, 459, 181, 661, 717, 6235, 13413, 1197, 40665}},
-{5303, 16, 26069, {1, 1, 5, 9, 19, 33, 65, 239, 463, 133, 461, 3601, 7755, 1771, 20683, 7417}},
-{5304, 16, 26100, {1, 1, 1, 1, 25, 19, 25, 155, 431, 33, 341, 959, 5679, 1205, 2599, 37499}},
-{5305, 16, 26109, {1, 1, 3, 5, 25, 5, 83, 87, 91, 991, 1833, 4063, 147, 14497, 25725, 4617}},
-{5306, 16, 26131, {1, 3, 5, 7, 31, 7, 73, 51, 339, 313, 1593, 2089, 7387, 15759, 3249, 7953}},
-{5307, 16, 26144, {1, 3, 7, 1, 27, 49, 35, 11, 21, 45, 1689, 1665, 4591, 3713, 12781, 4805}},
-{5308, 16, 26149, {1, 1, 3, 9, 29, 51, 73, 51, 303, 179, 67, 3917, 7615, 6131, 26225, 55991}},
-{5309, 16, 26162, {1, 3, 7, 11, 9, 63, 29, 47, 153, 883, 1859, 1913, 3563, 11451, 6333, 51367}},
-{5310, 16, 26167, {1, 3, 1, 3, 5, 25, 69, 87, 389, 613, 989, 3557, 1339, 12503, 14505, 63209}},
-{5311, 16, 26173, {1, 1, 3, 1, 5, 13, 37, 163, 499, 163, 2025, 1467, 5059, 8479, 2889, 62957}},
-{5312, 16, 26179, {1, 1, 7, 9, 23, 31, 109, 49, 73, 197, 337, 2763, 4789, 8983, 9691, 32155}},
-{5313, 16, 26193, {1, 3, 1, 3, 31, 25, 121, 91, 371, 339, 833, 2217, 4997, 9425, 10685, 60037}},
-{5314, 16, 26230, {1, 1, 7, 11, 31, 3, 105, 125, 255, 175, 803, 1787, 6231, 4441, 5031, 29737}},
-{5315, 16, 26234, {1, 1, 1, 11, 21, 63, 75, 209, 393, 437, 495, 2397, 4759, 15703, 29869, 62685}},
-{5316, 16, 26246, {1, 1, 7, 7, 25, 33, 117, 7, 293, 623, 2001, 2409, 2487, 14803, 3329, 38277}},
-{5317, 16, 26267, {1, 1, 7, 9, 31, 51, 75, 151, 487, 85, 639, 3529, 4491, 1957, 22099, 20263}},
-{5318, 16, 26283, {1, 1, 7, 5, 3, 29, 11, 1, 255, 555, 1269, 779, 1525, 7689, 25847, 39347}},
-{5319, 16, 26300, {1, 1, 7, 7, 19, 21, 9, 123, 3, 943, 1627, 2979, 919, 4565, 31435, 59789}},
-{5320, 16, 26341, {1, 3, 7, 5, 29, 13, 57, 221, 9, 893, 1685, 1879, 4575, 7369, 26191, 6067}},
-{5321, 16, 26356, {1, 3, 7, 9, 13, 11, 9, 27, 313, 751, 1377, 1121, 3799, 1673, 16305, 30665}},
-{5322, 16, 26377, {1, 3, 3, 13, 23, 17, 59, 47, 499, 525, 681, 3195, 1611, 7003, 7325, 53019}},
-{5323, 16, 26397, {1, 3, 1, 7, 23, 51, 59, 127, 67, 263, 1305, 2479, 637, 9441, 6329, 12857}},
-{5324, 16, 26404, {1, 1, 7, 7, 9, 3, 51, 193, 205, 503, 19, 2513, 7489, 9241, 15371, 20875}},
-{5325, 16, 26411, {1, 3, 3, 1, 1, 57, 17, 181, 23, 549, 769, 2325, 3669, 7017, 25601, 64479}},
-{5326, 16, 26422, {1, 3, 1, 15, 5, 55, 53, 13, 327, 447, 1031, 1599, 3639, 15305, 1387, 16035}},
-{5327, 16, 26451, {1, 3, 7, 15, 9, 41, 53, 113, 97, 99, 1377, 4047, 3713, 8891, 5601, 5853}},
-{5328, 16, 26454, {1, 1, 7, 9, 9, 7, 29, 249, 411, 315, 181, 2153, 6135, 6947, 27595, 15553}},
-{5329, 16, 26463, {1, 1, 7, 11, 3, 57, 35, 55, 165, 313, 577, 3049, 4259, 4231, 7225, 58973}},
-{5330, 16, 26488, {1, 1, 1, 1, 15, 43, 53, 143, 157, 843, 465, 3897, 4797, 12305, 28807, 46381}},
-{5331, 16, 26498, {1, 3, 7, 9, 17, 3, 99, 61, 475, 507, 831, 2207, 367, 27, 23205, 2303}},
-{5332, 16, 26509, {1, 1, 3, 11, 27, 29, 99, 237, 43, 955, 361, 3231, 1863, 7973, 8969, 58663}},
-{5333, 16, 26512, {1, 3, 1, 7, 15, 15, 11, 251, 135, 261, 675, 3723, 7675, 7993, 1725, 41149}},
-{5334, 16, 26517, {1, 3, 3, 9, 29, 11, 105, 37, 151, 215, 1911, 4051, 5427, 11019, 9073, 33129}},
-{5335, 16, 26534, {1, 3, 3, 1, 19, 7, 103, 81, 371, 253, 1043, 1231, 6497, 10377, 2349, 29047}},
-{5336, 16, 26545, {1, 3, 7, 9, 15, 11, 85, 61, 507, 629, 811, 3883, 1435, 13035, 31913, 2153}},
-{5337, 16, 26546, {1, 1, 5, 11, 13, 7, 63, 147, 117, 223, 1217, 3317, 3275, 6851, 2917, 55901}},
-{5338, 16, 26636, {1, 3, 3, 9, 7, 21, 1, 63, 117, 297, 405, 797, 337, 10173, 8327, 29157}},
-{5339, 16, 26749, {1, 1, 7, 11, 31, 63, 97, 191, 259, 421, 1829, 2117, 4203, 11919, 18001, 55791}},
-{5340, 16, 26753, {1, 3, 7, 9, 21, 13, 125, 247, 133, 611, 463, 227, 7815, 8877, 17961, 3641}},
-{5341, 16, 26759, {1, 1, 7, 9, 27, 21, 97, 165, 371, 715, 491, 3929, 3067, 12501, 5511, 18217}},
-{5342, 16, 26774, {1, 3, 3, 15, 27, 17, 81, 161, 263, 273, 135, 1159, 7535, 4581, 16065, 11493}},
-{5343, 16, 26789, {1, 3, 3, 7, 11, 59, 111, 47, 381, 413, 243, 2173, 4957, 2451, 15669, 22071}},
-{5344, 16, 26808, {1, 3, 7, 5, 3, 31, 65, 131, 111, 141, 1891, 2983, 3331, 769, 24075, 40865}},
-{5345, 16, 26825, {1, 3, 7, 11, 11, 63, 7, 213, 333, 111, 1235, 961, 3749, 9123, 5067, 9657}},
-{5346, 16, 26831, {1, 3, 3, 1, 9, 33, 1, 225, 37, 951, 1995, 3215, 3117, 3723, 15013, 64525}},
-{5347, 16, 26859, {1, 3, 3, 13, 29, 19, 103, 65, 67, 423, 1679, 3791, 5551, 11711, 195, 52291}},
-{5348, 16, 26888, {1, 3, 1, 15, 31, 7, 65, 249, 489, 287, 1385, 1075, 1357, 13593, 20853, 46221}},
-{5349, 16, 26918, {1, 1, 1, 13, 23, 45, 29, 175, 147, 101, 1007, 1867, 5387, 12683, 29609, 55861}},
-{5350, 16, 26929, {1, 3, 5, 13, 21, 31, 85, 187, 183, 179, 1337, 481, 71, 6117, 2177, 27915}},
-{5351, 16, 26950, {1, 3, 5, 1, 15, 5, 11, 141, 205, 177, 891, 3591, 4371, 889, 12957, 61083}},
-{5352, 16, 26954, {1, 3, 7, 7, 11, 39, 81, 241, 13, 757, 521, 3029, 2345, 12385, 20683, 64053}},
-{5353, 16, 26973, {1, 1, 5, 13, 7, 3, 77, 211, 215, 97, 1409, 1021, 1267, 4785, 27231, 2877}},
-{5354, 16, 26997, {1, 3, 5, 3, 11, 57, 93, 39, 415, 179, 1033, 3267, 5383, 10451, 27117, 10711}},
-{5355, 16, 26998, {1, 1, 1, 1, 3, 45, 93, 179, 453, 995, 1423, 3849, 4381, 15789, 20789, 18775}},
-{5356, 16, 27008, {1, 3, 1, 3, 13, 25, 33, 165, 351, 887, 1109, 195, 8131, 3061, 16743, 22997}},
-{5357, 16, 27038, {1, 3, 1, 5, 23, 35, 93, 155, 333, 603, 1571, 229, 2979, 6295, 20793, 40901}},
-{5358, 16, 27109, {1, 3, 3, 11, 29, 57, 101, 61, 487, 719, 1009, 1933, 7815, 15329, 12489, 26105}},
-{5359, 16, 27127, {1, 3, 3, 9, 23, 59, 73, 13, 141, 815, 1819, 3557, 2555, 5901, 23039, 62321}},
-{5360, 16, 27150, {1, 1, 3, 5, 19, 49, 27, 139, 35, 995, 565, 323, 6439, 15679, 27017, 30889}},
-{5361, 16, 27168, {1, 3, 7, 3, 1, 3, 27, 153, 235, 59, 989, 2763, 4197, 3931, 31227, 27129}},
-{5362, 16, 27178, {1, 3, 1, 15, 23, 45, 71, 205, 465, 451, 347, 1909, 3287, 8363, 9081, 35641}},
-{5363, 16, 27212, {1, 1, 5, 1, 25, 29, 17, 201, 463, 903, 1729, 3435, 2483, 10835, 14315, 52505}},
-{5364, 16, 27224, {1, 1, 1, 15, 13, 23, 3, 175, 273, 305, 1945, 3319, 7777, 9411, 4209, 4047}},
-{5365, 16, 27229, {1, 1, 5, 15, 25, 5, 71, 35, 307, 89, 301, 3465, 1497, 13467, 21911, 13611}},
-{5366, 16, 27246, {1, 3, 1, 7, 11, 7, 33, 241, 349, 751, 633, 3281, 6733, 13833, 23605, 34307}},
-{5367, 16, 27251, {1, 1, 1, 15, 17, 27, 45, 13, 259, 843, 1207, 1735, 4063, 6259, 1751, 45107}},
-{5368, 16, 27257, {1, 1, 5, 15, 29, 51, 73, 95, 5, 31, 933, 423, 5505, 2193, 14919, 2715}},
-{5369, 16, 27258, {1, 3, 1, 3, 23, 5, 29, 7, 271, 485, 827, 1159, 77, 16337, 27933, 18741}},
-{5370, 16, 27260, {1, 3, 7, 9, 23, 33, 47, 191, 59, 301, 1277, 3745, 7837, 799, 2861, 25853}},
-{5371, 16, 27287, {1, 3, 7, 13, 13, 39, 33, 91, 279, 855, 1917, 3601, 3971, 6193, 16951, 6115}},
-{5372, 16, 27300, {1, 1, 3, 13, 15, 59, 89, 239, 313, 545, 431, 3823, 5741, 14981, 2647, 42813}},
-{5373, 16, 27315, {1, 1, 1, 3, 17, 21, 45, 37, 343, 737, 1795, 2659, 2897, 7683, 15191, 1393}},
-{5374, 16, 27329, {1, 1, 3, 3, 19, 55, 27, 201, 459, 953, 1531, 671, 5667, 11695, 149, 14605}},
-{5375, 16, 27332, {1, 3, 7, 13, 9, 63, 67, 229, 69, 819, 859, 2035, 5725, 13403, 24197, 2599}},
-{5376, 16, 27349, {1, 1, 7, 7, 1, 59, 45, 105, 327, 779, 59, 791, 7593, 8189, 28161, 13339}},
-{5377, 16, 27350, {1, 3, 3, 15, 25, 55, 125, 189, 327, 733, 115, 3541, 5227, 12143, 32719, 15785}},
-{5378, 16, 27354, {1, 3, 3, 7, 19, 51, 35, 63, 507, 89, 1441, 2369, 4927, 7953, 10193, 8331}},
-{5379, 16, 27359, {1, 1, 5, 5, 21, 1, 41, 49, 217, 1001, 1649, 2789, 5267, 1525, 3811, 40785}},
-{5380, 16, 27377, {1, 1, 7, 15, 31, 21, 33, 183, 425, 393, 367, 3253, 3047, 465, 28229, 44743}},
-{5381, 16, 27378, {1, 3, 7, 5, 1, 23, 11, 71, 269, 707, 5, 2931, 1959, 15089, 9299, 43927}},
-{5382, 16, 27383, {1, 3, 5, 15, 21, 51, 31, 15, 49, 481, 297, 3871, 751, 10661, 26401, 62923}},
-{5383, 16, 27384, {1, 3, 1, 7, 17, 27, 35, 255, 205, 865, 1659, 1921, 5457, 11633, 2825, 13549}},
-{5384, 16, 27387, {1, 1, 5, 15, 17, 35, 83, 237, 437, 7, 2001, 2225, 2601, 10841, 7953, 20651}},
-{5385, 16, 27392, {1, 1, 1, 3, 3, 37, 43, 135, 451, 203, 1319, 261, 3889, 14489, 9635, 52545}},
-{5386, 16, 27402, {1, 3, 3, 13, 15, 41, 95, 207, 43, 997, 207, 3459, 5995, 5187, 15851, 28551}},
-{5387, 16, 27438, {1, 1, 1, 5, 23, 57, 49, 101, 303, 921, 745, 1407, 7071, 2765, 18703, 32671}},
-{5388, 16, 27481, {1, 1, 7, 13, 9, 59, 65, 157, 209, 295, 107, 3175, 3401, 1197, 1875, 9033}},
-{5389, 16, 27482, {1, 1, 3, 3, 17, 9, 101, 75, 177, 905, 1013, 397, 3421, 6475, 15897, 11269}},
-{5390, 16, 27494, {1, 3, 1, 5, 29, 53, 105, 83, 383, 137, 1169, 1245, 6973, 8701, 317, 10073}},
-{5391, 16, 27531, {1, 1, 1, 3, 15, 55, 69, 219, 507, 707, 945, 397, 779, 4157, 10333, 7869}},
-{5392, 16, 27542, {1, 3, 1, 3, 9, 21, 125, 153, 107, 969, 1979, 651, 1199, 11419, 17043, 32269}},
-{5393, 16, 27546, {1, 1, 1, 7, 1, 29, 71, 127, 209, 853, 1515, 1169, 5055, 9981, 30291, 29569}},
-{5394, 16, 27564, {1, 3, 1, 11, 1, 1, 109, 251, 329, 633, 2021, 1237, 2147, 11471, 26025, 19649}},
-{5395, 16, 27567, {1, 1, 5, 1, 5, 7, 77, 175, 251, 143, 711, 1241, 2133, 9993, 9203, 24949}},
-{5396, 16, 27582, {1, 3, 5, 11, 19, 11, 101, 83, 91, 595, 753, 2389, 1887, 11569, 29759, 55785}},
-{5397, 16, 27608, {1, 1, 1, 3, 29, 47, 49, 249, 495, 451, 1887, 2547, 543, 2755, 17207, 24379}},
-{5398, 16, 27611, {1, 3, 7, 7, 19, 15, 95, 143, 109, 221, 2041, 3593, 4571, 14547, 14217, 16711}},
-{5399, 16, 27624, {1, 3, 5, 13, 27, 55, 31, 209, 39, 989, 1435, 1665, 7265, 14127, 13517, 37647}},
-{5400, 16, 27629, {1, 1, 3, 7, 1, 49, 63, 71, 249, 371, 435, 3591, 2677, 143, 28897, 38981}},
-{5401, 16, 27655, {1, 1, 7, 7, 21, 9, 53, 221, 23, 515, 1971, 3759, 3511, 10207, 12929, 42021}},
-{5402, 16, 27667, {1, 3, 1, 13, 25, 21, 3, 85, 421, 19, 663, 3219, 3541, 13021, 5765, 39623}},
-{5403, 16, 27676, {1, 3, 1, 7, 11, 5, 125, 169, 293, 715, 1111, 2965, 4815, 6047, 27207, 23093}},
-{5404, 16, 27710, {1, 1, 5, 13, 11, 15, 37, 201, 457, 551, 821, 25, 435, 14307, 25855, 1811}},
-{5405, 16, 27724, {1, 3, 3, 9, 27, 15, 1, 253, 217, 549, 1013, 2277, 4171, 3813, 19857, 8641}},
-{5406, 16, 27745, {1, 3, 5, 5, 29, 37, 71, 49, 163, 949, 425, 2459, 945, 13125, 13981, 21669}},
-{5407, 16, 27752, {1, 3, 3, 9, 17, 23, 53, 235, 83, 887, 439, 1939, 7601, 15275, 15739, 17623}},
-{5408, 16, 27770, {1, 3, 5, 13, 7, 51, 73, 67, 167, 849, 2021, 2977, 6591, 3721, 5827, 40897}},
-{5409, 16, 27779, {1, 1, 5, 11, 27, 19, 81, 181, 383, 23, 1061, 3327, 1671, 7113, 7435, 17591}},
-{5410, 16, 27781, {1, 3, 3, 7, 25, 33, 73, 23, 103, 821, 917, 1425, 4739, 7227, 12365, 29509}},
-{5411, 16, 27791, {1, 1, 1, 7, 3, 37, 81, 231, 135, 663, 1983, 399, 6881, 14991, 4957, 20913}},
-{5412, 16, 27809, {1, 3, 7, 15, 25, 41, 65, 215, 301, 471, 1669, 65, 227, 9307, 29867, 9503}},
-{5413, 16, 27810, {1, 1, 7, 3, 25, 47, 31, 63, 53, 995, 33, 1297, 3423, 12301, 16255, 14467}},
-{5414, 16, 27815, {1, 3, 1, 1, 31, 25, 79, 131, 353, 169, 1425, 2257, 2631, 1559, 793, 48383}},
-{5415, 16, 27827, {1, 3, 3, 5, 31, 9, 93, 35, 503, 243, 595, 2939, 771, 7333, 13429, 59457}},
-{5416, 16, 27834, {1, 3, 1, 7, 5, 51, 21, 237, 453, 743, 775, 2207, 453, 12077, 12283, 9735}},
-{5417, 16, 27865, {1, 3, 1, 15, 5, 47, 59, 239, 87, 97, 885, 3191, 2547, 13227, 7433, 4989}},
-{5418, 16, 27899, {1, 3, 5, 15, 21, 33, 41, 155, 509, 317, 517, 1101, 133, 1897, 8235, 57673}},
-{5419, 16, 27901, {1, 1, 5, 15, 7, 9, 59, 155, 415, 831, 1173, 1263, 5451, 7181, 7233, 51483}},
-{5420, 16, 27914, {1, 1, 7, 3, 31, 43, 71, 39, 155, 529, 895, 827, 3203, 4625, 32185, 53507}},
-{5421, 16, 27950, {1, 3, 1, 11, 15, 17, 85, 141, 277, 439, 1775, 4015, 4457, 281, 22455, 47591}},
-{5422, 16, 27994, {1, 3, 5, 11, 25, 41, 93, 39, 51, 655, 1347, 3109, 2479, 9057, 18939, 26217}},
-{5423, 16, 28005, {1, 3, 3, 11, 31, 41, 7, 189, 241, 443, 65, 1723, 4817, 13405, 9641, 63965}},
-{5424, 16, 28009, {1, 1, 5, 3, 19, 29, 111, 11, 399, 277, 425, 1331, 5365, 14521, 16449, 29411}},
-{5425, 16, 28033, {1, 1, 3, 9, 25, 53, 91, 175, 481, 307, 1025, 71, 7425, 10667, 4053, 25605}},
-{5426, 16, 28039, {1, 3, 7, 7, 3, 13, 75, 175, 467, 363, 1889, 1759, 1155, 5511, 13047, 39637}},
-{5427, 16, 28060, {1, 3, 7, 9, 5, 21, 65, 43, 223, 97, 835, 2253, 3313, 9817, 23015, 55365}},
-{5428, 16, 28067, {1, 1, 1, 13, 9, 63, 95, 61, 417, 713, 1469, 1815, 795, 13609, 1567, 33535}},
-{5429, 16, 28069, {1, 3, 7, 1, 25, 45, 41, 27, 53, 407, 1633, 1317, 6267, 3293, 8899, 45235}},
-{5430, 16, 28099, {1, 3, 5, 11, 23, 47, 91, 211, 41, 775, 1301, 1407, 7931, 4491, 7579, 62321}},
-{5431, 16, 28113, {1, 1, 1, 7, 23, 15, 57, 31, 437, 293, 1999, 2589, 5453, 2519, 15533, 26949}},
-{5432, 16, 28114, {1, 3, 1, 9, 1, 27, 41, 165, 129, 297, 1887, 1171, 201, 5817, 24503, 38911}},
-{5433, 16, 28139, {1, 3, 1, 7, 1, 11, 63, 225, 191, 623, 1281, 3275, 167, 14697, 4905, 47289}},
-{5434, 16, 28142, {1, 3, 7, 7, 15, 47, 87, 177, 303, 391, 355, 3997, 7557, 6201, 20531, 22483}},
-{5435, 16, 28153, {1, 3, 3, 15, 17, 31, 111, 87, 61, 477, 1581, 3787, 5919, 10511, 2607, 62951}},
-{5436, 16, 28166, {1, 3, 3, 9, 29, 19, 63, 27, 205, 915, 1131, 3821, 673, 2875, 12703, 14367}},
-{5437, 16, 28172, {1, 3, 7, 1, 21, 19, 25, 97, 281, 635, 629, 181, 5207, 11133, 3687, 3489}},
-{5438, 16, 28183, {1, 3, 3, 9, 5, 63, 3, 21, 385, 713, 1805, 3583, 2807, 15455, 13057, 39771}},
-{5439, 16, 28194, {1, 3, 5, 9, 3, 59, 1, 253, 123, 405, 575, 3911, 4609, 11869, 23593, 947}},
-{5440, 16, 28232, {1, 1, 7, 5, 21, 27, 101, 221, 413, 153, 1647, 3637, 803, 5697, 20761, 61137}},
-{5441, 16, 28245, {1, 3, 7, 13, 31, 35, 111, 253, 187, 499, 465, 157, 5551, 10417, 323, 34913}},
-{5442, 16, 28246, {1, 1, 1, 7, 11, 41, 29, 65, 393, 69, 1373, 2291, 7807, 13159, 13735, 31001}},
-{5443, 16, 28252, {1, 3, 7, 13, 31, 49, 1, 35, 377, 11, 427, 2803, 1725, 9165, 22633, 63985}},
-{5444, 16, 28265, {1, 3, 7, 13, 3, 41, 27, 43, 269, 599, 1035, 3681, 309, 6011, 1065, 27901}},
-{5445, 16, 28301, {1, 3, 5, 13, 1, 19, 105, 143, 425, 883, 1669, 155, 189, 8573, 10759, 25507}},
-{5446, 16, 28323, {1, 3, 5, 1, 15, 37, 115, 9, 149, 79, 1733, 1045, 1849, 3289, 13957, 63171}},
-{5447, 16, 28344, {1, 1, 3, 9, 17, 27, 49, 201, 155, 901, 47, 1585, 4419, 8117, 25425, 14699}},
-{5448, 16, 28362, {1, 1, 7, 13, 19, 55, 19, 21, 427, 77, 1295, 1471, 6271, 7985, 19337, 12701}},
-{5449, 16, 28400, {1, 1, 1, 1, 11, 49, 101, 53, 175, 157, 839, 2713, 6149, 6391, 8089, 27739}},
-{5450, 16, 28417, {1, 3, 1, 1, 5, 21, 121, 199, 107, 221, 993, 1737, 409, 2545, 9287, 54605}},
-{5451, 16, 28454, {1, 1, 1, 3, 25, 25, 51, 121, 371, 861, 967, 3257, 6221, 11701, 27897, 42509}},
-{5452, 16, 28466, {1, 1, 1, 3, 17, 25, 101, 191, 313, 817, 815, 1855, 7999, 12649, 23385, 26081}},
-{5453, 16, 28468, {1, 1, 5, 1, 25, 55, 51, 237, 63, 943, 455, 619, 2381, 9773, 14575, 34205}},
-{5454, 16, 28477, {1, 3, 3, 3, 13, 49, 101, 37, 457, 727, 1009, 2389, 4841, 16303, 9599, 17773}},
-{5455, 16, 28498, {1, 1, 7, 9, 19, 59, 111, 205, 19, 229, 1755, 1169, 7767, 13335, 19669, 33269}},
-{5456, 16, 28510, {1, 3, 1, 15, 29, 1, 51, 167, 7, 415, 1295, 3165, 1241, 12859, 5531, 20083}},
-{5457, 16, 28513, {1, 1, 3, 7, 7, 51, 31, 221, 57, 643, 1461, 3951, 6237, 5757, 1907, 40471}},
-{5458, 16, 28571, {1, 3, 3, 5, 23, 39, 49, 177, 183, 117, 1379, 3803, 771, 12723, 22291, 32667}},
-{5459, 16, 28573, {1, 1, 3, 13, 27, 17, 39, 27, 313, 141, 1421, 2967, 2213, 1915, 23219, 15113}},
-{5460, 16, 28578, {1, 1, 1, 11, 5, 55, 51, 55, 389, 895, 57, 1447, 1497, 2799, 19585, 11587}},
-{5461, 16, 28587, {1, 1, 5, 13, 11, 55, 91, 77, 69, 131, 93, 1383, 3321, 10487, 15087, 8539}},
-{5462, 16, 28601, {1, 1, 3, 9, 23, 49, 107, 131, 363, 733, 1189, 3575, 7815, 10071, 20291, 7533}},
-{5463, 16, 28646, {1, 1, 3, 15, 31, 31, 73, 15, 199, 17, 761, 3271, 1419, 12985, 32717, 37317}},
-{5464, 16, 28663, {1, 3, 1, 13, 23, 9, 3, 59, 109, 729, 1321, 4023, 7041, 14445, 22205, 8993}},
-{5465, 16, 28681, {1, 1, 3, 15, 19, 43, 99, 59, 491, 479, 715, 2235, 7493, 889, 31465, 1375}},
-{5466, 16, 28682, {1, 3, 3, 15, 9, 47, 35, 115, 227, 615, 605, 1143, 5923, 10939, 9497, 24911}},
-{5467, 16, 28699, {1, 1, 3, 15, 23, 53, 111, 87, 423, 497, 85, 3525, 7341, 8885, 21543, 30083}},
-{5468, 16, 28706, {1, 1, 5, 3, 21, 5, 117, 157, 407, 743, 715, 1883, 4425, 10187, 6395, 43673}},
-{5469, 16, 28708, {1, 3, 3, 3, 31, 39, 119, 77, 269, 891, 1391, 3085, 2881, 10639, 3391, 44911}},
-{5470, 16, 28717, {1, 3, 7, 5, 7, 5, 115, 91, 5, 107, 1401, 1409, 1811, 737, 5399, 9119}},
-{5471, 16, 28720, {1, 1, 5, 9, 17, 45, 107, 15, 397, 299, 1219, 1675, 963, 10111, 31679, 13809}},
-{5472, 16, 28735, {1, 1, 3, 7, 29, 17, 43, 95, 261, 601, 1091, 3633, 1357, 13461, 16583, 12183}},
-{5473, 16, 28761, {1, 1, 5, 1, 19, 55, 5, 195, 187, 427, 421, 1717, 4223, 2943, 23147, 32985}},
-{5474, 16, 28783, {1, 3, 1, 3, 3, 23, 69, 95, 347, 273, 1223, 3061, 1587, 4707, 32415, 53991}},
-{5475, 16, 28788, {1, 1, 7, 13, 15, 13, 29, 151, 325, 949, 2029, 813, 5339, 14165, 1159, 56917}},
-{5476, 16, 28811, {1, 1, 1, 13, 9, 33, 67, 109, 215, 313, 1407, 3543, 2403, 5051, 20367, 13527}},
-{5477, 16, 28825, {1, 3, 1, 9, 5, 1, 9, 195, 497, 495, 1107, 745, 1647, 10637, 1933, 44965}},
-{5478, 16, 28838, {1, 1, 3, 9, 13, 19, 49, 183, 497, 519, 1433, 519, 4317, 2359, 10349, 63789}},
-{5479, 16, 28850, {1, 3, 5, 9, 29, 45, 55, 163, 189, 533, 275, 237, 5453, 8895, 6377, 14117}},
-{5480, 16, 28891, {1, 3, 7, 5, 25, 3, 111, 241, 139, 383, 689, 3481, 2557, 11163, 5275, 14671}},
-{5481, 16, 28897, {1, 3, 3, 9, 3, 5, 5, 141, 507, 331, 645, 1957, 5857, 2083, 24717, 11131}},
-{5482, 16, 28932, {1, 1, 5, 1, 11, 49, 113, 45, 491, 945, 1467, 3485, 6369, 15983, 14489, 12679}},
-{5483, 16, 28975, {1, 3, 7, 9, 11, 41, 77, 127, 147, 635, 1757, 587, 7423, 4233, 14875, 30531}},
-{5484, 16, 28998, {1, 3, 3, 9, 17, 29, 21, 249, 155, 441, 1443, 2093, 1967, 2117, 5815, 3857}},
-{5485, 16, 29052, {1, 3, 5, 3, 11, 55, 75, 157, 105, 507, 309, 3737, 2645, 7547, 29373, 62775}},
-{5486, 16, 29090, {1, 1, 3, 3, 11, 29, 49, 241, 21, 653, 1273, 715, 8123, 14241, 25257, 1681}},
-{5487, 16, 29096, {1, 1, 7, 5, 11, 31, 33, 215, 243, 369, 247, 3365, 4065, 9389, 32457, 58393}},
-{5488, 16, 29104, {1, 3, 5, 3, 31, 55, 51, 201, 439, 835, 1805, 25, 7987, 10611, 26893, 43663}},
-{5489, 16, 29113, {1, 1, 5, 9, 27, 51, 29, 31, 17, 163, 71, 603, 3083, 12439, 11043, 6471}},
-{5490, 16, 29133, {1, 1, 5, 7, 13, 1, 91, 109, 213, 721, 1345, 3037, 3047, 5209, 15559, 17467}},
-{5491, 16, 29142, {1, 1, 3, 9, 19, 37, 93, 185, 107, 859, 501, 3843, 1631, 4389, 2215, 52225}},
-{5492, 16, 29170, {1, 1, 3, 3, 25, 5, 119, 17, 33, 841, 997, 439, 6135, 7405, 8445, 40087}},
-{5493, 16, 29192, {1, 1, 7, 15, 19, 17, 101, 43, 423, 647, 29, 1143, 3259, 7807, 15929, 809}},
-{5494, 16, 29221, {1, 1, 7, 13, 21, 57, 83, 101, 183, 309, 171, 3173, 7919, 7263, 29403, 11055}},
-{5495, 16, 29236, {1, 1, 1, 13, 3, 1, 57, 15, 435, 713, 459, 847, 3115, 191, 19809, 43037}},
-{5496, 16, 29246, {1, 1, 7, 7, 17, 45, 91, 117, 157, 647, 121, 4091, 3611, 14169, 19883, 9069}},
-{5497, 16, 29293, {1, 1, 7, 7, 1, 47, 21, 253, 419, 157, 549, 2105, 4475, 3127, 3939, 5809}},
-{5498, 16, 29305, {1, 1, 5, 7, 15, 7, 71, 195, 87, 757, 77, 1391, 151, 12995, 26403, 17789}},
-{5499, 16, 29312, {1, 1, 1, 15, 15, 3, 79, 43, 475, 263, 1195, 2385, 5955, 7039, 15625, 19263}},
-{5500, 16, 29339, {1, 1, 5, 13, 13, 29, 5, 29, 489, 929, 2027, 2771, 6899, 14173, 13747, 1019}},
-{5501, 16, 29365, {1, 1, 7, 1, 5, 45, 37, 85, 221, 871, 627, 3445, 4853, 4243, 21651, 30201}},
-{5502, 16, 29389, {1, 3, 7, 11, 9, 49, 73, 245, 161, 321, 579, 2641, 6653, 5513, 11555, 53091}},
-{5503, 16, 29402, {1, 1, 7, 7, 25, 63, 101, 179, 497, 113, 9, 549, 5341, 6097, 13305, 52421}},
-{5504, 16, 29423, {1, 3, 3, 7, 21, 7, 89, 79, 137, 651, 189, 3025, 1403, 4559, 32611, 1857}},
-{5505, 16, 29443, {1, 3, 1, 13, 27, 55, 61, 135, 81, 195, 799, 3477, 4873, 2691, 29769, 59033}},
-{5506, 16, 29445, {1, 3, 3, 15, 29, 11, 7, 11, 151, 649, 1511, 2327, 6921, 12911, 3571, 35039}},
-{5507, 16, 29463, {1, 1, 5, 11, 25, 19, 49, 133, 455, 373, 1827, 3619, 2127, 3365, 11327, 52785}},
-{5508, 16, 29473, {1, 3, 5, 1, 9, 19, 107, 171, 205, 93, 1557, 2693, 4297, 4415, 20407, 19221}},
-{5509, 16, 29493, {1, 3, 3, 11, 15, 45, 37, 143, 61, 759, 2047, 2465, 3923, 9477, 30831, 46377}},
-{5510, 16, 29506, {1, 3, 7, 11, 17, 51, 117, 129, 77, 579, 1167, 1575, 1967, 10099, 22137, 31431}},
-{5511, 16, 29518, {1, 1, 5, 13, 31, 61, 67, 37, 49, 283, 235, 783, 7353, 5149, 12245, 18725}},
-{5512, 16, 29532, {1, 1, 5, 3, 17, 33, 35, 83, 359, 253, 1911, 913, 6481, 4635, 24223, 19693}},
-{5513, 16, 29560, {1, 1, 1, 13, 19, 15, 81, 131, 417, 969, 1911, 2829, 3097, 5333, 11175, 52269}},
-{5514, 16, 29590, {1, 3, 7, 15, 5, 39, 19, 205, 329, 83, 1473, 3259, 6409, 12297, 30557, 40917}},
-{5515, 16, 29594, {1, 3, 1, 15, 17, 33, 123, 185, 501, 299, 621, 929, 5797, 10539, 12321, 61043}},
-{5516, 16, 29637, {1, 3, 3, 1, 7, 51, 119, 19, 17, 203, 373, 2145, 2367, 9965, 28071, 50083}},
-{5517, 16, 29647, {1, 1, 1, 5, 1, 35, 43, 243, 91, 793, 1299, 2705, 7987, 1291, 10147, 17863}},
-{5518, 16, 29650, {1, 3, 5, 15, 27, 13, 99, 33, 179, 479, 897, 1113, 1639, 12321, 23987, 36219}},
-{5519, 16, 29655, {1, 1, 5, 9, 29, 41, 85, 9, 389, 583, 293, 1727, 2575, 13767, 15443, 40027}},
-{5520, 16, 29661, {1, 1, 7, 11, 29, 33, 93, 115, 51, 747, 1569, 3557, 869, 1991, 29877, 44131}},
-{5521, 16, 29680, {1, 3, 7, 7, 29, 11, 33, 137, 411, 689, 1815, 1789, 6557, 5973, 19445, 49449}},
-{5522, 16, 29721, {1, 1, 5, 1, 17, 3, 77, 55, 351, 325, 983, 3935, 819, 14127, 18893, 62553}},
-{5523, 16, 29751, {1, 3, 3, 1, 15, 33, 25, 159, 135, 385, 837, 3615, 1649, 1687, 3421, 47579}},
-{5524, 16, 29755, {1, 3, 1, 7, 17, 25, 125, 169, 469, 919, 1789, 863, 2827, 949, 21347, 10517}},
-{5525, 16, 29760, {1, 3, 1, 11, 27, 19, 45, 255, 175, 483, 1073, 3779, 611, 2809, 179, 19767}},
-{5526, 16, 29772, {1, 1, 3, 1, 21, 61, 47, 171, 179, 85, 61, 1209, 4005, 11439, 8477, 27229}},
-{5527, 16, 29778, {1, 1, 1, 1, 3, 1, 43, 159, 261, 411, 1449, 1621, 3681, 3465, 24029, 3493}},
-{5528, 16, 29799, {1, 3, 1, 11, 5, 13, 9, 23, 369, 769, 363, 3329, 409, 13151, 30269, 9621}},
-{5529, 16, 29824, {1, 1, 5, 1, 13, 39, 121, 39, 295, 981, 1151, 4039, 8179, 5007, 25527, 1249}},
-{5530, 16, 29841, {1, 3, 7, 5, 17, 21, 47, 233, 211, 349, 643, 109, 7553, 11453, 30967, 30959}},
-{5531, 16, 29842, {1, 1, 5, 3, 31, 39, 105, 137, 487, 855, 107, 1567, 2385, 2889, 25777, 33709}},
-{5532, 16, 29853, {1, 1, 1, 9, 1, 7, 9, 69, 465, 965, 355, 299, 3327, 14997, 14599, 2241}},
-{5533, 16, 29867, {1, 3, 5, 11, 5, 39, 69, 203, 367, 611, 199, 3931, 5039, 8683, 8675, 49151}},
-{5534, 16, 29949, {1, 1, 7, 13, 31, 35, 101, 213, 273, 827, 203, 2773, 4131, 1397, 15311, 62903}},
-{5535, 16, 29950, {1, 3, 7, 9, 23, 41, 33, 213, 411, 965, 563, 3035, 247, 15019, 20429, 61081}},
-{5536, 16, 29964, {1, 1, 5, 5, 5, 1, 1, 203, 27, 199, 67, 1301, 7831, 12839, 2777, 6325}},
-{5537, 16, 29967, {1, 3, 1, 11, 27, 3, 11, 173, 9, 121, 1701, 2741, 29, 16319, 15849, 11989}},
-{5538, 16, 29985, {1, 1, 5, 13, 17, 49, 125, 153, 261, 603, 1617, 3967, 6083, 7745, 19683, 49885}},
-{5539, 16, 29992, {1, 3, 3, 7, 23, 13, 39, 169, 135, 361, 579, 1443, 7615, 2389, 5669, 651}},
-{5540, 16, 30000, {1, 3, 5, 9, 31, 19, 81, 83, 483, 93, 1895, 2285, 7771, 8281, 8353, 39677}},
-{5541, 16, 30020, {1, 1, 7, 7, 23, 51, 127, 25, 101, 611, 1095, 3013, 2685, 8153, 22629, 53355}},
-{5542, 16, 30024, {1, 1, 1, 11, 11, 37, 35, 127, 317, 877, 1591, 401, 4121, 9945, 12121, 28257}},
-{5543, 16, 30030, {1, 3, 5, 11, 23, 9, 43, 135, 37, 405, 2009, 2903, 3065, 6591, 8473, 58231}},
-{5544, 16, 30066, {1, 1, 3, 11, 21, 45, 21, 205, 425, 891, 357, 2609, 495, 7541, 2161, 37853}},
-{5545, 16, 30071, {1, 3, 1, 1, 25, 9, 113, 243, 317, 491, 997, 2023, 5869, 13643, 11483, 6733}},
-{5546, 16, 30078, {1, 3, 1, 15, 13, 3, 75, 25, 409, 421, 1817, 857, 4575, 12559, 1211, 62177}},
-{5547, 16, 30082, {1, 1, 3, 7, 17, 35, 115, 195, 217, 223, 1195, 749, 5619, 7265, 7369, 46907}},
-{5548, 16, 30096, {1, 1, 1, 13, 5, 57, 117, 161, 121, 533, 987, 3959, 5047, 15213, 15811, 41841}},
-{5549, 16, 30101, {1, 3, 7, 1, 19, 55, 97, 191, 217, 75, 1881, 3351, 3737, 12179, 22875, 28767}},
-{5550, 16, 30102, {1, 3, 1, 9, 15, 41, 9, 97, 491, 31, 1191, 963, 875, 8259, 2723, 9503}},
-{5551, 16, 30122, {1, 3, 7, 9, 3, 17, 21, 71, 1, 523, 2031, 3469, 3181, 8707, 6093, 8837}},
-{5552, 16, 30141, {1, 3, 5, 3, 5, 1, 11, 91, 33, 37, 643, 85, 4325, 4293, 8351, 28311}},
-{5553, 16, 30159, {1, 3, 7, 5, 15, 45, 47, 183, 391, 113, 493, 3607, 2541, 13521, 31613, 36049}},
-{5554, 16, 30168, {1, 1, 3, 9, 15, 33, 115, 69, 289, 217, 1875, 1339, 4995, 9073, 6909, 15977}},
-{5555, 16, 30177, {1, 1, 7, 3, 9, 29, 39, 219, 119, 369, 893, 1293, 4511, 15703, 11093, 30259}},
-{5556, 16, 30183, {1, 1, 5, 13, 19, 9, 17, 75, 149, 415, 35, 97, 563, 1689, 18311, 54291}},
-{5557, 16, 30197, {1, 1, 7, 3, 17, 15, 71, 29, 25, 883, 1801, 1675, 5585, 9413, 3813, 26673}},
-{5558, 16, 30213, {1, 1, 3, 15, 5, 13, 31, 41, 311, 411, 573, 281, 8075, 7163, 11817, 29121}},
-{5559, 16, 30231, {1, 1, 7, 9, 7, 57, 15, 141, 337, 123, 269, 3737, 6455, 2539, 13655, 59809}},
-{5560, 16, 30232, {1, 3, 1, 15, 15, 23, 111, 51, 429, 483, 1567, 1317, 8057, 1609, 30181, 35687}},
-{5561, 16, 30241, {1, 3, 7, 9, 25, 43, 67, 13, 319, 587, 1827, 443, 2031, 8563, 16173, 58667}},
-{5562, 16, 30253, {1, 3, 5, 13, 11, 63, 89, 105, 377, 257, 7, 4077, 5091, 5125, 25, 39033}},
-{5563, 16, 30259, {1, 3, 3, 1, 9, 29, 7, 87, 239, 469, 1851, 1711, 5797, 7137, 11405, 20175}},
-{5564, 16, 30262, {1, 3, 3, 1, 13, 17, 101, 209, 301, 95, 1181, 3091, 4451, 1241, 17057, 335}},
-{5565, 16, 30268, {1, 1, 1, 9, 31, 7, 81, 161, 391, 677, 115, 141, 5375, 7279, 1887, 1645}},
-{5566, 16, 30297, {1, 1, 1, 11, 27, 61, 3, 195, 189, 409, 1747, 331, 2931, 9535, 1369, 47233}},
-{5567, 16, 30316, {1, 3, 5, 15, 7, 15, 105, 255, 491, 689, 97, 1131, 3459, 7147, 27541, 62307}},
-{5568, 16, 30322, {1, 3, 5, 9, 5, 23, 1, 209, 233, 717, 1919, 1835, 5073, 10403, 28979, 1945}},
-{5569, 16, 30344, {1, 1, 3, 9, 3, 35, 107, 209, 255, 447, 227, 273, 443, 9367, 24105, 34095}},
-{5570, 16, 30350, {1, 1, 3, 11, 3, 33, 5, 165, 83, 787, 1555, 31, 4351, 16301, 27453, 56739}},
-{5571, 16, 30355, {1, 1, 5, 5, 29, 9, 127, 253, 281, 487, 441, 1129, 2811, 9113, 28855, 57117}},
-{5572, 16, 30429, {1, 1, 1, 13, 13, 1, 17, 143, 121, 917, 1571, 3777, 2297, 3691, 3001, 42327}},
-{5573, 16, 30445, {1, 1, 5, 1, 25, 7, 41, 245, 241, 929, 1203, 3755, 7113, 9333, 22549, 12253}},
-{5574, 16, 30477, {1, 3, 1, 11, 1, 13, 69, 73, 285, 975, 1331, 3411, 7777, 3489, 2763, 44297}},
-{5575, 16, 30513, {1, 3, 5, 11, 3, 37, 21, 105, 153, 307, 989, 627, 3127, 6169, 10573, 22139}},
-{5576, 16, 30520, {1, 3, 5, 15, 11, 11, 39, 21, 355, 437, 547, 2283, 6443, 5561, 6367, 53899}},
-{5577, 16, 30540, {1, 1, 1, 9, 25, 51, 97, 175, 131, 207, 1367, 2561, 7455, 8289, 5877, 4383}},
-{5578, 16, 30551, {1, 3, 7, 1, 29, 17, 7, 1, 43, 831, 591, 2145, 975, 909, 23107, 43987}},
-{5579, 16, 30573, {1, 3, 5, 13, 5, 47, 65, 65, 439, 807, 271, 1615, 1873, 10905, 30537, 3337}},
-{5580, 16, 30609, {1, 1, 1, 13, 29, 1, 53, 5, 307, 347, 1059, 545, 1129, 11883, 5969, 50433}},
-{5581, 16, 30622, {1, 1, 3, 5, 31, 29, 63, 201, 255, 803, 677, 1499, 1691, 14037, 18251, 6881}},
-{5582, 16, 30635, {1, 3, 1, 5, 5, 13, 13, 121, 505, 855, 467, 2803, 3297, 4689, 18443, 60757}},
-{5583, 16, 30658, {1, 1, 5, 13, 11, 19, 11, 201, 101, 431, 693, 1267, 6909, 7759, 2265, 6125}},
-{5584, 16, 30667, {1, 1, 7, 13, 9, 3, 37, 209, 269, 27, 1041, 2587, 4667, 11077, 27009, 27967}},
-{5585, 16, 30681, {1, 1, 5, 5, 1, 5, 127, 179, 463, 949, 1525, 231, 1201, 3283, 9929, 46677}},
-{5586, 16, 30684, {1, 3, 1, 15, 9, 11, 89, 129, 331, 833, 1415, 229, 2059, 13145, 30525, 33773}},
-{5587, 16, 30703, {1, 1, 7, 15, 7, 43, 95, 177, 313, 989, 483, 825, 1885, 4535, 8213, 39835}},
-{5588, 16, 30705, {1, 1, 7, 3, 19, 27, 45, 163, 17, 523, 1565, 3753, 7433, 14117, 8499, 40177}},
-{5589, 16, 30715, {1, 3, 3, 15, 23, 45, 95, 31, 55, 469, 383, 237, 6287, 5561, 20901, 48259}},
-{5590, 16, 30742, {1, 1, 3, 1, 23, 61, 101, 185, 35, 553, 463, 1169, 2875, 12491, 14327, 47999}},
-{5591, 16, 30748, {1, 3, 3, 13, 23, 29, 77, 21, 19, 3, 769, 1943, 2081, 9135, 29767, 11367}},
-{5592, 16, 30758, {1, 1, 5, 15, 5, 11, 59, 163, 355, 993, 375, 3181, 2675, 8515, 17007, 38467}},
-{5593, 16, 30767, {1, 1, 5, 13, 19, 5, 107, 83, 123, 843, 413, 2137, 7531, 3833, 6149, 55925}},
-{5594, 16, 30770, {1, 3, 1, 13, 23, 9, 41, 145, 265, 591, 1899, 3145, 5255, 13653, 12245, 25367}},
-{5595, 16, 30772, {1, 1, 3, 15, 1, 45, 119, 79, 121, 137, 1945, 2041, 2409, 1377, 29501, 29885}},
-{5596, 16, 30807, {1, 1, 7, 11, 27, 57, 75, 183, 341, 237, 1909, 2785, 5973, 9965, 21729, 45089}},
-{5597, 16, 30814, {1, 3, 5, 7, 21, 1, 41, 189, 131, 1021, 1375, 1463, 5985, 12499, 4115, 9131}},
-{5598, 16, 30824, {1, 3, 7, 15, 21, 19, 59, 171, 339, 841, 1725, 2909, 6437, 2499, 17191, 43275}},
-{5599, 16, 30857, {1, 3, 1, 1, 15, 55, 31, 199, 351, 183, 1819, 1873, 7877, 12407, 7881, 1663}},
-{5600, 16, 30875, {1, 1, 3, 15, 1, 61, 111, 61, 115, 243, 1281, 3195, 1229, 10973, 189, 36049}},
-{5601, 16, 30931, {1, 1, 3, 15, 13, 13, 3, 49, 61, 839, 1615, 1853, 3619, 7805, 25441, 8789}},
-{5602, 16, 30933, {1, 3, 1, 9, 27, 43, 7, 193, 397, 869, 1079, 1785, 6535, 1801, 29363, 59269}},
-{5603, 16, 30949, {1, 3, 5, 5, 31, 57, 37, 53, 41, 871, 809, 1235, 1011, 12979, 8749, 52151}},
-{5604, 16, 30953, {1, 1, 7, 13, 25, 59, 69, 117, 463, 587, 513, 297, 6991, 5905, 25737, 37249}},
-{5605, 16, 30982, {1, 1, 5, 1, 27, 19, 121, 97, 349, 793, 1971, 3057, 4781, 15841, 22625, 58637}},
-{5606, 16, 31010, {1, 1, 5, 5, 25, 31, 11, 133, 411, 239, 1071, 3473, 1733, 7175, 31841, 46665}},
-{5607, 16, 31012, {1, 3, 3, 13, 19, 25, 99, 175, 271, 175, 1755, 3597, 4615, 15207, 25573, 16089}},
-{5608, 16, 31039, {1, 1, 7, 11, 17, 19, 119, 91, 505, 791, 55, 2979, 7463, 10147, 23647, 33283}},
-{5609, 16, 31041, {1, 3, 1, 1, 21, 11, 43, 173, 239, 839, 1533, 1559, 549, 15621, 22133, 46387}},
-{5610, 16, 31061, {1, 1, 3, 13, 31, 15, 73, 15, 209, 267, 701, 2899, 1163, 10093, 7727, 44211}},
-{5611, 16, 31082, {1, 3, 1, 11, 29, 21, 5, 39, 421, 375, 411, 3693, 3901, 8507, 10883, 16189}},
-{5612, 16, 31087, {1, 3, 1, 7, 13, 13, 73, 167, 149, 677, 1435, 621, 2511, 13813, 13129, 55327}},
-{5613, 16, 31096, {1, 3, 5, 15, 7, 59, 83, 221, 77, 357, 281, 2689, 5629, 5837, 1701, 30811}},
-{5614, 16, 31115, {1, 3, 3, 11, 17, 1, 43, 95, 473, 981, 1487, 1337, 905, 3307, 22357, 181}},
-{5615, 16, 31130, {1, 1, 3, 7, 1, 27, 9, 3, 489, 1, 1265, 2463, 539, 12769, 825, 6149}},
-{5616, 16, 31168, {1, 3, 3, 3, 11, 27, 81, 237, 411, 241, 1613, 931, 6397, 4325, 29651, 49003}},
-{5617, 16, 31171, {1, 3, 3, 13, 1, 19, 55, 73, 47, 203, 1661, 1245, 6847, 2457, 25427, 33069}},
-{5618, 16, 31177, {1, 3, 7, 3, 7, 47, 11, 165, 391, 457, 301, 1213, 1913, 14531, 7847, 14811}},
-{5619, 16, 31180, {1, 3, 1, 9, 1, 9, 57, 203, 15, 733, 1131, 2751, 5869, 3165, 21497, 28881}},
-{5620, 16, 31191, {1, 3, 1, 5, 9, 7, 29, 85, 71, 571, 469, 2395, 2819, 8443, 2281, 50489}},
-{5621, 16, 31207, {1, 3, 5, 11, 13, 63, 47, 47, 349, 21, 861, 2217, 2945, 6967, 6605, 16459}},
-{5622, 16, 31247, {1, 1, 7, 5, 13, 3, 41, 53, 409, 289, 1225, 2965, 5283, 1785, 14443, 51755}},
-{5623, 16, 31249, {1, 3, 7, 13, 19, 1, 29, 191, 119, 37, 697, 1909, 481, 14157, 13425, 60581}},
-{5624, 16, 31285, {1, 3, 1, 13, 1, 15, 105, 79, 505, 681, 1741, 3683, 5775, 7479, 11387, 1321}},
-{5625, 16, 31303, {1, 1, 1, 11, 9, 35, 77, 73, 351, 217, 2029, 2845, 5143, 5677, 15465, 33123}},
-{5626, 16, 31310, {1, 1, 3, 3, 19, 49, 63, 109, 335, 743, 741, 1673, 3311, 3139, 25197, 13793}},
-{5627, 16, 31337, {1, 3, 1, 3, 29, 63, 79, 1, 493, 13, 1487, 4015, 6983, 1433, 26023, 55591}},
-{5628, 16, 31352, {1, 3, 3, 11, 1, 25, 57, 207, 309, 201, 1513, 1749, 3785, 9217, 11531, 40597}},
-{5629, 16, 31357, {1, 3, 7, 13, 3, 23, 69, 253, 311, 773, 807, 1063, 745, 4843, 25221, 55885}},
-{5630, 16, 31374, {1, 1, 3, 11, 29, 47, 67, 183, 11, 259, 5, 1935, 2295, 8105, 19139, 11707}},
-{5631, 16, 31379, {1, 1, 3, 3, 23, 3, 53, 165, 255, 501, 1547, 3649, 5631, 13307, 8869, 5595}},
-{5632, 16, 31388, {1, 1, 3, 5, 7, 29, 37, 223, 289, 925, 959, 309, 1479, 3141, 18661, 52123}},
-{5633, 16, 31410, {1, 3, 1, 1, 7, 59, 101, 219, 91, 793, 1103, 1485, 7547, 12889, 19097, 15613}},
-{5634, 16, 31416, {1, 1, 5, 15, 1, 17, 79, 83, 131, 683, 1611, 1635, 5405, 9621, 29489, 4801}},
-{5635, 16, 31467, {1, 1, 5, 7, 31, 63, 59, 125, 401, 261, 1445, 33, 187, 12913, 8639, 48413}},
-{5636, 16, 31495, {1, 3, 3, 13, 27, 37, 27, 99, 379, 851, 1311, 4051, 5483, 13935, 29679, 30905}},
-{5637, 16, 31504, {1, 1, 3, 1, 7, 57, 79, 23, 97, 561, 1083, 2327, 1545, 5387, 12119, 29717}},
-{5638, 16, 31507, {1, 1, 7, 7, 9, 41, 63, 165, 315, 247, 89, 2055, 7399, 1399, 2057, 39851}},
-{5639, 16, 31509, {1, 1, 1, 15, 9, 23, 7, 15, 457, 669, 661, 3269, 915, 3475, 15845, 59769}},
-{5640, 16, 31514, {1, 3, 7, 15, 17, 53, 83, 5, 457, 103, 1297, 2413, 1095, 7711, 27935, 56357}},
-{5641, 16, 31516, {1, 1, 3, 5, 17, 3, 81, 23, 165, 341, 781, 3583, 1751, 6763, 13937, 35331}},
-{5642, 16, 31530, {1, 1, 5, 11, 31, 21, 7, 63, 369, 867, 573, 45, 2781, 4507, 21553, 51933}},
-{5643, 16, 31555, {1, 1, 5, 15, 1, 37, 85, 133, 489, 733, 1471, 2089, 979, 7723, 7339, 59595}},
-{5644, 16, 31567, {1, 1, 1, 1, 7, 3, 3, 77, 137, 1009, 481, 1343, 397, 15865, 21701, 37509}},
-{5645, 16, 31570, {1, 3, 7, 5, 17, 57, 19, 245, 249, 289, 1847, 3057, 4905, 5905, 32459, 41305}},
-{5646, 16, 31586, {1, 1, 5, 1, 23, 23, 1, 177, 115, 337, 983, 421, 3135, 6319, 27109, 59641}},
-{5647, 16, 31598, {1, 3, 1, 5, 25, 1, 63, 73, 61, 967, 1567, 2645, 7347, 11877, 28777, 38507}},
-{5648, 16, 31605, {1, 1, 3, 9, 5, 41, 39, 101, 339, 337, 1079, 3861, 5049, 5601, 14377, 34093}},
-{5649, 16, 31609, {1, 3, 7, 7, 3, 47, 95, 157, 167, 1011, 1117, 3669, 7993, 11735, 8505, 64713}},
-{5650, 16, 31612, {1, 3, 1, 9, 3, 33, 11, 33, 65, 329, 401, 2659, 2851, 3903, 29791, 41613}},
-{5651, 16, 31626, {1, 1, 1, 15, 15, 17, 9, 69, 359, 41, 1475, 1919, 5829, 2189, 21295, 33255}},
-{5652, 16, 31634, {1, 3, 1, 3, 9, 23, 73, 247, 399, 775, 419, 3033, 865, 12595, 16345, 15079}},
-{5653, 16, 31655, {1, 3, 1, 5, 1, 17, 33, 23, 419, 585, 673, 929, 6955, 10247, 12647, 29107}},
-{5654, 16, 31681, {1, 3, 3, 13, 9, 33, 11, 13, 127, 529, 1219, 2401, 6459, 14745, 5123, 53023}},
-{5655, 16, 31705, {1, 3, 5, 11, 23, 11, 5, 19, 281, 121, 1671, 2171, 4545, 10691, 24875, 28849}},
-{5656, 16, 31706, {1, 3, 1, 3, 13, 25, 85, 131, 127, 977, 1599, 3319, 3107, 3185, 4879, 3455}},
-{5657, 16, 31718, {1, 1, 5, 1, 3, 13, 77, 15, 133, 185, 1319, 727, 2181, 12175, 28017, 28023}},
-{5658, 16, 31735, {1, 3, 7, 5, 29, 51, 113, 203, 331, 847, 1, 3445, 3669, 7711, 13647, 58651}},
-{5659, 16, 31741, {1, 3, 1, 3, 31, 27, 35, 199, 491, 839, 1275, 3385, 4743, 821, 26259, 11345}},
-{5660, 16, 31744, {1, 1, 7, 9, 21, 47, 9, 67, 119, 985, 127, 1987, 5451, 6403, 26183, 8349}},
-{5661, 16, 31762, {1, 3, 5, 1, 19, 3, 91, 217, 301, 595, 1789, 735, 4993, 229, 18033, 59625}},
-{5662, 16, 31774, {1, 3, 3, 3, 11, 25, 103, 211, 117, 9, 773, 1521, 2265, 8277, 23179, 22433}},
-{5663, 16, 31864, {1, 1, 7, 9, 3, 27, 63, 255, 175, 699, 293, 2409, 3155, 285, 8663, 53503}},
-{5664, 16, 31874, {1, 1, 5, 7, 27, 23, 63, 213, 323, 697, 1541, 3497, 2985, 12389, 11155, 26217}},
-{5665, 16, 31900, {1, 3, 1, 3, 31, 7, 47, 207, 185, 873, 1063, 1055, 205, 12469, 23505, 56245}},
-{5666, 16, 31910, {1, 3, 7, 13, 31, 17, 47, 95, 91, 483, 1997, 3273, 445, 2601, 15219, 10997}},
-{5667, 16, 31928, {1, 3, 3, 5, 29, 45, 29, 83, 457, 823, 1395, 1411, 1879, 9409, 11609, 32001}},
-{5668, 16, 31965, {1, 3, 5, 11, 21, 11, 43, 73, 159, 137, 29, 1957, 815, 5077, 16127, 42199}},
-{5669, 16, 31976, {1, 3, 5, 13, 9, 59, 47, 215, 293, 807, 309, 1951, 2285, 9287, 1019, 49501}},
-{5670, 16, 32016, {1, 1, 7, 13, 31, 7, 95, 189, 233, 363, 1039, 1675, 1715, 9049, 8537, 31051}},
-{5671, 16, 32032, {1, 3, 7, 9, 23, 35, 125, 251, 107, 401, 1113, 3585, 6331, 2363, 27889, 28877}},
-{5672, 16, 32037, {1, 1, 7, 13, 9, 1, 13, 69, 257, 369, 547, 1595, 1823, 9553, 25653, 31181}},
-{5673, 16, 32062, {1, 1, 7, 11, 9, 43, 3, 93, 69, 1019, 1935, 3297, 47, 7101, 1037, 63473}},
-{5674, 16, 32069, {1, 1, 7, 5, 21, 9, 97, 105, 405, 893, 1673, 3783, 2965, 7329, 4549, 25433}},
-{5675, 16, 32115, {1, 1, 5, 13, 5, 17, 31, 123, 415, 173, 1333, 2245, 1557, 16011, 28321, 4039}},
-{5676, 16, 32128, {1, 1, 5, 9, 15, 3, 27, 79, 511, 39, 945, 49, 3231, 9199, 21327, 11183}},
-{5677, 16, 32171, {1, 3, 3, 9, 3, 15, 115, 141, 387, 341, 953, 399, 6109, 12037, 21079, 26745}},
-{5678, 16, 32173, {1, 3, 3, 1, 5, 5, 31, 195, 477, 755, 687, 3811, 805, 679, 20687, 46299}},
-{5679, 16, 32182, {1, 1, 7, 15, 1, 31, 67, 159, 205, 141, 1667, 3077, 451, 13161, 16211, 6887}},
-{5680, 16, 32191, {1, 3, 3, 1, 7, 43, 87, 5, 49, 205, 231, 3957, 2947, 13199, 15743, 4681}},
-{5681, 16, 32193, {1, 3, 3, 15, 25, 37, 95, 11, 439, 553, 59, 1241, 7407, 13467, 22403, 44441}},
-{5682, 16, 32194, {1, 1, 1, 3, 21, 3, 127, 239, 491, 139, 1411, 3417, 4247, 6247, 13809, 31609}},
-{5683, 16, 32229, {1, 1, 5, 1, 9, 13, 5, 155, 109, 593, 119, 4091, 1911, 8301, 4239, 50081}},
-{5684, 16, 32230, {1, 3, 5, 13, 27, 3, 99, 225, 253, 169, 801, 3741, 1905, 12073, 31831, 17997}},
-{5685, 16, 32248, {1, 3, 7, 15, 9, 23, 93, 171, 453, 983, 1657, 1133, 6381, 5229, 32303, 17439}},
-{5686, 16, 32263, {1, 1, 7, 11, 7, 5, 125, 141, 63, 763, 1293, 1007, 4579, 1479, 11977, 59261}},
-{5687, 16, 32264, {1, 3, 1, 7, 1, 15, 49, 41, 367, 639, 1933, 401, 2335, 2441, 13653, 55555}},
-{5688, 16, 32269, {1, 3, 1, 7, 15, 23, 5, 213, 45, 721, 543, 2133, 4525, 9719, 28053, 54075}},
-{5689, 16, 32298, {1, 3, 7, 3, 11, 7, 23, 35, 169, 829, 1957, 2423, 3583, 4951, 28957, 29753}},
-{5690, 16, 32335, {1, 1, 3, 3, 1, 5, 19, 235, 175, 969, 229, 2335, 7215, 10195, 7487, 64191}},
-{5691, 16, 32340, {1, 1, 7, 3, 27, 1, 73, 49, 445, 863, 69, 3555, 993, 9553, 31941, 29901}},
-{5692, 16, 32356, {1, 3, 5, 11, 9, 25, 59, 177, 23, 997, 1041, 1135, 3879, 767, 2263, 51267}},
-{5693, 16, 32374, {1, 1, 7, 3, 1, 63, 49, 51, 237, 569, 1293, 1143, 3125, 16315, 17009, 24821}},
-{5694, 16, 32390, {1, 3, 3, 15, 11, 17, 121, 25, 349, 833, 557, 1975, 5405, 15189, 31243, 53541}},
-{5695, 16, 32401, {1, 3, 7, 9, 11, 15, 39, 15, 75, 87, 55, 2069, 3291, 507, 16925, 57751}},
-{5696, 16, 32414, {1, 1, 3, 15, 1, 21, 61, 139, 357, 931, 647, 947, 2291, 15557, 6739, 5881}},
-{5697, 16, 32417, {1, 3, 1, 9, 1, 47, 73, 59, 115, 497, 733, 1777, 905, 16181, 4351, 7345}},
-{5698, 16, 32442, {1, 3, 3, 7, 5, 21, 67, 113, 71, 743, 757, 1851, 7899, 10315, 15437, 61803}},
-{5699, 16, 32450, {1, 3, 7, 1, 9, 23, 77, 131, 395, 767, 1229, 2629, 5731, 11907, 32217, 18473}},
-{5700, 16, 32461, {1, 3, 5, 15, 1, 23, 123, 207, 291, 565, 1211, 501, 2111, 11381, 5171, 54841}},
-{5701, 16, 32473, {1, 1, 1, 15, 21, 13, 3, 175, 405, 109, 1353, 2495, 7619, 14971, 28179, 34737}},
-{5702, 16, 32479, {1, 3, 5, 3, 17, 25, 53, 71, 229, 729, 1953, 3119, 7747, 1551, 23417, 35563}},
-{5703, 16, 32530, {1, 1, 7, 7, 11, 31, 81, 43, 149, 537, 1253, 2759, 431, 4813, 8375, 46329}},
-{5704, 16, 32536, {1, 1, 1, 5, 11, 27, 61, 199, 239, 889, 723, 2353, 5663, 7385, 28165, 14675}},
-{5705, 16, 32548, {1, 3, 1, 7, 3, 3, 83, 247, 247, 57, 579, 1163, 2615, 4051, 2809, 46413}},
-{5706, 16, 32577, {1, 1, 3, 11, 13, 47, 11, 235, 475, 35, 843, 2329, 3519, 8899, 14533, 24889}},
-{5707, 16, 32628, {1, 3, 1, 1, 7, 31, 15, 101, 327, 499, 471, 1001, 339, 11863, 24787, 47191}},
-{5708, 16, 32642, {1, 1, 7, 1, 3, 55, 93, 43, 11, 65, 289, 1249, 5325, 13867, 29841, 34333}},
-{5709, 16, 32665, {1, 3, 3, 1, 25, 61, 87, 113, 115, 265, 1007, 1129, 7633, 6109, 5733, 22649}},
-{5710, 16, 32666, {1, 3, 1, 11, 31, 59, 127, 83, 33, 419, 1037, 3777, 6383, 2711, 2113, 17233}},
-{5711, 16, 32668, {1, 1, 5, 13, 11, 17, 73, 41, 257, 223, 359, 3821, 4617, 1943, 11331, 40153}},
-{5712, 16, 32696, {1, 1, 1, 1, 9, 25, 43, 179, 17, 1021, 1323, 761, 5861, 11547, 26017, 5165}},
-{5713, 16, 32722, {1, 3, 5, 3, 29, 21, 53, 111, 213, 717, 1101, 3215, 3021, 16343, 23387, 33439}},
-{5714, 16, 32757, {1, 3, 5, 13, 29, 11, 21, 89, 107, 111, 1121, 2785, 3493, 9873, 13, 40863}},
-{5715, 16, 32758, {1, 1, 5, 13, 15, 15, 111, 219, 59, 43, 333, 3581, 1311, 2799, 23987, 21637}},
-{5716, 17, 4, {1, 3, 1, 11, 21, 57, 115, 247, 499, 525, 1629, 3679, 2109, 6607, 27435, 1745, 71201}},
-{5717, 17, 7, {1, 3, 3, 3, 31, 17, 113, 165, 189, 361, 103, 1775, 3001, 3865, 30591, 2873, 17129}},
-{5718, 17, 16, {1, 1, 5, 5, 15, 47, 47, 85, 247, 471, 713, 3571, 2407, 9811, 8187, 32133, 8541}},
-{5719, 17, 22, {1, 3, 3, 1, 15, 1, 59, 151, 469, 351, 671, 2925, 7207, 5061, 28691, 4363, 50767}},
-{5720, 17, 25, {1, 1, 5, 7, 11, 35, 67, 45, 193, 3, 627, 3333, 6497, 12307, 28807, 13997, 108645}},
-{5721, 17, 31, {1, 3, 1, 1, 17, 63, 125, 185, 485, 759, 717, 1993, 6707, 3993, 2181, 8173, 18057}},
-{5722, 17, 32, {1, 1, 3, 13, 7, 15, 113, 207, 103, 191, 1895, 2595, 3873, 12021, 19259, 12553, 119119}},
-{5723, 17, 42, {1, 3, 7, 1, 17, 11, 101, 209, 315, 9, 901, 2303, 7623, 7459, 26391, 45143, 5753}},
-{5724, 17, 52, {1, 1, 5, 15, 1, 5, 71, 155, 167, 89, 145, 3483, 2385, 15205, 9193, 20637, 58473}},
-{5725, 17, 61, {1, 1, 5, 7, 25, 55, 57, 51, 333, 299, 1721, 1667, 6513, 10191, 29405, 21923, 76593}},
-{5726, 17, 70, {1, 1, 5, 1, 7, 37, 107, 91, 241, 137, 627, 2749, 5573, 11243, 26197, 4545, 105599}},
-{5727, 17, 76, {1, 3, 1, 5, 25, 37, 73, 61, 57, 249, 1953, 1385, 6479, 3701, 10693, 617, 62535}},
-{5728, 17, 81, {1, 1, 1, 15, 5, 63, 41, 151, 395, 681, 227, 3027, 8123, 15091, 15475, 35671, 21129}},
-{5729, 17, 87, {1, 3, 5, 11, 29, 21, 15, 233, 103, 463, 1829, 2257, 1717, 2249, 9599, 5097, 55705}},
-{5730, 17, 93, {1, 3, 5, 1, 29, 3, 35, 151, 193, 105, 1107, 827, 7169, 1843, 15225, 29025, 43165}},
-{5731, 17, 98, {1, 1, 7, 15, 17, 51, 93, 199, 205, 41, 113, 1081, 1571, 11471, 11057, 16149, 66905}},
-{5732, 17, 122, {1, 1, 3, 11, 5, 25, 107, 195, 51, 675, 1683, 3739, 1653, 611, 23249, 53157, 127785}},
-{5733, 17, 133, {1, 1, 7, 5, 7, 3, 25, 145, 453, 735, 441, 77, 8171, 9281, 22749, 36973, 106237}},
-{5734, 17, 134, {1, 1, 3, 13, 13, 5, 95, 33, 223, 369, 453, 2031, 3531, 6931, 8977, 54109, 115487}},
-{5735, 17, 140, {1, 1, 7, 7, 1, 61, 33, 183, 245, 623, 529, 1831, 1867, 2845, 8311, 10143, 67897}},
-{5736, 17, 146, {1, 3, 7, 11, 27, 23, 93, 9, 61, 451, 67, 1695, 4227, 2415, 19249, 44765, 24611}},
-{5737, 17, 158, {1, 3, 3, 11, 29, 57, 65, 117, 349, 149, 363, 1095, 4989, 3071, 17519, 18079, 7277}},
-{5738, 17, 171, {1, 3, 5, 9, 1, 7, 59, 87, 307, 111, 1291, 789, 7361, 6477, 11229, 36785, 33303}},
-{5739, 17, 176, {1, 3, 5, 1, 19, 47, 53, 81, 127, 849, 1479, 1459, 1889, 15087, 22115, 20587, 121005}},
-{5740, 17, 179, {1, 1, 7, 15, 31, 31, 71, 55, 253, 927, 277, 2087, 1313, 3721, 22729, 34709, 9821}},
-{5741, 17, 182, {1, 3, 5, 13, 13, 63, 73, 41, 165, 315, 1907, 2005, 691, 725, 22685, 8673, 76011}},
-{5742, 17, 191, {1, 1, 5, 9, 23, 61, 47, 167, 279, 683, 683, 1261, 4037, 15251, 9421, 45359, 38001}},
-{5743, 17, 193, {1, 1, 7, 3, 17, 33, 69, 139, 235, 709, 1475, 2483, 7559, 8581, 23965, 31153, 5097}},
-{5744, 17, 224, {1, 1, 7, 15, 23, 61, 43, 5, 433, 531, 761, 2749, 2881, 5225, 13491, 16479, 50203}},
-{5745, 17, 227, {1, 1, 3, 9, 29, 7, 9, 23, 339, 315, 1723, 779, 2983, 6571, 16025, 63055, 111103}},
-{5746, 17, 229, {1, 1, 7, 13, 23, 55, 71, 121, 297, 193, 41, 3165, 4419, 5853, 28127, 56151, 16597}},
-{5747, 17, 236, {1, 1, 5, 7, 7, 23, 93, 11, 261, 297, 1769, 1239, 2579, 531, 4423, 7891, 21729}},
-{5748, 17, 248, {1, 3, 5, 1, 13, 35, 83, 85, 125, 887, 161, 3311, 7261, 9557, 28975, 28643, 21479}},
-{5749, 17, 262, {1, 3, 5, 3, 27, 5, 47, 175, 287, 867, 141, 3079, 7583, 4997, 18271, 24097, 96319}},
-{5750, 17, 273, {1, 3, 5, 1, 21, 51, 47, 67, 211, 281, 1861, 1169, 6403, 4229, 3995, 9921, 41515}},
-{5751, 17, 276, {1, 3, 3, 11, 23, 23, 81, 55, 441, 211, 169, 3197, 7213, 7205, 15, 11771, 129091}},
-{5752, 17, 280, {1, 3, 7, 3, 23, 39, 23, 163, 253, 1005, 1775, 3393, 7659, 8065, 30021, 61065, 35171}},
-{5753, 17, 283, {1, 3, 1, 1, 29, 29, 39, 143, 191, 711, 1077, 13, 4137, 15425, 11139, 1269, 71915}},
-{5754, 17, 290, {1, 3, 3, 5, 11, 41, 101, 127, 301, 335, 45, 2065, 5835, 7801, 2639, 5735, 63445}},
-{5755, 17, 309, {1, 3, 5, 9, 3, 39, 51, 53, 489, 663, 951, 3931, 3075, 753, 22179, 20573, 10775}},
-{5756, 17, 316, {1, 3, 3, 15, 13, 31, 1, 237, 79, 587, 395, 591, 607, 13105, 21301, 26829, 112181}},
-{5757, 17, 319, {1, 1, 7, 7, 5, 55, 31, 117, 247, 229, 247, 307, 3821, 6483, 31317, 22975, 40535}},
-{5758, 17, 321, {1, 3, 7, 15, 15, 59, 101, 17, 437, 373, 1727, 471, 2783, 7825, 24555, 58765, 5097}},
-{5759, 17, 328, {1, 1, 3, 9, 31, 27, 71, 147, 71, 871, 793, 2363, 3213, 13383, 29801, 53187, 70021}},
-{5760, 17, 346, {1, 3, 1, 1, 19, 47, 121, 61, 303, 565, 1371, 3703, 2201, 6835, 26041, 56039, 80227}},
-{5761, 17, 355, {1, 1, 5, 5, 3, 45, 91, 61, 257, 947, 1449, 4031, 4925, 8627, 11909, 9529, 3429}},
-{5762, 17, 367, {1, 1, 1, 7, 9, 63, 69, 233, 141, 361, 1443, 2157, 2877, 643, 2779, 8109, 126911}},
-{5763, 17, 369, {1, 1, 5, 1, 5, 3, 67, 157, 21, 1, 361, 35, 1475, 12877, 22169, 6653, 85005}},
-{5764, 17, 372, {1, 1, 7, 9, 25, 1, 7, 175, 47, 963, 405, 3955, 3905, 8429, 8483, 62037, 11323}},
-{5765, 17, 382, {1, 1, 5, 11, 29, 23, 77, 211, 319, 745, 1935, 2429, 1687, 2173, 1571, 19457, 117777}},
-{5766, 17, 388, {1, 1, 7, 5, 15, 57, 121, 189, 303, 79, 527, 1801, 71, 9857, 14197, 59007, 75341}},
-{5767, 17, 392, {1, 3, 3, 5, 25, 3, 19, 141, 155, 157, 287, 769, 5789, 8443, 31823, 1019, 79111}},
-{5768, 17, 395, {1, 1, 5, 11, 27, 27, 117, 141, 355, 1023, 869, 995, 6311, 6573, 11721, 1565, 35517}},
-{5769, 17, 397, {1, 1, 1, 9, 1, 33, 107, 51, 41, 889, 1191, 1055, 503, 14779, 6641, 58117, 74157}},
-{5770, 17, 403, {1, 1, 7, 5, 13, 39, 39, 33, 293, 75, 963, 3379, 1847, 12371, 9005, 38107, 69753}},
-{5771, 17, 409, {1, 1, 5, 5, 7, 37, 19, 241, 427, 635, 1711, 3835, 773, 10525, 17207, 1675, 127255}},
-{5772, 17, 410, {1, 1, 3, 7, 17, 19, 11, 113, 191, 947, 1133, 3173, 213, 10125, 1373, 56797, 111011}},
-{5773, 17, 425, {1, 3, 1, 1, 29, 45, 65, 237, 223, 695, 697, 3197, 6887, 8079, 22099, 12079, 54847}},
-{5774, 17, 443, {1, 3, 3, 7, 5, 47, 19, 215, 341, 863, 1879, 571, 7113, 2465, 23407, 52555, 44375}},
-{5775, 17, 472, {1, 3, 5, 11, 25, 31, 109, 73, 429, 553, 1905, 1753, 6733, 4433, 13785, 32041, 27115}},
-{5776, 17, 475, {1, 1, 1, 3, 27, 5, 97, 47, 343, 977, 1241, 721, 3355, 3559, 28349, 56389, 63103}},
-{5777, 17, 481, {1, 3, 3, 9, 21, 53, 57, 211, 73, 155, 1855, 715, 3179, 5963, 10061, 35141, 63131}},
-{5778, 17, 488, {1, 3, 1, 15, 21, 25, 51, 73, 31, 25, 1385, 637, 6585, 49, 2105, 6829, 9353}},
-{5779, 17, 493, {1, 1, 7, 5, 11, 55, 31, 69, 145, 637, 1131, 2175, 3547, 13031, 2131, 12361, 74737}},
-{5780, 17, 501, {1, 3, 3, 5, 31, 7, 119, 119, 309, 925, 895, 3813, 1131, 4765, 17865, 48707, 113577}},
-{5781, 17, 515, {1, 3, 3, 9, 13, 33, 127, 177, 323, 727, 1881, 775, 7329, 11881, 28309, 987, 116093}},
-{5782, 17, 522, {1, 1, 3, 5, 31, 55, 39, 41, 511, 157, 1655, 2991, 3633, 8521, 27049, 18771, 54015}},
-{5783, 17, 524, {1, 3, 5, 13, 11, 45, 113, 185, 375, 661, 1331, 4013, 5521, 1037, 23365, 30239, 76957}},
-{5784, 17, 527, {1, 3, 3, 7, 19, 7, 23, 17, 435, 913, 1985, 353, 6049, 7549, 3371, 60867, 41099}},
-{5785, 17, 535, {1, 3, 3, 15, 17, 9, 53, 127, 149, 849, 1181, 2237, 1345, 539, 19715, 26277, 125445}},
-{5786, 17, 542, {1, 1, 1, 3, 1, 9, 67, 79, 79, 795, 1793, 3167, 5917, 5323, 22043, 22007, 3917}},
-{5787, 17, 545, {1, 3, 5, 9, 15, 19, 59, 37, 141, 145, 413, 1095, 7709, 669, 27061, 40171, 101499}},
-{5788, 17, 555, {1, 3, 1, 1, 9, 49, 109, 7, 119, 861, 875, 1049, 4125, 6113, 15699, 6105, 48799}},
-{5789, 17, 558, {1, 1, 3, 9, 11, 29, 43, 175, 371, 357, 1181, 3933, 43, 4559, 10333, 23603, 83095}},
-{5790, 17, 560, {1, 3, 3, 9, 9, 7, 57, 61, 409, 143, 591, 761, 4107, 8117, 1051, 4471, 91771}},
-{5791, 17, 563, {1, 1, 3, 11, 3, 53, 119, 21, 213, 219, 51, 3491, 7143, 937, 24693, 3211, 99463}},
-{5792, 17, 570, {1, 1, 3, 3, 1, 47, 53, 153, 211, 523, 1637, 3351, 3753, 12489, 31825, 27613, 96431}},
-{5793, 17, 578, {1, 1, 5, 15, 23, 57, 81, 231, 147, 9, 1043, 3157, 1463, 4835, 22435, 57407, 59615}},
-{5794, 17, 583, {1, 3, 3, 13, 15, 63, 111, 5, 449, 957, 1175, 2887, 7741, 8975, 28775, 4067, 69283}},
-{5795, 17, 590, {1, 3, 1, 1, 5, 61, 109, 211, 349, 179, 951, 153, 3147, 7555, 27037, 59829, 16077}},
-{5796, 17, 597, {1, 3, 3, 7, 15, 33, 53, 61, 309, 991, 227, 3437, 3983, 14559, 13065, 46387, 49105}},
-{5797, 17, 604, {1, 3, 5, 3, 25, 23, 97, 139, 315, 601, 1179, 1083, 6799, 1813, 15511, 60433, 65641}},
-{5798, 17, 608, {1, 1, 7, 1, 11, 43, 87, 87, 173, 161, 91, 3011, 1869, 2313, 13691, 3509, 39433}},
-{5799, 17, 614, {1, 3, 5, 7, 15, 5, 39, 251, 269, 819, 815, 2283, 5635, 6953, 27017, 65143, 45281}},
-{5800, 17, 635, {1, 3, 7, 9, 1, 37, 9, 57, 467, 37, 1743, 4031, 3751, 8105, 23789, 46847, 21911}},
-{5801, 17, 637, {1, 1, 7, 1, 23, 47, 63, 99, 59, 951, 1837, 2829, 161, 857, 4045, 9945, 53487}},
-{5802, 17, 653, {1, 3, 7, 7, 11, 47, 43, 99, 279, 945, 1189, 2091, 4597, 183, 15527, 7151, 112403}},
-{5803, 17, 654, {1, 3, 3, 15, 9, 53, 63, 135, 119, 95, 131, 2461, 157, 10631, 20847, 51699, 58865}},
-{5804, 17, 659, {1, 1, 3, 1, 25, 3, 115, 29, 303, 361, 1529, 3993, 5899, 11501, 4463, 47121, 75333}},
-{5805, 17, 666, {1, 3, 1, 15, 9, 39, 31, 199, 305, 279, 15, 611, 561, 6593, 3189, 1863, 61875}},
-{5806, 17, 671, {1, 3, 5, 15, 5, 49, 87, 17, 87, 5, 1179, 1351, 7647, 7529, 15901, 30351, 31959}},
-{5807, 17, 689, {1, 3, 3, 9, 31, 57, 127, 239, 349, 773, 547, 2649, 1309, 8071, 10741, 57645, 14423}},
-{5808, 17, 690, {1, 1, 5, 9, 5, 15, 59, 185, 315, 411, 1425, 3905, 853, 12393, 21, 15195, 114291}},
-{5809, 17, 695, {1, 3, 1, 5, 29, 47, 19, 203, 319, 673, 1169, 2413, 5295, 6251, 19883, 2725, 28937}},
-{5810, 17, 713, {1, 3, 1, 5, 21, 55, 19, 185, 103, 827, 117, 341, 3315, 5625, 345, 63845, 49081}},
-{5811, 17, 722, {1, 1, 7, 9, 27, 51, 105, 15, 243, 735, 1221, 1641, 293, 14423, 5363, 60873, 66223}},
-{5812, 17, 733, {1, 1, 5, 1, 19, 5, 109, 131, 131, 67, 231, 2907, 4389, 5079, 20503, 59045, 33625}},
-{5813, 17, 758, {1, 3, 1, 5, 5, 15, 79, 67, 287, 225, 519, 1543, 2389, 671, 7767, 62625, 61639}},
-{5814, 17, 770, {1, 1, 1, 9, 25, 35, 83, 15, 291, 207, 1757, 3691, 5669, 11255, 27939, 57813, 46251}},
-{5815, 17, 782, {1, 3, 1, 1, 29, 3, 83, 109, 323, 179, 1855, 3205, 7665, 16201, 13863, 16347, 98977}},
-{5816, 17, 784, {1, 3, 1, 13, 17, 1, 101, 183, 153, 985, 125, 999, 855, 15897, 19491, 8953, 23277}},
-{5817, 17, 793, {1, 1, 7, 11, 9, 33, 45, 229, 411, 155, 537, 3037, 1785, 11719, 8589, 16617, 47339}},
-{5818, 17, 803, {1, 1, 5, 5, 9, 11, 7, 163, 305, 621, 1647, 2609, 7901, 14421, 23447, 1205, 52681}},
-{5819, 17, 805, {1, 3, 3, 1, 7, 29, 39, 227, 419, 561, 129, 3299, 3123, 4243, 18689, 12335, 71783}},
-{5820, 17, 812, {1, 3, 1, 9, 11, 61, 65, 207, 123, 763, 485, 1943, 3617, 415, 22397, 58597, 128017}},
-{5821, 17, 838, {1, 1, 5, 13, 25, 43, 115, 73, 269, 137, 1765, 705, 1705, 16137, 22751, 60021, 4333}},
-{5822, 17, 849, {1, 1, 5, 13, 3, 57, 9, 141, 75, 695, 597, 3435, 1085, 4905, 19625, 16061, 12111}},
-{5823, 17, 875, {1, 1, 5, 9, 29, 13, 119, 251, 353, 421, 1955, 3503, 2605, 2587, 12503, 46419, 128815}},
-{5824, 17, 877, {1, 3, 5, 7, 7, 29, 67, 25, 37, 327, 1607, 1899, 1691, 5801, 17441, 9755, 24993}},
-{5825, 17, 880, {1, 1, 3, 11, 17, 29, 121, 201, 371, 597, 213, 2361, 6615, 169, 24801, 56175, 129241}},
-{5826, 17, 892, {1, 3, 5, 1, 31, 63, 85, 77, 151, 599, 103, 677, 4431, 12897, 6373, 40349, 100819}},
-{5827, 17, 895, {1, 3, 5, 9, 25, 9, 119, 219, 379, 939, 1907, 945, 5819, 7433, 32519, 56493, 50441}},
-{5828, 17, 899, {1, 1, 3, 9, 13, 1, 63, 189, 135, 839, 1821, 2247, 2547, 965, 6847, 63335, 32921}},
-{5829, 17, 919, {1, 3, 5, 13, 21, 25, 111, 37, 319, 469, 1999, 1637, 8167, 2641, 24615, 63713, 115923}},
-{5830, 17, 920, {1, 3, 5, 9, 9, 27, 1, 63, 275, 223, 1675, 3833, 7377, 9755, 6279, 37161, 108805}},
-{5831, 17, 932, {1, 3, 3, 13, 29, 23, 21, 73, 401, 863, 701, 2527, 4557, 5549, 22493, 6651, 39167}},
-{5832, 17, 935, {1, 1, 3, 15, 25, 21, 97, 25, 83, 925, 2029, 3789, 3241, 7617, 13699, 31123, 124619}},
-{5833, 17, 936, {1, 3, 7, 5, 23, 7, 95, 227, 123, 215, 359, 2099, 4505, 8477, 32665, 18211, 99679}},
-{5834, 17, 941, {1, 3, 1, 9, 11, 57, 75, 17, 105, 175, 831, 1033, 5425, 8419, 16163, 23901, 33889}},
-{5835, 17, 950, {1, 1, 7, 1, 17, 49, 71, 23, 129, 413, 333, 2547, 4627, 14961, 16745, 53649, 73059}},
-{5836, 17, 961, {1, 3, 5, 3, 13, 33, 121, 147, 443, 187, 1949, 319, 8141, 14359, 11203, 53569, 70415}},
-{5837, 17, 962, {1, 3, 1, 11, 15, 1, 23, 29, 509, 985, 1217, 3755, 385, 3697, 24631, 37619, 62435}},
-{5838, 17, 971, {1, 3, 3, 3, 17, 11, 107, 37, 227, 913, 259, 2799, 3249, 2347, 9703, 52741, 101187}},
-{5839, 17, 982, {1, 1, 5, 13, 25, 25, 47, 77, 405, 415, 1947, 1675, 5079, 1333, 10059, 32033, 88975}},
-{5840, 17, 986, {1, 3, 5, 9, 27, 7, 19, 241, 445, 205, 333, 285, 7997, 6339, 29643, 10229, 29965}},
-{5841, 17, 1012, {1, 3, 5, 11, 17, 9, 91, 223, 173, 1013, 779, 3967, 781, 5471, 4309, 24795, 99203}},
-{5842, 17, 1021, {1, 1, 1, 3, 19, 53, 7, 159, 351, 515, 223, 3375, 1, 4985, 16729, 43333, 85917}},
-{5843, 17, 1024, {1, 3, 3, 1, 19, 35, 95, 69, 19, 157, 1177, 579, 7109, 3499, 3219, 26641, 49491}},
-{5844, 17, 1029, {1, 3, 3, 5, 25, 21, 125, 5, 39, 857, 615, 2925, 2005, 5503, 25523, 36711, 30939}},
-{5845, 17, 1030, {1, 3, 1, 5, 11, 33, 29, 5, 425, 125, 939, 1641, 321, 1023, 12551, 4587, 116617}},
-{5846, 17, 1051, {1, 3, 3, 13, 9, 59, 93, 137, 103, 517, 1555, 13, 7965, 13629, 14339, 37425, 65891}},
-{5847, 17, 1054, {1, 3, 7, 1, 31, 31, 87, 237, 365, 951, 267, 2019, 5085, 6133, 29371, 50319, 94313}},
-{5848, 17, 1064, {1, 3, 5, 7, 17, 19, 23, 225, 501, 189, 1291, 603, 6873, 8633, 11425, 30565, 26355}},
-{5849, 17, 1067, {1, 3, 7, 11, 23, 17, 91, 111, 415, 225, 1287, 2081, 4683, 12069, 3627, 32281, 17995}},
-{5850, 17, 1082, {1, 1, 5, 15, 25, 59, 75, 203, 179, 405, 1711, 3147, 7483, 5583, 3729, 11765, 61019}},
-{5851, 17, 1096, {1, 3, 3, 9, 3, 43, 65, 7, 269, 33, 829, 1789, 967, 13119, 26329, 16937, 18533}},
-{5852, 17, 1116, {1, 1, 3, 15, 11, 39, 73, 11, 31, 143, 1913, 1227, 1363, 11831, 28687, 50489, 106373}},
-{5853, 17, 1119, {1, 1, 3, 3, 25, 19, 15, 11, 349, 1011, 421, 3193, 3665, 6149, 20729, 6997, 51437}},
-{5854, 17, 1129, {1, 3, 5, 9, 13, 63, 73, 55, 417, 223, 1753, 2913, 4809, 3947, 10769, 5751, 93867}},
-{5855, 17, 1130, {1, 3, 7, 13, 31, 39, 39, 133, 483, 839, 1137, 3303, 7285, 4309, 24079, 60529, 103337}},
-{5856, 17, 1132, {1, 1, 3, 7, 1, 55, 3, 253, 435, 589, 1949, 1461, 513, 381, 29455, 4263, 16831}},
-{5857, 17, 1137, {1, 1, 1, 15, 25, 19, 77, 101, 299, 187, 1021, 1533, 8021, 4165, 2277, 18927, 110439}},
-{5858, 17, 1147, {1, 1, 1, 11, 9, 35, 71, 159, 409, 527, 15, 4073, 5749, 8563, 2503, 53015, 111581}},
-{5859, 17, 1150, {1, 1, 7, 5, 21, 47, 113, 23, 477, 559, 543, 409, 4701, 11479, 30761, 8373, 87777}},
-{5860, 17, 1154, {1, 3, 5, 13, 9, 27, 25, 137, 81, 37, 799, 857, 3539, 4471, 15753, 59015, 48589}},
-{5861, 17, 1165, {1, 1, 3, 7, 11, 57, 103, 83, 209, 71, 193, 3251, 4839, 13959, 32009, 6471, 23631}},
-{5862, 17, 1166, {1, 1, 7, 11, 25, 33, 85, 31, 371, 253, 1667, 1627, 6159, 10039, 15177, 52121, 39475}},
-{5863, 17, 1174, {1, 1, 5, 9, 13, 55, 37, 13, 95, 113, 1895, 1525, 1907, 6361, 5863, 27767, 108143}},
-{5864, 17, 1177, {1, 1, 3, 13, 21, 5, 53, 39, 485, 171, 1355, 2117, 3127, 6467, 31697, 45343, 111477}},
-{5865, 17, 1184, {1, 1, 7, 15, 13, 57, 11, 231, 329, 703, 1823, 2983, 215, 2835, 19719, 56637, 126169}},
-{5866, 17, 1194, {1, 3, 5, 15, 13, 51, 13, 173, 301, 867, 127, 2391, 2795, 4945, 13293, 49947, 10765}},
-{5867, 17, 1204, {1, 3, 3, 9, 23, 5, 29, 165, 467, 599, 1181, 3213, 4069, 5473, 8937, 51495, 42611}},
-{5868, 17, 1208, {1, 1, 7, 15, 5, 5, 31, 125, 397, 519, 1465, 115, 7877, 7025, 14213, 50343, 85827}},
-{5869, 17, 1213, {1, 3, 7, 3, 25, 59, 95, 103, 101, 347, 95, 3, 1251, 15109, 12615, 7511, 56789}},
-{5870, 17, 1219, {1, 3, 5, 9, 13, 59, 71, 19, 107, 73, 345, 3177, 6519, 2407, 18033, 31075, 113185}},
-{5871, 17, 1233, {1, 1, 1, 3, 27, 37, 5, 219, 169, 149, 355, 549, 1811, 11351, 22627, 53931, 88619}},
-{5872, 17, 1264, {1, 3, 1, 3, 27, 7, 9, 97, 399, 947, 1393, 3917, 5439, 15845, 19465, 30123, 69099}},
-{5873, 17, 1267, {1, 1, 7, 9, 13, 25, 107, 45, 111, 409, 967, 3359, 2499, 1703, 20763, 45187, 16265}},
-{5874, 17, 1281, {1, 1, 1, 13, 5, 49, 43, 249, 49, 947, 597, 1773, 2387, 2693, 15297, 57969, 53385}},
-{5875, 17, 1312, {1, 1, 7, 15, 27, 25, 27, 121, 421, 781, 143, 817, 7335, 14211, 139, 55601, 56671}},
-{5876, 17, 1321, {1, 3, 1, 5, 29, 47, 77, 23, 413, 931, 785, 1221, 769, 13131, 26955, 56441, 85745}},
-{5877, 17, 1330, {1, 1, 1, 11, 27, 3, 53, 21, 467, 43, 1533, 1053, 691, 6369, 8325, 51087, 71261}},
-{5878, 17, 1332, {1, 1, 3, 15, 7, 9, 43, 225, 293, 143, 1049, 3095, 6119, 3165, 9913, 26023, 62657}},
-{5879, 17, 1335, {1, 3, 7, 9, 11, 39, 99, 193, 217, 941, 259, 3811, 6757, 281, 10377, 46961, 48949}},
-{5880, 17, 1341, {1, 1, 1, 1, 25, 1, 99, 61, 495, 861, 2013, 487, 2821, 12921, 30111, 27213, 97363}},
-{5881, 17, 1356, {1, 1, 5, 9, 23, 33, 103, 237, 161, 721, 2021, 159, 995, 475, 20615, 30961, 31767}},
-{5882, 17, 1371, {1, 3, 1, 1, 5, 59, 63, 139, 451, 789, 1285, 655, 5501, 273, 21061, 35937, 20811}},
-{5883, 17, 1377, {1, 3, 3, 9, 9, 15, 121, 233, 287, 929, 1605, 1243, 417, 1695, 29903, 28699, 85981}},
-{5884, 17, 1380, {1, 3, 3, 5, 7, 25, 27, 253, 469, 255, 285, 2467, 4897, 4079, 29759, 50351, 76451}},
-{5885, 17, 1384, {1, 1, 3, 3, 5, 33, 29, 209, 291, 967, 1429, 1953, 5957, 14065, 8875, 32675, 4629}},
-{5886, 17, 1395, {1, 3, 5, 9, 7, 31, 97, 21, 177, 485, 1115, 4051, 6683, 7761, 30181, 37531, 51789}},
-{5887, 17, 1397, {1, 1, 7, 3, 25, 51, 23, 183, 57, 699, 1245, 2519, 2783, 4457, 6381, 43199, 40071}},
-{5888, 17, 1411, {1, 3, 5, 5, 19, 55, 45, 101, 299, 461, 1009, 319, 7335, 7769, 5479, 61113, 7937}},
-{5889, 17, 1414, {1, 1, 7, 3, 29, 21, 55, 55, 437, 771, 363, 683, 4299, 15569, 13813, 40663, 86285}},
-{5890, 17, 1426, {1, 1, 1, 13, 31, 35, 93, 175, 451, 387, 1145, 3367, 3833, 13495, 11019, 48925, 85721}},
-{5891, 17, 1432, {1, 1, 7, 15, 31, 21, 55, 205, 117, 895, 535, 2627, 1473, 10779, 24493, 42999, 130805}},
-{5892, 17, 1435, {1, 1, 3, 13, 27, 11, 45, 37, 193, 237, 1505, 1405, 3613, 9565, 3037, 53643, 85211}},
-{5893, 17, 1437, {1, 1, 3, 13, 9, 17, 19, 27, 117, 503, 65, 1033, 7891, 4005, 9229, 20999, 96601}},
-{5894, 17, 1442, {1, 3, 3, 5, 17, 3, 71, 79, 145, 985, 935, 3997, 6239, 12511, 13895, 65031, 126383}},
-{5895, 17, 1454, {1, 1, 5, 1, 23, 55, 3, 105, 71, 243, 1479, 111, 7103, 10753, 26193, 35833, 14583}},
-{5896, 17, 1468, {1, 3, 3, 3, 15, 3, 73, 125, 267, 29, 1775, 1437, 8091, 10891, 25731, 54381, 12821}},
-{5897, 17, 1473, {1, 1, 1, 3, 23, 15, 67, 123, 401, 347, 807, 1097, 31, 11209, 8727, 58149, 129099}},
-{5898, 17, 1488, {1, 3, 3, 7, 7, 61, 49, 129, 423, 535, 135, 3587, 233, 4509, 23209, 59203, 41297}},
-{5899, 17, 1491, {1, 3, 1, 7, 5, 29, 65, 31, 335, 855, 835, 1421, 3081, 14219, 16321, 48269, 41603}},
-{5900, 17, 1509, {1, 1, 1, 13, 3, 21, 5, 117, 163, 603, 1519, 3789, 7873, 10981, 4615, 9165, 83929}},
-{5901, 17, 1524, {1, 3, 5, 11, 15, 21, 75, 151, 193, 757, 647, 1603, 333, 10515, 22771, 55459, 3315}},
-{5902, 17, 1533, {1, 1, 7, 1, 27, 3, 63, 197, 271, 175, 1599, 2119, 1031, 8671, 10893, 35641, 94535}},
-{5903, 17, 1555, {1, 1, 1, 15, 1, 59, 93, 17, 5, 213, 1663, 941, 435, 8107, 1963, 34951, 106181}},
-{5904, 17, 1567, {1, 1, 5, 11, 13, 35, 111, 97, 267, 737, 2023, 1301, 7407, 11249, 31785, 31933, 20673}},
-{5905, 17, 1571, {1, 3, 3, 15, 5, 15, 29, 63, 189, 687, 27, 2005, 7129, 11377, 23175, 42389, 30933}},
-{5906, 17, 1586, {1, 1, 1, 9, 13, 63, 7, 155, 67, 291, 1419, 755, 2623, 4749, 22971, 7545, 55711}},
-{5907, 17, 1592, {1, 3, 7, 7, 23, 29, 83, 151, 213, 201, 157, 3051, 6553, 6401, 15931, 47941, 22869}},
-{5908, 17, 1595, {1, 3, 5, 5, 7, 45, 33, 155, 225, 25, 49, 2419, 4241, 6835, 11401, 50725, 118343}},
-{5909, 17, 1600, {1, 1, 3, 13, 31, 27, 37, 41, 19, 375, 1771, 1789, 2313, 2577, 12615, 22715, 22179}},
-{5910, 17, 1606, {1, 3, 1, 11, 17, 53, 55, 229, 235, 837, 143, 3583, 2789, 5471, 6515, 44565, 8619}},
-{5911, 17, 1627, {1, 1, 5, 15, 5, 17, 23, 95, 217, 551, 353, 27, 3973, 2547, 27903, 50611, 72277}},
-{5912, 17, 1648, {1, 1, 3, 7, 5, 13, 41, 111, 157, 215, 1327, 3073, 1871, 11875, 24239, 40527, 97637}},
-{5913, 17, 1651, {1, 3, 1, 1, 29, 63, 111, 187, 369, 395, 1197, 3229, 4353, 14715, 29671, 50503, 89321}},
-{5914, 17, 1654, {1, 3, 1, 1, 5, 63, 11, 39, 171, 209, 463, 3421, 3451, 4453, 14397, 2219, 98261}},
-{5915, 17, 1667, {1, 3, 3, 5, 1, 1, 13, 101, 67, 815, 1521, 1543, 7221, 7337, 10765, 30029, 47881}},
-{5916, 17, 1669, {1, 1, 5, 7, 9, 9, 33, 197, 439, 893, 961, 11, 4319, 14265, 24839, 33581, 35531}},
-{5917, 17, 1674, {1, 3, 3, 15, 29, 35, 43, 229, 313, 369, 955, 1069, 2939, 12623, 20373, 1533, 9105}},
-{5918, 17, 1687, {1, 3, 1, 7, 21, 7, 127, 243, 103, 353, 859, 3789, 4369, 12063, 22369, 14531, 94289}},
-{5919, 17, 1698, {1, 3, 5, 15, 1, 27, 65, 127, 229, 99, 627, 2693, 7173, 7305, 29971, 7097, 10113}},
-{5920, 17, 1710, {1, 1, 5, 15, 3, 47, 61, 29, 155, 725, 1727, 2667, 7003, 16277, 21983, 21365, 129365}},
-{5921, 17, 1717, {1, 1, 5, 7, 27, 61, 115, 133, 137, 661, 1201, 2151, 367, 3567, 12885, 62143, 53955}},
-{5922, 17, 1722, {1, 1, 1, 11, 9, 41, 113, 103, 469, 687, 1541, 3679, 6833, 10493, 32747, 39909, 121445}},
-{5923, 17, 1735, {1, 1, 7, 5, 5, 5, 91, 91, 5, 405, 529, 3999, 6783, 2387, 16621, 12919, 8659}},
-{5924, 17, 1741, {1, 1, 7, 13, 21, 47, 125, 155, 83, 913, 1833, 4027, 6657, 7031, 31231, 58201, 88943}},
-{5925, 17, 1749, {1, 3, 7, 3, 17, 55, 25, 29, 181, 205, 1173, 1081, 6475, 5037, 18461, 22487, 114131}},
-{5926, 17, 1750, {1, 1, 7, 7, 25, 63, 101, 103, 171, 191, 1863, 3441, 2515, 14179, 30123, 19145, 31669}},
-{5927, 17, 1769, {1, 3, 7, 11, 29, 49, 73, 163, 415, 821, 1809, 723, 7049, 14565, 4829, 19395, 61131}},
-{5928, 17, 1775, {1, 1, 7, 9, 5, 25, 103, 167, 381, 757, 813, 471, 3021, 6619, 20929, 38133, 129505}},
-{5929, 17, 1777, {1, 1, 5, 13, 25, 61, 59, 199, 257, 999, 169, 3289, 7181, 2049, 2185, 39045, 102703}},
-{5930, 17, 1778, {1, 1, 3, 1, 21, 1, 111, 125, 289, 33, 701, 3491, 5569, 8055, 23149, 26793, 102563}},
-{5931, 17, 1792, {1, 1, 7, 3, 25, 15, 105, 235, 307, 201, 1947, 699, 2519, 10615, 29345, 17061, 112949}},
-{5932, 17, 1797, {1, 3, 3, 15, 19, 1, 93, 173, 399, 13, 269, 1189, 523, 5145, 32731, 54087, 94123}},
-{5933, 17, 1802, {1, 3, 1, 15, 9, 41, 59, 79, 217, 833, 1993, 2429, 3599, 6919, 30911, 12615, 67947}},
-{5934, 17, 1822, {1, 3, 3, 13, 31, 9, 95, 37, 343, 955, 1363, 3851, 4091, 13165, 15241, 14853, 35747}},
-{5935, 17, 1825, {1, 1, 3, 5, 27, 39, 37, 217, 385, 473, 1997, 2247, 7353, 1503, 9003, 15055, 27289}},
-{5936, 17, 1831, {1, 3, 7, 11, 1, 13, 21, 243, 375, 91, 1295, 1661, 203, 15251, 15355, 16065, 24183}},
-{5937, 17, 1838, {1, 3, 1, 13, 11, 45, 85, 5, 275, 741, 1395, 4011, 7987, 16087, 24113, 50555, 128147}},
-{5938, 17, 1852, {1, 1, 1, 7, 3, 11, 13, 189, 55, 151, 395, 657, 807, 11973, 26297, 13043, 109641}},
-{5939, 17, 1855, {1, 1, 7, 13, 31, 19, 33, 235, 491, 647, 1115, 2299, 6381, 7525, 2237, 36197, 126457}},
-{5940, 17, 1860, {1, 3, 5, 1, 21, 15, 53, 231, 77, 347, 969, 141, 4501, 9429, 1815, 50887, 74581}},
-{5941, 17, 1867, {1, 1, 1, 9, 29, 43, 47, 103, 327, 131, 927, 441, 7517, 7277, 21065, 409, 50351}},
-{5942, 17, 1869, {1, 1, 5, 1, 11, 13, 103, 157, 239, 69, 1347, 477, 5017, 9723, 28133, 65135, 12359}},
-{5943, 17, 1875, {1, 1, 1, 13, 17, 63, 117, 189, 323, 565, 927, 1727, 5337, 13243, 5739, 31241, 14209}},
-{5944, 17, 1882, {1, 1, 3, 9, 29, 9, 103, 61, 467, 217, 1367, 2405, 5355, 5743, 31469, 30149, 98775}},
-{5945, 17, 1903, {1, 1, 1, 15, 23, 23, 17, 229, 103, 583, 179, 115, 7081, 9437, 32623, 62639, 72391}},
-{5946, 17, 1908, {1, 1, 5, 11, 11, 39, 97, 209, 115, 107, 593, 2347, 1445, 6179, 32011, 8435, 65847}},
-{5947, 17, 1917, {1, 3, 7, 3, 29, 27, 55, 111, 27, 731, 995, 1871, 5017, 1485, 11313, 2559, 6561}},
-{5948, 17, 1927, {1, 3, 1, 3, 27, 9, 103, 247, 83, 197, 517, 1629, 2189, 7255, 183, 35111, 15077}},
-{5949, 17, 1941, {1, 3, 7, 5, 31, 37, 87, 223, 343, 331, 1361, 3371, 2007, 13235, 10897, 63839, 109837}},
-{5950, 17, 1945, {1, 1, 7, 11, 17, 5, 41, 197, 489, 625, 1595, 2663, 5941, 14029, 30999, 16781, 116001}},
-{5951, 17, 1948, {1, 3, 3, 7, 19, 19, 61, 175, 125, 609, 1391, 147, 3001, 4189, 10133, 24031, 46219}},
-{5952, 17, 1962, {1, 1, 3, 13, 13, 57, 117, 181, 299, 939, 583, 3151, 829, 6561, 30449, 12211, 107879}},
-{5953, 17, 1975, {1, 1, 5, 11, 23, 45, 87, 115, 259, 613, 1001, 171, 57, 13789, 22173, 56837, 26263}},
-{5954, 17, 1976, {1, 1, 3, 3, 7, 43, 45, 131, 87, 251, 1411, 2737, 2739, 4595, 12561, 12043, 82885}},
-{5955, 17, 1987, {1, 3, 3, 7, 19, 39, 87, 223, 461, 37, 283, 3937, 6193, 10887, 11509, 41131, 38359}},
-{5956, 17, 1993, {1, 3, 1, 11, 11, 37, 25, 133, 105, 1013, 925, 3301, 239, 16295, 4831, 8649, 125767}},
-{5957, 17, 2004, {1, 3, 3, 11, 25, 11, 41, 155, 1, 717, 1587, 635, 279, 1803, 14817, 28669, 88835}},
-{5958, 17, 2020, {1, 3, 3, 11, 29, 17, 39, 51, 13, 871, 1197, 2561, 6671, 8465, 22709, 15933, 15923}},
-{5959, 17, 2029, {1, 3, 7, 1, 13, 17, 57, 43, 267, 261, 901, 241, 3767, 15053, 11017, 36321, 72497}},
-{5960, 17, 2030, {1, 3, 1, 15, 23, 13, 17, 63, 171, 919, 1387, 2673, 7605, 8523, 14807, 21187, 56057}},
-{5961, 17, 2038, {1, 3, 7, 15, 23, 41, 85, 95, 53, 629, 1877, 3167, 2411, 9619, 24621, 31213, 30069}},
-{5962, 17, 2041, {1, 1, 5, 3, 3, 25, 99, 39, 321, 549, 599, 1279, 2401, 2335, 8227, 59429, 94549}},
-{5963, 17, 2048, {1, 3, 3, 11, 9, 21, 29, 55, 477, 19, 1275, 29, 2253, 11421, 30401, 57059, 93219}},
-{5964, 17, 2054, {1, 1, 7, 1, 27, 13, 117, 249, 463, 769, 281, 515, 7467, 11507, 1621, 39765, 31109}},
-{5965, 17, 2057, {1, 3, 5, 7, 19, 7, 77, 107, 23, 895, 1013, 2701, 3805, 7327, 27247, 6119, 102395}},
-{5966, 17, 2058, {1, 1, 3, 13, 21, 49, 99, 15, 163, 641, 1703, 3061, 163, 4265, 32571, 13957, 75005}},
-{5967, 17, 2068, {1, 1, 5, 11, 27, 17, 87, 169, 427, 959, 361, 1023, 5727, 16279, 1099, 39081, 67215}},
-{5968, 17, 2072, {1, 3, 3, 9, 23, 13, 1, 91, 173, 325, 1881, 1385, 8023, 935, 9221, 19673, 36949}},
-{5969, 17, 2075, {1, 3, 1, 7, 7, 25, 119, 189, 107, 249, 811, 973, 6499, 101, 11281, 55227, 32361}},
-{5970, 17, 2077, {1, 1, 5, 13, 19, 37, 117, 95, 463, 587, 1419, 445, 4019, 7257, 29757, 50773, 52247}},
-{5971, 17, 2082, {1, 1, 1, 1, 17, 57, 81, 57, 43, 789, 1035, 625, 1707, 9683, 3681, 12411, 110623}},
-{5972, 17, 2084, {1, 1, 7, 5, 7, 57, 49, 91, 459, 513, 1869, 3377, 139, 10037, 24091, 54247, 41279}},
-{5973, 17, 2087, {1, 3, 3, 9, 9, 33, 29, 51, 355, 415, 1907, 809, 6543, 349, 18507, 12919, 41667}},
-{5974, 17, 2101, {1, 1, 5, 11, 3, 17, 73, 201, 121, 909, 1623, 799, 3271, 9051, 5717, 15169, 127861}},
-{5975, 17, 2111, {1, 1, 7, 7, 23, 31, 1, 155, 475, 87, 2001, 2459, 1285, 5931, 6803, 56757, 71671}},
-{5976, 17, 2113, {1, 1, 5, 13, 5, 1, 21, 109, 263, 841, 723, 1539, 7529, 433, 23721, 33195, 57001}},
-{5977, 17, 2119, {1, 3, 3, 13, 29, 55, 105, 231, 405, 265, 671, 351, 4693, 9033, 21963, 52073, 125131}},
-{5978, 17, 2147, {1, 3, 1, 13, 25, 51, 55, 227, 245, 983, 251, 2553, 2017, 1381, 31461, 3953, 75775}},
-{5979, 17, 2154, {1, 1, 1, 11, 31, 11, 91, 91, 287, 749, 1019, 4055, 3237, 6965, 14765, 1663, 82987}},
-{5980, 17, 2161, {1, 1, 7, 3, 11, 15, 67, 161, 79, 729, 1115, 3713, 2715, 9361, 9365, 26093, 63409}},
-{5981, 17, 2164, {1, 3, 1, 7, 1, 51, 125, 15, 457, 433, 405, 2329, 157, 4817, 25867, 38177, 45319}},
-{5982, 17, 2177, {1, 3, 7, 9, 25, 57, 5, 233, 481, 781, 1313, 3179, 7219, 8717, 14825, 16079, 127149}},
-{5983, 17, 2178, {1, 1, 7, 15, 27, 51, 5, 65, 77, 313, 1751, 1489, 4307, 10541, 11345, 52577, 18143}},
-{5984, 17, 2184, {1, 1, 1, 15, 21, 5, 113, 71, 411, 327, 1681, 1023, 5661, 15815, 5387, 10351, 21121}},
-{5985, 17, 2198, {1, 1, 5, 5, 29, 55, 25, 255, 69, 879, 501, 1915, 3731, 633, 12197, 5249, 31129}},
-{5986, 17, 2201, {1, 3, 5, 7, 3, 23, 107, 163, 485, 853, 359, 3069, 4353, 371, 6027, 53239, 105541}},
-{5987, 17, 2213, {1, 3, 5, 15, 7, 41, 9, 47, 33, 327, 621, 147, 577, 29, 14623, 3403, 9791}},
-{5988, 17, 2217, {1, 3, 3, 15, 29, 47, 41, 149, 477, 127, 573, 877, 3101, 5963, 28457, 14231, 67425}},
-{5989, 17, 2228, {1, 1, 1, 15, 31, 7, 55, 191, 101, 259, 1071, 219, 2233, 3583, 21969, 32745, 80529}},
-{5990, 17, 2240, {1, 3, 7, 13, 17, 53, 115, 69, 241, 71, 1475, 191, 509, 3721, 15537, 53773, 18005}},
-{5991, 17, 2245, {1, 1, 3, 9, 5, 57, 13, 95, 103, 871, 2043, 2239, 7833, 10727, 6513, 55273, 3781}},
-{5992, 17, 2250, {1, 1, 5, 5, 9, 11, 55, 151, 239, 537, 135, 2779, 7393, 15393, 11097, 58593, 100745}},
-{5993, 17, 2263, {1, 1, 1, 9, 15, 39, 29, 105, 441, 181, 1113, 2125, 8145, 11045, 6589, 33603, 83377}},
-{5994, 17, 2267, {1, 3, 1, 1, 11, 63, 69, 153, 225, 845, 675, 407, 4691, 13383, 27359, 38881, 5509}},
-{5995, 17, 2285, {1, 3, 7, 11, 23, 31, 69, 3, 41, 57, 683, 887, 6861, 12161, 14537, 27293, 113001}},
-{5996, 17, 2286, {1, 1, 1, 11, 5, 1, 101, 175, 437, 3, 1477, 1005, 6607, 7429, 7213, 4025, 66479}},
-{5997, 17, 2291, {1, 1, 7, 5, 19, 7, 99, 131, 273, 977, 1717, 3831, 175, 5673, 12577, 36787, 30945}},
-{5998, 17, 2298, {1, 3, 1, 1, 15, 37, 105, 195, 61, 869, 255, 2625, 7401, 9361, 13217, 52811, 130811}},
-{5999, 17, 2306, {1, 3, 5, 3, 29, 27, 105, 23, 511, 813, 1311, 2859, 1647, 1949, 1329, 27589, 125209}},
-{6000, 17, 2325, {1, 3, 3, 1, 21, 11, 119, 247, 123, 401, 409, 1845, 2133, 10793, 221, 43217, 14069}},
-{6001, 17, 2329, {1, 1, 5, 1, 29, 21, 51, 73, 501, 861, 725, 249, 4249, 8029, 15767, 11985, 18637}},
-{6002, 17, 2332, {1, 1, 5, 11, 19, 39, 97, 65, 13, 283, 489, 2307, 5239, 4161, 18639, 60035, 22405}},
-{6003, 17, 2335, {1, 3, 5, 1, 3, 7, 109, 27, 429, 663, 1569, 3001, 3453, 8627, 9719, 23941, 110451}},
-{6004, 17, 2339, {1, 3, 7, 5, 17, 13, 125, 209, 347, 95, 1937, 1419, 5661, 7171, 20607, 9777, 68343}},
-{6005, 17, 2346, {1, 1, 1, 1, 7, 41, 43, 229, 57, 49, 1863, 2819, 3735, 915, 1571, 11603, 116275}},
-{6006, 17, 2351, {1, 1, 7, 9, 21, 27, 5, 199, 181, 521, 303, 1097, 5427, 8899, 30325, 55457, 16189}},
-{6007, 17, 2353, {1, 3, 3, 7, 19, 41, 3, 205, 279, 223, 971, 633, 2617, 13191, 10193, 23375, 62563}},
-{6008, 17, 2363, {1, 3, 3, 13, 23, 59, 85, 25, 253, 405, 65, 1625, 4401, 4679, 14381, 57833, 30001}},
-{6009, 17, 2378, {1, 3, 3, 3, 13, 35, 11, 157, 123, 397, 119, 2513, 1919, 14583, 5469, 11463, 94711}},
-{6010, 17, 2383, {1, 1, 1, 7, 17, 37, 83, 211, 451, 939, 449, 13, 6671, 1457, 19855, 15053, 52327}},
-{6011, 17, 2391, {1, 1, 5, 3, 9, 57, 39, 183, 331, 451, 1391, 1865, 7801, 14293, 29069, 705, 109497}},
-{6012, 17, 2401, {1, 3, 7, 7, 23, 21, 85, 81, 255, 9, 1685, 2879, 6327, 12675, 31657, 38877, 74131}},
-{6013, 17, 2408, {1, 1, 5, 9, 25, 19, 41, 195, 31, 555, 927, 1445, 593, 11067, 10819, 17205, 82037}},
-{6014, 17, 2414, {1, 3, 1, 13, 1, 35, 29, 71, 323, 705, 53, 3885, 6223, 1319, 30853, 59935, 35949}},
-{6015, 17, 2419, {1, 1, 7, 3, 27, 63, 67, 31, 149, 61, 1611, 77, 4271, 3161, 12493, 38341, 53837}},
-{6016, 17, 2428, {1, 1, 1, 15, 27, 53, 31, 249, 429, 925, 1485, 1855, 4421, 5703, 10097, 14827, 36685}},
-{6017, 17, 2441, {1, 3, 7, 13, 7, 63, 53, 9, 317, 485, 1679, 3631, 3745, 5643, 21615, 45129, 48027}},
-{6018, 17, 2444, {1, 1, 1, 1, 17, 43, 19, 163, 441, 847, 937, 959, 6649, 13071, 1065, 55193, 129509}},
-{6019, 17, 2461, {1, 1, 1, 11, 29, 47, 9, 215, 397, 637, 961, 3139, 2007, 12603, 27657, 22825, 72873}},
-{6020, 17, 2480, {1, 3, 3, 15, 7, 45, 55, 163, 259, 899, 951, 3245, 4191, 15813, 20195, 8361, 54025}},
-{6021, 17, 2483, {1, 1, 5, 11, 3, 17, 13, 223, 289, 255, 875, 2937, 1593, 9729, 21569, 63199, 83875}},
-{6022, 17, 2486, {1, 1, 1, 15, 19, 31, 17, 129, 267, 9, 2015, 3233, 6799, 12891, 18473, 37865, 19547}},
-{6023, 17, 2489, {1, 1, 5, 5, 5, 29, 81, 37, 357, 539, 1525, 2839, 8041, 5569, 4423, 8907, 35461}},
-{6024, 17, 2490, {1, 1, 5, 5, 29, 11, 85, 61, 333, 521, 1111, 3627, 325, 9805, 17889, 25655, 39537}},
-{6025, 17, 2518, {1, 3, 5, 11, 11, 53, 81, 25, 79, 253, 1963, 287, 7487, 15045, 21431, 35417, 102391}},
-{6026, 17, 2527, {1, 1, 1, 5, 11, 33, 45, 45, 425, 773, 1817, 4077, 1471, 11655, 683, 7115, 92651}},
-{6027, 17, 2540, {1, 1, 3, 3, 21, 13, 101, 215, 311, 853, 41, 1007, 5511, 2581, 25565, 13155, 117225}},
-{6028, 17, 2558, {1, 1, 3, 11, 19, 9, 125, 59, 273, 691, 499, 1547, 567, 10259, 21963, 48725, 3601}},
-{6029, 17, 2567, {1, 1, 3, 7, 27, 31, 39, 125, 317, 625, 1329, 3947, 3943, 6889, 2811, 34055, 1449}},
-{6030, 17, 2571, {1, 1, 1, 3, 29, 45, 73, 239, 319, 611, 647, 1839, 5277, 7807, 3107, 14683, 20203}},
-{6031, 17, 2574, {1, 3, 3, 3, 5, 5, 107, 139, 103, 809, 1343, 4041, 3273, 1789, 16205, 47873, 27803}},
-{6032, 17, 2579, {1, 3, 1, 9, 21, 23, 13, 131, 105, 741, 1773, 981, 5633, 14609, 12281, 50343, 14317}},
-{6033, 17, 2585, {1, 1, 1, 5, 11, 5, 125, 171, 109, 555, 159, 905, 691, 12401, 22817, 41411, 70113}},
-{6034, 17, 2615, {1, 3, 3, 9, 31, 37, 109, 231, 59, 615, 799, 319, 2459, 4521, 8525, 4827, 22969}},
-{6035, 17, 2639, {1, 3, 1, 5, 11, 7, 49, 237, 345, 473, 981, 2073, 6525, 8805, 13403, 3659, 69897}},
-{6036, 17, 2641, {1, 3, 1, 5, 9, 37, 13, 203, 141, 573, 745, 2613, 5589, 607, 24483, 38427, 95775}},
-{6037, 17, 2644, {1, 1, 3, 1, 23, 61, 75, 57, 299, 191, 805, 2993, 5175, 12037, 13649, 58831, 48791}},
-{6038, 17, 2663, {1, 3, 7, 13, 31, 57, 13, 219, 185, 717, 1607, 3785, 4719, 11583, 29285, 48207, 92021}},
-{6039, 17, 2667, {1, 3, 7, 15, 23, 35, 23, 69, 411, 773, 1549, 1087, 1685, 15703, 27193, 62675, 43505}},
-{6040, 17, 2669, {1, 1, 5, 3, 25, 19, 97, 75, 493, 549, 1655, 2881, 4989, 2765, 4797, 43143, 113955}},
-{6041, 17, 2672, {1, 1, 5, 7, 21, 5, 65, 37, 383, 133, 1907, 3747, 1525, 5803, 19977, 50551, 23157}},
-{6042, 17, 2687, {1, 1, 1, 11, 15, 61, 59, 109, 489, 901, 1787, 1611, 6101, 10653, 3071, 35643, 56227}},
-{6043, 17, 2700, {1, 3, 1, 5, 15, 25, 121, 111, 25, 251, 1467, 1795, 1631, 13753, 32391, 14831, 90739}},
-{6044, 17, 2705, {1, 1, 1, 13, 23, 55, 119, 147, 45, 871, 1389, 1929, 1023, 16131, 10041, 40055, 23337}},
-{6045, 17, 2724, {1, 3, 1, 15, 27, 33, 23, 41, 463, 603, 1633, 3445, 2007, 5999, 11175, 18343, 13159}},
-{6046, 17, 2728, {1, 3, 1, 9, 17, 15, 107, 63, 493, 411, 293, 3669, 6143, 3057, 8253, 25491, 58907}},
-{6047, 17, 2733, {1, 3, 5, 11, 1, 43, 5, 117, 127, 813, 1881, 3711, 2567, 7819, 5809, 64471, 104221}},
-{6048, 17, 2741, {1, 3, 5, 9, 25, 27, 49, 93, 77, 705, 1773, 1745, 4605, 16137, 14621, 62893, 81637}},
-{6049, 17, 2748, {1, 3, 1, 15, 9, 29, 41, 101, 291, 763, 1475, 3185, 3661, 10351, 26645, 50375, 59373}},
-{6050, 17, 2751, {1, 1, 5, 15, 9, 31, 107, 159, 125, 471, 1023, 2361, 4805, 8073, 21563, 14903, 77801}},
-{6051, 17, 2756, {1, 3, 7, 1, 27, 17, 75, 129, 71, 697, 551, 1969, 6597, 13821, 2605, 61783, 74791}},
-{6052, 17, 2771, {1, 1, 7, 15, 17, 27, 49, 47, 59, 47, 1671, 2535, 1299, 2387, 24349, 23661, 91123}},
-{6053, 17, 2774, {1, 1, 5, 15, 21, 61, 45, 37, 415, 189, 143, 351, 1815, 3479, 2399, 56753, 123893}},
-{6054, 17, 2793, {1, 1, 3, 7, 7, 19, 93, 249, 335, 305, 1437, 1329, 2693, 13201, 9589, 61513, 115995}},
-{6055, 17, 2796, {1, 1, 1, 11, 21, 57, 33, 205, 235, 253, 751, 259, 6029, 9811, 10231, 36899, 78035}},
-{6056, 17, 2804, {1, 1, 1, 11, 13, 25, 115, 195, 111, 913, 1851, 3283, 6083, 11717, 2773, 40727, 493}},
-{6057, 17, 2814, {1, 3, 3, 9, 9, 17, 83, 137, 465, 671, 1277, 325, 2767, 12413, 21977, 47525, 23041}},
-{6058, 17, 2822, {1, 1, 1, 11, 15, 47, 65, 219, 271, 197, 297, 3195, 1325, 9991, 26385, 46055, 43151}},
-{6059, 17, 2845, {1, 1, 1, 13, 31, 21, 39, 89, 127, 629, 367, 2935, 6259, 6627, 15691, 55781, 97251}},
-{6060, 17, 2846, {1, 1, 7, 13, 11, 45, 65, 75, 211, 785, 1221, 2087, 7751, 15619, 25489, 28195, 69007}},
-{6061, 17, 2850, {1, 3, 5, 15, 27, 37, 75, 111, 487, 219, 233, 583, 6433, 15105, 355, 28331, 21105}},
-{6062, 17, 2855, {1, 3, 3, 15, 31, 53, 33, 95, 27, 197, 1727, 1467, 7115, 15479, 26873, 31075, 12793}},
-{6063, 17, 2856, {1, 3, 7, 1, 19, 3, 19, 105, 225, 599, 737, 107, 7951, 10193, 31699, 59207, 85619}},
-{6064, 17, 2867, {1, 3, 1, 3, 7, 17, 73, 191, 247, 421, 537, 1473, 189, 4219, 29993, 25491, 21189}},
-{6065, 17, 2891, {1, 3, 7, 7, 13, 21, 33, 95, 147, 699, 943, 2275, 4093, 6067, 9063, 25503, 111085}},
-{6066, 17, 2894, {1, 1, 7, 9, 13, 47, 123, 121, 347, 467, 225, 957, 2329, 14075, 29843, 61753, 97179}},
-{6067, 17, 2902, {1, 3, 3, 7, 17, 55, 37, 167, 215, 819, 163, 1747, 4485, 15991, 28011, 36351, 106495}},
-{6068, 17, 2908, {1, 1, 3, 9, 25, 5, 83, 199, 209, 395, 1757, 1967, 5739, 2573, 13989, 32145, 4847}},
-{6069, 17, 2951, {1, 3, 3, 13, 11, 21, 25, 223, 239, 569, 1877, 299, 8089, 3697, 801, 64775, 26827}},
-{6070, 17, 2970, {1, 3, 5, 7, 17, 9, 127, 9, 65, 919, 1073, 2661, 1337, 10065, 30099, 30929, 90067}},
-{6071, 17, 2972, {1, 3, 1, 13, 25, 41, 35, 251, 279, 351, 111, 3917, 2815, 7989, 9895, 54859, 126355}},
-{6072, 17, 2975, {1, 1, 3, 7, 17, 61, 13, 73, 335, 831, 703, 37, 2765, 13169, 12513, 56301, 13907}},
-{6073, 17, 2976, {1, 1, 5, 13, 11, 15, 33, 45, 505, 127, 1723, 17, 4927, 11453, 28859, 9671, 80041}},
-{6074, 17, 2981, {1, 3, 1, 5, 9, 1, 25, 147, 281, 601, 243, 2687, 5533, 6725, 11075, 34807, 24619}},
-{6075, 17, 2986, {1, 1, 3, 1, 7, 21, 71, 31, 485, 561, 1361, 1237, 8171, 15885, 7941, 4583, 32851}},
-{6076, 17, 2999, {1, 3, 7, 1, 5, 35, 95, 155, 283, 959, 577, 1343, 4269, 13481, 30819, 40273, 8711}},
-{6077, 17, 3000, {1, 3, 7, 3, 1, 53, 77, 45, 215, 537, 1045, 77, 2791, 3553, 13273, 23819, 62263}},
-{6078, 17, 3006, {1, 3, 1, 15, 29, 59, 7, 145, 85, 3, 251, 2691, 7547, 11241, 32295, 24645, 75739}},
-{6079, 17, 3014, {1, 1, 5, 9, 19, 9, 39, 163, 303, 233, 2039, 2027, 7169, 2773, 28649, 38317, 66761}},
-{6080, 17, 3028, {1, 3, 7, 5, 21, 27, 93, 227, 131, 1019, 1619, 1497, 4043, 1131, 25761, 20173, 99957}},
-{6081, 17, 3031, {1, 3, 7, 5, 19, 33, 15, 173, 435, 399, 531, 2001, 3221, 12627, 10153, 24421, 61805}},
-{6082, 17, 3035, {1, 3, 1, 9, 11, 3, 69, 105, 289, 183, 1103, 831, 2297, 1613, 18801, 54395, 54243}},
-{6083, 17, 3037, {1, 3, 3, 9, 3, 53, 113, 183, 79, 355, 1629, 1061, 3713, 4563, 14365, 43529, 56073}},
-{6084, 17, 3053, {1, 3, 7, 11, 31, 39, 107, 139, 187, 873, 225, 33, 4943, 15837, 225, 6407, 85967}},
-{6085, 17, 3059, {1, 3, 1, 11, 17, 47, 93, 233, 119, 699, 1429, 2845, 2061, 8887, 20665, 45497, 33107}},
-{6086, 17, 3065, {1, 3, 5, 1, 25, 11, 55, 75, 91, 1009, 1887, 3167, 515, 15929, 11659, 57953, 63401}},
-{6087, 17, 3080, {1, 1, 3, 15, 27, 59, 103, 53, 353, 553, 2021, 1543, 2785, 9373, 14609, 21213, 19911}},
-{6088, 17, 3091, {1, 3, 7, 9, 3, 1, 101, 133, 437, 773, 1399, 1067, 7419, 1793, 16589, 3483, 42065}},
-{6089, 17, 3094, {1, 3, 7, 1, 25, 57, 127, 113, 65, 577, 1865, 1527, 6485, 11273, 15803, 39625, 75219}},
-{6090, 17, 3109, {1, 3, 5, 9, 7, 63, 29, 89, 155, 45, 1029, 2407, 6783, 4749, 4849, 26639, 54059}},
-{6091, 17, 3110, {1, 3, 7, 9, 25, 13, 113, 41, 267, 767, 1071, 1689, 269, 14437, 21255, 39473, 65771}},
-{6092, 17, 3113, {1, 3, 1, 15, 5, 3, 77, 43, 391, 763, 59, 1027, 6263, 3715, 31061, 43311, 130725}},
-{6093, 17, 3116, {1, 3, 7, 7, 21, 51, 127, 71, 229, 171, 397, 1099, 871, 2717, 1643, 17363, 125979}},
-{6094, 17, 3136, {1, 1, 5, 15, 25, 11, 11, 113, 203, 795, 1703, 3901, 1113, 12819, 25345, 46691, 112313}},
-{6095, 17, 3139, {1, 3, 7, 5, 1, 59, 91, 81, 325, 483, 595, 1491, 7455, 6699, 199, 35597, 59851}},
-{6096, 17, 3141, {1, 3, 5, 1, 3, 33, 43, 195, 201, 575, 1395, 1305, 7001, 2023, 22419, 15233, 120355}},
-{6097, 17, 3154, {1, 1, 3, 3, 15, 37, 81, 59, 87, 675, 199, 3231, 4473, 5023, 16753, 51475, 102113}},
-{6098, 17, 3160, {1, 1, 7, 9, 13, 39, 65, 9, 51, 565, 1171, 119, 7875, 12149, 6565, 56849, 123235}},
-{6099, 17, 3169, {1, 3, 3, 7, 15, 45, 53, 93, 111, 533, 1849, 643, 2265, 10241, 24741, 11559, 74333}},
-{6100, 17, 3182, {1, 3, 1, 1, 11, 61, 75, 51, 5, 199, 535, 279, 5821, 6005, 2907, 32521, 74121}},
-{6101, 17, 3187, {1, 1, 3, 15, 3, 21, 29, 193, 71, 993, 1719, 1865, 6135, 7683, 12171, 29275, 14539}},
-{6102, 17, 3189, {1, 1, 1, 7, 7, 13, 1, 61, 315, 431, 1145, 2067, 5745, 1641, 1047, 55111, 129477}},
-{6103, 17, 3190, {1, 1, 5, 1, 21, 43, 115, 193, 153, 573, 1181, 3947, 7809, 11317, 30649, 56891, 47741}},
-{6104, 17, 3203, {1, 1, 5, 7, 19, 15, 61, 239, 109, 683, 395, 2869, 3103, 1531, 12019, 45159, 37525}},
-{6105, 17, 3217, {1, 1, 5, 7, 29, 55, 45, 7, 353, 659, 591, 3371, 5777, 8475, 2743, 47483, 11983}},
-{6106, 17, 3229, {1, 3, 1, 3, 13, 17, 39, 195, 43, 5, 1749, 2559, 5843, 8719, 21421, 58511, 105637}},
-{6107, 17, 3236, {1, 3, 5, 5, 5, 21, 29, 63, 387, 301, 567, 3325, 2109, 403, 23053, 24851, 14493}},
-{6108, 17, 3248, {1, 1, 3, 3, 17, 57, 107, 131, 85, 855, 1101, 3199, 7159, 14739, 4197, 27943, 113009}},
-{6109, 17, 3257, {1, 1, 3, 11, 1, 61, 31, 79, 33, 123, 1509, 507, 6679, 2279, 8465, 37279, 17553}},
-{6110, 17, 3278, {1, 3, 1, 15, 7, 33, 11, 71, 217, 609, 1661, 3437, 5497, 13365, 6247, 649, 26407}},
-{6111, 17, 3283, {1, 1, 3, 1, 19, 45, 49, 125, 5, 455, 1669, 4083, 253, 10101, 27327, 16401, 120399}},
-{6112, 17, 3289, {1, 3, 1, 1, 27, 19, 117, 137, 261, 341, 1697, 457, 7553, 12169, 30049, 49281, 36937}},
-{6113, 17, 3292, {1, 1, 1, 3, 9, 49, 33, 13, 461, 545, 1537, 2623, 883, 10921, 5583, 58997, 114183}},
-{6114, 17, 3302, {1, 1, 7, 9, 29, 53, 29, 165, 205, 989, 1347, 2343, 7505, 7609, 18503, 51677, 105993}},
-{6115, 17, 3316, {1, 1, 1, 13, 1, 29, 59, 121, 297, 659, 1965, 1765, 5255, 10971, 32613, 18763, 41983}},
-{6116, 17, 3328, {1, 3, 7, 11, 21, 41, 19, 47, 125, 485, 475, 2745, 4075, 8101, 31227, 4679, 115473}},
-{6117, 17, 3333, {1, 3, 3, 7, 21, 23, 55, 65, 223, 1001, 317, 1459, 183, 5139, 26553, 41471, 116373}},
-{6118, 17, 3337, {1, 1, 7, 3, 1, 9, 29, 139, 343, 913, 1993, 3139, 3791, 5869, 6057, 23863, 35737}},
-{6119, 17, 3340, {1, 3, 3, 3, 7, 21, 77, 197, 239, 467, 35, 591, 1061, 3417, 31811, 38825, 124981}},
-{6120, 17, 3368, {1, 3, 3, 1, 21, 29, 5, 213, 417, 111, 1681, 1409, 2899, 16233, 1053, 51235, 87767}},
-{6121, 17, 3371, {1, 1, 5, 3, 13, 47, 61, 203, 223, 73, 1947, 3613, 5885, 13567, 7593, 34329, 68597}},
-{6122, 17, 3376, {1, 3, 1, 1, 17, 9, 11, 187, 361, 973, 781, 1835, 1539, 12917, 21725, 48279, 115037}},
-{6123, 17, 3385, {1, 3, 1, 1, 9, 25, 117, 157, 433, 395, 403, 2183, 3327, 5427, 7505, 2673, 77137}},
-{6124, 17, 3386, {1, 1, 7, 15, 31, 15, 27, 155, 441, 837, 1877, 3829, 5139, 16331, 31183, 15803, 95699}},
-{6125, 17, 3393, {1, 1, 7, 15, 5, 51, 77, 179, 289, 727, 1763, 2529, 6715, 3967, 29267, 27293, 67953}},
-{6126, 17, 3399, {1, 3, 7, 13, 7, 3, 3, 17, 311, 547, 1465, 1413, 3937, 2725, 24523, 12321, 109763}},
-{6127, 17, 3405, {1, 3, 5, 15, 9, 5, 87, 135, 281, 97, 2021, 1903, 8007, 10321, 27989, 18993, 110407}},
-{6128, 17, 3414, {1, 1, 1, 13, 25, 61, 89, 107, 233, 823, 1375, 3531, 1757, 1577, 29457, 1461, 17217}},
-{6129, 17, 3433, {1, 1, 1, 13, 17, 17, 27, 193, 485, 759, 145, 3943, 4183, 14119, 11217, 3793, 1935}},
-{6130, 17, 3436, {1, 1, 1, 3, 13, 31, 101, 227, 311, 363, 1925, 1525, 5275, 2385, 15093, 48769, 121189}},
-{6131, 17, 3448, {1, 1, 5, 13, 11, 61, 89, 141, 117, 229, 417, 3935, 7249, 13869, 30591, 62763, 67521}},
-{6132, 17, 3467, {1, 1, 3, 15, 7, 59, 105, 239, 453, 221, 1101, 395, 2031, 8941, 23155, 7077, 125593}},
-{6133, 17, 3469, {1, 1, 1, 11, 7, 55, 99, 31, 305, 371, 1035, 577, 4473, 577, 371, 46093, 69157}},
-{6134, 17, 3472, {1, 3, 1, 9, 9, 33, 35, 245, 95, 47, 1623, 2965, 6849, 7269, 5321, 31641, 73321}},
-{6135, 17, 3477, {1, 1, 1, 15, 21, 61, 65, 65, 159, 151, 625, 2281, 2993, 1311, 29757, 24703, 71029}},
-{6136, 17, 3484, {1, 3, 5, 15, 29, 59, 29, 69, 351, 901, 631, 3501, 7031, 703, 20805, 36437, 94931}},
-{6137, 17, 3494, {1, 3, 7, 1, 21, 11, 19, 125, 237, 807, 1651, 2389, 7347, 11759, 27151, 38669, 965}},
-{6138, 17, 3505, {1, 1, 5, 1, 15, 41, 1, 105, 89, 127, 895, 29, 2339, 15951, 18633, 2781, 67269}},
-{6139, 17, 3515, {1, 1, 5, 15, 25, 7, 3, 33, 375, 447, 203, 2579, 6145, 14015, 9939, 52777, 123181}},
-{6140, 17, 3523, {1, 3, 1, 15, 29, 7, 7, 27, 451, 869, 107, 2457, 5557, 11601, 28957, 36181, 41419}},
-{6141, 17, 3530, {1, 1, 1, 7, 1, 57, 33, 213, 329, 763, 815, 169, 623, 155, 20529, 20603, 73311}},
-{6142, 17, 3543, {1, 3, 5, 7, 25, 21, 7, 217, 159, 89, 1373, 1735, 705, 4093, 13083, 3855, 55875}},
-{6143, 17, 3559, {1, 3, 1, 1, 29, 33, 105, 127, 95, 543, 235, 67, 691, 5015, 22139, 18251, 89945}},
-{6144, 17, 3568, {1, 1, 3, 11, 27, 53, 105, 83, 337, 331, 1571, 1145, 745, 1845, 17881, 17697, 88139}},
-{6145, 17, 3577, {1, 3, 7, 15, 19, 37, 119, 35, 35, 463, 1925, 1665, 673, 12193, 12137, 62371, 10957}},
-{6146, 17, 3578, {1, 3, 3, 3, 19, 21, 113, 29, 459, 467, 623, 2661, 857, 16265, 27509, 46555, 18867}},
-{6147, 17, 3594, {1, 3, 7, 5, 17, 49, 123, 41, 85, 673, 41, 1871, 7649, 8687, 28269, 64423, 93675}},
-{6148, 17, 3601, {1, 3, 3, 3, 7, 23, 101, 171, 181, 527, 65, 2387, 6629, 6089, 17387, 46551, 36143}},
-{6149, 17, 3607, {1, 1, 5, 1, 13, 51, 21, 251, 139, 429, 1993, 3767, 1089, 5459, 19407, 41747, 41033}},
-{6150, 17, 3608, {1, 1, 1, 11, 15, 9, 81, 91, 73, 969, 1513, 2067, 7959, 2605, 26641, 37631, 124571}},
-{6151, 17, 3620, {1, 1, 3, 15, 29, 15, 5, 57, 247, 901, 527, 3325, 5859, 11299, 9871, 63947, 125247}},
-{6152, 17, 3629, {1, 3, 1, 5, 1, 35, 75, 21, 307, 43, 1111, 3299, 1647, 3585, 31045, 18217, 95169}},
-{6153, 17, 3644, {1, 3, 1, 7, 23, 35, 11, 103, 3, 461, 1915, 4019, 453, 13111, 26941, 43091, 22917}},
-{6154, 17, 3656, {1, 1, 5, 5, 1, 61, 121, 167, 475, 5, 1749, 887, 2237, 5055, 7077, 29453, 17691}},
-{6155, 17, 3664, {1, 3, 3, 15, 15, 15, 9, 15, 171, 787, 1965, 577, 4507, 7325, 20901, 8557, 111909}},
-{6156, 17, 3670, {1, 3, 5, 1, 27, 15, 123, 141, 63, 55, 599, 4095, 1245, 13919, 27485, 49977, 74551}},
-{6157, 17, 3680, {1, 3, 5, 9, 21, 61, 79, 119, 7, 573, 1923, 2775, 3127, 12689, 12135, 53429, 130163}},
-{6158, 17, 3685, {1, 3, 3, 13, 27, 41, 67, 249, 447, 277, 311, 775, 8187, 10161, 12953, 22885, 121247}},
-{6159, 17, 3686, {1, 3, 5, 9, 21, 55, 115, 65, 45, 395, 481, 2063, 6493, 4199, 19219, 27119, 62255}},
-{6160, 17, 3695, {1, 1, 3, 13, 7, 41, 3, 127, 383, 923, 1725, 1033, 7731, 11971, 3089, 46459, 98369}},
-{6161, 17, 3698, {1, 1, 3, 11, 13, 39, 39, 149, 309, 311, 1491, 807, 2109, 363, 14637, 65429, 124731}},
-{6162, 17, 3703, {1, 1, 7, 13, 13, 35, 67, 81, 493, 859, 1177, 237, 4605, 15319, 16669, 16661, 21385}},
-{6163, 17, 3710, {1, 1, 3, 7, 7, 39, 57, 103, 239, 753, 221, 1611, 1557, 13317, 27453, 10245, 33839}},
-{6164, 17, 3714, {1, 1, 5, 13, 27, 53, 97, 41, 123, 253, 535, 1839, 5827, 7587, 1261, 20313, 65961}},
-{6165, 17, 3726, {1, 1, 7, 1, 11, 47, 93, 135, 223, 591, 1087, 3329, 3293, 14207, 6187, 54789, 23781}},
-{6166, 17, 3731, {1, 3, 7, 7, 25, 21, 97, 105, 269, 515, 1805, 3711, 3295, 7307, 21065, 65205, 116969}},
-{6167, 17, 3733, {1, 3, 1, 11, 25, 37, 21, 89, 109, 581, 1055, 2393, 1291, 1115, 25545, 36383, 93605}},
-{6168, 17, 3737, {1, 3, 7, 1, 27, 13, 113, 11, 395, 473, 943, 4045, 5507, 15051, 25203, 2971, 31961}},
-{6169, 17, 3756, {1, 1, 5, 5, 27, 35, 57, 219, 67, 949, 659, 203, 5235, 6509, 13731, 61533, 54963}},
-{6170, 17, 3759, {1, 3, 1, 1, 15, 39, 85, 13, 347, 99, 25, 3595, 3081, 13617, 14373, 58909, 102181}},
-{6171, 17, 3767, {1, 1, 7, 13, 3, 25, 97, 91, 287, 389, 665, 2981, 2301, 12625, 4495, 57489, 68677}},
-{6172, 17, 3776, {1, 1, 5, 1, 15, 57, 77, 55, 299, 713, 1457, 3699, 2807, 5549, 467, 47367, 8163}},
-{6173, 17, 3785, {1, 1, 7, 3, 23, 45, 91, 251, 501, 193, 1121, 2359, 4781, 12797, 13713, 55171, 927}},
-{6174, 17, 3793, {1, 3, 3, 7, 7, 31, 87, 163, 249, 163, 937, 1293, 4827, 10299, 31935, 58787, 80589}},
-{6175, 17, 3812, {1, 3, 1, 9, 7, 1, 73, 65, 475, 791, 1429, 3319, 7149, 433, 10373, 44061, 121195}},
-{6176, 17, 3815, {1, 1, 5, 9, 9, 61, 27, 249, 435, 437, 1329, 2163, 5859, 13663, 623, 55569, 94283}},
-{6177, 17, 3824, {1, 3, 7, 11, 1, 29, 117, 195, 399, 999, 1705, 1325, 6043, 9823, 27335, 30377, 16627}},
-{6178, 17, 3844, {1, 1, 1, 15, 5, 11, 63, 185, 15, 741, 1061, 2961, 3455, 5, 26587, 54081, 18107}},
-{6179, 17, 3859, {1, 1, 5, 7, 29, 57, 17, 203, 501, 177, 49, 2773, 8069, 12513, 14437, 64489, 58661}},
-{6180, 17, 3866, {1, 3, 3, 9, 11, 23, 121, 3, 415, 447, 1773, 135, 5901, 4951, 2683, 437, 126251}},
-{6181, 17, 3872, {1, 3, 3, 1, 7, 23, 17, 23, 115, 591, 1075, 3133, 49, 15183, 10615, 37857, 122609}},
-{6182, 17, 3884, {1, 1, 3, 3, 13, 49, 63, 37, 275, 763, 1135, 2913, 1563, 11037, 6693, 18799, 32089}},
-{6183, 17, 3889, {1, 3, 5, 11, 7, 29, 59, 45, 227, 941, 1947, 2733, 797, 10485, 7071, 14741, 11451}},
-{6184, 17, 3899, {1, 1, 1, 9, 21, 19, 77, 97, 75, 991, 187, 1003, 5619, 11013, 3931, 19907, 79723}},
-{6185, 17, 3902, {1, 1, 7, 13, 1, 57, 61, 177, 443, 227, 1347, 2665, 2011, 12329, 14137, 37795, 63331}},
-{6186, 17, 3909, {1, 3, 3, 9, 31, 59, 87, 93, 485, 635, 901, 1845, 6153, 10797, 1289, 8989, 41717}},
-{6187, 17, 3913, {1, 1, 1, 1, 3, 7, 85, 17, 67, 309, 1891, 435, 303, 8011, 32127, 54309, 21457}},
-{6188, 17, 3933, {1, 3, 7, 1, 29, 27, 41, 239, 293, 717, 1331, 917, 6145, 7131, 28199, 35093, 103683}},
-{6189, 17, 3938, {1, 3, 7, 3, 21, 63, 65, 233, 257, 789, 1095, 505, 4557, 16259, 7397, 24815, 89529}},
-{6190, 17, 3949, {1, 3, 3, 11, 29, 41, 55, 17, 335, 715, 779, 2121, 6393, 8887, 32753, 45647, 82665}},
-{6191, 17, 3952, {1, 1, 1, 11, 27, 47, 71, 13, 141, 283, 967, 3359, 4309, 6661, 20481, 23175, 50835}},
-{6192, 17, 3980, {1, 3, 3, 7, 3, 25, 19, 241, 409, 573, 1565, 3355, 1307, 12205, 18017, 8271, 117007}},
-{6193, 17, 3991, {1, 3, 3, 9, 21, 39, 21, 253, 439, 963, 341, 3637, 2275, 1845, 11015, 481, 83369}},
-{6194, 17, 3992, {1, 3, 7, 9, 31, 29, 29, 163, 111, 983, 571, 713, 2621, 11569, 13341, 28341, 130381}},
-{6195, 17, 4002, {1, 3, 7, 7, 11, 35, 89, 49, 81, 115, 113, 1857, 3527, 14819, 6909, 14659, 23557}},
-{6196, 17, 4008, {1, 3, 3, 15, 29, 41, 85, 241, 317, 737, 213, 1667, 5789, 16321, 13991, 36165, 124151}},
-{6197, 17, 4011, {1, 3, 1, 3, 31, 1, 75, 99, 495, 241, 1499, 1535, 2033, 2135, 6699, 58893, 37031}},
-{6198, 17, 4016, {1, 1, 7, 9, 25, 15, 101, 23, 477, 563, 1691, 2655, 2321, 2323, 4255, 22055, 99661}},
-{6199, 17, 4034, {1, 3, 7, 5, 7, 7, 49, 221, 51, 83, 279, 2205, 2939, 2119, 14073, 32839, 108075}},
-{6200, 17, 4036, {1, 3, 5, 11, 17, 39, 3, 127, 87, 501, 799, 401, 4439, 9895, 13017, 64975, 67177}},
-{6201, 17, 4063, {1, 3, 3, 9, 17, 41, 59, 95, 283, 309, 83, 1293, 6385, 5783, 30115, 33997, 12531}},
-{6202, 17, 4067, {1, 3, 5, 3, 7, 31, 69, 171, 225, 409, 1237, 3343, 835, 8039, 16723, 37203, 129047}},
-{6203, 17, 4073, {1, 3, 3, 15, 17, 23, 107, 1, 105, 135, 1245, 993, 4101, 7325, 7425, 17379, 98121}},
-{6204, 17, 4082, {1, 1, 7, 9, 27, 5, 67, 111, 75, 531, 243, 2239, 2527, 4513, 27059, 40533, 88169}},
-{6205, 17, 4091, {1, 3, 5, 7, 21, 63, 57, 15, 75, 679, 1729, 1845, 6259, 8531, 18691, 49321, 101599}},
-{6206, 17, 4093, {1, 1, 5, 9, 3, 35, 7, 201, 351, 885, 669, 2339, 5009, 279, 26469, 54597, 67933}},
-{6207, 17, 4101, {1, 3, 5, 13, 27, 5, 85, 161, 141, 733, 1017, 2021, 6951, 15595, 21817, 17243, 88607}},
-{6208, 17, 4113, {1, 3, 5, 1, 11, 31, 117, 97, 175, 629, 995, 1207, 2941, 5825, 5319, 48191, 9505}},
-{6209, 17, 4120, {1, 3, 3, 7, 25, 39, 45, 79, 21, 607, 1593, 1749, 7951, 10425, 17491, 16617, 56903}},
-{6210, 17, 4125, {1, 1, 1, 5, 15, 41, 107, 115, 79, 693, 919, 3513, 6793, 6541, 5545, 58583, 27963}},
-{6211, 17, 4126, {1, 3, 7, 11, 21, 19, 123, 1, 441, 531, 359, 2117, 2465, 11389, 13489, 32755, 4577}},
-{6212, 17, 4139, {1, 1, 5, 13, 7, 7, 7, 127, 201, 377, 1423, 269, 2611, 3339, 19153, 25659, 33069}},
-{6213, 17, 4142, {1, 3, 7, 1, 13, 35, 45, 5, 313, 739, 1779, 2983, 1815, 8817, 14239, 3921, 57975}},
-{6214, 17, 4144, {1, 3, 1, 11, 9, 39, 33, 111, 39, 255, 159, 2345, 2193, 11475, 12841, 47579, 90309}},
-{6215, 17, 4147, {1, 1, 1, 3, 27, 49, 85, 157, 243, 247, 1473, 323, 4631, 1787, 15193, 5533, 104999}},
-{6216, 17, 4153, {1, 1, 7, 9, 11, 29, 23, 219, 57, 339, 1797, 409, 6025, 10569, 27409, 15147, 130281}},
-{6217, 17, 4154, {1, 1, 7, 1, 31, 31, 113, 229, 63, 877, 319, 2655, 3335, 7743, 19593, 10089, 28215}},
-{6218, 17, 4164, {1, 1, 3, 11, 23, 3, 71, 235, 329, 751, 159, 2579, 5363, 12681, 20233, 53855, 16407}},
-{6219, 17, 4174, {1, 1, 5, 1, 7, 61, 21, 235, 379, 849, 61, 2969, 6399, 2655, 21635, 16955, 58675}},
-{6220, 17, 4182, {1, 3, 7, 7, 29, 15, 5, 11, 143, 699, 1875, 2115, 6633, 6195, 5829, 53633, 111221}},
-{6221, 17, 4185, {1, 3, 7, 11, 19, 41, 17, 219, 483, 829, 1233, 3183, 6283, 2363, 25245, 63075, 82733}},
-{6222, 17, 4188, {1, 3, 7, 13, 21, 17, 1, 207, 443, 575, 521, 2585, 6875, 14871, 14739, 10211, 127435}},
-{6223, 17, 4191, {1, 3, 7, 7, 15, 39, 99, 197, 219, 259, 1723, 3737, 6625, 849, 887, 41293, 53825}},
-{6224, 17, 4195, {1, 3, 3, 3, 5, 3, 75, 155, 189, 935, 85, 2273, 1375, 4217, 10709, 58047, 81689}},
-{6225, 17, 4219, {1, 3, 5, 5, 27, 27, 107, 229, 179, 887, 91, 421, 7313, 6495, 451, 43859, 40033}},
-{6226, 17, 4225, {1, 3, 5, 11, 25, 49, 121, 73, 169, 311, 1387, 1037, 6519, 9317, 26975, 50627, 46805}},
-{6227, 17, 4228, {1, 1, 5, 11, 17, 21, 19, 125, 387, 697, 1017, 1759, 7295, 9869, 28241, 9367, 119255}},
-{6228, 17, 4232, {1, 1, 7, 5, 29, 27, 87, 187, 95, 625, 933, 1751, 5253, 313, 30841, 16349, 67347}},
-{6229, 17, 4246, {1, 1, 3, 3, 15, 51, 23, 101, 183, 267, 243, 711, 983, 12461, 17801, 1429, 47273}},
-{6230, 17, 4255, {1, 1, 1, 3, 17, 3, 73, 67, 49, 449, 879, 2559, 401, 11983, 13697, 12023, 78855}},
-{6231, 17, 4274, {1, 3, 7, 15, 25, 25, 43, 81, 141, 161, 595, 621, 1165, 10869, 22875, 6741, 90017}},
-{6232, 17, 4283, {1, 3, 5, 11, 13, 57, 53, 219, 145, 937, 769, 1961, 4725, 3335, 12623, 8335, 46305}},
-{6233, 17, 4286, {1, 1, 3, 5, 7, 39, 19, 101, 313, 583, 483, 2515, 125, 5211, 2559, 11937, 126717}},
-{6234, 17, 4306, {1, 3, 1, 7, 7, 1, 117, 49, 231, 133, 381, 697, 927, 8263, 26529, 64881, 25059}},
-{6235, 17, 4311, {1, 1, 1, 15, 11, 25, 77, 149, 233, 215, 1239, 3045, 99, 11183, 30279, 32271, 100943}},
-{6236, 17, 4317, {1, 1, 5, 7, 31, 25, 1, 51, 221, 607, 1733, 2145, 6765, 7011, 16927, 29257, 2445}},
-{6237, 17, 4321, {1, 3, 5, 1, 19, 23, 123, 93, 381, 295, 765, 2335, 8025, 14003, 4801, 54243, 57297}},
-{6238, 17, 4324, {1, 1, 7, 9, 9, 31, 63, 191, 495, 527, 251, 2119, 1663, 209, 7445, 1441, 4075}},
-{6239, 17, 4331, {1, 3, 5, 5, 13, 17, 97, 79, 369, 55, 677, 2031, 7315, 4769, 31659, 21975, 22061}},
-{6240, 17, 4333, {1, 3, 3, 7, 3, 63, 121, 243, 39, 917, 1917, 297, 7241, 1565, 31675, 14443, 67239}},
-{6241, 17, 4359, {1, 3, 7, 1, 13, 25, 51, 65, 145, 475, 1853, 4023, 5121, 14411, 15993, 42165, 13615}},
-{6242, 17, 4360, {1, 3, 3, 1, 3, 51, 75, 29, 169, 311, 1309, 2929, 7669, 1507, 14605, 32667, 103861}},
-{6243, 17, 4368, {1, 3, 7, 1, 23, 37, 89, 211, 137, 495, 1469, 3425, 1167, 12429, 27301, 46857, 83007}},
-{6244, 17, 4373, {1, 3, 7, 7, 27, 37, 33, 129, 73, 23, 761, 119, 6217, 4749, 20835, 47477, 33665}},
-{6245, 17, 4389, {1, 1, 3, 5, 29, 35, 79, 21, 183, 933, 43, 3149, 5273, 12159, 20695, 5387, 23569}},
-{6246, 17, 4394, {1, 1, 5, 5, 3, 11, 57, 205, 349, 657, 1509, 3693, 5495, 11865, 13861, 62215, 94141}},
-{6247, 17, 4413, {1, 3, 1, 7, 17, 43, 117, 119, 75, 849, 1247, 643, 2691, 2289, 9759, 18683, 68649}},
-{6248, 17, 4422, {1, 1, 1, 15, 5, 55, 89, 177, 427, 701, 735, 2993, 5293, 15395, 567, 5501, 102393}},
-{6249, 17, 4431, {1, 3, 3, 15, 5, 37, 73, 111, 9, 141, 407, 1579, 6691, 11843, 6377, 64181, 97347}},
-{6250, 17, 4436, {1, 1, 5, 1, 9, 17, 71, 127, 285, 929, 1243, 2605, 359, 14589, 32603, 39879, 115901}},
-{6251, 17, 4440, {1, 3, 7, 15, 3, 27, 91, 121, 47, 631, 1589, 385, 5997, 14077, 21285, 33895, 36985}},
-{6252, 17, 4445, {1, 3, 3, 9, 1, 47, 89, 79, 213, 27, 547, 1703, 4035, 13205, 4341, 21895, 34247}},
-{6253, 17, 4452, {1, 3, 5, 7, 9, 9, 47, 89, 231, 857, 297, 2949, 2715, 1275, 14427, 20227, 21569}},
-{6254, 17, 4462, {1, 3, 1, 3, 15, 57, 61, 183, 377, 477, 1135, 1729, 2863, 8607, 29241, 34983, 84443}},
-{6255, 17, 4469, {1, 1, 7, 7, 5, 53, 91, 149, 71, 41, 1025, 3945, 3989, 15853, 20903, 26943, 99841}},
-{6256, 17, 4470, {1, 3, 3, 3, 29, 21, 59, 217, 483, 257, 331, 657, 2935, 945, 9821, 42501, 98087}},
-{6257, 17, 4473, {1, 3, 5, 3, 17, 39, 123, 103, 109, 957, 853, 3821, 555, 10869, 27673, 38315, 83105}},
-{6258, 17, 4479, {1, 3, 1, 3, 27, 7, 97, 57, 429, 53, 1791, 1405, 4113, 8435, 12845, 21567, 91559}},
-{6259, 17, 4480, {1, 3, 3, 1, 17, 61, 125, 77, 225, 395, 945, 3213, 1363, 15947, 27049, 4389, 64037}},
-{6260, 17, 4483, {1, 1, 1, 3, 15, 51, 15, 189, 449, 989, 939, 985, 6929, 13779, 25011, 22277, 72543}},
-{6261, 17, 4489, {1, 3, 3, 1, 25, 53, 5, 219, 195, 703, 163, 1405, 821, 6797, 14329, 1675, 96653}},
-{6262, 17, 4503, {1, 1, 7, 13, 7, 1, 45, 135, 369, 125, 711, 2509, 131, 13663, 29769, 19497, 116779}},
-{6263, 17, 4519, {1, 1, 7, 15, 23, 25, 7, 225, 435, 835, 1981, 2537, 5727, 15961, 30089, 58905, 100339}},
-{6264, 17, 4520, {1, 3, 7, 3, 19, 9, 79, 63, 371, 419, 1357, 3649, 7987, 14541, 6631, 50555, 84217}},
-{6265, 17, 4525, {1, 3, 3, 9, 7, 61, 11, 157, 99, 95, 945, 2803, 1703, 117, 12891, 21817, 84259}},
-{6266, 17, 4526, {1, 3, 7, 7, 25, 37, 111, 99, 65, 599, 1313, 2557, 5489, 3625, 7429, 19309, 78111}},
-{6267, 17, 4533, {1, 3, 1, 1, 19, 15, 85, 253, 347, 315, 1349, 983, 2507, 4155, 15311, 43535, 101409}},
-{6268, 17, 4552, {1, 3, 3, 3, 1, 55, 3, 57, 375, 107, 177, 1673, 6871, 7137, 10297, 65363, 42293}},
-{6269, 17, 4581, {1, 1, 1, 3, 9, 5, 83, 45, 139, 893, 63, 2859, 6333, 15591, 18491, 26387, 25573}},
-{6270, 17, 4585, {1, 1, 7, 15, 1, 39, 113, 127, 503, 617, 1367, 1855, 185, 4233, 5787, 8265, 42097}},
-{6271, 17, 4591, {1, 1, 3, 11, 11, 41, 119, 165, 331, 625, 81, 2495, 7247, 9139, 15269, 31447, 128425}},
-{6272, 17, 4594, {1, 1, 5, 5, 17, 35, 39, 1, 91, 563, 1841, 2975, 1233, 3837, 22145, 36719, 104503}},
-{6273, 17, 4596, {1, 1, 7, 3, 23, 35, 77, 69, 271, 487, 921, 2597, 8011, 13037, 6001, 20519, 32673}},
-{6274, 17, 4599, {1, 1, 1, 1, 29, 17, 11, 145, 473, 877, 813, 727, 6805, 3563, 13371, 22169, 17239}},
-{6275, 17, 4612, {1, 1, 1, 13, 17, 13, 1, 125, 313, 423, 1079, 2401, 2325, 2219, 24071, 25613, 34163}},
-{6276, 17, 4621, {1, 1, 5, 7, 29, 33, 53, 215, 11, 555, 555, 1965, 3643, 5433, 12923, 59655, 25339}},
-{6277, 17, 4630, {1, 3, 3, 3, 23, 37, 119, 117, 459, 359, 1849, 1019, 433, 15391, 5625, 52649, 81313}},
-{6278, 17, 4636, {1, 3, 3, 1, 21, 31, 121, 161, 113, 667, 863, 105, 3805, 14459, 28235, 24543, 89755}},
-{6279, 17, 4640, {1, 1, 5, 15, 17, 37, 15, 111, 511, 477, 611, 955, 2591, 16137, 14179, 30995, 129575}},
-{6280, 17, 4649, {1, 3, 3, 3, 21, 49, 25, 37, 287, 263, 851, 1015, 8133, 9429, 10959, 64483, 82533}},
-{6281, 17, 4650, {1, 1, 5, 1, 25, 19, 49, 159, 155, 443, 975, 1413, 321, 7871, 22935, 57303, 124027}},
-{6282, 17, 4660, {1, 3, 1, 1, 19, 45, 47, 89, 409, 509, 1249, 2445, 2053, 3781, 7517, 61869, 125137}},
-{6283, 17, 4677, {1, 1, 5, 13, 27, 57, 45, 43, 361, 329, 1321, 771, 4665, 12245, 18993, 15121, 127485}},
-{6284, 17, 4687, {1, 3, 3, 7, 3, 41, 127, 75, 485, 821, 497, 2649, 6423, 12419, 31421, 9441, 63645}},
-{6285, 17, 4696, {1, 1, 3, 5, 19, 61, 91, 35, 311, 287, 449, 3955, 5805, 5631, 25613, 55409, 104545}},
-{6286, 17, 4701, {1, 3, 7, 11, 27, 19, 27, 53, 19, 35, 1687, 3923, 3379, 10435, 15053, 12343, 89077}},
-{6287, 17, 4705, {1, 3, 5, 13, 31, 41, 15, 239, 349, 533, 1771, 737, 6503, 14355, 18781, 27805, 79049}},
-{6288, 17, 4706, {1, 3, 1, 3, 13, 11, 69, 227, 169, 873, 533, 2217, 1047, 12415, 12271, 22447, 14163}},
-{6289, 17, 4711, {1, 1, 3, 9, 7, 31, 23, 155, 133, 305, 1569, 521, 201, 10339, 16999, 29163, 32817}},
-{6290, 17, 4720, {1, 1, 1, 5, 31, 57, 43, 223, 121, 803, 357, 1855, 4321, 10245, 25725, 2543, 47395}},
-{6291, 17, 4723, {1, 3, 5, 9, 3, 5, 47, 189, 217, 899, 1455, 691, 1277, 7861, 3627, 14895, 41109}},
-{6292, 17, 4732, {1, 3, 7, 3, 29, 9, 37, 63, 453, 709, 921, 771, 8069, 239, 22639, 59937, 10635}},
-{6293, 17, 4736, {1, 3, 7, 1, 11, 51, 79, 131, 225, 757, 549, 1605, 3921, 1849, 16307, 29809, 120597}},
-{6294, 17, 4742, {1, 3, 7, 7, 1, 45, 33, 185, 23, 881, 1941, 4093, 4741, 11633, 2059, 32007, 11103}},
-{6295, 17, 4748, {1, 3, 5, 11, 17, 21, 43, 205, 363, 559, 697, 4057, 631, 6697, 883, 61705, 102791}},
-{6296, 17, 4754, {1, 1, 7, 9, 29, 35, 109, 85, 373, 321, 415, 2969, 6163, 6999, 9999, 36435, 125267}},
-{6297, 17, 4759, {1, 1, 7, 11, 25, 9, 113, 91, 337, 889, 947, 2093, 5289, 1367, 13297, 36155, 21825}},
-{6298, 17, 4769, {1, 1, 3, 9, 17, 25, 35, 79, 275, 687, 335, 1181, 7327, 3729, 1561, 27441, 114355}},
-{6299, 17, 4787, {1, 3, 3, 11, 25, 41, 27, 89, 115, 361, 871, 1497, 5735, 6365, 1737, 14277, 63847}},
-{6300, 17, 4807, {1, 3, 7, 7, 1, 63, 31, 73, 289, 67, 277, 1821, 4883, 10795, 11755, 15471, 105871}},
-{6301, 17, 4814, {1, 3, 7, 9, 23, 17, 37, 179, 409, 957, 373, 2393, 2363, 6735, 28737, 41927, 115735}},
-{6302, 17, 4837, {1, 1, 3, 9, 15, 43, 111, 61, 455, 181, 1643, 3063, 4311, 13705, 29993, 21731, 25243}},
-{6303, 17, 4867, {1, 1, 1, 15, 13, 13, 69, 187, 91, 395, 209, 3477, 4649, 7727, 30557, 14719, 1953}},
-{6304, 17, 4873, {1, 1, 1, 15, 9, 39, 119, 193, 459, 135, 567, 25, 4583, 8401, 22161, 14771, 74165}},
-{6305, 17, 4879, {1, 1, 3, 7, 5, 39, 77, 149, 293, 585, 1245, 3615, 357, 11613, 13865, 40227, 41023}},
-{6306, 17, 4884, {1, 1, 7, 9, 9, 37, 5, 177, 121, 181, 771, 733, 7683, 4855, 13629, 8349, 46137}},
-{6307, 17, 4898, {1, 1, 3, 13, 3, 37, 73, 69, 281, 109, 563, 1427, 5127, 8957, 16749, 41489, 49531}},
-{6308, 17, 4907, {1, 1, 7, 11, 29, 63, 79, 127, 95, 809, 1175, 1567, 6353, 7505, 26551, 5073, 53733}},
-{6309, 17, 4910, {1, 1, 1, 5, 25, 41, 59, 103, 59, 365, 1111, 3909, 3749, 14889, 3639, 10435, 45407}},
-{6310, 17, 4918, {1, 1, 1, 5, 3, 61, 93, 199, 97, 779, 67, 241, 6197, 6785, 16869, 7573, 46745}},
-{6311, 17, 4924, {1, 1, 5, 9, 27, 29, 21, 69, 165, 661, 1245, 1265, 2979, 9685, 17781, 23329, 48029}},
-{6312, 17, 4953, {1, 1, 1, 7, 7, 23, 39, 197, 169, 561, 499, 2197, 4371, 157, 6837, 44635, 94861}},
-{6313, 17, 4956, {1, 1, 5, 13, 7, 5, 9, 207, 321, 243, 899, 2967, 3553, 15413, 8961, 55039, 6459}},
-{6314, 17, 4965, {1, 3, 5, 3, 13, 25, 33, 145, 45, 979, 33, 2211, 7003, 11147, 11327, 55151, 30697}},
-{6315, 17, 4966, {1, 1, 3, 13, 7, 51, 25, 229, 231, 115, 1815, 3867, 1533, 15259, 8067, 64803, 87535}},
-{6316, 17, 4970, {1, 1, 3, 3, 21, 51, 101, 49, 227, 393, 1659, 955, 545, 7395, 31563, 5499, 130541}},
-{6317, 17, 4972, {1, 3, 1, 1, 21, 41, 57, 161, 269, 35, 893, 1817, 857, 7027, 973, 12529, 46659}},
-{6318, 17, 4983, {1, 1, 3, 7, 17, 35, 23, 29, 335, 725, 453, 1051, 6019, 7595, 29451, 1853, 116615}},
-{6319, 17, 4989, {1, 3, 3, 1, 3, 55, 73, 187, 213, 329, 997, 703, 5829, 7903, 1081, 33359, 119123}},
-{6320, 17, 4994, {1, 3, 3, 15, 29, 55, 15, 17, 245, 117, 1735, 767, 4457, 8803, 17621, 26925, 72487}},
-{6321, 17, 5000, {1, 3, 5, 3, 25, 7, 119, 139, 159, 199, 317, 3875, 8115, 7581, 29239, 50225, 48459}},
-{6322, 17, 5005, {1, 3, 7, 11, 11, 41, 107, 225, 395, 545, 259, 2379, 6709, 11669, 14545, 43663, 69979}},
-{6323, 17, 5014, {1, 3, 5, 13, 23, 45, 73, 137, 447, 305, 117, 2659, 7989, 233, 31991, 60495, 571}},
-{6324, 17, 5018, {1, 3, 7, 9, 1, 37, 31, 1, 433, 701, 159, 3811, 4529, 6697, 7121, 31107, 61555}},
-{6325, 17, 5023, {1, 3, 5, 5, 13, 21, 81, 63, 95, 741, 1189, 1567, 1223, 12371, 28435, 10537, 53785}},
-{6326, 17, 5039, {1, 1, 1, 11, 17, 31, 67, 121, 281, 593, 561, 1759, 387, 9639, 28595, 22473, 4935}},
-{6327, 17, 5053, {1, 3, 7, 3, 5, 43, 59, 151, 351, 263, 297, 423, 1681, 3785, 15171, 7145, 57531}},
-{6328, 17, 5054, {1, 3, 7, 15, 9, 35, 105, 189, 261, 175, 1669, 1289, 5401, 12801, 19585, 48169, 93195}},
-{6329, 17, 5061, {1, 1, 7, 1, 31, 41, 23, 237, 151, 549, 1079, 2933, 5509, 15593, 1791, 15757, 44607}},
-{6330, 17, 5065, {1, 1, 1, 3, 29, 1, 59, 115, 13, 999, 1179, 3561, 2749, 10059, 12861, 6797, 11793}},
-{6331, 17, 5080, {1, 3, 3, 7, 11, 5, 23, 217, 101, 775, 1497, 4047, 2427, 5117, 9683, 28895, 27557}},
-{6332, 17, 5083, {1, 3, 7, 5, 31, 55, 99, 65, 55, 587, 1271, 2277, 7947, 12995, 13149, 4463, 37625}},
-{6333, 17, 5107, {1, 1, 7, 11, 3, 63, 23, 191, 125, 365, 1153, 2657, 6763, 4557, 21643, 26885, 36753}},
-{6334, 17, 5119, {1, 1, 1, 15, 25, 15, 111, 135, 507, 745, 1947, 2545, 4329, 14325, 8187, 52021, 63401}},
-{6335, 17, 5146, {1, 1, 3, 3, 27, 25, 19, 211, 393, 467, 1015, 2495, 7135, 495, 10385, 26961, 49325}},
-{6336, 17, 5151, {1, 1, 3, 5, 15, 35, 3, 203, 337, 337, 703, 1989, 6869, 6055, 21095, 4749, 125669}},
-{6337, 17, 5152, {1, 1, 5, 1, 31, 39, 57, 101, 419, 717, 1489, 199, 5729, 3003, 2607, 64593, 11515}},
-{6338, 17, 5155, {1, 3, 7, 13, 15, 3, 33, 61, 17, 433, 1097, 957, 5351, 3043, 3679, 44881, 126909}},
-{6339, 17, 5169, {1, 1, 3, 11, 5, 1, 121, 175, 119, 367, 399, 2527, 2157, 2667, 31069, 24797, 119621}},
-{6340, 17, 5170, {1, 3, 1, 7, 27, 47, 115, 229, 455, 775, 73, 837, 1181, 3457, 4057, 33907, 67151}},
-{6341, 17, 5176, {1, 3, 3, 1, 7, 51, 71, 177, 463, 921, 393, 3137, 1225, 5709, 303, 20597, 77581}},
-{6342, 17, 5179, {1, 3, 5, 3, 31, 1, 93, 53, 177, 433, 1471, 2191, 4471, 9211, 19397, 57727, 60367}},
-{6343, 17, 5182, {1, 1, 3, 11, 29, 55, 121, 89, 67, 869, 1631, 2657, 7357, 7159, 22449, 16357, 20077}},
-{6344, 17, 5189, {1, 3, 7, 15, 11, 39, 127, 63, 211, 359, 971, 1221, 1909, 9963, 7827, 60923, 98495}},
-{6345, 17, 5193, {1, 1, 7, 9, 23, 47, 47, 85, 307, 471, 1287, 3825, 5451, 15151, 15647, 63043, 92443}},
-{6346, 17, 5196, {1, 3, 7, 5, 19, 11, 11, 27, 307, 695, 99, 1037, 1997, 13673, 591, 8183, 82197}},
-{6347, 17, 5204, {1, 3, 5, 5, 3, 53, 109, 227, 503, 855, 1269, 3903, 5049, 10647, 21751, 58707, 78311}},
-{6348, 17, 5207, {1, 1, 3, 11, 31, 3, 51, 211, 285, 919, 487, 3393, 3463, 2271, 8053, 56791, 33763}},
-{6349, 17, 5211, {1, 3, 3, 5, 21, 15, 5, 5, 327, 809, 915, 1365, 7323, 4247, 31603, 26261, 80389}},
-{6350, 17, 5220, {1, 3, 7, 7, 15, 33, 31, 221, 291, 815, 1307, 929, 3249, 14573, 13613, 59509, 59741}},
-{6351, 17, 5258, {1, 3, 7, 15, 19, 41, 61, 27, 353, 965, 1901, 87, 2669, 12757, 29723, 47165, 16521}},
-{6352, 17, 5265, {1, 3, 5, 3, 11, 43, 97, 215, 361, 901, 1425, 4063, 5327, 14119, 457, 43145, 107401}},
-{6353, 17, 5271, {1, 1, 3, 15, 19, 37, 101, 69, 131, 927, 897, 477, 7641, 4299, 21213, 26017, 123801}},
-{6354, 17, 5277, {1, 3, 7, 7, 19, 5, 11, 51, 277, 985, 1071, 3437, 6595, 9547, 11855, 64249, 30957}},
-{6355, 17, 5278, {1, 1, 7, 9, 21, 41, 89, 113, 61, 235, 685, 1419, 7619, 9863, 21221, 28685, 53409}},
-{6356, 17, 5282, {1, 1, 1, 1, 27, 1, 19, 3, 473, 827, 269, 1659, 2621, 12347, 13359, 64687, 99293}},
-{6357, 17, 5296, {1, 3, 7, 7, 29, 37, 61, 49, 215, 883, 625, 2671, 3743, 4517, 2075, 64865, 58611}},
-{6358, 17, 5299, {1, 3, 3, 7, 15, 11, 35, 37, 255, 781, 613, 3587, 7643, 13081, 32467, 14427, 15235}},
-{6359, 17, 5319, {1, 1, 1, 11, 31, 47, 107, 65, 489, 377, 425, 3453, 2901, 9999, 7687, 13311, 103947}},
-{6360, 17, 5328, {1, 3, 3, 7, 9, 17, 7, 107, 33, 545, 407, 3335, 7563, 14315, 32725, 8483, 69093}},
-{6361, 17, 5343, {1, 1, 1, 5, 17, 9, 87, 229, 417, 769, 423, 569, 7073, 8705, 24487, 63743, 69807}},
-{6362, 17, 5353, {1, 3, 1, 9, 1, 29, 75, 25, 483, 259, 1941, 1533, 8147, 14127, 24087, 37475, 130961}},
-{6363, 17, 5364, {1, 3, 3, 11, 15, 15, 51, 45, 215, 283, 1687, 185, 4521, 12205, 13041, 33283, 77007}},
-{6364, 17, 5368, {1, 1, 3, 3, 5, 47, 107, 67, 325, 87, 1831, 2845, 1645, 1741, 10811, 8983, 58515}},
-{6365, 17, 5379, {1, 3, 1, 13, 19, 17, 1, 151, 411, 915, 1739, 3781, 4939, 15767, 25897, 7205, 17285}},
-{6366, 17, 5381, {1, 3, 5, 15, 19, 1, 125, 33, 321, 325, 639, 4013, 967, 4347, 19743, 13445, 61229}},
-{6367, 17, 5399, {1, 3, 3, 13, 13, 37, 71, 85, 51, 775, 973, 739, 4341, 15707, 12221, 24321, 48073}},
-{6368, 17, 5415, {1, 1, 7, 13, 15, 13, 9, 211, 331, 429, 1323, 3027, 1091, 13311, 289, 57789, 93261}},
-{6369, 17, 5422, {1, 1, 1, 1, 27, 7, 13, 27, 67, 573, 455, 2353, 113, 11831, 9069, 4503, 89291}},
-{6370, 17, 5441, {1, 1, 1, 7, 21, 63, 47, 39, 419, 991, 1623, 11, 3153, 12633, 9425, 65087, 44935}},
-{6371, 17, 5451, {1, 3, 1, 7, 23, 11, 15, 11, 99, 543, 1739, 3955, 5883, 12469, 7529, 14177, 1945}},
-{6372, 17, 5456, {1, 3, 1, 3, 5, 17, 31, 251, 387, 311, 725, 3827, 6835, 5065, 3141, 43441, 87955}},
-{6373, 17, 5462, {1, 1, 1, 11, 25, 7, 75, 135, 67, 589, 889, 3429, 155, 9081, 28653, 8059, 57251}},
-{6374, 17, 5490, {1, 3, 5, 15, 21, 15, 103, 149, 311, 407, 1391, 717, 1765, 14887, 14381, 37483, 29587}},
-{6375, 17, 5495, {1, 3, 5, 5, 19, 31, 93, 5, 507, 193, 1735, 3841, 7895, 9853, 10317, 14867, 49529}},
-{6376, 17, 5501, {1, 3, 7, 7, 19, 3, 99, 201, 479, 313, 693, 3435, 5453, 1157, 23127, 49005, 20167}},
-{6377, 17, 5502, {1, 3, 7, 9, 15, 21, 123, 41, 19, 281, 1837, 2589, 1003, 1993, 18345, 10039, 89325}},
-{6378, 17, 5505, {1, 3, 5, 1, 19, 21, 77, 151, 145, 951, 2017, 609, 5847, 4475, 12439, 6357, 108277}},
-{6379, 17, 5512, {1, 1, 1, 9, 17, 21, 91, 91, 111, 951, 497, 1759, 503, 12787, 25117, 24323, 96447}},
-{6380, 17, 5523, {1, 1, 3, 11, 13, 9, 73, 205, 329, 243, 1187, 829, 2821, 5563, 14391, 771, 116441}},
-{6381, 17, 5529, {1, 1, 1, 1, 11, 57, 39, 221, 41, 521, 1541, 3515, 2367, 4179, 21039, 52943, 11627}},
-{6382, 17, 5548, {1, 3, 3, 3, 23, 13, 103, 125, 67, 217, 863, 3755, 213, 12657, 31399, 3771, 54107}},
-{6383, 17, 5551, {1, 3, 3, 7, 3, 9, 107, 217, 497, 935, 519, 3041, 323, 14895, 5695, 28789, 36085}},
-{6384, 17, 5553, {1, 1, 5, 11, 23, 33, 81, 23, 167, 3, 1683, 2279, 5365, 847, 14717, 9689, 64481}},
-{6385, 17, 5565, {1, 3, 1, 7, 1, 15, 107, 93, 429, 363, 1745, 1459, 5879, 8351, 17527, 44001, 70293}},
-{6386, 17, 5568, {1, 3, 3, 9, 27, 55, 125, 211, 141, 827, 1239, 663, 4803, 11067, 32039, 28091, 56421}},
-{6387, 17, 5577, {1, 3, 5, 5, 7, 13, 125, 231, 427, 483, 967, 549, 3105, 13919, 3017, 39207, 23253}},
-{6388, 17, 5578, {1, 3, 7, 3, 21, 29, 79, 67, 39, 451, 157, 337, 3585, 3621, 9545, 31205, 63201}},
-{6389, 17, 5583, {1, 3, 1, 1, 29, 25, 77, 57, 167, 899, 95, 2487, 3743, 5381, 3637, 56289, 39453}},
-{6390, 17, 5585, {1, 1, 1, 9, 29, 19, 41, 97, 75, 199, 1709, 483, 4099, 3113, 10953, 20659, 109273}},
-{6391, 17, 5588, {1, 3, 5, 15, 13, 9, 83, 43, 111, 789, 965, 4061, 1239, 14577, 10113, 26359, 52609}},
-{6392, 17, 5613, {1, 3, 5, 5, 11, 39, 113, 31, 457, 119, 725, 831, 4143, 5675, 27431, 12431, 94977}},
-{6393, 17, 5614, {1, 1, 3, 3, 25, 17, 93, 253, 307, 625, 143, 1061, 4415, 3563, 3313, 53527, 29537}},
-{6394, 17, 5616, {1, 3, 5, 3, 29, 41, 43, 109, 147, 919, 1675, 465, 6101, 12251, 28915, 15397, 85233}},
-{6395, 17, 5622, {1, 1, 1, 1, 31, 25, 59, 187, 439, 561, 559, 413, 1917, 9319, 27475, 49715, 32953}},
-{6396, 17, 5631, {1, 1, 7, 13, 23, 31, 95, 231, 141, 207, 1373, 2173, 2905, 169, 23825, 55071, 6147}},
-{6397, 17, 5637, {1, 1, 7, 13, 15, 39, 43, 117, 321, 297, 661, 2941, 7359, 11675, 15483, 24093, 7269}},
-{6398, 17, 5638, {1, 3, 3, 13, 9, 59, 51, 49, 81, 563, 745, 1843, 295, 4689, 19847, 42137, 63197}},
-{6399, 17, 5668, {1, 3, 1, 9, 5, 33, 21, 199, 509, 927, 1777, 1349, 3593, 1065, 24943, 55667, 73539}},
-{6400, 17, 5675, {1, 3, 1, 11, 17, 15, 91, 21, 59, 587, 1207, 543, 6669, 10861, 24755, 1789, 91249}},
-{6401, 17, 5683, {1, 3, 7, 15, 13, 47, 57, 147, 381, 1021, 921, 1347, 3847, 5969, 9075, 39081, 127241}},
-{6402, 17, 5695, {1, 3, 3, 15, 19, 15, 1, 97, 203, 409, 1745, 1217, 2199, 7945, 24361, 41771, 123127}},
-{6403, 17, 5703, {1, 3, 3, 5, 17, 17, 43, 255, 179, 717, 1993, 645, 6527, 1533, 32719, 27481, 122425}},
-{6404, 17, 5710, {1, 3, 5, 9, 13, 59, 15, 157, 373, 937, 27, 3325, 2297, 89, 10861, 48615, 16083}},
-{6405, 17, 5715, {1, 3, 1, 3, 19, 27, 109, 243, 189, 17, 99, 1879, 695, 11329, 12467, 6053, 41749}},
-{6406, 17, 5727, {1, 1, 5, 5, 23, 41, 103, 69, 171, 917, 1303, 2101, 617, 10017, 26525, 11009, 66137}},
-{6407, 17, 5738, {1, 1, 1, 9, 21, 45, 47, 171, 455, 257, 411, 4021, 6995, 12881, 4793, 51193, 60775}},
-{6408, 17, 5752, {1, 3, 7, 5, 25, 31, 89, 53, 321, 593, 1795, 2435, 3833, 2767, 17241, 63373, 25457}},
-{6409, 17, 5767, {1, 3, 1, 1, 3, 45, 19, 255, 179, 991, 1407, 3683, 1435, 6803, 12215, 12835, 2005}},
-{6410, 17, 5773, {1, 3, 7, 3, 17, 5, 117, 251, 71, 983, 1391, 3499, 5119, 7257, 7325, 16565, 6321}},
-{6411, 17, 5776, {1, 3, 5, 7, 5, 49, 47, 201, 297, 485, 1879, 2205, 4903, 13619, 22537, 5479, 121625}},
-{6412, 17, 5781, {1, 1, 3, 5, 27, 27, 87, 61, 145, 943, 343, 1639, 6307, 4549, 20765, 33479, 113697}},
-{6413, 17, 5791, {1, 1, 3, 9, 17, 5, 101, 129, 305, 653, 1901, 3901, 6361, 2369, 7449, 55259, 75215}},
-{6414, 17, 5792, {1, 1, 7, 5, 31, 45, 117, 55, 335, 827, 1309, 2603, 2111, 11005, 14747, 56999, 97373}},
-{6415, 17, 5795, {1, 1, 7, 11, 29, 29, 81, 175, 169, 453, 293, 2589, 1057, 15795, 32397, 65433, 79455}},
-{6416, 17, 5798, {1, 1, 1, 5, 11, 7, 13, 249, 29, 407, 1289, 2385, 8113, 15327, 4029, 32005, 105901}},
-{6417, 17, 5801, {1, 1, 5, 5, 7, 61, 103, 141, 109, 391, 631, 821, 1479, 14771, 25057, 1415, 8081}},
-{6418, 17, 5810, {1, 3, 1, 1, 9, 37, 17, 231, 501, 745, 1695, 45, 7797, 2945, 5529, 34747, 39069}},
-{6419, 17, 5812, {1, 1, 7, 9, 21, 59, 103, 103, 33, 875, 723, 3477, 4729, 7311, 29979, 60901, 72187}},
-{6420, 17, 5836, {1, 3, 3, 3, 15, 63, 93, 237, 203, 635, 1189, 2035, 6499, 9943, 9133, 62977, 29657}},
-{6421, 17, 5839, {1, 1, 1, 9, 3, 11, 63, 207, 95, 563, 775, 3009, 7125, 13141, 4489, 16343, 120951}},
-{6422, 17, 5841, {1, 1, 3, 1, 21, 57, 15, 217, 185, 305, 463, 1597, 6529, 4989, 14011, 11265, 131031}},
-{6423, 17, 5867, {1, 3, 5, 15, 17, 61, 35, 127, 411, 579, 1349, 615, 3293, 8475, 9773, 30635, 117639}},
-{6424, 17, 5870, {1, 1, 7, 9, 11, 3, 55, 105, 305, 223, 1899, 2217, 1261, 9831, 23693, 3013, 30489}},
-{6425, 17, 5877, {1, 3, 7, 15, 15, 29, 1, 99, 67, 293, 499, 1941, 5303, 1329, 24547, 14065, 7927}},
-{6426, 17, 5881, {1, 1, 5, 11, 17, 55, 71, 49, 499, 435, 985, 2803, 6139, 1503, 24167, 47181, 102529}},
-{6427, 17, 5899, {1, 3, 5, 1, 19, 53, 71, 17, 63, 469, 1871, 2051, 357, 11661, 5689, 36373, 13379}},
-{6428, 17, 5914, {1, 1, 5, 1, 27, 47, 23, 247, 59, 381, 1895, 2453, 3665, 5487, 24081, 50501, 91659}},
-{6429, 17, 5925, {1, 1, 5, 7, 29, 19, 3, 33, 83, 301, 133, 3603, 5133, 16171, 22905, 36271, 10405}},
-{6430, 17, 5929, {1, 3, 7, 9, 11, 23, 57, 87, 9, 731, 631, 3703, 2593, 12851, 7115, 8801, 108919}},
-{6431, 17, 5943, {1, 3, 3, 3, 23, 35, 33, 99, 343, 837, 231, 3921, 6975, 15093, 15049, 64623, 123523}},
-{6432, 17, 5949, {1, 1, 7, 11, 15, 61, 113, 103, 501, 57, 1345, 3155, 2965, 4433, 10605, 43765, 42169}},
-{6433, 17, 5962, {1, 1, 7, 13, 7, 53, 91, 121, 229, 127, 103, 833, 7829, 1571, 10847, 20861, 101155}},
-{6434, 17, 5969, {1, 3, 7, 1, 9, 25, 71, 103, 37, 473, 1133, 1129, 1651, 6965, 6937, 16597, 20439}},
-{6435, 17, 5976, {1, 1, 5, 9, 1, 9, 47, 131, 285, 967, 1869, 1075, 8127, 135, 15575, 38569, 123729}},
-{6436, 17, 5988, {1, 1, 7, 9, 5, 31, 33, 227, 347, 41, 2025, 3755, 857, 7805, 13121, 38307, 125825}},
-{6437, 17, 5997, {1, 3, 5, 7, 11, 11, 19, 55, 23, 627, 1477, 3093, 2779, 7653, 7165, 23053, 76123}},
-{6438, 17, 6006, {1, 1, 3, 1, 3, 47, 83, 89, 177, 381, 1247, 141, 7051, 6443, 27369, 34323, 43063}},
-{6439, 17, 6010, {1, 1, 7, 7, 13, 15, 55, 223, 351, 525, 1051, 3009, 5443, 11499, 8335, 37949, 69149}},
-{6440, 17, 6016, {1, 1, 1, 3, 13, 61, 89, 33, 129, 921, 1905, 201, 3141, 5531, 135, 34103, 56883}},
-{6441, 17, 6022, {1, 1, 5, 13, 17, 27, 13, 163, 169, 471, 1263, 1421, 7015, 7927, 21027, 58001, 26739}},
-{6442, 17, 6026, {1, 1, 1, 15, 19, 49, 109, 207, 245, 49, 1271, 3635, 2561, 5091, 24415, 59195, 67701}},
-{6443, 17, 6031, {1, 3, 5, 7, 27, 57, 99, 155, 461, 595, 1859, 1727, 857, 4993, 31733, 42141, 10035}},
-{6444, 17, 6040, {1, 1, 1, 15, 11, 11, 85, 9, 251, 375, 155, 379, 7501, 12559, 32583, 36317, 4675}},
-{6445, 17, 6043, {1, 1, 5, 13, 19, 57, 81, 69, 201, 293, 593, 3169, 4519, 9057, 16685, 12847, 123797}},
-{6446, 17, 6050, {1, 3, 1, 5, 5, 1, 19, 243, 345, 661, 561, 3549, 2541, 5887, 25879, 41467, 72799}},
-{6447, 17, 6059, {1, 1, 5, 13, 15, 51, 67, 61, 79, 89, 447, 1471, 4915, 10637, 10901, 48157, 103545}},
-{6448, 17, 6079, {1, 3, 5, 13, 31, 25, 73, 129, 435, 659, 1851, 3595, 753, 7717, 10927, 30115, 109221}},
-{6449, 17, 6099, {1, 1, 1, 3, 25, 3, 121, 43, 349, 205, 1209, 2671, 6445, 8755, 7171, 58631, 74319}},
-{6450, 17, 6101, {1, 1, 3, 1, 11, 15, 83, 37, 483, 65, 759, 1835, 3883, 1693, 30051, 61077, 1187}},
-{6451, 17, 6105, {1, 3, 7, 15, 29, 23, 85, 77, 139, 903, 1821, 943, 6453, 1523, 18539, 49039, 110787}},
-{6452, 17, 6108, {1, 1, 7, 15, 15, 17, 69, 253, 507, 921, 523, 79, 747, 4011, 25795, 42029, 88309}},
-{6453, 17, 6124, {1, 1, 7, 3, 25, 47, 119, 83, 313, 45, 985, 145, 205, 3407, 9013, 64517, 115811}},
-{6454, 17, 6132, {1, 1, 7, 1, 29, 21, 9, 123, 97, 545, 1987, 2979, 6901, 12667, 23325, 63635, 70593}},
-{6455, 17, 6145, {1, 3, 7, 3, 23, 45, 81, 255, 41, 29, 1493, 4065, 3201, 10479, 17193, 39999, 55493}},
-{6456, 17, 6146, {1, 3, 1, 3, 9, 43, 43, 135, 235, 603, 481, 3139, 2729, 14759, 7269, 7995, 110351}},
-{6457, 17, 6151, {1, 3, 1, 11, 17, 35, 113, 93, 417, 967, 755, 659, 3115, 16163, 22997, 38205, 126961}},
-{6458, 17, 6152, {1, 1, 7, 11, 29, 57, 81, 235, 93, 869, 475, 825, 6269, 15819, 14977, 53057, 116021}},
-{6459, 17, 6158, {1, 1, 7, 13, 5, 61, 5, 241, 245, 673, 1651, 3367, 2355, 713, 20107, 30133, 735}},
-{6460, 17, 6160, {1, 1, 5, 9, 21, 3, 121, 241, 129, 703, 1435, 1943, 5087, 13123, 30023, 58287, 50377}},
-{6461, 17, 6163, {1, 1, 1, 15, 23, 27, 67, 197, 123, 629, 169, 3303, 1679, 11051, 16875, 28055, 12379}},
-{6462, 17, 6165, {1, 1, 3, 3, 7, 63, 97, 43, 89, 739, 779, 2893, 7763, 6351, 26135, 44647, 127987}},
-{6463, 17, 6170, {1, 3, 3, 9, 31, 59, 95, 131, 131, 321, 1125, 127, 4865, 145, 26237, 47871, 114549}},
-{6464, 17, 6182, {1, 3, 3, 13, 21, 3, 33, 17, 445, 693, 1599, 2517, 1679, 2237, 15053, 30983, 106755}},
-{6465, 17, 6196, {1, 1, 5, 13, 31, 37, 49, 67, 403, 27, 575, 1795, 3385, 1067, 585, 60277, 123189}},
-{6466, 17, 6199, {1, 3, 1, 15, 13, 35, 23, 247, 493, 305, 363, 451, 4011, 3679, 18281, 31751, 127933}},
-{6467, 17, 6200, {1, 1, 7, 5, 21, 45, 123, 253, 469, 267, 985, 2349, 3427, 7653, 25685, 13747, 531}},
-{6468, 17, 6205, {1, 1, 5, 11, 7, 59, 105, 209, 27, 847, 593, 3775, 6165, 1655, 29867, 28465, 92193}},
-{6469, 17, 6226, {1, 3, 1, 11, 7, 25, 101, 81, 233, 311, 9, 2735, 3951, 485, 10105, 24489, 649}},
-{6470, 17, 6228, {1, 3, 1, 7, 27, 5, 115, 243, 295, 659, 215, 1787, 5131, 2513, 29201, 21195, 103383}},
-{6471, 17, 6237, {1, 3, 5, 13, 29, 21, 7, 57, 345, 467, 1297, 207, 5115, 335, 6153, 32959, 125697}},
-{6472, 17, 6247, {1, 1, 1, 9, 3, 63, 63, 5, 373, 123, 1265, 2365, 1623, 1561, 14805, 17487, 104787}},
-{6473, 17, 6251, {1, 3, 1, 5, 15, 13, 55, 69, 251, 341, 463, 2611, 4793, 12157, 4669, 11613, 128705}},
-{6474, 17, 6253, {1, 3, 7, 13, 19, 7, 93, 149, 453, 693, 1731, 861, 6971, 943, 18891, 56547, 34411}},
-{6475, 17, 6256, {1, 1, 7, 1, 27, 49, 27, 9, 281, 121, 581, 393, 2583, 1159, 26989, 39955, 100765}},
-{6476, 17, 6268, {1, 1, 3, 9, 3, 43, 97, 207, 311, 617, 1987, 2559, 2101, 15791, 30085, 40713, 41909}},
-{6477, 17, 6272, {1, 3, 1, 3, 15, 19, 53, 183, 375, 867, 397, 3203, 4207, 5381, 25065, 60357, 88739}},
-{6478, 17, 6275, {1, 3, 3, 3, 27, 51, 85, 231, 19, 559, 567, 4049, 4875, 14201, 11623, 39763, 57339}},
-{6479, 17, 6281, {1, 1, 5, 1, 19, 7, 81, 249, 41, 789, 985, 3725, 4053, 4255, 9861, 1609, 29511}},
-{6480, 17, 6289, {1, 3, 5, 5, 21, 13, 49, 41, 367, 283, 1161, 2753, 4733, 3691, 27931, 53055, 83625}},
-{6481, 17, 6335, {1, 3, 5, 11, 29, 47, 95, 51, 265, 85, 385, 833, 7957, 14985, 7017, 41937, 41377}},
-{6482, 17, 6338, {1, 1, 7, 5, 1, 23, 17, 191, 185, 323, 515, 3183, 7685, 7361, 21143, 5227, 110297}},
-{6483, 17, 6355, {1, 3, 3, 7, 11, 39, 31, 97, 237, 497, 1649, 3529, 6153, 5055, 29021, 35125, 121581}},
-{6484, 17, 6362, {1, 3, 5, 3, 17, 47, 105, 75, 55, 343, 595, 2447, 5575, 10673, 32015, 37541, 127867}},
-{6485, 17, 6373, {1, 3, 1, 7, 19, 39, 31, 135, 167, 979, 219, 1353, 489, 9667, 27107, 55565, 72291}},
-{6486, 17, 6386, {1, 1, 3, 13, 31, 49, 87, 93, 235, 577, 1551, 2663, 387, 1129, 26683, 31285, 15913}},
-{6487, 17, 6388, {1, 3, 3, 7, 15, 29, 61, 33, 115, 511, 1781, 2029, 4265, 6745, 1467, 34415, 40907}},
-{6488, 17, 6391, {1, 1, 7, 5, 1, 55, 13, 129, 167, 937, 79, 2047, 3589, 1979, 4153, 15229, 85745}},
-{6489, 17, 6397, {1, 1, 7, 15, 15, 25, 89, 129, 31, 435, 1359, 49, 2659, 2829, 8741, 25215, 4239}},
-{6490, 17, 6405, {1, 3, 5, 3, 11, 39, 95, 239, 187, 615, 1481, 3509, 1133, 13497, 24833, 59635, 45695}},
-{6491, 17, 6406, {1, 1, 5, 3, 19, 17, 17, 235, 315, 943, 883, 1381, 7129, 15709, 9847, 41183, 116071}},
-{6492, 17, 6410, {1, 1, 1, 3, 9, 63, 109, 209, 309, 1015, 1391, 2617, 1481, 6483, 4151, 28063, 49887}},
-{6493, 17, 6417, {1, 1, 5, 13, 23, 37, 31, 89, 501, 461, 41, 931, 7863, 15499, 25635, 16995, 41651}},
-{6494, 17, 6443, {1, 1, 1, 9, 29, 29, 125, 161, 219, 439, 1465, 1615, 7483, 7497, 1121, 49693, 30269}},
-{6495, 17, 6457, {1, 3, 1, 5, 7, 43, 27, 161, 431, 375, 419, 2995, 527, 8207, 747, 18491, 15351}},
-{6496, 17, 6468, {1, 1, 3, 13, 25, 21, 67, 177, 9, 453, 1171, 65, 2845, 16147, 12699, 30905, 122255}},
-{6497, 17, 6475, {1, 3, 1, 5, 29, 47, 77, 251, 473, 385, 947, 3239, 5375, 13617, 10639, 36005, 95821}},
-{6498, 17, 6486, {1, 3, 1, 15, 13, 1, 75, 223, 509, 19, 175, 1541, 637, 5711, 1097, 44901, 35277}},
-{6499, 17, 6489, {1, 3, 3, 7, 3, 27, 17, 151, 39, 583, 391, 2739, 7339, 2051, 17005, 49573, 85969}},
-{6500, 17, 6495, {1, 3, 1, 11, 3, 25, 119, 125, 17, 629, 201, 2347, 2923, 1273, 14871, 58299, 97667}},
-{6501, 17, 6499, {1, 1, 7, 1, 31, 39, 11, 121, 339, 667, 1863, 3479, 1895, 11319, 5683, 64969, 9261}},
-{6502, 17, 6505, {1, 1, 5, 9, 27, 61, 101, 221, 221, 583, 287, 707, 5931, 4225, 29537, 46097, 114361}},
-{6503, 17, 6511, {1, 1, 1, 9, 23, 47, 1, 35, 85, 1021, 151, 3153, 3867, 971, 31573, 4745, 107639}},
-{6504, 17, 6520, {1, 1, 7, 13, 15, 15, 63, 37, 291, 907, 411, 1571, 6415, 7443, 26635, 27945, 130909}},
-{6505, 17, 6529, {1, 3, 1, 9, 21, 13, 77, 147, 485, 107, 235, 481, 2389, 957, 11493, 53033, 46373}},
-{6506, 17, 6542, {1, 3, 5, 7, 3, 55, 125, 237, 205, 411, 1911, 4053, 5983, 15489, 29333, 44727, 62167}},
-{6507, 17, 6547, {1, 1, 3, 3, 17, 3, 59, 239, 209, 495, 447, 3427, 3425, 2347, 10057, 26147, 52243}},
-{6508, 17, 6550, {1, 1, 3, 1, 11, 31, 3, 139, 441, 997, 295, 1267, 2181, 6047, 32419, 62657, 24921}},
-{6509, 17, 6554, {1, 3, 7, 15, 5, 3, 11, 9, 211, 701, 1987, 2611, 6195, 14379, 22919, 15785, 52149}},
-{6510, 17, 6556, {1, 1, 7, 9, 7, 27, 35, 253, 343, 679, 103, 1217, 3983, 8677, 17671, 41347, 89355}},
-{6511, 17, 6560, {1, 1, 1, 5, 7, 55, 111, 115, 231, 999, 773, 2111, 3617, 2469, 16967, 60735, 24557}},
-{6512, 17, 6569, {1, 3, 5, 1, 29, 5, 77, 217, 131, 307, 473, 3595, 2713, 6503, 18459, 57245, 91897}},
-{6513, 17, 6572, {1, 3, 5, 13, 9, 33, 93, 31, 59, 343, 1337, 1971, 7593, 15629, 22693, 19885, 4139}},
-{6514, 17, 6590, {1, 3, 3, 3, 21, 33, 115, 205, 373, 587, 739, 669, 8065, 5339, 16507, 29455, 15863}},
-{6515, 17, 6592, {1, 3, 5, 11, 9, 43, 45, 41, 91, 87, 19, 1523, 5059, 9403, 6739, 36893, 6395}},
-{6516, 17, 6601, {1, 1, 5, 15, 19, 43, 81, 3, 401, 621, 1839, 1443, 179, 8085, 27021, 7757, 95011}},
-{6517, 17, 6610, {1, 3, 5, 15, 19, 21, 45, 167, 77, 977, 309, 431, 3437, 8327, 12895, 50521, 68473}},
-{6518, 17, 6632, {1, 3, 3, 15, 7, 21, 49, 169, 327, 271, 7, 785, 1767, 14747, 7083, 65223, 24213}},
-{6519, 17, 6635, {1, 1, 5, 9, 9, 51, 101, 197, 507, 839, 1413, 3131, 331, 15725, 32293, 60433, 86759}},
-{6520, 17, 6640, {1, 1, 7, 1, 17, 39, 127, 201, 341, 607, 1565, 1615, 1367, 16043, 28265, 29139, 63813}},
-{6521, 17, 6643, {1, 3, 5, 7, 9, 1, 107, 73, 121, 649, 1385, 3203, 2897, 8479, 28519, 34041, 1359}},
-{6522, 17, 6649, {1, 1, 7, 7, 21, 55, 19, 13, 415, 647, 2015, 107, 4167, 5033, 16849, 41407, 94387}},
-{6523, 17, 6659, {1, 3, 5, 13, 31, 27, 107, 95, 425, 679, 55, 3521, 6737, 11459, 19995, 64189, 44323}},
-{6524, 17, 6662, {1, 1, 3, 9, 17, 47, 29, 167, 17, 63, 5, 2505, 6483, 14089, 7127, 7907, 68555}},
-{6525, 17, 6666, {1, 1, 5, 3, 29, 3, 87, 107, 227, 893, 1821, 341, 5481, 13317, 10637, 8611, 28625}},
-{6526, 17, 6690, {1, 1, 1, 13, 11, 19, 59, 157, 397, 103, 1821, 3913, 3083, 6053, 1015, 25475, 94813}},
-{6527, 17, 6692, {1, 3, 1, 3, 15, 45, 1, 209, 335, 1015, 539, 2959, 1711, 2567, 30169, 147, 25383}},
-{6528, 17, 6704, {1, 3, 7, 1, 17, 5, 99, 121, 91, 531, 865, 1667, 5615, 4729, 7473, 21445, 37925}},
-{6529, 17, 6713, {1, 1, 7, 13, 3, 51, 27, 115, 439, 761, 1121, 1503, 3047, 2127, 29253, 48147, 10813}},
-{6530, 17, 6728, {1, 3, 7, 15, 1, 51, 33, 161, 509, 159, 1705, 3365, 7953, 14027, 3873, 29609, 33101}},
-{6531, 17, 6731, {1, 1, 5, 15, 15, 53, 119, 115, 433, 75, 497, 1259, 1681, 7715, 24767, 34647, 82007}},
-{6532, 17, 6734, {1, 1, 5, 3, 27, 63, 41, 181, 393, 439, 95, 2765, 7617, 817, 1311, 18595, 16921}},
-{6533, 17, 6746, {1, 3, 1, 15, 31, 7, 57, 89, 371, 745, 475, 3211, 6893, 10681, 18547, 28373, 127787}},
-{6534, 17, 6755, {1, 3, 5, 13, 5, 55, 45, 167, 147, 833, 765, 1153, 4037, 8503, 10751, 49541, 77489}},
-{6535, 17, 6757, {1, 3, 1, 11, 11, 7, 45, 167, 431, 759, 1035, 1367, 1649, 11711, 4915, 58915, 72479}},
-{6536, 17, 6764, {1, 1, 5, 1, 11, 3, 15, 135, 427, 637, 879, 1667, 6139, 14759, 25665, 13083, 67961}},
-{6537, 17, 6772, {1, 3, 3, 9, 1, 3, 73, 167, 269, 51, 1481, 3659, 7863, 7187, 3951, 10711, 5909}},
-{6538, 17, 6792, {1, 1, 3, 3, 9, 53, 101, 209, 109, 691, 1641, 919, 1083, 6247, 23041, 44681, 130105}},
-{6539, 17, 6797, {1, 3, 7, 5, 21, 55, 127, 9, 437, 225, 1599, 2575, 5407, 8099, 20009, 40339, 110581}},
-{6540, 17, 6821, {1, 3, 3, 13, 7, 41, 15, 137, 363, 337, 995, 1215, 3651, 11011, 27209, 53927, 78065}},
-{6541, 17, 6822, {1, 1, 1, 7, 11, 17, 27, 9, 481, 79, 905, 1297, 811, 10221, 463, 12979, 114731}},
-{6542, 17, 6831, {1, 1, 3, 13, 7, 59, 105, 79, 253, 699, 139, 3823, 4939, 12955, 32069, 7255, 18159}},
-{6543, 17, 6834, {1, 3, 5, 7, 29, 7, 79, 79, 147, 921, 425, 1423, 5967, 6397, 17393, 30009, 84075}},
-{6544, 17, 6851, {1, 3, 7, 13, 23, 45, 51, 141, 237, 443, 1101, 309, 4533, 7479, 22415, 31517, 120407}},
-{6545, 17, 6858, {1, 1, 5, 13, 3, 19, 97, 185, 59, 179, 1343, 2537, 3165, 16295, 25005, 49769, 78007}},
-{6546, 17, 6860, {1, 3, 7, 15, 11, 53, 127, 195, 309, 121, 1741, 1415, 225, 15645, 16365, 38729, 70061}},
-{6547, 17, 6871, {1, 3, 7, 11, 29, 35, 47, 109, 179, 3, 849, 2305, 3035, 15289, 31569, 28851, 90057}},
-{6548, 17, 6875, {1, 1, 7, 1, 13, 27, 93, 119, 439, 45, 623, 1263, 6595, 6669, 12981, 64721, 130109}},
-{6549, 17, 6884, {1, 1, 7, 13, 5, 43, 43, 99, 395, 417, 795, 3991, 5601, 13115, 12803, 52247, 39245}},
-{6550, 17, 6888, {1, 3, 3, 3, 15, 61, 85, 91, 407, 391, 359, 3885, 1925, 4873, 169, 41727, 129471}},
-{6551, 17, 6894, {1, 3, 3, 9, 11, 47, 3, 33, 355, 853, 1329, 1347, 1995, 8197, 10015, 787, 66773}},
-{6552, 17, 6919, {1, 3, 3, 13, 31, 31, 49, 195, 55, 185, 1743, 3523, 1781, 8469, 7623, 55933, 74953}},
-{6553, 17, 6940, {1, 3, 5, 15, 29, 31, 5, 45, 149, 71, 2033, 3171, 4601, 9941, 15005, 55709, 74403}},
-{6554, 17, 6950, {1, 3, 5, 3, 1, 27, 105, 7, 139, 805, 1877, 915, 1843, 11897, 29485, 19275, 44711}},
-{6555, 17, 6959, {1, 1, 5, 7, 25, 57, 111, 57, 401, 935, 1685, 2985, 2015, 13501, 14581, 53579, 117011}},
-{6556, 17, 6968, {1, 1, 5, 11, 13, 47, 63, 137, 145, 77, 1727, 2629, 7377, 6311, 537, 13703, 129503}},
-{6557, 17, 6981, {1, 1, 7, 9, 5, 49, 67, 51, 163, 989, 845, 7, 2141, 14467, 3197, 57581, 121087}},
-{6558, 17, 6988, {1, 1, 5, 3, 31, 49, 57, 103, 171, 491, 1109, 1255, 4353, 11927, 29525, 16685, 48469}},
-{6559, 17, 6996, {1, 1, 1, 3, 7, 29, 17, 111, 339, 747, 763, 179, 7747, 2483, 18415, 45301, 25155}},
-{6560, 17, 6999, {1, 1, 7, 7, 1, 41, 71, 109, 401, 815, 1311, 3933, 1349, 13327, 20847, 44391, 49721}},
-{6561, 17, 7015, {1, 1, 1, 15, 27, 57, 39, 129, 391, 701, 619, 3925, 701, 403, 11821, 30517, 22035}},
-{6562, 17, 7019, {1, 1, 5, 11, 21, 49, 109, 101, 497, 417, 73, 2727, 2899, 2777, 22161, 35561, 70211}},
-{6563, 17, 7022, {1, 1, 3, 3, 15, 43, 1, 159, 41, 833, 55, 2415, 5009, 9663, 31295, 29397, 3187}},
-{6564, 17, 7040, {1, 1, 3, 7, 27, 5, 113, 187, 453, 753, 1649, 1605, 2405, 11791, 4239, 20915, 54033}},
-{6565, 17, 7045, {1, 3, 1, 11, 1, 57, 49, 229, 283, 113, 345, 785, 8009, 11977, 30169, 63787, 32011}},
-{6566, 17, 7049, {1, 1, 7, 3, 5, 59, 57, 91, 327, 685, 219, 1949, 3095, 8389, 2035, 11903, 73461}},
-{6567, 17, 7055, {1, 1, 3, 3, 19, 59, 19, 37, 453, 1, 1811, 3263, 1807, 16147, 24861, 14003, 31747}},
-{6568, 17, 7073, {1, 1, 3, 11, 1, 53, 93, 203, 429, 629, 1931, 1487, 3301, 8805, 4901, 2459, 98555}},
-{6569, 17, 7076, {1, 1, 7, 5, 21, 5, 37, 135, 159, 749, 1589, 2631, 8145, 7279, 28397, 47113, 82309}},
-{6570, 17, 7085, {1, 1, 5, 15, 25, 61, 19, 51, 217, 495, 109, 1179, 2743, 12107, 12509, 13003, 94375}},
-{6571, 17, 7091, {1, 3, 3, 15, 11, 7, 67, 165, 57, 925, 427, 2549, 7189, 5917, 13113, 30933, 62703}},
-{6572, 17, 7103, {1, 1, 5, 5, 9, 5, 43, 5, 485, 159, 757, 3979, 4963, 3389, 29731, 48477, 113429}},
-{6573, 17, 7112, {1, 3, 5, 1, 5, 5, 81, 163, 493, 357, 2005, 1093, 5951, 1045, 10569, 40321, 56881}},
-{6574, 17, 7117, {1, 3, 1, 5, 7, 29, 11, 7, 7, 13, 1641, 1031, 4025, 16337, 24333, 9589, 37779}},
-{6575, 17, 7118, {1, 3, 5, 11, 15, 3, 69, 19, 141, 79, 749, 391, 4505, 6939, 3079, 3647, 22363}},
-{6576, 17, 7123, {1, 3, 3, 3, 29, 3, 7, 189, 183, 513, 1225, 239, 4203, 9197, 23507, 33089, 124433}},
-{6577, 17, 7126, {1, 3, 3, 13, 27, 37, 81, 221, 287, 891, 1197, 3501, 539, 2053, 20509, 48635, 50269}},
-{6578, 17, 7154, {1, 1, 5, 7, 13, 3, 35, 79, 3, 885, 343, 3527, 1043, 7197, 6973, 8515, 39315}},
-{6579, 17, 7180, {1, 3, 3, 9, 21, 53, 79, 225, 229, 759, 457, 293, 953, 12857, 20483, 3677, 93839}},
-{6580, 17, 7192, {1, 3, 5, 3, 5, 17, 45, 107, 153, 279, 761, 1923, 7013, 2989, 10137, 19107, 126897}},
-{6581, 17, 7195, {1, 3, 1, 3, 23, 53, 91, 1, 133, 729, 13, 2017, 6933, 7405, 1255, 49509, 105571}},
-{6582, 17, 7207, {1, 3, 5, 1, 9, 45, 35, 153, 209, 289, 1779, 2557, 315, 981, 15347, 30391, 16027}},
-{6583, 17, 7208, {1, 3, 3, 5, 17, 3, 51, 105, 263, 959, 1255, 1177, 8143, 10541, 7687, 38731, 93561}},
-{6584, 17, 7214, {1, 1, 1, 13, 19, 1, 15, 135, 447, 847, 663, 3893, 3539, 6833, 13265, 62923, 8375}},
-{6585, 17, 7222, {1, 3, 1, 15, 31, 11, 105, 1, 91, 523, 1583, 3493, 2665, 117, 10757, 29845, 127201}},
-{6586, 17, 7234, {1, 1, 1, 3, 29, 49, 9, 103, 309, 605, 1751, 1981, 833, 3653, 14001, 16545, 58513}},
-{6587, 17, 7254, {1, 1, 5, 9, 1, 19, 117, 71, 237, 765, 249, 1983, 2289, 6019, 26505, 31427, 64333}},
-{6588, 17, 7258, {1, 1, 3, 11, 15, 31, 5, 207, 347, 143, 11, 1987, 3569, 2051, 31051, 22193, 93289}},
-{6589, 17, 7264, {1, 1, 3, 5, 13, 15, 5, 73, 457, 611, 673, 2675, 8071, 13245, 19443, 14399, 99599}},
-{6590, 17, 7279, {1, 1, 1, 9, 11, 5, 103, 231, 31, 457, 1031, 2257, 3159, 8323, 31585, 26163, 45159}},
-{6591, 17, 7282, {1, 3, 1, 11, 29, 51, 29, 7, 89, 331, 783, 951, 6353, 15421, 12801, 8337, 119171}},
-{6592, 17, 7293, {1, 1, 3, 13, 23, 57, 63, 43, 505, 1, 657, 4005, 6327, 7545, 15455, 27097, 53649}},
-{6593, 17, 7297, {1, 1, 1, 5, 31, 7, 51, 107, 175, 461, 1893, 305, 157, 4819, 18549, 33087, 9499}},
-{6594, 17, 7322, {1, 3, 1, 3, 19, 45, 37, 9, 459, 143, 1327, 3611, 1899, 15109, 30151, 17911, 13233}},
-{6595, 17, 7324, {1, 1, 5, 15, 19, 49, 11, 227, 375, 661, 665, 259, 3659, 13723, 28239, 48159, 59209}},
-{6596, 17, 7351, {1, 3, 7, 7, 17, 49, 77, 161, 505, 713, 1521, 935, 3629, 5033, 26717, 47199, 3693}},
-{6597, 17, 7363, {1, 3, 5, 9, 17, 61, 1, 201, 259, 179, 1637, 2485, 4995, 2813, 19923, 43739, 32183}},
-{6598, 17, 7380, {1, 1, 3, 5, 1, 23, 125, 61, 225, 703, 2011, 1013, 6651, 14029, 27375, 23301, 80269}},
-{6599, 17, 7384, {1, 1, 3, 9, 11, 57, 37, 49, 321, 443, 1055, 1989, 4755, 8467, 22001, 18647, 112617}},
-{6600, 17, 7389, {1, 3, 1, 5, 5, 39, 21, 139, 101, 583, 1881, 2599, 4185, 15679, 22215, 19093, 76737}},
-{6601, 17, 7396, {1, 3, 1, 11, 31, 51, 85, 91, 159, 421, 2005, 1075, 7757, 12653, 25489, 3545, 62961}},
-{6602, 17, 7413, {1, 1, 1, 15, 27, 57, 75, 151, 357, 571, 395, 299, 5607, 12865, 2149, 21059, 120753}},
-{6603, 17, 7417, {1, 1, 1, 3, 15, 57, 63, 171, 265, 709, 1089, 677, 7243, 10207, 9789, 38431, 130415}},
-{6604, 17, 7431, {1, 3, 7, 5, 21, 9, 73, 149, 197, 773, 773, 3931, 4135, 5671, 2733, 57173, 90693}},
-{6605, 17, 7443, {1, 1, 5, 1, 23, 1, 47, 201, 33, 167, 1643, 4009, 2687, 5725, 28733, 27859, 55163}},
-{6606, 17, 7445, {1, 1, 5, 15, 25, 11, 57, 139, 471, 625, 1067, 3647, 6213, 15605, 23537, 5005, 32593}},
-{6607, 17, 7450, {1, 3, 1, 11, 17, 11, 25, 163, 199, 21, 1775, 3721, 2845, 15769, 2381, 27643, 19909}},
-{6608, 17, 7456, {1, 3, 5, 5, 21, 41, 23, 125, 401, 483, 535, 925, 7065, 1727, 3761, 8485, 3519}},
-{6609, 17, 7466, {1, 1, 3, 15, 27, 31, 11, 7, 93, 237, 611, 3635, 4747, 9751, 20607, 20473, 73935}},
-{6610, 17, 7468, {1, 1, 7, 3, 15, 19, 69, 169, 387, 291, 1981, 635, 3387, 15817, 20357, 47537, 107311}},
-{6611, 17, 7474, {1, 3, 7, 15, 13, 59, 31, 235, 399, 343, 1265, 2975, 6839, 13335, 5397, 58915, 31313}},
-{6612, 17, 7479, {1, 1, 7, 1, 3, 35, 81, 243, 387, 421, 1533, 799, 2615, 13219, 9041, 26967, 22677}},
-{6613, 17, 7486, {1, 1, 7, 15, 17, 41, 89, 115, 67, 569, 1647, 1831, 5533, 4629, 1413, 20037, 97343}},
-{6614, 17, 7497, {1, 1, 5, 1, 23, 41, 11, 149, 319, 377, 439, 1237, 4819, 14303, 14657, 61711, 129235}},
-{6615, 17, 7508, {1, 3, 3, 7, 9, 11, 79, 219, 249, 607, 1453, 2931, 3407, 13725, 28289, 42869, 96759}},
-{6616, 17, 7515, {1, 1, 5, 11, 7, 9, 101, 51, 11, 893, 697, 1221, 4237, 1873, 11191, 25517, 119861}},
-{6617, 17, 7533, {1, 1, 3, 11, 23, 23, 19, 245, 485, 317, 1945, 2339, 193, 9389, 30709, 33927, 95089}},
-{6618, 17, 7542, {1, 1, 3, 1, 27, 55, 5, 81, 63, 185, 223, 3639, 6093, 10053, 1793, 11885, 29307}},
-{6619, 17, 7546, {1, 1, 7, 13, 15, 41, 33, 133, 467, 457, 213, 3687, 1313, 2555, 19487, 44257, 108667}},
-{6620, 17, 7551, {1, 1, 3, 5, 31, 51, 53, 115, 449, 273, 1043, 2743, 1759, 2013, 28171, 57091, 76837}},
-{6621, 17, 7569, {1, 1, 5, 15, 21, 43, 11, 215, 151, 253, 913, 1889, 2799, 13787, 3869, 54413, 50991}},
-{6622, 17, 7572, {1, 1, 3, 13, 29, 19, 81, 123, 461, 203, 81, 555, 6601, 15689, 12637, 41467, 105343}},
-{6623, 17, 7595, {1, 1, 3, 13, 7, 21, 75, 111, 47, 481, 1519, 3299, 6199, 3501, 31323, 29215, 45607}},
-{6624, 17, 7603, {1, 3, 1, 3, 17, 51, 45, 223, 321, 233, 267, 3333, 3803, 3099, 4601, 29061, 88441}},
-{6625, 17, 7605, {1, 1, 5, 13, 23, 27, 7, 57, 273, 893, 773, 239, 6357, 15875, 5497, 21775, 108291}},
-{6626, 17, 7629, {1, 3, 1, 15, 25, 17, 11, 229, 175, 909, 691, 3507, 5247, 2933, 1741, 35059, 62841}},
-{6627, 17, 7632, {1, 3, 5, 1, 29, 7, 11, 69, 345, 87, 99, 3243, 5669, 11053, 1185, 6979, 117069}},
-{6628, 17, 7638, {1, 3, 5, 11, 13, 33, 23, 183, 89, 475, 643, 2773, 7899, 15219, 133, 5073, 129355}},
-{6629, 17, 7648, {1, 3, 7, 9, 23, 17, 31, 53, 455, 193, 1695, 2557, 1645, 12675, 27857, 50447, 121335}},
-{6630, 17, 7654, {1, 1, 3, 11, 15, 19, 41, 57, 305, 235, 1131, 1165, 1857, 13667, 19285, 29755, 118885}},
-{6631, 17, 7663, {1, 3, 7, 3, 9, 43, 107, 3, 275, 673, 677, 3769, 3097, 5497, 24911, 4617, 80505}},
-{6632, 17, 7675, {1, 1, 7, 9, 21, 39, 107, 155, 471, 753, 579, 2929, 4951, 4245, 25035, 41795, 86955}},
-{6633, 17, 7693, {1, 3, 1, 7, 31, 51, 27, 165, 147, 751, 709, 399, 45, 947, 9893, 32721, 122127}},
-{6634, 17, 7705, {1, 3, 3, 1, 31, 31, 73, 59, 351, 293, 845, 3139, 4177, 3537, 9465, 20689, 65837}},
-{6635, 17, 7717, {1, 3, 5, 9, 27, 29, 13, 115, 417, 435, 465, 1291, 5225, 11687, 29207, 39895, 55443}},
-{6636, 17, 7724, {1, 3, 3, 15, 29, 49, 111, 179, 221, 565, 787, 1811, 4055, 7863, 27273, 32975, 26985}},
-{6637, 17, 7727, {1, 1, 1, 7, 15, 49, 121, 145, 277, 27, 149, 965, 4903, 3497, 32333, 37217, 105073}},
-{6638, 17, 7735, {1, 1, 7, 1, 23, 29, 31, 77, 353, 349, 755, 2081, 4291, 567, 641, 41751, 20397}},
-{6639, 17, 7761, {1, 1, 5, 3, 25, 31, 97, 3, 405, 607, 965, 2981, 3217, 14695, 25977, 22457, 113539}},
-{6640, 17, 7767, {1, 3, 3, 15, 25, 3, 91, 125, 269, 825, 1163, 2181, 4247, 6813, 4699, 35091, 87771}},
-{6641, 17, 7783, {1, 1, 5, 9, 25, 23, 113, 145, 71, 31, 1115, 3729, 6793, 11869, 26509, 18779, 99499}},
-{6642, 17, 7784, {1, 1, 1, 9, 31, 51, 77, 217, 247, 599, 1541, 3217, 1383, 5203, 27971, 23647, 71823}},
-{6643, 17, 7798, {1, 1, 5, 7, 17, 35, 113, 73, 475, 511, 35, 1961, 5311, 2257, 1935, 58963, 94349}},
-{6644, 17, 7802, {1, 3, 1, 7, 27, 31, 67, 253, 95, 883, 1213, 855, 3429, 15049, 26715, 56099, 101797}},
-{6645, 17, 7811, {1, 1, 3, 5, 9, 9, 61, 57, 511, 537, 1803, 949, 1327, 3921, 11297, 13807, 64629}},
-{6646, 17, 7817, {1, 1, 5, 1, 31, 57, 105, 161, 309, 283, 1291, 2737, 7141, 7497, 25893, 14453, 35375}},
-{6647, 17, 7823, {1, 1, 3, 1, 21, 3, 77, 37, 13, 211, 1863, 1895, 8035, 5801, 25981, 12317, 48375}},
-{6648, 17, 7832, {1, 3, 7, 7, 25, 45, 13, 77, 185, 553, 1501, 1349, 5951, 15581, 32657, 18467, 128363}},
-{6649, 17, 7837, {1, 3, 5, 9, 23, 63, 105, 239, 213, 935, 1331, 3653, 2775, 6591, 6067, 34597, 19217}},
-{6650, 17, 7842, {1, 3, 7, 13, 15, 19, 79, 91, 391, 637, 1685, 2263, 3507, 2025, 2111, 15875, 14831}},
-{6651, 17, 7853, {1, 3, 3, 5, 7, 29, 81, 69, 511, 399, 343, 737, 2833, 1021, 10471, 18689, 36181}},
-{6652, 17, 7854, {1, 1, 5, 11, 21, 17, 39, 137, 145, 857, 583, 789, 8057, 15995, 32113, 64163, 37153}},
-{6653, 17, 7856, {1, 3, 3, 11, 9, 61, 87, 131, 487, 667, 1295, 493, 4629, 7719, 18157, 49715, 2051}},
-{6654, 17, 7861, {1, 3, 5, 9, 19, 5, 85, 3, 491, 353, 571, 2829, 4411, 343, 24781, 62325, 123959}},
-{6655, 17, 7862, {1, 1, 7, 13, 13, 39, 11, 31, 413, 285, 27, 2433, 3307, 6165, 26565, 40065, 102655}},
-{6656, 17, 7873, {1, 1, 5, 11, 25, 45, 7, 97, 9, 973, 1833, 2537, 1457, 7389, 24087, 38061, 122805}},
-{6657, 17, 7874, {1, 3, 5, 3, 21, 63, 77, 21, 249, 525, 1145, 1421, 8011, 3357, 15051, 30293, 127017}},
-{6658, 17, 7886, {1, 1, 5, 3, 13, 53, 81, 185, 303, 307, 1579, 841, 2277, 607, 10899, 34209, 215}},
-{6659, 17, 7914, {1, 3, 3, 13, 17, 1, 125, 145, 205, 763, 127, 1865, 4129, 849, 27247, 29845, 36515}},
-{6660, 17, 7927, {1, 3, 7, 13, 5, 59, 19, 71, 227, 111, 365, 1309, 5857, 6035, 32379, 11303, 127329}},
-{6661, 17, 7936, {1, 1, 1, 1, 19, 61, 79, 253, 459, 23, 725, 3615, 4583, 429, 13215, 31879, 4523}},
-{6662, 17, 7951, {1, 1, 1, 7, 19, 13, 53, 41, 243, 107, 1767, 983, 3483, 2249, 2209, 58895, 14805}},
-{6663, 17, 7963, {1, 1, 1, 9, 5, 63, 31, 85, 119, 307, 633, 3295, 841, 3495, 22965, 57587, 108271}},
-{6664, 17, 7966, {1, 3, 5, 9, 17, 13, 57, 49, 97, 613, 405, 2637, 3229, 14253, 4663, 61345, 33415}},
-{6665, 17, 7976, {1, 3, 1, 1, 17, 37, 63, 3, 5, 375, 1073, 3971, 665, 4445, 153, 20437, 38513}},
-{6666, 17, 7993, {1, 3, 3, 15, 5, 9, 77, 161, 409, 461, 443, 567, 5581, 8623, 27735, 9041, 5517}},
-{6667, 17, 8001, {1, 3, 5, 13, 13, 5, 19, 53, 263, 155, 557, 3973, 6841, 4829, 30751, 30025, 121973}},
-{6668, 17, 8004, {1, 3, 7, 9, 27, 37, 49, 243, 107, 1013, 1743, 1509, 4465, 15415, 4741, 41409, 72695}},
-{6669, 17, 8013, {1, 1, 3, 5, 11, 49, 39, 45, 21, 463, 875, 3681, 1901, 15325, 24553, 51369, 82227}},
-{6670, 17, 8021, {1, 1, 3, 15, 11, 35, 21, 91, 383, 149, 1815, 911, 4633, 12027, 12413, 22307, 120049}},
-{6671, 17, 8026, {1, 3, 5, 7, 7, 3, 15, 83, 477, 687, 145, 1705, 6893, 5233, 20171, 43337, 72603}},
-{6672, 17, 8028, {1, 1, 3, 9, 25, 35, 19, 173, 67, 5, 561, 2139, 4557, 4911, 26273, 38409, 22801}},
-{6673, 17, 8031, {1, 1, 3, 13, 15, 39, 85, 91, 91, 187, 1851, 1181, 4049, 16353, 26525, 43703, 19415}},
-{6674, 17, 8035, {1, 3, 1, 9, 13, 41, 77, 179, 415, 705, 693, 3017, 5847, 16191, 11435, 28979, 51839}},
-{6675, 17, 8042, {1, 1, 3, 5, 23, 15, 3, 159, 269, 67, 625, 4043, 4701, 1599, 6467, 10949, 80073}},
-{6676, 17, 8071, {1, 3, 3, 15, 7, 43, 81, 157, 393, 321, 1875, 2801, 4359, 11703, 1063, 64015, 109997}},
-{6677, 17, 8085, {1, 1, 7, 3, 25, 21, 37, 123, 133, 691, 973, 3115, 2291, 10519, 13339, 22751, 85445}},
-{6678, 17, 8092, {1, 3, 1, 1, 21, 21, 9, 23, 431, 679, 1873, 289, 4503, 3939, 14417, 36081, 18709}},
-{6679, 17, 8102, {1, 3, 5, 5, 1, 53, 109, 133, 33, 279, 727, 2233, 3065, 8557, 7487, 25797, 109177}},
-{6680, 17, 8105, {1, 1, 7, 7, 1, 9, 47, 127, 179, 757, 1985, 547, 169, 13393, 22669, 58795, 92897}},
-{6681, 17, 8114, {1, 3, 5, 11, 17, 21, 95, 219, 263, 579, 1493, 3283, 5461, 1235, 1749, 33325, 36033}},
-{6682, 17, 8123, {1, 1, 3, 11, 21, 49, 45, 143, 511, 983, 1933, 965, 7905, 1925, 27857, 40723, 68251}},
-{6683, 17, 8131, {1, 3, 7, 3, 27, 9, 73, 7, 441, 877, 107, 1599, 4795, 7251, 6819, 7671, 21137}},
-{6684, 17, 8140, {1, 1, 3, 3, 21, 25, 49, 43, 247, 949, 627, 2859, 2507, 4787, 11269, 53221, 126387}},
-{6685, 17, 8145, {1, 1, 5, 3, 5, 53, 127, 65, 353, 521, 1701, 2981, 3201, 611, 13475, 58015, 2605}},
-{6686, 17, 8157, {1, 1, 5, 13, 9, 39, 55, 103, 53, 281, 705, 2433, 6179, 3381, 31973, 30267, 91307}},
-{6687, 17, 8158, {1, 1, 7, 13, 31, 23, 29, 161, 347, 449, 123, 3427, 5731, 12691, 15175, 20487, 74695}},
-{6688, 17, 8185, {1, 3, 3, 15, 13, 19, 83, 137, 437, 317, 921, 913, 7979, 6665, 5313, 1435, 60271}},
-{6689, 17, 8186, {1, 3, 5, 7, 19, 23, 31, 131, 421, 95, 1999, 897, 4839, 1815, 12387, 45009, 2609}},
-{6690, 17, 8188, {1, 1, 1, 7, 3, 53, 121, 33, 47, 283, 813, 3841, 4449, 2543, 15211, 59285, 42551}},
-{6691, 17, 8192, {1, 3, 1, 13, 9, 43, 37, 167, 93, 417, 213, 2721, 3395, 2089, 13743, 32925, 91147}},
-{6692, 17, 8212, {1, 3, 7, 5, 31, 25, 97, 25, 19, 11, 543, 1889, 455, 5765, 9517, 56963, 131069}},
-{6693, 17, 8219, {1, 3, 1, 7, 3, 7, 87, 61, 209, 39, 1303, 1637, 6687, 8001, 5003, 47911, 110657}},
-{6694, 17, 8221, {1, 1, 5, 3, 11, 25, 99, 77, 379, 843, 1423, 2933, 7535, 4181, 32223, 49327, 48041}},
-{6695, 17, 8235, {1, 3, 3, 13, 9, 7, 85, 59, 47, 777, 401, 2449, 2795, 11289, 25023, 7725, 73887}},
-{6696, 17, 8237, {1, 1, 3, 5, 11, 51, 93, 57, 369, 871, 1175, 2705, 1253, 5169, 24691, 14243, 119667}},
-{6697, 17, 8249, {1, 3, 1, 3, 5, 7, 33, 171, 359, 115, 1909, 2003, 1413, 13829, 3471, 36185, 118399}},
-{6698, 17, 8260, {1, 1, 1, 11, 5, 49, 97, 145, 415, 731, 671, 2309, 7211, 11359, 22757, 15415, 70951}},
-{6699, 17, 8264, {1, 1, 3, 5, 7, 51, 61, 101, 375, 575, 1321, 2835, 7569, 9599, 4707, 7655, 53417}},
-{6700, 17, 8270, {1, 3, 1, 15, 9, 63, 25, 117, 203, 5, 1345, 2571, 5273, 2059, 4689, 27237, 23199}},
-{6701, 17, 8282, {1, 1, 3, 15, 15, 23, 69, 49, 349, 995, 5, 1565, 903, 10165, 9565, 6343, 16653}},
-{6702, 17, 8291, {1, 1, 3, 9, 21, 15, 69, 9, 463, 69, 1447, 2347, 5125, 7479, 18257, 14405, 51321}},
-{6703, 17, 8293, {1, 1, 7, 11, 23, 57, 57, 179, 17, 129, 999, 777, 6281, 1693, 31885, 31085, 29237}},
-{6704, 17, 8297, {1, 3, 5, 1, 25, 55, 15, 21, 199, 271, 1645, 1719, 2023, 10049, 15215, 11959, 44875}},
-{6705, 17, 8298, {1, 3, 1, 3, 29, 43, 83, 11, 281, 27, 429, 685, 7189, 9151, 8665, 9553, 115293}},
-{6706, 17, 8305, {1, 3, 1, 7, 17, 43, 125, 11, 189, 803, 713, 683, 7285, 4455, 18195, 45333, 32281}},
-{6707, 17, 8306, {1, 3, 3, 3, 11, 55, 21, 59, 173, 283, 709, 1561, 5391, 5097, 24725, 19217, 13769}},
-{6708, 17, 8311, {1, 3, 5, 13, 7, 29, 117, 207, 415, 525, 567, 1741, 3553, 6729, 433, 17619, 45971}},
-{6709, 17, 8318, {1, 1, 7, 7, 3, 23, 43, 43, 213, 823, 609, 1037, 3797, 4733, 30717, 61067, 89581}},
-{6710, 17, 8327, {1, 3, 5, 7, 11, 7, 7, 241, 379, 217, 739, 2815, 2549, 14297, 10283, 1509, 80613}},
-{6711, 17, 8345, {1, 1, 1, 1, 17, 45, 53, 229, 193, 893, 1881, 227, 6751, 7135, 20823, 36939, 27667}},
-{6712, 17, 8379, {1, 3, 3, 1, 15, 39, 27, 217, 101, 949, 1963, 2213, 2357, 4129, 11925, 841, 59259}},
-{6713, 17, 8390, {1, 1, 3, 3, 5, 53, 59, 255, 421, 1009, 683, 2171, 6691, 12489, 20865, 29363, 70611}},
-{6714, 17, 8394, {1, 1, 7, 15, 7, 31, 105, 141, 153, 401, 549, 3045, 5443, 11147, 18159, 24283, 21859}},
-{6715, 17, 8414, {1, 3, 7, 1, 11, 17, 17, 231, 175, 603, 1915, 111, 3203, 10627, 9687, 47235, 87057}},
-{6716, 17, 8417, {1, 1, 1, 11, 19, 21, 115, 41, 45, 727, 1523, 739, 3025, 10321, 27353, 63139, 16051}},
-{6717, 17, 8432, {1, 3, 7, 11, 13, 9, 33, 121, 237, 565, 2043, 2131, 3079, 12575, 2187, 14427, 85939}},
-{6718, 17, 8437, {1, 3, 1, 15, 21, 19, 91, 227, 485, 49, 101, 15, 1903, 4039, 23819, 40001, 66405}},
-{6719, 17, 8441, {1, 3, 1, 5, 15, 25, 65, 25, 393, 287, 1435, 1851, 6437, 5983, 13769, 37847, 120907}},
-{6720, 17, 8449, {1, 3, 7, 15, 15, 21, 97, 37, 359, 155, 807, 1421, 517, 13135, 2955, 56979, 52299}},
-{6721, 17, 8456, {1, 1, 5, 1, 27, 53, 79, 27, 467, 605, 267, 1193, 31, 6177, 12369, 32621, 38319}},
-{6722, 17, 8473, {1, 1, 1, 11, 27, 15, 15, 231, 205, 677, 331, 133, 3313, 7193, 8059, 36449, 21671}},
-{6723, 17, 8489, {1, 3, 3, 11, 19, 57, 113, 83, 399, 801, 1843, 2119, 2779, 14061, 30901, 28745, 120903}},
-{6724, 17, 8495, {1, 1, 1, 11, 5, 27, 121, 247, 467, 251, 1487, 251, 897, 3171, 28383, 22473, 1709}},
-{6725, 17, 8522, {1, 1, 1, 15, 7, 59, 123, 165, 123, 373, 167, 1323, 5239, 9027, 13791, 55593, 78785}},
-{6726, 17, 8524, {1, 3, 1, 11, 31, 11, 81, 229, 123, 183, 461, 1751, 5713, 2615, 27795, 1657, 39253}},
-{6727, 17, 8529, {1, 1, 7, 1, 21, 45, 107, 3, 283, 149, 549, 3731, 6435, 3595, 32753, 16079, 84257}},
-{6728, 17, 8545, {1, 3, 3, 15, 19, 9, 81, 37, 51, 341, 909, 985, 1503, 12787, 16129, 37789, 113515}},
-{6729, 17, 8557, {1, 3, 5, 13, 3, 33, 127, 219, 369, 341, 1191, 1305, 567, 2339, 31221, 49435, 114927}},
-{6730, 17, 8565, {1, 1, 7, 15, 29, 47, 103, 107, 257, 15, 2029, 2133, 2129, 11235, 29553, 49139, 33809}},
-{6731, 17, 8572, {1, 3, 3, 13, 23, 33, 105, 43, 155, 815, 1087, 2261, 2781, 3461, 7371, 4479, 123093}},
-{6732, 17, 8576, {1, 1, 1, 13, 17, 7, 89, 107, 143, 349, 637, 3651, 4153, 12131, 28393, 45781, 84133}},
-{6733, 17, 8582, {1, 3, 5, 11, 31, 47, 105, 101, 267, 403, 1853, 3977, 3277, 1737, 15503, 47365, 14361}},
-{6734, 17, 8594, {1, 1, 1, 13, 1, 63, 125, 107, 123, 183, 1027, 3491, 3597, 15949, 5779, 34665, 81257}},
-{6735, 17, 8629, {1, 3, 1, 9, 13, 5, 125, 41, 389, 73, 1487, 1983, 957, 12645, 13983, 7675, 72711}},
-{6736, 17, 8636, {1, 3, 7, 5, 17, 5, 25, 63, 211, 591, 261, 2345, 3883, 4403, 773, 43963, 93509}},
-{6737, 17, 8668, {1, 3, 3, 1, 11, 35, 15, 251, 225, 643, 537, 3769, 7593, 6113, 1377, 52185, 81459}},
-{6738, 17, 8678, {1, 3, 5, 15, 27, 27, 51, 35, 389, 853, 1437, 2803, 5739, 1887, 15099, 3299, 111827}},
-{6739, 17, 8701, {1, 1, 3, 15, 25, 63, 31, 201, 79, 131, 31, 3929, 4195, 13045, 8681, 48121, 110723}},
-{6740, 17, 8702, {1, 1, 5, 7, 11, 43, 101, 57, 69, 271, 189, 3087, 4893, 11365, 6945, 14285, 41961}},
-{6741, 17, 8708, {1, 1, 7, 9, 21, 61, 41, 123, 25, 947, 1619, 2895, 7879, 12397, 17405, 48139, 71519}},
-{6742, 17, 8712, {1, 3, 1, 15, 1, 27, 113, 225, 441, 855, 541, 357, 3111, 4867, 20571, 30627, 70123}},
-{6743, 17, 8745, {1, 3, 5, 3, 5, 33, 103, 1, 21, 93, 383, 407, 5145, 7857, 20289, 51943, 16223}},
-{6744, 17, 8754, {1, 1, 7, 15, 1, 13, 41, 215, 463, 417, 513, 3417, 1755, 16165, 7271, 3101, 54353}},
-{6745, 17, 8759, {1, 3, 3, 13, 19, 29, 5, 205, 245, 927, 1249, 773, 3653, 9959, 357, 40863, 37289}},
-{6746, 17, 8763, {1, 3, 3, 7, 3, 5, 85, 241, 29, 627, 1963, 3133, 1369, 503, 11449, 4699, 2573}},
-{6747, 17, 8766, {1, 1, 7, 15, 3, 35, 47, 157, 413, 437, 1627, 3953, 947, 12721, 22209, 34303, 81237}},
-{6748, 17, 8780, {1, 1, 5, 5, 1, 45, 47, 245, 253, 349, 1853, 3481, 6105, 7267, 3159, 38833, 117889}},
-{6749, 17, 8783, {1, 3, 7, 15, 23, 43, 25, 181, 121, 681, 479, 1239, 6155, 3317, 9419, 28717, 44643}},
-{6750, 17, 8786, {1, 3, 3, 15, 31, 43, 111, 99, 405, 991, 301, 1689, 7107, 16131, 16703, 24059, 40345}},
-{6751, 17, 8798, {1, 1, 3, 9, 25, 5, 107, 91, 117, 351, 1595, 163, 3007, 13743, 24535, 38671, 29745}},
-{6752, 17, 8804, {1, 3, 3, 5, 27, 47, 15, 195, 119, 919, 665, 1903, 1981, 7753, 21709, 33699, 15963}},
-{6753, 17, 8819, {1, 3, 1, 11, 23, 23, 75, 115, 477, 105, 541, 1111, 209, 13939, 17129, 7565, 75415}},
-{6754, 17, 8826, {1, 1, 1, 11, 7, 61, 123, 201, 305, 713, 779, 2059, 4899, 13733, 20529, 15617, 39833}},
-{6755, 17, 8835, {1, 1, 7, 11, 21, 7, 63, 113, 213, 871, 375, 29, 1925, 15237, 7091, 12229, 8457}},
-{6756, 17, 8838, {1, 1, 1, 7, 19, 57, 83, 91, 297, 255, 1993, 63, 5337, 4569, 21243, 40867, 46969}},
-{6757, 17, 8856, {1, 1, 3, 7, 13, 63, 91, 191, 281, 259, 1367, 3505, 5885, 10557, 12423, 56303, 14731}},
-{6758, 17, 8862, {1, 1, 5, 15, 27, 15, 29, 67, 115, 287, 253, 1497, 3739, 2183, 14427, 44931, 11547}},
-{6759, 17, 8871, {1, 3, 1, 9, 25, 61, 25, 113, 137, 819, 781, 3741, 2457, 7817, 31209, 20707, 93007}},
-{6760, 17, 8875, {1, 1, 7, 3, 5, 13, 23, 3, 365, 77, 1117, 3061, 4707, 3013, 27899, 10887, 78677}},
-{6761, 17, 8890, {1, 3, 1, 15, 1, 39, 85, 107, 483, 83, 603, 3121, 1995, 5241, 32319, 9515, 94551}},
-{6762, 17, 8892, {1, 1, 7, 3, 27, 13, 105, 41, 285, 237, 1589, 517, 2009, 10833, 1459, 26217, 50759}},
-{6763, 17, 8898, {1, 1, 3, 11, 27, 1, 127, 83, 355, 107, 1003, 657, 4997, 4123, 13151, 56601, 122307}},
-{6764, 17, 8927, {1, 1, 1, 7, 13, 17, 93, 75, 481, 473, 131, 1359, 4859, 1319, 23919, 50079, 128849}},
-{6765, 17, 8928, {1, 1, 3, 7, 9, 33, 111, 229, 11, 283, 1089, 3049, 1635, 959, 19109, 62821, 105391}},
-{6766, 17, 8945, {1, 3, 1, 3, 9, 47, 49, 169, 343, 929, 1379, 1985, 5867, 6053, 12179, 39727, 116053}},
-{6767, 17, 8952, {1, 3, 3, 15, 27, 39, 61, 113, 439, 719, 1313, 3701, 4793, 10275, 2943, 32405, 95457}},
-{6768, 17, 8955, {1, 1, 1, 1, 27, 49, 121, 171, 319, 365, 1593, 1655, 63, 6257, 18097, 35285, 112245}},
-{6769, 17, 8965, {1, 3, 1, 1, 19, 33, 89, 235, 281, 519, 1867, 525, 4475, 12059, 26611, 14789, 59541}},
-{6770, 17, 8972, {1, 3, 1, 15, 1, 51, 65, 71, 131, 599, 117, 2459, 7421, 7157, 24393, 48139, 53701}},
-{6771, 17, 8977, {1, 1, 7, 7, 1, 41, 57, 191, 207, 329, 43, 1235, 5671, 12243, 22549, 40751, 104513}},
-{6772, 17, 8990, {1, 3, 5, 13, 15, 21, 55, 187, 283, 209, 1511, 1329, 6665, 15953, 4521, 16879, 57625}},
-{6773, 17, 8996, {1, 1, 5, 3, 3, 53, 75, 123, 291, 663, 1893, 3669, 4903, 8575, 27971, 46977, 56357}},
-{6774, 17, 9025, {1, 3, 1, 5, 27, 41, 19, 199, 489, 197, 439, 3299, 6315, 6957, 15809, 35297, 5559}},
-{6775, 17, 9037, {1, 3, 5, 1, 3, 25, 109, 191, 33, 543, 125, 2309, 429, 14059, 3149, 45747, 47357}},
-{6776, 17, 9040, {1, 1, 3, 11, 15, 61, 109, 103, 305, 1, 1479, 2781, 6521, 8921, 23681, 9583, 87257}},
-{6777, 17, 9049, {1, 1, 7, 15, 5, 19, 121, 139, 177, 967, 1363, 705, 211, 11877, 22457, 34563, 7801}},
-{6778, 17, 9062, {1, 1, 7, 13, 9, 21, 103, 95, 483, 567, 5, 2095, 4659, 2447, 23521, 27273, 85867}},
-{6779, 17, 9068, {1, 3, 5, 15, 23, 55, 13, 237, 275, 113, 1431, 2931, 5165, 5317, 5625, 51865, 42177}},
-{6780, 17, 9076, {1, 3, 3, 7, 1, 23, 15, 171, 303, 43, 1137, 1255, 3843, 9049, 1799, 7075, 2115}},
-{6781, 17, 9079, {1, 1, 7, 5, 23, 53, 75, 129, 1, 511, 793, 265, 6535, 9641, 25173, 9449, 46949}},
-{6782, 17, 9099, {1, 3, 3, 1, 19, 39, 51, 173, 5, 281, 2047, 4065, 3225, 14587, 16947, 1459, 87227}},
-{6783, 17, 9107, {1, 3, 7, 13, 13, 53, 39, 115, 403, 37, 1533, 2727, 2229, 8291, 18687, 59553, 37629}},
-{6784, 17, 9114, {1, 3, 1, 9, 3, 55, 63, 191, 147, 321, 1287, 2419, 6881, 2249, 11141, 54839, 50263}},
-{6785, 17, 9123, {1, 1, 5, 3, 9, 61, 85, 139, 1, 409, 633, 53, 163, 14677, 13043, 12253, 106939}},
-{6786, 17, 9126, {1, 1, 7, 3, 19, 3, 7, 165, 497, 621, 1563, 1267, 8113, 2383, 17205, 13337, 102547}},
-{6787, 17, 9137, {1, 3, 3, 13, 15, 29, 23, 31, 481, 535, 471, 2125, 331, 9421, 29799, 27097, 5307}},
-{6788, 17, 9149, {1, 1, 1, 1, 31, 45, 47, 139, 235, 509, 889, 685, 1855, 13599, 24431, 62105, 109509}},
-{6789, 17, 9150, {1, 3, 1, 7, 3, 13, 25, 197, 111, 45, 1815, 1031, 4803, 349, 32369, 40837, 111529}},
-{6790, 17, 9155, {1, 1, 7, 1, 27, 9, 3, 73, 403, 321, 967, 2713, 6953, 16123, 8611, 48651, 120635}},
-{6791, 17, 9161, {1, 3, 5, 3, 3, 25, 69, 231, 249, 393, 1141, 1721, 7071, 3711, 15627, 21815, 104735}},
-{6792, 17, 9162, {1, 3, 1, 11, 19, 63, 77, 5, 55, 481, 1021, 119, 3941, 1227, 10997, 29513, 18923}},
-{6793, 17, 9167, {1, 3, 7, 5, 1, 11, 13, 99, 365, 797, 1993, 699, 3091, 11401, 3659, 15339, 90395}},
-{6794, 17, 9172, {1, 3, 5, 7, 31, 43, 55, 143, 273, 379, 1189, 1689, 4811, 5159, 3281, 63819, 57065}},
-{6795, 17, 9186, {1, 1, 1, 13, 9, 25, 9, 3, 461, 281, 959, 2439, 3187, 4837, 13857, 20221, 29733}},
-{6796, 17, 9188, {1, 1, 7, 11, 31, 17, 13, 101, 81, 921, 1329, 2421, 2747, 9435, 23313, 7093, 7547}},
-{6797, 17, 9191, {1, 1, 3, 3, 9, 51, 67, 95, 511, 1011, 1519, 4089, 5001, 1351, 15367, 50665, 92111}},
-{6798, 17, 9198, {1, 1, 5, 13, 27, 43, 115, 77, 439, 589, 31, 915, 7027, 697, 25143, 1443, 59093}},
-{6799, 17, 9200, {1, 1, 7, 3, 17, 5, 107, 117, 133, 649, 1309, 2979, 969, 9789, 12597, 24507, 106825}},
-{6800, 17, 9205, {1, 1, 7, 13, 1, 27, 97, 35, 431, 183, 199, 2619, 515, 89, 20281, 30291, 97977}},
-{6801, 17, 9206, {1, 1, 7, 1, 31, 9, 35, 11, 359, 21, 1875, 3227, 1307, 15691, 17343, 21163, 84671}},
-{6802, 17, 9215, {1, 3, 1, 11, 29, 21, 47, 137, 441, 841, 1641, 3283, 1371, 8835, 16287, 45009, 13779}},
-{6803, 17, 9227, {1, 1, 3, 9, 23, 53, 1, 99, 473, 649, 447, 2589, 5667, 15579, 6497, 44321, 46993}},
-{6804, 17, 9232, {1, 1, 7, 9, 31, 63, 95, 81, 197, 373, 1027, 3959, 7189, 13369, 17287, 53643, 12673}},
-{6805, 17, 9241, {1, 3, 1, 5, 25, 61, 79, 183, 489, 725, 1077, 1147, 113, 7357, 27505, 529, 61855}},
-{6806, 17, 9244, {1, 1, 7, 11, 19, 35, 73, 223, 125, 765, 1303, 2887, 7861, 14839, 9537, 27027, 94327}},
-{6807, 17, 9251, {1, 3, 1, 3, 17, 35, 63, 233, 317, 133, 1837, 3339, 4351, 10071, 5005, 13245, 34327}},
-{6808, 17, 9254, {1, 3, 1, 3, 17, 13, 59, 113, 247, 1015, 1831, 3391, 6337, 6853, 7145, 64309, 40109}},
-{6809, 17, 9275, {1, 3, 5, 13, 15, 23, 65, 203, 241, 545, 1521, 1253, 3171, 7777, 21145, 565, 87813}},
-{6810, 17, 9283, {1, 1, 5, 15, 31, 9, 9, 145, 409, 155, 409, 2935, 5817, 11427, 32617, 38167, 69465}},
-{6811, 17, 9285, {1, 1, 5, 11, 19, 31, 43, 85, 97, 931, 687, 1501, 3991, 2215, 11091, 64735, 56999}},
-{6812, 17, 9303, {1, 1, 1, 3, 7, 11, 101, 21, 345, 829, 531, 1475, 6617, 1187, 26885, 32135, 9733}},
-{6813, 17, 9304, {1, 3, 5, 11, 7, 49, 79, 197, 57, 15, 1845, 1485, 6167, 10887, 17083, 59367, 7411}},
-{6814, 17, 9313, {1, 3, 7, 5, 9, 33, 7, 91, 311, 847, 1435, 3573, 3693, 5369, 26817, 30105, 115337}},
-{6815, 17, 9314, {1, 3, 1, 9, 25, 43, 65, 69, 225, 337, 575, 1979, 5555, 8499, 8127, 33035, 52549}},
-{6816, 17, 9320, {1, 1, 3, 11, 17, 29, 71, 99, 379, 145, 1067, 2561, 7635, 5647, 32491, 56621, 93603}},
-{6817, 17, 9328, {1, 1, 5, 13, 25, 43, 75, 237, 407, 393, 1219, 3651, 7719, 11685, 26123, 62767, 1043}},
-{6818, 17, 9333, {1, 1, 7, 15, 13, 59, 9, 163, 273, 225, 873, 3201, 633, 6121, 18777, 58763, 77731}},
-{6819, 17, 9337, {1, 3, 7, 7, 3, 7, 99, 155, 279, 991, 799, 753, 7205, 9567, 23643, 38263, 19083}},
-{6820, 17, 9338, {1, 3, 7, 11, 11, 29, 65, 3, 207, 575, 253, 2407, 7935, 11323, 23239, 1923, 47737}},
-{6821, 17, 9340, {1, 1, 5, 9, 25, 47, 1, 25, 397, 1009, 193, 4031, 3023, 2029, 10561, 32363, 104405}},
-{6822, 17, 9353, {1, 3, 7, 9, 19, 55, 63, 179, 385, 97, 461, 3393, 8137, 8929, 17621, 9611, 58925}},
-{6823, 17, 9356, {1, 1, 1, 7, 1, 17, 127, 45, 157, 529, 809, 3545, 5173, 5083, 13325, 52295, 91261}},
-{6824, 17, 9364, {1, 1, 7, 9, 25, 49, 99, 79, 157, 535, 1569, 2195, 1725, 1187, 18423, 47957, 10043}},
-{6825, 17, 9373, {1, 1, 3, 7, 3, 31, 83, 45, 199, 665, 1261, 3497, 7885, 5761, 17187, 12041, 12867}},
-{6826, 17, 9374, {1, 3, 1, 7, 3, 55, 73, 215, 41, 1011, 1883, 1051, 7293, 1881, 27435, 29459, 130933}},
-{6827, 17, 9378, {1, 1, 3, 9, 21, 31, 113, 209, 35, 771, 365, 3151, 787, 3845, 26555, 13823, 36951}},
-{6828, 17, 9380, {1, 3, 7, 15, 13, 21, 119, 91, 15, 251, 1337, 2715, 1665, 3451, 8309, 11033, 127159}},
-{6829, 17, 9389, {1, 3, 1, 9, 9, 63, 5, 145, 357, 9, 859, 1565, 1141, 14689, 25121, 41337, 83357}},
-{6830, 17, 9395, {1, 1, 7, 11, 13, 63, 57, 151, 33, 595, 2025, 571, 4713, 11019, 26771, 16221, 92439}},
-{6831, 17, 9412, {1, 3, 3, 15, 29, 49, 93, 131, 167, 835, 33, 263, 93, 8475, 16139, 61237, 95081}},
-{6832, 17, 9422, {1, 1, 7, 13, 1, 57, 43, 91, 485, 841, 1415, 3083, 2665, 8521, 9825, 59955, 21763}},
-{6833, 17, 9439, {1, 1, 1, 1, 29, 47, 63, 107, 439, 847, 537, 2011, 7571, 3699, 23961, 54887, 92681}},
-{6834, 17, 9450, {1, 3, 7, 5, 27, 41, 105, 161, 95, 821, 451, 2627, 4687, 1899, 18851, 35167, 6869}},
-{6835, 17, 9452, {1, 1, 1, 11, 7, 7, 13, 163, 399, 471, 1587, 2561, 1241, 5365, 27189, 49883, 68101}},
-{6836, 17, 9482, {1, 3, 7, 9, 19, 5, 119, 251, 151, 359, 235, 2387, 3919, 7135, 17591, 1053, 6265}},
-{6837, 17, 9487, {1, 1, 5, 9, 13, 25, 43, 23, 453, 693, 517, 1235, 1045, 4299, 27877, 3733, 72269}},
-{6838, 17, 9489, {1, 1, 7, 1, 27, 43, 103, 249, 487, 67, 855, 3239, 2157, 8121, 4701, 37803, 49971}},
-{6839, 17, 9499, {1, 1, 3, 13, 1, 37, 125, 115, 365, 57, 1419, 4085, 7039, 10079, 14991, 48861, 61979}},
-{6840, 17, 9501, {1, 1, 5, 5, 3, 35, 109, 19, 219, 653, 1219, 1625, 6847, 11271, 4525, 56341, 57801}},
-{6841, 17, 9508, {1, 3, 7, 5, 31, 19, 37, 73, 185, 13, 1723, 1139, 5919, 11717, 27161, 13635, 51765}},
-{6842, 17, 9515, {1, 1, 1, 1, 19, 61, 53, 111, 215, 189, 1199, 591, 943, 2111, 17171, 15621, 128459}},
-{6843, 17, 9518, {1, 1, 7, 9, 17, 61, 101, 159, 85, 537, 15, 1427, 6139, 4091, 32639, 28655, 115385}},
-{6844, 17, 9520, {1, 1, 7, 5, 23, 31, 125, 7, 151, 967, 1079, 4059, 3287, 11673, 19307, 49469, 65981}},
-{6845, 17, 9526, {1, 3, 3, 1, 29, 59, 95, 119, 31, 427, 1653, 721, 5509, 6385, 17043, 45133, 74155}},
-{6846, 17, 9537, {1, 1, 3, 9, 13, 61, 35, 189, 1, 559, 119, 3719, 4137, 1369, 19147, 10923, 43909}},
-{6847, 17, 9552, {1, 3, 3, 13, 1, 41, 31, 185, 451, 379, 29, 153, 4121, 13153, 4171, 36993, 109241}},
-{6848, 17, 9571, {1, 1, 1, 9, 15, 41, 99, 17, 21, 93, 649, 2765, 6955, 10843, 12547, 64989, 63713}},
-{6849, 17, 9588, {1, 1, 7, 5, 5, 5, 73, 187, 473, 235, 1907, 409, 7335, 4429, 7493, 20703, 14505}},
-{6850, 17, 9613, {1, 1, 3, 11, 27, 59, 17, 103, 337, 117, 1241, 951, 3701, 10407, 16741, 46531, 56485}},
-{6851, 17, 9619, {1, 1, 3, 15, 11, 51, 111, 189, 137, 939, 97, 1563, 851, 13949, 1375, 41463, 61445}},
-{6852, 17, 9622, {1, 1, 7, 9, 19, 39, 117, 173, 165, 547, 483, 361, 6819, 15093, 13631, 29785, 29593}},
-{6853, 17, 9637, {1, 3, 3, 5, 15, 39, 41, 249, 455, 79, 233, 3133, 405, 9487, 23161, 32751, 117743}},
-{6854, 17, 9652, {1, 1, 5, 15, 7, 63, 7, 57, 127, 349, 1913, 1145, 3371, 3733, 30971, 35717, 60935}},
-{6855, 17, 9655, {1, 1, 7, 11, 7, 57, 49, 63, 51, 233, 855, 2125, 6961, 15011, 28503, 40549, 47175}},
-{6856, 17, 9661, {1, 3, 7, 1, 25, 49, 35, 39, 237, 545, 1637, 1401, 3279, 10499, 14463, 34973, 29485}},
-{6857, 17, 9664, {1, 3, 3, 13, 7, 13, 79, 141, 55, 277, 843, 3087, 2339, 6855, 10635, 13021, 11273}},
-{6858, 17, 9669, {1, 3, 1, 1, 11, 39, 51, 255, 119, 691, 559, 3287, 5485, 791, 19283, 51027, 8061}},
-{6859, 17, 9681, {1, 3, 7, 7, 3, 59, 119, 241, 185, 81, 1843, 2313, 7471, 15689, 2271, 59781, 107439}},
-{6860, 17, 9682, {1, 3, 3, 3, 17, 63, 93, 217, 329, 39, 583, 3031, 4315, 4623, 12557, 42063, 11877}},
-{6861, 17, 9688, {1, 1, 1, 1, 15, 57, 37, 233, 387, 639, 37, 425, 637, 1577, 16449, 33665, 80417}},
-{6862, 17, 9697, {1, 1, 1, 15, 25, 1, 67, 159, 423, 961, 959, 417, 5657, 8417, 8127, 29251, 105893}},
-{6863, 17, 9700, {1, 3, 5, 15, 31, 9, 87, 217, 259, 771, 1663, 2899, 1531, 7849, 1961, 61487, 55399}},
-{6864, 17, 9715, {1, 1, 3, 9, 21, 13, 39, 107, 89, 811, 449, 2569, 4617, 8977, 1649, 37721, 48943}},
-{6865, 17, 9722, {1, 3, 7, 15, 15, 59, 63, 195, 287, 677, 269, 1715, 3545, 3269, 5231, 46433, 25921}},
-{6866, 17, 9727, {1, 1, 5, 7, 19, 27, 57, 221, 243, 47, 1791, 2309, 2751, 4403, 7083, 34223, 64905}},
-{6867, 17, 9734, {1, 1, 1, 15, 1, 63, 119, 155, 383, 649, 429, 3857, 7309, 9823, 9539, 8933, 128573}},
-{6868, 17, 9740, {1, 3, 7, 11, 17, 19, 99, 19, 321, 415, 1501, 2123, 6119, 9705, 11397, 39521, 34327}},
-{6869, 17, 9743, {1, 1, 5, 15, 29, 37, 9, 95, 417, 19, 1637, 2949, 4961, 10743, 9619, 16045, 48083}},
-{6870, 17, 9745, {1, 1, 1, 11, 21, 17, 57, 23, 247, 201, 1781, 779, 2207, 2511, 4829, 13847, 77593}},
-{6871, 17, 9757, {1, 3, 1, 13, 7, 1, 95, 87, 223, 73, 1129, 383, 1355, 4965, 29645, 63465, 76281}},
-{6872, 17, 9761, {1, 3, 3, 13, 3, 47, 33, 123, 155, 621, 1019, 1817, 4083, 4723, 24701, 47503, 18007}},
-{6873, 17, 9762, {1, 1, 7, 15, 13, 41, 73, 93, 379, 923, 1183, 2475, 5901, 10599, 10053, 9941, 112107}},
-{6874, 17, 9767, {1, 1, 3, 3, 13, 35, 59, 231, 45, 1011, 1101, 2467, 2703, 10305, 12575, 7587, 25737}},
-{6875, 17, 9768, {1, 3, 7, 1, 21, 31, 9, 55, 373, 779, 397, 1551, 5139, 16339, 1769, 10413, 74059}},
-{6876, 17, 9774, {1, 1, 7, 15, 7, 3, 67, 179, 411, 217, 1219, 13, 1577, 13463, 12263, 41465, 83001}},
-{6877, 17, 9786, {1, 3, 7, 1, 21, 53, 7, 187, 395, 777, 391, 737, 47, 12681, 16749, 26507, 49415}},
-{6878, 17, 9796, {1, 1, 5, 7, 5, 57, 93, 53, 419, 731, 825, 487, 45, 9199, 20947, 56067, 45343}},
-{6879, 17, 9820, {1, 3, 3, 9, 31, 41, 35, 133, 63, 293, 1503, 51, 3111, 15711, 15051, 1965, 64951}},
-{6880, 17, 9823, {1, 1, 5, 9, 9, 47, 53, 229, 405, 621, 1795, 1923, 6609, 6983, 1695, 18021, 71893}},
-{6881, 17, 9839, {1, 1, 5, 9, 23, 13, 107, 13, 149, 759, 1113, 1329, 1747, 14159, 16705, 61841, 82955}},
-{6882, 17, 9844, {1, 3, 3, 9, 25, 49, 31, 145, 481, 609, 1847, 1485, 6345, 7859, 21231, 37303, 69975}},
-{6883, 17, 9851, {1, 3, 1, 15, 13, 49, 59, 221, 27, 517, 431, 3961, 6401, 8483, 10161, 37453, 128237}},
-{6884, 17, 9853, {1, 1, 3, 1, 3, 55, 37, 111, 263, 735, 655, 2831, 2219, 9449, 8413, 49585, 91355}},
-{6885, 17, 9863, {1, 3, 7, 1, 31, 33, 7, 55, 261, 977, 1215, 1967, 7297, 14815, 27009, 35001, 89671}},
-{6886, 17, 9864, {1, 1, 7, 11, 13, 21, 33, 151, 195, 373, 181, 1631, 355, 7857, 12555, 7531, 50417}},
-{6887, 17, 9877, {1, 3, 1, 15, 19, 25, 79, 195, 237, 385, 1531, 2509, 4371, 16103, 3575, 62265, 124251}},
-{6888, 17, 9884, {1, 3, 1, 11, 5, 61, 21, 159, 51, 37, 845, 3075, 8039, 14269, 10505, 36369, 73793}},
-{6889, 17, 9888, {1, 3, 5, 9, 11, 43, 67, 57, 271, 451, 989, 3705, 2481, 10717, 10861, 63785, 10183}},
-{6890, 17, 9897, {1, 3, 3, 5, 13, 29, 119, 171, 439, 459, 479, 3173, 3781, 11131, 6827, 53925, 119939}},
-{6891, 17, 9915, {1, 3, 7, 3, 27, 21, 1, 167, 79, 305, 1283, 1903, 5483, 5727, 17911, 16075, 97629}},
-{6892, 17, 9925, {1, 3, 1, 3, 23, 21, 29, 185, 227, 295, 915, 2033, 6269, 2089, 20785, 15207, 115675}},
-{6893, 17, 9949, {1, 3, 7, 15, 11, 15, 65, 103, 249, 27, 1805, 2079, 4797, 2535, 16865, 61449, 90923}},
-{6894, 17, 9954, {1, 3, 7, 9, 27, 41, 77, 181, 457, 677, 633, 1601, 8085, 2431, 7957, 55913, 38677}},
-{6895, 17, 9960, {1, 1, 5, 7, 11, 37, 3, 221, 79, 895, 1023, 653, 3925, 12755, 19729, 18221, 91123}},
-{6896, 17, 9965, {1, 3, 1, 5, 23, 61, 119, 191, 425, 41, 853, 3497, 6915, 1927, 5513, 55303, 4895}},
-{6897, 17, 9978, {1, 3, 5, 3, 7, 35, 47, 243, 167, 821, 267, 2149, 5797, 6329, 32495, 51037, 18313}},
-{6898, 17, 9986, {1, 1, 7, 9, 23, 29, 79, 205, 115, 839, 1217, 479, 1601, 9681, 1, 35293, 28731}},
-{6899, 17, 9992, {1, 3, 3, 5, 31, 17, 31, 161, 35, 953, 377, 451, 7985, 11371, 15115, 60131, 27033}},
-{6900, 17, 9995, {1, 1, 3, 9, 15, 19, 43, 215, 327, 429, 145, 1837, 725, 14775, 10465, 7367, 21271}},
-{6901, 17, 10005, {1, 3, 7, 13, 31, 17, 85, 49, 487, 795, 1679, 599, 3783, 3195, 2683, 53475, 38603}},
-{6902, 17, 10026, {1, 1, 1, 7, 19, 11, 71, 143, 443, 199, 1117, 3445, 6429, 12037, 13751, 43609, 101563}},
-{6903, 17, 10031, {1, 3, 5, 7, 29, 63, 65, 87, 305, 721, 851, 2235, 4987, 3051, 23015, 1281, 15755}},
-{6904, 17, 10040, {1, 1, 3, 9, 17, 3, 57, 47, 223, 305, 1409, 235, 4379, 5779, 27695, 22535, 9387}},
-{6905, 17, 10051, {1, 1, 3, 11, 25, 33, 75, 141, 155, 699, 85, 1729, 2551, 7101, 7739, 18025, 100819}},
-{6906, 17, 10057, {1, 3, 3, 13, 5, 45, 63, 83, 141, 383, 1931, 3343, 7397, 4823, 28893, 41279, 67805}},
-{6907, 17, 10072, {1, 3, 5, 7, 19, 29, 97, 67, 177, 583, 1783, 4007, 5087, 805, 30999, 23197, 117553}},
-{6908, 17, 10096, {1, 3, 5, 1, 25, 41, 33, 109, 511, 449, 653, 995, 5881, 2163, 13689, 54385, 97419}},
-{6909, 17, 10102, {1, 3, 3, 13, 25, 17, 49, 77, 497, 659, 783, 3513, 3735, 3541, 573, 50237, 99247}},
-{6910, 17, 10105, {1, 3, 1, 7, 17, 13, 37, 169, 19, 965, 289, 455, 6855, 11233, 7553, 7007, 57389}},
-{6911, 17, 10115, {1, 1, 7, 11, 5, 15, 11, 177, 75, 243, 453, 3861, 3091, 4625, 12489, 11537, 74199}},
-{6912, 17, 10124, {1, 1, 5, 13, 17, 21, 23, 57, 343, 985, 1755, 3947, 3899, 11847, 19321, 62295, 51265}},
-{6913, 17, 10139, {1, 1, 3, 9, 19, 37, 31, 243, 433, 725, 535, 3733, 33, 7885, 1425, 41919, 66507}},
-{6914, 17, 10145, {1, 3, 5, 11, 15, 11, 25, 255, 93, 33, 71, 2389, 1855, 317, 12773, 13311, 81927}},
-{6915, 17, 10148, {1, 3, 1, 3, 7, 55, 21, 175, 357, 235, 1679, 931, 2051, 14213, 20539, 38049, 122513}},
-{6916, 17, 10157, {1, 1, 5, 15, 5, 51, 127, 79, 297, 135, 1423, 2783, 7229, 14451, 27619, 7299, 49189}},
-{6917, 17, 10158, {1, 1, 1, 3, 5, 13, 9, 209, 455, 483, 1745, 323, 789, 7645, 26373, 61659, 23671}},
-{6918, 17, 10163, {1, 1, 1, 9, 23, 63, 99, 91, 377, 275, 275, 3005, 1563, 5945, 23825, 33211, 52753}},
-{6919, 17, 10180, {1, 1, 1, 1, 31, 55, 31, 109, 481, 581, 771, 197, 6155, 3465, 8451, 25925, 41159}},
-{6920, 17, 10187, {1, 3, 7, 13, 5, 33, 113, 161, 265, 493, 1723, 513, 5111, 10177, 21755, 5321, 58831}},
-{6921, 17, 10198, {1, 1, 7, 1, 21, 33, 117, 183, 89, 689, 1253, 2215, 6565, 3079, 16343, 22427, 96447}},
-{6922, 17, 10208, {1, 1, 1, 5, 15, 61, 5, 139, 111, 463, 573, 1907, 4615, 14975, 5715, 51017, 69827}},
-{6923, 17, 10214, {1, 1, 1, 13, 3, 3, 117, 249, 25, 361, 1177, 2901, 1601, 11381, 18981, 44811, 47117}},
-{6924, 17, 10220, {1, 1, 5, 3, 29, 5, 49, 221, 247, 57, 553, 1889, 479, 15581, 7035, 7293, 53065}},
-{6925, 17, 10237, {1, 3, 3, 3, 15, 49, 91, 187, 213, 981, 1417, 211, 3719, 13693, 17671, 16691, 57147}},
-{6926, 17, 10238, {1, 1, 7, 9, 7, 17, 109, 185, 459, 769, 1783, 899, 885, 2291, 30023, 26315, 7337}},
-{6927, 17, 10241, {1, 1, 5, 11, 11, 31, 73, 191, 95, 25, 1953, 1387, 1077, 7547, 9661, 57739, 76799}},
-{6928, 17, 10244, {1, 1, 7, 13, 23, 41, 69, 177, 407, 699, 1055, 3653, 1239, 8113, 12823, 1803, 117815}},
-{6929, 17, 10251, {1, 1, 1, 15, 1, 55, 71, 133, 401, 593, 605, 2855, 4569, 3533, 14141, 65457, 125655}},
-{6930, 17, 10253, {1, 1, 7, 9, 31, 55, 53, 11, 65, 17, 561, 925, 1561, 8929, 19859, 57111, 12777}},
-{6931, 17, 10256, {1, 3, 3, 11, 7, 59, 125, 205, 473, 655, 1429, 337, 6829, 7551, 27873, 11667, 39231}},
-{6932, 17, 10259, {1, 3, 3, 9, 13, 23, 25, 161, 443, 545, 1967, 1895, 6929, 5975, 17801, 41769, 30429}},
-{6933, 17, 10266, {1, 3, 7, 13, 15, 1, 99, 43, 45, 451, 21, 639, 7121, 4781, 2813, 419, 17761}},
-{6934, 17, 10284, {1, 1, 5, 13, 11, 9, 53, 83, 443, 441, 1601, 3177, 1913, 12211, 25835, 1733, 4793}},
-{6935, 17, 10290, {1, 3, 3, 1, 13, 15, 11, 187, 471, 699, 1751, 3279, 2305, 15259, 31541, 21357, 73763}},
-{6936, 17, 10331, {1, 3, 5, 9, 23, 11, 125, 57, 261, 479, 879, 719, 3221, 2943, 10593, 11521, 83979}},
-{6937, 17, 10334, {1, 3, 7, 13, 3, 39, 119, 135, 85, 417, 1675, 971, 7577, 12709, 20407, 26105, 97021}},
-{6938, 17, 10350, {1, 1, 5, 11, 15, 63, 83, 141, 281, 663, 1745, 2775, 5605, 9127, 553, 7177, 115969}},
-{6939, 17, 10355, {1, 1, 7, 1, 19, 47, 7, 165, 87, 95, 361, 1879, 6351, 2861, 9103, 37489, 24525}},
-{6940, 17, 10357, {1, 3, 3, 11, 9, 21, 51, 149, 375, 967, 1583, 1427, 1223, 11611, 7481, 36619, 128429}},
-{6941, 17, 10367, {1, 1, 5, 1, 3, 31, 7, 217, 453, 565, 1517, 2847, 6937, 1197, 24339, 44311, 66843}},
-{6942, 17, 10368, {1, 1, 5, 3, 3, 17, 127, 59, 3, 905, 531, 1179, 3559, 5175, 24627, 60941, 129457}},
-{6943, 17, 10377, {1, 1, 1, 7, 15, 15, 1, 31, 373, 643, 279, 3831, 4881, 9763, 17641, 43219, 83109}},
-{6944, 17, 10388, {1, 3, 3, 9, 5, 21, 41, 71, 371, 201, 573, 1481, 3631, 10783, 6679, 1089, 117347}},
-{6945, 17, 10407, {1, 1, 7, 7, 5, 25, 73, 63, 173, 197, 147, 981, 1491, 1597, 11733, 14285, 74021}},
-{6946, 17, 10421, {1, 1, 5, 11, 17, 15, 3, 175, 391, 503, 1745, 319, 791, 5607, 18173, 37319, 92025}},
-{6947, 17, 10434, {1, 3, 1, 1, 9, 37, 43, 81, 439, 951, 805, 251, 4625, 15617, 13715, 62263, 3827}},
-{6948, 17, 10439, {1, 3, 1, 1, 25, 21, 67, 191, 499, 205, 1355, 105, 1637, 563, 22291, 9045, 6545}},
-{6949, 17, 10440, {1, 1, 5, 5, 9, 3, 75, 75, 287, 303, 1767, 1789, 3437, 4637, 9605, 2537, 64935}},
-{6950, 17, 10443, {1, 1, 3, 3, 1, 51, 27, 155, 375, 149, 885, 187, 1551, 13109, 27011, 57301, 41047}},
-{6951, 17, 10446, {1, 1, 7, 5, 21, 23, 1, 81, 163, 231, 2039, 1519, 1279, 15379, 25549, 6711, 81499}},
-{6952, 17, 10457, {1, 1, 3, 5, 3, 37, 71, 243, 165, 365, 379, 351, 4649, 4287, 13395, 30329, 78383}},
-{6953, 17, 10469, {1, 3, 1, 1, 25, 63, 27, 215, 223, 699, 2029, 3737, 5947, 7287, 20813, 4931, 19345}},
-{6954, 17, 10476, {1, 1, 3, 15, 21, 7, 25, 187, 219, 53, 1749, 1797, 3533, 14307, 53, 11095, 75469}},
-{6955, 17, 10479, {1, 1, 3, 13, 27, 31, 91, 121, 481, 291, 915, 535, 4291, 5271, 12181, 55921, 125917}},
-{6956, 17, 10481, {1, 3, 1, 1, 3, 29, 21, 251, 361, 747, 997, 2989, 1809, 7235, 17855, 31027, 100689}},
-{6957, 17, 10494, {1, 3, 7, 1, 21, 13, 49, 93, 183, 673, 881, 1931, 7009, 2565, 26021, 53815, 19807}},
-{6958, 17, 10501, {1, 1, 7, 13, 9, 23, 47, 237, 487, 843, 1357, 919, 1753, 903, 2911, 31527, 73027}},
-{6959, 17, 10505, {1, 1, 1, 1, 25, 33, 97, 241, 421, 375, 73, 2541, 6231, 14659, 15335, 5915, 110791}},
-{6960, 17, 10516, {1, 3, 3, 7, 21, 17, 97, 125, 7, 271, 167, 475, 4887, 1847, 30173, 25913, 36659}},
-{6961, 17, 10532, {1, 1, 3, 15, 15, 37, 67, 5, 463, 423, 823, 941, 1551, 14175, 15377, 6017, 118297}},
-{6962, 17, 10541, {1, 1, 1, 7, 31, 51, 71, 127, 73, 517, 881, 3205, 6219, 11213, 14783, 64275, 70033}},
-{6963, 17, 10547, {1, 3, 1, 5, 17, 17, 57, 107, 359, 999, 1415, 757, 4743, 7775, 14111, 20075, 73269}},
-{6964, 17, 10550, {1, 3, 5, 3, 21, 57, 87, 43, 307, 777, 717, 3329, 4159, 12545, 31355, 31329, 41377}},
-{6965, 17, 10591, {1, 3, 7, 15, 25, 43, 19, 147, 487, 517, 977, 3625, 2311, 14173, 15167, 56563, 110417}},
-{6966, 17, 10597, {1, 3, 3, 11, 23, 1, 67, 157, 461, 169, 231, 1977, 5657, 865, 711, 24213, 76895}},
-{6967, 17, 10602, {1, 1, 7, 13, 5, 37, 51, 165, 331, 97, 431, 3819, 1379, 12083, 27521, 19689, 100119}},
-{6968, 17, 10610, {1, 1, 7, 15, 29, 21, 59, 193, 397, 467, 951, 3037, 2955, 13235, 20981, 63865, 30069}},
-{6969, 17, 10619, {1, 3, 3, 5, 7, 49, 41, 143, 319, 71, 353, 2159, 3043, 15317, 24095, 12017, 64393}},
-{6970, 17, 10631, {1, 1, 5, 13, 25, 45, 57, 153, 311, 805, 953, 1763, 5655, 3961, 12085, 58761, 76533}},
-{6971, 17, 10646, {1, 1, 3, 15, 29, 19, 71, 107, 203, 221, 1173, 1597, 1179, 9649, 21659, 10463, 8195}},
-{6972, 17, 10655, {1, 1, 3, 9, 31, 29, 53, 151, 247, 577, 543, 459, 8141, 5613, 12029, 24199, 118603}},
-{6973, 17, 10665, {1, 3, 1, 5, 1, 55, 103, 23, 405, 5, 181, 3805, 1103, 13389, 6725, 48733, 99639}},
-{6974, 17, 10673, {1, 1, 5, 9, 1, 47, 115, 231, 151, 885, 427, 2849, 361, 12969, 705, 41711, 53587}},
-{6975, 17, 10674, {1, 1, 3, 11, 9, 3, 11, 231, 77, 775, 657, 2721, 3431, 11919, 10425, 29405, 91561}},
-{6976, 17, 10680, {1, 1, 1, 5, 5, 7, 79, 41, 181, 333, 963, 3117, 7703, 2259, 16671, 51139, 27997}},
-{6977, 17, 10693, {1, 3, 7, 7, 13, 55, 59, 157, 377, 711, 1475, 1509, 1375, 6825, 13729, 28613, 109199}},
-{6978, 17, 10700, {1, 3, 3, 3, 13, 11, 51, 1, 67, 609, 467, 2161, 7693, 9019, 1847, 27969, 74863}},
-{6979, 17, 10721, {1, 1, 3, 3, 11, 33, 87, 217, 239, 505, 1451, 2801, 1417, 695, 29883, 15877, 99969}},
-{6980, 17, 10727, {1, 3, 3, 5, 3, 61, 9, 171, 57, 547, 2003, 2335, 2259, 3205, 5639, 21721, 25893}},
-{6981, 17, 10746, {1, 3, 1, 3, 19, 15, 83, 69, 47, 897, 627, 2839, 7123, 8567, 14707, 13159, 125139}},
-{6982, 17, 10748, {1, 3, 7, 11, 1, 59, 53, 33, 135, 1009, 1829, 3011, 1245, 421, 28909, 45517, 55071}},
-{6983, 17, 10757, {1, 1, 5, 9, 3, 27, 11, 243, 235, 683, 1329, 3145, 2141, 14027, 3707, 5933, 51965}},
-{6984, 17, 10761, {1, 1, 5, 7, 13, 63, 79, 105, 27, 195, 1657, 3107, 1245, 1681, 29619, 10589, 78197}},
-{6985, 17, 10770, {1, 3, 3, 7, 21, 1, 5, 79, 73, 125, 1587, 3053, 5977, 10745, 28343, 39023, 56201}},
-{6986, 17, 10776, {1, 1, 3, 15, 23, 21, 39, 41, 173, 913, 1267, 1323, 2967, 1979, 16763, 53753, 21905}},
-{6987, 17, 10782, {1, 1, 5, 7, 11, 11, 117, 151, 409, 345, 1461, 1703, 687, 557, 31651, 35507, 54909}},
-{6988, 17, 10791, {1, 1, 1, 15, 15, 49, 55, 223, 289, 765, 1737, 1117, 3717, 15465, 31949, 55061, 97091}},
-{6989, 17, 10792, {1, 1, 5, 9, 21, 29, 99, 13, 119, 35, 1461, 61, 5155, 6785, 15957, 11295, 52203}},
-{6990, 17, 10805, {1, 3, 5, 7, 23, 39, 73, 161, 465, 715, 153, 3529, 2243, 13773, 16573, 26233, 130263}},
-{6991, 17, 10810, {1, 3, 7, 9, 11, 51, 5, 149, 501, 119, 2047, 3417, 3955, 15055, 31633, 473, 127305}},
-{6992, 17, 10832, {1, 1, 1, 9, 31, 57, 91, 119, 215, 11, 1013, 3969, 1285, 11521, 8039, 36737, 86365}},
-{6993, 17, 10835, {1, 1, 5, 3, 7, 17, 9, 27, 59, 883, 541, 3027, 6219, 1091, 2453, 38247, 21323}},
-{6994, 17, 10841, {1, 1, 1, 1, 25, 39, 55, 249, 61, 313, 467, 1763, 4067, 8367, 32431, 44463, 66439}},
-{6995, 17, 10842, {1, 3, 3, 1, 13, 3, 37, 209, 21, 653, 1971, 3649, 6165, 3789, 12793, 56327, 60351}},
-{6996, 17, 10847, {1, 1, 7, 9, 31, 33, 21, 51, 313, 631, 515, 1761, 4149, 2601, 12481, 25975, 94061}},
-{6997, 17, 10853, {1, 1, 7, 15, 3, 7, 55, 129, 297, 735, 779, 633, 3265, 11713, 3893, 61197, 113991}},
-{6998, 17, 10860, {1, 3, 5, 13, 1, 15, 27, 253, 435, 595, 1163, 2753, 7399, 15225, 26215, 59753, 74933}},
-{6999, 17, 10871, {1, 1, 7, 7, 15, 23, 111, 43, 467, 957, 1687, 2893, 2315, 2025, 1475, 9061, 101611}},
-{7000, 17, 10878, {1, 1, 3, 3, 29, 41, 53, 169, 125, 415, 361, 869, 3399, 8821, 18193, 38575, 73979}},
-{7001, 17, 10881, {1, 1, 1, 15, 3, 5, 27, 5, 293, 765, 1809, 1961, 955, 12441, 10915, 2363, 49617}},
-{7002, 17, 10888, {1, 1, 5, 15, 19, 11, 3, 91, 59, 323, 545, 1177, 7967, 2729, 14085, 3283, 79859}},
-{7003, 17, 10894, {1, 1, 7, 13, 11, 17, 29, 163, 295, 951, 311, 3471, 1339, 10719, 701, 32377, 41685}},
-{7004, 17, 10901, {1, 3, 5, 7, 21, 19, 81, 247, 495, 767, 251, 3455, 6383, 7221, 19943, 64865, 33193}},
-{7005, 17, 10915, {1, 1, 7, 15, 23, 41, 63, 195, 311, 619, 211, 743, 889, 7627, 12527, 15865, 40103}},
-{7006, 17, 10918, {1, 1, 3, 1, 23, 23, 57, 221, 153, 27, 939, 3949, 411, 6357, 31985, 939, 91001}},
-{7007, 17, 10922, {1, 3, 5, 15, 7, 5, 35, 135, 245, 921, 307, 823, 775, 4891, 24575, 53503, 48147}},
-{7008, 17, 10936, {1, 1, 5, 7, 9, 31, 23, 139, 477, 495, 287, 807, 1855, 8321, 13963, 52197, 78509}},
-{7009, 17, 10954, {1, 3, 3, 3, 29, 59, 33, 83, 211, 65, 623, 1269, 1745, 16383, 10759, 57199, 14035}},
-{7010, 17, 10968, {1, 3, 3, 15, 25, 55, 69, 171, 411, 937, 731, 2275, 2597, 4133, 5089, 50507, 39989}},
-{7011, 17, 10971, {1, 3, 1, 9, 5, 47, 51, 21, 171, 913, 233, 43, 2673, 471, 27077, 57039, 32579}},
-{7012, 17, 10973, {1, 3, 5, 3, 29, 35, 5, 105, 233, 379, 77, 1775, 2409, 4597, 19879, 12691, 49739}},
-{7013, 17, 10978, {1, 3, 7, 13, 17, 29, 117, 177, 163, 927, 45, 3227, 7263, 5551, 9219, 32101, 122473}},
-{7014, 17, 10998, {1, 1, 7, 5, 31, 39, 75, 147, 311, 991, 1431, 3821, 6891, 9637, 17887, 661, 23067}},
-{7015, 17, 11009, {1, 3, 5, 13, 31, 53, 69, 79, 153, 329, 207, 479, 2395, 6505, 29553, 52023, 31531}},
-{7016, 17, 11021, {1, 3, 1, 7, 15, 7, 87, 233, 25, 275, 981, 1207, 3083, 16349, 30185, 60611, 120607}},
-{7017, 17, 11029, {1, 1, 5, 3, 21, 7, 47, 173, 291, 965, 65, 545, 7465, 4471, 2249, 34281, 107217}},
-{7018, 17, 11030, {1, 1, 3, 11, 19, 53, 17, 243, 193, 297, 1937, 1513, 4979, 14867, 15497, 10049, 9135}},
-{7019, 17, 11034, {1, 3, 1, 3, 25, 39, 29, 63, 231, 145, 247, 1745, 3439, 8635, 26687, 18595, 67123}},
-{7020, 17, 11050, {1, 1, 7, 9, 29, 33, 89, 175, 429, 675, 891, 1739, 3567, 5453, 30427, 33671, 83395}},
-{7021, 17, 11063, {1, 3, 1, 5, 31, 25, 69, 237, 235, 307, 1217, 3805, 153, 13387, 6209, 14179, 128725}},
-{7022, 17, 11064, {1, 1, 3, 3, 19, 45, 117, 135, 67, 601, 369, 3369, 5505, 2049, 24099, 22515, 96575}},
-{7023, 17, 11077, {1, 1, 1, 3, 3, 45, 29, 255, 327, 77, 1103, 4067, 2875, 6487, 5903, 26625, 19631}},
-{7024, 17, 11078, {1, 3, 5, 1, 31, 63, 115, 7, 255, 855, 913, 1779, 7001, 14387, 26765, 51987, 3191}},
-{7025, 17, 11105, {1, 1, 3, 11, 15, 43, 71, 247, 303, 231, 445, 3963, 3699, 11851, 18941, 43465, 63431}},
-{7026, 17, 11106, {1, 1, 3, 5, 31, 33, 93, 127, 267, 399, 653, 1997, 5005, 14535, 4813, 64065, 2159}},
-{7027, 17, 11126, {1, 3, 7, 13, 31, 39, 61, 155, 141, 515, 1217, 161, 4309, 3697, 22445, 43599, 43329}},
-{7028, 17, 11129, {1, 3, 3, 3, 7, 51, 103, 147, 511, 971, 195, 3731, 6629, 12125, 12053, 34951, 60059}},
-{7029, 17, 11135, {1, 1, 5, 11, 21, 49, 99, 31, 55, 309, 1805, 2253, 7095, 15265, 28445, 54813, 48615}},
-{7030, 17, 11151, {1, 3, 1, 15, 9, 41, 61, 125, 65, 143, 1567, 3259, 6757, 653, 31601, 63127, 52179}},
-{7031, 17, 11159, {1, 1, 5, 3, 29, 5, 19, 197, 153, 447, 7, 1713, 469, 6043, 1259, 63641, 29171}},
-{7032, 17, 11165, {1, 3, 3, 7, 3, 41, 95, 245, 445, 15, 607, 565, 2361, 2673, 21077, 20153, 6199}},
-{7033, 17, 11176, {1, 1, 5, 1, 5, 59, 93, 127, 485, 663, 683, 635, 1599, 16377, 31819, 6539, 27789}},
-{7034, 17, 11179, {1, 3, 1, 3, 31, 3, 11, 215, 441, 1005, 1815, 3945, 5109, 5539, 23935, 62671, 90731}},
-{7035, 17, 11182, {1, 3, 3, 1, 13, 47, 19, 229, 191, 427, 1141, 2321, 7105, 1587, 26347, 63265, 23377}},
-{7036, 17, 11189, {1, 1, 5, 15, 31, 55, 61, 93, 89, 945, 1203, 3631, 4457, 15097, 32019, 41747, 46009}},
-{7037, 17, 11204, {1, 1, 5, 13, 5, 33, 69, 59, 93, 247, 503, 421, 1923, 9855, 9825, 14257, 98663}},
-{7038, 17, 11216, {1, 3, 1, 13, 27, 21, 91, 39, 131, 571, 1527, 2715, 2061, 627, 19705, 47165, 84345}},
-{7039, 17, 11232, {1, 1, 1, 7, 3, 3, 7, 251, 225, 959, 1017, 2423, 6163, 1549, 7473, 3193, 104259}},
-{7040, 17, 11235, {1, 3, 3, 1, 5, 5, 115, 221, 505, 649, 1525, 2459, 167, 1899, 23939, 29253, 122835}},
-{7041, 17, 11242, {1, 3, 1, 5, 15, 9, 123, 221, 133, 43, 31, 1211, 4737, 5001, 20065, 6369, 93865}},
-{7042, 17, 11250, {1, 1, 5, 11, 11, 5, 23, 29, 333, 133, 1469, 1895, 5879, 15599, 2131, 25005, 96271}},
-{7043, 17, 11264, {1, 1, 3, 11, 25, 11, 19, 57, 397, 645, 1233, 2433, 6371, 10577, 15489, 60709, 3957}},
-{7044, 17, 11273, {1, 3, 1, 1, 19, 3, 33, 131, 429, 835, 1363, 2213, 3185, 14385, 8831, 43159, 32975}},
-{7045, 17, 11282, {1, 1, 5, 5, 23, 11, 127, 139, 213, 259, 897, 1913, 5737, 1287, 26617, 4885, 30193}},
-{7046, 17, 11288, {1, 3, 5, 13, 3, 27, 99, 31, 11, 27, 1003, 2473, 7055, 12923, 4269, 41433, 90637}},
-{7047, 17, 11291, {1, 3, 1, 7, 17, 25, 95, 151, 199, 237, 207, 1879, 2943, 9845, 3765, 53533, 111191}},
-{7048, 17, 11293, {1, 3, 1, 9, 19, 27, 5, 249, 85, 185, 1883, 1401, 2041, 12721, 20593, 30993, 2601}},
-{7049, 17, 11318, {1, 3, 3, 9, 23, 1, 15, 133, 387, 779, 707, 2723, 4485, 989, 27125, 37295, 125319}},
-{7050, 17, 11321, {1, 1, 7, 3, 9, 41, 81, 151, 349, 941, 357, 3817, 7123, 10079, 27519, 107, 102281}},
-{7051, 17, 11329, {1, 1, 1, 1, 13, 5, 111, 167, 73, 85, 1185, 1213, 333, 153, 13101, 38087, 39389}},
-{7052, 17, 11336, {1, 3, 3, 15, 11, 41, 99, 231, 377, 539, 1335, 1059, 5373, 9611, 27927, 29801, 85749}},
-{7053, 17, 11339, {1, 3, 1, 9, 19, 37, 125, 27, 15, 699, 1867, 2711, 1589, 1675, 32007, 61339, 96919}},
-{7054, 17, 11342, {1, 3, 3, 3, 3, 27, 21, 159, 249, 783, 1517, 2923, 2609, 1207, 13705, 57371, 43603}},
-{7055, 17, 11356, {1, 1, 5, 15, 17, 55, 77, 1, 401, 897, 987, 345, 5283, 5827, 17755, 44371, 13253}},
-{7056, 17, 11383, {1, 3, 1, 7, 3, 3, 99, 237, 487, 405, 771, 3503, 1199, 4779, 26893, 45821, 46383}},
-{7057, 17, 11389, {1, 1, 7, 3, 9, 47, 81, 27, 459, 989, 1891, 3997, 4081, 4075, 15079, 65081, 125185}},
-{7058, 17, 11405, {1, 3, 5, 9, 25, 23, 71, 251, 251, 197, 353, 3553, 2165, 2953, 3733, 52369, 100641}},
-{7059, 17, 11411, {1, 1, 1, 5, 25, 43, 63, 187, 495, 345, 1547, 2293, 7327, 7797, 14001, 61865, 40329}},
-{7060, 17, 11423, {1, 1, 5, 15, 25, 37, 67, 23, 315, 801, 71, 1235, 7293, 7207, 30929, 9417, 94735}},
-{7061, 17, 11424, {1, 1, 1, 3, 23, 29, 87, 171, 337, 457, 1597, 3933, 4151, 1237, 19563, 56997, 81497}},
-{7062, 17, 11430, {1, 3, 3, 11, 3, 33, 79, 239, 277, 611, 205, 2283, 7459, 425, 21999, 26491, 58681}},
-{7063, 17, 11444, {1, 1, 7, 1, 5, 37, 53, 93, 205, 97, 779, 3623, 7777, 521, 21915, 46539, 128811}},
-{7064, 17, 11447, {1, 1, 5, 7, 19, 7, 39, 183, 299, 193, 1351, 3867, 5709, 11655, 1231, 15555, 128023}},
-{7065, 17, 11459, {1, 3, 7, 11, 31, 13, 113, 57, 197, 841, 921, 2087, 2195, 8279, 8353, 1955, 22121}},
-{7066, 17, 11465, {1, 3, 3, 11, 21, 55, 61, 105, 357, 747, 363, 3511, 2547, 16283, 25747, 56041, 33695}},
-{7067, 17, 11473, {1, 3, 3, 13, 27, 13, 5, 27, 93, 691, 1869, 2331, 3131, 14411, 2355, 37195, 129273}},
-{7068, 17, 11479, {1, 3, 3, 7, 27, 9, 11, 165, 435, 811, 215, 1617, 347, 4289, 29373, 15749, 91445}},
-{7069, 17, 11501, {1, 1, 7, 13, 29, 3, 95, 53, 457, 633, 959, 3705, 7461, 9307, 21963, 51599, 6751}},
-{7070, 17, 11510, {1, 1, 1, 15, 29, 25, 95, 1, 125, 61, 683, 2067, 6485, 9095, 5571, 61281, 70865}},
-{7071, 17, 11514, {1, 1, 7, 7, 1, 35, 119, 107, 247, 991, 237, 1865, 3961, 12583, 11417, 14913, 90897}},
-{7072, 17, 11522, {1, 3, 7, 15, 11, 51, 73, 193, 289, 381, 1767, 3803, 3197, 3797, 15059, 19393, 98947}},
-{7073, 17, 11527, {1, 1, 5, 3, 13, 7, 91, 223, 347, 59, 1721, 1501, 6391, 4141, 14495, 47283, 47237}},
-{7074, 17, 11533, {1, 3, 7, 11, 17, 39, 43, 247, 35, 423, 1859, 3199, 5343, 7061, 8609, 6819, 88575}},
-{7075, 17, 11536, {1, 1, 5, 13, 31, 27, 57, 19, 499, 1007, 1965, 795, 1231, 12755, 24631, 53343, 82305}},
-{7076, 17, 11548, {1, 1, 1, 9, 13, 23, 127, 161, 245, 467, 2025, 2545, 3085, 13035, 27087, 14461, 35971}},
-{7077, 17, 11551, {1, 3, 5, 1, 7, 3, 99, 159, 75, 341, 1755, 2337, 5981, 5055, 19445, 30043, 61427}},
-{7078, 17, 11552, {1, 1, 1, 7, 13, 33, 41, 73, 267, 21, 961, 3509, 6839, 13215, 8471, 46735, 93071}},
-{7079, 17, 11555, {1, 3, 7, 7, 3, 25, 81, 239, 357, 445, 1483, 389, 3891, 5131, 21357, 34757, 111063}},
-{7080, 17, 11572, {1, 3, 7, 1, 1, 37, 119, 121, 195, 935, 1711, 2049, 7001, 7117, 9957, 7309, 102293}},
-{7081, 17, 11587, {1, 1, 7, 11, 1, 49, 107, 95, 149, 329, 289, 1121, 7217, 15091, 19071, 13801, 13}},
-{7082, 17, 11601, {1, 1, 1, 13, 17, 17, 7, 105, 81, 1017, 1867, 1567, 5133, 7325, 19797, 16301, 40471}},
-{7083, 17, 11613, {1, 3, 5, 5, 27, 45, 117, 135, 499, 53, 973, 121, 53, 8771, 11893, 35827, 57691}},
-{7084, 17, 11614, {1, 1, 1, 1, 7, 23, 11, 163, 17, 871, 129, 2959, 5583, 12253, 1419, 28367, 32539}},
-{7085, 17, 11618, {1, 1, 3, 5, 23, 31, 127, 33, 115, 799, 331, 1873, 1729, 1383, 23601, 51145, 72027}},
-{7086, 17, 11624, {1, 1, 1, 9, 15, 49, 105, 163, 51, 539, 451, 3983, 6509, 1073, 30757, 13971, 51371}},
-{7087, 17, 11630, {1, 1, 7, 1, 1, 57, 71, 135, 5, 171, 983, 951, 777, 9257, 3607, 3239, 76237}},
-{7088, 17, 11663, {1, 1, 7, 7, 21, 17, 49, 175, 9, 807, 289, 2777, 7309, 14911, 28349, 43871, 96019}},
-{7089, 17, 11682, {1, 3, 1, 13, 5, 7, 83, 215, 297, 319, 347, 633, 7285, 8293, 18811, 31065, 114077}},
-{7090, 17, 11684, {1, 3, 1, 11, 3, 29, 91, 231, 161, 601, 355, 2719, 2941, 6065, 21849, 58051, 46515}},
-{7091, 17, 11702, {1, 1, 3, 9, 25, 41, 111, 135, 71, 755, 29, 131, 1339, 5053, 15713, 14557, 106777}},
-{7092, 17, 11705, {1, 1, 7, 13, 21, 59, 13, 45, 503, 71, 1611, 4021, 2359, 11653, 7261, 14537, 33031}},
-{7093, 17, 11713, {1, 1, 1, 11, 5, 31, 1, 181, 37, 527, 1345, 1979, 4899, 3289, 25181, 49959, 44609}},
-{7094, 17, 11731, {1, 3, 3, 13, 21, 25, 33, 105, 57, 637, 841, 1595, 3881, 5053, 9441, 58717, 127255}},
-{7095, 17, 11734, {1, 3, 5, 7, 23, 57, 9, 117, 281, 769, 1573, 2857, 1139, 6413, 14001, 21097, 55215}},
-{7096, 17, 11740, {1, 1, 7, 7, 3, 5, 75, 149, 269, 353, 437, 61, 2451, 11987, 17243, 5649, 105107}},
-{7097, 17, 11747, {1, 1, 3, 3, 25, 61, 53, 21, 113, 57, 1415, 2825, 11, 14977, 6159, 4181, 96765}},
-{7098, 17, 11754, {1, 1, 7, 5, 15, 25, 121, 159, 71, 773, 601, 147, 6507, 16171, 16607, 32017, 77845}},
-{7099, 17, 11761, {1, 3, 1, 1, 27, 19, 59, 109, 347, 991, 165, 683, 6147, 493, 22017, 19069, 52857}},
-{7100, 17, 11762, {1, 1, 5, 5, 21, 1, 93, 115, 407, 15, 421, 1305, 3495, 14287, 31831, 65347, 35339}},
-{7101, 17, 11787, {1, 3, 5, 11, 29, 35, 87, 27, 453, 769, 1991, 2757, 2607, 9225, 293, 49441, 18185}},
-{7102, 17, 11792, {1, 1, 5, 3, 23, 41, 67, 195, 499, 903, 197, 1121, 4691, 9277, 29225, 34597, 37395}},
-{7103, 17, 11814, {1, 1, 7, 7, 21, 7, 65, 245, 241, 909, 1063, 2271, 1979, 10287, 1747, 61523, 72969}},
-{7104, 17, 11823, {1, 3, 1, 13, 23, 25, 3, 89, 385, 481, 1463, 3431, 6907, 1129, 3519, 35789, 82585}},
-{7105, 17, 11825, {1, 3, 5, 3, 31, 17, 11, 209, 77, 991, 885, 3341, 6895, 3429, 21611, 38555, 35475}},
-{7106, 17, 11837, {1, 1, 3, 1, 9, 61, 27, 219, 433, 787, 281, 1155, 2915, 4449, 30881, 34461, 15357}},
-{7107, 17, 11838, {1, 1, 3, 15, 27, 55, 51, 101, 117, 799, 1475, 4013, 5145, 14991, 27847, 49537, 57339}},
-{7108, 17, 11846, {1, 3, 7, 13, 13, 9, 13, 167, 283, 883, 1501, 2635, 1463, 3353, 14961, 30349, 62043}},
-{7109, 17, 11855, {1, 1, 7, 3, 3, 47, 119, 37, 389, 655, 701, 2471, 5749, 6645, 845, 27065, 82299}},
-{7110, 17, 11864, {1, 1, 7, 15, 27, 5, 95, 195, 227, 991, 1137, 3715, 4901, 9459, 1917, 43857, 126505}},
-{7111, 17, 11876, {1, 3, 7, 5, 29, 35, 45, 165, 361, 257, 641, 1265, 6533, 11333, 26081, 12621, 66909}},
-{7112, 17, 11885, {1, 1, 1, 11, 19, 55, 73, 137, 29, 355, 725, 1161, 6717, 2035, 19769, 43531, 72577}},
-{7113, 17, 11904, {1, 3, 7, 5, 19, 3, 99, 17, 387, 621, 137, 117, 6567, 7667, 14979, 17981, 68319}},
-{7114, 17, 11909, {1, 1, 5, 5, 7, 53, 31, 33, 245, 371, 691, 2763, 95, 16369, 7853, 29839, 34957}},
-{7115, 17, 11913, {1, 1, 3, 1, 9, 1, 83, 177, 17, 141, 1739, 1791, 3849, 3093, 22271, 53755, 7817}},
-{7116, 17, 11916, {1, 3, 3, 1, 3, 51, 71, 69, 439, 987, 807, 3353, 4747, 16031, 29591, 61091, 95675}},
-{7117, 17, 11940, {1, 3, 5, 1, 17, 47, 51, 211, 7, 5, 1751, 1735, 1647, 13389, 13861, 49427, 13577}},
-{7118, 17, 11943, {1, 3, 7, 5, 11, 23, 17, 55, 11, 61, 809, 927, 6533, 1509, 29261, 21555, 55075}},
-{7119, 17, 11972, {1, 3, 1, 1, 15, 51, 37, 47, 183, 117, 597, 3225, 1435, 13359, 19127, 17339, 17345}},
-{7120, 17, 11981, {1, 1, 5, 3, 5, 11, 33, 179, 295, 129, 29, 713, 1561, 27, 21087, 50305, 39253}},
-{7121, 17, 11990, {1, 1, 5, 7, 17, 25, 105, 241, 41, 915, 1223, 2625, 617, 10983, 10749, 2137, 101831}},
-{7122, 17, 11993, {1, 3, 5, 7, 15, 15, 85, 23, 193, 625, 1803, 2903, 1935, 523, 8377, 12165, 105851}},
-{7123, 17, 12000, {1, 3, 3, 7, 3, 35, 5, 107, 191, 855, 405, 1659, 5523, 5011, 6401, 45187, 31345}},
-{7124, 17, 12005, {1, 3, 3, 1, 9, 21, 103, 75, 501, 669, 547, 3685, 411, 2663, 14743, 13869, 124389}},
-{7125, 17, 12015, {1, 3, 5, 13, 15, 37, 39, 79, 19, 165, 1685, 1367, 5951, 12303, 13423, 51083, 119933}},
-{7126, 17, 12020, {1, 1, 3, 1, 7, 25, 1, 221, 415, 591, 859, 1457, 1789, 2269, 15947, 31913, 86397}},
-{7127, 17, 12038, {1, 3, 7, 15, 11, 49, 15, 171, 45, 925, 407, 1719, 4505, 5695, 17397, 28849, 77}},
-{7128, 17, 12042, {1, 1, 3, 11, 21, 33, 91, 115, 263, 141, 753, 3335, 7695, 1981, 6029, 22629, 2467}},
-{7129, 17, 12056, {1, 3, 5, 3, 25, 5, 21, 67, 429, 323, 223, 2395, 761, 14817, 12387, 37905, 19551}},
-{7130, 17, 12065, {1, 3, 1, 15, 31, 43, 35, 255, 73, 533, 1093, 965, 557, 607, 6913, 35283, 12261}},
-{7131, 17, 12066, {1, 3, 1, 15, 25, 13, 39, 83, 77, 269, 1205, 1577, 4095, 6669, 8643, 48807, 98227}},
-{7132, 17, 12072, {1, 3, 3, 7, 31, 57, 25, 177, 441, 973, 1255, 675, 5579, 4899, 27925, 52555, 70845}},
-{7133, 17, 12080, {1, 3, 1, 5, 13, 47, 15, 75, 387, 461, 1909, 841, 7, 9567, 913, 41411, 12565}},
-{7134, 17, 12083, {1, 1, 5, 7, 5, 21, 17, 189, 319, 645, 403, 2723, 6747, 15471, 26533, 12709, 49417}},
-{7135, 17, 12090, {1, 1, 5, 7, 7, 41, 99, 179, 137, 435, 1061, 3987, 4583, 4101, 23781, 54263, 36695}},
-{7136, 17, 12092, {1, 3, 1, 11, 19, 37, 125, 177, 111, 921, 1003, 1433, 1399, 3991, 28193, 40471, 97041}},
-{7137, 17, 12103, {1, 1, 7, 1, 5, 33, 7, 139, 127, 413, 1171, 2237, 265, 10145, 18793, 28957, 25037}},
-{7138, 17, 12109, {1, 3, 1, 1, 25, 37, 13, 17, 471, 195, 1645, 3165, 5635, 8433, 28507, 453, 107709}},
-{7139, 17, 12112, {1, 3, 3, 11, 1, 55, 119, 97, 243, 371, 95, 97, 7833, 777, 12177, 1861, 56323}},
-{7140, 17, 12117, {1, 1, 7, 5, 7, 29, 59, 219, 405, 411, 275, 111, 4899, 10367, 24331, 57295, 47065}},
-{7141, 17, 12121, {1, 1, 3, 3, 19, 23, 91, 111, 221, 195, 1013, 3001, 3227, 6359, 30383, 49699, 49157}},
-{7142, 17, 12137, {1, 1, 5, 7, 1, 21, 125, 23, 177, 291, 249, 861, 1899, 14101, 5079, 5211, 14373}},
-{7143, 17, 12143, {1, 1, 7, 11, 11, 59, 33, 41, 291, 919, 253, 609, 1657, 14633, 15189, 22245, 99815}},
-{7144, 17, 12145, {1, 3, 5, 3, 23, 49, 71, 137, 393, 343, 1845, 343, 5853, 6639, 17435, 62143, 76041}},
-{7145, 17, 12148, {1, 1, 5, 3, 9, 27, 55, 193, 25, 965, 1453, 2739, 3785, 12497, 29607, 11111, 25145}},
-{7146, 17, 12168, {1, 1, 1, 1, 29, 11, 111, 73, 491, 629, 405, 2779, 5313, 589, 1459, 47555, 67945}},
-{7147, 17, 12174, {1, 3, 1, 7, 13, 21, 99, 75, 79, 963, 207, 1725, 6875, 8359, 10573, 45219, 130463}},
-{7148, 17, 12188, {1, 3, 7, 13, 1, 17, 105, 227, 487, 891, 1053, 1333, 7651, 5415, 18661, 22085, 82055}},
-{7149, 17, 12191, {1, 1, 3, 3, 31, 27, 91, 93, 383, 331, 965, 3035, 4931, 13265, 9729, 28985, 118227}},
-{7150, 17, 12192, {1, 3, 1, 1, 11, 9, 59, 191, 253, 909, 301, 3811, 255, 14937, 28627, 54509, 95993}},
-{7151, 17, 12201, {1, 3, 3, 5, 11, 5, 105, 77, 323, 713, 637, 1857, 2697, 12473, 12261, 2933, 101287}},
-{7152, 17, 12224, {1, 3, 3, 11, 9, 63, 19, 19, 213, 859, 1479, 2849, 1067, 5749, 13511, 14933, 11125}},
-{7153, 17, 12230, {1, 1, 5, 9, 19, 19, 13, 49, 237, 511, 533, 543, 575, 8095, 27335, 18847, 18173}},
-{7154, 17, 12239, {1, 3, 5, 5, 9, 53, 47, 157, 35, 827, 637, 2327, 787, 5269, 5145, 10135, 111273}},
-{7155, 17, 12242, {1, 3, 3, 7, 27, 41, 69, 173, 53, 655, 809, 481, 6999, 3101, 20781, 2481, 94957}},
-{7156, 17, 12251, {1, 1, 5, 11, 17, 23, 95, 201, 363, 613, 863, 1365, 1131, 15417, 20705, 8283, 55235}},
-{7157, 17, 12258, {1, 1, 5, 13, 3, 15, 37, 219, 291, 595, 1665, 1861, 1953, 15385, 20569, 46085, 15163}},
-{7158, 17, 12264, {1, 3, 3, 11, 23, 43, 125, 133, 85, 45, 819, 243, 7325, 8723, 1499, 58139, 120353}},
-{7159, 17, 12310, {1, 1, 1, 11, 21, 49, 91, 145, 175, 619, 1817, 3533, 8155, 7521, 30361, 45431, 130175}},
-{7160, 17, 12319, {1, 1, 3, 1, 11, 59, 57, 51, 37, 903, 1221, 3813, 8043, 14165, 31503, 7905, 61515}},
-{7161, 17, 12323, {1, 1, 1, 1, 15, 9, 115, 175, 285, 839, 97, 3119, 719, 15283, 22947, 25417, 40665}},
-{7162, 17, 12325, {1, 3, 1, 7, 5, 49, 127, 111, 373, 747, 393, 2351, 4577, 15227, 23149, 16901, 80253}},
-{7163, 17, 12332, {1, 1, 5, 3, 15, 5, 95, 197, 251, 275, 831, 1389, 3907, 12343, 11599, 24369, 65361}},
-{7164, 17, 12343, {1, 3, 7, 5, 25, 37, 11, 75, 417, 789, 745, 811, 2189, 15381, 4785, 41657, 2897}},
-{7165, 17, 12344, {1, 3, 1, 13, 29, 55, 55, 33, 279, 383, 1645, 975, 4683, 1357, 1149, 30271, 90527}},
-{7166, 17, 12352, {1, 3, 5, 3, 5, 3, 79, 61, 371, 225, 141, 369, 1037, 12249, 29431, 37253, 9899}},
-{7167, 17, 12370, {1, 1, 3, 13, 13, 7, 127, 147, 507, 119, 1085, 1949, 6289, 10179, 10107, 55989, 74395}},
-{7168, 17, 12388, {1, 3, 1, 7, 21, 35, 53, 209, 103, 365, 683, 553, 4977, 14371, 24037, 11453, 45369}},
-{7169, 17, 12395, {1, 1, 5, 11, 27, 39, 41, 145, 437, 55, 893, 2375, 4977, 5451, 21225, 46815, 1423}},
-{7170, 17, 12403, {1, 3, 5, 1, 23, 53, 113, 75, 209, 323, 1975, 3809, 1829, 14625, 3821, 53773, 129173}},
-{7171, 17, 12409, {1, 1, 5, 3, 7, 51, 97, 73, 289, 481, 339, 1375, 3101, 4395, 13933, 33267, 68115}},
-{7172, 17, 12410, {1, 3, 5, 1, 5, 45, 83, 57, 3, 667, 109, 3979, 6447, 8603, 20147, 49291, 18023}},
-{7173, 17, 12415, {1, 3, 7, 1, 11, 7, 45, 233, 65, 745, 1009, 2979, 5965, 10681, 3499, 23077, 87479}},
-{7174, 17, 12419, {1, 3, 3, 3, 13, 25, 25, 189, 197, 83, 1429, 2857, 2877, 8577, 24811, 33049, 46009}},
-{7175, 17, 12426, {1, 1, 1, 7, 11, 47, 47, 255, 89, 625, 449, 3747, 2035, 3509, 4901, 2961, 14073}},
-{7176, 17, 12439, {1, 1, 1, 13, 9, 55, 35, 47, 389, 573, 847, 1037, 1345, 5487, 7575, 57435, 77303}},
-{7177, 17, 12445, {1, 1, 5, 11, 25, 51, 113, 109, 79, 339, 95, 2049, 5881, 13209, 20041, 26419, 110319}},
-{7178, 17, 12459, {1, 1, 7, 1, 27, 15, 93, 145, 253, 917, 1211, 2221, 1087, 14209, 32097, 20083, 67841}},
-{7179, 17, 12464, {1, 1, 3, 15, 13, 19, 67, 107, 75, 919, 2047, 3675, 6231, 1243, 14335, 35939, 17281}},
-{7180, 17, 12474, {1, 3, 7, 5, 27, 47, 53, 239, 475, 231, 1645, 825, 4039, 15985, 10853, 32951, 34985}},
-{7181, 17, 12484, {1, 1, 7, 5, 15, 61, 107, 93, 51, 221, 717, 2859, 7885, 9571, 11841, 45143, 33723}},
-{7182, 17, 12491, {1, 1, 7, 7, 9, 25, 63, 25, 47, 55, 2041, 3965, 215, 14857, 31669, 54775, 42157}},
-{7183, 17, 12501, {1, 3, 5, 1, 5, 45, 123, 109, 471, 599, 479, 475, 3499, 11963, 23709, 18851, 66861}},
-{7184, 17, 12505, {1, 3, 3, 3, 5, 29, 71, 81, 315, 329, 1471, 3995, 623, 5871, 11171, 15645, 97251}},
-{7185, 17, 12508, {1, 1, 7, 11, 15, 15, 101, 173, 445, 871, 765, 1121, 1937, 13055, 7309, 54175, 85559}},
-{7186, 17, 12511, {1, 3, 5, 7, 7, 13, 43, 237, 361, 981, 19, 3113, 4681, 3313, 19147, 35193, 87281}},
-{7187, 17, 12521, {1, 3, 5, 3, 27, 13, 37, 51, 233, 573, 1599, 2807, 7149, 12083, 28927, 7797, 130879}},
-{7188, 17, 12522, {1, 1, 1, 13, 31, 63, 127, 89, 209, 717, 1075, 3887, 1427, 87, 18565, 39973, 55025}},
-{7189, 17, 12530, {1, 3, 1, 5, 15, 11, 121, 247, 273, 613, 1857, 2059, 7399, 13951, 9025, 39523, 68121}},
-{7190, 17, 12544, {1, 3, 7, 13, 31, 9, 61, 143, 375, 433, 471, 1315, 5299, 1167, 10099, 11445, 51693}},
-{7191, 17, 12547, {1, 1, 7, 9, 25, 31, 125, 5, 13, 595, 621, 3551, 7959, 10643, 14345, 37683, 118377}},
-{7192, 17, 12561, {1, 1, 5, 11, 1, 33, 45, 31, 447, 229, 893, 3777, 4101, 2505, 4855, 14057, 20133}},
-{7193, 17, 12571, {1, 1, 1, 1, 7, 23, 89, 53, 483, 873, 521, 2115, 1461, 11241, 1003, 28749, 68227}},
-{7194, 17, 12580, {1, 3, 5, 5, 3, 17, 23, 219, 281, 975, 895, 4043, 6505, 5991, 27401, 38791, 89239}},
-{7195, 17, 12597, {1, 1, 1, 7, 29, 41, 63, 151, 195, 495, 469, 305, 7437, 1107, 31147, 30755, 116551}},
-{7196, 17, 12607, {1, 3, 7, 3, 13, 25, 33, 193, 23, 135, 3, 513, 4169, 15355, 2255, 32167, 68691}},
-{7197, 17, 12609, {1, 3, 3, 11, 29, 19, 125, 177, 83, 361, 393, 663, 1859, 1333, 17507, 10661, 72387}},
-{7198, 17, 12610, {1, 1, 5, 11, 23, 13, 61, 33, 149, 145, 995, 649, 7587, 6743, 25225, 54997, 10193}},
-{7199, 17, 12616, {1, 1, 7, 13, 29, 51, 107, 79, 467, 881, 1227, 1083, 3277, 2559, 26819, 57311, 48095}},
-{7200, 17, 12621, {1, 3, 1, 1, 1, 19, 23, 25, 239, 703, 119, 2525, 8079, 5433, 8989, 42517, 116755}},
-{7201, 17, 12624, {1, 1, 7, 11, 31, 9, 9, 113, 381, 363, 447, 3751, 7523, 15995, 3853, 42069, 81455}},
-{7202, 17, 12639, {1, 1, 5, 9, 29, 41, 103, 179, 477, 527, 1593, 3003, 1095, 6823, 6911, 44987, 32445}},
-{7203, 17, 12645, {1, 1, 7, 15, 5, 31, 55, 181, 149, 127, 1745, 2753, 801, 285, 20199, 33707, 118397}},
-{7204, 17, 12652, {1, 3, 7, 7, 11, 29, 89, 215, 351, 303, 1519, 2593, 2045, 14699, 1657, 40799, 39641}},
-{7205, 17, 12655, {1, 1, 7, 13, 3, 35, 73, 111, 15, 803, 1819, 3453, 3611, 8337, 14239, 14875, 83983}},
-{7206, 17, 12660, {1, 1, 5, 15, 15, 49, 27, 101, 149, 3, 717, 2229, 7397, 6579, 10965, 35997, 28823}},
-{7207, 17, 12667, {1, 1, 5, 7, 3, 17, 49, 245, 343, 657, 15, 749, 6413, 10811, 2909, 47309, 34613}},
-{7208, 17, 12686, {1, 3, 5, 15, 13, 35, 67, 99, 481, 379, 2003, 3367, 3065, 5845, 7799, 43931, 15263}},
-{7209, 17, 12688, {1, 1, 5, 13, 21, 49, 81, 77, 395, 919, 1931, 661, 123, 9965, 10487, 55131, 1567}},
-{7210, 17, 12697, {1, 3, 5, 11, 23, 39, 41, 121, 159, 473, 191, 1983, 6411, 10503, 10523, 40601, 64153}},
-{7211, 17, 12700, {1, 1, 5, 7, 9, 37, 73, 207, 497, 789, 1671, 325, 1697, 11281, 31185, 4961, 124431}},
-{7212, 17, 12707, {1, 1, 5, 15, 7, 51, 71, 91, 449, 707, 621, 2427, 627, 1747, 12779, 17569, 98289}},
-{7213, 17, 12710, {1, 1, 5, 5, 31, 3, 89, 163, 77, 647, 1747, 2965, 1669, 3311, 17651, 8111, 30739}},
-{7214, 17, 12719, {1, 1, 3, 11, 15, 31, 77, 173, 405, 913, 459, 2955, 6153, 13391, 20439, 64433, 12371}},
-{7215, 17, 12739, {1, 1, 3, 11, 13, 55, 29, 37, 379, 689, 407, 1373, 397, 5027, 15497, 25687, 48193}},
-{7216, 17, 12742, {1, 3, 3, 15, 13, 7, 81, 207, 395, 901, 779, 1683, 2491, 3807, 31979, 32403, 81113}},
-{7217, 17, 12746, {1, 3, 3, 13, 29, 31, 25, 81, 459, 991, 793, 3285, 2775, 16199, 11423, 52597, 86041}},
-{7218, 17, 12754, {1, 3, 3, 13, 17, 17, 101, 183, 19, 735, 671, 1097, 2461, 9863, 25985, 31915, 73047}},
-{7219, 17, 12765, {1, 3, 3, 3, 3, 11, 71, 63, 429, 899, 351, 1275, 3907, 14241, 19135, 14875, 43325}},
-{7220, 17, 12772, {1, 1, 7, 11, 11, 61, 15, 213, 411, 13, 1409, 1741, 5257, 8729, 28351, 6381, 77501}},
-{7221, 17, 12784, {1, 1, 7, 7, 29, 27, 51, 217, 411, 261, 599, 3027, 7871, 9133, 32423, 44275, 34701}},
-{7222, 17, 12789, {1, 3, 7, 7, 1, 1, 127, 209, 151, 845, 1421, 3115, 7775, 10133, 6163, 41165, 91187}},
-{7223, 17, 12800, {1, 3, 1, 9, 1, 35, 75, 3, 81, 477, 131, 1383, 1377, 6857, 3863, 12583, 7855}},
-{7224, 17, 12805, {1, 3, 1, 3, 3, 11, 1, 167, 347, 317, 557, 3763, 7175, 13341, 759, 23275, 78039}},
-{7225, 17, 12809, {1, 3, 5, 11, 19, 53, 85, 139, 67, 757, 487, 919, 6001, 16031, 24959, 28013, 65771}},
-{7226, 17, 12815, {1, 1, 1, 1, 23, 9, 83, 55, 249, 305, 1305, 109, 5559, 5129, 30973, 19889, 6691}},
-{7227, 17, 12827, {1, 1, 1, 3, 21, 19, 85, 89, 213, 847, 861, 1651, 6613, 6001, 8157, 2555, 98673}},
-{7228, 17, 12830, {1, 1, 1, 15, 25, 15, 125, 133, 177, 295, 549, 1763, 2811, 4381, 1079, 7813, 87909}},
-{7229, 17, 12833, {1, 1, 1, 5, 5, 17, 25, 225, 353, 997, 1565, 2225, 7265, 16227, 28209, 9011, 97193}},
-{7230, 17, 12840, {1, 3, 7, 15, 13, 13, 35, 239, 331, 965, 1547, 1627, 6409, 7745, 30899, 36915, 59293}},
-{7231, 17, 12851, {1, 1, 1, 13, 27, 45, 23, 179, 193, 801, 381, 3783, 3551, 11855, 11041, 49911, 62101}},
-{7232, 17, 12868, {1, 1, 7, 3, 3, 31, 61, 5, 421, 939, 1637, 217, 389, 1797, 32141, 28817, 6997}},
-{7233, 17, 12871, {1, 3, 3, 5, 21, 31, 83, 65, 421, 577, 1137, 2561, 2943, 4171, 2803, 23325, 92315}},
-{7234, 17, 12886, {1, 1, 3, 3, 27, 33, 75, 81, 477, 3, 1903, 773, 5551, 10069, 7285, 58103, 98311}},
-{7235, 17, 12899, {1, 3, 7, 15, 1, 17, 95, 209, 65, 747, 1633, 581, 7395, 1393, 21795, 15735, 129757}},
-{7236, 17, 12923, {1, 3, 5, 3, 17, 3, 9, 131, 51, 693, 1571, 1865, 8137, 915, 13345, 35137, 59005}},
-{7237, 17, 12926, {1, 1, 3, 7, 23, 27, 61, 163, 449, 87, 717, 1075, 4309, 4887, 11741, 24549, 96729}},
-{7238, 17, 12932, {1, 3, 7, 13, 21, 5, 3, 97, 191, 999, 1193, 1215, 5907, 10491, 2281, 6455, 68625}},
-{7239, 17, 12935, {1, 1, 5, 7, 9, 9, 101, 5, 375, 137, 1473, 1265, 5307, 259, 20699, 25367, 129393}},
-{7240, 17, 12939, {1, 3, 7, 7, 21, 1, 77, 65, 23, 139, 945, 491, 1069, 253, 12335, 26861, 129467}},
-{7241, 17, 12942, {1, 1, 3, 9, 15, 33, 85, 225, 45, 311, 281, 1601, 7325, 12265, 2591, 51955, 130681}},
-{7242, 17, 12953, {1, 1, 1, 3, 27, 33, 17, 89, 495, 91, 527, 3347, 7883, 9481, 28731, 54729, 15265}},
-{7243, 17, 12959, {1, 1, 3, 3, 9, 47, 115, 161, 299, 493, 1857, 3597, 7175, 15603, 11523, 33837, 57557}},
-{7244, 17, 12960, {1, 3, 7, 3, 15, 47, 127, 195, 391, 869, 99, 429, 7125, 10413, 5063, 61845, 71843}},
-{7245, 17, 13002, {1, 3, 3, 1, 7, 31, 27, 69, 7, 83, 315, 2749, 5693, 13377, 28091, 13065, 111029}},
-{7246, 17, 13004, {1, 1, 3, 15, 15, 45, 125, 229, 459, 611, 1167, 3375, 3587, 81, 9275, 45327, 39749}},
-{7247, 17, 13016, {1, 3, 7, 11, 9, 3, 43, 161, 221, 209, 51, 1475, 3577, 13973, 15285, 35553, 83935}},
-{7248, 17, 13021, {1, 1, 7, 9, 15, 55, 25, 119, 39, 537, 317, 1331, 2161, 1791, 19221, 63459, 124595}},
-{7249, 17, 13035, {1, 1, 1, 11, 9, 7, 113, 187, 295, 67, 1795, 113, 119, 9127, 32119, 7719, 67591}},
-{7250, 17, 13038, {1, 3, 7, 13, 1, 53, 17, 19, 331, 711, 359, 2945, 5847, 7237, 23617, 17411, 2203}},
-{7251, 17, 13052, {1, 3, 3, 7, 21, 63, 115, 159, 225, 161, 1255, 2381, 7411, 95, 1625, 30493, 56685}},
-{7252, 17, 13058, {1, 1, 5, 9, 13, 57, 5, 107, 195, 271, 677, 2081, 6027, 11091, 14171, 19007, 102119}},
-{7253, 17, 13069, {1, 3, 3, 3, 19, 13, 31, 155, 209, 89, 955, 523, 615, 5319, 16079, 9289, 49135}},
-{7254, 17, 13082, {1, 3, 1, 13, 1, 31, 69, 143, 329, 813, 635, 891, 2967, 5563, 19643, 35813, 14345}},
-{7255, 17, 13093, {1, 1, 5, 5, 17, 47, 97, 49, 123, 997, 15, 3685, 3925, 4973, 11195, 17115, 63709}},
-{7256, 17, 13094, {1, 1, 7, 13, 13, 17, 99, 149, 309, 281, 329, 905, 6487, 4495, 31831, 24413, 26431}},
-{7257, 17, 13100, {1, 1, 5, 5, 5, 47, 113, 115, 61, 157, 955, 2323, 4445, 229, 24049, 14753, 15189}},
-{7258, 17, 13115, {1, 3, 7, 15, 25, 21, 13, 137, 377, 45, 629, 1339, 8037, 5073, 24741, 48589, 28953}},
-{7259, 17, 13125, {1, 3, 3, 9, 3, 41, 7, 101, 333, 59, 1213, 1871, 3993, 11261, 4403, 42785, 58753}},
-{7260, 17, 13132, {1, 3, 1, 7, 5, 33, 87, 73, 317, 575, 1459, 905, 1033, 14179, 19595, 30269, 103853}},
-{7261, 17, 13143, {1, 1, 1, 1, 19, 49, 63, 181, 227, 401, 695, 1811, 2383, 3835, 14379, 30685, 114731}},
-{7262, 17, 13144, {1, 1, 5, 15, 9, 41, 35, 91, 357, 659, 155, 3725, 6509, 405, 25449, 37719, 6013}},
-{7263, 17, 13153, {1, 1, 7, 3, 11, 59, 33, 151, 291, 393, 741, 3961, 2787, 993, 10361, 11737, 42047}},
-{7264, 17, 13160, {1, 3, 7, 3, 15, 15, 55, 59, 419, 203, 55, 801, 2719, 15487, 13213, 58473, 50315}},
-{7265, 17, 13165, {1, 3, 7, 13, 17, 21, 113, 111, 159, 163, 711, 1135, 1133, 15519, 30515, 55777, 25025}},
-{7266, 17, 13173, {1, 1, 3, 5, 13, 25, 23, 3, 93, 873, 559, 1815, 3381, 5311, 14365, 34349, 17333}},
-{7267, 17, 13174, {1, 3, 5, 7, 15, 43, 85, 33, 23, 903, 1247, 3279, 1393, 12059, 19251, 19389, 5097}},
-{7268, 17, 13187, {1, 3, 1, 11, 21, 59, 3, 153, 403, 95, 1939, 2679, 419, 9035, 31219, 2897, 15727}},
-{7269, 17, 13190, {1, 3, 5, 1, 11, 21, 35, 169, 453, 15, 791, 3931, 1021, 16321, 6033, 10639, 16173}},
-{7270, 17, 13204, {1, 3, 1, 11, 7, 57, 39, 61, 381, 465, 451, 2863, 575, 5597, 31041, 8625, 82373}},
-{7271, 17, 13218, {1, 1, 3, 5, 13, 5, 63, 1, 75, 245, 1305, 285, 3367, 10107, 5853, 35275, 128255}},
-{7272, 17, 13247, {1, 1, 1, 3, 1, 57, 21, 91, 139, 669, 765, 1867, 2153, 10347, 26119, 35517, 4725}},
-{7273, 17, 13250, {1, 3, 5, 1, 21, 41, 59, 247, 473, 1015, 975, 485, 2161, 11941, 10341, 35245, 55587}},
-{7274, 17, 13262, {1, 1, 5, 9, 7, 59, 33, 149, 97, 619, 393, 3613, 6037, 10895, 19461, 15975, 47919}},
-{7275, 17, 13267, {1, 3, 3, 15, 7, 17, 95, 13, 147, 361, 915, 2585, 4483, 3159, 12255, 44685, 116163}},
-{7276, 17, 13274, {1, 3, 1, 15, 27, 31, 75, 31, 423, 233, 1453, 2815, 3633, 6531, 25721, 29649, 80645}},
-{7277, 17, 13304, {1, 3, 3, 3, 19, 7, 73, 33, 163, 495, 1483, 2277, 6455, 6523, 9331, 21869, 52175}},
-{7278, 17, 13309, {1, 3, 5, 13, 5, 1, 63, 35, 335, 189, 713, 2997, 3277, 10049, 4681, 16753, 17107}},
-{7279, 17, 13315, {1, 3, 5, 9, 3, 55, 29, 171, 395, 585, 671, 1875, 4449, 12895, 5455, 11023, 106189}},
-{7280, 17, 13317, {1, 3, 5, 3, 25, 53, 33, 169, 109, 285, 787, 861, 5549, 5171, 15293, 2977, 14559}},
-{7281, 17, 13324, {1, 3, 7, 1, 21, 25, 97, 115, 1, 999, 1033, 3471, 129, 16093, 495, 16859, 34615}},
-{7282, 17, 13332, {1, 3, 5, 9, 13, 5, 109, 41, 57, 957, 231, 3771, 2917, 15649, 8869, 14857, 64943}},
-{7283, 17, 13342, {1, 1, 7, 7, 21, 41, 101, 59, 167, 441, 997, 2951, 7891, 16325, 12669, 53829, 100705}},
-{7284, 17, 13346, {1, 1, 7, 9, 19, 59, 23, 141, 193, 237, 1067, 1823, 3351, 3239, 3135, 9275, 37069}},
-{7285, 17, 13355, {1, 3, 3, 9, 3, 17, 95, 73, 19, 231, 779, 3065, 2245, 2967, 24971, 62589, 16729}},
-{7286, 17, 13358, {1, 3, 3, 13, 25, 19, 117, 147, 443, 123, 157, 2037, 327, 14715, 5693, 54641, 33325}},
-{7287, 17, 13360, {1, 3, 1, 9, 21, 21, 21, 125, 49, 787, 767, 2831, 511, 2461, 31537, 27155, 44053}},
-{7288, 17, 13369, {1, 3, 7, 9, 31, 19, 125, 67, 119, 465, 287, 1869, 3979, 15723, 21069, 8581, 66939}},
-{7289, 17, 13372, {1, 1, 1, 11, 7, 37, 123, 237, 353, 499, 113, 3829, 217, 4751, 7385, 20343, 83699}},
-{7290, 17, 13398, {1, 3, 7, 13, 9, 3, 53, 27, 487, 87, 35, 2645, 3481, 14409, 27875, 31695, 78489}},
-{7291, 17, 13404, {1, 3, 3, 13, 9, 43, 67, 51, 153, 83, 591, 1991, 1787, 11973, 7273, 34801, 47199}},
-{7292, 17, 13407, {1, 3, 7, 1, 15, 53, 71, 11, 205, 853, 2011, 581, 1281, 7819, 23083, 33731, 74951}},
-{7293, 17, 13414, {1, 1, 5, 5, 17, 63, 109, 219, 225, 997, 1251, 3287, 1441, 13489, 22723, 45191, 50249}},
-{7294, 17, 13426, {1, 1, 5, 3, 13, 1, 43, 53, 293, 685, 1369, 1515, 7479, 3233, 20007, 65235, 102467}},
-{7295, 17, 13432, {1, 3, 5, 7, 29, 45, 63, 45, 219, 445, 2047, 317, 7553, 325, 1465, 949, 35163}},
-{7296, 17, 13466, {1, 1, 3, 9, 7, 31, 73, 211, 501, 233, 1495, 701, 5857, 10763, 9743, 10289, 23801}},
-{7297, 17, 13481, {1, 3, 7, 3, 23, 47, 99, 61, 179, 833, 1425, 1275, 4467, 4367, 5567, 23513, 68677}},
-{7298, 17, 13490, {1, 1, 5, 5, 27, 33, 119, 229, 329, 51, 1025, 3167, 3405, 4039, 4135, 6655, 43771}},
-{7299, 17, 13496, {1, 3, 7, 15, 5, 49, 91, 55, 425, 15, 2003, 1571, 3539, 10375, 29645, 5889, 51887}},
-{7300, 17, 13504, {1, 1, 7, 3, 13, 55, 85, 91, 181, 723, 1941, 75, 4443, 11507, 7027, 14189, 50685}},
-{7301, 17, 13516, {1, 3, 5, 5, 29, 49, 13, 3, 97, 165, 41, 3039, 3325, 2161, 775, 38501, 42381}},
-{7302, 17, 13527, {1, 1, 5, 11, 9, 57, 47, 109, 9, 585, 375, 1839, 937, 6877, 29847, 60163, 103081}},
-{7303, 17, 13533, {1, 1, 3, 13, 5, 47, 11, 195, 253, 235, 275, 2313, 163, 14683, 5681, 13381, 84553}},
-{7304, 17, 13537, {1, 3, 3, 15, 15, 1, 93, 157, 437, 557, 307, 1179, 6857, 3101, 16723, 50579, 69603}},
-{7305, 17, 13552, {1, 1, 5, 9, 11, 29, 23, 219, 337, 689, 1155, 2007, 6853, 6749, 20127, 13199, 48433}},
-{7306, 17, 13561, {1, 1, 1, 13, 1, 61, 73, 213, 335, 539, 903, 2719, 775, 2775, 29109, 33367, 3281}},
-{7307, 17, 13567, {1, 3, 1, 5, 15, 31, 65, 231, 439, 623, 1871, 2299, 5365, 10333, 9147, 2781, 63813}},
-{7308, 17, 13582, {1, 1, 3, 1, 1, 25, 23, 229, 173, 279, 181, 1299, 2893, 15475, 12473, 46097, 123387}},
-{7309, 17, 13587, {1, 1, 7, 13, 7, 43, 17, 187, 467, 113, 1293, 2013, 6091, 14621, 22195, 24079, 45379}},
-{7310, 17, 13589, {1, 3, 1, 7, 1, 7, 119, 159, 377, 11, 705, 2853, 3767, 13739, 23375, 25563, 73987}},
-{7311, 17, 13593, {1, 1, 3, 15, 21, 13, 111, 119, 401, 1005, 777, 1699, 2431, 15139, 27887, 28415, 71519}},
-{7312, 17, 13596, {1, 1, 7, 9, 1, 49, 19, 171, 297, 77, 1343, 1249, 5769, 13889, 21401, 24915, 17641}},
-{7313, 17, 13615, {1, 1, 7, 11, 31, 45, 51, 231, 123, 817, 13, 791, 6235, 2787, 475, 1717, 5071}},
-{7314, 17, 13617, {1, 3, 3, 13, 5, 9, 21, 129, 253, 731, 785, 2275, 7343, 7841, 5477, 8973, 101033}},
-{7315, 17, 13623, {1, 1, 7, 13, 23, 1, 119, 221, 293, 709, 2031, 3019, 1529, 2007, 10823, 43193, 82661}},
-{7316, 17, 13641, {1, 3, 1, 11, 29, 29, 87, 79, 415, 679, 1899, 3453, 7355, 8627, 28225, 41857, 106645}},
-{7317, 17, 13647, {1, 1, 5, 15, 9, 13, 21, 241, 491, 927, 999, 2131, 3501, 11063, 28595, 54691, 21297}},
-{7318, 17, 13650, {1, 1, 1, 3, 5, 41, 85, 89, 483, 309, 791, 825, 3043, 2715, 16573, 6551, 77875}},
-{7319, 17, 13659, {1, 3, 1, 1, 25, 21, 107, 123, 79, 1019, 821, 1251, 4943, 1429, 17843, 37013, 53285}},
-{7320, 17, 13671, {1, 1, 5, 3, 7, 5, 35, 123, 445, 315, 627, 2543, 1261, 13737, 15991, 36591, 18309}},
-{7321, 17, 13677, {1, 3, 3, 5, 25, 43, 65, 249, 309, 1023, 737, 1933, 4735, 7725, 12063, 53023, 126677}},
-{7322, 17, 13678, {1, 3, 1, 9, 13, 37, 77, 61, 179, 275, 277, 1431, 2869, 14563, 665, 60553, 7661}},
-{7323, 17, 13680, {1, 3, 5, 3, 29, 1, 127, 73, 363, 311, 1591, 3863, 6481, 4725, 8287, 61311, 39011}},
-{7324, 17, 13685, {1, 3, 1, 7, 13, 23, 115, 215, 385, 563, 1033, 2343, 5023, 11013, 12131, 26997, 48645}},
-{7325, 17, 13689, {1, 1, 5, 13, 3, 59, 41, 155, 263, 507, 1175, 2967, 7929, 8237, 11841, 15365, 51881}},
-{7326, 17, 13701, {1, 1, 3, 11, 19, 35, 89, 115, 121, 315, 1697, 2121, 1867, 6865, 23639, 26525, 44687}},
-{7327, 17, 13706, {1, 3, 5, 15, 9, 5, 125, 183, 149, 447, 309, 1743, 6089, 369, 16153, 63799, 57657}},
-{7328, 17, 13720, {1, 1, 1, 7, 7, 39, 89, 139, 457, 741, 1613, 2883, 5057, 12495, 18669, 55469, 97941}},
-{7329, 17, 13729, {1, 1, 5, 7, 29, 39, 97, 9, 481, 667, 1353, 3387, 2813, 16205, 8353, 22121, 92965}},
-{7330, 17, 13735, {1, 3, 7, 9, 11, 55, 79, 159, 349, 717, 829, 3157, 1457, 6199, 5861, 2553, 20387}},
-{7331, 17, 13736, {1, 1, 1, 11, 3, 51, 113, 53, 287, 109, 1717, 2405, 7207, 4473, 11145, 2549, 591}},
-{7332, 17, 13756, {1, 1, 3, 13, 3, 61, 31, 141, 217, 487, 299, 2755, 3389, 10053, 1105, 21129, 74203}},
-{7333, 17, 13759, {1, 1, 1, 3, 11, 55, 7, 113, 413, 449, 787, 3279, 5123, 16025, 15005, 12175, 6795}},
-{7334, 17, 13761, {1, 3, 1, 1, 25, 23, 107, 191, 3, 3, 49, 1083, 3275, 10385, 7989, 53739, 25505}},
-{7335, 17, 13771, {1, 1, 5, 13, 7, 17, 59, 13, 471, 147, 1627, 2119, 3555, 15555, 10333, 49363, 80959}},
-{7336, 17, 13782, {1, 1, 1, 15, 23, 33, 61, 191, 207, 939, 45, 2781, 71, 9661, 28433, 13089, 76419}},
-{7337, 17, 13786, {1, 3, 3, 7, 29, 47, 111, 19, 315, 381, 851, 1303, 2627, 6255, 30369, 37723, 12949}},
-{7338, 17, 13798, {1, 1, 1, 13, 31, 43, 3, 193, 5, 99, 769, 2523, 1949, 129, 9693, 60535, 67059}},
-{7339, 17, 13810, {1, 1, 3, 15, 5, 33, 73, 149, 253, 985, 863, 1551, 4369, 5911, 8269, 35463, 117055}},
-{7340, 17, 13819, {1, 3, 1, 5, 27, 57, 3, 105, 253, 731, 119, 3287, 613, 4627, 22003, 56027, 123005}},
-{7341, 17, 13826, {1, 1, 3, 3, 27, 47, 67, 147, 495, 865, 1233, 3707, 2511, 2951, 7367, 15625, 86417}},
-{7342, 17, 13831, {1, 1, 7, 1, 7, 7, 13, 255, 457, 529, 953, 1481, 5565, 12495, 4723, 41615, 121829}},
-{7343, 17, 13837, {1, 3, 5, 11, 1, 51, 91, 153, 323, 609, 1353, 2995, 4035, 13835, 28619, 46217, 4967}},
-{7344, 17, 13846, {1, 1, 5, 7, 25, 59, 81, 101, 185, 709, 1249, 2285, 6579, 8655, 17563, 9707, 63845}},
-{7345, 17, 13856, {1, 3, 3, 9, 31, 25, 17, 19, 111, 627, 1187, 2621, 6529, 9457, 25027, 18069, 47559}},
-{7346, 17, 13862, {1, 3, 7, 15, 7, 15, 103, 201, 391, 1023, 817, 535, 2713, 1317, 13469, 56043, 70847}},
-{7347, 17, 13866, {1, 1, 3, 7, 17, 57, 35, 99, 439, 367, 27, 2695, 3519, 8337, 14047, 58489, 69}},
-{7348, 17, 13885, {1, 1, 1, 3, 17, 23, 71, 189, 57, 39, 715, 1779, 3081, 14657, 21895, 59203, 31005}},
-{7349, 17, 13891, {1, 1, 7, 13, 1, 47, 69, 159, 353, 517, 271, 973, 5077, 15707, 11095, 19671, 3389}},
-{7350, 17, 13893, {1, 1, 7, 13, 25, 55, 115, 21, 43, 939, 1697, 101, 4751, 1993, 2389, 28353, 45251}},
-{7351, 17, 13905, {1, 3, 1, 15, 11, 57, 17, 49, 121, 419, 909, 121, 5047, 4235, 13051, 21529, 42097}},
-{7352, 17, 13908, {1, 1, 1, 3, 19, 37, 31, 233, 251, 175, 929, 1527, 7527, 3605, 17075, 61053, 56235}},
-{7353, 17, 13912, {1, 1, 1, 3, 9, 5, 117, 131, 251, 475, 1695, 1381, 2445, 5921, 14921, 937, 80791}},
-{7354, 17, 13917, {1, 1, 3, 9, 11, 5, 31, 215, 37, 567, 1537, 2183, 3291, 1601, 14025, 48807, 7243}},
-{7355, 17, 13918, {1, 3, 1, 9, 7, 13, 81, 249, 321, 473, 1419, 3977, 7037, 14191, 10865, 56131, 43225}},
-{7356, 17, 13946, {1, 1, 1, 13, 15, 23, 31, 69, 449, 491, 1461, 729, 7955, 4003, 16817, 37273, 72025}},
-{7357, 17, 13948, {1, 1, 5, 13, 7, 41, 93, 169, 347, 1013, 301, 2813, 1455, 13187, 10769, 60807, 46333}},
-{7358, 17, 13964, {1, 1, 5, 3, 23, 15, 1, 161, 29, 35, 415, 235, 93, 14543, 29585, 29657, 36489}},
-{7359, 17, 13970, {1, 3, 1, 3, 31, 63, 39, 235, 153, 549, 43, 147, 2317, 3537, 25561, 58287, 58725}},
-{7360, 17, 13975, {1, 1, 3, 5, 5, 11, 59, 97, 349, 307, 501, 1701, 4243, 13717, 17419, 23387, 29533}},
-{7361, 17, 13979, {1, 3, 1, 7, 7, 19, 33, 243, 67, 353, 2023, 3111, 7173, 10979, 28117, 40175, 45337}},
-{7362, 17, 13997, {1, 1, 1, 5, 15, 59, 55, 135, 107, 543, 1743, 2695, 3293, 111, 32629, 8249, 52273}},
-{7363, 17, 14000, {1, 3, 5, 13, 15, 57, 39, 79, 5, 451, 571, 1445, 1393, 2125, 31713, 59655, 20897}},
-{7364, 17, 14006, {1, 1, 3, 11, 29, 61, 1, 37, 173, 513, 1779, 2649, 3289, 4679, 2039, 47587, 28973}},
-{7365, 17, 14020, {1, 1, 5, 5, 15, 19, 17, 143, 387, 359, 275, 625, 7383, 15537, 10311, 40005, 20729}},
-{7366, 17, 14023, {1, 1, 3, 9, 7, 23, 71, 179, 85, 447, 345, 3459, 2857, 8331, 5489, 62207, 64933}},
-{7367, 17, 14024, {1, 1, 1, 1, 11, 61, 47, 131, 213, 611, 701, 713, 1269, 9563, 25223, 50697, 88679}},
-{7368, 17, 14029, {1, 1, 5, 15, 21, 5, 77, 59, 455, 243, 459, 2809, 13, 9325, 32047, 3939, 48389}},
-{7369, 17, 14035, {1, 3, 7, 1, 21, 53, 111, 225, 407, 119, 713, 3635, 1539, 15321, 29827, 36069, 74483}},
-{7370, 17, 14044, {1, 1, 5, 13, 7, 45, 75, 43, 191, 715, 169, 759, 33, 11329, 1069, 36103, 28055}},
-{7371, 17, 14047, {1, 3, 7, 5, 7, 13, 7, 35, 27, 391, 517, 1439, 5699, 1067, 23857, 7293, 66167}},
-{7372, 17, 14058, {1, 1, 7, 11, 3, 31, 1, 83, 299, 345, 65, 669, 1529, 7569, 28959, 50561, 69493}},
-{7373, 17, 14066, {1, 3, 1, 5, 25, 25, 43, 149, 83, 225, 1589, 1691, 7777, 773, 10421, 49523, 23533}},
-{7374, 17, 14075, {1, 1, 5, 11, 25, 29, 81, 11, 497, 43, 951, 2551, 821, 13805, 12315, 61299, 81397}},
-{7375, 17, 14080, {1, 3, 1, 9, 29, 23, 109, 123, 235, 255, 1519, 3289, 7761, 14575, 11851, 1719, 51655}},
-{7376, 17, 14095, {1, 3, 5, 15, 21, 49, 13, 43, 87, 517, 687, 1457, 1501, 15959, 31907, 13771, 69379}},
-{7377, 17, 14100, {1, 1, 5, 3, 21, 11, 87, 9, 343, 317, 845, 1663, 7933, 14063, 24915, 31487, 17445}},
-{7378, 17, 14114, {1, 1, 3, 13, 21, 31, 87, 99, 185, 333, 993, 3899, 971, 2851, 23643, 195, 66957}},
-{7379, 17, 14116, {1, 1, 1, 15, 19, 47, 23, 1, 67, 57, 165, 3903, 421, 10561, 11621, 13815, 10349}},
-{7380, 17, 14123, {1, 3, 5, 11, 9, 19, 73, 17, 229, 913, 459, 3809, 2667, 9775, 3693, 52945, 90837}},
-{7381, 17, 14134, {1, 1, 5, 15, 3, 25, 109, 131, 507, 637, 1615, 859, 6785, 14891, 24801, 39095, 79557}},
-{7382, 17, 14143, {1, 1, 5, 7, 1, 51, 71, 251, 19, 799, 835, 1119, 2349, 15083, 16509, 55621, 123501}},
-{7383, 17, 14151, {1, 3, 5, 9, 13, 39, 127, 1, 233, 37, 735, 3307, 5163, 4529, 5961, 12893, 103641}},
-{7384, 17, 14160, {1, 1, 7, 5, 23, 15, 49, 123, 511, 201, 2025, 289, 3847, 15755, 24279, 52543, 42017}},
-{7385, 17, 14163, {1, 1, 5, 3, 9, 61, 19, 37, 3, 361, 1065, 2971, 2517, 1259, 27359, 3823, 60181}},
-{7386, 17, 14179, {1, 3, 1, 7, 15, 17, 57, 249, 57, 979, 147, 2407, 2579, 3159, 8467, 8433, 72873}},
-{7387, 17, 14181, {1, 1, 3, 1, 25, 7, 47, 117, 449, 321, 143, 3867, 165, 7961, 27597, 10033, 2437}},
-{7388, 17, 14193, {1, 3, 5, 13, 19, 49, 1, 83, 477, 549, 509, 2911, 1559, 14017, 10469, 62171, 82829}},
-{7389, 17, 14209, {1, 3, 3, 7, 27, 21, 15, 63, 31, 45, 1223, 3903, 5469, 11983, 29627, 27453, 32019}},
-{7390, 17, 14210, {1, 1, 7, 7, 9, 9, 7, 77, 349, 467, 61, 3465, 6921, 15761, 15179, 38649, 2469}},
-{7391, 17, 14224, {1, 3, 1, 13, 9, 59, 55, 67, 271, 617, 643, 4071, 7963, 8153, 5121, 43917, 26219}},
-{7392, 17, 14245, {1, 1, 3, 7, 29, 21, 63, 103, 327, 623, 931, 1511, 3125, 229, 28949, 61315, 72667}},
-{7393, 17, 14249, {1, 3, 7, 1, 19, 37, 49, 63, 403, 885, 161, 121, 1447, 9227, 15019, 50049, 26939}},
-{7394, 17, 14255, {1, 3, 3, 3, 23, 57, 95, 79, 485, 173, 93, 835, 7161, 11247, 3485, 5759, 36393}},
-{7395, 17, 14267, {1, 3, 7, 13, 23, 33, 5, 97, 235, 531, 313, 2925, 2223, 847, 18591, 15477, 3129}},
-{7396, 17, 14270, {1, 1, 3, 13, 25, 25, 101, 183, 477, 947, 1251, 2631, 7987, 13417, 23759, 55305, 123817}},
-{7397, 17, 14277, {1, 1, 5, 9, 27, 63, 49, 137, 179, 861, 33, 2375, 3827, 6485, 19689, 7867, 124429}},
-{7398, 17, 14305, {1, 3, 7, 3, 15, 43, 63, 103, 45, 947, 1837, 833, 7055, 7487, 19669, 12045, 78377}},
-{7399, 17, 14308, {1, 3, 5, 3, 29, 35, 57, 19, 471, 985, 1147, 741, 5403, 10057, 25375, 50889, 82719}},
-{7400, 17, 14312, {1, 3, 3, 1, 17, 19, 111, 13, 121, 821, 1831, 4043, 123, 9529, 1511, 10917, 105961}},
-{7401, 17, 14325, {1, 1, 3, 11, 1, 43, 23, 75, 345, 9, 1379, 2157, 5887, 1197, 14849, 17103, 91925}},
-{7402, 17, 14332, {1, 1, 3, 3, 19, 11, 1, 179, 343, 1023, 1801, 915, 255, 519, 5787, 32913, 43471}},
-{7403, 17, 14345, {1, 3, 5, 5, 3, 3, 3, 211, 461, 55, 851, 3165, 2903, 15077, 8537, 2037, 109057}},
-{7404, 17, 14354, {1, 1, 7, 15, 7, 7, 43, 249, 27, 511, 1369, 735, 6093, 12575, 26675, 21745, 117053}},
-{7405, 17, 14372, {1, 1, 5, 7, 21, 53, 45, 83, 415, 645, 325, 4027, 5181, 8485, 1917, 55623, 45203}},
-{7406, 17, 14387, {1, 1, 3, 15, 7, 1, 121, 221, 387, 403, 1877, 1671, 2113, 2379, 5667, 39867, 8079}},
-{7407, 17, 14390, {1, 1, 1, 7, 5, 29, 35, 77, 197, 661, 1859, 2539, 4045, 13497, 305, 44987, 31215}},
-{7408, 17, 14402, {1, 1, 5, 5, 13, 37, 13, 85, 287, 347, 579, 2283, 7911, 5463, 21141, 9035, 105067}},
-{7409, 17, 14408, {1, 1, 1, 9, 17, 17, 63, 97, 57, 629, 1917, 1133, 779, 12365, 17127, 52549, 18755}},
-{7410, 17, 14413, {1, 1, 7, 11, 7, 17, 65, 137, 485, 841, 653, 2921, 4935, 16273, 23333, 7399, 43129}},
-{7411, 17, 14431, {1, 3, 1, 11, 31, 55, 93, 225, 319, 35, 947, 1909, 7733, 8303, 20739, 55713, 6633}},
-{7412, 17, 14438, {1, 1, 1, 3, 11, 25, 1, 165, 305, 275, 607, 3845, 5203, 1989, 13803, 597, 39751}},
-{7413, 17, 14447, {1, 1, 5, 11, 31, 43, 83, 237, 453, 59, 457, 741, 411, 15895, 18891, 30133, 66767}},
-{7414, 17, 14455, {1, 3, 5, 11, 3, 23, 65, 81, 299, 527, 1057, 2731, 3839, 6023, 28887, 64929, 41405}},
-{7415, 17, 14461, {1, 3, 1, 1, 3, 5, 11, 169, 123, 957, 1495, 1717, 4079, 13239, 28339, 33677, 30591}},
-{7416, 17, 14466, {1, 1, 7, 15, 3, 1, 37, 245, 169, 273, 2039, 415, 6555, 13131, 11181, 62179, 36885}},
-{7417, 17, 14480, {1, 1, 3, 11, 1, 55, 19, 19, 425, 113, 1367, 2101, 5581, 985, 2475, 53983, 68999}},
-{7418, 17, 14490, {1, 1, 5, 9, 5, 33, 101, 193, 303, 579, 1265, 2791, 479, 12083, 17609, 31801, 113089}},
-{7419, 17, 14492, {1, 1, 3, 3, 17, 61, 59, 249, 81, 821, 1, 431, 5327, 8675, 23469, 15349, 67711}},
-{7420, 17, 14508, {1, 1, 7, 9, 31, 51, 89, 19, 469, 843, 561, 559, 4823, 7803, 31699, 44537, 56835}},
-{7421, 17, 14513, {1, 3, 7, 9, 11, 57, 27, 43, 469, 655, 433, 3081, 6719, 6651, 30823, 61503, 110711}},
-{7422, 17, 14516, {1, 3, 5, 11, 9, 53, 25, 147, 61, 533, 1369, 879, 7935, 13829, 26655, 17327, 52983}},
-{7423, 17, 14519, {1, 3, 7, 11, 15, 27, 97, 175, 435, 53, 75, 807, 549, 5277, 1831, 19421, 55669}},
-{7424, 17, 14525, {1, 1, 7, 15, 23, 5, 99, 133, 485, 587, 65, 2585, 7667, 2783, 19437, 52769, 1587}},
-{7425, 17, 14534, {1, 1, 7, 7, 13, 39, 111, 165, 489, 355, 1963, 333, 2993, 5233, 9173, 18951, 93737}},
-{7426, 17, 14537, {1, 1, 5, 7, 1, 29, 67, 135, 427, 91, 53, 3109, 3745, 9529, 17567, 42361, 84577}},
-{7427, 17, 14543, {1, 3, 5, 1, 31, 35, 59, 181, 87, 345, 1975, 781, 603, 16365, 19453, 9933, 112739}},
-{7428, 17, 14545, {1, 3, 3, 1, 31, 41, 127, 35, 263, 403, 1811, 383, 1523, 8477, 5973, 41569, 99309}},
-{7429, 17, 14552, {1, 3, 7, 7, 5, 25, 11, 201, 231, 679, 519, 2481, 7415, 12397, 21265, 49419, 13903}},
-{7430, 17, 14562, {1, 1, 7, 5, 1, 11, 63, 221, 327, 509, 419, 871, 7891, 11835, 11099, 10669, 43853}},
-{7431, 17, 14571, {1, 1, 5, 11, 19, 11, 37, 105, 265, 513, 1013, 707, 6083, 14571, 17573, 7645, 5363}},
-{7432, 17, 14574, {1, 1, 1, 13, 19, 19, 67, 93, 113, 509, 1013, 4037, 1939, 7015, 24487, 57183, 123463}},
-{7433, 17, 14582, {1, 1, 1, 1, 21, 17, 95, 25, 261, 1005, 685, 691, 4467, 14723, 24043, 32287, 19651}},
-{7434, 17, 14611, {1, 3, 1, 15, 15, 15, 57, 191, 27, 719, 229, 1977, 241, 9021, 21335, 30967, 81207}},
-{7435, 17, 14614, {1, 3, 1, 9, 23, 61, 103, 67, 361, 925, 811, 1007, 5707, 11479, 5907, 3897, 65141}},
-{7436, 17, 14620, {1, 3, 5, 9, 17, 61, 11, 15, 351, 715, 939, 2141, 4857, 8397, 9693, 26845, 120007}},
-{7437, 17, 14633, {1, 3, 1, 5, 19, 55, 99, 19, 291, 309, 287, 1969, 4341, 7579, 30909, 37277, 54927}},
-{7438, 17, 14641, {1, 3, 7, 3, 19, 29, 43, 163, 367, 753, 1733, 1463, 7927, 10671, 16817, 41229, 113887}},
-{7439, 17, 14648, {1, 3, 7, 1, 11, 51, 39, 207, 283, 73, 1423, 2473, 7593, 3581, 30179, 6369, 112217}},
-{7440, 17, 14671, {1, 1, 3, 15, 15, 25, 43, 5, 271, 611, 959, 537, 303, 3659, 18073, 8147, 81531}},
-{7441, 17, 14674, {1, 3, 7, 1, 27, 55, 77, 11, 367, 209, 1967, 3409, 935, 5309, 18857, 46225, 8367}},
-{7442, 17, 14689, {1, 1, 5, 11, 11, 63, 75, 73, 43, 869, 2021, 3285, 269, 9113, 32699, 2091, 17327}},
-{7443, 17, 14690, {1, 1, 5, 11, 9, 25, 31, 245, 109, 805, 1645, 3607, 817, 9571, 12767, 65441, 129977}},
-{7444, 17, 14692, {1, 3, 7, 5, 11, 61, 67, 223, 433, 387, 935, 1615, 7915, 6133, 24087, 55323, 100619}},
-{7445, 17, 14699, {1, 1, 1, 15, 25, 61, 7, 39, 311, 353, 183, 33, 2591, 4951, 31377, 9081, 9707}},
-{7446, 17, 14710, {1, 1, 3, 3, 1, 9, 65, 229, 185, 47, 1255, 1365, 2231, 6843, 26927, 27195, 60651}},
-{7447, 17, 14719, {1, 1, 7, 5, 7, 25, 91, 133, 159, 737, 1767, 3117, 7321, 6159, 3361, 27793, 33473}},
-{7448, 17, 14730, {1, 3, 7, 3, 11, 7, 5, 125, 369, 951, 1277, 65, 7703, 1817, 11773, 25657, 67045}},
-{7449, 17, 14732, {1, 1, 3, 9, 21, 27, 21, 41, 131, 605, 1, 119, 1553, 1361, 31973, 43135, 119321}},
-{7450, 17, 14743, {1, 3, 7, 1, 25, 63, 55, 173, 323, 403, 1401, 1367, 3455, 15335, 13045, 20759, 8309}},
-{7451, 17, 14744, {1, 1, 3, 5, 3, 61, 59, 7, 39, 439, 721, 2829, 3035, 2293, 32015, 28509, 104831}},
-{7452, 17, 14750, {1, 3, 5, 1, 29, 35, 71, 87, 351, 917, 1661, 547, 4501, 7107, 5493, 17833, 130729}},
-{7453, 17, 14759, {1, 1, 5, 5, 7, 5, 69, 57, 319, 595, 1749, 3789, 1437, 6327, 24089, 7387, 125109}},
-{7454, 17, 14763, {1, 3, 5, 9, 15, 53, 95, 59, 217, 37, 1561, 401, 5259, 4361, 1049, 3437, 30559}},
-{7455, 17, 14768, {1, 3, 7, 13, 15, 15, 107, 167, 475, 157, 1565, 2219, 1891, 1433, 11829, 43433, 48111}},
-{7456, 17, 14773, {1, 1, 1, 3, 11, 41, 25, 211, 243, 355, 1831, 2093, 2747, 2523, 9885, 9503, 120089}},
-{7457, 17, 14777, {1, 3, 7, 5, 11, 3, 1, 231, 243, 541, 341, 887, 3567, 14759, 26763, 35705, 29417}},
-{7458, 17, 14786, {1, 1, 7, 13, 17, 35, 117, 177, 81, 361, 1425, 2437, 6821, 1061, 15019, 19135, 106007}},
-{7459, 17, 14795, {1, 3, 3, 11, 19, 5, 39, 23, 367, 9, 879, 3583, 2527, 14375, 28359, 27393, 55041}},
-{7460, 17, 14800, {1, 1, 7, 11, 9, 41, 63, 125, 33, 337, 587, 3939, 2635, 4559, 1007, 38991, 35651}},
-{7461, 17, 14812, {1, 1, 3, 1, 19, 11, 83, 13, 227, 649, 415, 1661, 3285, 55, 3683, 22319, 2127}},
-{7462, 17, 14816, {1, 3, 7, 13, 19, 49, 113, 129, 83, 5, 19, 1095, 6561, 11049, 3805, 11355, 84265}},
-{7463, 17, 14836, {1, 3, 1, 9, 19, 41, 111, 193, 429, 319, 67, 1717, 1819, 12959, 31449, 21035, 113161}},
-{7464, 17, 14840, {1, 1, 5, 11, 19, 19, 115, 237, 145, 681, 1525, 2215, 7915, 15529, 7533, 45981, 85461}},
-{7465, 17, 14856, {1, 1, 1, 1, 25, 3, 73, 207, 15, 69, 43, 1643, 7707, 12505, 27101, 40735, 6091}},
-{7466, 17, 14859, {1, 1, 5, 11, 21, 61, 119, 7, 37, 147, 1379, 3165, 6555, 3867, 24027, 45161, 93015}},
-{7467, 17, 14870, {1, 1, 3, 9, 9, 25, 51, 125, 511, 209, 75, 2849, 2299, 2901, 25157, 13079, 67733}},
-{7468, 17, 14873, {1, 3, 7, 9, 31, 49, 99, 21, 89, 1, 1391, 1741, 2733, 7283, 12087, 9287, 39713}},
-{7469, 17, 14879, {1, 1, 5, 5, 1, 5, 89, 109, 499, 343, 431, 401, 2023, 5541, 16615, 40059, 119195}},
-{7470, 17, 14880, {1, 3, 5, 15, 27, 27, 9, 159, 395, 31, 865, 2793, 55, 10961, 23123, 63731, 54385}},
-{7471, 17, 14889, {1, 3, 7, 1, 11, 47, 123, 239, 399, 383, 1497, 4075, 4659, 2911, 2101, 8295, 115717}},
-{7472, 17, 14892, {1, 1, 3, 1, 11, 63, 125, 171, 65, 15, 349, 753, 2981, 6713, 6219, 14093, 78797}},
-{7473, 17, 14895, {1, 1, 1, 13, 9, 15, 1, 113, 221, 867, 1907, 103, 1411, 27, 22743, 377, 116907}},
-{7474, 17, 14900, {1, 3, 1, 5, 27, 5, 27, 245, 221, 575, 2009, 1561, 4263, 11843, 28331, 12865, 10483}},
-{7475, 17, 14903, {1, 3, 7, 9, 1, 51, 119, 241, 439, 913, 1191, 2343, 2055, 10247, 18283, 40175, 63321}},
-{7476, 17, 14910, {1, 1, 3, 15, 21, 59, 45, 151, 485, 293, 981, 3523, 7689, 2789, 5003, 62383, 126221}},
-{7477, 17, 14912, {1, 1, 1, 1, 13, 15, 39, 201, 405, 513, 1721, 2077, 5995, 2433, 20421, 12695, 20393}},
-{7478, 17, 14942, {1, 3, 5, 15, 11, 35, 113, 133, 187, 583, 577, 291, 7563, 12959, 9383, 44255, 81763}},
-{7479, 17, 14948, {1, 3, 7, 15, 9, 55, 57, 227, 189, 595, 1311, 1131, 1323, 11347, 12777, 50963, 13827}},
-{7480, 17, 14957, {1, 3, 5, 3, 11, 49, 77, 157, 107, 959, 761, 1457, 7121, 3027, 9269, 26291, 125261}},
-{7481, 17, 14963, {1, 1, 5, 9, 23, 53, 125, 211, 303, 433, 1103, 41, 2643, 5325, 11885, 23825, 80415}},
-{7482, 17, 14975, {1, 1, 7, 1, 29, 25, 51, 107, 209, 165, 707, 1855, 7429, 1583, 5941, 47509, 90105}},
-{7483, 17, 14985, {1, 1, 3, 3, 1, 15, 121, 165, 181, 259, 1949, 3049, 3545, 3093, 5967, 49207, 37129}},
-{7484, 17, 14993, {1, 1, 5, 13, 9, 59, 93, 87, 57, 343, 389, 1995, 4001, 11495, 12909, 13491, 61759}},
-{7485, 17, 15003, {1, 3, 1, 5, 11, 27, 27, 133, 459, 733, 1845, 1795, 4613, 3397, 12313, 52839, 129583}},
-{7486, 17, 15010, {1, 3, 5, 3, 19, 1, 7, 145, 255, 337, 1649, 1473, 4113, 4425, 12233, 55477, 69157}},
-{7487, 17, 15022, {1, 1, 3, 1, 25, 27, 93, 59, 415, 437, 25, 1565, 319, 8981, 2453, 53579, 45033}},
-{7488, 17, 15039, {1, 3, 7, 1, 27, 49, 47, 233, 341, 101, 2017, 2827, 8085, 237, 6363, 61139, 88903}},
-{7489, 17, 15041, {1, 1, 1, 5, 23, 47, 65, 251, 423, 957, 1751, 3541, 5405, 1335, 22703, 12587, 60201}},
-{7490, 17, 15047, {1, 1, 3, 3, 5, 51, 85, 195, 423, 519, 1797, 3821, 5915, 12257, 5377, 62733, 41197}},
-{7491, 17, 15048, {1, 3, 7, 15, 3, 47, 97, 1, 5, 175, 1449, 1609, 6873, 12017, 5579, 2665, 58389}},
-{7492, 17, 15056, {1, 3, 3, 15, 19, 37, 35, 29, 79, 767, 21, 1279, 1997, 11611, 14381, 35607, 127701}},
-{7493, 17, 15066, {1, 3, 7, 7, 7, 43, 47, 33, 69, 155, 703, 1373, 1589, 6997, 8627, 50647, 16989}},
-{7494, 17, 15068, {1, 3, 1, 5, 13, 33, 69, 133, 399, 361, 1633, 321, 2077, 8857, 13419, 23227, 40003}},
-{7495, 17, 15075, {1, 1, 1, 15, 15, 9, 45, 181, 427, 1005, 341, 1697, 6423, 5727, 7163, 10401, 38957}},
-{7496, 17, 15077, {1, 1, 7, 1, 17, 5, 17, 95, 279, 171, 825, 2459, 5243, 10683, 1849, 32809, 8995}},
-{7497, 17, 15082, {1, 3, 5, 15, 27, 47, 103, 69, 69, 255, 961, 2173, 5297, 5987, 5863, 14311, 117569}},
-{7498, 17, 15096, {1, 1, 1, 11, 21, 27, 61, 239, 183, 1013, 1955, 3171, 4183, 965, 14885, 49605, 87851}},
-{7499, 17, 15102, {1, 1, 7, 9, 9, 53, 99, 211, 267, 803, 1545, 4011, 7613, 13889, 28277, 6817, 26515}},
-{7500, 17, 15116, {1, 1, 3, 9, 1, 19, 33, 227, 461, 679, 499, 1069, 837, 12129, 20779, 12937, 104367}},
-{7501, 17, 15122, {1, 3, 3, 15, 7, 3, 29, 245, 179, 1015, 1651, 3753, 4185, 15357, 17379, 52835, 51953}},
-{7502, 17, 15127, {1, 3, 3, 3, 3, 25, 95, 239, 263, 427, 1749, 183, 5251, 361, 32549, 24331, 30789}},
-{7503, 17, 15133, {1, 1, 7, 1, 5, 3, 79, 9, 403, 195, 1433, 385, 8105, 7893, 16415, 23253, 127837}},
-{7504, 17, 15137, {1, 3, 7, 3, 23, 45, 115, 27, 473, 241, 361, 1787, 4247, 13451, 5627, 32923, 29375}},
-{7505, 17, 15138, {1, 3, 7, 1, 5, 55, 43, 37, 481, 899, 51, 2459, 5005, 12365, 19261, 32797, 45843}},
-{7506, 17, 15149, {1, 3, 7, 5, 9, 41, 83, 163, 241, 899, 567, 231, 4897, 15175, 10329, 6625, 95927}},
-{7507, 17, 15152, {1, 3, 1, 1, 7, 51, 61, 55, 253, 315, 1893, 2635, 4061, 257, 14147, 36639, 24893}},
-{7508, 17, 15155, {1, 1, 5, 1, 13, 63, 115, 119, 205, 309, 277, 2191, 341, 4715, 13111, 58043, 51241}},
-{7509, 17, 15158, {1, 3, 1, 15, 17, 23, 89, 121, 205, 15, 295, 667, 421, 14071, 27719, 1335, 9887}},
-{7510, 17, 15187, {1, 3, 5, 5, 17, 49, 5, 93, 251, 613, 1029, 945, 1547, 10479, 20183, 26787, 120441}},
-{7511, 17, 15189, {1, 3, 3, 15, 17, 11, 63, 97, 499, 313, 881, 2233, 4287, 5141, 13841, 40725, 49285}},
-{7512, 17, 15190, {1, 3, 3, 11, 19, 33, 105, 203, 325, 337, 353, 1923, 7157, 8623, 23881, 4513, 71495}},
-{7513, 17, 15196, {1, 1, 5, 1, 3, 15, 119, 43, 85, 869, 1597, 2433, 845, 5065, 12813, 64849, 58491}},
-{7514, 17, 15199, {1, 3, 7, 7, 25, 63, 119, 93, 303, 665, 571, 1795, 5853, 13527, 12715, 36483, 57723}},
-{7515, 17, 15205, {1, 3, 7, 13, 19, 43, 55, 85, 189, 627, 1457, 3185, 3491, 1913, 13399, 30681, 69015}},
-{7516, 17, 15212, {1, 3, 5, 9, 5, 41, 51, 65, 147, 425, 569, 1317, 1557, 7631, 17243, 37847, 51161}},
-{7517, 17, 15236, {1, 1, 3, 7, 29, 39, 61, 127, 489, 89, 749, 2073, 195, 14367, 13533, 27403, 16365}},
-{7518, 17, 15243, {1, 3, 7, 15, 13, 35, 45, 157, 373, 415, 725, 779, 3559, 7489, 11369, 36501, 60761}},
-{7519, 17, 15246, {1, 3, 1, 3, 13, 45, 25, 215, 385, 709, 499, 3861, 761, 15597, 3335, 37013, 13173}},
-{7520, 17, 15260, {1, 1, 7, 1, 13, 49, 89, 135, 175, 1015, 67, 957, 4893, 9843, 13027, 14709, 59721}},
-{7521, 17, 15267, {1, 3, 3, 11, 19, 37, 109, 143, 135, 535, 1543, 3991, 189, 6739, 28087, 18845, 41819}},
-{7522, 17, 15274, {1, 1, 7, 5, 1, 7, 11, 5, 211, 251, 1593, 2527, 3539, 10471, 25595, 60119, 89213}},
-{7523, 17, 15279, {1, 1, 5, 7, 13, 51, 121, 167, 299, 403, 977, 521, 279, 15521, 15901, 935, 14065}},
-{7524, 17, 15281, {1, 1, 7, 13, 7, 21, 27, 205, 377, 801, 1365, 1567, 6651, 139, 14229, 30827, 50429}},
-{7525, 17, 15282, {1, 1, 1, 1, 17, 11, 75, 87, 217, 413, 1923, 1765, 2037, 14061, 12433, 30671, 24883}},
-{7526, 17, 15284, {1, 1, 5, 13, 17, 51, 91, 241, 95, 505, 349, 2689, 1117, 4435, 1713, 44501, 125619}},
-{7527, 17, 15291, {1, 1, 3, 15, 11, 21, 25, 59, 511, 353, 799, 91, 4517, 16005, 17061, 21841, 46311}},
-{7528, 17, 15293, {1, 1, 1, 5, 19, 53, 109, 177, 213, 373, 761, 453, 5753, 69, 3503, 49411, 111105}},
-{7529, 17, 15302, {1, 3, 1, 5, 21, 27, 103, 167, 109, 55, 1849, 3999, 7801, 4185, 9789, 7515, 124983}},
-{7530, 17, 15319, {1, 3, 7, 7, 25, 9, 65, 127, 141, 169, 1079, 3377, 691, 5119, 6629, 3517, 28963}},
-{7531, 17, 15329, {1, 1, 3, 11, 15, 61, 127, 35, 87, 891, 1459, 483, 6763, 16173, 5633, 6939, 63411}},
-{7532, 17, 15336, {1, 3, 5, 3, 7, 63, 111, 85, 415, 273, 1705, 4045, 5551, 2377, 29025, 16831, 90203}},
-{7533, 17, 15347, {1, 3, 5, 13, 7, 23, 103, 227, 477, 985, 1059, 1489, 7233, 1917, 10409, 38759, 86761}},
-{7534, 17, 15353, {1, 3, 5, 7, 31, 33, 75, 41, 355, 577, 225, 5, 897, 15653, 27415, 83, 14911}},
-{7535, 17, 15361, {1, 3, 5, 5, 23, 13, 5, 43, 165, 53, 149, 2005, 4545, 477, 17885, 21343, 35751}},
-{7536, 17, 15371, {1, 3, 3, 3, 25, 51, 33, 203, 291, 835, 241, 3255, 3709, 3573, 9859, 33027, 122801}},
-{7537, 17, 15397, {1, 3, 5, 7, 13, 7, 3, 141, 455, 67, 2003, 3411, 4717, 157, 29491, 14429, 44849}},
-{7538, 17, 15404, {1, 1, 1, 11, 3, 33, 101, 93, 219, 371, 1191, 1521, 1663, 8485, 24815, 38283, 120867}},
-{7539, 17, 15407, {1, 1, 3, 9, 25, 61, 71, 173, 69, 181, 1525, 2129, 2979, 19, 13489, 627, 72619}},
-{7540, 17, 15421, {1, 3, 1, 7, 25, 33, 39, 247, 221, 7, 683, 1837, 8037, 9125, 4259, 63049, 63021}},
-{7541, 17, 15433, {1, 3, 3, 9, 17, 15, 9, 189, 357, 707, 521, 711, 8189, 12945, 29675, 11851, 126813}},
-{7542, 17, 15441, {1, 3, 1, 1, 23, 3, 57, 133, 245, 301, 957, 239, 3139, 7949, 27133, 18229, 93015}},
-{7543, 17, 15442, {1, 1, 3, 1, 29, 23, 35, 87, 231, 257, 1997, 271, 3019, 3409, 10613, 42245, 111309}},
-{7544, 17, 15463, {1, 1, 3, 3, 1, 21, 17, 37, 393, 943, 791, 3101, 6715, 11907, 25369, 9061, 75381}},
-{7545, 17, 15472, {1, 1, 7, 7, 17, 31, 25, 7, 183, 819, 1265, 3343, 6845, 2039, 3779, 41861, 38309}},
-{7546, 17, 15478, {1, 1, 1, 5, 17, 25, 1, 41, 173, 995, 863, 3515, 1779, 2159, 28223, 64661, 40697}},
-{7547, 17, 15488, {1, 1, 3, 15, 29, 49, 81, 241, 511, 817, 1301, 3593, 6759, 7483, 8859, 30339, 106137}},
-{7548, 17, 15493, {1, 3, 1, 11, 17, 61, 95, 231, 3, 693, 37, 1091, 3111, 11941, 17475, 8073, 62373}},
-{7549, 17, 15498, {1, 1, 1, 3, 7, 25, 93, 7, 291, 957, 859, 2519, 241, 10963, 10403, 933, 50599}},
-{7550, 17, 15511, {1, 1, 7, 1, 7, 33, 121, 91, 369, 333, 229, 4073, 6063, 6491, 31711, 65061, 107843}},
-{7551, 17, 15521, {1, 1, 5, 15, 17, 1, 117, 195, 445, 547, 867, 2893, 4835, 6513, 29091, 60367, 33409}},
-{7552, 17, 15534, {1, 3, 3, 7, 15, 5, 125, 131, 165, 127, 207, 853, 5927, 3605, 17083, 44481, 111333}},
-{7553, 17, 15539, {1, 1, 1, 9, 3, 43, 75, 191, 319, 889, 1513, 3301, 1535, 4693, 10367, 12491, 43175}},
-{7554, 17, 15541, {1, 3, 5, 5, 29, 19, 75, 221, 393, 977, 1373, 1571, 7377, 1763, 18073, 11381, 101241}},
-{7555, 17, 15560, {1, 3, 1, 15, 3, 15, 73, 91, 165, 213, 1077, 1267, 2411, 15807, 3979, 12731, 86597}},
-{7556, 17, 15563, {1, 1, 3, 7, 3, 21, 5, 135, 95, 337, 1853, 1675, 2449, 12535, 18505, 60127, 76949}},
-{7557, 17, 15574, {1, 1, 7, 3, 15, 11, 63, 127, 329, 169, 1569, 675, 4801, 5859, 3243, 25811, 77841}},
-{7558, 17, 15578, {1, 1, 1, 9, 19, 13, 73, 119, 105, 537, 951, 1033, 5303, 5775, 815, 19277, 57607}},
-{7559, 17, 15584, {1, 3, 5, 5, 23, 21, 91, 231, 117, 1007, 1603, 841, 2595, 11223, 17171, 25963, 17049}},
-{7560, 17, 15593, {1, 1, 5, 11, 15, 43, 7, 229, 55, 129, 599, 993, 563, 15677, 16703, 36253, 17847}},
-{7561, 17, 15604, {1, 3, 1, 9, 25, 3, 109, 21, 87, 721, 1927, 3219, 3395, 3267, 9117, 13591, 89267}},
-{7562, 17, 15614, {1, 1, 1, 15, 11, 17, 47, 49, 125, 925, 333, 945, 2411, 10907, 12021, 47857, 84303}},
-{7563, 17, 15619, {1, 1, 1, 1, 23, 11, 99, 215, 105, 417, 823, 1289, 421, 12285, 17711, 35389, 1935}},
-{7564, 17, 15622, {1, 1, 1, 15, 27, 7, 23, 141, 7, 929, 147, 681, 5473, 4173, 28645, 42053, 83573}},
-{7565, 17, 15633, {1, 1, 1, 11, 5, 61, 71, 65, 287, 697, 1183, 3257, 7251, 14011, 21349, 42445, 4701}},
-{7566, 17, 15639, {1, 3, 5, 9, 5, 23, 45, 217, 369, 189, 1495, 107, 425, 10467, 4909, 64293, 17885}},
-{7567, 17, 15646, {1, 1, 3, 11, 21, 45, 75, 65, 57, 893, 783, 3429, 409, 13617, 483, 62489, 2919}},
-{7568, 17, 15673, {1, 1, 7, 3, 5, 61, 51, 255, 501, 839, 367, 1165, 7055, 8139, 23891, 18807, 20739}},
-{7569, 17, 15674, {1, 1, 3, 7, 23, 15, 97, 139, 323, 463, 921, 1529, 6655, 8697, 23577, 56761, 62023}},
-{7570, 17, 15684, {1, 1, 5, 11, 13, 11, 57, 225, 277, 713, 1427, 95, 1135, 7721, 30731, 32625, 107891}},
-{7571, 17, 15691, {1, 1, 5, 7, 23, 35, 39, 91, 291, 609, 919, 3325, 6843, 7659, 5603, 37471, 41495}},
-{7572, 17, 15694, {1, 1, 1, 1, 25, 11, 117, 15, 389, 589, 1345, 423, 6531, 9903, 20243, 9523, 22991}},
-{7573, 17, 15696, {1, 3, 5, 15, 29, 7, 57, 113, 387, 883, 1141, 3295, 2973, 4129, 16973, 33429, 109997}},
-{7574, 17, 15701, {1, 3, 5, 3, 25, 1, 73, 207, 353, 203, 1479, 985, 6373, 3079, 28403, 63675, 21787}},
-{7575, 17, 15705, {1, 3, 1, 5, 31, 39, 107, 197, 359, 45, 203, 559, 4721, 6579, 11305, 12957, 10061}},
-{7576, 17, 15715, {1, 3, 7, 15, 9, 3, 55, 153, 373, 981, 575, 827, 4757, 15743, 14295, 43875, 17847}},
-{7577, 17, 15729, {1, 3, 5, 1, 17, 1, 93, 87, 207, 997, 1695, 3643, 6973, 9507, 29309, 58531, 6849}},
-{7578, 17, 15730, {1, 3, 1, 11, 3, 39, 17, 241, 83, 931, 39, 3839, 6437, 5159, 28869, 61859, 96873}},
-{7579, 17, 15741, {1, 1, 5, 13, 29, 43, 71, 159, 261, 563, 695, 1205, 2273, 8077, 12569, 17187, 54369}},
-{7580, 17, 15745, {1, 3, 7, 5, 11, 57, 17, 31, 311, 1001, 1419, 3899, 6679, 15531, 28877, 28221, 105413}},
-{7581, 17, 15748, {1, 3, 3, 13, 23, 29, 127, 19, 345, 1003, 1571, 2219, 3199, 9903, 18701, 31865, 108879}},
-{7582, 17, 15757, {1, 3, 7, 13, 23, 51, 95, 43, 35, 439, 25, 323, 2365, 12407, 27525, 57795, 74495}},
-{7583, 17, 15765, {1, 1, 1, 1, 17, 43, 57, 185, 439, 929, 69, 813, 6205, 3139, 3853, 56967, 19073}},
-{7584, 17, 15766, {1, 3, 7, 1, 27, 5, 43, 211, 395, 113, 1675, 1505, 6171, 5169, 9991, 21641, 27101}},
-{7585, 17, 15775, {1, 3, 3, 1, 17, 41, 59, 131, 131, 339, 955, 1145, 5301, 4585, 20441, 43227, 23123}},
-{7586, 17, 15776, {1, 1, 7, 9, 9, 55, 61, 31, 71, 229, 963, 3247, 4677, 9595, 21715, 36391, 86997}},
-{7587, 17, 15779, {1, 1, 7, 5, 9, 17, 55, 179, 27, 229, 79, 1335, 5887, 1003, 22085, 34377, 51367}},
-{7588, 17, 15786, {1, 1, 1, 5, 11, 45, 15, 219, 411, 27, 1003, 1553, 303, 13571, 13985, 6801, 52407}},
-{7589, 17, 15788, {1, 3, 3, 7, 7, 55, 111, 255, 453, 409, 1863, 1449, 4103, 8725, 26923, 5017, 43657}},
-{7590, 17, 15813, {1, 1, 1, 15, 23, 3, 95, 57, 29, 727, 1111, 3309, 1089, 471, 16099, 11517, 51563}},
-{7591, 17, 15814, {1, 3, 1, 15, 17, 57, 83, 163, 251, 987, 1159, 2079, 3463, 13109, 7443, 8665, 123397}},
-{7592, 17, 15842, {1, 1, 7, 1, 27, 13, 35, 209, 471, 843, 1029, 1383, 5413, 2085, 13431, 26557, 47033}},
-{7593, 17, 15851, {1, 3, 1, 1, 21, 21, 83, 135, 303, 27, 1407, 1751, 331, 9207, 31891, 59287, 120687}},
-{7594, 17, 15862, {1, 1, 1, 9, 11, 35, 103, 157, 1, 855, 175, 3203, 4381, 3113, 27589, 4567, 31897}},
-{7595, 17, 15875, {1, 1, 3, 5, 21, 5, 123, 161, 301, 101, 909, 947, 6893, 15459, 29139, 49377, 94901}},
-{7596, 17, 15878, {1, 3, 7, 7, 21, 27, 5, 69, 427, 409, 1389, 3737, 847, 2775, 603, 1001, 87651}},
-{7597, 17, 15889, {1, 1, 3, 5, 1, 57, 109, 89, 99, 593, 581, 3527, 1557, 4971, 27523, 26909, 35787}},
-{7598, 17, 15896, {1, 1, 7, 3, 31, 19, 83, 65, 239, 919, 15, 2289, 4117, 9127, 6033, 49667, 89343}},
-{7599, 17, 15901, {1, 3, 7, 7, 9, 31, 87, 117, 195, 681, 1711, 1753, 2221, 10053, 1985, 6273, 21801}},
-{7600, 17, 15908, {1, 3, 1, 7, 21, 61, 53, 231, 309, 115, 1729, 3883, 6085, 4825, 31455, 50097, 59779}},
-{7601, 17, 15911, {1, 1, 1, 9, 29, 25, 45, 91, 145, 927, 147, 371, 2603, 12537, 17267, 59895, 128009}},
-{7602, 17, 15915, {1, 1, 1, 1, 15, 41, 63, 43, 167, 215, 15, 3387, 1811, 12391, 25721, 6961, 13701}},
-{7603, 17, 15938, {1, 1, 7, 1, 27, 63, 25, 85, 337, 799, 87, 2237, 4085, 14529, 11493, 60149, 86399}},
-{7604, 17, 15944, {1, 3, 1, 11, 1, 41, 103, 145, 279, 805, 1201, 823, 5411, 4227, 25999, 14373, 36295}},
-{7605, 17, 15950, {1, 1, 7, 3, 27, 51, 83, 105, 155, 657, 1879, 3869, 2559, 2939, 19785, 47167, 34503}},
-{7606, 17, 15955, {1, 3, 1, 5, 3, 31, 47, 241, 257, 15, 983, 4095, 3745, 3901, 1639, 5421, 81585}},
-{7607, 17, 15974, {1, 3, 3, 5, 31, 13, 127, 125, 175, 577, 1103, 3573, 6229, 13969, 6267, 19067, 3933}},
-{7608, 17, 15978, {1, 1, 7, 1, 31, 17, 15, 15, 411, 553, 1929, 3731, 1955, 11749, 21991, 39189, 124427}},
-{7609, 17, 15980, {1, 3, 5, 5, 19, 63, 93, 201, 491, 599, 1093, 767, 3411, 13087, 23569, 42981, 35757}},
-{7610, 17, 15983, {1, 1, 1, 15, 27, 7, 51, 101, 429, 939, 111, 781, 2055, 14227, 17821, 42097, 32485}},
-{7611, 17, 15991, {1, 3, 7, 13, 11, 21, 3, 161, 353, 389, 285, 2633, 6245, 7089, 21907, 40765, 88869}},
-{7612, 17, 16004, {1, 1, 5, 9, 7, 27, 101, 203, 243, 897, 1375, 1619, 5275, 12935, 22103, 38005, 65603}},
-{7613, 17, 16011, {1, 1, 5, 9, 13, 25, 15, 21, 447, 7, 947, 1613, 5055, 129, 18057, 58551, 6603}},
-{7614, 17, 16016, {1, 3, 7, 15, 17, 41, 11, 55, 103, 339, 349, 1813, 7423, 11837, 20641, 51951, 61615}},
-{7615, 17, 16019, {1, 3, 3, 15, 21, 59, 113, 3, 123, 689, 465, 3039, 4109, 3241, 30317, 65053, 117845}},
-{7616, 17, 16025, {1, 3, 3, 1, 31, 33, 73, 155, 245, 401, 473, 51, 1387, 489, 10573, 55401, 106733}},
-{7617, 17, 16041, {1, 3, 3, 1, 31, 37, 15, 139, 127, 201, 229, 1753, 7287, 9045, 18321, 63485, 26399}},
-{7618, 17, 16064, {1, 3, 5, 5, 5, 23, 93, 3, 125, 715, 1827, 419, 1213, 9031, 25139, 20771, 41345}},
-{7619, 17, 16067, {1, 3, 5, 15, 23, 15, 13, 145, 105, 477, 1131, 2699, 1929, 10447, 9655, 26791, 80101}},
-{7620, 17, 16074, {1, 1, 1, 13, 1, 35, 75, 73, 269, 851, 737, 1909, 6805, 11359, 28991, 52435, 83767}},
-{7621, 17, 16082, {1, 1, 7, 5, 11, 31, 31, 91, 111, 161, 1865, 2545, 133, 12215, 8957, 20671, 92975}},
-{7622, 17, 16103, {1, 1, 7, 5, 25, 53, 55, 121, 53, 457, 831, 2493, 339, 10955, 30783, 9095, 97921}},
-{7623, 17, 16109, {1, 1, 5, 3, 25, 33, 81, 51, 211, 737, 1865, 4039, 6931, 8473, 22459, 24885, 96355}},
-{7624, 17, 16122, {1, 3, 7, 13, 23, 5, 101, 171, 65, 793, 443, 411, 7629, 14791, 28633, 9055, 123763}},
-{7625, 17, 16149, {1, 3, 3, 1, 11, 7, 99, 79, 461, 481, 1689, 3777, 2125, 4783, 13061, 19537, 68109}},
-{7626, 17, 16170, {1, 1, 3, 11, 31, 53, 109, 7, 49, 925, 1017, 2371, 1537, 13557, 75, 40677, 49181}},
-{7627, 17, 16175, {1, 3, 3, 3, 9, 1, 95, 113, 189, 389, 377, 393, 6523, 3183, 6461, 30201, 66549}},
-{7628, 17, 16178, {1, 1, 7, 15, 13, 19, 41, 171, 475, 157, 949, 3245, 5581, 2783, 25263, 53023, 11155}},
-{7629, 17, 16189, {1, 3, 5, 7, 29, 63, 61, 65, 315, 595, 905, 899, 5059, 4243, 27287, 14023, 64213}},
-{7630, 17, 16202, {1, 3, 1, 3, 15, 37, 109, 161, 9, 867, 1023, 2513, 4593, 7747, 1505, 4801, 127091}},
-{7631, 17, 16204, {1, 3, 1, 7, 11, 59, 75, 129, 469, 695, 63, 2757, 6357, 8675, 6193, 23439, 66445}},
-{7632, 17, 16222, {1, 1, 3, 13, 17, 9, 47, 91, 161, 265, 139, 129, 6707, 9659, 8917, 54757, 77835}},
-{7633, 17, 16231, {1, 1, 3, 13, 19, 37, 113, 255, 99, 913, 1445, 487, 337, 1001, 16395, 37141, 66595}},
-{7634, 17, 16238, {1, 1, 1, 15, 3, 63, 69, 43, 185, 293, 1137, 2061, 2377, 8741, 26817, 5833, 7807}},
-{7635, 17, 16262, {1, 1, 1, 5, 3, 29, 39, 33, 263, 355, 597, 539, 5055, 13075, 8977, 19829, 88171}},
-{7636, 17, 16265, {1, 3, 7, 9, 17, 49, 125, 101, 447, 597, 1337, 559, 2807, 7925, 12421, 17427, 34815}},
-{7637, 17, 16276, {1, 3, 1, 9, 11, 57, 31, 163, 503, 925, 911, 3721, 2515, 8429, 25749, 55209, 90105}},
-{7638, 17, 16285, {1, 3, 5, 3, 21, 57, 119, 233, 319, 745, 563, 3057, 2683, 7063, 11513, 49157, 64561}},
-{7639, 17, 16313, {1, 1, 3, 9, 15, 21, 93, 99, 227, 479, 965, 51, 6941, 9887, 32409, 23171, 98387}},
-{7640, 17, 16314, {1, 3, 5, 5, 19, 1, 47, 49, 233, 931, 971, 2369, 2827, 1291, 18653, 725, 19791}},
-{7641, 17, 16321, {1, 1, 5, 15, 3, 7, 71, 251, 341, 861, 1203, 793, 7627, 10929, 10717, 10677, 49743}},
-{7642, 17, 16327, {1, 3, 1, 7, 3, 43, 9, 187, 247, 621, 1069, 2875, 1525, 4221, 18813, 35807, 117609}},
-{7643, 17, 16333, {1, 3, 3, 3, 29, 39, 83, 201, 205, 337, 231, 547, 2893, 2483, 6197, 26869, 18921}},
-{7644, 17, 16334, {1, 1, 7, 3, 23, 29, 33, 137, 491, 691, 979, 65, 5711, 11685, 5137, 37993, 37075}},
-{7645, 17, 16364, {1, 3, 3, 1, 11, 3, 99, 119, 203, 901, 1887, 879, 7547, 4613, 31233, 13279, 105089}},
-{7646, 17, 16369, {1, 1, 1, 13, 25, 23, 111, 167, 313, 141, 127, 1223, 5711, 4101, 10977, 34695, 128303}},
-{7647, 17, 16370, {1, 1, 7, 15, 5, 3, 89, 151, 289, 769, 539, 2883, 8121, 15403, 22345, 63765, 117015}},
-{7648, 17, 16375, {1, 1, 1, 13, 15, 9, 71, 95, 37, 705, 1575, 3735, 7445, 2027, 27523, 53321, 106085}},
-{7649, 17, 16376, {1, 3, 5, 7, 5, 29, 7, 25, 181, 491, 1173, 1947, 3321, 9233, 17265, 26999, 97783}},
-{7650, 17, 16379, {1, 1, 3, 15, 1, 63, 111, 113, 279, 123, 345, 1529, 2725, 8643, 8551, 30073, 26689}},
-{7651, 17, 16393, {1, 3, 7, 7, 5, 55, 117, 211, 293, 851, 1491, 3265, 4009, 14949, 10297, 16219, 69983}},
-{7652, 17, 16402, {1, 1, 3, 11, 23, 45, 35, 91, 97, 191, 417, 3545, 1733, 3955, 10763, 10229, 75027}},
-{7653, 17, 16408, {1, 1, 3, 13, 3, 61, 69, 205, 379, 627, 295, 3979, 85, 11305, 2493, 35583, 3133}},
-{7654, 17, 16418, {1, 3, 5, 9, 5, 63, 67, 201, 351, 367, 1009, 739, 5409, 8715, 28939, 31511, 34599}},
-{7655, 17, 16438, {1, 1, 1, 5, 3, 25, 21, 25, 477, 301, 623, 157, 563, 9457, 24515, 30135, 107165}},
-{7656, 17, 16441, {1, 1, 3, 15, 5, 41, 49, 171, 469, 427, 857, 2165, 1437, 2151, 24061, 63243, 105331}},
-{7657, 17, 16447, {1, 3, 5, 11, 21, 25, 59, 167, 29, 653, 1503, 2223, 3889, 4605, 28381, 36075, 74907}},
-{7658, 17, 16450, {1, 3, 7, 7, 17, 55, 73, 127, 33, 319, 1565, 2761, 6473, 2187, 19939, 56687, 112137}},
-{7659, 17, 16455, {1, 1, 1, 9, 7, 53, 105, 3, 299, 15, 1009, 607, 6885, 12875, 20719, 16841, 70471}},
-{7660, 17, 16459, {1, 3, 5, 9, 7, 33, 23, 163, 279, 739, 1541, 3017, 2309, 11827, 3875, 44337, 82063}},
-{7661, 17, 16483, {1, 1, 1, 5, 19, 53, 109, 193, 331, 339, 477, 4093, 5177, 13527, 25731, 64137, 81411}},
-{7662, 17, 16490, {1, 3, 7, 13, 15, 63, 101, 145, 127, 13, 1431, 3581, 4993, 14287, 12125, 60217, 102563}},
-{7663, 17, 16492, {1, 3, 1, 7, 17, 27, 127, 81, 223, 763, 761, 2061, 1031, 12251, 14141, 23587, 124813}},
-{7664, 17, 16495, {1, 3, 5, 13, 27, 21, 9, 249, 285, 875, 65, 4075, 6749, 13417, 3079, 29343, 87075}},
-{7665, 17, 16523, {1, 3, 5, 13, 1, 31, 61, 21, 169, 145, 1681, 1229, 5059, 13555, 21373, 35597, 70669}},
-{7666, 17, 16528, {1, 3, 7, 15, 23, 31, 43, 237, 139, 9, 1905, 3197, 801, 14205, 13323, 18717, 88523}},
-{7667, 17, 16543, {1, 1, 1, 11, 1, 7, 21, 83, 15, 459, 537, 4029, 6973, 4019, 1, 35147, 16329}},
-{7668, 17, 16553, {1, 3, 7, 15, 23, 11, 17, 101, 235, 683, 913, 3529, 4363, 13899, 3603, 27741, 74143}},
-{7669, 17, 16562, {1, 1, 7, 7, 3, 3, 91, 107, 499, 723, 315, 2805, 5909, 11041, 18281, 54981, 76041}},
-{7670, 17, 16564, {1, 3, 7, 9, 15, 7, 93, 171, 275, 647, 655, 3565, 2199, 14795, 21945, 9373, 122299}},
-{7671, 17, 16576, {1, 1, 1, 5, 27, 53, 73, 27, 431, 707, 53, 1281, 49, 13199, 1973, 18935, 114821}},
-{7672, 17, 16588, {1, 1, 3, 3, 25, 1, 17, 159, 217, 413, 1393, 2119, 5611, 7659, 6003, 19927, 22287}},
-{7673, 17, 16612, {1, 1, 7, 15, 29, 59, 77, 9, 205, 795, 627, 2167, 2477, 6841, 17663, 34871, 79823}},
-{7674, 17, 16630, {1, 3, 5, 9, 13, 35, 79, 237, 11, 335, 789, 2291, 13, 853, 20373, 39049, 407}},
-{7675, 17, 16654, {1, 1, 5, 7, 13, 27, 21, 173, 137, 659, 123, 2677, 2153, 14879, 26737, 56291, 47613}},
-{7676, 17, 16656, {1, 3, 5, 15, 23, 47, 15, 109, 311, 597, 261, 2407, 8139, 3215, 28169, 60731, 79937}},
-{7677, 17, 16668, {1, 3, 3, 5, 11, 61, 71, 29, 189, 741, 1171, 397, 2669, 10627, 20037, 51703, 6697}},
-{7678, 17, 16672, {1, 3, 3, 3, 9, 41, 125, 1, 381, 399, 349, 3265, 6337, 8113, 14869, 5305, 83409}},
-{7679, 17, 16675, {1, 1, 3, 13, 5, 19, 33, 225, 45, 55, 1809, 1037, 5443, 15719, 9963, 363, 15145}},
-{7680, 17, 16678, {1, 3, 7, 1, 31, 25, 103, 29, 207, 169, 305, 913, 7501, 15323, 10575, 13477, 65245}},
-{7681, 17, 16681, {1, 3, 3, 15, 13, 23, 69, 255, 333, 157, 279, 1989, 3439, 12955, 13649, 52431, 90009}},
-{7682, 17, 16689, {1, 3, 7, 5, 23, 61, 111, 121, 79, 469, 89, 1545, 3405, 12393, 2035, 15989, 84855}},
-{7683, 17, 16699, {1, 1, 7, 5, 17, 21, 127, 151, 283, 521, 5, 3023, 5365, 11633, 21177, 42207, 48925}},
-{7684, 17, 16719, {1, 3, 7, 5, 21, 21, 61, 17, 415, 879, 1485, 3727, 935, 9899, 23241, 651, 103701}},
-{7685, 17, 16734, {1, 3, 5, 15, 31, 47, 19, 245, 249, 467, 253, 1575, 337, 863, 19353, 13153, 125453}},
-{7686, 17, 16737, {1, 1, 7, 15, 9, 41, 39, 63, 139, 875, 1011, 1961, 1627, 7461, 28961, 47195, 16239}},
-{7687, 17, 16750, {1, 3, 3, 7, 27, 55, 51, 245, 231, 619, 43, 91, 2125, 2685, 23661, 10189, 43085}},
-{7688, 17, 16752, {1, 1, 7, 9, 27, 55, 35, 139, 187, 143, 1545, 2685, 3173, 12065, 21607, 42619, 105279}},
-{7689, 17, 16757, {1, 1, 5, 3, 29, 63, 15, 197, 49, 995, 389, 1959, 2441, 11509, 31753, 40539, 26989}},
-{7690, 17, 16761, {1, 3, 7, 15, 19, 37, 17, 37, 305, 469, 945, 2335, 1493, 13843, 19905, 49031, 107893}},
-{7691, 17, 16773, {1, 3, 1, 11, 3, 35, 113, 181, 223, 27, 485, 2435, 3423, 11321, 1687, 45755, 18017}},
-{7692, 17, 16774, {1, 3, 3, 13, 17, 47, 109, 145, 287, 769, 1373, 3423, 1251, 14357, 3209, 28363, 97987}},
-{7693, 17, 16801, {1, 1, 3, 13, 7, 25, 93, 11, 23, 331, 517, 1705, 1957, 291, 763, 10411, 120367}},
-{7694, 17, 16802, {1, 3, 7, 15, 25, 9, 1, 33, 83, 61, 97, 509, 5387, 8701, 14243, 31883, 7375}},
-{7695, 17, 16822, {1, 3, 1, 5, 19, 11, 59, 95, 265, 205, 533, 1857, 693, 12469, 24445, 19449, 130623}},
-{7696, 17, 16831, {1, 1, 7, 7, 1, 5, 15, 159, 333, 361, 391, 1889, 2645, 15115, 30709, 60515, 13315}},
-{7697, 17, 16840, {1, 3, 5, 15, 25, 61, 69, 213, 183, 575, 1573, 3147, 1753, 2387, 23063, 12853, 108507}},
-{7698, 17, 16854, {1, 1, 1, 15, 17, 31, 11, 177, 411, 23, 469, 3985, 2159, 2273, 14175, 20425, 107741}},
-{7699, 17, 16858, {1, 1, 3, 9, 5, 35, 55, 225, 263, 641, 1393, 1277, 595, 2671, 7039, 64999, 114387}},
-{7700, 17, 16863, {1, 1, 3, 3, 11, 23, 1, 161, 77, 755, 1325, 1773, 4291, 13119, 29677, 27295, 81713}},
-{7701, 17, 16867, {1, 1, 5, 13, 31, 45, 115, 141, 449, 171, 1413, 2411, 7937, 10859, 19453, 64403, 45169}},
-{7702, 17, 16876, {1, 3, 5, 7, 1, 27, 117, 157, 99, 119, 1281, 2633, 5117, 16009, 19545, 7421, 30807}},
-{7703, 17, 16891, {1, 1, 3, 13, 19, 11, 61, 239, 331, 731, 1723, 1773, 2623, 15255, 17197, 63793, 100433}},
-{7704, 17, 16894, {1, 3, 7, 11, 11, 7, 119, 33, 195, 521, 811, 2599, 3113, 5497, 16751, 2541, 21813}},
-{7705, 17, 16898, {1, 1, 1, 15, 23, 47, 25, 73, 429, 213, 557, 1613, 7055, 7211, 2225, 1345, 58033}},
-{7706, 17, 16907, {1, 1, 1, 13, 15, 39, 69, 71, 11, 543, 267, 2803, 4853, 9819, 603, 4629, 78343}},
-{7707, 17, 16915, {1, 1, 7, 1, 15, 55, 47, 223, 63, 679, 1135, 3225, 3845, 12031, 6761, 20337, 29021}},
-{7708, 17, 16917, {1, 1, 3, 3, 3, 51, 127, 103, 43, 379, 169, 2549, 7775, 2553, 27415, 30671, 34043}},
-{7709, 17, 16922, {1, 1, 3, 11, 1, 31, 89, 113, 475, 857, 499, 3901, 5343, 8819, 4503, 58757, 60513}},
-{7710, 17, 16924, {1, 3, 5, 11, 27, 49, 97, 217, 91, 971, 1835, 3447, 2021, 3747, 20533, 13659, 84007}},
-{7711, 17, 16933, {1, 1, 5, 1, 31, 39, 49, 21, 135, 983, 579, 3509, 3611, 15101, 29781, 49941, 14353}},
-{7712, 17, 16938, {1, 1, 1, 9, 7, 17, 55, 233, 295, 161, 823, 3823, 4771, 13531, 24197, 42629, 60269}},
-{7713, 17, 16952, {1, 1, 3, 15, 23, 5, 101, 167, 55, 297, 1733, 3819, 7041, 9915, 27803, 60359, 10249}},
-{7714, 17, 16960, {1, 1, 7, 9, 25, 47, 67, 253, 303, 313, 1389, 3785, 2729, 11471, 27267, 42783, 111595}},
-{7715, 17, 16963, {1, 1, 5, 13, 25, 63, 17, 195, 457, 793, 1553, 1673, 6799, 12171, 9003, 22195, 90229}},
-{7716, 17, 16969, {1, 1, 3, 15, 11, 43, 43, 221, 423, 985, 873, 599, 1753, 4875, 7149, 34625, 8941}},
-{7717, 17, 16978, {1, 3, 5, 11, 1, 7, 109, 163, 309, 477, 1291, 3019, 1933, 14055, 15005, 1141, 66867}},
-{7718, 17, 17014, {1, 3, 3, 15, 21, 35, 95, 131, 413, 1009, 147, 2165, 6333, 8313, 20873, 18377, 23579}},
-{7719, 17, 17020, {1, 3, 1, 5, 21, 49, 29, 187, 67, 419, 253, 2345, 3179, 12331, 23127, 8799, 102493}},
-{7720, 17, 17034, {1, 1, 7, 5, 29, 59, 13, 189, 377, 595, 1893, 527, 7993, 14867, 24671, 14585, 38645}},
-{7721, 17, 17036, {1, 3, 5, 13, 3, 11, 99, 69, 253, 833, 1961, 2719, 3953, 8143, 21277, 16257, 26929}},
-{7722, 17, 17042, {1, 3, 7, 3, 3, 19, 19, 57, 393, 187, 945, 2107, 669, 14785, 13895, 26907, 92439}},
-{7723, 17, 17047, {1, 3, 5, 15, 11, 5, 73, 167, 99, 887, 1213, 2019, 3781, 14345, 30249, 16215, 1893}},
-{7724, 17, 17051, {1, 1, 5, 1, 17, 11, 69, 145, 97, 393, 1587, 2513, 1011, 6933, 7945, 41387, 34361}},
-{7725, 17, 17054, {1, 1, 5, 1, 5, 59, 57, 1, 501, 855, 1485, 977, 4981, 7631, 31853, 30737, 103023}},
-{7726, 17, 17063, {1, 3, 1, 5, 3, 27, 55, 171, 317, 641, 1875, 2523, 1631, 4971, 18743, 25119, 118913}},
-{7727, 17, 17069, {1, 1, 3, 15, 7, 39, 73, 209, 125, 29, 1031, 1569, 1793, 5461, 985, 59441, 92997}},
-{7728, 17, 17075, {1, 3, 5, 11, 27, 23, 57, 13, 65, 555, 1309, 1149, 5125, 11573, 3835, 57913, 78699}},
-{7729, 17, 17077, {1, 3, 7, 5, 29, 7, 51, 131, 443, 623, 1491, 1067, 6647, 6277, 25799, 54843, 90869}},
-{7730, 17, 17089, {1, 1, 1, 11, 7, 33, 67, 113, 319, 665, 11, 1225, 3137, 16269, 20101, 40263, 31091}},
-{7731, 17, 17090, {1, 3, 5, 15, 7, 5, 101, 153, 165, 173, 97, 1651, 6633, 6071, 29079, 35641, 77305}},
-{7732, 17, 17107, {1, 3, 7, 13, 9, 45, 103, 55, 121, 1021, 1841, 315, 8127, 6547, 1093, 7181, 39575}},
-{7733, 17, 17126, {1, 3, 3, 11, 15, 17, 27, 55, 341, 443, 377, 681, 3635, 1091, 16719, 49403, 85507}},
-{7734, 17, 17135, {1, 3, 5, 5, 29, 53, 51, 213, 273, 475, 981, 549, 539, 14989, 4037, 23911, 45997}},
-{7735, 17, 17150, {1, 3, 5, 3, 27, 37, 73, 115, 331, 911, 991, 4049, 6299, 3919, 10231, 31507, 98651}},
-{7736, 17, 17162, {1, 1, 5, 13, 21, 13, 1, 175, 137, 837, 1067, 2845, 307, 4399, 15671, 1309, 107409}},
-{7737, 17, 17169, {1, 1, 3, 1, 5, 47, 111, 75, 193, 389, 157, 3731, 6237, 5053, 9933, 28413, 32939}},
-{7738, 17, 17172, {1, 1, 7, 5, 29, 1, 51, 85, 267, 935, 1021, 3135, 3135, 9263, 32597, 6779, 71473}},
-{7739, 17, 17175, {1, 3, 5, 9, 21, 59, 27, 99, 155, 507, 1911, 3501, 4307, 6755, 17127, 29815, 1577}},
-{7740, 17, 17176, {1, 1, 5, 1, 15, 63, 45, 105, 125, 299, 689, 3935, 7229, 5007, 25003, 30453, 27819}},
-{7741, 17, 17191, {1, 1, 7, 15, 19, 9, 67, 151, 45, 985, 2015, 833, 5435, 15383, 25881, 46735, 56717}},
-{7742, 17, 17209, {1, 1, 5, 15, 27, 59, 119, 163, 293, 63, 1251, 1309, 485, 4937, 27207, 47481, 114357}},
-{7743, 17, 17218, {1, 3, 5, 13, 23, 11, 111, 87, 329, 467, 1657, 3309, 3421, 12013, 23163, 14105, 88761}},
-{7744, 17, 17220, {1, 1, 5, 11, 17, 63, 9, 61, 299, 585, 341, 3375, 3213, 15953, 11455, 5333, 66889}},
-{7745, 17, 17227, {1, 3, 5, 5, 5, 35, 57, 235, 137, 543, 77, 2811, 857, 12793, 10791, 55711, 93353}},
-{7746, 17, 17229, {1, 3, 7, 3, 23, 37, 19, 81, 321, 23, 1625, 2359, 3569, 4685, 7385, 32677, 18073}},
-{7747, 17, 17238, {1, 3, 3, 7, 21, 35, 81, 229, 207, 547, 1397, 2709, 7159, 1265, 16823, 9921, 29159}},
-{7748, 17, 17251, {1, 3, 7, 13, 27, 13, 107, 241, 395, 317, 307, 3927, 1153, 15915, 25179, 25173, 21503}},
-{7749, 17, 17257, {1, 3, 1, 5, 1, 51, 25, 135, 381, 229, 1491, 2009, 3331, 16165, 8169, 65161, 9335}},
-{7750, 17, 17258, {1, 1, 5, 5, 17, 15, 57, 221, 183, 225, 1649, 3701, 299, 12349, 4691, 64479, 82237}},
-{7751, 17, 17272, {1, 3, 7, 7, 31, 39, 65, 183, 149, 67, 1697, 3933, 3709, 15501, 12583, 60117, 88691}},
-{7752, 17, 17277, {1, 1, 5, 15, 17, 49, 117, 233, 161, 891, 789, 1347, 4887, 10713, 10613, 4389, 42619}},
-{7753, 17, 17308, {1, 3, 5, 9, 13, 3, 83, 69, 381, 777, 743, 2843, 7233, 3285, 8931, 48667, 120777}},
-{7754, 17, 17311, {1, 3, 1, 3, 11, 7, 55, 107, 165, 533, 1897, 3385, 1069, 12805, 30125, 42729, 123977}},
-{7755, 17, 17321, {1, 1, 1, 5, 13, 17, 103, 237, 77, 537, 1843, 2817, 7467, 13647, 15259, 3525, 18313}},
-{7756, 17, 17329, {1, 1, 7, 7, 13, 59, 29, 197, 309, 917, 1173, 2605, 4313, 12007, 25611, 60409, 104931}},
-{7757, 17, 17342, {1, 3, 3, 3, 27, 57, 7, 207, 491, 467, 1973, 3075, 8043, 3977, 14517, 13179, 47111}},
-{7758, 17, 17344, {1, 1, 7, 5, 31, 33, 125, 235, 79, 847, 1893, 3875, 7513, 1435, 24959, 46813, 82053}},
-{7759, 17, 17350, {1, 3, 7, 5, 3, 53, 103, 1, 215, 71, 787, 223, 1399, 6793, 11281, 39201, 122119}},
-{7760, 17, 17356, {1, 3, 3, 3, 3, 57, 7, 151, 319, 463, 685, 2917, 4037, 14929, 11971, 41827, 57449}},
-{7761, 17, 17371, {1, 1, 7, 3, 5, 11, 15, 139, 379, 563, 135, 65, 5633, 7535, 1451, 18289, 62457}},
-{7762, 17, 17374, {1, 1, 1, 15, 11, 23, 37, 57, 205, 107, 995, 151, 3279, 2015, 28927, 40731, 95551}},
-{7763, 17, 17392, {1, 3, 5, 9, 15, 43, 95, 217, 203, 215, 203, 2207, 8189, 465, 2175, 29285, 25375}},
-{7764, 17, 17402, {1, 3, 3, 5, 19, 59, 51, 123, 285, 721, 1335, 1777, 1645, 15811, 16539, 14637, 123323}},
-{7765, 17, 17410, {1, 3, 5, 5, 11, 35, 23, 23, 259, 789, 567, 1921, 4743, 6635, 6965, 43025, 43175}},
-{7766, 17, 17421, {1, 3, 7, 3, 7, 27, 77, 121, 285, 65, 647, 591, 2553, 7163, 12057, 43675, 24227}},
-{7767, 17, 17424, {1, 1, 5, 9, 3, 25, 17, 85, 235, 715, 1913, 2391, 3719, 11029, 18359, 6323, 4703}},
-{7768, 17, 17427, {1, 1, 1, 3, 25, 31, 37, 31, 89, 311, 1797, 3409, 6785, 9627, 29721, 58591, 111429}},
-{7769, 17, 17434, {1, 3, 1, 5, 9, 37, 47, 45, 419, 115, 1009, 1359, 65, 1161, 15673, 16075, 63895}},
-{7770, 17, 17449, {1, 1, 3, 5, 25, 47, 27, 87, 441, 547, 1801, 3589, 3773, 12215, 14509, 12669, 99983}},
-{7771, 17, 17452, {1, 1, 1, 3, 19, 33, 51, 91, 447, 577, 491, 539, 3177, 7033, 21633, 51737, 47089}},
-{7772, 17, 17463, {1, 1, 3, 15, 23, 53, 93, 113, 143, 973, 999, 2355, 1489, 3451, 29821, 23769, 74633}},
-{7773, 17, 17470, {1, 3, 7, 11, 27, 1, 35, 109, 111, 51, 425, 3203, 2585, 11255, 20939, 281, 92133}},
-{7774, 17, 17477, {1, 1, 1, 11, 13, 37, 13, 149, 421, 655, 79, 3093, 6429, 1145, 27663, 52861, 81431}},
-{7775, 17, 17482, {1, 1, 5, 13, 19, 23, 105, 39, 97, 239, 469, 1047, 4727, 12009, 8055, 45557, 124219}},
-{7776, 17, 17490, {1, 1, 1, 7, 7, 7, 5, 53, 269, 391, 1893, 2263, 2109, 11531, 12109, 31437, 20445}},
-{7777, 17, 17496, {1, 1, 3, 11, 9, 35, 69, 209, 93, 455, 1117, 3297, 2597, 15035, 17943, 19955, 829}},
-{7778, 17, 17508, {1, 1, 5, 7, 23, 23, 101, 71, 339, 553, 1653, 2997, 1191, 3121, 4575, 49979, 17353}},
-{7779, 17, 17511, {1, 3, 3, 13, 13, 9, 51, 181, 33, 185, 111, 589, 3117, 10105, 28811, 31529, 79657}},
-{7780, 17, 17536, {1, 1, 5, 3, 9, 57, 103, 65, 211, 473, 519, 3815, 4087, 2767, 10213, 37829, 9523}},
-{7781, 17, 17563, {1, 1, 5, 7, 7, 31, 81, 161, 311, 617, 1689, 3133, 57, 14595, 22783, 18475, 85811}},
-{7782, 17, 17570, {1, 3, 5, 5, 21, 51, 99, 249, 7, 525, 885, 3981, 2851, 529, 947, 29885, 122901}},
-{7783, 17, 17581, {1, 3, 1, 5, 1, 23, 85, 91, 309, 747, 183, 1347, 2399, 15777, 16205, 15687, 117333}},
-{7784, 17, 17590, {1, 3, 7, 3, 29, 21, 99, 137, 297, 229, 1063, 2747, 6415, 7791, 4775, 62863, 50849}},
-{7785, 17, 17608, {1, 3, 1, 3, 11, 3, 53, 153, 103, 911, 1595, 1899, 1049, 11643, 21105, 61587, 92399}},
-{7786, 17, 17616, {1, 1, 5, 15, 29, 55, 99, 101, 181, 453, 1917, 2081, 4687, 4335, 2817, 11861, 103167}},
-{7787, 17, 17621, {1, 3, 7, 15, 11, 7, 9, 3, 477, 281, 1141, 453, 4993, 7843, 6169, 49785, 53827}},
-{7788, 17, 17628, {1, 3, 7, 11, 25, 61, 77, 159, 83, 95, 1223, 85, 6309, 16145, 18729, 133, 14193}},
-{7789, 17, 17644, {1, 3, 3, 1, 7, 27, 97, 183, 263, 59, 915, 3857, 3349, 8123, 11251, 55163, 125703}},
-{7790, 17, 17649, {1, 3, 5, 5, 17, 33, 57, 55, 503, 811, 953, 349, 1949, 9127, 31015, 14475, 116769}},
-{7791, 17, 17652, {1, 3, 1, 1, 3, 53, 59, 131, 421, 971, 89, 3047, 3513, 13599, 4569, 54525, 54779}},
-{7792, 17, 17679, {1, 1, 3, 11, 9, 45, 95, 123, 197, 257, 1073, 1461, 5, 12701, 12559, 34989, 71631}},
-{7793, 17, 17691, {1, 3, 3, 7, 1, 27, 55, 191, 447, 561, 1975, 2665, 1341, 8969, 18519, 47389, 70847}},
-{7794, 17, 17693, {1, 1, 5, 5, 3, 31, 15, 165, 95, 423, 233, 2309, 7777, 3503, 20105, 3085, 92349}},
-{7795, 17, 17697, {1, 3, 1, 13, 23, 61, 7, 55, 157, 1, 83, 515, 2169, 14397, 18149, 56855, 117265}},
-{7796, 17, 17698, {1, 3, 3, 3, 3, 59, 69, 95, 127, 241, 65, 3145, 491, 13809, 17529, 20223, 96579}},
-{7797, 17, 17700, {1, 1, 1, 5, 13, 43, 117, 163, 305, 955, 2007, 3337, 807, 16019, 5721, 5479, 90937}},
-{7798, 17, 17704, {1, 3, 3, 1, 19, 9, 127, 5, 113, 491, 1873, 2127, 7949, 5207, 32531, 775, 131065}},
-{7799, 17, 17707, {1, 1, 7, 3, 1, 3, 91, 187, 37, 873, 1039, 4075, 5645, 243, 15127, 45615, 3813}},
-{7800, 17, 17715, {1, 1, 3, 11, 3, 37, 67, 59, 439, 763, 213, 1099, 1659, 12783, 30297, 60713, 43497}},
-{7801, 17, 17718, {1, 3, 3, 13, 23, 49, 47, 191, 245, 985, 487, 3165, 7803, 2437, 19073, 30605, 119641}},
-{7802, 17, 17721, {1, 3, 7, 7, 19, 43, 7, 253, 93, 99, 145, 219, 699, 2433, 3009, 565, 99671}},
-{7803, 17, 17722, {1, 1, 3, 13, 7, 5, 9, 23, 219, 155, 925, 3427, 6631, 16353, 4115, 20831, 49525}},
-{7804, 17, 17727, {1, 1, 7, 11, 15, 45, 41, 35, 301, 273, 241, 4031, 5441, 8281, 9341, 8499, 73841}},
-{7805, 17, 17729, {1, 3, 7, 13, 9, 19, 79, 3, 163, 197, 509, 2301, 6971, 11525, 8805, 33805, 111595}},
-{7806, 17, 17747, {1, 3, 3, 1, 15, 45, 69, 253, 155, 639, 1045, 749, 3619, 14871, 18063, 49763, 66687}},
-{7807, 17, 17754, {1, 3, 3, 3, 29, 5, 41, 171, 265, 677, 1719, 2623, 1721, 12243, 18741, 39595, 92873}},
-{7808, 17, 17756, {1, 3, 5, 7, 27, 23, 69, 61, 453, 399, 1857, 3901, 6565, 15595, 1083, 15065, 91249}},
-{7809, 17, 17760, {1, 1, 5, 7, 1, 27, 9, 145, 95, 983, 685, 2079, 5117, 5037, 22695, 53135, 43569}},
-{7810, 17, 17765, {1, 1, 3, 5, 5, 7, 69, 59, 331, 409, 179, 333, 1293, 3863, 9473, 12537, 55605}},
-{7811, 17, 17778, {1, 3, 5, 1, 1, 19, 1, 49, 317, 769, 91, 2073, 1765, 1197, 15029, 52553, 57361}},
-{7812, 17, 17784, {1, 1, 5, 1, 23, 13, 11, 69, 345, 877, 41, 817, 617, 14415, 8337, 53973, 50007}},
-{7813, 17, 17794, {1, 1, 7, 3, 19, 27, 69, 103, 115, 893, 219, 2891, 2813, 9933, 26401, 63323, 30909}},
-{7814, 17, 17805, {1, 1, 5, 5, 27, 15, 119, 3, 11, 783, 541, 2431, 2395, 3921, 15471, 34657, 100295}},
-{7815, 17, 17806, {1, 1, 7, 11, 15, 25, 39, 191, 345, 1001, 1773, 715, 1627, 15957, 30085, 34097, 58747}},
-{7816, 17, 17817, {1, 1, 1, 5, 17, 43, 65, 81, 487, 387, 1359, 145, 2231, 6693, 15857, 59539, 79615}},
-{7817, 17, 17824, {1, 1, 3, 5, 15, 19, 17, 233, 247, 611, 587, 2587, 2321, 2835, 1477, 41991, 88143}},
-{7818, 17, 17839, {1, 3, 3, 15, 27, 15, 53, 61, 359, 989, 283, 3569, 5551, 11849, 20995, 34065, 69407}},
-{7819, 17, 17842, {1, 3, 3, 11, 13, 31, 41, 87, 379, 47, 1289, 3143, 4213, 8643, 17065, 10707, 62773}},
-{7820, 17, 17844, {1, 3, 7, 1, 9, 61, 59, 121, 453, 663, 27, 793, 4501, 7713, 285, 13279, 11633}},
-{7821, 17, 17851, {1, 1, 7, 5, 29, 51, 57, 15, 233, 743, 879, 2317, 3399, 15741, 605, 57529, 87427}},
-{7822, 17, 17862, {1, 1, 1, 1, 19, 59, 51, 119, 273, 403, 1649, 3877, 3561, 10931, 21139, 2599, 77957}},
-{7823, 17, 17868, {1, 3, 1, 3, 5, 1, 79, 131, 251, 585, 359, 2073, 7041, 13611, 22937, 24645, 72827}},
-{7824, 17, 17871, {1, 3, 7, 9, 19, 39, 93, 137, 359, 565, 1123, 1301, 4111, 13683, 1361, 25147, 38315}},
-{7825, 17, 17873, {1, 1, 5, 13, 27, 31, 11, 243, 111, 243, 1615, 1649, 2999, 15873, 19161, 57485, 35819}},
-{7826, 17, 17896, {1, 3, 3, 5, 25, 57, 61, 207, 219, 969, 303, 1165, 6753, 13473, 10789, 52883, 45205}},
-{7827, 17, 17904, {1, 1, 7, 11, 9, 53, 55, 175, 399, 981, 255, 2499, 373, 13131, 26803, 48017, 25599}},
-{7828, 17, 17909, {1, 1, 3, 3, 11, 23, 73, 25, 83, 39, 1813, 747, 3287, 795, 11917, 55509, 105057}},
-{7829, 17, 17920, {1, 3, 7, 15, 29, 59, 47, 171, 219, 875, 71, 123, 8131, 15595, 12471, 62439, 131}},
-{7830, 17, 17923, {1, 3, 5, 13, 9, 27, 119, 233, 323, 943, 375, 3647, 185, 1639, 431, 27225, 130175}},
-{7831, 17, 17947, {1, 3, 7, 3, 7, 17, 31, 155, 89, 835, 1015, 2019, 3973, 7087, 16899, 29591, 40797}},
-{7832, 17, 17950, {1, 3, 3, 1, 3, 11, 83, 231, 209, 537, 1227, 1519, 1059, 14027, 18591, 34031, 125755}},
-{7833, 17, 17956, {1, 3, 3, 1, 7, 39, 19, 99, 169, 961, 385, 1621, 7373, 7459, 8979, 23643, 17101}},
-{7834, 17, 17959, {1, 1, 3, 11, 11, 23, 61, 37, 359, 981, 209, 2555, 2673, 6501, 12731, 10735, 97321}},
-{7835, 17, 17966, {1, 1, 3, 13, 15, 61, 115, 119, 99, 755, 1933, 345, 3133, 12071, 26657, 7133, 18553}},
-{7836, 17, 17971, {1, 3, 1, 5, 17, 7, 29, 119, 445, 911, 89, 19, 6137, 8037, 19527, 22467, 29253}},
-{7837, 17, 17973, {1, 1, 3, 11, 31, 21, 119, 21, 249, 371, 343, 4037, 7539, 14473, 23829, 46415, 60911}},
-{7838, 17, 17992, {1, 1, 7, 9, 21, 53, 29, 149, 467, 893, 479, 359, 1007, 13955, 9667, 10245, 74761}},
-{7839, 17, 18006, {1, 3, 1, 7, 7, 45, 7, 77, 289, 271, 1329, 261, 5675, 8275, 7443, 57945, 117825}},
-{7840, 17, 18009, {1, 1, 1, 3, 21, 57, 117, 77, 287, 119, 1073, 915, 2521, 455, 7433, 56953, 84433}},
-{7841, 17, 18010, {1, 1, 1, 9, 27, 47, 1, 189, 303, 375, 215, 3117, 4541, 12877, 15523, 32317, 104213}},
-{7842, 17, 18022, {1, 1, 3, 1, 13, 39, 37, 249, 371, 159, 1073, 1351, 4703, 2715, 17463, 3945, 51523}},
-{7843, 17, 18039, {1, 3, 5, 5, 29, 15, 79, 25, 61, 995, 1081, 3377, 345, 13773, 4205, 20589, 83591}},
-{7844, 17, 18046, {1, 1, 3, 1, 9, 1, 41, 39, 389, 509, 561, 3273, 1911, 15271, 22655, 34713, 2045}},
-{7845, 17, 18069, {1, 3, 1, 15, 17, 1, 55, 55, 119, 707, 843, 2657, 3687, 11557, 18331, 4935, 110639}},
-{7846, 17, 18074, {1, 3, 5, 1, 23, 35, 119, 215, 471, 643, 1581, 1965, 2627, 2991, 3361, 6737, 111657}},
-{7847, 17, 18076, {1, 3, 5, 7, 9, 19, 33, 197, 33, 993, 1795, 595, 7113, 14721, 12647, 41035, 13669}},
-{7848, 17, 18085, {1, 1, 7, 15, 31, 39, 51, 157, 373, 473, 665, 3541, 6695, 11741, 5617, 17189, 129851}},
-{7849, 17, 18086, {1, 3, 3, 7, 15, 37, 33, 175, 391, 159, 717, 593, 113, 9331, 10685, 59003, 26975}},
-{7850, 17, 18095, {1, 1, 3, 5, 13, 41, 11, 109, 9, 899, 1503, 901, 6237, 7789, 9963, 14923, 63665}},
-{7851, 17, 18100, {1, 3, 7, 7, 25, 61, 3, 231, 235, 29, 1049, 1997, 5371, 9047, 29595, 49239, 108649}},
-{7852, 17, 18109, {1, 1, 3, 5, 27, 1, 53, 209, 315, 747, 1803, 11, 1815, 6539, 8839, 18385, 88681}},
-{7853, 17, 18121, {1, 1, 5, 13, 25, 55, 117, 197, 13, 689, 751, 1203, 2277, 1763, 23453, 54459, 118023}},
-{7854, 17, 18127, {1, 3, 3, 11, 21, 1, 51, 101, 429, 723, 273, 3021, 1491, 9923, 6629, 63741, 98813}},
-{7855, 17, 18129, {1, 1, 1, 15, 17, 25, 111, 251, 43, 403, 465, 17, 787, 6045, 32185, 22921, 115851}},
-{7856, 17, 18132, {1, 1, 5, 11, 11, 13, 13, 93, 489, 941, 1391, 383, 7735, 1921, 16199, 53099, 25181}},
-{7857, 17, 18141, {1, 3, 3, 7, 15, 1, 3, 159, 507, 867, 1589, 2111, 3839, 8989, 12589, 37657, 97055}},
-{7858, 17, 18146, {1, 3, 3, 13, 25, 23, 7, 95, 489, 1001, 105, 2737, 5013, 14465, 25383, 57551, 77425}},
-{7859, 17, 18151, {1, 3, 5, 3, 3, 7, 81, 15, 255, 297, 1183, 655, 741, 3081, 2141, 34493, 103707}},
-{7860, 17, 18157, {1, 1, 7, 9, 27, 57, 49, 121, 21, 239, 829, 2001, 613, 9569, 4419, 20007, 59109}},
-{7861, 17, 18160, {1, 3, 7, 1, 3, 21, 109, 255, 45, 333, 915, 1245, 5893, 765, 28289, 53927, 15335}},
-{7862, 17, 18183, {1, 3, 3, 7, 5, 35, 33, 79, 111, 509, 347, 3915, 2017, 6461, 11847, 17807, 48601}},
-{7863, 17, 18204, {1, 3, 5, 1, 13, 63, 87, 65, 507, 277, 339, 3637, 6289, 719, 9383, 38887, 55061}},
-{7864, 17, 18218, {1, 1, 5, 15, 17, 5, 59, 107, 355, 1021, 1849, 1807, 7679, 305, 31533, 1221, 98165}},
-{7865, 17, 18226, {1, 1, 1, 13, 19, 7, 37, 63, 267, 399, 1451, 2149, 1003, 13635, 18693, 215, 15887}},
-{7866, 17, 18238, {1, 1, 3, 7, 11, 63, 81, 251, 253, 963, 635, 1697, 6393, 9775, 24189, 9099, 106277}},
-{7867, 17, 18245, {1, 3, 3, 13, 17, 47, 63, 47, 279, 879, 271, 1655, 1897, 10743, 2607, 16695, 32779}},
-{7868, 17, 18249, {1, 3, 5, 15, 3, 1, 121, 181, 303, 973, 19, 3327, 3827, 2197, 31857, 22835, 122611}},
-{7869, 17, 18260, {1, 1, 5, 13, 25, 41, 105, 197, 195, 85, 1515, 2735, 7539, 7557, 24297, 38721, 46895}},
-{7870, 17, 18267, {1, 1, 1, 1, 15, 63, 33, 7, 43, 971, 781, 1461, 4483, 2113, 32459, 37653, 68017}},
-{7871, 17, 18270, {1, 3, 3, 9, 7, 1, 65, 183, 171, 695, 191, 3675, 6749, 6823, 3577, 45031, 81597}},
-{7872, 17, 18273, {1, 3, 3, 3, 9, 61, 13, 159, 295, 329, 943, 3293, 79, 14497, 21461, 4667, 96435}},
-{7873, 17, 18274, {1, 1, 7, 9, 29, 37, 117, 215, 295, 591, 1139, 3093, 7469, 7995, 13581, 48075, 5943}},
-{7874, 17, 18276, {1, 3, 1, 9, 11, 11, 117, 255, 419, 551, 1445, 1987, 1169, 14227, 31095, 36041, 63739}},
-{7875, 17, 18283, {1, 1, 7, 15, 17, 25, 81, 27, 87, 463, 1871, 551, 7449, 12231, 28645, 32663, 43037}},
-{7876, 17, 18307, {1, 3, 5, 11, 3, 49, 109, 123, 397, 113, 1269, 2433, 4463, 1257, 2127, 6677, 96009}},
-{7877, 17, 18314, {1, 1, 1, 11, 27, 19, 83, 123, 297, 867, 941, 3929, 3483, 4641, 32505, 48999, 66169}},
-{7878, 17, 18321, {1, 1, 5, 11, 5, 21, 11, 255, 369, 859, 657, 587, 5245, 12973, 22403, 47935, 121375}},
-{7879, 17, 18334, {1, 3, 1, 13, 17, 43, 83, 51, 339, 967, 499, 1485, 5203, 10053, 31707, 31443, 75033}},
-{7880, 17, 18355, {1, 1, 5, 13, 11, 5, 121, 121, 73, 101, 1751, 3805, 1333, 14043, 26957, 27557, 110899}},
-{7881, 17, 18364, {1, 3, 7, 11, 9, 7, 125, 237, 437, 177, 841, 175, 5509, 9157, 3129, 54119, 109315}},
-{7882, 17, 18372, {1, 3, 7, 15, 1, 59, 87, 121, 43, 475, 1589, 1267, 1501, 1585, 31705, 33959, 27247}},
-{7883, 17, 18390, {1, 1, 5, 3, 27, 63, 117, 205, 169, 701, 1081, 2835, 8049, 11875, 4143, 17663, 90043}},
-{7884, 17, 18399, {1, 3, 1, 9, 23, 27, 31, 141, 411, 145, 1177, 3681, 3403, 6943, 10729, 47219, 102713}},
-{7885, 17, 18415, {1, 1, 7, 11, 5, 49, 33, 27, 121, 865, 471, 1871, 6945, 10051, 4493, 7121, 65551}},
-{7886, 17, 18420, {1, 1, 5, 1, 17, 27, 53, 13, 31, 403, 1319, 1381, 1371, 11693, 18805, 54683, 30137}},
-{7887, 17, 18434, {1, 1, 7, 11, 9, 21, 71, 155, 79, 145, 943, 3891, 641, 3163, 28493, 14729, 83391}},
-{7888, 17, 18443, {1, 3, 3, 13, 3, 53, 21, 189, 245, 803, 1625, 4005, 1163, 16033, 5549, 14301, 115859}},
-{7889, 17, 18446, {1, 3, 1, 5, 17, 59, 61, 31, 293, 677, 1753, 1803, 1671, 14619, 22361, 61453, 78203}},
-{7890, 17, 18460, {1, 3, 3, 1, 5, 51, 99, 231, 175, 97, 1335, 689, 1913, 6157, 22757, 52395, 118347}},
-{7891, 17, 18467, {1, 3, 3, 7, 25, 11, 113, 19, 289, 507, 1143, 3437, 7965, 12551, 27603, 8423, 46713}},
-{7892, 17, 18482, {1, 1, 3, 9, 13, 1, 73, 9, 425, 407, 363, 2915, 4269, 2903, 9251, 17733, 80321}},
-{7893, 17, 18484, {1, 1, 3, 11, 31, 47, 37, 211, 433, 237, 1069, 1891, 6175, 9305, 30385, 2497, 94775}},
-{7894, 17, 18501, {1, 1, 3, 1, 23, 5, 113, 103, 427, 587, 1863, 1863, 679, 2575, 13059, 16163, 42289}},
-{7895, 17, 18506, {1, 1, 5, 3, 7, 17, 45, 33, 209, 609, 1897, 95, 5123, 2239, 5483, 60715, 126497}},
-{7896, 17, 18516, {1, 1, 5, 11, 1, 55, 67, 223, 41, 967, 337, 2511, 7879, 1157, 17635, 64081, 421}},
-{7897, 17, 18519, {1, 3, 3, 9, 27, 33, 87, 97, 231, 895, 1337, 829, 47, 8481, 14059, 57209, 109159}},
-{7898, 17, 18547, {1, 3, 7, 1, 25, 5, 41, 161, 393, 523, 1623, 3761, 1933, 8319, 17309, 46717, 97299}},
-{7899, 17, 18569, {1, 1, 1, 11, 5, 55, 19, 191, 41, 791, 1611, 59, 2633, 13873, 25859, 42879, 54807}},
-{7900, 17, 18575, {1, 3, 1, 11, 11, 33, 5, 13, 199, 411, 895, 759, 2735, 16225, 31469, 24081, 31857}},
-{7901, 17, 18589, {1, 1, 7, 13, 27, 57, 21, 191, 389, 977, 1013, 3493, 6401, 15957, 23181, 52461, 41853}},
-{7902, 17, 18590, {1, 3, 7, 5, 23, 19, 117, 117, 427, 923, 1347, 3099, 247, 8879, 5309, 53277, 100625}},
-{7903, 17, 18605, {1, 1, 5, 13, 11, 23, 69, 37, 119, 329, 1935, 2851, 5127, 6907, 24651, 11135, 118287}},
-{7904, 17, 18611, {1, 1, 3, 15, 23, 1, 69, 107, 253, 771, 1697, 4035, 3219, 15011, 6995, 19255, 39909}},
-{7905, 17, 18625, {1, 3, 1, 1, 5, 21, 35, 173, 407, 603, 27, 3589, 2879, 2755, 17679, 6145, 95989}},
-{7906, 17, 18652, {1, 1, 5, 13, 31, 23, 61, 139, 341, 593, 1673, 4031, 4809, 1107, 22657, 29073, 53401}},
-{7907, 17, 18665, {1, 3, 1, 15, 13, 37, 39, 61, 443, 417, 1125, 1529, 1943, 7317, 2985, 50285, 107069}},
-{7908, 17, 18673, {1, 1, 3, 9, 5, 51, 87, 91, 31, 491, 1455, 1685, 2579, 6023, 10989, 64635, 130147}},
-{7909, 17, 18674, {1, 3, 5, 5, 31, 23, 15, 163, 357, 161, 1597, 1571, 5039, 13213, 32221, 4405, 88079}},
-{7910, 17, 18683, {1, 1, 1, 15, 13, 43, 7, 109, 243, 389, 683, 2671, 8003, 4187, 6507, 11171, 116727}},
-{7911, 17, 18688, {1, 3, 7, 1, 17, 31, 53, 5, 227, 755, 1755, 2939, 1789, 8951, 16777, 30203, 79005}},
-{7912, 17, 18691, {1, 3, 3, 9, 27, 5, 111, 241, 89, 333, 371, 1035, 5719, 2433, 29343, 50829, 25131}},
-{7913, 17, 18698, {1, 1, 3, 13, 7, 37, 125, 69, 79, 397, 1595, 123, 255, 2257, 10881, 27085, 99411}},
-{7914, 17, 18717, {1, 1, 3, 15, 1, 35, 61, 73, 507, 775, 1631, 2005, 4277, 8421, 5669, 39221, 19053}},
-{7915, 17, 18733, {1, 1, 3, 7, 15, 17, 65, 157, 19, 997, 861, 1249, 4059, 7975, 955, 5833, 97733}},
-{7916, 17, 18754, {1, 1, 5, 5, 21, 43, 1, 181, 1, 17, 1337, 3333, 3761, 12283, 20941, 231, 30457}},
-{7917, 17, 18759, {1, 3, 3, 7, 7, 23, 105, 101, 101, 757, 1407, 565, 2187, 1529, 29385, 22847, 57675}},
-{7918, 17, 18760, {1, 3, 3, 1, 11, 3, 65, 93, 201, 773, 1037, 1325, 673, 6625, 2909, 63435, 114311}},
-{7919, 17, 18771, {1, 3, 5, 1, 21, 43, 87, 37, 491, 323, 1093, 2493, 4755, 7225, 12037, 9483, 70351}},
-{7920, 17, 18777, {1, 1, 7, 9, 23, 39, 59, 117, 103, 645, 1975, 1177, 55, 325, 23781, 64365, 94915}},
-{7921, 17, 18796, {1, 3, 7, 15, 21, 29, 109, 35, 307, 847, 777, 3457, 7899, 17, 24065, 10517, 35651}},
-{7922, 17, 18799, {1, 1, 7, 9, 25, 35, 49, 131, 377, 429, 1773, 2107, 6305, 15209, 9567, 17685, 5599}},
-{7923, 17, 18807, {1, 1, 3, 11, 13, 27, 47, 125, 483, 229, 921, 2733, 2217, 2615, 24135, 28759, 109411}},
-{7924, 17, 18813, {1, 3, 1, 7, 19, 45, 23, 195, 445, 955, 853, 2877, 6889, 9507, 2009, 18747, 50545}},
-{7925, 17, 18817, {1, 1, 1, 5, 15, 35, 75, 177, 145, 683, 309, 893, 4999, 827, 26563, 30819, 111115}},
-{7926, 17, 18820, {1, 3, 3, 11, 5, 45, 49, 39, 93, 653, 1053, 2553, 863, 12185, 30261, 16459, 121061}},
-{7927, 17, 18827, {1, 3, 7, 5, 11, 29, 57, 43, 409, 71, 67, 3537, 263, 13237, 8825, 58411, 44629}},
-{7928, 17, 18829, {1, 1, 5, 13, 1, 37, 23, 171, 13, 309, 239, 2023, 6233, 8751, 11371, 5825, 77355}},
-{7929, 17, 18838, {1, 3, 1, 13, 5, 1, 47, 217, 369, 609, 453, 879, 4337, 4441, 8785, 51963, 53819}},
-{7930, 17, 18842, {1, 3, 5, 5, 23, 1, 67, 147, 27, 121, 1369, 569, 1519, 11585, 18193, 30889, 78055}},
-{7931, 17, 18848, {1, 1, 1, 13, 11, 53, 33, 37, 419, 111, 1649, 2495, 6105, 12385, 30865, 3683, 63813}},
-{7932, 17, 18853, {1, 3, 3, 5, 17, 35, 107, 235, 471, 735, 1093, 1007, 567, 173, 9623, 39533, 56455}},
-{7933, 17, 18885, {1, 1, 7, 15, 27, 13, 123, 211, 407, 857, 801, 3951, 8153, 4427, 15333, 13217, 92675}},
-{7934, 17, 18890, {1, 1, 1, 7, 11, 61, 99, 131, 121, 119, 1483, 1485, 3521, 13163, 24899, 56849, 111943}},
-{7935, 17, 18898, {1, 3, 3, 1, 19, 1, 29, 139, 127, 557, 1913, 1487, 1381, 185, 11195, 52499, 45059}},
-{7936, 17, 18903, {1, 3, 7, 11, 5, 29, 95, 111, 235, 55, 1101, 2631, 1219, 9867, 22209, 3095, 56793}},
-{7937, 17, 18910, {1, 3, 7, 1, 31, 61, 37, 125, 241, 985, 1079, 1439, 433, 2779, 8463, 59985, 39667}},
-{7938, 17, 18913, {1, 3, 7, 15, 5, 7, 71, 7, 435, 727, 1611, 135, 1421, 8329, 29995, 64243, 58285}},
-{7939, 17, 18931, {1, 3, 3, 15, 27, 11, 121, 27, 281, 499, 267, 2651, 7575, 9499, 5051, 49475, 79573}},
-{7940, 17, 18934, {1, 3, 3, 15, 29, 47, 11, 183, 235, 537, 79, 2467, 3751, 831, 6725, 52173, 108645}},
-{7941, 17, 18956, {1, 3, 5, 13, 23, 31, 23, 19, 477, 511, 727, 183, 5955, 7613, 31979, 8441, 39835}},
-{7942, 17, 18961, {1, 1, 5, 7, 17, 31, 53, 133, 387, 787, 1573, 89, 1975, 1825, 19963, 27203, 124923}},
-{7943, 17, 18968, {1, 1, 1, 9, 3, 15, 125, 135, 89, 37, 517, 3931, 2013, 2143, 25413, 18421, 6097}},
-{7944, 17, 18978, {1, 1, 3, 11, 23, 29, 89, 45, 53, 135, 223, 3523, 7921, 3271, 1819, 40931, 65471}},
-{7945, 17, 18983, {1, 1, 1, 13, 17, 3, 121, 25, 509, 61, 1009, 2009, 7813, 8499, 5807, 63171, 75991}},
-{7946, 17, 18987, {1, 3, 5, 13, 15, 35, 37, 45, 161, 683, 1665, 59, 6297, 9595, 10193, 46745, 105411}},
-{7947, 17, 18992, {1, 3, 1, 7, 21, 19, 85, 107, 3, 845, 673, 1271, 7581, 15971, 27085, 35375, 29027}},
-{7948, 17, 18997, {1, 3, 3, 9, 5, 17, 79, 137, 123, 809, 583, 3507, 7559, 2857, 13911, 57083, 8595}},
-{7949, 17, 19002, {1, 1, 7, 5, 31, 29, 77, 33, 439, 787, 1223, 2471, 5851, 15891, 27925, 51661, 82645}},
-{7950, 17, 19004, {1, 1, 7, 15, 19, 35, 35, 37, 197, 245, 799, 3971, 277, 11289, 20111, 13857, 104571}},
-{7951, 17, 19010, {1, 3, 5, 15, 19, 3, 65, 17, 201, 1007, 1665, 107, 2409, 1469, 23265, 24547, 8189}},
-{7952, 17, 19012, {1, 3, 1, 13, 29, 45, 109, 243, 43, 383, 631, 265, 6671, 15333, 21931, 30675, 103077}},
-{7953, 17, 19030, {1, 1, 5, 1, 25, 25, 77, 189, 109, 777, 1485, 2265, 1403, 2627, 13843, 27263, 14263}},
-{7954, 17, 19043, {1, 3, 5, 1, 13, 49, 73, 107, 225, 243, 1253, 3503, 735, 2605, 27165, 45467, 93001}},
-{7955, 17, 19049, {1, 1, 5, 9, 15, 17, 1, 33, 69, 321, 1375, 3635, 8131, 6579, 1225, 38699, 17447}},
-{7956, 17, 19079, {1, 3, 5, 3, 25, 49, 15, 149, 483, 37, 1929, 1219, 5841, 11975, 805, 31339, 130971}},
-{7957, 17, 19086, {1, 3, 3, 3, 15, 29, 3, 143, 291, 593, 1769, 3603, 1693, 151, 27701, 9015, 25847}},
-{7958, 17, 19100, {1, 3, 1, 11, 5, 35, 55, 127, 137, 71, 967, 2501, 1023, 2061, 31387, 44011, 130121}},
-{7959, 17, 19103, {1, 1, 7, 1, 29, 13, 93, 41, 125, 263, 521, 2633, 4361, 12153, 30647, 55883, 65185}},
-{7960, 17, 19107, {1, 3, 7, 9, 23, 19, 61, 197, 139, 463, 1867, 3627, 5185, 8251, 26977, 48027, 66301}},
-{7961, 17, 19109, {1, 3, 3, 7, 27, 53, 25, 137, 175, 155, 1843, 2253, 4797, 4989, 32613, 55779, 91625}},
-{7962, 17, 19113, {1, 3, 3, 11, 1, 5, 21, 233, 295, 675, 47, 2995, 8075, 8201, 3845, 23925, 82559}},
-{7963, 17, 19116, {1, 1, 3, 7, 31, 53, 93, 21, 307, 709, 9, 3061, 3935, 11009, 13411, 3657, 30251}},
-{7964, 17, 19127, {1, 3, 7, 13, 13, 25, 51, 205, 391, 897, 275, 333, 6831, 9383, 16101, 14301, 99101}},
-{7965, 17, 19134, {1, 1, 5, 15, 17, 47, 119, 7, 189, 765, 753, 2909, 3373, 2379, 20331, 61535, 51345}},
-{7966, 17, 19141, {1, 1, 3, 1, 27, 43, 9, 185, 9, 197, 1179, 67, 7689, 9679, 29683, 29905, 29393}},
-{7967, 17, 19179, {1, 1, 5, 5, 31, 55, 69, 9, 477, 91, 1705, 1877, 5463, 15401, 13449, 27541, 125521}},
-{7968, 17, 19193, {1, 1, 7, 15, 15, 33, 11, 233, 69, 771, 845, 2715, 5293, 10351, 19557, 15319, 36857}},
-{7969, 17, 19194, {1, 3, 7, 7, 15, 9, 123, 47, 165, 739, 361, 1675, 2743, 8021, 10241, 48275, 51935}},
-{7970, 17, 19201, {1, 1, 5, 1, 9, 25, 99, 83, 487, 627, 343, 3233, 6697, 13197, 19771, 38337, 89139}},
-{7971, 17, 19208, {1, 3, 7, 13, 1, 31, 15, 63, 463, 621, 935, 1093, 6043, 14051, 13665, 43413, 104893}},
-{7972, 17, 19214, {1, 1, 1, 3, 27, 1, 47, 151, 127, 357, 689, 3263, 141, 4459, 9847, 205, 88493}},
-{7973, 17, 19225, {1, 3, 7, 15, 29, 13, 41, 113, 495, 421, 195, 197, 6857, 10555, 22861, 30229, 31707}},
-{7974, 17, 19226, {1, 3, 5, 11, 11, 1, 89, 227, 425, 623, 1605, 1901, 7933, 7211, 16301, 3403, 59651}},
-{7975, 17, 19235, {1, 1, 3, 3, 27, 41, 37, 89, 395, 903, 1641, 2739, 5599, 11371, 8683, 61125, 105231}},
-{7976, 17, 19242, {1, 3, 7, 9, 1, 17, 51, 233, 507, 783, 459, 1187, 7281, 15809, 27637, 6067, 125877}},
-{7977, 17, 19264, {1, 3, 1, 3, 13, 57, 5, 199, 261, 357, 1255, 1849, 8013, 10313, 9375, 1271, 64117}},
-{7978, 17, 19267, {1, 3, 1, 11, 9, 59, 55, 95, 401, 423, 1657, 513, 3565, 12957, 19243, 53027, 11323}},
-{7979, 17, 19293, {1, 3, 7, 13, 27, 35, 121, 215, 397, 991, 191, 3443, 3829, 6107, 5381, 48497, 107997}},
-{7980, 17, 19309, {1, 1, 5, 5, 19, 15, 21, 53, 165, 835, 1599, 3245, 5609, 5991, 18141, 28075, 102809}},
-{7981, 17, 19318, {1, 3, 5, 9, 25, 21, 71, 15, 453, 475, 915, 3097, 5869, 699, 13883, 34919, 127211}},
-{7982, 17, 19324, {1, 1, 3, 7, 21, 53, 27, 207, 373, 703, 593, 17, 6991, 15013, 10125, 34801, 129245}},
-{7983, 17, 19337, {1, 3, 3, 13, 17, 9, 89, 95, 291, 681, 1415, 2323, 2885, 11381, 7703, 3691, 51505}},
-{7984, 17, 19340, {1, 1, 1, 11, 15, 63, 55, 153, 373, 665, 983, 3987, 5997, 6873, 27031, 65449, 22021}},
-{7985, 17, 19345, {1, 1, 5, 5, 1, 55, 119, 61, 159, 889, 225, 709, 1879, 2521, 69, 7815, 18733}},
-{7986, 17, 19346, {1, 3, 5, 11, 23, 53, 23, 61, 71, 993, 633, 1829, 3465, 12465, 30205, 40723, 74499}},
-{7987, 17, 19352, {1, 3, 3, 1, 17, 37, 19, 43, 55, 133, 1171, 3101, 3963, 5177, 24791, 7255, 10263}},
-{7988, 17, 19364, {1, 3, 7, 1, 21, 13, 21, 87, 237, 629, 1167, 3699, 597, 6251, 11545, 34429, 104393}},
-{7989, 17, 19382, {1, 1, 7, 1, 11, 53, 105, 111, 463, 869, 549, 2423, 17, 917, 879, 49367, 72235}},
-{7990, 17, 19391, {1, 1, 5, 15, 17, 51, 69, 55, 309, 867, 257, 573, 4821, 5245, 28033, 61801, 18253}},
-{7991, 17, 19405, {1, 1, 5, 3, 1, 23, 103, 241, 13, 267, 21, 1751, 6637, 12537, 26741, 40651, 94493}},
-{7992, 17, 19411, {1, 3, 3, 13, 25, 35, 21, 83, 337, 363, 1111, 1865, 7889, 985, 465, 40287, 64469}},
-{7993, 17, 19439, {1, 1, 7, 5, 27, 1, 99, 95, 209, 211, 1445, 1577, 6097, 13813, 22463, 64395, 106383}},
-{7994, 17, 19442, {1, 3, 1, 15, 1, 45, 77, 247, 273, 1023, 1377, 1989, 5787, 15267, 24363, 42717, 125617}},
-{7995, 17, 19444, {1, 1, 1, 3, 9, 49, 79, 171, 427, 439, 1725, 3179, 6263, 12437, 31353, 22077, 94455}},
-{7996, 17, 19451, {1, 3, 5, 11, 11, 45, 57, 97, 409, 935, 967, 2509, 3431, 5707, 19473, 15853, 129059}},
-{7997, 17, 19465, {1, 1, 7, 5, 7, 21, 105, 29, 359, 145, 1691, 131, 6721, 10971, 16173, 38193, 37091}},
-{7998, 17, 19471, {1, 1, 1, 15, 15, 35, 5, 185, 455, 507, 681, 3355, 2091, 3437, 27231, 28527, 5383}},
-{7999, 17, 19474, {1, 3, 5, 3, 7, 29, 33, 127, 57, 495, 1069, 3635, 7461, 9861, 18757, 39039, 92421}},
-{8000, 17, 19476, {1, 3, 5, 5, 11, 31, 51, 59, 413, 417, 1577, 2837, 5229, 4501, 18645, 37613, 31325}},
-{8001, 17, 19479, {1, 1, 5, 13, 15, 61, 17, 247, 413, 817, 907, 2249, 3901, 11275, 7469, 33403, 30629}},
-{8002, 17, 19485, {1, 3, 5, 7, 31, 7, 109, 177, 277, 75, 449, 3029, 7135, 427, 26641, 43157, 47671}},
-{8003, 17, 19489, {1, 3, 7, 13, 29, 63, 21, 187, 471, 289, 835, 3885, 6111, 8721, 9841, 24017, 18673}},
-{8004, 17, 19496, {1, 1, 5, 13, 25, 37, 15, 35, 227, 623, 47, 189, 3443, 1911, 8579, 50911, 10895}},
-{8005, 17, 19507, {1, 3, 1, 1, 29, 53, 89, 101, 251, 203, 821, 2485, 633, 7943, 27563, 58735, 72057}},
-{8006, 17, 19513, {1, 3, 7, 9, 23, 61, 121, 199, 19, 165, 131, 1373, 637, 7307, 7109, 42475, 126669}},
-{8007, 17, 19514, {1, 3, 7, 13, 7, 5, 125, 173, 365, 65, 565, 751, 3343, 13421, 6177, 39095, 97375}},
-{8008, 17, 19521, {1, 1, 7, 3, 1, 59, 65, 39, 307, 793, 887, 3291, 3405, 4497, 19351, 1821, 67861}},
-{8009, 17, 19524, {1, 1, 1, 3, 19, 9, 101, 183, 163, 819, 769, 49, 5293, 3715, 4055, 32403, 90763}},
-{8010, 17, 19546, {1, 3, 3, 1, 27, 31, 21, 123, 457, 1021, 1791, 2217, 6171, 11445, 15605, 59945, 19663}},
-{8011, 17, 19552, {1, 1, 1, 9, 13, 53, 61, 201, 457, 111, 1217, 377, 5871, 4591, 16379, 42817, 129807}},
-{8012, 17, 19555, {1, 3, 1, 5, 23, 37, 25, 7, 125, 651, 349, 3727, 1487, 5103, 31407, 40215, 16065}},
-{8013, 17, 19557, {1, 1, 3, 11, 19, 29, 1, 193, 13, 287, 331, 985, 5391, 7307, 28075, 9939, 84999}},
-{8014, 17, 19575, {1, 1, 1, 11, 21, 37, 117, 241, 229, 957, 2019, 819, 459, 6185, 21533, 64725, 24709}},
-{8015, 17, 19579, {1, 3, 5, 13, 11, 25, 107, 245, 175, 519, 629, 537, 2227, 15123, 10619, 32611, 118697}},
-{8016, 17, 19591, {1, 3, 1, 11, 5, 53, 119, 253, 489, 181, 1365, 3465, 1323, 949, 3657, 2467, 38545}},
-{8017, 17, 19595, {1, 1, 3, 9, 27, 17, 109, 19, 297, 541, 89, 3021, 761, 5577, 907, 21405, 128029}},
-{8018, 17, 19605, {1, 1, 3, 9, 31, 9, 61, 149, 267, 707, 671, 2733, 1247, 14623, 6395, 42579, 30845}},
-{8019, 17, 19615, {1, 1, 7, 7, 25, 29, 63, 41, 309, 275, 2019, 1373, 1003, 13891, 16571, 16209, 30115}},
-{8020, 17, 19616, {1, 3, 7, 1, 5, 21, 53, 97, 475, 799, 1963, 1181, 4187, 8767, 24779, 10403, 98349}},
-{8021, 17, 19626, {1, 3, 3, 13, 19, 9, 125, 227, 347, 535, 353, 3087, 769, 9049, 20145, 27433, 23105}},
-{8022, 17, 19631, {1, 1, 1, 15, 7, 61, 51, 113, 403, 501, 1767, 2785, 7151, 14517, 17533, 24913, 7121}},
-{8023, 17, 19634, {1, 1, 1, 9, 7, 21, 27, 169, 425, 567, 31, 35, 7859, 929, 6545, 33983, 13227}},
-{8024, 17, 19640, {1, 1, 5, 15, 11, 15, 69, 33, 127, 1005, 1947, 989, 6333, 15587, 18523, 53547, 115613}},
-{8025, 17, 19645, {1, 3, 5, 3, 1, 55, 7, 99, 213, 737, 363, 3167, 3949, 3723, 15777, 23207, 22901}},
-{8026, 17, 19678, {1, 1, 1, 9, 9, 29, 121, 85, 467, 811, 1, 3543, 6259, 4477, 31371, 27633, 22995}},
-{8027, 17, 19681, {1, 3, 5, 3, 11, 21, 95, 19, 55, 71, 803, 3655, 3749, 5113, 13611, 38097, 20943}},
-{8028, 17, 19682, {1, 3, 3, 11, 19, 25, 127, 105, 447, 499, 485, 881, 2649, 10297, 22283, 18305, 128919}},
-{8029, 17, 19706, {1, 3, 7, 1, 11, 45, 21, 87, 481, 645, 815, 793, 5763, 3945, 14379, 19623, 103199}},
-{8030, 17, 19708, {1, 3, 5, 1, 3, 45, 39, 229, 359, 151, 1079, 3955, 2107, 9593, 6701, 2811, 55215}},
-{8031, 17, 19713, {1, 3, 7, 7, 27, 59, 69, 211, 373, 643, 977, 3545, 2647, 10473, 27919, 10719, 24823}},
-{8032, 17, 19714, {1, 1, 3, 11, 7, 27, 117, 21, 59, 679, 969, 3813, 2701, 7363, 17525, 31229, 100665}},
-{8033, 17, 19720, {1, 3, 3, 5, 29, 53, 113, 141, 197, 991, 81, 2701, 6831, 7949, 16569, 44185, 29631}},
-{8034, 17, 19725, {1, 1, 1, 3, 1, 31, 9, 101, 347, 585, 577, 2529, 7461, 11921, 29475, 34505, 74911}},
-{8035, 17, 19743, {1, 1, 1, 15, 25, 19, 95, 37, 93, 755, 1891, 2309, 623, 13503, 5811, 45863, 106501}},
-{8036, 17, 19753, {1, 1, 5, 3, 15, 23, 51, 225, 87, 679, 1225, 4015, 3971, 163, 3185, 12921, 51267}},
-{8037, 17, 19756, {1, 1, 5, 1, 1, 37, 105, 181, 379, 657, 571, 2775, 5905, 8391, 32069, 18713, 125833}},
-{8038, 17, 19759, {1, 1, 7, 11, 11, 19, 109, 125, 371, 321, 629, 2165, 2861, 7883, 15503, 37679, 33057}},
-{8039, 17, 19762, {1, 1, 3, 5, 7, 5, 21, 5, 169, 321, 1145, 2243, 6143, 2537, 4429, 56493, 39391}},
-{8040, 17, 19776, {1, 3, 5, 5, 31, 7, 15, 175, 441, 663, 921, 3113, 2261, 13033, 19135, 28657, 92225}},
-{8041, 17, 19786, {1, 3, 1, 11, 13, 9, 25, 57, 297, 3, 1561, 825, 2803, 11327, 2699, 28631, 57277}},
-{8042, 17, 19799, {1, 1, 3, 9, 15, 25, 81, 197, 345, 341, 1557, 1375, 2509, 11949, 30201, 6807, 95199}},
-{8043, 17, 19800, {1, 3, 5, 3, 15, 23, 91, 147, 277, 59, 495, 1423, 1775, 12065, 8401, 22639, 111199}},
-{8044, 17, 19803, {1, 1, 5, 1, 1, 59, 35, 255, 229, 293, 187, 2663, 3967, 6493, 20103, 36703, 108939}},
-{8045, 17, 19806, {1, 3, 7, 11, 15, 1, 23, 39, 27, 281, 11, 3119, 2791, 1691, 16521, 39715, 32145}},
-{8046, 17, 19815, {1, 3, 5, 5, 9, 53, 43, 49, 107, 1015, 431, 3017, 3317, 9655, 19193, 45621, 56861}},
-{8047, 17, 19816, {1, 3, 1, 15, 27, 63, 127, 31, 21, 245, 1503, 3339, 6375, 5411, 12369, 35973, 9473}},
-{8048, 17, 19857, {1, 1, 3, 13, 31, 61, 19, 99, 25, 593, 539, 1807, 673, 12339, 23567, 22005, 130341}},
-{8049, 17, 19860, {1, 1, 5, 3, 3, 3, 13, 183, 255, 41, 641, 581, 6509, 1891, 19195, 28277, 51725}},
-{8050, 17, 19874, {1, 1, 3, 5, 3, 59, 17, 227, 9, 345, 1303, 1535, 3089, 2653, 20647, 63159, 124677}},
-{8051, 17, 19883, {1, 3, 1, 11, 25, 19, 117, 29, 221, 461, 1285, 1427, 7183, 3051, 10839, 47491, 92613}},
-{8052, 17, 19885, {1, 1, 3, 5, 27, 19, 1, 235, 51, 215, 783, 2325, 1191, 4679, 14365, 35479, 65083}},
-{8053, 17, 19886, {1, 3, 3, 5, 27, 17, 79, 185, 259, 369, 1399, 1029, 2219, 10975, 30487, 15247, 39789}},
-{8054, 17, 19893, {1, 3, 3, 1, 13, 13, 59, 119, 249, 471, 1433, 1165, 5345, 4431, 375, 64999, 85577}},
-{8055, 17, 19932, {1, 1, 1, 3, 1, 19, 13, 243, 35, 675, 321, 3625, 7835, 6403, 651, 48283, 91819}},
-{8056, 17, 19960, {1, 3, 3, 1, 27, 13, 73, 159, 145, 59, 287, 2419, 8115, 7923, 18933, 36109, 123879}},
-{8057, 17, 19972, {1, 3, 1, 7, 21, 1, 83, 245, 477, 623, 391, 129, 6897, 3447, 11109, 17017, 68277}},
-{8058, 17, 19975, {1, 1, 3, 11, 13, 43, 119, 93, 99, 393, 1219, 995, 1881, 7929, 4337, 33579, 103211}},
-{8059, 17, 20005, {1, 1, 7, 7, 31, 5, 39, 25, 119, 819, 409, 2395, 151, 12763, 28265, 28909, 35685}},
-{8060, 17, 20009, {1, 1, 1, 1, 3, 13, 59, 205, 19, 843, 1691, 955, 1859, 1791, 22083, 37843, 63615}},
-{8061, 17, 20010, {1, 1, 1, 3, 11, 63, 41, 243, 103, 875, 1337, 3731, 6317, 12951, 31743, 56935, 55975}},
-{8062, 17, 20012, {1, 1, 3, 13, 19, 11, 51, 97, 469, 279, 1621, 3521, 853, 11849, 3331, 27907, 119081}},
-{8063, 17, 20023, {1, 1, 5, 1, 23, 55, 9, 141, 449, 41, 167, 2441, 6783, 2785, 3547, 35379, 74973}},
-{8064, 17, 20024, {1, 1, 5, 3, 15, 55, 13, 75, 107, 153, 1841, 3991, 3229, 6523, 18541, 21571, 31539}},
-{8065, 17, 20030, {1, 3, 1, 1, 27, 37, 35, 201, 401, 867, 1861, 1783, 6255, 14001, 29543, 25843, 39719}},
-{8066, 17, 20038, {1, 1, 7, 15, 3, 43, 113, 173, 297, 457, 1369, 4053, 5033, 5513, 27387, 14725, 79937}},
-{8067, 17, 20041, {1, 1, 5, 13, 5, 27, 109, 93, 187, 833, 1551, 2899, 1681, 6979, 1289, 3507, 66499}},
-{8068, 17, 20055, {1, 1, 3, 11, 11, 47, 121, 29, 129, 807, 2037, 1527, 6083, 14803, 10669, 46047, 70241}},
-{8069, 17, 20059, {1, 3, 1, 9, 29, 3, 19, 191, 461, 527, 1389, 3359, 81, 6773, 12185, 49207, 19091}},
-{8070, 17, 20061, {1, 3, 7, 7, 5, 47, 33, 27, 445, 1, 149, 343, 4827, 91, 29233, 37775, 89321}},
-{8071, 17, 20080, {1, 3, 5, 1, 13, 55, 107, 99, 259, 591, 983, 3863, 1231, 3457, 29645, 10709, 16543}},
-{8072, 17, 20086, {1, 3, 7, 9, 29, 5, 9, 165, 337, 187, 219, 97, 6511, 193, 23947, 36329, 35317}},
-{8073, 17, 20089, {1, 3, 7, 1, 31, 25, 5, 175, 409, 1021, 1873, 289, 7143, 15341, 31501, 25707, 106453}},
-{8074, 17, 20095, {1, 3, 7, 7, 27, 1, 15, 221, 341, 987, 1739, 1183, 8139, 11081, 29721, 42991, 72805}},
-{8075, 17, 20111, {1, 1, 1, 9, 11, 1, 13, 17, 501, 543, 1485, 987, 1861, 8527, 1621, 30461, 23057}},
-{8076, 17, 20116, {1, 3, 7, 7, 9, 41, 1, 253, 71, 1009, 427, 3347, 6987, 3303, 30535, 33345, 126459}},
-{8077, 17, 20130, {1, 1, 1, 7, 11, 11, 15, 11, 305, 559, 1805, 1111, 377, 1495, 13471, 34831, 123125}},
-{8078, 17, 20136, {1, 1, 5, 7, 9, 37, 27, 45, 61, 705, 263, 3181, 7077, 5227, 28121, 42865, 3809}},
-{8079, 17, 20147, {1, 1, 5, 1, 23, 25, 29, 199, 259, 959, 661, 43, 6157, 1547, 1497, 24077, 129939}},
-{8080, 17, 20153, {1, 3, 5, 3, 13, 49, 33, 19, 367, 891, 1777, 3119, 5673, 8383, 14487, 1763, 63495}},
-{8081, 17, 20156, {1, 1, 1, 13, 9, 57, 35, 181, 7, 225, 449, 3843, 6257, 4983, 31307, 16559, 27633}},
-{8082, 17, 20167, {1, 3, 1, 11, 7, 33, 55, 81, 41, 61, 1711, 3273, 7629, 11283, 9103, 24105, 107547}},
-{8083, 17, 20173, {1, 3, 5, 5, 13, 17, 13, 51, 235, 869, 1543, 1249, 7749, 14773, 21751, 53497, 108709}},
-{8084, 17, 20182, {1, 1, 3, 9, 3, 63, 89, 43, 23, 479, 115, 3917, 7943, 7323, 5659, 64507, 46941}},
-{8085, 17, 20185, {1, 1, 3, 1, 25, 63, 25, 169, 459, 633, 1785, 1059, 5113, 4799, 29281, 24561, 17017}},
-{8086, 17, 20202, {1, 1, 3, 3, 15, 3, 11, 173, 493, 5, 1575, 653, 7391, 7453, 8297, 28653, 6213}},
-{8087, 17, 20209, {1, 1, 7, 5, 29, 5, 1, 57, 75, 479, 787, 3417, 3349, 111, 17787, 41141, 97597}},
-{8088, 17, 20229, {1, 3, 7, 1, 11, 7, 107, 159, 435, 159, 1401, 803, 7065, 5923, 4005, 37271, 113791}},
-{8089, 17, 20233, {1, 1, 5, 1, 23, 55, 7, 59, 351, 801, 1279, 3231, 4561, 2857, 20563, 46115, 79489}},
-{8090, 17, 20236, {1, 3, 3, 15, 19, 13, 113, 33, 149, 175, 1127, 3815, 4357, 12645, 4449, 61355, 83023}},
-{8091, 17, 20241, {1, 1, 7, 15, 3, 17, 41, 57, 243, 319, 1631, 2751, 7853, 5977, 28367, 20023, 56049}},
-{8092, 17, 20242, {1, 3, 1, 7, 27, 59, 7, 13, 497, 241, 1827, 2861, 1331, 1759, 6037, 18967, 42849}},
-{8093, 17, 20248, {1, 3, 1, 1, 31, 43, 41, 183, 241, 219, 335, 2331, 755, 10589, 29431, 29007, 66667}},
-{8094, 17, 20278, {1, 1, 3, 1, 27, 37, 61, 117, 471, 39, 139, 3821, 2945, 7035, 23673, 20167, 56169}},
-{8095, 17, 20282, {1, 3, 1, 1, 9, 29, 123, 61, 171, 1015, 1029, 1695, 1039, 11883, 259, 10879, 97709}},
-{8096, 17, 20299, {1, 3, 3, 5, 29, 39, 65, 193, 285, 635, 999, 717, 5465, 1849, 4293, 19775, 79121}},
-{8097, 17, 20307, {1, 1, 7, 1, 3, 3, 103, 15, 451, 307, 1027, 263, 6585, 11651, 14457, 62695, 38407}},
-{8098, 17, 20313, {1, 3, 7, 11, 13, 13, 29, 83, 267, 561, 2041, 13, 3167, 3475, 14735, 34455, 117533}},
-{8099, 17, 20314, {1, 3, 1, 15, 5, 1, 35, 225, 151, 637, 1347, 833, 7077, 13145, 10285, 46583, 14351}},
-{8100, 17, 20320, {1, 1, 3, 15, 27, 63, 119, 159, 209, 421, 1413, 2727, 1607, 7175, 6133, 29051, 97387}},
-{8101, 17, 20326, {1, 1, 3, 5, 9, 29, 35, 93, 353, 903, 1037, 469, 5473, 7193, 21883, 14709, 89023}},
-{8102, 17, 20332, {1, 1, 1, 11, 9, 17, 51, 155, 145, 443, 1985, 423, 4721, 15721, 9747, 10303, 21909}},
-{8103, 17, 20350, {1, 3, 7, 15, 19, 49, 53, 153, 241, 739, 1585, 3945, 4869, 11, 15845, 17937, 69397}},
-{8104, 17, 20360, {1, 1, 5, 7, 19, 53, 43, 211, 327, 723, 1513, 1569, 919, 1771, 11309, 50787, 7459}},
-{8105, 17, 20371, {1, 1, 1, 9, 7, 29, 49, 89, 409, 685, 201, 1327, 2807, 13101, 2485, 62909, 102595}},
-{8106, 17, 20373, {1, 3, 1, 13, 21, 51, 37, 231, 271, 475, 855, 3703, 4447, 5161, 17937, 14471, 47173}},
-{8107, 17, 20377, {1, 1, 7, 3, 9, 7, 121, 197, 71, 147, 1669, 1745, 6589, 15029, 1529, 12625, 121925}},
-{8108, 17, 20390, {1, 1, 1, 3, 7, 47, 63, 61, 187, 341, 919, 307, 389, 14141, 12941, 17917, 104289}},
-{8109, 17, 20396, {1, 3, 5, 13, 19, 43, 57, 11, 383, 311, 1229, 3527, 3301, 12473, 24377, 16279, 92733}},
-{8110, 17, 20404, {1, 3, 3, 5, 25, 35, 63, 23, 131, 481, 809, 3627, 5685, 13695, 14121, 64751, 66181}},
-{8111, 17, 20413, {1, 3, 1, 5, 11, 43, 89, 55, 103, 219, 1861, 3223, 5111, 5879, 31399, 1395, 87419}},
-{8112, 17, 20434, {1, 3, 1, 11, 21, 27, 123, 205, 47, 923, 7, 1635, 4019, 8431, 28313, 24275, 129617}},
-{8113, 17, 20436, {1, 1, 1, 3, 1, 11, 91, 215, 393, 999, 1071, 3225, 4415, 759, 24499, 16109, 33791}},
-{8114, 17, 20440, {1, 1, 3, 13, 19, 45, 77, 103, 105, 395, 529, 3631, 8179, 4467, 30263, 39379, 70507}},
-{8115, 17, 20443, {1, 3, 3, 9, 17, 45, 101, 219, 433, 971, 471, 1243, 6955, 5941, 20641, 16119, 129383}},
-{8116, 17, 20445, {1, 1, 7, 7, 9, 9, 91, 95, 503, 171, 129, 1509, 7179, 5367, 2219, 50445, 112459}},
-{8117, 17, 20464, {1, 3, 7, 1, 17, 17, 19, 173, 229, 519, 147, 1835, 3797, 8091, 20335, 33177, 90197}},
-{8118, 17, 20476, {1, 3, 3, 5, 23, 29, 107, 205, 43, 969, 799, 1239, 1353, 5221, 15175, 42945, 34043}},
-{8119, 17, 20494, {1, 1, 5, 7, 31, 63, 67, 87, 189, 301, 1719, 3937, 965, 2505, 24781, 25133, 91675}},
-{8120, 17, 20496, {1, 3, 1, 7, 15, 25, 11, 39, 281, 35, 1149, 1445, 6451, 12069, 20959, 29895, 60059}},
-{8121, 17, 20501, {1, 1, 5, 1, 1, 17, 65, 213, 359, 561, 2015, 1629, 3521, 6877, 8099, 62483, 103903}},
-{8122, 17, 20518, {1, 1, 7, 9, 7, 49, 1, 227, 49, 823, 1141, 2419, 2697, 13293, 14143, 6323, 16081}},
-{8123, 17, 20527, {1, 3, 3, 1, 9, 13, 99, 235, 343, 601, 927, 183, 4545, 14529, 5521, 55571, 90675}},
-{8124, 17, 20529, {1, 1, 5, 1, 13, 49, 95, 153, 131, 955, 283, 2951, 3651, 7743, 4285, 42621, 110577}},
-{8125, 17, 20535, {1, 1, 1, 9, 19, 59, 97, 181, 67, 357, 497, 287, 3523, 3729, 28981, 59687, 39463}},
-{8126, 17, 20544, {1, 1, 3, 7, 5, 19, 107, 55, 393, 225, 1953, 669, 8063, 6537, 15983, 59891, 95079}},
-{8127, 17, 20568, {1, 3, 1, 5, 29, 21, 17, 169, 447, 697, 1613, 3483, 3139, 11175, 28865, 12065, 130241}},
-{8128, 17, 20589, {1, 3, 5, 7, 5, 49, 35, 181, 85, 505, 1537, 1345, 773, 3255, 27405, 3959, 126377}},
-{8129, 17, 20592, {1, 1, 7, 15, 9, 9, 17, 99, 409, 319, 807, 1721, 4023, 2171, 32657, 51663, 23253}},
-{8130, 17, 20601, {1, 3, 5, 1, 5, 3, 37, 219, 89, 263, 397, 573, 6147, 9525, 2521, 11153, 94319}},
-{8131, 17, 20617, {1, 1, 5, 5, 11, 39, 55, 205, 209, 239, 1443, 2477, 1941, 8337, 2883, 54593, 129859}},
-{8132, 17, 20625, {1, 1, 1, 7, 11, 13, 127, 65, 127, 413, 1553, 413, 3395, 9451, 7517, 34103, 57029}},
-{8133, 17, 20626, {1, 1, 1, 15, 5, 25, 109, 181, 399, 1023, 277, 3365, 6209, 827, 13933, 27483, 63835}},
-{8134, 17, 20632, {1, 1, 3, 3, 21, 57, 95, 127, 481, 365, 197, 3631, 7443, 4925, 31277, 35061, 35875}},
-{8135, 17, 20638, {1, 1, 7, 13, 3, 31, 59, 127, 441, 967, 1049, 1281, 3553, 375, 9683, 45755, 18889}},
-{8136, 17, 20644, {1, 1, 1, 13, 11, 39, 49, 43, 383, 607, 157, 1887, 3623, 13335, 31949, 49843, 96781}},
-{8137, 17, 20647, {1, 3, 7, 13, 19, 35, 21, 9, 299, 425, 1921, 3481, 6849, 4149, 5227, 56737, 27559}},
-{8138, 17, 20662, {1, 3, 7, 5, 21, 11, 79, 97, 1, 849, 819, 1133, 3393, 5429, 10621, 38787, 120785}},
-{8139, 17, 20671, {1, 1, 1, 13, 21, 29, 3, 239, 399, 619, 759, 2655, 3691, 655, 30979, 15507, 114791}},
-{8140, 17, 20674, {1, 3, 5, 3, 1, 61, 79, 43, 273, 965, 1759, 3901, 2437, 1703, 20205, 46291, 23679}},
-{8141, 17, 20683, {1, 1, 1, 9, 19, 57, 75, 245, 377, 261, 231, 3683, 6745, 7797, 28471, 56269, 109969}},
-{8142, 17, 20704, {1, 3, 1, 11, 9, 55, 53, 87, 33, 431, 1805, 2933, 455, 12479, 16235, 2667, 70105}},
-{8143, 17, 20724, {1, 3, 5, 1, 29, 1, 101, 17, 377, 499, 1365, 209, 4819, 15099, 8769, 37003, 53003}},
-{8144, 17, 20742, {1, 3, 5, 11, 11, 39, 109, 235, 337, 393, 35, 1071, 7085, 7165, 25143, 24223, 71493}},
-{8145, 17, 20748, {1, 3, 1, 5, 13, 49, 9, 205, 305, 943, 799, 2405, 319, 10755, 9785, 32023, 48015}},
-{8146, 17, 20765, {1, 3, 1, 9, 29, 35, 123, 101, 73, 747, 1257, 407, 5871, 4271, 14837, 52727, 13339}},
-{8147, 17, 20776, {1, 3, 3, 9, 31, 7, 113, 27, 89, 123, 1117, 531, 5531, 7897, 11209, 35267, 123457}},
-{8148, 17, 20789, {1, 1, 1, 1, 29, 19, 93, 11, 61, 743, 267, 13, 6561, 7667, 20537, 12675, 10481}},
-{8149, 17, 20796, {1, 1, 5, 13, 27, 47, 103, 171, 349, 139, 1709, 961, 783, 7147, 5569, 53395, 80797}},
-{8150, 17, 20802, {1, 3, 1, 9, 21, 49, 41, 175, 507, 861, 1157, 1033, 6795, 5795, 603, 12485, 75263}},
-{8151, 17, 20807, {1, 1, 5, 7, 23, 3, 21, 165, 123, 951, 785, 2065, 8001, 7009, 22981, 10011, 9807}},
-{8152, 17, 20814, {1, 3, 7, 15, 1, 53, 49, 197, 231, 351, 141, 3465, 7907, 10695, 30913, 26753, 71079}},
-{8153, 17, 20821, {1, 3, 5, 3, 29, 45, 23, 131, 65, 507, 75, 275, 7287, 187, 1093, 52657, 31533}},
-{8154, 17, 20832, {1, 3, 5, 9, 9, 7, 113, 125, 441, 75, 663, 4081, 3147, 1469, 28375, 35747, 122965}},
-{8155, 17, 20835, {1, 1, 7, 3, 3, 57, 5, 17, 183, 237, 965, 3709, 4161, 9513, 217, 58835, 78789}},
-{8156, 17, 20847, {1, 1, 3, 1, 7, 25, 13, 29, 173, 319, 1723, 57, 2401, 10405, 15541, 52915, 93747}},
-{8157, 17, 20859, {1, 1, 7, 5, 1, 31, 11, 61, 341, 97, 1199, 2585, 5909, 3707, 31507, 51233, 2389}},
-{8158, 17, 20871, {1, 1, 5, 15, 15, 21, 127, 155, 229, 203, 1303, 3215, 1965, 9481, 31909, 52307, 112207}},
-{8159, 17, 20883, {1, 3, 1, 13, 9, 45, 91, 39, 113, 587, 895, 637, 2475, 1695, 9347, 53255, 75797}},
-{8160, 17, 20886, {1, 3, 5, 13, 17, 11, 35, 83, 69, 255, 741, 3927, 153, 11001, 29145, 37107, 51873}},
-{8161, 17, 20892, {1, 1, 7, 5, 5, 37, 35, 219, 153, 1005, 973, 2555, 893, 5931, 23857, 34631, 74561}},
-{8162, 17, 20906, {1, 3, 1, 11, 21, 63, 113, 29, 115, 307, 957, 407, 879, 4819, 2865, 1773, 116825}},
-{8163, 17, 20908, {1, 3, 7, 3, 19, 55, 87, 21, 139, 571, 311, 2295, 2729, 6371, 11845, 30223, 19247}},
-{8164, 17, 20957, {1, 3, 7, 5, 23, 9, 59, 25, 357, 863, 435, 2509, 5599, 14039, 25731, 41645, 255}},
-{8165, 17, 20962, {1, 3, 7, 13, 9, 3, 63, 115, 503, 489, 1585, 813, 5419, 691, 23973, 18677, 59979}},
-{8166, 17, 20968, {1, 1, 1, 1, 13, 3, 55, 23, 185, 731, 459, 1497, 433, 16243, 29995, 20777, 59513}},
-{8167, 17, 20979, {1, 1, 7, 3, 27, 55, 77, 57, 349, 5, 617, 385, 6225, 7025, 23335, 877, 21973}},
-{8168, 17, 20991, {1, 3, 3, 5, 3, 37, 105, 197, 153, 639, 1643, 1093, 801, 4605, 4551, 46081, 7739}},
-{8169, 17, 20998, {1, 1, 5, 11, 29, 23, 5, 91, 39, 489, 2029, 887, 4451, 11463, 5641, 56299, 34027}},
-{8170, 17, 21007, {1, 1, 7, 3, 17, 11, 25, 161, 317, 701, 155, 1989, 7549, 11529, 9945, 18395, 61251}},
-{8171, 17, 21010, {1, 1, 7, 13, 23, 55, 113, 91, 17, 149, 1893, 2793, 8185, 81, 29487, 47925, 51837}},
-{8172, 17, 21026, {1, 3, 7, 7, 9, 29, 103, 161, 215, 129, 113, 1987, 919, 9639, 20715, 6541, 15041}},
-{8173, 17, 21037, {1, 1, 5, 9, 19, 19, 127, 43, 263, 997, 1687, 3801, 4249, 6309, 25889, 1787, 122771}},
-{8174, 17, 21038, {1, 3, 5, 13, 17, 3, 91, 183, 349, 467, 333, 3299, 3085, 12135, 16801, 31471, 37227}},
-{8175, 17, 21045, {1, 1, 5, 3, 7, 53, 11, 221, 407, 545, 237, 3631, 1791, 3729, 19737, 921, 57303}},
-{8176, 17, 21057, {1, 3, 7, 15, 3, 27, 71, 45, 219, 9, 1135, 2267, 6841, 8637, 30317, 9397, 115425}},
-{8177, 17, 21082, {1, 1, 3, 5, 29, 59, 121, 225, 419, 813, 1725, 3969, 3451, 8457, 31803, 57659, 33263}},
-{8178, 17, 21093, {1, 3, 3, 3, 17, 3, 65, 249, 423, 293, 1333, 3947, 1477, 4005, 30445, 28171, 95823}},
-{8179, 17, 21094, {1, 3, 3, 11, 29, 45, 67, 89, 75, 95, 555, 1823, 2795, 11929, 1995, 30013, 116241}},
-{8180, 17, 21105, {1, 3, 3, 3, 23, 35, 87, 221, 385, 275, 803, 387, 7765, 15637, 27953, 20913, 25279}},
-{8181, 17, 21117, {1, 3, 7, 15, 15, 43, 21, 179, 393, 95, 1913, 1715, 4467, 15093, 13613, 50775, 37133}},
-{8182, 17, 21121, {1, 1, 7, 7, 31, 27, 49, 71, 323, 123, 597, 2395, 4449, 7249, 20197, 19789, 92685}},
-{8183, 17, 21124, {1, 1, 5, 13, 31, 37, 89, 225, 357, 201, 1887, 3915, 2165, 10809, 21623, 34375, 110905}},
-{8184, 17, 21136, {1, 1, 5, 7, 11, 53, 37, 55, 61, 679, 1465, 1587, 2215, 16237, 14985, 50507, 128637}},
-{8185, 17, 21139, {1, 1, 7, 1, 15, 53, 115, 21, 279, 555, 43, 2429, 7251, 2141, 4813, 47047, 119551}},
-{8186, 17, 21142, {1, 1, 5, 13, 11, 41, 59, 245, 337, 117, 1125, 4007, 947, 10591, 17795, 48535, 72171}},
-{8187, 17, 21145, {1, 1, 5, 15, 27, 41, 71, 43, 505, 539, 975, 1567, 795, 4433, 11689, 53051, 98819}},
-{8188, 17, 21167, {1, 1, 7, 9, 1, 57, 57, 137, 323, 311, 759, 3027, 3713, 13, 24133, 21451, 1153}},
-{8189, 17, 21170, {1, 1, 5, 15, 31, 49, 23, 123, 271, 549, 1995, 5, 6065, 3797, 1085, 50137, 19741}},
-{8190, 17, 21175, {1, 3, 3, 13, 5, 15, 21, 117, 487, 43, 1759, 2899, 4239, 9729, 16711, 31559, 34553}},
-{8191, 17, 21179, {1, 1, 5, 13, 5, 23, 83, 49, 147, 267, 923, 1377, 1687, 1793, 30383, 19537, 66989}},
-{8192, 17, 21182, {1, 1, 1, 13, 9, 41, 105, 241, 499, 891, 885, 3349, 4703, 5609, 11999, 58025, 69089}},
-{8193, 17, 21193, {1, 1, 7, 9, 21, 11, 121, 69, 115, 895, 91, 3745, 41, 12787, 26181, 31399, 30463}},
-{8194, 17, 21194, {1, 1, 7, 13, 11, 3, 23, 173, 5, 907, 45, 3465, 2807, 3731, 14347, 27973, 8567}},
-{8195, 17, 21207, {1, 3, 7, 5, 27, 47, 43, 25, 499, 57, 649, 705, 6223, 4213, 4549, 23213, 13657}},
-{8196, 17, 21217, {1, 1, 7, 11, 21, 35, 5, 79, 295, 359, 1993, 99, 7917, 14917, 2131, 45527, 31451}},
-{8197, 17, 21224, {1, 1, 5, 15, 1, 39, 85, 93, 65, 991, 389, 585, 4835, 11671, 10913, 41787, 84953}},
-{8198, 17, 21244, {1, 1, 1, 5, 27, 5, 1, 15, 11, 83, 1191, 3945, 4697, 7703, 6929, 6057, 88721}},
-{8199, 17, 21247, {1, 1, 3, 7, 27, 39, 71, 181, 191, 997, 419, 1671, 7771, 15305, 18677, 45033, 64745}},
-{8200, 17, 21252, {1, 3, 7, 3, 15, 41, 33, 239, 93, 307, 153, 2701, 1549, 5011, 6913, 19257, 55829}},
-{8201, 17, 21264, {1, 3, 3, 11, 21, 47, 69, 223, 365, 877, 431, 1629, 4803, 11591, 13973, 56359, 11897}},
-{8202, 17, 21273, {1, 3, 7, 7, 1, 59, 63, 129, 251, 873, 603, 2707, 2847, 8739, 31343, 63291, 5607}},
-{8203, 17, 21289, {1, 3, 5, 5, 19, 13, 79, 235, 151, 571, 953, 2191, 5973, 4751, 11119, 14439, 97755}},
-{8204, 17, 21290, {1, 1, 5, 1, 27, 3, 105, 139, 13, 821, 221, 2025, 7303, 1891, 28193, 45537, 92703}},
-{8205, 17, 21295, {1, 3, 7, 9, 13, 63, 27, 149, 51, 121, 587, 3695, 4115, 3955, 22493, 34903, 51669}},
-{8206, 17, 21297, {1, 1, 5, 7, 19, 5, 89, 87, 269, 585, 421, 3827, 315, 14739, 109, 43009, 94969}},
-{8207, 17, 21309, {1, 1, 5, 15, 9, 53, 125, 83, 159, 917, 1583, 585, 6839, 14957, 20007, 60467, 96309}},
-{8208, 17, 21318, {1, 3, 5, 1, 23, 49, 109, 91, 17, 731, 1083, 3153, 1825, 14293, 25639, 44599, 47541}},
-{8209, 17, 21322, {1, 1, 3, 7, 21, 51, 45, 25, 367, 925, 799, 1673, 6977, 7155, 829, 25899, 104615}},
-{8210, 17, 21324, {1, 3, 3, 13, 13, 49, 95, 239, 195, 353, 1967, 1419, 929, 503, 11717, 9485, 62885}},
-{8211, 17, 21329, {1, 1, 1, 15, 3, 41, 109, 91, 327, 789, 1429, 1159, 2801, 4845, 19663, 47737, 11029}},
-{8212, 17, 21332, {1, 3, 5, 1, 21, 63, 57, 107, 229, 771, 1911, 647, 6989, 12615, 23191, 64941, 97595}},
-{8213, 17, 21336, {1, 1, 1, 15, 5, 13, 15, 109, 459, 447, 1625, 1269, 7629, 7929, 4405, 12143, 40481}},
-{8214, 17, 21342, {1, 3, 3, 1, 23, 3, 95, 229, 363, 379, 1149, 1615, 5125, 3645, 27535, 58791, 38091}},
-{8215, 17, 21351, {1, 1, 1, 1, 9, 45, 119, 85, 151, 171, 1123, 41, 6517, 8067, 17845, 23301, 95383}},
-{8216, 17, 21355, {1, 3, 1, 15, 17, 31, 103, 71, 35, 1019, 1687, 1175, 6119, 14075, 26601, 28873, 36617}},
-{8217, 17, 21363, {1, 3, 3, 9, 13, 39, 7, 17, 207, 219, 637, 3025, 1709, 4031, 563, 14865, 129389}},
-{8218, 17, 21372, {1, 3, 7, 1, 21, 11, 121, 85, 111, 641, 1163, 3173, 5189, 13261, 19471, 39635, 76545}},
-{8219, 17, 21382, {1, 3, 7, 15, 3, 45, 3, 37, 121, 967, 1861, 3257, 3699, 6881, 11905, 8413, 59397}},
-{8220, 17, 21388, {1, 3, 3, 13, 25, 53, 85, 181, 1, 979, 2045, 297, 1739, 8139, 17897, 35251, 7193}},
-{8221, 17, 21394, {1, 1, 1, 3, 5, 49, 77, 115, 377, 209, 1415, 3747, 485, 803, 2507, 27729, 52201}},
-{8222, 17, 21403, {1, 3, 1, 5, 31, 55, 85, 171, 135, 893, 1423, 3693, 6155, 5321, 8297, 39183, 88377}},
-{8223, 17, 21409, {1, 3, 3, 15, 1, 35, 73, 239, 181, 101, 509, 2449, 4955, 13049, 27631, 16871, 40151}},
-{8224, 17, 21416, {1, 1, 7, 13, 27, 7, 109, 71, 437, 835, 563, 1355, 3681, 7431, 32743, 59693, 125055}},
-{8225, 17, 21421, {1, 1, 7, 5, 19, 23, 29, 147, 291, 507, 1943, 2069, 3309, 11569, 1031, 49345, 86735}},
-{8226, 17, 21424, {1, 1, 3, 13, 17, 45, 91, 167, 19, 137, 527, 961, 4435, 2277, 6863, 57917, 129407}},
-{8227, 17, 21444, {1, 3, 5, 7, 11, 31, 79, 207, 43, 871, 1121, 2929, 6899, 4099, 29533, 45333, 33299}},
-{8228, 17, 21453, {1, 1, 7, 5, 5, 49, 13, 95, 475, 91, 337, 3531, 3157, 1331, 32655, 46169, 3549}},
-{8229, 17, 21466, {1, 3, 1, 5, 5, 9, 73, 177, 123, 251, 717, 541, 7083, 6907, 1417, 31203, 9755}},
-{8230, 17, 21471, {1, 3, 1, 11, 21, 11, 91, 155, 447, 165, 1525, 2073, 5103, 193, 2677, 43673, 70579}},
-{8231, 17, 21495, {1, 3, 7, 1, 7, 27, 115, 247, 211, 779, 1999, 209, 3215, 111, 25567, 34641, 130873}},
-{8232, 17, 21499, {1, 1, 5, 9, 25, 7, 15, 19, 217, 831, 1577, 2051, 3533, 2337, 7675, 2845, 69135}},
-{8233, 17, 21504, {1, 3, 5, 15, 29, 11, 91, 59, 221, 383, 1235, 1261, 2967, 14989, 11455, 6459, 58047}},
-{8234, 17, 21507, {1, 3, 5, 1, 3, 35, 5, 127, 99, 981, 493, 3001, 5651, 3125, 27789, 57389, 115631}},
-{8235, 17, 21521, {1, 3, 5, 5, 29, 63, 123, 161, 247, 177, 1653, 2665, 3903, 11129, 20961, 49429, 44075}},
-{8236, 17, 21527, {1, 3, 1, 1, 13, 9, 57, 167, 291, 765, 1929, 397, 5503, 5601, 6957, 62003, 104631}},
-{8237, 17, 21555, {1, 1, 7, 15, 9, 43, 57, 85, 157, 361, 1931, 2183, 8045, 14939, 2169, 25733, 29095}},
-{8238, 17, 21558, {1, 1, 3, 15, 13, 35, 47, 123, 13, 667, 1373, 4069, 6259, 13453, 13439, 25349, 99437}},
-{8239, 17, 21562, {1, 3, 7, 1, 31, 15, 69, 45, 355, 919, 415, 793, 3987, 8785, 4905, 8177, 123989}},
-{8240, 17, 21570, {1, 3, 7, 13, 29, 27, 69, 57, 385, 185, 171, 2499, 3983, 13437, 23585, 21501, 88079}},
-{8241, 17, 21576, {1, 1, 5, 11, 27, 3, 77, 99, 221, 997, 1653, 1963, 2251, 15505, 26347, 51933, 100679}},
-{8242, 17, 21579, {1, 1, 1, 7, 19, 39, 49, 69, 193, 235, 959, 2823, 2573, 8001, 4389, 13217, 60975}},
-{8243, 17, 21581, {1, 1, 7, 5, 1, 3, 3, 189, 199, 293, 1225, 1913, 7271, 2255, 661, 23293, 82069}},
-{8244, 17, 21587, {1, 1, 5, 5, 21, 31, 35, 113, 47, 479, 325, 1663, 7409, 8975, 14151, 56317, 79663}},
-{8245, 17, 21590, {1, 1, 5, 9, 15, 63, 99, 135, 277, 715, 667, 387, 6929, 12873, 12913, 2599, 84939}},
-{8246, 17, 21599, {1, 1, 7, 15, 23, 39, 67, 25, 179, 313, 459, 295, 1103, 1737, 7529, 29463, 104693}},
-{8247, 17, 21605, {1, 1, 3, 13, 23, 11, 111, 67, 105, 191, 1967, 3497, 7621, 487, 18545, 59521, 115315}},
-{8248, 17, 21612, {1, 1, 1, 7, 25, 45, 83, 61, 231, 569, 155, 2817, 6985, 5289, 6731, 3087, 89749}},
-{8249, 17, 21618, {1, 3, 7, 1, 1, 61, 103, 49, 135, 411, 659, 1735, 4461, 8077, 12885, 62791, 114769}},
-{8250, 17, 21630, {1, 1, 7, 13, 3, 53, 21, 81, 433, 563, 857, 891, 195, 11669, 24769, 56539, 47601}},
-{8251, 17, 21639, {1, 3, 1, 13, 3, 41, 59, 101, 67, 803, 1209, 3267, 1255, 5763, 5483, 36339, 38451}},
-{8252, 17, 21640, {1, 3, 5, 3, 25, 51, 53, 213, 329, 11, 483, 81, 2151, 7623, 26309, 15289, 85103}},
-{8253, 17, 21643, {1, 3, 3, 13, 23, 17, 9, 161, 417, 207, 39, 3615, 7567, 15207, 20383, 58885, 121765}},
-{8254, 17, 21648, {1, 3, 1, 7, 15, 59, 9, 195, 187, 583, 341, 2737, 3891, 331, 18055, 60455, 113271}},
-{8255, 17, 21669, {1, 1, 3, 3, 19, 25, 95, 37, 281, 59, 1613, 2733, 5715, 4067, 5509, 5851, 35189}},
-{8256, 17, 21679, {1, 3, 1, 3, 31, 43, 125, 107, 341, 109, 1991, 849, 7795, 13607, 20421, 3339, 78979}},
-{8257, 17, 21681, {1, 3, 7, 13, 15, 57, 87, 151, 479, 99, 479, 447, 7407, 303, 16397, 15699, 122273}},
-{8258, 17, 21687, {1, 1, 3, 1, 27, 61, 79, 195, 5, 839, 1411, 3451, 4627, 13715, 18401, 24325, 44027}},
-{8259, 17, 21688, {1, 1, 7, 15, 21, 39, 57, 207, 213, 367, 547, 1203, 6385, 2555, 31465, 15675, 7133}},
-{8260, 17, 21706, {1, 1, 5, 15, 27, 3, 75, 123, 337, 1019, 1525, 3065, 1919, 10779, 27409, 6291, 86291}},
-{8261, 17, 21713, {1, 1, 7, 11, 15, 27, 67, 145, 125, 521, 647, 2957, 6337, 14973, 24139, 29107, 27151}},
-{8262, 17, 21714, {1, 1, 1, 13, 25, 57, 103, 83, 321, 111, 131, 2051, 5267, 4723, 1939, 40389, 4803}},
-{8263, 17, 21716, {1, 3, 1, 7, 29, 7, 35, 133, 349, 855, 613, 2563, 2261, 2119, 13939, 24727, 26719}},
-{8264, 17, 21730, {1, 3, 3, 1, 11, 61, 25, 177, 427, 1005, 2027, 649, 7871, 7803, 4717, 59207, 57945}},
-{8265, 17, 21732, {1, 1, 7, 1, 15, 45, 75, 133, 193, 745, 485, 197, 6001, 13837, 615, 43629, 127321}},
-{8266, 17, 21749, {1, 3, 3, 13, 5, 7, 101, 183, 211, 283, 1327, 1395, 8175, 13359, 18361, 54243, 3555}},
-{8267, 17, 21756, {1, 1, 7, 13, 7, 43, 19, 41, 319, 701, 795, 1407, 7113, 9149, 31953, 17075, 53975}},
-{8268, 17, 21774, {1, 3, 5, 13, 11, 19, 101, 125, 327, 75, 1471, 3465, 2247, 5107, 11519, 45161, 71373}},
-{8269, 17, 21779, {1, 3, 7, 13, 23, 59, 53, 57, 137, 575, 59, 3829, 963, 11259, 25771, 29223, 79535}},
-{8270, 17, 21781, {1, 3, 3, 11, 17, 31, 111, 147, 499, 441, 1385, 769, 6901, 8349, 1427, 16561, 7485}},
-{8271, 17, 21786, {1, 1, 7, 9, 21, 7, 47, 83, 351, 867, 265, 1329, 7853, 6959, 11821, 44947, 42275}},
-{8272, 17, 21792, {1, 1, 7, 15, 3, 17, 79, 143, 449, 577, 1007, 1101, 3229, 6861, 23921, 37551, 117309}},
-{8273, 17, 21810, {1, 3, 5, 11, 27, 63, 107, 15, 289, 821, 1723, 1945, 1373, 14469, 30985, 55987, 21255}},
-{8274, 17, 21819, {1, 3, 5, 3, 21, 39, 79, 85, 485, 733, 2031, 1573, 6873, 12225, 30471, 54233, 26967}},
-{8275, 17, 21829, {1, 3, 5, 7, 17, 29, 93, 251, 437, 583, 825, 551, 6545, 10905, 27863, 37037, 52129}},
-{8276, 17, 21830, {1, 3, 7, 9, 23, 1, 23, 85, 195, 319, 1759, 3985, 2413, 16205, 22197, 48821, 94907}},
-{8277, 17, 21844, {1, 1, 3, 7, 17, 47, 3, 195, 167, 925, 11, 3431, 1767, 5917, 13915, 54565, 64625}},
-{8278, 17, 21853, {1, 3, 1, 13, 23, 43, 97, 93, 313, 773, 591, 127, 6005, 11497, 32573, 8173, 92053}},
-{8279, 17, 21867, {1, 1, 5, 9, 17, 47, 115, 237, 389, 619, 377, 561, 1333, 6433, 9743, 32673, 98039}},
-{8280, 17, 21869, {1, 3, 7, 15, 23, 17, 99, 225, 145, 191, 2041, 581, 841, 9377, 18123, 32773, 66849}},
-{8281, 17, 21882, {1, 3, 7, 15, 21, 49, 97, 41, 357, 527, 2019, 2083, 2611, 12449, 20037, 52503, 105991}},
-{8282, 17, 21891, {1, 1, 5, 13, 17, 53, 41, 75, 355, 207, 1675, 591, 5797, 9217, 16443, 3205, 81905}},
-{8283, 17, 21898, {1, 3, 7, 11, 1, 61, 29, 207, 449, 103, 1527, 2327, 7895, 10137, 25223, 51607, 60809}},
-{8284, 17, 21917, {1, 3, 3, 5, 15, 57, 87, 233, 301, 989, 485, 2143, 7411, 5475, 23377, 56005, 59721}},
-{8285, 17, 21934, {1, 3, 1, 15, 29, 7, 95, 141, 369, 231, 735, 1103, 1565, 11575, 571, 3257, 62961}},
-{8286, 17, 21946, {1, 1, 5, 15, 27, 19, 25, 35, 303, 555, 95, 1323, 6139, 5079, 21763, 59591, 103537}},
-{8287, 17, 21948, {1, 1, 1, 13, 25, 23, 85, 151, 135, 349, 1753, 1061, 7697, 1723, 5213, 12581, 103995}},
-{8288, 17, 21963, {1, 3, 1, 9, 29, 51, 101, 195, 59, 809, 1527, 2179, 63, 3681, 29823, 57537, 121371}},
-{8289, 17, 21966, {1, 1, 7, 11, 27, 61, 85, 213, 245, 261, 1649, 2423, 6127, 5687, 4247, 56061, 109793}},
-{8290, 17, 21968, {1, 3, 5, 15, 11, 33, 127, 31, 269, 857, 2027, 2611, 1729, 11783, 16459, 31083, 30671}},
-{8291, 17, 21973, {1, 1, 7, 9, 11, 29, 127, 177, 505, 227, 1499, 1309, 6855, 9999, 21815, 32987, 79109}},
-{8292, 17, 21977, {1, 3, 7, 11, 7, 21, 107, 1, 493, 459, 867, 3199, 7985, 12957, 28197, 41133, 105985}},
-{8293, 17, 21980, {1, 1, 3, 15, 1, 57, 113, 97, 213, 547, 1017, 2961, 461, 16125, 10621, 4243, 58277}},
-{8294, 17, 21984, {1, 1, 3, 5, 11, 57, 61, 47, 209, 961, 333, 795, 4491, 15115, 25745, 62633, 66269}},
-{8295, 17, 21994, {1, 1, 7, 3, 19, 13, 49, 167, 455, 863, 581, 1407, 4247, 15023, 2247, 19981, 125891}},
-{8296, 17, 21999, {1, 1, 7, 15, 17, 55, 27, 35, 33, 349, 879, 1781, 1075, 2475, 30689, 42043, 29423}},
-{8297, 17, 22018, {1, 1, 1, 11, 25, 53, 121, 117, 117, 845, 447, 3927, 1951, 8643, 24497, 44833, 99533}},
-{8298, 17, 22020, {1, 1, 7, 13, 3, 59, 117, 9, 359, 453, 327, 3419, 5957, 97, 20541, 49441, 5673}},
-{8299, 17, 22029, {1, 3, 5, 5, 31, 35, 95, 107, 435, 733, 827, 1361, 6627, 8905, 2681, 25473, 46093}},
-{8300, 17, 22032, {1, 3, 3, 5, 7, 23, 75, 137, 231, 915, 637, 2963, 4409, 12799, 31587, 65363, 69539}},
-{8301, 17, 22041, {1, 1, 1, 7, 15, 35, 19, 233, 189, 837, 243, 2525, 6185, 565, 8133, 4265, 3089}},
-{8302, 17, 22047, {1, 1, 5, 5, 19, 59, 103, 201, 287, 449, 21, 2331, 341, 13145, 18607, 46407, 2767}},
-{8303, 17, 22048, {1, 3, 3, 15, 19, 41, 49, 179, 109, 367, 1185, 1045, 1635, 9647, 16613, 25357, 34291}},
-{8304, 17, 22071, {1, 3, 5, 1, 13, 11, 89, 25, 159, 637, 1979, 549, 3553, 9163, 227, 50553, 46307}},
-{8305, 17, 22075, {1, 1, 3, 1, 17, 33, 73, 239, 261, 751, 1267, 2643, 2549, 8331, 25083, 9715, 67289}},
-{8306, 17, 22078, {1, 1, 1, 13, 3, 49, 7, 35, 367, 293, 903, 1045, 569, 6017, 27635, 51833, 32963}},
-{8307, 17, 22083, {1, 3, 5, 3, 31, 3, 69, 137, 57, 87, 719, 3977, 3031, 7675, 24605, 8757, 93173}},
-{8308, 17, 22089, {1, 3, 3, 1, 7, 45, 97, 35, 233, 69, 1525, 4047, 2599, 13679, 4389, 49079, 121465}},
-{8309, 17, 22097, {1, 1, 7, 13, 7, 25, 57, 211, 337, 189, 1825, 2451, 7651, 11277, 27763, 40671, 57223}},
-{8310, 17, 22110, {1, 1, 1, 1, 15, 59, 55, 169, 461, 907, 407, 803, 3349, 4727, 20983, 47717, 51647}},
-{8311, 17, 22113, {1, 3, 7, 1, 15, 51, 25, 119, 439, 593, 1289, 3959, 5489, 13283, 31837, 8441, 58373}},
-{8312, 17, 22119, {1, 3, 1, 9, 5, 1, 81, 45, 13, 537, 1091, 3861, 6781, 5679, 2807, 29757, 40917}},
-{8313, 17, 22120, {1, 3, 5, 3, 27, 41, 19, 235, 207, 697, 775, 837, 3431, 3175, 10807, 42775, 67987}},
-{8314, 17, 22126, {1, 3, 7, 3, 29, 33, 35, 119, 271, 609, 1747, 2839, 3415, 2275, 30979, 41293, 99341}},
-{8315, 17, 22133, {1, 3, 3, 3, 5, 17, 13, 169, 269, 709, 1449, 3169, 1545, 16075, 8937, 39705, 19609}},
-{8316, 17, 22134, {1, 3, 5, 15, 29, 13, 1, 199, 65, 385, 977, 797, 1181, 10979, 241, 40393, 73663}},
-{8317, 17, 22140, {1, 1, 3, 7, 17, 35, 47, 63, 193, 451, 151, 3415, 99, 14557, 26025, 31361, 112639}},
-{8318, 17, 22147, {1, 1, 3, 5, 19, 13, 29, 33, 365, 311, 1241, 217, 6205, 13067, 18585, 21693, 97127}},
-{8319, 17, 22161, {1, 1, 3, 15, 19, 7, 87, 25, 91, 13, 1839, 1445, 957, 9779, 25557, 37027, 38987}},
-{8320, 17, 22164, {1, 1, 5, 1, 21, 5, 79, 67, 481, 455, 37, 1321, 7723, 1413, 7919, 11035, 5739}},
-{8321, 17, 22173, {1, 1, 1, 15, 9, 55, 111, 1, 383, 439, 1037, 4055, 4243, 10443, 26737, 21039, 130847}},
-{8322, 17, 22197, {1, 1, 7, 9, 13, 25, 71, 137, 307, 717, 1009, 2477, 3861, 14145, 14549, 59589, 93401}},
-{8323, 17, 22207, {1, 1, 7, 5, 29, 63, 77, 49, 471, 267, 1457, 1743, 1915, 14793, 17899, 28011, 92183}},
-{8324, 17, 22210, {1, 3, 7, 7, 7, 41, 47, 251, 75, 749, 1915, 1015, 5869, 3211, 24097, 14349, 130571}},
-{8325, 17, 22216, {1, 1, 1, 1, 31, 63, 105, 83, 345, 147, 975, 135, 7299, 15801, 19311, 26143, 80293}},
-{8326, 17, 22234, {1, 1, 3, 1, 7, 1, 47, 45, 251, 635, 583, 3515, 5233, 6281, 7797, 37949, 75877}},
-{8327, 17, 22257, {1, 1, 3, 3, 5, 53, 99, 175, 155, 327, 1841, 211, 2811, 16099, 17255, 34253, 124141}},
-{8328, 17, 22264, {1, 3, 1, 3, 13, 27, 81, 217, 115, 245, 101, 1641, 29, 1441, 4829, 28399, 102303}},
-{8329, 17, 22278, {1, 3, 1, 5, 11, 55, 31, 91, 337, 203, 987, 977, 4929, 14933, 25149, 20493, 19783}},
-{8330, 17, 22284, {1, 1, 5, 9, 9, 37, 103, 211, 349, 165, 1421, 3015, 5133, 4615, 28173, 45787, 10711}},
-{8331, 17, 22287, {1, 1, 1, 1, 1, 17, 29, 117, 421, 651, 1617, 1677, 7841, 16303, 8843, 1321, 90701}},
-{8332, 17, 22299, {1, 1, 1, 15, 27, 23, 49, 195, 139, 319, 1277, 901, 63, 14677, 21815, 19497, 24883}},
-{8333, 17, 22301, {1, 3, 3, 13, 1, 23, 17, 189, 293, 765, 1503, 1485, 7427, 11807, 17629, 61739, 111365}},
-{8334, 17, 22308, {1, 1, 5, 5, 15, 41, 25, 53, 221, 449, 1597, 2763, 4119, 6319, 17509, 23493, 104707}},
-{8335, 17, 22337, {1, 3, 7, 11, 29, 21, 101, 197, 161, 457, 331, 3817, 5139, 14307, 23225, 55567, 62535}},
-{8336, 17, 22349, {1, 1, 7, 5, 9, 57, 39, 101, 5, 847, 1311, 313, 2877, 14811, 21969, 31741, 8075}},
-{8337, 17, 22350, {1, 3, 5, 3, 1, 11, 45, 163, 251, 775, 1031, 1957, 1631, 1691, 3191, 6255, 13037}},
-{8338, 17, 22357, {1, 1, 3, 13, 7, 11, 95, 97, 409, 835, 707, 1579, 2409, 9451, 15069, 62425, 106499}},
-{8339, 17, 22364, {1, 3, 3, 11, 5, 25, 23, 207, 429, 299, 537, 1467, 6309, 891, 15009, 56733, 60397}},
-{8340, 17, 22373, {1, 3, 5, 3, 29, 47, 95, 115, 207, 177, 543, 427, 145, 11169, 7441, 10911, 87413}},
-{8341, 17, 22377, {1, 3, 7, 11, 25, 53, 15, 225, 115, 295, 919, 39, 513, 9989, 11045, 24015, 102387}},
-{8342, 17, 22380, {1, 1, 7, 15, 13, 31, 103, 143, 357, 825, 183, 137, 2671, 9803, 14777, 48333, 79483}},
-{8343, 17, 22386, {1, 3, 5, 1, 25, 13, 65, 9, 461, 307, 1289, 1035, 7253, 14223, 16829, 23361, 84987}},
-{8344, 17, 22391, {1, 3, 5, 7, 5, 57, 47, 251, 5, 9, 965, 2883, 3105, 13931, 807, 31977, 119035}},
-{8345, 17, 22392, {1, 1, 3, 5, 3, 7, 55, 165, 3, 787, 1587, 989, 6049, 14021, 30789, 15283, 92851}},
-{8346, 17, 22411, {1, 1, 5, 5, 3, 17, 11, 167, 487, 885, 193, 3485, 8179, 9485, 24913, 40267, 70625}},
-{8347, 17, 22422, {1, 1, 7, 1, 27, 31, 9, 139, 73, 137, 783, 321, 691, 6157, 19905, 45525, 84877}},
-{8348, 17, 22425, {1, 3, 1, 9, 17, 39, 127, 177, 301, 579, 1065, 3899, 281, 9177, 16295, 51217, 120293}},
-{8349, 17, 22431, {1, 1, 7, 9, 31, 59, 17, 93, 247, 779, 847, 1183, 3453, 1073, 18597, 2655, 121633}},
-{8350, 17, 22438, {1, 1, 7, 1, 25, 43, 47, 253, 23, 999, 973, 1201, 1061, 5947, 5619, 36311, 1545}},
-{8351, 17, 22441, {1, 3, 5, 7, 11, 5, 103, 119, 229, 657, 1993, 1991, 1597, 13165, 19137, 7161, 83487}},
-{8352, 17, 22442, {1, 1, 1, 1, 11, 23, 105, 183, 467, 83, 899, 2447, 4949, 4171, 28943, 4829, 13033}},
-{8353, 17, 22449, {1, 3, 1, 7, 15, 7, 47, 215, 253, 109, 1975, 3337, 1553, 13575, 16835, 61525, 26423}},
-{8354, 17, 22452, {1, 1, 7, 1, 21, 17, 53, 79, 175, 267, 999, 249, 6177, 10453, 12475, 59801, 47351}},
-{8355, 17, 22461, {1, 3, 5, 11, 3, 57, 5, 193, 421, 799, 1833, 2635, 6537, 4669, 9597, 40661, 12113}},
-{8356, 17, 22467, {1, 1, 7, 11, 9, 11, 69, 103, 139, 167, 159, 2469, 703, 1519, 21553, 62875, 60449}},
-{8357, 17, 22479, {1, 1, 5, 3, 9, 11, 17, 183, 499, 301, 1275, 605, 7655, 12141, 7783, 39413, 116263}},
-{8358, 17, 22484, {1, 1, 1, 7, 31, 55, 23, 79, 49, 247, 761, 3573, 8187, 4879, 27379, 15725, 81415}},
-{8359, 17, 22487, {1, 3, 5, 5, 5, 49, 23, 205, 509, 383, 1165, 3839, 7663, 1539, 19967, 55901, 4351}},
-{8360, 17, 22493, {1, 1, 1, 11, 7, 15, 3, 159, 235, 735, 391, 2231, 5043, 9759, 4569, 35601, 71989}},
-{8361, 17, 22510, {1, 3, 3, 15, 23, 3, 49, 97, 99, 517, 1097, 3517, 1035, 2319, 27705, 25547, 101555}},
-{8362, 17, 22521, {1, 3, 7, 11, 27, 29, 33, 241, 205, 113, 291, 1993, 3277, 13155, 1039, 42367, 130477}},
-{8363, 17, 22533, {1, 1, 1, 3, 29, 19, 15, 159, 35, 153, 1177, 3011, 6271, 8203, 8971, 19183, 102871}},
-{8364, 17, 22534, {1, 1, 1, 5, 5, 51, 19, 175, 209, 895, 229, 2355, 499, 7877, 4935, 22737, 35587}},
-{8365, 17, 22543, {1, 3, 7, 11, 15, 9, 7, 113, 41, 835, 1593, 3933, 7165, 10959, 15487, 30019, 114505}},
-{8366, 17, 22548, {1, 1, 7, 5, 31, 21, 27, 11, 421, 165, 1605, 1859, 29, 13051, 3273, 3893, 56089}},
-{8367, 17, 22552, {1, 3, 5, 5, 17, 51, 55, 187, 401, 977, 95, 2617, 727, 9609, 5075, 48989, 120299}},
-{8368, 17, 22558, {1, 1, 5, 7, 21, 31, 127, 87, 379, 125, 247, 3607, 2555, 11873, 32535, 16677, 122273}},
-{8369, 17, 22561, {1, 1, 1, 5, 19, 21, 51, 185, 203, 145, 1073, 167, 235, 12753, 17315, 14683, 44101}},
-{8370, 17, 22562, {1, 3, 3, 1, 5, 61, 71, 17, 63, 151, 823, 17, 5315, 4861, 17279, 23049, 84971}},
-{8371, 17, 22568, {1, 3, 3, 5, 21, 63, 21, 235, 295, 467, 1661, 2487, 335, 6107, 28709, 55875, 129085}},
-{8372, 17, 22571, {1, 3, 3, 5, 1, 55, 35, 187, 5, 687, 1633, 2999, 4513, 10105, 15249, 22591, 102857}},
-{8373, 17, 22574, {1, 3, 1, 5, 19, 1, 113, 27, 261, 623, 831, 3011, 4091, 11967, 17191, 17433, 99925}},
-{8374, 17, 22581, {1, 3, 5, 5, 25, 59, 81, 249, 463, 523, 183, 3049, 3675, 2705, 28379, 1279, 25579}},
-{8375, 17, 22594, {1, 1, 3, 9, 19, 19, 71, 127, 189, 613, 647, 1449, 7755, 1415, 9067, 30683, 79703}},
-{8376, 17, 22603, {1, 1, 7, 1, 27, 33, 61, 135, 233, 633, 1969, 2245, 5841, 14069, 6497, 63617, 101483}},
-{8377, 17, 22605, {1, 3, 3, 9, 23, 3, 17, 163, 309, 741, 2023, 2647, 5847, 7871, 22311, 38377, 70663}},
-{8378, 17, 22606, {1, 3, 5, 15, 31, 33, 51, 243, 209, 273, 1305, 1599, 6115, 6249, 8639, 5903, 17215}},
-{8379, 17, 22623, {1, 1, 1, 1, 21, 11, 107, 185, 463, 435, 149, 3789, 6283, 1327, 20893, 10417, 78673}},
-{8380, 17, 22630, {1, 1, 1, 13, 5, 53, 121, 129, 493, 419, 1711, 2765, 7673, 8979, 25845, 62759, 9669}},
-{8381, 17, 22651, {1, 3, 5, 5, 1, 39, 123, 47, 449, 639, 625, 2355, 511, 1685, 1415, 32417, 76529}},
-{8382, 17, 22657, {1, 3, 1, 11, 1, 49, 67, 237, 203, 967, 1401, 2773, 4951, 13889, 14147, 41031, 71897}},
-{8383, 17, 22669, {1, 3, 5, 11, 13, 49, 17, 113, 315, 207, 1057, 3395, 6151, 2767, 16571, 1811, 66403}},
-{8384, 17, 22670, {1, 1, 7, 7, 29, 63, 49, 115, 327, 987, 1853, 3355, 8139, 2703, 30039, 51343, 86999}},
-{8385, 17, 22677, {1, 1, 3, 9, 1, 3, 45, 35, 509, 483, 159, 1795, 8023, 6989, 3755, 20887, 13587}},
-{8386, 17, 22682, {1, 1, 3, 7, 1, 27, 39, 159, 283, 843, 317, 3229, 2297, 15031, 22039, 21721, 70583}},
-{8387, 17, 22698, {1, 1, 3, 11, 9, 23, 1, 35, 79, 77, 1671, 2583, 647, 12313, 16271, 2959, 108389}},
-{8388, 17, 22712, {1, 1, 1, 7, 5, 55, 1, 233, 429, 231, 833, 1279, 7815, 1051, 30627, 4435, 25997}},
-{8389, 17, 22715, {1, 3, 1, 15, 19, 53, 9, 165, 307, 437, 551, 2477, 1841, 11799, 18477, 5871, 20065}},
-{8390, 17, 22729, {1, 1, 1, 1, 21, 5, 65, 41, 77, 909, 93, 751, 2973, 7341, 30427, 60075, 71457}},
-{8391, 17, 22732, {1, 1, 3, 11, 25, 51, 49, 63, 165, 263, 1915, 747, 8053, 6361, 4843, 20189, 110147}},
-{8392, 17, 22735, {1, 3, 1, 9, 29, 9, 45, 177, 415, 557, 1555, 2967, 1239, 8115, 12853, 19193, 73681}},
-{8393, 17, 22738, {1, 1, 5, 5, 11, 5, 51, 157, 325, 517, 1601, 3911, 1487, 13631, 7483, 61515, 48937}},
-{8394, 17, 22740, {1, 3, 7, 5, 29, 31, 107, 47, 437, 837, 1791, 477, 1717, 7, 25855, 48793, 16385}},
-{8395, 17, 22750, {1, 1, 1, 3, 29, 49, 31, 255, 233, 935, 1993, 125, 2255, 12785, 2807, 54697, 62591}},
-{8396, 17, 22753, {1, 3, 1, 7, 15, 13, 9, 245, 79, 289, 841, 253, 5259, 16123, 29189, 63837, 127915}},
-{8397, 17, 22760, {1, 3, 7, 15, 15, 55, 91, 103, 445, 289, 1471, 423, 3387, 15609, 19311, 28993, 23473}},
-{8398, 17, 22765, {1, 1, 3, 11, 31, 39, 69, 125, 115, 309, 397, 3417, 5693, 10301, 1489, 25955, 2699}},
-{8399, 17, 22768, {1, 3, 3, 5, 13, 21, 51, 207, 239, 311, 1601, 2925, 6285, 9597, 30579, 62957, 6153}},
-{8400, 17, 22778, {1, 1, 7, 1, 27, 21, 63, 143, 399, 971, 1385, 1875, 5143, 6423, 6223, 27009, 14237}},
-{8401, 17, 22785, {1, 3, 5, 1, 5, 59, 125, 133, 151, 997, 1315, 3007, 8173, 16289, 13409, 839, 103519}},
-{8402, 17, 22809, {1, 1, 1, 13, 7, 57, 83, 33, 191, 121, 939, 3927, 6089, 10083, 5903, 52229, 78325}},
-{8403, 17, 22810, {1, 1, 3, 5, 9, 61, 43, 107, 279, 135, 1109, 3779, 5305, 15333, 12217, 41257, 20265}},
-{8404, 17, 22812, {1, 3, 7, 1, 31, 59, 83, 43, 219, 119, 511, 2973, 4587, 10701, 30959, 21489, 124077}},
-{8405, 17, 22828, {1, 1, 7, 9, 17, 3, 59, 151, 281, 209, 1405, 173, 3589, 7679, 29803, 53947, 68291}},
-{8406, 17, 22840, {1, 1, 7, 7, 5, 19, 53, 91, 1, 513, 1495, 231, 3627, 1115, 16121, 12953, 108343}},
-{8407, 17, 22845, {1, 3, 1, 13, 17, 3, 35, 35, 211, 481, 2029, 1035, 3131, 5653, 18097, 10735, 102453}},
-{8408, 17, 22848, {1, 3, 1, 11, 29, 7, 121, 135, 51, 837, 681, 1497, 7435, 2215, 26527, 33029, 93241}},
-{8409, 17, 22857, {1, 3, 3, 15, 29, 43, 17, 243, 195, 315, 499, 3801, 5691, 12119, 4061, 51769, 80497}},
-{8410, 17, 22877, {1, 1, 3, 1, 11, 1, 113, 11, 387, 579, 275, 2995, 895, 11859, 4017, 1543, 11853}},
-{8411, 17, 22882, {1, 1, 7, 9, 31, 27, 63, 217, 97, 275, 435, 1355, 5205, 6587, 32589, 46485, 103587}},
-{8412, 17, 22887, {1, 3, 7, 3, 7, 19, 51, 41, 81, 261, 1909, 1475, 425, 3173, 5679, 34701, 34977}},
-{8413, 17, 22894, {1, 1, 7, 3, 27, 15, 35, 49, 387, 471, 1997, 3643, 2701, 11853, 21311, 36027, 104357}},
-{8414, 17, 22912, {1, 3, 1, 9, 5, 47, 73, 163, 309, 891, 229, 2433, 6715, 6721, 25233, 37043, 29367}},
-{8415, 17, 22930, {1, 1, 1, 7, 27, 15, 9, 185, 421, 597, 565, 143, 1531, 15585, 17057, 54309, 82915}},
-{8416, 17, 22936, {1, 1, 7, 1, 5, 43, 87, 61, 121, 341, 25, 3795, 7161, 11985, 32197, 789, 69543}},
-{8417, 17, 22939, {1, 3, 5, 13, 29, 39, 81, 39, 263, 729, 1833, 365, 1073, 9869, 1845, 52621, 5}},
-{8418, 17, 22957, {1, 1, 7, 7, 5, 33, 117, 11, 371, 161, 1303, 629, 2285, 5827, 32355, 43359, 115595}},
-{8419, 17, 22970, {1, 3, 5, 5, 13, 57, 63, 9, 243, 533, 173, 2197, 717, 13441, 22131, 17783, 3319}},
-{8420, 17, 22980, {1, 1, 7, 11, 15, 31, 87, 255, 183, 273, 805, 2347, 5881, 15401, 273, 17397, 41827}},
-{8421, 17, 22984, {1, 3, 1, 13, 7, 17, 121, 49, 47, 121, 333, 3629, 5337, 4117, 2735, 36581, 61345}},
-{8422, 17, 22992, {1, 3, 3, 11, 9, 7, 25, 223, 379, 119, 385, 1217, 4803, 2947, 30665, 7733, 77893}},
-{8423, 17, 22998, {1, 3, 3, 7, 31, 35, 127, 97, 5, 373, 7, 3035, 843, 5991, 9265, 34289, 42785}},
-{8424, 17, 23001, {1, 3, 7, 3, 27, 19, 95, 253, 349, 871, 807, 413, 5847, 10467, 4277, 12429, 75773}},
-{8425, 17, 23044, {1, 3, 3, 7, 21, 1, 79, 89, 219, 505, 41, 505, 5159, 12839, 3317, 49873, 73705}},
-{8426, 17, 23061, {1, 3, 1, 7, 21, 43, 121, 113, 477, 559, 1831, 3759, 3315, 6367, 7149, 16395, 44703}},
-{8427, 17, 23062, {1, 1, 1, 7, 13, 53, 35, 53, 489, 975, 631, 863, 3067, 1905, 21351, 14705, 80041}},
-{8428, 17, 23071, {1, 1, 1, 5, 13, 27, 121, 65, 351, 123, 1731, 367, 8061, 5229, 8537, 20897, 130373}},
-{8429, 17, 23075, {1, 1, 5, 11, 15, 63, 101, 107, 105, 619, 1771, 3549, 7191, 9083, 16827, 29639, 34219}},
-{8430, 17, 23089, {1, 3, 1, 9, 15, 13, 87, 157, 379, 433, 217, 815, 5079, 1797, 26707, 35165, 92305}},
-{8431, 17, 23090, {1, 1, 5, 13, 27, 35, 31, 65, 313, 629, 375, 1391, 5373, 3497, 7311, 23105, 45293}},
-{8432, 17, 23096, {1, 3, 1, 3, 5, 39, 91, 37, 401, 419, 949, 2431, 3685, 6671, 20789, 8597, 44215}},
-{8433, 17, 23101, {1, 1, 7, 11, 7, 15, 3, 181, 363, 913, 309, 2009, 3805, 6651, 27677, 37711, 40813}},
-{8434, 17, 23114, {1, 3, 5, 5, 17, 11, 47, 9, 27, 459, 773, 1403, 7069, 12651, 8163, 42425, 126697}},
-{8435, 17, 23121, {1, 3, 1, 3, 11, 21, 65, 103, 405, 843, 59, 3653, 1759, 5265, 401, 58019, 124999}},
-{8436, 17, 23124, {1, 1, 3, 7, 11, 25, 61, 211, 199, 849, 1835, 1181, 5003, 3873, 23743, 45451, 54901}},
-{8437, 17, 23127, {1, 3, 5, 3, 29, 25, 43, 199, 481, 991, 699, 3937, 7601, 1253, 24399, 6625, 93917}},
-{8438, 17, 23128, {1, 1, 7, 3, 29, 33, 33, 151, 3, 825, 743, 773, 7825, 8157, 22121, 50095, 16435}},
-{8439, 17, 23137, {1, 3, 1, 1, 27, 15, 81, 151, 271, 167, 1755, 1289, 7473, 8525, 12525, 63139, 48787}},
-{8440, 17, 23138, {1, 1, 7, 13, 27, 33, 87, 125, 211, 631, 149, 3451, 643, 6975, 2659, 12629, 33187}},
-{8441, 17, 23150, {1, 1, 3, 3, 5, 49, 99, 99, 85, 647, 351, 2829, 7005, 7283, 5857, 46157, 52061}},
-{8442, 17, 23155, {1, 1, 3, 5, 11, 37, 43, 129, 21, 639, 187, 2279, 8189, 12877, 28707, 7133, 93639}},
-{8443, 17, 23168, {1, 1, 3, 7, 19, 13, 35, 51, 77, 811, 1553, 2769, 763, 4965, 4643, 37639, 44229}},
-{8444, 17, 23173, {1, 3, 5, 15, 11, 29, 103, 203, 435, 1017, 531, 1453, 1407, 6569, 619, 52103, 45213}},
-{8445, 17, 23174, {1, 1, 7, 5, 25, 25, 47, 229, 201, 843, 473, 2637, 2265, 4627, 20013, 41217, 76095}},
-{8446, 17, 23195, {1, 3, 3, 15, 23, 61, 109, 31, 57, 595, 1303, 3915, 67, 8205, 3553, 9543, 103385}},
-{8447, 17, 23202, {1, 1, 3, 3, 21, 19, 21, 41, 137, 905, 2045, 491, 1783, 151, 20963, 38009, 735}},
-{8448, 17, 23225, {1, 1, 7, 11, 13, 33, 95, 251, 179, 211, 1687, 3189, 6213, 3905, 2117, 15153, 4855}},
-{8449, 17, 23226, {1, 1, 5, 3, 19, 9, 67, 243, 23, 611, 1007, 1317, 7303, 11065, 21157, 56677, 81683}},
-{8450, 17, 23239, {1, 1, 3, 5, 19, 41, 63, 129, 233, 15, 37, 1445, 1095, 11309, 30181, 49199, 85113}},
-{8451, 17, 23253, {1, 3, 7, 1, 21, 53, 83, 79, 155, 379, 773, 1823, 1003, 2787, 31107, 36115, 40987}},
-{8452, 17, 23263, {1, 3, 3, 5, 3, 19, 7, 247, 417, 573, 407, 3577, 6079, 10275, 29791, 35149, 102565}},
-{8453, 17, 23264, {1, 3, 3, 9, 21, 49, 57, 223, 125, 671, 655, 2995, 5849, 5355, 21171, 54857, 114841}},
-{8454, 17, 23281, {1, 3, 7, 3, 27, 23, 125, 103, 485, 955, 963, 1865, 2321, 2263, 32497, 47973, 122111}},
-{8455, 17, 23282, {1, 1, 3, 15, 3, 1, 37, 19, 287, 165, 1717, 851, 3619, 13623, 24295, 48253, 13143}},
-{8456, 17, 23288, {1, 1, 7, 9, 13, 59, 69, 97, 113, 163, 871, 1795, 2719, 13675, 11767, 23687, 65841}},
-{8457, 17, 23294, {1, 1, 5, 3, 21, 31, 41, 115, 469, 177, 137, 2129, 1385, 10835, 16471, 59411, 30795}},
-{8458, 17, 23302, {1, 1, 7, 7, 13, 45, 73, 119, 457, 673, 1481, 3735, 2675, 11413, 9069, 34741, 8757}},
-{8459, 17, 23311, {1, 3, 5, 3, 15, 9, 11, 191, 499, 51, 1963, 3957, 1341, 7129, 13491, 65369, 4339}},
-{8460, 17, 23320, {1, 3, 7, 1, 5, 45, 103, 209, 183, 205, 525, 2417, 847, 10801, 10699, 16723, 36421}},
-{8461, 17, 23325, {1, 3, 7, 13, 3, 57, 37, 75, 299, 359, 2017, 125, 6737, 4859, 18443, 20765, 40319}},
-{8462, 17, 23356, {1, 1, 3, 5, 5, 17, 43, 141, 31, 141, 1019, 1685, 6831, 9433, 31245, 29227, 64083}},
-{8463, 17, 23374, {1, 3, 1, 13, 25, 47, 107, 69, 459, 595, 1759, 3391, 1531, 15197, 25975, 16971, 70861}},
-{8464, 17, 23388, {1, 1, 3, 11, 3, 53, 63, 211, 69, 469, 1407, 1435, 2763, 917, 19943, 16591, 97101}},
-{8465, 17, 23402, {1, 3, 5, 13, 25, 41, 39, 61, 319, 809, 1109, 169, 3101, 8801, 21697, 50759, 130985}},
-{8466, 17, 23415, {1, 3, 1, 9, 23, 1, 11, 249, 243, 605, 1419, 269, 1601, 2063, 5365, 38077, 106161}},
-{8467, 17, 23421, {1, 1, 7, 7, 19, 55, 97, 155, 477, 845, 61, 263, 1337, 8857, 31611, 44417, 43111}},
-{8468, 17, 23426, {1, 3, 3, 15, 7, 63, 45, 239, 291, 279, 1875, 3769, 1571, 15857, 13335, 17209, 34399}},
-{8469, 17, 23443, {1, 1, 7, 11, 19, 19, 69, 111, 217, 927, 1643, 1077, 4763, 15893, 17491, 39737, 10705}},
-{8470, 17, 23446, {1, 1, 5, 11, 3, 3, 31, 199, 109, 403, 973, 3833, 2729, 7285, 26743, 53915, 96203}},
-{8471, 17, 23455, {1, 3, 3, 11, 9, 7, 19, 145, 495, 805, 381, 919, 1323, 4343, 15887, 5163, 68267}},
-{8472, 17, 23461, {1, 1, 3, 11, 15, 31, 27, 201, 251, 279, 1377, 1313, 7143, 9731, 10451, 63431, 31307}},
-{8473, 17, 23468, {1, 1, 7, 1, 1, 55, 35, 249, 133, 645, 425, 279, 6401, 11687, 751, 947, 21791}},
-{8474, 17, 23471, {1, 3, 5, 9, 5, 43, 89, 31, 419, 573, 1087, 2197, 3451, 2393, 6569, 4859, 36607}},
-{8475, 17, 23485, {1, 3, 5, 15, 25, 51, 11, 149, 483, 789, 661, 967, 3537, 15511, 26587, 29861, 120337}},
-{8476, 17, 23486, {1, 3, 5, 13, 21, 39, 75, 111, 57, 321, 1591, 381, 7399, 10807, 26651, 62489, 78341}},
-{8477, 17, 23488, {1, 3, 1, 13, 1, 1, 49, 137, 193, 967, 805, 221, 803, 11381, 27803, 51013, 10475}},
-{8478, 17, 23498, {1, 3, 7, 5, 3, 13, 47, 195, 123, 753, 397, 1203, 981, 12863, 20845, 36155, 19055}},
-{8479, 17, 23500, {1, 1, 1, 9, 9, 11, 53, 203, 3, 163, 1537, 2061, 941, 12629, 16053, 34881, 31489}},
-{8480, 17, 23515, {1, 1, 1, 15, 5, 23, 51, 197, 459, 21, 1989, 2529, 4267, 1505, 8951, 15777, 20493}},
-{8481, 17, 23521, {1, 1, 7, 3, 31, 55, 9, 55, 217, 695, 1563, 4077, 3207, 7029, 10881, 39581, 82511}},
-{8482, 17, 23527, {1, 3, 1, 5, 1, 11, 81, 1, 505, 631, 1093, 3655, 2085, 7349, 5009, 49381, 30527}},
-{8483, 17, 23534, {1, 1, 7, 1, 27, 51, 25, 235, 213, 59, 611, 3883, 2909, 6411, 19605, 49001, 114529}},
-{8484, 17, 23546, {1, 3, 5, 3, 25, 29, 19, 137, 199, 681, 1625, 2711, 4873, 14677, 9767, 30441, 54673}},
-{8485, 17, 23559, {1, 1, 1, 9, 27, 43, 109, 161, 139, 675, 741, 2839, 1425, 5701, 19897, 12787, 33069}},
-{8486, 17, 23560, {1, 3, 5, 11, 21, 19, 77, 107, 197, 591, 1899, 1311, 3347, 6369, 26891, 3771, 32455}},
-{8487, 17, 23566, {1, 1, 7, 15, 31, 13, 109, 69, 207, 349, 249, 971, 7891, 10919, 31579, 38453, 124601}},
-{8488, 17, 23584, {1, 3, 5, 5, 27, 61, 67, 193, 53, 259, 1729, 4033, 2637, 8217, 22351, 4001, 118527}},
-{8489, 17, 23587, {1, 1, 3, 5, 9, 45, 55, 73, 189, 131, 1947, 1889, 837, 4085, 10393, 64359, 1037}},
-{8490, 17, 23594, {1, 3, 7, 3, 13, 51, 55, 37, 335, 939, 35, 461, 5057, 2595, 3305, 58823, 3941}},
-{8491, 17, 23602, {1, 1, 7, 11, 7, 3, 121, 139, 241, 477, 615, 2707, 5391, 7611, 11563, 41083, 16719}},
-{8492, 17, 23607, {1, 3, 3, 15, 27, 55, 13, 221, 195, 543, 215, 4035, 1647, 8111, 26425, 43571, 79893}},
-{8493, 17, 23616, {1, 1, 1, 5, 31, 5, 35, 145, 481, 339, 1951, 2155, 1309, 9851, 31505, 37371, 21247}},
-{8494, 17, 23621, {1, 1, 7, 9, 7, 5, 73, 119, 3, 741, 1351, 2855, 2207, 1465, 12047, 13507, 129173}},
-{8495, 17, 23631, {1, 1, 7, 13, 5, 57, 119, 63, 367, 327, 1257, 3191, 6929, 9593, 16565, 54397, 100305}},
-{8496, 17, 23634, {1, 3, 1, 11, 9, 1, 85, 53, 65, 945, 17, 1963, 4819, 16173, 11669, 53579, 33701}},
-{8497, 17, 23636, {1, 1, 3, 15, 25, 27, 3, 25, 23, 429, 197, 2717, 6107, 6719, 12457, 31793, 78647}},
-{8498, 17, 23649, {1, 1, 3, 1, 7, 63, 111, 235, 299, 91, 369, 1423, 7083, 4229, 18535, 33793, 19943}},
-{8499, 17, 23652, {1, 1, 7, 13, 9, 11, 123, 9, 169, 895, 1989, 1047, 6139, 11773, 19381, 9593, 14809}},
-{8500, 17, 23679, {1, 3, 1, 3, 29, 31, 63, 91, 59, 391, 1695, 2459, 3301, 5615, 3425, 8029, 16069}},
-{8501, 17, 23686, {1, 1, 7, 1, 25, 25, 79, 49, 131, 695, 987, 2911, 1109, 8237, 18227, 37287, 22443}},
-{8502, 17, 23697, {1, 3, 3, 3, 25, 21, 33, 207, 187, 381, 129, 445, 2967, 5119, 18777, 14849, 97115}},
-{8503, 17, 23703, {1, 1, 7, 13, 19, 9, 93, 185, 391, 579, 1509, 3245, 3921, 9473, 4795, 6685, 49549}},
-{8504, 17, 23714, {1, 1, 5, 11, 1, 49, 57, 127, 363, 811, 1383, 2869, 7625, 15177, 2581, 64253, 53677}},
-{8505, 17, 23719, {1, 1, 7, 3, 7, 27, 73, 187, 31, 1011, 1013, 3269, 6625, 5001, 20805, 13331, 93725}},
-{8506, 17, 23723, {1, 3, 7, 1, 23, 61, 123, 9, 141, 113, 1009, 3713, 4947, 9929, 24125, 1101, 104249}},
-{8507, 17, 23726, {1, 3, 7, 3, 23, 17, 25, 187, 189, 875, 1435, 163, 4197, 6619, 29031, 23117, 45347}},
-{8508, 17, 23728, {1, 1, 5, 7, 11, 17, 9, 55, 117, 223, 417, 3993, 1843, 5817, 20435, 56705, 98337}},
-{8509, 17, 23733, {1, 1, 7, 3, 21, 59, 3, 77, 297, 61, 407, 1603, 3209, 1611, 30185, 50275, 56139}},
-{8510, 17, 23740, {1, 1, 1, 5, 31, 3, 101, 167, 367, 543, 339, 1885, 7855, 9989, 30969, 6735, 108123}},
-{8511, 17, 23751, {1, 1, 3, 9, 27, 63, 9, 79, 335, 351, 673, 3107, 3955, 1799, 16879, 57631, 109073}},
-{8512, 17, 23755, {1, 1, 1, 3, 27, 17, 107, 115, 155, 371, 379, 2837, 6213, 2663, 1101, 451, 69517}},
-{8513, 17, 23765, {1, 1, 3, 9, 13, 3, 55, 9, 449, 43, 1011, 3281, 5311, 223, 10715, 6639, 79949}},
-{8514, 17, 23766, {1, 3, 3, 11, 23, 9, 43, 185, 271, 1005, 1041, 2633, 377, 4247, 10417, 51903, 19239}},
-{8515, 17, 23769, {1, 3, 1, 9, 15, 39, 115, 233, 33, 425, 1979, 583, 1901, 8943, 1527, 56065, 50159}},
-{8516, 17, 23779, {1, 1, 3, 1, 13, 1, 105, 149, 13, 625, 671, 1811, 3701, 241, 27357, 25835, 127265}},
-{8517, 17, 23794, {1, 3, 1, 9, 11, 23, 107, 197, 21, 589, 1065, 2591, 1163, 15013, 8931, 6355, 87079}},
-{8518, 17, 23796, {1, 3, 5, 3, 17, 5, 121, 61, 99, 987, 2033, 2237, 2299, 14689, 19785, 9599, 101035}},
-{8519, 17, 23803, {1, 1, 1, 1, 17, 25, 5, 97, 55, 75, 1419, 2793, 7215, 3185, 7029, 23023, 89089}},
-{8520, 17, 23813, {1, 3, 3, 3, 11, 57, 103, 191, 405, 463, 1421, 253, 6069, 10905, 18193, 719, 17337}},
-{8521, 17, 23820, {1, 3, 5, 11, 23, 37, 39, 169, 295, 527, 1671, 3913, 6057, 689, 27719, 47245, 95895}},
-{8522, 17, 23841, {1, 3, 7, 5, 13, 9, 43, 189, 411, 155, 559, 3701, 1623, 2401, 10359, 22675, 41897}},
-{8523, 17, 23853, {1, 1, 1, 11, 17, 55, 47, 101, 357, 669, 857, 2745, 6425, 11839, 13095, 10757, 52383}},
-{8524, 17, 23861, {1, 1, 7, 5, 11, 13, 53, 151, 93, 455, 133, 3353, 1417, 7917, 12913, 2615, 34281}},
-{8525, 17, 23862, {1, 1, 3, 5, 29, 57, 43, 35, 203, 423, 311, 3133, 1757, 1291, 2019, 3115, 126939}},
-{8526, 17, 23873, {1, 1, 3, 11, 9, 43, 119, 95, 135, 351, 1865, 2821, 717, 6275, 19713, 42315, 97935}},
-{8527, 17, 23876, {1, 3, 7, 7, 31, 51, 7, 29, 405, 31, 1765, 3231, 1315, 1307, 26469, 62033, 35619}},
-{8528, 17, 23897, {1, 1, 5, 7, 5, 17, 49, 137, 501, 631, 1401, 2851, 6971, 14721, 4329, 26483, 120007}},
-{8529, 17, 23898, {1, 1, 5, 13, 21, 19, 95, 93, 125, 331, 1797, 1653, 1891, 11081, 30989, 24671, 95421}},
-{8530, 17, 23903, {1, 3, 3, 11, 13, 29, 61, 157, 165, 39, 661, 89, 637, 1397, 12561, 62399, 129107}},
-{8531, 17, 23904, {1, 3, 1, 15, 13, 19, 5, 115, 345, 903, 531, 4069, 6775, 7433, 569, 21779, 13271}},
-{8532, 17, 23910, {1, 3, 3, 9, 5, 53, 17, 115, 67, 939, 1907, 3979, 4311, 3573, 857, 34931, 112397}},
-{8533, 17, 23931, {1, 3, 7, 11, 9, 47, 83, 85, 277, 219, 1701, 3013, 3037, 3473, 3797, 40713, 118573}},
-{8534, 17, 23933, {1, 1, 3, 13, 25, 33, 117, 115, 179, 119, 487, 3213, 2873, 17, 20865, 20043, 64381}},
-{8535, 17, 23934, {1, 1, 1, 3, 1, 45, 73, 103, 75, 579, 981, 2449, 2141, 8697, 22995, 59693, 104461}},
-{8536, 17, 23943, {1, 3, 1, 1, 29, 9, 9, 201, 55, 389, 1069, 2057, 4149, 9217, 10753, 7889, 95849}},
-{8537, 17, 23952, {1, 3, 7, 9, 27, 39, 19, 223, 7, 253, 55, 503, 3339, 6049, 32603, 34807, 115403}},
-{8538, 17, 23955, {1, 1, 5, 3, 13, 21, 67, 87, 205, 309, 1371, 1579, 281, 16135, 28403, 25951, 24109}},
-{8539, 17, 23962, {1, 3, 1, 3, 17, 21, 49, 77, 393, 943, 1701, 2661, 5173, 12875, 2731, 40531, 19301}},
-{8540, 17, 23971, {1, 3, 1, 5, 23, 29, 61, 161, 373, 389, 1699, 359, 2513, 4717, 30397, 24395, 20881}},
-{8541, 17, 23978, {1, 3, 5, 5, 29, 3, 115, 251, 277, 487, 7, 3301, 7945, 14233, 20497, 62035, 21537}},
-{8542, 17, 23998, {1, 1, 1, 9, 7, 59, 23, 85, 367, 109, 1761, 4011, 6535, 8263, 2081, 63647, 69807}},
-{8543, 17, 24003, {1, 1, 7, 11, 21, 41, 29, 219, 271, 617, 929, 407, 2899, 14299, 7645, 44815, 58817}},
-{8544, 17, 24009, {1, 3, 5, 7, 11, 29, 119, 33, 261, 571, 2013, 3327, 2181, 12767, 93, 2437, 76533}},
-{8545, 17, 24017, {1, 1, 7, 13, 17, 39, 55, 203, 261, 917, 967, 3651, 7235, 13751, 14439, 7591, 96553}},
-{8546, 17, 24045, {1, 1, 1, 1, 11, 39, 19, 21, 125, 93, 1773, 1155, 6213, 7173, 9057, 6219, 4643}},
-{8547, 17, 24046, {1, 3, 1, 5, 1, 31, 55, 143, 425, 539, 61, 3377, 7647, 257, 15007, 24511, 8707}},
-{8548, 17, 24060, {1, 3, 3, 11, 27, 51, 103, 197, 427, 139, 181, 1169, 3123, 11803, 5285, 1321, 62267}},
-{8549, 17, 24064, {1, 3, 5, 9, 11, 3, 13, 149, 197, 37, 31, 927, 3313, 16149, 14209, 60177, 46525}},
-{8550, 17, 24076, {1, 1, 5, 13, 15, 29, 103, 49, 355, 797, 1253, 1833, 621, 3877, 9981, 49207, 91035}},
-{8551, 17, 24079, {1, 1, 3, 3, 13, 19, 27, 51, 151, 275, 35, 3755, 7511, 14197, 26141, 43765, 104327}},
-{8552, 17, 24087, {1, 3, 5, 15, 23, 47, 101, 213, 97, 957, 831, 1533, 7913, 15763, 29717, 60425, 38559}},
-{8553, 17, 24094, {1, 1, 7, 9, 29, 31, 49, 245, 361, 299, 151, 2969, 1487, 1761, 11697, 4043, 100909}},
-{8554, 17, 24100, {1, 1, 1, 3, 17, 49, 99, 159, 3, 525, 1527, 3435, 5113, 459, 13341, 54103, 85813}},
-{8555, 17, 24118, {1, 3, 1, 1, 5, 59, 35, 75, 107, 91, 1621, 3261, 619, 3271, 10813, 29857, 1547}},
-{8556, 17, 24121, {1, 1, 5, 9, 9, 33, 85, 245, 39, 879, 1621, 2587, 3825, 12939, 30113, 24611, 68491}},
-{8557, 17, 24132, {1, 3, 1, 3, 9, 39, 93, 241, 307, 237, 3, 1763, 7729, 9257, 31911, 32591, 77333}},
-{8558, 17, 24147, {1, 3, 1, 3, 27, 7, 51, 121, 317, 361, 1027, 95, 7035, 3097, 21007, 38311, 88287}},
-{8559, 17, 24165, {1, 3, 7, 3, 19, 3, 111, 115, 339, 793, 1571, 3101, 1911, 14929, 12841, 45871, 119905}},
-{8560, 17, 24172, {1, 1, 5, 7, 31, 61, 37, 143, 279, 941, 1215, 2411, 7617, 1657, 10189, 19139, 6307}},
-{8561, 17, 24177, {1, 1, 3, 9, 21, 35, 13, 157, 187, 79, 689, 1085, 37, 4549, 5901, 15321, 61627}},
-{8562, 17, 24184, {1, 3, 1, 13, 15, 39, 21, 231, 39, 327, 801, 2321, 587, 1877, 3489, 54467, 95773}},
-{8563, 17, 24187, {1, 1, 5, 7, 1, 9, 53, 1, 243, 365, 789, 3833, 317, 10697, 26567, 65187, 22507}},
-{8564, 17, 24213, {1, 3, 3, 7, 9, 41, 31, 135, 425, 939, 15, 2043, 6593, 7651, 25467, 62549, 35847}},
-{8565, 17, 24217, {1, 1, 1, 7, 15, 23, 19, 57, 421, 25, 1037, 3055, 6173, 12451, 485, 54567, 109561}},
-{8566, 17, 24223, {1, 3, 5, 1, 3, 29, 67, 233, 157, 677, 1711, 513, 4673, 2895, 1983, 31075, 1861}},
-{8567, 17, 24230, {1, 1, 1, 1, 7, 39, 115, 251, 275, 791, 15, 1685, 6835, 14685, 12607, 28213, 121475}},
-{8568, 17, 24234, {1, 1, 5, 5, 13, 11, 103, 93, 489, 709, 1339, 2407, 1663, 10195, 3135, 15531, 88427}},
-{8569, 17, 24241, {1, 1, 7, 7, 17, 1, 123, 143, 31, 721, 1739, 2273, 3785, 10261, 14741, 52573, 113677}},
-{8570, 17, 24248, {1, 3, 7, 3, 9, 21, 77, 13, 241, 429, 165, 3399, 7543, 2633, 21129, 13537, 84473}},
-{8571, 17, 24259, {1, 1, 1, 11, 21, 33, 125, 123, 189, 337, 163, 3727, 2101, 14113, 1719, 46017, 68601}},
-{8572, 17, 24262, {1, 1, 7, 9, 9, 53, 101, 111, 125, 605, 1419, 3901, 1769, 4585, 20063, 20857, 21901}},
-{8573, 17, 24271, {1, 3, 7, 11, 1, 19, 51, 7, 457, 119, 871, 3847, 57, 11437, 28763, 58831, 675}},
-{8574, 17, 24279, {1, 3, 1, 15, 25, 63, 69, 25, 405, 823, 1701, 2441, 7561, 8679, 31643, 29325, 25563}},
-{8575, 17, 24286, {1, 1, 3, 9, 15, 5, 89, 13, 73, 951, 959, 2693, 4565, 13095, 991, 12419, 8267}},
-{8576, 17, 24289, {1, 1, 7, 1, 15, 1, 119, 223, 213, 585, 1047, 2623, 4141, 2043, 1583, 59155, 5133}},
-{8577, 17, 24295, {1, 3, 3, 3, 17, 37, 81, 233, 87, 843, 1597, 1251, 4713, 10813, 24357, 48499, 84465}},
-{8578, 17, 24296, {1, 1, 1, 1, 11, 55, 125, 5, 255, 809, 543, 2351, 7079, 7801, 29247, 23937, 97405}},
-{8579, 17, 24299, {1, 3, 3, 5, 17, 55, 87, 245, 371, 679, 943, 655, 5857, 261, 28229, 22519, 35191}},
-{8580, 17, 24314, {1, 1, 7, 15, 9, 49, 25, 155, 13, 893, 1303, 2317, 2903, 15601, 1433, 20397, 70125}},
-{8581, 17, 24336, {1, 3, 5, 3, 11, 47, 99, 63, 253, 95, 1023, 397, 4307, 4771, 17027, 19833, 18269}},
-{8582, 17, 24342, {1, 3, 3, 7, 25, 17, 69, 119, 475, 575, 1637, 3785, 649, 11557, 22457, 38633, 96153}},
-{8583, 17, 24346, {1, 1, 1, 5, 31, 55, 85, 83, 307, 201, 1543, 727, 977, 15779, 21907, 31025, 38969}},
-{8584, 17, 24357, {1, 3, 5, 1, 7, 53, 107, 239, 341, 237, 1567, 2717, 3197, 12419, 23733, 42119, 86619}},
-{8585, 17, 24367, {1, 1, 5, 13, 3, 7, 105, 95, 201, 953, 781, 2043, 5263, 13427, 10303, 60027, 19297}},
-{8586, 17, 24370, {1, 1, 5, 15, 25, 51, 5, 77, 165, 297, 1281, 1635, 4139, 11569, 32325, 23135, 27013}},
-{8587, 17, 24372, {1, 1, 3, 9, 3, 59, 107, 137, 251, 715, 1477, 511, 5629, 12205, 7541, 62559, 4253}},
-{8588, 17, 24387, {1, 1, 7, 11, 31, 29, 7, 251, 119, 547, 1179, 3063, 1625, 8941, 30515, 13601, 72741}},
-{8589, 17, 24389, {1, 3, 7, 13, 27, 43, 31, 43, 465, 355, 1063, 2305, 1425, 11963, 27327, 53335, 127517}},
-{8590, 17, 24402, {1, 3, 1, 3, 21, 17, 53, 171, 269, 783, 349, 1879, 575, 13537, 16931, 61171, 23499}},
-{8591, 17, 24414, {1, 3, 5, 3, 11, 5, 121, 227, 237, 841, 431, 3209, 3241, 6071, 23465, 39533, 102391}},
-{8592, 17, 24420, {1, 3, 5, 11, 9, 1, 59, 143, 181, 869, 1859, 1543, 6419, 13305, 29075, 28051, 105799}},
-{8593, 17, 24435, {1, 1, 7, 13, 31, 1, 105, 169, 67, 693, 1667, 2181, 4127, 4605, 3701, 36467, 19631}},
-{8594, 17, 24437, {1, 1, 7, 5, 31, 15, 119, 161, 55, 549, 1195, 4051, 1923, 2497, 8289, 60393, 96181}},
-{8595, 17, 24442, {1, 1, 3, 3, 5, 43, 13, 123, 469, 603, 2047, 2347, 815, 3457, 7503, 25261, 71951}},
-{8596, 17, 24444, {1, 1, 7, 3, 13, 25, 85, 141, 497, 405, 957, 1407, 2075, 12445, 6675, 9993, 40429}},
-{8597, 17, 24447, {1, 1, 5, 13, 29, 43, 99, 113, 307, 1003, 859, 723, 7513, 12249, 12653, 57685, 89551}},
-{8598, 17, 24468, {1, 3, 7, 3, 11, 3, 9, 141, 501, 113, 69, 2285, 4525, 9049, 24765, 11585, 53787}},
-{8599, 17, 24475, {1, 1, 3, 1, 25, 41, 103, 159, 215, 871, 77, 1849, 609, 15877, 32515, 22931, 11933}},
-{8600, 17, 24484, {1, 1, 5, 11, 3, 27, 27, 111, 479, 861, 1041, 3777, 4443, 3095, 30379, 6293, 30823}},
-{8601, 17, 24493, {1, 3, 5, 5, 27, 45, 9, 25, 451, 845, 1153, 897, 325, 15679, 30151, 37695, 54593}},
-{8602, 17, 24494, {1, 3, 7, 1, 15, 47, 87, 135, 87, 567, 221, 3173, 769, 8173, 2957, 51287, 20961}},
-{8603, 17, 24496, {1, 3, 1, 9, 3, 33, 1, 71, 147, 983, 1485, 3531, 213, 2353, 28269, 49353, 88343}},
-{8604, 17, 24514, {1, 1, 3, 11, 11, 63, 109, 255, 35, 127, 1777, 791, 1379, 9539, 4915, 21593, 98901}},
-{8605, 17, 24519, {1, 1, 7, 5, 3, 47, 93, 219, 381, 963, 359, 2461, 7629, 2803, 17345, 54311, 79057}},
-{8606, 17, 24533, {1, 3, 5, 13, 13, 21, 1, 65, 455, 203, 29, 3717, 4495, 1285, 25289, 38597, 42431}},
-{8607, 17, 24538, {1, 1, 3, 3, 27, 57, 7, 171, 65, 469, 1921, 3855, 1637, 5517, 14907, 48239, 117573}},
-{8608, 17, 24559, {1, 3, 5, 1, 11, 35, 105, 251, 19, 219, 1191, 2177, 7885, 8399, 30527, 61415, 122215}},
-{8609, 17, 24568, {1, 3, 5, 5, 21, 25, 59, 193, 509, 147, 1805, 561, 3505, 9639, 14221, 31, 99261}},
-{8610, 17, 24573, {1, 1, 5, 13, 31, 23, 35, 143, 367, 385, 1335, 2497, 3573, 8113, 16661, 16147, 8763}},
-{8611, 17, 24577, {1, 1, 7, 13, 15, 27, 35, 15, 7, 539, 633, 1145, 2267, 11527, 20975, 16689, 58227}},
-{8612, 17, 24587, {1, 1, 1, 15, 9, 11, 51, 121, 381, 331, 1445, 187, 519, 15827, 27611, 32891, 113671}},
-{8613, 17, 24592, {1, 3, 1, 5, 19, 3, 77, 67, 107, 105, 1025, 3229, 6869, 5717, 4227, 28489, 59759}},
-{8614, 17, 24601, {1, 1, 5, 15, 25, 23, 7, 25, 103, 733, 525, 453, 6467, 2901, 7197, 33267, 68177}},
-{8615, 17, 24602, {1, 1, 5, 7, 27, 27, 41, 93, 449, 733, 571, 411, 1709, 9557, 549, 5925, 24123}},
-{8616, 17, 24608, {1, 1, 7, 5, 31, 57, 119, 227, 105, 533, 717, 3357, 2495, 6467, 7211, 38169, 44603}},
-{8617, 17, 24645, {1, 1, 5, 7, 29, 9, 125, 241, 471, 571, 1271, 2911, 8087, 5067, 31139, 39681, 28579}},
-{8618, 17, 24650, {1, 3, 5, 11, 25, 53, 109, 35, 183, 109, 1961, 1681, 7773, 6935, 28049, 37279, 96829}},
-{8619, 17, 24657, {1, 1, 1, 11, 1, 17, 47, 245, 231, 747, 1395, 1635, 5129, 3165, 627, 34463, 38967}},
-{8620, 17, 24664, {1, 3, 5, 1, 9, 41, 25, 215, 251, 525, 1399, 3405, 7399, 11041, 5599, 51167, 38697}},
-{8621, 17, 24670, {1, 3, 3, 13, 11, 15, 121, 95, 139, 611, 633, 3941, 2619, 15123, 28535, 64823, 17527}},
-{8622, 17, 24673, {1, 3, 7, 13, 21, 53, 65, 175, 81, 5, 699, 1525, 7397, 2465, 4479, 58225, 26387}},
-{8623, 17, 24676, {1, 1, 5, 7, 9, 31, 31, 149, 359, 613, 397, 153, 4861, 8195, 22969, 26003, 124423}},
-{8624, 17, 24680, {1, 3, 1, 13, 27, 17, 107, 27, 19, 13, 1481, 573, 7701, 6273, 30255, 16125, 11809}},
-{8625, 17, 24686, {1, 3, 1, 9, 15, 1, 45, 105, 287, 901, 667, 3197, 3493, 12259, 1511, 63361, 94257}},
-{8626, 17, 24700, {1, 3, 1, 3, 25, 53, 19, 87, 365, 585, 1569, 1731, 3747, 11985, 22673, 17767, 113779}},
-{8627, 17, 24704, {1, 3, 3, 9, 7, 21, 103, 201, 501, 149, 1939, 3111, 4739, 8389, 27127, 55889, 54487}},
-{8628, 17, 24714, {1, 3, 5, 7, 25, 53, 75, 57, 19, 505, 849, 2631, 6999, 11269, 24541, 17695, 97671}},
-{8629, 17, 24728, {1, 1, 7, 15, 5, 51, 123, 93, 445, 379, 1729, 2747, 5821, 10779, 29335, 57419, 109339}},
-{8630, 17, 24731, {1, 1, 7, 3, 7, 57, 117, 65, 297, 891, 487, 1535, 2361, 10457, 30759, 34571, 129949}},
-{8631, 17, 24733, {1, 3, 5, 5, 17, 51, 27, 103, 55, 925, 947, 1237, 1629, 12687, 14775, 49627, 100939}},
-{8632, 17, 24747, {1, 3, 3, 15, 1, 11, 75, 177, 399, 55, 1705, 1165, 7525, 8909, 13071, 60703, 11561}},
-{8633, 17, 24749, {1, 1, 1, 7, 13, 29, 23, 65, 279, 853, 637, 3947, 4099, 6465, 7061, 50417, 35015}},
-{8634, 17, 24750, {1, 1, 3, 3, 15, 11, 111, 169, 135, 279, 1941, 3035, 3027, 6813, 13363, 20387, 3257}},
-{8635, 17, 24764, {1, 3, 3, 11, 3, 5, 95, 181, 405, 313, 39, 1503, 2443, 3221, 17021, 23485, 43909}},
-{8636, 17, 24782, {1, 1, 1, 3, 17, 63, 27, 247, 441, 533, 449, 3845, 4021, 14269, 31477, 7013, 37473}},
-{8637, 17, 24784, {1, 1, 5, 13, 29, 39, 41, 95, 417, 21, 685, 609, 5787, 13145, 32677, 6121, 50919}},
-{8638, 17, 24793, {1, 1, 5, 3, 17, 5, 93, 143, 171, 681, 1143, 2875, 805, 15823, 29649, 63327, 12041}},
-{8639, 17, 24794, {1, 1, 1, 11, 3, 53, 123, 105, 59, 485, 1799, 2939, 657, 2485, 29563, 36221, 89095}},
-{8640, 17, 24810, {1, 1, 5, 5, 15, 13, 127, 87, 211, 579, 175, 793, 6895, 9051, 17681, 28831, 31783}},
-{8641, 17, 24817, {1, 3, 7, 5, 11, 37, 9, 219, 453, 697, 139, 335, 6411, 8495, 4203, 29065, 114837}},
-{8642, 17, 24820, {1, 1, 3, 5, 31, 25, 89, 215, 249, 271, 1731, 3133, 3947, 10227, 9679, 51303, 82833}},
-{8643, 17, 24823, {1, 3, 5, 1, 31, 15, 7, 131, 369, 757, 1963, 3223, 35, 13967, 31807, 5093, 113743}},
-{8644, 17, 24832, {1, 1, 7, 3, 15, 23, 21, 173, 295, 929, 1137, 3943, 1985, 13015, 8523, 59117, 127}},
-{8645, 17, 24855, {1, 3, 7, 1, 31, 1, 115, 229, 345, 859, 1757, 1835, 7491, 4545, 1483, 40149, 122321}},
-{8646, 17, 24859, {1, 1, 1, 3, 13, 5, 3, 133, 177, 47, 1515, 17, 5663, 3185, 2775, 31389, 37409}},
-{8647, 17, 24862, {1, 1, 3, 3, 31, 3, 43, 137, 185, 803, 709, 391, 3513, 8117, 32593, 46593, 61037}},
-{8648, 17, 24877, {1, 1, 1, 7, 29, 27, 13, 35, 61, 961, 777, 2725, 7379, 7053, 21781, 60285, 49221}},
-{8649, 17, 24890, {1, 3, 7, 15, 7, 7, 15, 123, 109, 97, 361, 791, 4773, 8111, 4319, 13981, 92505}},
-{8650, 17, 24900, {1, 1, 3, 11, 21, 33, 113, 221, 453, 981, 341, 4041, 5129, 5981, 11051, 17243, 19023}},
-{8651, 17, 24904, {1, 3, 1, 1, 19, 7, 75, 213, 467, 221, 1829, 1275, 5729, 6843, 23855, 44805, 89269}},
-{8652, 17, 24909, {1, 1, 3, 7, 5, 29, 39, 125, 147, 329, 1485, 2793, 2329, 14979, 18395, 37951, 58699}},
-{8653, 17, 24910, {1, 3, 1, 3, 11, 37, 117, 189, 103, 381, 39, 31, 5205, 5601, 17127, 49073, 121417}},
-{8654, 17, 24915, {1, 3, 3, 13, 23, 49, 57, 187, 441, 189, 349, 2559, 3313, 1321, 7731, 57309, 80195}},
-{8655, 17, 24922, {1, 3, 7, 1, 17, 9, 21, 15, 447, 333, 959, 3471, 5301, 8573, 9761, 23183, 57997}},
-{8656, 17, 24937, {1, 3, 1, 9, 19, 1, 101, 71, 325, 309, 85, 2097, 8003, 12249, 1887, 2097, 68375}},
-{8657, 17, 24945, {1, 1, 7, 7, 11, 39, 85, 241, 293, 205, 387, 1539, 6583, 1395, 8869, 48843, 49983}},
-{8658, 17, 24962, {1, 3, 7, 13, 11, 23, 83, 125, 55, 429, 169, 1893, 4657, 643, 3405, 9943, 128753}},
-{8659, 17, 24964, {1, 1, 3, 11, 19, 43, 13, 171, 495, 117, 437, 3697, 6723, 6199, 1859, 39637, 111499}},
-{8660, 17, 24991, {1, 1, 1, 5, 1, 31, 83, 199, 129, 941, 1637, 1997, 5011, 14957, 32427, 60797, 4989}},
-{8661, 17, 24992, {1, 3, 3, 3, 5, 61, 33, 225, 315, 157, 1709, 807, 7809, 11063, 319, 20901, 73599}},
-{8662, 17, 24995, {1, 1, 7, 3, 27, 3, 1, 173, 125, 769, 1203, 3357, 4899, 13115, 7081, 42459, 18525}},
-{8663, 17, 25001, {1, 1, 7, 9, 9, 27, 43, 115, 229, 867, 661, 1825, 2883, 4285, 22393, 65141, 24699}},
-{8664, 17, 25009, {1, 1, 3, 7, 5, 9, 93, 47, 33, 823, 309, 2977, 5791, 9177, 27645, 35683, 57455}},
-{8665, 17, 25019, {1, 1, 5, 7, 9, 53, 9, 77, 499, 1023, 917, 209, 7311, 249, 773, 18303, 41447}},
-{8666, 17, 25021, {1, 1, 3, 5, 7, 9, 33, 73, 325, 369, 1657, 2257, 2893, 13911, 10797, 21055, 103511}},
-{8667, 17, 25029, {1, 3, 1, 3, 21, 31, 125, 29, 149, 513, 979, 2271, 989, 9541, 4179, 13215, 71369}},
-{8668, 17, 25034, {1, 1, 7, 7, 19, 41, 39, 165, 59, 79, 137, 3479, 3389, 6635, 21467, 51073, 20765}},
-{8669, 17, 25036, {1, 3, 3, 5, 7, 13, 109, 53, 335, 627, 339, 3825, 287, 6077, 11319, 2377, 112693}},
-{8670, 17, 25039, {1, 3, 3, 1, 3, 57, 9, 47, 437, 717, 563, 1219, 6191, 9081, 21533, 2651, 17275}},
-{8671, 17, 25057, {1, 1, 1, 5, 21, 9, 109, 109, 339, 947, 1699, 1487, 6477, 12601, 12327, 39427, 80937}},
-{8672, 17, 25063, {1, 1, 7, 9, 1, 5, 55, 43, 95, 733, 1151, 3657, 2119, 11947, 21279, 21581, 22053}},
-{8673, 17, 25064, {1, 3, 5, 11, 7, 9, 97, 149, 55, 523, 1911, 1389, 5343, 5533, 15439, 65313, 73421}},
-{8674, 17, 25075, {1, 1, 3, 7, 19, 15, 119, 141, 57, 243, 423, 981, 1407, 12633, 20455, 53069, 98593}},
-{8675, 17, 25077, {1, 1, 3, 3, 15, 57, 71, 203, 15, 133, 601, 805, 2821, 11623, 147, 4333, 97681}},
-{8676, 17, 25084, {1, 1, 5, 7, 17, 61, 15, 251, 53, 699, 105, 1195, 3979, 41, 9077, 5145, 80057}},
-{8677, 17, 25088, {1, 1, 5, 15, 29, 33, 53, 19, 41, 471, 1143, 65, 5833, 8417, 17263, 35859, 45035}},
-{8678, 17, 25091, {1, 1, 1, 1, 15, 51, 73, 131, 181, 147, 1863, 3777, 1749, 10135, 11591, 12395, 85163}},
-{8679, 17, 25105, {1, 3, 1, 9, 23, 63, 83, 199, 87, 499, 2025, 863, 4665, 3941, 17647, 52463, 108615}},
-{8680, 17, 25134, {1, 3, 5, 7, 11, 39, 65, 161, 367, 593, 699, 1807, 7217, 5221, 22093, 44933, 6201}},
-{8681, 17, 25165, {1, 1, 7, 13, 9, 41, 35, 77, 353, 291, 1267, 3923, 5397, 15401, 30317, 14945, 8715}},
-{8682, 17, 25183, {1, 3, 1, 15, 11, 3, 29, 25, 505, 945, 1425, 2297, 1133, 4675, 8069, 55115, 114177}},
-{8683, 17, 25184, {1, 3, 1, 5, 27, 63, 25, 7, 5, 399, 473, 1325, 7391, 5953, 27755, 65407, 89435}},
-{8684, 17, 25202, {1, 3, 3, 13, 21, 61, 5, 119, 23, 999, 849, 1225, 3077, 821, 12059, 43223, 45427}},
-{8685, 17, 25204, {1, 3, 7, 13, 1, 5, 93, 173, 181, 453, 1449, 3823, 1713, 14737, 8891, 43643, 1983}},
-{8686, 17, 25211, {1, 1, 3, 3, 29, 53, 31, 163, 321, 539, 1283, 429, 3449, 15617, 4761, 21187, 120725}},
-{8687, 17, 25223, {1, 1, 1, 1, 13, 27, 49, 37, 33, 631, 375, 425, 2465, 8773, 2777, 2115, 35633}},
-{8688, 17, 25224, {1, 3, 5, 3, 25, 25, 27, 201, 63, 259, 1571, 1143, 2325, 6773, 11941, 28897, 19719}},
-{8689, 17, 25235, {1, 1, 3, 5, 11, 39, 59, 203, 37, 899, 559, 2599, 4397, 12159, 29579, 51251, 83213}},
-{8690, 17, 25241, {1, 1, 1, 7, 9, 19, 63, 169, 257, 921, 381, 3605, 3479, 1739, 26599, 20599, 29617}},
-{8691, 17, 25253, {1, 1, 1, 9, 7, 29, 123, 35, 419, 963, 855, 1903, 6199, 2727, 29811, 49279, 101673}},
-{8692, 17, 25258, {1, 3, 5, 11, 29, 23, 73, 13, 467, 935, 181, 3837, 8117, 11501, 18361, 26803, 99471}},
-{8693, 17, 25277, {1, 1, 1, 5, 31, 41, 109, 45, 115, 113, 1893, 727, 2453, 13463, 22339, 13495, 11473}},
-{8694, 17, 25278, {1, 1, 5, 9, 5, 31, 109, 145, 511, 243, 57, 2219, 1601, 1821, 12787, 48239, 89645}},
-{8695, 17, 25280, {1, 3, 1, 7, 19, 41, 25, 57, 45, 489, 1531, 3959, 2007, 14247, 13445, 1991, 114977}},
-{8696, 17, 25290, {1, 3, 7, 15, 7, 17, 107, 27, 249, 207, 183, 2483, 5817, 8927, 10715, 63631, 51947}},
-{8697, 17, 25295, {1, 3, 1, 3, 13, 21, 57, 113, 171, 885, 1335, 783, 7575, 4443, 19497, 13827, 130727}},
-{8698, 17, 25300, {1, 1, 5, 7, 19, 33, 95, 13, 387, 297, 1597, 767, 7543, 16063, 10367, 51683, 119811}},
-{8699, 17, 25307, {1, 3, 7, 9, 27, 57, 111, 209, 305, 139, 179, 25, 2295, 2593, 31361, 23677, 74501}},
-{8700, 17, 25319, {1, 3, 7, 3, 21, 63, 97, 189, 3, 693, 209, 2227, 7169, 9, 32575, 61521, 115155}},
-{8701, 17, 25323, {1, 1, 1, 11, 13, 21, 125, 249, 193, 895, 139, 1207, 5941, 5821, 6623, 7753, 80939}},
-{8702, 17, 25326, {1, 3, 5, 5, 11, 49, 17, 21, 423, 497, 835, 539, 6195, 12783, 1271, 20069, 2657}},
-{8703, 17, 25333, {1, 1, 7, 15, 13, 39, 83, 191, 77, 95, 661, 3627, 1853, 1349, 23109, 43583, 104121}},
-{8704, 17, 25334, {1, 3, 1, 15, 31, 15, 71, 255, 489, 91, 351, 367, 309, 6275, 18325, 51231, 52159}},
-{8705, 17, 25337, {1, 1, 7, 13, 21, 49, 37, 135, 355, 421, 507, 2563, 4955, 4095, 1933, 29517, 119699}},
-{8706, 17, 25348, {1, 1, 1, 1, 27, 41, 15, 161, 475, 635, 863, 3773, 6015, 6197, 24261, 26271, 42375}},
-{8707, 17, 25351, {1, 1, 7, 13, 25, 7, 23, 185, 129, 597, 1561, 3003, 2879, 15187, 4913, 24589, 12927}},
-{8708, 17, 25372, {1, 1, 3, 3, 9, 23, 49, 233, 345, 83, 823, 2627, 5019, 2365, 23755, 9855, 48515}},
-{8709, 17, 25381, {1, 3, 1, 1, 11, 7, 117, 213, 27, 923, 375, 2597, 8173, 8935, 16487, 49283, 104569}},
-{8710, 17, 25403, {1, 1, 7, 7, 23, 13, 61, 131, 313, 883, 495, 1105, 6207, 1473, 21655, 51883, 403}},
-{8711, 17, 25406, {1, 3, 3, 1, 25, 5, 5, 159, 243, 929, 1429, 1151, 5043, 11551, 21231, 38767, 105299}},
-{8712, 17, 25431, {1, 3, 7, 7, 15, 37, 49, 219, 67, 147, 873, 2391, 455, 9565, 8977, 64759, 40347}},
-{8713, 17, 25437, {1, 1, 1, 13, 21, 13, 13, 243, 303, 333, 187, 3591, 871, 2501, 30853, 5247, 48855}},
-{8714, 17, 25453, {1, 1, 1, 5, 1, 5, 127, 249, 23, 79, 789, 3507, 8119, 5025, 26545, 54009, 100633}},
-{8715, 17, 25459, {1, 3, 3, 11, 3, 31, 27, 115, 423, 309, 1805, 169, 789, 4081, 28139, 35355, 47991}},
-{8716, 17, 25462, {1, 3, 1, 5, 19, 13, 43, 165, 165, 241, 309, 1703, 7631, 5899, 12041, 21235, 97045}},
-{8717, 17, 25466, {1, 3, 1, 13, 15, 49, 29, 199, 93, 611, 77, 2681, 191, 10215, 8115, 11895, 108687}},
-{8718, 17, 25477, {1, 1, 3, 3, 13, 45, 15, 151, 345, 111, 1829, 1357, 6317, 5239, 26193, 46763, 73101}},
-{8719, 17, 25484, {1, 3, 7, 3, 1, 19, 119, 63, 23, 759, 173, 307, 967, 2731, 9353, 14479, 119}},
-{8720, 17, 25495, {1, 3, 5, 15, 5, 21, 127, 21, 419, 575, 991, 3465, 7365, 5711, 30657, 43513, 22447}},
-{8721, 17, 25501, {1, 3, 7, 1, 19, 5, 49, 7, 45, 963, 1755, 3745, 4061, 4619, 9089, 59953, 100265}},
-{8722, 17, 25506, {1, 1, 1, 3, 25, 53, 97, 97, 347, 749, 823, 1499, 8151, 9957, 731, 22317, 121623}},
-{8723, 17, 25511, {1, 3, 5, 5, 19, 3, 121, 127, 313, 457, 1737, 4065, 5295, 7957, 16373, 62085, 5711}},
-{8724, 17, 25515, {1, 1, 7, 13, 7, 37, 97, 43, 179, 837, 161, 477, 5095, 4985, 111, 58743, 24049}},
-{8725, 17, 25525, {1, 3, 1, 13, 27, 13, 91, 241, 339, 235, 111, 369, 3361, 15105, 11097, 23955, 53561}},
-{8726, 17, 25529, {1, 3, 5, 3, 9, 17, 103, 133, 309, 683, 71, 3329, 7229, 8763, 4165, 9649, 8529}},
-{8727, 17, 25532, {1, 3, 5, 13, 29, 55, 29, 205, 433, 1007, 1173, 731, 5653, 89, 18447, 37911, 65603}},
-{8728, 17, 25538, {1, 3, 5, 1, 15, 1, 7, 195, 397, 877, 1433, 3487, 1581, 1539, 3361, 7453, 46451}},
-{8729, 17, 25549, {1, 1, 5, 13, 23, 1, 47, 245, 19, 859, 681, 2971, 2531, 11393, 32765, 4595, 45213}},
-{8730, 17, 25552, {1, 3, 1, 3, 1, 11, 85, 185, 467, 413, 25, 3677, 881, 1791, 14655, 44811, 50819}},
-{8731, 17, 25564, {1, 3, 5, 9, 9, 21, 65, 99, 441, 215, 1453, 2873, 5883, 485, 20883, 1303, 11837}},
-{8732, 17, 25567, {1, 3, 3, 5, 9, 37, 87, 211, 247, 535, 1163, 1785, 4219, 12559, 17419, 48201, 21725}},
-{8733, 17, 25574, {1, 1, 1, 11, 29, 11, 9, 215, 375, 601, 627, 2641, 6961, 6175, 10995, 49299, 102891}},
-{8734, 17, 25577, {1, 3, 1, 3, 7, 7, 23, 139, 89, 1005, 1815, 947, 1507, 10349, 35, 43595, 104697}},
-{8735, 17, 25583, {1, 1, 5, 13, 29, 47, 77, 255, 341, 333, 1211, 3473, 1303, 11237, 28371, 43283, 77617}},
-{8736, 17, 25588, {1, 3, 3, 13, 27, 17, 73, 95, 227, 241, 1369, 833, 6683, 2193, 309, 64249, 6731}},
-{8737, 17, 25603, {1, 3, 3, 3, 15, 29, 45, 209, 401, 725, 1123, 1659, 6099, 15941, 5797, 30563, 119385}},
-{8738, 17, 25610, {1, 1, 1, 1, 7, 55, 95, 151, 351, 373, 1131, 2357, 7535, 3899, 19047, 17879, 34623}},
-{8739, 17, 25615, {1, 3, 1, 5, 31, 5, 33, 97, 477, 399, 1255, 1073, 1513, 11651, 2951, 31351, 102635}},
-{8740, 17, 25624, {1, 1, 3, 13, 17, 63, 51, 209, 57, 87, 977, 3663, 6717, 15441, 10709, 607, 48297}},
-{8741, 17, 25636, {1, 1, 5, 1, 9, 29, 1, 105, 343, 19, 977, 3401, 3873, 4259, 23057, 13071, 105771}},
-{8742, 17, 25639, {1, 1, 1, 5, 1, 33, 59, 17, 115, 225, 853, 3295, 965, 12547, 26971, 50097, 54999}},
-{8743, 17, 25643, {1, 3, 3, 13, 1, 51, 29, 19, 245, 781, 493, 1121, 2937, 4177, 3267, 47463, 101195}},
-{8744, 17, 25645, {1, 3, 7, 5, 3, 51, 25, 131, 451, 997, 1809, 1583, 355, 15383, 28159, 39141, 109379}},
-{8745, 17, 25648, {1, 1, 5, 7, 3, 19, 75, 103, 401, 115, 1627, 423, 2485, 7281, 6177, 54677, 31499}},
-{8746, 17, 25671, {1, 1, 1, 11, 23, 7, 57, 121, 5, 921, 1191, 1779, 1979, 3427, 25617, 19423, 73835}},
-{8747, 17, 25678, {1, 3, 3, 11, 17, 51, 15, 163, 265, 665, 1399, 1977, 3097, 7109, 14741, 24291, 79239}},
-{8748, 17, 25689, {1, 1, 7, 3, 25, 61, 69, 77, 341, 23, 713, 2879, 8075, 14855, 9691, 58241, 113277}},
-{8749, 17, 25708, {1, 3, 7, 9, 27, 43, 95, 11, 239, 445, 951, 3869, 1049, 6493, 9569, 9285, 29183}},
-{8750, 17, 25716, {1, 1, 3, 1, 1, 23, 27, 101, 337, 171, 1977, 3181, 2693, 8591, 32309, 24909, 106535}},
-{8751, 17, 25725, {1, 1, 1, 7, 23, 59, 79, 115, 49, 351, 871, 1209, 1045, 5985, 28427, 23047, 113571}},
-{8752, 17, 25730, {1, 1, 7, 13, 27, 3, 35, 7, 319, 503, 977, 3747, 4859, 16315, 30375, 25999, 24341}},
-{8753, 17, 25739, {1, 3, 3, 7, 23, 43, 67, 21, 399, 349, 1541, 2991, 5781, 14501, 5609, 65093, 12789}},
-{8754, 17, 25747, {1, 3, 1, 11, 5, 21, 17, 157, 311, 663, 469, 4033, 1557, 7569, 31163, 14079, 127771}},
-{8755, 17, 25753, {1, 1, 7, 15, 15, 31, 15, 183, 365, 35, 1433, 2793, 6685, 10565, 30409, 46815, 14173}},
-{8756, 17, 25790, {1, 1, 7, 7, 7, 45, 61, 163, 99, 353, 1535, 3185, 4023, 7999, 26173, 12675, 98073}},
-{8757, 17, 25797, {1, 1, 5, 13, 1, 11, 107, 41, 171, 773, 1513, 883, 2117, 14449, 32323, 58271, 97173}},
-{8758, 17, 25804, {1, 1, 3, 13, 27, 15, 123, 247, 281, 851, 233, 1173, 6863, 14805, 12401, 30729, 104127}},
-{8759, 17, 25809, {1, 1, 7, 11, 25, 9, 97, 215, 217, 51, 1865, 3897, 725, 4779, 21661, 11853, 72225}},
-{8760, 17, 25816, {1, 1, 5, 3, 5, 31, 125, 81, 367, 705, 325, 519, 3879, 5607, 3247, 7149, 33177}},
-{8761, 17, 25825, {1, 3, 3, 7, 17, 17, 19, 113, 331, 277, 317, 1893, 1287, 8965, 27523, 61355, 45331}},
-{8762, 17, 25831, {1, 3, 7, 9, 27, 15, 87, 21, 343, 479, 11, 2945, 1235, 1591, 28195, 40559, 42773}},
-{8763, 17, 25845, {1, 3, 3, 13, 1, 45, 115, 41, 263, 569, 71, 4051, 739, 1031, 19213, 23961, 110767}},
-{8764, 17, 25846, {1, 3, 7, 1, 9, 41, 21, 131, 3, 617, 191, 4051, 2445, 13451, 11889, 25075, 82631}},
-{8765, 17, 25867, {1, 3, 3, 15, 7, 55, 65, 67, 443, 1023, 1445, 1467, 3907, 11449, 2247, 65085, 102161}},
-{8766, 17, 25870, {1, 3, 5, 15, 19, 27, 97, 181, 51, 591, 99, 1443, 4927, 9809, 29693, 44293, 29369}},
-{8767, 17, 25897, {1, 1, 7, 7, 17, 59, 69, 163, 37, 171, 107, 2581, 3567, 9455, 19707, 6329, 27755}},
-{8768, 17, 25908, {1, 1, 1, 11, 15, 17, 83, 223, 183, 861, 1047, 3739, 3509, 5571, 28259, 42781, 130657}},
-{8769, 17, 25937, {1, 3, 3, 7, 15, 11, 33, 115, 297, 841, 1629, 1559, 2261, 11763, 22255, 63819, 55831}},
-{8770, 17, 25940, {1, 3, 3, 5, 19, 49, 17, 251, 507, 251, 805, 1041, 3947, 2219, 19977, 65449, 25031}},
-{8771, 17, 25944, {1, 1, 1, 11, 3, 7, 81, 17, 219, 729, 949, 3257, 6495, 4701, 2181, 7009, 106465}},
-{8772, 17, 25949, {1, 3, 7, 5, 27, 35, 15, 83, 43, 1013, 1427, 1943, 7555, 6613, 26879, 42685, 22071}},
-{8773, 17, 25954, {1, 1, 3, 13, 23, 55, 15, 87, 15, 579, 717, 777, 149, 11431, 26197, 17711, 7337}},
-{8774, 17, 25960, {1, 1, 5, 1, 31, 45, 113, 253, 211, 915, 1855, 4043, 2159, 1803, 5061, 40473, 3657}},
-{8775, 17, 25963, {1, 1, 3, 7, 25, 15, 37, 73, 467, 969, 1123, 4053, 4837, 10091, 25461, 40803, 91157}},
-{8776, 17, 25966, {1, 1, 5, 1, 7, 31, 77, 207, 21, 623, 577, 1195, 5839, 13013, 11189, 61691, 33327}},
-{8777, 17, 25978, {1, 3, 7, 7, 13, 3, 9, 55, 47, 779, 599, 3747, 1533, 14705, 23185, 4011, 36003}},
-{8778, 17, 25996, {1, 1, 5, 5, 31, 17, 99, 253, 103, 957, 241, 1893, 7435, 14907, 9089, 23205, 70639}},
-{8779, 17, 26007, {1, 3, 7, 15, 7, 55, 53, 101, 227, 541, 2017, 275, 577, 15621, 1799, 50373, 43197}},
-{8780, 17, 26011, {1, 3, 1, 15, 29, 23, 69, 193, 429, 359, 1045, 4091, 6551, 1673, 29113, 43247, 80993}},
-{8781, 17, 26027, {1, 3, 7, 11, 5, 37, 13, 27, 277, 65, 565, 2631, 6919, 5593, 8481, 14703, 9719}},
-{8782, 17, 26032, {1, 3, 1, 15, 5, 7, 83, 51, 77, 307, 1299, 1373, 5281, 15359, 15569, 50093, 59661}},
-{8783, 17, 26038, {1, 3, 5, 11, 13, 31, 99, 123, 263, 319, 2033, 4055, 2427, 103, 2009, 27517, 112467}},
-{8784, 17, 26049, {1, 1, 7, 3, 13, 1, 51, 131, 17, 861, 459, 3925, 5511, 5255, 28553, 36437, 54591}},
-{8785, 17, 26052, {1, 3, 7, 5, 9, 57, 49, 119, 291, 727, 1611, 4035, 4517, 10979, 28445, 26905, 57517}},
-{8786, 17, 26055, {1, 1, 5, 9, 9, 55, 43, 209, 411, 137, 1619, 3965, 5253, 8217, 7569, 42043, 104163}},
-{8787, 17, 26085, {1, 3, 3, 7, 21, 3, 107, 255, 353, 735, 71, 1789, 3351, 755, 22805, 53537, 126859}},
-{8788, 17, 26089, {1, 1, 7, 5, 15, 55, 13, 167, 165, 289, 1231, 2547, 8135, 5475, 2361, 49019, 110579}},
-{8789, 17, 26090, {1, 3, 1, 11, 17, 21, 59, 37, 177, 517, 499, 4035, 749, 14297, 22415, 54975, 29769}},
-{8790, 17, 26098, {1, 3, 7, 3, 3, 59, 55, 17, 483, 625, 875, 1465, 7583, 2969, 2741, 36965, 80367}},
-{8791, 17, 26104, {1, 1, 3, 13, 31, 5, 11, 149, 7, 297, 1485, 735, 4095, 10089, 5757, 64997, 56629}},
-{8792, 17, 26110, {1, 3, 1, 13, 19, 43, 77, 209, 309, 739, 1765, 3297, 8167, 6523, 27987, 25235, 80555}},
-{8793, 17, 26113, {1, 1, 3, 9, 31, 57, 125, 75, 3, 633, 85, 3339, 1691, 9721, 17465, 36801, 106147}},
-{8794, 17, 26126, {1, 3, 5, 15, 27, 7, 111, 7, 475, 523, 1825, 1367, 1549, 15533, 13827, 14471, 100271}},
-{8795, 17, 26133, {1, 1, 5, 3, 5, 61, 1, 221, 163, 183, 1701, 3549, 349, 10057, 26169, 20725, 55305}},
-{8796, 17, 26138, {1, 1, 3, 1, 15, 41, 13, 71, 269, 909, 1253, 2553, 83, 10055, 1057, 39841, 20437}},
-{8797, 17, 26140, {1, 3, 3, 5, 29, 39, 113, 23, 137, 601, 361, 1779, 279, 15803, 8993, 2633, 114847}},
-{8798, 17, 26156, {1, 1, 3, 7, 29, 45, 35, 27, 71, 253, 231, 3449, 1955, 9109, 9043, 50593, 15023}},
-{8799, 17, 26159, {1, 3, 1, 11, 17, 45, 85, 255, 341, 957, 769, 3009, 3997, 6435, 1161, 34219, 97077}},
-{8800, 17, 26176, {1, 1, 5, 1, 1, 19, 9, 51, 477, 129, 1411, 3223, 5069, 3237, 15947, 27215, 70401}},
-{8801, 17, 26186, {1, 1, 3, 1, 1, 1, 73, 31, 301, 227, 119, 607, 3379, 3907, 1263, 2651, 43769}},
-{8802, 17, 26203, {1, 1, 1, 15, 21, 59, 109, 155, 473, 361, 1871, 3085, 513, 12607, 12747, 41067, 44977}},
-{8803, 17, 26210, {1, 1, 7, 3, 27, 21, 89, 71, 437, 671, 1469, 2191, 4225, 6343, 1131, 29141, 25221}},
-{8804, 17, 26222, {1, 1, 7, 9, 7, 45, 95, 197, 391, 11, 1913, 3107, 5247, 959, 30395, 32809, 20893}},
-{8805, 17, 26224, {1, 3, 7, 15, 13, 49, 77, 245, 463, 769, 1807, 1311, 2715, 14819, 27595, 57521, 105221}},
-{8806, 17, 26229, {1, 1, 1, 5, 23, 45, 119, 77, 325, 405, 1631, 461, 6357, 7037, 31699, 46295, 118577}},
-{8807, 17, 26233, {1, 3, 5, 1, 21, 3, 31, 13, 7, 571, 633, 425, 6547, 3423, 19355, 49481, 76289}},
-{8808, 17, 26236, {1, 1, 3, 9, 7, 51, 113, 173, 169, 97, 1821, 979, 2553, 11505, 20047, 39277, 122905}},
-{8809, 17, 26239, {1, 1, 5, 13, 17, 9, 111, 205, 261, 671, 657, 507, 3903, 10767, 4387, 3045, 102617}},
-{8810, 17, 26267, {1, 1, 3, 3, 5, 11, 19, 61, 401, 605, 455, 2457, 4471, 7255, 18435, 49673, 97289}},
-{8811, 17, 26291, {1, 3, 1, 1, 31, 25, 77, 35, 65, 127, 929, 2325, 2315, 13819, 5509, 12515, 36991}},
-{8812, 17, 26293, {1, 1, 7, 5, 21, 49, 33, 119, 181, 645, 1425, 2411, 245, 13755, 18775, 50061, 47119}},
-{8813, 17, 26298, {1, 3, 7, 5, 27, 43, 81, 191, 233, 435, 829, 3881, 713, 11153, 4637, 37721, 115567}},
-{8814, 17, 26303, {1, 3, 7, 1, 27, 59, 51, 165, 59, 931, 1921, 3059, 6843, 813, 22063, 29445, 114765}},
-{8815, 17, 26308, {1, 1, 5, 11, 31, 53, 89, 69, 29, 893, 1241, 7, 1707, 16167, 8371, 14021, 103281}},
-{8816, 17, 26312, {1, 3, 1, 1, 23, 21, 3, 35, 73, 769, 1417, 4051, 3223, 813, 1141, 18823, 31951}},
-{8817, 17, 26315, {1, 3, 7, 11, 9, 17, 89, 85, 407, 137, 1865, 2881, 1495, 3757, 3711, 36651, 1797}},
-{8818, 17, 26342, {1, 3, 5, 1, 25, 29, 29, 217, 15, 173, 479, 2363, 2341, 6193, 16403, 64097, 1173}},
-{8819, 17, 26354, {1, 3, 3, 3, 11, 29, 113, 167, 333, 573, 1467, 2223, 5693, 1063, 20299, 40993, 69055}},
-{8820, 17, 26363, {1, 1, 3, 7, 3, 51, 45, 139, 79, 393, 1251, 1087, 1423, 1827, 23445, 41635, 78511}},
-{8821, 17, 26365, {1, 3, 3, 13, 29, 45, 85, 229, 33, 373, 113, 1205, 997, 11777, 7663, 18513, 5797}},
-{8822, 17, 26383, {1, 1, 5, 5, 15, 5, 127, 85, 49, 345, 901, 3215, 2347, 2329, 19597, 39555, 25031}},
-{8823, 17, 26391, {1, 1, 7, 11, 9, 25, 71, 183, 341, 1011, 439, 3649, 2859, 10183, 7635, 45297, 38581}},
-{8824, 17, 26398, {1, 1, 1, 11, 23, 13, 1, 69, 461, 77, 1641, 2851, 1889, 2413, 1131, 39009, 33773}},
-{8825, 17, 26416, {1, 3, 7, 7, 25, 19, 67, 233, 141, 207, 1501, 453, 4773, 7411, 22839, 25365, 53189}},
-{8826, 17, 26421, {1, 1, 7, 3, 3, 17, 13, 167, 73, 1005, 887, 2595, 4351, 3249, 5653, 36025, 33733}},
-{8827, 17, 26425, {1, 1, 7, 15, 11, 1, 105, 215, 329, 601, 1477, 723, 4597, 3525, 26235, 63957, 26677}},
-{8828, 17, 26434, {1, 1, 1, 11, 27, 15, 111, 133, 327, 567, 845, 2135, 7905, 7297, 29255, 14947, 104885}},
-{8829, 17, 26439, {1, 1, 7, 9, 21, 11, 67, 179, 459, 423, 295, 3445, 1681, 12907, 29281, 7445, 35539}},
-{8830, 17, 26453, {1, 1, 3, 11, 23, 61, 111, 123, 81, 439, 299, 3557, 2821, 705, 15393, 37175, 11533}},
-{8831, 17, 26454, {1, 1, 3, 1, 13, 15, 113, 227, 285, 313, 687, 2085, 6363, 8003, 32661, 36461, 68759}},
-{8832, 17, 26470, {1, 3, 3, 1, 27, 7, 101, 177, 363, 461, 1519, 2339, 473, 7469, 4335, 30951, 130987}},
-{8833, 17, 26491, {1, 1, 1, 3, 31, 39, 59, 159, 207, 93, 581, 1973, 945, 11343, 15901, 22001, 3515}},
-{8834, 17, 26493, {1, 3, 7, 5, 11, 53, 125, 57, 389, 985, 1055, 3803, 3879, 5537, 28221, 36805, 16025}},
-{8835, 17, 26500, {1, 1, 1, 9, 1, 63, 81, 57, 59, 813, 865, 3491, 3771, 6121, 6847, 14765, 68567}},
-{8836, 17, 26509, {1, 1, 7, 7, 13, 17, 23, 211, 435, 167, 933, 357, 3567, 3019, 28439, 17701, 119937}},
-{8837, 17, 26518, {1, 1, 1, 9, 7, 53, 103, 155, 211, 719, 413, 3673, 2795, 15687, 1737, 50855, 129133}},
-{8838, 17, 26531, {1, 1, 3, 13, 11, 23, 53, 121, 497, 383, 1655, 937, 5563, 2549, 23183, 46149, 78875}},
-{8839, 17, 26533, {1, 3, 5, 11, 25, 1, 45, 139, 437, 729, 2009, 3245, 4091, 551, 25993, 31655, 33641}},
-{8840, 17, 26540, {1, 3, 1, 13, 7, 23, 87, 111, 471, 501, 1767, 1051, 7037, 3199, 19609, 43227, 53667}},
-{8841, 17, 26552, {1, 3, 7, 1, 25, 1, 49, 189, 55, 375, 601, 2065, 2991, 7697, 25739, 14951, 43705}},
-{8842, 17, 26566, {1, 1, 7, 5, 29, 21, 51, 111, 81, 809, 1963, 2143, 5529, 15701, 4719, 11857, 88207}},
-{8843, 17, 26569, {1, 1, 5, 11, 27, 27, 7, 145, 281, 939, 537, 1255, 1475, 11383, 15081, 9105, 102775}},
-{8844, 17, 26583, {1, 1, 5, 7, 9, 45, 67, 23, 65, 139, 1871, 3975, 6357, 6515, 25423, 23915, 76289}},
-{8845, 17, 26590, {1, 1, 5, 11, 31, 31, 89, 65, 451, 341, 819, 2439, 6753, 15113, 9085, 32687, 5055}},
-{8846, 17, 26596, {1, 1, 5, 1, 15, 29, 123, 83, 495, 185, 303, 315, 6015, 5257, 2467, 4903, 78269}},
-{8847, 17, 26624, {1, 1, 3, 5, 31, 51, 49, 199, 501, 407, 733, 1181, 8023, 7321, 14765, 17535, 19893}},
-{8848, 17, 26636, {1, 1, 5, 5, 19, 15, 103, 183, 13, 969, 1537, 3053, 3173, 12983, 21761, 33733, 67799}},
-{8849, 17, 26667, {1, 3, 1, 1, 27, 55, 37, 149, 379, 11, 1655, 2317, 3135, 6459, 25941, 12679, 60245}},
-{8850, 17, 26669, {1, 1, 3, 9, 9, 13, 33, 243, 337, 741, 1685, 1147, 5465, 4865, 559, 23993, 47273}},
-{8851, 17, 26672, {1, 3, 5, 13, 21, 11, 39, 169, 135, 209, 1909, 3655, 3117, 1075, 8165, 54633, 28189}},
-{8852, 17, 26675, {1, 3, 1, 15, 9, 23, 11, 123, 63, 133, 947, 907, 3853, 10291, 22905, 4561, 92497}},
-{8853, 17, 26687, {1, 1, 3, 13, 17, 9, 5, 209, 429, 3, 2035, 1497, 6765, 5991, 24991, 8155, 103417}},
-{8854, 17, 26689, {1, 1, 5, 13, 27, 47, 79, 11, 41, 791, 1939, 3099, 4069, 4665, 20801, 18659, 72163}},
-{8855, 17, 26696, {1, 3, 1, 13, 25, 37, 79, 131, 233, 647, 291, 1419, 5157, 4261, 27715, 611, 83157}},
-{8856, 17, 26702, {1, 1, 5, 1, 17, 61, 45, 163, 137, 937, 91, 1695, 1553, 543, 28615, 6855, 75201}},
-{8857, 17, 26714, {1, 1, 3, 13, 7, 63, 109, 13, 351, 159, 1111, 2791, 4701, 5805, 9707, 18361, 98091}},
-{8858, 17, 26716, {1, 1, 3, 11, 11, 21, 55, 247, 111, 801, 93, 3091, 1043, 9761, 23679, 5555, 195}},
-{8859, 17, 26729, {1, 1, 1, 1, 13, 43, 123, 113, 265, 561, 659, 3755, 6605, 10949, 30511, 29495, 9075}},
-{8860, 17, 26732, {1, 3, 1, 7, 23, 63, 19, 73, 233, 1017, 851, 1971, 3999, 7407, 25309, 63991, 92867}},
-{8861, 17, 26737, {1, 3, 3, 3, 19, 63, 127, 107, 465, 463, 1507, 1323, 4729, 14717, 9129, 24859, 117565}},
-{8862, 17, 26747, {1, 1, 7, 1, 19, 11, 13, 85, 339, 939, 895, 887, 765, 15501, 8783, 65087, 77899}},
-{8863, 17, 26773, {1, 3, 7, 3, 7, 15, 43, 153, 365, 223, 1947, 2295, 787, 5549, 20089, 29203, 4807}},
-{8864, 17, 26780, {1, 3, 7, 3, 31, 27, 51, 217, 483, 623, 633, 2123, 1211, 9173, 17949, 54251, 89161}},
-{8865, 17, 26801, {1, 3, 3, 11, 3, 11, 111, 73, 283, 23, 1925, 253, 5141, 12545, 24913, 16847, 13067}},
-{8866, 17, 26811, {1, 3, 5, 5, 31, 39, 35, 235, 135, 85, 191, 999, 6633, 12527, 21401, 61339, 81239}},
-{8867, 17, 26813, {1, 1, 3, 15, 9, 13, 39, 125, 137, 639, 555, 813, 2821, 1199, 32075, 15079, 104609}},
-{8868, 17, 26831, {1, 3, 7, 7, 15, 43, 99, 51, 245, 25, 147, 89, 6841, 5523, 28493, 13967, 113109}},
-{8869, 17, 26836, {1, 1, 3, 13, 7, 5, 27, 121, 269, 231, 1011, 1365, 5055, 11619, 27393, 48033, 65725}},
-{8870, 17, 26839, {1, 1, 7, 5, 9, 23, 41, 71, 327, 339, 1681, 3303, 4143, 421, 15213, 48405, 98067}},
-{8871, 17, 26849, {1, 3, 7, 15, 15, 33, 73, 33, 351, 131, 1051, 3909, 7535, 7659, 9443, 35015, 329}},
-{8872, 17, 26862, {1, 1, 3, 9, 19, 55, 97, 223, 265, 877, 235, 867, 4961, 3137, 19885, 10955, 7655}},
-{8873, 17, 26869, {1, 3, 5, 13, 1, 11, 75, 215, 271, 793, 1691, 1437, 1317, 10977, 1311, 64865, 92361}},
-{8874, 17, 26873, {1, 1, 1, 5, 23, 23, 35, 53, 187, 345, 115, 929, 3919, 4523, 31709, 16771, 33399}},
-{8875, 17, 26874, {1, 3, 5, 11, 17, 7, 75, 57, 351, 359, 1737, 2665, 4259, 13905, 6999, 45359, 117891}},
-{8876, 17, 26888, {1, 1, 5, 3, 23, 29, 49, 209, 417, 843, 531, 1649, 7829, 6271, 3759, 39727, 47415}},
-{8877, 17, 26891, {1, 1, 7, 1, 21, 45, 101, 105, 385, 797, 985, 1447, 3757, 3287, 583, 29283, 96821}},
-{8878, 17, 26896, {1, 1, 7, 9, 1, 29, 15, 207, 289, 465, 815, 2289, 449, 9403, 19197, 13797, 102651}},
-{8879, 17, 26899, {1, 3, 7, 15, 5, 45, 81, 187, 21, 433, 679, 2759, 3375, 6935, 22595, 50149, 13557}},
-{8880, 17, 26912, {1, 3, 3, 5, 11, 55, 69, 219, 95, 21, 645, 1955, 7527, 6037, 29427, 36297, 62013}},
-{8881, 17, 26921, {1, 1, 7, 15, 13, 35, 25, 67, 383, 13, 539, 2399, 4611, 8065, 3815, 27771, 50411}},
-{8882, 17, 26935, {1, 3, 1, 3, 27, 47, 65, 33, 393, 895, 1663, 1289, 1057, 11887, 1259, 53611, 36811}},
-{8883, 17, 26941, {1, 3, 5, 3, 5, 1, 27, 65, 379, 15, 1643, 1461, 3009, 8177, 15589, 5889, 1103}},
-{8884, 17, 26949, {1, 1, 5, 15, 27, 53, 43, 173, 377, 665, 581, 1061, 1363, 15015, 26709, 29507, 28075}},
-{8885, 17, 26954, {1, 1, 7, 3, 9, 11, 45, 71, 23, 995, 1277, 855, 1001, 12927, 19753, 46639, 16949}},
-{8886, 17, 26967, {1, 1, 7, 5, 15, 33, 27, 27, 437, 415, 1785, 2091, 279, 8041, 2209, 15821, 122363}},
-{8887, 17, 26977, {1, 1, 7, 1, 21, 1, 47, 215, 463, 959, 849, 1703, 5175, 10043, 16991, 11023, 52201}},
-{8888, 17, 27011, {1, 1, 1, 11, 21, 7, 121, 31, 95, 631, 1717, 3017, 2083, 2047, 12051, 63117, 25949}},
-{8889, 17, 27018, {1, 1, 5, 5, 9, 5, 105, 121, 205, 643, 1721, 2601, 2991, 2381, 4873, 12049, 20043}},
-{8890, 17, 27026, {1, 3, 5, 11, 7, 11, 97, 187, 253, 571, 101, 3077, 1479, 9513, 15451, 37105, 34445}},
-{8891, 17, 27028, {1, 1, 7, 11, 19, 19, 39, 115, 221, 13, 217, 369, 6855, 14529, 143, 13461, 62927}},
-{8892, 17, 27032, {1, 3, 3, 7, 29, 27, 9, 171, 419, 571, 837, 3829, 1871, 12691, 30693, 4195, 38905}},
-{8893, 17, 27044, {1, 1, 1, 11, 5, 55, 17, 41, 241, 419, 337, 897, 4663, 14469, 18701, 18009, 44605}},
-{8894, 17, 27053, {1, 1, 7, 7, 1, 33, 63, 197, 257, 655, 1287, 2571, 57, 13275, 29669, 8501, 61389}},
-{8895, 17, 27062, {1, 3, 5, 3, 29, 39, 101, 215, 101, 271, 1373, 2171, 841, 9865, 28951, 20369, 42413}},
-{8896, 17, 27065, {1, 3, 5, 1, 31, 23, 119, 137, 263, 633, 1239, 281, 4965, 14913, 30229, 14147, 37183}},
-{8897, 17, 27068, {1, 3, 1, 3, 11, 55, 33, 45, 69, 913, 269, 1021, 4005, 15191, 11187, 45917, 76905}},
-{8898, 17, 27080, {1, 1, 1, 13, 27, 11, 75, 139, 243, 221, 1289, 2195, 7041, 10053, 5731, 35245, 41317}},
-{8899, 17, 27083, {1, 1, 7, 9, 25, 11, 81, 243, 233, 137, 831, 2825, 6007, 7305, 31733, 64343, 7047}},
-{8900, 17, 27093, {1, 3, 5, 9, 17, 61, 25, 245, 285, 969, 1397, 1331, 5393, 3653, 15533, 9121, 111115}},
-{8901, 17, 27098, {1, 1, 5, 9, 1, 9, 61, 205, 285, 849, 1071, 1013, 2655, 10121, 15165, 25189, 56207}},
-{8902, 17, 27107, {1, 3, 5, 7, 19, 45, 121, 19, 237, 711, 1523, 3251, 693, 13567, 31993, 11239, 64127}},
-{8903, 17, 27110, {1, 1, 1, 11, 23, 25, 33, 211, 321, 1021, 1855, 291, 2911, 11841, 21929, 64147, 63201}},
-{8904, 17, 27114, {1, 1, 7, 3, 27, 21, 119, 219, 431, 819, 83, 2487, 7533, 10697, 3129, 53301, 104999}},
-{8905, 17, 27121, {1, 3, 5, 15, 9, 25, 89, 65, 293, 411, 989, 3103, 5563, 15703, 8757, 32595, 43409}},
-{8906, 17, 27127, {1, 3, 3, 1, 31, 31, 45, 173, 231, 171, 1185, 1499, 1713, 9945, 11575, 37113, 103989}},
-{8907, 17, 27137, {1, 1, 5, 13, 27, 3, 93, 253, 23, 71, 1963, 2571, 6259, 15757, 9709, 42835, 42047}},
-{8908, 17, 27144, {1, 1, 7, 11, 5, 11, 123, 117, 39, 559, 111, 527, 6253, 781, 9177, 47189, 94031}},
-{8909, 17, 27155, {1, 1, 5, 15, 5, 49, 93, 185, 167, 787, 1553, 3291, 3723, 1651, 23225, 5643, 42967}},
-{8910, 17, 27171, {1, 3, 1, 13, 15, 35, 19, 193, 505, 127, 661, 1943, 1249, 5103, 8233, 64319, 76955}},
-{8911, 17, 27178, {1, 3, 7, 7, 17, 13, 97, 185, 415, 331, 283, 3341, 2903, 2927, 7729, 4095, 103083}},
-{8912, 17, 27180, {1, 1, 3, 15, 15, 25, 65, 45, 413, 521, 747, 2605, 5845, 12909, 7651, 45937, 99043}},
-{8913, 17, 27185, {1, 1, 5, 9, 9, 21, 3, 75, 335, 745, 1493, 1721, 1977, 11105, 22621, 49281, 107113}},
-{8914, 17, 27191, {1, 3, 1, 11, 25, 11, 99, 53, 239, 831, 655, 615, 7565, 14039, 29115, 26165, 127159}},
-{8915, 17, 27192, {1, 1, 7, 5, 31, 35, 75, 157, 441, 815, 119, 565, 2703, 14059, 7867, 42487, 93647}},
-{8916, 17, 27195, {1, 3, 7, 3, 3, 59, 101, 223, 257, 989, 363, 1059, 5157, 11129, 1481, 19287, 117623}},
-{8917, 17, 27212, {1, 1, 1, 1, 29, 27, 1, 129, 253, 673, 103, 1881, 7053, 1261, 32003, 23345, 102503}},
-{8918, 17, 27215, {1, 3, 1, 9, 11, 37, 3, 99, 303, 519, 1175, 3021, 2275, 9919, 25011, 45865, 71351}},
-{8919, 17, 27218, {1, 1, 7, 15, 27, 9, 107, 61, 385, 21, 861, 2119, 4643, 8379, 25455, 22425, 113387}},
-{8920, 17, 27230, {1, 1, 1, 7, 27, 15, 73, 211, 497, 527, 873, 329, 2213, 415, 13987, 56581, 27829}},
-{8921, 17, 27234, {1, 3, 5, 1, 31, 43, 107, 149, 209, 211, 2029, 2793, 2213, 12389, 27177, 51375, 51983}},
-{8922, 17, 27245, {1, 3, 3, 7, 25, 57, 67, 101, 127, 43, 1775, 801, 3343, 12203, 8667, 58387, 10735}},
-{8923, 17, 27248, {1, 1, 7, 5, 13, 47, 101, 123, 133, 593, 1409, 3525, 2545, 13009, 11873, 38463, 1075}},
-{8924, 17, 27263, {1, 3, 3, 1, 3, 19, 75, 221, 157, 67, 397, 1141, 5073, 10795, 9857, 35459, 62701}},
-{8925, 17, 27279, {1, 1, 7, 7, 23, 17, 41, 179, 83, 543, 1839, 3709, 131, 15681, 9147, 18685, 90389}},
-{8926, 17, 27288, {1, 1, 5, 7, 17, 15, 31, 217, 79, 687, 1927, 2889, 6127, 15095, 28437, 16403, 123275}},
-{8927, 17, 27294, {1, 3, 7, 15, 13, 17, 123, 75, 45, 635, 525, 3897, 6769, 13855, 16695, 18039, 37479}},
-{8928, 17, 27303, {1, 1, 5, 1, 23, 15, 69, 161, 503, 339, 1061, 839, 9, 10013, 24493, 32711, 50147}},
-{8929, 17, 27304, {1, 3, 3, 11, 5, 45, 9, 233, 131, 629, 1111, 3311, 2211, 9079, 19763, 23793, 85389}},
-{8930, 17, 27312, {1, 1, 7, 7, 7, 27, 15, 85, 291, 925, 1545, 3061, 4867, 1613, 13467, 53731, 92811}},
-{8931, 17, 27330, {1, 3, 5, 1, 21, 21, 71, 33, 141, 675, 1519, 3275, 1491, 10717, 28199, 14983, 18961}},
-{8932, 17, 27341, {1, 3, 5, 5, 31, 13, 109, 239, 369, 373, 257, 3765, 2531, 13281, 11877, 29439, 106939}},
-{8933, 17, 27342, {1, 3, 7, 15, 13, 39, 111, 203, 109, 179, 789, 3849, 433, 5745, 2343, 15795, 92603}},
-{8934, 17, 27344, {1, 3, 5, 5, 11, 57, 3, 245, 289, 249, 713, 315, 2261, 1249, 6963, 44507, 100829}},
-{8935, 17, 27353, {1, 3, 5, 11, 5, 49, 97, 245, 363, 315, 509, 17, 4485, 15393, 28491, 17945, 65663}},
-{8936, 17, 27356, {1, 3, 5, 1, 5, 13, 15, 17, 141, 119, 1393, 581, 2439, 2015, 11527, 8537, 103005}},
-{8937, 17, 27366, {1, 3, 5, 1, 25, 9, 117, 25, 99, 777, 985, 1159, 99, 3013, 21429, 19027, 61833}},
-{8938, 17, 27369, {1, 1, 1, 5, 1, 47, 37, 83, 159, 29, 281, 3789, 2525, 15999, 8965, 11145, 14453}},
-{8939, 17, 27377, {1, 1, 3, 1, 11, 63, 77, 207, 267, 473, 241, 629, 6969, 9093, 839, 3875, 18873}},
-{8940, 17, 27387, {1, 3, 5, 7, 31, 57, 103, 65, 349, 321, 717, 2403, 105, 643, 27999, 2509, 123061}},
-{8941, 17, 27409, {1, 1, 5, 7, 3, 31, 7, 113, 17, 995, 1211, 1749, 6757, 3391, 8011, 47715, 24301}},
-{8942, 17, 27437, {1, 3, 7, 11, 7, 55, 29, 155, 373, 81, 1255, 2205, 3233, 9537, 22129, 24505, 79021}},
-{8943, 17, 27443, {1, 1, 7, 5, 3, 49, 5, 51, 89, 107, 585, 3933, 745, 11685, 20663, 12521, 24357}},
-{8944, 17, 27446, {1, 1, 7, 1, 17, 17, 83, 215, 357, 581, 2025, 3411, 7287, 11925, 2253, 43513, 98655}},
-{8945, 17, 27450, {1, 3, 5, 3, 27, 27, 51, 147, 471, 509, 423, 3807, 677, 8429, 581, 47999, 35913}},
-{8946, 17, 27452, {1, 3, 3, 9, 15, 31, 1, 93, 207, 759, 1991, 473, 2273, 43, 12547, 58085, 20953}},
-{8947, 17, 27457, {1, 1, 3, 3, 1, 27, 39, 219, 381, 187, 159, 2333, 6141, 3775, 5693, 14853, 38765}},
-{8948, 17, 27472, {1, 3, 1, 5, 19, 1, 19, 237, 231, 975, 1609, 723, 241, 10105, 18817, 58373, 118889}},
-{8949, 17, 27475, {1, 1, 5, 7, 7, 43, 99, 181, 109, 529, 421, 1493, 1075, 12219, 24287, 33479, 29987}},
-{8950, 17, 27487, {1, 1, 7, 1, 17, 11, 79, 85, 157, 851, 1429, 3355, 139, 14327, 30025, 60303, 109015}},
-{8951, 17, 27488, {1, 3, 5, 9, 11, 15, 37, 79, 5, 169, 999, 815, 6255, 11763, 16299, 49891, 101917}},
-{8952, 17, 27493, {1, 3, 5, 9, 29, 45, 51, 211, 159, 771, 1631, 2871, 4877, 4941, 18127, 15669, 57515}},
-{8953, 17, 27506, {1, 1, 3, 3, 19, 29, 9, 205, 253, 399, 303, 2441, 3187, 641, 23341, 52951, 57559}},
-{8954, 17, 27508, {1, 3, 3, 15, 11, 29, 121, 227, 69, 935, 365, 217, 4617, 13193, 27663, 46903, 107843}},
-{8955, 17, 27521, {1, 1, 5, 11, 13, 31, 13, 243, 275, 685, 1613, 1915, 2775, 11225, 4729, 45549, 103875}},
-{8956, 17, 27522, {1, 1, 5, 1, 9, 61, 35, 143, 165, 441, 517, 1735, 5281, 10139, 21107, 11713, 130483}},
-{8957, 17, 27527, {1, 3, 5, 5, 13, 21, 7, 219, 97, 887, 1845, 469, 2523, 1569, 9959, 4397, 15823}},
-{8958, 17, 27536, {1, 3, 7, 11, 15, 27, 73, 223, 365, 939, 331, 145, 683, 6441, 23421, 59177, 31763}},
-{8959, 17, 27539, {1, 3, 1, 5, 9, 59, 85, 113, 343, 831, 121, 3157, 6059, 14923, 27401, 19759, 14223}},
-{8960, 17, 27541, {1, 3, 1, 7, 17, 25, 3, 39, 471, 759, 2041, 609, 4293, 7491, 8041, 50857, 25601}},
-{8961, 17, 27546, {1, 1, 5, 15, 19, 45, 21, 5, 269, 197, 527, 1839, 1719, 15105, 18671, 42167, 9617}},
-{8962, 17, 27557, {1, 3, 1, 3, 5, 35, 3, 105, 395, 113, 1945, 3945, 3951, 12207, 32135, 34121, 10237}},
-{8963, 17, 27564, {1, 1, 5, 13, 21, 43, 51, 255, 57, 399, 1937, 1573, 363, 11589, 26989, 54345, 94341}},
-{8964, 17, 27572, {1, 3, 3, 3, 5, 45, 83, 125, 179, 923, 39, 3617, 7683, 8191, 31469, 23633, 79179}},
-{8965, 17, 27576, {1, 3, 7, 9, 9, 37, 107, 65, 423, 77, 1779, 1375, 2085, 11779, 6535, 2973, 29425}},
-{8966, 17, 27584, {1, 1, 7, 3, 11, 39, 101, 137, 407, 855, 1767, 1717, 2821, 10447, 31187, 6329, 124111}},
-{8967, 17, 27608, {1, 1, 5, 11, 27, 27, 45, 103, 225, 681, 725, 1791, 2881, 2923, 14473, 12269, 58743}},
-{8968, 17, 27611, {1, 1, 3, 11, 15, 39, 113, 167, 143, 677, 1189, 1571, 5339, 6065, 30187, 19639, 42227}},
-{8969, 17, 27618, {1, 1, 1, 3, 13, 7, 113, 75, 129, 619, 1741, 1495, 4751, 11085, 22391, 199, 105463}},
-{8970, 17, 27620, {1, 1, 3, 3, 19, 47, 77, 195, 209, 453, 495, 1605, 5255, 15327, 8941, 18239, 54511}},
-{8971, 17, 27627, {1, 1, 7, 7, 21, 29, 95, 175, 3, 689, 611, 2467, 6919, 12399, 18869, 16171, 102753}},
-{8972, 17, 27630, {1, 1, 5, 1, 27, 43, 61, 133, 37, 603, 315, 1915, 813, 15769, 27447, 29589, 122281}},
-{8973, 17, 27637, {1, 1, 7, 3, 11, 1, 119, 235, 93, 481, 1811, 1643, 4853, 11313, 8991, 6153, 68985}},
-{8974, 17, 27638, {1, 1, 1, 7, 1, 13, 99, 83, 221, 775, 1345, 219, 4445, 11837, 10405, 43563, 122111}},
-{8975, 17, 27641, {1, 1, 5, 13, 21, 33, 105, 19, 343, 571, 703, 429, 2485, 15531, 9801, 24101, 88275}},
-{8976, 17, 27647, {1, 3, 5, 1, 27, 55, 73, 49, 33, 773, 1411, 1227, 6827, 1271, 28897, 24265, 32383}},
-{8977, 17, 27650, {1, 3, 7, 3, 9, 45, 59, 5, 157, 669, 261, 2077, 1425, 8221, 5849, 40857, 121029}},
-{8978, 17, 27676, {1, 3, 7, 11, 23, 5, 87, 113, 279, 611, 1195, 1775, 5813, 6737, 18051, 41341, 93331}},
-{8979, 17, 27683, {1, 1, 7, 7, 9, 55, 113, 3, 167, 295, 1579, 2833, 4003, 7583, 22833, 44427, 34781}},
-{8980, 17, 27690, {1, 1, 5, 13, 21, 33, 127, 175, 153, 961, 819, 143, 3969, 6159, 29437, 14123, 65317}},
-{8981, 17, 27695, {1, 1, 1, 15, 31, 27, 1, 17, 329, 963, 1907, 421, 535, 2323, 22749, 44375, 115531}},
-{8982, 17, 27700, {1, 1, 5, 15, 15, 23, 57, 171, 253, 401, 1577, 3855, 197, 7979, 17577, 25275, 88831}},
-{8983, 17, 27704, {1, 1, 7, 9, 27, 9, 7, 13, 381, 847, 533, 357, 6551, 13441, 5717, 20209, 64347}},
-{8984, 17, 27709, {1, 1, 7, 9, 1, 1, 31, 245, 315, 901, 1857, 497, 4285, 13227, 3937, 45025, 59627}},
-{8985, 17, 27715, {1, 1, 7, 3, 5, 23, 119, 147, 479, 71, 113, 3379, 863, 8285, 31259, 15863, 47267}},
-{8986, 17, 27727, {1, 3, 5, 1, 5, 7, 77, 163, 421, 353, 1757, 1335, 4975, 3011, 11703, 56075, 12045}},
-{8987, 17, 27745, {1, 1, 5, 3, 31, 25, 81, 59, 211, 463, 1693, 609, 3307, 3641, 19643, 29361, 8399}},
-{8988, 17, 27763, {1, 1, 7, 13, 19, 47, 43, 43, 275, 735, 535, 3689, 3987, 10695, 17243, 60565, 72299}},
-{8989, 17, 27769, {1, 3, 3, 5, 25, 35, 75, 63, 305, 127, 189, 1785, 731, 12089, 27811, 43259, 28191}},
-{8990, 17, 27770, {1, 3, 7, 11, 17, 17, 59, 107, 139, 355, 1055, 3181, 4743, 14785, 26323, 441, 35613}},
-{8991, 17, 27796, {1, 3, 1, 1, 17, 17, 39, 203, 373, 601, 449, 1837, 835, 7061, 14655, 61765, 80735}},
-{8992, 17, 27810, {1, 3, 5, 7, 27, 17, 25, 41, 125, 895, 1843, 3167, 1527, 4707, 6477, 33575, 97247}},
-{8993, 17, 27812, {1, 3, 3, 3, 13, 39, 25, 15, 279, 347, 1121, 3603, 3019, 9577, 16863, 61483, 15995}},
-{8994, 17, 27834, {1, 3, 5, 11, 15, 33, 15, 81, 185, 289, 909, 1237, 3623, 3983, 24211, 62719, 79685}},
-{8995, 17, 27847, {1, 1, 1, 7, 29, 1, 53, 17, 137, 269, 1209, 3937, 4167, 14057, 8061, 38863, 101477}},
-{8996, 17, 27848, {1, 1, 1, 9, 5, 45, 95, 127, 507, 159, 1763, 1527, 5689, 11007, 549, 22837, 99207}},
-{8997, 17, 27862, {1, 3, 3, 1, 15, 57, 127, 39, 73, 397, 67, 3159, 119, 8929, 29425, 57687, 68063}},
-{8998, 17, 27868, {1, 3, 1, 3, 27, 7, 111, 209, 291, 17, 1381, 1597, 5389, 4577, 20463, 28325, 23743}},
-{8999, 17, 27881, {1, 3, 3, 7, 23, 41, 83, 81, 213, 537, 1037, 2371, 1485, 8391, 12471, 58541, 27559}},
-{9000, 17, 27884, {1, 3, 1, 15, 21, 43, 87, 75, 451, 851, 1917, 2739, 2167, 12531, 29931, 8017, 15163}},
-{9001, 17, 27890, {1, 1, 3, 9, 27, 19, 41, 145, 401, 759, 527, 3085, 187, 10615, 4995, 22421, 69867}},
-{9002, 17, 27895, {1, 3, 3, 13, 29, 51, 65, 47, 157, 609, 1061, 1913, 6195, 12503, 10375, 55819, 122091}},
-{9003, 17, 27904, {1, 1, 3, 7, 1, 19, 3, 149, 453, 279, 569, 3429, 331, 711, 26773, 21163, 129339}},
-{9004, 17, 27914, {1, 1, 5, 3, 7, 47, 39, 181, 115, 771, 2037, 411, 2697, 7501, 6393, 19461, 74967}},
-{9005, 17, 27919, {1, 3, 3, 5, 5, 17, 89, 161, 409, 49, 1447, 3977, 4777, 15553, 3521, 32553, 126385}},
-{9006, 17, 27921, {1, 3, 1, 3, 25, 59, 73, 105, 505, 1009, 1147, 317, 3457, 13743, 8337, 38077, 7709}},
-{9007, 17, 27931, {1, 3, 3, 15, 23, 37, 25, 123, 413, 911, 637, 2345, 691, 15199, 22927, 52467, 126715}},
-{9008, 17, 27933, {1, 1, 5, 1, 9, 51, 93, 123, 269, 45, 1947, 179, 5091, 3743, 31491, 39771, 119175}},
-{9009, 17, 27938, {1, 3, 1, 5, 29, 23, 107, 183, 25, 115, 187, 857, 7337, 469, 8755, 17281, 45941}},
-{9010, 17, 27943, {1, 3, 1, 13, 25, 61, 85, 115, 181, 955, 1365, 837, 5941, 13209, 27009, 58865, 115149}},
-{9011, 17, 27949, {1, 1, 1, 11, 31, 63, 101, 29, 37, 185, 465, 2651, 6249, 6887, 25021, 60539, 50037}},
-{9012, 17, 28005, {1, 3, 1, 7, 7, 61, 57, 243, 143, 223, 1759, 4085, 6765, 13293, 31929, 29579, 35053}},
-{9013, 17, 28012, {1, 3, 1, 3, 29, 9, 121, 3, 285, 199, 1439, 3151, 5059, 8535, 17049, 38917, 46347}},
-{9014, 17, 28017, {1, 3, 1, 3, 17, 43, 63, 87, 427, 341, 1251, 3775, 7729, 3183, 10579, 917, 49035}},
-{9015, 17, 28024, {1, 1, 7, 3, 5, 59, 119, 227, 495, 345, 841, 2021, 2483, 15987, 24663, 9819, 33009}},
-{9016, 17, 28030, {1, 1, 5, 11, 19, 57, 23, 181, 63, 991, 1, 2927, 4785, 9645, 17435, 55627, 1069}},
-{9017, 17, 28034, {1, 1, 7, 1, 31, 11, 57, 123, 279, 815, 1407, 3509, 3963, 8503, 20345, 7777, 103701}},
-{9018, 17, 28045, {1, 1, 5, 5, 19, 51, 37, 15, 363, 939, 1863, 3485, 7073, 3035, 31279, 7289, 39811}},
-{9019, 17, 28048, {1, 1, 3, 3, 3, 41, 29, 37, 311, 535, 1993, 3937, 309, 13055, 22595, 59641, 95317}},
-{9020, 17, 28054, {1, 3, 7, 9, 19, 29, 23, 181, 503, 223, 1655, 997, 7861, 5867, 16979, 4559, 7447}},
-{9021, 17, 28063, {1, 3, 5, 3, 13, 13, 3, 137, 361, 101, 1005, 2339, 609, 11891, 15245, 9653, 63579}},
-{9022, 17, 28069, {1, 1, 1, 15, 31, 15, 117, 151, 51, 805, 1403, 3243, 4007, 11979, 3945, 61935, 43225}},
-{9023, 17, 28070, {1, 1, 7, 3, 1, 43, 93, 105, 9, 555, 731, 655, 2097, 8015, 27557, 27985, 11323}},
-{9024, 17, 28073, {1, 3, 3, 9, 23, 35, 59, 217, 437, 755, 685, 1431, 2965, 5269, 25621, 21735, 1397}},
-{9025, 17, 28084, {1, 1, 5, 1, 9, 61, 41, 53, 101, 111, 531, 3385, 4771, 9535, 15995, 29687, 99035}},
-{9026, 17, 28096, {1, 1, 7, 7, 1, 3, 25, 251, 463, 99, 677, 1889, 3697, 5579, 11429, 38301, 57917}},
-{9027, 17, 28114, {1, 1, 5, 9, 11, 15, 65, 31, 369, 825, 1229, 1595, 3891, 5235, 16973, 25307, 7805}},
-{9028, 17, 28126, {1, 3, 7, 15, 27, 37, 35, 103, 393, 781, 1713, 2009, 1973, 15461, 6801, 17557, 105139}},
-{9029, 17, 28141, {1, 3, 7, 7, 17, 51, 83, 29, 113, 173, 1733, 2137, 3041, 11361, 15999, 25779, 112493}},
-{9030, 17, 28149, {1, 3, 5, 11, 19, 3, 89, 103, 449, 375, 437, 4077, 889, 12163, 29323, 48845, 7783}},
-{9031, 17, 28165, {1, 3, 7, 1, 19, 25, 83, 35, 203, 27, 507, 25, 6629, 13941, 6187, 17533, 83349}},
-{9032, 17, 28177, {1, 3, 5, 9, 15, 59, 3, 87, 473, 733, 1263, 1733, 4275, 9283, 32535, 20807, 59487}},
-{9033, 17, 28189, {1, 3, 3, 9, 19, 11, 27, 83, 355, 949, 1339, 171, 921, 14171, 16271, 41485, 20405}},
-{9034, 17, 28190, {1, 1, 3, 11, 25, 51, 9, 241, 367, 519, 1895, 429, 7689, 9469, 32709, 46363, 75767}},
-{9035, 17, 28203, {1, 1, 7, 7, 27, 59, 85, 87, 467, 273, 1763, 391, 451, 16165, 7501, 44779, 68281}},
-{9036, 17, 28206, {1, 1, 7, 5, 1, 35, 5, 217, 31, 145, 1151, 2255, 3543, 401, 17141, 5981, 25183}},
-{9037, 17, 28208, {1, 1, 1, 13, 11, 11, 19, 93, 95, 751, 31, 1091, 2733, 10517, 2553, 5247, 42651}},
-{9038, 17, 28220, {1, 3, 7, 5, 15, 1, 67, 21, 303, 137, 355, 1989, 5211, 4985, 645, 6867, 126931}},
-{9039, 17, 28226, {1, 1, 3, 15, 21, 23, 59, 209, 121, 623, 575, 2447, 6149, 10481, 4959, 22913, 64963}},
-{9040, 17, 28231, {1, 3, 1, 1, 25, 55, 47, 95, 215, 609, 639, 1023, 1579, 5953, 3063, 13721, 17607}},
-{9041, 17, 28249, {1, 1, 1, 11, 7, 61, 127, 173, 307, 623, 453, 3827, 4847, 16085, 4407, 4043, 14881}},
-{9042, 17, 28256, {1, 1, 7, 11, 5, 15, 51, 125, 439, 795, 203, 91, 3543, 6925, 32055, 52277, 26841}},
-{9043, 17, 28259, {1, 1, 1, 13, 15, 9, 107, 183, 391, 751, 243, 1105, 8031, 7443, 137, 45695, 80163}},
-{9044, 17, 28265, {1, 3, 5, 9, 5, 61, 117, 113, 121, 291, 225, 1705, 4017, 13113, 11035, 28613, 25927}},
-{9045, 17, 28266, {1, 1, 3, 11, 27, 9, 45, 85, 309, 991, 1639, 1183, 8013, 14587, 7563, 21111, 48497}},
-{9046, 17, 28271, {1, 3, 1, 9, 21, 61, 123, 189, 265, 593, 163, 3681, 2271, 2795, 753, 48019, 129507}},
-{9047, 17, 28274, {1, 1, 1, 5, 31, 51, 127, 79, 333, 177, 1723, 1365, 2055, 3063, 10693, 61223, 60659}},
-{9048, 17, 28280, {1, 3, 7, 15, 9, 11, 11, 223, 31, 397, 319, 3283, 3765, 4729, 4711, 58323, 114063}},
-{9049, 17, 28296, {1, 1, 7, 11, 7, 63, 107, 215, 19, 491, 131, 2491, 6373, 11081, 2159, 1311, 109547}},
-{9050, 17, 28316, {1, 3, 5, 5, 21, 13, 105, 21, 193, 447, 1331, 2439, 4165, 15689, 21273, 4007, 55161}},
-{9051, 17, 28319, {1, 3, 5, 11, 19, 47, 25, 211, 335, 437, 1041, 2093, 7239, 2869, 18273, 40505, 13681}},
-{9052, 17, 28343, {1, 3, 3, 15, 7, 13, 127, 59, 439, 163, 1841, 1945, 4915, 16269, 18315, 15057, 43197}},
-{9053, 17, 28344, {1, 1, 3, 3, 15, 33, 101, 241, 131, 353, 1749, 3965, 1231, 8167, 9309, 40337, 4419}},
-{9054, 17, 28357, {1, 3, 1, 1, 1, 43, 33, 129, 137, 889, 799, 2937, 3633, 4769, 2411, 56059, 585}},
-{9055, 17, 28358, {1, 1, 3, 9, 25, 31, 45, 199, 229, 175, 1099, 1143, 1721, 11811, 22757, 59843, 117813}},
-{9056, 17, 28364, {1, 1, 7, 7, 19, 45, 43, 101, 219, 209, 1169, 599, 5523, 2463, 15161, 16675, 85111}},
-{9057, 17, 28370, {1, 1, 3, 15, 23, 27, 91, 51, 397, 705, 651, 2345, 3875, 10005, 29523, 42805, 76891}},
-{9058, 17, 28372, {1, 3, 3, 5, 29, 49, 17, 233, 149, 821, 1953, 1931, 7127, 957, 6477, 21259, 126657}},
-{9059, 17, 28379, {1, 3, 3, 3, 27, 49, 57, 145, 143, 1, 583, 3987, 651, 12285, 20139, 51063, 21449}},
-{9060, 17, 28388, {1, 1, 3, 5, 29, 61, 41, 93, 277, 111, 395, 2929, 5325, 15183, 3981, 23799, 72781}},
-{9061, 17, 28392, {1, 1, 7, 5, 25, 43, 85, 137, 401, 261, 1183, 3959, 1983, 16209, 30523, 429, 109181}},
-{9062, 17, 28395, {1, 1, 1, 5, 7, 19, 79, 237, 373, 929, 907, 1771, 6991, 211, 5269, 2135, 32051}},
-{9063, 17, 28406, {1, 1, 7, 5, 17, 15, 41, 49, 363, 15, 1483, 1017, 2439, 11713, 19983, 26275, 11945}},
-{9064, 17, 28418, {1, 1, 7, 7, 19, 5, 55, 15, 15, 573, 1075, 3225, 6815, 11893, 18417, 50833, 71903}},
-{9065, 17, 28423, {1, 1, 7, 9, 23, 37, 75, 3, 477, 291, 37, 1861, 2697, 13369, 24573, 27285, 96757}},
-{9066, 17, 28435, {1, 1, 1, 13, 5, 29, 65, 195, 365, 465, 865, 2705, 5249, 7051, 3795, 56611, 72317}},
-{9067, 17, 28444, {1, 1, 3, 9, 19, 9, 85, 239, 509, 313, 1137, 2221, 5475, 71, 11901, 1877, 68701}},
-{9068, 17, 28454, {1, 3, 3, 7, 3, 53, 55, 223, 441, 159, 933, 2573, 3441, 3295, 25005, 29021, 97145}},
-{9069, 17, 28468, {1, 3, 5, 5, 3, 11, 101, 181, 293, 319, 47, 2971, 387, 4697, 26613, 8531, 20461}},
-{9070, 17, 28477, {1, 3, 3, 13, 17, 11, 41, 233, 455, 353, 1817, 3065, 4657, 1717, 3039, 10937, 107085}},
-{9071, 17, 28478, {1, 1, 7, 1, 17, 23, 85, 5, 291, 725, 1791, 3525, 7705, 6561, 25311, 44679, 21419}},
-{9072, 17, 28480, {1, 1, 7, 1, 23, 41, 97, 117, 435, 261, 2007, 965, 6913, 12245, 25723, 8445, 30871}},
-{9073, 17, 28486, {1, 1, 1, 15, 29, 39, 101, 33, 55, 1019, 1431, 2601, 3837, 14873, 11785, 12449, 30815}},
-{9074, 17, 28489, {1, 1, 5, 3, 15, 35, 101, 7, 479, 535, 1875, 2435, 1461, 13967, 2755, 45879, 93561}},
-{9075, 17, 28500, {1, 3, 1, 5, 29, 57, 89, 209, 473, 289, 1843, 2051, 3997, 1753, 18179, 41355, 89301}},
-{9076, 17, 28507, {1, 3, 1, 11, 17, 45, 47, 57, 109, 309, 1009, 653, 5175, 15599, 21617, 35353, 55253}},
-{9077, 17, 28519, {1, 3, 5, 3, 1, 11, 57, 83, 385, 765, 1887, 785, 2115, 8689, 14783, 14841, 122221}},
-{9078, 17, 28523, {1, 3, 5, 11, 11, 5, 77, 115, 189, 371, 887, 3653, 8159, 15737, 6763, 52807, 128841}},
-{9079, 17, 28534, {1, 1, 1, 11, 11, 33, 9, 145, 439, 565, 171, 3867, 7149, 4369, 15073, 3277, 25873}},
-{9080, 17, 28547, {1, 1, 3, 1, 11, 9, 17, 255, 129, 835, 1705, 1551, 877, 4831, 12717, 2549, 62723}},
-{9081, 17, 28549, {1, 1, 7, 11, 17, 33, 21, 195, 143, 153, 1855, 1323, 1225, 16359, 16479, 8883, 76449}},
-{9082, 17, 28562, {1, 1, 1, 5, 31, 23, 61, 53, 77, 465, 1983, 4019, 4865, 14721, 18601, 48179, 100453}},
-{9083, 17, 28571, {1, 3, 1, 13, 19, 53, 83, 63, 165, 393, 469, 1465, 2669, 10155, 7029, 26185, 121223}},
-{9084, 17, 28583, {1, 1, 1, 3, 3, 3, 123, 23, 45, 359, 1063, 847, 3943, 6113, 23749, 30323, 10583}},
-{9085, 17, 28584, {1, 3, 5, 15, 1, 55, 65, 149, 139, 217, 141, 2425, 7019, 14127, 11725, 50821, 52643}},
-{9086, 17, 28595, {1, 3, 5, 15, 13, 13, 15, 93, 457, 869, 117, 585, 7159, 5957, 15073, 21861, 118119}},
-{9087, 17, 28597, {1, 3, 1, 15, 3, 31, 29, 245, 47, 895, 197, 1169, 945, 11503, 26615, 14079, 27175}},
-{9088, 17, 28604, {1, 3, 5, 5, 31, 1, 107, 109, 253, 999, 1451, 2243, 6675, 10779, 26181, 64597, 16443}},
-{9089, 17, 28607, {1, 3, 7, 15, 9, 53, 25, 41, 151, 197, 1955, 2365, 5305, 2901, 24825, 9595, 57377}},
-{9090, 17, 28609, {1, 3, 1, 3, 25, 37, 37, 193, 417, 373, 1127, 3239, 4583, 2861, 14501, 64163, 30055}},
-{9091, 17, 28612, {1, 3, 7, 9, 7, 21, 49, 231, 241, 95, 1757, 2281, 2679, 1611, 11115, 31743, 26851}},
-{9092, 17, 28630, {1, 3, 5, 5, 1, 1, 23, 173, 195, 593, 1639, 1449, 4733, 2451, 12677, 31959, 128217}},
-{9093, 17, 28640, {1, 1, 1, 7, 17, 49, 117, 253, 167, 721, 889, 3027, 7781, 13521, 15477, 17981, 95487}},
-{9094, 17, 28669, {1, 1, 1, 15, 13, 47, 125, 9, 33, 567, 1733, 1263, 307, 10285, 6325, 55827, 39823}},
-{9095, 17, 28677, {1, 1, 1, 15, 23, 3, 11, 169, 369, 667, 313, 2287, 6655, 16067, 5915, 8605, 92177}},
-{9096, 17, 28682, {1, 3, 3, 15, 13, 21, 125, 111, 171, 785, 79, 2281, 1247, 11321, 30397, 28555, 84863}},
-{9097, 17, 28690, {1, 1, 5, 13, 1, 31, 123, 97, 127, 245, 1213, 2381, 3545, 13545, 28657, 54087, 79039}},
-{9098, 17, 28695, {1, 1, 7, 9, 9, 21, 87, 111, 27, 33, 843, 199, 1465, 6555, 8019, 39521, 98883}},
-{9099, 17, 28696, {1, 3, 3, 5, 5, 55, 61, 219, 279, 207, 1811, 667, 2989, 3133, 25213, 51979, 87695}},
-{9100, 17, 28717, {1, 1, 7, 3, 17, 11, 31, 97, 277, 385, 229, 3045, 557, 13521, 32733, 36831, 43003}},
-{9101, 17, 28730, {1, 3, 5, 13, 27, 57, 31, 207, 147, 405, 1495, 2471, 4889, 14861, 4861, 28185, 62363}},
-{9102, 17, 28737, {1, 1, 5, 13, 23, 19, 5, 21, 509, 299, 1077, 1747, 6229, 2375, 17903, 58473, 72637}},
-{9103, 17, 28752, {1, 3, 7, 11, 15, 61, 63, 165, 27, 461, 1359, 3375, 3029, 9907, 17393, 11097, 43593}},
-{9104, 17, 28761, {1, 3, 5, 1, 17, 29, 15, 5, 419, 19, 1981, 3169, 2389, 9169, 31697, 26201, 6997}},
-{9105, 17, 28774, {1, 3, 3, 1, 29, 31, 89, 79, 347, 707, 505, 2087, 2163, 5465, 8677, 11421, 93217}},
-{9106, 17, 28783, {1, 3, 7, 9, 3, 23, 75, 215, 7, 971, 925, 3223, 7825, 12347, 19763, 10927, 41245}},
-{9107, 17, 28791, {1, 3, 5, 5, 3, 43, 119, 79, 373, 761, 709, 1897, 3953, 13895, 13421, 16939, 112449}},
-{9108, 17, 28801, {1, 1, 3, 15, 11, 25, 65, 101, 315, 1005, 1319, 1163, 161, 15331, 4845, 40375, 121361}},
-{9109, 17, 28802, {1, 1, 3, 7, 1, 57, 63, 131, 145, 1007, 549, 2327, 1513, 3591, 10839, 56297, 80613}},
-{9110, 17, 28814, {1, 1, 3, 5, 1, 19, 79, 81, 505, 945, 65, 319, 6105, 5491, 13257, 4651, 48247}},
-{9111, 17, 28837, {1, 3, 1, 9, 27, 41, 61, 41, 421, 707, 1279, 3699, 2403, 4075, 16947, 53435, 2917}},
-{9112, 17, 28838, {1, 1, 5, 13, 11, 29, 35, 141, 313, 769, 749, 4025, 2597, 12197, 32265, 32159, 37003}},
-{9113, 17, 28842, {1, 3, 7, 11, 25, 63, 121, 15, 273, 877, 637, 409, 5001, 4723, 27985, 55501, 43495}},
-{9114, 17, 28844, {1, 3, 1, 13, 27, 29, 127, 65, 275, 967, 1723, 4007, 6147, 13277, 8361, 12305, 95433}},
-{9115, 17, 28849, {1, 3, 3, 13, 11, 45, 7, 101, 169, 361, 517, 2897, 4283, 7587, 7495, 31549, 29113}},
-{9116, 17, 28864, {1, 3, 3, 1, 9, 27, 65, 15, 279, 127, 1039, 829, 5739, 1949, 24789, 30433, 54503}},
-{9117, 17, 28867, {1, 3, 7, 5, 13, 19, 95, 133, 25, 271, 1527, 3571, 101, 15987, 10985, 55761, 39833}},
-{9118, 17, 28881, {1, 3, 5, 9, 27, 5, 37, 219, 249, 947, 1063, 4081, 1763, 15003, 23753, 3975, 109803}},
-{9119, 17, 28882, {1, 3, 3, 5, 21, 37, 35, 145, 323, 573, 1939, 885, 4645, 4515, 16815, 28783, 76017}},
-{9120, 17, 28893, {1, 3, 7, 13, 27, 41, 39, 123, 423, 949, 1487, 2207, 8069, 15337, 20671, 20163, 70667}},
-{9121, 17, 28903, {1, 1, 3, 3, 15, 29, 69, 15, 151, 729, 35, 2067, 6715, 12759, 27611, 54133, 16561}},
-{9122, 17, 28907, {1, 3, 7, 13, 21, 13, 7, 161, 327, 339, 535, 2059, 413, 11161, 18415, 12415, 63713}},
-{9123, 17, 28909, {1, 3, 5, 5, 23, 49, 9, 181, 417, 339, 1013, 1707, 5097, 13319, 18951, 56415, 14397}},
-{9124, 17, 28921, {1, 1, 5, 7, 29, 23, 117, 159, 287, 695, 71, 2393, 2655, 6417, 24349, 20441, 77987}},
-{9125, 17, 28927, {1, 1, 5, 7, 31, 23, 81, 125, 145, 141, 1459, 4095, 713, 1817, 9263, 21025, 91983}},
-{9126, 17, 28929, {1, 1, 1, 9, 17, 23, 91, 39, 459, 299, 1951, 3229, 6229, 3267, 15883, 31719, 96573}},
-{9127, 17, 28935, {1, 1, 1, 15, 3, 51, 9, 7, 455, 653, 1447, 153, 8117, 723, 2177, 9107, 7757}},
-{9128, 17, 28941, {1, 3, 1, 15, 27, 47, 49, 245, 499, 807, 175, 1653, 1693, 3931, 27479, 30095, 62353}},
-{9129, 17, 28942, {1, 1, 5, 5, 23, 7, 15, 193, 499, 193, 201, 2771, 4153, 11533, 25883, 23337, 126685}},
-{9130, 17, 28954, {1, 1, 1, 7, 9, 43, 125, 181, 425, 557, 1401, 2593, 1933, 6803, 20021, 32687, 126465}},
-{9131, 17, 28959, {1, 3, 3, 13, 27, 19, 99, 29, 395, 765, 1137, 2963, 7397, 9695, 19259, 27965, 83157}},
-{9132, 17, 28960, {1, 3, 7, 7, 17, 29, 7, 241, 5, 281, 1489, 1599, 5567, 4579, 7739, 41413, 110571}},
-{9133, 17, 28990, {1, 3, 3, 9, 7, 5, 83, 1, 231, 1003, 631, 2557, 831, 6495, 30409, 53519, 79331}},
-{9134, 17, 28992, {1, 1, 5, 1, 7, 49, 45, 241, 201, 551, 1645, 2003, 1455, 3317, 23639, 7841, 100765}},
-{9135, 17, 29004, {1, 3, 5, 13, 25, 47, 103, 37, 81, 263, 1143, 801, 5863, 6871, 8615, 57363, 90161}},
-{9136, 17, 29010, {1, 3, 7, 11, 27, 23, 119, 211, 473, 207, 605, 637, 3369, 7287, 27827, 25003, 65925}},
-{9137, 17, 29012, {1, 3, 1, 15, 27, 31, 97, 247, 75, 893, 1099, 3609, 6807, 4393, 10253, 62759, 89971}},
-{9138, 17, 29021, {1, 1, 7, 15, 27, 19, 43, 59, 419, 263, 387, 3193, 5589, 4197, 19143, 64749, 103093}},
-{9139, 17, 29035, {1, 1, 7, 11, 21, 51, 97, 227, 251, 869, 1927, 2331, 7741, 8207, 12885, 13267, 17945}},
-{9140, 17, 29040, {1, 1, 7, 7, 5, 53, 41, 147, 75, 709, 607, 1073, 2853, 8081, 12797, 5279, 86083}},
-{9141, 17, 29059, {1, 1, 5, 5, 15, 21, 77, 189, 269, 595, 197, 3117, 5073, 14277, 26867, 49505, 75755}},
-{9142, 17, 29068, {1, 3, 5, 15, 13, 55, 1, 223, 135, 367, 735, 3139, 4851, 9773, 11699, 19081, 26011}},
-{9143, 17, 29080, {1, 3, 5, 7, 9, 3, 89, 103, 321, 727, 1809, 3527, 6881, 2399, 13593, 27867, 16219}},
-{9144, 17, 29086, {1, 3, 3, 1, 23, 5, 53, 51, 403, 753, 2037, 1261, 7575, 2725, 11341, 18533, 98767}},
-{9145, 17, 29089, {1, 1, 1, 11, 1, 13, 37, 141, 477, 689, 1789, 1913, 5753, 6069, 6965, 55209, 77329}},
-{9146, 17, 29090, {1, 3, 7, 3, 17, 59, 79, 249, 381, 163, 1773, 1645, 7295, 2359, 21889, 28429, 117073}},
-{9147, 17, 29095, {1, 3, 5, 15, 7, 45, 59, 3, 93, 259, 1257, 2967, 1175, 10171, 873, 51423, 67437}},
-{9148, 17, 29113, {1, 1, 7, 13, 17, 33, 53, 217, 159, 683, 1169, 3363, 4591, 3959, 10089, 35443, 99677}},
-{9149, 17, 29127, {1, 3, 7, 9, 3, 1, 5, 171, 17, 635, 369, 1529, 4861, 4977, 29303, 42357, 69309}},
-{9150, 17, 29131, {1, 3, 7, 9, 21, 17, 77, 127, 105, 427, 525, 1123, 2365, 7487, 6315, 64773, 122747}},
-{9151, 17, 29148, {1, 1, 1, 15, 19, 63, 65, 83, 219, 987, 169, 2589, 3809, 8807, 22473, 6479, 44617}},
-{9152, 17, 29161, {1, 3, 1, 7, 11, 51, 107, 19, 379, 191, 1013, 3145, 1501, 11871, 14111, 18269, 98247}},
-{9153, 17, 29172, {1, 1, 7, 5, 17, 63, 23, 231, 423, 855, 1955, 907, 4553, 16173, 7701, 40329, 42047}},
-{9154, 17, 29179, {1, 3, 7, 1, 7, 45, 103, 127, 185, 721, 1035, 839, 691, 6823, 23819, 50781, 92767}},
-{9155, 17, 29188, {1, 1, 1, 3, 9, 21, 57, 253, 285, 85, 1227, 365, 2347, 7491, 15183, 8619, 108819}},
-{9156, 17, 29192, {1, 1, 3, 15, 27, 13, 5, 85, 45, 1009, 1315, 1749, 2797, 3941, 19367, 50855, 60693}},
-{9157, 17, 29195, {1, 3, 5, 15, 29, 63, 115, 197, 317, 601, 711, 377, 7489, 4247, 4843, 56549, 108447}},
-{9158, 17, 29206, {1, 3, 7, 15, 11, 25, 7, 145, 371, 395, 1743, 267, 2609, 15707, 13909, 55031, 71115}},
-{9159, 17, 29210, {1, 3, 1, 1, 1, 53, 111, 245, 433, 309, 245, 15, 2091, 9051, 11095, 31821, 104535}},
-{9160, 17, 29215, {1, 3, 1, 15, 25, 31, 99, 89, 259, 595, 1095, 3681, 5105, 8671, 23663, 29717, 126429}},
-{9161, 17, 29221, {1, 3, 7, 7, 5, 31, 15, 59, 109, 527, 257, 1785, 6799, 1283, 11741, 34589, 102397}},
-{9162, 17, 29222, {1, 3, 3, 15, 9, 27, 55, 35, 291, 587, 1281, 779, 4615, 373, 24037, 64671, 124019}},
-{9163, 17, 29236, {1, 1, 5, 5, 13, 51, 49, 19, 37, 857, 539, 1291, 6021, 8645, 30351, 33839, 111515}},
-{9164, 17, 29246, {1, 1, 5, 13, 3, 47, 9, 197, 19, 337, 2025, 3003, 7179, 5755, 31187, 59317, 69753}},
-{9165, 17, 29248, {1, 1, 7, 3, 3, 43, 11, 3, 123, 29, 857, 3349, 791, 11157, 23967, 33729, 28445}},
-{9166, 17, 29253, {1, 1, 5, 1, 1, 11, 73, 231, 173, 925, 331, 161, 3303, 11015, 17507, 21271, 56865}},
-{9167, 17, 29272, {1, 1, 3, 9, 21, 21, 115, 145, 421, 981, 1789, 3343, 7591, 12043, 5795, 17737, 106501}},
-{9168, 17, 29288, {1, 1, 7, 13, 7, 15, 51, 75, 497, 637, 1073, 1505, 5613, 1415, 30861, 26159, 79573}},
-{9169, 17, 29293, {1, 1, 3, 15, 17, 35, 17, 129, 169, 283, 1383, 149, 211, 1381, 22205, 28367, 831}},
-{9170, 17, 29294, {1, 3, 5, 5, 17, 11, 127, 183, 503, 499, 2011, 2721, 2717, 3105, 4731, 60319, 9361}},
-{9171, 17, 29308, {1, 1, 1, 7, 27, 55, 77, 203, 255, 761, 1159, 2915, 4479, 13671, 19757, 65497, 4461}},
-{9172, 17, 29318, {1, 3, 1, 9, 9, 51, 67, 205, 445, 35, 371, 1837, 3623, 10365, 19463, 59005, 3185}},
-{9173, 17, 29321, {1, 3, 7, 3, 23, 5, 51, 141, 293, 489, 263, 2187, 1259, 2729, 1779, 61027, 53931}},
-{9174, 17, 29322, {1, 1, 1, 15, 27, 7, 15, 109, 475, 839, 175, 953, 4531, 437, 22475, 24167, 19051}},
-{9175, 17, 29339, {1, 1, 7, 9, 25, 23, 41, 107, 299, 115, 1713, 1559, 5701, 5427, 28813, 39913, 15941}},
-{9176, 17, 29365, {1, 3, 5, 7, 5, 25, 99, 9, 307, 591, 1303, 3501, 1589, 12095, 26629, 52127, 60635}},
-{9177, 17, 29369, {1, 3, 7, 3, 9, 23, 3, 29, 113, 49, 1601, 541, 1415, 11601, 19165, 46595, 111623}},
-{9178, 17, 29372, {1, 1, 3, 11, 5, 53, 37, 153, 51, 41, 1267, 545, 2055, 13137, 7749, 30721, 119591}},
-{9179, 17, 29377, {1, 3, 5, 11, 1, 15, 65, 17, 155, 65, 745, 2547, 6351, 2347, 13553, 5785, 129857}},
-{9180, 17, 29392, {1, 3, 7, 13, 5, 53, 11, 59, 453, 467, 1275, 3669, 4481, 5229, 2953, 23369, 100161}},
-{9181, 17, 29401, {1, 3, 1, 1, 13, 41, 91, 179, 331, 547, 1571, 1787, 6467, 12375, 4579, 45023, 119149}},
-{9182, 17, 29402, {1, 3, 3, 5, 17, 55, 105, 57, 227, 323, 1517, 1215, 3149, 13919, 18595, 5525, 82445}},
-{9183, 17, 29418, {1, 3, 1, 13, 19, 23, 17, 239, 81, 481, 1625, 2003, 7295, 2185, 7021, 19357, 37867}},
-{9184, 17, 29437, {1, 3, 5, 9, 11, 15, 61, 223, 153, 139, 2023, 2579, 495, 14319, 2835, 26541, 113115}},
-{9185, 17, 29445, {1, 1, 3, 13, 29, 9, 13, 149, 325, 87, 697, 2345, 2205, 5069, 9939, 61351, 127313}},
-{9186, 17, 29446, {1, 1, 7, 11, 13, 53, 45, 197, 167, 551, 439, 3715, 4587, 8549, 28193, 35827, 96721}},
-{9187, 17, 29460, {1, 3, 1, 1, 17, 7, 31, 205, 219, 739, 1165, 243, 3877, 15943, 15207, 43857, 120565}},
-{9188, 17, 29467, {1, 3, 7, 9, 7, 43, 81, 203, 295, 553, 279, 2717, 9, 751, 24715, 21591, 11485}},
-{9189, 17, 29473, {1, 1, 1, 11, 15, 17, 41, 121, 355, 157, 955, 3875, 7595, 235, 4937, 20607, 11401}},
-{9190, 17, 29476, {1, 1, 7, 7, 13, 49, 33, 161, 65, 251, 1895, 2665, 3017, 9725, 10797, 46313, 43407}},
-{9191, 17, 29488, {1, 1, 3, 9, 23, 17, 127, 69, 385, 875, 461, 3305, 3001, 5875, 13547, 61239, 113571}},
-{9192, 17, 29511, {1, 3, 7, 5, 15, 47, 113, 131, 465, 89, 733, 433, 799, 5689, 723, 63479, 106945}},
-{9193, 17, 29512, {1, 3, 3, 15, 29, 1, 51, 115, 317, 1021, 1219, 1797, 4005, 10435, 28935, 49467, 66833}},
-{9194, 17, 29517, {1, 1, 3, 11, 15, 9, 51, 209, 477, 479, 1099, 2781, 5525, 12715, 9067, 18317, 121671}},
-{9195, 17, 29523, {1, 3, 1, 7, 19, 35, 61, 27, 479, 815, 1639, 2825, 7449, 13697, 3079, 49833, 35119}},
-{9196, 17, 29526, {1, 3, 7, 3, 17, 53, 95, 155, 505, 185, 717, 3419, 3857, 2369, 14525, 22797, 38553}},
-{9197, 17, 29535, {1, 3, 1, 13, 27, 5, 11, 21, 507, 65, 39, 2841, 7887, 2783, 18767, 34171, 40527}},
-{9198, 17, 29539, {1, 3, 1, 7, 9, 47, 69, 217, 251, 775, 631, 1967, 5541, 10679, 16439, 33533, 57817}},
-{9199, 17, 29545, {1, 1, 5, 11, 27, 57, 103, 255, 359, 745, 63, 3725, 4113, 10943, 7833, 46857, 99239}},
-{9200, 17, 29559, {1, 3, 1, 5, 31, 41, 69, 245, 401, 451, 959, 351, 6999, 6187, 21437, 55067, 53547}},
-{9201, 17, 29560, {1, 1, 1, 13, 25, 49, 85, 181, 457, 731, 743, 1901, 7013, 12027, 14729, 24193, 89685}},
-{9202, 17, 29589, {1, 3, 3, 1, 31, 29, 101, 137, 117, 135, 345, 1419, 7133, 2695, 3631, 53049, 45875}},
-{9203, 17, 29593, {1, 1, 1, 13, 11, 51, 95, 221, 339, 655, 201, 3007, 8179, 8093, 22399, 59123, 127319}},
-{9204, 17, 29599, {1, 3, 7, 3, 31, 37, 23, 199, 191, 649, 817, 1959, 893, 2333, 21477, 29087, 115667}},
-{9205, 17, 29603, {1, 3, 3, 5, 9, 55, 123, 67, 39, 533, 797, 2575, 3955, 14585, 28587, 13079, 60053}},
-{9206, 17, 29610, {1, 3, 1, 1, 17, 19, 15, 219, 185, 21, 967, 667, 3361, 3883, 8059, 26199, 80913}},
-{9207, 17, 29629, {1, 3, 3, 11, 23, 5, 99, 57, 379, 151, 271, 3735, 7087, 12731, 2949, 54831, 37835}},
-{9208, 17, 29644, {1, 3, 1, 7, 21, 25, 9, 195, 497, 585, 901, 19, 7675, 13611, 31155, 14567, 20545}},
-{9209, 17, 29656, {1, 1, 3, 3, 27, 45, 51, 169, 397, 531, 673, 2935, 3779, 7169, 23479, 16157, 100237}},
-{9210, 17, 29662, {1, 1, 1, 1, 19, 49, 3, 75, 455, 805, 591, 1929, 2883, 2797, 31379, 12025, 120929}},
-{9211, 17, 29675, {1, 3, 5, 3, 17, 39, 115, 93, 341, 329, 1857, 2753, 4923, 12539, 25589, 19437, 29027}},
-{9212, 17, 29692, {1, 3, 5, 9, 27, 37, 21, 235, 499, 369, 1341, 3719, 6819, 3153, 30619, 50901, 52999}},
-{9213, 17, 29704, {1, 3, 1, 11, 3, 55, 43, 219, 83, 771, 783, 3569, 7879, 2363, 30605, 5965, 126855}},
-{9214, 17, 29707, {1, 3, 7, 13, 7, 25, 111, 63, 355, 317, 1579, 1523, 2733, 11963, 25205, 20545, 67389}},
-{9215, 17, 29715, {1, 3, 5, 7, 3, 17, 55, 99, 321, 633, 2013, 1991, 1019, 9223, 21117, 23337, 90589}},
-{9216, 17, 29717, {1, 3, 1, 1, 17, 25, 79, 171, 303, 403, 2037, 2595, 3951, 8021, 8669, 9363, 20345}},
-{9217, 17, 29722, {1, 1, 1, 7, 13, 7, 11, 7, 347, 53, 1763, 3097, 3353, 3769, 22947, 20919, 92247}},
-{9218, 17, 29731, {1, 3, 5, 11, 19, 29, 91, 191, 511, 705, 1317, 3367, 7, 4999, 30251, 18299, 66983}},
-{9219, 17, 29740, {1, 1, 3, 7, 19, 17, 71, 77, 285, 189, 853, 2305, 4205, 15603, 15501, 48073, 11411}},
-{9220, 17, 29743, {1, 3, 7, 5, 21, 15, 47, 13, 277, 969, 1861, 3493, 6723, 11521, 22145, 43779, 44713}},
-{9221, 17, 29752, {1, 1, 3, 5, 19, 47, 51, 207, 229, 957, 709, 267, 8081, 611, 26403, 14871, 111841}},
-{9222, 17, 29760, {1, 3, 7, 1, 19, 43, 71, 73, 405, 351, 1131, 3527, 5949, 14363, 20041, 48123, 68123}},
-{9223, 17, 29766, {1, 3, 3, 7, 23, 51, 81, 13, 161, 453, 365, 1089, 3505, 12359, 14277, 56113, 19717}},
-{9224, 17, 29770, {1, 1, 1, 7, 29, 35, 103, 137, 317, 417, 1465, 2787, 6935, 9885, 12943, 43937, 28353}},
-{9225, 17, 29794, {1, 1, 3, 13, 19, 37, 97, 5, 115, 89, 1005, 3033, 2011, 2633, 10615, 6641, 73385}},
-{9226, 17, 29796, {1, 3, 7, 7, 31, 39, 107, 165, 61, 1009, 1159, 865, 3469, 11093, 10425, 43959, 37395}},
-{9227, 17, 29814, {1, 3, 5, 9, 7, 51, 99, 91, 37, 457, 39, 2455, 7481, 4929, 29755, 50603, 48943}},
-{9228, 17, 29817, {1, 1, 5, 13, 5, 39, 47, 149, 341, 303, 843, 3619, 7527, 8739, 5893, 42623, 99899}},
-{9229, 17, 29829, {1, 1, 1, 1, 1, 41, 73, 71, 409, 351, 131, 515, 6657, 337, 23913, 583, 21665}},
-{9230, 17, 29841, {1, 1, 3, 3, 11, 45, 39, 113, 315, 965, 1605, 2779, 501, 7429, 2567, 7011, 71445}},
-{9231, 17, 29851, {1, 3, 7, 13, 21, 13, 45, 105, 385, 281, 1683, 3997, 6391, 10943, 22349, 37261, 57555}},
-{9232, 17, 29860, {1, 1, 3, 5, 17, 55, 109, 71, 393, 561, 433, 1091, 1923, 13861, 12981, 5523, 15467}},
-{9233, 17, 29864, {1, 3, 7, 5, 17, 11, 113, 119, 37, 989, 1609, 2191, 1511, 11835, 25423, 793, 15227}},
-{9234, 17, 29869, {1, 3, 1, 5, 5, 55, 105, 225, 349, 351, 1259, 1309, 821, 2733, 1357, 3665, 38863}},
-{9235, 17, 29870, {1, 3, 5, 1, 23, 61, 49, 113, 169, 319, 85, 1581, 97, 5271, 30625, 37693, 7297}},
-{9236, 17, 29889, {1, 3, 5, 1, 1, 25, 31, 125, 307, 731, 1815, 1047, 7251, 12481, 20781, 63275, 51985}},
-{9237, 17, 29896, {1, 3, 5, 9, 11, 9, 121, 111, 45, 751, 793, 2593, 6409, 4355, 30183, 36959, 105161}},
-{9238, 17, 29901, {1, 1, 3, 9, 25, 37, 95, 253, 401, 481, 1521, 3555, 231, 15459, 1581, 36661, 121727}},
-{9239, 17, 29913, {1, 3, 5, 3, 27, 11, 107, 115, 213, 813, 27, 1789, 603, 383, 1129, 63365, 51147}},
-{9240, 17, 29919, {1, 1, 3, 13, 25, 7, 33, 1, 97, 907, 35, 4069, 5001, 507, 911, 62037, 22019}},
-{9241, 17, 29920, {1, 1, 3, 5, 7, 55, 35, 95, 261, 217, 1565, 3473, 3475, 12181, 569, 27389, 81771}},
-{9242, 17, 29947, {1, 1, 3, 5, 11, 33, 95, 121, 453, 711, 361, 3927, 5231, 15685, 31143, 56915, 23707}},
-{9243, 17, 29958, {1, 1, 3, 11, 25, 15, 53, 155, 469, 647, 1547, 335, 3753, 12873, 13639, 25129, 79287}},
-{9244, 17, 29975, {1, 3, 3, 3, 1, 21, 21, 121, 105, 903, 83, 2287, 4295, 14369, 29183, 26841, 38115}},
-{9245, 17, 29981, {1, 1, 7, 11, 5, 29, 65, 191, 389, 419, 1315, 739, 3485, 10587, 2399, 36377, 28789}},
-{9246, 17, 29985, {1, 3, 3, 11, 3, 29, 71, 169, 265, 747, 395, 1211, 3487, 15705, 25611, 18183, 85771}},
-{9247, 17, 29998, {1, 1, 7, 3, 23, 5, 45, 47, 337, 571, 33, 1221, 5671, 1233, 28361, 36945, 911}},
-{9248, 17, 30010, {1, 1, 5, 11, 17, 15, 57, 97, 185, 999, 1277, 3371, 2785, 3341, 13395, 11925, 86777}},
-{9249, 17, 30012, {1, 1, 3, 1, 31, 37, 23, 105, 503, 869, 1309, 3733, 4629, 8263, 11763, 30669, 26179}},
-{9250, 17, 30044, {1, 1, 3, 15, 25, 61, 37, 27, 325, 413, 809, 2959, 8137, 3397, 21185, 27995, 84297}},
-{9251, 17, 30048, {1, 3, 5, 5, 1, 55, 95, 41, 493, 469, 331, 1789, 7037, 7947, 14239, 16109, 51795}},
-{9252, 17, 30051, {1, 1, 1, 1, 19, 33, 111, 237, 261, 331, 871, 3539, 1731, 6953, 11345, 37901, 5623}},
-{9253, 17, 30063, {1, 1, 5, 7, 21, 41, 49, 179, 49, 797, 231, 1299, 145, 7743, 725, 60595, 19581}},
-{9254, 17, 30065, {1, 3, 7, 15, 7, 43, 67, 219, 133, 641, 1657, 2301, 1591, 12309, 6395, 3999, 92961}},
-{9255, 17, 30072, {1, 1, 1, 5, 1, 49, 37, 81, 219, 323, 461, 1379, 1797, 14825, 21811, 7347, 35643}},
-{9256, 17, 30077, {1, 1, 1, 11, 1, 3, 83, 31, 307, 83, 1169, 3277, 1875, 13397, 20265, 46707, 15205}},
-{9257, 17, 30087, {1, 3, 7, 11, 29, 41, 69, 33, 405, 991, 1937, 1217, 2137, 8657, 4319, 41119, 43371}},
-{9258, 17, 30088, {1, 3, 3, 3, 25, 49, 107, 197, 347, 923, 1585, 3023, 4087, 13875, 22015, 35733, 33755}},
-{9259, 17, 30101, {1, 3, 3, 5, 15, 61, 89, 249, 141, 853, 1469, 999, 7425, 10015, 12341, 51535, 61619}},
-{9260, 17, 30112, {1, 1, 7, 13, 31, 61, 89, 113, 117, 429, 1011, 1589, 1419, 5083, 4843, 26759, 47401}},
-{9261, 17, 30121, {1, 1, 7, 9, 17, 37, 119, 39, 499, 93, 1155, 3069, 2033, 12483, 29849, 40077, 11103}},
-{9262, 17, 30122, {1, 3, 1, 15, 11, 5, 23, 121, 283, 717, 1573, 3911, 2031, 2617, 20387, 33157, 301}},
-{9263, 17, 30130, {1, 3, 5, 7, 17, 61, 109, 3, 205, 617, 1171, 223, 6609, 15027, 2629, 15801, 73749}},
-{9264, 17, 30135, {1, 1, 3, 7, 5, 49, 9, 73, 333, 401, 675, 2765, 993, 77, 19237, 60929, 88703}},
-{9265, 17, 30139, {1, 1, 1, 9, 21, 25, 53, 249, 241, 43, 1959, 545, 3729, 11395, 3027, 12661, 87729}},
-{9266, 17, 30142, {1, 3, 3, 15, 15, 61, 33, 59, 155, 773, 1043, 3111, 6549, 5397, 29099, 57851, 107671}},
-{9267, 17, 30164, {1, 3, 7, 1, 29, 29, 1, 161, 273, 883, 1913, 2389, 401, 9425, 17613, 50443, 84601}},
-{9268, 17, 30167, {1, 3, 7, 11, 15, 63, 41, 53, 371, 153, 1491, 3013, 6635, 4955, 30145, 20175, 16541}},
-{9269, 17, 30180, {1, 3, 3, 11, 31, 27, 127, 207, 11, 313, 1067, 3445, 3075, 4071, 28305, 58911, 85273}},
-{9270, 17, 30202, {1, 1, 7, 11, 17, 47, 77, 119, 209, 657, 1181, 459, 5821, 4267, 5757, 53703, 35621}},
-{9271, 17, 30211, {1, 3, 1, 15, 27, 41, 3, 217, 457, 531, 1749, 2847, 4715, 11451, 25071, 53999, 93503}},
-{9272, 17, 30214, {1, 3, 5, 3, 19, 29, 9, 177, 355, 265, 883, 1113, 2397, 1819, 20757, 50389, 95551}},
-{9273, 17, 30217, {1, 1, 3, 15, 3, 45, 85, 211, 377, 293, 1791, 1193, 1117, 9383, 28039, 27155, 129513}},
-{9274, 17, 30223, {1, 1, 7, 5, 1, 17, 59, 215, 161, 933, 1653, 2407, 2693, 3655, 7515, 2239, 88985}},
-{9275, 17, 30228, {1, 1, 3, 11, 31, 3, 1, 77, 459, 817, 651, 603, 1711, 9391, 20607, 48195, 127153}},
-{9276, 17, 30235, {1, 1, 5, 13, 11, 49, 25, 13, 51, 443, 1877, 1257, 163, 4673, 30313, 18841, 24547}},
-{9277, 17, 30256, {1, 1, 7, 7, 15, 33, 43, 79, 127, 625, 1991, 1311, 2095, 14659, 3477, 56023, 57955}},
-{9278, 17, 30265, {1, 3, 7, 15, 29, 7, 119, 183, 123, 323, 1723, 959, 2733, 2097, 2927, 57595, 86067}},
-{9279, 17, 30286, {1, 3, 5, 5, 29, 57, 93, 139, 495, 739, 1715, 713, 243, 2027, 11223, 44143, 119155}},
-{9280, 17, 30293, {1, 3, 1, 9, 3, 63, 113, 29, 19, 439, 869, 1101, 4947, 2191, 14737, 57049, 93505}},
-{9281, 17, 30298, {1, 1, 7, 1, 11, 39, 27, 29, 281, 829, 1979, 2185, 2207, 14969, 7447, 55541, 59593}},
-{9282, 17, 30310, {1, 1, 7, 13, 11, 15, 15, 143, 383, 469, 1439, 2823, 7489, 7675, 15433, 26203, 80433}},
-{9283, 17, 30314, {1, 1, 1, 7, 15, 45, 23, 93, 477, 1, 1431, 3173, 7879, 12211, 13051, 56971, 114289}},
-{9284, 17, 30327, {1, 3, 1, 1, 27, 55, 61, 185, 323, 569, 1063, 1357, 7373, 14947, 15967, 64517, 104625}},
-{9285, 17, 30333, {1, 1, 5, 11, 25, 1, 127, 163, 419, 657, 911, 361, 3675, 10765, 24565, 2661, 61979}},
-{9286, 17, 30334, {1, 3, 7, 15, 29, 53, 29, 149, 465, 535, 1865, 2243, 4783, 9327, 24843, 52313, 15683}},
-{9287, 17, 30337, {1, 1, 7, 7, 17, 7, 85, 187, 91, 1013, 1917, 2959, 3571, 12047, 25267, 34095, 9877}},
-{9288, 17, 30338, {1, 1, 1, 7, 5, 27, 111, 107, 313, 571, 1081, 3193, 1025, 2589, 1523, 40453, 77065}},
-{9289, 17, 30344, {1, 3, 7, 1, 19, 27, 1, 103, 479, 405, 583, 1737, 3495, 9093, 20397, 16429, 45609}},
-{9290, 17, 30349, {1, 1, 3, 11, 17, 1, 125, 97, 261, 651, 901, 1245, 1181, 14469, 16229, 31935, 100227}},
-{9291, 17, 30352, {1, 1, 7, 11, 15, 1, 19, 151, 453, 833, 1371, 1109, 5373, 25, 5619, 58351, 26349}},
-{9292, 17, 30362, {1, 1, 7, 15, 17, 55, 51, 67, 123, 13, 1873, 1035, 5871, 11943, 11543, 43261, 62587}},
-{9293, 17, 30374, {1, 3, 1, 13, 21, 15, 83, 205, 333, 379, 2021, 1389, 861, 10395, 20587, 38207, 49109}},
-{9294, 17, 30380, {1, 1, 5, 3, 13, 49, 89, 85, 463, 1005, 1367, 3487, 581, 12145, 22445, 35343, 65745}},
-{9295, 17, 30388, {1, 3, 3, 3, 29, 27, 99, 195, 89, 793, 1677, 3989, 4811, 8303, 9165, 50349, 96947}},
-{9296, 17, 30391, {1, 1, 3, 5, 29, 11, 91, 107, 13, 659, 213, 1613, 2245, 11567, 28157, 2937, 53275}},
-{9297, 17, 30395, {1, 3, 7, 5, 3, 41, 65, 27, 93, 747, 1143, 505, 3881, 2123, 2903, 54137, 96185}},
-{9298, 17, 30403, {1, 1, 3, 15, 9, 49, 3, 25, 77, 681, 1709, 915, 2243, 2127, 18243, 13915, 67399}},
-{9299, 17, 30409, {1, 3, 5, 7, 13, 49, 89, 67, 63, 271, 1651, 897, 4035, 1067, 13743, 56791, 44371}},
-{9300, 17, 30424, {1, 1, 7, 9, 25, 19, 125, 15, 125, 705, 1359, 817, 1241, 12447, 19097, 33209, 89091}},
-{9301, 17, 30427, {1, 3, 7, 3, 19, 43, 127, 197, 39, 709, 257, 3547, 3069, 1187, 21255, 6453, 40763}},
-{9302, 17, 30430, {1, 3, 3, 5, 3, 53, 37, 65, 415, 183, 991, 533, 7805, 9905, 18925, 52665, 100987}},
-{9303, 17, 30451, {1, 3, 3, 11, 17, 41, 17, 137, 143, 277, 945, 1531, 7427, 7287, 30869, 27651, 116507}},
-{9304, 17, 30460, {1, 1, 1, 3, 13, 3, 9, 163, 113, 373, 1909, 1051, 97, 10729, 28615, 40081, 129297}},
-{9305, 17, 30475, {1, 3, 3, 9, 11, 47, 113, 27, 307, 339, 1319, 3083, 7383, 1551, 26691, 28769, 114313}},
-{9306, 17, 30480, {1, 3, 7, 7, 25, 49, 31, 231, 485, 629, 59, 283, 7463, 6603, 23055, 63643, 10121}},
-{9307, 17, 30485, {1, 3, 7, 9, 5, 55, 53, 127, 147, 103, 1697, 485, 7051, 14153, 21631, 35561, 10393}},
-{9308, 17, 30486, {1, 3, 3, 7, 23, 7, 83, 17, 135, 487, 315, 719, 7003, 3919, 13255, 24031, 110493}},
-{9309, 17, 30489, {1, 3, 1, 15, 27, 55, 121, 177, 205, 733, 933, 1535, 2925, 4259, 22203, 59059, 89209}},
-{9310, 17, 30492, {1, 1, 1, 11, 9, 11, 127, 47, 493, 349, 1415, 3089, 4739, 14347, 31579, 20739, 72997}},
-{9311, 17, 30499, {1, 3, 1, 7, 9, 31, 121, 111, 163, 733, 1699, 1507, 5467, 13499, 25269, 6303, 70201}},
-{9312, 17, 30511, {1, 3, 1, 5, 7, 23, 123, 203, 329, 387, 577, 2331, 2283, 14029, 19409, 103, 2477}},
-{9313, 17, 30533, {1, 1, 7, 15, 11, 29, 29, 153, 289, 333, 1669, 2065, 5465, 8835, 28753, 21209, 34283}},
-{9314, 17, 30534, {1, 3, 5, 11, 15, 33, 45, 81, 241, 461, 1167, 1073, 5511, 795, 30955, 49121, 42805}},
-{9315, 17, 30540, {1, 1, 1, 13, 7, 33, 11, 201, 161, 475, 1359, 2329, 177, 9883, 8967, 21399, 73045}},
-{9316, 17, 30545, {1, 3, 3, 1, 25, 59, 85, 51, 481, 751, 1213, 3019, 421, 9903, 30071, 50661, 94715}},
-{9317, 17, 30552, {1, 3, 3, 1, 5, 61, 3, 179, 131, 233, 1627, 3577, 6323, 14161, 21595, 44963, 20215}},
-{9318, 17, 30557, {1, 1, 1, 5, 9, 53, 45, 105, 275, 769, 105, 2757, 6769, 14987, 19955, 18291, 81707}},
-{9319, 17, 30558, {1, 1, 7, 1, 1, 59, 33, 19, 385, 775, 423, 1799, 1325, 13545, 16027, 58347, 102397}},
-{9320, 17, 30567, {1, 1, 3, 11, 15, 61, 63, 59, 355, 659, 1483, 3781, 7383, 5563, 32537, 34175, 40303}},
-{9321, 17, 30568, {1, 3, 5, 7, 5, 37, 19, 223, 323, 129, 287, 2655, 3767, 16201, 4147, 315, 54885}},
-{9322, 17, 30581, {1, 1, 7, 13, 13, 23, 43, 129, 405, 205, 1691, 2189, 3313, 11789, 10263, 16367, 65547}},
-{9323, 17, 30597, {1, 3, 5, 1, 15, 21, 85, 233, 427, 71, 475, 3731, 3335, 11483, 28613, 4335, 35669}},
-{9324, 17, 30607, {1, 1, 3, 3, 31, 47, 27, 109, 373, 451, 1459, 3103, 1941, 10405, 20233, 30517, 122787}},
-{9325, 17, 30621, {1, 3, 1, 7, 3, 11, 113, 49, 355, 465, 1959, 1355, 6521, 10863, 11481, 13385, 31787}},
-{9326, 17, 30632, {1, 3, 1, 1, 9, 45, 125, 69, 267, 413, 717, 2767, 833, 317, 23019, 37753, 3081}},
-{9327, 17, 30650, {1, 1, 7, 7, 13, 55, 75, 105, 71, 505, 239, 3739, 4873, 4257, 18841, 41711, 24045}},
-{9328, 17, 30655, {1, 1, 5, 13, 21, 59, 107, 229, 421, 441, 1079, 3727, 7941, 8443, 30433, 56419, 105751}},
-{9329, 17, 30657, {1, 1, 1, 9, 15, 59, 29, 49, 117, 1009, 1971, 115, 2899, 1069, 29145, 11855, 35277}},
-{9330, 17, 30660, {1, 3, 7, 15, 19, 55, 111, 77, 169, 537, 1695, 2687, 3871, 14017, 15119, 27313, 112807}},
-{9331, 17, 30669, {1, 1, 3, 7, 29, 5, 41, 201, 211, 127, 1877, 643, 2441, 8743, 29393, 6077, 52597}},
-{9332, 17, 30675, {1, 3, 1, 11, 7, 1, 95, 15, 229, 339, 475, 3463, 7827, 9943, 30903, 65013, 1145}},
-{9333, 17, 30678, {1, 1, 1, 5, 23, 19, 81, 23, 475, 169, 373, 1147, 1805, 12779, 13173, 8945, 28175}},
-{9334, 17, 30682, {1, 3, 5, 9, 3, 53, 127, 33, 237, 803, 121, 307, 4981, 8765, 12761, 23601, 92921}},
-{9335, 17, 30687, {1, 1, 3, 7, 17, 63, 11, 37, 213, 619, 1095, 1693, 6747, 7373, 17355, 5987, 97923}},
-{9336, 17, 30688, {1, 1, 3, 15, 11, 37, 109, 175, 503, 339, 591, 2745, 2387, 7419, 13915, 4769, 48229}},
-{9337, 17, 30698, {1, 3, 5, 7, 19, 17, 5, 81, 471, 989, 249, 437, 7309, 5747, 25277, 31911, 87907}},
-{9338, 17, 30711, {1, 3, 1, 7, 15, 25, 49, 243, 423, 911, 1957, 911, 6331, 9831, 26021, 58877, 99257}},
-{9339, 17, 30728, {1, 3, 5, 11, 3, 55, 39, 129, 271, 145, 1973, 3391, 2905, 9229, 7989, 15641, 67933}},
-{9340, 17, 30733, {1, 3, 5, 9, 13, 13, 43, 135, 183, 319, 1391, 2953, 2207, 14205, 31203, 6329, 98907}},
-{9341, 17, 30741, {1, 3, 1, 9, 27, 41, 27, 155, 11, 191, 1747, 975, 7043, 13139, 30387, 47099, 120321}},
-{9342, 17, 30746, {1, 1, 5, 9, 25, 27, 53, 235, 437, 77, 371, 2413, 4867, 14245, 27199, 37387, 88217}},
-{9343, 17, 30752, {1, 1, 7, 7, 11, 59, 103, 15, 109, 65, 1987, 3695, 7737, 7341, 26963, 16075, 6301}},
-{9344, 17, 30764, {1, 3, 7, 5, 7, 59, 109, 159, 121, 377, 1851, 3983, 5421, 7633, 7321, 14869, 54633}},
-{9345, 17, 30769, {1, 1, 3, 15, 21, 51, 35, 243, 397, 411, 1107, 3689, 7913, 14715, 26349, 23361, 90665}},
-{9346, 17, 30784, {1, 1, 1, 3, 5, 11, 77, 205, 187, 981, 1969, 1749, 6295, 8267, 16073, 54451, 103603}},
-{9347, 17, 30796, {1, 3, 3, 9, 11, 13, 113, 83, 243, 1021, 2003, 2277, 6457, 10535, 13461, 52741, 9385}},
-{9348, 17, 30799, {1, 3, 3, 11, 19, 9, 103, 13, 219, 269, 1805, 2689, 5219, 11497, 4909, 57985, 40141}},
-{9349, 17, 30804, {1, 1, 1, 1, 29, 25, 15, 217, 69, 567, 839, 1515, 3627, 9837, 21433, 37177, 10487}},
-{9350, 17, 30811, {1, 1, 7, 15, 15, 23, 119, 217, 277, 447, 551, 825, 7571, 3083, 16573, 1189, 64959}},
-{9351, 17, 30814, {1, 1, 3, 11, 9, 13, 63, 77, 313, 195, 941, 1621, 165, 8905, 20265, 53761, 25091}},
-{9352, 17, 30818, {1, 3, 3, 9, 17, 5, 9, 183, 175, 1015, 253, 233, 2883, 15587, 27175, 38517, 22707}},
-{9353, 17, 30827, {1, 3, 3, 11, 23, 63, 83, 17, 49, 671, 749, 3249, 7821, 7189, 26735, 28995, 101737}},
-{9354, 17, 30838, {1, 1, 7, 5, 25, 15, 97, 247, 161, 585, 1307, 3803, 1105, 9093, 23523, 1383, 65671}},
-{9355, 17, 30842, {1, 1, 3, 15, 29, 51, 65, 237, 349, 709, 799, 1425, 6267, 6283, 4773, 18123, 74833}},
-{9356, 17, 30854, {1, 1, 5, 5, 11, 13, 9, 251, 373, 189, 467, 945, 7279, 11349, 10917, 6581, 83967}},
-{9357, 17, 30863, {1, 1, 7, 15, 23, 27, 1, 197, 41, 325, 757, 1229, 6295, 345, 26147, 40135, 123063}},
-{9358, 17, 30865, {1, 1, 7, 9, 23, 9, 93, 225, 191, 837, 103, 3367, 5411, 8289, 7057, 55391, 10669}},
-{9359, 17, 30877, {1, 1, 5, 15, 21, 17, 49, 221, 487, 23, 1943, 1563, 6157, 4035, 27769, 14933, 56913}},
-{9360, 17, 30881, {1, 1, 5, 13, 13, 43, 67, 245, 457, 365, 1115, 2205, 6229, 4173, 25167, 56333, 55605}},
-{9361, 17, 30887, {1, 1, 5, 11, 15, 59, 109, 83, 17, 913, 497, 1299, 5221, 321, 32139, 13717, 94311}},
-{9362, 17, 30908, {1, 3, 3, 3, 31, 11, 5, 203, 3, 843, 2039, 25, 6211, 14927, 6015, 46269, 90369}},
-{9363, 17, 30916, {1, 1, 3, 9, 21, 51, 91, 203, 149, 147, 197, 1771, 2921, 6609, 2343, 35249, 12963}},
-{9364, 17, 30919, {1, 3, 1, 7, 17, 43, 91, 229, 107, 521, 737, 2355, 5855, 6707, 21217, 47041, 81833}},
-{9365, 17, 30925, {1, 3, 3, 7, 7, 31, 97, 135, 503, 665, 1799, 2937, 6867, 4125, 7375, 34401, 18111}},
-{9366, 17, 30928, {1, 1, 7, 1, 11, 29, 89, 185, 495, 633, 507, 3727, 5999, 5871, 5911, 24877, 10259}},
-{9367, 17, 30944, {1, 1, 1, 13, 25, 3, 25, 65, 91, 411, 147, 3699, 7003, 3017, 25635, 56619, 101491}},
-{9368, 17, 30947, {1, 3, 5, 7, 31, 1, 63, 255, 115, 179, 87, 735, 1649, 4767, 31093, 60149, 49829}},
-{9369, 17, 30950, {1, 1, 3, 1, 21, 63, 67, 85, 399, 279, 1963, 1759, 4679, 15423, 11533, 54387, 36563}},
-{9370, 17, 30968, {1, 3, 5, 3, 31, 53, 73, 73, 481, 443, 1393, 2763, 1199, 5375, 8977, 5369, 114603}},
-{9371, 17, 30971, {1, 1, 1, 3, 29, 47, 73, 205, 469, 187, 815, 2787, 1431, 4705, 11455, 53643, 89269}},
-{9372, 17, 30973, {1, 3, 3, 9, 27, 57, 93, 55, 287, 539, 1259, 3279, 1563, 11399, 22975, 27077, 41031}},
-{9373, 17, 30976, {1, 1, 3, 15, 7, 27, 67, 25, 169, 263, 621, 1921, 509, 11715, 15363, 27447, 75535}},
-{9374, 17, 30986, {1, 1, 1, 9, 29, 63, 31, 99, 321, 361, 1693, 763, 5593, 10815, 741, 31257, 70843}},
-{9375, 17, 30993, {1, 1, 1, 9, 1, 17, 73, 141, 401, 549, 415, 1289, 1697, 1903, 8919, 59563, 60017}},
-{9376, 17, 30994, {1, 3, 7, 3, 5, 51, 127, 221, 9, 929, 153, 1045, 6587, 13653, 5343, 14043, 116125}},
-{9377, 17, 31012, {1, 3, 3, 13, 13, 17, 29, 93, 465, 59, 1207, 3121, 6331, 8647, 5047, 41869, 51969}},
-{9378, 17, 31016, {1, 1, 1, 15, 23, 29, 47, 149, 119, 855, 367, 1419, 7739, 1141, 19787, 38185, 84403}},
-{9379, 17, 31029, {1, 3, 1, 9, 29, 63, 5, 63, 435, 401, 1023, 1981, 6819, 7547, 30065, 33833, 7471}},
-{9380, 17, 31039, {1, 3, 1, 15, 1, 47, 35, 161, 243, 225, 935, 2179, 7737, 7841, 28523, 11505, 103741}},
-{9381, 17, 31041, {1, 1, 7, 3, 7, 57, 73, 55, 101, 905, 1705, 4057, 3781, 8213, 18997, 17185, 33265}},
-{9382, 17, 31042, {1, 1, 5, 1, 7, 57, 31, 77, 323, 395, 927, 1969, 6973, 9013, 30789, 757, 84075}},
-{9383, 17, 31044, {1, 1, 3, 7, 15, 53, 51, 205, 401, 679, 1295, 1955, 7739, 11423, 23207, 55449, 60419}},
-{9384, 17, 31053, {1, 3, 5, 11, 23, 21, 67, 141, 157, 767, 219, 3607, 1847, 11051, 31499, 8461, 106353}},
-{9385, 17, 31059, {1, 1, 3, 9, 17, 19, 123, 169, 1, 31, 1019, 1823, 6043, 1895, 17293, 62079, 16945}},
-{9386, 17, 31062, {1, 3, 5, 9, 3, 15, 49, 27, 183, 293, 989, 2161, 1845, 1103, 20149, 11121, 31935}},
-{9387, 17, 31077, {1, 3, 1, 3, 17, 39, 103, 45, 491, 91, 413, 487, 1381, 5457, 22503, 40477, 94297}},
-{9388, 17, 31095, {1, 1, 3, 7, 29, 11, 87, 79, 349, 437, 945, 3753, 6691, 4373, 24875, 54397, 33697}},
-{9389, 17, 31101, {1, 1, 7, 1, 9, 31, 105, 121, 97, 947, 129, 1909, 2371, 5493, 29523, 52685, 24325}},
-{9390, 17, 31105, {1, 1, 5, 9, 19, 21, 63, 115, 511, 525, 49, 1879, 6075, 8181, 10135, 56785, 53309}},
-{9391, 17, 31118, {1, 1, 5, 15, 3, 55, 75, 135, 451, 697, 1407, 2765, 2443, 11589, 24863, 47187, 98477}},
-{9392, 17, 31129, {1, 1, 1, 13, 27, 37, 77, 157, 121, 603, 491, 2201, 619, 9157, 32511, 19843, 49919}},
-{9393, 17, 31132, {1, 1, 3, 1, 23, 17, 23, 115, 119, 349, 987, 2587, 1847, 12099, 31955, 31685, 1989}},
-{9394, 17, 31141, {1, 3, 7, 7, 5, 47, 63, 209, 69, 921, 1041, 1391, 7485, 11121, 30993, 5691, 74551}},
-{9395, 17, 31159, {1, 3, 1, 3, 23, 61, 55, 253, 355, 299, 971, 279, 3543, 10073, 5199, 50539, 88303}},
-{9396, 17, 31183, {1, 1, 1, 11, 13, 19, 7, 255, 189, 267, 2021, 93, 219, 10537, 28627, 58141, 53675}},
-{9397, 17, 31185, {1, 3, 3, 7, 27, 61, 83, 95, 163, 777, 1533, 2485, 7211, 6979, 4013, 20797, 91411}},
-{9398, 17, 31195, {1, 1, 7, 13, 15, 37, 5, 109, 133, 225, 59, 3855, 3351, 659, 24321, 63531, 15573}},
-{9399, 17, 31202, {1, 1, 5, 1, 7, 55, 59, 213, 45, 77, 2003, 2921, 1105, 11089, 17197, 45459, 67681}},
-{9400, 17, 31213, {1, 1, 1, 5, 13, 21, 107, 245, 505, 409, 1453, 1201, 6945, 2103, 7377, 59413, 8785}},
-{9401, 17, 31238, {1, 1, 1, 13, 5, 37, 73, 55, 39, 219, 225, 3877, 6583, 3105, 25355, 14839, 23435}},
-{9402, 17, 31241, {1, 1, 7, 1, 21, 35, 87, 227, 487, 767, 609, 1685, 2731, 10135, 381, 24021, 122137}},
-{9403, 17, 31252, {1, 1, 1, 3, 29, 13, 19, 255, 355, 505, 1757, 3537, 3029, 11403, 22685, 61169, 397}},
-{9404, 17, 31262, {1, 1, 7, 1, 29, 43, 11, 207, 83, 97, 435, 1453, 4709, 4193, 18517, 47203, 3255}},
-{9405, 17, 31265, {1, 1, 1, 1, 21, 49, 39, 163, 459, 849, 561, 1207, 4109, 1435, 17519, 14839, 1331}},
-{9406, 17, 31295, {1, 1, 3, 11, 27, 35, 65, 219, 135, 559, 1111, 2959, 7835, 5165, 26641, 22765, 121829}},
-{9407, 17, 31300, {1, 3, 5, 3, 23, 31, 57, 149, 431, 451, 189, 1771, 5877, 3503, 7531, 46485, 129031}},
-{9408, 17, 31303, {1, 1, 3, 11, 1, 13, 47, 17, 331, 1003, 215, 2797, 689, 6289, 12719, 37139, 35827}},
-{9409, 17, 31317, {1, 3, 5, 9, 19, 13, 11, 29, 275, 165, 783, 313, 2153, 6009, 2247, 5699, 128753}},
-{9410, 17, 31318, {1, 1, 7, 13, 5, 43, 51, 75, 411, 743, 335, 217, 559, 15389, 6567, 41193, 127443}},
-{9411, 17, 31324, {1, 3, 5, 15, 5, 63, 7, 145, 445, 835, 825, 35, 5951, 5121, 16365, 36789, 2941}},
-{9412, 17, 31338, {1, 3, 5, 5, 29, 1, 61, 19, 427, 245, 445, 3505, 3647, 8817, 8031, 64577, 60745}},
-{9413, 17, 31340, {1, 1, 3, 9, 29, 9, 35, 225, 55, 535, 1537, 831, 6483, 16123, 26079, 32809, 62227}},
-{9414, 17, 31345, {1, 3, 7, 7, 25, 33, 15, 61, 343, 749, 1963, 2763, 3171, 6755, 6529, 49449, 88903}},
-{9415, 17, 31355, {1, 1, 7, 13, 17, 35, 91, 119, 87, 1023, 1101, 1785, 2005, 15947, 21679, 63179, 3389}},
-{9416, 17, 31362, {1, 3, 1, 1, 1, 1, 123, 195, 315, 681, 153, 1621, 5097, 3669, 20505, 39305, 127065}},
-{9417, 17, 31371, {1, 1, 5, 11, 1, 17, 73, 251, 185, 59, 1723, 2321, 2103, 6331, 29571, 63811, 66651}},
-{9418, 17, 31373, {1, 1, 7, 13, 15, 19, 111, 91, 211, 85, 711, 2197, 3107, 2717, 16725, 52995, 65791}},
-{9419, 17, 31381, {1, 3, 3, 9, 21, 41, 53, 145, 459, 155, 93, 2833, 6747, 737, 30625, 40581, 65825}},
-{9420, 17, 31391, {1, 3, 3, 3, 1, 45, 119, 81, 185, 431, 1221, 3043, 7277, 10537, 12355, 42261, 126117}},
-{9421, 17, 31409, {1, 3, 7, 7, 11, 47, 37, 41, 123, 643, 707, 2963, 6183, 15527, 10951, 24031, 38187}},
-{9422, 17, 31410, {1, 3, 1, 7, 13, 57, 1, 149, 117, 627, 1999, 2805, 4857, 12805, 31453, 25699, 109447}},
-{9423, 17, 31412, {1, 3, 5, 3, 9, 37, 83, 221, 77, 573, 661, 465, 1279, 7355, 24061, 36151, 96595}},
-{9424, 17, 31434, {1, 1, 7, 15, 29, 31, 125, 205, 449, 563, 1263, 3427, 8013, 14025, 15235, 11833, 25601}},
-{9425, 17, 31458, {1, 3, 7, 11, 31, 35, 99, 193, 163, 527, 1455, 395, 4853, 2561, 11909, 57311, 101007}},
-{9426, 17, 31467, {1, 1, 5, 3, 17, 39, 99, 173, 497, 245, 1671, 3457, 83, 11959, 2963, 3401, 102259}},
-{9427, 17, 31470, {1, 1, 1, 5, 25, 41, 119, 81, 301, 797, 661, 2543, 1195, 2111, 1785, 41533, 51947}},
-{9428, 17, 31475, {1, 3, 3, 13, 5, 59, 61, 153, 213, 541, 1849, 249, 3897, 3877, 17095, 6857, 76781}},
-{9429, 17, 31481, {1, 3, 7, 1, 19, 13, 57, 47, 359, 165, 1085, 2263, 3261, 12825, 17405, 25853, 20731}},
-{9430, 17, 31482, {1, 1, 1, 7, 7, 43, 7, 65, 51, 503, 173, 1023, 283, 14809, 1183, 33497, 110683}},
-{9431, 17, 31484, {1, 3, 5, 11, 19, 51, 29, 157, 159, 191, 1293, 2951, 6569, 12433, 14587, 30631, 30485}},
-{9432, 17, 31492, {1, 3, 7, 5, 1, 27, 25, 221, 255, 471, 779, 3991, 6985, 1803, 28451, 33403, 5567}},
-{9433, 17, 31507, {1, 1, 5, 5, 7, 29, 55, 241, 457, 863, 1715, 3393, 4127, 13985, 6313, 13683, 114837}},
-{9434, 17, 31514, {1, 3, 5, 5, 11, 27, 55, 109, 247, 199, 1593, 2881, 307, 97, 24751, 35921, 121931}},
-{9435, 17, 31538, {1, 3, 1, 13, 3, 59, 17, 161, 47, 467, 1019, 3629, 3017, 15645, 3983, 32393, 79213}},
-{9436, 17, 31547, {1, 1, 3, 11, 19, 57, 67, 199, 319, 107, 2043, 2045, 4025, 5733, 29979, 37721, 117031}},
-{9437, 17, 31549, {1, 3, 7, 11, 9, 23, 31, 81, 177, 801, 1177, 3451, 7777, 15351, 7579, 39033, 23847}},
-{9438, 17, 31555, {1, 1, 3, 5, 17, 61, 63, 7, 371, 905, 1147, 1383, 4075, 6721, 17503, 32015, 112547}},
-{9439, 17, 31557, {1, 1, 3, 13, 13, 25, 69, 159, 49, 133, 227, 2155, 1603, 10077, 3429, 39131, 18949}},
-{9440, 17, 31597, {1, 3, 5, 3, 29, 5, 115, 93, 243, 791, 1113, 2841, 4733, 3041, 31733, 28539, 84567}},
-{9441, 17, 31598, {1, 3, 3, 7, 21, 9, 5, 95, 489, 517, 1453, 2697, 7951, 12369, 19571, 29811, 51805}},
-{9442, 17, 31610, {1, 1, 5, 9, 1, 29, 97, 191, 73, 357, 745, 2787, 7815, 4565, 19761, 33729, 86849}},
-{9443, 17, 31625, {1, 3, 5, 13, 3, 5, 35, 79, 387, 813, 1673, 3187, 337, 5539, 6761, 46903, 122967}},
-{9444, 17, 31634, {1, 1, 7, 11, 1, 15, 125, 175, 255, 35, 145, 2391, 887, 10505, 11587, 53941, 5089}},
-{9445, 17, 31643, {1, 1, 7, 13, 9, 13, 15, 215, 361, 227, 1665, 3345, 3615, 14031, 16281, 4457, 52037}},
-{9446, 17, 31645, {1, 3, 5, 9, 31, 21, 3, 189, 211, 855, 1781, 2097, 1345, 6763, 27651, 54137, 52689}},
-{9447, 17, 31659, {1, 3, 1, 5, 29, 9, 99, 183, 183, 205, 149, 53, 7179, 3387, 9603, 4281, 47145}},
-{9448, 17, 31669, {1, 3, 1, 11, 13, 35, 97, 21, 29, 877, 191, 1621, 2501, 4283, 1707, 48957, 129029}},
-{9449, 17, 31670, {1, 3, 1, 9, 5, 19, 57, 219, 105, 467, 1179, 3155, 7743, 4835, 14845, 35671, 47655}},
-{9450, 17, 31682, {1, 3, 1, 7, 27, 41, 27, 185, 271, 611, 1173, 2875, 529, 11619, 20231, 18741, 41799}},
-{9451, 17, 31694, {1, 3, 7, 13, 9, 3, 35, 71, 467, 689, 1797, 319, 6657, 13193, 15861, 7567, 12891}},
-{9452, 17, 31717, {1, 1, 7, 13, 19, 57, 25, 141, 195, 995, 859, 811, 4685, 6711, 8963, 49657, 54751}},
-{9453, 17, 31718, {1, 1, 1, 11, 27, 25, 9, 91, 97, 251, 757, 2783, 5447, 3617, 26801, 32501, 55245}},
-{9454, 17, 31729, {1, 3, 7, 1, 5, 1, 103, 129, 127, 593, 857, 3957, 3665, 10279, 26211, 2095, 15869}},
-{9455, 17, 31736, {1, 1, 7, 1, 25, 49, 3, 139, 25, 545, 615, 1353, 4103, 1099, 21729, 45383, 110611}},
-{9456, 17, 31742, {1, 3, 5, 3, 7, 49, 83, 41, 209, 357, 939, 849, 5851, 3945, 831, 8131, 105897}},
-{9457, 17, 31749, {1, 1, 1, 3, 27, 19, 123, 71, 195, 1019, 1021, 1287, 5665, 5277, 8647, 27033, 89539}},
-{9458, 17, 31773, {1, 1, 1, 9, 27, 51, 49, 159, 401, 1013, 763, 653, 1449, 12441, 21191, 28871, 106181}},
-{9459, 17, 31777, {1, 1, 5, 7, 31, 7, 105, 137, 331, 367, 1305, 2761, 863, 3915, 12633, 32251, 82867}},
-{9460, 17, 31778, {1, 3, 7, 11, 9, 47, 35, 57, 137, 269, 443, 79, 11, 11817, 28995, 46681, 104263}},
-{9461, 17, 31784, {1, 3, 1, 5, 3, 25, 89, 179, 183, 835, 367, 2215, 295, 5365, 1899, 10785, 88979}},
-{9462, 17, 31801, {1, 3, 7, 13, 3, 5, 93, 43, 409, 363, 267, 2077, 3745, 445, 25957, 34103, 29475}},
-{9463, 17, 31812, {1, 1, 1, 7, 27, 21, 121, 29, 171, 783, 553, 265, 6835, 3929, 18127, 33463, 70999}},
-{9464, 17, 31821, {1, 3, 3, 15, 15, 55, 13, 1, 297, 935, 1307, 1779, 2239, 15471, 32453, 30649, 45973}},
-{9465, 17, 31822, {1, 3, 7, 5, 25, 41, 3, 171, 347, 607, 1873, 1087, 2433, 8377, 7959, 19941, 117319}},
-{9466, 17, 31836, {1, 1, 1, 3, 5, 47, 107, 69, 431, 63, 325, 1241, 3487, 11249, 28559, 30001, 93789}},
-{9467, 17, 31850, {1, 1, 1, 5, 15, 17, 9, 145, 335, 169, 1099, 3637, 5397, 6711, 16095, 27053, 124247}},
-{9468, 17, 31855, {1, 3, 3, 5, 3, 9, 65, 97, 421, 951, 2003, 2837, 7095, 15685, 5147, 56801, 98679}},
-{9469, 17, 31858, {1, 3, 7, 15, 1, 33, 115, 45, 215, 253, 361, 555, 787, 15483, 25531, 53273, 8933}},
-{9470, 17, 31860, {1, 3, 1, 9, 3, 63, 47, 205, 457, 977, 991, 3189, 1369, 14899, 10937, 56999, 11525}},
-{9471, 17, 31886, {1, 1, 7, 5, 11, 61, 53, 55, 231, 357, 1695, 2489, 2355, 7583, 14097, 50039, 96595}},
-{9472, 17, 31891, {1, 3, 7, 7, 3, 57, 115, 245, 259, 573, 1275, 2971, 1793, 13683, 8683, 51815, 26807}},
-{9473, 17, 31909, {1, 1, 5, 3, 17, 59, 55, 237, 491, 757, 1447, 2941, 2641, 14175, 4401, 4367, 36853}},
-{9474, 17, 31928, {1, 3, 1, 15, 3, 63, 67, 1, 403, 79, 1161, 2379, 3337, 14447, 5877, 40759, 12573}},
-{9475, 17, 31931, {1, 1, 7, 15, 17, 1, 91, 5, 173, 215, 1567, 1851, 3309, 9813, 21215, 19151, 96785}},
-{9476, 17, 31934, {1, 1, 1, 9, 31, 45, 123, 221, 397, 51, 1489, 3247, 923, 10423, 10461, 51231, 92909}},
-{9477, 17, 31941, {1, 1, 1, 13, 27, 17, 105, 163, 403, 193, 1487, 2421, 4415, 14303, 6419, 24105, 29997}},
-{9478, 17, 31942, {1, 1, 5, 13, 31, 55, 17, 125, 341, 219, 401, 1611, 891, 12909, 13949, 46245, 26769}},
-{9479, 17, 31945, {1, 3, 7, 3, 31, 41, 65, 207, 311, 643, 1617, 271, 3749, 14635, 26385, 55251, 50719}},
-{9480, 17, 31951, {1, 3, 3, 13, 7, 55, 69, 241, 413, 399, 137, 2255, 5395, 12625, 26583, 64603, 22571}},
-{9481, 17, 31959, {1, 3, 5, 3, 31, 15, 15, 161, 153, 445, 595, 273, 6631, 12845, 23331, 16963, 52099}},
-{9482, 17, 31963, {1, 3, 3, 1, 27, 39, 71, 41, 455, 841, 831, 1719, 3531, 5113, 29183, 1933, 42227}},
-{9483, 17, 31970, {1, 3, 7, 3, 1, 15, 31, 183, 429, 557, 1747, 1059, 2079, 16361, 29103, 43207, 921}},
-{9484, 17, 31984, {1, 3, 1, 1, 31, 39, 97, 73, 339, 405, 1423, 2215, 5435, 9205, 1889, 58249, 61517}},
-{9485, 17, 31987, {1, 3, 7, 1, 23, 59, 127, 245, 11, 627, 1555, 2497, 6427, 7205, 22675, 62847, 69691}},
-{9486, 17, 31990, {1, 1, 3, 5, 1, 13, 95, 9, 167, 481, 947, 3181, 8057, 5559, 7537, 33757, 72419}},
-{9487, 17, 32001, {1, 1, 7, 3, 15, 9, 105, 205, 287, 375, 115, 1731, 1063, 11551, 12077, 41013, 88853}},
-{9488, 17, 32007, {1, 3, 3, 9, 5, 63, 127, 33, 409, 279, 1379, 4069, 4091, 14703, 27435, 19525, 71261}},
-{9489, 17, 32008, {1, 3, 1, 13, 31, 31, 59, 205, 167, 131, 891, 1259, 6909, 211, 31517, 8085, 112065}},
-{9490, 17, 32025, {1, 1, 5, 11, 17, 25, 119, 77, 449, 569, 381, 825, 2459, 983, 2959, 51611, 90721}},
-{9491, 17, 32035, {1, 3, 1, 7, 17, 55, 91, 231, 133, 541, 499, 3609, 4237, 11627, 30007, 58911, 43443}},
-{9492, 17, 32038, {1, 3, 7, 7, 29, 5, 47, 187, 71, 695, 1389, 2855, 5815, 11605, 3643, 24961, 25793}},
-{9493, 17, 32047, {1, 3, 3, 5, 11, 31, 43, 31, 185, 1021, 795, 3585, 3981, 8627, 18117, 42351, 19513}},
-{9494, 17, 32049, {1, 1, 5, 13, 9, 3, 115, 45, 39, 577, 1847, 653, 2625, 9367, 27923, 35661, 113613}},
-{9495, 17, 32062, {1, 3, 7, 7, 17, 9, 69, 233, 367, 673, 11, 2215, 1177, 4501, 9693, 62013, 45647}},
-{9496, 17, 32067, {1, 3, 5, 7, 7, 53, 11, 227, 465, 843, 2017, 689, 6767, 10321, 25163, 56561, 6865}},
-{9497, 17, 32070, {1, 3, 3, 5, 13, 43, 119, 9, 185, 893, 133, 863, 7137, 6653, 7875, 23167, 13893}},
-{9498, 17, 32073, {1, 3, 5, 9, 1, 47, 17, 85, 273, 901, 493, 2411, 983, 15717, 25151, 21323, 57939}},
-{9499, 17, 32074, {1, 1, 7, 5, 19, 17, 49, 37, 425, 443, 781, 2593, 4929, 12313, 12727, 42285, 88451}},
-{9500, 17, 32079, {1, 3, 3, 11, 9, 53, 17, 67, 237, 463, 1509, 2153, 3715, 7909, 21151, 64517, 87695}},
-{9501, 17, 32081, {1, 3, 7, 1, 29, 39, 25, 83, 413, 1005, 2011, 3933, 2911, 7041, 10537, 23135, 22671}},
-{9502, 17, 32082, {1, 1, 3, 9, 23, 61, 117, 33, 431, 181, 1819, 683, 1809, 1723, 27041, 29113, 99347}},
-{9503, 17, 32107, {1, 1, 5, 11, 11, 7, 101, 181, 51, 857, 923, 3495, 7123, 7775, 30081, 48513, 116137}},
-{9504, 17, 32127, {1, 1, 3, 11, 15, 31, 97, 127, 365, 799, 715, 2101, 6081, 11607, 1055, 35027, 62967}},
-{9505, 17, 32145, {1, 3, 5, 7, 3, 31, 109, 247, 225, 221, 1093, 2633, 1847, 7427, 8767, 16581, 32145}},
-{9506, 17, 32151, {1, 3, 1, 7, 15, 23, 43, 109, 327, 417, 1895, 2333, 6265, 6599, 6623, 47375, 92731}},
-{9507, 17, 32152, {1, 3, 7, 1, 29, 29, 45, 217, 163, 941, 1327, 3685, 5481, 15783, 26281, 60339, 34277}},
-{9508, 17, 32173, {1, 1, 7, 11, 1, 7, 119, 201, 29, 193, 1805, 1395, 267, 2011, 637, 26765, 48883}},
-{9509, 17, 32174, {1, 1, 3, 7, 11, 63, 41, 89, 365, 729, 25, 3185, 2143, 1737, 29693, 7443, 78079}},
-{9510, 17, 32186, {1, 3, 1, 13, 25, 27, 63, 233, 79, 1007, 1357, 679, 7581, 8333, 2469, 31787, 128531}},
-{9511, 17, 32194, {1, 3, 1, 3, 23, 39, 53, 99, 219, 475, 931, 507, 3615, 10613, 14663, 1151, 123459}},
-{9512, 17, 32196, {1, 1, 1, 1, 13, 15, 67, 45, 393, 791, 415, 2731, 1151, 8935, 28983, 7239, 106247}},
-{9513, 17, 32200, {1, 3, 7, 7, 11, 35, 95, 153, 421, 193, 1997, 2587, 3183, 9229, 17663, 28221, 6759}},
-{9514, 17, 32208, {1, 3, 1, 7, 5, 5, 123, 55, 509, 973, 261, 463, 2723, 15225, 1925, 62283, 86329}},
-{9515, 17, 32218, {1, 1, 3, 13, 5, 47, 123, 239, 273, 407, 1725, 717, 1229, 1387, 11743, 13739, 104503}},
-{9516, 17, 32236, {1, 3, 3, 13, 23, 35, 43, 113, 299, 847, 1903, 3445, 3395, 641, 11271, 61517, 40747}},
-{9517, 17, 32260, {1, 3, 1, 15, 17, 49, 97, 9, 335, 731, 151, 167, 8129, 11845, 18285, 20113, 122397}},
-{9518, 17, 32263, {1, 1, 5, 11, 11, 63, 3, 153, 345, 511, 1939, 1815, 7231, 10555, 14293, 50753, 14681}},
-{9519, 17, 32288, {1, 3, 7, 5, 21, 31, 127, 223, 241, 783, 887, 3519, 4743, 3541, 4143, 57461, 27791}},
-{9520, 17, 32298, {1, 1, 5, 7, 13, 15, 83, 225, 201, 979, 145, 769, 1491, 12155, 21307, 64877, 113277}},
-{9521, 17, 32315, {1, 1, 7, 1, 27, 25, 105, 69, 239, 323, 1059, 573, 4913, 14215, 27007, 42351, 66315}},
-{9522, 17, 32332, {1, 1, 3, 11, 21, 33, 93, 23, 363, 633, 935, 637, 6171, 12695, 14077, 17505, 69681}},
-{9523, 17, 32340, {1, 3, 1, 5, 15, 11, 93, 211, 175, 377, 33, 1403, 5097, 1503, 8483, 2881, 85877}},
-{9524, 17, 32354, {1, 1, 5, 3, 5, 51, 5, 255, 429, 661, 625, 3015, 4813, 3573, 22917, 45967, 70559}},
-{9525, 17, 32359, {1, 1, 7, 3, 11, 41, 3, 197, 181, 897, 767, 1385, 7395, 15543, 4655, 40309, 73169}},
-{9526, 17, 32366, {1, 1, 5, 9, 15, 35, 71, 119, 509, 817, 1169, 75, 1337, 2959, 611, 38243, 46987}},
-{9527, 17, 32368, {1, 1, 1, 9, 1, 7, 43, 65, 479, 625, 1685, 1309, 5619, 14163, 13633, 18169, 8311}},
-{9528, 17, 32377, {1, 3, 5, 9, 19, 39, 95, 105, 273, 1023, 79, 229, 6895, 2931, 5717, 27911, 22139}},
-{9529, 17, 32384, {1, 3, 5, 7, 1, 55, 15, 15, 297, 731, 2029, 2789, 11, 1333, 26571, 62595, 15131}},
-{9530, 17, 32399, {1, 1, 5, 7, 29, 35, 3, 125, 381, 709, 2047, 2395, 6315, 2301, 7175, 19857, 75085}},
-{9531, 17, 32417, {1, 1, 5, 15, 23, 45, 95, 117, 49, 635, 1525, 1105, 7335, 4653, 18159, 29729, 62627}},
-{9532, 17, 32424, {1, 3, 3, 11, 29, 19, 29, 169, 141, 243, 1765, 1829, 4555, 16299, 3053, 58933, 44605}},
-{9533, 17, 32427, {1, 1, 3, 15, 5, 45, 35, 213, 385, 993, 1521, 9, 3561, 10497, 12601, 38163, 86501}},
-{9534, 17, 32429, {1, 3, 3, 13, 9, 23, 109, 95, 491, 1003, 473, 3325, 6577, 14617, 17765, 33391, 82927}},
-{9535, 17, 32438, {1, 3, 3, 11, 25, 31, 93, 111, 231, 71, 1233, 3581, 6789, 4569, 16741, 61967, 32249}},
-{9536, 17, 32442, {1, 3, 3, 15, 15, 63, 39, 247, 79, 923, 327, 2639, 2013, 12325, 18133, 60623, 2215}},
-{9537, 17, 32447, {1, 3, 5, 1, 5, 49, 121, 53, 283, 529, 37, 3233, 6285, 12447, 4355, 9343, 45631}},
-{9538, 17, 32469, {1, 1, 7, 11, 11, 11, 111, 139, 429, 279, 1019, 2139, 2033, 6809, 8847, 22535, 107005}},
-{9539, 17, 32479, {1, 3, 5, 1, 1, 21, 35, 97, 167, 57, 491, 511, 4065, 11699, 16851, 6847, 40929}},
-{9540, 17, 32483, {1, 3, 1, 15, 3, 55, 113, 33, 255, 537, 835, 1867, 3927, 839, 955, 29079, 93727}},
-{9541, 17, 32498, {1, 1, 7, 3, 5, 7, 35, 111, 165, 885, 115, 3051, 4541, 1701, 22827, 361, 91843}},
-{9542, 17, 32503, {1, 1, 7, 11, 7, 55, 81, 43, 237, 725, 1761, 1599, 639, 14189, 31241, 52827, 107943}},
-{9543, 17, 32507, {1, 3, 1, 3, 29, 35, 67, 119, 369, 877, 1861, 123, 8121, 13861, 31155, 60245, 79799}},
-{9544, 17, 32521, {1, 1, 3, 13, 7, 49, 63, 19, 253, 723, 639, 1677, 291, 13697, 22231, 46893, 90069}},
-{9545, 17, 32532, {1, 3, 5, 1, 7, 57, 29, 233, 35, 715, 515, 3221, 2715, 13839, 18321, 4445, 103843}},
-{9546, 17, 32539, {1, 3, 1, 7, 1, 63, 33, 7, 481, 461, 1923, 2679, 2441, 5449, 13233, 2245, 48667}},
-{9547, 17, 32551, {1, 1, 7, 11, 11, 9, 95, 151, 441, 333, 1871, 1181, 3027, 12887, 11923, 63847, 6953}},
-{9548, 17, 32572, {1, 3, 5, 5, 15, 33, 53, 47, 351, 387, 55, 393, 5475, 3027, 18565, 37997, 120877}},
-{9549, 17, 32577, {1, 3, 5, 9, 23, 43, 67, 97, 445, 783, 1499, 1977, 1441, 10159, 13479, 149, 4939}},
-{9550, 17, 32578, {1, 3, 7, 3, 15, 41, 119, 55, 139, 25, 849, 857, 53, 10421, 2683, 24839, 107797}},
-{9551, 17, 32587, {1, 1, 7, 13, 25, 51, 51, 13, 333, 93, 95, 1755, 3055, 12585, 3519, 44857, 11257}},
-{9552, 17, 32592, {1, 1, 5, 11, 29, 55, 13, 235, 419, 327, 823, 2675, 8031, 9303, 8749, 20215, 12111}},
-{9553, 17, 32602, {1, 1, 3, 5, 7, 31, 103, 19, 467, 255, 583, 419, 2845, 12179, 63, 51693, 9755}},
-{9554, 17, 32604, {1, 1, 1, 13, 15, 29, 109, 81, 381, 659, 601, 3867, 7663, 7307, 16445, 56327, 48559}},
-{9555, 17, 32613, {1, 3, 3, 15, 31, 35, 29, 153, 423, 247, 55, 3259, 6199, 4199, 13931, 14433, 52645}},
-{9556, 17, 32625, {1, 1, 5, 11, 9, 17, 17, 191, 231, 977, 721, 2817, 2485, 4965, 32341, 55131, 4547}},
-{9557, 17, 32631, {1, 1, 7, 7, 7, 7, 89, 69, 299, 503, 597, 311, 1321, 2335, 30193, 45347, 126631}},
-{9558, 17, 32641, {1, 1, 7, 11, 13, 43, 105, 153, 89, 229, 1573, 1549, 3699, 15981, 28911, 45011, 83759}},
-{9559, 17, 32642, {1, 3, 7, 3, 1, 3, 121, 137, 263, 325, 1449, 3793, 5795, 7715, 7449, 26453, 85081}},
-{9560, 17, 32644, {1, 3, 1, 7, 23, 15, 39, 217, 99, 873, 1641, 1411, 4627, 283, 20707, 41795, 62239}},
-{9561, 17, 32656, {1, 3, 5, 9, 15, 15, 35, 255, 501, 945, 79, 799, 2361, 4495, 27825, 27699, 129335}},
-{9562, 17, 32678, {1, 3, 1, 7, 9, 19, 89, 31, 65, 905, 1475, 1353, 7253, 12825, 20723, 47757, 12007}},
-{9563, 17, 32681, {1, 1, 3, 3, 15, 35, 83, 239, 463, 835, 1249, 2521, 3429, 14073, 13569, 6161, 71309}},
-{9564, 17, 32701, {1, 1, 7, 11, 31, 43, 15, 57, 461, 917, 339, 3787, 2925, 1879, 7217, 17091, 108819}},
-{9565, 17, 32713, {1, 3, 7, 3, 17, 51, 29, 105, 221, 941, 1291, 835, 1563, 15623, 2953, 62985, 63037}},
-{9566, 17, 32721, {1, 1, 7, 3, 1, 39, 83, 41, 399, 465, 587, 2011, 137, 6017, 5067, 52389, 71053}},
-{9567, 17, 32727, {1, 1, 7, 11, 17, 55, 103, 239, 173, 181, 1219, 2671, 5183, 3799, 19589, 31247, 68889}},
-{9568, 17, 32731, {1, 1, 3, 3, 21, 43, 123, 253, 281, 627, 353, 3077, 1685, 12143, 19723, 57775, 70761}},
-{9569, 17, 32734, {1, 1, 7, 15, 31, 13, 101, 159, 311, 305, 1783, 3523, 149, 9269, 7103, 40315, 30569}},
-{9570, 17, 32740, {1, 1, 5, 3, 29, 47, 11, 219, 301, 207, 1361, 563, 7831, 14469, 18983, 54535, 64647}},
-{9571, 17, 32773, {1, 1, 3, 15, 11, 37, 85, 237, 225, 1009, 1065, 985, 6849, 5395, 22853, 43965, 51363}},
-{9572, 17, 32774, {1, 3, 3, 1, 11, 61, 45, 131, 201, 609, 757, 2539, 3817, 9309, 24759, 26789, 41437}},
-{9573, 17, 32785, {1, 1, 7, 3, 21, 5, 19, 137, 75, 573, 583, 2499, 41, 3429, 24273, 36711, 110015}},
-{9574, 17, 32788, {1, 3, 7, 9, 1, 51, 39, 75, 115, 269, 1983, 2709, 6989, 6521, 5551, 43675, 1019}},
-{9575, 17, 32792, {1, 1, 3, 9, 27, 1, 125, 7, 67, 821, 275, 1253, 4635, 3557, 4155, 13831, 1523}},
-{9576, 17, 32797, {1, 1, 5, 15, 23, 15, 79, 43, 275, 791, 1867, 2495, 2933, 2167, 22819, 52913, 88871}},
-{9577, 17, 32801, {1, 1, 1, 5, 31, 59, 27, 153, 159, 919, 219, 3373, 3227, 6321, 27559, 33905, 126145}},
-{9578, 17, 32811, {1, 3, 3, 13, 23, 21, 119, 175, 119, 741, 1745, 3985, 3847, 5163, 13699, 32373, 75201}},
-{9579, 17, 32821, {1, 3, 7, 15, 1, 47, 101, 89, 425, 269, 713, 3587, 3373, 13315, 16481, 40031, 50353}},
-{9580, 17, 32828, {1, 3, 7, 3, 19, 29, 5, 69, 385, 979, 1893, 1849, 8007, 14415, 18343, 60555, 109117}},
-{9581, 17, 32839, {1, 1, 3, 13, 5, 35, 111, 239, 489, 395, 1565, 1607, 543, 89, 8971, 22311, 899}},
-{9582, 17, 32854, {1, 1, 7, 7, 11, 51, 105, 211, 341, 85, 991, 1275, 3995, 12611, 2363, 29501, 44217}},
-{9583, 17, 32867, {1, 1, 5, 13, 9, 17, 93, 69, 145, 917, 469, 1109, 7405, 12903, 8341, 50383, 20133}},
-{9584, 17, 32870, {1, 3, 1, 7, 27, 45, 45, 85, 101, 161, 1117, 2757, 7847, 359, 17155, 27073, 123535}},
-{9585, 17, 32873, {1, 3, 1, 3, 9, 11, 67, 205, 109, 257, 1635, 141, 3969, 11571, 211, 48683, 108671}},
-{9586, 17, 32881, {1, 1, 3, 7, 13, 9, 29, 251, 113, 851, 1549, 981, 5553, 6095, 28885, 32953, 112563}},
-{9587, 17, 32891, {1, 1, 5, 7, 11, 5, 13, 83, 343, 499, 587, 3887, 3859, 11459, 7361, 25665, 86151}},
-{9588, 17, 32900, {1, 1, 5, 1, 13, 43, 3, 37, 273, 749, 1707, 2069, 3083, 1095, 3081, 23919, 21939}},
-{9589, 17, 32903, {1, 3, 5, 13, 13, 49, 115, 99, 357, 95, 699, 2615, 1911, 12675, 8607, 12535, 118651}},
-{9590, 17, 32910, {1, 1, 7, 7, 29, 43, 17, 131, 271, 895, 1427, 3659, 1843, 8247, 1175, 48239, 54435}},
-{9591, 17, 32917, {1, 1, 1, 9, 1, 27, 85, 163, 353, 669, 745, 317, 2505, 7685, 14831, 31131, 106687}},
-{9592, 17, 32922, {1, 1, 7, 9, 1, 23, 121, 53, 289, 651, 303, 3049, 6819, 6733, 17485, 20023, 110009}},
-{9593, 17, 32928, {1, 3, 7, 3, 5, 47, 93, 75, 363, 479, 825, 1801, 6807, 3341, 6419, 9889, 5557}},
-{9594, 17, 32945, {1, 1, 3, 15, 23, 5, 7, 25, 73, 811, 1597, 2041, 6707, 6817, 20427, 50749, 46255}},
-{9595, 17, 32946, {1, 3, 7, 9, 1, 11, 61, 63, 435, 977, 1937, 93, 2685, 643, 20113, 25873, 63829}},
-{9596, 17, 32951, {1, 1, 3, 15, 5, 41, 31, 53, 143, 271, 27, 3899, 5045, 1063, 17229, 52715, 67689}},
-{9597, 17, 32958, {1, 1, 3, 11, 1, 57, 121, 13, 291, 861, 1547, 3899, 7949, 15401, 29807, 52307, 104359}},
-{9598, 17, 32965, {1, 3, 5, 15, 23, 3, 95, 43, 377, 437, 1687, 3075, 5131, 11791, 3637, 12621, 105575}},
-{9599, 17, 32978, {1, 3, 1, 3, 27, 1, 117, 11, 153, 401, 1971, 2097, 3227, 14603, 4757, 56281, 112263}},
-{9600, 17, 32980, {1, 3, 3, 5, 13, 25, 51, 209, 367, 327, 1941, 1943, 1347, 14393, 31997, 16001, 129047}},
-{9601, 17, 32983, {1, 1, 5, 11, 19, 51, 109, 229, 71, 923, 1741, 1193, 4657, 6043, 26703, 17757, 75009}},
-{9602, 17, 32987, {1, 1, 7, 3, 23, 3, 125, 165, 137, 999, 1583, 3493, 859, 15603, 7143, 28791, 28201}},
-{9603, 17, 33023, {1, 1, 5, 11, 29, 57, 65, 41, 295, 729, 635, 1871, 6347, 3509, 59, 40765, 42673}},
-{9604, 17, 33031, {1, 3, 3, 3, 15, 59, 53, 97, 15, 131, 891, 1105, 841, 6065, 14427, 4721, 106433}},
-{9605, 17, 33032, {1, 1, 1, 7, 19, 37, 101, 121, 141, 613, 1363, 691, 1731, 12477, 8339, 55669, 99379}},
-{9606, 17, 33035, {1, 3, 5, 13, 17, 49, 75, 25, 447, 113, 1853, 3465, 5225, 4531, 14287, 1039, 17399}},
-{9607, 17, 33038, {1, 3, 5, 3, 3, 49, 101, 79, 117, 939, 1161, 1991, 2343, 7183, 12599, 52877, 94337}},
-{9608, 17, 33040, {1, 3, 1, 1, 19, 47, 73, 195, 475, 435, 1807, 2723, 7885, 15469, 26057, 37325, 57005}},
-{9609, 17, 33043, {1, 1, 1, 11, 17, 7, 111, 143, 357, 977, 719, 553, 4559, 7225, 10405, 26895, 8385}},
-{9610, 17, 33050, {1, 3, 3, 9, 17, 5, 1, 73, 125, 913, 1275, 2387, 5153, 13611, 20585, 8465, 27545}},
-{9611, 17, 33059, {1, 1, 7, 5, 27, 51, 107, 147, 503, 699, 851, 1729, 2875, 16331, 28025, 26451, 92705}},
-{9612, 17, 33080, {1, 1, 5, 9, 3, 37, 21, 139, 13, 427, 225, 1345, 2491, 15495, 25847, 3095, 128879}},
-{9613, 17, 33098, {1, 1, 3, 11, 7, 47, 113, 133, 99, 871, 1151, 1953, 7931, 6389, 28715, 36861, 60017}},
-{9614, 17, 33108, {1, 1, 7, 1, 21, 47, 35, 83, 137, 945, 2047, 3491, 3719, 3001, 20563, 51243, 14491}},
-{9615, 17, 33115, {1, 1, 5, 15, 1, 13, 85, 61, 479, 853, 813, 805, 4931, 12651, 22757, 29531, 92861}},
-{9616, 17, 33117, {1, 3, 7, 7, 27, 63, 31, 169, 43, 185, 637, 729, 7231, 2381, 23539, 53885, 90215}},
-{9617, 17, 33133, {1, 1, 3, 13, 5, 51, 69, 111, 357, 277, 1889, 3809, 8031, 13341, 14261, 34001, 63317}},
-{9618, 17, 33134, {1, 1, 7, 3, 11, 59, 1, 43, 227, 503, 1407, 3917, 7077, 847, 4513, 53007, 66721}},
-{9619, 17, 33157, {1, 1, 5, 11, 15, 25, 109, 169, 25, 391, 597, 2997, 2377, 9045, 15239, 25291, 5451}},
-{9620, 17, 33169, {1, 3, 3, 11, 15, 11, 1, 59, 347, 707, 239, 2473, 8057, 4787, 32247, 17955, 79151}},
-{9621, 17, 33170, {1, 3, 7, 11, 9, 59, 9, 117, 137, 713, 451, 1105, 4485, 14979, 26271, 46017, 89211}},
-{9622, 17, 33176, {1, 3, 3, 3, 3, 19, 95, 131, 413, 291, 1179, 3265, 7107, 10419, 13527, 19905, 8059}},
-{9623, 17, 33182, {1, 3, 7, 9, 29, 43, 19, 243, 443, 27, 1401, 3469, 6925, 2833, 19715, 39667, 11983}},
-{9624, 17, 33192, {1, 3, 3, 7, 23, 33, 115, 59, 29, 61, 1085, 1115, 4007, 12673, 26479, 22397, 95609}},
-{9625, 17, 33205, {1, 3, 3, 5, 1, 47, 43, 83, 21, 621, 59, 1, 891, 12285, 31855, 48641, 52479}},
-{9626, 17, 33212, {1, 3, 3, 5, 3, 9, 17, 181, 15, 315, 1705, 2461, 1853, 14007, 17665, 40593, 126179}},
-{9627, 17, 33215, {1, 3, 5, 3, 3, 23, 83, 163, 29, 293, 1891, 2631, 2989, 7295, 2441, 21689, 8187}},
-{9628, 17, 33217, {1, 3, 1, 1, 1, 23, 53, 215, 185, 843, 1083, 2603, 3857, 4981, 25079, 20249, 93717}},
-{9629, 17, 33227, {1, 3, 5, 11, 7, 61, 127, 13, 449, 395, 1909, 3967, 2441, 3073, 8159, 33979, 26345}},
-{9630, 17, 33229, {1, 1, 5, 1, 15, 5, 93, 87, 319, 173, 1729, 1395, 1019, 5139, 10819, 29877, 81025}},
-{9631, 17, 33238, {1, 3, 3, 7, 17, 55, 61, 227, 299, 245, 849, 211, 895, 2999, 18215, 37069, 32821}},
-{9632, 17, 33241, {1, 1, 5, 3, 17, 49, 115, 55, 447, 533, 1463, 2983, 3245, 9345, 11955, 49145, 128035}},
-{9633, 17, 33260, {1, 3, 1, 7, 5, 17, 61, 71, 101, 529, 1761, 827, 7887, 5713, 31039, 18087, 82277}},
-{9634, 17, 33271, {1, 3, 1, 11, 27, 59, 1, 231, 303, 431, 1279, 3647, 1333, 3675, 29401, 55533, 65997}},
-{9635, 17, 33278, {1, 1, 5, 9, 7, 9, 111, 245, 269, 919, 1147, 1601, 6219, 4931, 3035, 12231, 4011}},
-{9636, 17, 33293, {1, 3, 5, 15, 3, 19, 83, 25, 129, 979, 79, 3027, 3983, 7703, 16859, 12085, 83115}},
-{9637, 17, 33294, {1, 1, 5, 11, 31, 41, 99, 3, 383, 943, 1579, 2435, 1209, 161, 31733, 11755, 95697}},
-{9638, 17, 33296, {1, 1, 1, 9, 9, 55, 115, 187, 499, 165, 1081, 813, 2545, 8065, 10501, 15475, 85107}},
-{9639, 17, 33302, {1, 1, 1, 3, 1, 31, 81, 213, 301, 575, 605, 543, 3347, 12759, 21645, 37173, 36127}},
-{9640, 17, 33305, {1, 3, 3, 9, 21, 29, 51, 91, 307, 617, 1839, 443, 1013, 4473, 3885, 57669, 123271}},
-{9641, 17, 33329, {1, 3, 1, 15, 31, 43, 83, 187, 51, 513, 1505, 3895, 3557, 9527, 27537, 6173, 99595}},
-{9642, 17, 33330, {1, 3, 3, 1, 3, 53, 113, 27, 431, 505, 219, 2143, 6691, 3219, 9589, 9885, 24037}},
-{9643, 17, 33332, {1, 1, 5, 9, 13, 3, 53, 145, 49, 411, 691, 289, 6443, 4963, 13815, 23663, 95497}},
-{9644, 17, 33354, {1, 3, 5, 9, 19, 7, 53, 101, 199, 69, 1821, 3233, 3267, 5947, 4869, 30095, 21255}},
-{9645, 17, 33383, {1, 1, 5, 11, 29, 7, 79, 11, 451, 585, 987, 2333, 1891, 1853, 14739, 34399, 62895}},
-{9646, 17, 33387, {1, 3, 1, 7, 29, 43, 103, 219, 139, 359, 1663, 3453, 7469, 1943, 11457, 19227, 62211}},
-{9647, 17, 33397, {1, 3, 3, 11, 9, 47, 17, 237, 87, 881, 583, 3473, 2579, 975, 1531, 50997, 76219}},
-{9648, 17, 33408, {1, 1, 7, 15, 31, 37, 79, 115, 95, 515, 2003, 2595, 4077, 4537, 9171, 31183, 41219}},
-{9649, 17, 33417, {1, 1, 1, 9, 21, 41, 93, 33, 211, 341, 233, 2217, 6657, 12913, 8329, 3881, 42563}},
-{9650, 17, 33420, {1, 3, 3, 11, 25, 3, 23, 197, 49, 339, 877, 1117, 7817, 14143, 1575, 50301, 92367}},
-{9651, 17, 33423, {1, 3, 5, 5, 19, 45, 69, 179, 447, 861, 1633, 1941, 5821, 1843, 4085, 23501, 109047}},
-{9652, 17, 33431, {1, 3, 1, 3, 31, 29, 49, 183, 311, 133, 345, 1541, 111, 5571, 1943, 11039, 127673}},
-{9653, 17, 33438, {1, 3, 1, 5, 3, 13, 63, 5, 59, 789, 71, 3271, 3871, 9105, 22525, 31, 117803}},
-{9654, 17, 33442, {1, 3, 1, 13, 31, 43, 97, 133, 313, 729, 287, 2971, 5623, 13183, 15179, 47271, 28853}},
-{9655, 17, 33444, {1, 1, 3, 13, 27, 15, 35, 37, 507, 139, 1933, 2847, 361, 10261, 21031, 3889, 56875}},
-{9656, 17, 33448, {1, 3, 1, 15, 31, 13, 45, 73, 279, 331, 471, 3881, 3295, 12035, 28329, 899, 47397}},
-{9657, 17, 33456, {1, 1, 3, 13, 1, 7, 81, 255, 315, 595, 43, 3919, 5229, 7953, 25711, 19509, 107181}},
-{9658, 17, 33459, {1, 1, 3, 15, 7, 33, 117, 169, 71, 577, 629, 3665, 7761, 13529, 26375, 17181, 22125}},
-{9659, 17, 33466, {1, 3, 5, 7, 5, 7, 1, 93, 489, 289, 329, 2273, 685, 14835, 11433, 26041, 112735}},
-{9660, 17, 33473, {1, 3, 3, 3, 9, 39, 45, 23, 171, 35, 571, 551, 7815, 6169, 24283, 61477, 71877}},
-{9661, 17, 33476, {1, 1, 5, 7, 23, 15, 81, 215, 297, 269, 655, 2059, 3643, 12741, 11955, 41085, 46047}},
-{9662, 17, 33491, {1, 1, 7, 5, 3, 35, 125, 141, 419, 137, 1031, 2053, 7925, 7267, 6267, 34323, 77495}},
-{9663, 17, 33494, {1, 1, 7, 11, 3, 57, 91, 43, 139, 691, 1569, 1825, 7855, 1093, 19263, 31601, 16019}},
-{9664, 17, 33507, {1, 3, 1, 5, 21, 7, 11, 225, 105, 757, 1493, 455, 4757, 12007, 5139, 3545, 79717}},
-{9665, 17, 33514, {1, 3, 1, 13, 17, 29, 125, 249, 475, 79, 1271, 341, 863, 853, 2105, 32897, 121261}},
-{9666, 17, 33521, {1, 3, 1, 11, 17, 59, 3, 29, 61, 399, 1465, 4029, 2103, 12481, 28495, 34363, 63781}},
-{9667, 17, 33528, {1, 3, 3, 15, 29, 13, 101, 191, 435, 215, 1355, 2263, 6059, 4545, 7535, 15041, 84091}},
-{9668, 17, 33534, {1, 1, 3, 9, 29, 23, 99, 55, 91, 145, 235, 2847, 725, 209, 24565, 16545, 103669}},
-{9669, 17, 33536, {1, 1, 1, 1, 31, 15, 93, 197, 207, 357, 667, 3511, 3865, 5329, 6491, 9027, 125979}},
-{9670, 17, 33551, {1, 3, 3, 13, 17, 35, 99, 187, 153, 589, 1633, 4053, 1023, 9541, 9841, 39585, 24885}},
-{9671, 17, 33554, {1, 3, 7, 11, 23, 5, 71, 89, 455, 665, 1221, 1821, 591, 11459, 503, 56777, 65691}},
-{9672, 17, 33563, {1, 3, 1, 1, 9, 33, 51, 203, 223, 709, 1263, 3535, 7753, 8279, 8673, 60259, 2671}},
-{9673, 17, 33575, {1, 1, 7, 9, 17, 63, 5, 229, 495, 435, 1711, 3359, 399, 15901, 28519, 56627, 8079}},
-{9674, 17, 33579, {1, 3, 5, 11, 9, 25, 49, 143, 275, 989, 461, 447, 1917, 9253, 28421, 1803, 119725}},
-{9675, 17, 33582, {1, 3, 3, 7, 25, 3, 39, 171, 303, 905, 1353, 2561, 7347, 7339, 15271, 61945, 26343}},
-{9676, 17, 33601, {1, 1, 1, 3, 5, 63, 9, 229, 107, 815, 1705, 3621, 2345, 3065, 16315, 17017, 33667}},
-{9677, 17, 33602, {1, 3, 5, 13, 29, 13, 91, 111, 475, 561, 443, 3825, 5331, 11211, 27639, 28305, 101831}},
-{9678, 17, 33614, {1, 3, 1, 9, 15, 33, 17, 47, 249, 89, 429, 3819, 1959, 14317, 10737, 28151, 40395}},
-{9679, 17, 33625, {1, 3, 7, 13, 19, 29, 83, 81, 511, 783, 823, 2865, 5823, 9459, 27413, 63297, 44181}},
-{9680, 17, 33628, {1, 3, 1, 1, 19, 53, 45, 227, 193, 631, 289, 1227, 6241, 6915, 16051, 31237, 50201}},
-{9681, 17, 33637, {1, 3, 7, 7, 15, 49, 77, 147, 421, 515, 927, 1561, 4391, 12943, 6807, 36889, 70249}},
-{9682, 17, 33656, {1, 3, 7, 7, 17, 15, 63, 123, 101, 283, 59, 977, 5185, 16161, 5007, 36255, 11537}},
-{9683, 17, 33665, {1, 1, 7, 1, 13, 17, 79, 35, 193, 947, 767, 1365, 2145, 13267, 30561, 51949, 37591}},
-{9684, 17, 33683, {1, 1, 1, 13, 11, 13, 91, 129, 355, 549, 295, 673, 209, 15953, 14703, 30857, 47967}},
-{9685, 17, 33695, {1, 3, 5, 9, 17, 17, 83, 161, 189, 585, 21, 1019, 4879, 15943, 17281, 46013, 94839}},
-{9686, 17, 33696, {1, 3, 5, 9, 23, 39, 65, 25, 181, 3, 2005, 635, 201, 9391, 8755, 38535, 88697}},
-{9687, 17, 33702, {1, 3, 1, 15, 13, 35, 47, 125, 429, 901, 895, 3495, 327, 397, 7847, 62157, 3489}},
-{9688, 17, 33708, {1, 3, 5, 3, 19, 21, 81, 39, 85, 169, 1981, 3323, 113, 2057, 16617, 58051, 55059}},
-{9689, 17, 33711, {1, 3, 1, 13, 9, 1, 101, 81, 129, 717, 1495, 4077, 5555, 93, 12957, 14805, 110219}},
-{9690, 17, 33716, {1, 3, 5, 5, 5, 47, 107, 111, 387, 987, 2009, 179, 1111, 3443, 25579, 12293, 123035}},
-{9691, 17, 33728, {1, 1, 7, 13, 21, 25, 33, 211, 9, 783, 1785, 2691, 6835, 2867, 22469, 17853, 90685}},
-{9692, 17, 33737, {1, 1, 3, 3, 19, 57, 59, 203, 197, 347, 553, 1361, 7593, 91, 15303, 30045, 86605}},
-{9693, 17, 33761, {1, 3, 5, 7, 29, 23, 1, 235, 159, 277, 1227, 1727, 1853, 9717, 2377, 13597, 18119}},
-{9694, 17, 33774, {1, 1, 1, 11, 15, 29, 5, 15, 349, 685, 197, 3127, 1075, 8847, 27873, 539, 57149}},
-{9695, 17, 33782, {1, 1, 7, 9, 23, 25, 121, 239, 219, 747, 1981, 2683, 5319, 75, 22569, 29697, 27627}},
-{9696, 17, 33788, {1, 3, 7, 5, 31, 43, 95, 131, 423, 547, 1437, 127, 1953, 861, 839, 54503, 20465}},
-{9697, 17, 33791, {1, 1, 5, 3, 29, 29, 71, 237, 275, 493, 513, 4067, 393, 9415, 20511, 29257, 86267}},
-{9698, 17, 33793, {1, 1, 1, 1, 25, 11, 59, 185, 211, 175, 37, 2999, 4919, 10225, 16727, 60447, 59985}},
-{9699, 17, 33811, {1, 1, 3, 3, 1, 9, 69, 195, 197, 677, 229, 599, 5613, 4537, 5495, 58801, 14297}},
-{9700, 17, 33813, {1, 3, 1, 15, 17, 23, 5, 101, 331, 943, 1433, 2199, 313, 469, 3651, 3281, 100119}},
-{9701, 17, 33818, {1, 1, 5, 15, 13, 25, 87, 45, 229, 821, 59, 761, 6259, 15159, 3197, 39763, 87301}},
-{9702, 17, 33829, {1, 3, 5, 7, 19, 21, 89, 15, 19, 623, 603, 4069, 3531, 13353, 21267, 6355, 53821}},
-{9703, 17, 33842, {1, 1, 5, 9, 13, 13, 111, 77, 439, 599, 1577, 959, 4567, 3117, 7127, 49265, 35667}},
-{9704, 17, 33854, {1, 3, 7, 9, 27, 61, 1, 19, 43, 475, 221, 655, 4351, 15827, 30489, 22245, 41077}},
-{9705, 17, 33856, {1, 1, 3, 13, 17, 17, 111, 85, 253, 11, 367, 2349, 4103, 12517, 27037, 42481, 84451}},
-{9706, 17, 33868, {1, 3, 5, 7, 7, 25, 53, 27, 429, 503, 893, 2923, 2539, 15849, 30157, 12111, 108893}},
-{9707, 17, 33879, {1, 1, 7, 9, 13, 29, 51, 113, 273, 745, 759, 263, 3031, 705, 23203, 64245, 127183}},
-{9708, 17, 33885, {1, 1, 1, 9, 29, 5, 25, 165, 261, 319, 645, 2199, 3135, 10263, 10711, 18713, 63337}},
-{9709, 17, 33886, {1, 1, 5, 1, 23, 41, 43, 71, 365, 683, 1107, 1671, 7079, 8933, 12815, 8095, 97955}},
-{9710, 17, 33892, {1, 3, 1, 15, 9, 43, 105, 217, 131, 299, 1459, 1087, 3493, 15297, 11741, 43383, 35021}},
-{9711, 17, 33907, {1, 3, 1, 3, 3, 57, 69, 7, 73, 977, 1163, 3591, 243, 13129, 23247, 20609, 22489}},
-{9712, 17, 33913, {1, 3, 7, 5, 1, 57, 65, 27, 121, 575, 903, 3527, 5601, 5597, 1941, 60079, 88121}},
-{9713, 17, 33923, {1, 3, 1, 3, 15, 3, 23, 87, 233, 389, 1671, 1557, 4825, 1017, 17697, 26735, 53421}},
-{9714, 17, 33925, {1, 3, 5, 3, 5, 43, 61, 249, 273, 251, 1383, 2415, 1061, 12363, 3071, 23785, 127909}},
-{9715, 17, 33935, {1, 3, 3, 13, 5, 63, 15, 165, 353, 603, 1627, 2037, 487, 11603, 719, 54693, 52645}},
-{9716, 17, 33937, {1, 3, 5, 11, 31, 41, 41, 83, 481, 251, 1903, 2655, 5237, 6073, 20201, 14069, 91649}},
-{9717, 17, 33954, {1, 3, 1, 15, 21, 41, 99, 61, 55, 63, 1595, 1805, 7625, 12261, 23275, 43471, 5147}},
-{9718, 17, 33963, {1, 3, 1, 5, 23, 21, 71, 169, 197, 51, 1653, 3053, 4663, 293, 12751, 15641, 83993}},
-{9719, 17, 33966, {1, 3, 5, 15, 29, 45, 55, 199, 275, 103, 1093, 3569, 5997, 9445, 2291, 30973, 68589}},
-{9720, 17, 33977, {1, 3, 5, 7, 15, 3, 15, 3, 287, 961, 1759, 1153, 7613, 9885, 8981, 5109, 112865}},
-{9721, 17, 33978, {1, 1, 1, 9, 1, 37, 111, 61, 309, 581, 875, 2121, 1035, 4345, 1351, 59743, 34955}},
-{9722, 17, 33991, {1, 3, 7, 7, 11, 23, 51, 235, 23, 697, 991, 1995, 3615, 6665, 15885, 18555, 11711}},
-{9723, 17, 33998, {1, 3, 7, 13, 3, 59, 87, 129, 405, 689, 1189, 2071, 877, 12347, 18381, 28367, 27247}},
-{9724, 17, 34012, {1, 1, 1, 9, 23, 29, 113, 71, 479, 421, 215, 1029, 6125, 13575, 10823, 45303, 3153}},
-{9725, 17, 34016, {1, 1, 3, 11, 13, 5, 31, 29, 279, 597, 791, 319, 1391, 14487, 3811, 36913, 11513}},
-{9726, 17, 34025, {1, 3, 7, 11, 9, 11, 55, 167, 69, 519, 1887, 145, 6133, 1307, 14465, 17419, 18319}},
-{9727, 17, 34033, {1, 1, 3, 1, 29, 25, 57, 75, 19, 187, 1591, 421, 959, 7499, 8377, 42811, 53423}},
-{9728, 17, 34036, {1, 3, 1, 3, 7, 9, 73, 217, 383, 755, 1561, 3923, 3891, 16129, 13195, 62097, 67493}},
-{9729, 17, 34045, {1, 3, 7, 9, 5, 7, 47, 29, 319, 243, 405, 2867, 5803, 2273, 4913, 54777, 88301}},
-{9730, 17, 34065, {1, 3, 7, 1, 25, 11, 51, 183, 387, 863, 39, 2119, 2395, 10175, 20833, 3235, 108197}},
-{9731, 17, 34078, {1, 1, 7, 13, 25, 43, 21, 67, 103, 709, 603, 1045, 7079, 8867, 29039, 61499, 39533}},
-{9732, 17, 34093, {1, 1, 7, 5, 7, 55, 77, 115, 409, 287, 1149, 1535, 7459, 5525, 27129, 43659, 86953}},
-{9733, 17, 34101, {1, 3, 5, 3, 21, 41, 47, 147, 267, 473, 1501, 2663, 5381, 41, 18265, 53845, 16039}},
-{9734, 17, 34108, {1, 1, 7, 15, 27, 63, 95, 103, 169, 1, 133, 3103, 7539, 5765, 11453, 4133, 95133}},
-{9735, 17, 34111, {1, 3, 3, 15, 3, 53, 121, 135, 385, 475, 889, 2557, 4937, 11129, 18461, 16757, 30339}},
-{9736, 17, 34120, {1, 3, 1, 13, 11, 39, 111, 13, 475, 201, 1973, 2151, 6973, 4083, 12593, 44093, 108037}},
-{9737, 17, 34123, {1, 3, 7, 9, 31, 31, 97, 235, 179, 689, 403, 1995, 7697, 7511, 29333, 11005, 50723}},
-{9738, 17, 34125, {1, 1, 7, 13, 23, 5, 7, 171, 441, 921, 1455, 3865, 7089, 5469, 10423, 53013, 80559}},
-{9739, 17, 34153, {1, 3, 5, 3, 25, 43, 105, 157, 507, 143, 297, 1111, 2761, 14103, 4965, 36733, 11741}},
-{9740, 17, 34171, {1, 3, 7, 9, 29, 61, 49, 239, 271, 697, 211, 1633, 2991, 14933, 12347, 44291, 12219}},
-{9741, 17, 34174, {1, 1, 7, 7, 17, 61, 29, 43, 87, 633, 937, 1931, 3541, 12259, 23045, 5923, 48479}},
-{9742, 17, 34178, {1, 3, 3, 3, 15, 25, 105, 17, 159, 863, 1377, 331, 1475, 10573, 28947, 8141, 26671}},
-{9743, 17, 34183, {1, 1, 7, 7, 31, 59, 81, 23, 467, 241, 1257, 1337, 7731, 9071, 3417, 51191, 78369}},
-{9744, 17, 34190, {1, 1, 5, 9, 11, 45, 49, 227, 319, 63, 1339, 885, 4571, 11649, 5607, 10509, 55055}},
-{9745, 17, 34201, {1, 3, 3, 9, 29, 17, 7, 235, 191, 927, 575, 1115, 4111, 14179, 2041, 13331, 29825}},
-{9746, 17, 34211, {1, 1, 5, 9, 27, 61, 71, 201, 341, 577, 221, 1371, 1135, 4347, 24211, 36171, 23435}},
-{9747, 17, 34220, {1, 3, 3, 1, 1, 29, 75, 121, 193, 647, 1429, 275, 5243, 783, 28533, 13941, 68035}},
-{9748, 17, 34225, {1, 3, 5, 15, 21, 27, 117, 183, 251, 991, 935, 3119, 5133, 2765, 7423, 28867, 120565}},
-{9749, 17, 34237, {1, 3, 5, 5, 13, 23, 29, 101, 299, 699, 1249, 1225, 1335, 6079, 17825, 60467, 87787}},
-{9750, 17, 34249, {1, 1, 1, 9, 15, 19, 11, 163, 433, 553, 1487, 813, 3293, 1195, 895, 28431, 62905}},
-{9751, 17, 34250, {1, 1, 1, 13, 25, 37, 111, 129, 391, 813, 1061, 4065, 7339, 10731, 23799, 41463, 99673}},
-{9752, 17, 34264, {1, 1, 7, 15, 3, 21, 45, 77, 471, 155, 967, 711, 4947, 13983, 27827, 28653, 117839}},
-{9753, 17, 34269, {1, 1, 5, 9, 13, 39, 107, 237, 233, 881, 297, 2189, 8085, 1221, 18659, 299, 90951}},
-{9754, 17, 34276, {1, 1, 1, 13, 21, 53, 83, 17, 487, 215, 1203, 3017, 7887, 3759, 10521, 31223, 87917}},
-{9755, 17, 34279, {1, 1, 7, 1, 13, 31, 123, 219, 127, 743, 1325, 3907, 129, 8901, 4855, 22509, 47331}},
-{9756, 17, 34293, {1, 1, 7, 11, 29, 37, 11, 157, 401, 35, 2037, 2873, 7409, 7837, 1247, 33911, 3979}},
-{9757, 17, 34303, {1, 1, 5, 15, 1, 13, 35, 253, 287, 1007, 1417, 1613, 6019, 11617, 6323, 56263, 45073}},
-{9758, 17, 34310, {1, 3, 1, 15, 1, 59, 41, 239, 373, 443, 897, 275, 5783, 8619, 18559, 16279, 92063}},
-{9759, 17, 34340, {1, 3, 1, 9, 23, 33, 83, 43, 231, 819, 1657, 1031, 5507, 12621, 8961, 23059, 63453}},
-{9760, 17, 34349, {1, 1, 7, 5, 29, 49, 21, 251, 267, 43, 729, 4013, 1497, 15489, 16761, 49689, 122755}},
-{9761, 17, 34352, {1, 3, 7, 1, 31, 21, 11, 149, 127, 711, 1249, 49, 5503, 677, 12313, 61301, 16279}},
-{9762, 17, 34355, {1, 1, 5, 11, 9, 15, 41, 61, 81, 991, 1387, 3567, 221, 15835, 8609, 28265, 98199}},
-{9763, 17, 34358, {1, 3, 1, 7, 21, 35, 13, 59, 173, 637, 107, 393, 4551, 6523, 27389, 33129, 45579}},
-{9764, 17, 34362, {1, 1, 1, 9, 29, 51, 65, 199, 417, 553, 1321, 2513, 4749, 8477, 19721, 24301, 16301}},
-{9765, 17, 34376, {1, 3, 5, 1, 25, 13, 7, 55, 163, 581, 1677, 2313, 6843, 15697, 3055, 53171, 59899}},
-{9766, 17, 34381, {1, 3, 1, 5, 31, 13, 101, 195, 235, 359, 911, 1017, 2575, 12801, 997, 7819, 73243}},
-{9767, 17, 34387, {1, 1, 7, 1, 9, 39, 59, 83, 57, 885, 317, 2689, 5741, 11833, 25563, 62581, 62239}},
-{9768, 17, 34389, {1, 1, 5, 15, 25, 25, 55, 207, 223, 907, 913, 387, 5599, 15567, 8859, 13703, 66071}},
-{9769, 17, 34394, {1, 1, 5, 15, 19, 39, 83, 177, 333, 531, 1257, 2687, 7793, 15967, 19175, 1381, 106629}},
-{9770, 17, 34410, {1, 3, 5, 13, 29, 29, 77, 1, 273, 483, 725, 3825, 5115, 4043, 11571, 8693, 49761}},
-{9771, 17, 34423, {1, 1, 7, 3, 5, 45, 37, 65, 267, 191, 301, 2863, 167, 9303, 14563, 41553, 119561}},
-{9772, 17, 34434, {1, 1, 7, 5, 21, 41, 107, 213, 267, 427, 699, 1485, 2125, 16011, 29243, 4691, 50545}},
-{9773, 17, 34436, {1, 3, 3, 9, 15, 29, 81, 53, 289, 689, 933, 2667, 5175, 10409, 28221, 56375, 49109}},
-{9774, 17, 34448, {1, 1, 1, 15, 3, 11, 77, 107, 353, 349, 219, 1961, 7559, 10081, 25119, 46041, 103827}},
-{9775, 17, 34453, {1, 3, 3, 1, 5, 27, 109, 17, 271, 543, 565, 397, 2649, 12037, 4525, 37835, 107071}},
-{9776, 17, 34454, {1, 1, 5, 15, 3, 37, 123, 157, 389, 619, 1379, 4093, 6107, 4419, 21011, 36189, 21269}},
-{9777, 17, 34460, {1, 3, 1, 7, 25, 17, 37, 133, 247, 113, 985, 815, 441, 7869, 25121, 49459, 429}},
-{9778, 17, 34464, {1, 3, 3, 11, 7, 23, 59, 51, 403, 685, 2019, 1167, 7973, 6915, 10819, 43807, 127793}},
-{9779, 17, 34479, {1, 1, 3, 1, 29, 3, 125, 107, 305, 101, 391, 2733, 6883, 5867, 5139, 16025, 112439}},
-{9780, 17, 34491, {1, 1, 5, 5, 23, 23, 89, 33, 275, 451, 1033, 649, 3761, 4735, 26021, 9627, 102747}},
-{9781, 17, 34501, {1, 1, 5, 13, 3, 17, 117, 251, 425, 917, 759, 3047, 8171, 14421, 27765, 11085, 64889}},
-{9782, 17, 34508, {1, 3, 1, 9, 7, 23, 107, 143, 123, 413, 2045, 655, 6283, 8783, 20263, 55463, 33271}},
-{9783, 17, 34516, {1, 3, 7, 11, 5, 49, 73, 55, 465, 43, 587, 3943, 521, 12357, 16273, 26603, 23219}},
-{9784, 17, 34529, {1, 3, 5, 13, 9, 3, 127, 171, 271, 227, 993, 1427, 2235, 6325, 13501, 1411, 44393}},
-{9785, 17, 34530, {1, 1, 1, 3, 13, 27, 19, 37, 175, 423, 5, 3403, 5427, 16345, 30297, 11909, 104647}},
-{9786, 17, 34553, {1, 3, 1, 3, 3, 39, 111, 179, 487, 923, 1945, 1609, 4689, 11807, 13725, 3081, 48163}},
-{9787, 17, 34564, {1, 3, 1, 1, 9, 35, 7, 151, 109, 925, 1249, 3171, 1207, 2053, 5135, 34821, 57291}},
-{9788, 17, 34568, {1, 1, 5, 13, 31, 35, 101, 199, 499, 725, 1229, 2857, 6437, 503, 14437, 35721, 24971}},
-{9789, 17, 34571, {1, 1, 1, 15, 3, 49, 75, 101, 373, 119, 875, 245, 15, 12937, 4731, 13037, 1555}},
-{9790, 17, 34582, {1, 1, 1, 7, 15, 5, 53, 5, 423, 69, 73, 2139, 383, 4035, 6723, 59941, 124503}},
-{9791, 17, 34586, {1, 1, 3, 13, 1, 23, 29, 47, 145, 785, 1013, 1579, 4579, 107, 17571, 46311, 27777}},
-{9792, 17, 34598, {1, 1, 1, 5, 23, 25, 97, 75, 105, 183, 827, 3871, 2005, 6453, 28729, 42583, 62979}},
-{9793, 17, 34604, {1, 3, 5, 9, 11, 49, 29, 201, 333, 441, 429, 1955, 5301, 11775, 22915, 58693, 111917}},
-{9794, 17, 34610, {1, 3, 3, 1, 15, 37, 117, 223, 319, 181, 61, 177, 507, 14871, 16419, 34261, 106937}},
-{9795, 17, 34619, {1, 3, 3, 9, 25, 27, 81, 253, 459, 5, 693, 1271, 485, 16171, 427, 17917, 4393}},
-{9796, 17, 34621, {1, 3, 3, 1, 27, 47, 11, 57, 269, 95, 569, 2733, 3275, 1599, 15073, 58071, 86805}},
-{9797, 17, 34633, {1, 3, 7, 13, 21, 57, 75, 63, 53, 487, 251, 3193, 4279, 2311, 6613, 38319, 93557}},
-{9798, 17, 34634, {1, 3, 5, 5, 31, 35, 39, 255, 11, 81, 605, 1457, 6367, 14121, 8069, 46653, 79945}},
-{9799, 17, 34657, {1, 1, 1, 7, 17, 19, 19, 247, 13, 757, 1069, 2811, 4969, 10943, 29399, 4153, 120817}},
-{9800, 17, 34682, {1, 1, 1, 15, 31, 13, 1, 247, 157, 785, 1565, 897, 4825, 8375, 4933, 60671, 88403}},
-{9801, 17, 34688, {1, 3, 3, 7, 31, 53, 117, 207, 243, 603, 625, 1039, 5725, 5021, 20227, 28613, 123759}},
-{9802, 17, 34691, {1, 1, 5, 1, 7, 29, 65, 153, 393, 821, 295, 2705, 5999, 15801, 31301, 15545, 52917}},
-{9803, 17, 34694, {1, 1, 1, 1, 11, 51, 97, 143, 27, 279, 1005, 1235, 5539, 1523, 26293, 35015, 47835}},
-{9804, 17, 34706, {1, 3, 3, 13, 27, 17, 123, 147, 39, 35, 567, 961, 5431, 5557, 17849, 46675, 102181}},
-{9805, 17, 34708, {1, 1, 7, 11, 7, 25, 73, 223, 459, 207, 1637, 647, 2057, 685, 24539, 48809, 26877}},
-{9806, 17, 34724, {1, 3, 1, 3, 21, 43, 121, 11, 431, 383, 1703, 1451, 2349, 11845, 13801, 20589, 43125}},
-{9807, 17, 34727, {1, 1, 5, 1, 27, 29, 89, 233, 437, 303, 853, 3425, 263, 2073, 14111, 39129, 59547}},
-{9808, 17, 34751, {1, 1, 1, 3, 3, 47, 99, 207, 261, 179, 1761, 2657, 4339, 6567, 25455, 18729, 51431}},
-{9809, 17, 34753, {1, 3, 3, 13, 5, 5, 109, 125, 123, 233, 1713, 1539, 4375, 12187, 18355, 49597, 109959}},
-{9810, 17, 34759, {1, 3, 7, 7, 9, 23, 45, 193, 363, 837, 855, 1413, 7587, 9091, 27907, 17809, 63249}},
-{9811, 17, 34763, {1, 3, 3, 9, 19, 23, 63, 85, 419, 1007, 1753, 539, 1471, 2171, 9239, 36289, 105503}},
-{9812, 17, 34777, {1, 3, 1, 11, 23, 5, 105, 79, 473, 879, 1623, 3155, 5157, 4699, 697, 41919, 15441}},
-{9813, 17, 34778, {1, 1, 7, 11, 5, 21, 43, 207, 491, 355, 857, 2325, 819, 15849, 24529, 5789, 110661}},
-{9814, 17, 34780, {1, 1, 5, 15, 19, 33, 81, 137, 473, 853, 1681, 3841, 5617, 13715, 1987, 52983, 66327}},
-{9815, 17, 34796, {1, 3, 5, 7, 11, 31, 69, 85, 33, 197, 1771, 1957, 1311, 169, 14159, 7327, 8577}},
-{9816, 17, 34799, {1, 1, 3, 9, 11, 23, 19, 143, 9, 579, 111, 2973, 3567, 8561, 10447, 55875, 64305}},
-{9817, 17, 34801, {1, 1, 5, 7, 1, 17, 93, 11, 423, 1007, 839, 719, 3965, 14531, 17301, 29577, 4083}},
-{9818, 17, 34817, {1, 3, 5, 13, 19, 17, 123, 61, 59, 115, 1165, 579, 2545, 633, 5597, 21865, 109167}},
-{9819, 17, 34824, {1, 1, 5, 3, 29, 29, 99, 163, 321, 367, 1523, 3719, 665, 15843, 28831, 63823, 113533}},
-{9820, 17, 34827, {1, 1, 1, 3, 15, 7, 85, 1, 181, 759, 537, 3315, 7159, 4363, 4183, 53775, 8801}},
-{9821, 17, 34837, {1, 3, 1, 1, 15, 53, 9, 35, 459, 417, 1169, 2055, 1175, 10923, 335, 24269, 93001}},
-{9822, 17, 34841, {1, 3, 1, 5, 31, 43, 51, 149, 175, 541, 629, 1147, 7585, 9725, 18623, 13345, 65391}},
-{9823, 17, 34853, {1, 3, 7, 1, 13, 39, 13, 217, 507, 765, 721, 1491, 5037, 6267, 2871, 19181, 123751}},
-{9824, 17, 34858, {1, 1, 3, 5, 21, 9, 123, 195, 63, 347, 7, 531, 3015, 9457, 29543, 51479, 26607}},
-{9825, 17, 34877, {1, 1, 1, 1, 21, 15, 81, 127, 429, 15, 901, 1503, 1919, 6515, 2477, 53571, 113447}},
-{9826, 17, 34886, {1, 3, 1, 13, 9, 33, 79, 169, 499, 767, 441, 2085, 2429, 10213, 4125, 2611, 26137}},
-{9827, 17, 34895, {1, 1, 3, 1, 19, 23, 83, 179, 447, 513, 913, 1201, 1861, 11595, 29037, 7775, 116417}},
-{9828, 17, 34897, {1, 3, 3, 7, 3, 57, 47, 183, 413, 319, 1375, 1401, 2231, 14331, 28625, 43839, 102717}},
-{9829, 17, 34898, {1, 1, 5, 11, 31, 27, 111, 85, 191, 155, 2025, 1501, 4991, 4655, 3451, 10219, 60391}},
-{9830, 17, 34916, {1, 3, 3, 7, 17, 19, 113, 37, 423, 479, 709, 3659, 6567, 1709, 13483, 61821, 77101}},
-{9831, 17, 34923, {1, 3, 1, 13, 3, 17, 73, 61, 275, 359, 1341, 449, 1373, 12047, 11207, 52651, 83305}},
-{9832, 17, 34928, {1, 1, 7, 9, 9, 45, 15, 121, 15, 51, 509, 2189, 5057, 6119, 11669, 14559, 108323}},
-{9833, 17, 34934, {1, 1, 7, 7, 25, 13, 13, 141, 157, 249, 823, 821, 1909, 5925, 3505, 13187, 19237}},
-{9834, 17, 34940, {1, 3, 3, 1, 9, 51, 79, 91, 5, 709, 787, 2427, 4613, 7307, 20141, 1675, 49779}},
-{9835, 17, 34944, {1, 1, 1, 11, 11, 13, 33, 81, 413, 981, 907, 2709, 4113, 10607, 2587, 12845, 11103}},
-{9836, 17, 34947, {1, 1, 7, 9, 13, 25, 37, 81, 375, 1013, 2027, 321, 3947, 2269, 10687, 7537, 67495}},
-{9837, 17, 34953, {1, 3, 5, 11, 9, 43, 53, 111, 339, 841, 503, 3209, 6437, 10893, 13627, 51809, 57229}},
-{9838, 17, 34956, {1, 3, 1, 1, 21, 15, 71, 93, 453, 405, 1099, 2979, 7471, 10173, 17875, 13179, 48615}},
-{9839, 17, 34967, {1, 3, 5, 9, 9, 1, 121, 117, 275, 157, 57, 3459, 4787, 15005, 24591, 23963, 45077}},
-{9840, 17, 34968, {1, 1, 5, 3, 21, 57, 113, 207, 169, 603, 637, 1455, 6281, 6527, 17219, 32307, 18617}},
-{9841, 17, 34971, {1, 3, 7, 5, 25, 15, 99, 91, 253, 267, 537, 713, 3929, 895, 7999, 47989, 118731}},
-{9842, 17, 34974, {1, 3, 7, 15, 23, 17, 5, 129, 121, 251, 219, 2547, 7291, 1079, 14577, 56229, 35253}},
-{9843, 17, 34977, {1, 3, 1, 15, 5, 61, 35, 135, 497, 681, 751, 2303, 6697, 11225, 30389, 61673, 87313}},
-{9844, 17, 34980, {1, 3, 1, 7, 7, 37, 9, 85, 257, 805, 1325, 3597, 6065, 727, 18203, 57077, 437}},
-{9845, 17, 34983, {1, 3, 5, 7, 5, 43, 29, 179, 73, 173, 1441, 1233, 1779, 7893, 10629, 27547, 7775}},
-{9846, 17, 34998, {1, 1, 7, 5, 31, 29, 21, 35, 289, 423, 449, 3331, 2929, 6827, 15569, 9873, 76889}},
-{9847, 17, 35004, {1, 1, 7, 13, 13, 37, 55, 99, 135, 797, 1263, 2539, 893, 4225, 16689, 38259, 50857}},
-{9848, 17, 35010, {1, 1, 3, 1, 5, 3, 95, 29, 15, 539, 825, 3931, 4809, 8299, 29891, 61357, 97523}},
-{9849, 17, 35012, {1, 3, 1, 9, 27, 25, 115, 239, 387, 163, 1153, 31, 2375, 7943, 31929, 1121, 33085}},
-{9850, 17, 35030, {1, 3, 5, 9, 3, 53, 121, 159, 165, 81, 317, 3051, 1991, 493, 2029, 43305, 130209}},
-{9851, 17, 35039, {1, 1, 1, 5, 9, 57, 39, 247, 73, 613, 1047, 3289, 2569, 5363, 18475, 32749, 39415}},
-{9852, 17, 35058, {1, 3, 1, 5, 19, 23, 39, 33, 151, 463, 153, 737, 2501, 7531, 2769, 35595, 71799}},
-{9853, 17, 35063, {1, 3, 5, 5, 29, 49, 105, 81, 67, 441, 1101, 2241, 6243, 6177, 7157, 51635, 81241}},
-{9854, 17, 35082, {1, 3, 3, 3, 29, 53, 13, 239, 487, 503, 97, 1323, 1817, 13021, 12881, 26943, 21011}},
-{9855, 17, 35095, {1, 1, 1, 15, 25, 9, 5, 205, 85, 635, 789, 2495, 5069, 4987, 847, 26857, 84225}},
-{9856, 17, 35096, {1, 1, 3, 15, 9, 51, 79, 13, 377, 637, 159, 3407, 2057, 13967, 31781, 40869, 52987}},
-{9857, 17, 35101, {1, 3, 1, 13, 11, 27, 103, 207, 383, 887, 749, 1119, 285, 4269, 31745, 57539, 5671}},
-{9858, 17, 35102, {1, 3, 1, 13, 23, 19, 41, 43, 455, 425, 1653, 4091, 4855, 16321, 169, 59289, 82397}},
-{9859, 17, 35105, {1, 3, 3, 15, 31, 39, 51, 127, 391, 989, 1831, 3327, 6487, 6077, 17277, 52093, 20389}},
-{9860, 17, 35112, {1, 3, 5, 15, 19, 1, 21, 241, 15, 543, 1529, 2355, 1503, 12795, 17321, 41219, 61115}},
-{9861, 17, 35118, {1, 1, 3, 11, 9, 33, 21, 197, 307, 141, 1663, 371, 1663, 8307, 3617, 56941, 62477}},
-{9862, 17, 35120, {1, 3, 7, 9, 19, 53, 123, 3, 29, 635, 1795, 2471, 2491, 15847, 9169, 2561, 101515}},
-{9863, 17, 35130, {1, 1, 5, 3, 19, 11, 117, 231, 475, 837, 1833, 3499, 4415, 9961, 28285, 37821, 81497}},
-{9864, 17, 35143, {1, 1, 3, 5, 7, 11, 57, 89, 345, 157, 1519, 3021, 7157, 2159, 32557, 31559, 128907}},
-{9865, 17, 35147, {1, 1, 7, 3, 27, 1, 15, 177, 489, 405, 811, 3597, 4939, 15595, 7279, 58097, 84703}},
-{9866, 17, 35152, {1, 3, 1, 9, 25, 61, 119, 219, 111, 339, 1091, 759, 6087, 16001, 6757, 15627, 1691}},
-{9867, 17, 35157, {1, 3, 7, 9, 1, 39, 107, 139, 143, 917, 421, 1623, 7135, 4851, 6687, 6177, 102425}},
-{9868, 17, 35164, {1, 1, 7, 13, 23, 17, 19, 167, 317, 331, 743, 3737, 2195, 545, 2185, 9125, 30503}},
-{9869, 17, 35178, {1, 1, 5, 13, 27, 33, 117, 141, 493, 129, 1553, 2335, 4161, 14205, 24177, 35163, 84869}},
-{9870, 17, 35195, {1, 3, 7, 1, 11, 9, 75, 133, 113, 507, 2007, 2473, 4769, 14655, 17967, 17709, 90653}},
-{9871, 17, 35197, {1, 1, 7, 11, 17, 11, 83, 23, 387, 61, 29, 3905, 4351, 15173, 28375, 9129, 111939}},
-{9872, 17, 35201, {1, 1, 5, 15, 15, 53, 81, 125, 189, 937, 1607, 2595, 2847, 7229, 22241, 26269, 64781}},
-{9873, 17, 35207, {1, 3, 1, 7, 5, 11, 61, 111, 13, 423, 885, 2329, 6003, 16331, 11207, 25743, 54619}},
-{9874, 17, 35231, {1, 3, 5, 9, 1, 13, 95, 241, 237, 629, 263, 1629, 1063, 12695, 14501, 5455, 121483}},
-{9875, 17, 35249, {1, 1, 7, 15, 5, 17, 45, 255, 143, 79, 87, 1755, 6215, 5095, 32411, 8695, 85511}},
-{9876, 17, 35250, {1, 3, 7, 7, 21, 11, 117, 135, 333, 73, 1471, 2749, 5801, 4209, 9353, 46171, 90645}},
-{9877, 17, 35256, {1, 1, 7, 13, 11, 35, 77, 149, 159, 783, 1527, 2881, 1409, 3455, 26991, 3225, 30693}},
-{9878, 17, 35259, {1, 1, 3, 15, 19, 55, 21, 245, 207, 103, 775, 2041, 4637, 7333, 11267, 60509, 43099}},
-{9879, 17, 35262, {1, 3, 3, 15, 17, 63, 23, 81, 183, 923, 75, 391, 615, 13343, 20839, 56529, 115747}},
-{9880, 17, 35273, {1, 3, 1, 13, 5, 5, 15, 27, 263, 497, 1365, 2733, 5395, 7461, 2725, 24735, 89251}},
-{9881, 17, 35282, {1, 1, 7, 7, 29, 17, 39, 117, 363, 915, 123, 283, 4575, 3497, 20995, 37883, 16645}},
-{9882, 17, 35298, {1, 3, 3, 9, 1, 25, 79, 181, 331, 617, 393, 1807, 5145, 8007, 9173, 45189, 37945}},
-{9883, 17, 35307, {1, 3, 1, 5, 1, 9, 127, 137, 379, 371, 367, 3237, 581, 15295, 18191, 37689, 103495}},
-{9884, 17, 35328, {1, 1, 7, 1, 29, 53, 103, 173, 171, 973, 933, 3847, 3185, 10107, 31701, 45021, 106251}},
-{9885, 17, 35334, {1, 1, 1, 7, 23, 9, 61, 25, 343, 471, 2041, 2179, 7647, 1885, 15353, 50379, 67681}},
-{9886, 17, 35343, {1, 1, 5, 11, 31, 13, 51, 185, 83, 917, 85, 1317, 8185, 14949, 32455, 57939, 1217}},
-{9887, 17, 35345, {1, 1, 7, 5, 23, 45, 101, 227, 497, 941, 985, 167, 6847, 9611, 20011, 40069, 83285}},
-{9888, 17, 35355, {1, 1, 5, 13, 17, 33, 61, 197, 433, 255, 67, 1479, 5663, 6501, 30695, 27235, 80141}},
-{9889, 17, 35388, {1, 1, 3, 5, 11, 45, 123, 49, 327, 893, 1963, 2225, 2611, 8925, 22811, 2313, 8411}},
-{9890, 17, 35399, {1, 3, 7, 7, 15, 39, 75, 235, 13, 847, 575, 3947, 6947, 2061, 13467, 103, 86285}},
-{9891, 17, 35403, {1, 1, 7, 3, 21, 43, 113, 197, 141, 873, 1139, 2707, 7235, 10683, 10831, 33695, 57063}},
-{9892, 17, 35408, {1, 3, 5, 1, 3, 27, 45, 43, 119, 979, 1933, 1851, 6497, 14937, 4965, 41285, 120221}},
-{9893, 17, 35413, {1, 1, 3, 1, 23, 59, 67, 7, 49, 351, 1053, 1837, 501, 7671, 26239, 51951, 95119}},
-{9894, 17, 35418, {1, 3, 5, 11, 3, 19, 33, 33, 219, 175, 1439, 197, 1841, 159, 11229, 20463, 81797}},
-{9895, 17, 35434, {1, 1, 7, 1, 13, 11, 79, 75, 53, 525, 91, 233, 5999, 2921, 21295, 56831, 116049}},
-{9896, 17, 35436, {1, 3, 3, 13, 29, 7, 71, 207, 193, 635, 1393, 3093, 3775, 12445, 23281, 29401, 103225}},
-{9897, 17, 35448, {1, 1, 7, 3, 29, 57, 111, 163, 63, 593, 881, 1587, 3027, 12599, 30977, 38891, 95495}},
-{9898, 17, 35460, {1, 1, 5, 15, 17, 57, 111, 169, 149, 767, 377, 765, 7533, 1539, 22979, 55489, 29799}},
-{9899, 17, 35475, {1, 3, 5, 15, 25, 7, 127, 71, 319, 389, 497, 1513, 1287, 7359, 12311, 45457, 45897}},
-{9900, 17, 35494, {1, 1, 5, 3, 3, 35, 45, 17, 49, 483, 197, 727, 5355, 7201, 3035, 14313, 40933}},
-{9901, 17, 35497, {1, 1, 7, 15, 1, 9, 27, 59, 455, 653, 1907, 281, 1435, 14593, 18909, 37655, 87603}},
-{9902, 17, 35503, {1, 1, 7, 11, 29, 9, 67, 17, 353, 709, 859, 3687, 7741, 4251, 12263, 41717, 79393}},
-{9903, 17, 35508, {1, 3, 3, 3, 1, 15, 113, 187, 255, 851, 503, 4089, 7923, 1701, 305, 8353, 16357}},
-{9904, 17, 35511, {1, 1, 5, 3, 17, 31, 29, 233, 377, 215, 1889, 3459, 2443, 3907, 4193, 16519, 49089}},
-{9905, 17, 35518, {1, 1, 3, 1, 17, 39, 11, 255, 247, 305, 669, 1769, 1355, 12055, 2275, 51681, 112337}},
-{9906, 17, 35520, {1, 3, 1, 1, 17, 17, 75, 95, 409, 21, 1513, 1443, 4931, 6491, 1587, 62979, 90395}},
-{9907, 17, 35530, {1, 1, 3, 5, 3, 19, 125, 175, 279, 911, 301, 407, 7773, 949, 32107, 13571, 58717}},
-{9908, 17, 35537, {1, 3, 3, 15, 31, 35, 11, 223, 125, 209, 1719, 1725, 3387, 14879, 32243, 7219, 126791}},
-{9909, 17, 35543, {1, 1, 3, 1, 31, 29, 67, 79, 93, 193, 1573, 2285, 3209, 8397, 17717, 5657, 61545}},
-{9910, 17, 35560, {1, 3, 1, 9, 11, 33, 85, 121, 193, 63, 461, 1835, 889, 10687, 19831, 49551, 59087}},
-{9911, 17, 35566, {1, 3, 3, 7, 11, 3, 9, 87, 91, 487, 289, 1113, 8135, 7971, 16693, 31009, 81197}},
-{9912, 17, 35571, {1, 3, 3, 1, 23, 23, 61, 209, 409, 845, 547, 1493, 465, 6399, 17633, 53647, 52425}},
-{9913, 17, 35598, {1, 1, 7, 7, 21, 31, 71, 249, 63, 895, 653, 93, 4429, 8951, 16873, 48089, 33947}},
-{9914, 17, 35609, {1, 3, 5, 11, 3, 35, 49, 15, 379, 645, 855, 3657, 8019, 2141, 11233, 60731, 80455}},
-{9915, 17, 35612, {1, 3, 1, 3, 1, 53, 101, 157, 255, 765, 1575, 1615, 7677, 9699, 13351, 2207, 90939}},
-{9916, 17, 35615, {1, 3, 7, 7, 5, 43, 123, 109, 119, 391, 1889, 1991, 3151, 1457, 16321, 65245, 75891}},
-{9917, 17, 35616, {1, 3, 1, 15, 9, 1, 113, 249, 1, 675, 501, 487, 2209, 4411, 6609, 29243, 100177}},
-{9918, 17, 35622, {1, 1, 1, 7, 9, 23, 9, 197, 341, 191, 453, 3733, 5475, 15515, 28979, 36077, 17801}},
-{9919, 17, 35626, {1, 1, 3, 13, 5, 35, 85, 121, 59, 429, 1251, 3437, 3121, 12411, 14713, 28125, 31921}},
-{9920, 17, 35633, {1, 3, 5, 3, 27, 17, 61, 255, 485, 709, 83, 3201, 2191, 3371, 2941, 10931, 22141}},
-{9921, 17, 35636, {1, 1, 1, 1, 19, 19, 25, 177, 397, 579, 529, 1619, 3887, 4537, 8123, 52481, 8305}},
-{9922, 17, 35645, {1, 1, 3, 15, 3, 15, 77, 51, 31, 881, 203, 2359, 4947, 6321, 14705, 16471, 84395}},
-{9923, 17, 35653, {1, 3, 7, 9, 13, 53, 67, 41, 289, 721, 1743, 2725, 435, 1327, 14953, 14283, 113211}},
-{9924, 17, 35663, {1, 3, 1, 5, 19, 23, 73, 181, 187, 675, 125, 1877, 6167, 7919, 3955, 25007, 28299}},
-{9925, 17, 35665, {1, 1, 3, 1, 5, 11, 123, 189, 173, 123, 499, 2175, 483, 13017, 14709, 5797, 36327}},
-{9926, 17, 35682, {1, 3, 7, 5, 21, 39, 79, 229, 19, 203, 375, 3901, 1053, 14209, 13535, 63155, 99727}},
-{9927, 17, 35687, {1, 1, 1, 13, 11, 29, 29, 173, 441, 271, 1147, 2891, 965, 10777, 16325, 37135, 101601}},
-{9928, 17, 35688, {1, 1, 3, 3, 25, 13, 79, 233, 75, 191, 987, 3231, 3667, 1525, 14193, 62027, 77441}},
-{9929, 17, 35691, {1, 3, 1, 1, 15, 53, 17, 45, 367, 263, 425, 1565, 6139, 13833, 12547, 61103, 75361}},
-{9930, 17, 35696, {1, 1, 5, 15, 5, 57, 123, 47, 407, 887, 375, 1181, 5367, 10283, 24799, 33121, 76373}},
-{9931, 17, 35727, {1, 1, 7, 3, 11, 17, 65, 133, 3, 609, 601, 3391, 7801, 4137, 32095, 55983, 23037}},
-{9932, 17, 35741, {1, 3, 1, 3, 25, 5, 125, 5, 297, 571, 145, 3601, 1929, 13457, 16977, 21049, 92169}},
-{9933, 17, 35742, {1, 3, 5, 13, 23, 29, 13, 143, 507, 187, 857, 427, 5125, 1377, 10947, 58473, 110541}},
-{9934, 17, 35746, {1, 3, 3, 15, 15, 49, 39, 103, 193, 507, 639, 2399, 3829, 12105, 15993, 52975, 115935}},
-{9935, 17, 35748, {1, 3, 7, 3, 7, 41, 95, 127, 193, 923, 1729, 3039, 7959, 3345, 7725, 35293, 34361}},
-{9936, 17, 35752, {1, 3, 5, 13, 17, 53, 111, 141, 151, 389, 1955, 3333, 4523, 6331, 21239, 57447, 113325}},
-{9937, 17, 35770, {1, 3, 7, 15, 31, 7, 11, 35, 105, 607, 1665, 3281, 487, 9417, 26205, 26963, 81537}},
-{9938, 17, 35811, {1, 3, 1, 1, 17, 15, 3, 55, 451, 691, 1525, 2009, 6443, 4629, 15091, 46961, 83361}},
-{9939, 17, 35817, {1, 3, 1, 15, 1, 29, 99, 79, 225, 665, 623, 2389, 3303, 7221, 20567, 15917, 24677}},
-{9940, 17, 35832, {1, 1, 3, 15, 3, 17, 125, 239, 485, 849, 327, 1459, 3911, 2145, 14475, 24337, 19695}},
-{9941, 17, 35838, {1, 3, 5, 7, 7, 37, 19, 51, 373, 587, 147, 563, 7623, 7781, 18289, 37239, 6803}},
-{9942, 17, 35850, {1, 3, 5, 1, 9, 63, 5, 87, 171, 5, 1553, 429, 5001, 7881, 1493, 20425, 57727}},
-{9943, 17, 35863, {1, 3, 5, 9, 25, 43, 17, 71, 87, 869, 1219, 2661, 4571, 9689, 18799, 62467, 128531}},
-{9944, 17, 35870, {1, 1, 3, 3, 19, 53, 61, 9, 55, 433, 1555, 2369, 1423, 9081, 19185, 8513, 111079}},
-{9945, 17, 35879, {1, 3, 5, 15, 11, 61, 1, 147, 17, 71, 1563, 1113, 4809, 16229, 23743, 59757, 64699}},
-{9946, 17, 35880, {1, 1, 5, 11, 29, 23, 61, 43, 203, 97, 1119, 237, 6445, 14507, 9799, 18447, 14745}},
-{9947, 17, 35891, {1, 3, 5, 15, 11, 17, 117, 139, 117, 537, 251, 149, 2731, 15863, 1381, 25435, 25501}},
-{9948, 17, 35893, {1, 3, 3, 15, 31, 57, 53, 43, 95, 445, 1423, 3833, 2485, 11789, 16011, 8101, 39165}},
-{9949, 17, 35903, {1, 1, 3, 11, 15, 37, 117, 3, 245, 57, 593, 2771, 7181, 11397, 5691, 3217, 44139}},
-{9950, 17, 35905, {1, 3, 5, 1, 11, 13, 121, 85, 85, 511, 1837, 611, 237, 4893, 24025, 28903, 102025}},
-{9951, 17, 35926, {1, 3, 1, 11, 5, 45, 43, 45, 393, 741, 1157, 1511, 1665, 2359, 19071, 24537, 122879}},
-{9952, 17, 35930, {1, 3, 3, 3, 9, 59, 27, 11, 257, 203, 1535, 2729, 2313, 3539, 1689, 31901, 42949}},
-{9953, 17, 35941, {1, 1, 1, 11, 17, 7, 21, 35, 479, 697, 107, 1317, 6585, 705, 3789, 20439, 33375}},
-{9954, 17, 35956, {1, 1, 3, 11, 19, 37, 123, 233, 253, 733, 901, 3047, 3595, 2357, 24533, 40519, 109171}},
-{9955, 17, 35963, {1, 3, 3, 13, 29, 51, 25, 149, 57, 253, 2001, 351, 7367, 15361, 4955, 60951, 19449}},
-{9956, 17, 35970, {1, 1, 3, 15, 21, 53, 25, 239, 257, 437, 711, 3599, 5441, 7405, 15039, 19207, 63841}},
-{9957, 17, 35984, {1, 3, 1, 9, 17, 41, 43, 231, 413, 747, 1447, 1407, 2615, 14529, 10781, 20001, 82713}},
-{9958, 17, 35996, {1, 3, 7, 7, 9, 29, 25, 55, 53, 423, 1711, 2871, 2675, 421, 31703, 57099, 2955}},
-{9959, 17, 36005, {1, 3, 1, 7, 31, 17, 113, 83, 387, 611, 1815, 2137, 3453, 4409, 20377, 60263, 81205}},
-{9960, 17, 36012, {1, 1, 5, 3, 11, 1, 7, 225, 367, 267, 95, 939, 3801, 2619, 1207, 62695, 116407}},
-{9961, 17, 36015, {1, 3, 3, 9, 5, 39, 85, 45, 247, 483, 491, 865, 3493, 8243, 8411, 26449, 50473}},
-{9962, 17, 36030, {1, 3, 3, 9, 1, 53, 23, 127, 13, 529, 1925, 2629, 3451, 15073, 16075, 29909, 34101}},
-{9963, 17, 36035, {1, 3, 1, 11, 1, 9, 125, 57, 79, 633, 979, 3843, 325, 883, 7769, 40155, 104057}},
-{9964, 17, 36042, {1, 1, 7, 13, 23, 53, 27, 157, 493, 901, 1077, 1079, 1327, 15903, 20603, 64377, 103335}},
-{9965, 17, 36047, {1, 3, 3, 3, 3, 35, 37, 167, 73, 301, 385, 1045, 6913, 2269, 22491, 19735, 70125}},
-{9966, 17, 36049, {1, 1, 1, 11, 5, 23, 23, 85, 267, 845, 207, 77, 1245, 16209, 25579, 12417, 48723}},
-{9967, 17, 36059, {1, 1, 5, 15, 11, 17, 43, 83, 373, 1005, 541, 115, 163, 2165, 8181, 35839, 44471}},
-{9968, 17, 36071, {1, 3, 5, 7, 27, 41, 101, 13, 213, 235, 2037, 2179, 2121, 4481, 8127, 20011, 3981}},
-{9969, 17, 36080, {1, 1, 5, 11, 7, 43, 59, 129, 127, 387, 489, 1985, 623, 13307, 19765, 62155, 93271}},
-{9970, 17, 36085, {1, 1, 7, 5, 23, 63, 23, 177, 211, 233, 101, 1809, 7411, 8003, 25101, 32601, 75071}},
-{9971, 17, 36097, {1, 1, 1, 11, 3, 25, 9, 91, 459, 611, 867, 3639, 5457, 9101, 15333, 40069, 67723}},
-{9972, 17, 36110, {1, 3, 7, 5, 3, 29, 111, 75, 459, 195, 1405, 2281, 6085, 4425, 29061, 57335, 87449}},
-{9973, 17, 36115, {1, 3, 7, 11, 21, 45, 53, 81, 77, 863, 1901, 3355, 5253, 10897, 26289, 48399, 26877}},
-{9974, 17, 36118, {1, 3, 3, 13, 21, 37, 69, 87, 259, 101, 1203, 167, 6229, 145, 9355, 15347, 68047}},
-{9975, 17, 36124, {1, 1, 3, 1, 31, 1, 15, 229, 429, 915, 929, 381, 1857, 8441, 22207, 47071, 127853}},
-{9976, 17, 36137, {1, 3, 7, 3, 15, 9, 13, 161, 173, 573, 405, 3253, 7331, 13965, 3061, 40687, 130185}},
-{9977, 17, 36138, {1, 3, 5, 5, 29, 29, 9, 115, 393, 377, 909, 321, 2861, 9881, 17863, 52033, 55133}},
-{9978, 17, 36155, {1, 1, 7, 7, 27, 53, 101, 213, 199, 301, 1995, 2549, 5037, 13639, 18423, 23547, 79359}},
-{9979, 17, 36160, {1, 3, 1, 7, 21, 51, 29, 151, 301, 665, 571, 53, 2637, 7229, 12517, 33647, 49413}},
-{9980, 17, 36189, {1, 3, 3, 13, 13, 49, 49, 131, 325, 273, 1127, 2981, 2365, 14287, 23185, 26915, 81755}},
-{9981, 17, 36190, {1, 1, 5, 3, 17, 45, 25, 79, 37, 265, 1205, 1805, 6707, 11525, 16473, 39525, 9571}},
-{9982, 17, 36203, {1, 3, 3, 15, 9, 43, 55, 101, 469, 939, 365, 3443, 5759, 4751, 28893, 46727, 74569}},
-{9983, 17, 36211, {1, 3, 7, 9, 5, 33, 11, 201, 263, 227, 1475, 2795, 1489, 11129, 18053, 31009, 73105}},
-{9984, 17, 36218, {1, 3, 5, 5, 5, 25, 41, 151, 393, 237, 2017, 3811, 953, 13835, 28761, 22439, 76355}},
-{9985, 17, 36230, {1, 1, 5, 13, 21, 37, 29, 11, 289, 67, 1317, 511, 685, 15227, 8731, 15039, 79491}},
-{9986, 17, 36241, {1, 3, 1, 9, 31, 59, 123, 169, 473, 139, 575, 1057, 3213, 8213, 21845, 28123, 105335}},
-{9987, 17, 36244, {1, 1, 1, 5, 21, 47, 23, 121, 403, 5, 1457, 2137, 569, 9267, 6367, 6991, 3113}},
-{9988, 17, 36253, {1, 3, 3, 7, 13, 7, 25, 215, 81, 1003, 2041, 1317, 3913, 14705, 30551, 50889, 83441}},
-{9989, 17, 36257, {1, 3, 3, 3, 13, 17, 63, 229, 83, 901, 953, 2603, 4685, 6961, 7519, 52441, 33223}},
-{9990, 17, 36264, {1, 3, 7, 5, 7, 57, 65, 73, 243, 531, 261, 2517, 4083, 5889, 22913, 49603, 67135}},
-{9991, 17, 36272, {1, 3, 5, 11, 15, 47, 81, 83, 35, 1021, 1313, 1109, 5103, 5469, 18149, 15307, 34939}},
-{9992, 17, 36290, {1, 3, 7, 5, 21, 13, 105, 157, 435, 23, 931, 3565, 1, 4987, 8829, 7327, 51049}},
-{9993, 17, 36292, {1, 1, 3, 11, 29, 9, 59, 49, 261, 1009, 1953, 2683, 8125, 10937, 16683, 36013, 5967}},
-{9994, 17, 36301, {1, 1, 1, 1, 19, 29, 57, 9, 307, 457, 675, 3023, 495, 15257, 7945, 10449, 30155}},
-{9995, 17, 36309, {1, 1, 7, 13, 25, 9, 51, 135, 491, 205, 1715, 3253, 1031, 4137, 14885, 39925, 6061}},
-{9996, 17, 36313, {1, 1, 7, 7, 3, 13, 111, 91, 469, 133, 1221, 1035, 919, 3697, 26387, 41675, 487}},
-{9997, 17, 36316, {1, 1, 3, 1, 19, 53, 11, 113, 245, 747, 189, 4051, 87, 1767, 3595, 10259, 100097}},
-{9998, 17, 36319, {1, 1, 5, 3, 23, 49, 31, 47, 341, 1019, 723, 2353, 6191, 3809, 3297, 39443, 73529}},
-{9999, 17, 36330, {1, 3, 3, 9, 25, 27, 123, 49, 51, 85, 1063, 2633, 6549, 14493, 7367, 3557, 60651}},
-{10000, 17, 36335, {1, 3, 7, 5, 13, 27, 127, 65, 115, 731, 1147, 283, 91, 14205, 2457, 57083, 35815}},
-{10001, 17, 36347, {1, 3, 3, 3, 25, 63, 99, 249, 25, 951, 733, 3621, 7139, 14223, 23641, 20287, 30743}},
-{10002, 17, 36353, {1, 3, 3, 7, 21, 23, 83, 207, 235, 467, 1857, 2661, 1391, 10097, 12297, 54825, 5035}},
-{10003, 17, 36356, {1, 1, 5, 3, 31, 17, 77, 9, 215, 553, 989, 3643, 729, 2057, 32053, 50305, 5499}},
-{10004, 17, 36368, {1, 1, 7, 1, 23, 5, 111, 195, 431, 947, 403, 1781, 943, 15073, 67, 52225, 98987}},
-{10005, 17, 36374, {1, 1, 5, 11, 23, 1, 41, 33, 457, 767, 275, 801, 5119, 3781, 14805, 52789, 41775}},
-{10006, 17, 36377, {1, 1, 5, 3, 9, 53, 15, 183, 281, 691, 165, 3277, 7673, 1509, 16605, 53799, 100185}},
-{10007, 17, 36384, {1, 3, 5, 11, 19, 45, 29, 159, 167, 67, 1259, 879, 7787, 8855, 24153, 42667, 102855}},
-{10008, 17, 36407, {1, 1, 7, 13, 31, 19, 43, 133, 295, 287, 1985, 2451, 2297, 3853, 22401, 27659, 11149}},
-{10009, 17, 36413, {1, 1, 7, 13, 31, 39, 125, 21, 173, 103, 1119, 3739, 6467, 2113, 4465, 26537, 129949}},
-{10010, 17, 36419, {1, 1, 5, 15, 21, 47, 35, 125, 199, 335, 421, 31, 185, 12769, 30659, 33427, 106981}},
-{10011, 17, 36425, {1, 3, 5, 13, 25, 35, 53, 253, 325, 921, 1705, 2735, 6437, 2287, 20479, 61107, 91453}},
-{10012, 17, 36426, {1, 3, 7, 13, 25, 63, 83, 183, 5, 401, 329, 525, 3141, 393, 30469, 16529, 9605}},
-{10013, 17, 36446, {1, 3, 3, 13, 19, 23, 15, 85, 323, 545, 149, 3645, 6269, 15595, 18453, 39, 128169}},
-{10014, 17, 36461, {1, 3, 7, 15, 17, 5, 61, 61, 91, 353, 1039, 2959, 4147, 13205, 12599, 53281, 39509}},
-{10015, 17, 36467, {1, 1, 3, 7, 21, 9, 97, 111, 249, 775, 845, 1789, 667, 489, 6689, 29217, 56527}},
-{10016, 17, 36474, {1, 3, 5, 7, 11, 5, 59, 219, 29, 803, 923, 3861, 7953, 8969, 1819, 43501, 20513}},
-{10017, 17, 36480, {1, 1, 5, 11, 7, 53, 63, 231, 193, 293, 1467, 1409, 6397, 13237, 15903, 19271, 66257}},
-{10018, 17, 36486, {1, 3, 1, 15, 23, 15, 37, 123, 189, 63, 1121, 751, 6711, 10095, 6493, 40709, 47641}},
-{10019, 17, 36489, {1, 3, 7, 3, 23, 59, 99, 183, 249, 479, 771, 1087, 7979, 409, 4819, 4337, 33345}},
-{10020, 17, 36495, {1, 1, 5, 1, 17, 7, 15, 167, 305, 411, 1429, 3127, 23, 9123, 7185, 44405, 114841}},
-{10021, 17, 36525, {1, 1, 5, 11, 3, 29, 29, 31, 399, 777, 251, 1841, 3607, 211, 23543, 29111, 54565}},
-{10022, 17, 36526, {1, 3, 3, 9, 27, 33, 79, 27, 469, 67, 1327, 183, 5783, 10039, 13165, 20443, 4913}},
-{10023, 17, 36533, {1, 3, 7, 15, 21, 23, 5, 227, 141, 1021, 69, 3347, 7221, 13837, 20921, 20525, 32567}},
-{10024, 17, 36534, {1, 1, 5, 5, 25, 53, 73, 111, 319, 311, 1597, 1809, 5343, 13963, 6613, 14471, 53871}},
-{10025, 17, 36540, {1, 3, 3, 1, 15, 57, 47, 205, 53, 471, 185, 273, 8077, 5031, 31195, 30859, 15979}},
-{10026, 17, 36555, {1, 1, 3, 5, 23, 15, 87, 211, 83, 265, 1629, 2979, 69, 12559, 30455, 36363, 61461}},
-{10027, 17, 36563, {1, 1, 7, 7, 1, 47, 5, 199, 95, 17, 57, 1887, 6847, 9501, 21361, 57763, 77069}},
-{10028, 17, 36565, {1, 1, 3, 5, 9, 15, 15, 149, 141, 605, 639, 2197, 7237, 5753, 9415, 4677, 129947}},
-{10029, 17, 36588, {1, 3, 7, 1, 7, 9, 29, 249, 275, 461, 1667, 4093, 5763, 3205, 24079, 11883, 86455}},
-{10030, 17, 36593, {1, 1, 3, 5, 15, 39, 117, 145, 153, 671, 1819, 111, 3607, 12279, 4927, 63759, 42905}},
-{10031, 17, 36596, {1, 1, 1, 5, 31, 5, 35, 183, 189, 839, 1811, 1877, 6545, 11373, 27947, 27183, 29857}},
-{10032, 17, 36606, {1, 3, 5, 7, 29, 47, 3, 183, 511, 145, 1953, 3419, 6385, 7745, 12823, 59783, 69399}},
-{10033, 17, 36614, {1, 3, 5, 9, 5, 39, 85, 145, 33, 899, 1009, 2035, 6145, 3855, 20583, 4329, 95231}},
-{10034, 17, 36626, {1, 1, 3, 3, 15, 61, 85, 181, 247, 705, 413, 1633, 7489, 1785, 30397, 42851, 80197}},
-{10035, 17, 36628, {1, 3, 3, 13, 23, 11, 3, 97, 307, 183, 113, 3881, 7455, 8327, 6749, 23977, 101629}},
-{10036, 17, 36641, {1, 1, 7, 13, 1, 23, 59, 219, 125, 789, 1401, 707, 6915, 6275, 25813, 46595, 54119}},
-{10037, 17, 36642, {1, 3, 7, 9, 5, 7, 37, 33, 165, 181, 833, 1993, 4541, 5799, 23323, 39825, 44575}},
-{10038, 17, 36651, {1, 3, 1, 13, 13, 43, 69, 219, 437, 521, 503, 2293, 3607, 6845, 22583, 291, 65645}},
-{10039, 17, 36653, {1, 1, 7, 9, 29, 13, 123, 67, 191, 933, 1875, 1223, 5525, 13797, 29771, 58191, 84469}},
-{10040, 17, 36673, {1, 1, 7, 7, 3, 57, 101, 69, 23, 239, 1023, 3289, 1541, 6245, 23379, 161, 61155}},
-{10041, 17, 36676, {1, 3, 7, 13, 25, 33, 49, 145, 487, 681, 451, 1719, 109, 16273, 20009, 3003, 115815}},
-{10042, 17, 36679, {1, 1, 5, 11, 11, 59, 41, 133, 303, 469, 1975, 847, 5291, 13947, 8759, 8533, 25099}},
-{10043, 17, 36694, {1, 1, 1, 1, 29, 31, 53, 11, 239, 57, 1627, 1247, 1577, 3269, 20751, 4627, 40499}},
-{10044, 17, 36698, {1, 3, 7, 15, 1, 1, 51, 39, 383, 203, 1841, 3867, 4975, 9937, 1863, 52611, 83189}},
-{10045, 17, 36704, {1, 3, 7, 7, 13, 59, 15, 217, 355, 945, 1317, 815, 2413, 10985, 30647, 37745, 126553}},
-{10046, 17, 36714, {1, 1, 3, 11, 7, 29, 101, 137, 97, 119, 927, 3269, 6977, 4253, 10741, 61907, 122815}},
-{10047, 17, 36721, {1, 3, 3, 1, 29, 5, 49, 137, 411, 349, 905, 2481, 4961, 4513, 29409, 19503, 77915}},
-{10048, 17, 36722, {1, 1, 7, 13, 29, 59, 93, 61, 393, 29, 257, 3601, 6281, 5105, 17339, 53827, 83137}},
-{10049, 17, 36727, {1, 1, 1, 13, 5, 23, 61, 7, 51, 161, 737, 1549, 6021, 3385, 5539, 21261, 69995}},
-{10050, 17, 36749, {1, 1, 1, 15, 31, 1, 21, 113, 481, 7, 175, 717, 1593, 5937, 12347, 51835, 66649}},
-{10051, 17, 36758, {1, 1, 3, 7, 9, 51, 9, 199, 39, 607, 1157, 3913, 7767, 14195, 28721, 27655, 34709}},
-{10052, 17, 36761, {1, 3, 5, 5, 1, 15, 49, 33, 441, 721, 1749, 1497, 2023, 8351, 12641, 11861, 78545}},
-{10053, 17, 36771, {1, 3, 1, 7, 7, 17, 103, 113, 243, 25, 889, 1419, 3163, 12401, 22459, 39037, 101719}},
-{10054, 17, 36788, {1, 1, 7, 11, 17, 45, 121, 215, 3, 409, 1871, 2149, 4249, 5071, 14277, 55869, 91233}},
-{10055, 17, 36797, {1, 1, 3, 7, 19, 31, 47, 241, 175, 749, 1709, 355, 6037, 10555, 24107, 64683, 42673}},
-{10056, 17, 36805, {1, 3, 7, 11, 5, 21, 105, 137, 307, 101, 417, 1903, 1027, 10257, 27767, 9755, 92105}},
-{10057, 17, 36830, {1, 1, 3, 13, 9, 59, 11, 63, 295, 923, 401, 1471, 3517, 7761, 28855, 11525, 72455}},
-{10058, 17, 36833, {1, 1, 7, 15, 31, 51, 77, 29, 323, 579, 1313, 3441, 2903, 1683, 20605, 8185, 29753}},
-{10059, 17, 36839, {1, 1, 5, 15, 11, 59, 119, 109, 233, 1001, 1527, 2709, 73, 5311, 18313, 27155, 85999}},
-{10060, 17, 36843, {1, 3, 1, 5, 9, 59, 105, 93, 213, 401, 839, 3225, 3263, 13501, 2413, 60367, 121281}},
-{10061, 17, 36860, {1, 1, 7, 3, 19, 25, 75, 27, 325, 435, 527, 1465, 3601, 5785, 6135, 32841, 60129}},
-{10062, 17, 36866, {1, 1, 3, 7, 31, 19, 37, 157, 189, 51, 869, 2963, 5269, 9151, 14845, 30441, 89685}},
-{10063, 17, 36871, {1, 3, 3, 9, 17, 51, 23, 177, 417, 255, 1739, 3085, 7811, 15177, 25433, 38487, 51021}},
-{10064, 17, 36875, {1, 1, 3, 7, 27, 1, 45, 235, 59, 491, 1327, 3967, 7585, 4313, 29669, 47193, 89427}},
-{10065, 17, 36877, {1, 1, 3, 9, 19, 5, 27, 63, 263, 593, 1599, 1311, 1029, 603, 25291, 51391, 98915}},
-{10066, 17, 36880, {1, 3, 3, 15, 11, 7, 97, 99, 263, 155, 437, 3849, 2665, 3371, 8179, 51883, 3601}},
-{10067, 17, 36892, {1, 1, 3, 15, 7, 35, 37, 149, 251, 619, 1423, 553, 4453, 16365, 22543, 6951, 34655}},
-{10068, 17, 36911, {1, 3, 3, 11, 15, 21, 95, 143, 31, 425, 179, 2383, 4799, 7655, 26945, 9273, 103469}},
-{10069, 17, 36914, {1, 3, 1, 9, 13, 49, 3, 117, 361, 459, 227, 2067, 4909, 13461, 22505, 10259, 59697}},
-{10070, 17, 36916, {1, 1, 7, 7, 7, 23, 67, 217, 313, 965, 1747, 995, 579, 6217, 8915, 49329, 851}},
-{10071, 17, 36923, {1, 1, 3, 1, 17, 19, 7, 99, 281, 207, 1685, 2401, 967, 9399, 28741, 28839, 6003}},
-{10072, 17, 36940, {1, 3, 3, 5, 31, 61, 105, 251, 499, 319, 1167, 2203, 1195, 2663, 11797, 12981, 125523}},
-{10073, 17, 36943, {1, 3, 1, 5, 23, 19, 99, 101, 85, 837, 501, 2737, 4051, 2413, 9275, 38995, 21633}},
-{10074, 17, 36948, {1, 3, 7, 13, 17, 17, 119, 75, 281, 527, 1477, 1515, 7765, 5573, 10143, 6219, 57817}},
-{10075, 17, 36957, {1, 1, 5, 11, 19, 35, 85, 171, 107, 905, 1395, 1199, 7345, 15719, 14021, 47425, 36081}},
-{10076, 17, 36958, {1, 1, 3, 9, 9, 63, 109, 15, 323, 73, 1541, 2227, 5197, 12617, 23379, 53415, 105291}},
-{10077, 17, 36967, {1, 3, 3, 5, 5, 41, 85, 99, 3, 895, 1383, 3627, 3897, 1893, 23673, 56501, 78411}},
-{10078, 17, 36974, {1, 1, 7, 1, 25, 27, 45, 185, 475, 577, 1619, 727, 1407, 2383, 9215, 55295, 27349}},
-{10079, 17, 36981, {1, 3, 7, 11, 3, 51, 53, 53, 399, 711, 1075, 511, 5369, 10777, 14419, 63217, 130181}},
-{10080, 17, 37001, {1, 1, 7, 13, 25, 19, 107, 71, 151, 73, 735, 3837, 5307, 10229, 10529, 9989, 111925}},
-{10081, 17, 37012, {1, 1, 1, 15, 19, 59, 65, 77, 465, 957, 1085, 1359, 3959, 15823, 6273, 12565, 126167}},
-{10082, 17, 37015, {1, 1, 5, 5, 31, 53, 23, 173, 407, 795, 41, 3275, 1953, 13673, 26625, 33477, 14149}},
-{10083, 17, 37019, {1, 1, 7, 7, 1, 11, 121, 139, 77, 321, 1939, 2597, 621, 9579, 11629, 13119, 30505}},
-{10084, 17, 37035, {1, 1, 1, 5, 3, 33, 45, 127, 169, 581, 1521, 1019, 6489, 1069, 2469, 40255, 66619}},
-{10085, 17, 37040, {1, 3, 7, 5, 29, 47, 7, 245, 459, 417, 1027, 857, 4905, 11255, 3267, 9491, 78013}},
-{10086, 17, 37063, {1, 3, 5, 9, 25, 49, 61, 215, 19, 731, 303, 1001, 6031, 3705, 7797, 31957, 119383}},
-{10087, 17, 37064, {1, 3, 5, 5, 1, 9, 37, 187, 235, 453, 963, 2833, 3501, 605, 2763, 41215, 93547}},
-{10088, 17, 37069, {1, 3, 1, 1, 21, 3, 41, 53, 425, 687, 1051, 2365, 7835, 3981, 5557, 61993, 127417}},
-{10089, 17, 37077, {1, 3, 3, 7, 13, 61, 41, 189, 261, 163, 1931, 1803, 2379, 16379, 25453, 17911, 123431}},
-{10090, 17, 37093, {1, 1, 7, 15, 23, 21, 95, 7, 27, 897, 721, 3917, 7971, 4643, 5223, 46583, 32453}},
-{10091, 17, 37097, {1, 1, 7, 7, 1, 25, 83, 109, 223, 573, 533, 449, 6477, 10719, 28705, 8283, 94963}},
-{10092, 17, 37106, {1, 1, 5, 13, 21, 45, 63, 31, 21, 223, 31, 1249, 425, 7199, 11539, 7731, 44333}},
-{10093, 17, 37115, {1, 1, 5, 15, 29, 5, 87, 215, 287, 567, 297, 451, 5867, 15511, 1005, 57469, 87257}},
-{10094, 17, 37118, {1, 3, 5, 11, 13, 51, 117, 139, 377, 1015, 1237, 2053, 7625, 1003, 22673, 64345, 16203}},
-{10095, 17, 37123, {1, 1, 3, 15, 19, 39, 73, 205, 185, 331, 869, 857, 5043, 7247, 25253, 5799, 64857}},
-{10096, 17, 37129, {1, 3, 7, 1, 25, 63, 125, 47, 161, 289, 373, 1603, 1663, 1123, 28907, 37855, 47935}},
-{10097, 17, 37130, {1, 1, 7, 15, 9, 17, 97, 63, 79, 123, 1357, 3055, 2323, 16083, 21861, 38743, 81291}},
-{10098, 17, 37135, {1, 1, 3, 15, 5, 23, 7, 159, 127, 511, 55, 2691, 6823, 16151, 8059, 43021, 18911}},
-{10099, 17, 37137, {1, 1, 3, 9, 27, 19, 41, 75, 375, 921, 1745, 35, 1189, 5857, 29869, 43827, 16899}},
-{10100, 17, 37138, {1, 1, 1, 5, 3, 21, 13, 235, 51, 529, 291, 2619, 5419, 12573, 10907, 8865, 54987}},
-{10101, 17, 37140, {1, 3, 1, 13, 7, 9, 85, 131, 159, 743, 1671, 3001, 4559, 12343, 27563, 49941, 68447}},
-{10102, 17, 37144, {1, 1, 7, 5, 17, 61, 99, 63, 199, 383, 485, 2569, 5329, 645, 18805, 20421, 101229}},
-{10103, 17, 37149, {1, 1, 1, 15, 3, 59, 41, 247, 213, 843, 2003, 125, 7755, 4203, 20277, 47195, 48249}},
-{10104, 17, 37156, {1, 1, 5, 15, 15, 17, 113, 101, 27, 811, 1791, 1777, 749, 14317, 17267, 54467, 118369}},
-{10105, 17, 37159, {1, 3, 3, 3, 19, 37, 23, 117, 275, 733, 1259, 567, 1769, 12071, 5413, 49411, 99259}},
-{10106, 17, 37163, {1, 3, 1, 11, 3, 27, 103, 113, 251, 731, 481, 2771, 3205, 14151, 19403, 30307, 114691}},
-{10107, 17, 37165, {1, 1, 5, 15, 19, 15, 103, 25, 357, 197, 1437, 3621, 4747, 773, 5769, 33465, 28307}},
-{10108, 17, 37183, {1, 1, 5, 15, 5, 17, 89, 87, 423, 611, 549, 2549, 1275, 14545, 2931, 3853, 24577}},
-{10109, 17, 37185, {1, 3, 5, 1, 15, 13, 29, 49, 279, 495, 697, 1015, 4899, 15977, 10765, 47979, 40237}},
-{10110, 17, 37195, {1, 3, 3, 9, 31, 51, 21, 5, 279, 947, 1871, 3075, 5433, 1631, 30075, 30517, 99609}},
-{10111, 17, 37198, {1, 1, 1, 15, 19, 63, 79, 81, 19, 629, 617, 1887, 4015, 15501, 10551, 56419, 108739}},
-{10112, 17, 37203, {1, 1, 3, 9, 31, 15, 45, 37, 43, 349, 1357, 189, 4551, 9363, 15683, 48445, 89279}},
-{10113, 17, 37212, {1, 1, 1, 1, 17, 19, 121, 119, 397, 947, 1797, 613, 1627, 9591, 15779, 62295, 118843}},
-{10114, 17, 37233, {1, 1, 1, 7, 25, 55, 71, 227, 507, 497, 1209, 2919, 5733, 15785, 21437, 40043, 2325}},
-{10115, 17, 37236, {1, 1, 1, 15, 11, 1, 59, 93, 69, 859, 67, 1831, 6345, 5643, 29515, 20337, 77281}},
-{10116, 17, 37240, {1, 3, 5, 9, 19, 53, 59, 63, 161, 853, 697, 1441, 3457, 951, 29659, 15337, 38443}},
-{10117, 17, 37256, {1, 3, 1, 9, 7, 21, 73, 81, 89, 291, 411, 3793, 4639, 2829, 6855, 38113, 32875}},
-{10118, 17, 37264, {1, 1, 7, 1, 15, 3, 79, 35, 363, 459, 907, 1157, 5165, 8021, 10135, 36367, 111991}},
-{10119, 17, 37267, {1, 3, 5, 13, 21, 23, 63, 155, 393, 869, 1553, 3345, 2711, 8249, 24907, 28111, 36667}},
-{10120, 17, 37273, {1, 1, 7, 11, 15, 25, 29, 93, 45, 637, 1473, 2053, 313, 8047, 23411, 8643, 2925}},
-{10121, 17, 37295, {1, 3, 7, 9, 11, 5, 73, 69, 311, 949, 2017, 259, 2861, 10547, 12017, 34125, 74101}},
-{10122, 17, 37315, {1, 3, 1, 13, 19, 61, 115, 59, 447, 787, 1621, 2221, 7841, 5329, 18137, 13857, 51889}},
-{10123, 17, 37330, {1, 3, 7, 13, 1, 23, 117, 49, 449, 541, 7, 3269, 1725, 6677, 15979, 4319, 40919}},
-{10124, 17, 37336, {1, 3, 5, 5, 17, 29, 35, 123, 3, 481, 305, 1589, 4319, 5183, 31907, 53019, 49375}},
-{10125, 17, 37339, {1, 3, 1, 7, 11, 59, 79, 89, 479, 821, 763, 3597, 7457, 13775, 11213, 22777, 80379}},
-{10126, 17, 37342, {1, 1, 3, 7, 13, 17, 65, 155, 335, 671, 331, 895, 7459, 1719, 10675, 60109, 63143}},
-{10127, 17, 37357, {1, 3, 5, 1, 29, 33, 105, 249, 61, 469, 1629, 3777, 4393, 14457, 11701, 6065, 2635}},
-{10128, 17, 37365, {1, 3, 7, 3, 13, 13, 21, 15, 363, 63, 1263, 1479, 1459, 6577, 7481, 30393, 19831}},
-{10129, 17, 37372, {1, 1, 3, 7, 29, 25, 71, 247, 501, 815, 1697, 2457, 4975, 3821, 25759, 24901, 120603}},
-{10130, 17, 37381, {1, 1, 1, 5, 19, 3, 59, 163, 367, 779, 47, 905, 897, 3293, 13951, 25497, 99151}},
-{10131, 17, 37399, {1, 3, 1, 5, 11, 47, 21, 171, 123, 215, 1797, 3741, 4921, 7213, 4847, 3239, 114839}},
-{10132, 17, 37416, {1, 3, 3, 5, 23, 63, 57, 31, 409, 431, 1337, 3301, 4695, 7401, 9383, 12639, 34347}},
-{10133, 17, 37429, {1, 3, 3, 5, 27, 57, 29, 147, 111, 1015, 815, 1509, 3967, 7255, 15109, 26001, 90775}},
-{10134, 17, 37436, {1, 1, 7, 13, 31, 45, 21, 99, 377, 399, 255, 459, 6043, 11055, 5675, 3333, 32813}},
-{10135, 17, 37442, {1, 3, 1, 7, 1, 55, 121, 77, 429, 433, 297, 3181, 3029, 6777, 22795, 61515, 58553}},
-{10136, 17, 37451, {1, 3, 5, 9, 1, 19, 121, 1, 499, 589, 1597, 2219, 1029, 4223, 31613, 45685, 53517}},
-{10137, 17, 37453, {1, 3, 1, 9, 29, 39, 83, 193, 43, 41, 467, 1711, 2761, 10635, 15503, 38043, 120615}},
-{10138, 17, 37475, {1, 1, 7, 13, 27, 61, 1, 181, 163, 613, 221, 63, 6147, 8215, 15093, 2417, 71489}},
-{10139, 17, 37482, {1, 1, 7, 15, 31, 63, 47, 139, 427, 847, 53, 1275, 1019, 9455, 12537, 22467, 129947}},
-{10140, 17, 37489, {1, 1, 5, 3, 7, 1, 67, 189, 501, 319, 37, 2849, 2535, 10917, 11115, 48083, 67255}},
-{10141, 17, 37490, {1, 1, 3, 13, 7, 31, 69, 137, 19, 73, 1553, 3945, 2381, 8761, 3977, 24291, 128189}},
-{10142, 17, 37523, {1, 3, 5, 11, 1, 59, 43, 229, 301, 771, 559, 195, 1675, 12605, 22211, 2915, 90351}},
-{10143, 17, 37525, {1, 3, 3, 9, 13, 27, 97, 33, 273, 229, 1537, 1179, 6985, 11679, 17889, 44673, 126641}},
-{10144, 17, 37530, {1, 1, 7, 3, 31, 29, 41, 123, 491, 639, 269, 45, 2155, 14103, 6725, 50781, 42785}},
-{10145, 17, 37535, {1, 3, 5, 9, 9, 11, 89, 249, 475, 701, 1029, 985, 8167, 439, 31897, 24529, 45759}},
-{10146, 17, 37539, {1, 1, 5, 11, 9, 39, 127, 179, 15, 135, 1437, 3331, 5553, 939, 15319, 64937, 110783}},
-{10147, 17, 37548, {1, 3, 1, 5, 7, 61, 1, 219, 111, 801, 85, 3427, 2533, 12861, 5395, 28969, 48091}},
-{10148, 17, 37559, {1, 1, 1, 9, 23, 57, 77, 41, 61, 635, 457, 231, 8121, 5349, 27021, 64807, 87563}},
-{10149, 17, 37560, {1, 3, 5, 7, 31, 31, 101, 155, 255, 199, 1973, 903, 7681, 15379, 12845, 47943, 60663}},
-{10150, 17, 37566, {1, 1, 5, 7, 1, 7, 71, 121, 323, 669, 193, 1209, 267, 9, 21223, 22037, 121567}},
-{10151, 17, 37597, {1, 3, 1, 5, 17, 29, 97, 189, 219, 813, 187, 1763, 5817, 13185, 467, 40159, 18037}},
-{10152, 17, 37601, {1, 1, 7, 9, 7, 59, 3, 189, 379, 843, 631, 3945, 2909, 4191, 30343, 11223, 105629}},
-{10153, 17, 37602, {1, 3, 1, 3, 15, 17, 23, 73, 439, 699, 657, 451, 6139, 15869, 4101, 32327, 55485}},
-{10154, 17, 37604, {1, 3, 3, 5, 21, 37, 87, 157, 205, 493, 705, 1539, 2193, 13539, 2797, 49063, 55595}},
-{10155, 17, 37616, {1, 1, 5, 11, 11, 41, 5, 131, 445, 781, 1153, 1371, 6763, 3101, 32449, 16065, 86579}},
-{10156, 17, 37622, {1, 3, 5, 1, 23, 51, 97, 87, 161, 261, 269, 2035, 2139, 3049, 32217, 25189, 93571}},
-{10157, 17, 37658, {1, 3, 1, 11, 23, 1, 111, 45, 19, 19, 1767, 3571, 6027, 3593, 17453, 53821, 28121}},
-{10158, 17, 37660, {1, 3, 3, 5, 17, 5, 17, 247, 5, 73, 29, 443, 7713, 15803, 22311, 56755, 100119}},
-{10159, 17, 37667, {1, 3, 1, 13, 7, 1, 41, 139, 317, 977, 1529, 1217, 529, 3231, 21491, 28461, 96699}},
-{10160, 17, 37684, {1, 3, 1, 13, 11, 41, 103, 99, 81, 849, 231, 1729, 761, 711, 11499, 25581, 59433}},
-{10161, 17, 37693, {1, 1, 5, 5, 13, 33, 79, 175, 89, 29, 295, 2867, 1197, 6137, 32063, 23471, 21721}},
-{10162, 17, 37694, {1, 1, 5, 15, 17, 29, 123, 249, 273, 437, 443, 2601, 3957, 11955, 261, 54863, 85727}},
-{10163, 17, 37696, {1, 1, 5, 13, 3, 31, 57, 205, 3, 903, 905, 3851, 757, 13761, 28615, 48185, 33227}},
-{10164, 17, 37706, {1, 3, 7, 1, 1, 1, 107, 15, 307, 405, 45, 297, 4365, 1569, 9263, 13685, 36027}},
-{10165, 17, 37711, {1, 3, 1, 9, 17, 61, 113, 121, 249, 743, 191, 2523, 6621, 5395, 23797, 57975, 51675}},
-{10166, 17, 37730, {1, 3, 5, 3, 27, 21, 49, 113, 59, 989, 501, 2651, 3827, 5121, 29667, 32903, 84199}},
-{10167, 17, 37735, {1, 1, 7, 7, 19, 43, 11, 191, 143, 93, 1167, 2521, 2569, 12187, 28575, 13073, 113545}},
-{10168, 17, 37742, {1, 1, 7, 3, 27, 39, 11, 85, 61, 979, 49, 2191, 2607, 13967, 28123, 48903, 16327}},
-{10169, 17, 37744, {1, 1, 5, 3, 17, 17, 1, 149, 189, 1017, 705, 3119, 6441, 1595, 30533, 18795, 34265}},
-{10170, 17, 37759, {1, 1, 3, 11, 31, 11, 125, 109, 39, 41, 191, 2615, 1377, 16089, 8793, 31425, 90507}},
-{10171, 17, 37777, {1, 1, 1, 1, 23, 15, 21, 245, 337, 649, 585, 2893, 927, 883, 15119, 2595, 127963}},
-{10172, 17, 37783, {1, 3, 5, 3, 13, 17, 123, 167, 471, 5, 1671, 2787, 5081, 12903, 4257, 19213, 2503}},
-{10173, 17, 37784, {1, 1, 5, 7, 21, 57, 75, 171, 509, 591, 85, 407, 1747, 6375, 19641, 55683, 111289}},
-{10174, 17, 37793, {1, 1, 7, 7, 3, 31, 121, 111, 19, 361, 1033, 4033, 2359, 13451, 15095, 61817, 69683}},
-{10175, 17, 37800, {1, 1, 5, 9, 21, 33, 83, 179, 387, 69, 1085, 2147, 2751, 10899, 16971, 40623, 110891}},
-{10176, 17, 37818, {1, 1, 7, 9, 11, 45, 81, 71, 73, 551, 145, 159, 7519, 3459, 5197, 48913, 59045}},
-{10177, 17, 37823, {1, 3, 1, 3, 7, 35, 17, 249, 207, 767, 1189, 1451, 4351, 3673, 28807, 671, 69271}},
-{10178, 17, 37825, {1, 3, 1, 15, 21, 27, 81, 243, 55, 191, 1497, 3205, 1601, 705, 14891, 14403, 130729}},
-{10179, 17, 37828, {1, 3, 1, 7, 17, 43, 41, 123, 507, 201, 1873, 3547, 5681, 1819, 4251, 39661, 57923}},
-{10180, 17, 37832, {1, 3, 1, 9, 3, 59, 57, 235, 445, 479, 961, 1937, 2229, 2511, 15235, 59707, 72261}},
-{10181, 17, 37849, {1, 1, 5, 13, 9, 63, 67, 217, 63, 259, 175, 2469, 3075, 12365, 7727, 42215, 12635}},
-{10182, 17, 37856, {1, 1, 3, 13, 11, 9, 125, 131, 17, 399, 675, 767, 7349, 10433, 21615, 46823, 3955}},
-{10183, 17, 37861, {1, 1, 3, 15, 19, 53, 73, 171, 125, 531, 1093, 1449, 2931, 10897, 12263, 9799, 98251}},
-{10184, 17, 37862, {1, 1, 5, 5, 11, 27, 33, 9, 503, 545, 339, 1099, 1973, 13261, 26871, 14569, 22755}},
-{10185, 17, 37886, {1, 3, 7, 1, 19, 5, 79, 133, 247, 1021, 1431, 3707, 4603, 3285, 5469, 46963, 98203}},
-{10186, 17, 37893, {1, 3, 5, 7, 15, 11, 87, 169, 495, 763, 1295, 2533, 4213, 8671, 21683, 12521, 90071}},
-{10187, 17, 37915, {1, 1, 3, 1, 17, 55, 7, 165, 313, 659, 49, 377, 6675, 15255, 9881, 11751, 87789}},
-{10188, 17, 37922, {1, 3, 1, 15, 3, 49, 27, 109, 145, 1011, 1939, 3201, 6141, 7229, 20741, 59285, 129365}},
-{10189, 17, 37936, {1, 1, 5, 5, 5, 51, 117, 17, 363, 795, 1343, 2637, 6209, 1045, 22515, 10687, 48487}},
-{10190, 17, 37939, {1, 1, 5, 15, 1, 37, 91, 241, 245, 703, 505, 3369, 6163, 10265, 12497, 46301, 109523}},
-{10191, 17, 37945, {1, 1, 7, 11, 3, 37, 67, 35, 229, 823, 193, 913, 3331, 4475, 9271, 11859, 52709}},
-{10192, 17, 37956, {1, 1, 3, 3, 7, 25, 61, 159, 81, 1011, 1491, 1439, 1031, 765, 9839, 61891, 20969}},
-{10193, 17, 37960, {1, 3, 3, 7, 25, 39, 73, 59, 101, 101, 225, 1105, 5943, 5223, 12585, 16411, 62699}},
-{10194, 17, 37971, {1, 1, 7, 5, 25, 19, 27, 113, 465, 319, 2035, 2127, 1319, 11793, 26821, 44805, 28217}},
-{10195, 17, 37980, {1, 3, 5, 11, 7, 9, 81, 107, 67, 31, 1503, 3303, 4451, 11417, 32681, 26861, 54845}},
-{10196, 17, 38002, {1, 3, 1, 1, 3, 51, 93, 235, 93, 247, 2027, 1517, 6797, 1703, 10233, 45313, 60771}},
-{10197, 17, 38007, {1, 3, 3, 15, 25, 11, 83, 77, 413, 189, 119, 597, 2199, 12347, 7935, 40191, 125569}},
-{10198, 17, 38018, {1, 3, 7, 9, 11, 3, 77, 31, 89, 163, 1993, 3017, 3973, 10943, 22247, 45565, 7261}},
-{10199, 17, 38020, {1, 3, 7, 7, 15, 13, 7, 155, 373, 893, 607, 3521, 7455, 13809, 6145, 31743, 86329}},
-{10200, 17, 38038, {1, 1, 1, 15, 25, 41, 111, 65, 11, 627, 59, 2725, 995, 3761, 25361, 45189, 48355}},
-{10201, 17, 38041, {1, 1, 7, 5, 29, 43, 91, 139, 323, 503, 679, 4079, 403, 1899, 1425, 26989, 117057}},
-{10202, 17, 38044, {1, 3, 5, 13, 1, 17, 19, 61, 205, 833, 345, 1031, 7995, 999, 27469, 15943, 88011}},
-{10203, 17, 38048, {1, 3, 1, 7, 23, 49, 123, 9, 11, 761, 1163, 669, 3837, 15225, 23393, 19513, 9457}},
-{10204, 17, 38051, {1, 1, 5, 9, 9, 33, 29, 123, 277, 433, 1799, 1583, 3133, 13461, 26443, 15807, 80173}},
-{10205, 17, 38054, {1, 3, 7, 3, 31, 29, 77, 105, 297, 617, 491, 647, 6541, 5033, 31841, 48405, 126985}},
-{10206, 17, 38065, {1, 1, 5, 5, 31, 39, 17, 25, 3, 279, 89, 3985, 3333, 5681, 3701, 36319, 12585}},
-{10207, 17, 38066, {1, 1, 7, 13, 13, 19, 93, 129, 51, 875, 1083, 1739, 5193, 6217, 10033, 51839, 66071}},
-{10208, 17, 38077, {1, 1, 7, 9, 15, 23, 93, 121, 507, 115, 707, 3181, 1521, 9609, 4577, 54389, 19167}},
-{10209, 17, 38090, {1, 3, 3, 7, 17, 51, 19, 29, 387, 711, 1105, 1627, 4421, 15183, 14149, 26485, 106425}},
-{10210, 17, 38109, {1, 3, 3, 15, 25, 59, 11, 45, 259, 1019, 1997, 3373, 5083, 5701, 30217, 44845, 67559}},
-{10211, 17, 38119, {1, 3, 3, 9, 17, 47, 5, 103, 477, 785, 235, 1523, 1505, 8811, 15255, 53493, 4383}},
-{10212, 17, 38120, {1, 3, 7, 3, 7, 37, 73, 247, 397, 409, 1065, 525, 5665, 8533, 30627, 19035, 22937}},
-{10213, 17, 38123, {1, 3, 3, 15, 15, 47, 123, 215, 413, 249, 55, 2563, 8033, 8743, 18659, 7947, 56057}},
-{10214, 17, 38146, {1, 1, 7, 3, 11, 61, 103, 109, 313, 293, 149, 999, 901, 13387, 15351, 52973, 68385}},
-{10215, 17, 38155, {1, 1, 1, 5, 31, 13, 57, 43, 263, 141, 335, 2777, 3435, 4231, 20623, 2597, 33481}},
-{10216, 17, 38160, {1, 1, 7, 13, 21, 53, 101, 75, 237, 275, 1903, 3501, 8023, 3651, 19609, 44417, 60287}},
-{10217, 17, 38181, {1, 1, 1, 1, 13, 43, 83, 255, 355, 567, 1781, 2943, 1061, 2701, 24861, 58381, 60255}},
-{10218, 17, 38188, {1, 1, 3, 9, 25, 5, 81, 85, 445, 857, 517, 3687, 2641, 6699, 19273, 4481, 8715}},
-{10219, 17, 38199, {1, 1, 3, 7, 17, 39, 33, 31, 29, 269, 379, 3149, 4731, 10387, 7941, 49199, 18423}},
-{10220, 17, 38203, {1, 1, 7, 15, 19, 37, 105, 157, 185, 1023, 1865, 53, 6765, 3, 22897, 17019, 109521}},
-{10221, 17, 38225, {1, 3, 7, 5, 5, 7, 117, 211, 19, 149, 1091, 3721, 201, 4455, 18965, 51401, 67225}},
-{10222, 17, 38226, {1, 3, 5, 11, 1, 55, 101, 41, 469, 271, 1251, 949, 861, 11903, 14773, 25675, 114161}},
-{10223, 17, 38231, {1, 1, 7, 7, 23, 13, 103, 185, 137, 575, 797, 1195, 5301, 13307, 12043, 26003, 31719}},
-{10224, 17, 38244, {1, 1, 5, 7, 11, 51, 17, 71, 321, 559, 1461, 3571, 1033, 15575, 7097, 14703, 52359}},
-{10225, 17, 38248, {1, 1, 1, 5, 21, 9, 123, 211, 233, 81, 111, 1433, 7825, 11771, 30743, 23993, 48717}},
-{10226, 17, 38259, {1, 3, 5, 15, 7, 3, 109, 33, 99, 135, 393, 3463, 7271, 14387, 30723, 19079, 83073}},
-{10227, 17, 38268, {1, 3, 3, 15, 3, 51, 77, 219, 409, 11, 67, 3787, 5155, 9259, 7185, 21611, 32577}},
-{10228, 17, 38271, {1, 3, 7, 1, 5, 49, 125, 85, 151, 301, 887, 1765, 5, 12849, 11775, 11319, 29547}},
-{10229, 17, 38272, {1, 1, 7, 11, 17, 15, 105, 29, 327, 637, 1493, 3361, 1823, 14709, 18355, 741, 57807}},
-{10230, 17, 38278, {1, 1, 7, 7, 3, 27, 15, 113, 227, 617, 1543, 1719, 8065, 13627, 23525, 20511, 64759}},
-{10231, 17, 38292, {1, 1, 3, 3, 21, 47, 89, 177, 381, 711, 1367, 2405, 887, 2351, 22957, 49679, 5963}},
-{10232, 17, 38296, {1, 3, 7, 9, 7, 1, 39, 71, 9, 275, 875, 1385, 6215, 10419, 25921, 63427, 18031}},
-{10233, 17, 38318, {1, 1, 7, 5, 23, 57, 27, 7, 445, 111, 953, 37, 2769, 1967, 8165, 35417, 36471}},
-{10234, 17, 38326, {1, 3, 3, 11, 23, 17, 119, 113, 275, 625, 1957, 2795, 3815, 7937, 11049, 31939, 128053}},
-{10235, 17, 38338, {1, 3, 3, 5, 7, 35, 45, 41, 251, 491, 1953, 3201, 751, 5705, 595, 27003, 77917}},
-{10236, 17, 38347, {1, 3, 5, 3, 25, 17, 55, 137, 299, 541, 289, 2225, 4667, 3569, 13687, 36193, 75705}},
-{10237, 17, 38373, {1, 1, 7, 15, 21, 9, 27, 157, 469, 441, 193, 2097, 4863, 2147, 31197, 24283, 102039}},
-{10238, 17, 38378, {1, 1, 1, 11, 17, 39, 73, 37, 91, 121, 1283, 367, 1875, 14365, 28349, 60993, 10791}},
-{10239, 17, 38380, {1, 3, 5, 9, 13, 63, 89, 53, 459, 347, 343, 2321, 5237, 2497, 279, 63833, 10709}},
-{10240, 17, 38388, {1, 1, 1, 15, 11, 23, 41, 79, 45, 567, 1217, 1669, 1679, 2561, 16191, 49041, 4081}},
-{10241, 17, 38392, {1, 3, 1, 5, 3, 9, 103, 245, 47, 561, 229, 2945, 6563, 797, 21571, 25769, 12995}},
-{10242, 17, 38397, {1, 3, 5, 7, 5, 47, 99, 55, 49, 951, 765, 2095, 8021, 4389, 20501, 26047, 119967}},
-{10243, 17, 38398, {1, 1, 5, 3, 15, 47, 81, 121, 379, 527, 419, 1093, 367, 10939, 17181, 13905, 49859}},
-{10244, 17, 38401, {1, 3, 3, 5, 7, 59, 53, 255, 131, 685, 1677, 3757, 3601, 89, 6225, 32705, 28287}},
-{10245, 17, 38404, {1, 3, 7, 1, 7, 55, 85, 47, 425, 793, 605, 2313, 791, 4247, 9693, 10633, 82915}},
-{10246, 17, 38422, {1, 3, 5, 13, 13, 49, 127, 213, 27, 657, 419, 55, 6289, 295, 4211, 8899, 120237}},
-{10247, 17, 38432, {1, 1, 7, 11, 11, 7, 75, 35, 315, 125, 517, 3677, 2323, 6897, 11535, 36789, 20179}},
-{10248, 17, 38469, {1, 1, 5, 9, 11, 3, 77, 43, 323, 647, 383, 485, 3937, 9081, 27745, 59149, 103433}},
-{10249, 17, 38482, {1, 3, 3, 13, 3, 47, 91, 81, 115, 625, 2003, 3601, 531, 113, 20719, 47391, 111039}},
-{10250, 17, 38493, {1, 1, 3, 13, 5, 49, 123, 189, 109, 325, 497, 923, 3861, 14029, 22651, 19857, 104801}},
-{10251, 17, 38507, {1, 1, 5, 3, 29, 23, 25, 23, 501, 371, 1983, 1303, 2261, 11865, 13281, 2587, 75741}},
-{10252, 17, 38518, {1, 3, 5, 13, 27, 61, 45, 11, 157, 615, 897, 1529, 2213, 757, 30105, 2011, 27267}},
-{10253, 17, 38521, {1, 3, 5, 13, 29, 31, 95, 159, 449, 307, 1575, 1897, 2301, 14023, 6921, 30543, 31843}},
-{10254, 17, 38527, {1, 3, 3, 5, 1, 1, 79, 147, 437, 623, 1161, 3407, 3073, 15425, 4329, 19651, 90597}},
-{10255, 17, 38533, {1, 1, 1, 11, 17, 7, 43, 171, 447, 841, 573, 3775, 5517, 3629, 18241, 31907, 51423}},
-{10256, 17, 38534, {1, 1, 3, 7, 15, 53, 111, 203, 171, 963, 1983, 2017, 6067, 12281, 3417, 7431, 33803}},
-{10257, 17, 38552, {1, 3, 1, 1, 31, 49, 125, 65, 7, 579, 1709, 1815, 2643, 11537, 30093, 11813, 65157}},
-{10258, 17, 38561, {1, 3, 7, 15, 1, 3, 61, 21, 163, 809, 1263, 2577, 7811, 12611, 6921, 18529, 25709}},
-{10259, 17, 38576, {1, 1, 3, 5, 17, 43, 13, 81, 29, 905, 1975, 589, 5875, 15683, 29447, 46453, 127911}},
-{10260, 17, 38581, {1, 1, 5, 3, 19, 29, 11, 67, 375, 771, 755, 3939, 1465, 3275, 1119, 24695, 105105}},
-{10261, 17, 38585, {1, 1, 3, 11, 23, 37, 33, 135, 329, 733, 245, 2353, 2547, 7823, 16265, 5975, 37877}},
-{10262, 17, 38594, {1, 3, 7, 13, 15, 9, 47, 181, 239, 723, 1219, 409, 1685, 5493, 14189, 18107, 26231}},
-{10263, 17, 38606, {1, 1, 5, 1, 9, 1, 65, 125, 439, 591, 1499, 3797, 5879, 4231, 18655, 9643, 42265}},
-{10264, 17, 38613, {1, 1, 7, 7, 11, 51, 111, 47, 169, 39, 45, 2211, 6729, 10987, 22367, 27257, 112711}},
-{10265, 17, 38617, {1, 3, 5, 3, 19, 61, 89, 185, 23, 793, 1457, 1743, 3743, 15063, 14053, 50201, 109175}},
-{10266, 17, 38634, {1, 1, 5, 13, 31, 51, 69, 135, 427, 527, 1673, 2393, 5829, 683, 1509, 56617, 105735}},
-{10267, 17, 38644, {1, 1, 1, 15, 31, 51, 3, 105, 125, 593, 1589, 3217, 7449, 525, 30599, 11689, 14781}},
-{10268, 17, 38651, {1, 1, 1, 11, 9, 37, 113, 45, 487, 961, 87, 1461, 3521, 8645, 19771, 43817, 43277}},
-{10269, 17, 38661, {1, 1, 7, 3, 7, 11, 45, 97, 11, 593, 319, 2597, 37, 4157, 6669, 29929, 17213}},
-{10270, 17, 38665, {1, 3, 7, 3, 29, 21, 101, 93, 289, 975, 1937, 3423, 757, 7075, 12575, 26801, 90989}},
-{10271, 17, 38668, {1, 1, 7, 15, 25, 49, 49, 149, 503, 365, 1359, 2155, 7977, 14955, 18439, 44269, 88995}},
-{10272, 17, 38674, {1, 3, 7, 13, 25, 27, 15, 67, 157, 873, 339, 2143, 1405, 12209, 30939, 36109, 107699}},
-{10273, 17, 38689, {1, 3, 5, 5, 21, 33, 121, 95, 61, 159, 1423, 2899, 3811, 263, 9139, 54481, 107375}},
-{10274, 17, 38695, {1, 1, 7, 7, 13, 49, 83, 53, 267, 131, 673, 3945, 5255, 2009, 21017, 41749, 44817}},
-{10275, 17, 38696, {1, 3, 1, 13, 25, 57, 125, 5, 323, 653, 221, 2013, 7225, 8719, 28049, 41953, 14725}},
-{10276, 17, 38707, {1, 3, 7, 7, 5, 13, 35, 161, 221, 951, 769, 717, 267, 2233, 23387, 47411, 95739}},
-{10277, 17, 38710, {1, 3, 7, 11, 23, 47, 37, 67, 501, 159, 763, 4045, 5125, 5667, 9895, 33041, 101171}},
-{10278, 17, 38716, {1, 1, 7, 1, 31, 31, 111, 183, 33, 895, 1819, 3593, 1285, 10145, 3679, 36615, 82863}},
-{10279, 17, 38733, {1, 3, 5, 7, 21, 59, 55, 163, 139, 855, 1903, 3229, 3745, 10289, 28831, 46895, 12647}},
-{10280, 17, 38736, {1, 3, 7, 9, 25, 31, 113, 177, 459, 201, 565, 2089, 725, 9273, 26249, 5987, 49573}},
-{10281, 17, 38742, {1, 1, 7, 15, 3, 37, 49, 145, 121, 803, 1197, 2797, 21, 833, 2277, 28189, 93171}},
-{10282, 17, 38751, {1, 1, 7, 7, 13, 31, 93, 153, 345, 363, 1825, 1481, 3347, 13277, 26119, 63153, 118231}},
-{10283, 17, 38752, {1, 3, 1, 11, 31, 9, 33, 95, 433, 595, 1131, 465, 1797, 15453, 32527, 40789, 37799}},
-{10284, 17, 38775, {1, 1, 5, 11, 31, 29, 83, 33, 243, 633, 1325, 3843, 7717, 851, 29789, 48827, 89209}},
-{10285, 17, 38779, {1, 1, 3, 7, 25, 31, 127, 219, 281, 51, 1843, 3363, 5985, 1697, 3083, 18967, 117421}},
-{10286, 17, 38792, {1, 3, 7, 9, 1, 19, 125, 199, 41, 117, 903, 1131, 7731, 14431, 24753, 62841, 50251}},
-{10287, 17, 38798, {1, 3, 5, 5, 11, 37, 19, 249, 97, 59, 1849, 1151, 2171, 1217, 31277, 26547, 86601}},
-{10288, 17, 38819, {1, 3, 3, 7, 29, 35, 21, 7, 93, 971, 1155, 1847, 89, 6759, 29611, 40793, 88327}},
-{10289, 17, 38822, {1, 3, 5, 5, 29, 23, 91, 71, 479, 943, 1839, 3699, 2491, 9603, 15061, 43221, 20435}},
-{10290, 17, 38839, {1, 3, 3, 7, 29, 11, 15, 83, 21, 585, 501, 161, 4797, 11243, 14879, 12519, 19069}},
-{10291, 17, 38851, {1, 1, 5, 15, 13, 37, 9, 215, 433, 925, 987, 3253, 8027, 7013, 20801, 12891, 36497}},
-{10292, 17, 38854, {1, 3, 7, 1, 15, 31, 95, 85, 355, 1013, 1963, 2943, 1925, 13691, 15237, 28943, 63873}},
-{10293, 17, 38863, {1, 3, 3, 1, 17, 21, 99, 201, 465, 819, 665, 901, 2671, 2457, 29603, 35275, 28339}},
-{10294, 17, 38865, {1, 1, 1, 9, 5, 23, 111, 107, 27, 433, 1341, 91, 6879, 1933, 25433, 37435, 99061}},
-{10295, 17, 38887, {1, 3, 5, 13, 11, 55, 27, 151, 397, 591, 89, 1221, 5581, 2701, 15033, 41879, 71415}},
-{10296, 17, 38896, {1, 3, 3, 5, 17, 35, 15, 119, 487, 903, 875, 3391, 7731, 12181, 27823, 32561, 59133}},
-{10297, 17, 38901, {1, 1, 5, 7, 15, 33, 67, 53, 307, 947, 857, 2713, 803, 765, 4175, 15513, 23985}},
-{10298, 17, 38912, {1, 3, 1, 15, 23, 11, 15, 101, 467, 429, 153, 3205, 5627, 7555, 22515, 12721, 7905}},
-{10299, 17, 38918, {1, 1, 3, 7, 19, 61, 55, 187, 413, 49, 1031, 3415, 3903, 6933, 20017, 50429, 116407}},
-{10300, 17, 38929, {1, 3, 1, 13, 13, 15, 33, 1, 403, 441, 1969, 775, 2209, 15061, 15657, 28819, 62705}},
-{10301, 17, 38941, {1, 1, 5, 13, 13, 47, 67, 97, 87, 677, 1639, 3281, 1395, 8499, 18449, 49935, 25775}},
-{10302, 17, 38948, {1, 3, 3, 13, 7, 13, 77, 45, 405, 881, 293, 2263, 6517, 15415, 25809, 5681, 31327}},
-{10303, 17, 38965, {1, 3, 7, 5, 5, 51, 63, 171, 401, 671, 1631, 1735, 7361, 8741, 31933, 44761, 12209}},
-{10304, 17, 38969, {1, 1, 7, 3, 13, 3, 39, 223, 105, 781, 241, 2895, 5165, 12135, 5683, 63009, 58399}},
-{10305, 17, 38977, {1, 1, 5, 11, 29, 11, 37, 1, 445, 157, 219, 2269, 3025, 5721, 24539, 41879, 128445}},
-{10306, 17, 38987, {1, 3, 7, 15, 23, 21, 125, 105, 141, 101, 1981, 3765, 5349, 13781, 10055, 7069, 77721}},
-{10307, 17, 38992, {1, 1, 7, 9, 3, 37, 111, 95, 33, 53, 1021, 1629, 6945, 4657, 19977, 36715, 101401}},
-{10308, 17, 38995, {1, 3, 3, 1, 9, 5, 65, 77, 459, 471, 1045, 2351, 2787, 13001, 16211, 22585, 116205}},
-{10309, 17, 39001, {1, 1, 7, 9, 25, 41, 21, 187, 471, 997, 583, 2243, 6537, 11837, 21089, 51051, 98517}},
-{10310, 17, 39004, {1, 1, 7, 5, 13, 15, 81, 39, 223, 935, 951, 5, 4315, 11789, 18365, 49647, 92461}},
-{10311, 17, 39011, {1, 3, 3, 5, 11, 15, 97, 245, 43, 819, 1415, 3287, 2051, 15879, 21727, 54467, 53875}},
-{10312, 17, 39018, {1, 3, 1, 11, 7, 47, 125, 155, 301, 469, 805, 3789, 6967, 12117, 30369, 55183, 12671}},
-{10313, 17, 39025, {1, 1, 3, 13, 17, 25, 45, 199, 69, 1015, 581, 3891, 7743, 9273, 7639, 59055, 93923}},
-{10314, 17, 39031, {1, 1, 5, 11, 9, 47, 39, 251, 489, 47, 83, 2147, 943, 1959, 21361, 5325, 106079}},
-{10315, 17, 39032, {1, 3, 5, 13, 27, 59, 35, 1, 155, 367, 165, 2665, 3021, 1127, 28585, 45347, 66763}},
-{10316, 17, 39044, {1, 3, 1, 5, 31, 31, 15, 125, 485, 581, 1987, 2293, 4573, 11431, 20773, 58661, 79869}},
-{10317, 17, 39056, {1, 3, 5, 15, 31, 11, 109, 229, 11, 831, 1545, 919, 6125, 9337, 4169, 58041, 67577}},
-{10318, 17, 39065, {1, 1, 1, 3, 1, 43, 13, 89, 89, 863, 1607, 1897, 4831, 5239, 24503, 51853, 126983}},
-{10319, 17, 39066, {1, 1, 5, 11, 11, 37, 11, 253, 495, 83, 941, 3665, 5187, 13679, 11811, 29563, 80571}},
-{10320, 17, 39084, {1, 3, 7, 15, 3, 45, 45, 157, 477, 321, 1401, 1133, 271, 12455, 31543, 18223, 116701}},
-{10321, 17, 39095, {1, 1, 5, 3, 7, 5, 17, 127, 195, 583, 715, 3975, 6865, 7617, 6749, 15687, 42375}},
-{10322, 17, 39099, {1, 1, 1, 7, 5, 7, 21, 163, 303, 45, 1435, 1345, 2489, 15333, 18459, 60837, 104339}},
-{10323, 17, 39101, {1, 3, 1, 1, 7, 23, 39, 93, 347, 947, 345, 1713, 6383, 15411, 10849, 32559, 126431}},
-{10324, 17, 39102, {1, 3, 1, 5, 19, 41, 119, 213, 3, 991, 1745, 3989, 155, 7761, 28179, 59805, 106759}},
-{10325, 17, 39104, {1, 1, 7, 5, 25, 11, 105, 89, 505, 711, 1213, 2831, 8087, 8855, 31171, 49749, 921}},
-{10326, 17, 39109, {1, 1, 5, 5, 23, 61, 49, 101, 209, 805, 123, 17, 805, 9033, 25753, 33261, 33753}},
-{10327, 17, 39114, {1, 1, 3, 5, 5, 17, 93, 223, 179, 307, 869, 1851, 4313, 477, 12925, 21365, 103999}},
-{10328, 17, 39121, {1, 1, 7, 13, 21, 23, 105, 53, 393, 939, 291, 2407, 4815, 4961, 30305, 8613, 62599}},
-{10329, 17, 39122, {1, 1, 1, 11, 9, 55, 55, 135, 411, 225, 205, 3357, 4553, 10139, 17649, 51209, 94037}},
-{10330, 17, 39127, {1, 3, 5, 15, 17, 17, 119, 15, 121, 581, 169, 2495, 3673, 7173, 13099, 7683, 53397}},
-{10331, 17, 39150, {1, 3, 1, 11, 29, 29, 119, 255, 447, 85, 845, 1015, 2793, 2471, 12639, 32155, 99193}},
-{10332, 17, 39172, {1, 3, 3, 3, 9, 33, 77, 251, 425, 1007, 1003, 2697, 4989, 7799, 26581, 15963, 50443}},
-{10333, 17, 39181, {1, 3, 1, 5, 13, 47, 13, 203, 473, 529, 147, 2061, 343, 4029, 14615, 51355, 27863}},
-{10334, 17, 39184, {1, 1, 3, 15, 19, 63, 39, 25, 241, 487, 461, 3021, 3545, 4537, 8991, 17689, 77131}},
-{10335, 17, 39193, {1, 3, 5, 5, 7, 1, 61, 89, 495, 943, 1061, 405, 449, 12785, 25151, 24497, 65709}},
-{10336, 17, 39199, {1, 1, 5, 3, 7, 43, 51, 55, 193, 615, 37, 1377, 2541, 3861, 29447, 32269, 106335}},
-{10337, 17, 39200, {1, 1, 5, 11, 21, 55, 103, 43, 421, 673, 175, 979, 5175, 1301, 8617, 55875, 111095}},
-{10338, 17, 39206, {1, 3, 5, 13, 29, 31, 33, 241, 129, 473, 201, 2015, 447, 99, 23781, 33517, 107851}},
-{10339, 17, 39209, {1, 3, 5, 3, 13, 27, 125, 205, 287, 957, 1609, 2907, 5481, 14239, 19719, 22459, 75365}},
-{10340, 17, 39235, {1, 3, 3, 5, 27, 23, 53, 39, 329, 381, 745, 517, 7853, 5333, 2773, 29119, 7049}},
-{10341, 17, 39238, {1, 3, 5, 15, 29, 11, 89, 3, 503, 755, 485, 2669, 6737, 16241, 7345, 50991, 107291}},
-{10342, 17, 39242, {1, 1, 7, 3, 17, 45, 11, 3, 157, 715, 577, 1309, 3323, 9401, 10573, 55135, 100067}},
-{10343, 17, 39244, {1, 1, 5, 9, 19, 21, 49, 103, 349, 503, 1447, 675, 4273, 7673, 27507, 57697, 80875}},
-{10344, 17, 39280, {1, 1, 5, 1, 9, 53, 19, 99, 225, 915, 431, 781, 3291, 4383, 26505, 50339, 99799}},
-{10345, 17, 39290, {1, 3, 1, 5, 7, 37, 87, 201, 481, 991, 1553, 1867, 7893, 13147, 18647, 10373, 51951}},
-{10346, 17, 39292, {1, 1, 3, 13, 17, 37, 19, 199, 253, 901, 759, 3545, 3565, 10461, 11867, 57605, 75555}},
-{10347, 17, 39296, {1, 1, 1, 5, 15, 23, 115, 69, 363, 673, 201, 2451, 3197, 10059, 1667, 47145, 89}},
-{10348, 17, 39305, {1, 1, 7, 13, 19, 31, 63, 35, 93, 939, 1057, 3221, 951, 3575, 9659, 7005, 2087}},
-{10349, 17, 39308, {1, 1, 7, 15, 15, 21, 79, 7, 23, 595, 1123, 1909, 6863, 7383, 28067, 30113, 107497}},
-{10350, 17, 39311, {1, 3, 5, 7, 11, 47, 41, 177, 163, 855, 1853, 3837, 6995, 9727, 27285, 62667, 77531}},
-{10351, 17, 39326, {1, 3, 7, 3, 3, 29, 99, 163, 95, 893, 1049, 2001, 2961, 601, 4613, 59745, 61203}},
-{10352, 17, 39329, {1, 3, 5, 1, 27, 5, 5, 47, 119, 631, 1171, 3467, 2115, 8581, 24863, 64193, 52093}},
-{10353, 17, 39330, {1, 1, 1, 5, 9, 51, 49, 251, 97, 177, 311, 993, 1103, 7875, 25273, 51587, 9081}},
-{10354, 17, 39336, {1, 3, 7, 5, 31, 21, 43, 137, 143, 779, 691, 2331, 5073, 5409, 13335, 999, 127765}},
-{10355, 17, 39339, {1, 1, 7, 1, 31, 33, 27, 193, 175, 755, 1559, 659, 5663, 10491, 29209, 50979, 116683}},
-{10356, 17, 39353, {1, 3, 1, 7, 23, 49, 1, 39, 117, 45, 1767, 3503, 4901, 5699, 23613, 44195, 17867}},
-{10357, 17, 39359, {1, 3, 7, 13, 3, 5, 105, 89, 343, 627, 1117, 3419, 2081, 5747, 7919, 44329, 125133}},
-{10358, 17, 39374, {1, 3, 1, 9, 13, 33, 53, 203, 17, 927, 127, 2195, 415, 11301, 15115, 54467, 128777}},
-{10359, 17, 39391, {1, 3, 7, 1, 9, 41, 15, 89, 403, 333, 57, 1159, 1325, 2335, 10609, 20485, 110317}},
-{10360, 17, 39392, {1, 3, 3, 5, 3, 61, 25, 155, 477, 907, 359, 359, 5119, 8157, 29945, 38955, 106485}},
-{10361, 17, 39402, {1, 1, 7, 5, 19, 47, 91, 89, 367, 703, 761, 431, 6813, 2983, 29739, 52453, 125935}},
-{10362, 17, 39409, {1, 1, 1, 7, 7, 61, 127, 239, 277, 649, 1111, 2319, 1737, 5071, 13469, 52119, 48899}},
-{10363, 17, 39410, {1, 3, 5, 15, 7, 17, 21, 209, 265, 895, 719, 263, 6871, 5835, 28483, 49859, 67619}},
-{10364, 17, 39415, {1, 3, 3, 15, 3, 7, 113, 109, 333, 545, 597, 1193, 7593, 3961, 25169, 64673, 47839}},
-{10365, 17, 39419, {1, 1, 1, 3, 15, 45, 55, 41, 317, 719, 1587, 2953, 2441, 1127, 9183, 21637, 69075}},
-{10366, 17, 39431, {1, 3, 1, 9, 25, 57, 59, 29, 89, 833, 379, 1085, 763, 14747, 30797, 24089, 83367}},
-{10367, 17, 39432, {1, 1, 5, 13, 29, 3, 117, 239, 453, 595, 243, 3103, 6047, 631, 22739, 41669, 11683}},
-{10368, 17, 39438, {1, 1, 3, 1, 9, 53, 81, 21, 67, 735, 827, 3519, 7991, 16249, 4183, 61295, 4531}},
-{10369, 17, 39443, {1, 3, 5, 3, 1, 57, 47, 99, 91, 71, 1421, 2949, 5951, 15439, 25239, 26453, 50199}},
-{10370, 17, 39445, {1, 1, 3, 15, 21, 3, 93, 21, 41, 809, 855, 727, 7797, 6957, 15835, 27175, 60617}},
-{10371, 17, 39449, {1, 1, 1, 13, 1, 3, 83, 135, 197, 171, 1459, 2841, 5021, 6961, 30675, 38295, 39555}},
-{10372, 17, 39461, {1, 1, 7, 5, 7, 49, 83, 83, 117, 73, 639, 2717, 651, 3253, 31635, 14427, 116509}},
-{10373, 17, 39462, {1, 3, 1, 3, 23, 63, 15, 23, 433, 539, 903, 2655, 1787, 12901, 12013, 41315, 128217}},
-{10374, 17, 39485, {1, 3, 1, 7, 5, 19, 3, 137, 493, 681, 775, 3725, 4855, 10817, 25277, 3631, 60779}},
-{10375, 17, 39508, {1, 3, 3, 5, 1, 7, 67, 39, 309, 77, 1679, 2853, 3803, 2065, 7461, 1555, 88219}},
-{10376, 17, 39515, {1, 1, 3, 5, 3, 47, 17, 193, 429, 789, 1525, 969, 7905, 6523, 10149, 64689, 40037}},
-{10377, 17, 39522, {1, 3, 5, 7, 21, 17, 65, 61, 255, 517, 1765, 2603, 4929, 11073, 7871, 29313, 84739}},
-{10378, 17, 39533, {1, 1, 5, 7, 13, 55, 111, 63, 499, 9, 1715, 957, 6951, 15839, 13531, 45483, 17923}},
-{10379, 17, 39541, {1, 1, 1, 1, 27, 7, 13, 135, 27, 259, 1735, 3847, 7931, 14777, 15249, 62367, 45773}},
-{10380, 17, 39542, {1, 1, 5, 3, 5, 7, 99, 171, 491, 1007, 195, 2223, 2657, 13557, 6549, 47125, 25117}},
-{10381, 17, 39557, {1, 1, 1, 9, 13, 21, 59, 205, 205, 951, 1707, 3387, 2901, 5463, 13403, 1917, 90591}},
-{10382, 17, 39570, {1, 3, 3, 5, 21, 37, 71, 91, 297, 885, 1415, 355, 2877, 9261, 6485, 45855, 90081}},
-{10383, 17, 39575, {1, 1, 5, 9, 23, 51, 107, 75, 93, 1015, 439, 3589, 3307, 337, 17247, 42285, 85417}},
-{10384, 17, 39576, {1, 1, 7, 15, 29, 33, 51, 23, 269, 35, 1241, 1137, 729, 14531, 14603, 47547, 17151}},
-{10385, 17, 39591, {1, 3, 3, 1, 25, 21, 51, 229, 55, 561, 653, 3289, 7629, 15445, 21115, 35941, 113669}},
-{10386, 17, 39597, {1, 1, 5, 15, 1, 33, 119, 171, 75, 621, 2025, 3235, 1895, 8279, 13205, 61085, 105401}},
-{10387, 17, 39603, {1, 3, 1, 7, 25, 33, 73, 25, 1, 531, 603, 77, 4939, 5957, 28065, 59467, 66659}},
-{10388, 17, 39610, {1, 1, 7, 3, 17, 61, 103, 47, 289, 39, 917, 2515, 6607, 1129, 23361, 46321, 81929}},
-{10389, 17, 39612, {1, 1, 7, 5, 29, 53, 5, 191, 151, 19, 895, 1215, 5401, 9861, 24751, 15481, 34179}},
-{10390, 17, 39617, {1, 3, 7, 9, 5, 3, 29, 205, 173, 547, 727, 947, 5619, 4181, 30621, 5553, 37587}},
-{10391, 17, 39620, {1, 1, 3, 9, 13, 59, 95, 145, 287, 849, 1483, 3375, 3531, 6585, 29565, 4243, 88333}},
-{10392, 17, 39624, {1, 1, 7, 11, 21, 23, 59, 223, 71, 743, 443, 697, 7789, 10371, 28565, 45127, 37967}},
-{10393, 17, 39627, {1, 3, 5, 11, 15, 25, 79, 71, 21, 817, 751, 189, 1769, 3835, 21465, 17991, 102043}},
-{10394, 17, 39635, {1, 1, 7, 11, 3, 19, 25, 5, 261, 181, 49, 261, 7715, 2195, 19771, 43463, 36533}},
-{10395, 17, 39641, {1, 1, 7, 13, 21, 21, 15, 235, 191, 197, 1305, 1351, 4511, 625, 6613, 37053, 59491}},
-{10396, 17, 39666, {1, 1, 1, 13, 15, 13, 93, 239, 251, 1009, 527, 1347, 4173, 14753, 27389, 20397, 13101}},
-{10397, 17, 39668, {1, 1, 3, 1, 15, 11, 127, 141, 277, 775, 1419, 2353, 6929, 2265, 7253, 19807, 74853}},
-{10398, 17, 39686, {1, 3, 3, 15, 15, 49, 9, 183, 407, 377, 675, 871, 347, 3417, 4409, 7805, 40507}},
-{10399, 17, 39692, {1, 3, 5, 3, 23, 11, 81, 53, 343, 681, 1777, 3411, 757, 10875, 3581, 56105, 79907}},
-{10400, 17, 39700, {1, 3, 5, 1, 25, 9, 109, 55, 283, 311, 1607, 2479, 5675, 8819, 10853, 38719, 44471}},
-{10401, 17, 39709, {1, 1, 7, 7, 9, 53, 33, 195, 503, 167, 993, 3203, 3885, 1921, 1039, 25785, 47411}},
-{10402, 17, 39726, {1, 3, 3, 3, 31, 3, 11, 85, 475, 743, 1825, 2649, 2373, 12177, 21481, 35579, 85803}},
-{10403, 17, 39728, {1, 3, 7, 3, 23, 45, 45, 207, 369, 773, 1579, 783, 2491, 7441, 21203, 57091, 107413}},
-{10404, 17, 39737, {1, 1, 1, 5, 19, 7, 97, 213, 431, 533, 637, 1767, 4945, 4693, 977, 64781, 111811}},
-{10405, 17, 39738, {1, 3, 7, 7, 1, 55, 101, 251, 153, 95, 1043, 3219, 3499, 6297, 11571, 9131, 61899}},
-{10406, 17, 39755, {1, 3, 5, 5, 25, 53, 121, 255, 69, 661, 799, 3559, 2029, 11701, 14151, 37897, 18333}},
-{10407, 17, 39757, {1, 1, 1, 9, 21, 19, 97, 21, 321, 957, 1115, 251, 5131, 8465, 24215, 34423, 12747}},
-{10408, 17, 39758, {1, 3, 5, 7, 17, 19, 99, 135, 429, 625, 1401, 1025, 4193, 2911, 7349, 34135, 9341}},
-{10409, 17, 39765, {1, 3, 5, 1, 5, 63, 97, 121, 307, 547, 1967, 641, 487, 4627, 30899, 62049, 94343}},
-{10410, 17, 39766, {1, 3, 5, 13, 1, 1, 109, 23, 267, 843, 271, 2277, 855, 4245, 2177, 33633, 113835}},
-{10411, 17, 39769, {1, 1, 3, 7, 3, 27, 91, 79, 27, 855, 2025, 443, 4797, 9005, 27533, 20497, 100431}},
-{10412, 17, 39779, {1, 3, 3, 5, 23, 7, 73, 35, 395, 649, 881, 2923, 4065, 853, 10829, 19461, 82383}},
-{10413, 17, 39785, {1, 3, 1, 5, 25, 13, 85, 93, 369, 259, 393, 3233, 799, 12409, 26631, 64291, 110133}},
-{10414, 17, 39794, {1, 3, 5, 5, 31, 35, 25, 239, 455, 893, 573, 1449, 3359, 12077, 17149, 12921, 66931}},
-{10415, 17, 39796, {1, 1, 7, 3, 25, 39, 67, 87, 215, 325, 627, 3609, 4417, 10021, 12047, 64593, 116525}},
-{10416, 17, 39809, {1, 1, 5, 5, 23, 51, 125, 247, 83, 419, 655, 635, 7053, 4907, 12887, 18083, 49481}},
-{10417, 17, 39815, {1, 1, 7, 11, 5, 25, 65, 139, 235, 331, 1885, 1851, 1061, 13265, 14371, 23067, 56757}},
-{10418, 17, 39829, {1, 1, 7, 9, 11, 15, 29, 255, 509, 869, 561, 2201, 487, 2989, 14943, 65373, 35789}},
-{10419, 17, 39834, {1, 1, 1, 3, 3, 33, 23, 121, 129, 351, 1481, 65, 321, 15927, 23849, 2813, 98547}},
-{10420, 17, 39839, {1, 1, 1, 3, 23, 55, 121, 35, 339, 87, 1147, 401, 1477, 10617, 15943, 20535, 89321}},
-{10421, 17, 39850, {1, 3, 5, 15, 25, 59, 111, 185, 305, 47, 523, 2801, 5485, 625, 30191, 58153, 9019}},
-{10422, 17, 39857, {1, 1, 7, 13, 15, 51, 105, 55, 77, 419, 1011, 1117, 2705, 15093, 15629, 51429, 58487}},
-{10423, 17, 39881, {1, 3, 7, 5, 15, 27, 19, 7, 401, 295, 1841, 1167, 2133, 1967, 6941, 13571, 29467}},
-{10424, 17, 39905, {1, 1, 5, 15, 25, 43, 23, 253, 173, 927, 1299, 2779, 5489, 16135, 1503, 51097, 105751}},
-{10425, 17, 39912, {1, 3, 3, 5, 9, 13, 5, 13, 411, 639, 1323, 1495, 2539, 15087, 21489, 49653, 76229}},
-{10426, 17, 39938, {1, 1, 1, 11, 7, 51, 47, 99, 247, 541, 1355, 2373, 4121, 13621, 7715, 16763, 127985}},
-{10427, 17, 39940, {1, 1, 3, 9, 7, 1, 85, 45, 269, 769, 581, 2229, 7143, 5203, 22483, 18511, 30997}},
-{10428, 17, 39944, {1, 3, 5, 7, 21, 41, 97, 225, 109, 195, 1197, 3417, 7613, 13225, 29157, 18969, 82045}},
-{10429, 17, 39955, {1, 3, 3, 3, 17, 41, 13, 77, 129, 679, 1659, 1299, 4809, 8537, 19081, 1281, 70793}},
-{10430, 17, 39961, {1, 1, 5, 5, 5, 49, 5, 15, 313, 941, 775, 259, 6579, 7745, 20531, 51669, 35257}},
-{10431, 17, 39977, {1, 1, 5, 5, 17, 35, 13, 235, 169, 699, 1365, 3907, 4231, 10965, 7737, 6735, 4253}},
-{10432, 17, 39980, {1, 1, 5, 3, 29, 3, 1, 197, 133, 935, 571, 3977, 2467, 2029, 12803, 64559, 6427}},
-{10433, 17, 39986, {1, 3, 5, 5, 27, 5, 69, 57, 439, 925, 1695, 827, 4685, 10971, 3011, 56821, 92187}},
-{10434, 17, 39988, {1, 1, 1, 3, 9, 45, 77, 179, 173, 1023, 907, 1999, 3913, 6973, 26987, 30237, 62987}},
-{10435, 17, 39991, {1, 3, 7, 3, 5, 21, 17, 97, 433, 277, 1515, 2923, 8025, 14119, 11243, 3983, 33943}},
-{10436, 17, 39998, {1, 1, 5, 7, 15, 13, 119, 169, 21, 927, 439, 361, 2655, 2237, 19775, 4157, 84245}},
-{10437, 17, 40003, {1, 3, 5, 5, 31, 41, 117, 159, 421, 505, 1617, 3855, 7835, 8105, 29525, 56735, 82335}},
-{10438, 17, 40005, {1, 1, 5, 5, 1, 33, 51, 3, 79, 933, 389, 493, 5969, 12493, 26723, 61159, 116951}},
-{10439, 17, 40023, {1, 3, 7, 13, 17, 23, 75, 13, 355, 111, 675, 3191, 3931, 5651, 17495, 4595, 49869}},
-{10440, 17, 40024, {1, 1, 7, 7, 15, 21, 35, 125, 89, 903, 697, 3493, 4043, 6631, 4793, 45655, 86969}},
-{10441, 17, 40045, {1, 3, 1, 15, 13, 43, 113, 213, 451, 473, 191, 2913, 6391, 1321, 29615, 24791, 26979}},
-{10442, 17, 40046, {1, 3, 3, 13, 17, 25, 9, 163, 163, 161, 1647, 3949, 1343, 12881, 10931, 31365, 70013}},
-{10443, 17, 40058, {1, 3, 7, 3, 3, 19, 1, 121, 387, 543, 1655, 1797, 6727, 2951, 21925, 21595, 73207}},
-{10444, 17, 40088, {1, 1, 5, 9, 7, 19, 91, 9, 83, 893, 1393, 163, 2219, 7763, 32395, 29569, 98645}},
-{10445, 17, 40091, {1, 1, 5, 7, 13, 63, 91, 115, 247, 387, 87, 3239, 7561, 297, 32615, 48817, 41761}},
-{10446, 17, 40098, {1, 3, 5, 3, 21, 23, 27, 141, 257, 377, 1745, 443, 897, 9033, 1715, 9225, 110181}},
-{10447, 17, 40109, {1, 1, 7, 9, 23, 49, 125, 131, 225, 253, 139, 2057, 3273, 4049, 6861, 4463, 11659}},
-{10448, 17, 40112, {1, 1, 5, 11, 5, 41, 97, 213, 133, 481, 2009, 2039, 1533, 10765, 22427, 23297, 80661}},
-{10449, 17, 40124, {1, 1, 5, 15, 9, 11, 77, 129, 421, 219, 1623, 703, 1611, 13377, 9859, 42869, 101943}},
-{10450, 17, 40130, {1, 3, 3, 3, 17, 63, 55, 29, 317, 973, 1159, 11, 1733, 14551, 25911, 39151, 45861}},
-{10451, 17, 40153, {1, 3, 7, 11, 29, 63, 107, 193, 263, 799, 1171, 543, 553, 12591, 21965, 8165, 64347}},
-{10452, 17, 40166, {1, 1, 7, 15, 23, 49, 65, 65, 401, 897, 681, 1113, 6737, 9157, 1557, 55891, 129175}},
-{10453, 17, 40175, {1, 3, 3, 1, 15, 23, 107, 123, 313, 633, 1009, 2615, 1155, 11701, 21945, 7939, 28111}},
-{10454, 17, 40183, {1, 3, 1, 11, 15, 11, 47, 137, 299, 393, 877, 1989, 5903, 6505, 9599, 4129, 23073}},
-{10455, 17, 40184, {1, 1, 7, 15, 9, 49, 67, 15, 79, 125, 505, 17, 8071, 12957, 13855, 23611, 66465}},
-{10456, 17, 40207, {1, 1, 5, 13, 31, 49, 1, 161, 121, 145, 711, 1347, 5297, 11309, 9871, 43075, 95541}},
-{10457, 17, 40215, {1, 3, 3, 13, 19, 7, 55, 199, 469, 471, 1269, 3779, 6251, 3513, 1775, 19501, 94055}},
-{10458, 17, 40225, {1, 3, 3, 13, 9, 41, 109, 211, 197, 227, 1211, 3327, 1247, 12253, 4493, 31507, 38677}},
-{10459, 17, 40235, {1, 1, 7, 3, 11, 45, 11, 103, 325, 849, 1817, 3971, 1059, 9047, 27237, 32211, 121165}},
-{10460, 17, 40240, {1, 3, 3, 3, 13, 43, 7, 35, 293, 3, 679, 1441, 5189, 7585, 32009, 6151, 89803}},
-{10461, 17, 40255, {1, 1, 7, 9, 29, 41, 127, 255, 363, 913, 2027, 3891, 5187, 10233, 8871, 48085, 125609}},
-{10462, 17, 40263, {1, 3, 1, 5, 21, 23, 59, 145, 171, 775, 535, 3803, 6981, 15901, 20255, 63199, 92905}},
-{10463, 17, 40270, {1, 3, 5, 9, 7, 63, 53, 7, 145, 547, 1753, 3351, 1273, 8175, 24103, 42133, 87459}},
-{10464, 17, 40277, {1, 3, 7, 7, 25, 33, 5, 217, 469, 473, 1573, 2525, 7345, 5261, 7023, 50893, 124129}},
-{10465, 17, 40282, {1, 3, 5, 13, 5, 51, 23, 61, 429, 775, 519, 2671, 1979, 9005, 21617, 33611, 120487}},
-{10466, 17, 40297, {1, 3, 3, 15, 23, 1, 73, 187, 47, 369, 943, 99, 2529, 5569, 13649, 51481, 128949}},
-{10467, 17, 40306, {1, 3, 1, 5, 25, 55, 35, 191, 327, 845, 1353, 261, 6297, 6067, 22241, 32381, 17749}},
-{10468, 17, 40315, {1, 1, 5, 15, 31, 5, 29, 129, 15, 47, 739, 755, 7595, 14743, 14705, 34347, 11805}},
-{10469, 17, 40333, {1, 3, 1, 3, 15, 49, 119, 47, 185, 63, 2003, 2847, 5393, 855, 7699, 29521, 67011}},
-{10470, 17, 40334, {1, 3, 7, 15, 11, 41, 37, 149, 173, 1015, 29, 1805, 1269, 16199, 32337, 11023, 60065}},
-{10471, 17, 40336, {1, 1, 1, 7, 31, 19, 65, 81, 255, 875, 1379, 2347, 1873, 14427, 29523, 38413, 65583}},
-{10472, 17, 40342, {1, 1, 1, 15, 13, 59, 3, 219, 127, 479, 1029, 3385, 563, 11825, 10081, 17423, 26431}},
-{10473, 17, 40345, {1, 1, 1, 1, 25, 27, 79, 87, 489, 281, 457, 3527, 5117, 4705, 21167, 46211, 90383}},
-{10474, 17, 40348, {1, 3, 7, 13, 7, 5, 67, 111, 53, 439, 1483, 3639, 7781, 9471, 10957, 60711, 64957}},
-{10475, 17, 40355, {1, 3, 7, 9, 7, 7, 41, 137, 159, 245, 551, 4007, 1277, 4743, 4863, 48689, 123289}},
-{10476, 17, 40372, {1, 3, 7, 9, 15, 49, 55, 77, 41, 475, 1563, 3569, 5993, 301, 14831, 44095, 22641}},
-{10477, 17, 40381, {1, 1, 1, 1, 15, 33, 39, 135, 81, 533, 869, 305, 1125, 6399, 14321, 37217, 121081}},
-{10478, 17, 40390, {1, 1, 7, 15, 21, 59, 43, 7, 225, 1, 115, 1531, 2931, 2593, 15935, 61973, 106899}},
-{10479, 17, 40407, {1, 1, 1, 1, 13, 13, 99, 191, 437, 367, 641, 1933, 5807, 11677, 13557, 46475, 34875}},
-{10480, 17, 40435, {1, 3, 7, 9, 21, 7, 119, 209, 31, 919, 901, 1229, 5823, 11439, 18151, 18991, 114743}},
-{10481, 17, 40437, {1, 3, 3, 3, 19, 37, 109, 53, 411, 617, 1841, 2769, 1271, 5719, 22359, 1199, 72405}},
-{10482, 17, 40441, {1, 1, 1, 5, 29, 3, 51, 59, 141, 897, 1907, 3799, 1463, 5661, 181, 50565, 95085}},
-{10483, 17, 40444, {1, 1, 1, 7, 1, 35, 77, 225, 341, 587, 137, 35, 2177, 15177, 12869, 35013, 39471}},
-{10484, 17, 40458, {1, 1, 3, 13, 15, 63, 45, 33, 337, 1, 1133, 263, 4985, 11591, 1085, 31197, 67897}},
-{10485, 17, 40460, {1, 1, 5, 13, 23, 11, 123, 21, 185, 639, 145, 3865, 2999, 6261, 23247, 23055, 32755}},
-{10486, 17, 40481, {1, 1, 5, 9, 19, 21, 47, 133, 281, 431, 1661, 3719, 3637, 973, 9727, 52627, 60035}},
-{10487, 17, 40484, {1, 1, 3, 5, 3, 19, 19, 89, 63, 549, 551, 3357, 5665, 4781, 22437, 1149, 10825}},
-{10488, 17, 40487, {1, 3, 5, 15, 3, 25, 81, 193, 11, 711, 1481, 1767, 1159, 4967, 16915, 3387, 26245}},
-{10489, 17, 40493, {1, 1, 1, 3, 29, 39, 23, 131, 473, 107, 765, 2249, 6087, 9145, 20751, 21085, 42989}},
-{10490, 17, 40494, {1, 3, 1, 9, 7, 39, 13, 199, 475, 333, 269, 1041, 5927, 14039, 19081, 9045, 119645}},
-{10491, 17, 40501, {1, 1, 5, 13, 11, 61, 99, 71, 151, 175, 1327, 3397, 5063, 10683, 7895, 62255, 85749}},
-{10492, 17, 40502, {1, 3, 7, 9, 1, 57, 21, 217, 423, 467, 1435, 2887, 1567, 8819, 19961, 36507, 110309}},
-{10493, 17, 40525, {1, 3, 3, 11, 11, 35, 77, 127, 153, 357, 865, 1943, 1947, 10995, 13617, 44347, 26851}},
-{10494, 17, 40550, {1, 3, 1, 11, 9, 43, 31, 81, 123, 813, 995, 169, 6593, 13621, 32195, 51125, 53509}},
-{10495, 17, 40553, {1, 1, 5, 5, 27, 29, 77, 35, 93, 545, 377, 2345, 6475, 15729, 15103, 49591, 101121}},
-{10496, 17, 40559, {1, 1, 5, 13, 1, 17, 97, 187, 129, 173, 641, 2937, 3277, 15087, 28111, 46905, 112367}},
-{10497, 17, 40562, {1, 3, 7, 7, 1, 27, 75, 43, 305, 431, 571, 1327, 7419, 3093, 2691, 23417, 11975}},
-{10498, 17, 40573, {1, 1, 5, 15, 17, 3, 91, 57, 417, 87, 1891, 1973, 5765, 5521, 21931, 60011, 20883}},
-{10499, 17, 40574, {1, 3, 1, 3, 27, 13, 105, 153, 495, 371, 453, 1295, 5675, 6377, 8971, 40505, 41149}},
-{10500, 17, 40578, {1, 1, 1, 15, 1, 17, 105, 177, 41, 455, 611, 3585, 2307, 2603, 20985, 5581, 14033}},
-{10501, 17, 40583, {1, 3, 3, 9, 7, 41, 33, 145, 307, 293, 1321, 2151, 3265, 14845, 15687, 38715, 8041}},
-{10502, 17, 40584, {1, 3, 3, 3, 5, 47, 127, 253, 129, 337, 1467, 5, 2743, 1921, 26979, 11737, 41479}},
-{10503, 17, 40587, {1, 1, 1, 5, 15, 35, 37, 9, 5, 405, 1041, 1903, 3655, 14315, 9441, 20577, 50715}},
-{10504, 17, 40597, {1, 1, 5, 15, 7, 5, 53, 61, 409, 353, 87, 1805, 4523, 11417, 24105, 21451, 56387}},
-{10505, 17, 40620, {1, 3, 3, 5, 5, 9, 25, 249, 511, 795, 559, 2695, 3071, 3971, 29421, 46593, 96563}},
-{10506, 17, 40623, {1, 1, 3, 1, 3, 39, 61, 85, 399, 105, 1253, 3787, 3065, 10553, 8195, 5637, 129579}},
-{10507, 17, 40631, {1, 3, 3, 7, 23, 23, 23, 197, 263, 687, 943, 1977, 5767, 15373, 17995, 24509, 81293}},
-{10508, 17, 40643, {1, 3, 1, 11, 15, 37, 15, 67, 207, 985, 895, 509, 3435, 11563, 2055, 19253, 42649}},
-{10509, 17, 40660, {1, 1, 7, 3, 1, 51, 59, 133, 241, 569, 1575, 3633, 2243, 11939, 5501, 11249, 86013}},
-{10510, 17, 40667, {1, 1, 7, 13, 25, 59, 97, 191, 385, 179, 1195, 1537, 1837, 11953, 14231, 37025, 49803}},
-{10511, 17, 40676, {1, 3, 5, 5, 13, 49, 19, 171, 503, 433, 1633, 553, 2759, 4379, 18313, 62437, 37453}},
-{10512, 17, 40693, {1, 3, 3, 15, 29, 49, 107, 239, 21, 913, 1095, 989, 4749, 10657, 27169, 15913, 1573}},
-{10513, 17, 40697, {1, 1, 1, 1, 3, 3, 53, 241, 287, 149, 557, 2665, 2027, 449, 29231, 23025, 102521}},
-{10514, 17, 40708, {1, 3, 5, 7, 23, 21, 9, 1, 11, 837, 1337, 2815, 7883, 16053, 10031, 43405, 5037}},
-{10515, 17, 40718, {1, 3, 7, 1, 23, 53, 113, 125, 337, 491, 1125, 3083, 4941, 951, 15805, 1571, 79779}},
-{10516, 17, 40726, {1, 3, 7, 13, 1, 3, 95, 105, 431, 723, 1771, 3773, 177, 2045, 24719, 57727, 79005}},
-{10517, 17, 40735, {1, 3, 1, 1, 7, 17, 107, 171, 213, 437, 409, 2015, 7543, 12693, 23597, 44477, 72543}},
-{10518, 17, 40739, {1, 3, 5, 9, 7, 21, 27, 167, 473, 901, 1245, 3737, 3485, 14593, 7619, 18753, 14209}},
-{10519, 17, 40748, {1, 1, 1, 3, 25, 37, 51, 21, 363, 73, 711, 3749, 5147, 8495, 30151, 14275, 128217}},
-{10520, 17, 40760, {1, 3, 1, 13, 17, 35, 69, 15, 293, 331, 301, 691, 7315, 6495, 315, 62909, 105047}},
-{10521, 17, 40763, {1, 3, 5, 3, 25, 23, 105, 111, 213, 887, 1701, 2085, 5931, 9217, 4009, 2321, 103631}},
-{10522, 17, 40773, {1, 1, 7, 15, 17, 57, 59, 249, 267, 941, 777, 2509, 6587, 12033, 24969, 31563, 129049}},
-{10523, 17, 40774, {1, 1, 1, 5, 31, 23, 31, 217, 509, 973, 659, 673, 7759, 3865, 21221, 4319, 117411}},
-{10524, 17, 40786, {1, 1, 3, 7, 13, 13, 103, 179, 107, 233, 753, 3121, 835, 13595, 9271, 31421, 45275}},
-{10525, 17, 40791, {1, 3, 5, 13, 23, 61, 125, 189, 283, 83, 1087, 755, 3697, 14845, 27901, 16389, 82993}},
-{10526, 17, 40798, {1, 3, 1, 3, 1, 55, 25, 139, 435, 681, 1913, 975, 3109, 6699, 12943, 50865, 71811}},
-{10527, 17, 40801, {1, 3, 1, 5, 15, 61, 17, 219, 29, 805, 1881, 3761, 3535, 473, 15629, 26301, 51085}},
-{10528, 17, 40808, {1, 3, 1, 1, 7, 43, 87, 93, 355, 247, 641, 2851, 4565, 9293, 6025, 1945, 112549}},
-{10529, 17, 40811, {1, 3, 7, 5, 19, 55, 69, 227, 107, 443, 1587, 2457, 2873, 953, 27529, 57527, 54145}},
-{10530, 17, 40813, {1, 1, 5, 9, 1, 33, 31, 241, 339, 791, 399, 3435, 1711, 10815, 32657, 59875, 31291}},
-{10531, 17, 40825, {1, 1, 1, 7, 25, 59, 87, 115, 435, 47, 1907, 193, 6069, 10933, 9877, 46443, 3451}},
-{10532, 17, 40831, {1, 3, 3, 15, 25, 33, 19, 121, 133, 253, 1227, 75, 2839, 3341, 30727, 52451, 44883}},
-{10533, 17, 40835, {1, 1, 7, 11, 5, 47, 97, 255, 235, 565, 1701, 529, 839, 15473, 24471, 5749, 73135}},
-{10534, 17, 40856, {1, 1, 3, 7, 21, 15, 31, 81, 389, 957, 603, 3879, 2875, 11987, 24625, 53667, 77775}},
-{10535, 17, 40861, {1, 1, 5, 11, 29, 29, 31, 233, 107, 541, 561, 2533, 1421, 13587, 6943, 45635, 71315}},
-{10536, 17, 40880, {1, 3, 1, 9, 25, 19, 33, 53, 509, 485, 1637, 2877, 5927, 16059, 195, 17279, 127025}},
-{10537, 17, 40889, {1, 1, 1, 3, 9, 23, 97, 101, 337, 43, 1979, 1139, 3693, 2601, 8225, 53037, 63709}},
-{10538, 17, 40912, {1, 1, 7, 7, 17, 25, 121, 253, 63, 105, 527, 1397, 121, 9665, 29151, 10795, 79077}},
-{10539, 17, 40918, {1, 3, 3, 1, 27, 33, 123, 69, 209, 25, 1677, 1569, 4441, 7817, 5165, 29517, 117165}},
-{10540, 17, 40924, {1, 1, 5, 15, 3, 59, 13, 25, 359, 71, 179, 3925, 6899, 6007, 9121, 36297, 88541}},
-{10541, 17, 40927, {1, 1, 3, 11, 23, 17, 55, 133, 27, 277, 1055, 1057, 807, 1221, 1665, 64129, 102395}},
-{10542, 17, 40928, {1, 3, 1, 15, 13, 15, 105, 141, 329, 73, 609, 1663, 3277, 1767, 6371, 34325, 109563}},
-{10543, 17, 40938, {1, 1, 5, 1, 17, 21, 37, 81, 187, 403, 291, 1495, 5071, 14289, 29075, 44089, 95001}},
-{10544, 17, 40952, {1, 3, 3, 3, 15, 33, 49, 155, 41, 853, 15, 3571, 1433, 8469, 18711, 59007, 98703}},
-{10545, 17, 40957, {1, 3, 1, 13, 17, 47, 61, 151, 127, 87, 207, 3157, 5141, 14745, 32567, 18401, 7497}},
-{10546, 17, 40961, {1, 3, 5, 1, 19, 25, 49, 147, 137, 603, 1223, 3195, 5965, 11335, 20343, 10109, 63975}},
-{10547, 17, 40968, {1, 1, 7, 13, 29, 59, 1, 33, 157, 765, 961, 641, 7303, 3279, 20287, 37553, 114573}},
-{10548, 17, 40974, {1, 3, 5, 1, 11, 63, 63, 41, 15, 717, 1037, 227, 7875, 8681, 26943, 11761, 28005}},
-{10549, 17, 40986, {1, 3, 1, 3, 19, 5, 67, 169, 209, 293, 343, 2033, 7669, 1077, 15513, 54475, 15459}},
-{10550, 17, 40992, {1, 1, 3, 3, 17, 47, 49, 187, 341, 767, 1463, 301, 2083, 9265, 12313, 14763, 126627}},
-{10551, 17, 41001, {1, 3, 5, 13, 11, 15, 45, 237, 445, 55, 319, 2989, 5043, 1053, 22809, 23111, 7617}},
-{10552, 17, 41004, {1, 1, 7, 9, 7, 15, 41, 185, 511, 701, 1279, 1995, 7829, 2947, 3431, 45799, 1709}},
-{10553, 17, 41022, {1, 3, 7, 15, 5, 15, 85, 29, 487, 811, 1653, 483, 1193, 11331, 21815, 57215, 8373}},
-{10554, 17, 41033, {1, 3, 1, 15, 27, 19, 111, 161, 19, 373, 419, 1547, 2415, 10705, 17283, 56663, 73625}},
-{10555, 17, 41036, {1, 1, 3, 11, 27, 7, 75, 57, 411, 35, 685, 1249, 5227, 7313, 3167, 30537, 40655}},
-{10556, 17, 41039, {1, 3, 1, 9, 7, 37, 9, 209, 353, 319, 843, 657, 2069, 6523, 611, 16291, 107121}},
-{10557, 17, 41044, {1, 1, 5, 11, 11, 51, 25, 171, 315, 63, 207, 2279, 2379, 3583, 31927, 62451, 109911}},
-{10558, 17, 41064, {1, 1, 7, 11, 15, 41, 19, 175, 103, 605, 1889, 3161, 1217, 3259, 29655, 11715, 35551}},
-{10559, 17, 41078, {1, 3, 5, 13, 23, 11, 121, 147, 179, 397, 659, 3753, 2355, 1093, 25863, 39751, 112381}},
-{10560, 17, 41091, {1, 3, 5, 7, 1, 23, 37, 117, 7, 361, 991, 661, 4427, 15333, 5307, 55171, 96959}},
-{10561, 17, 41103, {1, 3, 1, 5, 17, 9, 77, 147, 289, 79, 295, 1271, 7809, 6387, 31785, 26489, 9335}},
-{10562, 17, 41108, {1, 1, 1, 7, 17, 33, 63, 147, 17, 515, 1349, 1907, 7703, 5511, 27773, 54025, 30019}},
-{10563, 17, 41112, {1, 3, 5, 3, 27, 57, 75, 129, 219, 533, 207, 3569, 5799, 6943, 12271, 53115, 120389}},
-{10564, 17, 41127, {1, 1, 1, 13, 11, 25, 101, 251, 289, 215, 1875, 1821, 703, 15395, 27167, 43187, 63401}},
-{10565, 17, 41128, {1, 1, 7, 15, 7, 39, 125, 41, 57, 513, 17, 965, 3225, 12833, 21131, 53243, 60377}},
-{10566, 17, 41136, {1, 3, 5, 3, 21, 19, 43, 195, 259, 523, 587, 3393, 6621, 43, 10951, 51877, 79967}},
-{10567, 17, 41141, {1, 3, 3, 7, 7, 19, 11, 89, 321, 821, 99, 2201, 1297, 949, 11539, 6295, 19721}},
-{10568, 17, 41146, {1, 1, 5, 3, 29, 27, 123, 111, 441, 441, 337, 3849, 1677, 14403, 17203, 50661, 92177}},
-{10569, 17, 41156, {1, 3, 5, 9, 23, 23, 73, 153, 241, 841, 371, 1503, 5815, 14117, 4679, 17997, 112269}},
-{10570, 17, 41159, {1, 1, 1, 1, 7, 37, 105, 185, 453, 905, 15, 57, 6963, 9665, 3371, 2391, 96023}},
-{10571, 17, 41163, {1, 3, 7, 1, 1, 21, 35, 43, 449, 111, 191, 2163, 3249, 15049, 30215, 43569, 127973}},
-{10572, 17, 41165, {1, 3, 3, 3, 17, 13, 77, 123, 471, 929, 1797, 2061, 355, 4441, 1101, 24631, 128711}},
-{10573, 17, 41166, {1, 3, 7, 7, 17, 51, 1, 69, 23, 1003, 535, 3751, 765, 5253, 21027, 52901, 61951}},
-{10574, 17, 41184, {1, 1, 7, 9, 25, 13, 33, 13, 423, 787, 223, 729, 4443, 227, 11487, 14259, 52951}},
-{10575, 17, 41193, {1, 3, 5, 5, 25, 27, 113, 93, 13, 679, 1295, 3773, 7253, 14629, 8907, 45885, 85387}},
-{10576, 17, 41202, {1, 3, 3, 13, 15, 55, 99, 31, 119, 955, 1477, 3745, 6777, 973, 4723, 62133, 65093}},
-{10577, 17, 41211, {1, 3, 3, 9, 13, 51, 105, 37, 477, 579, 765, 2573, 6869, 3891, 30969, 63413, 56603}},
-{10578, 17, 41216, {1, 3, 1, 3, 15, 23, 67, 109, 75, 721, 523, 1433, 3455, 6377, 23795, 13711, 121349}},
-{10579, 17, 41239, {1, 1, 3, 11, 5, 5, 99, 117, 233, 621, 509, 3235, 7483, 12325, 13203, 20075, 27537}},
-{10580, 17, 41243, {1, 3, 3, 9, 23, 51, 93, 245, 307, 689, 1993, 3607, 1985, 11839, 25553, 54941, 68741}},
-{10581, 17, 41249, {1, 1, 3, 5, 19, 21, 33, 71, 447, 539, 351, 2549, 87, 4317, 1287, 62289, 121065}},
-{10582, 17, 41262, {1, 3, 5, 5, 9, 23, 37, 189, 449, 263, 37, 3127, 1709, 10793, 7379, 38565, 8267}},
-{10583, 17, 41267, {1, 1, 7, 7, 7, 33, 23, 79, 457, 947, 1275, 2755, 3747, 9225, 31385, 8785, 76945}},
-{10584, 17, 41276, {1, 3, 1, 9, 17, 33, 29, 59, 505, 649, 1679, 3609, 1361, 5987, 26455, 17295, 98697}},
-{10585, 17, 41279, {1, 1, 3, 11, 7, 47, 127, 79, 419, 143, 349, 985, 6397, 10271, 29427, 19661, 32629}},
-{10586, 17, 41305, {1, 1, 5, 13, 15, 5, 79, 171, 491, 223, 1601, 705, 623, 4405, 10065, 28057, 105737}},
-{10587, 17, 41306, {1, 1, 7, 3, 29, 7, 81, 69, 265, 669, 1763, 2109, 6275, 7683, 19561, 26737, 54449}},
-{10588, 17, 41312, {1, 1, 1, 7, 1, 1, 5, 9, 65, 487, 1663, 1021, 1819, 9971, 22065, 40407, 4187}},
-{10589, 17, 41317, {1, 3, 5, 5, 21, 33, 11, 213, 309, 575, 427, 1421, 6435, 981, 31533, 16751, 47813}},
-{10590, 17, 41321, {1, 3, 3, 13, 7, 59, 65, 65, 401, 195, 211, 421, 1139, 11729, 19717, 20699, 111863}},
-{10591, 17, 41332, {1, 3, 7, 5, 17, 51, 25, 217, 223, 935, 431, 1703, 4869, 5635, 199, 5485, 37311}},
-{10592, 17, 41335, {1, 1, 3, 11, 23, 25, 15, 37, 187, 1007, 857, 3327, 5471, 10089, 13745, 1741, 37769}},
-{10593, 17, 41345, {1, 3, 5, 15, 31, 17, 75, 125, 1, 449, 1293, 3427, 709, 8285, 31143, 50655, 130793}},
-{10594, 17, 41346, {1, 1, 7, 3, 25, 55, 105, 255, 319, 183, 1571, 2425, 5429, 7151, 8569, 37447, 23055}},
-{10595, 17, 41351, {1, 3, 1, 1, 23, 37, 17, 61, 161, 559, 1025, 2651, 5861, 5231, 1365, 4853, 127301}},
-{10596, 17, 41365, {1, 3, 1, 9, 17, 37, 87, 241, 411, 53, 1555, 3805, 6867, 125, 9829, 53581, 117413}},
-{10597, 17, 41388, {1, 3, 3, 3, 23, 55, 121, 109, 441, 623, 1345, 3055, 2591, 11329, 16891, 61347, 125643}},
-{10598, 17, 41399, {1, 3, 1, 1, 5, 29, 53, 97, 15, 275, 1587, 1245, 379, 16117, 24369, 26873, 39547}},
-{10599, 17, 41405, {1, 3, 1, 5, 3, 63, 85, 167, 301, 45, 1357, 1185, 3939, 945, 24961, 59427, 128129}},
-{10600, 17, 41414, {1, 3, 1, 7, 23, 25, 109, 253, 37, 151, 17, 1241, 787, 15895, 7947, 65071, 14765}},
-{10601, 17, 41432, {1, 3, 3, 1, 7, 3, 103, 35, 73, 533, 1055, 823, 7403, 8117, 28813, 42457, 56037}},
-{10602, 17, 41454, {1, 3, 5, 15, 1, 15, 97, 109, 293, 259, 935, 2977, 5257, 14563, 28871, 17647, 34185}},
-{10603, 17, 41461, {1, 1, 1, 3, 29, 21, 101, 163, 173, 1019, 1025, 553, 945, 3781, 1097, 58025, 124819}},
-{10604, 17, 41462, {1, 1, 3, 9, 7, 35, 65, 61, 31, 547, 75, 3515, 6719, 12809, 23287, 14609, 30341}},
-{10605, 17, 41471, {1, 3, 7, 9, 3, 53, 21, 207, 383, 917, 1383, 2873, 1663, 15665, 1787, 50741, 35145}},
-{10606, 17, 41478, {1, 3, 7, 5, 3, 35, 113, 191, 171, 635, 1597, 2943, 2421, 5555, 6457, 22087, 104221}},
-{10607, 17, 41490, {1, 1, 1, 1, 29, 25, 3, 225, 175, 807, 1325, 215, 6475, 10729, 18619, 45401, 20627}},
-{10608, 17, 41506, {1, 1, 5, 11, 23, 25, 39, 207, 81, 633, 403, 3369, 1295, 1289, 20853, 48899, 16613}},
-{10609, 17, 41508, {1, 1, 7, 15, 5, 23, 17, 77, 169, 969, 1459, 3795, 3121, 5501, 32323, 46743, 124175}},
-{10610, 17, 41512, {1, 1, 7, 13, 3, 25, 77, 153, 105, 1017, 1599, 237, 4691, 1993, 6707, 50265, 13529}},
-{10611, 17, 41517, {1, 3, 3, 15, 7, 11, 81, 223, 61, 589, 1263, 3999, 7643, 12101, 19853, 49279, 29999}},
-{10612, 17, 41520, {1, 3, 1, 13, 3, 31, 61, 59, 41, 313, 115, 561, 3973, 13513, 6359, 29395, 34565}},
-{10613, 17, 41529, {1, 1, 7, 7, 7, 61, 91, 181, 307, 875, 2045, 1367, 3743, 6497, 2443, 12153, 96431}},
-{10614, 17, 41530, {1, 1, 3, 7, 19, 63, 97, 211, 157, 945, 891, 3747, 5483, 3081, 28939, 11179, 15935}},
-{10615, 17, 41544, {1, 3, 7, 3, 23, 39, 51, 137, 91, 179, 1515, 1397, 2783, 9343, 11483, 52407, 111725}},
-{10616, 17, 41550, {1, 3, 3, 11, 11, 25, 111, 61, 115, 329, 485, 1713, 565, 8607, 18869, 6595, 18605}},
-{10617, 17, 41571, {1, 1, 5, 1, 13, 59, 67, 231, 443, 695, 1185, 393, 6393, 12957, 15817, 37219, 113127}},
-{10618, 17, 41577, {1, 3, 5, 3, 15, 57, 25, 97, 321, 627, 15, 2005, 3813, 10399, 26779, 24243, 66463}},
-{10619, 17, 41580, {1, 3, 7, 7, 17, 43, 117, 179, 447, 1005, 2007, 1753, 7685, 13331, 5187, 49341, 111927}},
-{10620, 17, 41595, {1, 1, 3, 3, 5, 53, 35, 185, 93, 847, 1523, 3039, 25, 3351, 23195, 41133, 38547}},
-{10621, 17, 41613, {1, 1, 7, 5, 27, 59, 95, 137, 55, 129, 331, 127, 7421, 5633, 557, 18137, 89055}},
-{10622, 17, 41622, {1, 3, 3, 11, 5, 53, 93, 137, 175, 191, 1645, 2047, 2569, 8177, 22691, 4037, 31823}},
-{10623, 17, 41635, {1, 3, 3, 11, 11, 45, 77, 7, 21, 541, 49, 1689, 171, 829, 28917, 45095, 1807}},
-{10624, 17, 41642, {1, 3, 7, 5, 21, 5, 113, 81, 33, 681, 361, 1107, 1597, 115, 11503, 27413, 9199}},
-{10625, 17, 41661, {1, 1, 3, 11, 29, 57, 15, 249, 105, 683, 833, 2579, 3517, 16153, 17373, 32587, 124333}},
-{10626, 17, 41676, {1, 3, 7, 13, 3, 35, 55, 23, 293, 5, 2003, 2741, 4237, 8117, 20569, 63967, 106041}},
-{10627, 17, 41681, {1, 3, 3, 1, 1, 15, 57, 119, 135, 967, 1495, 801, 4959, 5037, 10051, 53915, 116891}},
-{10628, 17, 41684, {1, 1, 7, 9, 15, 29, 53, 139, 505, 473, 1179, 3289, 369, 13147, 15739, 16739, 54949}},
-{10629, 17, 41687, {1, 1, 5, 7, 7, 45, 17, 213, 381, 63, 437, 3099, 3765, 175, 13521, 11689, 58675}},
-{10630, 17, 41688, {1, 1, 7, 1, 15, 35, 55, 43, 147, 873, 1193, 3801, 2301, 14569, 31789, 50443, 62577}},
-{10631, 17, 41694, {1, 1, 5, 7, 21, 41, 3, 45, 43, 303, 1465, 1461, 5295, 13397, 30439, 7103, 87505}},
-{10632, 17, 41698, {1, 1, 1, 15, 19, 27, 81, 141, 307, 259, 521, 1785, 6917, 15635, 27781, 64809, 53297}},
-{10633, 17, 41710, {1, 1, 1, 7, 27, 15, 53, 99, 377, 935, 1869, 3835, 741, 8447, 18947, 10727, 72179}},
-{10634, 17, 41712, {1, 1, 3, 5, 15, 51, 91, 207, 7, 997, 935, 591, 7325, 3025, 11335, 32087, 109535}},
-{10635, 17, 41721, {1, 3, 1, 5, 11, 13, 1, 57, 45, 307, 1839, 1735, 2247, 13117, 17471, 16599, 103063}},
-{10636, 17, 41722, {1, 3, 5, 11, 19, 7, 121, 3, 325, 731, 1945, 4025, 7649, 8939, 11147, 59065, 49971}},
-{10637, 17, 41729, {1, 3, 1, 5, 29, 63, 95, 121, 467, 7, 1857, 2389, 5213, 3931, 21187, 43529, 6767}},
-{10638, 17, 41744, {1, 1, 7, 7, 9, 53, 31, 227, 95, 827, 927, 3501, 2003, 12853, 2595, 33223, 125799}},
-{10639, 17, 41747, {1, 3, 3, 3, 27, 25, 105, 143, 233, 887, 1135, 3449, 5767, 11447, 10251, 34621, 102113}},
-{10640, 17, 41753, {1, 3, 3, 15, 3, 63, 85, 119, 103, 835, 443, 3861, 4957, 5389, 6137, 48851, 51887}},
-{10641, 17, 41766, {1, 3, 7, 9, 23, 23, 45, 129, 463, 653, 1309, 3533, 1303, 2955, 18023, 37457, 114765}},
-{10642, 17, 41783, {1, 3, 7, 1, 23, 17, 31, 151, 71, 515, 781, 1793, 3507, 6051, 30279, 29461, 48271}},
-{10643, 17, 41790, {1, 3, 5, 15, 1, 31, 9, 187, 131, 571, 1309, 965, 7561, 16113, 23209, 54615, 16969}},
-{10644, 17, 41810, {1, 3, 5, 11, 11, 9, 109, 161, 9, 697, 1683, 1245, 2223, 3571, 18117, 13085, 99315}},
-{10645, 17, 41819, {1, 3, 3, 1, 13, 21, 27, 17, 11, 11, 1095, 1447, 6941, 3399, 21245, 36661, 54283}},
-{10646, 17, 41825, {1, 3, 1, 3, 21, 51, 21, 197, 161, 689, 1219, 1337, 6623, 5765, 11579, 2679, 23889}},
-{10647, 17, 41828, {1, 1, 5, 11, 7, 31, 101, 25, 231, 719, 1677, 1545, 459, 14735, 25153, 65079, 15141}},
-{10648, 17, 41843, {1, 1, 7, 9, 17, 7, 49, 1, 83, 829, 815, 307, 3405, 15189, 23699, 50889, 70391}},
-{10649, 17, 41846, {1, 1, 3, 15, 21, 57, 97, 191, 415, 899, 197, 2635, 7507, 14009, 8633, 48997, 93925}},
-{10650, 17, 41862, {1, 3, 5, 15, 23, 13, 67, 127, 33, 551, 911, 3933, 2027, 10665, 19509, 18485, 76111}},
-{10651, 17, 41871, {1, 1, 5, 7, 23, 63, 19, 149, 139, 155, 1621, 3391, 2337, 2809, 21161, 38565, 401}},
-{10652, 17, 41874, {1, 1, 1, 7, 19, 23, 81, 49, 339, 879, 1903, 657, 2677, 2273, 10853, 3225, 57933}},
-{10653, 17, 41876, {1, 3, 5, 5, 13, 31, 19, 203, 269, 1015, 997, 2151, 4471, 11331, 5363, 46519, 51709}},
-{10654, 17, 41892, {1, 1, 5, 11, 29, 19, 17, 169, 511, 389, 1429, 2707, 1341, 10511, 6779, 43345, 68693}},
-{10655, 17, 41899, {1, 1, 5, 11, 19, 25, 29, 37, 423, 345, 953, 2525, 5937, 6595, 31389, 39347, 36343}},
-{10656, 17, 41916, {1, 3, 1, 3, 15, 25, 45, 95, 111, 207, 19, 1723, 4113, 421, 3297, 46771, 8639}},
-{10657, 17, 41928, {1, 1, 3, 9, 9, 47, 27, 99, 327, 393, 1547, 1587, 4463, 719, 14609, 24347, 68107}},
-{10658, 17, 41957, {1, 3, 7, 7, 29, 19, 57, 229, 131, 497, 109, 251, 6599, 8947, 10255, 12875, 83831}},
-{10659, 17, 41964, {1, 3, 3, 7, 17, 5, 17, 45, 423, 393, 1793, 3, 603, 15221, 13141, 40585, 37489}},
-{10660, 17, 41969, {1, 1, 1, 11, 5, 1, 53, 147, 129, 135, 1473, 17, 7539, 13513, 16045, 17375, 41261}},
-{10661, 17, 41981, {1, 3, 1, 5, 3, 15, 75, 57, 47, 581, 739, 3529, 4323, 10225, 27861, 14431, 106811}},
-{10662, 17, 41996, {1, 3, 3, 13, 23, 57, 41, 39, 217, 67, 595, 1381, 6281, 10125, 30605, 7935, 124219}},
-{10663, 17, 41999, {1, 1, 7, 15, 15, 45, 1, 135, 495, 271, 2023, 3267, 39, 15025, 32763, 39023, 20041}},
-{10664, 17, 42001, {1, 3, 7, 13, 23, 53, 75, 147, 187, 633, 1989, 1885, 6581, 12169, 13639, 19707, 96429}},
-{10665, 17, 42017, {1, 1, 5, 9, 13, 55, 13, 41, 305, 105, 1983, 273, 35, 5185, 22569, 54203, 31641}},
-{10666, 17, 42023, {1, 1, 3, 15, 21, 19, 59, 35, 165, 575, 1961, 1443, 4803, 2339, 28329, 47695, 21505}},
-{10667, 17, 42027, {1, 3, 1, 3, 23, 45, 95, 85, 55, 457, 1957, 1243, 4091, 14669, 13213, 53901, 122605}},
-{10668, 17, 42032, {1, 3, 7, 1, 13, 1, 61, 253, 195, 839, 181, 1153, 1391, 205, 6725, 1757, 86817}},
-{10669, 17, 42035, {1, 1, 3, 9, 7, 13, 115, 137, 169, 851, 299, 509, 6709, 6331, 51, 31833, 25217}},
-{10670, 17, 42044, {1, 1, 5, 15, 29, 23, 119, 15, 41, 585, 1713, 1203, 1653, 3287, 25333, 58873, 71853}},
-{10671, 17, 42050, {1, 3, 5, 15, 1, 45, 35, 79, 97, 381, 2027, 3795, 2127, 4775, 4579, 63267, 24719}},
-{10672, 17, 42061, {1, 1, 5, 7, 17, 21, 123, 75, 3, 887, 1537, 2017, 1623, 16315, 12535, 64281, 54925}},
-{10673, 17, 42062, {1, 1, 3, 13, 5, 23, 117, 43, 305, 365, 775, 1599, 5917, 13995, 6353, 3113, 106317}},
-{10674, 17, 42073, {1, 1, 3, 11, 21, 19, 9, 11, 129, 349, 579, 3523, 5259, 8083, 24513, 15077, 115377}},
-{10675, 17, 42098, {1, 1, 7, 9, 19, 31, 107, 3, 185, 821, 907, 2389, 7015, 3161, 13603, 35063, 60641}},
-{10676, 17, 42104, {1, 1, 3, 1, 19, 35, 105, 245, 363, 745, 1287, 4051, 5201, 7787, 20919, 26567, 37357}},
-{10677, 17, 42109, {1, 3, 1, 1, 23, 31, 1, 149, 61, 489, 371, 987, 3689, 14275, 8581, 48221, 44183}},
-{10678, 17, 42120, {1, 1, 5, 3, 9, 35, 51, 17, 439, 355, 461, 2129, 1567, 13261, 22347, 17013, 53857}},
-{10679, 17, 42125, {1, 3, 3, 15, 3, 33, 59, 185, 157, 933, 1489, 647, 4839, 12139, 3145, 57819, 11731}},
-{10680, 17, 42131, {1, 3, 5, 15, 17, 31, 59, 51, 117, 1001, 1585, 2861, 2785, 9579, 28013, 4481, 126723}},
-{10681, 17, 42143, {1, 3, 7, 13, 27, 1, 41, 119, 179, 879, 1617, 4053, 3537, 15389, 16381, 40153, 68019}},
-{10682, 17, 42153, {1, 1, 3, 13, 13, 35, 45, 203, 333, 337, 1415, 1889, 2361, 4207, 10411, 21013, 44009}},
-{10683, 17, 42176, {1, 3, 3, 5, 27, 9, 17, 85, 331, 369, 1219, 247, 1977, 12267, 1181, 18811, 54017}},
-{10684, 17, 42182, {1, 3, 5, 9, 21, 57, 57, 175, 283, 639, 1155, 1595, 8187, 9981, 21451, 7525, 52751}},
-{10685, 17, 42188, {1, 3, 1, 5, 27, 61, 95, 25, 271, 81, 1335, 2821, 7805, 10167, 13197, 58341, 62325}},
-{10686, 17, 42203, {1, 1, 7, 3, 15, 31, 75, 5, 211, 663, 551, 963, 6015, 11907, 17045, 22863, 32389}},
-{10687, 17, 42216, {1, 1, 7, 5, 21, 53, 67, 71, 251, 135, 1153, 2247, 2499, 15431, 21419, 46737, 2827}},
-{10688, 17, 42219, {1, 1, 5, 3, 31, 25, 39, 209, 437, 791, 1595, 637, 1581, 6575, 26407, 24043, 11277}},
-{10689, 17, 42227, {1, 3, 3, 5, 21, 15, 13, 19, 259, 949, 1237, 239, 5739, 4661, 3405, 55775, 58781}},
-{10690, 17, 42234, {1, 1, 3, 5, 1, 63, 5, 197, 329, 625, 981, 913, 3957, 2765, 8801, 56675, 129511}},
-{10691, 17, 42251, {1, 3, 3, 3, 29, 53, 65, 145, 435, 937, 787, 2043, 4945, 14585, 2789, 15771, 112335}},
-{10692, 17, 42254, {1, 3, 7, 13, 3, 23, 33, 141, 131, 375, 739, 711, 897, 469, 3635, 43335, 3069}},
-{10693, 17, 42256, {1, 1, 7, 11, 29, 13, 111, 149, 197, 793, 1541, 1879, 7683, 9397, 6873, 43733, 118507}},
-{10694, 17, 42259, {1, 3, 7, 7, 29, 21, 97, 113, 139, 573, 1099, 2615, 5123, 13021, 9533, 57673, 79283}},
-{10695, 17, 42282, {1, 3, 1, 5, 11, 9, 59, 89, 469, 797, 1119, 1037, 1667, 5947, 6051, 65045, 98275}},
-{10696, 17, 42289, {1, 3, 3, 9, 11, 7, 51, 191, 321, 677, 1601, 681, 3579, 14441, 26579, 18019, 43065}},
-{10697, 17, 42302, {1, 3, 5, 11, 7, 11, 79, 21, 335, 537, 801, 3553, 4311, 375, 7333, 64839, 88841}},
-{10698, 17, 42307, {1, 3, 1, 7, 5, 11, 15, 163, 69, 645, 57, 3685, 5143, 8275, 12763, 25035, 68949}},
-{10699, 17, 42310, {1, 1, 3, 13, 29, 33, 125, 179, 431, 129, 1367, 951, 5843, 13419, 13897, 17315, 58083}},
-{10700, 17, 42322, {1, 1, 3, 11, 31, 33, 3, 7, 185, 821, 231, 869, 6147, 15243, 32029, 20295, 60871}},
-{10701, 17, 42328, {1, 1, 1, 1, 31, 43, 21, 103, 275, 573, 805, 225, 2049, 8375, 32595, 53201, 126487}},
-{10702, 17, 42338, {1, 1, 1, 9, 31, 29, 7, 91, 277, 937, 1223, 2435, 4335, 7861, 9647, 13577, 30059}},
-{10703, 17, 42349, {1, 1, 1, 1, 23, 25, 69, 175, 293, 905, 765, 1527, 6655, 15431, 2511, 3147, 75431}},
-{10704, 17, 42367, {1, 3, 3, 3, 15, 53, 109, 195, 87, 557, 1277, 1471, 7401, 14127, 11479, 41505, 769}},
-{10705, 17, 42386, {1, 1, 5, 11, 23, 37, 121, 181, 199, 359, 1521, 2561, 3641, 7621, 14219, 6959, 77529}},
-{10706, 17, 42398, {1, 3, 1, 11, 5, 7, 69, 199, 501, 251, 707, 1485, 8125, 3209, 30883, 40259, 85087}},
-{10707, 17, 42404, {1, 3, 5, 13, 9, 35, 5, 133, 505, 39, 581, 1605, 6303, 1211, 27211, 55591, 31689}},
-{10708, 17, 42413, {1, 1, 5, 3, 17, 7, 11, 61, 483, 59, 1569, 2583, 759, 5759, 3575, 44547, 89783}},
-{10709, 17, 42419, {1, 1, 7, 15, 5, 27, 107, 5, 471, 421, 383, 3591, 3609, 13817, 633, 22043, 83119}},
-{10710, 17, 42421, {1, 1, 3, 7, 27, 55, 61, 249, 37, 241, 1483, 2839, 1231, 4765, 1551, 55801, 129679}},
-{10711, 17, 42422, {1, 1, 1, 3, 11, 1, 19, 207, 143, 351, 409, 721, 4597, 13389, 30297, 43253, 129923}},
-{10712, 17, 42431, {1, 3, 3, 7, 7, 53, 83, 27, 167, 163, 537, 3871, 2459, 12813, 30019, 41131, 56109}},
-{10713, 17, 42445, {1, 1, 5, 1, 23, 37, 11, 67, 161, 751, 123, 307, 3341, 12983, 21565, 58529, 94503}},
-{10714, 17, 42448, {1, 3, 3, 15, 11, 33, 39, 195, 467, 647, 1479, 1197, 7949, 6501, 18375, 15263, 21121}},
-{10715, 17, 42451, {1, 3, 5, 13, 3, 35, 9, 253, 299, 679, 69, 165, 2735, 14725, 4217, 16391, 107017}},
-{10716, 17, 42454, {1, 1, 1, 15, 3, 11, 87, 87, 391, 515, 843, 3957, 1365, 13201, 15983, 53647, 35643}},
-{10717, 17, 42458, {1, 1, 3, 7, 9, 53, 45, 221, 209, 855, 169, 2729, 1219, 5229, 14111, 28877, 114653}},
-{10718, 17, 42470, {1, 1, 5, 3, 11, 17, 5, 93, 303, 785, 1895, 2483, 7399, 14031, 1007, 2743, 47307}},
-{10719, 17, 42476, {1, 1, 7, 11, 9, 13, 115, 31, 223, 1011, 723, 1291, 5183, 559, 15881, 43045, 28131}},
-{10720, 17, 42500, {1, 3, 7, 11, 7, 59, 85, 111, 79, 227, 691, 1597, 2453, 10023, 19255, 47781, 88351}},
-{10721, 17, 42509, {1, 3, 3, 7, 21, 33, 39, 35, 253, 743, 563, 2455, 8015, 13403, 24883, 47881, 115559}},
-{10722, 17, 42538, {1, 3, 1, 1, 5, 33, 69, 37, 225, 157, 1347, 3241, 4981, 15985, 9949, 49189, 21267}},
-{10723, 17, 42543, {1, 1, 3, 11, 9, 33, 123, 133, 215, 297, 961, 1571, 1133, 1, 31871, 25253, 100097}},
-{10724, 17, 42545, {1, 1, 1, 7, 13, 29, 101, 127, 113, 785, 1257, 525, 7397, 13143, 30315, 5969, 37829}},
-{10725, 17, 42546, {1, 1, 1, 7, 29, 33, 17, 95, 439, 577, 1857, 423, 63, 15365, 4777, 59073, 7773}},
-{10726, 17, 42563, {1, 1, 5, 15, 3, 17, 89, 133, 217, 601, 1979, 391, 105, 13709, 10081, 37725, 40957}},
-{10727, 17, 42570, {1, 1, 1, 15, 25, 7, 85, 197, 155, 367, 1927, 2007, 2563, 13147, 2345, 28735, 88243}},
-{10728, 17, 42580, {1, 3, 5, 3, 5, 33, 87, 153, 153, 779, 825, 2163, 385, 11663, 2005, 51261, 25893}},
-{10729, 17, 42584, {1, 3, 5, 5, 23, 15, 19, 99, 71, 723, 523, 3683, 7773, 191, 17423, 30497, 129889}},
-{10730, 17, 42589, {1, 1, 7, 11, 1, 3, 49, 119, 39, 661, 297, 27, 1575, 12145, 18519, 57285, 50059}},
-{10731, 17, 42608, {1, 3, 7, 5, 7, 37, 75, 235, 403, 743, 603, 1689, 5031, 8871, 28241, 16917, 16947}},
-{10732, 17, 42618, {1, 1, 5, 13, 17, 41, 67, 219, 237, 365, 833, 3521, 3211, 1037, 5657, 34789, 119739}},
-{10733, 17, 42629, {1, 1, 5, 7, 3, 61, 89, 107, 335, 825, 803, 2445, 6861, 5421, 14585, 44037, 92711}},
-{10734, 17, 42636, {1, 3, 7, 3, 19, 25, 81, 51, 101, 477, 1653, 2841, 6597, 9261, 30609, 15681, 48897}},
-{10735, 17, 42639, {1, 1, 7, 11, 17, 1, 43, 39, 133, 513, 1839, 553, 6379, 4865, 28161, 7249, 80073}},
-{10736, 17, 42644, {1, 1, 5, 5, 13, 45, 19, 225, 399, 679, 195, 3613, 413, 2901, 26749, 39971, 31435}},
-{10737, 17, 42647, {1, 3, 7, 3, 23, 55, 57, 77, 447, 721, 677, 271, 6211, 12631, 5843, 35991, 82653}},
-{10738, 17, 42651, {1, 1, 1, 1, 3, 63, 23, 195, 1, 1019, 723, 3865, 5913, 5491, 5495, 27483, 73637}},
-{10739, 17, 42654, {1, 3, 1, 11, 17, 31, 27, 211, 411, 789, 1049, 2487, 2203, 6457, 7275, 4833, 14131}},
-{10740, 17, 42658, {1, 1, 5, 15, 15, 13, 65, 155, 127, 753, 1605, 1859, 2873, 9197, 1763, 11969, 82971}},
-{10741, 17, 42669, {1, 1, 3, 11, 11, 63, 13, 29, 31, 851, 251, 3231, 1227, 5513, 9785, 34659, 123811}},
-{10742, 17, 42678, {1, 3, 5, 1, 19, 57, 41, 205, 91, 39, 989, 1897, 4789, 16071, 6507, 29363, 75773}},
-{10743, 17, 42689, {1, 1, 1, 1, 5, 29, 113, 203, 53, 599, 1529, 1417, 7017, 9609, 4867, 17659, 80719}},
-{10744, 17, 42695, {1, 3, 7, 9, 27, 17, 77, 25, 461, 511, 781, 2977, 7601, 3551, 23615, 57669, 119723}},
-{10745, 17, 42696, {1, 3, 3, 9, 23, 43, 115, 21, 125, 237, 893, 1431, 7423, 3717, 4371, 36193, 30481}},
-{10746, 17, 42710, {1, 1, 5, 13, 3, 37, 13, 239, 267, 665, 205, 2745, 3865, 12167, 26689, 999, 9355}},
-{10747, 17, 42716, {1, 1, 1, 1, 31, 35, 55, 115, 387, 217, 657, 2827, 2963, 3687, 24271, 41701, 5911}},
-{10748, 17, 42730, {1, 1, 3, 3, 27, 57, 41, 183, 351, 841, 1327, 719, 7043, 12503, 17953, 60719, 98223}},
-{10749, 17, 42732, {1, 3, 1, 1, 27, 1, 119, 85, 197, 673, 1951, 2949, 4783, 561, 12807, 43355, 63397}},
-{10750, 17, 42747, {1, 1, 7, 7, 17, 63, 109, 87, 303, 439, 529, 685, 111, 8405, 21249, 33803, 77927}},
-{10751, 17, 42750, {1, 1, 7, 9, 11, 63, 27, 185, 445, 25, 1313, 3979, 4229, 8797, 10671, 33995, 84463}},
-{10752, 17, 42752, {1, 1, 1, 15, 27, 63, 67, 237, 39, 993, 851, 4075, 3417, 1077, 11939, 31737, 93897}},
-{10753, 17, 42761, {1, 1, 3, 5, 25, 9, 51, 241, 213, 661, 1135, 213, 7027, 5933, 24485, 65029, 8583}},
-{10754, 17, 42772, {1, 3, 5, 11, 31, 1, 17, 237, 107, 1021, 279, 181, 1741, 11099, 7871, 63231, 64445}},
-{10755, 17, 42776, {1, 3, 5, 9, 17, 21, 11, 45, 23, 409, 519, 1703, 5467, 9591, 13555, 23739, 73837}},
-{10756, 17, 42779, {1, 3, 3, 15, 3, 39, 11, 157, 273, 241, 413, 1723, 3179, 2125, 16859, 5231, 122969}},
-{10757, 17, 42797, {1, 3, 5, 11, 21, 27, 29, 243, 255, 1011, 1179, 3545, 3557, 8091, 31569, 10217, 108361}},
-{10758, 17, 42815, {1, 1, 5, 9, 25, 33, 29, 67, 395, 123, 1405, 3855, 7481, 5601, 21231, 17099, 13399}},
-{10759, 17, 42824, {1, 1, 5, 5, 13, 17, 111, 47, 77, 827, 577, 1767, 3367, 11719, 8801, 22431, 85451}},
-{10760, 17, 42837, {1, 3, 7, 11, 11, 31, 17, 141, 149, 293, 55, 3459, 19, 13709, 29135, 62765, 66455}},
-{10761, 17, 42844, {1, 1, 7, 15, 13, 19, 59, 211, 189, 773, 1791, 2089, 2857, 1635, 17777, 46585, 70115}},
-{10762, 17, 42868, {1, 1, 5, 11, 29, 29, 15, 7, 93, 733, 1605, 3731, 2381, 1063, 15565, 25081, 46651}},
-{10763, 17, 42877, {1, 3, 1, 9, 25, 5, 87, 113, 25, 93, 881, 1137, 3237, 10983, 14317, 25945, 121493}},
-{10764, 17, 42888, {1, 1, 5, 11, 29, 47, 99, 111, 165, 453, 259, 2001, 7715, 2609, 15633, 40273, 2065}},
-{10765, 17, 42891, {1, 1, 7, 13, 11, 29, 33, 255, 149, 361, 89, 2837, 49, 3033, 1917, 9029, 38123}},
-{10766, 17, 42912, {1, 1, 1, 7, 27, 31, 105, 61, 469, 497, 1919, 3005, 3651, 2143, 24359, 8053, 103647}},
-{10767, 17, 42918, {1, 1, 3, 13, 31, 63, 101, 47, 397, 89, 1915, 2385, 5399, 8897, 21001, 42997, 110333}},
-{10768, 17, 42921, {1, 3, 7, 5, 29, 1, 5, 119, 493, 349, 153, 1839, 283, 14343, 12975, 55597, 89467}},
-{10769, 17, 42927, {1, 3, 5, 3, 5, 51, 71, 227, 63, 799, 745, 1387, 2435, 1003, 27937, 43421, 12279}},
-{10770, 17, 42949, {1, 3, 3, 7, 7, 31, 37, 61, 11, 175, 581, 1583, 4737, 3087, 10335, 60683, 57085}},
-{10771, 17, 42953, {1, 3, 1, 1, 1, 63, 59, 47, 417, 35, 1673, 3277, 1873, 14981, 22463, 26835, 91115}},
-{10772, 17, 42967, {1, 1, 7, 5, 15, 23, 115, 13, 253, 583, 219, 1307, 1189, 9891, 641, 20841, 87133}},
-{10773, 17, 42974, {1, 1, 5, 11, 1, 3, 71, 235, 429, 335, 1649, 1775, 3077, 13723, 3209, 19807, 7283}},
-{10774, 17, 42989, {1, 1, 7, 1, 31, 49, 39, 141, 127, 63, 1561, 2559, 7661, 4825, 9419, 15327, 87145}},
-{10775, 17, 42995, {1, 1, 5, 3, 17, 33, 51, 219, 467, 151, 161, 3301, 7509, 2235, 30371, 64031, 62741}},
-{10776, 17, 42997, {1, 3, 1, 3, 23, 63, 43, 29, 399, 279, 271, 3537, 1863, 1811, 14917, 28247, 34807}},
-{10777, 17, 43007, {1, 1, 3, 5, 13, 29, 37, 151, 129, 19, 149, 2145, 5363, 6835, 19655, 1207, 74527}},
-{10778, 17, 43018, {1, 3, 5, 7, 27, 35, 63, 53, 247, 987, 1767, 483, 3489, 1711, 10763, 6981, 78251}},
-{10779, 17, 43025, {1, 1, 3, 1, 15, 47, 83, 147, 375, 539, 1623, 29, 4599, 7981, 23533, 64659, 48753}},
-{10780, 17, 43031, {1, 1, 1, 9, 21, 17, 85, 45, 167, 469, 1319, 2969, 1605, 1405, 9961, 28829, 125757}},
-{10781, 17, 43032, {1, 3, 1, 11, 3, 45, 43, 159, 301, 579, 1821, 701, 1149, 457, 16601, 49377, 99845}},
-{10782, 17, 43038, {1, 1, 7, 13, 11, 7, 37, 227, 345, 973, 1167, 1247, 5109, 10917, 3029, 60065, 127347}},
-{10783, 17, 43041, {1, 1, 3, 5, 3, 63, 95, 233, 495, 225, 1225, 3451, 7731, 14677, 10437, 1417, 33293}},
-{10784, 17, 43054, {1, 1, 7, 15, 1, 3, 3, 171, 201, 1009, 1481, 587, 7661, 10085, 4961, 46415, 28573}},
-{10785, 17, 43074, {1, 1, 5, 1, 3, 45, 67, 79, 463, 733, 2007, 2811, 2943, 14857, 23469, 14479, 97875}},
-{10786, 17, 43085, {1, 1, 1, 5, 19, 1, 29, 29, 447, 173, 1081, 153, 5343, 5707, 1357, 30169, 122527}},
-{10787, 17, 43097, {1, 1, 1, 5, 15, 57, 33, 129, 71, 717, 173, 3271, 4741, 13211, 28321, 56793, 119833}},
-{10788, 17, 43098, {1, 3, 3, 9, 9, 41, 47, 71, 103, 713, 725, 1335, 5261, 13835, 17619, 47429, 69815}},
-{10789, 17, 43110, {1, 3, 3, 15, 7, 3, 71, 25, 75, 967, 1037, 3585, 3407, 9979, 2195, 51087, 126535}},
-{10790, 17, 43119, {1, 3, 3, 11, 25, 7, 25, 249, 473, 339, 1211, 3503, 4343, 9707, 26127, 62061, 52479}},
-{10791, 17, 43131, {1, 1, 3, 3, 27, 9, 79, 197, 207, 845, 377, 3231, 5177, 899, 19497, 41187, 105897}},
-{10792, 17, 43143, {1, 3, 5, 15, 5, 27, 65, 151, 207, 677, 713, 2495, 681, 15341, 5389, 51965, 43761}},
-{10793, 17, 43144, {1, 3, 3, 11, 19, 11, 55, 189, 291, 183, 1345, 2677, 791, 2391, 25771, 55147, 24223}},
-{10794, 17, 43152, {1, 1, 3, 11, 31, 59, 29, 5, 275, 483, 1361, 1527, 3019, 245, 17667, 57905, 41329}},
-{10795, 17, 43157, {1, 3, 3, 9, 7, 19, 83, 71, 147, 999, 793, 3535, 1931, 12817, 2707, 45735, 31311}},
-{10796, 17, 43178, {1, 1, 5, 7, 5, 1, 117, 247, 127, 1011, 1441, 2449, 4095, 12239, 4743, 64781, 32621}},
-{10797, 17, 43180, {1, 3, 1, 11, 19, 57, 43, 39, 97, 485, 951, 989, 5975, 5219, 14421, 43681, 37305}},
-{10798, 17, 43192, {1, 1, 5, 15, 7, 49, 113, 161, 199, 545, 1113, 3821, 2019, 8747, 4085, 50823, 31955}},
-{10799, 17, 43197, {1, 3, 3, 3, 19, 41, 47, 191, 403, 25, 2043, 3489, 6263, 4843, 12961, 63791, 5027}},
-{10800, 17, 43203, {1, 1, 7, 1, 25, 55, 5, 51, 121, 273, 973, 3893, 1771, 9373, 21927, 29353, 95935}},
-{10801, 17, 43220, {1, 3, 3, 3, 27, 1, 97, 63, 445, 179, 481, 2995, 3123, 4687, 24359, 35973, 74535}},
-{10802, 17, 43236, {1, 1, 5, 1, 29, 23, 117, 183, 197, 819, 695, 641, 4155, 13593, 30965, 41407, 42433}},
-{10803, 17, 43245, {1, 3, 5, 1, 23, 53, 61, 253, 87, 487, 1995, 1281, 3367, 15047, 3493, 41711, 53407}},
-{10804, 17, 43246, {1, 1, 1, 9, 27, 49, 83, 21, 63, 181, 1661, 1649, 281, 12141, 25771, 35563, 42643}},
-{10805, 17, 43260, {1, 3, 5, 13, 15, 59, 121, 113, 379, 487, 1929, 3725, 2477, 6527, 8619, 64869, 57103}},
-{10806, 17, 43265, {1, 3, 1, 7, 27, 39, 69, 93, 193, 395, 433, 2091, 151, 6921, 11599, 36143, 41179}},
-{10807, 17, 43271, {1, 1, 7, 1, 31, 33, 73, 199, 57, 37, 1387, 3505, 7919, 3507, 2855, 8239, 84527}},
-{10808, 17, 43285, {1, 1, 7, 5, 15, 5, 119, 253, 263, 785, 1409, 1485, 3675, 5515, 13057, 30323, 98015}},
-{10809, 17, 43286, {1, 3, 1, 1, 11, 5, 57, 83, 365, 703, 1923, 1397, 1103, 4015, 13123, 47093, 113793}},
-{10810, 17, 43290, {1, 3, 3, 1, 5, 61, 29, 173, 189, 999, 897, 3389, 6745, 1487, 2349, 59105, 107407}},
-{10811, 17, 43299, {1, 1, 1, 1, 17, 51, 65, 1, 249, 863, 399, 3819, 2485, 12215, 12365, 58909, 25559}},
-{10812, 17, 43314, {1, 3, 7, 1, 31, 39, 43, 219, 51, 13, 779, 505, 2259, 14571, 9049, 21555, 11869}},
-{10813, 17, 43323, {1, 1, 7, 7, 13, 5, 97, 85, 111, 511, 587, 63, 2395, 8099, 26223, 757, 119821}},
-{10814, 17, 43337, {1, 3, 3, 5, 5, 19, 113, 35, 101, 41, 499, 1313, 6489, 6793, 31435, 45007, 95691}},
-{10815, 17, 43348, {1, 3, 5, 15, 19, 37, 103, 187, 347, 667, 1957, 1825, 7447, 12359, 21779, 52749, 18679}},
-{10816, 17, 43355, {1, 3, 5, 5, 17, 19, 19, 193, 435, 379, 439, 2093, 725, 2133, 15659, 54645, 59567}},
-{10817, 17, 43357, {1, 3, 7, 3, 23, 35, 33, 13, 23, 349, 231, 1635, 1625, 5039, 21299, 36413, 104681}},
-{10818, 17, 43358, {1, 1, 3, 13, 23, 49, 15, 253, 509, 9, 411, 2157, 3737, 11227, 6021, 42919, 100375}},
-{10819, 17, 43361, {1, 1, 7, 1, 17, 11, 33, 167, 219, 63, 137, 741, 4193, 16149, 9657, 50223, 85213}},
-{10820, 17, 43362, {1, 3, 7, 11, 23, 59, 113, 149, 427, 697, 1723, 255, 201, 10081, 1079, 323, 109091}},
-{10821, 17, 43364, {1, 3, 3, 15, 11, 9, 89, 39, 67, 249, 1939, 1737, 3719, 10515, 16517, 22345, 83959}},
-{10822, 17, 43368, {1, 3, 3, 13, 5, 33, 127, 9, 329, 429, 563, 1579, 4427, 8343, 22083, 5035, 124915}},
-{10823, 17, 43376, {1, 1, 1, 5, 15, 57, 121, 171, 315, 983, 743, 2015, 2421, 12431, 2561, 13331, 73163}},
-{10824, 17, 43385, {1, 1, 3, 9, 1, 39, 85, 159, 23, 979, 1467, 231, 4231, 3669, 16747, 24195, 46745}},
-{10825, 17, 43386, {1, 1, 3, 7, 3, 11, 65, 67, 85, 455, 365, 2279, 3471, 12771, 14443, 42773, 28723}},
-{10826, 17, 43391, {1, 3, 5, 1, 13, 9, 105, 237, 103, 59, 1301, 3125, 509, 12669, 3893, 9775, 81303}},
-{10827, 17, 43397, {1, 1, 3, 11, 19, 9, 125, 23, 191, 979, 533, 429, 3239, 15013, 13833, 40689, 102827}},
-{10828, 17, 43431, {1, 3, 3, 7, 15, 5, 83, 243, 467, 913, 1279, 3889, 8049, 8357, 5957, 39073, 93521}},
-{10829, 17, 43438, {1, 3, 3, 3, 19, 5, 123, 77, 289, 57, 2001, 807, 5257, 1671, 20273, 10183, 128439}},
-{10830, 17, 43440, {1, 1, 7, 13, 19, 45, 25, 47, 135, 929, 1353, 2731, 3351, 7637, 27037, 58835, 50285}},
-{10831, 17, 43452, {1, 3, 1, 1, 13, 55, 55, 197, 409, 93, 1351, 161, 1885, 5913, 27937, 49793, 84541}},
-{10832, 17, 43463, {1, 1, 3, 7, 29, 21, 113, 179, 203, 533, 1471, 2035, 447, 6781, 28729, 31099, 23027}},
-{10833, 17, 43470, {1, 1, 3, 11, 27, 3, 5, 209, 367, 945, 749, 3637, 2881, 8139, 27875, 34223, 97263}},
-{10834, 17, 43478, {1, 3, 5, 13, 25, 27, 35, 3, 13, 707, 303, 3663, 6617, 13501, 25537, 33077, 71485}},
-{10835, 17, 43481, {1, 1, 7, 15, 11, 29, 65, 47, 235, 635, 133, 153, 6175, 2961, 8171, 28641, 122589}},
-{10836, 17, 43488, {1, 1, 5, 15, 17, 41, 85, 147, 323, 673, 1629, 3477, 3341, 16373, 13901, 60961, 39451}},
-{10837, 17, 43491, {1, 3, 1, 15, 29, 15, 37, 109, 293, 863, 1835, 1173, 2263, 13815, 24995, 6989, 103417}},
-{10838, 17, 43506, {1, 3, 3, 15, 3, 31, 23, 47, 15, 717, 1457, 1067, 6229, 7051, 21771, 54815, 115827}},
-{10839, 17, 43512, {1, 1, 1, 13, 21, 3, 45, 239, 89, 603, 407, 781, 8095, 7389, 18035, 32229, 39867}},
-{10840, 17, 43539, {1, 1, 3, 7, 7, 59, 79, 51, 411, 917, 803, 2455, 2623, 12413, 23957, 44199, 67903}},
-{10841, 17, 43567, {1, 3, 1, 9, 17, 37, 117, 47, 101, 733, 1861, 1111, 6785, 13743, 24371, 49427, 54711}},
-{10842, 17, 43579, {1, 3, 1, 15, 27, 63, 107, 33, 351, 287, 1765, 1947, 6209, 8127, 30007, 18757, 31453}},
-{10843, 17, 43584, {1, 3, 5, 13, 11, 13, 29, 247, 7, 609, 1235, 1767, 5365, 12673, 10151, 51579, 106407}},
-{10844, 17, 43601, {1, 3, 7, 15, 5, 25, 81, 197, 51, 615, 1695, 259, 7983, 1403, 7903, 21441, 73263}},
-{10845, 17, 43614, {1, 1, 5, 1, 13, 61, 55, 175, 445, 3, 1957, 1171, 6823, 4285, 11847, 12789, 79787}},
-{10846, 17, 43617, {1, 1, 5, 15, 17, 51, 111, 201, 45, 97, 45, 2533, 1125, 3663, 13685, 45719, 51497}},
-{10847, 17, 43623, {1, 3, 3, 13, 29, 59, 111, 97, 381, 477, 1229, 3709, 5185, 7055, 32729, 32881, 25539}},
-{10848, 17, 43630, {1, 3, 1, 9, 1, 39, 57, 143, 189, 625, 1717, 1755, 3129, 807, 27975, 15511, 66123}},
-{10849, 17, 43647, {1, 3, 3, 1, 5, 41, 25, 27, 163, 397, 1595, 2325, 1803, 12439, 25743, 24509, 72613}},
-{10850, 17, 43658, {1, 1, 5, 13, 29, 41, 125, 113, 367, 709, 1911, 669, 831, 5375, 31145, 26197, 33543}},
-{10851, 17, 43663, {1, 1, 5, 1, 1, 5, 91, 199, 133, 273, 393, 1179, 717, 12791, 17693, 6905, 20433}},
-{10852, 17, 43665, {1, 1, 3, 15, 29, 35, 9, 127, 383, 673, 1821, 2765, 2425, 11789, 19741, 43189, 99557}},
-{10853, 17, 43691, {1, 1, 7, 13, 9, 19, 119, 103, 11, 983, 623, 391, 1609, 2333, 19843, 28269, 41237}},
-{10854, 17, 43701, {1, 3, 7, 5, 29, 3, 13, 213, 387, 361, 749, 669, 1625, 5687, 11369, 38119, 38389}},
-{10855, 17, 43705, {1, 3, 5, 13, 13, 51, 47, 33, 1, 979, 1817, 2633, 7181, 47, 3603, 49211, 4377}},
-{10856, 17, 43708, {1, 3, 1, 1, 11, 63, 5, 249, 13, 805, 1097, 1449, 5235, 16299, 25855, 30949, 3013}},
-{10857, 17, 43719, {1, 3, 7, 9, 29, 35, 89, 135, 475, 945, 999, 771, 6023, 13317, 32611, 43971, 10393}},
-{10858, 17, 43731, {1, 1, 1, 5, 23, 3, 37, 117, 95, 985, 1599, 2191, 3617, 5831, 31113, 10873, 112219}},
-{10859, 17, 43737, {1, 3, 5, 7, 11, 15, 55, 65, 239, 365, 1209, 3509, 8101, 8619, 24775, 65291, 50589}},
-{10860, 17, 43740, {1, 1, 7, 9, 21, 19, 123, 83, 317, 717, 433, 31, 2597, 14723, 28839, 7817, 126123}},
-{10861, 17, 43747, {1, 1, 7, 11, 3, 33, 99, 39, 227, 279, 353, 1921, 7883, 16187, 5157, 41121, 89425}},
-{10862, 17, 43749, {1, 3, 5, 9, 25, 7, 29, 165, 129, 77, 159, 923, 1357, 1159, 23537, 58087, 56443}},
-{10863, 17, 43750, {1, 1, 7, 3, 13, 51, 45, 161, 27, 41, 1295, 2937, 7223, 5271, 17927, 23311, 2543}},
-{10864, 17, 43754, {1, 1, 1, 1, 11, 53, 119, 165, 409, 785, 1649, 3587, 259, 10997, 3171, 31271, 104631}},
-{10865, 17, 43764, {1, 1, 5, 7, 5, 7, 49, 201, 373, 825, 1755, 3751, 8041, 8133, 21347, 12039, 3049}},
-{10866, 17, 43767, {1, 1, 1, 3, 7, 29, 103, 1, 473, 65, 761, 1611, 5121, 14345, 32535, 16679, 11321}},
-{10867, 17, 43768, {1, 3, 3, 11, 21, 57, 35, 63, 237, 415, 1943, 483, 5377, 14647, 23433, 45459, 32535}},
-{10868, 17, 43773, {1, 1, 1, 15, 21, 57, 7, 103, 493, 279, 665, 3699, 169, 7619, 3571, 11539, 31983}},
-{10869, 17, 43785, {1, 1, 1, 1, 9, 5, 81, 159, 105, 927, 379, 1133, 1805, 14341, 9833, 63151, 70877}},
-{10870, 17, 43788, {1, 1, 7, 5, 19, 5, 63, 127, 129, 43, 757, 2215, 3899, 643, 19731, 17345, 102611}},
-{10871, 17, 43810, {1, 3, 7, 7, 27, 21, 3, 69, 475, 283, 319, 833, 3683, 11275, 18191, 44027, 24901}},
-{10872, 17, 43819, {1, 1, 5, 5, 31, 25, 63, 33, 505, 765, 257, 1147, 779, 12505, 19971, 24695, 65935}},
-{10873, 17, 43834, {1, 1, 1, 15, 23, 33, 31, 107, 59, 639, 1307, 3211, 6171, 15665, 16775, 61671, 25569}},
-{10874, 17, 43853, {1, 3, 3, 9, 31, 3, 113, 199, 425, 895, 1051, 2125, 1525, 15199, 14845, 4213, 18449}},
-{10875, 17, 43866, {1, 3, 5, 3, 3, 11, 75, 121, 33, 265, 459, 3879, 909, 6533, 18451, 32421, 117427}},
-{10876, 17, 43871, {1, 1, 1, 9, 11, 9, 125, 175, 309, 847, 959, 2013, 1557, 9291, 2963, 43275, 9917}},
-{10877, 17, 43872, {1, 1, 5, 3, 15, 39, 67, 35, 373, 601, 463, 1263, 1615, 15059, 31011, 36059, 114493}},
-{10878, 17, 43881, {1, 1, 5, 15, 5, 43, 49, 239, 461, 171, 1863, 2249, 2923, 15897, 22941, 29925, 21429}},
-{10879, 17, 43889, {1, 1, 1, 15, 13, 31, 127, 205, 361, 149, 1641, 1443, 5959, 13183, 13861, 9533, 1011}},
-{10880, 17, 43902, {1, 1, 3, 13, 9, 49, 39, 67, 165, 695, 611, 2261, 3425, 6247, 23575, 51833, 106167}},
-{10881, 17, 43926, {1, 1, 7, 9, 29, 21, 75, 251, 87, 263, 2035, 1007, 3821, 12719, 8889, 47901, 39037}},
-{10882, 17, 43935, {1, 3, 1, 3, 15, 51, 79, 127, 201, 497, 1881, 3841, 1821, 14435, 4933, 6853, 104305}},
-{10883, 17, 43946, {1, 1, 5, 11, 23, 47, 33, 109, 481, 585, 333, 2525, 593, 1625, 5787, 23839, 30647}},
-{10884, 17, 43951, {1, 1, 5, 1, 17, 3, 7, 43, 113, 873, 1433, 3377, 45, 831, 17015, 21479, 7257}},
-{10885, 17, 43953, {1, 1, 1, 1, 13, 21, 59, 159, 279, 871, 53, 3647, 2599, 12417, 25807, 6867, 18251}},
-{10886, 17, 43971, {1, 1, 5, 9, 29, 61, 7, 81, 353, 761, 269, 4047, 3051, 8385, 2919, 18875, 15239}},
-{10887, 17, 44008, {1, 1, 7, 13, 31, 17, 71, 103, 107, 655, 1263, 849, 1809, 349, 3239, 45381, 117451}},
-{10888, 17, 44011, {1, 1, 5, 9, 27, 45, 83, 207, 117, 77, 437, 523, 851, 13595, 12381, 27271, 59951}},
-{10889, 17, 44026, {1, 3, 3, 15, 3, 33, 103, 217, 61, 443, 1077, 2887, 1751, 11111, 465, 37051, 89687}},
-{10890, 17, 44033, {1, 1, 1, 5, 15, 15, 13, 115, 275, 565, 1257, 1067, 6561, 8143, 2149, 53169, 123637}},
-{10891, 17, 44048, {1, 3, 3, 15, 27, 63, 25, 191, 143, 103, 1247, 1053, 2469, 9823, 4437, 18195, 91751}},
-{10892, 17, 44057, {1, 1, 7, 11, 1, 63, 31, 103, 249, 861, 983, 335, 35, 4291, 16307, 43669, 68065}},
-{10893, 17, 44058, {1, 3, 1, 15, 13, 29, 51, 145, 177, 851, 39, 3531, 4477, 4243, 3301, 64293, 15741}},
-{10894, 17, 44067, {1, 1, 7, 3, 29, 45, 5, 85, 185, 191, 1007, 3085, 2177, 14911, 18319, 265, 25435}},
-{10895, 17, 44081, {1, 1, 5, 9, 9, 57, 47, 143, 217, 947, 2021, 1835, 4773, 15145, 26519, 46407, 103667}},
-{10896, 17, 44087, {1, 3, 1, 11, 1, 7, 51, 75, 207, 757, 89, 1289, 39, 15641, 9477, 28503, 47113}},
-{10897, 17, 44099, {1, 3, 1, 11, 9, 19, 21, 197, 429, 121, 813, 3447, 6091, 3167, 5401, 27791, 26499}},
-{10898, 17, 44105, {1, 1, 7, 15, 1, 15, 85, 247, 3, 111, 433, 3103, 5049, 7929, 22645, 53247, 53417}},
-{10899, 17, 44106, {1, 1, 7, 7, 27, 19, 125, 101, 269, 7, 777, 1289, 1429, 11561, 18043, 3601, 125857}},
-{10900, 17, 44114, {1, 1, 1, 13, 11, 9, 127, 231, 239, 435, 1291, 4025, 1049, 15549, 7577, 51147, 38121}},
-{10901, 17, 44116, {1, 1, 7, 3, 9, 55, 57, 137, 387, 565, 873, 1417, 5993, 4849, 1731, 51653, 105697}},
-{10902, 17, 44130, {1, 1, 7, 9, 7, 47, 115, 119, 325, 881, 1687, 1009, 7007, 12541, 6737, 28471, 7369}},
-{10903, 17, 44139, {1, 3, 1, 1, 11, 47, 25, 163, 399, 977, 1777, 727, 5575, 1311, 23843, 2199, 93229}},
-{10904, 17, 44141, {1, 1, 7, 5, 13, 19, 53, 123, 439, 585, 1977, 3387, 5305, 1463, 14307, 9519, 537}},
-{10905, 17, 44153, {1, 1, 7, 15, 1, 53, 13, 213, 323, 699, 1585, 3499, 2441, 3055, 31263, 63923, 9779}},
-{10906, 17, 44159, {1, 1, 5, 5, 21, 43, 123, 43, 475, 521, 1301, 3185, 5627, 7443, 1195, 39485, 113125}},
-{10907, 17, 44160, {1, 1, 5, 7, 9, 3, 39, 5, 237, 719, 1743, 1153, 6401, 14701, 5503, 38491, 24123}},
-{10908, 17, 44170, {1, 3, 5, 9, 17, 33, 117, 23, 409, 63, 1829, 2587, 3489, 3209, 4775, 40069, 4721}},
-{10909, 17, 44172, {1, 3, 3, 5, 21, 63, 95, 231, 25, 167, 1181, 813, 4591, 5227, 21999, 19633, 37547}},
-{10910, 17, 44187, {1, 1, 7, 11, 13, 9, 13, 147, 239, 951, 1247, 1199, 7907, 12493, 25371, 1917, 107499}},
-{10911, 17, 44190, {1, 1, 5, 15, 3, 49, 31, 103, 189, 561, 1763, 3941, 3525, 3165, 7789, 57729, 92635}},
-{10912, 17, 44193, {1, 1, 1, 5, 3, 61, 107, 163, 465, 631, 1519, 169, 4469, 8153, 11039, 247, 37657}},
-{10913, 17, 44199, {1, 3, 1, 5, 9, 37, 51, 195, 465, 975, 169, 1077, 995, 2669, 7663, 28997, 25779}},
-{10914, 17, 44213, {1, 1, 7, 13, 7, 37, 3, 117, 147, 335, 629, 4077, 5855, 2893, 5629, 55075, 83359}},
-{10915, 17, 44218, {1, 1, 5, 9, 9, 25, 53, 63, 315, 287, 1833, 1397, 2395, 5719, 6719, 18003, 101073}},
-{10916, 17, 44223, {1, 1, 7, 1, 13, 19, 13, 81, 497, 399, 413, 2411, 3915, 14037, 19735, 4587, 69655}},
-{10917, 17, 44235, {1, 3, 1, 7, 5, 61, 101, 209, 299, 729, 1359, 4013, 2057, 8439, 8113, 57417, 8951}},
-{10918, 17, 44243, {1, 3, 5, 7, 29, 21, 67, 73, 107, 359, 1655, 3729, 4403, 10467, 28103, 10261, 74651}},
-{10919, 17, 44262, {1, 1, 1, 9, 3, 39, 25, 91, 287, 497, 1743, 339, 4739, 1709, 16351, 45385, 64693}},
-{10920, 17, 44283, {1, 3, 1, 1, 7, 13, 41, 93, 49, 285, 997, 891, 4353, 4249, 11269, 36935, 71249}},
-{10921, 17, 44291, {1, 3, 3, 13, 13, 23, 97, 231, 101, 93, 1183, 201, 6795, 16287, 30707, 20845, 105873}},
-{10922, 17, 44293, {1, 1, 1, 9, 7, 57, 123, 167, 451, 245, 1887, 1839, 2967, 2387, 15075, 11877, 629}},
-{10923, 17, 44308, {1, 3, 3, 1, 13, 13, 83, 41, 219, 313, 1743, 1265, 4435, 11731, 17625, 64235, 24865}},
-{10924, 17, 44327, {1, 3, 1, 9, 13, 17, 109, 235, 387, 581, 887, 1071, 603, 10955, 5001, 8419, 20997}},
-{10925, 17, 44341, {1, 3, 1, 5, 31, 55, 1, 219, 27, 623, 1425, 1309, 5409, 9633, 3231, 15029, 22989}},
-{10926, 17, 44346, {1, 3, 3, 13, 25, 47, 23, 223, 283, 189, 1665, 3743, 387, 1807, 16919, 8511, 15933}},
-{10927, 17, 44348, {1, 1, 1, 1, 13, 11, 81, 59, 423, 1007, 317, 2761, 2617, 9715, 24853, 63585, 77083}},
-{10928, 17, 44354, {1, 3, 1, 3, 3, 11, 103, 123, 401, 467, 1159, 2725, 3275, 15513, 2281, 21617, 87211}},
-{10929, 17, 44366, {1, 1, 5, 7, 23, 17, 25, 83, 11, 901, 809, 3233, 3929, 8685, 7609, 50949, 104841}},
-{10930, 17, 44368, {1, 3, 7, 1, 15, 33, 37, 245, 275, 453, 729, 721, 1589, 5417, 29839, 57315, 67227}},
-{10931, 17, 44373, {1, 3, 7, 3, 21, 17, 51, 213, 225, 471, 1201, 931, 1229, 9503, 5507, 4057, 7737}},
-{10932, 17, 44384, {1, 3, 1, 11, 29, 55, 19, 193, 9, 151, 597, 1377, 827, 8549, 1293, 10963, 86183}},
-{10933, 17, 44390, {1, 3, 3, 15, 17, 23, 89, 47, 195, 333, 2001, 1001, 6715, 9797, 21631, 5723, 88847}},
-{10934, 17, 44393, {1, 3, 5, 9, 21, 33, 111, 101, 503, 513, 785, 1947, 1139, 7921, 13189, 34831, 80963}},
-{10935, 17, 44394, {1, 3, 3, 13, 9, 61, 35, 39, 451, 485, 661, 1993, 4705, 9477, 32541, 16553, 33167}},
-{10936, 17, 44399, {1, 3, 3, 9, 29, 37, 115, 87, 367, 325, 539, 1975, 6769, 1453, 31099, 3335, 16939}},
-{10937, 17, 44401, {1, 1, 1, 7, 15, 21, 113, 203, 97, 847, 625, 847, 1819, 1109, 14503, 25319, 100259}},
-{10938, 17, 44408, {1, 1, 5, 11, 9, 13, 65, 21, 429, 865, 513, 2183, 3785, 11817, 6283, 23041, 7969}},
-{10939, 17, 44411, {1, 1, 5, 13, 1, 41, 109, 43, 91, 211, 1477, 3543, 5217, 3133, 12503, 15523, 12917}},
-{10940, 17, 44417, {1, 3, 7, 9, 23, 53, 109, 89, 229, 939, 1211, 2771, 541, 15915, 5411, 47273, 54453}},
-{10941, 17, 44420, {1, 1, 1, 3, 3, 45, 31, 63, 99, 347, 17, 523, 441, 12325, 15673, 1887, 15289}},
-{10942, 17, 44424, {1, 1, 1, 7, 29, 61, 35, 115, 345, 1011, 5, 595, 465, 3897, 28147, 791, 98757}},
-{10943, 17, 44444, {1, 1, 5, 9, 27, 1, 21, 155, 467, 469, 1565, 1439, 5809, 851, 32503, 3025, 97231}},
-{10944, 17, 44451, {1, 1, 1, 9, 3, 17, 15, 73, 487, 1011, 63, 2605, 6647, 9385, 4527, 21993, 19783}},
-{10945, 17, 44453, {1, 1, 3, 9, 17, 17, 65, 75, 175, 897, 1317, 2593, 1495, 15835, 12025, 57457, 29577}},
-{10946, 17, 44466, {1, 1, 1, 13, 7, 1, 13, 145, 491, 427, 375, 1235, 3045, 2991, 26607, 30581, 43377}},
-{10947, 17, 44472, {1, 1, 1, 1, 31, 1, 75, 235, 345, 75, 1505, 1401, 6921, 6207, 13729, 21545, 34703}},
-{10948, 17, 44475, {1, 3, 7, 9, 31, 35, 53, 233, 85, 385, 2045, 1401, 5365, 827, 13093, 41097, 97381}},
-{10949, 17, 44486, {1, 3, 7, 15, 5, 9, 19, 125, 49, 29, 1553, 675, 3947, 4775, 8161, 12321, 55191}},
-{10950, 17, 44500, {1, 3, 3, 7, 17, 17, 27, 237, 87, 927, 275, 1965, 4993, 1429, 31613, 38403, 119319}},
-{10951, 17, 44510, {1, 3, 7, 13, 25, 61, 87, 133, 37, 725, 697, 371, 7607, 13861, 8015, 63997, 25745}},
-{10952, 17, 44531, {1, 1, 5, 3, 1, 29, 115, 53, 355, 533, 1711, 3863, 6983, 4849, 15787, 38933, 100299}},
-{10953, 17, 44534, {1, 1, 3, 5, 7, 11, 95, 21, 363, 1005, 425, 3497, 841, 8251, 11933, 47783, 122699}},
-{10954, 17, 44553, {1, 1, 1, 11, 15, 41, 23, 159, 191, 433, 919, 3151, 5311, 2061, 11277, 4947, 10549}},
-{10955, 17, 44559, {1, 1, 5, 1, 29, 57, 23, 239, 179, 821, 1825, 1745, 4357, 4041, 27517, 8557, 86969}},
-{10956, 17, 44564, {1, 3, 1, 13, 3, 45, 91, 21, 221, 203, 683, 1787, 375, 4101, 13555, 43269, 8063}},
-{10957, 17, 44580, {1, 1, 5, 15, 17, 61, 95, 95, 285, 597, 1967, 4061, 389, 3813, 6061, 50261, 56035}},
-{10958, 17, 44583, {1, 1, 7, 9, 9, 35, 103, 255, 239, 77, 145, 4089, 757, 16151, 29963, 1229, 31895}},
-{10959, 17, 44589, {1, 1, 7, 7, 29, 51, 63, 105, 55, 609, 665, 2101, 4605, 7085, 18543, 64221, 102503}},
-{10960, 17, 44592, {1, 1, 3, 9, 23, 49, 83, 71, 191, 917, 39, 1013, 4689, 2407, 1733, 31113, 31263}},
-{10961, 17, 44609, {1, 1, 5, 11, 31, 51, 17, 223, 325, 829, 541, 3561, 5319, 15397, 12479, 57199, 38611}},
-{10962, 17, 44627, {1, 3, 1, 3, 19, 57, 19, 191, 427, 905, 1111, 695, 5447, 4061, 25543, 45699, 113283}},
-{10963, 17, 44633, {1, 1, 3, 7, 5, 11, 59, 249, 375, 889, 563, 2757, 5857, 3595, 23183, 1785, 105017}},
-{10964, 17, 44643, {1, 3, 5, 7, 11, 55, 95, 167, 27, 823, 903, 2403, 1137, 3209, 6313, 61871, 129865}},
-{10965, 17, 44646, {1, 1, 3, 11, 25, 3, 89, 171, 209, 409, 1357, 3825, 5261, 10805, 13493, 3303, 129987}},
-{10966, 17, 44650, {1, 1, 5, 1, 23, 21, 3, 207, 471, 375, 1785, 2555, 1613, 16235, 1585, 48221, 10197}},
-{10967, 17, 44674, {1, 1, 1, 15, 13, 33, 89, 185, 331, 239, 1401, 789, 2687, 15193, 20911, 18935, 28751}},
-{10968, 17, 44676, {1, 1, 1, 13, 27, 19, 111, 139, 385, 531, 1069, 2343, 7405, 10305, 7049, 48215, 77591}},
-{10969, 17, 44680, {1, 3, 7, 13, 23, 9, 113, 107, 441, 265, 1617, 63, 7629, 5505, 7059, 47307, 82527}},
-{10970, 17, 44683, {1, 3, 1, 9, 27, 27, 35, 233, 189, 517, 1285, 1843, 1569, 14921, 6617, 44337, 46917}},
-{10971, 17, 44703, {1, 1, 3, 15, 7, 15, 9, 255, 109, 629, 437, 3601, 6591, 10873, 1765, 46459, 110991}},
-{10972, 17, 44704, {1, 1, 5, 15, 17, 13, 115, 97, 401, 979, 1139, 2607, 6537, 5369, 17775, 7657, 57175}},
-{10973, 17, 44716, {1, 1, 5, 15, 27, 15, 43, 95, 271, 945, 1205, 3505, 7403, 13203, 27259, 24821, 62921}},
-{10974, 17, 44733, {1, 1, 7, 15, 9, 13, 53, 177, 93, 169, 1933, 1101, 4847, 15477, 22107, 13009, 93675}},
-{10975, 17, 44748, {1, 3, 1, 3, 13, 57, 121, 229, 353, 449, 769, 1207, 557, 5673, 13129, 29383, 35925}},
-{10976, 17, 44759, {1, 3, 3, 1, 31, 33, 5, 87, 461, 873, 795, 2715, 1421, 14723, 17917, 20681, 46103}},
-{10977, 17, 44763, {1, 1, 7, 3, 29, 5, 49, 215, 341, 25, 1473, 177, 1443, 14181, 26723, 49143, 73461}},
-{10978, 17, 44781, {1, 3, 1, 5, 17, 53, 5, 27, 1, 325, 1335, 2941, 7195, 8179, 26971, 63469, 49357}},
-{10979, 17, 44782, {1, 3, 5, 3, 3, 5, 29, 241, 119, 415, 1371, 3201, 2815, 15567, 32521, 18635, 2101}},
-{10980, 17, 44789, {1, 3, 1, 3, 7, 13, 127, 157, 271, 403, 187, 3663, 4073, 12613, 1305, 31061, 48361}},
-{10981, 17, 44794, {1, 1, 3, 5, 1, 39, 41, 201, 113, 923, 621, 497, 3823, 12543, 27273, 58509, 21613}},
-{10982, 17, 44799, {1, 1, 1, 11, 5, 51, 93, 39, 345, 175, 679, 617, 3445, 8591, 4017, 5147, 88847}},
-{10983, 17, 44804, {1, 1, 7, 7, 7, 9, 63, 7, 89, 711, 487, 69, 447, 3355, 31929, 34719, 93629}},
-{10984, 17, 44813, {1, 3, 1, 3, 27, 11, 51, 11, 471, 889, 1935, 2185, 1277, 3127, 8853, 17839, 40279}},
-{10985, 17, 44822, {1, 3, 3, 15, 25, 35, 71, 213, 121, 935, 1601, 537, 5753, 8743, 15243, 59545, 60399}},
-{10986, 17, 44838, {1, 1, 3, 15, 31, 41, 51, 205, 123, 215, 305, 3777, 4103, 7275, 21603, 56853, 54575}},
-{10987, 17, 44842, {1, 3, 7, 9, 17, 19, 37, 59, 193, 303, 1079, 3627, 6503, 14649, 10283, 64469, 83677}},
-{10988, 17, 44849, {1, 3, 1, 5, 11, 3, 115, 139, 213, 307, 721, 1611, 5093, 11817, 32503, 38559, 38449}},
-{10989, 17, 44856, {1, 3, 1, 1, 17, 31, 41, 113, 135, 733, 723, 2021, 7397, 15917, 15741, 7295, 69885}},
-{10990, 17, 44870, {1, 1, 7, 11, 31, 3, 125, 77, 89, 793, 1441, 1527, 457, 9457, 13581, 62979, 125279}},
-{10991, 17, 44887, {1, 1, 1, 5, 9, 17, 19, 115, 43, 395, 183, 2091, 7021, 7555, 20165, 45165, 58925}},
-{10992, 17, 44904, {1, 1, 1, 15, 23, 37, 97, 45, 357, 201, 425, 3605, 5305, 10079, 16397, 40635, 15355}},
-{10993, 17, 44915, {1, 1, 3, 7, 3, 43, 65, 89, 51, 801, 917, 2835, 5675, 2347, 16587, 19701, 68655}},
-{10994, 17, 44917, {1, 3, 7, 13, 11, 59, 93, 155, 53, 435, 165, 3231, 429, 12757, 27033, 14081, 12625}},
-{10995, 17, 44921, {1, 3, 1, 15, 15, 33, 121, 157, 271, 295, 901, 1689, 709, 13395, 17773, 14397, 37743}},
-{10996, 17, 44928, {1, 1, 1, 3, 7, 17, 125, 113, 223, 603, 425, 3213, 2781, 2921, 15181, 18649, 93493}},
-{10997, 17, 44933, {1, 3, 3, 5, 1, 25, 3, 101, 151, 435, 1339, 1207, 7687, 12579, 29331, 4653, 67353}},
-{10998, 17, 44934, {1, 1, 7, 1, 29, 53, 101, 61, 31, 633, 1899, 3919, 1879, 3143, 25319, 45809, 77425}},
-{10999, 17, 44937, {1, 1, 5, 1, 17, 31, 79, 247, 77, 197, 1693, 313, 2183, 14343, 4511, 26009, 44943}},
-{11000, 17, 44940, {1, 1, 7, 5, 31, 29, 119, 251, 345, 867, 271, 165, 6425, 8343, 11251, 28125, 34849}},
-{11001, 17, 44951, {1, 3, 1, 1, 13, 35, 9, 103, 365, 675, 1653, 4095, 3123, 8245, 4679, 18951, 88543}},
-{11002, 17, 44961, {1, 1, 1, 1, 23, 29, 109, 157, 253, 751, 145, 2077, 4555, 7523, 30099, 37709, 97369}},
-{11003, 17, 44962, {1, 3, 3, 11, 5, 1, 51, 11, 203, 963, 1961, 351, 6697, 8137, 25933, 53505, 28531}},
-{11004, 17, 44971, {1, 1, 7, 15, 27, 1, 31, 159, 447, 501, 1873, 2845, 875, 1671, 5049, 38901, 32559}},
-{11005, 17, 44982, {1, 1, 3, 3, 29, 19, 33, 83, 71, 703, 1861, 3683, 3589, 15339, 21075, 40399, 47853}},
-{11006, 17, 44985, {1, 3, 3, 7, 5, 41, 61, 181, 319, 77, 777, 2537, 3887, 2687, 29227, 55217, 55813}},
-{11007, 17, 44996, {1, 3, 3, 1, 25, 41, 23, 31, 31, 775, 693, 891, 861, 7613, 9557, 43275, 36311}},
-{11008, 17, 44999, {1, 1, 7, 13, 11, 5, 99, 217, 81, 441, 765, 3981, 2921, 9657, 6905, 30657, 18395}},
-{11009, 17, 45014, {1, 3, 1, 11, 21, 55, 25, 209, 13, 1021, 1373, 785, 3243, 1541, 12033, 17309, 116517}},
-{11010, 17, 45029, {1, 1, 1, 7, 3, 3, 61, 113, 453, 405, 1321, 2327, 3529, 12779, 11707, 55795, 105137}},
-{11011, 17, 45033, {1, 3, 1, 13, 15, 53, 17, 189, 197, 459, 1999, 935, 7835, 9563, 31231, 47757, 80807}},
-{11012, 17, 45036, {1, 3, 5, 13, 11, 15, 91, 115, 427, 723, 1815, 3527, 5917, 4931, 28297, 12257, 5587}},
-{11013, 17, 45047, {1, 1, 5, 9, 31, 5, 77, 201, 373, 143, 581, 1199, 6807, 6059, 3133, 57069, 4895}},
-{11014, 17, 45065, {1, 3, 1, 9, 17, 13, 127, 61, 235, 991, 279, 1545, 2875, 8453, 13329, 39763, 66897}},
-{11015, 17, 45076, {1, 1, 3, 15, 31, 51, 3, 95, 221, 685, 635, 1747, 177, 9781, 4859, 45345, 37607}},
-{11016, 17, 45085, {1, 3, 5, 1, 3, 55, 63, 51, 63, 707, 883, 2985, 3699, 3881, 8159, 41775, 41411}},
-{11017, 17, 45086, {1, 1, 1, 11, 3, 41, 69, 181, 413, 33, 525, 1883, 6063, 13787, 1259, 19497, 8119}},
-{11018, 17, 45090, {1, 1, 5, 15, 13, 27, 65, 63, 117, 831, 855, 369, 1005, 9069, 16179, 32027, 6527}},
-{11019, 17, 45107, {1, 3, 7, 5, 25, 51, 63, 163, 101, 299, 1637, 641, 2077, 9195, 11181, 59783, 109481}},
-{11020, 17, 45119, {1, 3, 5, 13, 27, 13, 117, 253, 257, 919, 709, 411, 5525, 1247, 19951, 51423, 34605}},
-{11021, 17, 45121, {1, 1, 5, 5, 1, 37, 49, 125, 87, 291, 339, 3235, 1477, 9787, 19637, 22855, 103013}},
-{11022, 17, 45128, {1, 3, 7, 15, 25, 17, 77, 23, 303, 739, 1921, 1425, 6451, 9521, 6311, 38551, 123683}},
-{11023, 17, 45139, {1, 3, 1, 7, 13, 19, 33, 73, 347, 85, 1693, 3671, 713, 1191, 3285, 6815, 61833}},
-{11024, 17, 45151, {1, 1, 3, 3, 13, 53, 81, 177, 305, 967, 551, 1177, 2315, 4899, 5733, 11147, 128895}},
-{11025, 17, 45157, {1, 3, 5, 3, 17, 17, 93, 173, 417, 645, 1631, 1817, 6127, 3545, 6127, 22331, 59751}},
-{11026, 17, 45162, {1, 1, 5, 11, 7, 53, 61, 117, 133, 141, 283, 3351, 6745, 599, 7221, 50583, 9067}},
-{11027, 17, 45164, {1, 3, 7, 3, 29, 45, 71, 177, 97, 897, 589, 3319, 1821, 7207, 25715, 13043, 96695}},
-{11028, 17, 45176, {1, 3, 3, 1, 13, 39, 19, 49, 419, 905, 1063, 4023, 145, 1479, 22197, 43883, 45503}},
-{11029, 17, 45179, {1, 3, 3, 15, 9, 45, 45, 201, 61, 193, 375, 2439, 2339, 15981, 5197, 6285, 109389}},
-{11030, 17, 45198, {1, 1, 7, 13, 29, 51, 93, 223, 509, 1003, 1861, 3715, 2511, 13843, 25297, 1241, 12157}},
-{11031, 17, 45209, {1, 3, 5, 15, 19, 17, 95, 243, 251, 485, 1837, 1829, 2081, 15117, 29635, 63861, 100397}},
-{11032, 17, 45231, {1, 1, 7, 3, 1, 37, 31, 53, 483, 849, 1197, 3069, 2539, 2529, 12749, 64331, 45757}},
-{11033, 17, 45234, {1, 3, 7, 7, 1, 19, 25, 243, 335, 99, 1507, 2155, 6085, 2253, 32439, 16141, 6781}},
-{11034, 17, 45236, {1, 3, 7, 15, 9, 13, 35, 63, 371, 373, 1891, 3913, 4577, 15553, 13079, 60251, 71193}},
-{11035, 17, 45251, {1, 3, 1, 7, 15, 13, 105, 113, 409, 289, 57, 1095, 791, 15675, 21471, 42851, 29203}},
-{11036, 17, 45260, {1, 1, 1, 13, 1, 57, 65, 7, 153, 929, 1325, 229, 3841, 8967, 29889, 49427, 46853}},
-{11037, 17, 45268, {1, 1, 3, 11, 29, 1, 79, 111, 479, 931, 1619, 505, 4503, 4055, 18849, 3979, 46091}},
-{11038, 17, 45277, {1, 1, 7, 3, 31, 27, 127, 63, 219, 43, 883, 1265, 5733, 9051, 17059, 61625, 93843}},
-{11039, 17, 45299, {1, 1, 7, 7, 23, 21, 35, 211, 243, 399, 1225, 1415, 5923, 2143, 25303, 36171, 126349}},
-{11040, 17, 45301, {1, 3, 1, 3, 3, 13, 77, 205, 271, 393, 769, 2101, 4045, 6159, 3409, 44065, 102799}},
-{11041, 17, 45338, {1, 1, 5, 15, 19, 1, 67, 199, 367, 51, 495, 2051, 3195, 15239, 10525, 45319, 50489}},
-{11042, 17, 45344, {1, 1, 1, 9, 3, 19, 105, 147, 417, 399, 373, 1025, 2727, 13779, 30079, 22723, 41551}},
-{11043, 17, 45349, {1, 1, 3, 1, 9, 15, 105, 95, 267, 995, 275, 2627, 3883, 10785, 8075, 40591, 54647}},
-{11044, 17, 45364, {1, 1, 1, 5, 31, 37, 117, 185, 55, 273, 525, 445, 4221, 2081, 16017, 19859, 3297}},
-{11045, 17, 45367, {1, 3, 5, 13, 21, 13, 105, 231, 461, 831, 393, 3253, 1213, 2625, 3393, 36715, 104889}},
-{11046, 17, 45371, {1, 3, 5, 15, 1, 17, 103, 129, 257, 1003, 285, 2927, 3967, 53, 5197, 39665, 50751}},
-{11047, 17, 45373, {1, 1, 1, 13, 1, 61, 47, 255, 137, 849, 213, 301, 681, 9547, 28209, 32941, 72109}},
-{11048, 17, 45376, {1, 1, 7, 11, 31, 15, 81, 117, 327, 289, 1861, 861, 6189, 13425, 18279, 7635, 116969}},
-{11049, 17, 45381, {1, 3, 3, 3, 9, 11, 13, 181, 183, 621, 329, 2751, 3989, 6345, 20319, 52267, 79695}},
-{11050, 17, 45400, {1, 1, 7, 13, 9, 1, 5, 125, 1, 735, 691, 13, 3961, 2273, 18299, 65221, 20115}},
-{11051, 17, 45406, {1, 3, 7, 1, 7, 3, 87, 115, 241, 101, 523, 3019, 7571, 7721, 27409, 49751, 97859}},
-{11052, 17, 45416, {1, 3, 5, 11, 9, 5, 33, 59, 299, 191, 307, 2115, 2823, 10187, 10437, 34137, 93217}},
-{11053, 17, 45422, {1, 3, 3, 7, 21, 31, 5, 113, 77, 215, 177, 2029, 7241, 4465, 31489, 10165, 19035}},
-{11054, 17, 45427, {1, 3, 5, 1, 27, 63, 11, 161, 435, 941, 1593, 1765, 1519, 9111, 12787, 35961, 105263}},
-{11055, 17, 45440, {1, 1, 1, 9, 11, 57, 41, 229, 387, 617, 1991, 221, 2857, 4337, 13851, 23185, 111031}},
-{11056, 17, 45458, {1, 1, 3, 5, 21, 27, 125, 83, 129, 919, 65, 403, 2981, 10111, 17017, 24829, 12205}},
-{11057, 17, 45467, {1, 3, 3, 9, 25, 19, 109, 47, 199, 395, 1909, 2819, 5361, 6629, 7067, 18755, 17921}},
-{11058, 17, 45474, {1, 1, 3, 15, 25, 37, 111, 129, 409, 291, 1403, 2785, 3819, 10245, 24647, 64799, 64951}},
-{11059, 17, 45476, {1, 3, 5, 11, 1, 7, 105, 223, 427, 661, 1817, 1023, 145, 927, 6507, 13235, 30147}},
-{11060, 17, 45488, {1, 3, 5, 13, 7, 15, 65, 125, 121, 113, 923, 2729, 1397, 14247, 8487, 54907, 41921}},
-{11061, 17, 45494, {1, 1, 5, 1, 13, 15, 47, 111, 453, 375, 1705, 1539, 4103, 601, 7499, 33287, 123689}},
-{11062, 17, 45497, {1, 1, 5, 3, 21, 11, 87, 115, 483, 617, 1593, 2817, 6519, 16203, 361, 34415, 100829}},
-{11063, 17, 45500, {1, 3, 7, 15, 23, 25, 41, 193, 473, 517, 1195, 3627, 1089, 13391, 3653, 25637, 5643}},
-{11064, 17, 45512, {1, 3, 1, 1, 13, 57, 29, 175, 35, 107, 5, 3641, 1843, 1507, 7591, 39967, 66859}},
-{11065, 17, 45515, {1, 1, 3, 13, 1, 39, 31, 11, 493, 123, 523, 843, 133, 7971, 14131, 51927, 97943}},
-{11066, 17, 45523, {1, 1, 3, 7, 23, 45, 5, 195, 195, 683, 497, 1215, 5855, 14569, 20441, 29541, 30431}},
-{11067, 17, 45542, {1, 3, 1, 11, 31, 39, 127, 187, 187, 17, 817, 907, 4657, 8223, 13305, 36489, 28909}},
-{11068, 17, 45553, {1, 1, 7, 13, 9, 1, 59, 27, 449, 887, 39, 191, 803, 2339, 5213, 2611, 93175}},
-{11069, 17, 45559, {1, 1, 1, 1, 29, 17, 105, 13, 175, 401, 1145, 297, 6873, 889, 10301, 48993, 49959}},
-{11070, 17, 45589, {1, 3, 5, 5, 1, 57, 81, 81, 403, 719, 1887, 2597, 1069, 5219, 29767, 46905, 8025}},
-{11071, 17, 45594, {1, 1, 5, 11, 13, 37, 41, 3, 487, 895, 343, 1729, 3777, 8681, 24737, 34179, 15015}},
-{11072, 17, 45596, {1, 1, 1, 15, 9, 43, 67, 203, 71, 399, 23, 529, 2375, 15373, 21013, 17389, 93809}},
-{11073, 17, 45603, {1, 3, 7, 7, 9, 23, 81, 27, 39, 529, 631, 199, 3555, 953, 4249, 39297, 88107}},
-{11074, 17, 45605, {1, 3, 1, 3, 31, 45, 33, 63, 319, 245, 1567, 3359, 2051, 11523, 30177, 20293, 13245}},
-{11075, 17, 45610, {1, 1, 1, 13, 9, 61, 39, 127, 453, 1019, 2037, 3541, 6983, 10717, 19587, 8981, 99637}},
-{11076, 17, 45630, {1, 3, 5, 9, 15, 7, 55, 79, 93, 303, 1423, 499, 5499, 795, 14553, 16945, 46161}},
-{11077, 17, 45638, {1, 1, 7, 5, 21, 21, 27, 201, 147, 461, 363, 267, 2963, 3409, 17835, 40777, 71879}},
-{11078, 17, 45641, {1, 1, 7, 9, 23, 63, 115, 243, 103, 119, 2023, 2223, 7989, 1365, 26181, 4631, 88001}},
-{11079, 17, 45647, {1, 3, 5, 5, 27, 57, 101, 199, 461, 853, 449, 2733, 2225, 8609, 19461, 15265, 54079}},
-{11080, 17, 45655, {1, 3, 3, 15, 29, 59, 115, 105, 145, 391, 303, 901, 5481, 1491, 30441, 22331, 3841}},
-{11081, 17, 45659, {1, 1, 3, 1, 27, 45, 11, 167, 73, 181, 253, 1947, 1731, 15269, 16971, 12299, 46439}},
-{11082, 17, 45665, {1, 1, 7, 13, 11, 21, 83, 157, 75, 705, 1709, 487, 5029, 9879, 27589, 21601, 50575}},
-{11083, 17, 45689, {1, 1, 5, 3, 27, 37, 101, 163, 115, 903, 1137, 3807, 2899, 3407, 27935, 14203, 31009}},
-{11084, 17, 45695, {1, 3, 5, 9, 31, 33, 63, 69, 159, 737, 1973, 3661, 6159, 1781, 9239, 12989, 82947}},
-{11085, 17, 45702, {1, 3, 5, 9, 15, 33, 41, 89, 183, 933, 1305, 1013, 7245, 16225, 10891, 6641, 61699}},
-{11086, 17, 45708, {1, 1, 5, 3, 25, 41, 91, 183, 45, 553, 1817, 3305, 5169, 9051, 24917, 52431, 52505}},
-{11087, 17, 45726, {1, 3, 3, 9, 3, 9, 127, 59, 117, 1001, 1255, 3435, 3797, 8507, 28593, 24119, 75569}},
-{11088, 17, 45729, {1, 3, 1, 5, 17, 43, 45, 21, 461, 339, 1127, 2213, 7351, 14585, 2001, 32619, 33825}},
-{11089, 17, 45739, {1, 1, 5, 11, 3, 37, 61, 83, 101, 707, 861, 3037, 1867, 7747, 16313, 58745, 14387}},
-{11090, 17, 45744, {1, 1, 5, 3, 27, 25, 99, 17, 293, 867, 1655, 2301, 2007, 7379, 14487, 18233, 3625}},
-{11091, 17, 45747, {1, 1, 7, 13, 25, 29, 21, 133, 207, 119, 423, 1561, 6587, 1221, 27295, 48141, 125473}},
-{11092, 17, 45762, {1, 3, 3, 1, 19, 45, 39, 85, 127, 249, 157, 1307, 7343, 6309, 31073, 16909, 93223}},
-{11093, 17, 45764, {1, 1, 5, 13, 19, 43, 111, 109, 385, 847, 1071, 1009, 2783, 8471, 5719, 50459, 110507}},
-{11094, 17, 45773, {1, 1, 5, 15, 1, 45, 39, 197, 209, 839, 485, 3943, 5939, 11835, 18297, 61217, 85015}},
-{11095, 17, 45774, {1, 1, 1, 15, 5, 61, 1, 195, 415, 355, 1593, 151, 8143, 3527, 11633, 44337, 99749}},
-{11096, 17, 45781, {1, 1, 5, 13, 11, 11, 117, 109, 91, 663, 1351, 2361, 1409, 9317, 31133, 17577, 123919}},
-{11097, 17, 45785, {1, 3, 3, 9, 3, 5, 115, 173, 459, 937, 1581, 781, 1069, 573, 24025, 30721, 116837}},
-{11098, 17, 45792, {1, 1, 1, 5, 21, 37, 47, 51, 21, 169, 119, 3285, 2543, 14023, 29179, 13407, 130491}},
-{11099, 17, 45801, {1, 3, 5, 5, 25, 27, 41, 147, 485, 79, 737, 699, 6763, 16347, 9265, 52129, 41431}},
-{11100, 17, 45802, {1, 1, 1, 3, 5, 33, 115, 187, 311, 717, 1897, 2215, 2639, 4167, 1429, 26359, 52703}},
-{11101, 17, 45812, {1, 3, 5, 5, 13, 51, 103, 5, 47, 683, 319, 2969, 7701, 11031, 9257, 16725, 80825}},
-{11102, 17, 45816, {1, 3, 1, 11, 31, 47, 17, 205, 11, 411, 523, 4053, 6743, 3095, 3219, 63163, 84547}},
-{11103, 17, 45829, {1, 1, 7, 15, 9, 55, 109, 225, 273, 595, 1697, 2059, 21, 11319, 23277, 60613, 4539}},
-{11104, 17, 45833, {1, 1, 5, 13, 3, 59, 49, 239, 509, 847, 975, 3361, 5443, 1941, 29277, 56379, 38997}},
-{11105, 17, 45847, {1, 3, 1, 7, 15, 5, 49, 19, 235, 437, 1309, 827, 4123, 5839, 22409, 42535, 98041}},
-{11106, 17, 45851, {1, 1, 5, 15, 9, 33, 57, 153, 165, 215, 177, 1271, 1861, 15489, 4183, 43701, 114169}},
-{11107, 17, 45854, {1, 3, 5, 5, 13, 3, 119, 89, 17, 421, 1205, 835, 4917, 6113, 28991, 26839, 114871}},
-{11108, 17, 45863, {1, 3, 5, 1, 7, 49, 49, 159, 205, 601, 1939, 4063, 5975, 11747, 10329, 21103, 16779}},
-{11109, 17, 45870, {1, 1, 5, 15, 13, 33, 89, 21, 113, 639, 891, 989, 829, 1435, 11475, 42711, 67049}},
-{11110, 17, 45901, {1, 1, 5, 5, 9, 59, 57, 105, 385, 733, 1175, 329, 6809, 7175, 27267, 9941, 14203}},
-{11111, 17, 45910, {1, 3, 1, 13, 21, 53, 83, 139, 287, 659, 1991, 3225, 4153, 4325, 16803, 27719, 86263}},
-{11112, 17, 45920, {1, 3, 5, 13, 27, 21, 111, 105, 29, 573, 405, 2781, 1737, 12057, 25263, 16903, 45389}},
-{11113, 17, 45932, {1, 1, 5, 5, 23, 23, 61, 27, 335, 279, 937, 2509, 4751, 2993, 28069, 30187, 3595}},
-{11114, 17, 45938, {1, 1, 5, 7, 29, 37, 117, 71, 221, 875, 1987, 2329, 5953, 15901, 29813, 17419, 4745}},
-{11115, 17, 45940, {1, 3, 3, 13, 21, 51, 77, 85, 53, 573, 1129, 3415, 2283, 5221, 29991, 46091, 65843}},
-{11116, 17, 45943, {1, 1, 1, 3, 17, 51, 89, 211, 463, 743, 1189, 4083, 1437, 5219, 8373, 15559, 18557}},
-{11117, 17, 45949, {1, 1, 5, 3, 29, 27, 1, 207, 285, 739, 505, 1587, 6565, 14195, 4995, 39453, 61023}},
-{11118, 17, 45953, {1, 3, 3, 15, 7, 57, 19, 45, 39, 881, 1207, 2829, 3265, 2637, 7843, 62889, 53289}},
-{11119, 17, 45963, {1, 1, 1, 11, 31, 21, 73, 245, 87, 457, 1523, 2397, 1157, 8237, 26195, 23149, 106523}},
-{11120, 17, 45971, {1, 3, 5, 13, 3, 55, 3, 179, 107, 85, 639, 2711, 6359, 1599, 2325, 59573, 111941}},
-{11121, 17, 45989, {1, 1, 1, 13, 17, 61, 45, 253, 45, 149, 1251, 139, 7113, 6503, 27675, 37301, 21713}},
-{11122, 17, 45999, {1, 3, 5, 9, 31, 31, 67, 79, 355, 225, 1187, 761, 4927, 5481, 9139, 13399, 35653}},
-{11123, 17, 46001, {1, 1, 5, 3, 7, 3, 95, 119, 161, 529, 1443, 1099, 609, 3919, 10935, 37779, 92993}},
-{11124, 17, 46008, {1, 1, 7, 9, 13, 21, 13, 7, 165, 173, 989, 2315, 2305, 13115, 6933, 56233, 112113}},
-{11125, 17, 46022, {1, 1, 7, 3, 9, 11, 25, 45, 493, 119, 839, 3907, 2273, 14113, 29453, 55181, 667}},
-{11126, 17, 46026, {1, 3, 5, 15, 25, 33, 15, 23, 245, 517, 1883, 2865, 1483, 7043, 32615, 12261, 49297}},
-{11127, 17, 46034, {1, 3, 7, 9, 31, 35, 89, 103, 245, 441, 1709, 1321, 3743, 3767, 23885, 43587, 18017}},
-{11128, 17, 46040, {1, 3, 7, 5, 23, 43, 103, 7, 47, 187, 1257, 3517, 591, 16263, 12047, 16699, 81633}},
-{11129, 17, 46043, {1, 1, 5, 15, 5, 5, 79, 11, 327, 719, 37, 2913, 6107, 3463, 25901, 6125, 100647}},
-{11130, 17, 46045, {1, 1, 1, 11, 13, 29, 83, 251, 41, 125, 1137, 2627, 4643, 29, 24631, 51435, 98643}},
-{11131, 17, 46061, {1, 1, 7, 3, 27, 3, 69, 245, 365, 599, 1575, 2969, 3441, 12327, 18951, 56167, 13861}},
-{11132, 17, 46062, {1, 3, 3, 11, 5, 47, 103, 233, 351, 821, 867, 3199, 6133, 4627, 22663, 14775, 83205}},
-{11133, 17, 46076, {1, 3, 1, 13, 9, 35, 27, 251, 281, 727, 873, 3713, 5247, 8407, 17739, 57207, 126201}},
-{11134, 17, 46084, {1, 1, 7, 11, 11, 35, 53, 115, 93, 663, 625, 565, 3137, 7869, 18845, 49155, 83395}},
-{11135, 17, 46094, {1, 3, 3, 5, 21, 13, 99, 151, 319, 9, 1363, 1489, 2545, 1963, 1271, 24815, 43355}},
-{11136, 17, 46102, {1, 3, 5, 9, 15, 51, 109, 85, 67, 131, 1947, 181, 7331, 15163, 2255, 33449, 78107}},
-{11137, 17, 46118, {1, 1, 7, 9, 27, 61, 1, 163, 309, 739, 453, 1837, 2093, 16021, 8485, 19755, 61335}},
-{11138, 17, 46149, {1, 3, 5, 7, 3, 13, 11, 195, 91, 143, 203, 2785, 7319, 7153, 19265, 11597, 63365}},
-{11139, 17, 46154, {1, 3, 1, 9, 29, 1, 123, 247, 253, 757, 191, 1699, 6625, 1785, 29199, 29409, 32577}},
-{11140, 17, 46167, {1, 3, 5, 11, 23, 21, 31, 35, 383, 587, 65, 1695, 4045, 12305, 12437, 5919, 51465}},
-{11141, 17, 46173, {1, 1, 5, 9, 11, 13, 123, 171, 499, 877, 1785, 561, 2547, 1797, 27679, 56305, 93223}},
-{11142, 17, 46177, {1, 3, 1, 3, 25, 41, 63, 243, 219, 533, 753, 1903, 3257, 11901, 4777, 28629, 111141}},
-{11143, 17, 46192, {1, 3, 3, 5, 31, 47, 1, 253, 283, 995, 1787, 1767, 6599, 11913, 21515, 39259, 117727}},
-{11144, 17, 46197, {1, 1, 7, 7, 31, 35, 39, 255, 463, 763, 881, 2583, 347, 14343, 22761, 45821, 119155}},
-{11145, 17, 46201, {1, 3, 5, 9, 5, 37, 43, 55, 423, 525, 157, 3593, 2831, 11539, 15675, 11695, 100609}},
-{11146, 17, 46214, {1, 3, 3, 5, 11, 9, 27, 57, 409, 201, 1029, 2461, 5823, 2593, 32031, 4203, 55327}},
-{11147, 17, 46217, {1, 1, 7, 15, 15, 25, 69, 83, 309, 687, 1607, 819, 7381, 3697, 5289, 33153, 48157}},
-{11148, 17, 46223, {1, 1, 5, 5, 31, 57, 41, 195, 201, 59, 2045, 2213, 6695, 3839, 17331, 4981, 26803}},
-{11149, 17, 46226, {1, 1, 1, 11, 7, 53, 109, 169, 387, 181, 391, 19, 4159, 299, 29059, 27781, 110193}},
-{11150, 17, 46228, {1, 3, 7, 15, 5, 31, 95, 155, 47, 601, 1463, 1799, 8027, 3003, 18067, 24589, 108171}},
-{11151, 17, 46237, {1, 3, 3, 7, 11, 61, 21, 121, 117, 149, 1037, 3829, 3581, 15223, 17051, 34539, 37263}},
-{11152, 17, 46241, {1, 3, 3, 3, 15, 15, 115, 91, 443, 309, 1073, 2053, 789, 7415, 26253, 62657, 49729}},
-{11153, 17, 46251, {1, 3, 5, 5, 31, 19, 23, 221, 19, 105, 1105, 2025, 4209, 7531, 30191, 40777, 46069}},
-{11154, 17, 46259, {1, 1, 1, 7, 29, 45, 29, 215, 33, 21, 1147, 1725, 3711, 2759, 12731, 57031, 42361}},
-{11155, 17, 46262, {1, 1, 5, 15, 13, 59, 111, 169, 317, 841, 1387, 3513, 3137, 8265, 31789, 26963, 126219}},
-{11156, 17, 46266, {1, 1, 3, 1, 23, 21, 13, 113, 71, 177, 345, 3149, 1461, 12945, 3971, 59759, 61839}},
-{11157, 17, 46294, {1, 3, 5, 13, 9, 19, 103, 17, 95, 617, 1477, 263, 4259, 12899, 24351, 47431, 11583}},
-{11158, 17, 46300, {1, 3, 5, 11, 13, 11, 7, 61, 13, 63, 1687, 631, 381, 5899, 10225, 19657, 37087}},
-{11159, 17, 46303, {1, 3, 5, 3, 7, 53, 11, 193, 103, 427, 1097, 299, 2905, 5019, 31803, 28931, 47495}},
-{11160, 17, 46309, {1, 3, 3, 11, 21, 31, 125, 249, 233, 941, 975, 2287, 7837, 6481, 11021, 52829, 63023}},
-{11161, 17, 46321, {1, 1, 7, 15, 13, 17, 33, 85, 503, 11, 689, 637, 4063, 12223, 1835, 17161, 35213}},
-{11162, 17, 46331, {1, 3, 5, 13, 25, 37, 21, 135, 377, 623, 895, 2547, 2757, 9055, 17337, 65457, 24737}},
-{11163, 17, 46339, {1, 1, 1, 15, 25, 11, 17, 95, 65, 271, 1791, 841, 1441, 11177, 10087, 63963, 71481}},
-{11164, 17, 46342, {1, 3, 5, 11, 31, 1, 37, 107, 109, 459, 1185, 2155, 271, 11775, 23243, 53517, 103669}},
-{11165, 17, 46354, {1, 3, 1, 9, 1, 49, 23, 141, 169, 475, 469, 2271, 1379, 13139, 1765, 63625, 14143}},
-{11166, 17, 46370, {1, 1, 1, 9, 13, 7, 23, 219, 381, 105, 743, 1745, 2999, 661, 7245, 39653, 99913}},
-{11167, 17, 46372, {1, 3, 1, 11, 7, 35, 9, 215, 41, 537, 1569, 1803, 3613, 667, 15089, 39485, 85457}},
-{11168, 17, 46379, {1, 1, 1, 15, 9, 49, 75, 235, 119, 97, 273, 209, 2707, 2071, 21943, 60249, 57737}},
-{11169, 17, 46382, {1, 1, 5, 15, 31, 19, 33, 49, 279, 461, 143, 3001, 3539, 1015, 27597, 35389, 36483}},
-{11170, 17, 46393, {1, 3, 7, 1, 23, 51, 123, 247, 485, 343, 1365, 593, 6465, 12305, 29375, 30641, 43165}},
-{11171, 17, 46402, {1, 1, 7, 13, 15, 11, 125, 51, 235, 717, 1427, 3203, 1711, 12607, 8805, 5773, 27467}},
-{11172, 17, 46407, {1, 3, 5, 5, 5, 13, 51, 181, 133, 977, 469, 2513, 6819, 12985, 8917, 47317, 47557}},
-{11173, 17, 46416, {1, 1, 5, 7, 3, 7, 71, 17, 345, 921, 1621, 2801, 5825, 827, 17711, 33701, 113503}},
-{11174, 17, 46425, {1, 3, 1, 1, 17, 7, 99, 83, 73, 349, 567, 713, 5639, 4969, 11549, 35317, 28995}},
-{11175, 17, 46437, {1, 3, 3, 9, 11, 53, 123, 227, 391, 775, 1013, 3971, 6183, 14453, 6403, 57063, 7123}},
-{11176, 17, 46444, {1, 1, 1, 15, 27, 13, 51, 147, 151, 535, 2017, 3019, 6791, 3931, 12529, 30855, 33243}},
-{11177, 17, 46447, {1, 3, 1, 1, 27, 43, 103, 85, 135, 207, 621, 251, 3723, 10893, 29533, 31023, 11043}},
-{11178, 17, 46449, {1, 3, 7, 5, 7, 39, 55, 133, 141, 63, 237, 3299, 861, 15123, 11859, 13271, 32893}},
-{11179, 17, 46456, {1, 3, 7, 9, 23, 17, 73, 197, 113, 725, 137, 2835, 2877, 6913, 22949, 56071, 67597}},
-{11180, 17, 46462, {1, 3, 7, 7, 15, 3, 15, 253, 51, 443, 15, 2549, 7833, 4713, 29211, 22339, 6009}},
-{11181, 17, 46472, {1, 3, 5, 15, 19, 55, 35, 59, 281, 995, 1113, 605, 2345, 10009, 14629, 11757, 53241}},
-{11182, 17, 46475, {1, 1, 1, 11, 3, 31, 11, 193, 437, 1003, 873, 909, 6513, 2045, 10495, 17387, 25461}},
-{11183, 17, 46486, {1, 1, 3, 5, 21, 61, 47, 177, 379, 773, 951, 419, 4455, 10171, 17403, 19045, 87327}},
-{11184, 17, 46490, {1, 3, 3, 11, 31, 41, 69, 229, 207, 299, 1743, 1417, 4785, 1327, 26967, 43077, 124319}},
-{11185, 17, 46495, {1, 3, 7, 15, 19, 37, 65, 219, 33, 691, 205, 1577, 4775, 8427, 28315, 53559, 100789}},
-{11186, 17, 46501, {1, 3, 5, 11, 5, 39, 55, 147, 139, 871, 1563, 3661, 4791, 423, 30007, 1589, 20255}},
-{11187, 17, 46514, {1, 1, 3, 15, 5, 61, 89, 83, 261, 519, 1367, 2019, 3799, 8237, 9011, 28995, 1587}},
-{11188, 17, 46526, {1, 1, 7, 15, 17, 55, 49, 41, 353, 507, 1565, 3365, 7947, 10391, 1323, 61591, 126305}},
-{11189, 17, 46528, {1, 3, 3, 5, 13, 19, 49, 195, 355, 915, 1867, 3513, 1239, 4809, 16925, 22947, 92641}},
-{11190, 17, 46538, {1, 1, 7, 3, 31, 51, 45, 241, 55, 195, 1233, 3675, 8077, 4981, 17679, 53025, 77927}},
-{11191, 17, 46551, {1, 3, 5, 11, 23, 5, 93, 49, 277, 979, 1093, 3031, 6131, 8085, 19121, 45305, 6705}},
-{11192, 17, 46552, {1, 1, 7, 13, 29, 25, 83, 105, 469, 729, 1495, 2607, 2681, 13959, 101, 1913, 2671}},
-{11193, 17, 46564, {1, 1, 1, 15, 7, 19, 63, 105, 253, 807, 1889, 2433, 1591, 16267, 11997, 18939, 113313}},
-{11194, 17, 46579, {1, 1, 5, 3, 13, 23, 29, 227, 337, 115, 783, 475, 6949, 9485, 1797, 18713, 123981}},
-{11195, 17, 46586, {1, 3, 3, 9, 21, 43, 115, 225, 147, 753, 919, 1157, 2901, 14813, 30035, 52553, 30225}},
-{11196, 17, 46602, {1, 1, 3, 15, 23, 19, 65, 83, 457, 965, 579, 2133, 291, 2033, 7533, 52995, 92243}},
-{11197, 17, 46615, {1, 1, 1, 5, 11, 3, 23, 245, 255, 373, 1119, 3695, 6449, 13497, 817, 32215, 103599}},
-{11198, 17, 46616, {1, 3, 1, 5, 5, 19, 57, 53, 145, 441, 1253, 929, 1299, 11491, 29457, 11245, 55717}},
-{11199, 17, 46621, {1, 1, 7, 13, 9, 13, 73, 85, 127, 29, 629, 409, 2487, 13079, 3767, 27985, 110139}},
-{11200, 17, 46635, {1, 1, 5, 11, 29, 39, 27, 9, 487, 623, 757, 2879, 669, 12521, 23471, 47933, 41721}},
-{11201, 17, 46643, {1, 1, 7, 15, 21, 9, 59, 39, 325, 787, 1347, 3039, 7333, 9793, 19337, 41285, 48339}},
-{11202, 17, 46645, {1, 3, 3, 11, 11, 21, 127, 45, 173, 981, 483, 3707, 3651, 10545, 16865, 62105, 114847}},
-{11203, 17, 46649, {1, 3, 5, 11, 11, 49, 89, 179, 393, 455, 1775, 1903, 8173, 12589, 17281, 57687, 56153}},
-{11204, 17, 46667, {1, 3, 1, 3, 7, 7, 59, 223, 255, 559, 375, 2427, 6921, 3709, 24767, 16213, 60373}},
-{11205, 17, 46670, {1, 1, 7, 15, 3, 31, 37, 129, 307, 1023, 1807, 519, 6779, 8997, 15383, 4391, 61161}},
-{11206, 17, 46672, {1, 1, 1, 1, 9, 25, 53, 27, 263, 459, 1015, 417, 4195, 10931, 20507, 19299, 82371}},
-{11207, 17, 46678, {1, 1, 3, 1, 7, 7, 49, 221, 47, 7, 1747, 1533, 3089, 14369, 32609, 64157, 78139}},
-{11208, 17, 46681, {1, 3, 7, 5, 5, 13, 101, 231, 227, 19, 1359, 3017, 1405, 3715, 3541, 933, 1117}},
-{11209, 17, 46684, {1, 1, 7, 15, 5, 63, 59, 253, 269, 781, 1639, 2247, 1041, 667, 7055, 21221, 84447}},
-{11210, 17, 46687, {1, 1, 7, 3, 9, 13, 115, 247, 215, 173, 457, 1125, 5613, 13171, 17847, 26323, 68461}},
-{11211, 17, 46705, {1, 3, 5, 9, 15, 19, 95, 213, 425, 567, 1625, 1659, 6961, 10569, 20985, 17255, 89919}},
-{11212, 17, 46708, {1, 3, 5, 5, 3, 11, 107, 123, 265, 743, 499, 1885, 6079, 7791, 24953, 30925, 112517}},
-{11213, 17, 46721, {1, 1, 5, 15, 29, 27, 103, 195, 119, 873, 1751, 2091, 6623, 7583, 20413, 52367, 16831}},
-{11214, 17, 46724, {1, 1, 7, 7, 21, 15, 111, 197, 89, 107, 1317, 2107, 1951, 189, 31663, 63007, 21405}},
-{11215, 17, 46739, {1, 3, 1, 13, 27, 15, 93, 251, 209, 93, 1419, 3785, 1899, 3143, 3205, 16309, 121455}},
-{11216, 17, 46757, {1, 1, 7, 7, 17, 43, 23, 251, 425, 591, 1101, 1317, 6369, 14209, 10257, 33813, 59557}},
-{11217, 17, 46762, {1, 1, 7, 3, 5, 41, 65, 59, 327, 369, 1867, 1045, 4953, 3155, 25679, 8545, 22753}},
-{11218, 17, 46764, {1, 1, 5, 3, 5, 25, 117, 97, 369, 721, 1459, 2501, 4899, 5299, 3859, 2509, 127723}},
-{11219, 17, 46776, {1, 3, 3, 1, 27, 13, 65, 185, 255, 543, 2013, 2027, 1131, 4067, 1327, 44639, 53275}},
-{11220, 17, 46784, {1, 1, 7, 3, 11, 15, 53, 67, 265, 477, 971, 3201, 51, 10599, 23691, 10493, 130347}},
-{11221, 17, 46790, {1, 3, 7, 7, 19, 35, 47, 61, 375, 547, 1867, 1147, 7775, 12757, 15101, 63243, 89817}},
-{11222, 17, 46796, {1, 1, 5, 3, 5, 21, 57, 59, 145, 901, 835, 1093, 6487, 12727, 20585, 6309, 67803}},
-{11223, 17, 46799, {1, 1, 1, 11, 13, 31, 75, 171, 189, 741, 1923, 3503, 4887, 15423, 2499, 39125, 4125}},
-{11224, 17, 46802, {1, 3, 7, 1, 29, 31, 103, 207, 383, 631, 1017, 1693, 6251, 9429, 17491, 60959, 68131}},
-{11225, 17, 46813, {1, 1, 1, 1, 19, 45, 127, 105, 451, 287, 657, 3521, 2021, 15793, 8993, 34837, 65441}},
-{11226, 17, 46814, {1, 1, 7, 9, 17, 15, 13, 189, 255, 753, 1779, 3047, 1179, 13201, 28249, 5909, 35775}},
-{11227, 17, 46824, {1, 3, 3, 3, 5, 11, 125, 207, 375, 375, 135, 2939, 1141, 12211, 727, 16137, 52253}},
-{11228, 17, 46832, {1, 3, 7, 9, 29, 3, 83, 221, 281, 299, 667, 3435, 589, 8039, 7991, 24289, 13079}},
-{11229, 17, 46841, {1, 3, 5, 13, 9, 11, 11, 99, 337, 155, 233, 2497, 3385, 15045, 5783, 40915, 19201}},
-{11230, 17, 46856, {1, 1, 7, 5, 5, 23, 25, 223, 341, 149, 505, 893, 4933, 14899, 29899, 207, 125359}},
-{11231, 17, 46862, {1, 3, 3, 15, 3, 5, 43, 165, 21, 993, 1091, 3849, 6005, 1905, 7199, 13495, 76915}},
-{11232, 17, 46864, {1, 1, 1, 15, 1, 19, 55, 217, 179, 431, 935, 2219, 8135, 15071, 17437, 43271, 115963}},
-{11233, 17, 46869, {1, 1, 7, 15, 7, 61, 45, 157, 441, 107, 1955, 2877, 5285, 12157, 21783, 60999, 102949}},
-{11234, 17, 46874, {1, 1, 1, 3, 9, 29, 41, 75, 81, 73, 1859, 2923, 3009, 10847, 30257, 44527, 21933}},
-{11235, 17, 46895, {1, 1, 3, 3, 29, 29, 103, 3, 401, 197, 237, 3727, 7919, 13669, 26869, 64987, 1581}},
-{11236, 17, 46900, {1, 1, 5, 13, 13, 47, 99, 209, 45, 745, 1239, 663, 5535, 3777, 10479, 15327, 1441}},
-{11237, 17, 46903, {1, 3, 1, 9, 1, 49, 31, 231, 15, 1001, 773, 2113, 1957, 15271, 25355, 7461, 33089}},
-{11238, 17, 46927, {1, 1, 1, 5, 13, 31, 123, 123, 439, 373, 1817, 2555, 7905, 3151, 2311, 62083, 45535}},
-{11239, 17, 46946, {1, 3, 1, 3, 31, 37, 83, 117, 177, 483, 1285, 1725, 821, 2115, 12893, 54301, 36491}},
-{11240, 17, 46948, {1, 3, 3, 3, 9, 13, 87, 7, 467, 287, 1173, 2739, 3293, 883, 9123, 30799, 110221}},
-{11241, 17, 46955, {1, 3, 1, 15, 3, 5, 119, 235, 393, 789, 67, 1193, 1613, 8607, 17371, 16723, 103747}},
-{11242, 17, 46965, {1, 3, 1, 13, 13, 47, 61, 51, 447, 1, 1221, 1619, 3785, 5851, 10557, 51181, 6535}},
-{11243, 17, 46972, {1, 3, 5, 11, 1, 1, 85, 119, 195, 177, 805, 1161, 4851, 15765, 24405, 41757, 110081}},
-{11244, 17, 46976, {1, 1, 7, 1, 17, 21, 89, 13, 59, 169, 1847, 2401, 6243, 2841, 6153, 16039, 47407}},
-{11245, 17, 46985, {1, 1, 3, 15, 21, 53, 103, 187, 143, 897, 65, 3677, 213, 4027, 22365, 53703, 82951}},
-{11246, 17, 46999, {1, 3, 5, 5, 25, 5, 39, 49, 55, 71, 825, 2123, 2345, 5683, 18027, 29897, 53023}},
-{11247, 17, 47003, {1, 1, 3, 5, 13, 55, 27, 77, 327, 429, 1219, 2103, 7095, 13461, 31027, 15383, 98485}},
-{11248, 17, 47006, {1, 3, 1, 3, 9, 41, 33, 241, 487, 229, 1743, 951, 2319, 15595, 3213, 5959, 90721}},
-{11249, 17, 47016, {1, 1, 7, 1, 29, 45, 45, 163, 123, 227, 305, 1577, 5465, 5639, 14507, 65155, 71425}},
-{11250, 17, 47030, {1, 1, 5, 1, 3, 5, 33, 15, 203, 141, 465, 3509, 6653, 14193, 7073, 22525, 22951}},
-{11251, 17, 47034, {1, 1, 7, 3, 27, 39, 3, 27, 75, 821, 1329, 3655, 4715, 7659, 31957, 60219, 79123}},
-{11252, 17, 47053, {1, 3, 5, 13, 29, 45, 111, 19, 207, 387, 87, 3731, 7427, 13351, 9497, 34285, 25623}},
-{11253, 17, 47056, {1, 1, 3, 11, 19, 39, 79, 219, 97, 125, 947, 1397, 3645, 1021, 9403, 38695, 54985}},
-{11254, 17, 47059, {1, 3, 3, 7, 3, 3, 45, 93, 65, 289, 1843, 1599, 897, 16159, 23485, 24699, 43123}},
-{11255, 17, 47072, {1, 3, 5, 3, 15, 1, 81, 219, 299, 429, 1115, 1763, 6381, 869, 7817, 143, 23583}},
-{11256, 17, 47077, {1, 1, 3, 5, 1, 35, 95, 147, 425, 1011, 1039, 2875, 3089, 3685, 9995, 13279, 60923}},
-{11257, 17, 47099, {1, 1, 5, 7, 5, 59, 105, 241, 151, 307, 735, 1541, 3115, 12331, 19535, 56965, 127015}},
-{11258, 17, 47105, {1, 3, 5, 7, 5, 33, 83, 179, 65, 397, 787, 3425, 1305, 10713, 6973, 9007, 112081}},
-{11259, 17, 47108, {1, 3, 7, 13, 29, 11, 37, 31, 271, 501, 897, 1383, 5333, 13627, 22091, 38421, 94575}},
-{11260, 17, 47112, {1, 3, 1, 1, 9, 61, 87, 115, 13, 79, 391, 2385, 7157, 3369, 26035, 883, 34705}},
-{11261, 17, 47115, {1, 1, 3, 9, 21, 29, 15, 165, 53, 719, 1509, 1295, 4437, 8229, 17961, 55297, 62635}},
-{11262, 17, 47117, {1, 1, 7, 5, 27, 21, 23, 141, 341, 423, 9, 2693, 5555, 5797, 13179, 1107, 33489}},
-{11263, 17, 47120, {1, 3, 1, 13, 27, 33, 101, 29, 379, 119, 1259, 861, 6843, 69, 3253, 61977, 80061}},
-{11264, 17, 47129, {1, 1, 3, 11, 1, 37, 35, 43, 105, 655, 221, 873, 91, 9095, 8999, 44033, 24807}},
-{11265, 17, 47135, {1, 3, 3, 7, 29, 15, 23, 227, 399, 305, 2007, 747, 2717, 14767, 6515, 40617, 7873}},
-{11266, 17, 47151, {1, 1, 5, 15, 21, 43, 39, 7, 261, 421, 505, 1433, 1155, 5621, 2337, 54027, 54039}},
-{11267, 17, 47154, {1, 1, 1, 9, 15, 39, 49, 185, 503, 895, 1321, 375, 4245, 4929, 9637, 50561, 65733}},
-{11268, 17, 47156, {1, 1, 5, 15, 7, 29, 27, 155, 423, 631, 1295, 973, 4227, 2637, 8479, 29527, 70505}},
-{11269, 17, 47166, {1, 3, 1, 3, 31, 33, 13, 67, 195, 335, 1577, 3715, 559, 7251, 7215, 46443, 125359}},
-{11270, 17, 47171, {1, 3, 1, 9, 17, 37, 15, 119, 79, 851, 911, 3549, 99, 9221, 29897, 63489, 34937}},
-{11271, 17, 47195, {1, 3, 5, 9, 31, 11, 125, 1, 265, 467, 835, 2997, 2401, 9615, 19397, 50947, 29963}},
-{11272, 17, 47204, {1, 1, 5, 3, 11, 21, 63, 15, 471, 763, 1963, 2815, 4419, 11457, 7151, 27009, 124847}},
-{11273, 17, 47213, {1, 1, 7, 3, 19, 9, 97, 59, 375, 109, 519, 305, 2787, 3001, 14199, 27415, 35403}},
-{11274, 17, 47222, {1, 1, 1, 3, 13, 47, 3, 93, 307, 979, 419, 2817, 3741, 305, 1813, 34549, 116959}},
-{11275, 17, 47228, {1, 3, 5, 13, 13, 19, 35, 231, 493, 973, 895, 1583, 1843, 9057, 27705, 32333, 130347}},
-{11276, 17, 47241, {1, 1, 1, 13, 31, 35, 81, 11, 363, 229, 1865, 2849, 7805, 877, 3965, 45337, 33239}},
-{11277, 17, 47242, {1, 3, 5, 1, 15, 3, 125, 93, 191, 405, 1359, 929, 3085, 7907, 7777, 7815, 103717}},
-{11278, 17, 47247, {1, 1, 3, 7, 15, 33, 61, 235, 283, 141, 817, 1611, 665, 13113, 4197, 45831, 44505}},
-{11279, 17, 47249, {1, 1, 5, 5, 25, 3, 63, 159, 223, 531, 1147, 2323, 2715, 10319, 32203, 23943, 95407}},
-{11280, 17, 47250, {1, 3, 3, 3, 3, 33, 37, 99, 317, 811, 515, 339, 6527, 11149, 13071, 7177, 1549}},
-{11281, 17, 47261, {1, 3, 1, 11, 31, 53, 9, 17, 297, 259, 1235, 53, 7065, 1721, 8191, 21663, 13393}},
-{11282, 17, 47266, {1, 3, 7, 7, 29, 41, 127, 179, 113, 191, 783, 861, 6509, 5199, 3369, 18327, 30647}},
-{11283, 17, 47268, {1, 3, 1, 7, 23, 41, 49, 155, 135, 513, 1127, 1443, 8081, 2553, 10389, 35459, 122513}},
-{11284, 17, 47278, {1, 1, 7, 3, 25, 3, 117, 125, 283, 165, 1409, 1587, 7915, 12899, 12239, 48161, 7385}},
-{11285, 17, 47286, {1, 3, 7, 3, 23, 19, 29, 47, 7, 723, 455, 4013, 2739, 12303, 29883, 51485, 1571}},
-{11286, 17, 47312, {1, 1, 1, 11, 1, 31, 111, 199, 207, 209, 1163, 2865, 5335, 2647, 9125, 6737, 99881}},
-{11287, 17, 47315, {1, 3, 1, 11, 31, 19, 59, 153, 65, 133, 1399, 2709, 905, 3257, 13603, 46299, 15139}},
-{11288, 17, 47321, {1, 3, 1, 1, 23, 19, 123, 115, 59, 667, 333, 2461, 1843, 16049, 12353, 17297, 107779}},
-{11289, 17, 47322, {1, 1, 5, 1, 5, 29, 91, 241, 97, 557, 1701, 2441, 2995, 13103, 9261, 55833, 843}},
-{11290, 17, 47324, {1, 1, 1, 5, 15, 19, 23, 189, 69, 91, 427, 3149, 5199, 13073, 32273, 41503, 98749}},
-{11291, 17, 47331, {1, 3, 5, 11, 19, 3, 71, 125, 307, 241, 861, 681, 5657, 5189, 7555, 2037, 72921}},
-{11292, 17, 47338, {1, 1, 5, 5, 29, 61, 93, 61, 421, 685, 883, 1559, 5875, 10561, 11761, 18879, 31577}},
-{11293, 17, 47366, {1, 3, 7, 15, 9, 29, 41, 241, 365, 941, 1087, 3743, 6781, 9467, 1409, 20605, 2361}},
-{11294, 17, 47372, {1, 1, 5, 13, 25, 29, 7, 21, 41, 621, 1751, 3731, 2667, 8613, 20999, 3851, 39677}},
-{11295, 17, 47375, {1, 1, 7, 5, 17, 23, 25, 43, 401, 749, 975, 91, 5277, 2711, 19847, 41419, 11851}},
-{11296, 17, 47378, {1, 1, 7, 9, 13, 37, 113, 89, 435, 749, 1553, 1853, 7709, 5449, 25055, 45207, 2269}},
-{11297, 17, 47387, {1, 3, 1, 11, 3, 59, 79, 13, 35, 901, 165, 907, 7579, 12739, 24679, 54163, 61059}},
-{11298, 17, 47389, {1, 1, 5, 7, 9, 47, 101, 61, 25, 461, 1737, 2825, 4439, 5363, 28433, 61979, 120401}},
-{11299, 17, 47390, {1, 3, 3, 3, 1, 55, 103, 1, 449, 473, 375, 2609, 4933, 3411, 19663, 6067, 61129}},
-{11300, 17, 47396, {1, 1, 3, 9, 27, 29, 53, 151, 391, 507, 425, 3469, 6605, 5783, 31747, 37677, 116037}},
-{11301, 17, 47400, {1, 1, 1, 5, 5, 43, 61, 67, 319, 553, 1163, 3095, 4447, 7505, 15617, 26167, 11145}},
-{11302, 17, 47405, {1, 1, 5, 7, 3, 3, 9, 161, 155, 869, 337, 3693, 6847, 8449, 15077, 54769, 123335}},
-{11303, 17, 47408, {1, 3, 3, 7, 11, 19, 17, 71, 105, 649, 323, 3033, 1695, 15973, 6361, 3163, 17669}},
-{11304, 17, 47411, {1, 3, 7, 13, 13, 9, 3, 251, 149, 513, 637, 2211, 6397, 1741, 8547, 3165, 38241}},
-{11305, 17, 47431, {1, 1, 5, 5, 1, 57, 73, 35, 287, 347, 221, 3261, 7693, 5443, 6175, 18181, 23733}},
-{11306, 17, 47443, {1, 3, 7, 5, 5, 19, 1, 167, 5, 825, 815, 1369, 7657, 6169, 9583, 34761, 81003}},
-{11307, 17, 47459, {1, 3, 3, 5, 15, 17, 23, 157, 475, 297, 1495, 811, 8135, 11453, 9683, 55505, 84361}},
-{11308, 17, 47466, {1, 1, 1, 11, 1, 63, 59, 189, 205, 1023, 1065, 1095, 2293, 14629, 29399, 2925, 28327}},
-{11309, 17, 47479, {1, 3, 1, 3, 31, 33, 85, 183, 383, 731, 1223, 3353, 3703, 5655, 31265, 12249, 22127}},
-{11310, 17, 47480, {1, 3, 5, 7, 7, 29, 61, 3, 375, 95, 1815, 4065, 6287, 3797, 32397, 50581, 123371}},
-{11311, 17, 47495, {1, 3, 1, 9, 13, 37, 57, 139, 43, 561, 425, 3603, 1167, 10281, 31825, 32673, 106169}},
-{11312, 17, 47504, {1, 3, 5, 3, 15, 41, 29, 223, 79, 851, 1741, 2241, 5659, 9773, 18369, 37239, 14831}},
-{11313, 17, 47519, {1, 3, 1, 1, 7, 11, 83, 63, 51, 521, 1911, 475, 5207, 3219, 10257, 40461, 9087}},
-{11314, 17, 47520, {1, 3, 5, 7, 23, 17, 97, 195, 5, 451, 1971, 1881, 921, 8729, 3443, 64529, 67747}},
-{11315, 17, 47530, {1, 1, 3, 9, 21, 63, 45, 181, 429, 605, 169, 3493, 2381, 2887, 19515, 53151, 60147}},
-{11316, 17, 47537, {1, 3, 3, 7, 15, 11, 117, 161, 333, 139, 587, 2331, 3175, 12093, 12649, 52381, 107117}},
-{11317, 17, 47555, {1, 1, 5, 15, 23, 57, 19, 57, 507, 461, 799, 611, 1589, 10909, 7649, 17817, 24677}},
-{11318, 17, 47558, {1, 1, 3, 15, 1, 61, 9, 201, 401, 387, 527, 2855, 2339, 3813, 11825, 14273, 73745}},
-{11319, 17, 47567, {1, 3, 1, 5, 1, 37, 27, 105, 475, 335, 1169, 3233, 3225, 12861, 10133, 36673, 55025}},
-{11320, 17, 47569, {1, 1, 1, 9, 27, 53, 55, 197, 229, 5, 93, 1157, 7929, 9745, 5295, 15359, 75567}},
-{11321, 17, 47572, {1, 1, 7, 5, 11, 3, 109, 81, 457, 159, 1899, 557, 1067, 295, 2661, 1145, 8745}},
-{11322, 17, 47582, {1, 1, 1, 15, 31, 29, 77, 171, 411, 425, 1041, 2791, 2567, 5357, 21871, 27689, 103485}},
-{11323, 17, 47591, {1, 3, 5, 11, 19, 47, 23, 97, 405, 667, 2045, 2951, 2063, 7775, 20629, 34283, 26925}},
-{11324, 17, 47595, {1, 3, 5, 7, 5, 51, 125, 67, 165, 145, 733, 1649, 5787, 4333, 24355, 33397, 101001}},
-{11325, 17, 47598, {1, 3, 7, 11, 13, 7, 117, 147, 449, 201, 953, 553, 1839, 6903, 10417, 42751, 36823}},
-{11326, 17, 47609, {1, 1, 3, 5, 3, 21, 109, 35, 95, 953, 211, 2849, 5681, 16287, 16553, 30345, 69729}},
-{11327, 17, 47612, {1, 3, 7, 5, 25, 37, 21, 143, 317, 621, 1417, 283, 3801, 15375, 3799, 13345, 59727}},
-{11328, 17, 47616, {1, 3, 3, 9, 3, 37, 113, 127, 123, 979, 1225, 2585, 2055, 2571, 16727, 38863, 74347}},
-{11329, 17, 47625, {1, 3, 3, 3, 23, 13, 49, 111, 277, 143, 1171, 605, 91, 13693, 1971, 18209, 114203}},
-{11330, 17, 47640, {1, 1, 1, 9, 27, 33, 73, 9, 93, 343, 55, 3045, 2029, 3665, 28483, 6601, 72085}},
-{11331, 17, 47649, {1, 1, 1, 15, 17, 55, 87, 231, 103, 1005, 1451, 3617, 7477, 2045, 10683, 39053, 1289}},
-{11332, 17, 47655, {1, 3, 7, 7, 25, 55, 39, 89, 489, 609, 1969, 159, 7485, 10713, 28371, 14935, 95347}},
-{11333, 17, 47661, {1, 3, 3, 13, 25, 9, 83, 167, 25, 135, 2017, 3313, 1493, 7799, 22479, 49471, 20149}},
-{11334, 17, 47688, {1, 1, 1, 15, 25, 13, 63, 117, 97, 449, 1331, 229, 6027, 1023, 26705, 15283, 60385}},
-{11335, 17, 47711, {1, 1, 7, 5, 5, 37, 3, 79, 337, 861, 1549, 915, 7303, 1503, 19245, 60721, 45313}},
-{11336, 17, 47717, {1, 3, 7, 15, 19, 1, 11, 39, 505, 757, 1627, 2137, 3209, 7651, 31291, 45913, 26851}},
-{11337, 17, 47721, {1, 3, 1, 5, 25, 21, 85, 233, 171, 269, 367, 1651, 3961, 2487, 1977, 7027, 2725}},
-{11338, 17, 47724, {1, 1, 5, 15, 13, 23, 81, 145, 201, 323, 425, 2785, 1149, 12617, 11451, 23205, 117691}},
-{11339, 17, 47727, {1, 1, 7, 11, 29, 37, 69, 141, 15, 773, 1299, 2147, 8129, 12227, 27811, 58701, 103637}},
-{11340, 17, 47730, {1, 3, 5, 13, 3, 33, 29, 227, 261, 221, 823, 1399, 5107, 2423, 23809, 42175, 28207}},
-{11341, 17, 47739, {1, 3, 1, 15, 21, 1, 121, 255, 259, 441, 45, 1899, 2489, 4155, 18317, 52695, 607}},
-{11342, 17, 47745, {1, 3, 5, 9, 25, 43, 115, 111, 329, 997, 753, 1513, 6949, 3197, 28275, 48855, 25089}},
-{11343, 17, 47752, {1, 3, 3, 3, 25, 9, 21, 213, 111, 173, 913, 1465, 4437, 9725, 1455, 53517, 81843}},
-{11344, 17, 47758, {1, 3, 5, 5, 5, 25, 3, 159, 19, 203, 181, 3447, 6395, 2145, 11289, 16797, 59567}},
-{11345, 17, 47765, {1, 3, 3, 1, 29, 25, 43, 115, 257, 833, 379, 941, 4389, 5795, 12593, 2471, 127149}},
-{11346, 17, 47770, {1, 3, 1, 9, 3, 15, 81, 141, 155, 515, 1677, 2569, 1105, 15653, 24143, 3439, 17317}},
-{11347, 17, 47782, {1, 3, 1, 13, 27, 13, 103, 87, 27, 971, 671, 629, 4943, 13897, 4003, 21507, 40193}},
-{11348, 17, 47786, {1, 3, 5, 9, 1, 49, 11, 15, 511, 837, 1953, 1585, 1867, 9095, 543, 16993, 115187}},
-{11349, 17, 47791, {1, 1, 5, 11, 21, 49, 37, 61, 9, 629, 1025, 1635, 4047, 15491, 28481, 43235, 53165}},
-{11350, 17, 47793, {1, 1, 5, 7, 15, 57, 121, 119, 405, 29, 655, 3085, 7131, 14761, 2273, 47113, 8603}},
-{11351, 17, 47796, {1, 1, 3, 3, 11, 45, 51, 107, 367, 235, 675, 3777, 6081, 16319, 19499, 36893, 25579}},
-{11352, 17, 47814, {1, 1, 7, 11, 1, 13, 43, 159, 415, 423, 1223, 2201, 1089, 10189, 12457, 26691, 3603}},
-{11353, 17, 47823, {1, 1, 3, 3, 3, 37, 109, 67, 487, 785, 637, 3931, 929, 14153, 25283, 483, 14371}},
-{11354, 17, 47826, {1, 1, 7, 9, 31, 59, 9, 245, 479, 113, 1419, 3265, 8131, 11123, 32519, 12141, 82059}},
-{11355, 17, 47837, {1, 1, 1, 7, 25, 25, 31, 13, 81, 217, 997, 1161, 1049, 5487, 8487, 57807, 126115}},
-{11356, 17, 47854, {1, 1, 3, 15, 1, 23, 63, 39, 503, 933, 1915, 687, 547, 779, 7689, 38607, 125229}},
-{11357, 17, 47856, {1, 1, 3, 3, 31, 49, 51, 87, 99, 327, 783, 3487, 7307, 2759, 22781, 56343, 126805}},
-{11358, 17, 47871, {1, 3, 3, 11, 27, 43, 99, 197, 275, 19, 775, 329, 3815, 14277, 3363, 26375, 75427}},
-{11359, 17, 47879, {1, 1, 5, 15, 15, 19, 65, 109, 103, 411, 1591, 2569, 1981, 4773, 7861, 6303, 127421}},
-{11360, 17, 47880, {1, 3, 1, 13, 1, 53, 107, 151, 317, 201, 1053, 2701, 5039, 2179, 10085, 31727, 85579}},
-{11361, 17, 47885, {1, 3, 1, 9, 5, 55, 71, 143, 187, 29, 1363, 2403, 2675, 2187, 12123, 32825, 56461}},
-{11362, 17, 47886, {1, 1, 7, 11, 5, 57, 91, 95, 85, 597, 925, 11, 1915, 9159, 9997, 29565, 111655}},
-{11363, 17, 47903, {1, 1, 5, 9, 25, 57, 79, 189, 205, 687, 471, 601, 5343, 9031, 7853, 6079, 40567}},
-{11364, 17, 47907, {1, 1, 3, 1, 31, 53, 67, 191, 511, 369, 1273, 3859, 4253, 14469, 3427, 17691, 22599}},
-{11365, 17, 47913, {1, 1, 3, 9, 17, 53, 101, 219, 41, 663, 635, 3889, 2197, 8125, 8313, 14957, 111445}},
-{11366, 17, 47916, {1, 1, 5, 5, 7, 49, 113, 9, 399, 257, 617, 63, 2773, 4411, 1193, 54449, 89003}},
-{11367, 17, 47928, {1, 1, 7, 11, 13, 29, 77, 73, 161, 419, 985, 303, 2237, 15217, 26621, 20441, 113955}},
-{11368, 17, 47936, {1, 3, 3, 9, 17, 39, 37, 139, 289, 421, 1021, 2635, 2805, 5815, 9101, 48077, 114009}},
-{11369, 17, 47945, {1, 1, 1, 15, 25, 43, 71, 35, 103, 827, 1301, 3567, 3425, 3689, 14453, 10733, 81257}},
-{11370, 17, 47948, {1, 3, 5, 5, 15, 31, 41, 161, 481, 231, 1135, 3045, 439, 11785, 14863, 39729, 59539}},
-{11371, 17, 47956, {1, 1, 5, 7, 27, 9, 81, 141, 395, 105, 41, 3719, 3105, 13685, 7451, 31381, 82907}},
-{11372, 17, 47965, {1, 3, 1, 13, 15, 25, 127, 231, 433, 837, 1923, 1301, 2479, 3243, 21605, 55789, 11311}},
-{11373, 17, 47970, {1, 3, 5, 7, 17, 5, 27, 111, 217, 445, 1245, 1029, 7663, 10291, 16483, 37503, 110205}},
-{11374, 17, 47972, {1, 1, 1, 7, 31, 21, 51, 235, 487, 457, 1687, 2947, 5067, 13779, 7671, 7257, 119141}},
-{11375, 17, 47981, {1, 1, 5, 13, 25, 31, 59, 183, 33, 887, 469, 813, 7939, 11775, 5795, 26227, 57703}},
-{11376, 17, 47987, {1, 3, 3, 15, 17, 7, 19, 87, 365, 177, 1157, 1023, 3055, 15439, 27187, 32593, 112507}},
-{11377, 17, 48010, {1, 1, 1, 9, 19, 49, 103, 239, 207, 409, 1613, 2793, 5477, 11221, 21611, 19963, 99333}},
-{11378, 17, 48012, {1, 3, 3, 11, 17, 1, 103, 77, 93, 197, 1883, 4053, 4613, 11571, 1841, 23189, 4235}},
-{11379, 17, 48023, {1, 3, 5, 9, 9, 49, 29, 231, 167, 593, 1909, 2457, 323, 10549, 6551, 45597, 96591}},
-{11380, 17, 48033, {1, 1, 7, 11, 15, 39, 33, 61, 13, 879, 1589, 2169, 125, 2427, 13029, 24919, 14147}},
-{11381, 17, 48051, {1, 3, 5, 5, 25, 53, 49, 255, 263, 917, 1997, 171, 2945, 14243, 12983, 21821, 119547}},
-{11382, 17, 48071, {1, 1, 1, 15, 5, 25, 113, 235, 311, 377, 1059, 1365, 3457, 8699, 18617, 25119, 110659}},
-{11383, 17, 48075, {1, 1, 5, 1, 9, 61, 1, 137, 301, 85, 1527, 3831, 923, 13753, 20909, 14007, 22939}},
-{11384, 17, 48077, {1, 1, 7, 9, 23, 17, 31, 107, 55, 293, 425, 3513, 3503, 10075, 6299, 40007, 54355}},
-{11385, 17, 48080, {1, 3, 5, 5, 27, 39, 95, 187, 239, 949, 531, 3541, 99, 6339, 32295, 10377, 111287}},
-{11386, 17, 48099, {1, 1, 5, 15, 19, 39, 23, 89, 185, 47, 87, 1721, 2471, 13221, 13201, 31, 12897}},
-{11387, 17, 48106, {1, 3, 1, 9, 7, 7, 109, 241, 39, 687, 175, 139, 583, 1629, 19775, 6371, 121879}},
-{11388, 17, 48114, {1, 1, 1, 13, 13, 9, 73, 153, 367, 425, 217, 3981, 5203, 1111, 12333, 59799, 105259}},
-{11389, 17, 48120, {1, 1, 3, 5, 7, 33, 27, 123, 335, 727, 1619, 3999, 7799, 2807, 2251, 45835, 113193}},
-{11390, 17, 48128, {1, 3, 1, 7, 25, 3, 49, 163, 447, 555, 647, 1461, 5881, 15755, 32233, 48915, 96203}},
-{11391, 17, 48145, {1, 3, 7, 7, 21, 11, 61, 101, 323, 165, 1489, 2933, 3363, 8471, 4311, 65279, 123813}},
-{11392, 17, 48152, {1, 3, 1, 1, 15, 1, 101, 225, 473, 479, 1237, 113, 7591, 2883, 3891, 53703, 14607}},
-{11393, 17, 48155, {1, 3, 5, 3, 17, 51, 23, 31, 487, 957, 1623, 2329, 2801, 6213, 7523, 14131, 23893}},
-{11394, 17, 48182, {1, 1, 5, 7, 9, 39, 93, 105, 13, 481, 53, 3785, 5621, 11889, 993, 23611, 73651}},
-{11395, 17, 48188, {1, 3, 7, 15, 21, 57, 97, 69, 339, 289, 1805, 2661, 1165, 6079, 1127, 51285, 54453}},
-{11396, 17, 48203, {1, 1, 3, 3, 3, 3, 1, 179, 123, 1011, 1363, 231, 6983, 9499, 91, 52573, 32565}},
-{11397, 17, 48217, {1, 3, 3, 15, 5, 37, 97, 7, 189, 547, 1965, 3821, 4907, 8181, 12857, 7907, 19361}},
-{11398, 17, 48218, {1, 1, 5, 3, 29, 33, 45, 99, 359, 337, 1377, 577, 3117, 9545, 30093, 26147, 128509}},
-{11399, 17, 48236, {1, 3, 5, 11, 7, 49, 99, 249, 37, 755, 383, 2845, 4153, 695, 11099, 33653, 105155}},
-{11400, 17, 48241, {1, 3, 1, 1, 19, 3, 3, 177, 97, 323, 1367, 213, 4391, 11223, 26497, 12289, 39047}},
-{11401, 17, 48244, {1, 1, 3, 7, 3, 33, 73, 199, 339, 479, 1797, 3905, 2849, 5667, 18015, 36653, 83491}},
-{11402, 17, 48264, {1, 1, 5, 3, 27, 59, 27, 241, 49, 161, 451, 3993, 2489, 10681, 11895, 60405, 47021}},
-{11403, 17, 48269, {1, 1, 7, 5, 9, 23, 115, 131, 383, 895, 1591, 585, 2571, 7485, 31535, 12871, 95717}},
-{11404, 17, 48278, {1, 1, 1, 15, 13, 49, 3, 157, 311, 159, 1239, 159, 5643, 6405, 11763, 34609, 75259}},
-{11405, 17, 48282, {1, 1, 1, 13, 11, 41, 119, 3, 165, 943, 2035, 179, 357, 14591, 20099, 4787, 12659}},
-{11406, 17, 48288, {1, 1, 5, 11, 13, 9, 67, 139, 259, 947, 1559, 283, 1557, 11297, 29753, 21953, 100317}},
-{11407, 17, 48311, {1, 1, 7, 11, 13, 39, 105, 83, 109, 723, 1643, 3599, 1471, 13653, 4583, 18595, 91935}},
-{11408, 17, 48315, {1, 1, 5, 9, 25, 5, 69, 189, 209, 779, 1421, 467, 849, 12887, 10317, 3005, 100813}},
-{11409, 17, 48317, {1, 3, 7, 11, 19, 1, 93, 239, 333, 713, 1525, 813, 5913, 10811, 7077, 20573, 86999}},
-{11410, 17, 48329, {1, 3, 1, 5, 25, 1, 107, 153, 225, 889, 1319, 497, 2193, 11511, 17553, 23733, 83179}},
-{11411, 17, 48330, {1, 3, 3, 3, 5, 45, 51, 37, 443, 851, 263, 4067, 2629, 10887, 29081, 30489, 1161}},
-{11412, 17, 48337, {1, 1, 3, 9, 25, 19, 115, 31, 347, 641, 1103, 1121, 7051, 14071, 16663, 48517, 24655}},
-{11413, 17, 48350, {1, 1, 3, 15, 11, 33, 123, 181, 225, 437, 875, 1997, 209, 5487, 1989, 6745, 38423}},
-{11414, 17, 48353, {1, 3, 7, 5, 27, 5, 105, 203, 51, 683, 1523, 347, 6881, 4353, 4531, 29589, 108053}},
-{11415, 17, 48360, {1, 1, 3, 9, 15, 33, 127, 145, 125, 429, 915, 1307, 1495, 3553, 26797, 36819, 121375}},
-{11416, 17, 48374, {1, 3, 5, 15, 7, 1, 55, 99, 7, 405, 885, 59, 5359, 13969, 32037, 53399, 77293}},
-{11417, 17, 48380, {1, 1, 7, 1, 29, 31, 89, 69, 405, 837, 1949, 2337, 1139, 14129, 16867, 15167, 21117}},
-{11418, 17, 48405, {1, 1, 3, 5, 3, 25, 61, 175, 135, 109, 959, 501, 13, 16057, 25031, 16321, 27617}},
-{11419, 17, 48406, {1, 3, 1, 5, 17, 39, 59, 113, 25, 707, 1641, 3489, 6193, 10085, 13837, 57851, 77475}},
-{11420, 17, 48409, {1, 1, 3, 5, 17, 35, 111, 163, 253, 641, 715, 1101, 4411, 10771, 20241, 46415, 114719}},
-{11421, 17, 48412, {1, 3, 1, 1, 7, 11, 77, 59, 71, 869, 1505, 751, 4367, 9603, 29735, 7333, 62487}},
-{11422, 17, 48416, {1, 3, 7, 9, 3, 51, 93, 195, 497, 659, 1563, 3801, 6933, 9089, 10891, 9853, 93611}},
-{11423, 17, 48419, {1, 3, 1, 7, 21, 47, 61, 117, 293, 281, 1547, 3437, 4947, 12119, 21425, 5591, 23951}},
-{11424, 17, 48425, {1, 1, 7, 13, 19, 59, 121, 249, 147, 759, 1963, 465, 7785, 7015, 81, 47869, 123845}},
-{11425, 17, 48434, {1, 1, 7, 13, 5, 35, 45, 69, 167, 263, 979, 2855, 1845, 5531, 17167, 7363, 89233}},
-{11426, 17, 48443, {1, 3, 3, 3, 17, 43, 109, 193, 389, 867, 1403, 1271, 7127, 13977, 22547, 53997, 24475}},
-{11427, 17, 48445, {1, 1, 1, 5, 25, 43, 47, 163, 417, 967, 819, 2433, 439, 8499, 29705, 32697, 109963}},
-{11428, 17, 48453, {1, 1, 1, 15, 19, 5, 83, 237, 431, 697, 1383, 2499, 6907, 9033, 12147, 23479, 17649}},
-{11429, 17, 48454, {1, 3, 5, 13, 27, 35, 103, 95, 239, 903, 537, 601, 417, 15859, 16533, 16753, 128229}},
-{11430, 17, 48482, {1, 1, 3, 1, 11, 55, 57, 9, 229, 135, 805, 2745, 2023, 12645, 29135, 39051, 17065}},
-{11431, 17, 48491, {1, 3, 5, 3, 13, 25, 77, 29, 449, 31, 1733, 1451, 3895, 11551, 1011, 22817, 35959}},
-{11432, 17, 48501, {1, 3, 3, 3, 1, 31, 93, 47, 255, 393, 571, 443, 6079, 6245, 11773, 42087, 40651}},
-{11433, 17, 48517, {1, 3, 1, 5, 17, 49, 119, 219, 375, 337, 29, 3409, 3187, 15243, 25853, 44385, 103675}},
-{11434, 17, 48518, {1, 3, 7, 15, 15, 21, 79, 109, 81, 119, 603, 1665, 7813, 3485, 11801, 48693, 108307}},
-{11435, 17, 48545, {1, 1, 1, 15, 9, 5, 103, 141, 181, 841, 7, 1217, 7713, 4843, 9089, 53641, 3029}},
-{11436, 17, 48548, {1, 3, 3, 1, 29, 47, 13, 179, 439, 387, 1553, 3141, 947, 4893, 29119, 30865, 14207}},
-{11437, 17, 48552, {1, 1, 1, 15, 29, 1, 41, 135, 43, 673, 1527, 883, 3211, 5195, 30219, 47133, 56819}},
-{11438, 17, 48569, {1, 3, 5, 13, 13, 47, 97, 219, 277, 397, 1901, 821, 1961, 705, 7291, 19435, 123563}},
-{11439, 17, 48575, {1, 1, 7, 15, 5, 49, 93, 59, 221, 205, 115, 559, 5633, 5819, 6923, 18301, 72639}},
-{11440, 17, 48580, {1, 3, 5, 13, 29, 49, 25, 203, 125, 385, 487, 1897, 2177, 6859, 6105, 763, 36673}},
-{11441, 17, 48584, {1, 3, 3, 9, 23, 63, 9, 115, 489, 89, 1113, 1351, 8181, 2569, 18263, 32619, 24795}},
-{11442, 17, 48590, {1, 1, 5, 11, 25, 51, 97, 155, 15, 139, 1275, 3479, 5851, 3099, 7417, 57155, 90185}},
-{11443, 17, 48595, {1, 3, 1, 11, 1, 37, 67, 221, 493, 475, 1881, 2277, 4365, 9411, 16629, 65229, 28803}},
-{11444, 17, 48602, {1, 3, 1, 1, 15, 53, 39, 141, 453, 151, 335, 795, 1515, 2719, 24197, 21153, 129549}},
-{11445, 17, 48604, {1, 1, 1, 7, 19, 31, 59, 123, 73, 149, 469, 1199, 3603, 1539, 29157, 50031, 22109}},
-{11446, 17, 48618, {1, 1, 3, 15, 23, 51, 45, 211, 423, 553, 1289, 1125, 6347, 6711, 23761, 14109, 17261}},
-{11447, 17, 48625, {1, 3, 5, 13, 5, 7, 35, 185, 263, 791, 161, 325, 4771, 11913, 31595, 56675, 68615}},
-{11448, 17, 48626, {1, 1, 5, 9, 19, 27, 89, 147, 55, 197, 1695, 99, 755, 15115, 1933, 41439, 85063}},
-{11449, 17, 48638, {1, 1, 7, 7, 17, 11, 103, 55, 281, 707, 1973, 2055, 5015, 5713, 3717, 44149, 8033}},
-{11450, 17, 48668, {1, 3, 1, 5, 21, 49, 55, 93, 161, 565, 81, 3241, 3709, 8185, 16935, 60369, 118127}},
-{11451, 17, 48677, {1, 3, 7, 9, 27, 1, 105, 133, 397, 351, 1021, 739, 161, 9971, 24733, 29239, 68853}},
-{11452, 17, 48678, {1, 1, 7, 1, 1, 19, 97, 243, 73, 969, 313, 399, 2955, 2467, 18265, 60637, 35457}},
-{11453, 17, 48687, {1, 3, 1, 11, 29, 25, 35, 35, 469, 143, 1195, 911, 1023, 14685, 10933, 16449, 102113}},
-{11454, 17, 48692, {1, 1, 5, 3, 31, 21, 65, 181, 13, 235, 501, 3621, 3567, 8771, 32747, 59231, 91551}},
-{11455, 17, 48696, {1, 1, 1, 13, 29, 21, 13, 33, 193, 565, 203, 3927, 4749, 9897, 26109, 14221, 27733}},
-{11456, 17, 48704, {1, 1, 1, 5, 29, 41, 7, 125, 391, 295, 533, 2135, 3107, 7711, 27811, 55767, 78821}},
-{11457, 17, 48707, {1, 1, 7, 3, 19, 25, 117, 195, 155, 685, 147, 2049, 3751, 4585, 24893, 36895, 80371}},
-{11458, 17, 48714, {1, 3, 5, 5, 23, 41, 9, 125, 315, 809, 1019, 1453, 4605, 13753, 30641, 50677, 94781}},
-{11459, 17, 48731, {1, 1, 1, 7, 27, 45, 103, 199, 37, 291, 651, 185, 6715, 15387, 30873, 63051, 123231}},
-{11460, 17, 48740, {1, 1, 5, 7, 17, 5, 75, 129, 401, 107, 1681, 2039, 299, 12399, 30947, 26327, 91589}},
-{11461, 17, 48750, {1, 3, 3, 15, 17, 19, 109, 19, 493, 797, 209, 929, 2821, 395, 22173, 27803, 87953}},
-{11462, 17, 48761, {1, 3, 7, 5, 7, 5, 71, 159, 483, 389, 1817, 4093, 963, 4253, 31267, 63919, 62113}},
-{11463, 17, 48785, {1, 3, 3, 15, 9, 49, 89, 49, 15, 61, 2041, 2357, 2173, 3349, 32565, 23207, 21177}},
-{11464, 17, 48786, {1, 1, 1, 13, 15, 21, 31, 143, 387, 371, 567, 1903, 3793, 9559, 7055, 31251, 13663}},
-{11465, 17, 48798, {1, 1, 3, 13, 3, 7, 49, 31, 255, 581, 627, 1947, 2965, 2787, 8275, 59785, 19979}},
-{11466, 17, 48807, {1, 3, 3, 13, 29, 47, 53, 133, 301, 253, 1215, 3409, 5745, 247, 31585, 5555, 31011}},
-{11467, 17, 48808, {1, 3, 7, 15, 23, 49, 1, 89, 141, 423, 707, 645, 7955, 10485, 27223, 35867, 45461}},
-{11468, 17, 48814, {1, 1, 3, 3, 29, 25, 123, 63, 197, 429, 169, 3229, 3797, 4029, 29947, 52781, 16065}},
-{11469, 17, 48826, {1, 3, 3, 7, 29, 17, 83, 95, 199, 253, 133, 265, 6723, 6207, 12863, 61311, 21937}},
-{11470, 17, 48828, {1, 3, 7, 13, 19, 61, 89, 151, 249, 597, 1389, 717, 5111, 3285, 6251, 50237, 108703}},
-{11471, 17, 48834, {1, 3, 5, 11, 1, 23, 35, 61, 143, 45, 625, 1693, 4943, 2213, 9317, 7601, 28359}},
-{11472, 17, 48840, {1, 3, 3, 15, 29, 43, 115, 23, 167, 355, 977, 439, 4767, 9967, 22997, 54725, 125637}},
-{11473, 17, 48845, {1, 3, 7, 1, 29, 45, 83, 71, 395, 247, 1, 113, 6393, 12445, 16137, 35125, 102053}},
-{11474, 17, 48858, {1, 1, 1, 7, 17, 55, 17, 159, 33, 237, 207, 1297, 5611, 6023, 17709, 60905, 3533}},
-{11475, 17, 48864, {1, 3, 1, 13, 27, 57, 27, 235, 141, 917, 1655, 659, 939, 559, 2651, 705, 80141}},
-{11476, 17, 48869, {1, 3, 7, 3, 3, 17, 111, 117, 467, 129, 1105, 3457, 2093, 8513, 19941, 22111, 54597}},
-{11477, 17, 48870, {1, 3, 7, 3, 5, 17, 59, 195, 23, 547, 1799, 1427, 391, 4043, 10407, 31055, 38495}},
-{11478, 17, 48879, {1, 1, 1, 7, 21, 9, 71, 33, 209, 773, 1243, 3239, 3763, 15229, 9609, 24395, 56145}},
-{11479, 17, 48887, {1, 3, 5, 13, 13, 45, 71, 91, 23, 553, 665, 1753, 5173, 4355, 14317, 42517, 32307}},
-{11480, 17, 48899, {1, 3, 5, 11, 31, 3, 37, 95, 63, 425, 1611, 2983, 5075, 1375, 14305, 11099, 101203}},
-{11481, 17, 48911, {1, 1, 3, 1, 21, 7, 15, 141, 389, 871, 617, 271, 1037, 13569, 13019, 58899, 54097}},
-{11482, 17, 48920, {1, 3, 7, 1, 13, 25, 21, 251, 467, 373, 1539, 4065, 1871, 791, 26315, 64187, 119455}},
-{11483, 17, 48926, {1, 3, 1, 3, 25, 37, 43, 9, 187, 323, 409, 443, 2861, 14145, 26185, 24049, 109613}},
-{11484, 17, 48929, {1, 1, 3, 7, 21, 61, 3, 81, 445, 673, 1269, 613, 1279, 8209, 22911, 48017, 54181}},
-{11485, 17, 48971, {1, 1, 1, 15, 25, 63, 71, 147, 217, 491, 183, 977, 4967, 3471, 8791, 11843, 68005}},
-{11486, 17, 48974, {1, 1, 1, 5, 25, 43, 13, 237, 57, 919, 1641, 399, 4269, 7357, 3465, 63901, 61329}},
-{11487, 17, 48981, {1, 1, 7, 15, 27, 57, 47, 187, 295, 117, 1223, 2963, 4995, 13279, 25107, 56089, 37293}},
-{11488, 17, 48998, {1, 1, 5, 13, 29, 19, 83, 121, 129, 931, 1933, 1141, 3125, 3321, 22019, 52729, 119643}},
-{11489, 17, 49007, {1, 1, 1, 1, 21, 19, 49, 241, 227, 57, 1919, 113, 6993, 4687, 1043, 5247, 15565}},
-{11490, 17, 49028, {1, 3, 3, 15, 5, 21, 65, 129, 485, 173, 1663, 2419, 4279, 4167, 25827, 28457, 68219}},
-{11491, 17, 49031, {1, 1, 3, 1, 17, 9, 65, 21, 487, 875, 1111, 1679, 6451, 14825, 23931, 16053, 79687}},
-{11492, 17, 49056, {1, 3, 3, 5, 13, 5, 49, 15, 267, 389, 1111, 1505, 5815, 6285, 26075, 167, 70325}},
-{11493, 17, 49065, {1, 1, 3, 11, 5, 15, 57, 171, 407, 497, 1979, 2819, 1267, 6893, 6601, 30971, 24477}},
-{11494, 17, 49079, {1, 1, 1, 15, 7, 5, 69, 181, 195, 847, 1245, 4019, 2469, 1407, 17013, 43437, 16307}},
-{11495, 17, 49083, {1, 3, 1, 11, 15, 17, 115, 197, 215, 35, 1489, 659, 4725, 11339, 30259, 52539, 13365}},
-{11496, 17, 49088, {1, 1, 1, 13, 23, 43, 21, 33, 17, 969, 1321, 2469, 4371, 7685, 6817, 20179, 113483}},
-{11497, 17, 49093, {1, 3, 7, 3, 31, 11, 79, 55, 123, 263, 1061, 2087, 183, 11623, 20703, 60291, 115261}},
-{11498, 17, 49100, {1, 1, 5, 13, 5, 53, 21, 71, 399, 165, 1997, 2667, 7361, 8863, 27859, 17235, 77623}},
-{11499, 17, 49103, {1, 3, 3, 15, 21, 55, 27, 31, 371, 289, 253, 1453, 105, 7035, 14787, 2281, 128359}},
-{11500, 17, 49124, {1, 1, 3, 15, 23, 29, 3, 143, 47, 255, 115, 2741, 6773, 16267, 5975, 3689, 97497}},
-{11501, 17, 49136, {1, 1, 1, 15, 9, 57, 109, 43, 359, 365, 1577, 4091, 7399, 10521, 7983, 56119, 65451}},
-{11502, 17, 49139, {1, 3, 7, 7, 29, 55, 115, 155, 121, 679, 663, 2345, 3765, 4493, 9555, 24043, 41467}},
-{11503, 17, 49142, {1, 1, 3, 1, 19, 55, 67, 255, 355, 701, 2027, 3703, 7839, 1701, 7657, 36429, 36623}},
-{11504, 17, 49145, {1, 3, 5, 5, 29, 7, 31, 123, 21, 901, 1581, 3993, 5105, 9715, 18347, 27415, 19253}},
-{11505, 17, 49146, {1, 3, 5, 3, 3, 53, 121, 105, 51, 577, 157, 2151, 5105, 7855, 8595, 24457, 55931}},
-{11506, 17, 49171, {1, 3, 1, 9, 23, 25, 67, 115, 79, 809, 1215, 943, 1075, 7103, 729, 18791, 115977}},
-{11507, 17, 49187, {1, 3, 1, 13, 3, 57, 105, 161, 277, 393, 1671, 2765, 5781, 13429, 24075, 10931, 50951}},
-{11508, 17, 49190, {1, 3, 5, 9, 19, 61, 9, 227, 455, 541, 721, 2855, 949, 10159, 13801, 48199, 26747}},
-{11509, 17, 49194, {1, 3, 1, 3, 25, 61, 53, 177, 441, 697, 1845, 3573, 6673, 9691, 911, 46387, 64727}},
-{11510, 17, 49196, {1, 1, 1, 11, 7, 13, 95, 221, 455, 967, 869, 883, 6301, 5261, 18401, 35745, 114645}},
-{11511, 17, 49207, {1, 3, 1, 11, 15, 7, 115, 217, 235, 539, 491, 603, 2201, 241, 25445, 29773, 122695}},
-{11512, 17, 49216, {1, 1, 5, 3, 19, 9, 71, 193, 131, 927, 1931, 3981, 7537, 10811, 27285, 45865, 106171}},
-{11513, 17, 49219, {1, 1, 7, 5, 5, 21, 107, 77, 363, 733, 1011, 3259, 5263, 15043, 19153, 32117, 129409}},
-{11514, 17, 49222, {1, 1, 3, 13, 21, 5, 9, 103, 369, 699, 329, 1065, 895, 13211, 19017, 5359, 38335}},
-{11515, 17, 49240, {1, 1, 7, 15, 21, 11, 73, 153, 371, 753, 805, 3519, 5839, 1809, 7201, 8189, 68361}},
-{11516, 17, 49250, {1, 3, 7, 9, 27, 45, 25, 175, 317, 381, 961, 619, 4827, 15161, 19091, 29369, 21097}},
-{11517, 17, 49262, {1, 1, 5, 5, 7, 7, 21, 69, 23, 589, 1413, 653, 911, 13599, 18349, 47307, 64047}},
-{11518, 17, 49276, {1, 1, 1, 13, 27, 23, 87, 249, 135, 727, 375, 3641, 1489, 13053, 5151, 62689, 101347}},
-{11519, 17, 49289, {1, 1, 5, 11, 7, 39, 1, 109, 203, 961, 973, 1181, 2357, 5123, 31481, 58345, 52705}},
-{11520, 17, 49292, {1, 1, 1, 15, 25, 15, 85, 49, 77, 235, 1761, 2731, 4157, 2057, 27587, 30299, 52997}},
-{11521, 17, 49298, {1, 1, 5, 3, 1, 13, 47, 219, 51, 521, 625, 3243, 7093, 10823, 9559, 58191, 95573}},
-{11522, 17, 49319, {1, 3, 5, 13, 27, 63, 13, 7, 167, 909, 1559, 2103, 1807, 943, 28997, 31015, 85407}},
-{11523, 17, 49320, {1, 1, 3, 5, 17, 21, 101, 163, 477, 223, 175, 3435, 7071, 5121, 28015, 33365, 121057}},
-{11524, 17, 49325, {1, 3, 7, 1, 11, 35, 111, 41, 261, 45, 1009, 2827, 4019, 5029, 22289, 20235, 13481}},
-{11525, 17, 49333, {1, 3, 5, 5, 15, 41, 109, 7, 329, 447, 65, 1317, 6169, 15947, 31191, 47091, 60643}},
-{11526, 17, 49340, {1, 3, 7, 7, 21, 13, 29, 113, 511, 407, 1211, 2065, 455, 10049, 5745, 48589, 48669}},
-{11527, 17, 49343, {1, 1, 5, 5, 21, 45, 89, 19, 279, 165, 1897, 957, 8045, 565, 4959, 37173, 100773}},
-{11528, 17, 49352, {1, 3, 1, 15, 9, 17, 99, 143, 489, 633, 1721, 1255, 3655, 10083, 29079, 17109, 10035}},
-{11529, 17, 49363, {1, 1, 3, 3, 3, 23, 47, 9, 255, 169, 1103, 1799, 7899, 7673, 19259, 61919, 112831}},
-{11530, 17, 49375, {1, 1, 5, 5, 31, 37, 83, 229, 93, 575, 1589, 2353, 185, 7783, 9413, 9617, 123197}},
-{11531, 17, 49391, {1, 3, 5, 7, 31, 7, 113, 255, 231, 309, 1215, 737, 3635, 14631, 28737, 45127, 111399}},
-{11532, 17, 49405, {1, 1, 7, 1, 11, 5, 55, 235, 369, 983, 873, 655, 6277, 11425, 11191, 38231, 88941}},
-{11533, 17, 49413, {1, 3, 1, 9, 3, 1, 119, 93, 245, 167, 853, 2543, 203, 5313, 14129, 6283, 107117}},
-{11534, 17, 49420, {1, 3, 3, 13, 21, 33, 59, 167, 435, 163, 1873, 3341, 2895, 13205, 14147, 19567, 100127}},
-{11535, 17, 49425, {1, 1, 5, 9, 7, 15, 39, 81, 475, 511, 1585, 63, 6861, 10055, 3577, 48999, 80979}},
-{11536, 17, 49431, {1, 1, 5, 13, 21, 29, 17, 3, 499, 739, 1257, 2925, 8179, 13367, 18879, 19917, 109907}},
-{11537, 17, 49432, {1, 3, 7, 13, 15, 57, 109, 19, 265, 579, 233, 2507, 5059, 14713, 9549, 41915, 56199}},
-{11538, 17, 49441, {1, 3, 3, 5, 31, 25, 85, 163, 187, 795, 1597, 1963, 473, 4673, 4555, 51365, 73817}},
-{11539, 17, 49456, {1, 3, 3, 13, 25, 35, 71, 251, 33, 971, 235, 1919, 6705, 14657, 23417, 56377, 21071}},
-{11540, 17, 49476, {1, 3, 3, 11, 3, 29, 85, 193, 11, 831, 29, 1233, 6199, 11991, 9205, 3323, 23749}},
-{11541, 17, 49479, {1, 3, 7, 7, 11, 15, 1, 17, 87, 665, 1593, 2331, 845, 7821, 89, 7057, 114975}},
-{11542, 17, 49504, {1, 1, 5, 11, 9, 37, 39, 79, 455, 397, 1431, 1541, 7629, 15133, 21395, 35619, 123801}},
-{11543, 17, 49514, {1, 1, 1, 7, 11, 59, 67, 45, 169, 869, 1547, 2947, 3025, 12967, 29927, 22181, 44783}},
-{11544, 17, 49528, {1, 1, 5, 7, 3, 57, 123, 253, 369, 537, 83, 1147, 3469, 9775, 14137, 38899, 101143}},
-{11545, 17, 49543, {1, 3, 5, 3, 19, 35, 11, 215, 343, 677, 1873, 1211, 3129, 9017, 29595, 1291, 39397}},
-{11546, 17, 49544, {1, 1, 7, 3, 25, 7, 61, 229, 187, 839, 747, 3347, 4321, 13201, 19665, 56951, 85273}},
-{11547, 17, 49550, {1, 1, 1, 1, 11, 5, 51, 41, 227, 895, 553, 2673, 6581, 6583, 15429, 33211, 100599}},
-{11548, 17, 49558, {1, 3, 3, 5, 21, 27, 91, 65, 213, 341, 723, 567, 4761, 11549, 15041, 23079, 55245}},
-{11549, 17, 49568, {1, 1, 3, 1, 15, 43, 83, 57, 473, 453, 1351, 2055, 5769, 3887, 29481, 57915, 14017}},
-{11550, 17, 49578, {1, 3, 3, 3, 21, 29, 121, 137, 99, 527, 711, 1169, 7869, 6245, 25423, 38989, 87019}},
-{11551, 17, 49600, {1, 1, 5, 11, 9, 61, 125, 7, 207, 245, 1019, 635, 7099, 13133, 11809, 56705, 18801}},
-{11552, 17, 49612, {1, 3, 7, 9, 15, 31, 37, 205, 439, 651, 255, 971, 4311, 7137, 11821, 45041, 31081}},
-{11553, 17, 49633, {1, 1, 5, 9, 7, 55, 51, 147, 371, 881, 359, 3021, 1141, 14515, 14605, 64067, 98231}},
-{11554, 17, 49634, {1, 3, 1, 3, 29, 9, 109, 21, 437, 321, 753, 3227, 2929, 14787, 2451, 54331, 115921}},
-{11555, 17, 49636, {1, 3, 5, 7, 1, 29, 13, 167, 89, 185, 409, 209, 6625, 5237, 22513, 2095, 26427}},
-{11556, 17, 49643, {1, 1, 1, 3, 3, 31, 25, 145, 27, 345, 957, 823, 7873, 9469, 29115, 12455, 39447}},
-{11557, 17, 49654, {1, 1, 3, 3, 31, 15, 99, 181, 247, 165, 441, 59, 1181, 2851, 1337, 4929, 31079}},
-{11558, 17, 49657, {1, 1, 3, 11, 3, 47, 41, 53, 41, 435, 945, 3839, 8083, 4927, 26919, 24689, 61015}},
-{11559, 17, 49663, {1, 3, 3, 9, 7, 21, 121, 233, 493, 271, 549, 1627, 5861, 377, 20751, 52927, 3649}},
-{11560, 17, 49667, {1, 1, 1, 7, 15, 49, 29, 149, 57, 513, 873, 93, 337, 12559, 24287, 27771, 28207}},
-{11561, 17, 49693, {1, 1, 5, 7, 7, 7, 75, 161, 419, 601, 55, 2599, 5325, 12419, 26755, 5103, 10231}},
-{11562, 17, 49700, {1, 3, 5, 15, 3, 55, 67, 183, 7, 371, 141, 4093, 4567, 13971, 3327, 20701, 78819}},
-{11563, 17, 49703, {1, 1, 1, 13, 15, 41, 45, 29, 375, 235, 1985, 1051, 5863, 7043, 11143, 59381, 55007}},
-{11564, 17, 49712, {1, 3, 1, 15, 15, 29, 15, 101, 395, 39, 1839, 1689, 429, 405, 29337, 28573, 10599}},
-{11565, 17, 49717, {1, 3, 3, 11, 7, 5, 11, 153, 235, 227, 561, 1037, 2283, 6657, 6729, 17939, 29809}},
-{11566, 17, 49718, {1, 1, 1, 5, 15, 59, 33, 69, 275, 447, 661, 2071, 5811, 10463, 32707, 64503, 106313}},
-{11567, 17, 49721, {1, 1, 7, 1, 21, 53, 21, 235, 497, 309, 1207, 1613, 7739, 12785, 7743, 37671, 29197}},
-{11568, 17, 49727, {1, 3, 5, 9, 9, 51, 33, 105, 275, 917, 1911, 3607, 865, 899, 5405, 59593, 113965}},
-{11569, 17, 49730, {1, 3, 1, 7, 7, 63, 51, 83, 481, 347, 1323, 3549, 2873, 12527, 16515, 61077, 63239}},
-{11570, 17, 49735, {1, 1, 1, 1, 13, 21, 87, 139, 461, 215, 1173, 1197, 2091, 11247, 25647, 23443, 105761}},
-{11571, 17, 49739, {1, 1, 1, 1, 27, 33, 21, 27, 365, 75, 351, 2111, 3897, 13325, 4821, 41355, 95681}},
-{11572, 17, 49747, {1, 3, 5, 5, 15, 41, 15, 93, 397, 461, 1993, 321, 4375, 1205, 18417, 37549, 30181}},
-{11573, 17, 49765, {1, 3, 5, 15, 1, 49, 101, 129, 215, 773, 1265, 2245, 2517, 16261, 32149, 3545, 27631}},
-{11574, 17, 49770, {1, 1, 1, 15, 5, 5, 3, 127, 265, 721, 875, 3117, 2177, 7843, 15871, 22687, 89347}},
-{11575, 17, 49772, {1, 3, 7, 11, 29, 23, 69, 41, 155, 257, 563, 509, 6105, 9169, 18341, 25373, 127397}},
-{11576, 17, 49777, {1, 1, 5, 13, 31, 23, 65, 131, 131, 61, 1979, 2737, 3793, 3617, 14385, 189, 84567}},
-{11577, 17, 49789, {1, 1, 1, 13, 21, 33, 43, 97, 83, 903, 1971, 3209, 5391, 7703, 13795, 3895, 78045}},
-{11578, 17, 49817, {1, 3, 3, 5, 17, 53, 113, 237, 269, 83, 589, 4029, 3309, 14531, 11359, 25803, 25525}},
-{11579, 17, 49829, {1, 1, 7, 1, 21, 35, 43, 73, 251, 705, 1737, 3341, 1581, 9663, 6251, 16329, 44491}},
-{11580, 17, 49839, {1, 3, 3, 7, 17, 5, 65, 19, 203, 717, 807, 1759, 6907, 15801, 30369, 2655, 69565}},
-{11581, 17, 49844, {1, 1, 1, 1, 31, 21, 75, 221, 115, 395, 1495, 2739, 1745, 5981, 28045, 56581, 130695}},
-{11582, 17, 49851, {1, 3, 1, 9, 27, 5, 113, 123, 367, 701, 647, 117, 2389, 12309, 1747, 23421, 21583}},
-{11583, 17, 49854, {1, 1, 1, 15, 27, 57, 95, 81, 347, 765, 1435, 1727, 153, 6051, 27085, 62787, 40903}},
-{11584, 17, 49874, {1, 1, 3, 11, 23, 29, 23, 29, 169, 653, 835, 357, 5113, 5293, 11779, 23567, 64569}},
-{11585, 17, 49883, {1, 1, 7, 13, 31, 7, 101, 235, 99, 247, 1267, 509, 3927, 14317, 3217, 24389, 34215}},
-{11586, 17, 49886, {1, 3, 3, 5, 21, 27, 33, 229, 33, 551, 815, 3551, 4261, 13325, 31117, 40689, 66549}},
-{11587, 17, 49892, {1, 3, 7, 1, 23, 1, 99, 11, 139, 569, 365, 1233, 3281, 7817, 8833, 47699, 97825}},
-{11588, 17, 49895, {1, 1, 3, 1, 19, 39, 19, 151, 25, 73, 1271, 1435, 3109, 2571, 9191, 48257, 61001}},
-{11589, 17, 49914, {1, 3, 7, 1, 23, 63, 1, 115, 159, 943, 1637, 1443, 809, 10705, 12563, 63111, 96343}},
-{11590, 17, 49931, {1, 1, 7, 15, 5, 17, 65, 157, 45, 199, 371, 2497, 4367, 9109, 31955, 64253, 69279}},
-{11591, 17, 49933, {1, 3, 3, 15, 29, 45, 103, 183, 87, 543, 97, 1545, 2719, 5619, 28871, 4049, 111825}},
-{11592, 17, 49934, {1, 1, 5, 7, 27, 63, 65, 241, 103, 483, 579, 3589, 5673, 13283, 24193, 31993, 72713}},
-{11593, 17, 49941, {1, 3, 7, 9, 21, 35, 59, 183, 459, 211, 753, 3941, 5389, 10535, 2895, 44307, 26577}},
-{11594, 17, 49952, {1, 3, 1, 3, 9, 11, 15, 141, 159, 853, 1975, 4027, 8053, 16129, 32687, 29117, 67507}},
-{11595, 17, 49967, {1, 3, 3, 1, 19, 51, 55, 167, 85, 869, 437, 457, 7879, 2097, 4403, 2139, 10589}},
-{11596, 17, 49969, {1, 3, 3, 15, 19, 33, 63, 229, 197, 269, 1189, 317, 5087, 3147, 787, 64317, 43293}},
-{11597, 17, 49972, {1, 3, 5, 11, 25, 25, 121, 37, 371, 117, 1683, 2921, 671, 11353, 32273, 57597, 56901}},
-{11598, 17, 49976, {1, 3, 7, 7, 9, 37, 91, 159, 195, 1, 77, 2085, 985, 9999, 5639, 25041, 66393}},
-{11599, 17, 49979, {1, 1, 7, 5, 11, 17, 67, 21, 301, 971, 591, 3809, 4795, 12301, 16977, 27495, 98539}},
-{11600, 17, 49999, {1, 3, 1, 9, 13, 53, 83, 205, 111, 609, 631, 23, 1781, 15401, 1563, 34367, 40345}},
-{11601, 17, 50008, {1, 3, 7, 1, 31, 23, 101, 47, 55, 905, 953, 733, 5173, 5937, 17703, 31077, 49707}},
-{11602, 17, 50030, {1, 3, 5, 3, 5, 3, 127, 171, 511, 289, 685, 1157, 6521, 3301, 3017, 58857, 55289}},
-{11603, 17, 50041, {1, 1, 5, 1, 1, 29, 59, 7, 423, 83, 797, 2633, 2015, 1657, 7575, 39819, 181}},
-{11604, 17, 50042, {1, 3, 5, 15, 25, 27, 39, 99, 83, 381, 401, 1033, 867, 15645, 28643, 34917, 53215}},
-{11605, 17, 50044, {1, 3, 5, 15, 17, 1, 67, 63, 355, 841, 681, 2807, 531, 15295, 7859, 64031, 121519}},
-{11606, 17, 50057, {1, 3, 1, 5, 21, 57, 63, 247, 467, 101, 129, 2627, 4763, 479, 11145, 8861, 69803}},
-{11607, 17, 50060, {1, 3, 1, 15, 13, 13, 77, 39, 297, 401, 1653, 659, 3909, 13179, 10477, 45967, 1665}},
-{11608, 17, 50075, {1, 3, 7, 5, 29, 17, 35, 157, 309, 747, 1717, 1279, 6103, 3509, 17499, 22989, 43157}},
-{11609, 17, 50077, {1, 1, 1, 7, 11, 51, 55, 119, 145, 505, 179, 3979, 1237, 12801, 15921, 13561, 69161}},
-{11610, 17, 50091, {1, 1, 5, 7, 13, 9, 73, 203, 247, 257, 1607, 1183, 6237, 12327, 5059, 51645, 88781}},
-{11611, 17, 50096, {1, 3, 5, 9, 1, 9, 27, 59, 235, 81, 689, 2457, 893, 6107, 27643, 40145, 2329}},
-{11612, 17, 50099, {1, 1, 1, 11, 11, 19, 65, 63, 27, 513, 1473, 2955, 8037, 4991, 22035, 41965, 82589}},
-{11613, 17, 50106, {1, 3, 1, 1, 9, 53, 97, 95, 247, 379, 259, 2789, 1433, 15299, 18309, 51813, 63271}},
-{11614, 17, 50116, {1, 1, 5, 1, 11, 41, 69, 193, 391, 27, 1511, 1575, 1161, 14741, 25193, 31149, 79573}},
-{11615, 17, 50133, {1, 3, 7, 15, 19, 31, 101, 9, 111, 427, 531, 1335, 767, 15075, 28373, 54015, 108021}},
-{11616, 17, 50144, {1, 3, 1, 3, 29, 17, 83, 163, 179, 703, 2027, 3027, 5267, 16111, 23929, 9653, 38633}},
-{11617, 17, 50153, {1, 3, 5, 9, 3, 7, 111, 1, 311, 143, 1563, 2605, 301, 2447, 5009, 63767, 37529}},
-{11618, 17, 50154, {1, 3, 5, 5, 23, 23, 97, 11, 475, 741, 1385, 2491, 1717, 14587, 6289, 27651, 21873}},
-{11619, 17, 50168, {1, 1, 5, 1, 31, 31, 119, 93, 209, 861, 1591, 1233, 3469, 9799, 5969, 35965, 110841}},
-{11620, 17, 50179, {1, 1, 5, 13, 19, 31, 69, 107, 423, 651, 757, 665, 1297, 9985, 14983, 3153, 26425}},
-{11621, 17, 50188, {1, 1, 5, 3, 23, 5, 89, 77, 461, 799, 683, 2885, 845, 12847, 26721, 13145, 88689}},
-{11622, 17, 50194, {1, 1, 3, 3, 19, 3, 41, 71, 247, 293, 1047, 2349, 6815, 2413, 13683, 51421, 110737}},
-{11623, 17, 50203, {1, 3, 3, 9, 19, 51, 91, 193, 447, 305, 751, 1757, 1547, 12683, 4645, 39767, 6433}},
-{11624, 17, 50212, {1, 1, 7, 1, 11, 51, 83, 175, 461, 259, 1337, 175, 877, 15895, 22487, 8079, 71291}},
-{11625, 17, 50216, {1, 1, 1, 11, 13, 23, 19, 69, 285, 629, 563, 2433, 815, 4851, 10617, 59949, 59119}},
-{11626, 17, 50222, {1, 3, 5, 5, 19, 49, 47, 27, 343, 579, 197, 35, 7051, 2441, 30091, 9645, 101899}},
-{11627, 17, 50229, {1, 1, 3, 3, 21, 25, 125, 215, 159, 259, 1915, 2193, 4213, 16157, 8665, 10967, 112793}},
-{11628, 17, 50230, {1, 1, 5, 11, 29, 11, 53, 45, 121, 533, 257, 1749, 6311, 7715, 12037, 12003, 38987}},
-{11629, 17, 50234, {1, 3, 1, 11, 25, 31, 93, 191, 231, 801, 361, 1275, 5031, 7927, 26333, 39795, 45875}},
-{11630, 17, 50251, {1, 1, 5, 1, 7, 37, 117, 35, 257, 225, 1769, 1805, 1593, 1507, 27741, 31561, 52107}},
-{11631, 17, 50253, {1, 1, 3, 3, 27, 23, 55, 5, 137, 677, 459, 2821, 1331, 5845, 17751, 17557, 60495}},
-{11632, 17, 50262, {1, 1, 7, 7, 5, 47, 85, 17, 287, 757, 2013, 2233, 2975, 13769, 23199, 32117, 84429}},
-{11633, 17, 50266, {1, 3, 3, 11, 1, 15, 39, 133, 79, 915, 147, 1489, 2319, 13715, 31317, 46785, 64147}},
-{11634, 17, 50272, {1, 1, 3, 11, 1, 25, 83, 69, 395, 537, 895, 565, 2781, 12685, 7831, 36369, 27871}},
-{11635, 17, 50287, {1, 1, 1, 1, 13, 17, 59, 179, 509, 979, 315, 3495, 1773, 16375, 27873, 18065, 20285}},
-{11636, 17, 50295, {1, 1, 5, 1, 27, 31, 39, 251, 121, 899, 751, 1603, 7501, 425, 25791, 35407, 110405}},
-{11637, 17, 50305, {1, 1, 7, 11, 11, 3, 107, 247, 79, 349, 405, 3469, 2201, 8007, 22891, 7901, 11413}},
-{11638, 17, 50306, {1, 1, 1, 11, 15, 55, 121, 151, 127, 239, 115, 611, 6191, 15435, 19831, 64745, 110473}},
-{11639, 17, 50311, {1, 1, 7, 1, 21, 25, 57, 11, 31, 823, 1855, 2337, 7655, 10845, 22167, 36977, 94265}},
-{11640, 17, 50320, {1, 3, 5, 1, 31, 11, 117, 97, 341, 953, 1499, 2487, 559, 8609, 6321, 20669, 28945}},
-{11641, 17, 50323, {1, 3, 7, 1, 5, 27, 15, 161, 83, 139, 75, 3645, 5227, 16199, 1833, 21767, 67579}},
-{11642, 17, 50325, {1, 1, 7, 5, 31, 35, 75, 115, 451, 773, 1987, 1069, 651, 961, 16317, 18391, 56519}},
-{11643, 17, 50339, {1, 1, 1, 1, 31, 11, 23, 255, 215, 251, 867, 2381, 2351, 13189, 17705, 33569, 102361}},
-{11644, 17, 50356, {1, 3, 7, 1, 17, 49, 49, 125, 445, 947, 1985, 2113, 3025, 6277, 1981, 33329, 99413}},
-{11645, 17, 50365, {1, 3, 3, 3, 27, 7, 59, 109, 37, 777, 1359, 2157, 3185, 7317, 30887, 10499, 126563}},
-{11646, 17, 50366, {1, 3, 3, 9, 27, 5, 99, 167, 457, 363, 2031, 1805, 4661, 8695, 4667, 61129, 81143}},
-{11647, 17, 50368, {1, 1, 5, 13, 5, 47, 95, 249, 289, 631, 1739, 2947, 7169, 13019, 10429, 16197, 11539}},
-{11648, 17, 50377, {1, 3, 7, 15, 27, 45, 93, 131, 269, 835, 399, 1133, 6509, 1279, 3635, 17977, 38667}},
-{11649, 17, 50386, {1, 1, 5, 3, 17, 51, 1, 77, 105, 237, 995, 2643, 6921, 6707, 30129, 1543, 94501}},
-{11650, 17, 50397, {1, 1, 1, 7, 29, 1, 117, 33, 141, 805, 1553, 3943, 45, 8911, 24191, 45191, 36525}},
-{11651, 17, 50411, {1, 1, 7, 7, 31, 21, 97, 29, 179, 345, 1059, 701, 7709, 15831, 22923, 57233, 58961}},
-{11652, 17, 50414, {1, 1, 3, 15, 15, 5, 85, 227, 13, 351, 1167, 3283, 6833, 565, 21019, 53249, 4639}},
-{11653, 17, 50425, {1, 3, 3, 5, 27, 1, 5, 89, 101, 295, 481, 2397, 1459, 3729, 3703, 25109, 69237}},
-{11654, 17, 50451, {1, 3, 7, 13, 31, 37, 69, 147, 505, 487, 1701, 1145, 2061, 10067, 18269, 13049, 92091}},
-{11655, 17, 50463, {1, 3, 3, 1, 29, 39, 33, 199, 499, 377, 1081, 3787, 4843, 16287, 23397, 19083, 91381}},
-{11656, 17, 50467, {1, 1, 1, 13, 21, 61, 121, 251, 511, 615, 625, 2245, 5951, 16165, 2155, 37301, 68319}},
-{11657, 17, 50473, {1, 1, 1, 15, 19, 35, 57, 99, 1, 97, 1177, 3109, 7213, 5447, 25251, 24803, 107449}},
-{11658, 17, 50487, {1, 3, 1, 11, 11, 59, 95, 135, 329, 931, 843, 2847, 463, 10725, 3933, 32325, 44545}},
-{11659, 17, 50501, {1, 1, 7, 13, 13, 57, 29, 175, 11, 701, 231, 2907, 5555, 16159, 1249, 38049, 40115}},
-{11660, 17, 50505, {1, 1, 5, 15, 23, 37, 47, 221, 465, 631, 57, 1189, 2083, 6561, 10725, 8015, 21231}},
-{11661, 17, 50514, {1, 3, 7, 5, 9, 25, 31, 47, 139, 639, 999, 2909, 39, 16227, 16967, 30555, 125541}},
-{11662, 17, 50516, {1, 3, 3, 9, 5, 3, 9, 9, 43, 999, 159, 3063, 3661, 7089, 28929, 55305, 105521}},
-{11663, 17, 50536, {1, 3, 1, 11, 17, 7, 3, 57, 457, 753, 135, 3721, 1111, 7267, 12603, 50511, 85433}},
-{11664, 17, 50547, {1, 3, 5, 1, 27, 3, 107, 187, 247, 891, 1311, 423, 1767, 14769, 22119, 36225, 94267}},
-{11665, 17, 50566, {1, 3, 5, 15, 1, 13, 65, 35, 435, 557, 1755, 1343, 2647, 179, 7781, 62903, 18741}},
-{11666, 17, 50572, {1, 1, 7, 15, 29, 57, 63, 227, 407, 163, 1207, 2717, 2731, 1737, 6379, 14937, 46683}},
-{11667, 17, 50583, {1, 1, 1, 9, 25, 35, 93, 1, 77, 677, 875, 3787, 3075, 14033, 23017, 3487, 14999}},
-{11668, 17, 50593, {1, 3, 3, 9, 3, 45, 115, 61, 437, 823, 1401, 459, 301, 5519, 31003, 64499, 1757}},
-{11669, 17, 50599, {1, 3, 1, 11, 23, 37, 69, 215, 197, 961, 1501, 2953, 3679, 6775, 24679, 44215, 52357}},
-{11670, 17, 50613, {1, 3, 1, 15, 29, 23, 1, 133, 451, 677, 687, 1269, 5987, 11975, 11929, 63691, 48683}},
-{11671, 17, 50617, {1, 1, 1, 7, 13, 31, 13, 71, 355, 345, 1193, 3421, 7601, 7413, 6719, 28681, 97605}},
-{11672, 17, 50618, {1, 1, 5, 13, 23, 3, 15, 253, 109, 17, 341, 471, 1131, 14901, 31783, 41369, 64139}},
-{11673, 17, 50620, {1, 1, 3, 1, 25, 25, 85, 157, 443, 83, 269, 3789, 7977, 7783, 28433, 30563, 82805}},
-{11674, 17, 50628, {1, 1, 7, 5, 3, 11, 83, 63, 253, 349, 217, 2733, 4183, 2759, 7617, 41749, 14015}},
-{11675, 17, 50638, {1, 1, 5, 7, 7, 7, 91, 201, 449, 247, 889, 3829, 3529, 14253, 24091, 33521, 6049}},
-{11676, 17, 50652, {1, 1, 3, 7, 25, 7, 123, 161, 227, 965, 511, 619, 4359, 11833, 12859, 26091, 3867}},
-{11677, 17, 50655, {1, 1, 7, 9, 5, 41, 71, 111, 95, 261, 1809, 3835, 7625, 12085, 28885, 64829, 48981}},
-{11678, 17, 50662, {1, 1, 5, 3, 13, 55, 57, 79, 457, 785, 653, 1429, 3879, 13559, 3953, 18205, 5777}},
-{11679, 17, 50665, {1, 3, 5, 9, 23, 25, 107, 255, 151, 191, 119, 3367, 1081, 12691, 3575, 38171, 42573}},
-{11680, 17, 50673, {1, 1, 7, 15, 3, 23, 115, 233, 265, 187, 1961, 1303, 5101, 1035, 6803, 14557, 4527}},
-{11681, 17, 50683, {1, 1, 3, 11, 19, 37, 45, 167, 17, 793, 1361, 3571, 5889, 14421, 20453, 5093, 59927}},
-{11682, 17, 50689, {1, 1, 7, 15, 3, 53, 1, 11, 159, 389, 171, 2351, 7189, 3109, 1541, 53595, 24247}},
-{11683, 17, 50690, {1, 1, 7, 1, 7, 43, 75, 175, 253, 687, 1811, 3277, 447, 8711, 14281, 53265, 7379}},
-{11684, 17, 50692, {1, 1, 5, 3, 21, 45, 113, 25, 309, 31, 1765, 305, 1423, 115, 26421, 50267, 122115}},
-{11685, 17, 50696, {1, 3, 5, 13, 15, 47, 17, 17, 445, 775, 243, 3959, 7263, 9375, 12017, 57399, 58203}},
-{11686, 17, 50704, {1, 3, 3, 1, 31, 37, 37, 213, 125, 929, 243, 1011, 2841, 4499, 16961, 12639, 23381}},
-{11687, 17, 50713, {1, 3, 1, 3, 7, 53, 31, 165, 311, 239, 731, 1759, 1769, 203, 23201, 20267, 33381}},
-{11688, 17, 50719, {1, 3, 3, 11, 1, 1, 73, 57, 497, 693, 693, 861, 5587, 16307, 8559, 28785, 91147}},
-{11689, 17, 50738, {1, 3, 1, 3, 11, 61, 11, 241, 473, 479, 1831, 1771, 25, 10217, 32683, 40165, 98433}},
-{11690, 17, 50757, {1, 1, 5, 3, 17, 51, 39, 27, 189, 631, 689, 2849, 1849, 9143, 19263, 32729, 23031}},
-{11691, 17, 50761, {1, 1, 5, 9, 15, 39, 103, 83, 485, 689, 1561, 55, 5219, 12069, 32225, 7781, 114299}},
-{11692, 17, 50764, {1, 1, 1, 1, 31, 49, 71, 145, 485, 907, 1551, 3931, 4081, 2159, 24747, 6953, 15887}},
-{11693, 17, 50770, {1, 1, 3, 7, 27, 61, 57, 153, 15, 881, 271, 267, 5827, 7625, 18179, 3769, 42211}},
-{11694, 17, 50776, {1, 3, 1, 3, 21, 49, 65, 177, 341, 851, 1825, 3347, 113, 8077, 1117, 9463, 115821}},
-{11695, 17, 50803, {1, 3, 5, 11, 27, 17, 75, 35, 475, 389, 313, 2187, 7005, 911, 21921, 10979, 13705}},
-{11696, 17, 50805, {1, 1, 5, 9, 1, 49, 15, 21, 163, 355, 193, 3473, 4451, 5325, 28343, 251, 125963}},
-{11697, 17, 50806, {1, 3, 7, 1, 9, 63, 9, 129, 453, 887, 1841, 597, 1989, 14755, 7847, 7581, 251}},
-{11698, 17, 50816, {1, 3, 7, 13, 31, 15, 123, 3, 427, 101, 1039, 1355, 3653, 2871, 28937, 31243, 108827}},
-{11699, 17, 50826, {1, 3, 7, 13, 3, 17, 71, 243, 145, 747, 1933, 1105, 455, 6355, 20321, 60075, 31575}},
-{11700, 17, 50840, {1, 3, 5, 5, 11, 25, 95, 85, 461, 459, 313, 173, 1413, 15761, 31481, 63793, 29047}},
-{11701, 17, 50845, {1, 3, 7, 7, 3, 5, 3, 95, 107, 995, 1203, 2965, 2419, 5325, 17667, 40205, 91059}},
-{11702, 17, 50852, {1, 1, 3, 9, 25, 3, 113, 79, 359, 69, 93, 1539, 483, 12701, 19075, 35021, 17929}},
-{11703, 17, 50855, {1, 3, 5, 1, 31, 35, 67, 97, 105, 381, 973, 1355, 3901, 3847, 12343, 64309, 29835}},
-{11704, 17, 50862, {1, 3, 7, 1, 11, 33, 117, 237, 449, 101, 317, 23, 5157, 8187, 28839, 29465, 97485}},
-{11705, 17, 50876, {1, 3, 5, 5, 1, 49, 93, 71, 89, 607, 1143, 3271, 5825, 8529, 18479, 23859, 40571}},
-{11706, 17, 50879, {1, 3, 1, 3, 13, 35, 79, 9, 315, 943, 1199, 1521, 2023, 11745, 8273, 27643, 89545}},
-{11707, 17, 50882, {1, 3, 5, 1, 21, 3, 15, 111, 19, 895, 1539, 3331, 6741, 9087, 5231, 13435, 60645}},
-{11708, 17, 50894, {1, 3, 1, 9, 25, 9, 109, 253, 263, 425, 915, 1955, 659, 6249, 11803, 34523, 22645}},
-{11709, 17, 50899, {1, 1, 1, 9, 15, 23, 13, 79, 369, 689, 565, 743, 3897, 8837, 13753, 17213, 86801}},
-{11710, 17, 50905, {1, 1, 1, 5, 31, 27, 111, 231, 25, 617, 897, 1325, 4885, 5731, 2027, 34639, 67863}},
-{11711, 17, 50924, {1, 1, 3, 13, 1, 9, 29, 23, 95, 113, 1035, 2729, 6555, 335, 24795, 35387, 31301}},
-{11712, 17, 50936, {1, 1, 1, 7, 3, 53, 91, 143, 167, 773, 207, 31, 4993, 7953, 26997, 40031, 113939}},
-{11713, 17, 50944, {1, 1, 3, 5, 17, 43, 121, 231, 411, 575, 1621, 3079, 535, 3313, 19443, 58271, 54207}},
-{11714, 17, 50973, {1, 1, 1, 7, 11, 41, 61, 81, 97, 91, 1987, 981, 3745, 819, 23785, 48331, 63761}},
-{11715, 17, 50974, {1, 1, 5, 13, 7, 29, 25, 73, 355, 669, 241, 65, 2249, 5551, 5217, 58573, 34049}},
-{11716, 17, 51002, {1, 1, 7, 11, 1, 45, 125, 107, 127, 639, 1989, 2727, 2103, 8985, 30249, 40037, 40931}},
-{11717, 17, 51007, {1, 1, 5, 13, 21, 59, 99, 131, 359, 615, 665, 577, 2559, 3555, 11355, 26213, 76427}},
-{11718, 17, 51009, {1, 3, 3, 1, 19, 9, 85, 111, 381, 661, 561, 3419, 1355, 8473, 329, 4989, 9087}},
-{11719, 17, 51029, {1, 1, 7, 5, 11, 23, 33, 95, 343, 9, 1579, 2663, 6245, 267, 7187, 25381, 103181}},
-{11720, 17, 51036, {1, 1, 7, 11, 23, 7, 113, 49, 89, 587, 1221, 409, 873, 15531, 2721, 44519, 25349}},
-{11721, 17, 51063, {1, 3, 3, 1, 17, 17, 45, 239, 453, 639, 1433, 2829, 6009, 12447, 9393, 59979, 93343}},
-{11722, 17, 51067, {1, 1, 3, 15, 19, 61, 125, 101, 219, 327, 1551, 1623, 951, 8379, 21009, 64089, 21891}},
-{11723, 17, 51070, {1, 1, 5, 7, 23, 5, 111, 43, 57, 71, 407, 4027, 4869, 12033, 19941, 51969, 120115}},
-{11724, 17, 51074, {1, 3, 7, 15, 17, 49, 31, 145, 185, 169, 1559, 4011, 5293, 7559, 23487, 12213, 2757}},
-{11725, 17, 51079, {1, 3, 7, 3, 3, 59, 119, 3, 509, 539, 1623, 539, 1405, 3913, 213, 30293, 68497}},
-{11726, 17, 51083, {1, 1, 1, 9, 15, 43, 67, 171, 397, 233, 379, 1681, 6877, 9169, 19667, 1971, 115347}},
-{11727, 17, 51093, {1, 1, 5, 15, 1, 45, 25, 133, 99, 181, 1825, 3485, 5633, 4629, 30181, 15761, 87161}},
-{11728, 17, 51094, {1, 1, 5, 3, 5, 55, 97, 117, 303, 591, 733, 3631, 4305, 169, 5361, 64491, 71793}},
-{11729, 17, 51124, {1, 1, 5, 11, 19, 9, 5, 147, 223, 51, 1763, 3899, 7393, 8107, 19619, 60509, 61427}},
-{11730, 17, 51131, {1, 1, 1, 15, 15, 3, 103, 15, 423, 649, 613, 1387, 6229, 4147, 17517, 225, 35697}},
-{11731, 17, 51151, {1, 3, 1, 3, 21, 57, 77, 193, 203, 649, 631, 3753, 4259, 3983, 27707, 33623, 83857}},
-{11732, 17, 51153, {1, 3, 3, 5, 11, 37, 95, 201, 83, 643, 1639, 153, 7683, 15249, 23859, 27021, 43321}},
-{11733, 17, 51156, {1, 3, 5, 13, 23, 31, 69, 215, 303, 433, 1325, 1013, 2903, 12659, 3813, 34497, 59651}},
-{11734, 17, 51165, {1, 3, 1, 9, 15, 39, 113, 253, 173, 393, 19, 2343, 2939, 8871, 29741, 2141, 121675}},
-{11735, 17, 51175, {1, 1, 7, 9, 7, 9, 91, 211, 169, 299, 507, 2849, 1321, 15397, 23949, 32387, 108691}},
-{11736, 17, 51184, {1, 1, 7, 13, 1, 21, 119, 127, 229, 253, 39, 323, 1831, 121, 17385, 45511, 43743}},
-{11737, 17, 51187, {1, 1, 1, 15, 25, 25, 97, 209, 375, 945, 1343, 2205, 1701, 13085, 25547, 55555, 129395}},
-{11738, 17, 51203, {1, 1, 1, 5, 31, 25, 91, 255, 163, 169, 703, 1607, 4731, 7413, 10013, 10925, 109151}},
-{11739, 17, 51220, {1, 3, 3, 9, 15, 47, 71, 219, 9, 37, 231, 3227, 3447, 8129, 23421, 30113, 120725}},
-{11740, 17, 51224, {1, 3, 3, 11, 15, 47, 93, 203, 299, 865, 151, 3999, 1245, 8487, 13355, 27373, 93583}},
-{11741, 17, 51233, {1, 3, 7, 5, 13, 7, 97, 81, 271, 95, 513, 365, 5039, 403, 5285, 29475, 129347}},
-{11742, 17, 51234, {1, 1, 7, 7, 9, 27, 25, 207, 161, 785, 1453, 3031, 763, 2313, 29347, 61457, 52561}},
-{11743, 17, 51239, {1, 3, 3, 11, 25, 25, 39, 61, 165, 803, 1435, 3643, 299, 13751, 24239, 53955, 94889}},
-{11744, 17, 51246, {1, 3, 5, 9, 9, 13, 63, 221, 123, 947, 905, 913, 953, 7429, 25409, 43017, 2217}},
-{11745, 17, 51248, {1, 1, 3, 3, 31, 19, 107, 211, 503, 675, 1921, 3027, 1273, 5699, 20683, 55605, 119803}},
-{11746, 17, 51251, {1, 1, 3, 3, 9, 17, 115, 183, 325, 259, 2013, 1505, 6999, 11573, 5315, 18731, 9405}},
-{11747, 17, 51257, {1, 3, 1, 5, 29, 37, 81, 145, 5, 851, 1803, 2011, 6655, 3601, 11325, 17137, 68501}},
-{11748, 17, 51266, {1, 3, 5, 1, 25, 51, 111, 19, 75, 765, 1843, 139, 7253, 12967, 13387, 48631, 124881}},
-{11749, 17, 51280, {1, 3, 3, 7, 15, 29, 7, 231, 13, 901, 1913, 3817, 3993, 3049, 32367, 4201, 90837}},
-{11750, 17, 51285, {1, 3, 1, 11, 27, 5, 109, 57, 81, 147, 1141, 2153, 5255, 6367, 189, 5959, 88843}},
-{11751, 17, 51286, {1, 3, 5, 5, 19, 35, 17, 149, 407, 889, 1583, 1727, 465, 10785, 6043, 21785, 80935}},
-{11752, 17, 51289, {1, 1, 3, 7, 15, 21, 105, 249, 427, 491, 923, 3189, 8103, 3875, 18347, 35799, 36703}},
-{11753, 17, 51295, {1, 1, 3, 15, 3, 45, 93, 197, 265, 309, 1909, 1635, 1743, 9499, 21897, 36889, 67449}},
-{11754, 17, 51296, {1, 3, 1, 11, 15, 57, 31, 231, 363, 879, 1377, 1941, 6969, 10721, 21933, 33419, 102939}},
-{11755, 17, 51311, {1, 1, 3, 9, 3, 57, 49, 51, 71, 991, 885, 1367, 2937, 9301, 29893, 9867, 113711}},
-{11756, 17, 51329, {1, 3, 7, 7, 11, 59, 123, 247, 51, 659, 1323, 3371, 3417, 12295, 2021, 62753, 28059}},
-{11757, 17, 51350, {1, 1, 7, 11, 3, 57, 53, 1, 203, 287, 219, 3531, 1365, 6235, 30187, 4479, 29567}},
-{11758, 17, 51356, {1, 1, 7, 9, 5, 41, 41, 39, 137, 495, 149, 2421, 7365, 11381, 25403, 16063, 47491}},
-{11759, 17, 51363, {1, 1, 5, 13, 25, 25, 47, 25, 213, 661, 1345, 883, 7573, 3291, 21303, 8033, 102639}},
-{11760, 17, 51365, {1, 1, 5, 3, 9, 49, 75, 221, 455, 139, 1533, 3155, 1023, 7249, 10129, 63165, 1713}},
-{11761, 17, 51370, {1, 3, 5, 11, 17, 1, 23, 241, 83, 359, 1243, 2791, 2975, 6271, 19035, 55057, 7625}},
-{11762, 17, 51372, {1, 3, 1, 9, 17, 61, 109, 255, 447, 939, 899, 551, 7049, 4247, 17333, 43369, 30105}},
-{11763, 17, 51377, {1, 1, 3, 5, 3, 31, 79, 39, 225, 605, 1893, 3523, 5391, 6879, 18619, 2339, 108295}},
-{11764, 17, 51383, {1, 1, 5, 1, 29, 15, 123, 39, 239, 57, 843, 2799, 4755, 4993, 23383, 45559, 48359}},
-{11765, 17, 51384, {1, 1, 5, 5, 7, 5, 99, 1, 351, 213, 1061, 721, 343, 16071, 29641, 55607, 76727}},
-{11766, 17, 51397, {1, 3, 1, 7, 9, 9, 15, 25, 87, 595, 71, 3769, 2583, 10105, 28639, 48899, 49753}},
-{11767, 17, 51407, {1, 3, 5, 3, 31, 29, 99, 77, 323, 615, 581, 1725, 2471, 16263, 4903, 205, 55441}},
-{11768, 17, 51422, {1, 1, 5, 11, 17, 53, 47, 53, 125, 717, 867, 1251, 4009, 13981, 10165, 4769, 117431}},
-{11769, 17, 51435, {1, 1, 3, 7, 7, 19, 119, 27, 163, 11, 693, 3197, 3981, 12591, 26017, 62113, 48391}},
-{11770, 17, 51440, {1, 1, 3, 15, 13, 17, 13, 81, 19, 821, 677, 233, 5227, 14855, 18269, 18895, 90041}},
-{11771, 17, 51446, {1, 1, 3, 9, 27, 61, 125, 221, 415, 183, 1137, 1879, 3451, 3599, 27317, 53449, 35499}},
-{11772, 17, 51463, {1, 3, 3, 15, 3, 27, 53, 93, 17, 405, 373, 2531, 3121, 2299, 1593, 34623, 102389}},
-{11773, 17, 51467, {1, 1, 1, 11, 23, 19, 85, 87, 209, 17, 1805, 4067, 7401, 6097, 5865, 61383, 42971}},
-{11774, 17, 51491, {1, 1, 7, 9, 29, 43, 99, 125, 385, 347, 97, 1121, 1533, 10545, 17383, 48649, 78443}},
-{11775, 17, 51493, {1, 3, 3, 13, 7, 9, 95, 105, 463, 911, 357, 423, 5701, 2389, 16307, 17817, 108775}},
-{11776, 17, 51494, {1, 3, 5, 11, 21, 21, 79, 53, 511, 995, 1709, 1715, 6031, 10507, 10735, 48817, 28569}},
-{11777, 17, 51508, {1, 3, 5, 7, 31, 49, 43, 109, 267, 981, 1529, 3611, 3379, 1295, 27489, 46721, 58423}},
-{11778, 17, 51518, {1, 3, 3, 11, 3, 31, 21, 3, 79, 31, 1885, 3029, 6337, 15457, 8995, 9955, 95019}},
-{11779, 17, 51520, {1, 1, 7, 13, 9, 9, 77, 73, 111, 769, 813, 1599, 5925, 1063, 12151, 54125, 67723}},
-{11780, 17, 51526, {1, 1, 1, 7, 13, 5, 43, 201, 379, 199, 769, 3227, 3995, 1543, 21903, 10651, 122007}},
-{11781, 17, 51529, {1, 3, 7, 13, 11, 53, 83, 201, 231, 137, 617, 2395, 2513, 6659, 9387, 15653, 96927}},
-{11782, 17, 51530, {1, 3, 1, 13, 29, 19, 97, 57, 231, 985, 805, 1169, 831, 15867, 20195, 53533, 99735}},
-{11783, 17, 51537, {1, 1, 3, 13, 19, 15, 19, 39, 99, 31, 421, 755, 7439, 4927, 19893, 15449, 47937}},
-{11784, 17, 51547, {1, 3, 3, 9, 1, 17, 71, 37, 289, 537, 69, 3687, 6537, 12295, 28403, 6627, 72991}},
-{11785, 17, 51559, {1, 3, 3, 15, 31, 53, 21, 223, 451, 309, 895, 3923, 3149, 5167, 1979, 31425, 53485}},
-{11786, 17, 51565, {1, 3, 1, 1, 29, 7, 5, 197, 445, 455, 185, 633, 897, 4561, 28833, 39477, 46665}},
-{11787, 17, 51568, {1, 1, 3, 9, 29, 19, 45, 239, 323, 1005, 101, 2083, 7403, 10401, 987, 32301, 58141}},
-{11788, 17, 51580, {1, 3, 3, 5, 31, 17, 7, 141, 245, 301, 1607, 3381, 7517, 6663, 6327, 15321, 19963}},
-{11789, 17, 51583, {1, 1, 7, 5, 5, 37, 109, 31, 285, 767, 1689, 2961, 5511, 15415, 32011, 14889, 7237}},
-{11790, 17, 51584, {1, 1, 3, 7, 31, 35, 47, 157, 407, 719, 1213, 1241, 2475, 10321, 11547, 52641, 21603}},
-{11791, 17, 51593, {1, 1, 1, 7, 5, 45, 35, 137, 403, 321, 1151, 529, 6297, 3059, 27791, 18387, 101431}},
-{11792, 17, 51594, {1, 1, 3, 11, 21, 19, 97, 121, 377, 325, 741, 1601, 1115, 6233, 19089, 40491, 53259}},
-{11793, 17, 51607, {1, 1, 1, 9, 3, 13, 83, 243, 443, 91, 1455, 1875, 3327, 7245, 12735, 14943, 44163}},
-{11794, 17, 51608, {1, 3, 5, 11, 1, 15, 107, 211, 25, 125, 623, 1319, 6133, 12177, 1377, 32547, 110919}},
-{11795, 17, 51620, {1, 1, 3, 3, 7, 39, 23, 99, 433, 581, 53, 3421, 733, 12767, 23595, 22957, 88821}},
-{11796, 17, 51624, {1, 1, 1, 13, 5, 53, 103, 127, 409, 379, 1155, 3097, 6529, 11685, 22147, 46003, 59771}},
-{11797, 17, 51642, {1, 3, 3, 3, 15, 37, 9, 67, 237, 79, 697, 1943, 1021, 3217, 16013, 14727, 105729}},
-{11798, 17, 51649, {1, 1, 7, 1, 9, 43, 55, 79, 63, 553, 871, 2881, 6487, 4667, 24263, 41995, 60907}},
-{11799, 17, 51652, {1, 1, 7, 7, 23, 31, 55, 23, 451, 593, 85, 43, 965, 12491, 15121, 16129, 90639}},
-{11800, 17, 51659, {1, 1, 7, 13, 11, 53, 21, 123, 237, 147, 511, 2105, 5961, 4465, 4015, 19069, 89203}},
-{11801, 17, 51661, {1, 3, 5, 1, 1, 39, 59, 239, 391, 91, 923, 85, 1047, 1489, 31119, 58485, 129171}},
-{11802, 17, 51670, {1, 3, 5, 13, 3, 21, 35, 205, 219, 795, 901, 2465, 5887, 275, 22003, 29659, 50589}},
-{11803, 17, 51674, {1, 3, 1, 5, 1, 35, 127, 147, 159, 791, 1643, 1811, 1199, 3851, 9681, 19845, 127075}},
-{11804, 17, 51698, {1, 3, 3, 7, 17, 19, 13, 223, 395, 971, 125, 181, 4455, 13305, 30433, 46161, 122277}},
-{11805, 17, 51707, {1, 3, 1, 3, 19, 1, 15, 71, 425, 459, 655, 2251, 5525, 7611, 5819, 1255, 43107}},
-{11806, 17, 51725, {1, 1, 5, 15, 3, 9, 83, 191, 439, 663, 399, 2263, 1857, 15421, 2079, 2381, 59193}},
-{11807, 17, 51737, {1, 3, 5, 5, 1, 7, 9, 77, 347, 419, 1329, 3173, 7295, 3631, 13435, 3217, 18053}},
-{11808, 17, 51753, {1, 3, 3, 7, 29, 39, 35, 71, 119, 745, 603, 2247, 377, 3297, 30983, 27857, 105739}},
-{11809, 17, 51754, {1, 1, 5, 13, 9, 59, 57, 239, 247, 921, 1383, 2315, 241, 4435, 24661, 6129, 122727}},
-{11810, 17, 51779, {1, 1, 5, 7, 3, 15, 39, 165, 27, 803, 609, 3081, 6009, 12665, 24155, 51647, 3857}},
-{11811, 17, 51791, {1, 3, 5, 11, 27, 41, 61, 255, 195, 169, 557, 1739, 4029, 1791, 471, 16321, 49801}},
-{11812, 17, 51796, {1, 3, 7, 13, 17, 45, 35, 177, 109, 113, 551, 219, 4065, 303, 15489, 25427, 12349}},
-{11813, 17, 51809, {1, 3, 5, 5, 25, 15, 79, 165, 231, 867, 483, 3563, 6611, 11277, 3193, 37455, 127373}},
-{11814, 17, 51816, {1, 3, 3, 11, 25, 21, 47, 255, 27, 543, 485, 2675, 5893, 3029, 3857, 50967, 14681}},
-{11815, 17, 51819, {1, 3, 7, 11, 3, 23, 81, 135, 77, 227, 417, 1733, 5175, 15295, 15985, 50329, 48641}},
-{11816, 17, 51827, {1, 3, 5, 1, 3, 47, 33, 67, 201, 235, 1299, 3703, 1959, 8091, 11115, 10869, 9595}},
-{11817, 17, 51829, {1, 3, 7, 13, 1, 45, 61, 49, 471, 923, 1827, 2175, 1433, 3473, 3781, 7923, 121525}},
-{11818, 17, 51834, {1, 3, 5, 7, 25, 59, 113, 19, 415, 839, 167, 3549, 7435, 6573, 767, 2751, 18383}},
-{11819, 17, 51836, {1, 3, 3, 1, 5, 11, 125, 241, 395, 423, 955, 2551, 963, 8197, 30253, 10473, 28505}},
-{11820, 17, 51846, {1, 1, 1, 3, 5, 31, 69, 103, 153, 505, 1507, 2827, 165, 4943, 8343, 54253, 87593}},
-{11821, 17, 51849, {1, 3, 3, 1, 7, 37, 27, 75, 251, 623, 965, 1907, 6063, 761, 765, 10103, 43479}},
-{11822, 17, 51855, {1, 1, 1, 13, 7, 21, 53, 219, 267, 57, 959, 579, 2951, 13797, 3249, 29895, 47467}},
-{11823, 17, 51858, {1, 1, 5, 9, 13, 7, 85, 107, 3, 635, 1235, 1339, 3263, 3895, 25911, 7521, 34149}},
-{11824, 17, 51869, {1, 1, 5, 15, 29, 37, 73, 43, 413, 993, 499, 719, 1557, 14397, 11245, 58197, 127901}},
-{11825, 17, 51870, {1, 1, 5, 15, 9, 37, 87, 57, 63, 337, 927, 1887, 6407, 11237, 23233, 53567, 120449}},
-{11826, 17, 51874, {1, 1, 3, 7, 27, 11, 85, 227, 159, 849, 647, 1977, 4623, 7343, 8089, 4251, 26609}},
-{11827, 17, 51918, {1, 1, 5, 11, 11, 3, 105, 191, 189, 627, 367, 3935, 6647, 13069, 26195, 23137, 56427}},
-{11828, 17, 51926, {1, 1, 3, 3, 29, 51, 39, 3, 437, 1011, 1061, 1747, 3051, 11165, 8155, 9723, 41035}},
-{11829, 17, 51932, {1, 3, 7, 15, 9, 43, 79, 195, 265, 395, 1349, 337, 911, 15767, 3593, 42859, 70181}},
-{11830, 17, 51936, {1, 3, 7, 7, 11, 47, 11, 85, 489, 801, 1177, 3861, 3517, 9209, 27505, 12291, 35691}},
-{11831, 17, 51948, {1, 1, 3, 9, 15, 61, 71, 123, 287, 419, 1079, 3489, 3519, 12739, 21341, 24323, 33961}},
-{11832, 17, 51954, {1, 3, 7, 3, 9, 17, 119, 137, 389, 391, 601, 1875, 2197, 5271, 13289, 43597, 43279}},
-{11833, 17, 51959, {1, 3, 7, 15, 29, 35, 41, 171, 183, 701, 1673, 981, 5479, 21, 11353, 64953, 88189}},
-{11834, 17, 51971, {1, 3, 3, 13, 15, 35, 35, 81, 297, 245, 475, 393, 5401, 12369, 21129, 65213, 125013}},
-{11835, 17, 51983, {1, 1, 7, 13, 15, 57, 25, 143, 389, 111, 1219, 2195, 769, 9005, 10367, 39435, 3631}},
-{11836, 17, 51992, {1, 3, 3, 13, 9, 29, 9, 47, 127, 377, 1195, 1221, 5751, 15481, 10537, 29909, 112691}},
-{11837, 17, 51997, {1, 1, 3, 5, 17, 47, 29, 1, 299, 651, 1023, 1601, 5917, 3781, 18421, 42393, 51789}},
-{11838, 17, 52016, {1, 3, 3, 15, 31, 51, 101, 147, 367, 159, 359, 705, 3773, 8649, 31373, 5733, 58287}},
-{11839, 17, 52021, {1, 3, 5, 11, 11, 51, 55, 79, 147, 917, 1945, 1725, 289, 12777, 30099, 3013, 91527}},
-{11840, 17, 52031, {1, 1, 7, 13, 1, 51, 33, 27, 169, 573, 117, 2479, 761, 1283, 32723, 13589, 88821}},
-{11841, 17, 52033, {1, 1, 1, 3, 23, 13, 33, 207, 137, 391, 1309, 4093, 6889, 827, 9331, 57113, 110193}},
-{11842, 17, 52034, {1, 1, 1, 13, 15, 57, 115, 53, 59, 443, 1, 3545, 6923, 6603, 8631, 41703, 8519}},
-{11843, 17, 52048, {1, 1, 5, 5, 25, 29, 53, 153, 107, 423, 1829, 2469, 1843, 889, 31727, 20701, 6343}},
-{11844, 17, 52053, {1, 1, 7, 13, 11, 41, 7, 219, 77, 663, 329, 2639, 1111, 1293, 16771, 20731, 46973}},
-{11845, 17, 52057, {1, 3, 3, 15, 23, 19, 45, 107, 111, 155, 1595, 1821, 471, 6089, 21587, 49259, 85393}},
-{11846, 17, 52067, {1, 3, 1, 3, 27, 21, 39, 227, 359, 885, 449, 2615, 3519, 5377, 16017, 57159, 82399}},
-{11847, 17, 52076, {1, 3, 3, 15, 31, 33, 77, 33, 87, 821, 701, 2859, 1777, 3007, 16757, 5447, 3557}},
-{11848, 17, 52079, {1, 1, 1, 15, 11, 31, 127, 79, 363, 341, 169, 3451, 6351, 6867, 13511, 833, 103151}},
-{11849, 17, 52081, {1, 3, 5, 7, 27, 23, 5, 67, 159, 535, 103, 843, 8187, 6891, 19169, 22565, 95255}},
-{11850, 17, 52109, {1, 3, 5, 5, 15, 27, 53, 49, 343, 815, 1203, 1031, 6359, 1337, 1629, 47783, 103391}},
-{11851, 17, 52127, {1, 3, 1, 1, 13, 19, 51, 185, 45, 549, 619, 2247, 2541, 10421, 31507, 60785, 87139}},
-{11852, 17, 52128, {1, 3, 1, 15, 29, 9, 47, 127, 41, 767, 1375, 2183, 7169, 12855, 15021, 377, 69327}},
-{11853, 17, 52133, {1, 1, 3, 9, 5, 23, 23, 203, 101, 809, 1155, 2885, 3901, 3081, 1827, 65373, 106133}},
-{11854, 17, 52148, {1, 3, 3, 13, 3, 21, 73, 135, 353, 905, 1757, 1361, 3801, 15541, 2261, 17159, 18037}},
-{11855, 17, 52155, {1, 1, 7, 7, 27, 23, 57, 33, 225, 407, 1709, 1159, 6353, 13341, 15883, 17339, 50423}},
-{11856, 17, 52157, {1, 1, 3, 15, 13, 21, 33, 91, 183, 975, 1623, 3187, 5495, 8947, 7031, 19687, 104483}},
-{11857, 17, 52172, {1, 3, 5, 7, 17, 25, 77, 1, 335, 85, 1783, 2617, 4463, 3807, 12883, 24487, 66205}},
-{11858, 17, 52178, {1, 1, 3, 15, 23, 37, 83, 93, 211, 757, 903, 2681, 49, 435, 21057, 63635, 36489}},
-{11859, 17, 52184, {1, 3, 1, 13, 3, 45, 63, 57, 65, 21, 627, 1467, 51, 15887, 27465, 59227, 108233}},
-{11860, 17, 52199, {1, 1, 7, 5, 15, 41, 53, 57, 301, 677, 803, 1675, 6937, 3159, 14281, 22355, 37783}},
-{11861, 17, 52200, {1, 1, 5, 13, 15, 43, 39, 245, 191, 875, 1505, 2085, 3903, 185, 24461, 28939, 98771}},
-{11862, 17, 52205, {1, 1, 7, 9, 17, 25, 29, 31, 439, 159, 533, 3177, 4155, 403, 23735, 61817, 121909}},
-{11863, 17, 52206, {1, 1, 3, 15, 29, 43, 111, 47, 483, 513, 63, 2423, 4979, 5159, 15499, 33391, 51575}},
-{11864, 17, 52232, {1, 1, 5, 15, 15, 43, 13, 41, 445, 929, 1365, 2023, 6173, 6067, 30969, 51457, 51179}},
-{11865, 17, 52237, {1, 3, 3, 11, 15, 17, 93, 235, 159, 599, 635, 1113, 1017, 7413, 7737, 20051, 79127}},
-{11866, 17, 52243, {1, 1, 1, 15, 5, 19, 81, 65, 479, 119, 1831, 2515, 2929, 15395, 31607, 29969, 49935}},
-{11867, 17, 52246, {1, 3, 1, 13, 23, 47, 45, 151, 51, 217, 803, 3265, 5907, 14371, 8287, 25659, 27655}},
-{11868, 17, 52252, {1, 1, 1, 13, 13, 53, 11, 63, 501, 487, 1683, 1147, 4693, 2761, 19359, 2215, 112393}},
-{11869, 17, 52261, {1, 3, 3, 1, 31, 15, 61, 237, 129, 119, 135, 39, 6509, 3753, 16997, 3841, 24521}},
-{11870, 17, 52265, {1, 3, 5, 7, 5, 27, 113, 251, 217, 923, 229, 2259, 5241, 6331, 6773, 41929, 89605}},
-{11871, 17, 52266, {1, 1, 5, 9, 17, 41, 21, 185, 95, 137, 1151, 195, 913, 531, 15731, 22893, 93521}},
-{11872, 17, 52273, {1, 1, 5, 1, 29, 57, 123, 11, 345, 581, 227, 1539, 7527, 8537, 16429, 8437, 18953}},
-{11873, 17, 52274, {1, 1, 3, 7, 7, 21, 103, 239, 115, 513, 1287, 3717, 331, 5453, 18943, 17247, 64975}},
-{11874, 17, 52288, {1, 3, 7, 11, 21, 37, 79, 83, 93, 155, 1297, 1371, 1109, 6569, 21137, 29237, 24007}},
-{11875, 17, 52300, {1, 1, 1, 13, 17, 11, 127, 89, 397, 497, 1017, 721, 2837, 5623, 31745, 52243, 107225}},
-{11876, 17, 52303, {1, 1, 7, 9, 15, 43, 29, 215, 449, 233, 313, 2587, 2903, 2735, 4539, 50481, 85279}},
-{11877, 17, 52321, {1, 1, 3, 15, 13, 35, 109, 211, 299, 255, 1595, 533, 1801, 13965, 25277, 52347, 13447}},
-{11878, 17, 52322, {1, 1, 1, 15, 9, 23, 115, 119, 207, 973, 1339, 1315, 6465, 9917, 4593, 65435, 2515}},
-{11879, 17, 52328, {1, 3, 3, 3, 7, 25, 115, 115, 213, 845, 1445, 1217, 1563, 12491, 5197, 44409, 79895}},
-{11880, 17, 52333, {1, 1, 1, 3, 9, 33, 31, 203, 19, 895, 1145, 2893, 4807, 7501, 6999, 54883, 13797}},
-{11881, 17, 52351, {1, 1, 3, 1, 19, 51, 73, 29, 451, 533, 83, 2477, 335, 9703, 9747, 57427, 69443}},
-{11882, 17, 52357, {1, 1, 7, 5, 21, 11, 53, 133, 165, 291, 591, 1419, 3661, 4697, 21363, 53467, 84063}},
-{11883, 17, 52372, {1, 1, 7, 3, 13, 7, 85, 49, 193, 289, 1531, 709, 2351, 12085, 28553, 57145, 129517}},
-{11884, 17, 52381, {1, 1, 1, 1, 17, 19, 13, 213, 75, 977, 811, 1813, 7293, 13795, 28569, 28133, 11949}},
-{11885, 17, 52386, {1, 1, 5, 1, 27, 11, 47, 89, 271, 65, 1651, 2331, 3289, 6227, 15027, 19959, 22945}},
-{11886, 17, 52395, {1, 3, 7, 9, 17, 37, 17, 245, 249, 501, 405, 951, 3005, 9757, 10265, 35575, 70529}},
-{11887, 17, 52403, {1, 3, 1, 15, 21, 47, 15, 75, 113, 45, 125, 1393, 3361, 13477, 24325, 39743, 67409}},
-{11888, 17, 52423, {1, 3, 5, 1, 13, 3, 33, 51, 463, 241, 1421, 1607, 3937, 3405, 26653, 33955, 97915}},
-{11889, 17, 52427, {1, 3, 7, 13, 29, 17, 41, 193, 461, 787, 459, 4019, 1887, 13831, 9387, 25215, 69801}},
-{11890, 17, 52432, {1, 3, 1, 11, 31, 55, 13, 235, 85, 953, 109, 233, 1893, 13225, 26165, 59237, 15845}},
-{11891, 17, 52438, {1, 1, 1, 13, 11, 43, 127, 193, 143, 831, 875, 2471, 7011, 3063, 21979, 42113, 80581}},
-{11892, 17, 52444, {1, 3, 7, 1, 5, 1, 63, 55, 349, 525, 441, 2695, 3301, 15737, 13355, 16727, 25001}},
-{11893, 17, 52457, {1, 3, 7, 7, 31, 23, 87, 99, 331, 101, 1341, 3, 1447, 9507, 18627, 2503, 57597}},
-{11894, 17, 52468, {1, 1, 1, 9, 11, 19, 89, 141, 269, 31, 1933, 429, 7765, 5905, 15327, 25913, 17281}},
-{11895, 17, 52480, {1, 3, 1, 9, 23, 61, 75, 15, 121, 635, 1409, 615, 7841, 11993, 1637, 26073, 70763}},
-{11896, 17, 52498, {1, 3, 3, 1, 5, 63, 85, 3, 443, 87, 1201, 275, 3457, 16187, 26839, 16593, 36335}},
-{11897, 17, 52516, {1, 1, 5, 5, 27, 61, 1, 145, 287, 563, 1135, 2703, 733, 10209, 3937, 23807, 56857}},
-{11898, 17, 52520, {1, 3, 3, 7, 1, 41, 97, 155, 305, 395, 1607, 1171, 1061, 12301, 8041, 12111, 66831}},
-{11899, 17, 52525, {1, 3, 7, 15, 9, 61, 127, 225, 125, 231, 87, 2433, 6951, 2999, 24859, 61685, 111943}},
-{11900, 17, 52531, {1, 3, 5, 15, 13, 39, 87, 57, 305, 469, 1929, 1559, 1383, 2779, 3883, 845, 45181}},
-{11901, 17, 52540, {1, 1, 1, 15, 19, 1, 23, 41, 207, 731, 501, 1147, 6543, 5011, 483, 56889, 48993}},
-{11902, 17, 52545, {1, 3, 3, 15, 21, 35, 75, 129, 441, 497, 953, 201, 6849, 2893, 6351, 62163, 84127}},
-{11903, 17, 52546, {1, 1, 1, 9, 21, 31, 91, 79, 345, 649, 1529, 805, 4931, 12887, 30167, 52305, 92561}},
-{11904, 17, 52552, {1, 1, 5, 1, 3, 21, 121, 223, 67, 185, 801, 889, 7443, 8419, 19929, 11451, 11487}},
-{11905, 17, 52557, {1, 1, 3, 15, 21, 51, 119, 31, 197, 773, 617, 2055, 799, 9105, 12353, 33635, 27589}},
-{11906, 17, 52569, {1, 3, 5, 3, 27, 11, 41, 105, 289, 877, 1175, 3111, 3161, 12537, 18001, 38061, 59089}},
-{11907, 17, 52575, {1, 3, 3, 5, 3, 27, 101, 253, 225, 915, 1757, 1601, 3391, 10443, 3983, 58427, 93391}},
-{11908, 17, 52582, {1, 3, 1, 7, 9, 43, 85, 115, 169, 285, 1267, 3791, 2701, 5599, 10099, 48105, 45219}},
-{11909, 17, 52594, {1, 1, 7, 13, 25, 57, 35, 223, 265, 451, 1913, 2715, 8017, 3725, 7079, 34611, 61159}},
-{11910, 17, 52615, {1, 1, 3, 7, 23, 27, 93, 195, 449, 845, 865, 655, 4263, 12743, 7467, 7929, 7095}},
-{11911, 17, 52619, {1, 3, 5, 5, 29, 51, 109, 123, 227, 693, 2033, 3829, 7187, 4027, 17861, 45093, 7355}},
-{11912, 17, 52624, {1, 1, 1, 11, 27, 31, 127, 75, 443, 479, 865, 1377, 711, 3791, 27235, 17405, 25975}},
-{11913, 17, 52645, {1, 3, 5, 7, 1, 49, 79, 167, 471, 453, 211, 265, 8163, 6517, 3413, 17283, 51961}},
-{11914, 17, 52663, {1, 3, 1, 5, 17, 29, 15, 239, 385, 239, 425, 2197, 3553, 14913, 14889, 31645, 67477}},
-{11915, 17, 52664, {1, 3, 3, 5, 1, 11, 25, 105, 367, 253, 1395, 2077, 2613, 4535, 18215, 37657, 48283}},
-{11916, 17, 52675, {1, 3, 3, 1, 1, 41, 7, 161, 437, 659, 833, 3175, 2063, 14497, 6655, 8817, 127321}},
-{11917, 17, 52687, {1, 3, 1, 11, 17, 27, 3, 51, 75, 183, 1889, 287, 5429, 14007, 14445, 47395, 94543}},
-{11918, 17, 52696, {1, 1, 7, 13, 29, 9, 109, 19, 73, 3, 1529, 457, 6413, 4113, 14733, 24455, 44623}},
-{11919, 17, 52701, {1, 3, 1, 15, 15, 31, 83, 25, 263, 229, 1801, 377, 1703, 8571, 10393, 52021, 100937}},
-{11920, 17, 52706, {1, 3, 5, 9, 25, 57, 79, 19, 117, 437, 275, 3439, 6393, 2111, 8317, 3521, 96927}},
-{11921, 17, 52708, {1, 3, 1, 13, 27, 43, 103, 171, 361, 949, 347, 809, 5819, 2763, 10447, 35129, 46985}},
-{11922, 17, 52711, {1, 3, 5, 11, 17, 1, 27, 37, 473, 851, 1057, 831, 4373, 5179, 18193, 48731, 64317}},
-{11923, 17, 52726, {1, 3, 1, 7, 17, 5, 19, 217, 439, 549, 1983, 2473, 6059, 5271, 10279, 7793, 114357}},
-{11924, 17, 52748, {1, 3, 1, 5, 25, 19, 99, 65, 507, 527, 825, 2517, 2299, 1725, 9913, 5779, 12207}},
-{11925, 17, 52754, {1, 3, 1, 1, 29, 41, 119, 27, 411, 475, 461, 1885, 2339, 4945, 24665, 13621, 78129}},
-{11926, 17, 52756, {1, 3, 1, 11, 27, 29, 119, 155, 487, 29, 1545, 675, 1417, 6119, 12451, 21345, 39377}},
-{11927, 17, 52759, {1, 1, 3, 7, 19, 5, 111, 227, 49, 307, 549, 737, 4793, 13885, 22971, 18653, 69573}},
-{11928, 17, 52769, {1, 3, 3, 1, 27, 59, 87, 7, 379, 497, 903, 591, 6105, 1957, 25849, 55957, 120181}},
-{11929, 17, 52784, {1, 3, 5, 15, 19, 31, 43, 1, 35, 341, 311, 1343, 3625, 16181, 31047, 59679, 89231}},
-{11930, 17, 52790, {1, 1, 1, 15, 21, 19, 93, 229, 49, 597, 1465, 2027, 5935, 12269, 20239, 17861, 26311}},
-{11931, 17, 52804, {1, 1, 1, 1, 3, 31, 115, 87, 129, 419, 871, 2469, 3807, 4473, 25025, 36923, 67959}},
-{11932, 17, 52807, {1, 1, 1, 3, 23, 31, 41, 247, 295, 369, 1131, 2183, 8097, 7609, 4387, 37565, 50177}},
-{11933, 17, 52808, {1, 3, 1, 11, 9, 17, 111, 249, 417, 775, 217, 1435, 6295, 5065, 2967, 55361, 91933}},
-{11934, 17, 52819, {1, 3, 5, 7, 19, 21, 71, 219, 411, 31, 335, 2915, 3687, 5691, 12405, 34659, 76721}},
-{11935, 17, 52826, {1, 3, 5, 13, 29, 31, 95, 203, 149, 399, 547, 2529, 2485, 3371, 20219, 33647, 34217}},
-{11936, 17, 52828, {1, 3, 5, 13, 31, 41, 97, 115, 427, 35, 1319, 2335, 715, 2541, 4507, 49395, 33895}},
-{11937, 17, 52832, {1, 3, 7, 15, 3, 49, 3, 49, 153, 93, 1343, 1035, 5685, 15855, 15751, 27663, 99553}},
-{11938, 17, 52835, {1, 1, 7, 5, 27, 7, 53, 135, 453, 981, 1767, 3503, 1259, 11973, 23259, 41051, 96593}},
-{11939, 17, 52849, {1, 1, 7, 9, 5, 59, 57, 141, 41, 639, 1681, 145, 7019, 6621, 14221, 12051, 71871}},
-{11940, 17, 52859, {1, 1, 3, 1, 13, 39, 7, 187, 7, 919, 1555, 2111, 6507, 2099, 10643, 22851, 82033}},
-{11941, 17, 52877, {1, 3, 7, 9, 25, 59, 27, 225, 239, 715, 1115, 2309, 7785, 11849, 8991, 54305, 107305}},
-{11942, 17, 52880, {1, 1, 7, 11, 21, 51, 1, 223, 481, 195, 2005, 2651, 6797, 12201, 11013, 1843, 65167}},
-{11943, 17, 52896, {1, 3, 3, 11, 27, 3, 117, 5, 255, 595, 399, 1329, 1437, 12061, 32679, 16655, 76235}},
-{11944, 17, 52899, {1, 1, 7, 13, 21, 1, 35, 159, 329, 37, 1247, 2663, 3889, 14603, 25799, 45363, 87963}},
-{11945, 17, 52905, {1, 1, 7, 7, 7, 11, 53, 215, 351, 329, 1039, 969, 4449, 14785, 28617, 25953, 78663}},
-{11946, 17, 52913, {1, 1, 7, 7, 27, 17, 19, 223, 143, 433, 789, 1941, 5527, 711, 25097, 4571, 121975}},
-{11947, 17, 52933, {1, 3, 1, 13, 11, 47, 31, 249, 325, 1003, 509, 2741, 3953, 1691, 12661, 16097, 80211}},
-{11948, 17, 52934, {1, 3, 7, 9, 27, 11, 21, 129, 25, 57, 1523, 3631, 2639, 2541, 14249, 34539, 70551}},
-{11949, 17, 52938, {1, 1, 5, 3, 31, 47, 47, 73, 71, 783, 1353, 2157, 2563, 14015, 997, 31611, 118649}},
-{11950, 17, 52957, {1, 1, 5, 5, 25, 35, 25, 207, 349, 503, 121, 3455, 5783, 10899, 12745, 35117, 36679}},
-{11951, 17, 52979, {1, 3, 1, 3, 11, 39, 123, 177, 19, 441, 1979, 1257, 1351, 4253, 15145, 44559, 59379}},
-{11952, 17, 52981, {1, 3, 7, 3, 7, 35, 41, 203, 439, 1013, 1055, 1165, 1043, 11183, 1795, 31253, 113693}},
-{11953, 17, 52986, {1, 3, 1, 13, 7, 43, 57, 1, 229, 345, 631, 841, 7923, 5971, 20489, 47917, 66833}},
-{11954, 17, 53005, {1, 1, 1, 15, 27, 5, 31, 117, 153, 755, 1207, 619, 8185, 4329, 9979, 57255, 79045}},
-{11955, 17, 53008, {1, 3, 3, 7, 23, 1, 7, 227, 337, 417, 1895, 765, 7799, 13599, 27253, 4485, 112391}},
-{11956, 17, 53024, {1, 3, 5, 13, 27, 63, 5, 87, 101, 351, 953, 2235, 1587, 5479, 26529, 34165, 83303}},
-{11957, 17, 53029, {1, 1, 5, 15, 1, 43, 63, 193, 143, 711, 1779, 3531, 1355, 16253, 14595, 32343, 131021}},
-{11958, 17, 53054, {1, 1, 1, 9, 29, 37, 29, 71, 11, 877, 1301, 2415, 5593, 1855, 25223, 6805, 12901}},
-{11959, 17, 53073, {1, 1, 7, 9, 31, 5, 49, 63, 185, 373, 129, 1695, 7841, 4477, 17809, 42771, 120221}},
-{11960, 17, 53083, {1, 1, 5, 3, 15, 43, 49, 45, 47, 775, 699, 2787, 7831, 4189, 18317, 63933, 83669}},
-{11961, 17, 53086, {1, 3, 5, 3, 23, 33, 85, 255, 119, 685, 1245, 1647, 1999, 13063, 9241, 49017, 32619}},
-{11962, 17, 53095, {1, 1, 7, 15, 29, 15, 125, 233, 189, 411, 1251, 3459, 7213, 10081, 4403, 56819, 17103}},
-{11963, 17, 53102, {1, 3, 3, 11, 21, 13, 93, 125, 213, 793, 1057, 2363, 661, 12213, 2259, 3787, 91451}},
-{11964, 17, 53107, {1, 3, 5, 5, 19, 35, 5, 153, 507, 691, 1743, 1777, 7579, 14229, 10155, 18529, 35945}},
-{11965, 17, 53126, {1, 3, 7, 5, 27, 35, 13, 77, 189, 793, 877, 643, 2787, 5817, 22589, 58363, 49059}},
-{11966, 17, 53130, {1, 3, 7, 9, 9, 37, 21, 251, 119, 895, 1023, 91, 4317, 10943, 7355, 36961, 36903}},
-{11967, 17, 53138, {1, 3, 3, 13, 19, 49, 15, 105, 399, 29, 1903, 3503, 3453, 15429, 31503, 57815, 34009}},
-{11968, 17, 53144, {1, 1, 5, 1, 19, 35, 49, 97, 335, 665, 1871, 887, 4713, 517, 9571, 41601, 9673}},
-{11969, 17, 53156, {1, 3, 5, 13, 29, 45, 111, 233, 251, 407, 1135, 2791, 6525, 11633, 22295, 65381, 117511}},
-{11970, 17, 53163, {1, 1, 3, 3, 17, 7, 65, 43, 391, 91, 315, 3559, 479, 7337, 25629, 785, 19855}},
-{11971, 17, 53165, {1, 1, 5, 9, 29, 31, 67, 17, 381, 875, 1001, 415, 2263, 4415, 11263, 309, 117623}},
-{11972, 17, 53173, {1, 1, 7, 11, 25, 1, 59, 61, 247, 649, 687, 907, 1037, 13935, 7229, 39769, 92755}},
-{11973, 17, 53177, {1, 3, 5, 15, 21, 51, 27, 79, 343, 785, 1567, 1349, 7991, 8531, 11243, 61351, 21297}},
-{11974, 17, 53183, {1, 1, 1, 3, 31, 41, 67, 169, 83, 959, 813, 1953, 2467, 12369, 31431, 50761, 75731}},
-{11975, 17, 53192, {1, 1, 5, 11, 25, 37, 83, 163, 3, 161, 1249, 3009, 7167, 5473, 10561, 44899, 130879}},
-{11976, 17, 53195, {1, 1, 7, 11, 9, 61, 61, 113, 81, 205, 731, 3887, 5525, 13415, 25181, 11557, 59343}},
-{11977, 17, 53200, {1, 3, 7, 5, 19, 27, 107, 89, 295, 715, 1439, 1285, 5813, 8895, 7233, 32905, 3273}},
-{11978, 17, 53212, {1, 1, 5, 1, 29, 11, 125, 253, 445, 295, 1721, 1271, 2203, 2215, 7613, 55655, 112157}},
-{11979, 17, 53219, {1, 1, 5, 11, 11, 13, 111, 55, 19, 551, 1365, 477, 2513, 12311, 22485, 23291, 92447}},
-{11980, 17, 53221, {1, 1, 7, 11, 9, 5, 3, 109, 507, 441, 1767, 1781, 3077, 219, 29293, 21237, 71159}},
-{11981, 17, 53245, {1, 1, 3, 11, 3, 45, 99, 113, 367, 569, 1907, 1281, 51, 13693, 14639, 32999, 77461}},
-{11982, 17, 53254, {1, 3, 5, 11, 5, 19, 97, 11, 473, 937, 1623, 1507, 3245, 9331, 16005, 37505, 40085}},
-{11983, 17, 53257, {1, 1, 7, 13, 21, 61, 103, 111, 35, 141, 61, 1043, 1989, 1311, 29021, 2617, 89915}},
-{11984, 17, 53265, {1, 3, 7, 15, 19, 31, 39, 175, 371, 459, 1293, 1645, 1125, 1199, 4811, 55721, 76071}},
-{11985, 17, 53266, {1, 1, 7, 3, 3, 35, 17, 7, 91, 317, 1615, 3559, 191, 2579, 15027, 58711, 36009}},
-{11986, 17, 53268, {1, 1, 1, 13, 1, 27, 45, 87, 443, 443, 853, 3917, 1437, 4053, 14861, 2897, 109853}},
-{11987, 17, 53275, {1, 1, 5, 3, 21, 47, 73, 195, 115, 517, 1781, 2341, 805, 5679, 12053, 29113, 100479}},
-{11988, 17, 53277, {1, 1, 7, 1, 25, 27, 61, 167, 203, 57, 527, 1071, 7131, 8403, 9943, 11503, 33081}},
-{11989, 17, 53284, {1, 1, 5, 13, 31, 43, 35, 195, 177, 229, 1401, 4011, 2363, 15787, 21125, 32103, 62337}},
-{11990, 17, 53294, {1, 1, 5, 11, 19, 13, 3, 249, 119, 35, 747, 1419, 5451, 13043, 19813, 54859, 94825}},
-{11991, 17, 53308, {1, 3, 1, 9, 17, 13, 51, 125, 391, 157, 1199, 1805, 1763, 11831, 20915, 38547, 14221}},
-{11992, 17, 53314, {1, 1, 7, 1, 23, 61, 25, 69, 435, 183, 1379, 1211, 5529, 9447, 4575, 14127, 91867}},
-{11993, 17, 53319, {1, 3, 3, 15, 11, 15, 101, 135, 419, 685, 1097, 787, 2045, 3393, 26221, 23653, 116917}},
-{11994, 17, 53326, {1, 3, 1, 11, 29, 23, 13, 153, 27, 683, 1569, 413, 261, 10291, 23763, 15579, 39337}},
-{11995, 17, 53328, {1, 3, 7, 7, 19, 23, 121, 23, 339, 165, 1137, 2791, 319, 16111, 14847, 28171, 79237}},
-{11996, 17, 53340, {1, 3, 1, 5, 9, 59, 33, 19, 191, 707, 1883, 1683, 1161, 12905, 12299, 22201, 19811}},
-{11997, 17, 53364, {1, 3, 1, 3, 27, 11, 69, 199, 415, 251, 1079, 1709, 4539, 7867, 21321, 33617, 53459}},
-{11998, 17, 53367, {1, 1, 3, 9, 19, 59, 21, 95, 275, 213, 1819, 721, 6271, 11845, 9573, 16105, 12755}},
-{11999, 17, 53377, {1, 1, 1, 15, 23, 7, 91, 235, 43, 95, 913, 715, 3229, 12339, 23089, 30963, 129525}},
-{12000, 17, 53395, {1, 1, 7, 9, 7, 41, 43, 131, 485, 621, 1293, 1955, 5215, 6545, 29225, 53587, 46901}},
-{12001, 17, 53398, {1, 3, 1, 5, 7, 57, 97, 199, 225, 707, 1223, 1829, 497, 12587, 24551, 12907, 82411}},
-{12002, 17, 53407, {1, 1, 3, 7, 21, 9, 63, 15, 263, 957, 155, 4021, 4455, 2025, 16981, 19743, 88619}},
-{12003, 17, 53413, {1, 1, 7, 5, 31, 3, 27, 45, 369, 747, 1559, 1429, 8049, 15069, 19897, 50067, 52861}},
-{12004, 17, 53414, {1, 1, 5, 13, 23, 35, 91, 139, 73, 275, 207, 2709, 3801, 12755, 19155, 61629, 5513}},
-{12005, 17, 53417, {1, 1, 5, 7, 5, 25, 33, 45, 325, 847, 81, 891, 3191, 14115, 25095, 39867, 3839}},
-{12006, 17, 53443, {1, 3, 5, 13, 9, 31, 31, 113, 507, 833, 691, 2041, 4873, 81, 21365, 35265, 37627}},
-{12007, 17, 53473, {1, 1, 5, 13, 9, 51, 127, 131, 285, 683, 593, 3411, 6685, 3601, 12255, 8337, 80597}},
-{12008, 17, 53476, {1, 1, 5, 15, 29, 13, 79, 199, 157, 421, 1697, 2063, 2213, 4141, 21045, 45785, 124023}},
-{12009, 17, 53480, {1, 3, 1, 11, 19, 5, 79, 57, 71, 373, 487, 671, 3671, 9093, 20989, 48477, 104951}},
-{12010, 17, 53486, {1, 3, 5, 15, 13, 7, 39, 243, 507, 739, 1905, 3431, 4141, 9345, 27877, 64735, 112997}},
-{12011, 17, 53506, {1, 3, 3, 5, 17, 25, 31, 243, 393, 61, 199, 2825, 6981, 5887, 22289, 9201, 77689}},
-{12012, 17, 53542, {1, 3, 5, 15, 15, 63, 77, 39, 463, 883, 671, 3285, 6925, 15085, 1665, 64005, 130619}},
-{12013, 17, 53546, {1, 3, 3, 11, 21, 15, 7, 115, 9, 879, 1097, 3993, 3929, 9809, 22105, 9549, 31819}},
-{12014, 17, 53554, {1, 1, 7, 15, 3, 9, 19, 97, 327, 105, 1915, 205, 3873, 1229, 29915, 57375, 108217}},
-{12015, 17, 53563, {1, 1, 3, 11, 29, 41, 77, 11, 183, 73, 1651, 3739, 3911, 8695, 15339, 19293, 1827}},
-{12016, 17, 53580, {1, 1, 1, 5, 23, 49, 35, 175, 99, 49, 615, 1733, 6901, 2351, 18765, 55553, 99791}},
-{12017, 17, 53591, {1, 3, 7, 3, 25, 17, 67, 161, 507, 941, 35, 2619, 339, 791, 6485, 64277, 123867}},
-{12018, 17, 53598, {1, 1, 3, 13, 11, 9, 79, 193, 75, 391, 1753, 3537, 6971, 6607, 11933, 4447, 87793}},
-{12019, 17, 53611, {1, 1, 1, 5, 19, 9, 63, 203, 51, 395, 1365, 2393, 7265, 11709, 13721, 4519, 118765}},
-{12020, 17, 53621, {1, 1, 3, 9, 17, 53, 29, 103, 325, 973, 903, 785, 7535, 9951, 8121, 12603, 38679}},
-{12021, 17, 53625, {1, 3, 1, 7, 7, 63, 1, 123, 439, 181, 1373, 2705, 995, 10789, 7495, 54543, 120109}},
-{12022, 17, 53628, {1, 1, 7, 3, 17, 13, 79, 179, 165, 965, 1537, 3753, 3497, 12127, 6983, 48605, 113057}},
-{12023, 17, 53632, {1, 1, 5, 7, 3, 7, 41, 25, 267, 633, 19, 1317, 3445, 12377, 27881, 55249, 40841}},
-{12024, 17, 53650, {1, 3, 5, 1, 31, 55, 43, 129, 411, 281, 1, 851, 2419, 7943, 13721, 39371, 114557}},
-{12025, 17, 53655, {1, 1, 7, 7, 23, 19, 83, 37, 9, 161, 125, 3179, 7973, 9703, 23199, 32723, 130915}},
-{12026, 17, 53675, {1, 1, 7, 5, 27, 21, 11, 219, 403, 239, 1723, 2957, 3029, 9911, 10981, 35421, 74025}},
-{12027, 17, 53677, {1, 3, 1, 1, 31, 59, 69, 77, 395, 1, 157, 1259, 4913, 2089, 17619, 51033, 130899}},
-{12028, 17, 53680, {1, 3, 3, 3, 19, 11, 83, 237, 103, 921, 487, 1833, 8187, 3811, 18887, 9389, 80927}},
-{12029, 17, 53683, {1, 3, 7, 3, 17, 51, 107, 209, 187, 831, 1501, 1337, 803, 10361, 11347, 65291, 42219}},
-{12030, 17, 53700, {1, 3, 3, 15, 7, 29, 61, 25, 413, 257, 1185, 4009, 7463, 1839, 6645, 28389, 14449}},
-{12031, 17, 53709, {1, 3, 1, 9, 5, 31, 83, 55, 375, 399, 945, 997, 7649, 12631, 7691, 53325, 50173}},
-{12032, 17, 53724, {1, 1, 5, 9, 13, 9, 83, 37, 487, 975, 487, 3587, 7285, 7505, 10155, 673, 126505}},
-{12033, 17, 53731, {1, 3, 5, 7, 21, 3, 35, 21, 367, 323, 1579, 3351, 5465, 13719, 17033, 42573, 55079}},
-{12034, 17, 53733, {1, 3, 3, 15, 11, 27, 121, 109, 267, 855, 1417, 3839, 6535, 1051, 29355, 23815, 76031}},
-{12035, 17, 53738, {1, 1, 7, 9, 5, 31, 35, 53, 369, 137, 1545, 927, 825, 1333, 13637, 11003, 96963}},
-{12036, 17, 53762, {1, 1, 5, 3, 29, 41, 31, 85, 35, 477, 227, 3325, 1213, 681, 14591, 31325, 12199}},
-{12037, 17, 53767, {1, 3, 7, 11, 11, 11, 33, 255, 335, 747, 855, 31, 6101, 293, 20423, 47521, 62573}},
-{12038, 17, 53785, {1, 1, 1, 15, 31, 15, 33, 175, 321, 441, 1197, 3579, 4989, 9275, 30485, 1077, 122947}},
-{12039, 17, 53786, {1, 3, 5, 15, 23, 21, 127, 223, 249, 373, 1309, 1469, 5701, 9097, 29897, 26627, 38489}},
-{12040, 17, 53795, {1, 3, 7, 3, 3, 35, 83, 149, 259, 315, 1467, 1953, 6035, 7961, 10901, 25171, 130713}},
-{12041, 17, 53802, {1, 1, 3, 9, 7, 63, 55, 33, 375, 421, 151, 1721, 1999, 14937, 17539, 48323, 97345}},
-{12042, 17, 53812, {1, 1, 5, 5, 3, 21, 47, 19, 227, 131, 1591, 3779, 929, 13879, 13489, 19805, 20135}},
-{12043, 17, 53821, {1, 1, 7, 1, 31, 25, 87, 125, 213, 135, 809, 3067, 5035, 7407, 2193, 31423, 123973}},
-{12044, 17, 53827, {1, 3, 5, 13, 17, 19, 77, 169, 345, 115, 227, 649, 3609, 15063, 1895, 17533, 95859}},
-{12045, 17, 53833, {1, 3, 5, 15, 17, 29, 17, 11, 145, 601, 1871, 851, 8161, 14029, 10039, 4247, 62393}},
-{12046, 17, 53841, {1, 1, 7, 13, 25, 5, 49, 231, 261, 71, 335, 4081, 7915, 11367, 17087, 26041, 128737}},
-{12047, 17, 53848, {1, 1, 1, 13, 13, 21, 77, 113, 373, 1005, 109, 2877, 3001, 15011, 2465, 37015, 69049}},
-{12048, 17, 53869, {1, 1, 3, 15, 31, 33, 119, 121, 41, 9, 1567, 577, 1687, 12117, 17049, 675, 10729}},
-{12049, 17, 53897, {1, 3, 5, 11, 31, 7, 47, 41, 127, 81, 273, 1649, 975, 3953, 17021, 24163, 12599}},
-{12050, 17, 53905, {1, 3, 1, 3, 27, 41, 75, 237, 317, 85, 1995, 2255, 2191, 6441, 26629, 25797, 97681}},
-{12051, 17, 53912, {1, 1, 1, 3, 11, 5, 31, 109, 227, 977, 59, 793, 3305, 10905, 16529, 21345, 2403}},
-{12052, 17, 53921, {1, 3, 5, 9, 9, 37, 107, 129, 421, 383, 1415, 885, 3383, 9547, 7303, 41745, 59919}},
-{12053, 17, 53928, {1, 1, 7, 7, 29, 27, 59, 177, 97, 299, 1019, 1393, 7763, 5715, 9253, 58035, 23431}},
-{12054, 17, 53948, {1, 3, 3, 3, 23, 13, 51, 101, 75, 857, 1699, 2687, 3983, 10427, 19845, 49503, 96033}},
-{12055, 17, 53954, {1, 1, 1, 7, 21, 51, 25, 71, 265, 999, 1259, 625, 775, 11045, 20769, 42597, 115521}},
-{12056, 17, 53968, {1, 3, 1, 13, 25, 47, 21, 245, 201, 667, 1193, 1087, 407, 6057, 14929, 35291, 57615}},
-{12057, 17, 53977, {1, 1, 1, 7, 27, 25, 93, 85, 321, 1009, 1045, 1901, 349, 11393, 10917, 10413, 94125}},
-{12058, 17, 53983, {1, 1, 1, 15, 3, 63, 59, 51, 307, 135, 785, 1921, 6921, 5689, 8487, 21061, 69903}},
-{12059, 17, 53984, {1, 3, 7, 1, 13, 47, 59, 155, 107, 573, 843, 2849, 6685, 5927, 31747, 21541, 94271}},
-{12060, 17, 54002, {1, 1, 7, 15, 23, 7, 85, 169, 209, 527, 1027, 3745, 4773, 14893, 10789, 1243, 87133}},
-{12061, 17, 54007, {1, 1, 5, 9, 1, 1, 53, 57, 245, 899, 1785, 1951, 7651, 10909, 30167, 40789, 66965}},
-{12062, 17, 54013, {1, 1, 1, 7, 17, 33, 65, 79, 455, 677, 157, 1313, 1573, 9697, 4161, 4609, 42783}},
-{12063, 17, 54014, {1, 3, 7, 7, 27, 15, 109, 113, 239, 521, 563, 2493, 1471, 15817, 14515, 48465, 66009}},
-{12064, 17, 54021, {1, 3, 5, 3, 29, 33, 125, 169, 483, 593, 1665, 657, 3799, 15829, 29591, 25813, 40987}},
-{12065, 17, 54026, {1, 3, 1, 11, 15, 25, 21, 215, 341, 241, 1599, 3807, 6633, 15137, 15377, 56881, 47499}},
-{12066, 17, 54028, {1, 3, 3, 3, 15, 49, 89, 117, 191, 641, 675, 2671, 4243, 1617, 20261, 42669, 119173}},
-{12067, 17, 54031, {1, 1, 1, 13, 13, 43, 73, 103, 183, 239, 555, 2121, 4889, 1431, 20601, 21545, 11809}},
-{12068, 17, 54036, {1, 3, 1, 9, 9, 9, 121, 51, 77, 455, 1481, 427, 1961, 12149, 21273, 16295, 21909}},
-{12069, 17, 54067, {1, 1, 5, 11, 19, 55, 37, 63, 493, 663, 945, 2191, 2491, 11545, 7407, 36295, 94293}},
-{12070, 17, 54069, {1, 3, 5, 15, 25, 35, 103, 33, 171, 425, 409, 5, 2519, 2239, 30557, 20007, 69079}},
-{12071, 17, 54074, {1, 1, 5, 11, 13, 29, 71, 21, 35, 833, 191, 365, 7013, 12413, 10227, 56705, 61705}},
-{12072, 17, 54076, {1, 1, 1, 1, 21, 13, 87, 113, 63, 537, 283, 925, 2147, 1683, 31239, 2775, 131021}},
-{12073, 17, 54105, {1, 1, 3, 9, 23, 1, 117, 19, 487, 235, 877, 149, 369, 9615, 12501, 60175, 35741}},
-{12074, 17, 54111, {1, 1, 7, 9, 5, 25, 107, 199, 339, 755, 245, 2861, 1119, 14683, 2221, 5227, 81479}},
-{12075, 17, 54118, {1, 1, 1, 15, 5, 15, 37, 63, 511, 219, 783, 3245, 5563, 13231, 22311, 16803, 10393}},
-{12076, 17, 54129, {1, 3, 7, 5, 1, 15, 9, 21, 287, 991, 555, 771, 7683, 1661, 6553, 43735, 118713}},
-{12077, 17, 54145, {1, 3, 1, 3, 3, 29, 119, 157, 13, 599, 537, 2921, 5207, 11621, 1515, 6351, 118429}},
-{12078, 17, 54157, {1, 1, 5, 1, 27, 39, 111, 117, 481, 25, 549, 913, 6427, 7703, 23099, 50501, 7617}},
-{12079, 17, 54158, {1, 1, 7, 5, 29, 63, 43, 151, 63, 43, 197, 3165, 3879, 12435, 461, 64475, 60597}},
-{12080, 17, 54163, {1, 3, 1, 11, 31, 35, 59, 207, 387, 441, 1293, 2117, 3751, 12653, 2811, 42585, 33297}},
-{12081, 17, 54166, {1, 3, 7, 15, 27, 47, 13, 15, 135, 433, 615, 1, 171, 11503, 27117, 64635, 122191}},
-{12082, 17, 54172, {1, 1, 7, 1, 23, 23, 107, 135, 311, 395, 373, 2771, 81, 12513, 16739, 6715, 94999}},
-{12083, 17, 54185, {1, 3, 5, 7, 19, 9, 21, 139, 307, 231, 65, 59, 7767, 2897, 3503, 58163, 48807}},
-{12084, 17, 54186, {1, 3, 5, 13, 23, 5, 51, 247, 125, 911, 1395, 1337, 3215, 15811, 12729, 21495, 22597}},
-{12085, 17, 54188, {1, 3, 5, 5, 1, 19, 123, 125, 197, 533, 1699, 1397, 3473, 15201, 24493, 3395, 98261}},
-{12086, 17, 54208, {1, 1, 3, 7, 29, 39, 69, 97, 353, 293, 1103, 543, 5015, 9913, 6965, 61921, 122073}},
-{12087, 17, 54223, {1, 1, 3, 13, 19, 41, 117, 253, 449, 231, 865, 3055, 4751, 3277, 22863, 3249, 38359}},
-{12088, 17, 54237, {1, 3, 5, 13, 9, 7, 107, 17, 251, 501, 1925, 3733, 5035, 13213, 12535, 13705, 73047}},
-{12089, 17, 54241, {1, 3, 7, 5, 23, 5, 83, 45, 457, 667, 913, 1167, 7063, 10915, 10911, 20501, 61823}},
-{12090, 17, 54244, {1, 3, 3, 13, 7, 15, 29, 223, 503, 713, 667, 3989, 5927, 5909, 27633, 17615, 97931}},
-{12091, 17, 54259, {1, 3, 7, 13, 19, 53, 25, 41, 311, 327, 1323, 3361, 1095, 12701, 1065, 34155, 34705}},
-{12092, 17, 54273, {1, 1, 7, 7, 11, 35, 63, 73, 179, 477, 467, 4043, 3097, 16089, 12749, 18233, 50299}},
-{12093, 17, 54276, {1, 3, 3, 13, 5, 27, 31, 207, 357, 469, 607, 961, 7393, 6707, 25833, 22337, 119083}},
-{12094, 17, 54280, {1, 1, 3, 3, 7, 53, 47, 55, 267, 107, 1307, 2151, 793, 15605, 12153, 13075, 76529}},
-{12095, 17, 54294, {1, 3, 5, 1, 13, 35, 63, 191, 375, 221, 1603, 2049, 5363, 1481, 32271, 22635, 118603}},
-{12096, 17, 54298, {1, 1, 1, 11, 17, 63, 13, 3, 353, 943, 443, 141, 7441, 12335, 4499, 15923, 63677}},
-{12097, 17, 54303, {1, 3, 7, 13, 21, 51, 125, 61, 203, 1, 707, 3893, 4627, 3125, 14629, 62721, 85101}},
-{12098, 17, 54304, {1, 1, 3, 5, 31, 23, 63, 241, 41, 721, 599, 1761, 2593, 1685, 31247, 7811, 87561}},
-{12099, 17, 54309, {1, 1, 7, 9, 7, 53, 51, 9, 303, 675, 1261, 1591, 4363, 15, 29723, 54533, 103869}},
-{12100, 17, 54310, {1, 3, 5, 7, 27, 21, 103, 113, 463, 379, 635, 2363, 607, 11445, 22475, 58433, 93071}},
-{12101, 17, 54316, {1, 1, 5, 5, 5, 63, 23, 67, 399, 279, 829, 945, 6545, 14951, 5135, 22889, 87625}},
-{12102, 17, 54336, {1, 1, 7, 15, 1, 59, 69, 123, 169, 821, 1125, 2051, 3375, 11691, 1379, 57461, 124209}},
-{12103, 17, 54354, {1, 1, 5, 15, 31, 57, 51, 59, 297, 459, 701, 241, 2801, 11893, 4007, 13165, 79403}},
-{12104, 17, 54359, {1, 1, 5, 9, 11, 41, 79, 47, 19, 529, 21, 1871, 371, 6269, 7433, 36183, 96113}},
-{12105, 17, 54375, {1, 1, 7, 5, 29, 3, 33, 191, 119, 501, 1637, 2903, 3347, 4581, 17407, 18169, 10595}},
-{12106, 17, 54376, {1, 3, 5, 11, 9, 35, 95, 193, 413, 727, 1157, 3331, 5993, 1781, 22653, 3975, 110557}},
-{12107, 17, 54381, {1, 1, 1, 1, 23, 5, 35, 65, 57, 515, 569, 4031, 7983, 4603, 29419, 44847, 63601}},
-{12108, 17, 54390, {1, 3, 1, 7, 21, 5, 77, 23, 317, 803, 723, 3229, 7171, 2883, 10943, 50323, 108579}},
-{12109, 17, 54396, {1, 3, 5, 11, 15, 53, 75, 127, 177, 19, 501, 1201, 5113, 9069, 8817, 14725, 104737}},
-{12110, 17, 54399, {1, 3, 7, 9, 7, 39, 5, 121, 409, 103, 1075, 451, 7603, 16023, 32557, 43159, 94385}},
-{12111, 17, 54409, {1, 3, 1, 11, 29, 57, 123, 141, 57, 945, 1777, 2427, 2359, 12839, 7325, 7945, 129811}},
-{12112, 17, 54424, {1, 3, 5, 15, 5, 3, 17, 55, 467, 61, 131, 2891, 6331, 5859, 20437, 49425, 80731}},
-{12113, 17, 54434, {1, 1, 1, 15, 29, 13, 127, 181, 361, 1019, 1675, 2755, 6533, 8957, 14691, 4285, 65459}},
-{12114, 17, 54436, {1, 1, 7, 11, 23, 43, 111, 183, 103, 269, 229, 3291, 1873, 11349, 29319, 64829, 19639}},
-{12115, 17, 54439, {1, 3, 7, 11, 15, 63, 1, 253, 489, 863, 1707, 2769, 3201, 7901, 18161, 12515, 130237}},
-{12116, 17, 54445, {1, 3, 1, 7, 1, 25, 43, 159, 505, 511, 1745, 1421, 6779, 11103, 23535, 61129, 124571}},
-{12117, 17, 54448, {1, 1, 3, 13, 19, 33, 17, 243, 481, 617, 1061, 1891, 7165, 6821, 18505, 8965, 70179}},
-{12118, 17, 54457, {1, 1, 7, 13, 17, 17, 65, 23, 255, 361, 1873, 1605, 2041, 11119, 11419, 63131, 49207}},
-{12119, 17, 54465, {1, 1, 5, 13, 15, 57, 27, 223, 199, 529, 1115, 1513, 8083, 11713, 21005, 50741, 122223}},
-{12120, 17, 54471, {1, 3, 5, 15, 29, 35, 107, 85, 141, 505, 1553, 1283, 4581, 5077, 9461, 59853, 23219}},
-{12121, 17, 54472, {1, 3, 5, 11, 11, 45, 53, 195, 199, 773, 1911, 721, 1563, 3769, 3267, 30673, 80313}},
-{12122, 17, 54485, {1, 3, 7, 7, 21, 37, 9, 129, 431, 79, 1559, 2125, 7781, 6441, 23533, 46919, 25315}},
-{12123, 17, 54508, {1, 1, 5, 15, 11, 61, 77, 231, 349, 647, 225, 85, 6789, 12557, 6505, 21985, 54965}},
-{12124, 17, 54513, {1, 1, 5, 1, 19, 21, 33, 211, 347, 491, 1119, 1619, 3739, 11255, 26705, 59691, 35337}},
-{12125, 17, 54528, {1, 1, 3, 3, 29, 15, 7, 23, 279, 145, 699, 289, 475, 1681, 3201, 64477, 24919}},
-{12126, 17, 54534, {1, 1, 7, 7, 23, 53, 75, 71, 315, 403, 1521, 1417, 3749, 11243, 3951, 61039, 51143}},
-{12127, 17, 54537, {1, 3, 7, 3, 15, 21, 81, 219, 249, 387, 1405, 3495, 7143, 2599, 25435, 15259, 66069}},
-{12128, 17, 54540, {1, 1, 5, 7, 31, 9, 63, 55, 409, 421, 1851, 847, 1593, 10447, 2833, 13209, 47285}},
-{12129, 17, 54551, {1, 1, 3, 7, 15, 3, 35, 49, 253, 21, 1705, 357, 2751, 9671, 12429, 4549, 118691}},
-{12130, 17, 54561, {1, 1, 5, 15, 1, 3, 97, 197, 43, 923, 1273, 663, 4291, 12357, 28221, 15291, 60989}},
-{12131, 17, 54573, {1, 1, 7, 7, 15, 3, 35, 115, 449, 641, 743, 1855, 359, 10983, 2831, 43983, 56465}},
-{12132, 17, 54579, {1, 3, 7, 11, 1, 51, 69, 27, 29, 187, 1673, 1273, 7987, 1223, 8971, 53805, 4413}},
-{12133, 17, 54586, {1, 1, 3, 11, 1, 55, 91, 241, 35, 97, 1027, 3967, 703, 3535, 21681, 55825, 50423}},
-{12134, 17, 54591, {1, 1, 7, 11, 21, 53, 111, 125, 11, 355, 1585, 3603, 1705, 16311, 7045, 15503, 63625}},
-{12135, 17, 54596, {1, 1, 5, 15, 25, 47, 31, 29, 333, 361, 1831, 1545, 7751, 8679, 32453, 61755, 94637}},
-{12136, 17, 54599, {1, 1, 3, 3, 23, 3, 79, 11, 367, 551, 281, 1273, 5097, 12527, 473, 33855, 85783}},
-{12137, 17, 54605, {1, 1, 1, 15, 27, 21, 107, 121, 187, 495, 1877, 1957, 3647, 13263, 30729, 18131, 33689}},
-{12138, 17, 54613, {1, 1, 5, 13, 3, 43, 41, 53, 127, 299, 839, 3327, 7929, 9921, 29471, 18075, 34283}},
-{12139, 17, 54623, {1, 1, 7, 13, 31, 5, 59, 75, 335, 929, 379, 139, 7121, 9281, 31161, 3177, 2615}},
-{12140, 17, 54654, {1, 3, 7, 1, 11, 19, 81, 199, 425, 639, 497, 693, 1271, 7363, 10543, 52513, 130549}},
-{12141, 17, 54667, {1, 3, 3, 7, 21, 41, 101, 67, 363, 5, 1455, 1433, 81, 15609, 16231, 13285, 38995}},
-{12142, 17, 54681, {1, 1, 3, 15, 11, 19, 123, 177, 429, 27, 141, 3095, 5379, 2241, 29877, 59383, 25199}},
-{12143, 17, 54684, {1, 1, 7, 7, 19, 63, 93, 217, 279, 349, 149, 2479, 2355, 6475, 29993, 37941, 58715}},
-{12144, 17, 54687, {1, 3, 7, 3, 21, 23, 59, 177, 489, 817, 1209, 1629, 5805, 3137, 23767, 62967, 16609}},
-{12145, 17, 54694, {1, 3, 3, 7, 9, 55, 59, 31, 191, 891, 833, 1059, 3007, 2331, 385, 58247, 110697}},
-{12146, 17, 54706, {1, 1, 3, 3, 11, 61, 9, 189, 79, 621, 209, 2785, 2959, 4133, 20691, 45605, 117089}},
-{12147, 17, 54712, {1, 3, 3, 5, 5, 47, 31, 1, 451, 765, 2027, 2327, 1725, 14341, 7997, 6449, 77893}},
-{12148, 17, 54715, {1, 1, 7, 1, 7, 27, 27, 129, 227, 505, 1461, 783, 945, 12653, 17913, 61631, 41875}},
-{12149, 17, 54723, {1, 1, 1, 11, 13, 41, 41, 221, 483, 825, 451, 493, 1717, 10389, 7805, 37707, 30733}},
-{12150, 17, 54725, {1, 1, 5, 3, 31, 31, 75, 3, 323, 83, 563, 919, 7387, 1673, 6157, 7415, 14947}},
-{12151, 17, 54726, {1, 1, 7, 13, 19, 37, 29, 93, 153, 491, 1033, 1389, 6361, 11133, 20049, 24585, 107325}},
-{12152, 17, 54740, {1, 1, 1, 15, 3, 35, 79, 251, 383, 665, 2033, 3165, 3411, 15965, 28281, 56521, 56479}},
-{12153, 17, 54750, {1, 3, 1, 15, 23, 1, 87, 145, 443, 405, 635, 1597, 1455, 5983, 12741, 55133, 2815}},
-{12154, 17, 54760, {1, 1, 1, 13, 11, 25, 19, 129, 23, 913, 1121, 223, 1991, 13449, 30443, 50573, 108467}},
-{12155, 17, 54768, {1, 1, 7, 11, 29, 31, 49, 51, 415, 293, 173, 4091, 159, 2679, 30643, 58725, 109287}},
-{12156, 17, 54771, {1, 1, 1, 7, 15, 53, 69, 231, 387, 693, 1299, 1383, 7935, 10313, 22403, 59341, 3347}},
-{12157, 17, 54773, {1, 3, 3, 5, 9, 21, 111, 11, 469, 109, 1565, 3107, 2975, 12491, 26773, 33245, 27589}},
-{12158, 17, 54796, {1, 1, 3, 5, 3, 9, 103, 127, 345, 301, 857, 2035, 3269, 13819, 7555, 5197, 94557}},
-{12159, 17, 54801, {1, 3, 7, 3, 31, 3, 61, 253, 221, 359, 1281, 1405, 4819, 1329, 17773, 29539, 127043}},
-{12160, 17, 54808, {1, 1, 7, 11, 17, 47, 105, 253, 253, 531, 119, 2009, 6125, 9387, 13141, 29079, 28361}},
-{12161, 17, 54814, {1, 1, 3, 5, 21, 13, 21, 223, 79, 819, 1425, 1001, 6517, 8883, 29997, 30637, 7717}},
-{12162, 17, 54837, {1, 3, 1, 3, 1, 23, 113, 69, 235, 95, 1873, 689, 4611, 13209, 12681, 16057, 114071}},
-{12163, 17, 54847, {1, 3, 3, 13, 25, 21, 93, 55, 253, 373, 1659, 829, 6539, 7453, 28195, 33131, 92559}},
-{12164, 17, 54849, {1, 1, 3, 11, 25, 29, 81, 235, 429, 811, 1867, 2923, 5949, 4423, 93, 64631, 48357}},
-{12165, 17, 54864, {1, 3, 5, 13, 29, 27, 35, 15, 105, 849, 247, 3999, 6441, 12443, 19817, 49897, 21515}},
-{12166, 17, 54867, {1, 1, 5, 15, 13, 59, 3, 199, 267, 463, 655, 3875, 2895, 13411, 5081, 22069, 6053}},
-{12167, 17, 54889, {1, 1, 5, 9, 5, 13, 111, 83, 281, 543, 629, 1349, 1863, 9523, 19201, 39229, 78265}},
-{12168, 17, 54895, {1, 3, 7, 1, 29, 23, 109, 75, 347, 643, 97, 1981, 2797, 11201, 28355, 54105, 45551}},
-{12169, 17, 54907, {1, 3, 1, 7, 9, 5, 77, 17, 179, 957, 621, 779, 7117, 1491, 11563, 10131, 98335}},
-{12170, 17, 54919, {1, 3, 3, 1, 3, 53, 39, 217, 309, 105, 485, 3123, 3143, 2359, 4923, 22307, 120319}},
-{12171, 17, 54923, {1, 1, 7, 7, 11, 5, 65, 165, 321, 455, 625, 2417, 999, 14999, 6777, 13319, 43399}},
-{12172, 17, 54926, {1, 1, 7, 3, 11, 55, 43, 119, 135, 129, 581, 3593, 3475, 14667, 30509, 5007, 120135}},
-{12173, 17, 54940, {1, 1, 1, 11, 7, 17, 95, 169, 401, 87, 1425, 1821, 7619, 3605, 10993, 35837, 87311}},
-{12174, 17, 54950, {1, 1, 7, 11, 11, 35, 29, 63, 395, 301, 373, 2457, 6859, 1915, 11215, 41075, 78219}},
-{12175, 17, 54954, {1, 3, 5, 7, 25, 3, 97, 43, 273, 459, 103, 3441, 71, 10269, 29893, 46053, 104801}},
-{12176, 17, 54961, {1, 3, 3, 7, 31, 3, 121, 255, 73, 783, 977, 513, 6527, 1189, 8925, 23245, 22287}},
-{12177, 17, 54973, {1, 3, 3, 13, 15, 53, 51, 135, 465, 341, 263, 1687, 4085, 14257, 18745, 46945, 115475}},
-{12178, 17, 54974, {1, 3, 1, 5, 31, 1, 1, 91, 511, 771, 1501, 2613, 991, 3859, 28911, 65417, 201}},
-{12179, 17, 54976, {1, 1, 7, 1, 27, 21, 107, 153, 163, 949, 811, 3087, 3443, 5621, 28795, 58311, 63763}},
-{12180, 17, 54986, {1, 1, 7, 5, 29, 29, 57, 175, 29, 821, 1545, 2643, 725, 16225, 29111, 19675, 129995}},
-{12181, 17, 54993, {1, 1, 7, 3, 31, 31, 61, 155, 265, 323, 1829, 3891, 6393, 8573, 10627, 10839, 78683}},
-{12182, 17, 55000, {1, 3, 5, 7, 29, 7, 67, 181, 313, 731, 1761, 1681, 3673, 8939, 811, 48931, 82021}},
-{12183, 17, 55010, {1, 3, 1, 3, 11, 51, 81, 67, 173, 881, 855, 3627, 1613, 4825, 7035, 36261, 64899}},
-{12184, 17, 55019, {1, 3, 7, 7, 15, 53, 123, 41, 265, 817, 807, 3875, 7675, 16225, 13313, 62217, 47647}},
-{12185, 17, 55021, {1, 1, 3, 13, 23, 47, 125, 155, 403, 651, 1693, 2185, 5565, 9947, 20893, 11287, 118943}},
-{12186, 17, 55030, {1, 3, 7, 3, 19, 47, 69, 5, 209, 259, 367, 3929, 7579, 12687, 18109, 51885, 128281}},
-{12187, 17, 55033, {1, 1, 7, 5, 27, 41, 45, 41, 205, 1001, 1509, 2649, 1141, 5355, 10265, 34131, 112111}},
-{12188, 17, 55039, {1, 3, 7, 5, 19, 41, 103, 63, 49, 25, 271, 793, 3217, 4741, 2563, 61333, 113205}},
-{12189, 17, 55047, {1, 3, 3, 15, 15, 35, 13, 233, 277, 673, 545, 545, 7419, 6707, 1867, 58873, 110027}},
-{12190, 17, 55048, {1, 1, 7, 3, 9, 23, 67, 55, 3, 1019, 2001, 2909, 7311, 9295, 26953, 43217, 54597}},
-{12191, 17, 55054, {1, 3, 5, 7, 13, 33, 67, 27, 75, 569, 1777, 791, 1223, 1805, 19167, 60537, 60039}},
-{12192, 17, 55059, {1, 1, 5, 13, 15, 61, 49, 59, 289, 907, 1055, 3579, 8169, 12119, 25479, 32867, 65343}},
-{12193, 17, 55068, {1, 3, 5, 9, 5, 63, 91, 225, 377, 469, 891, 891, 5115, 11487, 30151, 44357, 120077}},
-{12194, 17, 55071, {1, 1, 1, 15, 29, 59, 19, 51, 295, 585, 149, 497, 5837, 11629, 7825, 18129, 113797}},
-{12195, 17, 55075, {1, 1, 3, 7, 31, 25, 77, 209, 183, 337, 1753, 2703, 2559, 11847, 17349, 27359, 21771}},
-{12196, 17, 55077, {1, 1, 7, 7, 13, 23, 69, 61, 353, 339, 833, 1935, 4333, 10521, 20331, 62145, 59245}},
-{12197, 17, 55081, {1, 1, 5, 13, 19, 57, 35, 59, 203, 99, 487, 2747, 637, 8213, 27053, 29, 64335}},
-{12198, 17, 55095, {1, 3, 5, 7, 27, 5, 71, 147, 339, 313, 913, 2845, 5713, 4383, 18969, 54871, 51931}},
-{12199, 17, 55099, {1, 1, 1, 5, 7, 23, 19, 11, 111, 543, 311, 1519, 387, 10175, 18209, 14115, 123421}},
-{12200, 17, 55110, {1, 3, 7, 11, 7, 7, 123, 193, 417, 65, 1317, 3821, 2315, 14527, 14113, 25873, 23977}},
-{12201, 17, 55116, {1, 1, 3, 15, 21, 11, 3, 37, 115, 395, 877, 1227, 6997, 4357, 11397, 52855, 24899}},
-{12202, 17, 55122, {1, 1, 7, 5, 15, 45, 45, 17, 441, 605, 429, 739, 4759, 5249, 11311, 55049, 56909}},
-{12203, 17, 55134, {1, 1, 1, 5, 3, 5, 77, 31, 407, 703, 385, 235, 7751, 617, 16013, 27269, 66971}},
-{12204, 17, 55144, {1, 3, 3, 15, 25, 27, 19, 251, 465, 197, 1039, 3261, 4557, 4821, 16083, 43997, 61371}},
-{12205, 17, 55147, {1, 3, 3, 15, 21, 45, 13, 139, 213, 797, 619, 2125, 3805, 4149, 11427, 59807, 104587}},
-{12206, 17, 55158, {1, 3, 1, 1, 29, 27, 25, 7, 371, 535, 1613, 1083, 4221, 8913, 10601, 6447, 17619}},
-{12207, 17, 55162, {1, 1, 3, 3, 13, 35, 37, 127, 285, 899, 307, 123, 129, 14035, 26503, 64103, 27155}},
-{12208, 17, 55171, {1, 1, 7, 7, 27, 25, 45, 245, 271, 281, 69, 3505, 7087, 1529, 7121, 30327, 89131}},
-{12209, 17, 55185, {1, 1, 3, 11, 13, 57, 31, 23, 455, 427, 1683, 3019, 5827, 8817, 12943, 321, 39951}},
-{12210, 17, 55192, {1, 3, 1, 3, 31, 41, 69, 211, 385, 275, 1569, 2265, 4017, 11057, 15, 16619, 126967}},
-{12211, 17, 55197, {1, 3, 3, 1, 27, 27, 21, 145, 125, 929, 1371, 1469, 1591, 5283, 4651, 1265, 17161}},
-{12212, 17, 55207, {1, 3, 7, 5, 29, 31, 41, 141, 49, 967, 1421, 663, 6089, 3831, 11353, 38809, 108605}},
-{12213, 17, 55228, {1, 1, 7, 15, 11, 23, 91, 31, 9, 717, 265, 1729, 3563, 8145, 20441, 22933, 103683}},
-{12214, 17, 55246, {1, 1, 7, 3, 17, 13, 47, 13, 241, 1017, 1803, 2091, 7379, 2941, 11783, 36189, 53513}},
-{12215, 17, 55253, {1, 3, 1, 11, 31, 63, 107, 79, 427, 385, 1497, 1265, 5135, 13597, 27343, 56733, 100595}},
-{12216, 17, 55254, {1, 3, 7, 3, 9, 15, 119, 29, 205, 151, 1453, 3575, 3627, 7815, 3553, 31457, 14267}},
-{12217, 17, 55281, {1, 3, 1, 7, 15, 21, 73, 47, 417, 29, 1231, 2477, 161, 15997, 4457, 3939, 43929}},
-{12218, 17, 55300, {1, 1, 5, 5, 19, 49, 103, 251, 359, 69, 669, 299, 8161, 10579, 13999, 26859, 92199}},
-{12219, 17, 55303, {1, 1, 3, 1, 9, 27, 81, 7, 115, 29, 1067, 1933, 3061, 2885, 27883, 65227, 59365}},
-{12220, 17, 55307, {1, 1, 1, 5, 23, 17, 1, 113, 495, 155, 1673, 3945, 8053, 7935, 3537, 65141, 11809}},
-{12221, 17, 55312, {1, 1, 1, 15, 15, 59, 61, 213, 303, 851, 1893, 615, 6659, 9351, 16621, 6097, 114383}},
-{12222, 17, 55328, {1, 3, 1, 7, 19, 11, 95, 127, 277, 677, 1631, 2563, 3295, 7029, 4059, 44079, 128857}},
-{12223, 17, 55331, {1, 3, 7, 11, 27, 49, 99, 43, 279, 771, 123, 2969, 699, 12915, 22039, 62257, 79359}},
-{12224, 17, 55337, {1, 1, 7, 3, 19, 45, 45, 113, 251, 883, 715, 1541, 1573, 3345, 23855, 62681, 57591}},
-{12225, 17, 55348, {1, 1, 5, 15, 11, 1, 51, 15, 135, 519, 961, 1447, 4425, 2139, 3309, 35111, 74143}},
-{12226, 17, 55352, {1, 3, 7, 7, 17, 39, 109, 25, 11, 549, 315, 2175, 685, 11837, 9151, 6277, 45011}},
-{12227, 17, 55357, {1, 1, 1, 9, 27, 7, 95, 1, 385, 167, 453, 1027, 4105, 16351, 19, 10375, 62833}},
-{12228, 17, 55372, {1, 3, 7, 13, 17, 19, 107, 11, 441, 171, 185, 3567, 1245, 12161, 30257, 48105, 87105}},
-{12229, 17, 55375, {1, 3, 3, 9, 15, 5, 109, 225, 85, 919, 513, 3559, 5411, 9009, 27391, 25115, 84875}},
-{12230, 17, 55377, {1, 3, 3, 7, 11, 37, 81, 51, 121, 25, 1897, 2121, 6425, 16087, 4259, 29501, 118067}},
-{12231, 17, 55394, {1, 1, 7, 3, 5, 53, 73, 127, 137, 739, 543, 1723, 1163, 2791, 18519, 1459, 50869}},
-{12232, 17, 55406, {1, 1, 3, 11, 29, 51, 101, 189, 193, 839, 25, 3109, 3035, 3917, 23929, 38577, 129705}},
-{12233, 17, 55424, {1, 3, 7, 15, 9, 29, 93, 101, 271, 791, 1257, 1843, 2701, 8205, 15195, 9109, 120835}},
-{12234, 17, 55429, {1, 3, 3, 5, 29, 47, 31, 135, 483, 385, 1395, 2955, 7291, 12885, 9491, 14581, 66293}},
-{12235, 17, 55430, {1, 1, 7, 1, 5, 37, 105, 149, 63, 617, 1611, 3025, 3177, 15463, 3373, 3503, 95001}},
-{12236, 17, 55436, {1, 1, 5, 13, 1, 57, 19, 35, 127, 423, 1221, 1547, 4083, 347, 17131, 60087, 27437}},
-{12237, 17, 55439, {1, 3, 7, 9, 25, 1, 105, 39, 25, 921, 1897, 1729, 2207, 7761, 24197, 457, 64241}},
-{12238, 17, 55447, {1, 3, 7, 9, 15, 21, 13, 113, 379, 1021, 489, 1757, 5869, 4833, 24717, 52227, 3209}},
-{12239, 17, 55453, {1, 3, 1, 5, 9, 61, 25, 41, 183, 473, 383, 2259, 6939, 3, 32161, 6319, 93099}},
-{12240, 17, 55458, {1, 1, 5, 13, 13, 47, 97, 3, 357, 837, 1655, 485, 4251, 12153, 9013, 25121, 51877}},
-{12241, 17, 55460, {1, 1, 1, 15, 7, 59, 65, 119, 467, 313, 1333, 2007, 5165, 13935, 13679, 3999, 81811}},
-{12242, 17, 55478, {1, 1, 5, 13, 13, 1, 63, 117, 449, 13, 1017, 1583, 7599, 3669, 32699, 59455, 32363}},
-{12243, 17, 55489, {1, 1, 7, 9, 7, 15, 37, 251, 167, 25, 1085, 2067, 2771, 5737, 20661, 19231, 59547}},
-{12244, 17, 55501, {1, 1, 5, 13, 29, 11, 63, 37, 281, 657, 1567, 2879, 7601, 15617, 16527, 51695, 5583}},
-{12245, 17, 55502, {1, 1, 5, 3, 31, 17, 19, 65, 315, 413, 927, 3617, 4089, 11899, 3759, 47991, 1685}},
-{12246, 17, 55519, {1, 1, 1, 1, 13, 47, 89, 91, 379, 429, 283, 3765, 2923, 14955, 26399, 9579, 39817}},
-{12247, 17, 55525, {1, 1, 1, 9, 1, 17, 91, 119, 327, 291, 39, 2883, 6265, 553, 7559, 60577, 34393}},
-{12248, 17, 55530, {1, 3, 5, 5, 9, 33, 123, 219, 103, 529, 181, 1321, 6815, 2411, 10555, 43911, 18889}},
-{12249, 17, 55544, {1, 1, 5, 7, 9, 13, 7, 45, 427, 523, 1189, 255, 2103, 7217, 16249, 14631, 90409}},
-{12250, 17, 55550, {1, 1, 1, 9, 11, 35, 55, 71, 89, 637, 1417, 411, 5305, 10125, 20715, 62927, 4993}},
-{12251, 17, 55558, {1, 3, 1, 9, 1, 59, 27, 221, 267, 797, 1081, 951, 1369, 2677, 20763, 63301, 61963}},
-{12252, 17, 55561, {1, 3, 5, 5, 17, 9, 67, 177, 89, 953, 1329, 1649, 989, 7773, 28747, 26231, 42331}},
-{12253, 17, 55569, {1, 3, 3, 9, 23, 35, 17, 145, 53, 519, 1173, 2079, 2593, 3633, 32005, 30573, 55651}},
-{12254, 17, 55586, {1, 1, 7, 7, 17, 41, 47, 253, 107, 843, 9, 323, 2391, 3267, 25813, 1741, 93493}},
-{12255, 17, 55591, {1, 1, 1, 9, 31, 43, 47, 91, 235, 569, 2017, 2385, 5055, 5747, 26471, 48819, 47315}},
-{12256, 17, 55598, {1, 3, 5, 9, 1, 17, 87, 91, 55, 287, 995, 2577, 1151, 9119, 22791, 50899, 16423}},
-{12257, 17, 55605, {1, 3, 7, 1, 3, 29, 9, 193, 269, 201, 325, 2209, 1061, 7957, 23265, 65083, 27575}},
-{12258, 17, 55609, {1, 3, 7, 15, 27, 23, 37, 239, 165, 959, 1965, 2105, 1581, 6621, 17315, 49255, 62487}},
-{12259, 17, 55618, {1, 3, 7, 7, 11, 31, 73, 145, 429, 421, 571, 3375, 2797, 15889, 26523, 12315, 48061}},
-{12260, 17, 55630, {1, 3, 3, 15, 23, 27, 105, 75, 497, 137, 475, 1343, 537, 10499, 27807, 46623, 32435}},
-{12261, 17, 55642, {1, 1, 7, 15, 15, 11, 51, 107, 225, 557, 1461, 3447, 1243, 13827, 23675, 26139, 54603}},
-{12262, 17, 55644, {1, 3, 5, 5, 7, 25, 51, 3, 85, 371, 1503, 3217, 1779, 7141, 29471, 42247, 107699}},
-{12263, 17, 55653, {1, 3, 7, 15, 23, 53, 127, 229, 241, 165, 1985, 1921, 5917, 15743, 18349, 23981, 58241}},
-{12264, 17, 55654, {1, 1, 3, 13, 9, 63, 49, 67, 21, 57, 377, 1807, 5603, 13651, 28039, 3745, 4903}},
-{12265, 17, 55660, {1, 3, 7, 11, 1, 43, 17, 95, 79, 343, 1939, 2349, 5195, 3047, 4325, 27829, 53809}},
-{12266, 17, 55671, {1, 1, 5, 9, 7, 43, 111, 221, 493, 151, 1635, 3949, 6661, 4861, 17661, 61909, 4975}},
-{12267, 17, 55693, {1, 3, 1, 3, 31, 47, 63, 45, 401, 153, 1139, 2125, 6639, 14093, 31607, 20645, 52245}},
-{12268, 17, 55706, {1, 1, 3, 1, 19, 31, 59, 139, 285, 749, 751, 775, 7795, 14917, 30295, 61037, 12315}},
-{12269, 17, 55712, {1, 3, 3, 9, 15, 55, 79, 183, 373, 663, 497, 2589, 4955, 5409, 23527, 2683, 5487}},
-{12270, 17, 55718, {1, 3, 7, 11, 25, 47, 53, 225, 197, 109, 1937, 1375, 7347, 7353, 2335, 21775, 14877}},
-{12271, 17, 55739, {1, 3, 1, 9, 23, 61, 51, 221, 129, 57, 115, 1031, 6793, 14773, 3331, 24951, 94761}},
-{12272, 17, 55747, {1, 1, 5, 15, 31, 9, 69, 117, 295, 147, 673, 3627, 7167, 13835, 20593, 53163, 83033}},
-{12273, 17, 55754, {1, 3, 7, 9, 15, 63, 111, 225, 147, 863, 691, 629, 7485, 483, 21835, 46251, 94645}},
-{12274, 17, 55771, {1, 3, 3, 3, 11, 41, 23, 159, 133, 787, 1617, 629, 5047, 4465, 29051, 47499, 7211}},
-{12275, 17, 55774, {1, 1, 3, 13, 21, 61, 29, 159, 73, 165, 917, 2577, 7237, 11807, 3767, 56861, 51395}},
-{12276, 17, 55780, {1, 1, 5, 3, 15, 31, 37, 233, 283, 265, 1645, 3843, 1971, 4989, 26823, 15243, 74931}},
-{12277, 17, 55783, {1, 3, 7, 11, 9, 51, 7, 119, 237, 905, 1211, 3041, 7641, 3387, 8373, 38961, 68925}},
-{12278, 17, 55784, {1, 1, 7, 3, 17, 53, 55, 195, 57, 957, 2027, 3965, 2993, 411, 13947, 58349, 32169}},
-{12279, 17, 55789, {1, 1, 7, 9, 7, 37, 55, 93, 173, 769, 1381, 3977, 5293, 5051, 21455, 45547, 64653}},
-{12280, 17, 55798, {1, 3, 5, 7, 1, 41, 89, 161, 315, 361, 1675, 2993, 3281, 13043, 19003, 22129, 130379}},
-{12281, 17, 55802, {1, 3, 1, 9, 13, 37, 85, 197, 465, 177, 661, 943, 541, 11117, 9751, 4193, 98291}},
-{12282, 17, 55823, {1, 1, 3, 7, 21, 7, 67, 17, 41, 817, 1159, 1483, 6937, 10079, 3639, 27887, 14541}},
-{12283, 17, 55828, {1, 3, 3, 15, 17, 63, 69, 215, 437, 883, 1857, 3319, 3107, 16279, 10709, 30433, 52551}},
-{12284, 17, 55837, {1, 1, 3, 11, 1, 5, 69, 37, 419, 999, 1711, 875, 3807, 10811, 16345, 61155, 116043}},
-{12285, 17, 55838, {1, 3, 7, 13, 17, 7, 57, 237, 81, 691, 1143, 4075, 2481, 643, 8091, 8243, 80111}},
-{12286, 17, 55847, {1, 1, 7, 7, 17, 61, 73, 215, 113, 885, 159, 2243, 1177, 10981, 10123, 48995, 123349}},
-{12287, 17, 55848, {1, 1, 1, 7, 31, 47, 99, 15, 371, 343, 1483, 1985, 25, 11125, 8357, 10677, 130895}},
-{12288, 17, 55885, {1, 3, 1, 13, 25, 41, 83, 37, 129, 493, 641, 185, 6607, 7213, 13285, 10439, 73227}},
-{12289, 17, 55897, {1, 1, 5, 7, 17, 15, 93, 53, 281, 91, 115, 3675, 3081, 9825, 23653, 40095, 91803}},
-{12290, 17, 55904, {1, 1, 1, 5, 3, 25, 39, 207, 419, 361, 953, 2823, 8105, 15763, 29199, 61607, 32633}},
-{12291, 17, 55910, {1, 1, 3, 1, 31, 51, 55, 3, 277, 639, 191, 1783, 139, 29, 16659, 30199, 69109}},
-{12292, 17, 55919, {1, 1, 1, 7, 31, 59, 25, 13, 239, 617, 115, 1787, 5757, 9927, 2417, 37313, 115135}},
-{12293, 17, 55922, {1, 1, 3, 5, 19, 35, 5, 187, 483, 823, 1875, 163, 4235, 853, 23679, 50899, 94981}},
-{12294, 17, 55931, {1, 3, 3, 11, 9, 39, 121, 201, 189, 543, 1493, 1215, 351, 16063, 1701, 56559, 108053}},
-{12295, 17, 55933, {1, 3, 1, 7, 1, 39, 31, 163, 347, 307, 349, 4081, 1729, 16265, 363, 28297, 50631}},
-{12296, 17, 55937, {1, 3, 7, 13, 21, 55, 127, 161, 75, 9, 1285, 1839, 5283, 5667, 10979, 22185, 7581}},
-{12297, 17, 55943, {1, 1, 3, 5, 13, 45, 17, 181, 117, 395, 1685, 663, 3441, 5359, 7157, 27759, 102343}},
-{12298, 17, 55955, {1, 3, 1, 7, 7, 31, 97, 187, 383, 769, 1469, 4007, 5521, 13973, 49, 43823, 75649}},
-{12299, 17, 55957, {1, 3, 5, 7, 31, 13, 47, 11, 335, 961, 321, 3367, 1903, 503, 8409, 1101, 58215}},
-{12300, 17, 55968, {1, 1, 7, 7, 25, 49, 39, 1, 453, 419, 333, 1759, 2287, 6243, 10723, 13687, 56853}},
-{12301, 17, 55980, {1, 3, 3, 7, 11, 55, 125, 197, 19, 591, 1969, 511, 2501, 8429, 29467, 27917, 63457}},
-{12302, 17, 55986, {1, 1, 3, 11, 11, 43, 35, 213, 231, 119, 379, 3761, 4891, 5677, 20317, 5459, 55487}},
-{12303, 17, 55992, {1, 1, 5, 7, 21, 9, 127, 59, 97, 963, 847, 2131, 7907, 11409, 8785, 48197, 96907}},
-{12304, 17, 56005, {1, 3, 5, 3, 23, 7, 45, 95, 179, 691, 1571, 3091, 6359, 9105, 26021, 26925, 43}},
-{12305, 17, 56034, {1, 3, 3, 7, 21, 7, 11, 219, 439, 465, 1983, 117, 4639, 8387, 27637, 15883, 5567}},
-{12306, 17, 56051, {1, 1, 7, 3, 1, 3, 51, 205, 425, 133, 563, 1317, 533, 1227, 8361, 23407, 39825}},
-{12307, 17, 56054, {1, 1, 5, 3, 3, 39, 19, 69, 477, 605, 3, 1887, 2077, 13673, 2763, 64415, 104519}},
-{12308, 17, 56065, {1, 1, 5, 15, 11, 45, 89, 245, 177, 591, 1313, 587, 4781, 5103, 26401, 12643, 38959}},
-{12309, 17, 56080, {1, 1, 1, 5, 11, 13, 15, 95, 271, 99, 2001, 2701, 6065, 3527, 7423, 37525, 117161}},
-{12310, 17, 56101, {1, 3, 7, 7, 21, 17, 111, 149, 373, 591, 1461, 809, 3877, 8635, 13209, 31439, 64285}},
-{12311, 17, 56113, {1, 3, 1, 15, 25, 51, 55, 161, 357, 181, 41, 2345, 3553, 9917, 30123, 40683, 122497}},
-{12312, 17, 56126, {1, 3, 7, 15, 5, 55, 119, 239, 291, 665, 1537, 3309, 2519, 12397, 25897, 51529, 28673}},
-{12313, 17, 56131, {1, 1, 1, 9, 25, 45, 21, 119, 19, 145, 313, 2509, 1031, 3319, 14863, 10759, 22577}},
-{12314, 17, 56134, {1, 3, 1, 15, 1, 61, 87, 229, 511, 83, 79, 51, 1407, 16293, 26217, 25839, 86207}},
-{12315, 17, 56143, {1, 3, 7, 7, 23, 43, 89, 11, 43, 801, 569, 3273, 315, 9537, 681, 34783, 97101}},
-{12316, 17, 56148, {1, 1, 5, 1, 13, 31, 77, 115, 501, 669, 27, 3765, 6789, 9139, 30587, 45995, 102433}},
-{12317, 17, 56152, {1, 1, 7, 1, 15, 21, 57, 197, 243, 353, 71, 341, 7319, 8467, 9779, 15755, 4185}},
-{12318, 17, 56174, {1, 1, 1, 1, 17, 21, 3, 185, 277, 585, 265, 3189, 3975, 353, 8541, 23905, 21881}},
-{12319, 17, 56181, {1, 3, 5, 3, 5, 23, 113, 253, 343, 73, 1419, 2529, 4333, 2007, 14307, 60591, 55411}},
-{12320, 17, 56182, {1, 1, 7, 3, 25, 35, 109, 173, 351, 487, 1551, 3207, 1189, 5091, 3581, 4699, 22085}},
-{12321, 17, 56185, {1, 1, 3, 11, 9, 9, 71, 173, 17, 595, 2015, 2543, 4889, 6025, 15265, 6459, 3977}},
-{12322, 17, 56192, {1, 3, 5, 15, 11, 13, 11, 189, 431, 307, 317, 3131, 1421, 10863, 5311, 25273, 43187}},
-{12323, 17, 56201, {1, 1, 1, 7, 7, 41, 103, 231, 321, 327, 1849, 2485, 6461, 10259, 4577, 52951, 33053}},
-{12324, 17, 56215, {1, 3, 3, 15, 11, 33, 73, 155, 453, 597, 575, 2119, 327, 4227, 32271, 7429, 102007}},
-{12325, 17, 56219, {1, 1, 3, 7, 15, 9, 95, 177, 21, 245, 257, 3637, 821, 16351, 1733, 10635, 59885}},
-{12326, 17, 56222, {1, 1, 3, 7, 23, 41, 107, 147, 57, 877, 1609, 3275, 339, 12997, 5989, 62293, 21549}},
-{12327, 17, 56258, {1, 1, 7, 13, 19, 39, 111, 229, 321, 487, 873, 3365, 4915, 251, 30629, 45775, 73549}},
-{12328, 17, 56264, {1, 1, 1, 13, 25, 61, 43, 111, 135, 463, 1921, 1723, 7505, 13805, 30633, 51683, 7353}},
-{12329, 17, 56269, {1, 1, 1, 1, 31, 41, 35, 205, 375, 189, 635, 3589, 3507, 8131, 13437, 22823, 68451}},
-{12330, 17, 56272, {1, 3, 7, 5, 31, 47, 13, 229, 105, 195, 685, 529, 39, 2651, 6821, 11043, 112123}},
-{12331, 17, 56278, {1, 3, 7, 13, 3, 23, 21, 203, 89, 957, 1577, 1711, 585, 3937, 17681, 55577, 61075}},
-{12332, 17, 56282, {1, 3, 3, 3, 17, 37, 49, 7, 287, 183, 1185, 2979, 2103, 1217, 22105, 11677, 19603}},
-{12333, 17, 56306, {1, 1, 1, 9, 29, 35, 93, 179, 403, 563, 441, 3485, 6909, 12647, 3885, 60089, 29275}},
-{12334, 17, 56308, {1, 3, 3, 9, 15, 37, 49, 103, 509, 77, 495, 921, 2599, 14735, 30951, 22779, 47747}},
-{12335, 17, 56318, {1, 3, 3, 11, 17, 45, 43, 235, 379, 51, 925, 89, 2241, 10273, 27649, 8101, 93977}},
-{12336, 17, 56329, {1, 3, 3, 3, 11, 7, 25, 163, 405, 997, 847, 2743, 4705, 7041, 10997, 50189, 10775}},
-{12337, 17, 56356, {1, 1, 1, 13, 19, 43, 3, 125, 37, 41, 5, 965, 2681, 3737, 29057, 37777, 119537}},
-{12338, 17, 56360, {1, 1, 1, 1, 11, 27, 101, 67, 73, 199, 1739, 2835, 5837, 10595, 9865, 38493, 99323}},
-{12339, 17, 56383, {1, 3, 1, 13, 27, 43, 21, 79, 419, 847, 843, 2563, 8133, 10295, 10127, 30839, 104863}},
-{12340, 17, 56388, {1, 3, 3, 11, 15, 37, 71, 251, 157, 971, 165, 1647, 2583, 205, 23555, 55297, 106893}},
-{12341, 17, 56391, {1, 1, 5, 15, 1, 21, 113, 107, 287, 727, 71, 2655, 1435, 11125, 15257, 18899, 37737}},
-{12342, 17, 56405, {1, 1, 3, 3, 27, 49, 17, 85, 57, 237, 349, 4049, 1103, 2523, 3919, 36587, 128595}},
-{12343, 17, 56406, {1, 3, 5, 9, 13, 1, 65, 13, 361, 409, 413, 2153, 5953, 10651, 25383, 49777, 65399}},
-{12344, 17, 56416, {1, 1, 7, 9, 19, 47, 69, 127, 121, 925, 57, 2775, 4981, 3643, 4077, 3081, 56093}},
-{12345, 17, 56426, {1, 3, 3, 13, 1, 53, 45, 13, 489, 445, 623, 3547, 1659, 1899, 11971, 3725, 12445}},
-{12346, 17, 56439, {1, 3, 7, 11, 13, 9, 59, 157, 125, 975, 1283, 297, 3609, 3179, 31341, 54727, 112515}},
-{12347, 17, 56446, {1, 1, 1, 13, 23, 63, 69, 249, 159, 593, 47, 3957, 757, 14693, 26345, 18839, 111263}},
-{12348, 17, 56450, {1, 1, 1, 1, 31, 37, 37, 199, 7, 425, 337, 1475, 271, 16215, 12089, 16765, 13519}},
-{12349, 17, 56459, {1, 1, 7, 11, 31, 59, 121, 139, 413, 807, 737, 1235, 3505, 5859, 14205, 31939, 4713}},
-{12350, 17, 56461, {1, 1, 1, 9, 21, 51, 113, 159, 345, 807, 635, 523, 5535, 13307, 4239, 14847, 23711}},
-{12351, 17, 56464, {1, 3, 5, 13, 31, 7, 33, 1, 293, 271, 1829, 2535, 6333, 12037, 29401, 35009, 37789}},
-{12352, 17, 56469, {1, 1, 7, 3, 7, 57, 31, 45, 177, 475, 843, 1265, 585, 16099, 29293, 52407, 56131}},
-{12353, 17, 56489, {1, 3, 3, 11, 1, 25, 117, 205, 139, 141, 1229, 903, 1883, 11269, 30493, 3979, 4263}},
-{12354, 17, 56490, {1, 1, 5, 13, 25, 43, 9, 237, 347, 869, 1765, 1389, 1931, 13331, 17325, 45999, 121201}},
-{12355, 17, 56497, {1, 3, 3, 11, 3, 13, 95, 49, 389, 53, 491, 1467, 5105, 16053, 6305, 15759, 51991}},
-{12356, 17, 56509, {1, 3, 5, 15, 1, 53, 85, 69, 75, 409, 1299, 1245, 7951, 10709, 9157, 3509, 103975}},
-{12357, 17, 56515, {1, 1, 1, 13, 1, 33, 97, 235, 463, 413, 1759, 1891, 1781, 5261, 5759, 201, 69199}},
-{12358, 17, 56518, {1, 1, 3, 13, 21, 27, 101, 143, 123, 705, 969, 2461, 6057, 13091, 6077, 38311, 30379}},
-{12359, 17, 56524, {1, 3, 3, 1, 13, 11, 73, 33, 495, 513, 763, 3089, 421, 13663, 30169, 56599, 38847}},
-{12360, 17, 56535, {1, 1, 7, 13, 13, 31, 91, 63, 233, 137, 859, 2449, 539, 12461, 13477, 31605, 58919}},
-{12361, 17, 56542, {1, 1, 1, 9, 13, 49, 107, 45, 451, 707, 1735, 1881, 3451, 9131, 25481, 10841, 116067}},
-{12362, 17, 56545, {1, 3, 7, 1, 27, 21, 51, 117, 63, 53, 575, 3325, 1099, 11181, 23609, 47141, 115421}},
-{12363, 17, 56551, {1, 3, 1, 13, 25, 29, 53, 135, 165, 319, 1695, 341, 8157, 10671, 7095, 60749, 31513}},
-{12364, 17, 56555, {1, 1, 7, 5, 3, 53, 123, 137, 449, 87, 951, 693, 6943, 15331, 1515, 24019, 56613}},
-{12365, 17, 56560, {1, 3, 7, 5, 25, 17, 43, 251, 301, 203, 633, 1271, 6253, 4475, 10773, 25003, 67599}},
-{12366, 17, 56569, {1, 1, 3, 9, 1, 25, 117, 159, 13, 155, 851, 2497, 6155, 6549, 27909, 24423, 82357}},
-{12367, 17, 56580, {1, 1, 1, 1, 21, 59, 103, 43, 291, 111, 1355, 401, 5129, 16017, 25947, 15391, 46745}},
-{12368, 17, 56584, {1, 1, 1, 13, 13, 51, 95, 111, 17, 963, 1535, 3003, 6163, 11377, 6787, 57275, 109559}},
-{12369, 17, 56598, {1, 1, 5, 11, 11, 3, 85, 207, 489, 117, 269, 747, 5719, 8501, 7307, 59223, 18941}},
-{12370, 17, 56601, {1, 1, 5, 1, 9, 53, 41, 255, 271, 995, 1939, 2739, 2221, 14841, 22617, 10643, 6427}},
-{12371, 17, 56602, {1, 3, 3, 9, 7, 55, 109, 143, 427, 45, 579, 115, 2061, 8447, 29469, 5523, 129063}},
-{12372, 17, 56623, {1, 3, 7, 5, 23, 63, 119, 31, 53, 821, 135, 2677, 807, 4685, 24391, 55165, 88079}},
-{12373, 17, 56637, {1, 3, 5, 9, 15, 11, 73, 177, 243, 375, 115, 1633, 7983, 15039, 21169, 25325, 128479}},
-{12374, 17, 56638, {1, 3, 3, 5, 21, 51, 13, 51, 75, 993, 77, 209, 2761, 451, 11987, 40297, 2383}},
-{12375, 17, 56643, {1, 3, 7, 1, 19, 9, 11, 161, 19, 851, 1313, 1169, 4405, 7493, 23935, 37323, 107387}},
-{12376, 17, 56650, {1, 3, 5, 15, 5, 11, 79, 129, 507, 247, 811, 1145, 3893, 5205, 11309, 38205, 2051}},
-{12377, 17, 56673, {1, 1, 5, 1, 11, 13, 33, 155, 21, 185, 771, 3261, 981, 743, 12479, 22611, 25321}},
-{12378, 17, 56676, {1, 1, 5, 9, 7, 25, 11, 235, 429, 563, 1647, 1429, 1385, 14411, 3831, 19769, 67599}},
-{12379, 17, 56686, {1, 3, 3, 5, 5, 7, 109, 117, 251, 823, 669, 2043, 1843, 11829, 27051, 35865, 11461}},
-{12380, 17, 56704, {1, 3, 5, 5, 7, 3, 45, 63, 305, 99, 393, 1765, 1711, 15569, 27295, 16555, 77631}},
-{12381, 17, 56710, {1, 3, 5, 11, 23, 33, 49, 125, 85, 677, 1589, 2667, 5723, 15619, 30415, 39561, 122763}},
-{12382, 17, 56721, {1, 3, 7, 13, 27, 21, 99, 209, 481, 123, 1285, 115, 6517, 11753, 11365, 44959, 89}},
-{12383, 17, 56731, {1, 1, 1, 7, 15, 15, 45, 151, 489, 169, 933, 2987, 657, 3095, 6745, 131, 37767}},
-{12384, 17, 56738, {1, 3, 1, 15, 1, 37, 99, 137, 151, 891, 715, 383, 1293, 719, 10957, 5557, 92841}},
-{12385, 17, 56747, {1, 1, 1, 3, 27, 59, 93, 49, 473, 313, 431, 1129, 5995, 13101, 13185, 7091, 109677}},
-{12386, 17, 56750, {1, 3, 3, 7, 1, 41, 55, 135, 271, 527, 1919, 1093, 2579, 3725, 22853, 31613, 4729}},
-{12387, 17, 56752, {1, 1, 7, 1, 7, 13, 63, 255, 219, 837, 117, 2323, 4295, 15697, 8607, 47047, 117869}},
-{12388, 17, 56757, {1, 1, 1, 7, 29, 29, 55, 171, 437, 733, 491, 1037, 7221, 5705, 31819, 19583, 103991}},
-{12389, 17, 56787, {1, 3, 7, 1, 31, 19, 65, 39, 151, 517, 1985, 2251, 6147, 12983, 28263, 35891, 7545}},
-{12390, 17, 56796, {1, 1, 7, 7, 21, 41, 97, 253, 427, 391, 849, 611, 4827, 10807, 6267, 22513, 62803}},
-{12391, 17, 56803, {1, 3, 7, 7, 25, 9, 49, 245, 491, 39, 603, 1853, 5655, 3517, 10745, 55069, 121497}},
-{12392, 17, 56812, {1, 3, 1, 5, 9, 39, 109, 195, 283, 141, 2007, 3, 1267, 13053, 8387, 48665, 48877}},
-{12393, 17, 56815, {1, 1, 3, 7, 27, 61, 49, 43, 229, 497, 2015, 1345, 3195, 7139, 13453, 56993, 15099}},
-{12394, 17, 56824, {1, 3, 5, 11, 31, 53, 87, 97, 385, 387, 1107, 3287, 2517, 7421, 1007, 37421, 124113}},
-{12395, 17, 56829, {1, 3, 3, 11, 9, 55, 51, 215, 181, 419, 863, 3149, 5815, 15579, 28527, 34715, 61375}},
-{12396, 17, 56833, {1, 3, 3, 3, 31, 57, 5, 35, 445, 957, 1897, 105, 2533, 10255, 19795, 49127, 38491}},
-{12397, 17, 56839, {1, 3, 3, 13, 25, 53, 1, 159, 443, 541, 439, 3377, 5511, 9667, 26777, 32599, 36981}},
-{12398, 17, 56840, {1, 1, 1, 3, 23, 29, 97, 131, 59, 143, 1601, 2765, 4569, 11081, 6027, 38641, 100745}},
-{12399, 17, 56845, {1, 3, 3, 15, 9, 15, 19, 35, 321, 935, 465, 2707, 4799, 7455, 12743, 31029, 114149}},
-{12400, 17, 56853, {1, 1, 1, 1, 11, 51, 23, 79, 387, 701, 107, 623, 231, 12571, 7719, 3061, 79605}},
-{12401, 17, 56854, {1, 3, 5, 15, 17, 49, 109, 83, 185, 295, 853, 219, 3615, 535, 32001, 6655, 4185}},
-{12402, 17, 56858, {1, 3, 3, 15, 15, 7, 35, 151, 305, 705, 1383, 1595, 5595, 11995, 15491, 49119, 83383}},
-{12403, 17, 56863, {1, 3, 7, 9, 3, 25, 57, 47, 359, 719, 1937, 1403, 1399, 10827, 24181, 29141, 79017}},
-{12404, 17, 56864, {1, 3, 5, 1, 1, 21, 21, 245, 361, 485, 1521, 3935, 1587, 8653, 25871, 49449, 103413}},
-{12405, 17, 56881, {1, 3, 3, 3, 9, 61, 31, 69, 401, 261, 1217, 3069, 4045, 12437, 32017, 15113, 10769}},
-{12406, 17, 56882, {1, 3, 1, 1, 21, 33, 123, 87, 481, 793, 625, 4087, 1361, 11077, 18835, 13287, 40107}},
-{12407, 17, 56896, {1, 3, 7, 3, 9, 49, 101, 213, 467, 77, 1691, 2621, 4411, 8025, 30247, 13691, 20559}},
-{12408, 17, 56901, {1, 1, 1, 9, 29, 49, 47, 135, 1, 337, 1649, 389, 3845, 7213, 19527, 2619, 78841}},
-{12409, 17, 56902, {1, 3, 7, 9, 23, 23, 47, 97, 493, 767, 137, 1467, 7015, 2883, 12749, 9267, 12441}},
-{12410, 17, 56908, {1, 1, 3, 15, 9, 57, 53, 19, 401, 385, 1159, 1185, 6977, 14027, 3183, 59119, 42065}},
-{12411, 17, 56923, {1, 1, 1, 15, 21, 33, 83, 251, 147, 395, 321, 443, 6893, 1877, 6687, 28863, 86531}},
-{12412, 17, 56925, {1, 3, 3, 1, 3, 47, 27, 247, 121, 827, 1399, 4079, 7545, 11691, 27915, 28811, 17099}},
-{12413, 17, 56926, {1, 3, 5, 7, 5, 59, 73, 69, 117, 897, 905, 3273, 2935, 11077, 32443, 60959, 16081}},
-{12414, 17, 56932, {1, 1, 7, 5, 27, 49, 107, 169, 75, 435, 1913, 2089, 5733, 2361, 5163, 52239, 87411}},
-{12415, 17, 56939, {1, 1, 7, 13, 1, 13, 123, 89, 427, 301, 1217, 1491, 5361, 10381, 28971, 57655, 108607}},
-{12416, 17, 56947, {1, 1, 7, 11, 13, 5, 23, 151, 117, 369, 623, 2263, 2609, 109, 32485, 52133, 69391}},
-{12417, 17, 56954, {1, 3, 7, 11, 7, 33, 127, 43, 123, 203, 775, 3215, 5115, 1805, 14581, 46791, 128781}},
-{12418, 17, 56970, {1, 3, 3, 1, 7, 23, 37, 99, 1, 719, 293, 2727, 6859, 683, 13241, 17839, 4215}},
-{12419, 17, 56972, {1, 1, 1, 13, 27, 41, 93, 25, 59, 947, 971, 1523, 4443, 1209, 32317, 58651, 11121}},
-{12420, 17, 56977, {1, 1, 1, 3, 31, 33, 23, 87, 349, 265, 445, 3489, 783, 7833, 5767, 59295, 45057}},
-{12421, 17, 56980, {1, 1, 1, 1, 15, 47, 19, 15, 217, 837, 2043, 2805, 4701, 5873, 1517, 46743, 61655}},
-{12422, 17, 56993, {1, 3, 7, 1, 27, 27, 9, 107, 25, 897, 955, 3763, 821, 1535, 14557, 38537, 128737}},
-{12423, 17, 57013, {1, 3, 3, 7, 19, 49, 121, 217, 401, 975, 1189, 715, 3113, 4219, 4885, 57861, 6833}},
-{12424, 17, 57017, {1, 3, 3, 1, 17, 59, 53, 15, 259, 791, 2035, 499, 7707, 13685, 14367, 20155, 91033}},
-{12425, 17, 57018, {1, 3, 5, 5, 11, 11, 69, 237, 139, 73, 541, 1135, 2647, 14109, 18113, 8051, 31917}},
-{12426, 17, 57031, {1, 1, 1, 15, 11, 23, 89, 181, 295, 743, 29, 4009, 4683, 13989, 4575, 38865, 30449}},
-{12427, 17, 57059, {1, 1, 1, 11, 21, 63, 31, 121, 55, 153, 1143, 4059, 3247, 11725, 17659, 48935, 118369}},
-{12428, 17, 57062, {1, 1, 7, 9, 17, 29, 27, 167, 69, 957, 2009, 2795, 3161, 3493, 16365, 43637, 102321}},
-{12429, 17, 57065, {1, 3, 5, 13, 27, 23, 17, 7, 345, 253, 631, 1389, 2523, 9993, 32619, 46731, 4757}},
-{12430, 17, 57071, {1, 1, 1, 11, 17, 1, 41, 107, 25, 183, 1361, 1211, 3607, 12713, 16011, 42987, 36415}},
-{12431, 17, 57083, {1, 1, 7, 5, 13, 29, 33, 69, 261, 213, 73, 3737, 3867, 503, 28225, 53735, 91695}},
-{12432, 17, 57093, {1, 3, 7, 7, 21, 63, 75, 39, 259, 367, 487, 2087, 5411, 1925, 29589, 39019, 73283}},
-{12433, 17, 57097, {1, 3, 1, 7, 29, 29, 25, 191, 91, 509, 1485, 853, 7011, 13321, 27769, 10249, 87341}},
-{12434, 17, 57106, {1, 1, 7, 7, 1, 9, 115, 71, 321, 913, 1679, 2129, 771, 9217, 4731, 24353, 35631}},
-{12435, 17, 57118, {1, 3, 1, 13, 5, 45, 53, 255, 429, 805, 1983, 1437, 2677, 6337, 22221, 55455, 39855}},
-{12436, 17, 57133, {1, 1, 1, 1, 1, 5, 111, 231, 321, 961, 371, 3825, 3623, 3985, 32151, 6113, 130687}},
-{12437, 17, 57134, {1, 3, 7, 3, 15, 29, 103, 181, 261, 149, 1161, 1745, 1765, 1677, 20051, 47033, 84997}},
-{12438, 17, 57141, {1, 3, 7, 1, 25, 21, 7, 229, 407, 673, 1525, 1207, 3099, 14849, 22103, 45695, 85951}},
-{12439, 17, 57146, {1, 3, 7, 1, 9, 5, 105, 149, 181, 81, 1589, 3477, 5387, 7943, 29203, 50355, 39001}},
-{12440, 17, 57156, {1, 3, 7, 1, 21, 31, 39, 121, 397, 1023, 711, 623, 6193, 12315, 11101, 11911, 50033}},
-{12441, 17, 57174, {1, 3, 7, 3, 7, 19, 73, 69, 201, 337, 1037, 3663, 2679, 5153, 28171, 24455, 74685}},
-{12442, 17, 57183, {1, 3, 1, 1, 21, 35, 121, 111, 217, 809, 507, 1347, 4439, 4601, 26371, 23595, 3583}},
-{12443, 17, 57189, {1, 3, 3, 7, 1, 51, 83, 231, 419, 597, 305, 3405, 5831, 11845, 1861, 48671, 105315}},
-{12444, 17, 57190, {1, 3, 1, 15, 25, 37, 103, 141, 495, 727, 1919, 2821, 4689, 6727, 27117, 2259, 54559}},
-{12445, 17, 57193, {1, 3, 5, 3, 27, 55, 5, 117, 199, 979, 1745, 401, 7967, 5345, 29747, 54085, 124765}},
-{12446, 17, 57196, {1, 3, 3, 15, 23, 61, 1, 29, 489, 131, 583, 389, 6033, 8007, 22933, 44513, 111845}},
-{12447, 17, 57207, {1, 1, 7, 13, 3, 55, 119, 147, 181, 485, 793, 3593, 6971, 2227, 28507, 62393, 127303}},
-{12448, 17, 57211, {1, 1, 5, 3, 29, 53, 37, 59, 213, 283, 1809, 3685, 2677, 5761, 19705, 47079, 3477}},
-{12449, 17, 57214, {1, 1, 1, 7, 21, 63, 91, 13, 347, 605, 589, 415, 5737, 10281, 30941, 25609, 67973}},
-{12450, 17, 57218, {1, 1, 3, 1, 27, 49, 87, 161, 507, 693, 59, 1375, 6737, 1029, 14731, 32335, 51961}},
-{12451, 17, 57230, {1, 3, 3, 9, 11, 15, 121, 121, 151, 335, 221, 3099, 1999, 1047, 20891, 23015, 95809}},
-{12452, 17, 57235, {1, 1, 7, 7, 1, 49, 63, 227, 113, 161, 863, 801, 2559, 7737, 27619, 27419, 128009}},
-{12453, 17, 57241, {1, 1, 7, 1, 25, 59, 67, 111, 435, 309, 807, 2107, 8077, 9671, 6739, 53757, 41259}},
-{12454, 17, 57251, {1, 3, 7, 3, 3, 19, 7, 111, 237, 981, 1717, 3131, 6631, 467, 13103, 61435, 126469}},
-{12455, 17, 57260, {1, 1, 7, 9, 19, 31, 59, 185, 199, 111, 351, 611, 6355, 1095, 28549, 32871, 44537}},
-{12456, 17, 57263, {1, 1, 3, 11, 23, 25, 31, 1, 461, 83, 1723, 1711, 3679, 10963, 14927, 17377, 911}},
-{12457, 17, 57265, {1, 1, 5, 13, 3, 37, 127, 159, 199, 223, 1097, 3033, 5825, 13777, 22189, 44305, 20509}},
-{12458, 17, 57271, {1, 1, 5, 15, 13, 49, 17, 79, 289, 601, 1023, 657, 1687, 14477, 15929, 4279, 68007}},
-{12459, 17, 57272, {1, 1, 5, 7, 29, 3, 45, 225, 65, 711, 1039, 3585, 4957, 9041, 22761, 26649, 95627}},
-{12460, 17, 57290, {1, 3, 5, 5, 13, 29, 33, 211, 461, 799, 1437, 1057, 485, 9535, 8133, 57527, 12873}},
-{12461, 17, 57295, {1, 1, 3, 3, 15, 43, 53, 15, 395, 561, 1371, 3543, 7707, 2399, 13311, 25641, 58865}},
-{12462, 17, 57298, {1, 3, 1, 7, 1, 9, 115, 39, 249, 87, 835, 97, 8137, 6665, 11951, 21045, 76387}},
-{12463, 17, 57325, {1, 3, 3, 9, 5, 63, 115, 163, 331, 1007, 733, 4027, 2911, 5329, 6967, 3535, 107293}},
-{12464, 17, 57328, {1, 3, 1, 11, 5, 55, 81, 63, 345, 535, 1093, 207, 4053, 9129, 10397, 26641, 95171}},
-{12465, 17, 57340, {1, 1, 3, 3, 13, 27, 65, 37, 255, 69, 19, 2565, 4329, 11223, 18131, 18701, 31111}},
-{12466, 17, 57344, {1, 3, 7, 7, 25, 57, 81, 189, 227, 377, 829, 1583, 1343, 4643, 23485, 47463, 83535}},
-{12467, 17, 57353, {1, 3, 5, 9, 13, 33, 103, 75, 501, 803, 427, 1171, 1187, 2655, 24187, 32907, 120239}},
-{12468, 17, 57368, {1, 3, 1, 7, 31, 63, 21, 137, 241, 63, 1925, 2193, 1135, 11159, 14685, 28397, 59}},
-{12469, 17, 57371, {1, 1, 7, 1, 15, 7, 85, 87, 493, 63, 561, 1069, 5481, 12253, 25149, 35283, 16123}},
-{12470, 17, 57383, {1, 3, 3, 5, 19, 17, 23, 95, 429, 805, 1343, 2243, 233, 7219, 6549, 21477, 83679}},
-{12471, 17, 57402, {1, 3, 3, 1, 3, 55, 83, 107, 131, 311, 741, 781, 6227, 10059, 3903, 235, 45971}},
-{12472, 17, 57407, {1, 1, 3, 13, 21, 43, 79, 149, 367, 755, 463, 221, 5117, 7015, 17599, 64665, 37443}},
-{12473, 17, 57419, {1, 1, 7, 15, 3, 59, 107, 13, 213, 287, 1505, 2131, 6965, 12873, 23973, 8449, 24829}},
-{12474, 17, 57424, {1, 3, 5, 11, 25, 45, 39, 17, 175, 749, 1179, 3349, 6723, 12543, 3557, 34521, 103197}},
-{12475, 17, 57433, {1, 1, 3, 13, 23, 41, 21, 25, 91, 941, 879, 4015, 137, 12949, 17245, 41903, 39803}},
-{12476, 17, 57452, {1, 1, 7, 15, 11, 33, 45, 127, 321, 895, 1543, 4013, 6179, 14209, 13317, 46803, 99891}},
-{12477, 17, 57458, {1, 3, 3, 13, 13, 11, 101, 11, 177, 869, 509, 2323, 449, 16379, 31965, 2899, 59229}},
-{12478, 17, 57467, {1, 1, 5, 7, 15, 37, 113, 237, 463, 489, 1145, 1629, 3101, 10305, 31705, 29957, 99665}},
-{12479, 17, 57470, {1, 3, 5, 7, 21, 29, 45, 133, 367, 657, 1315, 537, 6069, 8141, 31479, 32983, 57}},
-{12480, 17, 57473, {1, 1, 3, 9, 13, 39, 109, 125, 467, 975, 829, 4007, 773, 6639, 8793, 4579, 60547}},
-{12481, 17, 57479, {1, 1, 1, 15, 21, 5, 113, 51, 159, 501, 1921, 4095, 5603, 16055, 16649, 50229, 49863}},
-{12482, 17, 57480, {1, 1, 5, 13, 9, 21, 77, 187, 355, 299, 1017, 491, 6725, 4177, 16739, 15909, 84069}},
-{12483, 17, 57486, {1, 3, 7, 5, 13, 13, 51, 19, 159, 339, 735, 933, 2523, 11435, 20793, 21975, 19007}},
-{12484, 17, 57491, {1, 1, 7, 5, 1, 11, 61, 111, 129, 643, 1741, 945, 7349, 11579, 24793, 1751, 2367}},
-{12485, 17, 57493, {1, 1, 5, 5, 29, 45, 63, 177, 507, 277, 1789, 729, 4277, 10099, 28985, 43009, 2319}},
-{12486, 17, 57524, {1, 3, 3, 13, 19, 53, 73, 227, 487, 131, 1227, 3735, 3979, 7383, 6923, 31979, 6651}},
-{12487, 17, 57528, {1, 3, 3, 15, 7, 47, 31, 255, 317, 621, 497, 4069, 5249, 15093, 18013, 6891, 81893}},
-{12488, 17, 57534, {1, 1, 7, 5, 17, 23, 119, 27, 55, 555, 221, 2693, 1757, 11117, 23409, 21135, 122977}},
-{12489, 17, 57542, {1, 1, 5, 1, 15, 17, 127, 109, 75, 1017, 1167, 2975, 3249, 5399, 12599, 50779, 78215}},
-{12490, 17, 57560, {1, 3, 5, 5, 1, 13, 65, 199, 101, 75, 513, 493, 6931, 9363, 5607, 16331, 69219}},
-{12491, 17, 57565, {1, 1, 1, 15, 19, 37, 63, 177, 397, 645, 905, 1599, 609, 14291, 14681, 46719, 117745}},
-{12492, 17, 57570, {1, 3, 7, 13, 3, 57, 63, 49, 67, 913, 1659, 1857, 3595, 9219, 11341, 39735, 82275}},
-{12493, 17, 57579, {1, 1, 5, 11, 19, 1, 5, 181, 55, 763, 469, 2417, 2349, 12437, 22589, 17867, 95701}},
-{12494, 17, 57590, {1, 3, 7, 13, 1, 9, 11, 159, 103, 737, 1989, 59, 4711, 8093, 31703, 45663, 92913}},
-{12495, 17, 57601, {1, 3, 3, 11, 15, 9, 35, 217, 299, 479, 1539, 2605, 2003, 8841, 27261, 28853, 98877}},
-{12496, 17, 57604, {1, 1, 5, 5, 15, 45, 73, 159, 205, 1017, 159, 3659, 2377, 3651, 6489, 19711, 109959}},
-{12497, 17, 57607, {1, 1, 3, 15, 7, 41, 7, 47, 357, 433, 211, 111, 2565, 8637, 15917, 47887, 128513}},
-{12498, 17, 57621, {1, 3, 7, 3, 25, 9, 33, 33, 5, 805, 1541, 3333, 7257, 9011, 4813, 53195, 52469}},
-{12499, 17, 57635, {1, 1, 7, 15, 27, 3, 11, 57, 415, 371, 563, 2515, 149, 6555, 31273, 51465, 2989}},
-{12500, 17, 57642, {1, 1, 1, 11, 3, 41, 25, 175, 499, 879, 1145, 1083, 7857, 10497, 16991, 23351, 115353}},
-{12501, 17, 57650, {1, 1, 3, 15, 15, 9, 39, 239, 285, 413, 989, 2927, 7205, 79, 20101, 30115, 113933}},
-{12502, 17, 57655, {1, 1, 7, 5, 13, 29, 29, 69, 25, 533, 1731, 1391, 4065, 12597, 19167, 51989, 101273}},
-{12503, 17, 57670, {1, 1, 5, 3, 9, 41, 83, 127, 197, 627, 173, 273, 593, 15733, 19285, 26517, 107877}},
-{12504, 17, 57676, {1, 1, 1, 5, 29, 17, 89, 163, 125, 473, 1577, 2435, 3379, 3057, 1829, 64325, 111719}},
-{12505, 17, 57682, {1, 3, 1, 11, 1, 29, 97, 53, 421, 941, 1737, 3337, 2715, 1633, 28485, 30369, 116047}},
-{12506, 17, 57687, {1, 1, 5, 13, 25, 43, 39, 85, 385, 129, 819, 1647, 3527, 12319, 573, 58703, 29463}},
-{12507, 17, 57691, {1, 3, 3, 9, 23, 59, 31, 215, 49, 451, 645, 3687, 4507, 9359, 28161, 34609, 123409}},
-{12508, 17, 57700, {1, 3, 1, 9, 13, 25, 97, 239, 203, 31, 1465, 1089, 7665, 3007, 22465, 28389, 119869}},
-{12509, 17, 57704, {1, 3, 3, 1, 29, 51, 19, 83, 443, 193, 647, 3125, 7269, 3031, 9967, 40447, 102179}},
-{12510, 17, 57707, {1, 3, 5, 15, 5, 63, 125, 55, 295, 787, 559, 3309, 7491, 9907, 5775, 15155, 41793}},
-{12511, 17, 57721, {1, 3, 7, 7, 21, 61, 125, 207, 43, 159, 539, 435, 1945, 725, 797, 47489, 43099}},
-{12512, 17, 57731, {1, 1, 5, 7, 11, 11, 61, 103, 23, 693, 493, 1045, 4435, 9009, 22075, 24839, 125431}},
-{12513, 17, 57733, {1, 3, 1, 9, 13, 61, 83, 181, 373, 949, 1397, 247, 5079, 10933, 31887, 14147, 55121}},
-{12514, 17, 57738, {1, 1, 7, 15, 31, 47, 87, 219, 357, 409, 943, 2993, 7615, 7071, 14179, 41489, 104401}},
-{12515, 17, 57745, {1, 3, 3, 1, 11, 15, 87, 241, 389, 761, 1523, 3049, 2111, 11581, 5493, 11301, 32017}},
-{12516, 17, 57748, {1, 1, 7, 11, 29, 39, 37, 63, 411, 671, 1789, 3541, 5651, 11721, 10871, 53867, 112895}},
-{12517, 17, 57751, {1, 3, 3, 1, 23, 21, 99, 161, 467, 197, 1263, 451, 5469, 7667, 22139, 31599, 8345}},
-{12518, 17, 57757, {1, 3, 1, 3, 11, 41, 13, 79, 3, 377, 1865, 2297, 1383, 14033, 17141, 24787, 127911}},
-{12519, 17, 57761, {1, 1, 1, 1, 5, 11, 5, 181, 323, 853, 831, 1599, 3939, 6391, 22817, 37969, 9997}},
-{12520, 17, 57774, {1, 1, 3, 11, 29, 61, 11, 171, 181, 631, 757, 3879, 4779, 16183, 5969, 7909, 42855}},
-{12521, 17, 57779, {1, 3, 3, 15, 19, 17, 107, 187, 19, 743, 909, 1963, 2131, 2107, 659, 35829, 57905}},
-{12522, 17, 57786, {1, 1, 7, 1, 31, 29, 67, 99, 353, 715, 65, 3907, 1931, 1289, 9217, 60635, 32737}},
-{12523, 17, 57808, {1, 3, 3, 13, 3, 17, 19, 173, 263, 203, 1233, 1407, 933, 8905, 26905, 63343, 64963}},
-{12524, 17, 57814, {1, 3, 1, 13, 21, 43, 97, 79, 163, 529, 1571, 1027, 4339, 16235, 9189, 29203, 36789}},
-{12525, 17, 57817, {1, 1, 7, 1, 31, 1, 117, 247, 193, 333, 1797, 3515, 285, 2803, 25345, 9101, 110569}},
-{12526, 17, 57824, {1, 1, 5, 11, 17, 63, 45, 167, 35, 925, 569, 3687, 6739, 12453, 26171, 28249, 73827}},
-{12527, 17, 57827, {1, 1, 5, 1, 19, 49, 107, 183, 435, 305, 1191, 2711, 891, 15813, 13449, 23489, 89749}},
-{12528, 17, 57848, {1, 1, 1, 11, 7, 53, 105, 17, 433, 351, 1151, 4077, 5371, 10183, 18895, 13229, 101219}},
-{12529, 17, 57853, {1, 3, 7, 9, 21, 33, 27, 125, 177, 607, 817, 2689, 2123, 2037, 29643, 27219, 44591}},
-{12530, 17, 57857, {1, 3, 5, 11, 27, 51, 29, 161, 469, 349, 1445, 3613, 1487, 961, 29017, 2235, 45905}},
-{12531, 17, 57858, {1, 1, 3, 11, 7, 15, 37, 195, 329, 875, 559, 1361, 7373, 7143, 15059, 59205, 37167}},
-{12532, 17, 57867, {1, 1, 5, 1, 7, 25, 27, 211, 301, 369, 227, 123, 4415, 15993, 4829, 43801, 83639}},
-{12533, 17, 57872, {1, 1, 3, 5, 25, 37, 31, 205, 69, 275, 855, 1407, 2989, 11001, 16963, 31497, 3505}},
-{12534, 17, 57887, {1, 1, 7, 7, 25, 33, 81, 181, 197, 717, 207, 535, 8083, 5765, 2523, 40347, 27245}},
-{12535, 17, 57894, {1, 3, 1, 5, 13, 3, 107, 143, 233, 419, 1831, 2149, 7277, 13449, 31609, 48345, 82621}},
-{12536, 17, 57915, {1, 3, 5, 9, 31, 35, 39, 113, 415, 803, 1479, 3169, 8015, 4659, 2445, 9159, 91625}},
-{12537, 17, 57920, {1, 3, 1, 5, 27, 25, 83, 165, 459, 955, 1535, 377, 5531, 2945, 18285, 18097, 21589}},
-{12538, 17, 57923, {1, 1, 1, 15, 13, 23, 11, 159, 471, 951, 1971, 677, 2641, 3227, 14761, 39421, 29841}},
-{12539, 17, 57932, {1, 1, 7, 11, 19, 37, 101, 97, 373, 559, 105, 905, 897, 15309, 14979, 52029, 38989}},
-{12540, 17, 57937, {1, 1, 5, 15, 31, 43, 71, 75, 481, 997, 5, 1005, 4987, 7907, 16237, 43075, 94827}},
-{12541, 17, 57943, {1, 3, 5, 11, 23, 55, 123, 91, 183, 307, 97, 1999, 3341, 4717, 19643, 9455, 26555}},
-{12542, 17, 57950, {1, 1, 7, 3, 29, 61, 75, 197, 125, 579, 145, 1333, 85, 15655, 28177, 6169, 43289}},
-{12543, 17, 57960, {1, 3, 7, 13, 21, 15, 1, 221, 293, 991, 35, 2701, 2909, 7333, 27319, 32281, 77861}},
-{12544, 17, 57971, {1, 1, 3, 1, 17, 11, 81, 209, 499, 125, 105, 2987, 3891, 9531, 27963, 39611, 43633}},
-{12545, 17, 57974, {1, 3, 3, 3, 29, 45, 51, 63, 209, 75, 1321, 4055, 7851, 12329, 8371, 59513, 49105}},
-{12546, 17, 57983, {1, 1, 7, 5, 9, 63, 59, 127, 445, 899, 1857, 3737, 625, 15021, 25177, 21007, 25935}},
-{12547, 17, 57987, {1, 1, 5, 9, 9, 57, 25, 63, 235, 191, 1527, 1783, 1401, 1813, 2553, 1241, 100029}},
-{12548, 17, 57994, {1, 3, 1, 11, 27, 5, 49, 39, 505, 653, 1083, 921, 1045, 11337, 25499, 36211, 75851}},
-{12549, 17, 58001, {1, 3, 3, 1, 29, 19, 71, 93, 223, 153, 561, 1657, 5821, 14181, 1275, 24633, 114787}},
-{12550, 17, 58002, {1, 1, 1, 9, 7, 13, 17, 239, 457, 731, 1811, 3015, 4465, 5865, 2387, 30455, 17405}},
-{12551, 17, 58013, {1, 3, 5, 1, 7, 45, 117, 207, 7, 645, 131, 863, 6443, 14455, 11885, 39257, 126431}},
-{12552, 17, 58023, {1, 1, 3, 5, 17, 23, 3, 27, 475, 731, 431, 1967, 981, 12727, 1301, 17647, 62481}},
-{12553, 17, 58027, {1, 1, 1, 13, 11, 53, 105, 109, 105, 461, 1787, 2851, 1299, 9925, 13055, 58301, 24483}},
-{12554, 17, 58029, {1, 1, 1, 11, 7, 35, 11, 173, 247, 289, 1269, 361, 2059, 5051, 25731, 58085, 21387}},
-{12555, 17, 58032, {1, 3, 1, 5, 9, 31, 59, 151, 435, 519, 1863, 2255, 2585, 10033, 29189, 27189, 25023}},
-{12556, 17, 58041, {1, 1, 5, 5, 25, 17, 53, 189, 187, 847, 369, 3287, 6047, 2385, 26045, 48821, 23335}},
-{12557, 17, 58047, {1, 1, 1, 9, 15, 55, 79, 21, 433, 131, 1677, 3681, 6173, 9189, 15053, 12971, 81135}},
-{12558, 17, 58062, {1, 1, 3, 5, 29, 5, 11, 213, 151, 77, 1493, 3959, 7675, 7689, 10381, 15871, 123463}},
-{12559, 17, 58086, {1, 3, 7, 11, 19, 47, 31, 81, 207, 789, 1945, 2671, 1987, 6363, 26401, 9799, 59531}},
-{12560, 17, 58092, {1, 1, 1, 7, 17, 7, 83, 181, 339, 423, 267, 2251, 1847, 14883, 13423, 27223, 81799}},
-{12561, 17, 58095, {1, 3, 5, 15, 9, 9, 73, 95, 197, 267, 743, 2369, 6417, 3555, 9885, 6373, 87651}},
-{12562, 17, 58097, {1, 1, 3, 13, 21, 29, 57, 59, 395, 631, 993, 17, 2939, 14117, 27521, 61387, 74927}},
-{12563, 17, 58100, {1, 1, 3, 13, 1, 29, 23, 151, 381, 591, 1217, 2295, 4403, 15865, 4325, 31329, 56989}},
-{12564, 17, 58117, {1, 3, 5, 1, 27, 7, 111, 79, 287, 945, 1237, 2857, 1461, 2477, 10929, 17117, 98677}},
-{12565, 17, 58121, {1, 1, 1, 5, 15, 35, 109, 39, 391, 57, 1783, 3133, 5563, 7721, 12651, 3437, 46697}},
-{12566, 17, 58132, {1, 3, 5, 5, 13, 47, 123, 51, 383, 91, 641, 1607, 4461, 7, 6427, 42755, 130097}},
-{12567, 17, 58142, {1, 1, 5, 5, 25, 49, 33, 59, 351, 1003, 301, 2721, 7705, 5447, 21367, 63007, 112465}},
-{12568, 17, 58145, {1, 1, 5, 13, 31, 11, 73, 1, 359, 201, 1465, 187, 7385, 12817, 12911, 17775, 77937}},
-{12569, 17, 58152, {1, 3, 1, 15, 29, 5, 117, 69, 79, 93, 947, 133, 1049, 13907, 3611, 42123, 8041}},
-{12570, 17, 58155, {1, 1, 7, 7, 29, 17, 71, 171, 357, 619, 1199, 3817, 6889, 9607, 19075, 15539, 54939}},
-{12571, 17, 58163, {1, 1, 1, 7, 23, 29, 91, 227, 119, 865, 943, 381, 5289, 189, 15917, 13875, 31095}},
-{12572, 17, 58166, {1, 1, 7, 1, 9, 49, 93, 175, 105, 61, 1285, 3659, 2383, 505, 12337, 43801, 67035}},
-{12573, 17, 58170, {1, 3, 5, 1, 31, 47, 75, 17, 455, 231, 1887, 2295, 2533, 733, 29001, 22001, 119423}},
-{12574, 17, 58175, {1, 3, 7, 3, 5, 5, 69, 205, 459, 805, 1257, 3283, 3305, 6845, 1405, 56051, 63453}},
-{12575, 17, 58184, {1, 3, 3, 3, 19, 57, 65, 149, 175, 683, 1719, 637, 4951, 13645, 30455, 22379, 105369}},
-{12576, 17, 58197, {1, 3, 1, 11, 31, 27, 69, 13, 191, 645, 1563, 3897, 2387, 2269, 12999, 42217, 100853}},
-{12577, 17, 58202, {1, 3, 1, 13, 31, 7, 11, 227, 267, 373, 1249, 2591, 4769, 303, 5865, 59911, 4991}},
-{12578, 17, 58204, {1, 3, 7, 11, 7, 31, 87, 205, 45, 785, 1947, 1965, 5851, 7501, 89, 38897, 91939}},
-{12579, 17, 58208, {1, 3, 5, 9, 21, 37, 79, 181, 163, 355, 1129, 3439, 5103, 15903, 2935, 22505, 97451}},
-{12580, 17, 58213, {1, 1, 3, 9, 7, 37, 107, 255, 69, 133, 551, 1357, 31, 7059, 29195, 30151, 81785}},
-{12581, 17, 58220, {1, 3, 3, 5, 3, 51, 3, 143, 305, 697, 1041, 1267, 7635, 1483, 649, 28275, 65059}},
-{12582, 17, 58226, {1, 3, 1, 7, 11, 13, 113, 81, 159, 993, 797, 3207, 3787, 13005, 29393, 51107, 42709}},
-{12583, 17, 58231, {1, 1, 3, 13, 7, 11, 113, 195, 349, 377, 2033, 197, 147, 13839, 5405, 29577, 64535}},
-{12584, 17, 58235, {1, 3, 1, 9, 1, 1, 77, 73, 383, 463, 1871, 1589, 1805, 2085, 5195, 17805, 33159}},
-{12585, 17, 58254, {1, 1, 1, 9, 25, 37, 123, 119, 507, 515, 1547, 139, 7501, 4725, 30195, 18199, 41145}},
-{12586, 17, 58261, {1, 3, 3, 7, 17, 33, 99, 11, 487, 343, 403, 337, 3831, 6031, 20375, 2071, 39795}},
-{12587, 17, 58271, {1, 1, 5, 1, 13, 57, 59, 11, 391, 953, 597, 1411, 3929, 13963, 15003, 59385, 12293}},
-{12588, 17, 58278, {1, 3, 1, 15, 23, 61, 67, 129, 63, 555, 433, 631, 2725, 317, 10121, 9217, 124371}},
-{12589, 17, 58287, {1, 1, 5, 7, 19, 23, 17, 45, 75, 819, 1879, 2315, 1439, 2643, 26561, 19209, 16081}},
-{12590, 17, 58327, {1, 3, 5, 7, 5, 35, 121, 233, 91, 89, 1741, 3015, 4223, 9605, 22795, 55845, 47167}},
-{12591, 17, 58333, {1, 3, 7, 7, 13, 23, 11, 51, 91, 367, 773, 1303, 2151, 14423, 22263, 28413, 107461}},
-{12592, 17, 58337, {1, 1, 1, 11, 29, 17, 49, 53, 379, 819, 1551, 2907, 5805, 2167, 16123, 9263, 43903}},
-{12593, 17, 58357, {1, 3, 1, 13, 19, 27, 33, 127, 131, 697, 489, 3289, 1895, 3243, 19497, 32419, 55741}},
-{12594, 17, 58362, {1, 3, 1, 15, 7, 51, 91, 45, 251, 829, 2015, 2659, 151, 3327, 25281, 49291, 106343}},
-{12595, 17, 58364, {1, 1, 5, 5, 27, 11, 85, 45, 203, 413, 293, 3067, 4109, 959, 22337, 38767, 75829}},
-{12596, 17, 58375, {1, 1, 3, 5, 21, 35, 65, 173, 315, 423, 171, 3837, 817, 10153, 5517, 18115, 117437}},
-{12597, 17, 58384, {1, 1, 1, 7, 9, 29, 101, 55, 253, 37, 1717, 7, 3181, 1067, 20637, 54773, 106777}},
-{12598, 17, 58387, {1, 3, 7, 11, 13, 11, 87, 83, 83, 969, 589, 3625, 3373, 3921, 24487, 34235, 96289}},
-{12599, 17, 58405, {1, 3, 1, 11, 25, 35, 65, 131, 491, 167, 449, 2949, 5807, 5649, 7569, 37363, 106819}},
-{12600, 17, 58406, {1, 1, 5, 1, 9, 37, 33, 237, 79, 163, 1791, 3499, 4951, 2009, 16183, 10121, 40221}},
-{12601, 17, 58417, {1, 1, 5, 15, 21, 49, 123, 53, 27, 273, 1655, 3713, 5699, 1659, 31985, 6779, 10195}},
-{12602, 17, 58424, {1, 3, 5, 11, 27, 37, 93, 17, 263, 41, 1583, 703, 7689, 6667, 15497, 15255, 67153}},
-{12603, 17, 58435, {1, 1, 5, 9, 19, 13, 121, 39, 321, 177, 711, 3223, 3859, 14775, 19061, 40587, 97199}},
-{12604, 17, 58450, {1, 3, 7, 9, 23, 11, 93, 243, 3, 811, 679, 1103, 7579, 14147, 20255, 22485, 117179}},
-{12605, 17, 58452, {1, 3, 3, 5, 23, 9, 21, 243, 27, 501, 1273, 1501, 5331, 15663, 19483, 10637, 90905}},
-{12606, 17, 58459, {1, 3, 1, 15, 13, 11, 89, 37, 63, 463, 731, 3615, 3923, 4677, 21329, 1069, 57565}},
-{12607, 17, 58461, {1, 1, 1, 13, 19, 39, 63, 59, 389, 367, 1285, 2005, 8103, 4179, 3805, 55475, 126589}},
-{12608, 17, 58466, {1, 3, 5, 11, 27, 57, 27, 63, 365, 171, 665, 2035, 2831, 15955, 11551, 26741, 121059}},
-{12609, 17, 58468, {1, 3, 3, 3, 23, 19, 13, 7, 331, 613, 1783, 733, 7465, 1089, 4683, 15695, 31125}},
-{12610, 17, 58485, {1, 1, 5, 3, 3, 23, 95, 157, 303, 987, 307, 2679, 6173, 6633, 17727, 30901, 76109}},
-{12611, 17, 58489, {1, 1, 1, 1, 11, 21, 111, 81, 31, 727, 1133, 4083, 5811, 2707, 31749, 42939, 92225}},
-{12612, 17, 58492, {1, 3, 1, 11, 29, 21, 31, 115, 351, 213, 201, 3511, 3707, 12821, 8845, 59789, 59721}},
-{12613, 17, 58495, {1, 3, 5, 9, 7, 27, 65, 1, 305, 937, 1201, 2045, 2431, 12275, 24431, 3317, 119671}},
-{12614, 17, 58505, {1, 1, 7, 11, 19, 43, 107, 107, 261, 933, 1125, 1875, 1943, 7477, 20759, 57853, 29459}},
-{12615, 17, 58523, {1, 1, 3, 3, 17, 43, 79, 19, 167, 341, 237, 677, 725, 2353, 12003, 48921, 20707}},
-{12616, 17, 58535, {1, 3, 3, 5, 31, 39, 91, 81, 121, 59, 737, 1767, 4407, 9159, 10237, 25361, 38891}},
-{12617, 17, 58536, {1, 1, 5, 7, 31, 47, 37, 47, 171, 623, 597, 2807, 4875, 15139, 18809, 24279, 36563}},
-{12618, 17, 58549, {1, 3, 5, 3, 3, 7, 31, 135, 81, 777, 1055, 337, 4309, 9575, 11075, 54429, 30097}},
-{12619, 17, 58550, {1, 1, 5, 1, 3, 57, 53, 25, 117, 961, 947, 257, 2645, 6935, 27511, 54051, 129095}},
-{12620, 17, 58561, {1, 1, 1, 15, 23, 45, 11, 173, 407, 373, 1051, 3519, 1875, 1291, 4393, 9047, 102159}},
-{12621, 17, 58562, {1, 1, 3, 5, 9, 51, 23, 253, 261, 339, 505, 3601, 265, 8375, 7241, 40715, 114439}},
-{12622, 17, 58573, {1, 1, 7, 7, 3, 63, 5, 233, 259, 947, 1367, 2699, 6029, 9371, 6567, 39961, 31621}},
-{12623, 17, 58576, {1, 1, 3, 3, 25, 43, 73, 61, 305, 257, 235, 421, 6621, 1025, 18831, 44525, 87665}},
-{12624, 17, 58592, {1, 3, 5, 7, 19, 33, 77, 163, 191, 115, 1275, 3551, 3521, 6767, 30209, 48895, 114185}},
-{12625, 17, 58601, {1, 1, 3, 3, 29, 37, 3, 165, 267, 807, 967, 2893, 3287, 12249, 21411, 19291, 91781}},
-{12626, 17, 58622, {1, 1, 5, 5, 27, 55, 51, 137, 429, 775, 1525, 3911, 5367, 5981, 24373, 16331, 31887}},
-{12627, 17, 58627, {1, 1, 5, 11, 17, 49, 37, 243, 509, 563, 1381, 2013, 7341, 10509, 10049, 29135, 32709}},
-{12628, 17, 58629, {1, 1, 3, 13, 1, 33, 119, 5, 477, 701, 1329, 1023, 2091, 12895, 6443, 1053, 44741}},
-{12629, 17, 58634, {1, 3, 5, 7, 13, 19, 1, 113, 3, 481, 1555, 2857, 3519, 7903, 16153, 62909, 78877}},
-{12630, 17, 58639, {1, 1, 7, 11, 7, 27, 47, 175, 87, 605, 411, 4065, 8059, 5023, 27719, 3111, 62247}},
-{12631, 17, 58641, {1, 3, 1, 15, 27, 37, 71, 77, 297, 647, 1651, 2543, 3925, 4827, 28587, 49663, 56581}},
-{12632, 17, 58644, {1, 3, 5, 1, 19, 49, 63, 9, 43, 243, 931, 3577, 2371, 10513, 13691, 27739, 61011}},
-{12633, 17, 58654, {1, 1, 3, 1, 23, 27, 53, 149, 157, 735, 1087, 1529, 6613, 2493, 4879, 26771, 123711}},
-{12634, 17, 58663, {1, 3, 7, 13, 5, 3, 43, 3, 343, 497, 943, 3443, 4335, 4779, 4033, 25871, 10965}},
-{12635, 17, 58667, {1, 3, 5, 1, 5, 11, 93, 73, 199, 455, 421, 3495, 4381, 717, 21033, 41287, 44743}},
-{12636, 17, 58677, {1, 1, 3, 9, 13, 33, 77, 143, 81, 57, 1061, 3205, 2411, 1347, 23149, 21913, 119331}},
-{12637, 17, 58682, {1, 3, 1, 7, 1, 15, 45, 247, 119, 905, 457, 3939, 4865, 11191, 27705, 46315, 68367}},
-{12638, 17, 58690, {1, 3, 3, 15, 31, 5, 55, 169, 381, 1009, 1893, 2751, 411, 8653, 30367, 54919, 23541}},
-{12639, 17, 58692, {1, 3, 7, 1, 29, 27, 77, 239, 109, 125, 355, 2759, 2229, 3435, 16241, 53309, 613}},
-{12640, 17, 58695, {1, 3, 1, 3, 11, 27, 33, 167, 311, 1003, 1635, 2479, 1831, 6225, 17711, 30185, 87043}},
-{12641, 17, 58710, {1, 3, 7, 13, 7, 61, 3, 243, 55, 259, 461, 3357, 121, 9107, 19393, 3719, 71403}},
-{12642, 17, 58713, {1, 1, 7, 15, 23, 25, 55, 89, 241, 297, 113, 59, 4799, 381, 29127, 811, 91149}},
-{12643, 17, 58723, {1, 1, 3, 3, 13, 35, 43, 163, 69, 69, 1949, 2383, 887, 2349, 12539, 167, 23697}},
-{12644, 17, 58740, {1, 3, 3, 11, 3, 45, 23, 149, 55, 963, 1293, 2715, 1401, 16081, 12821, 2129, 26835}},
-{12645, 17, 58749, {1, 3, 3, 13, 29, 47, 21, 249, 141, 179, 627, 329, 6377, 12049, 11715, 1447, 119359}},
-{12646, 17, 58760, {1, 1, 5, 13, 7, 59, 103, 189, 401, 169, 455, 1197, 1881, 12679, 4533, 25561, 79281}},
-{12647, 17, 58766, {1, 1, 7, 15, 21, 59, 97, 77, 397, 487, 647, 2277, 269, 713, 17741, 37387, 100143}},
-{12648, 17, 58773, {1, 3, 5, 1, 1, 43, 31, 201, 21, 805, 1533, 1407, 4719, 2673, 22757, 7605, 72485}},
-{12649, 17, 58780, {1, 1, 3, 11, 27, 25, 99, 135, 225, 367, 1311, 683, 7193, 8209, 17081, 55709, 3029}},
-{12650, 17, 58787, {1, 3, 5, 5, 17, 9, 59, 27, 153, 353, 647, 2919, 1877, 5359, 19787, 46237, 7}},
-{12651, 17, 58796, {1, 3, 3, 15, 11, 39, 75, 223, 489, 57, 1355, 3941, 6603, 12883, 20909, 24065, 53543}},
-{12652, 17, 58816, {1, 1, 3, 9, 17, 47, 61, 49, 397, 23, 2019, 37, 23, 8967, 10357, 54419, 27279}},
-{12653, 17, 58822, {1, 1, 1, 7, 31, 43, 87, 111, 293, 969, 1431, 2275, 3131, 2915, 24595, 63049, 71517}},
-{12654, 17, 58831, {1, 1, 3, 11, 11, 63, 89, 33, 95, 299, 593, 3353, 7389, 841, 1895, 64835, 19915}},
-{12655, 17, 58839, {1, 1, 1, 3, 13, 63, 51, 3, 327, 401, 1289, 2699, 5599, 5101, 3189, 23415, 53429}},
-{12656, 17, 58849, {1, 1, 7, 13, 27, 15, 57, 201, 365, 643, 171, 2417, 1763, 7567, 5323, 50911, 24281}},
-{12657, 17, 58859, {1, 3, 3, 13, 31, 37, 31, 243, 225, 431, 379, 1565, 1567, 11477, 4641, 58823, 88565}},
-{12658, 17, 58870, {1, 3, 3, 7, 13, 39, 79, 169, 401, 177, 2023, 1703, 5563, 15619, 21445, 59287, 30141}},
-{12659, 17, 58879, {1, 3, 3, 15, 17, 47, 13, 163, 361, 353, 1435, 2083, 4109, 14105, 28585, 1721, 119133}},
-{12660, 17, 58889, {1, 3, 3, 3, 29, 41, 97, 131, 501, 415, 1735, 2315, 6499, 11417, 3879, 3957, 47117}},
-{12661, 17, 58904, {1, 1, 3, 13, 5, 25, 29, 65, 235, 949, 1571, 927, 515, 7519, 23123, 4127, 71019}},
-{12662, 17, 58914, {1, 1, 5, 13, 1, 41, 5, 137, 487, 711, 561, 2495, 5367, 6955, 9453, 54499, 118373}},
-{12663, 17, 58923, {1, 3, 3, 5, 27, 15, 23, 237, 95, 873, 1949, 1579, 7089, 8837, 30463, 9903, 61919}},
-{12664, 17, 58940, {1, 3, 1, 13, 5, 5, 15, 5, 429, 617, 383, 2495, 409, 15541, 11209, 20625, 58493}},
-{12665, 17, 58945, {1, 1, 7, 11, 25, 21, 113, 219, 459, 777, 289, 2435, 6665, 83, 22997, 6561, 82923}},
-{12666, 17, 58952, {1, 1, 1, 7, 19, 53, 37, 249, 273, 639, 2007, 1463, 7819, 9013, 19539, 41235, 58059}},
-{12667, 17, 58960, {1, 1, 3, 11, 13, 51, 97, 55, 237, 159, 1305, 3705, 2527, 13065, 13873, 10275, 3769}},
-{12668, 17, 58965, {1, 1, 5, 7, 13, 49, 41, 13, 301, 461, 1169, 3805, 7163, 4133, 17255, 48283, 87059}},
-{12669, 17, 58986, {1, 3, 7, 15, 9, 19, 45, 195, 445, 145, 543, 2839, 315, 10991, 3317, 46501, 29209}},
-{12670, 17, 59000, {1, 1, 3, 5, 23, 51, 53, 119, 217, 747, 1307, 3039, 5523, 5891, 21035, 56471, 80305}},
-{12671, 17, 59006, {1, 3, 1, 3, 23, 17, 97, 71, 7, 839, 229, 3407, 3025, 1989, 16599, 38755, 11139}},
-{12672, 17, 59027, {1, 1, 7, 7, 7, 19, 67, 43, 293, 191, 1549, 1621, 7083, 11633, 1899, 4515, 89753}},
-{12673, 17, 59034, {1, 3, 7, 11, 1, 23, 17, 63, 265, 709, 453, 1309, 6861, 7257, 17705, 28565, 15231}},
-{12674, 17, 59052, {1, 3, 5, 13, 1, 53, 99, 79, 241, 771, 497, 987, 2353, 6931, 227, 57781, 109583}},
-{12675, 17, 59058, {1, 3, 3, 5, 31, 47, 17, 97, 93, 119, 2045, 3597, 7983, 4993, 30659, 3419, 32803}},
-{12676, 17, 59081, {1, 3, 7, 1, 11, 41, 3, 7, 155, 627, 979, 2405, 7467, 6763, 28523, 56493, 1291}},
-{12677, 17, 59082, {1, 1, 1, 7, 3, 43, 13, 187, 415, 1001, 667, 1371, 8075, 12855, 27215, 9399, 70657}},
-{12678, 17, 59089, {1, 3, 1, 9, 29, 53, 117, 17, 443, 381, 507, 643, 5891, 10725, 20251, 497, 101313}},
-{12679, 17, 59096, {1, 3, 3, 1, 31, 47, 59, 75, 173, 347, 1, 117, 3639, 10231, 863, 56795, 56107}},
-{12680, 17, 59118, {1, 3, 1, 15, 11, 41, 97, 251, 177, 275, 1849, 1281, 3659, 9709, 16239, 7445, 47661}},
-{12681, 17, 59123, {1, 3, 3, 5, 13, 1, 27, 251, 89, 863, 685, 3915, 2201, 4313, 32083, 37171, 120885}},
-{12682, 17, 59126, {1, 3, 3, 3, 3, 11, 77, 135, 147, 475, 505, 611, 4763, 9445, 28639, 51343, 119093}},
-{12683, 17, 59132, {1, 3, 7, 1, 11, 9, 67, 73, 375, 977, 1011, 1621, 6623, 8077, 26321, 7461, 130637}},
-{12684, 17, 59135, {1, 3, 5, 15, 15, 59, 63, 217, 117, 375, 1151, 3451, 5843, 13221, 20673, 10817, 57711}},
-{12685, 17, 59150, {1, 1, 3, 5, 19, 5, 9, 101, 321, 815, 451, 719, 523, 1299, 27823, 48041, 45939}},
-{12686, 17, 59174, {1, 1, 1, 9, 5, 49, 59, 59, 409, 5, 1075, 21, 7837, 4543, 3085, 55473, 89309}},
-{12687, 17, 59177, {1, 3, 3, 13, 9, 31, 93, 181, 153, 795, 713, 933, 6001, 9075, 29781, 14029, 46361}},
-{12688, 17, 59185, {1, 3, 5, 3, 9, 21, 79, 129, 361, 627, 743, 3041, 5381, 3627, 12581, 35183, 83183}},
-{12689, 17, 59195, {1, 3, 3, 3, 29, 29, 93, 187, 341, 727, 181, 133, 6525, 5673, 2739, 23349, 62505}},
-{12690, 17, 59203, {1, 3, 5, 13, 27, 59, 127, 149, 321, 613, 1543, 1537, 2909, 5139, 3755, 49285, 35183}},
-{12691, 17, 59206, {1, 3, 3, 9, 5, 31, 19, 173, 137, 19, 799, 1847, 3897, 15775, 22411, 55405, 95713}},
-{12692, 17, 59234, {1, 3, 5, 5, 31, 1, 87, 97, 481, 797, 459, 793, 4339, 5443, 31717, 6691, 68841}},
-{12693, 17, 59248, {1, 3, 3, 5, 3, 9, 123, 21, 393, 683, 1007, 971, 729, 7113, 2811, 51183, 37093}},
-{12694, 17, 59258, {1, 3, 5, 5, 27, 31, 19, 227, 123, 937, 763, 2117, 3825, 9151, 95, 54963, 62919}},
-{12695, 17, 59260, {1, 3, 1, 3, 23, 21, 21, 7, 7, 165, 99, 3073, 91, 8725, 17613, 47119, 41441}},
-{12696, 17, 59270, {1, 3, 7, 9, 29, 49, 117, 49, 205, 605, 1567, 3323, 1559, 10949, 14349, 34951, 99901}},
-{12697, 17, 59284, {1, 1, 1, 1, 15, 41, 31, 133, 439, 305, 719, 147, 6849, 5947, 31749, 45171, 15265}},
-{12698, 17, 59291, {1, 1, 5, 11, 19, 37, 13, 253, 385, 625, 1801, 1191, 547, 12025, 17971, 54127, 97323}},
-{12699, 17, 59293, {1, 3, 5, 5, 27, 9, 57, 245, 59, 211, 1195, 763, 6743, 6309, 25759, 26633, 27497}},
-{12700, 17, 59297, {1, 3, 5, 5, 9, 51, 49, 29, 213, 855, 305, 3961, 3187, 6815, 19015, 2539, 81705}},
-{12701, 17, 59312, {1, 1, 5, 7, 11, 61, 123, 163, 127, 871, 463, 2279, 5931, 2913, 23215, 40215, 91373}},
-{12702, 17, 59315, {1, 1, 7, 1, 29, 57, 55, 189, 285, 603, 747, 3753, 3359, 10277, 25319, 17569, 80125}},
-{12703, 17, 59327, {1, 3, 1, 9, 7, 53, 9, 55, 117, 495, 2045, 2487, 1625, 775, 17773, 62159, 79537}},
-{12704, 17, 59332, {1, 1, 5, 1, 1, 11, 67, 79, 57, 677, 2045, 3913, 853, 3581, 10509, 35097, 24585}},
-{12705, 17, 59347, {1, 3, 7, 7, 19, 15, 13, 237, 297, 807, 657, 2229, 2931, 10283, 49, 56485, 113889}},
-{12706, 17, 59354, {1, 3, 5, 13, 11, 23, 37, 229, 253, 411, 39, 1069, 3683, 12141, 11087, 64875, 62991}},
-{12707, 17, 59363, {1, 1, 1, 1, 13, 11, 21, 227, 305, 1021, 1039, 3095, 4621, 5723, 31989, 30681, 58487}},
-{12708, 17, 59369, {1, 3, 3, 5, 17, 47, 127, 65, 85, 961, 277, 549, 2111, 4183, 771, 11921, 111489}},
-{12709, 17, 59377, {1, 3, 3, 5, 31, 39, 89, 51, 277, 705, 375, 1603, 2793, 7425, 25065, 44945, 48391}},
-{12710, 17, 59406, {1, 1, 5, 7, 9, 45, 21, 217, 183, 65, 625, 1239, 4241, 8043, 13615, 5611, 82501}},
-{12711, 17, 59413, {1, 1, 7, 13, 15, 51, 29, 35, 73, 601, 233, 3117, 3031, 4229, 4299, 62761, 45291}},
-{12712, 17, 59423, {1, 3, 5, 5, 27, 55, 7, 1, 333, 501, 913, 1939, 5131, 5597, 1271, 30195, 20947}},
-{12713, 17, 59434, {1, 3, 5, 15, 19, 27, 43, 111, 435, 615, 811, 2113, 2503, 7553, 1619, 24773, 40881}},
-{12714, 17, 59441, {1, 3, 5, 11, 11, 31, 21, 147, 151, 141, 527, 1839, 339, 1225, 29621, 19691, 22031}},
-{12715, 17, 59442, {1, 1, 3, 13, 23, 35, 61, 181, 221, 837, 241, 3033, 1849, 12563, 11387, 3027, 33419}},
-{12716, 17, 59456, {1, 3, 3, 7, 1, 39, 125, 249, 231, 575, 1847, 197, 3969, 12945, 10257, 27227, 94097}},
-{12717, 17, 59465, {1, 3, 1, 11, 19, 7, 85, 119, 37, 253, 1575, 447, 6947, 14399, 32095, 15385, 62917}},
-{12718, 17, 59479, {1, 3, 7, 11, 23, 53, 113, 193, 253, 651, 1717, 447, 4055, 13675, 18479, 28375, 66475}},
-{12719, 17, 59501, {1, 1, 7, 3, 17, 27, 13, 209, 67, 271, 121, 1565, 2589, 8033, 3939, 14181, 111787}},
-{12720, 17, 59504, {1, 1, 3, 3, 5, 57, 75, 87, 165, 947, 967, 3353, 2055, 16195, 3701, 62637, 58343}},
-{12721, 17, 59507, {1, 1, 7, 13, 31, 41, 125, 111, 253, 257, 57, 679, 3333, 8259, 26331, 15883, 95023}},
-{12722, 17, 59514, {1, 3, 7, 11, 1, 47, 5, 249, 353, 271, 1121, 1935, 4971, 8447, 9983, 55959, 66179}},
-{12723, 17, 59523, {1, 3, 5, 11, 1, 61, 101, 43, 97, 241, 687, 4027, 4319, 4905, 12357, 51099, 97093}},
-{12724, 17, 59525, {1, 1, 3, 15, 25, 25, 117, 139, 475, 961, 1585, 2795, 2411, 11049, 18209, 15511, 43193}},
-{12725, 17, 59526, {1, 3, 3, 9, 9, 11, 107, 15, 189, 27, 289, 3111, 851, 3401, 31981, 7181, 47533}},
-{12726, 17, 59537, {1, 1, 5, 15, 31, 57, 37, 77, 205, 707, 1505, 1343, 629, 13335, 6719, 35405, 38905}},
-{12727, 17, 59543, {1, 3, 7, 7, 21, 63, 35, 125, 507, 285, 621, 2257, 3009, 13703, 9761, 54927, 16925}},
-{12728, 17, 59560, {1, 1, 1, 11, 11, 53, 37, 17, 167, 663, 1349, 1395, 7721, 9329, 2161, 37093, 52425}},
-{12729, 17, 59563, {1, 1, 7, 9, 1, 15, 113, 53, 87, 133, 131, 847, 609, 14737, 1639, 15511, 46987}},
-{12730, 17, 59566, {1, 1, 7, 7, 25, 21, 125, 149, 201, 791, 1323, 2817, 1141, 289, 14349, 64461, 76575}},
-{12731, 17, 59577, {1, 3, 3, 7, 15, 1, 123, 227, 83, 967, 2039, 3205, 715, 10787, 11235, 50375, 66911}},
-{12732, 17, 59580, {1, 3, 3, 11, 9, 45, 41, 57, 327, 903, 1705, 3947, 3173, 1035, 25529, 15217, 80795}},
-{12733, 17, 59586, {1, 3, 1, 13, 15, 63, 69, 57, 479, 277, 1641, 3465, 2629, 9901, 5781, 55101, 33049}},
-{12734, 17, 59597, {1, 1, 3, 3, 31, 25, 57, 189, 491, 335, 373, 3069, 1623, 10781, 6559, 27057, 111491}},
-{12735, 17, 59612, {1, 3, 3, 15, 19, 57, 67, 225, 343, 93, 315, 1011, 4437, 10371, 27927, 51269, 65653}},
-{12736, 17, 59615, {1, 3, 5, 5, 21, 43, 105, 153, 65, 167, 369, 3167, 785, 7509, 3753, 9035, 29039}},
-{12737, 17, 59622, {1, 1, 7, 3, 17, 9, 113, 21, 175, 967, 13, 2701, 5667, 9761, 20267, 33497, 88819}},
-{12738, 17, 59631, {1, 1, 1, 7, 9, 61, 121, 205, 283, 259, 2027, 2361, 3995, 6787, 26867, 61681, 96149}},
-{12739, 17, 59657, {1, 3, 3, 13, 31, 37, 125, 151, 317, 947, 423, 2907, 6905, 13247, 27997, 4755, 73173}},
-{12740, 17, 59660, {1, 1, 7, 13, 1, 63, 85, 75, 33, 483, 85, 1583, 4783, 14003, 31147, 12643, 99447}},
-{12741, 17, 59665, {1, 1, 1, 7, 31, 5, 93, 179, 213, 857, 3, 1015, 1481, 2413, 28759, 13941, 24851}},
-{12742, 17, 59671, {1, 1, 5, 5, 5, 35, 73, 57, 469, 885, 1951, 3599, 5555, 7259, 22599, 7627, 109227}},
-{12743, 17, 59675, {1, 1, 5, 13, 1, 1, 69, 107, 473, 793, 1851, 887, 2241, 7851, 21821, 25431, 118565}},
-{12744, 17, 59688, {1, 1, 1, 3, 15, 51, 57, 175, 91, 113, 1671, 925, 2187, 1097, 28793, 45819, 41855}},
-{12745, 17, 59706, {1, 1, 3, 3, 15, 51, 99, 177, 379, 713, 1273, 3245, 5515, 14657, 28981, 1197, 29283}},
-{12746, 17, 59708, {1, 3, 3, 15, 13, 27, 29, 7, 17, 373, 779, 1589, 3077, 13673, 31029, 43765, 74339}},
-{12747, 17, 59713, {1, 1, 3, 1, 25, 17, 15, 223, 219, 569, 155, 1307, 7143, 7975, 22581, 53223, 44271}},
-{12748, 17, 59714, {1, 1, 1, 7, 11, 23, 67, 177, 189, 267, 1799, 2453, 2367, 4193, 1827, 10191, 12265}},
-{12749, 17, 59720, {1, 3, 3, 11, 3, 29, 121, 231, 211, 191, 1803, 1171, 6801, 4007, 14111, 42951, 8311}},
-{12750, 17, 59737, {1, 3, 3, 11, 9, 23, 11, 231, 349, 47, 1645, 345, 3681, 12227, 29955, 32131, 391}},
-{12751, 17, 59743, {1, 1, 3, 11, 27, 17, 17, 49, 463, 173, 1993, 2339, 3763, 1931, 29969, 55579, 114805}},
-{12752, 17, 59744, {1, 3, 5, 15, 5, 21, 105, 69, 173, 771, 815, 3807, 577, 12589, 32193, 37601, 23961}},
-{12753, 17, 59749, {1, 1, 3, 9, 21, 63, 57, 213, 327, 765, 333, 2065, 719, 6159, 15769, 49335, 2289}},
-{12754, 17, 59756, {1, 3, 3, 1, 27, 51, 13, 87, 465, 729, 507, 2811, 6721, 14279, 31733, 56165, 78169}},
-{12755, 17, 59783, {1, 1, 1, 9, 25, 1, 47, 37, 407, 623, 1409, 3703, 4491, 3037, 8129, 13547, 50517}},
-{12756, 17, 59784, {1, 3, 5, 13, 5, 51, 127, 225, 215, 377, 1013, 2387, 4237, 1317, 5245, 17535, 100707}},
-{12757, 17, 59787, {1, 3, 5, 13, 31, 25, 123, 243, 317, 505, 483, 1743, 3097, 4139, 4525, 63143, 47665}},
-{12758, 17, 59795, {1, 3, 3, 13, 27, 19, 21, 187, 211, 471, 1931, 2877, 3635, 9233, 12385, 15741, 50843}},
-{12759, 17, 59804, {1, 1, 3, 13, 23, 33, 71, 45, 371, 621, 1057, 1605, 6329, 3763, 8613, 2965, 8141}},
-{12760, 17, 59811, {1, 1, 5, 7, 7, 17, 33, 209, 293, 35, 1665, 3721, 6245, 14567, 15349, 16195, 59757}},
-{12761, 17, 59814, {1, 1, 7, 7, 31, 19, 47, 83, 277, 323, 1225, 969, 2193, 10175, 27657, 50265, 9817}},
-{12762, 17, 59823, {1, 1, 5, 7, 15, 21, 103, 95, 189, 737, 309, 357, 5953, 9701, 15757, 20753, 88647}},
-{12763, 17, 59838, {1, 1, 5, 13, 5, 13, 61, 235, 333, 889, 1559, 1653, 1871, 10631, 18067, 47037, 9507}},
-{12764, 17, 59840, {1, 3, 7, 1, 31, 61, 69, 159, 41, 107, 807, 1517, 3551, 3435, 6151, 50025, 126949}},
-{12765, 17, 59846, {1, 1, 7, 15, 7, 41, 55, 103, 9, 105, 1397, 3955, 7723, 3389, 32435, 36005, 73733}},
-{12766, 17, 59849, {1, 1, 1, 13, 15, 59, 43, 151, 321, 215, 411, 3103, 7455, 14041, 1673, 56425, 59085}},
-{12767, 17, 59855, {1, 1, 1, 1, 5, 39, 81, 183, 509, 455, 753, 3743, 227, 7807, 23747, 42289, 122765}},
-{12768, 17, 59860, {1, 1, 7, 3, 9, 29, 89, 131, 141, 851, 1221, 67, 3117, 1329, 13151, 36827, 34313}},
-{12769, 17, 59867, {1, 3, 1, 5, 9, 29, 11, 189, 389, 79, 1903, 835, 6043, 8953, 18985, 8305, 51939}},
-{12770, 17, 59869, {1, 3, 5, 3, 9, 49, 47, 43, 193, 917, 795, 2719, 5709, 9993, 30637, 26841, 93113}},
-{12771, 17, 59885, {1, 3, 7, 5, 13, 15, 85, 169, 315, 963, 617, 1191, 6739, 11535, 3423, 6695, 2047}},
-{12772, 17, 59888, {1, 3, 1, 3, 5, 49, 41, 255, 131, 255, 825, 1485, 7005, 10107, 3913, 4731, 33199}},
-{12773, 17, 59893, {1, 3, 1, 9, 27, 63, 109, 29, 183, 381, 591, 617, 1187, 4381, 30543, 9933, 109785}},
-{12774, 17, 59904, {1, 3, 7, 7, 13, 29, 125, 105, 353, 677, 623, 1553, 5435, 10853, 16663, 42277, 64333}},
-{12775, 17, 59919, {1, 3, 3, 11, 3, 47, 49, 41, 249, 497, 963, 237, 625, 11303, 6871, 60441, 39559}},
-{12776, 17, 59922, {1, 3, 3, 1, 1, 27, 107, 253, 59, 445, 1761, 2865, 7117, 2363, 4007, 46047, 10811}},
-{12777, 17, 59927, {1, 3, 5, 5, 25, 13, 17, 107, 321, 691, 351, 577, 5001, 9437, 12451, 44997, 42727}},
-{12778, 17, 59937, {1, 3, 1, 9, 1, 31, 87, 117, 111, 379, 1989, 1155, 4777, 8563, 14585, 33375, 66985}},
-{12779, 17, 59940, {1, 3, 5, 5, 9, 51, 79, 135, 89, 929, 277, 763, 5569, 15545, 28393, 56921, 102093}},
-{12780, 17, 59944, {1, 1, 3, 7, 7, 55, 15, 37, 3, 439, 577, 2051, 101, 13655, 11959, 38127, 6639}},
-{12781, 17, 59947, {1, 1, 3, 9, 21, 11, 27, 221, 465, 565, 1313, 1405, 2421, 10543, 18369, 33751, 87785}},
-{12782, 17, 59949, {1, 3, 5, 11, 21, 39, 105, 231, 469, 711, 997, 427, 5797, 3249, 15141, 29413, 66509}},
-{12783, 17, 59961, {1, 3, 7, 5, 25, 31, 111, 37, 229, 773, 193, 553, 673, 4693, 24441, 8713, 121203}},
-{12784, 17, 59975, {1, 3, 1, 9, 23, 27, 103, 7, 183, 549, 1433, 2831, 3383, 13229, 10005, 14135, 15967}},
-{12785, 17, 59981, {1, 3, 3, 11, 11, 59, 11, 251, 373, 399, 255, 1177, 5493, 13559, 29037, 23405, 79495}},
-{12786, 17, 59994, {1, 3, 1, 11, 25, 45, 69, 115, 153, 259, 527, 9, 5807, 6015, 3765, 61621, 8645}},
-{12787, 17, 59999, {1, 3, 3, 9, 19, 5, 113, 191, 345, 655, 429, 3975, 4297, 5723, 5345, 64457, 79031}},
-{12788, 17, 60018, {1, 3, 7, 7, 15, 59, 5, 87, 289, 1005, 931, 2403, 485, 16043, 15623, 39253, 61377}},
-{12789, 17, 60023, {1, 3, 3, 9, 17, 53, 31, 9, 217, 711, 1007, 1375, 2733, 13735, 19825, 59741, 83827}},
-{12790, 17, 60024, {1, 1, 3, 15, 11, 11, 41, 195, 79, 1013, 1353, 1961, 7365, 7533, 13315, 8441, 90705}},
-{12791, 17, 60039, {1, 1, 5, 7, 23, 17, 93, 165, 371, 495, 865, 2753, 15, 10729, 16553, 6039, 96721}},
-{12792, 17, 60043, {1, 3, 3, 3, 25, 25, 67, 119, 485, 63, 75, 2365, 4711, 16129, 5589, 50621, 1203}},
-{12793, 17, 60048, {1, 1, 7, 1, 27, 57, 49, 79, 479, 79, 683, 753, 345, 2007, 18983, 42729, 56369}},
-{12794, 17, 60054, {1, 1, 7, 7, 1, 23, 9, 155, 425, 735, 1625, 2271, 7875, 11219, 12147, 52351, 55845}},
-{12795, 17, 60073, {1, 1, 1, 9, 13, 11, 67, 139, 259, 59, 1593, 1207, 237, 11683, 24719, 27689, 115617}},
-{12796, 17, 60079, {1, 1, 5, 7, 7, 15, 9, 171, 35, 131, 133, 3939, 1401, 6347, 4051, 64235, 68581}},
-{12797, 17, 60082, {1, 3, 3, 1, 27, 21, 29, 119, 201, 527, 763, 203, 1139, 3951, 3341, 17023, 13493}},
-{12798, 17, 60102, {1, 1, 1, 15, 27, 31, 97, 203, 255, 573, 781, 4095, 3381, 363, 32733, 34517, 77973}},
-{12799, 17, 60108, {1, 1, 3, 9, 29, 9, 115, 207, 267, 513, 1071, 3943, 5045, 10071, 6627, 18043, 44289}},
-{12800, 17, 60111, {1, 1, 7, 7, 29, 25, 51, 31, 305, 239, 197, 3825, 2363, 4903, 16237, 37571, 66545}},
-{12801, 17, 60120, {1, 1, 5, 11, 29, 11, 63, 145, 185, 359, 249, 1179, 105, 1745, 28819, 40513, 74525}},
-{12802, 17, 60149, {1, 1, 7, 1, 15, 35, 39, 5, 139, 119, 2047, 3369, 2857, 11037, 30523, 24813, 89209}},
-{12803, 17, 60153, {1, 1, 5, 11, 9, 41, 97, 15, 357, 95, 361, 3, 3227, 8445, 16541, 30661, 84215}},
-{12804, 17, 60161, {1, 1, 7, 5, 11, 55, 77, 19, 331, 621, 893, 577, 1025, 1561, 32331, 59469, 67065}},
-{12805, 17, 60168, {1, 3, 7, 7, 17, 53, 55, 65, 295, 391, 445, 33, 5361, 669, 6447, 3833, 129463}},
-{12806, 17, 60176, {1, 3, 7, 5, 21, 5, 83, 207, 485, 597, 1429, 581, 6831, 2885, 24669, 35211, 69549}},
-{12807, 17, 60182, {1, 3, 3, 1, 3, 33, 69, 199, 427, 893, 1823, 1291, 4533, 11779, 18515, 17597, 79159}},
-{12808, 17, 60185, {1, 3, 1, 1, 17, 41, 91, 21, 509, 875, 777, 639, 4009, 12103, 12947, 58395, 36625}},
-{12809, 17, 60204, {1, 1, 7, 15, 13, 11, 19, 243, 365, 661, 1193, 279, 6055, 13921, 5811, 14337, 105375}},
-{12810, 17, 60212, {1, 3, 7, 3, 3, 51, 101, 175, 83, 921, 523, 3909, 8003, 1295, 4153, 4757, 107881}},
-{12811, 17, 60215, {1, 1, 1, 3, 19, 15, 39, 125, 401, 399, 381, 1123, 2339, 12231, 13387, 50829, 79263}},
-{12812, 17, 60219, {1, 3, 1, 1, 15, 13, 55, 181, 53, 671, 1929, 1003, 521, 15279, 1837, 11877, 79241}},
-{12813, 17, 60222, {1, 3, 3, 9, 23, 45, 21, 37, 1, 701, 1253, 2595, 6261, 4139, 24443, 6655, 109755}},
-{12814, 17, 60229, {1, 3, 7, 1, 1, 13, 57, 41, 95, 985, 1613, 3487, 7509, 213, 32139, 27869, 123589}},
-{12815, 17, 60234, {1, 3, 7, 11, 15, 27, 27, 97, 167, 755, 1331, 3961, 3067, 13827, 8983, 8755, 77847}},
-{12816, 17, 60241, {1, 1, 5, 13, 5, 59, 51, 193, 339, 837, 137, 3807, 2617, 14449, 11035, 16827, 24531}},
-{12817, 17, 60248, {1, 1, 7, 15, 17, 37, 67, 99, 261, 743, 275, 33, 8107, 4959, 9683, 19757, 36471}},
-{12818, 17, 60277, {1, 3, 5, 5, 29, 7, 107, 95, 235, 761, 1205, 3125, 4791, 4645, 25623, 6463, 121887}},
-{12819, 17, 60282, {1, 3, 1, 1, 19, 19, 73, 189, 243, 669, 489, 1927, 1651, 11391, 30699, 64719, 60359}},
-{12820, 17, 60287, {1, 3, 7, 3, 29, 47, 7, 21, 299, 739, 1605, 749, 5755, 11579, 793, 36845, 14695}},
-{12821, 17, 60303, {1, 1, 5, 15, 17, 53, 107, 49, 103, 505, 1191, 2881, 7435, 7515, 24237, 5397, 47003}},
-{12822, 17, 60306, {1, 1, 7, 15, 25, 45, 121, 157, 313, 709, 1519, 2195, 5487, 1789, 32401, 4197, 9329}},
-{12823, 17, 60327, {1, 3, 3, 11, 21, 17, 77, 153, 275, 765, 1943, 3395, 5807, 12809, 29891, 42579, 75565}},
-{12824, 17, 60333, {1, 3, 5, 11, 11, 3, 63, 9, 223, 441, 1047, 441, 867, 3399, 15813, 13, 25293}},
-{12825, 17, 60334, {1, 1, 7, 1, 17, 25, 1, 7, 211, 117, 1417, 1057, 3369, 13211, 11437, 20877, 114867}},
-{12826, 17, 60336, {1, 1, 1, 15, 5, 41, 89, 165, 343, 447, 55, 1013, 8179, 12295, 18615, 23885, 46149}},
-{12827, 17, 60345, {1, 1, 5, 1, 15, 37, 109, 141, 323, 151, 1669, 1365, 3047, 13145, 30355, 12377, 102467}},
-{12828, 17, 60359, {1, 1, 3, 15, 15, 49, 83, 127, 285, 715, 981, 1153, 3019, 11071, 24229, 63807, 16315}},
-{12829, 17, 60368, {1, 1, 3, 1, 23, 35, 21, 179, 83, 929, 1033, 643, 3591, 10363, 7739, 259, 106879}},
-{12830, 17, 60380, {1, 1, 5, 7, 19, 9, 63, 241, 387, 851, 1709, 1161, 7469, 2093, 6169, 6085, 29851}},
-{12831, 17, 60389, {1, 3, 7, 5, 17, 59, 99, 87, 189, 853, 193, 1191, 5683, 15865, 27791, 55575, 13479}},
-{12832, 17, 60390, {1, 3, 3, 3, 25, 51, 81, 129, 365, 319, 179, 2863, 511, 14471, 3689, 59505, 80105}},
-{12833, 17, 60394, {1, 1, 1, 15, 5, 33, 69, 35, 429, 715, 1781, 783, 1089, 8969, 26987, 23519, 34227}},
-{12834, 17, 60407, {1, 3, 5, 9, 1, 51, 9, 121, 325, 945, 2025, 1985, 7337, 10837, 21299, 20591, 76905}},
-{12835, 17, 60414, {1, 3, 7, 3, 15, 51, 19, 109, 297, 491, 15, 1905, 1479, 1997, 18129, 43861, 84925}},
-{12836, 17, 60419, {1, 1, 3, 5, 7, 21, 1, 137, 207, 943, 1171, 2019, 6687, 10683, 20937, 34033, 43907}},
-{12837, 17, 60426, {1, 1, 1, 11, 25, 21, 47, 227, 247, 933, 471, 955, 4299, 5605, 18469, 62357, 98273}},
-{12838, 17, 60428, {1, 1, 5, 13, 21, 39, 41, 23, 493, 311, 1401, 537, 2919, 11519, 12597, 58321, 41401}},
-{12839, 17, 60431, {1, 1, 7, 5, 31, 55, 93, 151, 219, 765, 1247, 2775, 7167, 13413, 17071, 57969, 114069}},
-{12840, 17, 60440, {1, 3, 1, 15, 31, 41, 85, 161, 379, 337, 1639, 933, 3511, 925, 3523, 52379, 18421}},
-{12841, 17, 60450, {1, 3, 3, 11, 17, 17, 71, 11, 291, 305, 1295, 1175, 1803, 6247, 26523, 46467, 126999}},
-{12842, 17, 60469, {1, 1, 1, 13, 9, 43, 113, 7, 1, 443, 719, 3045, 2527, 5233, 13969, 50463, 115629}},
-{12843, 17, 60473, {1, 1, 1, 13, 9, 31, 87, 119, 351, 53, 985, 2017, 1187, 10429, 13719, 41383, 12749}},
-{12844, 17, 60474, {1, 1, 1, 15, 23, 17, 5, 215, 383, 299, 305, 3577, 7707, 6927, 28591, 44287, 65697}},
-{12845, 17, 60484, {1, 1, 5, 7, 23, 61, 89, 235, 97, 463, 237, 2117, 5503, 13693, 28231, 7745, 73631}},
-{12846, 17, 60496, {1, 3, 7, 3, 17, 43, 73, 245, 145, 267, 855, 187, 6167, 3999, 9935, 14347, 57727}},
-{12847, 17, 60502, {1, 1, 7, 3, 25, 47, 11, 221, 425, 527, 1341, 3973, 4635, 16321, 30021, 48547, 109409}},
-{12848, 17, 60508, {1, 3, 1, 13, 5, 11, 41, 191, 121, 219, 1315, 583, 2997, 5883, 31689, 64835, 35351}},
-{12849, 17, 60511, {1, 1, 3, 3, 15, 47, 49, 115, 107, 757, 329, 1653, 4633, 14605, 1579, 62413, 88685}},
-{12850, 17, 60522, {1, 1, 1, 5, 19, 47, 63, 131, 427, 335, 269, 3581, 7613, 15685, 16957, 30487, 94965}},
-{12851, 17, 60529, {1, 1, 3, 15, 31, 11, 77, 115, 467, 249, 247, 651, 3769, 3701, 21627, 36219, 77309}},
-{12852, 17, 60530, {1, 3, 1, 5, 5, 29, 45, 21, 37, 733, 1773, 2467, 2747, 9391, 5449, 23285, 20089}},
-{12853, 17, 60536, {1, 3, 5, 13, 29, 31, 51, 199, 77, 711, 1313, 3303, 2675, 177, 7915, 37129, 123641}},
-{12854, 17, 60551, {1, 3, 7, 15, 17, 17, 99, 43, 9, 699, 491, 669, 1313, 1377, 30015, 59261, 97321}},
-{12855, 17, 60557, {1, 3, 1, 13, 9, 13, 21, 199, 249, 775, 399, 897, 2205, 15357, 17281, 3193, 255}},
-{12856, 17, 60566, {1, 3, 1, 13, 7, 23, 7, 181, 65, 253, 199, 333, 6507, 4409, 13319, 30165, 95191}},
-{12857, 17, 60576, {1, 3, 3, 1, 31, 9, 31, 71, 301, 867, 1655, 2065, 597, 15247, 3019, 31763, 91889}},
-{12858, 17, 60579, {1, 3, 5, 5, 3, 35, 113, 133, 39, 1013, 991, 3521, 5805, 87, 32393, 28619, 34325}},
-{12859, 17, 60585, {1, 3, 1, 9, 15, 27, 45, 85, 61, 99, 1085, 3251, 7085, 4137, 27443, 42581, 94031}},
-{12860, 17, 60588, {1, 1, 5, 7, 11, 49, 97, 129, 339, 259, 821, 165, 833, 11383, 21629, 17473, 2947}},
-{12861, 17, 60600, {1, 3, 3, 3, 11, 7, 27, 231, 169, 847, 1767, 1823, 3855, 14277, 12457, 55825, 14377}},
-{12862, 17, 60613, {1, 1, 7, 3, 27, 5, 47, 193, 207, 747, 271, 3155, 1097, 2229, 4919, 22327, 12659}},
-{12863, 17, 60628, {1, 1, 5, 3, 27, 29, 105, 199, 31, 73, 1741, 2173, 4577, 3917, 31513, 45983, 118015}},
-{12864, 17, 60631, {1, 1, 3, 1, 19, 5, 23, 249, 35, 891, 1105, 1907, 5453, 1877, 1965, 3169, 107091}},
-{12865, 17, 60648, {1, 1, 7, 9, 11, 47, 57, 171, 255, 661, 1925, 2223, 525, 4775, 12327, 8067, 47083}},
-{12866, 17, 60651, {1, 3, 3, 11, 29, 43, 37, 33, 459, 117, 7, 1739, 3585, 7429, 2217, 9533, 95299}},
-{12867, 17, 60653, {1, 1, 5, 11, 23, 3, 33, 13, 45, 201, 467, 597, 4891, 2673, 32407, 56935, 121991}},
-{12868, 17, 60671, {1, 1, 7, 5, 29, 63, 7, 59, 417, 547, 17, 3701, 5775, 1079, 26527, 47187, 14827}},
-{12869, 17, 60673, {1, 1, 5, 3, 27, 11, 85, 129, 377, 497, 1659, 1965, 581, 15075, 31265, 195, 62307}},
-{12870, 17, 60691, {1, 1, 3, 9, 3, 57, 33, 57, 279, 955, 741, 955, 6501, 8069, 27305, 15363, 34715}},
-{12871, 17, 60697, {1, 3, 7, 13, 29, 23, 25, 171, 201, 529, 661, 4089, 5755, 12459, 31269, 9763, 53217}},
-{12872, 17, 60700, {1, 3, 7, 1, 3, 19, 27, 201, 261, 421, 1487, 2907, 547, 15791, 7661, 42871, 116343}},
-{12873, 17, 60714, {1, 3, 7, 9, 5, 59, 51, 91, 7, 399, 2001, 661, 6577, 7473, 5439, 29073, 3391}},
-{12874, 17, 60724, {1, 1, 7, 1, 23, 39, 119, 105, 113, 913, 1097, 2547, 8143, 11409, 23197, 59527, 55677}},
-{12875, 17, 60728, {1, 3, 3, 15, 31, 35, 103, 207, 247, 801, 1821, 1995, 4437, 12891, 659, 15687, 53}},
-{12876, 17, 60733, {1, 3, 3, 5, 13, 5, 45, 187, 231, 661, 1553, 2909, 3715, 4499, 14773, 5957, 24171}},
-{12877, 17, 60736, {1, 1, 1, 11, 3, 53, 93, 29, 379, 713, 299, 445, 2815, 9825, 30941, 22413, 91563}},
-{12878, 17, 60745, {1, 3, 1, 1, 27, 31, 111, 83, 349, 895, 1007, 2649, 7139, 5863, 27739, 53099, 6837}},
-{12879, 17, 60746, {1, 3, 1, 5, 23, 57, 121, 229, 487, 405, 2001, 2761, 3011, 2219, 10711, 31139, 83809}},
-{12880, 17, 60753, {1, 3, 7, 5, 13, 51, 37, 181, 359, 909, 2001, 793, 1143, 9219, 5111, 23021, 126081}},
-{12881, 17, 60754, {1, 3, 1, 13, 27, 27, 99, 25, 189, 129, 1831, 1005, 8119, 2557, 26985, 63447, 89693}},
-{12882, 17, 60782, {1, 1, 7, 5, 1, 21, 79, 33, 99, 7, 433, 1343, 3121, 3705, 477, 41191, 13749}},
-{12883, 17, 60784, {1, 1, 5, 5, 29, 53, 75, 243, 35, 461, 1399, 129, 177, 6533, 22209, 23503, 43819}},
-{12884, 17, 60790, {1, 3, 7, 7, 31, 37, 109, 9, 255, 263, 35, 3451, 7629, 9849, 10387, 3165, 120623}},
-{12885, 17, 60793, {1, 3, 5, 3, 27, 53, 93, 111, 239, 723, 293, 1481, 4427, 13623, 1989, 47705, 122069}},
-{12886, 17, 60805, {1, 3, 7, 7, 31, 37, 37, 213, 191, 627, 1821, 3621, 2875, 15759, 17525, 50969, 35311}},
-{12887, 17, 60830, {1, 3, 5, 5, 11, 41, 87, 233, 79, 251, 25, 1385, 3527, 7853, 5541, 36519, 42779}},
-{12888, 17, 60836, {1, 3, 1, 5, 9, 1, 117, 11, 61, 879, 553, 383, 6237, 15207, 3057, 28051, 59149}},
-{12889, 17, 60846, {1, 1, 1, 15, 15, 7, 37, 133, 81, 815, 893, 2281, 2459, 15325, 20107, 2289, 34535}},
-{12890, 17, 60851, {1, 1, 5, 11, 17, 3, 45, 159, 409, 643, 969, 1289, 4353, 10465, 16233, 55561, 111667}},
-{12891, 17, 60880, {1, 1, 5, 13, 23, 1, 79, 127, 485, 1013, 629, 791, 853, 9247, 26333, 1123, 17313}},
-{12892, 17, 60896, {1, 1, 5, 11, 27, 17, 97, 157, 479, 421, 1739, 3257, 2419, 6673, 2759, 19399, 120305}},
-{12893, 17, 60905, {1, 3, 5, 1, 3, 43, 71, 55, 111, 949, 1957, 3777, 3409, 8229, 26585, 49221, 33639}},
-{12894, 17, 60923, {1, 3, 7, 9, 17, 45, 71, 71, 417, 1007, 213, 1069, 2693, 5065, 23489, 33363, 120459}},
-{12895, 17, 60925, {1, 1, 1, 1, 25, 47, 81, 251, 341, 101, 1941, 1133, 3205, 4141, 26561, 56095, 37193}},
-{12896, 17, 60932, {1, 1, 3, 7, 25, 45, 97, 95, 135, 871, 949, 3489, 7593, 10717, 26163, 12711, 76989}},
-{12897, 17, 60939, {1, 3, 1, 9, 3, 11, 35, 7, 471, 509, 1335, 385, 1297, 11201, 28553, 51609, 45351}},
-{12898, 17, 60942, {1, 1, 5, 11, 21, 23, 105, 31, 125, 5, 1721, 1503, 7807, 13093, 24873, 18467, 30183}},
-{12899, 17, 60953, {1, 3, 7, 15, 15, 57, 61, 213, 79, 655, 517, 1031, 6719, 4807, 12805, 2605, 35407}},
-{12900, 17, 60956, {1, 1, 3, 15, 21, 5, 93, 61, 103, 945, 935, 115, 1281, 7735, 20723, 37211, 50039}},
-{12901, 17, 60959, {1, 3, 3, 15, 19, 51, 79, 187, 127, 205, 121, 701, 6065, 15185, 29343, 58249, 25331}},
-{12902, 17, 60963, {1, 3, 3, 15, 17, 49, 23, 163, 201, 809, 1203, 687, 1777, 695, 18779, 31571, 118383}},
-{12903, 17, 60969, {1, 1, 1, 5, 25, 45, 121, 223, 233, 193, 1459, 1889, 5537, 4421, 13659, 4591, 112563}},
-{12904, 17, 60978, {1, 3, 5, 3, 31, 37, 109, 15, 381, 373, 993, 3633, 641, 4411, 32265, 46481, 49195}},
-{12905, 17, 60980, {1, 3, 3, 11, 19, 21, 39, 67, 447, 829, 1163, 55, 2153, 15045, 6643, 48235, 59261}},
-{12906, 17, 60987, {1, 3, 3, 1, 7, 63, 37, 71, 35, 601, 1719, 447, 8009, 7235, 13225, 44103, 82409}},
-{12907, 17, 61007, {1, 3, 3, 7, 13, 33, 69, 115, 207, 807, 109, 2989, 3727, 9017, 29095, 11377, 122401}},
-{12908, 17, 61012, {1, 1, 3, 15, 9, 9, 57, 197, 115, 73, 1277, 1727, 5275, 11897, 12157, 34763, 58273}},
-{12909, 17, 61015, {1, 1, 3, 15, 19, 19, 127, 105, 289, 663, 877, 1303, 4901, 8897, 4803, 36853, 93361}},
-{12910, 17, 61025, {1, 1, 3, 7, 23, 29, 121, 29, 439, 795, 1469, 523, 7767, 12061, 15613, 57343, 21291}},
-{12911, 17, 61026, {1, 1, 1, 9, 25, 29, 15, 165, 383, 233, 91, 2065, 2741, 7809, 5325, 48581, 65551}},
-{12912, 17, 61038, {1, 1, 5, 15, 29, 19, 103, 143, 283, 597, 1055, 3525, 6115, 11083, 22497, 42893, 86849}},
-{12913, 17, 61040, {1, 1, 1, 15, 13, 43, 75, 157, 267, 519, 1231, 929, 1585, 16137, 1045, 4353, 63473}},
-{12914, 17, 61052, {1, 1, 1, 9, 17, 25, 73, 227, 145, 921, 1845, 2057, 3099, 15523, 8993, 14135, 37811}},
-{12915, 17, 61061, {1, 3, 3, 15, 17, 57, 107, 215, 271, 841, 1543, 2803, 625, 15359, 13341, 36879, 83191}},
-{12916, 17, 61074, {1, 3, 5, 13, 3, 17, 127, 81, 193, 253, 71, 3205, 1157, 1313, 27341, 49657, 96539}},
-{12917, 17, 61083, {1, 3, 1, 5, 27, 43, 1, 111, 23, 963, 1853, 925, 7401, 13999, 29797, 47125, 59955}},
-{12918, 17, 61085, {1, 3, 3, 1, 31, 55, 107, 121, 37, 159, 61, 577, 5711, 6745, 20077, 42333, 37105}},
-{12919, 17, 61086, {1, 1, 5, 3, 31, 11, 1, 7, 295, 515, 203, 707, 2919, 9619, 8877, 45143, 101861}},
-{12920, 17, 61096, {1, 3, 7, 11, 5, 23, 71, 9, 99, 947, 1141, 1651, 1903, 13607, 15433, 55005, 127639}},
-{12921, 17, 61119, {1, 1, 7, 3, 13, 61, 25, 111, 239, 243, 1069, 3551, 3339, 743, 29921, 21313, 54953}},
-{12922, 17, 61124, {1, 1, 3, 3, 23, 7, 21, 47, 367, 871, 1647, 2183, 2615, 2257, 30447, 25761, 110221}},
-{12923, 17, 61127, {1, 3, 7, 15, 13, 51, 115, 19, 277, 463, 475, 3467, 7313, 2477, 10841, 13585, 61449}},
-{12924, 17, 61128, {1, 1, 7, 9, 1, 27, 111, 209, 391, 621, 1047, 549, 2013, 549, 24213, 6369, 68691}},
-{12925, 17, 61133, {1, 1, 1, 11, 19, 59, 11, 107, 79, 1013, 357, 1729, 889, 12823, 6537, 35717, 42761}},
-{12926, 17, 61134, {1, 1, 3, 15, 29, 41, 49, 177, 309, 293, 1035, 1481, 1395, 2009, 7917, 365, 28981}},
-{12927, 17, 61146, {1, 3, 7, 11, 31, 19, 51, 113, 479, 347, 353, 929, 1089, 3373, 2807, 55201, 23137}},
-{12928, 17, 61155, {1, 3, 1, 15, 7, 55, 79, 191, 267, 701, 1885, 1241, 7085, 9835, 24239, 7609, 13967}},
-{12929, 17, 61161, {1, 1, 3, 15, 25, 33, 69, 5, 93, 375, 435, 2401, 1591, 8173, 17293, 20281, 63809}},
-{12930, 17, 61162, {1, 3, 5, 3, 9, 49, 63, 47, 217, 773, 1241, 1131, 7521, 15607, 24341, 20353, 122801}},
-{12931, 17, 61169, {1, 3, 7, 15, 21, 1, 57, 159, 279, 987, 1641, 3883, 1659, 7875, 24857, 33273, 88933}},
-{12932, 17, 61179, {1, 1, 3, 11, 3, 23, 45, 31, 279, 643, 1285, 471, 137, 15871, 13927, 52361, 118901}},
-{12933, 17, 61182, {1, 3, 1, 15, 27, 51, 83, 19, 299, 213, 1001, 897, 2751, 13085, 20841, 24891, 113173}},
-{12934, 17, 61190, {1, 1, 7, 5, 5, 27, 77, 77, 165, 489, 359, 1607, 3903, 16241, 641, 25999, 29279}},
-{12935, 17, 61201, {1, 3, 3, 7, 15, 23, 103, 49, 259, 519, 641, 1577, 3713, 12181, 287, 29483, 58505}},
-{12936, 17, 61208, {1, 1, 7, 13, 11, 29, 125, 45, 45, 167, 261, 2735, 2421, 15457, 5965, 44005, 82141}},
-{12937, 17, 61238, {1, 1, 3, 9, 25, 21, 9, 3, 57, 1017, 1359, 79, 6789, 7805, 20683, 25695, 38893}},
-{12938, 17, 61241, {1, 1, 7, 1, 29, 53, 87, 171, 51, 5, 9, 3033, 787, 10611, 15913, 35703, 70459}},
-{12939, 17, 61247, {1, 1, 3, 5, 1, 33, 111, 139, 477, 33, 1287, 3615, 5235, 15491, 2915, 47821, 55257}},
-{12940, 17, 61259, {1, 1, 1, 13, 5, 23, 55, 225, 303, 587, 1595, 307, 3809, 8093, 13297, 63213, 104317}},
-{12941, 17, 61267, {1, 1, 3, 15, 31, 29, 13, 33, 267, 481, 1039, 3805, 2549, 861, 12483, 61829, 127725}},
-{12942, 17, 61269, {1, 3, 5, 11, 23, 17, 23, 117, 333, 167, 1965, 1387, 5453, 15545, 123, 12991, 36281}},
-{12943, 17, 61295, {1, 3, 5, 1, 3, 9, 25, 55, 497, 951, 1377, 993, 6089, 4801, 32719, 31579, 126663}},
-{12944, 17, 61304, {1, 3, 5, 11, 15, 37, 103, 51, 509, 585, 769, 425, 835, 14027, 30265, 55735, 36655}},
-{12945, 17, 61309, {1, 1, 1, 13, 9, 49, 105, 61, 493, 3, 1663, 815, 8105, 16361, 32477, 30437, 61519}},
-{12946, 17, 61310, {1, 3, 7, 11, 29, 23, 105, 87, 119, 399, 1405, 1515, 7017, 12729, 13769, 29741, 30921}},
-{12947, 17, 61313, {1, 3, 7, 13, 13, 7, 93, 227, 489, 843, 923, 3373, 759, 5105, 9059, 21079, 101335}},
-{12948, 17, 61320, {1, 1, 1, 1, 29, 53, 119, 227, 171, 363, 289, 827, 425, 12827, 25791, 21587, 109567}},
-{12949, 17, 61325, {1, 1, 5, 11, 29, 29, 53, 127, 441, 219, 1049, 275, 525, 5535, 20907, 9299, 76319}},
-{12950, 17, 61334, {1, 3, 7, 15, 3, 53, 109, 61, 275, 391, 1147, 2953, 1439, 4417, 679, 10949, 35101}},
-{12951, 17, 61337, {1, 1, 5, 13, 9, 1, 109, 137, 249, 835, 721, 129, 2883, 13043, 31827, 36741, 107167}},
-{12952, 17, 61386, {1, 1, 5, 9, 27, 17, 117, 121, 111, 433, 743, 1987, 6839, 8439, 2533, 62135, 54281}},
-{12953, 17, 61399, {1, 3, 5, 15, 11, 61, 117, 103, 409, 485, 1047, 469, 2245, 7193, 2541, 9399, 88127}},
-{12954, 17, 61422, {1, 3, 1, 9, 3, 49, 111, 201, 87, 181, 1243, 3261, 1827, 10385, 13045, 58331, 107729}},
-{12955, 17, 61429, {1, 3, 5, 15, 13, 29, 61, 223, 227, 733, 1757, 755, 4231, 13537, 1509, 54623, 120221}},
-{12956, 17, 61436, {1, 1, 1, 15, 13, 9, 7, 233, 391, 689, 355, 1203, 5811, 7759, 2647, 54949, 51891}},
-{12957, 17, 61439, {1, 1, 3, 1, 3, 27, 95, 51, 497, 315, 915, 1055, 2917, 167, 1849, 26591, 102729}},
-{12958, 17, 61466, {1, 3, 7, 13, 1, 51, 3, 113, 437, 449, 1889, 2887, 4735, 5693, 8191, 12847, 52651}},
-{12959, 17, 61477, {1, 1, 7, 13, 1, 45, 41, 221, 403, 185, 1653, 1809, 6405, 9193, 1381, 36677, 43255}},
-{12960, 17, 61478, {1, 1, 5, 1, 25, 51, 109, 245, 291, 809, 1381, 3235, 5933, 10185, 18663, 15589, 39539}},
-{12961, 17, 61490, {1, 3, 3, 1, 27, 29, 3, 227, 275, 705, 489, 681, 323, 7453, 26005, 13791, 115219}},
-{12962, 17, 61495, {1, 3, 5, 1, 3, 51, 101, 75, 157, 529, 45, 3105, 3617, 13081, 21665, 50065, 117823}},
-{12963, 17, 61504, {1, 3, 5, 15, 9, 43, 41, 169, 391, 455, 1375, 253, 1257, 14427, 16325, 11571, 26361}},
-{12964, 17, 61514, {1, 1, 5, 7, 5, 41, 81, 173, 275, 225, 301, 335, 5473, 1509, 20897, 21951, 103967}},
-{12965, 17, 61516, {1, 3, 5, 1, 13, 27, 107, 19, 221, 609, 823, 1193, 665, 4947, 11967, 57373, 21665}},
-{12966, 17, 61521, {1, 3, 7, 13, 7, 11, 109, 59, 193, 103, 943, 595, 5121, 6159, 2103, 52863, 57541}},
-{12967, 17, 61527, {1, 3, 5, 3, 5, 51, 85, 227, 465, 1013, 601, 1687, 7615, 5991, 8635, 64487, 69967}},
-{12968, 17, 61531, {1, 3, 1, 11, 29, 49, 79, 25, 447, 119, 569, 383, 5261, 6209, 21965, 40863, 96593}},
-{12969, 17, 61540, {1, 1, 3, 13, 9, 49, 59, 93, 369, 789, 1373, 425, 3565, 13357, 17783, 46435, 129653}},
-{12970, 17, 61550, {1, 3, 7, 5, 5, 39, 51, 15, 421, 531, 1855, 2105, 5335, 8509, 20841, 44997, 48235}},
-{12971, 17, 61557, {1, 3, 7, 3, 27, 47, 113, 1, 453, 565, 1843, 243, 7663, 10697, 7725, 24485, 49435}},
-{12972, 17, 61562, {1, 1, 1, 11, 25, 25, 47, 1, 475, 831, 1833, 391, 5173, 14873, 14263, 36061, 26781}},
-{12973, 17, 61577, {1, 1, 7, 15, 21, 13, 5, 169, 241, 235, 547, 1565, 2053, 6877, 12811, 22213, 106907}},
-{12974, 17, 61583, {1, 3, 7, 1, 21, 11, 101, 115, 243, 985, 1389, 2189, 563, 12453, 14951, 58889, 48079}},
-{12975, 17, 61597, {1, 1, 5, 7, 9, 37, 33, 241, 337, 453, 1955, 1731, 4445, 8887, 27715, 63975, 95891}},
-{12976, 17, 61602, {1, 1, 5, 1, 23, 21, 95, 237, 241, 991, 1159, 2417, 2279, 8941, 20987, 39773, 79327}},
-{12977, 17, 61604, {1, 3, 3, 1, 19, 39, 73, 253, 137, 1009, 1793, 4007, 2017, 7503, 16689, 29013, 41571}},
-{12978, 17, 61607, {1, 3, 7, 15, 3, 63, 77, 11, 293, 495, 339, 3525, 5747, 1807, 11705, 55807, 54163}},
-{12979, 17, 61622, {1, 3, 7, 3, 25, 41, 127, 23, 113, 807, 387, 3529, 2173, 11217, 21257, 61169, 47749}},
-{12980, 17, 61625, {1, 3, 3, 5, 27, 5, 43, 55, 207, 995, 811, 1473, 481, 4317, 2015, 49161, 94711}},
-{12981, 17, 61633, {1, 3, 1, 9, 21, 61, 41, 147, 425, 353, 1943, 2455, 379, 10729, 3045, 16013, 44527}},
-{12982, 17, 61640, {1, 3, 1, 5, 17, 43, 109, 231, 313, 277, 939, 3491, 5883, 2297, 4763, 33403, 62395}},
-{12983, 17, 61643, {1, 1, 3, 9, 1, 49, 37, 145, 383, 467, 621, 2873, 873, 6163, 16475, 49045, 115599}},
-{12984, 17, 61651, {1, 1, 1, 9, 5, 15, 125, 157, 459, 727, 807, 2769, 5531, 11531, 4277, 42301, 16969}},
-{12985, 17, 61658, {1, 1, 3, 1, 15, 23, 39, 121, 163, 537, 409, 1217, 8007, 5671, 19681, 25371, 69227}},
-{12986, 17, 61670, {1, 3, 7, 9, 23, 1, 93, 41, 267, 995, 1917, 3441, 6237, 7233, 30215, 31945, 33967}},
-{12987, 17, 61674, {1, 1, 1, 15, 7, 5, 123, 53, 359, 677, 1061, 1649, 651, 14079, 30211, 14827, 123175}},
-{12988, 17, 61676, {1, 3, 1, 5, 11, 19, 121, 135, 167, 293, 493, 949, 5459, 11785, 21445, 57161, 129737}},
-{12989, 17, 61679, {1, 1, 3, 13, 19, 39, 43, 55, 149, 549, 479, 925, 341, 1151, 12007, 23473, 10671}},
-{12990, 17, 61688, {1, 3, 5, 9, 7, 41, 37, 103, 381, 373, 1767, 3959, 3001, 7903, 24033, 55123, 93627}},
-{12991, 17, 61693, {1, 3, 3, 3, 31, 27, 93, 175, 393, 575, 703, 3715, 6043, 11763, 7613, 15907, 56821}},
-{12992, 17, 61701, {1, 3, 3, 13, 3, 13, 75, 85, 89, 851, 1171, 3075, 5265, 10293, 14745, 32153, 89877}},
-{12993, 17, 61711, {1, 1, 7, 11, 1, 25, 101, 149, 187, 197, 1485, 1555, 1599, 7413, 23275, 27093, 73483}},
-{12994, 17, 61714, {1, 3, 1, 1, 19, 15, 63, 111, 211, 197, 77, 1683, 3159, 235, 32601, 35715, 59537}},
-{12995, 17, 61723, {1, 3, 5, 11, 23, 61, 91, 135, 403, 669, 267, 2507, 2931, 7813, 5047, 40027, 111705}},
-{12996, 17, 61725, {1, 1, 5, 13, 7, 5, 65, 37, 87, 405, 335, 1095, 3717, 1717, 31551, 28181, 47407}},
-{12997, 17, 61726, {1, 1, 5, 13, 3, 43, 67, 99, 507, 861, 1063, 3003, 6095, 11079, 6919, 41597, 97709}},
-{12998, 17, 61729, {1, 1, 3, 1, 7, 23, 109, 161, 321, 499, 549, 363, 2061, 6519, 1531, 1969, 83845}},
-{12999, 17, 61741, {1, 3, 7, 5, 17, 39, 55, 59, 455, 433, 601, 365, 7987, 2207, 3463, 31755, 94203}},
-{13000, 17, 61761, {1, 3, 5, 5, 29, 61, 79, 101, 125, 1011, 867, 2935, 3269, 13601, 21935, 50355, 65883}},
-{13001, 17, 61779, {1, 1, 1, 5, 3, 41, 101, 107, 299, 125, 81, 2421, 2937, 787, 19479, 25803, 74473}},
-{13002, 17, 61781, {1, 3, 3, 1, 3, 15, 73, 13, 167, 387, 75, 601, 415, 6927, 32277, 16709, 12477}},
-{13003, 17, 61782, {1, 1, 5, 1, 19, 37, 53, 45, 139, 737, 159, 2299, 6219, 11613, 22873, 18303, 56875}},
-{13004, 17, 61797, {1, 1, 3, 9, 23, 15, 17, 37, 373, 445, 1369, 2997, 49, 13901, 13155, 37375, 29063}},
-{13005, 17, 61809, {1, 3, 3, 11, 17, 1, 45, 91, 445, 631, 1297, 1907, 3765, 13893, 29379, 17939, 36573}},
-{13006, 17, 61810, {1, 1, 7, 13, 11, 31, 101, 165, 413, 305, 361, 4019, 3183, 2321, 7819, 49275, 101041}},
-{13007, 17, 61816, {1, 1, 7, 1, 13, 43, 125, 165, 357, 293, 1343, 2219, 4189, 6095, 28509, 27763, 53871}},
-{13008, 17, 61822, {1, 3, 3, 11, 29, 33, 105, 71, 297, 637, 1493, 3797, 5525, 15093, 21647, 57647, 1467}},
-{13009, 17, 61849, {1, 1, 1, 13, 19, 7, 5, 141, 71, 221, 923, 1039, 4777, 9481, 1267, 55345, 116061}},
-{13010, 17, 61876, {1, 1, 7, 11, 19, 43, 57, 243, 21, 217, 1075, 569, 3735, 10477, 18595, 34133, 70391}},
-{13011, 17, 61893, {1, 3, 3, 1, 21, 61, 7, 135, 401, 101, 321, 2959, 7371, 3303, 23023, 28163, 19833}},
-{13012, 17, 61905, {1, 1, 3, 9, 31, 43, 27, 243, 297, 145, 663, 3951, 4283, 10421, 9355, 30381, 68317}},
-{13013, 17, 61908, {1, 3, 7, 13, 29, 53, 101, 253, 49, 129, 831, 513, 5567, 5063, 157, 6465, 90983}},
-{13014, 17, 61911, {1, 1, 5, 15, 27, 29, 3, 231, 503, 173, 913, 3971, 7685, 9679, 32243, 967, 73195}},
-{13015, 17, 61912, {1, 1, 1, 15, 19, 55, 127, 3, 405, 239, 1063, 3473, 7543, 4049, 14509, 22657, 5611}},
-{13016, 17, 61928, {1, 3, 7, 1, 21, 39, 61, 249, 421, 401, 1667, 1981, 5503, 9191, 24027, 35049, 12199}},
-{13017, 17, 61934, {1, 3, 5, 5, 27, 1, 99, 83, 287, 997, 721, 1345, 2197, 6335, 4245, 42575, 102635}},
-{13018, 17, 61957, {1, 3, 3, 1, 31, 7, 103, 107, 387, 273, 951, 2475, 1275, 15607, 2159, 55083, 86107}},
-{13019, 17, 61961, {1, 3, 3, 5, 21, 59, 69, 55, 121, 601, 5, 1871, 7161, 4583, 23867, 7933, 3125}},
-{13020, 17, 61969, {1, 1, 1, 15, 17, 41, 51, 45, 383, 579, 713, 275, 1395, 11665, 30521, 11683, 126493}},
-{13021, 17, 61979, {1, 1, 1, 15, 17, 47, 15, 139, 175, 283, 1377, 827, 5753, 8855, 26437, 59219, 105601}},
-{13022, 17, 61982, {1, 1, 7, 11, 13, 3, 27, 141, 137, 851, 767, 2575, 7685, 11719, 24401, 52547, 127299}},
-{13023, 17, 62003, {1, 3, 3, 9, 11, 41, 75, 69, 167, 897, 1213, 3723, 6773, 12141, 28033, 19695, 128545}},
-{13024, 17, 62006, {1, 1, 5, 13, 7, 61, 55, 131, 465, 169, 1669, 711, 5901, 10769, 11273, 23809, 63625}},
-{13025, 17, 62010, {1, 1, 5, 1, 27, 25, 35, 167, 83, 921, 251, 2571, 6723, 14767, 26715, 21699, 60779}},
-{13026, 17, 62015, {1, 3, 1, 9, 15, 5, 59, 241, 405, 323, 1917, 1161, 6079, 13443, 13079, 58617, 63381}},
-{13027, 17, 62020, {1, 3, 1, 5, 9, 5, 79, 123, 87, 395, 667, 2787, 3711, 3613, 1803, 17885, 78975}},
-{13028, 17, 62024, {1, 3, 3, 5, 17, 45, 61, 107, 485, 163, 33, 1491, 7131, 59, 27327, 8043, 14907}},
-{13029, 17, 62029, {1, 3, 1, 11, 27, 37, 5, 251, 115, 339, 1621, 2013, 3517, 2213, 10145, 47121, 84485}},
-{13030, 17, 62032, {1, 3, 3, 1, 9, 11, 71, 25, 363, 867, 1485, 3897, 3339, 7599, 20777, 52009, 127097}},
-{13031, 17, 62035, {1, 1, 3, 9, 25, 37, 29, 231, 183, 315, 399, 879, 6169, 6355, 3729, 9187, 19405}},
-{13032, 17, 62038, {1, 3, 5, 3, 31, 37, 127, 71, 171, 687, 1237, 151, 7391, 2395, 11979, 23381, 117879}},
-{13033, 17, 62047, {1, 1, 1, 13, 13, 43, 71, 235, 131, 79, 1321, 235, 2221, 1133, 13509, 12205, 44771}},
-{13034, 17, 62068, {1, 3, 7, 5, 29, 51, 125, 191, 153, 35, 1657, 2141, 3701, 7177, 31723, 15189, 55441}},
-{13035, 17, 62071, {1, 1, 5, 1, 5, 35, 13, 165, 461, 255, 1825, 1531, 6195, 7717, 973, 12367, 71747}},
-{13036, 17, 62082, {1, 3, 1, 9, 13, 57, 25, 83, 389, 405, 227, 1037, 3805, 15653, 25365, 47991, 54315}},
-{13037, 17, 62088, {1, 1, 1, 13, 17, 55, 113, 151, 145, 951, 1849, 2205, 6513, 7845, 7947, 59429, 44911}},
-{13038, 17, 62096, {1, 3, 5, 3, 25, 9, 99, 159, 183, 445, 153, 3053, 2537, 1787, 19029, 60047, 128203}},
-{13039, 17, 62108, {1, 1, 5, 5, 31, 37, 13, 11, 271, 491, 1141, 1827, 3751, 9471, 7579, 35969, 95245}},
-{13040, 17, 62124, {1, 3, 3, 15, 1, 43, 9, 109, 13, 991, 345, 1577, 947, 3197, 16747, 8127, 116937}},
-{13041, 17, 62142, {1, 3, 3, 15, 11, 17, 103, 89, 33, 741, 1855, 2879, 3899, 9535, 15119, 56165, 86055}},
-{13042, 17, 62147, {1, 3, 5, 1, 31, 41, 57, 205, 69, 163, 1383, 2087, 6483, 6281, 32079, 40825, 28709}},
-{13043, 17, 62153, {1, 1, 1, 13, 23, 57, 103, 247, 421, 773, 1733, 3249, 6681, 9675, 11669, 51673, 86189}},
-{13044, 17, 62159, {1, 1, 5, 15, 7, 37, 63, 123, 77, 941, 277, 1061, 803, 2135, 15745, 47413, 73843}},
-{13045, 17, 62161, {1, 1, 3, 5, 19, 15, 35, 59, 321, 527, 1669, 2929, 513, 4453, 20521, 19781, 115501}},
-{13046, 17, 62171, {1, 1, 7, 3, 23, 1, 99, 251, 129, 271, 1555, 1191, 2445, 11533, 11921, 19131, 80653}},
-{13047, 17, 62189, {1, 1, 7, 15, 15, 33, 79, 89, 113, 517, 1655, 43, 6255, 15415, 19559, 63309, 16857}},
-{13048, 17, 62207, {1, 3, 5, 1, 13, 61, 87, 159, 65, 875, 163, 663, 7651, 8775, 32505, 39313, 83331}},
-{13049, 17, 62227, {1, 1, 7, 15, 27, 19, 63, 117, 427, 233, 1243, 755, 3201, 5153, 31959, 64545, 69219}},
-{13050, 17, 62230, {1, 1, 5, 3, 3, 27, 15, 11, 427, 431, 107, 2433, 6923, 7503, 31347, 64849, 14541}},
-{13051, 17, 62234, {1, 1, 3, 11, 7, 23, 53, 253, 483, 63, 1749, 2989, 5219, 7361, 6423, 1503, 95431}},
-{13052, 17, 62236, {1, 1, 5, 9, 1, 19, 23, 25, 301, 665, 1457, 2423, 6623, 9771, 2755, 8963, 51037}},
-{13053, 17, 62239, {1, 3, 3, 7, 21, 1, 3, 131, 377, 897, 15, 437, 4075, 7669, 31529, 64123, 101249}},
-{13054, 17, 62257, {1, 3, 5, 3, 31, 41, 99, 27, 397, 393, 1895, 2249, 3925, 6393, 2839, 375, 56721}},
-{13055, 17, 62270, {1, 3, 7, 15, 1, 45, 65, 113, 85, 557, 857, 2281, 1395, 2055, 2405, 34541, 63719}},
-{13056, 17, 62278, {1, 3, 1, 15, 7, 43, 21, 29, 15, 229, 1287, 3005, 339, 5833, 21867, 21643, 37557}},
-{13057, 17, 62287, {1, 3, 7, 3, 3, 51, 67, 119, 423, 539, 1995, 4039, 2999, 2787, 29327, 62687, 11893}},
-{13058, 17, 62295, {1, 3, 7, 3, 25, 23, 85, 11, 105, 523, 889, 2983, 2031, 2049, 16119, 41925, 38345}},
-{13059, 17, 62301, {1, 3, 7, 3, 13, 63, 59, 65, 183, 695, 293, 3301, 7895, 13915, 25847, 22819, 92189}},
-{13060, 17, 62306, {1, 1, 3, 3, 7, 27, 101, 229, 435, 227, 1759, 1275, 5781, 6079, 25125, 64833, 69577}},
-{13061, 17, 62312, {1, 1, 3, 1, 29, 1, 61, 45, 193, 441, 687, 841, 4491, 10683, 13989, 60461, 78071}},
-{13062, 17, 62317, {1, 3, 1, 9, 5, 33, 99, 229, 181, 675, 1629, 1855, 4719, 9585, 8059, 26363, 31161}},
-{13063, 17, 62330, {1, 3, 1, 11, 11, 37, 79, 53, 163, 49, 1173, 1715, 8087, 6535, 14985, 24069, 118597}},
-{13064, 17, 62342, {1, 1, 7, 15, 9, 59, 123, 79, 237, 131, 1693, 2525, 6339, 9843, 24309, 24969, 37645}},
-{13065, 17, 62359, {1, 3, 3, 7, 19, 49, 85, 133, 415, 239, 555, 2581, 6523, 2733, 19665, 19989, 105585}},
-{13066, 17, 62365, {1, 3, 3, 7, 23, 37, 31, 121, 59, 7, 2031, 2893, 6429, 10305, 21221, 20105, 38879}},
-{13067, 17, 62366, {1, 3, 1, 13, 23, 21, 93, 93, 343, 641, 411, 971, 1777, 2135, 22895, 9055, 114457}},
-{13068, 17, 62370, {1, 3, 5, 3, 15, 33, 23, 7, 59, 413, 277, 3551, 7737, 2285, 7951, 5013, 94469}},
-{13069, 17, 62375, {1, 3, 1, 15, 25, 1, 109, 245, 153, 187, 1099, 1071, 145, 6735, 10327, 3921, 62123}},
-{13070, 17, 62376, {1, 1, 7, 11, 11, 53, 51, 123, 277, 281, 1763, 3161, 7639, 14515, 29725, 3919, 5525}},
-{13071, 17, 62387, {1, 3, 3, 15, 27, 47, 109, 121, 317, 221, 187, 617, 1331, 5401, 861, 62465, 9227}},
-{13072, 17, 62404, {1, 3, 3, 15, 27, 25, 101, 111, 469, 85, 1285, 1621, 5393, 1367, 17115, 35141, 126989}},
-{13073, 17, 62411, {1, 3, 5, 1, 15, 23, 25, 249, 69, 17, 1103, 2603, 59, 15637, 22051, 29243, 53113}},
-{13074, 17, 62435, {1, 3, 1, 9, 17, 49, 73, 13, 207, 963, 379, 3561, 6447, 7895, 18651, 8109, 3943}},
-{13075, 17, 62441, {1, 3, 5, 11, 7, 41, 55, 85, 481, 831, 593, 4093, 1151, 12353, 24231, 46091, 80967}},
-{13076, 17, 62442, {1, 3, 7, 7, 5, 39, 47, 187, 427, 1007, 813, 3617, 6063, 12981, 18573, 34061, 85741}},
-{13077, 17, 62452, {1, 3, 3, 11, 9, 17, 29, 141, 341, 485, 1075, 4067, 7247, 11295, 31803, 18347, 54985}},
-{13078, 17, 62459, {1, 1, 3, 7, 17, 25, 7, 29, 355, 35, 1753, 669, 4123, 4293, 22875, 36677, 61201}},
-{13079, 17, 62461, {1, 1, 5, 9, 13, 45, 29, 153, 169, 387, 1275, 3161, 4937, 5331, 16203, 43925, 129231}},
-{13080, 17, 62473, {1, 3, 3, 9, 19, 27, 109, 95, 499, 929, 1627, 3215, 6097, 15837, 5655, 29877, 122513}},
-{13081, 17, 62474, {1, 3, 7, 11, 1, 25, 15, 41, 65, 411, 289, 883, 5069, 8405, 11159, 57357, 114253}},
-{13082, 17, 62493, {1, 1, 3, 11, 31, 57, 39, 89, 77, 321, 1667, 871, 6429, 1005, 18905, 13877, 9305}},
-{13083, 17, 62510, {1, 1, 7, 7, 27, 57, 23, 37, 281, 625, 1871, 565, 5979, 13925, 22591, 2375, 8577}},
-{13084, 17, 62518, {1, 1, 1, 7, 31, 35, 91, 221, 495, 811, 1321, 2235, 4287, 3009, 5745, 35013, 93715}},
-{13085, 17, 62524, {1, 1, 7, 3, 11, 53, 17, 13, 319, 225, 117, 3365, 537, 5249, 14219, 23879, 4321}},
-{13086, 17, 62549, {1, 3, 5, 1, 31, 57, 35, 95, 257, 933, 471, 627, 6733, 8707, 25173, 44291, 105041}},
-{13087, 17, 62556, {1, 1, 3, 3, 31, 53, 69, 19, 277, 669, 497, 3957, 2781, 14107, 27741, 53519, 41057}},
-{13088, 17, 62565, {1, 1, 3, 15, 11, 21, 11, 25, 257, 665, 491, 2119, 3893, 14401, 29147, 3369, 116569}},
-{13089, 17, 62566, {1, 3, 1, 1, 13, 49, 31, 231, 217, 711, 1987, 1487, 7073, 473, 28781, 51283, 86049}},
-{13090, 17, 62580, {1, 1, 1, 5, 23, 31, 119, 115, 381, 179, 1725, 2323, 8013, 15191, 13255, 57813, 95437}},
-{13091, 17, 62584, {1, 1, 3, 15, 15, 37, 83, 223, 259, 605, 2013, 4089, 395, 2063, 11735, 51931, 74677}},
-{13092, 17, 62589, {1, 1, 7, 3, 1, 61, 107, 169, 213, 789, 425, 2309, 225, 1305, 20697, 26281, 60129}},
-{13093, 17, 62596, {1, 1, 5, 15, 27, 15, 69, 169, 289, 931, 1491, 3711, 6875, 7723, 21103, 31795, 53955}},
-{13094, 17, 62608, {1, 1, 1, 3, 3, 43, 49, 205, 247, 817, 2037, 2305, 7935, 255, 18835, 49423, 90727}},
-{13095, 17, 62636, {1, 3, 7, 9, 17, 3, 95, 239, 431, 665, 1271, 3559, 5703, 14607, 9723, 11807, 122937}},
-{13096, 17, 62642, {1, 3, 5, 13, 5, 15, 13, 111, 375, 895, 833, 813, 5451, 13841, 1321, 25273, 25443}},
-{13097, 17, 62651, {1, 1, 3, 1, 11, 49, 3, 97, 467, 631, 51, 3577, 1777, 15965, 6837, 38827, 68627}},
-{13098, 17, 62654, {1, 1, 7, 1, 3, 11, 73, 155, 77, 623, 811, 337, 6837, 10925, 2097, 28325, 97487}},
-{13099, 17, 62659, {1, 1, 1, 3, 29, 35, 9, 215, 415, 143, 1837, 3723, 73, 11305, 23187, 19995, 52987}},
-{13100, 17, 62666, {1, 1, 7, 1, 25, 39, 35, 67, 245, 295, 1143, 2043, 1049, 629, 14111, 62893, 86899}},
-{13101, 17, 62680, {1, 3, 7, 5, 3, 41, 123, 97, 241, 743, 259, 3163, 2289, 6363, 24033, 10789, 44117}},
-{13102, 17, 62692, {1, 3, 1, 7, 25, 33, 33, 17, 359, 567, 901, 3595, 179, 8671, 841, 24787, 4367}},
-{13103, 17, 62701, {1, 3, 1, 13, 5, 13, 57, 185, 321, 727, 789, 3081, 5345, 9721, 32029, 11663, 55695}},
-{13104, 17, 62702, {1, 1, 7, 7, 5, 51, 85, 255, 329, 263, 297, 1687, 6799, 10973, 8265, 19615, 115333}},
-{13105, 17, 62714, {1, 1, 1, 5, 29, 27, 55, 167, 465, 73, 661, 137, 7831, 2571, 15373, 64223, 27335}},
-{13106, 17, 62716, {1, 3, 7, 13, 5, 23, 77, 15, 345, 21, 1729, 3231, 967, 12573, 31415, 24249, 110525}},
-{13107, 17, 62733, {1, 1, 7, 9, 31, 37, 41, 119, 169, 891, 1845, 2139, 1747, 1147, 21983, 11617, 25963}},
-{13108, 17, 62762, {1, 3, 3, 7, 23, 5, 1, 11, 95, 795, 1371, 2631, 3241, 6935, 17353, 25013, 89765}},
-{13109, 17, 62769, {1, 3, 1, 7, 19, 3, 121, 19, 389, 117, 1905, 3135, 7601, 12541, 20855, 38613, 15005}},
-{13110, 17, 62770, {1, 3, 3, 5, 17, 43, 91, 99, 113, 545, 1955, 37, 3411, 15173, 24961, 28761, 15245}},
-{13111, 17, 62787, {1, 3, 3, 13, 25, 9, 83, 17, 17, 271, 1133, 3851, 4607, 11017, 14867, 20677, 42881}},
-{13112, 17, 62794, {1, 1, 5, 15, 5, 9, 99, 179, 263, 623, 441, 2577, 189, 11595, 21505, 27215, 54081}},
-{13113, 17, 62801, {1, 1, 7, 1, 1, 63, 123, 119, 245, 467, 169, 3075, 909, 3581, 14571, 33071, 6261}},
-{13114, 17, 62807, {1, 1, 1, 13, 9, 35, 47, 161, 47, 893, 57, 703, 3373, 4167, 26555, 51265, 1391}},
-{13115, 17, 62808, {1, 3, 1, 13, 9, 61, 9, 5, 47, 259, 579, 113, 355, 14539, 25757, 10119, 96869}},
-{13116, 17, 62813, {1, 1, 5, 11, 3, 5, 61, 231, 291, 21, 1711, 2981, 4727, 14287, 12149, 40275, 51809}},
-{13117, 17, 62817, {1, 3, 5, 3, 21, 5, 87, 251, 373, 679, 949, 1023, 5183, 14549, 4135, 54927, 20369}},
-{13118, 17, 62818, {1, 3, 3, 11, 7, 43, 127, 97, 469, 81, 1843, 3955, 125, 8607, 27185, 50761, 122753}},
-{13119, 17, 62832, {1, 3, 5, 5, 25, 61, 1, 55, 333, 949, 1005, 1051, 6291, 8343, 9627, 37739, 116911}},
-{13120, 17, 62841, {1, 3, 3, 13, 21, 9, 67, 225, 179, 837, 2009, 3171, 217, 5629, 23451, 63171, 53225}},
-{13121, 17, 62857, {1, 3, 7, 1, 23, 15, 91, 163, 351, 883, 579, 3923, 2641, 12735, 24955, 1131, 65119}},
-{13122, 17, 62860, {1, 1, 1, 11, 29, 5, 113, 217, 171, 535, 913, 2419, 3843, 12365, 8287, 27367, 57369}},
-{13123, 17, 62871, {1, 1, 5, 11, 9, 41, 57, 243, 123, 159, 1517, 2653, 4307, 4243, 2801, 43131, 18435}},
-{13124, 17, 62882, {1, 1, 7, 9, 23, 59, 83, 159, 57, 723, 1635, 7, 1463, 121, 541, 7657, 83917}},
-{13125, 17, 62888, {1, 3, 7, 7, 23, 27, 125, 103, 247, 1019, 1063, 3979, 8085, 6449, 12443, 63427, 106235}},
-{13126, 17, 62913, {1, 1, 7, 5, 9, 31, 23, 83, 503, 605, 1731, 3341, 7427, 14571, 5981, 39043, 42965}},
-{13127, 17, 62919, {1, 3, 5, 1, 17, 49, 109, 171, 301, 951, 1879, 1317, 457, 8085, 6803, 62521, 67871}},
-{13128, 17, 62920, {1, 1, 7, 11, 11, 27, 1, 71, 335, 137, 265, 1267, 6399, 14823, 925, 49895, 19731}},
-{13129, 17, 62925, {1, 3, 1, 13, 3, 35, 75, 253, 211, 483, 1495, 3695, 3033, 14643, 1861, 51269, 32655}},
-{13130, 17, 62933, {1, 3, 7, 1, 5, 17, 63, 1, 83, 435, 2007, 2023, 57, 8639, 27067, 4039, 1955}},
-{13131, 17, 62938, {1, 3, 5, 15, 27, 51, 59, 47, 77, 131, 507, 559, 645, 16067, 20989, 15565, 39925}},
-{13132, 17, 62940, {1, 3, 3, 5, 11, 15, 63, 121, 39, 1019, 1027, 2821, 3297, 13769, 18587, 14199, 82251}},
-{13133, 17, 62949, {1, 1, 5, 1, 31, 11, 89, 75, 147, 1007, 917, 3519, 5097, 5695, 15185, 14819, 38597}},
-{13134, 17, 62956, {1, 3, 3, 3, 15, 7, 127, 55, 83, 887, 1901, 75, 639, 713, 13631, 27447, 106707}},
-{13135, 17, 62971, {1, 3, 3, 15, 27, 25, 85, 163, 187, 959, 815, 1403, 6129, 6515, 31597, 28307, 30077}},
-{13136, 17, 62978, {1, 3, 1, 13, 5, 19, 117, 89, 11, 489, 845, 2899, 3695, 3279, 22355, 38759, 85849}},
-{13137, 17, 62990, {1, 3, 1, 7, 25, 59, 109, 185, 87, 591, 825, 1119, 7439, 5451, 17959, 51299, 76693}},
-{13138, 17, 62995, {1, 1, 7, 5, 25, 29, 115, 249, 185, 529, 593, 103, 1739, 4769, 25925, 3317, 102445}},
-{13139, 17, 62997, {1, 1, 3, 1, 3, 35, 19, 255, 279, 295, 1075, 2817, 3513, 7501, 15885, 21653, 113447}},
-{13140, 17, 63004, {1, 3, 1, 5, 27, 1, 21, 137, 303, 981, 631, 2339, 397, 13075, 28815, 50925, 44379}},
-{13141, 17, 63011, {1, 1, 7, 7, 31, 31, 59, 129, 105, 181, 1041, 2685, 1061, 1721, 30365, 6873, 30011}},
-{13142, 17, 63032, {1, 1, 3, 1, 19, 31, 125, 39, 9, 631, 1239, 1061, 6313, 9639, 5991, 27293, 84635}},
-{13143, 17, 63038, {1, 3, 3, 11, 17, 59, 17, 241, 195, 175, 1845, 251, 3323, 13399, 20493, 15241, 69303}},
-{13144, 17, 63067, {1, 1, 5, 3, 9, 19, 59, 25, 49, 359, 263, 4045, 1527, 6703, 555, 26413, 42757}},
-{13145, 17, 63069, {1, 1, 5, 9, 23, 5, 7, 223, 247, 407, 1079, 1069, 3417, 14795, 5015, 2965, 99059}},
-{13146, 17, 63076, {1, 3, 7, 5, 27, 47, 9, 37, 47, 181, 819, 2049, 2643, 9231, 8173, 33495, 91321}},
-{13147, 17, 63083, {1, 3, 5, 11, 5, 27, 5, 237, 349, 653, 1443, 137, 7969, 5961, 24749, 37523, 88921}},
-{13148, 17, 63088, {1, 3, 7, 13, 11, 51, 49, 71, 339, 195, 1239, 3479, 2771, 15217, 23729, 7839, 32633}},
-{13149, 17, 63094, {1, 1, 5, 5, 5, 13, 103, 185, 13, 273, 1793, 761, 5327, 8659, 32599, 38181, 121115}},
-{13150, 17, 63097, {1, 3, 7, 15, 17, 55, 69, 151, 231, 421, 1679, 3657, 8001, 12599, 13761, 13517, 130199}},
-{13151, 17, 63100, {1, 1, 5, 3, 5, 15, 15, 61, 489, 219, 925, 2329, 3415, 10779, 31297, 63805, 13375}},
-{13152, 17, 63104, {1, 1, 7, 9, 7, 11, 87, 45, 39, 885, 87, 1877, 8135, 1247, 25685, 23631, 65579}},
-{13153, 17, 63114, {1, 3, 3, 7, 1, 17, 31, 75, 455, 535, 509, 2151, 1737, 7579, 12727, 25139, 32659}},
-{13154, 17, 63116, {1, 3, 5, 7, 15, 27, 111, 145, 99, 767, 167, 3391, 2155, 7895, 3405, 47451, 65185}},
-{13155, 17, 63122, {1, 1, 1, 3, 23, 31, 15, 53, 59, 787, 431, 2691, 71, 2843, 13469, 54029, 2233}},
-{13156, 17, 63128, {1, 1, 5, 1, 5, 39, 57, 31, 75, 507, 811, 2747, 317, 13545, 7395, 65161, 87987}},
-{13157, 17, 63149, {1, 3, 5, 5, 13, 17, 11, 89, 371, 337, 913, 2775, 27, 4923, 24013, 62955, 65185}},
-{13158, 17, 63150, {1, 3, 3, 7, 9, 27, 91, 187, 17, 443, 807, 853, 6243, 12351, 8123, 4203, 61021}},
-{13159, 17, 63157, {1, 1, 1, 5, 9, 33, 101, 211, 205, 701, 1289, 1253, 653, 8591, 13009, 48525, 77051}},
-{13160, 17, 63167, {1, 3, 5, 11, 5, 19, 1, 67, 259, 355, 15, 2169, 6785, 2019, 8675, 1019, 85903}},
-{13161, 17, 63187, {1, 3, 7, 5, 27, 31, 103, 163, 369, 685, 659, 2009, 5819, 10437, 17311, 35083, 122125}},
-{13162, 17, 63200, {1, 3, 5, 7, 19, 13, 93, 113, 377, 359, 1697, 4063, 4379, 9321, 7335, 25491, 85939}},
-{13163, 17, 63220, {1, 3, 3, 5, 7, 25, 41, 225, 355, 257, 743, 2067, 7627, 14317, 7385, 25187, 63103}},
-{13164, 17, 63223, {1, 1, 7, 7, 17, 43, 75, 1, 95, 547, 1937, 2263, 1709, 5067, 22651, 55733, 44619}},
-{13165, 17, 63229, {1, 1, 7, 3, 5, 27, 45, 23, 107, 547, 1733, 1169, 6709, 861, 4439, 55381, 96447}},
-{13166, 17, 63235, {1, 1, 7, 11, 25, 23, 127, 159, 489, 945, 843, 3715, 5215, 2131, 9681, 35515, 108109}},
-{13167, 17, 63247, {1, 1, 3, 7, 5, 1, 67, 59, 83, 745, 1337, 855, 6087, 14319, 13405, 36261, 49091}},
-{13168, 17, 63252, {1, 3, 1, 1, 13, 27, 41, 155, 463, 709, 1111, 2017, 4701, 8663, 29703, 45311, 113347}},
-{13169, 17, 63255, {1, 1, 7, 5, 1, 11, 83, 101, 283, 505, 893, 705, 2331, 5127, 21793, 28095, 59055}},
-{13170, 17, 63289, {1, 1, 5, 9, 25, 7, 97, 155, 71, 569, 1481, 897, 6177, 13367, 12163, 18171, 24785}},
-{13171, 17, 63298, {1, 3, 5, 11, 19, 25, 7, 15, 511, 369, 957, 1247, 6097, 11181, 17265, 24777, 87377}},
-{13172, 17, 63303, {1, 3, 1, 7, 11, 9, 39, 191, 9, 793, 867, 2779, 3447, 3805, 21025, 64719, 15669}},
-{13173, 17, 63327, {1, 1, 3, 1, 31, 43, 107, 103, 175, 131, 1525, 993, 635, 14383, 26835, 15929, 109977}},
-{13174, 17, 63328, {1, 1, 1, 3, 19, 17, 99, 249, 47, 467, 853, 2805, 3155, 1565, 17291, 18865, 11039}},
-{13175, 17, 63348, {1, 1, 5, 13, 25, 61, 91, 67, 361, 947, 1909, 3403, 945, 3481, 16703, 50227, 43963}},
-{13176, 17, 63355, {1, 3, 1, 3, 19, 27, 31, 219, 185, 579, 1539, 315, 4421, 9473, 30289, 48477, 61365}},
-{13177, 17, 63357, {1, 1, 3, 1, 23, 11, 101, 1, 133, 305, 1107, 1145, 1733, 13275, 221, 5071, 81987}},
-{13178, 17, 63368, {1, 1, 1, 13, 7, 61, 47, 5, 137, 979, 1183, 2049, 5263, 6515, 5585, 6093, 119689}},
-{13179, 17, 63391, {1, 3, 1, 5, 19, 47, 83, 115, 215, 901, 1685, 755, 2327, 13297, 6847, 40329, 19225}},
-{13180, 17, 63402, {1, 1, 3, 3, 3, 13, 31, 127, 199, 655, 55, 2183, 5031, 945, 6073, 54729, 108281}},
-{13181, 17, 63409, {1, 1, 1, 1, 11, 51, 37, 19, 73, 205, 1377, 1881, 3679, 4487, 14693, 41735, 27349}},
-{13182, 17, 63416, {1, 3, 7, 13, 1, 35, 37, 73, 45, 973, 209, 529, 5283, 9765, 26367, 12697, 8685}},
-{13183, 17, 63419, {1, 3, 3, 9, 3, 45, 115, 35, 475, 663, 487, 3613, 4151, 15623, 3057, 31519, 87545}},
-{13184, 17, 63430, {1, 3, 7, 5, 23, 13, 25, 255, 355, 433, 1671, 667, 7463, 14189, 14107, 1531, 11695}},
-{13185, 17, 63442, {1, 1, 7, 3, 15, 25, 37, 127, 265, 493, 1763, 2721, 4335, 13753, 5947, 18375, 29911}},
-{13186, 17, 63457, {1, 1, 3, 15, 1, 55, 25, 69, 335, 157, 1923, 1757, 5689, 6731, 723, 6471, 57415}},
-{13187, 17, 63458, {1, 3, 3, 3, 1, 15, 127, 227, 401, 395, 503, 3783, 1737, 8785, 16287, 34949, 91683}},
-{13188, 17, 63482, {1, 3, 5, 15, 23, 29, 55, 119, 115, 855, 657, 3729, 5309, 14773, 5647, 25953, 67303}},
-{13189, 17, 63487, {1, 3, 5, 13, 23, 25, 1, 187, 67, 389, 359, 619, 2523, 11203, 11049, 60345, 53931}},
-{13190, 17, 63488, {1, 3, 1, 7, 7, 45, 99, 123, 495, 797, 939, 3387, 7563, 16289, 8309, 14917, 99867}},
-{13191, 17, 63500, {1, 3, 5, 11, 29, 49, 89, 205, 447, 541, 1279, 1153, 7277, 5393, 8743, 41057, 100119}},
-{13192, 17, 63511, {1, 1, 1, 9, 1, 7, 43, 165, 259, 311, 993, 1381, 3363, 577, 4023, 443, 101785}},
-{13193, 17, 63517, {1, 1, 7, 9, 25, 55, 93, 63, 423, 787, 549, 1039, 383, 15855, 6013, 51399, 60007}},
-{13194, 17, 63528, {1, 3, 3, 1, 5, 17, 103, 91, 309, 85, 1319, 3869, 559, 3993, 18111, 17753, 66681}},
-{13195, 17, 63531, {1, 3, 7, 9, 1, 11, 87, 151, 311, 597, 811, 3955, 275, 6555, 17005, 26763, 31227}},
-{13196, 17, 63559, {1, 1, 3, 11, 19, 51, 41, 101, 183, 1003, 1635, 2061, 3305, 12925, 7223, 4859, 24433}},
-{13197, 17, 63566, {1, 3, 7, 11, 7, 43, 79, 53, 43, 429, 947, 2533, 7005, 15147, 13435, 33997, 21201}},
-{13198, 17, 63578, {1, 1, 3, 5, 15, 17, 61, 41, 383, 465, 1439, 3503, 3981, 14469, 5075, 25953, 70461}},
-{13199, 17, 63580, {1, 1, 1, 13, 21, 53, 25, 59, 59, 195, 665, 3367, 2777, 9179, 24207, 56729, 94241}},
-{13200, 17, 63584, {1, 3, 7, 15, 27, 13, 41, 147, 415, 351, 961, 3811, 1605, 14231, 31789, 41189, 50265}},
-{13201, 17, 63587, {1, 3, 3, 7, 31, 39, 85, 219, 323, 657, 423, 1579, 3623, 7663, 14631, 47169, 88795}},
-{13202, 17, 63594, {1, 3, 1, 3, 1, 3, 125, 65, 259, 3, 1897, 2203, 347, 4101, 23841, 20217, 117407}},
-{13203, 17, 63607, {1, 1, 3, 7, 29, 1, 75, 255, 413, 237, 1531, 2103, 6847, 10395, 9817, 9383, 60679}},
-{13204, 17, 63611, {1, 3, 5, 3, 7, 63, 17, 83, 375, 835, 1707, 3227, 327, 2205, 25025, 47471, 39967}},
-{13205, 17, 63630, {1, 3, 7, 7, 9, 51, 23, 189, 157, 351, 755, 2695, 3923, 3481, 12159, 1041, 94563}},
-{13206, 17, 63632, {1, 1, 3, 11, 25, 27, 39, 19, 221, 795, 523, 695, 3257, 8045, 2643, 43239, 13291}},
-{13207, 17, 63641, {1, 3, 3, 5, 29, 1, 33, 117, 477, 147, 1117, 1943, 7967, 15999, 10673, 13349, 89471}},
-{13208, 17, 63647, {1, 1, 3, 9, 17, 51, 55, 115, 147, 687, 1751, 3685, 3099, 15369, 371, 55673, 67951}},
-{13209, 17, 63651, {1, 1, 7, 1, 5, 25, 67, 31, 103, 439, 1581, 705, 3855, 15985, 7151, 56511, 23697}},
-{13210, 17, 63666, {1, 3, 5, 3, 21, 7, 11, 123, 121, 1009, 277, 623, 7913, 7525, 4759, 19245, 16735}},
-{13211, 17, 63668, {1, 1, 5, 11, 7, 57, 103, 147, 199, 209, 233, 3665, 4215, 13511, 16393, 37873, 120857}},
-{13212, 17, 63695, {1, 1, 7, 9, 27, 45, 29, 97, 279, 379, 1683, 1965, 1183, 11389, 20445, 38435, 56893}},
-{13213, 17, 63697, {1, 3, 5, 5, 27, 23, 89, 169, 329, 659, 393, 903, 6217, 6459, 27327, 2843, 44889}},
-{13214, 17, 63709, {1, 1, 1, 15, 3, 53, 109, 83, 195, 5, 1865, 729, 3627, 13307, 20761, 50375, 60379}},
-{13215, 17, 63723, {1, 1, 1, 13, 25, 57, 17, 185, 359, 797, 469, 2637, 973, 2731, 25299, 15169, 90187}},
-{13216, 17, 63737, {1, 3, 5, 1, 19, 39, 87, 161, 117, 565, 1737, 3995, 6487, 5067, 18531, 38803, 45453}},
-{13217, 17, 63746, {1, 1, 1, 5, 19, 3, 93, 85, 479, 369, 469, 1407, 475, 7775, 12273, 34417, 65611}},
-{13218, 17, 63752, {1, 1, 3, 15, 31, 11, 105, 19, 281, 711, 713, 3423, 797, 11215, 31409, 44891, 110413}},
-{13219, 17, 63755, {1, 1, 3, 11, 13, 17, 59, 111, 59, 431, 1517, 2159, 1697, 12309, 16293, 2097, 107273}},
-{13220, 17, 63775, {1, 3, 5, 15, 25, 19, 97, 107, 97, 563, 247, 3691, 2775, 10631, 15113, 25721, 12995}},
-{13221, 17, 63781, {1, 1, 5, 3, 31, 25, 47, 201, 231, 123, 1923, 2287, 1711, 12271, 1573, 6605, 72991}},
-{13222, 17, 63794, {1, 1, 5, 5, 27, 17, 109, 125, 423, 1, 819, 3041, 685, 8791, 19697, 13107, 67681}},
-{13223, 17, 63796, {1, 1, 5, 3, 5, 63, 115, 95, 117, 715, 1523, 1231, 8171, 1615, 9819, 14361, 87075}},
-{13224, 17, 63808, {1, 1, 7, 7, 7, 35, 35, 175, 349, 853, 1665, 3101, 6051, 10737, 933, 40591, 9419}},
-{13225, 17, 63817, {1, 1, 1, 3, 23, 49, 65, 23, 103, 837, 403, 3799, 6515, 15363, 28079, 36381, 59523}},
-{13226, 17, 63820, {1, 3, 1, 15, 15, 25, 119, 181, 229, 685, 1047, 2397, 4855, 15393, 2371, 42441, 30151}},
-{13227, 17, 63826, {1, 3, 7, 11, 15, 5, 13, 93, 219, 203, 475, 523, 5827, 6579, 26759, 29795, 108463}},
-{13228, 17, 63838, {1, 1, 7, 13, 25, 53, 75, 195, 443, 1003, 501, 2543, 5453, 3119, 19225, 59631, 16413}},
-{13229, 17, 63848, {1, 1, 7, 13, 13, 25, 93, 211, 191, 1005, 1567, 3057, 3001, 1125, 6237, 35725, 108257}},
-{13230, 17, 63861, {1, 1, 3, 7, 21, 11, 57, 205, 487, 263, 1801, 3235, 1819, 10875, 6063, 26211, 54699}},
-{13231, 17, 63862, {1, 3, 3, 7, 11, 59, 89, 217, 15, 991, 1343, 1247, 277, 13377, 18499, 64987, 26053}},
-{13232, 17, 63866, {1, 3, 3, 1, 15, 51, 111, 69, 137, 817, 1207, 1729, 3877, 9873, 18449, 50749, 57457}},
-{13233, 17, 63878, {1, 3, 3, 5, 3, 39, 97, 147, 327, 257, 1547, 769, 7077, 5221, 13679, 44237, 70053}},
-{13234, 17, 63889, {1, 1, 5, 11, 19, 15, 79, 187, 335, 645, 1235, 4041, 4831, 10847, 28135, 48353, 64921}},
-{13235, 17, 63892, {1, 1, 7, 9, 3, 43, 41, 149, 71, 205, 1513, 2801, 6785, 3187, 25401, 55367, 114491}},
-{13236, 17, 63901, {1, 1, 7, 1, 25, 11, 37, 205, 365, 435, 147, 1303, 587, 14563, 32461, 28983, 86157}},
-{13237, 17, 63915, {1, 1, 7, 1, 31, 11, 51, 37, 401, 343, 1677, 991, 501, 11993, 14781, 37055, 30161}},
-{13238, 17, 63917, {1, 3, 5, 9, 9, 21, 95, 45, 447, 957, 943, 3997, 4033, 8371, 25007, 52827, 50207}},
-{13239, 17, 63926, {1, 1, 7, 1, 9, 45, 3, 255, 297, 341, 215, 3631, 7049, 7625, 4145, 50109, 48615}},
-{13240, 17, 63932, {1, 3, 3, 9, 27, 49, 41, 143, 291, 343, 719, 311, 3819, 7699, 17631, 64785, 49239}},
-{13241, 17, 63937, {1, 1, 7, 3, 27, 35, 61, 183, 153, 781, 979, 1465, 3315, 14893, 29847, 18461, 74949}},
-{13242, 17, 63938, {1, 3, 5, 15, 19, 61, 39, 219, 279, 909, 1295, 1681, 8021, 957, 7675, 14001, 77669}},
-{13243, 17, 63943, {1, 3, 1, 5, 15, 59, 127, 85, 229, 649, 503, 3267, 2465, 5637, 2729, 24831, 44791}},
-{13244, 17, 63944, {1, 3, 7, 11, 23, 55, 61, 191, 345, 255, 105, 1361, 3913, 7655, 8865, 1825, 80619}},
-{13245, 17, 63950, {1, 3, 3, 13, 29, 15, 53, 19, 1, 651, 917, 2043, 2333, 13695, 28225, 16457, 11287}},
-{13246, 17, 63952, {1, 1, 3, 13, 15, 53, 41, 211, 13, 287, 383, 3923, 665, 10343, 4803, 22199, 90521}},
-{13247, 17, 63955, {1, 3, 7, 11, 23, 27, 127, 241, 11, 451, 495, 2779, 319, 13119, 5575, 43043, 11659}},
-{13248, 17, 63957, {1, 1, 1, 7, 17, 53, 55, 39, 233, 273, 1873, 843, 7885, 329, 6809, 33119, 116017}},
-{13249, 17, 63961, {1, 1, 1, 7, 21, 41, 23, 113, 283, 265, 1535, 2371, 3975, 6293, 22497, 65349, 48653}},
-{13250, 17, 63962, {1, 3, 7, 9, 25, 21, 61, 135, 245, 777, 679, 2603, 565, 3251, 32469, 12707, 40297}},
-{13251, 17, 63978, {1, 1, 1, 5, 31, 49, 35, 215, 445, 669, 779, 2231, 5399, 5853, 17941, 33973, 126141}},
-{13252, 17, 63983, {1, 3, 5, 5, 3, 31, 45, 235, 51, 65, 295, 3755, 8101, 821, 28331, 38837, 55235}},
-{13253, 17, 63988, {1, 1, 5, 15, 23, 15, 37, 197, 59, 455, 1875, 1745, 7565, 8039, 15901, 63129, 36095}},
-{13254, 17, 64008, {1, 1, 5, 11, 7, 1, 77, 235, 309, 245, 1539, 1421, 3401, 1477, 12655, 19851, 86147}},
-{13255, 17, 64013, {1, 1, 3, 9, 27, 9, 113, 127, 167, 213, 161, 4065, 1275, 10699, 26111, 26213, 129091}},
-{13256, 17, 64019, {1, 3, 5, 9, 9, 17, 109, 205, 23, 145, 1261, 51, 5855, 7411, 20551, 5801, 47841}},
-{13257, 17, 64026, {1, 1, 3, 3, 15, 1, 1, 39, 431, 601, 177, 525, 6951, 6271, 27031, 37157, 73979}},
-{13258, 17, 64028, {1, 3, 1, 3, 19, 61, 11, 131, 31, 223, 959, 3531, 2433, 15675, 29201, 49277, 43977}},
-{13259, 17, 64032, {1, 1, 5, 9, 5, 27, 57, 3, 503, 755, 1261, 3659, 6685, 10041, 24739, 12201, 19753}},
-{13260, 17, 64042, {1, 1, 7, 3, 31, 27, 7, 191, 7, 415, 1665, 1413, 7493, 2645, 23577, 46331, 9481}},
-{13261, 17, 64044, {1, 1, 5, 1, 29, 59, 99, 231, 33, 613, 1347, 2671, 1767, 15685, 26583, 44699, 73511}},
-{13262, 17, 64055, {1, 1, 3, 3, 9, 47, 93, 87, 45, 549, 219, 2141, 233, 10239, 30325, 14985, 70325}},
-{13263, 17, 64070, {1, 1, 3, 3, 21, 39, 81, 179, 319, 853, 93, 2869, 59, 6675, 22391, 16089, 33949}},
-{13264, 17, 64079, {1, 1, 3, 7, 31, 19, 73, 249, 175, 57, 1717, 3557, 2307, 4595, 22045, 33291, 123003}},
-{13265, 17, 64084, {1, 1, 1, 3, 7, 23, 81, 229, 387, 1001, 1371, 17, 667, 3043, 30507, 44613, 32239}},
-{13266, 17, 64087, {1, 1, 7, 15, 15, 59, 83, 99, 101, 863, 333, 845, 7547, 13345, 7599, 51, 10963}},
-{13267, 17, 64093, {1, 1, 1, 3, 15, 55, 73, 37, 429, 711, 1315, 2911, 5109, 953, 14721, 25551, 33527}},
-{13268, 17, 64100, {1, 1, 5, 9, 11, 57, 75, 107, 449, 293, 1267, 2633, 5291, 9939, 12365, 1975, 75705}},
-{13269, 17, 64104, {1, 3, 3, 7, 19, 51, 111, 233, 369, 873, 1419, 425, 6587, 11371, 29613, 28041, 77405}},
-{13270, 17, 64109, {1, 3, 1, 15, 11, 1, 65, 185, 301, 25, 75, 1353, 6879, 11519, 24093, 65223, 130659}},
-{13271, 17, 64140, {1, 1, 3, 3, 17, 17, 33, 177, 467, 841, 949, 1119, 7869, 5835, 22175, 20439, 98923}},
-{13272, 17, 64148, {1, 3, 1, 9, 1, 19, 1, 9, 487, 425, 1095, 1995, 693, 12661, 27717, 56167, 34829}},
-{13273, 17, 64151, {1, 1, 7, 7, 27, 57, 85, 159, 109, 801, 477, 3953, 3195, 11079, 26885, 59833, 4971}},
-{13274, 17, 64152, {1, 1, 1, 15, 25, 9, 89, 231, 499, 623, 1385, 3753, 4781, 15263, 12721, 17511, 67327}},
-{13275, 17, 64171, {1, 1, 3, 7, 9, 11, 103, 65, 319, 681, 1423, 2355, 6243, 399, 8483, 23697, 107995}},
-{13276, 17, 64179, {1, 1, 1, 1, 5, 7, 63, 117, 151, 905, 163, 3813, 6931, 13161, 15131, 63067, 15649}},
-{13277, 17, 64186, {1, 3, 3, 3, 13, 57, 69, 199, 283, 153, 617, 123, 3125, 3057, 8121, 14483, 28085}},
-{13278, 17, 64203, {1, 3, 7, 15, 25, 45, 25, 179, 91, 457, 681, 537, 243, 4369, 11395, 17565, 47875}},
-{13279, 17, 64206, {1, 3, 1, 13, 29, 51, 101, 23, 143, 715, 1725, 791, 6001, 4283, 10689, 49237, 5231}},
-{13280, 17, 64213, {1, 3, 3, 5, 27, 41, 39, 17, 501, 587, 1067, 1859, 9, 13449, 31257, 17675, 99769}},
-{13281, 17, 64214, {1, 1, 1, 3, 15, 57, 119, 195, 15, 779, 761, 733, 3505, 4815, 23167, 411, 52303}},
-{13282, 17, 64220, {1, 3, 1, 13, 9, 31, 5, 141, 19, 487, 739, 577, 4383, 1951, 24293, 45503, 111923}},
-{13283, 17, 64233, {1, 3, 1, 11, 25, 37, 107, 245, 89, 107, 1969, 1569, 7475, 11795, 6123, 45311, 52251}},
-{13284, 17, 64239, {1, 1, 7, 11, 15, 9, 67, 141, 199, 91, 819, 3721, 6251, 6107, 9393, 14941, 98545}},
-{13285, 17, 64248, {1, 3, 3, 11, 23, 9, 31, 211, 339, 665, 1507, 2255, 3589, 11495, 28393, 2017, 106735}},
-{13286, 17, 64251, {1, 3, 5, 11, 27, 13, 105, 217, 173, 337, 1573, 837, 3771, 8645, 28749, 27501, 45045}},
-{13287, 17, 64259, {1, 1, 5, 1, 11, 43, 99, 217, 131, 545, 1323, 3089, 5689, 785, 9043, 29961, 17855}},
-{13288, 17, 64268, {1, 1, 3, 9, 31, 41, 61, 239, 271, 123, 1583, 397, 4243, 12197, 9847, 12341, 130533}},
-{13289, 17, 64273, {1, 3, 5, 3, 27, 11, 33, 31, 77, 403, 823, 2791, 3475, 4201, 15967, 39149, 107137}},
-{13290, 17, 64279, {1, 3, 1, 11, 9, 5, 103, 145, 85, 341, 1615, 729, 7209, 10289, 20807, 54167, 15613}},
-{13291, 17, 64283, {1, 3, 7, 1, 29, 33, 91, 219, 171, 367, 907, 3645, 1059, 9031, 247, 13231, 14323}},
-{13292, 17, 64292, {1, 1, 1, 7, 19, 15, 65, 61, 221, 941, 1005, 1447, 3513, 8917, 17399, 52471, 64245}},
-{13293, 17, 64296, {1, 1, 5, 7, 5, 35, 15, 253, 325, 313, 2015, 3239, 1633, 9745, 11617, 10575, 35877}},
-{13294, 17, 64301, {1, 3, 5, 3, 13, 1, 115, 207, 227, 637, 1119, 781, 2897, 1573, 16499, 43167, 20631}},
-{13295, 17, 64302, {1, 3, 5, 9, 17, 47, 117, 7, 303, 719, 975, 1167, 2463, 5255, 28237, 33495, 57133}},
-{13296, 17, 64324, {1, 3, 5, 11, 5, 43, 123, 63, 19, 97, 1423, 695, 5985, 5923, 5755, 22721, 5411}},
-{13297, 17, 64331, {1, 3, 1, 9, 9, 25, 87, 197, 325, 827, 1679, 1561, 101, 3951, 17453, 33537, 121431}},
-{13298, 17, 64346, {1, 1, 7, 5, 13, 33, 3, 191, 171, 37, 619, 1917, 7525, 14103, 25807, 25455, 57455}},
-{13299, 17, 64364, {1, 3, 3, 1, 9, 35, 93, 159, 455, 115, 479, 665, 477, 4483, 29751, 45047, 41251}},
-{13300, 17, 64382, {1, 3, 1, 3, 11, 47, 41, 199, 511, 475, 151, 1163, 239, 6731, 4461, 39845, 99555}},
-{13301, 17, 64386, {1, 1, 5, 7, 9, 5, 49, 221, 503, 637, 1323, 3303, 4137, 6675, 17709, 49233, 38325}},
-{13302, 17, 64400, {1, 1, 5, 15, 1, 43, 55, 67, 291, 393, 237, 3555, 4171, 909, 8655, 46309, 61799}},
-{13303, 17, 64409, {1, 3, 5, 3, 3, 37, 125, 249, 509, 611, 983, 4093, 1633, 10063, 10811, 60033, 40999}},
-{13304, 17, 64419, {1, 3, 5, 11, 1, 37, 75, 255, 279, 545, 1999, 833, 2789, 14601, 16707, 64703, 53545}},
-{13305, 17, 64433, {1, 1, 5, 7, 3, 15, 59, 11, 17, 711, 721, 765, 3747, 13549, 28641, 47437, 42261}},
-{13306, 17, 64454, {1, 3, 7, 1, 3, 45, 65, 45, 279, 929, 933, 2215, 7095, 14593, 6047, 40747, 109789}},
-{13307, 17, 64458, {1, 3, 7, 15, 15, 55, 89, 155, 345, 515, 1005, 2921, 1761, 1095, 28463, 20971, 62451}},
-{13308, 17, 64482, {1, 3, 3, 1, 1, 41, 35, 149, 481, 171, 305, 1411, 237, 4515, 32375, 22645, 741}},
-{13309, 17, 64494, {1, 1, 1, 15, 17, 1, 123, 235, 221, 495, 1693, 3109, 6453, 8827, 23775, 9303, 30237}},
-{13310, 17, 64496, {1, 3, 3, 5, 7, 63, 37, 13, 457, 159, 1683, 2207, 1731, 3341, 7415, 21073, 119417}},
-{13311, 17, 64505, {1, 1, 7, 15, 21, 27, 5, 67, 267, 919, 203, 1129, 4029, 3407, 16767, 35485, 66903}},
-{13312, 17, 64514, {1, 1, 1, 5, 15, 29, 99, 5, 219, 677, 443, 3799, 2461, 747, 20885, 32661, 44079}},
-{13313, 17, 64519, {1, 1, 1, 1, 3, 55, 53, 151, 195, 587, 1155, 2439, 3817, 8735, 30849, 54107, 14113}},
-{13314, 17, 64525, {1, 1, 1, 9, 29, 15, 89, 175, 373, 925, 301, 3749, 5439, 2653, 22819, 41201, 77043}},
-{13315, 17, 64528, {1, 1, 1, 1, 25, 49, 29, 129, 331, 539, 1247, 773, 7891, 5905, 19571, 17919, 6815}},
-{13316, 17, 64534, {1, 1, 3, 15, 5, 63, 123, 133, 141, 383, 1893, 573, 629, 3939, 9455, 50433, 111415}},
-{13317, 17, 64561, {1, 1, 7, 9, 15, 33, 119, 159, 17, 511, 1841, 427, 3911, 8609, 4215, 9799, 84397}},
-{13318, 17, 64571, {1, 1, 7, 3, 9, 25, 63, 247, 235, 635, 915, 3423, 5421, 7021, 9203, 18121, 3683}},
-{13319, 17, 64579, {1, 3, 1, 1, 25, 11, 105, 1, 491, 137, 1923, 103, 3371, 3543, 5173, 36777, 23417}},
-{13320, 17, 64591, {1, 3, 3, 13, 19, 37, 93, 191, 101, 193, 351, 839, 7147, 5477, 29225, 45307, 1455}},
-{13321, 17, 64606, {1, 3, 1, 5, 11, 17, 95, 239, 105, 407, 395, 919, 3317, 14825, 23447, 4897, 128363}},
-{13322, 17, 64616, {1, 1, 1, 11, 27, 47, 83, 137, 163, 673, 1291, 3041, 4559, 7217, 23613, 19477, 93805}},
-{13323, 17, 64619, {1, 1, 1, 15, 25, 51, 37, 9, 23, 757, 1921, 2649, 5677, 11421, 10231, 1775, 124709}},
-{13324, 17, 64640, {1, 3, 1, 13, 31, 37, 37, 163, 59, 975, 1203, 1425, 1255, 3259, 16681, 38101, 118165}},
-{13325, 17, 64645, {1, 1, 3, 11, 17, 17, 31, 23, 169, 305, 3, 1631, 6853, 7019, 14539, 57663, 70377}},
-{13326, 17, 64649, {1, 1, 7, 3, 15, 61, 113, 31, 497, 935, 473, 819, 1223, 13907, 5075, 45177, 20255}},
-{13327, 17, 64652, {1, 3, 7, 13, 9, 41, 123, 121, 497, 877, 915, 3323, 4815, 4175, 25979, 38751, 107099}},
-{13328, 17, 64670, {1, 1, 3, 7, 13, 33, 31, 167, 331, 595, 517, 1237, 1947, 1905, 28155, 52431, 93065}},
-{13329, 17, 64673, {1, 3, 1, 1, 11, 51, 7, 151, 323, 211, 523, 2929, 233, 3633, 2785, 6043, 100101}},
-{13330, 17, 64674, {1, 1, 7, 13, 29, 3, 125, 247, 121, 567, 857, 3225, 7461, 15413, 773, 54939, 67443}},
-{13331, 17, 64683, {1, 1, 1, 15, 19, 29, 101, 179, 369, 115, 1777, 3223, 1499, 12487, 41, 50607, 111137}},
-{13332, 17, 64697, {1, 1, 3, 1, 9, 59, 21, 25, 173, 357, 1143, 1353, 3907, 10743, 30325, 39211, 116671}},
-{13333, 17, 64703, {1, 1, 7, 15, 9, 63, 67, 229, 7, 399, 2037, 3531, 6393, 4273, 9365, 52009, 118093}},
-{13334, 17, 64711, {1, 1, 7, 1, 31, 21, 5, 251, 433, 1, 481, 4041, 6179, 825, 8671, 20597, 103257}},
-{13335, 17, 64723, {1, 1, 7, 1, 15, 41, 69, 93, 47, 17, 1901, 2671, 4739, 1883, 30239, 50763, 108295}},
-{13336, 17, 64736, {1, 3, 7, 15, 29, 19, 63, 213, 475, 133, 43, 955, 2001, 555, 10479, 1333, 52807}},
-{13337, 17, 64739, {1, 3, 3, 15, 27, 13, 91, 109, 71, 333, 1971, 3355, 2175, 11457, 31101, 30217, 68263}},
-{13338, 17, 64741, {1, 1, 5, 1, 21, 33, 51, 169, 365, 475, 1015, 985, 7217, 15453, 7727, 49843, 57733}},
-{13339, 17, 64748, {1, 1, 7, 1, 11, 37, 67, 135, 429, 403, 1663, 2037, 7849, 3757, 6373, 38703, 46393}},
-{13340, 17, 64759, {1, 1, 1, 3, 15, 3, 29, 101, 327, 643, 47, 1805, 6873, 1659, 31097, 34847, 46843}},
-{13341, 17, 64768, {1, 3, 1, 15, 9, 45, 7, 189, 175, 955, 45, 3545, 3595, 7443, 2913, 54501, 63279}},
-{13342, 17, 64771, {1, 3, 7, 11, 1, 39, 59, 179, 209, 121, 445, 4077, 4851, 15161, 29133, 13543, 106247}},
-{13343, 17, 64778, {1, 3, 7, 7, 5, 53, 73, 107, 409, 639, 1731, 1921, 999, 14445, 17629, 3667, 74819}},
-{13344, 17, 64792, {1, 3, 3, 9, 23, 41, 117, 195, 497, 425, 627, 1599, 7715, 1401, 7217, 61113, 67135}},
-{13345, 17, 64821, {1, 1, 5, 13, 9, 33, 97, 115, 233, 833, 1041, 1755, 5317, 12703, 25709, 62293, 2569}},
-{13346, 17, 64831, {1, 1, 1, 11, 1, 7, 27, 151, 325, 905, 1279, 4093, 7495, 9803, 17339, 7977, 24009}},
-{13347, 17, 64839, {1, 3, 1, 11, 25, 59, 89, 175, 67, 139, 1507, 411, 7863, 9585, 14869, 46655, 126021}},
-{13348, 17, 64848, {1, 3, 3, 15, 29, 5, 111, 251, 69, 177, 519, 901, 4331, 5341, 22031, 3851, 114369}},
-{13349, 17, 64860, {1, 3, 5, 3, 19, 9, 83, 69, 411, 673, 1549, 3429, 3647, 12601, 17177, 16161, 114561}},
-{13350, 17, 64867, {1, 1, 5, 5, 21, 15, 65, 179, 405, 571, 1245, 3693, 7471, 12109, 20177, 28783, 124339}},
-{13351, 17, 64870, {1, 1, 5, 5, 9, 61, 69, 99, 9, 829, 1823, 3803, 1181, 3073, 10069, 28689, 21347}},
-{13352, 17, 64874, {1, 1, 5, 1, 3, 11, 25, 99, 241, 957, 1137, 7, 3809, 7073, 21217, 49447, 41425}},
-{13353, 17, 64879, {1, 3, 1, 9, 15, 59, 13, 29, 467, 893, 1667, 31, 3269, 12599, 28673, 17101, 81591}},
-{13354, 17, 64887, {1, 3, 7, 3, 15, 55, 79, 177, 1, 891, 217, 2725, 6171, 7779, 16173, 1003, 37093}},
-{13355, 17, 64894, {1, 3, 7, 11, 15, 61, 13, 181, 421, 83, 905, 1089, 4597, 3291, 23243, 53123, 21315}},
-{13356, 17, 64897, {1, 1, 3, 3, 21, 63, 113, 149, 203, 379, 583, 1955, 8087, 9155, 23019, 17757, 1537}},
-{13357, 17, 64898, {1, 3, 5, 9, 27, 41, 61, 207, 213, 253, 693, 273, 1835, 14135, 11519, 40819, 50999}},
-{13358, 17, 64921, {1, 3, 5, 3, 1, 51, 71, 237, 355, 327, 1903, 133, 6075, 4685, 29689, 48723, 67791}},
-{13359, 17, 64933, {1, 3, 5, 9, 21, 13, 101, 23, 95, 369, 1657, 989, 4081, 1373, 29005, 7247, 53923}},
-{13360, 17, 64940, {1, 1, 7, 13, 15, 3, 71, 189, 345, 771, 251, 937, 1041, 3017, 27279, 1635, 32581}},
-{13361, 17, 64957, {1, 1, 5, 7, 23, 63, 99, 43, 237, 189, 1549, 25, 63, 14089, 14387, 51423, 57193}},
-{13362, 17, 64969, {1, 1, 7, 15, 13, 55, 89, 87, 95, 241, 827, 501, 2341, 14357, 831, 27101, 98285}},
-{13363, 17, 64972, {1, 1, 1, 9, 29, 29, 125, 81, 73, 123, 329, 2617, 1259, 4415, 30007, 19467, 117847}},
-{13364, 17, 64978, {1, 3, 1, 11, 15, 63, 85, 121, 409, 885, 1197, 423, 2673, 12107, 1127, 14119, 90541}},
-{13365, 17, 64984, {1, 3, 1, 3, 1, 35, 117, 149, 213, 925, 923, 1013, 3547, 6877, 3467, 47893, 38645}},
-{13366, 17, 64993, {1, 1, 3, 15, 3, 21, 87, 199, 197, 851, 1711, 3449, 1771, 1727, 11651, 51903, 99835}},
-{13367, 17, 64999, {1, 3, 3, 1, 5, 27, 57, 243, 465, 173, 697, 4011, 6177, 3019, 31317, 24699, 53151}},
-{13368, 17, 65000, {1, 3, 5, 7, 7, 51, 61, 177, 489, 381, 493, 1975, 3143, 8003, 7735, 46363, 110705}},
-{13369, 17, 65006, {1, 1, 7, 5, 27, 45, 69, 33, 229, 725, 2033, 3655, 3027, 11795, 2941, 7921, 117605}},
-{13370, 17, 65011, {1, 3, 1, 7, 3, 37, 91, 255, 13, 651, 49, 309, 7425, 11641, 3661, 3929, 94199}},
-{13371, 17, 65014, {1, 3, 7, 5, 7, 47, 121, 203, 297, 941, 1585, 3659, 265, 159, 30729, 31825, 343}},
-{13372, 17, 65036, {1, 3, 5, 9, 3, 25, 95, 215, 125, 105, 37, 943, 4095, 8169, 26763, 20975, 122307}},
-{13373, 17, 65044, {1, 1, 3, 15, 9, 13, 81, 25, 51, 15, 599, 835, 6723, 9487, 25219, 60401, 48749}},
-{13374, 17, 65063, {1, 3, 3, 15, 15, 47, 41, 219, 77, 43, 1705, 2363, 7005, 7137, 17687, 665, 116097}},
-{13375, 17, 65067, {1, 3, 5, 1, 17, 33, 71, 3, 253, 355, 117, 1995, 3339, 11789, 13563, 58889, 18553}},
-{13376, 17, 65075, {1, 3, 5, 1, 21, 33, 89, 177, 9, 951, 1593, 1419, 3295, 9617, 31661, 7841, 119939}},
-{13377, 17, 65077, {1, 3, 3, 1, 31, 35, 25, 9, 379, 271, 923, 2387, 3351, 5869, 4501, 6855, 28273}},
-{13378, 17, 65082, {1, 1, 5, 9, 11, 15, 127, 79, 405, 579, 395, 2469, 5847, 7589, 17577, 61717, 6493}},
-{13379, 17, 65095, {1, 3, 7, 13, 29, 13, 99, 209, 79, 469, 5, 2231, 89, 1557, 5123, 47169, 46529}},
-{13380, 17, 65101, {1, 3, 7, 9, 13, 35, 119, 53, 7, 351, 601, 901, 5407, 13673, 6929, 38311, 2659}},
-{13381, 17, 65104, {1, 3, 7, 9, 13, 23, 61, 255, 113, 331, 367, 2979, 2741, 6971, 26447, 6861, 116267}},
-{13382, 17, 65109, {1, 1, 3, 3, 25, 57, 93, 5, 387, 87, 1765, 1277, 8175, 11185, 4377, 9779, 95569}},
-{13383, 17, 65110, {1, 1, 7, 11, 29, 43, 31, 155, 111, 409, 733, 1919, 2681, 8435, 5877, 35439, 15435}},
-{13384, 17, 65116, {1, 1, 1, 7, 19, 33, 109, 125, 51, 733, 997, 3467, 5081, 8371, 263, 31461, 46117}},
-{13385, 17, 65126, {1, 3, 3, 7, 27, 61, 57, 75, 317, 247, 1535, 3757, 4617, 15627, 11191, 3581, 64475}},
-{13386, 17, 65129, {1, 3, 3, 1, 31, 7, 95, 151, 159, 475, 559, 379, 361, 5953, 5551, 20313, 64015}},
-{13387, 17, 65138, {1, 1, 5, 1, 11, 31, 71, 77, 493, 697, 345, 1809, 611, 14319, 6591, 23657, 44071}},
-{13388, 17, 65160, {1, 1, 1, 13, 5, 1, 9, 233, 229, 397, 1201, 1817, 7409, 11521, 3753, 35611, 123037}},
-{13389, 17, 65171, {1, 3, 7, 15, 9, 15, 85, 163, 99, 867, 265, 1021, 129, 11059, 123, 27185, 68435}},
-{13390, 17, 65173, {1, 3, 1, 11, 25, 43, 105, 165, 291, 977, 463, 2699, 5361, 9951, 29735, 63501, 86235}},
-{13391, 17, 65180, {1, 3, 7, 13, 9, 33, 39, 145, 441, 233, 373, 193, 1451, 7975, 2871, 64431, 43339}},
-{13392, 17, 65189, {1, 1, 7, 13, 15, 25, 45, 27, 319, 719, 1801, 447, 3027, 769, 271, 37227, 26447}},
-{13393, 17, 65193, {1, 1, 5, 1, 29, 1, 59, 59, 121, 251, 387, 55, 5957, 10527, 24227, 38841, 29115}},
-{13394, 17, 65208, {1, 3, 1, 5, 31, 25, 67, 191, 137, 849, 631, 953, 3103, 9737, 28993, 49413, 60709}},
-{13395, 17, 65214, {1, 3, 3, 15, 7, 5, 37, 179, 357, 961, 1649, 441, 5287, 4161, 24013, 39661, 76233}},
-{13396, 17, 65216, {1, 1, 5, 1, 9, 1, 47, 209, 219, 1021, 969, 2343, 5675, 7137, 14247, 50305, 72613}},
-{13397, 17, 65225, {1, 1, 3, 1, 9, 43, 43, 47, 35, 97, 617, 1033, 2387, 14155, 17049, 53333, 108619}},
-{13398, 17, 65236, {1, 3, 1, 3, 1, 45, 11, 171, 349, 65, 909, 1801, 1075, 10905, 7395, 19997, 128205}},
-{13399, 17, 65239, {1, 1, 7, 11, 19, 39, 117, 175, 459, 791, 1383, 3473, 6937, 8447, 10077, 13353, 122063}},
-{13400, 17, 65273, {1, 3, 3, 9, 3, 27, 115, 29, 135, 305, 1023, 2517, 1981, 4969, 18149, 35565, 120785}},
-{13401, 17, 65274, {1, 3, 3, 11, 15, 23, 27, 115, 411, 805, 841, 2205, 5997, 5141, 10679, 25235, 81989}},
-{13402, 17, 65281, {1, 1, 3, 9, 11, 63, 27, 185, 337, 891, 1447, 1397, 8009, 4453, 23077, 37599, 93389}},
-{13403, 17, 65294, {1, 1, 5, 13, 27, 11, 77, 11, 447, 81, 1603, 2317, 6499, 6631, 27305, 51049, 40967}},
-{13404, 17, 65324, {1, 3, 7, 1, 7, 43, 83, 33, 69, 119, 139, 1391, 4879, 3759, 31211, 29203, 110229}},
-{13405, 17, 65335, {1, 3, 7, 15, 31, 59, 53, 97, 135, 233, 1421, 587, 2985, 3627, 7355, 53829, 51581}},
-{13406, 17, 65354, {1, 3, 7, 15, 1, 37, 39, 225, 147, 37, 327, 2819, 6081, 4337, 22063, 21177, 91065}},
-{13407, 17, 65359, {1, 1, 3, 1, 13, 31, 61, 133, 433, 243, 131, 3625, 6389, 335, 24029, 33217, 80833}},
-{13408, 17, 65373, {1, 1, 7, 11, 21, 39, 95, 181, 35, 499, 677, 3935, 1379, 6791, 12633, 13671, 28317}},
-{13409, 17, 65383, {1, 3, 1, 5, 7, 57, 5, 229, 389, 197, 1523, 1221, 609, 10449, 6389, 9279, 53871}},
-{13410, 17, 65387, {1, 3, 5, 7, 1, 39, 69, 131, 387, 839, 1375, 3841, 81, 7395, 5837, 32067, 51183}},
-{13411, 17, 65397, {1, 1, 5, 3, 5, 27, 107, 171, 53, 923, 345, 445, 1101, 11201, 20563, 30889, 72361}},
-{13412, 17, 65411, {1, 3, 7, 11, 19, 7, 99, 219, 485, 403, 293, 3967, 7517, 4765, 11331, 55, 92641}},
-{13413, 17, 65413, {1, 1, 7, 13, 19, 9, 73, 31, 405, 513, 941, 3645, 7075, 8109, 21431, 52791, 120927}},
-{13414, 17, 65418, {1, 1, 1, 15, 29, 33, 75, 65, 479, 47, 35, 4023, 4853, 2793, 29895, 2711, 83779}},
-{13415, 17, 65441, {1, 1, 3, 15, 11, 1, 9, 149, 503, 845, 647, 1233, 4355, 3623, 3197, 36015, 24839}},
-{13416, 17, 65444, {1, 1, 7, 1, 31, 35, 59, 25, 393, 503, 227, 3243, 301, 11121, 32463, 38185, 69969}},
-{13417, 17, 65447, {1, 1, 1, 7, 9, 15, 11, 89, 19, 605, 1657, 3335, 1967, 29, 28619, 42301, 79909}},
-{13418, 17, 65448, {1, 3, 7, 7, 19, 29, 111, 55, 299, 733, 547, 395, 4831, 1991, 7357, 25781, 115129}},
-{13419, 17, 65473, {1, 1, 3, 7, 5, 33, 31, 101, 163, 389, 1163, 1843, 4105, 14209, 29261, 5821, 17929}},
-{13420, 17, 65476, {1, 3, 5, 1, 11, 23, 53, 227, 497, 695, 313, 3305, 6549, 15401, 9339, 40283, 60531}},
-{13421, 17, 65480, {1, 3, 5, 5, 3, 29, 77, 149, 509, 747, 85, 2561, 4435, 14475, 22887, 38177, 24535}},
-{13422, 17, 65494, {1, 1, 7, 1, 1, 33, 7, 77, 153, 369, 689, 3325, 1173, 16203, 1499, 36627, 66915}},
-{13423, 17, 65509, {1, 1, 5, 11, 23, 61, 95, 61, 289, 71, 653, 2817, 365, 7391, 1613, 48901, 57471}},
-{13424, 17, 65519, {1, 3, 3, 7, 15, 29, 65, 133, 15, 921, 1601, 1941, 6917, 10945, 20101, 59809, 9017}},
-{13425, 17, 65527, {1, 3, 3, 15, 7, 51, 95, 53, 87, 1017, 1039, 3405, 1967, 9855, 4905, 4651, 83487}},
-{13426, 18, 19, {1, 3, 5, 13, 23, 27, 31, 179, 121, 597, 829, 4003, 2487, 3977, 3087, 26791, 28305, 138357}},
-{13427, 18, 31, {1, 1, 5, 5, 5, 39, 95, 117, 461, 117, 109, 2571, 7651, 12361, 17921, 555, 33353, 186427}},
-{13428, 18, 38, {1, 1, 3, 13, 23, 47, 89, 125, 271, 609, 215, 3861, 6883, 3217, 2547, 54943, 60565, 215939}},
-{13429, 18, 61, {1, 1, 7, 15, 25, 61, 47, 93, 219, 919, 1551, 1417, 2753, 4353, 9201, 46423, 31227, 150649}},
-{13430, 18, 64, {1, 1, 1, 3, 29, 39, 11, 61, 137, 809, 147, 2715, 5455, 9431, 5725, 46135, 118193, 54099}},
-{13431, 18, 109, {1, 1, 3, 1, 25, 37, 83, 211, 423, 779, 1731, 2827, 883, 10477, 28771, 21723, 114333, 56293}},
-{13432, 18, 115, {1, 1, 5, 5, 27, 17, 21, 125, 495, 655, 1803, 3555, 1997, 15593, 29705, 48537, 53935, 179773}},
-{13433, 18, 118, {1, 1, 7, 5, 19, 63, 55, 15, 469, 769, 967, 3047, 1713, 11655, 15313, 29965, 78857, 223391}},
-{13434, 18, 131, {1, 3, 3, 5, 27, 33, 51, 171, 417, 243, 1203, 3505, 2533, 2695, 219, 57423, 5145, 143165}},
-{13435, 18, 167, {1, 3, 5, 9, 5, 19, 95, 97, 1, 863, 693, 2977, 4839, 6649, 22587, 40745, 113839, 69131}},
-{13436, 18, 200, {1, 3, 5, 1, 31, 39, 53, 85, 509, 5, 359, 1947, 3279, 5433, 21763, 46713, 37289, 35911}},
-{13437, 18, 241, {1, 3, 7, 13, 17, 35, 59, 63, 95, 667, 1775, 2165, 7861, 15731, 12159, 36179, 115457, 184819}},
-{13438, 18, 244, {1, 3, 3, 15, 19, 51, 7, 83, 367, 573, 503, 535, 333, 13041, 7187, 14479, 57473, 242951}},
-{13439, 18, 247, {1, 3, 5, 1, 7, 27, 65, 201, 365, 445, 985, 1175, 6391, 7345, 19935, 29085, 103001, 231855}},
-{13440, 18, 261, {1, 3, 5, 13, 15, 61, 95, 125, 135, 217, 1787, 417, 7641, 11825, 14531, 48497, 125087, 73279}},
-{13441, 18, 265, {1, 1, 5, 13, 7, 25, 77, 99, 341, 447, 1711, 137, 2749, 3465, 26255, 719, 102595, 112825}},
-{13442, 18, 304, {1, 1, 7, 7, 15, 13, 127, 57, 359, 591, 713, 409, 1293, 4979, 7035, 11369, 85255, 207241}},
-{13443, 18, 314, {1, 3, 3, 5, 1, 45, 123, 183, 297, 375, 1269, 1197, 2389, 6269, 24549, 44643, 75893, 161509}},
-{13444, 18, 341, {1, 1, 5, 7, 17, 55, 67, 51, 449, 383, 2037, 871, 1359, 15317, 22055, 4655, 18065, 258271}},
-{13445, 18, 376, {1, 1, 3, 11, 21, 27, 59, 205, 145, 195, 1747, 1121, 1061, 8879, 31455, 56541, 74765, 183047}},
-{13446, 18, 395, {1, 1, 5, 15, 1, 11, 69, 157, 13, 185, 1355, 467, 4383, 13103, 21679, 35169, 33427, 32113}},
-{13447, 18, 405, {1, 3, 1, 3, 29, 41, 15, 209, 313, 61, 1749, 2457, 1897, 15595, 24441, 39913, 40499, 5179}},
-{13448, 18, 406, {1, 3, 7, 15, 25, 41, 87, 125, 239, 73, 207, 2043, 1133, 12845, 8533, 16339, 117913, 118677}},
-{13449, 18, 443, {1, 1, 3, 15, 25, 9, 15, 97, 395, 99, 2017, 1003, 847, 2535, 11753, 54769, 54011, 73541}},
-{13450, 18, 451, {1, 1, 7, 15, 11, 61, 13, 49, 319, 871, 893, 165, 3957, 8683, 31197, 39491, 58705, 213411}},
-{13451, 18, 458, {1, 3, 7, 3, 17, 43, 29, 81, 461, 595, 541, 243, 5587, 13083, 29981, 16187, 124601, 89543}},
-{13452, 18, 460, {1, 1, 5, 11, 7, 5, 61, 43, 445, 115, 1705, 419, 4627, 15063, 16053, 26249, 112243, 208711}},
-{13453, 18, 468, {1, 3, 3, 9, 27, 21, 89, 49, 41, 859, 681, 2043, 7445, 9591, 13443, 36981, 66785, 227899}},
-{13454, 18, 472, {1, 1, 3, 5, 11, 55, 51, 45, 41, 739, 1199, 191, 4563, 4035, 3657, 12189, 52879, 33961}},
-{13455, 18, 482, {1, 1, 1, 3, 17, 59, 47, 217, 389, 783, 1501, 517, 6311, 7903, 1371, 50617, 41723, 116473}},
-{13456, 18, 491, {1, 1, 5, 13, 29, 39, 101, 203, 101, 479, 1337, 2647, 6447, 563, 2593, 16533, 122535, 25587}},
-{13457, 18, 496, {1, 1, 3, 3, 27, 21, 75, 173, 289, 279, 665, 3177, 559, 8539, 10903, 16779, 128219, 125907}},
-{13458, 18, 524, {1, 1, 1, 11, 27, 1, 61, 247, 113, 585, 331, 3443, 5939, 5213, 27289, 57057, 17349, 62359}},
-{13459, 18, 536, {1, 3, 5, 15, 21, 41, 67, 47, 121, 11, 545, 3609, 7745, 3669, 9045, 8377, 97655, 99631}},
-{13460, 18, 542, {1, 3, 5, 9, 11, 15, 111, 61, 67, 775, 579, 3421, 7827, 13607, 32373, 43531, 86149, 238827}},
-{13461, 18, 557, {1, 1, 1, 1, 9, 45, 79, 153, 331, 399, 1777, 3515, 3363, 3499, 13461, 48651, 21731, 220611}},
-{13462, 18, 572, {1, 1, 1, 1, 31, 57, 117, 223, 139, 725, 1115, 3203, 8185, 11983, 20245, 55913, 36803, 68101}},
-{13463, 18, 580, {1, 1, 1, 3, 31, 57, 53, 79, 225, 307, 1645, 3311, 643, 6587, 12037, 12453, 83461, 195503}},
-{13464, 18, 592, {1, 3, 1, 7, 23, 25, 65, 233, 273, 97, 37, 1563, 3635, 9299, 24367, 42761, 55, 128675}},
-{13465, 18, 656, {1, 3, 3, 11, 29, 21, 97, 143, 447, 345, 389, 381, 1403, 685, 309, 11103, 69769, 194441}},
-{13466, 18, 713, {1, 3, 3, 11, 23, 55, 119, 71, 23, 291, 1241, 1723, 5025, 4499, 26617, 22875, 62185, 240321}},
-{13467, 18, 719, {1, 1, 7, 11, 19, 63, 31, 131, 393, 99, 1061, 3805, 7477, 15357, 8269, 26067, 113349, 239333}},
-{13468, 18, 738, {1, 3, 5, 1, 5, 37, 77, 83, 37, 759, 1297, 3067, 5369, 5977, 7531, 49079, 94503, 192765}},
-{13469, 18, 749, {1, 1, 7, 1, 23, 9, 119, 137, 469, 73, 2001, 2629, 2681, 2295, 2055, 44027, 47627, 45283}},
-{13470, 18, 752, {1, 3, 1, 7, 31, 17, 61, 137, 241, 325, 1417, 2383, 4171, 2495, 215, 59593, 98495, 74727}},
-{13471, 18, 767, {1, 1, 7, 13, 7, 5, 59, 189, 131, 865, 1963, 1811, 5629, 16189, 16397, 58069, 72081, 191457}},
-{13472, 18, 772, {1, 1, 7, 15, 23, 33, 93, 247, 395, 643, 693, 3587, 4375, 5519, 9449, 37515, 11455, 218337}},
-{13473, 18, 782, {1, 1, 3, 1, 27, 63, 113, 91, 477, 55, 1461, 1547, 4743, 699, 21639, 1815, 169, 34239}},
-{13474, 18, 789, {1, 1, 5, 15, 29, 37, 19, 19, 247, 771, 695, 319, 1779, 10553, 16165, 60507, 87161, 86967}},
-{13475, 18, 830, {1, 1, 7, 1, 25, 61, 13, 167, 251, 861, 1717, 1533, 7323, 3945, 20879, 37759, 129689, 35901}},
-{13476, 18, 838, {1, 3, 3, 7, 7, 61, 11, 25, 187, 949, 1393, 1743, 745, 16313, 5293, 16921, 17619, 237705}},
-{13477, 18, 916, {1, 3, 5, 11, 7, 27, 11, 107, 299, 711, 149, 1581, 7747, 14285, 6411, 52209, 79043, 61117}},
-{13478, 18, 920, {1, 1, 5, 1, 17, 19, 91, 185, 53, 699, 1185, 4007, 1099, 1965, 20239, 19547, 120859, 234149}},
-{13479, 18, 936, {1, 1, 5, 5, 13, 61, 117, 187, 149, 957, 837, 3549, 6221, 501, 24755, 47975, 67007, 12329}},
-{13480, 18, 991, {1, 1, 3, 15, 21, 41, 55, 81, 397, 403, 1699, 1057, 6125, 11987, 3103, 43361, 21277, 156577}},
-{13481, 18, 998, {1, 1, 5, 11, 5, 27, 5, 177, 387, 859, 809, 3919, 4085, 1535, 6009, 13265, 3065, 217945}},
-{13482, 18, 1016, {1, 3, 1, 13, 15, 57, 107, 81, 437, 305, 879, 1691, 3685, 11415, 3749, 46999, 113933, 10515}},
-{13483, 18, 1024, {1, 1, 7, 13, 9, 43, 59, 223, 189, 329, 829, 2033, 1835, 8255, 8121, 46463, 61433, 86453}},
-{13484, 18, 1053, {1, 3, 1, 9, 11, 49, 63, 125, 11, 987, 2017, 2623, 4753, 13889, 57, 24755, 108489, 175383}},
-{13485, 18, 1081, {1, 1, 1, 3, 25, 33, 39, 151, 405, 657, 1755, 957, 5557, 7611, 25839, 51385, 92713, 64009}},
-{13486, 18, 1090, {1, 3, 7, 9, 17, 17, 115, 89, 225, 715, 1085, 543, 1047, 15053, 14359, 43301, 31455, 156555}},
-{13487, 18, 1125, {1, 1, 7, 11, 11, 21, 115, 5, 371, 1003, 1053, 1713, 5921, 7277, 799, 62483, 28079, 222319}},
-{13488, 18, 1135, {1, 1, 3, 3, 31, 15, 127, 213, 459, 229, 1477, 1863, 1021, 14881, 16299, 5953, 121455, 49659}},
-{13489, 18, 1143, {1, 1, 5, 9, 3, 39, 87, 219, 57, 479, 69, 2777, 8105, 11975, 14743, 26205, 93303, 45311}},
-{13490, 18, 1150, {1, 1, 5, 13, 3, 43, 55, 139, 19, 715, 2035, 2993, 2945, 9075, 6275, 32233, 103127, 49523}},
-{13491, 18, 1154, {1, 3, 1, 13, 19, 31, 109, 211, 261, 231, 697, 383, 2173, 14617, 11877, 37009, 5485, 236549}},
-{13492, 18, 1171, {1, 1, 5, 3, 5, 23, 91, 115, 369, 11, 1021, 519, 655, 4461, 23743, 56981, 51687, 114845}},
-{13493, 18, 1174, {1, 3, 7, 9, 29, 23, 19, 127, 17, 369, 1537, 2705, 4993, 1869, 15447, 28127, 73609, 97683}},
-{13494, 18, 1202, {1, 1, 3, 9, 17, 61, 97, 187, 213, 861, 725, 3205, 103, 12729, 2915, 28389, 83123, 124065}},
-{13495, 18, 1213, {1, 3, 1, 1, 5, 61, 47, 187, 471, 137, 1595, 707, 2449, 14315, 16409, 41467, 37533, 1649}},
-{13496, 18, 1225, {1, 3, 5, 5, 7, 39, 1, 245, 361, 43, 1259, 3149, 3449, 15723, 6225, 27445, 80529, 215349}},
-{13497, 18, 1233, {1, 3, 3, 11, 17, 27, 37, 47, 157, 345, 1437, 3219, 5663, 7299, 23925, 34067, 102379, 42767}},
-{13498, 18, 1234, {1, 3, 5, 13, 21, 59, 43, 189, 17, 303, 1949, 3627, 3495, 7981, 18115, 34221, 43511, 255257}},
-{13499, 18, 1252, {1, 3, 7, 15, 3, 29, 81, 243, 321, 853, 595, 2451, 1713, 11859, 27689, 12849, 24505, 9547}},
-{13500, 18, 1255, {1, 3, 1, 3, 7, 7, 89, 183, 51, 901, 253, 2421, 7453, 15827, 21451, 58653, 51933, 239113}},
-{13501, 18, 1294, {1, 1, 7, 3, 21, 59, 93, 25, 219, 805, 1699, 3777, 3683, 5351, 5481, 44797, 651, 32161}},
-{13502, 18, 1349, {1, 3, 7, 5, 31, 15, 15, 167, 305, 545, 331, 3765, 8191, 5763, 16965, 7239, 73735, 1049}},
-{13503, 18, 1354, {1, 3, 1, 15, 13, 19, 59, 107, 213, 39, 1547, 3413, 6175, 16195, 4635, 8945, 60301, 196697}},
-{13504, 18, 1378, {1, 1, 3, 1, 29, 17, 51, 61, 261, 951, 643, 2329, 2235, 9171, 11265, 3523, 89781, 227125}},
-{13505, 18, 1383, {1, 3, 5, 1, 1, 51, 75, 199, 479, 899, 1425, 3697, 2039, 4503, 11789, 16853, 94607, 236887}},
-{13506, 18, 1387, {1, 3, 1, 9, 19, 43, 111, 41, 385, 677, 1067, 3391, 7819, 13663, 17713, 10155, 124243, 56005}},
-{13507, 18, 1392, {1, 3, 5, 3, 15, 3, 105, 23, 307, 955, 843, 1277, 6697, 11903, 8901, 36129, 51685, 251115}},
-{13508, 18, 1402, {1, 3, 1, 5, 27, 35, 95, 57, 207, 49, 1559, 171, 4703, 511, 4169, 23241, 111447, 173109}},
-{13509, 18, 1420, {1, 3, 1, 13, 23, 5, 31, 15, 223, 673, 1333, 2243, 2479, 7489, 31891, 33909, 96803, 227027}},
-{13510, 18, 1428, {1, 3, 5, 11, 5, 45, 19, 13, 367, 475, 1719, 3947, 5295, 2319, 20697, 181, 16925, 80239}},
-{13511, 18, 1437, {1, 1, 5, 13, 15, 47, 89, 15, 153, 73, 523, 3529, 5401, 15881, 13779, 32123, 82347, 58749}},
-{13512, 18, 1448, {1, 3, 5, 7, 5, 7, 123, 217, 261, 65, 685, 2175, 3289, 7473, 17857, 48335, 94183, 216857}},
-{13513, 18, 1459, {1, 3, 7, 13, 7, 23, 85, 25, 231, 19, 1179, 2705, 6433, 10827, 1969, 51521, 76775, 260291}},
-{13514, 18, 1473, {1, 3, 3, 13, 9, 39, 5, 141, 475, 777, 1809, 1975, 2347, 12611, 28303, 15239, 45429, 170015}},
-{13515, 18, 1507, {1, 1, 7, 7, 31, 31, 39, 19, 317, 897, 739, 275, 2261, 16013, 1123, 33181, 96603, 37563}},
-{13516, 18, 1516, {1, 1, 7, 13, 31, 55, 87, 239, 193, 435, 625, 2153, 3979, 15537, 19937, 50621, 48273, 31381}},
-{13517, 18, 1528, {1, 1, 1, 15, 1, 57, 73, 237, 361, 749, 379, 2511, 501, 10783, 2787, 36983, 12393, 14345}},
-{13518, 18, 1573, {1, 1, 1, 3, 25, 33, 85, 25, 83, 939, 139, 2601, 6385, 16041, 28463, 38977, 28163, 232165}},
-{13519, 18, 1592, {1, 3, 5, 3, 9, 19, 119, 171, 499, 19, 569, 353, 1619, 6235, 24431, 47401, 48125, 168819}},
-{13520, 18, 1597, {1, 1, 1, 3, 9, 27, 121, 137, 411, 391, 1437, 1339, 7475, 3889, 15451, 34809, 69807, 162851}},
-{13521, 18, 1654, {1, 3, 5, 11, 31, 39, 41, 3, 171, 35, 81, 2713, 1077, 10697, 12343, 52133, 52825, 152255}},
-{13522, 18, 1663, {1, 1, 3, 11, 17, 51, 83, 19, 357, 207, 897, 2167, 1333, 4111, 29295, 65371, 73447, 61765}},
-{13523, 18, 1730, {1, 1, 3, 7, 9, 59, 17, 135, 365, 931, 1203, 277, 5531, 4213, 12969, 2617, 591, 154539}},
-{13524, 18, 1739, {1, 3, 7, 11, 1, 53, 31, 49, 135, 603, 227, 911, 7371, 8559, 27195, 33065, 71351, 245255}},
-{13525, 18, 1741, {1, 1, 7, 1, 15, 5, 31, 135, 197, 791, 1531, 2567, 2545, 15515, 25417, 27431, 15571, 176829}},
-{13526, 18, 1753, {1, 3, 1, 1, 15, 7, 89, 217, 505, 859, 1329, 2285, 7921, 11839, 7699, 56867, 112483, 3895}},
-{13527, 18, 1783, {1, 3, 1, 3, 27, 57, 37, 117, 491, 815, 275, 381, 7443, 3297, 1523, 34211, 97589, 232261}},
-{13528, 18, 1804, {1, 1, 3, 3, 29, 63, 69, 153, 297, 423, 1435, 3927, 7265, 13223, 17607, 21201, 57929, 73037}},
-{13529, 18, 1807, {1, 3, 1, 3, 23, 41, 1, 167, 121, 217, 973, 2149, 3807, 9895, 29635, 1625, 99829, 218541}},
-{13530, 18, 1832, {1, 3, 5, 7, 31, 33, 53, 165, 51, 119, 7, 1655, 6521, 5481, 9503, 6833, 80483, 252111}},
-{13531, 18, 1850, {1, 1, 7, 1, 5, 63, 25, 219, 165, 893, 1665, 2789, 1113, 9277, 3151, 12625, 82403, 59749}},
-{13532, 18, 1852, {1, 3, 7, 3, 21, 13, 127, 127, 145, 993, 715, 1947, 7501, 4385, 11759, 2179, 26039, 28027}},
-{13533, 18, 1881, {1, 3, 5, 9, 23, 27, 123, 1, 231, 709, 1615, 1433, 5991, 1045, 16269, 123, 110249, 154819}},
-{13534, 18, 1894, {1, 1, 1, 5, 17, 11, 123, 151, 387, 905, 991, 1571, 4463, 6765, 31905, 59307, 75175, 204571}},
-{13535, 18, 1927, {1, 3, 1, 11, 27, 49, 1, 181, 77, 1023, 807, 3479, 7965, 4633, 17495, 5991, 77081, 249343}},
-{13536, 18, 1952, {1, 3, 1, 1, 13, 53, 105, 79, 269, 173, 1319, 1695, 1215, 3651, 25063, 34949, 77243, 214671}},
-{13537, 18, 1969, {1, 1, 1, 1, 3, 19, 103, 233, 1, 507, 721, 1797, 5025, 405, 13027, 23693, 89963, 25771}},
-{13538, 18, 1999, {1, 3, 5, 9, 21, 53, 1, 241, 405, 707, 1807, 3615, 1199, 11155, 27741, 53931, 55091, 248677}},
-{13539, 18, 2018, {1, 3, 5, 7, 27, 27, 39, 77, 475, 845, 1393, 3779, 5261, 13017, 13517, 18595, 64485, 180577}},
-{13540, 18, 2047, {1, 1, 3, 5, 7, 21, 95, 59, 203, 233, 1167, 3457, 3965, 4321, 14885, 6335, 78353, 39341}},
-{13541, 18, 2066, {1, 1, 7, 13, 27, 19, 27, 133, 419, 507, 945, 3595, 131, 7981, 31451, 62347, 19151, 256127}},
-{13542, 18, 2068, {1, 3, 7, 3, 7, 15, 9, 173, 257, 983, 223, 2881, 6911, 3681, 26183, 38943, 112171, 148627}},
-{13543, 18, 2093, {1, 3, 3, 15, 5, 49, 91, 205, 303, 183, 775, 3841, 4943, 14417, 23013, 59337, 85835, 181771}},
-{13544, 18, 2105, {1, 3, 5, 9, 21, 1, 117, 27, 509, 263, 1215, 893, 6677, 3275, 20831, 5045, 127323, 62589}},
-{13545, 18, 2116, {1, 1, 1, 3, 17, 61, 77, 239, 379, 649, 1151, 2359, 2659, 13853, 30589, 55873, 50359, 184125}},
-{13546, 18, 2149, {1, 1, 7, 5, 17, 33, 95, 111, 245, 873, 1721, 3079, 7753, 12889, 27107, 8267, 119413, 249045}},
-{13547, 18, 2201, {1, 1, 1, 15, 13, 23, 59, 169, 449, 283, 913, 2099, 5337, 4307, 3701, 16395, 112987, 14183}},
-{13548, 18, 2228, {1, 1, 5, 3, 5, 15, 3, 249, 97, 849, 1551, 3437, 1247, 10915, 24073, 53723, 40345, 37215}},
-{13549, 18, 2245, {1, 1, 1, 5, 21, 59, 109, 79, 9, 827, 1329, 405, 3821, 8415, 11239, 1003, 78967, 112627}},
-{13550, 18, 2246, {1, 1, 1, 11, 21, 7, 21, 45, 327, 365, 865, 1409, 1273, 15675, 21425, 45367, 22279, 240943}},
-{13551, 18, 2283, {1, 3, 3, 7, 3, 19, 83, 163, 381, 547, 195, 1537, 7905, 9057, 1309, 41135, 118857, 101725}},
-{13552, 18, 2288, {1, 1, 5, 9, 11, 19, 107, 247, 309, 343, 1697, 699, 7137, 12815, 18405, 42673, 505, 104801}},
-{13553, 18, 2320, {1, 3, 5, 3, 13, 43, 55, 15, 441, 843, 1153, 3739, 67, 11053, 30985, 55329, 57301, 190991}},
-{13554, 18, 2326, {1, 1, 5, 3, 23, 41, 9, 239, 227, 145, 1895, 2645, 945, 6421, 2859, 16173, 97043, 234649}},
-{13555, 18, 2386, {1, 3, 1, 3, 23, 47, 57, 207, 441, 279, 1951, 3041, 2465, 6143, 27669, 41171, 89627, 2489}},
-{13556, 18, 2392, {1, 3, 1, 11, 7, 9, 19, 51, 345, 187, 1699, 1483, 15, 10321, 25277, 34889, 85225, 259071}},
-{13557, 18, 2395, {1, 1, 1, 15, 27, 15, 79, 51, 407, 757, 611, 3955, 1123, 14659, 11273, 56639, 64727, 183077}},
-{13558, 18, 2413, {1, 3, 7, 1, 13, 61, 89, 157, 29, 561, 791, 995, 4233, 11351, 16335, 47041, 108671, 120115}},
-{13559, 18, 2419, {1, 3, 3, 15, 17, 35, 15, 223, 57, 7, 961, 3327, 7287, 5537, 26231, 3289, 106555, 109781}},
-{13560, 18, 2441, {1, 3, 7, 15, 17, 3, 25, 121, 349, 995, 1353, 2991, 3071, 3583, 26173, 42343, 60495, 44035}},
-{13561, 18, 2466, {1, 3, 1, 11, 5, 5, 83, 249, 427, 173, 1733, 45, 3277, 7911, 18091, 61305, 130251, 31849}},
-{13562, 18, 2477, {1, 1, 1, 9, 3, 23, 23, 127, 371, 1011, 573, 1769, 1707, 15351, 30077, 61139, 122963, 203481}},
-{13563, 18, 2485, {1, 1, 1, 13, 27, 41, 97, 29, 461, 207, 1393, 707, 5633, 7155, 13455, 7305, 107539, 136413}},
-{13564, 18, 2492, {1, 1, 1, 9, 3, 13, 61, 115, 297, 333, 1679, 127, 8049, 3129, 31845, 40039, 77087, 6831}},
-{13565, 18, 2495, {1, 3, 3, 11, 27, 25, 49, 29, 423, 193, 1955, 2927, 5679, 3537, 16911, 47065, 126803, 129957}},
-{13566, 18, 2498, {1, 1, 1, 3, 21, 31, 25, 187, 301, 883, 1301, 415, 1515, 14761, 227, 24377, 54415, 64553}},
-{13567, 18, 2504, {1, 3, 7, 7, 3, 5, 69, 221, 357, 587, 1387, 3719, 5355, 10569, 14731, 22515, 107237, 1673}},
-{13568, 18, 2515, {1, 1, 3, 15, 27, 7, 89, 23, 213, 655, 779, 1641, 1793, 1499, 27279, 59423, 56715, 90313}},
-{13569, 18, 2521, {1, 3, 3, 7, 3, 33, 85, 181, 509, 327, 353, 1625, 4995, 15627, 17071, 31885, 122423, 100337}},
-{13570, 18, 2561, {1, 3, 5, 9, 7, 39, 45, 157, 279, 211, 1163, 3283, 4419, 10187, 22397, 42119, 25105, 163925}},
-{13571, 18, 2579, {1, 3, 3, 15, 17, 37, 75, 65, 501, 765, 1171, 2451, 309, 551, 15573, 65497, 106435, 20817}},
-{13572, 18, 2604, {1, 1, 3, 1, 13, 1, 79, 117, 5, 285, 953, 2401, 2479, 15765, 25677, 63611, 91807, 78153}},
-{13573, 18, 2657, {1, 1, 5, 15, 1, 7, 123, 159, 217, 307, 1779, 2625, 101, 13887, 31721, 55769, 94899, 183427}},
-{13574, 18, 2681, {1, 3, 5, 5, 11, 13, 59, 205, 221, 871, 753, 823, 547, 11055, 31621, 54379, 23631, 137027}},
-{13575, 18, 2691, {1, 3, 3, 7, 5, 17, 7, 31, 37, 237, 1633, 969, 4123, 6643, 28499, 3277, 130223, 37465}},
-{13576, 18, 2731, {1, 3, 7, 5, 29, 41, 65, 159, 487, 61, 1217, 4093, 487, 15257, 13379, 46641, 88043, 107425}},
-{13577, 18, 2739, {1, 1, 7, 7, 19, 29, 87, 119, 13, 877, 467, 2661, 7733, 9303, 20069, 8445, 126159, 69421}},
-{13578, 18, 2765, {1, 3, 1, 13, 1, 57, 77, 241, 185, 479, 859, 2397, 1167, 6545, 20715, 50701, 107781, 149965}},
-{13579, 18, 2790, {1, 1, 5, 1, 1, 3, 19, 31, 473, 685, 1455, 1537, 1843, 4051, 17475, 56717, 70257, 112815}},
-{13580, 18, 2802, {1, 3, 7, 15, 9, 21, 19, 201, 13, 551, 1053, 1291, 3793, 7923, 30425, 55513, 30033, 70597}},
-{13581, 18, 2819, {1, 3, 1, 15, 21, 47, 127, 117, 199, 655, 1979, 1291, 8017, 11769, 9071, 12029, 112369, 2529}},
-{13582, 18, 2891, {1, 3, 5, 1, 15, 3, 25, 199, 101, 997, 597, 2485, 6509, 11913, 19573, 13985, 56165, 249}},
-{13583, 18, 2905, {1, 1, 7, 3, 19, 45, 107, 229, 241, 747, 1219, 3133, 3675, 4441, 13933, 64571, 95445, 250713}},
-{13584, 18, 2911, {1, 3, 1, 5, 11, 31, 89, 119, 503, 99, 75, 349, 7479, 15161, 6365, 62461, 39443, 188455}},
-{13585, 18, 2912, {1, 1, 5, 13, 25, 31, 65, 237, 259, 329, 89, 1283, 6033, 4401, 7655, 38837, 62367, 76555}},
-{13586, 18, 2921, {1, 1, 1, 7, 19, 61, 109, 41, 361, 89, 171, 2319, 3625, 8905, 24461, 36135, 28515, 101547}},
-{13587, 18, 2924, {1, 3, 5, 3, 5, 45, 123, 227, 339, 79, 309, 2619, 1621, 1295, 6395, 6717, 119933, 187231}},
-{13588, 18, 2945, {1, 1, 1, 3, 3, 45, 91, 225, 269, 475, 1159, 2599, 5087, 4141, 28375, 22413, 56235, 256559}},
-{13589, 18, 2952, {1, 1, 1, 13, 7, 51, 27, 65, 65, 381, 169, 1759, 4653, 9885, 25839, 19851, 4965, 249097}},
-{13590, 18, 2972, {1, 3, 7, 11, 25, 11, 83, 137, 419, 277, 503, 2823, 2759, 8173, 9405, 23731, 116087, 9735}},
-{13591, 18, 2986, {1, 1, 5, 5, 27, 17, 123, 145, 41, 85, 1099, 1087, 1465, 7063, 8585, 39427, 15479, 243967}},
-{13592, 18, 3000, {1, 1, 7, 3, 21, 53, 105, 185, 101, 763, 593, 2649, 3273, 5655, 12233, 11761, 27093, 121347}},
-{13593, 18, 3008, {1, 1, 1, 5, 11, 55, 107, 167, 179, 681, 741, 1821, 4297, 14677, 9949, 9647, 60465, 36999}},
-{13594, 18, 3011, {1, 1, 1, 7, 25, 43, 95, 71, 161, 517, 1475, 1989, 6273, 13295, 19681, 51773, 93523, 33441}},
-{13595, 18, 3018, {1, 3, 1, 13, 23, 59, 95, 177, 73, 707, 37, 421, 3747, 14207, 17159, 4957, 20161, 26185}},
-{13596, 18, 3047, {1, 1, 7, 13, 13, 1, 19, 153, 445, 429, 1911, 3515, 639, 16015, 833, 54347, 87717, 82175}},
-{13597, 18, 3071, {1, 3, 5, 9, 1, 9, 115, 87, 341, 651, 1583, 807, 559, 13579, 9647, 37277, 125555, 169655}},
-{13598, 18, 3079, {1, 1, 3, 5, 13, 23, 117, 229, 205, 803, 1381, 2773, 7099, 4031, 597, 37135, 11643, 92325}},
-{13599, 18, 3083, {1, 3, 7, 9, 27, 15, 33, 147, 1, 799, 1511, 2609, 1419, 5991, 15571, 56995, 97695, 223969}},
-{13600, 18, 3086, {1, 3, 1, 3, 17, 9, 17, 189, 407, 355, 765, 2545, 1079, 15253, 4785, 5187, 80775, 238775}},
-{13601, 18, 3148, {1, 1, 3, 1, 31, 29, 3, 159, 263, 325, 125, 2221, 6369, 5717, 13985, 33829, 21375, 134249}},
-{13602, 18, 3156, {1, 3, 7, 3, 5, 29, 39, 75, 183, 155, 1017, 637, 921, 9561, 14893, 59695, 38325, 15503}},
-{13603, 18, 3194, {1, 1, 3, 13, 9, 31, 43, 71, 241, 661, 325, 357, 431, 903, 5039, 24535, 94241, 228605}},
-{13604, 18, 3230, {1, 3, 1, 1, 17, 37, 93, 47, 25, 207, 611, 415, 6473, 15979, 2025, 19003, 8941, 248779}},
-{13605, 18, 3233, {1, 1, 7, 15, 19, 17, 81, 201, 121, 11, 1975, 1289, 4405, 7851, 9707, 20057, 33749, 187161}},
-{13606, 18, 3254, {1, 1, 3, 5, 29, 31, 47, 99, 435, 795, 947, 1299, 4011, 8315, 12827, 48071, 86567, 154655}},
-{13607, 18, 3268, {1, 1, 5, 3, 9, 59, 115, 191, 177, 65, 1835, 3989, 1819, 14325, 8939, 25337, 16099, 200577}},
-{13608, 18, 3305, {1, 3, 7, 9, 15, 47, 7, 195, 413, 1013, 1607, 3317, 6979, 13243, 275, 34125, 66069, 90201}},
-{13609, 18, 3323, {1, 1, 3, 3, 29, 3, 51, 137, 341, 393, 897, 351, 1937, 6793, 12551, 18873, 110949, 133925}},
-{13610, 18, 3326, {1, 3, 5, 9, 29, 41, 79, 169, 113, 123, 1229, 1885, 6153, 1549, 31729, 41949, 74083, 41387}},
-{13611, 18, 3343, {1, 3, 1, 15, 31, 49, 7, 233, 305, 435, 1299, 3037, 2387, 15431, 817, 11783, 24067, 116527}},
-{13612, 18, 3345, {1, 3, 5, 13, 7, 17, 49, 33, 133, 45, 689, 2381, 2649, 2433, 27535, 21755, 88611, 200585}},
-{13613, 18, 3382, {1, 1, 5, 11, 1, 61, 87, 97, 91, 433, 313, 2541, 5289, 5769, 17963, 5719, 12165, 146849}},
-{13614, 18, 3413, {1, 3, 7, 13, 17, 21, 37, 191, 489, 847, 841, 3567, 7339, 15233, 23973, 1209, 99741, 243303}},
-{13615, 18, 3420, {1, 3, 1, 1, 5, 21, 11, 39, 69, 751, 1679, 143, 6187, 2963, 695, 45763, 126749, 243841}},
-{13616, 18, 3434, {1, 3, 3, 9, 21, 55, 43, 73, 133, 417, 495, 2899, 5681, 13049, 30241, 44519, 19095, 30673}},
-{13617, 18, 3453, {1, 1, 5, 9, 17, 51, 121, 205, 273, 597, 1325, 3755, 5113, 12287, 21323, 17947, 23807, 20025}},
-{13618, 18, 3472, {1, 1, 7, 7, 21, 11, 25, 33, 207, 13, 1639, 1971, 7401, 11771, 7879, 59027, 111981, 65451}},
-{13619, 18, 3488, {1, 3, 5, 15, 3, 15, 121, 23, 199, 839, 937, 3659, 5379, 2139, 31631, 17215, 65349, 157413}},
-{13620, 18, 3503, {1, 1, 1, 7, 3, 7, 81, 49, 17, 693, 1819, 2737, 7329, 49, 1655, 42317, 31385, 11435}},
-{13621, 18, 3506, {1, 3, 5, 15, 25, 51, 121, 133, 457, 159, 869, 855, 3529, 2691, 147, 58621, 78379, 148519}},
-{13622, 18, 3518, {1, 1, 3, 7, 1, 53, 109, 81, 37, 553, 1921, 3081, 2665, 12665, 13887, 1035, 16987, 48883}},
-{13623, 18, 3532, {1, 1, 5, 1, 19, 1, 121, 97, 143, 871, 1401, 2879, 5657, 5479, 14011, 65131, 56011, 241055}},
-{13624, 18, 3543, {1, 1, 7, 5, 9, 21, 9, 43, 331, 183, 1313, 2495, 6905, 2763, 29567, 7579, 95169, 130937}},
-{13625, 18, 3547, {1, 3, 7, 3, 3, 37, 65, 195, 339, 527, 1383, 3063, 7749, 11109, 8097, 27257, 107615, 134241}},
-{13626, 18, 3573, {1, 1, 1, 5, 25, 25, 63, 179, 135, 65, 169, 2709, 5435, 12119, 21549, 59847, 129639, 220163}},
-{13627, 18, 3574, {1, 3, 5, 1, 3, 17, 87, 181, 9, 923, 731, 3397, 7079, 3281, 10455, 35471, 20439, 206209}},
-{13628, 18, 3587, {1, 1, 1, 5, 31, 25, 15, 89, 381, 675, 1217, 3175, 707, 585, 1695, 57771, 92433, 203523}},
-{13629, 18, 3632, {1, 3, 5, 15, 5, 7, 9, 87, 461, 1017, 869, 1541, 7833, 3117, 24917, 13917, 104797, 149045}},
-{13630, 18, 3664, {1, 1, 7, 15, 13, 49, 9, 89, 165, 827, 657, 1977, 7471, 15437, 25785, 1455, 52803, 198793}},
-{13631, 18, 3713, {1, 3, 1, 15, 3, 39, 27, 205, 325, 345, 965, 1439, 4403, 10717, 9591, 46845, 123983, 76181}},
-{13632, 18, 3726, {1, 3, 1, 1, 25, 23, 97, 135, 367, 179, 1563, 75, 455, 3517, 21539, 59565, 43449, 139495}},
-{13633, 18, 3768, {1, 1, 5, 15, 13, 27, 55, 21, 1, 505, 1349, 409, 2491, 5299, 15771, 59389, 110377, 209275}},
-{13634, 18, 3771, {1, 1, 7, 9, 31, 15, 63, 91, 3, 559, 419, 1237, 1157, 5811, 24335, 19215, 12581, 148813}},
-{13635, 18, 3810, {1, 1, 7, 13, 23, 3, 81, 127, 33, 931, 867, 2905, 1011, 16207, 1543, 54309, 10611, 152733}},
-{13636, 18, 3848, {1, 3, 5, 7, 21, 19, 45, 101, 439, 537, 267, 945, 8007, 9383, 13211, 21867, 5731, 150203}},
-{13637, 18, 3868, {1, 1, 3, 9, 29, 3, 31, 219, 217, 775, 1011, 445, 2663, 1691, 9837, 5727, 116283, 128627}},
-{13638, 18, 3896, {1, 3, 3, 3, 21, 1, 97, 239, 457, 925, 1923, 1693, 1187, 13437, 8529, 22081, 633, 76109}},
-{13639, 18, 3910, {1, 3, 7, 7, 19, 5, 9, 15, 337, 855, 1563, 3159, 2799, 4103, 2013, 47789, 77027, 22425}},
-{13640, 18, 3921, {1, 1, 3, 15, 15, 41, 27, 77, 489, 377, 1953, 305, 5081, 1895, 5117, 51455, 71859, 190289}},
-{13641, 18, 3928, {1, 1, 5, 7, 7, 7, 13, 25, 115, 657, 223, 3185, 5327, 2559, 5147, 22237, 91933, 195429}},
-{13642, 18, 3940, {1, 1, 3, 5, 5, 19, 3, 197, 371, 237, 555, 2873, 3401, 3329, 29165, 4593, 111677, 244025}},
-{13643, 18, 3947, {1, 3, 5, 15, 15, 55, 29, 75, 329, 623, 279, 2831, 4489, 7803, 24119, 12959, 59783, 135213}},
-{13644, 18, 3949, {1, 3, 5, 13, 31, 21, 93, 77, 401, 353, 893, 917, 4813, 8027, 7847, 55315, 60213, 102763}},
-{13645, 18, 4001, {1, 1, 5, 13, 29, 49, 91, 35, 79, 625, 1539, 509, 823, 2239, 30867, 21729, 33195, 38189}},
-{13646, 18, 4004, {1, 3, 3, 3, 19, 11, 39, 145, 5, 329, 1653, 3205, 4431, 9291, 30369, 63173, 72317, 236103}},
-{13647, 18, 4022, {1, 3, 3, 15, 27, 9, 111, 191, 249, 845, 1845, 2097, 6529, 9559, 25757, 29085, 2615, 175759}},
-{13648, 18, 4026, {1, 3, 7, 1, 17, 59, 119, 125, 213, 995, 601, 2517, 1225, 2301, 13031, 40881, 31623, 165799}},
-{13649, 18, 4036, {1, 3, 3, 13, 25, 61, 97, 157, 347, 931, 1731, 3697, 5815, 7309, 30605, 3853, 72395, 103609}},
-{13650, 18, 4073, {1, 1, 7, 5, 23, 13, 51, 117, 495, 683, 777, 1629, 5683, 801, 4907, 24935, 9457, 214131}},
-{13651, 18, 4093, {1, 1, 5, 9, 1, 29, 107, 253, 195, 921, 345, 1451, 2253, 12723, 571, 12009, 34149, 140659}},
-{13652, 18, 4099, {1, 1, 5, 9, 31, 17, 93, 5, 455, 205, 1439, 1199, 7371, 12973, 16455, 675, 60561, 99575}},
-{13653, 18, 4120, {1, 3, 3, 3, 31, 37, 115, 49, 31, 285, 2029, 1369, 3443, 2411, 10367, 44859, 26737, 195703}},
-{13654, 18, 4136, {1, 1, 3, 1, 15, 39, 113, 37, 257, 3, 817, 2901, 4029, 12595, 30475, 34883, 109133, 92159}},
-{13655, 18, 4156, {1, 1, 7, 5, 9, 1, 9, 101, 317, 167, 1975, 411, 6875, 6951, 4401, 59483, 129813, 78289}},
-{13656, 18, 4176, {1, 1, 7, 9, 9, 5, 73, 7, 57, 907, 1887, 2923, 961, 8521, 873, 33791, 114485, 43081}},
-{13657, 18, 4182, {1, 1, 5, 7, 13, 45, 91, 179, 499, 197, 1337, 1321, 5307, 15503, 20449, 60813, 97393, 255741}},
-{13658, 18, 4191, {1, 1, 1, 5, 25, 13, 69, 221, 207, 823, 845, 3845, 6743, 5123, 27447, 2079, 100635, 124157}},
-{13659, 18, 4198, {1, 3, 5, 11, 13, 39, 121, 209, 137, 63, 1479, 323, 5347, 9797, 17785, 55541, 108713, 243347}},
-{13660, 18, 4252, {1, 1, 3, 9, 29, 45, 43, 81, 115, 979, 727, 423, 1133, 8757, 27833, 39907, 104663, 33067}},
-{13661, 18, 4259, {1, 3, 5, 1, 13, 61, 49, 17, 409, 567, 1035, 2299, 3711, 15485, 7767, 27809, 1275, 96455}},
-{13662, 18, 4261, {1, 1, 5, 9, 5, 33, 13, 9, 505, 459, 747, 4079, 4271, 6925, 13933, 31349, 5793, 68381}},
-{13663, 18, 4294, {1, 3, 3, 11, 15, 47, 15, 187, 349, 847, 817, 3551, 6059, 6451, 32615, 1635, 108889, 48003}},
-{13664, 18, 4341, {1, 3, 5, 7, 3, 31, 11, 255, 367, 295, 1079, 2981, 5583, 10771, 25359, 16083, 24163, 111201}},
-{13665, 18, 4348, {1, 3, 5, 5, 7, 5, 127, 19, 343, 849, 287, 1471, 7299, 1209, 31349, 33473, 4989, 229181}},
-{13666, 18, 4356, {1, 1, 3, 9, 25, 61, 7, 65, 77, 745, 1871, 2427, 3669, 8965, 11177, 5531, 115801, 34327}},
-{13667, 18, 4384, {1, 3, 3, 15, 1, 57, 125, 167, 173, 875, 347, 2317, 6687, 4339, 10573, 7841, 16241, 192225}},
-{13668, 18, 4389, {1, 3, 1, 3, 15, 37, 45, 189, 75, 1017, 1919, 3401, 329, 2539, 32697, 60801, 52017, 192611}},
-{13669, 18, 4401, {1, 3, 1, 5, 1, 23, 43, 55, 1, 443, 1769, 1633, 5225, 6855, 5419, 65139, 22237, 17415}},
-{13670, 18, 4428, {1, 3, 5, 15, 25, 7, 107, 209, 325, 367, 373, 1855, 1313, 12899, 30137, 19007, 9911, 11791}},
-{13671, 18, 4431, {1, 3, 7, 13, 3, 57, 123, 93, 279, 469, 1817, 3409, 565, 3997, 14119, 58341, 59691, 163323}},
-{13672, 18, 4445, {1, 1, 3, 9, 3, 3, 69, 109, 47, 487, 1895, 2003, 7309, 9803, 9527, 52211, 31213, 41521}},
-{13673, 18, 4470, {1, 1, 7, 7, 9, 15, 101, 227, 75, 501, 25, 1481, 4847, 13279, 28673, 11069, 61987, 5365}},
-{13674, 18, 4473, {1, 3, 1, 1, 25, 5, 47, 125, 97, 969, 1077, 1185, 6033, 13927, 18149, 34255, 14353, 66323}},
-{13675, 18, 4474, {1, 1, 3, 1, 25, 41, 19, 69, 385, 585, 1049, 3497, 3615, 13211, 18855, 61303, 115739, 42639}},
-{13676, 18, 4490, {1, 3, 7, 7, 13, 15, 13, 133, 497, 265, 1809, 4073, 5673, 7543, 30823, 13505, 76167, 98683}},
-{13677, 18, 4509, {1, 1, 5, 5, 3, 59, 47, 191, 419, 505, 2035, 329, 553, 1561, 27885, 39767, 102611, 12689}},
-{13678, 18, 4510, {1, 3, 7, 3, 27, 49, 27, 133, 305, 537, 385, 335, 2417, 14891, 31299, 26201, 124655, 150545}},
-{13679, 18, 4533, {1, 1, 1, 9, 7, 1, 27, 105, 347, 481, 2043, 1645, 4367, 10335, 16457, 48713, 64699, 63595}},
-{13680, 18, 4548, {1, 1, 3, 3, 7, 57, 125, 209, 299, 525, 591, 1265, 7557, 15113, 19319, 56269, 43919, 215435}},
-{13681, 18, 4558, {1, 1, 1, 11, 29, 59, 119, 245, 63, 919, 1913, 3969, 545, 1033, 20975, 61327, 36783, 124303}},
-{13682, 18, 4594, {1, 1, 7, 7, 11, 63, 45, 135, 405, 931, 753, 2559, 5475, 2107, 6437, 6055, 43497, 133571}},
-{13683, 18, 4596, {1, 3, 1, 13, 31, 39, 39, 141, 231, 83, 69, 473, 1095, 13617, 10909, 49861, 98029, 235003}},
-{13684, 18, 4603, {1, 3, 7, 13, 13, 41, 73, 107, 505, 359, 957, 1599, 7617, 1843, 25531, 63755, 96295, 167955}},
-{13685, 18, 4610, {1, 3, 3, 11, 13, 41, 61, 65, 165, 507, 1007, 1695, 91, 8781, 15017, 12063, 95331, 179853}},
-{13686, 18, 4619, {1, 3, 7, 7, 29, 19, 7, 95, 303, 641, 581, 3539, 4495, 13549, 20195, 20845, 16961, 95053}},
-{13687, 18, 4630, {1, 1, 7, 5, 15, 27, 13, 155, 345, 341, 1583, 2207, 2497, 6509, 24343, 3109, 71431, 184871}},
-{13688, 18, 4652, {1, 1, 3, 15, 31, 35, 37, 249, 71, 1005, 681, 3457, 3387, 13797, 8781, 11789, 16825, 11133}},
-{13689, 18, 4658, {1, 3, 7, 11, 5, 29, 121, 139, 77, 859, 163, 2749, 6401, 16303, 22659, 11817, 61667, 119993}},
-{13690, 18, 4682, {1, 1, 7, 11, 15, 45, 71, 87, 293, 981, 1581, 2789, 4117, 12791, 13611, 489, 74823, 71263}},
-{13691, 18, 4708, {1, 1, 3, 9, 15, 21, 59, 167, 469, 723, 1609, 2111, 6359, 10781, 1043, 51039, 24429, 14605}},
-{13692, 18, 4736, {1, 3, 3, 9, 13, 25, 1, 43, 61, 869, 1919, 601, 8003, 15841, 10141, 33187, 124991, 94205}},
-{13693, 18, 4753, {1, 1, 7, 5, 23, 13, 67, 43, 167, 667, 1743, 2523, 2245, 9287, 8115, 64995, 121371, 188321}},
-{13694, 18, 4760, {1, 1, 1, 9, 13, 19, 45, 249, 21, 751, 239, 4035, 4549, 8905, 9377, 47535, 78135, 210429}},
-{13695, 18, 4781, {1, 1, 3, 7, 5, 43, 13, 227, 75, 785, 631, 205, 3475, 9735, 17867, 61407, 75897, 51151}},
-{13696, 18, 4784, {1, 3, 3, 9, 31, 21, 11, 53, 247, 717, 1505, 3903, 3249, 3185, 29007, 48795, 43413, 158653}},
-{13697, 18, 4799, {1, 1, 5, 11, 19, 9, 37, 159, 183, 521, 743, 2877, 2291, 10317, 1211, 17951, 16335, 66439}},
-{13698, 18, 4807, {1, 1, 3, 7, 3, 41, 15, 113, 125, 391, 201, 3841, 255, 15381, 16801, 47219, 119691, 51811}},
-{13699, 18, 4808, {1, 1, 3, 1, 1, 29, 79, 181, 481, 969, 297, 625, 7449, 5813, 5915, 20011, 44853, 231933}},
-{13700, 18, 4842, {1, 1, 1, 5, 5, 49, 63, 171, 93, 107, 1083, 1277, 121, 4421, 18951, 61155, 66643, 120049}},
-{13701, 18, 4882, {1, 3, 7, 5, 25, 59, 111, 197, 459, 217, 1819, 1603, 5581, 11361, 17721, 57475, 11171, 186577}},
-{13702, 18, 4897, {1, 3, 3, 1, 25, 19, 29, 157, 25, 595, 501, 2145, 7513, 10323, 11107, 13269, 21763, 9427}},
-{13703, 18, 4900, {1, 3, 7, 3, 9, 49, 119, 117, 445, 91, 227, 1203, 6245, 9575, 30653, 65429, 64987, 81249}},
-{13704, 18, 4922, {1, 1, 5, 5, 5, 5, 77, 77, 425, 789, 467, 3931, 4815, 11195, 21939, 59513, 78547, 238035}},
-{13705, 18, 4936, {1, 3, 1, 11, 11, 29, 115, 37, 423, 997, 1231, 3987, 5057, 14533, 18005, 51513, 71851, 258137}},
-{13706, 18, 4960, {1, 3, 1, 1, 27, 31, 7, 223, 23, 59, 1465, 2045, 6677, 15707, 25101, 22269, 46995, 89141}},
-{13707, 18, 4970, {1, 1, 1, 5, 21, 7, 115, 133, 407, 373, 1495, 2551, 6947, 3309, 14903, 5683, 67345, 139381}},
-{13708, 18, 4978, {1, 1, 5, 3, 13, 31, 5, 221, 187, 9, 165, 2295, 1239, 5665, 14543, 3963, 4931, 8269}},
-{13709, 18, 4994, {1, 3, 5, 13, 15, 5, 37, 171, 419, 665, 765, 1619, 1561, 1661, 5873, 25595, 34827, 215599}},
-{13710, 18, 5003, {1, 3, 1, 15, 13, 33, 45, 107, 275, 771, 1105, 2895, 187, 5173, 21179, 35047, 50825, 176775}},
-{13711, 18, 5044, {1, 3, 7, 5, 17, 5, 59, 195, 441, 625, 1205, 207, 4703, 10627, 17123, 61785, 100779, 258597}},
-{13712, 18, 5061, {1, 1, 1, 13, 17, 3, 13, 201, 241, 657, 153, 289, 5213, 2129, 13447, 28807, 25405, 33803}},
-{13713, 18, 5107, {1, 3, 1, 9, 19, 9, 51, 133, 159, 743, 1023, 291, 7137, 6949, 30419, 13449, 111505, 212393}},
-{13714, 18, 5127, {1, 3, 5, 7, 31, 29, 79, 211, 425, 93, 1173, 1957, 6737, 1725, 30703, 43237, 119747, 157395}},
-{13715, 18, 5131, {1, 1, 7, 3, 17, 21, 39, 19, 485, 663, 19, 761, 1525, 11059, 12833, 17567, 61123, 124801}},
-{13716, 18, 5136, {1, 1, 7, 3, 7, 25, 17, 199, 413, 821, 1561, 3855, 1871, 14041, 7525, 19383, 51017, 213357}},
-{13717, 18, 5145, {1, 3, 3, 9, 25, 11, 63, 83, 217, 587, 47, 3775, 767, 9191, 5127, 9133, 97689, 122949}},
-{13718, 18, 5146, {1, 1, 1, 9, 19, 7, 89, 125, 23, 813, 1277, 2965, 1939, 1453, 6349, 53127, 109813, 63767}},
-{13719, 18, 5175, {1, 1, 5, 15, 29, 63, 117, 37, 185, 69, 1823, 2791, 4125, 11757, 14847, 15567, 126141, 185951}},
-{13720, 18, 5218, {1, 3, 7, 1, 23, 11, 15, 113, 209, 785, 229, 3207, 97, 2489, 4587, 14253, 30421, 51027}},
-{13721, 18, 5223, {1, 3, 1, 7, 7, 33, 57, 51, 219, 233, 89, 3781, 2055, 4163, 10935, 51913, 63507, 18645}},
-{13722, 18, 5248, {1, 3, 1, 7, 7, 55, 107, 187, 109, 867, 955, 139, 4979, 8627, 5835, 28761, 72061, 99413}},
-{13723, 18, 5294, {1, 1, 1, 3, 5, 59, 17, 121, 511, 29, 1009, 2875, 2459, 1817, 11741, 13869, 72543, 70485}},
-{13724, 18, 5299, {1, 1, 5, 1, 27, 19, 125, 65, 379, 803, 411, 2403, 719, 10683, 23351, 18113, 66773, 252223}},
-{13725, 18, 5301, {1, 1, 7, 9, 31, 51, 65, 233, 171, 357, 1465, 1609, 4263, 15207, 18825, 48831, 69459, 211321}},
-{13726, 18, 5311, {1, 1, 3, 3, 5, 35, 53, 245, 469, 1011, 759, 455, 4487, 9835, 10349, 61755, 73279, 186049}},
-{13727, 18, 5343, {1, 1, 7, 3, 27, 19, 105, 193, 403, 907, 295, 1445, 1867, 8867, 7821, 45309, 129069, 83953}},
-{13728, 18, 5344, {1, 1, 7, 7, 7, 51, 85, 97, 473, 837, 201, 501, 2929, 9457, 6473, 3653, 126991, 218069}},
-{13729, 18, 5396, {1, 3, 3, 5, 25, 49, 85, 223, 127, 563, 239, 1975, 119, 6029, 19349, 59533, 44173, 142229}},
-{13730, 18, 5406, {1, 1, 3, 7, 23, 11, 27, 49, 467, 701, 2037, 2367, 5829, 12533, 9641, 38629, 90505, 132013}},
-{13731, 18, 5410, {1, 1, 7, 1, 13, 25, 79, 107, 37, 331, 355, 3639, 4875, 6635, 21703, 18289, 36257, 201857}},
-{13732, 18, 5424, {1, 1, 5, 1, 3, 39, 25, 101, 199, 401, 1495, 3683, 5447, 12313, 19707, 20853, 66821, 73959}},
-{13733, 18, 5447, {1, 1, 1, 9, 15, 9, 3, 231, 479, 97, 221, 973, 839, 1757, 8759, 45625, 44691, 139803}},
-{13734, 18, 5461, {1, 1, 7, 15, 9, 51, 23, 233, 311, 83, 287, 4035, 2087, 4245, 25457, 43105, 104903, 132811}},
-{13735, 18, 5468, {1, 1, 1, 9, 5, 13, 33, 167, 363, 67, 601, 2143, 5495, 1277, 14615, 32759, 34935, 158625}},
-{13736, 18, 5475, {1, 1, 5, 11, 5, 63, 35, 49, 183, 705, 377, 2607, 2947, 10119, 15631, 60247, 99309, 25747}},
-{13737, 18, 5478, {1, 3, 7, 5, 7, 3, 127, 109, 165, 767, 1873, 3825, 441, 11957, 2581, 38309, 129623, 77451}},
-{13738, 18, 5523, {1, 3, 1, 7, 19, 53, 101, 117, 505, 363, 1399, 1015, 631, 8309, 17507, 28941, 42585, 116283}},
-{13739, 18, 5530, {1, 1, 7, 7, 9, 27, 127, 195, 499, 225, 153, 517, 3909, 9801, 3787, 32829, 6599, 190807}},
-{13740, 18, 5535, {1, 1, 5, 1, 3, 49, 125, 235, 255, 329, 909, 1685, 759, 2287, 3479, 23491, 71157, 81457}},
-{13741, 18, 5548, {1, 1, 3, 9, 19, 21, 93, 37, 259, 69, 219, 1943, 4747, 13951, 14945, 46099, 87189, 222287}},
-{13742, 18, 5559, {1, 1, 7, 5, 21, 33, 61, 227, 167, 569, 1355, 2997, 4917, 10765, 7015, 54335, 125543, 112867}},
-{13743, 18, 5580, {1, 1, 5, 3, 25, 35, 97, 23, 365, 159, 1211, 1283, 979, 8993, 21323, 6863, 46869, 36169}},
-{13744, 18, 5604, {1, 1, 7, 13, 15, 49, 45, 209, 397, 785, 47, 2307, 4749, 2735, 29525, 54921, 23321, 216197}},
-{13745, 18, 5622, {1, 1, 1, 11, 31, 23, 27, 127, 197, 595, 29, 773, 3291, 6355, 11891, 6635, 99871, 177531}},
-{13746, 18, 5641, {1, 1, 7, 11, 9, 49, 85, 59, 211, 307, 1821, 3947, 4175, 11287, 27889, 107, 46463, 237129}},
-{13747, 18, 5649, {1, 3, 3, 7, 31, 31, 9, 49, 365, 189, 1211, 943, 337, 13809, 16941, 17053, 70125, 149865}},
-{13748, 18, 5656, {1, 3, 1, 13, 9, 21, 67, 1, 365, 77, 1701, 559, 3461, 8961, 13801, 16111, 65239, 157713}},
-{13749, 18, 5671, {1, 3, 7, 13, 19, 49, 29, 233, 361, 1011, 1617, 2989, 2387, 14027, 4021, 28791, 33155, 171449}},
-{13750, 18, 5689, {1, 1, 5, 13, 31, 19, 77, 69, 49, 513, 1411, 77, 4993, 907, 23483, 20129, 29491, 138187}},
-{13751, 18, 5721, {1, 3, 3, 11, 23, 33, 19, 55, 307, 455, 1783, 3997, 6411, 3355, 8815, 39883, 124381, 49667}},
-{13752, 18, 5731, {1, 3, 3, 15, 27, 7, 25, 243, 275, 27, 23, 3039, 6497, 15975, 5877, 58611, 6317, 209119}},
-{13753, 18, 5734, {1, 3, 1, 5, 7, 21, 97, 247, 297, 181, 773, 3095, 2441, 15683, 29609, 50431, 92813, 723}},
-{13754, 18, 5738, {1, 1, 1, 3, 17, 25, 69, 171, 27, 83, 173, 163, 7915, 13547, 5915, 20275, 101613, 225081}},
-{13755, 18, 5740, {1, 1, 7, 15, 19, 13, 53, 95, 171, 889, 131, 1979, 2537, 7749, 77, 49293, 68875, 159125}},
-{13756, 18, 5748, {1, 1, 1, 5, 11, 7, 7, 29, 397, 435, 1495, 2263, 3677, 11121, 1269, 5415, 44427, 249943}},
-{13757, 18, 5791, {1, 3, 1, 5, 23, 21, 13, 185, 231, 757, 1647, 663, 1273, 11641, 25563, 46793, 54231, 113143}},
-{13758, 18, 5801, {1, 3, 3, 7, 11, 21, 83, 109, 409, 923, 1541, 2805, 1781, 6903, 9093, 37327, 60923, 167271}},
-{13759, 18, 5807, {1, 3, 7, 5, 29, 37, 87, 85, 93, 749, 875, 2869, 1023, 13303, 26865, 30971, 40863, 237075}},
-{13760, 18, 5822, {1, 1, 7, 13, 21, 25, 39, 213, 303, 265, 1251, 2963, 3819, 8507, 23239, 52625, 123375, 58553}},
-{13761, 18, 5829, {1, 1, 1, 1, 3, 1, 7, 67, 339, 583, 3, 2489, 5481, 12241, 21695, 31351, 39389, 131925}},
-{13762, 18, 5834, {1, 1, 5, 11, 11, 3, 95, 23, 133, 415, 77, 1891, 4083, 7097, 26455, 28689, 83047, 49759}},
-{13763, 18, 5847, {1, 3, 7, 15, 19, 31, 65, 189, 489, 461, 1255, 1897, 3361, 12223, 9721, 45937, 102695, 113431}},
-{13764, 18, 5854, {1, 3, 1, 5, 9, 57, 3, 225, 241, 769, 1003, 2255, 7655, 4837, 25267, 35845, 49545, 24931}},
-{13765, 18, 5878, {1, 1, 1, 1, 1, 43, 3, 217, 397, 419, 1189, 2037, 5941, 4341, 19851, 13773, 15225, 167581}},
-{13766, 18, 5882, {1, 1, 1, 9, 3, 27, 65, 49, 115, 787, 1637, 1867, 7265, 8541, 1587, 58987, 82161, 19997}},
-{13767, 18, 5919, {1, 3, 7, 11, 17, 17, 93, 103, 309, 159, 781, 3179, 5759, 7661, 5693, 48531, 127375, 141449}},
-{13768, 18, 5947, {1, 3, 7, 5, 13, 39, 79, 241, 7, 137, 219, 523, 541, 4787, 23327, 41665, 111017, 118901}},
-{13769, 18, 5981, {1, 1, 3, 15, 31, 23, 107, 221, 295, 935, 1165, 2463, 1635, 10205, 18057, 28217, 51755, 85579}},
-{13770, 18, 5982, {1, 3, 1, 11, 23, 47, 7, 59, 75, 603, 1237, 2601, 6873, 12735, 32181, 46849, 106363, 171753}},
-{13771, 18, 6025, {1, 1, 7, 13, 15, 31, 3, 113, 355, 955, 919, 1807, 7903, 5485, 1733, 64759, 15817, 93829}},
-{13772, 18, 6028, {1, 1, 3, 15, 11, 33, 95, 67, 511, 971, 343, 41, 2849, 10695, 24487, 8971, 129279, 197635}},
-{13773, 18, 6039, {1, 3, 1, 13, 13, 47, 77, 127, 193, 191, 1185, 3321, 1685, 1421, 28675, 12593, 86689, 186763}},
-{13774, 18, 6056, {1, 3, 7, 13, 1, 11, 123, 91, 287, 751, 11, 2753, 7153, 5253, 21817, 10459, 122225, 105775}},
-{13775, 18, 6064, {1, 3, 3, 13, 1, 17, 121, 13, 391, 253, 1323, 1515, 2067, 8009, 5173, 59543, 109511, 156821}},
-{13776, 18, 6073, {1, 1, 5, 3, 7, 1, 119, 151, 281, 859, 675, 2923, 6627, 16071, 24653, 41325, 118413, 191981}},
-{13777, 18, 6081, {1, 3, 5, 3, 31, 17, 57, 255, 473, 455, 203, 173, 345, 1477, 27939, 39289, 105081, 136179}},
-{13778, 18, 6088, {1, 3, 3, 7, 1, 35, 29, 81, 337, 483, 951, 955, 4343, 14827, 17427, 59919, 81883, 114289}},
-{13779, 18, 6101, {1, 3, 5, 11, 3, 39, 49, 177, 335, 57, 173, 1827, 5729, 2689, 12109, 13247, 117559, 31735}},
-{13780, 18, 6139, {1, 3, 1, 3, 9, 9, 41, 97, 37, 897, 545, 2289, 7917, 5701, 21953, 1863, 33727, 28451}},
-{13781, 18, 6142, {1, 1, 5, 3, 29, 61, 59, 129, 387, 965, 285, 3503, 1651, 10423, 24861, 31853, 38491, 155187}},
-{13782, 18, 6194, {1, 3, 1, 13, 23, 33, 13, 161, 133, 29, 1073, 1491, 3687, 6821, 24153, 3675, 33771, 230087}},
-{13783, 18, 6199, {1, 1, 7, 7, 29, 23, 23, 55, 189, 203, 641, 3391, 1217, 3199, 32531, 43103, 24007, 85613}},
-{13784, 18, 6200, {1, 1, 1, 11, 7, 57, 117, 245, 467, 861, 1265, 2827, 2761, 2817, 15679, 53223, 47245, 139871}},
-{13785, 18, 6203, {1, 1, 3, 15, 25, 1, 125, 237, 489, 1003, 515, 1117, 4427, 4877, 8685, 46211, 19889, 82491}},
-{13786, 18, 6214, {1, 1, 3, 3, 25, 3, 63, 217, 485, 699, 161, 1459, 2973, 15949, 30681, 30991, 13933, 86505}},
-{13787, 18, 6238, {1, 1, 7, 9, 27, 57, 23, 217, 401, 613, 277, 2827, 7111, 2133, 17489, 62059, 7273, 170917}},
-{13788, 18, 6241, {1, 1, 3, 13, 7, 19, 39, 63, 203, 1001, 279, 879, 4293, 10121, 969, 11571, 96427, 218969}},
-{13789, 18, 6244, {1, 3, 7, 7, 5, 21, 113, 203, 77, 971, 1351, 1097, 2581, 7519, 16049, 10565, 5055, 241561}},
-{13790, 18, 6248, {1, 3, 3, 11, 1, 21, 93, 111, 221, 31, 1245, 1499, 2289, 2299, 23457, 49221, 68879, 125029}},
-{13791, 18, 6256, {1, 1, 7, 3, 15, 19, 57, 189, 243, 785, 399, 3147, 6107, 2327, 6275, 9993, 53051, 34053}},
-{13792, 18, 6266, {1, 3, 7, 15, 5, 63, 7, 193, 115, 579, 1987, 765, 7871, 14179, 26383, 61455, 14241, 123515}},
-{13793, 18, 6271, {1, 3, 7, 13, 19, 13, 91, 225, 295, 675, 1995, 1145, 4929, 5163, 1101, 60681, 76777, 146875}},
-{13794, 18, 6275, {1, 3, 7, 15, 21, 37, 57, 89, 297, 143, 717, 4021, 3259, 8869, 21189, 39333, 125045, 94469}},
-{13795, 18, 6295, {1, 1, 5, 9, 27, 35, 69, 121, 433, 39, 889, 915, 4055, 11479, 24757, 53455, 17503, 113295}},
-{13796, 18, 6315, {1, 1, 3, 3, 23, 19, 81, 191, 33, 865, 59, 603, 2819, 4919, 22495, 25089, 73905, 44971}},
-{13797, 18, 6364, {1, 3, 3, 11, 19, 45, 125, 229, 143, 167, 867, 671, 2225, 16099, 14909, 14937, 78063, 135143}},
-{13798, 18, 6368, {1, 1, 7, 11, 21, 55, 73, 247, 211, 895, 1147, 17, 2119, 3261, 19815, 28055, 50139, 178459}},
-{13799, 18, 6377, {1, 1, 3, 1, 19, 3, 37, 221, 243, 459, 1539, 3899, 4597, 5503, 23015, 57019, 62637, 177821}},
-{13800, 18, 6400, {1, 3, 1, 3, 9, 5, 91, 3, 319, 609, 1241, 3953, 5569, 8757, 6453, 8083, 55285, 38297}},
-{13801, 18, 6430, {1, 3, 5, 15, 9, 51, 37, 53, 137, 95, 123, 157, 15, 7421, 22469, 49787, 96245, 199309}},
-{13802, 18, 6477, {1, 3, 1, 1, 29, 61, 85, 211, 437, 1013, 1251, 61, 157, 4325, 24247, 1065, 24875, 31509}},
-{13803, 18, 6480, {1, 3, 1, 13, 7, 43, 13, 171, 53, 567, 77, 3781, 5077, 6691, 32485, 24253, 83919, 159371}},
-{13804, 18, 6490, {1, 1, 1, 13, 15, 15, 19, 53, 325, 309, 53, 1857, 7361, 8831, 31751, 44749, 109265, 227875}},
-{13805, 18, 6526, {1, 3, 7, 3, 31, 19, 113, 253, 361, 697, 1137, 2029, 3673, 10323, 10455, 24935, 7325, 43673}},
-{13806, 18, 6539, {1, 3, 1, 1, 17, 31, 3, 55, 121, 967, 1701, 2171, 4393, 11937, 3987, 5139, 68913, 134233}},
-{13807, 18, 6556, {1, 1, 7, 15, 23, 37, 121, 241, 297, 419, 373, 1219, 739, 4567, 28593, 61267, 95711, 201299}},
-{13808, 18, 6584, {1, 1, 1, 9, 23, 31, 101, 243, 163, 333, 1707, 2553, 5285, 12827, 5051, 14165, 505, 253585}},
-{13809, 18, 6598, {1, 1, 1, 9, 11, 29, 81, 45, 101, 235, 1079, 4091, 1069, 3439, 23599, 6699, 71783, 236943}},
-{13810, 18, 6601, {1, 3, 7, 11, 29, 49, 99, 59, 1, 267, 887, 2941, 6717, 7501, 22549, 53393, 34569, 34671}},
-{13811, 18, 6609, {1, 3, 1, 15, 23, 13, 113, 47, 11, 79, 989, 1025, 35, 10475, 8079, 33121, 32477, 178595}},
-{13812, 18, 6612, {1, 3, 7, 1, 21, 19, 51, 31, 393, 171, 553, 2221, 7017, 8567, 21803, 51803, 83737, 196409}},
-{13813, 18, 6645, {1, 1, 3, 3, 1, 27, 117, 207, 37, 733, 2001, 2575, 4849, 5609, 743, 35987, 109993, 227663}},
-{13814, 18, 6655, {1, 1, 7, 15, 29, 47, 85, 213, 335, 633, 849, 3269, 7723, 4651, 355, 54565, 58829, 22781}},
-{13815, 18, 6679, {1, 3, 7, 5, 5, 3, 91, 243, 17, 85, 1983, 3909, 1839, 10403, 503, 28451, 3221, 215397}},
-{13816, 18, 6683, {1, 1, 1, 15, 13, 3, 9, 25, 249, 113, 1619, 2313, 6461, 2323, 14319, 59635, 9569, 220583}},
-{13817, 18, 6719, {1, 3, 5, 7, 31, 59, 41, 43, 43, 921, 647, 2141, 7011, 2749, 24711, 19067, 107895, 107145}},
-{13818, 18, 6727, {1, 1, 3, 3, 15, 63, 41, 241, 181, 729, 843, 3569, 2645, 2727, 25331, 23067, 115421, 86025}},
-{13819, 18, 6734, {1, 3, 1, 15, 11, 47, 9, 183, 341, 775, 1067, 1317, 6835, 7873, 2653, 33517, 103979, 196761}},
-{13820, 18, 6770, {1, 1, 3, 13, 29, 11, 105, 9, 49, 823, 1343, 759, 1263, 12413, 26047, 54285, 57319, 215387}},
-{13821, 18, 6776, {1, 1, 5, 13, 21, 55, 75, 149, 63, 737, 1305, 929, 4149, 2793, 24505, 11541, 74765, 8207}},
-{13822, 18, 6791, {1, 3, 5, 9, 25, 1, 43, 157, 303, 395, 301, 1561, 5963, 3501, 2259, 59777, 100953, 16051}},
-{13823, 18, 6798, {1, 3, 1, 13, 19, 25, 33, 209, 11, 95, 655, 595, 3081, 10345, 26615, 45129, 84023, 158079}},
-{13824, 18, 6800, {1, 3, 1, 9, 31, 61, 103, 203, 471, 215, 1103, 759, 1197, 3333, 15859, 36103, 31563, 5987}},
-{13825, 18, 6826, {1, 1, 1, 7, 1, 49, 121, 227, 153, 793, 1723, 1033, 6875, 6683, 2503, 57213, 97967, 120383}},
-{13826, 18, 6833, {1, 3, 7, 11, 3, 15, 35, 181, 19, 249, 755, 1385, 3297, 4665, 2761, 22717, 126199, 85065}},
-{13827, 18, 6836, {1, 3, 7, 15, 5, 45, 17, 55, 111, 597, 553, 1203, 7183, 8465, 28523, 50073, 90889, 187205}},
-{13828, 18, 6858, {1, 3, 3, 9, 31, 57, 13, 139, 291, 881, 501, 2051, 617, 5151, 28225, 44777, 31645, 6805}},
-{13829, 18, 6882, {1, 3, 5, 13, 1, 23, 107, 1, 201, 35, 1673, 2281, 7663, 1115, 25061, 59615, 127955, 169685}},
-{13830, 18, 6901, {1, 1, 3, 15, 15, 5, 17, 75, 307, 591, 1661, 855, 4239, 13359, 20027, 51871, 35241, 32769}},
-{13831, 18, 6923, {1, 1, 1, 15, 5, 23, 59, 205, 223, 103, 1889, 141, 6157, 9187, 23571, 15267, 1941, 119173}},
-{13832, 18, 6967, {1, 3, 5, 9, 27, 63, 59, 11, 279, 493, 209, 4087, 1055, 9841, 31753, 37459, 27757, 213151}},
-{13833, 18, 6979, {1, 1, 3, 11, 31, 33, 13, 87, 285, 847, 2005, 3431, 253, 15157, 31359, 45303, 114337, 42541}},
-{13834, 18, 7022, {1, 1, 1, 7, 7, 3, 17, 203, 133, 321, 241, 1323, 5639, 10953, 10069, 4941, 17077, 54493}},
-{13835, 18, 7060, {1, 1, 7, 1, 9, 5, 125, 5, 421, 609, 645, 1927, 3785, 2295, 1491, 23019, 85497, 161231}},
-{13836, 18, 7064, {1, 3, 3, 11, 19, 35, 115, 95, 353, 773, 2025, 2621, 2821, 6361, 29589, 20989, 99645, 90387}},
-{13837, 18, 7083, {1, 3, 1, 15, 23, 3, 71, 253, 467, 307, 1109, 2695, 7175, 15087, 1587, 48229, 104307, 218905}},
-{13838, 18, 7093, {1, 3, 3, 5, 17, 29, 107, 153, 371, 205, 7, 597, 7393, 2345, 20149, 47417, 37983, 200683}},
-{13839, 18, 7094, {1, 1, 7, 1, 3, 55, 113, 117, 241, 923, 1217, 3825, 2635, 8007, 12673, 9533, 7121, 3825}},
-{13840, 18, 7120, {1, 1, 1, 3, 21, 63, 25, 111, 31, 151, 67, 3735, 7833, 749, 28743, 59291, 4989, 93329}},
-{13841, 18, 7125, {1, 3, 5, 13, 31, 5, 91, 153, 235, 1019, 431, 1951, 7501, 8483, 19625, 57789, 13203, 36693}},
-{13842, 18, 7142, {1, 1, 7, 3, 15, 51, 99, 29, 403, 343, 1903, 907, 3255, 4149, 29551, 18885, 74391, 96119}},
-{13843, 18, 7151, {1, 1, 7, 11, 31, 11, 63, 213, 437, 879, 359, 555, 7549, 14269, 31489, 51001, 76857, 237305}},
-{13844, 18, 7165, {1, 1, 1, 15, 23, 21, 31, 227, 311, 273, 253, 2439, 7217, 2191, 31743, 47669, 62279, 201305}},
-{13845, 18, 7173, {1, 3, 5, 11, 3, 43, 97, 121, 363, 91, 201, 1095, 5267, 633, 19111, 36099, 23035, 205655}},
-{13846, 18, 7188, {1, 3, 1, 9, 21, 31, 39, 11, 227, 699, 473, 2109, 2757, 13821, 31181, 40493, 57279, 260085}},
-{13847, 18, 7191, {1, 1, 5, 7, 27, 57, 65, 11, 173, 709, 1139, 3735, 5291, 16053, 32579, 25275, 79865, 196033}},
-{13848, 18, 7202, {1, 1, 1, 9, 19, 35, 83, 153, 287, 207, 593, 2177, 3243, 10433, 24583, 881, 71865, 250223}},
-{13849, 18, 7216, {1, 3, 3, 9, 3, 35, 107, 3, 193, 1011, 463, 1643, 2733, 2157, 6329, 24583, 116901, 226385}},
-{13850, 18, 7219, {1, 3, 1, 11, 3, 47, 39, 33, 495, 137, 1591, 1335, 1347, 4527, 389, 43341, 80163, 5219}},
-{13851, 18, 7267, {1, 3, 3, 5, 19, 51, 121, 135, 93, 891, 13, 1339, 5187, 5005, 12823, 14465, 73845, 119685}},
-{13852, 18, 7358, {1, 3, 7, 7, 19, 1, 57, 193, 325, 49, 813, 5, 4431, 1119, 13625, 43613, 127989, 42669}},
-{13853, 18, 7383, {1, 3, 5, 15, 11, 33, 7, 45, 215, 469, 1059, 4095, 3549, 11839, 5463, 21383, 4831, 188345}},
-{13854, 18, 7387, {1, 1, 1, 13, 5, 61, 7, 161, 99, 623, 1589, 1045, 2385, 8899, 19327, 41373, 109241, 111895}},
-{13855, 18, 7396, {1, 1, 5, 7, 11, 39, 115, 41, 21, 491, 1221, 2805, 4311, 7137, 3151, 1387, 24633, 94679}},
-{13856, 18, 7408, {1, 1, 3, 7, 3, 39, 71, 175, 443, 187, 1727, 2535, 5099, 1881, 21639, 5717, 48589, 95037}},
-{13857, 18, 7432, {1, 1, 1, 11, 25, 21, 37, 227, 407, 73, 721, 3515, 381, 981, 21389, 5205, 31851, 140457}},
-{13858, 18, 7462, {1, 3, 3, 3, 27, 35, 13, 129, 457, 315, 253, 2545, 5469, 6695, 25223, 20115, 38039, 133655}},
-{13859, 18, 7480, {1, 1, 3, 11, 21, 47, 77, 231, 87, 245, 2039, 2515, 2873, 1711, 3361, 62123, 67117, 239047}},
-{13860, 18, 7488, {1, 1, 7, 7, 29, 21, 39, 175, 477, 813, 447, 1109, 7391, 14631, 4437, 42539, 13003, 75403}},
-{13861, 18, 7497, {1, 3, 1, 11, 11, 9, 119, 19, 99, 483, 61, 1883, 3415, 2137, 30415, 34519, 115191, 24437}},
-{13862, 18, 7531, {1, 1, 1, 9, 7, 47, 115, 233, 419, 427, 1605, 3821, 6243, 10861, 28495, 48265, 80811, 147701}},
-{13863, 18, 7561, {1, 3, 5, 5, 11, 61, 51, 155, 279, 463, 31, 1559, 2837, 8795, 4049, 13651, 109227, 52131}},
-{13864, 18, 7582, {1, 1, 7, 9, 25, 33, 97, 79, 477, 83, 923, 3293, 6381, 3063, 23293, 35381, 82867, 233189}},
-{13865, 18, 7591, {1, 1, 1, 9, 11, 39, 109, 189, 219, 1021, 137, 2041, 2719, 1763, 31787, 29377, 96287, 179685}},
-{13866, 18, 7612, {1, 3, 7, 5, 3, 15, 37, 179, 77, 751, 709, 893, 7705, 1563, 7843, 29843, 1107, 35919}},
-{13867, 18, 7677, {1, 3, 3, 3, 29, 17, 123, 201, 275, 487, 1979, 1361, 7523, 13783, 10129, 16877, 127049, 163221}},
-{13868, 18, 7687, {1, 1, 1, 9, 27, 35, 69, 167, 509, 133, 1073, 3773, 265, 8455, 12341, 127, 115075, 94537}},
-{13869, 18, 7701, {1, 3, 7, 9, 13, 35, 57, 83, 123, 211, 739, 253, 3907, 5405, 3229, 46837, 77483, 5915}},
-{13870, 18, 7705, {1, 1, 7, 3, 7, 27, 71, 235, 133, 803, 611, 529, 4449, 16113, 8151, 36519, 34561, 36361}},
-{13871, 18, 7712, {1, 1, 3, 1, 31, 9, 123, 85, 407, 415, 353, 3239, 673, 4641, 25883, 61117, 7669, 240851}},
-{13872, 18, 7721, {1, 1, 5, 11, 29, 9, 49, 31, 3, 249, 1769, 3325, 503, 1397, 30677, 22515, 81279, 90309}},
-{13873, 18, 7736, {1, 3, 5, 3, 15, 63, 121, 253, 421, 279, 497, 3881, 6977, 11061, 5883, 38347, 8351, 118123}},
-{13874, 18, 7756, {1, 1, 1, 13, 1, 27, 3, 91, 281, 563, 1283, 1893, 7593, 12171, 27041, 7769, 95691, 13791}},
-{13875, 18, 7777, {1, 1, 3, 3, 29, 59, 87, 153, 337, 819, 787, 2631, 1889, 13869, 29237, 57097, 91621, 4011}},
-{13876, 18, 7783, {1, 1, 1, 15, 7, 49, 1, 83, 299, 353, 131, 1635, 3723, 16209, 1061, 50669, 68083, 133443}},
-{13877, 18, 7792, {1, 3, 5, 5, 27, 17, 5, 239, 285, 831, 1487, 721, 4891, 4265, 23753, 43921, 116709, 105027}},
-{13878, 18, 7797, {1, 1, 7, 7, 5, 35, 63, 97, 215, 447, 353, 495, 8119, 12537, 9679, 58641, 65057, 21999}},
-{13879, 18, 7802, {1, 3, 7, 5, 23, 43, 69, 115, 59, 603, 493, 1665, 5003, 13607, 28491, 4439, 11855, 228183}},
-{13880, 18, 7808, {1, 3, 3, 3, 15, 35, 19, 63, 241, 357, 979, 2891, 3105, 14085, 10539, 62335, 130903, 163153}},
-{13881, 18, 7866, {1, 3, 5, 3, 23, 51, 23, 193, 129, 171, 1913, 1025, 6397, 15657, 19611, 57455, 87531, 51039}},
-{13882, 18, 7885, {1, 1, 3, 9, 1, 9, 7, 239, 87, 527, 1401, 2703, 4021, 3845, 29269, 48217, 61091, 131949}},
-{13883, 18, 7891, {1, 3, 1, 5, 17, 45, 59, 223, 287, 295, 1959, 3985, 3671, 14605, 18949, 34147, 51251, 10271}},
-{13884, 18, 7913, {1, 3, 5, 9, 5, 49, 63, 105, 43, 157, 1827, 495, 5823, 6323, 6601, 51379, 64411, 204103}},
-{13885, 18, 7936, {1, 1, 7, 1, 11, 31, 117, 9, 13, 965, 177, 1247, 2487, 9849, 20367, 49287, 2193, 235689}},
-{13886, 18, 7946, {1, 1, 3, 11, 19, 31, 23, 215, 489, 657, 801, 3937, 379, 12083, 14969, 37857, 39027, 63985}},
-{13887, 18, 7963, {1, 1, 5, 1, 9, 59, 53, 187, 341, 65, 1251, 767, 4897, 13263, 17439, 26625, 122107, 163653}},
-{13888, 18, 7996, {1, 1, 3, 13, 31, 41, 125, 253, 481, 107, 233, 2305, 3321, 7303, 28585, 12787, 83307, 31497}},
-{13889, 18, 7999, {1, 1, 3, 13, 25, 41, 55, 83, 101, 115, 549, 531, 3085, 9497, 27989, 28257, 121075, 189671}},
-{13890, 18, 8011, {1, 3, 5, 11, 13, 53, 121, 85, 355, 275, 1925, 2117, 1349, 5903, 2041, 20963, 60803, 1121}},
-{13891, 18, 8014, {1, 1, 5, 5, 13, 7, 125, 63, 311, 187, 1127, 643, 6137, 845, 23945, 9403, 451, 53027}},
-{13892, 18, 8028, {1, 1, 3, 7, 19, 31, 27, 239, 337, 61, 641, 1693, 7289, 5675, 30067, 41091, 124607, 36971}},
-{13893, 18, 8047, {1, 3, 1, 13, 25, 61, 11, 81, 165, 129, 241, 711, 5193, 13017, 30821, 35239, 110809, 60909}},
-{13894, 18, 8077, {1, 3, 3, 13, 15, 13, 71, 19, 87, 499, 1395, 1191, 1445, 2687, 4691, 16773, 114269, 186237}},
-{13895, 18, 8101, {1, 3, 3, 15, 1, 49, 33, 109, 241, 5, 431, 461, 3865, 14029, 9827, 54455, 52159, 211585}},
-{13896, 18, 8119, {1, 3, 5, 7, 31, 27, 115, 113, 367, 591, 873, 1447, 6819, 7011, 14095, 55243, 4039, 226985}},
-{13897, 18, 8125, {1, 1, 7, 3, 1, 19, 69, 239, 417, 833, 1867, 3111, 2617, 12781, 5531, 17345, 75717, 139667}},
-{13898, 18, 8140, {1, 1, 5, 11, 11, 63, 23, 141, 221, 897, 1269, 2185, 6057, 8865, 20449, 58255, 27073, 158305}},
-{13899, 18, 8152, {1, 3, 3, 5, 23, 23, 121, 39, 457, 935, 691, 2329, 7055, 2821, 12669, 28713, 82321, 245783}},
-{13900, 18, 8209, {1, 1, 1, 9, 27, 9, 35, 23, 139, 823, 703, 917, 1281, 12155, 11681, 26083, 119445, 181489}},
-{13901, 18, 8212, {1, 1, 3, 7, 27, 21, 35, 243, 17, 633, 1665, 3419, 6301, 16099, 17477, 24983, 128455, 127501}},
-{13902, 18, 8231, {1, 3, 1, 1, 17, 19, 59, 165, 487, 985, 597, 689, 7103, 14475, 6985, 29755, 115977, 105943}},
-{13903, 18, 8258, {1, 1, 5, 5, 23, 41, 67, 175, 3, 571, 1501, 3315, 6111, 1847, 28975, 54117, 66605, 69997}},
-{13904, 18, 8275, {1, 3, 5, 5, 13, 37, 113, 75, 383, 297, 1187, 2055, 3433, 14651, 30393, 29647, 126403, 32265}},
-{13905, 18, 8303, {1, 1, 3, 5, 31, 29, 25, 169, 465, 219, 81, 2019, 4255, 6003, 7425, 53269, 31105, 211937}},
-{13906, 18, 8308, {1, 3, 7, 11, 13, 7, 11, 195, 327, 883, 1295, 3721, 1197, 7585, 5693, 993, 125017, 12007}},
-{13907, 18, 8312, {1, 3, 3, 7, 5, 37, 71, 37, 63, 651, 669, 3445, 3959, 249, 10599, 22329, 107701, 107729}},
-{13908, 18, 8345, {1, 1, 1, 9, 7, 47, 21, 181, 395, 345, 757, 481, 2759, 8157, 19847, 55743, 63137, 224765}},
-{13909, 18, 8346, {1, 3, 5, 9, 29, 3, 61, 35, 271, 157, 549, 843, 2907, 91, 16325, 4241, 94495, 78861}},
-{13910, 18, 8370, {1, 3, 1, 9, 17, 11, 53, 243, 49, 911, 1193, 793, 901, 3727, 21849, 33987, 565, 154171}},
-{13911, 18, 8402, {1, 1, 5, 1, 9, 5, 89, 81, 65, 111, 781, 3775, 591, 4987, 29833, 58159, 7253, 206447}},
-{13912, 18, 8411, {1, 3, 1, 7, 3, 59, 77, 83, 173, 545, 103, 2541, 8095, 10797, 11111, 62351, 88827, 55081}},
-{13913, 18, 8414, {1, 1, 3, 11, 29, 37, 19, 47, 145, 19, 513, 3269, 2205, 5317, 19207, 38051, 5413, 78089}},
-{13914, 18, 8424, {1, 1, 5, 9, 21, 57, 75, 249, 21, 879, 1377, 3407, 6123, 11917, 12493, 44873, 113539, 114717}},
-{13915, 18, 8435, {1, 3, 3, 9, 7, 55, 121, 57, 491, 39, 1561, 2625, 639, 13553, 1159, 43071, 68869, 248837}},
-{13916, 18, 8452, {1, 1, 1, 11, 25, 19, 107, 239, 171, 1001, 69, 4095, 49, 9569, 22613, 59865, 54959, 70031}},
-{13917, 18, 8462, {1, 1, 3, 13, 27, 15, 105, 205, 205, 581, 1965, 1535, 6531, 15935, 7623, 33695, 9317, 44257}},
-{13918, 18, 8479, {1, 1, 1, 3, 3, 51, 115, 185, 315, 763, 211, 339, 7083, 4895, 23277, 14165, 101731, 218903}},
-{13919, 18, 8509, {1, 1, 3, 13, 29, 1, 69, 55, 423, 781, 183, 1417, 151, 14507, 5217, 27757, 52447, 145913}},
-{13920, 18, 8515, {1, 3, 1, 11, 29, 39, 29, 151, 85, 387, 885, 507, 133, 9819, 12627, 30951, 79839, 206267}},
-{13921, 18, 8522, {1, 3, 3, 7, 1, 53, 99, 141, 91, 51, 143, 1751, 3989, 6811, 7339, 52141, 43473, 18615}},
-{13922, 18, 8541, {1, 3, 3, 15, 27, 11, 29, 37, 387, 655, 2019, 1135, 3619, 12995, 12755, 26063, 109419, 103875}},
-{13923, 18, 8560, {1, 3, 3, 13, 31, 15, 93, 231, 195, 261, 1055, 2363, 1123, 3927, 6907, 365, 27043, 157049}},
-{13924, 18, 8563, {1, 1, 1, 15, 7, 29, 105, 199, 507, 437, 117, 2963, 7801, 6291, 19261, 30377, 92205, 20723}},
-{13925, 18, 8585, {1, 1, 1, 9, 29, 19, 75, 189, 3, 387, 1491, 2291, 7739, 12993, 11835, 10873, 54583, 207963}},
-{13926, 18, 8594, {1, 3, 7, 3, 23, 11, 25, 105, 57, 713, 1291, 3293, 4693, 13859, 27541, 31529, 65929, 245143}},
-{13927, 18, 8596, {1, 1, 7, 7, 19, 13, 19, 189, 253, 337, 351, 1751, 6173, 12207, 24483, 31381, 82035, 157143}},
-{13928, 18, 8603, {1, 3, 3, 11, 11, 49, 117, 177, 301, 417, 855, 2433, 5619, 7339, 30361, 29251, 20411, 184981}},
-{13929, 18, 8610, {1, 1, 1, 1, 11, 55, 77, 99, 209, 781, 1193, 2841, 783, 1485, 19413, 52255, 19529, 253927}},
-{13930, 18, 8647, {1, 3, 1, 3, 15, 49, 85, 191, 389, 411, 479, 341, 4985, 6193, 19099, 11497, 103285, 162333}},
-{13931, 18, 8661, {1, 3, 1, 3, 11, 31, 71, 91, 357, 615, 2007, 3601, 5393, 8079, 16811, 54127, 26049, 116341}},
-{13932, 18, 8662, {1, 1, 3, 15, 9, 39, 121, 53, 43, 617, 905, 3629, 6327, 13453, 1435, 24113, 7523, 228523}},
-{13933, 18, 8672, {1, 3, 5, 11, 21, 51, 11, 125, 33, 935, 1069, 2807, 4951, 13261, 17611, 38779, 62203, 135759}},
-{13934, 18, 8690, {1, 1, 1, 13, 29, 59, 53, 245, 219, 423, 809, 1109, 7255, 14679, 25247, 43235, 129565, 72649}},
-{13935, 18, 8696, {1, 3, 5, 7, 27, 29, 119, 91, 297, 407, 187, 2829, 5637, 13851, 14073, 461, 64081, 33971}},
-{13936, 18, 8739, {1, 1, 5, 11, 15, 27, 29, 233, 487, 859, 1021, 3117, 1439, 16021, 31315, 35775, 117363, 131635}},
-{13937, 18, 8783, {1, 1, 5, 3, 3, 1, 91, 229, 327, 777, 393, 3853, 3455, 1785, 13749, 25173, 51575, 167237}},
-{13938, 18, 8811, {1, 3, 7, 9, 27, 7, 15, 71, 283, 71, 1783, 1357, 5581, 3143, 26075, 47751, 71001, 157107}},
-{13939, 18, 8813, {1, 3, 3, 7, 23, 9, 69, 21, 333, 223, 1735, 1057, 8091, 1927, 8507, 40901, 40233, 164115}},
-{13940, 18, 8821, {1, 3, 7, 3, 11, 49, 29, 81, 215, 289, 1137, 765, 6385, 5935, 3435, 11991, 30867, 60745}},
-{13941, 18, 8856, {1, 1, 1, 1, 7, 39, 33, 173, 225, 533, 1927, 3607, 1059, 8779, 2649, 6801, 103963, 167471}},
-{13942, 18, 8877, {1, 3, 3, 15, 27, 51, 107, 3, 195, 87, 739, 1425, 747, 1501, 22245, 59233, 124867, 79753}},
-{13943, 18, 8885, {1, 1, 3, 3, 13, 41, 125, 101, 225, 749, 221, 2735, 6441, 11353, 3943, 35329, 53437, 149063}},
-{13944, 18, 8897, {1, 3, 3, 15, 3, 53, 75, 77, 1, 907, 573, 1909, 363, 6913, 559, 58489, 1053, 25513}},
-{13945, 18, 8898, {1, 1, 7, 11, 7, 15, 91, 155, 447, 555, 473, 3625, 7529, 16307, 32241, 64077, 46943, 85717}},
-{13946, 18, 8934, {1, 1, 1, 13, 9, 61, 91, 41, 101, 107, 1081, 2511, 2881, 14095, 3861, 22771, 32687, 77287}},
-{13947, 18, 8955, {1, 3, 3, 7, 21, 3, 51, 177, 203, 861, 1507, 1177, 2369, 11735, 1667, 28607, 97671, 123263}},
-{13948, 18, 8972, {1, 1, 1, 3, 5, 57, 13, 127, 353, 65, 663, 3849, 3579, 5521, 11765, 63427, 76349, 102517}},
-{13949, 18, 8977, {1, 1, 7, 11, 27, 55, 79, 249, 397, 77, 1543, 3787, 4889, 11145, 18691, 62899, 66425, 116195}},
-{13950, 18, 9038, {1, 1, 1, 3, 5, 3, 1, 143, 73, 999, 2013, 2001, 4001, 6563, 30811, 61445, 2645, 203631}},
-{13951, 18, 9045, {1, 1, 1, 15, 1, 49, 35, 61, 493, 101, 1407, 2211, 7467, 12321, 15901, 15479, 62939, 14643}},
-{13952, 18, 9071, {1, 1, 3, 11, 21, 33, 123, 95, 449, 355, 1501, 1627, 1411, 6183, 17457, 2199, 96313, 25023}},
-{13953, 18, 9085, {1, 1, 5, 5, 13, 49, 73, 203, 83, 3, 137, 119, 3001, 10685, 18231, 60727, 31785, 158605}},
-{13954, 18, 9110, {1, 3, 1, 11, 23, 19, 123, 9, 269, 501, 2005, 3695, 3327, 5353, 12619, 12987, 18213, 29355}},
-{13955, 18, 9120, {1, 3, 1, 5, 1, 25, 99, 197, 327, 575, 773, 2009, 6653, 1807, 20381, 55725, 124359, 176893}},
-{13956, 18, 9157, {1, 1, 7, 15, 27, 9, 81, 175, 73, 727, 1907, 1237, 4983, 16123, 16479, 2283, 57805, 13593}},
-{13957, 18, 9164, {1, 1, 3, 13, 7, 13, 13, 139, 283, 721, 487, 1821, 4257, 5105, 8057, 27193, 46857, 169927}},
-{13958, 18, 9185, {1, 1, 5, 5, 29, 5, 81, 211, 441, 685, 981, 3097, 6253, 10673, 12253, 54943, 69401, 147769}},
-{13959, 18, 9203, {1, 3, 3, 1, 13, 35, 73, 145, 139, 781, 37, 803, 3607, 4327, 1153, 11325, 131025, 168729}},
-{13960, 18, 9235, {1, 3, 1, 13, 17, 41, 19, 59, 23, 561, 315, 719, 3325, 275, 12715, 59843, 16597, 81691}},
-{13961, 18, 9278, {1, 3, 1, 11, 1, 53, 11, 237, 363, 345, 331, 129, 6885, 3105, 12487, 53803, 8897, 193777}},
-{13962, 18, 9290, {1, 3, 7, 15, 3, 53, 55, 101, 389, 839, 413, 2851, 3989, 12857, 25723, 16595, 94145, 193049}},
-{13963, 18, 9292, {1, 3, 1, 7, 15, 31, 3, 115, 197, 753, 1035, 1369, 4925, 4497, 1641, 63743, 127089, 114097}},
-{13964, 18, 9319, {1, 3, 5, 5, 23, 1, 35, 99, 277, 769, 895, 581, 6969, 15339, 10309, 27101, 22611, 86179}},
-{13965, 18, 9334, {1, 1, 1, 11, 19, 17, 45, 35, 257, 313, 815, 1469, 3651, 15101, 22775, 51729, 75401, 123653}},
-{13966, 18, 9362, {1, 3, 1, 15, 5, 11, 83, 141, 373, 935, 1123, 1849, 1267, 15427, 10615, 63303, 109771, 188601}},
-{13967, 18, 9387, {1, 3, 5, 3, 29, 23, 79, 193, 261, 29, 1857, 789, 4359, 14211, 22181, 64901, 129089, 65587}},
-{13968, 18, 9404, {1, 3, 1, 3, 29, 15, 19, 239, 497, 771, 239, 2853, 2391, 8153, 31899, 53759, 127219, 78833}},
-{13969, 18, 9407, {1, 1, 7, 7, 5, 57, 9, 93, 69, 993, 193, 3629, 5761, 9339, 28073, 50035, 81635, 83119}},
-{13970, 18, 9410, {1, 1, 5, 13, 7, 35, 79, 247, 43, 1011, 1189, 2881, 1963, 8889, 9929, 50043, 112581, 224139}},
-{13971, 18, 9422, {1, 3, 3, 7, 15, 63, 85, 33, 107, 37, 45, 1271, 4735, 1151, 19793, 6589, 50875, 185061}},
-{13972, 18, 9478, {1, 3, 1, 15, 1, 63, 1, 201, 207, 179, 67, 3703, 2629, 10517, 1, 39645, 119733, 6449}},
-{13973, 18, 9512, {1, 3, 5, 1, 3, 7, 97, 101, 233, 71, 255, 3767, 8127, 8041, 25001, 7601, 129595, 131657}},
-{13974, 18, 9535, {1, 1, 7, 1, 25, 29, 105, 25, 267, 191, 267, 3141, 4445, 5043, 25203, 32055, 11035, 229031}},
-{13975, 18, 9604, {1, 1, 1, 13, 3, 1, 1, 147, 63, 259, 1171, 401, 6289, 13577, 28129, 1349, 85027, 178123}},
-{13976, 18, 9616, {1, 1, 1, 13, 1, 59, 109, 95, 49, 309, 1141, 1355, 3415, 11237, 21619, 12039, 1795, 57775}},
-{13977, 18, 9622, {1, 3, 1, 11, 19, 3, 51, 227, 277, 49, 703, 2701, 515, 8893, 20163, 65297, 114781, 225687}},
-{13978, 18, 9631, {1, 3, 7, 11, 19, 47, 121, 199, 173, 905, 1903, 1781, 2425, 13381, 25843, 23279, 87701, 10723}},
-{13979, 18, 9656, {1, 3, 1, 13, 7, 21, 17, 15, 85, 241, 119, 2361, 7921, 6077, 955, 34221, 78179, 35511}},
-{13980, 18, 9710, {1, 1, 7, 11, 9, 1, 1, 29, 445, 557, 241, 959, 6077, 3547, 30987, 48129, 79699, 236611}},
-{13981, 18, 9721, {1, 3, 1, 15, 13, 29, 57, 117, 347, 719, 1435, 307, 5209, 4009, 10517, 3373, 67667, 260101}},
-{13982, 18, 9728, {1, 1, 7, 13, 11, 41, 17, 143, 467, 993, 779, 3991, 623, 8915, 21615, 56477, 59721, 164241}},
-{13983, 18, 9733, {1, 1, 3, 7, 15, 37, 53, 33, 395, 547, 1815, 2517, 6575, 14035, 1, 10919, 25467, 117521}},
-{13984, 18, 9738, {1, 1, 3, 9, 17, 47, 45, 3, 509, 53, 1245, 883, 7917, 15445, 4169, 49637, 90933, 109469}},
-{13985, 18, 9774, {1, 3, 1, 3, 27, 37, 3, 95, 31, 665, 701, 1979, 3735, 3257, 18943, 41201, 95721, 69451}},
-{13986, 18, 9791, {1, 1, 1, 15, 19, 49, 61, 5, 115, 801, 805, 2723, 1387, 13165, 20717, 40767, 88857, 28207}},
-{13987, 18, 9803, {1, 1, 5, 9, 21, 25, 23, 179, 59, 29, 547, 1829, 4411, 6689, 22363, 43975, 52259, 187563}},
-{13988, 18, 9805, {1, 1, 5, 11, 13, 31, 97, 131, 135, 415, 53, 4015, 3629, 6613, 25541, 47221, 66483, 224545}},
-{13989, 18, 9817, {1, 3, 1, 11, 19, 13, 65, 95, 381, 759, 1319, 2997, 6321, 9203, 24483, 9925, 10799, 117119}},
-{13990, 18, 9823, {1, 3, 5, 13, 27, 17, 39, 225, 199, 125, 1125, 2673, 6787, 8861, 13139, 13849, 65459, 40183}},
-{13991, 18, 9839, {1, 1, 5, 3, 17, 55, 23, 75, 457, 959, 1507, 1267, 6857, 16141, 1889, 10779, 41331, 166075}},
-{13992, 18, 9847, {1, 3, 1, 15, 7, 55, 109, 59, 241, 431, 1281, 183, 1029, 14617, 4003, 41871, 36007, 129617}},
-{13993, 18, 9854, {1, 3, 1, 1, 27, 61, 79, 93, 217, 251, 671, 989, 7031, 10035, 15455, 13685, 95471, 997}},
-{13994, 18, 9863, {1, 1, 3, 13, 1, 5, 125, 179, 357, 537, 1303, 2653, 7319, 2075, 3861, 11743, 89659, 221705}},
-{13995, 18, 9872, {1, 1, 1, 7, 3, 55, 5, 201, 153, 639, 835, 1913, 3331, 10727, 30365, 15133, 67911, 17851}},
-{13996, 18, 9884, {1, 1, 3, 13, 21, 1, 67, 71, 265, 43, 279, 2009, 873, 4447, 32001, 50783, 76613, 63919}},
-{13997, 18, 9935, {1, 1, 3, 11, 17, 43, 19, 195, 233, 17, 1855, 1227, 3435, 4313, 6417, 51019, 130091, 124947}},
-{13998, 18, 9937, {1, 1, 7, 9, 19, 9, 95, 87, 297, 817, 1217, 3637, 2371, 7073, 387, 62121, 43507, 93927}},
-{13999, 18, 9974, {1, 3, 5, 13, 1, 15, 29, 123, 137, 425, 531, 2659, 2077, 1345, 2803, 49469, 29031, 170825}},
-{14000, 18, 9980, {1, 1, 5, 7, 15, 13, 119, 231, 139, 673, 1105, 2355, 3023, 4437, 17491, 47367, 12751, 183319}},
-{14001, 18, 10003, {1, 1, 5, 15, 19, 5, 125, 121, 509, 539, 473, 2087, 4421, 4205, 23457, 34481, 111231, 145035}},
-{14002, 18, 10015, {1, 3, 7, 5, 23, 21, 85, 23, 415, 715, 1579, 3447, 2373, 233, 19401, 54869, 15977, 138119}},
-{14003, 18, 10016, {1, 1, 3, 11, 21, 1, 37, 127, 101, 943, 79, 2119, 5679, 10749, 16209, 16715, 29421, 259735}},
-{14004, 18, 10066, {1, 3, 7, 7, 23, 25, 1, 73, 505, 979, 535, 87, 4165, 9353, 20075, 57597, 74651, 22133}},
-{14005, 18, 10093, {1, 1, 7, 3, 11, 19, 75, 213, 293, 15, 1981, 1259, 5455, 2897, 18861, 6317, 10339, 123967}},
-{14006, 18, 10118, {1, 3, 1, 3, 29, 5, 93, 169, 51, 519, 1649, 2789, 1251, 8359, 11489, 62443, 91549, 148357}},
-{14007, 18, 10132, {1, 3, 3, 13, 5, 47, 39, 163, 341, 755, 737, 2335, 2389, 8351, 26193, 58111, 18425, 129313}},
-{14008, 18, 10135, {1, 1, 3, 1, 31, 49, 101, 69, 345, 291, 1257, 1801, 1613, 1479, 4403, 21307, 44947, 68591}},
-{14009, 18, 10151, {1, 3, 3, 9, 5, 23, 65, 65, 187, 709, 883, 2199, 1037, 8679, 31527, 23561, 92225, 254215}},
-{14010, 18, 10158, {1, 3, 7, 7, 23, 13, 87, 209, 163, 705, 1199, 3007, 5469, 2453, 2691, 17841, 97045, 174149}},
-{14011, 18, 10169, {1, 1, 1, 9, 5, 35, 21, 91, 145, 559, 131, 3911, 1777, 8225, 6077, 58223, 100827, 3641}},
-{14012, 18, 10172, {1, 1, 5, 5, 7, 5, 31, 189, 117, 785, 1493, 3899, 471, 10971, 4607, 21063, 67225, 195367}},
-{14013, 18, 10180, {1, 1, 7, 5, 31, 61, 63, 163, 417, 655, 2033, 1255, 1139, 6867, 28655, 55295, 100519, 166629}},
-{14014, 18, 10187, {1, 3, 3, 3, 7, 35, 83, 55, 7, 607, 253, 915, 6801, 7505, 15929, 16829, 78469, 150947}},
-{14015, 18, 10189, {1, 3, 3, 9, 29, 3, 127, 235, 347, 3, 193, 1547, 8073, 14963, 20351, 28951, 53855, 261375}},
-{14016, 18, 10192, {1, 1, 7, 3, 31, 19, 75, 87, 23, 419, 75, 1677, 2371, 8875, 31993, 4465, 76085, 86499}},
-{14017, 18, 10197, {1, 3, 5, 7, 1, 51, 47, 161, 415, 521, 1099, 1295, 2545, 15167, 13983, 7347, 60631, 4089}},
-{14018, 18, 10211, {1, 1, 1, 9, 7, 59, 71, 187, 441, 273, 769, 2649, 3261, 12661, 23045, 32035, 104573, 120589}},
-{14019, 18, 10214, {1, 3, 7, 13, 23, 51, 113, 205, 443, 291, 475, 2961, 7615, 105, 22099, 6045, 22667, 65515}},
-{14020, 18, 10256, {1, 1, 5, 11, 1, 1, 23, 231, 413, 371, 1285, 2695, 2751, 4235, 15779, 1903, 24469, 259157}},
-{14021, 18, 10278, {1, 3, 3, 7, 7, 47, 87, 105, 311, 251, 573, 3221, 5757, 11107, 11161, 8809, 14467, 33153}},
-{14022, 18, 10290, {1, 1, 7, 1, 31, 49, 51, 31, 305, 315, 547, 1159, 2741, 3773, 13299, 40115, 62523, 108487}},
-{14023, 18, 10301, {1, 3, 1, 11, 11, 43, 33, 213, 107, 467, 1509, 4081, 4723, 2409, 1447, 42759, 64717, 161991}},
-{14024, 18, 10310, {1, 3, 7, 3, 31, 23, 25, 159, 95, 721, 1981, 3659, 4819, 10119, 25451, 10165, 31281, 238319}},
-{14025, 18, 10344, {1, 3, 1, 5, 19, 27, 67, 125, 481, 585, 43, 3697, 4997, 581, 6439, 33477, 115023, 51759}},
-{14026, 18, 10473, {1, 3, 7, 7, 15, 53, 89, 173, 369, 365, 91, 1583, 4611, 7189, 30383, 47397, 73657, 158695}},
-{14027, 18, 10474, {1, 1, 1, 15, 1, 21, 125, 13, 243, 729, 1397, 2451, 3233, 15593, 2815, 56215, 22685, 167343}},
-{14028, 18, 10482, {1, 3, 1, 13, 13, 29, 119, 223, 51, 695, 273, 2381, 4431, 4891, 29875, 49511, 111003, 174413}},
-{14029, 18, 10499, {1, 3, 3, 15, 9, 13, 19, 177, 371, 957, 255, 115, 4701, 6089, 7237, 17077, 87949, 3111}},
-{14030, 18, 10525, {1, 1, 7, 11, 29, 49, 59, 201, 145, 219, 1159, 3863, 715, 10489, 25883, 56445, 122103, 149877}},
-{14031, 18, 10532, {1, 3, 1, 13, 15, 51, 91, 109, 433, 45, 2045, 3121, 1109, 14713, 2667, 40463, 52185, 64743}},
-{14032, 18, 10535, {1, 3, 3, 7, 21, 31, 7, 155, 347, 305, 1557, 1311, 3315, 1363, 403, 62063, 114195, 44623}},
-{14033, 18, 10556, {1, 3, 5, 11, 9, 11, 11, 245, 49, 21, 239, 3043, 3525, 1055, 21891, 19153, 123689, 170195}},
-{14034, 18, 10568, {1, 1, 1, 11, 17, 51, 83, 249, 483, 489, 1063, 469, 6153, 15551, 13783, 27945, 103775, 68175}},
-{14035, 18, 10579, {1, 3, 3, 13, 11, 61, 107, 113, 503, 819, 1593, 2851, 6711, 14623, 3709, 10931, 8743, 62321}},
-{14036, 18, 10586, {1, 1, 5, 15, 5, 37, 23, 131, 329, 499, 1765, 1273, 819, 11573, 3307, 46933, 22087, 173459}},
-{14037, 18, 10609, {1, 1, 1, 3, 31, 5, 49, 57, 239, 981, 1863, 3233, 2727, 7389, 7923, 63259, 62873, 113607}},
-{14038, 18, 10612, {1, 1, 7, 7, 11, 27, 119, 137, 115, 211, 1239, 2153, 2579, 11501, 747, 31141, 129793, 151589}},
-{14039, 18, 10650, {1, 3, 3, 9, 9, 55, 121, 199, 91, 835, 521, 2433, 8123, 2045, 32553, 48993, 9935, 220537}},
-{14040, 18, 10665, {1, 3, 7, 11, 15, 57, 53, 145, 299, 623, 691, 1557, 785, 15851, 27075, 5983, 18043, 22241}},
-{14041, 18, 10685, {1, 1, 3, 1, 1, 57, 57, 195, 381, 913, 167, 333, 5541, 2323, 17001, 34817, 30795, 144051}},
-{14042, 18, 10686, {1, 3, 3, 3, 31, 1, 83, 31, 91, 855, 195, 3449, 8057, 11061, 29089, 1597, 127581, 189033}},
-{14043, 18, 10688, {1, 3, 1, 1, 21, 59, 113, 179, 13, 523, 629, 3693, 7155, 893, 17449, 46535, 18051, 9191}},
-{14044, 18, 10711, {1, 1, 1, 3, 27, 19, 75, 229, 181, 653, 1849, 501, 5871, 14769, 27461, 59193, 115013, 72227}},
-{14045, 18, 10728, {1, 3, 3, 13, 17, 41, 111, 107, 453, 299, 1699, 2871, 2955, 4215, 13919, 19785, 30339, 148445}},
-{14046, 18, 10748, {1, 3, 3, 11, 5, 19, 21, 87, 173, 439, 1651, 2393, 4137, 16285, 16093, 22953, 105663, 226575}},
-{14047, 18, 10751, {1, 3, 5, 7, 19, 61, 101, 251, 295, 89, 1695, 1359, 5797, 8587, 18753, 65223, 51079, 96169}},
-{14048, 18, 10781, {1, 1, 1, 5, 3, 1, 79, 63, 221, 601, 1385, 1963, 4601, 15217, 4861, 58295, 61043, 88523}},
-{14049, 18, 10805, {1, 3, 3, 7, 31, 63, 73, 177, 455, 487, 1009, 2103, 4753, 3143, 10121, 36509, 24753, 230869}},
-{14050, 18, 10823, {1, 1, 5, 1, 17, 27, 103, 63, 475, 665, 1189, 3513, 89, 2669, 1227, 20635, 121549, 248851}},
-{14051, 18, 10838, {1, 1, 3, 7, 25, 19, 117, 243, 337, 207, 903, 3751, 3309, 11955, 12651, 25359, 83419, 19701}},
-{14052, 18, 10857, {1, 1, 7, 15, 19, 21, 3, 235, 289, 185, 1175, 2291, 4003, 7753, 4775, 65321, 48957, 220261}},
-{14053, 18, 10865, {1, 3, 5, 11, 23, 21, 107, 65, 117, 329, 1085, 3555, 1183, 15241, 32663, 50985, 66753, 38023}},
-{14054, 18, 10872, {1, 1, 7, 9, 11, 49, 65, 17, 291, 435, 1221, 3829, 5467, 5181, 19891, 7091, 80673, 90495}},
-{14055, 18, 10893, {1, 1, 1, 15, 17, 47, 119, 173, 297, 477, 859, 3661, 8081, 8257, 20841, 55123, 11231, 193669}},
-{14056, 18, 10899, {1, 1, 7, 7, 27, 11, 119, 109, 199, 727, 1569, 3749, 4067, 11675, 30213, 58091, 64303, 92785}},
-{14057, 18, 10917, {1, 3, 7, 15, 15, 39, 101, 149, 299, 449, 1017, 723, 7731, 7929, 22465, 61583, 69851, 150507}},
-{14058, 18, 10935, {1, 3, 5, 15, 5, 13, 97, 127, 21, 673, 353, 3885, 5761, 11443, 10089, 23701, 85879, 42217}},
-{14059, 18, 11001, {1, 3, 1, 5, 27, 55, 31, 167, 69, 453, 925, 555, 5135, 2759, 27077, 14497, 94333, 108729}},
-{14060, 18, 11072, {1, 1, 7, 15, 11, 55, 9, 241, 55, 611, 149, 2605, 653, 1631, 15059, 6349, 12321, 124561}},
-{14061, 18, 11089, {1, 1, 1, 9, 3, 11, 95, 67, 443, 103, 1687, 2667, 4567, 4271, 15601, 27859, 4757, 53289}},
-{14062, 18, 11090, {1, 1, 5, 9, 23, 21, 1, 125, 105, 975, 1879, 1821, 5273, 7079, 25009, 10471, 29119, 73249}},
-{14063, 18, 11108, {1, 1, 7, 1, 31, 61, 17, 23, 485, 565, 1325, 1559, 4131, 751, 2071, 4719, 15925, 101207}},
-{14064, 18, 11117, {1, 1, 5, 5, 13, 53, 13, 93, 149, 139, 1429, 3605, 3545, 11193, 14139, 6093, 115727, 183105}},
-{14065, 18, 11136, {1, 1, 1, 7, 15, 37, 51, 77, 177, 967, 405, 563, 3047, 8499, 26787, 27609, 23613, 239679}},
-{14066, 18, 11148, {1, 1, 1, 5, 27, 37, 1, 129, 197, 133, 1329, 3673, 3143, 1059, 19209, 39027, 43787, 42821}},
-{14067, 18, 11153, {1, 3, 7, 5, 5, 47, 105, 121, 219, 777, 1569, 1359, 1955, 13207, 14895, 7829, 40499, 182911}},
-{14068, 18, 11181, {1, 3, 5, 7, 11, 41, 41, 155, 245, 383, 405, 2415, 5809, 5117, 31523, 16927, 76785, 113731}},
-{14069, 18, 11190, {1, 3, 3, 9, 9, 21, 13, 197, 409, 931, 305, 1129, 865, 12961, 5239, 35823, 82565, 226765}},
-{14070, 18, 11201, {1, 1, 5, 3, 17, 27, 59, 79, 359, 601, 979, 1355, 1657, 10479, 4741, 36391, 111527, 105139}},
-{14071, 18, 11204, {1, 3, 5, 9, 13, 43, 31, 1, 309, 723, 1049, 803, 1653, 2551, 26317, 49731, 67799, 129225}},
-{14072, 18, 11216, {1, 1, 5, 3, 1, 39, 95, 243, 499, 809, 1515, 981, 585, 7907, 16801, 43381, 117537, 99787}},
-{14073, 18, 11237, {1, 1, 5, 5, 25, 23, 15, 127, 33, 799, 647, 2923, 7805, 2681, 14773, 42751, 106861, 119657}},
-{14074, 18, 11259, {1, 3, 1, 1, 1, 47, 11, 179, 179, 659, 1061, 2511, 3601, 7107, 27887, 48427, 40559, 106043}},
-{14075, 18, 11279, {1, 1, 7, 11, 5, 33, 115, 195, 431, 383, 1571, 3485, 5741, 5775, 14891, 26389, 71723, 198861}},
-{14076, 18, 11282, {1, 1, 5, 5, 11, 55, 37, 57, 381, 607, 2017, 1981, 6113, 3771, 8827, 13335, 88587, 102791}},
-{14077, 18, 11304, {1, 1, 1, 11, 29, 23, 73, 149, 405, 581, 721, 281, 5315, 4675, 13013, 39003, 20335, 109855}},
-{14078, 18, 11312, {1, 1, 7, 15, 17, 57, 39, 51, 403, 979, 1543, 1235, 797, 5949, 26647, 15125, 33255, 152861}},
-{14079, 18, 11332, {1, 1, 5, 3, 25, 27, 7, 147, 257, 163, 1297, 2289, 693, 7771, 6341, 22323, 1653, 177669}},
-{14080, 18, 11341, {1, 1, 3, 9, 1, 39, 47, 231, 15, 705, 897, 3943, 6281, 6679, 21695, 29553, 39509, 83135}},
-{14081, 18, 11354, {1, 3, 3, 15, 17, 43, 15, 195, 31, 501, 529, 3117, 6031, 12101, 30687, 52465, 66171, 149591}},
-{14082, 18, 11356, {1, 1, 3, 5, 13, 17, 63, 41, 303, 671, 1225, 1761, 6159, 3203, 23611, 18309, 115027, 116325}},
-{14083, 18, 11365, {1, 1, 5, 13, 17, 5, 97, 155, 479, 525, 1403, 4063, 8167, 6443, 20627, 41399, 26897, 102841}},
-{14084, 18, 11377, {1, 3, 5, 9, 9, 27, 59, 177, 453, 659, 765, 431, 4209, 12679, 10719, 22473, 81597, 20057}},
-{14085, 18, 11417, {1, 3, 3, 1, 3, 37, 91, 97, 159, 845, 519, 2603, 6979, 6711, 29781, 53639, 103357, 111671}},
-{14086, 18, 11427, {1, 1, 3, 3, 25, 15, 27, 9, 503, 719, 153, 3071, 281, 5341, 32595, 13069, 6461, 160319}},
-{14087, 18, 11433, {1, 3, 3, 5, 29, 7, 119, 229, 117, 925, 465, 1703, 7277, 10631, 9429, 41011, 45181, 229239}},
-{14088, 18, 11434, {1, 1, 7, 7, 31, 63, 67, 55, 445, 39, 1363, 1369, 1061, 8555, 29263, 47341, 49563, 80445}},
-{14089, 18, 11439, {1, 1, 7, 1, 23, 23, 49, 205, 371, 101, 1963, 2763, 3475, 835, 20371, 51343, 9771, 69713}},
-{14090, 18, 11444, {1, 3, 3, 7, 3, 29, 7, 185, 511, 93, 1077, 3971, 2981, 16367, 12703, 36179, 47755, 42767}},
-{14091, 18, 11448, {1, 1, 1, 11, 27, 47, 43, 39, 129, 337, 1249, 3557, 2871, 13565, 19525, 46263, 49203, 148235}},
-{14092, 18, 11461, {1, 3, 5, 11, 19, 3, 83, 151, 425, 199, 847, 3751, 1729, 12457, 21819, 295, 53627, 17555}},
-{14093, 18, 11466, {1, 1, 3, 5, 7, 43, 21, 221, 93, 785, 1851, 3891, 2103, 5219, 31845, 58943, 42461, 160149}},
-{14094, 18, 11468, {1, 3, 5, 9, 25, 11, 43, 171, 445, 335, 1907, 3401, 815, 10341, 17779, 24895, 7727, 168143}},
-{14095, 18, 11473, {1, 3, 1, 5, 27, 25, 41, 13, 239, 233, 1861, 3409, 4325, 2227, 30197, 59329, 48501, 168799}},
-{14096, 18, 11489, {1, 3, 5, 13, 9, 55, 83, 185, 287, 83, 1545, 2803, 2177, 6195, 14455, 30541, 75731, 98915}},
-{14097, 18, 11499, {1, 3, 3, 5, 25, 19, 5, 203, 303, 703, 1861, 3867, 2683, 8223, 11107, 54785, 106053, 135543}},
-{14098, 18, 11516, {1, 1, 1, 13, 19, 7, 11, 197, 303, 541, 977, 2083, 4739, 7971, 2245, 11029, 77333, 16573}},
-{14099, 18, 11531, {1, 1, 1, 3, 11, 33, 77, 59, 283, 791, 365, 4027, 487, 10559, 4543, 58111, 91861, 102905}},
-{14100, 18, 11533, {1, 3, 7, 7, 15, 3, 19, 51, 339, 377, 929, 693, 1617, 14057, 7107, 27181, 7411, 202843}},
-{14101, 18, 11557, {1, 3, 3, 9, 19, 9, 73, 109, 333, 917, 1227, 2871, 4893, 11029, 5619, 27091, 9381, 213403}},
-{14102, 18, 11572, {1, 1, 1, 9, 9, 13, 77, 131, 163, 619, 169, 315, 1277, 13705, 16853, 1179, 86433, 135427}},
-{14103, 18, 11608, {1, 3, 5, 9, 15, 47, 57, 119, 325, 529, 893, 2395, 5159, 5481, 18689, 6457, 114733, 159999}},
-{14104, 18, 11635, {1, 3, 7, 5, 15, 9, 113, 235, 475, 93, 495, 2983, 2769, 5209, 7481, 49699, 46961, 246393}},
-{14105, 18, 11638, {1, 1, 7, 1, 5, 31, 113, 27, 359, 635, 955, 2795, 6289, 11621, 11059, 2259, 57443, 243143}},
-{14106, 18, 11644, {1, 3, 3, 13, 19, 33, 53, 141, 437, 415, 919, 1375, 2703, 13731, 31559, 14115, 50101, 85199}},
-{14107, 18, 11684, {1, 1, 7, 13, 27, 57, 111, 89, 89, 313, 1107, 4049, 2485, 269, 10197, 36995, 71381, 112795}},
-{14108, 18, 11702, {1, 1, 3, 7, 17, 23, 119, 123, 145, 213, 1273, 1707, 4005, 13815, 23495, 36359, 14391, 94287}},
-{14109, 18, 11740, {1, 1, 7, 1, 5, 49, 81, 193, 105, 1003, 413, 2975, 1725, 5647, 25447, 43501, 4431, 115489}},
-{14110, 18, 11749, {1, 3, 1, 5, 29, 13, 47, 37, 441, 955, 611, 853, 7225, 4959, 8739, 31703, 48095, 124085}},
-{14111, 18, 11754, {1, 1, 5, 15, 31, 9, 125, 53, 229, 631, 1031, 3923, 4417, 12637, 22093, 46985, 103417, 193443}},
-{14112, 18, 11764, {1, 1, 7, 1, 7, 9, 77, 11, 451, 615, 1259, 3097, 1513, 13641, 26845, 17399, 63661, 9231}},
-{14113, 18, 11767, {1, 1, 7, 13, 25, 47, 125, 1, 333, 599, 1133, 3527, 7451, 2849, 27227, 40015, 118185, 24737}},
-{14114, 18, 11784, {1, 1, 5, 5, 31, 15, 85, 37, 121, 677, 593, 2757, 739, 839, 3939, 36339, 116663, 955}},
-{14115, 18, 11789, {1, 3, 1, 11, 19, 13, 87, 109, 149, 215, 1811, 3813, 7699, 16189, 12841, 52081, 104545, 245819}},
-{14116, 18, 11795, {1, 1, 7, 3, 31, 17, 99, 23, 377, 131, 821, 1167, 4437, 15727, 20753, 8163, 43719, 7243}},
-{14117, 18, 11798, {1, 3, 7, 13, 21, 5, 5, 167, 9, 1009, 1013, 797, 6145, 2855, 19969, 59887, 3419, 238661}},
-{14118, 18, 11804, {1, 1, 7, 1, 5, 39, 47, 91, 185, 139, 959, 3149, 3423, 8909, 2045, 18187, 71935, 238605}},
-{14119, 18, 11818, {1, 3, 5, 11, 29, 63, 105, 43, 27, 221, 879, 181, 1499, 10343, 27135, 823, 4893, 101707}},
-{14120, 18, 11820, {1, 3, 5, 11, 5, 13, 59, 83, 315, 999, 1205, 939, 3661, 3081, 15551, 13791, 49027, 26843}},
-{14121, 18, 11860, {1, 1, 1, 5, 3, 57, 105, 169, 123, 463, 1471, 445, 743, 13353, 17661, 23437, 35451, 115919}},
-{14122, 18, 11869, {1, 1, 5, 11, 9, 3, 41, 63, 501, 861, 153, 1591, 1379, 5189, 24483, 8073, 43319, 248959}},
-{14123, 18, 11874, {1, 1, 7, 3, 29, 45, 51, 177, 1, 961, 1493, 2179, 3723, 1923, 1517, 44823, 81613, 194641}},
-{14124, 18, 11903, {1, 1, 5, 11, 17, 17, 61, 141, 5, 529, 379, 2509, 1487, 13141, 10877, 18603, 40569, 69639}},
-{14125, 18, 11916, {1, 1, 5, 15, 1, 15, 33, 219, 269, 557, 7, 3627, 183, 6975, 4627, 15235, 51863, 172393}},
-{14126, 18, 11927, {1, 3, 7, 9, 1, 37, 13, 75, 151, 153, 1693, 2835, 3093, 8847, 6721, 44135, 128931, 230745}},
-{14127, 18, 11933, {1, 1, 3, 13, 29, 63, 33, 153, 503, 137, 401, 2315, 2223, 10843, 4235, 37295, 103249, 183899}},
-{14128, 18, 11962, {1, 1, 7, 11, 15, 25, 49, 55, 39, 13, 269, 3119, 3445, 8265, 16781, 57239, 97489, 204841}},
-{14129, 18, 12009, {1, 1, 1, 1, 25, 57, 117, 199, 41, 351, 477, 1891, 7913, 14439, 25305, 64811, 57731, 184265}},
-{14130, 18, 12020, {1, 3, 3, 1, 13, 41, 33, 53, 381, 31, 1861, 2207, 1497, 15539, 23589, 53215, 36887, 134007}},
-{14131, 18, 12035, {1, 1, 5, 7, 15, 37, 13, 99, 17, 325, 643, 2943, 7967, 11531, 21301, 5125, 63201, 101203}},
-{14132, 18, 12041, {1, 1, 7, 11, 23, 21, 119, 151, 457, 929, 1917, 3123, 1133, 11861, 27889, 40421, 90949, 113237}},
-{14133, 18, 12049, {1, 3, 5, 9, 13, 35, 111, 83, 371, 589, 1507, 3559, 773, 5895, 31453, 40865, 124103, 250473}},
-{14134, 18, 12065, {1, 3, 3, 15, 11, 7, 93, 163, 285, 763, 2023, 1047, 3349, 13575, 22571, 21513, 56081, 204765}},
-{14135, 18, 12072, {1, 3, 3, 5, 19, 19, 47, 25, 49, 717, 1155, 3901, 407, 2699, 30961, 55647, 96043, 185559}},
-{14136, 18, 12098, {1, 1, 1, 7, 29, 1, 49, 87, 311, 435, 1235, 1041, 6595, 1639, 32495, 44245, 6593, 236331}},
-{14137, 18, 12100, {1, 3, 7, 9, 27, 13, 1, 41, 75, 953, 1635, 101, 7231, 13019, 14773, 17315, 120993, 111215}},
-{14138, 18, 12107, {1, 1, 5, 9, 23, 31, 87, 47, 83, 791, 1239, 1453, 5459, 4847, 7285, 32667, 45991, 103593}},
-{14139, 18, 12167, {1, 3, 1, 3, 27, 47, 97, 191, 5, 961, 1191, 3897, 6821, 4257, 22047, 31557, 52603, 251405}},
-{14140, 18, 12202, {1, 1, 5, 3, 23, 45, 103, 115, 287, 47, 93, 2761, 6467, 14031, 21881, 31631, 47605, 237635}},
-{14141, 18, 12207, {1, 3, 7, 15, 23, 41, 63, 239, 115, 655, 1949, 1969, 3145, 91, 16735, 49295, 117995, 40537}},
-{14142, 18, 12233, {1, 1, 7, 11, 5, 25, 99, 247, 11, 707, 1497, 785, 6055, 8521, 12179, 56363, 110131, 55449}},
-{14143, 18, 12269, {1, 1, 1, 7, 5, 31, 99, 7, 285, 281, 1207, 1173, 7637, 9595, 31413, 16597, 96157, 39059}},
-{14144, 18, 12290, {1, 3, 7, 7, 3, 49, 79, 69, 57, 523, 65, 2785, 2907, 11295, 16199, 25845, 51801, 67417}},
-{14145, 18, 12304, {1, 1, 3, 1, 1, 53, 57, 117, 1, 927, 1787, 3059, 7441, 14663, 10881, 2225, 29375, 93717}},
-{14146, 18, 12314, {1, 1, 5, 5, 29, 17, 67, 35, 475, 367, 155, 3463, 2339, 6239, 31073, 56169, 130309, 28981}},
-{14147, 18, 12340, {1, 1, 1, 5, 7, 53, 61, 105, 355, 817, 869, 2863, 6041, 11459, 4151, 61115, 100689, 32917}},
-{14148, 18, 12416, {1, 3, 5, 11, 31, 11, 33, 105, 437, 767, 101, 2979, 3911, 4859, 15551, 23545, 10705, 6271}},
-{14149, 18, 12425, {1, 1, 7, 5, 1, 17, 109, 205, 409, 893, 889, 2181, 6167, 14273, 25389, 50279, 5497, 191755}},
-{14150, 18, 12428, {1, 3, 7, 15, 29, 11, 79, 101, 123, 399, 1159, 1263, 3513, 13169, 2199, 41057, 98639, 227107}},
-{14151, 18, 12446, {1, 1, 3, 11, 13, 31, 51, 119, 257, 829, 337, 3267, 7673, 15459, 26681, 4041, 89429, 198607}},
-{14152, 18, 12462, {1, 3, 7, 11, 23, 29, 49, 159, 327, 415, 857, 2411, 2429, 11839, 20263, 61813, 31811, 225443}},
-{14153, 18, 12476, {1, 1, 3, 11, 7, 61, 61, 119, 431, 299, 1815, 2857, 7605, 7517, 15137, 13727, 73021, 199325}},
-{14154, 18, 12496, {1, 1, 7, 3, 5, 19, 51, 19, 59, 637, 591, 2999, 5997, 13487, 807, 4887, 112189, 226597}},
-{14155, 18, 12511, {1, 1, 1, 13, 21, 5, 55, 167, 463, 679, 891, 3597, 785, 7717, 17495, 51681, 55957, 48561}},
-{14156, 18, 12518, {1, 1, 5, 5, 9, 55, 55, 143, 193, 839, 785, 1713, 7457, 11591, 15803, 2479, 124663, 72631}},
-{14157, 18, 12530, {1, 3, 5, 9, 21, 27, 109, 91, 483, 905, 1369, 2573, 7173, 13977, 20131, 17637, 127477, 66457}},
-{14158, 18, 12532, {1, 1, 5, 7, 31, 17, 43, 153, 505, 413, 867, 769, 6947, 10815, 18805, 5957, 27715, 24529}},
-{14159, 18, 12539, {1, 3, 5, 9, 13, 41, 107, 199, 69, 1019, 2037, 3221, 1081, 15051, 6713, 46379, 17223, 85453}},
-{14160, 18, 12567, {1, 3, 3, 7, 23, 51, 45, 133, 227, 373, 1815, 3795, 5567, 7153, 25003, 64951, 75377, 174115}},
-{14161, 18, 12597, {1, 1, 7, 15, 7, 51, 33, 239, 113, 133, 1213, 327, 4841, 11297, 1093, 40013, 60843, 99845}},
-{14162, 18, 12601, {1, 1, 1, 11, 3, 37, 33, 107, 275, 747, 1451, 1787, 5029, 3101, 11575, 36555, 46181, 221643}},
-{14163, 18, 12602, {1, 1, 3, 3, 29, 53, 57, 67, 209, 153, 345, 2897, 5657, 8907, 14159, 9899, 102487, 237721}},
-{14164, 18, 12622, {1, 3, 1, 7, 7, 59, 17, 151, 423, 903, 2035, 861, 1057, 2399, 28547, 3659, 29583, 100651}},
-{14165, 18, 12693, {1, 1, 5, 15, 27, 53, 101, 17, 405, 869, 1253, 1923, 999, 7787, 23621, 4351, 48611, 47129}},
-{14166, 18, 12707, {1, 3, 7, 11, 13, 43, 61, 161, 43, 831, 2021, 579, 5353, 12451, 32261, 39885, 90051, 34407}},
-{14167, 18, 12713, {1, 1, 1, 5, 25, 19, 37, 33, 37, 59, 1399, 1587, 1517, 4261, 31215, 33777, 50447, 87049}},
-{14168, 18, 12716, {1, 1, 3, 1, 19, 17, 113, 31, 385, 135, 143, 3997, 1365, 2625, 22591, 8887, 31353, 240603}},
-{14169, 18, 12734, {1, 3, 7, 11, 21, 7, 55, 171, 233, 1007, 1321, 2903, 2457, 3941, 19667, 49115, 99119, 185989}},
-{14170, 18, 12763, {1, 3, 7, 9, 3, 31, 83, 99, 303, 443, 99, 2285, 1491, 15897, 21735, 1575, 74449, 59615}},
-{14171, 18, 12765, {1, 3, 1, 5, 29, 37, 125, 213, 277, 115, 255, 137, 6071, 13561, 23871, 48129, 120211, 168603}},
-{14172, 18, 12799, {1, 1, 7, 3, 9, 21, 93, 239, 399, 21, 9, 409, 3403, 9517, 6421, 17121, 65697, 251985}},
-{14173, 18, 12843, {1, 1, 1, 15, 27, 35, 17, 113, 471, 357, 1703, 871, 1803, 3495, 27437, 48343, 86425, 155245}},
-{14174, 18, 12853, {1, 3, 7, 11, 19, 45, 51, 195, 345, 77, 1403, 2527, 3405, 14057, 31965, 17375, 35107, 246545}},
-{14175, 18, 12865, {1, 3, 5, 7, 7, 5, 115, 39, 51, 261, 1883, 1793, 3423, 3613, 20399, 27267, 99875, 119719}},
-{14176, 18, 12866, {1, 3, 3, 9, 21, 23, 65, 69, 261, 79, 151, 3387, 7789, 13275, 30135, 52229, 40787, 181297}},
-{14177, 18, 12919, {1, 1, 5, 13, 19, 49, 111, 125, 433, 99, 1673, 2091, 5447, 9377, 9085, 4659, 75121, 105809}},
-{14178, 18, 12926, {1, 3, 7, 1, 3, 27, 107, 109, 245, 431, 1727, 3269, 2099, 10777, 21843, 63377, 47343, 126269}},
-{14179, 18, 12936, {1, 3, 1, 15, 7, 17, 107, 153, 37, 287, 1873, 573, 5025, 3735, 32545, 35693, 38083, 89569}},
-{14180, 18, 12944, {1, 3, 1, 3, 9, 51, 99, 247, 45, 703, 1231, 1895, 6309, 12137, 14697, 25441, 129701, 198811}},
-{14181, 18, 12959, {1, 3, 3, 11, 5, 43, 1, 31, 359, 563, 1013, 3475, 3935, 7855, 10085, 15279, 25109, 225643}},
-{14182, 18, 12965, {1, 3, 3, 3, 9, 47, 49, 193, 223, 23, 391, 847, 7233, 14955, 10645, 50535, 5415, 119791}},
-{14183, 18, 12980, {1, 3, 1, 7, 3, 7, 57, 189, 219, 287, 401, 1767, 5585, 13983, 18485, 56725, 71905, 33779}},
-{14184, 18, 13004, {1, 3, 5, 15, 23, 17, 115, 223, 35, 263, 345, 3459, 857, 1467, 30255, 50127, 72985, 62509}},
-{14185, 18, 13016, {1, 3, 1, 9, 3, 27, 125, 43, 47, 183, 1421, 319, 4273, 10701, 21761, 23947, 22531, 10855}},
-{14186, 18, 13019, {1, 1, 3, 15, 13, 55, 77, 1, 295, 841, 1115, 4093, 7993, 13309, 24851, 35411, 105201, 188543}},
-{14187, 18, 13037, {1, 3, 3, 5, 19, 39, 101, 19, 225, 997, 1999, 407, 3147, 15393, 30379, 26221, 21685, 114167}},
-{14188, 18, 13055, {1, 3, 3, 3, 23, 15, 3, 57, 45, 381, 47, 1839, 5491, 6775, 18477, 51443, 757, 183111}},
-{14189, 18, 13063, {1, 3, 3, 7, 31, 27, 107, 229, 1, 977, 125, 1137, 4873, 14381, 8705, 64641, 38447, 239887}},
-{14190, 18, 13098, {1, 1, 3, 13, 9, 35, 49, 187, 459, 407, 1677, 2007, 1091, 12385, 8911, 38221, 108681, 171641}},
-{14191, 18, 13103, {1, 1, 3, 5, 7, 61, 115, 155, 437, 829, 1041, 2191, 1489, 1269, 27613, 48713, 40095, 206057}},
-{14192, 18, 13106, {1, 3, 7, 1, 23, 1, 17, 215, 363, 119, 845, 987, 5619, 5857, 11307, 63171, 76921, 201767}},
-{14193, 18, 13115, {1, 1, 7, 9, 29, 23, 63, 247, 37, 199, 103, 1215, 913, 12865, 24089, 35101, 117677, 261393}},
-{14194, 18, 13143, {1, 1, 1, 1, 3, 19, 7, 159, 183, 275, 467, 3629, 6575, 3351, 26955, 29247, 119007, 67895}},
-{14195, 18, 13144, {1, 1, 7, 13, 1, 33, 31, 211, 103, 495, 417, 817, 7129, 10169, 11445, 41511, 73101, 185357}},
-{14196, 18, 13153, {1, 1, 3, 5, 3, 27, 99, 1, 425, 295, 131, 835, 1833, 4547, 8777, 29489, 60303, 191437}},
-{14197, 18, 13171, {1, 1, 5, 5, 31, 63, 71, 189, 317, 61, 385, 891, 2257, 8281, 17325, 12207, 125847, 28259}},
-{14198, 18, 13184, {1, 1, 3, 3, 19, 19, 97, 83, 495, 551, 1339, 1699, 3047, 13623, 27731, 28999, 101225, 146139}},
-{14199, 18, 13193, {1, 3, 5, 7, 25, 9, 37, 73, 239, 47, 583, 3337, 1329, 79, 30109, 12451, 10163, 62943}},
-{14200, 18, 13199, {1, 1, 3, 1, 9, 1, 31, 181, 231, 441, 1241, 233, 6049, 2401, 9867, 58911, 20599, 26321}},
-{14201, 18, 13207, {1, 3, 1, 15, 21, 43, 21, 43, 273, 865, 79, 2069, 3375, 16069, 12355, 56355, 9735, 243719}},
-{14202, 18, 13217, {1, 3, 5, 11, 13, 21, 5, 73, 423, 761, 1947, 2935, 3931, 5573, 83, 58251, 113115, 245767}},
-{14203, 18, 13227, {1, 3, 7, 7, 15, 49, 73, 211, 309, 635, 1257, 2185, 7151, 11959, 26885, 45955, 103503, 161709}},
-{14204, 18, 13232, {1, 3, 1, 15, 31, 53, 29, 35, 343, 87, 1833, 2483, 1847, 4709, 6105, 21961, 106541, 46741}},
-{14205, 18, 13276, {1, 1, 7, 7, 21, 43, 41, 51, 29, 521, 713, 3693, 483, 11777, 10453, 43691, 97585, 133193}},
-{14206, 18, 13283, {1, 3, 3, 11, 5, 45, 3, 179, 183, 255, 1291, 1795, 5721, 10911, 18395, 64349, 23141, 99481}},
-{14207, 18, 13307, {1, 1, 1, 5, 5, 25, 61, 169, 475, 953, 617, 559, 5945, 16377, 30063, 30079, 83305, 81745}},
-{14208, 18, 13317, {1, 1, 5, 11, 29, 59, 113, 37, 153, 807, 135, 2639, 4535, 7079, 6387, 63523, 89669, 198803}},
-{14209, 18, 13330, {1, 1, 7, 7, 19, 23, 71, 51, 165, 733, 1427, 2473, 331, 5027, 9299, 20617, 126775, 91619}},
-{14210, 18, 13345, {1, 3, 5, 7, 31, 35, 117, 235, 29, 677, 1243, 281, 6287, 535, 4783, 37781, 130929, 14193}},
-{14211, 18, 13363, {1, 1, 5, 3, 25, 1, 29, 109, 289, 631, 41, 361, 5537, 9657, 7475, 63749, 50325, 169791}},
-{14212, 18, 13387, {1, 3, 3, 15, 21, 53, 85, 43, 341, 907, 475, 3257, 2541, 10397, 30847, 63681, 121427, 192135}},
-{14213, 18, 13426, {1, 1, 1, 1, 9, 59, 59, 233, 335, 345, 1749, 4007, 1833, 7789, 21015, 48939, 15967, 201321}},
-{14214, 18, 13428, {1, 1, 1, 5, 11, 9, 101, 243, 391, 1003, 1019, 311, 3707, 10223, 21627, 8237, 53861, 159785}},
-{14215, 18, 13431, {1, 3, 7, 15, 5, 3, 109, 197, 507, 947, 833, 1161, 4021, 5575, 8081, 45381, 112597, 70407}},
-{14216, 18, 13489, {1, 1, 3, 1, 7, 63, 63, 53, 481, 1003, 43, 2503, 2303, 12593, 21403, 2965, 5377, 91491}},
-{14217, 18, 13501, {1, 1, 1, 1, 29, 45, 49, 73, 253, 197, 1245, 1509, 4747, 6207, 28321, 59193, 112687, 83719}},
-{14218, 18, 13533, {1, 1, 7, 3, 11, 51, 23, 83, 185, 643, 1427, 227, 2261, 12521, 27033, 5129, 53111, 34975}},
-{14219, 18, 13589, {1, 1, 7, 3, 5, 41, 55, 175, 447, 603, 723, 2141, 1189, 4921, 16905, 2463, 83641, 247241}},
-{14220, 18, 13600, {1, 3, 3, 13, 5, 11, 95, 59, 391, 319, 1675, 329, 7559, 11585, 28905, 27843, 106667, 15531}},
-{14221, 18, 13603, {1, 3, 3, 3, 27, 17, 103, 115, 447, 657, 267, 2541, 665, 7819, 4155, 32191, 60999, 48737}},
-{14222, 18, 13623, {1, 1, 5, 7, 7, 49, 87, 171, 457, 149, 1699, 4081, 3913, 7889, 29517, 3339, 33139, 8925}},
-{14223, 18, 13665, {1, 1, 1, 9, 11, 51, 87, 115, 429, 505, 1665, 2361, 5811, 1621, 12727, 33703, 52255, 93835}},
-{14224, 18, 13672, {1, 3, 3, 5, 27, 11, 35, 49, 281, 607, 1791, 4065, 5103, 5253, 975, 20353, 38253, 139363}},
-{14225, 18, 13675, {1, 1, 5, 9, 29, 15, 37, 141, 445, 751, 1219, 2217, 7207, 14981, 21113, 3313, 107127, 135567}},
-{14226, 18, 13708, {1, 3, 3, 15, 1, 41, 23, 27, 167, 609, 913, 631, 923, 6939, 9793, 57869, 126577, 145271}},
-{14227, 18, 13713, {1, 1, 3, 7, 27, 47, 127, 5, 213, 575, 559, 2541, 3457, 2903, 19529, 53395, 105353, 212607}},
-{14228, 18, 13720, {1, 3, 1, 13, 27, 41, 31, 111, 371, 1019, 241, 2075, 2571, 10739, 28163, 16093, 41127, 69783}},
-{14229, 18, 13730, {1, 1, 5, 1, 21, 9, 15, 141, 287, 675, 1721, 2291, 6587, 7503, 6363, 9109, 33547, 259627}},
-{14230, 18, 13735, {1, 3, 7, 3, 3, 53, 7, 153, 183, 761, 191, 3735, 2619, 11153, 19601, 33855, 82345, 72755}},
-{14231, 18, 13767, {1, 3, 1, 9, 19, 21, 41, 105, 281, 833, 981, 2733, 7179, 14691, 18365, 56283, 53719, 191601}},
-{14232, 18, 13773, {1, 1, 7, 11, 23, 1, 55, 213, 105, 517, 809, 4087, 825, 7011, 15701, 54047, 123831, 49833}},
-{14233, 18, 13792, {1, 1, 7, 13, 27, 9, 111, 57, 357, 95, 1489, 887, 5273, 2833, 8757, 9371, 44637, 94939}},
-{14234, 18, 13843, {1, 1, 3, 5, 1, 17, 43, 31, 509, 353, 401, 1077, 7567, 9657, 15065, 32017, 8491, 214477}},
-{14235, 18, 13891, {1, 1, 1, 15, 7, 59, 41, 99, 101, 845, 1479, 2153, 4281, 12839, 237, 54095, 125873, 57165}},
-{14236, 18, 13946, {1, 3, 7, 13, 5, 17, 1, 249, 309, 351, 709, 3943, 7775, 6449, 26611, 54019, 121015, 213535}},
-{14237, 18, 13967, {1, 1, 1, 5, 7, 25, 33, 149, 291, 777, 161, 2729, 117, 4999, 16781, 23383, 85161, 71689}},
-{14238, 18, 13976, {1, 1, 3, 11, 5, 63, 119, 165, 45, 135, 1723, 811, 1259, 11055, 28625, 37559, 128401, 100715}},
-{14239, 18, 14017, {1, 3, 7, 1, 1, 39, 11, 255, 423, 289, 1359, 2827, 4637, 4089, 26659, 58701, 117403, 133971}},
-{14240, 18, 14030, {1, 1, 7, 1, 25, 9, 127, 121, 147, 831, 17, 3521, 1535, 10931, 17305, 56671, 22425, 157341}},
-{14241, 18, 14041, {1, 3, 1, 15, 5, 55, 95, 95, 169, 497, 739, 2031, 339, 13461, 20619, 24553, 81805, 90789}},
-{14242, 18, 14054, {1, 1, 7, 7, 7, 19, 15, 203, 287, 673, 1033, 3857, 2761, 10835, 11039, 62329, 37893, 6119}},
-{14243, 18, 14058, {1, 1, 3, 11, 19, 35, 55, 9, 399, 443, 583, 89, 2387, 747, 9551, 9907, 96871, 175457}},
-{14244, 18, 14060, {1, 1, 3, 1, 11, 57, 121, 89, 491, 133, 545, 683, 5751, 839, 25975, 44725, 59863, 142671}},
-{14245, 18, 14063, {1, 1, 3, 1, 23, 1, 111, 177, 1, 103, 1933, 2783, 6857, 51, 14547, 5945, 14757, 39783}},
-{14246, 18, 14078, {1, 3, 7, 13, 25, 13, 51, 247, 325, 361, 1225, 15, 1929, 1729, 25293, 59495, 82111, 101809}},
-{14247, 18, 14080, {1, 3, 3, 1, 19, 37, 67, 85, 105, 589, 1273, 2995, 8017, 1613, 22189, 2549, 22671, 72813}},
-{14248, 18, 14089, {1, 3, 7, 9, 15, 41, 25, 43, 411, 663, 387, 2861, 3627, 5839, 733, 53479, 76241, 116763}},
-{14249, 18, 14131, {1, 3, 3, 3, 17, 5, 73, 153, 133, 247, 881, 2853, 6059, 2259, 10181, 63251, 107089, 22579}},
-{14250, 18, 14134, {1, 3, 1, 5, 11, 15, 17, 235, 23, 15, 521, 235, 4137, 12705, 24775, 18197, 56295, 28035}},
-{14251, 18, 14137, {1, 3, 5, 5, 13, 9, 77, 69, 19, 755, 1663, 1499, 1049, 12935, 28835, 55413, 71511, 221223}},
-{14252, 18, 14188, {1, 1, 1, 1, 27, 31, 21, 39, 197, 519, 1621, 3703, 2541, 8865, 21947, 53605, 114551, 205697}},
-{14253, 18, 14215, {1, 1, 1, 13, 11, 53, 41, 245, 495, 275, 385, 3071, 1913, 11135, 8571, 58551, 39049, 5459}},
-{14254, 18, 14222, {1, 3, 5, 5, 11, 63, 25, 173, 57, 441, 1749, 79, 3191, 7733, 13111, 23453, 118399, 101845}},
-{14255, 18, 14249, {1, 1, 3, 11, 29, 25, 119, 39, 65, 623, 517, 1325, 5981, 8381, 32031, 25585, 105537, 214241}},
-{14256, 18, 14292, {1, 3, 5, 9, 21, 43, 13, 69, 109, 311, 1893, 1941, 2491, 7815, 4067, 56749, 33761, 191145}},
-{14257, 18, 14320, {1, 1, 1, 7, 9, 5, 123, 149, 65, 729, 1967, 3089, 3757, 2333, 24587, 36047, 118105, 146277}},
-{14258, 18, 14339, {1, 3, 7, 13, 9, 35, 39, 219, 161, 93, 275, 3619, 353, 14595, 24673, 54753, 117175, 81891}},
-{14259, 18, 14346, {1, 3, 3, 13, 15, 61, 95, 135, 271, 595, 1103, 877, 747, 2535, 7733, 25509, 65673, 62089}},
-{14260, 18, 14353, {1, 3, 3, 5, 21, 21, 67, 5, 373, 377, 61, 2337, 489, 5801, 23203, 42377, 7801, 178095}},
-{14261, 18, 14365, {1, 1, 7, 5, 25, 17, 61, 133, 181, 261, 1627, 1615, 6851, 4763, 30353, 53349, 7545, 66733}},
-{14262, 18, 14384, {1, 3, 5, 7, 29, 3, 85, 231, 121, 669, 1925, 403, 777, 10605, 24125, 60819, 8253, 81209}},
-{14263, 18, 14414, {1, 1, 5, 3, 5, 5, 1, 53, 9, 445, 1339, 2643, 5527, 13757, 9409, 31993, 80845, 97863}},
-{14264, 18, 14428, {1, 1, 7, 13, 29, 49, 97, 89, 319, 349, 1739, 3615, 1113, 11791, 17429, 37195, 1159, 32211}},
-{14265, 18, 14435, {1, 3, 5, 11, 9, 61, 109, 167, 119, 499, 1157, 3615, 5773, 8839, 27915, 47837, 14945, 187225}},
-{14266, 18, 14483, {1, 1, 5, 1, 9, 3, 7, 179, 323, 279, 43, 1337, 4813, 9917, 2033, 34657, 130769, 208089}},
-{14267, 18, 14486, {1, 1, 3, 1, 31, 57, 57, 73, 21, 661, 1861, 1661, 7619, 12155, 23123, 49751, 130697, 74143}},
-{14268, 18, 14506, {1, 3, 3, 13, 11, 61, 95, 75, 227, 491, 463, 597, 2721, 12323, 26195, 53657, 44413, 68965}},
-{14269, 18, 14513, {1, 1, 7, 11, 5, 51, 103, 123, 203, 911, 203, 1641, 7009, 9479, 303, 37649, 32751, 172777}},
-{14270, 18, 14520, {1, 1, 3, 7, 11, 59, 111, 5, 271, 863, 269, 3457, 489, 10877, 8645, 62567, 24893, 201587}},
-{14271, 18, 14526, {1, 1, 5, 7, 29, 23, 127, 151, 371, 121, 1103, 3951, 3107, 15563, 6243, 1631, 75065, 107681}},
-{14272, 18, 14528, {1, 1, 7, 15, 27, 45, 43, 83, 461, 673, 715, 3245, 313, 13731, 21981, 58853, 46569, 165463}},
-{14273, 18, 14533, {1, 1, 1, 9, 7, 53, 63, 43, 3, 187, 1325, 447, 5113, 4993, 21807, 24329, 4499, 30067}},
-{14274, 18, 14576, {1, 3, 1, 9, 21, 45, 111, 231, 407, 213, 1977, 2269, 2323, 4595, 30427, 54753, 95049, 195409}},
-{14275, 18, 14599, {1, 1, 1, 9, 29, 43, 89, 201, 499, 329, 847, 3831, 5403, 13001, 6037, 14371, 25805, 169237}},
-{14276, 18, 14613, {1, 1, 1, 11, 29, 61, 61, 203, 91, 189, 1603, 939, 6575, 3195, 4731, 44923, 33627, 21683}},
-{14277, 18, 14639, {1, 3, 3, 11, 7, 57, 93, 181, 479, 99, 681, 2875, 7649, 5555, 27087, 6841, 69859, 153689}},
-{14278, 18, 14644, {1, 1, 1, 9, 17, 45, 97, 47, 91, 879, 1463, 3041, 2917, 769, 13675, 26489, 88559, 120991}},
-{14279, 18, 14653, {1, 3, 7, 1, 11, 13, 43, 9, 483, 399, 793, 3965, 2375, 4957, 17747, 50905, 56987, 231265}},
-{14280, 18, 14662, {1, 3, 3, 13, 23, 45, 69, 67, 397, 437, 1993, 2569, 8035, 8531, 27623, 53567, 123189, 242515}},
-{14281, 18, 14695, {1, 1, 1, 3, 5, 9, 21, 227, 499, 205, 431, 3711, 5307, 15773, 11337, 6349, 123507, 95941}},
-{14282, 18, 14704, {1, 3, 7, 1, 13, 15, 101, 91, 209, 611, 537, 1427, 101, 2619, 10513, 44323, 92745, 249127}},
-{14283, 18, 14713, {1, 3, 3, 1, 21, 7, 79, 241, 273, 567, 605, 2371, 5427, 15147, 20139, 40987, 75551, 236213}},
-{14284, 18, 14725, {1, 1, 7, 11, 25, 19, 77, 209, 313, 663, 115, 3697, 3641, 12461, 9877, 18331, 70809, 78923}},
-{14285, 18, 14783, {1, 1, 5, 5, 29, 45, 7, 207, 1, 357, 1089, 3861, 4161, 3209, 27845, 20947, 68909, 125179}},
-{14286, 18, 14810, {1, 3, 1, 13, 17, 11, 27, 165, 179, 489, 1611, 2801, 2385, 2971, 6777, 16149, 59811, 151043}},
-{14287, 18, 14816, {1, 1, 3, 3, 17, 53, 121, 227, 7, 71, 1855, 639, 5135, 6349, 7163, 22997, 112551, 44167}},
-{14288, 18, 14822, {1, 3, 1, 11, 15, 9, 125, 213, 485, 291, 1781, 3621, 7529, 13353, 13903, 24151, 130253, 187097}},
-{14289, 18, 14828, {1, 3, 1, 3, 1, 61, 39, 157, 455, 945, 739, 589, 7259, 7149, 16455, 12649, 72003, 152419}},
-{14290, 18, 14883, {1, 1, 3, 3, 31, 23, 17, 255, 319, 907, 563, 2571, 2149, 15323, 20289, 46061, 32769, 184353}},
-{14291, 18, 14889, {1, 3, 7, 9, 21, 51, 27, 13, 495, 909, 2039, 1435, 4791, 10037, 30119, 3405, 22535, 42247}},
-{14292, 18, 14904, {1, 1, 3, 15, 11, 25, 123, 149, 185, 635, 473, 527, 433, 10373, 18205, 853, 94619, 202507}},
-{14293, 18, 14917, {1, 1, 7, 15, 7, 39, 7, 69, 157, 533, 369, 4031, 1335, 4279, 8049, 28491, 103753, 257477}},
-{14294, 18, 14927, {1, 3, 1, 15, 29, 51, 113, 77, 5, 961, 1863, 1477, 5009, 9519, 32029, 2367, 55705, 149597}},
-{14295, 18, 14941, {1, 3, 1, 5, 19, 43, 49, 107, 59, 693, 867, 3011, 2703, 3633, 24567, 52621, 35839, 134823}},
-{14296, 18, 14946, {1, 3, 3, 7, 19, 15, 81, 105, 23, 375, 451, 3017, 1263, 7589, 24453, 21885, 57651, 52613}},
-{14297, 18, 14952, {1, 1, 3, 7, 3, 59, 19, 1, 3, 243, 1891, 2041, 4707, 15557, 28885, 5959, 22517, 237131}},
-{14298, 18, 15010, {1, 3, 7, 11, 25, 33, 105, 15, 245, 247, 1357, 1255, 7463, 4815, 13727, 41687, 112425, 58827}},
-{14299, 18, 15012, {1, 1, 7, 1, 19, 31, 37, 201, 217, 127, 927, 763, 6359, 9951, 2581, 49171, 104305, 215923}},
-{14300, 18, 15033, {1, 1, 7, 7, 13, 9, 9, 139, 363, 85, 1703, 3615, 2545, 15991, 20677, 12109, 54951, 2171}},
-{14301, 18, 15041, {1, 3, 1, 13, 27, 3, 37, 195, 185, 829, 815, 1621, 2917, 8643, 29071, 45523, 38475, 243505}},
-{14302, 18, 15047, {1, 1, 7, 3, 19, 29, 91, 85, 331, 231, 1609, 2583, 1091, 4191, 29929, 55377, 105077, 168425}},
-{14303, 18, 15066, {1, 1, 5, 3, 29, 35, 3, 61, 389, 339, 705, 473, 2075, 7373, 9699, 38809, 60415, 66423}},
-{14304, 18, 15068, {1, 3, 1, 5, 17, 25, 17, 37, 335, 787, 1891, 1861, 4325, 12721, 9675, 13671, 18655, 235443}},
-{14305, 18, 15072, {1, 3, 3, 5, 23, 13, 83, 191, 263, 325, 1847, 1717, 7089, 15709, 26567, 44489, 66523, 3107}},
-{14306, 18, 15095, {1, 3, 7, 7, 25, 29, 63, 55, 9, 481, 899, 669, 5481, 11227, 1637, 17017, 124509, 102775}},
-{14307, 18, 15150, {1, 1, 1, 5, 21, 41, 101, 93, 129, 1023, 561, 2969, 1525, 2929, 32729, 54513, 4359, 28745}},
-{14308, 18, 15152, {1, 1, 5, 13, 15, 13, 79, 9, 257, 535, 861, 2703, 6161, 6659, 10369, 7, 117467, 146651}},
-{14309, 18, 15175, {1, 1, 3, 13, 31, 11, 43, 95, 441, 921, 1323, 343, 5339, 13149, 19643, 24253, 32055, 180327}},
-{14310, 18, 15176, {1, 1, 5, 15, 11, 27, 109, 149, 255, 1021, 249, 1913, 5213, 301, 9939, 49779, 26097, 66007}},
-{14311, 18, 15210, {1, 3, 1, 11, 15, 33, 53, 159, 433, 167, 1107, 3577, 6231, 8309, 28125, 55381, 127309, 14459}},
-{14312, 18, 15245, {1, 3, 5, 9, 7, 3, 45, 139, 133, 359, 537, 805, 3931, 5181, 915, 63317, 86227, 231573}},
-{14313, 18, 15258, {1, 1, 1, 3, 11, 31, 97, 127, 117, 151, 711, 2457, 2777, 3855, 21829, 7913, 30785, 141449}},
-{14314, 18, 15263, {1, 3, 7, 13, 11, 17, 65, 63, 289, 851, 1929, 4021, 105, 5207, 17085, 64119, 48659, 31687}},
-{14315, 18, 15264, {1, 1, 7, 11, 31, 57, 63, 251, 341, 727, 505, 1851, 783, 16191, 9335, 39421, 14793, 238215}},
-{14316, 18, 15279, {1, 3, 3, 11, 23, 13, 119, 195, 117, 579, 693, 3059, 2967, 12791, 26905, 28527, 13393, 11869}},
-{14317, 18, 15301, {1, 3, 7, 11, 23, 7, 61, 143, 409, 309, 651, 3321, 4027, 1351, 10339, 18451, 18447, 235665}},
-{14318, 18, 15306, {1, 1, 1, 9, 13, 21, 7, 65, 103, 789, 973, 475, 2831, 13337, 18989, 40573, 105375, 2221}},
-{14319, 18, 15313, {1, 3, 5, 15, 3, 59, 115, 61, 365, 653, 523, 3927, 8175, 6751, 32561, 55919, 64903, 139005}},
-{14320, 18, 15329, {1, 3, 3, 13, 1, 7, 51, 63, 179, 525, 1899, 373, 3797, 6329, 5539, 32669, 65903, 154993}},
-{14321, 18, 15341, {1, 3, 1, 1, 31, 53, 87, 39, 317, 71, 1899, 925, 4719, 11645, 27125, 50391, 116491, 219271}},
-{14322, 18, 15367, {1, 3, 7, 13, 7, 23, 1, 57, 333, 277, 893, 3245, 1417, 13115, 21835, 25879, 91305, 54691}},
-{14323, 18, 15368, {1, 3, 1, 11, 27, 5, 109, 69, 221, 453, 299, 517, 609, 11959, 27789, 33107, 46559, 121673}},
-{14324, 18, 15386, {1, 3, 5, 7, 27, 7, 119, 169, 129, 643, 173, 2479, 6163, 11159, 11897, 57153, 11347, 135337}},
-{14325, 18, 15404, {1, 1, 5, 13, 13, 59, 21, 13, 429, 601, 267, 1635, 2579, 12053, 31583, 14847, 78187, 217099}},
-{14326, 18, 15422, {1, 3, 5, 9, 5, 3, 125, 159, 411, 15, 479, 933, 6307, 9707, 23491, 6501, 70993, 161365}},
-{14327, 18, 15436, {1, 1, 7, 7, 3, 33, 87, 177, 283, 825, 1935, 1545, 7071, 9975, 1795, 48277, 115725, 173439}},
-{14328, 18, 15444, {1, 3, 3, 9, 19, 63, 17, 119, 13, 337, 2021, 2221, 3237, 3253, 18661, 15479, 59377, 76095}},
-{14329, 18, 15467, {1, 1, 1, 11, 17, 15, 93, 249, 333, 171, 575, 3251, 5413, 3587, 22807, 29273, 56461, 97801}},
-{14330, 18, 15498, {1, 3, 3, 11, 13, 7, 27, 167, 389, 693, 1473, 555, 1603, 3167, 3985, 3841, 100283, 195253}},
-{14331, 18, 15503, {1, 3, 7, 1, 23, 7, 89, 231, 85, 797, 1935, 2557, 4365, 2221, 21069, 44055, 77723, 226547}},
-{14332, 18, 15528, {1, 3, 1, 5, 5, 49, 47, 187, 71, 903, 1279, 3219, 8041, 10915, 5249, 17755, 80077, 3479}},
-{14333, 18, 15534, {1, 1, 3, 13, 5, 53, 35, 25, 183, 791, 1651, 1041, 1221, 2171, 26221, 20649, 126851, 163047}},
-{14334, 18, 15536, {1, 1, 5, 9, 29, 3, 75, 31, 385, 293, 171, 3023, 2075, 14541, 30879, 13895, 67637, 87831}},
-{14335, 18, 15559, {1, 3, 5, 7, 3, 41, 115, 213, 23, 895, 361, 27, 5839, 12447, 13829, 29183, 106539, 134891}},
-{14336, 18, 15565, {1, 3, 7, 7, 11, 39, 99, 229, 195, 633, 837, 3697, 1161, 15119, 20831, 27371, 92195, 26993}},
-{14337, 18, 15583, {1, 1, 5, 9, 25, 17, 5, 169, 475, 73, 1451, 2057, 3671, 12801, 9671, 57427, 25321, 154969}},
-{14338, 18, 15599, {1, 3, 5, 11, 25, 23, 9, 145, 341, 339, 1855, 981, 8041, 569, 19851, 29521, 21767, 136505}},
-{14339, 18, 15602, {1, 1, 1, 1, 3, 9, 101, 253, 475, 529, 387, 1893, 5509, 5763, 29555, 13307, 30001, 105057}},
-{14340, 18, 15616, {1, 3, 3, 5, 17, 23, 127, 161, 375, 817, 1229, 1197, 1097, 3053, 14351, 21213, 12501, 137397}},
-{14341, 18, 15626, {1, 1, 1, 9, 7, 1, 57, 185, 281, 65, 181, 2483, 4739, 4353, 29837, 40613, 32489, 23317}},
-{14342, 18, 15667, {1, 1, 3, 9, 5, 35, 43, 191, 409, 95, 537, 2465, 515, 1633, 20887, 32535, 43863, 199885}},
-{14343, 18, 15684, {1, 3, 3, 13, 19, 49, 41, 51, 3, 979, 1623, 3323, 7711, 3707, 29417, 58011, 114467, 227499}},
-{14344, 18, 15711, {1, 1, 1, 11, 21, 7, 23, 51, 39, 25, 1971, 213, 369, 9149, 12845, 57631, 16597, 22031}},
-{14345, 18, 15745, {1, 3, 3, 11, 27, 59, 71, 37, 461, 353, 2041, 1961, 4643, 6953, 18129, 60337, 82769, 20819}},
-{14346, 18, 15763, {1, 1, 3, 11, 25, 19, 17, 5, 503, 227, 2021, 733, 2867, 201, 25779, 49811, 81167, 95437}},
-{14347, 18, 15779, {1, 3, 3, 15, 7, 53, 35, 143, 27, 937, 215, 3249, 4151, 1933, 25267, 18047, 35131, 25903}},
-{14348, 18, 15811, {1, 1, 1, 3, 3, 39, 71, 99, 291, 97, 1389, 3803, 2881, 9765, 11277, 20071, 15133, 37349}},
-{14349, 18, 15814, {1, 1, 7, 11, 9, 55, 1, 241, 391, 935, 1555, 3585, 1807, 10057, 2633, 14023, 14409, 199643}},
-{14350, 18, 15817, {1, 3, 3, 3, 19, 9, 57, 237, 107, 869, 147, 2673, 5271, 8999, 20723, 63017, 75989, 20131}},
-{14351, 18, 15853, {1, 3, 3, 3, 25, 11, 61, 77, 119, 657, 2011, 3489, 7835, 4473, 2531, 65231, 104797, 161443}},
-{14352, 18, 15881, {1, 1, 5, 5, 11, 63, 25, 93, 181, 797, 367, 3357, 5291, 5087, 28661, 34093, 75195, 165345}},
-{14353, 18, 15890, {1, 1, 1, 7, 17, 1, 77, 149, 59, 633, 1551, 1305, 7677, 8671, 17457, 64037, 104451, 112387}},
-{14354, 18, 15899, {1, 3, 1, 1, 15, 33, 37, 187, 247, 261, 1101, 3451, 7747, 12197, 22465, 30589, 12573, 204517}},
-{14355, 18, 15905, {1, 3, 3, 11, 3, 39, 71, 139, 145, 139, 101, 2815, 3457, 14033, 4531, 42133, 54147, 71259}},
-{14356, 18, 15915, {1, 3, 1, 1, 23, 37, 19, 113, 443, 57, 439, 2929, 3835, 5431, 11189, 4539, 72531, 124453}},
-{14357, 18, 15937, {1, 3, 3, 5, 3, 17, 21, 217, 41, 665, 1565, 3753, 5289, 9789, 29205, 16453, 88979, 171387}},
-{14358, 18, 15950, {1, 3, 3, 13, 27, 15, 15, 223, 231, 311, 311, 1143, 8113, 13863, 3191, 51103, 109437, 245557}},
-{14359, 18, 16002, {1, 1, 3, 13, 11, 59, 7, 191, 477, 683, 353, 2845, 7623, 9035, 453, 48429, 40111, 162859}},
-{14360, 18, 16041, {1, 3, 7, 5, 29, 37, 55, 59, 259, 851, 861, 1951, 7847, 8537, 30107, 2999, 59137, 155615}},
-{14361, 18, 16042, {1, 3, 7, 11, 3, 13, 73, 147, 393, 327, 1289, 37, 795, 1413, 19215, 28345, 124301, 23135}},
-{14362, 18, 16052, {1, 1, 5, 11, 29, 17, 107, 69, 433, 845, 1351, 2551, 807, 15315, 15511, 39475, 84879, 129405}},
-{14363, 18, 16121, {1, 3, 3, 9, 15, 3, 23, 5, 211, 871, 689, 2319, 39, 2215, 25171, 43169, 113715, 186049}},
-{14364, 18, 16132, {1, 1, 3, 7, 3, 37, 23, 9, 453, 649, 373, 1273, 1539, 6221, 27469, 44675, 13513, 131179}},
-{14365, 18, 16136, {1, 3, 1, 5, 29, 41, 119, 133, 37, 761, 1193, 2311, 4945, 7337, 17027, 12873, 51489, 160633}},
-{14366, 18, 16150, {1, 3, 1, 3, 21, 63, 75, 115, 105, 223, 933, 445, 5789, 4611, 13609, 2873, 16679, 222895}},
-{14367, 18, 16153, {1, 1, 7, 5, 17, 13, 15, 217, 193, 863, 1319, 2337, 3055, 14879, 8669, 5705, 42965, 166443}},
-{14368, 18, 16180, {1, 1, 7, 11, 3, 55, 57, 131, 289, 843, 1693, 881, 6737, 5557, 18365, 12393, 38479, 189177}},
-{14369, 18, 16190, {1, 1, 3, 5, 3, 59, 13, 123, 397, 479, 79, 569, 535, 2529, 26225, 43475, 76925, 187763}},
-{14370, 18, 16192, {1, 1, 5, 15, 15, 37, 1, 97, 489, 331, 1499, 1759, 3621, 5373, 1425, 6477, 45805, 235511}},
-{14371, 18, 16195, {1, 3, 1, 3, 7, 51, 55, 157, 61, 751, 1881, 4093, 2557, 11129, 23239, 16335, 8949, 205007}},
-{14372, 18, 16210, {1, 1, 1, 1, 13, 21, 67, 141, 85, 1023, 223, 747, 1951, 10279, 6399, 49887, 100437, 76757}},
-{14373, 18, 16225, {1, 1, 3, 11, 1, 51, 29, 33, 173, 769, 879, 2883, 417, 15031, 13377, 63919, 118803, 87969}},
-{14374, 18, 16256, {1, 1, 1, 5, 1, 1, 17, 153, 81, 691, 961, 3399, 5005, 10617, 18467, 13775, 34905, 241349}},
-{14375, 18, 16266, {1, 1, 1, 13, 7, 37, 57, 187, 389, 575, 1827, 2017, 4541, 10513, 23409, 30945, 126855, 239657}},
-{14376, 18, 16274, {1, 1, 5, 5, 17, 41, 83, 177, 285, 695, 29, 1653, 953, 6377, 13571, 58663, 9265, 100759}},
-{14377, 18, 16302, {1, 3, 5, 3, 5, 13, 27, 153, 207, 699, 1805, 947, 979, 2719, 389, 61953, 16991, 160073}},
-{14378, 18, 16310, {1, 1, 7, 13, 17, 37, 113, 185, 239, 455, 1557, 3201, 1111, 4875, 23197, 41883, 70507, 255047}},
-{14379, 18, 16322, {1, 3, 5, 11, 9, 51, 47, 137, 413, 1015, 259, 1829, 6043, 11757, 22317, 15155, 107827, 171003}},
-{14380, 18, 16339, {1, 1, 1, 13, 27, 7, 49, 91, 285, 13, 2007, 3469, 1223, 2483, 16155, 8413, 10529, 224195}},
-{14381, 18, 16345, {1, 1, 7, 3, 9, 49, 119, 81, 331, 187, 1695, 1729, 533, 6359, 7053, 34665, 37541, 100225}},
-{14382, 18, 16348, {1, 3, 7, 1, 7, 35, 115, 91, 479, 515, 1249, 121, 2885, 16383, 1777, 44205, 86459, 255885}},
-{14383, 18, 16357, {1, 1, 7, 13, 13, 27, 11, 49, 221, 829, 1787, 2889, 3875, 1679, 25333, 1323, 9813, 189373}},
-{14384, 18, 16382, {1, 3, 7, 5, 31, 5, 117, 77, 209, 619, 191, 2969, 2221, 15339, 11461, 64201, 130461, 204467}},
-{14385, 18, 16402, {1, 3, 1, 1, 29, 5, 91, 31, 313, 901, 1501, 2837, 3615, 7765, 341, 13873, 21663, 260637}},
-{14386, 18, 16461, {1, 1, 1, 9, 1, 41, 97, 15, 141, 901, 1309, 3341, 4871, 16033, 12343, 1555, 94989, 78295}},
-{14387, 18, 16469, {1, 1, 7, 3, 3, 15, 1, 29, 445, 59, 475, 3033, 4227, 3219, 6093, 58953, 92179, 49343}},
-{14388, 18, 16474, {1, 1, 5, 3, 27, 25, 109, 13, 219, 983, 131, 2517, 1161, 16063, 32737, 6077, 91183, 37457}},
-{14389, 18, 16483, {1, 3, 3, 1, 3, 1, 85, 147, 17, 543, 1475, 3873, 3719, 2737, 30977, 15953, 66077, 258979}},
-{14390, 18, 16497, {1, 3, 5, 1, 29, 9, 21, 51, 5, 985, 1177, 3287, 2183, 7301, 13713, 53403, 38439, 195863}},
-{14391, 18, 16523, {1, 1, 7, 15, 31, 53, 47, 173, 477, 439, 751, 1019, 3371, 9319, 17995, 29029, 90657, 209277}},
-{14392, 18, 16534, {1, 1, 5, 5, 17, 5, 59, 115, 375, 231, 1891, 1321, 3639, 16117, 32639, 28793, 68213, 41091}},
-{14393, 18, 16550, {1, 3, 5, 11, 17, 15, 13, 11, 459, 767, 849, 1407, 6611, 6409, 21515, 63175, 127155, 171959}},
-{14394, 18, 16564, {1, 1, 5, 1, 17, 49, 61, 161, 399, 137, 845, 2673, 2431, 15343, 389, 42337, 23031, 94811}},
-{14395, 18, 16582, {1, 1, 1, 9, 21, 23, 75, 177, 351, 197, 1619, 2443, 6829, 3773, 16399, 31949, 44975, 221363}},
-{14396, 18, 16591, {1, 1, 3, 1, 11, 19, 103, 61, 135, 863, 1427, 2657, 4553, 1277, 20249, 3973, 25467, 18847}},
-{14397, 18, 16609, {1, 3, 3, 13, 17, 31, 19, 163, 323, 195, 603, 4069, 3181, 12069, 22117, 44229, 23585, 202785}},
-{14398, 18, 16642, {1, 1, 7, 5, 17, 3, 77, 111, 491, 829, 1375, 2829, 5599, 14057, 21387, 52345, 108281, 211285}},
-{14399, 18, 16648, {1, 3, 3, 1, 17, 43, 71, 13, 321, 393, 1803, 727, 5101, 13485, 8693, 60505, 13893, 3467}},
-{14400, 18, 16656, {1, 1, 5, 1, 23, 31, 121, 15, 215, 215, 1113, 3335, 7431, 4863, 31429, 49903, 59403, 60797}},
-{14401, 18, 16662, {1, 3, 3, 9, 21, 43, 61, 171, 361, 323, 1895, 3647, 729, 8809, 9351, 14573, 93593, 17485}},
-{14402, 18, 16665, {1, 3, 3, 7, 7, 19, 45, 247, 203, 757, 1941, 3753, 5317, 13239, 18945, 26173, 43929, 66889}},
-{14403, 18, 16678, {1, 1, 1, 15, 5, 17, 11, 21, 193, 941, 517, 191, 6067, 8403, 27339, 31035, 34767, 28675}},
-{14404, 18, 16701, {1, 3, 1, 7, 27, 59, 27, 7, 491, 551, 867, 3693, 391, 9799, 11051, 28347, 57555, 23079}},
-{14405, 18, 16713, {1, 3, 3, 1, 25, 21, 63, 253, 459, 603, 107, 1229, 1433, 4263, 24341, 20493, 40165, 254725}},
-{14406, 18, 16716, {1, 3, 5, 3, 9, 7, 63, 195, 19, 973, 47, 811, 2207, 3613, 8911, 17495, 62403, 77951}},
-{14407, 18, 16758, {1, 3, 5, 11, 5, 13, 83, 125, 467, 111, 1819, 3807, 4259, 2885, 29577, 13539, 69859, 97379}},
-{14408, 18, 16768, {1, 1, 5, 15, 5, 33, 109, 203, 129, 587, 9, 3025, 2839, 11405, 11257, 7779, 30311, 14015}},
-{14409, 18, 16797, {1, 1, 7, 15, 5, 47, 103, 199, 391, 61, 129, 3511, 1295, 15067, 23919, 2941, 120463, 21665}},
-{14410, 18, 16804, {1, 1, 5, 5, 7, 7, 125, 153, 365, 815, 1423, 4053, 875, 2405, 21291, 26785, 31371, 211045}},
-{14411, 18, 16811, {1, 3, 3, 9, 31, 47, 1, 247, 197, 1019, 985, 2277, 875, 3969, 15093, 15561, 110101, 156547}},
-{14412, 18, 16813, {1, 1, 3, 1, 9, 47, 71, 125, 17, 501, 1783, 2337, 483, 12719, 22453, 16701, 102639, 152955}},
-{14413, 18, 16881, {1, 1, 3, 11, 13, 31, 9, 63, 261, 257, 319, 1443, 5011, 9799, 18639, 53081, 56879, 102335}},
-{14414, 18, 16888, {1, 3, 3, 1, 5, 59, 127, 163, 323, 997, 1755, 1445, 2285, 4935, 22123, 815, 115131, 1009}},
-{14415, 18, 16893, {1, 1, 3, 11, 11, 43, 65, 127, 137, 583, 173, 2601, 5809, 15773, 16129, 2543, 68281, 96107}},
-{14416, 18, 16922, {1, 3, 5, 9, 25, 25, 95, 73, 313, 893, 1805, 2301, 5917, 15159, 8637, 25505, 66053, 31627}},
-{14417, 18, 16937, {1, 1, 3, 7, 25, 59, 55, 13, 297, 849, 187, 359, 3745, 12655, 29293, 58581, 89799, 195867}},
-{14418, 18, 16958, {1, 1, 5, 13, 19, 5, 51, 85, 259, 59, 1003, 2991, 6605, 8405, 5221, 45607, 130729, 99641}},
-{14419, 18, 16965, {1, 3, 5, 5, 25, 61, 51, 211, 143, 233, 1465, 1165, 1769, 3021, 9491, 30335, 34787, 142605}},
-{14420, 18, 16978, {1, 3, 5, 13, 23, 9, 89, 249, 71, 179, 841, 3375, 21, 6757, 27495, 7531, 123725, 253855}},
-{14421, 18, 16980, {1, 3, 7, 13, 9, 33, 109, 103, 475, 781, 493, 2079, 6529, 13443, 2181, 26925, 31345, 142863}},
-{14422, 18, 16989, {1, 1, 7, 9, 15, 41, 17, 85, 503, 839, 533, 731, 2735, 12949, 11395, 22539, 130147, 40045}},
-{14423, 18, 17011, {1, 1, 5, 9, 25, 21, 29, 79, 405, 383, 1271, 385, 7629, 3889, 5319, 57739, 51411, 50895}},
-{14424, 18, 17014, {1, 3, 7, 5, 13, 35, 17, 97, 261, 437, 951, 1403, 2407, 11447, 13565, 10165, 100001, 253093}},
-{14425, 18, 17023, {1, 3, 1, 3, 11, 39, 31, 187, 473, 565, 351, 4007, 2621, 14463, 9009, 40679, 81069, 51131}},
-{14426, 18, 17063, {1, 3, 5, 5, 9, 17, 11, 151, 59, 249, 281, 203, 6423, 4977, 18557, 65383, 88361, 87437}},
-{14427, 18, 17081, {1, 3, 5, 7, 15, 25, 3, 157, 179, 439, 1627, 3493, 6641, 6403, 2361, 3613, 33817, 22585}},
-{14428, 18, 17084, {1, 3, 5, 1, 13, 63, 77, 195, 233, 175, 631, 1021, 637, 13231, 26187, 131, 127379, 256183}},
-{14429, 18, 17099, {1, 1, 7, 9, 5, 13, 15, 187, 55, 37, 1113, 2191, 3439, 1073, 26239, 3049, 19807, 250869}},
-{14430, 18, 17126, {1, 1, 7, 3, 13, 15, 77, 47, 317, 285, 753, 2419, 7795, 11423, 6043, 2913, 42819, 50603}},
-{14431, 18, 17129, {1, 3, 7, 15, 21, 17, 63, 71, 97, 535, 1085, 1531, 5165, 13717, 1537, 26797, 111787, 189403}},
-{14432, 18, 17138, {1, 1, 1, 7, 9, 3, 43, 209, 385, 851, 1411, 4039, 3259, 13387, 24505, 33325, 83741, 241255}},
-{14433, 18, 17164, {1, 1, 1, 1, 3, 41, 13, 43, 303, 445, 1097, 3517, 7753, 8459, 3017, 16385, 13775, 248655}},
-{14434, 18, 17170, {1, 3, 5, 15, 5, 61, 31, 57, 269, 931, 1071, 1137, 6181, 13005, 18493, 1345, 105203, 117309}},
-{14435, 18, 17203, {1, 1, 3, 13, 21, 29, 3, 179, 367, 155, 993, 117, 5849, 10181, 1175, 55769, 16025, 67669}},
-{14436, 18, 17206, {1, 1, 3, 9, 11, 9, 33, 131, 181, 1003, 253, 2759, 1877, 11851, 22959, 37823, 82737, 110329}},
-{14437, 18, 17224, {1, 1, 1, 5, 7, 5, 107, 191, 385, 129, 567, 2585, 7295, 3005, 28185, 7095, 54851, 257587}},
-{14438, 18, 17305, {1, 3, 7, 9, 21, 61, 103, 155, 503, 307, 993, 683, 1491, 14895, 9213, 34535, 17765, 12457}},
-{14439, 18, 17322, {1, 3, 3, 1, 7, 47, 27, 173, 97, 889, 853, 3995, 4943, 71, 20479, 16741, 35479, 35307}},
-{14440, 18, 17327, {1, 1, 5, 3, 15, 35, 29, 207, 117, 267, 1835, 2565, 1199, 3813, 13999, 10537, 129915, 210651}},
-{14441, 18, 17332, {1, 3, 3, 13, 5, 57, 77, 193, 11, 279, 745, 2511, 5775, 13527, 26329, 16303, 111511, 70025}},
-{14442, 18, 17342, {1, 3, 7, 9, 17, 1, 73, 1, 125, 939, 863, 2763, 1951, 3191, 5567, 59729, 32149, 149417}},
-{14443, 18, 17387, {1, 3, 3, 1, 19, 25, 119, 63, 101, 33, 77, 3587, 6367, 8275, 24957, 32087, 7031, 217291}},
-{14444, 18, 17410, {1, 1, 1, 13, 7, 25, 75, 161, 143, 353, 973, 2957, 749, 13519, 11295, 34287, 60727, 83731}},
-{14445, 18, 17419, {1, 3, 7, 7, 17, 9, 59, 45, 97, 619, 895, 1955, 8143, 2507, 4673, 39425, 35679, 152069}},
-{14446, 18, 17429, {1, 1, 5, 9, 31, 19, 115, 177, 349, 877, 525, 305, 2187, 12195, 13529, 61641, 102293, 69941}},
-{14447, 18, 17439, {1, 3, 7, 11, 23, 59, 15, 243, 511, 465, 905, 1979, 2263, 2105, 9009, 3691, 22241, 97765}},
-{14448, 18, 17440, {1, 1, 7, 9, 29, 13, 3, 207, 51, 405, 1703, 1923, 1781, 14723, 8103, 10707, 64799, 99349}},
-{14449, 18, 17457, {1, 1, 7, 5, 23, 29, 51, 63, 489, 273, 1577, 2807, 5427, 9949, 1929, 19791, 109405, 241465}},
-{14450, 18, 17458, {1, 3, 3, 7, 29, 61, 103, 55, 29, 17, 1081, 21, 5791, 9803, 19385, 45091, 118069, 61383}},
-{14451, 18, 17469, {1, 3, 1, 7, 3, 15, 75, 47, 475, 87, 1541, 3933, 1081, 12361, 29213, 64333, 7229, 226909}},
-{14452, 18, 17477, {1, 1, 5, 7, 21, 45, 19, 137, 351, 229, 1773, 1829, 5025, 12661, 18745, 54917, 10419, 176667}},
-{14453, 18, 17512, {1, 1, 1, 3, 9, 37, 81, 25, 11, 327, 1653, 2751, 2823, 12575, 30287, 46265, 17299, 93595}},
-{14454, 18, 17518, {1, 1, 1, 3, 15, 17, 43, 163, 223, 731, 631, 2813, 1723, 6089, 14245, 64339, 114291, 40331}},
-{14455, 18, 17532, {1, 3, 7, 5, 21, 45, 41, 17, 495, 61, 1369, 369, 4493, 12071, 3813, 41455, 62561, 174399}},
-{14456, 18, 17536, {1, 1, 1, 5, 9, 41, 95, 113, 109, 519, 1683, 2265, 2875, 12649, 15575, 53511, 100707, 224035}},
-{14457, 18, 17559, {1, 3, 7, 9, 29, 7, 109, 109, 283, 111, 1167, 3679, 369, 11597, 19459, 759, 128667, 172427}},
-{14458, 18, 17569, {1, 1, 1, 3, 13, 31, 97, 31, 477, 507, 835, 465, 7501, 2485, 19485, 51055, 56363, 229341}},
-{14459, 18, 17641, {1, 3, 5, 11, 3, 23, 67, 173, 99, 963, 977, 1949, 1263, 2427, 15181, 23571, 23509, 26481}},
-{14460, 18, 17667, {1, 3, 3, 1, 29, 3, 35, 191, 197, 277, 397, 205, 5945, 1069, 31789, 3551, 101901, 222609}},
-{14461, 18, 17674, {1, 1, 5, 9, 11, 23, 109, 81, 295, 7, 755, 2345, 2823, 11133, 22623, 14515, 57059, 231099}},
-{14462, 18, 17693, {1, 3, 1, 3, 21, 29, 37, 71, 111, 737, 1881, 871, 5843, 5889, 14615, 49909, 7105, 48335}},
-{14463, 18, 17710, {1, 3, 1, 15, 23, 31, 87, 181, 483, 225, 2003, 365, 1569, 11153, 14673, 30085, 56497, 203723}},
-{14464, 18, 17729, {1, 1, 3, 15, 17, 47, 99, 167, 485, 431, 1481, 2225, 1537, 8513, 19407, 34165, 27289, 84393}},
-{14465, 18, 17754, {1, 3, 7, 3, 11, 17, 115, 205, 403, 831, 1869, 3623, 5215, 15511, 11297, 25181, 127491, 155887}},
-{14466, 18, 17763, {1, 1, 7, 5, 31, 37, 23, 21, 403, 529, 1185, 3363, 6319, 2435, 2687, 39407, 121891, 133047}},
-{14467, 18, 17780, {1, 3, 7, 1, 21, 31, 43, 61, 371, 987, 1783, 3811, 6227, 13199, 31799, 28863, 49329, 73947}},
-{14468, 18, 17784, {1, 3, 1, 1, 13, 1, 5, 99, 35, 793, 483, 2573, 2249, 6345, 12793, 61917, 49419, 58011}},
-{14469, 18, 17790, {1, 3, 1, 15, 3, 45, 35, 189, 67, 447, 1455, 3575, 8191, 7907, 21559, 38211, 26945, 240679}},
-{14470, 18, 17830, {1, 1, 3, 11, 27, 49, 9, 109, 93, 473, 1465, 271, 7389, 47, 8101, 6219, 17437, 220461}},
-{14471, 18, 17851, {1, 1, 7, 3, 23, 31, 75, 61, 375, 901, 1329, 2603, 3469, 12957, 23949, 62183, 126763, 68965}},
-{14472, 18, 17868, {1, 1, 7, 9, 13, 59, 75, 233, 339, 29, 1117, 1693, 593, 15317, 29753, 3079, 43583, 79939}},
-{14473, 18, 17879, {1, 1, 5, 1, 17, 57, 81, 123, 101, 765, 1941, 3143, 7403, 9105, 23197, 28983, 128059, 5931}},
-{14474, 18, 17896, {1, 3, 5, 11, 19, 31, 89, 165, 213, 251, 965, 3203, 1621, 4323, 26877, 17109, 18321, 162413}},
-{14475, 18, 17901, {1, 3, 3, 9, 11, 59, 123, 213, 335, 267, 1767, 3317, 5189, 10149, 27921, 19331, 71541, 170501}},
-{14476, 18, 17916, {1, 3, 3, 15, 3, 3, 115, 235, 305, 219, 265, 1535, 4925, 5597, 20857, 32381, 117237, 197533}},
-{14477, 18, 17935, {1, 3, 5, 13, 13, 59, 93, 85, 419, 337, 513, 2131, 5665, 12229, 1389, 34355, 65485, 81141}},
-{14478, 18, 17953, {1, 3, 7, 7, 11, 59, 111, 219, 293, 289, 325, 623, 3853, 3775, 14771, 5945, 119451, 162861}},
-{14479, 18, 17991, {1, 3, 1, 11, 19, 33, 119, 239, 431, 803, 1119, 2445, 3203, 7219, 31963, 34519, 104953, 254491}},
-{14480, 18, 18009, {1, 3, 7, 9, 21, 53, 21, 115, 365, 419, 11, 3803, 4283, 417, 8937, 64533, 56433, 166025}},
-{14481, 18, 18016, {1, 1, 7, 3, 17, 5, 99, 143, 485, 309, 1255, 2641, 3427, 1681, 3301, 64531, 38629, 20945}},
-{14482, 18, 18034, {1, 1, 5, 1, 31, 3, 115, 217, 451, 5, 1447, 2317, 1725, 12931, 25799, 23569, 51747, 28821}},
-{14483, 18, 18061, {1, 3, 7, 3, 31, 55, 109, 107, 211, 381, 1067, 3973, 5007, 8939, 8605, 55221, 124603, 47115}},
-{14484, 18, 18070, {1, 1, 1, 11, 19, 13, 99, 241, 103, 711, 1823, 2671, 653, 10217, 14195, 39735, 54807, 105599}},
-{14485, 18, 18079, {1, 3, 3, 7, 9, 33, 43, 131, 493, 141, 827, 2909, 2847, 12879, 7879, 6263, 25981, 57323}},
-{14486, 18, 18132, {1, 1, 1, 1, 1, 41, 55, 175, 479, 725, 157, 3403, 5809, 10685, 20433, 21729, 9493, 205685}},
-{14487, 18, 18145, {1, 1, 7, 5, 1, 33, 31, 245, 109, 711, 1047, 941, 449, 1055, 16249, 45211, 48311, 171339}},
-{14488, 18, 18169, {1, 3, 3, 9, 27, 9, 113, 69, 269, 643, 1371, 3521, 4969, 5373, 11133, 63109, 42725, 126969}},
-{14489, 18, 18170, {1, 1, 5, 15, 9, 21, 1, 195, 421, 429, 1103, 2727, 463, 9801, 8955, 62841, 94687, 114509}},
-{14490, 18, 18190, {1, 1, 5, 5, 5, 47, 9, 221, 59, 115, 359, 1147, 749, 1009, 23129, 641, 39471, 23073}},
-{14491, 18, 18192, {1, 3, 5, 13, 27, 29, 19, 3, 121, 773, 625, 2757, 6377, 15867, 14563, 40391, 4351, 21153}},
-{14492, 18, 18201, {1, 1, 5, 9, 11, 25, 51, 101, 273, 541, 1761, 593, 7111, 4369, 30095, 34867, 103989, 19855}},
-{14493, 18, 18228, {1, 1, 3, 13, 27, 55, 79, 115, 105, 855, 627, 2227, 2927, 8757, 8713, 54607, 43671, 130153}},
-{14494, 18, 18243, {1, 1, 3, 5, 7, 45, 21, 71, 157, 773, 1265, 841, 2463, 2217, 6087, 28683, 21251, 72377}},
-{14495, 18, 18260, {1, 1, 3, 1, 15, 11, 117, 211, 223, 713, 545, 907, 6907, 41, 17039, 23079, 86657, 5765}},
-{14496, 18, 18279, {1, 1, 5, 3, 27, 33, 77, 137, 401, 585, 911, 1189, 2749, 3427, 2701, 2453, 84857, 176585}},
-{14497, 18, 18285, {1, 1, 1, 3, 7, 39, 73, 143, 29, 569, 939, 301, 7827, 7691, 11513, 64517, 113679, 234165}},
-{14498, 18, 18297, {1, 3, 1, 11, 29, 57, 127, 181, 175, 973, 1537, 761, 5205, 13641, 32649, 8621, 77509, 261235}},
-{14499, 18, 18300, {1, 3, 5, 5, 13, 19, 117, 225, 477, 297, 1807, 2357, 5653, 3791, 6325, 54877, 120659, 91013}},
-{14500, 18, 18321, {1, 3, 1, 1, 3, 55, 19, 99, 321, 877, 541, 511, 141, 15047, 26377, 9, 2765, 223533}},
-{14501, 18, 18344, {1, 1, 1, 11, 13, 59, 121, 147, 215, 117, 1047, 3055, 2129, 15191, 14425, 28327, 108541, 114275}},
-{14502, 18, 18358, {1, 1, 1, 15, 3, 21, 105, 61, 501, 899, 195, 2745, 5989, 4433, 19525, 35477, 22997, 241657}},
-{14503, 18, 18364, {1, 1, 3, 5, 19, 47, 77, 247, 413, 317, 1255, 2087, 4493, 2211, 9003, 22145, 94001, 50579}},
-{14504, 18, 18376, {1, 3, 7, 11, 31, 47, 25, 191, 65, 409, 1349, 2481, 7619, 223, 18051, 63609, 77187, 75483}},
-{14505, 18, 18390, {1, 1, 1, 9, 21, 59, 115, 251, 401, 91, 627, 3273, 2393, 2949, 11475, 23669, 16171, 77507}},
-{14506, 18, 18399, {1, 3, 5, 1, 19, 7, 65, 253, 217, 493, 227, 3269, 4261, 2295, 32037, 5773, 12925, 41821}},
-{14507, 18, 18400, {1, 1, 5, 11, 5, 31, 71, 205, 285, 37, 1863, 1873, 191, 16137, 2955, 51993, 91401, 206967}},
-{14508, 18, 18427, {1, 3, 1, 7, 23, 31, 21, 81, 37, 903, 817, 3447, 8067, 3087, 25831, 46247, 77255, 68365}},
-{14509, 18, 18443, {1, 1, 7, 11, 7, 43, 21, 243, 431, 633, 2047, 577, 7297, 8151, 15951, 30313, 121569, 241687}},
-{14510, 18, 18487, {1, 1, 3, 5, 7, 45, 35, 189, 381, 849, 1869, 1193, 6815, 9017, 29053, 63605, 113623, 249097}},
-{14511, 18, 18493, {1, 3, 3, 11, 13, 1, 73, 151, 197, 591, 1101, 2437, 6695, 8337, 26539, 40147, 45673, 57727}},
-{14512, 18, 18508, {1, 1, 5, 1, 19, 15, 61, 151, 37, 893, 1819, 2317, 6299, 13097, 5109, 32613, 123685, 128173}},
-{14513, 18, 18532, {1, 1, 1, 7, 25, 29, 29, 203, 179, 211, 1483, 3315, 7125, 6931, 609, 849, 117571, 26829}},
-{14514, 18, 18535, {1, 3, 3, 11, 11, 47, 33, 101, 181, 431, 183, 2777, 5269, 4177, 15727, 717, 111243, 34825}},
-{14515, 18, 18580, {1, 3, 5, 11, 17, 19, 19, 143, 137, 537, 1249, 2889, 1911, 3895, 15433, 60165, 83815, 205569}},
-{14516, 18, 18587, {1, 3, 3, 7, 9, 59, 13, 159, 307, 625, 1, 2887, 3307, 16371, 4269, 56253, 71171, 55543}},
-{14517, 18, 18606, {1, 1, 1, 11, 7, 63, 15, 53, 409, 7, 1317, 473, 7481, 10321, 27941, 4941, 40003, 194153}},
-{14518, 18, 18659, {1, 1, 1, 1, 11, 53, 93, 157, 289, 231, 31, 273, 8131, 7861, 31041, 55221, 58305, 203403}},
-{14519, 18, 18662, {1, 1, 5, 11, 15, 53, 103, 41, 439, 601, 1949, 1087, 4275, 4675, 31879, 40909, 22365, 124781}},
-{14520, 18, 18679, {1, 3, 5, 9, 1, 47, 81, 47, 197, 499, 329, 2387, 5455, 15571, 2289, 44121, 12105, 11883}},
-{14521, 18, 18694, {1, 1, 3, 3, 7, 47, 93, 33, 265, 149, 845, 723, 7783, 6651, 22939, 58027, 66959, 3991}},
-{14522, 18, 18697, {1, 1, 5, 11, 23, 35, 123, 143, 35, 981, 1269, 2853, 4547, 7877, 16181, 17155, 57605, 11589}},
-{14523, 18, 18706, {1, 1, 7, 11, 9, 57, 87, 151, 333, 743, 1939, 3273, 1047, 5033, 16061, 37237, 12013, 17669}},
-{14524, 18, 18708, {1, 3, 7, 5, 29, 15, 109, 185, 51, 159, 1353, 3041, 7821, 14053, 13643, 62045, 78475, 43603}},
-{14525, 18, 18728, {1, 3, 1, 9, 29, 25, 121, 49, 415, 561, 325, 1139, 1993, 6437, 6025, 25225, 20761, 250589}},
-{14526, 18, 18731, {1, 3, 5, 3, 15, 39, 33, 43, 437, 605, 1081, 2397, 3821, 10961, 4853, 19517, 95817, 142023}},
-{14527, 18, 18733, {1, 1, 3, 11, 23, 51, 119, 13, 227, 981, 2017, 3265, 1215, 8737, 10719, 48027, 43239, 19425}},
-{14528, 18, 18751, {1, 3, 1, 15, 5, 5, 33, 175, 509, 611, 451, 2653, 1553, 1941, 25221, 31259, 6027, 159847}},
-{14529, 18, 18766, {1, 3, 7, 11, 7, 25, 71, 61, 89, 775, 609, 2363, 4261, 10677, 1243, 44895, 49113, 209603}},
-{14530, 18, 18773, {1, 3, 5, 15, 23, 23, 3, 15, 489, 455, 1303, 745, 5311, 1639, 18317, 33729, 119303, 255359}},
-{14531, 18, 18796, {1, 3, 7, 5, 13, 53, 29, 127, 159, 67, 469, 1735, 3497, 6985, 24735, 32957, 1225, 24447}},
-{14532, 18, 18811, {1, 3, 5, 5, 9, 13, 119, 83, 387, 777, 361, 3183, 6351, 9071, 13699, 53873, 54663, 67453}},
-{14533, 18, 18823, {1, 1, 5, 9, 17, 33, 9, 159, 143, 193, 1055, 2903, 2719, 12521, 5231, 37639, 94963, 105673}},
-{14534, 18, 18832, {1, 3, 3, 1, 27, 53, 87, 49, 465, 517, 1333, 411, 4089, 9985, 12989, 59511, 49939, 223481}},
-{14535, 18, 18854, {1, 1, 5, 9, 27, 59, 35, 125, 393, 271, 1565, 2847, 8139, 15627, 16059, 55319, 11131, 35141}},
-{14536, 18, 18858, {1, 1, 1, 1, 25, 1, 27, 195, 113, 539, 1281, 2273, 4793, 695, 25599, 41145, 107431, 160137}},
-{14537, 18, 18883, {1, 3, 3, 7, 13, 7, 35, 137, 83, 995, 1671, 1701, 3157, 15583, 7637, 18947, 59675, 9421}},
-{14538, 18, 18900, {1, 1, 7, 15, 23, 37, 109, 93, 377, 885, 1843, 1867, 2013, 10535, 5717, 55463, 18307, 125537}},
-{14539, 18, 18967, {1, 3, 7, 11, 25, 33, 91, 213, 109, 599, 131, 1879, 1375, 2911, 4649, 8809, 41199, 61629}},
-{14540, 18, 18974, {1, 3, 1, 1, 11, 17, 117, 243, 427, 913, 495, 527, 4277, 8867, 3131, 14143, 81677, 177369}},
-{14541, 18, 18990, {1, 3, 7, 11, 11, 37, 71, 185, 487, 161, 1773, 837, 243, 14105, 6881, 2155, 63679, 220387}},
-{14542, 18, 19009, {1, 1, 5, 3, 11, 41, 33, 99, 495, 757, 1083, 1987, 1997, 11057, 18445, 61903, 78163, 121701}},
-{14543, 18, 19055, {1, 1, 1, 1, 23, 37, 9, 19, 411, 11, 1487, 1279, 2129, 7449, 29631, 34559, 129753, 112627}},
-{14544, 18, 19058, {1, 1, 3, 11, 31, 39, 41, 207, 141, 383, 723, 3053, 743, 4479, 12395, 56659, 130303, 152005}},
-{14545, 18, 19074, {1, 3, 1, 7, 27, 25, 19, 37, 29, 781, 1115, 2569, 4113, 14033, 18653, 1055, 50639, 70413}},
-{14546, 18, 19079, {1, 1, 3, 1, 9, 15, 109, 7, 221, 161, 569, 2915, 2717, 2439, 4257, 61851, 113183, 63139}},
-{14547, 18, 19086, {1, 3, 5, 1, 17, 45, 3, 147, 207, 769, 321, 11, 2747, 7189, 8067, 34951, 50851, 42625}},
-{14548, 18, 19128, {1, 1, 7, 11, 15, 53, 117, 161, 219, 937, 1661, 3767, 959, 10351, 26685, 40095, 109821, 140139}},
-{14549, 18, 19145, {1, 3, 3, 9, 15, 47, 61, 35, 289, 743, 1723, 2189, 749, 13499, 22897, 55385, 114953, 67191}},
-{14550, 18, 19163, {1, 3, 7, 3, 23, 19, 123, 217, 393, 889, 1665, 13, 5663, 8695, 29767, 13433, 65133, 226713}},
-{14551, 18, 19175, {1, 1, 7, 11, 5, 57, 59, 171, 321, 519, 1333, 1975, 5331, 2383, 26863, 8989, 82167, 6915}},
-{14552, 18, 19189, {1, 1, 3, 3, 7, 17, 105, 79, 7, 827, 1277, 3805, 5943, 3161, 28953, 15657, 615, 149131}},
-{14553, 18, 19196, {1, 1, 5, 1, 5, 7, 99, 65, 295, 933, 365, 1867, 1959, 10733, 26947, 29659, 121889, 200379}},
-{14554, 18, 19204, {1, 3, 1, 13, 25, 21, 89, 247, 251, 43, 1539, 1317, 1875, 9237, 20693, 58433, 16757, 25451}},
-{14555, 18, 19213, {1, 3, 3, 13, 11, 47, 73, 21, 467, 337, 1881, 2723, 7023, 2767, 12553, 65533, 20517, 203749}},
-{14556, 18, 19237, {1, 1, 1, 1, 1, 17, 85, 133, 369, 577, 71, 859, 8151, 919, 10843, 44017, 10097, 199893}},
-{14557, 18, 19276, {1, 3, 5, 5, 23, 19, 21, 233, 475, 123, 621, 687, 6945, 2373, 6447, 31243, 3525, 256545}},
-{14558, 18, 19287, {1, 1, 7, 5, 9, 5, 35, 21, 33, 353, 1429, 3249, 6159, 8757, 6213, 855, 75863, 74507}},
-{14559, 18, 19291, {1, 1, 5, 11, 29, 21, 45, 155, 369, 769, 1041, 3929, 7377, 1621, 5285, 55213, 66143, 110251}},
-{14560, 18, 19293, {1, 3, 7, 11, 13, 57, 45, 207, 259, 907, 573, 663, 7727, 12677, 5949, 57625, 42183, 217491}},
-{14561, 18, 19304, {1, 3, 5, 3, 21, 63, 113, 159, 87, 551, 1405, 2867, 239, 10941, 27633, 13947, 69689, 225771}},
-{14562, 18, 19371, {1, 1, 3, 1, 1, 59, 5, 41, 125, 707, 1457, 1, 4263, 5519, 26101, 46339, 44949, 63689}},
-{14563, 18, 19379, {1, 1, 1, 1, 11, 9, 65, 155, 3, 85, 273, 2287, 6059, 3289, 19045, 14705, 112465, 202019}},
-{14564, 18, 19381, {1, 3, 3, 3, 21, 49, 95, 75, 479, 519, 1511, 1609, 2421, 14435, 11749, 49627, 16221, 98351}},
-{14565, 18, 19405, {1, 1, 3, 5, 25, 57, 1, 39, 377, 523, 529, 701, 6749, 10109, 15845, 53301, 70979, 210997}},
-{14566, 18, 19417, {1, 3, 1, 3, 27, 29, 101, 87, 361, 1, 229, 2653, 769, 16121, 18221, 31937, 12187, 63801}},
-{14567, 18, 19420, {1, 3, 3, 1, 25, 27, 49, 235, 309, 23, 1625, 589, 1251, 10305, 26943, 38949, 82539, 135491}},
-{14568, 18, 19424, {1, 1, 7, 7, 13, 13, 13, 61, 509, 73, 201, 2309, 1601, 3145, 19867, 5623, 117455, 180681}},
-{14569, 18, 19462, {1, 3, 3, 13, 13, 47, 71, 9, 123, 719, 701, 353, 1877, 3103, 20017, 64731, 72729, 147631}},
-{14570, 18, 19474, {1, 3, 1, 7, 29, 29, 53, 97, 409, 67, 1033, 2403, 2471, 10869, 2837, 43459, 117415, 213371}},
-{14571, 18, 19492, {1, 1, 7, 1, 7, 23, 103, 157, 315, 335, 375, 3493, 4095, 5331, 7773, 64173, 23167, 21259}},
-{14572, 18, 19501, {1, 3, 5, 13, 13, 55, 107, 147, 447, 281, 401, 1897, 7887, 15005, 21645, 26007, 19673, 238931}},
-{14573, 18, 19504, {1, 3, 1, 7, 17, 39, 109, 113, 143, 59, 1095, 225, 1455, 5021, 5011, 2039, 4381, 219847}},
-{14574, 18, 19516, {1, 3, 3, 7, 1, 35, 121, 145, 297, 251, 1153, 1955, 7881, 15461, 26961, 915, 30253, 15289}},
-{14575, 18, 19519, {1, 3, 5, 15, 5, 57, 43, 157, 49, 17, 993, 4085, 5639, 9405, 28661, 30191, 73291, 76913}},
-{14576, 18, 19534, {1, 1, 7, 1, 25, 63, 117, 55, 63, 649, 1635, 2505, 2765, 2715, 30241, 62699, 19567, 65953}},
-{14577, 18, 19555, {1, 3, 5, 13, 21, 49, 111, 127, 179, 819, 1737, 2519, 815, 10541, 15821, 54203, 71767, 7091}},
-{14578, 18, 19597, {1, 1, 1, 3, 27, 41, 101, 139, 39, 995, 819, 319, 1481, 15265, 20611, 22445, 53733, 82871}},
-{14579, 18, 19600, {1, 3, 3, 13, 7, 61, 103, 203, 353, 205, 1927, 2665, 757, 12277, 31217, 22247, 14527, 26385}},
-{14580, 18, 19615, {1, 1, 7, 3, 5, 35, 87, 235, 139, 785, 417, 3975, 6753, 4267, 15201, 8747, 12491, 159979}},
-{14581, 18, 19621, {1, 3, 1, 9, 9, 11, 117, 231, 503, 933, 1461, 2657, 7771, 2161, 26723, 4853, 23215, 162315}},
-{14582, 18, 19646, {1, 1, 7, 15, 27, 25, 115, 9, 257, 89, 571, 41, 2169, 10619, 2695, 2107, 64747, 40489}},
-{14583, 18, 19651, {1, 3, 7, 9, 29, 61, 91, 117, 279, 721, 233, 177, 5509, 7599, 2379, 20297, 75425, 25051}},
-{14584, 18, 19693, {1, 1, 1, 15, 31, 41, 3, 57, 59, 47, 963, 2831, 1885, 1989, 26803, 48243, 112065, 27753}},
-{14585, 18, 19702, {1, 1, 5, 15, 9, 57, 41, 255, 179, 719, 1463, 2857, 285, 9623, 13111, 20415, 28819, 149441}},
-{14586, 18, 19726, {1, 3, 1, 9, 17, 63, 21, 79, 473, 525, 1557, 3205, 7097, 14379, 28039, 30731, 62383, 247429}},
-{14587, 18, 19754, {1, 3, 3, 13, 25, 45, 97, 213, 11, 801, 1519, 1085, 6167, 13701, 6707, 47223, 69923, 66239}},
-{14588, 18, 19759, {1, 1, 1, 13, 1, 1, 9, 21, 363, 729, 1715, 1249, 5299, 11357, 20627, 33559, 84255, 133743}},
-{14589, 18, 19764, {1, 3, 3, 13, 17, 33, 23, 255, 309, 605, 1177, 1305, 2717, 6561, 29193, 7971, 117525, 79139}},
-{14590, 18, 19788, {1, 3, 1, 1, 7, 15, 73, 171, 11, 791, 241, 2641, 5397, 10403, 22207, 64123, 124507, 63855}},
-{14591, 18, 19793, {1, 3, 1, 11, 11, 7, 109, 103, 321, 1009, 1237, 3347, 287, 2389, 16529, 7789, 3347, 97827}},
-{14592, 18, 19836, {1, 3, 3, 3, 1, 27, 17, 9, 223, 755, 559, 3811, 2997, 1543, 23197, 42371, 5837, 13809}},
-{14593, 18, 19855, {1, 3, 1, 3, 7, 57, 31, 23, 35, 329, 1155, 2525, 3029, 5495, 12005, 18045, 4539, 75789}},
-{14594, 18, 19858, {1, 1, 5, 13, 3, 31, 121, 161, 325, 869, 715, 851, 1273, 1871, 22711, 61499, 36291, 11663}},
-{14595, 18, 19880, {1, 1, 5, 11, 7, 39, 23, 139, 197, 47, 513, 373, 6859, 11217, 17725, 60949, 19299, 91425}},
-{14596, 18, 19883, {1, 1, 3, 7, 15, 63, 123, 11, 109, 829, 231, 2591, 7997, 9061, 18647, 3209, 38509, 211219}},
-{14597, 18, 19917, {1, 1, 1, 11, 13, 35, 73, 223, 325, 49, 1317, 4063, 4127, 2755, 555, 51057, 44909, 205723}},
-{14598, 18, 19918, {1, 3, 3, 13, 17, 41, 115, 141, 503, 525, 63, 2487, 3225, 959, 10623, 28577, 89127, 157269}},
-{14599, 18, 19936, {1, 3, 1, 9, 25, 9, 43, 43, 279, 111, 1141, 3033, 7229, 5725, 8277, 59141, 116811, 127945}},
-{14600, 18, 19946, {1, 3, 7, 11, 27, 27, 93, 243, 135, 333, 1475, 1259, 1583, 7191, 6831, 53485, 128819, 174211}},
-{14601, 18, 19954, {1, 3, 3, 3, 17, 17, 43, 251, 433, 1011, 1817, 2835, 7721, 2449, 9463, 23779, 31427, 88127}},
-{14602, 18, 19979, {1, 1, 3, 3, 11, 49, 61, 41, 211, 559, 1761, 1303, 2119, 5743, 25515, 60705, 54405, 241063}},
-{14603, 18, 19993, {1, 1, 3, 11, 7, 61, 15, 115, 29, 35, 187, 3137, 6177, 1449, 32723, 15917, 107851, 101077}},
-{14604, 18, 19994, {1, 3, 5, 13, 21, 7, 11, 231, 417, 73, 1175, 735, 627, 7393, 7233, 39883, 129481, 106733}},
-{14605, 18, 20006, {1, 3, 1, 15, 27, 61, 63, 201, 27, 431, 1127, 1555, 1953, 13051, 18701, 30097, 95549, 198465}},
-{14606, 18, 20017, {1, 1, 3, 1, 23, 25, 43, 85, 291, 85, 1861, 675, 7451, 14701, 3929, 10835, 25569, 154687}},
-{14607, 18, 20032, {1, 3, 7, 15, 5, 43, 91, 225, 283, 259, 1311, 3977, 585, 14803, 14117, 2121, 106981, 157577}},
-{14608, 18, 20038, {1, 1, 1, 11, 7, 51, 49, 115, 477, 861, 1115, 743, 5109, 959, 7105, 9245, 66297, 188751}},
-{14609, 18, 20050, {1, 3, 3, 11, 23, 1, 11, 111, 163, 643, 1907, 3613, 2967, 10071, 6023, 1307, 62341, 241025}},
-{14610, 18, 20080, {1, 3, 5, 5, 15, 29, 31, 43, 445, 219, 1261, 421, 6035, 6461, 25583, 817, 100509, 239637}},
-{14611, 18, 20135, {1, 1, 7, 3, 27, 51, 121, 93, 349, 125, 2013, 1671, 8049, 7807, 7291, 64413, 93625, 245611}},
-{14612, 18, 20142, {1, 3, 3, 9, 11, 1, 91, 137, 501, 617, 1513, 799, 1705, 15737, 14989, 53611, 48781, 64481}},
-{14613, 18, 20159, {1, 3, 3, 1, 21, 55, 95, 79, 383, 617, 1589, 2671, 4057, 13525, 9269, 23539, 13317, 87701}},
-{14614, 18, 20173, {1, 1, 3, 1, 29, 17, 121, 45, 91, 215, 325, 2853, 1213, 10221, 7233, 34063, 21887, 142943}},
-{14615, 18, 20186, {1, 3, 3, 11, 27, 53, 55, 149, 107, 379, 441, 585, 5697, 16353, 5613, 4323, 55315, 197603}},
-{14616, 18, 20229, {1, 3, 7, 3, 31, 9, 71, 175, 485, 35, 675, 2091, 2351, 7985, 14207, 52687, 8559, 1067}},
-{14617, 18, 20234, {1, 1, 5, 15, 29, 37, 9, 73, 357, 961, 489, 875, 7465, 3231, 27821, 42499, 127837, 117215}},
-{14618, 18, 20263, {1, 3, 7, 7, 19, 43, 75, 153, 27, 291, 2039, 2661, 5513, 13429, 27307, 5305, 44771, 200621}},
-{14619, 18, 20270, {1, 1, 1, 15, 5, 39, 61, 107, 201, 485, 319, 335, 5537, 14195, 31861, 63637, 68497, 45637}},
-{14620, 18, 20299, {1, 3, 7, 7, 23, 49, 95, 225, 25, 933, 667, 2993, 2181, 15659, 31343, 20249, 57039, 43399}},
-{14621, 18, 20304, {1, 3, 3, 7, 17, 25, 29, 243, 511, 91, 1409, 203, 2749, 7067, 12471, 41737, 32761, 7535}},
-{14622, 18, 20319, {1, 1, 7, 9, 27, 43, 63, 65, 325, 817, 1127, 2039, 6171, 5867, 10593, 17205, 95913, 207417}},
-{14623, 18, 20329, {1, 1, 7, 3, 3, 51, 107, 153, 193, 579, 593, 2915, 7641, 5157, 1131, 29793, 66579, 81903}},
-{14624, 18, 20337, {1, 1, 5, 15, 19, 61, 125, 107, 235, 513, 1897, 875, 6341, 1817, 10631, 63905, 42993, 150699}},
-{14625, 18, 20353, {1, 1, 3, 11, 27, 1, 93, 107, 325, 459, 1733, 2527, 4557, 2277, 19345, 8205, 67337, 242559}},
-{14626, 18, 20401, {1, 1, 7, 3, 3, 45, 27, 227, 201, 99, 589, 1665, 4851, 2655, 9915, 41321, 59865, 71501}},
-{14627, 18, 20434, {1, 3, 1, 9, 3, 25, 117, 199, 125, 849, 135, 1771, 4743, 13475, 23711, 17389, 52711, 200143}},
-{14628, 18, 20436, {1, 3, 1, 3, 11, 23, 67, 155, 133, 557, 1933, 3169, 1707, 16045, 11039, 13889, 71045, 245885}},
-{14629, 18, 20473, {1, 1, 5, 9, 1, 7, 99, 13, 315, 251, 1289, 225, 2847, 8451, 3139, 46829, 124745, 64825}},
-{14630, 18, 20488, {1, 3, 7, 13, 19, 45, 87, 161, 271, 401, 1995, 935, 1803, 4051, 11709, 26993, 120139, 147895}},
-{14631, 18, 20512, {1, 1, 7, 5, 15, 11, 47, 215, 51, 1019, 2039, 3767, 929, 3845, 3939, 64077, 48115, 61845}},
-{14632, 18, 20515, {1, 1, 1, 5, 1, 39, 15, 77, 179, 13, 1099, 203, 3363, 9071, 12033, 49159, 71137, 124177}},
-{14633, 18, 20517, {1, 3, 5, 5, 1, 31, 83, 219, 387, 347, 1099, 925, 4423, 5081, 15981, 35881, 79131, 248301}},
-{14634, 18, 20530, {1, 3, 7, 3, 25, 19, 53, 43, 347, 845, 1735, 3237, 2795, 2253, 2997, 43729, 122833, 124869}},
-{14635, 18, 20571, {1, 3, 5, 11, 5, 19, 93, 55, 297, 231, 239, 3335, 253, 13607, 16769, 48879, 61439, 54827}},
-{14636, 18, 20574, {1, 3, 7, 11, 11, 55, 121, 73, 19, 1017, 727, 579, 8011, 9559, 15051, 7895, 17609, 103061}},
-{14637, 18, 20589, {1, 1, 7, 5, 19, 47, 85, 195, 75, 1003, 439, 3069, 2107, 12751, 26729, 2329, 1191, 86547}},
-{14638, 18, 20592, {1, 3, 3, 9, 5, 31, 63, 227, 481, 793, 1853, 1491, 2109, 4199, 32149, 45229, 54685, 124819}},
-{14639, 18, 20611, {1, 1, 1, 3, 15, 15, 41, 45, 153, 429, 1691, 1897, 7253, 7239, 26133, 36527, 90319, 186097}},
-{14640, 18, 20613, {1, 3, 1, 13, 15, 33, 103, 113, 121, 387, 177, 1943, 3181, 5483, 18515, 38807, 22655, 59787}},
-{14641, 18, 20628, {1, 1, 5, 7, 15, 3, 53, 155, 99, 133, 579, 2129, 6881, 11091, 26715, 15485, 108071, 230881}},
-{14642, 18, 20637, {1, 1, 3, 13, 25, 61, 91, 81, 9, 1011, 1993, 2485, 3707, 11127, 21279, 15853, 104081, 203769}},
-{14643, 18, 20638, {1, 1, 7, 3, 17, 23, 37, 171, 315, 247, 275, 3215, 7139, 11739, 25859, 34803, 124601, 9169}},
-{14644, 18, 20719, {1, 3, 7, 9, 21, 29, 97, 213, 309, 865, 597, 1811, 5547, 3741, 31927, 53379, 43293, 23589}},
-{14645, 18, 20724, {1, 3, 7, 9, 7, 43, 107, 187, 485, 977, 1329, 3037, 3701, 9667, 13581, 6283, 39221, 63841}},
-{14646, 18, 20772, {1, 1, 3, 11, 3, 51, 117, 45, 293, 409, 689, 153, 1163, 10921, 22709, 30415, 120475, 120751}},
-{14647, 18, 20796, {1, 3, 5, 15, 31, 59, 57, 63, 249, 763, 1627, 3039, 4309, 14115, 25489, 35009, 126609, 146041}},
-{14648, 18, 20799, {1, 1, 1, 9, 3, 47, 21, 183, 495, 361, 1439, 407, 5757, 12645, 11425, 1923, 94511, 205127}},
-{14649, 18, 20816, {1, 3, 1, 9, 15, 5, 101, 107, 385, 175, 791, 901, 4427, 10415, 8163, 14417, 62997, 139309}},
-{14650, 18, 20841, {1, 3, 5, 3, 13, 57, 9, 99, 77, 123, 1607, 3643, 3879, 503, 6021, 60211, 106471, 221801}},
-{14651, 18, 20844, {1, 1, 7, 5, 27, 35, 11, 33, 415, 387, 1461, 741, 55, 15095, 21177, 5715, 109893, 204843}},
-{14652, 18, 20862, {1, 1, 1, 15, 7, 49, 51, 81, 157, 421, 279, 1951, 6847, 10259, 31925, 60761, 12395, 49511}},
-{14653, 18, 20865, {1, 3, 7, 11, 5, 33, 27, 135, 247, 813, 1889, 2547, 2359, 9535, 4141, 59713, 88685, 214641}},
-{14654, 18, 20902, {1, 1, 5, 15, 17, 61, 99, 103, 39, 151, 1033, 2743, 6639, 5271, 22059, 12681, 22763, 88255}},
-{14655, 18, 20938, {1, 1, 7, 13, 5, 11, 39, 139, 353, 989, 1391, 169, 3709, 735, 22965, 227, 103623, 153893}},
-{14656, 18, 20957, {1, 1, 7, 3, 9, 51, 53, 87, 411, 617, 671, 681, 5057, 6003, 23137, 30881, 2289, 187133}},
-{14657, 18, 20971, {1, 1, 7, 7, 17, 59, 77, 219, 25, 53, 145, 129, 4289, 14257, 7159, 44833, 22131, 53393}},
-{14658, 18, 20973, {1, 3, 7, 1, 9, 59, 79, 177, 149, 637, 1641, 3713, 2709, 12321, 5691, 18239, 8617, 225979}},
-{14659, 18, 20981, {1, 1, 7, 5, 9, 9, 67, 51, 451, 815, 295, 813, 1257, 179, 28769, 57241, 51753, 164873}},
-{14660, 18, 20982, {1, 3, 1, 9, 19, 61, 53, 65, 29, 503, 715, 1837, 7487, 16187, 27303, 54681, 98753, 100471}},
-{14661, 18, 20985, {1, 1, 3, 1, 15, 51, 1, 79, 179, 367, 841, 1313, 797, 4777, 1369, 13317, 65059, 204877}},
-{14662, 18, 20991, {1, 3, 5, 9, 15, 19, 109, 45, 473, 517, 1139, 15, 1997, 4245, 11169, 56417, 75017, 37957}},
-{14663, 18, 21012, {1, 1, 7, 1, 3, 41, 75, 95, 59, 503, 1439, 2633, 3527, 5363, 24357, 43659, 10387, 208319}},
-{14664, 18, 21022, {1, 1, 5, 1, 31, 7, 71, 231, 505, 241, 1579, 3517, 3995, 8269, 6793, 15883, 102779, 75589}},
-{14665, 18, 21026, {1, 3, 5, 1, 13, 61, 87, 213, 501, 307, 1629, 2715, 7245, 747, 20601, 28105, 79249, 76231}},
-{14666, 18, 21028, {1, 1, 7, 11, 5, 13, 69, 221, 485, 59, 2027, 483, 6851, 11719, 16787, 54111, 47579, 49959}},
-{14667, 18, 21050, {1, 1, 3, 15, 3, 33, 57, 75, 375, 45, 851, 1673, 8167, 867, 32087, 34157, 96701, 72893}},
-{14668, 18, 21075, {1, 1, 3, 1, 21, 31, 65, 85, 181, 453, 815, 3139, 205, 429, 7451, 50855, 41085, 137927}},
-{14669, 18, 21077, {1, 3, 1, 9, 3, 57, 99, 183, 305, 991, 809, 4021, 3131, 4459, 5839, 32493, 116541, 59329}},
-{14670, 18, 21078, {1, 3, 7, 1, 5, 19, 3, 91, 297, 715, 1081, 445, 393, 12685, 4457, 61437, 103701, 75917}},
-{14671, 18, 21106, {1, 1, 7, 15, 17, 39, 19, 255, 247, 391, 1055, 1241, 4515, 10217, 23363, 40301, 115053, 234349}},
-{14672, 18, 21122, {1, 3, 5, 1, 21, 9, 33, 243, 501, 793, 219, 3595, 2585, 5083, 15377, 35761, 90609, 93761}},
-{14673, 18, 21127, {1, 1, 5, 13, 3, 1, 5, 77, 265, 525, 1107, 1879, 1119, 2277, 30557, 43547, 81947, 134075}},
-{14674, 18, 21155, {1, 1, 7, 5, 11, 47, 71, 83, 255, 183, 515, 2591, 3933, 16025, 16727, 43421, 18725, 106675}},
-{14675, 18, 21167, {1, 3, 1, 1, 5, 17, 57, 209, 509, 421, 1247, 3153, 1835, 8777, 13285, 27699, 34001, 186553}},
-{14676, 18, 21169, {1, 1, 3, 11, 27, 19, 73, 65, 179, 115, 845, 2507, 7673, 14429, 10553, 4999, 82323, 247379}},
-{14677, 18, 21204, {1, 3, 7, 7, 17, 59, 97, 183, 407, 697, 1423, 123, 6479, 3997, 729, 31587, 114383, 61673}},
-{14678, 18, 21230, {1, 1, 5, 9, 21, 23, 21, 153, 187, 255, 125, 1469, 2639, 8099, 29689, 36415, 103959, 231621}},
-{14679, 18, 21256, {1, 1, 3, 11, 19, 59, 115, 205, 123, 133, 1953, 3471, 2495, 329, 32385, 21931, 9691, 51405}},
-{14680, 18, 21285, {1, 3, 3, 13, 7, 7, 115, 65, 301, 621, 1091, 2137, 5729, 5027, 21331, 24803, 114789, 142039}},
-{14681, 18, 21312, {1, 1, 7, 5, 31, 19, 103, 69, 503, 663, 1497, 2867, 5295, 893, 15927, 37513, 94553, 72369}},
-{14682, 18, 21329, {1, 3, 3, 15, 17, 33, 99, 249, 277, 259, 9, 99, 3073, 12017, 14847, 7685, 102499, 26489}},
-{14683, 18, 21351, {1, 1, 1, 1, 5, 23, 31, 45, 29, 483, 1977, 1129, 6925, 2273, 16573, 53039, 90251, 137191}},
-{14684, 18, 21372, {1, 3, 1, 13, 27, 47, 29, 51, 473, 895, 671, 3917, 6905, 15769, 9019, 28879, 120591, 220753}},
-{14685, 18, 21376, {1, 3, 1, 13, 27, 29, 53, 255, 507, 819, 1251, 2463, 1717, 14461, 31997, 30829, 8803, 115539}},
-{14686, 18, 21424, {1, 3, 3, 15, 27, 1, 109, 225, 451, 409, 2025, 2701, 4121, 9949, 1551, 13625, 73577, 211549}},
-{14687, 18, 21448, {1, 1, 1, 3, 23, 57, 49, 35, 365, 711, 2001, 997, 1853, 2913, 15667, 30255, 19535, 2171}},
-{14688, 18, 21465, {1, 1, 7, 1, 21, 37, 127, 3, 117, 449, 1689, 1391, 1427, 12641, 15199, 23769, 66553, 34669}},
-{14689, 18, 21495, {1, 3, 7, 9, 31, 45, 51, 137, 181, 469, 573, 89, 7257, 10991, 30705, 37827, 75071, 152885}},
-{14690, 18, 21509, {1, 3, 1, 1, 19, 13, 55, 223, 261, 353, 1497, 183, 8173, 14421, 9977, 24095, 47215, 155189}},
-{14691, 18, 21550, {1, 1, 3, 15, 15, 41, 31, 105, 459, 27, 299, 159, 2167, 14809, 9983, 2755, 121715, 35921}},
-{14692, 18, 21562, {1, 1, 3, 7, 31, 5, 85, 137, 431, 849, 1479, 2681, 167, 5727, 3211, 30765, 63295, 39509}},
-{14693, 18, 21575, {1, 1, 5, 7, 5, 51, 21, 103, 175, 927, 1115, 1507, 505, 8093, 25831, 54303, 40397, 61249}},
-{14694, 18, 21579, {1, 1, 7, 3, 23, 53, 49, 225, 7, 425, 403, 3949, 1081, 15335, 21737, 647, 107875, 236183}},
-{14695, 18, 21582, {1, 1, 5, 7, 17, 21, 85, 229, 325, 57, 601, 2785, 6417, 5135, 17917, 12861, 97675, 115457}},
-{14696, 18, 21600, {1, 1, 3, 3, 13, 23, 73, 111, 385, 47, 605, 1169, 1729, 2335, 18739, 61293, 41915, 237645}},
-{14697, 18, 21615, {1, 1, 1, 5, 31, 11, 123, 13, 465, 755, 1073, 1885, 2105, 5971, 2347, 10911, 125823, 156037}},
-{14698, 18, 21617, {1, 3, 7, 11, 17, 47, 3, 165, 227, 355, 87, 839, 7741, 12275, 28579, 25337, 87671, 224847}},
-{14699, 18, 21624, {1, 1, 5, 15, 23, 33, 9, 1, 257, 121, 1049, 1009, 187, 9935, 26093, 21921, 130247, 240291}},
-{14700, 18, 21633, {1, 1, 3, 13, 13, 27, 87, 221, 27, 117, 551, 2533, 7611, 5333, 14635, 9911, 37555, 250621}},
-{14701, 18, 21636, {1, 3, 7, 15, 29, 39, 33, 1, 495, 889, 1397, 3415, 7193, 11533, 27379, 36425, 13739, 146635}},
-{14702, 18, 21645, {1, 1, 7, 11, 1, 23, 85, 127, 79, 989, 321, 1913, 7571, 9889, 11803, 1307, 120513, 218077}},
-{14703, 18, 21654, {1, 1, 7, 5, 5, 15, 35, 9, 351, 973, 1455, 2043, 5527, 9431, 16059, 53915, 105785, 180579}},
-{14704, 18, 21660, {1, 1, 1, 13, 13, 45, 15, 41, 131, 463, 1011, 3559, 6393, 4737, 6041, 33073, 60989, 56761}},
-{14705, 18, 21667, {1, 1, 3, 9, 31, 35, 23, 133, 33, 233, 543, 957, 4913, 12441, 10293, 31611, 83383, 154551}},
-{14706, 18, 21702, {1, 3, 3, 1, 29, 37, 117, 247, 345, 197, 1617, 3333, 7901, 8343, 55, 16529, 34627, 172703}},
-{14707, 18, 21714, {1, 1, 1, 13, 23, 51, 7, 219, 503, 215, 375, 2275, 5467, 13953, 13987, 22735, 67505, 185977}},
-{14708, 18, 21719, {1, 3, 5, 5, 29, 53, 85, 147, 167, 409, 853, 667, 4431, 5227, 15535, 34375, 107135, 220637}},
-{14709, 18, 21736, {1, 3, 7, 7, 19, 3, 73, 123, 455, 539, 1735, 1423, 5337, 16311, 15469, 36071, 126437, 219249}},
-{14710, 18, 21767, {1, 1, 1, 3, 19, 49, 17, 133, 101, 1013, 683, 869, 6267, 409, 31379, 2535, 8039, 63205}},
-{14711, 18, 21781, {1, 1, 1, 13, 13, 53, 25, 31, 501, 629, 645, 1811, 3675, 13317, 17009, 7359, 85475, 249823}},
-{14712, 18, 21795, {1, 1, 3, 11, 5, 1, 41, 17, 159, 361, 1439, 2083, 1425, 7221, 9117, 59543, 59285, 188615}},
-{14713, 18, 21841, {1, 3, 7, 1, 11, 27, 71, 121, 471, 749, 1983, 3715, 6463, 5793, 1063, 18201, 189, 243751}},
-{14714, 18, 21853, {1, 3, 3, 11, 19, 17, 15, 175, 379, 683, 1491, 2385, 6981, 1183, 16829, 2103, 9309, 46119}},
-{14715, 18, 21867, {1, 1, 7, 5, 17, 39, 109, 9, 279, 309, 1, 1523, 4551, 3855, 13277, 36125, 54191, 45085}},
-{14716, 18, 21878, {1, 3, 5, 3, 9, 59, 51, 5, 431, 657, 161, 2725, 2401, 9743, 12925, 43501, 51551, 163737}},
-{14717, 18, 21891, {1, 1, 5, 3, 9, 13, 7, 177, 121, 795, 1169, 3169, 3793, 3995, 29027, 32967, 82273, 207939}},
-{14718, 18, 21897, {1, 3, 7, 13, 1, 1, 31, 91, 245, 775, 1589, 2263, 6303, 15787, 3111, 52553, 52507, 183971}},
-{14719, 18, 21954, {1, 3, 5, 11, 15, 49, 73, 191, 67, 449, 1245, 2445, 5617, 8625, 27971, 35939, 76907, 76207}},
-{14720, 18, 21956, {1, 3, 1, 11, 15, 47, 29, 91, 437, 895, 1941, 249, 2739, 15479, 29699, 7257, 39897, 65985}},
-{14721, 18, 21965, {1, 3, 5, 7, 13, 23, 45, 113, 297, 373, 1505, 2317, 7509, 12059, 13737, 29081, 87337, 221917}},
-{14722, 18, 21977, {1, 3, 3, 3, 1, 5, 13, 215, 221, 461, 1337, 3569, 2257, 12135, 14685, 39721, 16723, 234791}},
-{14723, 18, 21978, {1, 1, 7, 5, 11, 25, 71, 103, 87, 533, 779, 379, 6695, 13451, 24801, 49235, 35109, 100865}},
-{14724, 18, 21983, {1, 3, 3, 15, 13, 51, 27, 11, 279, 847, 135, 1119, 2765, 3805, 20273, 29089, 83379, 190353}},
-{14725, 18, 22002, {1, 3, 7, 5, 17, 29, 111, 35, 189, 273, 503, 541, 6691, 9051, 10403, 7559, 54787, 25403}},
-{14726, 18, 22013, {1, 3, 5, 9, 21, 29, 85, 235, 223, 677, 71, 1313, 6587, 10983, 199, 27721, 78627, 105505}},
-{14727, 18, 22014, {1, 3, 1, 3, 13, 3, 123, 115, 173, 907, 1555, 1489, 2745, 6451, 25347, 24105, 66471, 181009}},
-{14728, 18, 22054, {1, 1, 7, 1, 31, 15, 13, 97, 511, 827, 1193, 3081, 1517, 13511, 24887, 39239, 85175, 150213}},
-{14729, 18, 22058, {1, 1, 1, 5, 17, 39, 121, 67, 207, 877, 1885, 171, 2687, 13081, 27267, 58699, 118575, 213025}},
-{14730, 18, 22066, {1, 1, 3, 9, 9, 27, 101, 215, 31, 37, 1629, 3631, 3225, 9667, 31547, 41939, 38683, 150805}},
-{14731, 18, 22085, {1, 3, 1, 11, 11, 59, 17, 15, 187, 667, 747, 2193, 6749, 6019, 31805, 52433, 4141, 52613}},
-{14732, 18, 22103, {1, 3, 3, 13, 9, 1, 51, 101, 213, 881, 899, 2197, 3017, 1591, 9271, 44017, 99893, 192005}},
-{14733, 18, 22138, {1, 3, 7, 13, 23, 41, 79, 83, 123, 585, 49, 849, 2133, 12473, 6907, 15487, 45783, 46609}},
-{14734, 18, 22140, {1, 3, 7, 13, 27, 23, 71, 13, 319, 903, 1123, 933, 2603, 11631, 19953, 47001, 127751, 84547}},
-{14735, 18, 22153, {1, 1, 1, 15, 3, 61, 79, 231, 43, 217, 801, 997, 6545, 13657, 25589, 30435, 49497, 1037}},
-{14736, 18, 22164, {1, 3, 3, 3, 21, 29, 121, 35, 129, 239, 1645, 3147, 7647, 1201, 19287, 7075, 67961, 62481}},
-{14737, 18, 22167, {1, 3, 7, 7, 3, 23, 45, 177, 469, 897, 359, 2521, 2079, 985, 14993, 56813, 20667, 187341}},
-{14738, 18, 22189, {1, 3, 5, 7, 23, 53, 15, 45, 297, 93, 247, 1165, 2683, 5899, 7113, 14859, 22733, 173835}},
-{14739, 18, 22202, {1, 1, 3, 15, 23, 17, 43, 179, 103, 197, 1857, 323, 267, 12417, 2343, 41527, 12243, 112023}},
-{14740, 18, 22212, {1, 3, 7, 13, 7, 43, 75, 19, 169, 621, 735, 141, 3087, 765, 5901, 34029, 117603, 5137}},
-{14741, 18, 22234, {1, 1, 3, 5, 15, 17, 67, 177, 371, 249, 99, 1651, 3701, 343, 435, 50307, 33915, 115391}},
-{14742, 18, 22239, {1, 1, 3, 13, 19, 53, 69, 1, 435, 71, 339, 2289, 1591, 8783, 8087, 25855, 115311, 191115}},
-{14743, 18, 22245, {1, 3, 5, 11, 1, 55, 59, 7, 101, 655, 353, 483, 5681, 12721, 15973, 51377, 94921, 246365}},
-{14744, 18, 22272, {1, 3, 5, 3, 25, 23, 99, 145, 277, 741, 595, 2653, 1393, 2867, 271, 49131, 111973, 118869}},
-{14745, 18, 22308, {1, 1, 7, 13, 11, 51, 127, 27, 305, 265, 1755, 3189, 4679, 9721, 24409, 46941, 94353, 95643}},
-{14746, 18, 22318, {1, 1, 5, 11, 1, 63, 53, 149, 459, 155, 1431, 3969, 3417, 12121, 14535, 52089, 110745, 57}},
-{14747, 18, 22320, {1, 1, 5, 9, 23, 33, 17, 175, 313, 185, 101, 531, 2941, 14999, 31413, 12103, 33709, 260555}},
-{14748, 18, 22338, {1, 1, 3, 13, 3, 11, 67, 95, 211, 673, 23, 2379, 6985, 12101, 13021, 9255, 116437, 228877}},
-{14749, 18, 22350, {1, 1, 3, 15, 7, 51, 25, 109, 45, 691, 869, 485, 111, 11465, 27953, 54375, 10805, 221023}},
-{14750, 18, 22374, {1, 3, 7, 7, 17, 53, 59, 101, 221, 593, 587, 873, 931, 14617, 12067, 58655, 102437, 31675}},
-{14751, 18, 22388, {1, 1, 3, 15, 25, 57, 35, 231, 491, 671, 933, 3525, 1237, 10155, 27501, 50781, 23183, 108283}},
-{14752, 18, 22391, {1, 3, 5, 5, 31, 63, 117, 205, 199, 841, 1455, 3901, 2127, 13573, 20667, 49489, 60217, 197421}},
-{14753, 18, 22422, {1, 1, 3, 7, 15, 21, 73, 211, 421, 873, 607, 709, 9, 10985, 28653, 64579, 118145, 3095}},
-{14754, 18, 22426, {1, 1, 1, 13, 17, 53, 27, 105, 201, 399, 737, 3235, 1287, 13859, 6049, 62249, 88259, 52991}},
-{14755, 18, 22441, {1, 3, 7, 7, 25, 45, 67, 147, 275, 315, 1675, 2289, 4611, 6325, 26617, 38079, 125219, 23569}},
-{14756, 18, 22481, {1, 1, 7, 7, 9, 61, 115, 251, 297, 691, 1881, 1815, 7229, 10859, 8257, 38097, 87927, 162845}},
-{14757, 18, 22488, {1, 3, 3, 9, 9, 59, 17, 207, 433, 825, 93, 697, 7263, 15983, 14829, 47471, 17579, 151519}},
-{14758, 18, 22500, {1, 1, 1, 11, 21, 31, 7, 41, 383, 731, 2033, 3417, 4187, 5515, 10093, 15875, 78551, 2057}},
-{14759, 18, 22517, {1, 3, 7, 15, 5, 29, 7, 171, 129, 727, 1815, 1361, 6137, 10333, 22203, 361, 92437, 6545}},
-{14760, 18, 22531, {1, 1, 3, 13, 25, 45, 111, 69, 333, 365, 765, 2755, 3485, 2729, 23467, 64809, 120755, 169279}},
-{14761, 18, 22552, {1, 1, 3, 1, 19, 13, 33, 165, 157, 429, 1175, 3435, 7523, 5055, 12295, 34309, 36933, 164037}},
-{14762, 18, 22574, {1, 1, 3, 11, 31, 49, 37, 161, 465, 311, 1839, 689, 6837, 13473, 29883, 61587, 86077, 156921}},
-{14763, 18, 22579, {1, 3, 3, 1, 3, 23, 69, 159, 501, 303, 1495, 9, 6055, 545, 12247, 23413, 67247, 38137}},
-{14764, 18, 22582, {1, 1, 5, 15, 5, 39, 107, 121, 295, 167, 1055, 2703, 147, 7291, 3981, 51989, 92953, 225987}},
-{14765, 18, 22586, {1, 3, 1, 1, 21, 5, 91, 129, 57, 53, 365, 2497, 5017, 13535, 19305, 60447, 115467, 225317}},
-{14766, 18, 22594, {1, 3, 1, 7, 25, 17, 51, 15, 119, 1013, 719, 991, 2655, 12587, 15749, 11723, 18461, 155937}},
-{14767, 18, 22611, {1, 3, 7, 3, 25, 33, 59, 135, 501, 813, 235, 3775, 2781, 13137, 32673, 31643, 78881, 207651}},
-{14768, 18, 22614, {1, 1, 7, 13, 27, 51, 99, 189, 187, 577, 941, 1275, 7297, 14731, 12599, 49049, 96439, 35093}},
-{14769, 18, 22700, {1, 3, 1, 15, 9, 45, 1, 149, 305, 231, 935, 1377, 6345, 14795, 20969, 26263, 5711, 146949}},
-{14770, 18, 22711, {1, 1, 5, 9, 5, 9, 47, 127, 105, 517, 671, 67, 4639, 2477, 23109, 56707, 72131, 100709}},
-{14771, 18, 22749, {1, 3, 5, 3, 21, 23, 7, 193, 491, 197, 319, 3207, 2183, 2133, 3127, 34555, 53707, 170875}},
-{14772, 18, 22759, {1, 1, 3, 9, 5, 23, 109, 91, 359, 913, 179, 1031, 3617, 12497, 23299, 53293, 114603, 9931}},
-{14773, 18, 22774, {1, 3, 1, 5, 1, 47, 73, 103, 333, 483, 1015, 3085, 5229, 3171, 16539, 13493, 68957, 177645}},
-{14774, 18, 22777, {1, 1, 1, 9, 27, 15, 25, 255, 383, 501, 831, 2463, 237, 16065, 6991, 56503, 117303, 140573}},
-{14775, 18, 22780, {1, 1, 3, 5, 9, 25, 15, 179, 415, 729, 1163, 2649, 2907, 9591, 29129, 42775, 80537, 139897}},
-{14776, 18, 22783, {1, 1, 3, 7, 31, 15, 113, 1, 263, 685, 1953, 1479, 5143, 8585, 9057, 61479, 122065, 191541}},
-{14777, 18, 22785, {1, 3, 1, 11, 25, 47, 25, 229, 463, 197, 1123, 2665, 2345, 11701, 10435, 15205, 35437, 137619}},
-{14778, 18, 22840, {1, 3, 3, 5, 19, 57, 89, 101, 373, 283, 57, 1701, 5025, 6677, 20321, 58459, 9319, 161501}},
-{14779, 18, 22878, {1, 1, 1, 13, 3, 51, 111, 23, 325, 813, 441, 2371, 1993, 6839, 359, 9873, 33719, 208163}},
-{14780, 18, 22884, {1, 3, 1, 11, 23, 53, 35, 89, 91, 601, 433, 1671, 1919, 2115, 6355, 10639, 87305, 194185}},
-{14781, 18, 22888, {1, 1, 5, 9, 29, 31, 43, 153, 209, 835, 865, 2431, 1085, 9771, 14483, 19551, 98673, 146881}},
-{14782, 18, 22927, {1, 1, 7, 3, 7, 33, 49, 111, 111, 843, 479, 2113, 4575, 14911, 5161, 7153, 37525, 217887}},
-{14783, 18, 22941, {1, 1, 7, 9, 27, 5, 23, 217, 11, 79, 1637, 2047, 6697, 5601, 2877, 63497, 100127, 157833}},
-{14784, 18, 22951, {1, 1, 7, 11, 31, 41, 91, 39, 207, 185, 1163, 2115, 2963, 7605, 12597, 54175, 7221, 117129}},
-{14785, 18, 22958, {1, 3, 7, 13, 9, 15, 3, 47, 281, 451, 1111, 3585, 4505, 9465, 8047, 45893, 27179, 124373}},
-{14786, 18, 22980, {1, 3, 5, 11, 27, 29, 11, 221, 483, 29, 17, 1067, 6761, 39, 13419, 7263, 127547, 178951}},
-{14787, 18, 23007, {1, 3, 5, 5, 19, 3, 51, 155, 41, 251, 851, 1191, 4445, 8337, 25339, 32931, 4743, 31883}},
-{14788, 18, 23032, {1, 3, 7, 15, 9, 3, 113, 151, 239, 611, 381, 1141, 2865, 3071, 7293, 61997, 2891, 14533}},
-{14789, 18, 23041, {1, 3, 5, 3, 15, 59, 3, 37, 385, 587, 837, 2483, 5493, 10571, 26129, 44835, 63425, 246953}},
-{14790, 18, 23044, {1, 3, 5, 13, 9, 9, 93, 11, 139, 619, 581, 2859, 5481, 11941, 20661, 37463, 95369, 177009}},
-{14791, 18, 23059, {1, 1, 7, 11, 7, 17, 89, 7, 479, 377, 1631, 509, 7429, 13733, 24011, 24191, 98409, 180761}},
-{14792, 18, 23065, {1, 3, 7, 1, 5, 17, 51, 113, 181, 75, 1787, 2221, 6181, 16069, 3031, 32531, 107833, 239907}},
-{14793, 18, 23072, {1, 1, 5, 11, 3, 25, 13, 35, 311, 865, 873, 1811, 3101, 4445, 18155, 18647, 55693, 144963}},
-{14794, 18, 23137, {1, 3, 7, 13, 1, 9, 73, 189, 255, 301, 1579, 597, 6027, 15621, 27287, 14615, 76051, 143445}},
-{14795, 18, 23144, {1, 3, 1, 13, 19, 59, 11, 97, 501, 857, 1071, 3633, 8059, 2469, 16803, 49395, 73631, 114297}},
-{14796, 18, 23155, {1, 1, 1, 5, 19, 3, 59, 179, 343, 745, 497, 2965, 3841, 3119, 17707, 31577, 39801, 108819}},
-{14797, 18, 23162, {1, 3, 3, 9, 11, 17, 19, 199, 283, 229, 493, 631, 8133, 1531, 25271, 11353, 114759, 70655}},
-{14798, 18, 23167, {1, 1, 7, 7, 3, 11, 1, 95, 167, 863, 1009, 1695, 2773, 11667, 23515, 12927, 87883, 28773}},
-{14799, 18, 23183, {1, 3, 1, 15, 9, 1, 31, 243, 57, 349, 483, 659, 1971, 7971, 23797, 4403, 83837, 239261}},
-{14800, 18, 23192, {1, 3, 7, 5, 11, 17, 55, 5, 209, 233, 1969, 925, 695, 1321, 11965, 29849, 120519, 195105}},
-{14801, 18, 23197, {1, 3, 7, 11, 9, 45, 27, 9, 57, 649, 1801, 2653, 1535, 45, 8901, 28755, 26475, 112341}},
-{14802, 18, 23216, {1, 1, 3, 13, 11, 57, 103, 213, 193, 779, 541, 3685, 4191, 6105, 7199, 63659, 49673, 208361}},
-{14803, 18, 23221, {1, 3, 3, 7, 15, 15, 9, 207, 387, 429, 1213, 1703, 5753, 10261, 8705, 62783, 9643, 248591}},
-{14804, 18, 23228, {1, 3, 3, 15, 23, 17, 5, 83, 295, 685, 2003, 1723, 2799, 14699, 25171, 20275, 45597, 214107}},
-{14805, 18, 23233, {1, 1, 1, 15, 13, 33, 111, 69, 329, 273, 1303, 3377, 4151, 12547, 20411, 54845, 7839, 173939}},
-{14806, 18, 23234, {1, 1, 5, 15, 25, 31, 11, 75, 69, 501, 1485, 3659, 3889, 9715, 9633, 45313, 112377, 27799}},
-{14807, 18, 23251, {1, 1, 3, 11, 31, 27, 7, 25, 315, 593, 315, 275, 1453, 9429, 10023, 17939, 37651, 217435}},
-{14808, 18, 23257, {1, 3, 7, 7, 27, 41, 69, 95, 19, 763, 1733, 2097, 6723, 7051, 15209, 53047, 56117, 87639}},
-{14809, 18, 23258, {1, 3, 7, 5, 15, 61, 31, 19, 361, 571, 727, 405, 835, 4847, 26777, 50311, 104125, 127197}},
-{14810, 18, 23288, {1, 1, 1, 11, 11, 61, 59, 63, 409, 219, 1135, 3385, 5583, 16143, 22709, 31247, 19871, 68557}},
-{14811, 18, 23302, {1, 3, 7, 1, 11, 3, 121, 41, 135, 427, 1267, 2169, 507, 757, 12411, 50655, 75625, 1199}},
-{14812, 18, 23341, {1, 1, 7, 5, 17, 21, 89, 119, 55, 395, 979, 909, 1711, 3289, 8433, 9, 12743, 109027}},
-{14813, 18, 23373, {1, 1, 1, 13, 5, 11, 93, 35, 437, 173, 1157, 2749, 6855, 8307, 26145, 22593, 125415, 65509}},
-{14814, 18, 23402, {1, 1, 5, 3, 25, 27, 1, 173, 113, 373, 1769, 2941, 1895, 3399, 27665, 50613, 20747, 31903}},
-{14815, 18, 23409, {1, 1, 1, 1, 9, 7, 53, 73, 465, 725, 1537, 579, 83, 925, 15507, 13595, 16927, 205087}},
-{14816, 18, 23428, {1, 1, 3, 7, 7, 23, 31, 127, 27, 727, 1305, 3879, 817, 15995, 28607, 22695, 6367, 161587}},
-{14817, 18, 23435, {1, 3, 1, 7, 29, 23, 27, 117, 279, 917, 1105, 2061, 7719, 13633, 16501, 33739, 71939, 143115}},
-{14818, 18, 23440, {1, 3, 7, 11, 7, 27, 65, 133, 411, 441, 925, 1485, 2035, 3067, 14511, 58511, 120773, 228731}},
-{14819, 18, 23449, {1, 1, 3, 9, 21, 55, 27, 73, 175, 395, 1201, 2599, 3839, 11163, 5057, 3385, 43265, 105211}},
-{14820, 18, 23459, {1, 1, 1, 3, 7, 63, 91, 197, 417, 763, 1391, 3729, 2791, 1975, 23655, 50611, 110315, 86879}},
-{14821, 18, 23473, {1, 3, 3, 5, 31, 35, 67, 67, 89, 933, 1005, 1837, 5947, 2559, 27731, 25151, 102959, 81557}},
-{14822, 18, 23500, {1, 3, 3, 1, 3, 39, 57, 199, 87, 91, 1641, 3407, 2823, 10441, 26357, 56677, 17647, 86831}},
-{14823, 18, 23511, {1, 3, 5, 7, 15, 5, 49, 227, 395, 837, 1707, 1677, 1907, 13101, 1929, 61701, 1479, 80671}},
-{14824, 18, 23548, {1, 1, 1, 11, 17, 57, 37, 151, 61, 709, 2027, 2239, 3283, 5467, 17221, 40759, 91637, 258167}},
-{14825, 18, 23560, {1, 3, 5, 11, 27, 29, 121, 181, 503, 705, 225, 1111, 7183, 3219, 3233, 2085, 113619, 32959}},
-{14826, 18, 23563, {1, 1, 7, 5, 29, 31, 93, 113, 457, 161, 337, 2003, 1865, 13357, 19961, 51485, 62751, 111285}},
-{14827, 18, 23594, {1, 3, 1, 1, 23, 25, 65, 99, 11, 835, 661, 3291, 2655, 1135, 19957, 5029, 110483, 2499}},
-{14828, 18, 23601, {1, 1, 1, 1, 25, 21, 59, 203, 471, 697, 455, 1561, 3215, 609, 5097, 8715, 115705, 21441}},
-{14829, 18, 23625, {1, 1, 5, 13, 27, 37, 15, 175, 191, 975, 977, 401, 7053, 14291, 14621, 48989, 113033, 172569}},
-{14830, 18, 23640, {1, 3, 1, 1, 19, 11, 125, 53, 307, 421, 93, 2487, 5907, 2195, 30569, 21009, 20759, 246937}},
-{14831, 18, 23650, {1, 3, 7, 3, 23, 21, 103, 115, 453, 537, 473, 1069, 3007, 15111, 3477, 5635, 46423, 68633}},
-{14832, 18, 23662, {1, 3, 3, 1, 21, 1, 49, 197, 173, 775, 1877, 1309, 729, 3555, 5981, 32539, 22765, 171077}},
-{14833, 18, 23692, {1, 1, 3, 13, 19, 5, 75, 149, 441, 665, 1567, 2433, 8173, 12639, 27479, 47221, 66203, 89017}},
-{14834, 18, 23726, {1, 1, 1, 11, 1, 55, 99, 119, 491, 621, 619, 2521, 905, 11601, 26481, 2023, 127413, 220387}},
-{14835, 18, 23738, {1, 1, 7, 11, 9, 21, 57, 93, 243, 229, 1445, 997, 1317, 2327, 14141, 45787, 82295, 72823}},
-{14836, 18, 23743, {1, 3, 7, 3, 11, 7, 115, 143, 349, 507, 1047, 2573, 2491, 13351, 19019, 4857, 62781, 261261}},
-{14837, 18, 23755, {1, 1, 3, 1, 1, 13, 45, 227, 41, 947, 693, 2853, 7459, 1485, 22087, 61195, 111771, 136389}},
-{14838, 18, 23760, {1, 1, 3, 11, 13, 53, 49, 15, 425, 29, 681, 1493, 1385, 9555, 13291, 36735, 12351, 29293}},
-{14839, 18, 23799, {1, 1, 3, 1, 5, 19, 37, 45, 69, 209, 365, 3949, 6163, 5207, 9297, 21147, 71437, 40487}},
-{14840, 18, 23848, {1, 3, 3, 13, 31, 21, 9, 177, 95, 285, 1953, 1969, 7367, 7401, 12017, 9939, 11895, 213133}},
-{14841, 18, 23859, {1, 1, 7, 1, 1, 63, 103, 141, 39, 679, 123, 2941, 4335, 199, 12237, 6599, 48641, 140063}},
-{14842, 18, 23876, {1, 3, 7, 3, 31, 17, 21, 77, 65, 979, 109, 3325, 1781, 6983, 31477, 23149, 33943, 96137}},
-{14843, 18, 23897, {1, 3, 3, 5, 21, 5, 125, 117, 427, 381, 511, 2643, 409, 4945, 3167, 45879, 1469, 56077}},
-{14844, 18, 23907, {1, 3, 1, 5, 27, 43, 83, 31, 65, 645, 1205, 1387, 723, 15359, 13517, 23601, 61717, 47079}},
-{14845, 18, 23919, {1, 3, 3, 13, 15, 37, 101, 175, 225, 513, 483, 1291, 669, 5335, 16023, 287, 51819, 239803}},
-{14846, 18, 23921, {1, 3, 3, 3, 3, 1, 75, 175, 185, 949, 673, 2239, 4355, 10687, 27093, 37409, 23193, 211819}},
-{14847, 18, 23931, {1, 1, 3, 13, 21, 3, 41, 55, 243, 501, 285, 7, 6291, 7725, 17051, 45753, 115117, 14323}},
-{14848, 18, 23933, {1, 1, 1, 5, 13, 11, 51, 175, 435, 673, 67, 1525, 323, 5739, 19977, 62317, 97511, 130883}},
-{14849, 18, 23943, {1, 3, 5, 11, 7, 11, 97, 59, 295, 409, 453, 2439, 5217, 10315, 469, 31187, 17325, 158079}},
-{14850, 18, 23957, {1, 1, 3, 5, 31, 9, 15, 63, 411, 427, 277, 2687, 5021, 1507, 22453, 35559, 122081, 121669}},
-{14851, 18, 23986, {1, 3, 5, 13, 3, 21, 69, 51, 27, 571, 1981, 2729, 5733, 1225, 26821, 43763, 57355, 169279}},
-{14852, 18, 24020, {1, 1, 1, 13, 31, 37, 33, 19, 313, 341, 1141, 1689, 4511, 789, 15317, 61263, 79371, 65157}},
-{14853, 18, 24043, {1, 3, 3, 15, 27, 41, 107, 23, 499, 339, 273, 1937, 2743, 10879, 27127, 64817, 1217, 45863}},
-{14854, 18, 24064, {1, 1, 5, 9, 19, 43, 125, 223, 473, 489, 1999, 1513, 6479, 9511, 12503, 29419, 22559, 209499}},
-{14855, 18, 24082, {1, 3, 1, 13, 25, 55, 53, 61, 303, 337, 1325, 2525, 6503, 1155, 6841, 58167, 8175, 183949}},
-{14856, 18, 24084, {1, 3, 3, 11, 3, 15, 55, 105, 497, 527, 1007, 3545, 4187, 8723, 12761, 20751, 101583, 225373}},
-{14857, 18, 24088, {1, 3, 3, 9, 19, 59, 57, 215, 313, 871, 407, 2475, 879, 15147, 31945, 23939, 104073, 217619}},
-{14858, 18, 24117, {1, 1, 3, 1, 27, 23, 3, 43, 471, 757, 1525, 3003, 2779, 6731, 12423, 59621, 72935, 192283}},
-{14859, 18, 24149, {1, 3, 1, 7, 13, 23, 13, 91, 95, 745, 639, 2627, 4595, 11735, 4143, 23573, 98647, 171201}},
-{14860, 18, 24165, {1, 1, 1, 15, 3, 61, 33, 181, 351, 777, 1365, 1691, 2465, 5289, 24567, 8059, 95301, 75855}},
-{14861, 18, 24223, {1, 3, 5, 13, 1, 57, 57, 187, 1, 601, 563, 1703, 1307, 14673, 7793, 44589, 7629, 254071}},
-{14862, 18, 24247, {1, 1, 5, 13, 29, 17, 61, 233, 371, 909, 529, 185, 127, 15773, 19529, 49271, 26749, 70869}},
-{14863, 18, 24259, {1, 1, 3, 9, 21, 41, 37, 71, 505, 969, 301, 1667, 5879, 13187, 2461, 17301, 103673, 235133}},
-{14864, 18, 24283, {1, 3, 1, 3, 9, 13, 75, 63, 313, 273, 1061, 3821, 539, 9887, 19775, 17259, 93133, 217245}},
-{14865, 18, 24296, {1, 3, 5, 5, 21, 27, 9, 11, 461, 575, 507, 577, 4559, 9995, 13953, 61023, 121941, 195419}},
-{14866, 18, 24336, {1, 3, 3, 7, 17, 17, 45, 193, 271, 571, 1337, 2107, 1923, 4791, 23773, 60923, 58085, 81219}},
-{14867, 18, 24342, {1, 3, 1, 7, 11, 7, 85, 33, 231, 307, 993, 1509, 1427, 9545, 7919, 39775, 81145, 79139}},
-{14868, 18, 24389, {1, 3, 5, 3, 9, 57, 117, 187, 57, 719, 1635, 2499, 6747, 6649, 22643, 16429, 83233, 122057}},
-{14869, 18, 24394, {1, 1, 3, 11, 7, 39, 103, 221, 167, 181, 1355, 989, 3399, 9471, 10493, 57267, 106551, 158599}},
-{14870, 18, 24414, {1, 3, 1, 15, 23, 19, 29, 11, 355, 923, 1401, 509, 3647, 5663, 2353, 53217, 70687, 145613}},
-{14871, 18, 24424, {1, 3, 3, 11, 11, 5, 21, 107, 177, 429, 119, 1029, 5931, 7543, 15455, 62797, 118095, 35387}},
-{14872, 18, 24441, {1, 3, 5, 15, 19, 53, 17, 215, 279, 497, 1157, 2235, 5541, 5899, 20711, 20843, 113821, 164231}},
-{14873, 18, 24491, {1, 1, 1, 15, 21, 33, 67, 247, 55, 573, 1863, 2703, 5267, 4071, 18235, 44659, 102379, 171529}},
-{14874, 18, 24502, {1, 3, 1, 15, 5, 59, 69, 189, 313, 243, 339, 3097, 4999, 5909, 1903, 56143, 76209, 83073}},
-{14875, 18, 24534, {1, 3, 5, 15, 11, 41, 65, 207, 95, 115, 1203, 3731, 6845, 11173, 8281, 40623, 97119, 218455}},
-{14876, 18, 24540, {1, 3, 7, 13, 29, 57, 5, 31, 255, 539, 107, 953, 3707, 9233, 20295, 17459, 2005, 56193}},
-{14877, 18, 24543, {1, 1, 1, 15, 5, 31, 83, 165, 211, 433, 1411, 2949, 4817, 1645, 1693, 9877, 118493, 142923}},
-{14878, 18, 24549, {1, 3, 1, 11, 19, 61, 35, 21, 159, 159, 1717, 3227, 3351, 8641, 20575, 13721, 114649, 129201}},
-{14879, 18, 24567, {1, 3, 1, 13, 9, 41, 17, 7, 209, 501, 445, 23, 7911, 5867, 30129, 643, 36363, 52037}},
-{14880, 18, 24583, {1, 3, 5, 11, 31, 55, 27, 81, 413, 167, 599, 2231, 7055, 4013, 26729, 63927, 12075, 208123}},
-{14881, 18, 24693, {1, 1, 7, 9, 11, 39, 99, 187, 169, 999, 609, 3647, 2497, 8969, 30919, 29145, 67699, 51601}},
-{14882, 18, 24704, {1, 3, 1, 1, 11, 11, 69, 29, 197, 979, 1135, 869, 5435, 5151, 26349, 55911, 68051, 131849}},
-{14883, 18, 24719, {1, 1, 1, 5, 27, 1, 85, 145, 439, 585, 1713, 677, 1833, 14139, 5547, 31265, 82223, 47605}},
-{14884, 18, 24749, {1, 3, 5, 9, 17, 23, 31, 199, 447, 551, 683, 2977, 7839, 8681, 15923, 61057, 89875, 52945}},
-{14885, 18, 24799, {1, 1, 3, 11, 9, 17, 29, 125, 195, 123, 1259, 2729, 3099, 2229, 9683, 13121, 105399, 111833}},
-{14886, 18, 24830, {1, 3, 1, 3, 1, 47, 93, 117, 461, 633, 1641, 933, 7927, 13569, 483, 28159, 121561, 164325}},
-{14887, 18, 24835, {1, 3, 1, 5, 21, 19, 79, 183, 395, 23, 767, 519, 4857, 10385, 12425, 26207, 114623, 37125}},
-{14888, 18, 24907, {1, 1, 5, 5, 9, 47, 67, 217, 499, 843, 1539, 301, 1485, 3157, 22375, 47199, 26215, 182785}},
-{14889, 18, 24917, {1, 1, 1, 13, 9, 37, 87, 49, 445, 681, 1097, 1049, 4093, 13167, 18447, 58243, 41797, 217929}},
-{14890, 18, 24940, {1, 1, 5, 13, 13, 49, 21, 149, 79, 113, 1217, 921, 6321, 9345, 27987, 21723, 49249, 18813}},
-{14891, 18, 24943, {1, 3, 1, 3, 15, 27, 67, 69, 131, 713, 1741, 1955, 5665, 8749, 11971, 11257, 13999, 124535}},
-{14892, 18, 24958, {1, 3, 1, 3, 3, 11, 21, 167, 441, 557, 593, 3261, 3099, 2801, 21725, 23247, 106891, 129187}},
-{14893, 18, 24962, {1, 1, 1, 11, 5, 55, 33, 71, 505, 85, 1609, 521, 5459, 12777, 13007, 255, 67537, 2877}},
-{14894, 18, 24964, {1, 1, 1, 3, 31, 47, 49, 119, 351, 797, 1407, 4089, 2381, 12409, 12849, 23489, 53631, 119387}},
-{14895, 18, 24968, {1, 3, 5, 11, 25, 11, 25, 185, 85, 849, 141, 385, 3663, 13133, 8451, 61463, 35129, 149933}},
-{14896, 18, 25015, {1, 3, 7, 9, 23, 17, 21, 197, 15, 893, 939, 707, 5491, 7249, 14009, 18973, 111545, 36809}},
-{14897, 18, 25024, {1, 3, 3, 13, 23, 15, 19, 193, 223, 627, 1529, 1963, 1003, 7199, 15361, 25233, 110281, 221761}},
-{14898, 18, 25027, {1, 3, 3, 1, 17, 51, 61, 215, 311, 919, 349, 59, 2897, 12137, 5931, 37611, 124387, 83503}},
-{14899, 18, 25033, {1, 3, 7, 9, 13, 47, 53, 139, 481, 733, 389, 1209, 3281, 593, 29103, 61521, 41445, 11015}},
-{14900, 18, 25041, {1, 1, 1, 13, 3, 31, 19, 47, 151, 883, 1707, 827, 2129, 4333, 871, 42967, 79701, 192211}},
-{14901, 18, 25047, {1, 3, 3, 11, 11, 51, 121, 241, 199, 881, 1493, 2381, 5161, 13287, 8155, 52481, 120307, 206203}},
-{14902, 18, 25057, {1, 1, 1, 13, 15, 37, 27, 151, 17, 851, 1343, 1447, 43, 10267, 18267, 21347, 129277, 83987}},
-{14903, 18, 25082, {1, 1, 3, 3, 13, 17, 53, 217, 253, 853, 1461, 1953, 617, 4209, 9925, 377, 42789, 150415}},
-{14904, 18, 25093, {1, 3, 7, 11, 13, 23, 83, 235, 39, 701, 1091, 25, 1807, 15431, 2169, 5339, 123679, 117053}},
-{14905, 18, 25105, {1, 3, 7, 13, 3, 29, 43, 149, 33, 873, 1177, 1961, 7943, 11317, 30725, 55765, 50929, 12335}},
-{14906, 18, 25112, {1, 1, 3, 5, 25, 1, 91, 121, 295, 25, 1743, 2125, 2643, 11175, 15089, 44979, 28355, 543}},
-{14907, 18, 25117, {1, 1, 1, 13, 27, 27, 43, 195, 377, 821, 437, 3445, 2673, 15221, 15101, 25143, 22347, 218549}},
-{14908, 18, 25131, {1, 1, 3, 7, 9, 51, 121, 231, 91, 913, 1325, 167, 8067, 8119, 9307, 33551, 58069, 170567}},
-{14909, 18, 25139, {1, 3, 7, 7, 15, 7, 85, 51, 11, 353, 1117, 2479, 3091, 2377, 23589, 38537, 113047, 261285}},
-{14910, 18, 25194, {1, 1, 3, 5, 15, 33, 61, 145, 147, 815, 767, 9, 2059, 11463, 1883, 8565, 101043, 117565}},
-{14911, 18, 25204, {1, 3, 5, 3, 5, 49, 5, 33, 15, 13, 895, 3973, 7963, 3831, 26817, 10799, 111409, 90679}},
-{14912, 18, 25244, {1, 1, 5, 7, 5, 51, 35, 237, 217, 531, 719, 2711, 1937, 16071, 23233, 22799, 66023, 145739}},
-{14913, 18, 25247, {1, 3, 5, 1, 5, 63, 1, 163, 9, 697, 1379, 2989, 7113, 9821, 15941, 6495, 7825, 29715}},
-{14914, 18, 25253, {1, 3, 5, 7, 9, 41, 113, 173, 151, 963, 2019, 3531, 1133, 4287, 16917, 16929, 12345, 31201}},
-{14915, 18, 25258, {1, 3, 7, 1, 25, 9, 5, 195, 175, 297, 717, 3725, 33, 5155, 4405, 56171, 105597, 132407}},
-{14916, 18, 25275, {1, 1, 7, 7, 3, 59, 115, 95, 227, 951, 843, 619, 7791, 10981, 11773, 57651, 108391, 179561}},
-{14917, 18, 25320, {1, 3, 3, 1, 9, 3, 59, 161, 417, 413, 1933, 1027, 4575, 10427, 15643, 16049, 120089, 176607}},
-{14918, 18, 25338, {1, 3, 3, 3, 15, 1, 83, 195, 59, 859, 1669, 1063, 2069, 15875, 16459, 53741, 114521, 37641}},
-{14919, 18, 25343, {1, 1, 1, 11, 11, 45, 47, 143, 11, 239, 1329, 865, 2693, 899, 26265, 43255, 125679, 130099}},
-{14920, 18, 25351, {1, 3, 5, 3, 31, 51, 95, 127, 79, 167, 117, 3177, 5875, 14039, 20341, 47815, 118799, 211871}},
-{14921, 18, 25358, {1, 1, 1, 1, 3, 21, 65, 203, 11, 565, 537, 1307, 8189, 11423, 7745, 56117, 110959, 95361}},
-{14922, 18, 25372, {1, 1, 7, 7, 21, 63, 63, 231, 441, 127, 1943, 13, 4813, 10607, 23867, 43891, 15801, 173245}},
-{14923, 18, 25399, {1, 3, 3, 5, 25, 23, 123, 133, 129, 303, 1993, 1453, 1109, 4649, 30315, 62399, 121575, 60069}},
-{14924, 18, 25408, {1, 3, 5, 3, 29, 23, 69, 141, 137, 1017, 1915, 35, 3817, 6249, 22427, 7281, 88473, 230167}},
-{14925, 18, 25432, {1, 3, 7, 7, 19, 37, 93, 217, 287, 731, 583, 3377, 2879, 4873, 5549, 52949, 127285, 211173}},
-{14926, 18, 25442, {1, 1, 5, 7, 23, 41, 49, 145, 277, 571, 1225, 455, 2133, 1229, 25421, 20179, 70919, 242825}},
-{14927, 18, 25462, {1, 3, 5, 5, 29, 3, 1, 89, 413, 901, 1343, 3963, 6969, 14649, 18331, 4573, 82077, 100693}},
-{14928, 18, 25465, {1, 1, 1, 13, 31, 53, 107, 95, 151, 539, 1593, 3763, 1007, 8959, 25235, 16461, 121819, 106143}},
-{14929, 18, 25468, {1, 1, 1, 3, 11, 15, 5, 157, 347, 81, 2013, 2025, 6541, 12287, 1315, 23285, 23539, 75027}},
-{14930, 18, 25482, {1, 1, 5, 7, 17, 11, 65, 157, 93, 607, 1445, 4089, 3139, 4699, 1225, 58935, 93673, 146467}},
-{14931, 18, 25489, {1, 3, 3, 13, 29, 59, 69, 141, 257, 463, 93, 649, 8179, 15205, 6943, 45317, 31269, 70825}},
-{14932, 18, 25490, {1, 3, 5, 9, 23, 39, 113, 61, 315, 463, 1739, 149, 6007, 2789, 12021, 969, 18551, 153669}},
-{14933, 18, 25505, {1, 1, 3, 15, 19, 9, 23, 211, 265, 877, 325, 2635, 8131, 4957, 24371, 60975, 3887, 198927}},
-{14934, 18, 25511, {1, 1, 3, 11, 29, 31, 5, 105, 157, 573, 2009, 1701, 1549, 1641, 17429, 13587, 48421, 8675}},
-{14935, 18, 25512, {1, 1, 5, 13, 3, 13, 17, 55, 101, 369, 705, 3635, 5195, 10439, 12881, 21565, 1671, 75489}},
-{14936, 18, 25552, {1, 3, 3, 1, 1, 23, 85, 189, 347, 205, 5, 3465, 3269, 3347, 10163, 26921, 86555, 9387}},
-{14937, 18, 25555, {1, 3, 7, 15, 27, 21, 79, 151, 279, 627, 1093, 1929, 5549, 12141, 5245, 55747, 65939, 193759}},
-{14938, 18, 25595, {1, 1, 1, 5, 5, 23, 57, 235, 143, 129, 795, 35, 4375, 12577, 871, 20879, 82811, 52279}},
-{14939, 18, 25636, {1, 3, 1, 5, 11, 1, 125, 99, 89, 629, 857, 2631, 393, 15075, 27473, 42695, 61505, 239651}},
-{14940, 18, 25672, {1, 1, 5, 1, 9, 11, 55, 203, 453, 677, 259, 1979, 4101, 16067, 26783, 17907, 75349, 62797}},
-{14941, 18, 25685, {1, 3, 7, 5, 5, 19, 85, 165, 341, 405, 1779, 87, 889, 265, 9851, 36175, 69697, 123769}},
-{14942, 18, 25696, {1, 3, 7, 1, 7, 49, 93, 57, 85, 597, 183, 3253, 6301, 9307, 8753, 38133, 58743, 19621}},
-{14943, 18, 25720, {1, 1, 3, 9, 1, 15, 125, 215, 391, 141, 87, 37, 4333, 5033, 30549, 64281, 18577, 156093}},
-{14944, 18, 25730, {1, 3, 3, 15, 17, 25, 29, 81, 339, 865, 1619, 773, 901, 8163, 22275, 57159, 119951, 137451}},
-{14945, 18, 25735, {1, 3, 5, 15, 7, 57, 113, 221, 13, 49, 1653, 3695, 4423, 4383, 28669, 64175, 130355, 202543}},
-{14946, 18, 25753, {1, 1, 3, 9, 29, 21, 19, 119, 409, 717, 1853, 3981, 4489, 3985, 31205, 10423, 13223, 131973}},
-{14947, 18, 25756, {1, 1, 3, 15, 29, 7, 1, 85, 133, 345, 317, 2363, 7803, 4975, 19441, 10497, 42059, 131531}},
-{14948, 18, 25769, {1, 1, 7, 13, 3, 53, 49, 27, 487, 901, 801, 335, 6317, 14205, 26655, 52747, 102659, 231359}},
-{14949, 18, 25821, {1, 3, 3, 3, 13, 33, 113, 107, 407, 499, 903, 3059, 1343, 11859, 6315, 23071, 73627, 44239}},
-{14950, 18, 25825, {1, 3, 5, 15, 1, 53, 59, 247, 213, 981, 443, 3, 615, 12067, 3881, 61759, 101219, 110407}},
-{14951, 18, 25840, {1, 3, 5, 13, 7, 31, 87, 161, 61, 1023, 147, 2075, 7245, 9025, 7229, 60935, 104481, 169561}},
-{14952, 18, 25860, {1, 3, 1, 15, 25, 17, 53, 107, 311, 621, 1493, 2443, 4635, 12163, 12543, 43031, 90843, 139645}},
-{14953, 18, 25869, {1, 3, 5, 11, 7, 49, 91, 165, 91, 329, 493, 3533, 7429, 7047, 14767, 31641, 62005, 77267}},
-{14954, 18, 25872, {1, 1, 3, 9, 31, 21, 19, 167, 185, 199, 1989, 1093, 4213, 4769, 21659, 19685, 122123, 215233}},
-{14955, 18, 25956, {1, 3, 3, 7, 27, 23, 99, 205, 365, 689, 1281, 419, 4207, 5355, 20245, 25029, 123029, 61499}},
-{14956, 18, 25973, {1, 3, 3, 7, 19, 15, 29, 185, 165, 203, 1859, 2895, 6361, 6331, 13641, 42577, 33757, 41305}},
-{14957, 18, 25994, {1, 3, 5, 11, 21, 43, 15, 11, 425, 125, 1597, 1109, 3335, 7009, 20799, 41261, 127813, 181261}},
-{14958, 18, 26002, {1, 1, 5, 5, 27, 35, 35, 159, 111, 1011, 1487, 813, 4985, 2555, 23741, 44675, 97159, 250477}},
-{14959, 18, 26020, {1, 3, 3, 7, 17, 41, 81, 187, 367, 767, 1345, 205, 5797, 9129, 21973, 39911, 130131, 96891}},
-{14960, 18, 26023, {1, 3, 5, 1, 1, 47, 57, 177, 127, 791, 1427, 1895, 5995, 12569, 32711, 58599, 55641, 80405}},
-{14961, 18, 26041, {1, 3, 3, 1, 23, 13, 115, 81, 511, 677, 775, 3143, 4963, 7093, 15963, 59893, 22609, 137601}},
-{14962, 18, 26044, {1, 1, 5, 9, 17, 17, 115, 127, 397, 139, 1171, 207, 3485, 15869, 465, 26267, 29957, 205459}},
-{14963, 18, 26069, {1, 3, 7, 3, 9, 29, 23, 189, 447, 481, 753, 2415, 2669, 6007, 15201, 7317, 18861, 173759}},
-{14964, 18, 26097, {1, 3, 5, 7, 13, 43, 13, 163, 363, 683, 1869, 1237, 2523, 3661, 13887, 5593, 91513, 220177}},
-{14965, 18, 26113, {1, 1, 1, 11, 7, 11, 43, 39, 319, 793, 375, 3159, 7621, 8965, 25743, 351, 31873, 18115}},
-{14966, 18, 26138, {1, 1, 5, 5, 11, 57, 79, 147, 55, 553, 417, 1365, 3979, 9789, 22677, 58645, 104549, 9019}},
-{14967, 18, 26167, {1, 1, 3, 11, 17, 37, 127, 5, 165, 867, 79, 2259, 197, 4789, 28109, 46721, 3431, 118939}},
-{14968, 18, 26216, {1, 1, 5, 13, 19, 45, 113, 11, 125, 351, 1753, 3201, 1697, 2567, 9717, 22247, 84309, 248583}},
-{14969, 18, 26230, {1, 1, 5, 9, 5, 37, 65, 47, 261, 855, 1573, 2267, 7977, 13029, 32527, 59805, 103591, 180041}},
-{14970, 18, 26243, {1, 3, 3, 9, 31, 5, 115, 159, 111, 899, 1907, 2671, 1575, 7021, 10281, 34905, 641, 63549}},
-{14971, 18, 26245, {1, 3, 5, 1, 17, 61, 45, 9, 375, 761, 117, 1767, 4657, 12217, 12067, 42807, 118587, 72715}},
-{14972, 18, 26263, {1, 1, 1, 13, 3, 3, 93, 3, 351, 97, 119, 1743, 81, 12761, 22529, 47191, 111315, 256501}},
-{14973, 18, 26264, {1, 1, 5, 7, 29, 23, 41, 9, 231, 567, 1565, 3539, 7241, 11535, 7375, 10391, 127045, 9371}},
-{14974, 18, 26269, {1, 1, 1, 15, 23, 47, 39, 57, 73, 809, 513, 3233, 8071, 8595, 13817, 821, 89091, 107173}},
-{14975, 18, 26311, {1, 1, 1, 13, 13, 43, 75, 239, 487, 175, 1561, 3925, 3743, 14247, 15713, 55005, 116135, 199827}},
-{14976, 18, 26346, {1, 1, 3, 7, 13, 15, 67, 147, 77, 241, 1763, 651, 1107, 4943, 15651, 23259, 45931, 34717}},
-{14977, 18, 26354, {1, 1, 3, 5, 15, 15, 67, 153, 163, 179, 1567, 685, 3245, 2205, 8373, 56567, 32091, 23313}},
-{14978, 18, 26365, {1, 1, 7, 9, 1, 27, 79, 209, 263, 517, 635, 3, 103, 2173, 22659, 11319, 103757, 144449}},
-{14979, 18, 26368, {1, 1, 1, 5, 11, 63, 21, 89, 443, 775, 327, 1559, 1421, 2309, 18597, 46385, 16547, 186813}},
-{14980, 18, 26398, {1, 1, 7, 9, 27, 37, 43, 7, 305, 117, 1103, 1801, 3349, 12225, 28215, 8857, 118677, 88909}},
-{14981, 18, 26401, {1, 3, 3, 7, 15, 59, 21, 19, 371, 81, 755, 1565, 4823, 16363, 20301, 33571, 74423, 177205}},
-{14982, 18, 26426, {1, 1, 3, 9, 15, 33, 23, 31, 171, 713, 271, 2437, 3609, 4271, 24355, 46283, 121767, 188501}},
-{14983, 18, 26436, {1, 1, 1, 1, 21, 3, 3, 241, 339, 211, 443, 1577, 343, 2625, 1077, 29933, 106401, 51439}},
-{14984, 18, 26443, {1, 3, 5, 15, 13, 31, 11, 167, 15, 101, 373, 2095, 3017, 1347, 15029, 6579, 21233, 87589}},
-{14985, 18, 26448, {1, 3, 1, 3, 15, 1, 61, 239, 13, 867, 1621, 2275, 5757, 8275, 7923, 44469, 113513, 84927}},
-{14986, 18, 26458, {1, 1, 1, 13, 23, 27, 101, 25, 459, 517, 127, 1131, 669, 13209, 23671, 3379, 66091, 72919}},
-{14987, 18, 26464, {1, 3, 5, 7, 29, 53, 25, 185, 101, 707, 281, 183, 2823, 7241, 3127, 48093, 20195, 208349}},
-{14988, 18, 26476, {1, 3, 3, 15, 31, 11, 3, 165, 453, 609, 1053, 3937, 1989, 13887, 13415, 8005, 103537, 17853}},
-{14989, 18, 26503, {1, 1, 3, 7, 3, 41, 13, 67, 227, 265, 767, 391, 1835, 8827, 13131, 42605, 117089, 12475}},
-{14990, 18, 26504, {1, 1, 7, 3, 15, 31, 45, 157, 261, 207, 1109, 1587, 5389, 13239, 31697, 35969, 79839, 209633}},
-{14991, 18, 26515, {1, 1, 5, 9, 31, 3, 35, 187, 5, 945, 633, 2645, 171, 2221, 18369, 41765, 82373, 8007}},
-{14992, 18, 26531, {1, 1, 7, 7, 3, 57, 73, 103, 245, 811, 1637, 101, 6335, 9911, 663, 21779, 31681, 119141}},
-{14993, 18, 26548, {1, 1, 5, 13, 27, 25, 5, 203, 183, 251, 1803, 665, 6295, 965, 5269, 379, 78455, 7097}},
-{14994, 18, 26570, {1, 1, 5, 3, 19, 55, 45, 161, 481, 737, 1903, 1093, 3313, 4427, 7959, 6231, 94769, 123827}},
-{14995, 18, 26589, {1, 1, 7, 11, 29, 41, 77, 165, 49, 875, 137, 2003, 8093, 1941, 25979, 10765, 99241, 71275}},
-{14996, 18, 26594, {1, 3, 5, 3, 23, 1, 89, 163, 293, 701, 29, 2543, 4487, 14873, 28123, 48643, 31633, 74179}},
-{14997, 18, 26608, {1, 1, 7, 1, 13, 33, 33, 173, 111, 959, 205, 1633, 3127, 3963, 6455, 41809, 60655, 247121}},
-{14998, 18, 26623, {1, 3, 5, 13, 1, 49, 87, 217, 381, 125, 823, 837, 3967, 8157, 11097, 35721, 93591, 3939}},
-{14999, 18, 26678, {1, 3, 7, 1, 7, 27, 29, 21, 295, 127, 823, 2409, 1873, 2417, 27961, 39211, 14785, 71557}},
-{15000, 18, 26690, {1, 3, 1, 5, 31, 59, 43, 121, 217, 417, 2029, 3983, 5629, 10447, 1073, 57515, 58849, 178927}},
-{15001, 18, 26709, {1, 3, 3, 11, 5, 59, 45, 39, 269, 483, 757, 3245, 4383, 11127, 26535, 17395, 60953, 259333}},
-{15002, 18, 26725, {1, 1, 1, 5, 5, 49, 81, 241, 371, 353, 1293, 3375, 6725, 11891, 5973, 13901, 37999, 17751}},
-{15003, 18, 26744, {1, 3, 3, 7, 31, 21, 45, 107, 33, 911, 1869, 2643, 2655, 3979, 5509, 33065, 128463, 246937}},
-{15004, 18, 26763, {1, 1, 1, 1, 31, 33, 99, 29, 485, 11, 1423, 1775, 2045, 741, 30691, 53957, 13891, 57303}},
-{15005, 18, 26765, {1, 1, 7, 13, 7, 37, 117, 121, 51, 743, 887, 1769, 1049, 12859, 1663, 27763, 90969, 38935}},
-{15006, 18, 26768, {1, 3, 5, 7, 3, 41, 121, 89, 461, 979, 457, 2973, 8109, 13819, 30237, 54671, 66967, 135233}},
-{15007, 18, 26784, {1, 1, 7, 13, 13, 47, 51, 121, 295, 847, 681, 1163, 8123, 14179, 26561, 54057, 74043, 146155}},
-{15008, 18, 26802, {1, 3, 3, 11, 21, 15, 9, 85, 445, 11, 1525, 3165, 5929, 12481, 10769, 31885, 51487, 248933}},
-{15009, 18, 26814, {1, 3, 1, 9, 25, 41, 59, 139, 293, 1021, 2043, 967, 3949, 7309, 6545, 62761, 37761, 22395}},
-{15010, 18, 26856, {1, 3, 7, 15, 25, 45, 29, 75, 283, 845, 687, 3285, 7263, 10237, 5343, 58635, 85137, 2387}},
-{15011, 18, 26861, {1, 1, 3, 15, 29, 33, 111, 175, 251, 181, 709, 1373, 1661, 1155, 30479, 57823, 28809, 74117}},
-{15012, 18, 26862, {1, 3, 3, 5, 11, 37, 55, 155, 439, 173, 1861, 1713, 1675, 12119, 12531, 50995, 124657, 58321}},
-{15013, 18, 26894, {1, 1, 5, 13, 1, 23, 27, 141, 3, 985, 1439, 781, 7381, 2223, 26673, 46607, 54953, 24547}},
-{15014, 18, 26908, {1, 1, 5, 7, 5, 3, 41, 115, 503, 731, 633, 3631, 3455, 15937, 22639, 41163, 65243, 233749}},
-{15015, 18, 26915, {1, 3, 1, 1, 5, 57, 89, 35, 53, 653, 1763, 1247, 6999, 1811, 28191, 52327, 129421, 191093}},
-{15016, 18, 26929, {1, 3, 3, 9, 3, 27, 107, 13, 475, 409, 1623, 483, 3127, 12841, 4777, 36157, 24967, 89795}},
-{15017, 18, 26930, {1, 1, 3, 5, 7, 29, 15, 225, 257, 923, 251, 21, 4559, 3571, 9351, 1739, 37393, 170789}},
-{15018, 18, 26939, {1, 3, 7, 5, 11, 7, 107, 237, 343, 665, 767, 2293, 4781, 4811, 11227, 25045, 3951, 44307}},
-{15019, 18, 26941, {1, 3, 7, 7, 13, 31, 47, 9, 121, 441, 1011, 2015, 8053, 355, 13441, 23213, 60675, 259761}},
-{15020, 18, 26987, {1, 1, 5, 9, 21, 61, 85, 141, 271, 577, 17, 243, 3049, 2479, 28947, 53351, 67379, 211133}},
-{15021, 18, 27023, {1, 1, 1, 15, 23, 1, 119, 141, 311, 543, 1463, 3633, 8111, 9439, 4147, 64913, 28261, 197217}},
-{15022, 18, 27066, {1, 3, 1, 15, 15, 33, 125, 231, 225, 797, 605, 259, 3673, 10423, 7541, 26289, 61681, 136463}},
-{15023, 18, 27079, {1, 3, 1, 13, 23, 15, 15, 151, 289, 657, 1883, 2923, 6861, 1411, 17159, 9353, 79463, 135813}},
-{15024, 18, 27086, {1, 3, 7, 11, 5, 59, 101, 167, 291, 63, 753, 1105, 8173, 2389, 22097, 7207, 110377, 15797}},
-{15025, 18, 27091, {1, 3, 7, 15, 7, 9, 7, 135, 303, 675, 1803, 2827, 1711, 9543, 16567, 24075, 17065, 22193}},
-{15026, 18, 27113, {1, 3, 5, 7, 17, 7, 125, 57, 423, 733, 1813, 4031, 713, 10687, 27315, 37599, 78807, 103429}},
-{15027, 18, 27157, {1, 1, 5, 15, 21, 11, 87, 21, 415, 571, 1169, 2561, 7071, 12499, 195, 20111, 116757, 157731}},
-{15028, 18, 27174, {1, 3, 3, 15, 7, 33, 11, 241, 23, 189, 599, 2891, 2829, 13327, 21777, 57733, 38583, 162161}},
-{15029, 18, 27188, {1, 1, 1, 15, 3, 49, 7, 143, 291, 301, 1439, 793, 3447, 1167, 2815, 24875, 117437, 112561}},
-{15030, 18, 27191, {1, 3, 5, 13, 29, 11, 51, 255, 365, 741, 1919, 2091, 2865, 12721, 4329, 37281, 128703, 739}},
-{15031, 18, 27197, {1, 1, 1, 13, 19, 31, 39, 141, 81, 133, 297, 3837, 7537, 16043, 11755, 10289, 74399, 95371}},
-{15032, 18, 27206, {1, 1, 7, 5, 21, 35, 125, 109, 241, 217, 1219, 2617, 1925, 9573, 19305, 44689, 89365, 248869}},
-{15033, 18, 27210, {1, 3, 5, 5, 13, 33, 43, 221, 325, 267, 837, 809, 6025, 9847, 9267, 13465, 45937, 204339}},
-{15034, 18, 27245, {1, 3, 1, 3, 25, 53, 85, 249, 105, 619, 917, 1213, 5365, 6197, 22929, 27529, 71011, 141651}},
-{15035, 18, 27254, {1, 1, 5, 1, 29, 9, 27, 161, 269, 775, 1043, 303, 4503, 5059, 479, 17237, 51383, 152495}},
-{15036, 18, 27383, {1, 3, 1, 5, 19, 5, 127, 139, 1, 461, 943, 593, 7457, 3357, 1909, 64633, 91811, 92703}},
-{15037, 18, 27387, {1, 1, 5, 7, 1, 21, 83, 29, 123, 83, 1085, 2727, 651, 15801, 20561, 34821, 17671, 162227}},
-{15038, 18, 27416, {1, 3, 7, 1, 19, 59, 33, 195, 81, 69, 51, 1473, 3873, 4247, 3587, 4293, 30831, 245345}},
-{15039, 18, 27422, {1, 3, 1, 3, 23, 27, 19, 115, 275, 293, 705, 131, 1001, 8881, 30165, 25149, 38679, 175167}},
-{15040, 18, 27472, {1, 1, 3, 15, 11, 11, 79, 55, 323, 217, 859, 897, 6567, 12529, 3161, 13009, 100787, 3501}},
-{15041, 18, 27478, {1, 3, 1, 15, 17, 63, 51, 71, 55, 207, 1095, 2527, 611, 9281, 7375, 14553, 16021, 88537}},
-{15042, 18, 27548, {1, 1, 7, 9, 11, 23, 95, 25, 327, 873, 575, 3583, 6587, 137, 23737, 59341, 83281, 93541}},
-{15043, 18, 27579, {1, 1, 5, 7, 15, 37, 89, 105, 471, 757, 103, 3747, 3565, 4957, 23537, 16193, 84843, 256757}},
-{15044, 18, 27582, {1, 3, 5, 1, 15, 17, 119, 231, 387, 715, 797, 3807, 4985, 8335, 4885, 45541, 69597, 238599}},
-{15045, 18, 27589, {1, 1, 3, 1, 7, 21, 87, 205, 39, 503, 433, 3643, 4719, 2051, 10049, 28997, 75981, 253647}},
-{15046, 18, 27593, {1, 3, 1, 13, 9, 21, 103, 63, 27, 267, 185, 3507, 3009, 5183, 2261, 40249, 33733, 70493}},
-{15047, 18, 27613, {1, 1, 3, 13, 7, 7, 79, 13, 141, 327, 1035, 1699, 6273, 5621, 13877, 57607, 50207, 184643}},
-{15048, 18, 27649, {1, 1, 3, 1, 9, 19, 75, 99, 115, 469, 1025, 1999, 1985, 9975, 11069, 59113, 80877, 124153}},
-{15049, 18, 27717, {1, 3, 5, 7, 19, 27, 47, 3, 313, 575, 107, 991, 2575, 11001, 12323, 21443, 126245, 219649}},
-{15050, 18, 27729, {1, 1, 1, 5, 19, 33, 13, 1, 357, 225, 1355, 1827, 7127, 6387, 19299, 24935, 26847, 251433}},
-{15051, 18, 27751, {1, 1, 1, 5, 3, 3, 113, 19, 425, 209, 159, 347, 1349, 6771, 13125, 8393, 21435, 186369}},
-{15052, 18, 27757, {1, 1, 5, 11, 5, 39, 95, 3, 193, 741, 1755, 3361, 1927, 12909, 5413, 29111, 123429, 109191}},
-{15053, 18, 27766, {1, 1, 1, 13, 31, 23, 43, 163, 421, 719, 457, 3149, 7741, 1465, 15719, 42831, 99051, 164675}},
-{15054, 18, 27791, {1, 1, 1, 7, 15, 1, 29, 15, 9, 577, 269, 31, 4361, 5081, 32185, 54869, 115105, 151233}},
-{15055, 18, 27794, {1, 1, 1, 11, 19, 3, 67, 3, 377, 487, 1287, 3463, 6523, 15237, 3171, 38673, 7359, 29739}},
-{15056, 18, 27854, {1, 3, 5, 11, 9, 13, 47, 191, 97, 641, 807, 1085, 1537, 2855, 24615, 32383, 66425, 53713}},
-{15057, 18, 27856, {1, 1, 5, 7, 19, 25, 93, 1, 21, 853, 813, 2535, 4291, 9051, 3385, 507, 73889, 85397}},
-{15058, 18, 27866, {1, 1, 3, 13, 7, 15, 103, 199, 83, 585, 1859, 2089, 839, 8923, 14615, 3399, 7703, 229937}},
-{15059, 18, 27875, {1, 1, 3, 3, 11, 23, 125, 135, 475, 613, 327, 339, 3081, 13221, 4889, 41233, 36547, 195357}},
-{15060, 18, 27902, {1, 3, 7, 7, 19, 23, 85, 217, 501, 447, 1873, 2175, 6753, 2825, 5171, 47561, 13321, 59583}},
-{15061, 18, 27916, {1, 1, 5, 13, 23, 59, 109, 195, 487, 785, 21, 1595, 5641, 10103, 8115, 60647, 78425, 237379}},
-{15062, 18, 27924, {1, 1, 3, 15, 21, 17, 85, 51, 369, 475, 1021, 1129, 7233, 6593, 12467, 55399, 128157, 80539}},
-{15063, 18, 27933, {1, 3, 3, 9, 31, 27, 69, 145, 489, 251, 1997, 1157, 2027, 16109, 4085, 24859, 63561, 79591}},
-{15064, 18, 27940, {1, 3, 3, 5, 29, 49, 41, 185, 405, 471, 431, 3539, 6593, 1185, 24383, 17009, 111215, 79839}},
-{15065, 18, 27947, {1, 1, 7, 3, 3, 15, 97, 157, 301, 227, 717, 3291, 2471, 11515, 30657, 30745, 72147, 98653}},
-{15066, 18, 27969, {1, 3, 5, 1, 23, 21, 67, 223, 185, 385, 137, 2897, 2423, 6119, 28471, 52269, 95725, 9105}},
-{15067, 18, 27981, {1, 3, 3, 11, 19, 1, 111, 131, 293, 495, 1043, 631, 1375, 15347, 22029, 29163, 120025, 81631}},
-{15068, 18, 27996, {1, 1, 7, 5, 17, 55, 47, 183, 367, 81, 555, 2857, 4787, 5605, 32053, 11815, 81771, 234993}},
-{15069, 18, 28005, {1, 3, 7, 15, 15, 49, 45, 221, 49, 299, 887, 3991, 2097, 10819, 23297, 1823, 11319, 205273}},
-{15070, 18, 28030, {1, 1, 1, 1, 1, 15, 91, 253, 213, 849, 501, 1073, 5503, 1379, 28887, 51811, 109763, 226149}},
-{15071, 18, 28064, {1, 1, 1, 7, 27, 39, 17, 29, 359, 655, 1695, 1781, 1203, 1125, 8983, 3477, 13925, 218399}},
-{15072, 18, 28102, {1, 3, 7, 13, 1, 25, 33, 185, 87, 19, 151, 371, 1221, 4859, 20103, 11435, 104263, 218515}},
-{15073, 18, 28108, {1, 1, 3, 5, 17, 43, 29, 149, 207, 39, 1539, 2933, 6825, 12391, 18163, 24543, 35305, 196295}},
-{15074, 18, 28120, {1, 3, 7, 9, 21, 61, 69, 231, 401, 95, 1757, 839, 3395, 7573, 6583, 34621, 119303, 20767}},
-{15075, 18, 28125, {1, 1, 7, 1, 25, 53, 63, 105, 241, 591, 23, 3219, 2387, 13945, 3047, 30939, 63243, 60941}},
-{15076, 18, 28130, {1, 1, 5, 7, 25, 47, 7, 227, 57, 279, 81, 4017, 3117, 6229, 20029, 30031, 25049, 102291}},
-{15077, 18, 28142, {1, 3, 3, 1, 21, 15, 69, 57, 311, 9, 853, 3377, 2949, 4781, 15419, 54741, 11603, 136821}},
-{15078, 18, 28149, {1, 3, 3, 13, 13, 5, 103, 253, 27, 449, 821, 3241, 41, 6643, 15217, 61691, 58463, 46117}},
-{15079, 18, 28165, {1, 1, 7, 7, 27, 51, 1, 239, 71, 955, 145, 1059, 5645, 7025, 4839, 11459, 3051, 235989}},
-{15080, 18, 28169, {1, 1, 5, 15, 15, 13, 33, 21, 209, 681, 1163, 3109, 1441, 6895, 20829, 48769, 35373, 195171}},
-{15081, 18, 28177, {1, 1, 7, 3, 11, 7, 25, 27, 463, 77, 1293, 1977, 4931, 8089, 11079, 14793, 123049, 32259}},
-{15082, 18, 28211, {1, 3, 1, 15, 11, 49, 7, 103, 79, 773, 235, 1653, 6477, 8835, 26627, 61101, 40633, 98155}},
-{15083, 18, 28213, {1, 3, 5, 7, 3, 53, 77, 197, 49, 57, 1533, 3485, 6603, 1131, 9073, 37023, 85293, 170883}},
-{15084, 18, 28220, {1, 3, 7, 15, 23, 5, 125, 75, 413, 521, 1897, 1099, 35, 2013, 687, 51511, 21359, 19995}},
-{15085, 18, 28261, {1, 3, 1, 11, 19, 13, 91, 181, 39, 613, 1917, 3149, 669, 9927, 20967, 38313, 13537, 181873}},
-{15086, 18, 28271, {1, 3, 5, 7, 5, 23, 25, 145, 189, 679, 483, 2689, 2855, 9631, 8863, 34841, 83311, 211507}},
-{15087, 18, 28299, {1, 3, 5, 15, 15, 15, 87, 53, 309, 807, 1405, 259, 3181, 12187, 31529, 8861, 70557, 247787}},
-{15088, 18, 28326, {1, 1, 7, 13, 7, 15, 1, 205, 91, 325, 1371, 531, 4917, 10291, 30827, 32491, 34497, 250301}},
-{15089, 18, 28330, {1, 3, 1, 11, 29, 17, 97, 37, 259, 1021, 1705, 4001, 4385, 7047, 14593, 63443, 3283, 18195}},
-{15090, 18, 28350, {1, 1, 7, 9, 9, 55, 11, 113, 351, 513, 197, 873, 1595, 11331, 27711, 419, 73097, 144357}},
-{15091, 18, 28355, {1, 3, 7, 15, 29, 31, 37, 15, 233, 573, 1457, 293, 5437, 15909, 3087, 24535, 6507, 173555}},
-{15092, 18, 28367, {1, 1, 1, 7, 7, 47, 81, 241, 257, 389, 233, 3275, 919, 14911, 14473, 58457, 78195, 121421}},
-{15093, 18, 28376, {1, 3, 7, 13, 1, 63, 9, 233, 231, 771, 1851, 3829, 7089, 4573, 13297, 58963, 2065, 8365}},
-{15094, 18, 28379, {1, 1, 5, 1, 31, 45, 45, 209, 77, 977, 159, 1521, 969, 10115, 32387, 52821, 124209, 51841}},
-{15095, 18, 28381, {1, 3, 5, 5, 13, 27, 53, 171, 91, 743, 217, 3805, 7721, 15127, 20679, 57459, 53649, 16381}},
-{15096, 18, 28447, {1, 3, 1, 15, 23, 43, 105, 169, 143, 759, 463, 1237, 3311, 2919, 16675, 53049, 12403, 153651}},
-{15097, 18, 28465, {1, 3, 3, 11, 5, 27, 1, 135, 17, 683, 679, 2591, 2929, 12417, 18379, 61903, 81991, 25231}},
-{15098, 18, 28471, {1, 1, 1, 5, 13, 59, 73, 119, 369, 445, 553, 243, 7523, 1105, 20349, 8417, 87535, 148857}},
-{15099, 18, 28472, {1, 3, 7, 15, 29, 3, 49, 49, 7, 753, 1597, 1427, 7485, 9119, 17427, 24961, 114897, 62841}},
-{15100, 18, 28478, {1, 1, 7, 7, 17, 35, 49, 225, 267, 801, 1359, 2131, 6093, 3859, 11305, 6287, 106459, 31093}},
-{15101, 18, 28480, {1, 1, 5, 3, 1, 45, 19, 89, 145, 23, 1071, 3053, 3463, 6781, 8635, 1961, 54403, 183401}},
-{15102, 18, 28489, {1, 3, 1, 13, 17, 35, 105, 155, 145, 597, 1169, 3731, 725, 2185, 23365, 31849, 113717, 185413}},
-{15103, 18, 28514, {1, 3, 3, 5, 3, 5, 13, 119, 39, 383, 1595, 63, 7003, 6465, 19847, 37213, 42921, 254479}},
-{15104, 18, 28525, {1, 3, 3, 1, 3, 33, 43, 255, 227, 151, 1911, 2657, 6529, 3855, 24411, 8485, 30385, 193265}},
-{15105, 18, 28537, {1, 1, 7, 7, 21, 53, 101, 37, 193, 107, 1095, 369, 6423, 3491, 1219, 53385, 31041, 122587}},
-{15106, 18, 28550, {1, 1, 7, 3, 13, 39, 101, 109, 113, 201, 619, 2489, 4545, 5017, 25519, 44281, 128605, 128595}},
-{15107, 18, 28559, {1, 1, 3, 13, 25, 7, 99, 141, 465, 625, 667, 1633, 6719, 16195, 365, 34355, 65025, 128025}},
-{15108, 18, 28595, {1, 1, 1, 7, 15, 51, 43, 159, 223, 493, 411, 65, 5753, 10219, 21885, 33267, 116643, 76777}},
-{15109, 18, 28601, {1, 3, 5, 13, 25, 39, 97, 31, 245, 367, 685, 103, 4093, 10449, 3849, 52659, 63355, 262059}},
-{15110, 18, 28629, {1, 3, 3, 1, 9, 49, 25, 157, 107, 821, 265, 2939, 6365, 7539, 17935, 50147, 88907, 214317}},
-{15111, 18, 28657, {1, 1, 1, 13, 17, 5, 55, 217, 137, 915, 121, 3187, 3111, 7145, 30477, 20023, 71969, 179417}},
-{15112, 18, 28667, {1, 1, 1, 5, 7, 15, 47, 71, 197, 725, 523, 2207, 5729, 741, 8595, 39125, 25431, 101093}},
-{15113, 18, 28711, {1, 3, 1, 7, 19, 37, 117, 235, 353, 459, 207, 953, 4955, 14979, 22897, 53911, 7783, 203667}},
-{15114, 18, 28718, {1, 1, 5, 13, 9, 17, 21, 95, 37, 751, 1463, 2491, 791, 1569, 32055, 61415, 113885, 259285}},
-{15115, 18, 28730, {1, 1, 3, 11, 1, 23, 5, 73, 61, 719, 215, 469, 3267, 12003, 16535, 46913, 58321, 2407}},
-{15116, 18, 28732, {1, 1, 5, 11, 5, 9, 81, 1, 275, 877, 791, 1591, 2109, 9983, 29085, 15069, 44757, 17887}},
-{15117, 18, 28777, {1, 3, 7, 11, 23, 47, 121, 53, 55, 677, 1239, 2591, 579, 11321, 14231, 53701, 71947, 56793}},
-{15118, 18, 28801, {1, 1, 5, 1, 7, 31, 39, 205, 231, 843, 159, 2301, 7765, 3317, 8935, 60647, 110545, 142543}},
-{15119, 18, 28822, {1, 3, 3, 11, 25, 39, 9, 131, 145, 373, 41, 1687, 417, 9427, 8657, 18315, 18505, 144055}},
-{15120, 18, 28855, {1, 3, 7, 3, 1, 51, 61, 223, 409, 607, 1281, 1767, 4719, 10741, 21537, 17307, 5473, 76127}},
-{15121, 18, 28859, {1, 1, 1, 1, 1, 43, 35, 157, 183, 835, 1141, 3235, 1383, 11381, 4503, 20435, 73125, 196955}},
-{15122, 18, 28869, {1, 1, 5, 7, 13, 47, 9, 191, 349, 587, 1887, 3667, 619, 9443, 28781, 7759, 6023, 81595}},
-{15123, 18, 28893, {1, 3, 5, 9, 31, 27, 77, 47, 375, 229, 989, 1241, 4937, 5881, 18797, 21743, 49947, 246165}},
-{15124, 18, 28904, {1, 1, 5, 1, 29, 23, 43, 237, 293, 391, 243, 3471, 5205, 9951, 29329, 19873, 114325, 19239}},
-{15125, 18, 28922, {1, 3, 3, 5, 19, 49, 23, 149, 419, 23, 21, 515, 3321, 3157, 28559, 8521, 11119, 192881}},
-{15126, 18, 28930, {1, 3, 1, 9, 29, 17, 15, 13, 171, 57, 1849, 3815, 7361, 7723, 23657, 60883, 54953, 159861}},
-{15127, 18, 28949, {1, 1, 3, 5, 13, 57, 35, 227, 143, 725, 2023, 2583, 2277, 4721, 4395, 61479, 112487, 211861}},
-{15128, 18, 28972, {1, 1, 5, 7, 7, 25, 83, 95, 281, 931, 415, 1661, 1543, 5313, 13317, 21203, 23965, 60891}},
-{15129, 18, 29002, {1, 3, 3, 1, 25, 51, 65, 147, 7, 521, 235, 2165, 6219, 14247, 30621, 43245, 8133, 49481}},
-{15130, 18, 29009, {1, 1, 5, 11, 13, 27, 39, 51, 213, 811, 151, 1157, 7821, 6481, 32097, 12319, 52005, 33291}},
-{15131, 18, 29061, {1, 1, 1, 13, 19, 15, 39, 205, 481, 253, 1643, 2969, 3181, 13995, 29877, 1307, 101721, 119111}},
-{15132, 18, 29068, {1, 1, 1, 11, 5, 63, 57, 53, 187, 315, 1521, 847, 5955, 3179, 21459, 25937, 83215, 181599}},
-{15133, 18, 29107, {1, 1, 7, 13, 17, 35, 113, 73, 105, 497, 1183, 3397, 4443, 14697, 29201, 40737, 40943, 3529}},
-{15134, 18, 29119, {1, 3, 5, 5, 3, 53, 101, 125, 173, 137, 333, 381, 1143, 1165, 789, 50013, 23595, 50235}},
-{15135, 18, 29142, {1, 1, 3, 1, 23, 3, 21, 143, 475, 337, 1693, 2341, 6509, 4167, 21031, 13887, 83191, 85187}},
-{15136, 18, 29146, {1, 1, 3, 1, 29, 59, 39, 217, 77, 943, 1531, 383, 6535, 2593, 8601, 61865, 26629, 57313}},
-{15137, 18, 29152, {1, 3, 5, 15, 17, 15, 19, 31, 273, 507, 1193, 2501, 4677, 13355, 5287, 1155, 102959, 185219}},
-{15138, 18, 29200, {1, 1, 1, 9, 3, 3, 5, 111, 159, 913, 331, 303, 3673, 12227, 5245, 63749, 107123, 26315}},
-{15139, 18, 29206, {1, 3, 5, 11, 13, 13, 115, 237, 481, 793, 1783, 1107, 4811, 3965, 29571, 63237, 15013, 176925}},
-{15140, 18, 29245, {1, 1, 7, 1, 13, 57, 85, 15, 19, 889, 1637, 1721, 6299, 6659, 5541, 24365, 38363, 67749}},
-{15141, 18, 29254, {1, 1, 3, 1, 9, 39, 15, 183, 133, 821, 1361, 2617, 7197, 8251, 12599, 60549, 42947, 72519}},
-{15142, 18, 29258, {1, 3, 1, 5, 19, 17, 69, 189, 309, 33, 2003, 569, 6189, 7845, 22351, 14623, 35287, 160511}},
-{15143, 18, 29260, {1, 1, 7, 13, 25, 3, 1, 203, 163, 661, 513, 3513, 741, 16259, 29817, 6059, 23823, 51869}},
-{15144, 18, 29268, {1, 3, 3, 1, 9, 43, 59, 77, 465, 223, 2007, 2187, 1499, 9373, 10535, 22207, 111689, 108485}},
-{15145, 18, 29281, {1, 1, 5, 15, 1, 21, 87, 163, 177, 751, 115, 3981, 4257, 5345, 31211, 44075, 16983, 69783}},
-{15146, 18, 29306, {1, 1, 1, 3, 29, 31, 7, 41, 181, 979, 1661, 1403, 2577, 983, 545, 6205, 20183, 44735}},
-{15147, 18, 29317, {1, 3, 3, 15, 5, 1, 85, 243, 59, 161, 1053, 803, 1813, 13583, 2559, 62761, 105337, 83209}},
-{15148, 18, 29324, {1, 3, 3, 3, 5, 21, 101, 61, 379, 369, 1865, 3289, 2643, 951, 26493, 17915, 8185, 42387}},
-{15149, 18, 29342, {1, 3, 5, 15, 15, 13, 119, 103, 141, 735, 1317, 3345, 2885, 4145, 30719, 965, 10819, 90295}},
-{15150, 18, 29375, {1, 3, 7, 13, 15, 11, 19, 163, 495, 369, 1285, 609, 1559, 9965, 31123, 55101, 76743, 104435}},
-{15151, 18, 29384, {1, 1, 5, 1, 25, 5, 5, 139, 441, 447, 353, 1369, 959, 14593, 30991, 20651, 126945, 2219}},
-{15152, 18, 29389, {1, 3, 5, 9, 21, 9, 113, 83, 115, 15, 161, 1559, 3095, 1447, 10253, 51481, 114541, 248375}},
-{15153, 18, 29411, {1, 3, 3, 1, 31, 61, 111, 69, 495, 195, 1153, 2605, 5061, 15509, 8253, 41909, 126033, 51173}},
-{15154, 18, 29413, {1, 1, 7, 15, 15, 41, 121, 75, 471, 539, 341, 441, 5357, 11509, 32525, 65477, 101251, 164835}},
-{15155, 18, 29446, {1, 1, 5, 7, 3, 63, 13, 123, 285, 499, 1023, 3533, 483, 13747, 26515, 52381, 9073, 256319}},
-{15156, 18, 29457, {1, 3, 1, 13, 29, 41, 75, 43, 229, 557, 1775, 1933, 5567, 11439, 22045, 10571, 96761, 98559}},
-{15157, 18, 29458, {1, 1, 3, 11, 19, 39, 3, 93, 435, 433, 2005, 1561, 385, 15865, 19763, 44105, 48107, 163063}},
-{15158, 18, 29483, {1, 1, 7, 5, 29, 37, 53, 19, 335, 325, 133, 2055, 3029, 14573, 30395, 38599, 97637, 203443}},
-{15159, 18, 29488, {1, 1, 7, 15, 29, 51, 7, 145, 21, 955, 1013, 579, 4971, 4849, 11691, 23725, 71079, 102641}},
-{15160, 18, 29494, {1, 1, 7, 3, 9, 49, 79, 187, 237, 823, 1951, 2947, 3633, 9119, 14393, 52969, 44703, 222389}},
-{15161, 18, 29506, {1, 3, 5, 11, 13, 9, 13, 245, 499, 661, 1899, 1313, 6907, 12259, 4577, 38547, 79687, 17555}},
-{15162, 18, 29553, {1, 3, 3, 1, 5, 59, 123, 197, 293, 247, 687, 695, 7493, 3115, 28535, 44335, 31905, 81607}},
-{15163, 18, 29569, {1, 3, 1, 3, 19, 5, 45, 101, 457, 395, 565, 3155, 8081, 4863, 1199, 32133, 73087, 27025}},
-{15164, 18, 29587, {1, 3, 7, 1, 31, 35, 111, 95, 379, 663, 731, 1813, 4551, 13105, 18275, 19729, 121971, 139959}},
-{15165, 18, 29590, {1, 1, 7, 3, 23, 47, 11, 117, 323, 943, 183, 2169, 4625, 12931, 1305, 23345, 119521, 67911}},
-{15166, 18, 29600, {1, 1, 1, 13, 19, 45, 37, 77, 301, 741, 747, 241, 5865, 11141, 7961, 10609, 97833, 256555}},
-{15167, 18, 29612, {1, 1, 1, 11, 27, 21, 119, 103, 277, 761, 201, 2063, 1043, 13303, 6535, 15553, 57695, 124187}},
-{15168, 18, 29665, {1, 3, 7, 3, 1, 11, 79, 143, 345, 237, 1421, 193, 1889, 2515, 11729, 559, 35227, 9393}},
-{15169, 18, 29722, {1, 3, 1, 1, 27, 27, 117, 159, 183, 871, 47, 989, 999, 303, 30833, 8229, 116301, 199439}},
-{15170, 18, 29745, {1, 1, 1, 1, 31, 27, 41, 83, 435, 409, 999, 2275, 4489, 1985, 21455, 23275, 125039, 192979}},
-{15171, 18, 29746, {1, 3, 7, 3, 19, 49, 27, 185, 9, 385, 191, 735, 3439, 16307, 21181, 58749, 128393, 140383}},
-{15172, 18, 29752, {1, 3, 7, 3, 15, 5, 65, 89, 11, 915, 673, 947, 3847, 6833, 10095, 34261, 101645, 42131}},
-{15173, 18, 29775, {1, 3, 5, 11, 11, 25, 79, 225, 495, 951, 1033, 5, 699, 9621, 1791, 48221, 59275, 49875}},
-{15174, 18, 29778, {1, 3, 7, 13, 29, 59, 105, 101, 233, 901, 863, 413, 2087, 16209, 445, 27463, 61465, 121795}},
-{15175, 18, 29800, {1, 1, 1, 11, 5, 19, 11, 51, 503, 313, 195, 3, 7249, 4919, 11931, 15569, 118297, 115989}},
-{15176, 18, 29829, {1, 3, 3, 13, 13, 61, 63, 57, 429, 487, 2033, 847, 7539, 1469, 3197, 1307, 124557, 211999}},
-{15177, 18, 29830, {1, 3, 7, 13, 25, 27, 39, 103, 165, 39, 1587, 3103, 1745, 12593, 10779, 37105, 29059, 256739}},
-{15178, 18, 29877, {1, 3, 3, 9, 25, 51, 105, 109, 99, 267, 623, 1351, 3837, 793, 28609, 52199, 15621, 77873}},
-{15179, 18, 29881, {1, 1, 3, 7, 29, 61, 45, 237, 431, 791, 91, 1259, 8071, 11103, 27257, 10153, 18639, 248949}},
-{15180, 18, 29884, {1, 1, 1, 9, 15, 47, 113, 189, 291, 837, 1317, 2263, 7183, 6669, 17241, 35275, 9087, 241577}},
-{15181, 18, 29895, {1, 1, 3, 1, 15, 59, 85, 21, 69, 569, 1473, 2735, 713, 3817, 14677, 26897, 75291, 251255}},
-{15182, 18, 29899, {1, 1, 1, 7, 17, 21, 105, 77, 367, 905, 513, 1807, 5571, 14627, 10349, 47821, 34395, 51143}},
-{15183, 18, 29916, {1, 3, 7, 13, 27, 19, 123, 145, 371, 857, 1699, 2231, 373, 781, 28713, 21441, 64059, 10689}},
-{15184, 18, 29923, {1, 1, 1, 7, 19, 57, 81, 223, 87, 315, 1253, 421, 1371, 1547, 1411, 6809, 23889, 213385}},
-{15185, 18, 29935, {1, 3, 1, 5, 23, 57, 89, 15, 227, 965, 1247, 3861, 7723, 15621, 7151, 53961, 47167, 73679}},
-{15186, 18, 29955, {1, 3, 7, 15, 31, 21, 9, 79, 87, 561, 1001, 3395, 2095, 15381, 30725, 48111, 68031, 121687}},
-{15187, 18, 29962, {1, 3, 1, 9, 15, 29, 83, 87, 377, 331, 2035, 93, 2319, 3637, 4809, 40091, 93141, 39881}},
-{15188, 18, 29969, {1, 3, 3, 11, 21, 39, 27, 159, 161, 439, 1417, 595, 4873, 15703, 32743, 56603, 35881, 160727}},
-{15189, 18, 29997, {1, 1, 3, 5, 21, 37, 55, 159, 497, 425, 469, 1185, 5015, 7045, 7179, 65325, 97167, 75723}},
-{15190, 18, 30032, {1, 3, 1, 7, 31, 21, 125, 223, 479, 765, 1115, 33, 2765, 12781, 22923, 36051, 103749, 33703}},
-{15191, 18, 30041, {1, 1, 7, 1, 9, 3, 29, 125, 337, 973, 253, 3179, 3269, 8801, 19369, 20693, 17331, 190295}},
-{15192, 18, 30048, {1, 1, 3, 3, 13, 5, 115, 31, 481, 45, 855, 81, 3663, 10443, 13853, 29847, 99471, 249943}},
-{15193, 18, 30060, {1, 1, 3, 7, 3, 1, 47, 31, 169, 625, 201, 2257, 4617, 1633, 26681, 53793, 78257, 8955}},
-{15194, 18, 30063, {1, 1, 5, 1, 23, 3, 95, 89, 429, 559, 119, 2619, 1235, 7609, 21905, 45495, 19461, 189091}},
-{15195, 18, 30105, {1, 3, 5, 5, 11, 33, 123, 45, 89, 899, 1607, 3717, 6745, 15199, 22955, 15891, 50411, 148201}},
-{15196, 18, 30122, {1, 3, 5, 9, 19, 23, 87, 21, 39, 117, 603, 823, 3015, 14853, 4341, 49029, 97183, 218713}},
-{15197, 18, 30141, {1, 1, 3, 7, 11, 55, 31, 255, 399, 861, 745, 1013, 4583, 15871, 32453, 25357, 90645, 100835}},
-{15198, 18, 30142, {1, 1, 1, 11, 13, 27, 57, 233, 45, 339, 305, 3689, 5273, 11801, 29109, 44139, 83171, 250559}},
-{15199, 18, 30153, {1, 3, 7, 13, 19, 1, 29, 113, 207, 313, 1465, 3563, 2535, 3307, 14921, 1923, 31429, 59815}},
-{15200, 18, 30171, {1, 3, 1, 5, 29, 25, 59, 95, 177, 795, 353, 3973, 8029, 1687, 5045, 16157, 30361, 218479}},
-{15201, 18, 30192, {1, 3, 5, 3, 5, 27, 109, 239, 121, 347, 93, 1645, 3293, 13181, 23793, 42935, 98659, 85385}},
-{15202, 18, 30197, {1, 1, 7, 9, 9, 37, 127, 211, 77, 557, 177, 2465, 7895, 5523, 26665, 23463, 71715, 126673}},
-{15203, 18, 30223, {1, 3, 7, 1, 27, 55, 125, 85, 47, 739, 1513, 3763, 5335, 3135, 11913, 22405, 90785, 88845}},
-{15204, 18, 30235, {1, 3, 3, 9, 29, 21, 123, 211, 491, 83, 697, 929, 3507, 7139, 30569, 16365, 122657, 77523}},
-{15205, 18, 30241, {1, 3, 5, 5, 27, 21, 41, 129, 67, 503, 877, 1893, 6055, 12709, 24613, 43831, 124035, 62631}},
-{15206, 18, 30256, {1, 3, 3, 1, 21, 15, 59, 185, 405, 487, 627, 3737, 345, 14751, 2947, 15815, 55047, 207137}},
-{15207, 18, 30291, {1, 1, 1, 9, 15, 29, 19, 155, 101, 405, 597, 329, 2977, 4333, 5465, 43863, 6009, 229481}},
-{15208, 18, 30293, {1, 1, 1, 11, 7, 27, 93, 207, 43, 599, 1899, 3979, 4219, 10199, 2901, 34261, 19435, 58317}},
-{15209, 18, 30300, {1, 1, 7, 15, 9, 47, 33, 209, 235, 655, 253, 3507, 3355, 1685, 7045, 58907, 41791, 175835}},
-{15210, 18, 30331, {1, 3, 3, 11, 11, 43, 21, 255, 45, 831, 1051, 1271, 7945, 9793, 11125, 17709, 118267, 169981}},
-{15211, 18, 30349, {1, 3, 7, 13, 27, 37, 45, 221, 243, 37, 1493, 2773, 6655, 7451, 22609, 56559, 12063, 221143}},
-{15212, 18, 30361, {1, 3, 1, 1, 9, 15, 97, 61, 241, 825, 735, 3953, 5331, 16373, 19403, 28933, 31881, 111545}},
-{15213, 18, 30367, {1, 1, 1, 15, 29, 1, 127, 111, 329, 741, 1589, 1653, 5949, 8703, 27617, 65285, 122167, 11895}},
-{15214, 18, 30392, {1, 1, 3, 3, 17, 31, 91, 197, 421, 865, 1901, 897, 6917, 15943, 12823, 15325, 17011, 110783}},
-{15215, 18, 30405, {1, 1, 3, 15, 21, 57, 29, 179, 503, 929, 1513, 205, 6083, 4015, 32517, 26921, 54229, 147789}},
-{15216, 18, 30410, {1, 1, 7, 15, 27, 21, 95, 59, 193, 97, 1235, 819, 4435, 371, 627, 24673, 1775, 261041}},
-{15217, 18, 30415, {1, 1, 7, 15, 3, 37, 99, 85, 505, 1011, 19, 1241, 5299, 15661, 27323, 44625, 12683, 225687}},
-{15218, 18, 30439, {1, 1, 7, 3, 25, 37, 111, 121, 217, 659, 365, 2627, 5499, 12911, 951, 54317, 51927, 235327}},
-{15219, 18, 30446, {1, 1, 3, 9, 29, 31, 99, 195, 427, 735, 1817, 3675, 4269, 1579, 12593, 39285, 74909, 230613}},
-{15220, 18, 30501, {1, 3, 1, 13, 7, 21, 37, 101, 111, 931, 1581, 465, 4753, 15607, 14515, 29769, 107711, 32703}},
-{15221, 18, 30526, {1, 1, 7, 15, 25, 57, 117, 119, 309, 345, 491, 3647, 2933, 5409, 15431, 43731, 25537, 17269}},
-{15222, 18, 30531, {1, 1, 5, 3, 15, 9, 83, 221, 501, 675, 1441, 129, 213, 5587, 22361, 16739, 118845, 192835}},
-{15223, 18, 30537, {1, 3, 7, 13, 1, 31, 75, 23, 13, 447, 687, 2711, 7577, 8275, 5051, 61835, 22159, 56477}},
-{15224, 18, 30546, {1, 1, 3, 1, 23, 19, 111, 45, 395, 841, 1665, 21, 7435, 12457, 11065, 20007, 48785, 15115}},
-{15225, 18, 30568, {1, 3, 7, 7, 21, 3, 117, 35, 117, 433, 561, 3045, 2169, 3255, 18015, 41093, 99699, 3479}},
-{15226, 18, 30581, {1, 1, 3, 7, 9, 59, 65, 143, 315, 63, 29, 3817, 1259, 7119, 20847, 44407, 80015, 37851}},
-{15227, 18, 30588, {1, 3, 7, 13, 13, 33, 85, 75, 39, 163, 1759, 1197, 5971, 8815, 8745, 45625, 121873, 246197}},
-{15228, 18, 30598, {1, 1, 1, 13, 31, 41, 61, 7, 145, 113, 943, 3757, 2141, 3523, 22351, 14143, 107683, 105579}},
-{15229, 18, 30607, {1, 1, 5, 5, 23, 27, 75, 77, 25, 901, 1295, 3091, 981, 10109, 12649, 15123, 102433, 145557}},
-{15230, 18, 30609, {1, 1, 7, 5, 9, 11, 19, 229, 301, 835, 1577, 3365, 425, 2271, 15647, 11685, 57315, 131043}},
-{15231, 18, 30616, {1, 3, 1, 13, 31, 3, 113, 7, 473, 395, 1979, 61, 4205, 2031, 28007, 34789, 54463, 94741}},
-{15232, 18, 30626, {1, 1, 3, 5, 7, 13, 35, 151, 461, 621, 185, 2645, 907, 9151, 25953, 26363, 105531, 235555}},
-{15233, 18, 30628, {1, 3, 3, 13, 21, 5, 43, 183, 149, 607, 509, 777, 4089, 16365, 32201, 60431, 58773, 92719}},
-{15234, 18, 30638, {1, 3, 3, 11, 25, 53, 103, 203, 269, 1017, 77, 3537, 4839, 15991, 29223, 57397, 122735, 67299}},
-{15235, 18, 30658, {1, 3, 3, 1, 29, 45, 85, 171, 307, 455, 1399, 2367, 5991, 5751, 27957, 36649, 9251, 38581}},
-{15236, 18, 30663, {1, 1, 5, 13, 29, 15, 127, 1, 175, 921, 671, 2469, 3137, 3679, 32521, 5321, 92505, 45901}},
-{15237, 18, 30675, {1, 3, 3, 11, 23, 23, 113, 255, 443, 609, 1085, 133, 5369, 885, 17043, 20961, 36137, 260457}},
-{15238, 18, 30698, {1, 3, 3, 9, 13, 55, 117, 19, 111, 323, 275, 495, 6679, 2217, 12015, 3053, 32745, 189413}},
-{15239, 18, 30708, {1, 3, 5, 13, 31, 43, 37, 225, 67, 755, 1427, 3967, 6497, 9987, 28145, 50583, 59457, 213217}},
-{15240, 18, 30712, {1, 3, 1, 15, 1, 5, 121, 249, 293, 695, 1697, 313, 61, 4037, 11757, 53739, 5693, 106225}},
-{15241, 18, 30727, {1, 1, 7, 1, 23, 9, 111, 211, 303, 147, 1291, 3807, 1969, 4115, 7473, 50077, 60745, 41605}},
-{15242, 18, 30736, {1, 3, 3, 15, 21, 51, 63, 171, 197, 403, 1327, 1851, 6991, 9069, 19221, 45765, 55489, 34853}},
-{15243, 18, 30748, {1, 1, 5, 3, 5, 53, 87, 241, 255, 309, 1319, 3727, 3189, 10887, 13401, 32371, 24479, 170571}},
-{15244, 18, 30758, {1, 1, 7, 11, 5, 5, 59, 177, 317, 835, 527, 165, 2137, 9597, 30181, 1779, 75407, 185827}},
-{15245, 18, 30775, {1, 3, 3, 7, 25, 15, 15, 183, 235, 955, 27, 2223, 5587, 11301, 17653, 56697, 70787, 198347}},
-{15246, 18, 30793, {1, 3, 5, 5, 11, 63, 123, 41, 169, 975, 1709, 2965, 7491, 4183, 15217, 41343, 36139, 9649}},
-{15247, 18, 30802, {1, 1, 3, 7, 5, 37, 87, 247, 379, 603, 781, 463, 8063, 13681, 32005, 43485, 107401, 42303}},
-{15248, 18, 30820, {1, 3, 5, 9, 19, 53, 61, 219, 217, 361, 769, 1687, 5643, 3145, 12885, 40303, 86377, 255051}},
-{15249, 18, 30823, {1, 1, 7, 11, 15, 49, 127, 99, 127, 515, 647, 1725, 1605, 2357, 2069, 31803, 14179, 180367}},
-{15250, 18, 30827, {1, 3, 5, 15, 9, 7, 41, 3, 49, 485, 1471, 207, 6477, 4463, 12255, 53481, 110785, 909}},
-{15251, 18, 30848, {1, 1, 5, 9, 23, 51, 107, 227, 205, 987, 1525, 2739, 6761, 12343, 32311, 12523, 93351, 29663}},
-{15252, 18, 30893, {1, 3, 5, 11, 21, 19, 53, 169, 197, 21, 825, 4029, 6733, 8943, 13475, 60677, 31001, 242291}},
-{15253, 18, 30906, {1, 3, 7, 13, 9, 27, 87, 37, 265, 877, 735, 2249, 4801, 2365, 16923, 40451, 29693, 222483}},
-{15254, 18, 30950, {1, 1, 3, 9, 31, 61, 71, 103, 215, 421, 193, 3451, 6181, 4271, 30875, 59573, 80773, 100369}},
-{15255, 18, 30956, {1, 1, 3, 13, 17, 55, 73, 191, 233, 821, 961, 1637, 2393, 3453, 25959, 5069, 114585, 186001}},
-{15256, 18, 30996, {1, 1, 7, 5, 15, 27, 39, 23, 69, 811, 709, 2349, 6011, 803, 12497, 7387, 62023, 247875}},
-{15257, 18, 31015, {1, 1, 5, 13, 29, 55, 51, 41, 121, 599, 1633, 3813, 1913, 3803, 26097, 53799, 30997, 261965}},
-{15258, 18, 31016, {1, 1, 1, 11, 31, 25, 19, 195, 87, 657, 1005, 3853, 61, 6585, 24665, 38283, 5495, 257201}},
-{15259, 18, 31034, {1, 1, 1, 11, 23, 43, 91, 121, 49, 491, 1443, 1873, 7689, 15957, 30463, 64079, 100003, 325}},
-{15260, 18, 31099, {1, 1, 7, 1, 25, 51, 27, 105, 119, 233, 513, 3403, 2647, 2847, 12687, 15619, 71225, 243759}},
-{15261, 18, 31123, {1, 1, 7, 3, 17, 49, 19, 123, 307, 463, 1619, 1853, 7019, 2605, 17351, 7971, 20675, 235929}},
-{15262, 18, 31145, {1, 1, 5, 3, 17, 29, 71, 215, 365, 955, 1631, 3549, 1379, 13881, 25409, 55703, 29863, 135401}},
-{15263, 18, 31166, {1, 3, 7, 15, 3, 27, 107, 149, 65, 681, 505, 3957, 6697, 11203, 9321, 63323, 98587, 199241}},
-{15264, 18, 31168, {1, 1, 1, 13, 27, 41, 59, 223, 431, 339, 1805, 899, 639, 6559, 13233, 4773, 37415, 110477}},
-{15265, 18, 31174, {1, 3, 7, 9, 1, 59, 79, 161, 311, 905, 1755, 3915, 6259, 8955, 14187, 11331, 86185, 209805}},
-{15266, 18, 31216, {1, 1, 7, 9, 5, 27, 75, 93, 285, 89, 891, 3341, 1157, 11219, 8883, 8093, 68949, 189643}},
-{15267, 18, 31219, {1, 3, 1, 5, 1, 43, 97, 71, 67, 605, 739, 1641, 4415, 4487, 13437, 12755, 121595, 55761}},
-{15268, 18, 31238, {1, 1, 1, 3, 1, 13, 61, 77, 297, 507, 1527, 3585, 4515, 13913, 7679, 28461, 61807, 196517}},
-{15269, 18, 31256, {1, 1, 1, 3, 21, 23, 101, 135, 59, 485, 1601, 3713, 7409, 349, 16543, 18897, 97253, 149055}},
-{15270, 18, 31304, {1, 1, 1, 13, 5, 37, 15, 37, 109, 1005, 363, 1925, 2701, 13169, 17027, 58453, 27667, 234027}},
-{15271, 18, 31315, {1, 1, 7, 1, 1, 41, 67, 231, 143, 951, 2023, 3465, 1717, 645, 17353, 9037, 129127, 199467}},
-{15272, 18, 31324, {1, 1, 1, 11, 27, 29, 65, 139, 425, 947, 141, 2601, 7339, 4451, 25065, 62691, 62355, 91819}},
-{15273, 18, 31364, {1, 3, 7, 15, 29, 29, 93, 25, 139, 267, 1319, 3839, 7295, 11855, 17775, 30199, 44127, 150875}},
-{15274, 18, 31379, {1, 3, 5, 1, 3, 55, 23, 191, 199, 583, 1167, 1357, 6477, 11827, 15581, 56541, 16603, 120139}},
-{15275, 18, 31382, {1, 1, 1, 3, 5, 47, 103, 211, 443, 491, 1043, 4001, 121, 1637, 5685, 42675, 13009, 22979}},
-{15276, 18, 31412, {1, 1, 1, 9, 21, 7, 77, 17, 303, 955, 51, 2389, 3573, 8817, 28053, 40269, 35457, 211023}},
-{15277, 18, 31451, {1, 3, 5, 15, 3, 39, 17, 75, 223, 37, 1231, 2127, 3575, 9085, 10715, 41871, 103703, 154181}},
-{15278, 18, 31487, {1, 3, 3, 15, 25, 31, 31, 223, 473, 267, 1519, 3205, 7029, 10753, 24757, 28187, 117921, 26783}},
-{15279, 18, 31509, {1, 3, 7, 1, 5, 21, 105, 191, 55, 115, 1813, 3701, 1673, 4199, 2441, 19737, 46913, 208725}},
-{15280, 18, 31510, {1, 1, 5, 5, 19, 63, 89, 141, 143, 783, 545, 883, 2979, 9219, 24983, 41793, 88441, 207095}},
-{15281, 18, 31520, {1, 1, 1, 9, 21, 21, 93, 161, 93, 733, 417, 3133, 8155, 12415, 16343, 11727, 82877, 94469}},
-{15282, 18, 31535, {1, 1, 5, 15, 5, 39, 33, 203, 213, 731, 1849, 1675, 6029, 2743, 1529, 16345, 13955, 54929}},
-{15283, 18, 31564, {1, 1, 7, 7, 23, 47, 121, 211, 271, 737, 1015, 1021, 5641, 12659, 27545, 52363, 104761, 150143}},
-{15284, 18, 31585, {1, 3, 1, 11, 11, 51, 79, 141, 255, 1007, 481, 3221, 7741, 6861, 24943, 63091, 46741, 33359}},
-{15285, 18, 31586, {1, 1, 3, 3, 27, 47, 85, 27, 423, 811, 75, 3911, 1951, 10821, 7487, 18971, 83355, 197479}},
-{15286, 18, 31600, {1, 1, 5, 5, 1, 63, 125, 251, 457, 795, 557, 217, 2335, 5659, 18375, 52183, 9789, 31417}},
-{15287, 18, 31643, {1, 3, 3, 3, 19, 61, 41, 129, 345, 361, 187, 3881, 43, 7197, 7673, 25011, 115155, 16375}},
-{15288, 18, 31646, {1, 3, 3, 7, 13, 7, 55, 91, 153, 341, 2003, 2013, 6891, 2411, 14825, 39555, 50267, 61405}},
-{15289, 18, 31649, {1, 3, 5, 7, 13, 57, 21, 91, 331, 615, 1297, 2881, 2011, 1907, 16489, 43061, 75731, 76675}},
-{15290, 18, 31650, {1, 1, 5, 5, 25, 15, 77, 175, 101, 885, 835, 529, 2787, 547, 20191, 50457, 58557, 61807}},
-{15291, 18, 31674, {1, 3, 7, 1, 13, 47, 101, 117, 179, 245, 861, 611, 4377, 5257, 12807, 26667, 19889, 112485}},
-{15292, 18, 31679, {1, 3, 7, 1, 27, 3, 23, 109, 197, 187, 963, 1827, 5741, 11921, 6359, 3989, 108939, 5761}},
-{15293, 18, 31684, {1, 1, 7, 5, 27, 7, 119, 159, 53, 969, 557, 597, 7821, 7121, 17341, 11233, 10811, 23969}},
-{15294, 18, 31688, {1, 1, 3, 13, 23, 55, 75, 131, 339, 917, 317, 2645, 5973, 9939, 26375, 29261, 80883, 229897}},
-{15295, 18, 31706, {1, 1, 5, 13, 3, 63, 41, 191, 315, 191, 649, 2119, 317, 14699, 4097, 19557, 97015, 124557}},
-{15296, 18, 31735, {1, 3, 7, 15, 13, 29, 29, 43, 47, 37, 729, 185, 4477, 15091, 13991, 18701, 56785, 218823}},
-{15297, 18, 31754, {1, 3, 7, 15, 31, 39, 17, 133, 469, 509, 995, 1683, 391, 1775, 15431, 63489, 7405, 122125}},
-{15298, 18, 31761, {1, 3, 7, 5, 15, 63, 5, 235, 193, 411, 1493, 3967, 3279, 6421, 13359, 20949, 68097, 69469}},
-{15299, 18, 31774, {1, 3, 3, 13, 7, 37, 7, 207, 399, 553, 1629, 1903, 329, 7577, 5813, 17151, 40889, 174811}},
-{15300, 18, 31807, {1, 3, 1, 13, 7, 39, 119, 109, 323, 61, 749, 1377, 911, 8195, 19753, 6265, 60783, 182339}},
-{15301, 18, 31812, {1, 1, 5, 11, 3, 21, 89, 61, 243, 273, 1317, 3443, 117, 6205, 13907, 12903, 95485, 103355}},
-{15302, 18, 31821, {1, 3, 7, 13, 19, 27, 45, 251, 405, 289, 121, 1501, 2599, 8111, 5163, 17437, 75095, 165847}},
-{15303, 18, 31855, {1, 3, 3, 5, 23, 13, 29, 145, 333, 573, 1939, 2133, 5797, 5263, 18835, 11945, 42161, 103123}},
-{15304, 18, 31919, {1, 3, 5, 13, 9, 31, 45, 17, 181, 111, 219, 3451, 1591, 5823, 20307, 41207, 77047, 173401}},
-{15305, 18, 31934, {1, 3, 1, 9, 19, 63, 73, 111, 377, 875, 1749, 2887, 7035, 14209, 1805, 20527, 93839, 225185}},
-{15306, 18, 31956, {1, 3, 1, 9, 15, 45, 97, 235, 11, 803, 899, 427, 3353, 7363, 26687, 1307, 5451, 176233}},
-{15307, 18, 31965, {1, 3, 7, 5, 7, 51, 59, 53, 3, 263, 159, 1005, 6079, 7237, 17419, 56653, 61091, 182209}},
-{15308, 18, 31975, {1, 1, 3, 15, 19, 47, 17, 185, 167, 219, 233, 2921, 5755, 1277, 27281, 33671, 3191, 169477}},
-{15309, 18, 31981, {1, 3, 7, 1, 25, 27, 99, 81, 57, 969, 821, 2397, 2947, 5913, 15247, 47651, 449, 183295}},
-{15310, 18, 31999, {1, 3, 1, 15, 3, 63, 83, 75, 41, 959, 1005, 153, 97, 15381, 6901, 55141, 90215, 161321}},
-{15311, 18, 32014, {1, 3, 1, 9, 1, 1, 29, 191, 43, 241, 607, 667, 1189, 4389, 31335, 14133, 104049, 100925}},
-{15312, 18, 32022, {1, 1, 3, 1, 1, 61, 109, 23, 325, 27, 1601, 3957, 7181, 8375, 9823, 50533, 114895, 73825}},
-{15313, 18, 32049, {1, 1, 7, 7, 1, 25, 51, 19, 383, 955, 1717, 2953, 5431, 7883, 14451, 18619, 9601, 153151}},
-{15314, 18, 32055, {1, 3, 1, 5, 1, 1, 35, 3, 141, 37, 1531, 1855, 7905, 6509, 6223, 45911, 54267, 172275}},
-{15315, 18, 32082, {1, 1, 3, 15, 23, 39, 109, 145, 215, 147, 1191, 2425, 301, 5543, 997, 31071, 101697, 169677}},
-{15316, 18, 32087, {1, 1, 3, 5, 17, 23, 41, 191, 367, 967, 1625, 3669, 769, 7599, 111, 4399, 64121, 232275}},
-{15317, 18, 32100, {1, 3, 5, 1, 25, 61, 47, 247, 413, 605, 399, 1233, 2789, 9775, 7111, 42853, 2305, 87423}},
-{15318, 18, 32104, {1, 3, 7, 3, 1, 25, 73, 247, 221, 235, 169, 889, 5635, 4325, 27015, 39549, 107545, 80885}},
-{15319, 18, 32109, {1, 1, 7, 11, 15, 55, 61, 103, 179, 157, 481, 3089, 4539, 375, 25425, 14995, 60119, 31031}},
-{15320, 18, 32138, {1, 3, 3, 1, 31, 17, 87, 123, 27, 309, 1693, 3871, 7319, 15615, 20113, 18239, 86407, 172381}},
-{15321, 18, 32140, {1, 1, 1, 13, 17, 31, 83, 149, 451, 305, 847, 223, 5705, 9697, 4967, 34273, 4041, 252891}},
-{15322, 18, 32148, {1, 3, 3, 15, 7, 27, 105, 207, 443, 825, 701, 1159, 5267, 14085, 28295, 41757, 47799, 14835}},
-{15323, 18, 32161, {1, 3, 7, 3, 1, 31, 77, 219, 139, 497, 1575, 905, 4341, 4611, 27861, 59871, 45525, 21735}},
-{15324, 18, 32162, {1, 3, 3, 3, 7, 17, 65, 183, 231, 955, 1111, 1899, 1677, 13685, 29395, 10449, 62505, 125643}},
-{15325, 18, 32174, {1, 3, 5, 7, 27, 57, 81, 165, 279, 989, 1569, 573, 7593, 10067, 1343, 12039, 117175, 225125}},
-{15326, 18, 32196, {1, 3, 3, 15, 19, 37, 47, 175, 87, 153, 1137, 1985, 2473, 14767, 19587, 41751, 98937, 66667}},
-{15327, 18, 32220, {1, 3, 5, 3, 19, 51, 25, 155, 37, 597, 719, 1039, 165, 1871, 15677, 59891, 29899, 231979}},
-{15328, 18, 32223, {1, 3, 5, 13, 15, 39, 17, 21, 73, 695, 1813, 2463, 3549, 3081, 14037, 13077, 40417, 258995}},
-{15329, 18, 32267, {1, 1, 5, 9, 29, 5, 105, 75, 97, 937, 1767, 975, 637, 9419, 30673, 33537, 979, 45381}},
-{15330, 18, 32272, {1, 1, 5, 9, 3, 31, 91, 193, 171, 163, 925, 3519, 3621, 4943, 14093, 22881, 18459, 110155}},
-{15331, 18, 32308, {1, 1, 3, 7, 29, 1, 39, 107, 359, 805, 91, 2911, 4741, 3099, 16967, 45849, 95255, 63225}},
-{15332, 18, 32315, {1, 1, 5, 13, 25, 41, 49, 145, 345, 823, 1571, 341, 6323, 9679, 14855, 19965, 108367, 99833}},
-{15333, 18, 32317, {1, 3, 5, 3, 27, 35, 87, 83, 373, 425, 281, 1313, 5153, 6301, 2745, 12677, 34603, 181835}},
-{15334, 18, 32347, {1, 1, 7, 7, 13, 17, 83, 101, 141, 789, 1403, 2777, 2749, 1551, 9009, 9909, 48443, 176679}},
-{15335, 18, 32360, {1, 3, 5, 9, 7, 25, 125, 109, 155, 357, 1111, 3057, 771, 11253, 25811, 60333, 68505, 146987}},
-{15336, 18, 32394, {1, 3, 7, 7, 29, 19, 69, 115, 411, 793, 51, 715, 3035, 11577, 14237, 23963, 13915, 196771}},
-{15337, 18, 32411, {1, 1, 3, 3, 27, 37, 61, 163, 131, 749, 37, 1333, 47, 2519, 25473, 40851, 55861, 113961}},
-{15338, 18, 32420, {1, 3, 5, 1, 3, 49, 19, 251, 125, 387, 1887, 3571, 1465, 4831, 3859, 43357, 20859, 225835}},
-{15339, 18, 32423, {1, 3, 5, 9, 27, 53, 53, 143, 383, 781, 819, 2921, 3499, 11551, 18761, 14453, 58209, 181763}},
-{15340, 18, 32455, {1, 3, 7, 9, 17, 17, 79, 61, 145, 413, 541, 895, 2077, 6957, 28681, 44821, 30609, 131705}},
-{15341, 18, 32456, {1, 1, 3, 15, 1, 57, 17, 125, 11, 43, 1079, 1023, 5391, 67, 31701, 5737, 429, 75411}},
-{15342, 18, 32510, {1, 1, 7, 7, 21, 45, 65, 127, 447, 793, 161, 333, 637, 7403, 12861, 30173, 125121, 254687}},
-{15343, 18, 32517, {1, 1, 3, 9, 27, 53, 85, 223, 297, 455, 919, 2371, 7049, 7167, 18075, 22815, 10265, 14765}},
-{15344, 18, 32541, {1, 1, 3, 7, 1, 53, 91, 181, 471, 101, 771, 4043, 3039, 1215, 19289, 15941, 55187, 147355}},
-{15345, 18, 32552, {1, 3, 1, 1, 13, 19, 13, 47, 159, 965, 1383, 297, 4299, 7181, 1271, 17057, 114847, 180883}},
-{15346, 18, 32555, {1, 3, 1, 15, 29, 55, 113, 243, 215, 665, 641, 1975, 5907, 2617, 17077, 43697, 61101, 70007}},
-{15347, 18, 32580, {1, 3, 1, 11, 5, 55, 109, 145, 307, 663, 1327, 1247, 8033, 15425, 18539, 57027, 72161, 181655}},
-{15348, 18, 32598, {1, 3, 5, 9, 25, 17, 3, 57, 7, 449, 1049, 3423, 5769, 12713, 29849, 1017, 92579, 131255}},
-{15349, 18, 32654, {1, 1, 7, 13, 25, 13, 55, 217, 461, 595, 931, 1883, 2645, 9625, 20467, 45825, 72027, 163767}},
-{15350, 18, 32662, {1, 3, 5, 15, 29, 49, 23, 47, 45, 645, 973, 3837, 621, 7373, 3585, 16083, 93823, 184593}},
-{15351, 18, 32665, {1, 3, 7, 11, 27, 19, 59, 125, 447, 33, 541, 1067, 6983, 3779, 27275, 34269, 106937, 65085}},
-{15352, 18, 32678, {1, 3, 1, 9, 23, 23, 51, 43, 475, 861, 1759, 2559, 3059, 1175, 31555, 27671, 117653, 162735}},
-{15353, 18, 32682, {1, 1, 7, 13, 7, 61, 33, 49, 23, 737, 949, 1785, 2921, 873, 26631, 61941, 14467, 76225}},
-{15354, 18, 32687, {1, 3, 7, 5, 31, 11, 49, 149, 7, 85, 1929, 1001, 4185, 221, 23719, 52265, 52973, 67967}},
-{15355, 18, 32692, {1, 3, 1, 13, 17, 31, 35, 191, 65, 527, 51, 1093, 3673, 11167, 29985, 59739, 43567, 109817}},
-{15356, 18, 32710, {1, 1, 1, 11, 23, 39, 95, 121, 501, 355, 1043, 993, 7533, 15763, 18399, 31601, 49373, 243209}},
-{15357, 18, 32791, {1, 1, 3, 3, 15, 37, 57, 183, 27, 981, 153, 1481, 549, 7847, 2689, 57401, 46359, 175401}},
-{15358, 18, 32792, {1, 3, 5, 9, 31, 19, 83, 79, 413, 597, 1957, 3027, 4751, 1437, 11255, 39513, 56927, 166841}},
-{15359, 18, 32813, {1, 3, 7, 5, 27, 61, 69, 65, 143, 321, 1129, 2521, 4467, 4369, 11727, 35643, 80155, 184241}},
-{15360, 18, 32826, {1, 3, 7, 1, 25, 27, 107, 219, 481, 457, 2027, 1057, 6409, 5641, 19711, 11009, 44295, 28171}},
-{15361, 18, 32831, {1, 3, 3, 9, 3, 17, 85, 5, 341, 107, 2037, 93, 741, 5279, 20093, 28637, 80823, 210279}},
-{15362, 18, 32836, {1, 1, 7, 15, 5, 9, 33, 167, 451, 463, 1951, 2395, 3821, 2915, 15195, 34517, 113545, 22173}},
-{15363, 18, 32843, {1, 1, 3, 1, 23, 55, 113, 159, 139, 795, 69, 2021, 6769, 10807, 18605, 54161, 39501, 233797}},
-{15364, 18, 32854, {1, 1, 7, 11, 17, 53, 103, 131, 385, 909, 629, 3127, 6117, 11457, 31115, 8255, 33227, 170877}},
-{15365, 18, 32893, {1, 1, 3, 9, 23, 19, 99, 221, 141, 731, 311, 2617, 2763, 375, 26763, 56473, 6613, 60519}},
-{15366, 18, 32897, {1, 3, 1, 9, 7, 29, 15, 105, 243, 159, 1755, 3999, 5861, 12009, 30111, 48269, 70427, 187173}},
-{15367, 18, 32912, {1, 1, 3, 13, 1, 35, 39, 121, 409, 571, 1835, 1535, 4671, 12671, 4503, 4783, 48009, 216837}},
-{15368, 18, 32951, {1, 1, 1, 9, 25, 61, 87, 109, 489, 107, 1741, 859, 237, 7161, 27117, 58587, 55445, 155763}},
-{15369, 18, 32963, {1, 1, 7, 15, 9, 21, 61, 159, 301, 863, 1823, 11, 419, 6717, 28199, 24129, 58419, 22147}},
-{15370, 18, 32970, {1, 3, 1, 5, 9, 7, 13, 205, 185, 759, 777, 2877, 5991, 14555, 18793, 51485, 6373, 232105}},
-{15371, 18, 32975, {1, 1, 3, 5, 7, 25, 51, 79, 227, 447, 867, 2709, 2677, 15249, 22957, 45577, 39011, 16839}},
-{15372, 18, 33028, {1, 1, 1, 3, 5, 51, 69, 135, 395, 339, 685, 3657, 3789, 16345, 2911, 51737, 97471, 126605}},
-{15373, 18, 33052, {1, 3, 7, 15, 15, 5, 85, 153, 507, 347, 1457, 527, 1055, 7773, 4161, 10487, 92373, 256535}},
-{15374, 18, 33061, {1, 3, 3, 3, 1, 9, 25, 1, 155, 321, 1739, 555, 7719, 10501, 19075, 12529, 75975, 229905}},
-{15375, 18, 33083, {1, 1, 1, 3, 29, 31, 89, 23, 283, 875, 1653, 855, 7613, 15277, 23845, 47443, 287, 217441}},
-{15376, 18, 33103, {1, 3, 3, 1, 25, 7, 75, 119, 493, 131, 231, 3063, 7171, 5437, 16385, 50347, 87427, 53603}},
-{15377, 18, 33117, {1, 3, 7, 7, 27, 55, 103, 223, 219, 103, 733, 1233, 1931, 2119, 19333, 59839, 100421, 256811}},
-{15378, 18, 33139, {1, 3, 7, 15, 23, 63, 77, 151, 285, 701, 1403, 1267, 6975, 11421, 24943, 51647, 75651, 191675}},
-{15379, 18, 33151, {1, 1, 5, 7, 25, 23, 25, 7, 503, 759, 997, 1711, 1439, 12483, 30117, 55205, 8813, 221589}},
-{15380, 18, 33162, {1, 3, 7, 5, 21, 3, 117, 65, 461, 851, 915, 575, 3061, 1055, 11999, 8375, 128677, 98005}},
-{15381, 18, 33209, {1, 3, 7, 7, 19, 13, 123, 23, 41, 293, 79, 1435, 1175, 7399, 14907, 4671, 88029, 220627}},
-{15382, 18, 33210, {1, 3, 3, 13, 11, 17, 65, 21, 143, 257, 1001, 2423, 5659, 11681, 23605, 40649, 49797, 55497}},
-{15383, 18, 33223, {1, 3, 5, 5, 29, 15, 125, 83, 139, 381, 1435, 2129, 1699, 10725, 531, 767, 112477, 134223}},
-{15384, 18, 33227, {1, 3, 7, 9, 9, 23, 35, 1, 127, 143, 707, 1475, 4705, 8921, 14919, 50909, 64425, 33381}},
-{15385, 18, 33241, {1, 1, 1, 15, 11, 63, 87, 101, 243, 833, 707, 4095, 201, 4877, 10219, 39019, 129779, 229857}},
-{15386, 18, 33263, {1, 1, 1, 11, 5, 9, 35, 177, 303, 545, 917, 1037, 1789, 12147, 29095, 27391, 112833, 104713}},
-{15387, 18, 33341, {1, 1, 1, 5, 27, 23, 111, 219, 439, 445, 967, 3527, 6203, 1829, 19657, 48965, 85213, 58719}},
-{15388, 18, 33344, {1, 3, 7, 11, 15, 7, 95, 113, 317, 225, 1229, 3033, 5777, 4075, 24093, 3539, 19333, 212757}},
-{15389, 18, 33356, {1, 3, 7, 7, 1, 35, 35, 67, 459, 769, 1675, 3509, 7393, 10433, 12003, 7385, 4425, 188989}},
-{15390, 18, 33390, {1, 1, 7, 9, 5, 45, 35, 27, 443, 301, 533, 2803, 99, 17, 20749, 58353, 93067, 118763}},
-{15391, 18, 33398, {1, 1, 3, 3, 13, 51, 61, 181, 81, 859, 1461, 3455, 2277, 13769, 1251, 4313, 119973, 30693}},
-{15392, 18, 33423, {1, 1, 3, 7, 15, 29, 23, 207, 239, 65, 1889, 151, 7793, 2657, 13673, 29033, 74477, 215027}},
-{15393, 18, 33428, {1, 1, 5, 1, 19, 35, 19, 71, 187, 783, 543, 505, 347, 3191, 1087, 49735, 54109, 27979}},
-{15394, 18, 33444, {1, 3, 3, 3, 3, 61, 67, 59, 207, 957, 1709, 1567, 7973, 5921, 29841, 8311, 81165, 91965}},
-{15395, 18, 33454, {1, 1, 1, 7, 23, 47, 109, 189, 447, 861, 1615, 3283, 3059, 749, 28729, 8713, 38743, 211019}},
-{15396, 18, 33479, {1, 3, 5, 1, 17, 51, 127, 181, 355, 515, 603, 465, 1825, 9281, 31971, 42793, 22467, 175777}},
-{15397, 18, 33510, {1, 3, 1, 5, 3, 29, 111, 91, 99, 15, 535, 3047, 1083, 7181, 28003, 60719, 71825, 12293}},
-{15398, 18, 33514, {1, 3, 5, 7, 1, 43, 83, 117, 221, 353, 139, 647, 6017, 4655, 31823, 22097, 118537, 71803}},
-{15399, 18, 33528, {1, 1, 3, 3, 27, 11, 35, 169, 215, 883, 1195, 2983, 4651, 15893, 24051, 313, 103947, 5227}},
-{15400, 18, 33548, {1, 3, 5, 13, 3, 51, 33, 159, 499, 763, 845, 1541, 3837, 9397, 855, 4187, 112167, 243817}},
-{15401, 18, 33566, {1, 1, 7, 9, 1, 15, 19, 239, 227, 561, 1685, 2841, 53, 9753, 15105, 34277, 128859, 100085}},
-{15402, 18, 33570, {1, 3, 5, 13, 15, 7, 57, 9, 415, 1005, 583, 1347, 4349, 3603, 9125, 15019, 77735, 237011}},
-{15403, 18, 33593, {1, 1, 1, 13, 27, 21, 105, 17, 235, 605, 1417, 2053, 3233, 11617, 28651, 43161, 71663, 98373}},
-{15404, 18, 33599, {1, 3, 5, 13, 29, 17, 123, 105, 477, 359, 613, 1699, 2581, 3007, 8507, 14391, 95487, 633}},
-{15405, 18, 33619, {1, 1, 7, 7, 13, 55, 107, 211, 71, 339, 1169, 2629, 165, 16207, 25523, 7101, 47553, 261131}},
-{15406, 18, 33635, {1, 3, 5, 15, 11, 7, 45, 207, 39, 41, 781, 3347, 2529, 4475, 9665, 31499, 119837, 128755}},
-{15407, 18, 33659, {1, 3, 1, 15, 23, 59, 59, 17, 89, 823, 59, 3991, 305, 14893, 1411, 8015, 92193, 66935}},
-{15408, 18, 33680, {1, 1, 7, 15, 19, 29, 11, 207, 429, 851, 1661, 2903, 4413, 447, 29447, 39243, 70435, 160451}},
-{15409, 18, 33699, {1, 1, 3, 13, 17, 5, 93, 89, 455, 67, 33, 65, 7957, 14383, 28525, 56983, 71899, 4881}},
-{15410, 18, 33713, {1, 3, 3, 5, 11, 7, 47, 233, 433, 791, 47, 2561, 6539, 1151, 2083, 12309, 62353, 69507}},
-{15411, 18, 33758, {1, 3, 5, 11, 15, 55, 101, 251, 41, 39, 383, 3481, 1817, 3447, 6205, 38169, 98267, 157091}},
-{15412, 18, 33771, {1, 3, 5, 7, 9, 47, 113, 55, 421, 703, 849, 2251, 129, 9257, 28097, 33475, 98933, 32041}},
-{15413, 18, 33779, {1, 3, 3, 11, 9, 59, 1, 211, 277, 969, 977, 3079, 4707, 3341, 17679, 9469, 52859, 125883}},
-{15414, 18, 33800, {1, 1, 7, 13, 29, 19, 49, 149, 259, 573, 1137, 2571, 2661, 12865, 24993, 10721, 96921, 85931}},
-{15415, 18, 33829, {1, 3, 1, 9, 15, 27, 91, 127, 305, 159, 523, 2539, 1969, 4325, 595, 37077, 79919, 26889}},
-{15416, 18, 33836, {1, 3, 1, 11, 1, 5, 65, 75, 317, 909, 1601, 2713, 6891, 4927, 28427, 5791, 82285, 35209}},
-{15417, 18, 33844, {1, 3, 7, 7, 9, 5, 111, 167, 477, 437, 1133, 2715, 6189, 5051, 4765, 26267, 99819, 70419}},
-{15418, 18, 33856, {1, 1, 3, 9, 27, 57, 23, 233, 423, 191, 1159, 1539, 6397, 16041, 8803, 19787, 114447, 17029}},
-{15419, 18, 33859, {1, 1, 5, 1, 11, 3, 111, 125, 287, 487, 1663, 1953, 3771, 2011, 18167, 47471, 94041, 87569}},
-{15420, 18, 33873, {1, 3, 1, 11, 5, 9, 75, 153, 37, 803, 971, 1667, 4631, 9183, 20179, 6905, 80949, 54443}},
-{15421, 18, 33874, {1, 1, 1, 5, 13, 29, 91, 201, 49, 739, 1569, 2725, 257, 5505, 5289, 40731, 27843, 16565}},
-{15422, 18, 33929, {1, 1, 7, 13, 27, 41, 81, 199, 99, 43, 1331, 3237, 6493, 3839, 19329, 44371, 19715, 60553}},
-{15423, 18, 33944, {1, 1, 5, 7, 29, 41, 67, 163, 467, 93, 1977, 2625, 6967, 6655, 19835, 39517, 10259, 200487}},
-{15424, 18, 33965, {1, 1, 3, 15, 23, 35, 31, 171, 175, 883, 593, 245, 6209, 7381, 5555, 54507, 66159, 40771}},
-{15425, 18, 33978, {1, 3, 3, 11, 3, 63, 75, 177, 239, 77, 1543, 875, 7951, 7571, 961, 9909, 101781, 160399}},
-{15426, 18, 33986, {1, 3, 1, 3, 3, 37, 71, 231, 373, 443, 835, 1321, 2107, 2929, 7527, 47969, 15329, 94537}},
-{15427, 18, 34006, {1, 3, 3, 15, 7, 5, 127, 121, 159, 25, 399, 3009, 4401, 9649, 4311, 18045, 22557, 135177}},
-{15428, 18, 34025, {1, 1, 1, 3, 29, 57, 75, 73, 261, 493, 1417, 1351, 3407, 8553, 4893, 10325, 123149, 161435}},
-{15429, 18, 34106, {1, 3, 3, 11, 15, 5, 87, 115, 337, 213, 949, 1925, 5057, 5831, 6837, 51167, 25291, 182197}},
-{15430, 18, 34126, {1, 3, 1, 11, 25, 49, 27, 101, 403, 989, 1129, 3933, 1147, 13091, 11965, 38075, 68251, 103293}},
-{15431, 18, 34171, {1, 1, 7, 5, 7, 49, 1, 189, 275, 63, 149, 3255, 1175, 7811, 24845, 20755, 99391, 140673}},
-{15432, 18, 34189, {1, 3, 1, 13, 17, 35, 37, 37, 415, 125, 643, 443, 6215, 299, 31237, 45687, 78535, 102123}},
-{15433, 18, 34204, {1, 3, 5, 3, 27, 41, 85, 215, 47, 21, 725, 1967, 2317, 121, 7827, 48229, 82027, 60271}},
-{15434, 18, 34260, {1, 3, 5, 1, 1, 55, 37, 183, 117, 421, 383, 3883, 5519, 6161, 6823, 18423, 77747, 215969}},
-{15435, 18, 34270, {1, 3, 5, 13, 31, 3, 117, 59, 375, 797, 1129, 1283, 3245, 12775, 30353, 3837, 130273, 228899}},
-{15436, 18, 34280, {1, 3, 5, 1, 7, 33, 17, 153, 179, 255, 537, 2911, 1223, 367, 18131, 25903, 33509, 220031}},
-{15437, 18, 34298, {1, 3, 7, 5, 5, 7, 103, 233, 309, 947, 1835, 3509, 4267, 15619, 5895, 30707, 81841, 191899}},
-{15438, 18, 34313, {1, 1, 5, 11, 3, 15, 91, 83, 319, 765, 895, 2565, 6833, 1719, 2971, 37483, 21709, 23193}},
-{15439, 18, 34321, {1, 1, 3, 11, 31, 57, 83, 233, 439, 161, 1503, 749, 6347, 15379, 2317, 24671, 93399, 239585}},
-{15440, 18, 34333, {1, 1, 3, 9, 29, 45, 19, 107, 295, 153, 189, 2521, 5465, 7321, 6143, 229, 100553, 258911}},
-{15441, 18, 34370, {1, 3, 7, 11, 31, 27, 95, 21, 249, 981, 1725, 1481, 1025, 9301, 11809, 53109, 29007, 127683}},
-{15442, 18, 34376, {1, 3, 1, 3, 1, 23, 97, 137, 5, 471, 1887, 1035, 2681, 5143, 3145, 1517, 88107, 245245}},
-{15443, 18, 34387, {1, 1, 1, 1, 15, 11, 13, 9, 405, 607, 403, 1693, 4363, 9365, 6425, 48121, 78969, 87341}},
-{15444, 18, 34389, {1, 1, 7, 15, 3, 17, 7, 51, 111, 1023, 9, 465, 1909, 16283, 4763, 50939, 119029, 198257}},
-{15445, 18, 34417, {1, 3, 3, 1, 31, 11, 113, 13, 499, 433, 1941, 991, 5439, 3123, 24591, 16171, 55099, 206015}},
-{15446, 18, 34429, {1, 3, 5, 15, 25, 49, 125, 101, 251, 619, 1895, 4063, 3065, 14965, 20081, 11233, 58253, 69633}},
-{15447, 18, 34440, {1, 1, 1, 5, 21, 35, 29, 241, 359, 553, 1001, 1865, 5183, 5233, 16371, 55277, 102091, 143275}},
-{15448, 18, 34443, {1, 1, 1, 3, 29, 37, 3, 191, 239, 961, 2031, 1337, 1169, 5229, 22861, 38257, 55027, 153703}},
-{15449, 18, 34451, {1, 3, 5, 7, 7, 35, 49, 139, 509, 381, 1267, 2641, 747, 16239, 23133, 32111, 70471, 128427}},
-{15450, 18, 34470, {1, 1, 1, 9, 23, 25, 117, 125, 369, 891, 103, 2215, 3571, 1291, 9001, 35671, 67119, 198847}},
-{15451, 18, 34484, {1, 1, 5, 9, 17, 19, 27, 7, 207, 55, 1099, 2117, 7511, 14999, 7761, 32215, 103401, 68599}},
-{15452, 18, 34493, {1, 1, 7, 9, 1, 59, 41, 91, 9, 225, 457, 3241, 4713, 2923, 11973, 2867, 130583, 202007}},
-{15453, 18, 34496, {1, 3, 1, 9, 31, 47, 63, 49, 457, 757, 885, 937, 2973, 12147, 2607, 52907, 126047, 83275}},
-{15454, 18, 34514, {1, 3, 5, 11, 17, 1, 79, 123, 505, 203, 1779, 71, 4357, 2285, 31625, 15225, 86519, 2021}},
-{15455, 18, 34526, {1, 3, 1, 11, 21, 17, 41, 169, 125, 995, 351, 1235, 25, 7463, 2099, 18917, 71355, 26983}},
-{15456, 18, 34535, {1, 1, 7, 1, 21, 23, 41, 5, 415, 405, 1235, 1245, 151, 11283, 25293, 45147, 12597, 39501}},
-{15457, 18, 34585, {1, 1, 1, 5, 29, 29, 15, 165, 259, 179, 1479, 3535, 779, 6583, 885, 34331, 71193, 154417}},
-{15458, 18, 34591, {1, 1, 1, 5, 3, 1, 13, 181, 507, 339, 333, 4059, 7963, 15649, 15507, 16913, 34741, 202039}},
-{15459, 18, 34592, {1, 3, 7, 1, 1, 9, 17, 119, 77, 583, 259, 883, 4011, 4275, 9599, 58663, 73237, 202783}},
-{15460, 18, 34602, {1, 1, 5, 11, 23, 27, 19, 171, 373, 779, 661, 1701, 3363, 13095, 897, 51233, 1319, 41093}},
-{15461, 18, 34607, {1, 3, 3, 3, 29, 21, 105, 29, 429, 657, 1735, 1279, 809, 14963, 9735, 23251, 44879, 159371}},
-{15462, 18, 34644, {1, 1, 5, 11, 17, 27, 117, 65, 193, 539, 1095, 439, 1687, 11277, 513, 30611, 88885, 69145}},
-{15463, 18, 34657, {1, 3, 1, 7, 11, 1, 27, 41, 63, 501, 917, 2397, 6839, 10835, 26437, 56169, 46631, 64095}},
-{15464, 18, 34675, {1, 1, 7, 15, 29, 5, 17, 217, 333, 389, 403, 3167, 3599, 12055, 30669, 44821, 109811, 237393}},
-{15465, 18, 34681, {1, 3, 5, 13, 1, 39, 51, 233, 159, 135, 763, 2499, 7741, 13099, 8639, 8043, 39827, 5989}},
-{15466, 18, 34693, {1, 1, 7, 3, 1, 61, 41, 37, 37, 67, 867, 2631, 6265, 5551, 161, 56643, 126087, 126829}},
-{15467, 18, 34706, {1, 1, 7, 1, 21, 39, 101, 225, 489, 123, 661, 2489, 1865, 6809, 21663, 59405, 45579, 51257}},
-{15468, 18, 34745, {1, 3, 7, 9, 27, 53, 11, 97, 369, 389, 1933, 3321, 543, 12331, 11571, 10685, 49049, 244027}},
-{15469, 18, 34759, {1, 3, 5, 3, 7, 15, 21, 165, 181, 877, 1161, 1815, 2097, 449, 32411, 22843, 12467, 55397}},
-{15470, 18, 34765, {1, 3, 1, 3, 11, 45, 23, 193, 287, 137, 333, 1831, 457, 583, 23081, 4525, 4781, 249509}},
-{15471, 18, 34774, {1, 3, 5, 5, 15, 13, 27, 199, 267, 297, 923, 3861, 4949, 7945, 25291, 45407, 47529, 127287}},
-{15472, 18, 34780, {1, 1, 5, 7, 19, 29, 113, 51, 503, 487, 699, 2097, 2957, 6519, 19487, 46873, 38871, 89997}},
-{15473, 18, 34794, {1, 1, 5, 13, 17, 31, 57, 127, 335, 223, 1545, 3749, 1539, 3293, 21159, 13019, 48343, 190895}},
-{15474, 18, 34807, {1, 1, 7, 9, 25, 19, 75, 41, 511, 269, 819, 3313, 6805, 15051, 4349, 1809, 34841, 190641}},
-{15475, 18, 34808, {1, 3, 5, 9, 27, 7, 91, 187, 123, 519, 477, 2719, 211, 1225, 22689, 37043, 66291, 205441}},
-{15476, 18, 34835, {1, 1, 5, 13, 5, 41, 95, 49, 187, 239, 1213, 2363, 8075, 12423, 6361, 42471, 70047, 188063}},
-{15477, 18, 34842, {1, 3, 7, 3, 27, 23, 21, 217, 65, 143, 1171, 1441, 1603, 2235, 20923, 32611, 111903, 132771}},
-{15478, 18, 34865, {1, 1, 7, 9, 3, 29, 33, 203, 497, 179, 1253, 2083, 7407, 12551, 8371, 62167, 93875, 193017}},
-{15479, 18, 34907, {1, 1, 1, 13, 7, 61, 43, 107, 417, 757, 1701, 3187, 5489, 11359, 20469, 20249, 93581, 207969}},
-{15480, 18, 34928, {1, 1, 7, 3, 31, 51, 51, 183, 483, 885, 1627, 3605, 6687, 1271, 27013, 40409, 103807, 189805}},
-{15481, 18, 34949, {1, 1, 3, 1, 21, 21, 107, 185, 267, 981, 147, 1873, 1085, 15829, 10315, 21673, 7713, 120087}},
-{15482, 18, 34961, {1, 1, 5, 3, 7, 27, 73, 131, 287, 657, 1351, 547, 3655, 2433, 6753, 2465, 110299, 194587}},
-{15483, 18, 34964, {1, 1, 7, 7, 17, 55, 29, 223, 411, 775, 745, 3515, 4573, 4289, 7411, 55999, 22021, 110567}},
-{15484, 18, 34987, {1, 3, 1, 3, 29, 55, 7, 183, 507, 773, 1299, 3653, 7693, 3773, 29549, 4171, 123039, 137495}},
-{15485, 18, 34990, {1, 1, 1, 7, 5, 25, 53, 85, 41, 837, 587, 2997, 7281, 6821, 15609, 47855, 49017, 108557}},
-{15486, 18, 35019, {1, 1, 5, 5, 1, 17, 109, 231, 295, 825, 1909, 683, 2197, 1895, 8641, 37917, 36347, 38683}},
-{15487, 18, 35069, {1, 3, 7, 3, 23, 39, 91, 121, 223, 505, 127, 3439, 7779, 12917, 17351, 33063, 84019, 40077}},
-{15488, 18, 35077, {1, 3, 3, 1, 19, 1, 125, 99, 143, 549, 709, 3605, 2377, 761, 14369, 52191, 80811, 214877}},
-{15489, 18, 35090, {1, 1, 7, 9, 13, 57, 39, 91, 505, 299, 1241, 1697, 5821, 5327, 22439, 42321, 120941, 40009}},
-{15490, 18, 35152, {1, 1, 3, 13, 15, 59, 15, 129, 265, 841, 1255, 1915, 4645, 5991, 26801, 7839, 66961, 59045}},
-{15491, 18, 35173, {1, 3, 7, 15, 17, 57, 61, 173, 391, 1001, 1815, 2565, 1445, 13237, 2273, 61683, 62327, 180255}},
-{15492, 18, 35174, {1, 1, 3, 3, 23, 29, 115, 185, 333, 103, 1807, 3271, 4803, 9743, 3031, 25263, 30761, 1899}},
-{15493, 18, 35202, {1, 1, 1, 7, 1, 13, 63, 113, 467, 17, 1803, 3141, 7069, 8895, 25823, 40347, 11211, 88769}},
-{15494, 18, 35214, {1, 3, 5, 1, 3, 3, 29, 101, 315, 915, 341, 287, 4167, 7579, 19797, 18287, 19079, 52805}},
-{15495, 18, 35219, {1, 3, 7, 15, 31, 61, 27, 153, 387, 273, 343, 881, 2273, 6621, 19391, 41735, 123899, 117851}},
-{15496, 18, 35226, {1, 1, 7, 11, 5, 49, 83, 223, 87, 341, 1023, 2785, 3635, 2651, 5179, 25907, 115249, 74001}},
-{15497, 18, 35235, {1, 3, 3, 7, 31, 37, 123, 79, 365, 455, 639, 691, 2659, 12215, 26785, 48785, 120175, 155501}},
-{15498, 18, 35255, {1, 3, 3, 11, 19, 49, 81, 97, 429, 317, 257, 663, 5009, 2855, 22721, 51553, 32511, 188977}},
-{15499, 18, 35310, {1, 1, 7, 11, 5, 37, 1, 123, 477, 747, 839, 3975, 6347, 489, 31387, 56037, 62935, 177587}},
-{15500, 18, 35318, {1, 1, 1, 1, 29, 7, 119, 233, 255, 25, 127, 1377, 991, 12151, 31259, 64863, 34733, 86101}},
-{15501, 18, 35321, {1, 3, 7, 5, 19, 57, 67, 1, 81, 719, 891, 2485, 3817, 1055, 437, 9779, 23823, 173219}},
-{15502, 18, 35333, {1, 1, 1, 5, 1, 63, 87, 163, 135, 809, 637, 1233, 5245, 481, 11011, 23477, 114963, 96051}},
-{15503, 18, 35337, {1, 1, 7, 5, 25, 39, 57, 129, 311, 525, 1555, 179, 639, 4949, 8809, 31215, 95975, 79407}},
-{15504, 18, 35346, {1, 3, 1, 1, 15, 59, 77, 87, 479, 889, 1619, 331, 4781, 10597, 935, 28105, 83861, 134273}},
-{15505, 18, 35373, {1, 3, 5, 15, 21, 55, 61, 105, 373, 185, 1579, 3487, 2621, 8993, 6443, 31709, 57329, 128165}},
-{15506, 18, 35414, {1, 3, 3, 3, 7, 21, 117, 159, 177, 927, 1873, 1865, 3219, 1693, 1173, 34365, 107053, 113949}},
-{15507, 18, 35478, {1, 3, 7, 1, 17, 37, 35, 101, 305, 141, 1681, 1949, 47, 11351, 989, 13887, 127429, 13059}},
-{15508, 18, 35497, {1, 1, 3, 7, 13, 41, 125, 115, 65, 621, 1401, 631, 5875, 8589, 17185, 22757, 83625, 92907}},
-{15509, 18, 35503, {1, 3, 1, 5, 25, 37, 73, 39, 495, 645, 265, 2685, 5875, 5919, 23223, 44593, 26207, 49921}},
-{15510, 18, 35512, {1, 3, 1, 13, 25, 31, 39, 15, 179, 791, 1817, 3617, 2139, 1827, 21215, 21767, 15009, 239443}},
-{15511, 18, 35515, {1, 1, 3, 7, 17, 9, 33, 121, 235, 535, 1537, 3307, 2881, 4351, 4721, 34131, 129619, 137993}},
-{15512, 18, 35526, {1, 1, 3, 1, 3, 51, 79, 213, 205, 323, 1749, 2563, 2013, 6519, 18923, 25937, 74445, 252283}},
-{15513, 18, 35577, {1, 3, 5, 11, 3, 53, 17, 195, 305, 543, 1937, 2997, 4593, 7801, 15307, 46359, 39365, 59537}},
-{15514, 18, 35585, {1, 1, 1, 13, 31, 53, 111, 163, 139, 163, 999, 83, 5125, 10047, 11143, 51407, 13627, 3621}},
-{15515, 18, 35592, {1, 1, 3, 9, 5, 1, 125, 95, 281, 939, 913, 1441, 1209, 12983, 27759, 22393, 75985, 178997}},
-{15516, 18, 35615, {1, 3, 5, 3, 5, 27, 91, 41, 51, 447, 491, 3405, 497, 2873, 17865, 30651, 104197, 71751}},
-{15517, 18, 35616, {1, 3, 7, 1, 29, 61, 73, 31, 423, 933, 1327, 809, 1461, 269, 15121, 18649, 36095, 139429}},
-{15518, 18, 35622, {1, 1, 7, 7, 19, 49, 51, 173, 297, 411, 1255, 1093, 2821, 6743, 1927, 27563, 68459, 261411}},
-{15519, 18, 35634, {1, 3, 5, 1, 5, 33, 27, 119, 103, 615, 149, 2299, 6801, 15615, 7361, 31045, 87719, 9557}},
-{15520, 18, 35657, {1, 1, 3, 9, 17, 23, 89, 35, 151, 385, 319, 2065, 1897, 1987, 15159, 34855, 5395, 110751}},
-{15521, 18, 35672, {1, 3, 1, 13, 7, 47, 19, 185, 207, 787, 1179, 1073, 1463, 6277, 6129, 25031, 91969, 123235}},
-{15522, 18, 35708, {1, 1, 7, 3, 19, 63, 97, 1, 381, 71, 1169, 339, 6585, 3629, 31357, 59451, 102735, 253667}},
-{15523, 18, 35772, {1, 3, 3, 13, 9, 27, 69, 17, 509, 599, 1247, 2267, 3309, 1905, 17995, 41263, 5947, 51607}},
-{15524, 18, 35790, {1, 3, 1, 9, 31, 45, 69, 243, 171, 555, 61, 1135, 1993, 8615, 18363, 19545, 64015, 81391}},
-{15525, 18, 35804, {1, 1, 1, 1, 19, 49, 31, 65, 53, 123, 271, 3007, 4509, 9465, 3855, 12673, 19457, 14677}},
-{15526, 18, 35811, {1, 3, 5, 13, 29, 53, 91, 145, 115, 53, 839, 1911, 2887, 6053, 18437, 42273, 63093, 70937}},
-{15527, 18, 35814, {1, 1, 5, 5, 27, 13, 87, 175, 485, 699, 463, 811, 4991, 15303, 23007, 10021, 59125, 39997}},
-{15528, 18, 35837, {1, 1, 5, 5, 27, 21, 89, 61, 109, 555, 953, 2811, 3015, 3249, 16085, 64413, 84605, 177333}},
-{15529, 18, 35846, {1, 1, 7, 3, 1, 29, 83, 143, 67, 577, 971, 2339, 6521, 6341, 27141, 37149, 99813, 37579}},
-{15530, 18, 35873, {1, 3, 3, 7, 23, 29, 117, 5, 287, 559, 667, 2349, 7481, 679, 9633, 40857, 89841, 98125}},
-{15531, 18, 35883, {1, 1, 1, 3, 31, 31, 83, 117, 213, 213, 23, 3803, 5967, 7759, 19521, 13229, 62231, 150687}},
-{15532, 18, 35918, {1, 3, 7, 9, 1, 15, 37, 191, 19, 107, 1723, 3517, 3477, 3777, 4359, 45815, 58661, 33217}},
-{15533, 18, 35920, {1, 1, 5, 1, 17, 3, 3, 255, 501, 1021, 1731, 481, 6145, 3475, 3417, 11847, 92203, 75109}},
-{15534, 18, 35925, {1, 1, 5, 1, 1, 61, 89, 107, 503, 627, 931, 1355, 2067, 12487, 20665, 61543, 15501, 103843}},
-{15535, 18, 35926, {1, 1, 5, 9, 25, 17, 7, 255, 251, 939, 851, 2241, 939, 15331, 29357, 2485, 80791, 152601}},
-{15536, 18, 35945, {1, 1, 5, 3, 13, 25, 35, 113, 83, 765, 1317, 1409, 369, 2215, 5659, 3581, 13925, 108673}},
-{15537, 18, 35956, {1, 1, 1, 1, 13, 13, 83, 27, 5, 563, 723, 2733, 3155, 6567, 24595, 45569, 37587, 144401}},
-{15538, 18, 36003, {1, 1, 1, 9, 31, 51, 73, 105, 299, 857, 669, 963, 4115, 14939, 11669, 46215, 92707, 149249}},
-{15539, 18, 36023, {1, 1, 3, 5, 7, 41, 105, 213, 3, 999, 93, 1497, 6783, 1559, 20047, 40761, 88219, 64769}},
-{15540, 18, 36024, {1, 3, 1, 5, 13, 17, 79, 29, 453, 75, 1095, 623, 7401, 4225, 30467, 60795, 130045, 154767}},
-{15541, 18, 36059, {1, 1, 5, 3, 31, 59, 33, 129, 505, 277, 1623, 3531, 6841, 12903, 7231, 5801, 92405, 260195}},
-{15542, 18, 36061, {1, 1, 3, 5, 27, 23, 63, 219, 225, 547, 1163, 1899, 4191, 9725, 30077, 30157, 73395, 38195}},
-{15543, 18, 36072, {1, 1, 1, 11, 17, 27, 63, 127, 95, 205, 1753, 2023, 6803, 4355, 28169, 16691, 25105, 8969}},
-{15544, 18, 36075, {1, 1, 5, 3, 23, 23, 89, 115, 231, 647, 513, 3161, 3175, 5061, 5797, 35387, 109827, 19511}},
-{15545, 18, 36103, {1, 3, 5, 5, 11, 9, 39, 251, 367, 253, 2031, 3909, 1057, 12545, 25397, 51571, 91229, 83721}},
-{15546, 18, 36110, {1, 3, 5, 7, 5, 35, 57, 153, 111, 789, 177, 2237, 1333, 13185, 993, 22099, 62113, 211815}},
-{15547, 18, 36131, {1, 1, 5, 15, 19, 37, 123, 221, 375, 605, 791, 1663, 7537, 7193, 20149, 58077, 113129, 185493}},
-{15548, 18, 36151, {1, 1, 1, 1, 1, 53, 117, 227, 441, 851, 1171, 4031, 2313, 2847, 25533, 31767, 18197, 153101}},
-{15549, 18, 36160, {1, 1, 3, 3, 13, 9, 65, 225, 71, 763, 1507, 3795, 4321, 399, 12515, 4527, 89193, 236161}},
-{15550, 18, 36199, {1, 1, 3, 11, 21, 63, 73, 125, 369, 309, 953, 3525, 3925, 13609, 26061, 21739, 112867, 112985}},
-{15551, 18, 36223, {1, 1, 7, 1, 27, 25, 3, 129, 321, 193, 1871, 233, 837, 11163, 14861, 42721, 72849, 206739}},
-{15552, 18, 36227, {1, 3, 7, 3, 5, 51, 43, 177, 167, 11, 1297, 1805, 515, 6485, 8253, 271, 47435, 252291}},
-{15553, 18, 36234, {1, 3, 3, 3, 19, 47, 47, 47, 299, 101, 1535, 3593, 4669, 10367, 19219, 16579, 85269, 36115}},
-{15554, 18, 36236, {1, 1, 7, 15, 7, 51, 53, 181, 379, 267, 985, 3401, 2189, 10197, 14183, 413, 76797, 24751}},
-{15555, 18, 36284, {1, 1, 5, 7, 13, 27, 65, 119, 235, 131, 1921, 3411, 1511, 11221, 30315, 11799, 127563, 203533}},
-{15556, 18, 36319, {1, 3, 1, 3, 13, 55, 101, 189, 483, 261, 467, 645, 417, 6203, 9221, 19671, 102331, 259335}},
-{15557, 18, 36332, {1, 1, 5, 15, 19, 7, 81, 1, 371, 119, 1433, 1211, 303, 14393, 27107, 45295, 109211, 224661}},
-{15558, 18, 36343, {1, 3, 7, 9, 19, 53, 31, 55, 103, 351, 1511, 377, 981, 6709, 19553, 53579, 55043, 170489}},
-{15559, 18, 36373, {1, 3, 3, 15, 31, 49, 1, 251, 187, 73, 119, 3041, 5455, 5355, 22245, 7735, 14661, 258447}},
-{15560, 18, 36401, {1, 3, 7, 11, 13, 1, 61, 97, 179, 975, 1653, 3301, 4303, 2271, 30171, 63287, 51271, 21909}},
-{15561, 18, 36413, {1, 1, 5, 11, 21, 45, 101, 131, 121, 881, 1205, 1849, 4337, 5687, 31967, 22559, 98017, 202557}},
-{15562, 18, 36433, {1, 3, 3, 7, 1, 49, 11, 35, 141, 309, 651, 3319, 4313, 3675, 27699, 49429, 109805, 167089}},
-{15563, 18, 36459, {1, 1, 3, 13, 13, 15, 61, 251, 335, 365, 677, 2183, 6291, 8857, 15231, 551, 63149, 76729}},
-{15564, 18, 36480, {1, 3, 3, 13, 1, 59, 85, 127, 409, 1007, 1947, 3495, 6227, 11447, 14329, 3769, 109619, 59063}},
-{15565, 18, 36485, {1, 3, 5, 11, 11, 59, 67, 209, 491, 757, 1137, 1977, 3155, 9339, 11219, 20303, 66417, 187911}},
-{15566, 18, 36510, {1, 1, 5, 9, 27, 51, 87, 249, 327, 867, 29, 3811, 4769, 12353, 24803, 35747, 84101, 210975}},
-{15567, 18, 36513, {1, 3, 7, 7, 23, 37, 23, 55, 237, 543, 779, 1305, 1535, 13333, 1403, 10903, 113135, 195799}},
-{15568, 18, 36523, {1, 1, 3, 11, 1, 1, 3, 153, 401, 35, 981, 79, 4227, 9203, 8179, 29325, 104809, 140613}},
-{15569, 18, 36528, {1, 3, 5, 9, 13, 39, 101, 181, 507, 307, 1411, 1443, 6855, 8747, 22709, 37869, 102303, 577}},
-{15570, 18, 36537, {1, 3, 5, 1, 25, 41, 3, 239, 195, 1, 1277, 2085, 4253, 14683, 24171, 56733, 82795, 213291}},
-{15571, 18, 36558, {1, 1, 3, 5, 25, 55, 31, 55, 215, 149, 1813, 3775, 779, 6137, 10561, 41671, 96883, 177435}},
-{15572, 18, 36563, {1, 1, 5, 11, 15, 5, 1, 237, 131, 13, 229, 3203, 2431, 1829, 31983, 59535, 31381, 175455}},
-{15573, 18, 36576, {1, 3, 3, 7, 5, 19, 61, 253, 223, 609, 1395, 2495, 5501, 6571, 12989, 889, 49435, 200251}},
-{15574, 18, 36608, {1, 1, 7, 13, 25, 49, 33, 157, 457, 259, 1935, 2249, 7419, 12685, 30509, 32187, 108839, 178963}},
-{15575, 18, 36611, {1, 3, 3, 15, 19, 27, 91, 133, 369, 931, 359, 759, 2647, 13643, 14877, 14031, 115367, 201745}},
-{15576, 18, 36617, {1, 1, 5, 3, 9, 23, 87, 27, 203, 995, 1759, 999, 949, 2733, 29053, 46581, 129003, 42585}},
-{15577, 18, 36653, {1, 1, 3, 1, 1, 21, 63, 243, 257, 741, 681, 2471, 2455, 15145, 31739, 8751, 15963, 165405}},
-{15578, 18, 36716, {1, 3, 3, 1, 25, 21, 69, 213, 219, 9, 199, 487, 4103, 141, 18177, 58797, 60415, 6313}},
-{15579, 18, 36721, {1, 3, 1, 5, 23, 43, 61, 121, 123, 89, 283, 1313, 2707, 10199, 7699, 17437, 130995, 140327}},
-{15580, 18, 36733, {1, 3, 5, 13, 31, 41, 111, 39, 403, 5, 1125, 2867, 3143, 7051, 9891, 43349, 20751, 88465}},
-{15581, 18, 36761, {1, 1, 3, 1, 19, 53, 83, 207, 285, 789, 1515, 3455, 4057, 15777, 27879, 46971, 122661, 143407}},
-{15582, 18, 36783, {1, 3, 3, 11, 25, 21, 127, 191, 313, 357, 1625, 1323, 1151, 12509, 22275, 23517, 12221, 258709}},
-{15583, 18, 36786, {1, 1, 5, 7, 1, 47, 1, 107, 387, 965, 1319, 2911, 2121, 8595, 9, 21587, 81187, 2803}},
-{15584, 18, 36795, {1, 3, 3, 5, 19, 55, 37, 213, 23, 767, 1493, 635, 4289, 2503, 16835, 47851, 77335, 60565}},
-{15585, 18, 36800, {1, 1, 1, 7, 23, 9, 101, 145, 457, 691, 1895, 2145, 7527, 7687, 20781, 10957, 24859, 79137}},
-{15586, 18, 36810, {1, 3, 7, 15, 9, 9, 15, 195, 493, 859, 687, 1445, 429, 8599, 24591, 40709, 118361, 148163}},
-{15587, 18, 36812, {1, 1, 1, 3, 7, 51, 45, 143, 339, 475, 1177, 2829, 785, 10141, 4923, 29135, 22603, 119973}},
-{15588, 18, 36817, {1, 3, 5, 15, 25, 37, 1, 13, 351, 127, 143, 2637, 1215, 14577, 12465, 10575, 67997, 21877}},
-{15589, 18, 36818, {1, 3, 7, 3, 27, 19, 59, 241, 327, 307, 731, 3471, 6123, 13607, 8793, 14825, 110681, 83259}},
-{15590, 18, 36851, {1, 1, 1, 11, 25, 5, 59, 85, 335, 189, 499, 1305, 5801, 7259, 2397, 14045, 55585, 258579}},
-{15591, 18, 36853, {1, 1, 3, 5, 21, 49, 49, 63, 261, 657, 1453, 55, 1325, 15513, 14891, 60689, 15381, 252641}},
-{15592, 18, 36868, {1, 1, 7, 15, 25, 3, 85, 33, 495, 867, 903, 1813, 2871, 365, 17399, 45695, 102851, 225873}},
-{15593, 18, 36889, {1, 1, 1, 13, 13, 63, 29, 35, 325, 893, 1313, 133, 8169, 7791, 9271, 36759, 92275, 169717}},
-{15594, 18, 36890, {1, 1, 7, 3, 21, 45, 7, 151, 387, 891, 1921, 1701, 307, 5323, 16321, 51229, 79369, 21513}},
-{15595, 18, 36896, {1, 1, 1, 11, 7, 27, 17, 75, 161, 649, 337, 1731, 2905, 4589, 17387, 10455, 70673, 228373}},
-{15596, 18, 36905, {1, 1, 3, 15, 17, 35, 45, 131, 469, 629, 1771, 1965, 5065, 6249, 29041, 52791, 55619, 154531}},
-{15597, 18, 36919, {1, 1, 7, 3, 25, 53, 85, 233, 161, 163, 1155, 3159, 1551, 13099, 25647, 26777, 91647, 162755}},
-{15598, 18, 36938, {1, 1, 3, 9, 17, 11, 39, 63, 503, 927, 1621, 3425, 4835, 7083, 16449, 47913, 127905, 165567}},
-{15599, 18, 36946, {1, 1, 7, 1, 29, 9, 1, 111, 285, 1009, 1427, 3071, 205, 12269, 31337, 14501, 10923, 14277}},
-{15600, 18, 36951, {1, 1, 5, 5, 1, 3, 51, 205, 477, 661, 1555, 2113, 6487, 4755, 13633, 16391, 35775, 52623}},
-{15601, 18, 36952, {1, 3, 3, 3, 27, 23, 109, 49, 71, 19, 733, 1361, 4369, 14527, 20443, 10507, 120183, 246115}},
-{15602, 18, 36964, {1, 3, 3, 5, 7, 47, 51, 197, 97, 471, 1631, 3317, 5857, 9405, 30359, 7741, 45079, 175929}},
-{15603, 18, 36968, {1, 1, 3, 3, 13, 63, 39, 173, 511, 525, 1687, 1735, 6877, 7383, 27971, 26503, 6189, 232251}},
-{15604, 18, 36979, {1, 1, 5, 3, 5, 31, 101, 99, 51, 987, 1627, 3899, 6321, 9441, 4983, 64001, 30923, 199495}},
-{15605, 18, 36981, {1, 3, 1, 1, 11, 39, 119, 123, 33, 1017, 1477, 283, 4939, 453, 16445, 25599, 106857, 257811}},
-{15606, 18, 37021, {1, 3, 1, 11, 13, 1, 3, 101, 275, 75, 1795, 1449, 2503, 11765, 19299, 14237, 157, 244825}},
-{15607, 18, 37026, {1, 3, 7, 15, 23, 1, 85, 65, 55, 103, 1523, 1443, 1021, 5733, 3297, 10889, 22487, 82503}},
-{15608, 18, 37075, {1, 1, 7, 3, 17, 59, 109, 113, 17, 173, 1709, 273, 5327, 3243, 10751, 58361, 42303, 78391}},
-{15609, 18, 37077, {1, 1, 5, 15, 25, 11, 101, 133, 193, 131, 1671, 3045, 7111, 14331, 15665, 56407, 31561, 154555}},
-{15610, 18, 37108, {1, 3, 3, 5, 15, 41, 105, 65, 81, 293, 389, 2653, 1883, 14741, 23553, 33349, 39665, 154233}},
-{15611, 18, 37112, {1, 1, 5, 15, 31, 19, 121, 41, 261, 511, 1679, 957, 1647, 12647, 12285, 30291, 122483, 187911}},
-{15612, 18, 37150, {1, 3, 1, 5, 27, 25, 17, 45, 303, 947, 1123, 2729, 281, 12389, 27987, 42667, 16089, 17129}},
-{15613, 18, 37154, {1, 3, 7, 15, 13, 17, 25, 223, 125, 837, 159, 253, 2599, 11381, 639, 32545, 50633, 139025}},
-{15614, 18, 37156, {1, 3, 1, 13, 23, 43, 25, 83, 507, 47, 99, 697, 4453, 2139, 17151, 50709, 37099, 212957}},
-{15615, 18, 37163, {1, 1, 7, 7, 29, 7, 63, 141, 475, 853, 1073, 143, 6979, 5663, 29691, 59489, 89689, 223047}},
-{15616, 18, 37178, {1, 1, 1, 1, 13, 27, 101, 61, 27, 735, 207, 2065, 5811, 5461, 21493, 15481, 103727, 80017}},
-{15617, 18, 37183, {1, 3, 1, 11, 9, 9, 35, 251, 147, 841, 1891, 1909, 5053, 5103, 11751, 16209, 110475, 114875}},
-{15618, 18, 37185, {1, 3, 3, 11, 13, 55, 117, 205, 71, 159, 1797, 989, 2221, 16087, 18287, 8355, 96403, 146613}},
-{15619, 18, 37191, {1, 1, 5, 5, 29, 25, 73, 63, 299, 839, 1225, 3583, 5641, 1341, 29431, 7035, 99107, 13493}},
-{15620, 18, 37198, {1, 1, 3, 5, 27, 53, 9, 51, 79, 701, 667, 1469, 4455, 13761, 18607, 39429, 7687, 201115}},
-{15621, 18, 37203, {1, 3, 7, 11, 23, 35, 101, 129, 491, 369, 565, 2557, 2529, 1003, 16003, 33873, 52155, 861}},
-{15622, 18, 37225, {1, 1, 1, 15, 27, 63, 1, 55, 331, 853, 899, 1027, 7389, 8935, 12559, 27315, 101753, 255331}},
-{15623, 18, 37243, {1, 3, 3, 15, 5, 41, 93, 39, 473, 887, 1667, 847, 7619, 8407, 6539, 31989, 63807, 21861}},
-{15624, 18, 37252, {1, 1, 5, 11, 27, 57, 73, 249, 331, 653, 21, 2937, 4403, 16195, 18785, 30375, 22939, 235291}},
-{15625, 18, 37262, {1, 1, 7, 1, 7, 41, 59, 161, 295, 503, 595, 3021, 455, 3991, 8617, 65361, 107239, 83205}},
-{15626, 18, 37264, {1, 3, 3, 15, 17, 41, 61, 229, 273, 687, 657, 1969, 2817, 2367, 29183, 41199, 24123, 184081}},
-{15627, 18, 37276, {1, 3, 7, 5, 25, 63, 43, 65, 443, 423, 549, 2031, 3353, 7041, 6563, 18819, 46047, 239823}},
-{15628, 18, 37327, {1, 3, 3, 3, 3, 17, 13, 115, 377, 623, 1959, 127, 5125, 13209, 24731, 23151, 21303, 7213}},
-{15629, 18, 37355, {1, 1, 7, 1, 21, 11, 21, 41, 491, 37, 1759, 2771, 1301, 12995, 17621, 30907, 75511, 82321}},
-{15630, 18, 37403, {1, 3, 3, 13, 13, 23, 77, 211, 215, 711, 427, 2213, 8041, 1595, 26105, 39051, 105407, 242141}},
-{15631, 18, 37415, {1, 3, 3, 9, 13, 35, 117, 207, 75, 395, 723, 3321, 6643, 2429, 10043, 10585, 3529, 64067}},
-{15632, 18, 37422, {1, 1, 1, 7, 3, 1, 83, 93, 311, 157, 891, 1717, 7669, 16067, 11775, 27693, 11757, 94471}},
-{15633, 18, 37448, {1, 3, 3, 5, 17, 63, 23, 177, 289, 921, 315, 3083, 5903, 8697, 22425, 37845, 31171, 49237}},
-{15634, 18, 37451, {1, 1, 7, 9, 21, 63, 29, 227, 427, 271, 525, 2071, 7103, 8389, 29185, 51601, 110737, 16949}},
-{15635, 18, 37478, {1, 3, 3, 3, 3, 49, 25, 173, 79, 343, 509, 1939, 6389, 15501, 20135, 54365, 69931, 135269}},
-{15636, 18, 37484, {1, 1, 3, 3, 21, 23, 41, 71, 169, 947, 1027, 2345, 3397, 12181, 15409, 31725, 41223, 58837}},
-{15637, 18, 37525, {1, 3, 7, 1, 19, 23, 57, 201, 27, 449, 1479, 921, 4703, 10949, 14369, 27929, 45399, 46055}},
-{15638, 18, 37553, {1, 1, 3, 9, 13, 17, 125, 17, 393, 295, 497, 3089, 6589, 4003, 8687, 48145, 2683, 175521}},
-{15639, 18, 37640, {1, 3, 3, 15, 15, 13, 3, 31, 51, 101, 973, 101, 3709, 13437, 51, 14293, 21561, 136497}},
-{15640, 18, 37645, {1, 1, 5, 11, 17, 27, 51, 45, 77, 539, 225, 2029, 533, 153, 26085, 33611, 28153, 75671}},
-{15641, 18, 37658, {1, 1, 1, 15, 3, 59, 59, 123, 475, 225, 1613, 3121, 2865, 4647, 14553, 35449, 121657, 37457}},
-{15642, 18, 37667, {1, 1, 5, 1, 27, 33, 121, 225, 57, 619, 1293, 3813, 2121, 3525, 21995, 47253, 33095, 257451}},
-{15643, 18, 37708, {1, 3, 1, 11, 11, 43, 115, 233, 335, 185, 989, 3567, 4135, 2357, 20559, 43325, 43015, 51695}},
-{15644, 18, 37723, {1, 1, 5, 9, 11, 49, 45, 187, 93, 967, 1609, 2511, 1549, 4045, 21309, 16341, 13495, 214827}},
-{15645, 18, 37732, {1, 1, 1, 13, 21, 23, 81, 7, 259, 483, 1059, 773, 5297, 10123, 9857, 61187, 47355, 76307}},
-{15646, 18, 37747, {1, 3, 7, 9, 29, 51, 113, 255, 223, 853, 1173, 1019, 1587, 9629, 22373, 32731, 125179, 193271}},
-{15647, 18, 37753, {1, 1, 5, 11, 3, 55, 25, 145, 347, 451, 1447, 3399, 5873, 11579, 11107, 64707, 10161, 142003}},
-{15648, 18, 37772, {1, 1, 1, 7, 15, 49, 109, 93, 267, 919, 177, 2247, 8129, 8039, 15629, 63767, 98153, 143255}},
-{15649, 18, 37789, {1, 1, 5, 3, 3, 27, 47, 151, 231, 35, 155, 2745, 7349, 6543, 14117, 19549, 54927, 10819}},
-{15650, 18, 37817, {1, 3, 7, 15, 31, 29, 17, 203, 249, 169, 1071, 3069, 6269, 3455, 27177, 33761, 111003, 4527}},
-{15651, 18, 37826, {1, 3, 1, 5, 31, 15, 65, 189, 3, 917, 857, 1221, 3553, 2883, 3631, 32971, 68057, 109081}},
-{15652, 18, 37831, {1, 3, 1, 9, 3, 55, 127, 57, 125, 463, 199, 317, 3373, 967, 5569, 55997, 17167, 33585}},
-{15653, 18, 37845, {1, 3, 5, 1, 9, 57, 15, 89, 335, 119, 1445, 1931, 4177, 2495, 27507, 8209, 60003, 29657}},
-{15654, 18, 37855, {1, 3, 5, 7, 15, 43, 83, 117, 283, 131, 653, 57, 6789, 7633, 30525, 64131, 101981, 122017}},
-{15655, 18, 37859, {1, 3, 7, 11, 3, 17, 115, 217, 391, 825, 1633, 885, 7787, 5595, 12235, 30233, 53587, 62985}},
-{15656, 18, 37866, {1, 1, 5, 3, 5, 13, 99, 1, 75, 329, 1247, 107, 2337, 4201, 6217, 12273, 41585, 46563}},
-{15657, 18, 37880, {1, 3, 1, 15, 25, 53, 33, 125, 311, 955, 161, 3631, 581, 11915, 4223, 63207, 16517, 201665}},
-{15658, 18, 37885, {1, 1, 5, 1, 27, 23, 93, 211, 483, 691, 949, 1825, 391, 12111, 13639, 61009, 88503, 104823}},
-{15659, 18, 37897, {1, 3, 1, 13, 3, 9, 51, 133, 259, 977, 697, 661, 7661, 3987, 8327, 50155, 112235, 236135}},
-{15660, 18, 37906, {1, 1, 3, 13, 7, 39, 121, 37, 151, 973, 1275, 2699, 3345, 7167, 19245, 55535, 12305, 33567}},
-{15661, 18, 37948, {1, 1, 1, 1, 27, 5, 91, 63, 409, 579, 459, 2335, 4721, 3305, 11293, 15405, 74513, 157863}},
-{15662, 18, 37954, {1, 1, 5, 1, 21, 45, 55, 111, 475, 381, 659, 1131, 3575, 5165, 27221, 46757, 53587, 90741}},
-{15663, 18, 37978, {1, 1, 5, 15, 11, 31, 121, 209, 69, 389, 779, 2833, 4519, 1801, 4363, 24723, 105849, 54475}},
-{15664, 18, 37980, {1, 1, 3, 9, 7, 19, 11, 75, 275, 77, 1997, 1661, 6139, 13165, 30653, 49469, 67053, 3811}},
-{15665, 18, 37990, {1, 1, 3, 9, 5, 11, 5, 151, 395, 715, 1381, 3011, 5939, 1805, 8063, 62877, 99749, 112951}},
-{15666, 18, 38001, {1, 1, 5, 13, 19, 15, 113, 47, 455, 173, 1897, 701, 6093, 2089, 3977, 20599, 60947, 23671}},
-{15667, 18, 38020, {1, 1, 1, 13, 23, 19, 13, 117, 275, 313, 1683, 2975, 179, 3949, 4361, 60211, 91999, 211219}},
-{15668, 18, 38029, {1, 3, 5, 15, 13, 53, 83, 161, 491, 1001, 1773, 1227, 1965, 14479, 17677, 24399, 86431, 203303}},
-{15669, 18, 38047, {1, 1, 7, 15, 5, 51, 103, 131, 351, 747, 1227, 2859, 6693, 10615, 29485, 6619, 106239, 148739}},
-{15670, 18, 38063, {1, 3, 5, 1, 9, 43, 91, 173, 223, 393, 1181, 3785, 6589, 1299, 10217, 20891, 64125, 63409}},
-{15671, 18, 38077, {1, 1, 5, 7, 11, 23, 45, 57, 397, 771, 511, 1849, 343, 14139, 26271, 56241, 52581, 163187}},
-{15672, 18, 38110, {1, 3, 7, 5, 15, 59, 89, 151, 255, 247, 291, 219, 995, 10821, 1445, 35581, 88767, 16871}},
-{15673, 18, 38116, {1, 1, 7, 11, 7, 25, 3, 175, 253, 193, 1641, 1669, 7095, 11871, 10801, 42567, 120663, 109347}},
-{15674, 18, 38119, {1, 3, 5, 7, 31, 41, 119, 39, 149, 653, 153, 2783, 1377, 5223, 17915, 3127, 41869, 193477}},
-{15675, 18, 38176, {1, 3, 3, 13, 23, 19, 47, 85, 487, 103, 237, 2363, 4451, 5077, 23749, 17011, 73561, 169165}},
-{15676, 18, 38186, {1, 1, 3, 9, 21, 25, 77, 235, 53, 681, 1463, 2093, 1525, 12797, 5469, 54277, 15587, 68395}},
-{15677, 18, 38194, {1, 1, 1, 15, 23, 63, 63, 225, 239, 143, 1073, 199, 3231, 1371, 11215, 5999, 100705, 174681}},
-{15678, 18, 38218, {1, 1, 1, 3, 17, 25, 69, 179, 445, 695, 281, 379, 8115, 9443, 13221, 50669, 37369, 62151}},
-{15679, 18, 38241, {1, 3, 3, 9, 11, 29, 21, 89, 441, 353, 401, 1139, 5003, 8087, 24457, 50237, 110993, 117233}},
-{15680, 18, 38247, {1, 3, 3, 1, 13, 45, 31, 249, 295, 149, 591, 2071, 3611, 931, 16261, 8239, 82767, 195665}},
-{15681, 18, 38261, {1, 3, 3, 9, 19, 47, 69, 177, 493, 231, 431, 1359, 6867, 7641, 15661, 25285, 65477, 212643}},
-{15682, 18, 38268, {1, 3, 3, 13, 19, 63, 83, 153, 367, 407, 547, 661, 7743, 5473, 2993, 62937, 33811, 101313}},
-{15683, 18, 38277, {1, 3, 5, 3, 29, 17, 19, 203, 79, 279, 1333, 1851, 51, 9793, 12955, 17383, 73437, 121743}},
-{15684, 18, 38287, {1, 1, 1, 11, 11, 43, 31, 187, 463, 827, 1511, 225, 845, 8963, 1553, 61269, 122033, 245633}},
-{15685, 18, 38295, {1, 1, 3, 3, 31, 23, 9, 241, 377, 317, 655, 2197, 2461, 13239, 15649, 7879, 55085, 129855}},
-{15686, 18, 38299, {1, 3, 5, 7, 9, 37, 1, 191, 185, 145, 1567, 3423, 1127, 1991, 10741, 38407, 22915, 222845}},
-{15687, 18, 38301, {1, 1, 5, 3, 27, 31, 11, 227, 307, 973, 745, 1079, 7479, 10065, 31389, 19195, 114775, 246615}},
-{15688, 18, 38305, {1, 3, 1, 11, 29, 27, 11, 83, 205, 399, 1489, 739, 715, 7955, 16473, 21127, 62379, 260399}},
-{15689, 18, 38312, {1, 3, 3, 3, 25, 25, 123, 163, 399, 841, 963, 2089, 4949, 13085, 19831, 15345, 60377, 164235}},
-{15690, 18, 38315, {1, 1, 1, 9, 3, 21, 101, 105, 397, 23, 1505, 3201, 547, 295, 23247, 18823, 115243, 151073}},
-{15691, 18, 38317, {1, 3, 7, 1, 31, 27, 111, 23, 205, 709, 1625, 3921, 6225, 11039, 29549, 51239, 119003, 133663}},
-{15692, 18, 38343, {1, 3, 3, 11, 21, 49, 111, 195, 25, 833, 1991, 563, 7031, 15429, 5707, 12351, 32221, 16599}},
-{15693, 18, 38344, {1, 1, 5, 7, 5, 7, 39, 171, 39, 921, 385, 2343, 625, 15355, 4923, 36597, 56901, 148377}},
-{15694, 18, 38350, {1, 1, 3, 15, 7, 43, 89, 217, 67, 271, 853, 147, 6767, 3183, 341, 40769, 116767, 22351}},
-{15695, 18, 38358, {1, 3, 5, 7, 7, 3, 105, 27, 183, 59, 953, 4027, 1277, 10323, 29437, 56085, 32677, 198067}},
-{15696, 18, 38364, {1, 1, 1, 15, 23, 29, 51, 209, 13, 177, 1103, 1723, 2877, 9199, 25601, 15537, 8599, 230819}},
-{15697, 18, 38371, {1, 1, 7, 1, 29, 39, 41, 217, 467, 423, 431, 2707, 2017, 11865, 11989, 12045, 71349, 6311}},
-{15698, 18, 38373, {1, 1, 1, 13, 15, 25, 3, 55, 403, 833, 1843, 1159, 1703, 2221, 15379, 65027, 18327, 108881}},
-{15699, 18, 38377, {1, 3, 7, 13, 3, 27, 13, 227, 215, 873, 1073, 1117, 7941, 13607, 7571, 6957, 44991, 239761}},
-{15700, 18, 38392, {1, 3, 7, 11, 23, 1, 95, 235, 283, 977, 1443, 161, 5937, 4351, 30835, 35569, 57509, 1835}},
-{15701, 18, 38407, {1, 3, 3, 13, 11, 1, 85, 75, 261, 543, 9, 899, 5821, 5465, 9771, 53707, 101003, 219215}},
-{15702, 18, 38408, {1, 3, 1, 7, 21, 49, 35, 19, 35, 759, 1467, 1423, 6355, 8415, 563, 24157, 121029, 87309}},
-{15703, 18, 38421, {1, 1, 7, 1, 9, 13, 65, 85, 209, 583, 387, 1743, 2665, 12021, 7525, 27665, 45885, 135039}},
-{15704, 18, 38438, {1, 1, 7, 11, 29, 41, 91, 17, 291, 211, 1801, 493, 899, 14491, 1741, 28971, 35205, 131417}},
-{15705, 18, 38442, {1, 1, 5, 13, 23, 55, 119, 165, 61, 653, 1375, 3575, 5081, 7767, 19963, 61583, 107149, 240639}},
-{15706, 18, 38464, {1, 3, 5, 15, 25, 3, 51, 27, 127, 259, 55, 2221, 3951, 6243, 15825, 42881, 37009, 254401}},
-{15707, 18, 38473, {1, 3, 5, 11, 25, 63, 13, 105, 111, 677, 1545, 2399, 4419, 10853, 7213, 17183, 103411, 67459}},
-{15708, 18, 38484, {1, 1, 1, 11, 11, 31, 73, 125, 155, 545, 1857, 2749, 6389, 4083, 16239, 23651, 68881, 43455}},
-{15709, 18, 38491, {1, 3, 7, 7, 21, 3, 117, 237, 431, 17, 687, 2613, 7483, 3253, 30511, 53833, 33077, 157055}},
-{15710, 18, 38510, {1, 1, 1, 1, 1, 57, 65, 97, 415, 477, 1003, 1415, 1493, 12993, 30965, 24809, 1467, 213021}},
-{15711, 18, 38518, {1, 1, 3, 7, 25, 33, 45, 25, 511, 733, 1077, 2483, 5899, 14295, 11631, 50609, 128989, 45177}},
-{15712, 18, 38531, {1, 1, 3, 3, 25, 17, 115, 31, 115, 191, 293, 3991, 3039, 6751, 16217, 16517, 21121, 193641}},
-{15713, 18, 38537, {1, 3, 3, 13, 25, 23, 7, 51, 363, 641, 333, 2533, 605, 1105, 12941, 4195, 129571, 13253}},
-{15714, 18, 38538, {1, 3, 1, 11, 17, 21, 7, 205, 293, 159, 9, 441, 3287, 10247, 2115, 54099, 128109, 8137}},
-{15715, 18, 38567, {1, 1, 7, 5, 21, 17, 43, 87, 117, 737, 149, 3175, 343, 8509, 12147, 22041, 80037, 23277}},
-{15716, 18, 38594, {1, 3, 3, 1, 3, 7, 101, 245, 11, 1003, 175, 2323, 7807, 15611, 5161, 10277, 37009, 83231}},
-{15717, 18, 38647, {1, 3, 1, 5, 13, 17, 113, 75, 315, 237, 77, 587, 5409, 2053, 22551, 15205, 82545, 18531}},
-{15718, 18, 38651, {1, 3, 5, 11, 9, 57, 61, 117, 281, 111, 369, 2411, 1691, 3391, 5379, 8237, 87329, 4253}},
-{15719, 18, 38654, {1, 3, 3, 3, 19, 25, 101, 1, 495, 25, 1317, 2333, 6183, 12215, 27879, 56403, 37169, 71635}},
-{15720, 18, 38686, {1, 1, 3, 5, 17, 63, 49, 127, 171, 405, 1763, 3697, 405, 2233, 4137, 28787, 108319, 53133}},
-{15721, 18, 38702, {1, 1, 5, 7, 23, 43, 87, 189, 97, 239, 1459, 2115, 7517, 7799, 28957, 37105, 71835, 199195}},
-{15722, 18, 38751, {1, 3, 1, 3, 25, 25, 23, 61, 369, 717, 1711, 1103, 7535, 9871, 25, 26849, 55955, 113389}},
-{15723, 18, 38821, {1, 1, 1, 11, 25, 57, 33, 175, 127, 541, 1031, 2847, 2069, 4033, 25593, 10615, 50097, 122955}},
-{15724, 18, 38825, {1, 3, 3, 13, 11, 27, 97, 171, 245, 33, 213, 4069, 753, 3535, 11727, 34941, 100543, 220789}},
-{15725, 18, 38853, {1, 3, 3, 9, 3, 17, 13, 237, 477, 507, 1751, 3191, 3385, 13977, 23355, 57355, 64341, 37683}},
-{15726, 18, 38863, {1, 1, 7, 13, 13, 43, 7, 153, 209, 7, 63, 585, 1715, 13313, 25355, 46759, 71893, 29755}},
-{15727, 18, 38882, {1, 3, 3, 3, 11, 23, 11, 147, 135, 1011, 1105, 3931, 3861, 13589, 32183, 30727, 37685, 67123}},
-{15728, 18, 38884, {1, 3, 7, 1, 11, 13, 25, 229, 147, 843, 329, 3337, 7559, 13193, 3011, 31549, 102461, 46195}},
-{15729, 18, 38932, {1, 1, 5, 11, 5, 47, 127, 89, 53, 663, 261, 541, 7743, 13037, 9013, 23079, 81225, 239875}},
-{15730, 18, 38941, {1, 1, 7, 3, 5, 39, 15, 177, 357, 357, 1959, 1721, 6703, 11829, 1195, 42113, 88699, 244347}},
-{15731, 18, 38952, {1, 1, 5, 15, 25, 19, 7, 3, 225, 773, 1535, 99, 6555, 4105, 19137, 56155, 109141, 161015}},
-{15732, 18, 38960, {1, 1, 5, 15, 5, 59, 41, 53, 203, 459, 1063, 3015, 5397, 1559, 20835, 57773, 67687, 206189}},
-{15733, 18, 38980, {1, 3, 1, 11, 17, 25, 61, 221, 37, 809, 1461, 1961, 7697, 1777, 23179, 54761, 7787, 177737}},
-{15734, 18, 38995, {1, 3, 7, 15, 27, 21, 49, 107, 353, 677, 461, 239, 5871, 1059, 3011, 32397, 13149, 103973}},
-{15735, 18, 39004, {1, 1, 5, 3, 11, 53, 61, 239, 479, 913, 479, 3435, 4979, 7931, 16841, 60077, 26667, 212601}},
-{15736, 18, 39013, {1, 1, 3, 5, 3, 19, 43, 143, 353, 507, 871, 2547, 7321, 6163, 9425, 62911, 86153, 239011}},
-{15737, 18, 39017, {1, 1, 1, 3, 15, 7, 115, 43, 69, 299, 1235, 1511, 3111, 7465, 769, 46981, 127707, 195839}},
-{15738, 18, 39026, {1, 1, 1, 5, 23, 27, 19, 21, 273, 291, 953, 3577, 3147, 3863, 18625, 53505, 33699, 123305}},
-{15739, 18, 39056, {1, 3, 5, 9, 3, 11, 89, 27, 447, 119, 493, 2605, 8175, 8837, 27555, 2319, 99101, 79121}},
-{15740, 18, 39121, {1, 1, 7, 11, 1, 11, 77, 129, 97, 261, 1241, 3117, 1627, 5397, 6495, 52339, 52711, 206237}},
-{15741, 18, 39124, {1, 3, 7, 9, 27, 57, 77, 147, 35, 845, 1417, 1615, 6097, 12559, 10765, 19027, 91693, 204339}},
-{15742, 18, 39133, {1, 1, 3, 5, 25, 47, 17, 145, 7, 969, 1981, 733, 4303, 7785, 4241, 39733, 82569, 78061}},
-{15743, 18, 39157, {1, 1, 5, 1, 5, 47, 45, 111, 405, 943, 1911, 1613, 3817, 10483, 17729, 7201, 88033, 261701}},
-{15744, 18, 39181, {1, 3, 3, 13, 9, 3, 87, 39, 277, 769, 57, 2503, 7803, 11041, 20945, 19623, 32617, 110027}},
-{15745, 18, 39187, {1, 1, 3, 3, 27, 57, 1, 103, 427, 935, 1617, 665, 837, 8001, 13543, 44771, 64033, 65239}},
-{15746, 18, 39212, {1, 1, 5, 3, 13, 21, 31, 59, 225, 945, 1825, 1511, 3273, 3171, 30347, 21993, 40203, 143297}},
-{15747, 18, 39223, {1, 3, 5, 7, 11, 3, 3, 217, 167, 885, 975, 3249, 7909, 13621, 18697, 61021, 31497, 198033}},
-{15748, 18, 39250, {1, 3, 5, 9, 11, 5, 87, 33, 117, 471, 267, 529, 5879, 13969, 5731, 52613, 106411, 74341}},
-{15749, 18, 39265, {1, 1, 7, 11, 5, 31, 25, 55, 135, 779, 717, 1953, 7929, 11011, 6133, 14099, 106975, 178337}},
-{15750, 18, 39320, {1, 3, 1, 1, 29, 17, 125, 7, 445, 299, 1897, 3235, 8189, 14339, 14725, 63185, 126751, 88747}},
-{15751, 18, 39330, {1, 1, 5, 3, 1, 11, 65, 161, 243, 605, 1945, 3141, 6443, 9703, 13331, 2239, 6315, 247595}},
-{15752, 18, 39335, {1, 3, 1, 7, 15, 23, 83, 215, 331, 631, 453, 879, 4109, 4897, 16535, 55749, 90799, 147287}},
-{15753, 18, 39353, {1, 3, 5, 13, 25, 1, 109, 205, 49, 471, 1735, 973, 1279, 9917, 18225, 44921, 98519, 211541}},
-{15754, 18, 39371, {1, 1, 5, 11, 29, 41, 113, 187, 75, 479, 1633, 841, 6259, 8919, 27751, 25179, 115369, 166567}},
-{15755, 18, 39385, {1, 3, 5, 11, 17, 31, 107, 41, 435, 647, 811, 2937, 5819, 3483, 3835, 57033, 53543, 61973}},
-{15756, 18, 39421, {1, 3, 3, 11, 15, 45, 33, 103, 505, 67, 463, 1275, 2449, 15261, 22867, 25215, 38793, 189309}},
-{15757, 18, 39432, {1, 1, 1, 5, 19, 45, 35, 173, 365, 39, 1599, 3623, 2231, 12141, 19437, 27053, 15869, 104719}},
-{15758, 18, 39443, {1, 3, 7, 7, 9, 17, 87, 151, 249, 81, 1109, 1951, 7475, 1699, 17847, 64149, 50285, 242793}},
-{15759, 18, 39450, {1, 3, 5, 13, 15, 51, 35, 105, 479, 763, 1945, 2349, 2987, 621, 283, 20411, 65799, 86517}},
-{15760, 18, 39455, {1, 3, 3, 1, 19, 31, 49, 229, 249, 689, 737, 4027, 5405, 15211, 26785, 39143, 93163, 190421}},
-{15761, 18, 39468, {1, 3, 7, 5, 1, 21, 63, 97, 347, 73, 745, 3455, 2347, 3821, 31385, 6545, 91803, 72895}},
-{15762, 18, 39473, {1, 1, 1, 15, 23, 11, 107, 47, 183, 235, 1985, 3277, 933, 8491, 14423, 24293, 6783, 162199}},
-{15763, 18, 39488, {1, 3, 3, 9, 17, 3, 123, 59, 277, 773, 1617, 2979, 1555, 9753, 10947, 24745, 89043, 45185}},
-{15764, 18, 39497, {1, 3, 7, 3, 25, 17, 79, 43, 311, 415, 1045, 1289, 7451, 11413, 11319, 37177, 101327, 147453}},
-{15765, 18, 39521, {1, 3, 7, 7, 17, 45, 49, 33, 313, 613, 1773, 773, 161, 13579, 1207, 5681, 120597, 178639}},
-{15766, 18, 39531, {1, 3, 5, 5, 17, 43, 65, 243, 287, 223, 253, 687, 887, 14887, 1077, 53337, 62381, 43531}},
-{15767, 18, 39542, {1, 3, 5, 1, 21, 3, 39, 149, 497, 939, 1537, 437, 5345, 10321, 25151, 48785, 49879, 90945}},
-{15768, 18, 39585, {1, 1, 7, 11, 1, 61, 113, 63, 285, 615, 343, 2897, 1939, 7911, 16387, 10781, 92769, 27995}},
-{15769, 18, 39605, {1, 1, 3, 3, 19, 29, 85, 227, 355, 857, 883, 1853, 5065, 13795, 5749, 59107, 57947, 35775}},
-{15770, 18, 39658, {1, 3, 5, 9, 23, 37, 119, 161, 23, 511, 81, 973, 4769, 10821, 32607, 61731, 64907, 99055}},
-{15771, 18, 39677, {1, 3, 1, 3, 11, 17, 109, 241, 349, 887, 1651, 3865, 2045, 15893, 4597, 11557, 53313, 48489}},
-{15772, 18, 39703, {1, 1, 5, 9, 31, 43, 49, 193, 171, 477, 363, 735, 1379, 8977, 9759, 56477, 99495, 170433}},
-{15773, 18, 39726, {1, 1, 3, 7, 25, 25, 77, 31, 21, 1001, 1527, 1725, 6479, 8927, 11249, 63969, 86291, 74391}},
-{15774, 18, 39731, {1, 3, 5, 13, 1, 43, 27, 7, 507, 569, 251, 2199, 3895, 7845, 13641, 1655, 112949, 119493}},
-{15775, 18, 39745, {1, 3, 7, 15, 7, 1, 123, 27, 121, 261, 201, 1469, 4229, 2933, 25157, 1919, 127937, 21607}},
-{15776, 18, 39776, {1, 1, 3, 9, 29, 59, 47, 81, 293, 191, 401, 849, 4355, 1643, 23533, 8469, 389, 97891}},
-{15777, 18, 39796, {1, 3, 5, 5, 9, 55, 37, 175, 203, 179, 901, 3473, 1489, 1009, 24623, 54895, 8711, 190271}},
-{15778, 18, 39809, {1, 1, 7, 1, 13, 39, 49, 105, 385, 189, 1079, 2799, 5901, 2511, 23199, 58925, 111727, 131193}},
-{15779, 18, 39833, {1, 1, 1, 7, 31, 63, 37, 181, 493, 745, 1131, 223, 8055, 9507, 26667, 22163, 26495, 200945}},
-{15780, 18, 39850, {1, 3, 7, 1, 25, 15, 127, 71, 445, 935, 1439, 1167, 3751, 799, 27253, 46209, 33413, 38553}},
-{15781, 18, 39869, {1, 3, 3, 11, 29, 35, 125, 77, 129, 851, 731, 3259, 4651, 4137, 20921, 19779, 119261, 141507}},
-{15782, 18, 39882, {1, 3, 1, 9, 11, 13, 31, 211, 87, 377, 547, 113, 1071, 7167, 28377, 52943, 50669, 156915}},
-{15783, 18, 39906, {1, 1, 3, 7, 29, 55, 89, 215, 425, 513, 175, 1145, 6995, 1929, 14253, 20563, 118543, 104403}},
-{15784, 18, 39918, {1, 1, 1, 5, 23, 25, 1, 23, 175, 571, 1597, 3801, 1411, 1783, 13045, 37499, 86831, 139101}},
-{15785, 18, 39929, {1, 3, 3, 13, 15, 19, 35, 139, 483, 17, 1555, 3431, 3417, 13695, 15985, 65243, 96659, 76027}},
-{15786, 18, 39947, {1, 3, 7, 9, 23, 7, 17, 89, 33, 353, 1999, 2561, 331, 15661, 25757, 63389, 112913, 131757}},
-{15787, 18, 39985, {1, 3, 1, 11, 27, 59, 37, 75, 121, 429, 1833, 3243, 2029, 2601, 5013, 29433, 123565, 234803}},
-{15788, 18, 39986, {1, 3, 1, 7, 31, 13, 33, 25, 459, 803, 267, 1573, 5579, 4575, 8125, 7491, 72681, 239409}},
-{15789, 18, 40023, {1, 1, 3, 7, 31, 43, 93, 191, 237, 75, 1809, 3257, 4131, 1983, 29153, 23205, 38393, 197859}},
-{15790, 18, 40024, {1, 3, 5, 5, 17, 47, 17, 153, 499, 529, 1515, 1587, 2951, 12431, 12787, 13245, 54117, 82663}},
-{15791, 18, 40039, {1, 1, 1, 13, 7, 23, 23, 7, 441, 991, 641, 2713, 151, 1863, 6065, 47381, 60493, 136325}},
-{15792, 18, 40053, {1, 3, 3, 11, 11, 15, 31, 137, 285, 439, 835, 3033, 6083, 7883, 3405, 35803, 65059, 150143}},
-{15793, 18, 40079, {1, 1, 7, 3, 19, 47, 61, 163, 313, 813, 1315, 2995, 2805, 14397, 6589, 62123, 46229, 206697}},
-{15794, 18, 40084, {1, 3, 5, 5, 27, 51, 25, 99, 241, 571, 1411, 1191, 7095, 8639, 29195, 53733, 53219, 42851}},
-{15795, 18, 40087, {1, 3, 1, 5, 11, 29, 1, 49, 61, 149, 1931, 29, 7163, 3717, 525, 42375, 71451, 8345}},
-{15796, 18, 40094, {1, 3, 3, 3, 13, 19, 97, 249, 265, 509, 1347, 3081, 6535, 7941, 31565, 59897, 91909, 171789}},
-{15797, 18, 40100, {1, 3, 3, 1, 25, 17, 75, 169, 251, 607, 73, 549, 1397, 10661, 1743, 9615, 41327, 243207}},
-{15798, 18, 40112, {1, 3, 1, 11, 7, 7, 15, 181, 385, 883, 651, 2939, 5457, 15309, 9807, 22221, 72893, 146331}},
-{15799, 18, 40129, {1, 3, 3, 5, 7, 7, 53, 75, 139, 459, 1861, 917, 4101, 10379, 18555, 12633, 70023, 254761}},
-{15800, 18, 40132, {1, 3, 3, 1, 17, 51, 5, 109, 471, 3, 1555, 3731, 6711, 9791, 63, 61931, 75269, 138697}},
-{15801, 18, 40142, {1, 1, 7, 15, 11, 1, 53, 141, 423, 567, 1937, 849, 5657, 7437, 32657, 16253, 115219, 106027}},
-{15802, 18, 40154, {1, 3, 5, 1, 17, 29, 65, 213, 443, 541, 697, 3859, 1463, 16081, 23299, 7645, 19475, 77857}},
-{15803, 18, 40177, {1, 1, 7, 3, 21, 43, 99, 101, 329, 755, 1123, 1277, 1381, 7017, 21763, 28243, 109995, 178377}},
-{15804, 18, 40178, {1, 3, 5, 7, 9, 31, 103, 123, 43, 895, 1925, 3383, 3539, 13669, 873, 57361, 45281, 256517}},
-{15805, 18, 40202, {1, 1, 1, 13, 1, 37, 115, 55, 415, 703, 1217, 939, 1145, 4015, 7233, 44799, 79711, 164725}},
-{15806, 18, 40219, {1, 1, 7, 1, 29, 17, 101, 15, 205, 281, 1059, 301, 753, 11953, 10533, 31881, 67741, 12683}},
-{15807, 18, 40303, {1, 1, 7, 13, 9, 23, 31, 237, 181, 813, 1765, 2237, 4897, 9955, 2139, 13113, 123423, 227629}},
-{15808, 18, 40305, {1, 1, 7, 15, 27, 57, 37, 75, 405, 185, 1671, 2245, 7151, 10531, 13161, 15695, 107547, 47689}},
-{15809, 18, 40311, {1, 1, 5, 15, 17, 53, 75, 251, 277, 1001, 179, 589, 1401, 4937, 11601, 47113, 36677, 39263}},
-{15810, 18, 40336, {1, 3, 5, 15, 23, 47, 53, 81, 115, 547, 1363, 2457, 4407, 10861, 25649, 64013, 44747, 97949}},
-{15811, 18, 40342, {1, 1, 3, 1, 25, 29, 121, 43, 205, 591, 211, 1899, 5835, 739, 19627, 60387, 127369, 11255}},
-{15812, 18, 40358, {1, 1, 3, 15, 31, 11, 93, 227, 501, 731, 1355, 3963, 347, 83, 12595, 56431, 80049, 42103}},
-{15813, 18, 40381, {1, 3, 1, 11, 13, 17, 51, 165, 311, 67, 1873, 1493, 3815, 13209, 11637, 5809, 94219, 118077}},
-{15814, 18, 40417, {1, 1, 7, 15, 19, 17, 13, 73, 365, 413, 1215, 2265, 2173, 8725, 4725, 1373, 76733, 95379}},
-{15815, 18, 40438, {1, 3, 1, 7, 7, 61, 13, 145, 205, 113, 1579, 3851, 7515, 10659, 28665, 5277, 65925, 10141}},
-{15816, 18, 40463, {1, 3, 7, 1, 9, 63, 11, 83, 197, 797, 1065, 1521, 1751, 7423, 7473, 4371, 29533, 225167}},
-{15817, 18, 40471, {1, 3, 7, 7, 3, 63, 71, 177, 53, 279, 1837, 2609, 7819, 7285, 11059, 65247, 102869, 24429}},
-{15818, 18, 40472, {1, 3, 3, 13, 9, 21, 123, 125, 367, 85, 85, 1009, 1009, 7779, 3375, 30999, 5035, 215107}},
-{15819, 18, 40488, {1, 3, 3, 9, 31, 53, 5, 43, 483, 483, 1359, 2605, 377, 4243, 13291, 50211, 118603, 259865}},
-{15820, 18, 40491, {1, 1, 1, 5, 19, 37, 109, 139, 373, 79, 1951, 3379, 5679, 6445, 29127, 56229, 97369, 232561}},
-{15821, 18, 40525, {1, 1, 3, 5, 19, 37, 61, 225, 321, 573, 1831, 971, 6507, 10005, 6837, 16433, 70913, 170873}},
-{15822, 18, 40526, {1, 1, 5, 11, 31, 17, 21, 29, 329, 679, 869, 389, 5121, 1819, 3539, 43793, 31617, 204983}},
-{15823, 18, 40550, {1, 1, 7, 7, 21, 11, 83, 97, 297, 275, 1559, 1899, 4957, 11463, 25647, 21095, 70121, 113395}},
-{15824, 18, 40553, {1, 3, 5, 11, 19, 57, 39, 37, 441, 715, 383, 4083, 1937, 12263, 6989, 36159, 118135, 238475}},
-{15825, 18, 40562, {1, 1, 1, 3, 9, 53, 85, 201, 357, 807, 865, 1621, 1993, 7623, 3165, 1005, 93343, 227765}},
-{15826, 18, 40568, {1, 1, 7, 7, 21, 29, 123, 175, 319, 621, 303, 117, 5589, 12511, 26053, 41603, 78439, 71819}},
-{15827, 18, 40580, {1, 1, 7, 15, 31, 47, 75, 225, 295, 67, 1349, 1749, 1363, 8763, 9153, 4059, 72015, 3155}},
-{15828, 18, 40608, {1, 3, 5, 13, 19, 23, 79, 25, 319, 475, 1517, 2757, 4009, 12663, 535, 51617, 55695, 64399}},
-{15829, 18, 40613, {1, 3, 7, 13, 19, 39, 61, 235, 369, 951, 111, 2169, 353, 15371, 8611, 42477, 130981, 97419}},
-{15830, 18, 40652, {1, 1, 3, 13, 27, 31, 115, 201, 3, 291, 793, 237, 3593, 2307, 12745, 54603, 96451, 80853}},
-{15831, 18, 40703, {1, 3, 3, 11, 11, 35, 43, 1, 35, 415, 1307, 2303, 5407, 6883, 29023, 31271, 119721, 90599}},
-{15832, 18, 40712, {1, 1, 5, 9, 21, 23, 3, 1, 333, 463, 1277, 1165, 6521, 4887, 16029, 32537, 43681, 21633}},
-{15833, 18, 40720, {1, 1, 1, 13, 1, 35, 45, 57, 293, 435, 1113, 2477, 6641, 14083, 28489, 26189, 44695, 220481}},
-{15834, 18, 40723, {1, 3, 5, 5, 5, 31, 75, 149, 309, 921, 941, 1063, 7041, 12651, 29533, 46955, 88133, 89989}},
-{15835, 18, 40746, {1, 1, 3, 5, 15, 23, 127, 143, 193, 739, 281, 991, 3731, 16243, 25483, 24979, 102317, 186657}},
-{15836, 18, 40759, {1, 1, 3, 13, 3, 63, 23, 69, 181, 163, 1733, 893, 5513, 1525, 31483, 15033, 108021, 167875}},
-{15837, 18, 40765, {1, 1, 5, 15, 15, 51, 79, 59, 55, 243, 565, 159, 7925, 8393, 20059, 35011, 53779, 166241}},
-{15838, 18, 40771, {1, 1, 3, 5, 11, 57, 85, 175, 495, 999, 1577, 2377, 715, 2473, 16979, 5949, 87691, 195607}},
-{15839, 18, 40778, {1, 1, 1, 13, 17, 21, 53, 73, 187, 63, 335, 3251, 4439, 5701, 13469, 23567, 70125, 68931}},
-{15840, 18, 40788, {1, 1, 1, 13, 23, 11, 55, 75, 37, 845, 745, 2193, 7113, 5657, 29449, 41153, 115547, 87261}},
-{15841, 18, 40804, {1, 3, 3, 9, 21, 39, 47, 145, 301, 883, 625, 2479, 1089, 3393, 23265, 49577, 81027, 186485}},
-{15842, 18, 40835, {1, 1, 3, 7, 3, 11, 37, 117, 79, 905, 493, 265, 1819, 12179, 12361, 27457, 14459, 231837}},
-{15843, 18, 40841, {1, 3, 5, 11, 19, 45, 99, 5, 455, 497, 1851, 2349, 5213, 3671, 5871, 43187, 59011, 211167}},
-{15844, 18, 40907, {1, 3, 7, 5, 23, 61, 63, 97, 413, 575, 1073, 2587, 573, 1805, 32307, 58463, 84927, 15065}},
-{15845, 18, 40934, {1, 3, 1, 13, 23, 9, 39, 1, 53, 383, 1277, 3599, 7719, 16175, 4443, 53143, 24345, 111899}},
-{15846, 18, 40955, {1, 1, 7, 1, 19, 37, 103, 245, 253, 5, 1367, 3127, 4689, 5089, 30697, 45513, 111291, 26599}},
-{15847, 18, 40986, {1, 3, 3, 7, 31, 31, 107, 163, 1, 855, 163, 875, 7481, 5325, 30107, 19377, 3167, 5613}},
-{15848, 18, 41007, {1, 1, 5, 13, 21, 17, 115, 203, 233, 333, 441, 3185, 3197, 3397, 8515, 61879, 11163, 233277}},
-{15849, 18, 41016, {1, 3, 5, 3, 17, 53, 93, 233, 465, 573, 1075, 1905, 1141, 4965, 13469, 24901, 23653, 225233}},
-{15850, 18, 41034, {1, 3, 7, 11, 11, 1, 95, 47, 85, 65, 9, 2413, 7347, 2127, 305, 4673, 79281, 188081}},
-{15851, 18, 41041, {1, 1, 7, 5, 9, 5, 27, 23, 393, 201, 467, 3677, 2641, 4671, 24627, 18927, 45137, 74167}},
-{15852, 18, 41063, {1, 3, 5, 11, 11, 9, 19, 247, 423, 693, 1885, 1129, 7459, 8411, 2573, 54111, 98919, 160075}},
-{15853, 18, 41084, {1, 3, 3, 3, 1, 3, 67, 131, 317, 915, 151, 3609, 4083, 6395, 12877, 44017, 28877, 244165}},
-{15854, 18, 41093, {1, 3, 1, 3, 1, 33, 29, 23, 19, 323, 873, 115, 2439, 4699, 5449, 51637, 68889, 105197}},
-{15855, 18, 41097, {1, 1, 7, 1, 19, 55, 37, 241, 53, 695, 729, 1565, 19, 12875, 26993, 18511, 35615, 169281}},
-{15856, 18, 41111, {1, 3, 3, 1, 1, 7, 121, 49, 345, 883, 1001, 657, 2647, 15387, 30633, 18107, 13745, 217735}},
-{15857, 18, 41118, {1, 3, 5, 15, 11, 45, 73, 77, 307, 373, 1723, 335, 473, 5735, 11747, 39257, 87199, 47663}},
-{15858, 18, 41121, {1, 1, 7, 7, 27, 21, 121, 169, 427, 605, 1593, 3147, 1001, 3773, 31505, 22823, 21543, 82931}},
-{15859, 18, 41141, {1, 1, 1, 9, 11, 59, 91, 165, 249, 859, 483, 3133, 5729, 12675, 7761, 6475, 116823, 224187}},
-{15860, 18, 41160, {1, 1, 3, 3, 27, 31, 51, 1, 429, 517, 1439, 3959, 2343, 6709, 5287, 24039, 52409, 20749}},
-{15861, 18, 41207, {1, 3, 7, 7, 11, 31, 83, 111, 391, 729, 721, 1675, 5679, 14637, 22065, 49903, 113759, 40881}},
-{15862, 18, 41214, {1, 3, 7, 1, 25, 15, 91, 59, 87, 313, 155, 1439, 2419, 2099, 22709, 10289, 40655, 17351}},
-{15863, 18, 41255, {1, 3, 5, 1, 15, 5, 11, 21, 261, 227, 1563, 1177, 4731, 3487, 1607, 46599, 105599, 193425}},
-{15864, 18, 41284, {1, 1, 5, 5, 5, 45, 77, 181, 431, 27, 1985, 881, 2555, 7589, 16199, 31041, 66683, 52499}},
-{15865, 18, 41287, {1, 1, 1, 15, 5, 29, 111, 209, 335, 747, 93, 3551, 5951, 14995, 18451, 33329, 9117, 167455}},
-{15866, 18, 41308, {1, 3, 1, 7, 25, 9, 113, 123, 387, 87, 267, 2251, 3509, 10829, 32733, 48025, 58267, 143553}},
-{15867, 18, 41330, {1, 3, 5, 15, 17, 17, 65, 107, 175, 427, 733, 797, 3837, 12773, 27865, 29481, 4557, 196163}},
-{15868, 18, 41336, {1, 3, 1, 3, 1, 53, 93, 175, 509, 351, 1093, 1039, 6931, 2691, 14957, 44395, 84383, 58915}},
-{15869, 18, 41437, {1, 1, 1, 11, 1, 43, 61, 123, 377, 813, 1335, 1597, 147, 13663, 30781, 47635, 24111, 64307}},
-{15870, 18, 41444, {1, 1, 3, 11, 25, 27, 15, 215, 125, 679, 1491, 3203, 5403, 4531, 11839, 44227, 49239, 110439}},
-{15871, 18, 41456, {1, 1, 3, 13, 9, 35, 71, 127, 127, 629, 1363, 585, 6713, 10637, 6803, 20963, 47157, 157781}},
-{15872, 18, 41481, {1, 1, 3, 11, 13, 21, 117, 241, 365, 175, 1397, 1279, 4117, 5427, 24007, 50711, 465, 225003}},
-{15873, 18, 41489, {1, 1, 1, 9, 13, 63, 49, 189, 113, 61, 353, 2221, 7541, 4075, 5283, 5505, 51035, 35191}},
-{15874, 18, 41499, {1, 1, 7, 9, 11, 37, 123, 63, 331, 691, 1299, 1661, 3769, 7827, 32127, 32149, 7271, 150363}},
-{15875, 18, 41555, {1, 1, 1, 5, 25, 5, 127, 195, 413, 657, 479, 879, 6743, 8959, 791, 22425, 77119, 180721}},
-{15876, 18, 41561, {1, 1, 7, 3, 13, 57, 123, 125, 135, 69, 455, 3363, 1783, 1557, 20401, 26707, 130345, 195881}},
-{15877, 18, 41562, {1, 3, 3, 7, 27, 19, 125, 71, 201, 1017, 1285, 3955, 5255, 14375, 18163, 28537, 76157, 247193}},
-{15878, 18, 41571, {1, 1, 3, 1, 27, 33, 123, 137, 189, 655, 1891, 2419, 5195, 97, 32565, 38581, 62715, 164697}},
-{15879, 18, 41592, {1, 1, 1, 15, 9, 47, 23, 147, 197, 503, 1803, 2953, 2961, 13787, 10545, 35465, 53997, 198655}},
-{15880, 18, 41631, {1, 3, 1, 9, 9, 43, 65, 237, 119, 621, 1517, 3479, 4165, 12797, 14731, 53131, 105501, 112845}},
-{15881, 18, 41661, {1, 3, 3, 15, 3, 23, 47, 163, 469, 363, 1813, 3107, 6167, 8987, 26829, 33099, 6821, 203017}},
-{15882, 18, 41682, {1, 1, 1, 9, 1, 11, 85, 11, 251, 907, 395, 3935, 3403, 229, 16825, 48337, 103647, 91425}},
-{15883, 18, 41710, {1, 3, 1, 5, 17, 57, 21, 181, 31, 27, 235, 4041, 4927, 8319, 29765, 61603, 19081, 75879}},
-{15884, 18, 41724, {1, 1, 5, 15, 11, 3, 7, 225, 247, 221, 251, 1979, 1151, 10829, 26491, 39705, 41587, 99063}},
-{15885, 18, 41727, {1, 3, 5, 5, 19, 23, 57, 127, 467, 409, 43, 829, 3883, 10767, 24351, 31365, 115943, 209231}},
-{15886, 18, 41730, {1, 1, 7, 15, 3, 51, 17, 251, 219, 33, 1511, 2027, 4995, 12277, 7639, 59895, 85267, 87735}},
-{15887, 18, 41744, {1, 3, 7, 3, 7, 29, 93, 57, 427, 235, 1591, 3475, 1159, 2387, 851, 43307, 87081, 151543}},
-{15888, 18, 41769, {1, 3, 7, 7, 1, 9, 21, 167, 73, 439, 2035, 2091, 4563, 4819, 5591, 57123, 78739, 63235}},
-{15889, 18, 41795, {1, 1, 3, 13, 19, 35, 63, 17, 425, 277, 1669, 931, 597, 5621, 22367, 1155, 109099, 169965}},
-{15890, 18, 41798, {1, 3, 7, 5, 11, 11, 41, 71, 35, 183, 555, 2631, 5199, 16381, 16319, 1851, 121551, 141711}},
-{15891, 18, 41804, {1, 3, 5, 5, 21, 17, 3, 95, 47, 1011, 1757, 3295, 1111, 16043, 6377, 16257, 37941, 206637}},
-{15892, 18, 41826, {1, 3, 1, 5, 25, 19, 19, 69, 395, 589, 1311, 1075, 5763, 12475, 3633, 40647, 54487, 97459}},
-{15893, 18, 41852, {1, 3, 5, 7, 13, 23, 83, 91, 419, 415, 685, 1685, 2893, 12953, 30641, 43565, 11851, 187837}},
-{15894, 18, 41868, {1, 1, 5, 11, 27, 1, 61, 155, 279, 737, 215, 2909, 969, 57, 17979, 34537, 41861, 243717}},
-{15895, 18, 41910, {1, 1, 5, 1, 17, 61, 57, 199, 127, 569, 1109, 3057, 7301, 16097, 17579, 25753, 82653, 237273}},
-{15896, 18, 41914, {1, 1, 7, 15, 17, 45, 19, 53, 153, 785, 51, 291, 5261, 1317, 21163, 44393, 108131, 254373}},
-{15897, 18, 41942, {1, 1, 3, 11, 5, 19, 61, 125, 127, 961, 2019, 1725, 855, 677, 20853, 38845, 3239, 95697}},
-{15898, 18, 41969, {1, 1, 3, 15, 3, 3, 117, 17, 61, 201, 241, 1759, 4465, 3985, 6985, 47703, 58657, 52633}},
-{15899, 18, 41975, {1, 3, 3, 11, 31, 39, 107, 171, 19, 825, 1309, 807, 7787, 10761, 20215, 9287, 21553, 179599}},
-{15900, 18, 41976, {1, 3, 7, 9, 5, 7, 121, 15, 3, 199, 97, 3177, 5461, 15713, 27609, 54349, 24963, 186279}},
-{15901, 18, 41994, {1, 3, 1, 15, 11, 9, 123, 187, 363, 5, 837, 451, 1601, 6597, 10857, 46893, 83729, 20409}},
-{15902, 18, 42002, {1, 3, 1, 9, 1, 53, 71, 191, 217, 165, 1709, 1827, 1977, 10073, 11373, 35311, 26637, 134519}},
-{15903, 18, 42037, {1, 3, 5, 11, 31, 55, 101, 189, 277, 347, 629, 223, 785, 5739, 25505, 55601, 55017, 212837}},
-{15904, 18, 42056, {1, 1, 5, 11, 3, 13, 45, 235, 65, 459, 621, 587, 7105, 6181, 13193, 5683, 42935, 198585}},
-{15905, 18, 42079, {1, 1, 3, 1, 3, 17, 27, 109, 261, 979, 903, 1499, 4799, 11759, 10591, 65429, 74587, 16629}},
-{15906, 18, 42085, {1, 1, 5, 1, 13, 63, 29, 11, 441, 151, 611, 4073, 3933, 6793, 28845, 39223, 120823, 49397}},
-{15907, 18, 42089, {1, 3, 3, 5, 21, 13, 23, 53, 357, 197, 1327, 1773, 2961, 11509, 16585, 10201, 28451, 45109}},
-{15908, 18, 42123, {1, 3, 5, 7, 19, 17, 97, 63, 295, 111, 85, 2981, 6719, 9193, 15197, 12117, 2553, 59909}},
-{15909, 18, 42128, {1, 1, 5, 5, 15, 3, 9, 85, 333, 379, 1409, 1445, 4173, 3953, 833, 48089, 120249, 122703}},
-{15910, 18, 42140, {1, 3, 7, 7, 29, 13, 57, 19, 141, 979, 1991, 4011, 8125, 3915, 15753, 1371, 113771, 117273}},
-{15911, 18, 42149, {1, 3, 3, 13, 21, 53, 115, 187, 279, 29, 1355, 1843, 253, 3531, 8193, 54731, 6213, 123467}},
-{15912, 18, 42156, {1, 3, 3, 1, 25, 29, 109, 19, 37, 385, 901, 3737, 6247, 9941, 13185, 2895, 88819, 53029}},
-{15913, 18, 42186, {1, 1, 1, 1, 3, 31, 89, 157, 483, 657, 1833, 2975, 3187, 631, 28685, 7277, 4915, 115955}},
-{15914, 18, 42191, {1, 3, 3, 1, 25, 41, 13, 99, 385, 303, 297, 419, 7919, 12411, 757, 9227, 47867, 120175}},
-{15915, 18, 42205, {1, 3, 5, 11, 23, 15, 21, 157, 177, 301, 789, 2791, 5769, 7809, 2369, 26123, 116465, 22595}},
-{15916, 18, 42221, {1, 1, 5, 9, 17, 63, 45, 239, 465, 811, 1157, 1443, 8137, 12587, 26209, 62057, 59299, 167171}},
-{15917, 18, 42222, {1, 3, 3, 7, 3, 45, 41, 17, 341, 461, 571, 541, 989, 4069, 17531, 46729, 107915, 47871}},
-{15918, 18, 42230, {1, 1, 7, 1, 1, 23, 45, 213, 125, 799, 5, 3443, 2535, 12983, 2133, 63411, 93027, 89831}},
-{15919, 18, 42233, {1, 1, 1, 15, 7, 31, 49, 181, 213, 923, 281, 2059, 861, 6951, 25659, 32209, 66423, 225885}},
-{15920, 18, 42241, {1, 3, 3, 7, 9, 39, 107, 197, 383, 179, 27, 1395, 6397, 16139, 32049, 33567, 43977, 203939}},
-{15921, 18, 42247, {1, 1, 3, 5, 13, 37, 13, 31, 339, 527, 641, 181, 1413, 8145, 341, 57605, 108031, 109311}},
-{15922, 18, 42248, {1, 1, 1, 1, 21, 35, 87, 15, 279, 967, 1003, 813, 5075, 10595, 5609, 33901, 86443, 150007}},
-{15923, 18, 42254, {1, 3, 1, 5, 27, 9, 75, 199, 377, 889, 545, 1987, 6277, 361, 12563, 35699, 27105, 187995}},
-{15924, 18, 42259, {1, 3, 7, 1, 11, 3, 41, 215, 273, 61, 821, 1207, 2809, 8731, 26409, 50323, 22355, 16521}},
-{15925, 18, 42268, {1, 1, 7, 5, 29, 13, 99, 133, 15, 673, 215, 445, 4051, 2187, 9395, 62491, 58685, 224707}},
-{15926, 18, 42295, {1, 3, 3, 13, 21, 59, 17, 1, 271, 613, 939, 1881, 2379, 16325, 3275, 63707, 59961, 106937}},
-{15927, 18, 42304, {1, 3, 3, 1, 23, 53, 51, 181, 391, 375, 767, 239, 373, 4593, 25211, 37173, 70409, 252345}},
-{15928, 18, 42322, {1, 3, 3, 11, 15, 17, 37, 145, 41, 107, 151, 1351, 3457, 14727, 755, 36321, 99397, 73359}},
-{15929, 18, 42334, {1, 3, 5, 7, 25, 31, 39, 185, 341, 721, 1799, 1803, 5985, 10587, 11605, 9937, 23905, 56485}},
-{15930, 18, 42355, {1, 3, 1, 3, 19, 35, 25, 71, 109, 209, 1675, 4043, 2053, 6285, 25317, 50171, 68293, 124385}},
-{15931, 18, 42361, {1, 1, 1, 1, 21, 11, 63, 137, 361, 157, 1985, 2161, 7239, 1795, 10459, 38511, 36817, 253347}},
-{15932, 18, 42373, {1, 1, 1, 5, 31, 3, 13, 83, 185, 175, 567, 295, 459, 11453, 3765, 9841, 30333, 201377}},
-{15933, 18, 42374, {1, 1, 3, 13, 5, 57, 99, 125, 371, 903, 2001, 285, 2005, 8475, 31617, 58265, 641, 115507}},
-{15934, 18, 42398, {1, 3, 5, 9, 11, 17, 123, 67, 77, 803, 815, 3173, 4795, 11917, 1187, 32389, 102289, 248359}},
-{15935, 18, 42411, {1, 1, 5, 5, 27, 19, 59, 145, 361, 821, 33, 1465, 7643, 11101, 145, 21705, 55105, 181245}},
-{15936, 18, 42443, {1, 3, 7, 5, 15, 55, 127, 133, 157, 989, 1211, 3573, 4021, 2967, 2941, 38657, 97681, 114505}},
-{15937, 18, 42446, {1, 1, 7, 7, 23, 17, 39, 209, 117, 195, 931, 5, 7509, 9187, 6011, 10297, 13727, 258007}},
-{15938, 18, 42463, {1, 3, 1, 13, 3, 17, 105, 69, 9, 163, 1615, 241, 5207, 13173, 28521, 51417, 130645, 106787}},
-{15939, 18, 42479, {1, 1, 7, 13, 15, 3, 5, 187, 5, 239, 1799, 3083, 7801, 12781, 24817, 59341, 73867, 175273}},
-{15940, 18, 42482, {1, 1, 3, 11, 11, 1, 89, 17, 497, 217, 1565, 2933, 6449, 7687, 6561, 57903, 92751, 261371}},
-{15941, 18, 42484, {1, 1, 1, 1, 15, 39, 47, 249, 39, 765, 249, 2785, 4401, 16033, 11463, 127, 120109, 83133}},
-{15942, 18, 42498, {1, 1, 3, 3, 19, 59, 47, 153, 505, 1009, 413, 1177, 5999, 6841, 12013, 40295, 115641, 189241}},
-{15943, 18, 42534, {1, 3, 3, 11, 17, 51, 45, 101, 459, 971, 1133, 3467, 4945, 12445, 1267, 41783, 66825, 130167}},
-{15944, 18, 42537, {1, 3, 1, 7, 17, 45, 77, 211, 387, 23, 1903, 2309, 2681, 6897, 6959, 30981, 113537, 207415}},
-{15945, 18, 42557, {1, 1, 3, 1, 19, 9, 103, 89, 461, 881, 71, 2019, 6475, 13563, 18835, 2375, 34807, 1373}},
-{15946, 18, 42570, {1, 1, 7, 11, 3, 31, 125, 121, 43, 737, 1995, 3043, 811, 8883, 8169, 22131, 29295, 194963}},
-{15947, 18, 42599, {1, 3, 7, 11, 7, 45, 125, 149, 427, 187, 1361, 2405, 2815, 8877, 15255, 36867, 95517, 261969}},
-{15948, 18, 42600, {1, 1, 7, 11, 9, 29, 89, 175, 467, 997, 937, 3869, 7843, 12629, 8701, 60717, 30443, 193427}},
-{15949, 18, 42633, {1, 1, 5, 7, 3, 3, 57, 199, 315, 477, 189, 2029, 2059, 3473, 27411, 30419, 26465, 187807}},
-{15950, 18, 42639, {1, 3, 1, 15, 3, 3, 11, 55, 233, 603, 1749, 1737, 5709, 4559, 13427, 39137, 44885, 61611}},
-{15951, 18, 42672, {1, 1, 7, 1, 25, 15, 61, 199, 107, 737, 909, 3229, 1799, 5129, 27655, 45937, 919, 36161}},
-{15952, 18, 42681, {1, 1, 3, 5, 31, 27, 99, 247, 425, 689, 1335, 1661, 625, 15817, 22601, 33293, 113927, 261931}},
-{15953, 18, 42687, {1, 1, 1, 9, 5, 57, 117, 121, 465, 859, 335, 879, 665, 12787, 21313, 46387, 16437, 53769}},
-{15954, 18, 42704, {1, 1, 3, 1, 11, 11, 75, 145, 307, 621, 833, 235, 3907, 11331, 6633, 51905, 72581, 129613}},
-{15955, 18, 42713, {1, 1, 3, 13, 17, 13, 81, 125, 377, 499, 1597, 3437, 4323, 789, 23825, 46609, 105997, 159709}},
-{15956, 18, 42714, {1, 3, 3, 9, 5, 29, 113, 51, 23, 957, 1981, 3205, 2549, 9771, 2555, 44289, 103893, 170241}},
-{15957, 18, 42716, {1, 1, 5, 15, 13, 17, 101, 67, 71, 7, 185, 3775, 5399, 5213, 13095, 26045, 59467, 95547}},
-{15958, 18, 42726, {1, 1, 5, 5, 31, 11, 77, 169, 3, 1007, 1853, 2245, 509, 13489, 2807, 55227, 67541, 242835}},
-{15959, 18, 42730, {1, 3, 7, 15, 11, 63, 39, 97, 1, 219, 1827, 2343, 6009, 4909, 4327, 21853, 46079, 87719}},
-{15960, 18, 42737, {1, 3, 1, 9, 17, 51, 119, 93, 179, 607, 1051, 2381, 619, 11215, 10839, 44771, 20555, 12721}},
-{15961, 18, 42752, {1, 3, 3, 5, 21, 47, 35, 133, 61, 937, 1561, 1655, 6527, 5085, 4141, 60811, 59971, 6309}},
-{15962, 18, 42757, {1, 3, 1, 7, 5, 63, 7, 235, 489, 675, 945, 943, 7107, 6005, 32695, 27655, 113219, 132963}},
-{15963, 18, 42772, {1, 1, 1, 7, 7, 5, 81, 237, 365, 1, 811, 3075, 1771, 5223, 7337, 24601, 68383, 156975}},
-{15964, 18, 42809, {1, 3, 1, 15, 5, 35, 39, 91, 301, 387, 805, 3537, 737, 7453, 4655, 16349, 108261, 123697}},
-{15965, 18, 42853, {1, 3, 5, 3, 9, 59, 95, 187, 155, 183, 589, 2107, 967, 1095, 4875, 46131, 100699, 212797}},
-{15966, 18, 42857, {1, 3, 1, 7, 27, 29, 77, 133, 397, 445, 933, 1483, 5027, 12569, 22163, 58989, 16657, 195347}},
-{15967, 18, 42902, {1, 3, 5, 15, 21, 51, 97, 135, 165, 311, 525, 171, 4785, 7947, 14649, 40837, 58875, 222303}},
-{15968, 18, 42912, {1, 3, 3, 5, 23, 47, 41, 23, 321, 709, 1555, 1139, 3775, 11617, 13001, 18235, 51803, 197863}},
-{15969, 18, 42930, {1, 3, 5, 3, 3, 41, 91, 157, 29, 1005, 945, 3471, 2563, 8493, 24961, 44759, 103079, 50841}},
-{15970, 18, 42936, {1, 1, 5, 11, 23, 19, 91, 115, 165, 291, 1653, 1061, 1067, 6171, 18441, 26067, 3569, 117329}},
-{15971, 18, 42956, {1, 3, 7, 15, 17, 19, 89, 23, 103, 389, 623, 1071, 203, 9545, 21259, 36155, 55395, 141741}},
-{15972, 18, 42959, {1, 3, 5, 11, 27, 43, 31, 193, 55, 489, 353, 1615, 7461, 13977, 31901, 64051, 82667, 258825}},
-{15973, 18, 42978, {1, 1, 3, 7, 5, 39, 7, 245, 241, 843, 1545, 3499, 8117, 15057, 14153, 2665, 107401, 66059}},
-{15974, 18, 43001, {1, 3, 5, 11, 9, 11, 41, 171, 255, 153, 1973, 759, 51, 15601, 327, 25889, 110861, 20555}},
-{15975, 18, 43011, {1, 3, 5, 7, 5, 15, 41, 77, 87, 143, 1141, 3975, 2675, 7131, 5549, 52397, 42073, 27585}},
-{15976, 18, 43047, {1, 1, 3, 7, 29, 5, 79, 243, 359, 817, 1053, 3509, 3347, 6207, 5147, 31063, 116851, 132627}},
-{15977, 18, 43059, {1, 3, 7, 3, 27, 51, 39, 7, 95, 239, 263, 3497, 867, 1869, 16773, 46947, 59193, 37523}},
-{15978, 18, 43094, {1, 3, 1, 1, 25, 31, 113, 127, 187, 77, 675, 3307, 999, 12255, 26441, 30933, 122761, 116783}},
-{15979, 18, 43124, {1, 1, 5, 7, 7, 11, 87, 59, 437, 485, 685, 3159, 7259, 16271, 24899, 17919, 130271, 52953}},
-{15980, 18, 43218, {1, 1, 3, 11, 7, 13, 61, 157, 149, 1001, 285, 3631, 1923, 16013, 19507, 64447, 8073, 261171}},
-{15981, 18, 43220, {1, 3, 7, 9, 7, 13, 45, 7, 225, 671, 287, 1059, 5223, 2077, 7551, 58385, 92955, 162725}},
-{15982, 18, 43240, {1, 1, 5, 11, 11, 21, 17, 145, 97, 633, 475, 2639, 2069, 9663, 23633, 50949, 109941, 119865}},
-{15983, 18, 43258, {1, 1, 5, 13, 9, 49, 127, 171, 199, 413, 1315, 645, 305, 12123, 9559, 38319, 99945, 103313}},
-{15984, 18, 43263, {1, 3, 5, 3, 19, 21, 119, 17, 301, 611, 1785, 2081, 2245, 8761, 4755, 9507, 23133, 144575}},
-{15985, 18, 43265, {1, 3, 7, 11, 17, 25, 101, 59, 397, 249, 687, 715, 1151, 15941, 20525, 5171, 24073, 46257}},
-{15986, 18, 43290, {1, 1, 3, 15, 11, 45, 9, 201, 421, 867, 389, 3615, 5965, 10561, 18309, 17143, 52771, 230743}},
-{15987, 18, 43346, {1, 1, 3, 5, 9, 1, 109, 233, 431, 849, 421, 475, 1331, 9903, 20649, 34759, 118611, 38541}},
-{15988, 18, 43364, {1, 3, 5, 15, 9, 55, 113, 217, 83, 409, 1449, 2325, 4825, 11311, 14565, 65075, 124399, 3591}},
-{15989, 18, 43373, {1, 3, 3, 9, 27, 13, 101, 181, 255, 313, 693, 951, 1153, 13941, 14097, 8325, 4589, 102883}},
-{15990, 18, 43401, {1, 3, 7, 3, 3, 1, 43, 65, 321, 623, 1389, 57, 3461, 9965, 6743, 34843, 91673, 249573}},
-{15991, 18, 43416, {1, 3, 5, 5, 11, 29, 101, 79, 275, 685, 569, 59, 6921, 16065, 30625, 53339, 32283, 93401}},
-{15992, 18, 43443, {1, 3, 1, 11, 29, 33, 103, 145, 431, 289, 1845, 1915, 23, 699, 5475, 18413, 127185, 162637}},
-{15993, 18, 43458, {1, 3, 1, 11, 27, 23, 71, 63, 45, 579, 1187, 1189, 1781, 5595, 9043, 10155, 33321, 36487}},
-{15994, 18, 43497, {1, 3, 3, 15, 17, 19, 85, 233, 293, 833, 1711, 857, 7573, 393, 23141, 58713, 21399, 228381}},
-{15995, 18, 43506, {1, 3, 3, 15, 3, 35, 33, 35, 403, 123, 575, 3509, 6303, 13203, 17997, 15649, 64331, 124101}},
-{15996, 18, 43545, {1, 1, 3, 9, 23, 25, 39, 53, 119, 879, 573, 3225, 5069, 15489, 21887, 11773, 37783, 169523}},
-{15997, 18, 43558, {1, 3, 5, 5, 5, 25, 29, 189, 145, 863, 661, 3939, 1059, 11993, 1487, 3157, 118287, 69835}},
-{15998, 18, 43576, {1, 3, 7, 3, 15, 9, 85, 107, 17, 965, 1097, 2087, 1947, 14649, 4099, 50941, 64511, 209153}},
-{15999, 18, 43579, {1, 3, 5, 15, 19, 21, 127, 71, 429, 97, 1989, 835, 743, 11973, 14635, 45371, 114657, 208085}},
-{16000, 18, 43624, {1, 3, 5, 7, 23, 61, 99, 133, 235, 237, 435, 2681, 331, 7859, 20859, 3573, 102901, 775}},
-{16001, 18, 43630, {1, 3, 3, 9, 7, 57, 29, 15, 53, 569, 871, 1703, 2573, 10791, 719, 3487, 105709, 89573}},
-{16002, 18, 43637, {1, 1, 1, 9, 7, 21, 21, 207, 459, 621, 737, 635, 5101, 4343, 4961, 32067, 64017, 73675}},
-{16003, 18, 43654, {1, 1, 3, 9, 25, 27, 77, 69, 251, 327, 921, 3759, 1715, 14537, 21399, 10937, 9085, 241329}},
-{16004, 18, 43660, {1, 1, 5, 1, 23, 13, 63, 117, 81, 427, 1063, 1987, 2433, 14837, 13473, 28623, 44799, 202223}},
-{16005, 18, 43696, {1, 3, 1, 11, 17, 55, 89, 89, 455, 255, 1009, 1891, 2197, 9045, 23543, 48783, 22871, 58613}},
-{16006, 18, 43706, {1, 3, 7, 15, 25, 5, 11, 71, 399, 23, 239, 93, 6681, 11311, 23403, 58131, 59549, 38917}},
-{16007, 18, 43725, {1, 1, 1, 1, 19, 63, 73, 31, 69, 145, 921, 2475, 3505, 4797, 23805, 28621, 101153, 98895}},
-{16008, 18, 43733, {1, 3, 3, 3, 9, 1, 113, 111, 275, 851, 519, 1607, 635, 13287, 6191, 24545, 112039, 114383}},
-{16009, 18, 43753, {1, 3, 7, 9, 13, 13, 107, 97, 37, 133, 21, 1059, 4201, 6777, 2843, 43503, 23761, 13247}},
-{16010, 18, 43756, {1, 1, 7, 9, 25, 23, 101, 135, 471, 901, 539, 4083, 1765, 15553, 5879, 10787, 67543, 104543}},
-{16011, 18, 43761, {1, 3, 3, 13, 25, 63, 1, 49, 287, 357, 1701, 3689, 3895, 16313, 22619, 20203, 8195, 93127}},
-{16012, 18, 43768, {1, 1, 1, 11, 15, 37, 75, 43, 311, 443, 1639, 549, 4707, 3099, 677, 59115, 11709, 71013}},
-{16013, 18, 43812, {1, 1, 5, 11, 17, 43, 23, 21, 421, 613, 199, 1029, 5255, 271, 12911, 63431, 108889, 253379}},
-{16014, 18, 43822, {1, 3, 7, 11, 27, 45, 9, 89, 65, 25, 1183, 3497, 8123, 2389, 215, 16819, 63777, 163423}},
-{16015, 18, 43841, {1, 1, 5, 5, 29, 43, 65, 201, 391, 861, 1133, 3985, 983, 13039, 15545, 13695, 91467, 963}},
-{16016, 18, 43861, {1, 3, 7, 3, 9, 55, 73, 205, 287, 765, 941, 353, 7379, 2511, 555, 64399, 77605, 121959}},
-{16017, 18, 43868, {1, 3, 1, 11, 25, 15, 109, 35, 351, 675, 1219, 3791, 233, 15133, 30733, 24477, 86077, 85857}},
-{16018, 18, 43877, {1, 1, 1, 7, 13, 33, 63, 45, 503, 525, 781, 517, 2187, 1587, 17297, 26147, 35421, 61269}},
-{16019, 18, 43878, {1, 3, 1, 9, 9, 35, 69, 79, 447, 675, 803, 2793, 5793, 4433, 29227, 5437, 103347, 37713}},
-{16020, 18, 43908, {1, 3, 1, 9, 27, 31, 65, 167, 327, 231, 1959, 657, 3141, 8659, 11055, 23923, 73597, 187139}},
-{16021, 18, 43917, {1, 1, 5, 9, 29, 5, 37, 3, 281, 693, 133, 2139, 5867, 12073, 23669, 11427, 80627, 249003}},
-{16022, 18, 43936, {1, 1, 1, 13, 9, 35, 89, 203, 381, 281, 535, 1061, 7417, 13373, 12149, 37943, 113133, 110797}},
-{16023, 18, 43954, {1, 1, 7, 5, 7, 17, 71, 65, 385, 851, 1357, 3435, 4441, 6999, 27065, 32753, 129531, 52447}},
-{16024, 18, 43963, {1, 3, 7, 1, 3, 21, 25, 113, 361, 219, 1345, 2193, 5711, 3331, 14343, 23075, 39955, 71223}},
-{16025, 18, 43977, {1, 1, 7, 9, 15, 9, 101, 183, 59, 861, 931, 3385, 6517, 12067, 7753, 37997, 128361, 4591}},
-{16026, 18, 44008, {1, 3, 5, 3, 23, 5, 37, 217, 203, 749, 993, 2537, 2425, 13949, 17235, 15461, 21275, 141815}},
-{16027, 18, 44013, {1, 3, 5, 1, 19, 59, 63, 241, 211, 285, 2033, 1111, 2859, 14801, 9491, 14557, 12973, 223089}},
-{16028, 18, 44026, {1, 1, 1, 11, 15, 41, 57, 59, 233, 897, 1193, 381, 2237, 5309, 19237, 57607, 97941, 116573}},
-{16029, 18, 44028, {1, 1, 3, 9, 15, 17, 75, 15, 385, 129, 495, 887, 4933, 15113, 7449, 56213, 15841, 248029}},
-{16030, 18, 44045, {1, 3, 1, 1, 29, 37, 19, 221, 47, 185, 1105, 3297, 5235, 6917, 12041, 10815, 54747, 132329}},
-{16031, 18, 44046, {1, 3, 1, 5, 3, 17, 33, 35, 395, 491, 1157, 2563, 6257, 1025, 18295, 5293, 77851, 140157}},
-{16032, 18, 44053, {1, 3, 1, 13, 7, 31, 95, 21, 347, 409, 1485, 925, 327, 11497, 7305, 6503, 111175, 70989}},
-{16033, 18, 44091, {1, 3, 3, 1, 11, 41, 127, 93, 367, 649, 1585, 3379, 7269, 5537, 26077, 28541, 55379, 22989}},
-{16034, 18, 44101, {1, 1, 1, 5, 27, 11, 35, 49, 7, 113, 1477, 3615, 7567, 505, 13915, 51023, 50783, 45031}},
-{16035, 18, 44129, {1, 1, 7, 5, 25, 1, 35, 59, 269, 427, 791, 3179, 1423, 9801, 17717, 23631, 97947, 126861}},
-{16036, 18, 44139, {1, 3, 5, 7, 1, 51, 77, 97, 19, 287, 303, 791, 307, 4939, 13615, 61225, 98127, 114693}},
-{16037, 18, 44172, {1, 3, 3, 15, 5, 5, 93, 119, 429, 977, 1763, 3727, 1761, 3597, 16489, 71, 44103, 257929}},
-{16038, 18, 44203, {1, 1, 5, 1, 15, 29, 79, 33, 335, 381, 1233, 47, 6741, 4953, 29689, 11223, 129185, 182487}},
-{16039, 18, 44211, {1, 1, 1, 11, 29, 27, 27, 189, 507, 523, 1949, 2567, 4105, 1227, 16631, 34187, 28521, 265}},
-{16040, 18, 44240, {1, 3, 3, 7, 3, 7, 39, 155, 315, 439, 1953, 1227, 6135, 16291, 453, 50929, 67507, 166981}},
-{16041, 18, 44259, {1, 3, 1, 5, 7, 55, 121, 119, 87, 869, 1049, 575, 3675, 13505, 15661, 43899, 106877, 141691}},
-{16042, 18, 44305, {1, 3, 1, 11, 23, 9, 117, 243, 329, 767, 335, 2951, 2887, 13441, 27579, 15437, 31699, 165177}},
-{16043, 18, 44383, {1, 3, 7, 11, 5, 49, 47, 125, 431, 511, 299, 3215, 3287, 7029, 9737, 28317, 34355, 232365}},
-{16044, 18, 44384, {1, 3, 7, 3, 17, 9, 29, 255, 509, 393, 1583, 1979, 6735, 941, 4393, 35741, 82019, 109633}},
-{16045, 18, 44389, {1, 1, 5, 1, 13, 31, 95, 133, 117, 257, 993, 1513, 4669, 12239, 7841, 751, 79567, 23289}},
-{16046, 18, 44390, {1, 1, 7, 9, 25, 33, 127, 181, 61, 333, 1087, 1661, 2715, 2569, 30041, 4937, 36053, 3435}},
-{16047, 18, 44432, {1, 3, 1, 13, 15, 27, 123, 73, 377, 85, 435, 3435, 2079, 9271, 28685, 30089, 38799, 210247}},
-{16048, 18, 44435, {1, 1, 5, 3, 5, 17, 93, 181, 313, 837, 1115, 3099, 3603, 3483, 23185, 9933, 53127, 123245}},
-{16049, 18, 44468, {1, 1, 1, 13, 3, 57, 11, 67, 41, 273, 1005, 2313, 505, 6593, 27287, 47359, 104597, 45475}},
-{16050, 18, 44472, {1, 1, 1, 5, 13, 41, 97, 251, 317, 483, 163, 1493, 6629, 11995, 31293, 4715, 98569, 178419}},
-{16051, 18, 44483, {1, 3, 5, 5, 21, 7, 69, 169, 223, 953, 1573, 1137, 8075, 7733, 23031, 14589, 6453, 228883}},
-{16052, 18, 44497, {1, 1, 7, 9, 27, 37, 3, 183, 41, 99, 111, 1713, 1291, 8263, 6373, 39549, 3099, 156793}},
-{16053, 18, 44550, {1, 1, 3, 1, 23, 43, 15, 27, 223, 173, 1601, 2159, 3595, 15143, 31065, 35799, 77339, 141397}},
-{16054, 18, 44577, {1, 1, 5, 13, 9, 35, 27, 93, 23, 999, 593, 563, 5333, 8825, 27277, 46381, 3171, 6311}},
-{16055, 18, 44584, {1, 3, 7, 15, 25, 17, 7, 237, 379, 649, 1879, 2643, 5951, 4227, 4937, 24549, 43577, 116327}},
-{16056, 18, 44601, {1, 1, 3, 9, 29, 35, 101, 105, 19, 151, 1135, 897, 2427, 15779, 31851, 29183, 44471, 187817}},
-{16057, 18, 44674, {1, 3, 7, 11, 9, 55, 19, 115, 395, 559, 1883, 409, 2459, 201, 18975, 339, 108251, 19429}},
-{16058, 18, 44683, {1, 3, 1, 13, 1, 11, 67, 45, 407, 169, 1401, 381, 3913, 6491, 28133, 63857, 52095, 115749}},
-{16059, 18, 44688, {1, 1, 1, 11, 21, 45, 65, 253, 511, 51, 893, 3533, 2101, 4779, 23941, 22449, 82457, 44447}},
-{16060, 18, 44694, {1, 1, 7, 11, 19, 33, 101, 241, 493, 111, 1967, 469, 6575, 10445, 733, 56467, 27403, 25863}},
-{16061, 18, 44703, {1, 3, 1, 1, 5, 49, 21, 79, 53, 621, 43, 1183, 1385, 9129, 21727, 35559, 35269, 211383}},
-{16062, 18, 44713, {1, 1, 1, 13, 23, 43, 53, 145, 149, 611, 745, 899, 7095, 3243, 1993, 35807, 110783, 246199}},
-{16063, 18, 44721, {1, 1, 7, 9, 25, 37, 71, 233, 407, 1, 1749, 759, 7689, 15573, 7351, 33505, 22631, 49125}},
-{16064, 18, 44722, {1, 3, 1, 13, 31, 49, 105, 13, 257, 843, 1171, 2819, 621, 12567, 24339, 6689, 127413, 249671}},
-{16065, 18, 44733, {1, 1, 5, 11, 5, 1, 93, 21, 317, 789, 571, 2493, 7255, 6459, 14737, 13989, 47003, 246561}},
-{16066, 18, 44746, {1, 3, 5, 7, 9, 11, 69, 143, 175, 581, 825, 2219, 1165, 9061, 6073, 57169, 18135, 94943}},
-{16067, 18, 44748, {1, 1, 5, 7, 7, 55, 121, 107, 395, 939, 1291, 2497, 3757, 1361, 31823, 19375, 22551, 224653}},
-{16068, 18, 44760, {1, 1, 7, 15, 15, 1, 47, 225, 223, 589, 1539, 173, 6257, 5461, 11197, 9801, 80687, 84279}},
-{16069, 18, 44765, {1, 3, 7, 11, 23, 47, 83, 119, 367, 895, 431, 1949, 565, 1397, 24911, 29661, 67861, 74621}},
-{16070, 18, 44766, {1, 3, 3, 9, 17, 29, 15, 65, 157, 255, 303, 1467, 3279, 8873, 31279, 431, 8497, 7209}},
-{16071, 18, 44775, {1, 1, 5, 13, 9, 39, 85, 133, 427, 897, 1665, 2109, 2865, 15573, 27729, 59905, 2241, 83099}},
-{16072, 18, 44794, {1, 3, 1, 13, 1, 45, 65, 65, 249, 79, 1515, 503, 953, 9859, 13307, 27419, 102209, 107529}},
-{16073, 18, 44822, {1, 3, 7, 9, 17, 13, 79, 93, 231, 5, 1811, 557, 1837, 8077, 8109, 3497, 79985, 134375}},
-{16074, 18, 44841, {1, 1, 5, 9, 15, 3, 23, 27, 491, 9, 1657, 3877, 3783, 12645, 2599, 10673, 40035, 197681}},
-{16075, 18, 44859, {1, 1, 5, 3, 5, 13, 121, 145, 291, 621, 1731, 145, 2033, 341, 3667, 4139, 52035, 115865}},
-{16076, 18, 44894, {1, 3, 5, 5, 3, 29, 115, 227, 339, 23, 1659, 2367, 1079, 10757, 30709, 41473, 55847, 228761}},
-{16077, 18, 44900, {1, 3, 5, 7, 7, 61, 103, 57, 197, 31, 237, 2507, 5247, 10529, 13823, 47845, 129031, 47029}},
-{16078, 18, 44904, {1, 3, 7, 5, 3, 17, 91, 31, 277, 977, 1905, 3991, 3657, 12197, 14535, 43263, 109629, 31665}},
-{16079, 18, 44946, {1, 1, 5, 15, 29, 43, 121, 113, 159, 929, 669, 2067, 4999, 6847, 12369, 61795, 98525, 78051}},
-{16080, 18, 44967, {1, 1, 3, 7, 25, 61, 65, 79, 373, 683, 113, 1495, 5447, 15507, 16731, 53959, 62905, 252173}},
-{16081, 18, 44994, {1, 3, 1, 11, 1, 15, 101, 55, 477, 357, 333, 3243, 3325, 5885, 11385, 685, 90575, 23015}},
-{16082, 18, 44999, {1, 3, 1, 7, 15, 13, 91, 141, 209, 865, 2035, 2791, 367, 9953, 29547, 36731, 13649, 192911}},
-{16083, 18, 45013, {1, 1, 5, 15, 9, 59, 37, 131, 3, 299, 897, 119, 7515, 5271, 2207, 18187, 62613, 210345}},
-{16084, 18, 45017, {1, 3, 1, 7, 29, 53, 95, 185, 327, 473, 1525, 3751, 915, 5883, 4137, 46343, 104917, 182895}},
-{16085, 18, 45020, {1, 1, 7, 3, 31, 57, 53, 169, 215, 607, 541, 1081, 5265, 2509, 28379, 41767, 19435, 143693}},
-{16086, 18, 45027, {1, 1, 7, 7, 31, 57, 19, 203, 467, 57, 1305, 1513, 6069, 15595, 31717, 44687, 65335, 159315}},
-{16087, 18, 45029, {1, 1, 1, 1, 13, 1, 41, 39, 489, 465, 1645, 2847, 6193, 11025, 11297, 55945, 92085, 243061}},
-{16088, 18, 45066, {1, 3, 3, 13, 15, 47, 87, 77, 321, 903, 181, 2093, 1673, 5375, 17969, 48467, 83441, 120867}},
-{16089, 18, 45074, {1, 3, 3, 13, 13, 17, 65, 181, 283, 471, 745, 1091, 7255, 5987, 29423, 27579, 96201, 218157}},
-{16090, 18, 45080, {1, 1, 1, 7, 13, 5, 101, 131, 309, 401, 99, 2353, 55, 2377, 6059, 64777, 33401, 225605}},
-{16091, 18, 45090, {1, 3, 1, 15, 9, 35, 37, 197, 65, 593, 411, 2233, 1485, 9599, 9581, 31935, 115145, 76867}},
-{16092, 18, 45101, {1, 3, 7, 9, 3, 41, 103, 237, 453, 335, 1831, 3947, 7573, 3859, 12495, 60617, 20715, 163119}},
-{16093, 18, 45110, {1, 3, 5, 7, 9, 9, 25, 79, 421, 267, 585, 1093, 2237, 8881, 7311, 39417, 110901, 8969}},
-{16094, 18, 45113, {1, 3, 3, 15, 1, 29, 75, 159, 89, 965, 457, 1645, 1485, 729, 30547, 2275, 79633, 126089}},
-{16095, 18, 45134, {1, 3, 7, 7, 19, 47, 55, 115, 287, 477, 719, 3311, 2455, 12033, 13811, 34011, 45153, 126991}},
-{16096, 18, 45136, {1, 3, 7, 5, 9, 33, 27, 215, 7, 113, 1027, 415, 1057, 13011, 1547, 7955, 21347, 79427}},
-{16097, 18, 45148, {1, 3, 1, 11, 1, 41, 27, 29, 255, 763, 219, 897, 915, 453, 9417, 22845, 31655, 228869}},
-{16098, 18, 45158, {1, 1, 7, 13, 7, 49, 105, 111, 53, 219, 171, 841, 5027, 5311, 28171, 58719, 32241, 170921}},
-{16099, 18, 45176, {1, 3, 5, 7, 21, 53, 11, 169, 45, 429, 1727, 1953, 8119, 14955, 19997, 62665, 31345, 135715}},
-{16100, 18, 45181, {1, 1, 5, 13, 17, 13, 125, 247, 411, 663, 1725, 2515, 7995, 8963, 5797, 32871, 66603, 137997}},
-{16101, 18, 45185, {1, 1, 5, 5, 23, 37, 15, 63, 35, 817, 463, 1413, 1203, 8031, 4169, 45755, 93511, 134751}},
-{16102, 18, 45188, {1, 1, 1, 1, 31, 17, 15, 125, 199, 57, 1499, 1567, 6113, 6503, 515, 57841, 49885, 213881}},
-{16103, 18, 45203, {1, 1, 7, 7, 15, 1, 67, 213, 197, 471, 577, 27, 1533, 13009, 31861, 62435, 113139, 77057}},
-{16104, 18, 45209, {1, 3, 7, 1, 29, 21, 99, 173, 137, 19, 1727, 1157, 5215, 4367, 28803, 26031, 120195, 60111}},
-{16105, 18, 45231, {1, 1, 5, 9, 25, 55, 27, 45, 231, 693, 765, 429, 2897, 6045, 19705, 61903, 5385, 172967}},
-{16106, 18, 45234, {1, 3, 1, 5, 9, 17, 35, 151, 91, 41, 89, 3751, 27, 5721, 26117, 6105, 31609, 79569}},
-{16107, 18, 45239, {1, 3, 5, 11, 15, 3, 25, 73, 383, 765, 729, 51, 4245, 6215, 9435, 45223, 68071, 68453}},
-{16108, 18, 45246, {1, 1, 7, 5, 31, 61, 19, 153, 331, 233, 11, 3047, 3939, 11959, 897, 4437, 2941, 174493}},
-{16109, 18, 45260, {1, 1, 7, 11, 27, 11, 83, 33, 7, 761, 805, 2327, 2997, 12269, 18707, 10615, 114357, 54951}},
-{16110, 18, 45284, {1, 3, 5, 9, 3, 45, 65, 193, 347, 771, 663, 2901, 6467, 14109, 5169, 38021, 39605, 216877}},
-{16111, 18, 45301, {1, 1, 7, 1, 1, 13, 109, 179, 499, 325, 1763, 1923, 7429, 259, 20589, 48473, 49605, 124709}},
-{16112, 18, 45333, {1, 3, 1, 3, 5, 27, 25, 127, 313, 541, 589, 751, 5959, 5801, 32467, 40597, 75625, 24827}},
-{16113, 18, 45350, {1, 1, 1, 3, 13, 35, 71, 223, 281, 767, 447, 1253, 2227, 7305, 23125, 62847, 16783, 76145}},
-{16114, 18, 45354, {1, 1, 5, 5, 11, 1, 95, 215, 351, 915, 1471, 143, 4011, 3373, 19019, 31797, 85891, 33871}},
-{16115, 18, 45446, {1, 1, 3, 9, 15, 39, 125, 29, 85, 625, 1155, 753, 6679, 14239, 14597, 32715, 97313, 162291}},
-{16116, 18, 45458, {1, 1, 1, 7, 13, 47, 127, 69, 199, 145, 123, 3207, 7673, 9991, 27501, 29189, 93027, 136881}},
-{16117, 18, 45518, {1, 3, 1, 15, 9, 21, 121, 23, 457, 315, 437, 1919, 5531, 13817, 8883, 4421, 19487, 88591}},
-{16118, 18, 45566, {1, 3, 1, 9, 15, 49, 101, 27, 11, 283, 1277, 971, 7697, 5915, 12709, 38251, 88165, 261609}},
-{16119, 18, 45569, {1, 1, 3, 9, 17, 19, 53, 131, 327, 917, 603, 2451, 3597, 14731, 9223, 29719, 113507, 69875}},
-{16120, 18, 45575, {1, 1, 5, 7, 1, 3, 77, 71, 149, 901, 283, 1599, 1053, 16305, 9937, 20907, 4133, 29623}},
-{16121, 18, 45576, {1, 1, 3, 9, 25, 63, 101, 255, 397, 233, 1111, 1583, 3431, 5245, 30209, 33201, 63859, 16551}},
-{16122, 18, 45587, {1, 1, 7, 5, 19, 25, 9, 137, 105, 363, 867, 811, 5829, 12595, 18867, 61021, 19425, 99399}},
-{16123, 18, 45615, {1, 1, 3, 7, 11, 1, 119, 95, 367, 239, 1677, 67, 283, 5701, 3635, 26917, 112895, 224049}},
-{16124, 18, 45661, {1, 3, 5, 11, 13, 33, 11, 191, 305, 551, 159, 1953, 4231, 811, 8711, 41291, 110917, 176177}},
-{16125, 18, 45798, {1, 3, 5, 9, 15, 3, 27, 29, 77, 881, 849, 1113, 7151, 3433, 11199, 38409, 98173, 21373}},
-{16126, 18, 45829, {1, 1, 5, 13, 25, 57, 81, 169, 215, 379, 1707, 493, 1071, 4869, 19149, 24585, 61803, 149305}},
-{16127, 18, 45847, {1, 1, 5, 11, 13, 11, 9, 45, 207, 347, 1203, 185, 3919, 3119, 27879, 50793, 18499, 109239}},
-{16128, 18, 45858, {1, 1, 1, 5, 3, 23, 123, 175, 445, 439, 215, 1883, 6857, 14837, 29411, 33633, 96241, 68361}},
-{16129, 18, 45864, {1, 1, 5, 7, 31, 53, 19, 41, 477, 203, 1133, 1471, 5067, 3875, 30655, 9207, 24835, 22019}},
-{16130, 18, 45899, {1, 3, 1, 11, 19, 9, 91, 217, 135, 169, 489, 727, 5471, 2125, 20867, 19689, 78859, 222433}},
-{16131, 18, 45904, {1, 1, 1, 13, 5, 37, 37, 39, 397, 527, 789, 1447, 7123, 6099, 16849, 48895, 95543, 56135}},
-{16132, 18, 45919, {1, 3, 7, 7, 15, 31, 81, 165, 31, 867, 1879, 1161, 3651, 5167, 12855, 60195, 85611, 191791}},
-{16133, 18, 45974, {1, 1, 1, 9, 31, 35, 19, 123, 281, 445, 63, 2683, 7073, 1489, 9791, 40125, 43723, 103765}},
-{16134, 18, 45987, {1, 3, 3, 9, 23, 31, 113, 241, 149, 463, 1047, 3737, 8105, 16295, 4565, 8095, 16617, 87455}},
-{16135, 18, 45989, {1, 3, 5, 15, 1, 47, 29, 77, 27, 1013, 1091, 3657, 835, 563, 7139, 58839, 92697, 114523}},
-{16136, 18, 46008, {1, 3, 1, 1, 5, 49, 87, 251, 473, 583, 2033, 809, 5341, 15835, 691, 57133, 75751, 127717}},
-{16137, 18, 46036, {1, 3, 1, 11, 23, 51, 95, 167, 73, 739, 573, 1113, 7585, 5457, 25767, 5583, 29583, 48263}},
-{16138, 18, 46039, {1, 1, 3, 5, 9, 59, 1, 235, 17, 973, 1987, 3629, 1739, 6419, 29943, 44963, 63943, 18571}},
-{16139, 18, 46043, {1, 3, 7, 11, 9, 37, 25, 253, 307, 411, 891, 1977, 6979, 11287, 12619, 50327, 25831, 135673}},
-{16140, 18, 46045, {1, 1, 5, 15, 23, 27, 83, 157, 253, 559, 1989, 2431, 4821, 6617, 4295, 16143, 249, 109855}},
-{16141, 18, 46079, {1, 1, 3, 9, 31, 59, 117, 139, 379, 703, 49, 3013, 6383, 4019, 7289, 4567, 34931, 224967}},
-{16142, 18, 46084, {1, 1, 1, 3, 3, 33, 49, 127, 177, 417, 723, 3259, 1547, 3297, 19733, 59465, 122179, 13209}},
-{16143, 18, 46091, {1, 3, 3, 1, 3, 61, 23, 177, 77, 579, 1739, 2707, 5319, 13291, 10223, 45395, 62797, 124675}},
-{16144, 18, 46105, {1, 1, 3, 15, 25, 47, 79, 111, 245, 853, 1103, 3741, 5783, 2075, 26371, 28801, 117831, 111735}},
-{16145, 18, 46117, {1, 1, 5, 11, 3, 47, 43, 61, 75, 963, 1507, 3491, 6031, 14171, 32557, 23779, 44815, 168409}},
-{16146, 18, 46141, {1, 3, 3, 7, 21, 39, 61, 109, 13, 833, 373, 4021, 4035, 7987, 18957, 10423, 82823, 8763}},
-{16147, 18, 46147, {1, 1, 7, 3, 3, 33, 113, 77, 447, 127, 213, 1605, 3873, 12345, 7847, 63903, 80665, 6647}},
-{16148, 18, 46162, {1, 3, 1, 5, 25, 11, 49, 233, 377, 791, 43, 195, 393, 1403, 27567, 29673, 11327, 190513}},
-{16149, 18, 46184, {1, 3, 1, 15, 21, 3, 21, 169, 221, 495, 1045, 3715, 4923, 2437, 23203, 59905, 70285, 258455}},
-{16150, 18, 46197, {1, 1, 7, 13, 29, 33, 91, 153, 31, 359, 25, 3947, 1699, 4081, 20907, 24953, 64977, 88115}},
-{16151, 18, 46207, {1, 1, 5, 11, 17, 7, 17, 129, 91, 835, 139, 3823, 1827, 6787, 27367, 26801, 61513, 189677}},
-{16152, 18, 46214, {1, 3, 3, 9, 23, 21, 97, 103, 481, 859, 413, 893, 4021, 8111, 23703, 18791, 102735, 82735}},
-{16153, 18, 46218, {1, 1, 1, 7, 11, 53, 61, 3, 347, 633, 191, 3605, 41, 12605, 14381, 60403, 126223, 186157}},
-{16154, 18, 46237, {1, 3, 5, 1, 11, 33, 61, 235, 245, 623, 2019, 3289, 5761, 15557, 1685, 2173, 104825, 245139}},
-{16155, 18, 46247, {1, 1, 3, 7, 19, 55, 75, 219, 11, 75, 1765, 1833, 263, 6605, 26297, 24969, 17721, 109495}},
-{16156, 18, 46251, {1, 1, 7, 5, 7, 33, 23, 109, 207, 137, 385, 3233, 6765, 3517, 31389, 57049, 25645, 176257}},
-{16157, 18, 46327, {1, 1, 5, 5, 27, 63, 65, 23, 93, 721, 1665, 3805, 3611, 7543, 21119, 38565, 99921, 72773}},
-{16158, 18, 46333, {1, 1, 1, 13, 13, 19, 23, 5, 425, 727, 1469, 1261, 6597, 725, 27129, 36953, 25781, 191581}},
-{16159, 18, 46342, {1, 3, 3, 1, 3, 29, 25, 109, 237, 135, 409, 2239, 5033, 11007, 31861, 55171, 76313, 216271}},
-{16160, 18, 46366, {1, 3, 7, 13, 31, 33, 11, 31, 179, 67, 755, 2513, 37, 12863, 24053, 12315, 45009, 166643}},
-{16161, 18, 46376, {1, 1, 5, 13, 13, 37, 19, 223, 409, 387, 139, 3283, 243, 15573, 24173, 63271, 91561, 168665}},
-{16162, 18, 46384, {1, 3, 5, 7, 17, 25, 63, 231, 23, 965, 1873, 1021, 7927, 11127, 19553, 9883, 83009, 258991}},
-{16163, 18, 46404, {1, 3, 1, 7, 17, 21, 71, 65, 165, 845, 1739, 2395, 5959, 14803, 17333, 59003, 36477, 202511}},
-{16164, 18, 46478, {1, 3, 5, 13, 15, 57, 59, 205, 507, 41, 703, 195, 4373, 4023, 13399, 62061, 43645, 204899}},
-{16165, 18, 46511, {1, 3, 5, 11, 13, 13, 43, 19, 497, 599, 1345, 2001, 407, 2731, 16283, 55161, 130887, 189201}},
-{16166, 18, 46540, {1, 1, 7, 5, 13, 3, 105, 83, 235, 363, 869, 1715, 4031, 3419, 15149, 10627, 47787, 226107}},
-{16167, 18, 46638, {1, 3, 3, 3, 9, 49, 99, 161, 413, 739, 195, 2815, 1157, 9069, 15591, 4509, 30765, 184013}},
-{16168, 18, 46700, {1, 3, 7, 5, 25, 63, 23, 91, 507, 647, 1249, 2035, 4341, 8811, 8345, 49463, 69023, 195775}},
-{16169, 18, 46706, {1, 3, 5, 5, 5, 21, 117, 1, 321, 495, 251, 1961, 8043, 6593, 11017, 6167, 56607, 144009}},
-{16170, 18, 46745, {1, 1, 3, 3, 15, 63, 41, 177, 403, 375, 1771, 3, 7481, 4887, 799, 59283, 106319, 32155}},
-{16171, 18, 46757, {1, 1, 1, 7, 19, 57, 97, 91, 489, 561, 335, 3809, 3167, 8879, 1789, 22329, 58851, 84461}},
-{16172, 18, 46772, {1, 3, 3, 11, 3, 23, 79, 25, 187, 497, 1343, 543, 4495, 14599, 29365, 14795, 26341, 26923}},
-{16173, 18, 46776, {1, 3, 1, 13, 21, 35, 9, 227, 423, 761, 439, 3099, 5167, 12955, 12877, 5591, 123511, 74227}},
-{16174, 18, 46790, {1, 1, 3, 7, 1, 49, 115, 95, 481, 659, 183, 2337, 39, 235, 30869, 10223, 59673, 65293}},
-{16175, 18, 46794, {1, 1, 1, 13, 11, 29, 113, 37, 153, 993, 1195, 1695, 4741, 13671, 29097, 65023, 78281, 156235}},
-{16176, 18, 46804, {1, 3, 5, 11, 19, 17, 47, 243, 273, 679, 393, 4059, 705, 12473, 1867, 13783, 86821, 240545}},
-{16177, 18, 46820, {1, 3, 1, 11, 23, 35, 15, 31, 275, 261, 427, 909, 7925, 4737, 22825, 34859, 28593, 20071}},
-{16178, 18, 46849, {1, 3, 1, 1, 13, 1, 115, 115, 103, 63, 1023, 815, 7007, 6063, 13329, 28051, 29807, 109861}},
-{16179, 18, 46870, {1, 1, 1, 11, 19, 57, 49, 169, 33, 59, 579, 2409, 89, 9655, 18091, 57771, 34509, 175991}},
-{16180, 18, 46876, {1, 1, 5, 9, 27, 19, 41, 217, 313, 359, 1745, 3887, 589, 3103, 10087, 30615, 56793, 102515}},
-{16181, 18, 46903, {1, 3, 7, 11, 25, 43, 101, 245, 67, 1003, 1379, 2141, 8025, 15231, 20705, 45513, 82251, 147295}},
-{16182, 18, 46904, {1, 3, 5, 5, 5, 47, 19, 33, 107, 773, 627, 4077, 5829, 6483, 25791, 35079, 103073, 201657}},
-{16183, 18, 46907, {1, 1, 5, 15, 1, 37, 115, 15, 61, 987, 1029, 2125, 5357, 10233, 14907, 12077, 92143, 207301}},
-{16184, 18, 46932, {1, 1, 7, 7, 3, 15, 95, 3, 393, 535, 819, 743, 3613, 11459, 2269, 17083, 65547, 74813}},
-{16185, 18, 46955, {1, 1, 7, 5, 11, 27, 117, 65, 55, 87, 105, 3219, 1587, 383, 25349, 54561, 11935, 101203}},
-{16186, 18, 46963, {1, 1, 5, 15, 23, 53, 37, 149, 191, 963, 1407, 4091, 1647, 9537, 30247, 23501, 123745, 76301}},
-{16187, 18, 46991, {1, 3, 1, 1, 21, 31, 11, 107, 55, 823, 805, 141, 7177, 15883, 3307, 52245, 115171, 260589}},
-{16188, 18, 47029, {1, 3, 7, 13, 25, 15, 5, 221, 347, 83, 51, 1227, 4591, 851, 10173, 37777, 82441, 175219}},
-{16189, 18, 47036, {1, 1, 7, 15, 17, 41, 121, 215, 111, 999, 367, 1961, 3207, 10145, 10395, 24381, 95937, 12693}},
-{16190, 18, 47054, {1, 1, 1, 11, 23, 27, 117, 255, 87, 519, 599, 3471, 3983, 2797, 13477, 56479, 27321, 101585}},
-{16191, 18, 47099, {1, 1, 5, 9, 1, 3, 35, 15, 457, 209, 141, 1295, 1631, 9745, 30247, 44865, 78113, 13207}},
-{16192, 18, 47106, {1, 3, 3, 1, 27, 63, 29, 31, 277, 173, 1321, 3847, 4127, 8713, 10507, 8697, 97025, 105995}},
-{16193, 18, 47132, {1, 1, 5, 13, 13, 47, 33, 69, 113, 369, 539, 4075, 1013, 9733, 9291, 33377, 130567, 238331}},
-{16194, 18, 47145, {1, 3, 7, 13, 15, 15, 125, 219, 205, 763, 1233, 1911, 7733, 7623, 27305, 6067, 16169, 238805}},
-{16195, 18, 47151, {1, 3, 1, 9, 23, 17, 35, 175, 157, 627, 1045, 1791, 1675, 11699, 2151, 28293, 14529, 30523}},
-{16196, 18, 47156, {1, 1, 5, 9, 5, 1, 23, 151, 295, 949, 371, 3317, 2557, 5815, 9699, 48379, 104561, 103747}},
-{16197, 18, 47171, {1, 3, 5, 5, 11, 57, 125, 247, 29, 257, 979, 2437, 4391, 8229, 11231, 30145, 111165, 92347}},
-{16198, 18, 47188, {1, 1, 3, 3, 27, 17, 71, 71, 357, 367, 1213, 2549, 6049, 15299, 2891, 21839, 109889, 34643}},
-{16199, 18, 47201, {1, 1, 1, 11, 7, 21, 41, 77, 249, 567, 1947, 2989, 875, 12975, 23599, 49313, 67213, 98415}},
-{16200, 18, 47219, {1, 1, 7, 7, 27, 51, 103, 221, 295, 247, 1579, 2435, 67, 3087, 9421, 59573, 111143, 42363}},
-{16201, 18, 47226, {1, 1, 1, 13, 27, 27, 75, 33, 81, 841, 1295, 2823, 997, 16329, 6117, 43361, 63727, 113347}},
-{16202, 18, 47241, {1, 1, 1, 3, 19, 7, 43, 93, 397, 293, 803, 3021, 3915, 1417, 22255, 38529, 53737, 133705}},
-{16203, 18, 47252, {1, 3, 3, 13, 1, 33, 1, 235, 255, 345, 1621, 315, 2685, 6451, 7133, 239, 103075, 175033}},
-{16204, 18, 47261, {1, 3, 1, 11, 29, 47, 61, 115, 395, 633, 1913, 2983, 4581, 3729, 22511, 16479, 80607, 232859}},
-{16205, 18, 47295, {1, 3, 7, 7, 27, 25, 29, 121, 511, 533, 1791, 3349, 4915, 8213, 13913, 6595, 2353, 207495}},
-{16206, 18, 47297, {1, 3, 7, 5, 21, 25, 77, 189, 473, 1015, 1455, 1923, 3281, 15163, 2329, 58529, 55369, 195007}},
-{16207, 18, 47333, {1, 3, 1, 1, 25, 37, 117, 41, 207, 413, 143, 1707, 7463, 15399, 3013, 4141, 37669, 70953}},
-{16208, 18, 47337, {1, 3, 5, 3, 31, 61, 41, 157, 141, 387, 1705, 1661, 3607, 6905, 3305, 63235, 7977, 253707}},
-{16209, 18, 47360, {1, 1, 5, 11, 29, 15, 61, 127, 417, 795, 171, 415, 7935, 4553, 29979, 21153, 108811, 219959}},
-{16210, 18, 47377, {1, 1, 5, 11, 17, 61, 3, 9, 297, 53, 933, 341, 507, 2683, 15313, 24113, 78617, 191127}},
-{16211, 18, 47378, {1, 1, 7, 15, 5, 57, 65, 187, 15, 541, 1843, 731, 7331, 2479, 26259, 32685, 125259, 108693}},
-{16212, 18, 47384, {1, 1, 7, 7, 11, 15, 33, 183, 225, 609, 1755, 3531, 2767, 6267, 30823, 36797, 59699, 136769}},
-{16213, 18, 47389, {1, 3, 5, 13, 15, 19, 77, 239, 307, 691, 1165, 1327, 7901, 9299, 7777, 39151, 96261, 79791}},
-{16214, 18, 47417, {1, 1, 3, 5, 29, 31, 85, 109, 381, 243, 955, 193, 3461, 5163, 18607, 51143, 74457, 84685}},
-{16215, 18, 47420, {1, 1, 5, 9, 11, 23, 77, 247, 149, 759, 1153, 1781, 4107, 16315, 15513, 48545, 55607, 163947}},
-{16216, 18, 47426, {1, 3, 3, 5, 21, 27, 57, 61, 75, 943, 97, 1507, 4091, 671, 23023, 49095, 61649, 222401}},
-{16217, 18, 47443, {1, 1, 3, 13, 1, 3, 15, 105, 285, 255, 577, 1347, 2917, 10257, 21607, 63041, 79823, 6447}},
-{16218, 18, 47504, {1, 1, 3, 1, 17, 25, 109, 47, 445, 225, 1729, 2835, 4569, 8755, 21847, 25839, 43503, 173599}},
-{16219, 18, 47507, {1, 1, 5, 15, 19, 1, 121, 119, 33, 77, 1147, 359, 5747, 2785, 15567, 5409, 125979, 199183}},
-{16220, 18, 47510, {1, 3, 1, 9, 17, 45, 85, 83, 427, 223, 531, 1681, 2343, 14959, 27297, 54607, 70889, 45529}},
-{16221, 18, 47526, {1, 1, 5, 11, 31, 61, 109, 195, 505, 197, 159, 2799, 4517, 11549, 10297, 17415, 58277, 206577}},
-{16222, 18, 47550, {1, 1, 3, 5, 17, 43, 107, 207, 453, 161, 1775, 1287, 5775, 12417, 14201, 48187, 75073, 121099}},
-{16223, 18, 47552, {1, 1, 5, 7, 31, 27, 67, 251, 127, 443, 263, 895, 8081, 14053, 32023, 54743, 14723, 221285}},
-{16224, 18, 47557, {1, 3, 3, 13, 27, 45, 51, 47, 243, 15, 1283, 2291, 3613, 14733, 8777, 3959, 36769, 104789}},
-{16225, 18, 47564, {1, 3, 5, 1, 5, 31, 1, 139, 411, 79, 959, 1431, 2329, 3595, 19231, 55747, 18923, 223709}},
-{16226, 18, 47591, {1, 3, 1, 1, 7, 9, 69, 201, 305, 411, 459, 3201, 2525, 6977, 16249, 17777, 114321, 243831}},
-{16227, 18, 47610, {1, 3, 3, 5, 13, 7, 3, 27, 201, 279, 1253, 1725, 1481, 8885, 1233, 40699, 7267, 189095}},
-{16228, 18, 47621, {1, 3, 5, 5, 31, 61, 53, 231, 93, 597, 2027, 2179, 4517, 565, 27807, 5447, 130341, 10411}},
-{16229, 18, 47639, {1, 1, 7, 1, 9, 17, 63, 245, 405, 23, 1647, 285, 6625, 8935, 959, 29095, 657, 185511}},
-{16230, 18, 47646, {1, 1, 7, 7, 5, 15, 49, 69, 479, 585, 437, 1097, 5933, 1709, 26169, 36895, 16981, 147033}},
-{16231, 18, 47676, {1, 3, 7, 13, 29, 19, 89, 249, 195, 687, 379, 1291, 4791, 9039, 6381, 12965, 99995, 105107}},
-{16232, 18, 47682, {1, 1, 5, 7, 13, 49, 101, 217, 205, 635, 577, 3301, 911, 1793, 22285, 20163, 22593, 45701}},
-{16233, 18, 47732, {1, 3, 7, 9, 3, 21, 55, 123, 205, 309, 59, 3739, 1625, 839, 26733, 27443, 6699, 244287}},
-{16234, 18, 47741, {1, 1, 1, 11, 29, 3, 33, 57, 481, 691, 1401, 3595, 5435, 571, 6945, 10911, 94721, 89751}},
-{16235, 18, 47751, {1, 1, 3, 5, 21, 19, 23, 169, 263, 137, 771, 1995, 2211, 6287, 18691, 14219, 65647, 89885}},
-{16236, 18, 47757, {1, 1, 3, 7, 7, 53, 9, 155, 327, 325, 301, 3703, 1069, 15573, 14873, 15665, 71617, 5079}},
-{16237, 18, 47786, {1, 3, 1, 3, 27, 15, 1, 203, 465, 629, 71, 1093, 2071, 7743, 22441, 42997, 35249, 113329}},
-{16238, 18, 47803, {1, 3, 5, 3, 21, 35, 107, 73, 247, 575, 719, 3215, 3181, 5861, 25169, 6503, 12347, 196371}},
-{16239, 18, 47828, {1, 3, 1, 3, 7, 29, 117, 115, 221, 345, 165, 1367, 1491, 15791, 12647, 34679, 1043, 219311}},
-{16240, 18, 47848, {1, 3, 5, 7, 19, 47, 65, 65, 101, 323, 1209, 3185, 3803, 1077, 18933, 17081, 7475, 165133}},
-{16241, 18, 47853, {1, 1, 7, 1, 25, 9, 61, 245, 175, 201, 1837, 2119, 943, 14043, 14343, 46299, 81151, 5587}},
-{16242, 18, 47856, {1, 1, 1, 1, 31, 27, 49, 89, 387, 975, 1203, 2995, 2969, 1465, 925, 39611, 38101, 126043}},
-{16243, 18, 47862, {1, 3, 7, 13, 21, 17, 45, 139, 359, 11, 335, 79, 6629, 6137, 7879, 62735, 99493, 138943}},
-{16244, 18, 47874, {1, 3, 5, 5, 9, 23, 91, 195, 89, 195, 1931, 3855, 387, 3491, 29643, 59939, 32347, 171539}},
-{16245, 18, 47883, {1, 3, 3, 15, 21, 55, 5, 13, 139, 125, 1731, 3131, 1927, 16051, 8351, 18625, 32465, 255813}},
-{16246, 18, 47916, {1, 3, 7, 11, 21, 45, 53, 225, 33, 733, 115, 639, 4801, 5529, 11041, 3557, 83521, 37525}},
-{16247, 18, 47934, {1, 3, 7, 15, 3, 37, 111, 127, 463, 565, 543, 2593, 2203, 5719, 11667, 63735, 16481, 155613}},
-{16248, 18, 47951, {1, 1, 3, 13, 31, 1, 17, 53, 479, 629, 1517, 89, 3377, 4831, 9213, 55029, 69547, 52363}},
-{16249, 18, 47979, {1, 1, 7, 1, 5, 47, 115, 73, 59, 407, 1227, 2955, 5249, 7921, 4713, 28699, 41455, 1161}},
-{16250, 18, 48010, {1, 1, 7, 7, 5, 7, 39, 7, 97, 867, 247, 639, 3125, 14961, 19737, 52589, 59821, 96095}},
-{16251, 18, 48027, {1, 1, 7, 5, 11, 51, 63, 245, 385, 1003, 189, 4039, 6137, 3621, 13241, 55753, 14855, 50221}},
-{16252, 18, 48046, {1, 3, 5, 3, 9, 61, 83, 209, 301, 917, 259, 187, 6253, 1579, 28285, 16571, 100945, 158067}},
-{16253, 18, 48060, {1, 3, 5, 11, 5, 47, 123, 173, 253, 183, 1823, 459, 4719, 13639, 8455, 12217, 88779, 134863}},
-{16254, 18, 48065, {1, 1, 1, 5, 1, 45, 43, 163, 371, 427, 1791, 1073, 1615, 14473, 15895, 4971, 105269, 109201}},
-{16255, 18, 48075, {1, 3, 1, 15, 11, 9, 99, 99, 25, 21, 1499, 83, 6967, 12923, 13623, 27423, 4707, 477}},
-{16256, 18, 48096, {1, 1, 3, 5, 15, 49, 45, 27, 51, 391, 1849, 347, 6841, 2831, 4425, 40701, 61135, 116945}},
-{16257, 18, 48119, {1, 1, 3, 7, 21, 23, 15, 223, 403, 395, 1997, 3247, 6345, 11739, 6511, 44323, 86667, 213287}},
-{16258, 18, 48173, {1, 3, 7, 11, 31, 21, 75, 129, 427, 777, 1787, 4031, 1493, 2279, 10681, 36675, 25527, 123533}},
-{16259, 18, 48176, {1, 3, 5, 15, 9, 5, 117, 147, 259, 265, 1817, 583, 5341, 12115, 2369, 4023, 123479, 218877}},
-{16260, 18, 48186, {1, 1, 1, 15, 5, 21, 87, 57, 487, 529, 1129, 2989, 39, 5995, 28779, 35813, 97425, 5227}},
-{16261, 18, 48213, {1, 1, 7, 3, 7, 1, 41, 231, 195, 205, 1663, 3149, 4439, 8241, 3085, 43965, 58833, 216779}},
-{16262, 18, 48223, {1, 1, 3, 1, 23, 45, 65, 3, 55, 653, 131, 2425, 5653, 9105, 16921, 55221, 29241, 220927}},
-{16263, 18, 48224, {1, 3, 1, 3, 5, 47, 107, 49, 175, 957, 1287, 1299, 5215, 4141, 31697, 9371, 43339, 133933}},
-{16264, 18, 48229, {1, 3, 1, 7, 13, 55, 33, 163, 361, 793, 101, 2159, 3457, 12893, 11627, 27115, 95201, 2945}},
-{16265, 18, 48241, {1, 1, 7, 15, 11, 39, 79, 113, 385, 41, 1715, 3887, 1347, 8141, 6121, 18653, 50867, 55745}},
-{16266, 18, 48281, {1, 1, 7, 13, 3, 5, 23, 59, 223, 665, 1823, 2989, 1069, 15161, 8917, 5539, 47437, 240933}},
-{16267, 18, 48284, {1, 3, 7, 13, 13, 19, 73, 25, 413, 211, 439, 339, 1159, 16063, 9589, 33451, 28789, 118883}},
-{16268, 18, 48291, {1, 1, 5, 11, 13, 61, 81, 63, 197, 569, 961, 253, 2065, 8969, 24045, 52811, 26929, 111329}},
-{16269, 18, 48308, {1, 3, 7, 5, 19, 23, 27, 163, 37, 103, 1737, 175, 1853, 597, 14147, 46159, 26385, 69427}},
-{16270, 18, 48340, {1, 3, 7, 9, 27, 43, 45, 209, 61, 115, 645, 1149, 1473, 10557, 8541, 51703, 29207, 92059}},
-{16271, 18, 48344, {1, 1, 5, 5, 25, 53, 123, 243, 493, 403, 485, 1505, 6879, 1921, 13569, 28271, 24407, 73057}},
-{16272, 18, 48368, {1, 1, 3, 11, 15, 31, 99, 29, 503, 819, 55, 773, 2993, 15341, 7625, 12835, 28555, 200609}},
-{16273, 18, 48400, {1, 1, 7, 9, 21, 49, 47, 207, 13, 571, 57, 1727, 7441, 1703, 4253, 64851, 113, 180273}},
-{16274, 18, 48406, {1, 3, 3, 9, 23, 1, 1, 53, 195, 569, 925, 1969, 3031, 14371, 17673, 39163, 11819, 117573}},
-{16275, 18, 48409, {1, 1, 1, 11, 5, 3, 103, 133, 447, 1015, 1049, 3283, 7507, 233, 13721, 50721, 75511, 227561}},
-{16276, 18, 48421, {1, 3, 1, 1, 17, 59, 79, 105, 503, 173, 1575, 1563, 5807, 12841, 7983, 28209, 27527, 229919}},
-{16277, 18, 48448, {1, 1, 3, 9, 3, 41, 125, 213, 361, 939, 161, 2235, 2575, 13519, 7957, 21527, 40693, 51055}},
-{16278, 18, 48453, {1, 3, 7, 11, 11, 7, 117, 21, 7, 745, 1109, 3393, 953, 5163, 19909, 49121, 85061, 209555}},
-{16279, 18, 48457, {1, 1, 7, 5, 27, 59, 127, 199, 119, 461, 653, 497, 5867, 767, 16373, 21201, 87589, 171491}},
-{16280, 18, 48478, {1, 1, 7, 11, 7, 21, 121, 97, 17, 827, 1191, 113, 6527, 14977, 32567, 15191, 104541, 140359}},
-{16281, 18, 48493, {1, 1, 7, 13, 19, 29, 127, 207, 233, 511, 43, 3177, 7963, 5559, 24185, 13373, 37853, 150537}},
-{16282, 18, 48527, {1, 3, 3, 9, 15, 17, 119, 201, 443, 51, 17, 605, 4191, 5251, 28903, 4861, 92571, 143499}},
-{16283, 18, 48583, {1, 1, 5, 11, 21, 45, 111, 245, 115, 705, 1267, 3013, 7907, 14973, 30499, 44117, 118229, 136571}},
-{16284, 18, 48597, {1, 3, 7, 7, 31, 35, 69, 143, 269, 27, 1365, 775, 6067, 11477, 28475, 54573, 92827, 226459}},
-{16285, 18, 48641, {1, 1, 5, 1, 1, 29, 41, 189, 423, 245, 1031, 1667, 3465, 1491, 26787, 53851, 26189, 215443}},
-{16286, 18, 48668, {1, 3, 3, 5, 23, 29, 97, 141, 135, 249, 767, 3627, 7867, 9311, 25411, 38325, 118643, 128453}},
-{16287, 18, 48671, {1, 3, 7, 13, 3, 25, 61, 121, 285, 401, 1099, 2327, 5509, 16127, 2363, 52395, 114233, 216013}},
-{16288, 18, 48682, {1, 1, 1, 13, 7, 37, 83, 151, 447, 605, 289, 2941, 6273, 5945, 7493, 29805, 34935, 101177}},
-{16289, 18, 48709, {1, 1, 7, 13, 31, 51, 125, 9, 321, 293, 489, 4023, 2425, 7645, 2927, 20973, 111223, 71255}},
-{16290, 18, 48719, {1, 1, 7, 3, 27, 9, 59, 143, 307, 543, 1995, 111, 5807, 4641, 3581, 2421, 64213, 187567}},
-{16291, 18, 48731, {1, 3, 3, 9, 23, 33, 47, 81, 441, 995, 213, 3501, 1003, 9885, 24101, 58767, 49507, 30525}},
-{16292, 18, 48780, {1, 3, 1, 3, 19, 51, 117, 53, 49, 167, 1799, 1421, 2473, 3183, 14421, 58621, 130703, 48095}},
-{16293, 18, 48791, {1, 1, 7, 7, 5, 25, 33, 237, 447, 377, 517, 2047, 4357, 2747, 16491, 23935, 21655, 144151}},
-{16294, 18, 48797, {1, 1, 7, 7, 17, 5, 57, 67, 89, 897, 1163, 3517, 1651, 6745, 23449, 2853, 43829, 50707}},
-{16295, 18, 48807, {1, 1, 1, 13, 5, 45, 87, 139, 339, 1021, 649, 2957, 7887, 11957, 11235, 11063, 77329, 93121}},
-{16296, 18, 48811, {1, 1, 1, 7, 11, 35, 73, 241, 11, 287, 551, 207, 4701, 2031, 27191, 44337, 35577, 226387}},
-{16297, 18, 48814, {1, 3, 5, 11, 19, 3, 41, 211, 29, 913, 1455, 2525, 3935, 5581, 8043, 12033, 97479, 73521}},
-{16298, 18, 48821, {1, 3, 5, 7, 15, 49, 53, 185, 229, 161, 121, 3407, 903, 7257, 19535, 42197, 3983, 222077}},
-{16299, 18, 48836, {1, 1, 5, 7, 17, 33, 61, 121, 343, 111, 151, 1147, 3743, 2423, 24151, 42307, 50711, 140317}},
-{16300, 18, 48846, {1, 3, 3, 7, 27, 1, 119, 209, 243, 185, 1253, 2307, 7659, 7839, 9697, 16799, 5189, 130005}},
-{16301, 18, 48848, {1, 3, 3, 1, 27, 21, 115, 175, 157, 735, 1233, 1133, 1763, 1125, 4667, 42569, 125185, 218417}},
-{16302, 18, 48854, {1, 3, 5, 9, 5, 37, 97, 165, 87, 447, 1491, 3141, 597, 10651, 9727, 65163, 2469, 141859}},
-{16303, 18, 48874, {1, 1, 5, 13, 11, 53, 111, 123, 423, 413, 1519, 3715, 6623, 15415, 24085, 20925, 1529, 85183}},
-{16304, 18, 48908, {1, 3, 7, 1, 31, 45, 93, 45, 363, 779, 443, 3687, 6051, 11683, 31733, 57251, 55087, 240877}},
-{16305, 18, 48929, {1, 1, 1, 15, 1, 17, 53, 237, 131, 673, 1919, 1531, 7455, 5043, 1709, 23375, 75657, 194393}},
-{16306, 18, 48941, {1, 3, 5, 9, 21, 3, 101, 141, 387, 887, 1329, 2627, 2865, 2685, 20273, 18901, 43805, 181049}},
-{16307, 18, 48954, {1, 3, 5, 5, 7, 49, 55, 243, 311, 653, 959, 3157, 4891, 8777, 14381, 28105, 119323, 181129}},
-{16308, 18, 48961, {1, 1, 1, 9, 17, 33, 97, 123, 71, 5, 793, 2829, 4385, 8577, 9927, 26213, 53287, 203555}},
-{16309, 18, 48962, {1, 1, 1, 9, 15, 61, 51, 31, 195, 1003, 1915, 2349, 5319, 13411, 15265, 36321, 76157, 200437}},
-{16310, 18, 48985, {1, 3, 1, 13, 19, 41, 11, 227, 447, 395, 1885, 2953, 3537, 3855, 21611, 14547, 106573, 233205}},
-{16311, 18, 49001, {1, 3, 1, 11, 1, 1, 7, 61, 69, 631, 1687, 1131, 6901, 5801, 14431, 17807, 35777, 253941}},
-{16312, 18, 49007, {1, 3, 5, 9, 15, 47, 71, 145, 419, 401, 1781, 2031, 3157, 14483, 2393, 4061, 122053, 81701}},
-{16313, 18, 49015, {1, 3, 7, 13, 23, 21, 67, 147, 137, 277, 259, 3119, 4785, 5349, 3193, 21805, 108265, 231111}},
-{16314, 18, 49035, {1, 1, 3, 9, 23, 63, 77, 153, 75, 643, 1341, 3607, 6001, 3387, 17485, 17893, 124699, 99515}},
-{16315, 18, 49062, {1, 1, 7, 11, 9, 51, 79, 255, 255, 723, 1797, 2805, 2505, 3437, 4835, 30731, 73741, 8051}},
-{16316, 18, 49066, {1, 1, 5, 7, 5, 19, 73, 75, 19, 889, 1443, 2263, 5773, 9997, 329, 46679, 82313, 130897}},
-{16317, 18, 49085, {1, 3, 3, 9, 7, 53, 69, 11, 287, 861, 1367, 1433, 2693, 16255, 6785, 24705, 77463, 231247}},
-{16318, 18, 49091, {1, 1, 3, 7, 21, 15, 115, 131, 169, 447, 1731, 2873, 119, 643, 31719, 22193, 17959, 150567}},
-{16319, 18, 49094, {1, 3, 3, 9, 23, 21, 7, 39, 185, 837, 379, 3687, 3751, 14801, 15231, 7239, 77521, 80135}},
-{16320, 18, 49127, {1, 1, 1, 1, 7, 33, 93, 247, 487, 873, 1951, 3273, 551, 3735, 29477, 62387, 30361, 145613}},
-{16321, 18, 49134, {1, 1, 3, 7, 5, 47, 17, 31, 93, 517, 1175, 1033, 7421, 75, 541, 1967, 13059, 104751}},
-{16322, 18, 49183, {1, 3, 5, 3, 19, 23, 123, 115, 99, 747, 655, 2885, 2991, 7497, 5989, 33419, 54363, 224947}},
-{16323, 18, 49221, {1, 3, 3, 1, 15, 9, 51, 3, 307, 879, 1065, 1835, 2267, 11299, 21995, 2997, 102207, 39}},
-{16324, 18, 49231, {1, 3, 5, 3, 9, 19, 19, 79, 499, 121, 951, 1151, 379, 5299, 13727, 49061, 32605, 208683}},
-{16325, 18, 49250, {1, 3, 7, 7, 23, 41, 71, 23, 493, 969, 271, 3729, 6199, 14693, 17625, 52509, 121257, 151175}},
-{16326, 18, 49252, {1, 1, 7, 15, 9, 51, 61, 9, 147, 527, 803, 3255, 723, 3241, 23961, 17497, 122569, 50863}},
-{16327, 18, 49270, {1, 3, 5, 1, 19, 19, 31, 31, 95, 667, 377, 1193, 6759, 8583, 29801, 7989, 113899, 43481}},
-{16328, 18, 49297, {1, 3, 7, 5, 17, 47, 1, 7, 305, 489, 1035, 1335, 5901, 9635, 10433, 4235, 108577, 52661}},
-{16329, 18, 49313, {1, 1, 7, 3, 15, 7, 105, 189, 429, 287, 679, 111, 2087, 8479, 3053, 21763, 65655, 16207}},
-{16330, 18, 49340, {1, 3, 5, 13, 19, 41, 45, 115, 311, 653, 1301, 3797, 6183, 7203, 9829, 13263, 71649, 255611}},
-{16331, 18, 49365, {1, 3, 1, 9, 21, 33, 19, 233, 83, 423, 1701, 347, 3999, 11885, 19699, 61931, 63895, 59615}},
-{16332, 18, 49379, {1, 1, 7, 7, 15, 19, 61, 43, 183, 223, 1135, 3099, 3137, 16181, 31019, 20151, 30169, 13125}},
-{16333, 18, 49386, {1, 1, 1, 11, 9, 11, 3, 157, 495, 207, 603, 1919, 3565, 7639, 4281, 49179, 2465, 224033}},
-{16334, 18, 49391, {1, 3, 1, 13, 13, 19, 127, 81, 475, 659, 1053, 3153, 5223, 12567, 30945, 47109, 98253, 41571}},
-{16335, 18, 49417, {1, 1, 5, 11, 19, 1, 9, 67, 501, 149, 1695, 1265, 6467, 5285, 29865, 46777, 97581, 209395}},
-{16336, 18, 49438, {1, 1, 1, 11, 21, 23, 123, 103, 419, 787, 111, 3327, 673, 3425, 8097, 2411, 107353, 121379}},
-{16337, 18, 49444, {1, 1, 3, 3, 17, 7, 87, 35, 501, 973, 351, 751, 4813, 12245, 3053, 38633, 44995, 37151}},
-{16338, 18, 49453, {1, 3, 5, 15, 7, 57, 99, 53, 3, 355, 153, 3897, 6923, 2075, 10821, 41819, 75665, 21237}},
-{16339, 18, 49454, {1, 3, 5, 9, 3, 29, 85, 115, 191, 977, 1067, 1539, 5287, 3589, 18017, 35571, 41633, 148565}},
-{16340, 18, 49480, {1, 1, 3, 9, 9, 57, 1, 63, 333, 107, 1173, 3377, 3599, 277, 20643, 19295, 91169, 168891}},
-{16341, 18, 49485, {1, 1, 5, 13, 21, 7, 55, 15, 79, 995, 1553, 949, 6357, 8137, 9539, 861, 95635, 63021}},
-{16342, 18, 49498, {1, 1, 5, 13, 31, 59, 11, 55, 159, 449, 307, 2725, 2305, 8259, 13823, 51225, 44775, 54253}},
-{16343, 18, 49513, {1, 3, 3, 15, 19, 61, 105, 19, 211, 693, 835, 3607, 3703, 14007, 24597, 47109, 49855, 166115}},
-{16344, 18, 49527, {1, 3, 1, 9, 27, 33, 81, 229, 445, 171, 247, 2019, 5227, 8759, 30155, 1851, 26909, 47145}},
-{16345, 18, 49531, {1, 1, 3, 5, 23, 1, 57, 49, 177, 451, 1283, 3859, 4719, 13507, 29439, 9155, 129585, 94713}},
-{16346, 18, 49564, {1, 3, 3, 5, 1, 9, 37, 23, 423, 611, 113, 119, 4307, 11747, 93, 51213, 5479, 172061}},
-{16347, 18, 49588, {1, 3, 3, 15, 5, 35, 9, 43, 423, 877, 1563, 3411, 4233, 6961, 22421, 7347, 39553, 199745}},
-{16348, 18, 49609, {1, 3, 1, 9, 15, 35, 85, 57, 151, 323, 1627, 27, 3603, 11475, 6561, 6091, 72099, 185321}},
-{16349, 18, 49617, {1, 1, 3, 15, 17, 21, 3, 119, 455, 147, 1077, 3955, 1355, 3083, 28217, 50745, 114445, 46563}},
-{16350, 18, 49645, {1, 1, 5, 3, 13, 11, 35, 185, 357, 447, 649, 139, 2847, 12011, 7753, 671, 113693, 236281}},
-{16351, 18, 49646, {1, 3, 5, 1, 19, 27, 117, 195, 67, 259, 1073, 81, 5527, 6829, 26675, 60029, 8159, 13553}},
-{16352, 18, 49654, {1, 3, 3, 7, 27, 63, 115, 191, 431, 191, 1547, 2261, 6527, 13459, 12773, 37485, 114847, 61709}},
-{16353, 18, 49697, {1, 1, 3, 1, 29, 63, 47, 77, 415, 191, 325, 2487, 7457, 13721, 1573, 15037, 31941, 226651}},
-{16354, 18, 49718, {1, 1, 5, 11, 29, 59, 49, 209, 195, 901, 691, 3167, 7471, 11609, 30135, 22067, 71395, 248151}},
-{16355, 18, 49741, {1, 3, 7, 11, 7, 43, 55, 69, 289, 735, 1479, 139, 1395, 6463, 19827, 52151, 18963, 103367}},
-{16356, 18, 49754, {1, 3, 5, 5, 27, 45, 77, 79, 89, 79, 913, 1437, 3337, 8861, 5477, 46195, 105869, 242599}},
-{16357, 18, 49756, {1, 3, 5, 3, 3, 27, 103, 207, 233, 995, 1173, 1143, 3517, 3207, 8373, 45145, 79687, 150107}},
-{16358, 18, 49833, {1, 3, 7, 3, 7, 37, 1, 137, 45, 479, 861, 3863, 4249, 3075, 23639, 12531, 118473, 255805}},
-{16359, 18, 49834, {1, 1, 1, 9, 7, 23, 125, 57, 347, 215, 1749, 3029, 97, 14715, 16213, 29291, 104725, 92043}},
-{16360, 18, 49879, {1, 3, 3, 15, 31, 39, 111, 97, 369, 675, 1471, 3889, 6437, 1499, 13325, 46141, 121087, 202493}},
-{16361, 18, 49942, {1, 1, 1, 15, 15, 21, 3, 167, 251, 793, 1291, 427, 6407, 15521, 15441, 20071, 54513, 200485}},
-{16362, 18, 49946, {1, 1, 7, 11, 27, 47, 123, 195, 241, 385, 609, 2323, 1221, 815, 279, 28553, 17663, 180977}},
-{16363, 18, 49982, {1, 1, 3, 15, 23, 53, 21, 19, 329, 903, 561, 1539, 2829, 13037, 29867, 27825, 84005, 14853}},
-{16364, 18, 49994, {1, 1, 5, 1, 21, 27, 103, 99, 31, 829, 515, 3949, 3635, 935, 2127, 56659, 123477, 47003}},
-{16365, 18, 50001, {1, 3, 1, 11, 17, 63, 51, 15, 319, 539, 55, 2561, 1109, 16115, 23387, 20051, 120867, 4019}},
-{16366, 18, 50023, {1, 3, 3, 7, 31, 11, 45, 251, 209, 21, 553, 887, 393, 15183, 14735, 13163, 123681, 15013}},
-{16367, 18, 50047, {1, 3, 1, 7, 21, 41, 105, 39, 213, 477, 985, 2375, 937, 7099, 8867, 36519, 60503, 143225}},
-{16368, 18, 50120, {1, 3, 1, 1, 19, 55, 73, 171, 379, 271, 791, 2477, 5381, 1703, 3805, 37227, 55553, 34549}},
-{16369, 18, 50133, {1, 1, 5, 5, 29, 51, 127, 111, 209, 663, 975, 2293, 8155, 11263, 7891, 15463, 74889, 227403}},
-{16370, 18, 50137, {1, 3, 5, 1, 15, 1, 115, 221, 23, 247, 1597, 87, 7513, 3329, 14491, 8961, 78147, 89499}},
-{16371, 18, 50140, {1, 3, 5, 15, 25, 23, 99, 85, 189, 487, 1559, 427, 6179, 5291, 27279, 65507, 77347, 177073}},
-{16372, 18, 50156, {1, 3, 7, 1, 23, 35, 7, 89, 455, 659, 2039, 3115, 4057, 139, 1269, 62319, 13629, 201571}},
-{16373, 18, 50199, {1, 1, 1, 5, 9, 47, 55, 171, 213, 813, 135, 1545, 1421, 4055, 26697, 18889, 57653, 201369}},
-{16374, 18, 50205, {1, 3, 1, 11, 9, 45, 5, 69, 261, 907, 1229, 1371, 1867, 1771, 17309, 41759, 119129, 43521}},
-{16375, 18, 50215, {1, 1, 7, 5, 11, 27, 9, 237, 405, 53, 1359, 3665, 169, 3547, 23331, 14353, 106627, 219711}},
-{16376, 18, 50216, {1, 3, 3, 5, 17, 23, 9, 41, 81, 601, 1447, 3225, 6721, 161, 16109, 54331, 111273, 81061}},
-{16377, 18, 50224, {1, 1, 5, 7, 7, 37, 71, 13, 505, 671, 425, 2771, 1131, 1259, 13715, 45779, 114839, 217499}},
-{16378, 18, 50229, {1, 1, 1, 5, 9, 51, 85, 223, 117, 403, 1117, 723, 2465, 11947, 7495, 62991, 17825, 169147}},
-{16379, 18, 50233, {1, 1, 3, 13, 5, 57, 47, 35, 313, 901, 365, 1265, 137, 6335, 31419, 38497, 93285, 177187}},
-{16380, 18, 50251, {1, 3, 5, 5, 7, 9, 21, 109, 47, 557, 1449, 3459, 5175, 5135, 727, 55425, 60593, 86571}},
-{16381, 18, 50281, {1, 3, 7, 5, 1, 17, 119, 239, 347, 75, 1345, 2765, 1491, 16297, 25233, 60401, 85433, 59287}},
-{16382, 18, 50326, {1, 1, 5, 5, 19, 57, 41, 53, 161, 475, 1791, 3617, 1651, 15227, 30357, 63547, 69937, 246473}},
-{16383, 18, 50332, {1, 3, 7, 11, 11, 43, 79, 79, 195, 437, 39, 1259, 6041, 14989, 6615, 58747, 43583, 246979}},
-{16384, 18, 50348, {1, 1, 7, 9, 11, 13, 49, 133, 365, 931, 1089, 713, 5997, 8759, 5789, 61329, 22639, 149845}},
-{16385, 18, 50359, {1, 3, 7, 13, 9, 3, 11, 253, 339, 883, 1933, 443, 4265, 14165, 15845, 12625, 1453, 70961}},
-{16386, 18, 50374, {1, 1, 7, 13, 21, 35, 113, 83, 473, 719, 1601, 1727, 3715, 631, 28075, 17725, 11393, 116883}},
-{16387, 18, 50404, {1, 3, 7, 7, 7, 13, 117, 83, 365, 529, 1297, 3903, 2633, 9617, 15819, 38137, 49065, 189445}},
-{16388, 18, 50443, {1, 1, 1, 7, 11, 41, 107, 33, 381, 395, 1993, 2819, 3301, 7543, 6787, 27437, 113681, 132403}},
-{16389, 18, 50488, {1, 1, 1, 1, 3, 59, 91, 235, 67, 987, 1587, 1119, 5851, 13201, 1125, 49709, 381, 183295}},
-{16390, 18, 50493, {1, 3, 5, 9, 3, 33, 45, 187, 455, 151, 823, 565, 5725, 1927, 25387, 61785, 130271, 134083}},
-{16391, 18, 50505, {1, 1, 7, 5, 15, 25, 63, 231, 133, 401, 307, 2961, 4249, 2639, 10207, 8349, 8203, 72783}},
-{16392, 18, 50511, {1, 1, 5, 13, 19, 27, 43, 153, 165, 815, 1385, 3041, 853, 7683, 1035, 13255, 69779, 128765}},
-{16393, 18, 50525, {1, 1, 1, 3, 31, 61, 97, 15, 327, 717, 841, 643, 4781, 11609, 14181, 14625, 75369, 251015}},
-{16394, 18, 50542, {1, 1, 5, 11, 17, 33, 9, 45, 111, 91, 1923, 967, 5649, 13647, 30497, 2925, 18395, 255089}},
-{16395, 18, 50550, {1, 3, 3, 1, 3, 55, 33, 29, 101, 211, 1731, 2351, 7389, 14935, 29703, 60031, 122305, 174323}},
-{16396, 18, 50560, {1, 1, 1, 3, 13, 23, 79, 117, 367, 267, 143, 1537, 3159, 2303, 9653, 12029, 2841, 226971}},
-{16397, 18, 50570, {1, 1, 1, 13, 19, 57, 103, 159, 315, 895, 1879, 2153, 1901, 7635, 14145, 56495, 6203, 151203}},
-{16398, 18, 50587, {1, 3, 3, 11, 31, 11, 75, 5, 419, 963, 1809, 3751, 7291, 12697, 2841, 17965, 91707, 80361}},
-{16399, 18, 50593, {1, 1, 7, 7, 5, 23, 29, 199, 413, 501, 19, 697, 6523, 3997, 4945, 59817, 127613, 220399}},
-{16400, 18, 50611, {1, 1, 7, 5, 1, 17, 51, 9, 183, 689, 325, 2391, 2095, 1907, 10325, 51045, 20097, 33719}},
-{16401, 18, 50649, {1, 3, 5, 11, 3, 33, 45, 221, 325, 7, 253, 1323, 4959, 14067, 10035, 39463, 123171, 194581}},
-{16402, 18, 50656, {1, 1, 3, 3, 15, 45, 25, 57, 357, 907, 1249, 3279, 2631, 9209, 7857, 58233, 29049, 173859}},
-{16403, 18, 50685, {1, 3, 3, 9, 29, 39, 105, 55, 295, 583, 825, 1777, 2403, 9489, 9079, 24855, 18155, 252733}},
-{16404, 18, 50686, {1, 1, 5, 15, 5, 63, 77, 215, 287, 743, 1937, 2103, 2673, 15487, 27855, 46683, 120215, 89721}},
-{16405, 18, 50692, {1, 3, 3, 5, 27, 1, 45, 19, 309, 679, 1405, 415, 6107, 13567, 5803, 61941, 130285, 51847}},
-{16406, 18, 50702, {1, 3, 1, 15, 23, 49, 47, 113, 401, 825, 1299, 2711, 6509, 12225, 16147, 20615, 121305, 121937}},
-{16407, 18, 50704, {1, 3, 5, 5, 31, 41, 31, 57, 385, 919, 593, 1371, 6773, 12099, 23767, 17663, 128321, 188921}},
-{16408, 18, 50709, {1, 1, 3, 15, 5, 41, 17, 7, 479, 143, 549, 1827, 8107, 14775, 28817, 12297, 119893, 191297}},
-{16409, 18, 50720, {1, 3, 7, 5, 29, 61, 27, 123, 269, 223, 121, 1745, 3513, 1989, 9759, 8129, 78933, 40085}},
-{16410, 18, 50726, {1, 1, 5, 13, 23, 49, 125, 225, 479, 123, 41, 2359, 4443, 4729, 31717, 3139, 3869, 118803}},
-{16411, 18, 50729, {1, 3, 3, 3, 15, 7, 7, 87, 415, 95, 1799, 2009, 4711, 15635, 21997, 47201, 16815, 99815}},
-{16412, 18, 50737, {1, 3, 3, 1, 31, 57, 73, 31, 423, 363, 1469, 2411, 6449, 15275, 14189, 51079, 130201, 130181}},
-{16413, 18, 50758, {1, 1, 5, 3, 3, 31, 107, 11, 355, 647, 1463, 3019, 3263, 13727, 10461, 26577, 4439, 132737}},
-{16414, 18, 50772, {1, 1, 1, 7, 13, 55, 31, 227, 71, 563, 1467, 3733, 725, 3443, 19279, 4111, 35749, 62275}},
-{16415, 18, 50849, {1, 3, 3, 15, 9, 17, 61, 95, 43, 583, 1381, 1285, 2655, 9213, 27551, 16237, 29569, 216879}},
-{16416, 18, 50850, {1, 1, 1, 3, 29, 3, 87, 193, 53, 599, 1581, 907, 4381, 8697, 27299, 40259, 122653, 43559}},
-{16417, 18, 50881, {1, 3, 5, 3, 15, 49, 21, 27, 35, 353, 1281, 3253, 7339, 9333, 25253, 35035, 30379, 87387}},
-{16418, 18, 50901, {1, 1, 1, 15, 7, 27, 69, 41, 45, 729, 1005, 3495, 1445, 7421, 27443, 29609, 70105, 93883}},
-{16419, 18, 50906, {1, 1, 7, 7, 1, 41, 15, 149, 107, 121, 639, 3703, 3397, 1727, 14165, 2845, 78531, 175767}},
-{16420, 18, 50915, {1, 3, 7, 15, 27, 17, 121, 175, 399, 551, 1889, 2283, 4343, 3633, 653, 3267, 101901, 162157}},
-{16421, 18, 50961, {1, 3, 3, 15, 23, 41, 97, 251, 435, 955, 69, 509, 8001, 11783, 7397, 7587, 127089, 15391}},
-{16422, 18, 50992, {1, 3, 5, 5, 25, 25, 63, 25, 203, 655, 2039, 2545, 5405, 1377, 30543, 65531, 122825, 6853}},
-{16423, 18, 50997, {1, 1, 7, 9, 9, 43, 73, 195, 465, 497, 1085, 3821, 7115, 7513, 21913, 32499, 96467, 181905}},
-{16424, 18, 51001, {1, 1, 3, 7, 29, 29, 63, 131, 409, 423, 687, 2549, 7367, 6867, 2685, 29137, 61845, 194409}},
-{16425, 18, 51004, {1, 3, 7, 7, 3, 23, 47, 31, 121, 629, 1771, 2387, 861, 2269, 29565, 19599, 18051, 121531}},
-{16426, 18, 51033, {1, 1, 1, 3, 21, 13, 109, 105, 163, 433, 521, 3467, 6225, 3705, 30605, 3265, 119313, 2535}},
-{16427, 18, 51045, {1, 3, 5, 3, 25, 25, 89, 177, 415, 67, 361, 3317, 6411, 4857, 23249, 41959, 59931, 35797}},
-{16428, 18, 51052, {1, 3, 7, 15, 5, 37, 37, 65, 71, 13, 1621, 2217, 3723, 2113, 23755, 46521, 48091, 44307}},
-{16429, 18, 51064, {1, 1, 5, 13, 5, 5, 63, 75, 61, 443, 1663, 3239, 7717, 2623, 5723, 42673, 8519, 58773}},
-{16430, 18, 51085, {1, 1, 3, 1, 29, 13, 35, 61, 391, 517, 1007, 17, 2519, 7121, 20095, 33449, 21397, 103787}},
-{16431, 18, 51127, {1, 1, 5, 1, 9, 45, 49, 151, 39, 347, 1821, 2687, 1551, 12117, 29429, 40963, 77795, 20941}},
-{16432, 18, 51139, {1, 1, 5, 3, 13, 49, 107, 105, 201, 601, 1335, 2389, 6837, 11123, 22985, 62705, 59057, 128333}},
-{16433, 18, 51153, {1, 3, 3, 13, 5, 3, 21, 103, 481, 621, 2037, 2963, 425, 4685, 27475, 24363, 116419, 171743}},
-{16434, 18, 51181, {1, 3, 3, 5, 27, 27, 5, 91, 245, 421, 795, 1869, 6455, 4463, 23467, 24039, 69681, 262127}},
-{16435, 18, 51182, {1, 3, 1, 11, 11, 5, 31, 253, 469, 593, 877, 2041, 4615, 1541, 11823, 58525, 128689, 95985}},
-{16436, 18, 51194, {1, 3, 5, 13, 31, 35, 115, 73, 97, 213, 1499, 1371, 4239, 7897, 3987, 4833, 115043, 222743}},
-{16437, 18, 51196, {1, 3, 3, 5, 31, 15, 17, 233, 137, 521, 1721, 1913, 1881, 13457, 10733, 61527, 19825, 192601}},
-{16438, 18, 51200, {1, 3, 1, 3, 11, 21, 81, 77, 377, 915, 321, 3925, 867, 5491, 4707, 37307, 52141, 29155}},
-{16439, 18, 51239, {1, 1, 5, 1, 13, 51, 97, 161, 295, 159, 1717, 3817, 4687, 1907, 2655, 60577, 73867, 161851}},
-{16440, 18, 51240, {1, 1, 3, 13, 21, 31, 33, 145, 375, 377, 1429, 1981, 4851, 9047, 2685, 49037, 67399, 124243}},
-{16441, 18, 51254, {1, 1, 7, 13, 1, 55, 65, 147, 471, 277, 1585, 3949, 1885, 1635, 15687, 46367, 120931, 192097}},
-{16442, 18, 51260, {1, 1, 7, 9, 13, 27, 33, 41, 377, 863, 1297, 181, 2685, 11285, 3961, 63201, 59757, 70231}},
-{16443, 18, 51342, {1, 1, 3, 15, 29, 3, 79, 25, 147, 683, 1563, 805, 5891, 3355, 20113, 48261, 38195, 14589}},
-{16444, 18, 51370, {1, 1, 7, 11, 9, 15, 21, 33, 47, 923, 1291, 4001, 203, 305, 21575, 41915, 74769, 114921}},
-{16445, 18, 51372, {1, 3, 7, 11, 15, 1, 75, 173, 473, 493, 291, 811, 931, 10731, 9855, 57891, 81575, 250565}},
-{16446, 18, 51377, {1, 3, 3, 3, 31, 31, 71, 141, 389, 661, 71, 3245, 6827, 9219, 26607, 50511, 94783, 130785}},
-{16447, 18, 51398, {1, 1, 7, 3, 9, 15, 67, 141, 293, 779, 3, 3311, 7063, 13709, 29715, 55227, 11043, 150343}},
-{16448, 18, 51402, {1, 3, 3, 3, 21, 9, 45, 111, 207, 715, 345, 1345, 3079, 3851, 23709, 33919, 108213, 25353}},
-{16449, 18, 51407, {1, 3, 5, 13, 7, 3, 35, 95, 397, 397, 1159, 2759, 5233, 16237, 12469, 29543, 39133, 64429}},
-{16450, 18, 51410, {1, 1, 5, 13, 19, 35, 9, 7, 153, 843, 2025, 1379, 3361, 15889, 7411, 26399, 106295, 19851}},
-{16451, 18, 51412, {1, 3, 1, 1, 21, 15, 71, 143, 279, 431, 487, 967, 4445, 11969, 16671, 48891, 59605, 230607}},
-{16452, 18, 51419, {1, 3, 5, 1, 25, 63, 23, 143, 221, 805, 377, 1441, 1971, 1985, 10055, 35991, 115873, 223455}},
-{16453, 18, 51428, {1, 3, 1, 7, 21, 57, 1, 185, 117, 75, 1623, 3805, 2385, 10245, 29009, 59149, 130219, 114763}},
-{16454, 18, 51431, {1, 3, 1, 13, 19, 13, 105, 241, 47, 597, 1725, 2579, 3785, 1667, 12427, 62623, 60883, 189977}},
-{16455, 18, 51460, {1, 3, 5, 13, 1, 55, 59, 133, 263, 415, 1013, 139, 3037, 13661, 15303, 27279, 84095, 184807}},
-{16456, 18, 51475, {1, 3, 1, 11, 7, 45, 3, 179, 315, 639, 875, 3299, 5221, 8463, 17507, 59673, 73865, 98867}},
-{16457, 18, 51477, {1, 3, 7, 7, 3, 3, 53, 233, 219, 519, 585, 3029, 3623, 9559, 2251, 43735, 121513, 208007}},
-{16458, 18, 51478, {1, 3, 1, 3, 17, 47, 47, 145, 445, 541, 163, 2653, 165, 7213, 3311, 57335, 43967, 191841}},
-{16459, 18, 51482, {1, 3, 5, 5, 7, 47, 39, 119, 13, 727, 887, 3743, 3807, 15267, 3977, 52833, 14851, 61851}},
-{16460, 18, 51511, {1, 1, 3, 5, 9, 9, 107, 119, 501, 723, 1965, 3093, 6947, 1783, 11287, 24243, 14005, 106677}},
-{16461, 18, 51518, {1, 3, 3, 11, 11, 29, 85, 243, 359, 195, 221, 1767, 6969, 15275, 20853, 26921, 40903, 29849}},
-{16462, 18, 51568, {1, 3, 1, 5, 31, 3, 11, 247, 371, 339, 1263, 119, 791, 7425, 18879, 11333, 34359, 178929}},
-{16463, 18, 51607, {1, 1, 3, 7, 23, 15, 121, 203, 441, 499, 779, 1971, 339, 8737, 6859, 32417, 97073, 256143}},
-{16464, 18, 51618, {1, 1, 5, 11, 3, 23, 25, 51, 407, 677, 97, 281, 427, 3671, 7939, 54485, 3967, 210199}},
-{16465, 18, 51630, {1, 1, 5, 9, 5, 45, 23, 171, 255, 967, 313, 3881, 6039, 10545, 3591, 51985, 37145, 99291}},
-{16466, 18, 51655, {1, 1, 5, 7, 3, 13, 55, 147, 83, 369, 1707, 1919, 491, 11507, 29559, 29169, 65897, 80587}},
-{16467, 18, 51673, {1, 1, 3, 13, 31, 41, 41, 237, 245, 109, 969, 1797, 8169, 6351, 3657, 9655, 109201, 245117}},
-{16468, 18, 51683, {1, 3, 7, 5, 17, 23, 17, 219, 473, 1, 865, 1949, 7589, 10107, 3035, 19903, 79579, 138695}},
-{16469, 18, 51709, {1, 3, 1, 15, 13, 57, 109, 117, 277, 773, 31, 3807, 7615, 2453, 22655, 51513, 108367, 248473}},
-{16470, 18, 51716, {1, 1, 7, 11, 17, 59, 27, 167, 63, 931, 13, 3721, 1789, 7621, 31093, 27541, 37283, 35193}},
-{16471, 18, 51774, {1, 3, 3, 11, 13, 9, 7, 85, 45, 151, 1865, 4049, 4433, 9517, 231, 30733, 93701, 126585}},
-{16472, 18, 51829, {1, 3, 1, 13, 21, 33, 19, 87, 77, 425, 351, 1163, 7453, 12567, 24615, 35563, 127643, 28625}},
-{16473, 18, 51830, {1, 1, 3, 11, 7, 35, 27, 47, 465, 595, 985, 573, 2541, 7841, 14749, 43761, 26699, 135895}},
-{16474, 18, 51839, {1, 1, 1, 7, 25, 51, 93, 237, 355, 575, 1, 443, 5697, 1997, 28801, 11621, 62531, 88449}},
-{16475, 18, 51849, {1, 1, 1, 9, 23, 35, 23, 91, 161, 601, 1401, 2187, 6283, 10711, 21277, 47771, 12589, 176625}},
-{16476, 18, 51869, {1, 3, 3, 5, 13, 23, 33, 65, 213, 835, 539, 2487, 273, 6113, 18327, 52493, 17571, 160909}},
-{16477, 18, 51886, {1, 3, 1, 5, 25, 9, 117, 201, 457, 331, 1455, 439, 4891, 5515, 21701, 9343, 29085, 120299}},
-{16478, 18, 51905, {1, 1, 1, 5, 29, 7, 43, 125, 155, 43, 1949, 2901, 7293, 13683, 18289, 16873, 27899, 168631}},
-{16479, 18, 51906, {1, 1, 7, 3, 29, 33, 53, 137, 301, 27, 1101, 837, 5843, 13167, 6073, 49083, 120031, 45065}},
-{16480, 18, 51915, {1, 3, 5, 1, 31, 47, 127, 185, 279, 603, 1699, 1693, 3263, 9055, 3525, 46065, 79305, 19949}},
-{16481, 18, 51948, {1, 3, 7, 9, 17, 47, 25, 191, 369, 877, 1477, 3041, 5123, 1393, 5061, 1755, 61051, 55299}},
-{16482, 18, 51988, {1, 1, 5, 13, 13, 7, 89, 141, 251, 321, 1515, 2677, 5103, 12901, 29875, 165, 15073, 47795}},
-{16483, 18, 51998, {1, 3, 1, 7, 1, 37, 55, 173, 191, 981, 685, 4003, 6319, 3037, 30637, 11955, 81015, 89239}},
-{16484, 18, 52004, {1, 3, 5, 5, 1, 5, 55, 251, 229, 153, 425, 2793, 6779, 15797, 10087, 7573, 121789, 115479}},
-{16485, 18, 52026, {1, 3, 7, 13, 23, 39, 23, 21, 55, 543, 1539, 3055, 7825, 2865, 8967, 56719, 117219, 142137}},
-{16486, 18, 52036, {1, 1, 5, 13, 1, 29, 81, 11, 509, 61, 1681, 1911, 829, 10583, 7105, 42047, 128579, 48891}},
-{16487, 18, 52082, {1, 1, 3, 13, 7, 27, 81, 89, 129, 239, 309, 1353, 5265, 12255, 29391, 1659, 114857, 43551}},
-{16488, 18, 52127, {1, 1, 7, 13, 23, 15, 9, 93, 35, 839, 549, 1793, 4693, 13295, 10603, 18179, 33141, 239555}},
-{16489, 18, 52145, {1, 3, 1, 7, 17, 5, 11, 193, 143, 579, 1199, 1239, 4503, 15855, 23345, 34789, 59427, 235319}},
-{16490, 18, 52157, {1, 3, 5, 3, 25, 63, 11, 203, 415, 135, 261, 1843, 3409, 4605, 15213, 28537, 75787, 100007}},
-{16491, 18, 52165, {1, 1, 1, 5, 3, 37, 29, 157, 213, 235, 959, 1087, 2843, 10265, 28233, 14281, 25867, 204031}},
-{16492, 18, 52193, {1, 3, 3, 7, 19, 49, 55, 111, 253, 823, 533, 941, 2509, 5595, 9267, 28457, 84301, 165385}},
-{16493, 18, 52211, {1, 3, 5, 9, 5, 59, 13, 85, 339, 889, 597, 3517, 7001, 5525, 25451, 13855, 19033, 182677}},
-{16494, 18, 52213, {1, 3, 1, 15, 23, 29, 31, 105, 353, 825, 1977, 2013, 131, 1969, 427, 16465, 90817, 257931}},
-{16495, 18, 52218, {1, 3, 1, 3, 29, 9, 109, 243, 321, 15, 1479, 787, 4667, 13925, 7347, 7977, 105585, 143959}},
-{16496, 18, 52220, {1, 1, 7, 15, 5, 45, 11, 95, 215, 719, 827, 77, 7263, 5705, 26971, 26845, 82127, 2849}},
-{16497, 18, 52238, {1, 1, 7, 9, 5, 43, 103, 133, 203, 127, 2021, 3609, 6971, 13447, 27089, 62287, 104391, 147901}},
-{16498, 18, 52240, {1, 3, 1, 3, 3, 41, 61, 101, 381, 985, 1795, 2465, 2899, 13517, 23953, 38831, 43569, 128643}},
-{16499, 18, 52243, {1, 3, 5, 5, 9, 49, 13, 7, 215, 85, 1203, 647, 6627, 1861, 17901, 40203, 13007, 84975}},
-{16500, 18, 52250, {1, 3, 5, 15, 31, 13, 55, 89, 397, 641, 1599, 3379, 3401, 4173, 5757, 42945, 59269, 106891}},
-{16501, 18, 52279, {1, 1, 5, 13, 25, 17, 45, 27, 151, 725, 819, 581, 3675, 3983, 9499, 47511, 128039, 56825}},
-{16502, 18, 52285, {1, 1, 5, 1, 7, 11, 65, 63, 301, 927, 409, 3729, 7227, 12849, 17855, 36527, 2907, 66819}},
-{16503, 18, 52306, {1, 3, 3, 3, 29, 35, 39, 1, 349, 429, 805, 3639, 3909, 4211, 10393, 36223, 72543, 136375}},
-{16504, 18, 52370, {1, 1, 1, 9, 23, 27, 25, 213, 195, 455, 883, 3357, 7277, 9061, 14103, 6005, 35031, 72703}},
-{16505, 18, 52432, {1, 1, 3, 3, 11, 17, 19, 181, 25, 775, 897, 3809, 2031, 13017, 7505, 37469, 107335, 174309}},
-{16506, 18, 52457, {1, 1, 7, 13, 7, 1, 57, 27, 159, 465, 533, 3409, 3863, 14001, 8011, 25873, 14971, 67243}},
-{16507, 18, 52466, {1, 1, 3, 11, 19, 5, 11, 19, 75, 489, 1879, 1539, 6563, 4729, 15605, 35203, 47993, 110139}},
-{16508, 18, 52514, {1, 3, 5, 9, 23, 17, 67, 89, 379, 849, 1667, 955, 1537, 11781, 9791, 46959, 79481, 237335}},
-{16509, 18, 52557, {1, 1, 7, 9, 3, 31, 127, 145, 29, 35, 463, 4009, 4427, 16215, 12093, 50085, 51259, 45091}},
-{16510, 18, 52560, {1, 1, 5, 9, 25, 3, 1, 131, 221, 951, 117, 3227, 797, 7617, 13243, 50139, 26737, 105875}},
-{16511, 18, 52585, {1, 1, 5, 3, 11, 5, 7, 155, 211, 865, 27, 3943, 7923, 9973, 23233, 37399, 89951, 106555}},
-{16512, 18, 52586, {1, 1, 3, 13, 21, 61, 77, 121, 227, 527, 1641, 3535, 3801, 7221, 6423, 9179, 114935, 33373}},
-{16513, 18, 52603, {1, 3, 7, 5, 31, 7, 123, 159, 367, 369, 1905, 1689, 6773, 675, 30289, 54149, 71469, 232835}},
-{16514, 18, 52650, {1, 1, 1, 13, 9, 23, 83, 237, 251, 941, 781, 1489, 6037, 6001, 15909, 50527, 60143, 238499}},
-{16515, 18, 52672, {1, 3, 1, 11, 5, 7, 103, 43, 413, 247, 535, 2107, 1801, 16381, 32529, 2355, 39143, 71281}},
-{16516, 18, 52681, {1, 1, 7, 5, 5, 31, 19, 11, 191, 643, 923, 1661, 2215, 11817, 23937, 62907, 128301, 21459}},
-{16517, 18, 52692, {1, 3, 7, 15, 1, 51, 123, 61, 99, 751, 1819, 1191, 3865, 8765, 7131, 33965, 55697, 87059}},
-{16518, 18, 52735, {1, 1, 5, 13, 5, 57, 41, 103, 135, 207, 517, 3995, 2537, 15705, 9123, 26193, 30653, 190549}},
-{16519, 18, 52760, {1, 1, 3, 1, 23, 5, 109, 209, 407, 143, 943, 2325, 8087, 559, 23675, 31815, 43805, 67497}},
-{16520, 18, 52772, {1, 1, 5, 9, 25, 33, 13, 21, 93, 357, 1551, 739, 5595, 16285, 30761, 54075, 75505, 177333}},
-{16521, 18, 52781, {1, 3, 5, 11, 17, 59, 31, 249, 95, 561, 1849, 4061, 5577, 2607, 30083, 59033, 56697, 89761}},
-{16522, 18, 52793, {1, 1, 3, 13, 27, 57, 9, 17, 323, 813, 1197, 2775, 3443, 9523, 24509, 12129, 89697, 169043}},
-{16523, 18, 52796, {1, 3, 5, 13, 17, 51, 91, 1, 105, 345, 829, 1365, 2755, 7197, 26655, 1303, 52223, 133893}},
-{16524, 18, 52807, {1, 1, 7, 1, 31, 3, 51, 21, 327, 851, 153, 3329, 3393, 8489, 5879, 25035, 124403, 172657}},
-{16525, 18, 52821, {1, 1, 1, 5, 3, 21, 61, 29, 99, 343, 621, 3163, 3763, 9347, 7691, 34667, 24555, 125819}},
-{16526, 18, 52849, {1, 1, 1, 1, 3, 17, 83, 191, 83, 315, 1091, 589, 5081, 4611, 15521, 25791, 9103, 13741}},
-{16527, 18, 52866, {1, 3, 5, 3, 7, 53, 9, 227, 399, 857, 673, 3027, 5045, 5573, 7467, 4813, 99659, 142845}},
-{16528, 18, 52868, {1, 1, 5, 11, 23, 37, 71, 151, 279, 879, 601, 2391, 7091, 12669, 10203, 11747, 9613, 248261}},
-{16529, 18, 52872, {1, 1, 3, 3, 29, 25, 33, 25, 1, 683, 1475, 457, 3641, 14219, 20105, 21449, 6903, 43819}},
-{16530, 18, 52875, {1, 1, 7, 7, 5, 1, 73, 79, 357, 971, 699, 1105, 1683, 1687, 32677, 62467, 47671, 88149}},
-{16531, 18, 52886, {1, 3, 1, 15, 23, 13, 93, 75, 307, 81, 1607, 1333, 6969, 7747, 27135, 58941, 26355, 5565}},
-{16532, 18, 52890, {1, 1, 7, 3, 27, 35, 85, 195, 421, 999, 1721, 2029, 283, 13995, 21649, 7519, 73357, 193171}},
-{16533, 18, 52896, {1, 3, 7, 15, 17, 63, 21, 187, 475, 671, 1681, 2731, 8169, 3327, 19789, 53295, 43219, 6949}},
-{16534, 18, 52925, {1, 1, 7, 13, 9, 33, 47, 115, 295, 123, 1293, 1627, 4261, 4503, 15925, 16521, 81759, 247089}},
-{16535, 18, 52931, {1, 3, 1, 13, 11, 15, 83, 129, 409, 465, 873, 1333, 7939, 973, 2753, 33727, 128975, 43333}},
-{16536, 18, 52937, {1, 3, 3, 3, 27, 59, 1, 137, 145, 29, 1189, 2615, 3249, 11197, 17165, 32313, 14065, 44199}},
-{16537, 18, 52938, {1, 3, 3, 11, 17, 49, 107, 111, 45, 963, 1129, 1775, 7671, 1495, 14531, 49743, 63321, 159841}},
-{16538, 18, 52952, {1, 1, 5, 9, 5, 11, 79, 99, 155, 347, 1777, 3793, 1765, 2319, 3135, 30237, 100845, 52689}},
-{16539, 18, 52979, {1, 3, 7, 13, 21, 57, 71, 207, 149, 161, 265, 991, 6967, 8905, 21581, 13921, 79201, 95667}},
-{16540, 18, 53013, {1, 3, 5, 15, 13, 53, 95, 81, 443, 161, 1071, 2749, 6637, 837, 15015, 62397, 33295, 112005}},
-{16541, 18, 53023, {1, 3, 1, 1, 31, 25, 37, 111, 79, 293, 249, 1523, 1509, 1993, 17167, 62939, 118281, 62699}},
-{16542, 18, 53027, {1, 3, 7, 7, 5, 33, 61, 179, 265, 405, 287, 1899, 437, 1609, 19617, 41093, 36341, 176593}},
-{16543, 18, 53033, {1, 1, 5, 3, 9, 33, 97, 45, 23, 807, 1575, 627, 7465, 4805, 11191, 35439, 69433, 47275}},
-{16544, 18, 53039, {1, 1, 1, 5, 1, 51, 51, 247, 453, 449, 1487, 141, 2501, 8039, 14749, 63733, 91963, 232951}},
-{16545, 18, 53041, {1, 3, 3, 13, 15, 7, 81, 211, 445, 15, 899, 835, 5163, 3403, 7367, 29963, 80413, 87209}},
-{16546, 18, 53048, {1, 3, 1, 11, 25, 43, 113, 139, 381, 391, 485, 1503, 4195, 10109, 13771, 35865, 50909, 224887}},
-{16547, 18, 53073, {1, 1, 7, 9, 9, 51, 21, 85, 137, 765, 951, 2453, 227, 9177, 1457, 47937, 84203, 118987}},
-{16548, 18, 53095, {1, 3, 5, 9, 1, 1, 21, 41, 133, 317, 519, 2249, 3453, 2957, 2029, 54737, 42515, 176017}},
-{16549, 18, 53099, {1, 3, 1, 7, 9, 27, 79, 193, 209, 281, 267, 1267, 7013, 13667, 13331, 32863, 5289, 15077}},
-{16550, 18, 53120, {1, 1, 5, 11, 29, 3, 3, 177, 75, 485, 1735, 3955, 4349, 7893, 13075, 58735, 8629, 78143}},
-{16551, 18, 53154, {1, 1, 7, 13, 3, 15, 15, 77, 7, 843, 1561, 461, 6817, 4363, 7861, 45697, 115663, 93789}},
-{16552, 18, 53168, {1, 1, 1, 7, 5, 35, 83, 213, 229, 383, 747, 337, 2589, 683, 18575, 42415, 74889, 227331}},
-{16553, 18, 53192, {1, 3, 5, 3, 17, 35, 57, 213, 247, 273, 689, 1889, 5667, 357, 4267, 11611, 20621, 159039}},
-{16554, 18, 53205, {1, 3, 3, 15, 7, 55, 25, 83, 293, 939, 1169, 2507, 3939, 7537, 2959, 40231, 124511, 181091}},
-{16555, 18, 53206, {1, 1, 5, 9, 31, 51, 67, 149, 509, 695, 449, 2761, 6597, 4741, 4205, 49177, 45599, 167807}},
-{16556, 18, 53234, {1, 1, 7, 15, 3, 7, 113, 71, 279, 885, 251, 2831, 855, 6673, 6511, 63861, 41109, 177119}},
-{16557, 18, 53246, {1, 1, 5, 3, 7, 23, 125, 11, 217, 1023, 549, 529, 3891, 10595, 13751, 37729, 113469, 110549}},
-{16558, 18, 53253, {1, 1, 3, 15, 21, 9, 13, 63, 93, 635, 659, 2837, 6303, 10083, 10107, 27859, 33891, 181229}},
-{16559, 18, 53263, {1, 1, 7, 3, 3, 43, 5, 149, 353, 353, 565, 2441, 7113, 6493, 30355, 17887, 110787, 187199}},
-{16560, 18, 53275, {1, 1, 3, 7, 19, 43, 99, 63, 169, 743, 185, 3817, 6677, 5549, 1609, 24701, 98669, 233701}},
-{16561, 18, 53313, {1, 1, 1, 1, 21, 49, 73, 169, 223, 551, 553, 917, 4705, 14951, 14031, 19753, 96205, 131755}},
-{16562, 18, 53331, {1, 1, 3, 3, 17, 49, 51, 249, 293, 921, 435, 2915, 3125, 3487, 11417, 35043, 29543, 35933}},
-{16563, 18, 53349, {1, 1, 3, 9, 23, 43, 73, 151, 379, 911, 671, 151, 955, 11885, 28795, 23967, 117135, 137985}},
-{16564, 18, 53367, {1, 1, 3, 7, 29, 3, 51, 231, 59, 227, 443, 3533, 7785, 12535, 25725, 7451, 9391, 239281}},
-{16565, 18, 53383, {1, 3, 3, 9, 17, 37, 91, 195, 5, 843, 313, 1417, 1207, 3225, 15949, 34023, 1275, 221057}},
-{16566, 18, 53392, {1, 1, 3, 15, 3, 51, 111, 135, 63, 495, 1967, 2151, 197, 10913, 20705, 1021, 68431, 67119}},
-{16567, 18, 53404, {1, 1, 5, 3, 7, 29, 87, 219, 273, 267, 1317, 797, 6723, 947, 29867, 32571, 12337, 234715}},
-{16568, 18, 53407, {1, 3, 5, 15, 1, 9, 91, 63, 97, 107, 451, 4025, 233, 7803, 17031, 7669, 49417, 256611}},
-{16569, 18, 53411, {1, 1, 7, 3, 17, 17, 45, 197, 227, 133, 799, 411, 6739, 8037, 19553, 53009, 25201, 107625}},
-{16570, 18, 53417, {1, 3, 5, 7, 3, 39, 25, 95, 197, 127, 45, 173, 3305, 6575, 19633, 54919, 35373, 59509}},
-{16571, 18, 53425, {1, 3, 3, 3, 9, 1, 107, 211, 217, 715, 311, 3641, 8055, 1, 9017, 29329, 128467, 46911}},
-{16572, 18, 53443, {1, 1, 1, 7, 1, 13, 13, 79, 259, 533, 1761, 449, 3363, 3061, 26227, 50407, 122951, 261425}},
-{16573, 18, 53469, {1, 3, 5, 5, 29, 19, 41, 7, 25, 203, 587, 3321, 655, 15877, 10423, 41481, 70325, 165527}},
-{16574, 18, 53480, {1, 3, 5, 9, 11, 45, 91, 253, 7, 137, 795, 2379, 4527, 1677, 5081, 6523, 97245, 3691}},
-{16575, 18, 53508, {1, 3, 7, 9, 25, 43, 125, 243, 391, 785, 651, 3245, 7979, 14689, 15443, 40501, 5519, 96551}},
-{16576, 18, 53535, {1, 1, 1, 3, 25, 53, 45, 159, 47, 701, 1655, 2019, 2355, 11213, 12403, 42291, 44925, 72689}},
-{16577, 18, 53536, {1, 1, 1, 5, 21, 19, 77, 31, 3, 161, 149, 3759, 6331, 12311, 7021, 1117, 12459, 134821}},
-{16578, 18, 53542, {1, 1, 3, 9, 9, 59, 23, 255, 437, 625, 719, 3727, 7157, 1889, 31523, 59127, 114143, 174179}},
-{16579, 18, 53563, {1, 1, 1, 15, 23, 7, 47, 137, 77, 519, 1681, 1159, 6121, 14789, 21343, 43101, 44709, 179863}},
-{16580, 18, 53577, {1, 3, 1, 3, 17, 27, 103, 11, 327, 735, 1949, 3719, 811, 2267, 13187, 29747, 98433, 242021}},
-{16581, 18, 53591, {1, 1, 7, 15, 15, 63, 25, 203, 109, 585, 409, 4093, 6669, 2381, 30721, 58975, 17235, 257959}},
-{16582, 18, 53607, {1, 3, 3, 5, 5, 19, 27, 69, 69, 193, 693, 1169, 6321, 3425, 9285, 28019, 128343, 185165}},
-{16583, 18, 53626, {1, 1, 3, 9, 7, 51, 113, 93, 81, 385, 1811, 2601, 2065, 1029, 24515, 7199, 26425, 174283}},
-{16584, 18, 53628, {1, 1, 1, 5, 29, 55, 93, 219, 281, 887, 891, 2763, 6083, 9627, 18559, 21329, 73887, 83699}},
-{16585, 18, 53638, {1, 1, 1, 3, 21, 31, 49, 173, 15, 177, 1001, 3453, 5623, 14107, 8837, 10163, 26817, 41947}},
-{16586, 18, 53675, {1, 1, 3, 5, 27, 63, 117, 49, 405, 281, 981, 2363, 1525, 9685, 29089, 16739, 66509, 125823}},
-{16587, 18, 53685, {1, 3, 7, 13, 27, 29, 57, 189, 345, 135, 753, 463, 731, 4823, 14335, 33299, 105229, 54705}},
-{16588, 18, 53692, {1, 3, 1, 1, 9, 43, 51, 25, 371, 261, 1409, 3493, 2811, 12915, 16075, 62159, 125945, 108453}},
-{16589, 18, 53703, {1, 3, 7, 15, 13, 33, 47, 53, 263, 669, 1383, 3059, 4043, 4777, 14679, 2077, 11019, 5803}},
-{16590, 18, 53722, {1, 1, 3, 11, 21, 7, 39, 71, 215, 79, 1849, 1261, 45, 1273, 27591, 4653, 25119, 30445}},
-{16591, 18, 53738, {1, 3, 5, 9, 21, 3, 17, 207, 417, 777, 37, 3349, 2761, 4469, 3457, 15593, 87251, 38601}},
-{16592, 18, 53748, {1, 1, 7, 13, 29, 29, 101, 103, 487, 87, 1129, 2497, 5501, 4813, 8623, 25077, 50487, 94053}},
-{16593, 18, 53752, {1, 3, 3, 11, 7, 23, 95, 245, 127, 55, 431, 2707, 4955, 15871, 29589, 60023, 1921, 227623}},
-{16594, 18, 53764, {1, 1, 3, 11, 17, 61, 103, 59, 477, 99, 1203, 157, 203, 557, 22921, 47363, 12853, 144067}},
-{16595, 18, 53781, {1, 3, 1, 13, 15, 23, 51, 109, 499, 841, 1779, 2515, 2519, 4945, 20061, 12395, 9223, 157901}},
-{16596, 18, 53788, {1, 3, 7, 9, 9, 15, 57, 223, 223, 463, 427, 2145, 1219, 12639, 28361, 46019, 128101, 198479}},
-{16597, 18, 53791, {1, 3, 7, 7, 1, 1, 99, 101, 135, 169, 1885, 3979, 3051, 13649, 26607, 45067, 4503, 74087}},
-{16598, 18, 53816, {1, 3, 7, 5, 17, 63, 27, 45, 447, 759, 1099, 3407, 489, 2719, 31577, 10355, 126835, 203439}},
-{16599, 18, 53824, {1, 1, 5, 1, 21, 19, 1, 239, 433, 531, 1181, 2021, 423, 3235, 8457, 44459, 117401, 63545}},
-{16600, 18, 53830, {1, 3, 7, 13, 21, 39, 25, 65, 405, 785, 137, 2899, 3255, 11165, 7827, 46425, 89063, 102787}},
-{16601, 18, 53839, {1, 1, 1, 11, 25, 3, 39, 61, 395, 35, 2001, 3201, 2233, 9625, 26489, 54167, 88495, 127441}},
-{16602, 18, 53844, {1, 1, 7, 7, 3, 27, 11, 49, 117, 711, 1881, 1457, 6759, 10517, 12733, 47435, 103111, 237237}},
-{16603, 18, 53875, {1, 1, 5, 5, 1, 61, 121, 155, 223, 733, 1349, 2825, 2093, 4481, 21389, 40227, 20453, 116907}},
-{16604, 18, 53921, {1, 3, 7, 7, 5, 11, 85, 131, 345, 723, 853, 3679, 7859, 11923, 16619, 63169, 127261, 155665}},
-{16605, 18, 53922, {1, 1, 5, 1, 3, 51, 93, 225, 197, 893, 555, 2611, 6225, 7819, 31655, 12235, 24919, 31451}},
-{16606, 18, 53927, {1, 1, 3, 3, 11, 23, 95, 205, 85, 705, 545, 155, 5533, 14837, 8341, 42473, 96891, 70695}},
-{16607, 18, 53948, {1, 3, 3, 5, 17, 31, 99, 187, 219, 275, 685, 2933, 4535, 13495, 20351, 60667, 95211, 129233}},
-{16608, 18, 53956, {1, 1, 1, 11, 9, 11, 123, 231, 127, 199, 733, 2495, 2601, 10565, 3155, 45251, 128319, 187457}},
-{16609, 18, 53990, {1, 3, 1, 9, 3, 33, 41, 109, 279, 851, 1115, 3773, 2383, 1885, 6993, 59693, 69863, 88081}},
-{16610, 18, 53994, {1, 1, 7, 13, 3, 27, 27, 203, 337, 965, 959, 1125, 2897, 8653, 15827, 51187, 12121, 4665}},
-{16611, 18, 54001, {1, 3, 1, 9, 19, 7, 23, 113, 257, 671, 571, 1061, 4353, 217, 13603, 27961, 68431, 147187}},
-{16612, 18, 54016, {1, 3, 5, 9, 25, 61, 7, 139, 237, 859, 761, 2005, 5981, 153, 6553, 53005, 72653, 33571}},
-{16613, 18, 54019, {1, 3, 5, 5, 9, 35, 63, 149, 427, 65, 635, 1955, 1845, 13781, 9761, 36147, 91479, 141305}},
-{16614, 18, 54070, {1, 1, 3, 5, 13, 39, 53, 113, 481, 933, 239, 3713, 7453, 12363, 14763, 46955, 108545, 74349}},
-{16615, 18, 54074, {1, 3, 1, 7, 13, 41, 57, 225, 213, 617, 1947, 2855, 4885, 8553, 20259, 57125, 59369, 178553}},
-{16616, 18, 54088, {1, 3, 5, 15, 31, 31, 19, 87, 461, 403, 1193, 2123, 4991, 14551, 17153, 14171, 17157, 194879}},
-{16617, 18, 54102, {1, 1, 5, 11, 5, 27, 119, 65, 111, 455, 1949, 3441, 6951, 6819, 12839, 6913, 57695, 145925}},
-{16618, 18, 54111, {1, 1, 1, 15, 19, 41, 55, 45, 33, 559, 589, 3773, 745, 8515, 32389, 47797, 145, 105503}},
-{16619, 18, 54130, {1, 1, 3, 15, 13, 53, 35, 223, 247, 893, 149, 553, 829, 5129, 26417, 15769, 95411, 6595}},
-{16620, 18, 54152, {1, 1, 5, 3, 3, 59, 35, 187, 387, 3, 847, 3579, 7869, 481, 23955, 22191, 21041, 230449}},
-{16621, 18, 54170, {1, 1, 3, 15, 23, 11, 97, 199, 11, 647, 803, 2391, 5791, 2223, 22187, 49675, 87775, 196871}},
-{16622, 18, 54172, {1, 3, 7, 5, 25, 63, 107, 227, 133, 337, 1767, 2459, 2987, 10463, 25001, 17047, 79901, 222877}},
-{16623, 18, 54211, {1, 3, 1, 13, 25, 5, 47, 109, 473, 389, 1743, 3951, 4231, 827, 4189, 29903, 106909, 152835}},
-{16624, 18, 54218, {1, 1, 5, 3, 7, 61, 121, 189, 303, 21, 957, 545, 7893, 3217, 25847, 29371, 100569, 132393}},
-{16625, 18, 54228, {1, 1, 1, 15, 29, 17, 59, 37, 449, 149, 845, 555, 7603, 11911, 18477, 23279, 107167, 160339}},
-{16626, 18, 54251, {1, 1, 7, 5, 13, 27, 43, 167, 443, 445, 2011, 2179, 2785, 13663, 21957, 2455, 18217, 19303}},
-{16627, 18, 54253, {1, 1, 1, 5, 19, 45, 71, 39, 21, 791, 1467, 855, 3101, 8267, 15529, 919, 105313, 75627}},
-{16628, 18, 54268, {1, 3, 1, 11, 31, 25, 57, 177, 211, 327, 679, 771, 7725, 6123, 23931, 48223, 9063, 133319}},
-{16629, 18, 54271, {1, 3, 5, 3, 1, 11, 19, 153, 177, 563, 1919, 117, 5583, 1519, 16623, 10871, 15511, 66113}},
-{16630, 18, 54274, {1, 1, 7, 7, 9, 45, 63, 253, 415, 347, 81, 2991, 2691, 2383, 15573, 33783, 12445, 224107}},
-{16631, 18, 54288, {1, 3, 5, 5, 7, 17, 99, 231, 439, 1009, 623, 833, 685, 6419, 30313, 56197, 73239, 260007}},
-{16632, 18, 54314, {1, 1, 5, 5, 5, 51, 97, 239, 267, 629, 1211, 2175, 5681, 3107, 11381, 57047, 120175, 131285}},
-{16633, 18, 54319, {1, 1, 7, 7, 29, 11, 21, 49, 481, 279, 1795, 1295, 453, 15985, 19941, 51853, 15115, 107271}},
-{16634, 18, 54321, {1, 1, 5, 1, 23, 61, 33, 21, 409, 57, 903, 557, 1673, 2759, 23705, 4109, 58865, 233081}},
-{16635, 18, 54324, {1, 1, 1, 5, 11, 37, 79, 15, 213, 485, 1477, 3925, 3205, 9267, 22043, 54197, 57101, 66185}},
-{16636, 18, 54341, {1, 1, 7, 13, 31, 27, 95, 141, 131, 43, 2039, 2257, 17, 14427, 5699, 22263, 86851, 226283}},
-{16637, 18, 54353, {1, 3, 5, 5, 11, 5, 5, 217, 363, 163, 1241, 3683, 1409, 1731, 20973, 63849, 35041, 94859}},
-{16638, 18, 54366, {1, 1, 7, 1, 25, 61, 67, 239, 369, 319, 1157, 2435, 2147, 12057, 4451, 3005, 31787, 199653}},
-{16639, 18, 54370, {1, 3, 5, 1, 11, 57, 1, 163, 433, 11, 1299, 1711, 1601, 4677, 16481, 25175, 63893, 41853}},
-{16640, 18, 54420, {1, 1, 3, 1, 29, 49, 91, 15, 313, 533, 115, 4005, 3157, 10615, 27915, 52613, 64447, 93091}},
-{16641, 18, 54423, {1, 3, 7, 3, 7, 17, 103, 67, 237, 595, 1571, 3421, 3971, 11123, 145, 52087, 59273, 21417}},
-{16642, 18, 54434, {1, 3, 5, 11, 31, 37, 105, 205, 377, 243, 841, 3153, 6847, 14171, 19947, 61561, 35, 261753}},
-{16643, 18, 54440, {1, 3, 5, 9, 29, 21, 103, 219, 107, 427, 1841, 2015, 2919, 5721, 8631, 48841, 33281, 35835}},
-{16644, 18, 54454, {1, 1, 3, 5, 25, 27, 67, 65, 305, 677, 1975, 1049, 7277, 15279, 30181, 48941, 119087, 130265}},
-{16645, 18, 54495, {1, 1, 3, 9, 29, 27, 109, 167, 351, 463, 663, 3155, 919, 10627, 30163, 62233, 32927, 210775}},
-{16646, 18, 54501, {1, 3, 5, 5, 19, 9, 17, 93, 33, 999, 1537, 3045, 3735, 4625, 31363, 46075, 80985, 108331}},
-{16647, 18, 54526, {1, 3, 7, 7, 11, 63, 83, 157, 205, 505, 657, 1901, 1405, 8349, 16473, 29397, 130379, 167963}},
-{16648, 18, 54639, {1, 3, 1, 15, 25, 49, 65, 189, 461, 923, 1839, 2597, 2471, 14103, 2915, 48429, 74387, 243465}},
-{16649, 18, 54653, {1, 3, 7, 11, 31, 47, 109, 21, 205, 343, 1999, 315, 8119, 15937, 8761, 55257, 99983, 131641}},
-{16650, 18, 54667, {1, 1, 3, 11, 3, 23, 73, 125, 17, 967, 1811, 1413, 4783, 8303, 25301, 26859, 90583, 140721}},
-{16651, 18, 54678, {1, 1, 5, 5, 25, 41, 49, 127, 391, 381, 1575, 1697, 5205, 12805, 24365, 20275, 58819, 167845}},
-{16652, 18, 54700, {1, 1, 7, 11, 17, 53, 51, 35, 383, 931, 359, 2863, 119, 6683, 26247, 14281, 49205, 256869}},
-{16653, 18, 54717, {1, 1, 7, 9, 23, 5, 69, 97, 407, 15, 579, 2905, 47, 6227, 23997, 42459, 26569, 225467}},
-{16654, 18, 54780, {1, 3, 3, 11, 7, 3, 125, 87, 347, 79, 1571, 1513, 285, 12101, 1731, 27887, 42009, 173243}},
-{16655, 18, 54801, {1, 3, 7, 13, 3, 5, 99, 29, 77, 873, 1111, 1451, 5493, 10669, 22597, 54437, 55521, 101617}},
-{16656, 18, 54813, {1, 3, 1, 3, 3, 17, 41, 215, 207, 71, 683, 1979, 4849, 2437, 5717, 28999, 55005, 233929}},
-{16657, 18, 54814, {1, 1, 1, 1, 23, 21, 105, 223, 5, 235, 1533, 3715, 2689, 13937, 12125, 63879, 111537, 39817}},
-{16658, 18, 54850, {1, 3, 3, 15, 25, 47, 71, 229, 21, 563, 1851, 2423, 131, 4431, 31567, 8883, 1311, 227893}},
-{16659, 18, 54883, {1, 3, 5, 11, 7, 23, 19, 59, 397, 315, 1149, 3595, 5973, 11027, 5233, 55237, 102777, 137421}},
-{16660, 18, 54907, {1, 1, 7, 9, 17, 61, 45, 235, 387, 171, 1079, 3119, 6933, 3591, 751, 35495, 49969, 204611}},
-{16661, 18, 54919, {1, 1, 7, 7, 21, 7, 105, 79, 81, 245, 1229, 409, 5159, 9815, 6713, 4687, 120541, 246133}},
-{16662, 18, 54931, {1, 3, 7, 13, 23, 31, 85, 97, 481, 497, 581, 1179, 243, 1767, 11855, 11599, 3141, 104741}},
-{16663, 18, 54933, {1, 3, 7, 3, 3, 45, 15, 29, 413, 631, 273, 1007, 2979, 11307, 24535, 9305, 83591, 77121}},
-{16664, 18, 54991, {1, 3, 7, 15, 21, 55, 11, 169, 417, 631, 141, 1489, 3371, 16073, 11215, 15479, 125341, 131731}},
-{16665, 18, 55003, {1, 1, 7, 5, 13, 33, 7, 121, 295, 191, 497, 2233, 997, 13833, 14503, 38357, 79007, 53985}},
-{16666, 18, 55009, {1, 3, 3, 3, 29, 63, 97, 27, 449, 643, 317, 1989, 1481, 2873, 21247, 35989, 61295, 101829}},
-{16667, 18, 55030, {1, 3, 1, 7, 13, 49, 27, 227, 21, 983, 179, 2761, 2859, 2851, 26447, 33295, 126963, 41441}},
-{16668, 18, 55034, {1, 1, 5, 13, 27, 1, 61, 115, 185, 867, 2017, 2257, 5035, 7855, 25849, 48189, 28287, 133261}},
-{16669, 18, 55039, {1, 1, 7, 13, 27, 17, 13, 205, 379, 717, 247, 3341, 2841, 10845, 26979, 5589, 1935, 48371}},
-{16670, 18, 55048, {1, 3, 1, 11, 9, 51, 25, 185, 65, 643, 1867, 3825, 3395, 8883, 29239, 20019, 19071, 3377}},
-{16671, 18, 55059, {1, 1, 1, 1, 11, 57, 61, 113, 419, 249, 153, 2883, 87, 7919, 11941, 46725, 38701, 73715}},
-{16672, 18, 55061, {1, 3, 3, 11, 3, 15, 19, 87, 27, 839, 463, 1757, 3137, 10821, 2857, 58101, 91983, 137045}},
-{16673, 18, 55068, {1, 3, 3, 1, 25, 25, 15, 93, 359, 5, 53, 647, 6245, 1957, 4651, 14697, 12193, 231303}},
-{16674, 18, 55077, {1, 1, 5, 9, 31, 49, 69, 223, 133, 595, 777, 1281, 727, 6671, 21453, 14193, 51769, 258301}},
-{16675, 18, 55122, {1, 3, 5, 11, 29, 37, 75, 17, 229, 121, 313, 2873, 5233, 13231, 7589, 40075, 42101, 137697}},
-{16676, 18, 55149, {1, 1, 7, 1, 31, 9, 15, 63, 149, 5, 1785, 21, 2619, 15071, 3243, 58023, 20697, 205181}},
-{16677, 18, 55157, {1, 3, 7, 7, 25, 61, 59, 157, 251, 303, 1905, 2389, 1681, 319, 14155, 49089, 45381, 124447}},
-{16678, 18, 55158, {1, 3, 5, 5, 25, 27, 41, 125, 105, 867, 365, 117, 7215, 2887, 28499, 9597, 105999, 150189}},
-{16679, 18, 55178, {1, 1, 5, 13, 5, 33, 47, 221, 207, 641, 525, 3215, 5293, 16343, 16169, 44393, 26305, 194411}},
-{16680, 18, 55222, {1, 3, 5, 13, 29, 17, 31, 77, 511, 465, 1141, 597, 5111, 6629, 14557, 13057, 11643, 250925}},
-{16681, 18, 55234, {1, 1, 7, 11, 1, 5, 65, 139, 471, 265, 1145, 965, 47, 10971, 15615, 62031, 58523, 175593}},
-{16682, 18, 55236, {1, 1, 5, 1, 23, 61, 57, 139, 377, 843, 79, 2873, 1823, 7551, 26741, 63031, 124879, 115295}},
-{16683, 18, 55251, {1, 1, 5, 13, 9, 19, 1, 61, 331, 1015, 1035, 1691, 4057, 6071, 24929, 39569, 95695, 39307}},
-{16684, 18, 55269, {1, 3, 3, 5, 23, 17, 13, 65, 381, 893, 1879, 3735, 1547, 6735, 30251, 11471, 102997, 126429}},
-{16685, 18, 55270, {1, 1, 5, 13, 1, 43, 15, 1, 155, 221, 1463, 3793, 6467, 7221, 28027, 55357, 69397, 87565}},
-{16686, 18, 55284, {1, 1, 7, 3, 17, 9, 71, 75, 77, 639, 1251, 701, 473, 12337, 1893, 6349, 10837, 27797}},
-{16687, 18, 55309, {1, 3, 5, 11, 11, 11, 125, 23, 161, 937, 707, 2487, 695, 8495, 16219, 33671, 109463, 248305}},
-{16688, 18, 55322, {1, 1, 1, 11, 5, 49, 15, 47, 393, 407, 39, 1867, 7727, 12701, 7805, 119, 77401, 186421}},
-{16689, 18, 55334, {1, 1, 5, 5, 19, 21, 77, 187, 387, 51, 1497, 1225, 3101, 791, 529, 4321, 118435, 112889}},
-{16690, 18, 55340, {1, 3, 1, 13, 27, 17, 11, 63, 201, 909, 1549, 3243, 1803, 9461, 20985, 24637, 100993, 200473}},
-{16691, 18, 55348, {1, 3, 7, 13, 11, 35, 97, 213, 415, 467, 2013, 2159, 7017, 7895, 18235, 50659, 113169, 141887}},
-{16692, 18, 55377, {1, 1, 3, 7, 13, 21, 119, 109, 471, 323, 277, 1685, 2399, 14777, 2643, 5879, 113043, 45223}},
-{16693, 18, 55430, {1, 3, 1, 13, 19, 5, 1, 75, 499, 297, 1897, 591, 3223, 12939, 30593, 4053, 122207, 215171}},
-{16694, 18, 55433, {1, 3, 3, 9, 21, 11, 29, 205, 13, 381, 569, 599, 7089, 8145, 18531, 34477, 101057, 64269}},
-{16695, 18, 55441, {1, 1, 5, 15, 1, 19, 37, 131, 325, 441, 3, 4001, 6937, 9207, 27543, 30321, 37083, 241019}},
-{16696, 18, 55470, {1, 3, 7, 13, 7, 15, 9, 159, 97, 905, 557, 1913, 7325, 4057, 19461, 14277, 36873, 25619}},
-{16697, 18, 55535, {1, 3, 5, 7, 3, 51, 99, 9, 185, 227, 2041, 331, 3925, 12481, 17485, 37137, 3753, 125269}},
-{16698, 18, 55561, {1, 1, 7, 11, 31, 49, 89, 37, 49, 863, 833, 3263, 351, 6277, 23055, 49727, 25005, 161585}},
-{16699, 18, 55567, {1, 3, 5, 1, 9, 35, 89, 101, 117, 365, 1015, 1159, 4623, 4541, 6831, 28091, 10647, 221415}},
-{16700, 18, 55597, {1, 1, 5, 5, 13, 47, 125, 209, 199, 885, 927, 1411, 795, 8835, 28589, 48753, 27191, 53455}},
-{16701, 18, 55630, {1, 1, 5, 9, 7, 19, 3, 87, 157, 121, 1433, 1463, 3241, 5969, 203, 36723, 14779, 63949}},
-{16702, 18, 55648, {1, 1, 3, 9, 1, 47, 71, 113, 405, 561, 1149, 3599, 4173, 6819, 5493, 45987, 41521, 221503}},
-{16703, 18, 55653, {1, 3, 3, 1, 3, 55, 101, 103, 161, 549, 457, 2529, 2043, 8843, 5677, 7449, 45185, 178289}},
-{16704, 18, 55657, {1, 1, 1, 3, 31, 25, 1, 161, 7, 503, 641, 2221, 749, 1521, 6151, 19245, 55913, 80141}},
-{16705, 18, 55665, {1, 1, 1, 9, 3, 45, 73, 217, 249, 929, 163, 2139, 3921, 11223, 11161, 52697, 89633, 14243}},
-{16706, 18, 55678, {1, 1, 7, 15, 17, 41, 5, 119, 211, 53, 985, 2679, 679, 9349, 25577, 26947, 35141, 93999}},
-{16707, 18, 55684, {1, 3, 1, 15, 17, 43, 51, 15, 363, 615, 889, 195, 6279, 15477, 31545, 50941, 119711, 66535}},
-{16708, 18, 55691, {1, 1, 1, 13, 7, 11, 17, 127, 131, 759, 739, 161, 5937, 13611, 31757, 10681, 101357, 82873}},
-{16709, 18, 55693, {1, 3, 5, 7, 21, 63, 75, 33, 233, 981, 589, 3409, 3523, 1871, 8919, 38513, 32825, 56935}},
-{16710, 18, 55702, {1, 3, 5, 3, 9, 9, 85, 221, 203, 727, 1035, 1069, 2409, 2687, 235, 23395, 64163, 193235}},
-{16711, 18, 55708, {1, 3, 3, 7, 1, 35, 119, 175, 203, 819, 207, 2283, 4175, 3581, 11647, 43073, 104573, 86607}},
-{16712, 18, 55715, {1, 3, 3, 15, 11, 63, 59, 153, 279, 779, 261, 3317, 7671, 11727, 19381, 33227, 79331, 187227}},
-{16713, 18, 55739, {1, 1, 3, 1, 7, 1, 115, 15, 235, 9, 1877, 1911, 1089, 9939, 9537, 39563, 95327, 70323}},
-{16714, 18, 55761, {1, 1, 5, 7, 25, 61, 63, 145, 425, 617, 1813, 3255, 6797, 16019, 18849, 44191, 69877, 179933}},
-{16715, 18, 55767, {1, 1, 3, 13, 17, 45, 69, 247, 27, 367, 871, 1185, 895, 7991, 8145, 22869, 97609, 14673}},
-{16716, 18, 55768, {1, 3, 3, 11, 19, 41, 99, 213, 159, 803, 121, 1197, 2849, 15191, 15603, 52445, 105077, 128231}},
-{16717, 18, 55774, {1, 3, 1, 11, 21, 61, 117, 167, 437, 447, 419, 1673, 755, 15331, 29819, 16099, 130773, 177547}},
-{16718, 18, 55787, {1, 3, 7, 7, 1, 15, 79, 109, 351, 71, 985, 89, 7517, 4175, 30533, 52125, 100863, 186477}},
-{16719, 18, 55811, {1, 1, 3, 1, 15, 1, 103, 65, 511, 241, 1279, 3233, 7141, 255, 10925, 28271, 56151, 252121}},
-{16720, 18, 55835, {1, 1, 1, 13, 17, 49, 59, 93, 19, 343, 979, 865, 3447, 4595, 3067, 26807, 98915, 126237}},
-{16721, 18, 55894, {1, 3, 3, 5, 17, 5, 91, 199, 191, 775, 233, 919, 277, 3485, 9231, 37025, 23493, 186745}},
-{16722, 18, 55897, {1, 3, 1, 1, 11, 5, 103, 187, 85, 47, 1111, 883, 6155, 15315, 9041, 58275, 75037, 7773}},
-{16723, 18, 55904, {1, 3, 1, 3, 19, 5, 7, 211, 481, 713, 383, 1203, 6089, 15817, 31577, 7283, 25457, 101455}},
-{16724, 18, 55931, {1, 3, 5, 7, 21, 9, 59, 127, 375, 477, 721, 3931, 7089, 9079, 5015, 62019, 113747, 36055}},
-{16725, 18, 55950, {1, 3, 7, 13, 3, 17, 47, 177, 103, 535, 1787, 509, 5253, 2857, 13421, 19875, 37397, 251353}},
-{16726, 18, 55961, {1, 1, 5, 7, 19, 31, 41, 93, 301, 45, 251, 2691, 4657, 2627, 17321, 24627, 80221, 117191}},
-{16727, 18, 55973, {1, 3, 5, 7, 5, 31, 27, 3, 463, 549, 1669, 499, 815, 4091, 7049, 60957, 102849, 235617}},
-{16728, 18, 56078, {1, 3, 5, 1, 21, 31, 57, 201, 503, 977, 893, 3927, 1605, 8265, 5137, 51009, 89375, 237909}},
-{16729, 18, 56099, {1, 3, 3, 1, 27, 5, 11, 81, 445, 229, 5, 543, 3397, 12961, 31911, 36945, 59485, 305}},
-{16730, 18, 56105, {1, 1, 5, 13, 31, 63, 39, 171, 243, 39, 1147, 459, 7215, 14603, 20625, 47369, 121495, 237741}},
-{16731, 18, 56119, {1, 3, 3, 13, 15, 63, 39, 23, 305, 685, 1885, 571, 2657, 16031, 24759, 10639, 25619, 246137}},
-{16732, 18, 56133, {1, 1, 1, 5, 19, 33, 5, 187, 167, 725, 1405, 511, 701, 13283, 3513, 16495, 8755, 221751}},
-{16733, 18, 56168, {1, 1, 7, 11, 3, 27, 27, 237, 495, 637, 479, 3247, 3825, 2567, 12853, 52881, 34807, 161483}},
-{16734, 18, 56191, {1, 3, 3, 9, 23, 43, 101, 175, 19, 443, 787, 1053, 4113, 12777, 4615, 53115, 2873, 117383}},
-{16735, 18, 56202, {1, 3, 1, 13, 3, 23, 33, 93, 145, 937, 957, 2463, 827, 383, 16749, 61567, 10029, 188159}},
-{16736, 18, 56209, {1, 1, 7, 15, 21, 23, 3, 71, 323, 995, 645, 1189, 1029, 519, 3479, 13587, 95641, 215337}},
-{16737, 18, 56215, {1, 3, 7, 11, 9, 17, 101, 59, 421, 417, 797, 3089, 773, 15959, 18127, 13681, 104667, 217433}},
-{16738, 18, 56232, {1, 3, 5, 7, 31, 21, 9, 7, 377, 589, 1497, 939, 5389, 10997, 22291, 19639, 72187, 66193}},
-{16739, 18, 56240, {1, 1, 1, 13, 19, 1, 127, 185, 251, 167, 1289, 2715, 5885, 12715, 18261, 36861, 102721, 246917}},
-{16740, 18, 56260, {1, 1, 7, 1, 23, 41, 19, 151, 125, 465, 813, 1711, 7933, 13561, 29737, 59207, 62533, 124149}},
-{16741, 18, 56270, {1, 3, 5, 9, 7, 13, 17, 119, 425, 877, 1207, 2211, 2943, 13921, 28251, 44143, 112149, 152341}},
-{16742, 18, 56278, {1, 3, 5, 9, 15, 21, 87, 83, 77, 731, 91, 3091, 5687, 9647, 2037, 39031, 106583, 66533}},
-{16743, 18, 56281, {1, 1, 7, 9, 31, 49, 7, 119, 147, 599, 1191, 297, 1597, 10723, 16893, 47387, 106995, 165409}},
-{16744, 18, 56288, {1, 3, 3, 3, 3, 63, 11, 193, 241, 63, 1671, 2139, 5689, 13967, 9239, 7535, 34237, 140283}},
-{16745, 18, 56303, {1, 3, 5, 13, 9, 23, 65, 247, 473, 825, 109, 1897, 245, 10517, 8147, 25989, 96447, 118689}},
-{16746, 18, 56308, {1, 1, 3, 5, 27, 35, 65, 23, 159, 729, 189, 2661, 4245, 14377, 21043, 15551, 2717, 146949}},
-{16747, 18, 56312, {1, 1, 3, 13, 23, 5, 35, 63, 293, 347, 883, 149, 5145, 10821, 5813, 24183, 94711, 64787}},
-{16748, 18, 56320, {1, 1, 5, 3, 27, 3, 127, 141, 237, 535, 1509, 2755, 5843, 2379, 19413, 52345, 100247, 42571}},
-{16749, 18, 56326, {1, 3, 3, 9, 1, 55, 61, 105, 29, 1021, 1215, 2157, 7453, 4643, 26793, 33553, 2959, 51485}},
-{16750, 18, 56392, {1, 1, 3, 7, 31, 51, 59, 49, 321, 207, 415, 2115, 219, 5045, 31133, 17961, 130779, 28255}},
-{16751, 18, 56395, {1, 3, 7, 15, 9, 29, 31, 185, 111, 959, 7, 827, 7891, 5449, 22221, 49933, 2091, 194683}},
-{16752, 18, 56403, {1, 3, 7, 1, 11, 59, 75, 255, 387, 913, 423, 2915, 5079, 6363, 5175, 57977, 5559, 13257}},
-{16753, 18, 56419, {1, 1, 7, 1, 21, 3, 21, 13, 157, 3, 715, 3525, 7769, 5333, 25345, 53473, 44323, 203167}},
-{16754, 18, 56428, {1, 1, 7, 11, 31, 25, 55, 5, 169, 695, 1599, 2357, 1427, 14469, 15223, 34275, 42605, 23005}},
-{16755, 18, 56450, {1, 1, 1, 15, 19, 51, 117, 135, 297, 831, 329, 3793, 4673, 3795, 24185, 52971, 30423, 68771}},
-{16756, 18, 56452, {1, 1, 7, 5, 19, 33, 79, 77, 315, 29, 307, 1709, 3489, 14515, 12477, 58939, 53753, 165031}},
-{16757, 18, 56485, {1, 1, 7, 1, 27, 57, 119, 207, 355, 279, 1371, 3917, 2821, 5285, 12673, 28973, 54957, 94001}},
-{16758, 18, 56486, {1, 3, 7, 3, 19, 57, 53, 199, 485, 805, 301, 1337, 5993, 2187, 30573, 12045, 101205, 129841}},
-{16759, 18, 56492, {1, 1, 3, 9, 15, 45, 71, 119, 445, 759, 1361, 1299, 2927, 2343, 22085, 53733, 21241, 1553}},
-{16760, 18, 56498, {1, 3, 5, 3, 27, 11, 1, 239, 497, 343, 1989, 1463, 2473, 5191, 6271, 14129, 124453, 96817}},
-{16761, 18, 56510, {1, 3, 5, 7, 27, 19, 123, 27, 483, 557, 1545, 1871, 1297, 587, 1067, 51259, 119231, 173659}},
-{16762, 18, 56512, {1, 3, 1, 1, 27, 45, 41, 113, 453, 553, 2019, 2039, 1709, 13017, 5497, 34459, 60295, 229405}},
-{16763, 18, 56524, {1, 3, 1, 11, 1, 57, 51, 125, 261, 915, 1673, 25, 529, 653, 17247, 64225, 98991, 248143}},
-{16764, 18, 56530, {1, 3, 5, 15, 25, 27, 31, 1, 463, 249, 113, 1955, 2223, 5463, 12281, 20843, 26495, 256759}},
-{16765, 18, 56545, {1, 1, 3, 11, 27, 33, 57, 205, 89, 435, 1983, 1165, 3843, 127, 30179, 63971, 10211, 105403}},
-{16766, 18, 56551, {1, 3, 3, 5, 21, 49, 35, 161, 273, 205, 41, 1881, 2013, 12549, 24859, 55711, 98235, 237281}},
-{16767, 18, 56565, {1, 3, 3, 1, 15, 35, 95, 1, 221, 675, 385, 2257, 2531, 2129, 12895, 11565, 125977, 51973}},
-{16768, 18, 56580, {1, 1, 1, 15, 19, 61, 35, 55, 9, 721, 499, 2577, 3001, 14861, 22293, 56195, 72855, 166703}},
-{16769, 18, 56587, {1, 1, 1, 7, 5, 25, 59, 175, 81, 989, 935, 2579, 8183, 1109, 4645, 53753, 115795, 105091}},
-{16770, 18, 56589, {1, 3, 3, 13, 7, 55, 7, 113, 197, 763, 1747, 3291, 1109, 4391, 18257, 28563, 97413, 5847}},
-{16771, 18, 56592, {1, 1, 1, 7, 23, 55, 91, 83, 479, 305, 843, 2055, 3405, 15243, 31551, 5275, 8651, 66915}},
-{16772, 18, 56611, {1, 3, 7, 9, 3, 19, 83, 229, 235, 903, 1495, 1033, 2729, 14927, 11847, 22979, 13905, 84413}},
-{16773, 18, 56623, {1, 3, 3, 13, 27, 37, 83, 193, 475, 439, 745, 757, 7359, 6683, 5839, 50765, 6933, 117411}},
-{16774, 18, 56635, {1, 3, 5, 11, 31, 25, 33, 77, 113, 815, 123, 2721, 2133, 8995, 15237, 54565, 5155, 51235}},
-{16775, 18, 56646, {1, 3, 3, 7, 15, 31, 73, 91, 379, 39, 913, 53, 41, 1059, 25883, 11769, 63015, 48125}},
-{16776, 18, 56660, {1, 1, 5, 5, 5, 13, 81, 169, 71, 529, 1429, 2101, 4069, 5509, 30283, 40625, 103673, 183243}},
-{16777, 18, 56680, {1, 3, 3, 5, 23, 39, 39, 237, 445, 567, 343, 2521, 2287, 1851, 2315, 59979, 5015, 243349}},
-{16778, 18, 56686, {1, 1, 7, 1, 1, 51, 89, 229, 187, 207, 245, 3521, 2987, 4347, 6997, 62565, 54397, 140473}},
-{16779, 18, 56716, {1, 3, 1, 5, 7, 59, 45, 161, 457, 655, 1591, 215, 2213, 15101, 14791, 40397, 95811, 126291}},
-{16780, 18, 56749, {1, 1, 3, 1, 5, 23, 7, 199, 143, 561, 1669, 17, 8109, 11003, 4535, 8593, 112021, 223153}},
-{16781, 18, 56790, {1, 3, 5, 9, 3, 37, 111, 15, 235, 697, 385, 2197, 909, 1247, 26199, 50661, 100643, 122577}},
-{16782, 18, 56809, {1, 3, 5, 11, 23, 53, 95, 75, 463, 137, 1511, 3373, 3071, 547, 22399, 51891, 9123, 240925}},
-{16783, 18, 56869, {1, 3, 7, 3, 21, 35, 69, 197, 371, 15, 185, 3539, 29, 15071, 17069, 34669, 37023, 189385}},
-{16784, 18, 56884, {1, 1, 1, 15, 5, 21, 7, 5, 201, 881, 841, 827, 503, 3545, 17771, 64481, 65105, 209947}},
-{16785, 18, 56887, {1, 1, 1, 5, 3, 31, 83, 201, 455, 169, 1797, 1769, 1999, 8629, 14313, 16851, 64955, 180631}},
-{16786, 18, 56893, {1, 1, 5, 5, 1, 35, 49, 61, 499, 619, 1509, 3015, 237, 8979, 3471, 11513, 80193, 24135}},
-{16787, 18, 56906, {1, 3, 3, 9, 25, 29, 111, 19, 339, 739, 1751, 2671, 5399, 5965, 3943, 45577, 70605, 203117}},
-{16788, 18, 56932, {1, 3, 3, 7, 3, 9, 15, 147, 177, 545, 161, 2211, 4653, 15891, 15939, 19153, 77827, 245787}},
-{16789, 18, 56959, {1, 1, 1, 1, 25, 47, 37, 159, 273, 825, 1037, 2047, 7149, 5517, 699, 49687, 110115, 159475}},
-{16790, 18, 56965, {1, 3, 1, 7, 7, 55, 77, 231, 197, 381, 2013, 2421, 7551, 9955, 21031, 11365, 48271, 190147}},
-{16791, 18, 56983, {1, 1, 5, 9, 25, 1, 81, 145, 215, 427, 905, 2307, 6149, 12777, 131, 57091, 106137, 24625}},
-{16792, 18, 57018, {1, 3, 1, 13, 13, 63, 103, 245, 275, 745, 841, 2993, 2083, 8903, 4499, 55979, 22323, 244447}},
-{16793, 18, 57023, {1, 1, 5, 5, 15, 11, 59, 181, 191, 219, 599, 59, 1079, 4445, 16537, 31127, 103257, 233855}},
-{16794, 18, 57025, {1, 3, 7, 9, 9, 37, 109, 41, 145, 1001, 609, 551, 6843, 13791, 15103, 27851, 7693, 145207}},
-{16795, 18, 57032, {1, 3, 1, 9, 3, 35, 63, 219, 49, 567, 1537, 1327, 6487, 16039, 26019, 13851, 116929, 175121}},
-{16796, 18, 57040, {1, 3, 7, 15, 17, 31, 27, 91, 241, 229, 485, 2601, 3859, 12609, 19847, 31939, 50815, 235529}},
-{16797, 18, 57046, {1, 1, 5, 15, 27, 31, 3, 47, 69, 427, 95, 1445, 1223, 2953, 32343, 6841, 67851, 79561}},
-{16798, 18, 57071, {1, 3, 5, 13, 13, 37, 19, 127, 259, 139, 1597, 651, 4845, 6413, 18205, 56005, 32107, 140783}},
-{16799, 18, 57091, {1, 1, 7, 5, 15, 23, 81, 195, 127, 113, 499, 733, 5907, 12107, 18105, 28113, 16111, 152327}},
-{16800, 18, 57094, {1, 1, 5, 15, 9, 49, 109, 181, 187, 591, 1625, 3641, 313, 1225, 11725, 9047, 30351, 124301}},
-{16801, 18, 57108, {1, 3, 1, 1, 9, 45, 103, 219, 155, 805, 1775, 759, 1687, 11415, 21623, 37831, 18995, 21667}},
-{16802, 18, 57122, {1, 3, 3, 5, 25, 13, 11, 37, 489, 935, 373, 811, 5045, 3615, 2111, 22909, 117155, 69483}},
-{16803, 18, 57127, {1, 3, 3, 5, 9, 45, 71, 87, 265, 93, 161, 2983, 1023, 3633, 5965, 9499, 35653, 219257}},
-{16804, 18, 57168, {1, 1, 5, 13, 21, 27, 101, 231, 85, 469, 1023, 3735, 5093, 253, 22585, 61975, 81041, 4175}},
-{16805, 18, 57183, {1, 3, 1, 7, 5, 41, 105, 153, 391, 5, 1917, 331, 7679, 14359, 13177, 40755, 78669, 133527}},
-{16806, 18, 57184, {1, 3, 3, 15, 21, 61, 87, 63, 227, 195, 1095, 1629, 7787, 5887, 20855, 30203, 61973, 30627}},
-{16807, 18, 57193, {1, 3, 1, 15, 31, 41, 125, 223, 201, 717, 1309, 595, 5333, 10585, 32525, 8597, 92637, 111073}},
-{16808, 18, 57202, {1, 3, 5, 3, 21, 29, 39, 105, 275, 515, 503, 79, 6715, 14203, 14035, 20871, 122417, 243167}},
-{16809, 18, 57235, {1, 3, 7, 5, 29, 41, 3, 89, 165, 879, 773, 3989, 3945, 4771, 2809, 59105, 37177, 193887}},
-{16810, 18, 57237, {1, 3, 3, 3, 27, 1, 91, 191, 135, 257, 527, 2971, 7117, 6013, 8735, 52363, 110617, 96959}},
-{16811, 18, 57251, {1, 3, 7, 9, 3, 63, 67, 67, 231, 23, 1539, 771, 1485, 4331, 19231, 50539, 15081, 75945}},
-{16812, 18, 57289, {1, 3, 3, 11, 29, 11, 77, 67, 497, 861, 21, 2939, 2463, 14435, 27399, 19733, 118207, 60909}},
-{16813, 18, 57349, {1, 1, 5, 5, 1, 11, 117, 55, 485, 877, 1213, 2231, 2613, 14027, 18491, 45431, 113303, 28457}},
-{16814, 18, 57359, {1, 3, 7, 1, 13, 49, 77, 59, 455, 251, 1033, 3451, 7641, 389, 3987, 62361, 90125, 94569}},
-{16815, 18, 57374, {1, 1, 7, 15, 3, 5, 45, 173, 343, 445, 1871, 2505, 1385, 2641, 21299, 35139, 61781, 101195}},
-{16816, 18, 57377, {1, 3, 1, 9, 25, 27, 89, 123, 473, 901, 1513, 2585, 5641, 13123, 22653, 32985, 15763, 9161}},
-{16817, 18, 57387, {1, 3, 3, 9, 29, 41, 5, 127, 489, 715, 1981, 3953, 3557, 10081, 31913, 52191, 118727, 4443}},
-{16818, 18, 57415, {1, 1, 5, 1, 19, 57, 125, 33, 253, 297, 265, 2249, 6859, 14971, 3519, 24783, 127491, 210441}},
-{16819, 18, 57440, {1, 1, 7, 7, 31, 1, 47, 175, 305, 933, 679, 317, 7511, 13219, 9509, 61183, 58907, 72905}},
-{16820, 18, 57446, {1, 1, 1, 7, 13, 49, 75, 85, 341, 911, 1217, 3631, 1849, 9715, 23193, 947, 106647, 180455}},
-{16821, 18, 57450, {1, 1, 7, 7, 1, 49, 91, 195, 329, 771, 607, 1707, 2723, 291, 21393, 6549, 31645, 151431}},
-{16822, 18, 57469, {1, 3, 7, 5, 17, 57, 7, 231, 247, 217, 1729, 3231, 7515, 15341, 18681, 21733, 28723, 228187}},
-{16823, 18, 57491, {1, 1, 5, 9, 5, 19, 121, 251, 43, 951, 957, 173, 4863, 5027, 6781, 29421, 4877, 47749}},
-{16824, 18, 57503, {1, 3, 7, 7, 11, 33, 107, 233, 329, 589, 869, 913, 7687, 13223, 27577, 24379, 13037, 214713}},
-{16825, 18, 57507, {1, 3, 7, 13, 1, 13, 121, 103, 387, 193, 543, 3085, 4323, 9885, 24499, 34985, 45763, 13107}},
-{16826, 18, 57542, {1, 1, 3, 15, 25, 63, 85, 41, 457, 779, 1199, 2235, 309, 2549, 3341, 36265, 17873, 32361}},
-{16827, 18, 57569, {1, 3, 3, 3, 15, 31, 11, 57, 499, 415, 1625, 1195, 6863, 6073, 25083, 57705, 76203, 130993}},
-{16828, 18, 57599, {1, 3, 5, 5, 21, 13, 43, 161, 255, 31, 1901, 3325, 3209, 9809, 8227, 9005, 57263, 95095}},
-{16829, 18, 57601, {1, 1, 3, 15, 13, 33, 5, 123, 291, 579, 1747, 3319, 7351, 1679, 11365, 26909, 74445, 139017}},
-{16830, 18, 57607, {1, 1, 3, 13, 17, 39, 1, 253, 487, 935, 1711, 1397, 503, 7817, 28509, 20665, 78551, 204319}},
-{16831, 18, 57608, {1, 1, 3, 1, 5, 39, 123, 105, 305, 77, 63, 3285, 7463, 11199, 647, 37757, 91083, 108325}},
-{16832, 18, 57625, {1, 1, 7, 5, 9, 49, 121, 155, 389, 119, 1327, 3583, 7715, 2705, 20047, 19151, 101455, 205263}},
-{16833, 18, 57644, {1, 1, 5, 7, 31, 23, 13, 109, 103, 41, 433, 3609, 4973, 11481, 8381, 4725, 113633, 134651}},
-{16834, 18, 57662, {1, 3, 7, 7, 25, 25, 107, 189, 89, 625, 187, 2185, 713, 10107, 11139, 63681, 97005, 79329}},
-{16835, 18, 57664, {1, 3, 1, 11, 3, 41, 43, 161, 337, 955, 1035, 451, 5989, 3593, 18087, 22667, 110213, 128545}},
-{16836, 18, 57674, {1, 1, 5, 1, 25, 31, 95, 113, 205, 565, 557, 3885, 7163, 10703, 27159, 11395, 117459, 52439}},
-{16837, 18, 57698, {1, 1, 1, 5, 27, 31, 39, 61, 323, 983, 1361, 2387, 5401, 8287, 17855, 49783, 65327, 202861}},
-{16838, 18, 57700, {1, 3, 5, 3, 31, 39, 105, 113, 183, 311, 667, 945, 3677, 14623, 27907, 16673, 77899, 182863}},
-{16839, 18, 57709, {1, 1, 5, 3, 17, 27, 99, 93, 81, 805, 1799, 2855, 6859, 3917, 26177, 22307, 59213, 210123}},
-{16840, 18, 57724, {1, 3, 5, 1, 19, 37, 51, 65, 495, 229, 229, 1283, 2967, 5329, 24339, 58739, 23145, 7033}},
-{16841, 18, 57728, {1, 3, 3, 15, 11, 51, 121, 41, 75, 845, 1771, 3625, 6137, 3463, 11767, 45181, 70907, 42771}},
-{16842, 18, 57740, {1, 3, 7, 9, 15, 25, 55, 219, 265, 655, 167, 1247, 5409, 5623, 21045, 12333, 25799, 218601}},
-{16843, 18, 57745, {1, 3, 3, 13, 31, 39, 77, 155, 471, 969, 755, 2745, 3057, 3621, 32423, 48687, 9409, 90997}},
-{16844, 18, 57751, {1, 1, 3, 15, 27, 1, 77, 231, 147, 235, 2027, 4045, 7431, 14655, 6361, 43155, 9839, 161713}},
-{16845, 18, 57774, {1, 3, 7, 5, 25, 19, 25, 75, 415, 931, 457, 3691, 687, 4849, 15469, 42871, 37949, 74163}},
-{16846, 18, 57782, {1, 3, 5, 9, 17, 19, 29, 117, 387, 1021, 1159, 2467, 2585, 2563, 9155, 44763, 93319, 6321}},
-{16847, 18, 57796, {1, 3, 5, 7, 25, 33, 127, 175, 143, 705, 539, 2563, 945, 11369, 19971, 19019, 116195, 84121}},
-{16848, 18, 57803, {1, 3, 7, 7, 5, 55, 29, 1, 419, 715, 1275, 2983, 7853, 12245, 32109, 27371, 123547, 82723}},
-{16849, 18, 57823, {1, 1, 1, 13, 3, 29, 31, 213, 195, 609, 1465, 1711, 6747, 13309, 1131, 3151, 48779, 91571}},
-{16850, 18, 57863, {1, 1, 5, 3, 17, 7, 103, 7, 217, 87, 1641, 833, 4551, 14205, 15119, 6711, 111273, 200545}},
-{16851, 18, 57894, {1, 3, 1, 5, 3, 39, 99, 15, 433, 895, 165, 4049, 3183, 4385, 24695, 40009, 67151, 156643}},
-{16852, 18, 57925, {1, 1, 7, 3, 29, 9, 15, 27, 109, 1019, 327, 2837, 5297, 12455, 2355, 37703, 122995, 177871}},
-{16853, 18, 57971, {1, 1, 5, 15, 29, 5, 121, 117, 31, 155, 1027, 1105, 8057, 8677, 9523, 3019, 98801, 15539}},
-{16854, 18, 58013, {1, 3, 7, 3, 1, 1, 37, 67, 471, 317, 1571, 2801, 7383, 4339, 8095, 45685, 95885, 39577}},
-{16855, 18, 58020, {1, 3, 7, 13, 17, 13, 91, 79, 49, 321, 1235, 311, 129, 6537, 6643, 25813, 48251, 138823}},
-{16856, 18, 58032, {1, 1, 5, 3, 21, 19, 67, 61, 153, 611, 1819, 3755, 5959, 3419, 6117, 1159, 68925, 146199}},
-{16857, 18, 58038, {1, 1, 7, 9, 23, 3, 7, 13, 429, 463, 653, 3461, 6337, 4511, 18097, 44837, 99845, 37101}},
-{16858, 18, 58061, {1, 3, 5, 13, 9, 5, 123, 199, 83, 409, 1391, 1567, 7327, 8173, 30971, 18241, 7755, 185375}},
-{16859, 18, 58069, {1, 3, 1, 7, 19, 51, 51, 23, 85, 923, 1969, 2329, 7343, 12489, 16135, 64783, 117063, 141071}},
-{16860, 18, 58080, {1, 3, 1, 3, 23, 29, 5, 77, 207, 351, 367, 2097, 2639, 9255, 21971, 64167, 98069, 81153}},
-{16861, 18, 58089, {1, 1, 7, 15, 27, 1, 83, 255, 47, 935, 567, 3573, 3629, 5833, 483, 1001, 9337, 119847}},
-{16862, 18, 58107, {1, 3, 7, 11, 31, 53, 25, 35, 463, 51, 401, 3279, 7709, 11265, 17905, 40423, 26277, 43355}},
-{16863, 18, 58121, {1, 1, 7, 5, 9, 15, 73, 217, 239, 405, 1651, 2131, 6791, 11241, 21717, 7393, 77251, 28131}},
-{16864, 18, 58130, {1, 3, 5, 3, 13, 43, 115, 159, 215, 811, 1349, 2941, 2073, 1821, 6891, 17285, 72027, 137849}},
-{16865, 18, 58146, {1, 3, 3, 3, 15, 11, 29, 53, 307, 409, 1069, 3713, 3205, 6185, 2565, 14973, 46149, 162527}},
-{16866, 18, 58190, {1, 1, 3, 15, 21, 39, 61, 209, 211, 123, 697, 2285, 859, 2501, 5847, 56449, 106575, 261069}},
-{16867, 18, 58195, {1, 3, 3, 5, 25, 21, 39, 131, 189, 747, 1499, 1865, 3369, 9161, 12543, 63155, 70083, 69441}},
-{16868, 18, 58202, {1, 3, 1, 15, 31, 43, 127, 57, 169, 109, 979, 1399, 3065, 5865, 16891, 56003, 14319, 94109}},
-{16869, 18, 58237, {1, 1, 1, 13, 23, 57, 13, 239, 139, 41, 1959, 429, 209, 543, 21297, 15343, 16521, 52305}},
-{16870, 18, 58253, {1, 1, 7, 1, 17, 1, 115, 139, 93, 123, 867, 3257, 8135, 12089, 1503, 33287, 79283, 151419}},
-{16871, 18, 58299, {1, 3, 7, 7, 27, 17, 15, 253, 89, 959, 597, 2193, 3505, 13865, 2179, 58711, 114615, 15227}},
-{16872, 18, 58302, {1, 3, 7, 5, 1, 5, 105, 241, 361, 229, 1069, 3815, 1409, 4909, 31785, 46555, 123523, 53259}},
-{16873, 18, 58327, {1, 1, 5, 5, 15, 49, 13, 195, 467, 285, 1405, 3011, 2069, 8331, 13953, 31107, 46581, 154615}},
-{16874, 18, 58328, {1, 3, 5, 7, 21, 23, 17, 17, 345, 369, 1521, 3755, 2165, 15387, 2851, 11115, 60483, 236049}},
-{16875, 18, 58364, {1, 3, 3, 1, 5, 41, 53, 239, 127, 237, 609, 927, 3787, 5059, 1865, 52991, 56229, 102093}},
-{16876, 18, 58367, {1, 1, 7, 5, 23, 7, 15, 199, 325, 695, 1525, 3435, 3997, 11577, 22985, 57713, 94309, 218433}},
-{16877, 18, 58375, {1, 3, 3, 5, 25, 25, 61, 99, 237, 447, 1905, 783, 5239, 11415, 16833, 27815, 115539, 161111}},
-{16878, 18, 58394, {1, 1, 5, 9, 31, 49, 55, 199, 159, 751, 849, 1045, 5485, 8883, 8549, 11735, 35983, 161067}},
-{16879, 18, 58405, {1, 1, 5, 9, 23, 51, 79, 171, 87, 493, 1911, 3867, 3435, 493, 16639, 64085, 97797, 244959}},
-{16880, 18, 58417, {1, 1, 5, 11, 29, 33, 15, 107, 283, 545, 1995, 995, 7181, 3581, 8621, 42391, 117997, 397}},
-{16881, 18, 58424, {1, 3, 7, 13, 31, 25, 91, 75, 123, 451, 1023, 375, 4505, 13235, 8913, 34389, 77385, 168659}},
-{16882, 18, 58430, {1, 1, 3, 3, 3, 3, 85, 143, 173, 709, 1313, 593, 6931, 14609, 13803, 30305, 109089, 11473}},
-{16883, 18, 58452, {1, 3, 7, 5, 25, 45, 25, 223, 407, 597, 83, 2543, 3823, 13959, 9089, 28325, 29237, 57147}},
-{16884, 18, 58466, {1, 1, 1, 3, 25, 53, 57, 255, 231, 361, 109, 113, 6091, 13043, 28399, 29111, 57987, 137709}},
-{16885, 18, 58468, {1, 1, 1, 5, 11, 25, 53, 141, 275, 237, 1427, 1691, 6043, 8951, 10683, 17477, 117645, 89007}},
-{16886, 18, 58495, {1, 3, 3, 13, 7, 23, 73, 213, 285, 667, 1765, 1545, 1401, 12483, 6349, 47205, 25791, 16749}},
-{16887, 18, 58501, {1, 1, 1, 15, 31, 45, 105, 249, 385, 607, 723, 745, 7037, 15735, 3637, 29013, 127315, 165507}},
-{16888, 18, 58544, {1, 1, 7, 5, 21, 63, 95, 247, 161, 839, 939, 931, 4277, 7363, 8289, 55183, 122413, 152997}},
-{16889, 18, 58571, {1, 3, 7, 11, 15, 59, 91, 5, 209, 31, 1581, 979, 6289, 11443, 26641, 20183, 106907, 128647}},
-{16890, 18, 58609, {1, 1, 3, 15, 21, 33, 117, 89, 457, 405, 1971, 2211, 4379, 16189, 7933, 39351, 79813, 56373}},
-{16891, 18, 58610, {1, 3, 3, 9, 5, 9, 93, 75, 55, 271, 321, 3143, 3893, 2601, 26169, 35179, 43063, 156635}},
-{16892, 18, 58616, {1, 3, 3, 11, 29, 37, 95, 249, 221, 965, 423, 1637, 4663, 14839, 16757, 4261, 128453, 165593}},
-{16893, 18, 58619, {1, 3, 3, 7, 1, 55, 31, 235, 447, 839, 721, 1125, 6503, 4019, 23351, 37057, 96103, 143805}},
-{16894, 18, 58641, {1, 3, 7, 5, 31, 39, 7, 157, 469, 719, 1613, 395, 8133, 9753, 17323, 13849, 45409, 7601}},
-{16895, 18, 58642, {1, 3, 7, 7, 31, 37, 89, 215, 453, 659, 605, 3325, 987, 4611, 29667, 23229, 4201, 229675}},
-{16896, 18, 58648, {1, 1, 5, 5, 3, 3, 21, 249, 377, 343, 1751, 891, 5275, 14853, 32703, 51001, 6759, 162991}},
-{16897, 18, 58660, {1, 3, 1, 13, 11, 21, 55, 17, 495, 481, 1817, 919, 2495, 16367, 3343, 16997, 83437, 127791}},
-{16898, 18, 58675, {1, 3, 1, 1, 5, 57, 65, 223, 33, 491, 1953, 1521, 4903, 5007, 14583, 17321, 82231, 206299}},
-{16899, 18, 58678, {1, 3, 7, 11, 21, 45, 55, 141, 185, 379, 851, 885, 3385, 10311, 701, 2983, 71045, 171525}},
-{16900, 18, 58690, {1, 3, 7, 3, 29, 1, 53, 139, 7, 985, 291, 3949, 1163, 14637, 363, 59679, 121571, 121081}},
-{16901, 18, 58735, {1, 3, 7, 1, 31, 1, 111, 19, 421, 917, 1529, 1361, 4461, 12457, 9791, 19985, 77283, 117059}},
-{16902, 18, 58760, {1, 3, 1, 5, 7, 55, 93, 243, 477, 193, 1983, 489, 3735, 1391, 24035, 36395, 49101, 175861}},
-{16903, 18, 58766, {1, 1, 1, 11, 3, 25, 69, 167, 351, 193, 1299, 617, 7455, 2545, 18359, 9951, 119513, 128139}},
-{16904, 18, 58799, {1, 3, 3, 7, 5, 23, 101, 47, 385, 591, 345, 3501, 531, 3277, 28945, 18695, 58587, 87221}},
-{16905, 18, 58825, {1, 1, 3, 3, 29, 47, 5, 91, 365, 1, 2015, 323, 1601, 10615, 28975, 60263, 4813, 143351}},
-{16906, 18, 58836, {1, 3, 1, 7, 25, 43, 65, 211, 91, 759, 985, 3675, 5701, 4373, 27781, 51949, 40667, 102665}},
-{16907, 18, 58855, {1, 3, 3, 5, 3, 43, 91, 33, 247, 593, 849, 1955, 7769, 2307, 2877, 26037, 28907, 211021}},
-{16908, 18, 58864, {1, 3, 5, 15, 29, 29, 85, 97, 99, 979, 2033, 1415, 2955, 15733, 5567, 6241, 100195, 89077}},
-{16909, 18, 58910, {1, 3, 7, 13, 13, 19, 121, 211, 381, 73, 1131, 1881, 1693, 7873, 27557, 201, 24997, 202471}},
-{16910, 18, 58937, {1, 3, 1, 15, 15, 33, 11, 99, 479, 271, 1873, 1117, 3559, 6605, 15995, 44805, 12465, 71933}},
-{16911, 18, 58943, {1, 3, 5, 3, 19, 61, 15, 55, 423, 431, 1321, 3345, 1633, 4587, 24909, 54985, 31831, 181083}},
-{16912, 18, 58952, {1, 1, 3, 5, 29, 43, 49, 205, 415, 907, 1651, 57, 3043, 10763, 16255, 9567, 59453, 135637}},
-{16913, 18, 58965, {1, 3, 3, 1, 17, 11, 29, 33, 293, 203, 1687, 1565, 6131, 5435, 29023, 28425, 102151, 251913}},
-{16914, 18, 58988, {1, 1, 5, 7, 9, 9, 43, 191, 269, 681, 607, 3045, 2799, 14919, 8083, 57781, 19345, 49365}},
-{16915, 18, 58994, {1, 1, 5, 13, 11, 53, 67, 127, 117, 395, 575, 1651, 2601, 15019, 21413, 34433, 66847, 84159}},
-{16916, 18, 58999, {1, 3, 5, 5, 15, 59, 33, 41, 301, 699, 1479, 2285, 1813, 2459, 4775, 53213, 26039, 223155}},
-{16917, 18, 59006, {1, 3, 1, 15, 17, 57, 5, 211, 357, 175, 945, 3625, 3943, 12871, 26805, 29305, 8839, 107837}},
-{16918, 18, 59029, {1, 3, 5, 15, 21, 41, 105, 229, 265, 777, 2047, 767, 2901, 8873, 7631, 18545, 86697, 252965}},
-{16919, 18, 59033, {1, 1, 5, 11, 31, 63, 115, 119, 271, 921, 1221, 3341, 6083, 4293, 28581, 57323, 33889, 112577}},
-{16920, 18, 59069, {1, 1, 5, 5, 31, 21, 119, 93, 287, 139, 451, 2535, 3925, 10671, 21279, 55071, 76127, 248203}},
-{16921, 18, 59096, {1, 3, 7, 11, 19, 61, 61, 53, 203, 181, 963, 3581, 519, 14679, 7717, 31981, 128709, 197269}},
-{16922, 18, 59106, {1, 1, 1, 13, 25, 23, 89, 95, 221, 803, 1433, 3617, 3217, 2033, 7859, 14279, 107239, 5139}},
-{16923, 18, 59123, {1, 3, 7, 3, 29, 41, 87, 21, 71, 959, 1149, 2961, 7471, 11665, 16037, 5791, 110155, 35365}},
-{16924, 18, 59130, {1, 1, 1, 11, 21, 49, 101, 45, 311, 529, 1301, 1377, 983, 3937, 6967, 8413, 33511, 9617}},
-{16925, 18, 59152, {1, 3, 3, 5, 15, 41, 107, 49, 409, 537, 289, 3351, 5307, 16221, 907, 39847, 61579, 161487}},
-{16926, 18, 59162, {1, 1, 3, 11, 5, 49, 71, 107, 431, 469, 453, 1367, 7811, 10485, 3861, 62797, 82025, 253785}},
-{16927, 18, 59180, {1, 1, 3, 3, 27, 19, 89, 13, 445, 915, 1259, 1423, 3987, 3661, 18183, 18521, 18831, 191447}},
-{16928, 18, 59183, {1, 1, 7, 5, 13, 15, 9, 89, 129, 949, 1733, 245, 6815, 8477, 1273, 34737, 33027, 191415}},
-{16929, 18, 59195, {1, 1, 7, 15, 25, 63, 83, 195, 319, 987, 1395, 3559, 6287, 5139, 25967, 48711, 58467, 110983}},
-{16930, 18, 59205, {1, 1, 3, 9, 5, 3, 35, 171, 15, 883, 915, 2451, 871, 11741, 32715, 33475, 81711, 259157}},
-{16931, 18, 59210, {1, 1, 7, 13, 23, 63, 33, 11, 117, 351, 1701, 671, 6753, 5, 9477, 54701, 65507, 242621}},
-{16932, 18, 59217, {1, 3, 7, 11, 21, 37, 127, 143, 369, 819, 1369, 93, 7009, 3773, 30153, 30181, 120783, 137857}},
-{16933, 18, 59218, {1, 3, 3, 7, 27, 61, 15, 141, 67, 815, 1449, 1129, 4703, 3811, 3067, 61697, 8881, 110957}},
-{16934, 18, 59236, {1, 1, 7, 13, 31, 21, 59, 75, 335, 851, 503, 251, 4869, 11789, 30871, 14641, 19319, 156843}},
-{16935, 18, 59267, {1, 3, 5, 5, 9, 41, 11, 67, 231, 945, 37, 2925, 5723, 9053, 13477, 59735, 75181, 60335}},
-{16936, 18, 59298, {1, 1, 5, 1, 13, 39, 81, 43, 363, 611, 1661, 3833, 7387, 10531, 21319, 55579, 102705, 103009}},
-{16937, 18, 59318, {1, 3, 1, 7, 23, 25, 67, 179, 327, 401, 1693, 1453, 4773, 6363, 27169, 49747, 29055, 49145}},
-{16938, 18, 59321, {1, 3, 5, 7, 13, 47, 5, 175, 369, 921, 507, 113, 6069, 10919, 11099, 19795, 95819, 52419}},
-{16939, 18, 59327, {1, 1, 1, 5, 5, 53, 93, 47, 75, 837, 109, 3691, 6961, 10715, 14269, 63791, 1941, 136899}},
-{16940, 18, 59354, {1, 1, 1, 3, 1, 63, 57, 117, 157, 327, 879, 2411, 3987, 15393, 8503, 29829, 77795, 121307}},
-{16941, 18, 59363, {1, 3, 5, 1, 25, 5, 47, 45, 433, 121, 607, 1233, 6433, 3031, 16369, 58589, 79357, 151353}},
-{16942, 18, 59377, {1, 1, 1, 1, 9, 15, 77, 163, 225, 445, 1479, 1267, 2571, 2661, 21489, 5433, 123969, 191967}},
-{16943, 18, 59389, {1, 1, 7, 1, 9, 49, 17, 19, 449, 113, 1289, 2335, 3309, 2595, 17819, 18481, 86605, 125911}},
-{16944, 18, 59403, {1, 1, 5, 11, 11, 23, 65, 147, 257, 625, 1901, 913, 5711, 8159, 16237, 25133, 100059, 11395}},
-{16945, 18, 59420, {1, 3, 7, 13, 5, 33, 89, 189, 171, 185, 751, 2915, 5025, 15981, 14853, 12229, 52829, 59953}},
-{16946, 18, 59444, {1, 3, 1, 13, 3, 37, 15, 87, 463, 655, 1927, 2705, 1885, 14801, 3491, 52835, 81761, 90273}},
-{16947, 18, 59471, {1, 1, 7, 3, 5, 15, 29, 255, 199, 225, 647, 3215, 6795, 3821, 31763, 31059, 65495, 89981}},
-{16948, 18, 59476, {1, 1, 7, 7, 9, 25, 11, 85, 111, 283, 507, 2077, 2993, 5415, 31785, 16495, 82361, 122105}},
-{16949, 18, 59483, {1, 1, 3, 11, 27, 21, 127, 175, 397, 419, 1115, 2285, 223, 3881, 4187, 53759, 115035, 181647}},
-{16950, 18, 59502, {1, 3, 7, 11, 27, 31, 29, 233, 137, 827, 1009, 3879, 7595, 12989, 27655, 8517, 28083, 214985}},
-{16951, 18, 59509, {1, 3, 5, 9, 25, 23, 85, 191, 475, 445, 621, 1341, 4045, 4299, 24933, 32765, 20219, 86949}},
-{16952, 18, 59538, {1, 3, 1, 5, 25, 35, 121, 33, 199, 405, 163, 3487, 1087, 743, 21989, 47273, 49221, 124831}},
-{16953, 18, 59556, {1, 1, 5, 1, 7, 3, 91, 15, 335, 351, 1311, 777, 4303, 7203, 19465, 9135, 32251, 69805}},
-{16954, 18, 59571, {1, 3, 3, 7, 23, 55, 73, 77, 189, 801, 1877, 1901, 2675, 1015, 3041, 35925, 125903, 126227}},
-{16955, 18, 59592, {1, 3, 3, 1, 1, 23, 105, 75, 435, 743, 651, 1045, 579, 13637, 14821, 62683, 95229, 156475}},
-{16956, 18, 59610, {1, 3, 3, 5, 1, 53, 89, 239, 439, 195, 189, 731, 1805, 15123, 23315, 47737, 29167, 112081}},
-{16957, 18, 59654, {1, 1, 5, 7, 31, 11, 119, 191, 155, 61, 247, 915, 5813, 995, 20093, 23379, 118969, 65001}},
-{16958, 18, 59677, {1, 3, 7, 3, 1, 61, 45, 85, 295, 269, 539, 1787, 6639, 11093, 11303, 18509, 77637, 200743}},
-{16959, 18, 59699, {1, 3, 1, 1, 13, 17, 75, 51, 199, 151, 1529, 1443, 4983, 6723, 6071, 34711, 39159, 5441}},
-{16960, 18, 59716, {1, 3, 3, 3, 31, 15, 91, 125, 261, 683, 1769, 1697, 2761, 11373, 13607, 24933, 19079, 55497}},
-{16961, 18, 59719, {1, 1, 1, 15, 21, 49, 117, 99, 29, 969, 463, 3869, 1251, 8815, 16443, 46861, 82839, 233325}},
-{16962, 18, 59737, {1, 3, 5, 3, 27, 39, 89, 225, 161, 63, 61, 2875, 4037, 10413, 5067, 27893, 78825, 250207}},
-{16963, 18, 59747, {1, 1, 1, 9, 13, 49, 93, 11, 23, 25, 2003, 57, 3065, 11241, 13935, 2969, 44235, 39287}},
-{16964, 18, 59789, {1, 3, 3, 9, 21, 5, 55, 247, 193, 523, 575, 1235, 3277, 5253, 5293, 7919, 7573, 168809}},
-{16965, 18, 59807, {1, 3, 1, 13, 29, 39, 43, 21, 511, 205, 303, 703, 3861, 2467, 3909, 31597, 51081, 9863}},
-{16966, 18, 59811, {1, 3, 7, 1, 25, 55, 11, 131, 5, 49, 371, 1683, 1907, 5661, 1015, 15171, 101477, 11221}},
-{16967, 18, 59818, {1, 3, 5, 5, 9, 15, 93, 245, 357, 703, 701, 3675, 4527, 9225, 16137, 55433, 81887, 99153}},
-{16968, 18, 59825, {1, 1, 3, 3, 11, 1, 39, 251, 291, 599, 643, 231, 4031, 7055, 99, 14039, 81811, 184251}},
-{16969, 18, 59826, {1, 3, 5, 13, 29, 55, 11, 117, 325, 401, 2013, 3235, 995, 9255, 2741, 8211, 71451, 180619}},
-{16970, 18, 59832, {1, 1, 1, 5, 31, 41, 41, 175, 247, 3, 739, 1391, 3311, 5975, 16921, 4291, 75065, 161745}},
-{16971, 18, 59858, {1, 1, 7, 13, 23, 19, 13, 149, 203, 351, 2033, 1867, 3871, 14437, 3793, 17399, 99577, 171605}},
-{16972, 18, 59860, {1, 1, 5, 11, 7, 9, 1, 195, 261, 977, 315, 3771, 1179, 16281, 20747, 56309, 108609, 209205}},
-{16973, 18, 59873, {1, 3, 3, 5, 19, 15, 123, 153, 325, 601, 393, 753, 93, 4803, 24343, 42645, 128209, 45773}},
-{16974, 18, 59876, {1, 3, 1, 13, 3, 29, 97, 95, 115, 539, 155, 2789, 1277, 13127, 20383, 52807, 97295, 54589}},
-{16975, 18, 59907, {1, 1, 1, 3, 25, 59, 27, 149, 365, 317, 773, 3379, 5931, 14637, 19881, 37283, 118027, 21557}},
-{16976, 18, 59928, {1, 3, 5, 3, 25, 11, 101, 221, 199, 689, 515, 2255, 6107, 6259, 2853, 19039, 117089, 107181}},
-{16977, 18, 59933, {1, 3, 5, 7, 29, 63, 19, 113, 249, 147, 737, 3959, 209, 7001, 24263, 20443, 99923, 145709}},
-{16978, 18, 59938, {1, 1, 5, 9, 25, 37, 69, 41, 87, 369, 1913, 2255, 7581, 5301, 25751, 24981, 1183, 171969}},
-{16979, 18, 59940, {1, 3, 3, 1, 9, 25, 55, 5, 267, 295, 43, 819, 4569, 7065, 31527, 57811, 48721, 107707}},
-{16980, 18, 59958, {1, 1, 7, 9, 19, 19, 1, 199, 371, 1003, 597, 2097, 4071, 6185, 879, 13545, 30033, 120313}},
-{16981, 18, 59984, {1, 1, 1, 7, 9, 11, 51, 155, 309, 493, 899, 3121, 2085, 10541, 21979, 4725, 70381, 69643}},
-{16982, 18, 60020, {1, 1, 1, 1, 13, 45, 123, 119, 459, 295, 1005, 4093, 393, 11063, 27235, 28209, 1671, 215619}},
-{16983, 18, 60024, {1, 1, 7, 13, 19, 25, 125, 255, 509, 529, 1577, 3221, 4051, 7697, 2065, 42597, 86295, 131719}},
-{16984, 18, 60033, {1, 3, 3, 9, 19, 13, 21, 199, 97, 949, 1297, 379, 1801, 13247, 22563, 49517, 22757, 87371}},
-{16985, 18, 60034, {1, 3, 3, 1, 17, 63, 109, 175, 301, 565, 1181, 465, 3457, 7175, 21225, 33149, 122169, 148043}},
-{16986, 18, 60063, {1, 1, 1, 1, 5, 7, 21, 251, 53, 369, 955, 583, 4703, 9729, 15853, 55701, 29317, 27}},
-{16987, 18, 60070, {1, 3, 3, 1, 31, 3, 53, 57, 231, 441, 109, 149, 8107, 2303, 29729, 42279, 46909, 209877}},
-{16988, 18, 60087, {1, 1, 1, 11, 23, 57, 63, 189, 259, 657, 1653, 1155, 2885, 3317, 22559, 3145, 19151, 172507}},
-{16989, 18, 60091, {1, 3, 7, 5, 31, 63, 103, 147, 287, 685, 1197, 99, 4907, 12335, 12001, 20303, 75503, 231259}},
-{16990, 18, 60105, {1, 3, 3, 13, 15, 33, 63, 11, 99, 299, 97, 2669, 3635, 9969, 1525, 36555, 85215, 86915}},
-{16991, 18, 60126, {1, 3, 7, 5, 25, 47, 25, 61, 227, 939, 1719, 245, 2389, 14663, 30671, 22667, 38873, 245509}},
-{16992, 18, 60132, {1, 1, 3, 5, 25, 15, 105, 203, 57, 961, 1941, 1241, 3163, 6203, 19631, 10383, 19235, 57569}},
-{16993, 18, 60154, {1, 1, 3, 9, 1, 35, 41, 3, 449, 87, 641, 269, 1529, 14559, 16571, 4863, 21625, 921}},
-{16994, 18, 60174, {1, 1, 7, 11, 25, 53, 85, 209, 181, 417, 1657, 2117, 4581, 7069, 15533, 64475, 82381, 146943}},
-{16995, 18, 60181, {1, 3, 1, 7, 17, 53, 5, 199, 347, 887, 1041, 595, 1843, 10931, 30559, 42849, 73723, 220473}},
-{16996, 18, 60198, {1, 3, 7, 7, 21, 53, 105, 21, 141, 575, 1965, 2187, 7293, 13675, 2471, 1259, 42485, 62911}},
-{16997, 18, 60212, {1, 1, 3, 9, 5, 27, 21, 101, 101, 71, 1215, 3235, 2451, 14835, 27817, 30079, 124301, 253691}},
-{16998, 18, 60247, {1, 1, 7, 1, 11, 37, 105, 127, 115, 157, 279, 2425, 2139, 131, 22717, 40803, 74867, 86021}},
-{16999, 18, 60254, {1, 1, 1, 7, 11, 59, 95, 61, 255, 523, 501, 2895, 7531, 8151, 18393, 42069, 120809, 236537}},
-{17000, 18, 60275, {1, 1, 1, 7, 17, 23, 31, 59, 377, 187, 873, 1565, 3459, 2975, 11633, 13247, 13095, 193803}},
-{17001, 18, 60284, {1, 3, 7, 1, 25, 3, 85, 5, 485, 451, 1385, 1663, 4825, 14019, 29437, 33717, 105343, 161335}},
-{17002, 18, 60317, {1, 1, 1, 3, 27, 43, 71, 167, 425, 579, 1739, 3557, 7403, 2023, 6533, 61177, 119273, 85229}},
-{17003, 18, 60318, {1, 1, 7, 3, 31, 37, 19, 213, 373, 505, 97, 3669, 7005, 2205, 26519, 61999, 18395, 25967}},
-{17004, 18, 60346, {1, 3, 3, 7, 29, 17, 9, 137, 265, 875, 887, 3029, 3295, 11619, 8357, 46241, 23543, 43191}},
-{17005, 18, 60360, {1, 1, 5, 1, 25, 43, 33, 133, 65, 7, 1581, 3577, 5997, 6129, 30649, 18923, 56459, 227869}},
-{17006, 18, 60380, {1, 1, 5, 13, 27, 45, 27, 111, 429, 565, 1449, 1475, 6613, 4469, 16083, 42349, 66843, 214875}},
-{17007, 18, 60389, {1, 3, 1, 1, 21, 21, 107, 7, 15, 675, 233, 4021, 1097, 1393, 6445, 3323, 102435, 249355}},
-{17008, 18, 60393, {1, 1, 5, 15, 17, 51, 99, 249, 437, 667, 1921, 2371, 3813, 10543, 19, 39079, 116825, 242821}},
-{17009, 18, 60401, {1, 1, 1, 1, 7, 15, 27, 29, 161, 37, 1847, 287, 4379, 1399, 24547, 60361, 68131, 232883}},
-{17010, 18, 60407, {1, 1, 3, 9, 17, 21, 41, 169, 61, 771, 241, 1435, 4151, 1789, 12195, 27239, 62371, 165145}},
-{17011, 18, 60408, {1, 3, 5, 15, 31, 19, 127, 181, 463, 183, 749, 253, 2403, 1363, 3965, 7953, 124025, 226691}},
-{17012, 18, 60462, {1, 1, 3, 7, 17, 57, 85, 89, 17, 33, 819, 2191, 1525, 15651, 23483, 26027, 86379, 40191}},
-{17013, 18, 60484, {1, 1, 5, 1, 9, 45, 65, 65, 359, 5, 531, 2581, 6313, 13219, 6005, 36215, 16275, 208253}},
-{17014, 18, 60505, {1, 3, 1, 1, 23, 15, 51, 43, 85, 461, 773, 219, 2681, 3377, 9797, 54469, 112871, 231533}},
-{17015, 18, 60521, {1, 3, 7, 7, 15, 9, 97, 115, 301, 493, 1085, 2021, 2305, 15003, 11381, 9339, 63015, 179115}},
-{17016, 18, 60527, {1, 3, 5, 3, 3, 61, 111, 103, 283, 7, 143, 353, 7815, 7901, 25795, 7577, 92991, 228315}},
-{17017, 18, 60532, {1, 1, 7, 13, 29, 3, 53, 105, 83, 531, 497, 729, 1375, 7063, 18655, 35219, 9671, 102913}},
-{17018, 18, 60545, {1, 1, 5, 15, 11, 7, 65, 31, 15, 921, 743, 1469, 5669, 5437, 20019, 28123, 5717, 6181}},
-{17019, 18, 60546, {1, 3, 3, 15, 19, 1, 3, 183, 315, 595, 1033, 3259, 7815, 8281, 32103, 8699, 59149, 56657}},
-{17020, 18, 60555, {1, 1, 1, 7, 9, 1, 87, 81, 267, 637, 1617, 2113, 487, 23, 11213, 29211, 92715, 177767}},
-{17021, 18, 60563, {1, 3, 5, 13, 29, 37, 31, 55, 343, 759, 813, 2945, 7189, 4821, 30661, 38373, 2793, 98683}},
-{17022, 18, 60586, {1, 3, 5, 7, 9, 43, 113, 145, 103, 303, 1065, 3781, 3527, 9449, 17355, 38301, 74859, 30735}},
-{17023, 18, 60626, {1, 1, 1, 1, 3, 53, 53, 27, 119, 701, 1777, 3959, 5911, 8473, 24997, 17557, 11593, 201381}},
-{17024, 18, 60637, {1, 3, 3, 9, 3, 3, 107, 115, 423, 531, 735, 931, 8053, 4661, 1919, 29551, 62515, 210255}},
-{17025, 18, 60665, {1, 1, 3, 9, 21, 21, 117, 67, 301, 49, 2025, 781, 7951, 15719, 27287, 34551, 115241, 243981}},
-{17026, 18, 60673, {1, 1, 7, 9, 9, 25, 87, 229, 375, 353, 445, 3169, 1865, 7305, 11175, 47081, 28609, 107301}},
-{17027, 18, 60685, {1, 3, 3, 11, 7, 31, 19, 177, 17, 535, 1353, 2587, 7723, 8039, 13607, 5017, 104937, 207761}},
-{17028, 18, 60703, {1, 1, 5, 3, 11, 27, 29, 193, 235, 435, 1451, 3487, 5749, 4825, 9487, 53933, 92061, 223305}},
-{17029, 18, 60734, {1, 3, 3, 3, 5, 5, 99, 237, 91, 945, 1373, 3303, 3079, 5345, 6843, 34131, 62851, 259561}},
-{17030, 18, 60742, {1, 1, 3, 7, 7, 25, 11, 27, 329, 37, 307, 771, 659, 13045, 25767, 18887, 54407, 251313}},
-{17031, 18, 60790, {1, 1, 1, 11, 29, 59, 37, 121, 281, 55, 495, 159, 3925, 4447, 14825, 24831, 103147, 211951}},
-{17032, 18, 60830, {1, 3, 3, 7, 23, 31, 59, 67, 303, 383, 1179, 2347, 4001, 14797, 14579, 55365, 112239, 65309}},
-{17033, 18, 60848, {1, 3, 3, 9, 15, 17, 61, 123, 339, 319, 765, 1517, 1269, 69, 9065, 32347, 21377, 38449}},
-{17034, 18, 60857, {1, 3, 5, 3, 7, 35, 71, 63, 251, 457, 351, 385, 4041, 11489, 14511, 11875, 45307, 205041}},
-{17035, 18, 60871, {1, 1, 1, 7, 1, 25, 115, 195, 41, 1001, 835, 767, 7991, 7475, 22397, 36899, 77255, 194827}},
-{17036, 18, 60875, {1, 3, 3, 11, 7, 49, 45, 13, 373, 167, 741, 2569, 3781, 1131, 2909, 40387, 77877, 201859}},
-{17037, 18, 60913, {1, 3, 5, 3, 17, 11, 123, 137, 65, 835, 1385, 1157, 7387, 12301, 5759, 13137, 30595, 50923}},
-{17038, 18, 60923, {1, 1, 5, 7, 1, 55, 57, 97, 377, 223, 115, 2515, 2565, 14965, 10485, 23957, 108239, 160707}},
-{17039, 18, 60972, {1, 3, 1, 9, 15, 17, 81, 65, 387, 275, 997, 1485, 4129, 999, 4915, 55867, 103799, 191829}},
-{17040, 18, 60989, {1, 1, 1, 5, 15, 5, 35, 167, 249, 419, 267, 503, 469, 3163, 19939, 65501, 88573, 11621}},
-{17041, 18, 61001, {1, 3, 3, 13, 7, 9, 101, 125, 371, 97, 1855, 1755, 4103, 12283, 18655, 5965, 17743, 254779}},
-{17042, 18, 61002, {1, 1, 3, 7, 13, 15, 119, 227, 451, 863, 1005, 491, 6515, 717, 12783, 14161, 106249, 185297}},
-{17043, 18, 61019, {1, 1, 7, 13, 17, 23, 95, 143, 133, 219, 897, 2291, 7469, 923, 22323, 60583, 2457, 197231}},
-{17044, 18, 61022, {1, 1, 1, 11, 3, 25, 115, 187, 319, 999, 867, 1725, 6969, 239, 2527, 55283, 91099, 252153}},
-{17045, 18, 61059, {1, 1, 7, 9, 3, 37, 107, 25, 425, 95, 631, 2831, 1265, 11509, 18865, 39791, 22281, 220517}},
-{17046, 18, 61065, {1, 3, 5, 1, 1, 47, 121, 173, 489, 241, 3, 3707, 7081, 5341, 23143, 7321, 30605, 191665}},
-{17047, 18, 61066, {1, 1, 7, 7, 7, 27, 23, 43, 145, 11, 1155, 691, 6993, 9509, 5991, 40705, 58215, 202915}},
-{17048, 18, 61071, {1, 3, 5, 1, 31, 1, 7, 189, 379, 431, 417, 3843, 3885, 3263, 16333, 58123, 68307, 33795}},
-{17049, 18, 61076, {1, 1, 5, 5, 19, 27, 19, 217, 509, 535, 287, 1637, 4829, 2665, 15393, 35185, 125335, 10909}},
-{17050, 18, 61141, {1, 3, 5, 7, 25, 13, 67, 243, 255, 1021, 1203, 821, 7811, 149, 26731, 12913, 18171, 101385}},
-{17051, 18, 61148, {1, 1, 1, 3, 25, 61, 59, 207, 449, 789, 1831, 1731, 513, 10099, 291, 1963, 100233, 21847}},
-{17052, 18, 61167, {1, 1, 7, 1, 27, 19, 45, 81, 479, 31, 707, 2669, 3589, 15411, 12089, 38235, 60897, 135451}},
-{17053, 18, 61190, {1, 3, 5, 15, 11, 3, 113, 169, 171, 21, 1291, 2031, 2023, 5783, 6137, 54637, 50247, 233753}},
-{17054, 18, 61218, {1, 1, 5, 1, 11, 13, 73, 97, 269, 801, 1015, 1329, 1779, 15225, 24251, 35191, 8619, 130993}},
-{17055, 18, 61247, {1, 1, 7, 9, 9, 19, 35, 255, 505, 513, 547, 405, 3065, 4965, 30877, 50091, 81319, 29273}},
-{17056, 18, 61256, {1, 1, 1, 9, 7, 61, 45, 75, 343, 911, 1683, 453, 1225, 10939, 19901, 63685, 123507, 252027}},
-{17057, 18, 61289, {1, 1, 5, 11, 21, 55, 37, 161, 143, 463, 1937, 3349, 2953, 14827, 7893, 26581, 128459, 72325}},
-{17058, 18, 61292, {1, 3, 5, 9, 31, 57, 115, 77, 225, 859, 621, 731, 5677, 759, 20773, 52285, 65555, 4303}},
-{17059, 18, 61307, {1, 1, 3, 15, 23, 15, 49, 171, 137, 449, 855, 565, 5579, 5957, 13643, 8979, 90327, 116349}},
-{17060, 18, 61319, {1, 1, 3, 5, 9, 13, 27, 43, 391, 595, 731, 101, 7121, 13555, 29181, 38273, 42309, 175297}},
-{17061, 18, 61353, {1, 1, 3, 11, 3, 59, 17, 143, 251, 47, 1391, 1297, 23, 15871, 13153, 44081, 65423, 54875}},
-{17062, 18, 61362, {1, 3, 7, 11, 25, 43, 3, 163, 273, 277, 755, 2743, 5909, 10841, 31331, 64131, 13945, 91557}},
-{17063, 18, 61379, {1, 3, 1, 13, 31, 35, 5, 165, 417, 623, 1083, 1221, 1051, 8917, 6725, 11385, 76315, 119837}},
-{17064, 18, 61382, {1, 1, 5, 3, 21, 53, 47, 247, 471, 877, 709, 2425, 3, 1963, 24331, 52151, 98859, 119033}},
-{17065, 18, 61433, {1, 1, 7, 3, 29, 29, 43, 59, 503, 891, 763, 2927, 1613, 9091, 10393, 36003, 61147, 3437}},
-{17066, 18, 61434, {1, 1, 5, 15, 27, 59, 73, 163, 425, 855, 349, 3451, 5779, 10523, 9103, 46477, 129873, 39091}},
-{17067, 18, 61454, {1, 3, 7, 15, 25, 45, 77, 171, 467, 1017, 1553, 1877, 5507, 3909, 12157, 60441, 98261, 37781}},
-{17068, 18, 61461, {1, 1, 7, 13, 13, 39, 99, 51, 197, 327, 1101, 2679, 8025, 11853, 7763, 62537, 96999, 88673}},
-{17069, 18, 61475, {1, 3, 1, 11, 5, 61, 29, 219, 471, 387, 319, 433, 5383, 3933, 27603, 61171, 104711, 233295}},
-{17070, 18, 61481, {1, 3, 5, 11, 15, 23, 91, 119, 207, 717, 1333, 783, 437, 13073, 10923, 27049, 87233, 174899}},
-{17071, 18, 61534, {1, 1, 1, 1, 13, 19, 109, 139, 183, 299, 1023, 3265, 5153, 6307, 27879, 55311, 95201, 19481}},
-{17072, 18, 61547, {1, 1, 5, 11, 13, 61, 81, 115, 53, 483, 693, 3527, 5033, 8527, 31345, 46155, 12403, 126815}},
-{17073, 18, 61564, {1, 3, 7, 3, 27, 7, 73, 227, 269, 683, 719, 763, 5417, 9523, 13625, 6945, 116225, 223093}},
-{17074, 18, 61568, {1, 3, 5, 9, 21, 51, 111, 157, 451, 247, 1375, 1631, 2783, 3371, 22713, 34153, 41949, 141351}},
-{17075, 18, 61588, {1, 1, 5, 1, 21, 19, 45, 69, 41, 453, 523, 3163, 7351, 4467, 18865, 35371, 129577, 78039}},
-{17076, 18, 61604, {1, 3, 5, 1, 29, 33, 13, 19, 341, 321, 117, 1187, 7021, 5785, 5553, 58055, 113557, 46957}},
-{17077, 18, 61626, {1, 1, 5, 5, 13, 59, 47, 59, 69, 125, 1491, 2813, 5005, 5973, 3145, 27579, 7763, 129949}},
-{17078, 18, 61645, {1, 1, 7, 11, 11, 7, 117, 235, 407, 749, 1925, 1735, 4499, 13027, 19355, 1981, 105657, 242853}},
-{17079, 18, 61646, {1, 1, 7, 1, 15, 19, 5, 247, 203, 707, 809, 2085, 5801, 9947, 569, 9883, 109861, 156751}},
-{17080, 18, 61654, {1, 3, 5, 3, 13, 59, 67, 181, 261, 873, 1589, 2249, 7213, 14625, 28403, 41101, 73439, 46873}},
-{17081, 18, 61663, {1, 1, 5, 7, 3, 63, 79, 115, 123, 485, 1373, 3781, 4315, 4627, 29003, 64101, 67521, 184053}},
-{17082, 18, 61669, {1, 1, 3, 9, 11, 57, 93, 243, 505, 189, 449, 643, 5267, 7447, 32265, 44095, 63015, 36905}},
-{17083, 18, 61702, {1, 3, 7, 13, 25, 59, 31, 93, 401, 41, 183, 759, 2473, 8705, 8211, 13543, 59749, 235217}},
-{17084, 18, 61705, {1, 1, 5, 5, 29, 3, 65, 133, 325, 239, 649, 3225, 4095, 11691, 4479, 15419, 100551, 261981}},
-{17085, 18, 61714, {1, 3, 7, 1, 17, 11, 63, 97, 431, 161, 1437, 3679, 1643, 10583, 20731, 45919, 94093, 147067}},
-{17086, 18, 61739, {1, 1, 7, 1, 25, 13, 63, 155, 221, 345, 189, 1199, 5465, 14767, 26263, 54093, 23697, 71231}},
-{17087, 18, 61744, {1, 1, 7, 3, 3, 19, 23, 75, 381, 339, 1989, 1137, 6449, 1437, 32279, 17195, 117423, 259311}},
-{17088, 18, 61749, {1, 3, 5, 3, 27, 45, 117, 113, 129, 585, 2019, 807, 5573, 7407, 9957, 8741, 52333, 115607}},
-{17089, 18, 61776, {1, 1, 3, 7, 9, 5, 77, 9, 417, 725, 429, 1657, 5445, 1901, 28745, 26807, 111743, 169739}},
-{17090, 18, 61786, {1, 3, 1, 5, 7, 63, 51, 183, 117, 383, 435, 755, 7849, 5997, 32697, 5789, 5189, 80645}},
-{17091, 18, 61822, {1, 1, 3, 15, 5, 47, 105, 175, 41, 275, 1441, 3183, 3651, 9561, 5749, 20431, 45969, 59473}},
-{17092, 18, 61826, {1, 1, 1, 11, 13, 35, 19, 129, 125, 35, 339, 3099, 5337, 15605, 10213, 1171, 61869, 216681}},
-{17093, 18, 61862, {1, 3, 7, 1, 7, 25, 23, 9, 431, 73, 1803, 3969, 7853, 12845, 8075, 14553, 124825, 50561}},
-{17094, 18, 61865, {1, 1, 1, 7, 29, 21, 79, 247, 313, 143, 59, 2689, 5643, 827, 26597, 56423, 107903, 180809}},
-{17095, 18, 61868, {1, 3, 7, 1, 3, 3, 25, 39, 269, 529, 67, 3703, 2163, 12417, 6307, 29883, 40303, 171831}},
-{17096, 18, 61879, {1, 3, 7, 13, 1, 19, 71, 245, 267, 105, 749, 1203, 7953, 1881, 9273, 4629, 71793, 195393}},
-{17097, 18, 61885, {1, 1, 1, 15, 3, 49, 53, 145, 47, 959, 1107, 1361, 4517, 16055, 32119, 58433, 110123, 81487}},
-{17098, 18, 61900, {1, 3, 1, 1, 5, 3, 99, 93, 257, 659, 19, 3789, 203, 6183, 11571, 54845, 80591, 243303}},
-{17099, 18, 61905, {1, 3, 7, 1, 1, 7, 27, 11, 255, 261, 769, 2877, 6013, 8431, 25669, 43591, 122501, 208947}},
-{17100, 18, 61906, {1, 1, 7, 7, 3, 25, 117, 19, 15, 843, 401, 613, 801, 10579, 129, 12249, 107465, 95953}},
-{17101, 18, 61962, {1, 1, 3, 5, 1, 35, 95, 93, 243, 937, 1543, 3443, 175, 2199, 12521, 2521, 87225, 38631}},
-{17102, 18, 61967, {1, 3, 7, 13, 21, 29, 81, 139, 247, 937, 1835, 3887, 6917, 15709, 20947, 3341, 125521, 247195}},
-{17103, 18, 61972, {1, 1, 5, 11, 31, 19, 111, 215, 191, 347, 1215, 1757, 6751, 3099, 755, 43753, 2813, 159123}},
-{17104, 18, 61976, {1, 3, 3, 3, 31, 5, 35, 87, 293, 581, 1501, 3255, 7041, 5233, 2053, 63403, 37943, 12115}},
-{17105, 18, 62027, {1, 1, 7, 15, 11, 31, 5, 123, 225, 703, 733, 635, 2193, 3059, 30933, 43149, 79409, 106995}},
-{17106, 18, 62048, {1, 3, 1, 7, 11, 21, 45, 135, 99, 883, 85, 3861, 6617, 7169, 29887, 329, 42487, 129001}},
-{17107, 18, 62051, {1, 1, 1, 3, 11, 53, 31, 245, 141, 667, 1615, 3311, 1475, 12785, 3509, 47153, 105747, 141275}},
-{17108, 18, 62066, {1, 1, 3, 15, 7, 15, 55, 13, 465, 707, 1299, 1393, 399, 9229, 4897, 50313, 1275, 131811}},
-{17109, 18, 62081, {1, 1, 3, 15, 5, 57, 43, 19, 335, 929, 459, 327, 5715, 7173, 27643, 535, 46221, 144619}},
-{17110, 18, 62108, {1, 3, 5, 1, 9, 1, 63, 187, 71, 899, 969, 1349, 1553, 15593, 22783, 211, 41643, 163981}},
-{17111, 18, 62178, {1, 1, 1, 13, 3, 63, 35, 37, 311, 253, 1393, 629, 5299, 14837, 15053, 28041, 81541, 149037}},
-{17112, 18, 62189, {1, 3, 3, 11, 13, 45, 17, 165, 497, 751, 635, 2939, 6891, 14877, 32763, 20671, 106845, 258033}},
-{17113, 18, 62224, {1, 1, 3, 11, 21, 7, 3, 247, 243, 219, 1651, 929, 2737, 9507, 31819, 61389, 14593, 137207}},
-{17114, 18, 62229, {1, 1, 7, 5, 15, 33, 31, 29, 467, 75, 523, 1067, 7313, 11715, 26581, 47037, 106385, 199859}},
-{17115, 18, 62282, {1, 3, 1, 7, 19, 59, 35, 35, 3, 899, 799, 1379, 5113, 7653, 17977, 42197, 52397, 179705}},
-{17116, 18, 62318, {1, 1, 7, 5, 13, 13, 67, 157, 181, 633, 21, 3107, 6301, 7523, 23981, 9079, 88875, 195869}},
-{17117, 18, 62320, {1, 3, 7, 9, 7, 9, 115, 49, 293, 691, 1729, 4087, 6353, 963, 12433, 22135, 96383, 127745}},
-{17118, 18, 62329, {1, 3, 7, 7, 21, 5, 43, 247, 89, 275, 1219, 311, 5677, 7161, 13853, 38613, 84935, 223563}},
-{17119, 18, 62341, {1, 3, 1, 5, 29, 61, 17, 235, 127, 979, 973, 1463, 371, 5567, 6949, 34165, 3075, 169347}},
-{17120, 18, 62353, {1, 3, 3, 15, 25, 51, 43, 73, 7, 123, 1761, 1461, 5291, 14271, 19335, 45379, 123469, 190439}},
-{17121, 18, 62359, {1, 3, 3, 13, 19, 57, 25, 161, 351, 703, 819, 753, 3101, 9043, 19179, 22665, 118533, 45817}},
-{17122, 18, 62382, {1, 3, 5, 15, 3, 33, 15, 63, 251, 87, 611, 1187, 2639, 6001, 16135, 27505, 71077, 34101}},
-{17123, 18, 62389, {1, 1, 5, 3, 31, 5, 13, 239, 119, 803, 1881, 3479, 1933, 6421, 21411, 62923, 76851, 211029}},
-{17124, 18, 62396, {1, 3, 1, 11, 13, 59, 13, 77, 87, 343, 1733, 3493, 5937, 15733, 7763, 12839, 68639, 70965}},
-{17125, 18, 62425, {1, 1, 1, 3, 5, 19, 73, 109, 197, 1007, 1369, 623, 3249, 9263, 12463, 37105, 40599, 115323}},
-{17126, 18, 62455, {1, 1, 7, 1, 21, 23, 27, 221, 117, 27, 1811, 837, 7355, 8083, 12657, 34137, 102025, 6511}},
-{17127, 18, 62484, {1, 3, 7, 13, 13, 29, 7, 103, 511, 449, 1443, 775, 3503, 1057, 8809, 48583, 27649, 206219}},
-{17128, 18, 62494, {1, 1, 7, 1, 15, 37, 53, 205, 393, 691, 989, 3493, 7813, 12371, 18125, 62569, 57075, 100625}},
-{17129, 18, 62507, {1, 3, 5, 7, 11, 11, 55, 7, 487, 861, 1589, 1003, 607, 10031, 22481, 41905, 67791, 168167}},
-{17130, 18, 62512, {1, 3, 1, 9, 21, 31, 25, 187, 315, 379, 961, 2721, 3395, 12321, 21693, 56977, 73197, 160023}},
-{17131, 18, 62550, {1, 3, 3, 7, 9, 25, 103, 1, 13, 1021, 1777, 1015, 2269, 2131, 191, 2561, 74755, 27131}},
-{17132, 18, 62577, {1, 1, 3, 13, 21, 29, 97, 153, 499, 207, 719, 585, 8155, 2873, 22073, 45933, 92875, 19205}},
-{17133, 18, 62590, {1, 3, 7, 15, 13, 31, 43, 223, 405, 839, 1241, 2219, 6911, 9469, 24477, 63157, 95503, 128431}},
-{17134, 18, 62599, {1, 3, 5, 15, 5, 11, 79, 129, 235, 171, 289, 1791, 6061, 9107, 13859, 55923, 30197, 111025}},
-{17135, 18, 62617, {1, 1, 7, 11, 13, 23, 51, 139, 219, 467, 1923, 2847, 1977, 1503, 1939, 55579, 65357, 50047}},
-{17136, 18, 62679, {1, 3, 7, 11, 27, 25, 91, 95, 73, 189, 1537, 273, 725, 1215, 15255, 18847, 67419, 162153}},
-{17137, 18, 62702, {1, 3, 3, 11, 3, 63, 49, 131, 219, 285, 819, 2801, 2645, 2943, 15055, 15659, 130641, 82913}},
-{17138, 18, 62745, {1, 1, 3, 7, 17, 19, 37, 59, 391, 1009, 1569, 2569, 2519, 33, 18827, 23277, 94797, 103673}},
-{17139, 18, 62772, {1, 3, 5, 9, 27, 57, 69, 185, 49, 829, 29, 1247, 6129, 14935, 8005, 48343, 55789, 170099}},
-{17140, 18, 62794, {1, 3, 3, 7, 19, 55, 77, 231, 79, 787, 1597, 2701, 4999, 4247, 31849, 7797, 118993, 77871}},
-{17141, 18, 62835, {1, 1, 7, 13, 5, 45, 105, 137, 239, 923, 593, 3227, 3603, 15463, 15533, 55285, 95295, 141951}},
-{17142, 18, 62842, {1, 3, 1, 5, 29, 3, 113, 241, 255, 181, 1933, 2579, 1865, 11083, 8023, 34271, 78603, 240781}},
-{17143, 18, 62847, {1, 1, 3, 7, 17, 21, 123, 75, 305, 485, 9, 3037, 677, 8001, 16803, 25851, 121773, 77729}},
-{17144, 18, 62857, {1, 3, 1, 5, 23, 7, 39, 25, 381, 1003, 361, 995, 1751, 9599, 6399, 9627, 19303, 249899}},
-{17145, 18, 62894, {1, 3, 5, 5, 13, 39, 65, 145, 351, 135, 981, 3657, 4711, 13649, 17253, 46443, 99187, 176683}},
-{17146, 18, 62911, {1, 3, 1, 9, 9, 41, 79, 237, 445, 507, 1947, 2905, 8161, 715, 24499, 62397, 26393, 197221}},
-{17147, 18, 62928, {1, 3, 5, 3, 23, 9, 107, 121, 59, 265, 177, 3495, 391, 4537, 32099, 45217, 128285, 259285}},
-{17148, 18, 62954, {1, 3, 3, 15, 5, 61, 87, 209, 139, 461, 485, 3261, 7425, 6193, 22221, 22145, 93989, 101459}},
-{17149, 18, 62964, {1, 3, 1, 1, 15, 51, 29, 145, 385, 695, 375, 3743, 1387, 15385, 7995, 22993, 64115, 239897}},
-{17150, 18, 62977, {1, 1, 5, 15, 9, 11, 73, 219, 293, 941, 477, 3935, 2717, 9559, 20537, 6935, 39711, 13623}},
-{17151, 18, 62984, {1, 3, 3, 11, 3, 23, 127, 21, 61, 59, 1685, 507, 3883, 6587, 6355, 65407, 54311, 228555}},
-{17152, 18, 63007, {1, 3, 1, 1, 25, 47, 51, 111, 77, 871, 1045, 4017, 7683, 7729, 24155, 3481, 31749, 245155}},
-{17153, 18, 63017, {1, 3, 5, 1, 25, 29, 119, 131, 475, 763, 1639, 1937, 7387, 2307, 24081, 34797, 91785, 52055}},
-{17154, 18, 63058, {1, 1, 5, 1, 29, 19, 119, 111, 119, 751, 1079, 1911, 4085, 8909, 4351, 30037, 37691, 57175}},
-{17155, 18, 63067, {1, 1, 7, 7, 27, 33, 71, 189, 105, 821, 1543, 2939, 3829, 6485, 22235, 7097, 76987, 207121}},
-{17156, 18, 63085, {1, 1, 3, 3, 7, 7, 65, 121, 355, 405, 1019, 1779, 7301, 10609, 25927, 16501, 37287, 133383}},
-{17157, 18, 63150, {1, 1, 3, 11, 31, 57, 109, 197, 165, 711, 271, 653, 5835, 14905, 26065, 52287, 106215, 225075}},
-{17158, 18, 63170, {1, 1, 3, 3, 1, 41, 5, 169, 15, 49, 1311, 2715, 579, 1693, 28001, 17935, 18585, 123531}},
-{17159, 18, 63184, {1, 1, 7, 7, 1, 49, 59, 75, 173, 361, 1947, 2707, 1835, 12025, 24051, 24359, 121841, 215797}},
-{17160, 18, 63210, {1, 1, 5, 13, 7, 49, 15, 181, 409, 1005, 383, 3449, 2987, 13051, 7097, 34571, 55495, 65251}},
-{17161, 18, 63215, {1, 1, 3, 11, 5, 9, 67, 41, 9, 79, 401, 379, 4107, 5231, 519, 47877, 17273, 137479}},
-{17162, 18, 63217, {1, 1, 3, 13, 25, 7, 9, 165, 103, 37, 1369, 933, 1119, 1025, 19767, 25765, 55487, 249709}},
-{17163, 18, 63229, {1, 3, 5, 5, 19, 53, 105, 135, 245, 957, 185, 2901, 1741, 10429, 747, 23365, 49363, 84095}},
-{17164, 18, 63237, {1, 1, 1, 15, 29, 17, 107, 193, 17, 447, 1261, 1935, 5749, 2303, 23287, 59883, 28655, 188055}},
-{17165, 18, 63259, {1, 1, 5, 9, 13, 27, 99, 253, 299, 481, 89, 3041, 1549, 15417, 30495, 2063, 53649, 219883}},
-{17166, 18, 63265, {1, 3, 3, 15, 19, 19, 7, 149, 67, 349, 789, 129, 2783, 2887, 28631, 26001, 62407, 151767}},
-{17167, 18, 63271, {1, 3, 3, 13, 7, 29, 65, 25, 93, 627, 301, 721, 7249, 13295, 19995, 33715, 36441, 157625}},
-{17168, 18, 63286, {1, 1, 1, 3, 29, 63, 85, 27, 507, 543, 1887, 3169, 4239, 4455, 22047, 15369, 48913, 192071}},
-{17169, 18, 63298, {1, 3, 7, 5, 9, 33, 125, 41, 7, 723, 1091, 3311, 8173, 3861, 31507, 42669, 68853, 60043}},
-{17170, 18, 63343, {1, 3, 1, 13, 13, 7, 121, 41, 181, 913, 371, 163, 7061, 8779, 18345, 41915, 1785, 107113}},
-{17171, 18, 63355, {1, 1, 1, 9, 13, 41, 23, 35, 157, 247, 1243, 1101, 5193, 4027, 29917, 44099, 46211, 162059}},
-{17172, 18, 63361, {1, 3, 1, 5, 15, 51, 3, 241, 131, 741, 1885, 2397, 5673, 9097, 9319, 15381, 55655, 207569}},
-{17173, 18, 63362, {1, 1, 3, 15, 25, 15, 69, 55, 435, 727, 1007, 375, 7871, 10437, 11011, 36711, 11269, 105159}},
-{17174, 18, 63379, {1, 3, 3, 13, 17, 1, 101, 189, 295, 185, 1715, 2609, 6767, 11751, 11469, 3951, 80743, 114439}},
-{17175, 18, 63397, {1, 3, 1, 7, 21, 41, 93, 39, 433, 917, 279, 161, 267, 10201, 26583, 30363, 110187, 46501}},
-{17176, 18, 63415, {1, 1, 7, 7, 13, 15, 89, 167, 365, 925, 107, 3537, 6815, 15251, 23149, 61821, 66569, 135353}},
-{17177, 18, 63421, {1, 1, 1, 3, 13, 59, 21, 255, 111, 603, 547, 465, 3001, 16055, 26389, 64301, 112751, 219279}},
-{17178, 18, 63463, {1, 1, 1, 15, 17, 3, 21, 49, 327, 349, 489, 957, 807, 11685, 23975, 34729, 100773, 223551}},
-{17179, 18, 63491, {1, 3, 5, 15, 19, 59, 63, 71, 233, 767, 1789, 3609, 5911, 3405, 7519, 3611, 92015, 126669}},
-{17180, 18, 63527, {1, 1, 1, 11, 7, 31, 79, 57, 115, 763, 1643, 3329, 7209, 1385, 15565, 64353, 60637, 59445}},
-{17181, 18, 63545, {1, 1, 3, 1, 13, 3, 47, 89, 507, 523, 1, 1391, 6973, 7267, 32527, 52631, 20775, 234503}},
-{17182, 18, 63553, {1, 3, 1, 9, 23, 23, 95, 57, 295, 857, 213, 1211, 3503, 3043, 24843, 16149, 118719, 171585}},
-{17183, 18, 63560, {1, 3, 1, 5, 1, 13, 63, 167, 305, 711, 759, 2521, 5051, 9125, 22917, 24647, 100777, 261137}},
-{17184, 18, 63563, {1, 1, 5, 9, 25, 19, 5, 225, 511, 543, 685, 733, 7249, 10447, 11115, 25927, 104327, 92861}},
-{17185, 18, 63566, {1, 3, 1, 7, 15, 7, 15, 83, 379, 461, 943, 317, 7735, 12655, 7549, 6371, 20901, 170331}},
-{17186, 18, 63589, {1, 1, 1, 13, 7, 17, 41, 51, 47, 15, 477, 1203, 819, 1615, 13805, 40147, 3967, 192647}},
-{17187, 18, 63599, {1, 3, 7, 11, 9, 11, 111, 75, 171, 833, 1503, 2325, 7279, 2687, 16499, 11547, 99409, 186429}},
-{17188, 18, 63601, {1, 1, 5, 3, 13, 21, 75, 17, 447, 647, 1309, 2297, 7911, 12093, 16237, 50831, 96123, 134479}},
-{17189, 18, 63608, {1, 1, 5, 15, 19, 29, 35, 255, 291, 437, 85, 2143, 3281, 3629, 29339, 28169, 46561, 236595}},
-{17190, 18, 63620, {1, 3, 7, 1, 31, 57, 125, 109, 317, 461, 681, 1379, 6387, 14971, 8451, 17655, 87619, 51721}},
-{17191, 18, 63654, {1, 3, 7, 1, 23, 33, 45, 149, 43, 465, 997, 601, 693, 6273, 12867, 25885, 81353, 60437}},
-{17192, 18, 63703, {1, 1, 7, 7, 31, 25, 113, 205, 481, 141, 1757, 587, 2981, 7637, 3869, 4151, 69541, 68587}},
-{17193, 18, 63719, {1, 1, 7, 13, 17, 31, 69, 247, 137, 79, 1221, 1693, 3747, 10711, 1671, 31587, 12139, 248585}},
-{17194, 18, 63758, {1, 1, 1, 3, 1, 61, 39, 139, 37, 79, 125, 1145, 7505, 10129, 29209, 52045, 99159, 195553}},
-{17195, 18, 63769, {1, 1, 5, 3, 13, 41, 13, 11, 167, 953, 1961, 3557, 871, 1687, 28479, 10621, 27533, 243519}},
-{17196, 18, 63782, {1, 1, 7, 7, 1, 35, 107, 227, 375, 225, 483, 1239, 7591, 8549, 7351, 62001, 70245, 102795}},
-{17197, 18, 63803, {1, 1, 1, 9, 29, 35, 15, 3, 337, 1017, 1065, 2107, 2457, 9455, 7069, 55081, 57887, 149679}},
-{17198, 18, 63811, {1, 1, 7, 1, 1, 1, 13, 63, 287, 895, 593, 1253, 4717, 10313, 10275, 22143, 59149, 38865}},
-{17199, 18, 63851, {1, 1, 3, 15, 27, 39, 73, 11, 509, 391, 1901, 503, 5523, 6777, 30849, 41301, 35067, 68443}},
-{17200, 18, 63854, {1, 3, 3, 15, 17, 57, 39, 229, 273, 917, 577, 3627, 3285, 4495, 28581, 34011, 38537, 194999}},
-{17201, 18, 63872, {1, 1, 7, 3, 17, 51, 91, 203, 161, 757, 581, 1625, 477, 8839, 16515, 43101, 121497, 23603}},
-{17202, 18, 63878, {1, 3, 3, 5, 19, 29, 55, 127, 283, 999, 1227, 1937, 4471, 11305, 8813, 40509, 78521, 175573}},
-{17203, 18, 63895, {1, 3, 3, 3, 5, 29, 33, 249, 25, 213, 1315, 393, 6967, 12751, 7485, 39561, 14801, 191921}},
-{17204, 18, 63917, {1, 3, 7, 9, 23, 15, 93, 69, 23, 239, 1993, 3375, 539, 14141, 10123, 33561, 127565, 181527}},
-{17205, 18, 63930, {1, 3, 3, 15, 13, 15, 65, 241, 83, 351, 1943, 1305, 7181, 11803, 31907, 63623, 5439, 150661}},
-{17206, 18, 63935, {1, 3, 7, 11, 13, 17, 17, 37, 409, 577, 973, 797, 1761, 5333, 13803, 22991, 29743, 53051}},
-{17207, 18, 63955, {1, 3, 5, 5, 27, 25, 91, 225, 411, 23, 877, 2487, 8061, 12337, 11471, 8857, 10791, 112699}},
-{17208, 18, 63964, {1, 1, 5, 3, 15, 1, 87, 249, 205, 1011, 2045, 1879, 4137, 5877, 12709, 5231, 74283, 124315}},
-{17209, 18, 63967, {1, 1, 7, 7, 31, 37, 117, 71, 139, 391, 1085, 4033, 3087, 3063, 19991, 8787, 96899, 17279}},
-{17210, 18, 63980, {1, 1, 7, 15, 19, 47, 45, 181, 303, 151, 337, 2557, 6131, 3161, 13097, 52777, 77783, 259817}},
-{17211, 18, 63985, {1, 1, 3, 3, 1, 55, 115, 227, 83, 591, 967, 4067, 3441, 243, 13443, 4043, 129365, 161459}},
-{17212, 18, 63992, {1, 1, 3, 15, 5, 23, 71, 31, 271, 585, 931, 909, 3375, 15063, 12111, 35811, 124047, 68225}},
-{17213, 18, 64021, {1, 1, 5, 11, 1, 59, 19, 193, 323, 489, 837, 3709, 1807, 11617, 30931, 33561, 2805, 100979}},
-{17214, 18, 64026, {1, 3, 5, 7, 27, 7, 71, 67, 167, 521, 1237, 2911, 3531, 2885, 4669, 25703, 87647, 36381}},
-{17215, 18, 64044, {1, 3, 3, 13, 13, 21, 97, 225, 477, 1023, 2029, 877, 3849, 4675, 17665, 19257, 9697, 168577}},
-{17216, 18, 64055, {1, 1, 7, 15, 25, 31, 19, 255, 45, 539, 1831, 2655, 7471, 12011, 12455, 3681, 123881, 234471}},
-{17217, 18, 64056, {1, 1, 3, 9, 17, 39, 105, 73, 271, 555, 987, 873, 5371, 12381, 13469, 54961, 125701, 194063}},
-{17218, 18, 64061, {1, 1, 5, 5, 7, 27, 15, 195, 121, 175, 991, 955, 5007, 11423, 1539, 21381, 79891, 162149}},
-{17219, 18, 64067, {1, 3, 1, 7, 25, 23, 69, 69, 177, 545, 481, 3503, 3721, 1077, 8763, 6919, 64743, 172311}},
-{17220, 18, 64081, {1, 1, 3, 15, 31, 5, 33, 45, 81, 795, 435, 399, 4591, 3741, 26493, 14791, 59529, 89989}},
-{17221, 18, 64100, {1, 1, 7, 13, 21, 29, 95, 75, 213, 59, 1635, 479, 441, 14667, 16389, 9139, 30955, 169895}},
-{17222, 18, 64109, {1, 3, 3, 3, 17, 61, 103, 85, 233, 287, 447, 2687, 4755, 9489, 1669, 10405, 58489, 170429}},
-{17223, 18, 64112, {1, 1, 5, 5, 13, 9, 63, 129, 321, 531, 393, 3353, 5309, 16375, 20473, 12595, 52239, 183647}},
-{17224, 18, 64118, {1, 1, 3, 7, 7, 31, 101, 253, 119, 325, 351, 2321, 1899, 14073, 8985, 13609, 32043, 33225}},
-{17225, 18, 64124, {1, 1, 3, 13, 7, 25, 73, 191, 399, 591, 819, 2859, 6053, 815, 30417, 5709, 18277, 121991}},
-{17226, 18, 64145, {1, 3, 3, 1, 7, 47, 7, 81, 451, 463, 699, 1857, 8169, 15649, 22693, 28673, 9717, 227583}},
-{17227, 18, 64151, {1, 3, 3, 3, 31, 45, 123, 205, 23, 901, 1003, 1149, 7481, 6925, 23845, 18573, 97047, 248957}},
-{17228, 18, 64203, {1, 1, 3, 3, 21, 9, 53, 241, 125, 583, 1055, 3981, 8113, 12477, 8455, 6289, 112253, 17321}},
-{17229, 18, 64208, {1, 1, 7, 3, 19, 5, 51, 111, 443, 283, 117, 2127, 4273, 2335, 20373, 2885, 57439, 56839}},
-{17230, 18, 64236, {1, 1, 5, 15, 7, 5, 65, 163, 27, 691, 1667, 69, 2459, 7477, 21349, 52417, 42299, 75965}},
-{17231, 18, 64254, {1, 1, 1, 13, 13, 19, 87, 223, 475, 205, 1113, 887, 2213, 5533, 15875, 36173, 53933, 200173}},
-{17232, 18, 64261, {1, 3, 3, 13, 23, 17, 93, 37, 391, 127, 873, 1445, 3007, 10863, 21245, 55025, 99275, 255329}},
-{17233, 18, 64280, {1, 3, 1, 15, 1, 47, 57, 5, 207, 825, 161, 539, 6151, 12829, 14121, 51217, 25547, 234303}},
-{17234, 18, 64296, {1, 1, 5, 1, 21, 63, 15, 83, 19, 817, 591, 3131, 889, 12451, 14363, 27295, 83877, 124701}},
-{17235, 18, 64313, {1, 1, 7, 7, 11, 21, 87, 85, 13, 555, 163, 9, 5973, 14749, 19585, 57287, 43421, 66301}},
-{17236, 18, 64314, {1, 3, 5, 5, 7, 33, 19, 7, 9, 819, 533, 2105, 4275, 10611, 30517, 35863, 84687, 245157}},
-{17237, 18, 64316, {1, 3, 5, 13, 3, 55, 111, 157, 235, 405, 39, 2191, 905, 3099, 245, 37371, 365, 257385}},
-{17238, 18, 64348, {1, 3, 3, 13, 29, 39, 125, 235, 213, 879, 497, 1659, 6689, 12165, 18621, 14657, 37079, 167867}},
-{17239, 18, 64352, {1, 1, 5, 15, 5, 5, 27, 197, 77, 477, 1115, 3369, 2253, 5757, 20855, 4473, 112501, 76881}},
-{17240, 18, 64355, {1, 3, 3, 13, 13, 61, 37, 97, 229, 743, 1381, 3979, 307, 319, 16765, 56295, 109303, 21361}},
-{17241, 18, 64361, {1, 1, 7, 11, 19, 7, 63, 145, 129, 899, 93, 1851, 7901, 8767, 15553, 13913, 4897, 129483}},
-{17242, 18, 64388, {1, 3, 5, 11, 7, 23, 19, 5, 465, 365, 883, 3563, 4395, 2759, 4273, 623, 75047, 249519}},
-{17243, 18, 64398, {1, 3, 1, 5, 29, 43, 75, 7, 509, 373, 359, 2041, 5957, 1251, 32431, 37803, 120915, 45137}},
-{17244, 18, 64403, {1, 3, 1, 5, 21, 9, 43, 1, 337, 743, 1359, 1629, 5117, 2499, 16129, 22831, 38795, 32137}},
-{17245, 18, 64419, {1, 3, 3, 7, 23, 57, 9, 31, 351, 559, 1729, 1461, 3037, 12685, 8899, 14859, 108851, 170195}},
-{17246, 18, 64421, {1, 1, 1, 15, 23, 57, 39, 23, 283, 487, 1055, 1265, 6781, 7955, 195, 37745, 66115, 56413}},
-{17247, 18, 64428, {1, 1, 3, 7, 27, 35, 57, 17, 137, 17, 905, 4033, 5775, 5305, 22975, 17547, 106297, 146287}},
-{17248, 18, 64453, {1, 1, 1, 3, 5, 39, 73, 151, 469, 523, 119, 539, 2817, 7783, 22957, 59937, 21331, 172437}},
-{17249, 18, 64463, {1, 1, 3, 13, 21, 1, 23, 109, 113, 257, 817, 1671, 6729, 1571, 15009, 48539, 94025, 160379}},
-{17250, 18, 64475, {1, 1, 1, 1, 31, 23, 83, 107, 225, 715, 949, 69, 2163, 4777, 7715, 25901, 82935, 81455}},
-{17251, 18, 64511, {1, 3, 5, 13, 29, 11, 61, 169, 241, 973, 315, 3991, 1389, 3293, 31123, 59419, 7359, 170929}},
-{17252, 18, 64537, {1, 1, 7, 3, 21, 15, 111, 41, 329, 513, 1175, 4037, 2747, 11465, 17253, 54055, 29409, 230925}},
-{17253, 18, 64576, {1, 3, 5, 15, 31, 17, 105, 45, 61, 339, 1387, 1021, 4499, 13671, 25521, 52081, 49153, 31587}},
-{17254, 18, 64579, {1, 3, 3, 3, 29, 17, 51, 103, 429, 849, 1759, 1267, 6255, 4631, 32643, 44977, 40875, 239457}},
-{17255, 18, 64581, {1, 1, 7, 15, 3, 11, 123, 157, 73, 151, 777, 3855, 1913, 969, 11821, 16889, 63503, 197305}},
-{17256, 18, 64606, {1, 3, 1, 5, 13, 49, 61, 209, 105, 523, 851, 3667, 7525, 5537, 12851, 42867, 50535, 131403}},
-{17257, 18, 64615, {1, 3, 1, 7, 13, 19, 107, 71, 479, 895, 405, 89, 1345, 5543, 12709, 6093, 97581, 20483}},
-{17258, 18, 64649, {1, 3, 3, 11, 3, 47, 117, 175, 175, 321, 1257, 365, 1193, 12813, 2713, 26941, 43605, 223323}},
-{17259, 18, 64655, {1, 1, 7, 1, 19, 35, 45, 143, 395, 255, 1599, 575, 2637, 1287, 27673, 48329, 57975, 44173}},
-{17260, 18, 64664, {1, 3, 5, 1, 1, 19, 107, 233, 465, 661, 91, 4007, 6409, 3399, 8175, 54171, 111417, 124955}},
-{17261, 18, 64667, {1, 1, 5, 13, 9, 27, 121, 225, 55, 761, 779, 3015, 6333, 10779, 26531, 57103, 33463, 90219}},
-{17262, 18, 64712, {1, 3, 1, 9, 17, 3, 85, 147, 111, 133, 869, 1833, 2401, 5811, 24415, 27095, 65529, 164121}},
-{17263, 18, 64715, {1, 1, 5, 13, 11, 37, 13, 83, 391, 909, 2013, 1327, 6697, 1711, 29265, 10607, 20127, 57873}},
-{17264, 18, 64718, {1, 3, 1, 11, 17, 17, 33, 101, 383, 837, 1769, 1711, 3735, 14777, 27101, 56853, 110643, 101917}},
-{17265, 18, 64741, {1, 3, 5, 13, 25, 7, 37, 99, 473, 211, 1469, 1827, 6307, 8835, 15853, 22027, 43095, 15817}},
-{17266, 18, 64766, {1, 3, 1, 5, 19, 13, 61, 193, 57, 359, 1277, 749, 5499, 11239, 20681, 48477, 7225, 259259}},
-{17267, 18, 64780, {1, 1, 1, 7, 27, 17, 79, 213, 307, 761, 429, 1519, 7483, 6007, 11251, 13263, 24851, 7919}},
-{17268, 18, 64788, {1, 1, 3, 5, 9, 37, 101, 149, 405, 413, 1213, 157, 3811, 4485, 13099, 32697, 75677, 127815}},
-{17269, 18, 64791, {1, 3, 3, 7, 29, 29, 13, 113, 45, 885, 1471, 3433, 2289, 4375, 815, 16741, 20933, 9763}},
-{17270, 18, 64795, {1, 3, 5, 15, 5, 3, 7, 37, 347, 41, 1977, 395, 6363, 3591, 21457, 31455, 60547, 108153}},
-{17271, 18, 64798, {1, 3, 5, 7, 19, 9, 113, 1, 241, 439, 731, 1591, 3347, 1295, 6635, 25267, 13239, 214669}},
-{17272, 18, 64816, {1, 1, 3, 5, 7, 7, 69, 77, 281, 851, 1533, 1, 7351, 3429, 29237, 54597, 11171, 66613}},
-{17273, 18, 64819, {1, 1, 7, 15, 29, 7, 59, 9, 105, 129, 1397, 3841, 3945, 4755, 19877, 11109, 17497, 225473}},
-{17274, 18, 64822, {1, 3, 7, 7, 15, 61, 3, 207, 97, 229, 1251, 101, 3157, 5729, 15579, 14849, 119119, 91891}},
-{17275, 18, 64833, {1, 3, 3, 9, 27, 15, 85, 221, 231, 577, 1787, 3489, 2393, 7593, 13175, 25561, 108505, 97267}},
-{17276, 18, 64836, {1, 3, 7, 13, 23, 3, 7, 85, 307, 899, 371, 3539, 3467, 7955, 9539, 53583, 125587, 30969}},
-{17277, 18, 64876, {1, 1, 5, 7, 7, 31, 115, 245, 375, 803, 1121, 3775, 3565, 15283, 25981, 24681, 34469, 172003}},
-{17278, 18, 64891, {1, 1, 5, 1, 31, 5, 5, 161, 153, 235, 1703, 2163, 1089, 16233, 6183, 25167, 102925, 36673}},
-{17279, 18, 64907, {1, 3, 3, 5, 1, 57, 59, 5, 87, 497, 151, 1731, 2727, 4583, 28165, 63053, 76003, 29259}},
-{17280, 18, 64943, {1, 1, 5, 7, 5, 21, 79, 111, 347, 879, 827, 3947, 4421, 9589, 23971, 11681, 104555, 226535}},
-{17281, 18, 64965, {1, 1, 5, 1, 17, 35, 105, 159, 391, 495, 1709, 3731, 261, 2359, 1413, 37105, 8979, 189381}},
-{17282, 18, 64977, {1, 3, 3, 1, 11, 23, 21, 213, 261, 755, 1503, 2369, 1765, 14531, 2605, 15609, 48691, 113059}},
-{17283, 18, 64999, {1, 3, 5, 1, 1, 55, 87, 197, 89, 391, 1157, 3523, 385, 5871, 13681, 29097, 101903, 184553}},
-{17284, 18, 65034, {1, 3, 7, 5, 17, 51, 87, 191, 495, 761, 1943, 1845, 2963, 13133, 22439, 20101, 96759, 215215}},
-{17285, 18, 65036, {1, 3, 5, 11, 23, 9, 53, 41, 229, 233, 2025, 2835, 2359, 4755, 3015, 48267, 20721, 61001}},
-{17286, 18, 65089, {1, 1, 7, 9, 27, 35, 45, 201, 137, 291, 151, 733, 6199, 3127, 3073, 14491, 95051, 12469}},
-{17287, 18, 65107, {1, 1, 1, 9, 7, 49, 73, 233, 239, 881, 1991, 695, 5947, 9377, 12027, 41137, 80217, 122961}},
-{17288, 18, 65110, {1, 1, 5, 11, 3, 15, 85, 203, 305, 945, 1007, 1831, 3999, 373, 21141, 63829, 91779, 122495}},
-{17289, 18, 65120, {1, 1, 1, 11, 23, 51, 127, 215, 441, 467, 229, 3071, 2731, 8813, 30155, 60289, 54531, 196187}},
-{17290, 18, 65132, {1, 3, 5, 15, 29, 31, 11, 129, 443, 649, 773, 3035, 7915, 13831, 31979, 5577, 42869, 153591}},
-{17291, 18, 65143, {1, 1, 3, 11, 21, 37, 23, 79, 153, 7, 1801, 441, 8189, 7235, 6311, 965, 71993, 81755}},
-{17292, 18, 65150, {1, 3, 5, 5, 23, 13, 93, 39, 247, 367, 811, 1381, 6809, 16219, 8755, 41923, 79873, 105781}},
-{17293, 18, 65177, {1, 3, 5, 9, 19, 43, 21, 229, 251, 187, 1047, 2295, 5529, 2965, 1507, 16185, 121183, 30551}},
-{17294, 18, 65201, {1, 3, 7, 9, 19, 11, 33, 213, 39, 811, 231, 1527, 6093, 1507, 3541, 37585, 78785, 215419}},
-{17295, 18, 65214, {1, 3, 7, 7, 11, 13, 109, 119, 175, 311, 719, 3127, 6351, 1909, 5441, 5411, 58751, 80875}},
-{17296, 18, 65234, {1, 1, 1, 7, 17, 35, 57, 139, 289, 137, 1919, 2131, 6145, 3953, 24887, 64737, 4677, 23833}},
-{17297, 18, 65240, {1, 1, 3, 13, 1, 21, 83, 243, 27, 69, 501, 3925, 3339, 13313, 27021, 38319, 76441, 146397}},
-{17298, 18, 65243, {1, 3, 7, 9, 15, 17, 97, 117, 505, 673, 1333, 3891, 7775, 6323, 12967, 17387, 19501, 68347}},
-{17299, 18, 65259, {1, 1, 1, 5, 27, 55, 43, 47, 399, 147, 1539, 2663, 5555, 11993, 8759, 33783, 8361, 78633}},
-{17300, 18, 65276, {1, 1, 1, 15, 1, 17, 21, 85, 129, 117, 339, 1319, 1119, 6869, 12913, 56873, 30795, 76849}},
-{17301, 18, 65287, {1, 1, 5, 5, 11, 1, 11, 175, 355, 737, 1367, 3089, 5993, 4377, 10325, 3817, 61735, 187689}},
-{17302, 18, 65306, {1, 3, 5, 5, 21, 41, 85, 219, 425, 611, 1219, 1849, 349, 925, 26185, 31591, 23855, 35549}},
-{17303, 18, 65311, {1, 1, 3, 5, 21, 3, 77, 25, 265, 949, 1979, 1561, 4243, 12437, 5215, 23445, 33295, 130385}},
-{17304, 18, 65321, {1, 1, 3, 1, 13, 7, 3, 81, 143, 735, 31, 1781, 1537, 10789, 11923, 61589, 75761, 178837}},
-{17305, 18, 65350, {1, 1, 7, 7, 11, 47, 55, 37, 39, 533, 1773, 3121, 183, 7193, 19403, 45757, 20457, 158437}},
-{17306, 18, 65364, {1, 1, 5, 5, 3, 15, 53, 41, 139, 529, 601, 2967, 4683, 3869, 13449, 30155, 85833, 190053}},
-{17307, 18, 65451, {1, 1, 5, 1, 11, 39, 85, 131, 349, 175, 267, 779, 923, 5905, 32727, 22055, 63087, 247607}},
-{17308, 18, 65488, {1, 3, 5, 7, 7, 59, 11, 49, 465, 617, 557, 251, 1303, 10369, 29207, 13457, 113591, 43717}},
-{17309, 18, 65510, {1, 3, 5, 3, 27, 39, 21, 157, 39, 891, 1833, 2887, 7395, 7965, 21771, 42675, 71705, 177323}},
-{17310, 18, 65528, {1, 3, 7, 7, 21, 51, 53, 83, 433, 889, 1033, 1701, 6285, 14335, 1683, 3637, 110241, 110355}},
-{17311, 18, 65533, {1, 1, 7, 7, 11, 23, 35, 63, 71, 867, 79, 2551, 1837, 773, 21093, 60433, 67305, 70731}},
-{17312, 18, 65553, {1, 3, 5, 11, 9, 25, 67, 23, 137, 75, 707, 2229, 6237, 9871, 29063, 30433, 112897, 68037}},
-{17313, 18, 65563, {1, 3, 7, 13, 1, 45, 119, 149, 487, 667, 1177, 2927, 1875, 11963, 20771, 1177, 2331, 244039}},
-{17314, 18, 65579, {1, 3, 3, 7, 19, 61, 89, 163, 91, 409, 1109, 1947, 1017, 12385, 13487, 45645, 64175, 184221}},
-{17315, 18, 65621, {1, 1, 1, 15, 13, 47, 21, 203, 341, 845, 443, 1891, 2591, 2721, 7515, 52161, 70359, 173139}},
-{17316, 18, 65625, {1, 3, 3, 11, 5, 3, 119, 179, 509, 33, 1909, 2531, 6713, 12447, 30157, 61019, 45857, 165557}},
-{17317, 18, 65635, {1, 3, 7, 5, 3, 47, 79, 55, 321, 71, 1917, 4053, 6603, 3079, 28133, 15611, 99161, 118279}},
-{17318, 18, 65644, {1, 1, 1, 7, 19, 13, 3, 31, 213, 705, 435, 2381, 991, 4719, 24473, 8907, 122013, 228081}},
-{17319, 18, 65690, {1, 1, 7, 11, 27, 15, 5, 123, 169, 197, 361, 3803, 2001, 14547, 22967, 27575, 118325, 130651}},
-{17320, 18, 65696, {1, 3, 3, 5, 29, 43, 77, 15, 463, 753, 695, 3489, 2023, 9913, 13029, 26621, 129393, 209439}},
-{17321, 18, 65705, {1, 1, 5, 15, 1, 39, 55, 129, 247, 729, 1537, 2529, 3981, 13153, 1505, 12743, 104173, 218423}},
-{17322, 18, 65716, {1, 3, 7, 3, 21, 3, 49, 173, 445, 821, 3, 2671, 1865, 1377, 7589, 65485, 96485, 80193}},
-{17323, 18, 65725, {1, 3, 3, 11, 7, 21, 99, 143, 333, 869, 1469, 1579, 1749, 2203, 18773, 47377, 103211, 238357}},
-{17324, 18, 65733, {1, 3, 5, 11, 11, 19, 25, 253, 229, 755, 101, 269, 6703, 5603, 23201, 57163, 28431, 159653}},
-{17325, 18, 65740, {1, 3, 5, 3, 3, 15, 45, 225, 325, 997, 1061, 883, 3885, 7633, 461, 44411, 52129, 84535}},
-{17326, 18, 65758, {1, 1, 7, 1, 27, 29, 51, 23, 473, 443, 117, 3021, 55, 7413, 7911, 3063, 47533, 234941}},
-{17327, 18, 65786, {1, 3, 3, 15, 19, 43, 37, 95, 249, 805, 603, 865, 2115, 6999, 9739, 59029, 12181, 211159}},
-{17328, 18, 65806, {1, 3, 7, 3, 3, 61, 105, 113, 11, 169, 1007, 689, 2553, 14561, 17473, 38249, 41225, 80021}},
-{17329, 18, 65834, {1, 3, 7, 11, 5, 47, 69, 49, 457, 931, 435, 1423, 411, 15163, 3171, 29143, 101153, 240869}},
-{17330, 18, 65844, {1, 3, 7, 1, 17, 1, 13, 45, 155, 551, 1783, 3583, 2767, 2761, 18019, 61635, 104527, 123817}},
-{17331, 18, 65866, {1, 1, 5, 11, 9, 43, 101, 205, 233, 689, 1247, 2903, 3117, 12261, 11827, 50403, 103727, 35533}},
-{17332, 18, 65895, {1, 1, 5, 13, 23, 37, 121, 195, 133, 265, 1517, 823, 5933, 13917, 6363, 8533, 58443, 178549}},
-{17333, 18, 65902, {1, 1, 7, 9, 29, 1, 3, 195, 221, 877, 71, 473, 1173, 15285, 6057, 60005, 92401, 65357}},
-{17334, 18, 65953, {1, 3, 7, 1, 5, 25, 15, 207, 455, 447, 1125, 3731, 1289, 867, 22111, 38893, 70779, 88277}},
-{17335, 18, 65954, {1, 1, 1, 13, 31, 19, 15, 179, 183, 351, 1197, 1929, 3569, 12251, 17641, 4097, 24141, 186857}},
-{17336, 18, 65983, {1, 1, 1, 9, 19, 9, 125, 23, 431, 225, 943, 479, 2615, 443, 30977, 10889, 17107, 116819}},
-{17337, 18, 65985, {1, 3, 1, 9, 9, 13, 85, 123, 85, 857, 125, 3149, 1105, 3687, 2313, 38749, 52131, 259511}},
-{17338, 18, 66003, {1, 3, 5, 7, 27, 33, 57, 105, 511, 871, 1089, 2311, 3291, 2245, 3365, 30211, 62549, 56207}},
-{17339, 18, 66010, {1, 1, 7, 11, 1, 19, 75, 37, 139, 173, 391, 317, 2575, 11887, 4289, 32275, 43487, 487}},
-{17340, 18, 66025, {1, 1, 7, 1, 11, 3, 9, 217, 343, 35, 59, 93, 1343, 5043, 14869, 63717, 40983, 235373}},
-{17341, 18, 66050, {1, 1, 3, 5, 15, 13, 93, 247, 417, 179, 307, 3299, 4383, 5491, 21271, 37155, 32289, 75737}},
-{17342, 18, 66074, {1, 3, 3, 9, 3, 39, 63, 243, 305, 729, 9, 3317, 3301, 13165, 20437, 36505, 32977, 2761}},
-{17343, 18, 66076, {1, 3, 7, 5, 3, 37, 61, 109, 351, 641, 1699, 2517, 2637, 4995, 27365, 56971, 53609, 14373}},
-{17344, 18, 66097, {1, 3, 1, 15, 31, 53, 127, 123, 219, 1003, 1425, 1201, 5303, 10369, 21481, 26987, 42541, 37855}},
-{17345, 18, 66132, {1, 3, 3, 13, 9, 29, 35, 111, 395, 791, 1619, 2647, 713, 15955, 19145, 33883, 65215, 166267}},
-{17346, 18, 66158, {1, 1, 7, 11, 17, 5, 45, 249, 421, 273, 411, 2885, 7027, 11933, 24847, 36969, 124701, 214931}},
-{17347, 18, 66175, {1, 1, 3, 1, 27, 41, 125, 83, 327, 643, 223, 151, 6709, 15949, 125, 13275, 90405, 15759}},
-{17348, 18, 66185, {1, 1, 5, 15, 19, 45, 55, 109, 497, 1011, 1363, 1937, 3697, 7475, 10533, 65325, 29681, 76275}},
-{17349, 18, 66199, {1, 1, 1, 3, 23, 17, 59, 209, 229, 151, 1199, 279, 191, 8993, 25939, 13885, 113477, 166961}},
-{17350, 18, 66206, {1, 3, 5, 1, 19, 61, 27, 129, 103, 721, 1451, 2803, 5879, 3523, 15443, 4047, 95927, 50339}},
-{17351, 18, 66222, {1, 1, 1, 11, 27, 9, 53, 47, 331, 185, 1337, 3429, 807, 3341, 14871, 11035, 50651, 243843}},
-{17352, 18, 66227, {1, 3, 5, 11, 7, 57, 125, 15, 271, 811, 1873, 3093, 7841, 5761, 19955, 571, 123319, 149465}},
-{17353, 18, 66241, {1, 3, 1, 3, 31, 61, 71, 47, 477, 273, 167, 1069, 3513, 1463, 2667, 22097, 60367, 246045}},
-{17354, 18, 66272, {1, 1, 1, 11, 1, 55, 35, 233, 37, 659, 1517, 411, 2981, 10339, 21857, 33701, 44393, 6861}},
-{17355, 18, 66324, {1, 1, 5, 7, 11, 43, 109, 205, 103, 315, 1925, 2109, 6307, 7915, 19793, 61167, 27963, 251913}},
-{17356, 18, 66424, {1, 1, 5, 11, 5, 63, 107, 219, 53, 251, 1053, 2035, 77, 15885, 22011, 3945, 91, 204899}},
-{17357, 18, 66460, {1, 3, 7, 13, 21, 45, 51, 53, 99, 831, 1421, 3171, 4241, 14105, 26161, 45071, 2813, 54339}},
-{17358, 18, 66464, {1, 3, 5, 1, 3, 61, 43, 141, 355, 699, 11, 2203, 8055, 14815, 24597, 65201, 32689, 70167}},
-{17359, 18, 66481, {1, 3, 1, 5, 11, 27, 109, 239, 199, 23, 375, 1477, 3197, 4401, 29901, 46623, 79593, 133143}},
-{17360, 18, 66482, {1, 1, 1, 3, 23, 9, 63, 103, 41, 177, 1365, 1971, 5937, 13055, 27713, 13535, 47371, 57841}},
-{17361, 18, 66523, {1, 1, 5, 5, 19, 15, 5, 21, 307, 65, 215, 3801, 4149, 6565, 10249, 63541, 30867, 12129}},
-{17362, 18, 66526, {1, 3, 3, 9, 11, 1, 107, 99, 235, 331, 1479, 1365, 2557, 9545, 25767, 12461, 6471, 184643}},
-{17363, 18, 66532, {1, 3, 3, 5, 17, 13, 103, 223, 95, 955, 1479, 1825, 705, 5311, 28531, 22787, 118899, 181829}},
-{17364, 18, 66539, {1, 3, 7, 1, 5, 59, 65, 11, 251, 419, 659, 2559, 5445, 4221, 5871, 51845, 33925, 167037}},
-{17365, 18, 66541, {1, 3, 5, 13, 15, 45, 35, 181, 325, 293, 1897, 3321, 6081, 9919, 27641, 9407, 35263, 231009}},
-{17366, 18, 66573, {1, 3, 3, 3, 3, 35, 85, 33, 293, 777, 1945, 3771, 6967, 12353, 2737, 12501, 127359, 163591}},
-{17367, 18, 66582, {1, 3, 7, 9, 13, 7, 119, 107, 309, 811, 1113, 2465, 4867, 4295, 565, 59159, 94587, 119761}},
-{17368, 18, 66591, {1, 3, 3, 1, 1, 31, 61, 49, 461, 635, 233, 175, 6237, 10463, 17847, 54925, 115675, 260575}},
-{17369, 18, 66615, {1, 3, 5, 15, 25, 17, 61, 155, 235, 483, 1771, 2903, 3163, 2525, 17153, 54701, 49521, 11911}},
-{17370, 18, 66622, {1, 3, 3, 5, 1, 35, 51, 23, 187, 107, 177, 1381, 165, 6149, 10841, 3619, 107811, 188811}},
-{17371, 18, 66629, {1, 1, 5, 9, 7, 35, 5, 233, 43, 913, 939, 2195, 1369, 5355, 7941, 26075, 66813, 227623}},
-{17372, 18, 66641, {1, 3, 7, 11, 5, 43, 97, 211, 427, 875, 1179, 3631, 7989, 2419, 17209, 15789, 128209, 224117}},
-{17373, 18, 66712, {1, 1, 1, 7, 17, 7, 109, 255, 111, 883, 371, 3481, 6031, 14665, 5905, 28735, 113003, 327}},
-{17374, 18, 66724, {1, 3, 5, 3, 5, 61, 7, 155, 87, 861, 39, 3163, 179, 15493, 16403, 18755, 116157, 233185}},
-{17375, 18, 66731, {1, 3, 5, 5, 23, 45, 67, 205, 395, 417, 1235, 669, 5097, 6823, 31483, 61395, 36073, 24183}},
-{17376, 18, 66745, {1, 1, 3, 1, 11, 35, 123, 171, 125, 759, 197, 907, 2273, 3623, 31861, 60071, 91857, 158011}},
-{17377, 18, 66759, {1, 3, 7, 11, 19, 19, 25, 25, 167, 429, 1565, 3179, 5453, 15731, 30727, 32111, 63685, 113309}},
-{17378, 18, 66808, {1, 3, 7, 9, 15, 33, 67, 225, 495, 19, 1881, 1357, 4311, 9547, 18717, 20749, 8819, 209979}},
-{17379, 18, 66814, {1, 3, 5, 3, 13, 47, 107, 153, 461, 815, 1521, 2361, 7721, 10631, 2799, 62321, 59755, 170803}},
-{17380, 18, 66821, {1, 3, 7, 5, 25, 61, 5, 235, 71, 349, 1555, 3419, 1159, 2027, 17391, 29849, 47145, 122057}},
-{17381, 18, 66831, {1, 1, 5, 11, 19, 19, 101, 45, 333, 553, 1431, 4077, 2629, 15997, 19793, 65521, 124287, 174675}},
-{17382, 18, 66834, {1, 3, 7, 11, 25, 39, 103, 219, 375, 27, 227, 1061, 445, 14803, 18883, 49191, 33303, 114467}},
-{17383, 18, 66879, {1, 1, 5, 7, 3, 13, 117, 29, 387, 891, 371, 2199, 7023, 13671, 26291, 61563, 2733, 16093}},
-{17384, 18, 66884, {1, 3, 5, 11, 29, 5, 17, 249, 149, 777, 1817, 319, 19, 12321, 15241, 29069, 58381, 157467}},
-{17385, 18, 66899, {1, 3, 7, 9, 29, 17, 81, 141, 201, 383, 429, 3675, 69, 8155, 22821, 60707, 127015, 248279}},
-{17386, 18, 66901, {1, 3, 7, 9, 25, 5, 11, 27, 423, 987, 99, 3599, 4849, 4513, 32119, 34301, 6327, 249457}},
-{17387, 18, 66924, {1, 3, 3, 7, 13, 25, 71, 227, 307, 985, 665, 3097, 6713, 3823, 6357, 58199, 84057, 28055}},
-{17388, 18, 66929, {1, 3, 5, 7, 19, 21, 93, 45, 159, 527, 493, 59, 1111, 1415, 1949, 28525, 50343, 11039}},
-{17389, 18, 66942, {1, 3, 5, 13, 17, 35, 79, 229, 449, 533, 235, 3445, 8153, 15473, 12975, 53909, 24589, 237049}},
-{17390, 18, 66985, {1, 1, 7, 5, 3, 53, 93, 33, 339, 423, 497, 2691, 6125, 3931, 25357, 27509, 92509, 227209}},
-{17391, 18, 66986, {1, 1, 7, 3, 13, 49, 111, 179, 449, 279, 827, 1481, 2477, 6867, 18079, 6261, 30885, 205675}},
-{17392, 18, 66994, {1, 3, 7, 7, 11, 9, 13, 105, 367, 639, 1307, 1617, 4759, 8387, 8909, 13715, 56599, 113259}},
-{17393, 18, 67066, {1, 1, 3, 3, 15, 17, 103, 125, 205, 67, 999, 3965, 907, 13235, 15275, 58457, 66889, 227279}},
-{17394, 18, 67075, {1, 3, 3, 3, 11, 35, 99, 81, 421, 75, 1757, 2413, 5655, 1227, 4019, 14503, 20719, 224807}},
-{17395, 18, 67099, {1, 1, 7, 11, 17, 17, 109, 203, 331, 813, 987, 2925, 1601, 13617, 29, 8235, 95129, 117987}},
-{17396, 18, 67130, {1, 3, 7, 5, 5, 33, 105, 191, 183, 899, 1949, 2923, 2473, 3435, 8097, 35615, 10109, 62563}},
-{17397, 18, 67173, {1, 1, 7, 13, 5, 25, 21, 159, 487, 415, 1507, 2161, 649, 14425, 2605, 8357, 92441, 87323}},
-{17398, 18, 67183, {1, 3, 7, 15, 3, 23, 87, 209, 407, 765, 975, 3859, 675, 6351, 18703, 44919, 57155, 134961}},
-{17399, 18, 67186, {1, 3, 5, 15, 7, 59, 77, 37, 235, 565, 1707, 3531, 6733, 2223, 12621, 59523, 83547, 172355}},
-{17400, 18, 67197, {1, 3, 7, 5, 23, 15, 57, 217, 151, 333, 1033, 2549, 303, 1455, 5329, 20187, 55415, 166093}},
-{17401, 18, 67201, {1, 3, 1, 13, 21, 27, 1, 85, 335, 201, 135, 2603, 291, 10573, 28411, 1059, 129871, 98303}},
-{17402, 18, 67208, {1, 1, 3, 5, 23, 61, 123, 169, 503, 629, 711, 2795, 2291, 13273, 32703, 63377, 72809, 214927}},
-{17403, 18, 67221, {1, 3, 5, 13, 31, 11, 115, 133, 443, 709, 263, 3739, 2777, 11545, 19137, 61285, 64065, 214477}},
-{17404, 18, 67238, {1, 3, 1, 11, 29, 25, 3, 5, 385, 613, 1277, 1445, 1643, 15137, 28041, 47713, 122051, 62915}},
-{17405, 18, 67252, {1, 3, 5, 11, 3, 11, 1, 137, 457, 577, 783, 1745, 5, 5817, 26569, 50751, 14075, 246219}},
-{17406, 18, 67256, {1, 1, 1, 9, 7, 9, 105, 27, 167, 939, 799, 2773, 6427, 15579, 1975, 10695, 111429, 227105}},
-{17407, 18, 67270, {1, 3, 1, 11, 23, 23, 73, 103, 103, 61, 1743, 3061, 8127, 15893, 21223, 43549, 103659, 89129}},
-{17408, 18, 67288, {1, 1, 7, 13, 5, 43, 59, 235, 139, 961, 839, 3843, 1317, 4903, 21043, 15479, 115065, 112531}},
-{17409, 18, 67318, {1, 3, 1, 3, 19, 15, 57, 145, 193, 321, 1919, 385, 125, 15517, 14243, 62845, 38995, 120045}},
-{17410, 18, 67329, {1, 3, 3, 7, 17, 61, 77, 75, 267, 203, 1911, 2599, 1797, 761, 28101, 58603, 107755, 158689}},
-{17411, 18, 67349, {1, 1, 5, 11, 15, 21, 71, 227, 377, 361, 2013, 129, 6271, 1421, 6009, 52261, 113389, 74915}},
-{17412, 18, 67369, {1, 1, 5, 7, 3, 39, 27, 49, 97, 885, 651, 1633, 3445, 3415, 20167, 26667, 52997, 221391}},
-{17413, 18, 67392, {1, 1, 7, 9, 7, 59, 95, 127, 479, 871, 845, 2951, 673, 6385, 10057, 2605, 78529, 230771}},
-{17414, 18, 67435, {1, 3, 5, 7, 31, 15, 53, 125, 223, 711, 875, 429, 7237, 4005, 2153, 26865, 63205, 144125}},
-{17415, 18, 67473, {1, 1, 7, 9, 1, 57, 19, 189, 67, 423, 1937, 37, 4925, 15503, 25969, 20419, 59921, 58119}},
-{17416, 18, 67496, {1, 1, 7, 7, 31, 51, 99, 189, 21, 1011, 1551, 3529, 7617, 15805, 11365, 43123, 84785, 203703}},
-{17417, 18, 67507, {1, 1, 3, 15, 3, 63, 9, 67, 399, 151, 253, 1839, 1365, 16295, 13145, 29211, 48681, 177643}},
-{17418, 18, 67514, {1, 1, 1, 5, 13, 37, 1, 21, 435, 483, 939, 535, 1505, 10879, 7027, 5599, 63261, 158573}},
-{17419, 18, 67536, {1, 1, 7, 15, 13, 39, 113, 209, 213, 1017, 1197, 285, 4221, 6831, 13383, 2265, 34313, 160879}},
-{17420, 18, 67555, {1, 3, 7, 15, 25, 23, 95, 217, 141, 681, 451, 1275, 4957, 10197, 21375, 50905, 11087, 96135}},
-{17421, 18, 67598, {1, 3, 1, 11, 17, 35, 87, 15, 57, 777, 1429, 615, 681, 8437, 23981, 51781, 112169, 198471}},
-{17422, 18, 67615, {1, 3, 1, 5, 21, 37, 113, 105, 123, 327, 549, 1641, 7697, 2127, 5709, 8351, 56787, 260157}},
-{17423, 18, 67625, {1, 3, 7, 15, 19, 17, 51, 15, 367, 89, 1635, 353, 4855, 1551, 7197, 27403, 11259, 176029}},
-{17424, 18, 67645, {1, 3, 1, 1, 27, 9, 3, 35, 213, 31, 885, 797, 7077, 15641, 22509, 35193, 112411, 157335}},
-{17425, 18, 67651, {1, 1, 5, 1, 5, 9, 101, 149, 169, 581, 1927, 197, 5935, 6361, 3915, 15541, 69575, 102451}},
-{17426, 18, 67663, {1, 3, 3, 13, 23, 63, 45, 205, 271, 17, 707, 937, 2547, 12019, 8559, 26163, 58117, 138625}},
-{17427, 18, 67672, {1, 1, 3, 1, 19, 63, 125, 175, 253, 629, 1121, 3701, 7755, 61, 13037, 39417, 6179, 261923}},
-{17428, 18, 67682, {1, 1, 5, 1, 25, 63, 27, 245, 371, 657, 157, 3821, 3279, 8977, 9065, 35611, 27325, 205737}},
-{17429, 18, 67699, {1, 3, 7, 15, 7, 57, 19, 191, 1, 927, 1379, 2579, 4335, 7163, 4877, 51435, 17309, 100173}},
-{17430, 18, 67718, {1, 1, 1, 5, 21, 59, 107, 195, 317, 691, 541, 69, 7235, 2175, 25191, 23913, 126369, 9263}},
-{17431, 18, 67780, {1, 3, 5, 15, 17, 7, 67, 27, 263, 855, 1065, 973, 6705, 10729, 8719, 32741, 59207, 249107}},
-{17432, 18, 67795, {1, 3, 1, 1, 21, 23, 115, 119, 351, 207, 1691, 1105, 7479, 3877, 24439, 29017, 34171, 133797}},
-{17433, 18, 67804, {1, 3, 3, 3, 11, 23, 39, 165, 99, 1023, 309, 3933, 4235, 3891, 27237, 30887, 34363, 175017}},
-{17434, 18, 67818, {1, 3, 1, 5, 17, 33, 79, 105, 253, 515, 823, 1783, 1523, 2095, 10355, 8929, 51001, 112815}},
-{17435, 18, 67832, {1, 3, 7, 15, 11, 27, 123, 161, 279, 541, 1343, 1009, 6015, 8565, 27031, 233, 2153, 179243}},
-{17436, 18, 67941, {1, 1, 7, 7, 1, 53, 1, 33, 75, 57, 723, 3855, 3301, 14941, 6637, 25181, 103441, 208339}},
-{17437, 18, 67984, {1, 3, 7, 13, 3, 23, 11, 75, 55, 19, 1181, 3451, 4901, 2621, 18323, 42395, 95701, 237753}},
-{17438, 18, 68044, {1, 1, 1, 5, 1, 1, 123, 203, 367, 71, 1897, 295, 6719, 2647, 7135, 34511, 79853, 58351}},
-{17439, 18, 68059, {1, 3, 3, 7, 7, 63, 87, 91, 223, 265, 927, 3843, 1703, 11633, 8077, 26425, 46573, 181201}},
-{17440, 18, 68062, {1, 3, 3, 3, 1, 51, 3, 99, 37, 251, 1739, 2813, 3955, 8745, 4425, 42419, 124177, 173997}},
-{17441, 18, 68065, {1, 3, 5, 15, 9, 19, 11, 207, 123, 287, 1703, 2155, 2729, 4541, 4925, 4735, 77159, 97911}},
-{17442, 18, 68071, {1, 3, 3, 15, 23, 31, 35, 33, 507, 315, 1071, 3001, 7569, 11749, 3183, 6989, 68637, 177803}},
-{17443, 18, 68072, {1, 3, 5, 1, 31, 1, 113, 39, 295, 263, 1113, 619, 5523, 15385, 24115, 24233, 91943, 129299}},
-{17444, 18, 68085, {1, 1, 5, 11, 9, 57, 89, 49, 67, 601, 1277, 2275, 6349, 4141, 28397, 47061, 28143, 126291}},
-{17445, 18, 68090, {1, 3, 7, 15, 11, 63, 123, 187, 305, 1009, 1509, 2569, 2235, 8233, 27351, 53437, 34353, 105799}},
-{17446, 18, 68101, {1, 1, 3, 1, 13, 9, 11, 169, 427, 171, 1031, 633, 4275, 1173, 11233, 57997, 107753, 257337}},
-{17447, 18, 68102, {1, 3, 5, 5, 3, 39, 49, 233, 309, 999, 1275, 85, 1663, 16275, 9145, 18439, 59055, 249657}},
-{17448, 18, 68106, {1, 1, 3, 7, 11, 55, 73, 75, 115, 397, 945, 3657, 6847, 7341, 21305, 30119, 65675, 169281}},
-{17449, 18, 68164, {1, 1, 7, 7, 3, 5, 31, 179, 183, 479, 329, 217, 1077, 6893, 23425, 21903, 34293, 184819}},
-{17450, 18, 68191, {1, 1, 3, 3, 7, 63, 97, 255, 289, 917, 1881, 3829, 2433, 3473, 11045, 37739, 73349, 171899}},
-{17451, 18, 68192, {1, 3, 5, 5, 27, 23, 61, 151, 353, 667, 1889, 2323, 3261, 15999, 24225, 35265, 97301, 75743}},
-{17452, 18, 68195, {1, 3, 7, 1, 19, 41, 81, 61, 461, 275, 131, 2665, 5615, 1719, 21047, 42025, 97725, 196587}},
-{17453, 18, 68209, {1, 1, 7, 11, 3, 5, 47, 107, 397, 237, 1795, 3049, 5317, 14147, 15299, 50469, 83855, 75685}},
-{17454, 18, 68245, {1, 1, 7, 7, 19, 31, 39, 153, 225, 591, 1547, 3755, 3219, 15823, 4015, 30977, 63999, 198023}},
-{17455, 18, 68246, {1, 3, 1, 1, 17, 57, 91, 3, 425, 465, 735, 719, 2955, 3003, 6669, 14335, 32137, 82265}},
-{17456, 18, 68274, {1, 3, 1, 9, 13, 25, 93, 187, 119, 735, 447, 3387, 5111, 6525, 28241, 37643, 99023, 58551}},
-{17457, 18, 68293, {1, 1, 7, 1, 23, 15, 105, 89, 109, 743, 2007, 3131, 4839, 3285, 14681, 47097, 69531, 104647}},
-{17458, 18, 68294, {1, 1, 5, 7, 27, 33, 85, 109, 165, 569, 511, 3223, 2201, 2869, 30457, 42585, 125187, 83115}},
-{17459, 18, 68322, {1, 1, 7, 13, 1, 39, 55, 69, 279, 757, 425, 1317, 2403, 10711, 3341, 33491, 5607, 214161}},
-{17460, 18, 68353, {1, 3, 3, 9, 23, 57, 109, 9, 473, 323, 1371, 657, 5039, 1947, 12787, 29099, 81887, 44039}},
-{17461, 18, 68359, {1, 3, 1, 9, 21, 49, 39, 71, 493, 611, 1465, 3965, 7509, 5315, 4095, 21865, 123533, 148467}},
-{17462, 18, 68377, {1, 1, 7, 5, 15, 45, 67, 109, 143, 423, 205, 849, 1291, 245, 26275, 62873, 69177, 173705}},
-{17463, 18, 68401, {1, 3, 7, 13, 3, 13, 103, 45, 171, 919, 903, 2171, 5025, 14855, 895, 36937, 37643, 30311}},
-{17464, 18, 68422, {1, 3, 1, 5, 31, 35, 67, 111, 201, 183, 375, 905, 5705, 8839, 31551, 22525, 53013, 34189}},
-{17465, 18, 68434, {1, 1, 3, 7, 25, 11, 85, 231, 285, 957, 1731, 1267, 8179, 14195, 18405, 8489, 32503, 86257}},
-{17466, 18, 68443, {1, 3, 7, 5, 29, 7, 73, 15, 501, 909, 1325, 793, 4479, 12137, 30871, 36243, 109781, 7235}},
-{17467, 18, 68445, {1, 1, 3, 15, 13, 13, 75, 221, 497, 921, 1939, 2791, 5277, 6257, 11129, 109, 27549, 44901}},
-{17468, 18, 68476, {1, 1, 7, 3, 21, 9, 35, 113, 101, 15, 545, 2429, 5869, 11379, 14427, 28605, 108313, 220523}},
-{17469, 18, 68492, {1, 3, 5, 5, 21, 31, 79, 101, 11, 687, 609, 3741, 1259, 1529, 10185, 49863, 86529, 5147}},
-{17470, 18, 68504, {1, 3, 1, 5, 5, 49, 105, 213, 435, 201, 511, 525, 5219, 9503, 32023, 25407, 2493, 51165}},
-{17471, 18, 68525, {1, 1, 5, 9, 9, 61, 67, 107, 351, 519, 1373, 1261, 1069, 4325, 9579, 37117, 71759, 17601}},
-{17472, 18, 68540, {1, 1, 7, 7, 27, 63, 63, 229, 239, 291, 1813, 3831, 8091, 2553, 18445, 60707, 88855, 224325}},
-{17473, 18, 68543, {1, 1, 5, 7, 15, 23, 109, 7, 409, 447, 185, 3535, 4643, 13431, 11107, 48771, 95843, 155889}},
-{17474, 18, 68555, {1, 3, 3, 11, 9, 47, 13, 31, 83, 837, 1661, 2283, 299, 13161, 25305, 6079, 107237, 58477}},
-{17475, 18, 68563, {1, 3, 7, 15, 3, 31, 21, 245, 105, 141, 703, 71, 1887, 9345, 15719, 37737, 58431, 195997}},
-{17476, 18, 68576, {1, 1, 1, 13, 25, 21, 23, 67, 349, 581, 1585, 809, 3955, 4621, 25989, 25633, 107229, 193271}},
-{17477, 18, 68581, {1, 1, 5, 3, 15, 57, 111, 147, 243, 575, 851, 3461, 5171, 4203, 21855, 59579, 90509, 16897}},
-{17478, 18, 68617, {1, 1, 5, 13, 5, 45, 83, 59, 253, 261, 1277, 3179, 6397, 4277, 6629, 10979, 55759, 3033}},
-{17479, 18, 68631, {1, 1, 1, 9, 25, 1, 127, 159, 273, 357, 1343, 3209, 649, 6631, 1365, 40813, 98955, 181679}},
-{17480, 18, 68656, {1, 3, 1, 11, 1, 9, 67, 5, 41, 661, 863, 3769, 2737, 7261, 26829, 43093, 113025, 127975}},
-{17481, 18, 68666, {1, 1, 3, 3, 7, 5, 77, 207, 125, 625, 437, 1059, 2635, 1099, 25567, 63759, 97575, 231313}},
-{17482, 18, 68714, {1, 3, 7, 5, 21, 41, 11, 177, 489, 405, 1831, 1373, 6267, 11275, 23613, 55565, 120353, 98771}},
-{17483, 18, 68743, {1, 1, 3, 11, 15, 55, 103, 185, 493, 755, 1235, 3143, 4355, 4887, 11245, 60103, 4023, 184729}},
-{17484, 18, 68761, {1, 3, 1, 1, 23, 5, 103, 117, 269, 101, 2013, 1781, 6445, 8753, 15041, 13993, 28753, 47133}},
-{17485, 18, 68764, {1, 3, 7, 5, 9, 23, 1, 203, 19, 535, 1445, 1713, 5503, 11555, 6195, 35797, 55663, 10187}},
-{17486, 18, 68767, {1, 3, 5, 1, 15, 3, 125, 225, 447, 269, 1663, 1823, 4309, 12243, 16689, 3889, 41111, 123355}},
-{17487, 18, 68768, {1, 1, 1, 5, 21, 33, 83, 147, 243, 101, 1085, 121, 4939, 6081, 22621, 52995, 103047, 82531}},
-{17488, 18, 68786, {1, 3, 5, 3, 21, 3, 5, 81, 431, 191, 1973, 3675, 6691, 8687, 31619, 51669, 95541, 110447}},
-{17489, 18, 68788, {1, 1, 1, 15, 1, 11, 83, 145, 75, 133, 967, 2837, 5111, 6099, 9119, 53661, 128647, 40557}},
-{17490, 18, 68848, {1, 1, 1, 7, 3, 57, 101, 231, 255, 117, 1903, 2133, 3867, 11299, 647, 58853, 22153, 135959}},
-{17491, 18, 68851, {1, 3, 5, 5, 9, 19, 89, 229, 313, 421, 201, 953, 2487, 6283, 1305, 33421, 20933, 164841}},
-{17492, 18, 68914, {1, 1, 3, 3, 1, 45, 93, 165, 343, 577, 1329, 3019, 2727, 14397, 7123, 63347, 45525, 35133}},
-{17493, 18, 68946, {1, 3, 5, 5, 19, 1, 33, 55, 49, 1003, 1567, 2539, 7461, 14641, 7655, 37499, 65525, 84961}},
-{17494, 18, 68952, {1, 3, 5, 5, 29, 3, 77, 39, 251, 791, 215, 3779, 1589, 3577, 22299, 24133, 105449, 257157}},
-{17495, 18, 68973, {1, 3, 1, 5, 7, 23, 109, 209, 35, 571, 1047, 3453, 3657, 11713, 19379, 57101, 29943, 60909}},
-{17496, 18, 69001, {1, 1, 7, 11, 17, 63, 15, 175, 333, 831, 1447, 1991, 3339, 2519, 30127, 51481, 71935, 144995}},
-{17497, 18, 69016, {1, 3, 1, 11, 13, 51, 17, 67, 43, 209, 789, 1285, 5655, 5841, 10203, 32053, 15721, 211725}},
-{17498, 18, 69035, {1, 1, 5, 7, 31, 49, 69, 255, 325, 819, 1769, 1961, 7403, 1241, 2241, 40425, 14839, 178969}},
-{17499, 18, 69037, {1, 1, 3, 9, 1, 5, 9, 35, 167, 865, 337, 1079, 6195, 10139, 19215, 57607, 122437, 197147}},
-{17500, 18, 69049, {1, 1, 1, 15, 23, 7, 47, 155, 345, 547, 333, 3747, 961, 1397, 17067, 33385, 48253, 138611}},
-{17501, 18, 69052, {1, 1, 7, 9, 29, 27, 81, 183, 153, 171, 1125, 1929, 1047, 12463, 1543, 42981, 126163, 203259}},
-{17502, 18, 69058, {1, 1, 5, 3, 1, 41, 123, 213, 7, 179, 1, 3527, 1437, 3545, 2025, 5325, 27097, 187823}},
-{17503, 18, 69063, {1, 1, 7, 1, 19, 5, 111, 251, 431, 91, 1437, 1155, 335, 9587, 18287, 23937, 123331, 3939}},
-{17504, 18, 69075, {1, 1, 1, 9, 13, 59, 75, 219, 225, 313, 525, 2003, 7829, 7063, 22123, 4263, 95491, 9375}},
-{17505, 18, 69112, {1, 3, 1, 1, 27, 29, 71, 189, 169, 301, 165, 2967, 5147, 7127, 2191, 34259, 66605, 149603}},
-{17506, 18, 69117, {1, 3, 5, 13, 29, 57, 105, 31, 495, 311, 1161, 2109, 1471, 1275, 12761, 58379, 46365, 229935}},
-{17507, 18, 69124, {1, 1, 7, 3, 7, 49, 125, 189, 309, 399, 1361, 3969, 2177, 8171, 26623, 41855, 2809, 5825}},
-{17508, 18, 69127, {1, 3, 5, 7, 17, 21, 77, 101, 37, 661, 1743, 2243, 823, 12431, 26931, 7163, 108093, 191305}},
-{17509, 18, 69134, {1, 1, 7, 5, 27, 55, 109, 119, 13, 727, 421, 3469, 1137, 6125, 5107, 52733, 102891, 147425}},
-{17510, 18, 69139, {1, 1, 3, 5, 17, 45, 17, 211, 137, 21, 689, 1487, 233, 9845, 6499, 52617, 73081, 198137}},
-{17511, 18, 69161, {1, 3, 7, 1, 25, 27, 67, 7, 161, 633, 729, 807, 7371, 7301, 29499, 45939, 110565, 219491}},
-{17512, 18, 69196, {1, 3, 3, 13, 17, 7, 55, 211, 103, 981, 1809, 1913, 5705, 14011, 7405, 13893, 92053, 17997}},
-{17513, 18, 69224, {1, 1, 1, 1, 15, 9, 75, 37, 5, 443, 157, 2749, 5587, 16087, 14953, 26793, 21229, 226879}},
-{17514, 18, 69238, {1, 3, 3, 3, 9, 13, 113, 7, 255, 647, 235, 1713, 525, 8579, 20873, 49565, 43869, 145823}},
-{17515, 18, 69301, {1, 1, 5, 15, 9, 1, 119, 189, 73, 321, 1045, 467, 1565, 14381, 22683, 7939, 44337, 231901}},
-{17516, 18, 69316, {1, 1, 3, 13, 21, 61, 35, 105, 425, 395, 381, 1205, 3631, 8099, 23723, 29435, 94683, 180367}},
-{17517, 18, 69325, {1, 3, 3, 13, 19, 15, 59, 111, 355, 165, 857, 3131, 5037, 2527, 17533, 53563, 621, 89837}},
-{17518, 18, 69334, {1, 3, 3, 11, 11, 41, 3, 75, 179, 325, 897, 3141, 75, 1735, 493, 1123, 126763, 68645}},
-{17519, 18, 69347, {1, 3, 5, 7, 19, 61, 9, 99, 101, 583, 1967, 621, 1869, 10693, 2025, 62797, 85727, 212309}},
-{17520, 18, 69359, {1, 3, 1, 13, 23, 47, 15, 29, 199, 889, 423, 3995, 1655, 10753, 25301, 55551, 94829, 205833}},
-{17521, 18, 69381, {1, 1, 1, 1, 21, 1, 91, 237, 195, 721, 881, 1155, 4109, 10367, 1873, 6851, 13295, 182363}},
-{17522, 18, 69388, {1, 1, 5, 15, 19, 35, 37, 197, 137, 255, 93, 681, 949, 15183, 24785, 39357, 65547, 149013}},
-{17523, 18, 69393, {1, 3, 3, 3, 27, 27, 95, 239, 171, 513, 655, 1629, 4577, 3005, 1681, 2581, 59995, 83981}},
-{17524, 18, 69409, {1, 3, 3, 7, 29, 33, 111, 85, 437, 297, 1563, 2411, 6171, 2043, 17625, 59093, 995, 211599}},
-{17525, 18, 69422, {1, 3, 1, 13, 19, 35, 33, 9, 57, 153, 819, 2017, 5879, 13559, 23135, 25981, 41091, 50975}},
-{17526, 18, 69453, {1, 3, 5, 11, 23, 53, 11, 123, 119, 57, 1775, 3457, 7939, 4999, 10771, 23571, 30099, 17361}},
-{17527, 18, 69459, {1, 1, 7, 11, 27, 13, 7, 215, 7, 1009, 1967, 1845, 6679, 13781, 21797, 18755, 47131, 245907}},
-{17528, 18, 69481, {1, 1, 1, 3, 19, 47, 35, 13, 287, 349, 439, 3125, 2387, 12483, 3833, 29399, 27037, 30235}},
-{17529, 18, 69487, {1, 3, 1, 15, 17, 41, 15, 21, 499, 87, 1899, 2835, 1919, 925, 4525, 12935, 25021, 106657}},
-{17530, 18, 69490, {1, 1, 1, 13, 17, 59, 73, 75, 443, 199, 1871, 3447, 4517, 8395, 16661, 30655, 17871, 231337}},
-{17531, 18, 69495, {1, 1, 7, 1, 1, 53, 17, 49, 259, 77, 917, 631, 6061, 12291, 17715, 49761, 70699, 68313}},
-{17532, 18, 69501, {1, 1, 3, 9, 13, 27, 67, 149, 229, 347, 1397, 3457, 6047, 13117, 11, 18121, 70323, 36441}},
-{17533, 18, 69511, {1, 3, 5, 7, 27, 13, 69, 177, 451, 87, 647, 3797, 5433, 3137, 20213, 9809, 126877, 55243}},
-{17534, 18, 69512, {1, 3, 7, 13, 21, 57, 73, 157, 173, 631, 1527, 337, 5605, 8041, 2181, 19567, 19829, 63353}},
-{17535, 18, 69532, {1, 3, 3, 7, 11, 5, 111, 161, 247, 553, 435, 3883, 5639, 10889, 8953, 58297, 15197, 99711}},
-{17536, 18, 69542, {1, 1, 7, 13, 11, 29, 71, 251, 387, 1003, 1275, 763, 67, 10597, 5995, 53677, 4683, 2157}},
-{17537, 18, 69560, {1, 1, 3, 9, 23, 27, 93, 209, 325, 517, 297, 3215, 4359, 395, 10377, 36967, 69803, 190037}},
-{17538, 18, 69565, {1, 1, 1, 3, 27, 61, 21, 229, 469, 3, 387, 523, 4753, 2267, 9879, 32113, 60837, 76205}},
-{17539, 18, 69571, {1, 3, 1, 7, 31, 31, 67, 15, 161, 699, 713, 2973, 2007, 693, 21823, 57549, 28989, 157879}},
-{17540, 18, 69611, {1, 3, 1, 1, 3, 63, 111, 61, 311, 685, 1029, 345, 6763, 16217, 14505, 9777, 3513, 160985}},
-{17541, 18, 69633, {1, 1, 1, 11, 5, 25, 13, 79, 337, 3, 1997, 3489, 7621, 12115, 9221, 7953, 19067, 52697}},
-{17542, 18, 69640, {1, 1, 1, 3, 19, 3, 85, 127, 475, 391, 293, 2249, 1211, 1185, 17133, 6753, 65517, 98157}},
-{17543, 18, 69667, {1, 1, 5, 9, 11, 31, 57, 107, 315, 983, 1117, 2189, 4813, 9925, 26635, 30589, 32989, 44195}},
-{17544, 18, 69669, {1, 1, 7, 7, 21, 1, 1, 221, 421, 199, 539, 3981, 4627, 15655, 12621, 20427, 11619, 187185}},
-{17545, 18, 69679, {1, 1, 7, 5, 13, 19, 49, 31, 55, 35, 1847, 3173, 475, 15245, 30907, 50075, 130837, 87283}},
-{17546, 18, 69688, {1, 1, 7, 15, 13, 47, 13, 17, 169, 185, 1411, 1689, 2339, 2159, 10591, 52283, 26785, 255707}},
-{17547, 18, 69699, {1, 3, 5, 7, 3, 29, 7, 83, 329, 747, 1755, 1067, 2565, 2437, 12309, 15043, 97589, 69409}},
-{17548, 18, 69756, {1, 3, 3, 9, 19, 49, 9, 231, 427, 131, 485, 1637, 1129, 14723, 19071, 47997, 74613, 171539}},
-{17549, 18, 69759, {1, 1, 1, 1, 5, 17, 105, 39, 313, 407, 1321, 3013, 8035, 4395, 15917, 21105, 53599, 21341}},
-{17550, 18, 69770, {1, 3, 1, 15, 7, 35, 5, 153, 485, 1019, 713, 1891, 5023, 13885, 15911, 48215, 81719, 228189}},
-{17551, 18, 69772, {1, 1, 3, 3, 19, 3, 103, 55, 221, 847, 27, 1653, 4887, 3617, 30235, 42353, 67007, 21443}},
-{17552, 18, 69826, {1, 1, 7, 15, 15, 39, 65, 189, 251, 411, 1953, 1187, 141, 14919, 7763, 50879, 2569, 63467}},
-{17553, 18, 69840, {1, 1, 7, 1, 15, 3, 37, 133, 11, 745, 697, 3755, 1233, 2009, 25597, 40661, 40743, 198117}},
-{17554, 18, 69846, {1, 1, 7, 15, 5, 17, 13, 253, 197, 491, 1499, 2141, 6803, 13833, 27297, 385, 54341, 64305}},
-{17555, 18, 69868, {1, 3, 5, 7, 3, 11, 19, 193, 441, 575, 1649, 1821, 2621, 15803, 7343, 37361, 16467, 60629}},
-{17556, 18, 69885, {1, 3, 3, 11, 11, 29, 109, 1, 83, 475, 1913, 1975, 1289, 5221, 24221, 7479, 26683, 203435}},
-{17557, 18, 69946, {1, 1, 3, 13, 3, 35, 119, 131, 323, 413, 147, 4009, 3167, 11161, 30523, 65223, 109859, 239317}},
-{17558, 18, 69966, {1, 3, 1, 11, 25, 17, 103, 165, 437, 163, 1141, 105, 3655, 8105, 20859, 50727, 27915, 19309}},
-{17559, 18, 69973, {1, 3, 3, 11, 9, 59, 17, 135, 131, 781, 675, 2865, 7287, 11431, 3717, 56691, 54971, 83433}},
-{17560, 18, 69977, {1, 1, 1, 11, 3, 1, 59, 35, 299, 927, 1761, 823, 287, 13271, 30321, 32895, 45961, 23151}},
-{17561, 18, 69980, {1, 3, 3, 7, 11, 3, 11, 115, 241, 497, 1359, 1789, 6677, 2683, 21145, 58185, 46131, 17591}},
-{17562, 18, 69984, {1, 3, 1, 3, 17, 5, 65, 169, 247, 1001, 1183, 1801, 759, 2797, 28721, 7549, 112463, 127451}},
-{17563, 18, 69994, {1, 1, 1, 11, 1, 49, 5, 227, 333, 793, 759, 2845, 6261, 6325, 6581, 35853, 39737, 21457}},
-{17564, 18, 70024, {1, 1, 1, 3, 7, 17, 81, 105, 453, 207, 1113, 301, 4933, 14715, 18815, 29165, 85251, 209171}},
-{17565, 18, 70044, {1, 3, 1, 13, 3, 25, 7, 109, 249, 649, 1009, 937, 659, 14605, 13325, 26003, 45507, 166837}},
-{17566, 18, 70053, {1, 3, 7, 11, 19, 57, 55, 213, 261, 325, 761, 3167, 6823, 15039, 13329, 30195, 52103, 27877}},
-{17567, 18, 70086, {1, 3, 3, 11, 31, 45, 3, 185, 225, 143, 651, 327, 4263, 6005, 31577, 57779, 90485, 48393}},
-{17568, 18, 70113, {1, 1, 3, 13, 9, 21, 97, 63, 285, 531, 1275, 175, 693, 3735, 15137, 62193, 80533, 196545}},
-{17569, 18, 70120, {1, 1, 1, 11, 5, 25, 101, 111, 101, 17, 1999, 3709, 19, 5087, 20151, 4781, 88417, 186293}},
-{17570, 18, 70131, {1, 1, 5, 7, 31, 37, 39, 85, 451, 189, 1521, 619, 5021, 2601, 32447, 43513, 8317, 170611}},
-{17571, 18, 70150, {1, 1, 7, 1, 25, 45, 33, 111, 443, 719, 1869, 3619, 5751, 2649, 27823, 55465, 113203, 23875}},
-{17572, 18, 70178, {1, 3, 5, 15, 19, 47, 49, 241, 75, 395, 307, 1001, 137, 7029, 21661, 39159, 94129, 106693}},
-{17573, 18, 70198, {1, 3, 7, 1, 7, 35, 85, 27, 285, 975, 565, 2119, 5861, 9229, 15877, 25017, 10551, 155357}},
-{17574, 18, 70227, {1, 3, 3, 5, 29, 41, 17, 159, 211, 571, 907, 1745, 6541, 11643, 4441, 54599, 83359, 57227}},
-{17575, 18, 70285, {1, 3, 7, 5, 19, 11, 37, 191, 75, 443, 1833, 1715, 6949, 2477, 31161, 15647, 84305, 82887}},
-{17576, 18, 70288, {1, 1, 3, 9, 29, 35, 87, 11, 147, 443, 1659, 2457, 1615, 16135, 10729, 31583, 111583, 52607}},
-{17577, 18, 70291, {1, 3, 7, 1, 7, 47, 55, 133, 53, 23, 225, 2689, 3075, 12435, 8337, 37065, 58631, 247415}},
-{17578, 18, 70309, {1, 3, 3, 9, 23, 39, 5, 17, 353, 443, 627, 1609, 5277, 3899, 31111, 5935, 25445, 161043}},
-{17579, 18, 70334, {1, 3, 3, 11, 31, 11, 97, 99, 37, 169, 1361, 689, 5481, 5935, 11957, 36761, 105641, 250905}},
-{17580, 18, 70339, {1, 1, 7, 15, 31, 33, 3, 201, 125, 649, 315, 497, 7715, 2331, 9081, 16073, 88459, 70475}},
-{17581, 18, 70381, {1, 1, 7, 13, 25, 25, 39, 193, 185, 253, 495, 1143, 3745, 3459, 10935, 22029, 70213, 245827}},
-{17582, 18, 70413, {1, 3, 3, 11, 1, 47, 93, 27, 117, 755, 1837, 4045, 4839, 3413, 21395, 41905, 6505, 158029}},
-{17583, 18, 70414, {1, 3, 5, 5, 3, 41, 23, 207, 3, 409, 1635, 3511, 899, 747, 10623, 44933, 62439, 75577}},
-{17584, 18, 70481, {1, 3, 7, 15, 1, 15, 113, 175, 43, 513, 515, 1295, 1903, 9961, 20995, 57319, 40649, 22799}},
-{17585, 18, 70488, {1, 1, 5, 9, 7, 25, 99, 167, 117, 547, 777, 3819, 4409, 13465, 3963, 53355, 67895, 58007}},
-{17586, 18, 70493, {1, 1, 5, 9, 25, 9, 11, 113, 455, 563, 143, 1507, 4055, 6805, 25027, 37645, 475, 193193}},
-{17587, 18, 70515, {1, 1, 1, 11, 15, 27, 123, 199, 229, 27, 1285, 4013, 6541, 11203, 23705, 56821, 59665, 151109}},
-{17588, 18, 70540, {1, 1, 3, 1, 31, 19, 27, 129, 235, 407, 865, 2723, 5387, 7727, 2309, 45787, 118107, 199907}},
-{17589, 18, 70543, {1, 1, 5, 15, 17, 1, 21, 167, 165, 203, 745, 825, 7993, 15191, 13731, 13417, 543, 201511}},
-{17590, 18, 70558, {1, 3, 1, 1, 29, 49, 45, 81, 321, 755, 1319, 633, 4889, 7809, 6305, 58233, 20213, 144915}},
-{17591, 18, 70568, {1, 1, 3, 13, 1, 31, 73, 173, 111, 961, 1995, 3827, 879, 5567, 31103, 13227, 126611, 204507}},
-{17592, 18, 70582, {1, 1, 3, 7, 21, 3, 75, 137, 125, 981, 1991, 1167, 1249, 3821, 19503, 52855, 122329, 68717}},
-{17593, 18, 70593, {1, 1, 1, 13, 17, 17, 69, 167, 327, 635, 427, 2125, 7499, 9715, 24097, 39361, 64301, 63411}},
-{17594, 18, 70596, {1, 1, 1, 1, 31, 57, 55, 31, 289, 251, 823, 2301, 5965, 3381, 479, 39545, 93051, 68683}},
-{17595, 18, 70613, {1, 1, 3, 3, 15, 27, 117, 37, 29, 851, 1891, 3507, 6279, 323, 11451, 57961, 41487, 188359}},
-{17596, 18, 70620, {1, 1, 5, 1, 25, 55, 125, 207, 129, 849, 589, 1381, 3395, 645, 1157, 29285, 105423, 104429}},
-{17597, 18, 70647, {1, 1, 7, 7, 9, 47, 41, 103, 473, 395, 883, 1087, 2827, 9685, 6313, 15461, 39803, 254865}},
-{17598, 18, 70666, {1, 1, 7, 3, 17, 55, 71, 119, 159, 185, 1415, 3033, 3045, 1403, 18349, 2727, 123995, 45953}},
-{17599, 18, 70710, {1, 1, 3, 15, 17, 11, 19, 25, 483, 29, 1329, 1779, 2885, 6655, 28327, 42255, 87555, 211051}},
-{17600, 18, 70719, {1, 3, 5, 11, 29, 19, 43, 141, 157, 87, 1091, 3505, 3139, 11919, 12123, 31581, 116229, 167875}},
-{17601, 18, 70721, {1, 3, 1, 5, 25, 55, 113, 219, 491, 607, 1641, 3833, 3153, 1881, 16027, 39923, 38551, 204819}},
-{17602, 18, 70722, {1, 1, 5, 3, 7, 9, 73, 181, 305, 211, 1699, 983, 3051, 11643, 12445, 44827, 74613, 199699}},
-{17603, 18, 70742, {1, 1, 3, 5, 23, 21, 115, 49, 311, 205, 963, 1357, 4013, 8357, 7065, 47757, 7937, 249935}},
-{17604, 18, 70757, {1, 1, 1, 9, 23, 61, 21, 165, 9, 829, 457, 3975, 5831, 10901, 15871, 36769, 45899, 162083}},
-{17605, 18, 70764, {1, 1, 3, 3, 25, 41, 91, 45, 37, 939, 299, 3815, 6433, 3121, 10585, 62125, 51333, 171615}},
-{17606, 18, 70781, {1, 1, 5, 11, 1, 1, 39, 45, 141, 803, 1493, 1151, 6243, 8683, 30223, 53661, 7949, 197291}},
-{17607, 18, 70795, {1, 1, 3, 1, 17, 35, 29, 253, 395, 933, 1015, 3431, 139, 9095, 30745, 39747, 58837, 28517}},
-{17608, 18, 70803, {1, 1, 5, 3, 21, 17, 105, 21, 249, 387, 1985, 951, 6323, 8221, 24601, 57367, 18751, 240661}},
-{17609, 18, 70809, {1, 1, 7, 9, 5, 21, 23, 149, 243, 501, 935, 855, 1821, 15885, 2239, 39091, 93615, 31411}},
-{17610, 18, 70821, {1, 1, 1, 3, 23, 11, 43, 5, 65, 193, 1723, 3253, 7533, 12987, 571, 56073, 125061, 97117}},
-{17611, 18, 70846, {1, 1, 1, 13, 13, 21, 113, 79, 115, 867, 777, 2199, 501, 2913, 18697, 14959, 18369, 41631}},
-{17612, 18, 70882, {1, 1, 7, 13, 13, 53, 101, 165, 447, 995, 587, 201, 1701, 6429, 8647, 59265, 27321, 110841}},
-{17613, 18, 70887, {1, 3, 1, 3, 25, 35, 67, 95, 173, 877, 1133, 3027, 2321, 12517, 4313, 24469, 40313, 253095}},
-{17614, 18, 70940, {1, 1, 1, 9, 17, 33, 103, 141, 259, 963, 1975, 2979, 5017, 15689, 30659, 55145, 73737, 43539}},
-{17615, 18, 70961, {1, 3, 1, 15, 7, 7, 7, 1, 267, 415, 1591, 17, 2451, 13415, 6993, 16631, 90019, 237161}},
-{17616, 18, 70996, {1, 1, 7, 11, 11, 37, 107, 143, 263, 49, 1391, 3269, 6139, 1413, 26557, 16369, 86789, 89151}},
-{17617, 18, 71012, {1, 1, 7, 13, 27, 41, 3, 169, 453, 547, 157, 3219, 4711, 9805, 10657, 8121, 40229, 247825}},
-{17618, 18, 71046, {1, 3, 3, 3, 25, 25, 109, 253, 67, 901, 259, 1159, 6161, 6763, 19669, 42775, 74089, 69821}},
-{17619, 18, 71057, {1, 3, 7, 15, 11, 25, 91, 137, 247, 851, 511, 1847, 1179, 411, 9545, 31275, 46201, 169677}},
-{17620, 18, 71060, {1, 1, 5, 3, 3, 61, 19, 167, 491, 765, 1997, 3267, 883, 15439, 27581, 24865, 128245, 130055}},
-{17621, 18, 71063, {1, 1, 3, 9, 17, 61, 7, 109, 325, 347, 1109, 889, 2995, 4763, 21551, 60137, 91833, 126989}},
-{17622, 18, 71079, {1, 3, 3, 7, 5, 17, 61, 107, 209, 577, 885, 2611, 1471, 7549, 16199, 12319, 48865, 242229}},
-{17623, 18, 71080, {1, 3, 5, 1, 5, 49, 85, 177, 213, 583, 857, 179, 1805, 4297, 5835, 61923, 22741, 261983}},
-{17624, 18, 71111, {1, 3, 1, 13, 1, 1, 83, 227, 457, 375, 567, 1563, 2085, 8153, 12563, 44561, 115487, 188351}},
-{17625, 18, 71118, {1, 3, 1, 9, 15, 39, 127, 135, 181, 967, 1495, 3187, 7463, 9651, 26261, 57435, 42069, 48549}},
-{17626, 18, 71129, {1, 3, 1, 7, 5, 31, 111, 19, 19, 855, 273, 2089, 6001, 2799, 26013, 6625, 75623, 150185}},
-{17627, 18, 71136, {1, 1, 7, 1, 31, 19, 15, 159, 35, 791, 1005, 3947, 7031, 41, 28807, 45299, 37761, 101191}},
-{17628, 18, 71142, {1, 3, 5, 3, 15, 7, 7, 67, 329, 367, 843, 2309, 3023, 5369, 21561, 18881, 14395, 193369}},
-{17629, 18, 71145, {1, 3, 3, 11, 21, 53, 3, 251, 87, 131, 563, 847, 8049, 1639, 30103, 30461, 108427, 125197}},
-{17630, 18, 71151, {1, 1, 1, 5, 21, 45, 79, 229, 29, 133, 1873, 261, 4221, 3091, 25569, 11219, 70693, 227025}},
-{17631, 18, 71163, {1, 3, 1, 5, 17, 9, 75, 101, 155, 311, 789, 821, 7361, 3791, 18511, 57607, 97647, 42107}},
-{17632, 18, 71218, {1, 3, 1, 11, 21, 39, 33, 179, 7, 775, 55, 3779, 6163, 3575, 27535, 32363, 9169, 57133}},
-{17633, 18, 71223, {1, 3, 7, 3, 19, 33, 19, 11, 173, 175, 219, 3585, 1115, 15693, 23481, 45669, 94149, 19531}},
-{17634, 18, 71232, {1, 1, 5, 11, 11, 49, 29, 217, 229, 757, 1031, 3833, 4235, 13535, 8765, 20707, 52851, 9037}},
-{17635, 18, 71237, {1, 3, 1, 13, 25, 61, 65, 111, 95, 533, 1235, 2947, 3239, 9513, 11395, 9321, 117535, 228289}},
-{17636, 18, 71272, {1, 1, 1, 3, 19, 33, 13, 233, 331, 811, 1931, 1109, 7705, 3129, 19757, 44325, 97903, 165311}},
-{17637, 18, 71323, {1, 1, 3, 15, 13, 55, 57, 81, 257, 613, 1305, 653, 6059, 4935, 15707, 4717, 1859, 109265}},
-{17638, 18, 71339, {1, 1, 7, 15, 15, 19, 19, 91, 213, 311, 1651, 2215, 6985, 2989, 11961, 28647, 111163, 217187}},
-{17639, 18, 71341, {1, 3, 3, 5, 15, 31, 45, 193, 119, 11, 511, 3155, 5989, 813, 32655, 41531, 121007, 24733}},
-{17640, 18, 71349, {1, 3, 7, 1, 19, 63, 61, 11, 225, 677, 1323, 1655, 7607, 15691, 27083, 56743, 116167, 250413}},
-{17641, 18, 71368, {1, 1, 1, 15, 7, 25, 27, 213, 171, 1011, 1483, 119, 6849, 12527, 20601, 35701, 68377, 245669}},
-{17642, 18, 71379, {1, 3, 7, 5, 27, 5, 7, 117, 127, 871, 631, 3395, 1501, 4839, 1857, 45769, 107597, 90385}},
-{17643, 18, 71395, {1, 1, 3, 13, 1, 15, 49, 69, 479, 919, 881, 3069, 5609, 12795, 30225, 14411, 122847, 75569}},
-{17644, 18, 71407, {1, 1, 5, 9, 1, 15, 91, 207, 235, 667, 321, 2047, 841, 16049, 12499, 8799, 8245, 42199}},
-{17645, 18, 71421, {1, 3, 7, 15, 11, 19, 99, 163, 331, 953, 791, 3443, 3215, 8025, 1999, 43685, 72595, 153185}},
-{17646, 18, 71430, {1, 3, 1, 13, 25, 23, 17, 133, 59, 233, 151, 1971, 3611, 3951, 16979, 991, 73325, 158475}},
-{17647, 18, 71436, {1, 3, 5, 11, 1, 53, 123, 81, 285, 457, 1183, 489, 939, 3069, 15845, 24799, 81301, 105187}},
-{17648, 18, 71454, {1, 3, 5, 1, 11, 5, 61, 151, 5, 813, 1347, 1107, 4915, 4035, 18709, 20909, 60569, 55007}},
-{17649, 18, 71467, {1, 3, 3, 7, 27, 41, 79, 193, 471, 415, 937, 2561, 1669, 9213, 21145, 44917, 64763, 33195}},
-{17650, 18, 71472, {1, 3, 7, 13, 31, 5, 71, 237, 419, 957, 1741, 2829, 5879, 8143, 8717, 48995, 114465, 110295}},
-{17651, 18, 71478, {1, 1, 7, 3, 7, 23, 83, 161, 381, 313, 383, 2813, 333, 4647, 18321, 10437, 111645, 55509}},
-{17652, 18, 71481, {1, 1, 5, 9, 23, 1, 83, 121, 245, 37, 1097, 1437, 3891, 2727, 30775, 27649, 95571, 216245}},
-{17653, 18, 71501, {1, 1, 5, 7, 1, 43, 59, 253, 329, 421, 791, 3945, 2599, 2243, 11121, 37761, 27223, 176867}},
-{17654, 18, 71519, {1, 3, 5, 5, 25, 59, 85, 155, 367, 291, 1025, 1415, 7871, 14191, 23249, 32233, 93253, 177869}},
-{17655, 18, 71530, {1, 1, 1, 9, 21, 41, 111, 241, 177, 999, 779, 2827, 1683, 6405, 16133, 26523, 102567, 190313}},
-{17656, 18, 71550, {1, 3, 3, 15, 13, 59, 69, 239, 231, 511, 1675, 147, 4041, 3723, 29191, 24913, 15601, 198141}},
-{17657, 18, 71573, {1, 3, 3, 9, 17, 29, 1, 107, 243, 509, 1949, 205, 1693, 6339, 31591, 61527, 128043, 222497}},
-{17658, 18, 71593, {1, 3, 7, 3, 21, 7, 87, 57, 9, 209, 1831, 2189, 5523, 8509, 23687, 46221, 87469, 146815}},
-{17659, 18, 71608, {1, 3, 7, 9, 5, 45, 51, 207, 401, 681, 469, 1951, 793, 16379, 32143, 55457, 91787, 178569}},
-{17660, 18, 71619, {1, 3, 3, 9, 19, 15, 121, 143, 243, 795, 1839, 2411, 7175, 11535, 31995, 4157, 20111, 92653}},
-{17661, 18, 71622, {1, 3, 1, 1, 1, 5, 47, 107, 455, 429, 1411, 2375, 2823, 14657, 16297, 21893, 115257, 50343}},
-{17662, 18, 71636, {1, 3, 5, 9, 19, 63, 55, 197, 281, 797, 1539, 2601, 4497, 1631, 26583, 23819, 104553, 27285}},
-{17663, 18, 71650, {1, 1, 3, 9, 23, 41, 123, 37, 327, 789, 1711, 1299, 6735, 7243, 30635, 21251, 56081, 65623}},
-{17664, 18, 71655, {1, 3, 7, 15, 25, 49, 89, 231, 133, 1003, 351, 765, 7115, 16239, 1141, 44063, 31519, 233719}},
-{17665, 18, 71685, {1, 3, 7, 3, 13, 37, 93, 83, 59, 539, 1185, 525, 705, 993, 1113, 1871, 60817, 254075}},
-{17666, 18, 71703, {1, 3, 7, 11, 25, 33, 23, 21, 141, 451, 25, 1321, 5139, 8947, 10305, 30175, 43123, 113049}},
-{17667, 18, 71714, {1, 3, 5, 5, 17, 1, 125, 211, 143, 637, 1175, 1149, 6775, 11091, 12503, 5537, 35379, 30045}},
-{17668, 18, 71748, {1, 1, 1, 15, 17, 31, 123, 33, 279, 831, 1247, 2305, 1033, 3201, 231, 23173, 34453, 66617}},
-{17669, 18, 71758, {1, 3, 3, 1, 3, 1, 23, 115, 421, 553, 273, 4091, 5965, 7521, 18393, 31229, 78533, 243921}},
-{17670, 18, 71766, {1, 1, 7, 15, 15, 29, 73, 165, 391, 215, 1801, 45, 7451, 6969, 27897, 36599, 103647, 145165}},
-{17671, 18, 71772, {1, 3, 3, 13, 5, 7, 67, 81, 477, 301, 1397, 921, 3777, 12431, 14753, 50555, 24497, 52995}},
-{17672, 18, 71785, {1, 1, 5, 5, 27, 21, 91, 155, 405, 347, 1135, 3701, 2471, 577, 3927, 52605, 1725, 25803}},
-{17673, 18, 71794, {1, 3, 1, 3, 15, 57, 117, 175, 437, 13, 1821, 649, 899, 1295, 2753, 2183, 47923, 163407}},
-{17674, 18, 71796, {1, 3, 5, 9, 23, 15, 103, 179, 233, 787, 715, 3751, 3321, 2069, 8299, 43417, 96549, 180737}},
-{17675, 18, 71803, {1, 3, 7, 9, 1, 41, 81, 205, 141, 707, 397, 763, 4797, 8843, 3311, 37425, 43873, 131491}},
-{17676, 18, 71809, {1, 1, 5, 3, 9, 29, 123, 163, 15, 871, 159, 2615, 6987, 471, 25653, 11295, 94481, 195409}},
-{17677, 18, 71858, {1, 3, 7, 3, 13, 7, 9, 59, 59, 381, 2027, 2639, 59, 7977, 14505, 34327, 99113, 157439}},
-{17678, 18, 71863, {1, 1, 5, 9, 27, 13, 87, 85, 443, 531, 1069, 3479, 6547, 13943, 13711, 11007, 37395, 190293}},
-{17679, 18, 71878, {1, 3, 7, 9, 19, 47, 95, 229, 395, 979, 359, 1799, 7389, 14377, 19371, 56785, 6699, 215433}},
-{17680, 18, 71895, {1, 1, 1, 5, 21, 15, 59, 17, 281, 585, 293, 3029, 2539, 16089, 19, 34757, 115811, 235565}},
-{17681, 18, 71899, {1, 1, 7, 11, 27, 19, 55, 217, 475, 119, 1291, 1761, 6879, 4355, 30019, 17573, 14987, 204623}},
-{17682, 18, 71906, {1, 1, 7, 11, 29, 47, 5, 201, 165, 845, 385, 2903, 7735, 10855, 14171, 17881, 45001, 100725}},
-{17683, 18, 71908, {1, 1, 5, 5, 31, 57, 99, 35, 315, 363, 1135, 897, 1041, 729, 26987, 15299, 29563, 67293}},
-{17684, 18, 71917, {1, 1, 5, 7, 27, 13, 99, 81, 491, 887, 1309, 3343, 7241, 1289, 12021, 52533, 101799, 238721}},
-{17685, 18, 71952, {1, 1, 1, 11, 27, 49, 79, 235, 49, 215, 2003, 2771, 5943, 1183, 31931, 33885, 56971, 52665}},
-{17686, 18, 71957, {1, 1, 1, 13, 13, 1, 123, 1, 191, 747, 859, 2287, 5113, 3715, 2217, 61483, 195, 237163}},
-{17687, 18, 71961, {1, 3, 7, 15, 13, 13, 17, 207, 141, 821, 231, 1373, 5355, 6503, 2403, 18183, 83717, 170047}},
-{17688, 18, 71973, {1, 3, 1, 3, 13, 11, 41, 51, 443, 201, 1349, 2331, 1009, 16169, 5247, 50315, 15589, 150497}},
-{17689, 18, 71980, {1, 3, 5, 13, 29, 21, 93, 55, 27, 17, 1615, 3473, 3641, 10999, 31955, 4699, 23585, 141243}},
-{17690, 18, 71997, {1, 3, 3, 11, 11, 27, 125, 139, 53, 637, 241, 2651, 4999, 5923, 16203, 13645, 95965, 94459}},
-{17691, 18, 72017, {1, 3, 7, 3, 9, 53, 87, 171, 489, 691, 303, 3599, 6093, 841, 3527, 12953, 22907, 69823}},
-{17692, 18, 72060, {1, 1, 5, 13, 31, 11, 33, 207, 437, 683, 703, 1757, 1443, 14269, 12677, 20877, 46791, 176135}},
-{17693, 18, 72091, {1, 1, 7, 1, 13, 53, 123, 199, 173, 585, 1099, 3653, 2253, 13741, 15675, 38755, 74545, 139053}},
-{17694, 18, 72097, {1, 3, 3, 3, 17, 11, 1, 161, 383, 409, 605, 889, 827, 263, 9677, 42857, 127691, 99621}},
-{17695, 18, 72166, {1, 3, 5, 9, 21, 21, 11, 151, 199, 695, 493, 569, 881, 10533, 11255, 61997, 124921, 211139}},
-{17696, 18, 72172, {1, 3, 5, 5, 9, 47, 109, 7, 195, 287, 97, 3691, 6929, 6985, 3063, 16185, 6313, 228147}},
-{17697, 18, 72183, {1, 3, 1, 3, 3, 9, 107, 243, 391, 893, 1207, 2229, 5295, 723, 14753, 10921, 104147, 214941}},
-{17698, 18, 72203, {1, 3, 1, 9, 5, 63, 63, 247, 413, 805, 285, 4001, 6735, 3531, 25949, 44845, 66959, 194429}},
-{17699, 18, 72205, {1, 1, 3, 1, 15, 15, 43, 69, 419, 739, 1739, 1091, 1043, 3217, 1139, 44749, 74131, 165145}},
-{17700, 18, 72213, {1, 1, 3, 9, 17, 53, 119, 25, 427, 791, 1873, 481, 6793, 4767, 30449, 18079, 52105, 260371}},
-{17701, 18, 72214, {1, 1, 3, 15, 15, 41, 15, 53, 395, 571, 1727, 3081, 4531, 4215, 22359, 18165, 91843, 157273}},
-{17702, 18, 72230, {1, 3, 3, 9, 19, 15, 55, 185, 321, 285, 695, 1067, 2551, 1401, 20023, 22671, 21365, 89053}},
-{17703, 18, 72239, {1, 1, 7, 15, 23, 57, 71, 141, 57, 479, 543, 3783, 3635, 14011, 23603, 40877, 21837, 81079}},
-{17704, 18, 72248, {1, 3, 7, 11, 31, 5, 83, 177, 105, 981, 331, 2901, 1781, 8407, 30199, 19287, 116219, 78471}},
-{17705, 18, 72251, {1, 1, 1, 9, 7, 13, 61, 21, 299, 15, 1045, 475, 7141, 4827, 5921, 17323, 42909, 203623}},
-{17706, 18, 72280, {1, 3, 7, 1, 17, 59, 99, 221, 77, 37, 1263, 2137, 1567, 12473, 20029, 9231, 32739, 17021}},
-{17707, 18, 72313, {1, 1, 1, 5, 23, 61, 39, 13, 97, 191, 1479, 19, 1913, 3185, 32393, 59067, 5483, 158895}},
-{17708, 18, 72338, {1, 1, 1, 7, 5, 51, 81, 223, 435, 939, 781, 1153, 6409, 6369, 30559, 19007, 50121, 26525}},
-{17709, 18, 72340, {1, 3, 3, 5, 29, 1, 57, 127, 153, 897, 161, 683, 295, 11207, 245, 1819, 3061, 242609}},
-{17710, 18, 72343, {1, 1, 1, 7, 5, 19, 105, 57, 263, 433, 1339, 1479, 6671, 9917, 26299, 4573, 68725, 195}},
-{17711, 18, 72368, {1, 3, 5, 15, 1, 19, 45, 95, 155, 117, 367, 2051, 1053, 8847, 6399, 23641, 95355, 98415}},
-{17712, 18, 72371, {1, 3, 3, 15, 3, 1, 5, 115, 349, 747, 1865, 1669, 659, 7097, 7871, 3685, 11013, 59837}},
-{17713, 18, 72426, {1, 3, 3, 5, 9, 47, 51, 131, 327, 903, 975, 2481, 3509, 12481, 4049, 38053, 4629, 254415}},
-{17714, 18, 72439, {1, 3, 5, 9, 31, 47, 1, 29, 37, 683, 1363, 2527, 4019, 4965, 14077, 14191, 101, 1945}},
-{17715, 18, 72446, {1, 1, 7, 1, 9, 35, 41, 187, 509, 33, 385, 3907, 1461, 6827, 6931, 44723, 109495, 184641}},
-{17716, 18, 72494, {1, 3, 5, 9, 5, 49, 21, 171, 353, 927, 409, 913, 5199, 11747, 8777, 19891, 63189, 118839}},
-{17717, 18, 72519, {1, 3, 3, 1, 27, 49, 43, 157, 75, 469, 787, 3957, 4147, 13919, 17489, 57103, 62091, 135589}},
-{17718, 18, 72573, {1, 1, 3, 11, 7, 45, 29, 177, 185, 185, 1537, 127, 121, 817, 31269, 1677, 20245, 3835}},
-{17719, 18, 72577, {1, 1, 5, 3, 21, 9, 67, 79, 391, 971, 1711, 2607, 5705, 12863, 12415, 41255, 26447, 1643}},
-{17720, 18, 72578, {1, 1, 5, 5, 9, 63, 67, 245, 31, 225, 309, 1753, 1507, 817, 4275, 51843, 22331, 196875}},
-{17721, 18, 72614, {1, 3, 1, 13, 15, 39, 3, 245, 147, 485, 241, 2507, 1859, 7299, 15037, 41139, 82757, 224031}},
-{17722, 18, 72628, {1, 3, 3, 15, 7, 51, 9, 103, 37, 643, 25, 2067, 7619, 11991, 12885, 46809, 109107, 22393}},
-{17723, 18, 72640, {1, 1, 1, 9, 1, 55, 119, 85, 115, 827, 187, 2241, 2553, 577, 12115, 2391, 69705, 232101}},
-{17724, 18, 72676, {1, 1, 5, 7, 13, 61, 125, 129, 475, 703, 1723, 3233, 5713, 1941, 21375, 42119, 75199, 73163}},
-{17725, 18, 72708, {1, 1, 5, 5, 5, 21, 73, 155, 493, 81, 1627, 827, 5925, 7391, 1587, 39425, 11807, 64385}},
-{17726, 18, 72717, {1, 3, 1, 15, 27, 35, 111, 183, 283, 335, 1387, 669, 6041, 11637, 26255, 21113, 121183, 219703}},
-{17727, 18, 72766, {1, 3, 5, 15, 15, 23, 119, 91, 197, 809, 975, 3275, 6171, 11769, 8385, 5461, 4561, 29159}},
-{17728, 18, 72786, {1, 1, 5, 9, 29, 9, 107, 233, 417, 1005, 799, 1437, 2679, 15643, 32341, 54055, 27861, 115483}},
-{17729, 18, 72788, {1, 1, 5, 7, 27, 19, 95, 153, 175, 407, 215, 303, 8165, 14791, 2099, 61797, 129411, 10461}},
-{17730, 18, 72795, {1, 1, 1, 13, 25, 51, 11, 77, 97, 495, 971, 449, 2833, 7121, 24105, 34527, 123135, 129305}},
-{17731, 18, 72797, {1, 1, 7, 11, 23, 9, 111, 101, 169, 233, 267, 953, 6379, 15887, 22921, 33665, 95195, 159707}},
-{17732, 18, 72798, {1, 1, 5, 15, 21, 3, 21, 57, 173, 513, 2027, 1235, 5031, 5375, 2717, 23361, 71817, 232101}},
-{17733, 18, 72808, {1, 3, 3, 11, 7, 25, 43, 65, 19, 135, 1611, 85, 7673, 6459, 27813, 55557, 100989, 25205}},
-{17734, 18, 72826, {1, 3, 7, 1, 15, 37, 55, 141, 239, 205, 647, 3715, 1617, 13507, 9847, 64681, 108711, 231329}},
-{17735, 18, 72835, {1, 3, 5, 9, 21, 27, 79, 153, 335, 299, 493, 887, 1457, 16011, 13795, 50205, 43319, 130963}},
-{17736, 18, 72837, {1, 1, 3, 1, 23, 59, 121, 83, 463, 151, 323, 2977, 4769, 6011, 20135, 59541, 23179, 203487}},
-{17737, 18, 72865, {1, 1, 5, 7, 9, 17, 63, 149, 59, 281, 763, 619, 2551, 8179, 2963, 61283, 107727, 119817}},
-{17738, 18, 72871, {1, 3, 7, 3, 15, 39, 11, 145, 141, 965, 505, 2625, 4335, 7619, 11007, 43321, 33199, 212661}},
-{17739, 18, 72872, {1, 3, 5, 9, 9, 61, 27, 223, 5, 941, 513, 1437, 481, 9651, 6567, 57945, 52547, 21283}},
-{17740, 18, 72898, {1, 3, 1, 1, 25, 1, 87, 25, 121, 757, 529, 3857, 1321, 13479, 5357, 49341, 5797, 235895}},
-{17741, 18, 72907, {1, 3, 5, 1, 21, 35, 37, 215, 509, 165, 1423, 3067, 4779, 4693, 12523, 48099, 69283, 255111}},
-{17742, 18, 72909, {1, 1, 3, 1, 31, 15, 45, 127, 339, 331, 1249, 1075, 6169, 2941, 30471, 46789, 118039, 224651}},
-{17743, 18, 72917, {1, 1, 5, 13, 21, 37, 39, 61, 191, 17, 177, 3719, 2177, 11039, 20047, 14489, 20475, 171235}},
-{17744, 18, 72934, {1, 1, 3, 9, 19, 11, 65, 111, 121, 901, 99, 1861, 3687, 765, 24861, 46315, 63433, 171679}},
-{17745, 18, 72987, {1, 3, 1, 7, 1, 51, 87, 199, 241, 909, 353, 2471, 7163, 9547, 16351, 41129, 12217, 194099}},
-{17746, 18, 73000, {1, 1, 7, 7, 17, 17, 127, 67, 51, 217, 1189, 19, 2099, 10281, 9071, 21185, 122821, 110211}},
-{17747, 18, 73005, {1, 3, 3, 7, 15, 3, 53, 45, 77, 665, 701, 3175, 6151, 2639, 19819, 1063, 25079, 203343}},
-{17748, 18, 73014, {1, 1, 5, 11, 11, 5, 103, 11, 481, 999, 713, 499, 5069, 921, 20619, 25623, 69601, 82941}},
-{17749, 18, 73023, {1, 3, 5, 9, 15, 61, 67, 79, 371, 993, 475, 617, 1611, 12513, 14907, 55313, 39207, 112653}},
-{17750, 18, 73025, {1, 1, 5, 15, 17, 45, 91, 187, 175, 465, 907, 3371, 3743, 15657, 30511, 58191, 105683, 216759}},
-{17751, 18, 73074, {1, 1, 5, 9, 23, 1, 17, 79, 73, 717, 1785, 677, 7377, 4511, 21927, 34341, 47119, 193977}},
-{17752, 18, 73076, {1, 3, 7, 13, 21, 1, 59, 179, 121, 641, 175, 563, 961, 10549, 15779, 49875, 8109, 1039}},
-{17753, 18, 73113, {1, 1, 5, 7, 17, 9, 37, 171, 335, 135, 1403, 2541, 3845, 15311, 1905, 40853, 11013, 255669}},
-{17754, 18, 73116, {1, 1, 7, 1, 5, 23, 113, 111, 337, 755, 2037, 3067, 2821, 10549, 28467, 22615, 71585, 61871}},
-{17755, 18, 73140, {1, 1, 3, 9, 7, 3, 49, 229, 111, 871, 1711, 1793, 3089, 12571, 30883, 44773, 80827, 151709}},
-{17756, 18, 73149, {1, 1, 5, 1, 13, 41, 3, 253, 399, 881, 1107, 4081, 1849, 115, 31557, 2515, 126751, 195663}},
-{17757, 18, 73186, {1, 1, 3, 1, 13, 31, 113, 85, 57, 549, 1653, 2927, 5433, 11879, 22709, 41675, 13395, 46931}},
-{17758, 18, 73188, {1, 1, 3, 9, 21, 1, 109, 65, 377, 63, 861, 1031, 2709, 7265, 9861, 64109, 34577, 9743}},
-{17759, 18, 73191, {1, 1, 7, 7, 17, 31, 5, 177, 253, 387, 1271, 2805, 2211, 1813, 11649, 3217, 123793, 197753}},
-{17760, 18, 73205, {1, 1, 3, 9, 15, 63, 89, 59, 455, 783, 1181, 7, 2309, 15961, 11231, 37389, 101221, 119331}},
-{17761, 18, 73215, {1, 3, 3, 13, 7, 3, 15, 251, 431, 951, 639, 1585, 1247, 15927, 9695, 37469, 34945, 219723}},
-{17762, 18, 73216, {1, 1, 5, 3, 21, 29, 83, 151, 383, 227, 215, 2329, 1297, 13709, 15653, 3119, 111319, 222877}},
-{17763, 18, 73239, {1, 3, 1, 13, 1, 43, 127, 125, 243, 955, 583, 3497, 6605, 3821, 4657, 10599, 90927, 82725}},
-{17764, 18, 73294, {1, 1, 1, 1, 15, 51, 61, 167, 489, 603, 873, 907, 575, 6957, 24409, 63587, 50205, 159291}},
-{17765, 18, 73311, {1, 3, 3, 1, 19, 23, 7, 23, 239, 961, 1001, 1541, 2211, 4637, 19931, 39153, 102769, 242005}},
-{17766, 18, 73330, {1, 1, 1, 15, 19, 31, 73, 121, 119, 199, 979, 4061, 3903, 12055, 27957, 15999, 5709, 210329}},
-{17767, 18, 73366, {1, 1, 7, 13, 25, 35, 21, 25, 241, 937, 13, 947, 943, 3727, 15321, 46665, 99437, 233919}},
-{17768, 18, 73379, {1, 1, 1, 9, 3, 51, 127, 113, 105, 335, 685, 2173, 4329, 7569, 5617, 32407, 21649, 30609}},
-{17769, 18, 73386, {1, 3, 7, 9, 9, 13, 69, 191, 95, 727, 1649, 1201, 2093, 10053, 29381, 6207, 70755, 118505}},
-{17770, 18, 73391, {1, 1, 1, 11, 21, 57, 77, 139, 271, 21, 1747, 2337, 7761, 7753, 6847, 5219, 87033, 229105}},
-{17771, 18, 73418, {1, 3, 3, 1, 5, 51, 15, 235, 87, 567, 391, 3039, 2253, 11177, 11899, 25305, 14815, 51051}},
-{17772, 18, 73438, {1, 3, 5, 7, 27, 51, 69, 93, 261, 947, 31, 2751, 6685, 3655, 24125, 22161, 108421, 230865}},
-{17773, 18, 73476, {1, 1, 3, 3, 27, 17, 35, 97, 285, 855, 1767, 2545, 825, 11519, 11231, 50951, 32883, 78573}},
-{17774, 18, 73503, {1, 3, 7, 13, 1, 57, 99, 193, 371, 839, 1319, 2295, 5897, 7893, 14339, 64217, 16951, 234953}},
-{17775, 18, 73509, {1, 3, 1, 3, 11, 37, 13, 21, 299, 379, 63, 1209, 7879, 5001, 10181, 40173, 1753, 104821}},
-{17776, 18, 73534, {1, 3, 5, 9, 23, 51, 75, 103, 249, 533, 621, 15, 1883, 2109, 20859, 4635, 120615, 135515}},
-{17777, 18, 73545, {1, 1, 3, 3, 21, 45, 113, 57, 495, 457, 685, 3625, 243, 14831, 12351, 63001, 118191, 153875}},
-{17778, 18, 73548, {1, 3, 5, 5, 21, 15, 65, 251, 183, 241, 1513, 2711, 4527, 12675, 26747, 5181, 4237, 246479}},
-{17779, 18, 73563, {1, 1, 5, 3, 27, 29, 91, 93, 345, 893, 195, 3109, 2611, 12657, 10401, 15063, 95807, 244587}},
-{17780, 18, 73575, {1, 3, 5, 13, 19, 49, 85, 155, 159, 939, 1139, 1569, 1129, 8641, 18391, 55201, 108491, 77863}},
-{17781, 18, 73582, {1, 3, 5, 9, 25, 53, 75, 77, 85, 903, 1399, 2379, 2219, 14725, 21877, 24271, 40955, 61849}},
-{17782, 18, 73603, {1, 1, 5, 9, 13, 49, 53, 177, 163, 331, 533, 1469, 1397, 8187, 12379, 10185, 125541, 260271}},
-{17783, 18, 73609, {1, 1, 7, 9, 19, 31, 81, 89, 281, 397, 1917, 145, 2723, 15019, 18841, 13887, 11859, 171749}},
-{17784, 18, 73610, {1, 3, 7, 13, 25, 17, 87, 189, 29, 283, 913, 3855, 5707, 15881, 12787, 42357, 84579, 78531}},
-{17785, 18, 73645, {1, 1, 5, 15, 15, 31, 37, 249, 445, 119, 431, 4069, 5699, 10119, 31661, 9555, 6869, 1145}},
-{17786, 18, 73646, {1, 3, 7, 1, 31, 29, 57, 177, 341, 411, 1019, 1889, 383, 1461, 26695, 61777, 18367, 137233}},
-{17787, 18, 73678, {1, 3, 5, 1, 7, 53, 29, 53, 387, 675, 435, 461, 6247, 7519, 14003, 9037, 116599, 54471}},
-{17788, 18, 73685, {1, 3, 3, 7, 17, 59, 91, 77, 169, 591, 95, 113, 6135, 10479, 17153, 52953, 16183, 90775}},
-{17789, 18, 73708, {1, 3, 3, 15, 11, 11, 117, 141, 493, 163, 65, 1305, 7477, 7383, 22651, 64271, 80983, 154845}},
-{17790, 18, 73747, {1, 1, 1, 3, 9, 15, 83, 11, 113, 77, 1115, 1417, 511, 6825, 21013, 37241, 104695, 31335}},
-{17791, 18, 73765, {1, 1, 7, 3, 13, 33, 115, 121, 245, 673, 1991, 2157, 479, 9843, 5963, 4637, 8925, 27751}},
-{17792, 18, 73797, {1, 3, 3, 7, 19, 11, 67, 125, 339, 27, 1545, 2319, 5977, 11603, 23219, 48273, 119265, 20151}},
-{17793, 18, 73810, {1, 1, 5, 7, 27, 29, 31, 227, 279, 405, 1133, 689, 1133, 8957, 29629, 48849, 109995, 259749}},
-{17794, 18, 73819, {1, 3, 5, 7, 7, 61, 95, 243, 91, 741, 1591, 3169, 2287, 11015, 15601, 43043, 65319, 50671}},
-{17795, 18, 73825, {1, 1, 5, 5, 13, 47, 31, 95, 425, 715, 1603, 3485, 673, 12869, 32561, 42329, 112809, 181971}},
-{17796, 18, 73845, {1, 3, 3, 3, 17, 51, 109, 45, 397, 457, 1379, 3845, 4215, 14185, 16597, 27711, 74283, 98151}},
-{17797, 18, 73855, {1, 1, 1, 15, 7, 25, 13, 49, 441, 513, 1769, 707, 6037, 9689, 18915, 35647, 110823, 196633}},
-{17798, 18, 73866, {1, 1, 1, 1, 23, 53, 93, 61, 277, 125, 55, 2453, 3331, 14037, 10809, 33205, 43785, 248743}},
-{17799, 18, 73890, {1, 1, 3, 7, 23, 15, 93, 77, 333, 801, 1969, 31, 51, 5239, 24241, 5077, 113503, 132211}},
-{17800, 18, 73919, {1, 3, 3, 1, 7, 55, 53, 5, 311, 657, 1507, 3413, 565, 15745, 6129, 40285, 91811, 90527}},
-{17801, 18, 73922, {1, 3, 3, 13, 19, 23, 45, 25, 509, 313, 915, 2199, 5549, 8469, 32735, 37877, 11607, 37993}},
-{17802, 18, 73936, {1, 1, 5, 11, 25, 33, 55, 31, 311, 851, 159, 2103, 2641, 8957, 9375, 37179, 33667, 100513}},
-{17803, 18, 73939, {1, 3, 1, 1, 7, 7, 17, 75, 217, 171, 359, 1169, 4105, 929, 6427, 56349, 77985, 41941}},
-{17804, 18, 73964, {1, 1, 1, 15, 5, 51, 73, 63, 259, 351, 1797, 1001, 5025, 11203, 30221, 54345, 11331, 158415}},
-{17805, 18, 73976, {1, 3, 1, 5, 3, 21, 13, 3, 63, 779, 871, 2517, 6345, 4103, 16321, 30211, 120815, 83751}},
-{17806, 18, 73984, {1, 1, 3, 13, 11, 7, 41, 255, 215, 37, 279, 2485, 6511, 12855, 22857, 55695, 122717, 238151}},
-{17807, 18, 73990, {1, 3, 3, 3, 1, 55, 27, 193, 509, 677, 1861, 573, 5341, 5285, 6909, 51781, 91203, 139791}},
-{17808, 18, 74013, {1, 3, 7, 11, 5, 63, 87, 215, 305, 235, 1049, 1339, 5301, 9639, 29861, 58415, 68303, 76907}},
-{17809, 18, 74014, {1, 1, 5, 11, 13, 13, 67, 139, 19, 577, 165, 3067, 8023, 10905, 3159, 41289, 118231, 119673}},
-{17810, 18, 74020, {1, 1, 3, 1, 15, 5, 69, 119, 363, 703, 461, 2293, 3801, 14217, 10709, 9553, 100651, 186115}},
-{17811, 18, 74035, {1, 3, 7, 15, 19, 21, 59, 237, 227, 193, 827, 619, 3447, 13815, 3467, 38911, 41403, 99627}},
-{17812, 18, 74038, {1, 1, 3, 3, 27, 23, 41, 199, 161, 555, 1629, 3187, 1355, 5947, 1157, 25877, 110989, 231285}},
-{17813, 18, 74069, {1, 1, 3, 15, 3, 43, 103, 29, 179, 223, 375, 2877, 1917, 9367, 15337, 15381, 62833, 139003}},
-{17814, 18, 74119, {1, 3, 3, 11, 23, 33, 107, 189, 511, 209, 1519, 2809, 6185, 5921, 20939, 63879, 113687, 79149}},
-{17815, 18, 74123, {1, 3, 5, 15, 1, 63, 101, 227, 419, 803, 59, 2261, 6905, 10679, 5393, 54447, 58521, 59855}},
-{17816, 18, 74126, {1, 1, 7, 13, 13, 21, 121, 123, 181, 371, 1485, 3191, 2627, 6197, 11169, 44927, 34739, 10687}},
-{17817, 18, 74153, {1, 1, 3, 3, 25, 47, 13, 115, 187, 967, 1439, 1021, 4413, 3343, 31463, 3729, 13511, 162125}},
-{17818, 18, 74179, {1, 3, 3, 15, 15, 59, 29, 129, 469, 171, 2045, 2859, 1097, 11199, 12147, 37465, 14179, 197923}},
-{17819, 18, 74200, {1, 1, 7, 5, 13, 35, 41, 167, 207, 123, 1077, 3145, 2803, 15729, 767, 7321, 84375, 190855}},
-{17820, 18, 74210, {1, 3, 5, 11, 3, 5, 65, 3, 111, 725, 143, 2945, 4755, 3407, 31801, 15329, 70311, 119197}},
-{17821, 18, 74216, {1, 1, 5, 3, 17, 19, 61, 73, 261, 663, 821, 3389, 3883, 9961, 17727, 33113, 98371, 247097}},
-{17822, 18, 74250, {1, 3, 1, 9, 29, 17, 43, 43, 481, 1015, 1249, 607, 3495, 13259, 29001, 23083, 51487, 81723}},
-{17823, 18, 74263, {1, 3, 1, 3, 25, 57, 5, 33, 313, 21, 1731, 3417, 7033, 6609, 31631, 63231, 61107, 10941}},
-{17824, 18, 74264, {1, 3, 3, 11, 29, 29, 117, 131, 417, 789, 1545, 1677, 3213, 13869, 5319, 41387, 13895, 252387}},
-{17825, 18, 74279, {1, 3, 3, 13, 25, 47, 55, 213, 83, 345, 1453, 159, 1521, 14777, 24177, 7631, 81259, 135411}},
-{17826, 18, 74285, {1, 1, 3, 15, 11, 63, 49, 69, 273, 843, 1661, 1157, 1285, 12751, 5, 54909, 114375, 6395}},
-{17827, 18, 74294, {1, 3, 1, 11, 25, 1, 83, 55, 161, 125, 1547, 401, 7639, 4289, 7075, 9971, 33825, 135071}},
-{17828, 18, 74298, {1, 3, 7, 9, 17, 5, 79, 131, 373, 1023, 573, 2219, 1789, 5789, 5347, 26455, 58661, 206417}},
-{17829, 18, 74303, {1, 1, 7, 5, 1, 43, 83, 107, 125, 289, 793, 1731, 5167, 8943, 28397, 26877, 53781, 95899}},
-{17830, 18, 74306, {1, 3, 3, 13, 21, 53, 123, 103, 385, 753, 1917, 2075, 4385, 5757, 9221, 35797, 86743, 69069}},
-{17831, 18, 74366, {1, 3, 3, 3, 5, 19, 119, 221, 457, 907, 359, 3493, 2331, 5685, 11133, 29293, 27051, 213927}},
-{17832, 18, 74369, {1, 1, 3, 11, 11, 31, 29, 129, 429, 601, 1217, 3653, 5935, 14823, 21161, 33423, 98391, 214703}},
-{17833, 18, 74403, {1, 1, 3, 15, 31, 49, 109, 139, 349, 13, 205, 2483, 8083, 8391, 4789, 30355, 12165, 195263}},
-{17834, 18, 74406, {1, 1, 1, 9, 19, 63, 15, 167, 45, 185, 811, 529, 6811, 13441, 27195, 59047, 106675, 167125}},
-{17835, 18, 74442, {1, 1, 7, 1, 19, 19, 39, 1, 349, 467, 551, 4081, 4743, 11627, 607, 22005, 60893, 49101}},
-{17836, 18, 74450, {1, 3, 7, 9, 9, 25, 105, 119, 113, 825, 1429, 2019, 5209, 8491, 6017, 47783, 88455, 119083}},
-{17837, 18, 74452, {1, 3, 3, 13, 21, 39, 107, 119, 321, 251, 563, 311, 4441, 6491, 3157, 65479, 107349, 211621}},
-{17838, 18, 74459, {1, 1, 7, 13, 9, 3, 17, 117, 327, 459, 489, 7, 6883, 10047, 31935, 28069, 37903, 188281}},
-{17839, 18, 74461, {1, 1, 7, 1, 15, 53, 47, 127, 483, 595, 811, 1143, 4543, 10043, 30349, 24409, 91947, 240165}},
-{17840, 18, 74477, {1, 1, 1, 13, 25, 43, 109, 161, 147, 1009, 1071, 1533, 2781, 13439, 20507, 41387, 26943, 84675}},
-{17841, 18, 74478, {1, 3, 5, 13, 19, 21, 23, 167, 135, 257, 587, 2691, 5877, 3047, 11745, 24895, 114799, 48003}},
-{17842, 18, 74489, {1, 3, 1, 1, 9, 57, 33, 51, 137, 109, 137, 195, 1233, 11139, 16833, 27545, 35877, 126627}},
-{17843, 18, 74504, {1, 1, 1, 15, 5, 37, 7, 19, 363, 411, 1193, 767, 6209, 9115, 14699, 55515, 46023, 90693}},
-{17844, 18, 74528, {1, 3, 5, 3, 19, 55, 85, 117, 391, 757, 861, 3537, 6507, 6993, 19589, 6843, 33557, 64683}},
-{17845, 18, 74533, {1, 1, 7, 5, 5, 61, 99, 9, 311, 595, 807, 429, 63, 12359, 28289, 709, 129911, 143745}},
-{17846, 18, 74538, {1, 1, 1, 7, 17, 9, 9, 117, 19, 985, 657, 2803, 2699, 829, 31069, 13277, 106769, 109231}},
-{17847, 18, 74551, {1, 1, 5, 13, 25, 19, 63, 217, 419, 221, 1921, 215, 2631, 4659, 29855, 46549, 62257, 260113}},
-{17848, 18, 74580, {1, 3, 3, 9, 13, 45, 63, 129, 147, 489, 879, 3025, 6777, 1119, 20963, 30553, 20863, 169837}},
-{17849, 18, 74589, {1, 3, 5, 9, 25, 61, 79, 51, 495, 583, 1519, 1501, 123, 13871, 32239, 957, 31921, 255561}},
-{17850, 18, 74590, {1, 3, 7, 3, 31, 61, 89, 65, 305, 429, 785, 3871, 7711, 2745, 24131, 43055, 51167, 87743}},
-{17851, 18, 74593, {1, 3, 1, 11, 19, 23, 89, 117, 185, 121, 109, 1327, 6553, 14367, 16069, 28657, 81751, 10185}},
-{17852, 18, 74608, {1, 3, 5, 5, 17, 33, 115, 61, 101, 367, 1465, 3899, 6601, 4483, 2447, 49575, 129987, 11703}},
-{17853, 18, 74611, {1, 1, 3, 13, 13, 59, 79, 83, 253, 171, 53, 2467, 5005, 1045, 943, 62419, 98563, 78935}},
-{17854, 18, 74617, {1, 1, 7, 15, 31, 17, 77, 73, 249, 247, 119, 1655, 7079, 14593, 105, 55767, 130401, 74189}},
-{17855, 18, 74623, {1, 3, 5, 11, 19, 29, 79, 251, 75, 949, 527, 2779, 5839, 11451, 24125, 45991, 127437, 86541}},
-{17856, 18, 74648, {1, 1, 5, 7, 1, 29, 127, 27, 477, 807, 829, 1569, 205, 13319, 16149, 26003, 38985, 188587}},
-{17857, 18, 74704, {1, 1, 1, 3, 19, 29, 39, 71, 17, 51, 1169, 467, 7505, 1867, 4469, 32161, 43031, 31675}},
-{17858, 18, 74735, {1, 1, 1, 15, 27, 45, 67, 107, 127, 469, 1955, 1933, 2379, 8513, 32071, 35043, 126537, 23303}},
-{17859, 18, 74737, {1, 3, 7, 9, 23, 41, 23, 197, 97, 213, 17, 1751, 5467, 6179, 29291, 33397, 42131, 151093}},
-{17860, 18, 74738, {1, 3, 7, 15, 27, 3, 39, 87, 365, 77, 487, 293, 6405, 2239, 30455, 44723, 12399, 100013}},
-{17861, 18, 74779, {1, 3, 5, 9, 29, 21, 55, 183, 343, 263, 1643, 2027, 2255, 6259, 18277, 64661, 39391, 255839}},
-{17862, 18, 74781, {1, 1, 7, 11, 21, 55, 11, 139, 261, 11, 1721, 3779, 85, 8203, 12089, 50579, 128341, 119043}},
-{17863, 18, 74809, {1, 3, 5, 13, 27, 53, 109, 1, 313, 661, 431, 1543, 1571, 7337, 18857, 49951, 7881, 228161}},
-{17864, 18, 74812, {1, 1, 7, 5, 5, 31, 27, 149, 239, 199, 1011, 1979, 5297, 14609, 26971, 65531, 64215, 115109}},
-{17865, 18, 74827, {1, 1, 5, 13, 15, 11, 63, 225, 165, 405, 1367, 2291, 5171, 12419, 19561, 37719, 621, 137607}},
-{17866, 18, 74868, {1, 3, 1, 15, 25, 1, 125, 243, 97, 455, 1977, 3333, 801, 1343, 993, 18453, 19285, 71547}},
-{17867, 18, 74871, {1, 1, 5, 11, 9, 51, 109, 135, 73, 147, 649, 4071, 7425, 3093, 26417, 51139, 1523, 142225}},
-{17868, 18, 74905, {1, 3, 7, 11, 1, 39, 109, 119, 337, 715, 1087, 4005, 1393, 6397, 31135, 38935, 106255, 60723}},
-{17869, 18, 74930, {1, 1, 1, 9, 9, 11, 45, 11, 171, 671, 965, 109, 2261, 13775, 8539, 63669, 10507, 249113}},
-{17870, 18, 74962, {1, 3, 1, 15, 21, 33, 127, 173, 419, 31, 299, 857, 4915, 11331, 29385, 47375, 111891, 14505}},
-{17871, 18, 74990, {1, 3, 5, 13, 7, 43, 85, 183, 377, 275, 803, 1755, 8005, 15327, 31043, 18851, 122581, 229731}},
-{17872, 18, 74995, {1, 3, 5, 1, 27, 9, 41, 73, 283, 475, 671, 747, 1419, 15209, 25465, 60061, 91417, 103203}},
-{17873, 18, 75007, {1, 3, 1, 15, 15, 43, 13, 45, 217, 519, 363, 3265, 6213, 13045, 3709, 22119, 79733, 224195}},
-{17874, 18, 75012, {1, 3, 1, 15, 15, 59, 95, 71, 171, 769, 1395, 2673, 4523, 749, 13411, 60431, 124651, 11475}},
-{17875, 18, 75030, {1, 1, 7, 3, 1, 35, 13, 239, 101, 355, 1201, 3665, 5403, 11413, 11983, 52469, 63621, 155819}},
-{17876, 18, 75033, {1, 1, 1, 7, 31, 59, 87, 25, 511, 483, 569, 3337, 4027, 8347, 3031, 24351, 57963, 79425}},
-{17877, 18, 75039, {1, 3, 1, 3, 11, 17, 29, 249, 61, 923, 585, 2107, 2727, 8589, 22809, 3, 17937, 163267}},
-{17878, 18, 75055, {1, 3, 5, 11, 27, 3, 73, 187, 19, 975, 257, 2361, 935, 9071, 29991, 13619, 92169, 101031}},
-{17879, 18, 75078, {1, 1, 5, 13, 17, 53, 105, 157, 343, 673, 237, 3231, 7311, 1593, 18521, 57889, 79805, 97847}},
-{17880, 18, 75120, {1, 3, 1, 3, 31, 55, 63, 167, 489, 167, 121, 3333, 2475, 1545, 13291, 921, 101757, 62147}},
-{17881, 18, 75130, {1, 3, 3, 15, 13, 17, 9, 209, 339, 567, 2011, 1737, 1455, 9289, 6105, 49733, 74237, 93195}},
-{17882, 18, 75159, {1, 1, 7, 11, 3, 13, 77, 115, 305, 327, 1005, 3381, 4269, 4835, 27221, 16301, 75173, 244603}},
-{17883, 18, 75163, {1, 3, 5, 7, 7, 31, 47, 75, 499, 41, 281, 167, 3525, 8649, 23623, 4987, 2057, 204083}},
-{17884, 18, 75170, {1, 3, 3, 5, 9, 5, 35, 53, 269, 437, 1035, 1675, 4567, 13291, 19787, 28937, 108915, 62545}},
-{17885, 18, 75193, {1, 3, 1, 5, 15, 59, 57, 181, 321, 1, 791, 2149, 591, 6691, 8759, 62861, 10815, 257331}},
-{17886, 18, 75228, {1, 1, 7, 1, 21, 25, 93, 39, 429, 455, 669, 1725, 7087, 11805, 22405, 13083, 88411, 225967}},
-{17887, 18, 75244, {1, 1, 5, 15, 5, 45, 15, 1, 55, 281, 2027, 97, 2639, 57, 23717, 21669, 92181, 32731}},
-{17888, 18, 75249, {1, 3, 7, 3, 7, 3, 67, 201, 445, 577, 1011, 793, 7763, 10823, 30309, 41565, 37263, 218909}},
-{17889, 18, 75328, {1, 1, 7, 3, 17, 53, 51, 119, 399, 903, 1785, 1053, 4315, 2967, 17579, 64185, 55005, 12969}},
-{17890, 18, 75357, {1, 3, 3, 13, 21, 63, 13, 1, 427, 39, 71, 1811, 1237, 1623, 11401, 14371, 44355, 93089}},
-{17891, 18, 75373, {1, 1, 5, 1, 17, 39, 39, 105, 187, 691, 251, 3957, 931, 12149, 18299, 48819, 23061, 49179}},
-{17892, 18, 75392, {1, 1, 5, 11, 31, 3, 23, 211, 101, 763, 237, 3635, 417, 4935, 14997, 3859, 22343, 153541}},
-{17893, 18, 75428, {1, 3, 7, 5, 21, 37, 59, 137, 13, 179, 527, 895, 3451, 1743, 3149, 10665, 119427, 259343}},
-{17894, 18, 75438, {1, 3, 5, 3, 7, 37, 103, 173, 453, 327, 131, 2453, 7795, 12585, 13947, 59161, 41845, 29527}},
-{17895, 18, 75469, {1, 3, 3, 1, 17, 49, 57, 251, 295, 279, 1545, 3963, 589, 9211, 32371, 14963, 116927, 197321}},
-{17896, 18, 75487, {1, 1, 3, 7, 17, 59, 37, 115, 315, 591, 481, 767, 4611, 14741, 6949, 19507, 6567, 143371}},
-{17897, 18, 75494, {1, 1, 5, 3, 19, 53, 121, 229, 355, 909, 339, 1645, 2747, 7045, 9085, 5799, 50997, 17981}},
-{17898, 18, 75515, {1, 3, 3, 9, 3, 1, 109, 7, 15, 177, 789, 3911, 6427, 8453, 22583, 12039, 124587, 123887}},
-{17899, 18, 75526, {1, 1, 5, 1, 7, 23, 15, 193, 109, 685, 1147, 3921, 2329, 15153, 25045, 28389, 34759, 256611}},
-{17900, 18, 75532, {1, 1, 3, 3, 23, 27, 55, 43, 485, 541, 1617, 3761, 1051, 7525, 19941, 52699, 35421, 162939}},
-{17901, 18, 75543, {1, 3, 7, 1, 25, 9, 113, 251, 477, 1005, 9, 3321, 5817, 965, 18523, 29407, 53353, 205575}},
-{17902, 18, 75549, {1, 1, 7, 11, 9, 31, 111, 175, 227, 33, 1745, 1141, 1547, 2113, 8785, 40273, 100301, 190749}},
-{17903, 18, 75559, {1, 1, 5, 11, 19, 49, 45, 197, 457, 223, 91, 2769, 6331, 1161, 6609, 61905, 42257, 152117}},
-{17904, 18, 75563, {1, 1, 7, 11, 1, 17, 37, 153, 431, 933, 269, 1529, 1297, 15567, 149, 41701, 59867, 93631}},
-{17905, 18, 75568, {1, 1, 5, 9, 25, 33, 83, 127, 305, 667, 343, 185, 3527, 13079, 10567, 35753, 72191, 214091}},
-{17906, 18, 75598, {1, 3, 7, 1, 1, 7, 75, 241, 185, 81, 2043, 3081, 3563, 385, 3055, 59421, 27081, 32521}},
-{17907, 18, 75612, {1, 1, 3, 5, 31, 1, 101, 21, 69, 979, 917, 695, 5601, 12251, 15031, 18715, 116985, 53071}},
-{17908, 18, 75622, {1, 1, 3, 9, 23, 57, 91, 127, 327, 979, 721, 3855, 1131, 997, 32227, 33843, 128299, 15239}},
-{17909, 18, 75640, {1, 3, 7, 13, 23, 1, 87, 105, 259, 939, 1935, 1983, 6619, 1611, 31901, 14745, 96641, 211945}},
-{17910, 18, 75683, {1, 1, 3, 5, 25, 17, 39, 95, 137, 971, 377, 2493, 981, 329, 25845, 44513, 100561, 57985}},
-{17911, 18, 75689, {1, 1, 3, 9, 27, 37, 69, 103, 167, 131, 487, 2935, 7099, 15375, 4825, 12209, 117165, 84909}},
-{17912, 18, 75690, {1, 3, 1, 15, 27, 19, 115, 239, 247, 243, 83, 1535, 8095, 3953, 25721, 62983, 89045, 16783}},
-{17913, 18, 75692, {1, 1, 5, 1, 19, 13, 125, 39, 439, 411, 171, 155, 5117, 15137, 19851, 251, 37921, 97209}},
-{17914, 18, 75752, {1, 1, 1, 5, 13, 41, 17, 97, 215, 323, 1333, 775, 1155, 15269, 19943, 48489, 71741, 202501}},
-{17915, 18, 75766, {1, 3, 5, 3, 1, 31, 55, 125, 69, 437, 1649, 2791, 8027, 15509, 31575, 8491, 106953, 155215}},
-{17916, 18, 75769, {1, 3, 3, 13, 19, 45, 39, 63, 227, 67, 2021, 1243, 6525, 7211, 6275, 39719, 74513, 6713}},
-{17917, 18, 75791, {1, 1, 5, 11, 13, 45, 15, 101, 171, 613, 1561, 2939, 3849, 2917, 29765, 2027, 53617, 59939}},
-{17918, 18, 75794, {1, 1, 5, 9, 27, 21, 119, 19, 441, 759, 703, 2985, 3007, 2087, 5207, 64403, 20273, 66181}},
-{17919, 18, 75806, {1, 1, 7, 13, 21, 3, 49, 3, 485, 883, 1863, 1925, 877, 10009, 24191, 58639, 107755, 106539}},
-{17920, 18, 75809, {1, 1, 1, 5, 27, 37, 23, 185, 281, 533, 437, 555, 8151, 6489, 22343, 4573, 91577, 167919}},
-{17921, 18, 75819, {1, 1, 7, 15, 3, 61, 103, 221, 223, 703, 133, 2923, 1027, 14643, 26413, 16523, 107223, 97185}},
-{17922, 18, 75834, {1, 3, 1, 11, 13, 15, 1, 203, 363, 675, 511, 3225, 1163, 741, 16063, 8097, 95905, 148465}},
-{17923, 18, 75895, {1, 3, 1, 7, 11, 11, 11, 243, 371, 129, 209, 3533, 1279, 12181, 31973, 29165, 122089, 115117}},
-{17924, 18, 75908, {1, 3, 1, 5, 25, 17, 31, 45, 215, 809, 1443, 3245, 1005, 2903, 20783, 23041, 96577, 192063}},
-{17925, 18, 75951, {1, 3, 3, 3, 19, 17, 101, 219, 91, 805, 189, 761, 4771, 11629, 7285, 21631, 21691, 47421}},
-{17926, 18, 75960, {1, 3, 7, 1, 31, 11, 71, 149, 303, 793, 35, 3109, 2769, 11593, 31839, 2053, 4541, 202997}},
-{17927, 18, 75965, {1, 1, 1, 3, 11, 19, 113, 249, 141, 659, 1117, 2145, 2617, 1075, 25347, 12913, 27457, 222095}},
-{17928, 18, 75974, {1, 3, 1, 3, 5, 23, 41, 57, 193, 815, 1293, 1109, 7597, 999, 10773, 41065, 18555, 35617}},
-{17929, 18, 75978, {1, 1, 3, 1, 31, 11, 127, 99, 163, 293, 299, 3415, 3761, 8781, 5327, 47631, 56411, 242787}},
-{17930, 18, 75998, {1, 3, 7, 13, 3, 41, 23, 169, 419, 725, 1419, 2643, 5265, 77, 24077, 18639, 78665, 205303}},
-{17931, 18, 76001, {1, 1, 5, 1, 31, 39, 39, 205, 413, 393, 1713, 309, 707, 4153, 10461, 16053, 26963, 253993}},
-{17932, 18, 76007, {1, 3, 7, 5, 23, 37, 125, 87, 199, 631, 1935, 551, 7047, 4585, 21257, 42345, 39365, 249393}},
-{17933, 18, 76016, {1, 3, 5, 13, 17, 55, 29, 209, 151, 465, 155, 363, 3097, 4093, 9869, 23297, 33973, 115543}},
-{17934, 18, 76091, {1, 1, 1, 13, 23, 59, 83, 71, 145, 717, 127, 1299, 1701, 10885, 5343, 40793, 87819, 66621}},
-{17935, 18, 76119, {1, 3, 3, 9, 19, 37, 23, 11, 269, 603, 871, 851, 837, 15303, 7595, 56481, 57819, 185065}},
-{17936, 18, 76135, {1, 3, 1, 1, 3, 15, 11, 249, 413, 723, 1403, 3233, 2747, 10335, 7127, 63285, 29237, 191953}},
-{17937, 18, 76170, {1, 3, 1, 1, 11, 31, 67, 139, 51, 413, 521, 969, 171, 5943, 31613, 16477, 85771, 202139}},
-{17938, 18, 76189, {1, 3, 7, 5, 5, 21, 109, 25, 463, 873, 493, 2673, 6409, 11199, 17195, 40623, 76821, 72509}},
-{17939, 18, 76214, {1, 1, 7, 7, 11, 1, 95, 43, 243, 67, 1289, 3219, 2255, 4957, 17561, 40499, 48537, 108809}},
-{17940, 18, 76225, {1, 1, 7, 15, 3, 39, 45, 75, 43, 821, 533, 4043, 1503, 83, 26937, 56327, 114149, 156845}},
-{17941, 18, 76235, {1, 3, 1, 1, 31, 21, 59, 1, 77, 147, 137, 1827, 4123, 2791, 27859, 57921, 40569, 134753}},
-{17942, 18, 76259, {1, 1, 5, 13, 31, 41, 111, 11, 181, 963, 459, 2771, 6123, 4035, 1627, 2047, 109537, 33653}},
-{17943, 18, 76261, {1, 3, 5, 7, 31, 57, 17, 21, 5, 761, 1833, 1279, 1239, 10089, 22531, 32547, 82699, 28389}},
-{17944, 18, 76262, {1, 3, 5, 13, 11, 39, 11, 61, 299, 753, 1067, 1347, 5189, 12859, 681, 46309, 31873, 90333}},
-{17945, 18, 76266, {1, 3, 1, 5, 13, 27, 119, 205, 377, 457, 817, 3017, 279, 1859, 30241, 52089, 61445, 176203}},
-{17946, 18, 76286, {1, 1, 3, 5, 11, 35, 17, 163, 27, 1001, 417, 2899, 1959, 5513, 1441, 19743, 67147, 236591}},
-{17947, 18, 76289, {1, 3, 5, 13, 15, 39, 53, 179, 447, 675, 933, 1261, 4415, 9845, 28459, 33497, 107375, 156855}},
-{17948, 18, 76310, {1, 3, 3, 13, 27, 31, 11, 191, 413, 1011, 2035, 3965, 2071, 5429, 16247, 7439, 15079, 225041}},
-{17949, 18, 76319, {1, 3, 3, 11, 7, 23, 87, 215, 241, 687, 1351, 2399, 4677, 12967, 22957, 10443, 116701, 155477}},
-{17950, 18, 76364, {1, 3, 7, 5, 25, 55, 5, 197, 359, 879, 619, 1969, 1513, 12743, 10953, 28343, 63685, 39115}},
-{17951, 18, 76375, {1, 1, 3, 1, 19, 15, 63, 7, 305, 343, 1333, 3845, 377, 14031, 28383, 4271, 60063, 11827}},
-{17952, 18, 76392, {1, 3, 5, 15, 25, 21, 115, 101, 171, 735, 787, 3143, 593, 8793, 4121, 15471, 53491, 20617}},
-{17953, 18, 76422, {1, 1, 5, 15, 15, 51, 103, 17, 433, 611, 1351, 1729, 6147, 11623, 3, 6319, 6133, 19029}},
-{17954, 18, 76450, {1, 3, 1, 13, 29, 15, 115, 97, 505, 985, 745, 745, 1459, 7193, 1247, 58901, 114255, 212849}},
-{17955, 18, 76496, {1, 1, 7, 1, 1, 53, 99, 35, 377, 723, 1751, 2625, 5113, 13295, 20133, 26831, 41657, 51717}},
-{17956, 18, 76521, {1, 3, 5, 15, 15, 39, 17, 227, 351, 435, 49, 203, 6959, 11673, 15755, 29733, 51445, 64619}},
-{17957, 18, 76522, {1, 1, 1, 3, 25, 51, 57, 137, 415, 49, 355, 2149, 7607, 10781, 30363, 43889, 55543, 36637}},
-{17958, 18, 76527, {1, 1, 7, 5, 5, 15, 73, 189, 153, 949, 527, 587, 513, 12891, 16765, 41477, 75569, 80747}},
-{17959, 18, 76536, {1, 1, 5, 5, 9, 5, 3, 225, 115, 125, 821, 3551, 4833, 927, 24331, 63669, 26549, 220159}},
-{17960, 18, 76541, {1, 1, 3, 9, 21, 7, 9, 183, 391, 783, 493, 2785, 3879, 8311, 9935, 60629, 119329, 5791}},
-{17961, 18, 76553, {1, 1, 5, 15, 15, 41, 61, 97, 33, 29, 199, 3335, 1531, 6107, 757, 33797, 3001, 224507}},
-{17962, 18, 76568, {1, 1, 3, 9, 13, 39, 25, 247, 407, 1, 1129, 1453, 7091, 5557, 8657, 33961, 100763, 25099}},
-{17963, 18, 76574, {1, 3, 3, 13, 31, 21, 69, 73, 431, 827, 861, 235, 2369, 4283, 27183, 29095, 99957, 97577}},
-{17964, 18, 76584, {1, 1, 7, 13, 1, 25, 21, 173, 365, 921, 21, 3527, 2481, 8795, 25621, 41755, 127249, 221385}},
-{17965, 18, 76604, {1, 1, 1, 5, 25, 25, 65, 203, 305, 373, 527, 4033, 3483, 9403, 28669, 32083, 52273, 77037}},
-{17966, 18, 76607, {1, 3, 1, 15, 9, 23, 19, 7, 29, 83, 1163, 1147, 5315, 2381, 21203, 33915, 109511, 40669}},
-{17967, 18, 76609, {1, 3, 7, 15, 23, 19, 69, 127, 113, 937, 935, 1067, 2431, 7677, 21327, 44095, 82799, 5715}},
-{17968, 18, 76669, {1, 1, 5, 5, 7, 37, 107, 223, 433, 515, 393, 1721, 1977, 6383, 18835, 54841, 103263, 196997}},
-{17969, 18, 76683, {1, 1, 1, 3, 1, 11, 85, 173, 259, 685, 595, 1635, 6979, 4483, 8097, 42249, 56259, 105925}},
-{17970, 18, 76745, {1, 1, 7, 7, 1, 23, 11, 253, 187, 665, 313, 3745, 2423, 15835, 32085, 48643, 75625, 47511}},
-{17971, 18, 76753, {1, 1, 3, 5, 1, 59, 127, 83, 501, 387, 977, 3515, 7921, 12329, 14757, 20287, 49699, 91237}},
-{17972, 18, 76754, {1, 3, 5, 11, 31, 45, 51, 109, 319, 621, 1013, 3519, 4023, 12099, 28829, 26691, 83131, 261497}},
-{17973, 18, 76756, {1, 1, 3, 3, 5, 35, 51, 253, 253, 569, 1017, 2299, 8159, 13783, 22123, 55213, 111527, 110699}},
-{17974, 18, 76760, {1, 3, 7, 3, 9, 5, 59, 129, 41, 845, 723, 1607, 3047, 14323, 19277, 39447, 12465, 45925}},
-{17975, 18, 76782, {1, 1, 3, 1, 17, 35, 51, 79, 115, 361, 739, 2037, 6167, 14699, 28187, 65271, 67285, 48489}},
-{17976, 18, 76821, {1, 3, 1, 11, 1, 29, 95, 181, 419, 235, 745, 621, 3889, 2933, 743, 23801, 32057, 54103}},
-{17977, 18, 76828, {1, 3, 1, 11, 17, 47, 43, 55, 7, 695, 1653, 3983, 961, 3037, 8669, 10039, 86571, 6981}},
-{17978, 18, 76849, {1, 1, 5, 15, 13, 19, 67, 141, 291, 511, 1913, 397, 7423, 6541, 21845, 49821, 126047, 218587}},
-{17979, 18, 76850, {1, 1, 5, 3, 11, 13, 103, 213, 189, 115, 1495, 2695, 2127, 11979, 13609, 46615, 64775, 206417}},
-{17980, 18, 76870, {1, 3, 1, 5, 5, 9, 57, 207, 253, 251, 1155, 1319, 6699, 6613, 21757, 49703, 124879, 89987}},
-{17981, 18, 76874, {1, 3, 5, 7, 23, 25, 35, 81, 165, 789, 771, 415, 5557, 8431, 12043, 44359, 9447, 229481}},
-{17982, 18, 76898, {1, 1, 1, 13, 17, 21, 63, 251, 387, 767, 85, 3901, 3227, 10329, 5049, 56173, 58065, 78595}},
-{17983, 18, 76903, {1, 3, 1, 15, 23, 5, 45, 7, 123, 389, 1041, 1223, 5865, 5365, 2915, 24861, 106893, 170769}},
-{17984, 18, 76910, {1, 3, 7, 15, 27, 61, 27, 59, 309, 103, 279, 1829, 1501, 11277, 4461, 34817, 60973, 99805}},
-{17985, 18, 76921, {1, 1, 3, 9, 1, 25, 57, 85, 411, 699, 911, 1643, 2687, 13539, 10187, 21597, 18883, 212975}},
-{17986, 18, 76968, {1, 1, 3, 7, 5, 7, 81, 209, 225, 321, 1867, 2189, 6315, 5393, 8859, 47471, 41677, 222455}},
-{17987, 18, 77013, {1, 1, 5, 11, 27, 33, 119, 159, 273, 659, 883, 3773, 6519, 15449, 17219, 23923, 33749, 225489}},
-{17988, 18, 77027, {1, 1, 7, 13, 29, 39, 1, 161, 165, 531, 1019, 2369, 2093, 4341, 24945, 28537, 49467, 258065}},
-{17989, 18, 77042, {1, 3, 3, 3, 15, 59, 23, 143, 377, 943, 1329, 977, 7025, 2167, 17973, 65087, 115757, 75959}},
-{17990, 18, 77059, {1, 1, 1, 15, 17, 55, 33, 167, 43, 719, 51, 3873, 3317, 10763, 639, 58195, 20023, 100725}},
-{17991, 18, 77062, {1, 1, 7, 5, 17, 23, 71, 249, 23, 929, 467, 3073, 3355, 1343, 18755, 12247, 49737, 184103}},
-{17992, 18, 77074, {1, 3, 3, 15, 1, 9, 17, 193, 157, 265, 983, 1825, 4805, 2131, 22117, 32937, 57, 261867}},
-{17993, 18, 77076, {1, 3, 5, 9, 5, 1, 101, 141, 511, 489, 73, 1789, 1303, 2633, 709, 11891, 44897, 191229}},
-{17994, 18, 77110, {1, 1, 7, 15, 1, 27, 121, 7, 129, 421, 725, 1421, 3883, 13335, 7247, 8393, 85029, 127691}},
-{17995, 18, 77113, {1, 1, 3, 9, 19, 53, 121, 115, 85, 909, 1535, 3261, 7063, 16381, 1719, 19847, 19041, 215433}},
-{17996, 18, 77131, {1, 1, 7, 3, 17, 45, 91, 187, 181, 829, 609, 931, 5727, 3971, 14567, 15871, 9825, 184165}},
-{17997, 18, 77157, {1, 1, 1, 3, 5, 29, 7, 249, 361, 815, 1101, 1485, 6879, 5379, 7179, 27467, 101427, 196089}},
-{17998, 18, 77158, {1, 1, 5, 7, 23, 11, 27, 175, 237, 747, 1911, 3107, 961, 6649, 29887, 11003, 27561, 233841}},
-{17999, 18, 77216, {1, 1, 1, 5, 11, 5, 125, 227, 303, 315, 1879, 817, 7445, 1447, 9333, 54825, 118865, 216397}},
-{18000, 18, 77246, {1, 1, 3, 13, 17, 33, 27, 95, 245, 25, 1741, 2633, 1869, 14111, 24507, 61287, 46397, 220803}},
-{18001, 18, 77258, {1, 1, 7, 7, 25, 5, 41, 101, 171, 333, 497, 3417, 4921, 4553, 25487, 51529, 72873, 43525}},
-{18002, 18, 77281, {1, 1, 7, 7, 9, 19, 25, 161, 235, 929, 1663, 3237, 323, 3889, 31423, 2345, 63113, 212659}},
-{18003, 18, 77284, {1, 1, 5, 13, 29, 59, 39, 25, 393, 519, 429, 1461, 5867, 113, 28091, 36813, 47827, 163407}},
-{18004, 18, 77294, {1, 3, 5, 13, 15, 49, 85, 161, 83, 389, 765, 3349, 4659, 11007, 24749, 51121, 93511, 229885}},
-{18005, 18, 77302, {1, 3, 5, 11, 5, 27, 107, 233, 221, 425, 941, 1181, 5403, 4373, 32625, 41991, 2019, 245967}},
-{18006, 18, 77306, {1, 3, 5, 9, 9, 53, 97, 27, 221, 731, 1301, 3517, 4407, 11369, 4251, 31121, 4813, 42029}},
-{18007, 18, 77315, {1, 1, 1, 9, 17, 59, 107, 247, 231, 123, 1177, 3299, 6163, 4855, 14547, 63171, 45201, 27711}},
-{18008, 18, 77352, {1, 3, 7, 3, 25, 31, 63, 37, 123, 457, 1531, 3723, 4807, 14665, 17973, 42547, 5417, 170323}},
-{18009, 18, 77360, {1, 3, 7, 3, 17, 19, 57, 7, 359, 741, 385, 3127, 855, 10803, 30093, 24501, 53629, 40447}},
-{18010, 18, 77365, {1, 3, 7, 15, 11, 45, 49, 125, 445, 795, 113, 2425, 7085, 7337, 16297, 26447, 94369, 12371}},
-{18011, 18, 77370, {1, 3, 7, 9, 29, 59, 35, 191, 123, 619, 415, 1081, 2469, 4125, 25587, 7853, 119781, 9447}},
-{18012, 18, 77378, {1, 3, 1, 15, 13, 13, 111, 89, 381, 757, 389, 253, 6929, 33, 8263, 17385, 122129, 146679}},
-{18013, 18, 77380, {1, 1, 3, 3, 15, 35, 101, 95, 479, 577, 1645, 3781, 7533, 4665, 6561, 49897, 72413, 151383}},
-{18014, 18, 77407, {1, 1, 1, 1, 7, 49, 23, 223, 189, 763, 227, 2805, 8093, 389, 11525, 30915, 91341, 210231}},
-{18015, 18, 77408, {1, 1, 7, 3, 19, 23, 3, 137, 79, 569, 1833, 2091, 4235, 10739, 22855, 33845, 120141, 220267}},
-{18016, 18, 77414, {1, 3, 7, 3, 11, 43, 85, 63, 419, 681, 365, 3017, 3603, 6413, 13515, 16003, 107949, 241261}},
-{18017, 18, 77444, {1, 1, 5, 13, 3, 35, 41, 193, 189, 999, 1395, 2431, 2227, 7245, 23929, 16137, 14591, 54999}},
-{18018, 18, 77454, {1, 1, 7, 15, 23, 51, 47, 77, 31, 25, 589, 611, 371, 13329, 5873, 2133, 40351, 145293}},
-{18019, 18, 77481, {1, 1, 7, 15, 17, 19, 53, 155, 309, 573, 1059, 3557, 2445, 12205, 4497, 32061, 130293, 73859}},
-{18020, 18, 77482, {1, 1, 7, 13, 3, 25, 71, 157, 237, 185, 1035, 1759, 1331, 13533, 25635, 811, 54391, 91109}},
-{18021, 18, 77531, {1, 1, 1, 11, 5, 21, 99, 31, 259, 413, 2033, 2187, 755, 4591, 28641, 64031, 88499, 160789}},
-{18022, 18, 77544, {1, 3, 7, 13, 29, 33, 13, 157, 97, 981, 329, 81, 6351, 4171, 10925, 22733, 72521, 105477}},
-{18023, 18, 77552, {1, 3, 7, 9, 11, 31, 97, 35, 337, 309, 847, 3429, 2697, 3141, 19481, 43679, 11129, 205757}},
-{18024, 18, 77569, {1, 3, 1, 7, 27, 45, 123, 193, 439, 639, 633, 1375, 7307, 1599, 23379, 56811, 100877, 228687}},
-{18025, 18, 77579, {1, 3, 7, 1, 29, 43, 103, 131, 103, 933, 143, 2431, 2221, 4565, 20841, 58611, 49163, 13673}},
-{18026, 18, 77610, {1, 3, 5, 13, 25, 17, 121, 17, 455, 941, 1577, 509, 5401, 797, 29573, 38373, 50527, 17951}},
-{18027, 18, 77612, {1, 1, 1, 13, 25, 21, 77, 253, 199, 871, 935, 3919, 1687, 6653, 20345, 56969, 77989, 244767}},
-{18028, 18, 77623, {1, 1, 3, 1, 17, 5, 5, 191, 279, 33, 579, 651, 969, 6091, 11659, 1643, 17935, 85145}},
-{18029, 18, 77649, {1, 3, 3, 9, 29, 1, 103, 39, 83, 295, 1237, 207, 4837, 7899, 27879, 23195, 29549, 206885}},
-{18030, 18, 77650, {1, 3, 5, 1, 9, 55, 115, 37, 225, 447, 943, 1133, 6203, 949, 9973, 4309, 43969, 166795}},
-{18031, 18, 77661, {1, 1, 7, 7, 17, 43, 75, 251, 35, 489, 1011, 355, 4113, 2377, 13775, 34935, 84905, 252973}},
-{18032, 18, 77675, {1, 3, 3, 3, 11, 45, 3, 1, 135, 499, 81, 3265, 6657, 3875, 27565, 60931, 13117, 87931}},
-{18033, 18, 77686, {1, 1, 3, 1, 9, 1, 77, 69, 137, 241, 1613, 2607, 3307, 171, 13551, 54529, 45937, 180411}},
-{18034, 18, 77742, {1, 1, 1, 1, 19, 29, 77, 255, 95, 461, 567, 1103, 2753, 10627, 19479, 43411, 128565, 29869}},
-{18035, 18, 77791, {1, 1, 3, 5, 5, 63, 123, 159, 165, 733, 1107, 1711, 5039, 9221, 15541, 5527, 27629, 206505}},
-{18036, 18, 77792, {1, 3, 1, 3, 7, 45, 73, 63, 413, 693, 433, 2281, 3981, 7719, 31473, 56939, 70391, 67467}},
-{18037, 18, 77807, {1, 1, 1, 11, 19, 33, 113, 151, 427, 603, 1653, 2451, 5367, 12171, 14373, 33175, 62013, 209273}},
-{18038, 18, 77815, {1, 3, 5, 5, 17, 37, 109, 5, 187, 293, 617, 2663, 7381, 14217, 23561, 48999, 108717, 248289}},
-{18039, 18, 77842, {1, 1, 5, 1, 9, 27, 35, 127, 355, 479, 281, 2081, 7303, 259, 8893, 59141, 20927, 61611}},
-{18040, 18, 77847, {1, 3, 3, 15, 31, 33, 71, 209, 315, 363, 593, 1035, 8029, 12501, 2859, 54745, 39391, 153259}},
-{18041, 18, 77899, {1, 3, 3, 11, 21, 39, 35, 173, 171, 15, 987, 3737, 7415, 1827, 973, 6831, 108643, 241333}},
-{18042, 18, 77901, {1, 3, 7, 9, 17, 37, 127, 243, 153, 195, 113, 309, 5301, 13619, 7927, 35385, 9501, 99241}},
-{18043, 18, 77904, {1, 3, 5, 13, 23, 9, 81, 235, 139, 635, 443, 2235, 2613, 2389, 18431, 8409, 2885, 254811}},
-{18044, 18, 77914, {1, 3, 7, 9, 1, 5, 15, 109, 141, 173, 1059, 1961, 7945, 10381, 17337, 19591, 42173, 119831}},
-{18045, 18, 77925, {1, 3, 1, 13, 19, 7, 111, 111, 345, 327, 1147, 2293, 49, 16213, 25309, 60537, 50421, 108467}},
-{18046, 18, 77950, {1, 1, 5, 1, 3, 23, 63, 219, 69, 879, 1397, 3857, 1859, 1939, 4851, 26549, 86019, 7927}},
-{18047, 18, 77959, {1, 3, 1, 13, 23, 61, 25, 31, 301, 189, 1031, 2817, 829, 8777, 26869, 54405, 43535, 234687}},
-{18048, 18, 77994, {1, 1, 1, 9, 11, 31, 13, 139, 77, 567, 949, 3415, 6955, 14973, 9565, 37911, 18395, 94167}},
-{18049, 18, 78004, {1, 3, 5, 13, 17, 17, 21, 213, 171, 993, 1001, 979, 5085, 3909, 11797, 48669, 73541, 48979}},
-{18050, 18, 78043, {1, 1, 7, 9, 7, 37, 35, 107, 347, 239, 585, 2883, 3235, 1053, 14871, 25799, 4861, 56335}},
-{18051, 18, 78052, {1, 1, 3, 5, 19, 7, 91, 139, 325, 921, 863, 209, 845, 15943, 8281, 55103, 110193, 216091}},
-{18052, 18, 78061, {1, 3, 1, 13, 31, 33, 65, 155, 177, 103, 1991, 343, 6299, 3587, 30215, 64335, 114301, 220403}},
-{18053, 18, 78064, {1, 3, 5, 3, 31, 37, 121, 157, 443, 349, 1097, 3683, 503, 14061, 14685, 29755, 61543, 232983}},
-{18054, 18, 78084, {1, 3, 3, 11, 17, 59, 29, 161, 381, 791, 1647, 1077, 6369, 1095, 17279, 43141, 65003, 144609}},
-{18055, 18, 78094, {1, 1, 5, 1, 1, 15, 67, 77, 3, 585, 1909, 1485, 3003, 591, 4711, 10279, 75901, 226417}},
-{18056, 18, 78099, {1, 3, 7, 5, 1, 5, 5, 193, 469, 631, 1065, 607, 2751, 8163, 13633, 40563, 1417, 118169}},
-{18057, 18, 78129, {1, 1, 7, 9, 25, 25, 109, 27, 157, 495, 225, 1385, 4315, 995, 10591, 1629, 129939, 56765}},
-{18058, 18, 78142, {1, 3, 1, 7, 9, 23, 61, 63, 35, 145, 1537, 1029, 4225, 1467, 10519, 32861, 519, 53983}},
-{18059, 18, 78149, {1, 3, 3, 11, 7, 59, 25, 199, 403, 967, 1089, 1121, 1063, 6701, 16827, 55479, 72983, 36873}},
-{18060, 18, 78153, {1, 1, 1, 13, 9, 27, 19, 23, 395, 229, 1837, 1231, 1737, 10475, 16743, 42369, 130331, 47255}},
-{18061, 18, 78171, {1, 1, 5, 7, 29, 15, 95, 155, 339, 65, 751, 2399, 5615, 2987, 16769, 57381, 113021, 41417}},
-{18062, 18, 78173, {1, 3, 1, 9, 15, 17, 1, 111, 197, 7, 417, 3999, 7261, 5939, 16773, 29275, 105559, 84685}},
-{18063, 18, 78174, {1, 3, 3, 13, 19, 31, 103, 1, 37, 269, 1257, 1397, 4293, 3019, 6503, 7727, 93943, 237313}},
-{18064, 18, 78195, {1, 1, 3, 9, 13, 37, 67, 129, 43, 669, 1331, 1787, 8185, 323, 18749, 13737, 86123, 154131}},
-{18065, 18, 78201, {1, 3, 1, 11, 3, 51, 13, 35, 197, 867, 559, 1381, 1057, 13293, 20603, 18633, 50503, 169685}},
-{18066, 18, 78202, {1, 3, 1, 11, 9, 35, 7, 51, 499, 885, 353, 4095, 6491, 5917, 15053, 18363, 99593, 213089}},
-{18067, 18, 78241, {1, 1, 3, 9, 19, 23, 107, 147, 339, 331, 1349, 2855, 3721, 13317, 26457, 783, 93949, 196051}},
-{18068, 18, 78247, {1, 1, 5, 1, 9, 61, 89, 217, 315, 385, 1729, 2641, 5753, 6269, 547, 33737, 20103, 31533}},
-{18069, 18, 78274, {1, 3, 5, 13, 13, 61, 3, 191, 57, 683, 1227, 1255, 3651, 10687, 9049, 6529, 60783, 28639}},
-{18070, 18, 78276, {1, 1, 7, 11, 25, 41, 79, 19, 383, 363, 1731, 1597, 1651, 15037, 22191, 51883, 41927, 82419}},
-{18071, 18, 78303, {1, 3, 5, 9, 15, 61, 39, 149, 49, 633, 709, 1743, 621, 14659, 3309, 64129, 91897, 74235}},
-{18072, 18, 78307, {1, 3, 7, 15, 5, 59, 7, 197, 111, 885, 1737, 855, 2807, 3817, 13759, 29989, 45105, 171689}},
-{18073, 18, 78328, {1, 1, 3, 9, 21, 25, 55, 67, 483, 437, 303, 703, 6993, 1971, 4565, 56117, 6105, 254517}},
-{18074, 18, 78344, {1, 3, 3, 13, 15, 13, 19, 3, 487, 751, 1185, 2985, 1619, 7139, 26087, 21105, 9049, 236153}},
-{18075, 18, 78362, {1, 1, 5, 7, 15, 55, 51, 231, 85, 953, 713, 659, 2021, 4271, 15961, 26873, 31141, 76635}},
-{18076, 18, 78367, {1, 3, 5, 1, 11, 39, 3, 223, 367, 903, 799, 415, 7247, 9539, 14479, 37195, 59951, 181935}},
-{18077, 18, 78368, {1, 1, 5, 3, 13, 47, 17, 159, 439, 859, 1067, 3111, 5277, 13973, 21999, 28381, 115685, 231483}},
-{18078, 18, 78409, {1, 1, 7, 15, 17, 21, 69, 131, 193, 479, 1075, 3271, 2057, 1295, 31235, 35027, 94145, 65419}},
-{18079, 18, 78412, {1, 3, 3, 5, 5, 21, 5, 81, 113, 259, 837, 831, 5985, 6717, 12041, 40355, 50957, 111185}},
-{18080, 18, 78417, {1, 1, 1, 9, 15, 47, 103, 195, 465, 739, 1415, 225, 3121, 12623, 7539, 17555, 36703, 217641}},
-{18081, 18, 78430, {1, 3, 1, 3, 31, 17, 91, 153, 221, 217, 525, 981, 281, 9869, 9713, 10669, 12049, 97615}},
-{18082, 18, 78433, {1, 1, 5, 7, 29, 1, 1, 199, 415, 843, 301, 941, 4589, 13301, 5833, 41311, 74019, 78537}},
-{18083, 18, 78440, {1, 1, 5, 11, 13, 5, 41, 127, 213, 917, 1297, 2281, 3193, 3877, 9517, 40685, 14657, 185139}},
-{18084, 18, 78451, {1, 1, 1, 7, 21, 45, 87, 33, 425, 487, 643, 271, 7087, 5979, 14795, 27575, 34541, 173251}},
-{18085, 18, 78453, {1, 3, 7, 5, 21, 11, 7, 169, 325, 905, 973, 2853, 7929, 8801, 1005, 60641, 45973, 81859}},
-{18086, 18, 78458, {1, 3, 3, 1, 1, 35, 39, 81, 93, 463, 697, 2309, 7769, 5169, 17595, 41447, 28837, 52613}},
-{18087, 18, 78467, {1, 1, 7, 1, 1, 23, 37, 17, 137, 873, 1657, 681, 503, 7887, 24463, 32453, 112727, 133347}},
-{18088, 18, 78479, {1, 1, 5, 9, 19, 35, 37, 85, 11, 245, 11, 3, 6475, 5953, 247, 49447, 32813, 243841}},
-{18089, 18, 78507, {1, 3, 5, 3, 19, 53, 37, 45, 431, 259, 1831, 1443, 2237, 7651, 20701, 22857, 50041, 119667}},
-{18090, 18, 78518, {1, 1, 7, 1, 5, 37, 113, 69, 389, 369, 1251, 1989, 7613, 10669, 4233, 33379, 72465, 256861}},
-{18091, 18, 78535, {1, 1, 7, 5, 27, 55, 17, 75, 373, 325, 1981, 1743, 7341, 319, 28169, 3587, 66057, 169723}},
-{18092, 18, 78542, {1, 3, 3, 15, 27, 31, 47, 91, 367, 245, 2045, 979, 2169, 10935, 29523, 64871, 119447, 92131}},
-{18093, 18, 78549, {1, 3, 7, 15, 9, 11, 93, 61, 249, 107, 1883, 2547, 375, 4195, 6451, 14533, 62529, 93557}},
-{18094, 18, 78554, {1, 1, 1, 3, 29, 61, 65, 155, 301, 1017, 131, 1567, 3649, 3447, 27943, 52111, 9133, 88147}},
-{18095, 18, 78556, {1, 1, 1, 1, 21, 59, 107, 151, 265, 707, 767, 2325, 8095, 14027, 15355, 15465, 83143, 116199}},
-{18096, 18, 78583, {1, 3, 1, 15, 23, 51, 31, 25, 439, 357, 1563, 1091, 2135, 1327, 18427, 60965, 29215, 157351}},
-{18097, 18, 78590, {1, 3, 3, 13, 29, 37, 25, 215, 149, 487, 703, 1787, 3641, 8301, 8795, 13845, 95245, 169793}},
-{18098, 18, 78615, {1, 3, 3, 11, 27, 3, 49, 87, 69, 687, 1181, 3405, 589, 12901, 14199, 48607, 74027, 181379}},
-{18099, 18, 78635, {1, 3, 5, 13, 9, 15, 33, 229, 135, 769, 1005, 2435, 4831, 5493, 16745, 64379, 20253, 52661}},
-{18100, 18, 78649, {1, 1, 1, 13, 9, 61, 33, 127, 339, 15, 945, 219, 4291, 6995, 29127, 61853, 40741, 170541}},
-{18101, 18, 78684, {1, 3, 3, 15, 9, 33, 75, 39, 327, 133, 733, 1125, 2747, 15031, 24575, 65013, 41997, 158679}},
-{18102, 18, 78691, {1, 1, 3, 9, 3, 9, 63, 83, 493, 175, 249, 1977, 8177, 4067, 2131, 12467, 86185, 73417}},
-{18103, 18, 78705, {1, 1, 3, 13, 29, 55, 91, 109, 73, 913, 1343, 2147, 105, 8763, 7613, 55749, 4339, 61253}},
-{18104, 18, 78724, {1, 1, 5, 5, 17, 19, 45, 57, 345, 835, 341, 1365, 5187, 7485, 22685, 32321, 67279, 141119}},
-{18105, 18, 78755, {1, 1, 3, 11, 9, 47, 11, 231, 241, 681, 255, 3663, 5547, 997, 2445, 64413, 55349, 61785}},
-{18106, 18, 78770, {1, 3, 5, 5, 23, 29, 23, 249, 149, 1011, 173, 271, 485, 1239, 81, 59277, 96669, 210859}},
-{18107, 18, 78772, {1, 3, 3, 1, 17, 9, 41, 39, 309, 131, 1431, 1497, 1669, 14191, 22795, 48951, 101731, 70847}},
-{18108, 18, 78818, {1, 1, 3, 15, 1, 11, 37, 79, 23, 1023, 585, 127, 7817, 15009, 3897, 44601, 83039, 240457}},
-{18109, 18, 78837, {1, 3, 5, 9, 21, 33, 55, 31, 193, 745, 1741, 3637, 7265, 8969, 11797, 33239, 29123, 126077}},
-{18110, 18, 78844, {1, 3, 3, 13, 31, 5, 87, 215, 271, 573, 1423, 2611, 947, 14669, 23785, 60579, 127099, 55877}},
-{18111, 18, 78849, {1, 3, 1, 13, 5, 53, 103, 85, 237, 457, 739, 1201, 133, 8589, 13471, 6707, 42257, 141989}},
-{18112, 18, 78909, {1, 1, 1, 5, 23, 3, 65, 159, 445, 823, 341, 1723, 6263, 9421, 16023, 19145, 52337, 229397}},
-{18113, 18, 78915, {1, 3, 5, 3, 15, 3, 15, 251, 407, 137, 951, 1319, 1035, 7713, 29579, 19591, 77841, 84949}},
-{18114, 18, 78941, {1, 1, 7, 15, 19, 25, 63, 141, 511, 11, 1027, 1209, 6627, 8127, 14879, 12965, 109973, 144501}},
-{18115, 18, 78958, {1, 1, 1, 3, 11, 57, 65, 169, 453, 197, 1249, 2933, 3743, 1971, 19373, 32109, 73265, 46185}},
-{18116, 18, 78975, {1, 1, 3, 1, 3, 1, 21, 47, 471, 565, 1795, 1771, 3187, 7189, 18627, 22993, 112319, 158693}},
-{18117, 18, 78979, {1, 1, 5, 7, 5, 25, 127, 113, 31, 609, 1273, 2799, 5713, 16091, 22239, 43617, 126003, 218991}},
-{18118, 18, 78986, {1, 3, 3, 7, 19, 59, 19, 185, 483, 431, 335, 565, 819, 2555, 18653, 36573, 50085, 31007}},
-{18119, 18, 79029, {1, 1, 3, 13, 17, 61, 5, 219, 297, 755, 2005, 391, 4927, 1517, 11341, 9527, 51739, 182599}},
-{18120, 18, 79030, {1, 3, 7, 9, 9, 3, 39, 211, 475, 717, 189, 819, 529, 469, 28559, 7321, 60213, 79505}},
-{18121, 18, 79044, {1, 3, 1, 9, 17, 39, 53, 65, 247, 145, 9, 1669, 7221, 8359, 11021, 29775, 24693, 208655}},
-{18122, 18, 79048, {1, 1, 5, 13, 7, 7, 31, 135, 375, 439, 1419, 3579, 4313, 14057, 31505, 55249, 5345, 69537}},
-{18123, 18, 79056, {1, 3, 5, 9, 21, 3, 125, 223, 9, 73, 1693, 281, 3941, 10377, 29365, 19807, 73973, 169113}},
-{18124, 18, 79095, {1, 3, 7, 15, 29, 41, 119, 75, 241, 79, 1969, 1091, 6241, 10685, 11579, 3791, 124443, 5051}},
-{18125, 18, 79099, {1, 3, 7, 15, 23, 53, 13, 255, 205, 547, 255, 1589, 7261, 15735, 14521, 29679, 109373, 236433}},
-{18126, 18, 79121, {1, 3, 7, 3, 17, 37, 71, 163, 95, 265, 1, 3239, 1779, 9047, 31387, 32291, 86741, 55317}},
-{18127, 18, 79150, {1, 3, 1, 9, 31, 55, 117, 247, 317, 673, 749, 1155, 7743, 6427, 25273, 49701, 62345, 20913}},
-{18128, 18, 79196, {1, 3, 3, 7, 27, 55, 35, 111, 69, 799, 213, 3011, 4359, 14763, 7387, 13281, 58397, 38415}},
-{18129, 18, 79199, {1, 1, 5, 9, 5, 61, 49, 219, 419, 297, 1019, 2181, 6069, 12957, 24637, 23317, 6389, 240893}},
-{18130, 18, 79220, {1, 1, 5, 15, 13, 57, 59, 43, 373, 647, 1407, 3955, 5583, 15229, 20935, 38007, 65971, 95987}},
-{18131, 18, 79229, {1, 1, 7, 7, 23, 17, 77, 91, 449, 75, 1059, 3337, 2041, 261, 25077, 28161, 44537, 189443}},
-{18132, 18, 79263, {1, 1, 7, 11, 9, 7, 117, 225, 457, 941, 161, 1825, 1101, 193, 32619, 37245, 102633, 86707}},
-{18133, 18, 79264, {1, 1, 1, 7, 13, 43, 33, 137, 275, 691, 1387, 1265, 759, 1457, 4877, 41813, 4159, 234397}},
-{18134, 18, 79296, {1, 3, 3, 1, 9, 23, 71, 39, 205, 175, 953, 2965, 3283, 6025, 5905, 34691, 120987, 71841}},
-{18135, 18, 79302, {1, 3, 1, 13, 31, 63, 49, 73, 299, 169, 1265, 2205, 1299, 10045, 6919, 26067, 56909, 42549}},
-{18136, 18, 79354, {1, 3, 3, 1, 31, 41, 75, 219, 457, 407, 5, 1901, 6823, 531, 3155, 64375, 38523, 68217}},
-{18137, 18, 79387, {1, 1, 7, 9, 7, 35, 123, 193, 145, 1021, 757, 3775, 2313, 11885, 11649, 61071, 129363, 120467}},
-{18138, 18, 79399, {1, 3, 7, 3, 29, 21, 127, 93, 415, 641, 453, 923, 7713, 9569, 5961, 25969, 31095, 93317}},
-{18139, 18, 79435, {1, 3, 3, 1, 5, 15, 21, 235, 211, 663, 385, 2429, 319, 11571, 17539, 42975, 43179, 100105}},
-{18140, 18, 79525, {1, 3, 7, 7, 25, 57, 51, 215, 393, 167, 1569, 3235, 5555, 3391, 2389, 36485, 21919, 164479}},
-{18141, 18, 79540, {1, 3, 3, 3, 29, 21, 81, 59, 239, 671, 605, 583, 2341, 2321, 28593, 19035, 10209, 36433}},
-{18142, 18, 79552, {1, 3, 3, 11, 31, 33, 1, 147, 111, 523, 427, 3545, 111, 8009, 29101, 34549, 122745, 82117}},
-{18143, 18, 79562, {1, 3, 5, 15, 19, 37, 97, 141, 387, 523, 467, 1657, 4161, 5505, 18091, 39597, 124423, 74827}},
-{18144, 18, 79576, {1, 1, 1, 11, 21, 63, 61, 13, 169, 851, 1863, 3307, 7189, 10791, 22619, 24431, 127781, 14717}},
-{18145, 18, 79579, {1, 1, 3, 13, 27, 41, 69, 127, 497, 565, 1489, 277, 2551, 15409, 9885, 187, 101319, 194121}},
-{18146, 18, 79605, {1, 1, 7, 7, 17, 45, 1, 139, 347, 503, 1189, 1459, 6117, 14319, 22153, 2915, 91991, 246679}},
-{18147, 18, 79618, {1, 3, 3, 3, 9, 41, 25, 199, 327, 295, 945, 2765, 563, 11605, 24267, 37729, 80057, 169479}},
-{18148, 18, 79648, {1, 1, 7, 3, 23, 19, 13, 219, 235, 837, 1015, 2071, 2727, 3989, 32539, 26713, 112391, 163943}},
-{18149, 18, 79654, {1, 3, 3, 9, 21, 27, 17, 187, 315, 753, 817, 3053, 5961, 973, 23973, 37621, 105637, 247711}},
-{18150, 18, 79666, {1, 1, 7, 1, 11, 15, 45, 25, 421, 213, 663, 3829, 469, 15889, 28773, 14323, 107705, 111729}},
-{18151, 18, 79686, {1, 1, 1, 7, 7, 7, 51, 189, 457, 95, 1903, 639, 1933, 7409, 22327, 18959, 42679, 158987}},
-{18152, 18, 79697, {1, 1, 5, 9, 13, 13, 49, 159, 387, 365, 1799, 2399, 6375, 14965, 32495, 5383, 73479, 5653}},
-{18153, 18, 79700, {1, 1, 3, 1, 29, 23, 81, 73, 183, 563, 435, 133, 5731, 6663, 21219, 60007, 101215, 68775}},
-{18154, 18, 79723, {1, 1, 7, 11, 31, 47, 43, 159, 221, 745, 1317, 2405, 4563, 4073, 27675, 14225, 114231, 222553}},
-{18155, 18, 79749, {1, 1, 1, 5, 11, 63, 105, 99, 413, 81, 771, 547, 1633, 8097, 30431, 31417, 101379, 163575}},
-{18156, 18, 79750, {1, 1, 3, 9, 23, 29, 123, 149, 241, 267, 1925, 467, 7743, 4473, 12223, 10521, 86265, 89949}},
-{18157, 18, 79764, {1, 3, 5, 1, 31, 29, 111, 67, 311, 851, 1919, 2563, 3725, 4035, 7241, 13859, 105207, 200599}},
-{18158, 18, 79771, {1, 3, 7, 3, 19, 53, 113, 107, 133, 243, 2021, 2669, 4633, 14393, 24827, 1233, 81471, 20105}},
-{18159, 18, 79774, {1, 1, 1, 5, 3, 23, 43, 149, 157, 875, 1175, 963, 6189, 7343, 13913, 41375, 112857, 236047}},
-{18160, 18, 79780, {1, 3, 5, 15, 11, 31, 43, 225, 469, 229, 703, 3033, 2341, 10309, 12057, 13325, 109019, 130789}},
-{18161, 18, 79789, {1, 1, 1, 7, 27, 47, 45, 49, 371, 971, 1121, 2179, 1267, 9499, 10771, 28781, 77059, 90765}},
-{18162, 18, 79798, {1, 1, 7, 1, 17, 27, 59, 169, 269, 217, 983, 1365, 1985, 12287, 5385, 46407, 24827, 155761}},
-{18163, 18, 79821, {1, 1, 7, 11, 9, 5, 19, 205, 159, 937, 763, 3823, 3625, 14209, 32031, 58879, 118449, 50723}},
-{18164, 18, 79850, {1, 1, 5, 3, 25, 55, 27, 35, 125, 999, 1541, 3883, 539, 5691, 18071, 63199, 112089, 194825}},
-{18165, 18, 79864, {1, 3, 3, 1, 27, 43, 57, 225, 173, 673, 1339, 3433, 5743, 1375, 32429, 35071, 98035, 229973}},
-{18166, 18, 79898, {1, 3, 3, 9, 3, 51, 5, 203, 439, 41, 529, 863, 6735, 13211, 7075, 55637, 24481, 46673}},
-{18167, 18, 79904, {1, 1, 5, 11, 15, 23, 93, 7, 181, 843, 777, 1299, 1941, 7147, 26253, 10967, 5387, 84611}},
-{18168, 18, 79934, {1, 3, 1, 7, 9, 57, 127, 155, 257, 423, 1421, 261, 4477, 11169, 22997, 12371, 8705, 135883}},
-{18169, 18, 79936, {1, 3, 1, 9, 17, 9, 15, 209, 427, 889, 1939, 3623, 2587, 4037, 32233, 40391, 32529, 63851}},
-{18170, 18, 79942, {1, 3, 3, 13, 3, 19, 49, 155, 213, 239, 817, 1787, 2999, 9955, 20155, 44711, 41367, 59623}},
-{18171, 18, 79945, {1, 3, 7, 5, 5, 39, 103, 181, 405, 85, 1997, 3639, 1259, 10737, 189, 44377, 23589, 89371}},
-{18172, 18, 79963, {1, 3, 5, 11, 15, 13, 57, 81, 203, 773, 1571, 3235, 6625, 13803, 2091, 64265, 131013, 189705}},
-{18173, 18, 79987, {1, 1, 1, 13, 15, 3, 113, 159, 149, 55, 355, 2345, 5043, 4067, 23277, 32647, 43755, 5445}},
-{18174, 18, 80057, {1, 3, 3, 9, 31, 7, 67, 177, 423, 269, 1731, 3957, 4383, 13483, 14653, 8243, 57689, 37375}},
-{18175, 18, 80077, {1, 1, 3, 5, 25, 5, 77, 199, 161, 859, 497, 1679, 6809, 4877, 1107, 16443, 15505, 138155}},
-{18176, 18, 80078, {1, 3, 5, 1, 11, 57, 7, 49, 145, 569, 571, 2679, 7531, 14517, 12425, 6285, 116961, 116397}},
-{18177, 18, 80080, {1, 1, 7, 11, 1, 37, 65, 43, 151, 419, 801, 3231, 5321, 10725, 12885, 62771, 16507, 179009}},
-{18178, 18, 80102, {1, 1, 5, 11, 29, 55, 89, 81, 325, 47, 1037, 3235, 2017, 10875, 8919, 25115, 118035, 178227}},
-{18179, 18, 80106, {1, 3, 1, 7, 1, 43, 101, 25, 449, 617, 381, 3437, 6655, 1291, 18693, 53939, 99143, 195695}},
-{18180, 18, 80111, {1, 3, 1, 5, 23, 7, 47, 159, 295, 939, 173, 3087, 1497, 6353, 13893, 13465, 118973, 193737}},
-{18181, 18, 80152, {1, 1, 3, 9, 3, 41, 65, 79, 449, 345, 2039, 1193, 5915, 13689, 1257, 23273, 48515, 256793}},
-{18182, 18, 80155, {1, 3, 5, 11, 11, 55, 13, 117, 343, 899, 1853, 373, 6885, 12863, 1209, 34433, 48215, 218187}},
-{18183, 18, 80173, {1, 3, 7, 7, 3, 45, 103, 145, 55, 507, 743, 4027, 2075, 15707, 4473, 50077, 64551, 204305}},
-{18184, 18, 80186, {1, 1, 3, 5, 31, 45, 123, 233, 363, 1003, 411, 1459, 6455, 985, 29451, 17625, 44153, 137097}},
-{18185, 18, 80203, {1, 3, 3, 1, 27, 11, 53, 251, 41, 43, 495, 107, 6145, 8785, 28997, 7181, 92903, 105785}},
-{18186, 18, 80223, {1, 1, 3, 11, 13, 5, 117, 141, 463, 639, 1857, 2873, 3627, 6081, 18207, 29451, 80909, 73557}},
-{18187, 18, 80233, {1, 1, 1, 3, 29, 51, 15, 81, 85, 487, 307, 2481, 2769, 14901, 9407, 58321, 52813, 230393}},
-{18188, 18, 80258, {1, 3, 3, 11, 31, 7, 107, 43, 205, 811, 1121, 2757, 2447, 6843, 21347, 9143, 41003, 80507}},
-{18189, 18, 80281, {1, 1, 1, 1, 29, 19, 13, 203, 47, 689, 2003, 1477, 7857, 5031, 21781, 5745, 3649, 160389}},
-{18190, 18, 80318, {1, 3, 3, 7, 21, 21, 65, 3, 351, 157, 167, 3425, 2395, 9165, 26143, 57221, 127171, 54461}},
-{18191, 18, 80326, {1, 3, 1, 15, 13, 13, 65, 53, 305, 719, 181, 709, 5485, 13385, 30287, 52669, 82647, 83851}},
-{18192, 18, 80330, {1, 1, 3, 11, 11, 23, 31, 109, 205, 123, 509, 3831, 7771, 7341, 31613, 28035, 38061, 49375}},
-{18193, 18, 80337, {1, 3, 3, 3, 15, 33, 47, 159, 321, 589, 393, 3253, 3743, 6161, 445, 33129, 8181, 27793}},
-{18194, 18, 80344, {1, 1, 1, 13, 9, 57, 111, 253, 203, 539, 673, 855, 1937, 2699, 25795, 6889, 13531, 63561}},
-{18195, 18, 80365, {1, 1, 1, 13, 31, 45, 13, 101, 113, 903, 1699, 2423, 7967, 7957, 20303, 64395, 124447, 33947}},
-{18196, 18, 80383, {1, 3, 5, 11, 17, 39, 59, 181, 421, 535, 1445, 3927, 5433, 12885, 12497, 47231, 39819, 46371}},
-{18197, 18, 80389, {1, 3, 5, 7, 27, 3, 75, 49, 461, 781, 433, 1767, 6903, 11907, 2063, 55199, 82823, 229405}},
-{18198, 18, 80413, {1, 3, 3, 15, 17, 61, 17, 23, 247, 683, 33, 4027, 341, 8069, 2529, 9757, 95653, 12927}},
-{18199, 18, 80441, {1, 3, 3, 11, 17, 7, 29, 205, 353, 917, 219, 3509, 7803, 5939, 25111, 45357, 9259, 1549}},
-{18200, 18, 80449, {1, 3, 3, 15, 21, 7, 23, 25, 459, 291, 31, 2091, 1177, 9311, 12231, 16617, 33575, 252643}},
-{18201, 18, 80461, {1, 3, 5, 5, 3, 51, 113, 123, 453, 503, 1575, 2785, 5011, 1789, 819, 30857, 12955, 172421}},
-{18202, 18, 80467, {1, 1, 5, 3, 15, 15, 125, 65, 113, 281, 53, 3417, 5279, 6351, 25931, 54835, 124077, 204241}},
-{18203, 18, 80476, {1, 1, 3, 9, 29, 31, 19, 179, 275, 933, 711, 3351, 6221, 1711, 9375, 11645, 118911, 249395}},
-{18204, 18, 80507, {1, 3, 7, 13, 23, 59, 43, 61, 85, 267, 691, 3949, 2135, 3203, 21455, 61895, 71157, 136739}},
-{18205, 18, 80516, {1, 1, 7, 5, 19, 27, 69, 141, 9, 633, 95, 3789, 7823, 12635, 27661, 30285, 129469, 67163}},
-{18206, 18, 80519, {1, 3, 3, 9, 11, 25, 103, 47, 425, 809, 1279, 411, 219, 6703, 24145, 17303, 56835, 84879}},
-{18207, 18, 80568, {1, 1, 5, 13, 29, 41, 47, 133, 197, 615, 169, 2157, 1795, 4945, 31693, 57763, 39369, 83353}},
-{18208, 18, 80571, {1, 3, 1, 3, 27, 23, 23, 213, 387, 239, 977, 221, 383, 11005, 7221, 8795, 100963, 163777}},
-{18209, 18, 80579, {1, 1, 1, 1, 31, 29, 87, 93, 239, 399, 801, 3143, 6973, 16331, 16865, 1823, 1127, 41983}},
-{18210, 18, 80586, {1, 1, 3, 13, 7, 39, 25, 251, 277, 417, 119, 3033, 6785, 9783, 1641, 60169, 25047, 182263}},
-{18211, 18, 80599, {1, 1, 5, 5, 7, 35, 17, 47, 295, 861, 1671, 1971, 4583, 3925, 31013, 50039, 125191, 143019}},
-{18212, 18, 80610, {1, 1, 5, 1, 3, 57, 11, 23, 273, 209, 617, 1499, 665, 1193, 7539, 1625, 48065, 82843}},
-{18213, 18, 80629, {1, 1, 3, 15, 15, 17, 39, 145, 193, 503, 1305, 2071, 93, 11529, 14267, 14779, 49327, 51347}},
-{18214, 18, 80642, {1, 3, 5, 3, 7, 39, 63, 171, 263, 493, 383, 3209, 4277, 6259, 1345, 48013, 110571, 127865}},
-{18215, 18, 80690, {1, 3, 1, 7, 15, 29, 93, 75, 37, 235, 1095, 153, 745, 9785, 28831, 58899, 67091, 34743}},
-{18216, 18, 80713, {1, 3, 7, 9, 27, 23, 67, 85, 491, 447, 1899, 709, 555, 13979, 12529, 38383, 16091, 117301}},
-{18217, 18, 80716, {1, 1, 5, 3, 9, 55, 109, 173, 29, 19, 1265, 2391, 7761, 1953, 5643, 24079, 14187, 127017}},
-{18218, 18, 80737, {1, 3, 7, 13, 21, 57, 105, 145, 73, 421, 403, 5, 3523, 7005, 1109, 63357, 111671, 191857}},
-{18219, 18, 80743, {1, 1, 7, 13, 5, 27, 21, 5, 199, 515, 917, 365, 2775, 12453, 26989, 60593, 98977, 161759}},
-{18220, 18, 80750, {1, 3, 1, 13, 15, 37, 71, 65, 27, 533, 1311, 2981, 1945, 7183, 5337, 20659, 67355, 185633}},
-{18221, 18, 80786, {1, 1, 5, 7, 21, 39, 21, 195, 443, 979, 1033, 1823, 3045, 3023, 31783, 61803, 1023, 119291}},
-{18222, 18, 80811, {1, 1, 3, 11, 5, 15, 107, 155, 465, 249, 1845, 357, 2769, 3313, 12335, 16615, 20809, 103469}},
-{18223, 18, 80834, {1, 1, 3, 9, 13, 21, 11, 227, 173, 949, 1255, 3257, 601, 10865, 12779, 9173, 87255, 12867}},
-{18224, 18, 80839, {1, 3, 3, 15, 3, 41, 97, 141, 385, 23, 1253, 2905, 1523, 7647, 7069, 61143, 101245, 59747}},
-{18225, 18, 80840, {1, 3, 1, 3, 7, 35, 117, 93, 357, 741, 1673, 3295, 6809, 547, 22949, 42151, 91241, 16189}},
-{18226, 18, 80846, {1, 3, 5, 9, 25, 31, 27, 221, 55, 595, 1513, 3963, 3143, 1189, 19843, 6361, 19575, 231765}},
-{18227, 18, 80848, {1, 1, 5, 1, 3, 35, 91, 217, 385, 717, 57, 1471, 3529, 859, 15259, 4411, 54491, 79841}},
-{18228, 18, 80876, {1, 1, 5, 9, 29, 47, 111, 89, 469, 975, 513, 1339, 1747, 8839, 30375, 46217, 128191, 95831}},
-{18229, 18, 80911, {1, 1, 5, 13, 9, 45, 3, 221, 223, 461, 1353, 3953, 5505, 3139, 3407, 12953, 74487, 209401}},
-{18230, 18, 80947, {1, 1, 7, 7, 7, 43, 33, 143, 427, 183, 573, 2881, 7355, 10693, 12841, 14267, 61847, 47689}},
-{18231, 18, 81001, {1, 1, 3, 5, 23, 45, 53, 173, 347, 715, 173, 3385, 429, 8143, 2831, 57883, 77245, 37613}},
-{18232, 18, 81031, {1, 1, 1, 13, 21, 47, 33, 157, 171, 47, 1981, 2003, 7401, 7687, 10553, 38083, 111901, 30251}},
-{18233, 18, 81045, {1, 1, 5, 9, 23, 35, 121, 251, 7, 835, 1561, 1605, 7023, 15645, 14313, 6361, 107973, 211667}},
-{18234, 18, 81056, {1, 3, 1, 13, 25, 39, 81, 31, 145, 483, 1587, 3457, 5293, 927, 3529, 22457, 69689, 190371}},
-{18235, 18, 81073, {1, 1, 1, 3, 25, 61, 87, 111, 441, 829, 313, 2271, 205, 10187, 3003, 47237, 99899, 200553}},
-{18236, 18, 81083, {1, 1, 7, 13, 31, 51, 9, 243, 219, 139, 1703, 2001, 959, 11265, 27897, 9081, 4473, 107737}},
-{18237, 18, 81145, {1, 3, 5, 1, 25, 37, 61, 131, 487, 35, 1293, 833, 3847, 11315, 11811, 2763, 2199, 81127}},
-{18238, 18, 81168, {1, 3, 7, 7, 31, 33, 87, 111, 429, 809, 173, 1093, 7719, 14307, 5735, 61019, 21223, 26361}},
-{18239, 18, 81177, {1, 1, 3, 11, 17, 33, 31, 17, 49, 885, 1279, 2243, 3693, 61, 30909, 35807, 14027, 159225}},
-{18240, 18, 81207, {1, 3, 7, 11, 9, 35, 61, 75, 171, 117, 1285, 935, 7271, 3509, 14119, 31065, 58181, 136623}},
-{18241, 18, 81208, {1, 1, 3, 15, 3, 43, 93, 221, 239, 783, 37, 4007, 3637, 10461, 18425, 59629, 93781, 252689}},
-{18242, 18, 81226, {1, 3, 5, 7, 5, 61, 19, 107, 123, 417, 1655, 2307, 8177, 13617, 17195, 31597, 66241, 107199}},
-{18243, 18, 81245, {1, 3, 7, 7, 5, 5, 25, 69, 383, 217, 993, 2719, 3425, 8395, 1125, 10763, 80111, 70421}},
-{18244, 18, 81269, {1, 1, 3, 9, 29, 45, 123, 45, 89, 1015, 1703, 4049, 4969, 3801, 23657, 41031, 66415, 34063}},
-{18245, 18, 81285, {1, 1, 3, 3, 7, 53, 125, 63, 67, 335, 1937, 1793, 4641, 7115, 10951, 45503, 54723, 177433}},
-{18246, 18, 81289, {1, 3, 5, 1, 21, 55, 83, 199, 509, 331, 695, 2133, 1881, 14369, 21687, 2343, 85895, 99255}},
-{18247, 18, 81292, {1, 1, 5, 9, 11, 5, 111, 97, 433, 851, 1537, 411, 6629, 5185, 30749, 50017, 46177, 213347}},
-{18248, 18, 81298, {1, 3, 3, 1, 7, 21, 95, 229, 311, 605, 1277, 2435, 5053, 3051, 15447, 35479, 2835, 204149}},
-{18249, 18, 81310, {1, 3, 5, 9, 31, 27, 79, 201, 329, 735, 1933, 27, 6201, 9375, 24801, 34045, 16227, 61013}},
-{18250, 18, 81346, {1, 1, 5, 5, 31, 7, 73, 197, 455, 835, 1845, 2733, 3371, 513, 10495, 43659, 4621, 68969}},
-{18251, 18, 81348, {1, 1, 1, 15, 21, 55, 15, 83, 419, 471, 1427, 919, 7125, 7635, 25579, 19493, 37381, 191563}},
-{18252, 18, 81355, {1, 1, 7, 3, 15, 35, 25, 73, 295, 507, 719, 3307, 4253, 945, 21005, 24903, 80287, 48885}},
-{18253, 18, 81388, {1, 3, 7, 15, 27, 13, 71, 79, 189, 491, 1185, 3007, 4285, 13005, 18973, 33759, 15327, 45595}},
-{18254, 18, 81396, {1, 3, 3, 9, 9, 33, 115, 103, 31, 949, 1817, 2865, 1215, 9611, 16019, 7925, 72945, 208301}},
-{18255, 18, 81415, {1, 1, 1, 5, 19, 35, 89, 181, 409, 641, 1277, 2201, 2825, 5707, 13463, 34741, 39303, 217803}},
-{18256, 18, 81460, {1, 1, 3, 11, 13, 31, 65, 191, 11, 179, 509, 2513, 3861, 13323, 11817, 24901, 53815, 44343}},
-{18257, 18, 81482, {1, 3, 1, 5, 5, 57, 97, 25, 83, 177, 1963, 2367, 6703, 13361, 8749, 45533, 87883, 2977}},
-{18258, 18, 81518, {1, 3, 5, 3, 15, 41, 113, 145, 39, 509, 81, 1387, 2881, 1441, 75, 28409, 61417, 79393}},
-{18259, 18, 81523, {1, 3, 3, 3, 17, 1, 41, 19, 173, 133, 2033, 3637, 7415, 1841, 19497, 42643, 122885, 195301}},
-{18260, 18, 81529, {1, 3, 3, 9, 15, 37, 11, 87, 291, 881, 1471, 2469, 6877, 6813, 8273, 1455, 30957, 181887}},
-{18261, 18, 81545, {1, 3, 5, 9, 25, 41, 7, 71, 451, 831, 495, 3991, 4173, 4307, 31249, 7253, 57141, 35495}},
-{18262, 18, 81570, {1, 1, 7, 9, 15, 39, 29, 193, 327, 837, 991, 3503, 1175, 14965, 18151, 22479, 51127, 159019}},
-{18263, 18, 81576, {1, 3, 1, 9, 23, 41, 89, 211, 179, 507, 1005, 613, 8083, 15655, 1927, 23401, 51025, 21589}},
-{18264, 18, 81604, {1, 1, 5, 15, 5, 63, 105, 229, 239, 399, 591, 2233, 391, 2871, 29829, 49961, 62045, 190437}},
-{18265, 18, 81613, {1, 3, 5, 9, 7, 23, 85, 219, 163, 37, 1881, 589, 4239, 12845, 19993, 57267, 29519, 207597}},
-{18266, 18, 81631, {1, 3, 7, 15, 19, 19, 115, 141, 41, 405, 657, 2517, 4231, 10247, 21383, 11479, 52955, 121545}},
-{18267, 18, 81656, {1, 3, 1, 7, 23, 33, 65, 229, 287, 739, 1265, 1105, 487, 3801, 5211, 44731, 5359, 103685}},
-{18268, 18, 81679, {1, 3, 1, 13, 23, 29, 101, 153, 395, 335, 899, 303, 2073, 15767, 1303, 15539, 12889, 35517}},
-{18269, 18, 81684, {1, 1, 5, 11, 5, 63, 41, 53, 99, 339, 563, 2921, 4959, 13941, 13655, 10115, 56867, 42919}},
-{18270, 18, 81698, {1, 3, 5, 5, 5, 35, 127, 225, 497, 27, 139, 3269, 3929, 3369, 22697, 19421, 2921, 171927}},
-{18271, 18, 81736, {1, 1, 1, 15, 15, 21, 35, 251, 67, 447, 1045, 1173, 2951, 6589, 27261, 36597, 98721, 7205}},
-{18272, 18, 81747, {1, 3, 3, 9, 11, 63, 83, 19, 163, 381, 87, 1211, 3007, 4971, 27105, 2341, 21389, 32995}},
-{18273, 18, 81765, {1, 1, 3, 3, 21, 19, 63, 65, 505, 987, 1821, 2419, 3195, 2573, 1481, 35279, 45135, 597}},
-{18274, 18, 81775, {1, 3, 1, 15, 29, 5, 77, 65, 121, 223, 2009, 593, 7929, 10353, 22301, 25137, 40289, 95847}},
-{18275, 18, 81805, {1, 1, 3, 1, 17, 49, 9, 167, 69, 729, 1189, 1191, 1, 12603, 8281, 45193, 1427, 15887}},
-{18276, 18, 81842, {1, 1, 3, 7, 17, 5, 11, 217, 505, 317, 505, 1201, 8025, 13255, 12591, 16207, 32387, 242425}},
-{18277, 18, 81859, {1, 3, 7, 9, 25, 9, 97, 23, 91, 765, 653, 2689, 2787, 11719, 8455, 24665, 26907, 78525}},
-{18278, 18, 81865, {1, 3, 3, 15, 27, 19, 79, 157, 117, 715, 1921, 2453, 499, 13593, 14173, 1993, 110087, 151427}},
-{18279, 18, 81866, {1, 3, 1, 13, 5, 43, 59, 21, 451, 863, 533, 1723, 2059, 1611, 10403, 36479, 36999, 109553}},
-{18280, 18, 81892, {1, 3, 7, 7, 29, 63, 51, 5, 475, 549, 123, 1949, 5279, 8581, 20053, 52287, 125223, 152299}},
-{18281, 18, 81902, {1, 3, 1, 1, 7, 19, 1, 215, 273, 157, 1557, 425, 7549, 12337, 1735, 30917, 116487, 177335}},
-{18282, 18, 81933, {1, 1, 1, 1, 7, 47, 61, 191, 73, 551, 1435, 2283, 3191, 8545, 11875, 41389, 17607, 26869}},
-{18283, 18, 81934, {1, 1, 7, 9, 13, 61, 109, 121, 365, 223, 1729, 3311, 7249, 10765, 12419, 4235, 64127, 132257}},
-{18284, 18, 81942, {1, 1, 3, 13, 17, 25, 65, 49, 417, 311, 141, 1127, 53, 945, 28277, 33347, 96399, 166049}},
-{18285, 18, 81969, {1, 3, 7, 9, 5, 21, 93, 203, 467, 805, 115, 1757, 4535, 8687, 10423, 8065, 2955, 20403}},
-{18286, 18, 81981, {1, 3, 3, 15, 7, 63, 103, 137, 227, 111, 735, 2139, 4293, 5347, 4131, 63405, 42599, 173299}},
-{18287, 18, 81999, {1, 3, 7, 7, 17, 53, 127, 251, 57, 625, 843, 3045, 1319, 10085, 18591, 36115, 104193, 183891}},
-{18288, 18, 82004, {1, 3, 7, 1, 31, 57, 107, 253, 207, 739, 1703, 1377, 3807, 10289, 22969, 13087, 2805, 261279}},
-{18289, 18, 82008, {1, 1, 5, 5, 5, 59, 59, 63, 77, 663, 1109, 2159, 3725, 12355, 4805, 22433, 81851, 9419}},
-{18290, 18, 82032, {1, 1, 7, 15, 1, 1, 101, 101, 295, 311, 447, 3931, 933, 15713, 8919, 7185, 38577, 254203}},
-{18291, 18, 82035, {1, 1, 5, 15, 7, 35, 35, 141, 283, 665, 1685, 3875, 495, 1655, 8269, 23493, 1523, 248783}},
-{18292, 18, 82060, {1, 1, 5, 9, 27, 35, 25, 57, 285, 469, 1491, 1479, 3705, 11357, 5319, 11575, 116207, 215961}},
-{18293, 18, 82063, {1, 3, 5, 11, 7, 41, 67, 161, 73, 777, 247, 823, 6677, 1631, 3431, 2821, 25291, 17633}},
-{18294, 18, 82071, {1, 1, 3, 9, 19, 17, 45, 181, 139, 85, 857, 1231, 7167, 2951, 26847, 39113, 51705, 104617}},
-{18295, 18, 82081, {1, 3, 5, 1, 5, 55, 101, 209, 1, 47, 1059, 2175, 1549, 8007, 11267, 21863, 125567, 102775}},
-{18296, 18, 82082, {1, 3, 3, 15, 15, 21, 79, 85, 427, 963, 1335, 2129, 6831, 6613, 13319, 15781, 3781, 222547}},
-{18297, 18, 82105, {1, 3, 3, 13, 19, 63, 25, 123, 1, 215, 139, 1345, 5035, 3107, 14381, 6239, 18481, 202581}},
-{18298, 18, 82106, {1, 1, 5, 1, 11, 11, 11, 53, 109, 533, 1113, 177, 609, 15391, 22735, 62229, 103591, 89143}},
-{18299, 18, 82120, {1, 1, 5, 15, 3, 21, 115, 223, 167, 441, 277, 2971, 933, 2841, 26893, 48513, 74553, 250413}},
-{18300, 18, 82125, {1, 1, 1, 7, 19, 17, 43, 181, 483, 897, 819, 1657, 5539, 8847, 23483, 57605, 104703, 242559}},
-{18301, 18, 82156, {1, 3, 5, 11, 3, 63, 3, 129, 45, 981, 45, 845, 1481, 14735, 30451, 16937, 13789, 27107}},
-{18302, 18, 82176, {1, 3, 3, 15, 25, 11, 33, 49, 155, 947, 521, 3417, 3299, 1123, 9517, 32127, 117795, 223167}},
-{18303, 18, 82203, {1, 3, 5, 15, 3, 35, 27, 37, 287, 541, 727, 2779, 7033, 5189, 21579, 36895, 109645, 123353}},
-{18304, 18, 82210, {1, 3, 7, 9, 15, 53, 123, 125, 405, 841, 119, 63, 853, 8693, 1537, 25509, 49345, 54301}},
-{18305, 18, 82241, {1, 3, 7, 9, 11, 63, 65, 145, 283, 529, 1553, 883, 3319, 8601, 29379, 26991, 127343, 98701}},
-{18306, 18, 82287, {1, 1, 1, 7, 23, 59, 11, 89, 407, 869, 445, 659, 3029, 5465, 5063, 36775, 69089, 205367}},
-{18307, 18, 82323, {1, 3, 7, 5, 19, 35, 99, 49, 257, 287, 1113, 2825, 2797, 7283, 31757, 47015, 106987, 82589}},
-{18308, 18, 82330, {1, 3, 7, 11, 15, 37, 41, 101, 493, 725, 1091, 503, 2611, 13025, 11071, 39311, 5193, 92127}},
-{18309, 18, 82366, {1, 1, 3, 7, 9, 59, 69, 113, 381, 341, 1495, 3169, 5099, 69, 7911, 9721, 84609, 254171}},
-{18310, 18, 82378, {1, 3, 5, 7, 21, 19, 75, 71, 7, 617, 1185, 2787, 4147, 16045, 18859, 52347, 66551, 161563}},
-{18311, 18, 82395, {1, 3, 5, 3, 27, 39, 17, 205, 425, 3, 1443, 1947, 7645, 10125, 24577, 45373, 38015, 30407}},
-{18312, 18, 82398, {1, 3, 3, 11, 1, 57, 105, 251, 65, 389, 1993, 3933, 3093, 1425, 9483, 5953, 13147, 234121}},
-{18313, 18, 82401, {1, 3, 3, 3, 1, 27, 105, 45, 435, 393, 609, 291, 545, 4905, 22621, 62115, 78955, 84355}},
-{18314, 18, 82404, {1, 3, 7, 9, 1, 15, 91, 183, 301, 223, 1183, 1877, 2141, 5549, 371, 44147, 6771, 136777}},
-{18315, 18, 82419, {1, 1, 5, 15, 5, 49, 127, 161, 121, 979, 1247, 3681, 3805, 3363, 11643, 25735, 21193, 111657}},
-{18316, 18, 82421, {1, 3, 5, 15, 15, 33, 47, 91, 137, 323, 1577, 3723, 3609, 11533, 4415, 26467, 120947, 200919}},
-{18317, 18, 82428, {1, 3, 3, 3, 3, 33, 121, 161, 453, 205, 1815, 65, 5893, 4669, 14377, 10905, 9559, 56359}},
-{18318, 18, 82442, {1, 1, 1, 7, 1, 55, 21, 143, 411, 65, 1009, 2989, 133, 7059, 30981, 15417, 2651, 110345}},
-{18319, 18, 82452, {1, 1, 3, 7, 19, 25, 91, 241, 193, 903, 661, 665, 7681, 14111, 29197, 51299, 109519, 155827}},
-{18320, 18, 82455, {1, 1, 1, 15, 25, 3, 79, 57, 417, 73, 705, 7, 4415, 7699, 28185, 53005, 88547, 7281}},
-{18321, 18, 82466, {1, 1, 7, 13, 27, 21, 35, 197, 65, 171, 1773, 393, 3759, 8335, 5987, 20611, 91373, 80715}},
-{18322, 18, 82510, {1, 3, 7, 3, 17, 51, 85, 229, 131, 733, 281, 3157, 1283, 10751, 20203, 49955, 23861, 128517}},
-{18323, 18, 82524, {1, 1, 5, 15, 3, 27, 35, 87, 391, 509, 1627, 769, 701, 4933, 24597, 9695, 111441, 198493}},
-{18324, 18, 82545, {1, 1, 1, 15, 3, 31, 73, 235, 341, 263, 883, 2369, 4887, 4659, 9493, 6763, 130625, 15031}},
-{18325, 18, 82555, {1, 3, 1, 15, 1, 11, 63, 79, 389, 355, 619, 1361, 313, 1199, 555, 42213, 81089, 170863}},
-{18326, 18, 82581, {1, 3, 1, 15, 21, 27, 1, 179, 19, 241, 1655, 1803, 5413, 5353, 65, 31211, 3501, 27205}},
-{18327, 18, 82588, {1, 3, 3, 9, 9, 19, 63, 191, 217, 271, 1453, 2777, 2915, 13291, 31391, 37489, 86435, 22857}},
-{18328, 18, 82591, {1, 3, 5, 9, 13, 41, 85, 11, 333, 479, 363, 2591, 697, 8587, 3647, 5741, 21627, 244573}},
-{18329, 18, 82636, {1, 1, 3, 1, 5, 61, 83, 229, 193, 977, 677, 2585, 3273, 12035, 2621, 12943, 49293, 37985}},
-{18330, 18, 82658, {1, 1, 5, 7, 27, 9, 69, 189, 489, 747, 519, 719, 1493, 13337, 14933, 44359, 11471, 57245}},
-{18331, 18, 82675, {1, 3, 5, 1, 5, 17, 75, 89, 417, 367, 57, 1641, 1573, 1819, 31237, 5213, 78821, 149853}},
-{18332, 18, 82678, {1, 1, 7, 3, 7, 17, 121, 91, 211, 101, 1145, 3753, 2997, 67, 10755, 11261, 122489, 61679}},
-{18333, 18, 82716, {1, 3, 7, 7, 15, 17, 73, 133, 429, 285, 201, 1917, 5677, 1793, 21653, 49729, 68965, 5347}},
-{18334, 18, 82725, {1, 3, 3, 13, 23, 17, 49, 249, 71, 169, 619, 843, 2163, 585, 23309, 39509, 68087, 232233}},
-{18335, 18, 82743, {1, 1, 7, 15, 23, 15, 19, 227, 89, 719, 1247, 2521, 1509, 7553, 12225, 12865, 100107, 261847}},
-{18336, 18, 82744, {1, 1, 5, 3, 23, 17, 117, 5, 401, 57, 1945, 1081, 1269, 5921, 31815, 42341, 112099, 130047}},
-{18337, 18, 82762, {1, 1, 1, 1, 9, 5, 87, 203, 211, 1009, 403, 1617, 3969, 2541, 7261, 6989, 16579, 206159}},
-{18338, 18, 82770, {1, 3, 7, 9, 5, 13, 93, 191, 79, 631, 1019, 3639, 7137, 13859, 19603, 63263, 82947, 181023}},
-{18339, 18, 82809, {1, 1, 5, 11, 25, 17, 85, 51, 61, 311, 517, 2001, 6325, 6831, 10835, 20101, 115241, 15815}},
-{18340, 18, 82846, {1, 3, 7, 13, 29, 19, 33, 115, 473, 477, 471, 773, 4097, 11697, 30781, 20843, 27089, 181927}},
-{18341, 18, 82855, {1, 3, 5, 5, 21, 27, 3, 239, 45, 335, 505, 149, 3005, 3511, 18037, 31291, 6145, 2913}},
-{18342, 18, 82882, {1, 1, 3, 1, 25, 49, 21, 225, 27, 395, 415, 1813, 5727, 7211, 9887, 63533, 99185, 119269}},
-{18343, 18, 82899, {1, 3, 3, 5, 15, 53, 127, 195, 81, 895, 587, 561, 5951, 9901, 18117, 37855, 19393, 259031}},
-{18344, 18, 82905, {1, 1, 7, 13, 9, 49, 109, 127, 53, 735, 391, 1523, 3759, 10363, 11299, 3203, 89121, 122643}},
-{18345, 18, 82950, {1, 1, 5, 3, 13, 3, 21, 247, 259, 557, 977, 1465, 6889, 3879, 4627, 1439, 122809, 248941}},
-{18346, 18, 82953, {1, 3, 7, 15, 7, 19, 113, 251, 245, 63, 267, 1873, 6601, 16253, 24643, 7433, 130051, 233047}},
-{18347, 18, 82967, {1, 1, 3, 9, 29, 39, 47, 31, 493, 817, 1697, 2139, 1059, 11365, 31653, 56477, 119191, 45509}},
-{18348, 18, 82971, {1, 1, 1, 15, 9, 29, 99, 61, 109, 341, 1009, 1551, 897, 13075, 10603, 25153, 65911, 228213}},
-{18349, 18, 82987, {1, 3, 7, 7, 29, 47, 57, 85, 263, 767, 1633, 2473, 199, 49, 22287, 33345, 118877, 248435}},
-{18350, 18, 83007, {1, 3, 1, 9, 5, 45, 5, 179, 9, 129, 1231, 4075, 7497, 2159, 18101, 31039, 95213, 171913}},
-{18351, 18, 83009, {1, 1, 1, 13, 23, 1, 89, 63, 21, 983, 481, 773, 5957, 4823, 4483, 50405, 42979, 243567}},
-{18352, 18, 83012, {1, 1, 5, 13, 15, 21, 65, 133, 347, 511, 1887, 743, 7825, 1681, 4857, 49247, 21277, 212995}},
-{18353, 18, 83030, {1, 3, 7, 9, 7, 51, 3, 233, 287, 727, 815, 3609, 397, 5721, 16473, 7549, 100455, 136233}},
-{18354, 18, 83045, {1, 3, 1, 1, 31, 51, 59, 37, 79, 623, 1219, 2655, 4619, 11967, 11377, 28985, 16069, 188773}},
-{18355, 18, 83050, {1, 3, 3, 13, 13, 59, 93, 159, 197, 339, 1633, 1601, 255, 1631, 4989, 12019, 23921, 261273}},
-{18356, 18, 83052, {1, 1, 3, 13, 27, 25, 55, 43, 147, 981, 65, 725, 5753, 115, 26125, 25501, 89099, 233419}},
-{18357, 18, 83070, {1, 3, 7, 5, 25, 3, 95, 135, 191, 417, 929, 3855, 5829, 3827, 13979, 65367, 63683, 85911}},
-{18358, 18, 83076, {1, 3, 5, 1, 7, 63, 45, 187, 355, 735, 1325, 1461, 3869, 2127, 18231, 45891, 24027, 202997}},
-{18359, 18, 83086, {1, 3, 7, 13, 19, 47, 89, 229, 253, 659, 355, 3323, 4081, 8243, 32553, 46579, 46431, 53291}},
-{18360, 18, 83128, {1, 1, 5, 11, 3, 61, 33, 65, 239, 779, 665, 1337, 6427, 12787, 1495, 27105, 71455, 89715}},
-{18361, 18, 83141, {1, 3, 1, 11, 31, 33, 115, 69, 511, 187, 99, 1055, 1065, 9531, 29897, 23897, 80581, 166957}},
-{18362, 18, 83153, {1, 1, 7, 13, 19, 1, 13, 241, 89, 761, 425, 3865, 961, 14999, 24175, 19103, 39095, 38899}},
-{18363, 18, 83156, {1, 3, 7, 7, 11, 17, 25, 217, 113, 615, 1455, 1409, 5679, 2321, 28687, 8089, 74031, 230559}},
-{18364, 18, 83194, {1, 3, 7, 1, 25, 15, 77, 111, 405, 523, 961, 647, 3857, 14355, 27063, 48829, 87913, 254965}},
-{18365, 18, 83225, {1, 1, 3, 3, 5, 13, 67, 155, 393, 943, 1875, 1209, 3765, 8627, 15123, 43405, 78473, 146127}},
-{18366, 18, 83261, {1, 1, 3, 7, 29, 43, 23, 33, 35, 883, 1859, 1559, 4163, 13277, 16971, 15289, 60305, 56743}},
-{18367, 18, 83264, {1, 1, 1, 5, 19, 55, 37, 53, 123, 35, 1477, 1035, 4683, 259, 20079, 37041, 48081, 198685}},
-{18368, 18, 83322, {1, 1, 3, 3, 1, 19, 27, 129, 427, 685, 959, 2501, 2761, 9495, 23649, 18789, 54521, 219547}},
-{18369, 18, 83382, {1, 1, 7, 1, 31, 11, 65, 171, 229, 11, 1825, 1641, 2731, 11085, 2567, 30831, 20365, 242731}},
-{18370, 18, 83391, {1, 1, 1, 13, 13, 5, 21, 175, 265, 271, 133, 407, 3415, 5943, 15385, 12817, 106159, 41859}},
-{18371, 18, 83399, {1, 3, 7, 1, 11, 45, 105, 229, 395, 877, 1495, 2113, 1733, 10117, 1125, 9989, 109637, 124517}},
-{18372, 18, 83406, {1, 1, 7, 3, 27, 43, 57, 77, 63, 907, 1137, 3333, 189, 15285, 13895, 23773, 73523, 47811}},
-{18373, 18, 83427, {1, 3, 3, 11, 17, 19, 81, 197, 73, 897, 515, 3801, 5105, 6987, 10125, 7239, 32339, 124411}},
-{18374, 18, 83439, {1, 3, 1, 9, 11, 15, 99, 109, 307, 133, 249, 1463, 5479, 8565, 19489, 13773, 11443, 149799}},
-{18375, 18, 83444, {1, 3, 7, 7, 19, 53, 61, 75, 83, 545, 1449, 683, 5845, 8325, 18111, 35941, 51843, 97907}},
-{18376, 18, 83453, {1, 1, 1, 3, 31, 23, 37, 187, 207, 51, 439, 3095, 2217, 6393, 9117, 2779, 47331, 118275}},
-{18377, 18, 83457, {1, 1, 3, 9, 23, 17, 41, 37, 59, 281, 319, 1333, 6207, 2265, 4445, 50831, 115893, 120491}},
-{18378, 18, 83475, {1, 3, 1, 13, 27, 23, 25, 23, 187, 51, 1257, 379, 921, 3801, 24537, 59547, 34191, 184625}},
-{18379, 18, 83484, {1, 1, 5, 3, 23, 21, 23, 159, 163, 537, 1589, 2797, 8007, 6767, 31331, 20741, 119969, 174135}},
-{18380, 18, 83488, {1, 3, 1, 1, 13, 35, 73, 147, 491, 317, 69, 1069, 5413, 13973, 19741, 44717, 63263, 77145}},
-{18381, 18, 83493, {1, 3, 1, 15, 31, 41, 23, 79, 55, 863, 129, 2229, 3395, 1621, 6273, 44521, 100047, 42337}},
-{18382, 18, 83512, {1, 3, 7, 3, 7, 5, 79, 1, 191, 227, 1039, 2909, 1085, 3173, 29311, 13861, 124785, 212453}},
-{18383, 18, 83525, {1, 3, 1, 5, 13, 9, 99, 213, 61, 201, 889, 1171, 3981, 2091, 31679, 26643, 5611, 154339}},
-{18384, 18, 83535, {1, 3, 3, 7, 27, 49, 53, 77, 285, 441, 1669, 2157, 223, 1899, 2725, 36547, 39273, 206653}},
-{18385, 18, 83560, {1, 3, 3, 9, 29, 5, 91, 1, 13, 409, 1275, 891, 6557, 5157, 6481, 57381, 87683, 117277}},
-{18386, 18, 83617, {1, 3, 3, 1, 11, 7, 13, 69, 9, 1015, 907, 2685, 6665, 16307, 24567, 13191, 9567, 55073}},
-{18387, 18, 83664, {1, 3, 1, 5, 19, 15, 65, 13, 503, 427, 1947, 1869, 5857, 823, 20533, 25337, 83551, 128505}},
-{18388, 18, 83676, {1, 1, 5, 11, 25, 53, 83, 175, 445, 5, 841, 2773, 4381, 2829, 1927, 63689, 63643, 246629}},
-{18389, 18, 83757, {1, 3, 1, 11, 27, 63, 43, 95, 453, 235, 673, 117, 6617, 7589, 5767, 16465, 36961, 39395}},
-{18390, 18, 83770, {1, 1, 3, 13, 3, 27, 119, 87, 209, 167, 721, 1499, 1955, 9151, 11649, 29009, 25249, 26125}},
-{18391, 18, 83775, {1, 1, 5, 1, 9, 59, 47, 57, 81, 243, 485, 559, 7311, 15119, 9827, 47219, 5941, 16909}},
-{18392, 18, 83835, {1, 3, 7, 11, 29, 13, 97, 63, 289, 653, 1811, 835, 801, 13103, 9333, 7785, 111587, 10021}},
-{18393, 18, 83838, {1, 3, 3, 1, 27, 61, 73, 165, 279, 239, 865, 517, 7763, 1917, 9839, 20725, 50721, 171351}},
-{18394, 18, 83848, {1, 3, 7, 1, 27, 29, 43, 137, 353, 927, 889, 2511, 709, 3309, 967, 18119, 48099, 98139}},
-{18395, 18, 83856, {1, 3, 1, 1, 17, 5, 79, 23, 367, 231, 605, 3809, 7557, 14283, 18417, 15775, 107421, 9587}},
-{18396, 18, 83878, {1, 1, 1, 7, 25, 9, 93, 41, 165, 509, 661, 2165, 3595, 2555, 11399, 2403, 76179, 176003}},
-{18397, 18, 83884, {1, 3, 3, 7, 27, 19, 55, 213, 83, 601, 377, 2381, 6831, 5609, 31321, 26897, 105321, 144705}},
-{18398, 18, 83896, {1, 3, 7, 7, 21, 11, 45, 55, 379, 133, 653, 3593, 7481, 15789, 12723, 9697, 20073, 58211}},
-{18399, 18, 83902, {1, 3, 5, 1, 1, 57, 89, 159, 461, 719, 1251, 3899, 1063, 10753, 6509, 28391, 129377, 195279}},
-{18400, 18, 83922, {1, 3, 7, 7, 5, 39, 59, 81, 27, 169, 1541, 2213, 3631, 11601, 13153, 43221, 14587, 29719}},
-{18401, 18, 83977, {1, 1, 1, 1, 3, 29, 103, 125, 35, 455, 255, 3855, 567, 12013, 13285, 44753, 117415, 226285}},
-{18402, 18, 83985, {1, 1, 5, 1, 21, 41, 59, 69, 83, 813, 1041, 2559, 1947, 7343, 5291, 39281, 56141, 54487}},
-{18403, 18, 83988, {1, 1, 7, 15, 25, 17, 83, 115, 321, 659, 1625, 3253, 281, 6673, 26301, 45647, 92151, 150707}},
-{18404, 18, 84034, {1, 1, 5, 15, 9, 19, 83, 167, 325, 869, 501, 483, 2155, 14697, 12755, 54687, 100637, 6791}},
-{18405, 18, 84046, {1, 1, 7, 3, 3, 47, 91, 79, 347, 215, 847, 2957, 5881, 5371, 20099, 45603, 29349, 175357}},
-{18406, 18, 84058, {1, 3, 1, 3, 13, 43, 101, 235, 505, 289, 691, 673, 5579, 8721, 9639, 18569, 44797, 250887}},
-{18407, 18, 84069, {1, 1, 3, 11, 23, 27, 85, 223, 365, 767, 577, 2781, 4179, 12963, 25235, 51021, 84989, 149521}},
-{18408, 18, 84107, {1, 1, 1, 1, 9, 51, 13, 129, 393, 725, 1301, 1391, 4693, 4979, 16801, 21361, 122157, 56675}},
-{18409, 18, 84155, {1, 3, 5, 11, 7, 21, 97, 97, 17, 915, 255, 155, 3961, 7999, 7493, 52683, 49377, 131663}},
-{18410, 18, 84157, {1, 3, 5, 15, 31, 23, 41, 187, 89, 933, 309, 2519, 6595, 13785, 14339, 44393, 64439, 142105}},
-{18411, 18, 84160, {1, 1, 1, 11, 13, 57, 29, 249, 467, 863, 77, 3185, 6221, 13109, 32397, 13859, 27331, 35295}},
-{18412, 18, 84165, {1, 3, 3, 3, 23, 31, 29, 189, 405, 855, 1597, 3167, 4171, 13801, 12297, 38019, 130141, 135517}},
-{18413, 18, 84187, {1, 1, 5, 7, 13, 37, 87, 41, 503, 281, 103, 1997, 3603, 4185, 25331, 55123, 74263, 248695}},
-{18414, 18, 84214, {1, 3, 1, 15, 13, 57, 67, 135, 429, 489, 829, 2069, 7657, 15713, 3907, 5819, 114005, 187859}},
-{18415, 18, 84226, {1, 1, 3, 1, 23, 43, 93, 63, 5, 435, 1649, 1429, 2923, 9035, 28667, 13991, 74491, 236225}},
-{18416, 18, 84235, {1, 3, 3, 7, 19, 29, 37, 143, 443, 955, 1431, 3193, 6023, 2421, 28955, 29171, 126785, 124709}},
-{18417, 18, 84240, {1, 3, 7, 7, 23, 45, 59, 101, 25, 711, 1685, 851, 3101, 12273, 10775, 57633, 52739, 244681}},
-{18418, 18, 84255, {1, 1, 1, 5, 3, 13, 97, 143, 367, 139, 1535, 873, 8005, 2795, 11103, 3837, 125833, 194903}},
-{18419, 18, 84273, {1, 3, 5, 7, 23, 61, 61, 203, 443, 543, 573, 2835, 941, 12315, 18453, 34367, 94359, 132437}},
-{18420, 18, 84291, {1, 1, 7, 5, 11, 21, 87, 27, 495, 67, 1267, 2029, 5041, 4133, 18821, 50249, 52397, 101431}},
-{18421, 18, 84311, {1, 3, 3, 3, 13, 51, 89, 183, 61, 919, 1841, 373, 7091, 9413, 1227, 44515, 72869, 198769}},
-{18422, 18, 84317, {1, 3, 3, 11, 13, 63, 13, 253, 203, 571, 91, 3477, 123, 15353, 7803, 62729, 14337, 252725}},
-{18423, 18, 84328, {1, 1, 7, 1, 11, 57, 45, 251, 351, 895, 1813, 3857, 7545, 9739, 32029, 24915, 46261, 8149}},
-{18424, 18, 84346, {1, 3, 1, 15, 25, 41, 71, 47, 265, 567, 307, 4079, 1943, 10407, 2999, 6605, 97621, 194711}},
-{18425, 18, 84357, {1, 1, 3, 5, 17, 29, 97, 249, 449, 761, 1727, 1533, 7417, 16167, 421, 39075, 1029, 180923}},
-{18426, 18, 84361, {1, 1, 1, 3, 11, 27, 67, 227, 131, 453, 951, 3897, 515, 4513, 17361, 50049, 4533, 35953}},
-{18427, 18, 84372, {1, 1, 1, 13, 7, 53, 25, 163, 453, 195, 1115, 1019, 3799, 7489, 12419, 15141, 112001, 106459}},
-{18428, 18, 84388, {1, 1, 3, 9, 27, 15, 63, 109, 293, 867, 645, 1821, 2867, 9653, 32617, 39617, 125589, 249169}},
-{18429, 18, 84415, {1, 1, 7, 5, 19, 17, 15, 105, 65, 143, 961, 493, 7301, 11299, 4549, 49873, 82447, 107}},
-{18430, 18, 84438, {1, 1, 7, 1, 31, 21, 19, 61, 255, 815, 421, 3097, 4993, 9709, 11529, 53839, 32653, 137861}},
-{18431, 18, 84444, {1, 3, 1, 9, 5, 5, 59, 179, 115, 101, 407, 1143, 309, 843, 31143, 60639, 126659, 111695}},
-{18432, 18, 84447, {1, 3, 7, 13, 7, 47, 65, 127, 159, 817, 1029, 2983, 5443, 11087, 10595, 47143, 128353, 195189}},
-{18433, 18, 84451, {1, 3, 7, 1, 27, 21, 61, 235, 433, 929, 581, 1925, 8185, 6037, 28859, 16843, 43499, 217091}},
-{18434, 18, 84465, {1, 3, 7, 11, 1, 11, 81, 187, 227, 967, 25, 2285, 1251, 10743, 2321, 29029, 89739, 188023}},
-{18435, 18, 84471, {1, 3, 5, 11, 21, 25, 57, 201, 89, 965, 1593, 2879, 2469, 13675, 28789, 11407, 13109, 52749}},
-{18436, 18, 84496, {1, 3, 3, 3, 19, 25, 87, 3, 127, 881, 645, 207, 1129, 4235, 1533, 52503, 128733, 238679}},
-{18437, 18, 84554, {1, 3, 3, 1, 5, 5, 63, 181, 493, 457, 1529, 1795, 219, 10807, 26713, 49673, 47167, 103595}},
-{18438, 18, 84561, {1, 1, 3, 3, 1, 31, 65, 79, 473, 257, 1477, 387, 2843, 4031, 8459, 44849, 115157, 8417}},
-{18439, 18, 84571, {1, 3, 3, 5, 15, 1, 105, 67, 343, 333, 1961, 649, 5105, 11387, 27437, 35471, 26295, 220309}},
-{18440, 18, 84580, {1, 3, 7, 15, 1, 7, 23, 113, 67, 1019, 1793, 3237, 7223, 5691, 6279, 50231, 49393, 84393}},
-{18441, 18, 84598, {1, 1, 1, 7, 9, 29, 125, 249, 89, 813, 561, 871, 1957, 1095, 18563, 5257, 39563, 225651}},
-{18442, 18, 84611, {1, 1, 1, 15, 17, 11, 51, 191, 217, 617, 793, 3633, 4673, 15463, 10621, 47221, 51611, 155937}},
-{18443, 18, 84620, {1, 3, 7, 15, 13, 7, 63, 57, 45, 1005, 685, 2913, 3597, 9933, 14819, 26015, 80023, 60547}},
-{18444, 18, 84625, {1, 1, 5, 5, 31, 43, 69, 63, 425, 439, 143, 933, 675, 11301, 31779, 53445, 25143, 213213}},
-{18445, 18, 84632, {1, 1, 1, 5, 21, 9, 91, 89, 483, 153, 389, 7, 633, 15527, 21833, 45171, 88331, 150935}},
-{18446, 18, 84648, {1, 3, 5, 5, 11, 31, 49, 139, 295, 289, 1623, 3359, 7551, 11285, 25083, 27699, 91869, 237571}},
-{18447, 18, 84659, {1, 1, 1, 9, 9, 25, 55, 71, 51, 603, 1901, 2729, 6803, 11135, 5427, 37285, 69141, 262073}},
-{18448, 18, 84662, {1, 1, 3, 11, 3, 7, 81, 89, 49, 303, 755, 223, 603, 12525, 26037, 47867, 118871, 238677}},
-{18449, 18, 84683, {1, 3, 3, 11, 1, 53, 55, 15, 341, 151, 245, 1979, 3523, 15151, 25075, 21425, 48689, 125391}},
-{18450, 18, 84697, {1, 3, 3, 7, 15, 21, 73, 247, 215, 339, 1995, 633, 2557, 5625, 28443, 16413, 34615, 260591}},
-{18451, 18, 84698, {1, 3, 5, 1, 1, 59, 21, 247, 403, 15, 1129, 2263, 3361, 10675, 30417, 31285, 69913, 124329}},
-{18452, 18, 84709, {1, 1, 5, 1, 17, 3, 103, 107, 333, 191, 345, 3219, 3845, 5953, 26403, 51115, 71623, 52293}},
-{18453, 18, 84722, {1, 1, 7, 5, 29, 13, 59, 65, 185, 91, 717, 3179, 1237, 1187, 25485, 40119, 6069, 23567}},
-{18454, 18, 84753, {1, 1, 1, 5, 17, 57, 27, 39, 269, 627, 1239, 135, 623, 483, 19229, 51939, 114387, 146431}},
-{18455, 18, 84775, {1, 3, 7, 9, 21, 41, 119, 129, 177, 149, 1527, 3639, 4489, 11635, 23007, 59863, 85199, 87795}},
-{18456, 18, 84789, {1, 3, 5, 9, 17, 25, 57, 237, 129, 855, 199, 1929, 2793, 4277, 4509, 46301, 32905, 102015}},
-{18457, 18, 84885, {1, 1, 7, 1, 15, 23, 3, 131, 475, 347, 1301, 241, 153, 2801, 29271, 1337, 107613, 154105}},
-{18458, 18, 84890, {1, 1, 1, 13, 5, 19, 43, 47, 381, 709, 637, 2565, 7503, 10027, 16873, 23511, 101785, 47987}},
-{18459, 18, 84899, {1, 1, 5, 13, 31, 15, 125, 97, 361, 819, 121, 2723, 3395, 6943, 5279, 55977, 103559, 134177}},
-{18460, 18, 84926, {1, 1, 7, 13, 17, 27, 105, 11, 327, 203, 1355, 1437, 959, 10113, 7405, 43511, 114073, 199463}},
-{18461, 18, 84946, {1, 1, 7, 5, 29, 19, 7, 151, 107, 739, 1021, 1287, 6881, 2741, 3407, 13847, 75669, 116015}},
-{18462, 18, 84958, {1, 1, 1, 5, 5, 17, 99, 67, 179, 319, 149, 4069, 7811, 3055, 24669, 21635, 68057, 72059}},
-{18463, 18, 84976, {1, 3, 1, 11, 3, 3, 103, 45, 431, 159, 1693, 1069, 3403, 6121, 12695, 16565, 29787, 199327}},
-{18464, 18, 84979, {1, 1, 5, 5, 5, 35, 97, 9, 7, 703, 1533, 847, 7693, 16041, 13127, 26829, 68801, 205219}},
-{18465, 18, 85003, {1, 1, 5, 9, 25, 59, 3, 63, 305, 71, 1429, 1567, 2377, 12611, 9267, 62381, 32373, 187735}},
-{18466, 18, 85014, {1, 1, 3, 15, 5, 31, 21, 113, 329, 573, 1975, 1615, 947, 987, 4655, 46803, 100251, 89729}},
-{18467, 18, 85017, {1, 1, 5, 9, 15, 63, 83, 5, 71, 191, 1127, 3529, 7325, 1169, 4255, 6715, 42765, 73231}},
-{18468, 18, 85024, {1, 3, 3, 9, 11, 1, 1, 23, 97, 967, 1465, 1305, 2073, 3143, 31333, 1409, 95321, 182333}},
-{18469, 18, 85029, {1, 3, 5, 13, 21, 53, 47, 105, 75, 721, 239, 3619, 2581, 2063, 21227, 25579, 23729, 20067}},
-{18470, 18, 85036, {1, 3, 5, 13, 1, 55, 55, 115, 391, 539, 869, 3347, 189, 11087, 11533, 18747, 25387, 19205}},
-{18471, 18, 85042, {1, 3, 1, 15, 25, 57, 81, 27, 379, 635, 1697, 2805, 8071, 11407, 14843, 17593, 20819, 42891}},
-{18472, 18, 85054, {1, 3, 5, 11, 1, 59, 51, 187, 11, 211, 1425, 3829, 3193, 15743, 16479, 4205, 108205, 205367}},
-{18473, 18, 85056, {1, 1, 1, 5, 7, 7, 59, 85, 63, 509, 897, 2473, 7345, 111, 4431, 55273, 114037, 232541}},
-{18474, 18, 85061, {1, 1, 5, 9, 29, 7, 25, 41, 401, 843, 115, 163, 6835, 13943, 5223, 31033, 10813, 250471}},
-{18475, 18, 85066, {1, 1, 5, 11, 27, 45, 43, 233, 195, 151, 11, 1539, 4775, 15743, 15507, 26939, 30353, 162929}},
-{18476, 18, 85073, {1, 3, 1, 7, 7, 39, 1, 87, 85, 1019, 1711, 2707, 735, 5093, 8231, 25069, 102861, 45751}},
-{18477, 18, 85096, {1, 3, 7, 1, 19, 49, 55, 249, 255, 809, 1799, 3475, 7697, 5003, 12437, 52313, 96355, 138537}},
-{18478, 18, 85101, {1, 1, 3, 5, 5, 43, 25, 95, 349, 775, 213, 3643, 1355, 7745, 9553, 53367, 123655, 195365}},
-{18479, 18, 85109, {1, 1, 1, 1, 19, 53, 39, 105, 449, 447, 147, 2293, 7817, 1503, 31985, 37193, 51039, 209083}},
-{18480, 18, 85114, {1, 3, 3, 15, 27, 15, 59, 51, 411, 543, 421, 3595, 2091, 7171, 23595, 33509, 37283, 105719}},
-{18481, 18, 85119, {1, 3, 1, 11, 5, 37, 5, 203, 171, 853, 1875, 2735, 4003, 15163, 26193, 36149, 31389, 256631}},
-{18482, 18, 85123, {1, 3, 5, 1, 21, 1, 127, 41, 185, 929, 1757, 2711, 2947, 9709, 18401, 45037, 1371, 242397}},
-{18483, 18, 85149, {1, 1, 1, 1, 13, 43, 51, 187, 487, 759, 1579, 959, 2499, 4781, 27179, 6839, 43869, 36163}},
-{18484, 18, 85185, {1, 3, 1, 15, 5, 3, 101, 25, 181, 107, 1105, 879, 5341, 12215, 21615, 9619, 129591, 108393}},
-{18485, 18, 85228, {1, 1, 7, 1, 11, 39, 55, 101, 43, 935, 1703, 1269, 6751, 13723, 7463, 10055, 112971, 72789}},
-{18486, 18, 85236, {1, 3, 5, 13, 7, 3, 81, 41, 55, 375, 663, 801, 5051, 14583, 30793, 63897, 127255, 174179}},
-{18487, 18, 85281, {1, 3, 1, 7, 19, 31, 53, 29, 313, 57, 1411, 103, 6863, 10673, 4341, 5587, 106059, 222309}},
-{18488, 18, 85282, {1, 3, 7, 3, 1, 33, 89, 199, 91, 557, 715, 2715, 4753, 5987, 30355, 13819, 57443, 112179}},
-{18489, 18, 85293, {1, 3, 5, 7, 13, 27, 55, 11, 495, 29, 1273, 1727, 3397, 2739, 22907, 46203, 16687, 47385}},
-{18490, 18, 85302, {1, 3, 5, 9, 13, 23, 23, 107, 353, 429, 359, 2667, 6137, 7213, 7977, 35903, 118507, 209243}},
-{18491, 18, 85319, {1, 3, 1, 13, 9, 7, 37, 135, 377, 753, 1819, 113, 7379, 2795, 10373, 7131, 17845, 246101}},
-{18492, 18, 85353, {1, 1, 3, 11, 11, 45, 53, 209, 49, 385, 1573, 1129, 2939, 10949, 413, 59193, 15399, 169355}},
-{18493, 18, 85354, {1, 1, 5, 15, 29, 29, 89, 139, 403, 11, 1335, 2601, 3631, 15317, 1707, 3517, 1939, 121997}},
-{18494, 18, 85356, {1, 3, 1, 7, 17, 3, 113, 97, 435, 911, 1743, 1649, 4829, 9995, 2873, 17527, 46931, 86199}},
-{18495, 18, 85389, {1, 1, 7, 1, 13, 19, 83, 51, 49, 671, 1651, 3443, 2279, 5677, 8859, 41945, 110607, 200469}},
-{18496, 18, 85418, {1, 1, 5, 13, 19, 63, 19, 73, 205, 571, 507, 1781, 1489, 5909, 10351, 64607, 67023, 49441}},
-{18497, 18, 85446, {1, 1, 3, 5, 13, 35, 107, 63, 489, 69, 1541, 3761, 17, 9317, 20323, 35401, 61451, 116115}},
-{18498, 18, 85450, {1, 3, 1, 5, 31, 35, 39, 119, 237, 533, 107, 3235, 4929, 15839, 9309, 50131, 110945, 24739}},
-{18499, 18, 85463, {1, 3, 1, 5, 3, 25, 73, 145, 391, 481, 1927, 3071, 4347, 13415, 26723, 51629, 3003, 54575}},
-{18500, 18, 85497, {1, 3, 3, 11, 29, 63, 63, 183, 11, 269, 153, 3379, 5603, 14279, 28579, 4653, 98179, 125693}},
-{18501, 18, 85534, {1, 1, 5, 15, 1, 51, 101, 69, 177, 233, 213, 2389, 4963, 3391, 13419, 41283, 25667, 187239}},
-{18502, 18, 85543, {1, 1, 1, 11, 13, 29, 95, 231, 481, 283, 1323, 521, 4689, 5311, 21949, 31851, 115845, 50433}},
-{18503, 18, 85549, {1, 3, 7, 15, 11, 31, 67, 207, 57, 439, 1561, 2167, 673, 6467, 8189, 31783, 5051, 64097}},
-{18504, 18, 85562, {1, 1, 7, 9, 17, 57, 77, 85, 119, 149, 211, 2727, 4921, 8701, 23121, 36355, 9179, 68003}},
-{18505, 18, 85587, {1, 1, 5, 15, 1, 15, 123, 205, 79, 299, 71, 3413, 7635, 5699, 32393, 10253, 86205, 216015}},
-{18506, 18, 85590, {1, 1, 5, 11, 23, 39, 105, 187, 487, 247, 333, 2423, 5643, 8111, 23549, 50153, 122859, 100361}},
-{18507, 18, 85599, {1, 1, 1, 9, 11, 33, 65, 125, 67, 743, 1331, 1563, 6333, 11375, 15873, 18137, 52765, 224889}},
-{18508, 18, 85630, {1, 3, 5, 9, 15, 17, 81, 165, 3, 609, 635, 2093, 6635, 8647, 25883, 18907, 73333, 80835}},
-{18509, 18, 85660, {1, 1, 1, 11, 1, 1, 25, 115, 205, 941, 1917, 1295, 3659, 821, 11355, 1435, 40289, 115627}},
-{18510, 18, 85669, {1, 3, 1, 9, 13, 23, 35, 105, 441, 777, 1255, 3315, 1157, 8719, 9939, 38931, 120723, 123201}},
-{18511, 18, 85693, {1, 1, 5, 3, 1, 21, 95, 143, 23, 233, 73, 1223, 5619, 8583, 21417, 61971, 74565, 116249}},
-{18512, 18, 85711, {1, 1, 7, 7, 23, 35, 21, 201, 441, 623, 419, 2375, 1189, 15681, 29469, 29437, 124525, 241899}},
-{18513, 18, 85716, {1, 1, 3, 1, 11, 7, 23, 171, 435, 467, 1811, 63, 3705, 9395, 579, 58305, 86165, 67805}},
-{18514, 18, 85773, {1, 3, 1, 3, 13, 11, 107, 243, 163, 79, 815, 1149, 2247, 12411, 30287, 56915, 26939, 85883}},
-{18515, 18, 85801, {1, 3, 3, 1, 5, 23, 105, 63, 35, 57, 1815, 3325, 3727, 3623, 7203, 8301, 28073, 190053}},
-{18516, 18, 85815, {1, 3, 1, 11, 23, 33, 121, 55, 287, 139, 491, 907, 4237, 17, 20055, 63729, 7517, 151597}},
-{18517, 18, 85839, {1, 3, 5, 5, 21, 1, 37, 19, 159, 1013, 27, 2627, 851, 14021, 31311, 5871, 77613, 125311}},
-{18518, 18, 85842, {1, 3, 3, 1, 27, 3, 51, 133, 459, 581, 383, 1351, 6149, 15611, 2631, 20797, 65955, 113665}},
-{18519, 18, 85864, {1, 3, 1, 11, 23, 61, 75, 217, 283, 405, 767, 1151, 7501, 5553, 113, 48331, 49379, 191473}},
-{18520, 18, 85867, {1, 3, 5, 5, 15, 3, 19, 27, 497, 519, 1611, 709, 405, 13329, 27861, 14981, 47197, 173979}},
-{18521, 18, 85903, {1, 1, 7, 7, 25, 19, 99, 219, 349, 713, 1421, 3427, 153, 13319, 22415, 48617, 119637, 20835}},
-{18522, 18, 85917, {1, 1, 1, 3, 13, 37, 43, 9, 317, 961, 1255, 2975, 2775, 12283, 29941, 57495, 77413, 256695}},
-{18523, 18, 85921, {1, 1, 7, 5, 29, 37, 91, 199, 397, 739, 877, 251, 847, 2951, 19497, 57285, 76891, 258711}},
-{18524, 18, 85928, {1, 1, 7, 15, 21, 55, 107, 115, 481, 845, 2015, 481, 3823, 14071, 4037, 39687, 62867, 170891}},
-{18525, 18, 85934, {1, 3, 3, 1, 17, 51, 81, 195, 189, 455, 1343, 1493, 351, 361, 20289, 37423, 7747, 245861}},
-{18526, 18, 85974, {1, 1, 5, 15, 9, 41, 71, 155, 197, 563, 1271, 2227, 2557, 6657, 13565, 8467, 96135, 5903}},
-{18527, 18, 85994, {1, 1, 5, 13, 29, 33, 115, 131, 283, 435, 1327, 1113, 4729, 14125, 23743, 40121, 119955, 237453}},
-{18528, 18, 85999, {1, 1, 1, 1, 13, 21, 109, 91, 105, 749, 1695, 1123, 4349, 9855, 31565, 64001, 7919, 83591}},
-{18529, 18, 86004, {1, 3, 1, 1, 13, 19, 89, 83, 13, 609, 731, 2655, 1123, 13415, 5645, 10003, 69381, 187621}},
-{18530, 18, 86008, {1, 3, 1, 15, 3, 37, 1, 139, 11, 917, 1191, 1381, 6035, 13851, 4565, 5427, 117703, 109965}},
-{18531, 18, 86046, {1, 1, 5, 3, 17, 37, 15, 115, 19, 65, 1807, 3879, 2709, 9819, 11457, 53705, 14821, 156079}},
-{18532, 18, 86067, {1, 1, 7, 13, 17, 29, 105, 77, 127, 457, 1287, 1533, 6879, 4001, 4083, 29523, 81175, 226409}},
-{18533, 18, 86084, {1, 3, 1, 5, 5, 59, 21, 253, 459, 733, 409, 3359, 1913, 8893, 16113, 61063, 6511, 22441}},
-{18534, 18, 86087, {1, 3, 5, 11, 7, 1, 121, 217, 63, 83, 173, 1869, 7931, 655, 21053, 20703, 116853, 131785}},
-{18535, 18, 86093, {1, 1, 7, 7, 5, 13, 41, 57, 1, 17, 649, 233, 2867, 5577, 30553, 7635, 45305, 47979}},
-{18536, 18, 86121, {1, 1, 7, 1, 1, 29, 61, 241, 107, 891, 49, 3433, 5045, 143, 22473, 29243, 82625, 184163}},
-{18537, 18, 86122, {1, 3, 1, 11, 11, 21, 119, 43, 117, 429, 1569, 637, 67, 9475, 31779, 2237, 122037, 245361}},
-{18538, 18, 86127, {1, 1, 7, 1, 31, 61, 9, 179, 467, 153, 1913, 2839, 6255, 12715, 28229, 20189, 3617, 213539}},
-{18539, 18, 86151, {1, 1, 7, 13, 25, 61, 9, 109, 331, 577, 21, 1017, 6521, 5991, 26573, 56881, 58455, 169407}},
-{18540, 18, 86166, {1, 1, 7, 9, 31, 57, 51, 41, 327, 859, 1295, 1577, 1071, 3277, 11685, 62129, 34111, 174639}},
-{18541, 18, 86179, {1, 3, 5, 1, 7, 63, 35, 165, 43, 943, 1545, 3717, 1471, 11579, 29637, 22913, 8867, 12837}},
-{18542, 18, 86188, {1, 1, 3, 1, 23, 7, 19, 151, 359, 347, 1085, 3923, 1039, 5149, 6047, 49811, 33099, 247983}},
-{18543, 18, 86193, {1, 1, 1, 5, 29, 23, 73, 189, 59, 865, 1499, 1953, 1261, 1071, 26761, 26145, 129427, 223219}},
-{18544, 18, 86206, {1, 3, 1, 9, 1, 29, 107, 173, 387, 703, 193, 1965, 6233, 10997, 32697, 31005, 15415, 94345}},
-{18545, 18, 86214, {1, 1, 3, 9, 31, 35, 7, 15, 317, 79, 2045, 1455, 1559, 15087, 287, 46665, 37225, 149017}},
-{18546, 18, 86226, {1, 1, 5, 13, 17, 27, 11, 107, 47, 803, 1487, 3049, 1171, 6237, 9157, 10037, 122349, 236877}},
-{18547, 18, 86242, {1, 1, 7, 9, 21, 35, 53, 139, 165, 73, 1405, 2941, 3553, 11945, 2493, 5743, 63749, 140535}},
-{18548, 18, 86256, {1, 3, 7, 11, 7, 57, 41, 187, 483, 499, 687, 117, 4951, 14709, 17025, 23027, 94863, 228465}},
-{18549, 18, 86259, {1, 3, 7, 7, 27, 29, 85, 117, 201, 637, 823, 1135, 7595, 3323, 23579, 40759, 25087, 995}},
-{18550, 18, 86298, {1, 3, 1, 9, 31, 53, 101, 29, 381, 101, 1939, 1973, 8191, 8155, 13881, 32309, 92907, 239525}},
-{18551, 18, 86300, {1, 1, 5, 7, 3, 35, 15, 207, 1, 47, 325, 559, 3377, 3909, 31225, 28367, 63891, 19129}},
-{18552, 18, 86307, {1, 1, 1, 5, 31, 61, 117, 211, 127, 969, 73, 1295, 7167, 14881, 9965, 28143, 28161, 131867}},
-{18553, 18, 86310, {1, 3, 7, 5, 5, 57, 37, 207, 201, 79, 1151, 3685, 2071, 1751, 5481, 51447, 103437, 154895}},
-{18554, 18, 86319, {1, 3, 5, 13, 9, 5, 57, 27, 131, 211, 1481, 2237, 4227, 6927, 18625, 49773, 55399, 15209}},
-{18555, 18, 86321, {1, 3, 1, 7, 23, 29, 3, 179, 479, 787, 463, 2041, 2581, 6281, 1657, 51433, 93807, 160047}},
-{18556, 18, 86328, {1, 1, 3, 13, 25, 35, 33, 231, 385, 479, 335, 3837, 5517, 13603, 15623, 46737, 42507, 208355}},
-{18557, 18, 86356, {1, 1, 7, 9, 3, 25, 51, 125, 213, 175, 1575, 1755, 1843, 14361, 13155, 22445, 55435, 62793}},
-{18558, 18, 86360, {1, 1, 1, 7, 25, 3, 21, 7, 309, 547, 19, 471, 2679, 16185, 12149, 41437, 47625, 75113}},
-{18559, 18, 86375, {1, 1, 5, 1, 9, 23, 81, 95, 123, 143, 1111, 9, 3501, 11897, 26499, 10009, 48073, 182529}},
-{18560, 18, 86399, {1, 3, 1, 1, 1, 17, 15, 157, 129, 1005, 543, 3917, 3493, 6537, 26997, 33217, 7987, 251635}},
-{18561, 18, 86400, {1, 3, 1, 13, 11, 41, 9, 19, 173, 751, 491, 1645, 5205, 9907, 28503, 61137, 79727, 200851}},
-{18562, 18, 86403, {1, 1, 1, 1, 3, 5, 105, 203, 97, 903, 1507, 2719, 5275, 1023, 29595, 42507, 39893, 151495}},
-{18563, 18, 86430, {1, 1, 1, 11, 31, 53, 51, 65, 145, 671, 489, 109, 803, 8541, 4439, 33893, 98495, 114955}},
-{18564, 18, 86446, {1, 1, 7, 11, 27, 63, 117, 235, 497, 841, 1461, 3757, 1077, 6997, 9611, 47453, 20197, 176939}},
-{18565, 18, 86460, {1, 3, 3, 3, 31, 17, 85, 145, 377, 225, 1033, 3017, 735, 5811, 25503, 25457, 124623, 51713}},
-{18566, 18, 86465, {1, 3, 3, 13, 19, 33, 127, 57, 321, 687, 1651, 3321, 5051, 8511, 19609, 49927, 30499, 102613}},
-{18567, 18, 86486, {1, 1, 5, 13, 7, 17, 17, 147, 381, 137, 1007, 2607, 1071, 8921, 13955, 47223, 130359, 246265}},
-{18568, 18, 86502, {1, 3, 7, 9, 13, 35, 71, 129, 57, 233, 357, 3181, 2841, 3707, 24947, 57777, 115133, 6049}},
-{18569, 18, 86563, {1, 3, 7, 15, 23, 1, 107, 225, 57, 633, 1515, 1631, 4303, 4221, 8281, 59139, 45023, 70219}},
-{18570, 18, 86595, {1, 1, 7, 5, 9, 9, 93, 131, 41, 245, 1261, 459, 4811, 10987, 10421, 63839, 34067, 196353}},
-{18571, 18, 86635, {1, 3, 3, 13, 17, 3, 87, 255, 167, 701, 821, 1965, 1415, 4101, 549, 6347, 92421, 47193}},
-{18572, 18, 86649, {1, 3, 7, 11, 23, 17, 51, 81, 71, 345, 971, 917, 1057, 3627, 20361, 13491, 12855, 234215}},
-{18573, 18, 86661, {1, 1, 1, 13, 17, 9, 25, 155, 463, 851, 243, 3887, 2445, 7459, 19915, 21813, 86969, 85891}},
-{18574, 18, 86674, {1, 1, 7, 1, 9, 15, 57, 201, 193, 169, 351, 1355, 1089, 4705, 15153, 51359, 49907, 66007}},
-{18575, 18, 86689, {1, 3, 1, 9, 19, 13, 69, 83, 39, 667, 1549, 1503, 7167, 8657, 17269, 59357, 80091, 194007}},
-{18576, 18, 86721, {1, 3, 5, 5, 17, 37, 125, 117, 355, 685, 637, 3159, 4783, 3159, 14953, 12731, 126759, 89149}},
-{18577, 18, 86734, {1, 3, 3, 9, 15, 53, 7, 41, 473, 857, 511, 3741, 6837, 6167, 26351, 9885, 104819, 48221}},
-{18578, 18, 86741, {1, 3, 7, 15, 21, 21, 21, 101, 465, 223, 13, 1773, 2763, 8621, 23591, 12633, 82143, 134899}},
-{18579, 18, 86742, {1, 3, 1, 1, 29, 25, 67, 19, 349, 503, 655, 3567, 97, 6967, 18253, 42755, 33041, 250279}},
-{18580, 18, 86784, {1, 1, 7, 9, 17, 1, 7, 165, 255, 613, 579, 127, 7567, 13181, 6255, 1785, 21527, 113815}},
-{18581, 18, 86799, {1, 3, 1, 5, 27, 33, 61, 235, 37, 135, 1515, 3611, 1825, 9627, 18805, 37065, 126107, 23223}},
-{18582, 18, 86808, {1, 3, 7, 5, 23, 11, 29, 121, 129, 311, 429, 1653, 5789, 7693, 18775, 18189, 97203, 213501}},
-{18583, 18, 86837, {1, 3, 7, 3, 29, 61, 87, 197, 43, 509, 5, 3275, 345, 7885, 4381, 22059, 1395, 40125}},
-{18584, 18, 86869, {1, 3, 5, 1, 1, 59, 69, 125, 297, 983, 641, 2665, 7045, 8591, 16581, 58657, 119189, 256579}},
-{18585, 18, 86900, {1, 3, 7, 7, 7, 53, 65, 181, 149, 987, 1377, 4045, 971, 9827, 17727, 59357, 90975, 27395}},
-{18586, 18, 86949, {1, 1, 7, 7, 1, 51, 109, 165, 361, 515, 739, 3709, 6431, 113, 21401, 41743, 53071, 134205}},
-{18587, 18, 86993, {1, 3, 1, 13, 5, 51, 107, 99, 135, 163, 1705, 1683, 6221, 1377, 2211, 13379, 22801, 208753}},
-{18588, 18, 86999, {1, 3, 5, 11, 11, 39, 49, 45, 503, 549, 821, 4077, 885, 13721, 29673, 28435, 6235, 212071}},
-{18589, 18, 87030, {1, 3, 3, 11, 15, 25, 17, 67, 125, 7, 1163, 973, 5325, 12707, 12763, 9481, 21363, 195897}},
-{18590, 18, 87041, {1, 1, 7, 9, 17, 19, 15, 13, 107, 919, 461, 343, 1101, 8195, 29293, 61643, 64995, 230469}},
-{18591, 18, 87044, {1, 3, 5, 1, 9, 25, 39, 65, 27, 461, 669, 2841, 7973, 11565, 9531, 52235, 6741, 215513}},
-{18592, 18, 87084, {1, 3, 3, 1, 7, 57, 101, 199, 37, 79, 2033, 1723, 6877, 2733, 26445, 62625, 21671, 238431}},
-{18593, 18, 87116, {1, 1, 1, 9, 27, 31, 125, 199, 331, 611, 523, 407, 747, 9499, 4685, 17805, 43717, 253233}},
-{18594, 18, 87138, {1, 1, 3, 7, 29, 7, 7, 153, 339, 337, 701, 2639, 6311, 6375, 26023, 27693, 59733, 260405}},
-{18595, 18, 87162, {1, 1, 7, 7, 15, 27, 23, 49, 181, 433, 485, 2915, 6021, 9095, 15951, 47257, 104513, 208089}},
-{18596, 18, 87188, {1, 1, 5, 7, 19, 19, 125, 153, 109, 829, 1967, 2567, 7157, 6001, 10151, 55323, 92405, 82549}},
-{18597, 18, 87211, {1, 1, 3, 11, 13, 17, 85, 215, 265, 875, 311, 3773, 8059, 2115, 19259, 63999, 77411, 220267}},
-{18598, 18, 87234, {1, 3, 1, 15, 15, 35, 81, 213, 411, 435, 105, 1487, 1991, 14539, 8175, 2115, 47259, 45893}},
-{18599, 18, 87245, {1, 3, 1, 11, 9, 47, 27, 115, 449, 521, 321, 2463, 1355, 5785, 11269, 45337, 29049, 91675}},
-{18600, 18, 87246, {1, 3, 1, 13, 21, 53, 49, 83, 373, 519, 757, 1241, 577, 14443, 449, 44773, 116673, 155209}},
-{18601, 18, 87260, {1, 3, 3, 1, 29, 63, 97, 145, 371, 585, 1809, 3997, 249, 283, 28369, 27325, 61673, 12637}},
-{18602, 18, 87270, {1, 3, 5, 9, 11, 55, 77, 89, 285, 297, 861, 2791, 3245, 15093, 32489, 40477, 97603, 35347}},
-{18603, 18, 87284, {1, 1, 1, 3, 27, 33, 115, 209, 169, 893, 393, 1457, 6069, 12511, 20423, 11385, 86711, 197555}},
-{18604, 18, 87293, {1, 3, 5, 15, 21, 25, 87, 159, 477, 177, 991, 495, 29, 9347, 9721, 4071, 30145, 214155}},
-{18605, 18, 87296, {1, 1, 5, 3, 11, 45, 53, 251, 177, 651, 549, 3377, 3247, 8761, 20339, 27743, 103387, 159591}},
-{18606, 18, 87299, {1, 3, 7, 11, 17, 27, 43, 179, 507, 553, 261, 3939, 6133, 6347, 12987, 46071, 42551, 99225}},
-{18607, 18, 87305, {1, 3, 3, 11, 3, 33, 85, 51, 277, 117, 1295, 2435, 1467, 13787, 2209, 52673, 53515, 157625}},
-{18608, 18, 87308, {1, 3, 3, 3, 9, 15, 121, 229, 227, 795, 541, 3727, 4333, 2251, 27833, 43567, 82505, 230427}},
-{18609, 18, 87313, {1, 1, 5, 13, 29, 19, 119, 63, 207, 945, 761, 2601, 1391, 8939, 11683, 52433, 63301, 82501}},
-{18610, 18, 87323, {1, 3, 7, 1, 3, 57, 127, 115, 209, 31, 1631, 347, 3937, 4015, 13313, 49507, 15103, 237071}},
-{18611, 18, 87332, {1, 3, 1, 13, 3, 25, 85, 151, 115, 385, 303, 2453, 2417, 8051, 1447, 59517, 3711, 160345}},
-{18612, 18, 87361, {1, 3, 1, 13, 1, 23, 49, 75, 117, 295, 1737, 2091, 6229, 3157, 32737, 13751, 101667, 96261}},
-{18613, 18, 87376, {1, 3, 3, 5, 27, 19, 103, 201, 65, 757, 1847, 239, 2185, 15139, 8883, 17737, 9207, 147663}},
-{18614, 18, 87392, {1, 3, 1, 9, 3, 39, 51, 1, 419, 929, 1049, 2891, 2585, 2759, 27587, 55711, 15461, 46851}},
-{18615, 18, 87419, {1, 1, 5, 3, 23, 23, 23, 101, 249, 997, 1889, 2293, 5693, 939, 29619, 2775, 49293, 168895}},
-{18616, 18, 87432, {1, 3, 1, 15, 9, 63, 17, 97, 385, 517, 1737, 713, 157, 2597, 20889, 35209, 47525, 14389}},
-{18617, 18, 87435, {1, 3, 1, 1, 7, 27, 9, 147, 349, 493, 341, 2699, 7743, 4283, 24691, 11881, 78619, 153899}},
-{18618, 18, 87445, {1, 3, 1, 9, 15, 25, 103, 177, 485, 355, 1319, 767, 6675, 3425, 7187, 53767, 92023, 151523}},
-{18619, 18, 87466, {1, 1, 3, 3, 15, 35, 25, 177, 295, 5, 661, 3651, 2597, 16229, 1343, 54941, 72047, 169155}},
-{18620, 18, 87491, {1, 1, 1, 1, 19, 29, 63, 229, 79, 551, 1401, 2851, 6935, 12485, 9243, 21671, 54209, 105347}},
-{18621, 18, 87503, {1, 1, 3, 1, 13, 33, 53, 125, 261, 623, 65, 3863, 1899, 2453, 16483, 48655, 50771, 248555}},
-{18622, 18, 87558, {1, 3, 5, 7, 25, 15, 107, 149, 485, 247, 1977, 3125, 4663, 4925, 15749, 39429, 52315, 30545}},
-{18623, 18, 87570, {1, 1, 7, 13, 23, 13, 127, 111, 9, 17, 1887, 1341, 3017, 14333, 6003, 35113, 14935, 17593}},
-{18624, 18, 87581, {1, 1, 1, 15, 23, 17, 111, 43, 71, 549, 1369, 1711, 3903, 13605, 14573, 18973, 28157, 128421}},
-{18625, 18, 87603, {1, 1, 7, 15, 27, 23, 5, 99, 87, 865, 1979, 3287, 3977, 14989, 17439, 14593, 92711, 211259}},
-{18626, 18, 87615, {1, 3, 3, 15, 5, 19, 3, 231, 127, 863, 1537, 369, 7915, 10281, 13925, 12931, 3905, 178609}},
-{18627, 18, 87623, {1, 1, 3, 15, 13, 5, 17, 217, 383, 251, 1701, 3379, 8157, 4991, 8563, 24611, 66081, 205775}},
-{18628, 18, 87635, {1, 3, 7, 11, 9, 25, 73, 131, 217, 601, 843, 807, 4509, 16209, 29581, 50869, 56595, 14283}},
-{18629, 18, 87647, {1, 3, 5, 9, 5, 59, 57, 153, 359, 775, 859, 1897, 6415, 7389, 10851, 64247, 21627, 145017}},
-{18630, 18, 87651, {1, 3, 7, 1, 27, 11, 117, 179, 175, 343, 687, 2775, 3655, 11655, 2641, 355, 83447, 237799}},
-{18631, 18, 87657, {1, 1, 7, 11, 17, 59, 91, 21, 403, 797, 1839, 525, 3279, 6575, 30083, 12503, 83057, 109465}},
-{18632, 18, 87665, {1, 3, 7, 1, 25, 27, 41, 223, 169, 679, 699, 3287, 6305, 6459, 23145, 45519, 127487, 183563}},
-{18633, 18, 87694, {1, 3, 3, 1, 9, 45, 105, 57, 185, 97, 899, 3113, 7081, 7057, 14559, 53537, 105623, 155399}},
-{18634, 18, 87701, {1, 3, 7, 5, 17, 35, 89, 13, 87, 587, 451, 4079, 1005, 4311, 15861, 49977, 59653, 12107}},
-{18635, 18, 87705, {1, 3, 7, 3, 19, 55, 43, 77, 317, 369, 71, 937, 1905, 5005, 17715, 4005, 55445, 25159}},
-{18636, 18, 87722, {1, 1, 7, 15, 15, 51, 87, 37, 59, 755, 763, 455, 711, 13399, 30999, 61269, 66037, 202793}},
-{18637, 18, 87739, {1, 1, 3, 5, 11, 57, 111, 135, 325, 553, 273, 1533, 3431, 6427, 24771, 42143, 56711, 220873}},
-{18638, 18, 87750, {1, 1, 1, 13, 3, 49, 53, 81, 491, 177, 1543, 1847, 7907, 7817, 15417, 9897, 101597, 160195}},
-{18639, 18, 87790, {1, 3, 1, 15, 19, 15, 91, 123, 365, 113, 129, 3371, 5789, 13553, 6887, 62317, 84269, 44777}},
-{18640, 18, 87795, {1, 3, 7, 13, 15, 63, 43, 175, 449, 437, 597, 1371, 5101, 13797, 28025, 15809, 7645, 21169}},
-{18641, 18, 87797, {1, 1, 7, 13, 23, 63, 105, 69, 219, 153, 1539, 1537, 6899, 9363, 27459, 34551, 62563, 236679}},
-{18642, 18, 87816, {1, 3, 7, 3, 9, 33, 3, 101, 135, 571, 127, 3881, 7017, 13403, 13817, 55167, 8645, 471}},
-{18643, 18, 87884, {1, 3, 3, 13, 7, 53, 29, 89, 473, 135, 639, 3137, 93, 965, 4867, 58265, 114963, 175295}},
-{18644, 18, 87917, {1, 3, 1, 1, 9, 11, 45, 123, 129, 441, 1601, 39, 4657, 3701, 29581, 16045, 57173, 75195}},
-{18645, 18, 87930, {1, 1, 3, 11, 7, 21, 9, 73, 25, 891, 1625, 3019, 223, 14351, 30621, 3075, 79051, 178127}},
-{18646, 18, 87942, {1, 1, 7, 3, 7, 43, 69, 209, 9, 857, 1539, 2629, 5277, 14583, 16443, 28275, 54143, 206479}},
-{18647, 18, 87953, {1, 3, 5, 9, 27, 15, 109, 237, 323, 103, 837, 597, 3609, 6249, 795, 37191, 20997, 142079}},
-{18648, 18, 87954, {1, 1, 3, 1, 27, 33, 123, 191, 55, 531, 1707, 2633, 6717, 9645, 21377, 51593, 9017, 178185}},
-{18649, 18, 87984, {1, 1, 5, 15, 3, 3, 67, 225, 229, 161, 2039, 1499, 873, 8803, 29901, 58809, 35625, 207797}},
-{18650, 18, 87989, {1, 3, 3, 7, 3, 47, 99, 237, 221, 31, 1043, 1081, 837, 1617, 17323, 43879, 55615, 238537}},
-{18651, 18, 88008, {1, 3, 7, 1, 17, 37, 45, 211, 245, 657, 221, 1067, 1683, 16127, 585, 9067, 25935, 162469}},
-{18652, 18, 88016, {1, 1, 5, 9, 23, 27, 5, 237, 137, 227, 129, 279, 4171, 5963, 349, 12387, 40701, 177255}},
-{18653, 18, 88038, {1, 3, 7, 15, 17, 11, 95, 69, 49, 901, 509, 2541, 3001, 15501, 24235, 39863, 95381, 260793}},
-{18654, 18, 88042, {1, 3, 3, 3, 29, 3, 125, 3, 423, 609, 1401, 2337, 1093, 11419, 29735, 9033, 115977, 210201}},
-{18655, 18, 88044, {1, 1, 1, 9, 11, 21, 71, 33, 399, 1005, 1691, 1501, 2585, 7361, 21527, 7535, 87091, 192319}},
-{18656, 18, 88049, {1, 1, 1, 11, 5, 49, 65, 115, 239, 255, 381, 2803, 3447, 5775, 18243, 16545, 108901, 81355}},
-{18657, 18, 88083, {1, 3, 7, 15, 31, 5, 81, 213, 281, 903, 189, 1807, 3551, 4423, 3591, 27449, 71659, 255357}},
-{18658, 18, 88119, {1, 1, 1, 15, 11, 1, 25, 213, 259, 215, 435, 3531, 4889, 9509, 21391, 21589, 89871, 85895}},
-{18659, 18, 88134, {1, 3, 3, 9, 29, 29, 37, 127, 419, 631, 1793, 1547, 1463, 13265, 17233, 24627, 3687, 174179}},
-{18660, 18, 88138, {1, 1, 1, 7, 27, 61, 105, 135, 439, 161, 721, 2779, 6731, 14575, 4565, 25869, 38981, 191683}},
-{18661, 18, 88143, {1, 1, 7, 13, 21, 41, 43, 5, 313, 407, 505, 231, 5023, 8971, 15825, 38461, 38797, 136027}},
-{18662, 18, 88191, {1, 3, 7, 3, 7, 59, 11, 255, 327, 843, 1179, 889, 4505, 10891, 7901, 14485, 72297, 255985}},
-{18663, 18, 88216, {1, 1, 5, 3, 9, 37, 89, 59, 413, 51, 515, 4009, 6501, 8443, 14381, 60917, 43567, 234431}},
-{18664, 18, 88231, {1, 1, 3, 9, 9, 57, 65, 205, 367, 935, 1975, 2561, 225, 12529, 4721, 56659, 87901, 219641}},
-{18665, 18, 88232, {1, 3, 7, 15, 23, 55, 61, 15, 89, 267, 1245, 2703, 7471, 10499, 19, 19357, 72413, 199289}},
-{18666, 18, 88297, {1, 1, 1, 13, 1, 29, 65, 11, 353, 509, 1831, 2181, 5265, 14761, 913, 17109, 113613, 37143}},
-{18667, 18, 88300, {1, 1, 7, 5, 17, 37, 97, 249, 169, 223, 475, 2091, 3101, 8541, 325, 42359, 16121, 151739}},
-{18668, 18, 88308, {1, 1, 3, 13, 1, 45, 13, 209, 395, 215, 15, 2287, 5365, 9887, 29799, 51957, 97483, 109467}},
-{18669, 18, 88317, {1, 3, 7, 1, 9, 35, 91, 51, 387, 833, 783, 2483, 3743, 6155, 5881, 3047, 86191, 151867}},
-{18670, 18, 88344, {1, 1, 1, 7, 15, 25, 13, 3, 119, 333, 761, 3459, 2555, 15737, 12945, 15225, 45487, 78235}},
-{18671, 18, 88350, {1, 3, 1, 3, 13, 55, 111, 45, 121, 593, 633, 2705, 1653, 13275, 13533, 3559, 100573, 124363}},
-{18672, 18, 88371, {1, 1, 3, 1, 29, 49, 65, 69, 133, 667, 653, 2559, 6335, 8019, 9251, 5415, 90125, 197413}},
-{18673, 18, 88469, {1, 1, 1, 7, 23, 53, 99, 149, 39, 453, 129, 185, 1143, 12799, 23339, 41293, 94023, 105581}},
-{18674, 18, 88483, {1, 3, 3, 13, 5, 3, 5, 215, 425, 455, 421, 3815, 5983, 3851, 19569, 17363, 6411, 60037}},
-{18675, 18, 88485, {1, 3, 7, 1, 29, 7, 63, 207, 299, 17, 1915, 2041, 8129, 661, 32481, 55475, 72027, 239683}},
-{18676, 18, 88518, {1, 1, 5, 13, 29, 11, 39, 177, 177, 479, 1291, 3931, 4353, 327, 7827, 9529, 6967, 6469}},
-{18677, 18, 88586, {1, 1, 5, 3, 25, 39, 121, 15, 7, 715, 583, 3997, 1373, 7747, 1777, 7269, 105333, 201511}},
-{18678, 18, 88605, {1, 3, 3, 9, 11, 7, 81, 109, 129, 359, 1281, 1163, 4895, 10303, 17801, 43461, 120271, 173027}},
-{18679, 18, 88621, {1, 3, 5, 1, 23, 59, 123, 75, 505, 925, 637, 1713, 995, 14031, 13711, 62569, 90553, 242345}},
-{18680, 18, 88651, {1, 3, 3, 15, 19, 11, 39, 203, 229, 619, 735, 1367, 4963, 5263, 30229, 17847, 9623, 3277}},
-{18681, 18, 88656, {1, 1, 7, 13, 5, 27, 23, 223, 377, 335, 1821, 2481, 4111, 10373, 18423, 7237, 75225, 223433}},
-{18682, 18, 88665, {1, 3, 7, 1, 21, 19, 71, 107, 19, 703, 945, 3831, 1099, 6267, 17489, 27665, 8861, 127499}},
-{18683, 18, 88668, {1, 3, 5, 1, 19, 49, 117, 181, 245, 939, 1279, 3127, 4427, 3061, 23399, 64805, 43077, 100789}},
-{18684, 18, 88712, {1, 1, 3, 3, 31, 55, 53, 205, 97, 645, 215, 2617, 7419, 7159, 27373, 62341, 58121, 248677}},
-{18685, 18, 88717, {1, 1, 7, 5, 15, 41, 99, 75, 201, 187, 197, 3773, 3097, 6803, 5307, 31375, 26743, 142723}},
-{18686, 18, 88751, {1, 3, 5, 11, 23, 61, 127, 15, 89, 245, 1345, 1305, 5937, 15917, 23867, 50319, 91921, 248663}},
-{18687, 18, 88754, {1, 1, 3, 9, 27, 7, 1, 75, 181, 155, 1947, 577, 2975, 8855, 5295, 43403, 112497, 100679}},
-{18688, 18, 88756, {1, 1, 1, 11, 29, 61, 35, 241, 207, 73, 1747, 1797, 3665, 14275, 25359, 28685, 79367, 81819}},
-{18689, 18, 88785, {1, 3, 5, 9, 11, 1, 37, 79, 431, 157, 1979, 159, 3087, 1731, 26141, 31411, 56457, 94293}},
-{18690, 18, 88801, {1, 3, 7, 1, 17, 35, 107, 243, 279, 79, 227, 1275, 761, 11485, 22181, 16415, 68801, 4577}},
-{18691, 18, 88807, {1, 3, 1, 9, 21, 43, 115, 131, 129, 123, 1677, 1875, 7355, 15927, 845, 24101, 48985, 39703}},
-{18692, 18, 88826, {1, 1, 7, 3, 17, 25, 105, 189, 317, 109, 1629, 3103, 615, 1047, 621, 62743, 43631, 9811}},
-{18693, 18, 88848, {1, 3, 1, 3, 3, 45, 49, 73, 383, 761, 685, 3211, 3855, 16307, 30469, 1393, 52535, 165503}},
-{18694, 18, 88854, {1, 3, 5, 15, 1, 41, 89, 105, 213, 33, 1477, 711, 4823, 503, 12533, 56781, 42825, 223399}},
-{18695, 18, 88864, {1, 3, 5, 9, 17, 45, 63, 113, 359, 927, 1467, 2811, 4275, 5193, 6023, 32689, 87747, 234697}},
-{18696, 18, 88879, {1, 1, 3, 1, 21, 49, 73, 157, 97, 915, 1689, 3289, 7515, 10759, 32253, 63175, 66175, 125813}},
-{18697, 18, 88939, {1, 1, 1, 5, 19, 1, 127, 229, 453, 617, 511, 1515, 3815, 3125, 26851, 31635, 35389, 237483}},
-{18698, 18, 88947, {1, 1, 1, 13, 27, 61, 75, 23, 289, 133, 975, 3217, 3777, 12095, 15235, 33845, 125503, 88417}},
-{18699, 18, 88987, {1, 1, 3, 13, 27, 49, 29, 115, 221, 995, 1305, 2717, 2243, 13391, 20841, 863, 63195, 46829}},
-{18700, 18, 88990, {1, 3, 1, 11, 31, 49, 43, 163, 503, 123, 657, 1285, 3695, 8401, 17087, 48289, 3947, 41495}},
-{18701, 18, 88996, {1, 3, 7, 9, 21, 17, 125, 75, 395, 979, 781, 2501, 6511, 4619, 28943, 18295, 87547, 196289}},
-{18702, 18, 89008, {1, 3, 3, 5, 3, 39, 107, 199, 7, 331, 77, 511, 5787, 3155, 29605, 44633, 51041, 89141}},
-{18703, 18, 89011, {1, 1, 3, 7, 11, 37, 79, 69, 181, 623, 299, 2321, 4371, 7449, 3137, 25753, 116673, 30441}},
-{18704, 18, 89043, {1, 1, 5, 9, 11, 13, 49, 207, 179, 671, 1469, 1005, 6887, 12203, 9365, 62455, 36283, 42053}},
-{18705, 18, 89045, {1, 3, 1, 1, 7, 31, 115, 79, 435, 101, 1525, 3695, 3229, 11401, 23959, 62055, 37725, 219753}},
-{18706, 18, 89050, {1, 3, 3, 7, 25, 49, 123, 161, 275, 291, 255, 2247, 4271, 10771, 2449, 26343, 61169, 30691}},
-{18707, 18, 89097, {1, 1, 7, 1, 15, 3, 11, 15, 125, 1021, 1817, 417, 2721, 13985, 19039, 451, 32559, 199407}},
-{18708, 18, 89100, {1, 1, 5, 15, 11, 25, 23, 101, 427, 431, 1353, 1957, 3529, 513, 11937, 14469, 89539, 242015}},
-{18709, 18, 89106, {1, 1, 5, 13, 27, 5, 107, 29, 469, 3, 1427, 1949, 7007, 16339, 3375, 63545, 100739, 229487}},
-{18710, 18, 89134, {1, 3, 5, 13, 15, 17, 59, 213, 417, 557, 11, 811, 5041, 4133, 25735, 46807, 65669, 148081}},
-{18711, 18, 89178, {1, 1, 5, 13, 9, 47, 35, 173, 277, 805, 1249, 3707, 1079, 2833, 29383, 58995, 21005, 181567}},
-{18712, 18, 89189, {1, 3, 5, 1, 5, 25, 125, 45, 157, 291, 1329, 3317, 2311, 9919, 31001, 65127, 19451, 117621}},
-{18713, 18, 89202, {1, 1, 5, 9, 31, 21, 9, 193, 23, 879, 699, 1135, 7151, 8635, 20711, 45207, 67047, 4397}},
-{18714, 18, 89211, {1, 3, 1, 11, 11, 49, 119, 129, 409, 491, 463, 833, 3661, 607, 25961, 6061, 12747, 160337}},
-{18715, 18, 89224, {1, 3, 1, 15, 31, 35, 93, 95, 239, 695, 1113, 2371, 2625, 10371, 10781, 46209, 67051, 109923}},
-{18716, 18, 89241, {1, 3, 5, 9, 5, 61, 25, 19, 99, 159, 55, 43, 3679, 1023, 17951, 44841, 101653, 195955}},
-{18717, 18, 89251, {1, 1, 3, 11, 19, 45, 99, 47, 407, 115, 353, 3537, 7147, 5837, 27309, 44539, 30227, 93183}},
-{18718, 18, 89254, {1, 1, 7, 15, 13, 59, 83, 215, 79, 865, 269, 2999, 2415, 10631, 23655, 51583, 46105, 43965}},
-{18719, 18, 89258, {1, 3, 7, 5, 17, 1, 7, 119, 501, 25, 1097, 3639, 7017, 381, 4793, 37263, 60431, 77323}},
-{18720, 18, 89295, {1, 3, 7, 13, 1, 37, 99, 103, 459, 853, 5, 3093, 6167, 14497, 7003, 36979, 71919, 64823}},
-{18721, 18, 89328, {1, 3, 7, 5, 23, 7, 37, 255, 297, 115, 113, 579, 4561, 5245, 11173, 28645, 23989, 240777}},
-{18722, 18, 89357, {1, 3, 5, 9, 29, 47, 43, 145, 481, 251, 737, 2531, 2425, 529, 3953, 13229, 35933, 187855}},
-{18723, 18, 89403, {1, 3, 1, 15, 15, 15, 29, 73, 405, 91, 1399, 3599, 1517, 11075, 11265, 22817, 26619, 1183}},
-{18724, 18, 89420, {1, 1, 5, 15, 21, 47, 93, 33, 47, 527, 877, 3453, 3867, 4007, 32503, 11789, 68333, 187419}},
-{18725, 18, 89426, {1, 1, 3, 13, 5, 3, 99, 21, 17, 779, 541, 3919, 1339, 13507, 28965, 61145, 50421, 192319}},
-{18726, 18, 89465, {1, 1, 3, 7, 31, 63, 17, 9, 331, 681, 515, 1067, 351, 2471, 31271, 36015, 72911, 32383}},
-{18727, 18, 89471, {1, 1, 3, 7, 1, 55, 97, 211, 409, 499, 1207, 2405, 2291, 1373, 1263, 65303, 38655, 159965}},
-{18728, 18, 89475, {1, 1, 1, 5, 23, 11, 21, 23, 35, 19, 1699, 2325, 6117, 14971, 32327, 31369, 28061, 112819}},
-{18729, 18, 89547, {1, 3, 3, 13, 29, 63, 19, 201, 173, 395, 1437, 369, 7045, 14347, 5393, 11311, 28415, 161019}},
-{18730, 18, 89549, {1, 3, 1, 5, 31, 15, 101, 13, 97, 865, 1063, 2129, 811, 3337, 7585, 54803, 122099, 149531}},
-{18731, 18, 89558, {1, 3, 3, 13, 19, 5, 47, 13, 497, 683, 1197, 3509, 4375, 3353, 31847, 283, 95281, 7975}},
-{18732, 18, 89564, {1, 1, 7, 5, 25, 19, 59, 105, 167, 775, 581, 2679, 3003, 9345, 20209, 31487, 25357, 226341}},
-{18733, 18, 89611, {1, 1, 5, 5, 31, 61, 13, 77, 189, 141, 1157, 609, 7245, 15303, 32743, 50229, 67391, 173977}},
-{18734, 18, 89616, {1, 3, 7, 13, 17, 11, 49, 135, 475, 303, 1373, 1437, 6119, 1729, 21347, 31643, 86523, 41223}},
-{18735, 18, 89626, {1, 3, 7, 13, 3, 19, 103, 53, 209, 281, 77, 2009, 7911, 8549, 17655, 33165, 9685, 2289}},
-{18736, 18, 89650, {1, 3, 3, 9, 5, 31, 71, 113, 93, 255, 165, 3465, 6769, 13047, 20701, 33669, 22537, 175209}},
-{18737, 18, 89691, {1, 3, 1, 1, 15, 59, 89, 227, 275, 451, 869, 1865, 1327, 3895, 5459, 47997, 34287, 95343}},
-{18738, 18, 89718, {1, 3, 7, 13, 27, 1, 25, 99, 475, 421, 693, 1955, 4017, 16037, 29915, 52415, 99913, 59151}},
-{18739, 18, 89764, {1, 3, 5, 1, 9, 61, 107, 149, 465, 1003, 891, 2387, 407, 5851, 6287, 56401, 109693, 72035}},
-{18740, 18, 89776, {1, 1, 1, 11, 25, 53, 101, 125, 35, 949, 1019, 3087, 2785, 11271, 25623, 57313, 115683, 101923}},
-{18741, 18, 89785, {1, 3, 5, 13, 19, 13, 97, 147, 149, 483, 1727, 1771, 2089, 8661, 28223, 30437, 42565, 13261}},
-{18742, 18, 89813, {1, 3, 3, 11, 17, 9, 13, 13, 419, 531, 1617, 1459, 411, 9953, 25581, 30305, 120721, 81113}},
-{18743, 18, 89817, {1, 3, 3, 9, 9, 9, 83, 35, 367, 981, 911, 1915, 4937, 16187, 20441, 30433, 107605, 119939}},
-{18744, 18, 89861, {1, 3, 7, 11, 11, 47, 31, 7, 141, 905, 1753, 3069, 47, 7347, 10517, 19515, 126827, 68669}},
-{18745, 18, 89876, {1, 3, 3, 9, 17, 33, 121, 159, 265, 389, 261, 2479, 7705, 6453, 31963, 14123, 100201, 77235}},
-{18746, 18, 89889, {1, 1, 5, 5, 13, 63, 3, 1, 107, 383, 633, 2183, 1437, 14525, 29315, 3277, 2153, 204061}},
-{18747, 18, 89904, {1, 3, 3, 3, 17, 9, 47, 173, 17, 413, 451, 1127, 1807, 5265, 32543, 8215, 123601, 138777}},
-{18748, 18, 89939, {1, 3, 1, 1, 7, 57, 93, 29, 101, 955, 1445, 4017, 2853, 3551, 22173, 40355, 34687, 133063}},
-{18749, 18, 89948, {1, 1, 5, 11, 19, 15, 95, 177, 49, 971, 15, 2293, 2627, 7841, 2103, 64331, 60481, 182431}},
-{18750, 18, 89952, {1, 3, 1, 15, 25, 57, 47, 85, 485, 11, 1669, 995, 6939, 4125, 19513, 62397, 62645, 82213}},
-{18751, 18, 89964, {1, 1, 1, 11, 1, 37, 101, 157, 17, 261, 997, 817, 2195, 4141, 10505, 60685, 98165, 167391}},
-{18752, 18, 89969, {1, 1, 1, 1, 31, 9, 103, 97, 161, 13, 1043, 307, 7321, 671, 12417, 58661, 23031, 207833}},
-{18753, 18, 89979, {1, 1, 7, 9, 15, 49, 69, 117, 93, 95, 507, 393, 6169, 2111, 27179, 47217, 93699, 67315}},
-{18754, 18, 90009, {1, 3, 7, 1, 23, 41, 115, 125, 343, 615, 397, 1199, 3041, 11019, 1071, 51069, 75757, 245765}},
-{18755, 18, 90022, {1, 1, 1, 13, 7, 15, 111, 239, 29, 419, 203, 2395, 3995, 13, 32341, 17471, 53259, 3317}},
-{18756, 18, 90031, {1, 3, 1, 11, 29, 27, 15, 217, 17, 163, 1847, 3549, 4911, 4539, 4927, 57157, 44893, 41669}},
-{18757, 18, 90043, {1, 1, 7, 7, 25, 15, 101, 149, 433, 717, 1827, 3837, 4565, 14521, 28857, 27775, 117429, 136131}},
-{18758, 18, 90045, {1, 1, 1, 3, 25, 35, 85, 3, 381, 253, 375, 3967, 3101, 12727, 31739, 48885, 35821, 92229}},
-{18759, 18, 90068, {1, 3, 3, 7, 29, 5, 51, 157, 67, 467, 1957, 3453, 1353, 4839, 25379, 42731, 109385, 52479}},
-{18760, 18, 90071, {1, 3, 7, 13, 3, 55, 61, 73, 257, 313, 89, 2557, 7467, 2223, 2951, 49265, 126605, 72007}},
-{18761, 18, 90082, {1, 3, 7, 5, 5, 11, 83, 3, 347, 63, 479, 529, 5059, 7029, 20523, 58387, 44891, 168921}},
-{18762, 18, 90087, {1, 3, 1, 11, 3, 51, 99, 5, 161, 279, 1509, 3659, 3107, 13925, 5117, 46153, 48731, 69767}},
-{18763, 18, 90117, {1, 1, 5, 5, 3, 53, 49, 243, 383, 401, 1205, 975, 3305, 12769, 25533, 28733, 115161, 160885}},
-{18764, 18, 90127, {1, 1, 1, 7, 15, 5, 43, 143, 493, 527, 1625, 2115, 3929, 12425, 16127, 25045, 55973, 202359}},
-{18765, 18, 90163, {1, 3, 7, 7, 11, 9, 69, 79, 417, 941, 473, 1655, 5763, 9889, 22443, 12153, 103489, 74737}},
-{18766, 18, 90166, {1, 1, 7, 9, 27, 31, 97, 253, 199, 99, 1955, 1481, 2509, 11923, 6337, 15899, 122515, 244721}},
-{18767, 18, 90177, {1, 1, 5, 13, 29, 15, 35, 177, 261, 613, 1279, 2837, 2945, 4501, 22865, 36893, 51979, 245569}},
-{18768, 18, 90211, {1, 1, 5, 9, 21, 5, 85, 5, 303, 165, 681, 3965, 2575, 1493, 10367, 55845, 92139, 92539}},
-{18769, 18, 90218, {1, 3, 5, 1, 23, 49, 49, 161, 481, 181, 1991, 1845, 4541, 14187, 10893, 64931, 79943, 57907}},
-{18770, 18, 90225, {1, 3, 1, 5, 11, 27, 19, 193, 371, 463, 1573, 271, 1127, 15091, 9967, 40337, 104163, 159339}},
-{18771, 18, 90231, {1, 3, 1, 3, 13, 3, 57, 149, 465, 789, 1155, 2223, 2007, 13987, 19057, 40447, 5217, 86191}},
-{18772, 18, 90235, {1, 3, 5, 5, 9, 45, 27, 155, 95, 171, 489, 2539, 843, 16125, 7047, 58541, 84641, 212013}},
-{18773, 18, 90289, {1, 3, 5, 13, 13, 53, 101, 159, 7, 481, 143, 3869, 6629, 3527, 1555, 6019, 155, 230157}},
-{18774, 18, 90344, {1, 3, 1, 1, 19, 59, 59, 129, 107, 887, 1595, 93, 6577, 3947, 14409, 31081, 68595, 226741}},
-{18775, 18, 90347, {1, 3, 3, 11, 13, 49, 81, 253, 363, 875, 489, 2181, 3487, 1615, 31157, 32949, 44809, 119421}},
-{18776, 18, 90379, {1, 1, 3, 1, 3, 19, 71, 93, 397, 521, 2015, 3829, 3013, 3941, 29437, 1959, 70283, 254361}},
-{18777, 18, 90387, {1, 3, 1, 3, 27, 11, 95, 39, 299, 521, 389, 3451, 3047, 8637, 22537, 11279, 67407, 101511}},
-{18778, 18, 90418, {1, 3, 1, 1, 27, 43, 123, 237, 315, 503, 1059, 2185, 3963, 1593, 19157, 13909, 58025, 91649}},
-{18779, 18, 90435, {1, 1, 7, 1, 5, 19, 79, 109, 459, 541, 521, 89, 389, 13499, 9769, 1429, 117357, 153261}},
-{18780, 18, 90444, {1, 1, 5, 3, 9, 29, 21, 97, 219, 915, 2013, 1955, 1015, 549, 9777, 5005, 110953, 16915}},
-{18781, 18, 90472, {1, 1, 1, 9, 29, 11, 103, 167, 465, 515, 843, 151, 769, 12033, 9451, 14949, 110075, 113947}},
-{18782, 18, 90478, {1, 3, 5, 1, 21, 1, 105, 49, 35, 737, 231, 2761, 1519, 9997, 601, 20883, 42575, 98081}},
-{18783, 18, 90485, {1, 1, 1, 5, 13, 63, 47, 171, 187, 407, 643, 1423, 6325, 10079, 23781, 36353, 20655, 10231}},
-{18784, 18, 90486, {1, 1, 7, 13, 13, 13, 91, 31, 19, 305, 505, 1937, 2683, 10791, 7719, 54797, 9405, 195819}},
-{18785, 18, 90513, {1, 1, 1, 7, 17, 9, 21, 211, 85, 851, 211, 1533, 4035, 11, 26873, 16755, 77809, 44603}},
-{18786, 18, 90514, {1, 1, 3, 1, 29, 47, 31, 141, 9, 881, 1229, 1261, 3747, 4603, 22177, 48937, 21435, 157029}},
-{18787, 18, 90532, {1, 1, 1, 9, 11, 35, 109, 187, 319, 863, 1339, 2193, 4147, 3721, 7243, 18295, 92461, 88875}},
-{18788, 18, 90567, {1, 1, 1, 1, 25, 41, 79, 191, 47, 819, 2013, 3133, 2763, 9231, 10343, 49693, 26753, 97465}},
-{18789, 18, 90595, {1, 3, 1, 3, 17, 25, 63, 139, 179, 113, 1681, 1997, 4561, 14453, 30721, 7053, 22937, 183303}},
-{18790, 18, 90597, {1, 1, 7, 3, 29, 11, 41, 157, 427, 887, 295, 443, 5593, 8633, 9757, 37595, 121655, 135739}},
-{18791, 18, 90621, {1, 3, 1, 7, 29, 5, 23, 231, 85, 67, 103, 1395, 7821, 9551, 17019, 1825, 69963, 254583}},
-{18792, 18, 90631, {1, 1, 7, 9, 7, 23, 7, 205, 17, 111, 1219, 3101, 7485, 11579, 11791, 10203, 119835, 175985}},
-{18793, 18, 90668, {1, 3, 3, 13, 3, 57, 101, 255, 331, 911, 491, 3929, 2519, 2185, 21107, 24599, 92831, 75001}},
-{18794, 18, 90706, {1, 3, 7, 1, 23, 53, 69, 229, 295, 881, 905, 3727, 3885, 7967, 2061, 53595, 16033, 36443}},
-{18795, 18, 90708, {1, 1, 7, 15, 21, 1, 127, 115, 191, 53, 929, 1093, 5447, 1665, 4409, 22611, 38157, 139201}},
-{18796, 18, 90715, {1, 3, 3, 13, 29, 31, 113, 215, 365, 41, 1977, 2839, 4147, 8321, 1361, 45717, 80505, 176631}},
-{18797, 18, 90724, {1, 3, 5, 3, 3, 57, 25, 81, 41, 229, 669, 3371, 7505, 1197, 14921, 34365, 67571, 27355}},
-{18798, 18, 90769, {1, 3, 7, 9, 17, 35, 7, 169, 13, 163, 2007, 3697, 5635, 8003, 26105, 62917, 19349, 47029}},
-{18799, 18, 90791, {1, 1, 5, 5, 29, 27, 89, 137, 69, 189, 871, 3139, 6383, 14955, 15349, 60447, 122291, 26541}},
-{18800, 18, 90792, {1, 1, 7, 13, 27, 49, 115, 111, 441, 865, 1397, 161, 755, 14461, 8601, 45533, 105309, 149799}},
-{18801, 18, 90805, {1, 1, 7, 3, 9, 29, 91, 5, 239, 605, 491, 1705, 4099, 9111, 19821, 56903, 62815, 40615}},
-{18802, 18, 90810, {1, 1, 7, 15, 5, 45, 71, 225, 211, 539, 1881, 1201, 5675, 6061, 12121, 13289, 30455, 33131}},
-{18803, 18, 90820, {1, 1, 5, 15, 5, 59, 35, 121, 185, 143, 165, 2999, 7907, 5035, 8337, 11951, 66403, 219997}},
-{18804, 18, 90844, {1, 1, 5, 9, 3, 7, 27, 129, 245, 93, 715, 1249, 1717, 13381, 31255, 23153, 22227, 8077}},
-{18805, 18, 90907, {1, 3, 5, 11, 19, 49, 21, 163, 157, 615, 1475, 2453, 6315, 12325, 26565, 58399, 49385, 252127}},
-{18806, 18, 90925, {1, 3, 7, 11, 23, 3, 35, 61, 409, 795, 1447, 3461, 535, 6533, 25757, 31783, 9509, 217589}},
-{18807, 18, 90926, {1, 1, 5, 15, 9, 21, 67, 65, 399, 515, 777, 3183, 1155, 16071, 7339, 59985, 56659, 200701}},
-{18808, 18, 90934, {1, 3, 3, 1, 15, 33, 119, 145, 71, 517, 1775, 163, 5307, 1549, 31071, 56289, 128395, 230381}},
-{18809, 18, 90946, {1, 3, 1, 7, 7, 47, 97, 187, 193, 887, 515, 1301, 4841, 12069, 413, 41503, 36421, 45909}},
-{18810, 18, 90981, {1, 1, 5, 3, 17, 21, 53, 227, 137, 865, 715, 3601, 5027, 2983, 24113, 23349, 106391, 188193}},
-{18811, 18, 90999, {1, 3, 7, 15, 29, 37, 91, 235, 351, 15, 425, 681, 187, 1517, 30079, 41347, 49691, 66369}},
-{18812, 18, 91003, {1, 1, 5, 5, 15, 25, 93, 245, 397, 517, 1635, 2475, 5543, 9597, 27721, 21475, 79571, 259011}},
-{18813, 18, 91019, {1, 1, 1, 5, 21, 29, 5, 161, 37, 409, 1661, 3371, 5663, 4317, 9951, 23605, 7393, 90593}},
-{18814, 18, 91022, {1, 1, 3, 15, 21, 51, 79, 159, 209, 891, 1391, 2895, 5003, 6601, 17983, 42359, 104497, 162181}},
-{18815, 18, 91050, {1, 3, 7, 11, 23, 51, 99, 145, 21, 345, 1389, 1035, 5939, 8293, 22765, 23331, 7789, 115149}},
-{18816, 18, 91055, {1, 1, 5, 11, 27, 61, 115, 123, 317, 607, 463, 779, 5121, 3861, 18761, 39407, 125837, 244163}},
-{18817, 18, 91064, {1, 1, 7, 3, 15, 9, 33, 1, 437, 621, 31, 147, 8157, 3451, 18223, 61187, 125297, 211225}},
-{18818, 18, 91078, {1, 3, 1, 11, 27, 55, 21, 251, 5, 57, 1889, 71, 3745, 499, 9043, 62683, 21945, 138615}},
-{18819, 18, 91117, {1, 1, 3, 13, 25, 9, 1, 31, 277, 373, 507, 301, 2341, 1741, 11997, 47661, 44121, 183151}},
-{18820, 18, 91120, {1, 3, 3, 5, 15, 51, 5, 233, 475, 397, 1833, 1267, 7025, 2593, 15425, 47053, 16205, 208007}},
-{18821, 18, 91129, {1, 3, 3, 9, 31, 51, 123, 219, 493, 789, 659, 985, 7283, 11545, 15383, 25173, 130423, 196619}},
-{18822, 18, 91140, {1, 1, 1, 15, 9, 17, 37, 145, 297, 933, 1019, 1699, 2149, 12391, 17003, 42157, 126283, 252231}},
-{18823, 18, 91157, {1, 3, 5, 9, 17, 1, 91, 69, 335, 857, 925, 3855, 2225, 6909, 19101, 12191, 92117, 229077}},
-{18824, 18, 91161, {1, 3, 5, 13, 5, 21, 67, 17, 307, 879, 1563, 3169, 745, 6799, 27237, 39621, 1413, 146295}},
-{18825, 18, 91240, {1, 3, 7, 13, 17, 59, 23, 253, 415, 761, 451, 2773, 3523, 10985, 29853, 7275, 79521, 133447}},
-{18826, 18, 91260, {1, 1, 1, 1, 15, 43, 89, 19, 85, 837, 1335, 1641, 105, 5429, 8317, 45555, 104447, 102313}},
-{18827, 18, 91270, {1, 3, 3, 5, 17, 21, 67, 235, 367, 265, 1069, 835, 5457, 177, 26987, 39477, 6895, 123283}},
-{18828, 18, 91287, {1, 1, 5, 15, 19, 61, 5, 15, 487, 291, 661, 825, 1569, 8795, 13035, 57077, 112847, 160267}},
-{18829, 18, 91321, {1, 1, 7, 9, 27, 21, 91, 133, 361, 7, 447, 3035, 3523, 13167, 15927, 35555, 35713, 91291}},
-{18830, 18, 91336, {1, 3, 7, 11, 17, 23, 77, 255, 437, 897, 1185, 1633, 6451, 13081, 29097, 61335, 39671, 177835}},
-{18831, 18, 91341, {1, 1, 7, 5, 31, 49, 81, 221, 167, 241, 1895, 1813, 1493, 2475, 379, 5685, 116341, 121823}},
-{18832, 18, 91378, {1, 3, 5, 9, 25, 11, 117, 253, 337, 381, 743, 69, 1641, 3649, 26335, 59683, 28729, 83449}},
-{18833, 18, 91398, {1, 3, 1, 7, 15, 17, 59, 9, 129, 233, 1905, 1371, 6521, 8953, 26173, 9707, 70817, 260035}},
-{18834, 18, 91437, {1, 3, 1, 5, 19, 53, 23, 255, 305, 835, 1387, 2947, 3013, 9117, 27571, 47123, 49881, 47229}},
-{18835, 18, 91440, {1, 1, 3, 5, 23, 37, 123, 193, 365, 49, 1211, 3083, 8133, 14205, 11361, 55945, 23225, 159109}},
-{18836, 18, 91475, {1, 1, 7, 11, 5, 49, 43, 165, 97, 581, 617, 3045, 6187, 8399, 24045, 46713, 28389, 156811}},
-{18837, 18, 91494, {1, 3, 1, 5, 29, 17, 75, 231, 59, 143, 2041, 2319, 2289, 11805, 4039, 29895, 91305, 179091}},
-{18838, 18, 91500, {1, 1, 7, 7, 29, 5, 13, 43, 409, 81, 751, 2157, 2543, 13317, 28275, 60871, 119833, 36743}},
-{18839, 18, 91511, {1, 1, 5, 13, 5, 5, 21, 101, 497, 993, 157, 647, 3587, 1495, 20233, 30889, 112579, 172009}},
-{18840, 18, 91567, {1, 1, 7, 13, 7, 19, 101, 217, 305, 897, 1305, 1693, 6881, 2415, 17373, 56327, 53971, 19021}},
-{18841, 18, 91572, {1, 1, 7, 15, 31, 61, 93, 99, 459, 999, 239, 969, 2427, 12295, 23699, 4839, 73707, 110365}},
-{18842, 18, 91601, {1, 3, 5, 9, 15, 59, 29, 35, 15, 331, 93, 529, 2651, 5675, 3039, 25967, 2907, 222053}},
-{18843, 18, 91617, {1, 3, 3, 1, 1, 17, 59, 81, 495, 917, 1907, 3, 1989, 14339, 21311, 60909, 39393, 54115}},
-{18844, 18, 91653, {1, 3, 1, 9, 1, 37, 31, 201, 251, 117, 1753, 2453, 5007, 6935, 1165, 49231, 51495, 200219}},
-{18845, 18, 91678, {1, 1, 3, 3, 15, 47, 17, 175, 77, 363, 1455, 1417, 1357, 2295, 31165, 53337, 97891, 145621}},
-{18846, 18, 91705, {1, 3, 3, 3, 27, 31, 41, 179, 47, 629, 5, 2543, 6817, 8953, 7151, 20715, 52363, 251037}},
-{18847, 18, 91723, {1, 3, 1, 1, 21, 11, 103, 87, 285, 189, 1911, 2979, 7563, 13405, 2309, 25695, 106277, 179493}},
-{18848, 18, 91725, {1, 1, 1, 5, 7, 19, 1, 233, 261, 825, 1071, 3529, 5617, 11207, 24559, 47461, 79753, 41009}},
-{18849, 18, 91733, {1, 1, 3, 1, 15, 35, 65, 157, 381, 509, 1455, 3117, 31, 2251, 29729, 33687, 74999, 214765}},
-{18850, 18, 91761, {1, 1, 7, 11, 31, 43, 11, 147, 509, 891, 1929, 357, 3905, 16251, 30169, 27787, 124003, 142587}},
-{18851, 18, 91768, {1, 1, 7, 11, 3, 31, 93, 161, 311, 377, 1119, 2177, 4339, 3889, 24299, 35167, 87583, 145611}},
-{18852, 18, 91790, {1, 1, 5, 9, 23, 9, 73, 85, 233, 919, 1319, 13, 3353, 1029, 31251, 17731, 86759, 11705}},
-{18853, 18, 91804, {1, 1, 1, 7, 27, 23, 67, 235, 207, 161, 697, 2433, 833, 5305, 32695, 29327, 25285, 51289}},
-{18854, 18, 91807, {1, 3, 3, 3, 31, 55, 107, 211, 61, 993, 1443, 463, 5029, 5401, 8821, 29721, 113939, 194839}},
-{18855, 18, 91808, {1, 1, 1, 11, 11, 33, 39, 167, 17, 863, 363, 3967, 2277, 4053, 15403, 31887, 98565, 217953}},
-{18856, 18, 91818, {1, 1, 7, 1, 21, 47, 97, 147, 155, 327, 1417, 3531, 7649, 8975, 21221, 57631, 72611, 97745}},
-{18857, 18, 91840, {1, 3, 3, 1, 1, 63, 19, 91, 105, 991, 819, 673, 7845, 14947, 1633, 40517, 91525, 151041}},
-{18858, 18, 91849, {1, 1, 7, 11, 25, 43, 57, 141, 65, 415, 1045, 3947, 7099, 11653, 29321, 51591, 2591, 44803}},
-{18859, 18, 91869, {1, 3, 1, 9, 15, 19, 105, 37, 485, 3, 213, 1217, 951, 5637, 1589, 25501, 95073, 124683}},
-{18860, 18, 91873, {1, 1, 5, 7, 13, 19, 55, 143, 507, 575, 715, 1633, 5201, 10493, 26041, 18407, 8097, 152313}},
-{18861, 18, 91876, {1, 1, 3, 5, 9, 51, 5, 171, 143, 877, 1571, 2997, 4209, 13423, 9389, 23015, 6665, 254799}},
-{18862, 18, 91888, {1, 3, 5, 15, 31, 43, 87, 79, 89, 463, 1075, 1257, 1631, 13225, 13529, 53267, 73651, 89125}},
-{18863, 18, 91891, {1, 3, 7, 13, 23, 17, 93, 113, 45, 225, 1939, 3301, 6031, 9749, 16577, 12857, 68437, 169861}},
-{18864, 18, 91897, {1, 3, 3, 15, 31, 11, 91, 127, 227, 813, 105, 901, 6861, 10627, 18425, 2553, 102503, 83167}},
-{18865, 18, 91911, {1, 3, 3, 13, 17, 63, 83, 163, 451, 659, 1995, 2283, 6297, 8097, 20935, 6017, 4977, 5045}},
-{18866, 18, 91965, {1, 1, 5, 13, 27, 47, 103, 129, 259, 975, 391, 2343, 6639, 1385, 30187, 35401, 74321, 24751}},
-{18867, 18, 91971, {1, 3, 1, 13, 1, 57, 37, 65, 57, 413, 63, 3819, 5915, 3925, 20777, 48539, 3019, 54965}},
-{18868, 18, 91988, {1, 1, 7, 3, 7, 13, 91, 33, 143, 489, 657, 3127, 707, 10841, 11307, 37855, 92697, 119189}},
-{18869, 18, 91992, {1, 1, 3, 11, 25, 47, 11, 57, 463, 693, 55, 501, 3765, 15443, 12917, 61677, 97145, 213637}},
-{18870, 18, 92004, {1, 3, 1, 1, 13, 49, 13, 225, 101, 475, 627, 1447, 7587, 11335, 3599, 20795, 72915, 174663}},
-{18871, 18, 92021, {1, 3, 7, 5, 31, 15, 115, 255, 329, 365, 959, 3399, 4695, 14537, 1447, 17391, 88557, 130213}},
-{18872, 18, 92035, {1, 1, 1, 9, 25, 47, 29, 173, 29, 149, 291, 691, 7621, 7607, 20769, 7149, 27323, 57689}},
-{18873, 18, 92068, {1, 3, 5, 15, 3, 61, 119, 247, 25, 495, 1297, 1119, 8011, 16077, 21567, 30559, 88455, 68763}},
-{18874, 18, 92098, {1, 1, 7, 1, 11, 47, 109, 115, 313, 517, 1951, 3319, 337, 11793, 22345, 33457, 47383, 213893}},
-{18875, 18, 92104, {1, 1, 5, 11, 11, 53, 103, 237, 383, 927, 421, 4085, 3327, 169, 9941, 24753, 65437, 108173}},
-{18876, 18, 92121, {1, 1, 5, 11, 17, 59, 107, 53, 479, 143, 825, 2667, 5219, 6143, 11573, 33637, 124981, 98195}},
-{18877, 18, 92127, {1, 3, 3, 13, 3, 17, 61, 129, 475, 585, 1611, 1791, 7817, 4099, 20437, 51411, 130173, 220085}},
-{18878, 18, 92151, {1, 3, 3, 3, 27, 25, 33, 255, 361, 967, 1415, 3213, 3341, 15875, 32359, 53267, 27665, 178301}},
-{18879, 18, 92162, {1, 1, 5, 3, 13, 9, 91, 187, 173, 525, 1675, 2217, 4093, 2009, 16917, 18485, 104849, 163233}},
-{18880, 18, 92186, {1, 1, 1, 11, 3, 17, 125, 157, 9, 429, 1573, 2257, 7943, 9893, 5611, 64619, 4509, 200181}},
-{18881, 18, 92191, {1, 3, 1, 1, 3, 9, 83, 53, 315, 85, 1093, 2621, 663, 12369, 317, 6089, 16479, 225071}},
-{18882, 18, 92192, {1, 3, 3, 1, 25, 47, 57, 45, 219, 45, 945, 3989, 4889, 8989, 381, 52483, 57029, 253899}},
-{18883, 18, 92207, {1, 3, 3, 5, 3, 61, 75, 189, 53, 489, 553, 2381, 7485, 9941, 29733, 2611, 74119, 203647}},
-{18884, 18, 92260, {1, 3, 1, 11, 27, 63, 53, 61, 59, 613, 465, 867, 1985, 7605, 14301, 53847, 68547, 14717}},
-{18885, 18, 92282, {1, 3, 5, 11, 5, 41, 51, 11, 59, 761, 59, 267, 7273, 3061, 11223, 48825, 117869, 158551}},
-{18886, 18, 92288, {1, 3, 7, 1, 31, 47, 111, 43, 435, 997, 135, 3369, 6439, 5637, 13629, 13221, 90607, 86359}},
-{18887, 18, 92297, {1, 1, 1, 11, 23, 51, 109, 223, 495, 765, 1557, 3545, 305, 4949, 23931, 45115, 12121, 14487}},
-{18888, 18, 92303, {1, 3, 5, 9, 5, 25, 41, 249, 27, 375, 1339, 3647, 3529, 2077, 21091, 45523, 67191, 1257}},
-{18889, 18, 92315, {1, 1, 3, 7, 13, 15, 63, 45, 187, 761, 1245, 3381, 1817, 2491, 16469, 64417, 87333, 143103}},
-{18890, 18, 92322, {1, 1, 3, 13, 11, 33, 87, 11, 279, 689, 1047, 3935, 5359, 11309, 19735, 33259, 12347, 183653}},
-{18891, 18, 92327, {1, 1, 5, 7, 5, 49, 109, 221, 455, 167, 785, 1859, 4337, 14937, 209, 23435, 22923, 172985}},
-{18892, 18, 92341, {1, 3, 7, 9, 13, 7, 127, 117, 147, 741, 531, 2627, 2565, 11083, 30577, 42471, 77065, 120983}},
-{18893, 18, 92389, {1, 1, 7, 1, 5, 61, 115, 203, 15, 305, 1005, 2085, 2597, 4371, 11661, 33219, 53657, 40325}},
-{18894, 18, 92390, {1, 3, 7, 13, 13, 15, 69, 167, 369, 747, 1115, 1493, 4881, 2693, 32281, 27089, 56821, 121693}},
-{18895, 18, 92422, {1, 3, 5, 3, 19, 51, 101, 29, 411, 509, 847, 1033, 4135, 15561, 7045, 60757, 48479, 247295}},
-{18896, 18, 92439, {1, 1, 5, 3, 27, 47, 103, 123, 413, 71, 689, 2113, 4347, 1983, 25727, 20095, 3271, 133081}},
-{18897, 18, 92452, {1, 1, 3, 3, 5, 39, 87, 27, 505, 631, 689, 2591, 1955, 3205, 12681, 10821, 13343, 101505}},
-{18898, 18, 92470, {1, 3, 7, 9, 31, 23, 103, 223, 499, 721, 13, 1399, 7369, 3945, 27727, 7923, 60265, 197793}},
-{18899, 18, 92473, {1, 3, 3, 5, 27, 7, 119, 23, 371, 495, 1583, 3913, 5139, 12151, 17477, 10907, 121775, 13369}},
-{18900, 18, 92493, {1, 3, 7, 1, 19, 53, 91, 235, 161, 97, 37, 1115, 5909, 1943, 8137, 1541, 16253, 252151}},
-{18901, 18, 92508, {1, 3, 7, 5, 3, 1, 107, 241, 187, 253, 1225, 2827, 4191, 2749, 25629, 47465, 19969, 45035}},
-{18902, 18, 92517, {1, 3, 1, 5, 1, 29, 47, 233, 175, 313, 793, 2089, 6235, 6595, 27599, 20505, 63379, 8729}},
-{18903, 18, 92529, {1, 3, 7, 11, 15, 9, 87, 113, 389, 1, 1057, 3307, 3455, 1847, 1497, 28115, 92897, 2383}},
-{18904, 18, 92551, {1, 3, 7, 13, 19, 59, 45, 59, 49, 273, 1619, 1975, 5949, 9951, 7685, 52559, 42377, 29855}},
-{18905, 18, 92557, {1, 1, 3, 9, 19, 7, 119, 35, 85, 37, 269, 3443, 8015, 8061, 6001, 19123, 70643, 115513}},
-{18906, 18, 92596, {1, 1, 3, 15, 3, 19, 83, 171, 259, 207, 1495, 513, 5455, 4071, 27471, 15773, 66301, 228743}},
-{18907, 18, 92611, {1, 3, 7, 9, 3, 27, 93, 3, 471, 13, 677, 4067, 1941, 15345, 26629, 29419, 121593, 108669}},
-{18908, 18, 92613, {1, 3, 7, 15, 29, 43, 97, 41, 15, 181, 1969, 1901, 7237, 3879, 19337, 17659, 17957, 164667}},
-{18909, 18, 92642, {1, 3, 1, 1, 25, 33, 7, 41, 387, 469, 795, 781, 113, 4161, 29687, 32225, 73905, 137879}},
-{18910, 18, 92666, {1, 1, 3, 13, 9, 59, 89, 23, 393, 111, 1957, 719, 6179, 16183, 31331, 48015, 32147, 31691}},
-{18911, 18, 92684, {1, 3, 7, 5, 9, 45, 73, 219, 181, 51, 717, 1813, 2581, 1395, 17595, 23689, 89709, 201451}},
-{18912, 18, 92723, {1, 3, 7, 3, 1, 21, 15, 35, 131, 515, 803, 1429, 3855, 349, 11795, 26787, 6109, 117745}},
-{18913, 18, 92732, {1, 3, 3, 9, 7, 11, 57, 15, 491, 371, 1787, 85, 577, 11455, 27419, 20687, 2493, 209993}},
-{18914, 18, 92738, {1, 3, 7, 15, 5, 5, 87, 197, 93, 643, 247, 31, 357, 7377, 10509, 29883, 42747, 248861}},
-{18915, 18, 92783, {1, 3, 3, 3, 29, 33, 47, 253, 485, 25, 2003, 2953, 1629, 11549, 5697, 1135, 117761, 96411}},
-{18916, 18, 92808, {1, 3, 5, 1, 29, 5, 27, 187, 235, 423, 41, 1855, 4359, 15627, 28409, 49331, 37735, 68823}},
-{18917, 18, 92816, {1, 1, 5, 5, 21, 61, 67, 85, 41, 671, 1617, 3867, 7913, 1693, 18487, 1831, 100971, 168191}},
-{18918, 18, 92835, {1, 1, 7, 3, 1, 61, 111, 87, 55, 229, 217, 2801, 563, 13617, 9641, 22247, 16039, 113541}},
-{18919, 18, 92847, {1, 3, 5, 7, 5, 29, 67, 99, 91, 561, 1203, 643, 2607, 13421, 29695, 31925, 82985, 69031}},
-{18920, 18, 92879, {1, 1, 1, 1, 27, 7, 63, 107, 269, 163, 1711, 587, 5657, 15077, 24709, 10235, 95483, 94799}},
-{18921, 18, 92881, {1, 3, 3, 5, 29, 5, 127, 137, 67, 609, 1657, 1131, 959, 15773, 17295, 58575, 96525, 80529}},
-{18922, 18, 92884, {1, 3, 7, 7, 25, 15, 89, 93, 145, 695, 367, 2853, 3073, 4867, 26823, 31467, 94769, 9145}},
-{18923, 18, 92932, {1, 1, 7, 15, 15, 5, 1, 225, 57, 381, 1295, 2525, 1493, 2401, 91, 19809, 32803, 195289}},
-{18924, 18, 92935, {1, 3, 3, 7, 29, 51, 29, 63, 249, 107, 1689, 3703, 7227, 6967, 27861, 39167, 20043, 218827}},
-{18925, 18, 92960, {1, 1, 3, 13, 17, 1, 77, 143, 167, 255, 1709, 2089, 7465, 4805, 16185, 15167, 20493, 240855}},
-{18926, 18, 92990, {1, 1, 5, 1, 11, 43, 107, 175, 93, 955, 615, 2923, 3637, 7451, 18847, 53467, 12463, 127249}},
-{18927, 18, 93010, {1, 1, 3, 13, 31, 1, 61, 113, 479, 777, 1805, 3625, 6299, 12221, 29599, 60175, 31165, 122815}},
-{18928, 18, 93025, {1, 3, 3, 11, 11, 29, 89, 129, 195, 337, 1843, 2769, 1747, 7137, 9901, 18459, 25215, 70609}},
-{18929, 18, 93046, {1, 1, 3, 7, 17, 35, 55, 81, 413, 25, 1505, 2185, 3121, 11435, 17885, 12543, 36767, 64039}},
-{18930, 18, 93085, {1, 3, 1, 13, 25, 9, 83, 25, 5, 49, 1975, 3967, 4135, 13213, 26479, 63913, 14921, 96193}},
-{18931, 18, 93089, {1, 3, 7, 5, 17, 15, 101, 47, 245, 821, 1275, 3343, 5471, 5045, 31741, 3319, 8141, 95501}},
-{18932, 18, 93096, {1, 3, 1, 13, 1, 5, 105, 39, 175, 439, 1625, 249, 4859, 12449, 30529, 45669, 49071, 214037}},
-{18933, 18, 93145, {1, 1, 7, 7, 17, 21, 83, 123, 261, 559, 1967, 2933, 4417, 8331, 10119, 21793, 128729, 187247}},
-{18934, 18, 93155, {1, 1, 7, 9, 15, 43, 77, 231, 241, 419, 503, 3335, 927, 2567, 31259, 52453, 114441, 257449}},
-{18935, 18, 93169, {1, 3, 3, 1, 9, 29, 21, 89, 311, 185, 519, 271, 3595, 8951, 6105, 64593, 38209, 120491}},
-{18936, 18, 93179, {1, 1, 7, 9, 1, 57, 65, 5, 275, 615, 801, 2839, 2851, 15609, 28731, 31223, 87725, 437}},
-{18937, 18, 93184, {1, 3, 3, 5, 29, 3, 67, 53, 17, 499, 263, 651, 7963, 5371, 11593, 34761, 57427, 84979}},
-{18938, 18, 93204, {1, 3, 7, 11, 15, 9, 33, 165, 313, 659, 909, 969, 2309, 2197, 27263, 35273, 52887, 236107}},
-{18939, 18, 93211, {1, 1, 7, 1, 13, 17, 29, 3, 329, 573, 619, 1013, 6947, 7031, 30773, 41129, 116481, 184233}},
-{18940, 18, 93213, {1, 1, 5, 9, 13, 5, 87, 235, 63, 759, 1143, 1861, 3783, 2735, 26191, 64387, 3651, 119447}},
-{18941, 18, 93227, {1, 1, 3, 7, 15, 41, 117, 135, 273, 655, 251, 1859, 4363, 14725, 29385, 6269, 91505, 82679}},
-{18942, 18, 93285, {1, 3, 7, 3, 13, 21, 21, 9, 121, 899, 199, 1973, 7437, 9771, 26647, 30909, 118573, 152913}},
-{18943, 18, 93292, {1, 3, 3, 9, 31, 43, 5, 249, 109, 183, 161, 1185, 4025, 10331, 20983, 28549, 122687, 183429}},
-{18944, 18, 93320, {1, 3, 7, 7, 11, 45, 111, 99, 487, 971, 597, 1555, 273, 10403, 25289, 45483, 35845, 35791}},
-{18945, 18, 93356, {1, 1, 1, 7, 11, 49, 125, 229, 279, 289, 1945, 3575, 5683, 15659, 31123, 12517, 79303, 255797}},
-{18946, 18, 93371, {1, 3, 1, 15, 9, 23, 61, 53, 383, 855, 1743, 407, 4401, 7507, 26307, 56205, 110943, 184183}},
-{18947, 18, 93374, {1, 3, 5, 13, 23, 29, 101, 243, 417, 925, 1267, 257, 5893, 4335, 6309, 43519, 126035, 99205}},
-{18948, 18, 93385, {1, 3, 1, 5, 5, 35, 83, 25, 31, 455, 1799, 2919, 7037, 11829, 12239, 12969, 108469, 89513}},
-{18949, 18, 93403, {1, 3, 5, 9, 17, 29, 61, 217, 183, 131, 425, 4025, 7141, 5445, 21497, 10603, 53423, 5701}},
-{18950, 18, 93406, {1, 1, 1, 15, 27, 35, 9, 139, 261, 43, 587, 3835, 4627, 11689, 15739, 6031, 73547, 134271}},
-{18951, 18, 93427, {1, 1, 3, 3, 25, 15, 7, 225, 29, 785, 2047, 2219, 6083, 7973, 17053, 56167, 83915, 87597}},
-{18952, 18, 93451, {1, 3, 7, 15, 13, 43, 85, 121, 421, 867, 1895, 2437, 6003, 5269, 8625, 26877, 100023, 110229}},
-{18953, 18, 93454, {1, 3, 3, 3, 25, 49, 121, 1, 125, 353, 1811, 1575, 3925, 13897, 26087, 24977, 105995, 242817}},
-{18954, 18, 93472, {1, 1, 1, 9, 31, 55, 71, 241, 439, 927, 955, 109, 7779, 2397, 18797, 34177, 1255, 178671}},
-{18955, 18, 93482, {1, 1, 7, 7, 5, 15, 99, 225, 49, 407, 1711, 4027, 4845, 9209, 20983, 33969, 14205, 9351}},
-{18956, 18, 93507, {1, 3, 5, 1, 9, 13, 113, 143, 97, 189, 929, 1163, 2261, 9761, 30011, 32911, 117043, 169493}},
-{18957, 18, 93537, {1, 1, 3, 5, 9, 35, 95, 77, 5, 95, 1745, 2013, 7009, 5427, 18969, 2771, 5099, 52939}},
-{18958, 18, 93562, {1, 3, 7, 9, 13, 19, 31, 189, 367, 569, 95, 1665, 6231, 2169, 22589, 8427, 116097, 41077}},
-{18959, 18, 93564, {1, 3, 7, 3, 31, 61, 45, 233, 327, 541, 87, 3449, 2767, 12237, 17747, 53827, 80389, 121489}},
-{18960, 18, 93608, {1, 3, 7, 15, 31, 1, 49, 73, 157, 131, 553, 3417, 5283, 4737, 31675, 63213, 43689, 261869}},
-{18961, 18, 93636, {1, 3, 7, 1, 3, 5, 113, 43, 343, 39, 135, 1555, 7955, 9851, 30983, 21955, 34871, 147649}},
-{18962, 18, 93640, {1, 3, 5, 3, 5, 27, 15, 179, 141, 983, 265, 2651, 5907, 10501, 6275, 29629, 115965, 125745}},
-{18963, 18, 93653, {1, 3, 7, 13, 1, 1, 81, 105, 309, 457, 1817, 3435, 4615, 1181, 27835, 26075, 63447, 44701}},
-{18964, 18, 93654, {1, 1, 5, 5, 25, 19, 85, 103, 409, 323, 2001, 3719, 3403, 1301, 19615, 47829, 109905, 65777}},
-{18965, 18, 93664, {1, 3, 5, 3, 21, 15, 47, 75, 467, 273, 1885, 3929, 1877, 5209, 6881, 34431, 35663, 100205}},
-{18966, 18, 93676, {1, 1, 5, 3, 3, 9, 47, 143, 471, 653, 1011, 2263, 3673, 11921, 31207, 50365, 27177, 214377}},
-{18967, 18, 93721, {1, 3, 1, 15, 3, 43, 81, 253, 495, 139, 679, 2207, 4603, 5269, 27133, 46461, 120783, 185595}},
-{18968, 18, 93740, {1, 1, 7, 3, 13, 3, 109, 197, 477, 101, 859, 1035, 777, 10153, 15581, 22715, 17493, 120851}},
-{18969, 18, 93743, {1, 3, 1, 3, 23, 5, 121, 67, 265, 935, 741, 3311, 541, 1093, 1639, 5941, 5587, 150345}},
-{18970, 18, 93745, {1, 3, 1, 5, 3, 13, 65, 173, 493, 303, 359, 3813, 6007, 1105, 12185, 10431, 17117, 164899}},
-{18971, 18, 93751, {1, 3, 3, 1, 25, 33, 71, 181, 149, 7, 333, 1981, 2981, 14683, 10997, 63373, 22605, 119681}},
-{18972, 18, 93770, {1, 1, 1, 15, 29, 35, 89, 21, 281, 175, 587, 3117, 7221, 8239, 26399, 49133, 65895, 142175}},
-{18973, 18, 93796, {1, 3, 7, 15, 9, 9, 35, 161, 65, 749, 421, 3575, 6307, 2029, 11423, 63901, 102049, 26333}},
-{18974, 18, 93820, {1, 3, 1, 13, 1, 45, 97, 41, 231, 245, 271, 1497, 3119, 6225, 21665, 12113, 67315, 62779}},
-{18975, 18, 93824, {1, 1, 1, 7, 3, 29, 119, 193, 179, 353, 1015, 2803, 6869, 7653, 22309, 53421, 86969, 115549}},
-{18976, 18, 93833, {1, 3, 3, 5, 17, 37, 49, 129, 195, 537, 1237, 2775, 6683, 699, 19181, 61125, 27483, 175645}},
-{18977, 18, 93841, {1, 3, 7, 3, 7, 49, 107, 41, 285, 335, 1415, 4015, 1301, 6525, 32429, 9337, 87923, 176751}},
-{18978, 18, 93847, {1, 1, 5, 9, 21, 43, 91, 25, 225, 311, 417, 303, 2629, 3609, 29987, 28647, 104173, 52383}},
-{18979, 18, 93848, {1, 3, 5, 9, 13, 47, 75, 143, 109, 173, 503, 3843, 1767, 9433, 10009, 5653, 87339, 212975}},
-{18980, 18, 93854, {1, 3, 1, 13, 13, 55, 123, 95, 499, 245, 1875, 3661, 7661, 6927, 21003, 51729, 88089, 89063}},
-{18981, 18, 93882, {1, 1, 3, 1, 31, 7, 93, 35, 169, 191, 1079, 2137, 4401, 1563, 20021, 9101, 66881, 231589}},
-{18982, 18, 93943, {1, 3, 1, 15, 21, 41, 75, 231, 459, 701, 1715, 2581, 4445, 5877, 4765, 1037, 15827, 189529}},
-{18983, 18, 93958, {1, 3, 5, 13, 17, 23, 41, 133, 143, 297, 1335, 3907, 7745, 5139, 9397, 5765, 5347, 243091}},
-{18984, 18, 93972, {1, 1, 5, 13, 7, 15, 31, 183, 315, 153, 785, 2723, 97, 14361, 10509, 17717, 46615, 133289}},
-{18985, 18, 93975, {1, 3, 7, 9, 13, 3, 75, 103, 445, 409, 603, 201, 1873, 9277, 23953, 6881, 64327, 196771}},
-{18986, 18, 94003, {1, 1, 7, 13, 15, 21, 73, 183, 419, 997, 857, 1373, 3855, 417, 10175, 5253, 66509, 15731}},
-{18987, 18, 94009, {1, 3, 3, 9, 19, 7, 15, 119, 497, 25, 1165, 105, 2605, 15097, 28241, 2269, 519, 235655}},
-{18988, 18, 94020, {1, 3, 3, 9, 27, 9, 103, 205, 97, 317, 1621, 971, 931, 9099, 24583, 12695, 122399, 78021}},
-{18989, 18, 94072, {1, 1, 3, 5, 27, 45, 41, 239, 87, 603, 317, 3507, 7677, 9141, 26721, 40225, 80515, 205263}},
-{18990, 18, 94081, {1, 1, 3, 1, 25, 3, 63, 165, 41, 783, 291, 1997, 3769, 1881, 30613, 18821, 86175, 38837}},
-{18991, 18, 94093, {1, 1, 3, 5, 17, 19, 95, 17, 357, 587, 689, 3127, 6999, 6703, 23923, 55945, 97629, 210177}},
-{18992, 18, 94102, {1, 1, 3, 15, 21, 55, 63, 229, 397, 1007, 779, 2105, 681, 10659, 26679, 681, 115901, 83627}},
-{18993, 18, 94122, {1, 1, 7, 11, 25, 9, 47, 133, 109, 17, 697, 749, 5529, 9289, 29675, 2631, 15247, 13913}},
-{18994, 18, 94135, {1, 1, 7, 7, 3, 55, 29, 13, 467, 889, 675, 1187, 3301, 13721, 13783, 44559, 78177, 114219}},
-{18995, 18, 94136, {1, 3, 5, 13, 15, 11, 77, 71, 313, 427, 1385, 2007, 4003, 1529, 4797, 12289, 24897, 129513}},
-{18996, 18, 94150, {1, 1, 3, 11, 9, 47, 103, 253, 345, 659, 1109, 3493, 2515, 5669, 30551, 25077, 97393, 252689}},
-{18997, 18, 94184, {1, 3, 7, 9, 25, 19, 69, 161, 365, 51, 1365, 1045, 4319, 10035, 15529, 23251, 44359, 62163}},
-{18998, 18, 94187, {1, 3, 1, 7, 3, 25, 119, 33, 19, 561, 659, 2741, 6177, 899, 30911, 9627, 83003, 12939}},
-{18999, 18, 94258, {1, 3, 7, 1, 13, 37, 19, 161, 427, 621, 1045, 1963, 6067, 4439, 32507, 32775, 5201, 144645}},
-{19000, 18, 94264, {1, 1, 5, 7, 31, 17, 89, 239, 317, 109, 1827, 1395, 1587, 14813, 29911, 63545, 22939, 235383}},
-{19001, 18, 94272, {1, 1, 7, 15, 1, 17, 41, 123, 405, 539, 1063, 1443, 4611, 1847, 24107, 29365, 85859, 218601}},
-{19002, 18, 94278, {1, 1, 5, 13, 21, 27, 101, 223, 245, 705, 1579, 679, 5461, 8955, 15031, 7731, 31219, 165033}},
-{19003, 18, 94281, {1, 1, 7, 11, 19, 29, 13, 223, 179, 481, 761, 1543, 3195, 10695, 17147, 37577, 130901, 44699}},
-{19004, 18, 94317, {1, 1, 7, 3, 19, 53, 49, 1, 393, 583, 1183, 2817, 1293, 12949, 15491, 44467, 86261, 220439}},
-{19005, 18, 94348, {1, 3, 7, 15, 15, 47, 7, 125, 467, 511, 1207, 3787, 5575, 5359, 3859, 29933, 104627, 243073}},
-{19006, 18, 94376, {1, 1, 1, 13, 27, 25, 17, 243, 477, 457, 1835, 2859, 1023, 10107, 26829, 49853, 114569, 250471}},
-{19007, 18, 94382, {1, 3, 1, 15, 11, 43, 15, 235, 431, 671, 1935, 1143, 4121, 15403, 19313, 15919, 111961, 50455}},
-{19008, 18, 94387, {1, 3, 3, 3, 11, 45, 107, 143, 353, 671, 1259, 1599, 6075, 10645, 9131, 28133, 58679, 29883}},
-{19009, 18, 94389, {1, 3, 5, 15, 15, 43, 29, 171, 303, 71, 1751, 411, 7615, 12063, 26829, 31469, 34335, 3163}},
-{19010, 18, 94393, {1, 1, 7, 7, 25, 63, 25, 25, 27, 671, 505, 1235, 1985, 2593, 30031, 3251, 94729, 248911}},
-{19011, 18, 94402, {1, 1, 3, 1, 19, 15, 125, 133, 133, 209, 1749, 2091, 6325, 1275, 5675, 2249, 22631, 56293}},
-{19012, 18, 94421, {1, 1, 5, 1, 19, 27, 25, 99, 211, 739, 565, 3903, 7701, 7547, 12303, 5421, 24663, 22807}},
-{19013, 18, 94422, {1, 3, 5, 13, 5, 45, 99, 67, 21, 269, 851, 3333, 4555, 12483, 14645, 44757, 99047, 198521}},
-{19014, 18, 94431, {1, 1, 5, 13, 19, 1, 123, 87, 109, 799, 591, 2997, 1005, 16369, 10329, 34541, 100935, 200397}},
-{19015, 18, 94473, {1, 3, 5, 1, 13, 51, 93, 23, 19, 23, 965, 171, 6865, 3561, 23255, 44295, 87405, 222269}},
-{19016, 18, 94487, {1, 1, 3, 5, 1, 53, 25, 129, 123, 737, 271, 61, 113, 8481, 27075, 58633, 21499, 156689}},
-{19017, 18, 94504, {1, 3, 3, 11, 3, 43, 11, 123, 243, 1015, 1389, 3663, 1725, 6933, 5315, 7137, 127705, 56607}},
-{19018, 18, 94510, {1, 1, 5, 13, 7, 23, 43, 103, 503, 173, 267, 1509, 3311, 9553, 28851, 15771, 28741, 236427}},
-{19019, 18, 94522, {1, 1, 5, 15, 27, 43, 119, 3, 13, 107, 317, 3725, 6669, 4945, 30485, 10155, 96893, 154081}},
-{19020, 18, 94532, {1, 3, 7, 5, 11, 21, 61, 99, 155, 45, 569, 1325, 673, 15803, 12047, 55431, 9515, 106969}},
-{19021, 18, 94572, {1, 1, 7, 11, 27, 49, 121, 145, 105, 223, 1471, 1163, 3889, 4213, 21195, 45649, 14663, 82799}},
-{19022, 18, 94589, {1, 1, 3, 3, 31, 21, 17, 85, 31, 695, 1591, 2465, 907, 11621, 29681, 13131, 77187, 175913}},
-{19023, 18, 94599, {1, 3, 5, 5, 21, 49, 77, 229, 359, 825, 1851, 1223, 3351, 5349, 30971, 20797, 26975, 94425}},
-{19024, 18, 94603, {1, 1, 3, 1, 3, 63, 23, 219, 503, 47, 1675, 1641, 5257, 8035, 29793, 30093, 44897, 235691}},
-{19025, 18, 94647, {1, 1, 7, 9, 27, 37, 109, 33, 511, 203, 1195, 3281, 407, 15237, 28485, 21379, 106325, 231755}},
-{19026, 18, 94665, {1, 3, 1, 3, 9, 45, 19, 31, 255, 799, 909, 767, 421, 3301, 18557, 15043, 48505, 36763}},
-{19027, 18, 94695, {1, 3, 7, 13, 1, 45, 59, 233, 319, 265, 517, 1571, 4593, 12813, 30729, 19517, 70345, 142411}},
-{19028, 18, 94716, {1, 1, 1, 13, 17, 15, 79, 93, 265, 381, 285, 253, 919, 3715, 30555, 38801, 30439, 51511}},
-{19029, 18, 94738, {1, 1, 7, 15, 25, 39, 71, 57, 145, 487, 1655, 2589, 7655, 8413, 24537, 36761, 36427, 88929}},
-{19030, 18, 94740, {1, 1, 3, 3, 29, 41, 61, 191, 97, 849, 911, 3269, 5425, 13997, 7749, 537, 113705, 179765}},
-{19031, 18, 94778, {1, 1, 5, 9, 13, 55, 33, 221, 27, 521, 13, 2847, 6035, 8397, 6579, 29353, 101953, 88983}},
-{19032, 18, 94803, {1, 3, 3, 13, 31, 47, 97, 177, 373, 353, 159, 249, 4741, 7427, 8353, 38617, 13857, 122081}},
-{19033, 18, 94810, {1, 3, 5, 15, 13, 21, 1, 239, 369, 253, 1009, 1927, 5111, 2219, 28167, 32013, 51487, 210521}},
-{19034, 18, 94815, {1, 3, 5, 9, 17, 21, 37, 105, 405, 39, 321, 1515, 3759, 15469, 13643, 60157, 72127, 233505}},
-{19035, 18, 94821, {1, 3, 7, 5, 1, 3, 3, 125, 283, 757, 829, 2303, 3715, 6027, 17795, 37359, 54721, 5891}},
-{19036, 18, 94862, {1, 3, 7, 15, 27, 63, 117, 101, 341, 965, 1543, 51, 3397, 14051, 9889, 64647, 111169, 249477}},
-{19037, 18, 94886, {1, 1, 5, 13, 5, 29, 51, 61, 233, 685, 751, 163, 2319, 14691, 29881, 39029, 57093, 240147}},
-{19038, 18, 94900, {1, 3, 5, 3, 9, 21, 107, 147, 263, 471, 621, 3485, 197, 13271, 24689, 64341, 110163, 142711}},
-{19039, 18, 94924, {1, 3, 1, 7, 1, 23, 17, 31, 131, 631, 795, 3751, 5337, 9151, 2873, 31113, 65303, 244969}},
-{19040, 18, 94952, {1, 1, 5, 11, 3, 51, 93, 155, 389, 859, 1181, 2711, 1375, 6119, 229, 47767, 115521, 114129}},
-{19041, 18, 94963, {1, 3, 3, 15, 5, 7, 29, 187, 259, 911, 1537, 1885, 6139, 4549, 21655, 58771, 1003, 124609}},
-{19042, 18, 94970, {1, 1, 3, 15, 25, 45, 97, 217, 331, 305, 1105, 3465, 3651, 10171, 31601, 6947, 4545, 232627}},
-{19043, 18, 94980, {1, 1, 5, 5, 9, 53, 109, 201, 473, 201, 1113, 973, 1825, 13089, 1207, 9947, 92515, 216199}},
-{19044, 18, 94992, {1, 3, 7, 3, 1, 49, 25, 109, 249, 489, 1663, 3493, 4615, 13899, 27851, 60711, 14351, 41787}},
-{19045, 18, 95017, {1, 3, 3, 7, 3, 15, 29, 53, 61, 669, 371, 2187, 6769, 4623, 25785, 12997, 52263, 28387}},
-{19046, 18, 95028, {1, 1, 1, 3, 9, 31, 69, 3, 441, 219, 285, 183, 1971, 10903, 8271, 19389, 61913, 203537}},
-{19047, 18, 95031, {1, 1, 5, 3, 9, 63, 117, 131, 53, 525, 1349, 2701, 1317, 6047, 1661, 51785, 93199, 158645}},
-{19048, 18, 95035, {1, 3, 5, 3, 21, 61, 11, 91, 317, 635, 61, 1919, 2139, 12817, 6587, 63201, 52659, 8971}},
-{19049, 18, 95040, {1, 3, 1, 9, 11, 47, 49, 35, 115, 711, 511, 835, 3787, 837, 15737, 7467, 53263, 132047}},
-{19050, 18, 95058, {1, 1, 5, 3, 27, 47, 121, 211, 65, 363, 1067, 3813, 6353, 13701, 23943, 7573, 112721, 219587}},
-{19051, 18, 95079, {1, 1, 3, 7, 21, 39, 15, 199, 113, 517, 1429, 1399, 6007, 1389, 16425, 17709, 1231, 51803}},
-{19052, 18, 95122, {1, 3, 5, 11, 5, 37, 35, 97, 215, 281, 517, 1777, 4171, 10161, 18369, 23233, 83005, 75519}},
-{19053, 18, 95149, {1, 3, 7, 9, 3, 9, 69, 111, 135, 351, 971, 3551, 3739, 3571, 22861, 62669, 83723, 10707}},
-{19054, 18, 95150, {1, 3, 3, 5, 31, 35, 103, 205, 321, 553, 409, 363, 4085, 7735, 5513, 64249, 127883, 147839}},
-{19055, 18, 95167, {1, 1, 7, 3, 23, 35, 85, 231, 251, 237, 421, 757, 7081, 11247, 24941, 22649, 51111, 157383}},
-{19056, 18, 95175, {1, 3, 7, 5, 23, 35, 7, 101, 491, 529, 1437, 489, 5057, 12955, 27543, 60903, 104151, 42545}},
-{19057, 18, 95205, {1, 1, 3, 15, 23, 53, 85, 89, 247, 269, 1555, 3789, 467, 11145, 11751, 44343, 120117, 9975}},
-{19058, 18, 95229, {1, 1, 5, 3, 29, 49, 123, 179, 311, 45, 1839, 2725, 7307, 5525, 32075, 7979, 107751, 133677}},
-{19059, 18, 95321, {1, 1, 5, 3, 31, 21, 65, 229, 31, 597, 755, 2653, 2699, 2075, 11693, 28953, 55811, 13653}},
-{19060, 18, 95345, {1, 1, 1, 7, 25, 51, 119, 21, 245, 493, 407, 2997, 4255, 15487, 26359, 24153, 42955, 142191}},
-{19061, 18, 95364, {1, 1, 5, 3, 27, 61, 13, 209, 13, 401, 399, 2909, 3623, 8057, 21301, 32273, 112127, 210221}},
-{19062, 18, 95379, {1, 3, 5, 13, 3, 19, 121, 19, 57, 583, 947, 3591, 5283, 10831, 20429, 54097, 7559, 112465}},
-{19063, 18, 95386, {1, 3, 5, 1, 21, 1, 125, 245, 217, 165, 1319, 2119, 4641, 9481, 4147, 7079, 119015, 128401}},
-{19064, 18, 95395, {1, 1, 5, 3, 3, 31, 25, 63, 17, 191, 497, 819, 1515, 11215, 24961, 7679, 125801, 239521}},
-{19065, 18, 95416, {1, 1, 5, 1, 3, 25, 27, 43, 37, 863, 739, 2585, 773, 799, 17649, 21171, 123541, 164777}},
-{19066, 18, 95419, {1, 3, 5, 7, 7, 25, 15, 251, 305, 159, 1941, 3655, 2881, 15123, 10911, 35541, 62221, 175845}},
-{19067, 18, 95433, {1, 1, 1, 9, 19, 5, 103, 1, 417, 951, 139, 2413, 2983, 15471, 9495, 41349, 110175, 29501}},
-{19068, 18, 95464, {1, 1, 1, 5, 29, 53, 95, 173, 211, 803, 1599, 4093, 5559, 15855, 12271, 12583, 102221, 203453}},
-{19069, 18, 95490, {1, 3, 5, 5, 19, 43, 31, 175, 493, 289, 1865, 2925, 3833, 11327, 23337, 62669, 99485, 230583}},
-{19070, 18, 95496, {1, 3, 3, 11, 11, 25, 95, 215, 501, 421, 725, 1571, 2133, 2761, 8649, 45359, 88851, 55057}},
-{19071, 18, 95504, {1, 1, 7, 7, 21, 45, 69, 63, 399, 929, 1431, 3397, 3613, 14595, 10417, 62913, 106283, 120869}},
-{19072, 18, 95513, {1, 3, 7, 15, 13, 45, 11, 177, 125, 611, 1115, 2441, 2689, 12517, 8989, 34991, 23789, 51543}},
-{19073, 18, 95523, {1, 1, 3, 1, 3, 15, 5, 125, 511, 137, 1919, 2953, 5267, 3543, 5485, 7463, 130407, 255945}},
-{19074, 18, 95525, {1, 1, 3, 7, 7, 21, 95, 97, 51, 91, 813, 2819, 2839, 12041, 26197, 20143, 51403, 171337}},
-{19075, 18, 95558, {1, 1, 1, 1, 7, 27, 15, 125, 441, 387, 1869, 2157, 5863, 581, 893, 58827, 104063, 93735}},
-{19076, 18, 95572, {1, 3, 3, 7, 27, 9, 79, 97, 465, 207, 931, 2809, 2225, 13749, 18819, 30605, 9829, 130743}},
-{19077, 18, 95591, {1, 3, 5, 13, 31, 41, 19, 147, 293, 725, 297, 397, 1343, 12669, 15339, 58599, 12113, 149835}},
-{19078, 18, 95609, {1, 3, 3, 13, 27, 13, 121, 253, 349, 229, 915, 1673, 3819, 77, 20691, 53823, 78265, 138743}},
-{19079, 18, 95619, {1, 1, 5, 5, 29, 41, 65, 235, 123, 871, 1809, 3013, 3531, 1551, 8441, 23481, 58729, 117639}},
-{19080, 18, 95625, {1, 1, 7, 5, 23, 55, 89, 81, 201, 313, 1307, 2427, 2025, 8543, 26631, 58655, 122095, 247579}},
-{19081, 18, 95633, {1, 3, 1, 5, 3, 63, 89, 219, 449, 9, 1771, 2915, 5925, 13773, 26119, 61309, 65107, 33001}},
-{19082, 18, 95649, {1, 3, 7, 1, 27, 11, 25, 221, 139, 665, 1543, 2157, 7617, 9135, 567, 64985, 88749, 54223}},
-{19083, 18, 95652, {1, 1, 3, 9, 13, 41, 7, 99, 483, 115, 1499, 3343, 7207, 1805, 16031, 63707, 8555, 90959}},
-{19084, 18, 95655, {1, 3, 1, 9, 15, 53, 41, 239, 295, 47, 1645, 1095, 5163, 7739, 26635, 28245, 9315, 100629}},
-{19085, 18, 95696, {1, 3, 1, 5, 1, 19, 69, 5, 171, 669, 673, 633, 6895, 7571, 11539, 25133, 99235, 7991}},
-{19086, 18, 95721, {1, 3, 5, 11, 21, 37, 63, 77, 281, 307, 1711, 2671, 1315, 14683, 28757, 22751, 56477, 190805}},
-{19087, 18, 95766, {1, 3, 3, 5, 15, 1, 5, 21, 199, 161, 655, 1263, 3315, 16051, 2409, 773, 9075, 121265}},
-{19088, 18, 95772, {1, 3, 3, 3, 7, 23, 71, 195, 11, 263, 1845, 165, 3489, 447, 11315, 23861, 110949, 78909}},
-{19089, 18, 95775, {1, 1, 7, 5, 1, 53, 37, 9, 439, 135, 909, 457, 6993, 11401, 14065, 30795, 56149, 168013}},
-{19090, 18, 95794, {1, 1, 1, 15, 23, 37, 13, 87, 113, 251, 233, 725, 7757, 14399, 3023, 54277, 87879, 54053}},
-{19091, 18, 95796, {1, 3, 5, 11, 11, 57, 109, 171, 171, 17, 343, 2749, 6525, 9735, 11715, 23783, 54439, 82819}},
-{19092, 18, 95818, {1, 1, 1, 15, 3, 47, 73, 237, 399, 301, 947, 2055, 1909, 14105, 26893, 47805, 25, 172957}},
-{19093, 18, 95820, {1, 1, 7, 7, 11, 27, 93, 167, 117, 637, 351, 319, 4605, 12897, 31001, 39655, 53551, 246113}},
-{19094, 18, 95832, {1, 3, 5, 15, 3, 37, 25, 9, 421, 519, 257, 3251, 1649, 4069, 999, 59367, 112383, 32095}},
-{19095, 18, 95842, {1, 3, 7, 7, 25, 57, 11, 37, 271, 545, 1213, 1927, 6471, 5145, 22995, 51051, 126981, 260457}},
-{19096, 18, 95851, {1, 3, 5, 11, 1, 61, 77, 201, 395, 199, 477, 103, 4069, 7003, 26371, 49145, 103839, 195661}},
-{19097, 18, 95854, {1, 3, 3, 9, 13, 41, 25, 125, 161, 371, 179, 351, 7169, 7179, 21627, 57793, 104679, 158583}},
-{19098, 18, 95859, {1, 3, 7, 11, 5, 7, 111, 163, 201, 783, 189, 273, 2751, 13917, 28501, 18261, 12755, 15521}},
-{19099, 18, 95868, {1, 1, 5, 7, 3, 37, 121, 209, 503, 299, 1301, 3703, 2321, 99, 14953, 28087, 85059, 256911}},
-{19100, 18, 95881, {1, 3, 3, 13, 3, 29, 95, 249, 383, 971, 1291, 13, 1587, 3447, 26477, 15837, 111141, 73899}},
-{19101, 18, 95895, {1, 1, 7, 1, 17, 57, 31, 1, 219, 329, 19, 3841, 1829, 5179, 14945, 6625, 3783, 200583}},
-{19102, 18, 95943, {1, 3, 1, 3, 1, 31, 23, 17, 209, 383, 297, 3065, 4323, 7847, 30189, 56541, 57535, 24853}},
-{19103, 18, 95949, {1, 1, 3, 11, 31, 35, 125, 141, 251, 79, 161, 775, 2455, 6959, 26433, 39145, 26563, 665}},
-{19104, 18, 95978, {1, 1, 7, 1, 11, 9, 9, 211, 231, 723, 1337, 1713, 3779, 2001, 23451, 27107, 64297, 254943}},
-{19105, 18, 95980, {1, 3, 7, 15, 21, 55, 19, 159, 449, 837, 1259, 1851, 5061, 355, 21531, 63479, 114657, 139265}},
-{19106, 18, 96010, {1, 1, 1, 3, 11, 55, 103, 179, 363, 567, 421, 981, 7221, 2077, 19339, 1155, 67019, 218231}},
-{19107, 18, 96020, {1, 1, 7, 11, 3, 43, 55, 161, 347, 995, 1555, 3251, 1605, 13313, 4499, 19361, 60145, 71593}},
-{19108, 18, 96024, {1, 1, 5, 3, 9, 15, 119, 213, 455, 241, 857, 683, 1247, 13085, 23919, 20365, 16303, 73263}},
-{19109, 18, 96063, {1, 1, 3, 13, 25, 17, 45, 193, 375, 289, 1381, 3629, 3015, 15883, 20633, 7431, 108787, 233297}},
-{19110, 18, 96108, {1, 1, 1, 15, 21, 57, 105, 91, 233, 961, 1623, 3849, 711, 3857, 32657, 5935, 85113, 38287}},
-{19111, 18, 96125, {1, 3, 3, 3, 15, 31, 97, 217, 335, 385, 1661, 3927, 6849, 137, 28871, 56485, 32777, 260033}},
-{19112, 18, 96154, {1, 1, 3, 13, 5, 61, 19, 255, 123, 481, 1865, 1815, 3047, 173, 25363, 1277, 6453, 174405}},
-{19113, 18, 96172, {1, 3, 7, 13, 27, 9, 19, 21, 433, 857, 1931, 2927, 629, 7733, 13503, 48263, 67517, 26495}},
-{19114, 18, 96189, {1, 1, 1, 3, 5, 43, 61, 239, 81, 585, 187, 1123, 3319, 8699, 20925, 40815, 76575, 169383}},
-{19115, 18, 96204, {1, 3, 3, 3, 9, 49, 71, 225, 95, 365, 645, 237, 7829, 5727, 17031, 58971, 71415, 232423}},
-{19116, 18, 96219, {1, 3, 5, 9, 25, 49, 113, 47, 105, 609, 1557, 2099, 2129, 8663, 24811, 25505, 38153, 185821}},
-{19117, 18, 96256, {1, 3, 5, 13, 23, 55, 107, 17, 309, 807, 635, 1007, 6207, 3363, 7607, 25013, 4141, 171509}},
-{19118, 18, 96261, {1, 1, 1, 13, 27, 35, 31, 89, 109, 879, 1845, 3999, 5415, 8777, 9605, 29703, 28149, 36469}},
-{19119, 18, 96289, {1, 3, 1, 3, 13, 3, 51, 31, 479, 549, 1245, 2033, 961, 13893, 21829, 32791, 109497, 187425}},
-{19120, 18, 96292, {1, 1, 5, 3, 19, 5, 25, 187, 173, 869, 201, 3851, 7369, 6229, 16577, 45623, 19859, 209855}},
-{19121, 18, 96296, {1, 1, 7, 9, 1, 9, 53, 47, 289, 557, 999, 141, 3789, 3087, 30217, 24221, 81431, 157507}},
-{19122, 18, 96324, {1, 1, 3, 9, 1, 25, 11, 73, 155, 155, 621, 4047, 6759, 5641, 28147, 8523, 69439, 92613}},
-{19123, 18, 96345, {1, 3, 1, 5, 25, 23, 41, 79, 71, 793, 1381, 307, 7863, 16289, 28783, 5299, 128481, 222799}},
-{19124, 18, 96346, {1, 1, 7, 1, 17, 33, 117, 111, 15, 249, 1397, 1349, 4883, 6009, 3179, 33509, 56355, 31937}},
-{19125, 18, 96358, {1, 3, 5, 13, 29, 15, 41, 185, 91, 501, 571, 2889, 6901, 3875, 3737, 23657, 101587, 261181}},
-{19126, 18, 96386, {1, 1, 7, 9, 21, 49, 33, 143, 19, 203, 75, 1353, 585, 7719, 11311, 48989, 10803, 51743}},
-{19127, 18, 96412, {1, 1, 7, 13, 23, 31, 103, 209, 375, 817, 1461, 3657, 7931, 15893, 15065, 28721, 54299, 71147}},
-{19128, 18, 96428, {1, 3, 7, 7, 7, 25, 37, 173, 355, 499, 247, 459, 7701, 2219, 11703, 20631, 128857, 125367}},
-{19129, 18, 96445, {1, 1, 3, 5, 25, 61, 43, 135, 451, 667, 547, 443, 5071, 12671, 26975, 20131, 101545, 115281}},
-{19130, 18, 96446, {1, 3, 3, 5, 9, 19, 75, 133, 211, 585, 1283, 3397, 3181, 65, 20213, 47725, 101883, 194749}},
-{19131, 18, 96448, {1, 1, 1, 1, 19, 13, 75, 135, 111, 641, 765, 1631, 4711, 241, 15125, 38233, 95535, 177965}},
-{19132, 18, 96458, {1, 1, 7, 13, 31, 1, 91, 61, 299, 35, 1327, 3903, 6193, 5589, 6331, 6321, 105741, 89639}},
-{19133, 18, 96475, {1, 3, 3, 15, 1, 55, 11, 39, 171, 713, 973, 1827, 3487, 13057, 30775, 16881, 124989, 208193}},
-{19134, 18, 96482, {1, 3, 7, 1, 21, 29, 19, 75, 397, 755, 1601, 2907, 6861, 10377, 23127, 2443, 86545, 3841}},
-{19135, 18, 96494, {1, 3, 1, 11, 25, 33, 53, 195, 343, 425, 1523, 3051, 3115, 3205, 3457, 20521, 39187, 33307}},
-{19136, 18, 96502, {1, 3, 5, 1, 25, 23, 47, 5, 133, 511, 1549, 2691, 7861, 4987, 2877, 38693, 37491, 22481}},
-{19137, 18, 96508, {1, 1, 5, 15, 5, 55, 125, 231, 11, 451, 1443, 3865, 4115, 2379, 13675, 29953, 85721, 114859}},
-{19138, 18, 96511, {1, 3, 1, 15, 19, 37, 29, 75, 483, 785, 1933, 2435, 1811, 2787, 32653, 23159, 80993, 26867}},
-{19139, 18, 96516, {1, 1, 1, 15, 7, 27, 53, 99, 11, 693, 1085, 743, 939, 6461, 6391, 45913, 94037, 217039}},
-{19140, 18, 96520, {1, 3, 3, 9, 19, 37, 93, 77, 363, 125, 1675, 347, 5599, 7771, 23549, 39945, 106931, 127959}},
-{19141, 18, 96547, {1, 3, 1, 5, 27, 47, 107, 85, 31, 621, 1529, 2349, 7055, 889, 4663, 1705, 40011, 214775}},
-{19142, 18, 96556, {1, 3, 1, 5, 11, 47, 35, 13, 139, 783, 1009, 845, 4139, 14713, 24191, 17597, 124923, 219657}},
-{19143, 18, 96561, {1, 1, 7, 3, 3, 25, 63, 207, 361, 587, 763, 3027, 6523, 6783, 11203, 57313, 115397, 149921}},
-{19144, 18, 96568, {1, 1, 7, 1, 21, 55, 109, 183, 487, 869, 195, 83, 3675, 13103, 12383, 63519, 48379, 256443}},
-{19145, 18, 96581, {1, 3, 7, 13, 9, 21, 29, 163, 105, 871, 747, 2459, 7383, 439, 5223, 1655, 1469, 50345}},
-{19146, 18, 96582, {1, 3, 1, 1, 15, 63, 37, 159, 385, 795, 1369, 1973, 6119, 6027, 23913, 52475, 80827, 198261}},
-{19147, 18, 96679, {1, 3, 3, 11, 15, 5, 121, 231, 43, 907, 1621, 3895, 5075, 10865, 3123, 49657, 69827, 215813}},
-{19148, 18, 96683, {1, 3, 1, 15, 7, 41, 75, 105, 87, 899, 629, 1699, 5861, 9279, 30107, 37443, 7555, 64461}},
-{19149, 18, 96717, {1, 3, 1, 7, 9, 15, 119, 127, 121, 621, 1117, 1659, 605, 13705, 31181, 40063, 17257, 77645}},
-{19150, 18, 96754, {1, 1, 5, 5, 3, 37, 95, 237, 379, 375, 903, 257, 4425, 14191, 9185, 57133, 82067, 73521}},
-{19151, 18, 96769, {1, 1, 7, 15, 1, 43, 63, 45, 121, 669, 1775, 179, 7385, 3557, 17261, 379, 24759, 214831}},
-{19152, 18, 96799, {1, 1, 3, 9, 31, 5, 43, 153, 451, 573, 1623, 2831, 4483, 7219, 27657, 47111, 58165, 145799}},
-{19153, 18, 96805, {1, 1, 3, 11, 3, 11, 111, 83, 329, 807, 779, 1223, 6095, 7269, 22425, 19343, 11937, 10173}},
-{19154, 18, 96809, {1, 1, 1, 13, 27, 15, 7, 111, 37, 663, 51, 3759, 6321, 8253, 737, 59501, 109595, 177827}},
-{19155, 18, 96823, {1, 1, 3, 3, 29, 39, 79, 115, 307, 765, 331, 377, 1873, 14491, 11065, 11865, 76717, 29101}},
-{19156, 18, 96829, {1, 3, 7, 3, 21, 45, 97, 213, 309, 3, 483, 3933, 1043, 8519, 22517, 34675, 78819, 172479}},
-{19157, 18, 96832, {1, 3, 5, 3, 31, 51, 27, 137, 405, 427, 815, 43, 6551, 10971, 28589, 53077, 36639, 167661}},
-{19158, 18, 96850, {1, 3, 1, 3, 29, 5, 111, 19, 343, 21, 557, 4067, 1525, 12793, 11513, 48869, 78035, 171531}},
-{19159, 18, 96856, {1, 1, 5, 7, 25, 47, 53, 245, 135, 137, 1697, 2057, 3147, 15903, 26979, 2157, 43967, 207661}},
-{19160, 18, 96906, {1, 1, 5, 3, 25, 11, 15, 59, 511, 307, 757, 3275, 1299, 10373, 11943, 54169, 32417, 21645}},
-{19161, 18, 96962, {1, 3, 3, 11, 15, 15, 5, 137, 237, 741, 1613, 3565, 7359, 6181, 25953, 18137, 59759, 186693}},
-{19162, 18, 96974, {1, 3, 5, 3, 19, 13, 99, 167, 45, 71, 1683, 3635, 7603, 14879, 23903, 14795, 58395, 11853}},
-{19163, 18, 96979, {1, 3, 1, 7, 15, 45, 111, 111, 175, 567, 1031, 2255, 3895, 11861, 20195, 15461, 88411, 225713}},
-{19164, 18, 96997, {1, 1, 7, 3, 5, 5, 85, 65, 231, 643, 1591, 219, 2929, 4845, 29327, 14769, 46629, 131367}},
-{19165, 18, 96998, {1, 1, 5, 9, 29, 21, 47, 87, 113, 469, 1647, 2461, 3663, 5865, 6647, 41345, 39539, 220301}},
-{19166, 18, 97002, {1, 1, 5, 11, 9, 55, 5, 147, 141, 181, 283, 1695, 6537, 11095, 10385, 36013, 111653, 182273}},
-{19167, 18, 97054, {1, 1, 3, 5, 17, 45, 103, 253, 407, 151, 1585, 1585, 6661, 14579, 5723, 37641, 56813, 258819}},
-{19168, 18, 97064, {1, 3, 3, 3, 5, 63, 85, 201, 87, 419, 1993, 737, 5859, 6049, 17393, 9453, 65915, 1731}},
-{19169, 18, 97067, {1, 1, 3, 3, 3, 27, 97, 135, 137, 731, 1559, 3409, 5973, 15981, 19833, 8419, 33273, 44155}},
-{19170, 18, 97110, {1, 3, 3, 9, 31, 55, 109, 191, 119, 59, 645, 1047, 7767, 8379, 13781, 52289, 31605, 186667}},
-{19171, 18, 97116, {1, 3, 1, 15, 9, 1, 23, 31, 23, 311, 1879, 1939, 5509, 14573, 10501, 38867, 39131, 231151}},
-{19172, 18, 97137, {1, 3, 7, 1, 31, 33, 33, 19, 475, 723, 795, 1793, 6639, 14349, 16639, 31473, 110411, 95703}},
-{19173, 18, 97138, {1, 1, 5, 9, 11, 3, 39, 119, 455, 839, 513, 2423, 2219, 6059, 6125, 60995, 117701, 204057}},
-{19174, 18, 97143, {1, 1, 1, 9, 5, 23, 87, 33, 59, 241, 1427, 3867, 1091, 14683, 21651, 7091, 38011, 63809}},
-{19175, 18, 97183, {1, 1, 7, 15, 15, 23, 75, 227, 415, 1015, 2033, 1311, 6659, 5093, 14799, 65331, 96989, 170395}},
-{19176, 18, 97187, {1, 3, 5, 15, 25, 61, 33, 179, 503, 875, 1853, 257, 6727, 9117, 16777, 29585, 110901, 231617}},
-{19177, 18, 97190, {1, 1, 1, 15, 13, 53, 73, 151, 315, 887, 669, 3959, 5279, 1461, 15497, 40107, 9595, 252059}},
-{19178, 18, 97202, {1, 3, 7, 13, 17, 45, 43, 61, 99, 555, 981, 3255, 6385, 8723, 24451, 45243, 68617, 171911}},
-{19179, 18, 97219, {1, 3, 3, 11, 1, 29, 97, 219, 341, 597, 503, 773, 3777, 5431, 4581, 37169, 57269, 186377}},
-{19180, 18, 97239, {1, 3, 1, 11, 15, 49, 119, 189, 279, 821, 1541, 1343, 4379, 5833, 26537, 29769, 121125, 202553}},
-{19181, 18, 97245, {1, 3, 5, 9, 19, 23, 5, 197, 323, 101, 1155, 7, 5933, 3111, 19595, 36807, 40147, 153}},
-{19182, 18, 97246, {1, 1, 5, 11, 17, 9, 83, 51, 185, 415, 367, 1431, 7803, 8253, 16283, 54545, 99733, 57777}},
-{19183, 18, 97249, {1, 1, 5, 7, 5, 31, 41, 13, 33, 531, 1381, 781, 1699, 6321, 18125, 34567, 113253, 104181}},
-{19184, 18, 97264, {1, 3, 1, 5, 1, 59, 37, 239, 343, 395, 121, 2181, 2485, 13825, 19127, 22689, 103023, 198213}},
-{19185, 18, 97267, {1, 3, 1, 15, 29, 17, 11, 27, 413, 273, 1805, 2845, 8147, 10301, 5423, 29859, 85243, 190379}},
-{19186, 18, 97269, {1, 3, 1, 15, 7, 61, 29, 135, 273, 951, 725, 1345, 4231, 13651, 31291, 6081, 85735, 96023}},
-{19187, 18, 97274, {1, 1, 3, 11, 15, 29, 81, 129, 245, 295, 527, 3905, 4323, 5447, 21253, 51177, 105105, 48323}},
-{19188, 18, 97282, {1, 1, 3, 13, 13, 45, 71, 43, 383, 95, 1689, 639, 4631, 15113, 28053, 49247, 128303, 183999}},
-{19189, 18, 97287, {1, 1, 1, 3, 19, 31, 93, 35, 369, 765, 1201, 1625, 7683, 8719, 13843, 42723, 62323, 49431}},
-{19190, 18, 97294, {1, 3, 3, 11, 5, 39, 49, 217, 109, 63, 1753, 2489, 6017, 403, 16657, 59577, 80255, 66071}},
-{19191, 18, 97299, {1, 3, 5, 5, 11, 1, 79, 37, 261, 537, 1845, 3567, 3233, 16249, 9795, 2471, 69661, 118231}},
-{19192, 18, 97306, {1, 3, 3, 1, 19, 61, 35, 253, 31, 19, 161, 2597, 5733, 8231, 26569, 38613, 121945, 137391}},
-{19193, 18, 97347, {1, 3, 7, 3, 15, 25, 125, 231, 187, 797, 1237, 1767, 1557, 1095, 13613, 43325, 33801, 127881}},
-{19194, 18, 97361, {1, 1, 1, 9, 23, 63, 75, 107, 311, 493, 471, 2985, 1861, 4285, 27125, 14961, 122567, 152033}},
-{19195, 18, 97371, {1, 3, 5, 7, 9, 7, 43, 117, 203, 727, 101, 3831, 3201, 2327, 4675, 12085, 25131, 211835}},
-{19196, 18, 97435, {1, 1, 7, 11, 17, 1, 5, 87, 291, 1023, 1345, 3879, 7739, 9201, 19573, 20037, 128711, 187263}},
-{19197, 18, 97466, {1, 1, 3, 13, 25, 39, 71, 251, 365, 617, 1539, 2121, 3803, 8003, 23393, 56991, 56143, 223453}},
-{19198, 18, 97473, {1, 3, 5, 13, 25, 61, 71, 139, 319, 399, 903, 3063, 3667, 275, 13297, 25285, 120417, 169613}},
-{19199, 18, 97474, {1, 3, 1, 9, 9, 41, 59, 213, 195, 705, 313, 2313, 4993, 323, 24049, 30527, 27287, 80489}},
-{19200, 18, 97559, {1, 1, 5, 1, 29, 57, 107, 161, 217, 295, 721, 3857, 1935, 14981, 12243, 38541, 51177, 248889}},
-{19201, 18, 97565, {1, 1, 1, 15, 5, 25, 95, 137, 11, 215, 971, 1573, 4341, 4725, 8201, 33147, 87687, 187405}},
-{19202, 18, 97587, {1, 3, 3, 9, 9, 13, 31, 3, 175, 309, 145, 2265, 4863, 7199, 23881, 15445, 123753, 126653}},
-{19203, 18, 97611, {1, 1, 7, 3, 7, 43, 51, 191, 21, 639, 939, 691, 7823, 10529, 7757, 9291, 115045, 51539}},
-{19204, 18, 97622, {1, 1, 7, 13, 7, 45, 91, 173, 73, 779, 1647, 2059, 1373, 16027, 4611, 45787, 699, 78905}},
-{19205, 18, 97625, {1, 1, 5, 15, 5, 23, 123, 45, 265, 1009, 235, 1343, 5779, 209, 23263, 63163, 26079, 240905}},
-{19206, 18, 97632, {1, 1, 1, 11, 19, 31, 75, 105, 71, 21, 1361, 2125, 6949, 2111, 10333, 61881, 112811, 85723}},
-{19207, 18, 97635, {1, 3, 5, 7, 27, 17, 95, 35, 503, 181, 1885, 1097, 6019, 13745, 15009, 26343, 117727, 93017}},
-{19208, 18, 97652, {1, 1, 3, 11, 27, 41, 109, 23, 365, 283, 1509, 3269, 5969, 14567, 27715, 429, 65813, 169391}},
-{19209, 18, 97672, {1, 1, 5, 9, 11, 1, 23, 143, 401, 61, 993, 3029, 1901, 12947, 10439, 48661, 113863, 9353}},
-{19210, 18, 97678, {1, 3, 7, 3, 15, 27, 123, 51, 403, 569, 75, 3837, 8167, 10875, 29861, 44133, 52385, 185515}},
-{19211, 18, 97683, {1, 3, 3, 15, 15, 45, 3, 77, 439, 265, 103, 3715, 7889, 9241, 26511, 19063, 108239, 237233}},
-{19212, 18, 97695, {1, 1, 5, 13, 7, 47, 7, 185, 155, 833, 1895, 1103, 6761, 4307, 19551, 2371, 41079, 207663}},
-{19213, 18, 97705, {1, 1, 3, 7, 1, 49, 79, 127, 149, 383, 919, 3787, 6703, 8823, 15551, 28397, 11497, 144227}},
-{19214, 18, 97713, {1, 1, 7, 15, 7, 5, 9, 161, 425, 275, 1943, 3003, 3615, 1417, 587, 20949, 9651, 101257}},
-{19215, 18, 97719, {1, 3, 5, 11, 31, 11, 113, 201, 113, 889, 867, 3537, 7173, 3403, 4713, 29709, 50127, 55893}},
-{19216, 18, 97757, {1, 3, 7, 11, 11, 17, 123, 97, 3, 1009, 1567, 3261, 8053, 4639, 24493, 64085, 73975, 123965}},
-{19217, 18, 97761, {1, 1, 7, 1, 31, 7, 111, 137, 427, 615, 865, 2243, 3603, 5943, 1639, 22213, 81977, 77283}},
-{19218, 18, 97762, {1, 1, 5, 11, 25, 63, 5, 19, 67, 469, 621, 2831, 1635, 11859, 23143, 29189, 43955, 87475}},
-{19219, 18, 97771, {1, 3, 7, 15, 7, 61, 125, 207, 401, 567, 1943, 2645, 641, 15427, 24467, 41767, 122591, 48905}},
-{19220, 18, 97795, {1, 3, 3, 5, 1, 61, 65, 169, 329, 489, 435, 1719, 491, 6189, 18383, 34973, 90611, 180991}},
-{19221, 18, 97809, {1, 3, 7, 9, 25, 43, 115, 11, 289, 193, 263, 3885, 4881, 15669, 19757, 20073, 119873, 67069}},
-{19222, 18, 97826, {1, 1, 7, 11, 3, 45, 93, 115, 233, 891, 1541, 2557, 2115, 2237, 4253, 30445, 32983, 86185}},
-{19223, 18, 97845, {1, 3, 7, 3, 29, 23, 105, 51, 157, 505, 773, 2403, 1237, 5193, 32725, 53331, 66377, 25745}},
-{19224, 18, 97877, {1, 3, 5, 11, 31, 5, 111, 251, 287, 225, 913, 97, 3429, 15111, 10637, 18843, 102589, 229667}},
-{19225, 18, 97882, {1, 3, 7, 13, 21, 43, 27, 11, 265, 991, 1645, 1967, 2675, 3083, 2957, 65275, 7757, 201953}},
-{19226, 18, 97891, {1, 3, 7, 7, 23, 59, 37, 105, 113, 961, 1585, 855, 6037, 8461, 24057, 46861, 42421, 21061}},
-{19227, 18, 97903, {1, 1, 5, 1, 7, 45, 37, 147, 225, 793, 737, 753, 565, 5347, 15393, 42611, 39253, 246455}},
-{19228, 18, 97961, {1, 3, 3, 5, 29, 59, 125, 69, 283, 677, 1615, 3341, 219, 10753, 445, 43343, 117035, 137907}},
-{19229, 18, 97970, {1, 1, 5, 1, 19, 41, 93, 137, 481, 93, 703, 1211, 4051, 5591, 5913, 32831, 62027, 60519}},
-{19230, 18, 97975, {1, 1, 7, 13, 17, 63, 65, 147, 361, 83, 1383, 1761, 579, 9493, 2611, 6951, 12197, 81857}},
-{19231, 18, 97996, {1, 3, 3, 15, 11, 3, 25, 7, 221, 211, 1745, 1173, 5479, 12063, 5667, 43443, 4865, 193345}},
-{19232, 18, 98001, {1, 1, 5, 11, 31, 11, 71, 61, 57, 851, 1089, 1395, 4525, 1223, 27681, 14355, 23125, 257233}},
-{19233, 18, 98014, {1, 3, 1, 11, 25, 59, 17, 193, 229, 1005, 387, 3993, 2457, 4185, 18421, 1315, 125155, 142277}},
-{19234, 18, 98023, {1, 1, 5, 11, 13, 55, 123, 191, 5, 1023, 705, 3481, 367, 12961, 11917, 12131, 99109, 105093}},
-{19235, 18, 98035, {1, 1, 3, 11, 13, 29, 57, 57, 467, 19, 1409, 971, 3041, 13487, 24737, 3377, 97883, 248893}},
-{19236, 18, 98052, {1, 3, 7, 3, 3, 37, 109, 77, 201, 469, 39, 1747, 2027, 14781, 18821, 34647, 123865, 195097}},
-{19237, 18, 98059, {1, 3, 3, 5, 29, 27, 97, 217, 249, 141, 431, 1621, 539, 8945, 3443, 48227, 27867, 205355}},
-{19238, 18, 98061, {1, 1, 3, 13, 7, 57, 65, 167, 103, 511, 239, 325, 1793, 2811, 14223, 40999, 12589, 149759}},
-{19239, 18, 98086, {1, 3, 5, 11, 3, 1, 61, 87, 283, 29, 507, 3473, 2685, 13829, 32337, 8413, 12201, 152309}},
-{19240, 18, 98098, {1, 3, 5, 15, 1, 23, 103, 173, 423, 915, 1519, 1859, 7341, 8689, 17141, 53769, 81189, 144305}},
-{19241, 18, 98117, {1, 1, 1, 5, 31, 41, 89, 117, 329, 245, 381, 3357, 1053, 15079, 3569, 27665, 65645, 259279}},
-{19242, 18, 98118, {1, 1, 7, 5, 3, 55, 91, 35, 463, 15, 1195, 533, 6013, 10755, 1919, 61169, 81285, 82757}},
-{19243, 18, 98132, {1, 3, 5, 11, 3, 29, 85, 169, 163, 733, 939, 3401, 3709, 3307, 17329, 56873, 10721, 174235}},
-{19244, 18, 98135, {1, 1, 5, 1, 11, 45, 75, 247, 435, 21, 1985, 2261, 7013, 4935, 2457, 41077, 53121, 143269}},
-{19245, 18, 98145, {1, 3, 3, 13, 17, 59, 43, 149, 27, 1, 367, 957, 5607, 2591, 22161, 10095, 73769, 52455}},
-{19246, 18, 98160, {1, 1, 3, 13, 15, 15, 121, 83, 469, 819, 1973, 3595, 2313, 1621, 3105, 42971, 7243, 98727}},
-{19247, 18, 98194, {1, 1, 5, 7, 21, 53, 123, 9, 119, 437, 1567, 431, 3647, 10967, 22037, 8523, 81279, 126473}},
-{19248, 18, 98205, {1, 1, 5, 13, 5, 23, 125, 119, 195, 555, 341, 2037, 313, 6323, 27201, 8377, 122793, 197781}},
-{19249, 18, 98210, {1, 3, 3, 5, 17, 25, 67, 237, 349, 443, 1529, 3541, 3105, 10105, 13409, 20165, 64597, 244513}},
-{19250, 18, 98224, {1, 1, 5, 1, 11, 43, 77, 245, 359, 625, 1171, 597, 3, 591, 2457, 20275, 75995, 204685}},
-{19251, 18, 98227, {1, 3, 1, 11, 5, 13, 99, 107, 285, 617, 1687, 2959, 4439, 771, 3103, 62363, 89437, 172221}},
-{19252, 18, 98254, {1, 3, 1, 11, 1, 63, 43, 85, 23, 95, 501, 1223, 669, 16101, 1071, 53175, 102101, 419}},
-{19253, 18, 98271, {1, 3, 1, 5, 19, 23, 63, 105, 289, 419, 885, 441, 5107, 4213, 8683, 1847, 113301, 240821}},
-{19254, 18, 98272, {1, 1, 1, 9, 9, 9, 111, 63, 53, 531, 517, 3463, 8171, 2645, 13883, 52213, 40707, 24637}},
-{19255, 18, 98302, {1, 3, 1, 5, 15, 43, 71, 215, 117, 685, 1819, 1105, 5805, 8875, 31093, 31077, 93807, 65631}},
-{19256, 18, 98320, {1, 1, 7, 7, 17, 15, 31, 87, 13, 615, 2003, 3461, 7585, 1947, 6693, 26141, 95059, 52229}},
-{19257, 18, 98346, {1, 1, 3, 5, 5, 55, 7, 41, 473, 541, 545, 2901, 763, 12731, 24715, 43301, 7981, 123961}},
-{19258, 18, 98356, {1, 3, 1, 11, 13, 29, 65, 47, 511, 931, 1681, 3813, 995, 4261, 32243, 21327, 33749, 52607}},
-{19259, 18, 98360, {1, 1, 3, 1, 27, 51, 19, 119, 71, 989, 485, 1483, 4115, 11743, 5513, 32447, 62599, 163185}},
-{19260, 18, 98366, {1, 3, 7, 13, 7, 5, 127, 67, 221, 773, 1641, 3763, 2061, 2025, 29813, 64385, 109219, 70149}},
-{19261, 18, 98478, {1, 1, 5, 15, 9, 29, 105, 245, 333, 11, 803, 1877, 6735, 3797, 1913, 63837, 23649, 234721}},
-{19262, 18, 98483, {1, 3, 7, 13, 11, 21, 113, 175, 385, 885, 1259, 983, 7715, 11889, 12515, 35723, 9897, 63415}},
-{19263, 18, 98486, {1, 1, 5, 9, 31, 63, 53, 51, 375, 133, 2021, 3173, 3861, 9885, 4117, 37505, 73687, 16411}},
-{19264, 18, 98497, {1, 3, 7, 7, 11, 13, 99, 235, 285, 159, 489, 917, 3033, 7711, 6545, 52893, 28549, 68791}},
-{19265, 18, 98528, {1, 1, 5, 11, 31, 15, 89, 157, 105, 347, 455, 3391, 5341, 16035, 11819, 57679, 48057, 147673}},
-{19266, 18, 98537, {1, 3, 1, 5, 21, 5, 1, 41, 213, 677, 1745, 2591, 6237, 14265, 5963, 30017, 47293, 199411}},
-{19267, 18, 98551, {1, 3, 1, 15, 19, 9, 65, 103, 489, 977, 579, 2571, 2827, 12971, 24445, 17963, 68829, 89781}},
-{19268, 18, 98557, {1, 3, 5, 7, 3, 45, 9, 223, 137, 749, 919, 2695, 7569, 6735, 16649, 55899, 91531, 10709}},
-{19269, 18, 98572, {1, 1, 5, 11, 25, 51, 81, 243, 473, 85, 1189, 2317, 785, 9307, 25555, 36623, 66881, 150945}},
-{19270, 18, 98575, {1, 1, 3, 7, 9, 17, 99, 57, 333, 891, 71, 2359, 2067, 13265, 30077, 17935, 47343, 22673}},
-{19271, 18, 98600, {1, 1, 5, 7, 13, 17, 77, 109, 427, 667, 1367, 2383, 7505, 11239, 14229, 35431, 35473, 62447}},
-{19272, 18, 98628, {1, 1, 1, 15, 27, 5, 51, 221, 471, 877, 449, 3961, 4197, 15713, 2955, 58985, 31431, 241539}},
-{19273, 18, 98635, {1, 1, 7, 1, 13, 61, 55, 199, 87, 679, 723, 271, 1061, 8043, 13163, 8079, 81501, 60467}},
-{19274, 18, 98645, {1, 1, 3, 3, 11, 1, 85, 65, 445, 731, 2017, 3113, 8085, 7133, 14789, 2435, 38459, 234997}},
-{19275, 18, 98652, {1, 3, 3, 9, 23, 31, 49, 137, 349, 651, 1975, 3429, 7137, 7841, 28297, 58209, 36493, 259097}},
-{19276, 18, 98655, {1, 1, 7, 15, 23, 11, 87, 133, 245, 445, 151, 4075, 141, 15395, 16649, 36925, 98421, 217265}},
-{19277, 18, 98665, {1, 3, 3, 5, 25, 53, 57, 177, 481, 177, 671, 1249, 2663, 12855, 24537, 31867, 110323, 164113}},
-{19278, 18, 98710, {1, 3, 5, 7, 23, 25, 19, 91, 447, 1023, 373, 3863, 4399, 12973, 7475, 37485, 8567, 53271}},
-{19279, 18, 98719, {1, 1, 5, 7, 31, 33, 31, 75, 223, 299, 1549, 1863, 353, 4339, 8891, 10365, 3399, 185807}},
-{19280, 18, 98720, {1, 1, 7, 9, 31, 53, 23, 203, 319, 915, 1923, 205, 3119, 7243, 25251, 12907, 101921, 102695}},
-{19281, 18, 98786, {1, 1, 7, 9, 15, 1, 123, 173, 123, 215, 263, 3003, 5881, 1117, 15195, 47457, 66663, 224177}},
-{19282, 18, 98792, {1, 1, 7, 13, 11, 25, 61, 121, 173, 115, 1897, 2145, 7783, 9673, 3321, 1707, 61475, 53875}},
-{19283, 18, 98806, {1, 3, 7, 3, 31, 21, 27, 99, 421, 225, 1565, 2351, 2275, 10583, 7877, 43505, 27629, 140919}},
-{19284, 18, 98816, {1, 3, 5, 5, 11, 45, 71, 105, 487, 867, 361, 3995, 2039, 1495, 27481, 4753, 20657, 67077}},
-{19285, 18, 98836, {1, 1, 5, 1, 19, 33, 1, 77, 377, 353, 719, 1463, 7053, 7409, 32165, 15557, 117673, 69887}},
-{19286, 18, 98859, {1, 1, 5, 7, 25, 5, 15, 231, 23, 213, 1627, 1801, 7793, 651, 9903, 51745, 111611, 39679}},
-{19287, 18, 98864, {1, 3, 3, 5, 23, 43, 37, 199, 437, 19, 1853, 2119, 461, 12641, 15865, 39941, 122545, 213443}},
-{19288, 18, 98879, {1, 3, 3, 11, 31, 45, 19, 227, 507, 909, 1501, 2021, 905, 1763, 1897, 3735, 81475, 30005}},
-{19289, 18, 98905, {1, 1, 5, 5, 29, 9, 55, 25, 23, 59, 593, 2197, 6029, 8235, 8397, 27521, 96221, 168837}},
-{19290, 18, 98917, {1, 3, 1, 15, 5, 33, 75, 121, 433, 557, 1011, 3785, 2545, 953, 17295, 14407, 94871, 60445}},
-{19291, 18, 98929, {1, 3, 3, 7, 7, 53, 29, 75, 171, 587, 1701, 3815, 2761, 4403, 39, 17291, 34897, 187257}},
-{19292, 18, 98969, {1, 3, 1, 15, 17, 57, 11, 95, 335, 13, 265, 1161, 7945, 6419, 26723, 31907, 89995, 82265}},
-{19293, 18, 98975, {1, 1, 7, 5, 9, 59, 27, 153, 37, 165, 823, 3525, 621, 4777, 3485, 9109, 116567, 34691}},
-{19294, 18, 98976, {1, 1, 5, 13, 23, 27, 11, 63, 35, 39, 995, 2101, 2611, 14139, 2683, 63787, 19813, 97497}},
-{19295, 18, 98981, {1, 3, 7, 15, 31, 15, 3, 163, 167, 53, 71, 1881, 4213, 3485, 21525, 705, 122345, 203549}},
-{19296, 18, 98999, {1, 3, 5, 5, 21, 33, 85, 133, 21, 505, 1639, 3989, 771, 7171, 21953, 34503, 31247, 247459}},
-{19297, 18, 99020, {1, 1, 7, 7, 31, 1, 27, 39, 469, 243, 679, 4091, 7137, 8505, 13329, 34139, 69485, 259795}},
-{19298, 18, 99026, {1, 3, 5, 5, 31, 43, 31, 161, 413, 657, 1407, 1417, 7349, 3301, 7691, 49355, 22929, 68043}},
-{19299, 18, 99054, {1, 1, 7, 11, 15, 61, 73, 217, 163, 503, 193, 3795, 41, 16251, 1187, 65363, 113211, 100337}},
-{19300, 18, 99083, {1, 3, 1, 11, 9, 15, 109, 187, 109, 865, 845, 1579, 321, 1269, 20613, 5693, 58421, 254959}},
-{19301, 18, 99093, {1, 3, 1, 13, 11, 3, 19, 135, 93, 779, 1383, 219, 2737, 377, 1125, 35663, 130815, 103797}},
-{19302, 18, 99103, {1, 1, 5, 11, 25, 25, 71, 249, 201, 679, 1677, 1817, 7619, 10327, 14821, 47847, 33629, 250979}},
-{19303, 18, 99131, {1, 1, 7, 15, 23, 19, 69, 39, 25, 843, 99, 3499, 2457, 11681, 30009, 17609, 46653, 162427}},
-{19304, 18, 99156, {1, 3, 3, 7, 23, 25, 77, 135, 61, 501, 1381, 3977, 1957, 11255, 16053, 30297, 58835, 97589}},
-{19305, 18, 99159, {1, 3, 5, 3, 9, 31, 9, 55, 421, 109, 1823, 1921, 7349, 2661, 4503, 36691, 48843, 182631}},
-{19306, 18, 99165, {1, 1, 1, 11, 7, 23, 107, 125, 393, 105, 1407, 3461, 4539, 6121, 7881, 32407, 83749, 98831}},
-{19307, 18, 99170, {1, 3, 3, 13, 5, 59, 5, 3, 185, 959, 241, 819, 1443, 1789, 12771, 26703, 25399, 182583}},
-{19308, 18, 99189, {1, 1, 1, 3, 3, 47, 7, 45, 93, 373, 175, 87, 649, 12903, 5029, 1945, 111967, 140889}},
-{19309, 18, 99223, {1, 3, 1, 11, 9, 47, 25, 191, 215, 845, 1557, 9, 3451, 5837, 11763, 29127, 113115, 99039}},
-{19310, 18, 99227, {1, 1, 1, 5, 23, 53, 45, 1, 361, 751, 807, 1765, 685, 2109, 28437, 60489, 65739, 234511}},
-{19311, 18, 99271, {1, 3, 3, 7, 15, 57, 71, 61, 195, 123, 1745, 3249, 351, 14309, 2017, 15653, 110803, 45937}},
-{19312, 18, 99277, {1, 3, 7, 9, 25, 11, 25, 29, 467, 313, 1927, 2423, 7311, 14299, 8145, 8123, 115103, 213881}},
-{19313, 18, 99278, {1, 1, 3, 15, 1, 35, 111, 99, 507, 417, 1433, 129, 5565, 13365, 18853, 8607, 109739, 120623}},
-{19314, 18, 99313, {1, 1, 1, 7, 13, 31, 93, 3, 327, 67, 1101, 1965, 5939, 6505, 3117, 3021, 33707, 79353}},
-{19315, 18, 99314, {1, 1, 3, 7, 15, 21, 23, 117, 367, 137, 287, 903, 4685, 13943, 26779, 24607, 70853, 99743}},
-{19316, 18, 99345, {1, 1, 7, 11, 25, 43, 67, 181, 459, 737, 1567, 3491, 5085, 6487, 23115, 62341, 102943, 77301}},
-{19317, 18, 99361, {1, 1, 3, 15, 7, 35, 81, 199, 455, 851, 835, 3421, 4675, 15173, 9205, 7305, 109849, 15183}},
-{19318, 18, 99367, {1, 3, 5, 11, 9, 55, 3, 53, 235, 271, 1265, 3681, 3627, 3485, 11591, 53097, 85949, 158173}},
-{19319, 18, 99386, {1, 3, 7, 3, 15, 27, 57, 183, 487, 9, 1797, 2973, 3687, 12987, 9133, 14595, 52067, 131217}},
-{19320, 18, 99394, {1, 1, 5, 3, 7, 25, 19, 215, 291, 325, 813, 577, 4249, 10373, 17233, 29557, 72979, 70721}},
-{19321, 18, 99417, {1, 3, 1, 7, 25, 1, 107, 167, 367, 303, 883, 993, 4189, 6557, 13697, 15251, 77065, 116127}},
-{19322, 18, 99418, {1, 3, 5, 11, 13, 59, 9, 121, 489, 593, 1503, 601, 5263, 13837, 20991, 35761, 45867, 155905}},
-{19323, 18, 99453, {1, 1, 3, 3, 19, 47, 127, 115, 267, 261, 969, 961, 5919, 10085, 29363, 4935, 100485, 75561}},
-{19324, 18, 99454, {1, 3, 1, 15, 11, 53, 39, 187, 53, 11, 1951, 913, 965, 2565, 5457, 3237, 24923, 245681}},
-{19325, 18, 99477, {1, 1, 7, 3, 15, 5, 25, 45, 17, 45, 1317, 1853, 6627, 15879, 29935, 24749, 118149, 35359}},
-{19326, 18, 99518, {1, 1, 7, 1, 21, 45, 67, 71, 25, 743, 925, 3441, 3013, 1613, 6321, 12491, 119931, 164701}},
-{19327, 18, 99544, {1, 1, 7, 1, 13, 15, 35, 187, 91, 995, 401, 2443, 4183, 10823, 20589, 27413, 117095, 20359}},
-{19328, 18, 99559, {1, 3, 3, 7, 15, 51, 55, 167, 409, 859, 719, 3223, 2457, 16013, 13639, 4027, 79339, 225113}},
-{19329, 18, 99592, {1, 3, 1, 9, 3, 29, 105, 193, 279, 27, 1093, 2199, 6983, 619, 10163, 40365, 71015, 102191}},
-{19330, 18, 99597, {1, 1, 3, 9, 29, 5, 33, 247, 27, 299, 2017, 379, 6199, 15047, 18329, 3493, 47679, 76703}},
-{19331, 18, 99603, {1, 3, 5, 5, 9, 19, 51, 129, 157, 831, 1373, 653, 7489, 13125, 1815, 10915, 88679, 50269}},
-{19332, 18, 99621, {1, 3, 3, 9, 9, 49, 79, 11, 181, 679, 1697, 3707, 205, 13305, 6293, 56653, 42619, 116257}},
-{19333, 18, 99646, {1, 1, 5, 9, 23, 41, 17, 135, 145, 715, 257, 1561, 6941, 2411, 31459, 25055, 35807, 51579}},
-{19334, 18, 99693, {1, 1, 1, 7, 11, 13, 49, 155, 403, 569, 751, 2959, 425, 13949, 22047, 49829, 71925, 101647}},
-{19335, 18, 99722, {1, 1, 3, 15, 15, 15, 17, 213, 113, 395, 1999, 2039, 3623, 13255, 24435, 54487, 78773, 202637}},
-{19336, 18, 99760, {1, 3, 7, 9, 5, 21, 61, 165, 97, 349, 1131, 2677, 333, 13129, 2137, 22909, 95795, 143081}},
-{19337, 18, 99780, {1, 1, 1, 5, 31, 41, 109, 179, 295, 475, 639, 3929, 1841, 7545, 19411, 52573, 10173, 236769}},
-{19338, 18, 99789, {1, 1, 1, 5, 27, 51, 9, 217, 393, 671, 931, 433, 7303, 16295, 6727, 5703, 88241, 132665}},
-{19339, 18, 99804, {1, 1, 7, 13, 21, 33, 19, 241, 497, 519, 1413, 489, 4975, 1345, 24925, 40383, 110815, 136217}},
-{19340, 18, 99823, {1, 3, 1, 9, 7, 51, 79, 15, 15, 601, 997, 3713, 7829, 903, 12393, 60059, 42057, 175141}},
-{19341, 18, 99826, {1, 1, 5, 15, 9, 63, 107, 63, 495, 591, 207, 779, 8069, 3013, 23839, 3075, 127481, 193885}},
-{19342, 18, 99832, {1, 1, 1, 7, 13, 17, 121, 171, 99, 59, 1043, 1109, 1337, 1179, 27635, 34063, 12945, 1431}},
-{19343, 18, 99842, {1, 3, 1, 3, 5, 47, 101, 205, 157, 595, 263, 3887, 7015, 4693, 15211, 25381, 128803, 227233}},
-{19344, 18, 99851, {1, 1, 3, 11, 17, 33, 1, 19, 153, 603, 119, 2305, 4041, 4011, 19849, 761, 52807, 129811}},
-{19345, 18, 99862, {1, 3, 7, 15, 21, 7, 13, 225, 497, 459, 389, 911, 6349, 5059, 6363, 41915, 90687, 214501}},
-{19346, 18, 99871, {1, 3, 1, 15, 1, 39, 31, 83, 147, 629, 185, 1913, 3217, 959, 651, 65267, 108613, 20391}},
-{19347, 18, 99899, {1, 3, 1, 7, 9, 11, 29, 201, 245, 815, 1869, 2597, 5693, 15669, 23293, 30885, 4029, 225737}},
-{19348, 18, 99940, {1, 3, 5, 11, 7, 29, 119, 207, 499, 23, 1563, 3645, 3839, 2509, 24043, 64231, 22509, 221835}},
-{19349, 18, 99983, {1, 3, 3, 7, 11, 49, 13, 201, 353, 217, 831, 2803, 1521, 12989, 25339, 41035, 2125, 165271}},
-{19350, 18, 99985, {1, 1, 5, 11, 1, 45, 93, 29, 55, 1007, 1919, 241, 5931, 9211, 17291, 39849, 25453, 96077}},
-{19351, 18, 100025, {1, 3, 1, 1, 29, 43, 11, 105, 331, 693, 1363, 291, 8191, 7813, 14135, 38287, 15469, 256913}},
-{19352, 18, 100043, {1, 3, 5, 11, 19, 21, 23, 117, 253, 111, 733, 3785, 5835, 423, 30251, 27283, 79561, 162095}},
-{19353, 18, 100070, {1, 3, 3, 1, 9, 19, 83, 13, 37, 725, 1597, 1117, 8067, 8085, 1315, 41813, 8973, 175525}},
-{19354, 18, 100076, {1, 1, 5, 3, 13, 39, 3, 213, 335, 907, 1143, 1729, 601, 11255, 24351, 41045, 11335, 186221}},
-{19355, 18, 100084, {1, 3, 3, 9, 17, 11, 29, 33, 303, 815, 1607, 2403, 8095, 4213, 16697, 64733, 24439, 93081}},
-{19356, 18, 100096, {1, 1, 1, 3, 13, 37, 35, 181, 243, 645, 1915, 3521, 569, 3005, 7271, 32755, 64575, 119813}},
-{19357, 18, 100105, {1, 1, 5, 13, 25, 59, 77, 121, 459, 755, 385, 1893, 1227, 9957, 5069, 40063, 27261, 4703}},
-{19358, 18, 100108, {1, 3, 1, 3, 29, 41, 95, 255, 219, 21, 317, 3021, 2615, 5101, 19413, 25795, 6521, 157749}},
-{19359, 18, 100123, {1, 3, 3, 5, 7, 33, 7, 205, 415, 23, 1431, 117, 1605, 9541, 11825, 49195, 86341, 99673}},
-{19360, 18, 100132, {1, 3, 3, 5, 17, 37, 33, 209, 49, 161, 321, 3697, 6483, 12859, 895, 675, 1899, 260289}},
-{19361, 18, 100141, {1, 1, 3, 15, 1, 27, 83, 125, 309, 553, 505, 2209, 4931, 2593, 28253, 12879, 74971, 9047}},
-{19362, 18, 100181, {1, 3, 7, 3, 15, 3, 105, 19, 41, 119, 149, 3847, 6593, 875, 23777, 4547, 57717, 139387}},
-{19363, 18, 100191, {1, 1, 1, 3, 9, 43, 25, 15, 67, 609, 951, 273, 8095, 621, 24819, 17233, 53423, 192757}},
-{19364, 18, 100202, {1, 3, 5, 3, 9, 49, 107, 215, 245, 217, 545, 2285, 2075, 401, 26599, 32967, 130457, 203755}},
-{19365, 18, 100216, {1, 1, 5, 1, 7, 31, 87, 181, 135, 155, 9, 1431, 307, 13367, 31147, 10327, 2817, 63327}},
-{19366, 18, 100246, {1, 3, 3, 3, 29, 17, 55, 201, 33, 275, 2005, 3037, 3439, 1513, 7563, 46491, 103319, 5279}},
-{19367, 18, 100256, {1, 3, 7, 11, 31, 63, 105, 169, 257, 225, 711, 2041, 1519, 11801, 18543, 35173, 92125, 72729}},
-{19368, 18, 100271, {1, 1, 3, 3, 11, 13, 127, 231, 229, 809, 303, 1167, 47, 4281, 2373, 10455, 74685, 131775}},
-{19369, 18, 100285, {1, 1, 5, 15, 1, 5, 97, 139, 189, 39, 37, 3513, 2119, 1453, 11477, 45477, 75613, 169915}},
-{19370, 18, 100294, {1, 3, 5, 1, 15, 27, 31, 87, 311, 785, 489, 1331, 5259, 6963, 26441, 41675, 107187, 60723}},
-{19371, 18, 100305, {1, 1, 3, 5, 13, 9, 33, 3, 273, 357, 841, 1421, 5993, 12449, 6821, 4283, 9437, 215035}},
-{19372, 18, 100321, {1, 3, 3, 1, 15, 43, 101, 35, 23, 743, 29, 3953, 3095, 14355, 25977, 12513, 54565, 20199}},
-{19373, 18, 100331, {1, 3, 3, 1, 11, 53, 99, 95, 63, 503, 1361, 3231, 2445, 5073, 4667, 33033, 4575, 139475}},
-{19374, 18, 100334, {1, 3, 3, 5, 19, 57, 15, 115, 125, 1017, 1913, 907, 2461, 3229, 16591, 6591, 26385, 228661}},
-{19375, 18, 100345, {1, 3, 1, 11, 27, 19, 7, 121, 245, 997, 1743, 2571, 1333, 9603, 27811, 42081, 44365, 94943}},
-{19376, 18, 100346, {1, 3, 1, 1, 13, 5, 127, 217, 63, 137, 989, 1441, 1133, 8273, 18091, 22243, 122931, 28867}},
-{19377, 18, 100369, {1, 1, 7, 15, 23, 39, 57, 83, 321, 817, 819, 223, 4803, 6935, 2027, 20373, 119683, 29781}},
-{19378, 18, 100372, {1, 1, 7, 7, 9, 1, 55, 211, 455, 283, 1647, 471, 4351, 14119, 6945, 63117, 109687, 200165}},
-{19379, 18, 100382, {1, 1, 7, 7, 29, 45, 113, 253, 135, 375, 1091, 959, 1423, 1241, 31689, 33751, 73459, 91769}},
-{19380, 18, 100403, {1, 3, 5, 11, 23, 63, 55, 181, 453, 267, 995, 1309, 2847, 3791, 21683, 59809, 81891, 132635}},
-{19381, 18, 100451, {1, 1, 1, 13, 17, 37, 87, 17, 61, 689, 1895, 3877, 4717, 6447, 22329, 1619, 30069, 190887}},
-{19382, 18, 100488, {1, 3, 1, 7, 27, 61, 17, 51, 99, 909, 85, 951, 107, 1923, 35, 63389, 90273, 152643}},
-{19383, 18, 100499, {1, 1, 1, 1, 15, 39, 77, 255, 191, 613, 655, 1881, 267, 3927, 18025, 13825, 15381, 169193}},
-{19384, 18, 100501, {1, 3, 3, 1, 31, 17, 73, 69, 231, 221, 501, 3755, 1671, 2049, 22493, 16353, 1775, 181783}},
-{19385, 18, 100511, {1, 1, 7, 5, 31, 45, 125, 189, 287, 487, 1911, 3133, 3257, 8967, 21295, 1247, 72297, 68269}},
-{19386, 18, 100536, {1, 3, 3, 1, 7, 9, 123, 147, 7, 381, 1597, 1289, 7831, 14493, 21145, 15487, 70353, 147891}},
-{19387, 18, 100629, {1, 1, 5, 9, 15, 17, 43, 87, 101, 425, 1819, 163, 6741, 8255, 2591, 17719, 112871, 110793}},
-{19388, 18, 100652, {1, 1, 3, 9, 3, 27, 7, 41, 43, 743, 131, 705, 2607, 9963, 26367, 41191, 126347, 164291}},
-{19389, 18, 100655, {1, 3, 3, 15, 7, 17, 97, 153, 283, 461, 1723, 2421, 4973, 16369, 30633, 62299, 119425, 3591}},
-{19390, 18, 100669, {1, 1, 1, 13, 7, 33, 95, 255, 429, 693, 849, 3783, 5985, 8551, 23227, 1015, 109023, 42493}},
-{19391, 18, 100687, {1, 3, 1, 7, 3, 43, 53, 137, 413, 265, 2033, 1347, 335, 529, 24751, 16443, 122195, 158951}},
-{19392, 18, 100692, {1, 1, 5, 9, 27, 21, 83, 185, 325, 557, 1247, 2739, 6925, 5459, 26027, 62217, 61113, 197743}},
-{19393, 18, 100696, {1, 1, 3, 13, 9, 57, 79, 133, 137, 851, 863, 1605, 7839, 11809, 29941, 20473, 6687, 164479}},
-{19394, 18, 100701, {1, 1, 3, 9, 9, 51, 123, 29, 139, 43, 1329, 2701, 3413, 3875, 19673, 62369, 10529, 226525}},
-{19395, 18, 100706, {1, 3, 1, 5, 25, 47, 7, 201, 119, 623, 9, 25, 1713, 10817, 8201, 5847, 77477, 237883}},
-{19396, 18, 100711, {1, 1, 5, 13, 15, 53, 39, 93, 235, 619, 1695, 2389, 2571, 2389, 4619, 45769, 17245, 69973}},
-{19397, 18, 100726, {1, 1, 7, 1, 31, 9, 75, 143, 1, 67, 809, 1037, 2801, 16129, 22443, 26021, 119683, 14681}},
-{19398, 18, 100754, {1, 3, 1, 9, 23, 49, 69, 71, 139, 953, 1053, 3059, 1061, 5881, 26207, 15907, 79389, 95341}},
-{19399, 18, 100759, {1, 3, 5, 1, 19, 39, 69, 183, 95, 289, 847, 393, 1649, 1275, 21187, 34715, 67553, 123239}},
-{19400, 18, 100790, {1, 1, 1, 5, 21, 39, 119, 193, 347, 87, 731, 3327, 6089, 13781, 20389, 52303, 11869, 48975}},
-{19401, 18, 100838, {1, 3, 5, 1, 19, 17, 93, 33, 215, 457, 687, 1325, 1997, 2655, 21195, 54997, 36877, 57991}},
-{19402, 18, 100878, {1, 1, 1, 3, 17, 45, 91, 45, 231, 611, 413, 2321, 7181, 13765, 7791, 6973, 24497, 231795}},
-{19403, 18, 100880, {1, 3, 3, 15, 7, 29, 103, 31, 295, 637, 1775, 2293, 8001, 4175, 1257, 16881, 93695, 180591}},
-{19404, 18, 100885, {1, 1, 1, 13, 31, 7, 47, 51, 267, 231, 463, 939, 7977, 8593, 15329, 36871, 50449, 222341}},
-{19405, 18, 100886, {1, 3, 7, 3, 27, 31, 57, 135, 507, 177, 1455, 1963, 4473, 6449, 727, 49853, 65275, 237531}},
-{19406, 18, 100943, {1, 3, 7, 11, 31, 21, 111, 231, 269, 27, 719, 3275, 2489, 3689, 3425, 23763, 39413, 64565}},
-{19407, 18, 100948, {1, 1, 1, 11, 23, 27, 31, 153, 201, 985, 1553, 3061, 7663, 4079, 13549, 48765, 64169, 68223}},
-{19408, 18, 100957, {1, 1, 7, 15, 11, 53, 125, 23, 73, 799, 591, 665, 127, 3941, 11251, 12649, 2657, 230923}},
-{19409, 18, 100962, {1, 1, 7, 15, 29, 43, 95, 81, 337, 367, 779, 1237, 7627, 997, 3355, 1245, 70477, 159097}},
-{19410, 18, 100968, {1, 3, 1, 13, 19, 31, 11, 91, 179, 425, 1395, 1439, 2723, 401, 26779, 36723, 115743, 179653}},
-{19411, 18, 100981, {1, 1, 3, 1, 29, 35, 11, 217, 301, 421, 765, 1949, 5475, 2247, 3953, 27091, 16895, 194821}},
-{19412, 18, 100986, {1, 1, 5, 9, 11, 21, 95, 135, 127, 65, 609, 3893, 7143, 13231, 29199, 36205, 38711, 159599}},
-{19413, 18, 101001, {1, 3, 5, 13, 25, 25, 101, 221, 495, 993, 961, 2575, 907, 5277, 18415, 1797, 22043, 129889}},
-{19414, 18, 101012, {1, 1, 1, 15, 21, 21, 99, 3, 175, 735, 659, 543, 7573, 15549, 14067, 60009, 65785, 112927}},
-{19415, 18, 101015, {1, 3, 7, 7, 3, 39, 61, 203, 143, 581, 487, 2097, 3943, 6869, 14435, 46431, 101781, 233067}},
-{19416, 18, 101019, {1, 1, 3, 1, 13, 27, 21, 147, 295, 89, 1845, 1017, 4621, 10029, 3517, 25371, 104531, 225179}},
-{19417, 18, 101037, {1, 1, 3, 11, 25, 51, 45, 179, 299, 487, 2039, 85, 4643, 8211, 12051, 64819, 93481, 159511}},
-{19418, 18, 101063, {1, 1, 5, 3, 21, 7, 73, 193, 415, 7, 125, 2487, 7369, 2043, 7633, 19265, 65337, 57399}},
-{19419, 18, 101105, {1, 1, 5, 3, 3, 53, 51, 169, 313, 973, 1549, 243, 3155, 13827, 24971, 61393, 15147, 187397}},
-{19420, 18, 101144, {1, 3, 3, 3, 29, 33, 91, 41, 367, 77, 1259, 1703, 2105, 14473, 17763, 29809, 47777, 205553}},
-{19421, 18, 101147, {1, 3, 7, 3, 23, 61, 59, 235, 51, 41, 417, 691, 2953, 15577, 32283, 2793, 109557, 64729}},
-{19422, 18, 101154, {1, 1, 5, 9, 13, 17, 93, 201, 151, 323, 1481, 3645, 3039, 5131, 503, 42055, 114939, 198755}},
-{19423, 18, 101163, {1, 3, 5, 1, 21, 53, 75, 29, 283, 541, 499, 309, 1923, 995, 21479, 56183, 103743, 152113}},
-{19424, 18, 101166, {1, 3, 1, 3, 21, 51, 67, 97, 481, 509, 805, 213, 5157, 13573, 16187, 8199, 28025, 208445}},
-{19425, 18, 101173, {1, 1, 7, 7, 15, 25, 107, 127, 355, 249, 707, 1287, 6831, 5317, 15613, 12837, 48091, 27611}},
-{19426, 18, 101174, {1, 3, 3, 7, 31, 53, 127, 239, 17, 709, 979, 4023, 7149, 4239, 20015, 44365, 113245, 75873}},
-{19427, 18, 101219, {1, 3, 5, 11, 27, 37, 49, 123, 137, 967, 1857, 3961, 7429, 8355, 30733, 64587, 73903, 188581}},
-{19428, 18, 101240, {1, 3, 3, 7, 19, 51, 69, 121, 345, 637, 1987, 335, 7071, 13849, 22369, 46895, 20761, 148227}},
-{19429, 18, 101250, {1, 1, 3, 11, 9, 1, 93, 151, 487, 889, 919, 2429, 5425, 15303, 12583, 57627, 42683, 98265}},
-{19430, 18, 101259, {1, 3, 5, 3, 1, 29, 87, 189, 285, 805, 933, 1381, 2789, 107, 14215, 33171, 110573, 250983}},
-{19431, 18, 101273, {1, 3, 1, 1, 27, 43, 63, 115, 317, 401, 885, 1029, 7003, 10041, 15299, 42251, 58675, 177545}},
-{19432, 18, 101274, {1, 3, 5, 7, 11, 33, 119, 5, 185, 777, 1795, 1585, 3543, 1801, 17681, 1041, 44513, 105435}},
-{19433, 18, 101285, {1, 3, 1, 9, 19, 33, 15, 253, 299, 925, 241, 1333, 615, 12501, 499, 44449, 16595, 70357}},
-{19434, 18, 101300, {1, 1, 3, 13, 13, 31, 17, 123, 215, 805, 1177, 3683, 27, 11881, 7645, 25575, 63057, 89547}},
-{19435, 18, 101309, {1, 1, 5, 5, 17, 1, 57, 183, 267, 825, 1987, 329, 5603, 1295, 425, 61871, 27859, 157109}},
-{19436, 18, 101310, {1, 3, 3, 11, 19, 45, 37, 79, 191, 17, 17, 3379, 7941, 3159, 20351, 26341, 34687, 116281}},
-{19437, 18, 101321, {1, 1, 3, 7, 11, 7, 61, 199, 459, 993, 1729, 3751, 1067, 14965, 14669, 40281, 12579, 154601}},
-{19438, 18, 101324, {1, 3, 3, 13, 19, 53, 17, 39, 137, 219, 1645, 2899, 505, 10057, 22891, 32317, 81201, 126291}},
-{19439, 18, 101363, {1, 3, 5, 7, 21, 53, 65, 125, 69, 781, 761, 1683, 5817, 11859, 11543, 62853, 57149, 212261}},
-{19440, 18, 101366, {1, 3, 5, 9, 13, 25, 81, 119, 439, 25, 239, 2867, 421, 12631, 22705, 31039, 96105, 79023}},
-{19441, 18, 101377, {1, 3, 5, 3, 19, 9, 51, 135, 437, 393, 1711, 1205, 5195, 10927, 28583, 7513, 110227, 139295}},
-{19442, 18, 101380, {1, 3, 7, 9, 31, 15, 5, 143, 49, 13, 1143, 2325, 5437, 14289, 31555, 58777, 102675, 64559}},
-{19443, 18, 101389, {1, 1, 7, 3, 3, 21, 65, 127, 341, 109, 167, 1835, 6687, 1695, 15631, 47047, 127543, 51413}},
-{19444, 18, 101407, {1, 1, 3, 1, 31, 49, 103, 147, 59, 701, 1251, 3391, 1935, 5371, 28585, 50023, 73839, 118205}},
-{19445, 18, 101411, {1, 3, 3, 1, 5, 49, 91, 23, 91, 663, 1369, 1437, 2657, 11369, 29857, 53875, 127045, 242323}},
-{19446, 18, 101432, {1, 3, 1, 3, 23, 33, 7, 105, 353, 863, 1211, 1175, 1347, 12913, 11973, 55255, 27145, 175539}},
-{19447, 18, 101476, {1, 1, 1, 13, 9, 29, 71, 71, 509, 571, 2005, 3125, 2731, 6829, 26863, 16459, 113195, 80247}},
-{19448, 18, 101488, {1, 3, 5, 1, 7, 11, 45, 177, 281, 695, 1197, 2035, 2137, 11833, 12417, 5805, 77211, 45553}},
-{19449, 18, 101494, {1, 1, 7, 7, 27, 59, 91, 183, 267, 373, 677, 2431, 903, 4229, 31997, 19843, 125089, 242871}},
-{19450, 18, 101514, {1, 3, 3, 13, 23, 23, 53, 101, 225, 247, 2013, 853, 279, 2161, 30045, 28255, 130907, 57157}},
-{19451, 18, 101534, {1, 3, 5, 13, 5, 11, 63, 137, 219, 661, 773, 1991, 4081, 5963, 25207, 50461, 85293, 159441}},
-{19452, 18, 101537, {1, 3, 1, 15, 5, 59, 43, 87, 429, 77, 73, 1275, 2619, 16133, 20009, 26089, 38129, 157267}},
-{19453, 18, 101543, {1, 1, 5, 15, 9, 59, 37, 127, 127, 733, 1703, 1331, 4293, 3555, 22739, 49513, 34533, 143225}},
-{19454, 18, 101547, {1, 1, 7, 7, 11, 51, 121, 59, 505, 147, 1855, 1661, 5539, 3421, 28863, 14811, 39811, 228927}},
-{19455, 18, 101584, {1, 1, 5, 5, 1, 31, 57, 167, 107, 753, 1835, 2491, 3311, 8639, 8743, 17279, 77071, 8673}},
-{19456, 18, 101589, {1, 1, 3, 3, 15, 39, 1, 223, 395, 603, 1095, 435, 1225, 4045, 21721, 40767, 48971, 1583}},
-{19457, 18, 101590, {1, 1, 3, 13, 9, 17, 47, 175, 229, 827, 769, 2901, 137, 9931, 11115, 25337, 105811, 68413}},
-{19458, 18, 101629, {1, 1, 1, 5, 29, 55, 43, 39, 319, 919, 749, 931, 1973, 13147, 913, 48353, 40955, 189783}},
-{19459, 18, 101678, {1, 3, 5, 5, 13, 33, 81, 213, 79, 781, 1069, 3117, 5859, 9061, 30963, 17307, 6281, 208707}},
-{19460, 18, 101683, {1, 1, 5, 13, 27, 63, 41, 91, 123, 763, 1115, 3193, 4571, 4573, 8235, 24291, 40911, 225985}},
-{19461, 18, 101700, {1, 1, 1, 7, 13, 5, 77, 215, 67, 183, 1447, 1571, 213, 3481, 28349, 22451, 44951, 240257}},
-{19462, 18, 101712, {1, 3, 7, 7, 3, 21, 39, 233, 263, 19, 489, 1511, 2313, 1799, 25173, 17913, 70593, 2969}},
-{19463, 18, 101748, {1, 3, 7, 15, 3, 1, 93, 101, 393, 911, 1055, 953, 1279, 11947, 11963, 53443, 29105, 226057}},
-{19464, 18, 101757, {1, 1, 3, 7, 7, 53, 119, 39, 439, 629, 1845, 3411, 3633, 16345, 27501, 59565, 39581, 85373}},
-{19465, 18, 101762, {1, 1, 5, 7, 19, 39, 19, 191, 509, 239, 359, 645, 8107, 13721, 21289, 20763, 67727, 45957}},
-{19466, 18, 101771, {1, 1, 1, 13, 5, 13, 113, 41, 135, 351, 311, 1099, 2391, 16165, 15805, 54737, 102645, 224417}},
-{19467, 18, 101785, {1, 3, 3, 9, 17, 47, 95, 249, 45, 749, 313, 317, 2413, 15861, 27221, 35537, 6407, 50111}},
-{19468, 18, 101795, {1, 1, 7, 5, 29, 57, 81, 7, 233, 393, 307, 1089, 1367, 12275, 11861, 29119, 27271, 36351}},
-{19469, 18, 101822, {1, 3, 5, 15, 9, 15, 23, 241, 233, 305, 1025, 2035, 4897, 10321, 17345, 42873, 109045, 129533}},
-{19470, 18, 101851, {1, 3, 5, 9, 21, 33, 111, 81, 311, 829, 1851, 1437, 5935, 7847, 15493, 28531, 74879, 40567}},
-{19471, 18, 101863, {1, 3, 7, 7, 13, 21, 43, 119, 507, 701, 1385, 745, 799, 1567, 13271, 40267, 130843, 59951}},
-{19472, 18, 101894, {1, 3, 3, 1, 19, 43, 45, 119, 87, 263, 1475, 3897, 2811, 2711, 4949, 48043, 125237, 230897}},
-{19473, 18, 101903, {1, 1, 7, 1, 1, 53, 17, 71, 313, 373, 5, 2359, 1643, 9867, 18365, 5011, 40675, 105371}},
-{19474, 18, 101924, {1, 3, 7, 11, 23, 49, 123, 255, 33, 241, 473, 959, 1859, 6109, 5433, 27625, 46839, 90727}},
-{19475, 18, 101939, {1, 1, 1, 3, 31, 43, 33, 129, 159, 445, 1831, 1005, 587, 2091, 5749, 33271, 50909, 65057}},
-{19476, 18, 101980, {1, 1, 7, 13, 3, 21, 17, 125, 357, 97, 1255, 669, 1583, 7433, 32287, 61795, 5915, 211593}},
-{19477, 18, 101993, {1, 1, 7, 7, 31, 19, 71, 211, 213, 731, 1491, 3315, 3633, 14953, 21369, 4977, 33533, 12115}},
-{19478, 18, 101994, {1, 3, 1, 1, 31, 1, 87, 253, 211, 57, 1431, 2613, 4075, 14463, 11287, 38671, 100129, 4241}},
-{19479, 18, 101996, {1, 1, 1, 5, 21, 13, 27, 29, 31, 285, 179, 3861, 5319, 15683, 2579, 15663, 63357, 81849}},
-{19480, 18, 102007, {1, 1, 3, 7, 23, 29, 29, 79, 263, 865, 1237, 3871, 2097, 5337, 2387, 59277, 28831, 57957}},
-{19481, 18, 102044, {1, 3, 7, 15, 15, 31, 83, 195, 87, 691, 71, 1025, 3145, 675, 14619, 22399, 88885, 222969}},
-{19482, 18, 102086, {1, 1, 5, 7, 19, 3, 121, 105, 383, 675, 777, 2073, 643, 14439, 19467, 13159, 115421, 250561}},
-{19483, 18, 102097, {1, 3, 5, 9, 13, 41, 119, 23, 355, 765, 579, 849, 3313, 2443, 29521, 42965, 102559, 227707}},
-{19484, 18, 102113, {1, 3, 3, 7, 23, 55, 115, 83, 331, 873, 797, 621, 1197, 15299, 26307, 34287, 120459, 260603}},
-{19485, 18, 102123, {1, 1, 3, 5, 7, 11, 113, 119, 65, 691, 1169, 2291, 7283, 1391, 10737, 3801, 40649, 191009}},
-{19486, 18, 102155, {1, 1, 7, 9, 3, 23, 95, 109, 457, 277, 871, 3013, 2833, 4131, 21081, 43635, 19875, 162173}},
-{19487, 18, 102157, {1, 1, 3, 15, 25, 7, 45, 109, 195, 935, 1487, 1603, 1663, 15595, 10687, 4073, 34863, 45851}},
-{19488, 18, 102169, {1, 1, 1, 5, 21, 19, 37, 141, 377, 553, 1225, 2485, 1235, 13179, 2587, 43659, 1405, 52023}},
-{19489, 18, 102181, {1, 3, 1, 9, 5, 27, 1, 219, 397, 555, 533, 941, 2755, 1295, 16157, 30733, 54279, 168455}},
-{19490, 18, 102182, {1, 3, 3, 1, 27, 41, 93, 177, 119, 581, 167, 3943, 5765, 15455, 555, 17419, 33117, 160599}},
-{19491, 18, 102185, {1, 1, 3, 7, 15, 25, 29, 177, 503, 529, 229, 2535, 1493, 805, 30983, 26309, 123453, 118441}},
-{19492, 18, 102199, {1, 1, 7, 15, 13, 33, 83, 151, 183, 433, 823, 4003, 1991, 6563, 18743, 61835, 56535, 191193}},
-{19493, 18, 102208, {1, 1, 1, 13, 9, 31, 91, 63, 455, 67, 243, 1573, 3507, 9491, 4677, 13835, 121603, 241781}},
-{19494, 18, 102213, {1, 1, 5, 5, 29, 13, 45, 29, 289, 909, 1923, 3371, 3675, 13119, 24599, 58511, 109467, 126865}},
-{19495, 18, 102226, {1, 1, 5, 9, 21, 41, 41, 179, 25, 463, 949, 819, 397, 12329, 3461, 34773, 61337, 23579}},
-{19496, 18, 102290, {1, 3, 3, 11, 1, 25, 17, 165, 77, 455, 1983, 143, 2763, 8165, 14849, 1601, 30093, 54599}},
-{19497, 18, 102296, {1, 1, 7, 3, 7, 1, 117, 117, 53, 611, 1405, 3357, 1717, 8157, 247, 17501, 30201, 192485}},
-{19498, 18, 102306, {1, 1, 1, 5, 23, 47, 95, 173, 133, 603, 1627, 4039, 5599, 10575, 30275, 60287, 3313, 77551}},
-{19499, 18, 102317, {1, 1, 1, 9, 31, 49, 87, 169, 221, 561, 1045, 365, 1955, 9905, 13057, 33717, 91203, 57513}},
-{19500, 18, 102337, {1, 3, 3, 1, 19, 25, 113, 231, 415, 717, 1767, 755, 4825, 7541, 10121, 9351, 72093, 255877}},
-{19501, 18, 102344, {1, 3, 1, 7, 1, 35, 3, 231, 345, 375, 809, 2753, 849, 13915, 16127, 7575, 45259, 28917}},
-{19502, 18, 102350, {1, 3, 3, 11, 23, 43, 13, 37, 305, 765, 517, 333, 473, 14949, 11939, 35171, 63963, 181825}},
-{19503, 18, 102378, {1, 3, 3, 3, 5, 43, 35, 89, 293, 913, 1325, 2097, 603, 14365, 4005, 38935, 23837, 34271}},
-{19504, 18, 102383, {1, 1, 3, 15, 1, 47, 67, 199, 167, 909, 1167, 1513, 7087, 5017, 23469, 2621, 24961, 226679}},
-{19505, 18, 102391, {1, 3, 7, 15, 23, 37, 111, 217, 33, 423, 457, 1767, 4821, 10233, 27045, 33397, 85351, 156751}},
-{19506, 18, 102400, {1, 3, 3, 7, 31, 25, 67, 65, 291, 169, 1505, 1707, 4833, 11541, 1189, 62959, 59831, 48729}},
-{19507, 18, 102409, {1, 1, 5, 7, 27, 27, 15, 23, 189, 819, 709, 3591, 2781, 14807, 20303, 27795, 88349, 210251}},
-{19508, 18, 102427, {1, 3, 7, 15, 1, 19, 49, 103, 219, 85, 1281, 3981, 7229, 10427, 11689, 1547, 90747, 12283}},
-{19509, 18, 102434, {1, 1, 1, 13, 31, 49, 81, 121, 287, 851, 333, 353, 7373, 10165, 1157, 11713, 89445, 210709}},
-{19510, 18, 102453, {1, 3, 7, 5, 31, 35, 3, 229, 443, 973, 1971, 1861, 5695, 6725, 6405, 45927, 115313, 228667}},
-{19511, 18, 102472, {1, 3, 3, 11, 29, 17, 105, 203, 69, 945, 1239, 3213, 6005, 10095, 31233, 37421, 62911, 91371}},
-{19512, 18, 102502, {1, 1, 7, 1, 21, 59, 7, 43, 391, 299, 1225, 283, 3351, 11495, 25071, 16619, 65127, 114033}},
-{19513, 18, 102525, {1, 1, 3, 9, 17, 11, 71, 73, 377, 437, 311, 1083, 6941, 1039, 1047, 55647, 21239, 209201}},
-{19514, 18, 102547, {1, 3, 7, 5, 29, 51, 113, 163, 215, 511, 615, 2427, 2747, 14389, 1005, 27015, 31809, 30603}},
-{19515, 18, 102554, {1, 1, 1, 3, 9, 61, 9, 201, 259, 411, 175, 1003, 401, 13695, 13103, 3075, 43695, 177139}},
-{19516, 18, 102560, {1, 1, 5, 3, 17, 47, 125, 173, 277, 17, 619, 2295, 3091, 5615, 4529, 54065, 81875, 97279}},
-{19517, 18, 102578, {1, 3, 3, 9, 3, 61, 97, 151, 287, 671, 1439, 1129, 6343, 8161, 24593, 40371, 109705, 106279}},
-{19518, 18, 102580, {1, 3, 3, 1, 5, 61, 21, 31, 41, 855, 1541, 3351, 575, 3195, 17155, 46913, 1797, 146401}},
-{19519, 18, 102597, {1, 1, 7, 13, 11, 43, 27, 97, 479, 117, 1873, 3103, 1947, 9273, 29171, 35719, 10601, 209629}},
-{19520, 18, 102616, {1, 3, 1, 9, 21, 47, 53, 129, 85, 505, 165, 3437, 5687, 10289, 6615, 46719, 50731, 25271}},
-{19521, 18, 102625, {1, 1, 3, 1, 1, 33, 37, 239, 45, 565, 1907, 3831, 2177, 10967, 12689, 49395, 36289, 247507}},
-{19522, 18, 102632, {1, 1, 5, 1, 19, 57, 75, 245, 59, 967, 1319, 3971, 5267, 11713, 15417, 60503, 63431, 157267}},
-{19523, 18, 102663, {1, 1, 5, 7, 7, 15, 99, 87, 331, 261, 1973, 219, 3063, 4071, 19273, 48637, 128089, 55511}},
-{19524, 18, 102669, {1, 3, 5, 13, 23, 43, 7, 171, 173, 1023, 1145, 3551, 5127, 6365, 18013, 1613, 51997, 107265}},
-{19525, 18, 102681, {1, 3, 5, 3, 7, 7, 23, 195, 251, 387, 1889, 3645, 4221, 6025, 27291, 24831, 123749, 231403}},
-{19526, 18, 102694, {1, 3, 1, 1, 29, 49, 107, 215, 93, 211, 1349, 1925, 7149, 1015, 27465, 34139, 126149, 121349}},
-{19527, 18, 102706, {1, 1, 5, 5, 19, 15, 121, 189, 167, 801, 483, 1955, 8031, 4749, 26665, 64791, 18671, 123221}},
-{19528, 18, 102715, {1, 3, 3, 15, 23, 57, 15, 249, 197, 103, 2021, 1897, 5975, 12821, 6441, 62719, 81415, 232417}},
-{19529, 18, 102723, {1, 1, 3, 9, 17, 45, 111, 225, 103, 121, 1259, 2849, 2235, 2041, 13261, 7929, 76325, 38677}},
-{19530, 18, 102730, {1, 1, 3, 9, 25, 17, 63, 63, 369, 387, 31, 1423, 5699, 12519, 27407, 53193, 963, 123473}},
-{19531, 18, 102743, {1, 3, 3, 13, 3, 59, 59, 3, 367, 357, 1391, 1519, 2619, 2291, 1349, 28275, 21655, 8763}},
-{19532, 18, 102856, {1, 1, 7, 1, 31, 51, 121, 49, 157, 509, 1513, 3247, 3439, 8691, 20729, 17585, 49013, 228695}},
-{19533, 18, 102870, {1, 1, 5, 9, 11, 29, 103, 49, 209, 35, 673, 1409, 2483, 4561, 12435, 46139, 31019, 50929}},
-{19534, 18, 102898, {1, 1, 3, 9, 11, 45, 77, 143, 277, 769, 1151, 3705, 7901, 3735, 31155, 46135, 84061, 254357}},
-{19535, 18, 102926, {1, 3, 3, 3, 5, 51, 95, 7, 155, 121, 1899, 2261, 2915, 6637, 6557, 20535, 20937, 257275}},
-{19536, 18, 102931, {1, 1, 7, 9, 13, 49, 125, 135, 7, 535, 1171, 3501, 1701, 5791, 10121, 9845, 21645, 56451}},
-{19537, 18, 102938, {1, 1, 7, 5, 9, 1, 115, 27, 229, 813, 133, 753, 1959, 13121, 30425, 31059, 114619, 132257}},
-{19538, 18, 102947, {1, 1, 5, 3, 23, 25, 41, 165, 21, 551, 1751, 3563, 731, 15811, 14777, 22327, 82853, 116699}},
-{19539, 18, 102968, {1, 3, 1, 9, 3, 25, 95, 211, 457, 25, 349, 921, 213, 5721, 26725, 19541, 102473, 200845}},
-{19540, 18, 102976, {1, 3, 1, 13, 5, 1, 31, 49, 493, 785, 61, 2603, 5997, 12545, 9793, 32521, 99859, 256105}},
-{19541, 18, 102993, {1, 3, 3, 7, 31, 19, 31, 121, 507, 79, 685, 197, 4027, 12909, 30533, 38427, 38993, 14581}},
-{19542, 18, 103005, {1, 3, 7, 13, 13, 23, 63, 15, 223, 25, 1957, 2527, 6061, 11753, 4835, 34553, 45579, 205805}},
-{19543, 18, 103019, {1, 3, 3, 3, 5, 39, 55, 123, 275, 185, 749, 3227, 8137, 12959, 7243, 20613, 46247, 106127}},
-{19544, 18, 103022, {1, 1, 7, 13, 1, 21, 49, 145, 237, 291, 1721, 2981, 267, 1255, 21817, 39553, 21937, 115307}},
-{19545, 18, 103057, {1, 1, 1, 15, 5, 63, 3, 201, 117, 991, 1049, 1975, 5117, 5799, 28211, 37907, 46799, 240847}},
-{19546, 18, 103080, {1, 3, 3, 5, 25, 15, 29, 111, 201, 857, 319, 2695, 4251, 4303, 28495, 12481, 31979, 107503}},
-{19547, 18, 103100, {1, 1, 3, 11, 3, 27, 81, 55, 489, 983, 293, 3181, 4593, 4759, 18437, 51185, 47701, 75469}},
-{19548, 18, 103106, {1, 3, 1, 3, 11, 25, 113, 243, 365, 299, 1717, 561, 5173, 5983, 7453, 33563, 98519, 162451}},
-{19549, 18, 103126, {1, 3, 1, 5, 1, 21, 3, 87, 267, 483, 1397, 791, 4807, 4649, 13713, 19861, 110471, 51443}},
-{19550, 18, 103173, {1, 3, 7, 5, 31, 9, 13, 251, 351, 609, 841, 3267, 4201, 8771, 6673, 44867, 105221, 189399}},
-{19551, 18, 103202, {1, 1, 3, 1, 13, 43, 47, 153, 331, 1013, 705, 1867, 563, 6361, 7407, 46243, 30521, 213831}},
-{19552, 18, 103207, {1, 3, 3, 7, 29, 41, 3, 179, 319, 877, 905, 3803, 2775, 9729, 5673, 9521, 117887, 37605}},
-{19553, 18, 103219, {1, 1, 5, 5, 11, 49, 111, 195, 467, 931, 849, 2785, 7829, 2291, 29031, 52019, 86493, 213971}},
-{19554, 18, 103226, {1, 1, 3, 11, 13, 11, 81, 81, 419, 621, 181, 1203, 7305, 7857, 16885, 2531, 53127, 35553}},
-{19555, 18, 103228, {1, 1, 5, 1, 19, 35, 75, 131, 159, 211, 319, 2805, 6497, 14759, 28997, 62347, 4013, 233821}},
-{19556, 18, 103248, {1, 3, 3, 15, 1, 55, 107, 105, 35, 369, 1259, 665, 6717, 2555, 7149, 10373, 33153, 105915}},
-{19557, 18, 103274, {1, 3, 7, 5, 31, 13, 27, 207, 359, 355, 2047, 1777, 5555, 12659, 30547, 3655, 86189, 961}},
-{19558, 18, 103288, {1, 3, 7, 9, 9, 55, 7, 117, 57, 115, 745, 501, 2341, 3899, 8229, 10625, 66905, 187959}},
-{19559, 18, 103291, {1, 3, 3, 13, 25, 43, 87, 197, 303, 405, 1459, 3385, 4109, 8325, 24747, 18405, 48845, 96673}},
-{19560, 18, 103293, {1, 3, 5, 3, 21, 37, 109, 9, 183, 585, 1287, 3851, 4939, 1057, 19489, 42603, 32447, 117957}},
-{19561, 18, 103324, {1, 1, 5, 13, 3, 47, 109, 115, 73, 733, 1189, 3773, 7471, 10339, 5093, 50253, 122665, 254381}},
-{19562, 18, 103358, {1, 1, 5, 5, 21, 33, 113, 187, 51, 245, 241, 3887, 4075, 11945, 20883, 18817, 43567, 851}},
-{19563, 18, 103372, {1, 3, 7, 3, 1, 29, 87, 101, 29, 93, 643, 2659, 1753, 4797, 17477, 16087, 43453, 110383}},
-{19564, 18, 103375, {1, 1, 7, 13, 17, 51, 75, 91, 445, 171, 1369, 499, 3753, 14035, 4445, 21437, 86205, 231163}},
-{19565, 18, 103390, {1, 1, 7, 13, 17, 41, 67, 49, 225, 659, 1181, 1751, 5211, 6847, 20339, 34271, 60273, 52315}},
-{19566, 18, 103414, {1, 1, 5, 5, 5, 17, 87, 223, 25, 773, 53, 2447, 6805, 6547, 4429, 46809, 51171, 66457}},
-{19567, 18, 103432, {1, 1, 5, 3, 29, 49, 11, 205, 279, 821, 725, 2425, 443, 211, 6347, 59845, 90763, 237911}},
-{19568, 18, 103446, {1, 1, 3, 9, 31, 7, 49, 1, 229, 755, 517, 809, 2955, 3571, 2385, 33097, 19659, 55397}},
-{19569, 18, 103455, {1, 3, 5, 3, 5, 21, 67, 227, 359, 401, 1697, 2131, 4585, 2661, 3659, 22621, 51639, 245877}},
-{19570, 18, 103471, {1, 1, 7, 5, 11, 7, 57, 133, 9, 917, 427, 2777, 6009, 11393, 29473, 59311, 77095, 176215}},
-{19571, 18, 103474, {1, 1, 7, 5, 13, 29, 101, 15, 293, 7, 797, 437, 3739, 3369, 16917, 19047, 17773, 219541}},
-{19572, 18, 103476, {1, 3, 1, 9, 13, 51, 15, 19, 209, 991, 413, 787, 3797, 14029, 23699, 8591, 40429, 56115}},
-{19573, 18, 103515, {1, 3, 7, 3, 31, 9, 77, 33, 487, 155, 1903, 3023, 8163, 385, 4703, 57511, 102083, 85785}},
-{19574, 18, 103527, {1, 1, 5, 11, 17, 59, 115, 73, 89, 723, 1523, 2671, 1755, 3463, 19861, 31573, 126405, 90215}},
-{19575, 18, 103542, {1, 3, 3, 13, 17, 27, 123, 37, 71, 173, 203, 1245, 7905, 8955, 22589, 56705, 120473, 90129}},
-{19576, 18, 103562, {1, 3, 3, 1, 17, 63, 55, 225, 259, 531, 1493, 2639, 1319, 10865, 17993, 11205, 13253, 111261}},
-{19577, 18, 103569, {1, 1, 1, 11, 25, 17, 41, 45, 385, 1009, 1573, 1797, 527, 543, 14743, 35789, 63871, 112183}},
-{19578, 18, 103572, {1, 1, 7, 15, 15, 57, 109, 127, 143, 955, 1091, 2585, 3429, 11763, 5849, 53805, 116865, 68895}},
-{19579, 18, 103581, {1, 1, 7, 15, 9, 11, 1, 9, 491, 765, 1835, 3825, 5043, 13091, 4123, 19621, 17687, 241015}},
-{19580, 18, 103609, {1, 3, 5, 7, 25, 51, 117, 193, 91, 451, 1871, 3819, 1881, 8065, 25809, 36257, 107955, 37109}},
-{19581, 18, 103612, {1, 3, 1, 15, 5, 5, 101, 7, 59, 859, 977, 2673, 2825, 3291, 26283, 23467, 28383, 257775}},
-{19582, 18, 103618, {1, 3, 3, 15, 17, 43, 87, 191, 85, 829, 653, 327, 1773, 10101, 2707, 18341, 61435, 242215}},
-{19583, 18, 103637, {1, 3, 7, 13, 27, 43, 127, 253, 403, 81, 505, 2841, 1509, 4951, 23791, 18099, 46747, 192717}},
-{19584, 18, 103644, {1, 1, 1, 9, 31, 15, 127, 29, 171, 999, 1919, 4059, 2781, 2475, 8997, 15459, 37003, 217141}},
-{19585, 18, 103653, {1, 3, 3, 1, 31, 41, 67, 31, 171, 719, 789, 645, 3925, 11117, 1241, 63221, 1087, 59789}},
-{19586, 18, 103663, {1, 1, 1, 9, 17, 41, 107, 13, 405, 879, 1955, 3309, 1281, 10601, 13883, 43987, 111691, 130555}},
-{19587, 18, 103671, {1, 3, 7, 9, 21, 17, 127, 243, 51, 689, 1945, 3769, 7121, 7703, 16825, 34893, 32167, 20167}},
-{19588, 18, 103678, {1, 1, 1, 5, 7, 7, 61, 149, 75, 289, 717, 1951, 5917, 13375, 15683, 27507, 10897, 199009}},
-{19589, 18, 103695, {1, 3, 7, 9, 25, 61, 43, 167, 45, 299, 5, 125, 3289, 13685, 10843, 25535, 98383, 143401}},
-{19590, 18, 103698, {1, 1, 3, 15, 21, 27, 37, 45, 233, 179, 611, 3025, 7887, 9421, 16791, 17147, 49013, 33249}},
-{19591, 18, 103720, {1, 3, 7, 15, 19, 43, 43, 9, 255, 295, 649, 811, 1303, 1989, 5401, 53891, 42679, 66879}},
-{19592, 18, 103723, {1, 1, 7, 7, 25, 31, 89, 199, 455, 733, 295, 1157, 4375, 7341, 7823, 6025, 56311, 257579}},
-{19593, 18, 103738, {1, 1, 7, 3, 1, 51, 15, 29, 35, 917, 1839, 741, 1089, 8615, 4967, 34047, 32981, 200693}},
-{19594, 18, 103743, {1, 3, 3, 11, 21, 13, 71, 53, 315, 801, 1015, 3829, 2297, 6649, 28501, 18173, 83121, 107195}},
-{19595, 18, 103745, {1, 1, 7, 7, 1, 5, 127, 103, 435, 707, 7, 1045, 187, 10927, 32395, 24999, 58463, 94069}},
-{19596, 18, 103757, {1, 1, 7, 9, 11, 25, 73, 57, 231, 455, 1033, 2899, 2861, 8811, 21671, 16115, 97807, 221791}},
-{19597, 18, 103810, {1, 3, 5, 11, 11, 19, 105, 37, 181, 1, 1231, 2275, 4789, 13071, 24843, 25901, 123711, 145609}},
-{19598, 18, 103822, {1, 3, 7, 13, 7, 7, 21, 215, 393, 43, 1713, 2921, 1959, 14417, 17109, 55793, 36285, 81731}},
-{19599, 18, 103855, {1, 1, 5, 15, 29, 15, 5, 115, 15, 795, 1535, 2473, 3663, 10123, 20721, 32739, 21141, 217731}},
-{19600, 18, 103887, {1, 1, 3, 1, 15, 13, 21, 49, 293, 689, 985, 3949, 3329, 7167, 16925, 15069, 47345, 192749}},
-{19601, 18, 103905, {1, 3, 3, 7, 5, 27, 85, 11, 337, 651, 777, 1775, 5279, 15229, 21473, 36561, 85293, 27893}},
-{19602, 18, 103915, {1, 3, 7, 1, 15, 29, 7, 199, 71, 893, 1587, 1831, 3891, 3299, 14323, 23165, 28199, 84055}},
-{19603, 18, 103925, {1, 1, 1, 7, 9, 27, 15, 75, 497, 127, 433, 1781, 3711, 12659, 3765, 40827, 112425, 36281}},
-{19604, 18, 103929, {1, 1, 5, 1, 31, 59, 9, 91, 301, 217, 2013, 2015, 265, 3795, 14609, 13389, 5451, 260169}},
-{19605, 18, 103945, {1, 1, 1, 15, 19, 43, 85, 37, 33, 687, 1253, 2615, 4027, 3741, 13971, 21261, 106261, 204233}},
-{19606, 18, 103954, {1, 1, 7, 9, 31, 45, 105, 111, 207, 433, 633, 3949, 8057, 5049, 23657, 12227, 86251, 218077}},
-{19607, 18, 103969, {1, 3, 5, 11, 13, 33, 1, 67, 117, 595, 1835, 287, 2509, 14841, 1525, 15761, 61319, 182531}},
-{19608, 18, 104011, {1, 1, 3, 9, 7, 43, 105, 85, 17, 349, 1769, 3945, 31, 4907, 9373, 22447, 70905, 29189}},
-{19609, 18, 104055, {1, 1, 5, 5, 9, 19, 93, 179, 95, 255, 1807, 2717, 4757, 15025, 19479, 63499, 42441, 236519}},
-{19610, 18, 104111, {1, 1, 1, 1, 21, 35, 1, 101, 343, 1023, 1311, 347, 301, 8419, 23367, 31543, 51661, 148277}},
-{19611, 18, 104116, {1, 1, 7, 11, 23, 37, 113, 207, 147, 743, 1905, 1683, 3733, 5659, 22491, 62129, 111671, 227019}},
-{19612, 18, 104125, {1, 1, 3, 13, 27, 5, 21, 207, 445, 319, 1355, 2541, 2853, 583, 1261, 64477, 18337, 91611}},
-{19613, 18, 104145, {1, 3, 5, 3, 1, 31, 51, 55, 487, 735, 1599, 523, 5323, 10855, 28717, 62103, 18671, 143885}},
-{19614, 18, 104162, {1, 3, 1, 1, 15, 5, 79, 107, 173, 747, 1213, 1151, 875, 12759, 27115, 16403, 31349, 208909}},
-{19615, 18, 104176, {1, 3, 5, 9, 13, 57, 35, 121, 135, 237, 1707, 3655, 8109, 3623, 5119, 27645, 49401, 46453}},
-{19616, 18, 104193, {1, 3, 7, 11, 27, 3, 103, 231, 43, 515, 1279, 499, 1355, 2605, 11587, 33641, 81661, 29441}},
-{19617, 18, 104199, {1, 3, 5, 7, 13, 27, 55, 191, 81, 185, 527, 519, 4555, 3349, 24533, 60635, 40009, 230761}},
-{19618, 18, 104224, {1, 1, 5, 3, 13, 35, 75, 211, 67, 305, 705, 543, 3819, 16265, 9867, 64309, 35047, 24873}},
-{19619, 18, 104236, {1, 3, 1, 1, 11, 37, 75, 3, 145, 327, 1243, 3291, 7127, 5009, 7757, 59567, 90459, 98035}},
-{19620, 18, 104247, {1, 3, 5, 9, 9, 5, 71, 29, 243, 41, 447, 2597, 1243, 12899, 19681, 30523, 90799, 142279}},
-{19621, 18, 104254, {1, 3, 3, 3, 15, 21, 25, 101, 451, 651, 143, 3899, 3377, 4855, 23843, 25047, 87951, 239229}},
-{19622, 18, 104289, {1, 1, 1, 1, 23, 29, 25, 31, 227, 43, 399, 723, 693, 12379, 11343, 46123, 105435, 224997}},
-{19623, 18, 104325, {1, 1, 7, 3, 21, 47, 77, 57, 397, 689, 267, 813, 1279, 1727, 7451, 34025, 90273, 111663}},
-{19624, 18, 104332, {1, 1, 5, 3, 25, 61, 7, 137, 271, 723, 495, 2575, 3695, 4947, 31973, 47835, 107003, 221839}},
-{19625, 18, 104335, {1, 3, 1, 7, 5, 25, 21, 95, 323, 3, 613, 1721, 2551, 8803, 6803, 52765, 34543, 110945}},
-{19626, 18, 104353, {1, 3, 5, 9, 27, 23, 123, 193, 63, 161, 1395, 679, 161, 13719, 29321, 19243, 51947, 229547}},
-{19627, 18, 104363, {1, 3, 5, 15, 15, 37, 127, 103, 439, 513, 989, 1393, 3761, 9109, 20649, 18171, 69939, 117447}},
-{19628, 18, 104371, {1, 1, 7, 9, 7, 57, 87, 159, 195, 821, 57, 2469, 7693, 6759, 32595, 41109, 94785, 53381}},
-{19629, 18, 104373, {1, 3, 3, 7, 17, 63, 41, 7, 437, 469, 1453, 3741, 7591, 5563, 11819, 23861, 129777, 119731}},
-{19630, 18, 104406, {1, 1, 3, 3, 27, 55, 21, 145, 243, 991, 687, 909, 2105, 4485, 9095, 3677, 53819, 183027}},
-{19631, 18, 104412, {1, 1, 1, 15, 13, 61, 27, 81, 95, 37, 1439, 973, 7613, 5749, 16811, 26801, 105745, 8847}},
-{19632, 18, 104440, {1, 3, 1, 9, 15, 17, 111, 61, 27, 373, 89, 2729, 6397, 4899, 11297, 4403, 30657, 207379}},
-{19633, 18, 104459, {1, 3, 5, 15, 19, 9, 19, 19, 497, 667, 105, 601, 6715, 6355, 4231, 19241, 101771, 105651}},
-{19634, 18, 104461, {1, 1, 3, 9, 11, 11, 115, 109, 177, 753, 997, 2119, 5969, 13377, 13285, 25373, 105023, 158393}},
-{19635, 18, 104469, {1, 3, 5, 15, 27, 23, 19, 117, 129, 457, 1973, 2171, 8071, 2093, 13407, 9295, 82967, 184753}},
-{19636, 18, 104479, {1, 1, 7, 5, 1, 45, 9, 25, 307, 629, 1169, 2859, 3987, 11411, 13609, 44993, 26019, 107003}},
-{19637, 18, 104483, {1, 1, 1, 13, 29, 15, 13, 163, 203, 885, 281, 1605, 8001, 899, 4081, 65467, 61283, 198963}},
-{19638, 18, 104490, {1, 1, 3, 5, 27, 9, 89, 193, 375, 633, 1807, 2069, 3467, 3167, 23751, 39115, 90093, 190365}},
-{19639, 18, 104500, {1, 3, 3, 5, 1, 1, 19, 161, 21, 745, 493, 2227, 7993, 3337, 27041, 4817, 58963, 237015}},
-{19640, 18, 104536, {1, 3, 5, 15, 15, 45, 51, 145, 299, 787, 1059, 2407, 1143, 775, 17473, 22235, 18241, 103897}},
-{19641, 18, 104560, {1, 1, 1, 9, 11, 35, 75, 195, 281, 935, 113, 3009, 4797, 7221, 12475, 18563, 10315, 255541}},
-{19642, 18, 104569, {1, 1, 5, 7, 25, 9, 121, 179, 303, 511, 2041, 1485, 529, 13843, 29013, 28139, 63237, 21259}},
-{19643, 18, 104588, {1, 3, 7, 11, 9, 21, 61, 177, 63, 179, 679, 17, 4069, 8929, 14499, 53913, 27925, 48449}},
-{19644, 18, 104591, {1, 3, 5, 3, 9, 27, 111, 247, 253, 175, 1591, 3583, 3351, 9039, 597, 23859, 126585, 157367}},
-{19645, 18, 104621, {1, 1, 7, 9, 1, 9, 29, 1, 273, 89, 767, 1873, 39, 10487, 29857, 23577, 67457, 44571}},
-{19646, 18, 104661, {1, 1, 7, 5, 5, 23, 13, 181, 283, 333, 21, 1409, 5937, 8981, 7445, 61267, 21729, 32677}},
-{19647, 18, 104675, {1, 3, 1, 15, 31, 5, 45, 253, 179, 91, 341, 359, 4269, 7567, 23699, 30589, 42909, 126171}},
-{19648, 18, 104684, {1, 3, 7, 7, 23, 45, 15, 93, 115, 873, 49, 845, 827, 14357, 20163, 41565, 37105, 120331}},
-{19649, 18, 104713, {1, 1, 7, 7, 15, 25, 55, 175, 11, 457, 1537, 1937, 807, 11399, 27751, 16935, 75231, 204039}},
-{19650, 18, 104747, {1, 3, 7, 13, 1, 37, 67, 145, 471, 1013, 1273, 4093, 4449, 4433, 29063, 205, 93249, 140383}},
-{19651, 18, 104750, {1, 3, 1, 13, 1, 57, 85, 223, 349, 125, 863, 2179, 7813, 8817, 1767, 19169, 41367, 65883}},
-{19652, 18, 104757, {1, 3, 3, 15, 21, 39, 3, 31, 67, 505, 271, 505, 5495, 4183, 3631, 4567, 48061, 149565}},
-{19653, 18, 104775, {1, 1, 7, 11, 13, 39, 109, 201, 287, 1013, 1505, 3105, 3845, 1963, 4361, 61753, 29145, 146235}},
-{19654, 18, 104782, {1, 3, 5, 3, 29, 39, 71, 99, 501, 53, 835, 3295, 5335, 1017, 25913, 63637, 115353, 210509}},
-{19655, 18, 104803, {1, 3, 1, 13, 9, 53, 33, 177, 419, 63, 793, 1329, 2261, 11633, 18805, 49771, 47533, 74949}},
-{19656, 18, 104820, {1, 3, 7, 11, 7, 49, 123, 237, 195, 17, 1919, 1911, 4135, 11829, 26307, 34905, 114361, 228655}},
-{19657, 18, 104824, {1, 3, 5, 3, 5, 57, 65, 161, 195, 857, 1187, 2303, 1975, 2555, 26065, 17963, 57403, 136193}},
-{19658, 18, 104829, {1, 1, 3, 11, 1, 5, 105, 217, 229, 769, 1393, 2419, 7751, 14293, 9407, 4569, 30663, 89345}},
-{19659, 18, 104830, {1, 3, 3, 7, 23, 15, 15, 189, 67, 863, 485, 2435, 5145, 10537, 16485, 50369, 118245, 253201}},
-{19660, 18, 104836, {1, 1, 1, 5, 27, 27, 47, 129, 383, 227, 115, 3027, 1575, 15765, 10207, 4885, 125707, 184703}},
-{19661, 18, 104851, {1, 3, 5, 5, 17, 9, 45, 55, 151, 751, 415, 2139, 8071, 2309, 27641, 29743, 47183, 21437}},
-{19662, 18, 104882, {1, 3, 3, 7, 9, 47, 51, 31, 261, 237, 1695, 1065, 4503, 7167, 25791, 39659, 90145, 130481}},
-{19663, 18, 104920, {1, 1, 3, 3, 21, 27, 53, 249, 407, 779, 1315, 1005, 6953, 14959, 2265, 61645, 118623, 254067}},
-{19664, 18, 104941, {1, 3, 1, 9, 13, 25, 33, 225, 467, 325, 1513, 1237, 1569, 8749, 1587, 4699, 19893, 163597}},
-{19665, 18, 104963, {1, 3, 5, 5, 29, 29, 1, 55, 437, 575, 149, 791, 4243, 4405, 22963, 64125, 21631, 25819}},
-{19666, 18, 104989, {1, 3, 5, 3, 25, 9, 19, 27, 419, 139, 2035, 2065, 1925, 11499, 20053, 13161, 15115, 120891}},
-{19667, 18, 104999, {1, 1, 5, 9, 7, 9, 113, 3, 195, 555, 863, 595, 6569, 9819, 14727, 38285, 13737, 130903}},
-{19668, 18, 105006, {1, 1, 3, 7, 19, 17, 35, 107, 489, 285, 247, 3103, 2919, 11163, 2811, 62081, 42989, 24495}},
-{19669, 18, 105040, {1, 3, 1, 15, 17, 5, 123, 221, 117, 689, 1567, 3803, 5801, 14121, 23263, 8851, 41559, 226271}},
-{19670, 18, 105066, {1, 1, 1, 15, 21, 39, 87, 135, 485, 59, 1899, 2483, 2599, 8783, 6129, 55407, 7291, 217117}},
-{19671, 18, 105089, {1, 1, 3, 11, 27, 53, 45, 241, 51, 829, 121, 3047, 6785, 15127, 13923, 47913, 9087, 112005}},
-{19672, 18, 105120, {1, 1, 1, 13, 5, 9, 45, 37, 235, 497, 871, 1471, 2895, 247, 9085, 39611, 63445, 218391}},
-{19673, 18, 105125, {1, 1, 5, 3, 5, 29, 23, 155, 339, 293, 535, 1569, 2625, 2867, 4639, 53049, 88721, 96903}},
-{19674, 18, 105137, {1, 1, 3, 15, 5, 25, 17, 45, 47, 683, 949, 1381, 5929, 9539, 3345, 59883, 19071, 200411}},
-{19675, 18, 105179, {1, 1, 1, 11, 11, 5, 71, 15, 469, 749, 1763, 541, 7109, 11731, 8463, 35145, 121795, 219441}},
-{19676, 18, 105215, {1, 3, 7, 11, 5, 17, 63, 159, 69, 993, 1519, 1531, 6913, 3901, 22131, 42909, 41299, 261813}},
-{19677, 18, 105244, {1, 1, 3, 5, 21, 27, 27, 197, 339, 275, 2011, 2263, 855, 1939, 21561, 30577, 6515, 124417}},
-{19678, 18, 105258, {1, 3, 5, 15, 25, 35, 91, 31, 269, 857, 327, 3643, 3211, 14401, 18399, 9007, 12897, 25555}},
-{19679, 18, 105263, {1, 1, 7, 15, 19, 47, 127, 157, 407, 867, 943, 1509, 3113, 49, 32131, 46975, 130013, 66457}},
-{19680, 18, 105280, {1, 3, 3, 13, 31, 45, 59, 135, 67, 825, 157, 2441, 2851, 2355, 28115, 14075, 106317, 145945}},
-{19681, 18, 105286, {1, 1, 1, 15, 27, 27, 5, 211, 85, 749, 671, 1341, 6865, 10027, 14419, 20159, 126647, 147893}},
-{19682, 18, 105380, {1, 1, 1, 7, 25, 49, 115, 231, 65, 161, 1409, 573, 2859, 639, 12567, 58459, 73781, 136893}},
-{19683, 18, 105397, {1, 1, 1, 7, 11, 57, 97, 141, 327, 975, 1799, 3051, 365, 9331, 14583, 16723, 113153, 224127}},
-{19684, 18, 105409, {1, 3, 1, 13, 13, 17, 105, 109, 151, 41, 1903, 1685, 2285, 5697, 16559, 34133, 106045, 203217}},
-{19685, 18, 105427, {1, 1, 1, 3, 29, 61, 43, 255, 269, 277, 1847, 3781, 7991, 131, 9833, 34305, 10763, 41869}},
-{19686, 18, 105452, {1, 1, 7, 3, 11, 1, 85, 89, 247, 99, 419, 2041, 3729, 10301, 5291, 36033, 31749, 261871}},
-{19687, 18, 105469, {1, 3, 7, 9, 27, 27, 41, 3, 303, 893, 697, 1631, 5015, 4233, 22827, 3913, 22245, 121193}},
-{19688, 18, 105472, {1, 3, 3, 13, 19, 11, 15, 239, 419, 123, 1213, 185, 4465, 4909, 25421, 18363, 72537, 167939}},
-{19689, 18, 105477, {1, 1, 3, 5, 13, 49, 57, 197, 19, 877, 1465, 2933, 5909, 7147, 1039, 37035, 91209, 126013}},
-{19690, 18, 105490, {1, 1, 3, 5, 23, 7, 63, 179, 59, 47, 1501, 1863, 2949, 13959, 28131, 29705, 107975, 155251}},
-{19691, 18, 105505, {1, 1, 1, 5, 25, 51, 77, 169, 327, 585, 1531, 3367, 3075, 6313, 26725, 453, 68635, 173787}},
-{19692, 18, 105529, {1, 3, 7, 9, 5, 15, 43, 45, 311, 367, 297, 2249, 7507, 4785, 22685, 37279, 121683, 141453}},
-{19693, 18, 105530, {1, 3, 7, 15, 17, 33, 43, 251, 281, 345, 1659, 3729, 7629, 6179, 26107, 64255, 88003, 2545}},
-{19694, 18, 105604, {1, 3, 7, 9, 17, 13, 71, 49, 341, 495, 1975, 173, 5773, 3821, 6615, 50917, 53781, 75557}},
-{19695, 18, 105614, {1, 1, 5, 13, 17, 21, 121, 35, 195, 367, 1191, 1331, 6423, 8425, 7705, 59117, 44575, 225431}},
-{19696, 18, 105622, {1, 1, 1, 5, 25, 39, 89, 65, 449, 491, 211, 2949, 4493, 23, 22571, 4801, 50525, 222563}},
-{19697, 18, 105625, {1, 1, 7, 5, 7, 21, 15, 171, 443, 225, 577, 1841, 8139, 15071, 6095, 60185, 71957, 244753}},
-{19698, 18, 105652, {1, 1, 5, 9, 31, 33, 21, 195, 415, 1003, 441, 627, 2339, 8245, 11187, 55933, 59045, 177455}},
-{19699, 18, 105687, {1, 1, 3, 9, 31, 29, 7, 15, 31, 577, 1435, 1317, 2923, 3807, 29693, 45857, 61787, 213565}},
-{19700, 18, 105693, {1, 3, 7, 15, 17, 51, 65, 87, 295, 811, 753, 1113, 7695, 275, 28331, 46363, 53247, 166993}},
-{19701, 18, 105707, {1, 1, 5, 11, 15, 31, 31, 47, 273, 383, 1831, 3821, 1337, 13257, 415, 35453, 15293, 173095}},
-{19702, 18, 105721, {1, 3, 1, 13, 19, 21, 63, 199, 159, 475, 1257, 3119, 7083, 2861, 21099, 16873, 83583, 186289}},
-{19703, 18, 105730, {1, 1, 7, 13, 15, 23, 11, 103, 387, 899, 261, 2863, 3681, 5683, 5587, 64655, 7411, 148633}},
-{19704, 18, 105736, {1, 3, 1, 13, 1, 45, 5, 173, 379, 287, 1451, 2253, 3811, 10963, 20285, 59681, 81285, 48523}},
-{19705, 18, 105753, {1, 1, 5, 9, 27, 17, 57, 25, 499, 289, 1083, 3057, 793, 5251, 10519, 36647, 67751, 237487}},
-{19706, 18, 105759, {1, 1, 3, 1, 17, 13, 23, 73, 1, 951, 111, 3769, 3611, 4827, 10081, 55919, 21411, 127303}},
-{19707, 18, 105760, {1, 3, 1, 1, 29, 35, 93, 139, 179, 217, 1839, 1907, 4365, 1813, 31985, 28927, 39319, 233413}},
-{19708, 18, 105802, {1, 1, 1, 7, 7, 47, 37, 127, 449, 473, 311, 3833, 3263, 4163, 15985, 50159, 82685, 73273}},
-{19709, 18, 105822, {1, 1, 1, 3, 3, 5, 69, 95, 101, 115, 1575, 63, 1897, 13733, 22149, 8793, 82983, 192553}},
-{19710, 18, 105832, {1, 3, 1, 5, 3, 57, 121, 13, 291, 975, 505, 3105, 6929, 12737, 25869, 29173, 16757, 17733}},
-{19711, 18, 105865, {1, 1, 3, 13, 13, 23, 51, 51, 239, 795, 877, 1547, 6533, 11497, 14309, 32941, 128109, 187313}},
-{19712, 18, 105873, {1, 1, 3, 5, 19, 37, 57, 223, 509, 379, 1235, 1881, 4133, 13219, 5479, 36781, 56155, 231001}},
-{19713, 18, 105874, {1, 1, 1, 5, 25, 45, 111, 183, 37, 875, 1487, 3771, 5593, 6835, 10921, 40697, 114455, 259491}},
-{19714, 18, 105880, {1, 1, 3, 11, 13, 5, 43, 47, 7, 435, 1543, 3835, 1631, 8889, 23567, 24705, 26687, 14261}},
-{19715, 18, 105899, {1, 3, 3, 11, 1, 13, 51, 171, 433, 1011, 679, 1307, 1683, 7379, 7163, 29727, 40209, 259973}},
-{19716, 18, 105902, {1, 3, 1, 5, 25, 33, 111, 11, 303, 815, 1883, 263, 7907, 12637, 19203, 64151, 55739, 240509}},
-{19717, 18, 105909, {1, 3, 5, 7, 23, 51, 3, 183, 425, 47, 231, 807, 1891, 10943, 17873, 20209, 60871, 30269}},
-{19718, 18, 105919, {1, 1, 1, 1, 1, 23, 11, 183, 351, 5, 37, 3883, 1291, 15933, 11379, 53057, 61389, 240547}},
-{19719, 18, 105922, {1, 3, 1, 5, 7, 53, 97, 29, 239, 805, 1929, 1001, 5103, 11, 24695, 7825, 109755, 254717}},
-{19720, 18, 105946, {1, 3, 3, 11, 15, 37, 115, 117, 391, 313, 1761, 3627, 3931, 10277, 1767, 25401, 123827, 60463}},
-{19721, 18, 105975, {1, 1, 7, 9, 9, 61, 23, 65, 473, 579, 1979, 415, 629, 3613, 27409, 46909, 3281, 3883}},
-{19722, 18, 105992, {1, 3, 3, 13, 25, 17, 71, 247, 297, 451, 153, 1949, 2727, 6427, 19815, 54013, 129363, 248237}},
-{19723, 18, 106005, {1, 1, 7, 7, 29, 9, 57, 171, 159, 287, 693, 1365, 4665, 5255, 15013, 21225, 125409, 5893}},
-{19724, 18, 106057, {1, 3, 3, 1, 9, 43, 13, 139, 359, 267, 115, 2025, 693, 4789, 10353, 60459, 30835, 56575}},
-{19725, 18, 106081, {1, 1, 1, 7, 23, 35, 35, 77, 245, 705, 75, 2841, 1683, 6109, 19661, 49021, 25019, 7297}},
-{19726, 18, 106093, {1, 3, 1, 5, 1, 19, 49, 53, 19, 435, 1471, 409, 7051, 7057, 3621, 42925, 59551, 70941}},
-{19727, 18, 106117, {1, 3, 7, 5, 21, 27, 39, 221, 389, 255, 537, 597, 7729, 10473, 6657, 13261, 11303, 112409}},
-{19728, 18, 106127, {1, 3, 7, 13, 29, 29, 81, 107, 329, 25, 537, 561, 2247, 10371, 30031, 20537, 28437, 113319}},
-{19729, 18, 106135, {1, 1, 5, 9, 9, 7, 89, 155, 337, 829, 755, 3259, 3563, 11849, 31179, 43297, 79601, 187545}},
-{19730, 18, 106141, {1, 3, 3, 5, 11, 63, 101, 159, 357, 627, 587, 3233, 405, 4083, 5953, 44541, 110723, 240573}},
-{19731, 18, 106189, {1, 1, 3, 15, 5, 39, 87, 231, 455, 195, 1603, 315, 3869, 6375, 745, 28349, 56469, 119033}},
-{19732, 18, 106190, {1, 1, 7, 1, 11, 7, 79, 47, 391, 585, 1299, 3237, 7345, 15959, 4293, 43285, 111737, 215923}},
-{19733, 18, 106197, {1, 1, 3, 15, 21, 53, 113, 73, 265, 589, 299, 289, 3983, 1653, 17407, 15287, 53199, 44221}},
-{19734, 18, 106214, {1, 3, 1, 3, 1, 13, 31, 41, 509, 523, 401, 2647, 2731, 5699, 15649, 51737, 81249, 230865}},
-{19735, 18, 106237, {1, 3, 5, 3, 15, 53, 91, 209, 249, 243, 1119, 2531, 319, 9259, 26555, 59579, 28767, 235073}},
-{19736, 18, 106245, {1, 1, 1, 13, 29, 25, 57, 3, 413, 945, 841, 1151, 7167, 2545, 7283, 3947, 109375, 148677}},
-{19737, 18, 106257, {1, 3, 3, 7, 29, 27, 81, 141, 21, 771, 577, 897, 73, 13081, 30035, 49213, 90627, 7483}},
-{19738, 18, 106300, {1, 3, 1, 13, 23, 11, 19, 159, 183, 789, 683, 2071, 7107, 3025, 27333, 9571, 69621, 48529}},
-{19739, 18, 106335, {1, 3, 1, 9, 5, 43, 7, 123, 341, 75, 1709, 135, 7929, 14563, 6849, 32783, 91971, 223789}},
-{19740, 18, 106351, {1, 1, 7, 3, 19, 13, 45, 229, 7, 559, 1895, 2649, 7593, 1063, 17715, 45019, 29743, 37819}},
-{19741, 18, 106370, {1, 1, 5, 3, 11, 25, 11, 169, 249, 415, 249, 209, 2223, 5947, 23381, 12109, 37697, 131729}},
-{19742, 18, 106375, {1, 1, 1, 7, 19, 47, 125, 117, 235, 825, 801, 921, 2363, 1261, 20529, 65445, 55315, 173561}},
-{19743, 18, 106376, {1, 1, 1, 1, 5, 39, 31, 11, 239, 333, 727, 3991, 1453, 2201, 18129, 3513, 112057, 109673}},
-{19744, 18, 106384, {1, 1, 7, 5, 21, 59, 37, 255, 261, 1, 1401, 1101, 1233, 3813, 22809, 39389, 66263, 191623}},
-{19745, 18, 106403, {1, 3, 1, 7, 5, 51, 73, 85, 319, 671, 1149, 1631, 6021, 10711, 3813, 36485, 106147, 202021}},
-{19746, 18, 106405, {1, 3, 3, 13, 7, 63, 59, 253, 337, 453, 61, 209, 2809, 10429, 28069, 55971, 57985, 244779}},
-{19747, 18, 106406, {1, 1, 1, 9, 27, 59, 45, 101, 427, 713, 1667, 2965, 6161, 1235, 8793, 2387, 66031, 85151}},
-{19748, 18, 106429, {1, 1, 3, 1, 5, 25, 101, 7, 449, 149, 823, 725, 6803, 11949, 13009, 14785, 45633, 241957}},
-{19749, 18, 106447, {1, 3, 7, 15, 29, 45, 103, 151, 159, 23, 1353, 3541, 5909, 4173, 31391, 16179, 38289, 206603}},
-{19750, 18, 106466, {1, 1, 7, 7, 23, 3, 97, 29, 141, 383, 379, 3189, 4399, 4545, 30797, 55827, 126223, 97049}},
-{19751, 18, 106495, {1, 3, 3, 7, 25, 35, 61, 15, 349, 929, 65, 3697, 7637, 12239, 29051, 36001, 114513, 151069}},
-{19752, 18, 106532, {1, 3, 3, 11, 19, 1, 23, 245, 9, 689, 1251, 1043, 2393, 15817, 31561, 21059, 3435, 228091}},
-{19753, 18, 106542, {1, 3, 7, 3, 23, 17, 121, 147, 427, 47, 905, 3877, 2301, 15709, 13599, 48895, 108955, 53219}},
-{19754, 18, 106547, {1, 3, 7, 3, 25, 31, 53, 143, 1, 841, 1691, 749, 6713, 5373, 23487, 25749, 13911, 240923}},
-{19755, 18, 106564, {1, 3, 5, 3, 7, 39, 101, 83, 159, 187, 583, 721, 7745, 1119, 61, 27319, 35157, 241729}},
-{19756, 18, 106576, {1, 1, 5, 11, 27, 21, 79, 199, 179, 463, 987, 3909, 1741, 503, 12339, 15323, 4063, 180337}},
-{19757, 18, 106586, {1, 3, 7, 11, 23, 43, 7, 115, 489, 215, 209, 3213, 4057, 13221, 27061, 52037, 34921, 36385}},
-{19758, 18, 106592, {1, 1, 7, 1, 15, 13, 113, 55, 207, 839, 1939, 4095, 5629, 7647, 12753, 59739, 60779, 196589}},
-{19759, 18, 106597, {1, 1, 1, 5, 5, 13, 113, 243, 297, 513, 1615, 1513, 1247, 4025, 20901, 44775, 86987, 75437}},
-{19760, 18, 106610, {1, 1, 3, 7, 7, 35, 77, 115, 223, 929, 1683, 949, 2191, 15533, 29471, 24103, 102475, 173027}},
-{19761, 18, 106612, {1, 3, 1, 11, 23, 37, 7, 179, 287, 267, 319, 3147, 1481, 12297, 28185, 51423, 7505, 236225}},
-{19762, 18, 106635, {1, 1, 3, 5, 27, 5, 71, 95, 289, 121, 939, 3543, 365, 4903, 10091, 3903, 111155, 83517}},
-{19763, 18, 106640, {1, 1, 7, 9, 29, 3, 87, 245, 313, 973, 1181, 3389, 3697, 13237, 13703, 31557, 17269, 17329}},
-{19764, 18, 106673, {1, 1, 5, 11, 5, 41, 117, 51, 239, 907, 809, 741, 5327, 3403, 11825, 46981, 93485, 38053}},
-{19765, 18, 106691, {1, 1, 7, 1, 25, 41, 5, 169, 11, 599, 1451, 2189, 7255, 8441, 11169, 58313, 4387, 69}},
-{19766, 18, 106724, {1, 3, 1, 13, 5, 21, 75, 229, 153, 355, 1511, 175, 4793, 12111, 25321, 39983, 84205, 195003}},
-{19767, 18, 106731, {1, 1, 7, 1, 17, 61, 67, 181, 69, 149, 921, 1107, 6319, 431, 29481, 12507, 13109, 29527}},
-{19768, 18, 106741, {1, 1, 5, 5, 27, 47, 69, 119, 469, 193, 513, 1573, 7421, 2723, 20997, 59585, 49645, 261259}},
-{19769, 18, 106748, {1, 1, 3, 9, 27, 41, 41, 3, 181, 803, 1281, 2937, 6745, 5629, 8403, 18987, 98411, 128321}},
-{19770, 18, 106765, {1, 3, 3, 9, 5, 29, 55, 223, 309, 841, 1049, 1163, 3497, 8935, 8529, 51367, 90693, 77463}},
-{19771, 18, 106789, {1, 3, 5, 3, 3, 59, 23, 31, 309, 907, 107, 3471, 4365, 14463, 24093, 35435, 24587, 151163}},
-{19772, 18, 106822, {1, 3, 3, 1, 11, 37, 99, 95, 485, 601, 1797, 891, 5645, 8927, 22085, 5185, 18495, 260455}},
-{19773, 18, 106856, {1, 3, 7, 15, 31, 61, 5, 177, 159, 287, 311, 1377, 1419, 4387, 25297, 22505, 100937, 223785}},
-{19774, 18, 106861, {1, 3, 3, 3, 27, 31, 45, 171, 95, 507, 1475, 4013, 2781, 133, 6857, 3367, 103455, 69559}},
-{19775, 18, 106870, {1, 3, 3, 7, 9, 51, 47, 247, 213, 665, 1929, 2799, 5513, 9183, 20197, 14831, 75277, 187565}},
-{19776, 18, 106883, {1, 3, 1, 9, 13, 11, 15, 253, 145, 31, 847, 1579, 5513, 9, 3327, 46049, 16709, 56353}},
-{19777, 18, 106895, {1, 3, 3, 3, 9, 17, 59, 131, 3, 621, 1209, 3415, 2999, 127, 629, 7925, 6109, 59743}},
-{19778, 18, 106928, {1, 1, 5, 15, 29, 35, 87, 197, 495, 671, 51, 293, 3943, 7969, 4739, 10161, 119943, 97217}},
-{19779, 18, 106938, {1, 1, 1, 9, 25, 57, 61, 197, 139, 899, 783, 3835, 3407, 16301, 19033, 33359, 56309, 16237}},
-{19780, 18, 106979, {1, 1, 5, 11, 25, 47, 95, 121, 197, 511, 227, 2281, 5805, 10581, 14885, 19685, 28075, 25431}},
-{19781, 18, 106985, {1, 1, 3, 9, 1, 43, 59, 105, 319, 45, 1567, 905, 7641, 2199, 3979, 13717, 22829, 44777}},
-{19782, 18, 107005, {1, 3, 7, 1, 19, 49, 105, 53, 227, 293, 989, 697, 2553, 4561, 14851, 8999, 74815, 207475}},
-{19783, 18, 107012, {1, 1, 5, 11, 23, 3, 85, 29, 419, 847, 1385, 3857, 641, 14951, 25629, 18019, 2497, 24723}},
-{19784, 18, 107019, {1, 3, 5, 15, 5, 11, 51, 225, 179, 695, 787, 663, 7051, 3595, 4987, 53315, 88693, 7915}},
-{19785, 18, 107045, {1, 3, 1, 13, 17, 51, 51, 247, 431, 555, 603, 3301, 443, 629, 26509, 32047, 54433, 208297}},
-{19786, 18, 107052, {1, 3, 7, 7, 13, 41, 95, 105, 135, 443, 377, 1259, 3301, 6945, 11677, 33869, 107799, 186567}},
-{19787, 18, 107082, {1, 1, 5, 7, 31, 17, 85, 129, 409, 781, 983, 25, 6877, 83, 12625, 31919, 41989, 55195}},
-{19788, 18, 107089, {1, 1, 3, 3, 7, 45, 37, 45, 237, 967, 1371, 657, 7983, 3121, 32707, 25757, 49987, 92683}},
-{19789, 18, 107118, {1, 3, 1, 1, 19, 57, 63, 25, 355, 893, 2017, 1671, 7343, 4451, 28243, 22157, 103901, 178017}},
-{19790, 18, 107163, {1, 3, 7, 13, 17, 59, 81, 99, 329, 117, 1395, 2565, 5725, 2371, 343, 4713, 35077, 49793}},
-{19791, 18, 107202, {1, 3, 7, 15, 31, 19, 87, 243, 411, 339, 1063, 117, 1827, 1583, 12571, 23153, 3363, 81695}},
-{19792, 18, 107238, {1, 3, 7, 1, 3, 49, 95, 133, 295, 433, 1885, 843, 6679, 13673, 32277, 59085, 46957, 217037}},
-{19793, 18, 107242, {1, 1, 3, 9, 23, 53, 45, 183, 79, 55, 1267, 283, 3249, 4101, 8107, 54473, 126141, 127235}},
-{19794, 18, 107244, {1, 3, 5, 7, 19, 57, 113, 205, 37, 817, 929, 3643, 2231, 15725, 1733, 7877, 116741, 254529}},
-{19795, 18, 107264, {1, 3, 1, 9, 9, 7, 75, 45, 83, 203, 1401, 445, 1043, 239, 30865, 32189, 91081, 180681}},
-{19796, 18, 107273, {1, 1, 7, 7, 1, 3, 61, 255, 483, 599, 897, 1601, 5189, 13279, 4981, 37235, 117505, 66625}},
-{19797, 18, 107291, {1, 1, 3, 13, 29, 43, 65, 73, 213, 307, 959, 2735, 5155, 16063, 15745, 6225, 50159, 182445}},
-{19798, 18, 107293, {1, 1, 3, 9, 31, 61, 73, 185, 457, 687, 1887, 4041, 3455, 4739, 16399, 40929, 32631, 179031}},
-{19799, 18, 107312, {1, 3, 3, 15, 5, 45, 1, 241, 187, 23, 63, 2497, 7759, 9175, 11003, 40579, 45769, 107133}},
-{19800, 18, 107318, {1, 3, 3, 7, 5, 63, 7, 67, 31, 917, 1825, 2037, 2527, 9767, 2665, 18573, 14289, 21583}},
-{19801, 18, 107335, {1, 1, 5, 15, 15, 25, 51, 127, 261, 925, 1651, 769, 7779, 7327, 7239, 20437, 9947, 144697}},
-{19802, 18, 107349, {1, 1, 5, 1, 5, 13, 99, 7, 269, 135, 345, 1851, 7963, 457, 24573, 32529, 127359, 157755}},
-{19803, 18, 107350, {1, 3, 5, 15, 21, 17, 31, 115, 321, 351, 117, 1301, 2455, 3363, 14213, 62903, 75273, 261119}},
-{19804, 18, 107363, {1, 3, 7, 1, 1, 9, 53, 209, 319, 489, 827, 1365, 4709, 7419, 28213, 56095, 9611, 234877}},
-{19805, 18, 107390, {1, 1, 5, 5, 1, 7, 49, 15, 377, 309, 1701, 1775, 5571, 12437, 27521, 54753, 68977, 138549}},
-{19806, 18, 107405, {1, 1, 3, 11, 9, 29, 67, 21, 411, 647, 983, 1075, 2387, 13355, 1781, 56129, 87235, 260133}},
-{19807, 18, 107408, {1, 3, 1, 11, 5, 57, 71, 159, 345, 853, 745, 3733, 1607, 7265, 20097, 18911, 101141, 70495}},
-{19808, 18, 107427, {1, 1, 3, 9, 1, 43, 127, 127, 471, 465, 1777, 1879, 4655, 12925, 24935, 58445, 78303, 200463}},
-{19809, 18, 107433, {1, 1, 1, 15, 5, 33, 63, 17, 401, 831, 1559, 3547, 7869, 13901, 18185, 9399, 65859, 185315}},
-{19810, 18, 107444, {1, 3, 7, 1, 25, 21, 17, 175, 401, 833, 847, 3593, 1283, 14745, 11827, 1987, 89299, 187369}},
-{19811, 18, 107514, {1, 1, 7, 13, 29, 31, 45, 219, 177, 369, 1313, 3015, 5859, 1829, 8793, 49109, 97581, 233179}},
-{19812, 18, 107522, {1, 3, 3, 15, 17, 31, 61, 215, 231, 495, 1307, 3067, 3187, 8813, 22505, 14055, 30773, 177955}},
-{19813, 18, 107545, {1, 3, 7, 15, 9, 61, 57, 105, 89, 267, 233, 905, 3727, 1841, 31875, 32499, 27003, 208491}},
-{19814, 18, 107582, {1, 3, 1, 11, 31, 9, 63, 55, 213, 209, 1625, 2635, 4335, 15201, 6127, 11097, 37991, 62813}},
-{19815, 18, 107590, {1, 1, 1, 5, 13, 49, 127, 249, 339, 525, 1943, 2935, 3255, 5199, 6869, 6325, 731, 51085}},
-{19816, 18, 107593, {1, 1, 5, 7, 7, 29, 59, 187, 463, 409, 1321, 377, 7361, 8303, 20385, 39649, 81379, 235555}},
-{19817, 18, 107599, {1, 1, 5, 13, 15, 45, 99, 57, 217, 535, 1747, 4081, 4781, 1005, 25197, 23853, 90587, 189579}},
-{19818, 18, 107604, {1, 1, 7, 7, 23, 31, 1, 151, 339, 447, 523, 2609, 5917, 6965, 25815, 62797, 104083, 245917}},
-{19819, 18, 107608, {1, 3, 5, 3, 7, 37, 79, 253, 423, 511, 1477, 3121, 5557, 1413, 31075, 22249, 117639, 243543}},
-{19820, 18, 107627, {1, 1, 3, 7, 5, 31, 93, 117, 135, 235, 745, 3287, 4451, 2487, 15179, 62229, 18247, 150277}},
-{19821, 18, 107638, {1, 1, 7, 15, 31, 57, 125, 219, 433, 629, 1809, 2499, 6083, 7631, 31495, 63183, 28533, 120579}},
-{19822, 18, 107666, {1, 1, 1, 13, 31, 47, 77, 73, 343, 867, 1055, 1121, 3035, 15693, 6971, 50231, 16527, 190795}},
-{19823, 18, 107678, {1, 3, 7, 7, 11, 1, 5, 215, 87, 885, 1429, 1277, 3831, 9341, 22011, 34585, 56167, 65301}},
-{19824, 18, 107701, {1, 3, 1, 15, 13, 53, 91, 59, 277, 819, 453, 3191, 757, 4729, 20605, 4283, 110745, 233655}},
-{19825, 18, 107720, {1, 3, 3, 5, 17, 47, 69, 117, 113, 775, 935, 1879, 2239, 5877, 18337, 50895, 44891, 2759}},
-{19826, 18, 107723, {1, 3, 5, 1, 27, 31, 77, 65, 355, 405, 825, 2419, 3337, 10179, 27665, 35459, 13721, 154227}},
-{19827, 18, 107725, {1, 3, 3, 7, 23, 61, 9, 241, 239, 85, 485, 2659, 5371, 16175, 28691, 49109, 124433, 167033}},
-{19828, 18, 107731, {1, 3, 3, 3, 11, 57, 37, 155, 443, 249, 1913, 1347, 6569, 5357, 4231, 58273, 50707, 57097}},
-{19829, 18, 107737, {1, 1, 3, 3, 1, 7, 87, 115, 259, 807, 45, 2997, 63, 16313, 12507, 39925, 17699, 24411}},
-{19830, 18, 107767, {1, 3, 3, 1, 19, 59, 97, 209, 247, 395, 21, 1803, 2547, 11607, 15703, 58099, 111907, 196101}},
-{19831, 18, 107779, {1, 1, 7, 13, 27, 61, 73, 183, 493, 953, 445, 567, 7373, 15275, 30081, 539, 89365, 3455}},
-{19832, 18, 107788, {1, 3, 1, 3, 25, 35, 3, 105, 243, 781, 1937, 2781, 7849, 2159, 2221, 58005, 89313, 182183}},
-{19833, 18, 107799, {1, 1, 7, 15, 21, 7, 67, 163, 179, 453, 581, 2245, 3915, 8985, 16809, 35113, 93605, 79009}},
-{19834, 18, 107819, {1, 1, 7, 5, 29, 57, 13, 75, 387, 511, 331, 1119, 307, 6145, 3841, 49987, 67335, 120419}},
-{19835, 18, 107833, {1, 3, 1, 5, 13, 21, 119, 207, 453, 943, 137, 2245, 7771, 5737, 9541, 29209, 106867, 110513}},
-{19836, 18, 107881, {1, 3, 7, 13, 7, 3, 99, 129, 245, 687, 883, 1321, 1131, 6661, 7437, 1345, 128247, 167877}},
-{19837, 18, 107901, {1, 1, 3, 11, 7, 57, 59, 3, 217, 549, 85, 2607, 215, 2249, 3963, 42931, 33747, 226265}},
-{19838, 18, 107911, {1, 1, 5, 5, 29, 23, 115, 215, 103, 427, 1689, 831, 3293, 14055, 3735, 49521, 17703, 182887}},
-{19839, 18, 107930, {1, 1, 1, 15, 5, 43, 27, 181, 217, 955, 225, 2731, 7347, 14123, 26169, 4371, 26907, 15017}},
-{19840, 18, 107936, {1, 1, 7, 7, 31, 55, 63, 223, 61, 63, 431, 2779, 3169, 14323, 2945, 63913, 85407, 76511}},
-{19841, 18, 107980, {1, 1, 3, 11, 5, 27, 113, 75, 313, 697, 13, 1853, 7467, 5701, 16749, 17939, 13475, 39807}},
-{19842, 18, 108004, {1, 1, 7, 5, 13, 53, 55, 115, 125, 341, 321, 3291, 2675, 13659, 16819, 45397, 42917, 104361}},
-{19843, 18, 108008, {1, 3, 3, 15, 27, 47, 19, 213, 441, 605, 593, 2287, 4847, 10505, 22185, 36157, 10881, 87799}},
-{19844, 18, 108016, {1, 1, 1, 11, 15, 39, 109, 3, 469, 371, 1743, 2789, 199, 8703, 7407, 3353, 103417, 73319}},
-{19845, 18, 108066, {1, 3, 7, 5, 25, 61, 77, 111, 263, 399, 1579, 3447, 6205, 5945, 28099, 39183, 77003, 115001}},
-{19846, 18, 108071, {1, 1, 1, 3, 1, 7, 57, 193, 379, 923, 151, 2227, 7285, 2371, 24567, 34037, 80655, 125499}},
-{19847, 18, 108107, {1, 3, 5, 7, 13, 15, 5, 193, 55, 319, 1851, 2439, 8071, 5329, 3155, 64669, 18547, 238997}},
-{19848, 18, 108110, {1, 3, 3, 11, 7, 23, 1, 203, 333, 951, 153, 1249, 5093, 407, 361, 14175, 45149, 186291}},
-{19849, 18, 108124, {1, 3, 1, 11, 13, 19, 89, 229, 139, 981, 455, 907, 5109, 8513, 23823, 54933, 69985, 227679}},
-{19850, 18, 108145, {1, 3, 5, 13, 23, 47, 65, 123, 115, 759, 375, 1283, 729, 11045, 22015, 18287, 112603, 75911}},
-{19851, 18, 108148, {1, 1, 3, 1, 5, 43, 91, 123, 219, 409, 517, 3999, 1409, 5949, 15727, 62705, 73573, 198447}},
-{19852, 18, 108158, {1, 3, 3, 3, 5, 23, 95, 51, 275, 455, 1831, 2427, 3779, 10209, 30839, 23393, 25681, 8715}},
-{19853, 18, 108164, {1, 3, 5, 3, 9, 5, 61, 97, 497, 397, 695, 517, 3313, 4911, 1961, 45805, 99135, 216657}},
-{19854, 18, 108197, {1, 1, 1, 7, 13, 41, 19, 31, 103, 1005, 73, 1855, 405, 12395, 19979, 17663, 105183, 28493}},
-{19855, 18, 108198, {1, 3, 1, 11, 27, 27, 69, 149, 1, 225, 1809, 1367, 3663, 6545, 8475, 40837, 64459, 66705}},
-{19856, 18, 108219, {1, 3, 3, 1, 29, 21, 113, 149, 215, 443, 1069, 3437, 1793, 13573, 28285, 33707, 29127, 40715}},
-{19857, 18, 108222, {1, 3, 3, 5, 21, 9, 53, 181, 455, 283, 245, 3999, 875, 9799, 10963, 31603, 34907, 64977}},
-{19858, 18, 108224, {1, 3, 1, 11, 31, 51, 29, 103, 61, 529, 777, 1097, 445, 9169, 6305, 4513, 60189, 164103}},
-{19859, 18, 108227, {1, 1, 1, 3, 21, 5, 87, 11, 461, 637, 1283, 1471, 1429, 2401, 12163, 29401, 30089, 41745}},
-{19860, 18, 108290, {1, 1, 3, 3, 17, 43, 13, 153, 73, 419, 747, 279, 7195, 4383, 26345, 28365, 97753, 208989}},
-{19861, 18, 108302, {1, 3, 7, 1, 17, 55, 103, 151, 327, 575, 1923, 1533, 4699, 2171, 15447, 64047, 59007, 54523}},
-{19862, 18, 108329, {1, 3, 7, 7, 3, 51, 79, 39, 403, 599, 161, 2465, 4911, 10327, 23599, 3267, 44177, 184231}},
-{19863, 18, 108335, {1, 3, 3, 15, 5, 19, 57, 83, 507, 927, 665, 3471, 5037, 2051, 22923, 36813, 97393, 102715}},
-{19864, 18, 108338, {1, 3, 3, 13, 11, 19, 91, 179, 113, 295, 855, 2071, 3265, 4089, 8627, 7461, 23855, 53675}},
-{19865, 18, 108362, {1, 1, 3, 5, 21, 41, 11, 227, 87, 417, 209, 2013, 4849, 5291, 22073, 40235, 71283, 140785}},
-{19866, 18, 108398, {1, 3, 3, 5, 29, 57, 95, 65, 177, 177, 1973, 563, 5249, 337, 7611, 45099, 15443, 46583}},
-{19867, 18, 108405, {1, 1, 7, 3, 3, 5, 107, 75, 31, 293, 821, 1837, 2363, 13621, 8793, 29841, 127201, 131707}},
-{19868, 18, 108409, {1, 1, 1, 5, 1, 45, 69, 61, 157, 999, 183, 3431, 3487, 9461, 17545, 26973, 115527, 58419}},
-{19869, 18, 108431, {1, 1, 7, 7, 27, 5, 125, 153, 191, 745, 125, 2807, 5043, 10657, 24487, 19517, 31735, 42421}},
-{19870, 18, 108449, {1, 1, 7, 9, 25, 37, 73, 255, 141, 229, 1723, 1331, 6089, 13109, 30683, 2335, 111517, 105411}},
-{19871, 18, 108474, {1, 1, 5, 7, 3, 61, 79, 203, 423, 669, 1757, 1725, 4239, 7013, 28591, 61853, 81103, 39813}},
-{19872, 18, 108488, {1, 1, 3, 7, 21, 27, 23, 119, 441, 113, 1019, 285, 53, 8643, 31689, 2629, 126573, 60835}},
-{19873, 18, 108530, {1, 1, 5, 11, 29, 49, 23, 55, 441, 809, 1177, 1371, 5945, 6461, 11537, 12287, 85637, 232065}},
-{19874, 18, 108545, {1, 3, 1, 15, 5, 13, 19, 209, 105, 897, 565, 3209, 487, 9837, 22169, 26317, 39907, 185193}},
-{19875, 18, 108551, {1, 1, 1, 5, 23, 45, 49, 55, 501, 213, 1217, 3159, 733, 5889, 5475, 4953, 37317, 100369}},
-{19876, 18, 108558, {1, 1, 5, 1, 19, 5, 57, 137, 361, 605, 1077, 2015, 5511, 4667, 18457, 45979, 120253, 203397}},
-{19877, 18, 108585, {1, 1, 7, 9, 19, 19, 11, 187, 5, 647, 275, 1265, 7587, 16183, 369, 31885, 58347, 36829}},
-{19878, 18, 108613, {1, 3, 5, 3, 31, 31, 7, 105, 359, 839, 641, 3215, 4807, 13397, 885, 52867, 57125, 180607}},
-{19879, 18, 108638, {1, 1, 7, 9, 19, 45, 43, 211, 429, 757, 1637, 1569, 935, 8899, 24823, 18599, 111373, 190979}},
-{19880, 18, 108642, {1, 1, 7, 7, 13, 47, 3, 241, 467, 209, 323, 3467, 4397, 15395, 15373, 14499, 92443, 65931}},
-{19881, 18, 108653, {1, 3, 3, 5, 5, 9, 67, 115, 45, 279, 1753, 1575, 8127, 9651, 5169, 25643, 29671, 214383}},
-{19882, 18, 108671, {1, 3, 7, 7, 29, 7, 37, 205, 495, 445, 1771, 1439, 3577, 10423, 10865, 26851, 15251, 63373}},
-{19883, 18, 108675, {1, 3, 1, 9, 29, 13, 45, 61, 153, 193, 1407, 1075, 4023, 2367, 1147, 51277, 52975, 123061}},
-{19884, 18, 108684, {1, 3, 3, 3, 31, 25, 113, 173, 345, 565, 145, 3437, 7051, 12557, 27919, 41733, 76717, 192645}},
-{19885, 18, 108687, {1, 3, 3, 7, 3, 55, 35, 219, 55, 467, 635, 3833, 3753, 1099, 15301, 53121, 120807, 70481}},
-{19886, 18, 108696, {1, 3, 7, 7, 13, 1, 121, 191, 71, 193, 1891, 2303, 1401, 9143, 31297, 38979, 43093, 138941}},
-{19887, 18, 108786, {1, 3, 7, 5, 17, 51, 83, 201, 231, 423, 511, 1301, 6075, 475, 2603, 49327, 78565, 220827}},
-{19888, 18, 108792, {1, 3, 1, 7, 5, 61, 23, 11, 9, 711, 251, 1383, 613, 6213, 8921, 27267, 66009, 28575}},
-{19889, 18, 108795, {1, 3, 1, 3, 13, 13, 61, 211, 353, 883, 343, 1089, 2041, 7781, 25285, 9053, 76801, 153009}},
-{19890, 18, 108818, {1, 3, 7, 5, 17, 61, 67, 69, 361, 937, 949, 1483, 2825, 3753, 16533, 17277, 16539, 140521}},
-{19891, 18, 108830, {1, 3, 5, 9, 7, 19, 31, 239, 357, 561, 1583, 3059, 2023, 2213, 11283, 18603, 83487, 162415}},
-{19892, 18, 108836, {1, 1, 3, 15, 15, 59, 9, 43, 353, 203, 765, 1907, 2733, 3747, 30617, 32671, 119005, 72131}},
-{19893, 18, 108839, {1, 3, 1, 7, 17, 61, 55, 113, 439, 75, 703, 2741, 1059, 4561, 15923, 17153, 32563, 79681}},
-{19894, 18, 108851, {1, 1, 1, 15, 11, 57, 91, 245, 187, 185, 1859, 1209, 3247, 10863, 22421, 47287, 26831, 200935}},
-{19895, 18, 108875, {1, 1, 3, 13, 11, 39, 61, 211, 51, 197, 861, 2965, 4691, 9955, 2289, 28795, 61537, 235359}},
-{19896, 18, 108883, {1, 1, 7, 1, 31, 37, 121, 107, 79, 521, 371, 983, 6189, 4515, 25691, 26933, 123189, 70033}},
-{19897, 18, 108895, {1, 3, 3, 15, 19, 33, 31, 237, 35, 877, 1013, 3445, 573, 1145, 27781, 26327, 117451, 142339}},
-{19898, 18, 108908, {1, 3, 3, 15, 15, 9, 17, 185, 151, 499, 493, 1331, 1587, 12657, 22577, 7957, 126253, 57971}},
-{19899, 18, 108953, {1, 3, 7, 15, 3, 29, 43, 105, 423, 601, 793, 1011, 6657, 7287, 18561, 46993, 72945, 233051}},
-{19900, 18, 108956, {1, 1, 7, 5, 15, 17, 125, 141, 75, 877, 281, 2011, 4217, 9785, 7587, 42863, 35585, 212795}},
-{19901, 18, 108963, {1, 1, 3, 3, 3, 37, 67, 129, 433, 233, 115, 687, 6253, 12805, 10935, 49963, 91675, 241951}},
-{19902, 18, 108989, {1, 3, 1, 5, 3, 41, 3, 233, 317, 959, 1407, 1251, 743, 4165, 15561, 41165, 22393, 111633}},
-{19903, 18, 109001, {1, 3, 3, 15, 17, 15, 53, 245, 109, 413, 1149, 35, 2931, 11635, 27091, 63659, 33973, 16867}},
-{19904, 18, 109009, {1, 3, 7, 13, 3, 43, 83, 201, 367, 275, 235, 1795, 4041, 13539, 22345, 31451, 83985, 3527}},
-{19905, 18, 109052, {1, 3, 3, 9, 31, 47, 63, 117, 195, 497, 453, 1183, 3857, 14075, 28057, 13205, 54331, 54641}},
-{19906, 18, 109083, {1, 1, 7, 11, 11, 39, 37, 183, 213, 537, 1371, 901, 5255, 11791, 18993, 58785, 114113, 229815}},
-{19907, 18, 109090, {1, 3, 5, 5, 13, 45, 77, 165, 329, 439, 2011, 1845, 4577, 12457, 16959, 45943, 37715, 169775}},
-{19908, 18, 109104, {1, 1, 3, 11, 5, 7, 21, 245, 365, 371, 1291, 2569, 1791, 6003, 18619, 18661, 98551, 89645}},
-{19909, 18, 109121, {1, 3, 1, 7, 3, 51, 49, 245, 151, 919, 489, 3967, 3157, 7159, 17207, 19749, 94455, 112403}},
-{19910, 18, 109128, {1, 3, 7, 5, 9, 15, 17, 201, 273, 669, 1571, 3915, 1859, 2569, 28855, 27225, 116711, 148377}},
-{19911, 18, 109141, {1, 3, 7, 3, 19, 45, 115, 71, 201, 85, 1349, 3897, 4941, 10839, 14781, 36487, 107037, 109185}},
-{19912, 18, 109146, {1, 3, 5, 13, 11, 11, 35, 19, 213, 41, 45, 4075, 3163, 12937, 17487, 28911, 21289, 198489}},
-{19913, 18, 109155, {1, 1, 1, 11, 7, 35, 67, 23, 451, 235, 717, 181, 6697, 9359, 24561, 36187, 125179, 35119}},
-{19914, 18, 109162, {1, 1, 7, 15, 7, 47, 55, 125, 465, 251, 211, 3137, 4101, 1341, 2287, 22149, 45089, 94173}},
-{19915, 18, 109209, {1, 3, 1, 15, 19, 7, 15, 207, 7, 759, 869, 2337, 6805, 8287, 13447, 9963, 7177, 173505}},
-{19916, 18, 109216, {1, 3, 7, 13, 15, 3, 65, 143, 291, 511, 939, 669, 4095, 1931, 26015, 18253, 102461, 93837}},
-{19917, 18, 109243, {1, 3, 1, 5, 23, 3, 19, 121, 489, 583, 1425, 627, 4229, 5343, 3759, 17845, 105369, 132239}},
-{19918, 18, 109265, {1, 3, 3, 9, 29, 9, 17, 153, 111, 879, 1225, 979, 2687, 10477, 10105, 18091, 37825, 28077}},
-{19919, 18, 109282, {1, 1, 7, 9, 3, 51, 75, 101, 197, 551, 89, 1441, 607, 14025, 30411, 26887, 3435, 32977}},
-{19920, 18, 109306, {1, 1, 7, 3, 25, 29, 95, 123, 197, 767, 1513, 721, 4149, 10873, 32247, 4469, 42297, 49651}},
-{19921, 18, 109316, {1, 3, 5, 15, 11, 3, 77, 161, 309, 923, 513, 161, 6447, 9811, 9209, 21413, 8611, 237557}},
-{19922, 18, 109334, {1, 3, 1, 3, 23, 11, 61, 107, 317, 771, 1469, 3367, 6607, 11495, 12271, 59989, 52483, 194761}},
-{19923, 18, 109359, {1, 3, 7, 7, 23, 1, 37, 47, 185, 863, 1153, 3517, 6165, 3921, 19311, 37339, 112477, 204915}},
-{19924, 18, 109373, {1, 3, 7, 7, 15, 61, 9, 113, 175, 305, 1759, 2933, 2139, 3591, 15303, 54479, 126511, 255205}},
-{19925, 18, 109386, {1, 1, 1, 3, 29, 43, 19, 183, 121, 577, 1329, 1737, 4373, 5577, 24023, 40103, 22333, 123423}},
-{19926, 18, 109394, {1, 3, 5, 1, 29, 1, 5, 177, 271, 431, 139, 705, 4319, 9301, 15887, 13253, 13275, 233317}},
-{19927, 18, 109403, {1, 1, 3, 7, 21, 3, 13, 51, 459, 359, 1721, 193, 4887, 7805, 20615, 28813, 82427, 57853}},
-{19928, 18, 109409, {1, 3, 3, 13, 3, 29, 43, 95, 339, 993, 979, 2323, 7505, 10203, 9475, 16513, 21651, 104871}},
-{19929, 18, 109412, {1, 1, 3, 15, 11, 5, 97, 127, 397, 25, 507, 1839, 2313, 13399, 899, 25713, 94363, 178287}},
-{19930, 18, 109427, {1, 1, 5, 5, 9, 53, 95, 171, 107, 129, 1041, 3583, 5479, 943, 21435, 36481, 85519, 169651}},
-{19931, 18, 109439, {1, 1, 1, 1, 1, 11, 17, 249, 277, 805, 1827, 2705, 3015, 9033, 25019, 38593, 59235, 21145}},
-{19932, 18, 109464, {1, 1, 7, 3, 7, 59, 107, 213, 109, 213, 555, 3463, 953, 3173, 18947, 2863, 27889, 32493}},
-{19933, 18, 109467, {1, 3, 5, 15, 21, 11, 99, 131, 287, 513, 1393, 3327, 7347, 4343, 8805, 29571, 97151, 97313}},
-{19934, 18, 109476, {1, 3, 5, 3, 17, 53, 23, 21, 227, 291, 111, 1951, 6593, 16325, 31725, 31997, 116907, 181027}},
-{19935, 18, 109488, {1, 1, 5, 3, 15, 57, 93, 153, 345, 257, 169, 795, 3907, 5669, 25447, 28775, 1489, 216417}},
-{19936, 18, 109497, {1, 1, 1, 5, 19, 19, 113, 55, 431, 685, 1839, 711, 4909, 10211, 25765, 37, 72657, 79769}},
-{19937, 18, 109523, {1, 3, 5, 7, 19, 17, 93, 145, 99, 799, 1615, 1583, 7705, 1069, 30259, 37951, 78965, 16203}},
-{19938, 18, 109551, {1, 3, 7, 13, 23, 61, 119, 49, 413, 1021, 415, 465, 7395, 31, 16415, 1009, 9843, 86531}},
-{19939, 18, 109556, {1, 1, 3, 15, 17, 21, 83, 69, 411, 1, 269, 1391, 295, 13649, 21649, 62453, 11457, 215375}},
-{19940, 18, 109566, {1, 3, 3, 7, 25, 53, 95, 99, 447, 323, 27, 1595, 3771, 16099, 31523, 14405, 66999, 65733}},
-{19941, 18, 109598, {1, 1, 3, 11, 25, 29, 19, 95, 101, 661, 537, 641, 1455, 16151, 29087, 54009, 89395, 2223}},
-{19942, 18, 109628, {1, 1, 1, 11, 11, 33, 91, 227, 449, 661, 1621, 1743, 2859, 9797, 32397, 41767, 116325, 6839}},
-{19943, 18, 109643, {1, 3, 3, 7, 31, 41, 15, 139, 53, 789, 25, 67, 1131, 5987, 14091, 37259, 70313, 6633}},
-{19944, 18, 109663, {1, 3, 7, 13, 21, 29, 71, 245, 497, 493, 207, 3221, 3695, 3045, 1497, 29235, 65113, 82015}},
-{19945, 18, 109674, {1, 1, 7, 5, 29, 29, 87, 197, 123, 323, 773, 157, 2925, 9235, 31625, 58187, 121457, 25561}},
-{19946, 18, 109688, {1, 1, 1, 9, 3, 15, 99, 55, 133, 757, 1405, 997, 5201, 8971, 6095, 33309, 35587, 254545}},
-{19947, 18, 109691, {1, 3, 5, 9, 19, 57, 85, 45, 429, 823, 1369, 933, 1971, 13753, 11351, 45805, 16527, 129907}},
-{19948, 18, 109704, {1, 3, 3, 15, 23, 15, 35, 89, 477, 875, 1087, 2837, 1093, 617, 18687, 53269, 63447, 226393}},
-{19949, 18, 109715, {1, 1, 7, 9, 27, 37, 23, 107, 265, 485, 1975, 3159, 4065, 10089, 26975, 45067, 4241, 49051}},
-{19950, 18, 109717, {1, 3, 3, 1, 29, 53, 89, 129, 149, 717, 749, 1481, 7829, 15887, 23185, 30667, 11749, 188963}},
-{19951, 18, 109746, {1, 3, 5, 9, 13, 47, 119, 135, 407, 99, 1773, 2307, 7885, 4013, 25723, 53519, 37487, 205671}},
-{19952, 18, 109789, {1, 1, 5, 1, 11, 27, 121, 213, 147, 669, 799, 485, 4275, 15909, 30583, 45925, 90365, 226901}},
-{19953, 18, 109794, {1, 1, 3, 5, 1, 19, 81, 109, 217, 949, 1637, 3413, 5957, 7293, 17337, 63857, 103815, 80805}},
-{19954, 18, 109868, {1, 3, 7, 3, 9, 43, 119, 251, 345, 3, 203, 829, 3391, 2575, 6859, 50849, 22221, 227581}},
-{19955, 18, 109886, {1, 1, 7, 15, 13, 43, 7, 23, 101, 89, 1747, 1231, 1883, 13363, 10981, 59179, 59555, 242021}},
-{19956, 18, 109888, {1, 1, 5, 5, 23, 15, 93, 183, 231, 891, 1745, 2665, 1689, 8515, 11717, 35643, 113067, 233757}},
-{19957, 18, 109903, {1, 3, 7, 11, 29, 21, 13, 59, 103, 105, 483, 863, 2711, 7917, 29279, 53931, 7011, 60075}},
-{19958, 18, 109908, {1, 1, 3, 15, 5, 37, 101, 163, 31, 575, 2029, 1625, 4545, 12579, 15175, 32667, 59497, 63653}},
-{19959, 18, 109912, {1, 3, 5, 7, 23, 37, 61, 101, 273, 49, 1943, 3381, 491, 4079, 20341, 26463, 122261, 77965}},
-{19960, 18, 109927, {1, 1, 3, 15, 9, 51, 53, 89, 175, 487, 1583, 1797, 4353, 1339, 19613, 26913, 78955, 166523}},
-{19961, 18, 109936, {1, 3, 3, 9, 27, 57, 25, 207, 233, 675, 661, 2629, 6971, 8723, 31199, 47215, 36931, 28347}},
-{19962, 18, 109979, {1, 3, 1, 3, 31, 15, 123, 17, 211, 883, 1861, 2747, 8075, 5373, 23521, 46217, 86629, 171777}},
-{19963, 18, 110005, {1, 3, 5, 9, 11, 43, 45, 171, 465, 835, 603, 2121, 409, 1643, 20327, 63211, 129479, 223113}},
-{19964, 18, 110010, {1, 1, 5, 7, 13, 57, 83, 233, 307, 489, 941, 1723, 6149, 5557, 2053, 17377, 31597, 176051}},
-{19965, 18, 110017, {1, 1, 7, 3, 11, 11, 85, 163, 169, 989, 1289, 2749, 7681, 4679, 645, 36589, 85907, 194713}},
-{19966, 18, 110041, {1, 1, 1, 7, 3, 57, 39, 149, 463, 947, 481, 1163, 7171, 8539, 28991, 61235, 74487, 107051}},
-{19967, 18, 110042, {1, 1, 3, 7, 9, 57, 89, 101, 231, 163, 1355, 1393, 5823, 7565, 26285, 13523, 130329, 26099}},
-{19968, 18, 110047, {1, 1, 7, 15, 13, 59, 111, 35, 265, 927, 125, 1881, 5397, 757, 23845, 9677, 76077, 163361}},
-{19969, 18, 110048, {1, 1, 7, 9, 1, 63, 61, 157, 389, 143, 1445, 881, 3609, 9955, 11159, 59677, 45831, 138345}},
-{19970, 18, 110053, {1, 3, 5, 7, 5, 45, 65, 23, 257, 589, 905, 3651, 743, 117, 30307, 7415, 103331, 252889}},
-{19971, 18, 110054, {1, 1, 7, 13, 3, 57, 113, 91, 217, 967, 481, 989, 4795, 3549, 23717, 60793, 80281, 19977}},
-{19972, 18, 110057, {1, 3, 3, 1, 15, 37, 113, 245, 239, 575, 197, 2803, 7743, 13447, 3601, 56981, 76381, 13321}},
-{19973, 18, 110091, {1, 3, 1, 11, 27, 33, 99, 151, 43, 835, 1951, 1957, 2983, 6781, 9319, 2119, 40533, 118325}},
-{19974, 18, 110093, {1, 3, 3, 7, 27, 19, 23, 243, 347, 477, 1661, 1891, 2439, 2485, 31743, 1427, 20317, 90803}},
-{19975, 18, 110112, {1, 3, 1, 1, 3, 59, 71, 129, 21, 3, 449, 629, 3657, 4045, 8305, 40461, 60927, 38529}},
-{19976, 18, 110127, {1, 3, 3, 7, 9, 11, 85, 185, 369, 451, 887, 3709, 6931, 111, 1379, 8741, 58777, 188045}},
-{19977, 18, 110178, {1, 3, 7, 11, 23, 13, 77, 141, 99, 543, 725, 2439, 6825, 1361, 2785, 5345, 5941, 234751}},
-{19978, 18, 110183, {1, 1, 5, 5, 17, 55, 69, 9, 431, 585, 1049, 165, 1705, 14907, 8655, 12485, 22783, 91195}},
-{19979, 18, 110184, {1, 1, 7, 11, 29, 41, 91, 137, 17, 785, 1151, 2033, 7031, 15077, 2241, 21453, 117947, 128891}},
-{19980, 18, 110195, {1, 1, 1, 11, 17, 53, 113, 195, 409, 275, 1757, 245, 6263, 14785, 29159, 43827, 65027, 248403}},
-{19981, 18, 110307, {1, 3, 3, 3, 5, 15, 23, 41, 261, 891, 1021, 1999, 4883, 9233, 10385, 21953, 50711, 4247}},
-{19982, 18, 110334, {1, 1, 1, 13, 23, 47, 33, 77, 317, 251, 617, 2265, 7549, 327, 2317, 41209, 41063, 120863}},
-{19983, 18, 110336, {1, 1, 7, 11, 15, 17, 25, 105, 253, 713, 1147, 415, 5777, 2215, 4207, 33857, 17001, 260533}},
-{19984, 18, 110354, {1, 1, 1, 11, 31, 45, 3, 25, 329, 45, 1563, 121, 1413, 16229, 32485, 54477, 101025, 64847}},
-{19985, 18, 110356, {1, 3, 5, 1, 15, 59, 113, 203, 481, 545, 371, 1357, 5549, 3043, 397, 61483, 59779, 58159}},
-{19986, 18, 110390, {1, 3, 3, 3, 25, 39, 29, 193, 379, 293, 1173, 3389, 4231, 11519, 6681, 28813, 63609, 13029}},
-{19987, 18, 110419, {1, 3, 1, 1, 27, 57, 37, 249, 441, 905, 463, 3543, 7203, 10075, 5373, 46103, 6685, 146943}},
-{19988, 18, 110452, {1, 3, 5, 7, 31, 51, 21, 139, 209, 219, 1663, 837, 3351, 6291, 735, 8715, 33751, 199485}},
-{19989, 18, 110461, {1, 3, 5, 11, 19, 57, 41, 163, 287, 327, 243, 2891, 1095, 3959, 5067, 2867, 16207, 213089}},
-{19990, 18, 110465, {1, 1, 5, 11, 21, 59, 97, 239, 309, 371, 797, 453, 2595, 4277, 3771, 5665, 10075, 56101}},
-{19991, 18, 110466, {1, 1, 3, 15, 17, 29, 103, 33, 449, 525, 961, 3551, 3611, 14057, 15971, 26981, 35169, 130213}},
-{19992, 18, 110468, {1, 1, 3, 1, 5, 13, 39, 211, 387, 797, 1051, 3287, 3737, 12953, 3387, 35107, 78809, 162907}},
-{19993, 18, 110486, {1, 1, 7, 9, 7, 63, 127, 115, 173, 981, 623, 737, 7625, 12245, 4195, 61873, 104301, 250333}},
-{19994, 18, 110511, {1, 1, 1, 5, 19, 5, 123, 43, 209, 741, 747, 1057, 2683, 15359, 24121, 38413, 5823, 62213}},
-{19995, 18, 110531, {1, 1, 7, 1, 23, 13, 63, 165, 309, 323, 247, 3827, 5451, 4823, 23925, 56957, 69765, 259923}},
-{19996, 18, 110561, {1, 1, 5, 1, 5, 49, 51, 65, 31, 257, 1363, 3031, 5765, 3645, 16383, 6347, 30429, 130557}},
-{19997, 18, 110573, {1, 3, 5, 13, 9, 63, 31, 3, 317, 379, 1345, 2161, 7787, 2055, 21507, 20347, 97021, 183377}},
-{19998, 18, 110593, {1, 3, 5, 11, 15, 59, 13, 139, 415, 821, 639, 1249, 6349, 15861, 21377, 22813, 42839, 76595}},
-{19999, 18, 110611, {1, 1, 7, 9, 23, 11, 25, 115, 393, 153, 1269, 871, 1323, 1891, 11619, 3103, 79813, 39811}},
-{20000, 18, 110614, {1, 3, 1, 15, 27, 37, 63, 253, 1, 855, 1651, 3111, 6693, 1825, 22549, 64189, 18347, 253425}},
-{20001, 18, 110651, {1, 3, 1, 11, 23, 27, 119, 59, 421, 343, 831, 2679, 5899, 12087, 15953, 18601, 109551, 33895}},
-{20002, 18, 110661, {1, 3, 1, 13, 29, 3, 91, 227, 301, 491, 1045, 2105, 5189, 13717, 1095, 6039, 16229, 215687}},
-{20003, 18, 110665, {1, 1, 7, 3, 11, 53, 85, 25, 23, 293, 841, 3569, 5335, 8949, 28665, 15139, 100807, 155587}},
-{20004, 18, 110701, {1, 1, 1, 9, 31, 1, 77, 149, 181, 5, 915, 1155, 4717, 2837, 17545, 3235, 26811, 124901}},
-{20005, 18, 110730, {1, 1, 3, 5, 25, 27, 47, 215, 425, 195, 1575, 3961, 3521, 4197, 9565, 32523, 125091, 165543}},
-{20006, 18, 110735, {1, 3, 7, 3, 17, 57, 7, 137, 507, 303, 1123, 1511, 2465, 4277, 19959, 31951, 83157, 62843}},
-{20007, 18, 110738, {1, 3, 3, 1, 27, 43, 79, 191, 265, 167, 665, 4017, 6613, 1175, 5427, 47139, 91517, 32071}},
-{20008, 18, 110759, {1, 1, 1, 11, 29, 63, 9, 39, 303, 1021, 415, 2157, 5227, 13557, 4931, 12541, 74101, 13189}},
-{20009, 18, 110763, {1, 1, 3, 9, 15, 41, 45, 163, 301, 315, 1433, 1449, 3589, 15783, 16069, 16155, 10527, 69335}},
-{20010, 18, 110768, {1, 3, 1, 1, 1, 5, 75, 169, 215, 115, 939, 1285, 43, 1941, 27847, 5245, 51211, 244817}},
-{20011, 18, 110774, {1, 1, 1, 15, 7, 33, 31, 23, 397, 537, 1415, 329, 6705, 15015, 18883, 62895, 21435, 233075}},
-{20012, 18, 110783, {1, 3, 3, 5, 11, 49, 73, 147, 183, 317, 11, 1997, 1045, 6015, 29159, 55195, 105711, 134727}},
-{20013, 18, 110785, {1, 3, 3, 9, 21, 41, 5, 213, 421, 539, 1269, 1929, 3701, 2165, 14997, 21933, 58167, 239719}},
-{20014, 18, 110809, {1, 3, 1, 5, 23, 63, 37, 27, 21, 547, 1499, 1621, 141, 5309, 32257, 47241, 123617, 243853}},
-{20015, 18, 110812, {1, 1, 1, 13, 31, 45, 47, 91, 165, 1007, 1295, 4035, 1461, 10423, 7747, 7329, 114599, 169375}},
-{20016, 18, 110840, {1, 1, 5, 3, 21, 9, 75, 61, 35, 745, 31, 4085, 3645, 16239, 14979, 15725, 108859, 56745}},
-{20017, 18, 110853, {1, 1, 5, 15, 11, 31, 13, 229, 417, 147, 1993, 4043, 7757, 13507, 15297, 56119, 2223, 142275}},
-{20018, 18, 110905, {1, 3, 5, 13, 3, 57, 45, 109, 135, 829, 159, 769, 865, 2583, 15755, 44343, 84561, 98621}},
-{20019, 18, 110933, {1, 1, 7, 11, 17, 11, 115, 45, 371, 411, 863, 2139, 3897, 13981, 16771, 4587, 25195, 66077}},
-{20020, 18, 110961, {1, 3, 7, 15, 17, 47, 51, 133, 133, 475, 1363, 3325, 4287, 4837, 22077, 60225, 3097, 246805}},
-{20021, 18, 110962, {1, 3, 5, 9, 29, 51, 127, 125, 353, 519, 129, 1409, 1497, 3167, 14163, 24921, 81343, 129835}},
-{20022, 18, 110974, {1, 3, 5, 5, 19, 39, 95, 109, 229, 1015, 367, 2373, 709, 6169, 4089, 13533, 22399, 118977}},
-{20023, 18, 110987, {1, 1, 5, 5, 17, 21, 91, 131, 309, 739, 1373, 3723, 6659, 1119, 27521, 55589, 34967, 70831}},
-{20024, 18, 110989, {1, 3, 1, 11, 5, 7, 85, 215, 425, 947, 589, 375, 5943, 13399, 18307, 27007, 18919, 200617}},
-{20025, 18, 111007, {1, 1, 3, 15, 11, 37, 111, 179, 259, 517, 1679, 225, 3493, 15025, 21751, 40687, 73001, 214477}},
-{20026, 18, 111011, {1, 1, 7, 15, 17, 41, 109, 129, 427, 847, 1965, 3269, 5871, 12331, 26899, 49791, 103471, 213789}},
-{20027, 18, 111043, {1, 3, 3, 3, 9, 41, 25, 115, 95, 737, 717, 1545, 841, 14923, 7409, 45365, 100139, 77787}},
-{20028, 18, 111070, {1, 1, 3, 15, 11, 3, 63, 23, 425, 433, 537, 1599, 2691, 11271, 1695, 40579, 53507, 73033}},
-{20029, 18, 111088, {1, 3, 7, 13, 9, 21, 85, 31, 337, 583, 1883, 3877, 7197, 7715, 21525, 53273, 11263, 41907}},
-{20030, 18, 111127, {1, 3, 7, 1, 7, 53, 61, 45, 299, 885, 1391, 3109, 6851, 6079, 18857, 44537, 95713, 146125}},
-{20031, 18, 111140, {1, 1, 1, 3, 21, 49, 95, 105, 419, 315, 365, 3035, 4169, 5723, 26921, 62809, 27019, 243965}},
-{20032, 18, 111149, {1, 1, 3, 5, 11, 39, 71, 89, 249, 11, 1395, 105, 6637, 4577, 22979, 32405, 93163, 58785}},
-{20033, 18, 111229, {1, 1, 1, 1, 27, 25, 125, 85, 495, 697, 1793, 301, 7665, 12671, 25359, 38803, 58723, 189837}},
-{20034, 18, 111230, {1, 3, 5, 11, 17, 11, 61, 211, 19, 901, 1701, 223, 2195, 15571, 3529, 34699, 94607, 196519}},
-{20035, 18, 111243, {1, 3, 7, 11, 15, 1, 111, 1, 381, 145, 293, 3639, 6931, 13195, 19985, 58491, 53067, 184411}},
-{20036, 18, 111267, {1, 3, 1, 15, 31, 39, 39, 101, 17, 431, 1151, 2465, 727, 12709, 5377, 5857, 49707, 76439}},
-{20037, 18, 111287, {1, 3, 3, 5, 7, 1, 3, 39, 357, 339, 415, 567, 7245, 13943, 7495, 54133, 119705, 160615}},
-{20038, 18, 111313, {1, 3, 5, 15, 9, 17, 13, 253, 337, 673, 1745, 2613, 4635, 14025, 11159, 50001, 40753, 172983}},
-{20039, 18, 111356, {1, 3, 7, 11, 3, 15, 19, 107, 393, 1015, 1441, 181, 5721, 9987, 15557, 37263, 90053, 205685}},
-{20040, 18, 111368, {1, 1, 5, 1, 9, 3, 69, 123, 245, 111, 283, 1581, 259, 275, 813, 12213, 19639, 7335}},
-{20041, 18, 111409, {1, 3, 7, 7, 1, 55, 101, 63, 259, 705, 653, 3821, 2081, 6447, 25471, 15523, 38827, 68055}},
-{20042, 18, 111419, {1, 1, 5, 7, 27, 9, 97, 149, 445, 341, 167, 3695, 375, 853, 8143, 36027, 62729, 197357}},
-{20043, 18, 111430, {1, 3, 7, 1, 1, 37, 97, 103, 493, 319, 1287, 3787, 4079, 13049, 14305, 6665, 4631, 96225}},
-{20044, 18, 111433, {1, 1, 5, 7, 1, 5, 127, 143, 251, 725, 1759, 2381, 181, 15741, 9395, 64441, 44347, 221697}},
-{20045, 18, 111442, {1, 3, 1, 3, 25, 47, 29, 167, 397, 827, 1255, 3271, 6307, 13915, 3131, 19123, 88619, 62847}},
-{20046, 18, 111467, {1, 3, 5, 1, 29, 11, 59, 203, 245, 553, 617, 1287, 205, 2291, 3613, 39933, 116981, 43595}},
-{20047, 18, 111491, {1, 1, 3, 9, 27, 33, 35, 77, 437, 1003, 119, 253, 6643, 113, 10587, 41073, 55371, 233307}},
-{20048, 18, 111503, {1, 3, 7, 1, 29, 63, 1, 231, 373, 995, 1063, 1385, 273, 14115, 6899, 62991, 112003, 80527}},
-{20049, 18, 111527, {1, 3, 3, 1, 31, 21, 55, 115, 393, 685, 245, 1587, 5617, 267, 19639, 15169, 14073, 173091}},
-{20050, 18, 111531, {1, 3, 1, 11, 29, 45, 53, 21, 433, 979, 1067, 2999, 6279, 4739, 30835, 61653, 112893, 75839}},
-{20051, 18, 111541, {1, 1, 5, 11, 23, 25, 15, 107, 325, 981, 1057, 1181, 4465, 16291, 1523, 64497, 129437, 45067}},
-{20052, 18, 111546, {1, 1, 1, 5, 1, 21, 79, 135, 419, 997, 1967, 747, 2097, 15397, 4415, 15807, 79583, 259561}},
-{20053, 18, 111548, {1, 3, 1, 7, 5, 49, 105, 109, 243, 371, 13, 2297, 2845, 12569, 13165, 13551, 75471, 168579}},
-{20054, 18, 111577, {1, 1, 1, 1, 9, 33, 7, 233, 43, 773, 1121, 3763, 4047, 15039, 8165, 25407, 82561, 215045}},
-{20055, 18, 111625, {1, 3, 7, 1, 17, 41, 105, 129, 333, 687, 1357, 1197, 1271, 3835, 15823, 36777, 94311, 192321}},
-{20056, 18, 111636, {1, 1, 5, 15, 13, 31, 93, 249, 81, 167, 1681, 1587, 179, 5755, 27741, 29437, 100407, 63287}},
-{20057, 18, 111650, {1, 3, 3, 13, 11, 39, 85, 23, 37, 183, 547, 1255, 1167, 15961, 23281, 59989, 99393, 34983}},
-{20058, 18, 111655, {1, 3, 7, 5, 13, 33, 17, 243, 321, 845, 447, 1997, 4639, 11175, 24651, 18281, 82677, 244543}},
-{20059, 18, 111662, {1, 3, 5, 13, 3, 63, 75, 35, 493, 207, 1707, 1401, 3687, 11353, 5461, 23433, 71259, 93483}},
-{20060, 18, 111673, {1, 1, 3, 1, 19, 61, 81, 133, 115, 957, 669, 647, 347, 8739, 18451, 39641, 118677, 136601}},
-{20061, 18, 111699, {1, 1, 7, 13, 3, 13, 119, 187, 111, 181, 1865, 1613, 201, 3633, 17805, 46553, 8899, 100407}},
-{20062, 18, 111727, {1, 3, 3, 9, 19, 33, 35, 215, 235, 893, 877, 3099, 7597, 13521, 22473, 65435, 3205, 44897}},
-{20063, 18, 111729, {1, 3, 3, 11, 27, 3, 101, 201, 215, 373, 859, 1435, 2637, 6795, 21157, 3333, 27797, 199427}},
-{20064, 18, 111741, {1, 1, 7, 13, 31, 33, 85, 205, 273, 565, 2033, 3451, 7581, 16223, 1383, 16297, 1263, 49065}},
-{20065, 18, 111757, {1, 1, 1, 13, 11, 29, 65, 71, 395, 179, 1193, 3859, 3075, 10133, 6463, 34617, 20173, 203471}},
-{20066, 18, 111781, {1, 1, 7, 3, 7, 29, 11, 115, 465, 695, 1759, 3137, 6337, 977, 43, 62501, 13297, 59319}},
-{20067, 18, 111791, {1, 3, 5, 9, 31, 59, 11, 107, 109, 797, 177, 2891, 2535, 4305, 19255, 9591, 84417, 87381}},
-{20068, 18, 111826, {1, 3, 3, 3, 1, 9, 45, 219, 73, 573, 1477, 3699, 8145, 835, 7123, 37167, 53411, 45397}},
-{20069, 18, 111838, {1, 3, 5, 15, 15, 41, 37, 63, 233, 971, 1497, 1223, 3909, 11721, 9217, 41055, 9779, 199339}},
-{20070, 18, 111854, {1, 3, 3, 7, 17, 61, 91, 237, 313, 841, 7, 3283, 4049, 10403, 22157, 4889, 31903, 188043}},
-{20071, 18, 111861, {1, 3, 7, 1, 25, 3, 59, 87, 191, 725, 1615, 4057, 3037, 14597, 17371, 42221, 73919, 58009}},
-{20072, 18, 111866, {1, 3, 5, 11, 27, 7, 45, 231, 315, 727, 843, 2191, 7909, 53, 23309, 55189, 96193, 174017}},
-{20073, 18, 111868, {1, 3, 5, 11, 27, 51, 127, 187, 209, 883, 429, 137, 4585, 15195, 16527, 32571, 30905, 8137}},
-{20074, 18, 111897, {1, 1, 1, 11, 15, 55, 13, 161, 183, 671, 659, 3669, 4461, 13691, 17119, 26877, 52041, 110103}},
-{20075, 18, 111903, {1, 3, 5, 9, 5, 45, 29, 19, 415, 931, 683, 2987, 3839, 4529, 3091, 54457, 115537, 102671}},
-{20076, 18, 111904, {1, 1, 7, 13, 23, 31, 61, 17, 327, 951, 1333, 713, 4309, 1955, 22797, 27007, 106673, 47177}},
-{20077, 18, 111959, {1, 3, 3, 9, 31, 49, 19, 115, 413, 257, 1799, 3641, 2075, 15613, 14293, 16123, 45131, 209389}},
-{20078, 18, 111975, {1, 1, 7, 15, 1, 15, 27, 63, 463, 825, 1081, 991, 2641, 5999, 8551, 41119, 80251, 189263}},
-{20079, 18, 112018, {1, 1, 5, 9, 7, 55, 125, 97, 245, 997, 457, 1087, 1297, 3433, 14887, 24117, 30689, 184809}},
-{20080, 18, 112023, {1, 3, 1, 9, 23, 59, 81, 233, 341, 943, 1335, 2819, 2625, 4957, 14925, 7917, 107383, 204493}},
-{20081, 18, 112033, {1, 3, 5, 5, 5, 25, 79, 29, 191, 541, 1295, 269, 613, 5201, 28639, 52839, 52865, 75181}},
-{20082, 18, 112036, {1, 3, 3, 7, 19, 45, 35, 201, 391, 317, 1323, 2733, 3407, 10273, 32689, 52153, 108751, 242493}},
-{20083, 18, 112043, {1, 3, 1, 7, 15, 27, 45, 21, 383, 483, 1857, 3443, 2263, 11471, 3697, 63929, 116399, 229733}},
-{20084, 18, 112095, {1, 1, 3, 9, 13, 27, 19, 37, 181, 811, 1833, 177, 7689, 10073, 20229, 31397, 65415, 68461}},
-{20085, 18, 112113, {1, 1, 1, 15, 19, 53, 65, 209, 433, 783, 1647, 4075, 3155, 733, 25603, 39033, 43109, 151257}},
-{20086, 18, 112136, {1, 3, 3, 5, 9, 37, 61, 75, 497, 825, 1785, 3709, 1731, 889, 19325, 57453, 39095, 190855}},
-{20087, 18, 112153, {1, 3, 3, 13, 3, 53, 21, 39, 483, 833, 1191, 2829, 1323, 1877, 17257, 36077, 47997, 25349}},
-{20088, 18, 112165, {1, 1, 7, 9, 29, 25, 7, 91, 87, 723, 777, 1865, 7763, 10995, 15953, 36111, 21313, 214417}},
-{20089, 18, 112166, {1, 3, 5, 3, 17, 15, 85, 133, 245, 317, 879, 3237, 7049, 6501, 13359, 34063, 124703, 118289}},
-{20090, 18, 112177, {1, 1, 1, 7, 11, 25, 111, 143, 369, 593, 237, 2787, 1015, 13059, 23275, 38453, 90809, 25803}},
-{20091, 18, 112189, {1, 1, 7, 5, 13, 21, 39, 235, 381, 381, 949, 773, 1123, 9911, 18115, 47657, 47849, 197633}},
-{20092, 18, 112226, {1, 1, 3, 13, 15, 57, 47, 203, 483, 341, 137, 1283, 2847, 5051, 22593, 60915, 45123, 258733}},
-{20093, 18, 112237, {1, 1, 3, 5, 29, 7, 23, 127, 493, 543, 747, 3547, 4433, 5847, 28999, 18079, 81205, 231557}},
-{20094, 18, 112240, {1, 1, 3, 15, 9, 63, 17, 197, 75, 387, 1679, 2631, 1033, 2757, 18365, 11957, 98915, 24223}},
-{20095, 18, 112255, {1, 1, 3, 9, 27, 55, 67, 97, 345, 995, 1151, 1747, 4889, 13847, 13237, 9035, 13461, 10377}},
-{20096, 18, 112265, {1, 1, 5, 9, 27, 13, 7, 77, 399, 191, 137, 2801, 6379, 15969, 1727, 27503, 97385, 147625}},
-{20097, 18, 112280, {1, 3, 1, 7, 5, 9, 103, 163, 489, 615, 1359, 2635, 3115, 13795, 18853, 65225, 26545, 212065}},
-{20098, 18, 112292, {1, 3, 7, 3, 13, 25, 125, 133, 359, 423, 751, 4045, 1209, 7521, 6653, 39171, 125083, 229399}},
-{20099, 18, 112307, {1, 3, 1, 9, 15, 21, 121, 223, 283, 313, 1807, 3829, 5279, 10609, 20113, 7851, 23731, 245327}},
-{20100, 18, 112316, {1, 1, 1, 11, 15, 13, 63, 253, 311, 369, 1549, 2803, 2029, 14967, 14217, 1387, 104669, 63375}},
-{20101, 18, 112342, {1, 1, 3, 3, 31, 49, 59, 189, 249, 779, 275, 3761, 3465, 2205, 11543, 16973, 126249, 104769}},
-{20102, 18, 112345, {1, 3, 1, 5, 11, 39, 59, 33, 121, 151, 467, 1011, 1379, 13955, 20117, 52537, 51049, 50663}},
-{20103, 18, 112351, {1, 1, 1, 7, 5, 41, 121, 29, 357, 33, 849, 2441, 2127, 1337, 21147, 63869, 80215, 31211}},
-{20104, 18, 112361, {1, 3, 3, 3, 25, 41, 17, 101, 173, 915, 463, 2391, 1671, 8789, 13357, 42127, 17599, 61087}},
-{20105, 18, 112364, {1, 1, 3, 9, 29, 23, 47, 211, 435, 223, 1421, 2463, 4543, 8569, 30209, 46621, 14367, 13263}},
-{20106, 18, 112372, {1, 3, 7, 7, 5, 9, 75, 209, 299, 81, 1705, 2335, 6703, 6309, 5859, 57889, 43219, 7667}},
-{20107, 18, 112382, {1, 3, 3, 3, 19, 31, 107, 87, 413, 111, 215, 2711, 7053, 5223, 25241, 26675, 16067, 122719}},
-{20108, 18, 112389, {1, 1, 1, 15, 21, 3, 15, 13, 281, 63, 725, 2025, 4813, 14177, 18577, 875, 118623, 192005}},
-{20109, 18, 112408, {1, 3, 5, 9, 17, 21, 85, 173, 59, 153, 763, 3899, 1985, 2071, 10439, 44911, 60915, 122419}},
-{20110, 18, 112417, {1, 3, 7, 13, 11, 63, 59, 95, 53, 927, 555, 1897, 5195, 13469, 16973, 3463, 125173, 256021}},
-{20111, 18, 112423, {1, 1, 3, 7, 9, 63, 33, 193, 61, 445, 1247, 1379, 4701, 5311, 30709, 16795, 69871, 161113}},
-{20112, 18, 112476, {1, 3, 1, 3, 21, 25, 125, 111, 109, 75, 455, 861, 6483, 4501, 19095, 45601, 78415, 30995}},
-{20113, 18, 112480, {1, 1, 3, 5, 1, 25, 15, 25, 223, 961, 537, 1453, 4951, 5085, 19801, 9863, 108819, 7319}},
-{20114, 18, 112483, {1, 3, 1, 5, 29, 21, 79, 113, 177, 691, 219, 3159, 3493, 25, 30655, 46257, 23707, 243377}},
-{20115, 18, 112513, {1, 1, 3, 3, 27, 21, 11, 95, 43, 161, 2029, 4091, 6695, 7179, 9955, 45195, 32017, 128605}},
-{20116, 18, 112538, {1, 1, 7, 5, 19, 37, 47, 83, 169, 143, 773, 2127, 347, 1887, 2861, 8155, 21437, 175641}},
-{20117, 18, 112543, {1, 3, 1, 1, 27, 63, 119, 57, 77, 931, 629, 1807, 4469, 2315, 3767, 19207, 114581, 125135}},
-{20118, 18, 112574, {1, 1, 5, 11, 13, 51, 51, 239, 333, 369, 1035, 3017, 103, 1809, 14579, 34425, 123915, 258397}},
-{20119, 18, 112599, {1, 1, 1, 3, 3, 19, 63, 237, 141, 929, 943, 2597, 3983, 1043, 24269, 12325, 39013, 216689}},
-{20120, 18, 112605, {1, 1, 3, 7, 9, 61, 73, 31, 287, 303, 1415, 3453, 2667, 8625, 14347, 51953, 9181, 251937}},
-{20121, 18, 112667, {1, 1, 7, 1, 15, 41, 1, 197, 87, 311, 1147, 3799, 2585, 14027, 491, 54203, 124861, 227637}},
-{20122, 18, 112688, {1, 3, 7, 3, 15, 35, 97, 89, 65, 493, 1897, 3345, 3807, 5911, 12461, 21393, 116975, 212801}},
-{20123, 18, 112735, {1, 1, 7, 11, 29, 47, 61, 171, 399, 929, 93, 2815, 4933, 9209, 15053, 21911, 117217, 52539}},
-{20124, 18, 112746, {1, 3, 1, 1, 19, 25, 11, 41, 73, 317, 215, 923, 5153, 8025, 18703, 11513, 107981, 2027}},
-{20125, 18, 112810, {1, 1, 5, 7, 27, 33, 47, 99, 171, 259, 2017, 2055, 909, 4185, 26689, 23155, 109857, 213957}},
-{20126, 18, 112817, {1, 3, 7, 3, 31, 17, 39, 203, 255, 345, 1461, 1561, 4349, 6451, 14763, 32993, 74475, 140557}},
-{20127, 18, 112827, {1, 1, 5, 3, 21, 57, 75, 201, 371, 529, 1471, 243, 3751, 581, 18405, 40933, 106311, 745}},
-{20128, 18, 112835, {1, 1, 3, 13, 7, 53, 125, 15, 55, 267, 1865, 3297, 4331, 2913, 21675, 58911, 28419, 105585}},
-{20129, 18, 112892, {1, 3, 5, 13, 7, 13, 37, 37, 207, 127, 785, 1129, 8123, 7655, 16003, 18907, 48883, 2001}},
-{20130, 18, 112898, {1, 1, 5, 3, 11, 3, 127, 149, 503, 1019, 887, 3429, 7775, 7113, 19571, 34461, 38889, 66981}},
-{20131, 18, 112915, {1, 3, 7, 7, 1, 55, 87, 217, 465, 485, 411, 2955, 4899, 1741, 7051, 42885, 1837, 68175}},
-{20132, 18, 112918, {1, 1, 7, 1, 7, 39, 25, 1, 185, 523, 273, 2409, 1867, 3101, 29823, 4509, 81621, 11815}},
-{20133, 18, 112937, {1, 1, 1, 11, 13, 11, 89, 237, 355, 347, 91, 1791, 5745, 4181, 29207, 39495, 5275, 199395}},
-{20134, 18, 112940, {1, 1, 7, 3, 17, 37, 109, 169, 191, 295, 1001, 2631, 1981, 11821, 8315, 40675, 1293, 220247}},
-{20135, 18, 112958, {1, 3, 1, 7, 31, 25, 5, 55, 1, 795, 1663, 3177, 6821, 2073, 25789, 23691, 25015, 75203}},
-{20136, 18, 113013, {1, 3, 5, 9, 19, 9, 97, 129, 351, 735, 1897, 3555, 1731, 5413, 32051, 12869, 111973, 100157}},
-{20137, 18, 113014, {1, 3, 3, 15, 27, 1, 3, 167, 7, 851, 805, 713, 6389, 1455, 32371, 7617, 107157, 131299}},
-{20138, 18, 113027, {1, 3, 1, 13, 31, 29, 91, 123, 387, 939, 223, 3583, 2889, 5307, 16561, 6055, 4437, 123229}},
-{20139, 18, 113048, {1, 3, 5, 11, 27, 17, 5, 145, 369, 449, 1677, 1039, 3553, 3057, 11667, 51879, 20519, 41573}},
-{20140, 18, 113051, {1, 3, 1, 9, 9, 1, 91, 33, 379, 35, 691, 375, 5937, 15019, 16177, 53457, 52015, 232257}},
-{20141, 18, 113053, {1, 1, 3, 11, 23, 17, 75, 217, 377, 571, 1725, 2719, 3911, 12277, 27799, 55573, 21981, 112529}},
-{20142, 18, 113102, {1, 3, 1, 11, 9, 37, 81, 95, 501, 615, 327, 3751, 7333, 15407, 7785, 29113, 116335, 221853}},
-{20143, 18, 113104, {1, 1, 1, 3, 17, 1, 125, 157, 461, 845, 93, 107, 4429, 2271, 14445, 32919, 81175, 244557}},
-{20144, 18, 113114, {1, 3, 3, 1, 27, 23, 33, 15, 29, 361, 409, 981, 7819, 10259, 21971, 23317, 66641, 54591}},
-{20145, 18, 113130, {1, 3, 7, 13, 31, 63, 11, 167, 511, 81, 1165, 3973, 4275, 3315, 10227, 34973, 58505, 2333}},
-{20146, 18, 113159, {1, 3, 1, 9, 3, 49, 111, 101, 41, 775, 449, 1349, 4411, 8691, 535, 60137, 3269, 204895}},
-{20147, 18, 113180, {1, 3, 7, 15, 7, 43, 39, 147, 309, 185, 733, 1473, 5467, 6183, 17971, 56805, 111931, 163515}},
-{20148, 18, 113189, {1, 3, 1, 3, 21, 31, 17, 129, 317, 587, 801, 2517, 2569, 765, 20869, 16461, 34425, 101123}},
-{20149, 18, 113211, {1, 3, 1, 7, 13, 63, 117, 31, 25, 741, 365, 687, 6195, 2093, 14679, 16861, 123381, 25263}},
-{20150, 18, 113245, {1, 1, 1, 3, 13, 59, 65, 131, 41, 39, 1659, 1491, 225, 10277, 12445, 4161, 92119, 146705}},
-{20151, 18, 113261, {1, 3, 5, 1, 31, 11, 21, 203, 345, 473, 1643, 1377, 555, 11675, 15383, 30855, 41249, 231059}},
-{20152, 18, 113273, {1, 1, 7, 15, 3, 23, 33, 133, 433, 407, 1217, 3345, 7455, 11489, 21463, 41621, 95755, 86971}},
-{20153, 18, 113292, {1, 1, 1, 3, 13, 47, 45, 181, 489, 89, 427, 1915, 3993, 10133, 20437, 31811, 48421, 150009}},
-{20154, 18, 113314, {1, 3, 1, 9, 9, 25, 89, 195, 503, 755, 59, 1869, 6645, 13841, 22973, 17761, 46759, 68717}},
-{20155, 18, 113319, {1, 3, 1, 1, 19, 21, 119, 123, 481, 289, 1009, 3769, 3909, 1123, 17875, 17383, 71533, 45455}},
-{20156, 18, 113323, {1, 1, 1, 3, 31, 33, 127, 43, 467, 749, 377, 3025, 511, 13335, 23987, 63627, 50211, 197253}},
-{20157, 18, 113326, {1, 1, 5, 13, 29, 7, 101, 43, 299, 769, 1637, 3731, 1945, 9933, 22263, 1523, 127557, 116867}},
-{20158, 18, 113337, {1, 1, 3, 11, 1, 59, 25, 45, 275, 535, 1349, 3625, 8125, 727, 1215, 15487, 86229, 124817}},
-{20159, 18, 113338, {1, 3, 3, 13, 3, 11, 25, 237, 213, 331, 395, 1775, 1225, 6859, 16577, 39105, 118081, 74727}},
-{20160, 18, 113355, {1, 1, 1, 9, 5, 27, 117, 75, 479, 757, 1299, 2273, 3221, 5297, 249, 60327, 48739, 107023}},
-{20161, 18, 113365, {1, 1, 5, 9, 27, 9, 123, 49, 63, 763, 121, 3955, 2069, 5999, 25973, 64661, 6321, 1179}},
-{20162, 18, 113376, {1, 3, 7, 11, 9, 51, 65, 93, 51, 51, 829, 3239, 7431, 3489, 7691, 38777, 28151, 96635}},
-{20163, 18, 113408, {1, 3, 3, 13, 15, 51, 13, 203, 49, 73, 363, 2173, 7771, 11527, 27683, 39333, 2083, 178623}},
-{20164, 18, 113462, {1, 1, 5, 5, 15, 27, 27, 127, 503, 955, 427, 3061, 6213, 917, 889, 12601, 72445, 105383}},
-{20165, 18, 113476, {1, 3, 5, 3, 27, 43, 105, 187, 309, 747, 1843, 723, 539, 8829, 19171, 46009, 26129, 173145}},
-{20166, 18, 113503, {1, 3, 7, 7, 9, 51, 121, 139, 107, 453, 1103, 2957, 633, 1435, 27275, 53231, 51393, 16847}},
-{20167, 18, 113550, {1, 3, 7, 5, 25, 31, 71, 191, 169, 69, 1477, 1413, 7659, 11737, 12365, 25067, 21787, 16225}},
-{20168, 18, 113578, {1, 1, 7, 1, 9, 33, 37, 123, 391, 341, 829, 1543, 7323, 14695, 16431, 20009, 95821, 182791}},
-{20169, 18, 113580, {1, 3, 1, 5, 9, 59, 109, 39, 301, 977, 1963, 177, 8107, 16193, 5691, 14157, 71605, 250839}},
-{20170, 18, 113634, {1, 3, 5, 9, 29, 33, 33, 153, 7, 217, 201, 563, 6577, 9605, 16671, 63949, 97937, 234309}},
-{20171, 18, 113653, {1, 3, 7, 3, 25, 11, 81, 89, 275, 801, 477, 1921, 2279, 1651, 13333, 9127, 99693, 83141}},
-{20172, 18, 113677, {1, 3, 7, 5, 23, 51, 23, 51, 447, 689, 387, 1845, 6033, 2037, 20139, 33165, 56111, 243353}},
-{20173, 18, 113713, {1, 3, 5, 7, 5, 7, 105, 121, 439, 471, 721, 85, 1627, 3735, 29611, 15537, 36131, 30225}},
-{20174, 18, 113751, {1, 1, 5, 5, 7, 29, 31, 209, 183, 217, 467, 1287, 6145, 14737, 16249, 8857, 101405, 103355}},
-{20175, 18, 113771, {1, 3, 3, 5, 19, 1, 43, 15, 239, 63, 617, 2189, 3841, 1223, 12217, 4121, 88047, 14069}},
-{20176, 18, 113781, {1, 3, 7, 1, 9, 49, 11, 65, 297, 943, 1739, 3797, 6169, 2057, 5031, 2149, 21439, 141039}},
-{20177, 18, 113797, {1, 1, 1, 7, 15, 59, 35, 203, 347, 529, 1741, 1003, 6143, 4979, 15495, 48447, 2139, 187025}},
-{20178, 18, 113846, {1, 1, 7, 13, 15, 17, 77, 225, 461, 691, 1067, 1133, 6555, 511, 25845, 39835, 11755, 142743}},
-{20179, 18, 113849, {1, 3, 3, 11, 27, 25, 49, 51, 335, 1, 381, 2703, 7023, 14739, 19335, 39625, 82255, 76277}},
-{20180, 18, 113855, {1, 3, 3, 7, 19, 3, 35, 95, 203, 991, 515, 2245, 6085, 4129, 9581, 38309, 114203, 136021}},
-{20181, 18, 113878, {1, 1, 7, 7, 21, 61, 31, 57, 459, 119, 523, 1293, 3647, 735, 28849, 15581, 123943, 210069}},
-{20182, 18, 113884, {1, 1, 7, 3, 9, 55, 103, 23, 401, 109, 23, 4083, 6179, 12817, 2787, 43337, 53647, 241507}},
-{20183, 18, 113926, {1, 1, 5, 7, 9, 51, 37, 133, 97, 933, 1509, 2229, 1769, 12901, 15439, 25687, 128823, 72451}},
-{20184, 18, 113938, {1, 3, 1, 13, 17, 19, 7, 109, 299, 799, 621, 3393, 3645, 283, 29889, 63215, 97805, 45795}},
-{20185, 18, 113956, {1, 3, 1, 15, 21, 7, 65, 237, 221, 433, 1611, 2591, 3639, 3231, 6025, 53465, 88091, 17657}},
-{20186, 18, 113980, {1, 1, 7, 9, 27, 13, 11, 185, 381, 43, 961, 2743, 2691, 10531, 3713, 61757, 124011, 209323}},
-{20187, 18, 113986, {1, 3, 5, 1, 13, 7, 109, 65, 359, 577, 2001, 3085, 3519, 8577, 19299, 40145, 37159, 82421}},
-{20188, 18, 113991, {1, 1, 3, 11, 7, 5, 21, 215, 391, 317, 879, 1835, 611, 7189, 3887, 45383, 41025, 175701}},
-{20189, 18, 114005, {1, 1, 1, 1, 5, 17, 69, 115, 481, 477, 2017, 583, 8033, 11349, 16625, 213, 88033, 31707}},
-{20190, 18, 114022, {1, 1, 7, 15, 19, 55, 121, 35, 1, 71, 1011, 3247, 4133, 1681, 29943, 30149, 96797, 177707}},
-{20191, 18, 114036, {1, 3, 5, 13, 11, 45, 83, 153, 455, 223, 787, 2025, 5271, 229, 17549, 5775, 75311, 134523}},
-{20192, 18, 114046, {1, 3, 5, 7, 21, 43, 3, 253, 395, 651, 1111, 1685, 539, 6555, 25761, 39477, 15823, 261825}},
-{20193, 18, 114050, {1, 3, 7, 15, 27, 35, 43, 191, 269, 247, 883, 887, 1505, 7433, 6239, 5421, 49583, 17765}},
-{20194, 18, 114061, {1, 1, 5, 15, 7, 19, 113, 177, 63, 119, 517, 3987, 971, 12071, 13107, 28913, 85675, 204921}},
-{20195, 18, 114067, {1, 3, 7, 15, 31, 47, 21, 129, 31, 505, 661, 855, 6135, 13063, 27971, 63801, 27469, 75373}},
-{20196, 18, 114117, {1, 1, 7, 5, 13, 23, 111, 85, 279, 969, 483, 831, 483, 9065, 10997, 59031, 5083, 150939}},
-{20197, 18, 114142, {1, 3, 5, 7, 17, 55, 11, 223, 189, 209, 139, 577, 5443, 913, 19085, 53113, 8427, 11251}},
-{20198, 18, 114158, {1, 1, 1, 7, 23, 61, 95, 213, 443, 803, 1545, 3625, 2195, 2649, 10913, 14339, 23001, 16735}},
-{20199, 18, 114165, {1, 3, 3, 3, 13, 45, 15, 225, 419, 445, 527, 635, 2279, 5097, 25267, 199, 66187, 156717}},
-{20200, 18, 114200, {1, 1, 1, 7, 23, 17, 113, 245, 99, 159, 919, 2961, 1731, 6241, 12749, 8925, 44153, 243249}},
-{20201, 18, 114219, {1, 3, 1, 3, 29, 57, 43, 245, 389, 233, 135, 45, 3771, 14061, 10173, 51939, 128985, 81605}},
-{20202, 18, 114254, {1, 1, 1, 15, 1, 19, 25, 111, 91, 193, 1185, 3679, 7155, 7077, 13743, 35631, 128975, 196979}},
-{20203, 18, 114265, {1, 3, 3, 13, 31, 57, 25, 53, 149, 331, 643, 915, 1607, 14429, 29803, 23459, 72915, 39253}},
-{20204, 18, 114272, {1, 3, 3, 9, 23, 45, 9, 29, 383, 277, 981, 1647, 5217, 4449, 26759, 63849, 98081, 37565}},
-{20205, 18, 114312, {1, 1, 1, 15, 3, 23, 9, 121, 231, 27, 1961, 2389, 1689, 7041, 8069, 37973, 74601, 15553}},
-{20206, 18, 114318, {1, 1, 5, 15, 15, 29, 11, 177, 355, 47, 1821, 393, 3383, 10439, 6357, 41119, 60323, 206253}},
-{20207, 18, 114348, {1, 1, 1, 1, 21, 29, 87, 149, 157, 979, 1867, 729, 1949, 4409, 27495, 6841, 89033, 214957}},
-{20208, 18, 114377, {1, 1, 3, 3, 9, 7, 115, 129, 141, 157, 881, 109, 5537, 303, 32549, 1953, 9903, 82401}},
-{20209, 18, 114383, {1, 1, 5, 15, 9, 19, 93, 53, 319, 913, 1341, 705, 4639, 16189, 11375, 39155, 81393, 115843}},
-{20210, 18, 114386, {1, 1, 5, 7, 31, 21, 3, 47, 437, 799, 359, 3291, 3917, 12983, 19283, 23769, 34033, 226041}},
-{20211, 18, 114431, {1, 3, 7, 7, 27, 13, 65, 31, 181, 511, 1373, 3871, 1537, 6015, 12103, 42187, 121043, 95715}},
-{20212, 18, 114448, {1, 1, 5, 11, 1, 55, 91, 11, 105, 137, 1787, 81, 5163, 5793, 17403, 59433, 113439, 65751}},
-{20213, 18, 114479, {1, 1, 3, 13, 21, 57, 87, 157, 379, 5, 285, 3217, 4557, 3359, 28953, 63397, 110537, 230571}},
-{20214, 18, 114487, {1, 3, 7, 7, 7, 27, 25, 109, 125, 337, 719, 561, 5903, 12913, 6987, 17157, 50655, 195109}},
-{20215, 18, 114513, {1, 3, 3, 15, 3, 11, 97, 93, 441, 19, 1435, 515, 6129, 5177, 28075, 53495, 107817, 78399}},
-{20216, 18, 114542, {1, 3, 1, 9, 13, 7, 89, 171, 165, 479, 223, 4001, 691, 4033, 13577, 33363, 63447, 46609}},
-{20217, 18, 114572, {1, 3, 7, 1, 15, 47, 103, 45, 209, 639, 1465, 2795, 6025, 7981, 29491, 47743, 12861, 222445}},
-{20218, 18, 114584, {1, 3, 3, 3, 1, 25, 121, 91, 253, 969, 1259, 1409, 1329, 15995, 17733, 24081, 101747, 120619}},
-{20219, 18, 114600, {1, 3, 7, 11, 11, 5, 7, 241, 469, 411, 1733, 1385, 7005, 10977, 23369, 10675, 90341, 93077}},
-{20220, 18, 114605, {1, 3, 3, 13, 17, 35, 107, 189, 437, 801, 1761, 3133, 3847, 14079, 22465, 45957, 38449, 54273}},
-{20221, 18, 114623, {1, 1, 7, 9, 9, 47, 55, 107, 491, 281, 777, 2187, 6179, 6607, 2151, 9093, 42873, 104677}},
-{20222, 18, 114628, {1, 1, 5, 3, 25, 3, 37, 55, 339, 619, 1227, 3859, 5593, 9639, 31199, 48155, 80779, 6497}},
-{20223, 18, 114640, {1, 1, 7, 1, 21, 49, 105, 45, 119, 635, 163, 3821, 3689, 11395, 19265, 14289, 89259, 167433}},
-{20224, 18, 114650, {1, 3, 3, 15, 29, 23, 11, 255, 425, 443, 1659, 3965, 4791, 10223, 11113, 48751, 7987, 166605}},
-{20225, 18, 114668, {1, 1, 7, 3, 7, 1, 113, 153, 233, 803, 539, 297, 4847, 11203, 29393, 54319, 94373, 173471}},
-{20226, 18, 114671, {1, 3, 3, 5, 27, 57, 23, 147, 423, 617, 103, 3369, 4825, 13613, 23635, 61977, 5331, 115243}},
-{20227, 18, 114674, {1, 3, 3, 9, 11, 47, 41, 27, 345, 657, 1873, 365, 1685, 11181, 31977, 60489, 98741, 215357}},
-{20228, 18, 114700, {1, 3, 1, 11, 19, 33, 39, 223, 151, 921, 309, 3413, 6735, 11971, 25583, 6927, 54821, 125203}},
-{20229, 18, 114731, {1, 1, 5, 1, 27, 31, 61, 247, 207, 895, 1453, 3613, 7097, 6537, 29407, 9903, 39937, 98285}},
-{20230, 18, 114748, {1, 3, 1, 5, 7, 11, 119, 7, 323, 27, 1069, 2033, 7387, 3381, 19007, 49039, 39453, 115411}},
-{20231, 18, 114759, {1, 1, 7, 3, 9, 15, 51, 139, 353, 857, 1829, 3955, 7669, 3961, 22805, 39879, 26677, 66865}},
-{20232, 18, 114766, {1, 3, 5, 7, 1, 11, 59, 95, 181, 645, 829, 3119, 3607, 5973, 12381, 41577, 79443, 226945}},
-{20233, 18, 114768, {1, 3, 3, 5, 3, 13, 91, 119, 103, 889, 703, 3005, 541, 7529, 12613, 14267, 70445, 217543}},
-{20234, 18, 114784, {1, 1, 5, 7, 17, 41, 5, 225, 85, 759, 1071, 2055, 1655, 14811, 25635, 50803, 58545, 105687}},
-{20235, 18, 114808, {1, 3, 5, 13, 3, 7, 77, 209, 139, 717, 985, 1085, 831, 11011, 27313, 46423, 29435, 207359}},
-{20236, 18, 114813, {1, 3, 1, 7, 27, 45, 39, 75, 311, 937, 1593, 1357, 4815, 1997, 1045, 48681, 49301, 155607}},
-{20237, 18, 114829, {1, 3, 5, 11, 21, 9, 111, 39, 447, 241, 1613, 1799, 4817, 1861, 1263, 63641, 92081, 252051}},
-{20238, 18, 114830, {1, 1, 1, 13, 31, 13, 39, 29, 349, 25, 1227, 2457, 3831, 7965, 16903, 25825, 62381, 101765}},
-{20239, 18, 114842, {1, 1, 3, 7, 15, 17, 5, 29, 83, 607, 931, 261, 1087, 16247, 10129, 7813, 5445, 167723}},
-{20240, 18, 114875, {1, 3, 5, 9, 15, 31, 69, 191, 139, 467, 1681, 1951, 7813, 4295, 18191, 11411, 15601, 13025}},
-{20241, 18, 114898, {1, 1, 1, 11, 29, 53, 97, 205, 281, 917, 1009, 913, 1003, 16085, 30339, 55753, 53099, 30697}},
-{20242, 18, 114903, {1, 1, 3, 15, 25, 35, 7, 227, 63, 251, 845, 843, 7117, 6021, 26917, 43611, 108643, 215471}},
-{20243, 18, 114913, {1, 1, 3, 11, 19, 29, 75, 5, 131, 37, 1185, 2387, 8161, 1621, 19887, 20525, 33067, 30869}},
-{20244, 18, 114928, {1, 1, 3, 3, 7, 37, 75, 159, 313, 17, 479, 2477, 7779, 309, 26095, 35693, 92561, 143151}},
-{20245, 18, 114937, {1, 1, 5, 9, 5, 29, 65, 223, 331, 1013, 37, 1813, 1379, 9277, 14681, 61687, 24763, 124669}},
-{20246, 18, 114958, {1, 3, 1, 1, 17, 47, 7, 219, 11, 13, 1517, 2583, 7483, 5399, 6883, 51387, 17901, 108659}},
-{20247, 18, 114963, {1, 3, 7, 11, 9, 63, 81, 91, 411, 535, 255, 3683, 5285, 1787, 27205, 43651, 15647, 230651}},
-{20248, 18, 115000, {1, 3, 1, 11, 7, 47, 35, 255, 341, 379, 421, 753, 7821, 13271, 13021, 463, 48457, 132521}},
-{20249, 18, 115018, {1, 1, 5, 7, 21, 23, 53, 229, 393, 509, 1641, 2245, 6941, 10447, 3231, 5451, 18883, 47401}},
-{20250, 18, 115023, {1, 3, 1, 7, 13, 61, 71, 49, 147, 625, 299, 3843, 4851, 3483, 27005, 23871, 18855, 124893}},
-{20251, 18, 115028, {1, 3, 1, 7, 31, 13, 127, 177, 259, 179, 531, 1775, 5481, 13157, 23821, 31773, 93941, 237697}},
-{20252, 18, 115042, {1, 1, 7, 1, 23, 21, 111, 219, 401, 455, 1603, 2077, 1537, 2063, 17821, 52087, 20707, 29535}},
-{20253, 18, 115084, {1, 1, 3, 11, 17, 17, 13, 79, 49, 353, 1691, 361, 2805, 7121, 27013, 50631, 108235, 70513}},
-{20254, 18, 115096, {1, 1, 5, 3, 15, 25, 103, 73, 377, 253, 1303, 501, 555, 15789, 16647, 9019, 60581, 157337}},
-{20255, 18, 115105, {1, 3, 5, 9, 23, 45, 3, 251, 25, 559, 429, 1091, 5657, 15387, 5113, 64533, 131049, 127587}},
-{20256, 18, 115117, {1, 1, 3, 15, 1, 53, 71, 141, 413, 849, 737, 3045, 7119, 8049, 18295, 31447, 70735, 117457}},
-{20257, 18, 115149, {1, 1, 1, 11, 17, 11, 69, 155, 211, 249, 1869, 1575, 6859, 7045, 7015, 20135, 84157, 232621}},
-{20258, 18, 115155, {1, 3, 7, 5, 19, 55, 15, 163, 457, 371, 1665, 1935, 601, 3629, 21975, 1191, 45133, 111649}},
-{20259, 18, 115198, {1, 3, 7, 11, 23, 33, 5, 253, 355, 379, 933, 1781, 3989, 6191, 19081, 7651, 74671, 258799}},
-{20260, 18, 115221, {1, 1, 3, 3, 23, 3, 63, 123, 273, 861, 369, 2409, 1505, 9059, 10727, 189, 122911, 44037}},
-{20261, 18, 115222, {1, 1, 7, 13, 13, 23, 19, 87, 191, 397, 2027, 1689, 1143, 10919, 27073, 15013, 118429, 119165}},
-{20262, 18, 115225, {1, 1, 5, 9, 15, 13, 29, 81, 409, 955, 1827, 1341, 3473, 16005, 29041, 57527, 7329, 167093}},
-{20263, 18, 115276, {1, 1, 5, 3, 11, 31, 47, 13, 171, 995, 961, 3885, 3259, 2745, 12405, 49281, 2901, 207591}},
-{20264, 18, 115294, {1, 3, 5, 13, 31, 3, 1, 215, 465, 279, 1697, 2449, 3829, 2053, 9877, 52911, 126077, 210515}},
-{20265, 18, 115297, {1, 1, 3, 7, 11, 27, 55, 115, 249, 353, 407, 2567, 8105, 7747, 18111, 3383, 101875, 2185}},
-{20266, 18, 115321, {1, 1, 3, 9, 25, 5, 35, 137, 405, 667, 1671, 2965, 5975, 4999, 18421, 43623, 64621, 129797}},
-{20267, 18, 115348, {1, 3, 7, 13, 3, 17, 33, 191, 463, 787, 1795, 3037, 1679, 63, 12389, 3983, 22385, 84235}},
-{20268, 18, 115364, {1, 1, 5, 9, 11, 25, 85, 215, 355, 553, 317, 1637, 3461, 15943, 2619, 14545, 125507, 18659}},
-{20269, 18, 115376, {1, 1, 7, 5, 3, 41, 105, 179, 125, 557, 1345, 3631, 481, 10621, 11213, 40223, 46581, 113137}},
-{20270, 18, 115385, {1, 3, 3, 15, 1, 63, 95, 213, 89, 21, 1249, 3063, 413, 4307, 26723, 10225, 115143, 144817}},
-{20271, 18, 115386, {1, 3, 5, 15, 9, 43, 41, 117, 419, 143, 1651, 377, 4775, 8761, 23793, 8719, 76499, 208119}},
-{20272, 18, 115400, {1, 3, 3, 1, 21, 29, 47, 117, 23, 333, 1153, 1067, 5859, 9375, 29997, 58991, 55895, 204933}},
-{20273, 18, 115414, {1, 1, 3, 11, 11, 21, 115, 85, 223, 281, 701, 1331, 1341, 1149, 5993, 10885, 77353, 113553}},
-{20274, 18, 115465, {1, 1, 5, 1, 25, 1, 1, 153, 449, 231, 593, 3061, 4157, 6661, 21735, 11361, 57751, 129569}},
-{20275, 18, 115485, {1, 1, 3, 7, 27, 63, 81, 251, 125, 197, 1525, 1637, 4643, 4743, 17127, 51217, 95781, 973}},
-{20276, 18, 115492, {1, 1, 3, 7, 11, 51, 13, 139, 83, 341, 543, 3061, 7777, 6705, 9609, 28933, 24669, 225275}},
-{20277, 18, 115501, {1, 3, 1, 9, 25, 39, 99, 139, 5, 725, 1759, 1577, 1751, 3197, 3169, 39051, 1743, 108813}},
-{20278, 18, 115519, {1, 1, 7, 5, 31, 15, 115, 229, 499, 291, 501, 3119, 2293, 14137, 625, 16379, 111057, 101643}},
-{20279, 18, 115527, {1, 3, 7, 15, 31, 1, 51, 73, 455, 51, 1983, 3687, 6049, 3495, 26247, 6567, 28479, 158909}},
-{20280, 18, 115531, {1, 3, 5, 5, 9, 11, 77, 181, 165, 773, 1611, 3945, 6787, 3827, 28597, 53269, 34003, 237291}},
-{20281, 18, 115567, {1, 1, 5, 3, 31, 57, 15, 9, 163, 363, 1021, 2193, 8175, 3851, 26059, 63915, 114293, 163637}},
-{20282, 18, 115572, {1, 1, 3, 7, 27, 49, 35, 121, 469, 833, 879, 1601, 6991, 13271, 8085, 45343, 5189, 109413}},
-{20283, 18, 115631, {1, 3, 1, 15, 7, 11, 111, 153, 129, 769, 565, 2693, 333, 7343, 28535, 56937, 85641, 19871}},
-{20284, 18, 115648, {1, 1, 5, 13, 7, 49, 121, 223, 55, 33, 19, 2291, 1847, 10173, 23337, 23431, 18181, 155663}},
-{20285, 18, 115660, {1, 3, 1, 11, 25, 9, 3, 255, 425, 861, 1025, 3719, 6995, 14687, 31083, 60609, 115375, 17813}},
-{20286, 18, 115672, {1, 1, 5, 13, 1, 55, 109, 239, 13, 939, 1077, 669, 1643, 10949, 25399, 55055, 125829, 253077}},
-{20287, 18, 115681, {1, 1, 5, 3, 15, 51, 13, 133, 257, 387, 2017, 2223, 1479, 9377, 12867, 9833, 32323, 6255}},
-{20288, 18, 115688, {1, 3, 1, 9, 1, 53, 121, 163, 349, 491, 1867, 3403, 6859, 459, 1483, 23893, 66851, 150843}},
-{20289, 18, 115694, {1, 1, 1, 1, 1, 33, 51, 33, 177, 633, 449, 2705, 663, 3701, 8331, 43895, 87223, 48587}},
-{20290, 18, 115699, {1, 3, 5, 7, 23, 7, 99, 43, 217, 31, 749, 2831, 1557, 3295, 6797, 45229, 46831, 62183}},
-{20291, 18, 115719, {1, 1, 7, 7, 1, 45, 35, 51, 415, 693, 479, 1017, 6703, 241, 30887, 8953, 26901, 2951}},
-{20292, 18, 115726, {1, 3, 3, 7, 29, 3, 25, 217, 67, 769, 653, 3983, 5513, 15481, 21399, 17525, 81747, 109843}},
-{20293, 18, 115733, {1, 3, 5, 5, 29, 17, 97, 187, 157, 189, 1531, 1123, 4291, 14831, 15493, 62753, 53563, 153679}},
-{20294, 18, 115796, {1, 3, 7, 13, 15, 63, 47, 5, 351, 275, 1177, 3947, 6755, 1319, 17053, 14267, 98215, 228795}},
-{20295, 18, 115879, {1, 3, 7, 5, 19, 45, 43, 223, 213, 903, 539, 267, 83, 6951, 2979, 56929, 58405, 198373}},
-{20296, 18, 115880, {1, 1, 5, 11, 21, 37, 109, 103, 29, 49, 17, 3987, 5679, 2559, 17391, 46157, 38743, 82245}},
-{20297, 18, 115888, {1, 1, 3, 7, 7, 35, 57, 187, 113, 361, 721, 1821, 6473, 10233, 22549, 37725, 8445, 220669}},
-{20298, 18, 115908, {1, 3, 3, 9, 21, 41, 73, 29, 163, 701, 1277, 3869, 1529, 4889, 10091, 65507, 53829, 191347}},
-{20299, 18, 115925, {1, 1, 5, 15, 5, 21, 39, 39, 341, 271, 1543, 3161, 3935, 8319, 24921, 19575, 95009, 256221}},
-{20300, 18, 115942, {1, 1, 1, 3, 11, 33, 63, 189, 21, 773, 1261, 3947, 183, 6769, 31337, 22179, 57255, 8323}},
-{20301, 18, 115978, {1, 1, 3, 15, 29, 59, 103, 251, 107, 499, 915, 387, 3127, 5597, 3345, 15657, 979, 91685}},
-{20302, 18, 115986, {1, 3, 3, 11, 13, 27, 9, 137, 177, 75, 567, 1511, 7355, 3087, 15309, 51733, 87329, 217125}},
-{20303, 18, 116014, {1, 1, 1, 15, 9, 43, 113, 177, 507, 379, 765, 75, 6895, 7523, 24611, 7315, 49653, 59263}},
-{20304, 18, 116019, {1, 3, 1, 5, 29, 23, 59, 215, 267, 161, 1957, 341, 4081, 9635, 3345, 12323, 128751, 144577}},
-{20305, 18, 116031, {1, 3, 3, 13, 17, 55, 59, 73, 65, 697, 1209, 3345, 5629, 4545, 23043, 37649, 55015, 10263}},
-{20306, 18, 116048, {1, 1, 7, 1, 21, 3, 7, 19, 445, 417, 1677, 799, 1241, 15463, 19815, 52845, 81309, 256713}},
-{20307, 18, 116069, {1, 1, 3, 13, 13, 57, 17, 199, 3, 377, 1799, 2713, 3937, 12511, 7439, 33605, 56697, 168195}},
-{20308, 18, 116091, {1, 3, 1, 7, 21, 53, 115, 97, 389, 83, 961, 813, 1499, 3411, 22377, 33323, 118405, 115947}},
-{20309, 18, 116103, {1, 3, 7, 11, 23, 43, 85, 249, 151, 893, 833, 901, 7731, 13467, 14721, 38613, 104033, 136097}},
-{20310, 18, 116107, {1, 3, 1, 11, 23, 23, 119, 129, 175, 159, 1031, 2379, 2753, 6755, 10979, 18225, 52375, 257003}},
-{20311, 18, 116145, {1, 3, 1, 13, 1, 9, 61, 255, 433, 621, 1469, 705, 5841, 7421, 23873, 30487, 55823, 119705}},
-{20312, 18, 116152, {1, 3, 1, 15, 19, 31, 29, 163, 87, 793, 885, 2495, 4609, 2757, 5333, 52937, 79187, 228777}},
-{20313, 18, 116247, {1, 1, 1, 3, 17, 43, 69, 241, 143, 173, 327, 2747, 5617, 16347, 16155, 47775, 25917, 163663}},
-{20314, 18, 116289, {1, 1, 1, 1, 19, 19, 15, 27, 25, 139, 691, 4019, 3055, 10301, 11281, 10957, 59117, 178149}},
-{20315, 18, 116316, {1, 1, 1, 3, 15, 15, 37, 89, 103, 7, 527, 2823, 7205, 6831, 25179, 22249, 103323, 31251}},
-{20316, 18, 116344, {1, 1, 3, 3, 7, 49, 7, 241, 37, 11, 577, 1987, 1935, 14787, 16411, 36305, 65185, 221253}},
-{20317, 18, 116354, {1, 1, 1, 5, 31, 51, 123, 169, 441, 13, 721, 2359, 5687, 2641, 16339, 8441, 55967, 98775}},
-{20318, 18, 116368, {1, 1, 7, 5, 21, 23, 91, 229, 23, 105, 339, 2371, 7803, 14913, 12651, 40573, 117399, 134865}},
-{20319, 18, 116377, {1, 3, 1, 15, 19, 27, 127, 77, 469, 343, 451, 2251, 6705, 7765, 8623, 10367, 100379, 140899}},
-{20320, 18, 116383, {1, 3, 1, 5, 1, 11, 93, 231, 33, 133, 1545, 1015, 7577, 8871, 29975, 12141, 130833, 103123}},
-{20321, 18, 116387, {1, 3, 3, 5, 7, 25, 95, 93, 293, 543, 1785, 2097, 6045, 4225, 607, 443, 72055, 32269}},
-{20322, 18, 116408, {1, 1, 1, 1, 5, 55, 47, 105, 189, 359, 1589, 765, 2303, 11963, 25565, 40669, 98977, 242089}},
-{20323, 18, 116428, {1, 1, 1, 15, 13, 45, 121, 235, 125, 181, 1891, 3265, 2097, 3207, 31647, 13407, 22515, 15155}},
-{20324, 18, 116445, {1, 1, 5, 15, 13, 11, 81, 233, 307, 505, 221, 813, 6483, 741, 9819, 19405, 74235, 144761}},
-{20325, 18, 116476, {1, 3, 5, 7, 9, 25, 31, 209, 337, 473, 1831, 2711, 5551, 13531, 28747, 1875, 6401, 159995}},
-{20326, 18, 116482, {1, 1, 7, 7, 29, 3, 127, 207, 387, 849, 1449, 2741, 2105, 885, 18115, 5433, 122119, 16969}},
-{20327, 18, 116488, {1, 3, 7, 9, 25, 17, 43, 209, 41, 927, 409, 1567, 1609, 12487, 16305, 41365, 10991, 172127}},
-{20328, 18, 116493, {1, 1, 3, 7, 27, 29, 63, 127, 81, 283, 1459, 143, 5993, 14027, 8055, 28065, 128389, 255307}},
-{20329, 18, 116502, {1, 3, 7, 11, 13, 41, 63, 223, 215, 901, 1853, 2881, 5149, 7439, 4519, 33279, 127765, 139431}},
-{20330, 18, 116518, {1, 3, 7, 7, 15, 61, 61, 173, 221, 711, 191, 3863, 2695, 9663, 6277, 8791, 128019, 256755}},
-{20331, 18, 116524, {1, 3, 1, 9, 29, 45, 83, 43, 297, 605, 1887, 2421, 2307, 5199, 17275, 39225, 127215, 253687}},
-{20332, 18, 116527, {1, 1, 5, 3, 21, 23, 121, 125, 497, 945, 1367, 2757, 3481, 8607, 32447, 62373, 32171, 226621}},
-{20333, 18, 116549, {1, 3, 1, 5, 7, 1, 71, 255, 465, 951, 129, 1989, 6053, 3737, 6511, 54519, 16947, 124491}},
-{20334, 18, 116561, {1, 3, 5, 1, 9, 21, 127, 49, 85, 615, 1897, 1715, 7923, 10309, 16919, 24131, 18015, 140195}},
-{20335, 18, 116562, {1, 1, 1, 1, 5, 27, 3, 205, 29, 319, 485, 3941, 7829, 789, 4207, 39939, 67761, 152459}},
-{20336, 18, 116568, {1, 3, 7, 11, 9, 41, 1, 129, 511, 831, 1007, 2011, 6211, 9179, 20877, 62121, 21879, 23661}},
-{20337, 18, 116577, {1, 1, 7, 1, 19, 53, 75, 123, 181, 735, 925, 1065, 3317, 3201, 27473, 19379, 78223, 45725}},
-{20338, 18, 116590, {1, 1, 5, 9, 9, 61, 3, 193, 441, 815, 583, 3235, 247, 14091, 19877, 33505, 3477, 20111}},
-{20339, 18, 116602, {1, 1, 5, 13, 29, 53, 55, 165, 359, 889, 1833, 1543, 7913, 307, 22853, 37839, 15569, 140127}},
-{20340, 18, 116607, {1, 1, 1, 15, 21, 53, 63, 195, 299, 1019, 1371, 1311, 5401, 8015, 30335, 56281, 61011, 59279}},
-{20341, 18, 116611, {1, 1, 3, 13, 3, 57, 45, 239, 445, 419, 581, 3971, 4621, 9327, 27255, 53069, 126415, 250313}},
-{20342, 18, 116626, {1, 3, 1, 9, 5, 63, 21, 25, 447, 961, 1857, 3123, 3029, 9743, 26069, 38251, 58475, 108737}},
-{20343, 18, 116637, {1, 3, 1, 15, 13, 59, 5, 21, 171, 107, 1631, 2407, 6695, 8079, 2805, 50995, 53173, 104757}},
-{20344, 18, 116647, {1, 3, 7, 7, 1, 55, 103, 67, 369, 533, 515, 2363, 5147, 11633, 20435, 24591, 68155, 140029}},
-{20345, 18, 116665, {1, 3, 7, 13, 19, 51, 13, 149, 159, 915, 1029, 2825, 5259, 5139, 31325, 42825, 119923, 227811}},
-{20346, 18, 116674, {1, 3, 3, 3, 23, 17, 121, 25, 403, 333, 491, 2869, 881, 12997, 5101, 48351, 90831, 143009}},
-{20347, 18, 116700, {1, 1, 3, 15, 23, 63, 93, 43, 107, 393, 419, 3509, 1543, 10295, 11019, 8389, 73753, 42681}},
-{20348, 18, 116714, {1, 1, 7, 1, 29, 49, 41, 189, 303, 955, 1241, 1623, 2269, 3413, 6261, 2155, 90945, 95117}},
-{20349, 18, 116719, {1, 1, 3, 15, 31, 13, 103, 241, 189, 283, 1303, 1693, 1587, 16313, 205, 43421, 121799, 200151}},
-{20350, 18, 116744, {1, 3, 5, 1, 29, 27, 105, 83, 345, 411, 1197, 3489, 5891, 1137, 7311, 681, 127991, 69533}},
-{20351, 18, 116764, {1, 3, 5, 15, 31, 11, 105, 221, 57, 39, 145, 3233, 1431, 16271, 21225, 47989, 72583, 191327}},
-{20352, 18, 116774, {1, 3, 7, 9, 25, 47, 109, 61, 257, 949, 981, 1383, 8003, 4661, 19555, 20191, 114641, 84817}},
-{20353, 18, 116778, {1, 1, 5, 9, 17, 9, 19, 209, 73, 573, 1039, 2741, 1495, 1615, 6299, 20507, 84729, 166977}},
-{20354, 18, 116798, {1, 3, 5, 13, 27, 51, 39, 203, 437, 725, 1479, 3071, 621, 15563, 28473, 58403, 25943, 116683}},
-{20355, 18, 116803, {1, 1, 3, 9, 5, 29, 63, 61, 329, 305, 523, 2243, 6689, 11773, 19319, 57783, 24265, 218153}},
-{20356, 18, 116806, {1, 3, 7, 5, 17, 27, 115, 9, 243, 613, 679, 1915, 7265, 2989, 13663, 15115, 50779, 235761}},
-{20357, 18, 116827, {1, 1, 5, 5, 13, 35, 111, 151, 255, 569, 1209, 3277, 4503, 3797, 22601, 19523, 126339, 141289}},
-{20358, 18, 116839, {1, 1, 3, 9, 15, 51, 85, 125, 233, 1011, 231, 2949, 1091, 8605, 14855, 62401, 14143, 212557}},
-{20359, 18, 116863, {1, 3, 5, 11, 29, 53, 83, 31, 201, 219, 1083, 967, 6913, 10325, 1971, 55841, 7733, 208883}},
-{20360, 18, 116873, {1, 3, 3, 1, 23, 33, 51, 103, 265, 285, 1363, 2813, 3327, 7921, 13537, 31483, 43405, 189641}},
-{20361, 18, 116882, {1, 1, 7, 15, 27, 3, 5, 87, 117, 437, 1251, 189, 3271, 15579, 25025, 23203, 39421, 133581}},
-{20362, 18, 116887, {1, 1, 5, 1, 9, 3, 91, 45, 71, 557, 2019, 2355, 5539, 2843, 13025, 61017, 3475, 179891}},
-{20363, 18, 116915, {1, 1, 7, 5, 17, 11, 127, 241, 9, 971, 1699, 2719, 1947, 109, 19817, 13949, 120247, 60775}},
-{20364, 18, 116939, {1, 1, 5, 9, 9, 39, 117, 221, 197, 767, 1691, 4075, 3665, 1271, 16119, 64129, 2681, 105325}},
-{20365, 18, 116944, {1, 3, 3, 11, 31, 51, 5, 23, 419, 715, 1985, 4095, 7255, 10491, 25575, 6177, 35917, 178345}},
-{20366, 18, 116953, {1, 3, 5, 7, 15, 23, 99, 203, 461, 509, 1501, 1965, 1105, 1341, 21713, 21901, 129905, 67937}},
-{20367, 18, 116965, {1, 3, 3, 15, 25, 5, 55, 167, 477, 125, 163, 2379, 2433, 12975, 26259, 55825, 19913, 202873}},
-{20368, 18, 117002, {1, 3, 3, 7, 15, 15, 67, 227, 413, 905, 1609, 2083, 4011, 10477, 22809, 61873, 96423, 119253}},
-{20369, 18, 117007, {1, 3, 1, 11, 13, 17, 37, 147, 355, 445, 619, 3181, 5939, 6953, 15859, 37979, 24723, 133037}},
-{20370, 18, 117015, {1, 1, 5, 15, 5, 25, 89, 3, 279, 569, 343, 2453, 5739, 2901, 6709, 43957, 75791, 20791}},
-{20371, 18, 117032, {1, 1, 3, 5, 13, 39, 53, 203, 75, 945, 635, 349, 2339, 2549, 23827, 7903, 128005, 14949}},
-{20372, 18, 117035, {1, 1, 7, 3, 7, 59, 59, 77, 143, 99, 1313, 3957, 3807, 15731, 20919, 60829, 105967, 226767}},
-{20373, 18, 117052, {1, 1, 3, 7, 17, 49, 27, 245, 129, 583, 1055, 741, 5607, 689, 20075, 54837, 113257, 222677}},
-{20374, 18, 117087, {1, 1, 7, 13, 17, 5, 19, 141, 205, 749, 1769, 2981, 5787, 4511, 135, 19475, 113735, 116859}},
-{20375, 18, 117139, {1, 3, 7, 1, 9, 33, 111, 139, 77, 117, 363, 1171, 2587, 1539, 30791, 10697, 6879, 104827}},
-{20376, 18, 117157, {1, 3, 3, 5, 27, 47, 49, 215, 65, 435, 1601, 231, 2047, 10405, 28409, 17013, 103909, 232051}},
-{20377, 18, 117193, {1, 3, 3, 3, 13, 19, 3, 159, 293, 675, 247, 2829, 6703, 6085, 1935, 18209, 15709, 186669}},
-{20378, 18, 117211, {1, 3, 3, 5, 21, 55, 17, 237, 121, 603, 953, 947, 6973, 15979, 11029, 12381, 12807, 131603}},
-{20379, 18, 117214, {1, 3, 5, 3, 3, 41, 121, 203, 283, 349, 1841, 115, 6567, 2131, 883, 50515, 78381, 168189}},
-{20380, 18, 117220, {1, 3, 7, 15, 5, 55, 85, 13, 77, 443, 1711, 1043, 1265, 3701, 5121, 41435, 40637, 69125}},
-{20381, 18, 117238, {1, 1, 5, 15, 15, 33, 67, 235, 3, 95, 1685, 731, 2187, 11857, 7197, 62113, 12565, 127455}},
-{20382, 18, 117248, {1, 3, 7, 7, 11, 45, 125, 231, 263, 611, 221, 195, 6347, 14029, 7823, 52295, 78879, 211441}},
-{20383, 18, 117275, {1, 3, 7, 15, 9, 63, 75, 189, 187, 449, 27, 3647, 4705, 13037, 3773, 36441, 35445, 181793}},
-{20384, 18, 117293, {1, 1, 5, 3, 31, 19, 123, 39, 297, 1017, 1191, 2227, 6085, 5117, 16569, 64743, 29329, 157279}},
-{20385, 18, 117301, {1, 1, 5, 5, 15, 47, 111, 61, 435, 657, 141, 3445, 6921, 7759, 30141, 37631, 85969, 227563}},
-{20386, 18, 117319, {1, 3, 1, 13, 27, 39, 15, 167, 151, 185, 1513, 211, 951, 12705, 25703, 29289, 120993, 156741}},
-{20387, 18, 117338, {1, 3, 7, 7, 7, 39, 19, 221, 351, 951, 1231, 1915, 3043, 189, 18977, 50149, 56583, 122147}},
-{20388, 18, 117347, {1, 1, 5, 15, 29, 37, 77, 207, 291, 851, 131, 1041, 1657, 4393, 5023, 12745, 32253, 204431}},
-{20389, 18, 117361, {1, 1, 7, 15, 11, 59, 85, 255, 67, 23, 1321, 2153, 7043, 417, 15719, 59937, 37619, 109331}},
-{20390, 18, 117380, {1, 3, 7, 15, 25, 37, 43, 15, 385, 735, 1741, 3655, 4215, 1097, 19519, 44313, 99851, 204717}},
-{20391, 18, 117389, {1, 1, 3, 7, 15, 17, 17, 105, 399, 49, 105, 159, 465, 11991, 29797, 23907, 129609, 179013}},
-{20392, 18, 117398, {1, 1, 7, 13, 9, 17, 87, 51, 391, 695, 545, 3061, 4499, 2059, 10095, 13847, 68519, 60611}},
-{20393, 18, 117435, {1, 3, 3, 1, 31, 7, 11, 233, 231, 189, 1599, 1589, 401, 8759, 17273, 43613, 48709, 253521}},
-{20394, 18, 117458, {1, 1, 1, 11, 5, 9, 27, 77, 491, 951, 579, 1635, 3241, 14497, 27149, 45001, 56769, 160731}},
-{20395, 18, 117476, {1, 3, 7, 15, 29, 11, 125, 101, 19, 971, 107, 1525, 3939, 7633, 16355, 24727, 19475, 157571}},
-{20396, 18, 117498, {1, 1, 1, 9, 25, 7, 35, 187, 321, 483, 1919, 1911, 7869, 12903, 26977, 49419, 24973, 214731}},
-{20397, 18, 117500, {1, 1, 5, 3, 23, 1, 11, 143, 315, 1015, 1367, 1555, 1041, 6655, 10481, 49275, 49575, 101061}},
-{20398, 18, 117529, {1, 3, 5, 15, 15, 59, 13, 117, 217, 975, 1821, 3829, 1545, 921, 20875, 43305, 18793, 158651}},
-{20399, 18, 117554, {1, 3, 3, 11, 23, 23, 91, 7, 29, 613, 1093, 3881, 3301, 3751, 16137, 48277, 119813, 177341}},
-{20400, 18, 117556, {1, 3, 3, 15, 7, 37, 115, 19, 147, 585, 1877, 2395, 3343, 9567, 16199, 13969, 89731, 124835}},
-{20401, 18, 117565, {1, 1, 5, 7, 29, 3, 59, 141, 375, 527, 1219, 409, 7155, 2823, 32497, 23103, 73187, 53089}},
-{20402, 18, 117580, {1, 1, 5, 3, 13, 27, 111, 63, 189, 813, 643, 19, 3461, 13891, 26651, 52395, 74729, 148397}},
-{20403, 18, 117585, {1, 3, 5, 1, 27, 61, 97, 227, 123, 829, 1559, 2523, 7737, 6047, 213, 23613, 61571, 7093}},
-{20404, 18, 117592, {1, 1, 1, 11, 17, 1, 73, 203, 391, 937, 321, 3431, 7163, 3547, 29467, 65271, 69775, 226405}},
-{20405, 18, 117597, {1, 1, 5, 15, 25, 7, 75, 199, 511, 731, 1547, 2127, 1609, 5623, 26771, 29935, 76671, 178683}},
-{20406, 18, 117616, {1, 3, 5, 15, 25, 49, 99, 23, 281, 81, 507, 1499, 5235, 9945, 14099, 5993, 319, 178581}},
-{20407, 18, 117637, {1, 3, 7, 9, 5, 13, 105, 7, 135, 827, 927, 3463, 839, 7047, 19863, 63859, 13951, 221795}},
-{20408, 18, 117644, {1, 1, 1, 13, 7, 21, 59, 9, 467, 299, 1035, 1395, 7413, 7313, 24769, 44043, 50679, 72867}},
-{20409, 18, 117659, {1, 1, 7, 1, 31, 33, 95, 155, 429, 413, 493, 2025, 2069, 551, 507, 13515, 3507, 93873}},
-{20410, 18, 117703, {1, 1, 3, 5, 3, 33, 109, 1, 299, 727, 495, 2981, 3795, 11467, 27173, 4171, 6859, 129961}},
-{20411, 18, 117704, {1, 1, 7, 9, 23, 41, 113, 103, 161, 303, 1565, 2637, 7113, 11635, 13707, 3559, 21007, 250107}},
-{20412, 18, 117727, {1, 1, 5, 13, 1, 49, 11, 87, 31, 77, 1847, 1137, 3031, 1943, 28755, 32197, 96043, 152447}},
-{20413, 18, 117738, {1, 1, 3, 7, 3, 3, 123, 65, 175, 809, 681, 2135, 5279, 7119, 4573, 19287, 90235, 183391}},
-{20414, 18, 117770, {1, 3, 1, 13, 7, 5, 25, 151, 437, 155, 1841, 219, 5641, 12097, 6153, 11, 60315, 169293}},
-{20415, 18, 117796, {1, 1, 7, 5, 21, 29, 23, 83, 35, 651, 1507, 635, 3867, 12133, 25523, 55341, 105741, 240349}},
-{20416, 18, 117799, {1, 1, 1, 15, 9, 29, 27, 151, 463, 747, 547, 577, 1263, 15235, 6695, 60849, 72231, 175671}},
-{20417, 18, 117820, {1, 3, 5, 11, 11, 43, 81, 37, 505, 509, 1325, 3295, 839, 5855, 19795, 1403, 15711, 219481}},
-{20418, 18, 117832, {1, 3, 3, 15, 25, 61, 121, 37, 201, 133, 537, 1345, 4213, 13023, 18795, 8949, 84431, 105521}},
-{20419, 18, 117840, {1, 3, 7, 11, 13, 51, 87, 245, 357, 7, 699, 2003, 5963, 1399, 69, 19083, 114585, 232313}},
-{20420, 18, 117843, {1, 1, 1, 13, 9, 29, 65, 123, 37, 885, 227, 2795, 1037, 10905, 21217, 4081, 77643, 254245}},
-{20421, 18, 117865, {1, 3, 1, 3, 25, 23, 71, 189, 253, 785, 1337, 1275, 3285, 1067, 8607, 3883, 119099, 116637}},
-{20422, 18, 117868, {1, 1, 1, 15, 19, 43, 17, 89, 257, 175, 1943, 207, 597, 9279, 405, 33209, 65221, 39557}},
-{20423, 18, 117874, {1, 1, 7, 5, 7, 47, 127, 11, 197, 871, 23, 1951, 6829, 7831, 5223, 56287, 115649, 114283}},
-{20424, 18, 117886, {1, 3, 1, 3, 1, 35, 81, 189, 19, 117, 1683, 469, 8117, 5449, 22871, 5505, 125111, 128717}},
-{20425, 18, 117962, {1, 3, 7, 5, 7, 31, 105, 57, 387, 691, 1293, 3103, 2329, 16247, 18357, 55453, 112633, 225641}},
-{20426, 18, 117967, {1, 3, 1, 3, 13, 3, 65, 25, 47, 413, 521, 3507, 1793, 14431, 22341, 39813, 46399, 204501}},
-{20427, 18, 117995, {1, 3, 1, 1, 31, 37, 21, 45, 261, 665, 1243, 1937, 5001, 3789, 26473, 20153, 107131, 75523}},
-{20428, 18, 118000, {1, 3, 5, 15, 27, 61, 109, 139, 19, 583, 353, 445, 53, 67, 20753, 57827, 116527, 55109}},
-{20429, 18, 118017, {1, 1, 3, 3, 1, 37, 113, 21, 305, 967, 1703, 2095, 1059, 2843, 22381, 24871, 24765, 52425}},
-{20430, 18, 118037, {1, 3, 7, 11, 27, 59, 111, 111, 283, 79, 1227, 3631, 4169, 5671, 7769, 56553, 75503, 206259}},
-{20431, 18, 118038, {1, 1, 5, 11, 11, 1, 127, 13, 17, 255, 1383, 2879, 6785, 289, 7061, 53067, 11539, 131405}},
-{20432, 18, 118051, {1, 1, 5, 15, 29, 27, 67, 15, 247, 689, 579, 3237, 5279, 13847, 20305, 60237, 115841, 144855}},
-{20433, 18, 118057, {1, 1, 5, 1, 9, 25, 75, 11, 83, 1015, 281, 1617, 7449, 10673, 7033, 38839, 113703, 233101}},
-{20434, 18, 118072, {1, 3, 3, 3, 23, 41, 81, 109, 199, 969, 935, 1793, 6921, 4013, 9625, 48149, 54395, 1193}},
-{20435, 18, 118080, {1, 3, 5, 7, 19, 63, 25, 201, 63, 799, 765, 533, 1417, 3199, 7773, 44247, 112207, 11783}},
-{20436, 18, 118098, {1, 3, 1, 11, 7, 25, 87, 159, 491, 749, 1157, 667, 2951, 12019, 22259, 36933, 124159, 176041}},
-{20437, 18, 118107, {1, 1, 5, 15, 21, 19, 113, 175, 129, 385, 2025, 2685, 1925, 8547, 4835, 15953, 128023, 236341}},
-{20438, 18, 118109, {1, 1, 1, 9, 13, 47, 25, 81, 389, 249, 1857, 1061, 4439, 3717, 16299, 23247, 95275, 222701}},
-{20439, 18, 118114, {1, 3, 3, 1, 3, 61, 61, 117, 159, 689, 43, 113, 4203, 7699, 27607, 37195, 63415, 90481}},
-{20440, 18, 118123, {1, 3, 1, 5, 11, 49, 73, 13, 307, 655, 645, 2765, 6079, 12687, 22417, 44713, 5247, 40265}},
-{20441, 18, 118150, {1, 1, 7, 13, 5, 55, 57, 237, 317, 101, 481, 2515, 707, 6385, 9421, 50557, 92395, 193737}},
-{20442, 18, 118159, {1, 3, 5, 1, 27, 35, 65, 107, 63, 57, 1699, 4077, 4279, 8547, 15137, 11533, 117641, 64925}},
-{20443, 18, 118164, {1, 1, 5, 1, 13, 7, 7, 141, 305, 191, 2033, 2677, 6025, 12927, 4057, 12047, 60253, 90803}},
-{20444, 18, 118173, {1, 1, 7, 3, 1, 9, 63, 233, 185, 97, 913, 187, 4321, 8951, 27669, 27035, 30029, 218725}},
-{20445, 18, 118201, {1, 1, 7, 1, 11, 59, 41, 195, 335, 551, 491, 3079, 7777, 4003, 24543, 17165, 103261, 167505}},
-{20446, 18, 118212, {1, 1, 3, 3, 9, 59, 37, 185, 289, 845, 1083, 63, 7439, 4677, 29245, 40813, 16295, 45499}},
-{20447, 18, 118246, {1, 3, 5, 1, 1, 37, 89, 5, 277, 493, 155, 1641, 5395, 11389, 26247, 2833, 103803, 74447}},
-{20448, 18, 118257, {1, 1, 3, 1, 29, 55, 83, 211, 377, 583, 1075, 2679, 7157, 11719, 1653, 5977, 52263, 45531}},
-{20449, 18, 118303, {1, 1, 5, 15, 1, 31, 89, 7, 239, 821, 887, 1319, 225, 14555, 5443, 44717, 99803, 241577}},
-{20450, 18, 118310, {1, 3, 5, 11, 7, 23, 81, 161, 67, 1011, 177, 2837, 7767, 14385, 29415, 9377, 7407, 128403}},
-{20451, 18, 118313, {1, 1, 7, 11, 3, 13, 13, 237, 199, 601, 481, 3809, 6591, 8497, 25361, 22547, 28317, 22961}},
-{20452, 18, 118324, {1, 3, 1, 1, 31, 29, 105, 161, 483, 391, 321, 1087, 4149, 8803, 22291, 24611, 114447, 33645}},
-{20453, 18, 118334, {1, 3, 1, 11, 1, 47, 41, 45, 287, 503, 169, 2265, 1835, 6609, 25245, 7069, 61137, 160653}},
-{20454, 18, 118336, {1, 1, 7, 13, 11, 39, 29, 39, 489, 205, 741, 2871, 377, 10679, 11689, 50947, 85309, 95697}},
-{20455, 18, 118339, {1, 3, 7, 7, 23, 19, 103, 15, 79, 425, 369, 2009, 4417, 11031, 2113, 36969, 73241, 120903}},
-{20456, 18, 118353, {1, 3, 1, 7, 27, 9, 43, 33, 123, 895, 223, 1045, 2701, 3339, 12099, 24449, 52973, 175671}},
-{20457, 18, 118354, {1, 3, 5, 5, 3, 1, 13, 117, 429, 167, 1361, 2299, 7565, 1153, 9259, 29209, 25747, 71005}},
-{20458, 18, 118390, {1, 3, 1, 15, 7, 7, 13, 209, 73, 523, 1549, 2545, 5583, 10209, 27205, 41243, 14217, 208993}},
-{20459, 18, 118396, {1, 3, 5, 5, 3, 29, 99, 255, 479, 297, 1319, 2171, 7321, 14425, 15869, 44449, 10917, 171165}},
-{20460, 18, 118436, {1, 3, 3, 11, 13, 49, 29, 95, 79, 987, 161, 859, 6503, 8839, 14131, 30249, 16183, 40257}},
-{20461, 18, 118453, {1, 3, 3, 11, 27, 7, 27, 33, 255, 847, 789, 3897, 2599, 16107, 22379, 1853, 102713, 197547}},
-{20462, 18, 118466, {1, 1, 3, 9, 29, 11, 107, 227, 35, 183, 639, 1585, 313, 1451, 19789, 13855, 94277, 85569}},
-{20463, 18, 118492, {1, 3, 7, 7, 25, 33, 101, 49, 137, 457, 2027, 3317, 1961, 6097, 739, 12875, 69503, 95453}},
-{20464, 18, 118506, {1, 3, 3, 11, 29, 13, 127, 3, 31, 319, 1341, 927, 5067, 13891, 31265, 41381, 49341, 160343}},
-{20465, 18, 118525, {1, 1, 3, 15, 31, 21, 93, 155, 471, 707, 1395, 2995, 867, 10353, 8137, 44267, 24823, 6113}},
-{20466, 18, 118557, {1, 3, 1, 7, 7, 33, 83, 79, 349, 687, 1045, 1183, 4441, 15199, 1953, 36395, 84691, 134939}},
-{20467, 18, 118561, {1, 1, 3, 15, 13, 21, 41, 105, 189, 439, 1171, 4005, 7641, 1597, 24317, 58749, 35539, 220647}},
-{20468, 18, 118586, {1, 1, 3, 15, 13, 39, 49, 5, 461, 613, 1633, 1951, 7959, 5733, 10061, 18829, 49505, 90033}},
-{20469, 18, 118606, {1, 3, 5, 5, 29, 25, 19, 227, 379, 525, 687, 2629, 7729, 4791, 5911, 14481, 49063, 216669}},
-{20470, 18, 118627, {1, 3, 7, 7, 7, 63, 93, 227, 79, 165, 1971, 1695, 4485, 6009, 8769, 12861, 83653, 27667}},
-{20471, 18, 118641, {1, 1, 5, 5, 25, 11, 23, 89, 363, 491, 459, 4063, 3787, 9375, 28011, 44757, 56441, 116609}},
-{20472, 18, 118654, {1, 3, 5, 9, 7, 53, 43, 149, 435, 35, 135, 1759, 3197, 7749, 12731, 28295, 25901, 125847}},
-{20473, 18, 118687, {1, 1, 3, 5, 15, 15, 1, 215, 307, 711, 1971, 2795, 677, 11921, 10303, 37997, 6653, 51295}},
-{20474, 18, 118688, {1, 1, 5, 15, 1, 59, 75, 195, 51, 215, 1303, 3023, 8023, 10951, 13015, 23513, 37029, 23581}},
-{20475, 18, 118735, {1, 1, 1, 3, 27, 3, 77, 165, 97, 499, 937, 1129, 6649, 11305, 27763, 32849, 78251, 210407}},
-{20476, 18, 118737, {1, 3, 3, 3, 9, 21, 19, 197, 339, 53, 1875, 1057, 3485, 14645, 13417, 39307, 81437, 45857}},
-{20477, 18, 118750, {1, 1, 1, 5, 19, 5, 95, 205, 399, 699, 819, 1927, 7913, 8109, 1223, 28595, 397, 81051}},
-{20478, 18, 118773, {1, 3, 7, 13, 23, 11, 37, 167, 189, 813, 1199, 3545, 655, 13239, 10469, 33895, 119025, 185361}},
-{20479, 18, 118778, {1, 1, 5, 11, 9, 13, 41, 37, 443, 269, 1199, 1347, 7081, 11273, 14389, 64083, 117901, 51903}},
-{20480, 18, 118786, {1, 1, 3, 13, 5, 17, 117, 151, 155, 637, 731, 1839, 855, 9749, 19529, 18101, 20341, 21941}},
-{20481, 18, 118809, {1, 1, 1, 11, 15, 17, 35, 9, 91, 907, 667, 853, 1455, 10097, 31277, 749, 47089, 219517}},
-{20482, 18, 118833, {1, 3, 7, 1, 27, 31, 9, 145, 309, 811, 5, 2645, 7851, 1953, 21427, 18805, 108755, 77215}},
-{20483, 18, 118853, {1, 1, 7, 3, 21, 7, 25, 233, 145, 1015, 43, 2205, 4735, 13257, 24001, 50469, 42567, 253745}},
-{20484, 18, 118854, {1, 3, 1, 15, 3, 53, 51, 45, 397, 379, 641, 895, 7569, 15783, 23923, 6147, 121395, 261853}},
-{20485, 18, 118863, {1, 1, 1, 1, 23, 47, 35, 125, 289, 65, 1875, 2309, 519, 5435, 5271, 25319, 14557, 19389}},
-{20486, 18, 118881, {1, 3, 5, 7, 27, 43, 15, 61, 357, 791, 1781, 3671, 3911, 1325, 5607, 44107, 67873, 119849}},
-{20487, 18, 118896, {1, 3, 1, 5, 25, 37, 105, 51, 491, 407, 475, 1763, 1425, 14883, 31435, 48979, 120667, 131089}},
-{20488, 18, 118917, {1, 3, 5, 13, 1, 51, 109, 161, 215, 871, 185, 2389, 7977, 6705, 14045, 45569, 44557, 114795}},
-{20489, 18, 118921, {1, 3, 7, 11, 17, 21, 111, 183, 343, 593, 447, 3995, 759, 3709, 32655, 30141, 127225, 120899}},
-{20490, 18, 118939, {1, 1, 5, 3, 17, 3, 69, 25, 113, 897, 1933, 2717, 2003, 5847, 2541, 62415, 50975, 97903}},
-{20491, 18, 118948, {1, 1, 1, 1, 9, 35, 107, 81, 257, 57, 1719, 4049, 1237, 10659, 4689, 20887, 90791, 251911}},
-{20492, 18, 118960, {1, 1, 7, 11, 1, 49, 83, 213, 169, 169, 825, 2983, 5833, 2413, 32165, 47459, 129021, 156217}},
-{20493, 18, 118970, {1, 1, 5, 13, 15, 39, 61, 93, 407, 553, 839, 4035, 6609, 6327, 945, 49625, 127867, 240161}},
-{20494, 18, 118983, {1, 1, 1, 15, 23, 47, 21, 235, 81, 431, 1819, 1141, 7973, 4623, 4539, 23201, 83111, 230857}},
-{20495, 18, 119025, {1, 3, 3, 15, 9, 15, 15, 173, 29, 803, 1453, 2621, 8095, 6639, 6607, 21471, 44785, 122271}},
-{20496, 18, 119026, {1, 3, 3, 7, 21, 5, 127, 203, 43, 581, 1925, 165, 4615, 9141, 18563, 54413, 71559, 172791}},
-{20497, 18, 119064, {1, 3, 3, 3, 27, 31, 55, 3, 381, 971, 1087, 2659, 139, 10935, 9189, 3445, 15071, 218873}},
-{20498, 18, 119069, {1, 3, 1, 3, 1, 57, 47, 71, 85, 335, 207, 225, 2931, 14721, 21431, 17199, 745, 177403}},
-{20499, 18, 119079, {1, 3, 1, 7, 7, 17, 21, 57, 345, 29, 1147, 1179, 7371, 14725, 27445, 62061, 16483, 112489}},
-{20500, 18, 119085, {1, 3, 7, 15, 23, 11, 91, 1, 1, 117, 1665, 3899, 5683, 14497, 25633, 6233, 104029, 22155}},
-{20501, 18, 119115, {1, 3, 5, 9, 1, 27, 15, 187, 37, 329, 585, 729, 5651, 15715, 4339, 1899, 90611, 195643}},
-{20502, 18, 119165, {1, 1, 3, 11, 1, 45, 95, 103, 13, 83, 319, 2295, 6333, 13469, 19237, 55985, 129725, 141699}},
-{20503, 18, 119166, {1, 1, 5, 11, 7, 41, 97, 159, 511, 617, 1545, 3023, 7919, 8437, 8345, 16701, 69053, 105047}},
-{20504, 18, 119193, {1, 3, 3, 11, 29, 35, 23, 95, 277, 931, 857, 3887, 4597, 10841, 12947, 18009, 61499, 242827}},
-{20505, 18, 119194, {1, 1, 3, 3, 7, 63, 35, 161, 125, 637, 149, 1045, 3297, 16213, 1543, 8073, 80373, 61507}},
-{20506, 18, 119199, {1, 1, 7, 5, 31, 43, 113, 189, 181, 659, 1971, 3309, 4237, 4279, 31563, 29429, 17443, 154385}},
-{20507, 18, 119215, {1, 1, 1, 13, 19, 43, 99, 91, 47, 477, 153, 3295, 6281, 779, 17169, 343, 1723, 171133}},
-{20508, 18, 119218, {1, 1, 1, 15, 9, 35, 123, 45, 417, 631, 1415, 1835, 3063, 897, 18947, 62477, 12759, 97831}},
-{20509, 18, 119241, {1, 1, 3, 13, 31, 1, 31, 139, 411, 605, 1829, 303, 3891, 15807, 7335, 44833, 87427, 62183}},
-{20510, 18, 119277, {1, 1, 3, 13, 29, 55, 97, 107, 241, 981, 1281, 3295, 6825, 15865, 4221, 24695, 54203, 252069}},
-{20511, 18, 119301, {1, 3, 7, 13, 1, 3, 33, 165, 483, 813, 127, 1717, 8077, 3521, 23465, 41705, 2769, 173233}},
-{20512, 18, 119306, {1, 3, 1, 11, 11, 51, 39, 125, 375, 825, 1775, 2923, 4903, 4779, 907, 47787, 22293, 169631}},
-{20513, 18, 119335, {1, 3, 5, 5, 13, 27, 43, 229, 267, 153, 567, 3403, 2103, 6203, 29629, 29715, 116735, 122515}},
-{20514, 18, 119344, {1, 3, 5, 13, 3, 3, 15, 5, 345, 343, 691, 3703, 361, 2019, 9309, 26909, 22897, 103555}},
-{20515, 18, 119364, {1, 3, 1, 11, 9, 25, 123, 235, 131, 469, 1749, 3681, 3841, 10157, 15183, 61413, 42207, 170359}},
-{20516, 18, 119373, {1, 1, 7, 3, 13, 9, 7, 191, 239, 417, 817, 1381, 1179, 2719, 21025, 17429, 50295, 196485}},
-{20517, 18, 119382, {1, 1, 7, 9, 9, 31, 123, 229, 381, 569, 513, 1617, 6141, 9717, 31769, 30159, 113697, 254237}},
-{20518, 18, 119410, {1, 1, 1, 15, 31, 43, 37, 17, 283, 905, 297, 1317, 1883, 11313, 5653, 55655, 121029, 149831}},
-{20519, 18, 119425, {1, 1, 1, 7, 7, 47, 83, 101, 497, 465, 1133, 3877, 5371, 3355, 17161, 50185, 120837, 255103}},
-{20520, 18, 119459, {1, 1, 3, 5, 5, 19, 3, 251, 433, 303, 1193, 1263, 2139, 473, 10725, 57725, 111411, 133687}},
-{20521, 18, 119473, {1, 1, 1, 7, 3, 1, 99, 115, 481, 395, 115, 1699, 953, 2807, 7227, 52781, 2855, 161159}},
-{20522, 18, 119486, {1, 1, 5, 9, 25, 25, 85, 3, 451, 847, 837, 3669, 4717, 3661, 29111, 43735, 49445, 100379}},
-{20523, 18, 119500, {1, 1, 7, 9, 19, 61, 67, 123, 195, 483, 1741, 2719, 7809, 5035, 30689, 21325, 56191, 46127}},
-{20524, 18, 119508, {1, 1, 3, 11, 15, 39, 101, 27, 103, 807, 1557, 1647, 1285, 16169, 20203, 57153, 60749, 71361}},
-{20525, 18, 119511, {1, 3, 3, 3, 19, 1, 93, 31, 105, 925, 689, 3061, 7451, 12667, 27179, 36295, 61011, 90321}},
-{20526, 18, 119517, {1, 3, 7, 15, 19, 35, 47, 241, 261, 935, 1033, 751, 6519, 6911, 13519, 2539, 40285, 81535}},
-{20527, 18, 119528, {1, 1, 7, 13, 17, 31, 71, 135, 167, 5, 673, 2909, 4377, 3453, 31289, 38081, 21993, 192933}},
-{20528, 18, 119533, {1, 1, 5, 15, 23, 49, 85, 127, 13, 849, 1661, 2099, 3479, 3613, 21723, 58147, 56321, 203171}},
-{20529, 18, 119539, {1, 1, 7, 15, 23, 63, 3, 207, 445, 573, 1419, 1161, 2237, 1251, 23387, 65259, 81447, 74555}},
-{20530, 18, 119542, {1, 3, 5, 3, 25, 61, 37, 25, 287, 969, 37, 1615, 7923, 4457, 27611, 8519, 113957, 237427}},
-{20531, 18, 119546, {1, 3, 5, 11, 11, 25, 117, 169, 149, 701, 139, 2835, 6029, 9067, 841, 51707, 9287, 115825}},
-{20532, 18, 119566, {1, 1, 1, 13, 31, 5, 9, 5, 313, 1023, 551, 3635, 6765, 13379, 29135, 39737, 80913, 256355}},
-{20533, 18, 119587, {1, 3, 1, 13, 9, 23, 105, 117, 181, 211, 755, 555, 2763, 13965, 14743, 63725, 16377, 203435}},
-{20534, 18, 119590, {1, 3, 1, 15, 11, 45, 111, 147, 471, 321, 381, 2921, 6423, 629, 25117, 51213, 126941, 181931}},
-{20535, 18, 119607, {1, 1, 1, 11, 1, 49, 127, 105, 315, 1, 859, 1223, 5967, 2521, 14491, 58399, 45155, 192567}},
-{20536, 18, 119614, {1, 1, 3, 9, 19, 21, 73, 93, 95, 307, 293, 3243, 4765, 2253, 16775, 29861, 3785, 90357}},
-{20537, 18, 119625, {1, 1, 3, 7, 3, 53, 33, 167, 165, 509, 1133, 169, 6951, 7715, 26317, 5249, 86235, 39649}},
-{20538, 18, 119633, {1, 1, 5, 5, 3, 47, 105, 89, 201, 1003, 877, 635, 2225, 6391, 21247, 5707, 1233, 87055}},
-{20539, 18, 119634, {1, 1, 1, 1, 9, 39, 61, 201, 435, 843, 1245, 533, 1757, 1117, 19687, 54817, 32495, 228865}},
-{20540, 18, 119643, {1, 3, 1, 1, 3, 61, 63, 117, 143, 217, 435, 1977, 2647, 7631, 12969, 50211, 26483, 256329}},
-{20541, 18, 119683, {1, 3, 3, 9, 21, 25, 113, 243, 457, 143, 833, 1505, 3071, 1845, 17867, 58205, 103819, 185215}},
-{20542, 18, 119704, {1, 1, 5, 7, 23, 51, 11, 117, 195, 535, 685, 31, 3037, 9719, 22811, 42959, 21021, 126297}},
-{20543, 18, 119710, {1, 3, 3, 1, 1, 17, 107, 245, 257, 547, 887, 45, 5243, 2439, 22191, 19503, 2143, 75187}},
-{20544, 18, 119734, {1, 3, 7, 9, 11, 27, 123, 197, 353, 151, 1115, 403, 1105, 7425, 7463, 42065, 116187, 154537}},
-{20545, 18, 119752, {1, 3, 5, 15, 23, 5, 49, 177, 223, 615, 1255, 2081, 321, 8733, 19549, 53027, 275, 62739}},
-{20546, 18, 119760, {1, 3, 7, 1, 17, 61, 3, 233, 249, 763, 369, 555, 1621, 7221, 22575, 13295, 99793, 233635}},
-{20547, 18, 119826, {1, 1, 3, 1, 27, 41, 125, 113, 47, 583, 543, 453, 1213, 14187, 1645, 35761, 110051, 197081}},
-{20548, 18, 119922, {1, 1, 7, 9, 29, 43, 105, 125, 489, 135, 153, 2279, 4079, 6731, 12055, 60181, 82563, 173991}},
-{20549, 18, 119931, {1, 3, 7, 3, 29, 1, 67, 151, 127, 625, 113, 2127, 6723, 12359, 28609, 60605, 20375, 120129}},
-{20550, 18, 119977, {1, 1, 5, 7, 9, 13, 27, 171, 129, 199, 303, 4045, 2047, 8887, 22233, 57571, 40545, 36479}},
-{20551, 18, 120015, {1, 3, 1, 7, 1, 5, 127, 203, 213, 691, 1155, 27, 5409, 13519, 6747, 42371, 37089, 145855}},
-{20552, 18, 120020, {1, 3, 3, 9, 3, 33, 119, 25, 337, 715, 1093, 987, 7157, 14975, 28595, 19021, 1243, 148707}},
-{20553, 18, 120083, {1, 3, 1, 13, 3, 41, 81, 151, 23, 787, 181, 2357, 5077, 1997, 6451, 25505, 44875, 198341}},
-{20554, 18, 120086, {1, 1, 7, 3, 5, 15, 9, 169, 337, 487, 1325, 1505, 465, 2339, 20747, 8269, 96875, 108985}},
-{20555, 18, 120101, {1, 3, 1, 7, 23, 7, 113, 181, 25, 989, 1649, 1, 823, 6793, 18729, 3599, 97951, 239609}},
-{20556, 18, 120105, {1, 3, 7, 7, 3, 63, 63, 207, 419, 355, 1133, 2979, 2071, 11699, 32565, 61347, 106475, 16893}},
-{20557, 18, 120155, {1, 1, 7, 5, 7, 3, 119, 133, 189, 341, 1571, 1559, 4309, 16203, 22459, 21019, 80375, 3453}},
-{20558, 18, 120188, {1, 1, 3, 11, 21, 21, 45, 69, 485, 21, 727, 703, 5209, 14745, 3437, 54603, 104357, 151207}},
-{20559, 18, 120195, {1, 3, 7, 5, 25, 17, 13, 147, 329, 93, 121, 315, 2779, 6921, 425, 50441, 1133, 252291}},
-{20560, 18, 120216, {1, 1, 3, 5, 5, 51, 15, 135, 323, 841, 409, 1067, 3243, 4207, 6833, 59329, 90545, 116661}},
-{20561, 18, 120228, {1, 1, 3, 15, 25, 7, 43, 147, 153, 947, 79, 1897, 4519, 14441, 27181, 38517, 71673, 158597}},
-{20562, 18, 120238, {1, 3, 3, 3, 3, 47, 109, 111, 273, 271, 741, 3999, 649, 7367, 14933, 11785, 92709, 133815}},
-{20563, 18, 120255, {1, 1, 3, 13, 5, 41, 55, 15, 409, 355, 1255, 3043, 7503, 3523, 4261, 48927, 119901, 149411}},
-{20564, 18, 120317, {1, 1, 5, 1, 11, 57, 3, 149, 409, 287, 909, 3541, 4243, 4485, 3611, 63213, 102575, 49863}},
-{20565, 18, 120327, {1, 1, 3, 7, 15, 55, 119, 185, 511, 301, 237, 3701, 3195, 1323, 27511, 44635, 45363, 117683}},
-{20566, 18, 120369, {1, 3, 3, 11, 3, 61, 125, 15, 235, 819, 467, 1097, 1055, 16343, 8329, 37807, 38663, 145625}},
-{20567, 18, 120382, {1, 1, 7, 1, 25, 49, 117, 163, 413, 509, 63, 1313, 5113, 6505, 25475, 12059, 88021, 168037}},
-{20568, 18, 120404, {1, 3, 3, 9, 9, 37, 15, 185, 359, 231, 1483, 2999, 773, 10375, 27103, 39899, 100187, 54485}},
-{20569, 18, 120414, {1, 3, 3, 1, 13, 63, 111, 79, 133, 425, 1491, 3735, 533, 13417, 5161, 11455, 16907, 132267}},
-{20570, 18, 120432, {1, 3, 1, 15, 15, 47, 57, 157, 453, 681, 1811, 1685, 4329, 131, 22763, 1017, 66637, 1673}},
-{20571, 18, 120435, {1, 3, 7, 3, 31, 5, 105, 101, 431, 983, 1333, 845, 7369, 15041, 6527, 8617, 61911, 137513}},
-{20572, 18, 120454, {1, 3, 7, 15, 3, 45, 57, 23, 393, 495, 769, 215, 3611, 12907, 20637, 52997, 88345, 37961}},
-{20573, 18, 120463, {1, 3, 5, 7, 31, 3, 85, 249, 353, 559, 1803, 959, 4625, 9413, 22339, 6071, 124765, 43973}},
-{20574, 18, 120471, {1, 3, 1, 9, 31, 15, 109, 197, 179, 293, 457, 709, 627, 7743, 1997, 59625, 36919, 252849}},
-{20575, 18, 120505, {1, 1, 7, 11, 17, 21, 89, 11, 431, 617, 1029, 2649, 1725, 2723, 18367, 46103, 108063, 221855}},
-{20576, 18, 120528, {1, 3, 7, 1, 29, 7, 81, 187, 353, 807, 965, 3655, 3255, 9139, 28619, 32127, 107901, 139099}},
-{20577, 18, 120588, {1, 1, 5, 3, 17, 9, 39, 59, 431, 829, 525, 1885, 2387, 13381, 5271, 29739, 80413, 240595}},
-{20578, 18, 120616, {1, 3, 1, 5, 1, 5, 25, 9, 193, 971, 681, 2921, 3271, 3891, 20123, 37477, 33141, 82481}},
-{20579, 18, 120630, {1, 1, 3, 5, 1, 63, 77, 93, 63, 399, 1945, 387, 5457, 7339, 13279, 34119, 129903, 12621}},
-{20580, 18, 120644, {1, 3, 3, 11, 17, 11, 117, 189, 473, 23, 13, 1261, 2153, 12181, 21075, 33179, 43355, 168293}},
-{20581, 18, 120672, {1, 3, 5, 11, 21, 13, 73, 227, 211, 939, 885, 2091, 1123, 14809, 15705, 56675, 58087, 1451}},
-{20582, 18, 120677, {1, 3, 7, 1, 15, 15, 101, 235, 287, 675, 1741, 3885, 6211, 14817, 10235, 29289, 60401, 27639}},
-{20583, 18, 120718, {1, 3, 5, 13, 13, 7, 117, 31, 143, 505, 1823, 2841, 2133, 7305, 14093, 14229, 85179, 136793}},
-{20584, 18, 120725, {1, 1, 3, 15, 27, 15, 67, 237, 315, 793, 207, 3781, 5201, 13191, 9601, 44041, 116097, 178543}},
-{20585, 18, 120730, {1, 3, 1, 9, 9, 47, 53, 225, 109, 831, 1757, 349, 6353, 15417, 16395, 36295, 10901, 122349}},
-{20586, 18, 120756, {1, 1, 1, 1, 1, 17, 109, 13, 123, 537, 1859, 3717, 4441, 4271, 29017, 13601, 18533, 216695}},
-{20587, 18, 120759, {1, 3, 3, 13, 31, 23, 45, 233, 29, 295, 761, 757, 777, 3499, 26715, 24153, 113777, 256337}},
-{20588, 18, 120765, {1, 3, 5, 7, 23, 57, 37, 179, 511, 897, 2031, 1285, 3957, 15085, 19993, 28819, 39959, 187445}},
-{20589, 18, 120795, {1, 3, 1, 15, 25, 41, 121, 227, 433, 859, 357, 3107, 3241, 879, 10763, 59473, 73145, 258493}},
-{20590, 18, 120821, {1, 3, 3, 5, 13, 9, 85, 117, 347, 161, 995, 549, 5443, 9057, 28931, 57549, 27523, 54717}},
-{20591, 18, 120850, {1, 1, 5, 13, 13, 33, 97, 37, 55, 367, 403, 2361, 5717, 4433, 26921, 14227, 69445, 100337}},
-{20592, 18, 120868, {1, 3, 5, 7, 1, 41, 89, 165, 163, 1, 685, 3577, 1079, 1057, 125, 35853, 8387, 113035}},
-{20593, 18, 120880, {1, 3, 3, 13, 3, 59, 119, 51, 325, 205, 821, 1417, 2097, 13725, 31785, 53803, 15737, 2013}},
-{20594, 18, 120885, {1, 3, 7, 7, 1, 45, 95, 221, 249, 65, 1479, 2163, 5761, 15321, 8013, 25771, 110897, 214127}},
-{20595, 18, 120892, {1, 3, 3, 5, 25, 11, 27, 29, 95, 955, 1989, 3775, 609, 7073, 4571, 38857, 92205, 156209}},
-{20596, 18, 120897, {1, 3, 1, 13, 29, 57, 97, 47, 499, 641, 587, 2125, 2257, 13911, 13993, 1715, 46233, 181279}},
-{20597, 18, 120912, {1, 1, 7, 13, 7, 55, 69, 235, 379, 269, 1969, 2733, 3677, 1707, 26999, 64041, 98111, 138691}},
-{20598, 18, 120934, {1, 1, 3, 5, 27, 63, 65, 251, 413, 903, 1307, 2941, 5649, 11271, 1935, 49389, 37995, 218197}},
-{20599, 18, 120991, {1, 3, 3, 13, 7, 1, 45, 225, 13, 169, 581, 1657, 117, 10251, 23435, 40379, 127085, 88185}},
-{20600, 18, 121004, {1, 1, 7, 5, 21, 63, 69, 37, 459, 115, 1403, 1939, 6437, 13149, 3597, 50115, 129075, 260613}},
-{20601, 18, 121021, {1, 1, 3, 5, 29, 57, 15, 223, 131, 907, 1561, 1103, 4355, 2763, 6359, 55401, 1751, 53143}},
-{20602, 18, 121022, {1, 1, 7, 11, 15, 5, 17, 159, 505, 407, 1873, 2501, 2203, 12559, 5123, 53281, 29307, 16215}},
-{20603, 18, 121036, {1, 1, 1, 15, 9, 41, 77, 145, 325, 529, 1939, 3835, 3109, 12215, 18323, 2551, 89793, 94745}},
-{20604, 18, 121041, {1, 3, 1, 9, 21, 5, 7, 57, 99, 1005, 1211, 4063, 6851, 7653, 29283, 15463, 121289, 187055}},
-{20605, 18, 121069, {1, 1, 3, 3, 13, 11, 17, 125, 173, 283, 1419, 2533, 6875, 16031, 26633, 51027, 27343, 74257}},
-{20606, 18, 121078, {1, 1, 3, 11, 29, 49, 87, 19, 367, 941, 983, 1041, 8099, 8735, 30123, 62665, 87051, 98745}},
-{20607, 18, 121126, {1, 1, 1, 15, 25, 57, 97, 177, 467, 181, 923, 3833, 5405, 14335, 23495, 48323, 70331, 136825}},
-{20608, 18, 121135, {1, 1, 1, 13, 21, 17, 29, 237, 305, 117, 1077, 2999, 1879, 6875, 19321, 10999, 130513, 160883}},
-{20609, 18, 121138, {1, 3, 7, 15, 19, 47, 89, 153, 287, 7, 1429, 1507, 2853, 4197, 11195, 33891, 59063, 189601}},
-{20610, 18, 121162, {1, 1, 3, 15, 31, 5, 113, 71, 13, 925, 147, 451, 5701, 13671, 13943, 13799, 59627, 115715}},
-{20611, 18, 121176, {1, 1, 1, 5, 13, 25, 51, 11, 409, 393, 1479, 2583, 3101, 303, 17609, 10653, 69107, 150459}},
-{20612, 18, 121186, {1, 1, 5, 7, 21, 27, 107, 77, 61, 467, 1723, 1247, 287, 1039, 25347, 18111, 24837, 42903}},
-{20613, 18, 121209, {1, 3, 5, 5, 1, 29, 57, 177, 311, 9, 819, 3235, 3887, 9679, 11849, 31755, 68467, 135587}},
-{20614, 18, 121212, {1, 1, 5, 5, 29, 15, 13, 69, 163, 709, 1405, 3835, 777, 7567, 10153, 5043, 129465, 59113}},
-{20615, 18, 121221, {1, 1, 1, 13, 3, 47, 97, 101, 179, 53, 1919, 17, 3597, 11769, 17971, 39257, 76167, 255653}},
-{20616, 18, 121225, {1, 1, 7, 5, 1, 45, 121, 223, 299, 271, 1857, 1955, 5509, 1245, 9519, 60547, 78497, 191251}},
-{20617, 18, 121228, {1, 1, 1, 11, 5, 57, 87, 113, 59, 547, 1591, 1905, 475, 4687, 27591, 43807, 9617, 70769}},
-{20618, 18, 121239, {1, 1, 7, 1, 1, 35, 35, 11, 107, 401, 827, 2271, 2131, 12751, 25771, 51311, 46897, 198655}},
-{20619, 18, 121245, {1, 3, 3, 3, 15, 29, 91, 147, 9, 611, 1739, 3211, 3883, 14205, 24073, 37445, 54451, 208123}},
-{20620, 18, 121264, {1, 3, 7, 1, 25, 53, 33, 161, 365, 651, 1263, 1623, 1767, 3789, 18013, 52133, 60119, 100859}},
-{20621, 18, 121270, {1, 3, 5, 9, 15, 9, 97, 67, 379, 981, 1323, 1095, 3701, 3257, 13647, 12511, 53375, 156689}},
-{20622, 18, 121299, {1, 1, 3, 5, 9, 23, 97, 239, 171, 501, 1549, 1029, 8019, 5023, 9439, 14223, 54433, 152855}},
-{20623, 18, 121306, {1, 1, 7, 13, 17, 35, 111, 169, 81, 599, 1673, 3461, 7905, 7925, 16311, 20327, 57109, 158719}},
-{20624, 18, 121315, {1, 1, 3, 15, 7, 33, 23, 33, 273, 987, 1489, 363, 4017, 8919, 28839, 10143, 114179, 218155}},
-{20625, 18, 121317, {1, 3, 5, 13, 29, 5, 61, 133, 65, 933, 509, 551, 7365, 3703, 15003, 27849, 64211, 140383}},
-{20626, 18, 121321, {1, 1, 1, 13, 7, 25, 49, 1, 269, 601, 251, 33, 2443, 13725, 5805, 63347, 109489, 111491}},
-{20627, 18, 121324, {1, 1, 7, 9, 31, 23, 117, 71, 371, 733, 605, 4019, 4577, 3887, 31061, 24939, 57905, 148331}},
-{20628, 18, 121330, {1, 3, 5, 1, 3, 35, 35, 227, 355, 27, 1673, 2173, 5001, 14613, 6343, 40775, 72349, 101287}},
-{20629, 18, 121339, {1, 1, 7, 15, 29, 3, 43, 77, 43, 51, 1495, 2577, 2093, 7515, 20151, 44533, 32223, 6355}},
-{20630, 18, 121346, {1, 1, 5, 5, 11, 47, 91, 221, 35, 969, 343, 3287, 857, 4851, 12599, 939, 53615, 262125}},
-{20631, 18, 121370, {1, 1, 5, 7, 29, 11, 67, 155, 317, 629, 211, 583, 1061, 13243, 13999, 45405, 18187, 99021}},
-{20632, 18, 121372, {1, 3, 7, 13, 3, 39, 5, 207, 175, 515, 1181, 739, 379, 9919, 12079, 18903, 62475, 239383}},
-{20633, 18, 121393, {1, 1, 1, 15, 25, 15, 113, 215, 281, 861, 1055, 2577, 5545, 12365, 16097, 35775, 8331, 119353}},
-{20634, 18, 121396, {1, 1, 1, 1, 25, 55, 111, 185, 485, 361, 155, 4077, 5517, 16057, 19069, 40129, 38959, 211233}},
-{20635, 18, 121414, {1, 1, 3, 3, 13, 1, 93, 129, 243, 813, 115, 177, 53, 8251, 32351, 63847, 54537, 25527}},
-{20636, 18, 121442, {1, 3, 5, 11, 25, 47, 113, 69, 285, 451, 2011, 81, 6535, 3409, 8647, 56575, 975, 149571}},
-{20637, 18, 121475, {1, 1, 7, 7, 19, 1, 75, 123, 413, 697, 41, 3179, 4075, 15967, 2477, 17549, 54193, 258657}},
-{20638, 18, 121499, {1, 1, 5, 5, 11, 23, 19, 253, 303, 255, 901, 875, 1517, 6953, 25189, 26763, 28843, 167705}},
-{20639, 18, 121512, {1, 3, 7, 7, 17, 45, 31, 79, 279, 965, 1869, 1201, 1627, 14035, 11651, 45021, 76171, 49137}},
-{20640, 18, 121518, {1, 3, 1, 15, 9, 55, 83, 59, 437, 915, 1667, 89, 2797, 1841, 29261, 23497, 55785, 102265}},
-{20641, 18, 121588, {1, 1, 5, 5, 3, 59, 17, 131, 199, 541, 1647, 2175, 4449, 6081, 10609, 39467, 72945, 32423}},
-{20642, 18, 121597, {1, 3, 1, 7, 5, 7, 85, 11, 255, 397, 87, 1661, 6523, 5699, 29407, 28015, 50783, 246625}},
-{20643, 18, 121612, {1, 3, 3, 13, 5, 61, 123, 147, 295, 37, 301, 2549, 7615, 5725, 32477, 18121, 69353, 242579}},
-{20644, 18, 121629, {1, 3, 5, 7, 9, 45, 83, 211, 475, 281, 743, 3955, 7811, 6043, 30547, 5315, 53345, 25775}},
-{20645, 18, 121630, {1, 3, 3, 5, 7, 63, 125, 43, 131, 353, 345, 1689, 5483, 5467, 13445, 13041, 68381, 134567}},
-{20646, 18, 121634, {1, 3, 5, 11, 31, 9, 123, 53, 237, 911, 349, 3737, 1867, 7375, 3031, 4191, 8697, 182255}},
-{20647, 18, 121680, {1, 1, 3, 3, 11, 11, 89, 251, 69, 93, 1241, 1719, 2227, 1793, 21683, 58099, 110831, 24835}},
-{20648, 18, 121725, {1, 1, 5, 9, 3, 57, 3, 17, 11, 217, 923, 3623, 727, 1837, 21203, 63007, 33691, 216259}},
-{20649, 18, 121798, {1, 3, 3, 9, 21, 25, 83, 115, 325, 921, 811, 303, 3555, 10669, 5837, 45585, 61923, 159061}},
-{20650, 18, 121815, {1, 3, 3, 15, 17, 29, 77, 75, 509, 363, 199, 317, 7375, 11971, 15679, 17135, 101925, 103375}},
-{20651, 18, 121822, {1, 3, 5, 5, 29, 45, 85, 151, 73, 329, 911, 3055, 2381, 4717, 5133, 58987, 59885, 226689}},
-{20652, 18, 121837, {1, 3, 5, 1, 11, 59, 17, 83, 385, 867, 215, 2275, 7247, 10613, 6493, 63843, 74483, 134271}},
-{20653, 18, 121840, {1, 1, 7, 13, 29, 25, 77, 61, 281, 439, 353, 2213, 697, 14741, 1597, 7515, 7703, 149123}},
-{20654, 18, 121869, {1, 3, 7, 7, 7, 53, 77, 21, 483, 793, 969, 123, 3581, 12489, 22943, 54573, 25785, 178419}},
-{20655, 18, 121878, {1, 3, 5, 3, 17, 59, 75, 55, 125, 569, 1625, 77, 4593, 8493, 5259, 54537, 100479, 107509}},
-{20656, 18, 121897, {1, 1, 1, 15, 5, 7, 11, 169, 349, 133, 1113, 2877, 6109, 16275, 9755, 1385, 55005, 36095}},
-{20657, 18, 121920, {1, 1, 7, 7, 21, 25, 41, 161, 11, 321, 343, 705, 4601, 12867, 21997, 25283, 78467, 159089}},
-{20658, 18, 121929, {1, 3, 7, 1, 15, 3, 71, 227, 427, 883, 1021, 1405, 7791, 12669, 9159, 30931, 105993, 40917}},
-{20659, 18, 121944, {1, 1, 5, 5, 25, 41, 93, 57, 125, 915, 701, 2589, 7147, 15369, 28307, 54635, 13253, 97177}},
-{20660, 18, 121999, {1, 3, 1, 13, 11, 63, 103, 241, 317, 927, 965, 3179, 5213, 13849, 11509, 52665, 1637, 235647}},
-{20661, 18, 122008, {1, 3, 5, 3, 31, 31, 111, 9, 339, 1017, 1715, 101, 6849, 14329, 31607, 40741, 73067, 119001}},
-{20662, 18, 122056, {1, 3, 1, 13, 3, 55, 53, 15, 185, 717, 1447, 3029, 4899, 14217, 19949, 32817, 24829, 206829}},
-{20663, 18, 122062, {1, 3, 7, 9, 21, 11, 33, 213, 5, 769, 1807, 2179, 63, 5167, 23235, 25495, 113299, 129419}},
-{20664, 18, 122067, {1, 3, 7, 11, 11, 33, 23, 125, 21, 609, 595, 1329, 6175, 15837, 3889, 57797, 81453, 211413}},
-{20665, 18, 122083, {1, 1, 5, 11, 31, 7, 13, 73, 143, 559, 1541, 275, 3349, 2987, 21797, 32921, 125395, 247667}},
-{20666, 18, 122095, {1, 1, 3, 11, 19, 1, 23, 167, 337, 75, 1597, 3591, 2705, 7323, 5957, 7317, 58945, 44625}},
-{20667, 18, 122110, {1, 1, 5, 11, 27, 19, 63, 231, 353, 645, 531, 3861, 1681, 6901, 16217, 20639, 70077, 220233}},
-{20668, 18, 122118, {1, 1, 5, 15, 31, 41, 19, 253, 147, 365, 509, 1199, 6699, 14633, 1339, 48203, 58707, 83315}},
-{20669, 18, 122127, {1, 1, 5, 7, 19, 47, 47, 17, 267, 139, 549, 803, 4625, 6851, 32141, 12891, 43785, 211361}},
-{20670, 18, 122189, {1, 3, 1, 13, 19, 35, 13, 45, 167, 627, 1449, 3041, 5043, 9279, 15889, 41675, 25769, 13835}},
-{20671, 18, 122207, {1, 3, 7, 7, 19, 47, 13, 117, 403, 79, 1623, 3741, 3255, 2301, 25, 2311, 5237, 150879}},
-{20672, 18, 122226, {1, 1, 1, 15, 29, 43, 75, 21, 237, 809, 129, 2637, 181, 15921, 30709, 61281, 82405, 232885}},
-{20673, 18, 122253, {1, 1, 3, 15, 15, 15, 55, 217, 243, 579, 945, 3993, 1875, 2425, 25045, 36729, 42935, 213703}},
-{20674, 18, 122301, {1, 3, 3, 1, 5, 59, 115, 71, 483, 327, 701, 2893, 1815, 4611, 3843, 5893, 126479, 167807}},
-{20675, 18, 122324, {1, 3, 1, 7, 17, 59, 115, 191, 3, 615, 215, 2121, 5085, 15233, 16661, 6215, 31061, 192847}},
-{20676, 18, 122337, {1, 3, 1, 1, 21, 25, 41, 195, 151, 905, 1587, 439, 3317, 2275, 4743, 33505, 1185, 254873}},
-{20677, 18, 122362, {1, 1, 3, 9, 11, 49, 37, 117, 419, 1007, 789, 1323, 345, 2047, 20697, 57063, 69167, 219393}},
-{20678, 18, 122368, {1, 3, 1, 1, 25, 49, 81, 79, 117, 1015, 1777, 2427, 527, 10139, 16261, 42587, 33933, 19749}},
-{20679, 18, 122371, {1, 1, 5, 15, 31, 43, 19, 17, 97, 591, 891, 177, 7835, 3979, 15473, 2173, 65555, 182773}},
-{20680, 18, 122378, {1, 1, 3, 15, 13, 53, 31, 179, 247, 635, 683, 423, 2981, 14401, 26385, 10935, 68497, 181703}},
-{20681, 18, 122404, {1, 3, 3, 9, 25, 55, 43, 29, 487, 969, 989, 3561, 6425, 11619, 5773, 56515, 17461, 151239}},
-{20682, 18, 122443, {1, 1, 5, 13, 3, 31, 73, 51, 213, 215, 297, 783, 697, 14197, 7277, 60697, 985, 189995}},
-{20683, 18, 122451, {1, 3, 3, 5, 9, 47, 69, 27, 15, 407, 1029, 2541, 183, 4413, 5143, 33903, 49509, 49007}},
-{20684, 18, 122457, {1, 1, 1, 3, 5, 3, 9, 165, 215, 577, 1657, 363, 737, 5483, 5955, 34533, 45861, 104645}},
-{20685, 18, 122458, {1, 1, 5, 7, 31, 27, 37, 215, 125, 915, 1297, 3095, 1529, 12737, 25675, 29355, 83939, 106765}},
-{20686, 18, 122479, {1, 1, 3, 3, 1, 49, 29, 115, 395, 647, 147, 3905, 1025, 8873, 10587, 25471, 72089, 171467}},
-{20687, 18, 122484, {1, 3, 7, 1, 21, 55, 57, 233, 487, 883, 439, 929, 1405, 13709, 2389, 20205, 17579, 9129}},
-{20688, 18, 122521, {1, 3, 5, 5, 23, 51, 55, 45, 307, 855, 933, 1443, 4757, 8719, 28401, 35189, 105329, 9211}},
-{20689, 18, 122540, {1, 3, 7, 11, 29, 17, 17, 147, 221, 997, 1433, 59, 8027, 231, 30335, 2153, 21393, 116661}},
-{20690, 18, 122545, {1, 1, 7, 3, 5, 43, 47, 155, 357, 915, 1923, 3315, 4107, 9785, 4847, 57683, 87569, 179583}},
-{20691, 18, 122552, {1, 1, 7, 7, 27, 5, 37, 95, 265, 113, 143, 3755, 5793, 5601, 16621, 54777, 15989, 158933}},
-{20692, 18, 122560, {1, 3, 1, 1, 13, 31, 113, 255, 367, 559, 1777, 4065, 8061, 15785, 10345, 54833, 95277, 159347}},
-{20693, 18, 122575, {1, 1, 1, 15, 3, 43, 85, 251, 193, 19, 1685, 271, 1779, 11901, 18983, 65361, 128217, 248051}},
-{20694, 18, 122578, {1, 3, 5, 7, 29, 21, 5, 47, 263, 913, 83, 3233, 113, 8341, 14473, 37405, 2363, 155931}},
-{20695, 18, 122605, {1, 1, 7, 15, 7, 25, 41, 39, 315, 323, 827, 1277, 1211, 4465, 21161, 36865, 6689, 139147}},
-{20696, 18, 122661, {1, 1, 1, 9, 11, 45, 81, 235, 31, 247, 77, 1877, 7119, 16007, 2225, 65, 85537, 99251}},
-{20697, 18, 122673, {1, 1, 3, 11, 19, 5, 49, 179, 345, 961, 349, 2099, 2317, 12771, 27169, 59389, 116071, 68333}},
-{20698, 18, 122722, {1, 3, 3, 5, 15, 53, 47, 177, 103, 941, 87, 2813, 7729, 8003, 7717, 40095, 74569, 106617}},
-{20699, 18, 122728, {1, 1, 7, 7, 31, 23, 105, 205, 325, 855, 1529, 3601, 7151, 15827, 16241, 18221, 55771, 139225}},
-{20700, 18, 122739, {1, 3, 5, 13, 13, 5, 95, 167, 25, 779, 1147, 221, 5055, 10943, 28077, 15131, 89501, 137407}},
-{20701, 18, 122751, {1, 3, 7, 13, 31, 3, 105, 163, 41, 823, 1493, 2985, 5589, 3543, 24683, 34469, 40595, 200875}},
-{20702, 18, 122762, {1, 3, 5, 3, 27, 35, 105, 163, 477, 667, 45, 319, 3201, 11535, 19349, 55253, 60275, 209597}},
-{20703, 18, 122769, {1, 3, 1, 11, 5, 13, 25, 225, 169, 925, 1617, 537, 891, 5583, 7181, 39953, 97537, 104019}},
-{20704, 18, 122772, {1, 3, 5, 9, 13, 1, 69, 147, 465, 259, 1219, 2407, 4015, 4883, 4333, 40441, 31289, 52989}},
-{20705, 18, 122782, {1, 3, 5, 5, 17, 29, 105, 233, 307, 807, 1535, 251, 135, 925, 6865, 59739, 112757, 208275}},
-{20706, 18, 122798, {1, 1, 1, 7, 9, 21, 49, 247, 33, 127, 1277, 1745, 139, 12165, 23517, 50235, 101003, 109031}},
-{20707, 18, 122810, {1, 3, 5, 9, 19, 7, 9, 139, 511, 901, 551, 2717, 6091, 3213, 819, 51381, 108333, 119681}},
-{20708, 18, 122812, {1, 1, 1, 3, 19, 17, 73, 19, 313, 589, 1965, 1745, 921, 4237, 12527, 10735, 110139, 171513}},
-{20709, 18, 122818, {1, 1, 5, 15, 25, 29, 15, 217, 87, 793, 419, 915, 1359, 10507, 25343, 62977, 100913, 110041}},
-{20710, 18, 122829, {1, 3, 7, 15, 15, 15, 91, 243, 441, 437, 1759, 2659, 2319, 7783, 16857, 19051, 15463, 253115}},
-{20711, 18, 122851, {1, 1, 5, 13, 15, 5, 7, 165, 355, 559, 217, 235, 3565, 12047, 2387, 62285, 73363, 238551}},
-{20712, 18, 122857, {1, 3, 7, 11, 5, 5, 69, 205, 179, 815, 335, 979, 2129, 6221, 31987, 13623, 23103, 24373}},
-{20713, 18, 122868, {1, 1, 7, 11, 31, 51, 55, 93, 195, 219, 825, 2919, 4495, 5927, 11813, 16415, 121595, 188613}},
-{20714, 18, 122893, {1, 1, 3, 1, 3, 11, 73, 45, 141, 219, 337, 2569, 6549, 3699, 2417, 2945, 19389, 82561}},
-{20715, 18, 122894, {1, 3, 1, 13, 5, 47, 47, 81, 11, 57, 1965, 2173, 3209, 10617, 19887, 5571, 61403, 37401}},
-{20716, 18, 122902, {1, 3, 3, 7, 3, 5, 99, 253, 287, 655, 813, 3365, 2387, 8951, 1561, 37637, 97625, 148699}},
-{20717, 18, 122921, {1, 1, 3, 5, 9, 31, 49, 7, 55, 607, 1489, 3229, 5871, 1271, 22751, 32309, 16125, 93409}},
-{20718, 18, 122959, {1, 3, 1, 5, 19, 35, 29, 233, 407, 297, 1465, 3089, 7535, 7221, 24469, 42653, 65719, 196771}},
-{20719, 18, 122984, {1, 1, 7, 13, 17, 19, 37, 45, 211, 545, 963, 79, 13, 8319, 8045, 24975, 122749, 25845}},
-{20720, 18, 123001, {1, 3, 5, 3, 23, 23, 53, 101, 363, 49, 1351, 3419, 1603, 10795, 5289, 63695, 113911, 228301}},
-{20721, 18, 123038, {1, 3, 7, 9, 15, 59, 125, 59, 11, 397, 693, 397, 3829, 14349, 13973, 54739, 22093, 216009}},
-{20722, 18, 123076, {1, 1, 1, 13, 5, 63, 21, 23, 421, 35, 589, 803, 6193, 11375, 9501, 34441, 68421, 120109}},
-{20723, 18, 123100, {1, 3, 3, 7, 23, 25, 79, 203, 177, 173, 175, 809, 4331, 6953, 4999, 34345, 94481, 88683}},
-{20724, 18, 123107, {1, 3, 3, 3, 1, 51, 109, 195, 83, 747, 63, 325, 927, 1757, 32055, 37185, 22697, 41509}},
-{20725, 18, 123122, {1, 3, 5, 13, 1, 63, 45, 73, 121, 445, 1935, 3373, 563, 7503, 17941, 60313, 42219, 220917}},
-{20726, 18, 123139, {1, 3, 5, 13, 27, 31, 7, 83, 109, 387, 447, 1691, 1301, 7449, 8075, 30713, 87207, 84855}},
-{20727, 18, 123175, {1, 3, 1, 5, 25, 51, 83, 11, 261, 977, 1415, 2973, 1789, 12641, 16279, 4225, 44237, 173561}},
-{20728, 18, 123190, {1, 1, 5, 15, 17, 47, 105, 199, 83, 705, 1215, 2759, 7509, 10407, 4005, 4575, 65961, 209933}},
-{20729, 18, 123201, {1, 3, 1, 13, 27, 3, 5, 199, 405, 515, 291, 3399, 1497, 14755, 30229, 35075, 111585, 16633}},
-{20730, 18, 123219, {1, 1, 1, 13, 17, 53, 93, 161, 447, 903, 947, 1871, 3597, 10575, 18389, 48551, 65229, 32591}},
-{20731, 18, 123232, {1, 3, 5, 11, 9, 7, 53, 155, 299, 523, 1653, 3517, 2725, 9485, 27099, 47895, 30169, 260463}},
-{20732, 18, 123255, {1, 1, 3, 13, 11, 45, 31, 183, 445, 21, 313, 2597, 195, 16053, 7323, 52951, 25919, 9323}},
-{20733, 18, 123285, {1, 1, 1, 15, 1, 35, 15, 115, 53, 561, 1141, 3261, 83, 2547, 8925, 43455, 112755, 94157}},
-{20734, 18, 123328, {1, 1, 3, 5, 27, 25, 81, 51, 209, 87, 379, 3167, 4953, 13885, 20159, 103, 115363, 123585}},
-{20735, 18, 123385, {1, 3, 5, 1, 25, 29, 107, 225, 77, 435, 2009, 4069, 3703, 8855, 14101, 61683, 16993, 110823}},
-{20736, 18, 123397, {1, 3, 7, 3, 31, 25, 51, 117, 397, 271, 89, 3571, 2357, 4923, 16303, 2357, 107775, 73809}},
-{20737, 18, 123404, {1, 1, 3, 1, 29, 21, 33, 67, 363, 753, 915, 3715, 2013, 8439, 5779, 267, 32687, 104283}},
-{20738, 18, 123419, {1, 3, 1, 11, 11, 7, 31, 43, 339, 917, 2005, 759, 4285, 1933, 4341, 19111, 130651, 122853}},
-{20739, 18, 123435, {1, 1, 5, 1, 17, 63, 85, 63, 387, 127, 1313, 619, 6525, 9003, 10915, 64507, 13175, 45219}},
-{20740, 18, 123437, {1, 3, 7, 9, 25, 15, 43, 13, 411, 391, 571, 527, 8175, 10849, 20093, 2987, 29869, 77207}},
-{20741, 18, 123443, {1, 1, 5, 3, 29, 53, 105, 57, 91, 977, 1103, 2977, 5617, 7203, 26717, 28463, 55909, 59943}},
-{20742, 18, 123500, {1, 3, 1, 7, 1, 47, 111, 215, 189, 377, 11, 871, 2267, 5705, 8165, 38895, 71025, 10921}},
-{20743, 18, 123506, {1, 1, 7, 9, 29, 55, 1, 103, 505, 697, 317, 3209, 3643, 13689, 8499, 14671, 67937, 100467}},
-{20744, 18, 123511, {1, 3, 1, 5, 25, 15, 99, 199, 117, 957, 1421, 1719, 5185, 15247, 28615, 2657, 46867, 190135}},
-{20745, 18, 123512, {1, 1, 7, 9, 27, 55, 81, 47, 15, 497, 537, 857, 2905, 1909, 3341, 32625, 123189, 21875}},
-{20746, 18, 123518, {1, 3, 1, 3, 19, 51, 97, 143, 305, 1021, 543, 829, 7593, 8101, 6337, 4869, 19177, 38981}},
-{20747, 18, 123522, {1, 3, 3, 15, 9, 37, 51, 193, 295, 731, 809, 4065, 3377, 15303, 12505, 11327, 76191, 139899}},
-{20748, 18, 123545, {1, 1, 5, 1, 3, 19, 5, 223, 379, 7, 755, 1127, 505, 9429, 27409, 50817, 97599, 179019}},
-{20749, 18, 123572, {1, 3, 5, 3, 5, 11, 83, 119, 3, 311, 405, 2401, 1821, 1381, 4567, 44079, 61903, 183583}},
-{20750, 18, 123587, {1, 3, 7, 9, 7, 11, 107, 95, 271, 537, 335, 3079, 6695, 1163, 32055, 44985, 29075, 94235}},
-{20751, 18, 123594, {1, 3, 7, 7, 7, 57, 59, 85, 199, 563, 1835, 351, 7675, 2601, 3717, 57975, 92529, 101511}},
-{20752, 18, 123607, {1, 1, 1, 5, 17, 5, 97, 43, 101, 141, 1511, 199, 7157, 3169, 24815, 55653, 104195, 37951}},
-{20753, 18, 123608, {1, 1, 1, 11, 23, 29, 41, 47, 447, 583, 773, 859, 1657, 8707, 16709, 53477, 42037, 186809}},
-{20754, 18, 123630, {1, 1, 1, 13, 13, 5, 85, 9, 213, 511, 1003, 811, 2271, 14715, 21423, 48127, 50613, 214031}},
-{20755, 18, 123635, {1, 1, 3, 5, 7, 31, 87, 101, 297, 853, 1599, 1521, 4965, 9655, 23543, 62277, 11231, 49931}},
-{20756, 18, 123659, {1, 1, 7, 7, 19, 31, 9, 165, 207, 919, 739, 3849, 2121, 867, 3233, 40867, 75721, 5327}},
-{20757, 18, 123692, {1, 3, 7, 1, 17, 3, 27, 13, 431, 283, 465, 1427, 1937, 15601, 21793, 9315, 54285, 196453}},
-{20758, 18, 123695, {1, 1, 7, 3, 17, 39, 65, 137, 511, 19, 1357, 3373, 5227, 2485, 1151, 25061, 117507, 119219}},
-{20759, 18, 123700, {1, 3, 3, 9, 9, 23, 13, 235, 505, 625, 115, 3859, 6943, 14719, 6363, 14957, 28241, 187989}},
-{20760, 18, 123730, {1, 3, 7, 13, 11, 31, 23, 39, 463, 441, 1145, 417, 4177, 1655, 26491, 16895, 26263, 198157}},
-{20761, 18, 123748, {1, 3, 3, 7, 25, 55, 121, 157, 131, 537, 1891, 2367, 1717, 2331, 20251, 8679, 62657, 121957}},
-{20762, 18, 123751, {1, 1, 1, 11, 7, 43, 59, 101, 333, 961, 569, 1603, 3009, 6539, 9627, 5759, 44401, 127613}},
-{20763, 18, 123770, {1, 3, 3, 3, 1, 27, 15, 135, 235, 215, 627, 2427, 2647, 3201, 22873, 64445, 32635, 16587}},
-{20764, 18, 123793, {1, 3, 7, 7, 5, 49, 63, 103, 467, 897, 117, 1149, 6045, 5003, 5005, 6183, 90815, 190909}},
-{20765, 18, 123800, {1, 1, 3, 3, 31, 43, 45, 227, 363, 409, 1097, 3155, 1519, 14461, 29377, 19577, 52595, 94041}},
-{20766, 18, 123803, {1, 3, 1, 1, 3, 25, 83, 243, 57, 243, 389, 1427, 5197, 13125, 18571, 17845, 74961, 125569}},
-{20767, 18, 123851, {1, 3, 5, 5, 1, 39, 11, 175, 97, 1001, 143, 3653, 5887, 5845, 5691, 5433, 62629, 176261}},
-{20768, 18, 123859, {1, 1, 1, 13, 11, 41, 41, 155, 17, 823, 1507, 733, 5663, 13657, 24133, 9971, 27179, 108075}},
-{20769, 18, 123866, {1, 1, 7, 9, 19, 9, 103, 29, 427, 363, 931, 3959, 1629, 5127, 14807, 61937, 127175, 237233}},
-{20770, 18, 123868, {1, 1, 1, 5, 29, 53, 51, 229, 123, 1001, 697, 411, 4669, 5051, 18447, 55437, 129269, 72613}},
-{20771, 18, 123877, {1, 3, 7, 3, 19, 53, 111, 131, 255, 547, 653, 2839, 1447, 14397, 5707, 23773, 127897, 135177}},
-{20772, 18, 123884, {1, 3, 3, 5, 21, 37, 53, 219, 359, 341, 489, 2477, 3383, 6931, 7753, 2619, 114267, 63271}},
-{20773, 18, 123909, {1, 1, 3, 15, 15, 15, 95, 171, 301, 563, 603, 593, 4037, 7305, 10849, 11753, 103087, 74887}},
-{20774, 18, 123910, {1, 1, 5, 3, 11, 51, 105, 35, 155, 643, 569, 1697, 1679, 7547, 19289, 7065, 57359, 142855}},
-{20775, 18, 123919, {1, 1, 7, 15, 23, 55, 17, 67, 375, 559, 355, 165, 93, 973, 22831, 48027, 98435, 59945}},
-{20776, 18, 123927, {1, 3, 7, 3, 5, 43, 9, 253, 111, 819, 45, 3461, 4821, 14735, 14469, 29793, 30681, 26359}},
-{20777, 18, 123937, {1, 3, 3, 5, 15, 1, 39, 233, 63, 287, 131, 3453, 427, 4929, 30085, 18583, 50119, 262101}},
-{20778, 18, 123950, {1, 3, 7, 9, 31, 7, 127, 157, 287, 57, 1091, 1989, 5045, 13071, 27705, 58125, 85317, 66649}},
-{20779, 18, 123957, {1, 1, 1, 15, 17, 29, 25, 223, 311, 489, 1901, 3197, 1813, 10097, 31915, 54871, 32289, 227001}},
-{20780, 18, 123979, {1, 3, 7, 5, 31, 35, 69, 87, 131, 963, 1125, 1109, 8037, 3257, 27655, 50999, 3715, 57851}},
-{20781, 18, 123996, {1, 1, 5, 5, 27, 7, 119, 29, 425, 721, 541, 3069, 3349, 13623, 12293, 51395, 14033, 61545}},
-{20782, 18, 124040, {1, 3, 7, 3, 17, 49, 103, 115, 387, 729, 1389, 2257, 3273, 3375, 23143, 2835, 28071, 79533}},
-{20783, 18, 124054, {1, 1, 3, 7, 9, 19, 55, 159, 261, 467, 17, 2595, 3947, 7045, 193, 23629, 89067, 81197}},
-{20784, 18, 124063, {1, 1, 1, 15, 13, 39, 103, 195, 251, 769, 1003, 2707, 3263, 8451, 8007, 53789, 112653, 258717}},
-{20785, 18, 124067, {1, 3, 5, 1, 3, 21, 29, 217, 125, 779, 1597, 513, 2677, 3979, 31903, 64813, 69963, 92887}},
-{20786, 18, 124088, {1, 1, 3, 11, 11, 59, 81, 237, 447, 703, 41, 3369, 3547, 14935, 31693, 52005, 74149, 131039}},
-{20787, 18, 124101, {1, 1, 3, 1, 23, 1, 33, 93, 275, 847, 921, 2745, 533, 8975, 30529, 46809, 98975, 75541}},
-{20788, 18, 124154, {1, 1, 7, 7, 15, 1, 3, 213, 71, 1009, 1951, 3015, 713, 9365, 21949, 60983, 117633, 225387}},
-{20789, 18, 124162, {1, 1, 1, 11, 31, 27, 59, 179, 231, 635, 1555, 2765, 31, 15065, 22719, 59251, 84733, 96769}},
-{20790, 18, 124167, {1, 3, 7, 3, 19, 5, 35, 207, 317, 735, 943, 3987, 4021, 11229, 13015, 713, 125167, 55887}},
-{20791, 18, 124176, {1, 1, 3, 1, 27, 49, 81, 17, 253, 633, 43, 2953, 3151, 8429, 30625, 28551, 126683, 175087}},
-{20792, 18, 124195, {1, 3, 3, 3, 9, 53, 111, 245, 57, 557, 945, 2957, 7669, 12537, 17291, 9713, 87727, 44739}},
-{20793, 18, 124230, {1, 3, 1, 1, 5, 39, 77, 127, 87, 687, 1485, 1555, 2567, 13551, 17075, 24003, 47627, 129813}},
-{20794, 18, 124267, {1, 3, 5, 9, 25, 35, 87, 233, 439, 563, 1719, 419, 4459, 4285, 25157, 943, 111543, 232107}},
-{20795, 18, 124346, {1, 3, 5, 11, 1, 13, 97, 153, 459, 551, 73, 2087, 3985, 4661, 15603, 22211, 123163, 187233}},
-{20796, 18, 124389, {1, 1, 7, 13, 17, 59, 5, 219, 353, 441, 387, 441, 3009, 485, 20081, 38023, 50659, 159243}},
-{20797, 18, 124418, {1, 3, 1, 7, 21, 31, 117, 49, 227, 677, 417, 1153, 1611, 1669, 25161, 52223, 15109, 114759}},
-{20798, 18, 124420, {1, 1, 7, 9, 19, 13, 111, 7, 1, 701, 731, 2075, 685, 15679, 19149, 44315, 41719, 243975}},
-{20799, 18, 124454, {1, 3, 3, 7, 15, 63, 59, 105, 327, 39, 1497, 2407, 2865, 7065, 9957, 20031, 45359, 73657}},
-{20800, 18, 124490, {1, 3, 1, 13, 7, 3, 55, 221, 443, 953, 15, 2455, 4681, 16247, 18179, 44731, 41323, 172621}},
-{20801, 18, 124503, {1, 1, 3, 9, 1, 27, 65, 167, 115, 137, 819, 2129, 3393, 5901, 11735, 62753, 14941, 21425}},
-{20802, 18, 124519, {1, 3, 7, 11, 7, 9, 41, 175, 237, 481, 59, 265, 2135, 9419, 3937, 55959, 48343, 172549}},
-{20803, 18, 124533, {1, 1, 1, 13, 23, 33, 105, 87, 461, 297, 1345, 3715, 7715, 16369, 19017, 15141, 10873, 109641}},
-{20804, 18, 124544, {1, 3, 5, 1, 11, 1, 13, 41, 447, 511, 447, 2295, 2401, 14171, 16269, 50453, 40361, 205857}},
-{20805, 18, 124589, {1, 1, 3, 3, 27, 7, 35, 193, 113, 341, 335, 2113, 343, 4575, 20863, 40383, 86787, 142603}},
-{20806, 18, 124616, {1, 1, 7, 11, 17, 25, 51, 89, 341, 237, 1233, 1505, 7401, 6887, 26897, 20127, 51077, 107559}},
-{20807, 18, 124630, {1, 1, 1, 15, 9, 59, 29, 115, 339, 785, 201, 947, 1501, 6883, 169, 44059, 17527, 197623}},
-{20808, 18, 124636, {1, 3, 7, 3, 17, 59, 15, 5, 379, 347, 821, 4047, 3565, 13689, 23275, 27901, 121401, 43077}},
-{20809, 18, 124645, {1, 1, 1, 7, 15, 11, 35, 29, 59, 99, 181, 3035, 3239, 1553, 32319, 64195, 115247, 149211}},
-{20810, 18, 124652, {1, 1, 5, 3, 31, 49, 87, 177, 231, 167, 373, 1125, 5919, 4805, 31983, 42873, 30169, 91853}},
-{20811, 18, 124663, {1, 1, 5, 15, 7, 63, 37, 15, 459, 449, 1835, 1769, 2527, 2577, 4251, 62459, 76699, 81721}},
-{20812, 18, 124667, {1, 1, 1, 3, 21, 15, 19, 183, 423, 827, 341, 2101, 3797, 7103, 30845, 24511, 115337, 117019}},
-{20813, 18, 124690, {1, 3, 5, 5, 19, 1, 97, 13, 491, 51, 445, 1987, 7481, 2613, 23141, 36603, 26917, 177397}},
-{20814, 18, 124755, {1, 1, 1, 5, 15, 43, 21, 167, 259, 989, 1937, 1519, 2201, 13973, 18031, 31583, 57557, 252737}},
-{20815, 18, 124757, {1, 3, 3, 7, 31, 11, 89, 53, 279, 83, 1247, 1221, 5499, 1199, 361, 22269, 88633, 134975}},
-{20816, 18, 124819, {1, 1, 3, 5, 9, 5, 113, 41, 143, 655, 1147, 2043, 4229, 10523, 1453, 1735, 76259, 30607}},
-{20817, 18, 124862, {1, 1, 1, 11, 5, 7, 9, 155, 221, 619, 813, 3111, 6039, 10789, 10905, 33285, 62841, 229217}},
-{20818, 18, 124864, {1, 3, 5, 9, 19, 19, 123, 65, 419, 597, 87, 3843, 4857, 15903, 23655, 13023, 8389, 230803}},
-{20819, 18, 124874, {1, 3, 3, 15, 9, 19, 51, 223, 197, 759, 139, 59, 6547, 1043, 5077, 55267, 23681, 17099}},
-{20820, 18, 124882, {1, 1, 3, 3, 15, 43, 63, 85, 227, 961, 1043, 1069, 6557, 7499, 31639, 4345, 26991, 132783}},
-{20821, 18, 124903, {1, 3, 1, 1, 25, 33, 59, 219, 435, 105, 1001, 323, 2729, 12517, 16607, 57533, 101167, 53829}},
-{20822, 18, 124915, {1, 3, 7, 7, 9, 55, 3, 247, 303, 453, 861, 817, 705, 14337, 15965, 28867, 126763, 204005}},
-{20823, 18, 124938, {1, 1, 3, 7, 1, 39, 15, 39, 359, 313, 1753, 2835, 387, 16223, 10945, 19481, 19995, 29989}},
-{20824, 18, 124945, {1, 1, 1, 5, 3, 31, 103, 123, 493, 1023, 119, 2175, 2273, 11637, 21605, 23349, 100759, 41227}},
-{20825, 18, 124973, {1, 3, 7, 13, 5, 13, 17, 7, 341, 945, 621, 1421, 3893, 5825, 26777, 35497, 13791, 25415}},
-{20826, 18, 124986, {1, 1, 5, 1, 19, 27, 39, 7, 177, 749, 1217, 2133, 6913, 13489, 23713, 1085, 31529, 179741}},
-{20827, 18, 124991, {1, 3, 3, 3, 15, 21, 5, 145, 281, 131, 1347, 19, 4917, 8655, 2515, 36927, 56551, 202039}},
-{20828, 18, 125011, {1, 1, 3, 7, 27, 31, 33, 255, 511, 195, 1493, 2221, 2157, 9303, 3957, 14163, 70435, 215763}},
-{20829, 18, 125014, {1, 3, 3, 15, 31, 41, 33, 37, 239, 865, 375, 2217, 809, 11961, 29393, 52145, 76223, 202623}},
-{20830, 18, 125082, {1, 3, 5, 11, 5, 57, 73, 193, 341, 843, 1817, 231, 65, 5941, 29693, 31751, 57081, 180977}},
-{20831, 18, 125105, {1, 3, 1, 9, 29, 57, 85, 107, 343, 891, 465, 2413, 1965, 7303, 7461, 25857, 110517, 16995}},
-{20832, 18, 125163, {1, 1, 7, 15, 7, 49, 121, 211, 253, 511, 1385, 1205, 33, 7713, 20059, 47353, 3267, 215759}},
-{20833, 18, 125165, {1, 1, 3, 9, 15, 63, 45, 155, 415, 589, 651, 3707, 5429, 4497, 13733, 21231, 18953, 28671}},
-{20834, 18, 125205, {1, 1, 5, 15, 7, 57, 31, 109, 427, 921, 629, 3439, 7615, 4535, 1507, 58931, 49597, 214397}},
-{20835, 18, 125219, {1, 3, 3, 5, 21, 35, 9, 241, 67, 767, 659, 1639, 7797, 5209, 14851, 55311, 108549, 175937}},
-{20836, 18, 125239, {1, 1, 7, 15, 21, 61, 13, 47, 267, 269, 1169, 257, 2481, 8345, 1061, 28119, 127197, 95379}},
-{20837, 18, 125240, {1, 1, 3, 7, 21, 35, 121, 223, 145, 665, 1389, 2105, 5499, 1377, 32417, 39027, 5335, 248315}},
-{20838, 18, 125257, {1, 3, 3, 9, 13, 33, 57, 225, 123, 703, 1049, 709, 7347, 11317, 12339, 23247, 62157, 85931}},
-{20839, 18, 125284, {1, 3, 3, 3, 5, 3, 105, 115, 13, 675, 757, 987, 6429, 13017, 21347, 38829, 82153, 220677}},
-{20840, 18, 125302, {1, 3, 1, 13, 5, 51, 75, 205, 7, 561, 207, 1133, 3303, 1889, 17093, 5933, 48109, 244387}},
-{20841, 18, 125327, {1, 3, 3, 7, 11, 11, 71, 243, 235, 941, 1875, 2387, 1139, 16275, 4537, 18791, 67927, 156759}},
-{20842, 18, 125336, {1, 3, 5, 5, 11, 35, 29, 5, 351, 223, 847, 1539, 4903, 7619, 24907, 37071, 57899, 32981}},
-{20843, 18, 125355, {1, 3, 1, 7, 23, 7, 119, 17, 123, 845, 1423, 2995, 3595, 13287, 31217, 33939, 6891, 156477}},
-{20844, 18, 125363, {1, 1, 1, 9, 11, 55, 121, 85, 175, 757, 1093, 513, 1117, 14049, 22377, 4623, 38511, 51391}},
-{20845, 18, 125365, {1, 1, 7, 1, 17, 1, 7, 185, 173, 841, 61, 2735, 6679, 7617, 17309, 58047, 11791, 228635}},
-{20846, 18, 125372, {1, 1, 5, 5, 1, 1, 61, 57, 37, 857, 531, 2655, 1907, 4245, 3047, 50489, 93447, 116637}},
-{20847, 18, 125378, {1, 3, 5, 7, 27, 47, 121, 95, 73, 63, 539, 137, 1765, 4659, 31141, 24495, 109541, 16421}},
-{20848, 18, 125383, {1, 3, 7, 13, 13, 25, 47, 45, 97, 243, 1509, 3539, 4791, 5627, 31981, 57663, 65359, 32183}},
-{20849, 18, 125387, {1, 1, 1, 7, 15, 57, 117, 249, 183, 849, 557, 833, 5751, 8035, 3371, 11389, 125581, 248799}},
-{20850, 18, 125390, {1, 3, 1, 15, 13, 31, 59, 243, 17, 473, 289, 1527, 649, 2807, 6183, 6173, 74381, 261673}},
-{20851, 18, 125414, {1, 1, 7, 7, 19, 17, 95, 81, 191, 487, 2023, 307, 3261, 13885, 9285, 30831, 114009, 26483}},
-{20852, 18, 125435, {1, 1, 3, 11, 17, 21, 85, 193, 477, 267, 393, 39, 5793, 8621, 25379, 9721, 13947, 44235}},
-{20853, 18, 125466, {1, 1, 7, 5, 27, 33, 93, 9, 471, 751, 1279, 695, 2625, 7061, 29577, 5403, 80705, 77895}},
-{20854, 18, 125481, {1, 1, 3, 11, 7, 25, 125, 9, 233, 935, 1897, 3685, 595, 15499, 43, 29251, 18029, 250231}},
-{20855, 18, 125522, {1, 1, 5, 1, 9, 55, 125, 179, 287, 371, 233, 149, 5639, 5737, 25251, 103, 117015, 35579}},
-{20856, 18, 125531, {1, 1, 5, 9, 17, 33, 69, 15, 209, 521, 1083, 2469, 679, 9307, 31539, 63889, 48825, 126327}},
-{20857, 18, 125544, {1, 3, 5, 15, 15, 41, 105, 121, 21, 935, 721, 445, 6759, 4227, 15227, 54933, 69589, 2689}},
-{20858, 18, 125564, {1, 1, 7, 15, 1, 15, 111, 141, 279, 1013, 825, 1069, 3793, 12929, 153, 11463, 87759, 179987}},
-{20859, 18, 125588, {1, 1, 1, 9, 15, 59, 109, 103, 223, 695, 1979, 1241, 2559, 8627, 10559, 53319, 94311, 245193}},
-{20860, 18, 125602, {1, 1, 5, 3, 1, 41, 51, 129, 297, 15, 637, 2489, 343, 13549, 7707, 36757, 55703, 161043}},
-{20861, 18, 125613, {1, 3, 5, 1, 13, 35, 119, 219, 319, 733, 789, 1343, 8035, 15049, 981, 14477, 13717, 177481}},
-{20862, 18, 125621, {1, 1, 1, 11, 5, 17, 3, 43, 129, 705, 1701, 3635, 1201, 12283, 27443, 54257, 102281, 211859}},
-{20863, 18, 125648, {1, 3, 1, 13, 7, 63, 9, 45, 283, 41, 801, 131, 2797, 13329, 19011, 21055, 122965, 7961}},
-{20864, 18, 125651, {1, 3, 3, 5, 9, 27, 99, 129, 499, 523, 1939, 3661, 455, 12601, 11723, 3727, 32671, 78251}},
-{20865, 18, 125681, {1, 3, 7, 5, 9, 57, 63, 47, 49, 745, 945, 2927, 6659, 1023, 9991, 55379, 105295, 259901}},
-{20866, 18, 125719, {1, 1, 3, 3, 3, 47, 15, 237, 193, 409, 1165, 3581, 719, 3049, 14679, 31559, 7825, 96083}},
-{20867, 18, 125773, {1, 1, 7, 11, 9, 55, 29, 123, 163, 415, 2013, 97, 1471, 1409, 28867, 50405, 99417, 57113}},
-{20868, 18, 125774, {1, 1, 7, 15, 5, 17, 57, 123, 25, 119, 1699, 1289, 3139, 7177, 13465, 33583, 34517, 182669}},
-{20869, 18, 125779, {1, 1, 3, 1, 15, 45, 79, 7, 461, 223, 691, 3071, 6233, 14997, 4083, 65391, 60571, 82929}},
-{20870, 18, 125786, {1, 3, 5, 1, 25, 39, 89, 105, 497, 685, 1921, 133, 4849, 8467, 609, 62183, 123787, 223025}},
-{20871, 18, 125792, {1, 1, 1, 13, 3, 57, 117, 241, 501, 107, 1253, 3097, 603, 10645, 3395, 13997, 112527, 208263}},
-{20872, 18, 125822, {1, 1, 7, 9, 7, 31, 25, 97, 205, 785, 517, 549, 6841, 7097, 9635, 17151, 57135, 105469}},
-{20873, 18, 125828, {1, 3, 7, 1, 25, 35, 43, 75, 179, 1023, 1921, 1529, 2791, 6747, 9135, 61801, 46729, 26821}},
-{20874, 18, 125831, {1, 1, 3, 1, 31, 49, 107, 219, 285, 501, 1503, 3103, 5257, 14561, 31493, 7753, 34375, 260357}},
-{20875, 18, 125837, {1, 3, 7, 13, 15, 7, 75, 57, 329, 67, 1541, 2445, 3069, 6723, 10189, 22913, 110781, 243765}},
-{20876, 18, 125880, {1, 1, 5, 3, 5, 45, 47, 39, 493, 787, 1019, 3933, 535, 1763, 139, 45967, 123167, 115019}},
-{20877, 18, 125891, {1, 3, 1, 3, 23, 59, 93, 139, 349, 973, 1401, 2109, 701, 461, 19199, 21733, 80009, 37239}},
-{20878, 18, 125922, {1, 1, 3, 5, 3, 39, 117, 77, 257, 117, 1991, 3371, 509, 3963, 14579, 62459, 52281, 99209}},
-{20879, 18, 125928, {1, 3, 1, 15, 29, 47, 73, 157, 429, 497, 39, 123, 4851, 12871, 4567, 29453, 90777, 188683}},
-{20880, 18, 125931, {1, 3, 3, 1, 17, 25, 5, 247, 61, 81, 1555, 2167, 6003, 15911, 16023, 7841, 50731, 229163}},
-{20881, 18, 125941, {1, 1, 5, 9, 9, 39, 89, 37, 105, 133, 333, 2863, 7249, 2355, 9407, 28145, 25923, 68827}},
-{20882, 18, 125948, {1, 3, 7, 13, 15, 55, 11, 93, 197, 447, 1793, 1793, 4639, 1869, 1711, 1439, 15899, 106931}},
-{20883, 18, 125960, {1, 1, 5, 13, 23, 11, 67, 155, 511, 363, 1073, 2249, 719, 11167, 7953, 21699, 55735, 47353}},
-{20884, 18, 125973, {1, 1, 3, 3, 21, 59, 123, 227, 65, 695, 1769, 4057, 7071, 1827, 13639, 45711, 84019, 96897}},
-{20885, 18, 126014, {1, 3, 1, 11, 25, 51, 57, 139, 147, 589, 1565, 511, 3629, 7329, 9565, 62893, 85789, 112047}},
-{20886, 18, 126016, {1, 3, 5, 5, 23, 11, 93, 75, 25, 947, 1489, 4081, 3395, 4655, 27853, 41299, 89447, 100971}},
-{20887, 18, 126036, {1, 3, 5, 11, 25, 63, 93, 227, 411, 49, 403, 437, 1739, 8453, 31693, 51439, 89729, 113405}},
-{20888, 18, 126043, {1, 3, 7, 9, 29, 13, 51, 155, 403, 627, 173, 2111, 833, 11453, 17673, 7121, 52943, 114835}},
-{20889, 18, 126062, {1, 1, 5, 13, 11, 11, 105, 101, 309, 577, 1003, 3667, 3489, 11807, 6119, 13773, 89879, 12391}},
-{20890, 18, 126076, {1, 3, 7, 9, 17, 11, 111, 239, 225, 723, 933, 3353, 2003, 5273, 207, 38539, 82539, 209781}},
-{20891, 18, 126116, {1, 1, 7, 13, 15, 53, 69, 105, 155, 445, 353, 617, 5625, 13439, 29223, 60439, 119635, 49643}},
-{20892, 18, 126125, {1, 1, 3, 11, 13, 25, 107, 27, 109, 313, 1721, 2647, 1861, 10631, 17131, 31365, 65319, 102905}},
-{20893, 18, 126145, {1, 1, 1, 7, 21, 29, 39, 167, 341, 115, 1523, 2209, 95, 4399, 3881, 38875, 107691, 132471}},
-{20894, 18, 126152, {1, 1, 1, 13, 15, 61, 125, 23, 301, 407, 1497, 3731, 7013, 5405, 31233, 51701, 45619, 107407}},
-{20895, 18, 126175, {1, 3, 5, 5, 31, 27, 77, 21, 339, 1013, 371, 19, 5733, 2177, 15547, 27595, 6805, 172695}},
-{20896, 18, 126188, {1, 3, 5, 11, 5, 15, 71, 23, 441, 169, 1715, 437, 1791, 293, 13441, 11225, 119119, 223035}},
-{20897, 18, 126199, {1, 3, 1, 5, 11, 15, 95, 127, 433, 789, 899, 2591, 2339, 8237, 20765, 32897, 51511, 58437}},
-{20898, 18, 126205, {1, 3, 5, 9, 11, 57, 103, 5, 401, 51, 1813, 923, 1983, 1853, 21913, 3051, 56309, 19423}},
-{20899, 18, 126213, {1, 1, 3, 15, 3, 3, 41, 5, 231, 35, 391, 185, 7585, 1005, 20311, 11193, 18275, 114131}},
-{20900, 18, 126220, {1, 1, 3, 9, 13, 13, 115, 203, 223, 575, 459, 1839, 3949, 16027, 23137, 13723, 19195, 249337}},
-{20901, 18, 126286, {1, 1, 1, 9, 21, 51, 39, 245, 187, 609, 319, 2927, 3625, 10789, 31291, 45557, 45935, 132447}},
-{20902, 18, 126294, {1, 3, 3, 9, 25, 37, 47, 55, 219, 409, 1927, 553, 3953, 6209, 11807, 11133, 48047, 132437}},
-{20903, 18, 126300, {1, 3, 1, 13, 23, 31, 109, 167, 281, 179, 233, 1603, 7391, 9091, 27021, 31213, 13093, 86017}},
-{20904, 18, 126322, {1, 3, 1, 13, 13, 15, 7, 29, 409, 59, 505, 1307, 6247, 6055, 5531, 59727, 58069, 84049}},
-{20905, 18, 126324, {1, 1, 5, 7, 19, 7, 103, 245, 133, 609, 1087, 2365, 3341, 1689, 18841, 19625, 47413, 63445}},
-{20906, 18, 126343, {1, 1, 7, 3, 11, 27, 79, 75, 97, 355, 493, 2035, 3413, 11835, 9157, 51173, 1, 71797}},
-{20907, 18, 126344, {1, 1, 5, 5, 29, 1, 43, 135, 473, 329, 1197, 1693, 3823, 7723, 24771, 22349, 94383, 41461}},
-{20908, 18, 126430, {1, 3, 3, 15, 25, 9, 79, 213, 317, 615, 541, 441, 505, 13665, 3691, 17825, 49303, 91783}},
-{20909, 18, 126433, {1, 3, 1, 11, 27, 33, 65, 31, 469, 799, 1251, 3357, 5239, 5651, 13317, 28553, 64225, 9805}},
-{20910, 18, 126448, {1, 1, 7, 13, 9, 49, 77, 43, 363, 719, 1943, 1285, 1587, 1047, 29419, 24025, 89901, 229095}},
-{20911, 18, 126451, {1, 1, 1, 15, 19, 57, 33, 243, 111, 183, 497, 603, 923, 1957, 6493, 11833, 7331, 229975}},
-{20912, 18, 126457, {1, 3, 1, 1, 13, 43, 31, 25, 169, 303, 69, 723, 1745, 1025, 14301, 2523, 111887, 179519}},
-{20913, 18, 126458, {1, 3, 1, 5, 31, 55, 11, 103, 391, 881, 1885, 3923, 7507, 377, 29331, 32167, 56915, 44211}},
-{20914, 18, 126463, {1, 1, 7, 1, 27, 55, 33, 141, 393, 73, 701, 3173, 973, 15553, 10219, 51441, 55201, 131055}},
-{20915, 18, 126470, {1, 1, 3, 9, 1, 31, 115, 85, 173, 227, 163, 157, 5569, 8291, 27163, 7581, 8699, 104523}},
-{20916, 18, 126484, {1, 1, 1, 5, 5, 19, 11, 55, 217, 571, 1001, 945, 6237, 1993, 11809, 63893, 60081, 102997}},
-{20917, 18, 126518, {1, 3, 3, 15, 15, 7, 51, 161, 147, 263, 1701, 1079, 3027, 11779, 24885, 16127, 68985, 162975}},
-{20918, 18, 126521, {1, 3, 1, 9, 25, 1, 47, 107, 149, 997, 1779, 2905, 4951, 10345, 31059, 63831, 117219, 251935}},
-{20919, 18, 126547, {1, 3, 3, 9, 5, 23, 83, 95, 399, 343, 1597, 1733, 5959, 9685, 4721, 59109, 113633, 80365}},
-{20920, 18, 126556, {1, 1, 7, 11, 31, 43, 71, 133, 305, 529, 645, 3095, 6273, 4019, 14433, 41609, 64093, 79051}},
-{20921, 18, 126583, {1, 3, 5, 11, 1, 63, 123, 25, 245, 583, 1013, 3275, 2997, 13021, 27515, 16233, 113093, 249101}},
-{20922, 18, 126584, {1, 1, 1, 9, 3, 59, 113, 155, 125, 423, 259, 1559, 3745, 9105, 27673, 36601, 36117, 47953}},
-{20923, 18, 126633, {1, 3, 3, 7, 19, 41, 55, 87, 53, 801, 661, 329, 3391, 7581, 25487, 25751, 120171, 35953}},
-{20924, 18, 126673, {1, 1, 7, 15, 31, 57, 49, 179, 147, 139, 957, 289, 4321, 8747, 53, 46003, 40219, 96855}},
-{20925, 18, 126680, {1, 1, 7, 9, 29, 49, 71, 101, 389, 793, 1355, 3263, 6331, 4869, 28479, 8335, 74653, 8519}},
-{20926, 18, 126686, {1, 1, 1, 13, 1, 19, 31, 161, 261, 679, 1115, 985, 2855, 4395, 15087, 18593, 98535, 52537}},
-{20927, 18, 126689, {1, 1, 3, 11, 15, 51, 79, 7, 75, 75, 753, 2637, 7193, 7961, 21411, 24273, 7543, 6277}},
-{20928, 18, 126702, {1, 3, 1, 5, 5, 51, 67, 191, 201, 777, 587, 1439, 1027, 3759, 31141, 42159, 58475, 7355}},
-{20929, 18, 126710, {1, 3, 5, 3, 15, 37, 11, 251, 53, 799, 739, 2225, 6985, 9183, 12341, 29963, 44101, 23889}},
-{20930, 18, 126722, {1, 1, 3, 3, 5, 33, 81, 223, 89, 531, 301, 305, 2401, 4015, 18607, 65041, 82447, 228487}},
-{20931, 18, 126787, {1, 3, 1, 7, 15, 29, 71, 247, 445, 1005, 1229, 3897, 899, 11175, 6349, 29145, 103153, 90275}},
-{20932, 18, 126789, {1, 3, 3, 7, 15, 7, 75, 13, 417, 719, 121, 1345, 3737, 4119, 15259, 33579, 57727, 111517}},
-{20933, 18, 126794, {1, 3, 7, 3, 31, 11, 49, 61, 405, 741, 1607, 1561, 4655, 9775, 14349, 27431, 91791, 228607}},
-{20934, 18, 126801, {1, 3, 5, 13, 17, 27, 93, 153, 99, 683, 219, 3783, 6963, 1633, 6621, 8133, 5111, 57333}},
-{20935, 18, 126857, {1, 3, 3, 3, 25, 29, 75, 155, 159, 25, 637, 3053, 4737, 5831, 9651, 45331, 100407, 188607}},
-{20936, 18, 126891, {1, 3, 1, 9, 21, 55, 123, 27, 509, 227, 1569, 1379, 7137, 11749, 14257, 38349, 459, 54873}},
-{20937, 18, 126896, {1, 1, 7, 15, 29, 35, 81, 79, 237, 155, 1551, 343, 5127, 3233, 3691, 59917, 7367, 181979}},
-{20938, 18, 126902, {1, 3, 1, 15, 1, 57, 111, 121, 375, 635, 1529, 635, 2337, 6553, 22067, 36047, 80099, 116411}},
-{20939, 18, 126911, {1, 1, 3, 3, 29, 27, 19, 3, 69, 197, 1829, 1907, 5901, 12651, 3295, 7805, 57871, 47571}},
-{20940, 18, 126919, {1, 1, 1, 13, 21, 5, 115, 51, 203, 991, 1731, 1101, 1607, 14323, 12233, 48047, 33969, 147621}},
-{20941, 18, 126943, {1, 3, 3, 1, 25, 55, 41, 31, 101, 551, 1519, 1915, 6961, 13919, 15339, 13141, 107625, 9247}},
-{20942, 18, 126947, {1, 1, 7, 11, 17, 25, 87, 175, 341, 445, 1813, 2995, 3217, 6015, 1637, 65243, 72743, 248715}},
-{20943, 18, 126949, {1, 1, 5, 13, 11, 1, 61, 139, 233, 167, 1363, 1991, 7999, 16289, 25595, 8915, 32205, 169963}},
-{20944, 18, 126953, {1, 1, 1, 13, 31, 33, 67, 57, 121, 477, 755, 2035, 3683, 16205, 5511, 25615, 5169, 128843}},
-{20945, 18, 126971, {1, 3, 5, 15, 31, 1, 89, 29, 493, 379, 1627, 491, 2503, 8105, 30275, 27379, 43905, 46397}},
-{20946, 18, 126976, {1, 1, 7, 9, 31, 41, 127, 121, 61, 561, 223, 3231, 7321, 3683, 15455, 8019, 116739, 96557}},
-{20947, 18, 126982, {1, 1, 5, 9, 19, 41, 25, 65, 111, 535, 611, 1631, 4251, 107, 19787, 40749, 65701, 48749}},
-{20948, 18, 127009, {1, 3, 3, 11, 27, 49, 75, 93, 15, 937, 1517, 1577, 7485, 8713, 15979, 13799, 103057, 144799}},
-{20949, 18, 127021, {1, 1, 7, 7, 7, 29, 3, 63, 177, 781, 2001, 315, 6703, 8055, 19081, 33641, 44279, 87597}},
-{20950, 18, 127027, {1, 1, 7, 11, 29, 53, 83, 223, 275, 951, 1883, 2447, 1815, 9313, 9247, 17185, 8143, 135247}},
-{20951, 18, 127039, {1, 1, 5, 13, 21, 47, 87, 55, 169, 95, 777, 2787, 7227, 11373, 16707, 28237, 30789, 64589}},
-{20952, 18, 127041, {1, 1, 1, 11, 15, 41, 1, 55, 337, 493, 1379, 2505, 6831, 10955, 1875, 21821, 54101, 9379}},
-{20953, 18, 127044, {1, 3, 5, 15, 27, 9, 121, 49, 439, 781, 1457, 1341, 7433, 5879, 13039, 24001, 64059, 157077}},
-{20954, 18, 127059, {1, 1, 1, 9, 19, 55, 89, 37, 255, 345, 215, 4067, 8151, 14253, 12121, 3637, 29185, 60643}},
-{20955, 18, 127071, {1, 3, 1, 7, 31, 39, 71, 29, 71, 83, 1249, 871, 8037, 1001, 25245, 26651, 34509, 123607}},
-{20956, 18, 127075, {1, 1, 3, 11, 13, 21, 15, 171, 255, 373, 429, 2179, 4431, 16087, 17949, 16307, 129877, 186495}},
-{20957, 18, 127126, {1, 3, 3, 9, 17, 45, 75, 175, 3, 403, 215, 1781, 7875, 14113, 6967, 65263, 125885, 232983}},
-{20958, 18, 127129, {1, 1, 7, 9, 21, 57, 73, 105, 163, 583, 587, 2743, 2199, 5187, 5571, 56399, 797, 192405}},
-{20959, 18, 127145, {1, 1, 1, 3, 29, 27, 71, 145, 11, 455, 1505, 2789, 4083, 12345, 14785, 4981, 95121, 134977}},
-{20960, 18, 127154, {1, 1, 1, 1, 1, 27, 1, 145, 473, 483, 83, 3009, 7241, 13633, 15071, 30767, 128103, 94727}},
-{20961, 18, 127165, {1, 3, 5, 15, 17, 51, 71, 21, 237, 65, 901, 3365, 7831, 3027, 8751, 14435, 79445, 172587}},
-{20962, 18, 127171, {1, 1, 5, 1, 9, 49, 49, 31, 395, 339, 343, 1813, 2607, 9347, 11239, 6761, 127623, 43459}},
-{20963, 18, 127197, {1, 1, 1, 1, 13, 23, 71, 131, 225, 229, 117, 889, 8145, 5953, 10679, 38687, 80029, 63689}},
-{20964, 18, 127198, {1, 1, 5, 1, 29, 1, 87, 181, 441, 353, 257, 335, 203, 10897, 24085, 26967, 62573, 170285}},
-{20965, 18, 127207, {1, 1, 7, 3, 3, 39, 47, 135, 353, 977, 89, 259, 6411, 5511, 10697, 57623, 27367, 108451}},
-{20966, 18, 127226, {1, 3, 3, 11, 9, 57, 95, 211, 237, 281, 1703, 2107, 2179, 3411, 32621, 5387, 29971, 102889}},
-{20967, 18, 127240, {1, 1, 1, 13, 27, 49, 47, 49, 413, 985, 649, 1245, 807, 13637, 21741, 32565, 80135, 127971}},
-{20968, 18, 127254, {1, 3, 7, 13, 3, 19, 57, 97, 493, 597, 135, 1689, 5011, 4579, 6093, 28341, 37279, 142197}},
-{20969, 18, 127269, {1, 3, 1, 15, 15, 31, 3, 89, 327, 107, 827, 1111, 261, 6211, 4359, 38553, 43297, 75057}},
-{20970, 18, 127305, {1, 1, 1, 9, 19, 19, 53, 195, 141, 297, 141, 3859, 4173, 12243, 31399, 6353, 110505, 172219}},
-{20971, 18, 127323, {1, 3, 3, 9, 31, 51, 59, 53, 55, 723, 1575, 3399, 8057, 12317, 8393, 1719, 96987, 228955}},
-{20972, 18, 127342, {1, 1, 7, 11, 19, 59, 41, 9, 217, 267, 629, 2977, 4515, 463, 31773, 61765, 78827, 51331}},
-{20973, 18, 127347, {1, 3, 3, 13, 9, 55, 51, 177, 183, 431, 555, 3573, 7977, 3067, 21111, 12971, 78283, 260721}},
-{20974, 18, 127363, {1, 1, 1, 11, 27, 5, 89, 69, 435, 199, 221, 1017, 7703, 7469, 7755, 46319, 37941, 55285}},
-{20975, 18, 127394, {1, 1, 7, 13, 19, 55, 53, 207, 367, 177, 1483, 2857, 3753, 5493, 13349, 14033, 7933, 93457}},
-{20976, 18, 127426, {1, 1, 7, 3, 27, 35, 19, 223, 341, 137, 1195, 1263, 5937, 13517, 55, 6391, 106173, 176503}},
-{20977, 18, 127432, {1, 3, 7, 11, 23, 25, 37, 103, 351, 945, 1205, 2543, 3875, 155, 27777, 36647, 47979, 25113}},
-{20978, 18, 127440, {1, 1, 3, 15, 25, 59, 79, 39, 17, 553, 1119, 3353, 2619, 3851, 5945, 47501, 17369, 89355}},
-{20979, 18, 127462, {1, 1, 1, 13, 9, 55, 13, 173, 207, 925, 1855, 1871, 7851, 1361, 20117, 51677, 77703, 51309}},
-{20980, 18, 127468, {1, 3, 1, 1, 31, 57, 3, 25, 329, 927, 1683, 1447, 6853, 103, 9549, 21393, 415, 122749}},
-{20981, 18, 127473, {1, 1, 5, 5, 31, 61, 31, 213, 85, 531, 931, 999, 1189, 5189, 15127, 47799, 70769, 81901}},
-{20982, 18, 127486, {1, 1, 3, 1, 5, 59, 89, 53, 105, 761, 313, 3013, 4093, 9595, 4287, 51505, 20095, 232933}},
-{20983, 18, 127502, {1, 1, 7, 7, 23, 9, 41, 29, 399, 395, 759, 2541, 2373, 15365, 12083, 49579, 34401, 168121}},
-{20984, 18, 127510, {1, 1, 3, 1, 7, 23, 37, 183, 205, 377, 1081, 1081, 7767, 363, 14571, 16265, 18267, 102155}},
-{20985, 18, 127523, {1, 3, 3, 15, 19, 11, 59, 59, 465, 437, 965, 3707, 3505, 14785, 23605, 12505, 130607, 40693}},
-{20986, 18, 127543, {1, 1, 3, 13, 5, 15, 91, 33, 235, 215, 1997, 2035, 7407, 3203, 27143, 14007, 96411, 593}},
-{20987, 18, 127567, {1, 3, 7, 1, 19, 51, 1, 69, 489, 629, 1731, 393, 6807, 10521, 23971, 45649, 105183, 207351}},
-{20988, 18, 127570, {1, 3, 5, 3, 5, 41, 89, 141, 469, 177, 109, 2439, 7155, 2083, 31993, 13933, 100557, 137255}},
-{20989, 18, 127585, {1, 1, 7, 15, 21, 45, 41, 197, 365, 177, 61, 811, 2535, 5219, 3689, 53129, 42063, 60759}},
-{20990, 18, 127588, {1, 3, 5, 1, 23, 7, 19, 193, 253, 793, 539, 3747, 2611, 16211, 17199, 14875, 95377, 6999}},
-{20991, 18, 127619, {1, 1, 3, 5, 9, 5, 9, 129, 217, 473, 151, 3053, 6981, 8075, 32121, 31995, 41271, 208927}},
-{20992, 18, 127621, {1, 1, 5, 9, 9, 9, 89, 139, 381, 937, 1937, 1879, 8191, 2237, 25629, 51471, 87639, 173697}},
-{20993, 18, 127626, {1, 1, 5, 9, 17, 35, 81, 223, 161, 315, 139, 2597, 2599, 16191, 2567, 54947, 8603, 121589}},
-{20994, 18, 127628, {1, 1, 5, 5, 9, 7, 33, 49, 49, 723, 1013, 1055, 4025, 1471, 30081, 17475, 127931, 63723}},
-{20995, 18, 127640, {1, 3, 7, 7, 9, 49, 107, 17, 335, 119, 1959, 3613, 8129, 11033, 12197, 23803, 112595, 131655}},
-{20996, 18, 127662, {1, 3, 5, 11, 3, 45, 91, 17, 181, 1005, 985, 3045, 853, 8181, 5517, 48515, 16225, 237151}},
-{20997, 18, 127684, {1, 1, 3, 1, 3, 63, 35, 135, 61, 383, 1233, 675, 151, 2157, 18711, 37113, 40353, 61783}},
-{20998, 18, 127687, {1, 3, 5, 5, 29, 3, 105, 11, 351, 761, 165, 911, 6903, 10111, 1779, 24601, 3177, 110301}},
-{20999, 18, 127693, {1, 1, 3, 15, 25, 19, 73, 237, 263, 161, 731, 3853, 7705, 14497, 30799, 32979, 100729, 21761}},
-{21000, 18, 127696, {1, 1, 3, 5, 27, 9, 3, 149, 207, 715, 1435, 2563, 2451, 7951, 26313, 55115, 99423, 231639}},
-{21001, 18, 127708, {1, 1, 5, 15, 11, 51, 13, 47, 311, 969, 2013, 357, 4847, 1831, 2235, 22779, 32375, 40893}},
-{21002, 18, 127711, {1, 1, 3, 9, 21, 45, 11, 99, 275, 849, 443, 1257, 7855, 9121, 6549, 20289, 101337, 13869}},
-{21003, 18, 127722, {1, 1, 1, 15, 25, 27, 15, 111, 215, 437, 1923, 1985, 4603, 15469, 6667, 17941, 50433, 152759}},
-{21004, 18, 127732, {1, 3, 7, 15, 7, 37, 119, 53, 337, 853, 1785, 3507, 3743, 14303, 22757, 5149, 1539, 227051}},
-{21005, 18, 127747, {1, 1, 3, 13, 11, 23, 55, 19, 495, 531, 1021, 3831, 5993, 15819, 2121, 52773, 19775, 94643}},
-{21006, 18, 127767, {1, 1, 3, 3, 23, 55, 55, 69, 457, 755, 1187, 3993, 613, 12691, 1779, 21251, 2293, 236725}},
-{21007, 18, 127771, {1, 1, 5, 9, 23, 27, 61, 125, 113, 99, 503, 699, 6873, 13141, 10649, 65209, 21773, 162749}},
-{21008, 18, 127790, {1, 1, 1, 11, 15, 27, 111, 227, 493, 361, 1071, 607, 1409, 9281, 24515, 26739, 82421, 30463}},
-{21009, 18, 127816, {1, 3, 5, 1, 11, 57, 23, 239, 265, 675, 441, 4031, 5163, 15729, 2741, 26037, 32533, 140645}},
-{21010, 18, 127824, {1, 3, 3, 7, 3, 45, 105, 135, 493, 579, 1707, 2933, 1135, 11891, 3171, 45401, 24993, 175681}},
-{21011, 18, 127833, {1, 1, 1, 11, 11, 3, 67, 213, 483, 9, 1053, 213, 3205, 8487, 16093, 7305, 122591, 31811}},
-{21012, 18, 127869, {1, 1, 5, 13, 19, 31, 13, 65, 29, 929, 343, 463, 1885, 13467, 14997, 22737, 42869, 128239}},
-{21013, 18, 127910, {1, 3, 3, 13, 9, 47, 125, 33, 475, 285, 1901, 2525, 305, 11587, 27309, 30037, 70681, 180425}},
-{21014, 18, 127928, {1, 3, 5, 15, 9, 37, 45, 149, 19, 135, 555, 4037, 5173, 12473, 983, 40923, 28561, 185941}},
-{21015, 18, 127933, {1, 3, 3, 9, 23, 35, 35, 151, 113, 885, 1553, 2233, 351, 4071, 28127, 26109, 12299, 163973}},
-{21016, 18, 127963, {1, 3, 3, 11, 17, 55, 125, 87, 315, 917, 383, 2397, 1573, 9255, 10499, 16051, 99487, 139415}},
-{21017, 18, 127975, {1, 1, 3, 1, 29, 21, 101, 153, 5, 705, 1965, 1447, 8163, 13547, 25929, 28569, 57897, 173229}},
-{21018, 18, 128016, {1, 1, 7, 15, 3, 37, 113, 213, 495, 935, 529, 2299, 6901, 1765, 4255, 14579, 14175, 112333}},
-{21019, 18, 128031, {1, 3, 3, 9, 11, 53, 89, 27, 461, 235, 1525, 3533, 3061, 4351, 12847, 21649, 10843, 60901}},
-{21020, 18, 128059, {1, 1, 5, 1, 17, 11, 17, 157, 387, 887, 2017, 3641, 923, 12659, 19691, 18657, 3127, 218819}},
-{21021, 18, 128074, {1, 3, 1, 9, 5, 3, 49, 215, 379, 765, 1375, 345, 2285, 8197, 9531, 6725, 22475, 203883}},
-{21022, 18, 128107, {1, 1, 3, 9, 19, 41, 13, 233, 97, 755, 249, 2011, 5815, 6317, 4121, 63637, 43353, 154753}},
-{21023, 18, 128122, {1, 3, 7, 15, 31, 25, 93, 197, 455, 979, 1805, 2619, 803, 5705, 1679, 29317, 66477, 159187}},
-{21024, 18, 128157, {1, 1, 1, 13, 11, 25, 61, 233, 339, 171, 559, 427, 3239, 8889, 3711, 19743, 18099, 49201}},
-{21025, 18, 128161, {1, 3, 7, 13, 19, 5, 9, 183, 355, 137, 1767, 1113, 1149, 5791, 4099, 37911, 75945, 115397}},
-{21026, 18, 128200, {1, 1, 3, 13, 27, 25, 121, 3, 337, 195, 1841, 2009, 4181, 3197, 20275, 42493, 7495, 24407}},
-{21027, 18, 128213, {1, 1, 1, 15, 3, 43, 39, 25, 57, 829, 565, 1977, 4027, 11053, 13961, 13965, 4207, 1663}},
-{21028, 18, 128229, {1, 3, 5, 9, 11, 7, 107, 205, 479, 961, 1549, 1701, 6305, 15419, 23331, 46443, 55171, 235109}},
-{21029, 18, 128233, {1, 3, 5, 5, 19, 3, 39, 211, 429, 363, 765, 283, 2469, 1947, 10481, 1969, 95545, 187671}},
-{21030, 18, 128241, {1, 1, 1, 1, 11, 55, 47, 121, 251, 63, 767, 3673, 3233, 14865, 25713, 48443, 79139, 225021}},
-{21031, 18, 128259, {1, 1, 3, 11, 25, 35, 57, 103, 385, 155, 173, 4023, 489, 1733, 14423, 61843, 24793, 9871}},
-{21032, 18, 128295, {1, 3, 1, 15, 9, 29, 99, 187, 471, 877, 1321, 2489, 7439, 4259, 32703, 1459, 42093, 261097}},
-{21033, 18, 128299, {1, 1, 3, 11, 9, 25, 113, 251, 337, 405, 847, 2451, 5649, 3449, 11703, 18271, 108005, 208789}},
-{21034, 18, 128313, {1, 3, 3, 7, 13, 53, 61, 251, 461, 461, 1557, 1215, 6731, 13349, 21003, 11573, 66751, 79733}},
-{21035, 18, 128345, {1, 1, 5, 1, 23, 49, 101, 175, 251, 577, 1667, 2561, 6545, 16305, 18457, 65067, 35843, 123445}},
-{21036, 18, 128362, {1, 1, 5, 3, 7, 9, 61, 107, 395, 137, 559, 2315, 2559, 11929, 4843, 41661, 61361, 146163}},
-{21037, 18, 128375, {1, 3, 1, 5, 1, 3, 43, 251, 329, 289, 323, 2201, 4129, 4963, 27477, 18743, 46551, 93061}},
-{21038, 18, 128376, {1, 1, 7, 3, 17, 63, 21, 159, 447, 377, 69, 2517, 8181, 6043, 3039, 7747, 72465, 41027}},
-{21039, 18, 128406, {1, 1, 1, 1, 13, 3, 45, 93, 391, 509, 867, 1561, 5017, 11851, 24891, 22531, 18993, 129421}},
-{21040, 18, 128410, {1, 3, 3, 11, 15, 1, 127, 9, 161, 321, 2003, 239, 1379, 11903, 13503, 26529, 57725, 214797}},
-{21041, 18, 128416, {1, 1, 1, 13, 31, 11, 17, 25, 1, 645, 675, 735, 2083, 1919, 18977, 4995, 91559, 230463}},
-{21042, 18, 128443, {1, 3, 1, 13, 17, 21, 107, 167, 135, 797, 715, 3275, 5437, 4253, 11671, 14867, 36041, 71751}},
-{21043, 18, 128451, {1, 3, 5, 5, 11, 49, 93, 231, 431, 567, 1605, 3281, 7049, 2947, 863, 39593, 117167, 167301}},
-{21044, 18, 128465, {1, 1, 1, 1, 5, 13, 61, 91, 127, 189, 1879, 3921, 4303, 4831, 6765, 31005, 107627, 80693}},
-{21045, 18, 128466, {1, 3, 1, 3, 1, 49, 61, 9, 467, 891, 105, 317, 137, 12789, 12367, 57455, 39777, 88047}},
-{21046, 18, 128484, {1, 1, 3, 13, 23, 63, 37, 103, 23, 223, 647, 2523, 3211, 14551, 22663, 48237, 54777, 180297}},
-{21047, 18, 128499, {1, 3, 3, 7, 29, 51, 85, 179, 441, 431, 535, 2975, 8083, 8619, 30229, 31421, 54063, 163601}},
-{21048, 18, 128502, {1, 3, 1, 1, 27, 39, 125, 171, 57, 729, 511, 957, 7541, 2347, 1669, 32323, 108531, 69943}},
-{21049, 18, 128524, {1, 3, 3, 7, 1, 33, 89, 245, 95, 21, 699, 1441, 2659, 501, 32323, 39145, 82311, 155479}},
-{21050, 18, 128536, {1, 1, 3, 11, 29, 13, 87, 251, 329, 667, 325, 2411, 7959, 8069, 20817, 42445, 121675, 113421}},
-{21051, 18, 128541, {1, 1, 1, 7, 9, 57, 109, 237, 325, 535, 89, 1285, 5649, 13673, 29375, 51553, 81723, 11003}},
-{21052, 18, 128542, {1, 3, 1, 1, 13, 5, 31, 109, 157, 817, 1303, 725, 1841, 5503, 2255, 34637, 93603, 82825}},
-{21053, 18, 128592, {1, 3, 7, 7, 5, 33, 39, 233, 217, 157, 357, 2727, 3565, 1539, 5317, 23967, 30375, 260381}},
-{21054, 18, 128598, {1, 1, 5, 3, 23, 51, 45, 181, 353, 519, 949, 3043, 1517, 3387, 15081, 5997, 31523, 80007}},
-{21055, 18, 128623, {1, 1, 3, 5, 23, 21, 83, 51, 275, 629, 1433, 1821, 3761, 2367, 32089, 13813, 99629, 64603}},
-{21056, 18, 128632, {1, 1, 5, 15, 11, 49, 69, 197, 193, 459, 1915, 787, 3631, 5219, 11109, 12311, 56625, 117439}},
-{21057, 18, 128671, {1, 3, 3, 3, 31, 29, 57, 27, 43, 231, 777, 2139, 2609, 12273, 23777, 4151, 51749, 110013}},
-{21058, 18, 128713, {1, 1, 5, 13, 9, 63, 83, 69, 225, 913, 99, 1167, 5279, 14163, 3979, 55151, 84387, 234583}},
-{21059, 18, 128724, {1, 1, 7, 5, 9, 57, 87, 23, 335, 403, 1843, 725, 5187, 4137, 24299, 44807, 98523, 217815}},
-{21060, 18, 128731, {1, 3, 3, 3, 3, 23, 115, 229, 193, 655, 1205, 3159, 1935, 113, 20943, 32917, 69633, 2133}},
-{21061, 18, 128761, {1, 3, 3, 1, 17, 5, 59, 139, 75, 185, 1951, 3689, 4997, 2761, 8673, 41783, 75075, 101063}},
-{21062, 18, 128767, {1, 3, 1, 13, 1, 51, 63, 127, 67, 743, 1049, 2055, 4249, 131, 8153, 50237, 28135, 76059}},
-{21063, 18, 128782, {1, 3, 7, 13, 5, 39, 83, 63, 429, 573, 1915, 3801, 2223, 1585, 16997, 45571, 23311, 108099}},
-{21064, 18, 128793, {1, 3, 1, 3, 15, 49, 19, 65, 433, 401, 1901, 3653, 2399, 15171, 9695, 30257, 104877, 181221}},
-{21065, 18, 128805, {1, 3, 1, 1, 25, 37, 89, 7, 81, 343, 949, 3535, 1681, 10089, 23513, 3897, 127083, 214005}},
-{21066, 18, 128820, {1, 3, 7, 13, 1, 1, 123, 89, 433, 541, 1579, 931, 3459, 11095, 20729, 13117, 59323, 90309}},
-{21067, 18, 128830, {1, 1, 7, 1, 19, 9, 31, 211, 271, 25, 1053, 2249, 6549, 12785, 16947, 55633, 70155, 253741}},
-{21068, 18, 128842, {1, 3, 5, 9, 7, 49, 11, 251, 101, 795, 1015, 2037, 1239, 10151, 22179, 749, 2373, 224517}},
-{21069, 18, 128852, {1, 3, 7, 15, 21, 19, 15, 59, 439, 621, 1081, 3041, 1587, 3077, 2319, 51135, 110513, 222551}},
-{21070, 18, 128859, {1, 1, 5, 5, 9, 61, 49, 97, 361, 647, 351, 1977, 3023, 10213, 6889, 8753, 72203, 37521}},
-{21071, 18, 128866, {1, 3, 3, 1, 7, 29, 51, 117, 259, 81, 1263, 1829, 6541, 5699, 30367, 61325, 78795, 3491}},
-{21072, 18, 128875, {1, 1, 1, 5, 5, 23, 19, 255, 267, 251, 239, 3561, 6771, 10647, 4129, 40285, 11041, 27023}},
-{21073, 18, 128892, {1, 1, 7, 5, 29, 17, 121, 91, 427, 51, 243, 1617, 5389, 3633, 14105, 5329, 109507, 93719}},
-{21074, 18, 128896, {1, 3, 7, 5, 7, 59, 107, 89, 181, 719, 1029, 585, 2415, 9175, 11605, 9271, 12105, 42503}},
-{21075, 18, 128914, {1, 3, 5, 15, 27, 15, 83, 223, 489, 901, 1823, 1515, 6295, 12509, 27179, 181, 29813, 66163}},
-{21076, 18, 128935, {1, 1, 7, 15, 5, 9, 79, 29, 201, 391, 609, 935, 4025, 201, 8333, 24557, 33739, 257979}},
-{21077, 18, 128964, {1, 3, 3, 9, 9, 19, 55, 211, 347, 943, 559, 467, 1363, 10249, 7109, 41293, 28035, 205889}},
-{21078, 18, 128973, {1, 1, 5, 3, 21, 25, 25, 163, 95, 119, 789, 1679, 3845, 1427, 25531, 13375, 121029, 194845}},
-{21079, 18, 129001, {1, 1, 5, 3, 31, 21, 83, 27, 17, 59, 885, 3889, 4795, 4383, 28739, 55129, 10387, 176437}},
-{21080, 18, 129007, {1, 3, 1, 5, 31, 39, 37, 79, 433, 313, 1155, 3025, 6141, 10695, 27819, 28227, 32161, 250515}},
-{21081, 18, 129012, {1, 1, 5, 9, 27, 41, 3, 129, 235, 621, 1171, 3305, 6309, 5323, 15049, 16301, 13817, 238521}},
-{21082, 18, 129021, {1, 3, 7, 7, 27, 31, 63, 143, 183, 625, 1627, 3093, 6597, 14089, 30197, 60411, 66221, 221691}},
-{21083, 18, 129026, {1, 3, 7, 13, 21, 15, 59, 67, 441, 113, 1229, 1587, 5889, 6691, 10641, 11865, 89791, 82867}},
-{21084, 18, 129055, {1, 1, 7, 9, 13, 21, 53, 145, 235, 877, 2005, 1005, 7137, 6091, 19611, 25959, 124019, 216269}},
-{21085, 18, 129071, {1, 3, 7, 9, 17, 63, 5, 245, 397, 351, 1613, 4079, 7235, 4397, 18951, 11609, 71593, 148615}},
-{21086, 18, 129093, {1, 3, 3, 11, 5, 59, 65, 221, 237, 527, 861, 397, 249, 15273, 8415, 61185, 59419, 98115}},
-{21087, 18, 129105, {1, 1, 3, 5, 5, 59, 17, 247, 3, 765, 835, 1131, 3985, 9021, 18067, 28525, 86513, 250227}},
-{21088, 18, 129124, {1, 3, 7, 15, 25, 47, 119, 143, 143, 283, 1791, 59, 8171, 12577, 17079, 9809, 100299, 63977}},
-{21089, 18, 129148, {1, 3, 5, 13, 1, 47, 93, 159, 199, 863, 1279, 77, 4719, 3623, 30713, 39271, 126299, 130297}},
-{21090, 18, 129151, {1, 1, 5, 3, 23, 11, 119, 187, 57, 373, 747, 1507, 5165, 12929, 903, 49041, 70215, 117113}},
-{21091, 18, 129155, {1, 1, 5, 1, 3, 59, 23, 77, 151, 77, 627, 2865, 7055, 10469, 12095, 20481, 13429, 47573}},
-{21092, 18, 129161, {1, 3, 1, 13, 27, 13, 115, 233, 343, 407, 1321, 4011, 5589, 15369, 23495, 4435, 75421, 229325}},
-{21093, 18, 129200, {1, 3, 3, 3, 5, 51, 89, 53, 275, 279, 203, 2829, 4415, 4735, 25417, 17633, 99445, 183945}},
-{21094, 18, 129224, {1, 3, 3, 15, 7, 9, 91, 63, 143, 945, 453, 4001, 3943, 7285, 9359, 27507, 8571, 31827}},
-{21095, 18, 129230, {1, 3, 3, 11, 15, 49, 103, 25, 273, 791, 145, 2203, 4721, 7709, 25085, 33937, 98693, 97445}},
-{21096, 18, 129237, {1, 1, 5, 15, 9, 13, 87, 27, 331, 137, 1031, 585, 7841, 12213, 32259, 46953, 17813, 203379}},
-{21097, 18, 129298, {1, 3, 1, 5, 29, 53, 121, 179, 21, 311, 991, 2145, 6577, 12889, 8763, 46629, 128093, 105033}},
-{21098, 18, 129300, {1, 3, 1, 9, 7, 29, 57, 137, 333, 109, 615, 749, 2665, 13087, 13989, 41857, 102937, 125183}},
-{21099, 18, 129316, {1, 1, 5, 5, 3, 23, 107, 5, 319, 503, 1209, 47, 349, 11681, 28521, 44707, 112887, 232275}},
-{21100, 18, 129345, {1, 3, 3, 13, 13, 51, 13, 5, 293, 15, 555, 135, 2565, 13325, 30411, 14837, 65591, 249205}},
-{21101, 18, 129351, {1, 3, 5, 13, 17, 3, 73, 255, 447, 699, 503, 3655, 7735, 12163, 6167, 15027, 103831, 146395}},
-{21102, 18, 129352, {1, 3, 1, 13, 5, 9, 27, 45, 397, 463, 1739, 3193, 6731, 7533, 11217, 22359, 82603, 231613}},
-{21103, 18, 129363, {1, 1, 3, 15, 5, 43, 73, 191, 53, 187, 1905, 745, 1571, 9013, 8515, 59527, 104671, 227063}},
-{21104, 18, 129393, {1, 1, 3, 1, 5, 47, 57, 179, 433, 979, 147, 1701, 4019, 6855, 24487, 65495, 69919, 6659}},
-{21105, 18, 129410, {1, 3, 3, 1, 17, 17, 13, 75, 163, 781, 421, 1573, 2519, 9243, 20693, 60909, 65661, 208125}},
-{21106, 18, 129415, {1, 3, 5, 7, 27, 57, 39, 79, 157, 415, 729, 3651, 3581, 9443, 6409, 45993, 99051, 140977}},
-{21107, 18, 129449, {1, 3, 3, 13, 1, 7, 109, 77, 423, 185, 97, 3719, 2355, 10593, 2421, 37339, 24961, 24305}},
-{21108, 18, 129477, {1, 3, 5, 13, 17, 7, 125, 43, 453, 43, 643, 3757, 3721, 16083, 20871, 26451, 95201, 29153}},
-{21109, 18, 129501, {1, 1, 7, 3, 13, 49, 99, 253, 59, 21, 445, 3677, 6683, 2165, 32367, 55249, 5991, 155033}},
-{21110, 18, 129518, {1, 1, 3, 9, 21, 9, 15, 219, 175, 631, 665, 2455, 4701, 10639, 13907, 26937, 58867, 259861}},
-{21111, 18, 129520, {1, 3, 5, 5, 23, 5, 39, 233, 27, 811, 1435, 625, 4703, 3699, 20763, 50047, 123875, 10129}},
-{21112, 18, 129545, {1, 1, 7, 5, 23, 1, 49, 223, 309, 691, 953, 575, 5279, 10515, 11519, 35387, 48417, 134001}},
-{21113, 18, 129563, {1, 1, 7, 11, 3, 15, 125, 109, 39, 713, 1823, 1613, 4347, 6839, 29511, 26865, 102077, 31425}},
-{21114, 18, 129594, {1, 1, 1, 7, 31, 43, 13, 221, 115, 993, 1155, 1641, 1063, 2065, 18909, 45769, 65331, 188455}},
-{21115, 18, 129608, {1, 1, 7, 13, 21, 9, 59, 7, 79, 217, 2009, 667, 7685, 14761, 20149, 44133, 41037, 78369}},
-{21116, 18, 129616, {1, 3, 1, 9, 23, 57, 1, 193, 77, 681, 1135, 3657, 8149, 3559, 25011, 55027, 121903, 240157}},
-{21117, 18, 129652, {1, 3, 3, 5, 31, 41, 59, 5, 159, 627, 1569, 23, 2311, 2239, 20811, 54931, 130949, 193071}},
-{21118, 18, 129659, {1, 1, 1, 1, 27, 45, 43, 1, 381, 801, 451, 1361, 1611, 5379, 27819, 8949, 4953, 222335}},
-{21119, 18, 129680, {1, 1, 7, 7, 7, 11, 101, 17, 197, 561, 297, 159, 7443, 7273, 819, 23487, 24927, 151781}},
-{21120, 18, 129692, {1, 3, 1, 3, 15, 43, 119, 193, 205, 835, 7, 689, 8045, 11167, 19521, 65075, 87265, 53669}},
-{21121, 18, 129738, {1, 3, 7, 7, 9, 51, 43, 209, 239, 415, 995, 4037, 1219, 2683, 30459, 36161, 111157, 184551}},
-{21122, 18, 129764, {1, 3, 7, 11, 27, 3, 81, 43, 407, 463, 231, 3545, 2691, 5235, 22053, 37233, 98757, 149111}},
-{21123, 18, 129782, {1, 3, 1, 5, 17, 25, 47, 185, 487, 403, 1063, 1445, 4457, 15443, 11693, 54823, 131001, 9813}},
-{21124, 18, 129793, {1, 3, 5, 3, 5, 35, 127, 253, 173, 491, 133, 3575, 1981, 12735, 26021, 61615, 74615, 159829}},
-{21125, 18, 129820, {1, 1, 5, 9, 13, 37, 67, 155, 317, 389, 603, 4061, 3527, 9315, 32331, 43145, 82511, 240133}},
-{21126, 18, 129824, {1, 1, 5, 1, 21, 41, 89, 3, 61, 627, 1301, 2073, 447, 8139, 2509, 52075, 50687, 240239}},
-{21127, 18, 129829, {1, 3, 7, 13, 25, 61, 117, 107, 175, 7, 1173, 561, 5777, 10525, 20713, 34987, 48005, 214361}},
-{21128, 18, 129848, {1, 3, 7, 15, 25, 31, 127, 147, 177, 881, 95, 2115, 4765, 10485, 9253, 721, 193, 222459}},
-{21129, 18, 129854, {1, 3, 5, 3, 3, 13, 47, 77, 441, 1001, 215, 2365, 3603, 405, 11401, 14523, 65755, 258229}},
-{21130, 18, 129861, {1, 1, 3, 9, 19, 29, 71, 153, 77, 613, 1815, 2033, 1821, 15497, 18805, 28851, 88247, 143115}},
-{21131, 18, 129879, {1, 3, 1, 11, 21, 19, 37, 35, 427, 887, 1977, 1961, 3619, 10739, 30115, 55937, 102045, 110929}},
-{21132, 18, 129886, {1, 3, 3, 13, 21, 27, 49, 15, 405, 629, 2015, 867, 2121, 13789, 19225, 22343, 105629, 123113}},
-{21133, 18, 129907, {1, 1, 1, 1, 17, 19, 55, 207, 507, 1001, 1753, 315, 2799, 8643, 1519, 4057, 16599, 222223}},
-{21134, 18, 129949, {1, 1, 5, 7, 21, 37, 63, 53, 103, 261, 595, 389, 6041, 11127, 23625, 61683, 80953, 255891}},
-{21135, 18, 129953, {1, 1, 1, 5, 25, 21, 81, 233, 79, 57, 1311, 3965, 7747, 687, 32149, 397, 4551, 37657}},
-{21136, 18, 129980, {1, 1, 1, 5, 9, 19, 87, 67, 325, 157, 317, 591, 1401, 8275, 20413, 39529, 75349, 183679}},
-{21137, 18, 129998, {1, 3, 3, 15, 9, 3, 83, 205, 195, 599, 829, 3109, 3705, 13991, 8781, 41555, 31689, 86933}},
-{21138, 18, 130031, {1, 3, 5, 1, 3, 9, 37, 235, 271, 883, 561, 1473, 7693, 177, 14113, 19507, 75221, 67517}},
-{21139, 18, 130043, {1, 1, 1, 9, 7, 29, 87, 189, 239, 429, 537, 1657, 6373, 2449, 17621, 19649, 77235, 102775}},
-{21140, 18, 130057, {1, 1, 7, 7, 1, 43, 69, 207, 241, 561, 1809, 3119, 4657, 15797, 18751, 52169, 105005, 172657}},
-{21141, 18, 130065, {1, 1, 7, 5, 5, 59, 67, 231, 27, 435, 1073, 2689, 229, 733, 1579, 52289, 110285, 76721}},
-{21142, 18, 130087, {1, 3, 5, 9, 31, 19, 87, 41, 489, 705, 1363, 963, 5865, 8237, 10295, 43169, 81561, 177209}},
-{21143, 18, 130091, {1, 3, 3, 1, 25, 39, 63, 255, 403, 625, 1601, 71, 6609, 4165, 21987, 31269, 25473, 17063}},
-{21144, 18, 130096, {1, 3, 3, 11, 19, 13, 101, 245, 17, 687, 1037, 3345, 7257, 13081, 5131, 29003, 72319, 223505}},
-{21145, 18, 130101, {1, 3, 3, 3, 11, 49, 107, 29, 463, 465, 977, 4007, 2121, 4821, 1465, 53725, 36783, 247057}},
-{21146, 18, 130111, {1, 1, 1, 3, 1, 43, 71, 49, 261, 965, 1041, 3951, 3791, 2503, 26009, 52039, 4639, 141281}},
-{21147, 18, 130126, {1, 1, 3, 5, 29, 45, 79, 33, 119, 491, 1403, 1637, 853, 5609, 29853, 16435, 117877, 58443}},
-{21148, 18, 130137, {1, 1, 3, 5, 13, 17, 109, 187, 201, 705, 235, 1485, 7673, 6335, 3341, 20451, 64697, 129519}},
-{21149, 18, 130138, {1, 1, 7, 13, 11, 41, 95, 81, 135, 783, 1293, 2095, 3599, 10175, 3205, 56915, 131, 19281}},
-{21150, 18, 130149, {1, 3, 5, 9, 13, 19, 53, 223, 283, 733, 1915, 3029, 2779, 8133, 28163, 37263, 91245, 1927}},
-{21151, 18, 130177, {1, 3, 3, 3, 1, 55, 41, 123, 209, 195, 1423, 2467, 3809, 11169, 23593, 8703, 40975, 175651}},
-{21152, 18, 130180, {1, 3, 7, 9, 31, 57, 31, 115, 415, 445, 557, 3971, 1565, 15223, 7799, 10463, 117387, 225127}},
-{21153, 18, 130214, {1, 3, 5, 11, 31, 19, 3, 63, 315, 501, 903, 1925, 3393, 16149, 11013, 15483, 70765, 279}},
-{21154, 18, 130228, {1, 3, 3, 9, 29, 21, 13, 227, 263, 815, 1259, 2549, 955, 9237, 16083, 38891, 31145, 731}},
-{21155, 18, 130240, {1, 3, 3, 5, 27, 23, 33, 189, 107, 655, 889, 1549, 7315, 13341, 12721, 59339, 54503, 91679}},
-{21156, 18, 130267, {1, 3, 7, 5, 15, 9, 1, 255, 451, 91, 1279, 2359, 5913, 5215, 23161, 29327, 45275, 206709}},
-{21157, 18, 130280, {1, 3, 3, 9, 9, 41, 75, 91, 87, 695, 335, 3375, 7307, 14095, 5359, 7815, 9339, 46387}},
-{21158, 18, 130294, {1, 1, 3, 15, 5, 47, 69, 231, 423, 255, 1335, 3395, 2799, 8955, 31445, 59849, 104955, 240587}},
-{21159, 18, 130306, {1, 3, 5, 7, 7, 9, 21, 209, 321, 5, 653, 2199, 3657, 6397, 20229, 32349, 54543, 47971}},
-{21160, 18, 130325, {1, 3, 7, 11, 31, 21, 85, 49, 197, 865, 53, 609, 1867, 14503, 12671, 61703, 39245, 8493}},
-{21161, 18, 130398, {1, 3, 1, 13, 27, 31, 119, 247, 209, 65, 1729, 1563, 1597, 1617, 26597, 50139, 108667, 77035}},
-{21162, 18, 130402, {1, 1, 5, 13, 3, 49, 53, 219, 71, 1013, 1239, 3725, 117, 9273, 8277, 32619, 45933, 71509}},
-{21163, 18, 130421, {1, 3, 7, 13, 1, 3, 119, 153, 79, 555, 429, 1221, 3725, 6073, 1295, 7187, 117709, 258911}},
-{21164, 18, 130438, {1, 3, 3, 13, 1, 13, 105, 185, 81, 989, 563, 3761, 6725, 4699, 10539, 50247, 95307, 211927}},
-{21165, 18, 130441, {1, 3, 7, 3, 21, 11, 45, 81, 495, 391, 1437, 3495, 3789, 13701, 9479, 42505, 22561, 135019}},
-{21166, 18, 130475, {1, 3, 3, 11, 7, 61, 65, 211, 269, 997, 385, 3843, 4905, 2939, 28551, 19515, 25177, 68137}},
-{21167, 18, 130486, {1, 1, 3, 3, 3, 47, 73, 127, 15, 977, 209, 1791, 4711, 6733, 29093, 36311, 13665, 240603}},
-{21168, 18, 130503, {1, 3, 5, 5, 19, 39, 29, 211, 463, 755, 1723, 397, 213, 14009, 22701, 7131, 35587, 183885}},
-{21169, 18, 130551, {1, 3, 5, 9, 11, 29, 7, 25, 381, 631, 1343, 2255, 2535, 3239, 7287, 14161, 69295, 85245}},
-{21170, 18, 130574, {1, 1, 5, 5, 17, 47, 19, 217, 289, 411, 1855, 323, 4109, 2601, 5835, 61909, 99333, 99959}},
-{21171, 18, 130602, {1, 1, 3, 11, 1, 51, 121, 207, 403, 993, 1171, 3451, 3389, 957, 22125, 9333, 110775, 54125}},
-{21172, 18, 130612, {1, 3, 5, 15, 9, 51, 13, 251, 203, 861, 321, 2017, 6933, 10785, 20089, 65213, 105451, 117319}},
-{21173, 18, 130621, {1, 3, 3, 15, 19, 63, 89, 217, 269, 723, 57, 1923, 4267, 4895, 2191, 21605, 62401, 11063}},
-{21174, 18, 130633, {1, 3, 1, 3, 21, 47, 103, 75, 167, 989, 1401, 575, 3717, 10373, 21321, 5487, 36063, 140411}},
-{21175, 18, 130684, {1, 1, 7, 15, 19, 29, 121, 197, 429, 773, 901, 1875, 291, 11395, 31459, 55041, 49263, 185143}},
-{21176, 18, 130688, {1, 3, 3, 1, 19, 17, 19, 21, 41, 885, 1665, 547, 5887, 6205, 3317, 59399, 125559, 82721}},
-{21177, 18, 130698, {1, 3, 1, 9, 15, 39, 81, 9, 279, 33, 1287, 3035, 5759, 10647, 3933, 20953, 3137, 30693}},
-{21178, 18, 130700, {1, 3, 5, 13, 3, 33, 33, 169, 233, 83, 467, 3719, 5617, 6165, 15631, 56059, 95541, 245233}},
-{21179, 18, 130712, {1, 3, 5, 13, 5, 21, 81, 9, 413, 247, 1307, 3363, 3383, 11525, 1259, 8735, 36507, 98359}},
-{21180, 18, 130739, {1, 1, 1, 13, 17, 49, 105, 131, 385, 309, 1295, 565, 8031, 15391, 31263, 52657, 102721, 212195}},
-{21181, 18, 130748, {1, 3, 1, 7, 13, 41, 21, 103, 237, 649, 55, 1565, 6327, 8743, 15457, 29975, 34165, 80839}},
-{21182, 18, 130774, {1, 3, 5, 11, 15, 31, 121, 219, 375, 159, 731, 59, 3205, 15039, 10023, 46209, 34619, 110253}},
-{21183, 18, 130783, {1, 3, 3, 11, 31, 19, 79, 185, 363, 635, 463, 987, 2681, 6405, 30077, 21173, 14213, 58095}},
-{21184, 18, 130802, {1, 1, 5, 13, 23, 37, 57, 111, 293, 553, 269, 3393, 345, 1983, 1097, 47217, 22281, 212607}},
-{21185, 18, 130811, {1, 3, 5, 7, 7, 33, 65, 61, 185, 411, 187, 641, 6437, 4625, 17547, 38941, 81119, 48651}},
-{21186, 18, 130836, {1, 1, 7, 3, 19, 25, 39, 243, 139, 465, 691, 713, 7879, 14539, 31669, 35871, 130681, 255929}},
-{21187, 18, 130840, {1, 3, 1, 1, 3, 43, 87, 13, 179, 835, 719, 1189, 7207, 5863, 6077, 20669, 35469, 211155}},
-{21188, 18, 130856, {1, 3, 7, 13, 25, 59, 97, 129, 151, 985, 739, 1919, 7729, 14057, 21721, 17603, 82797, 181319}},
-{21189, 18, 130864, {1, 1, 7, 7, 5, 3, 21, 141, 379, 257, 207, 597, 4051, 7563, 25481, 59427, 45449, 61159}},
-{21190, 18, 130873, {1, 3, 3, 9, 11, 25, 5, 29, 131, 603, 637, 189, 4033, 13099, 15219, 4447, 73501, 135795}},
-{21191, 18, 130918, {1, 3, 1, 9, 1, 49, 57, 227, 141, 543, 1499, 3525, 3127, 11191, 4071, 47003, 7431, 155137}},
-{21192, 18, 130927, {1, 3, 1, 11, 27, 31, 15, 31, 113, 135, 1251, 245, 6965, 14263, 5679, 55201, 121453, 132503}},
-{21193, 18, 130929, {1, 1, 5, 15, 7, 23, 67, 163, 57, 513, 1809, 1343, 6165, 199, 31169, 30803, 86705, 71103}},
-{21194, 18, 130958, {1, 1, 3, 1, 15, 9, 75, 143, 273, 797, 819, 4037, 2305, 4841, 15697, 41191, 38187, 174131}},
-{21195, 18, 130966, {1, 3, 7, 7, 3, 55, 65, 135, 423, 185, 299, 2221, 7987, 4223, 28183, 32273, 95941, 260297}},
-{21196, 18, 130970, {1, 1, 7, 7, 7, 11, 67, 109, 507, 673, 1555, 2537, 7553, 4659, 3945, 20839, 32539, 43053}},
-{21197, 18, 130976, {1, 1, 7, 15, 1, 47, 61, 73, 211, 397, 1785, 4063, 6461, 13725, 11299, 17565, 80063, 118271}},
-{21198, 18, 131006, {1, 1, 7, 5, 29, 27, 97, 105, 379, 153, 915, 2795, 4933, 6729, 21207, 9995, 70241, 85641}},
-{21199, 18, 131008, {1, 3, 5, 5, 23, 13, 41, 67, 127, 649, 1351, 3597, 7077, 4989, 14649, 17401, 70883, 239841}},
-{21200, 18, 131020, {1, 1, 5, 1, 19, 1, 83, 3, 425, 873, 1943, 3935, 4257, 14587, 11829, 55217, 21963, 39683}},
-{21201, 18, 131059, {1, 1, 7, 11, 15, 7, 37, 239, 337, 245, 1557, 3681, 7357, 9639, 27367, 26869, 114603, 86317}}
-};
-/* clang-format on */
-
-void sobol_generate_direction_vectors(uint vectors[][SOBOL_BITS], int dimensions)
-{
- assert(dimensions <= SOBOL_MAX_DIMENSIONS);
-
- const uint L = SOBOL_BITS;
-
- /* first dimension is exception */
- uint *v = vectors[0];
-
- for (uint i = 0; i < L; i++)
- v[i] = 1 << (31 - i); // all m's = 1
-
- for (int dim = 1; dim < dimensions; dim++) {
- const SobolDirectionNumbers *numbers = &SOBOL_NUMBERS[dim - 1];
- const uint s = numbers->s;
- const uint a = numbers->a;
- const uint *m = numbers->m;
-
- v = vectors[dim];
-
- if (L <= s) {
- for (uint i = 0; i < L; i++)
- v[i] = m[i] << (31 - i);
- }
- else {
- for (uint i = 0; i < s; i++)
- v[i] = m[i] << (31 - i);
-
- for (uint i = s; i < L; i++) {
- v[i] = v[i - s] ^ (v[i - s] >> s);
-
- for (uint k = 1; k < s; k++)
- v[i] ^= (((a >> (s - 1 - k)) & 1) * v[i - k]);
- }
- }
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/sobol.h b/intern/cycles/render/sobol.h
deleted file mode 100644
index d38857d2b35..00000000000
--- a/intern/cycles/render/sobol.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SOBOL_H__
-#define __SOBOL_H__
-
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-#define SOBOL_BITS 32
-#define SOBOL_MAX_DIMENSIONS 21201
-
-void sobol_generate_direction_vectors(uint vectors[][SOBOL_BITS], int dimensions);
-
-CCL_NAMESPACE_END
-
-#endif /* __SOBOL_H__ */
diff --git a/intern/cycles/render/stats.cpp b/intern/cycles/render/stats.cpp
deleted file mode 100644
index 73eb7e21ff9..00000000000
--- a/intern/cycles/render/stats.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/stats.h"
-#include "render/object.h"
-#include "util/util_algorithm.h"
-#include "util/util_foreach.h"
-#include "util/util_string.h"
-
-CCL_NAMESPACE_BEGIN
-
-static int kIndentNumSpaces = 2;
-
-/* Named size entry. */
-
-namespace {
-
-bool namedSizeEntryComparator(const NamedSizeEntry &a, const NamedSizeEntry &b)
-{
- /* We sort in descending order. */
- return a.size > b.size;
-}
-
-bool namedTimeEntryComparator(const NamedTimeEntry &a, const NamedTimeEntry &b)
-{
- /* We sort in descending order. */
- return a.time > b.time;
-}
-
-bool namedTimeSampleEntryComparator(const NamedNestedSampleStats &a,
- const NamedNestedSampleStats &b)
-{
- return a.sum_samples > b.sum_samples;
-}
-
-bool namedSampleCountPairComparator(const NamedSampleCountPair &a, const NamedSampleCountPair &b)
-{
- return a.samples > b.samples;
-}
-
-} // namespace
-
-NamedSizeEntry::NamedSizeEntry() : name(""), size(0)
-{
-}
-
-NamedSizeEntry::NamedSizeEntry(const string &name, size_t size) : name(name), size(size)
-{
-}
-
-NamedTimeEntry::NamedTimeEntry() : name(""), time(0)
-{
-}
-
-NamedTimeEntry::NamedTimeEntry(const string &name, double time) : name(name), time(time)
-{
-}
-
-/* Named size statistics. */
-
-NamedSizeStats::NamedSizeStats() : total_size(0)
-{
-}
-
-void NamedSizeStats::add_entry(const NamedSizeEntry &entry)
-{
- total_size += entry.size;
- entries.push_back(entry);
-}
-
-string NamedSizeStats::full_report(int indent_level)
-{
- const string indent(indent_level * kIndentNumSpaces, ' ');
- const string double_indent = indent + indent;
- string result = "";
- result += string_printf("%sTotal memory: %s (%s)\n",
- indent.c_str(),
- string_human_readable_size(total_size).c_str(),
- string_human_readable_number(total_size).c_str());
- sort(entries.begin(), entries.end(), namedSizeEntryComparator);
- foreach (const NamedSizeEntry &entry, entries) {
- result += string_printf("%s%-32s %s (%s)\n",
- double_indent.c_str(),
- entry.name.c_str(),
- string_human_readable_size(entry.size).c_str(),
- string_human_readable_number(entry.size).c_str());
- }
- return result;
-}
-
-string NamedTimeStats::full_report(int indent_level)
-{
- const string indent(indent_level * kIndentNumSpaces, ' ');
- const string double_indent = indent + indent;
- string result = "";
- result += string_printf("%sTotal time: %fs\n", indent.c_str(), total_time);
- sort(entries.begin(), entries.end(), namedTimeEntryComparator);
- foreach (const NamedTimeEntry &entry, entries) {
- result += string_printf(
- "%s%-40s %fs\n", double_indent.c_str(), entry.name.c_str(), entry.time);
- }
- return result;
-}
-
-/* Named time sample statistics. */
-
-NamedNestedSampleStats::NamedNestedSampleStats() : name(""), self_samples(0), sum_samples(0)
-{
-}
-
-NamedNestedSampleStats::NamedNestedSampleStats(const string &name, uint64_t samples)
- : name(name), self_samples(samples), sum_samples(samples)
-{
-}
-
-NamedNestedSampleStats &NamedNestedSampleStats::add_entry(const string &name_, uint64_t samples_)
-{
- entries.push_back(NamedNestedSampleStats(name_, samples_));
- return entries[entries.size() - 1];
-}
-
-void NamedNestedSampleStats::update_sum()
-{
- sum_samples = self_samples;
- foreach (NamedNestedSampleStats &entry, entries) {
- entry.update_sum();
- sum_samples += entry.sum_samples;
- }
-}
-
-string NamedNestedSampleStats::full_report(int indent_level, uint64_t total_samples)
-{
- update_sum();
-
- if (total_samples == 0) {
- total_samples = sum_samples;
- }
-
- const string indent(indent_level * kIndentNumSpaces, ' ');
-
- const double sum_percent = 100 * ((double)sum_samples) / total_samples;
- const double sum_seconds = sum_samples * 0.001;
- const double self_percent = 100 * ((double)self_samples) / total_samples;
- const double self_seconds = self_samples * 0.001;
- string info = string_printf("%-32s: Total %3.2f%% (%.2fs), Self %3.2f%% (%.2fs)\n",
- name.c_str(),
- sum_percent,
- sum_seconds,
- self_percent,
- self_seconds);
- string result = indent + info;
-
- sort(entries.begin(), entries.end(), namedTimeSampleEntryComparator);
- foreach (NamedNestedSampleStats &entry, entries) {
- result += entry.full_report(indent_level + 1, total_samples);
- }
- return result;
-}
-
-/* Named sample count pairs. */
-
-NamedSampleCountPair::NamedSampleCountPair(const ustring &name, uint64_t samples, uint64_t hits)
- : name(name), samples(samples), hits(hits)
-{
-}
-
-NamedSampleCountStats::NamedSampleCountStats()
-{
-}
-
-void NamedSampleCountStats::add(const ustring &name, uint64_t samples, uint64_t hits)
-{
- entry_map::iterator entry = entries.find(name);
- if (entry != entries.end()) {
- entry->second.samples += samples;
- entry->second.hits += hits;
- return;
- }
- entries.emplace(name, NamedSampleCountPair(name, samples, hits));
-}
-
-string NamedSampleCountStats::full_report(int indent_level)
-{
- const string indent(indent_level * kIndentNumSpaces, ' ');
-
- vector<NamedSampleCountPair> sorted_entries;
- sorted_entries.reserve(entries.size());
-
- uint64_t total_hits = 0, total_samples = 0;
- foreach (entry_map::const_reference entry, entries) {
- const NamedSampleCountPair &pair = entry.second;
-
- total_hits += pair.hits;
- total_samples += pair.samples;
-
- sorted_entries.push_back(pair);
- }
- const double avg_samples_per_hit = ((double)total_samples) / total_hits;
-
- sort(sorted_entries.begin(), sorted_entries.end(), namedSampleCountPairComparator);
-
- string result = "";
- foreach (const NamedSampleCountPair &entry, sorted_entries) {
- const double seconds = entry.samples * 0.001;
- const double relative = ((double)entry.samples) / (entry.hits * avg_samples_per_hit);
-
- result += indent +
- string_printf(
- "%-32s: %.2fs (Relative cost: %.2f)\n", entry.name.c_str(), seconds, relative);
- }
- return result;
-}
-
-/* Mesh statistics. */
-
-MeshStats::MeshStats()
-{
-}
-
-string MeshStats::full_report(int indent_level)
-{
- const string indent(indent_level * kIndentNumSpaces, ' ');
- string result = "";
- result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1);
- return result;
-}
-
-/* Image statistics. */
-
-ImageStats::ImageStats()
-{
-}
-
-string ImageStats::full_report(int indent_level)
-{
- const string indent(indent_level * kIndentNumSpaces, ' ');
- string result = "";
- result += indent + "Textures:\n" + textures.full_report(indent_level + 1);
- return result;
-}
-
-/* Overall statistics. */
-
-RenderStats::RenderStats()
-{
- has_profiling = false;
-}
-
-void RenderStats::collect_profiling(Scene *scene, Profiler &prof)
-{
- has_profiling = true;
-
- kernel = NamedNestedSampleStats("Total render time", prof.get_event(PROFILING_UNKNOWN));
- kernel.add_entry("Ray setup", prof.get_event(PROFILING_RAY_SETUP));
- kernel.add_entry("Intersect Closest", prof.get_event(PROFILING_INTERSECT_CLOSEST));
- kernel.add_entry("Intersect Shadow", prof.get_event(PROFILING_INTERSECT_SHADOW));
- kernel.add_entry("Intersect Subsurface", prof.get_event(PROFILING_INTERSECT_SUBSURFACE));
- kernel.add_entry("Intersect Volume Stack", prof.get_event(PROFILING_INTERSECT_VOLUME_STACK));
-
- NamedNestedSampleStats &surface = kernel.add_entry("Shade Surface", 0);
- surface.add_entry("Setup", prof.get_event(PROFILING_SHADE_SURFACE_SETUP));
- surface.add_entry("Shader Evaluation", prof.get_event(PROFILING_SHADE_SURFACE_EVAL));
- surface.add_entry("Render Passes", prof.get_event(PROFILING_SHADE_SURFACE_PASSES));
- surface.add_entry("Direct Light", prof.get_event(PROFILING_SHADE_SURFACE_DIRECT_LIGHT));
- surface.add_entry("Indirect Light", prof.get_event(PROFILING_SHADE_SURFACE_INDIRECT_LIGHT));
- surface.add_entry("Ambient Occlusion", prof.get_event(PROFILING_SHADE_SURFACE_AO));
-
- NamedNestedSampleStats &volume = kernel.add_entry("Shade Volume", 0);
- volume.add_entry("Setup", prof.get_event(PROFILING_SHADE_VOLUME_SETUP));
- volume.add_entry("Integrate", prof.get_event(PROFILING_SHADE_VOLUME_INTEGRATE));
- volume.add_entry("Direct Light", prof.get_event(PROFILING_SHADE_VOLUME_DIRECT_LIGHT));
- volume.add_entry("Indirect Light", prof.get_event(PROFILING_SHADE_VOLUME_INDIRECT_LIGHT));
-
- NamedNestedSampleStats &shadow = kernel.add_entry("Shade Shadow", 0);
- shadow.add_entry("Setup", prof.get_event(PROFILING_SHADE_SHADOW_SETUP));
- shadow.add_entry("Surface", prof.get_event(PROFILING_SHADE_SHADOW_SURFACE));
- shadow.add_entry("Volume", prof.get_event(PROFILING_SHADE_SHADOW_VOLUME));
-
- NamedNestedSampleStats &light = kernel.add_entry("Shade Light", 0);
- light.add_entry("Setup", prof.get_event(PROFILING_SHADE_LIGHT_SETUP));
- light.add_entry("Shader Evaluation", prof.get_event(PROFILING_SHADE_LIGHT_EVAL));
-
- shaders.entries.clear();
- foreach (Shader *shader, scene->shaders) {
- uint64_t samples, hits;
- if (prof.get_shader(shader->id, samples, hits)) {
- shaders.add(shader->name, samples, hits);
- }
- }
-
- objects.entries.clear();
- foreach (Object *object, scene->objects) {
- uint64_t samples, hits;
- if (prof.get_object(object->get_device_index(), samples, hits)) {
- objects.add(object->name, samples, hits);
- }
- }
-}
-
-string RenderStats::full_report()
-{
- string result = "";
- result += "Mesh statistics:\n" + mesh.full_report(1);
- result += "Image statistics:\n" + image.full_report(1);
- if (has_profiling) {
- result += "Kernel statistics:\n" + kernel.full_report(1);
- result += "Shader statistics:\n" + shaders.full_report(1);
- result += "Object statistics:\n" + objects.full_report(1);
- }
- else {
- result += "Profiling information not available (only works with CPU rendering)";
- }
- return result;
-}
-
-NamedTimeStats::NamedTimeStats() : total_time(0.0)
-{
-}
-
-string UpdateTimeStats::full_report(int indent_level)
-{
- return times.full_report(indent_level + 1);
-}
-
-SceneUpdateStats::SceneUpdateStats()
-{
-}
-
-string SceneUpdateStats::full_report()
-{
- string result = "";
- result += "Scene:\n" + scene.full_report(1);
- result += "Geometry:\n" + geometry.full_report(1);
- result += "Light:\n" + light.full_report(1);
- result += "Object:\n" + object.full_report(1);
- result += "Image:\n" + image.full_report(1);
- result += "Background:\n" + background.full_report(1);
- result += "Bake:\n" + bake.full_report(1);
- result += "Camera:\n" + camera.full_report(1);
- result += "Film:\n" + film.full_report(1);
- result += "Integrator:\n" + integrator.full_report(1);
- result += "OSL:\n" + osl.full_report(1);
- result += "Particles:\n" + particles.full_report(1);
- result += "SVM:\n" + svm.full_report(1);
- result += "Tables:\n" + tables.full_report(1);
- result += "Procedurals:\n" + procedurals.full_report(1);
- return result;
-}
-
-void SceneUpdateStats::clear()
-{
- geometry.times.clear();
- image.times.clear();
- light.times.clear();
- object.times.clear();
- background.times.clear();
- bake.times.clear();
- camera.times.clear();
- film.times.clear();
- integrator.times.clear();
- osl.times.clear();
- particles.times.clear();
- scene.times.clear();
- svm.times.clear();
- tables.times.clear();
- procedurals.times.clear();
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/stats.h b/intern/cycles/render/stats.h
deleted file mode 100644
index 93d029bba61..00000000000
--- a/intern/cycles/render/stats.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __RENDER_STATS_H__
-#define __RENDER_STATS_H__
-
-#include "render/scene.h"
-
-#include "util/util_stats.h"
-#include "util/util_string.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Named statistics entry, which corresponds to a size. There is no real
- * semantic around the units of size, it just should be the same for all
- * entries.
- *
- * This is a generic entry for all size-related statistics, which helps
- * avoiding duplicating code for things like sorting.
- */
-class NamedSizeEntry {
- public:
- NamedSizeEntry();
- NamedSizeEntry(const string &name, size_t size);
-
- string name;
- size_t size;
-};
-
-class NamedTimeEntry {
- public:
- NamedTimeEntry();
- NamedTimeEntry(const string &name, double time);
-
- string name;
- double time;
-};
-
-/* Container of named size entries. Used, for example, to store per-mesh memory
- * usage statistics. But also keeps track of overall memory usage of the
- * container.
- */
-class NamedSizeStats {
- public:
- NamedSizeStats();
-
- /* Add entry to the statistics. */
- void add_entry(const NamedSizeEntry &entry);
-
- /* Generate full human-readable report. */
- string full_report(int indent_level = 0);
-
- /* Total size of all entries. */
- size_t total_size;
-
- /* NOTE: Is fine to read directly, but for adding use add_entry(), which
- * makes sure all accumulating values are properly updated.
- */
- vector<NamedSizeEntry> entries;
-};
-
-class NamedTimeStats {
- public:
- NamedTimeStats();
-
- /* Add entry to the statistics. */
- void add_entry(const NamedTimeEntry &entry)
- {
- total_time += entry.time;
- entries.push_back(entry);
- }
-
- /* Generate full human-readable report. */
- string full_report(int indent_level = 0);
-
- /* Total time of all entries. */
- double total_time;
-
- /* NOTE: Is fine to read directly, but for adding use add_entry(), which
- * makes sure all accumulating values are properly updated.
- */
- vector<NamedTimeEntry> entries;
-
- void clear()
- {
- total_time = 0.0;
- entries.clear();
- }
-};
-
-class NamedNestedSampleStats {
- public:
- NamedNestedSampleStats();
- NamedNestedSampleStats(const string &name, uint64_t samples);
-
- NamedNestedSampleStats &add_entry(const string &name, uint64_t samples);
-
- /* Updates sum_samples recursively. */
- void update_sum();
-
- string full_report(int indent_level = 0, uint64_t total_samples = 0);
-
- string name;
-
- /* self_samples contains only the samples that this specific event got,
- * while sum_samples also includes the samples of all sub-entries. */
- uint64_t self_samples, sum_samples;
-
- vector<NamedNestedSampleStats> entries;
-};
-
-/* Named entry containing both a time-sample count for objects of a type and a
- * total count of processed items.
- * This allows to estimate the time spent per item. */
-class NamedSampleCountPair {
- public:
- NamedSampleCountPair(const ustring &name, uint64_t samples, uint64_t hits);
-
- ustring name;
- uint64_t samples;
- uint64_t hits;
-};
-
-/* Contains statistics about pairs of samples and counts as described above. */
-class NamedSampleCountStats {
- public:
- NamedSampleCountStats();
-
- string full_report(int indent_level = 0);
- void add(const ustring &name, uint64_t samples, uint64_t hits);
-
- typedef unordered_map<ustring, NamedSampleCountPair, ustringHash> entry_map;
- entry_map entries;
-};
-
-/* Statistics about mesh in the render database. */
-class MeshStats {
- public:
- MeshStats();
-
- /* Generate full human-readable report. */
- string full_report(int indent_level = 0);
-
- /* Input geometry statistics, this is what is coming as an input to render
- * from. say, Blender. This does not include runtime or engine specific
- * memory like BVH.
- */
- NamedSizeStats geometry;
-};
-
-/* Statistics about images held in memory. */
-class ImageStats {
- public:
- ImageStats();
-
- /* Generate full human-readable report. */
- string full_report(int indent_level = 0);
-
- NamedSizeStats textures;
-};
-
-/* Render process statistics. */
-class RenderStats {
- public:
- RenderStats();
-
- /* Return full report as string. */
- string full_report();
-
- /* Collect kernel sampling information from Stats. */
- void collect_profiling(Scene *scene, Profiler &prof);
-
- bool has_profiling;
-
- MeshStats mesh;
- ImageStats image;
- NamedNestedSampleStats kernel;
- NamedSampleCountStats shaders;
- NamedSampleCountStats objects;
-};
-
-class UpdateTimeStats {
- public:
- /* Generate full human-readable report. */
- string full_report(int indent_level = 0);
-
- NamedTimeStats times;
-};
-
-class SceneUpdateStats {
- public:
- SceneUpdateStats();
-
- UpdateTimeStats geometry;
- UpdateTimeStats image;
- UpdateTimeStats light;
- UpdateTimeStats object;
- UpdateTimeStats background;
- UpdateTimeStats bake;
- UpdateTimeStats camera;
- UpdateTimeStats film;
- UpdateTimeStats integrator;
- UpdateTimeStats osl;
- UpdateTimeStats particles;
- UpdateTimeStats scene;
- UpdateTimeStats svm;
- UpdateTimeStats tables;
- UpdateTimeStats procedurals;
-
- string full_report();
-
- void clear();
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __RENDER_STATS_H__ */
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
deleted file mode 100644
index a670ceb3ea3..00000000000
--- a/intern/cycles/render/svm.cpp
+++ /dev/null
@@ -1,999 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "device/device.h"
-
-#include "render/background.h"
-#include "render/graph.h"
-#include "render/light.h"
-#include "render/mesh.h"
-#include "render/nodes.h"
-#include "render/scene.h"
-#include "render/shader.h"
-#include "render/stats.h"
-#include "render/svm.h"
-
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
-#include "util/util_task.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Shader Manager */
-
-SVMShaderManager::SVMShaderManager()
-{
-}
-
-SVMShaderManager::~SVMShaderManager()
-{
-}
-
-void SVMShaderManager::reset(Scene * /*scene*/)
-{
-}
-
-static void host_compile_shader(Scene *scene,
- Shader *shader,
- Progress *progress,
- array<int4> *svm_nodes)
-{
- if (progress->get_cancel()) {
- return;
- }
- assert(shader->graph);
-
- svm_nodes->push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
-
- SVMCompiler::Summary summary;
- SVMCompiler compiler(scene);
- compiler.background = (shader == scene->background->get_shader(scene));
- compiler.compile(shader, *svm_nodes, 0, &summary);
-
- VLOG(2) << "Compilation summary:\n"
- << "Shader name: " << shader->name << "\n"
- << summary.full_report();
-}
-
-void SVMShaderManager::host_update_specific(Scene *scene, Progress &progress)
-{
- if (!need_update()) {
- return;
- }
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->svm.times.add_entry({"host_update", time});
- }
- });
-
- const int num_shaders = scene->shaders.size();
-
- VLOG(1) << "Total " << num_shaders << " shaders.";
-
- /* Build all shaders. */
- TaskPool task_pool;
- shader_svm_nodes_.resize(num_shaders);
- for (int i = 0; i < num_shaders; i++) {
- task_pool.push(function_bind(
- host_compile_shader, scene, scene->shaders[i], &progress, &shader_svm_nodes_[i]));
- }
- task_pool.wait_work();
-}
-
-void SVMShaderManager::device_update_specific(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress)
-{
- if (!need_update())
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->svm.times.add_entry({"device_update", time});
- }
- });
-
- const int num_shaders = scene->shaders.size();
-
- VLOG(1) << "Total " << num_shaders << " shaders.";
-
- double start_time = time_dt();
-
- /* test if we need to update */
- device_free(device, dscene, scene);
-
- if (progress.get_cancel()) {
- return;
- }
-
- /* The global node list contains a jump table (one node per shader)
- * followed by the nodes of all shaders. */
- int svm_nodes_size = num_shaders;
- for (int i = 0; i < num_shaders; i++) {
- /* Since we're not copying the local jump node, the size ends up being one node lower. */
- svm_nodes_size += shader_svm_nodes_[i].size() - 1;
- }
-
- int4 *svm_nodes = dscene->svm_nodes.alloc(svm_nodes_size);
-
- int node_offset = num_shaders;
- for (int i = 0; i < num_shaders; i++) {
- Shader *shader = scene->shaders[i];
-
- shader->clear_modified();
- if (shader->get_use_mis() && shader->has_surface_emission) {
- scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
- }
-
- /* Update the global jump table.
- * Each compiled shader starts with a jump node that has offsets local
- * to the shader, so copy those and add the offset into the global node list. */
- int4 &global_jump_node = svm_nodes[shader->id];
- int4 &local_jump_node = shader_svm_nodes_[i][0];
-
- global_jump_node.x = NODE_SHADER_JUMP;
- global_jump_node.y = local_jump_node.y - 1 + node_offset;
- global_jump_node.z = local_jump_node.z - 1 + node_offset;
- global_jump_node.w = local_jump_node.w - 1 + node_offset;
-
- node_offset += shader_svm_nodes_[i].size() - 1;
- }
-
- /* Copy the nodes of each shader into the correct location. */
- svm_nodes += num_shaders;
- for (int i = 0; i < num_shaders; i++) {
- int shader_size = shader_svm_nodes_[i].size() - 1;
-
- memcpy(svm_nodes, &shader_svm_nodes_[i][1], sizeof(int4) * shader_size);
- svm_nodes += shader_size;
- }
-
- if (progress.get_cancel()) {
- return;
- }
-
- dscene->svm_nodes.copy_to_device();
-
- device_update_common(device, dscene, scene, progress);
-
- update_flags = UPDATE_NONE;
-
- shader_svm_nodes_.clear();
-
- VLOG(1) << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
- << " seconds.";
-}
-
-void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
-{
- device_free_common(device, dscene, scene);
-
- dscene->svm_nodes.free();
-}
-
-/* Graph Compiler */
-
-SVMCompiler::SVMCompiler(Scene *scene) : scene(scene)
-{
- max_stack_use = 0;
- current_type = SHADER_TYPE_SURFACE;
- current_shader = NULL;
- current_graph = NULL;
- background = false;
- mix_weight_offset = SVM_STACK_INVALID;
- compile_failed = false;
-}
-
-int SVMCompiler::stack_size(SocketType::Type type)
-{
- int size = 0;
-
- switch (type) {
- case SocketType::FLOAT:
- case SocketType::INT:
- size = 1;
- break;
- case SocketType::COLOR:
- case SocketType::VECTOR:
- case SocketType::NORMAL:
- case SocketType::POINT:
- size = 3;
- break;
- case SocketType::CLOSURE:
- size = 0;
- break;
- default:
- assert(0);
- break;
- }
-
- return size;
-}
-
-int SVMCompiler::stack_find_offset(int size)
-{
- int offset = -1;
-
- /* find free space in stack & mark as used */
- for (int i = 0, num_unused = 0; i < SVM_STACK_SIZE; i++) {
- if (active_stack.users[i])
- num_unused = 0;
- else
- num_unused++;
-
- if (num_unused == size) {
- offset = i + 1 - size;
- max_stack_use = max(i + 1, max_stack_use);
-
- while (i >= offset)
- active_stack.users[i--] = 1;
-
- return offset;
- }
- }
-
- if (!compile_failed) {
- compile_failed = true;
- fprintf(stderr,
- "Cycles: out of SVM stack space, shader \"%s\" too big.\n",
- current_shader->name.c_str());
- }
-
- return 0;
-}
-
-int SVMCompiler::stack_find_offset(SocketType::Type type)
-{
- return stack_find_offset(stack_size(type));
-}
-
-void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset)
-{
- int size = stack_size(type);
-
- for (int i = 0; i < size; i++)
- active_stack.users[offset + i]--;
-}
-
-int SVMCompiler::stack_assign(ShaderInput *input)
-{
- /* stack offset assign? */
- if (input->stack_offset == SVM_STACK_INVALID) {
- if (input->link) {
- /* linked to output -> use output offset */
- assert(input->link->stack_offset != SVM_STACK_INVALID);
- input->stack_offset = input->link->stack_offset;
- }
- else {
- Node *node = input->parent;
-
- /* not linked to output -> add nodes to load default value */
- input->stack_offset = stack_find_offset(input->type());
-
- if (input->type() == SocketType::FLOAT) {
- add_node(NODE_VALUE_F,
- __float_as_int(node->get_float(input->socket_type)),
- input->stack_offset);
- }
- else if (input->type() == SocketType::INT) {
- add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset);
- }
- else if (input->type() == SocketType::VECTOR || input->type() == SocketType::NORMAL ||
- input->type() == SocketType::POINT || input->type() == SocketType::COLOR) {
-
- add_node(NODE_VALUE_V, input->stack_offset);
- add_node(NODE_VALUE_V, node->get_float3(input->socket_type));
- }
- else /* should not get called for closure */
- assert(0);
- }
- }
-
- return input->stack_offset;
-}
-
-int SVMCompiler::stack_assign(ShaderOutput *output)
-{
- /* if no stack offset assigned yet, find one */
- if (output->stack_offset == SVM_STACK_INVALID)
- output->stack_offset = stack_find_offset(output->type());
-
- return output->stack_offset;
-}
-
-int SVMCompiler::stack_assign_if_linked(ShaderInput *input)
-{
- if (input->link || input->constant_folded_in)
- return stack_assign(input);
-
- return SVM_STACK_INVALID;
-}
-
-int SVMCompiler::stack_assign_if_linked(ShaderOutput *output)
-{
- if (!output->links.empty())
- return stack_assign(output);
-
- return SVM_STACK_INVALID;
-}
-
-void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output)
-{
- if (output->stack_offset == SVM_STACK_INVALID) {
- assert(input->link);
- assert(stack_size(output->type()) == stack_size(input->link->type()));
-
- output->stack_offset = input->link->stack_offset;
-
- int size = stack_size(output->type());
-
- for (int i = 0; i < size; i++)
- active_stack.users[output->stack_offset + i]++;
- }
-}
-
-void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet &done)
-{
- /* optimization we should add:
- * find and lower user counts for outputs for which all inputs are done.
- * this is done before the node is compiled, under the assumption that the
- * node will first load all inputs from the stack and then writes its
- * outputs. this used to work, but was disabled because it gave trouble
- * with inputs getting stack positions assigned */
-
- foreach (ShaderInput *input, node->inputs) {
- ShaderOutput *output = input->link;
-
- if (output && output->stack_offset != SVM_STACK_INVALID) {
- bool all_done = true;
-
- /* optimization we should add: verify if in->parent is actually used */
- foreach (ShaderInput *in, output->links)
- if (in->parent != node && done.find(in->parent) == done.end())
- all_done = false;
-
- if (all_done) {
- stack_clear_offset(output->type(), output->stack_offset);
- output->stack_offset = SVM_STACK_INVALID;
-
- foreach (ShaderInput *in, output->links)
- in->stack_offset = SVM_STACK_INVALID;
- }
- }
- }
-}
-
-void SVMCompiler::stack_clear_temporary(ShaderNode *node)
-{
- foreach (ShaderInput *input, node->inputs) {
- if (!input->link && input->stack_offset != SVM_STACK_INVALID) {
- stack_clear_offset(input->type(), input->stack_offset);
- input->stack_offset = SVM_STACK_INVALID;
- }
- }
-}
-
-uint SVMCompiler::encode_uchar4(uint x, uint y, uint z, uint w)
-{
- assert(x <= 255);
- assert(y <= 255);
- assert(z <= 255);
- assert(w <= 255);
-
- return (x) | (y << 8) | (z << 16) | (w << 24);
-}
-
-void SVMCompiler::add_node(int a, int b, int c, int d)
-{
- current_svm_nodes.push_back_slow(make_int4(a, b, c, d));
-}
-
-void SVMCompiler::add_node(ShaderNodeType type, int a, int b, int c)
-{
- current_svm_nodes.push_back_slow(make_int4(type, a, b, c));
-}
-
-void SVMCompiler::add_node(ShaderNodeType type, const float3 &f)
-{
- current_svm_nodes.push_back_slow(
- make_int4(type, __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z)));
-}
-
-void SVMCompiler::add_node(const float4 &f)
-{
- current_svm_nodes.push_back_slow(make_int4(
- __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), __float_as_int(f.w)));
-}
-
-uint SVMCompiler::attribute(ustring name)
-{
- return scene->shader_manager->get_attribute_id(name);
-}
-
-uint SVMCompiler::attribute(AttributeStandard std)
-{
- return scene->shader_manager->get_attribute_id(std);
-}
-
-uint SVMCompiler::attribute_standard(ustring name)
-{
- AttributeStandard std = Attribute::name_standard(name.c_str());
- return (std) ? attribute(std) : attribute(name);
-}
-
-void SVMCompiler::find_dependencies(ShaderNodeSet &dependencies,
- const ShaderNodeSet &done,
- ShaderInput *input,
- ShaderNode *skip_node)
-{
- ShaderNode *node = (input->link) ? input->link->parent : NULL;
- if (node != NULL && done.find(node) == done.end() && node != skip_node &&
- dependencies.find(node) == dependencies.end()) {
- foreach (ShaderInput *in, node->inputs) {
- find_dependencies(dependencies, done, in, skip_node);
- }
- dependencies.insert(node);
- }
-}
-
-void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet &done)
-{
- node->compile(*this);
- stack_clear_users(node, done);
- stack_clear_temporary(node);
-
- if (current_type == SHADER_TYPE_SURFACE) {
- if (node->has_spatial_varying())
- current_shader->has_surface_spatial_varying = true;
- if (node->get_feature() & KERNEL_FEATURE_NODE_RAYTRACE)
- current_shader->has_surface_raytrace = true;
- }
- else if (current_type == SHADER_TYPE_VOLUME) {
- if (node->has_spatial_varying())
- current_shader->has_volume_spatial_varying = true;
- if (node->has_attribute_dependency())
- current_shader->has_volume_attribute_dependency = true;
- }
-
- if (node->has_integrator_dependency()) {
- current_shader->has_integrator_dependency = true;
- }
-}
-
-void SVMCompiler::generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state)
-{
- ShaderNodeSet &done = state->nodes_done;
- vector<bool> &done_flag = state->nodes_done_flag;
-
- bool nodes_done;
- do {
- nodes_done = true;
-
- foreach (ShaderNode *node, nodes) {
- if (!done_flag[node->id]) {
- bool inputs_done = true;
-
- foreach (ShaderInput *input, node->inputs) {
- if (input->link && !done_flag[input->link->parent->id]) {
- inputs_done = false;
- }
- }
- if (inputs_done) {
- generate_node(node, done);
- done.insert(node);
- done_flag[node->id] = true;
- }
- else {
- nodes_done = false;
- }
- }
- }
- } while (!nodes_done);
-}
-
-void SVMCompiler::generate_closure_node(ShaderNode *node, CompilerState *state)
-{
- /* Skip generating closure that are not supported or needed for a particular
- * type of shader. For example a BSDF in a volume shader. */
- const int node_feature = node->get_feature();
- if ((state->node_feature_mask & node_feature) != node_feature) {
- return;
- }
-
- /* execute dependencies for closure */
- foreach (ShaderInput *in, node->inputs) {
- if (in->link != NULL) {
- ShaderNodeSet dependencies;
- find_dependencies(dependencies, state->nodes_done, in);
- generate_svm_nodes(dependencies, state);
- }
- }
-
- /* closure mix weight */
- const char *weight_name = (current_type == SHADER_TYPE_VOLUME) ? "VolumeMixWeight" :
- "SurfaceMixWeight";
- ShaderInput *weight_in = node->input(weight_name);
-
- if (weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f))
- mix_weight_offset = stack_assign(weight_in);
- else
- mix_weight_offset = SVM_STACK_INVALID;
-
- /* compile closure itself */
- generate_node(node, state->nodes_done);
-
- mix_weight_offset = SVM_STACK_INVALID;
-
- if (current_type == SHADER_TYPE_SURFACE) {
- if (node->has_surface_emission())
- current_shader->has_surface_emission = true;
- if (node->has_surface_transparent())
- current_shader->has_surface_transparent = true;
- if (node->has_surface_bssrdf()) {
- current_shader->has_surface_bssrdf = true;
- if (node->has_bssrdf_bump())
- current_shader->has_bssrdf_bump = true;
- }
- if (node->has_bump()) {
- current_shader->has_bump = true;
- }
- }
-}
-
-void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
- ShaderNode *node,
- CompilerState *state,
- const ShaderNodeSet &shared)
-{
- if (shared.find(node) != shared.end()) {
- generate_multi_closure(root_node, node, state);
- }
- else {
- foreach (ShaderInput *in, node->inputs) {
- if (in->type() == SocketType::CLOSURE && in->link)
- generated_shared_closure_nodes(root_node, in->link->parent, state, shared);
- }
- }
-}
-
-void SVMCompiler::find_aov_nodes_and_dependencies(ShaderNodeSet &aov_nodes,
- ShaderGraph *graph,
- CompilerState *state)
-{
- foreach (ShaderNode *node, graph->nodes) {
- if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
- OutputAOVNode *aov_node = static_cast<OutputAOVNode *>(node);
- if (aov_node->offset >= 0) {
- aov_nodes.insert(aov_node);
- foreach (ShaderInput *in, node->inputs) {
- if (in->link != NULL) {
- find_dependencies(aov_nodes, state->nodes_done, in);
- }
- }
- }
- }
- }
-}
-
-void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
- ShaderNode *node,
- CompilerState *state)
-{
- /* only generate once */
- if (state->closure_done.find(node) != state->closure_done.end())
- return;
-
- state->closure_done.insert(node);
-
- if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) {
- /* weighting is already taken care of in ShaderGraph::transform_multi_closure */
- ShaderInput *cl1in = node->input("Closure1");
- ShaderInput *cl2in = node->input("Closure2");
- ShaderInput *facin = node->input("Fac");
-
- /* skip empty mix/add closure nodes */
- if (!cl1in->link && !cl2in->link)
- return;
-
- if (facin && facin->link) {
- /* mix closure: generate instructions to compute mix weight */
- ShaderNodeSet dependencies;
- find_dependencies(dependencies, state->nodes_done, facin);
- generate_svm_nodes(dependencies, state);
-
- /* execute shared dependencies. this is needed to allow skipping
- * of zero weight closures and their dependencies later, so we
- * ensure that they only skip dependencies that are unique to them */
- ShaderNodeSet cl1deps, cl2deps, shareddeps;
-
- find_dependencies(cl1deps, state->nodes_done, cl1in);
- find_dependencies(cl2deps, state->nodes_done, cl2in);
-
- ShaderNodeIDComparator node_id_comp;
- set_intersection(cl1deps.begin(),
- cl1deps.end(),
- cl2deps.begin(),
- cl2deps.end(),
- std::inserter(shareddeps, shareddeps.begin()),
- node_id_comp);
-
- /* it's possible some nodes are not shared between this mix node
- * inputs, but still needed to be always executed, this mainly
- * happens when a node of current subbranch is used by a parent
- * node or so */
- if (root_node != node) {
- foreach (ShaderInput *in, root_node->inputs) {
- ShaderNodeSet rootdeps;
- find_dependencies(rootdeps, state->nodes_done, in, node);
- set_intersection(rootdeps.begin(),
- rootdeps.end(),
- cl1deps.begin(),
- cl1deps.end(),
- std::inserter(shareddeps, shareddeps.begin()),
- node_id_comp);
- set_intersection(rootdeps.begin(),
- rootdeps.end(),
- cl2deps.begin(),
- cl2deps.end(),
- std::inserter(shareddeps, shareddeps.begin()),
- node_id_comp);
- }
- }
-
- /* For dependencies AOV nodes, prevent them from being categorized
- * as exclusive deps of one or the other closure, since the need to
- * execute them for AOV writing is not dependent on the closure
- * weights. */
- if (state->aov_nodes.size()) {
- set_intersection(state->aov_nodes.begin(),
- state->aov_nodes.end(),
- cl1deps.begin(),
- cl1deps.end(),
- std::inserter(shareddeps, shareddeps.begin()),
- node_id_comp);
- set_intersection(state->aov_nodes.begin(),
- state->aov_nodes.end(),
- cl2deps.begin(),
- cl2deps.end(),
- std::inserter(shareddeps, shareddeps.begin()),
- node_id_comp);
- }
-
- if (!shareddeps.empty()) {
- if (cl1in->link) {
- generated_shared_closure_nodes(root_node, cl1in->link->parent, state, shareddeps);
- }
- if (cl2in->link) {
- generated_shared_closure_nodes(root_node, cl2in->link->parent, state, shareddeps);
- }
-
- generate_svm_nodes(shareddeps, state);
- }
-
- /* generate instructions for input closure 1 */
- if (cl1in->link) {
- /* Add instruction to skip closure and its dependencies if mix
- * weight is zero.
- */
- current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ONE, 0, stack_assign(facin), 0));
- int node_jump_skip_index = current_svm_nodes.size() - 1;
-
- generate_multi_closure(root_node, cl1in->link->parent, state);
-
- /* Fill in jump instruction location to be after closure. */
- current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() -
- node_jump_skip_index - 1;
- }
-
- /* generate instructions for input closure 2 */
- if (cl2in->link) {
- /* Add instruction to skip closure and its dependencies if mix
- * weight is zero.
- */
- current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ZERO, 0, stack_assign(facin), 0));
- int node_jump_skip_index = current_svm_nodes.size() - 1;
-
- generate_multi_closure(root_node, cl2in->link->parent, state);
-
- /* Fill in jump instruction location to be after closure. */
- current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() -
- node_jump_skip_index - 1;
- }
-
- /* unassign */
- facin->stack_offset = SVM_STACK_INVALID;
- }
- else {
- /* execute closures and their dependencies, no runtime checks
- * to skip closures here because was already optimized due to
- * fixed weight or add closure that always needs both */
- if (cl1in->link)
- generate_multi_closure(root_node, cl1in->link->parent, state);
- if (cl2in->link)
- generate_multi_closure(root_node, cl2in->link->parent, state);
- }
- }
- else {
- generate_closure_node(node, state);
- }
-
- state->nodes_done.insert(node);
- state->nodes_done_flag[node->id] = true;
-}
-
-void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
-{
- /* Converting a shader graph into svm_nodes that can be executed
- * sequentially on the virtual machine is fairly simple. We can keep
- * looping over nodes and each time all the inputs of a node are
- * ready, we add svm_nodes for it that read the inputs from the
- * stack and write outputs back to the stack.
- *
- * With the SVM, we always sample only a single closure. We can think
- * of all closures nodes as a binary tree with mix closures as inner
- * nodes and other closures as leafs. The SVM will traverse that tree,
- * each time deciding to go left or right depending on the mix weights,
- * until a closure is found.
- *
- * We only execute nodes that are needed for the mix weights and chosen
- * closure.
- */
-
- current_type = type;
- current_graph = graph;
-
- /* get input in output node */
- ShaderNode *output = graph->output();
- ShaderInput *clin = NULL;
-
- switch (type) {
- case SHADER_TYPE_SURFACE:
- clin = output->input("Surface");
- break;
- case SHADER_TYPE_VOLUME:
- clin = output->input("Volume");
- break;
- case SHADER_TYPE_DISPLACEMENT:
- clin = output->input("Displacement");
- break;
- case SHADER_TYPE_BUMP:
- clin = output->input("Normal");
- break;
- default:
- assert(0);
- break;
- }
-
- /* clear all compiler state */
- memset((void *)&active_stack, 0, sizeof(active_stack));
- current_svm_nodes.clear();
-
- foreach (ShaderNode *node, graph->nodes) {
- foreach (ShaderInput *input, node->inputs)
- input->stack_offset = SVM_STACK_INVALID;
- foreach (ShaderOutput *output, node->outputs)
- output->stack_offset = SVM_STACK_INVALID;
- }
-
- /* for the bump shader we need add a node to store the shader state */
- bool need_bump_state = (type == SHADER_TYPE_BUMP) &&
- (shader->get_displacement_method() == DISPLACE_BOTH);
- int bump_state_offset = SVM_STACK_INVALID;
- if (need_bump_state) {
- bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE);
- add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset);
- }
-
- if (shader->reference_count()) {
- CompilerState state(graph);
- if (clin->link) {
- bool generate = false;
-
- switch (type) {
- case SHADER_TYPE_SURFACE: /* generate surface shader */
- generate = true;
- shader->has_surface = true;
- state.node_feature_mask = KERNEL_FEATURE_NODE_MASK_SURFACE;
- break;
- case SHADER_TYPE_VOLUME: /* generate volume shader */
- generate = true;
- shader->has_volume = true;
- state.node_feature_mask = KERNEL_FEATURE_NODE_MASK_VOLUME;
- break;
- case SHADER_TYPE_DISPLACEMENT: /* generate displacement shader */
- generate = true;
- shader->has_displacement = true;
- state.node_feature_mask = KERNEL_FEATURE_NODE_MASK_DISPLACEMENT;
- break;
- case SHADER_TYPE_BUMP: /* generate bump shader */
- generate = true;
- state.node_feature_mask = KERNEL_FEATURE_NODE_MASK_BUMP;
- break;
- default:
- break;
- }
-
- if (generate) {
- if (type == SHADER_TYPE_SURFACE) {
- find_aov_nodes_and_dependencies(state.aov_nodes, graph, &state);
- }
- generate_multi_closure(clin->link->parent, clin->link->parent, &state);
- }
- }
-
- /* compile output node */
- output->compile(*this);
-
- if (!state.aov_nodes.empty()) {
- /* AOV passes are only written if the object is directly visible, so
- * there is no point in evaluating all the nodes generated only for the
- * AOV outputs if that's not the case. Therefore, we insert
- * NODE_AOV_START into the shader before the AOV-only nodes are
- * generated which tells the kernel that it can stop evaluation
- * early if AOVs will not be written. */
- add_node(NODE_AOV_START, 0, 0, 0);
- generate_svm_nodes(state.aov_nodes, &state);
- }
- }
-
- /* add node to restore state after bump shader has finished */
- if (need_bump_state) {
- add_node(NODE_LEAVE_BUMP_EVAL, bump_state_offset);
- }
-
- /* if compile failed, generate empty shader */
- if (compile_failed) {
- current_svm_nodes.clear();
- compile_failed = false;
- }
-
- /* for bump shaders we fall thru to the surface shader, but if this is any other kind of shader
- * it ends here */
- if (type != SHADER_TYPE_BUMP) {
- add_node(NODE_END, 0, 0, 0);
- }
-}
-
-void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary)
-{
- /* copy graph for shader with bump mapping */
- ShaderNode *output = shader->graph->output();
- int start_num_svm_nodes = svm_nodes.size();
-
- const double time_start = time_dt();
-
- bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) &&
- output->input("Surface")->link && output->input("Displacement")->link;
-
- /* finalize */
- {
- scoped_timer timer((summary != NULL) ? &summary->time_finalize : NULL);
- shader->graph->finalize(scene,
- has_bump,
- shader->has_integrator_dependency,
- shader->get_displacement_method() == DISPLACE_BOTH);
- }
-
- current_shader = shader;
-
- shader->has_surface = false;
- shader->has_surface_emission = false;
- shader->has_surface_transparent = false;
- shader->has_surface_raytrace = false;
- shader->has_surface_bssrdf = false;
- shader->has_bump = has_bump;
- shader->has_bssrdf_bump = has_bump;
- shader->has_volume = false;
- shader->has_displacement = false;
- shader->has_surface_spatial_varying = false;
- shader->has_volume_spatial_varying = false;
- shader->has_volume_attribute_dependency = false;
- shader->has_integrator_dependency = false;
-
- /* generate bump shader */
- if (has_bump) {
- scoped_timer timer((summary != NULL) ? &summary->time_generate_bump : NULL);
- compile_type(shader, shader->graph, SHADER_TYPE_BUMP);
- svm_nodes[index].y = svm_nodes.size();
- svm_nodes.append(current_svm_nodes);
- }
-
- /* generate surface shader */
- {
- scoped_timer timer((summary != NULL) ? &summary->time_generate_surface : NULL);
- compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
- /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this
- * one if it exists */
- if (!has_bump) {
- svm_nodes[index].y = svm_nodes.size();
- }
- svm_nodes.append(current_svm_nodes);
- }
-
- /* generate volume shader */
- {
- scoped_timer timer((summary != NULL) ? &summary->time_generate_volume : NULL);
- compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
- svm_nodes[index].z = svm_nodes.size();
- svm_nodes.append(current_svm_nodes);
- }
-
- /* generate displacement shader */
- {
- scoped_timer timer((summary != NULL) ? &summary->time_generate_displacement : NULL);
- compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
- svm_nodes[index].w = svm_nodes.size();
- svm_nodes.append(current_svm_nodes);
- }
-
- /* Fill in summary information. */
- if (summary != NULL) {
- summary->time_total = time_dt() - time_start;
- summary->peak_stack_usage = max_stack_use;
- summary->num_svm_nodes = svm_nodes.size() - start_num_svm_nodes;
- }
-}
-
-/* Compiler summary implementation. */
-
-SVMCompiler::Summary::Summary()
- : num_svm_nodes(0),
- peak_stack_usage(0),
- time_finalize(0.0),
- time_generate_surface(0.0),
- time_generate_bump(0.0),
- time_generate_volume(0.0),
- time_generate_displacement(0.0),
- time_total(0.0)
-{
-}
-
-string SVMCompiler::Summary::full_report() const
-{
- string report = "";
- report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes);
- report += string_printf("Peak stack usage: %d\n", peak_stack_usage);
-
- report += string_printf("Time (in seconds):\n");
- report += string_printf("Finalize: %f\n", time_finalize);
- report += string_printf(" Surface: %f\n", time_generate_surface);
- report += string_printf(" Bump: %f\n", time_generate_bump);
- report += string_printf(" Volume: %f\n", time_generate_volume);
- report += string_printf(" Displacement: %f\n", time_generate_displacement);
- report += string_printf("Generate: %f\n",
- time_generate_surface + time_generate_bump + time_generate_volume +
- time_generate_displacement);
- report += string_printf("Total: %f\n", time_total);
-
- return report;
-}
-
-/* Global state of the compiler. */
-
-SVMCompiler::CompilerState::CompilerState(ShaderGraph *graph)
-{
- int max_id = 0;
- foreach (ShaderNode *node, graph->nodes) {
- max_id = max(node->id, max_id);
- }
- nodes_done_flag.resize(max_id + 1, false);
- node_feature_mask = 0;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
deleted file mode 100644
index a45c66907b1..00000000000
--- a/intern/cycles/render/svm.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SVM_H__
-#define __SVM_H__
-
-#include "render/attribute.h"
-#include "render/graph.h"
-#include "render/shader.h"
-
-#include "util/util_array.h"
-#include "util/util_set.h"
-#include "util/util_string.h"
-#include "util/util_thread.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class ImageManager;
-class Scene;
-class ShaderGraph;
-class ShaderInput;
-class ShaderNode;
-class ShaderOutput;
-
-/* Shader Manager */
-
-class SVMShaderManager : public ShaderManager {
- public:
- SVMShaderManager();
- ~SVMShaderManager();
-
- void reset(Scene *scene) override;
-
- void host_update_specific(Scene *scene, Progress &progress) override;
-
- void device_update_specific(Device *device,
- DeviceScene *dscene,
- Scene *scene,
- Progress &progress) override;
- void device_free(Device *device, DeviceScene *dscene, Scene *scene) override;
-
- protected:
- /* Compiled shader nodes.
- *
- * The compilation happens in the `host_update_specific()`, and the `device_update_specific()`
- * moves these nodes to the device. */
- vector<array<int4>> shader_svm_nodes_;
-};
-
-/* Graph Compiler */
-
-class SVMCompiler {
- public:
- struct Summary {
- Summary();
-
- /* Number of SVM nodes shader was compiled into. */
- int num_svm_nodes;
-
- /* Peak stack usage during shader evaluation. */
- int peak_stack_usage;
-
- /* Time spent on surface graph finalization. */
- double time_finalize;
-
- /* Time spent on generating SVM nodes for surface shader. */
- double time_generate_surface;
-
- /* Time spent on generating SVM nodes for bump shader. */
- double time_generate_bump;
-
- /* Time spent on generating SVM nodes for volume shader. */
- double time_generate_volume;
-
- /* Time spent on generating SVM nodes for displacement shader. */
- double time_generate_displacement;
-
- /* Total time spent on all routines. */
- double time_total;
-
- /* A full multi-line description of the state of the compiler after compilation. */
- string full_report() const;
- };
-
- SVMCompiler(Scene *scene);
- void compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary = NULL);
-
- int stack_assign(ShaderOutput *output);
- int stack_assign(ShaderInput *input);
- int stack_assign_if_linked(ShaderInput *input);
- int stack_assign_if_linked(ShaderOutput *output);
- int stack_find_offset(int size);
- int stack_find_offset(SocketType::Type type);
- void stack_clear_offset(SocketType::Type type, int offset);
- void stack_link(ShaderInput *input, ShaderOutput *output);
-
- void add_node(ShaderNodeType type, int a = 0, int b = 0, int c = 0);
- void add_node(int a = 0, int b = 0, int c = 0, int d = 0);
- void add_node(ShaderNodeType type, const float3 &f);
- void add_node(const float4 &f);
- uint attribute(ustring name);
- uint attribute(AttributeStandard std);
- uint attribute_standard(ustring name);
- uint encode_uchar4(uint x, uint y = 0, uint z = 0, uint w = 0);
- uint closure_mix_weight_offset()
- {
- return mix_weight_offset;
- }
-
- ShaderType output_type()
- {
- return current_type;
- }
-
- Scene *scene;
- ShaderGraph *current_graph;
- bool background;
-
- protected:
- /* stack */
- struct Stack {
- Stack()
- {
- memset(users, 0, sizeof(users));
- }
- Stack(const Stack &other)
- {
- memcpy(users, other.users, sizeof(users));
- }
- Stack &operator=(const Stack &other)
- {
- memcpy(users, other.users, sizeof(users));
- return *this;
- }
-
- bool empty()
- {
- for (int i = 0; i < SVM_STACK_SIZE; i++)
- if (users[i])
- return false;
-
- return true;
- }
-
- void print()
- {
- printf("stack <");
-
- for (int i = 0; i < SVM_STACK_SIZE; i++)
- printf((users[i]) ? "*" : " ");
-
- printf(">\n");
- }
-
- int users[SVM_STACK_SIZE];
- };
-
- /* Global state of the compiler accessible from the compilation routines. */
- struct CompilerState {
- explicit CompilerState(ShaderGraph *graph);
-
- /* ** Global state, used by various compilation steps. ** */
-
- /* Set of nodes which were already compiled. */
- ShaderNodeSet nodes_done;
-
- /* Set of closures which were already compiled. */
- ShaderNodeSet closure_done;
-
- /* Set of nodes used for writing AOVs. */
- ShaderNodeSet aov_nodes;
-
- /* ** SVM nodes generation state ** */
-
- /* Flag whether the node with corresponding ID was already compiled or
- * not. Array element with index i corresponds to a node with such if.
- *
- * TODO(sergey): This is actually a copy of nodes_done just in another
- * notation. We can de-duplicate this storage actually after switching
- * all areas to use this flags array.
- */
- vector<bool> nodes_done_flag;
-
- /* Node features that can be compiled. */
- uint node_feature_mask;
- };
-
- void stack_clear_temporary(ShaderNode *node);
- int stack_size(SocketType::Type type);
- void stack_clear_users(ShaderNode *node, ShaderNodeSet &done);
-
- /* single closure */
- void find_dependencies(ShaderNodeSet &dependencies,
- const ShaderNodeSet &done,
- ShaderInput *input,
- ShaderNode *skip_node = NULL);
- void find_aov_nodes_and_dependencies(ShaderNodeSet &aov_nodes,
- ShaderGraph *graph,
- CompilerState *state);
- void generate_node(ShaderNode *node, ShaderNodeSet &done);
- void generate_aov_node(ShaderNode *node, CompilerState *state);
- void generate_closure_node(ShaderNode *node, CompilerState *state);
- void generated_shared_closure_nodes(ShaderNode *root_node,
- ShaderNode *node,
- CompilerState *state,
- const ShaderNodeSet &shared);
- void generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state);
-
- /* multi closure */
- void generate_multi_closure(ShaderNode *root_node, ShaderNode *node, CompilerState *state);
-
- /* compile */
- void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
-
- array<int4> current_svm_nodes;
- ShaderType current_type;
- Shader *current_shader;
- Stack active_stack;
- int max_stack_use;
- uint mix_weight_offset;
- bool compile_failed;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __SVM_H__ */
diff --git a/intern/cycles/render/tables.cpp b/intern/cycles/render/tables.cpp
deleted file mode 100644
index a0813400b1c..00000000000
--- a/intern/cycles/render/tables.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/tables.h"
-#include "device/device.h"
-#include "render/scene.h"
-#include "render/stats.h"
-
-#include "util/util_logging.h"
-#include "util/util_time.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Lookup Tables */
-
-LookupTables::LookupTables()
-{
- need_update_ = true;
-}
-
-LookupTables::~LookupTables()
-{
- assert(lookup_tables.size() == 0);
-}
-
-void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene)
-{
- if (!need_update())
- return;
-
- scoped_callback_timer timer([scene](double time) {
- if (scene->update_stats) {
- scene->update_stats->tables.times.add_entry({"device_update", time});
- }
- });
-
- VLOG(1) << "Total " << lookup_tables.size() << " lookup tables.";
-
- if (lookup_tables.size() > 0)
- dscene->lookup_table.copy_to_device();
-
- need_update_ = false;
-}
-
-void LookupTables::device_free(Device *, DeviceScene *dscene)
-{
- dscene->lookup_table.free();
-}
-
-bool LookupTables::need_update() const
-{
- return need_update_;
-}
-
-static size_t round_up_to_multiple(size_t size, size_t chunk)
-{
- return ((size + chunk - 1) / chunk) * chunk;
-}
-
-size_t LookupTables::add_table(DeviceScene *dscene, vector<float> &data)
-{
- assert(data.size() > 0);
-
- need_update_ = true;
-
- Table new_table;
- new_table.offset = 0;
- new_table.size = round_up_to_multiple(data.size(), TABLE_CHUNK_SIZE);
-
- /* find space to put lookup table */
- list<Table>::iterator table;
-
- for (table = lookup_tables.begin(); table != lookup_tables.end(); table++) {
- if (new_table.offset + new_table.size <= table->offset) {
- lookup_tables.insert(table, new_table);
- break;
- }
- else
- new_table.offset = table->offset + table->size;
- }
-
- if (table == lookup_tables.end()) {
- /* add at the end */
- lookup_tables.push_back(new_table);
- dscene->lookup_table.resize(new_table.offset + new_table.size);
- }
-
- /* copy table data and return offset */
- float *dtable = dscene->lookup_table.data();
- memcpy(dtable + new_table.offset, &data[0], sizeof(float) * data.size());
-
- return new_table.offset;
-}
-
-void LookupTables::remove_table(size_t *offset)
-{
- if (*offset == TABLE_OFFSET_INVALID) {
- /* The table isn't even allocated, so just return here. */
- return;
- }
-
- need_update_ = true;
-
- list<Table>::iterator table;
-
- for (table = lookup_tables.begin(); table != lookup_tables.end(); table++) {
- if (table->offset == *offset) {
- lookup_tables.erase(table);
- *offset = TABLE_OFFSET_INVALID;
- return;
- }
- }
-
- assert(table != lookup_tables.end());
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/tables.h b/intern/cycles/render/tables.h
deleted file mode 100644
index de538e2af78..00000000000
--- a/intern/cycles/render/tables.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __TABLES_H__
-#define __TABLES_H__
-
-#include "util/util_list.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Device;
-class DeviceScene;
-class Scene;
-
-enum { TABLE_CHUNK_SIZE = 256 };
-enum { TABLE_OFFSET_INVALID = -1 };
-
-class LookupTables {
- bool need_update_;
-
- public:
- struct Table {
- size_t offset;
- size_t size;
- };
-
- list<Table> lookup_tables;
-
- LookupTables();
- ~LookupTables();
-
- void device_update(Device *device, DeviceScene *dscene, Scene *scene);
- void device_free(Device *device, DeviceScene *dscene);
-
- bool need_update() const;
-
- size_t add_table(DeviceScene *dscene, vector<float> &data);
- void remove_table(size_t *offset);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __TABLES_H__ */
diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp
deleted file mode 100644
index 3070e93eff3..00000000000
--- a/intern/cycles/render/tile.cpp
+++ /dev/null
@@ -1,629 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/tile.h"
-
-#include <atomic>
-
-#include "graph/node.h"
-#include "render/background.h"
-#include "render/film.h"
-#include "render/integrator.h"
-#include "render/scene.h"
-#include "util/util_algorithm.h"
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_path.h"
-#include "util/util_string.h"
-#include "util/util_system.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* --------------------------------------------------------------------
- * Internal functions.
- */
-
-static const char *ATTR_PASSES_COUNT = "cycles.passes.count";
-static const char *ATTR_PASS_SOCKET_PREFIX_FORMAT = "cycles.passes.%d.";
-static const char *ATTR_BUFFER_SOCKET_PREFIX = "cycles.buffer.";
-static const char *ATTR_DENOISE_SOCKET_PREFIX = "cycles.denoise.";
-
-/* Global counter of ToleManager object instances. */
-static std::atomic<uint64_t> g_instance_index = 0;
-
-/* Construct names of EXR channels which will ensure order of all channels to match exact offsets
- * in render buffers corresponding to the given passes.
- *
- * Returns `std` datatypes so that it can be assigned directly to the OIIO's `ImageSpec`. */
-static std::vector<std::string> exr_channel_names_for_passes(const BufferParams &buffer_params)
-{
- static const char *component_suffixes[] = {"R", "G", "B", "A"};
-
- int pass_index = 0;
- int num_channels = 0;
- std::vector<std::string> channel_names;
- for (const BufferPass &pass : buffer_params.passes) {
- if (pass.offset == PASS_UNUSED) {
- continue;
- }
-
- const PassInfo pass_info = pass.get_info();
- num_channels += pass_info.num_components;
-
- /* EXR canonically expects first part of channel names to be sorted alphabetically, which is
- * not guaranteed to be the case with passes names. Assign a prefix based on the pass index
- * with a fixed width to ensure ordering. This makes it possible to dump existing render
- * buffers memory to disk and read it back without doing extra mapping. */
- const string prefix = string_printf("%08d", pass_index);
-
- const string channel_name_prefix = prefix + string(pass.name) + ".";
-
- for (int i = 0; i < pass_info.num_components; ++i) {
- channel_names.push_back(channel_name_prefix + component_suffixes[i]);
- }
-
- ++pass_index;
- }
-
- return channel_names;
-}
-
-inline string node_socket_attribute_name(const SocketType &socket, const string &attr_name_prefix)
-{
- return attr_name_prefix + string(socket.name);
-}
-
-template<typename ValidateValueFunc, typename GetValueFunc>
-static bool node_socket_generic_to_image_spec_atttributes(
- ImageSpec *image_spec,
- const Node *node,
- const SocketType &socket,
- const string &attr_name_prefix,
- const ValidateValueFunc &validate_value_func,
- const GetValueFunc &get_value_func)
-{
- if (!validate_value_func(node, socket)) {
- return false;
- }
-
- image_spec->attribute(node_socket_attribute_name(socket, attr_name_prefix),
- get_value_func(node, socket));
-
- return true;
-}
-
-static bool node_socket_to_image_spec_atttributes(ImageSpec *image_spec,
- const Node *node,
- const SocketType &socket,
- const string &attr_name_prefix)
-{
- const string attr_name = node_socket_attribute_name(socket, attr_name_prefix);
-
- switch (socket.type) {
- case SocketType::ENUM: {
- const ustring value = node->get_string(socket);
-
- /* Validate that the node is consistent with the node type definition. */
- const NodeEnum &enum_values = *socket.enum_values;
- if (!enum_values.exists(value)) {
- LOG(DFATAL) << "Node enum contains invalid value " << value;
- return false;
- }
-
- image_spec->attribute(attr_name, value);
-
- return true;
- }
-
- case SocketType::STRING:
- image_spec->attribute(attr_name, node->get_string(socket));
- return true;
-
- case SocketType::INT:
- image_spec->attribute(attr_name, node->get_int(socket));
- return true;
-
- case SocketType::FLOAT:
- image_spec->attribute(attr_name, node->get_float(socket));
- return true;
-
- case SocketType::BOOLEAN:
- image_spec->attribute(attr_name, node->get_bool(socket));
- return true;
-
- default:
- LOG(DFATAL) << "Unhandled socket type " << socket.type << ", should never happen.";
- return false;
- }
-}
-
-static bool node_socket_from_image_spec_atttributes(Node *node,
- const SocketType &socket,
- const ImageSpec &image_spec,
- const string &attr_name_prefix)
-{
- const string attr_name = node_socket_attribute_name(socket, attr_name_prefix);
-
- switch (socket.type) {
- case SocketType::ENUM: {
- /* TODO(sergey): Avoid construction of `ustring` by using `string_view` in the Node API. */
- const ustring value(image_spec.get_string_attribute(attr_name, ""));
-
- /* Validate that the node is consistent with the node type definition. */
- const NodeEnum &enum_values = *socket.enum_values;
- if (!enum_values.exists(value)) {
- LOG(ERROR) << "Invalid enumerator value " << value;
- return false;
- }
-
- node->set(socket, enum_values[value]);
-
- return true;
- }
-
- case SocketType::STRING:
- /* TODO(sergey): Avoid construction of `ustring` by using `string_view` in the Node API. */
- node->set(socket, ustring(image_spec.get_string_attribute(attr_name, "")));
- return true;
-
- case SocketType::INT:
- node->set(socket, image_spec.get_int_attribute(attr_name, 0));
- return true;
-
- case SocketType::FLOAT:
- node->set(socket, image_spec.get_float_attribute(attr_name, 0));
- return true;
-
- case SocketType::BOOLEAN:
- node->set(socket, static_cast<bool>(image_spec.get_int_attribute(attr_name, 0)));
- return true;
-
- default:
- LOG(DFATAL) << "Unhandled socket type " << socket.type << ", should never happen.";
- return false;
- }
-}
-
-static bool node_to_image_spec_atttributes(ImageSpec *image_spec,
- const Node *node,
- const string &attr_name_prefix)
-{
- for (const SocketType &socket : node->type->inputs) {
- if (!node_socket_to_image_spec_atttributes(image_spec, node, socket, attr_name_prefix)) {
- return false;
- }
- }
-
- return true;
-}
-
-static bool node_from_image_spec_atttributes(Node *node,
- const ImageSpec &image_spec,
- const string &attr_name_prefix)
-{
- for (const SocketType &socket : node->type->inputs) {
- if (!node_socket_from_image_spec_atttributes(node, socket, image_spec, attr_name_prefix)) {
- return false;
- }
- }
-
- return true;
-}
-
-static bool buffer_params_to_image_spec_atttributes(ImageSpec *image_spec,
- const BufferParams &buffer_params)
-{
- if (!node_to_image_spec_atttributes(image_spec, &buffer_params, ATTR_BUFFER_SOCKET_PREFIX)) {
- return false;
- }
-
- /* Passes storage is not covered by the node socket. so "expand" the loop manually. */
-
- const int num_passes = buffer_params.passes.size();
- image_spec->attribute(ATTR_PASSES_COUNT, num_passes);
-
- for (int pass_index = 0; pass_index < num_passes; ++pass_index) {
- const string attr_name_prefix = string_printf(ATTR_PASS_SOCKET_PREFIX_FORMAT, pass_index);
-
- const BufferPass *pass = &buffer_params.passes[pass_index];
- if (!node_to_image_spec_atttributes(image_spec, pass, attr_name_prefix)) {
- return false;
- }
- }
-
- return true;
-}
-
-static bool buffer_params_from_image_spec_atttributes(BufferParams *buffer_params,
- const ImageSpec &image_spec)
-{
- if (!node_from_image_spec_atttributes(buffer_params, image_spec, ATTR_BUFFER_SOCKET_PREFIX)) {
- return false;
- }
-
- /* Passes storage is not covered by the node socket. so "expand" the loop manually. */
-
- const int num_passes = image_spec.get_int_attribute(ATTR_PASSES_COUNT, 0);
- if (num_passes == 0) {
- LOG(ERROR) << "Missing passes count attribute.";
- return false;
- }
-
- for (int pass_index = 0; pass_index < num_passes; ++pass_index) {
- const string attr_name_prefix = string_printf(ATTR_PASS_SOCKET_PREFIX_FORMAT, pass_index);
-
- BufferPass pass;
-
- if (!node_from_image_spec_atttributes(&pass, image_spec, attr_name_prefix)) {
- return false;
- }
-
- buffer_params->passes.emplace_back(std::move(pass));
- }
-
- buffer_params->update_passes();
-
- return true;
-}
-
-/* Configure image specification for the given buffer parameters and passes.
- *
- * Image channels will be strictly ordered to match content of corresponding buffer, and the
- * metadata will be set so that the render buffers and passes can be reconstructed from it.
- *
- * If the tile size different from (0, 0) the image specification will be configured to use the
- * given tile size for tiled IO. */
-static bool configure_image_spec_from_buffer(ImageSpec *image_spec,
- const BufferParams &buffer_params,
- const int2 tile_size = make_int2(0, 0))
-{
- const std::vector<std::string> channel_names = exr_channel_names_for_passes(buffer_params);
- const int num_channels = channel_names.size();
-
- *image_spec = ImageSpec(
- buffer_params.width, buffer_params.height, num_channels, TypeDesc::FLOAT);
-
- image_spec->channelnames = move(channel_names);
-
- if (!buffer_params_to_image_spec_atttributes(image_spec, buffer_params)) {
- return false;
- }
-
- if (tile_size.x != 0 || tile_size.y != 0) {
- DCHECK_GT(tile_size.x, 0);
- DCHECK_GT(tile_size.y, 0);
-
- image_spec->tile_width = min(TileManager::IMAGE_TILE_SIZE, tile_size.x);
- image_spec->tile_height = min(TileManager::IMAGE_TILE_SIZE, tile_size.y);
- }
-
- return true;
-}
-
-/* --------------------------------------------------------------------
- * Tile Manager.
- */
-
-TileManager::TileManager()
-{
- /* Use process ID to separate different processes.
- * To ensure uniqueness from within a process use combination of object address and instance
- * index. This solves problem of possible object re-allocation at the same time, and solves
- * possible conflict when the counter overflows while there are still active instances of the
- * class. */
- const int tile_manager_id = g_instance_index.fetch_add(1, std::memory_order_relaxed);
- tile_file_unique_part_ = to_string(system_self_process_id()) + "-" +
- to_string(reinterpret_cast<uintptr_t>(this)) + "-" +
- to_string(tile_manager_id);
-}
-
-TileManager::~TileManager()
-{
-}
-
-int TileManager::compute_render_tile_size(const int suggested_tile_size) const
-{
- /* Must be a multiple of IMAGE_TILE_SIZE so that we can write render tiles into the image file
- * aligned on image tile boundaries. We can't set IMAGE_TILE_SIZE equal to the render tile size
- * because too big tile size leads to integer overflow inside OpenEXR. */
- return (suggested_tile_size <= IMAGE_TILE_SIZE) ? suggested_tile_size :
- align_up(suggested_tile_size, IMAGE_TILE_SIZE);
-}
-
-void TileManager::reset_scheduling(const BufferParams &params, int2 tile_size)
-{
- VLOG(3) << "Using tile size of " << tile_size;
-
- close_tile_output();
-
- tile_size_ = tile_size;
-
- tile_state_.num_tiles_x = divide_up(params.width, tile_size_.x);
- tile_state_.num_tiles_y = divide_up(params.height, tile_size_.y);
- tile_state_.num_tiles = tile_state_.num_tiles_x * tile_state_.num_tiles_y;
-
- tile_state_.next_tile_index = 0;
-
- tile_state_.current_tile = Tile();
-}
-
-void TileManager::update(const BufferParams &params, const Scene *scene)
-{
- DCHECK_NE(params.pass_stride, -1);
-
- buffer_params_ = params;
-
- /* TODO(sergey): Proper Error handling, so that if configuration has failed we don't attempt to
- * write to a partially configured file. */
- configure_image_spec_from_buffer(&write_state_.image_spec, buffer_params_, tile_size_);
-
- const DenoiseParams denoise_params = scene->integrator->get_denoise_params();
- const AdaptiveSampling adaptive_sampling = scene->integrator->get_adaptive_sampling();
-
- node_to_image_spec_atttributes(
- &write_state_.image_spec, &denoise_params, ATTR_DENOISE_SOCKET_PREFIX);
-
- if (adaptive_sampling.use) {
- overscan_ = 4;
- }
- else {
- overscan_ = 0;
- }
-}
-
-bool TileManager::done()
-{
- return tile_state_.next_tile_index == tile_state_.num_tiles;
-}
-
-bool TileManager::next()
-{
- if (done()) {
- return false;
- }
-
- tile_state_.current_tile = get_tile_for_index(tile_state_.next_tile_index);
-
- ++tile_state_.next_tile_index;
-
- return true;
-}
-
-Tile TileManager::get_tile_for_index(int index) const
-{
- /* TODO(sergey): Consider using hilbert spiral, or. maybe, even configurable. Not sure this
- * brings a lot of value since this is only applicable to BIG tiles. */
-
- const int tile_index_y = index / tile_state_.num_tiles_x;
- const int tile_index_x = index - tile_index_y * tile_state_.num_tiles_x;
-
- const int tile_window_x = tile_index_x * tile_size_.x;
- const int tile_window_y = tile_index_y * tile_size_.y;
-
- Tile tile;
-
- tile.x = max(0, tile_window_x - overscan_);
- tile.y = max(0, tile_window_y - overscan_);
-
- tile.window_x = tile_window_x - tile.x;
- tile.window_y = tile_window_y - tile.y;
- tile.window_width = min(tile_size_.x, buffer_params_.width - tile_window_x);
- tile.window_height = min(tile_size_.y, buffer_params_.height - tile_window_y);
-
- tile.width = min(buffer_params_.width - tile.x, tile.window_x + tile.window_width + overscan_);
- tile.height = min(buffer_params_.height - tile.y,
- tile.window_y + tile.window_height + overscan_);
-
- return tile;
-}
-
-const Tile &TileManager::get_current_tile() const
-{
- return tile_state_.current_tile;
-}
-
-const int2 TileManager::get_size() const
-{
- return make_int2(buffer_params_.width, buffer_params_.height);
-}
-
-bool TileManager::open_tile_output()
-{
- write_state_.filename = path_temp_get("cycles-tile-buffer-" + tile_file_unique_part_ + "-" +
- to_string(write_state_.tile_file_index) + ".exr");
-
- write_state_.tile_out = ImageOutput::create(write_state_.filename);
- if (!write_state_.tile_out) {
- LOG(ERROR) << "Error creating image output for " << write_state_.filename;
- return false;
- }
-
- if (!write_state_.tile_out->supports("tiles")) {
- LOG(ERROR) << "Progress tile file format does not support tiling.";
- return false;
- }
-
- if (!write_state_.tile_out->open(write_state_.filename, write_state_.image_spec)) {
- LOG(ERROR) << "Error opening tile file: " << write_state_.tile_out->geterror();
- write_state_.tile_out = nullptr;
- return false;
- }
-
- write_state_.num_tiles_written = 0;
-
- VLOG(3) << "Opened tile file " << write_state_.filename;
-
- return true;
-}
-
-bool TileManager::close_tile_output()
-{
- if (!write_state_.tile_out) {
- return true;
- }
-
- const bool success = write_state_.tile_out->close();
- write_state_.tile_out = nullptr;
-
- if (!success) {
- LOG(ERROR) << "Error closing tile file.";
- return false;
- }
-
- VLOG(3) << "Tile output is closed.";
-
- return true;
-}
-
-bool TileManager::write_tile(const RenderBuffers &tile_buffers)
-{
- if (!write_state_.tile_out) {
- if (!open_tile_output()) {
- return false;
- }
- }
-
- DCHECK_EQ(tile_buffers.params.pass_stride, buffer_params_.pass_stride);
-
- vector<float> pixel_storage;
-
- const BufferParams &tile_params = tile_buffers.params;
-
- const int tile_x = tile_params.full_x - buffer_params_.full_x + tile_params.window_x;
- const int tile_y = tile_params.full_y - buffer_params_.full_y + tile_params.window_y;
-
- const int64_t pass_stride = tile_params.pass_stride;
- const int64_t tile_row_stride = tile_params.width * pass_stride;
-
- const int64_t xstride = pass_stride * sizeof(float);
- const int64_t ystride = xstride * tile_params.width;
- const int64_t zstride = ystride * tile_params.height;
-
- const float *pixels = tile_buffers.buffer.data() + tile_params.window_x * pass_stride +
- tile_params.window_y * tile_row_stride;
-
- VLOG(3) << "Write tile at " << tile_x << ", " << tile_y;
-
- /* The image tile sizes in the OpenEXR file are different from the size of our big tiles. The
- * write_tiles() method expects a contiguous image region that will be split into tiles
- * internally. OpenEXR expects the size of this region to be a multiple of the tile size,
- * however OpenImageIO automatically adds the required padding.
- *
- * The only thing we have to ensure is that the tile_x and tile_y are a multiple of the
- * image tile size, which happens in compute_render_tile_size. */
- if (!write_state_.tile_out->write_tiles(tile_x,
- tile_x + tile_params.window_width,
- tile_y,
- tile_y + tile_params.window_height,
- 0,
- 1,
- TypeDesc::FLOAT,
- pixels,
- xstride,
- ystride,
- zstride)) {
- LOG(ERROR) << "Error writing tile " << write_state_.tile_out->geterror();
- return false;
- }
-
- ++write_state_.num_tiles_written;
-
- return true;
-}
-
-void TileManager::finish_write_tiles()
-{
- if (!write_state_.tile_out) {
- /* None of the tiles were written hence the file was not created.
- * Avoid creation of fully empty file since it is redundant. */
- return;
- }
-
- /* EXR expects all tiles to present in file. So explicitly write missing tiles as all-zero. */
- if (write_state_.num_tiles_written < tile_state_.num_tiles) {
- vector<float> pixel_storage(tile_size_.x * tile_size_.y * buffer_params_.pass_stride);
-
- for (int tile_index = write_state_.num_tiles_written; tile_index < tile_state_.num_tiles;
- ++tile_index) {
- const Tile tile = get_tile_for_index(tile_index);
-
- const int tile_x = tile.x + tile.window_x;
- const int tile_y = tile.y + tile.window_y;
-
- VLOG(3) << "Write dummy tile at " << tile_x << ", " << tile_y;
-
- write_state_.tile_out->write_tiles(tile_x,
- tile_x + tile.window_width,
- tile_y,
- tile_y + tile.window_height,
- 0,
- 1,
- TypeDesc::FLOAT,
- pixel_storage.data());
- }
- }
-
- close_tile_output();
-
- if (full_buffer_written_cb) {
- full_buffer_written_cb(write_state_.filename);
- }
-
- /* Advance the counter upon explicit finish of the file.
- * Makes it possible to re-use tile manager for another scene, and avoids unnecessary increments
- * of the tile-file-within-session index. */
- ++write_state_.tile_file_index;
-
- write_state_.filename = "";
-}
-
-bool TileManager::read_full_buffer_from_disk(const string_view filename,
- RenderBuffers *buffers,
- DenoiseParams *denoise_params)
-{
- unique_ptr<ImageInput> in(ImageInput::open(filename));
- if (!in) {
- LOG(ERROR) << "Error opening tile file " << filename;
- return false;
- }
-
- const ImageSpec &image_spec = in->spec();
-
- BufferParams buffer_params;
- if (!buffer_params_from_image_spec_atttributes(&buffer_params, image_spec)) {
- return false;
- }
- buffers->reset(buffer_params);
-
- if (!node_from_image_spec_atttributes(denoise_params, image_spec, ATTR_DENOISE_SOCKET_PREFIX)) {
- return false;
- }
-
- if (!in->read_image(TypeDesc::FLOAT, buffers->buffer.data())) {
- LOG(ERROR) << "Error reading pixels from the tile file " << in->geterror();
- return false;
- }
-
- if (!in->close()) {
- LOG(ERROR) << "Error closing tile file " << in->geterror();
- return false;
- }
-
- return true;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h
deleted file mode 100644
index 5872a9a8609..00000000000
--- a/intern/cycles/render/tile.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "render/buffers.h"
-#include "util/util_image.h"
-#include "util/util_string.h"
-#include "util/util_unique_ptr.h"
-
-CCL_NAMESPACE_BEGIN
-
-class DenoiseParams;
-class Scene;
-
-/* --------------------------------------------------------------------
- * Tile.
- */
-
-class Tile {
- public:
- int x = 0, y = 0;
- int width = 0, height = 0;
-
- int window_x = 0, window_y = 0;
- int window_width = 0, window_height = 0;
-
- Tile()
- {
- }
-};
-
-/* --------------------------------------------------------------------
- * Tile Manager.
- */
-
-class TileManager {
- public:
- /* This callback is invoked by whenever on-dist tiles storage file is closed after writing. */
- function<void(string_view)> full_buffer_written_cb;
-
- TileManager();
- ~TileManager();
-
- TileManager(const TileManager &other) = delete;
- TileManager(TileManager &&other) noexcept = delete;
- TileManager &operator=(const TileManager &other) = delete;
- TileManager &operator=(TileManager &&other) = delete;
-
- /* Reset current progress and start new rendering of the full-frame parameters in tiles of the
- * given size.
- * Only touches scheduling-related state of the tile manager. */
- /* TODO(sergey): Consider using tile area instead of exact size to help dealing with extreme
- * cases of stretched renders. */
- void reset_scheduling(const BufferParams &params, int2 tile_size);
-
- /* Update for the known buffer passes and scene parameters.
- * Will store all parameters needed for buffers access outside of the scene graph. */
- void update(const BufferParams &params, const Scene *scene);
-
- inline int get_num_tiles() const
- {
- return tile_state_.num_tiles;
- }
-
- inline bool has_multiple_tiles() const
- {
- return tile_state_.num_tiles > 1;
- }
-
- inline int get_tile_overscan() const
- {
- return overscan_;
- }
-
- bool next();
- bool done();
-
- const Tile &get_current_tile() const;
- const int2 get_size() const;
-
- /* Write render buffer of a tile to a file on disk.
- *
- * Opens file for write when first tile is written.
- *
- * Returns true on success. */
- bool write_tile(const RenderBuffers &tile_buffers);
-
- /* Inform the tile manager that no more tiles will be written to disk.
- * The file will be considered final, all handles to it will be closed. */
- void finish_write_tiles();
-
- /* Check whether any tile has been written to disk. */
- inline bool has_written_tiles() const
- {
- return write_state_.num_tiles_written != 0;
- }
-
- /* Read full frame render buffer from tiles file on disk.
- *
- * Returns true on success. */
- bool read_full_buffer_from_disk(string_view filename,
- RenderBuffers *buffers,
- DenoiseParams *denoise_params);
-
- /* Compute valid tile size compatible with image saving. */
- int compute_render_tile_size(const int suggested_tile_size) const;
-
- /* Tile size in the image file. */
- static const int IMAGE_TILE_SIZE = 128;
-
- protected:
- /* Get tile configuration for its index.
- * The tile index must be within [0, state_.tile_state_). */
- Tile get_tile_for_index(int index) const;
-
- bool open_tile_output();
- bool close_tile_output();
-
- /* Part of an on-disk tile file name which avoids conflicts between several Cycles instances or
- * several sessions. */
- string tile_file_unique_part_;
-
- int2 tile_size_ = make_int2(0, 0);
-
- /* Number of extra pixels around the actual tile to render. */
- int overscan_ = 0;
-
- BufferParams buffer_params_;
-
- /* Tile scheduling state. */
- struct {
- int num_tiles_x = 0;
- int num_tiles_y = 0;
- int num_tiles = 0;
-
- int next_tile_index;
-
- Tile current_tile;
- } tile_state_;
-
- /* State of tiles writing to a file on disk. */
- struct {
- /* Index of a tile file used during the current session.
- * This number is used for the file name construction, making it possible to render several
- * scenes throughout duration of the session and keep all results available for later read
- * access. */
- int tile_file_index = 0;
-
- string filename;
-
- /* Specification of the tile image which corresponds to the buffer parameters.
- * Contains channels configured according to the passes configuration in the path traces.
- *
- * Output images are saved using this specification, input images are expected to have matched
- * specification. */
- ImageSpec image_spec;
-
- /* Output handle for the tile file.
- *
- * This file can not be closed until all tiles has been provided, so the handle is stored in
- * the state and is created whenever writing is requested. */
- unique_ptr<ImageOutput> tile_out;
-
- int num_tiles_written = 0;
- } write_state_;
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/volume.cpp b/intern/cycles/render/volume.cpp
deleted file mode 100644
index 358ef71d501..00000000000
--- a/intern/cycles/render/volume.cpp
+++ /dev/null
@@ -1,635 +0,0 @@
-/*
- * Copyright 2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/volume.h"
-#include "render/attribute.h"
-#include "render/image_vdb.h"
-#include "render/scene.h"
-
-#ifdef WITH_OPENVDB
-# include <openvdb/tools/Dense.h>
-# include <openvdb/tools/GridTransformer.h>
-# include <openvdb/tools/Morphology.h>
-#endif
-
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-#include "util/util_logging.h"
-#include "util/util_openvdb.h"
-#include "util/util_progress.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-NODE_DEFINE(Volume)
-{
- NodeType *type = NodeType::add("volume", create, NodeType::NONE, Mesh::get_node_type());
-
- SOCKET_FLOAT(clipping, "Clipping", 0.001f);
- SOCKET_FLOAT(step_size, "Step Size", 0.0f);
- SOCKET_BOOLEAN(object_space, "Object Space", false);
-
- return type;
-}
-
-Volume::Volume() : Mesh(get_node_type(), Geometry::VOLUME)
-{
- clipping = 0.001f;
- step_size = 0.0f;
- object_space = false;
-}
-
-void Volume::clear(bool preserve_shaders)
-{
- Mesh::clear(preserve_shaders, true);
-}
-
-struct QuadData {
- int v0, v1, v2, v3;
-
- float3 normal;
-};
-
-enum {
- QUAD_X_MIN = 0,
- QUAD_X_MAX = 1,
- QUAD_Y_MIN = 2,
- QUAD_Y_MAX = 3,
- QUAD_Z_MIN = 4,
- QUAD_Z_MAX = 5,
-};
-
-#ifdef WITH_OPENVDB
-const int quads_indices[6][4] = {
- /* QUAD_X_MIN */
- {4, 0, 3, 7},
- /* QUAD_X_MAX */
- {1, 5, 6, 2},
- /* QUAD_Y_MIN */
- {4, 5, 1, 0},
- /* QUAD_Y_MAX */
- {3, 2, 6, 7},
- /* QUAD_Z_MIN */
- {0, 1, 2, 3},
- /* QUAD_Z_MAX */
- {5, 4, 7, 6},
-};
-
-const float3 quads_normals[6] = {
- /* QUAD_X_MIN */
- make_float3(-1.0f, 0.0f, 0.0f),
- /* QUAD_X_MAX */
- make_float3(1.0f, 0.0f, 0.0f),
- /* QUAD_Y_MIN */
- make_float3(0.0f, -1.0f, 0.0f),
- /* QUAD_Y_MAX */
- make_float3(0.0f, 1.0f, 0.0f),
- /* QUAD_Z_MIN */
- make_float3(0.0f, 0.0f, -1.0f),
- /* QUAD_Z_MAX */
- make_float3(0.0f, 0.0f, 1.0f),
-};
-
-static int add_vertex(int3 v,
- vector<int3> &vertices,
- int3 res,
- unordered_map<size_t, int> &used_verts)
-{
- size_t vert_key = v.x + v.y * (res.x + 1) + v.z * (res.x + 1) * (res.y + 1);
- unordered_map<size_t, int>::iterator it = used_verts.find(vert_key);
-
- if (it != used_verts.end()) {
- return it->second;
- }
-
- int vertex_offset = vertices.size();
- used_verts[vert_key] = vertex_offset;
- vertices.push_back(v);
- return vertex_offset;
-}
-
-static void create_quad(int3 corners[8],
- vector<int3> &vertices,
- vector<QuadData> &quads,
- int3 res,
- unordered_map<size_t, int> &used_verts,
- int face_index)
-{
- QuadData quad;
- quad.v0 = add_vertex(corners[quads_indices[face_index][0]], vertices, res, used_verts);
- quad.v1 = add_vertex(corners[quads_indices[face_index][1]], vertices, res, used_verts);
- quad.v2 = add_vertex(corners[quads_indices[face_index][2]], vertices, res, used_verts);
- quad.v3 = add_vertex(corners[quads_indices[face_index][3]], vertices, res, used_verts);
- quad.normal = quads_normals[face_index];
-
- quads.push_back(quad);
-}
-#endif
-
-/* Create a mesh from a volume.
- *
- * The way the algorithm works is as follows:
- *
- * - The topologies of input OpenVDB grids are merged into a temporary grid.
- * - Voxels of the temporary grid are dilated to account for the padding necessary for volume
- * sampling.
- * - Quads are created on the boundary between active and inactive leaf nodes of the temporary
- * grid.
- */
-class VolumeMeshBuilder {
- public:
-#ifdef WITH_OPENVDB
- /* use a MaskGrid to store the topology to save memory */
- openvdb::MaskGrid::Ptr topology_grid;
- openvdb::CoordBBox bbox;
-#endif
- bool first_grid;
-
- VolumeMeshBuilder();
-
-#ifdef WITH_OPENVDB
- void add_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping);
-#endif
-
- void add_padding(int pad_size);
-
- void create_mesh(vector<float3> &vertices,
- vector<int> &indices,
- vector<float3> &face_normals,
- const float face_overlap_avoidance);
-
- void generate_vertices_and_quads(vector<int3> &vertices_is, vector<QuadData> &quads);
-
- void convert_object_space(const vector<int3> &vertices,
- vector<float3> &out_vertices,
- const float face_overlap_avoidance);
-
- void convert_quads_to_tris(const vector<QuadData> &quads,
- vector<int> &tris,
- vector<float3> &face_normals);
-
- bool empty_grid() const;
-
-#ifdef WITH_OPENVDB
- template<typename GridType>
- void merge_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping)
- {
- typename GridType::ConstPtr typed_grid = openvdb::gridConstPtrCast<GridType>(grid);
-
- if (do_clipping) {
- using ValueType = typename GridType::ValueType;
- typename GridType::Ptr copy = typed_grid->deepCopy();
- typename GridType::ValueOnIter iter = copy->beginValueOn();
-
- for (; iter; ++iter) {
- if (iter.getValue() < ValueType(volume_clipping)) {
- iter.setValueOff();
- }
- }
-
- typed_grid = copy;
- }
-
- topology_grid->topologyUnion(*typed_grid);
- }
-#endif
-};
-
-VolumeMeshBuilder::VolumeMeshBuilder()
-{
- first_grid = true;
-}
-
-#ifdef WITH_OPENVDB
-void VolumeMeshBuilder::add_grid(openvdb::GridBase::ConstPtr grid,
- bool do_clipping,
- float volume_clipping)
-{
- /* set the transform of our grid from the first one */
- if (first_grid) {
- topology_grid = openvdb::MaskGrid::create();
- topology_grid->setTransform(grid->transform().copy());
- first_grid = false;
- }
- /* if the transforms do not match, we need to resample one of the grids so that
- * its index space registers with that of the other, here we resample our mask
- * grid so memory usage is kept low */
- else if (topology_grid->transform() != grid->transform()) {
- openvdb::MaskGrid::Ptr temp_grid = topology_grid->copyWithNewTree();
- temp_grid->setTransform(grid->transform().copy());
- openvdb::tools::resampleToMatch<openvdb::tools::BoxSampler>(*topology_grid, *temp_grid);
- topology_grid = temp_grid;
- topology_grid->setTransform(grid->transform().copy());
- }
-
- if (grid->isType<openvdb::FloatGrid>()) {
- merge_grid<openvdb::FloatGrid>(grid, do_clipping, volume_clipping);
- }
- else if (grid->isType<openvdb::Vec3fGrid>()) {
- merge_grid<openvdb::Vec3fGrid>(grid, do_clipping, volume_clipping);
- }
- else if (grid->isType<openvdb::Vec4fGrid>()) {
- merge_grid<openvdb::Vec4fGrid>(grid, do_clipping, volume_clipping);
- }
- else if (grid->isType<openvdb::BoolGrid>()) {
- merge_grid<openvdb::BoolGrid>(grid, do_clipping, volume_clipping);
- }
- else if (grid->isType<openvdb::DoubleGrid>()) {
- merge_grid<openvdb::DoubleGrid>(grid, do_clipping, volume_clipping);
- }
- else if (grid->isType<openvdb::Int32Grid>()) {
- merge_grid<openvdb::Int32Grid>(grid, do_clipping, volume_clipping);
- }
- else if (grid->isType<openvdb::Int64Grid>()) {
- merge_grid<openvdb::Int64Grid>(grid, do_clipping, volume_clipping);
- }
- else if (grid->isType<openvdb::Vec3IGrid>()) {
- merge_grid<openvdb::Vec3IGrid>(grid, do_clipping, volume_clipping);
- }
- else if (grid->isType<openvdb::Vec3dGrid>()) {
- merge_grid<openvdb::Vec3dGrid>(grid, do_clipping, volume_clipping);
- }
- else if (grid->isType<openvdb::MaskGrid>()) {
- topology_grid->topologyUnion(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid));
- }
-}
-#endif
-
-void VolumeMeshBuilder::add_padding(int pad_size)
-{
-#ifdef WITH_OPENVDB
- openvdb::tools::dilateVoxels(topology_grid->tree(), pad_size);
-#else
- (void)pad_size;
-#endif
-}
-
-void VolumeMeshBuilder::create_mesh(vector<float3> &vertices,
- vector<int> &indices,
- vector<float3> &face_normals,
- const float face_overlap_avoidance)
-{
-#ifdef WITH_OPENVDB
- /* We create vertices in index space (is), and only convert them to object
- * space when done. */
- vector<int3> vertices_is;
- vector<QuadData> quads;
-
- /* make sure we only have leaf nodes in the tree, as tiles are not handled by
- * this algorithm */
- topology_grid->tree().voxelizeActiveTiles();
-
- generate_vertices_and_quads(vertices_is, quads);
-
- convert_object_space(vertices_is, vertices, face_overlap_avoidance);
-
- convert_quads_to_tris(quads, indices, face_normals);
-#else
- (void)vertices;
- (void)indices;
- (void)face_normals;
- (void)face_overlap_avoidance;
-#endif
-}
-
-void VolumeMeshBuilder::generate_vertices_and_quads(vector<ccl::int3> &vertices_is,
- vector<QuadData> &quads)
-{
-#ifdef WITH_OPENVDB
- const openvdb::MaskGrid::TreeType &tree = topology_grid->tree();
- tree.evalLeafBoundingBox(bbox);
-
- const int3 resolution = make_int3(bbox.dim().x(), bbox.dim().y(), bbox.dim().z());
-
- unordered_map<size_t, int> used_verts;
-
- for (auto iter = tree.cbeginLeaf(); iter; ++iter) {
- openvdb::CoordBBox leaf_bbox = iter->getNodeBoundingBox();
- /* +1 to convert from exclusive to include bounds. */
- leaf_bbox.max() = leaf_bbox.max().offsetBy(1);
-
- int3 min = make_int3(leaf_bbox.min().x(), leaf_bbox.min().y(), leaf_bbox.min().z());
- int3 max = make_int3(leaf_bbox.max().x(), leaf_bbox.max().y(), leaf_bbox.max().z());
-
- int3 corners[8] = {
- make_int3(min[0], min[1], min[2]),
- make_int3(max[0], min[1], min[2]),
- make_int3(max[0], max[1], min[2]),
- make_int3(min[0], max[1], min[2]),
- make_int3(min[0], min[1], max[2]),
- make_int3(max[0], min[1], max[2]),
- make_int3(max[0], max[1], max[2]),
- make_int3(min[0], max[1], max[2]),
- };
-
- /* Only create a quad if on the border between an active and an inactive leaf.
- *
- * We verify that a leaf exists by probing a coordinate that is at its center,
- * to do so we compute the center of the current leaf and offset this coordinate
- * by the size of a leaf in each direction.
- */
- static const int LEAF_DIM = openvdb::MaskGrid::TreeType::LeafNodeType::DIM;
- auto center = leaf_bbox.min() + openvdb::Coord(LEAF_DIM / 2);
-
- if (!tree.probeLeaf(openvdb::Coord(center.x() - LEAF_DIM, center.y(), center.z()))) {
- create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_X_MIN);
- }
-
- if (!tree.probeLeaf(openvdb::Coord(center.x() + LEAF_DIM, center.y(), center.z()))) {
- create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_X_MAX);
- }
-
- if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y() - LEAF_DIM, center.z()))) {
- create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Y_MIN);
- }
-
- if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y() + LEAF_DIM, center.z()))) {
- create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Y_MAX);
- }
-
- if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y(), center.z() - LEAF_DIM))) {
- create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Z_MIN);
- }
-
- if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y(), center.z() + LEAF_DIM))) {
- create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Z_MAX);
- }
- }
-#else
- (void)vertices_is;
- (void)quads;
-#endif
-}
-
-void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
- vector<float3> &out_vertices,
- const float face_overlap_avoidance)
-{
-#ifdef WITH_OPENVDB
- /* compute the offset for the face overlap avoidance */
- bbox = topology_grid->evalActiveVoxelBoundingBox();
- openvdb::Coord dim = bbox.dim();
-
- float3 cell_size = make_float3(1.0f / dim.x(), 1.0f / dim.y(), 1.0f / dim.z());
- float3 point_offset = cell_size * face_overlap_avoidance;
-
- out_vertices.reserve(vertices.size());
-
- for (size_t i = 0; i < vertices.size(); ++i) {
- openvdb::math::Vec3d p = topology_grid->indexToWorld(
- openvdb::math::Vec3d(vertices[i].x, vertices[i].y, vertices[i].z));
- float3 vertex = make_float3((float)p.x(), (float)p.y(), (float)p.z());
- out_vertices.push_back(vertex + point_offset);
- }
-#else
- (void)vertices;
- (void)out_vertices;
- (void)face_overlap_avoidance;
-#endif
-}
-
-void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads,
- vector<int> &tris,
- vector<float3> &face_normals)
-{
- int index_offset = 0;
- tris.resize(quads.size() * 6);
- face_normals.reserve(quads.size() * 2);
-
- for (size_t i = 0; i < quads.size(); ++i) {
- tris[index_offset++] = quads[i].v0;
- tris[index_offset++] = quads[i].v2;
- tris[index_offset++] = quads[i].v1;
-
- face_normals.push_back(quads[i].normal);
-
- tris[index_offset++] = quads[i].v0;
- tris[index_offset++] = quads[i].v3;
- tris[index_offset++] = quads[i].v2;
-
- face_normals.push_back(quads[i].normal);
- }
-}
-
-bool VolumeMeshBuilder::empty_grid() const
-{
-#ifdef WITH_OPENVDB
- return !topology_grid || topology_grid->tree().leafCount() == 0;
-#else
- return true;
-#endif
-}
-
-#ifdef WITH_OPENVDB
-template<typename GridType>
-static openvdb::GridBase::ConstPtr openvdb_grid_from_device_texture(device_texture *image_memory,
- float volume_clipping,
- Transform transform_3d)
-{
- using ValueType = typename GridType::ValueType;
-
- openvdb::CoordBBox dense_bbox(0,
- 0,
- 0,
- image_memory->data_width - 1,
- image_memory->data_height - 1,
- image_memory->data_depth - 1);
-
- typename GridType::Ptr sparse = GridType::create(ValueType(0.0f));
- if (dense_bbox.empty()) {
- return sparse;
- }
-
- openvdb::tools::Dense<ValueType, openvdb::tools::MemoryLayout::LayoutXYZ> dense(
- dense_bbox, static_cast<ValueType *>(image_memory->host_pointer));
-
- openvdb::tools::copyFromDense(dense, *sparse, ValueType(volume_clipping));
-
- /* #copyFromDense will remove any leaf node that contains constant data and replace it with a
- * tile, however, we need to preserve the leaves in order to generate the mesh, so re-voxelize
- * the leaves that were pruned. This should not affect areas that were skipped due to the
- * volume_clipping parameter. */
- sparse->tree().voxelizeActiveTiles();
-
- /* Compute index to world matrix. */
- float3 voxel_size = make_float3(1.0f / image_memory->data_width,
- 1.0f / image_memory->data_height,
- 1.0f / image_memory->data_depth);
-
- transform_3d = transform_inverse(transform_3d);
-
- openvdb::Mat4R index_to_world_mat((double)(voxel_size.x * transform_3d[0][0]),
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- (double)(voxel_size.y * transform_3d[1][1]),
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- (double)(voxel_size.z * transform_3d[2][2]),
- 0.0,
- (double)transform_3d[0][3],
- (double)transform_3d[1][3],
- (double)transform_3d[2][3],
- 1.0);
-
- openvdb::math::Transform::Ptr index_to_world_tfm =
- openvdb::math::Transform::createLinearTransform(index_to_world_mat);
-
- sparse->setTransform(index_to_world_tfm);
-
- return sparse;
-}
-#endif
-
-/* ************************************************************************** */
-
-void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
-{
- string msg = string_printf("Computing Volume Mesh %s", volume->name.c_str());
- progress.set_status("Updating Mesh", msg);
-
- /* Find shader and compute padding based on volume shader interpolation settings. */
- Shader *volume_shader = NULL;
- int pad_size = 0;
-
- foreach (Node *node, volume->get_used_shaders()) {
- Shader *shader = static_cast<Shader *>(node);
-
- if (!shader->has_volume) {
- continue;
- }
-
- volume_shader = shader;
-
- if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_LINEAR) {
- pad_size = max(1, pad_size);
- }
- else if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC) {
- pad_size = max(2, pad_size);
- }
-
- break;
- }
-
- /* Clear existing volume mesh, done here in case we early out due to
- * empty grid or missing volume shader.
- * Also keep the shaders to avoid infinite loops when synchronizing, as this will tag the shaders
- * as having changed. */
- volume->clear(true);
- volume->need_update_rebuild = true;
-
- if (!volume_shader) {
- return;
- }
-
- /* Create volume mesh builder. */
- VolumeMeshBuilder builder;
-
-#ifdef WITH_OPENVDB
- foreach (Attribute &attr, volume->attributes.attributes) {
- if (attr.element != ATTR_ELEMENT_VOXEL) {
- continue;
- }
-
- bool do_clipping = false;
-
- ImageHandle &handle = attr.data_voxel();
-
- /* Try building from OpenVDB grid directly. */
- VDBImageLoader *vdb_loader = handle.vdb_loader();
- openvdb::GridBase::ConstPtr grid;
- if (vdb_loader) {
- grid = vdb_loader->get_grid();
-
- /* If building from an OpenVDB grid, we need to manually clip the values. */
- do_clipping = true;
- }
-
- /* Else fall back to creating an OpenVDB grid from the dense volume data. */
- if (!grid) {
- device_texture *image_memory = handle.image_memory();
-
- if (image_memory->data_elements == 1) {
- grid = openvdb_grid_from_device_texture<openvdb::FloatGrid>(
- image_memory, volume->get_clipping(), handle.metadata().transform_3d);
- }
- else if (image_memory->data_elements == 3) {
- grid = openvdb_grid_from_device_texture<openvdb::Vec3fGrid>(
- image_memory, volume->get_clipping(), handle.metadata().transform_3d);
- }
- else if (image_memory->data_elements == 4) {
- grid = openvdb_grid_from_device_texture<openvdb::Vec4fGrid>(
- image_memory, volume->get_clipping(), handle.metadata().transform_3d);
- }
- }
-
- if (grid) {
- builder.add_grid(grid, do_clipping, volume->get_clipping());
- }
- }
-#endif
-
- /* If nothing to build, early out. */
- if (builder.empty_grid()) {
- return;
- }
-
- builder.add_padding(pad_size);
-
- /* Slightly offset vertex coordinates to avoid overlapping faces with other
- * volumes or meshes. The proper solution would be to improve intersection in
- * the kernel to support robust handling of multiple overlapping faces or use
- * an all-hit intersection similar to shadows. */
- const float face_overlap_avoidance = 0.1f *
- hash_uint_to_float(hash_string(volume->name.c_str()));
-
- /* Create mesh. */
- vector<float3> vertices;
- vector<int> indices;
- vector<float3> face_normals;
- builder.create_mesh(vertices, indices, face_normals, face_overlap_avoidance);
-
- volume->reserve_mesh(vertices.size(), indices.size() / 3);
- volume->used_shaders.clear();
- volume->used_shaders.push_back_slow(volume_shader);
-
- for (size_t i = 0; i < vertices.size(); ++i) {
- volume->add_vertex(vertices[i]);
- }
-
- for (size_t i = 0; i < indices.size(); i += 3) {
- volume->add_triangle(indices[i], indices[i + 1], indices[i + 2], 0, false);
- }
-
- Attribute *attr_fN = volume->attributes.add(ATTR_STD_FACE_NORMAL);
- float3 *fN = attr_fN->data_float3();
-
- for (size_t i = 0; i < face_normals.size(); ++i) {
- fN[i] = face_normals[i];
- }
-
- /* Print stats. */
- VLOG(1) << "Memory usage volume mesh: "
- << ((vertices.size() + face_normals.size()) * sizeof(float3) +
- indices.size() * sizeof(int)) /
- (1024.0 * 1024.0)
- << "Mb.";
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/volume.h b/intern/cycles/render/volume.h
deleted file mode 100644
index 2e9703bf7ed..00000000000
--- a/intern/cycles/render/volume.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "graph/node.h"
-
-#include "render/mesh.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Volume : public Mesh {
- public:
- NODE_DECLARE
-
- Volume();
-
- NODE_SOCKET_API(float, clipping)
- NODE_SOCKET_API(float, step_size)
- NODE_SOCKET_API(bool, object_space)
-
- virtual void clear(bool preserve_shaders = false) override;
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/CMakeLists.txt b/intern/cycles/scene/CMakeLists.txt
new file mode 100644
index 00000000000..a3fde99306b
--- /dev/null
+++ b/intern/cycles/scene/CMakeLists.txt
@@ -0,0 +1,163 @@
+# Copyright 2011-2021 Blender Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(INC
+ ..
+ ../../sky/include
+)
+
+set(SRC
+ alembic.cpp
+ alembic_read.cpp
+ attribute.cpp
+ background.cpp
+ bake.cpp
+ camera.cpp
+ colorspace.cpp
+ constant_fold.cpp
+ film.cpp
+ geometry.cpp
+ hair.cpp
+ image.cpp
+ image_oiio.cpp
+ image_sky.cpp
+ image_vdb.cpp
+ integrator.cpp
+ jitter.cpp
+ light.cpp
+ mesh.cpp
+ mesh_displace.cpp
+ mesh_subdivision.cpp
+ procedural.cpp
+ object.cpp
+ osl.cpp
+ particles.cpp
+ pass.cpp
+ curves.cpp
+ scene.cpp
+ shader.cpp
+ shader_graph.cpp
+ shader_nodes.cpp
+ sobol.cpp
+ stats.cpp
+ svm.cpp
+ tables.cpp
+ volume.cpp
+)
+
+set(SRC_HEADERS
+ alembic.h
+ alembic_read.h
+ attribute.h
+ bake.h
+ background.h
+ camera.h
+ colorspace.h
+ constant_fold.h
+ film.h
+ geometry.h
+ hair.h
+ image.h
+ image_oiio.h
+ image_sky.h
+ image_vdb.h
+ integrator.h
+ light.h
+ jitter.h
+ mesh.h
+ object.h
+ osl.h
+ particles.h
+ pass.h
+ procedural.h
+ curves.h
+ scene.h
+ shader.h
+ shader_graph.h
+ shader_nodes.h
+ sobol.h
+ stats.h
+ svm.h
+ tables.h
+ volume.h
+)
+
+set(LIB
+ cycles_bvh
+ cycles_device
+ cycles_integrator
+ cycles_subd
+ cycles_util
+)
+
+if(CYCLES_STANDALONE_REPOSITORY)
+ list(APPEND LIB extern_sky)
+else()
+ list(APPEND LIB bf_intern_sky)
+endif()
+
+if(WITH_CYCLES_OSL)
+ list(APPEND LIB
+ cycles_kernel_osl
+ )
+
+ SET_PROPERTY(SOURCE osl.cpp PROPERTY COMPILE_FLAGS ${RTTI_DISABLE_FLAGS})
+endif()
+
+if(WITH_OPENCOLORIO)
+ add_definitions(-DWITH_OCIO)
+ include_directories(
+ SYSTEM
+ ${OPENCOLORIO_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${OPENCOLORIO_LIBRARIES}
+ )
+ if(WIN32)
+ add_definitions(-DOpenColorIO_SKIP_IMPORTS)
+ endif()
+endif()
+
+if(WITH_OPENVDB)
+ add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
+ list(APPEND INC_SYS
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${OPENVDB_LIBRARIES}
+ )
+endif()
+
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+ list(APPEND INC_SYS
+ ${ALEMBIC_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${ALEMBIC_LIBRARIES}
+ )
+endif()
+
+if(WITH_NANOVDB)
+ list(APPEND INC_SYS
+ ${NANOVDB_INCLUDE_DIRS}
+ )
+endif()
+
+include_directories(${INC})
+include_directories(SYSTEM ${INC_SYS})
+
+add_definitions(${GL_DEFINITIONS})
+
+cycles_add_library(cycles_scene "${LIB}" ${SRC} ${SRC_HEADERS})
diff --git a/intern/cycles/scene/alembic.cpp b/intern/cycles/scene/alembic.cpp
new file mode 100644
index 00000000000..39b5f467736
--- /dev/null
+++ b/intern/cycles/scene/alembic.cpp
@@ -0,0 +1,1431 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/alembic.h"
+
+#include "scene/alembic_read.h"
+#include "scene/camera.h"
+#include "scene/curves.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/progress.h"
+#include "util/transform.h"
+#include "util/vector.h"
+
+#ifdef WITH_ALEMBIC
+
+using namespace Alembic::AbcGeom;
+
+CCL_NAMESPACE_BEGIN
+
+/* TODO(kevindietrich): motion blur support. */
+
+template<typename SchemaType>
+static vector<FaceSetShaderIndexPair> parse_face_sets_for_shader_assignment(
+ SchemaType &schema, const array<Node *> &used_shaders)
+{
+ vector<FaceSetShaderIndexPair> result;
+
+ std::vector<std::string> face_set_names;
+ schema.getFaceSetNames(face_set_names);
+
+ if (face_set_names.empty()) {
+ return result;
+ }
+
+ for (const std::string &face_set_name : face_set_names) {
+ int shader_index = 0;
+
+ for (Node *node : used_shaders) {
+ if (node->name == face_set_name) {
+ break;
+ }
+
+ ++shader_index;
+ }
+
+ if (shader_index >= used_shaders.size()) {
+ /* use the first shader instead if none was found */
+ shader_index = 0;
+ }
+
+ const Alembic::AbcGeom::IFaceSet face_set = schema.getFaceSet(face_set_name);
+
+ if (!face_set.valid()) {
+ continue;
+ }
+
+ result.push_back({face_set, shader_index});
+ }
+
+ return result;
+}
+
+void CachedData::clear()
+{
+ attributes.clear();
+ curve_first_key.clear();
+ curve_keys.clear();
+ curve_radius.clear();
+ curve_shader.clear();
+ num_ngons.clear();
+ shader.clear();
+ subd_creases_edge.clear();
+ subd_creases_weight.clear();
+ subd_face_corners.clear();
+ subd_num_corners.clear();
+ subd_ptex_offset.clear();
+ subd_smooth.clear();
+ subd_start_corner.clear();
+ transforms.clear();
+ triangles.clear();
+ uv_loops.clear();
+ vertices.clear();
+
+ for (CachedAttribute &attr : attributes) {
+ attr.data.clear();
+ }
+
+ attributes.clear();
+}
+
+CachedData::CachedAttribute &CachedData::add_attribute(const ustring &name,
+ const TimeSampling &time_sampling)
+{
+ for (auto &attr : attributes) {
+ if (attr.name == name) {
+ return attr;
+ }
+ }
+
+ CachedAttribute &attr = attributes.emplace_back();
+ attr.name = name;
+ attr.data.set_time_sampling(time_sampling);
+ return attr;
+}
+
+bool CachedData::is_constant() const
+{
+# define CHECK_IF_CONSTANT(data) \
+ if (!data.is_constant()) { \
+ return false; \
+ }
+
+ CHECK_IF_CONSTANT(curve_first_key)
+ CHECK_IF_CONSTANT(curve_keys)
+ CHECK_IF_CONSTANT(curve_radius)
+ CHECK_IF_CONSTANT(curve_shader)
+ CHECK_IF_CONSTANT(num_ngons)
+ CHECK_IF_CONSTANT(shader)
+ CHECK_IF_CONSTANT(subd_creases_edge)
+ CHECK_IF_CONSTANT(subd_creases_weight)
+ CHECK_IF_CONSTANT(subd_face_corners)
+ CHECK_IF_CONSTANT(subd_num_corners)
+ CHECK_IF_CONSTANT(subd_ptex_offset)
+ CHECK_IF_CONSTANT(subd_smooth)
+ CHECK_IF_CONSTANT(subd_start_corner)
+ CHECK_IF_CONSTANT(transforms)
+ CHECK_IF_CONSTANT(triangles)
+ CHECK_IF_CONSTANT(uv_loops)
+ CHECK_IF_CONSTANT(vertices)
+
+ for (const CachedAttribute &attr : attributes) {
+ if (!attr.data.is_constant()) {
+ return false;
+ }
+ }
+
+ return true;
+
+# undef CHECK_IF_CONSTANT
+}
+
+void CachedData::invalidate_last_loaded_time(bool attributes_only)
+{
+ if (attributes_only) {
+ for (CachedAttribute &attr : attributes) {
+ attr.data.invalidate_last_loaded_time();
+ }
+
+ return;
+ }
+
+ curve_first_key.invalidate_last_loaded_time();
+ curve_keys.invalidate_last_loaded_time();
+ curve_radius.invalidate_last_loaded_time();
+ curve_shader.invalidate_last_loaded_time();
+ num_ngons.invalidate_last_loaded_time();
+ shader.invalidate_last_loaded_time();
+ subd_creases_edge.invalidate_last_loaded_time();
+ subd_creases_weight.invalidate_last_loaded_time();
+ subd_face_corners.invalidate_last_loaded_time();
+ subd_num_corners.invalidate_last_loaded_time();
+ subd_ptex_offset.invalidate_last_loaded_time();
+ subd_smooth.invalidate_last_loaded_time();
+ subd_start_corner.invalidate_last_loaded_time();
+ transforms.invalidate_last_loaded_time();
+ triangles.invalidate_last_loaded_time();
+ uv_loops.invalidate_last_loaded_time();
+ vertices.invalidate_last_loaded_time();
+}
+
+void CachedData::set_time_sampling(TimeSampling time_sampling)
+{
+ curve_first_key.set_time_sampling(time_sampling);
+ curve_keys.set_time_sampling(time_sampling);
+ curve_radius.set_time_sampling(time_sampling);
+ curve_shader.set_time_sampling(time_sampling);
+ num_ngons.set_time_sampling(time_sampling);
+ shader.set_time_sampling(time_sampling);
+ subd_creases_edge.set_time_sampling(time_sampling);
+ subd_creases_weight.set_time_sampling(time_sampling);
+ subd_face_corners.set_time_sampling(time_sampling);
+ subd_num_corners.set_time_sampling(time_sampling);
+ subd_ptex_offset.set_time_sampling(time_sampling);
+ subd_smooth.set_time_sampling(time_sampling);
+ subd_start_corner.set_time_sampling(time_sampling);
+ transforms.set_time_sampling(time_sampling);
+ triangles.set_time_sampling(time_sampling);
+ uv_loops.set_time_sampling(time_sampling);
+ vertices.set_time_sampling(time_sampling);
+
+ for (CachedAttribute &attr : attributes) {
+ attr.data.set_time_sampling(time_sampling);
+ }
+}
+
+size_t CachedData::memory_used() const
+{
+ size_t mem_used = 0;
+
+ mem_used += curve_first_key.memory_used();
+ mem_used += curve_keys.memory_used();
+ mem_used += curve_radius.memory_used();
+ mem_used += curve_shader.memory_used();
+ mem_used += num_ngons.memory_used();
+ mem_used += shader.memory_used();
+ mem_used += subd_creases_edge.memory_used();
+ mem_used += subd_creases_weight.memory_used();
+ mem_used += subd_face_corners.memory_used();
+ mem_used += subd_num_corners.memory_used();
+ mem_used += subd_ptex_offset.memory_used();
+ mem_used += subd_smooth.memory_used();
+ mem_used += subd_start_corner.memory_used();
+ mem_used += transforms.memory_used();
+ mem_used += triangles.memory_used();
+ mem_used += uv_loops.memory_used();
+ mem_used += vertices.memory_used();
+
+ for (const CachedAttribute &attr : attributes) {
+ mem_used += attr.data.memory_used();
+ }
+
+ return mem_used;
+}
+
+static M44d convert_yup_zup(const M44d &mtx, float scale_mult)
+{
+ V3d scale, shear, rotation, translation;
+ extractSHRT(mtx,
+ scale,
+ shear,
+ rotation,
+ translation,
+ true,
+ IMATH_INTERNAL_NAMESPACE::Euler<double>::XZY);
+
+ M44d rot_mat, scale_mat, trans_mat;
+ rot_mat.setEulerAngles(V3d(rotation.x, -rotation.z, rotation.y));
+ scale_mat.setScale(V3d(scale.x, scale.z, scale.y));
+ trans_mat.setTranslation(V3d(translation.x, -translation.z, translation.y));
+
+ M44d temp_mat = scale_mat * rot_mat * trans_mat;
+
+ scale_mat.setScale(static_cast<double>(scale_mult));
+
+ return temp_mat * scale_mat;
+}
+
+static void transform_decompose(
+ const M44d &mat, V3d &scale, V3d &shear, Quatd &rotation, V3d &translation)
+{
+ M44d mat_remainder(mat);
+
+ /* extract scale and shear */
+ Imath::extractAndRemoveScalingAndShear(mat_remainder, scale, shear);
+
+ /* extract translation */
+ translation.x = mat_remainder[3][0];
+ translation.y = mat_remainder[3][1];
+ translation.z = mat_remainder[3][2];
+
+ /* extract rotation */
+ rotation = extractQuat(mat_remainder);
+}
+
+static M44d transform_compose(const V3d &scale,
+ const V3d &shear,
+ const Quatd &rotation,
+ const V3d &translation)
+{
+ M44d scale_mat, shear_mat, rot_mat, trans_mat;
+
+ scale_mat.setScale(scale);
+ shear_mat.setShear(shear);
+ rot_mat = rotation.toMatrix44();
+ trans_mat.setTranslation(translation);
+
+ return scale_mat * shear_mat * rot_mat * trans_mat;
+}
+
+/* get the matrix for the specified time, or return the identity matrix if there is no exact match
+ */
+static M44d get_matrix_for_time(const MatrixSampleMap &samples, chrono_t time)
+{
+ MatrixSampleMap::const_iterator iter = samples.find(time);
+ if (iter != samples.end()) {
+ return iter->second;
+ }
+
+ return M44d();
+}
+
+/* get the matrix for the specified time, or interpolate between samples if there is no exact match
+ */
+static M44d get_interpolated_matrix_for_time(const MatrixSampleMap &samples, chrono_t time)
+{
+ if (samples.empty()) {
+ return M44d();
+ }
+
+ /* see if exact match */
+ MatrixSampleMap::const_iterator iter = samples.find(time);
+ if (iter != samples.end()) {
+ return iter->second;
+ }
+
+ if (samples.size() == 1) {
+ return samples.begin()->second;
+ }
+
+ if (time <= samples.begin()->first) {
+ return samples.begin()->second;
+ }
+
+ if (time >= samples.rbegin()->first) {
+ return samples.rbegin()->second;
+ }
+
+ /* find previous and next time sample to interpolate */
+ chrono_t prev_time = samples.begin()->first;
+ chrono_t next_time = samples.rbegin()->first;
+
+ for (MatrixSampleMap::const_iterator I = samples.begin(); I != samples.end(); ++I) {
+ chrono_t current_time = (*I).first;
+
+ if (current_time > prev_time && current_time <= time) {
+ prev_time = current_time;
+ }
+
+ if (current_time > next_time && current_time >= time) {
+ next_time = current_time;
+ }
+ }
+
+ const M44d prev_mat = get_matrix_for_time(samples, prev_time);
+ const M44d next_mat = get_matrix_for_time(samples, next_time);
+
+ V3d prev_scale, next_scale;
+ V3d prev_shear, next_shear;
+ V3d prev_translation, next_translation;
+ Quatd prev_rotation, next_rotation;
+
+ transform_decompose(prev_mat, prev_scale, prev_shear, prev_rotation, prev_translation);
+ transform_decompose(next_mat, next_scale, next_shear, next_rotation, next_translation);
+
+ chrono_t t = (time - prev_time) / (next_time - prev_time);
+
+ /* Ensure rotation around the shortest angle. */
+ if ((prev_rotation ^ next_rotation) < 0) {
+ next_rotation = -next_rotation;
+ }
+
+ return transform_compose(Imath::lerp(prev_scale, next_scale, t),
+ Imath::lerp(prev_shear, next_shear, t),
+ Imath::slerp(prev_rotation, next_rotation, t),
+ Imath::lerp(prev_translation, next_translation, t));
+}
+
+static void concatenate_xform_samples(const MatrixSampleMap &parent_samples,
+ const MatrixSampleMap &local_samples,
+ MatrixSampleMap &output_samples)
+{
+ set<chrono_t> union_of_samples;
+
+ for (const std::pair<chrono_t, M44d> pair : parent_samples) {
+ union_of_samples.insert(pair.first);
+ }
+
+ for (const std::pair<chrono_t, M44d> pair : local_samples) {
+ union_of_samples.insert(pair.first);
+ }
+
+ foreach (chrono_t time, union_of_samples) {
+ M44d parent_matrix = get_interpolated_matrix_for_time(parent_samples, time);
+ M44d local_matrix = get_interpolated_matrix_for_time(local_samples, time);
+
+ output_samples[time] = local_matrix * parent_matrix;
+ }
+}
+
+static Transform make_transform(const M44d &a, float scale)
+{
+ M44d m = convert_yup_zup(a, scale);
+ Transform trans;
+ for (int j = 0; j < 3; j++) {
+ for (int i = 0; i < 4; i++) {
+ trans[j][i] = static_cast<float>(m[i][j]);
+ }
+ }
+ return trans;
+}
+
+NODE_DEFINE(AlembicObject)
+{
+ NodeType *type = NodeType::add("alembic_object", create);
+
+ SOCKET_STRING(path, "Alembic Path", ustring());
+ SOCKET_NODE_ARRAY(used_shaders, "Used Shaders", Shader::get_node_type());
+
+ SOCKET_BOOLEAN(ignore_subdivision, "Ignore Subdivision", true);
+
+ SOCKET_INT(subd_max_level, "Max Subdivision Level", 1);
+ SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 1.0f);
+
+ SOCKET_FLOAT(radius_scale, "Radius Scale", 1.0f);
+
+ return type;
+}
+
+AlembicObject::AlembicObject() : Node(get_node_type())
+{
+ schema_type = INVALID;
+}
+
+AlembicObject::~AlembicObject()
+{
+}
+
+void AlembicObject::set_object(Object *object_)
+{
+ object = object_;
+}
+
+Object *AlembicObject::get_object()
+{
+ return object;
+}
+
+bool AlembicObject::has_data_loaded() const
+{
+ return data_loaded;
+}
+
+void AlembicObject::load_data_in_cache(CachedData &cached_data,
+ AlembicProcedural *proc,
+ IPolyMeshSchema &schema,
+ Progress &progress)
+{
+ /* Only load data for the original Geometry. */
+ if (instance_of) {
+ return;
+ }
+
+ cached_data.clear();
+
+ PolyMeshSchemaData data;
+ data.topology_variance = schema.getTopologyVariance();
+ data.time_sampling = schema.getTimeSampling();
+ data.positions = schema.getPositionsProperty();
+ data.face_counts = schema.getFaceCountsProperty();
+ data.face_indices = schema.getFaceIndicesProperty();
+ data.normals = schema.getNormalsParam();
+ data.num_samples = schema.getNumSamples();
+ data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders());
+
+ read_geometry_data(proc, cached_data, data, progress);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ /* Use the schema as the base compound property to also be able to look for top level properties.
+ */
+ read_attributes(
+ proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ cached_data.invalidate_last_loaded_time(true);
+ data_loaded = true;
+}
+
+void AlembicObject::load_data_in_cache(CachedData &cached_data,
+ AlembicProcedural *proc,
+ ISubDSchema &schema,
+ Progress &progress)
+{
+ /* Only load data for the original Geometry. */
+ if (instance_of) {
+ return;
+ }
+
+ cached_data.clear();
+
+ if (this->get_ignore_subdivision()) {
+ PolyMeshSchemaData data;
+ data.topology_variance = schema.getTopologyVariance();
+ data.time_sampling = schema.getTimeSampling();
+ data.positions = schema.getPositionsProperty();
+ data.face_counts = schema.getFaceCountsProperty();
+ data.face_indices = schema.getFaceIndicesProperty();
+ data.num_samples = schema.getNumSamples();
+ data.velocities = schema.getVelocitiesProperty();
+ data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders());
+
+ read_geometry_data(proc, cached_data, data, progress);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ /* Use the schema as the base compound property to also be able to look for top level
+ * properties. */
+ read_attributes(
+ proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
+
+ cached_data.invalidate_last_loaded_time(true);
+ data_loaded = true;
+ return;
+ }
+
+ SubDSchemaData data;
+ data.time_sampling = schema.getTimeSampling();
+ data.num_samples = schema.getNumSamples();
+ data.topology_variance = schema.getTopologyVariance();
+ data.face_counts = schema.getFaceCountsProperty();
+ data.face_indices = schema.getFaceIndicesProperty();
+ data.positions = schema.getPositionsProperty();
+ data.face_varying_interpolate_boundary = schema.getFaceVaryingInterpolateBoundaryProperty();
+ data.face_varying_propagate_corners = schema.getFaceVaryingPropagateCornersProperty();
+ data.interpolate_boundary = schema.getInterpolateBoundaryProperty();
+ data.crease_indices = schema.getCreaseIndicesProperty();
+ data.crease_lengths = schema.getCreaseLengthsProperty();
+ data.crease_sharpnesses = schema.getCreaseSharpnessesProperty();
+ data.corner_indices = schema.getCornerIndicesProperty();
+ data.corner_sharpnesses = schema.getCornerSharpnessesProperty();
+ data.holes = schema.getHolesProperty();
+ data.subdivision_scheme = schema.getSubdivisionSchemeProperty();
+ data.velocities = schema.getVelocitiesProperty();
+ data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders());
+
+ read_geometry_data(proc, cached_data, data, progress);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ /* Use the schema as the base compound property to also be able to look for top level properties.
+ */
+ read_attributes(
+ proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
+
+ cached_data.invalidate_last_loaded_time(true);
+ data_loaded = true;
+}
+
+void AlembicObject::load_data_in_cache(CachedData &cached_data,
+ AlembicProcedural *proc,
+ const ICurvesSchema &schema,
+ Progress &progress)
+{
+ /* Only load data for the original Geometry. */
+ if (instance_of) {
+ return;
+ }
+
+ cached_data.clear();
+
+ CurvesSchemaData data;
+ data.positions = schema.getPositionsProperty();
+ data.position_weights = schema.getPositionWeightsProperty();
+ data.normals = schema.getNormalsParam();
+ data.knots = schema.getKnotsProperty();
+ data.orders = schema.getOrdersProperty();
+ data.widths = schema.getWidthsParam();
+ data.velocities = schema.getVelocitiesProperty();
+ data.time_sampling = schema.getTimeSampling();
+ data.topology_variance = schema.getTopologyVariance();
+ data.num_samples = schema.getNumSamples();
+ data.num_vertices = schema.getNumVerticesProperty();
+ data.default_radius = proc->get_default_radius();
+ data.radius_scale = get_radius_scale();
+
+ read_geometry_data(proc, cached_data, data, progress);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ /* Use the schema as the base compound property to also be able to look for top level properties.
+ */
+ read_attributes(
+ proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
+
+ cached_data.invalidate_last_loaded_time(true);
+ data_loaded = true;
+}
+
+void AlembicObject::setup_transform_cache(CachedData &cached_data, float scale)
+{
+ cached_data.transforms.clear();
+ cached_data.transforms.invalidate_last_loaded_time();
+
+ if (scale == 0.0f) {
+ scale = 1.0f;
+ }
+
+ if (xform_time_sampling) {
+ cached_data.transforms.set_time_sampling(*xform_time_sampling);
+ }
+
+ if (xform_samples.size() == 0) {
+ Transform tfm = transform_scale(make_float3(scale));
+ cached_data.transforms.add_data(tfm, 0.0);
+ }
+ else {
+ /* It is possible for a leaf node of the hierarchy to have multiple samples for its transforms
+ * if a sibling has animated transforms. So check if we indeed have animated transformations.
+ */
+ M44d first_matrix = xform_samples.begin()->first;
+ bool has_animation = false;
+ for (const std::pair<chrono_t, M44d> pair : xform_samples) {
+ if (pair.second != first_matrix) {
+ has_animation = true;
+ break;
+ }
+ }
+
+ if (!has_animation) {
+ Transform tfm = make_transform(first_matrix, scale);
+ cached_data.transforms.add_data(tfm, 0.0);
+ }
+ else {
+ for (const std::pair<chrono_t, M44d> pair : xform_samples) {
+ Transform tfm = make_transform(pair.second, scale);
+ cached_data.transforms.add_data(tfm, pair.first);
+ }
+ }
+ }
+}
+
+AttributeRequestSet AlembicObject::get_requested_attributes()
+{
+ AttributeRequestSet requested_attributes;
+
+ Geometry *geometry = object->get_geometry();
+ assert(geometry);
+
+ foreach (Node *node, geometry->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+
+ foreach (const AttributeRequest &attr, shader->attributes.requests) {
+ if (attr.name != "") {
+ requested_attributes.add(attr.name);
+ }
+ }
+ }
+
+ return requested_attributes;
+}
+
+/* Update existing attributes and remove any attribute not in the cached_data, those attributes
+ * were added by Cycles (e.g. face normals) */
+static void update_attributes(AttributeSet &attributes, CachedData &cached_data, double frame_time)
+{
+ set<Attribute *> cached_attributes;
+
+ for (CachedData::CachedAttribute &attribute : cached_data.attributes) {
+ const CacheLookupResult<array<char>> result = attribute.data.data_for_time(frame_time);
+
+ if (result.has_no_data_for_time()) {
+ continue;
+ }
+
+ Attribute *attr = nullptr;
+ if (attribute.std != ATTR_STD_NONE) {
+ attr = attributes.add(attribute.std, attribute.name);
+ }
+ else {
+ attr = attributes.add(attribute.name, attribute.type_desc, attribute.element);
+ }
+ assert(attr);
+
+ cached_attributes.insert(attr);
+
+ if (!result.has_new_data()) {
+ continue;
+ }
+
+ const ccl::array<char> &attr_data = result.get_data();
+
+ /* weak way of detecting if the topology has changed
+ * todo: reuse code from device_update patch */
+ if (attr->buffer.size() != attr_data.size()) {
+ attr->buffer.resize(attr_data.size());
+ }
+
+ memcpy(attr->data(), attr_data.data(), attr_data.size());
+ attr->modified = true;
+ }
+
+ /* remove any attributes not in cached_attributes */
+ list<Attribute>::iterator it;
+ for (it = attributes.attributes.begin(); it != attributes.attributes.end();) {
+ if (cached_attributes.find(&(*it)) == cached_attributes.end()) {
+ attributes.remove(it++);
+ continue;
+ }
+
+ it++;
+ }
+}
+
+NODE_DEFINE(AlembicProcedural)
+{
+ NodeType *type = NodeType::add("alembic", create);
+
+ SOCKET_STRING(filepath, "Filename", ustring());
+ SOCKET_FLOAT(frame, "Frame", 1.0f);
+ SOCKET_FLOAT(start_frame, "Start Frame", 1.0f);
+ SOCKET_FLOAT(end_frame, "End Frame", 1.0f);
+ SOCKET_FLOAT(frame_rate, "Frame Rate", 24.0f);
+ SOCKET_FLOAT(frame_offset, "Frame Offset", 0.0f);
+ SOCKET_FLOAT(default_radius, "Default Radius", 0.01f);
+ SOCKET_FLOAT(scale, "Scale", 1.0f);
+
+ SOCKET_NODE_ARRAY(objects, "Objects", AlembicObject::get_node_type());
+
+ SOCKET_BOOLEAN(use_prefetch, "Use Prefetch", true);
+ SOCKET_INT(prefetch_cache_size, "Prefetch Cache Size", 4096);
+
+ return type;
+}
+
+AlembicProcedural::AlembicProcedural() : Procedural(get_node_type())
+{
+ objects_loaded = false;
+ scene_ = nullptr;
+}
+
+AlembicProcedural::~AlembicProcedural()
+{
+ ccl::set<Geometry *> geometries_set;
+ ccl::set<Object *> objects_set;
+ ccl::set<AlembicObject *> abc_objects_set;
+
+ foreach (Node *node, objects) {
+ AlembicObject *abc_object = static_cast<AlembicObject *>(node);
+
+ if (abc_object->get_object()) {
+ objects_set.insert(abc_object->get_object());
+
+ if (abc_object->get_object()->get_geometry()) {
+ geometries_set.insert(abc_object->get_object()->get_geometry());
+ }
+ }
+
+ delete_node(abc_object);
+ }
+
+ /* We may delete a Procedural before rendering started, so scene_ can be null. */
+ if (!scene_) {
+ assert(geometries_set.empty());
+ assert(objects_set.empty());
+ return;
+ }
+
+ scene_->delete_nodes(geometries_set, this);
+ scene_->delete_nodes(objects_set, this);
+}
+
+void AlembicProcedural::generate(Scene *scene, Progress &progress)
+{
+ assert(scene_ == nullptr || scene_ == scene);
+ scene_ = scene;
+
+ if (frame < start_frame || frame > end_frame) {
+ clear_modified();
+ return;
+ }
+
+ bool need_shader_updates = false;
+ bool need_data_updates = false;
+
+ foreach (Node *object_node, objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(object_node);
+
+ if (object->is_modified()) {
+ need_data_updates = true;
+ }
+
+ /* Check if the shaders were modified. */
+ if (object->used_shaders_is_modified() && object->get_object() &&
+ object->get_object()->get_geometry()) {
+ Geometry *geometry = object->get_object()->get_geometry();
+ array<Node *> used_shaders = object->get_used_shaders();
+ geometry->set_used_shaders(used_shaders);
+ need_shader_updates = true;
+ }
+
+ /* Check for changes in shaders (e.g. newly requested attributes). */
+ foreach (Node *shader_node, object->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(shader_node);
+
+ if (shader->need_update_geometry()) {
+ object->need_shader_update = true;
+ need_shader_updates = true;
+ }
+ }
+ }
+
+ if (!is_modified() && !need_shader_updates && !need_data_updates) {
+ return;
+ }
+
+ if (!archive.valid()) {
+ Alembic::AbcCoreFactory::IFactory factory;
+ factory.setPolicy(Alembic::Abc::ErrorHandler::kQuietNoopPolicy);
+ archive = factory.getArchive(filepath.c_str());
+
+ if (!archive.valid()) {
+ /* avoid potential infinite update loops in viewport synchronization */
+ filepath.clear();
+ clear_modified();
+ return;
+ }
+ }
+
+ if (!objects_loaded || objects_is_modified()) {
+ load_objects(progress);
+ objects_loaded = true;
+ }
+
+ const chrono_t frame_time = (chrono_t)((frame - frame_offset) / frame_rate);
+
+ /* Clear the subdivision caches as the data is stored differently. */
+ for (Node *node : objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+
+ if (object->schema_type != AlembicObject::SUBD) {
+ continue;
+ }
+
+ if (object->ignore_subdivision_is_modified()) {
+ object->clear_cache();
+ }
+ }
+
+ if (use_prefetch_is_modified()) {
+ if (!use_prefetch) {
+ for (Node *node : objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+ object->clear_cache();
+ }
+ }
+ }
+
+ if (prefetch_cache_size_is_modified()) {
+ /* Check whether the current memory usage fits in the new requested size,
+ * abort the render if it is any higher. */
+ size_t memory_used = 0ul;
+ for (Node *node : objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+ memory_used += object->get_cached_data().memory_used();
+ }
+
+ if (memory_used > get_prefetch_cache_size_in_bytes()) {
+ progress.set_error("Error: Alembic Procedural memory limit reached");
+ return;
+ }
+ }
+
+ build_caches(progress);
+
+ foreach (Node *node, objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ /* skip constant objects */
+ if (object->is_constant() && !object->is_modified() && !object->need_shader_update &&
+ !scale_is_modified()) {
+ continue;
+ }
+
+ if (object->schema_type == AlembicObject::POLY_MESH) {
+ read_mesh(object, frame_time);
+ }
+ else if (object->schema_type == AlembicObject::CURVES) {
+ read_curves(object, frame_time);
+ }
+ else if (object->schema_type == AlembicObject::SUBD) {
+ read_subd(object, frame_time);
+ }
+
+ object->need_shader_update = false;
+ object->clear_modified();
+ }
+
+ clear_modified();
+}
+
+void AlembicProcedural::add_object(AlembicObject *object)
+{
+ objects.push_back_slow(object);
+ tag_objects_modified();
+}
+
+void AlembicProcedural::tag_update(Scene *scene)
+{
+ scene->procedural_manager->tag_update();
+}
+
+AlembicObject *AlembicProcedural::get_or_create_object(const ustring &path)
+{
+ foreach (Node *node, objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+
+ if (object->get_path() == path) {
+ return object;
+ }
+ }
+
+ AlembicObject *object = create_node<AlembicObject>();
+ object->set_path(path);
+
+ add_object(object);
+
+ return object;
+}
+
+void AlembicProcedural::load_objects(Progress &progress)
+{
+ unordered_map<string, AlembicObject *> object_map;
+
+ foreach (Node *node, objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+
+ /* only consider newly added objects */
+ if (object->get_object() == nullptr) {
+ object_map.insert({object->get_path().c_str(), object});
+ }
+ }
+
+ IObject root = archive.getTop();
+
+ for (size_t i = 0; i < root.getNumChildren(); ++i) {
+ walk_hierarchy(root, root.getChildHeader(i), {}, object_map, progress);
+ }
+
+ /* Create nodes in the scene. */
+ for (std::pair<string, AlembicObject *> pair : object_map) {
+ AlembicObject *abc_object = pair.second;
+
+ Geometry *geometry = nullptr;
+
+ if (!abc_object->instance_of) {
+ if (abc_object->schema_type == AlembicObject::CURVES) {
+ geometry = scene_->create_node<Hair>();
+ }
+ else if (abc_object->schema_type == AlembicObject::POLY_MESH ||
+ abc_object->schema_type == AlembicObject::SUBD) {
+ geometry = scene_->create_node<Mesh>();
+ }
+ else {
+ continue;
+ }
+
+ geometry->set_owner(this);
+ geometry->name = abc_object->iobject.getName();
+
+ array<Node *> used_shaders = abc_object->get_used_shaders();
+ geometry->set_used_shaders(used_shaders);
+ }
+
+ Object *object = scene_->create_node<Object>();
+ object->set_owner(this);
+ object->set_geometry(geometry);
+ object->name = abc_object->iobject.getName();
+
+ abc_object->set_object(object);
+ }
+
+ /* Share geometries between instances. */
+ foreach (Node *node, objects) {
+ AlembicObject *abc_object = static_cast<AlembicObject *>(node);
+
+ if (abc_object->instance_of) {
+ abc_object->get_object()->set_geometry(
+ abc_object->instance_of->get_object()->get_geometry());
+ abc_object->schema_type = abc_object->instance_of->schema_type;
+ }
+ }
+}
+
+void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame_time)
+{
+ CachedData &cached_data = abc_object->get_cached_data();
+
+ /* update sockets */
+
+ Object *object = abc_object->get_object();
+ cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
+
+ if (object->is_modified()) {
+ object->tag_update(scene_);
+ }
+
+ /* Only update sockets for the original Geometry. */
+ if (abc_object->instance_of) {
+ return;
+ }
+
+ Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
+
+ /* Make sure shader ids are also updated. */
+ if (mesh->used_shaders_is_modified()) {
+ mesh->tag_shader_modified();
+ }
+
+ cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
+
+ cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_shader_socket());
+
+ array<int3> *triangle_data = cached_data.triangles.data_for_time(frame_time).get_data_or_null();
+ if (triangle_data) {
+ array<int> triangles;
+ array<bool> smooth;
+
+ triangles.reserve(triangle_data->size() * 3);
+ smooth.reserve(triangle_data->size());
+
+ for (size_t i = 0; i < triangle_data->size(); ++i) {
+ int3 tri = (*triangle_data)[i];
+ triangles.push_back_reserved(tri.x);
+ triangles.push_back_reserved(tri.y);
+ triangles.push_back_reserved(tri.z);
+ smooth.push_back_reserved(1);
+ }
+
+ mesh->set_triangles(triangles);
+ mesh->set_smooth(smooth);
+ }
+
+ /* update attributes */
+
+ update_attributes(mesh->attributes, cached_data, frame_time);
+
+ if (mesh->is_modified()) {
+ bool need_rebuild = mesh->triangles_is_modified();
+ mesh->tag_update(scene_, need_rebuild);
+ }
+}
+
+void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame_time)
+{
+ if (abc_object->get_ignore_subdivision()) {
+ read_mesh(abc_object, frame_time);
+ return;
+ }
+
+ CachedData &cached_data = abc_object->get_cached_data();
+
+ /* Update sockets. */
+
+ Object *object = abc_object->get_object();
+ cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
+
+ if (object->is_modified()) {
+ object->tag_update(scene_);
+ }
+
+ /* Only update sockets for the original Geometry. */
+ if (abc_object->instance_of) {
+ return;
+ }
+
+ if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) {
+ /* need to reset the current data is something changed */
+ cached_data.invalidate_last_loaded_time();
+ }
+
+ Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
+
+ /* Make sure shader ids are also updated. */
+ if (mesh->used_shaders_is_modified()) {
+ mesh->tag_shader_modified();
+ }
+
+ /* Cycles overwrites the original triangles when computing displacement, so we always have to
+ * repass the data if something is animated (vertices most likely) to avoid buffer overflows. */
+ if (!cached_data.is_constant()) {
+ cached_data.invalidate_last_loaded_time();
+
+ /* remove previous triangles, if any */
+ array<int> triangles;
+ mesh->set_triangles(triangles);
+ }
+
+ mesh->clear_non_sockets();
+
+ /* Alembic is OpenSubDiv compliant, there is no option to set another subdivision type. */
+ mesh->set_subdivision_type(Mesh::SubdivisionType::SUBDIVISION_CATMULL_CLARK);
+ mesh->set_subd_max_level(abc_object->get_subd_max_level());
+ mesh->set_subd_dicing_rate(abc_object->get_subd_dicing_rate());
+
+ cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
+
+ /* cached_data.shader is also used for subd_shader */
+ cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_subd_shader_socket());
+
+ cached_data.subd_start_corner.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_start_corner_socket());
+
+ cached_data.subd_num_corners.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_num_corners_socket());
+
+ cached_data.subd_smooth.copy_to_socket(frame_time, mesh, mesh->get_subd_smooth_socket());
+
+ cached_data.subd_ptex_offset.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_ptex_offset_socket());
+
+ cached_data.subd_face_corners.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_face_corners_socket());
+
+ cached_data.num_ngons.copy_to_socket(frame_time, mesh, mesh->get_num_ngons_socket());
+
+ cached_data.subd_creases_edge.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_creases_edge_socket());
+
+ cached_data.subd_creases_weight.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_creases_weight_socket());
+
+ mesh->set_num_subd_faces(mesh->get_subd_shader().size());
+
+ /* Update attributes. */
+
+ update_attributes(mesh->subd_attributes, cached_data, frame_time);
+
+ if (mesh->is_modified()) {
+ bool need_rebuild = (mesh->triangles_is_modified()) ||
+ (mesh->subd_num_corners_is_modified()) ||
+ (mesh->subd_shader_is_modified()) || (mesh->subd_smooth_is_modified()) ||
+ (mesh->subd_ptex_offset_is_modified()) ||
+ (mesh->subd_start_corner_is_modified()) ||
+ (mesh->subd_face_corners_is_modified());
+
+ mesh->tag_update(scene_, need_rebuild);
+ }
+}
+
+void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t frame_time)
+{
+ CachedData &cached_data = abc_object->get_cached_data();
+
+ /* update sockets */
+
+ Object *object = abc_object->get_object();
+ cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
+
+ if (object->is_modified()) {
+ object->tag_update(scene_);
+ }
+
+ /* Only update sockets for the original Geometry. */
+ if (abc_object->instance_of) {
+ return;
+ }
+
+ Hair *hair = static_cast<Hair *>(object->get_geometry());
+
+ /* Make sure shader ids are also updated. */
+ if (hair->used_shaders_is_modified()) {
+ hair->tag_curve_shader_modified();
+ }
+
+ cached_data.curve_keys.copy_to_socket(frame_time, hair, hair->get_curve_keys_socket());
+
+ cached_data.curve_radius.copy_to_socket(frame_time, hair, hair->get_curve_radius_socket());
+
+ cached_data.curve_shader.copy_to_socket(frame_time, hair, hair->get_curve_shader_socket());
+
+ cached_data.curve_first_key.copy_to_socket(frame_time, hair, hair->get_curve_first_key_socket());
+
+ /* update attributes */
+
+ update_attributes(hair->attributes, cached_data, frame_time);
+
+ const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
+ hair->tag_update(scene_, rebuild);
+}
+
+void AlembicProcedural::walk_hierarchy(
+ IObject parent,
+ const ObjectHeader &header,
+ MatrixSamplesData matrix_samples_data,
+ const unordered_map<std::string, AlembicObject *> &object_map,
+ Progress &progress)
+{
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ IObject next_object;
+
+ MatrixSampleMap concatenated_xform_samples;
+
+ if (IXform::matches(header)) {
+ IXform xform(parent, header.getName());
+
+ IXformSchema &xs = xform.getSchema();
+
+ if (xs.getNumOps() > 0) {
+ TimeSamplingPtr ts = xs.getTimeSampling();
+ MatrixSampleMap local_xform_samples;
+
+ MatrixSampleMap *temp_xform_samples = nullptr;
+ if (matrix_samples_data.samples == nullptr) {
+ /* If there is no parent transforms, fill the map directly. */
+ temp_xform_samples = &concatenated_xform_samples;
+ }
+ else {
+ /* use a temporary map */
+ temp_xform_samples = &local_xform_samples;
+ }
+
+ for (size_t i = 0; i < xs.getNumSamples(); ++i) {
+ chrono_t sample_time = ts->getSampleTime(index_t(i));
+ XformSample sample = xs.getValue(ISampleSelector(sample_time));
+ temp_xform_samples->insert({sample_time, sample.getMatrix()});
+ }
+
+ if (matrix_samples_data.samples != nullptr) {
+ concatenate_xform_samples(
+ *matrix_samples_data.samples, local_xform_samples, concatenated_xform_samples);
+ }
+
+ matrix_samples_data.samples = &concatenated_xform_samples;
+ matrix_samples_data.time_sampling = ts;
+ }
+
+ next_object = xform;
+ }
+ else if (ISubD::matches(header)) {
+ ISubD subd(parent, header.getName());
+
+ unordered_map<std::string, AlembicObject *>::const_iterator iter;
+ iter = object_map.find(subd.getFullName());
+
+ if (iter != object_map.end()) {
+ AlembicObject *abc_object = iter->second;
+ abc_object->iobject = subd;
+ abc_object->schema_type = AlembicObject::SUBD;
+
+ if (matrix_samples_data.samples) {
+ abc_object->xform_samples = *matrix_samples_data.samples;
+ abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
+ }
+ }
+
+ next_object = subd;
+ }
+ else if (IPolyMesh::matches(header)) {
+ IPolyMesh mesh(parent, header.getName());
+
+ unordered_map<std::string, AlembicObject *>::const_iterator iter;
+ iter = object_map.find(mesh.getFullName());
+
+ if (iter != object_map.end()) {
+ AlembicObject *abc_object = iter->second;
+ abc_object->iobject = mesh;
+ abc_object->schema_type = AlembicObject::POLY_MESH;
+
+ if (matrix_samples_data.samples) {
+ abc_object->xform_samples = *matrix_samples_data.samples;
+ abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
+ }
+ }
+
+ next_object = mesh;
+ }
+ else if (ICurves::matches(header)) {
+ ICurves curves(parent, header.getName());
+
+ unordered_map<std::string, AlembicObject *>::const_iterator iter;
+ iter = object_map.find(curves.getFullName());
+
+ if (iter != object_map.end()) {
+ AlembicObject *abc_object = iter->second;
+ abc_object->iobject = curves;
+ abc_object->schema_type = AlembicObject::CURVES;
+
+ if (matrix_samples_data.samples) {
+ abc_object->xform_samples = *matrix_samples_data.samples;
+ abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
+ }
+ }
+
+ next_object = curves;
+ }
+ else if (IFaceSet::matches(header)) {
+ // ignore the face set, it will be read along with the data
+ }
+ else if (IPoints::matches(header)) {
+ // unsupported for now
+ }
+ else if (INuPatch::matches(header)) {
+ // unsupported for now
+ }
+ else {
+ next_object = parent.getChild(header.getName());
+
+ if (next_object.isInstanceRoot()) {
+ unordered_map<std::string, AlembicObject *>::const_iterator iter;
+
+ /* Was this object asked to be rendered? */
+ iter = object_map.find(next_object.getFullName());
+
+ if (iter != object_map.end()) {
+ AlembicObject *abc_object = iter->second;
+
+ /* Only try to render an instance if the original object is also rendered. */
+ iter = object_map.find(next_object.instanceSourcePath());
+
+ if (iter != object_map.end()) {
+ abc_object->iobject = next_object;
+ abc_object->instance_of = iter->second;
+
+ if (matrix_samples_data.samples) {
+ abc_object->xform_samples = *matrix_samples_data.samples;
+ abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
+ }
+ }
+ }
+ }
+ }
+
+ if (next_object.valid()) {
+ for (size_t i = 0; i < next_object.getNumChildren(); ++i) {
+ walk_hierarchy(
+ next_object, next_object.getChildHeader(i), matrix_samples_data, object_map, progress);
+ }
+ }
+}
+
+void AlembicProcedural::build_caches(Progress &progress)
+{
+ size_t memory_used = 0;
+
+ for (Node *node : objects) {
+ AlembicObject *object = static_cast<AlembicObject *>(node);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ if (object->schema_type == AlembicObject::POLY_MESH) {
+ if (!object->has_data_loaded()) {
+ IPolyMesh polymesh(object->iobject, Alembic::Abc::kWrapExisting);
+ IPolyMeshSchema schema = polymesh.getSchema();
+ object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
+ }
+ else if (object->need_shader_update) {
+ IPolyMesh polymesh(object->iobject, Alembic::Abc::kWrapExisting);
+ IPolyMeshSchema schema = polymesh.getSchema();
+ read_attributes(this,
+ object->get_cached_data(),
+ schema,
+ schema.getUVsParam(),
+ object->get_requested_attributes(),
+ progress);
+ }
+ }
+ else if (object->schema_type == AlembicObject::CURVES) {
+ if (!object->has_data_loaded() || default_radius_is_modified() ||
+ object->radius_scale_is_modified()) {
+ ICurves curves(object->iobject, Alembic::Abc::kWrapExisting);
+ ICurvesSchema schema = curves.getSchema();
+ object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
+ }
+ }
+ else if (object->schema_type == AlembicObject::SUBD) {
+ if (!object->has_data_loaded()) {
+ ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting);
+ ISubDSchema schema = subd_mesh.getSchema();
+ object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
+ }
+ else if (object->need_shader_update) {
+ ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting);
+ ISubDSchema schema = subd_mesh.getSchema();
+ read_attributes(this,
+ object->get_cached_data(),
+ schema,
+ schema.getUVsParam(),
+ object->get_requested_attributes(),
+ progress);
+ }
+ }
+
+ if (scale_is_modified() || object->get_cached_data().transforms.size() == 0) {
+ object->setup_transform_cache(object->get_cached_data(), scale);
+ }
+
+ memory_used += object->get_cached_data().memory_used();
+
+ if (use_prefetch) {
+ if (memory_used > get_prefetch_cache_size_in_bytes()) {
+ progress.set_error("Error: Alembic Procedural memory limit reached");
+ return;
+ }
+ }
+ }
+
+ VLOG(1) << "AlembicProcedural memory usage : " << string_human_readable_size(memory_used);
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/scene/alembic.h b/intern/cycles/scene/alembic.h
new file mode 100644
index 00000000000..77aafd0ab32
--- /dev/null
+++ b/intern/cycles/scene/alembic.h
@@ -0,0 +1,568 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "graph/node.h"
+#include "scene/attribute.h"
+#include "scene/procedural.h"
+#include "util/set.h"
+#include "util/transform.h"
+#include "util/vector.h"
+
+#ifdef WITH_ALEMBIC
+
+# include <Alembic/AbcCoreFactory/All.h>
+# include <Alembic/AbcGeom/All.h>
+
+CCL_NAMESPACE_BEGIN
+
+class AlembicProcedural;
+class Geometry;
+class Object;
+class Progress;
+class Shader;
+
+using MatrixSampleMap = std::map<Alembic::Abc::chrono_t, Alembic::Abc::M44d>;
+
+struct MatrixSamplesData {
+ MatrixSampleMap *samples = nullptr;
+ Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling;
+};
+
+/* Helpers to detect if some type is a `ccl::array`. */
+template<typename> struct is_array : public std::false_type {
+};
+
+template<typename T> struct is_array<array<T>> : public std::true_type {
+};
+
+/* Holds the data for a cache lookup at a given time, as well as information to
+ * help disambiguate successes or failures to get data from the cache. */
+template<typename T> class CacheLookupResult {
+ enum class State {
+ NEW_DATA,
+ ALREADY_LOADED,
+ NO_DATA_FOR_TIME,
+ };
+
+ T *data;
+ State state;
+
+ protected:
+ /* Prevent default construction outside of the class: for a valid result, we
+ * should use the static functions below. */
+ CacheLookupResult() = default;
+
+ public:
+ static CacheLookupResult new_data(T *data_)
+ {
+ CacheLookupResult result;
+ result.data = data_;
+ result.state = State::NEW_DATA;
+ return result;
+ }
+
+ static CacheLookupResult no_data_found_for_time()
+ {
+ CacheLookupResult result;
+ result.data = nullptr;
+ result.state = State::NO_DATA_FOR_TIME;
+ return result;
+ }
+
+ static CacheLookupResult already_loaded()
+ {
+ CacheLookupResult result;
+ result.data = nullptr;
+ result.state = State::ALREADY_LOADED;
+ return result;
+ }
+
+ /* This should only be call if new data is available. */
+ const T &get_data() const
+ {
+ assert(state == State::NEW_DATA);
+ assert(data != nullptr);
+ return *data;
+ }
+
+ T *get_data_or_null() const
+ {
+ // data_ should already be null if there is no new data so no need to check
+ return data;
+ }
+
+ bool has_new_data() const
+ {
+ return state == State::NEW_DATA;
+ }
+
+ bool has_already_loaded() const
+ {
+ return state == State::ALREADY_LOADED;
+ }
+
+ bool has_no_data_for_time() const
+ {
+ return state == State::NO_DATA_FOR_TIME;
+ }
+};
+
+/* Store the data set for an animation at every time points, or at the beginning of the animation
+ * for constant data.
+ *
+ * The data is supposed to be stored in chronological order, and is looked up using the current
+ * animation time in seconds using the TimeSampling from the Alembic property. */
+template<typename T> class DataStore {
+ /* Holds information to map a cache entry for a given time to an index into the data array. */
+ struct TimeIndexPair {
+ /* Frame time for this entry. */
+ double time = 0;
+ /* Frame time for the data pointed to by `index`. */
+ double source_time = 0;
+ /* Index into the data array. */
+ size_t index = 0;
+ };
+
+ /* This is the actual data that is stored. We deduplicate data across frames to avoid storing
+ * values if they have not changed yet (e.g. the triangles for a building before fracturing, or a
+ * fluid simulation before a break or splash) */
+ vector<T> data{};
+
+ /* This is used to map they entry for a given time to an index into the data array, multiple
+ * frames can point to the same index. */
+ vector<TimeIndexPair> index_data_map{};
+
+ Alembic::AbcCoreAbstract::TimeSampling time_sampling{};
+
+ double last_loaded_time = std::numeric_limits<double>::max();
+
+ public:
+ /* Keys used to compare values. */
+ Alembic::AbcCoreAbstract::ArraySample::Key key1;
+ Alembic::AbcCoreAbstract::ArraySample::Key key2;
+
+ void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling_)
+ {
+ time_sampling = time_sampling_;
+ }
+
+ Alembic::AbcCoreAbstract::TimeSampling get_time_sampling() const
+ {
+ return time_sampling;
+ }
+
+ /* Get the data for the specified time.
+ * Return nullptr if there is no data or if the data for this time was already loaded. */
+ CacheLookupResult<T> data_for_time(double time)
+ {
+ if (size() == 0) {
+ return CacheLookupResult<T>::no_data_found_for_time();
+ }
+
+ const TimeIndexPair &index = get_index_for_time(time);
+
+ if (index.index == -1ul) {
+ return CacheLookupResult<T>::no_data_found_for_time();
+ }
+
+ if (last_loaded_time == index.time || last_loaded_time == index.source_time) {
+ return CacheLookupResult<T>::already_loaded();
+ }
+
+ last_loaded_time = index.source_time;
+
+ assert(index.index < data.size());
+
+ return CacheLookupResult<T>::new_data(&data[index.index]);
+ }
+
+ /* get the data for the specified time, but do not check if the data was already loaded for this
+ * time return nullptr if there is no data */
+ CacheLookupResult<T> data_for_time_no_check(double time)
+ {
+ if (size() == 0) {
+ return CacheLookupResult<T>::no_data_found_for_time();
+ }
+
+ const TimeIndexPair &index = get_index_for_time(time);
+
+ if (index.index == -1ul) {
+ return CacheLookupResult<T>::no_data_found_for_time();
+ }
+
+ assert(index.index < data.size());
+
+ return CacheLookupResult<T>::new_data(&data[index.index]);
+ }
+
+ void add_data(T &data_, double time)
+ {
+ index_data_map.push_back({time, time, data.size()});
+
+ if constexpr (is_array<T>::value) {
+ data.emplace_back();
+ data.back().steal_data(data_);
+ return;
+ }
+
+ data.push_back(data_);
+ }
+
+ void reuse_data_for_last_time(double time)
+ {
+ const TimeIndexPair &data_index = index_data_map.back();
+ index_data_map.push_back({time, data_index.source_time, data_index.index});
+ }
+
+ void add_no_data(double time)
+ {
+ index_data_map.push_back({time, time, -1ul});
+ }
+
+ bool is_constant() const
+ {
+ return data.size() <= 1;
+ }
+
+ size_t size() const
+ {
+ return data.size();
+ }
+
+ void clear()
+ {
+ invalidate_last_loaded_time();
+ data.clear();
+ index_data_map.clear();
+ }
+
+ void invalidate_last_loaded_time()
+ {
+ last_loaded_time = std::numeric_limits<double>::max();
+ }
+
+ /* Copy the data for the specified time to the node's socket. If there is no
+ * data for this time or it was already loaded, do nothing. */
+ void copy_to_socket(double time, Node *node, const SocketType *socket)
+ {
+ CacheLookupResult<T> result = data_for_time(time);
+
+ if (!result.has_new_data()) {
+ return;
+ }
+
+ /* TODO(kevindietrich): arrays are emptied when passed to the sockets, so for now we copy the
+ * arrays to avoid reloading the data */
+ T value = result.get_data();
+ node->set(*socket, value);
+ }
+
+ size_t memory_used() const
+ {
+ if constexpr (is_array<T>::value) {
+ size_t mem_used = 0;
+
+ for (const T &array : data) {
+ mem_used += array.size() * sizeof(array[0]);
+ }
+
+ return mem_used;
+ }
+
+ return data.size() * sizeof(T);
+ }
+
+ private:
+ const TimeIndexPair &get_index_for_time(double time) const
+ {
+ std::pair<size_t, Alembic::Abc::chrono_t> index_pair;
+ index_pair = time_sampling.getNearIndex(time, index_data_map.size());
+ return index_data_map[index_pair.first];
+ }
+};
+
+/* Actual cache for the stored data.
+ * This caches the topological, transformation, and attribute data for a Mesh node or a Hair node
+ * inside of DataStores.
+ */
+struct CachedData {
+ DataStore<Transform> transforms{};
+
+ /* mesh data */
+ DataStore<array<float3>> vertices;
+ DataStore<array<int3>> triangles{};
+ /* triangle "loops" are the polygons' vertices indices used for indexing face varying attributes
+ * (like UVs) */
+ DataStore<array<int>> uv_loops{};
+ DataStore<array<int>> shader{};
+
+ /* subd data */
+ DataStore<array<int>> subd_start_corner;
+ DataStore<array<int>> subd_num_corners;
+ DataStore<array<bool>> subd_smooth;
+ DataStore<array<int>> subd_ptex_offset;
+ DataStore<array<int>> subd_face_corners;
+ DataStore<int> num_ngons;
+ DataStore<array<int>> subd_creases_edge;
+ DataStore<array<float>> subd_creases_weight;
+
+ /* hair data */
+ DataStore<array<float3>> curve_keys;
+ DataStore<array<float>> curve_radius;
+ DataStore<array<int>> curve_first_key;
+ DataStore<array<int>> curve_shader;
+
+ struct CachedAttribute {
+ AttributeStandard std;
+ AttributeElement element;
+ TypeDesc type_desc;
+ ustring name;
+ DataStore<array<char>> data{};
+ };
+
+ vector<CachedAttribute> attributes{};
+
+ void clear();
+
+ CachedAttribute &add_attribute(const ustring &name,
+ const Alembic::Abc::TimeSampling &time_sampling);
+
+ bool is_constant() const;
+
+ void invalidate_last_loaded_time(bool attributes_only = false);
+
+ void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling);
+
+ size_t memory_used() const;
+};
+
+/* Representation of an Alembic object for the AlembicProcedural.
+ *
+ * The AlembicObject holds the path to the Alembic IObject inside of the archive that is desired
+ * for rendering, as well as the list of shaders that it is using.
+ *
+ * The names of the shaders should correspond to the names of the FaceSets inside of the Alembic
+ * archive for per-triangle shader association. If there is no FaceSets, or the names do not
+ * match, the first shader is used for rendering for all triangles.
+ */
+class AlembicObject : public Node {
+ public:
+ NODE_DECLARE
+
+ /* Path to the IObject inside of the archive. */
+ NODE_SOCKET_API(ustring, path)
+
+ /* Shaders used for rendering. */
+ NODE_SOCKET_API_ARRAY(array<Node *>, used_shaders)
+
+ /* Treat this subdivision object as a regular polygon mesh, so no subdivision will be performed.
+ */
+ NODE_SOCKET_API(bool, ignore_subdivision)
+
+ /* Maximum number of subdivisions for ISubD objects. */
+ NODE_SOCKET_API(int, subd_max_level)
+
+ /* Finest level of detail (in pixels) for the subdivision. */
+ NODE_SOCKET_API(float, subd_dicing_rate)
+
+ /* Scale the radius of points and curves. */
+ NODE_SOCKET_API(float, radius_scale)
+
+ AlembicObject();
+ ~AlembicObject();
+
+ private:
+ friend class AlembicProcedural;
+
+ void set_object(Object *object);
+ Object *get_object();
+
+ void load_data_in_cache(CachedData &cached_data,
+ AlembicProcedural *proc,
+ Alembic::AbcGeom::IPolyMeshSchema &schema,
+ Progress &progress);
+ void load_data_in_cache(CachedData &cached_data,
+ AlembicProcedural *proc,
+ Alembic::AbcGeom::ISubDSchema &schema,
+ Progress &progress);
+ void load_data_in_cache(CachedData &cached_data,
+ AlembicProcedural *proc,
+ const Alembic::AbcGeom::ICurvesSchema &schema,
+ Progress &progress);
+
+ bool has_data_loaded() const;
+
+ /* Enumeration used to speed up the discrimination of an IObject as IObject::matches() methods
+ * are too expensive and show up in profiles. */
+ enum AbcSchemaType {
+ INVALID,
+ POLY_MESH,
+ SUBD,
+ CURVES,
+ };
+
+ bool need_shader_update = true;
+
+ AlembicObject *instance_of = nullptr;
+
+ Alembic::AbcCoreAbstract::TimeSamplingPtr xform_time_sampling;
+ MatrixSampleMap xform_samples;
+ Alembic::AbcGeom::IObject iobject;
+
+ /* Set if the path points to a valid IObject whose type is supported. */
+ AbcSchemaType schema_type;
+
+ CachedData &get_cached_data()
+ {
+ return cached_data_;
+ }
+
+ bool is_constant() const
+ {
+ return cached_data_.is_constant();
+ }
+
+ void clear_cache()
+ {
+ cached_data_.clear();
+ }
+
+ Object *object = nullptr;
+
+ bool data_loaded = false;
+
+ CachedData cached_data_;
+
+ void setup_transform_cache(CachedData &cached_data, float scale);
+
+ AttributeRequestSet get_requested_attributes();
+};
+
+/* Procedural to render objects from a single Alembic archive.
+ *
+ * Every object desired to be rendered should be passed as an AlembicObject through the objects
+ * socket.
+ *
+ * This procedural will load the data set for the entire animation in memory on the first frame,
+ * and directly set the data for the new frames on the created Nodes if needed. This allows for
+ * faster updates between frames as it avoids reseeking the data on disk.
+ */
+class AlembicProcedural : public Procedural {
+ Alembic::AbcGeom::IArchive archive;
+ bool objects_loaded;
+ Scene *scene_;
+
+ public:
+ NODE_DECLARE
+
+ /* The file path to the Alembic archive */
+ NODE_SOCKET_API(ustring, filepath)
+
+ /* The current frame to render. */
+ NODE_SOCKET_API(float, frame)
+
+ /* The first frame to load data for. */
+ NODE_SOCKET_API(float, start_frame)
+
+ /* The last frame to load data for. */
+ NODE_SOCKET_API(float, end_frame)
+
+ /* Subtracted to the current frame. */
+ NODE_SOCKET_API(float, frame_offset)
+
+ /* The frame rate used for rendering in units of frames per second. */
+ NODE_SOCKET_API(float, frame_rate)
+
+ /* List of AlembicObjects to render. */
+ NODE_SOCKET_API_ARRAY(array<Node *>, objects)
+
+ /* Set the default radius to use for curves when the Alembic Curves Schemas do not have radius
+ * information. */
+ NODE_SOCKET_API(float, default_radius)
+
+ /* Multiplier to account for differences in default units for measuring objects in various
+ * software. */
+ NODE_SOCKET_API(float, scale)
+
+ /* Cache controls */
+ NODE_SOCKET_API(bool, use_prefetch)
+
+ /* Memory limit for the cache, if the data does not fit within this limit, rendering is aborted.
+ */
+ NODE_SOCKET_API(int, prefetch_cache_size)
+
+ AlembicProcedural();
+ ~AlembicProcedural();
+
+ /* Populates the Cycles scene with Nodes for every contained AlembicObject on the first
+ * invocation, and updates the data on subsequent invocations if the frame changed. */
+ void generate(Scene *scene, Progress &progress);
+
+ /* Tag for an update only if something was modified. */
+ void tag_update(Scene *scene);
+
+ /* This should be called by scene exporters to request the rendering of an object located
+ * in the Alembic archive at the given path.
+ *
+ * Since we lazily load object, the function does not validate the existence of the object
+ * in the archive. If no objects with such path if found in the archive during the next call
+ * to `generate`, it will be ignored.
+ *
+ * Returns a pointer to an existing or a newly created AlembicObject for the given path. */
+ AlembicObject *get_or_create_object(const ustring &path);
+
+ private:
+ /* Add an object to our list of objects, and tag the socket as modified. */
+ void add_object(AlembicObject *object);
+
+ /* Load the data for all the objects whose data has not yet been loaded. */
+ void load_objects(Progress &progress);
+
+ /* Traverse the Alembic hierarchy to lookup the IObjects for the AlembicObjects that were
+ * specified in our objects socket, and accumulate all of the transformations samples along the
+ * way for each IObject. */
+ void walk_hierarchy(Alembic::AbcGeom::IObject parent,
+ const Alembic::AbcGeom::ObjectHeader &ohead,
+ MatrixSamplesData matrix_samples_data,
+ const unordered_map<string, AlembicObject *> &object_map,
+ Progress &progress);
+
+ /* Read the data for an IPolyMesh at the specified frame_time. Creates corresponding Geometry and
+ * Object Nodes in the Cycles scene if none exist yet. */
+ void read_mesh(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
+
+ /* Read the data for an ICurves at the specified frame_time. Creates corresponding Geometry and
+ * Object Nodes in the Cycles scene if none exist yet. */
+ void read_curves(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
+
+ /* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and
+ * Object Nodes in the Cycles scene if none exist yet. */
+ void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
+
+ void build_caches(Progress &progress);
+
+ size_t get_prefetch_cache_size_in_bytes() const
+ {
+ /* prefetch_cache_size is in megabytes, so convert to bytes. */
+ return static_cast<size_t>(prefetch_cache_size) * 1024 * 1024;
+ }
+};
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/scene/alembic_read.cpp b/intern/cycles/scene/alembic_read.cpp
new file mode 100644
index 00000000000..35f4854127a
--- /dev/null
+++ b/intern/cycles/scene/alembic_read.cpp
@@ -0,0 +1,1037 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/alembic_read.h"
+#include "scene/alembic.h"
+#include "scene/mesh.h"
+
+#include "util/color.h"
+#include "util/progress.h"
+
+#ifdef WITH_ALEMBIC
+
+using namespace Alembic::AbcGeom;
+
+CCL_NAMESPACE_BEGIN
+
+static float3 make_float3_from_yup(const V3f &v)
+{
+ return make_float3(v.x, -v.z, v.y);
+}
+
+/* get the sample times to load data for the given the start and end frame of the procedural */
+static set<chrono_t> get_relevant_sample_times(AlembicProcedural *proc,
+ const TimeSampling &time_sampling,
+ size_t num_samples)
+{
+ set<chrono_t> result;
+
+ if (num_samples < 2) {
+ result.insert(0.0);
+ return result;
+ }
+
+ double start_frame;
+ double end_frame;
+
+ if (proc->get_use_prefetch()) {
+ // load the data for the entire animation
+ start_frame = static_cast<double>(proc->get_start_frame());
+ end_frame = static_cast<double>(proc->get_end_frame());
+ }
+ else {
+ // load the data for the current frame
+ start_frame = static_cast<double>(proc->get_frame());
+ end_frame = start_frame;
+ }
+
+ const double frame_rate = static_cast<double>(proc->get_frame_rate());
+ const double start_time = start_frame / frame_rate;
+ const double end_time = (end_frame + 1) / frame_rate;
+
+ const size_t start_index = time_sampling.getFloorIndex(start_time, num_samples).first;
+ const size_t end_index = time_sampling.getCeilIndex(end_time, num_samples).first;
+
+ for (size_t i = start_index; i < end_index; ++i) {
+ result.insert(time_sampling.getSampleTime(i));
+ }
+
+ return result;
+}
+
+/* Main function to read data, this will iterate over all the relevant sample times for the
+ * duration of the requested animation, and call the DataReadingFunc for each of those sample time.
+ */
+template<typename Params, typename DataReadingFunc>
+static void read_data_loop(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const Params &params,
+ DataReadingFunc &&func,
+ Progress &progress)
+{
+ const std::set<chrono_t> times = get_relevant_sample_times(
+ proc, *params.time_sampling, params.num_samples);
+
+ cached_data.set_time_sampling(*params.time_sampling);
+
+ for (chrono_t time : times) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ func(cached_data, params, time);
+ }
+}
+
+/* Polygon Mesh Geometries. */
+
+/* Compute the vertex normals in case none are present in the IPolyMeshSchema, this is mostly used
+ * to avoid computing them in the GeometryManager in order to speed up data updates. */
+static void compute_vertex_normals(CachedData &cache, double current_time)
+{
+ if (cache.vertices.size() == 0) {
+ return;
+ }
+
+ CachedData::CachedAttribute &attr_normal = cache.add_attribute(
+ ustring("N"), cache.vertices.get_time_sampling());
+ attr_normal.std = ATTR_STD_VERTEX_NORMAL;
+ attr_normal.element = ATTR_ELEMENT_VERTEX;
+ attr_normal.type_desc = TypeNormal;
+
+ const array<float3> *vertices =
+ cache.vertices.data_for_time_no_check(current_time).get_data_or_null();
+ const array<int3> *triangles =
+ cache.triangles.data_for_time_no_check(current_time).get_data_or_null();
+
+ if (!vertices || !triangles) {
+ attr_normal.data.add_no_data(current_time);
+ return;
+ }
+
+ array<char> attr_data(vertices->size() * sizeof(float3));
+ float3 *attr_ptr = reinterpret_cast<float3 *>(attr_data.data());
+ memset(attr_ptr, 0, vertices->size() * sizeof(float3));
+
+ for (size_t t = 0; t < triangles->size(); ++t) {
+ const int3 tri_int3 = triangles->data()[t];
+ Mesh::Triangle tri{};
+ tri.v[0] = tri_int3[0];
+ tri.v[1] = tri_int3[1];
+ tri.v[2] = tri_int3[2];
+
+ const float3 tri_N = tri.compute_normal(vertices->data());
+
+ for (int v = 0; v < 3; ++v) {
+ attr_ptr[tri_int3[v]] += tri_N;
+ }
+ }
+
+ for (size_t v = 0; v < vertices->size(); ++v) {
+ attr_ptr[v] = normalize(attr_ptr[v]);
+ }
+
+ attr_normal.data.add_data(attr_data, current_time);
+}
+
+static void add_normals(const Int32ArraySamplePtr face_indices,
+ const IN3fGeomParam &normals,
+ double time,
+ CachedData &cached_data)
+{
+ switch (normals.getScope()) {
+ case kFacevaryingScope: {
+ const ISampleSelector iss = ISampleSelector(time);
+ const IN3fGeomParam::Sample sample = normals.getExpandedValue(iss);
+
+ if (!sample.valid()) {
+ return;
+ }
+
+ CachedData::CachedAttribute &attr = cached_data.add_attribute(ustring(normals.getName()),
+ *normals.getTimeSampling());
+ attr.std = ATTR_STD_VERTEX_NORMAL;
+
+ const array<float3> *vertices =
+ cached_data.vertices.data_for_time_no_check(time).get_data_or_null();
+
+ if (!vertices) {
+ return;
+ }
+
+ array<char> data;
+ data.resize(vertices->size() * sizeof(float3));
+
+ float3 *data_float3 = reinterpret_cast<float3 *>(data.data());
+
+ const int *face_indices_array = face_indices->get();
+ const N3fArraySamplePtr values = sample.getVals();
+
+ for (size_t i = 0; i < face_indices->size(); ++i) {
+ int point_index = face_indices_array[i];
+ data_float3[point_index] = make_float3_from_yup(values->get()[i]);
+ }
+
+ attr.data.add_data(data, time);
+ break;
+ }
+ case kVaryingScope:
+ case kVertexScope: {
+ const ISampleSelector iss = ISampleSelector(time);
+ const IN3fGeomParam::Sample sample = normals.getExpandedValue(iss);
+
+ if (!sample.valid()) {
+ return;
+ }
+
+ CachedData::CachedAttribute &attr = cached_data.add_attribute(ustring(normals.getName()),
+ *normals.getTimeSampling());
+ attr.std = ATTR_STD_VERTEX_NORMAL;
+
+ const array<float3> *vertices =
+ cached_data.vertices.data_for_time_no_check(time).get_data_or_null();
+
+ if (!vertices) {
+ return;
+ }
+
+ array<char> data;
+ data.resize(vertices->size() * sizeof(float3));
+
+ float3 *data_float3 = reinterpret_cast<float3 *>(data.data());
+
+ const Imath::V3f *values = sample.getVals()->get();
+
+ for (size_t i = 0; i < vertices->size(); ++i) {
+ data_float3[i] = make_float3_from_yup(values[i]);
+ }
+
+ attr.data.add_data(data, time);
+
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+static void add_positions(const P3fArraySamplePtr positions, double time, CachedData &cached_data)
+{
+ if (!positions) {
+ return;
+ }
+
+ array<float3> vertices;
+ vertices.reserve(positions->size());
+
+ for (size_t i = 0; i < positions->size(); i++) {
+ V3f f = positions->get()[i];
+ vertices.push_back_reserved(make_float3_from_yup(f));
+ }
+
+ cached_data.vertices.add_data(vertices, time);
+}
+
+static void add_triangles(const Int32ArraySamplePtr face_counts,
+ const Int32ArraySamplePtr face_indices,
+ double time,
+ CachedData &cached_data,
+ const array<int> &polygon_to_shader)
+{
+ if (!face_counts || !face_indices) {
+ return;
+ }
+
+ const size_t num_faces = face_counts->size();
+ const int *face_counts_array = face_counts->get();
+ const int *face_indices_array = face_indices->get();
+
+ size_t num_triangles = 0;
+ for (size_t i = 0; i < face_counts->size(); i++) {
+ num_triangles += face_counts_array[i] - 2;
+ }
+
+ array<int> shader;
+ array<int3> triangles;
+ array<int> uv_loops;
+ shader.reserve(num_triangles);
+ triangles.reserve(num_triangles);
+ uv_loops.reserve(num_triangles * 3);
+ int index_offset = 0;
+
+ for (size_t i = 0; i < num_faces; i++) {
+ int current_shader = 0;
+
+ if (!polygon_to_shader.empty()) {
+ current_shader = polygon_to_shader[i];
+ }
+
+ for (int j = 0; j < face_counts_array[i] - 2; j++) {
+ int v0 = face_indices_array[index_offset];
+ int v1 = face_indices_array[index_offset + j + 1];
+ int v2 = face_indices_array[index_offset + j + 2];
+
+ shader.push_back_reserved(current_shader);
+
+ /* Alembic orders the loops following the RenderMan convention, so need to go in reverse. */
+ triangles.push_back_reserved(make_int3(v2, v1, v0));
+ uv_loops.push_back_reserved(index_offset + j + 2);
+ uv_loops.push_back_reserved(index_offset + j + 1);
+ uv_loops.push_back_reserved(index_offset);
+ }
+
+ index_offset += face_counts_array[i];
+ }
+
+ cached_data.triangles.add_data(triangles, time);
+ cached_data.uv_loops.add_data(uv_loops, time);
+ cached_data.shader.add_data(shader, time);
+}
+
+static array<int> compute_polygon_to_shader_map(
+ const Int32ArraySamplePtr &face_counts,
+ const vector<FaceSetShaderIndexPair> &face_set_shader_index,
+ ISampleSelector sample_sel)
+{
+ if (face_set_shader_index.empty()) {
+ return {};
+ }
+
+ if (!face_counts) {
+ return {};
+ }
+
+ if (face_counts->size() == 0) {
+ return {};
+ }
+
+ array<int> polygon_to_shader(face_counts->size());
+
+ for (const FaceSetShaderIndexPair &pair : face_set_shader_index) {
+ const IFaceSet &face_set = pair.face_set;
+ const IFaceSetSchema face_schem = face_set.getSchema();
+ const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel);
+ const Int32ArraySamplePtr group_faces = face_sample.getFaces();
+ const size_t num_group_faces = group_faces->size();
+
+ for (size_t l = 0; l < num_group_faces; l++) {
+ size_t pos = (*group_faces)[l];
+
+ if (pos >= polygon_to_shader.size()) {
+ continue;
+ }
+
+ polygon_to_shader[pos] = pair.shader_index;
+ }
+ }
+
+ return polygon_to_shader;
+}
+
+static void read_poly_mesh_geometry(CachedData &cached_data,
+ const PolyMeshSchemaData &data,
+ chrono_t time)
+{
+ const ISampleSelector iss = ISampleSelector(time);
+
+ add_positions(data.positions.getValue(iss), time, cached_data);
+
+ const Int32ArraySamplePtr face_counts = data.face_counts.getValue(iss);
+ const Int32ArraySamplePtr face_indices = data.face_indices.getValue(iss);
+
+ /* Only copy triangles for other frames if the topology is changing over time as well. */
+ if (data.topology_variance != kHomogeneousTopology || cached_data.triangles.size() == 0) {
+ bool do_triangles = true;
+
+ /* Compare key with last one to check whether the topology changed. */
+ if (cached_data.triangles.size() > 0) {
+ const ArraySample::Key key = face_indices->getKey();
+
+ if (key == cached_data.triangles.key1) {
+ do_triangles = false;
+ }
+
+ cached_data.triangles.key1 = key;
+ }
+
+ if (do_triangles) {
+ const array<int> polygon_to_shader = compute_polygon_to_shader_map(
+ face_counts, data.shader_face_sets, iss);
+ add_triangles(face_counts, face_indices, time, cached_data, polygon_to_shader);
+ }
+ else {
+ cached_data.triangles.reuse_data_for_last_time(time);
+ cached_data.uv_loops.reuse_data_for_last_time(time);
+ cached_data.shader.reuse_data_for_last_time(time);
+ }
+
+ /* Initialize the first key. */
+ if (data.topology_variance != kHomogeneousTopology && cached_data.triangles.size() == 1) {
+ cached_data.triangles.key1 = face_indices->getKey();
+ }
+ }
+
+ if (data.normals.valid()) {
+ add_normals(face_indices, data.normals, time, cached_data);
+ }
+ else {
+ compute_vertex_normals(cached_data, time);
+ }
+}
+
+void read_geometry_data(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const PolyMeshSchemaData &data,
+ Progress &progress)
+{
+ read_data_loop(proc, cached_data, data, read_poly_mesh_geometry, progress);
+}
+
+/* Subdivision Geometries */
+
+static void add_subd_polygons(CachedData &cached_data, const SubDSchemaData &data, chrono_t time)
+{
+ const ISampleSelector iss = ISampleSelector(time);
+
+ const Int32ArraySamplePtr face_counts = data.face_counts.getValue(iss);
+ const Int32ArraySamplePtr face_indices = data.face_indices.getValue(iss);
+
+ array<int> subd_start_corner;
+ array<int> shader;
+ array<int> subd_num_corners;
+ array<bool> subd_smooth;
+ array<int> subd_ptex_offset;
+ array<int> subd_face_corners;
+ array<int> uv_loops;
+
+ const size_t num_faces = face_counts->size();
+ const int *face_counts_array = face_counts->get();
+ const int *face_indices_array = face_indices->get();
+
+ int num_ngons = 0;
+ int num_corners = 0;
+ for (size_t i = 0; i < face_counts->size(); i++) {
+ num_ngons += (face_counts_array[i] == 4 ? 0 : 1);
+ num_corners += face_counts_array[i];
+ }
+
+ subd_start_corner.reserve(num_faces);
+ subd_num_corners.reserve(num_faces);
+ subd_smooth.reserve(num_faces);
+ subd_ptex_offset.reserve(num_faces);
+ shader.reserve(num_faces);
+ subd_face_corners.reserve(num_corners);
+ uv_loops.reserve(num_corners);
+
+ int start_corner = 0;
+ int current_shader = 0;
+ int ptex_offset = 0;
+
+ const array<int> polygon_to_shader = compute_polygon_to_shader_map(
+ face_counts, data.shader_face_sets, iss);
+
+ for (size_t i = 0; i < face_counts->size(); i++) {
+ num_corners = face_counts_array[i];
+
+ if (!polygon_to_shader.empty()) {
+ current_shader = polygon_to_shader[i];
+ }
+
+ subd_start_corner.push_back_reserved(start_corner);
+ subd_num_corners.push_back_reserved(num_corners);
+
+ for (int j = 0; j < num_corners; ++j) {
+ subd_face_corners.push_back_reserved(face_indices_array[start_corner + j]);
+ uv_loops.push_back_reserved(start_corner + j);
+ }
+
+ shader.push_back_reserved(current_shader);
+ subd_smooth.push_back_reserved(1);
+ subd_ptex_offset.push_back_reserved(ptex_offset);
+
+ ptex_offset += (num_corners == 4 ? 1 : num_corners);
+
+ start_corner += num_corners;
+ }
+
+ cached_data.shader.add_data(shader, time);
+ cached_data.subd_start_corner.add_data(subd_start_corner, time);
+ cached_data.subd_num_corners.add_data(subd_num_corners, time);
+ cached_data.subd_smooth.add_data(subd_smooth, time);
+ cached_data.subd_ptex_offset.add_data(subd_ptex_offset, time);
+ cached_data.subd_face_corners.add_data(subd_face_corners, time);
+ cached_data.num_ngons.add_data(num_ngons, time);
+ cached_data.uv_loops.add_data(uv_loops, time);
+}
+
+static void add_subd_creases(CachedData &cached_data, const SubDSchemaData &data, chrono_t time)
+{
+ if (!(data.crease_indices.valid() && data.crease_indices.valid() &&
+ data.crease_sharpnesses.valid())) {
+ return;
+ }
+
+ const ISampleSelector iss = ISampleSelector(time);
+
+ const Int32ArraySamplePtr creases_length = data.crease_lengths.getValue(iss);
+ const Int32ArraySamplePtr creases_indices = data.crease_indices.getValue(iss);
+ const FloatArraySamplePtr creases_sharpnesses = data.crease_sharpnesses.getValue(iss);
+
+ if (creases_length && creases_indices && creases_sharpnesses) {
+ array<int> creases_edge;
+ array<float> creases_weight;
+
+ creases_edge.reserve(creases_sharpnesses->size() * 2);
+ creases_weight.reserve(creases_sharpnesses->size());
+
+ int length_offset = 0;
+ int weight_offset = 0;
+ for (size_t c = 0; c < creases_length->size(); ++c) {
+ const int crease_length = creases_length->get()[c];
+
+ for (size_t j = 0; j < crease_length - 1; ++j) {
+ creases_edge.push_back_reserved(creases_indices->get()[length_offset + j]);
+ creases_edge.push_back_reserved(creases_indices->get()[length_offset + j + 1]);
+ creases_weight.push_back_reserved(creases_sharpnesses->get()[weight_offset++]);
+ }
+
+ length_offset += crease_length;
+ }
+
+ cached_data.subd_creases_edge.add_data(creases_edge, time);
+ cached_data.subd_creases_weight.add_data(creases_weight, time);
+ }
+}
+
+static void read_subd_geometry(CachedData &cached_data, const SubDSchemaData &data, chrono_t time)
+{
+ const ISampleSelector iss = ISampleSelector(time);
+
+ add_positions(data.positions.getValue(iss), time, cached_data);
+
+ if (data.topology_variance != kHomogenousTopology || cached_data.shader.size() == 0) {
+ add_subd_polygons(cached_data, data, time);
+ add_subd_creases(cached_data, data, time);
+ }
+}
+
+void read_geometry_data(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const SubDSchemaData &data,
+ Progress &progress)
+{
+ read_data_loop(proc, cached_data, data, read_subd_geometry, progress);
+}
+
+/* Curve Geometries. */
+
+static void read_curves_data(CachedData &cached_data, const CurvesSchemaData &data, chrono_t time)
+{
+ const ISampleSelector iss = ISampleSelector(time);
+
+ const Int32ArraySamplePtr curves_num_vertices = data.num_vertices.getValue(iss);
+ const P3fArraySamplePtr position = data.positions.getValue(iss);
+
+ FloatArraySamplePtr radiuses;
+
+ if (data.widths.valid()) {
+ IFloatGeomParam::Sample wsample = data.widths.getExpandedValue(iss);
+ radiuses = wsample.getVals();
+ }
+
+ const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
+ float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : data.default_radius;
+
+ array<float3> curve_keys;
+ array<float> curve_radius;
+ array<int> curve_first_key;
+ array<int> curve_shader;
+
+ const bool is_homogenous = data.topology_variance == kHomogenousTopology;
+
+ curve_keys.reserve(position->size());
+ curve_radius.reserve(position->size());
+ curve_first_key.reserve(curves_num_vertices->size());
+ curve_shader.reserve(curves_num_vertices->size());
+
+ int offset = 0;
+ for (size_t i = 0; i < curves_num_vertices->size(); i++) {
+ const int num_vertices = curves_num_vertices->get()[i];
+
+ for (int j = 0; j < num_vertices; j++) {
+ const V3f &f = position->get()[offset + j];
+ // todo(@kevindietrich): we are reading too much data?
+ curve_keys.push_back_slow(make_float3_from_yup(f));
+
+ if (do_radius) {
+ radius = (*radiuses)[offset + j];
+ }
+
+ curve_radius.push_back_slow(radius * data.radius_scale);
+ }
+
+ if (!is_homogenous || cached_data.curve_first_key.size() == 0) {
+ curve_first_key.push_back_reserved(offset);
+ curve_shader.push_back_reserved(0);
+ }
+
+ offset += num_vertices;
+ }
+
+ cached_data.curve_keys.add_data(curve_keys, time);
+ cached_data.curve_radius.add_data(curve_radius, time);
+
+ if (!is_homogenous || cached_data.curve_first_key.size() == 0) {
+ cached_data.curve_first_key.add_data(curve_first_key, time);
+ cached_data.curve_shader.add_data(curve_shader, time);
+ }
+}
+
+void read_geometry_data(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const CurvesSchemaData &data,
+ Progress &progress)
+{
+ read_data_loop(proc, cached_data, data, read_curves_data, progress);
+}
+
+/* Attributes conversions. */
+
+/* Type traits for converting between Alembic and Cycles types.
+ */
+
+template<typename T> struct value_type_converter {
+ using cycles_type = float;
+ /* Use `TypeDesc::FLOAT` instead of `TypeFloat` to work around a compiler bug in gcc 11. */
+ static constexpr TypeDesc type_desc = TypeDesc::FLOAT;
+ static constexpr const char *type_name = "float (default)";
+
+ static cycles_type convert_value(T value)
+ {
+ return static_cast<float>(value);
+ }
+};
+
+template<> struct value_type_converter<Imath::V2f> {
+ using cycles_type = float2;
+ static constexpr TypeDesc type_desc = TypeFloat2;
+ static constexpr const char *type_name = "float2";
+
+ static cycles_type convert_value(Imath::V2f value)
+ {
+ return make_float2(value.x, value.y);
+ }
+};
+
+template<> struct value_type_converter<Imath::V3f> {
+ using cycles_type = float3;
+ static constexpr TypeDesc type_desc = TypeVector;
+ static constexpr const char *type_name = "float3";
+
+ static cycles_type convert_value(Imath::V3f value)
+ {
+ return make_float3_from_yup(value);
+ }
+};
+
+template<> struct value_type_converter<Imath::C3f> {
+ using cycles_type = uchar4;
+ static constexpr TypeDesc type_desc = TypeRGBA;
+ static constexpr const char *type_name = "rgb";
+
+ static cycles_type convert_value(Imath::C3f value)
+ {
+ return color_float_to_byte(make_float3(value.x, value.y, value.z));
+ }
+};
+
+template<> struct value_type_converter<Imath::C4f> {
+ using cycles_type = uchar4;
+ static constexpr TypeDesc type_desc = TypeRGBA;
+ static constexpr const char *type_name = "rgba";
+
+ static cycles_type convert_value(Imath::C4f value)
+ {
+ return color_float4_to_uchar4(make_float4(value.r, value.g, value.b, value.a));
+ }
+};
+
+/* Main function used to read attributes of any type. */
+template<typename TRAIT>
+static void process_attribute(CachedData &cache,
+ CachedData::CachedAttribute &attribute,
+ GeometryScope scope,
+ const typename ITypedGeomParam<TRAIT>::Sample &sample,
+ double time)
+{
+ using abc_type = typename TRAIT::value_type;
+ using cycles_type = typename value_type_converter<abc_type>::cycles_type;
+
+ const TypedArraySample<TRAIT> &values = *sample.getVals();
+
+ switch (scope) {
+ case kConstantScope:
+ case kVertexScope: {
+ const array<float3> *vertices =
+ cache.vertices.data_for_time_no_check(time).get_data_or_null();
+
+ if (!vertices) {
+ attribute.data.add_no_data(time);
+ return;
+ }
+
+ if (vertices->size() != values.size()) {
+ attribute.data.add_no_data(time);
+ return;
+ }
+
+ array<char> data(vertices->size() * sizeof(cycles_type));
+
+ cycles_type *pod_typed_data = reinterpret_cast<cycles_type *>(data.data());
+
+ for (size_t i = 0; i < values.size(); ++i) {
+ *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[i]);
+ }
+
+ attribute.data.add_data(data, time);
+ break;
+ }
+ case kVaryingScope: {
+ const array<int3> *triangles =
+ cache.triangles.data_for_time_no_check(time).get_data_or_null();
+
+ if (!triangles) {
+ attribute.data.add_no_data(time);
+ return;
+ }
+
+ array<char> data(triangles->size() * 3 * sizeof(cycles_type));
+
+ cycles_type *pod_typed_data = reinterpret_cast<cycles_type *>(data.data());
+
+ for (const int3 &tri : *triangles) {
+ *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[tri.x]);
+ *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[tri.y]);
+ *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[tri.z]);
+ }
+
+ attribute.data.add_data(data, time);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+/* UVs are processed separately as their indexing is based on loops, instead of vertices or
+ * corners. */
+static void process_uvs(CachedData &cache,
+ CachedData::CachedAttribute &attribute,
+ GeometryScope scope,
+ const IV2fGeomParam::Sample &sample,
+ double time)
+{
+ if (scope != kFacevaryingScope && scope != kVaryingScope && scope != kVertexScope) {
+ return;
+ }
+
+ const array<int> *uv_loops = cache.uv_loops.data_for_time_no_check(time).get_data_or_null();
+
+ /* It's ok to not have loop indices, as long as the scope is not face-varying. */
+ if (!uv_loops && scope == kFacevaryingScope) {
+ return;
+ }
+
+ const array<int3> *triangles = cache.triangles.data_for_time_no_check(time).get_data_or_null();
+ const array<int> *corners =
+ cache.subd_face_corners.data_for_time_no_check(time).get_data_or_null();
+
+ array<char> data;
+ if (triangles) {
+ data.resize(triangles->size() * 3 * sizeof(float2));
+ }
+ else if (corners) {
+ data.resize(corners->size() * sizeof(float2));
+ }
+ else {
+ return;
+ }
+
+ float2 *data_float2 = reinterpret_cast<float2 *>(data.data());
+
+ const uint32_t *indices = sample.getIndices()->get();
+ const V2f *values = sample.getVals()->get();
+
+ if (scope == kFacevaryingScope) {
+ for (const int uv_loop_index : *uv_loops) {
+ const uint32_t index = indices[uv_loop_index];
+ *data_float2++ = make_float2(values[index][0], values[index][1]);
+ }
+ }
+ else if (scope == kVaryingScope || scope == kVertexScope) {
+ if (triangles) {
+ for (size_t i = 0; i < triangles->size(); i++) {
+ const int3 t = (*triangles)[i];
+ *data_float2++ = make_float2(values[t.x][0], values[t.x][1]);
+ *data_float2++ = make_float2(values[t.y][0], values[t.y][1]);
+ *data_float2++ = make_float2(values[t.z][0], values[t.z][1]);
+ }
+ }
+ else if (corners) {
+ for (size_t i = 0; i < corners->size(); i++) {
+ const int c = (*corners)[i];
+ *data_float2++ = make_float2(values[c][0], values[c][1]);
+ }
+ }
+ }
+
+ attribute.data.add_data(data, time);
+}
+
+/* Type of the function used to parse one time worth of data, either process_uvs or
+ * process_attribute_generic. */
+template<typename TRAIT>
+using process_callback_type = void (*)(CachedData &,
+ CachedData::CachedAttribute &,
+ GeometryScope,
+ const typename ITypedGeomParam<TRAIT>::Sample &,
+ double);
+
+/* Main loop to process the attributes, this will look at the given param's TimeSampling and
+ * extract data based on which frame time is requested by the procedural and execute the callback
+ * for each of those requested time. */
+template<typename TRAIT>
+static void read_attribute_loop(AlembicProcedural *proc,
+ CachedData &cache,
+ const ITypedGeomParam<TRAIT> &param,
+ process_callback_type<TRAIT> callback,
+ Progress &progress,
+ AttributeStandard std = ATTR_STD_NONE)
+{
+ const std::set<chrono_t> times = get_relevant_sample_times(
+ proc, *param.getTimeSampling(), param.getNumSamples());
+
+ if (times.empty()) {
+ return;
+ }
+
+ std::string name = param.getName();
+
+ if (std == ATTR_STD_UV) {
+ std::string uv_source_name = Alembic::Abc::GetSourceName(param.getMetaData());
+
+ /* According to the convention, primary UVs should have had their name
+ * set using Alembic::Abc::SetSourceName, but you can't expect everyone
+ * to follow it! :) */
+ if (!uv_source_name.empty()) {
+ name = uv_source_name;
+ }
+ }
+
+ CachedData::CachedAttribute &attribute = cache.add_attribute(ustring(name),
+ *param.getTimeSampling());
+
+ using abc_type = typename TRAIT::value_type;
+
+ attribute.data.set_time_sampling(*param.getTimeSampling());
+ attribute.std = std;
+ attribute.type_desc = value_type_converter<abc_type>::type_desc;
+
+ if (attribute.type_desc == TypeRGBA) {
+ attribute.element = ATTR_ELEMENT_CORNER_BYTE;
+ }
+ else {
+ if (param.getScope() == kVaryingScope || param.getScope() == kFacevaryingScope) {
+ attribute.element = ATTR_ELEMENT_CORNER;
+ }
+ else {
+ attribute.element = ATTR_ELEMENT_VERTEX;
+ }
+ }
+
+ for (const chrono_t time : times) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ ISampleSelector iss = ISampleSelector(time);
+ typename ITypedGeomParam<TRAIT>::Sample sample;
+ param.getIndexed(sample, iss);
+
+ if (!sample.valid()) {
+ continue;
+ }
+
+ if (!sample.getVals()) {
+ attribute.data.add_no_data(time);
+ continue;
+ }
+
+ /* Check whether we already loaded constant data. */
+ if (attribute.data.size() != 0) {
+ if (param.isConstant()) {
+ return;
+ }
+
+ const ArraySample::Key indices_key = sample.getIndices()->getKey();
+ const ArraySample::Key values_key = sample.getVals()->getKey();
+
+ const bool is_same_as_last_time = (indices_key == attribute.data.key1 &&
+ values_key == attribute.data.key2);
+
+ attribute.data.key1 = indices_key;
+ attribute.data.key2 = values_key;
+
+ if (is_same_as_last_time) {
+ attribute.data.reuse_data_for_last_time(time);
+ continue;
+ }
+ }
+
+ callback(cache, attribute, param.getScope(), sample, time);
+ }
+}
+
+/* Attributes requests. */
+
+/* This structure is used to tell which ICoumpoundProperty the PropertyHeader comes from, as we
+ * need the parent when downcasting to the proper type. */
+struct PropHeaderAndParent {
+ const PropertyHeader *prop;
+ ICompoundProperty parent;
+};
+
+/* Parse the ICompoundProperty to look for properties whose names appear in the
+ * AttributeRequestSet. This also looks into any child ICompoundProperty of the given
+ * ICompoundProperty. If no property of the given name is found, let it be that way, Cycles will
+ * use a zero value for the missing attribute. */
+static void parse_requested_attributes_recursive(const AttributeRequestSet &requested_attributes,
+ const ICompoundProperty &arb_geom_params,
+ vector<PropHeaderAndParent> &requested_properties)
+{
+ if (!arb_geom_params.valid()) {
+ return;
+ }
+
+ for (const AttributeRequest &req : requested_attributes.requests) {
+ const PropertyHeader *property_header = arb_geom_params.getPropertyHeader(req.name.c_str());
+
+ if (!property_header) {
+ continue;
+ }
+
+ requested_properties.push_back({property_header, arb_geom_params});
+ }
+
+ /* Look into children compound properties. */
+ for (size_t i = 0; i < arb_geom_params.getNumProperties(); ++i) {
+ const PropertyHeader &property_header = arb_geom_params.getPropertyHeader(i);
+
+ if (property_header.isCompound()) {
+ ICompoundProperty compound_property = ICompoundProperty(arb_geom_params,
+ property_header.getName());
+ parse_requested_attributes_recursive(
+ requested_attributes, compound_property, requested_properties);
+ }
+ }
+}
+
+/* Main entry point for parsing requested attributes from an ICompoundProperty, this exists so that
+ * we can simply return the list of properties instead of allocating it on the stack and passing it
+ * as a parameter. */
+static vector<PropHeaderAndParent> parse_requested_attributes(
+ const AttributeRequestSet &requested_attributes, const ICompoundProperty &arb_geom_params)
+{
+ vector<PropHeaderAndParent> requested_properties;
+ parse_requested_attributes_recursive(
+ requested_attributes, arb_geom_params, requested_properties);
+ return requested_properties;
+}
+
+/* Read the attributes requested by the shaders from the archive. This will recursively find named
+ * attributes from the AttributeRequestSet in the ICompoundProperty and any of its compound child.
+ * The attributes are added to the CachedData's attribute list. For each attribute we will try to
+ * deduplicate data across consecutive frames. */
+void read_attributes(AlembicProcedural *proc,
+ CachedData &cache,
+ const ICompoundProperty &arb_geom_params,
+ const IV2fGeomParam &default_uvs_param,
+ const AttributeRequestSet &requested_attributes,
+ Progress &progress)
+{
+ if (default_uvs_param.valid()) {
+ /* Only the default UVs should be treated as the standard UV attribute. */
+ read_attribute_loop(proc, cache, default_uvs_param, process_uvs, progress, ATTR_STD_UV);
+ }
+
+ vector<PropHeaderAndParent> requested_properties = parse_requested_attributes(
+ requested_attributes, arb_geom_params);
+
+ for (const PropHeaderAndParent &prop_and_parent : requested_properties) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ const PropertyHeader *prop = prop_and_parent.prop;
+ const ICompoundProperty &parent = prop_and_parent.parent;
+
+ if (IBoolGeomParam::matches(*prop)) {
+ const IBoolGeomParam &param = IBoolGeomParam(parent, prop->getName());
+ read_attribute_loop(proc, cache, param, process_attribute<BooleanTPTraits>, progress);
+ }
+ else if (IInt32GeomParam::matches(*prop)) {
+ const IInt32GeomParam &param = IInt32GeomParam(parent, prop->getName());
+ read_attribute_loop(proc, cache, param, process_attribute<Int32TPTraits>, progress);
+ }
+ else if (IFloatGeomParam::matches(*prop)) {
+ const IFloatGeomParam &param = IFloatGeomParam(parent, prop->getName());
+ read_attribute_loop(proc, cache, param, process_attribute<Float32TPTraits>, progress);
+ }
+ else if (IV2fGeomParam::matches(*prop)) {
+ const IV2fGeomParam &param = IV2fGeomParam(parent, prop->getName());
+ if (Alembic::AbcGeom::isUV(*prop)) {
+ read_attribute_loop(proc, cache, param, process_uvs, progress);
+ }
+ else {
+ read_attribute_loop(proc, cache, param, process_attribute<V2fTPTraits>, progress);
+ }
+ }
+ else if (IV3fGeomParam::matches(*prop)) {
+ const IV3fGeomParam &param = IV3fGeomParam(parent, prop->getName());
+ read_attribute_loop(proc, cache, param, process_attribute<V3fTPTraits>, progress);
+ }
+ else if (IN3fGeomParam::matches(*prop)) {
+ const IN3fGeomParam &param = IN3fGeomParam(parent, prop->getName());
+ read_attribute_loop(proc, cache, param, process_attribute<N3fTPTraits>, progress);
+ }
+ else if (IC3fGeomParam::matches(*prop)) {
+ const IC3fGeomParam &param = IC3fGeomParam(parent, prop->getName());
+ read_attribute_loop(proc, cache, param, process_attribute<C3fTPTraits>, progress);
+ }
+ else if (IC4fGeomParam::matches(*prop)) {
+ const IC4fGeomParam &param = IC4fGeomParam(parent, prop->getName());
+ read_attribute_loop(proc, cache, param, process_attribute<C4fTPTraits>, progress);
+ }
+ }
+
+ cache.invalidate_last_loaded_time(true);
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/scene/alembic_read.h b/intern/cycles/scene/alembic_read.h
new file mode 100644
index 00000000000..6b656b59481
--- /dev/null
+++ b/intern/cycles/scene/alembic_read.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifdef WITH_ALEMBIC
+
+# include <Alembic/AbcCoreFactory/All.h>
+# include <Alembic/AbcGeom/All.h>
+
+# include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class AlembicProcedural;
+class AttributeRequestSet;
+class Progress;
+struct CachedData;
+
+/* Maps a FaceSet whose name matches that of a Shader to the index of said shader in the Geometry's
+ * used_shaders list. */
+struct FaceSetShaderIndexPair {
+ Alembic::AbcGeom::IFaceSet face_set;
+ int shader_index;
+};
+
+/* Data of an IPolyMeshSchema that we need to read. */
+struct PolyMeshSchemaData {
+ Alembic::AbcGeom::TimeSamplingPtr time_sampling;
+ size_t num_samples;
+ Alembic::AbcGeom::MeshTopologyVariance topology_variance;
+
+ Alembic::AbcGeom::IP3fArrayProperty positions;
+ Alembic::AbcGeom::IInt32ArrayProperty face_indices;
+ Alembic::AbcGeom::IInt32ArrayProperty face_counts;
+
+ Alembic::AbcGeom::IN3fGeomParam normals;
+
+ vector<FaceSetShaderIndexPair> shader_face_sets;
+
+ // Unsupported for now.
+ Alembic::AbcGeom::IV3fArrayProperty velocities;
+};
+
+void read_geometry_data(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const PolyMeshSchemaData &data,
+ Progress &progress);
+
+/* Data of an ISubDSchema that we need to read. */
+struct SubDSchemaData {
+ Alembic::AbcGeom::TimeSamplingPtr time_sampling;
+ size_t num_samples;
+ Alembic::AbcGeom::MeshTopologyVariance topology_variance;
+
+ Alembic::AbcGeom::IInt32ArrayProperty face_counts;
+ Alembic::AbcGeom::IInt32ArrayProperty face_indices;
+ Alembic::AbcGeom::IP3fArrayProperty positions;
+
+ Alembic::AbcGeom::IInt32ArrayProperty crease_indices;
+ Alembic::AbcGeom::IInt32ArrayProperty crease_lengths;
+ Alembic::AbcGeom::IFloatArrayProperty crease_sharpnesses;
+
+ vector<FaceSetShaderIndexPair> shader_face_sets;
+
+ // Those are unsupported for now.
+ Alembic::AbcGeom::IInt32ArrayProperty corner_indices;
+ Alembic::AbcGeom::IFloatArrayProperty corner_sharpnesses;
+ Alembic::AbcGeom::IInt32Property face_varying_interpolate_boundary;
+ Alembic::AbcGeom::IInt32Property face_varying_propagate_corners;
+ Alembic::AbcGeom::IInt32Property interpolate_boundary;
+ Alembic::AbcGeom::IInt32ArrayProperty holes;
+ Alembic::AbcGeom::IStringProperty subdivision_scheme;
+ Alembic::AbcGeom::IV3fArrayProperty velocities;
+};
+
+void read_geometry_data(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const SubDSchemaData &data,
+ Progress &progress);
+
+/* Data of a ICurvesSchema that we need to read. */
+struct CurvesSchemaData {
+ Alembic::AbcGeom::TimeSamplingPtr time_sampling;
+ size_t num_samples;
+ Alembic::AbcGeom::MeshTopologyVariance topology_variance;
+
+ Alembic::AbcGeom::IP3fArrayProperty positions;
+
+ Alembic::AbcGeom::IInt32ArrayProperty num_vertices;
+
+ float default_radius;
+ float radius_scale;
+
+ // Those are unsupported for now.
+ Alembic::AbcGeom::IV3fArrayProperty velocities;
+ // if this property is invalid then the weight for every point is 1
+ Alembic::AbcGeom::IFloatArrayProperty position_weights;
+ Alembic::AbcGeom::IN3fGeomParam normals;
+ Alembic::AbcGeom::IFloatGeomParam widths;
+ Alembic::AbcGeom::IUcharArrayProperty orders;
+ Alembic::AbcGeom::IFloatArrayProperty knots;
+
+ // TODO(@kevindietrich): type, basis, wrap
+};
+
+void read_geometry_data(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const CurvesSchemaData &data,
+ Progress &progress);
+
+void read_attributes(AlembicProcedural *proc,
+ CachedData &cache,
+ const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
+ const Alembic::AbcGeom::IV2fGeomParam &default_uvs_param,
+ const AttributeRequestSet &requested_attributes,
+ Progress &progress);
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/scene/attribute.cpp b/intern/cycles/scene/attribute.cpp
new file mode 100644
index 00000000000..3401eea307f
--- /dev/null
+++ b/intern/cycles/scene/attribute.cpp
@@ -0,0 +1,896 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/attribute.h"
+#include "scene/hair.h"
+#include "scene/image.h"
+#include "scene/mesh.h"
+
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Attribute */
+
+Attribute::Attribute(
+ ustring name, TypeDesc type, AttributeElement element, Geometry *geom, AttributePrimitive prim)
+ : name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0), modified(true)
+{
+ /* string and matrix not supported! */
+ assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
+ type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix || type == TypeFloat2 ||
+ type == TypeFloat4 || type == TypeRGBA);
+
+ if (element == ATTR_ELEMENT_VOXEL) {
+ buffer.resize(sizeof(ImageHandle));
+ new (buffer.data()) ImageHandle();
+ }
+ else {
+ resize(geom, prim, false);
+ }
+}
+
+Attribute::~Attribute()
+{
+ /* For voxel data, we need to free the image handle. */
+ if (element == ATTR_ELEMENT_VOXEL && buffer.size()) {
+ ImageHandle &handle = data_voxel();
+ handle.~ImageHandle();
+ }
+}
+
+void Attribute::resize(Geometry *geom, AttributePrimitive prim, bool reserve_only)
+{
+ if (element != ATTR_ELEMENT_VOXEL) {
+ if (reserve_only) {
+ buffer.reserve(buffer_size(geom, prim));
+ }
+ else {
+ buffer.resize(buffer_size(geom, prim), 0);
+ }
+ }
+}
+
+void Attribute::resize(size_t num_elements)
+{
+ if (element != ATTR_ELEMENT_VOXEL) {
+ buffer.resize(num_elements * data_sizeof(), 0);
+ }
+}
+
+void Attribute::add(const float &f)
+{
+ assert(data_sizeof() == sizeof(float));
+
+ char *data = (char *)&f;
+ size_t size = sizeof(f);
+
+ for (size_t i = 0; i < size; i++)
+ buffer.push_back(data[i]);
+
+ modified = true;
+}
+
+void Attribute::add(const uchar4 &f)
+{
+ assert(data_sizeof() == sizeof(uchar4));
+
+ char *data = (char *)&f;
+ size_t size = sizeof(f);
+
+ for (size_t i = 0; i < size; i++)
+ buffer.push_back(data[i]);
+
+ modified = true;
+}
+
+void Attribute::add(const float2 &f)
+{
+ assert(data_sizeof() == sizeof(float2));
+
+ char *data = (char *)&f;
+ size_t size = sizeof(f);
+
+ for (size_t i = 0; i < size; i++)
+ buffer.push_back(data[i]);
+
+ modified = true;
+}
+
+void Attribute::add(const float3 &f)
+{
+ assert(data_sizeof() == sizeof(float3));
+
+ char *data = (char *)&f;
+ size_t size = sizeof(f);
+
+ for (size_t i = 0; i < size; i++)
+ buffer.push_back(data[i]);
+
+ modified = true;
+}
+
+void Attribute::add(const Transform &f)
+{
+ assert(data_sizeof() == sizeof(Transform));
+
+ char *data = (char *)&f;
+ size_t size = sizeof(f);
+
+ for (size_t i = 0; i < size; i++)
+ buffer.push_back(data[i]);
+
+ modified = true;
+}
+
+void Attribute::add(const char *data)
+{
+ size_t size = data_sizeof();
+
+ for (size_t i = 0; i < size; i++)
+ buffer.push_back(data[i]);
+
+ modified = true;
+}
+
+void Attribute::set_data_from(Attribute &&other)
+{
+ assert(other.std == std);
+ assert(other.type == type);
+ assert(other.element == element);
+
+ this->flags = other.flags;
+
+ if (this->buffer.size() != other.buffer.size()) {
+ this->buffer = std::move(other.buffer);
+ modified = true;
+ }
+ else if (memcmp(this->data(), other.data(), other.buffer.size()) != 0) {
+ this->buffer = std::move(other.buffer);
+ modified = true;
+ }
+}
+
+size_t Attribute::data_sizeof() const
+{
+ if (element == ATTR_ELEMENT_VOXEL)
+ return sizeof(ImageHandle);
+ else if (element == ATTR_ELEMENT_CORNER_BYTE)
+ return sizeof(uchar4);
+ else if (type == TypeDesc::TypeFloat)
+ return sizeof(float);
+ else if (type == TypeFloat2)
+ return sizeof(float2);
+ else if (type == TypeDesc::TypeMatrix)
+ return sizeof(Transform);
+ else
+ return sizeof(float3);
+}
+
+size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
+{
+ if (flags & ATTR_FINAL_SIZE) {
+ return buffer.size() / data_sizeof();
+ }
+
+ size_t size = 0;
+
+ switch (element) {
+ case ATTR_ELEMENT_OBJECT:
+ case ATTR_ELEMENT_MESH:
+ case ATTR_ELEMENT_VOXEL:
+ size = 1;
+ break;
+ case ATTR_ELEMENT_VERTEX:
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ size = mesh->get_verts().size() + mesh->get_num_ngons();
+ if (prim == ATTR_PRIM_SUBD) {
+ size -= mesh->get_num_subd_verts();
+ }
+ }
+ break;
+ case ATTR_ELEMENT_VERTEX_MOTION:
+ if (geom->geometry_type == Geometry::MESH) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ DCHECK_GT(mesh->get_motion_steps(), 0);
+ size = (mesh->get_verts().size() + mesh->get_num_ngons()) * (mesh->get_motion_steps() - 1);
+ if (prim == ATTR_PRIM_SUBD) {
+ size -= mesh->get_num_subd_verts() * (mesh->get_motion_steps() - 1);
+ }
+ }
+ break;
+ case ATTR_ELEMENT_FACE:
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (prim == ATTR_PRIM_GEOMETRY) {
+ size = mesh->num_triangles();
+ }
+ else {
+ size = mesh->get_num_subd_faces() + mesh->get_num_ngons();
+ }
+ }
+ break;
+ case ATTR_ELEMENT_CORNER:
+ case ATTR_ELEMENT_CORNER_BYTE:
+ if (geom->geometry_type == Geometry::MESH) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (prim == ATTR_PRIM_GEOMETRY) {
+ size = mesh->num_triangles() * 3;
+ }
+ else {
+ size = mesh->get_subd_face_corners().size() + mesh->get_num_ngons();
+ }
+ }
+ break;
+ case ATTR_ELEMENT_CURVE:
+ if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ size = hair->num_curves();
+ }
+ break;
+ case ATTR_ELEMENT_CURVE_KEY:
+ if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ size = hair->get_curve_keys().size();
+ }
+ break;
+ case ATTR_ELEMENT_CURVE_KEY_MOTION:
+ if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ DCHECK_GT(hair->get_motion_steps(), 0);
+ size = hair->get_curve_keys().size() * (hair->get_motion_steps() - 1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return size;
+}
+
+size_t Attribute::buffer_size(Geometry *geom, AttributePrimitive prim) const
+{
+ return element_size(geom, prim) * data_sizeof();
+}
+
+bool Attribute::same_storage(TypeDesc a, TypeDesc b)
+{
+ if (a == b)
+ return true;
+
+ if (a == TypeDesc::TypeColor || a == TypeDesc::TypePoint || a == TypeDesc::TypeVector ||
+ a == TypeDesc::TypeNormal) {
+ if (b == TypeDesc::TypeColor || b == TypeDesc::TypePoint || b == TypeDesc::TypeVector ||
+ b == TypeDesc::TypeNormal) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void Attribute::zero_data(void *dst)
+{
+ memset(dst, 0, data_sizeof());
+}
+
+void Attribute::add_with_weight(void *dst, void *src, float weight)
+{
+ if (element == ATTR_ELEMENT_CORNER_BYTE) {
+ for (int i = 0; i < 4; i++) {
+ ((uchar *)dst)[i] += uchar(((uchar *)src)[i] * weight);
+ }
+ }
+ else if (same_storage(type, TypeDesc::TypeFloat)) {
+ *((float *)dst) += *((float *)src) * weight;
+ }
+ else if (same_storage(type, TypeFloat2)) {
+ *((float2 *)dst) += *((float2 *)src) * weight;
+ }
+ else if (same_storage(type, TypeDesc::TypeVector)) {
+ *((float4 *)dst) += *((float4 *)src) * weight;
+ }
+ else {
+ assert(!"not implemented for this type");
+ }
+}
+
+const char *Attribute::standard_name(AttributeStandard std)
+{
+ switch (std) {
+ case ATTR_STD_VERTEX_NORMAL:
+ return "N";
+ case ATTR_STD_FACE_NORMAL:
+ return "Ng";
+ case ATTR_STD_UV:
+ return "uv";
+ case ATTR_STD_GENERATED:
+ return "generated";
+ case ATTR_STD_GENERATED_TRANSFORM:
+ return "generated_transform";
+ case ATTR_STD_UV_TANGENT:
+ return "tangent";
+ case ATTR_STD_UV_TANGENT_SIGN:
+ return "tangent_sign";
+ case ATTR_STD_VERTEX_COLOR:
+ return "vertex_color";
+ case ATTR_STD_POSITION_UNDEFORMED:
+ return "undeformed";
+ case ATTR_STD_POSITION_UNDISPLACED:
+ return "undisplaced";
+ case ATTR_STD_MOTION_VERTEX_POSITION:
+ return "motion_P";
+ case ATTR_STD_MOTION_VERTEX_NORMAL:
+ return "motion_N";
+ case ATTR_STD_PARTICLE:
+ return "particle";
+ case ATTR_STD_CURVE_INTERCEPT:
+ return "curve_intercept";
+ case ATTR_STD_CURVE_LENGTH:
+ return "curve_length";
+ case ATTR_STD_CURVE_RANDOM:
+ return "curve_random";
+ case ATTR_STD_PTEX_FACE_ID:
+ return "ptex_face_id";
+ case ATTR_STD_PTEX_UV:
+ return "ptex_uv";
+ case ATTR_STD_VOLUME_DENSITY:
+ return "density";
+ case ATTR_STD_VOLUME_COLOR:
+ return "color";
+ case ATTR_STD_VOLUME_FLAME:
+ return "flame";
+ case ATTR_STD_VOLUME_HEAT:
+ return "heat";
+ case ATTR_STD_VOLUME_TEMPERATURE:
+ return "temperature";
+ case ATTR_STD_VOLUME_VELOCITY:
+ return "velocity";
+ case ATTR_STD_POINTINESS:
+ return "pointiness";
+ case ATTR_STD_RANDOM_PER_ISLAND:
+ return "random_per_island";
+ case ATTR_STD_SHADOW_TRANSPARENCY:
+ return "shadow_transparency";
+ case ATTR_STD_NOT_FOUND:
+ case ATTR_STD_NONE:
+ case ATTR_STD_NUM:
+ return "";
+ }
+
+ return "";
+}
+
+AttributeStandard Attribute::name_standard(const char *name)
+{
+ if (name) {
+ for (int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) {
+ if (strcmp(name, Attribute::standard_name((AttributeStandard)std)) == 0) {
+ return (AttributeStandard)std;
+ }
+ }
+ }
+
+ return ATTR_STD_NONE;
+}
+
+AttrKernelDataType Attribute::kernel_type(const Attribute &attr)
+{
+ if (attr.element == ATTR_ELEMENT_CORNER) {
+ return AttrKernelDataType::UCHAR4;
+ }
+
+ if (attr.type == TypeDesc::TypeFloat) {
+ return AttrKernelDataType::FLOAT;
+ }
+
+ if (attr.type == TypeFloat2) {
+ return AttrKernelDataType::FLOAT2;
+ }
+
+ return AttrKernelDataType::FLOAT3;
+}
+
+void Attribute::get_uv_tiles(Geometry *geom,
+ AttributePrimitive prim,
+ unordered_set<int> &tiles) const
+{
+ if (type != TypeFloat2) {
+ return;
+ }
+
+ const int num = element_size(geom, prim);
+ const float2 *uv = data_float2();
+ for (int i = 0; i < num; i++, uv++) {
+ float u = uv->x, v = uv->y;
+ int x = (int)u, y = (int)v;
+
+ if (x < 0 || y < 0 || x >= 10) {
+ continue;
+ }
+
+ /* Be conservative in corners - precisely touching the right or upper edge of a tile
+ * should not load its right/upper neighbor as well. */
+ if (x > 0 && (u < x + 1e-6f)) {
+ x--;
+ }
+ if (y > 0 && (v < y + 1e-6f)) {
+ y--;
+ }
+
+ tiles.insert(1001 + 10 * y + x);
+ }
+}
+
+/* Attribute Set */
+
+AttributeSet::AttributeSet(Geometry *geometry, AttributePrimitive prim)
+ : modified_flag(~0u), geometry(geometry), prim(prim)
+{
+}
+
+AttributeSet::~AttributeSet()
+{
+}
+
+Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element)
+{
+ Attribute *attr = find(name);
+
+ if (attr) {
+ /* return if same already exists */
+ if (attr->type == type && attr->element == element)
+ return attr;
+
+ /* overwrite attribute with same name but different type/element */
+ remove(name);
+ }
+
+ Attribute new_attr(name, type, element, geometry, prim);
+ attributes.emplace_back(std::move(new_attr));
+ tag_modified(attributes.back());
+ return &attributes.back();
+}
+
+Attribute *AttributeSet::find(ustring name) const
+{
+ foreach (const Attribute &attr, attributes)
+ if (attr.name == name)
+ return (Attribute *)&attr;
+
+ return NULL;
+}
+
+void AttributeSet::remove(ustring name)
+{
+ Attribute *attr = find(name);
+
+ if (attr) {
+ list<Attribute>::iterator it;
+
+ for (it = attributes.begin(); it != attributes.end(); it++) {
+ if (&*it == attr) {
+ remove(it);
+ return;
+ }
+ }
+ }
+}
+
+Attribute *AttributeSet::add(AttributeStandard std, ustring name)
+{
+ Attribute *attr = NULL;
+
+ if (name == ustring())
+ name = Attribute::standard_name(std);
+
+ if (geometry->geometry_type == Geometry::MESH) {
+ switch (std) {
+ case ATTR_STD_VERTEX_NORMAL:
+ attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_FACE_NORMAL:
+ attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE);
+ break;
+ case ATTR_STD_UV:
+ attr = add(name, TypeFloat2, ATTR_ELEMENT_CORNER);
+ break;
+ case ATTR_STD_UV_TANGENT:
+ attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
+ break;
+ case ATTR_STD_UV_TANGENT_SIGN:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
+ break;
+ case ATTR_STD_VERTEX_COLOR:
+ attr = add(name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
+ break;
+ case ATTR_STD_GENERATED:
+ case ATTR_STD_POSITION_UNDEFORMED:
+ case ATTR_STD_POSITION_UNDISPLACED:
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_MOTION_VERTEX_POSITION:
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX_MOTION);
+ break;
+ case ATTR_STD_MOTION_VERTEX_NORMAL:
+ attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX_MOTION);
+ break;
+ case ATTR_STD_PTEX_FACE_ID:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE);
+ break;
+ case ATTR_STD_PTEX_UV:
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_GENERATED_TRANSFORM:
+ attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH);
+ break;
+ case ATTR_STD_POINTINESS:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_RANDOM_PER_ISLAND:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ else if (geometry->geometry_type == Geometry::VOLUME) {
+ switch (std) {
+ case ATTR_STD_VERTEX_NORMAL:
+ attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_FACE_NORMAL:
+ attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE);
+ break;
+ case ATTR_STD_VOLUME_DENSITY:
+ case ATTR_STD_VOLUME_FLAME:
+ case ATTR_STD_VOLUME_HEAT:
+ case ATTR_STD_VOLUME_TEMPERATURE:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL);
+ break;
+ case ATTR_STD_VOLUME_COLOR:
+ attr = add(name, TypeDesc::TypeColor, ATTR_ELEMENT_VOXEL);
+ break;
+ case ATTR_STD_VOLUME_VELOCITY:
+ attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_VOXEL);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ else if (geometry->geometry_type == Geometry::HAIR) {
+ switch (std) {
+ case ATTR_STD_UV:
+ attr = add(name, TypeFloat2, ATTR_ELEMENT_CURVE);
+ break;
+ case ATTR_STD_GENERATED:
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
+ break;
+ case ATTR_STD_MOTION_VERTEX_POSITION:
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY_MOTION);
+ break;
+ case ATTR_STD_CURVE_INTERCEPT:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY);
+ break;
+ case ATTR_STD_CURVE_LENGTH:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE);
+ break;
+ case ATTR_STD_CURVE_RANDOM:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE);
+ break;
+ case ATTR_STD_GENERATED_TRANSFORM:
+ attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH);
+ break;
+ case ATTR_STD_POINTINESS:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_RANDOM_PER_ISLAND:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE);
+ break;
+ case ATTR_STD_SHADOW_TRANSPARENCY:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+
+ attr->std = std;
+
+ return attr;
+}
+
+Attribute *AttributeSet::find(AttributeStandard std) const
+{
+ foreach (const Attribute &attr, attributes)
+ if (attr.std == std)
+ return (Attribute *)&attr;
+
+ return NULL;
+}
+
+void AttributeSet::remove(AttributeStandard std)
+{
+ Attribute *attr = find(std);
+
+ if (attr) {
+ list<Attribute>::iterator it;
+
+ for (it = attributes.begin(); it != attributes.end(); it++) {
+ if (&*it == attr) {
+ remove(it);
+ return;
+ }
+ }
+ }
+}
+
+Attribute *AttributeSet::find(AttributeRequest &req)
+{
+ if (req.std == ATTR_STD_NONE)
+ return find(req.name);
+ else
+ return find(req.std);
+}
+
+void AttributeSet::remove(Attribute *attribute)
+{
+ if (attribute->std == ATTR_STD_NONE) {
+ remove(attribute->name);
+ }
+ else {
+ remove(attribute->std);
+ }
+}
+
+void AttributeSet::remove(list<Attribute>::iterator it)
+{
+ tag_modified(*it);
+ attributes.erase(it);
+}
+
+void AttributeSet::resize(bool reserve_only)
+{
+ foreach (Attribute &attr, attributes) {
+ attr.resize(geometry, prim, reserve_only);
+ }
+}
+
+void AttributeSet::clear(bool preserve_voxel_data)
+{
+ if (preserve_voxel_data) {
+ list<Attribute>::iterator it;
+
+ for (it = attributes.begin(); it != attributes.end();) {
+ if (it->element == ATTR_ELEMENT_VOXEL || it->std == ATTR_STD_GENERATED_TRANSFORM) {
+ it++;
+ }
+ else {
+ attributes.erase(it++);
+ }
+ }
+ }
+ else {
+ attributes.clear();
+ }
+}
+
+void AttributeSet::update(AttributeSet &&new_attributes)
+{
+ /* add or update old_attributes based on the new_attributes */
+ foreach (Attribute &attr, new_attributes.attributes) {
+ Attribute *nattr = add(attr.name, attr.type, attr.element);
+ nattr->std = attr.std;
+ nattr->set_data_from(std::move(attr));
+ }
+
+ /* remove any attributes not on new_attributes */
+ list<Attribute>::iterator it;
+ for (it = attributes.begin(); it != attributes.end();) {
+ if (it->std != ATTR_STD_NONE) {
+ if (new_attributes.find(it->std) == nullptr) {
+ remove(it++);
+ continue;
+ }
+ }
+ else if (it->name != "") {
+ if (new_attributes.find(it->name) == nullptr) {
+ remove(it++);
+ continue;
+ }
+ }
+
+ it++;
+ }
+
+ /* If all attributes were replaced, transform is no longer applied. */
+ geometry->transform_applied = false;
+}
+
+void AttributeSet::clear_modified()
+{
+ foreach (Attribute &attr, attributes) {
+ attr.modified = false;
+ }
+
+ modified_flag = 0;
+}
+
+void AttributeSet::tag_modified(const Attribute &attr)
+{
+ /* Some attributes are not stored in the various kernel attribute arrays
+ * (DeviceScene::attribute_*), so the modified flags are only set if the associated standard
+ * corresponds to an attribute which will be stored in the kernel's attribute arrays. */
+ const bool modifies_device_array = (attr.std != ATTR_STD_FACE_NORMAL &&
+ attr.std != ATTR_STD_VERTEX_NORMAL);
+
+ if (modifies_device_array) {
+ AttrKernelDataType kernel_type = Attribute::kernel_type(attr);
+ modified_flag |= (1u << kernel_type);
+ }
+}
+
+bool AttributeSet::modified(AttrKernelDataType kernel_type) const
+{
+ return (modified_flag & (1u << kernel_type)) != 0;
+}
+
+/* AttributeRequest */
+
+AttributeRequest::AttributeRequest(ustring name_)
+{
+ name = name_;
+ std = ATTR_STD_NONE;
+
+ type = TypeDesc::TypeFloat;
+ desc.element = ATTR_ELEMENT_NONE;
+ desc.offset = 0;
+ desc.type = NODE_ATTR_FLOAT;
+
+ subd_type = TypeDesc::TypeFloat;
+ subd_desc.element = ATTR_ELEMENT_NONE;
+ subd_desc.offset = 0;
+ subd_desc.type = NODE_ATTR_FLOAT;
+}
+
+AttributeRequest::AttributeRequest(AttributeStandard std_)
+{
+ name = ustring();
+ std = std_;
+
+ type = TypeDesc::TypeFloat;
+ desc.element = ATTR_ELEMENT_NONE;
+ desc.offset = 0;
+ desc.type = NODE_ATTR_FLOAT;
+
+ subd_type = TypeDesc::TypeFloat;
+ subd_desc.element = ATTR_ELEMENT_NONE;
+ subd_desc.offset = 0;
+ subd_desc.type = NODE_ATTR_FLOAT;
+}
+
+/* AttributeRequestSet */
+
+AttributeRequestSet::AttributeRequestSet()
+{
+}
+
+AttributeRequestSet::~AttributeRequestSet()
+{
+}
+
+bool AttributeRequestSet::modified(const AttributeRequestSet &other)
+{
+ if (requests.size() != other.requests.size())
+ return true;
+
+ for (size_t i = 0; i < requests.size(); i++) {
+ bool found = false;
+
+ for (size_t j = 0; j < requests.size() && !found; j++)
+ if (requests[i].name == other.requests[j].name && requests[i].std == other.requests[j].std) {
+ found = true;
+ }
+
+ if (!found) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void AttributeRequestSet::add(ustring name)
+{
+ foreach (AttributeRequest &req, requests) {
+ if (req.name == name) {
+ return;
+ }
+ }
+
+ requests.push_back(AttributeRequest(name));
+}
+
+void AttributeRequestSet::add(AttributeStandard std)
+{
+ foreach (AttributeRequest &req, requests)
+ if (req.std == std)
+ return;
+
+ requests.push_back(AttributeRequest(std));
+}
+
+void AttributeRequestSet::add(AttributeRequestSet &reqs)
+{
+ foreach (AttributeRequest &req, reqs.requests) {
+ if (req.std == ATTR_STD_NONE)
+ add(req.name);
+ else
+ add(req.std);
+ }
+}
+
+void AttributeRequestSet::add_standard(ustring name)
+{
+ if (name.empty()) {
+ return;
+ }
+
+ AttributeStandard std = Attribute::name_standard(name.c_str());
+
+ if (std) {
+ add(std);
+ }
+ else {
+ add(name);
+ }
+}
+
+bool AttributeRequestSet::find(ustring name)
+{
+ foreach (AttributeRequest &req, requests)
+ if (req.name == name)
+ return true;
+
+ return false;
+}
+
+bool AttributeRequestSet::find(AttributeStandard std)
+{
+ foreach (AttributeRequest &req, requests)
+ if (req.std == std)
+ return true;
+
+ return false;
+}
+
+size_t AttributeRequestSet::size()
+{
+ return requests.size();
+}
+
+void AttributeRequestSet::clear()
+{
+ requests.clear();
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/attribute.h b/intern/cycles/scene/attribute.h
new file mode 100644
index 00000000000..4a25a900c14
--- /dev/null
+++ b/intern/cycles/scene/attribute.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ATTRIBUTE_H__
+#define __ATTRIBUTE_H__
+
+#include "scene/image.h"
+
+#include "kernel/types.h"
+
+#include "util/list.h"
+#include "util/param.h"
+#include "util/set.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Attribute;
+class AttributeRequest;
+class AttributeRequestSet;
+class AttributeSet;
+class ImageHandle;
+class Geometry;
+class Hair;
+class Mesh;
+struct Transform;
+
+/* AttrKernelDataType.
+ *
+ * The data type of the device arrays storing the attribute's data. Those data types are different
+ * than the ones for attributes as some attribute types are stored in the same array, e.g. Point,
+ * Vector, and Transform are all stored as float3 in the kernel.
+ *
+ * The values of this enumeration are also used as flags to detect changes in AttributeSet. */
+
+enum AttrKernelDataType {
+ FLOAT = 0,
+ FLOAT2 = 1,
+ FLOAT3 = 2,
+ UCHAR4 = 3,
+};
+
+/* Attribute
+ *
+ * Arbitrary data layers on meshes.
+ * Supported types: Float, Color, Vector, Normal, Point */
+
+class Attribute {
+ public:
+ ustring name;
+ AttributeStandard std;
+
+ TypeDesc type;
+ vector<char> buffer;
+ AttributeElement element;
+ uint flags; /* enum AttributeFlag */
+
+ bool modified;
+
+ Attribute(ustring name,
+ TypeDesc type,
+ AttributeElement element,
+ Geometry *geom,
+ AttributePrimitive prim);
+ Attribute(Attribute &&other) = default;
+ Attribute(const Attribute &other) = delete;
+ Attribute &operator=(const Attribute &other) = delete;
+ ~Attribute();
+
+ void set(ustring name, TypeDesc type, AttributeElement element);
+ void resize(Geometry *geom, AttributePrimitive prim, bool reserve_only);
+ void resize(size_t num_elements);
+
+ size_t data_sizeof() const;
+ size_t element_size(Geometry *geom, AttributePrimitive prim) const;
+ size_t buffer_size(Geometry *geom, AttributePrimitive prim) const;
+
+ char *data()
+ {
+ return (buffer.size()) ? &buffer[0] : NULL;
+ }
+ float2 *data_float2()
+ {
+ assert(data_sizeof() == sizeof(float2));
+ return (float2 *)data();
+ }
+ float3 *data_float3()
+ {
+ assert(data_sizeof() == sizeof(float3));
+ return (float3 *)data();
+ }
+ float4 *data_float4()
+ {
+ assert(data_sizeof() == sizeof(float4));
+ return (float4 *)data();
+ }
+ float *data_float()
+ {
+ assert(data_sizeof() == sizeof(float));
+ return (float *)data();
+ }
+ uchar4 *data_uchar4()
+ {
+ assert(data_sizeof() == sizeof(uchar4));
+ return (uchar4 *)data();
+ }
+ Transform *data_transform()
+ {
+ assert(data_sizeof() == sizeof(Transform));
+ return (Transform *)data();
+ }
+
+ /* Attributes for voxels are images */
+ ImageHandle &data_voxel()
+ {
+ assert(data_sizeof() == sizeof(ImageHandle));
+ return *(ImageHandle *)data();
+ }
+
+ const char *data() const
+ {
+ return (buffer.size()) ? &buffer[0] : NULL;
+ }
+ const float2 *data_float2() const
+ {
+ assert(data_sizeof() == sizeof(float2));
+ return (const float2 *)data();
+ }
+ const float3 *data_float3() const
+ {
+ assert(data_sizeof() == sizeof(float3));
+ return (const float3 *)data();
+ }
+ const float4 *data_float4() const
+ {
+ assert(data_sizeof() == sizeof(float4));
+ return (const float4 *)data();
+ }
+ const float *data_float() const
+ {
+ assert(data_sizeof() == sizeof(float));
+ return (const float *)data();
+ }
+ const Transform *data_transform() const
+ {
+ assert(data_sizeof() == sizeof(Transform));
+ return (const Transform *)data();
+ }
+ const ImageHandle &data_voxel() const
+ {
+ assert(data_sizeof() == sizeof(ImageHandle));
+ return *(const ImageHandle *)data();
+ }
+
+ void zero_data(void *dst);
+ void add_with_weight(void *dst, void *src, float weight);
+
+ void add(const float &f);
+ void add(const float2 &f);
+ void add(const float3 &f);
+ void add(const uchar4 &f);
+ void add(const Transform &tfm);
+ void add(const char *data);
+
+ void set_data_from(Attribute &&other);
+
+ static bool same_storage(TypeDesc a, TypeDesc b);
+ static const char *standard_name(AttributeStandard std);
+ static AttributeStandard name_standard(const char *name);
+
+ static AttrKernelDataType kernel_type(const Attribute &attr);
+
+ void get_uv_tiles(Geometry *geom, AttributePrimitive prim, unordered_set<int> &tiles) const;
+};
+
+/* Attribute Set
+ *
+ * Set of attributes on a mesh. */
+
+class AttributeSet {
+ uint32_t modified_flag;
+
+ public:
+ Geometry *geometry;
+ AttributePrimitive prim;
+ list<Attribute> attributes;
+
+ AttributeSet(Geometry *geometry, AttributePrimitive prim);
+ AttributeSet(AttributeSet &&) = default;
+ ~AttributeSet();
+
+ Attribute *add(ustring name, TypeDesc type, AttributeElement element);
+ Attribute *find(ustring name) const;
+ void remove(ustring name);
+
+ Attribute *add(AttributeStandard std, ustring name = ustring());
+ Attribute *find(AttributeStandard std) const;
+ void remove(AttributeStandard std);
+
+ Attribute *find(AttributeRequest &req);
+
+ void remove(Attribute *attribute);
+
+ void remove(list<Attribute>::iterator it);
+
+ void resize(bool reserve_only = false);
+ void clear(bool preserve_voxel_data = false);
+
+ /* Update the attributes in this AttributeSet with the ones from the new set,
+ * and remove any attribute not found on the new set from this. */
+ void update(AttributeSet &&new_attributes);
+
+ /* Return whether the attributes of the given kernel_type are modified, where "modified" means
+ * that some attributes of the given type were added or removed from this AttributeSet. This does
+ * not mean that the data of the remaining attributes in this AttributeSet were also modified. To
+ * check this, use Attribute.modified. */
+ bool modified(AttrKernelDataType kernel_type) const;
+
+ void clear_modified();
+
+ private:
+ /* Set the relevant modified flag for the attribute. Only attributes that are stored in device
+ * arrays will be considered for tagging this AttributeSet as modified. */
+ void tag_modified(const Attribute &attr);
+};
+
+/* AttributeRequest
+ *
+ * Request from a shader to use a certain attribute, so we can figure out
+ * which ones we need to export from the host app end store for the kernel.
+ * The attribute is found either by name or by standard attribute type. */
+
+class AttributeRequest {
+ public:
+ ustring name;
+ AttributeStandard std;
+
+ /* temporary variables used by GeometryManager */
+ TypeDesc type, subd_type;
+ AttributeDescriptor desc, subd_desc;
+
+ explicit AttributeRequest(ustring name_);
+ explicit AttributeRequest(AttributeStandard std);
+};
+
+/* AttributeRequestSet
+ *
+ * Set of attributes requested by a shader. */
+
+class AttributeRequestSet {
+ public:
+ vector<AttributeRequest> requests;
+
+ AttributeRequestSet();
+ ~AttributeRequestSet();
+
+ void add(ustring name);
+ void add(AttributeStandard std);
+ void add(AttributeRequestSet &reqs);
+ void add_standard(ustring name);
+
+ bool find(ustring name);
+ bool find(AttributeStandard std);
+
+ size_t size();
+ void clear();
+
+ bool modified(const AttributeRequestSet &other);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __ATTRIBUTE_H__ */
diff --git a/intern/cycles/scene/background.cpp b/intern/cycles/scene/background.cpp
new file mode 100644
index 00000000000..72dccc6f9a8
--- /dev/null
+++ b/intern/cycles/scene/background.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/background.h"
+#include "device/device.h"
+#include "scene/integrator.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+#include "scene/stats.h"
+
+#include "util/foreach.h"
+#include "util/math.h"
+#include "util/time.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+NODE_DEFINE(Background)
+{
+ NodeType *type = NodeType::add("background", create);
+
+ SOCKET_BOOLEAN(use_shader, "Use Shader", true);
+ SOCKET_UINT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY);
+
+ SOCKET_BOOLEAN(transparent, "Transparent", false);
+ SOCKET_BOOLEAN(transparent_glass, "Transparent Glass", false);
+ SOCKET_FLOAT(transparent_roughness_threshold, "Transparent Roughness Threshold", 0.0f);
+
+ SOCKET_FLOAT(volume_step_size, "Volume Step Size", 0.1f);
+
+ SOCKET_NODE(shader, "Shader", Shader::get_node_type());
+
+ return type;
+}
+
+Background::Background() : Node(get_node_type())
+{
+ shader = NULL;
+}
+
+Background::~Background()
+{
+ dereference_all_used_nodes();
+}
+
+void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene)
+{
+ if (!is_modified())
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->background.times.add_entry({"device_update", time});
+ }
+ });
+
+ device_free(device, dscene);
+
+ Shader *bg_shader = get_shader(scene);
+
+ /* set shader index and transparent option */
+ KernelBackground *kbackground = &dscene->data.background;
+
+ kbackground->transparent = transparent;
+ kbackground->surface_shader = scene->shader_manager->get_shader_id(bg_shader);
+
+ if (transparent && transparent_glass) {
+ /* Square twice, once for principled BSDF convention, and once for
+ * faster comparison in kernel with anisotropic roughness. */
+ kbackground->transparent_roughness_squared_threshold = sqr(
+ sqr(transparent_roughness_threshold));
+ }
+ else {
+ kbackground->transparent_roughness_squared_threshold = -1.0f;
+ }
+
+ if (bg_shader->has_volume)
+ kbackground->volume_shader = kbackground->surface_shader;
+ else
+ kbackground->volume_shader = SHADER_NONE;
+
+ kbackground->volume_step_size = volume_step_size * scene->integrator->get_volume_step_rate();
+
+ /* No background node, make world shader invisible to all rays, to skip evaluation in kernel. */
+ if (bg_shader->graph->nodes.size() <= 1) {
+ kbackground->surface_shader |= SHADER_EXCLUDE_ANY;
+ }
+ /* Background present, check visibilities */
+ else {
+ if (!(visibility & PATH_RAY_DIFFUSE))
+ kbackground->surface_shader |= SHADER_EXCLUDE_DIFFUSE;
+ if (!(visibility & PATH_RAY_GLOSSY))
+ kbackground->surface_shader |= SHADER_EXCLUDE_GLOSSY;
+ if (!(visibility & PATH_RAY_TRANSMIT))
+ kbackground->surface_shader |= SHADER_EXCLUDE_TRANSMIT;
+ if (!(visibility & PATH_RAY_VOLUME_SCATTER))
+ kbackground->surface_shader |= SHADER_EXCLUDE_SCATTER;
+ if (!(visibility & PATH_RAY_CAMERA))
+ kbackground->surface_shader |= SHADER_EXCLUDE_CAMERA;
+ }
+
+ clear_modified();
+}
+
+void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
+{
+}
+
+void Background::tag_update(Scene *scene)
+{
+ Shader *bg_shader = get_shader(scene);
+ if (bg_shader && bg_shader->is_modified()) {
+ /* Tag as modified to update the KernelBackground visibility information.
+ * We only tag the use_shader socket as modified as it is related to the shader
+ * and to avoid doing unnecessary updates anywhere else. */
+ tag_use_shader_modified();
+ }
+}
+
+Shader *Background::get_shader(const Scene *scene)
+{
+ return (use_shader) ? ((shader) ? shader : scene->default_background) : scene->default_empty;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/background.h b/intern/cycles/scene/background.h
new file mode 100644
index 00000000000..31f15d09749
--- /dev/null
+++ b/intern/cycles/scene/background.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BACKGROUND_H__
+#define __BACKGROUND_H__
+
+#include "graph/node.h"
+
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Scene;
+class Shader;
+
+class Background : public Node {
+ public:
+ NODE_DECLARE
+
+ NODE_SOCKET_API(bool, use_shader)
+
+ NODE_SOCKET_API(uint, visibility)
+ NODE_SOCKET_API(Shader *, shader)
+
+ NODE_SOCKET_API(bool, transparent)
+ NODE_SOCKET_API(bool, transparent_glass)
+ NODE_SOCKET_API(float, transparent_roughness_threshold)
+
+ NODE_SOCKET_API(float, volume_step_size)
+
+ Background();
+ ~Background();
+
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene);
+ void device_free(Device *device, DeviceScene *dscene);
+
+ void tag_update(Scene *scene);
+
+ Shader *get_shader(const Scene *scene);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BACKGROUND_H__ */
diff --git a/intern/cycles/scene/bake.cpp b/intern/cycles/scene/bake.cpp
new file mode 100644
index 00000000000..90c9e0e4ae8
--- /dev/null
+++ b/intern/cycles/scene/bake.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011-2014 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/bake.h"
+#include "scene/integrator.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/shader.h"
+#include "scene/stats.h"
+#include "session/buffers.h"
+
+#include "util/foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+BakeManager::BakeManager()
+{
+ need_update_ = true;
+}
+
+BakeManager::~BakeManager()
+{
+}
+
+bool BakeManager::get_baking() const
+{
+ return !object_name.empty();
+}
+
+void BakeManager::set(Scene *scene, const std::string &object_name_)
+{
+ object_name = object_name_;
+
+ /* create device and update scene */
+ scene->film->tag_modified();
+ scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
+
+ need_update_ = true;
+}
+
+void BakeManager::device_update(Device * /*device*/,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress & /* progress */)
+{
+ if (!need_update())
+ return;
+
+ KernelBake *kbake = &dscene->data.bake;
+ memset(kbake, 0, sizeof(*kbake));
+
+ if (!object_name.empty()) {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->bake.times.add_entry({"device_update", time});
+ }
+ });
+
+ kbake->use = true;
+
+ int object_index = 0;
+ foreach (Object *object, scene->objects) {
+ const Geometry *geom = object->get_geometry();
+ if (object->name == object_name && geom->geometry_type == Geometry::MESH) {
+ kbake->object_index = object_index;
+ kbake->tri_offset = geom->prim_offset;
+ break;
+ }
+
+ object_index++;
+ }
+ }
+
+ need_update_ = false;
+}
+
+void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
+{
+}
+
+void BakeManager::tag_update()
+{
+ need_update_ = true;
+}
+
+bool BakeManager::need_update() const
+{
+ return need_update_;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/bake.h b/intern/cycles/scene/bake.h
new file mode 100644
index 00000000000..370cc20ae4f
--- /dev/null
+++ b/intern/cycles/scene/bake.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011-2014 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BAKE_H__
+#define __BAKE_H__
+
+#include "device/device.h"
+#include "scene/scene.h"
+
+#include "util/progress.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BakeManager {
+ public:
+ BakeManager();
+ ~BakeManager();
+
+ void set(Scene *scene, const std::string &object_name);
+ bool get_baking() const;
+
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
+ void device_free(Device *device, DeviceScene *dscene);
+
+ void tag_update();
+
+ bool need_update() const;
+
+ private:
+ bool need_update_;
+ std::string object_name;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BAKE_H__ */
diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp
new file mode 100644
index 00000000000..5bafe736fb5
--- /dev/null
+++ b/intern/cycles/scene/camera.cpp
@@ -0,0 +1,818 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/camera.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "scene/stats.h"
+#include "scene/tables.h"
+
+#include "device/device.h"
+
+#include "util/foreach.h"
+#include "util/function.h"
+#include "util/log.h"
+#include "util/math_cdf.h"
+#include "util/task.h"
+#include "util/time.h"
+#include "util/vector.h"
+
+/* needed for calculating differentials */
+#include "kernel/device/cpu/compat.h"
+#include "kernel/device/cpu/globals.h"
+
+#include "kernel/camera/camera.h"
+
+CCL_NAMESPACE_BEGIN
+
+static float shutter_curve_eval(float x, array<float> &shutter_curve)
+{
+ if (shutter_curve.size() == 0) {
+ return 1.0f;
+ }
+
+ x *= shutter_curve.size();
+ int index = (int)x;
+ float frac = x - index;
+ if (index < shutter_curve.size() - 1) {
+ return lerp(shutter_curve[index], shutter_curve[index + 1], frac);
+ }
+ else {
+ return shutter_curve[shutter_curve.size() - 1];
+ }
+}
+
+NODE_DEFINE(Camera)
+{
+ NodeType *type = NodeType::add("camera", create);
+
+ SOCKET_FLOAT(shuttertime, "Shutter Time", 1.0f);
+
+ static NodeEnum motion_position_enum;
+ motion_position_enum.insert("start", MOTION_POSITION_START);
+ motion_position_enum.insert("center", MOTION_POSITION_CENTER);
+ motion_position_enum.insert("end", MOTION_POSITION_END);
+ SOCKET_ENUM(motion_position, "Motion Position", motion_position_enum, MOTION_POSITION_CENTER);
+
+ static NodeEnum rolling_shutter_type_enum;
+ rolling_shutter_type_enum.insert("none", ROLLING_SHUTTER_NONE);
+ rolling_shutter_type_enum.insert("top", ROLLING_SHUTTER_TOP);
+ SOCKET_ENUM(rolling_shutter_type,
+ "Rolling Shutter Type",
+ rolling_shutter_type_enum,
+ ROLLING_SHUTTER_NONE);
+ SOCKET_FLOAT(rolling_shutter_duration, "Rolling Shutter Duration", 0.1f);
+
+ SOCKET_FLOAT_ARRAY(shutter_curve, "Shutter Curve", array<float>());
+
+ SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f);
+ SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f);
+ SOCKET_UINT(blades, "Blades", 0);
+ SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f);
+
+ SOCKET_TRANSFORM(matrix, "Matrix", transform_identity());
+ SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
+
+ SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f);
+
+ static NodeEnum type_enum;
+ type_enum.insert("perspective", CAMERA_PERSPECTIVE);
+ type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC);
+ type_enum.insert("panorama", CAMERA_PANORAMA);
+ SOCKET_ENUM(camera_type, "Type", type_enum, CAMERA_PERSPECTIVE);
+
+ static NodeEnum panorama_type_enum;
+ panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR);
+ panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL);
+ panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT);
+ panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID);
+ SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR);
+
+ SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F);
+ SOCKET_FLOAT(fisheye_lens, "Fisheye Lens", 10.5f);
+ SOCKET_FLOAT(latitude_min, "Latitude Min", -M_PI_2_F);
+ SOCKET_FLOAT(latitude_max, "Latitude Max", M_PI_2_F);
+ SOCKET_FLOAT(longitude_min, "Longitude Min", -M_PI_F);
+ SOCKET_FLOAT(longitude_max, "Longitude Max", M_PI_F);
+ SOCKET_FLOAT(fov, "FOV", M_PI_4_F);
+ SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F);
+ SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F);
+
+ static NodeEnum stereo_eye_enum;
+ stereo_eye_enum.insert("none", STEREO_NONE);
+ stereo_eye_enum.insert("left", STEREO_LEFT);
+ stereo_eye_enum.insert("right", STEREO_RIGHT);
+ SOCKET_ENUM(stereo_eye, "Stereo Eye", stereo_eye_enum, STEREO_NONE);
+
+ SOCKET_BOOLEAN(use_spherical_stereo, "Use Spherical Stereo", false);
+
+ SOCKET_FLOAT(interocular_distance, "Interocular Distance", 0.065f);
+ SOCKET_FLOAT(convergence_distance, "Convergence Distance", 30.0f * 0.065f);
+
+ SOCKET_BOOLEAN(use_pole_merge, "Use Pole Merge", false);
+ SOCKET_FLOAT(pole_merge_angle_from, "Pole Merge Angle From", 60.0f * M_PI_F / 180.0f);
+ SOCKET_FLOAT(pole_merge_angle_to, "Pole Merge Angle To", 75.0f * M_PI_F / 180.0f);
+
+ SOCKET_FLOAT(sensorwidth, "Sensor Width", 0.036f);
+ SOCKET_FLOAT(sensorheight, "Sensor Height", 0.024f);
+
+ SOCKET_FLOAT(nearclip, "Near Clip", 1e-5f);
+ SOCKET_FLOAT(farclip, "Far Clip", 1e5f);
+
+ SOCKET_FLOAT(viewplane.left, "Viewplane Left", 0);
+ SOCKET_FLOAT(viewplane.right, "Viewplane Right", 0);
+ SOCKET_FLOAT(viewplane.bottom, "Viewplane Bottom", 0);
+ SOCKET_FLOAT(viewplane.top, "Viewplane Top", 0);
+
+ SOCKET_FLOAT(border.left, "Border Left", 0);
+ SOCKET_FLOAT(border.right, "Border Right", 0);
+ SOCKET_FLOAT(border.bottom, "Border Bottom", 0);
+ SOCKET_FLOAT(border.top, "Border Top", 0);
+
+ SOCKET_FLOAT(viewport_camera_border.left, "Viewport Border Left", 0);
+ SOCKET_FLOAT(viewport_camera_border.right, "Viewport Border Right", 0);
+ SOCKET_FLOAT(viewport_camera_border.bottom, "Viewport Border Bottom", 0);
+ SOCKET_FLOAT(viewport_camera_border.top, "Viewport Border Top", 0);
+
+ SOCKET_FLOAT(offscreen_dicing_scale, "Offscreen Dicing Scale", 1.0f);
+
+ SOCKET_INT(full_width, "Full Width", 1024);
+ SOCKET_INT(full_height, "Full Height", 512);
+
+ SOCKET_BOOLEAN(use_perspective_motion, "Use Perspective Motion", false);
+
+ return type;
+}
+
+Camera::Camera() : Node(get_node_type())
+{
+ shutter_table_offset = TABLE_OFFSET_INVALID;
+
+ width = 1024;
+ height = 512;
+
+ use_perspective_motion = false;
+
+ shutter_curve.resize(RAMP_TABLE_SIZE);
+ for (int i = 0; i < shutter_curve.size(); ++i) {
+ shutter_curve[i] = 1.0f;
+ }
+
+ compute_auto_viewplane();
+
+ screentoworld = projection_identity();
+ rastertoworld = projection_identity();
+ ndctoworld = projection_identity();
+ rastertocamera = projection_identity();
+ cameratoworld = transform_identity();
+ worldtoraster = projection_identity();
+
+ full_rastertocamera = projection_identity();
+
+ dx = zero_float3();
+ dy = zero_float3();
+
+ need_device_update = true;
+ need_flags_update = true;
+ previous_need_motion = -1;
+
+ memset((void *)&kernel_camera, 0, sizeof(kernel_camera));
+}
+
+Camera::~Camera()
+{
+}
+
+void Camera::compute_auto_viewplane()
+{
+ if (camera_type == CAMERA_PANORAMA) {
+ viewplane.left = 0.0f;
+ viewplane.right = 1.0f;
+ viewplane.bottom = 0.0f;
+ viewplane.top = 1.0f;
+ }
+ else {
+ float aspect = (float)full_width / (float)full_height;
+ if (full_width >= full_height) {
+ viewplane.left = -aspect;
+ viewplane.right = aspect;
+ viewplane.bottom = -1.0f;
+ viewplane.top = 1.0f;
+ }
+ else {
+ viewplane.left = -1.0f;
+ viewplane.right = 1.0f;
+ viewplane.bottom = -1.0f / aspect;
+ viewplane.top = 1.0f / aspect;
+ }
+ }
+}
+
+void Camera::update(Scene *scene)
+{
+ Scene::MotionType need_motion = scene->need_motion();
+
+ if (previous_need_motion != need_motion) {
+ /* scene's motion model could have been changed since previous device
+ * camera update this could happen for example in case when one render
+ * layer has got motion pass and another not */
+ need_device_update = true;
+ }
+
+ if (!is_modified())
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->camera.times.add_entry({"update", time});
+ }
+ });
+
+ /* Full viewport to camera border in the viewport. */
+ Transform fulltoborder = transform_from_viewplane(viewport_camera_border);
+ Transform bordertofull = transform_inverse(fulltoborder);
+
+ /* NDC to raster. */
+ Transform ndctoraster = transform_scale(width, height, 1.0f) * bordertofull;
+ Transform full_ndctoraster = transform_scale(full_width, full_height, 1.0f) * bordertofull;
+
+ /* Raster to screen. */
+ Transform screentondc = fulltoborder * transform_from_viewplane(viewplane);
+
+ Transform screentoraster = ndctoraster * screentondc;
+ Transform rastertoscreen = transform_inverse(screentoraster);
+ Transform full_screentoraster = full_ndctoraster * screentondc;
+ Transform full_rastertoscreen = transform_inverse(full_screentoraster);
+
+ /* Screen to camera. */
+ ProjectionTransform cameratoscreen;
+ if (camera_type == CAMERA_PERSPECTIVE)
+ cameratoscreen = projection_perspective(fov, nearclip, farclip);
+ else if (camera_type == CAMERA_ORTHOGRAPHIC)
+ cameratoscreen = projection_orthographic(nearclip, farclip);
+ else
+ cameratoscreen = projection_identity();
+
+ ProjectionTransform screentocamera = projection_inverse(cameratoscreen);
+
+ rastertocamera = screentocamera * rastertoscreen;
+ full_rastertocamera = screentocamera * full_rastertoscreen;
+ cameratoraster = screentoraster * cameratoscreen;
+
+ cameratoworld = matrix;
+ screentoworld = cameratoworld * screentocamera;
+ rastertoworld = cameratoworld * rastertocamera;
+ ndctoworld = rastertoworld * ndctoraster;
+
+ /* note we recompose matrices instead of taking inverses of the above, this
+ * is needed to avoid inverting near degenerate matrices that happen due to
+ * precision issues with large scenes */
+ worldtocamera = transform_inverse(matrix);
+ worldtoscreen = cameratoscreen * worldtocamera;
+ worldtondc = screentondc * worldtoscreen;
+ worldtoraster = ndctoraster * worldtondc;
+
+ /* differentials */
+ if (camera_type == CAMERA_ORTHOGRAPHIC) {
+ dx = transform_perspective_direction(&rastertocamera, make_float3(1, 0, 0));
+ dy = transform_perspective_direction(&rastertocamera, make_float3(0, 1, 0));
+ full_dx = transform_perspective_direction(&full_rastertocamera, make_float3(1, 0, 0));
+ full_dy = transform_perspective_direction(&full_rastertocamera, make_float3(0, 1, 0));
+ }
+ else if (camera_type == CAMERA_PERSPECTIVE) {
+ dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
+ transform_perspective(&rastertocamera, make_float3(0, 0, 0));
+ dy = transform_perspective(&rastertocamera, make_float3(0, 1, 0)) -
+ transform_perspective(&rastertocamera, make_float3(0, 0, 0));
+ full_dx = transform_perspective(&full_rastertocamera, make_float3(1, 0, 0)) -
+ transform_perspective(&full_rastertocamera, make_float3(0, 0, 0));
+ full_dy = transform_perspective(&full_rastertocamera, make_float3(0, 1, 0)) -
+ transform_perspective(&full_rastertocamera, make_float3(0, 0, 0));
+ }
+ else {
+ dx = zero_float3();
+ dy = zero_float3();
+ }
+
+ dx = transform_direction(&cameratoworld, dx);
+ dy = transform_direction(&cameratoworld, dy);
+ full_dx = transform_direction(&cameratoworld, full_dx);
+ full_dy = transform_direction(&cameratoworld, full_dy);
+
+ if (camera_type == CAMERA_PERSPECTIVE) {
+ float3 v = transform_perspective(&full_rastertocamera,
+ make_float3(full_width, full_height, 1.0f));
+ frustum_right_normal = normalize(make_float3(v.z, 0.0f, -v.x));
+ frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y));
+
+ v = transform_perspective(&full_rastertocamera, make_float3(0.0f, 0.0f, 1.0f));
+ frustum_left_normal = normalize(make_float3(-v.z, 0.0f, v.x));
+ frustum_bottom_normal = normalize(make_float3(0.0f, -v.z, v.y));
+ }
+
+ /* Compute kernel camera data. */
+ KernelCamera *kcam = &kernel_camera;
+
+ /* store matrices */
+ kcam->screentoworld = screentoworld;
+ kcam->rastertoworld = rastertoworld;
+ kcam->rastertocamera = rastertocamera;
+ kcam->cameratoworld = cameratoworld;
+ kcam->worldtocamera = worldtocamera;
+ kcam->worldtoscreen = worldtoscreen;
+ kcam->worldtoraster = worldtoraster;
+ kcam->worldtondc = worldtondc;
+ kcam->ndctoworld = ndctoworld;
+
+ /* camera motion */
+ kcam->num_motion_steps = 0;
+ kcam->have_perspective_motion = 0;
+ kernel_camera_motion.clear();
+
+ /* Test if any of the transforms are actually different. */
+ bool have_motion = false;
+ for (size_t i = 0; i < motion.size(); i++) {
+ have_motion = have_motion || motion[i] != matrix;
+ }
+
+ if (need_motion == Scene::MOTION_PASS) {
+ /* TODO(sergey): Support perspective (zoom, fov) motion. */
+ if (camera_type == CAMERA_PANORAMA) {
+ if (have_motion) {
+ kcam->motion_pass_pre = transform_inverse(motion[0]);
+ kcam->motion_pass_post = transform_inverse(motion[motion.size() - 1]);
+ }
+ else {
+ kcam->motion_pass_pre = kcam->worldtocamera;
+ kcam->motion_pass_post = kcam->worldtocamera;
+ }
+ }
+ else {
+ if (have_motion) {
+ kcam->perspective_pre = cameratoraster * transform_inverse(motion[0]);
+ kcam->perspective_post = cameratoraster * transform_inverse(motion[motion.size() - 1]);
+ }
+ else {
+ kcam->perspective_pre = worldtoraster;
+ kcam->perspective_post = worldtoraster;
+ }
+ }
+ }
+ else if (need_motion == Scene::MOTION_BLUR) {
+ if (have_motion) {
+ kernel_camera_motion.resize(motion.size());
+ transform_motion_decompose(kernel_camera_motion.data(), motion.data(), motion.size());
+ kcam->num_motion_steps = motion.size();
+ }
+
+ /* TODO(sergey): Support other types of camera. */
+ if (use_perspective_motion && camera_type == CAMERA_PERSPECTIVE) {
+ /* TODO(sergey): Move to an utility function and de-duplicate with
+ * calculation above.
+ */
+ ProjectionTransform screentocamera_pre = projection_inverse(
+ projection_perspective(fov_pre, nearclip, farclip));
+ ProjectionTransform screentocamera_post = projection_inverse(
+ projection_perspective(fov_post, nearclip, farclip));
+
+ kcam->perspective_pre = screentocamera_pre * rastertoscreen;
+ kcam->perspective_post = screentocamera_post * rastertoscreen;
+ kcam->have_perspective_motion = 1;
+ }
+ }
+
+ /* depth of field */
+ kcam->aperturesize = aperturesize;
+ kcam->focaldistance = focaldistance;
+ kcam->blades = (blades < 3) ? 0.0f : blades;
+ kcam->bladesrotation = bladesrotation;
+
+ /* motion blur */
+ kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime : -1.0f;
+
+ /* type */
+ kcam->type = camera_type;
+
+ /* anamorphic lens bokeh */
+ kcam->inv_aperture_ratio = 1.0f / aperture_ratio;
+
+ /* panorama */
+ kcam->panorama_type = panorama_type;
+ kcam->fisheye_fov = fisheye_fov;
+ kcam->fisheye_lens = fisheye_lens;
+ kcam->equirectangular_range = make_float4(longitude_min - longitude_max,
+ -longitude_min,
+ latitude_min - latitude_max,
+ -latitude_min + M_PI_2_F);
+
+ switch (stereo_eye) {
+ case STEREO_LEFT:
+ kcam->interocular_offset = -interocular_distance * 0.5f;
+ break;
+ case STEREO_RIGHT:
+ kcam->interocular_offset = interocular_distance * 0.5f;
+ break;
+ case STEREO_NONE:
+ default:
+ kcam->interocular_offset = 0.0f;
+ break;
+ }
+
+ kcam->convergence_distance = convergence_distance;
+ if (use_pole_merge) {
+ kcam->pole_merge_angle_from = pole_merge_angle_from;
+ kcam->pole_merge_angle_to = pole_merge_angle_to;
+ }
+ else {
+ kcam->pole_merge_angle_from = -1.0f;
+ kcam->pole_merge_angle_to = -1.0f;
+ }
+
+ /* sensor size */
+ kcam->sensorwidth = sensorwidth;
+ kcam->sensorheight = sensorheight;
+
+ /* render size */
+ kcam->width = width;
+ kcam->height = height;
+
+ /* store differentials */
+ kcam->dx = float3_to_float4(dx);
+ kcam->dy = float3_to_float4(dy);
+
+ /* clipping */
+ kcam->nearclip = nearclip;
+ kcam->cliplength = (farclip == FLT_MAX) ? FLT_MAX : farclip - nearclip;
+
+ /* Camera in volume. */
+ kcam->is_inside_volume = 0;
+
+ /* Rolling shutter effect */
+ kcam->rolling_shutter_type = rolling_shutter_type;
+ kcam->rolling_shutter_duration = rolling_shutter_duration;
+
+ /* Set further update flags */
+ clear_modified();
+ need_device_update = true;
+ need_flags_update = true;
+ previous_need_motion = need_motion;
+}
+
+void Camera::device_update(Device * /* device */, DeviceScene *dscene, Scene *scene)
+{
+ update(scene);
+
+ if (!need_device_update)
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->camera.times.add_entry({"device_update", time});
+ }
+ });
+
+ scene->lookup_tables->remove_table(&shutter_table_offset);
+ if (kernel_camera.shuttertime != -1.0f) {
+ vector<float> shutter_table;
+ util_cdf_inverted(SHUTTER_TABLE_SIZE,
+ 0.0f,
+ 1.0f,
+ function_bind(shutter_curve_eval, _1, shutter_curve),
+ false,
+ shutter_table);
+ shutter_table_offset = scene->lookup_tables->add_table(dscene, shutter_table);
+ kernel_camera.shutter_table_offset = (int)shutter_table_offset;
+ }
+
+ dscene->data.cam = kernel_camera;
+
+ size_t num_motion_steps = kernel_camera_motion.size();
+ if (num_motion_steps) {
+ DecomposedTransform *camera_motion = dscene->camera_motion.alloc(num_motion_steps);
+ memcpy(camera_motion, kernel_camera_motion.data(), sizeof(*camera_motion) * num_motion_steps);
+ dscene->camera_motion.copy_to_device();
+ }
+ else {
+ dscene->camera_motion.free();
+ }
+}
+
+void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scene *scene)
+{
+ if (!need_device_update && !need_flags_update) {
+ return;
+ }
+
+ KernelIntegrator *kintegrator = &dscene->data.integrator;
+ if (kintegrator->use_volumes) {
+ KernelCamera *kcam = &dscene->data.cam;
+ BoundBox viewplane_boundbox = viewplane_bounds_get();
+
+ /* Parallel object update, with grain size to avoid too much threading overhead
+ * for individual objects. */
+ static const int OBJECTS_PER_TASK = 32;
+ parallel_for(blocked_range<size_t>(0, scene->objects.size(), OBJECTS_PER_TASK),
+ [&](const blocked_range<size_t> &r) {
+ for (size_t i = r.begin(); i != r.end(); i++) {
+ Object *object = scene->objects[i];
+ if (object->get_geometry()->has_volume &&
+ viewplane_boundbox.intersects(object->bounds)) {
+ /* TODO(sergey): Consider adding more grained check. */
+ VLOG(1) << "Detected camera inside volume.";
+ kcam->is_inside_volume = 1;
+ parallel_for_cancel();
+ break;
+ }
+ }
+ });
+
+ if (!kcam->is_inside_volume) {
+ VLOG(1) << "Camera is outside of the volume.";
+ }
+ }
+
+ need_device_update = false;
+ need_flags_update = false;
+}
+
+void Camera::device_free(Device * /*device*/, DeviceScene *dscene, Scene *scene)
+{
+ scene->lookup_tables->remove_table(&shutter_table_offset);
+ dscene->camera_motion.free();
+}
+
+float3 Camera::transform_raster_to_world(float raster_x, float raster_y)
+{
+ float3 D, P;
+ if (camera_type == CAMERA_PERSPECTIVE) {
+ D = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
+ float3 Pclip = normalize(D);
+ P = zero_float3();
+ /* TODO(sergey): Aperture support? */
+ P = transform_point(&cameratoworld, P);
+ D = normalize(transform_direction(&cameratoworld, D));
+ /* TODO(sergey): Clipping is conditional in kernel, and hence it could
+ * be mistakes in here, currently leading to wrong camera-in-volume
+ * detection.
+ */
+ P += nearclip * D / Pclip.z;
+ }
+ else if (camera_type == CAMERA_ORTHOGRAPHIC) {
+ D = make_float3(0.0f, 0.0f, 1.0f);
+ /* TODO(sergey): Aperture support? */
+ P = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
+ P = transform_point(&cameratoworld, P);
+ D = normalize(transform_direction(&cameratoworld, D));
+ }
+ else {
+ assert(!"unsupported camera type");
+ }
+ return P;
+}
+
+BoundBox Camera::viewplane_bounds_get()
+{
+ /* TODO(sergey): This is all rather stupid, but is there a way to perform
+ * checks we need in a more clear and smart fashion? */
+ BoundBox bounds = BoundBox::empty;
+
+ if (camera_type == CAMERA_PANORAMA) {
+ if (use_spherical_stereo == false) {
+ bounds.grow(make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w), nearclip);
+ }
+ else {
+ float half_eye_distance = interocular_distance * 0.5f;
+
+ bounds.grow(
+ make_float3(cameratoworld.x.w + half_eye_distance, cameratoworld.y.w, cameratoworld.z.w),
+ nearclip);
+
+ bounds.grow(
+ make_float3(cameratoworld.z.w, cameratoworld.y.w + half_eye_distance, cameratoworld.z.w),
+ nearclip);
+
+ bounds.grow(
+ make_float3(cameratoworld.x.w - half_eye_distance, cameratoworld.y.w, cameratoworld.z.w),
+ nearclip);
+
+ bounds.grow(
+ make_float3(cameratoworld.x.w, cameratoworld.y.w - half_eye_distance, cameratoworld.z.w),
+ nearclip);
+ }
+ }
+ else {
+ bounds.grow(transform_raster_to_world(0.0f, 0.0f));
+ bounds.grow(transform_raster_to_world(0.0f, (float)height));
+ bounds.grow(transform_raster_to_world((float)width, (float)height));
+ bounds.grow(transform_raster_to_world((float)width, 0.0f));
+ if (camera_type == CAMERA_PERSPECTIVE) {
+ /* Center point has the most distance in local Z axis,
+ * use it to construct bounding box/
+ */
+ bounds.grow(transform_raster_to_world(0.5f * width, 0.5f * height));
+ }
+ }
+ return bounds;
+}
+
+float Camera::world_to_raster_size(float3 P)
+{
+ float res = 1.0f;
+
+ if (camera_type == CAMERA_ORTHOGRAPHIC) {
+ res = min(len(full_dx), len(full_dy));
+
+ if (offscreen_dicing_scale > 1.0f) {
+ float3 p = transform_point(&worldtocamera, P);
+ float3 v1 = transform_perspective(&full_rastertocamera,
+ make_float3(full_width, full_height, 0.0f));
+ float3 v2 = transform_perspective(&full_rastertocamera, zero_float3());
+
+ /* Create point clamped to frustum */
+ float3 c;
+ c.x = max(v2.x, min(v1.x, p.x));
+ c.y = max(v2.y, min(v1.y, p.y));
+ c.z = max(0.0f, p.z);
+
+ /* Check right side */
+ float f_dist = len(p - c) / sqrtf((v1.x * v1.x + v1.y * v1.y) * 0.5f);
+ if (f_dist < 0.0f) {
+ /* Check left side */
+ f_dist = len(p - c) / sqrtf((v2.x * v2.x + v2.y * v2.y) * 0.5f);
+ }
+ if (f_dist > 0.0f) {
+ res += res * f_dist * (offscreen_dicing_scale - 1.0f);
+ }
+ }
+ }
+ else if (camera_type == CAMERA_PERSPECTIVE) {
+ /* Calculate as if point is directly ahead of the camera. */
+ float3 raster = make_float3(0.5f * full_width, 0.5f * full_height, 0.0f);
+ float3 Pcamera = transform_perspective(&full_rastertocamera, raster);
+
+ /* dDdx */
+ float3 Ddiff = transform_direction(&cameratoworld, Pcamera);
+ float3 dx = len_squared(full_dx) < len_squared(full_dy) ? full_dx : full_dy;
+ float3 dDdx = normalize(Ddiff + dx) - normalize(Ddiff);
+
+ /* dPdx */
+ float dist = len(transform_point(&worldtocamera, P));
+ float3 D = normalize(Ddiff);
+ res = len(dist * dDdx - dot(dist * dDdx, D) * D);
+
+ /* Decent approx distance to frustum
+ * (doesn't handle corners correctly, but not that big of a deal) */
+ float f_dist = 0.0f;
+
+ if (offscreen_dicing_scale > 1.0f) {
+ float3 p = transform_point(&worldtocamera, P);
+
+ /* Distance from the four planes */
+ float r = dot(p, frustum_right_normal);
+ float t = dot(p, frustum_top_normal);
+ float l = dot(p, frustum_left_normal);
+ float b = dot(p, frustum_bottom_normal);
+
+ if (r <= 0.0f && l <= 0.0f && t <= 0.0f && b <= 0.0f) {
+ /* Point is inside frustum */
+ f_dist = 0.0f;
+ }
+ else if (r > 0.0f && l > 0.0f && t > 0.0f && b > 0.0f) {
+ /* Point is behind frustum */
+ f_dist = len(p);
+ }
+ else {
+ /* Point may be behind or off to the side, need to check */
+ float3 along_right = make_float3(-frustum_right_normal.z, 0.0f, frustum_right_normal.x);
+ float3 along_left = make_float3(frustum_left_normal.z, 0.0f, -frustum_left_normal.x);
+ float3 along_top = make_float3(0.0f, -frustum_top_normal.z, frustum_top_normal.y);
+ float3 along_bottom = make_float3(0.0f, frustum_bottom_normal.z, -frustum_bottom_normal.y);
+
+ float dist[] = {r, l, t, b};
+ float3 along[] = {along_right, along_left, along_top, along_bottom};
+
+ bool test_o = false;
+
+ float *d = dist;
+ float3 *a = along;
+ for (int i = 0; i < 4; i++, d++, a++) {
+ /* Test if we should check this side at all */
+ if (*d > 0.0f) {
+ if (dot(p, *a) >= 0.0f) {
+ /* We are in front of the back edge of this side of the frustum */
+ f_dist = max(f_dist, *d);
+ }
+ else {
+ /* Possibly far enough behind the frustum to use distance to origin instead of edge
+ */
+ test_o = true;
+ }
+ }
+ }
+
+ if (test_o) {
+ f_dist = (f_dist > 0) ? min(f_dist, len(p)) : len(p);
+ }
+ }
+
+ if (f_dist > 0.0f) {
+ res += len(dDdx - dot(dDdx, D) * D) * f_dist * (offscreen_dicing_scale - 1.0f);
+ }
+ }
+ }
+ else if (camera_type == CAMERA_PANORAMA) {
+ float3 D = transform_point(&worldtocamera, P);
+ float dist = len(D);
+
+ Ray ray;
+ memset(&ray, 0, sizeof(ray));
+
+ /* Distortion can become so great that the results become meaningless, there
+ * may be a better way to do this, but calculating differentials from the
+ * point directly ahead seems to produce good enough results. */
+#if 0
+ float2 dir = direction_to_panorama(&kernel_camera, kernel_camera_motion.data(), normalize(D));
+ float3 raster = transform_perspective(&full_cameratoraster, make_float3(dir.x, dir.y, 0.0f));
+
+ ray.t = 1.0f;
+ camera_sample_panorama(
+ &kernel_camera, kernel_camera_motion.data(), raster.x, raster.y, 0.0f, 0.0f, &ray);
+ if (ray.t == 0.0f) {
+ /* No differentials, just use from directly ahead. */
+ camera_sample_panorama(&kernel_camera,
+ kernel_camera_motion.data(),
+ 0.5f * full_width,
+ 0.5f * full_height,
+ 0.0f,
+ 0.0f,
+ &ray);
+ }
+#else
+ camera_sample_panorama(&kernel_camera,
+# ifdef __CAMERA_MOTION__
+ kernel_camera_motion.data(),
+# endif
+ 0.5f * full_width,
+ 0.5f * full_height,
+ 0.0f,
+ 0.0f,
+ &ray);
+#endif
+
+ /* TODO: would it help to use more accurate differentials here? */
+ differential3 dP;
+ differential_transfer_compact(&dP, ray.dP, ray.D, ray.dD, ray.D, dist);
+
+ return max(len(dP.dx), len(dP.dy));
+ }
+
+ return res;
+}
+
+bool Camera::use_motion() const
+{
+ return motion.size() > 1;
+}
+
+void Camera::set_screen_size(int width_, int height_)
+{
+ if (width_ != width || height_ != height) {
+ width = width_;
+ height = height_;
+ tag_modified();
+ }
+}
+
+float Camera::motion_time(int step) const
+{
+ return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
+}
+
+int Camera::motion_step(float time) const
+{
+ if (use_motion()) {
+ for (int step = 0; step < motion.size(); step++) {
+ if (time == motion_time(step)) {
+ return step;
+ }
+ }
+ }
+
+ return -1;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/camera.h b/intern/cycles/scene/camera.h
new file mode 100644
index 00000000000..58e39599267
--- /dev/null
+++ b/intern/cycles/scene/camera.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CAMERA_H__
+#define __CAMERA_H__
+
+#include "kernel/types.h"
+
+#include "graph/node.h"
+
+#include "util/array.h"
+#include "util/boundbox.h"
+#include "util/projection.h"
+#include "util/transform.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Scene;
+
+/* Camera
+ *
+ * The camera parameters are quite standard, tested to be both compatible with
+ * Renderman, and Blender after remapping.
+ */
+
+class Camera : public Node {
+ public:
+ NODE_DECLARE
+
+ /* Specifies an offset for the shutter's time interval. */
+ enum MotionPosition {
+ /* Shutter opens at the current frame. */
+ MOTION_POSITION_START = 0,
+ /* Shutter is fully open at the current frame. */
+ MOTION_POSITION_CENTER = 1,
+ /* Shutter closes at the current frame. */
+ MOTION_POSITION_END = 2,
+
+ MOTION_NUM_POSITIONS,
+ };
+
+ /* Specifies rolling shutter effect. */
+ enum RollingShutterType {
+ /* No rolling shutter effect. */
+ ROLLING_SHUTTER_NONE = 0,
+ /* Sensor is being scanned vertically from top to bottom. */
+ ROLLING_SHUTTER_TOP = 1,
+
+ ROLLING_SHUTTER_NUM_TYPES,
+ };
+
+ /* Stereo Type */
+ enum StereoEye {
+ STEREO_NONE,
+ STEREO_LEFT,
+ STEREO_RIGHT,
+ };
+
+ /* motion blur */
+ NODE_SOCKET_API(float, shuttertime)
+ NODE_SOCKET_API(MotionPosition, motion_position)
+ NODE_SOCKET_API_ARRAY(array<float>, shutter_curve)
+ size_t shutter_table_offset;
+
+ /* ** Rolling shutter effect. ** */
+ /* Defines rolling shutter effect type. */
+ NODE_SOCKET_API(RollingShutterType, rolling_shutter_type)
+ /* Specifies exposure time of scan-lines when using
+ * rolling shutter effect.
+ */
+ NODE_SOCKET_API(float, rolling_shutter_duration)
+
+ /* depth of field */
+ NODE_SOCKET_API(float, focaldistance)
+ NODE_SOCKET_API(float, aperturesize)
+ NODE_SOCKET_API(uint, blades)
+ NODE_SOCKET_API(float, bladesrotation)
+
+ /* type */
+ NODE_SOCKET_API(CameraType, camera_type)
+ NODE_SOCKET_API(float, fov)
+
+ /* panorama */
+ NODE_SOCKET_API(PanoramaType, panorama_type)
+ NODE_SOCKET_API(float, fisheye_fov)
+ NODE_SOCKET_API(float, fisheye_lens)
+ NODE_SOCKET_API(float, latitude_min)
+ NODE_SOCKET_API(float, latitude_max)
+ NODE_SOCKET_API(float, longitude_min)
+ NODE_SOCKET_API(float, longitude_max)
+
+ /* panorama stereo */
+ NODE_SOCKET_API(StereoEye, stereo_eye)
+ NODE_SOCKET_API(bool, use_spherical_stereo)
+ NODE_SOCKET_API(float, interocular_distance)
+ NODE_SOCKET_API(float, convergence_distance)
+ NODE_SOCKET_API(bool, use_pole_merge)
+ NODE_SOCKET_API(float, pole_merge_angle_from)
+ NODE_SOCKET_API(float, pole_merge_angle_to)
+
+ /* anamorphic lens bokeh */
+ NODE_SOCKET_API(float, aperture_ratio)
+
+ /* sensor */
+ NODE_SOCKET_API(float, sensorwidth)
+ NODE_SOCKET_API(float, sensorheight)
+
+ /* clipping */
+ NODE_SOCKET_API(float, nearclip)
+ NODE_SOCKET_API(float, farclip)
+
+ /* screen */
+ BoundBox2D viewplane;
+ NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, left)
+ NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, right)
+ NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, bottom)
+ NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, top)
+
+ /* width and height change during preview, so we need these for calculating dice rates. */
+ NODE_SOCKET_API(int, full_width)
+ NODE_SOCKET_API(int, full_height)
+ /* controls how fast the dicing rate falls off for geometry out side of view */
+ NODE_SOCKET_API(float, offscreen_dicing_scale)
+
+ /* border */
+ BoundBox2D border;
+ NODE_SOCKET_API_STRUCT_MEMBER(float, border, left)
+ NODE_SOCKET_API_STRUCT_MEMBER(float, border, right)
+ NODE_SOCKET_API_STRUCT_MEMBER(float, border, bottom)
+ NODE_SOCKET_API_STRUCT_MEMBER(float, border, top)
+
+ BoundBox2D viewport_camera_border;
+ NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, left)
+ NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, right)
+ NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, bottom)
+ NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, top)
+
+ /* transformation */
+ NODE_SOCKET_API(Transform, matrix)
+
+ /* motion */
+ NODE_SOCKET_API_ARRAY(array<Transform>, motion)
+ NODE_SOCKET_API(bool, use_perspective_motion)
+ NODE_SOCKET_API(float, fov_pre)
+ NODE_SOCKET_API(float, fov_post)
+
+ /* computed camera parameters */
+ ProjectionTransform screentoworld;
+ ProjectionTransform rastertoworld;
+ ProjectionTransform ndctoworld;
+ Transform cameratoworld;
+
+ ProjectionTransform worldtoraster;
+ ProjectionTransform worldtoscreen;
+ ProjectionTransform worldtondc;
+ Transform worldtocamera;
+
+ ProjectionTransform rastertocamera;
+ ProjectionTransform cameratoraster;
+
+ ProjectionTransform full_rastertocamera;
+
+ float3 dx;
+ float3 dy;
+
+ float3 full_dx;
+ float3 full_dy;
+
+ float3 frustum_right_normal;
+ float3 frustum_top_normal;
+ float3 frustum_left_normal;
+ float3 frustum_bottom_normal;
+
+ /* update */
+ bool need_device_update;
+ bool need_flags_update;
+ int previous_need_motion;
+
+ /* Kernel camera data, copied here for dicing. */
+ KernelCamera kernel_camera;
+ array<DecomposedTransform> kernel_camera_motion;
+
+ private:
+ int width;
+ int height;
+
+ public:
+ /* functions */
+ Camera();
+ ~Camera();
+
+ void compute_auto_viewplane();
+
+ void update(Scene *scene);
+
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene);
+ void device_update_volume(Device *device, DeviceScene *dscene, Scene *scene);
+ void device_free(Device *device, DeviceScene *dscene, Scene *scene);
+
+ /* Public utility functions. */
+ BoundBox viewplane_bounds_get();
+
+ /* Calculates the width of a pixel at point in world space. */
+ float world_to_raster_size(float3 P);
+
+ /* Motion blur. */
+ float motion_time(int step) const;
+ int motion_step(float time) const;
+ bool use_motion() const;
+
+ void set_screen_size(int width_, int height_);
+
+ private:
+ /* Private utility functions. */
+ float3 transform_raster_to_world(float raster_x, float raster_y);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __CAMERA_H__ */
diff --git a/intern/cycles/scene/colorspace.cpp b/intern/cycles/scene/colorspace.cpp
new file mode 100644
index 00000000000..c1a308fcbaa
--- /dev/null
+++ b/intern/cycles/scene/colorspace.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/colorspace.h"
+
+#include "util/color.h"
+#include "util/half.h"
+#include "util/image.h"
+#include "util/log.h"
+#include "util/math.h"
+#include "util/thread.h"
+#include "util/vector.h"
+
+#ifdef WITH_OCIO
+# include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* Builtin colorspaces. */
+ustring u_colorspace_auto;
+ustring u_colorspace_raw("__builtin_raw");
+ustring u_colorspace_srgb("__builtin_srgb");
+
+/* Cached data. */
+#ifdef WITH_OCIO
+static thread_mutex cache_colorspaces_mutex;
+static thread_mutex cache_processors_mutex;
+static unordered_map<ustring, ustring, ustringHash> cached_colorspaces;
+static unordered_map<ustring, OCIO::ConstProcessorRcPtr, ustringHash> cached_processors;
+#endif
+
+ColorSpaceProcessor *ColorSpaceManager::get_processor(ustring colorspace)
+{
+#ifdef WITH_OCIO
+ /* Only use this for OpenColorIO color spaces, not the builtin ones. */
+ assert(colorspace != u_colorspace_srgb && colorspace != u_colorspace_auto);
+
+ if (colorspace == u_colorspace_raw) {
+ return NULL;
+ }
+
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ if (!config) {
+ return NULL;
+ }
+
+ /* Cache processor until free_memory(), memory overhead is expected to be
+ * small and the processor is likely to be reused. */
+ thread_scoped_lock cache_processors_lock(cache_processors_mutex);
+ if (cached_processors.find(colorspace) == cached_processors.end()) {
+ try {
+ cached_processors[colorspace] = config->getProcessor(colorspace.c_str(), "scene_linear");
+ }
+ catch (OCIO::Exception &exception) {
+ cached_processors[colorspace] = OCIO::ConstProcessorRcPtr();
+ VLOG(1) << "Colorspace " << colorspace.c_str()
+ << " can't be converted to scene_linear: " << exception.what();
+ }
+ }
+
+ const OCIO::Processor *processor = cached_processors[colorspace].get();
+ return (ColorSpaceProcessor *)processor;
+#else
+ /* No OpenColorIO. */
+ (void)colorspace;
+ return NULL;
+#endif
+}
+
+bool ColorSpaceManager::colorspace_is_data(ustring colorspace)
+{
+ if (colorspace == u_colorspace_auto || colorspace == u_colorspace_raw ||
+ colorspace == u_colorspace_srgb) {
+ return false;
+ }
+
+#ifdef WITH_OCIO
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ if (!config) {
+ return false;
+ }
+
+ try {
+ OCIO::ConstColorSpaceRcPtr space = config->getColorSpace(colorspace.c_str());
+ return space && space->isData();
+ }
+ catch (OCIO::Exception &) {
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
+ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace,
+ const char *file_format,
+ bool is_float)
+{
+ if (colorspace == u_colorspace_auto) {
+ /* Auto detect sRGB or raw if none specified. */
+ if (is_float) {
+ bool srgb = (colorspace == "sRGB" || colorspace == "GammaCorrected" ||
+ (colorspace.empty() &&
+ (strcmp(file_format, "png") == 0 || strcmp(file_format, "tiff") == 0 ||
+ strcmp(file_format, "dpx") == 0 || strcmp(file_format, "jpeg2000") == 0)));
+ return srgb ? u_colorspace_srgb : u_colorspace_raw;
+ }
+ else {
+ return u_colorspace_srgb;
+ }
+ }
+ else if (colorspace == u_colorspace_srgb || colorspace == u_colorspace_raw) {
+ /* Builtin colorspaces. */
+ return colorspace;
+ }
+ else {
+ /* Use OpenColorIO. */
+#ifdef WITH_OCIO
+ {
+ thread_scoped_lock cache_lock(cache_colorspaces_mutex);
+ /* Cached lookup. */
+ if (cached_colorspaces.find(colorspace) != cached_colorspaces.end()) {
+ return cached_colorspaces[colorspace];
+ }
+ }
+
+ /* Detect if it matches a simple builtin colorspace. */
+ bool is_scene_linear, is_srgb;
+ is_builtin_colorspace(colorspace, is_scene_linear, is_srgb);
+
+ thread_scoped_lock cache_lock(cache_colorspaces_mutex);
+ if (is_scene_linear) {
+ VLOG(1) << "Colorspace " << colorspace.string() << " is no-op";
+ cached_colorspaces[colorspace] = u_colorspace_raw;
+ return u_colorspace_raw;
+ }
+ else if (is_srgb) {
+ VLOG(1) << "Colorspace " << colorspace.string() << " is sRGB";
+ cached_colorspaces[colorspace] = u_colorspace_srgb;
+ return u_colorspace_srgb;
+ }
+
+ /* Verify if we can convert from the requested color space. */
+ if (!get_processor(colorspace)) {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ if (!config || !config->getColorSpace(colorspace.c_str())) {
+ VLOG(1) << "Colorspace " << colorspace.c_str() << " not found, using raw instead";
+ }
+ else {
+ VLOG(1) << "Colorspace " << colorspace.c_str()
+ << " can't be converted to scene_linear, using raw instead";
+ }
+ cached_colorspaces[colorspace] = u_colorspace_raw;
+ return u_colorspace_raw;
+ }
+
+ /* Convert to/from colorspace with OpenColorIO. */
+ VLOG(1) << "Colorspace " << colorspace.string() << " handled through OpenColorIO";
+ cached_colorspaces[colorspace] = colorspace;
+ return colorspace;
+#else
+ VLOG(1) << "Colorspace " << colorspace.c_str() << " not available, built without OpenColorIO";
+ return u_colorspace_raw;
+#endif
+ }
+}
+
+void ColorSpaceManager::is_builtin_colorspace(ustring colorspace,
+ bool &is_scene_linear,
+ bool &is_srgb)
+{
+#ifdef WITH_OCIO
+ const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace);
+ if (!processor) {
+ is_scene_linear = false;
+ is_srgb = false;
+ return;
+ }
+
+ OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
+ is_scene_linear = true;
+ is_srgb = true;
+ for (int i = 0; i < 256; i++) {
+ float v = i / 255.0f;
+
+ float cR[3] = {v, 0, 0};
+ float cG[3] = {0, v, 0};
+ float cB[3] = {0, 0, v};
+ float cW[3] = {v, v, v};
+ device_processor->applyRGB(cR);
+ device_processor->applyRGB(cG);
+ device_processor->applyRGB(cB);
+ device_processor->applyRGB(cW);
+
+ /* Make sure that there is no channel crosstalk. */
+ if (fabsf(cR[1]) > 1e-5f || fabsf(cR[2]) > 1e-5f || fabsf(cG[0]) > 1e-5f ||
+ fabsf(cG[2]) > 1e-5f || fabsf(cB[0]) > 1e-5f || fabsf(cB[1]) > 1e-5f) {
+ is_scene_linear = false;
+ is_srgb = false;
+ break;
+ }
+ /* Make sure that the three primaries combine linearly. */
+ if (!compare_floats(cR[0], cW[0], 1e-6f, 64) || !compare_floats(cG[1], cW[1], 1e-6f, 64) ||
+ !compare_floats(cB[2], cW[2], 1e-6f, 64)) {
+ is_scene_linear = false;
+ is_srgb = false;
+ break;
+ }
+ /* Make sure that the three channels behave identically. */
+ if (!compare_floats(cW[0], cW[1], 1e-6f, 64) || !compare_floats(cW[1], cW[2], 1e-6f, 64)) {
+ is_scene_linear = false;
+ is_srgb = false;
+ break;
+ }
+
+ float out_v = average(make_float3(cW[0], cW[1], cW[2]));
+ if (!compare_floats(v, out_v, 1e-6f, 64)) {
+ is_scene_linear = false;
+ }
+ if (!compare_floats(color_srgb_to_linear(v), out_v, 1e-6f, 64)) {
+ is_srgb = false;
+ }
+ }
+#else
+ (void)colorspace;
+ is_scene_linear = false;
+ is_srgb = false;
+#endif
+}
+
+#ifdef WITH_OCIO
+
+template<typename T> inline float4 cast_to_float4(T *data)
+{
+ return make_float4(util_image_cast_to_float(data[0]),
+ util_image_cast_to_float(data[1]),
+ util_image_cast_to_float(data[2]),
+ util_image_cast_to_float(data[3]));
+}
+
+template<typename T> inline void cast_from_float4(T *data, float4 value)
+{
+ data[0] = util_image_cast_from_float<T>(value.x);
+ data[1] = util_image_cast_from_float<T>(value.y);
+ data[2] = util_image_cast_from_float<T>(value.z);
+ data[3] = util_image_cast_from_float<T>(value.w);
+}
+
+/* Slower versions for other all data types, which needs to convert to float and back. */
+template<typename T, bool compress_as_srgb = false>
+inline void processor_apply_pixels(const OCIO::Processor *processor, T *pixels, size_t num_pixels)
+{
+ /* TODO: implement faster version for when we know the conversion
+ * is a simple matrix transform between linear spaces. In that case
+ * un-premultiply is not needed. */
+ OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
+
+ /* Process large images in chunks to keep temporary memory requirement down. */
+ const size_t chunk_size = std::min((size_t)(16 * 1024 * 1024), num_pixels);
+ vector<float4> float_pixels(chunk_size);
+
+ for (size_t j = 0; j < num_pixels; j += chunk_size) {
+ size_t width = std::min(chunk_size, num_pixels - j);
+
+ for (size_t i = 0; i < width; i++) {
+ float4 value = cast_to_float4(pixels + 4 * (j + i));
+
+ if (!(value.w <= 0.0f || value.w == 1.0f)) {
+ float inv_alpha = 1.0f / value.w;
+ value.x *= inv_alpha;
+ value.y *= inv_alpha;
+ value.z *= inv_alpha;
+ }
+
+ float_pixels[i] = value;
+ }
+
+ OCIO::PackedImageDesc desc((float *)float_pixels.data(), width, 1, 4);
+ device_processor->apply(desc);
+
+ for (size_t i = 0; i < width; i++) {
+ float4 value = float_pixels[i];
+
+ if (compress_as_srgb) {
+ value = color_linear_to_srgb_v4(value);
+ }
+
+ if (!(value.w <= 0.0f || value.w == 1.0f)) {
+ value.x *= value.w;
+ value.y *= value.w;
+ value.z *= value.w;
+ }
+
+ cast_from_float4(pixels + 4 * (j + i), value);
+ }
+ }
+}
+#endif
+
+template<typename T>
+void ColorSpaceManager::to_scene_linear(ustring colorspace,
+ T *pixels,
+ size_t num_pixels,
+ bool compress_as_srgb)
+{
+#ifdef WITH_OCIO
+ const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace);
+
+ if (processor) {
+ if (compress_as_srgb) {
+ /* Compress output as sRGB. */
+ processor_apply_pixels<T, true>(processor, pixels, num_pixels);
+ }
+ else {
+ /* Write output as scene linear directly. */
+ processor_apply_pixels<T>(processor, pixels, num_pixels);
+ }
+ }
+#else
+ (void)colorspace;
+ (void)pixels;
+ (void)num_pixels;
+ (void)compress_as_srgb;
+#endif
+}
+
+void ColorSpaceManager::to_scene_linear(ColorSpaceProcessor *processor_,
+ float *pixel,
+ int channels)
+{
+#ifdef WITH_OCIO
+ const OCIO::Processor *processor = (const OCIO::Processor *)processor_;
+
+ if (processor) {
+ OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
+ if (channels == 3) {
+ device_processor->applyRGB(pixel);
+ }
+ else if (channels == 4) {
+ if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
+ /* Fast path for RGBA. */
+ device_processor->applyRGB(pixel);
+ }
+ else {
+ /* Un-associate and associate alpha since color management should not
+ * be affected by transparency. */
+ float alpha = pixel[3];
+ float inv_alpha = 1.0f / alpha;
+
+ pixel[0] *= inv_alpha;
+ pixel[1] *= inv_alpha;
+ pixel[2] *= inv_alpha;
+
+ device_processor->applyRGB(pixel);
+
+ pixel[0] *= alpha;
+ pixel[1] *= alpha;
+ pixel[2] *= alpha;
+ }
+ }
+ }
+#else
+ (void)processor_;
+ (void)pixel;
+ (void)channels;
+#endif
+}
+
+void ColorSpaceManager::free_memory()
+{
+#ifdef WITH_OCIO
+ map_free_memory(cached_colorspaces);
+ map_free_memory(cached_processors);
+#endif
+}
+
+/* Template instantiations so we don't have to inline functions. */
+template void ColorSpaceManager::to_scene_linear(ustring, uchar *, size_t, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, bool);
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/colorspace.h b/intern/cycles/scene/colorspace.h
new file mode 100644
index 00000000000..7f7bc604f07
--- /dev/null
+++ b/intern/cycles/scene/colorspace.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __COLORSPACE_H__
+#define __COLORSPACE_H__
+
+#include "util/map.h"
+#include "util/param.h"
+
+CCL_NAMESPACE_BEGIN
+
+extern ustring u_colorspace_auto;
+extern ustring u_colorspace_raw;
+extern ustring u_colorspace_srgb;
+
+class ColorSpaceProcessor;
+
+class ColorSpaceManager {
+ public:
+ /* Convert used specified colorspace to a colorspace that we are able to
+ * convert to and from. If the colorspace is u_colorspace_auto, we auto
+ * detect a colospace. */
+ static ustring detect_known_colorspace(ustring colorspace,
+ const char *file_format,
+ bool is_float);
+
+ /* Test if colorspace is for non-color data. */
+ static bool colorspace_is_data(ustring colorspace);
+
+ /* Convert pixels in the specified colorspace to scene linear color for
+ * rendering. Must be a colorspace returned from detect_known_colorspace. */
+ template<typename T>
+ static void to_scene_linear(ustring colorspace,
+ T *pixels,
+ size_t num_pixels,
+ bool compress_as_srgb);
+
+ /* Efficiently convert pixels to scene linear colorspace at render time,
+ * for OSL where the image texture cache contains original pixels. The
+ * handle is valid for the lifetime of the application. */
+ static ColorSpaceProcessor *get_processor(ustring colorspace);
+ static void to_scene_linear(ColorSpaceProcessor *processor, float *pixel, int channels);
+
+ /* Clear memory when the application exits. Invalidates all processors. */
+ static void free_memory();
+
+ private:
+ static void is_builtin_colorspace(ustring colorspace, bool &is_no_op, bool &is_srgb);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __COLORSPACE_H__ */
diff --git a/intern/cycles/scene/constant_fold.cpp b/intern/cycles/scene/constant_fold.cpp
new file mode 100644
index 00000000000..a1fa34e7628
--- /dev/null
+++ b/intern/cycles/scene/constant_fold.cpp
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/constant_fold.h"
+#include "scene/shader_graph.h"
+
+#include "util/foreach.h"
+#include "util/log.h"
+
+CCL_NAMESPACE_BEGIN
+
+ConstantFolder::ConstantFolder(ShaderGraph *graph,
+ ShaderNode *node,
+ ShaderOutput *output,
+ Scene *scene)
+ : graph(graph), node(node), output(output), scene(scene)
+{
+}
+
+bool ConstantFolder::all_inputs_constant() const
+{
+ foreach (ShaderInput *input, node->inputs) {
+ if (input->link) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ConstantFolder::make_constant(float value) const
+{
+ VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant (" << value
+ << ").";
+
+ foreach (ShaderInput *sock, output->links) {
+ sock->set(value);
+ sock->constant_folded_in = true;
+ }
+
+ graph->disconnect(output);
+}
+
+void ConstantFolder::make_constant(float3 value) const
+{
+ VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant " << value << ".";
+
+ foreach (ShaderInput *sock, output->links) {
+ sock->set(value);
+ sock->constant_folded_in = true;
+ }
+
+ graph->disconnect(output);
+}
+
+void ConstantFolder::make_constant_clamp(float value, bool clamp) const
+{
+ make_constant(clamp ? saturatef(value) : value);
+}
+
+void ConstantFolder::make_constant_clamp(float3 value, bool clamp) const
+{
+ if (clamp) {
+ value.x = saturatef(value.x);
+ value.y = saturatef(value.y);
+ value.z = saturatef(value.z);
+ }
+
+ make_constant(value);
+}
+
+void ConstantFolder::make_zero() const
+{
+ if (output->type() == SocketType::FLOAT) {
+ make_constant(0.0f);
+ }
+ else if (SocketType::is_float3(output->type())) {
+ make_constant(zero_float3());
+ }
+ else {
+ assert(0);
+ }
+}
+
+void ConstantFolder::make_one() const
+{
+ if (output->type() == SocketType::FLOAT) {
+ make_constant(1.0f);
+ }
+ else if (SocketType::is_float3(output->type())) {
+ make_constant(one_float3());
+ }
+ else {
+ assert(0);
+ }
+}
+
+void ConstantFolder::bypass(ShaderOutput *new_output) const
+{
+ assert(new_output);
+
+ VLOG(1) << "Folding " << node->name << "::" << output->name() << " to socket "
+ << new_output->parent->name << "::" << new_output->name() << ".";
+
+ /* Remove all outgoing links from socket and connect them to new_output instead.
+ * The graph->relink method affects node inputs, so it's not safe to use in constant
+ * folding if the node has multiple outputs and will thus be folded multiple times. */
+ vector<ShaderInput *> outputs = output->links;
+
+ graph->disconnect(output);
+
+ foreach (ShaderInput *sock, outputs) {
+ graph->connect(new_output, sock);
+ }
+}
+
+void ConstantFolder::discard() const
+{
+ assert(output->type() == SocketType::CLOSURE);
+
+ VLOG(1) << "Discarding closure " << node->name << ".";
+
+ graph->disconnect(output);
+}
+
+void ConstantFolder::bypass_or_discard(ShaderInput *input) const
+{
+ assert(input->type() == SocketType::CLOSURE);
+
+ if (input->link) {
+ bypass(input->link);
+ }
+ else {
+ discard();
+ }
+}
+
+bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, bool clamp) const
+{
+ if (input->type() != output->type()) {
+ return false;
+ }
+ else if (!input->link) {
+ if (input->type() == SocketType::FLOAT) {
+ make_constant_clamp(node->get_float(input->socket_type), clamp);
+ return true;
+ }
+ else if (SocketType::is_float3(input->type())) {
+ make_constant_clamp(node->get_float3(input->socket_type), clamp);
+ return true;
+ }
+ }
+ else if (!clamp) {
+ bypass(input->link);
+ return true;
+ }
+ else {
+ /* disconnect other inputs if we can't fully bypass due to clamp */
+ foreach (ShaderInput *other, node->inputs) {
+ if (other != input && other->link) {
+ graph->disconnect(other);
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ConstantFolder::is_zero(ShaderInput *input) const
+{
+ if (!input->link) {
+ if (input->type() == SocketType::FLOAT) {
+ return node->get_float(input->socket_type) == 0.0f;
+ }
+ else if (SocketType::is_float3(input->type())) {
+ return node->get_float3(input->socket_type) == zero_float3();
+ }
+ }
+
+ return false;
+}
+
+bool ConstantFolder::is_one(ShaderInput *input) const
+{
+ if (!input->link) {
+ if (input->type() == SocketType::FLOAT) {
+ return node->get_float(input->socket_type) == 1.0f;
+ }
+ else if (SocketType::is_float3(input->type())) {
+ return node->get_float3(input->socket_type) == one_float3();
+ }
+ }
+
+ return false;
+}
+
+/* Specific nodes */
+
+void ConstantFolder::fold_mix(NodeMix type, bool clamp) const
+{
+ ShaderInput *fac_in = node->input("Fac");
+ ShaderInput *color1_in = node->input("Color1");
+ ShaderInput *color2_in = node->input("Color2");
+
+ float fac = saturatef(node->get_float(fac_in->socket_type));
+ bool fac_is_zero = !fac_in->link && fac == 0.0f;
+ bool fac_is_one = !fac_in->link && fac == 1.0f;
+
+ /* remove no-op node when factor is 0.0 */
+ if (fac_is_zero) {
+ /* note that some of the modes will clamp out of bounds values even without use_clamp */
+ if (!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) {
+ if (try_bypass_or_make_constant(color1_in, clamp)) {
+ return;
+ }
+ }
+ }
+
+ switch (type) {
+ case NODE_MIX_BLEND:
+ /* remove useless mix colors nodes */
+ if (color1_in->link && color2_in->link) {
+ if (color1_in->link == color2_in->link) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ break;
+ }
+ }
+ else if (!color1_in->link && !color2_in->link) {
+ float3 color1 = node->get_float3(color1_in->socket_type);
+ float3 color2 = node->get_float3(color2_in->socket_type);
+ if (color1 == color2) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ break;
+ }
+ }
+ /* remove no-op mix color node when factor is 1.0 */
+ if (fac_is_one) {
+ try_bypass_or_make_constant(color2_in, clamp);
+ break;
+ }
+ break;
+ case NODE_MIX_ADD:
+ /* 0 + X (fac 1) == X */
+ if (is_zero(color1_in) && fac_is_one) {
+ try_bypass_or_make_constant(color2_in, clamp);
+ }
+ /* X + 0 (fac ?) == X */
+ else if (is_zero(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ break;
+ case NODE_MIX_SUB:
+ /* X - 0 (fac ?) == X */
+ if (is_zero(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ /* X - X (fac 1) == 0 */
+ else if (color1_in->link && color1_in->link == color2_in->link && fac_is_one) {
+ make_zero();
+ }
+ break;
+ case NODE_MIX_MUL:
+ /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */
+ if (is_one(color1_in) && fac_is_one) {
+ try_bypass_or_make_constant(color2_in, clamp);
+ }
+ else if (is_one(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ /* 0 * ? (fac ?) == 0, ? * 0 (fac 1) == 0 */
+ else if (is_zero(color1_in)) {
+ make_zero();
+ }
+ else if (is_zero(color2_in) && fac_is_one) {
+ make_zero();
+ }
+ break;
+ case NODE_MIX_DIV:
+ /* X / 1 (fac ?) == X */
+ if (is_one(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ /* 0 / ? (fac ?) == 0 */
+ else if (is_zero(color1_in)) {
+ make_zero();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void ConstantFolder::fold_math(NodeMathType type) const
+{
+ ShaderInput *value1_in = node->input("Value1");
+ ShaderInput *value2_in = node->input("Value2");
+
+ switch (type) {
+ case NODE_MATH_ADD:
+ /* X + 0 == 0 + X == X */
+ if (is_zero(value1_in)) {
+ try_bypass_or_make_constant(value2_in);
+ }
+ else if (is_zero(value2_in)) {
+ try_bypass_or_make_constant(value1_in);
+ }
+ break;
+ case NODE_MATH_SUBTRACT:
+ /* X - 0 == X */
+ if (is_zero(value2_in)) {
+ try_bypass_or_make_constant(value1_in);
+ }
+ break;
+ case NODE_MATH_MULTIPLY:
+ /* X * 1 == 1 * X == X */
+ if (is_one(value1_in)) {
+ try_bypass_or_make_constant(value2_in);
+ }
+ else if (is_one(value2_in)) {
+ try_bypass_or_make_constant(value1_in);
+ }
+ /* X * 0 == 0 * X == 0 */
+ else if (is_zero(value1_in) || is_zero(value2_in)) {
+ make_zero();
+ }
+ break;
+ case NODE_MATH_DIVIDE:
+ /* X / 1 == X */
+ if (is_one(value2_in)) {
+ try_bypass_or_make_constant(value1_in);
+ }
+ /* 0 / X == 0 */
+ else if (is_zero(value1_in)) {
+ make_zero();
+ }
+ break;
+ case NODE_MATH_POWER:
+ /* 1 ^ X == X ^ 0 == 1 */
+ if (is_one(value1_in) || is_zero(value2_in)) {
+ make_one();
+ }
+ /* X ^ 1 == X */
+ else if (is_one(value2_in)) {
+ try_bypass_or_make_constant(value1_in);
+ }
+ default:
+ break;
+ }
+}
+
+void ConstantFolder::fold_vector_math(NodeVectorMathType type) const
+{
+ ShaderInput *vector1_in = node->input("Vector1");
+ ShaderInput *vector2_in = node->input("Vector2");
+ ShaderInput *scale_in = node->input("Scale");
+
+ switch (type) {
+ case NODE_VECTOR_MATH_ADD:
+ /* X + 0 == 0 + X == X */
+ if (is_zero(vector1_in)) {
+ try_bypass_or_make_constant(vector2_in);
+ }
+ else if (is_zero(vector2_in)) {
+ try_bypass_or_make_constant(vector1_in);
+ }
+ break;
+ case NODE_VECTOR_MATH_SUBTRACT:
+ /* X - 0 == X */
+ if (is_zero(vector2_in)) {
+ try_bypass_or_make_constant(vector1_in);
+ }
+ break;
+ case NODE_VECTOR_MATH_MULTIPLY:
+ /* X * 0 == 0 * X == 0 */
+ if (is_zero(vector1_in) || is_zero(vector2_in)) {
+ make_zero();
+ } /* X * 1 == 1 * X == X */
+ else if (is_one(vector1_in)) {
+ try_bypass_or_make_constant(vector2_in);
+ }
+ else if (is_one(vector2_in)) {
+ try_bypass_or_make_constant(vector1_in);
+ }
+ break;
+ case NODE_VECTOR_MATH_DIVIDE:
+ /* X / 0 == 0 / X == 0 */
+ if (is_zero(vector1_in) || is_zero(vector2_in)) {
+ make_zero();
+ } /* X / 1 == X */
+ else if (is_one(vector2_in)) {
+ try_bypass_or_make_constant(vector1_in);
+ }
+ break;
+ case NODE_VECTOR_MATH_DOT_PRODUCT:
+ case NODE_VECTOR_MATH_CROSS_PRODUCT:
+ /* X * 0 == 0 * X == 0 */
+ if (is_zero(vector1_in) || is_zero(vector2_in)) {
+ make_zero();
+ }
+ break;
+ case NODE_VECTOR_MATH_LENGTH:
+ case NODE_VECTOR_MATH_ABSOLUTE:
+ if (is_zero(vector1_in)) {
+ make_zero();
+ }
+ break;
+ case NODE_VECTOR_MATH_SCALE:
+ /* X * 0 == 0 * X == 0 */
+ if (is_zero(vector1_in) || is_zero(scale_in)) {
+ make_zero();
+ } /* X * 1 == X */
+ else if (is_one(scale_in)) {
+ try_bypass_or_make_constant(vector1_in);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void ConstantFolder::fold_mapping(NodeMappingType type) const
+{
+ ShaderInput *vector_in = node->input("Vector");
+ ShaderInput *location_in = node->input("Location");
+ ShaderInput *rotation_in = node->input("Rotation");
+ ShaderInput *scale_in = node->input("Scale");
+
+ if (is_zero(scale_in)) {
+ make_zero();
+ }
+ else if ((is_zero(location_in) || type == NODE_MAPPING_TYPE_VECTOR ||
+ type == NODE_MAPPING_TYPE_NORMAL) &&
+ is_zero(rotation_in) && is_one(scale_in)) {
+ try_bypass_or_make_constant(vector_in);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/constant_fold.h b/intern/cycles/scene/constant_fold.h
new file mode 100644
index 00000000000..36b249920d0
--- /dev/null
+++ b/intern/cycles/scene/constant_fold.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONSTANT_FOLD_H__
+#define __CONSTANT_FOLD_H__
+
+#include "kernel/svm/types.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Scene;
+class ShaderGraph;
+class ShaderInput;
+class ShaderNode;
+class ShaderOutput;
+
+class ConstantFolder {
+ public:
+ ShaderGraph *const graph;
+ ShaderNode *const node;
+ ShaderOutput *const output;
+
+ Scene *scene;
+
+ ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output, Scene *scene);
+
+ bool all_inputs_constant() const;
+
+ /* Constant folding helpers */
+ void make_constant(float value) const;
+ void make_constant(float3 value) const;
+ void make_constant_clamp(float value, bool clamp) const;
+ void make_constant_clamp(float3 value, bool clamp) const;
+ void make_zero() const;
+ void make_one() const;
+
+ /* Bypass node, relinking to another output socket. */
+ void bypass(ShaderOutput *output) const;
+
+ /* For closure nodes, discard node entirely or bypass to one of its inputs. */
+ void discard() const;
+ void bypass_or_discard(ShaderInput *input) const;
+
+ /* Bypass or make constant, unless we can't due to clamp being true. */
+ bool try_bypass_or_make_constant(ShaderInput *input, bool clamp = false) const;
+
+ /* Test if shader inputs of the current nodes have fixed values. */
+ bool is_zero(ShaderInput *input) const;
+ bool is_one(ShaderInput *input) const;
+
+ /* Specific nodes. */
+ void fold_mix(NodeMix type, bool clamp) const;
+ void fold_math(NodeMathType type) const;
+ void fold_vector_math(NodeVectorMathType type) const;
+ void fold_mapping(NodeMappingType type) const;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __CONSTANT_FOLD_H__ */
diff --git a/intern/cycles/scene/curves.cpp b/intern/cycles/scene/curves.cpp
new file mode 100644
index 00000000000..7863ce6c666
--- /dev/null
+++ b/intern/cycles/scene/curves.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/curves.h"
+#include "device/device.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+
+#include "util/foreach.h"
+#include "util/map.h"
+#include "util/progress.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Curve functions */
+
+void curvebounds(float *lower, float *upper, float3 *p, int dim)
+{
+ float *p0 = &p[0].x;
+ float *p1 = &p[1].x;
+ float *p2 = &p[2].x;
+ float *p3 = &p[3].x;
+
+ /* Catmull-Rom weights. */
+ float curve_coef[4];
+ curve_coef[0] = p1[dim];
+ curve_coef[1] = 0.5f * (-p0[dim] + p2[dim]);
+ curve_coef[2] = 0.5f * (2 * p0[dim] - 5 * p1[dim] + 4 * p2[dim] - p3[dim]);
+ curve_coef[3] = 0.5f * (-p0[dim] + 3 * p1[dim] - 3 * p2[dim] + p3[dim]);
+
+ float discroot = curve_coef[2] * curve_coef[2] - 3 * curve_coef[3] * curve_coef[1];
+ float ta = -1.0f;
+ float tb = -1.0f;
+
+ if (discroot >= 0) {
+ discroot = sqrtf(discroot);
+ ta = (-curve_coef[2] - discroot) / (3 * curve_coef[3]);
+ tb = (-curve_coef[2] + discroot) / (3 * curve_coef[3]);
+ ta = (ta > 1.0f || ta < 0.0f) ? -1.0f : ta;
+ tb = (tb > 1.0f || tb < 0.0f) ? -1.0f : tb;
+ }
+
+ *upper = max(p1[dim], p2[dim]);
+ *lower = min(p1[dim], p2[dim]);
+
+ float exa = p1[dim];
+ float exb = p2[dim];
+
+ if (ta >= 0.0f) {
+ float t2 = ta * ta;
+ float t3 = t2 * ta;
+ exa = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * ta + curve_coef[0];
+ }
+ if (tb >= 0.0f) {
+ float t2 = tb * tb;
+ float t3 = t2 * tb;
+ exb = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * tb + curve_coef[0];
+ }
+
+ *upper = max(*upper, max(exa, exb));
+ *lower = min(*lower, min(exa, exb));
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/curves.h b/intern/cycles/scene/curves.h
new file mode 100644
index 00000000000..3076f4291f5
--- /dev/null
+++ b/intern/cycles/scene/curves.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CURVES_H__
+#define __CURVES_H__
+
+#include "util/array.h"
+#include "util/types.h"
+
+#include "scene/hair.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Progress;
+class Scene;
+
+void curvebounds(float *lower, float *upper, float3 *p, int dim);
+
+class ParticleCurveData {
+
+ public:
+ ParticleCurveData();
+ ~ParticleCurveData();
+
+ array<int> psys_firstcurve;
+ array<int> psys_curvenum;
+ array<int> psys_shader;
+
+ array<float> psys_rootradius;
+ array<float> psys_tipradius;
+ array<float> psys_shape;
+ array<bool> psys_closetip;
+
+ array<int> curve_firstkey;
+ array<int> curve_keynum;
+ array<float> curve_length;
+ array<float2> curve_uv;
+ array<float4> curve_vcol;
+
+ array<float3> curvekey_co;
+ array<float> curvekey_time;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __CURVES_H__ */
diff --git a/intern/cycles/scene/film.cpp b/intern/cycles/scene/film.cpp
new file mode 100644
index 00000000000..591f309384e
--- /dev/null
+++ b/intern/cycles/scene/film.cpp
@@ -0,0 +1,693 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/film.h"
+#include "device/device.h"
+#include "scene/background.h"
+#include "scene/bake.h"
+#include "scene/camera.h"
+#include "scene/integrator.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "scene/stats.h"
+#include "scene/tables.h"
+
+#include "util/algorithm.h"
+#include "util/foreach.h"
+#include "util/math.h"
+#include "util/math_cdf.h"
+#include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Pixel Filter */
+
+static float filter_func_box(float /*v*/, float /*width*/)
+{
+ return 1.0f;
+}
+
+static float filter_func_gaussian(float v, float width)
+{
+ v *= 6.0f / width;
+ return expf(-2.0f * v * v);
+}
+
+static float filter_func_blackman_harris(float v, float width)
+{
+ v = M_2PI_F * (v / width + 0.5f);
+ return 0.35875f - 0.48829f * cosf(v) + 0.14128f * cosf(2.0f * v) - 0.01168f * cosf(3.0f * v);
+}
+
+static vector<float> filter_table(FilterType type, float width)
+{
+ vector<float> filter_table(FILTER_TABLE_SIZE);
+ float (*filter_func)(float, float) = NULL;
+
+ switch (type) {
+ case FILTER_BOX:
+ filter_func = filter_func_box;
+ break;
+ case FILTER_GAUSSIAN:
+ filter_func = filter_func_gaussian;
+ width *= 3.0f;
+ break;
+ case FILTER_BLACKMAN_HARRIS:
+ filter_func = filter_func_blackman_harris;
+ width *= 2.0f;
+ break;
+ default:
+ assert(0);
+ }
+
+ /* Create importance sampling table. */
+
+ /* TODO(sergey): With the even filter table size resolution we can not
+ * really make it nice symmetric importance map without sampling full range
+ * (meaning, we would need to sample full filter range and not use the
+ * make_symmetric argument).
+ *
+ * Current code matches exactly initial filter table code, but we should
+ * consider either making FILTER_TABLE_SIZE odd value or sample full filter.
+ */
+
+ util_cdf_inverted(FILTER_TABLE_SIZE,
+ 0.0f,
+ width * 0.5f,
+ function_bind(filter_func, _1, width),
+ true,
+ filter_table);
+
+ return filter_table;
+}
+
+/* Film */
+
+NODE_DEFINE(Film)
+{
+ NodeType *type = NodeType::add("film", create);
+
+ SOCKET_FLOAT(exposure, "Exposure", 0.8f);
+ SOCKET_FLOAT(pass_alpha_threshold, "Pass Alpha Threshold", 0.0f);
+
+ static NodeEnum filter_enum;
+ filter_enum.insert("box", FILTER_BOX);
+ filter_enum.insert("gaussian", FILTER_GAUSSIAN);
+ filter_enum.insert("blackman_harris", FILTER_BLACKMAN_HARRIS);
+
+ SOCKET_ENUM(filter_type, "Filter Type", filter_enum, FILTER_BOX);
+ SOCKET_FLOAT(filter_width, "Filter Width", 1.0f);
+
+ SOCKET_FLOAT(mist_start, "Mist Start", 0.0f);
+ SOCKET_FLOAT(mist_depth, "Mist Depth", 100.0f);
+ SOCKET_FLOAT(mist_falloff, "Mist Falloff", 1.0f);
+
+ const NodeEnum *pass_type_enum = Pass::get_type_enum();
+ SOCKET_ENUM(display_pass, "Display Pass", *pass_type_enum, PASS_COMBINED);
+
+ SOCKET_BOOLEAN(show_active_pixels, "Show Active Pixels", false);
+
+ static NodeEnum cryptomatte_passes_enum;
+ cryptomatte_passes_enum.insert("none", CRYPT_NONE);
+ cryptomatte_passes_enum.insert("object", CRYPT_OBJECT);
+ cryptomatte_passes_enum.insert("material", CRYPT_MATERIAL);
+ cryptomatte_passes_enum.insert("asset", CRYPT_ASSET);
+ cryptomatte_passes_enum.insert("accurate", CRYPT_ACCURATE);
+ SOCKET_ENUM(cryptomatte_passes, "Cryptomatte Passes", cryptomatte_passes_enum, CRYPT_NONE);
+
+ SOCKET_INT(cryptomatte_depth, "Cryptomatte Depth", 0);
+
+ SOCKET_BOOLEAN(use_approximate_shadow_catcher, "Use Approximate Shadow Catcher", false);
+
+ return type;
+}
+
+Film::Film() : Node(get_node_type()), filter_table_offset_(TABLE_OFFSET_INVALID)
+{
+}
+
+Film::~Film()
+{
+}
+
+void Film::add_default(Scene *scene)
+{
+ Pass *pass = scene->create_node<Pass>();
+ pass->set_type(PASS_COMBINED);
+}
+
+void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
+{
+ if (!is_modified())
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->film.times.add_entry({"update", time});
+ }
+ });
+
+ device_free(device, dscene, scene);
+
+ KernelFilm *kfilm = &dscene->data.film;
+
+ /* update __data */
+ kfilm->exposure = exposure;
+ kfilm->pass_alpha_threshold = pass_alpha_threshold;
+ kfilm->pass_flag = 0;
+
+ kfilm->use_approximate_shadow_catcher = get_use_approximate_shadow_catcher();
+
+ kfilm->light_pass_flag = 0;
+ kfilm->pass_stride = 0;
+
+ /* Mark with PASS_UNUSED to avoid mask test in the kernel. */
+ kfilm->pass_background = PASS_UNUSED;
+ kfilm->pass_emission = PASS_UNUSED;
+ kfilm->pass_ao = PASS_UNUSED;
+ kfilm->pass_diffuse_direct = PASS_UNUSED;
+ kfilm->pass_diffuse_indirect = PASS_UNUSED;
+ kfilm->pass_glossy_direct = PASS_UNUSED;
+ kfilm->pass_glossy_indirect = PASS_UNUSED;
+ kfilm->pass_transmission_direct = PASS_UNUSED;
+ kfilm->pass_transmission_indirect = PASS_UNUSED;
+ kfilm->pass_volume_direct = PASS_UNUSED;
+ kfilm->pass_volume_indirect = PASS_UNUSED;
+ kfilm->pass_volume_direct = PASS_UNUSED;
+ kfilm->pass_volume_indirect = PASS_UNUSED;
+ kfilm->pass_shadow = PASS_UNUSED;
+
+ /* Mark passes as unused so that the kernel knows the pass is inaccessible. */
+ kfilm->pass_denoising_normal = PASS_UNUSED;
+ kfilm->pass_denoising_albedo = PASS_UNUSED;
+ kfilm->pass_denoising_depth = PASS_UNUSED;
+ kfilm->pass_sample_count = PASS_UNUSED;
+ kfilm->pass_adaptive_aux_buffer = PASS_UNUSED;
+ kfilm->pass_shadow_catcher = PASS_UNUSED;
+ kfilm->pass_shadow_catcher_sample_count = PASS_UNUSED;
+ kfilm->pass_shadow_catcher_matte = PASS_UNUSED;
+
+ bool have_cryptomatte = false;
+ bool have_aov_color = false;
+ bool have_aov_value = false;
+
+ for (size_t i = 0; i < scene->passes.size(); i++) {
+ const Pass *pass = scene->passes[i];
+
+ if (pass->get_type() == PASS_NONE || !pass->is_written()) {
+ continue;
+ }
+
+ if (pass->get_mode() == PassMode::DENOISED) {
+ /* Generally we only storing offsets of the noisy passes. The display pass is an exception
+ * since it is a read operation and not a write. */
+ kfilm->pass_stride += pass->get_info().num_components;
+ continue;
+ }
+
+ /* Can't do motion pass if no motion vectors are available. */
+ if (pass->get_type() == PASS_MOTION || pass->get_type() == PASS_MOTION_WEIGHT) {
+ if (scene->need_motion() != Scene::MOTION_PASS) {
+ kfilm->pass_stride += pass->get_info().num_components;
+ continue;
+ }
+ }
+
+ const int pass_flag = (1 << (pass->get_type() % 32));
+ if (pass->get_type() <= PASS_CATEGORY_LIGHT_END) {
+ kfilm->light_pass_flag |= pass_flag;
+ }
+ else if (pass->get_type() <= PASS_CATEGORY_DATA_END) {
+ kfilm->pass_flag |= pass_flag;
+ }
+ else {
+ assert(pass->get_type() <= PASS_CATEGORY_BAKE_END);
+ }
+
+ switch (pass->get_type()) {
+ case PASS_COMBINED:
+ kfilm->pass_combined = kfilm->pass_stride;
+ break;
+ case PASS_DEPTH:
+ kfilm->pass_depth = kfilm->pass_stride;
+ break;
+ case PASS_NORMAL:
+ kfilm->pass_normal = kfilm->pass_stride;
+ break;
+ case PASS_POSITION:
+ kfilm->pass_position = kfilm->pass_stride;
+ break;
+ case PASS_ROUGHNESS:
+ kfilm->pass_roughness = kfilm->pass_stride;
+ break;
+ case PASS_UV:
+ kfilm->pass_uv = kfilm->pass_stride;
+ break;
+ case PASS_MOTION:
+ kfilm->pass_motion = kfilm->pass_stride;
+ break;
+ case PASS_MOTION_WEIGHT:
+ kfilm->pass_motion_weight = kfilm->pass_stride;
+ break;
+ case PASS_OBJECT_ID:
+ kfilm->pass_object_id = kfilm->pass_stride;
+ break;
+ case PASS_MATERIAL_ID:
+ kfilm->pass_material_id = kfilm->pass_stride;
+ break;
+
+ case PASS_MIST:
+ kfilm->pass_mist = kfilm->pass_stride;
+ break;
+ case PASS_EMISSION:
+ kfilm->pass_emission = kfilm->pass_stride;
+ break;
+ case PASS_BACKGROUND:
+ kfilm->pass_background = kfilm->pass_stride;
+ break;
+ case PASS_AO:
+ kfilm->pass_ao = kfilm->pass_stride;
+ break;
+ case PASS_SHADOW:
+ kfilm->pass_shadow = kfilm->pass_stride;
+ break;
+
+ case PASS_DIFFUSE_COLOR:
+ kfilm->pass_diffuse_color = kfilm->pass_stride;
+ break;
+ case PASS_GLOSSY_COLOR:
+ kfilm->pass_glossy_color = kfilm->pass_stride;
+ break;
+ case PASS_TRANSMISSION_COLOR:
+ kfilm->pass_transmission_color = kfilm->pass_stride;
+ break;
+ case PASS_DIFFUSE_INDIRECT:
+ kfilm->pass_diffuse_indirect = kfilm->pass_stride;
+ break;
+ case PASS_GLOSSY_INDIRECT:
+ kfilm->pass_glossy_indirect = kfilm->pass_stride;
+ break;
+ case PASS_TRANSMISSION_INDIRECT:
+ kfilm->pass_transmission_indirect = kfilm->pass_stride;
+ break;
+ case PASS_VOLUME_INDIRECT:
+ kfilm->pass_volume_indirect = kfilm->pass_stride;
+ break;
+ case PASS_DIFFUSE_DIRECT:
+ kfilm->pass_diffuse_direct = kfilm->pass_stride;
+ break;
+ case PASS_GLOSSY_DIRECT:
+ kfilm->pass_glossy_direct = kfilm->pass_stride;
+ break;
+ case PASS_TRANSMISSION_DIRECT:
+ kfilm->pass_transmission_direct = kfilm->pass_stride;
+ break;
+ case PASS_VOLUME_DIRECT:
+ kfilm->pass_volume_direct = kfilm->pass_stride;
+ break;
+
+ case PASS_BAKE_PRIMITIVE:
+ kfilm->pass_bake_primitive = kfilm->pass_stride;
+ break;
+ case PASS_BAKE_DIFFERENTIAL:
+ kfilm->pass_bake_differential = kfilm->pass_stride;
+ break;
+
+ case PASS_CRYPTOMATTE:
+ kfilm->pass_cryptomatte = have_cryptomatte ?
+ min(kfilm->pass_cryptomatte, kfilm->pass_stride) :
+ kfilm->pass_stride;
+ have_cryptomatte = true;
+ break;
+
+ case PASS_DENOISING_NORMAL:
+ kfilm->pass_denoising_normal = kfilm->pass_stride;
+ break;
+ case PASS_DENOISING_ALBEDO:
+ kfilm->pass_denoising_albedo = kfilm->pass_stride;
+ break;
+ case PASS_DENOISING_DEPTH:
+ kfilm->pass_denoising_depth = kfilm->pass_stride;
+ break;
+
+ case PASS_SHADOW_CATCHER:
+ kfilm->pass_shadow_catcher = kfilm->pass_stride;
+ break;
+ case PASS_SHADOW_CATCHER_SAMPLE_COUNT:
+ kfilm->pass_shadow_catcher_sample_count = kfilm->pass_stride;
+ break;
+ case PASS_SHADOW_CATCHER_MATTE:
+ kfilm->pass_shadow_catcher_matte = kfilm->pass_stride;
+ break;
+
+ case PASS_ADAPTIVE_AUX_BUFFER:
+ kfilm->pass_adaptive_aux_buffer = kfilm->pass_stride;
+ break;
+ case PASS_SAMPLE_COUNT:
+ kfilm->pass_sample_count = kfilm->pass_stride;
+ break;
+
+ case PASS_AOV_COLOR:
+ if (!have_aov_color) {
+ kfilm->pass_aov_color = kfilm->pass_stride;
+ have_aov_color = true;
+ }
+ break;
+ case PASS_AOV_VALUE:
+ if (!have_aov_value) {
+ kfilm->pass_aov_value = kfilm->pass_stride;
+ have_aov_value = true;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ kfilm->pass_stride += pass->get_info().num_components;
+ }
+
+ /* update filter table */
+ vector<float> table = filter_table(filter_type, filter_width);
+ scene->lookup_tables->remove_table(&filter_table_offset_);
+ filter_table_offset_ = scene->lookup_tables->add_table(dscene, table);
+ kfilm->filter_table_offset = (int)filter_table_offset_;
+
+ /* mist pass parameters */
+ kfilm->mist_start = mist_start;
+ kfilm->mist_inv_depth = (mist_depth > 0.0f) ? 1.0f / mist_depth : 0.0f;
+ kfilm->mist_falloff = mist_falloff;
+
+ kfilm->cryptomatte_passes = cryptomatte_passes;
+ kfilm->cryptomatte_depth = cryptomatte_depth;
+
+ clear_modified();
+}
+
+void Film::device_free(Device * /*device*/, DeviceScene * /*dscene*/, Scene *scene)
+{
+ scene->lookup_tables->remove_table(&filter_table_offset_);
+}
+
+int Film::get_aov_offset(Scene *scene, string name, bool &is_color)
+{
+ int offset_color = 0, offset_value = 0;
+ foreach (const Pass *pass, scene->passes) {
+ if (pass->get_name() == name) {
+ if (pass->get_type() == PASS_AOV_VALUE) {
+ is_color = false;
+ return offset_value;
+ }
+ else if (pass->get_type() == PASS_AOV_COLOR) {
+ is_color = true;
+ return offset_color;
+ }
+ }
+
+ if (pass->get_type() == PASS_AOV_VALUE) {
+ offset_value += pass->get_info().num_components;
+ }
+ else if (pass->get_type() == PASS_AOV_COLOR) {
+ offset_color += pass->get_info().num_components;
+ }
+ }
+
+ return -1;
+}
+
+void Film::update_passes(Scene *scene, bool add_sample_count_pass)
+{
+ const Background *background = scene->background;
+ const BakeManager *bake_manager = scene->bake_manager;
+ const ObjectManager *object_manager = scene->object_manager;
+ Integrator *integrator = scene->integrator;
+
+ if (!is_modified() && !object_manager->need_update() && !integrator->is_modified() &&
+ !background->is_modified()) {
+ return;
+ }
+
+ /* Remove auto generated passes and recreate them. */
+ remove_auto_passes(scene);
+
+ /* Display pass for viewport. */
+ const PassType display_pass = get_display_pass();
+ add_auto_pass(scene, display_pass);
+
+ /* Assumption is that a combined pass always exists for now, for example
+ * adaptive sampling is always based on a combined pass. But we should
+ * try to lift this limitation in the future for faster rendering of
+ * individual passes. */
+ if (display_pass != PASS_COMBINED) {
+ add_auto_pass(scene, PASS_COMBINED);
+ }
+
+ /* Create passes needed for adaptive sampling. */
+ const AdaptiveSampling adaptive_sampling = integrator->get_adaptive_sampling();
+ if (adaptive_sampling.use) {
+ add_auto_pass(scene, PASS_SAMPLE_COUNT);
+ add_auto_pass(scene, PASS_ADAPTIVE_AUX_BUFFER);
+ }
+
+ /* Create passes needed for denoising. */
+ const bool use_denoise = integrator->get_use_denoise();
+ if (use_denoise) {
+ if (integrator->get_use_denoise_pass_normal()) {
+ add_auto_pass(scene, PASS_DENOISING_NORMAL);
+ }
+ if (integrator->get_use_denoise_pass_albedo()) {
+ add_auto_pass(scene, PASS_DENOISING_ALBEDO);
+ }
+ }
+
+ /* Create passes for shadow catcher. */
+ if (scene->has_shadow_catcher()) {
+ const bool need_background = get_use_approximate_shadow_catcher() &&
+ !background->get_transparent();
+
+ add_auto_pass(scene, PASS_SHADOW_CATCHER);
+ add_auto_pass(scene, PASS_SHADOW_CATCHER_SAMPLE_COUNT);
+ add_auto_pass(scene, PASS_SHADOW_CATCHER_MATTE);
+
+ if (need_background) {
+ add_auto_pass(scene, PASS_BACKGROUND);
+ }
+ }
+ else if (Pass::contains(scene->passes, PASS_SHADOW_CATCHER)) {
+ add_auto_pass(scene, PASS_SHADOW_CATCHER);
+ add_auto_pass(scene, PASS_SHADOW_CATCHER_SAMPLE_COUNT);
+ }
+
+ const vector<Pass *> passes_immutable = scene->passes;
+ for (const Pass *pass : passes_immutable) {
+ const PassInfo info = pass->get_info();
+ /* Add utility passes needed to generate some light passes. */
+ if (info.divide_type != PASS_NONE) {
+ add_auto_pass(scene, info.divide_type);
+ }
+ if (info.direct_type != PASS_NONE) {
+ add_auto_pass(scene, info.direct_type);
+ }
+ if (info.indirect_type != PASS_NONE) {
+ add_auto_pass(scene, info.indirect_type);
+ }
+
+ /* NOTE: Enable all denoised passes when storage is requested.
+ * This way it is possible to tweak denoiser parameters later on. */
+ if (info.support_denoise && use_denoise) {
+ add_auto_pass(scene, pass->get_type(), PassMode::DENOISED);
+ }
+ }
+
+ if (bake_manager->get_baking()) {
+ add_auto_pass(scene, PASS_BAKE_PRIMITIVE, "BakePrimitive");
+ add_auto_pass(scene, PASS_BAKE_DIFFERENTIAL, "BakeDifferential");
+ }
+
+ if (add_sample_count_pass) {
+ if (!Pass::contains(scene->passes, PASS_SAMPLE_COUNT)) {
+ add_auto_pass(scene, PASS_SAMPLE_COUNT);
+ }
+ }
+
+ /* Remove duplicates and initialize internal pass info. */
+ finalize_passes(scene, use_denoise);
+
+ /* Flush scene updates. */
+ const bool have_uv_pass = Pass::contains(scene->passes, PASS_UV);
+ const bool have_motion_pass = Pass::contains(scene->passes, PASS_MOTION);
+ const bool have_ao_pass = Pass::contains(scene->passes, PASS_AO);
+
+ if (have_uv_pass != prev_have_uv_pass) {
+ scene->geometry_manager->tag_update(scene, GeometryManager::UV_PASS_NEEDED);
+ foreach (Shader *shader, scene->shaders)
+ shader->need_update_uvs = true;
+ }
+ if (have_motion_pass != prev_have_motion_pass) {
+ scene->geometry_manager->tag_update(scene, GeometryManager::MOTION_PASS_NEEDED);
+ }
+ if (have_ao_pass != prev_have_ao_pass) {
+ scene->integrator->tag_update(scene, Integrator::AO_PASS_MODIFIED);
+ }
+
+ prev_have_uv_pass = have_uv_pass;
+ prev_have_motion_pass = have_motion_pass;
+ prev_have_ao_pass = have_ao_pass;
+
+ tag_modified();
+
+ /* Debug logging. */
+ if (VLOG_IS_ON(2)) {
+ VLOG(2) << "Effective scene passes:";
+ for (const Pass *pass : scene->passes) {
+ VLOG(2) << "- " << *pass;
+ }
+ }
+}
+
+void Film::add_auto_pass(Scene *scene, PassType type, const char *name)
+{
+ add_auto_pass(scene, type, PassMode::NOISY, name);
+}
+
+void Film::add_auto_pass(Scene *scene, PassType type, PassMode mode, const char *name)
+{
+ Pass *pass = new Pass();
+ pass->set_type(type);
+ pass->set_mode(mode);
+ pass->set_name(ustring((name) ? name : ""));
+ pass->is_auto_ = true;
+
+ pass->set_owner(scene);
+ scene->passes.push_back(pass);
+}
+
+void Film::remove_auto_passes(Scene *scene)
+{
+ /* Remove all passes which were automatically created. */
+ vector<Pass *> new_passes;
+
+ for (Pass *pass : scene->passes) {
+ if (!pass->is_auto_) {
+ new_passes.push_back(pass);
+ }
+ else {
+ delete pass;
+ }
+ }
+
+ scene->passes = new_passes;
+}
+
+static bool compare_pass_order(const Pass *a, const Pass *b)
+{
+ const int num_components_a = a->get_info().num_components;
+ const int num_components_b = b->get_info().num_components;
+
+ if (num_components_a == num_components_b) {
+ return (a->get_type() < b->get_type());
+ }
+
+ return num_components_a > num_components_b;
+}
+
+void Film::finalize_passes(Scene *scene, const bool use_denoise)
+{
+ /* Remove duplicate passes. */
+ vector<Pass *> new_passes;
+
+ for (Pass *pass : scene->passes) {
+ /* Disable denoising on passes if denoising is disabled, or if the
+ * pass does not support it. */
+ pass->set_mode((use_denoise && pass->get_info().support_denoise) ? pass->get_mode() :
+ PassMode::NOISY);
+
+ /* Merge duplicate passes. */
+ bool duplicate_found = false;
+ for (Pass *new_pass : new_passes) {
+ /* If different type or denoising, don't merge. */
+ if (new_pass->get_type() != pass->get_type() || new_pass->get_mode() != pass->get_mode()) {
+ continue;
+ }
+
+ /* If both passes have a name and the names are different, don't merge.
+ * If either pass has a name, we'll use that name. */
+ if (!pass->get_name().empty() && !new_pass->get_name().empty() &&
+ pass->get_name() != new_pass->get_name()) {
+ continue;
+ }
+
+ if (!pass->get_name().empty() && new_pass->get_name().empty()) {
+ new_pass->set_name(pass->get_name());
+ }
+
+ new_pass->is_auto_ &= pass->is_auto_;
+ duplicate_found = true;
+ break;
+ }
+
+ if (!duplicate_found) {
+ new_passes.push_back(pass);
+ }
+ else {
+ delete pass;
+ }
+ }
+
+ /* Order from by components and type, This is required to for AOVs and cryptomatte passes,
+ * which the kernel assumes to be in order. Note this must use stable sort so cryptomatte
+ * passes remain in the right order. */
+ stable_sort(new_passes.begin(), new_passes.end(), compare_pass_order);
+
+ scene->passes = new_passes;
+}
+
+uint Film::get_kernel_features(const Scene *scene) const
+{
+ uint kernel_features = 0;
+
+ for (const Pass *pass : scene->passes) {
+ if (!pass->is_written()) {
+ continue;
+ }
+
+ const PassType pass_type = pass->get_type();
+ const PassMode pass_mode = pass->get_mode();
+
+ if (pass_mode == PassMode::DENOISED || pass_type == PASS_DENOISING_NORMAL ||
+ pass_type == PASS_DENOISING_ALBEDO || pass_type == PASS_DENOISING_DEPTH) {
+ kernel_features |= KERNEL_FEATURE_DENOISING;
+ }
+
+ if (pass_type != PASS_NONE && pass_type != PASS_COMBINED &&
+ pass_type <= PASS_CATEGORY_LIGHT_END) {
+ kernel_features |= KERNEL_FEATURE_LIGHT_PASSES;
+
+ if (pass_type == PASS_SHADOW) {
+ kernel_features |= KERNEL_FEATURE_SHADOW_PASS;
+ }
+ }
+
+ if (pass_type == PASS_AO) {
+ kernel_features |= KERNEL_FEATURE_AO_PASS;
+ }
+ }
+
+ return kernel_features;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/film.h b/intern/cycles/scene/film.h
new file mode 100644
index 00000000000..5207c5e62b5
--- /dev/null
+++ b/intern/cycles/scene/film.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FILM_H__
+#define __FILM_H__
+
+#include "scene/pass.h"
+#include "util/string.h"
+#include "util/vector.h"
+
+#include "kernel/types.h"
+
+#include "graph/node.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Scene;
+
+typedef enum FilterType {
+ FILTER_BOX,
+ FILTER_GAUSSIAN,
+ FILTER_BLACKMAN_HARRIS,
+
+ FILTER_NUM_TYPES,
+} FilterType;
+
+class Film : public Node {
+ public:
+ NODE_DECLARE
+
+ NODE_SOCKET_API(float, exposure)
+ NODE_SOCKET_API(float, pass_alpha_threshold)
+
+ NODE_SOCKET_API(PassType, display_pass)
+ NODE_SOCKET_API(bool, show_active_pixels)
+
+ NODE_SOCKET_API(FilterType, filter_type)
+ NODE_SOCKET_API(float, filter_width)
+
+ NODE_SOCKET_API(float, mist_start)
+ NODE_SOCKET_API(float, mist_depth)
+ NODE_SOCKET_API(float, mist_falloff)
+
+ NODE_SOCKET_API(CryptomatteType, cryptomatte_passes)
+ NODE_SOCKET_API(int, cryptomatte_depth)
+
+ /* Approximate shadow catcher pass into its matte pass, so that both artificial objects and
+ * shadows can be alpha-overed onto a backdrop. */
+ NODE_SOCKET_API(bool, use_approximate_shadow_catcher)
+
+ private:
+ size_t filter_table_offset_;
+ bool prev_have_uv_pass = false;
+ bool prev_have_motion_pass = false;
+ bool prev_have_ao_pass = false;
+
+ public:
+ Film();
+ ~Film();
+
+ /* add default passes to scene */
+ static void add_default(Scene *scene);
+
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene);
+ void device_free(Device *device, DeviceScene *dscene, Scene *scene);
+
+ int get_aov_offset(Scene *scene, string name, bool &is_color);
+
+ /* Update passes so that they contain all passes required for the configured functionality.
+ *
+ * If `add_sample_count_pass` is true then the SAMPLE_COUNT pass is ensured to be added. */
+ void update_passes(Scene *scene, bool add_sample_count_pass);
+
+ uint get_kernel_features(const Scene *scene) const;
+
+ private:
+ void add_auto_pass(Scene *scene, PassType type, const char *name = nullptr);
+ void add_auto_pass(Scene *scene, PassType type, PassMode mode, const char *name = nullptr);
+ void remove_auto_passes(Scene *scene);
+ void finalize_passes(Scene *scene, const bool use_denoise);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __FILM_H__ */
diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp
new file mode 100644
index 00000000000..5141e1f8358
--- /dev/null
+++ b/intern/cycles/scene/geometry.cpp
@@ -0,0 +1,2074 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bvh/bvh.h"
+#include "bvh/bvh2.h"
+
+#include "device/device.h"
+
+#include "scene/attribute.h"
+#include "scene/camera.h"
+#include "scene/geometry.h"
+#include "scene/hair.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_nodes.h"
+#include "scene/stats.h"
+#include "scene/volume.h"
+
+#include "subd/patch_table.h"
+#include "subd/split.h"
+
+#include "kernel/osl/globals.h"
+
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/progress.h"
+#include "util/task.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Geometry */
+
+NODE_ABSTRACT_DEFINE(Geometry)
+{
+ NodeType *type = NodeType::add("geometry_base", NULL);
+
+ SOCKET_UINT(motion_steps, "Motion Steps", 3);
+ SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false);
+ SOCKET_NODE_ARRAY(used_shaders, "Shaders", Shader::get_node_type());
+
+ return type;
+}
+
+Geometry::Geometry(const NodeType *node_type, const Type type)
+ : Node(node_type), geometry_type(type), attributes(this, ATTR_PRIM_GEOMETRY)
+{
+ need_update_rebuild = false;
+ need_update_bvh_for_offset = false;
+
+ transform_applied = false;
+ transform_negative_scaled = false;
+ transform_normal = transform_identity();
+ bounds = BoundBox::empty;
+
+ has_volume = false;
+ has_surface_bssrdf = false;
+
+ bvh = NULL;
+ attr_map_offset = 0;
+ prim_offset = 0;
+}
+
+Geometry::~Geometry()
+{
+ dereference_all_used_nodes();
+ delete bvh;
+}
+
+void Geometry::clear(bool preserve_shaders)
+{
+ if (!preserve_shaders)
+ used_shaders.clear();
+
+ transform_applied = false;
+ transform_negative_scaled = false;
+ transform_normal = transform_identity();
+ tag_modified();
+}
+
+bool Geometry::need_attribute(Scene *scene, AttributeStandard std)
+{
+ if (std == ATTR_STD_NONE)
+ return false;
+
+ if (scene->need_global_attribute(std))
+ return true;
+
+ foreach (Node *node, used_shaders) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->attributes.find(std))
+ return true;
+ }
+
+ return false;
+}
+
+bool Geometry::need_attribute(Scene * /*scene*/, ustring name)
+{
+ if (name == ustring())
+ return false;
+
+ foreach (Node *node, used_shaders) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->attributes.find(name))
+ return true;
+ }
+
+ return false;
+}
+
+AttributeRequestSet Geometry::needed_attributes()
+{
+ AttributeRequestSet result;
+
+ foreach (Node *node, used_shaders) {
+ Shader *shader = static_cast<Shader *>(node);
+ result.add(shader->attributes);
+ }
+
+ return result;
+}
+
+float Geometry::motion_time(int step) const
+{
+ return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f;
+}
+
+int Geometry::motion_step(float time) const
+{
+ if (motion_steps > 1) {
+ int attr_step = 0;
+
+ for (int step = 0; step < motion_steps; step++) {
+ float step_time = motion_time(step);
+ if (step_time == time) {
+ return attr_step;
+ }
+
+ /* Center step is stored in a separate attribute. */
+ if (step != motion_steps / 2) {
+ attr_step++;
+ }
+ }
+ }
+
+ return -1;
+}
+
+bool Geometry::need_build_bvh(BVHLayout layout) const
+{
+ return is_instanced() || layout == BVH_LAYOUT_OPTIX || layout == BVH_LAYOUT_MULTI_OPTIX ||
+ layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE;
+}
+
+bool Geometry::is_instanced() const
+{
+ /* Currently we treat subsurface objects as instanced.
+ *
+ * While it might be not very optimal for ray traversal, it avoids having
+ * duplicated BVH in the memory, saving quite some space.
+ */
+ return !transform_applied || has_surface_bssrdf;
+}
+
+bool Geometry::has_true_displacement() const
+{
+ foreach (Node *node, used_shaders) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->has_displacement && shader->get_displacement_method() != DISPLACE_BUMP) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Geometry::compute_bvh(
+ Device *device, DeviceScene *dscene, SceneParams *params, Progress *progress, int n, int total)
+{
+ if (progress->get_cancel())
+ return;
+
+ compute_bounds();
+
+ const BVHLayout bvh_layout = BVHParams::best_bvh_layout(params->bvh_layout,
+ device->get_bvh_layout_mask());
+ if (need_build_bvh(bvh_layout)) {
+ string msg = "Updating Geometry BVH ";
+ if (name.empty())
+ msg += string_printf("%u/%u", (uint)(n + 1), (uint)total);
+ else
+ msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total);
+
+ Object object;
+
+ /* Ensure all visibility bits are set at the geometry level BVH. In
+ * the object level BVH is where actual visibility is tested. */
+ object.set_is_shadow_catcher(true);
+ object.set_visibility(~0);
+
+ object.set_geometry(this);
+
+ vector<Geometry *> geometry;
+ geometry.push_back(this);
+ vector<Object *> objects;
+ objects.push_back(&object);
+
+ if (bvh && !need_update_rebuild) {
+ progress->set_status(msg, "Refitting BVH");
+
+ bvh->geometry = geometry;
+ bvh->objects = objects;
+
+ device->build_bvh(bvh, *progress, true);
+ }
+ else {
+ progress->set_status(msg, "Building BVH");
+
+ BVHParams bparams;
+ bparams.use_spatial_split = params->use_bvh_spatial_split;
+ bparams.bvh_layout = bvh_layout;
+ bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
+ params->use_bvh_unaligned_nodes;
+ bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
+ bparams.num_motion_curve_steps = params->num_bvh_time_steps;
+ bparams.bvh_type = params->bvh_type;
+ bparams.curve_subdivisions = params->curve_subdivisions();
+
+ delete bvh;
+ bvh = BVH::create(bparams, geometry, objects, device);
+ MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false);
+ }
+ }
+
+ need_update_rebuild = false;
+ need_update_bvh_for_offset = false;
+}
+
+bool Geometry::has_motion_blur() const
+{
+ return (use_motion_blur && attributes.find(ATTR_STD_MOTION_VERTEX_POSITION));
+}
+
+bool Geometry::has_voxel_attributes() const
+{
+ foreach (const Attribute &attr, attributes.attributes) {
+ if (attr.element == ATTR_ELEMENT_VOXEL) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Geometry::tag_update(Scene *scene, bool rebuild)
+{
+ if (rebuild) {
+ need_update_rebuild = true;
+ scene->light_manager->tag_update(scene, LightManager::MESH_NEED_REBUILD);
+ }
+ else {
+ foreach (Node *node, used_shaders) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->has_surface_emission) {
+ scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED);
+ break;
+ }
+ }
+ }
+
+ scene->geometry_manager->tag_update(scene, GeometryManager::GEOMETRY_MODIFIED);
+}
+
+void Geometry::tag_bvh_update(bool rebuild)
+{
+ tag_modified();
+
+ if (rebuild) {
+ need_update_rebuild = true;
+ }
+}
+
+/* Geometry Manager */
+
+GeometryManager::GeometryManager()
+{
+ update_flags = UPDATE_ALL;
+ need_flags_update = true;
+}
+
+GeometryManager::~GeometryManager()
+{
+}
+
+void GeometryManager::update_osl_attributes(Device *device,
+ Scene *scene,
+ vector<AttributeRequestSet> &geom_attributes)
+{
+#ifdef WITH_OSL
+ /* for OSL, a hash map is used to lookup the attribute by name. */
+ OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
+
+ og->object_name_map.clear();
+ og->attribute_map.clear();
+ og->object_names.clear();
+
+ og->attribute_map.resize(scene->objects.size() * ATTR_PRIM_TYPES);
+
+ for (size_t i = 0; i < scene->objects.size(); i++) {
+ /* set object name to object index map */
+ Object *object = scene->objects[i];
+ og->object_name_map[object->name] = i;
+ og->object_names.push_back(object->name);
+
+ /* set object attributes */
+ foreach (ParamValue &attr, object->attributes) {
+ OSLGlobals::Attribute osl_attr;
+
+ osl_attr.type = attr.type();
+ osl_attr.desc.element = ATTR_ELEMENT_OBJECT;
+ osl_attr.value = attr;
+ osl_attr.desc.offset = 0;
+ osl_attr.desc.flags = 0;
+
+ og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_GEOMETRY][attr.name()] = osl_attr;
+ og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][attr.name()] = osl_attr;
+ }
+
+ /* find geometry attributes */
+ size_t j = object->geometry->index;
+ assert(j < scene->geometry.size() && scene->geometry[j] == object->geometry);
+
+ AttributeRequestSet &attributes = geom_attributes[j];
+
+ /* set mesh attributes */
+ foreach (AttributeRequest &req, attributes.requests) {
+ OSLGlobals::Attribute osl_attr;
+
+ if (req.desc.element != ATTR_ELEMENT_NONE) {
+ osl_attr.desc = req.desc;
+
+ if (req.type == TypeDesc::TypeFloat)
+ osl_attr.type = TypeDesc::TypeFloat;
+ else if (req.type == TypeDesc::TypeMatrix)
+ osl_attr.type = TypeDesc::TypeMatrix;
+ else if (req.type == TypeFloat2)
+ osl_attr.type = TypeFloat2;
+ else if (req.type == TypeRGBA)
+ osl_attr.type = TypeRGBA;
+ else
+ osl_attr.type = TypeDesc::TypeColor;
+
+ if (req.std != ATTR_STD_NONE) {
+ /* if standard attribute, add lookup by geom: name convention */
+ ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
+ og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_GEOMETRY][stdname] = osl_attr;
+ }
+ else if (req.name != ustring()) {
+ /* add lookup by geometry attribute name */
+ og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_GEOMETRY][req.name] = osl_attr;
+ }
+ }
+
+ if (req.subd_desc.element != ATTR_ELEMENT_NONE) {
+ osl_attr.desc = req.subd_desc;
+
+ if (req.subd_type == TypeDesc::TypeFloat)
+ osl_attr.type = TypeDesc::TypeFloat;
+ else if (req.subd_type == TypeDesc::TypeMatrix)
+ osl_attr.type = TypeDesc::TypeMatrix;
+ else if (req.subd_type == TypeFloat2)
+ osl_attr.type = TypeFloat2;
+ else if (req.subd_type == TypeRGBA)
+ osl_attr.type = TypeRGBA;
+ else
+ osl_attr.type = TypeDesc::TypeColor;
+
+ if (req.std != ATTR_STD_NONE) {
+ /* if standard attribute, add lookup by geom: name convention */
+ ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
+ og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][stdname] = osl_attr;
+ }
+ else if (req.name != ustring()) {
+ /* add lookup by geometry attribute name */
+ og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][req.name] = osl_attr;
+ }
+ }
+ }
+ }
+#else
+ (void)device;
+ (void)scene;
+ (void)geom_attributes;
+#endif
+}
+
+/* Generate a normal attribute map entry from an attribute descriptor. */
+static void emit_attribute_map_entry(
+ uint4 *attr_map, int index, uint id, TypeDesc type, const AttributeDescriptor &desc)
+{
+ attr_map[index].x = id;
+ attr_map[index].y = desc.element;
+ attr_map[index].z = as_uint(desc.offset);
+
+ if (type == TypeDesc::TypeFloat)
+ attr_map[index].w = NODE_ATTR_FLOAT;
+ else if (type == TypeDesc::TypeMatrix)
+ attr_map[index].w = NODE_ATTR_MATRIX;
+ else if (type == TypeFloat2)
+ attr_map[index].w = NODE_ATTR_FLOAT2;
+ else if (type == TypeFloat4)
+ attr_map[index].w = NODE_ATTR_FLOAT4;
+ else if (type == TypeRGBA)
+ attr_map[index].w = NODE_ATTR_RGBA;
+ else
+ attr_map[index].w = NODE_ATTR_FLOAT3;
+
+ attr_map[index].w |= desc.flags << 8;
+}
+
+/* Generate an attribute map end marker, optionally including a link to another map.
+ * Links are used to connect object attribute maps to mesh attribute maps. */
+static void emit_attribute_map_terminator(uint4 *attr_map, int index, bool chain, uint chain_link)
+{
+ for (int j = 0; j < ATTR_PRIM_TYPES; j++) {
+ attr_map[index + j].x = ATTR_STD_NONE;
+ attr_map[index + j].y = chain; /* link is valid flag */
+ attr_map[index + j].z = chain ? chain_link + j : 0; /* link to the correct sub-entry */
+ attr_map[index + j].w = 0;
+ }
+}
+
+/* Generate all necessary attribute map entries from the attribute request. */
+static void emit_attribute_mapping(
+ uint4 *attr_map, int index, Scene *scene, AttributeRequest &req, Geometry *geom)
+{
+ uint id;
+
+ if (req.std == ATTR_STD_NONE)
+ id = scene->shader_manager->get_attribute_id(req.name);
+ else
+ id = scene->shader_manager->get_attribute_id(req.std);
+
+ emit_attribute_map_entry(attr_map, index, id, req.type, req.desc);
+
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->get_num_subd_faces()) {
+ emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc);
+ }
+ }
+}
+
+void GeometryManager::update_svm_attributes(Device *,
+ DeviceScene *dscene,
+ Scene *scene,
+ vector<AttributeRequestSet> &geom_attributes,
+ vector<AttributeRequestSet> &object_attributes)
+{
+ /* for SVM, the attributes_map table is used to lookup the offset of an
+ * attribute, based on a unique shader attribute id. */
+
+ /* compute array stride */
+ int attr_map_size = 0;
+
+ for (size_t i = 0; i < scene->geometry.size(); i++) {
+ Geometry *geom = scene->geometry[i];
+ geom->attr_map_offset = attr_map_size;
+ attr_map_size += (geom_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
+ }
+
+ for (size_t i = 0; i < scene->objects.size(); i++) {
+ Object *object = scene->objects[i];
+
+ /* only allocate a table for the object if it actually has attributes */
+ if (object_attributes[i].size() == 0) {
+ object->attr_map_offset = 0;
+ }
+ else {
+ object->attr_map_offset = attr_map_size;
+ attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
+ }
+ }
+
+ if (attr_map_size == 0)
+ return;
+
+ if (!dscene->attributes_map.need_realloc()) {
+ return;
+ }
+
+ /* create attribute map */
+ uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size);
+ memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint));
+
+ for (size_t i = 0; i < scene->geometry.size(); i++) {
+ Geometry *geom = scene->geometry[i];
+ AttributeRequestSet &attributes = geom_attributes[i];
+
+ /* set geometry attributes */
+ int index = geom->attr_map_offset;
+
+ foreach (AttributeRequest &req, attributes.requests) {
+ emit_attribute_mapping(attr_map, index, scene, req, geom);
+ index += ATTR_PRIM_TYPES;
+ }
+
+ emit_attribute_map_terminator(attr_map, index, false, 0);
+ }
+
+ for (size_t i = 0; i < scene->objects.size(); i++) {
+ Object *object = scene->objects[i];
+ AttributeRequestSet &attributes = object_attributes[i];
+
+ /* set object attributes */
+ if (attributes.size() > 0) {
+ int index = object->attr_map_offset;
+
+ foreach (AttributeRequest &req, attributes.requests) {
+ emit_attribute_mapping(attr_map, index, scene, req, object->geometry);
+ index += ATTR_PRIM_TYPES;
+ }
+
+ emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset);
+ }
+ }
+
+ /* copy to device */
+ dscene->attributes_map.copy_to_device();
+}
+
+static void update_attribute_element_size(Geometry *geom,
+ Attribute *mattr,
+ AttributePrimitive prim,
+ size_t *attr_float_size,
+ size_t *attr_float2_size,
+ size_t *attr_float3_size,
+ size_t *attr_uchar4_size)
+{
+ if (mattr) {
+ size_t size = mattr->element_size(geom, prim);
+
+ if (mattr->element == ATTR_ELEMENT_VOXEL) {
+ /* pass */
+ }
+ else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
+ *attr_uchar4_size += size;
+ }
+ else if (mattr->type == TypeDesc::TypeFloat) {
+ *attr_float_size += size;
+ }
+ else if (mattr->type == TypeFloat2) {
+ *attr_float2_size += size;
+ }
+ else if (mattr->type == TypeDesc::TypeMatrix) {
+ *attr_float3_size += size * 4;
+ }
+ else {
+ *attr_float3_size += size;
+ }
+ }
+}
+
+void GeometryManager::update_attribute_element_offset(Geometry *geom,
+ device_vector<float> &attr_float,
+ size_t &attr_float_offset,
+ device_vector<float2> &attr_float2,
+ size_t &attr_float2_offset,
+ device_vector<float4> &attr_float3,
+ size_t &attr_float3_offset,
+ device_vector<uchar4> &attr_uchar4,
+ size_t &attr_uchar4_offset,
+ Attribute *mattr,
+ AttributePrimitive prim,
+ TypeDesc &type,
+ AttributeDescriptor &desc)
+{
+ if (mattr) {
+ /* store element and type */
+ desc.element = mattr->element;
+ desc.flags = mattr->flags;
+ type = mattr->type;
+
+ /* store attribute data in arrays */
+ size_t size = mattr->element_size(geom, prim);
+
+ AttributeElement &element = desc.element;
+ int &offset = desc.offset;
+
+ if (mattr->element == ATTR_ELEMENT_VOXEL) {
+ /* store slot in offset value */
+ ImageHandle &handle = mattr->data_voxel();
+ offset = handle.svm_slot();
+ }
+ else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
+ uchar4 *data = mattr->data_uchar4();
+ offset = attr_uchar4_offset;
+
+ assert(attr_uchar4.size() >= offset + size);
+ if (mattr->modified) {
+ for (size_t k = 0; k < size; k++) {
+ attr_uchar4[offset + k] = data[k];
+ }
+ }
+ attr_uchar4_offset += size;
+ }
+ else if (mattr->type == TypeDesc::TypeFloat) {
+ float *data = mattr->data_float();
+ offset = attr_float_offset;
+
+ assert(attr_float.size() >= offset + size);
+ if (mattr->modified) {
+ for (size_t k = 0; k < size; k++) {
+ attr_float[offset + k] = data[k];
+ }
+ }
+ attr_float_offset += size;
+ }
+ else if (mattr->type == TypeFloat2) {
+ float2 *data = mattr->data_float2();
+ offset = attr_float2_offset;
+
+ assert(attr_float2.size() >= offset + size);
+ if (mattr->modified) {
+ for (size_t k = 0; k < size; k++) {
+ attr_float2[offset + k] = data[k];
+ }
+ }
+ attr_float2_offset += size;
+ }
+ else if (mattr->type == TypeDesc::TypeMatrix) {
+ Transform *tfm = mattr->data_transform();
+ offset = attr_float3_offset;
+
+ assert(attr_float3.size() >= offset + size * 3);
+ if (mattr->modified) {
+ for (size_t k = 0; k < size * 3; k++) {
+ attr_float3[offset + k] = (&tfm->x)[k];
+ }
+ }
+ attr_float3_offset += size * 3;
+ }
+ else {
+ float4 *data = mattr->data_float4();
+ offset = attr_float3_offset;
+
+ assert(attr_float3.size() >= offset + size);
+ if (mattr->modified) {
+ for (size_t k = 0; k < size; k++) {
+ attr_float3[offset + k] = data[k];
+ }
+ }
+ attr_float3_offset += size;
+ }
+
+ /* mesh vertex/curve index is global, not per object, so we sneak
+ * a correction for that in here */
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK &&
+ desc.flags & ATTR_SUBDIVIDED) {
+ /* Indices for subdivided attributes are retrieved
+ * from patch table so no need for correction here. */
+ }
+ else if (element == ATTR_ELEMENT_VERTEX)
+ offset -= mesh->vert_offset;
+ else if (element == ATTR_ELEMENT_VERTEX_MOTION)
+ offset -= mesh->vert_offset;
+ else if (element == ATTR_ELEMENT_FACE) {
+ if (prim == ATTR_PRIM_GEOMETRY)
+ offset -= mesh->prim_offset;
+ else
+ offset -= mesh->face_offset;
+ }
+ else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) {
+ if (prim == ATTR_PRIM_GEOMETRY)
+ offset -= 3 * mesh->prim_offset;
+ else
+ offset -= mesh->corner_offset;
+ }
+ }
+ else if (geom->is_hair()) {
+ Hair *hair = static_cast<Hair *>(geom);
+ if (element == ATTR_ELEMENT_CURVE)
+ offset -= hair->prim_offset;
+ else if (element == ATTR_ELEMENT_CURVE_KEY)
+ offset -= hair->curve_key_offset;
+ else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION)
+ offset -= hair->curve_key_offset;
+ }
+ }
+ else {
+ /* attribute not found */
+ desc.element = ATTR_ELEMENT_NONE;
+ desc.offset = 0;
+ }
+}
+
+void GeometryManager::device_update_attributes(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ progress.set_status("Updating Mesh", "Computing attributes");
+
+ /* gather per mesh requested attributes. as meshes may have multiple
+ * shaders assigned, this merges the requested attributes that have
+ * been set per shader by the shader manager */
+ vector<AttributeRequestSet> geom_attributes(scene->geometry.size());
+
+ for (size_t i = 0; i < scene->geometry.size(); i++) {
+ Geometry *geom = scene->geometry[i];
+
+ geom->index = i;
+ scene->need_global_attributes(geom_attributes[i]);
+
+ foreach (Node *node, geom->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ geom_attributes[i].add(shader->attributes);
+ }
+
+ if (geom->is_hair() && static_cast<Hair *>(geom)->need_shadow_transparency()) {
+ geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY);
+ }
+ }
+
+ /* convert object attributes to use the same data structures as geometry ones */
+ vector<AttributeRequestSet> object_attributes(scene->objects.size());
+ vector<AttributeSet> object_attribute_values;
+
+ object_attribute_values.reserve(scene->objects.size());
+
+ for (size_t i = 0; i < scene->objects.size(); i++) {
+ Object *object = scene->objects[i];
+ Geometry *geom = object->geometry;
+ size_t geom_idx = geom->index;
+
+ assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom);
+
+ object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY));
+
+ AttributeRequestSet &geom_requests = geom_attributes[geom_idx];
+ AttributeRequestSet &attributes = object_attributes[i];
+ AttributeSet &values = object_attribute_values[i];
+
+ for (size_t j = 0; j < object->attributes.size(); j++) {
+ ParamValue &param = object->attributes[j];
+
+ /* add attributes that are requested and not already handled by the mesh */
+ if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) {
+ attributes.add(param.name());
+
+ Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT);
+ assert(param.datasize() == attr->buffer.size());
+ memcpy(attr->buffer.data(), param.data(), param.datasize());
+ }
+ }
+ }
+
+ /* mesh attribute are stored in a single array per data type. here we fill
+ * those arrays, and set the offset and element type to create attribute
+ * maps next */
+
+ /* Pre-allocate attributes to avoid arrays re-allocation which would
+ * take 2x of overall attribute memory usage.
+ */
+ size_t attr_float_size = 0;
+ size_t attr_float2_size = 0;
+ size_t attr_float3_size = 0;
+ size_t attr_uchar4_size = 0;
+
+ for (size_t i = 0; i < scene->geometry.size(); i++) {
+ Geometry *geom = scene->geometry[i];
+ AttributeRequestSet &attributes = geom_attributes[i];
+ foreach (AttributeRequest &req, attributes.requests) {
+ Attribute *attr = geom->attributes.find(req);
+
+ update_attribute_element_size(geom,
+ attr,
+ ATTR_PRIM_GEOMETRY,
+ &attr_float_size,
+ &attr_float2_size,
+ &attr_float3_size,
+ &attr_uchar4_size);
+
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ Attribute *subd_attr = mesh->subd_attributes.find(req);
+
+ update_attribute_element_size(mesh,
+ subd_attr,
+ ATTR_PRIM_SUBD,
+ &attr_float_size,
+ &attr_float2_size,
+ &attr_float3_size,
+ &attr_uchar4_size);
+ }
+ }
+ }
+
+ for (size_t i = 0; i < scene->objects.size(); i++) {
+ Object *object = scene->objects[i];
+
+ foreach (Attribute &attr, object_attribute_values[i].attributes) {
+ update_attribute_element_size(object->geometry,
+ &attr,
+ ATTR_PRIM_GEOMETRY,
+ &attr_float_size,
+ &attr_float2_size,
+ &attr_float3_size,
+ &attr_uchar4_size);
+ }
+ }
+
+ dscene->attributes_float.alloc(attr_float_size);
+ dscene->attributes_float2.alloc(attr_float2_size);
+ dscene->attributes_float3.alloc(attr_float3_size);
+ dscene->attributes_uchar4.alloc(attr_uchar4_size);
+
+ /* The order of those flags needs to match that of AttrKernelDataType. */
+ const bool attributes_need_realloc[4] = {
+ dscene->attributes_float.need_realloc(),
+ dscene->attributes_float2.need_realloc(),
+ dscene->attributes_float3.need_realloc(),
+ dscene->attributes_uchar4.need_realloc(),
+ };
+
+ size_t attr_float_offset = 0;
+ size_t attr_float2_offset = 0;
+ size_t attr_float3_offset = 0;
+ size_t attr_uchar4_offset = 0;
+
+ /* Fill in attributes. */
+ for (size_t i = 0; i < scene->geometry.size(); i++) {
+ Geometry *geom = scene->geometry[i];
+ AttributeRequestSet &attributes = geom_attributes[i];
+
+ /* todo: we now store std and name attributes from requests even if
+ * they actually refer to the same mesh attributes, optimize */
+ foreach (AttributeRequest &req, attributes.requests) {
+ Attribute *attr = geom->attributes.find(req);
+
+ if (attr) {
+ /* force a copy if we need to reallocate all the data */
+ attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
+ }
+
+ update_attribute_element_offset(geom,
+ dscene->attributes_float,
+ attr_float_offset,
+ dscene->attributes_float2,
+ attr_float2_offset,
+ dscene->attributes_float3,
+ attr_float3_offset,
+ dscene->attributes_uchar4,
+ attr_uchar4_offset,
+ attr,
+ ATTR_PRIM_GEOMETRY,
+ req.type,
+ req.desc);
+
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ Attribute *subd_attr = mesh->subd_attributes.find(req);
+
+ if (subd_attr) {
+ /* force a copy if we need to reallocate all the data */
+ subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)];
+ }
+
+ update_attribute_element_offset(mesh,
+ dscene->attributes_float,
+ attr_float_offset,
+ dscene->attributes_float2,
+ attr_float2_offset,
+ dscene->attributes_float3,
+ attr_float3_offset,
+ dscene->attributes_uchar4,
+ attr_uchar4_offset,
+ subd_attr,
+ ATTR_PRIM_SUBD,
+ req.subd_type,
+ req.subd_desc);
+ }
+
+ if (progress.get_cancel())
+ return;
+ }
+ }
+
+ for (size_t i = 0; i < scene->objects.size(); i++) {
+ Object *object = scene->objects[i];
+ AttributeRequestSet &attributes = object_attributes[i];
+ AttributeSet &values = object_attribute_values[i];
+
+ foreach (AttributeRequest &req, attributes.requests) {
+ Attribute *attr = values.find(req);
+
+ if (attr) {
+ attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
+ }
+
+ update_attribute_element_offset(object->geometry,
+ dscene->attributes_float,
+ attr_float_offset,
+ dscene->attributes_float2,
+ attr_float2_offset,
+ dscene->attributes_float3,
+ attr_float3_offset,
+ dscene->attributes_uchar4,
+ attr_uchar4_offset,
+ attr,
+ ATTR_PRIM_GEOMETRY,
+ req.type,
+ req.desc);
+
+ /* object attributes don't care about subdivision */
+ req.subd_type = req.type;
+ req.subd_desc = req.desc;
+
+ if (progress.get_cancel())
+ return;
+ }
+ }
+
+ /* create attribute lookup maps */
+ if (scene->shader_manager->use_osl())
+ update_osl_attributes(device, scene, geom_attributes);
+
+ update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes);
+
+ if (progress.get_cancel())
+ return;
+
+ /* copy to device */
+ progress.set_status("Updating Mesh", "Copying Attributes to device");
+
+ dscene->attributes_float.copy_to_device_if_modified();
+ dscene->attributes_float2.copy_to_device_if_modified();
+ dscene->attributes_float3.copy_to_device_if_modified();
+ dscene->attributes_uchar4.copy_to_device_if_modified();
+
+ if (progress.get_cancel())
+ return;
+
+ /* After mesh attributes and patch tables have been copied to device memory,
+ * we need to update offsets in the objects. */
+ scene->object_manager->device_update_mesh_offsets(device, dscene, scene);
+}
+
+void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout)
+{
+ size_t vert_size = 0;
+ size_t tri_size = 0;
+
+ size_t curve_size = 0;
+ size_t curve_key_size = 0;
+ size_t curve_segment_size = 0;
+
+ size_t patch_size = 0;
+ size_t face_size = 0;
+ size_t corner_size = 0;
+
+ foreach (Geometry *geom, scene->geometry) {
+ bool prim_offset_changed = false;
+
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+
+ prim_offset_changed = (mesh->prim_offset != tri_size);
+
+ mesh->vert_offset = vert_size;
+ mesh->prim_offset = tri_size;
+
+ mesh->patch_offset = patch_size;
+ mesh->face_offset = face_size;
+ mesh->corner_offset = corner_size;
+
+ vert_size += mesh->verts.size();
+ tri_size += mesh->num_triangles();
+
+ if (mesh->get_num_subd_faces()) {
+ Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1);
+ patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
+
+ /* patch tables are stored in same array so include them in patch_size */
+ if (mesh->patch_table) {
+ mesh->patch_table_offset = patch_size;
+ patch_size += mesh->patch_table->total_size();
+ }
+ }
+
+ face_size += mesh->get_num_subd_faces();
+ corner_size += mesh->subd_face_corners.size();
+ }
+ else if (geom->is_hair()) {
+ Hair *hair = static_cast<Hair *>(geom);
+
+ prim_offset_changed = (hair->curve_segment_offset != curve_segment_size);
+ hair->curve_key_offset = curve_key_size;
+ hair->curve_segment_offset = curve_segment_size;
+ hair->prim_offset = curve_size;
+
+ curve_size += hair->num_curves();
+ curve_key_size += hair->get_curve_keys().size();
+ curve_segment_size += hair->num_segments();
+ }
+
+ if (prim_offset_changed) {
+ /* Need to rebuild BVH in OptiX, since refit only allows modified mesh data there */
+ const bool has_optix_bvh = bvh_layout == BVH_LAYOUT_OPTIX ||
+ bvh_layout == BVH_LAYOUT_MULTI_OPTIX ||
+ bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE;
+ geom->need_update_rebuild |= has_optix_bvh;
+ geom->need_update_bvh_for_offset = true;
+ }
+ }
+}
+
+void GeometryManager::device_update_mesh(Device *,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ /* Count. */
+ size_t vert_size = 0;
+ size_t tri_size = 0;
+
+ size_t curve_key_size = 0;
+ size_t curve_size = 0;
+ size_t curve_segment_size = 0;
+
+ size_t patch_size = 0;
+
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+
+ vert_size += mesh->verts.size();
+ tri_size += mesh->num_triangles();
+
+ if (mesh->get_num_subd_faces()) {
+ Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1);
+ patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
+
+ /* patch tables are stored in same array so include them in patch_size */
+ if (mesh->patch_table) {
+ mesh->patch_table_offset = patch_size;
+ patch_size += mesh->patch_table->total_size();
+ }
+ }
+ }
+ else if (geom->is_hair()) {
+ Hair *hair = static_cast<Hair *>(geom);
+
+ curve_key_size += hair->get_curve_keys().size();
+ curve_size += hair->num_curves();
+ curve_segment_size += hair->num_segments();
+ }
+ }
+
+ /* Fill in all the arrays. */
+ if (tri_size != 0) {
+ /* normals */
+ progress.set_status("Updating Mesh", "Computing normals");
+
+ float4 *tri_verts = dscene->tri_verts.alloc(tri_size * 3);
+ uint *tri_shader = dscene->tri_shader.alloc(tri_size);
+ float4 *vnormal = dscene->tri_vnormal.alloc(vert_size);
+ uint4 *tri_vindex = dscene->tri_vindex.alloc(tri_size);
+ uint *tri_patch = dscene->tri_patch.alloc(tri_size);
+ float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
+
+ const bool copy_all_data = dscene->tri_shader.need_realloc() ||
+ dscene->tri_vindex.need_realloc() ||
+ dscene->tri_vnormal.need_realloc() ||
+ dscene->tri_patch.need_realloc() ||
+ dscene->tri_patch_uv.need_realloc();
+
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+
+ if (mesh->shader_is_modified() || mesh->smooth_is_modified() ||
+ mesh->triangles_is_modified() || copy_all_data) {
+ mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
+ }
+
+ if (mesh->verts_is_modified() || copy_all_data) {
+ mesh->pack_normals(&vnormal[mesh->vert_offset]);
+ }
+
+ if (mesh->verts_is_modified() || mesh->triangles_is_modified() ||
+ mesh->vert_patch_uv_is_modified() || copy_all_data) {
+ mesh->pack_verts(&tri_verts[mesh->prim_offset * 3],
+ &tri_vindex[mesh->prim_offset],
+ &tri_patch[mesh->prim_offset],
+ &tri_patch_uv[mesh->vert_offset]);
+ }
+
+ if (progress.get_cancel())
+ return;
+ }
+ }
+
+ /* vertex coordinates */
+ progress.set_status("Updating Mesh", "Copying Mesh to device");
+
+ dscene->tri_verts.copy_to_device_if_modified();
+ dscene->tri_shader.copy_to_device_if_modified();
+ dscene->tri_vnormal.copy_to_device_if_modified();
+ dscene->tri_vindex.copy_to_device_if_modified();
+ dscene->tri_patch.copy_to_device_if_modified();
+ dscene->tri_patch_uv.copy_to_device_if_modified();
+ }
+
+ if (curve_segment_size != 0) {
+ progress.set_status("Updating Mesh", "Copying Curves to device");
+
+ float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size);
+ KernelCurve *curves = dscene->curves.alloc(curve_size);
+ KernelCurveSegment *curve_segments = dscene->curve_segments.alloc(curve_segment_size);
+
+ const bool copy_all_data = dscene->curve_keys.need_realloc() ||
+ dscene->curves.need_realloc() ||
+ dscene->curve_segments.need_realloc();
+
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->is_hair()) {
+ Hair *hair = static_cast<Hair *>(geom);
+
+ bool curve_keys_co_modified = hair->curve_radius_is_modified() ||
+ hair->curve_keys_is_modified();
+ bool curve_data_modified = hair->curve_shader_is_modified() ||
+ hair->curve_first_key_is_modified();
+
+ if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) {
+ continue;
+ }
+
+ hair->pack_curves(scene,
+ &curve_keys[hair->curve_key_offset],
+ &curves[hair->prim_offset],
+ &curve_segments[hair->curve_segment_offset]);
+ if (progress.get_cancel())
+ return;
+ }
+ }
+
+ dscene->curve_keys.copy_to_device_if_modified();
+ dscene->curves.copy_to_device_if_modified();
+ dscene->curve_segments.copy_to_device_if_modified();
+ }
+
+ if (patch_size != 0 && dscene->patches.need_realloc()) {
+ progress.set_status("Updating Mesh", "Copying Patches to device");
+
+ uint *patch_data = dscene->patches.alloc(patch_size);
+
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ mesh->pack_patches(&patch_data[mesh->patch_offset]);
+
+ if (mesh->patch_table) {
+ mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset],
+ mesh->patch_table_offset);
+ }
+
+ if (progress.get_cancel())
+ return;
+ }
+ }
+
+ dscene->patches.copy_to_device();
+ }
+}
+
+void GeometryManager::device_update_bvh(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ /* bvh build */
+ progress.set_status("Updating Scene BVH", "Building");
+
+ BVHParams bparams;
+ bparams.top_level = true;
+ bparams.bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
+ device->get_bvh_layout_mask());
+ bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
+ bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
+ scene->params.use_bvh_unaligned_nodes;
+ bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps;
+ bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps;
+ bparams.bvh_type = scene->params.bvh_type;
+ bparams.curve_subdivisions = scene->params.curve_subdivisions();
+
+ VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
+
+ const bool can_refit = scene->bvh != nullptr &&
+ (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX);
+
+ BVH *bvh = scene->bvh;
+ if (!scene->bvh) {
+ bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
+ }
+
+ device->build_bvh(bvh, progress, can_refit);
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2);
+
+ PackedBVH pack;
+ if (has_bvh2_layout) {
+ pack = std::move(static_cast<BVH2 *>(bvh)->pack);
+ }
+ else {
+ pack.root_index = -1;
+ }
+
+ /* copy to device */
+ progress.set_status("Updating Scene BVH", "Copying BVH to device");
+
+ /* When using BVH2, we always have to copy/update the data as its layout is dependent on the
+ * BVH's leaf nodes which may be different when the objects or vertices move. */
+
+ if (pack.nodes.size()) {
+ dscene->bvh_nodes.steal_data(pack.nodes);
+ dscene->bvh_nodes.copy_to_device();
+ }
+ if (pack.leaf_nodes.size()) {
+ dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes);
+ dscene->bvh_leaf_nodes.copy_to_device();
+ }
+ if (pack.object_node.size()) {
+ dscene->object_node.steal_data(pack.object_node);
+ dscene->object_node.copy_to_device();
+ }
+ if (pack.prim_type.size()) {
+ dscene->prim_type.steal_data(pack.prim_type);
+ dscene->prim_type.copy_to_device();
+ }
+ if (pack.prim_visibility.size()) {
+ dscene->prim_visibility.steal_data(pack.prim_visibility);
+ dscene->prim_visibility.copy_to_device();
+ }
+ if (pack.prim_index.size()) {
+ dscene->prim_index.steal_data(pack.prim_index);
+ dscene->prim_index.copy_to_device();
+ }
+ if (pack.prim_object.size()) {
+ dscene->prim_object.steal_data(pack.prim_object);
+ dscene->prim_object.copy_to_device();
+ }
+ if (pack.prim_time.size()) {
+ dscene->prim_time.steal_data(pack.prim_time);
+ dscene->prim_time.copy_to_device();
+ }
+
+ dscene->data.bvh.root = pack.root_index;
+ dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
+ dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions();
+ /* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */
+ dscene->data.bvh.scene = 0;
+}
+
+/* Set of flags used to help determining what data has been modified or needs reallocation, so we
+ * can decide which device data to free or update. */
+enum {
+ DEVICE_CURVE_DATA_MODIFIED = (1 << 0),
+ DEVICE_MESH_DATA_MODIFIED = (1 << 1),
+
+ ATTR_FLOAT_MODIFIED = (1 << 2),
+ ATTR_FLOAT2_MODIFIED = (1 << 3),
+ ATTR_FLOAT3_MODIFIED = (1 << 4),
+ ATTR_UCHAR4_MODIFIED = (1 << 5),
+
+ CURVE_DATA_NEED_REALLOC = (1 << 6),
+ MESH_DATA_NEED_REALLOC = (1 << 7),
+
+ ATTR_FLOAT_NEEDS_REALLOC = (1 << 8),
+ ATTR_FLOAT2_NEEDS_REALLOC = (1 << 9),
+ ATTR_FLOAT3_NEEDS_REALLOC = (1 << 10),
+ ATTR_UCHAR4_NEEDS_REALLOC = (1 << 11),
+
+ ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
+ ATTR_FLOAT3_NEEDS_REALLOC | ATTR_UCHAR4_NEEDS_REALLOC),
+ DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
+ DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
+};
+
+static void update_device_flags_attribute(uint32_t &device_update_flags,
+ const AttributeSet &attributes)
+{
+ foreach (const Attribute &attr, attributes.attributes) {
+ if (!attr.modified) {
+ continue;
+ }
+
+ AttrKernelDataType kernel_type = Attribute::kernel_type(attr);
+
+ switch (kernel_type) {
+ case AttrKernelDataType::FLOAT: {
+ device_update_flags |= ATTR_FLOAT_MODIFIED;
+ break;
+ }
+ case AttrKernelDataType::FLOAT2: {
+ device_update_flags |= ATTR_FLOAT2_MODIFIED;
+ break;
+ }
+ case AttrKernelDataType::FLOAT3: {
+ device_update_flags |= ATTR_FLOAT3_MODIFIED;
+ break;
+ }
+ case AttrKernelDataType::UCHAR4: {
+ device_update_flags |= ATTR_UCHAR4_MODIFIED;
+ break;
+ }
+ }
+ }
+}
+
+static void update_attribute_realloc_flags(uint32_t &device_update_flags,
+ const AttributeSet &attributes)
+{
+ if (attributes.modified(AttrKernelDataType::FLOAT)) {
+ device_update_flags |= ATTR_FLOAT_NEEDS_REALLOC;
+ }
+ if (attributes.modified(AttrKernelDataType::FLOAT2)) {
+ device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC;
+ }
+ if (attributes.modified(AttrKernelDataType::FLOAT3)) {
+ device_update_flags |= ATTR_FLOAT3_NEEDS_REALLOC;
+ }
+ if (attributes.modified(AttrKernelDataType::UCHAR4)) {
+ device_update_flags |= ATTR_UCHAR4_NEEDS_REALLOC;
+ }
+}
+
+void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress)
+{
+ if (!need_update() && !need_flags_update) {
+ return;
+ }
+
+ uint32_t device_update_flags = 0;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry({"device_update_preprocess", time});
+ }
+ });
+
+ progress.set_status("Updating Meshes Flags");
+
+ /* Update flags. */
+ bool volume_images_updated = false;
+
+ foreach (Geometry *geom, scene->geometry) {
+ geom->has_volume = false;
+
+ update_attribute_realloc_flags(device_update_flags, geom->attributes);
+
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ update_attribute_realloc_flags(device_update_flags, mesh->subd_attributes);
+ }
+
+ foreach (Node *node, geom->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->has_volume) {
+ geom->has_volume = true;
+ }
+
+ if (shader->has_surface_bssrdf) {
+ geom->has_surface_bssrdf = true;
+ }
+
+ if (shader->need_update_uvs) {
+ device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC;
+
+ /* Attributes might need to be tessellated if added. */
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->need_tesselation()) {
+ mesh->tag_modified();
+ }
+ }
+ }
+
+ if (shader->need_update_attribute) {
+ device_update_flags |= ATTRS_NEED_REALLOC;
+
+ /* Attributes might need to be tessellated if added. */
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->need_tesselation()) {
+ mesh->tag_modified();
+ }
+ }
+ }
+
+ if (shader->need_update_displacement) {
+ /* tag displacement related sockets as modified */
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ mesh->tag_verts_modified();
+ mesh->tag_subd_dicing_rate_modified();
+ mesh->tag_subd_max_level_modified();
+ mesh->tag_subd_objecttoworld_modified();
+
+ device_update_flags |= ATTRS_NEED_REALLOC;
+ }
+ }
+ }
+
+ /* only check for modified attributes if we do not need to reallocate them already */
+ if ((device_update_flags & ATTRS_NEED_REALLOC) == 0) {
+ update_device_flags_attribute(device_update_flags, geom->attributes);
+ /* don't check for subd_attributes, as if they were modified, we would need to reallocate
+ * anyway */
+ }
+
+ /* Re-create volume mesh if we will rebuild or refit the BVH. Note we
+ * should only do it in that case, otherwise the BVH and mesh can go
+ * out of sync. */
+ if (geom->is_modified() && geom->geometry_type == Geometry::VOLUME) {
+ /* Create volume meshes if there is voxel data. */
+ if (!volume_images_updated) {
+ progress.set_status("Updating Meshes Volume Bounds");
+ device_update_volume_images(device, scene, progress);
+ volume_images_updated = true;
+ }
+
+ Volume *volume = static_cast<Volume *>(geom);
+ create_volume_mesh(volume, progress);
+
+ /* always reallocate when we have a volume, as we need to rebuild the BVH */
+ device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
+ }
+
+ if (geom->is_hair()) {
+ /* Set curve shape, still a global scene setting for now. */
+ Hair *hair = static_cast<Hair *>(geom);
+ hair->curve_shape = scene->params.hair_shape;
+
+ if (hair->need_update_rebuild) {
+ device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
+ }
+ else if (hair->is_modified()) {
+ device_update_flags |= DEVICE_CURVE_DATA_MODIFIED;
+ }
+ }
+
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+
+ if (mesh->need_update_rebuild) {
+ device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
+ }
+ else if (mesh->is_modified()) {
+ device_update_flags |= DEVICE_MESH_DATA_MODIFIED;
+ }
+ }
+ }
+
+ if (update_flags & (MESH_ADDED | MESH_REMOVED)) {
+ device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
+ }
+
+ if (update_flags & (HAIR_ADDED | HAIR_REMOVED)) {
+ device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
+ }
+
+ /* tag the device arrays for reallocation or modification */
+ DeviceScene *dscene = &scene->dscene;
+
+ if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC)) {
+ delete scene->bvh;
+ scene->bvh = nullptr;
+
+ dscene->bvh_nodes.tag_realloc();
+ dscene->bvh_leaf_nodes.tag_realloc();
+ dscene->object_node.tag_realloc();
+ dscene->prim_type.tag_realloc();
+ dscene->prim_visibility.tag_realloc();
+ dscene->prim_index.tag_realloc();
+ dscene->prim_object.tag_realloc();
+ dscene->prim_time.tag_realloc();
+
+ if (device_update_flags & DEVICE_MESH_DATA_NEEDS_REALLOC) {
+ dscene->tri_verts.tag_realloc();
+ dscene->tri_vnormal.tag_realloc();
+ dscene->tri_vindex.tag_realloc();
+ dscene->tri_patch.tag_realloc();
+ dscene->tri_patch_uv.tag_realloc();
+ dscene->tri_shader.tag_realloc();
+ dscene->patches.tag_realloc();
+ }
+
+ if (device_update_flags & DEVICE_CURVE_DATA_NEEDS_REALLOC) {
+ dscene->curves.tag_realloc();
+ dscene->curve_keys.tag_realloc();
+ dscene->curve_segments.tag_realloc();
+ }
+ }
+
+ if ((update_flags & VISIBILITY_MODIFIED) != 0) {
+ dscene->prim_visibility.tag_modified();
+ }
+
+ if (device_update_flags & ATTR_FLOAT_NEEDS_REALLOC) {
+ dscene->attributes_map.tag_realloc();
+ dscene->attributes_float.tag_realloc();
+ }
+ else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
+ dscene->attributes_float.tag_modified();
+ }
+
+ if (device_update_flags & ATTR_FLOAT2_NEEDS_REALLOC) {
+ dscene->attributes_map.tag_realloc();
+ dscene->attributes_float2.tag_realloc();
+ }
+ else if (device_update_flags & ATTR_FLOAT2_MODIFIED) {
+ dscene->attributes_float2.tag_modified();
+ }
+
+ if (device_update_flags & ATTR_FLOAT3_NEEDS_REALLOC) {
+ dscene->attributes_map.tag_realloc();
+ dscene->attributes_float3.tag_realloc();
+ }
+ else if (device_update_flags & ATTR_FLOAT3_MODIFIED) {
+ dscene->attributes_float3.tag_modified();
+ }
+
+ if (device_update_flags & ATTR_UCHAR4_NEEDS_REALLOC) {
+ dscene->attributes_map.tag_realloc();
+ dscene->attributes_uchar4.tag_realloc();
+ }
+ else if (device_update_flags & ATTR_UCHAR4_MODIFIED) {
+ dscene->attributes_uchar4.tag_modified();
+ }
+
+ if (device_update_flags & DEVICE_MESH_DATA_MODIFIED) {
+ /* if anything else than vertices or shaders are modified, we would need to reallocate, so
+ * these are the only arrays that can be updated */
+ dscene->tri_verts.tag_modified();
+ dscene->tri_vnormal.tag_modified();
+ dscene->tri_shader.tag_modified();
+ }
+
+ if (device_update_flags & DEVICE_CURVE_DATA_MODIFIED) {
+ dscene->curve_keys.tag_modified();
+ dscene->curves.tag_modified();
+ dscene->curve_segments.tag_modified();
+ }
+
+ need_flags_update = false;
+}
+
+void GeometryManager::device_update_displacement_images(Device *device,
+ Scene *scene,
+ Progress &progress)
+{
+ progress.set_status("Updating Displacement Images");
+ TaskPool pool;
+ ImageManager *image_manager = scene->image_manager;
+ set<int> bump_images;
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->is_modified()) {
+ foreach (Node *node, geom->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
+ continue;
+ }
+ foreach (ShaderNode *node, shader->graph->nodes) {
+ if (node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) {
+ continue;
+ }
+
+ ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode *>(node);
+ for (int i = 0; i < image_node->handle.num_tiles(); i++) {
+ const int slot = image_node->handle.svm_slot(i);
+ if (slot != -1) {
+ bump_images.insert(slot);
+ }
+ }
+ }
+ }
+ }
+ }
+ foreach (int slot, bump_images) {
+ pool.push(function_bind(
+ &ImageManager::device_update_slot, image_manager, device, scene, slot, &progress));
+ }
+ pool.wait_work();
+}
+
+void GeometryManager::device_update_volume_images(Device *device, Scene *scene, Progress &progress)
+{
+ progress.set_status("Updating Volume Images");
+ TaskPool pool;
+ ImageManager *image_manager = scene->image_manager;
+ set<int> volume_images;
+
+ foreach (Geometry *geom, scene->geometry) {
+ if (!geom->is_modified()) {
+ continue;
+ }
+
+ foreach (Attribute &attr, geom->attributes.attributes) {
+ if (attr.element != ATTR_ELEMENT_VOXEL) {
+ continue;
+ }
+
+ ImageHandle &handle = attr.data_voxel();
+ /* We can build directly from OpenVDB data structures, no need to
+ * load such images early. */
+ if (!handle.vdb_loader()) {
+ const int slot = handle.svm_slot();
+ if (slot != -1) {
+ volume_images.insert(slot);
+ }
+ }
+ }
+ }
+
+ foreach (int slot, volume_images) {
+ pool.push(function_bind(
+ &ImageManager::device_update_slot, image_manager, device, scene, slot, &progress));
+ }
+ pool.wait_work();
+}
+
+void GeometryManager::device_update(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ if (!need_update())
+ return;
+
+ VLOG(1) << "Total " << scene->geometry.size() << " meshes.";
+
+ bool true_displacement_used = false;
+ bool curve_shadow_transparency_used = false;
+ size_t total_tess_needed = 0;
+
+ {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry({"device_update (normals)", time});
+ }
+ });
+
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->is_modified()) {
+ if ((geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME)) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+
+ /* Update normals. */
+ mesh->add_face_normals();
+ mesh->add_vertex_normals();
+
+ if (mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) {
+ mesh->add_undisplaced();
+ }
+
+ /* Test if we need tessellation. */
+ if (mesh->need_tesselation()) {
+ total_tess_needed++;
+ }
+
+ /* Test if we need displacement. */
+ if (mesh->has_true_displacement()) {
+ true_displacement_used = true;
+ }
+ }
+ else if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ if (hair->need_shadow_transparency()) {
+ curve_shadow_transparency_used = true;
+ }
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+ }
+ }
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ /* Tessellate meshes that are using subdivision */
+ if (total_tess_needed) {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry(
+ {"device_update (adaptive subdivision)", time});
+ }
+ });
+
+ Camera *dicing_camera = scene->dicing_camera;
+ dicing_camera->set_screen_size(dicing_camera->get_full_width(),
+ dicing_camera->get_full_height());
+ dicing_camera->update(scene);
+
+ size_t i = 0;
+ foreach (Geometry *geom, scene->geometry) {
+ if (!(geom->is_modified() && geom->is_mesh())) {
+ continue;
+ }
+
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->need_tesselation()) {
+ string msg = "Tessellating ";
+ if (mesh->name == "")
+ msg += string_printf("%u/%u", (uint)(i + 1), (uint)total_tess_needed);
+ else
+ msg += string_printf(
+ "%s %u/%u", mesh->name.c_str(), (uint)(i + 1), (uint)total_tess_needed);
+
+ progress.set_status("Updating Mesh", msg);
+
+ mesh->subd_params->camera = dicing_camera;
+ DiagSplit dsplit(*mesh->subd_params);
+ mesh->tessellate(&dsplit);
+
+ i++;
+
+ if (progress.get_cancel()) {
+ return;
+ }
+ }
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+ }
+
+ /* Update images needed for true displacement. */
+ bool old_need_object_flags_update = false;
+ if (true_displacement_used || curve_shadow_transparency_used) {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry(
+ {"device_update (displacement: load images)", time});
+ }
+ });
+ device_update_displacement_images(device, scene, progress);
+ old_need_object_flags_update = scene->object_manager->need_flags_update;
+ scene->object_manager->device_update_flags(device, dscene, scene, progress, false);
+ }
+
+ /* Device update. */
+ device_free(device, dscene, false);
+
+ const BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
+ device->get_bvh_layout_mask());
+ mesh_calc_offset(scene, bvh_layout);
+ if (true_displacement_used || curve_shadow_transparency_used) {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry(
+ {"device_update (displacement: copy meshes to device)", time});
+ }
+ });
+ device_update_mesh(device, dscene, scene, progress);
+ }
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry({"device_update (attributes)", time});
+ }
+ });
+ device_update_attributes(device, dscene, scene, progress);
+ if (progress.get_cancel()) {
+ return;
+ }
+ }
+
+ /* Update displacement and hair shadow transparency. */
+ bool displacement_done = false;
+ bool curve_shadow_transparency_done = false;
+ size_t num_bvh = 0;
+
+ {
+ /* Copy constant data needed by shader evaluation. */
+ device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry({"device_update (displacement)", time});
+ }
+ });
+
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->is_modified()) {
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (displace(device, scene, mesh, progress)) {
+ displacement_done = true;
+ }
+ }
+ else if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ if (hair->update_shadow_transparency(device, scene, progress)) {
+ curve_shadow_transparency_done = true;
+ }
+ }
+ }
+
+ if (geom->is_modified() || geom->need_update_bvh_for_offset) {
+ if (geom->need_build_bvh(bvh_layout)) {
+ num_bvh++;
+ }
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+ }
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ /* Device re-update after displacement. */
+ if (displacement_done || curve_shadow_transparency_done) {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry(
+ {"device_update (displacement: attributes)", time});
+ }
+ });
+ device_free(device, dscene, false);
+
+ device_update_attributes(device, dscene, scene, progress);
+ if (progress.get_cancel()) {
+ return;
+ }
+ }
+
+ /* Update the BVH even when there is no geometry so the kernel's BVH data is still valid,
+ * especially when removing all of the objects during interactive renders.
+ * Also update the BVH if the transformations change, we cannot rely on tagging the Geometry
+ * as modified in this case, as we may accumulate displacement if the vertices do not also
+ * change. */
+ bool need_update_scene_bvh = (scene->bvh == nullptr ||
+ (update_flags & (TRANSFORM_MODIFIED | VISIBILITY_MODIFIED)) != 0);
+ {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry({"device_update (build object BVHs)", time});
+ }
+ });
+ TaskPool pool;
+
+ size_t i = 0;
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->is_modified() || geom->need_update_bvh_for_offset) {
+ need_update_scene_bvh = true;
+ pool.push(function_bind(
+ &Geometry::compute_bvh, geom, device, dscene, &scene->params, &progress, i, num_bvh));
+ if (geom->need_build_bvh(bvh_layout)) {
+ i++;
+ }
+ }
+ }
+
+ TaskPool::Summary summary;
+ pool.wait_work(&summary);
+ VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report();
+ }
+
+ foreach (Shader *shader, scene->shaders) {
+ shader->need_update_uvs = false;
+ shader->need_update_attribute = false;
+ shader->need_update_displacement = false;
+ }
+
+ Scene::MotionType need_motion = scene->need_motion();
+ bool motion_blur = need_motion == Scene::MOTION_BLUR;
+
+ /* Update objects. */
+ {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry({"device_update (compute bounds)", time});
+ }
+ });
+ foreach (Object *object, scene->objects) {
+ object->compute_bounds(motion_blur);
+ }
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ if (need_update_scene_bvh) {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry({"device_update (build scene BVH)", time});
+ }
+ });
+ device_update_bvh(device, dscene, scene, progress);
+ if (progress.get_cancel()) {
+ return;
+ }
+ }
+
+ /* Always set BVH layout again after displacement where it was set to none,
+ * to avoid ray-tracing at that stage. */
+ dscene->data.bvh.bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
+ device->get_bvh_layout_mask());
+
+ {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->geometry.times.add_entry(
+ {"device_update (copy meshes to device)", time});
+ }
+ });
+ device_update_mesh(device, dscene, scene, progress);
+ if (progress.get_cancel()) {
+ return;
+ }
+ }
+
+ if (true_displacement_used) {
+ /* Re-tag flags for update, so they're re-evaluated
+ * for meshes with correct bounding boxes.
+ *
+ * This wouldn't cause wrong results, just true
+ * displacement might be less optimal to calculate.
+ */
+ scene->object_manager->need_flags_update = old_need_object_flags_update;
+ }
+
+ /* unset flags */
+
+ foreach (Geometry *geom, scene->geometry) {
+ geom->clear_modified();
+ geom->attributes.clear_modified();
+
+ if (geom->is_mesh()) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ mesh->subd_attributes.clear_modified();
+ }
+ }
+
+ update_flags = UPDATE_NONE;
+
+ dscene->bvh_nodes.clear_modified();
+ dscene->bvh_leaf_nodes.clear_modified();
+ dscene->object_node.clear_modified();
+ dscene->prim_type.clear_modified();
+ dscene->prim_visibility.clear_modified();
+ dscene->prim_index.clear_modified();
+ dscene->prim_object.clear_modified();
+ dscene->prim_time.clear_modified();
+ dscene->tri_verts.clear_modified();
+ dscene->tri_shader.clear_modified();
+ dscene->tri_vindex.clear_modified();
+ dscene->tri_patch.clear_modified();
+ dscene->tri_vnormal.clear_modified();
+ dscene->tri_patch_uv.clear_modified();
+ dscene->curves.clear_modified();
+ dscene->curve_keys.clear_modified();
+ dscene->curve_segments.clear_modified();
+ dscene->patches.clear_modified();
+ dscene->attributes_map.clear_modified();
+ dscene->attributes_float.clear_modified();
+ dscene->attributes_float2.clear_modified();
+ dscene->attributes_float3.clear_modified();
+ dscene->attributes_uchar4.clear_modified();
+}
+
+void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool force_free)
+{
+ dscene->bvh_nodes.free_if_need_realloc(force_free);
+ dscene->bvh_leaf_nodes.free_if_need_realloc(force_free);
+ dscene->object_node.free_if_need_realloc(force_free);
+ dscene->prim_type.free_if_need_realloc(force_free);
+ dscene->prim_visibility.free_if_need_realloc(force_free);
+ dscene->prim_index.free_if_need_realloc(force_free);
+ dscene->prim_object.free_if_need_realloc(force_free);
+ dscene->prim_time.free_if_need_realloc(force_free);
+ dscene->tri_verts.free_if_need_realloc(force_free);
+ dscene->tri_shader.free_if_need_realloc(force_free);
+ dscene->tri_vnormal.free_if_need_realloc(force_free);
+ dscene->tri_vindex.free_if_need_realloc(force_free);
+ dscene->tri_patch.free_if_need_realloc(force_free);
+ dscene->tri_patch_uv.free_if_need_realloc(force_free);
+ dscene->curves.free_if_need_realloc(force_free);
+ dscene->curve_keys.free_if_need_realloc(force_free);
+ dscene->curve_segments.free_if_need_realloc(force_free);
+ dscene->patches.free_if_need_realloc(force_free);
+ dscene->attributes_map.free_if_need_realloc(force_free);
+ dscene->attributes_float.free_if_need_realloc(force_free);
+ dscene->attributes_float2.free_if_need_realloc(force_free);
+ dscene->attributes_float3.free_if_need_realloc(force_free);
+ dscene->attributes_uchar4.free_if_need_realloc(force_free);
+
+ /* Signal for shaders like displacement not to do ray tracing. */
+ dscene->data.bvh.bvh_layout = BVH_LAYOUT_NONE;
+
+#ifdef WITH_OSL
+ OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
+
+ if (og) {
+ og->object_name_map.clear();
+ og->attribute_map.clear();
+ og->object_names.clear();
+ }
+#else
+ (void)device;
+#endif
+}
+
+void GeometryManager::tag_update(Scene *scene, uint32_t flag)
+{
+ update_flags |= flag;
+
+ /* do not tag the object manager for an update if it is the one who tagged us */
+ if ((flag & OBJECT_MANAGER) == 0) {
+ scene->object_manager->tag_update(scene, ObjectManager::GEOMETRY_MANAGER);
+ }
+}
+
+bool GeometryManager::need_update() const
+{
+ return update_flags != UPDATE_NONE;
+}
+
+void GeometryManager::collect_statistics(const Scene *scene, RenderStats *stats)
+{
+ foreach (Geometry *geometry, scene->geometry) {
+ stats->mesh.geometry.add_entry(
+ NamedSizeEntry(string(geometry->name.c_str()), geometry->get_total_size_in_bytes()));
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h
new file mode 100644
index 00000000000..335bcdcd0b7
--- /dev/null
+++ b/intern/cycles/scene/geometry.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GEOMETRY_H__
+#define __GEOMETRY_H__
+
+#include "graph/node.h"
+
+#include "bvh/params.h"
+
+#include "scene/attribute.h"
+
+#include "util/boundbox.h"
+#include "util/set.h"
+#include "util/transform.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BVH;
+class Device;
+class DeviceScene;
+class Mesh;
+class Progress;
+class RenderStats;
+class Scene;
+class SceneParams;
+class Shader;
+class Volume;
+struct PackedBVH;
+
+/* Geometry
+ *
+ * Base class for geometric types like Mesh and Hair. */
+
+class Geometry : public Node {
+ public:
+ NODE_ABSTRACT_DECLARE
+
+ enum Type {
+ MESH,
+ HAIR,
+ VOLUME,
+ };
+
+ Type geometry_type;
+
+ /* Attributes */
+ AttributeSet attributes;
+
+ /* Shaders */
+ NODE_SOCKET_API_ARRAY(array<Node *>, used_shaders)
+
+ /* Transform */
+ BoundBox bounds;
+ bool transform_applied;
+ bool transform_negative_scaled;
+ Transform transform_normal;
+
+ /* Motion Blur */
+ NODE_SOCKET_API(uint, motion_steps)
+ NODE_SOCKET_API(bool, use_motion_blur)
+
+ /* Maximum number of motion steps supported (due to Embree). */
+ static const uint MAX_MOTION_STEPS = 129;
+
+ /* BVH */
+ BVH *bvh;
+ size_t attr_map_offset;
+ size_t prim_offset;
+
+ /* Shader Properties */
+ bool has_volume; /* Set in the device_update_flags(). */
+ bool has_surface_bssrdf; /* Set in the device_update_flags(). */
+
+ /* Update Flags */
+ bool need_update_rebuild;
+ bool need_update_bvh_for_offset;
+
+ /* Index into scene->geometry (only valid during update) */
+ size_t index;
+
+ /* Constructor/Destructor */
+ explicit Geometry(const NodeType *node_type, const Type type);
+ virtual ~Geometry();
+
+ /* Geometry */
+ virtual void clear(bool preserve_shaders = false);
+ virtual void compute_bounds() = 0;
+ virtual void apply_transform(const Transform &tfm, const bool apply_to_motion) = 0;
+
+ /* Attribute Requests */
+ bool need_attribute(Scene *scene, AttributeStandard std);
+ bool need_attribute(Scene *scene, ustring name);
+
+ AttributeRequestSet needed_attributes();
+
+ /* UDIM */
+ virtual void get_uv_tiles(ustring map, unordered_set<int> &tiles) = 0;
+
+ /* Convert between normalized -1..1 motion time and index in the
+ * VERTEX_MOTION attribute. */
+ float motion_time(int step) const;
+ int motion_step(float time) const;
+
+ /* BVH */
+ void compute_bvh(Device *device,
+ DeviceScene *dscene,
+ SceneParams *params,
+ Progress *progress,
+ int n,
+ int total);
+
+ virtual PrimitiveType primitive_type() const = 0;
+
+ /* Check whether the geometry should have own BVH built separately. Briefly,
+ * own BVH is needed for geometry, if:
+ *
+ * - It is instanced multiple times, so each instance object should share the
+ * same BVH tree.
+ * - Special ray intersection is needed, for example to limit subsurface rays
+ * to only the geometry itself.
+ * - The BVH layout requires the top level to only contain instances.
+ */
+ bool need_build_bvh(BVHLayout layout) const;
+
+ /* Test if the geometry should be treated as instanced. */
+ bool is_instanced() const;
+
+ bool has_true_displacement() const;
+ bool has_motion_blur() const;
+ bool has_voxel_attributes() const;
+
+ bool is_mesh() const
+ {
+ return geometry_type == MESH;
+ }
+
+ bool is_hair() const
+ {
+ return geometry_type == HAIR;
+ }
+
+ bool is_volume() const
+ {
+ return geometry_type == VOLUME;
+ }
+
+ /* Updates */
+ void tag_update(Scene *scene, bool rebuild);
+
+ void tag_bvh_update(bool rebuild);
+};
+
+/* Geometry Manager */
+
+class GeometryManager {
+ uint32_t update_flags;
+
+ public:
+ enum : uint32_t {
+ UV_PASS_NEEDED = (1 << 0),
+ MOTION_PASS_NEEDED = (1 << 1),
+ GEOMETRY_MODIFIED = (1 << 2),
+ OBJECT_MANAGER = (1 << 3),
+ MESH_ADDED = (1 << 4),
+ MESH_REMOVED = (1 << 5),
+ HAIR_ADDED = (1 << 6),
+ HAIR_REMOVED = (1 << 7),
+
+ SHADER_ATTRIBUTE_MODIFIED = (1 << 8),
+ SHADER_DISPLACEMENT_MODIFIED = (1 << 9),
+
+ GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED,
+ GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED,
+
+ TRANSFORM_MODIFIED = (1 << 10),
+
+ VISIBILITY_MODIFIED = (1 << 11),
+
+ /* tag everything in the manager for an update */
+ UPDATE_ALL = ~0u,
+
+ UPDATE_NONE = 0u,
+ };
+
+ /* Update Flags */
+ bool need_flags_update;
+
+ /* Constructor/Destructor */
+ GeometryManager();
+ ~GeometryManager();
+
+ /* Device Updates */
+ void device_update_preprocess(Device *device, Scene *scene, Progress &progress);
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
+ void device_free(Device *device, DeviceScene *dscene, bool force_free);
+
+ /* Updates */
+ void tag_update(Scene *scene, uint32_t flag);
+
+ bool need_update() const;
+
+ /* Statistics */
+ void collect_statistics(const Scene *scene, RenderStats *stats);
+
+ protected:
+ bool displace(Device *device, Scene *scene, Mesh *mesh, Progress &progress);
+
+ void create_volume_mesh(Volume *volume, Progress &progress);
+
+ /* Attributes */
+ void update_osl_attributes(Device *device,
+ Scene *scene,
+ vector<AttributeRequestSet> &geom_attributes);
+ void update_svm_attributes(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ vector<AttributeRequestSet> &geom_attributes,
+ vector<AttributeRequestSet> &object_attributes);
+
+ /* Compute verts/triangles/curves offsets in global arrays. */
+ void mesh_calc_offset(Scene *scene, BVHLayout bvh_layout);
+
+ void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
+
+ void device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
+
+ void device_update_attributes(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress);
+
+ void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
+
+ void device_update_displacement_images(Device *device, Scene *scene, Progress &progress);
+
+ void device_update_volume_images(Device *device, Scene *scene, Progress &progress);
+
+ private:
+ static void update_attribute_element_offset(Geometry *geom,
+ device_vector<float> &attr_float,
+ size_t &attr_float_offset,
+ device_vector<float2> &attr_float2,
+ size_t &attr_float2_offset,
+ device_vector<float4> &attr_float3,
+ size_t &attr_float3_offset,
+ device_vector<uchar4> &attr_uchar4,
+ size_t &attr_uchar4_offset,
+ Attribute *mattr,
+ AttributePrimitive prim,
+ TypeDesc &type,
+ AttributeDescriptor &desc);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __GEOMETRY_H__ */
diff --git a/intern/cycles/scene/hair.cpp b/intern/cycles/scene/hair.cpp
new file mode 100644
index 00000000000..2951a609ae9
--- /dev/null
+++ b/intern/cycles/scene/hair.cpp
@@ -0,0 +1,632 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bvh/bvh.h"
+
+#include "scene/curves.h"
+#include "scene/hair.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+
+#include "integrator/shader_eval.h"
+
+#include "util/progress.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Hair Curve */
+
+void Hair::Curve::bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ BoundBox &bounds) const
+{
+ float3 P[4];
+
+ P[0] = curve_keys[max(first_key + k - 1, first_key)];
+ P[1] = curve_keys[first_key + k];
+ P[2] = curve_keys[first_key + k + 1];
+ P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)];
+
+ float3 lower;
+ float3 upper;
+
+ curvebounds(&lower.x, &upper.x, P, 0);
+ curvebounds(&lower.y, &upper.y, P, 1);
+ curvebounds(&lower.z, &upper.z, P, 2);
+
+ float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]);
+
+ bounds.grow(lower, mr);
+ bounds.grow(upper, mr);
+}
+
+void Hair::Curve::bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ const Transform &aligned_space,
+ BoundBox &bounds) const
+{
+ float3 P[4];
+
+ P[0] = curve_keys[max(first_key + k - 1, first_key)];
+ P[1] = curve_keys[first_key + k];
+ P[2] = curve_keys[first_key + k + 1];
+ P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)];
+
+ P[0] = transform_point(&aligned_space, P[0]);
+ P[1] = transform_point(&aligned_space, P[1]);
+ P[2] = transform_point(&aligned_space, P[2]);
+ P[3] = transform_point(&aligned_space, P[3]);
+
+ float3 lower;
+ float3 upper;
+
+ curvebounds(&lower.x, &upper.x, P, 0);
+ curvebounds(&lower.y, &upper.y, P, 1);
+ curvebounds(&lower.z, &upper.z, P, 2);
+
+ float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]);
+
+ bounds.grow(lower, mr);
+ bounds.grow(upper, mr);
+}
+
+void Hair::Curve::bounds_grow(float4 keys[4], BoundBox &bounds) const
+{
+ float3 P[4] = {
+ float4_to_float3(keys[0]),
+ float4_to_float3(keys[1]),
+ float4_to_float3(keys[2]),
+ float4_to_float3(keys[3]),
+ };
+
+ float3 lower;
+ float3 upper;
+
+ curvebounds(&lower.x, &upper.x, P, 0);
+ curvebounds(&lower.y, &upper.y, P, 1);
+ curvebounds(&lower.z, &upper.z, P, 2);
+
+ float mr = max(keys[1].w, keys[2].w);
+
+ bounds.grow(lower, mr);
+ bounds.grow(upper, mr);
+}
+
+void Hair::Curve::motion_keys(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ float time,
+ size_t k0,
+ size_t k1,
+ float4 r_keys[2]) const
+{
+ /* Figure out which steps we need to fetch and their interpolation factor. */
+ const size_t max_step = num_steps - 1;
+ const size_t step = min((int)(time * max_step), max_step - 1);
+ const float t = time * max_step - step;
+ /* Fetch vertex coordinates. */
+ float4 curr_keys[2];
+ float4 next_keys[2];
+ keys_for_step(
+ curve_keys, curve_radius, key_steps, num_curve_keys, num_steps, step, k0, k1, curr_keys);
+ keys_for_step(
+ curve_keys, curve_radius, key_steps, num_curve_keys, num_steps, step + 1, k0, k1, next_keys);
+ /* Interpolate between steps. */
+ r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0];
+ r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1];
+}
+
+void Hair::Curve::cardinal_motion_keys(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ float time,
+ size_t k0,
+ size_t k1,
+ size_t k2,
+ size_t k3,
+ float4 r_keys[4]) const
+{
+ /* Figure out which steps we need to fetch and their interpolation factor. */
+ const size_t max_step = num_steps - 1;
+ const size_t step = min((int)(time * max_step), max_step - 1);
+ const float t = time * max_step - step;
+ /* Fetch vertex coordinates. */
+ float4 curr_keys[4];
+ float4 next_keys[4];
+ cardinal_keys_for_step(curve_keys,
+ curve_radius,
+ key_steps,
+ num_curve_keys,
+ num_steps,
+ step,
+ k0,
+ k1,
+ k2,
+ k3,
+ curr_keys);
+ cardinal_keys_for_step(curve_keys,
+ curve_radius,
+ key_steps,
+ num_curve_keys,
+ num_steps,
+ step + 1,
+ k0,
+ k1,
+ k2,
+ k3,
+ next_keys);
+ /* Interpolate between steps. */
+ r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0];
+ r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1];
+ r_keys[2] = (1.0f - t) * curr_keys[2] + t * next_keys[2];
+ r_keys[3] = (1.0f - t) * curr_keys[3] + t * next_keys[3];
+}
+
+void Hair::Curve::keys_for_step(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ size_t step,
+ size_t k0,
+ size_t k1,
+ float4 r_keys[2]) const
+{
+ k0 = max(k0, 0);
+ k1 = min(k1, num_keys - 1);
+ const size_t center_step = ((num_steps - 1) / 2);
+ if (step == center_step) {
+ /* Center step: regular key location. */
+ /* TODO(sergey): Consider adding make_float4(float3, float)
+ * function.
+ */
+ r_keys[0] = make_float4(curve_keys[first_key + k0].x,
+ curve_keys[first_key + k0].y,
+ curve_keys[first_key + k0].z,
+ curve_radius[first_key + k0]);
+ r_keys[1] = make_float4(curve_keys[first_key + k1].x,
+ curve_keys[first_key + k1].y,
+ curve_keys[first_key + k1].z,
+ curve_radius[first_key + k1]);
+ }
+ else {
+ /* Center step is not stored in this array. */
+ if (step > center_step) {
+ step--;
+ }
+ const size_t offset = first_key + step * num_curve_keys;
+ r_keys[0] = make_float4(key_steps[offset + k0].x,
+ key_steps[offset + k0].y,
+ key_steps[offset + k0].z,
+ curve_radius[first_key + k0]);
+ r_keys[1] = make_float4(key_steps[offset + k1].x,
+ key_steps[offset + k1].y,
+ key_steps[offset + k1].z,
+ curve_radius[first_key + k1]);
+ }
+}
+
+void Hair::Curve::cardinal_keys_for_step(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ size_t step,
+ size_t k0,
+ size_t k1,
+ size_t k2,
+ size_t k3,
+ float4 r_keys[4]) const
+{
+ k0 = max(k0, 0);
+ k3 = min(k3, num_keys - 1);
+ const size_t center_step = ((num_steps - 1) / 2);
+ if (step == center_step) {
+ /* Center step: regular key location. */
+ r_keys[0] = make_float4(curve_keys[first_key + k0].x,
+ curve_keys[first_key + k0].y,
+ curve_keys[first_key + k0].z,
+ curve_radius[first_key + k0]);
+ r_keys[1] = make_float4(curve_keys[first_key + k1].x,
+ curve_keys[first_key + k1].y,
+ curve_keys[first_key + k1].z,
+ curve_radius[first_key + k1]);
+ r_keys[2] = make_float4(curve_keys[first_key + k2].x,
+ curve_keys[first_key + k2].y,
+ curve_keys[first_key + k2].z,
+ curve_radius[first_key + k2]);
+ r_keys[3] = make_float4(curve_keys[first_key + k3].x,
+ curve_keys[first_key + k3].y,
+ curve_keys[first_key + k3].z,
+ curve_radius[first_key + k3]);
+ }
+ else {
+ /* Center step is not stored in this array. */
+ if (step > center_step) {
+ step--;
+ }
+ const size_t offset = first_key + step * num_curve_keys;
+ r_keys[0] = make_float4(key_steps[offset + k0].x,
+ key_steps[offset + k0].y,
+ key_steps[offset + k0].z,
+ curve_radius[first_key + k0]);
+ r_keys[1] = make_float4(key_steps[offset + k1].x,
+ key_steps[offset + k1].y,
+ key_steps[offset + k1].z,
+ curve_radius[first_key + k1]);
+ r_keys[2] = make_float4(key_steps[offset + k2].x,
+ key_steps[offset + k2].y,
+ key_steps[offset + k2].z,
+ curve_radius[first_key + k2]);
+ r_keys[3] = make_float4(key_steps[offset + k3].x,
+ key_steps[offset + k3].y,
+ key_steps[offset + k3].z,
+ curve_radius[first_key + k3]);
+ }
+}
+
+/* Hair */
+
+NODE_DEFINE(Hair)
+{
+ NodeType *type = NodeType::add("hair", create, NodeType::NONE, Geometry::get_node_base_type());
+
+ SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>());
+ SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>());
+ SOCKET_INT_ARRAY(curve_first_key, "Curve First Key", array<int>());
+ SOCKET_INT_ARRAY(curve_shader, "Curve Shader", array<int>());
+
+ return type;
+}
+
+Hair::Hair() : Geometry(get_node_type(), Geometry::HAIR)
+{
+ curve_key_offset = 0;
+ curve_segment_offset = 0;
+ curve_shape = CURVE_RIBBON;
+}
+
+Hair::~Hair()
+{
+}
+
+void Hair::resize_curves(int numcurves, int numkeys)
+{
+ curve_keys.resize(numkeys);
+ curve_radius.resize(numkeys);
+ curve_first_key.resize(numcurves);
+ curve_shader.resize(numcurves);
+
+ attributes.resize();
+}
+
+void Hair::reserve_curves(int numcurves, int numkeys)
+{
+ curve_keys.reserve(numkeys);
+ curve_radius.reserve(numkeys);
+ curve_first_key.reserve(numcurves);
+ curve_shader.reserve(numcurves);
+
+ attributes.resize(true);
+}
+
+void Hair::clear(bool preserve_shaders)
+{
+ Geometry::clear(preserve_shaders);
+
+ curve_keys.clear();
+ curve_radius.clear();
+ curve_first_key.clear();
+ curve_shader.clear();
+
+ attributes.clear();
+}
+
+void Hair::add_curve_key(float3 co, float radius)
+{
+ curve_keys.push_back_reserved(co);
+ curve_radius.push_back_reserved(radius);
+
+ tag_curve_keys_modified();
+ tag_curve_radius_modified();
+}
+
+void Hair::add_curve(int first_key, int shader)
+{
+ curve_first_key.push_back_reserved(first_key);
+ curve_shader.push_back_reserved(shader);
+
+ tag_curve_first_key_modified();
+ tag_curve_shader_modified();
+}
+
+void Hair::copy_center_to_motion_step(const int motion_step)
+{
+ Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ float3 *keys = &curve_keys[0];
+ size_t numkeys = curve_keys.size();
+ memcpy(attr_mP->data_float3() + motion_step * numkeys, keys, sizeof(float3) * numkeys);
+ }
+}
+
+void Hair::get_uv_tiles(ustring map, unordered_set<int> &tiles)
+{
+ Attribute *attr;
+
+ if (map.empty()) {
+ attr = attributes.find(ATTR_STD_UV);
+ }
+ else {
+ attr = attributes.find(map);
+ }
+
+ if (attr) {
+ attr->get_uv_tiles(this, ATTR_PRIM_GEOMETRY, tiles);
+ }
+}
+
+void Hair::compute_bounds()
+{
+ BoundBox bnds = BoundBox::empty;
+ size_t curve_keys_size = curve_keys.size();
+
+ if (curve_keys_size > 0) {
+ for (size_t i = 0; i < curve_keys_size; i++)
+ bnds.grow(curve_keys[i], curve_radius[i]);
+
+ Attribute *curve_attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (use_motion_blur && curve_attr) {
+ size_t steps_size = curve_keys.size() * (motion_steps - 1);
+ float3 *key_steps = curve_attr->data_float3();
+
+ for (size_t i = 0; i < steps_size; i++)
+ bnds.grow(key_steps[i]);
+ }
+
+ if (!bnds.valid()) {
+ bnds = BoundBox::empty;
+
+ /* skip nan or inf coordinates */
+ for (size_t i = 0; i < curve_keys_size; i++)
+ bnds.grow_safe(curve_keys[i], curve_radius[i]);
+
+ if (use_motion_blur && curve_attr) {
+ size_t steps_size = curve_keys.size() * (motion_steps - 1);
+ float3 *key_steps = curve_attr->data_float3();
+
+ for (size_t i = 0; i < steps_size; i++)
+ bnds.grow_safe(key_steps[i]);
+ }
+ }
+ }
+
+ if (!bnds.valid()) {
+ /* empty mesh */
+ bnds.grow(zero_float3());
+ }
+
+ bounds = bnds;
+}
+
+void Hair::apply_transform(const Transform &tfm, const bool apply_to_motion)
+{
+ /* compute uniform scale */
+ float3 c0 = transform_get_column(&tfm, 0);
+ float3 c1 = transform_get_column(&tfm, 1);
+ float3 c2 = transform_get_column(&tfm, 2);
+ float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f / 3.0f);
+
+ /* apply transform to curve keys */
+ for (size_t i = 0; i < curve_keys.size(); i++) {
+ float3 co = transform_point(&tfm, curve_keys[i]);
+ float radius = curve_radius[i] * scalar;
+
+ /* scale for curve radius is only correct for uniform scale */
+ curve_keys[i] = co;
+ curve_radius[i] = radius;
+ }
+
+ tag_curve_keys_modified();
+ tag_curve_radius_modified();
+
+ if (apply_to_motion) {
+ Attribute *curve_attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (curve_attr) {
+ /* apply transform to motion curve keys */
+ size_t steps_size = curve_keys.size() * (motion_steps - 1);
+ float4 *key_steps = curve_attr->data_float4();
+
+ for (size_t i = 0; i < steps_size; i++) {
+ float3 co = transform_point(&tfm, float4_to_float3(key_steps[i]));
+ float radius = key_steps[i].w * scalar;
+
+ /* scale for curve radius is only correct for uniform scale */
+ key_steps[i] = float3_to_float4(co);
+ key_steps[i].w = radius;
+ }
+ }
+ }
+}
+
+void Hair::pack_curves(Scene *scene,
+ float4 *curve_key_co,
+ KernelCurve *curves,
+ KernelCurveSegment *curve_segments)
+{
+ size_t curve_keys_size = curve_keys.size();
+
+ /* pack curve keys */
+ if (curve_keys_size) {
+ float3 *keys_ptr = curve_keys.data();
+ float *radius_ptr = curve_radius.data();
+
+ for (size_t i = 0; i < curve_keys_size; i++)
+ curve_key_co[i] = make_float4(keys_ptr[i].x, keys_ptr[i].y, keys_ptr[i].z, radius_ptr[i]);
+ }
+
+ /* pack curve segments */
+ const PrimitiveType type = primitive_type();
+
+ size_t curve_num = num_curves();
+ size_t index = 0;
+
+ for (size_t i = 0; i < curve_num; i++) {
+ Curve curve = get_curve(i);
+ int shader_id = curve_shader[i];
+ Shader *shader = (shader_id < used_shaders.size()) ?
+ static_cast<Shader *>(used_shaders[shader_id]) :
+ scene->default_surface;
+ shader_id = scene->shader_manager->get_shader_id(shader, false);
+
+ curves[i].shader_id = shader_id;
+ curves[i].first_key = curve_key_offset + curve.first_key;
+ curves[i].num_keys = curve.num_keys;
+ curves[i].type = type;
+
+ for (int k = 0; k < curve.num_segments(); ++k, ++index) {
+ curve_segments[index].prim = prim_offset + i;
+ curve_segments[index].type = PRIMITIVE_PACK_SEGMENT(type, k);
+ }
+ }
+}
+
+PrimitiveType Hair::primitive_type() const
+{
+ return has_motion_blur() ?
+ ((curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
+ PRIMITIVE_MOTION_CURVE_THICK) :
+ ((curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK);
+}
+
+/* Fill in coordinates for curve transparency shader evaluation on device. */
+static int fill_shader_input(const Hair *hair,
+ const int object_index,
+ device_vector<KernelShaderEvalInput> &d_input)
+{
+ int d_input_size = 0;
+ KernelShaderEvalInput *d_input_data = d_input.data();
+
+ const int num_curves = hair->num_curves();
+ for (int i = 0; i < num_curves; i++) {
+ const Hair::Curve curve = hair->get_curve(i);
+ const int num_segments = curve.num_segments();
+
+ for (int j = 0; j < num_segments + 1; j++) {
+ KernelShaderEvalInput in;
+ in.object = object_index;
+ in.prim = hair->prim_offset + i;
+ in.u = (j < num_segments) ? 0.0f : 1.0f;
+ in.v = (j < num_segments) ? __int_as_float(j) : __int_as_float(j - 1);
+ d_input_data[d_input_size++] = in;
+ }
+ }
+
+ return d_input_size;
+}
+
+/* Read back curve transparency shader output. */
+static void read_shader_output(float *shadow_transparency,
+ bool &is_fully_opaque,
+ const device_vector<float> &d_output)
+{
+ const int num_keys = d_output.size();
+ const float *output_data = d_output.data();
+ bool is_opaque = true;
+
+ for (int i = 0; i < num_keys; i++) {
+ shadow_transparency[i] = output_data[i];
+ if (shadow_transparency[i] > 0.0f) {
+ is_opaque = false;
+ }
+ }
+
+ is_fully_opaque = is_opaque;
+}
+
+bool Hair::need_shadow_transparency()
+{
+ for (const Node *node : used_shaders) {
+ const Shader *shader = static_cast<const Shader *>(node);
+ if (shader->has_surface_transparent && shader->get_use_transparent_shadow()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Hair::update_shadow_transparency(Device *device, Scene *scene, Progress &progress)
+{
+ if (!need_shadow_transparency()) {
+ /* If no shaders with shadow transparency, remove attribute. */
+ Attribute *attr = attributes.find(ATTR_STD_SHADOW_TRANSPARENCY);
+ if (attr) {
+ attributes.remove(attr);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ string msg = string_printf("Computing Shadow Transparency %s", name.c_str());
+ progress.set_status("Updating Hair", msg);
+
+ /* Create shadow transparency attribute. */
+ Attribute *attr = attributes.find(ATTR_STD_SHADOW_TRANSPARENCY);
+ const bool attribute_exists = (attr != nullptr);
+ if (!attribute_exists) {
+ attr = attributes.add(ATTR_STD_SHADOW_TRANSPARENCY);
+ }
+
+ float *attr_data = attr->data_float();
+
+ /* Find object index. */
+ size_t object_index = OBJECT_NONE;
+
+ for (size_t i = 0; i < scene->objects.size(); i++) {
+ if (scene->objects[i]->get_geometry() == this) {
+ object_index = i;
+ break;
+ }
+ }
+
+ /* Evaluate shader on device. */
+ ShaderEval shader_eval(device, progress);
+ bool is_fully_opaque = false;
+ shader_eval.eval(SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY,
+ num_keys(),
+ 1,
+ function_bind(&fill_shader_input, this, object_index, _1),
+ function_bind(&read_shader_output, attr_data, is_fully_opaque, _1));
+
+ if (is_fully_opaque) {
+ attributes.remove(attr);
+ return attribute_exists;
+ }
+
+ return true;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/hair.h b/intern/cycles/scene/hair.h
new file mode 100644
index 00000000000..832015058fe
--- /dev/null
+++ b/intern/cycles/scene/hair.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __HAIR_H__
+#define __HAIR_H__
+
+#include "scene/geometry.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct KernelCurveSegment;
+
+class Hair : public Geometry {
+ public:
+ NODE_DECLARE
+
+ /* Hair Curve */
+ struct Curve {
+ int first_key;
+ int num_keys;
+
+ int num_segments() const
+ {
+ return num_keys - 1;
+ }
+
+ void bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ BoundBox &bounds) const;
+ void bounds_grow(float4 keys[4], BoundBox &bounds) const;
+ void bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ const Transform &aligned_space,
+ BoundBox &bounds) const;
+
+ void motion_keys(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ float time,
+ size_t k0,
+ size_t k1,
+ float4 r_keys[2]) const;
+ void cardinal_motion_keys(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ float time,
+ size_t k0,
+ size_t k1,
+ size_t k2,
+ size_t k3,
+ float4 r_keys[4]) const;
+
+ void keys_for_step(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ size_t step,
+ size_t k0,
+ size_t k1,
+ float4 r_keys[2]) const;
+ void cardinal_keys_for_step(const float3 *curve_keys,
+ const float *curve_radius,
+ const float3 *key_steps,
+ size_t num_curve_keys,
+ size_t num_steps,
+ size_t step,
+ size_t k0,
+ size_t k1,
+ size_t k2,
+ size_t k3,
+ float4 r_keys[4]) const;
+ };
+
+ NODE_SOCKET_API_ARRAY(array<float3>, curve_keys)
+ NODE_SOCKET_API_ARRAY(array<float>, curve_radius)
+ NODE_SOCKET_API_ARRAY(array<int>, curve_first_key)
+ NODE_SOCKET_API_ARRAY(array<int>, curve_shader)
+
+ /* BVH */
+ size_t curve_key_offset;
+ size_t curve_segment_offset;
+ CurveShapeType curve_shape;
+
+ /* Constructor/Destructor */
+ Hair();
+ ~Hair();
+
+ /* Geometry */
+ void clear(bool preserve_shaders = false) override;
+
+ void resize_curves(int numcurves, int numkeys);
+ void reserve_curves(int numcurves, int numkeys);
+ void add_curve_key(float3 loc, float radius);
+ void add_curve(int first_key, int shader);
+
+ void copy_center_to_motion_step(const int motion_step);
+
+ void compute_bounds() override;
+ void apply_transform(const Transform &tfm, const bool apply_to_motion) override;
+
+ /* Curves */
+ Curve get_curve(size_t i) const
+ {
+ int first = curve_first_key[i];
+ int next_first = (i + 1 < curve_first_key.size()) ? curve_first_key[i + 1] : curve_keys.size();
+
+ Curve curve = {first, next_first - first};
+ return curve;
+ }
+
+ size_t num_keys() const
+ {
+ return curve_keys.size();
+ }
+
+ size_t num_curves() const
+ {
+ return curve_first_key.size();
+ }
+
+ size_t num_segments() const
+ {
+ return curve_keys.size() - curve_first_key.size();
+ }
+
+ /* UDIM */
+ void get_uv_tiles(ustring map, unordered_set<int> &tiles) override;
+
+ /* BVH */
+ void pack_curves(Scene *scene,
+ float4 *curve_key_co,
+ KernelCurve *curve,
+ KernelCurveSegment *curve_segments);
+
+ PrimitiveType primitive_type() const override;
+
+ /* Attributes */
+ bool need_shadow_transparency();
+ bool update_shadow_transparency(Device *device, Scene *scene, Progress &progress);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __HAIR_H__ */
diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp
new file mode 100644
index 00000000000..80091e01b8c
--- /dev/null
+++ b/intern/cycles/scene/image.cpp
@@ -0,0 +1,905 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/image.h"
+#include "device/device.h"
+#include "scene/colorspace.h"
+#include "scene/image_oiio.h"
+#include "scene/image_vdb.h"
+#include "scene/scene.h"
+#include "scene/stats.h"
+
+#include "util/foreach.h"
+#include "util/image.h"
+#include "util/image_impl.h"
+#include "util/log.h"
+#include "util/path.h"
+#include "util/progress.h"
+#include "util/task.h"
+#include "util/texture.h"
+#include "util/unique_ptr.h"
+
+#ifdef WITH_OSL
+# include <OSL/oslexec.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+namespace {
+
+/* Some helpers to silence warning in templated function. */
+bool isfinite(uchar /*value*/)
+{
+ return true;
+}
+bool isfinite(half /*value*/)
+{
+ return true;
+}
+bool isfinite(uint16_t /*value*/)
+{
+ return true;
+}
+
+const char *name_from_type(ImageDataType type)
+{
+ switch (type) {
+ case IMAGE_DATA_TYPE_FLOAT4:
+ return "float4";
+ case IMAGE_DATA_TYPE_BYTE4:
+ return "byte4";
+ case IMAGE_DATA_TYPE_HALF4:
+ return "half4";
+ case IMAGE_DATA_TYPE_FLOAT:
+ return "float";
+ case IMAGE_DATA_TYPE_BYTE:
+ return "byte";
+ case IMAGE_DATA_TYPE_HALF:
+ return "half";
+ case IMAGE_DATA_TYPE_USHORT4:
+ return "ushort4";
+ case IMAGE_DATA_TYPE_USHORT:
+ return "ushort";
+ case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
+ return "nanovdb_float";
+ case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
+ return "nanovdb_float3";
+ case IMAGE_DATA_NUM_TYPES:
+ assert(!"System enumerator type, should never be used");
+ return "";
+ }
+ assert(!"Unhandled image data type");
+ return "";
+}
+
+} // namespace
+
+/* Image Handle */
+
+ImageHandle::ImageHandle() : manager(NULL)
+{
+}
+
+ImageHandle::ImageHandle(const ImageHandle &other)
+ : tile_slots(other.tile_slots), manager(other.manager)
+{
+ /* Increase image user count. */
+ foreach (const int slot, tile_slots) {
+ manager->add_image_user(slot);
+ }
+}
+
+ImageHandle &ImageHandle::operator=(const ImageHandle &other)
+{
+ clear();
+ manager = other.manager;
+ tile_slots = other.tile_slots;
+
+ foreach (const int slot, tile_slots) {
+ manager->add_image_user(slot);
+ }
+
+ return *this;
+}
+
+ImageHandle::~ImageHandle()
+{
+ clear();
+}
+
+void ImageHandle::clear()
+{
+ foreach (const int slot, tile_slots) {
+ manager->remove_image_user(slot);
+ }
+
+ tile_slots.clear();
+ manager = NULL;
+}
+
+bool ImageHandle::empty()
+{
+ return tile_slots.empty();
+}
+
+int ImageHandle::num_tiles()
+{
+ return tile_slots.size();
+}
+
+ImageMetaData ImageHandle::metadata()
+{
+ if (tile_slots.empty()) {
+ return ImageMetaData();
+ }
+
+ ImageManager::Image *img = manager->images[tile_slots.front()];
+ manager->load_image_metadata(img);
+ return img->metadata;
+}
+
+int ImageHandle::svm_slot(const int tile_index) const
+{
+ if (tile_index >= tile_slots.size()) {
+ return -1;
+ }
+
+ if (manager->osl_texture_system) {
+ ImageManager::Image *img = manager->images[tile_slots[tile_index]];
+ if (!img->loader->osl_filepath().empty()) {
+ return -1;
+ }
+ }
+
+ return tile_slots[tile_index];
+}
+
+device_texture *ImageHandle::image_memory(const int tile_index) const
+{
+ if (tile_index >= tile_slots.size()) {
+ return NULL;
+ }
+
+ ImageManager::Image *img = manager->images[tile_slots[tile_index]];
+ return img ? img->mem : NULL;
+}
+
+VDBImageLoader *ImageHandle::vdb_loader(const int tile_index) const
+{
+ if (tile_index >= tile_slots.size()) {
+ return NULL;
+ }
+
+ ImageManager::Image *img = manager->images[tile_slots[tile_index]];
+
+ if (img == NULL) {
+ return NULL;
+ }
+
+ ImageLoader *loader = img->loader;
+
+ if (loader == NULL) {
+ return NULL;
+ }
+
+ if (loader->is_vdb_loader()) {
+ return dynamic_cast<VDBImageLoader *>(loader);
+ }
+
+ return NULL;
+}
+
+bool ImageHandle::operator==(const ImageHandle &other) const
+{
+ return manager == other.manager && tile_slots == other.tile_slots;
+}
+
+/* Image MetaData */
+
+ImageMetaData::ImageMetaData()
+ : channels(0),
+ width(0),
+ height(0),
+ depth(0),
+ byte_size(0),
+ type(IMAGE_DATA_NUM_TYPES),
+ colorspace(u_colorspace_raw),
+ colorspace_file_format(""),
+ use_transform_3d(false),
+ compress_as_srgb(false)
+{
+}
+
+bool ImageMetaData::operator==(const ImageMetaData &other) const
+{
+ return channels == other.channels && width == other.width && height == other.height &&
+ depth == other.depth && use_transform_3d == other.use_transform_3d &&
+ (!use_transform_3d || transform_3d == other.transform_3d) && type == other.type &&
+ colorspace == other.colorspace && compress_as_srgb == other.compress_as_srgb;
+}
+
+bool ImageMetaData::is_float() const
+{
+ return (type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4 ||
+ type == IMAGE_DATA_TYPE_HALF || type == IMAGE_DATA_TYPE_HALF4);
+}
+
+void ImageMetaData::detect_colorspace()
+{
+ /* Convert used specified color spaces to one we know how to handle. */
+ colorspace = ColorSpaceManager::detect_known_colorspace(
+ colorspace, colorspace_file_format, is_float());
+
+ if (colorspace == u_colorspace_raw) {
+ /* Nothing to do. */
+ }
+ else if (colorspace == u_colorspace_srgb) {
+ /* Keep sRGB colorspace stored as sRGB, to save memory and/or loading time
+ * for the common case of 8bit sRGB images like PNG. */
+ compress_as_srgb = true;
+ }
+ else {
+ /* Always compress non-raw 8bit images as scene linear + sRGB, as a
+ * heuristic to keep memory usage the same without too much data loss
+ * due to quantization in common cases. */
+ compress_as_srgb = (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_BYTE4);
+
+ /* If colorspace conversion needed, use half instead of short so we can
+ * represent HDR values that might result from conversion. */
+ if (type == IMAGE_DATA_TYPE_USHORT) {
+ type = IMAGE_DATA_TYPE_HALF;
+ }
+ else if (type == IMAGE_DATA_TYPE_USHORT4) {
+ type = IMAGE_DATA_TYPE_HALF4;
+ }
+ }
+}
+
+/* Image Loader */
+
+ImageLoader::ImageLoader()
+{
+}
+
+ustring ImageLoader::osl_filepath() const
+{
+ return ustring();
+}
+
+bool ImageLoader::equals(const ImageLoader *a, const ImageLoader *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+ else {
+ return (a && b && typeid(*a) == typeid(*b) && a->equals(*b));
+ }
+}
+
+bool ImageLoader::is_vdb_loader() const
+{
+ return false;
+}
+
+/* Image Manager */
+
+ImageManager::ImageManager(const DeviceInfo &info)
+{
+ need_update_ = true;
+ osl_texture_system = NULL;
+ animation_frame = 0;
+
+ /* Set image limits */
+ features.has_half_float = info.has_half_images;
+ features.has_nanovdb = info.has_nanovdb;
+}
+
+ImageManager::~ImageManager()
+{
+ for (size_t slot = 0; slot < images.size(); slot++)
+ assert(!images[slot]);
+}
+
+void ImageManager::set_osl_texture_system(void *texture_system)
+{
+ osl_texture_system = texture_system;
+}
+
+bool ImageManager::set_animation_frame_update(int frame)
+{
+ if (frame != animation_frame) {
+ thread_scoped_lock device_lock(images_mutex);
+ animation_frame = frame;
+
+ for (size_t slot = 0; slot < images.size(); slot++) {
+ if (images[slot] && images[slot]->params.animated)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ImageManager::load_image_metadata(Image *img)
+{
+ if (!img->need_metadata) {
+ return;
+ }
+
+ thread_scoped_lock image_lock(img->mutex);
+ if (!img->need_metadata) {
+ return;
+ }
+
+ ImageMetaData &metadata = img->metadata;
+ metadata = ImageMetaData();
+ metadata.colorspace = img->params.colorspace;
+
+ if (img->loader->load_metadata(features, metadata)) {
+ assert(metadata.type != IMAGE_DATA_NUM_TYPES);
+ }
+ else {
+ metadata.type = IMAGE_DATA_TYPE_BYTE4;
+ }
+
+ metadata.detect_colorspace();
+
+ assert(features.has_half_float ||
+ (metadata.type != IMAGE_DATA_TYPE_HALF4 && metadata.type != IMAGE_DATA_TYPE_HALF));
+ assert(features.has_nanovdb || (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT ||
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3));
+
+ img->need_metadata = false;
+}
+
+ImageHandle ImageManager::add_image(const string &filename, const ImageParams &params)
+{
+ const int slot = add_image_slot(new OIIOImageLoader(filename), params, false);
+
+ ImageHandle handle;
+ handle.tile_slots.push_back(slot);
+ handle.manager = this;
+ return handle;
+}
+
+ImageHandle ImageManager::add_image(const string &filename,
+ const ImageParams &params,
+ const array<int> &tiles)
+{
+ ImageHandle handle;
+ handle.manager = this;
+
+ foreach (int tile, tiles) {
+ string tile_filename = filename;
+ if (tile != 0) {
+ string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile));
+ }
+ const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false);
+ handle.tile_slots.push_back(slot);
+ }
+
+ return handle;
+}
+
+ImageHandle ImageManager::add_image(ImageLoader *loader,
+ const ImageParams &params,
+ const bool builtin)
+{
+ const int slot = add_image_slot(loader, params, builtin);
+
+ ImageHandle handle;
+ handle.tile_slots.push_back(slot);
+ handle.manager = this;
+ return handle;
+}
+
+int ImageManager::add_image_slot(ImageLoader *loader,
+ const ImageParams &params,
+ const bool builtin)
+{
+ Image *img;
+ size_t slot;
+
+ thread_scoped_lock device_lock(images_mutex);
+
+ /* Find existing image. */
+ for (slot = 0; slot < images.size(); slot++) {
+ img = images[slot];
+ if (img && ImageLoader::equals(img->loader, loader) && img->params == params) {
+ img->users++;
+ delete loader;
+ return slot;
+ }
+ }
+
+ /* Find free slot. */
+ for (slot = 0; slot < images.size(); slot++) {
+ if (!images[slot])
+ break;
+ }
+
+ if (slot == images.size()) {
+ images.resize(images.size() + 1);
+ }
+
+ /* Add new image. */
+ img = new Image();
+ img->params = params;
+ img->loader = loader;
+ img->need_metadata = true;
+ img->need_load = !(osl_texture_system && !img->loader->osl_filepath().empty());
+ img->builtin = builtin;
+ img->users = 1;
+ img->mem = NULL;
+
+ images[slot] = img;
+
+ need_update_ = true;
+
+ return slot;
+}
+
+void ImageManager::add_image_user(int slot)
+{
+ thread_scoped_lock device_lock(images_mutex);
+ Image *image = images[slot];
+ assert(image && image->users >= 1);
+
+ image->users++;
+}
+
+void ImageManager::remove_image_user(int slot)
+{
+ thread_scoped_lock device_lock(images_mutex);
+ Image *image = images[slot];
+ assert(image && image->users >= 1);
+
+ /* decrement user count */
+ image->users--;
+
+ /* don't remove immediately, rather do it all together later on. one of
+ * the reasons for this is that on shader changes we add and remove nodes
+ * that use them, but we do not want to reload the image all the time. */
+ if (image->users == 0)
+ need_update_ = true;
+}
+
+static bool image_associate_alpha(ImageManager::Image *img)
+{
+ /* For typical RGBA images we let OIIO convert to associated alpha,
+ * but some types we want to leave the RGB channels untouched. */
+ return !(ColorSpaceManager::colorspace_is_data(img->params.colorspace) ||
+ img->params.alpha_type == IMAGE_ALPHA_IGNORE ||
+ img->params.alpha_type == IMAGE_ALPHA_CHANNEL_PACKED);
+}
+
+template<TypeDesc::BASETYPE FileFormat, typename StorageType>
+bool ImageManager::file_load_image(Image *img, int texture_limit)
+{
+ /* Ignore empty images. */
+ if (!(img->metadata.channels > 0)) {
+ return false;
+ }
+
+ /* Get metadata. */
+ int width = img->metadata.width;
+ int height = img->metadata.height;
+ int depth = img->metadata.depth;
+ int components = img->metadata.channels;
+
+ /* Read pixels. */
+ vector<StorageType> pixels_storage;
+ StorageType *pixels;
+ const size_t max_size = max(max(width, height), depth);
+ if (max_size == 0) {
+ /* Don't bother with empty images. */
+ return false;
+ }
+
+ /* Allocate memory as needed, may be smaller to resize down. */
+ if (texture_limit > 0 && max_size > texture_limit) {
+ pixels_storage.resize(((size_t)width) * height * depth * 4);
+ pixels = &pixels_storage[0];
+ }
+ else {
+ thread_scoped_lock device_lock(device_mutex);
+ pixels = (StorageType *)img->mem->alloc(width, height, depth);
+ }
+
+ if (pixels == NULL) {
+ /* Could be that we've run out of memory. */
+ return false;
+ }
+
+ const size_t num_pixels = ((size_t)width) * height * depth;
+ img->loader->load_pixels(
+ img->metadata, pixels, num_pixels * components, image_associate_alpha(img));
+
+ /* The kernel can handle 1 and 4 channel images. Anything that is not a single
+ * channel image is converted to RGBA format. */
+ bool is_rgba = (img->metadata.type == IMAGE_DATA_TYPE_FLOAT4 ||
+ img->metadata.type == IMAGE_DATA_TYPE_HALF4 ||
+ img->metadata.type == IMAGE_DATA_TYPE_BYTE4 ||
+ img->metadata.type == IMAGE_DATA_TYPE_USHORT4);
+
+ if (is_rgba) {
+ const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
+
+ if (components == 2) {
+ /* Grayscale + alpha to RGBA. */
+ for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i * 4 + 3] = pixels[i * 2 + 1];
+ pixels[i * 4 + 2] = pixels[i * 2 + 0];
+ pixels[i * 4 + 1] = pixels[i * 2 + 0];
+ pixels[i * 4 + 0] = pixels[i * 2 + 0];
+ }
+ }
+ else if (components == 3) {
+ /* RGB to RGBA. */
+ for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i * 4 + 3] = one;
+ pixels[i * 4 + 2] = pixels[i * 3 + 2];
+ pixels[i * 4 + 1] = pixels[i * 3 + 1];
+ pixels[i * 4 + 0] = pixels[i * 3 + 0];
+ }
+ }
+ else if (components == 1) {
+ /* Grayscale to RGBA. */
+ for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i * 4 + 3] = one;
+ pixels[i * 4 + 2] = pixels[i];
+ pixels[i * 4 + 1] = pixels[i];
+ pixels[i * 4 + 0] = pixels[i];
+ }
+ }
+
+ /* Disable alpha if requested by the user. */
+ if (img->params.alpha_type == IMAGE_ALPHA_IGNORE) {
+ for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i * 4 + 3] = one;
+ }
+ }
+
+ if (img->metadata.colorspace != u_colorspace_raw &&
+ img->metadata.colorspace != u_colorspace_srgb) {
+ /* Convert to scene linear. */
+ ColorSpaceManager::to_scene_linear(
+ img->metadata.colorspace, pixels, num_pixels, img->metadata.compress_as_srgb);
+ }
+ }
+
+ /* Make sure we don't have buggy values. */
+ if (FileFormat == TypeDesc::FLOAT) {
+ /* For RGBA buffers we put all channels to 0 if either of them is not
+ * finite. This way we avoid possible artifacts caused by fully changed
+ * hue. */
+ if (is_rgba) {
+ for (size_t i = 0; i < num_pixels; i += 4) {
+ StorageType *pixel = &pixels[i * 4];
+ if (!isfinite(pixel[0]) || !isfinite(pixel[1]) || !isfinite(pixel[2]) ||
+ !isfinite(pixel[3])) {
+ pixel[0] = 0;
+ pixel[1] = 0;
+ pixel[2] = 0;
+ pixel[3] = 0;
+ }
+ }
+ }
+ else {
+ for (size_t i = 0; i < num_pixels; ++i) {
+ StorageType *pixel = &pixels[i];
+ if (!isfinite(pixel[0])) {
+ pixel[0] = 0;
+ }
+ }
+ }
+ }
+
+ /* Scale image down if needed. */
+ if (pixels_storage.size() > 0) {
+ float scale_factor = 1.0f;
+ while (max_size * scale_factor > texture_limit) {
+ scale_factor *= 0.5f;
+ }
+ VLOG(1) << "Scaling image " << img->loader->name() << " by a factor of " << scale_factor
+ << ".";
+ vector<StorageType> scaled_pixels;
+ size_t scaled_width, scaled_height, scaled_depth;
+ util_image_resize_pixels(pixels_storage,
+ width,
+ height,
+ depth,
+ is_rgba ? 4 : 1,
+ scale_factor,
+ &scaled_pixels,
+ &scaled_width,
+ &scaled_height,
+ &scaled_depth);
+
+ StorageType *texture_pixels;
+
+ {
+ thread_scoped_lock device_lock(device_mutex);
+ texture_pixels = (StorageType *)img->mem->alloc(scaled_width, scaled_height, scaled_depth);
+ }
+
+ memcpy(texture_pixels, &scaled_pixels[0], scaled_pixels.size() * sizeof(StorageType));
+ }
+
+ return true;
+}
+
+void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Progress *progress)
+{
+ if (progress->get_cancel()) {
+ return;
+ }
+
+ Image *img = images[slot];
+
+ progress->set_status("Updating Images", "Loading " + img->loader->name());
+
+ const int texture_limit = scene->params.texture_limit;
+
+ load_image_metadata(img);
+ ImageDataType type = img->metadata.type;
+
+ /* Name for debugging. */
+ img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type), slot);
+
+ /* Free previous texture in slot. */
+ if (img->mem) {
+ thread_scoped_lock device_lock(device_mutex);
+ delete img->mem;
+ img->mem = NULL;
+ }
+
+ img->mem = new device_texture(
+ device, img->mem_name.c_str(), slot, type, img->params.interpolation, img->params.extension);
+ img->mem->info.use_transform_3d = img->metadata.use_transform_3d;
+ img->mem->info.transform_3d = img->metadata.transform_3d;
+
+ /* Create new texture. */
+ if (type == IMAGE_DATA_TYPE_FLOAT4) {
+ if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ thread_scoped_lock device_lock(device_mutex);
+ float *pixels = (float *)img->mem->alloc(1, 1);
+
+ pixels[0] = TEX_IMAGE_MISSING_R;
+ pixels[1] = TEX_IMAGE_MISSING_G;
+ pixels[2] = TEX_IMAGE_MISSING_B;
+ pixels[3] = TEX_IMAGE_MISSING_A;
+ }
+ }
+ else if (type == IMAGE_DATA_TYPE_FLOAT) {
+ if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ thread_scoped_lock device_lock(device_mutex);
+ float *pixels = (float *)img->mem->alloc(1, 1);
+
+ pixels[0] = TEX_IMAGE_MISSING_R;
+ }
+ }
+ else if (type == IMAGE_DATA_TYPE_BYTE4) {
+ if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ thread_scoped_lock device_lock(device_mutex);
+ uchar *pixels = (uchar *)img->mem->alloc(1, 1);
+
+ pixels[0] = (TEX_IMAGE_MISSING_R * 255);
+ pixels[1] = (TEX_IMAGE_MISSING_G * 255);
+ pixels[2] = (TEX_IMAGE_MISSING_B * 255);
+ pixels[3] = (TEX_IMAGE_MISSING_A * 255);
+ }
+ }
+ else if (type == IMAGE_DATA_TYPE_BYTE) {
+ if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ thread_scoped_lock device_lock(device_mutex);
+ uchar *pixels = (uchar *)img->mem->alloc(1, 1);
+
+ pixels[0] = (TEX_IMAGE_MISSING_R * 255);
+ }
+ }
+ else if (type == IMAGE_DATA_TYPE_HALF4) {
+ if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ thread_scoped_lock device_lock(device_mutex);
+ half *pixels = (half *)img->mem->alloc(1, 1);
+
+ pixels[0] = TEX_IMAGE_MISSING_R;
+ pixels[1] = TEX_IMAGE_MISSING_G;
+ pixels[2] = TEX_IMAGE_MISSING_B;
+ pixels[3] = TEX_IMAGE_MISSING_A;
+ }
+ }
+ else if (type == IMAGE_DATA_TYPE_USHORT) {
+ if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ thread_scoped_lock device_lock(device_mutex);
+ uint16_t *pixels = (uint16_t *)img->mem->alloc(1, 1);
+
+ pixels[0] = (TEX_IMAGE_MISSING_R * 65535);
+ }
+ }
+ else if (type == IMAGE_DATA_TYPE_USHORT4) {
+ if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ thread_scoped_lock device_lock(device_mutex);
+ uint16_t *pixels = (uint16_t *)img->mem->alloc(1, 1);
+
+ pixels[0] = (TEX_IMAGE_MISSING_R * 65535);
+ pixels[1] = (TEX_IMAGE_MISSING_G * 65535);
+ pixels[2] = (TEX_IMAGE_MISSING_B * 65535);
+ pixels[3] = (TEX_IMAGE_MISSING_A * 65535);
+ }
+ }
+ else if (type == IMAGE_DATA_TYPE_HALF) {
+ if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ thread_scoped_lock device_lock(device_mutex);
+ half *pixels = (half *)img->mem->alloc(1, 1);
+
+ pixels[0] = TEX_IMAGE_MISSING_R;
+ }
+ }
+#ifdef WITH_NANOVDB
+ else if (type == IMAGE_DATA_TYPE_NANOVDB_FLOAT || type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
+ thread_scoped_lock device_lock(device_mutex);
+ void *pixels = img->mem->alloc(img->metadata.byte_size, 0);
+
+ if (pixels != NULL) {
+ img->loader->load_pixels(img->metadata, pixels, img->metadata.byte_size, false);
+ }
+ }
+#endif
+
+ {
+ thread_scoped_lock device_lock(device_mutex);
+ img->mem->copy_to_device();
+ }
+
+ /* Cleanup memory in image loader. */
+ img->loader->cleanup();
+ img->need_load = false;
+}
+
+void ImageManager::device_free_image(Device *, int slot)
+{
+ Image *img = images[slot];
+ if (img == NULL) {
+ return;
+ }
+
+ if (osl_texture_system) {
+#ifdef WITH_OSL
+ ustring filepath = img->loader->osl_filepath();
+ if (!filepath.empty()) {
+ ((OSL::TextureSystem *)osl_texture_system)->invalidate(filepath);
+ }
+#endif
+ }
+
+ if (img->mem) {
+ thread_scoped_lock device_lock(device_mutex);
+ delete img->mem;
+ }
+
+ delete img->loader;
+ delete img;
+ images[slot] = NULL;
+}
+
+void ImageManager::device_update(Device *device, Scene *scene, Progress &progress)
+{
+ if (!need_update()) {
+ return;
+ }
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->image.times.add_entry({"device_update", time});
+ }
+ });
+
+ TaskPool pool;
+ for (size_t slot = 0; slot < images.size(); slot++) {
+ Image *img = images[slot];
+ if (img && img->users == 0) {
+ device_free_image(device, slot);
+ }
+ else if (img && img->need_load) {
+ pool.push(
+ function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress));
+ }
+ }
+
+ pool.wait_work();
+
+ need_update_ = false;
+}
+
+void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress)
+{
+ Image *img = images[slot];
+ assert(img != NULL);
+
+ if (img->users == 0) {
+ device_free_image(device, slot);
+ }
+ else if (img->need_load) {
+ device_load_image(device, scene, slot, progress);
+ }
+}
+
+void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &progress)
+{
+ /* Load only builtin images, Blender needs this to load evaluated
+ * scene data from depsgraph before it is freed. */
+ if (!need_update()) {
+ return;
+ }
+
+ TaskPool pool;
+ for (size_t slot = 0; slot < images.size(); slot++) {
+ Image *img = images[slot];
+ if (img && img->need_load && img->builtin) {
+ pool.push(
+ function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress));
+ }
+ }
+
+ pool.wait_work();
+}
+
+void ImageManager::device_free_builtin(Device *device)
+{
+ for (size_t slot = 0; slot < images.size(); slot++) {
+ Image *img = images[slot];
+ if (img && img->builtin) {
+ device_free_image(device, slot);
+ }
+ }
+}
+
+void ImageManager::device_free(Device *device)
+{
+ for (size_t slot = 0; slot < images.size(); slot++) {
+ device_free_image(device, slot);
+ }
+ images.clear();
+}
+
+void ImageManager::collect_statistics(RenderStats *stats)
+{
+ foreach (const Image *image, images) {
+ stats->image.textures.add_entry(
+ NamedSizeEntry(image->loader->name(), image->mem->memory_size()));
+ }
+}
+
+void ImageManager::tag_update()
+{
+ need_update_ = true;
+}
+
+bool ImageManager::need_update() const
+{
+ return need_update_;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/image.h b/intern/cycles/scene/image.h
new file mode 100644
index 00000000000..6447b028ebf
--- /dev/null
+++ b/intern/cycles/scene/image.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __IMAGE_H__
+#define __IMAGE_H__
+
+#include "device/memory.h"
+
+#include "scene/colorspace.h"
+
+#include "util/string.h"
+#include "util/thread.h"
+#include "util/transform.h"
+#include "util/unique_ptr.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceInfo;
+class ImageHandle;
+class ImageKey;
+class ImageMetaData;
+class ImageManager;
+class Progress;
+class RenderStats;
+class Scene;
+class ColorSpaceProcessor;
+class VDBImageLoader;
+
+/* Image Parameters */
+class ImageParams {
+ public:
+ bool animated;
+ InterpolationType interpolation;
+ ExtensionType extension;
+ ImageAlphaType alpha_type;
+ ustring colorspace;
+ float frame;
+
+ ImageParams()
+ : animated(false),
+ interpolation(INTERPOLATION_LINEAR),
+ extension(EXTENSION_CLIP),
+ alpha_type(IMAGE_ALPHA_AUTO),
+ colorspace(u_colorspace_raw),
+ frame(0.0f)
+ {
+ }
+
+ bool operator==(const ImageParams &other) const
+ {
+ return (animated == other.animated && interpolation == other.interpolation &&
+ extension == other.extension && alpha_type == other.alpha_type &&
+ colorspace == other.colorspace && frame == other.frame);
+ }
+};
+
+/* Image MetaData
+ *
+ * Information about the image that is available before the image pixels are loaded. */
+class ImageMetaData {
+ public:
+ /* Set by ImageLoader.load_metadata(). */
+ int channels;
+ size_t width, height, depth;
+ size_t byte_size;
+ ImageDataType type;
+
+ /* Optional color space, defaults to raw. */
+ ustring colorspace;
+ const char *colorspace_file_format;
+
+ /* Optional transform for 3D images. */
+ bool use_transform_3d;
+ Transform transform_3d;
+
+ /* Automatically set. */
+ bool compress_as_srgb;
+
+ ImageMetaData();
+ bool operator==(const ImageMetaData &other) const;
+ bool is_float() const;
+ void detect_colorspace();
+};
+
+/* Information about supported features that Image loaders can use. */
+class ImageDeviceFeatures {
+ public:
+ bool has_half_float;
+ bool has_nanovdb;
+};
+
+/* Image loader base class, that can be subclassed to load image data
+ * from custom sources (file, memory, procedurally generated, etc). */
+class ImageLoader {
+ public:
+ ImageLoader();
+ virtual ~ImageLoader(){};
+
+ /* Load metadata without actual image yet, should be fast. */
+ virtual bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) = 0;
+
+ /* Load actual image contents. */
+ virtual bool load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha) = 0;
+
+ /* Name for logs and stats. */
+ virtual string name() const = 0;
+
+ /* Optional for OSL texture cache. */
+ virtual ustring osl_filepath() const;
+
+ /* Free any memory used for loading metadata and pixels. */
+ virtual void cleanup(){};
+
+ /* Compare avoid loading the same image multiple times. */
+ virtual bool equals(const ImageLoader &other) const = 0;
+ static bool equals(const ImageLoader *a, const ImageLoader *b);
+
+ virtual bool is_vdb_loader() const;
+
+ /* Work around for no RTTI. */
+};
+
+/* Image Handle
+ *
+ * Access handle for image in the image manager. Multiple shader nodes may
+ * share the same image, and this class handles reference counting for that. */
+class ImageHandle {
+ public:
+ ImageHandle();
+ ImageHandle(const ImageHandle &other);
+ ImageHandle &operator=(const ImageHandle &other);
+ ~ImageHandle();
+
+ bool operator==(const ImageHandle &other) const;
+
+ void clear();
+
+ bool empty();
+ int num_tiles();
+
+ ImageMetaData metadata();
+ int svm_slot(const int tile_index = 0) const;
+ device_texture *image_memory(const int tile_index = 0) const;
+
+ VDBImageLoader *vdb_loader(const int tile_index = 0) const;
+
+ protected:
+ vector<int> tile_slots;
+ ImageManager *manager;
+
+ friend class ImageManager;
+};
+
+/* Image Manager
+ *
+ * Handles loading and storage of all images in the scene. This includes 2D
+ * texture images and 3D volume images. */
+class ImageManager {
+ public:
+ explicit ImageManager(const DeviceInfo &info);
+ ~ImageManager();
+
+ ImageHandle add_image(const string &filename, const ImageParams &params);
+ ImageHandle add_image(const string &filename,
+ const ImageParams &params,
+ const array<int> &tiles);
+ ImageHandle add_image(ImageLoader *loader, const ImageParams &params, const bool builtin = true);
+
+ void device_update(Device *device, Scene *scene, Progress &progress);
+ void device_update_slot(Device *device, Scene *scene, int slot, Progress *progress);
+ void device_free(Device *device);
+
+ void device_load_builtin(Device *device, Scene *scene, Progress &progress);
+ void device_free_builtin(Device *device);
+
+ void set_osl_texture_system(void *texture_system);
+ bool set_animation_frame_update(int frame);
+
+ void collect_statistics(RenderStats *stats);
+
+ void tag_update();
+
+ bool need_update() const;
+
+ struct Image {
+ ImageParams params;
+ ImageMetaData metadata;
+ ImageLoader *loader;
+
+ float frame;
+ bool need_metadata;
+ bool need_load;
+ bool builtin;
+
+ string mem_name;
+ device_texture *mem;
+
+ int users;
+ thread_mutex mutex;
+ };
+
+ private:
+ bool need_update_;
+
+ ImageDeviceFeatures features;
+
+ thread_mutex device_mutex;
+ thread_mutex images_mutex;
+ int animation_frame;
+
+ vector<Image *> images;
+ void *osl_texture_system;
+
+ int add_image_slot(ImageLoader *loader, const ImageParams &params, const bool builtin);
+ void add_image_user(int slot);
+ void remove_image_user(int slot);
+
+ void load_image_metadata(Image *img);
+
+ template<TypeDesc::BASETYPE FileFormat, typename StorageType>
+ bool file_load_image(Image *img, int texture_limit);
+
+ void device_load_image(Device *device, Scene *scene, int slot, Progress *progress);
+ void device_free_image(Device *device, int slot);
+
+ friend class ImageHandle;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __IMAGE_H__ */
diff --git a/intern/cycles/scene/image_oiio.cpp b/intern/cycles/scene/image_oiio.cpp
new file mode 100644
index 00000000000..feafae035a1
--- /dev/null
+++ b/intern/cycles/scene/image_oiio.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/image_oiio.h"
+
+#include "util/image.h"
+#include "util/log.h"
+#include "util/path.h"
+
+CCL_NAMESPACE_BEGIN
+
+OIIOImageLoader::OIIOImageLoader(const string &filepath) : filepath(filepath)
+{
+}
+
+OIIOImageLoader::~OIIOImageLoader()
+{
+}
+
+bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata)
+{
+ /* Perform preliminary checks, with meaningful logging. */
+ if (!path_exists(filepath.string())) {
+ VLOG(1) << "File '" << filepath.string() << "' does not exist.";
+ return false;
+ }
+ if (path_is_directory(filepath.string())) {
+ VLOG(1) << "File '" << filepath.string() << "' is a directory, can't use as image.";
+ return false;
+ }
+
+ unique_ptr<ImageInput> in(ImageInput::create(filepath.string()));
+
+ if (!in) {
+ return false;
+ }
+
+ ImageSpec spec;
+ if (!in->open(filepath.string(), spec)) {
+ return false;
+ }
+
+ metadata.width = spec.width;
+ metadata.height = spec.height;
+ metadata.depth = spec.depth;
+ metadata.compress_as_srgb = false;
+
+ /* Check the main format, and channel formats. */
+ size_t channel_size = spec.format.basesize();
+
+ bool is_float = false;
+ bool is_half = false;
+
+ if (spec.format.is_floating_point()) {
+ is_float = true;
+ }
+
+ for (size_t channel = 0; channel < spec.channelformats.size(); channel++) {
+ channel_size = max(channel_size, spec.channelformats[channel].basesize());
+ if (spec.channelformats[channel].is_floating_point()) {
+ is_float = true;
+ }
+ }
+
+ /* check if it's half float */
+ if (spec.format == TypeDesc::HALF && features.has_half_float) {
+ is_half = true;
+ }
+
+ /* set type and channels */
+ metadata.channels = spec.nchannels;
+
+ if (is_half) {
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF;
+ }
+ else if (is_float) {
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
+ }
+ else if (spec.format == TypeDesc::USHORT) {
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT;
+ }
+ else {
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
+ }
+
+ metadata.colorspace_file_format = in->format_name();
+
+ in->close();
+
+ return true;
+}
+
+template<TypeDesc::BASETYPE FileFormat, typename StorageType>
+static void oiio_load_pixels(const ImageMetaData &metadata,
+ const unique_ptr<ImageInput> &in,
+ StorageType *pixels)
+{
+ const int width = metadata.width;
+ const int height = metadata.height;
+ const int depth = metadata.depth;
+ const int components = metadata.channels;
+
+ /* Read pixels through OpenImageIO. */
+ StorageType *readpixels = pixels;
+ vector<StorageType> tmppixels;
+ if (components > 4) {
+ tmppixels.resize(((size_t)width) * height * components);
+ readpixels = &tmppixels[0];
+ }
+
+ if (depth <= 1) {
+ size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType);
+ in->read_image(FileFormat,
+ (uchar *)readpixels + (height - 1) * scanlinesize,
+ AutoStride,
+ -scanlinesize,
+ AutoStride);
+ }
+ else {
+ in->read_image(FileFormat, (uchar *)readpixels);
+ }
+
+ if (components > 4) {
+ size_t dimensions = ((size_t)width) * height;
+ for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
+ pixels[i * 4 + 3] = tmppixels[i * components + 3];
+ pixels[i * 4 + 2] = tmppixels[i * components + 2];
+ pixels[i * 4 + 1] = tmppixels[i * components + 1];
+ pixels[i * 4 + 0] = tmppixels[i * components + 0];
+ }
+ tmppixels.clear();
+ }
+
+ /* CMYK to RGBA. */
+ const bool cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4;
+ if (cmyk) {
+ const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
+
+ const size_t num_pixels = ((size_t)width) * height * depth;
+ for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ float c = util_image_cast_to_float(pixels[i * 4 + 0]);
+ float m = util_image_cast_to_float(pixels[i * 4 + 1]);
+ float y = util_image_cast_to_float(pixels[i * 4 + 2]);
+ float k = util_image_cast_to_float(pixels[i * 4 + 3]);
+ pixels[i * 4 + 0] = util_image_cast_from_float<StorageType>((1.0f - c) * (1.0f - k));
+ pixels[i * 4 + 1] = util_image_cast_from_float<StorageType>((1.0f - m) * (1.0f - k));
+ pixels[i * 4 + 2] = util_image_cast_from_float<StorageType>((1.0f - y) * (1.0f - k));
+ pixels[i * 4 + 3] = one;
+ }
+ }
+}
+
+bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t,
+ const bool associate_alpha)
+{
+ unique_ptr<ImageInput> in = NULL;
+
+ /* NOTE: Error logging is done in meta data acquisition. */
+ if (!path_exists(filepath.string()) || path_is_directory(filepath.string())) {
+ return false;
+ }
+
+ /* load image from file through OIIO */
+ in = unique_ptr<ImageInput>(ImageInput::create(filepath.string()));
+ if (!in) {
+ return false;
+ }
+
+ ImageSpec spec = ImageSpec();
+ ImageSpec config = ImageSpec();
+
+ if (!associate_alpha) {
+ config.attribute("oiio:UnassociatedAlpha", 1);
+ }
+
+ if (!in->open(filepath.string(), spec, config)) {
+ return false;
+ }
+
+ switch (metadata.type) {
+ case IMAGE_DATA_TYPE_BYTE:
+ case IMAGE_DATA_TYPE_BYTE4:
+ oiio_load_pixels<TypeDesc::UINT8, uchar>(metadata, in, (uchar *)pixels);
+ break;
+ case IMAGE_DATA_TYPE_USHORT:
+ case IMAGE_DATA_TYPE_USHORT4:
+ oiio_load_pixels<TypeDesc::USHORT, uint16_t>(metadata, in, (uint16_t *)pixels);
+ break;
+ case IMAGE_DATA_TYPE_HALF:
+ case IMAGE_DATA_TYPE_HALF4:
+ oiio_load_pixels<TypeDesc::HALF, half>(metadata, in, (half *)pixels);
+ break;
+ case IMAGE_DATA_TYPE_FLOAT:
+ case IMAGE_DATA_TYPE_FLOAT4:
+ oiio_load_pixels<TypeDesc::FLOAT, float>(metadata, in, (float *)pixels);
+ break;
+ case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
+ case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
+ case IMAGE_DATA_NUM_TYPES:
+ break;
+ }
+
+ in->close();
+ return true;
+}
+
+string OIIOImageLoader::name() const
+{
+ return path_filename(filepath.string());
+}
+
+ustring OIIOImageLoader::osl_filepath() const
+{
+ return filepath;
+}
+
+bool OIIOImageLoader::equals(const ImageLoader &other) const
+{
+ const OIIOImageLoader &other_loader = (const OIIOImageLoader &)other;
+ return filepath == other_loader.filepath;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/image_oiio.h b/intern/cycles/scene/image_oiio.h
new file mode 100644
index 00000000000..87f8b20f254
--- /dev/null
+++ b/intern/cycles/scene/image_oiio.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __IMAGE_OIIO__
+#define __IMAGE_OIIO__
+
+#include "scene/image.h"
+
+CCL_NAMESPACE_BEGIN
+
+class OIIOImageLoader : public ImageLoader {
+ public:
+ OIIOImageLoader(const string &filepath);
+ ~OIIOImageLoader();
+
+ bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
+
+ bool load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha) override;
+
+ string name() const override;
+
+ ustring osl_filepath() const override;
+
+ bool equals(const ImageLoader &other) const override;
+
+ protected:
+ ustring filepath;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __IMAGE_OIIO__ */
diff --git a/intern/cycles/scene/image_sky.cpp b/intern/cycles/scene/image_sky.cpp
new file mode 100644
index 00000000000..4f0877aeb99
--- /dev/null
+++ b/intern/cycles/scene/image_sky.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/image_sky.h"
+
+#include "sky_model.h"
+
+#include "util/image.h"
+#include "util/log.h"
+#include "util/path.h"
+#include "util/task.h"
+
+CCL_NAMESPACE_BEGIN
+
+SkyLoader::SkyLoader(float sun_elevation,
+ float altitude,
+ float air_density,
+ float dust_density,
+ float ozone_density)
+ : sun_elevation(sun_elevation),
+ altitude(altitude),
+ air_density(air_density),
+ dust_density(dust_density),
+ ozone_density(ozone_density)
+{
+}
+
+SkyLoader::~SkyLoader(){};
+
+bool SkyLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
+{
+ metadata.width = 512;
+ metadata.height = 128;
+ metadata.channels = 3;
+ metadata.depth = 1;
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
+ metadata.compress_as_srgb = false;
+ return true;
+}
+
+bool SkyLoader::load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t /*pixels_size*/,
+ const bool /*associate_alpha*/)
+{
+ /* definitions */
+ int width = metadata.width;
+ int height = metadata.height;
+ float *pixel_data = (float *)pixels;
+
+ /* precompute sky texture */
+ const int rows_per_task = divide_up(1024, width);
+ parallel_for(blocked_range<size_t>(0, height, rows_per_task),
+ [&](const blocked_range<size_t> &r) {
+ SKY_nishita_skymodel_precompute_texture(pixel_data,
+ metadata.channels,
+ r.begin(),
+ r.end(),
+ width,
+ height,
+ sun_elevation,
+ altitude,
+ air_density,
+ dust_density,
+ ozone_density);
+ });
+
+ return true;
+}
+
+string SkyLoader::name() const
+{
+ return "sky_nishita";
+}
+
+bool SkyLoader::equals(const ImageLoader & /*other*/) const
+{
+ return false;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/image_sky.h b/intern/cycles/scene/image_sky.h
new file mode 100644
index 00000000000..d57e7bbee07
--- /dev/null
+++ b/intern/cycles/scene/image_sky.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/image.h"
+
+CCL_NAMESPACE_BEGIN
+
+class SkyLoader : public ImageLoader {
+ private:
+ float sun_elevation;
+ float altitude;
+ float air_density;
+ float dust_density;
+ float ozone_density;
+
+ public:
+ SkyLoader(float sun_elevation,
+ float altitude,
+ float air_density,
+ float dust_density,
+ float ozone_density);
+ ~SkyLoader();
+
+ bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
+
+ bool load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t /*pixels_size*/,
+ const bool /*associate_alpha*/) override;
+
+ string name() const override;
+
+ bool equals(const ImageLoader & /*other*/) const override;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/image_vdb.cpp b/intern/cycles/scene/image_vdb.cpp
new file mode 100644
index 00000000000..d3315670390
--- /dev/null
+++ b/intern/cycles/scene/image_vdb.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/image_vdb.h"
+
+#include "util/log.h"
+#include "util/openvdb.h"
+
+#ifdef WITH_OPENVDB
+# include <openvdb/tools/Dense.h>
+#endif
+#ifdef WITH_NANOVDB
+# include <nanovdb/util/OpenToNanoVDB.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_OPENVDB
+struct NumChannelsOp {
+ int num_channels = 0;
+
+ template<typename GridType, typename FloatGridType, typename FloatDataType, int channels>
+ bool operator()(const openvdb::GridBase::ConstPtr &)
+ {
+ num_channels = channels;
+ return true;
+ }
+};
+
+struct ToDenseOp {
+ openvdb::CoordBBox bbox;
+ void *pixels;
+
+ template<typename GridType, typename FloatGridType, typename FloatDataType, int channels>
+ bool operator()(const openvdb::GridBase::ConstPtr &grid)
+ {
+ openvdb::tools::Dense<FloatDataType, openvdb::tools::LayoutXYZ> dense(bbox,
+ (FloatDataType *)pixels);
+ openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<GridType>(grid), dense);
+ return true;
+ }
+};
+
+# ifdef WITH_NANOVDB
+struct ToNanoOp {
+ nanovdb::GridHandle<> nanogrid;
+
+ template<typename GridType, typename FloatGridType, typename FloatDataType, int channels>
+ bool operator()(const openvdb::GridBase::ConstPtr &grid)
+ {
+ if constexpr (!std::is_same_v<GridType, openvdb::MaskGrid>) {
+ try {
+ nanogrid = nanovdb::openToNanoVDB(
+ FloatGridType(*openvdb::gridConstPtrCast<GridType>(grid)));
+ }
+ catch (const std::exception &e) {
+ VLOG(1) << "Error converting OpenVDB to NanoVDB grid: " << e.what();
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+};
+# endif
+#endif
+
+VDBImageLoader::VDBImageLoader(const string &grid_name) : grid_name(grid_name)
+{
+}
+
+VDBImageLoader::~VDBImageLoader()
+{
+}
+
+bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata)
+{
+#ifdef WITH_OPENVDB
+ if (!grid) {
+ return false;
+ }
+
+ /* Get number of channels from type. */
+ NumChannelsOp op;
+ if (!openvdb::grid_type_operation(grid, op)) {
+ return false;
+ }
+
+ metadata.channels = op.num_channels;
+
+ /* Set data type. */
+# ifdef WITH_NANOVDB
+ if (features.has_nanovdb) {
+ /* NanoVDB expects no inactive leaf nodes. */
+ /*openvdb::FloatGrid &pruned_grid = *openvdb::gridPtrCast<openvdb::FloatGrid>(grid);
+ openvdb::tools::pruneInactive(pruned_grid.tree());
+ nanogrid = nanovdb::openToNanoVDB(pruned_grid);*/
+ ToNanoOp op;
+ if (!openvdb::grid_type_operation(grid, op)) {
+ return false;
+ }
+ nanogrid = std::move(op.nanogrid);
+ }
+# endif
+
+ /* Set dimensions. */
+ bbox = grid->evalActiveVoxelBoundingBox();
+ if (bbox.empty()) {
+ return false;
+ }
+
+ openvdb::Coord dim = bbox.dim();
+ metadata.width = dim.x();
+ metadata.height = dim.y();
+ metadata.depth = dim.z();
+
+# ifdef WITH_NANOVDB
+ if (nanogrid) {
+ metadata.byte_size = nanogrid.size();
+ if (metadata.channels == 1) {
+ metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT;
+ }
+ else {
+ metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT3;
+ }
+ }
+ else
+# endif
+ {
+ if (metadata.channels == 1) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT;
+ }
+ else {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
+ }
+ }
+
+ /* Set transform from object space to voxel index. */
+ openvdb::math::Mat4f grid_matrix = grid->transform().baseMap()->getAffineMap()->getMat4();
+ Transform index_to_object;
+ for (int col = 0; col < 4; col++) {
+ for (int row = 0; row < 3; row++) {
+ index_to_object[row][col] = (float)grid_matrix[col][row];
+ }
+ }
+
+ Transform texture_to_index;
+# ifdef WITH_NANOVDB
+ if (nanogrid) {
+ texture_to_index = transform_identity();
+ }
+ else
+# endif
+ {
+ openvdb::Coord min = bbox.min();
+ texture_to_index = transform_translate(min.x(), min.y(), min.z()) *
+ transform_scale(dim.x(), dim.y(), dim.z());
+ }
+
+ metadata.transform_3d = transform_inverse(index_to_object * texture_to_index);
+ metadata.use_transform_3d = true;
+
+# ifndef WITH_NANOVDB
+ (void)features;
+# endif
+ return true;
+#else
+ (void)metadata;
+ (void)features;
+ return false;
+#endif
+}
+
+bool VDBImageLoader::load_pixels(const ImageMetaData &, void *pixels, const size_t, const bool)
+{
+#ifdef WITH_OPENVDB
+# ifdef WITH_NANOVDB
+ if (nanogrid) {
+ memcpy(pixels, nanogrid.data(), nanogrid.size());
+ }
+ else
+# endif
+ {
+ ToDenseOp op;
+ op.pixels = pixels;
+ op.bbox = bbox;
+ openvdb::grid_type_operation(grid, op);
+ }
+ return true;
+#else
+ (void)pixels;
+ return false;
+#endif
+}
+
+string VDBImageLoader::name() const
+{
+ return grid_name;
+}
+
+bool VDBImageLoader::equals(const ImageLoader &other) const
+{
+#ifdef WITH_OPENVDB
+ const VDBImageLoader &other_loader = (const VDBImageLoader &)other;
+ return grid == other_loader.grid;
+#else
+ (void)other;
+ return true;
+#endif
+}
+
+void VDBImageLoader::cleanup()
+{
+#ifdef WITH_OPENVDB
+ /* Free OpenVDB grid memory as soon as we can. */
+ grid.reset();
+#endif
+#ifdef WITH_NANOVDB
+ nanogrid.reset();
+#endif
+}
+
+bool VDBImageLoader::is_vdb_loader() const
+{
+ return true;
+}
+
+#ifdef WITH_OPENVDB
+openvdb::GridBase::ConstPtr VDBImageLoader::get_grid()
+{
+ return grid;
+}
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/image_vdb.h b/intern/cycles/scene/image_vdb.h
new file mode 100644
index 00000000000..0a43d83a24f
--- /dev/null
+++ b/intern/cycles/scene/image_vdb.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __IMAGE_VDB__
+#define __IMAGE_VDB__
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+#endif
+#ifdef WITH_NANOVDB
+# include <nanovdb/util/GridHandle.h>
+#endif
+
+#include "scene/image.h"
+
+CCL_NAMESPACE_BEGIN
+
+class VDBImageLoader : public ImageLoader {
+ public:
+ VDBImageLoader(const string &grid_name);
+ ~VDBImageLoader();
+
+ virtual bool load_metadata(const ImageDeviceFeatures &features,
+ ImageMetaData &metadata) override;
+
+ virtual bool load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha) override;
+
+ virtual string name() const override;
+
+ virtual bool equals(const ImageLoader &other) const override;
+
+ virtual void cleanup() override;
+
+ virtual bool is_vdb_loader() const override;
+
+#ifdef WITH_OPENVDB
+ openvdb::GridBase::ConstPtr get_grid();
+#endif
+
+ protected:
+ string grid_name;
+#ifdef WITH_OPENVDB
+ openvdb::GridBase::ConstPtr grid;
+ openvdb::CoordBBox bbox;
+#endif
+#ifdef WITH_NANOVDB
+ nanovdb::GridHandle<> nanogrid;
+#endif
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __IMAGE_VDB__ */
diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp
new file mode 100644
index 00000000000..e9ff868c3fc
--- /dev/null
+++ b/intern/cycles/scene/integrator.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/integrator.h"
+#include "device/device.h"
+#include "scene/background.h"
+#include "scene/camera.h"
+#include "scene/film.h"
+#include "scene/jitter.h"
+#include "scene/light.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/sobol.h"
+#include "scene/stats.h"
+
+#include "kernel/types.h"
+
+#include "util/foreach.h"
+#include "util/hash.h"
+#include "util/log.h"
+#include "util/task.h"
+#include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+NODE_DEFINE(Integrator)
+{
+ NodeType *type = NodeType::add("integrator", create);
+
+ SOCKET_INT(min_bounce, "Min Bounce", 0);
+ SOCKET_INT(max_bounce, "Max Bounce", 7);
+
+ SOCKET_INT(max_diffuse_bounce, "Max Diffuse Bounce", 7);
+ SOCKET_INT(max_glossy_bounce, "Max Glossy Bounce", 7);
+ SOCKET_INT(max_transmission_bounce, "Max Transmission Bounce", 7);
+ SOCKET_INT(max_volume_bounce, "Max Volume Bounce", 7);
+
+ SOCKET_INT(transparent_min_bounce, "Transparent Min Bounce", 0);
+ SOCKET_INT(transparent_max_bounce, "Transparent Max Bounce", 7);
+
+ SOCKET_INT(ao_bounces, "AO Bounces", 0);
+ SOCKET_FLOAT(ao_factor, "AO Factor", 0.0f);
+ SOCKET_FLOAT(ao_distance, "AO Distance", FLT_MAX);
+ SOCKET_FLOAT(ao_additive_factor, "AO Additive Factor", 0.0f);
+
+ SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024);
+ SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
+
+ SOCKET_BOOLEAN(caustics_reflective, "Reflective Caustics", true);
+ SOCKET_BOOLEAN(caustics_refractive, "Refractive Caustics", true);
+ SOCKET_FLOAT(filter_glossy, "Filter Glossy", 0.0f);
+ SOCKET_INT(seed, "Seed", 0);
+ SOCKET_FLOAT(sample_clamp_direct, "Sample Clamp Direct", 0.0f);
+ SOCKET_FLOAT(sample_clamp_indirect, "Sample Clamp Indirect", 0.0f);
+ SOCKET_BOOLEAN(motion_blur, "Motion Blur", false);
+
+ SOCKET_INT(aa_samples, "AA Samples", 0);
+ SOCKET_INT(start_sample, "Start Sample", 0);
+
+ SOCKET_BOOLEAN(use_adaptive_sampling, "Use Adaptive Sampling", false);
+ SOCKET_FLOAT(adaptive_threshold, "Adaptive Threshold", 0.0f);
+ SOCKET_INT(adaptive_min_samples, "Adaptive Min Samples", 0);
+
+ SOCKET_FLOAT(light_sampling_threshold, "Light Sampling Threshold", 0.05f);
+
+ static NodeEnum sampling_pattern_enum;
+ sampling_pattern_enum.insert("sobol", SAMPLING_PATTERN_SOBOL);
+ sampling_pattern_enum.insert("pmj", SAMPLING_PATTERN_PMJ);
+ SOCKET_ENUM(sampling_pattern, "Sampling Pattern", sampling_pattern_enum, SAMPLING_PATTERN_SOBOL);
+ SOCKET_FLOAT(scrambling_distance, "Scrambling Distance", 1.0f);
+
+ static NodeEnum denoiser_type_enum;
+ denoiser_type_enum.insert("optix", DENOISER_OPTIX);
+ denoiser_type_enum.insert("openimagedenoise", DENOISER_OPENIMAGEDENOISE);
+
+ static NodeEnum denoiser_prefilter_enum;
+ denoiser_prefilter_enum.insert("none", DENOISER_PREFILTER_NONE);
+ denoiser_prefilter_enum.insert("fast", DENOISER_PREFILTER_FAST);
+ denoiser_prefilter_enum.insert("accurate", DENOISER_PREFILTER_ACCURATE);
+
+ /* Default to accurate denoising with OpenImageDenoise. For interactive viewport
+ * it's best use OptiX and disable the normal pass since it does not always have
+ * the desired effect for that denoiser. */
+ SOCKET_BOOLEAN(use_denoise, "Use Denoiser", false);
+ SOCKET_ENUM(denoiser_type, "Denoiser Type", denoiser_type_enum, DENOISER_OPENIMAGEDENOISE);
+ SOCKET_INT(denoise_start_sample, "Start Sample to Denoise", 0);
+ SOCKET_BOOLEAN(use_denoise_pass_albedo, "Use Albedo Pass for Denoiser", true);
+ SOCKET_BOOLEAN(use_denoise_pass_normal, "Use Normal Pass for Denoiser", true);
+ SOCKET_ENUM(
+ denoiser_prefilter, "Denoiser Type", denoiser_prefilter_enum, DENOISER_PREFILTER_ACCURATE);
+
+ return type;
+}
+
+Integrator::Integrator() : Node(get_node_type())
+{
+}
+
+Integrator::~Integrator()
+{
+}
+
+void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene)
+{
+ if (!is_modified())
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->integrator.times.add_entry({"device_update", time});
+ }
+ });
+
+ KernelIntegrator *kintegrator = &dscene->data.integrator;
+
+ /* Adaptive sampling requires PMJ samples.
+ *
+ * This also makes detection of sampling pattern a bit more involved: can not rely on the changed
+ * state of socket, since its value might be different from the effective value used here. So
+ * instead compare with previous value in the KernelIntegrator. Only do it if the device was
+ * updated once (in which case the `sample_pattern_lut` will be allocated to a non-zero size). */
+ const SamplingPattern new_sampling_pattern = (use_adaptive_sampling) ? SAMPLING_PATTERN_PMJ :
+ sampling_pattern;
+
+ const bool need_update_lut = max_bounce_is_modified() || max_transmission_bounce_is_modified() ||
+ dscene->sample_pattern_lut.size() == 0 ||
+ kintegrator->sampling_pattern != new_sampling_pattern;
+
+ if (need_update_lut) {
+ dscene->sample_pattern_lut.tag_realloc();
+ }
+
+ device_free(device, dscene);
+
+ /* integrator parameters */
+ kintegrator->min_bounce = min_bounce + 1;
+ kintegrator->max_bounce = max_bounce + 1;
+
+ kintegrator->max_diffuse_bounce = max_diffuse_bounce + 1;
+ kintegrator->max_glossy_bounce = max_glossy_bounce + 1;
+ kintegrator->max_transmission_bounce = max_transmission_bounce + 1;
+ kintegrator->max_volume_bounce = max_volume_bounce + 1;
+
+ kintegrator->transparent_min_bounce = transparent_min_bounce + 1;
+ kintegrator->transparent_max_bounce = transparent_max_bounce + 1;
+
+ kintegrator->ao_bounces = ao_bounces;
+ kintegrator->ao_bounces_distance = ao_distance;
+ kintegrator->ao_bounces_factor = ao_factor;
+ kintegrator->ao_additive_factor = ao_additive_factor;
+
+ /* Transparent Shadows
+ * We only need to enable transparent shadows, if we actually have
+ * transparent shaders in the scene. Otherwise we can disable it
+ * to improve performance a bit. */
+ kintegrator->transparent_shadows = false;
+ foreach (Shader *shader, scene->shaders) {
+ /* keep this in sync with SD_HAS_TRANSPARENT_SHADOW in shader.cpp */
+ if ((shader->has_surface_transparent && shader->get_use_transparent_shadow()) ||
+ shader->has_volume) {
+ kintegrator->transparent_shadows = true;
+ break;
+ }
+ }
+
+ kintegrator->volume_max_steps = volume_max_steps;
+ kintegrator->volume_step_rate = volume_step_rate;
+
+ kintegrator->caustics_reflective = caustics_reflective;
+ kintegrator->caustics_refractive = caustics_refractive;
+ kintegrator->filter_glossy = (filter_glossy == 0.0f) ? FLT_MAX : 1.0f / filter_glossy;
+
+ kintegrator->seed = seed;
+
+ kintegrator->sample_clamp_direct = (sample_clamp_direct == 0.0f) ? FLT_MAX :
+ sample_clamp_direct * 3.0f;
+ kintegrator->sample_clamp_indirect = (sample_clamp_indirect == 0.0f) ?
+ FLT_MAX :
+ sample_clamp_indirect * 3.0f;
+
+ kintegrator->sampling_pattern = new_sampling_pattern;
+ kintegrator->scrambling_distance = scrambling_distance;
+
+ if (light_sampling_threshold > 0.0f) {
+ kintegrator->light_inv_rr_threshold = 1.0f / light_sampling_threshold;
+ }
+ else {
+ kintegrator->light_inv_rr_threshold = 0.0f;
+ }
+
+ /* sobol directions table */
+ int max_samples = max_bounce + transparent_max_bounce + 3 + VOLUME_BOUNDS_MAX +
+ max(BSSRDF_MAX_HITS, BSSRDF_MAX_BOUNCES);
+
+ int dimensions = PRNG_BASE_NUM + max_samples * PRNG_BOUNCE_NUM;
+ dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS);
+
+ if (need_update_lut) {
+ if (kintegrator->sampling_pattern == SAMPLING_PATTERN_SOBOL) {
+ uint *directions = (uint *)dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions);
+
+ sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
+
+ dscene->sample_pattern_lut.copy_to_device();
+ }
+ else {
+ constexpr int sequence_size = NUM_PMJ_SAMPLES;
+ constexpr int num_sequences = NUM_PMJ_PATTERNS;
+ float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size *
+ num_sequences * 2);
+ TaskPool pool;
+ for (int j = 0; j < num_sequences; ++j) {
+ float2 *sequence = directions + j * sequence_size;
+ pool.push(
+ function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j));
+ }
+ pool.wait_work();
+
+ dscene->sample_pattern_lut.copy_to_device();
+ }
+ }
+
+ kintegrator->has_shadow_catcher = scene->has_shadow_catcher();
+
+ dscene->sample_pattern_lut.clear_modified();
+ clear_modified();
+}
+
+void Integrator::device_free(Device *, DeviceScene *dscene, bool force_free)
+{
+ dscene->sample_pattern_lut.free_if_need_realloc(force_free);
+}
+
+void Integrator::tag_update(Scene *scene, uint32_t flag)
+{
+ if (flag & UPDATE_ALL) {
+ tag_modified();
+ }
+
+ if (flag & AO_PASS_MODIFIED) {
+ /* tag only the ao_bounces socket as modified so we avoid updating sample_pattern_lut
+ * unnecessarily */
+ tag_ao_bounces_modified();
+ }
+
+ if (filter_glossy_is_modified()) {
+ foreach (Shader *shader, scene->shaders) {
+ if (shader->has_integrator_dependency) {
+ scene->shader_manager->tag_update(scene, ShaderManager::INTEGRATOR_MODIFIED);
+ break;
+ }
+ }
+ }
+
+ if (motion_blur_is_modified()) {
+ scene->object_manager->tag_update(scene, ObjectManager::MOTION_BLUR_MODIFIED);
+ scene->camera->tag_modified();
+ }
+}
+
+uint Integrator::get_kernel_features() const
+{
+ uint kernel_features = 0;
+
+ if (ao_additive_factor != 0.0f) {
+ kernel_features |= KERNEL_FEATURE_AO_ADDITIVE;
+ }
+
+ return kernel_features;
+}
+
+AdaptiveSampling Integrator::get_adaptive_sampling() const
+{
+ AdaptiveSampling adaptive_sampling;
+
+ adaptive_sampling.use = use_adaptive_sampling;
+
+ if (!adaptive_sampling.use) {
+ return adaptive_sampling;
+ }
+
+ if (aa_samples > 0 && adaptive_threshold == 0.0f) {
+ adaptive_sampling.threshold = max(0.001f, 1.0f / (float)aa_samples);
+ VLOG(1) << "Cycles adaptive sampling: automatic threshold = " << adaptive_sampling.threshold;
+ }
+ else {
+ adaptive_sampling.threshold = adaptive_threshold;
+ }
+
+ if (adaptive_sampling.threshold > 0 && adaptive_min_samples == 0) {
+ /* Threshold 0.1 -> 32, 0.01 -> 64, 0.001 -> 128.
+ * This is highly scene dependent, we make a guess that seemed to work well
+ * in various test scenes. */
+ const int min_samples = (int)ceilf(16.0f / powf(adaptive_sampling.threshold, 0.3f));
+ adaptive_sampling.min_samples = max(4, min_samples);
+ VLOG(1) << "Cycles adaptive sampling: automatic min samples = "
+ << adaptive_sampling.min_samples;
+ }
+ else {
+ adaptive_sampling.min_samples = max(4, adaptive_min_samples);
+ }
+
+ /* Arbitrary factor that makes the threshold more similar to what is was before,
+ * and gives arguably more intuitive values. */
+ adaptive_sampling.threshold *= 5.0f;
+
+ adaptive_sampling.adaptive_step = 16;
+
+ DCHECK(is_power_of_two(adaptive_sampling.adaptive_step))
+ << "Adaptive step must be a power of two for bitwise operations to work";
+
+ return adaptive_sampling;
+}
+
+DenoiseParams Integrator::get_denoise_params() const
+{
+ DenoiseParams denoise_params;
+
+ denoise_params.use = use_denoise;
+
+ denoise_params.type = denoiser_type;
+
+ denoise_params.start_sample = denoise_start_sample;
+
+ denoise_params.use_pass_albedo = use_denoise_pass_albedo;
+ denoise_params.use_pass_normal = use_denoise_pass_normal;
+
+ denoise_params.prefilter = denoiser_prefilter;
+
+ return denoise_params;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/integrator.h b/intern/cycles/scene/integrator.h
new file mode 100644
index 00000000000..75764bcdedc
--- /dev/null
+++ b/intern/cycles/scene/integrator.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __INTEGRATOR_H__
+#define __INTEGRATOR_H__
+
+#include "kernel/types.h"
+
+#include "device/denoise.h" /* For the parameters and type enum. */
+#include "graph/node.h"
+#include "integrator/adaptive_sampling.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Scene;
+
+class Integrator : public Node {
+ public:
+ NODE_DECLARE
+
+ NODE_SOCKET_API(int, min_bounce)
+ NODE_SOCKET_API(int, max_bounce)
+
+ NODE_SOCKET_API(int, max_diffuse_bounce)
+ NODE_SOCKET_API(int, max_glossy_bounce)
+ NODE_SOCKET_API(int, max_transmission_bounce)
+ NODE_SOCKET_API(int, max_volume_bounce)
+
+ NODE_SOCKET_API(int, transparent_min_bounce)
+ NODE_SOCKET_API(int, transparent_max_bounce)
+
+ NODE_SOCKET_API(int, ao_bounces)
+ NODE_SOCKET_API(float, ao_factor)
+ NODE_SOCKET_API(float, ao_distance)
+ NODE_SOCKET_API(float, ao_additive_factor)
+
+ NODE_SOCKET_API(int, volume_max_steps)
+ NODE_SOCKET_API(float, volume_step_rate)
+
+ NODE_SOCKET_API(bool, caustics_reflective)
+ NODE_SOCKET_API(bool, caustics_refractive)
+ NODE_SOCKET_API(float, filter_glossy)
+
+ NODE_SOCKET_API(int, seed)
+
+ NODE_SOCKET_API(float, sample_clamp_direct)
+ NODE_SOCKET_API(float, sample_clamp_indirect)
+ NODE_SOCKET_API(bool, motion_blur)
+
+ /* Maximum number of samples, beyond which we are likely to run into
+ * precision issues for sampling patterns. */
+ static const int MAX_SAMPLES = (1 << 24);
+
+ NODE_SOCKET_API(int, aa_samples)
+ NODE_SOCKET_API(int, start_sample)
+
+ NODE_SOCKET_API(float, light_sampling_threshold)
+
+ NODE_SOCKET_API(bool, use_adaptive_sampling)
+ NODE_SOCKET_API(int, adaptive_min_samples)
+ NODE_SOCKET_API(float, adaptive_threshold)
+
+ NODE_SOCKET_API(SamplingPattern, sampling_pattern)
+ NODE_SOCKET_API(float, scrambling_distance)
+
+ NODE_SOCKET_API(bool, use_denoise);
+ NODE_SOCKET_API(DenoiserType, denoiser_type);
+ NODE_SOCKET_API(int, denoise_start_sample);
+ NODE_SOCKET_API(bool, use_denoise_pass_albedo);
+ NODE_SOCKET_API(bool, use_denoise_pass_normal);
+ NODE_SOCKET_API(DenoiserPrefilter, denoiser_prefilter);
+
+ enum : uint32_t {
+ AO_PASS_MODIFIED = (1 << 0),
+ OBJECT_MANAGER = (1 << 1),
+
+ /* tag everything in the manager for an update */
+ UPDATE_ALL = ~0u,
+
+ UPDATE_NONE = 0u,
+ };
+
+ Integrator();
+ ~Integrator();
+
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene);
+ void device_free(Device *device, DeviceScene *dscene, bool force_free = false);
+
+ void tag_update(Scene *scene, uint32_t flag);
+
+ uint get_kernel_features() const;
+
+ AdaptiveSampling get_adaptive_sampling() const;
+ DenoiseParams get_denoise_params() const;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __INTEGRATOR_H__ */
diff --git a/intern/cycles/scene/jitter.cpp b/intern/cycles/scene/jitter.cpp
new file mode 100644
index 00000000000..e2162195ad8
--- /dev/null
+++ b/intern/cycles/scene/jitter.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2019 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This file is based on "Progressive Multi-Jittered Sample Sequences"
+ * by Per Christensen, Andrew Kensler and Charlie Kilpatrick.
+ * http://graphics.pixar.com/library/ProgressiveMultiJitteredSampling/paper.pdf
+ *
+ * Performance can be improved in the future by implementing the new
+ * algorithm from Matt Pharr in http://jcgt.org/published/0008/01/04/
+ * "Efficient Generation of Points that Satisfy Two-Dimensional Elementary Intervals"
+ */
+
+#include "scene/jitter.h"
+
+#include <math.h>
+#include <vector>
+
+CCL_NAMESPACE_BEGIN
+
+static uint cmj_hash(uint i, uint p)
+{
+ i ^= p;
+ i ^= i >> 17;
+ i ^= i >> 10;
+ i *= 0xb36534e5;
+ i ^= i >> 12;
+ i ^= i >> 21;
+ i *= 0x93fc4795;
+ i ^= 0xdf6e307f;
+ i ^= i >> 17;
+ i *= 1 | p >> 18;
+
+ return i;
+}
+
+static float cmj_randfloat(uint i, uint p)
+{
+ return cmj_hash(i, p) * (1.0f / 4294967808.0f);
+}
+
+class PMJ_Generator {
+ public:
+ static void generate_2D(float2 points[], int size, int rng_seed_in)
+ {
+ PMJ_Generator g(rng_seed_in);
+ points[0].x = g.rnd();
+ points[0].y = g.rnd();
+ int N = 1;
+ while (N < size) {
+ g.extend_sequence_even(points, N);
+ g.extend_sequence_odd(points, 2 * N);
+ N = 4 * N;
+ }
+ }
+
+ protected:
+ PMJ_Generator(int rnd_seed_in) : num_samples(1), rnd_index(2), rnd_seed(rnd_seed_in)
+ {
+ }
+
+ float rnd()
+ {
+ return cmj_randfloat(++rnd_index, rnd_seed);
+ }
+
+ virtual void mark_occupied_strata(float2 points[], int N)
+ {
+ int NN = 2 * N;
+ for (int s = 0; s < NN; ++s) {
+ occupied1Dx[s] = occupied1Dy[s] = false;
+ }
+ for (int s = 0; s < N; ++s) {
+ int xstratum = (int)(NN * points[s].x);
+ int ystratum = (int)(NN * points[s].y);
+ occupied1Dx[xstratum] = true;
+ occupied1Dy[ystratum] = true;
+ }
+ }
+
+ virtual void generate_sample_point(
+ float2 points[], float i, float j, float xhalf, float yhalf, int n, int N)
+ {
+ int NN = 2 * N;
+ float2 pt;
+ int xstratum, ystratum;
+ do {
+ pt.x = (i + 0.5f * (xhalf + rnd())) / n;
+ xstratum = (int)(NN * pt.x);
+ } while (occupied1Dx[xstratum]);
+ do {
+ pt.y = (j + 0.5f * (yhalf + rnd())) / n;
+ ystratum = (int)(NN * pt.y);
+ } while (occupied1Dy[ystratum]);
+ occupied1Dx[xstratum] = true;
+ occupied1Dy[ystratum] = true;
+ points[num_samples] = pt;
+ ++num_samples;
+ }
+
+ void extend_sequence_even(float2 points[], int N)
+ {
+ int n = (int)sqrtf(N);
+ occupied1Dx.resize(2 * N);
+ occupied1Dy.resize(2 * N);
+ mark_occupied_strata(points, N);
+ for (int s = 0; s < N; ++s) {
+ float2 oldpt = points[s];
+ float i = floorf(n * oldpt.x);
+ float j = floorf(n * oldpt.y);
+ float xhalf = floorf(2.0f * (n * oldpt.x - i));
+ float yhalf = floorf(2.0f * (n * oldpt.y - j));
+ xhalf = 1.0f - xhalf;
+ yhalf = 1.0f - yhalf;
+ generate_sample_point(points, i, j, xhalf, yhalf, n, N);
+ }
+ }
+
+ void extend_sequence_odd(float2 points[], int N)
+ {
+ int n = (int)sqrtf(N / 2);
+ occupied1Dx.resize(2 * N);
+ occupied1Dy.resize(2 * N);
+ mark_occupied_strata(points, N);
+ std::vector<float> xhalves(N / 2);
+ std::vector<float> yhalves(N / 2);
+ for (int s = 0; s < N / 2; ++s) {
+ float2 oldpt = points[s];
+ float i = floorf(n * oldpt.x);
+ float j = floorf(n * oldpt.y);
+ float xhalf = floorf(2.0f * (n * oldpt.x - i));
+ float yhalf = floorf(2.0f * (n * oldpt.y - j));
+ if (rnd() > 0.5f) {
+ xhalf = 1.0f - xhalf;
+ }
+ else {
+ yhalf = 1.0f - yhalf;
+ }
+ xhalves[s] = xhalf;
+ yhalves[s] = yhalf;
+ generate_sample_point(points, i, j, xhalf, yhalf, n, N);
+ }
+ for (int s = 0; s < N / 2; ++s) {
+ float2 oldpt = points[s];
+ float i = floorf(n * oldpt.x);
+ float j = floorf(n * oldpt.y);
+ float xhalf = 1.0f - xhalves[s];
+ float yhalf = 1.0f - yhalves[s];
+ generate_sample_point(points, i, j, xhalf, yhalf, n, N);
+ }
+ }
+
+ std::vector<bool> occupied1Dx, occupied1Dy;
+ int num_samples;
+ int rnd_index, rnd_seed;
+};
+
+class PMJ02_Generator : public PMJ_Generator {
+ protected:
+ void generate_sample_point(
+ float2 points[], float i, float j, float xhalf, float yhalf, int n, int N) override
+ {
+ int NN = 2 * N;
+ float2 pt;
+ do {
+ pt.x = (i + 0.5f * (xhalf + rnd())) / n;
+ pt.y = (j + 0.5f * (yhalf + rnd())) / n;
+ } while (is_occupied(pt, NN));
+ mark_occupied_strata1(pt, NN);
+ points[num_samples] = pt;
+ ++num_samples;
+ }
+
+ void mark_occupied_strata(float2 points[], int N) override
+ {
+ int NN = 2 * N;
+ int num_shapes = (int)log2f(NN) + 1;
+ occupiedStrata.resize(num_shapes);
+ for (int shape = 0; shape < num_shapes; ++shape) {
+ occupiedStrata[shape].resize(NN);
+ for (int n = 0; n < NN; ++n) {
+ occupiedStrata[shape][n] = false;
+ }
+ }
+ for (int s = 0; s < N; ++s) {
+ mark_occupied_strata1(points[s], NN);
+ }
+ }
+
+ void mark_occupied_strata1(float2 pt, int NN)
+ {
+ int shape = 0;
+ int xdivs = NN;
+ int ydivs = 1;
+ do {
+ int xstratum = (int)(xdivs * pt.x);
+ int ystratum = (int)(ydivs * pt.y);
+ size_t index = ystratum * xdivs + xstratum;
+ assert(index < NN);
+ occupiedStrata[shape][index] = true;
+ shape = shape + 1;
+ xdivs = xdivs / 2;
+ ydivs = ydivs * 2;
+ } while (xdivs > 0);
+ }
+
+ bool is_occupied(float2 pt, int NN)
+ {
+ int shape = 0;
+ int xdivs = NN;
+ int ydivs = 1;
+ do {
+ int xstratum = (int)(xdivs * pt.x);
+ int ystratum = (int)(ydivs * pt.y);
+ size_t index = ystratum * xdivs + xstratum;
+ assert(index < NN);
+ if (occupiedStrata[shape][index]) {
+ return true;
+ }
+ shape = shape + 1;
+ xdivs = xdivs / 2;
+ ydivs = ydivs * 2;
+ } while (xdivs > 0);
+ return false;
+ }
+
+ private:
+ std::vector<std::vector<bool>> occupiedStrata;
+};
+
+static void shuffle(float2 points[], int size, int rng_seed)
+{
+ if (rng_seed == 0) {
+ return;
+ }
+
+ constexpr int odd[8] = {0, 1, 4, 5, 10, 11, 14, 15};
+ constexpr int even[8] = {2, 3, 6, 7, 8, 9, 12, 13};
+
+ int rng_index = 0;
+ for (int yy = 0; yy < size / 16; ++yy) {
+ for (int xx = 0; xx < 8; ++xx) {
+ int other = (int)(cmj_randfloat(++rng_index, rng_seed) * (8.0f - xx) + xx);
+ float2 tmp = points[odd[other] + yy * 16];
+ points[odd[other] + yy * 16] = points[odd[xx] + yy * 16];
+ points[odd[xx] + yy * 16] = tmp;
+ }
+ for (int xx = 0; xx < 8; ++xx) {
+ int other = (int)(cmj_randfloat(++rng_index, rng_seed) * (8.0f - xx) + xx);
+ float2 tmp = points[even[other] + yy * 16];
+ points[even[other] + yy * 16] = points[even[xx] + yy * 16];
+ points[even[xx] + yy * 16] = tmp;
+ }
+ }
+}
+
+void progressive_multi_jitter_generate_2D(float2 points[], int size, int rng_seed)
+{
+ PMJ_Generator::generate_2D(points, size, rng_seed);
+ shuffle(points, size, rng_seed);
+}
+
+void progressive_multi_jitter_02_generate_2D(float2 points[], int size, int rng_seed)
+{
+ PMJ02_Generator::generate_2D(points, size, rng_seed);
+ shuffle(points, size, rng_seed);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/jitter.h b/intern/cycles/scene/jitter.h
new file mode 100644
index 00000000000..756e4a1de78
--- /dev/null
+++ b/intern/cycles/scene/jitter.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __JITTER_H__
+#define __JITTER_H__
+
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+void progressive_multi_jitter_generate_2D(float2 points[], int size, int rng_seed);
+void progressive_multi_jitter_02_generate_2D(float2 points[], int size, int rng_seed);
+
+CCL_NAMESPACE_END
+
+#endif /* __JITTER_H__ */
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
new file mode 100644
index 00000000000..83e531f42ef
--- /dev/null
+++ b/intern/cycles/scene/light.cpp
@@ -0,0 +1,1150 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device/device.h"
+
+#include "scene/background.h"
+#include "scene/film.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+#include "scene/stats.h"
+
+#include "integrator/shader_eval.h"
+
+#include "util/foreach.h"
+#include "util/hash.h"
+#include "util/log.h"
+#include "util/path.h"
+#include "util/progress.h"
+#include "util/task.h"
+
+CCL_NAMESPACE_BEGIN
+
+static void shade_background_pixels(Device *device,
+ DeviceScene *dscene,
+ int width,
+ int height,
+ vector<float3> &pixels,
+ Progress &progress)
+{
+ /* Needs to be up to data for attribute access. */
+ device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
+
+ const int size = width * height;
+ const int num_channels = 3;
+ pixels.resize(size);
+
+ /* Evaluate shader on device. */
+ ShaderEval shader_eval(device, progress);
+ shader_eval.eval(
+ SHADER_EVAL_BACKGROUND,
+ size,
+ num_channels,
+ [&](device_vector<KernelShaderEvalInput> &d_input) {
+ /* Fill coordinates for shading. */
+ KernelShaderEvalInput *d_input_data = d_input.data();
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ float u = (x + 0.5f) / width;
+ float v = (y + 0.5f) / height;
+
+ KernelShaderEvalInput in;
+ in.object = OBJECT_NONE;
+ in.prim = PRIM_NONE;
+ in.u = u;
+ in.v = v;
+ d_input_data[x + y * width] = in;
+ }
+ }
+
+ return size;
+ },
+ [&](device_vector<float> &d_output) {
+ /* Copy output to pixel buffer. */
+ float *d_output_data = d_output.data();
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ pixels[y * width + x].x = d_output_data[(y * width + x) * num_channels + 0];
+ pixels[y * width + x].y = d_output_data[(y * width + x) * num_channels + 1];
+ pixels[y * width + x].z = d_output_data[(y * width + x) * num_channels + 2];
+ }
+ }
+ });
+}
+
+/* Light */
+
+NODE_DEFINE(Light)
+{
+ NodeType *type = NodeType::add("light", create);
+
+ static NodeEnum type_enum;
+ type_enum.insert("point", LIGHT_POINT);
+ type_enum.insert("distant", LIGHT_DISTANT);
+ type_enum.insert("background", LIGHT_BACKGROUND);
+ type_enum.insert("area", LIGHT_AREA);
+ type_enum.insert("spot", LIGHT_SPOT);
+ SOCKET_ENUM(light_type, "Type", type_enum, LIGHT_POINT);
+
+ SOCKET_COLOR(strength, "Strength", one_float3());
+
+ SOCKET_POINT(co, "Co", zero_float3());
+
+ SOCKET_VECTOR(dir, "Dir", zero_float3());
+ SOCKET_FLOAT(size, "Size", 0.0f);
+ SOCKET_FLOAT(angle, "Angle", 0.0f);
+
+ SOCKET_VECTOR(axisu, "Axis U", zero_float3());
+ SOCKET_FLOAT(sizeu, "Size U", 1.0f);
+ SOCKET_VECTOR(axisv, "Axis V", zero_float3());
+ SOCKET_FLOAT(sizev, "Size V", 1.0f);
+ SOCKET_BOOLEAN(round, "Round", false);
+ SOCKET_FLOAT(spread, "Spread", M_PI_F);
+
+ SOCKET_INT(map_resolution, "Map Resolution", 0);
+
+ SOCKET_FLOAT(spot_angle, "Spot Angle", M_PI_4_F);
+ SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f);
+
+ SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
+
+ SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true);
+ SOCKET_BOOLEAN(use_mis, "Use Mis", false);
+ SOCKET_BOOLEAN(use_camera, "Use Camera", true);
+ SOCKET_BOOLEAN(use_diffuse, "Use Diffuse", true);
+ SOCKET_BOOLEAN(use_glossy, "Use Glossy", true);
+ SOCKET_BOOLEAN(use_transmission, "Use Transmission", true);
+ SOCKET_BOOLEAN(use_scatter, "Use Scatter", true);
+
+ SOCKET_INT(max_bounces, "Max Bounces", 1024);
+ SOCKET_UINT(random_id, "Random ID", 0);
+
+ SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", true);
+ SOCKET_BOOLEAN(is_portal, "Is Portal", false);
+ SOCKET_BOOLEAN(is_enabled, "Is Enabled", true);
+
+ SOCKET_NODE(shader, "Shader", Shader::get_node_type());
+
+ return type;
+}
+
+Light::Light() : Node(get_node_type())
+{
+ dereference_all_used_nodes();
+}
+
+void Light::tag_update(Scene *scene)
+{
+ if (is_modified()) {
+ scene->light_manager->tag_update(scene, LightManager::LIGHT_MODIFIED);
+ }
+}
+
+bool Light::has_contribution(Scene *scene)
+{
+ if (strength == zero_float3()) {
+ return false;
+ }
+ if (is_portal) {
+ return false;
+ }
+ if (light_type == LIGHT_BACKGROUND) {
+ return true;
+ }
+ return (shader) ? shader->has_surface_emission : scene->default_light->has_surface_emission;
+}
+
+/* Light Manager */
+
+LightManager::LightManager()
+{
+ update_flags = UPDATE_ALL;
+ need_update_background = true;
+ last_background_enabled = false;
+ last_background_resolution = 0;
+}
+
+LightManager::~LightManager()
+{
+ foreach (IESSlot *slot, ies_slots) {
+ delete slot;
+ }
+}
+
+bool LightManager::has_background_light(Scene *scene)
+{
+ foreach (Light *light, scene->lights) {
+ if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void LightManager::test_enabled_lights(Scene *scene)
+{
+ /* Make all lights enabled by default, and perform some preliminary checks
+ * needed for finer-tuning of settings (for example, check whether we've
+ * got portals or not).
+ */
+ bool has_portal = false, has_background = false;
+ foreach (Light *light, scene->lights) {
+ light->is_enabled = light->has_contribution(scene);
+ has_portal |= light->is_portal;
+ has_background |= light->light_type == LIGHT_BACKGROUND;
+ }
+
+ bool background_enabled = false;
+ int background_resolution = 0;
+
+ if (has_background) {
+ /* Ignore background light if:
+ * - If unsupported on a device
+ * - If we don't need it (no HDRs etc.)
+ */
+ Shader *shader = scene->background->get_shader(scene);
+ const bool disable_mis = !(has_portal || shader->has_surface_spatial_varying);
+ VLOG_IF(1, disable_mis) << "Background MIS has been disabled.\n";
+ foreach (Light *light, scene->lights) {
+ if (light->light_type == LIGHT_BACKGROUND) {
+ light->is_enabled = !disable_mis;
+ background_enabled = !disable_mis;
+ background_resolution = light->map_resolution;
+ }
+ }
+ }
+
+ if (last_background_enabled != background_enabled ||
+ last_background_resolution != background_resolution) {
+ last_background_enabled = background_enabled;
+ last_background_resolution = background_resolution;
+ need_update_background = true;
+ }
+}
+
+bool LightManager::object_usable_as_light(Object *object)
+{
+ Geometry *geom = object->get_geometry();
+ if (geom->geometry_type != Geometry::MESH && geom->geometry_type != Geometry::VOLUME) {
+ return false;
+ }
+ /* Skip objects with NaNs */
+ if (!object->bounds.valid()) {
+ return false;
+ }
+ /* Skip if we are not visible for BSDFs. */
+ if (!(object->get_visibility() & (PATH_RAY_DIFFUSE | PATH_RAY_GLOSSY | PATH_RAY_TRANSMIT))) {
+ return false;
+ }
+ /* Skip if we have no emission shaders. */
+ /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll
+ * iterate all geometry shaders twice (when counting and when calculating
+ * triangle area.
+ */
+ foreach (Node *node, geom->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->get_use_mis() && shader->has_surface_emission) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void LightManager::device_update_distribution(Device *,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ progress.set_status("Updating Lights", "Computing distribution");
+
+ /* count */
+ size_t num_lights = 0;
+ size_t num_portals = 0;
+ size_t num_background_lights = 0;
+ size_t num_triangles = 0;
+
+ bool background_mis = false;
+
+ foreach (Light *light, scene->lights) {
+ if (light->is_enabled) {
+ num_lights++;
+ }
+ if (light->is_portal) {
+ num_portals++;
+ }
+ }
+
+ foreach (Object *object, scene->objects) {
+ if (progress.get_cancel())
+ return;
+
+ if (!object_usable_as_light(object)) {
+ continue;
+ }
+
+ /* Count triangles. */
+ Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
+ size_t mesh_num_triangles = mesh->num_triangles();
+ for (size_t i = 0; i < mesh_num_triangles; i++) {
+ int shader_index = mesh->get_shader()[i];
+ Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
+ static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
+ scene->default_surface;
+
+ if (shader->get_use_mis() && shader->has_surface_emission) {
+ num_triangles++;
+ }
+ }
+ }
+
+ size_t num_distribution = num_triangles + num_lights;
+ VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
+
+ /* emission area */
+ KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
+ float totarea = 0.0f;
+
+ /* triangles */
+ size_t offset = 0;
+ int j = 0;
+
+ foreach (Object *object, scene->objects) {
+ if (progress.get_cancel())
+ return;
+
+ if (!object_usable_as_light(object)) {
+ j++;
+ continue;
+ }
+ /* Sum area. */
+ Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
+ bool transform_applied = mesh->transform_applied;
+ Transform tfm = object->get_tfm();
+ int object_id = j;
+ int shader_flag = 0;
+
+ if (!(object->get_visibility() & PATH_RAY_CAMERA)) {
+ shader_flag |= SHADER_EXCLUDE_CAMERA;
+ }
+ if (!(object->get_visibility() & PATH_RAY_DIFFUSE)) {
+ shader_flag |= SHADER_EXCLUDE_DIFFUSE;
+ }
+ if (!(object->get_visibility() & PATH_RAY_GLOSSY)) {
+ shader_flag |= SHADER_EXCLUDE_GLOSSY;
+ }
+ if (!(object->get_visibility() & PATH_RAY_TRANSMIT)) {
+ shader_flag |= SHADER_EXCLUDE_TRANSMIT;
+ }
+ if (!(object->get_visibility() & PATH_RAY_VOLUME_SCATTER)) {
+ shader_flag |= SHADER_EXCLUDE_SCATTER;
+ }
+ if (!(object->get_is_shadow_catcher())) {
+ shader_flag |= SHADER_EXCLUDE_SHADOW_CATCHER;
+ }
+
+ size_t mesh_num_triangles = mesh->num_triangles();
+ for (size_t i = 0; i < mesh_num_triangles; i++) {
+ int shader_index = mesh->get_shader()[i];
+ Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
+ static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
+ scene->default_surface;
+
+ if (shader->get_use_mis() && shader->has_surface_emission) {
+ distribution[offset].totarea = totarea;
+ distribution[offset].prim = i + mesh->prim_offset;
+ distribution[offset].mesh_light.shader_flag = shader_flag;
+ distribution[offset].mesh_light.object_id = object_id;
+ offset++;
+
+ Mesh::Triangle t = mesh->get_triangle(i);
+ if (!t.valid(&mesh->get_verts()[0])) {
+ continue;
+ }
+ float3 p1 = mesh->get_verts()[t.v[0]];
+ float3 p2 = mesh->get_verts()[t.v[1]];
+ float3 p3 = mesh->get_verts()[t.v[2]];
+
+ if (!transform_applied) {
+ p1 = transform_point(&tfm, p1);
+ p2 = transform_point(&tfm, p2);
+ p3 = transform_point(&tfm, p3);
+ }
+
+ totarea += triangle_area(p1, p2, p3);
+ }
+ }
+
+ j++;
+ }
+
+ float trianglearea = totarea;
+ /* point lights */
+ bool use_lamp_mis = false;
+ int light_index = 0;
+
+ if (num_lights > 0) {
+ float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
+ foreach (Light *light, scene->lights) {
+ if (!light->is_enabled)
+ continue;
+
+ distribution[offset].totarea = totarea;
+ distribution[offset].prim = ~light_index;
+ distribution[offset].lamp.pad = 1.0f;
+ distribution[offset].lamp.size = light->size;
+ totarea += lightarea;
+
+ if (light->light_type == LIGHT_DISTANT) {
+ use_lamp_mis |= (light->angle > 0.0f && light->use_mis);
+ }
+ else if (light->light_type == LIGHT_POINT || light->light_type == LIGHT_SPOT) {
+ use_lamp_mis |= (light->size > 0.0f && light->use_mis);
+ }
+ else if (light->light_type == LIGHT_AREA) {
+ use_lamp_mis |= light->use_mis;
+ }
+ else if (light->light_type == LIGHT_BACKGROUND) {
+ num_background_lights++;
+ background_mis |= light->use_mis;
+ }
+
+ light_index++;
+ offset++;
+ }
+ }
+
+ /* normalize cumulative distribution functions */
+ distribution[num_distribution].totarea = totarea;
+ distribution[num_distribution].prim = 0.0f;
+ distribution[num_distribution].lamp.pad = 0.0f;
+ distribution[num_distribution].lamp.size = 0.0f;
+
+ if (totarea > 0.0f) {
+ for (size_t i = 0; i < num_distribution; i++)
+ distribution[i].totarea /= totarea;
+ distribution[num_distribution].totarea = 1.0f;
+ }
+
+ if (progress.get_cancel())
+ return;
+
+ /* update device */
+ KernelIntegrator *kintegrator = &dscene->data.integrator;
+ KernelBackground *kbackground = &dscene->data.background;
+ KernelFilm *kfilm = &dscene->data.film;
+ kintegrator->use_direct_light = (totarea > 0.0f);
+
+ if (kintegrator->use_direct_light) {
+ /* number of emissives */
+ kintegrator->num_distribution = num_distribution;
+
+ /* precompute pdfs */
+ kintegrator->pdf_triangles = 0.0f;
+ kintegrator->pdf_lights = 0.0f;
+
+ /* sample one, with 0.5 probability of light or triangle */
+ kintegrator->num_all_lights = num_lights;
+
+ if (trianglearea > 0.0f) {
+ kintegrator->pdf_triangles = 1.0f / trianglearea;
+ if (num_lights)
+ kintegrator->pdf_triangles *= 0.5f;
+ }
+
+ if (num_lights) {
+ kintegrator->pdf_lights = 1.0f / num_lights;
+ if (trianglearea > 0.0f)
+ kintegrator->pdf_lights *= 0.5f;
+ }
+
+ kintegrator->use_lamp_mis = use_lamp_mis;
+
+ /* bit of an ugly hack to compensate for emitting triangles influencing
+ * amount of samples we get for this pass */
+ kfilm->pass_shadow_scale = 1.0f;
+
+ if (kintegrator->pdf_triangles != 0.0f)
+ kfilm->pass_shadow_scale /= 0.5f;
+
+ if (num_background_lights < num_lights)
+ kfilm->pass_shadow_scale /= (float)(num_lights - num_background_lights) / (float)num_lights;
+
+ /* CDF */
+ dscene->light_distribution.copy_to_device();
+
+ /* Portals */
+ if (num_portals > 0) {
+ kbackground->portal_offset = light_index;
+ kbackground->num_portals = num_portals;
+ kbackground->portal_weight = 1.0f;
+ }
+ else {
+ kbackground->num_portals = 0;
+ kbackground->portal_offset = 0;
+ kbackground->portal_weight = 0.0f;
+ }
+
+ /* Map */
+ kbackground->map_weight = background_mis ? 1.0f : 0.0f;
+ }
+ else {
+ dscene->light_distribution.free();
+
+ kintegrator->num_distribution = 0;
+ kintegrator->num_all_lights = 0;
+ kintegrator->pdf_triangles = 0.0f;
+ kintegrator->pdf_lights = 0.0f;
+ kintegrator->use_lamp_mis = false;
+
+ kbackground->num_portals = 0;
+ kbackground->portal_offset = 0;
+ kbackground->portal_weight = 0.0f;
+ kbackground->sun_weight = 0.0f;
+ kbackground->map_weight = 0.0f;
+
+ kfilm->pass_shadow_scale = 1.0f;
+ }
+}
+
+static void background_cdf(
+ int start, int end, int res_x, int res_y, const vector<float3> *pixels, float2 *cond_cdf)
+{
+ int cdf_width = res_x + 1;
+ /* Conditional CDFs (rows, U direction). */
+ for (int i = start; i < end; i++) {
+ float sin_theta = sinf(M_PI_F * (i + 0.5f) / res_y);
+ float3 env_color = (*pixels)[i * res_x];
+ float ave_luminance = average(env_color);
+
+ cond_cdf[i * cdf_width].x = ave_luminance * sin_theta;
+ cond_cdf[i * cdf_width].y = 0.0f;
+
+ for (int j = 1; j < res_x; j++) {
+ env_color = (*pixels)[i * res_x + j];
+ ave_luminance = average(env_color);
+
+ cond_cdf[i * cdf_width + j].x = ave_luminance * sin_theta;
+ cond_cdf[i * cdf_width + j].y = cond_cdf[i * cdf_width + j - 1].y +
+ cond_cdf[i * cdf_width + j - 1].x / res_x;
+ }
+
+ const float cdf_total = cond_cdf[i * cdf_width + res_x - 1].y +
+ cond_cdf[i * cdf_width + res_x - 1].x / res_x;
+
+ /* stuff the total into the brightness value for the last entry, because
+ * we are going to normalize the CDFs to 0.0 to 1.0 afterwards */
+ cond_cdf[i * cdf_width + res_x].x = cdf_total;
+
+ if (cdf_total > 0.0f) {
+ const float cdf_total_inv = 1.0f / cdf_total;
+ for (int j = 1; j < res_x; j++) {
+ cond_cdf[i * cdf_width + j].y *= cdf_total_inv;
+ }
+ }
+
+ cond_cdf[i * cdf_width + res_x].y = 1.0f;
+ }
+}
+
+void LightManager::device_update_background(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ KernelBackground *kbackground = &dscene->data.background;
+ Light *background_light = NULL;
+
+ /* find background light */
+ foreach (Light *light, scene->lights) {
+ if (light->light_type == LIGHT_BACKGROUND) {
+ background_light = light;
+ break;
+ }
+ }
+
+ /* no background light found, signal renderer to skip sampling */
+ if (!background_light || !background_light->is_enabled) {
+ kbackground->map_res_x = 0;
+ kbackground->map_res_y = 0;
+ kbackground->map_weight = 0.0f;
+ kbackground->sun_weight = 0.0f;
+ kbackground->use_mis = (kbackground->portal_weight > 0.0f);
+ return;
+ }
+
+ progress.set_status("Updating Lights", "Importance map");
+
+ assert(dscene->data.integrator.use_direct_light);
+
+ int2 environment_res = make_int2(0, 0);
+ Shader *shader = scene->background->get_shader(scene);
+ int num_suns = 0;
+ foreach (ShaderNode *node, shader->graph->nodes) {
+ if (node->type == EnvironmentTextureNode::get_node_type()) {
+ EnvironmentTextureNode *env = (EnvironmentTextureNode *)node;
+ ImageMetaData metadata;
+ if (!env->handle.empty()) {
+ ImageMetaData metadata = env->handle.metadata();
+ environment_res.x = max(environment_res.x, metadata.width);
+ environment_res.y = max(environment_res.y, metadata.height);
+ }
+ }
+ if (node->type == SkyTextureNode::get_node_type()) {
+ SkyTextureNode *sky = (SkyTextureNode *)node;
+ if (sky->get_sky_type() == NODE_SKY_NISHITA && sky->get_sun_disc()) {
+ /* Ensure that the input coordinates aren't transformed before they reach the node.
+ * If that is the case, the logic used for sampling the sun's location does not work
+ * and we have to fall back to map-based sampling. */
+ const ShaderInput *vec_in = sky->input("Vector");
+ if (vec_in && vec_in->link && vec_in->link->parent) {
+ ShaderNode *vec_src = vec_in->link->parent;
+ if ((vec_src->type != TextureCoordinateNode::get_node_type()) ||
+ (vec_in->link != vec_src->output("Generated"))) {
+ environment_res.x = max(environment_res.x, 4096);
+ environment_res.y = max(environment_res.y, 2048);
+ continue;
+ }
+ }
+
+ /* Determine sun direction from lat/long and texture mapping. */
+ float latitude = sky->get_sun_elevation();
+ float longitude = M_2PI_F - sky->get_sun_rotation() + M_PI_2_F;
+ float3 sun_direction = make_float3(
+ cosf(latitude) * cosf(longitude), cosf(latitude) * sinf(longitude), sinf(latitude));
+ Transform sky_transform = transform_inverse(sky->tex_mapping.compute_transform());
+ sun_direction = transform_direction(&sky_transform, sun_direction);
+
+ /* Pack sun direction and size. */
+ float half_angle = sky->get_sun_size() * 0.5f;
+ kbackground->sun = make_float4(
+ sun_direction.x, sun_direction.y, sun_direction.z, half_angle);
+
+ kbackground->sun_weight = 4.0f;
+ environment_res.x = max(environment_res.x, 512);
+ environment_res.y = max(environment_res.y, 256);
+ num_suns++;
+ }
+ }
+ }
+
+ /* If there's more than one sun, fall back to map sampling instead. */
+ if (num_suns != 1) {
+ kbackground->sun_weight = 0.0f;
+ environment_res.x = max(environment_res.x, 4096);
+ environment_res.y = max(environment_res.y, 2048);
+ }
+
+ /* Enable MIS for background sampling if any strategy is active. */
+ kbackground->use_mis = (kbackground->portal_weight + kbackground->map_weight +
+ kbackground->sun_weight) > 0.0f;
+
+ /* get the resolution from the light's size (we stuff it in there) */
+ int2 res = make_int2(background_light->map_resolution, background_light->map_resolution / 2);
+ /* If the resolution isn't set manually, try to find an environment texture. */
+ if (res.x == 0) {
+ res = environment_res;
+ if (res.x > 0 && res.y > 0) {
+ VLOG(2) << "Automatically set World MIS resolution to " << res.x << " by " << res.y << "\n";
+ }
+ }
+ /* If it's still unknown, just use the default. */
+ if (res.x == 0 || res.y == 0) {
+ res = make_int2(1024, 512);
+ VLOG(2) << "Setting World MIS resolution to default\n";
+ }
+ kbackground->map_res_x = res.x;
+ kbackground->map_res_y = res.y;
+
+ vector<float3> pixels;
+ shade_background_pixels(device, dscene, res.x, res.y, pixels, progress);
+
+ if (progress.get_cancel())
+ return;
+
+ /* build row distributions and column distribution for the infinite area environment light */
+ int cdf_width = res.x + 1;
+ float2 *marg_cdf = dscene->light_background_marginal_cdf.alloc(res.y + 1);
+ float2 *cond_cdf = dscene->light_background_conditional_cdf.alloc(cdf_width * res.y);
+
+ double time_start = time_dt();
+
+ /* Create CDF in parallel. */
+ const int rows_per_task = divide_up(10240, res.x);
+ parallel_for(blocked_range<size_t>(0, res.y, rows_per_task),
+ [&](const blocked_range<size_t> &r) {
+ background_cdf(r.begin(), r.end(), res.x, res.y, &pixels, cond_cdf);
+ });
+
+ /* marginal CDFs (column, V direction, sum of rows) */
+ marg_cdf[0].x = cond_cdf[res.x].x;
+ marg_cdf[0].y = 0.0f;
+
+ for (int i = 1; i < res.y; i++) {
+ marg_cdf[i].x = cond_cdf[i * cdf_width + res.x].x;
+ marg_cdf[i].y = marg_cdf[i - 1].y + marg_cdf[i - 1].x / res.y;
+ }
+
+ float cdf_total = marg_cdf[res.y - 1].y + marg_cdf[res.y - 1].x / res.y;
+ marg_cdf[res.y].x = cdf_total;
+
+ if (cdf_total > 0.0f)
+ for (int i = 1; i < res.y; i++)
+ marg_cdf[i].y /= cdf_total;
+
+ marg_cdf[res.y].y = 1.0f;
+
+ VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n";
+
+ /* update device */
+ dscene->light_background_marginal_cdf.copy_to_device();
+ dscene->light_background_conditional_cdf.copy_to_device();
+}
+
+void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *scene)
+{
+ int num_scene_lights = scene->lights.size();
+
+ int num_lights = 0;
+ foreach (Light *light, scene->lights) {
+ if (light->is_enabled || light->is_portal) {
+ num_lights++;
+ }
+ }
+
+ KernelLight *klights = dscene->lights.alloc(num_lights);
+
+ if (num_lights == 0) {
+ VLOG(1) << "No effective light, ignoring points update.";
+ return;
+ }
+
+ int light_index = 0;
+
+ foreach (Light *light, scene->lights) {
+ if (!light->is_enabled) {
+ continue;
+ }
+
+ float3 co = light->co;
+ Shader *shader = (light->shader) ? light->shader : scene->default_light;
+ int shader_id = scene->shader_manager->get_shader_id(shader);
+ int max_bounces = light->max_bounces;
+ float random = (float)light->random_id * (1.0f / (float)0xFFFFFFFF);
+
+ if (!light->cast_shadow)
+ shader_id &= ~SHADER_CAST_SHADOW;
+
+ if (!light->use_camera) {
+ shader_id |= SHADER_EXCLUDE_CAMERA;
+ }
+ if (!light->use_diffuse) {
+ shader_id |= SHADER_EXCLUDE_DIFFUSE;
+ }
+ if (!light->use_glossy) {
+ shader_id |= SHADER_EXCLUDE_GLOSSY;
+ }
+ if (!light->use_transmission) {
+ shader_id |= SHADER_EXCLUDE_TRANSMIT;
+ }
+ if (!light->use_scatter) {
+ shader_id |= SHADER_EXCLUDE_SCATTER;
+ }
+ if (!light->is_shadow_catcher) {
+ shader_id |= SHADER_EXCLUDE_SHADOW_CATCHER;
+ }
+
+ klights[light_index].type = light->light_type;
+ klights[light_index].strength[0] = light->strength.x;
+ klights[light_index].strength[1] = light->strength.y;
+ klights[light_index].strength[2] = light->strength.z;
+
+ if (light->light_type == LIGHT_POINT) {
+ shader_id &= ~SHADER_AREA_LIGHT;
+
+ float radius = light->size;
+ float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f;
+
+ if (light->use_mis && radius > 0.0f)
+ shader_id |= SHADER_USE_MIS;
+
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].spot.radius = radius;
+ klights[light_index].spot.invarea = invarea;
+ }
+ else if (light->light_type == LIGHT_DISTANT) {
+ shader_id &= ~SHADER_AREA_LIGHT;
+
+ float angle = light->angle / 2.0f;
+ float radius = tanf(angle);
+ float cosangle = cosf(angle);
+ float area = M_PI_F * radius * radius;
+ float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
+ float3 dir = light->dir;
+
+ dir = safe_normalize(dir);
+
+ if (light->use_mis && area > 0.0f)
+ shader_id |= SHADER_USE_MIS;
+
+ klights[light_index].co[0] = dir.x;
+ klights[light_index].co[1] = dir.y;
+ klights[light_index].co[2] = dir.z;
+
+ klights[light_index].distant.invarea = invarea;
+ klights[light_index].distant.radius = radius;
+ klights[light_index].distant.cosangle = cosangle;
+ }
+ else if (light->light_type == LIGHT_BACKGROUND) {
+ uint visibility = scene->background->get_visibility();
+
+ shader_id &= ~SHADER_AREA_LIGHT;
+ shader_id |= SHADER_USE_MIS;
+
+ if (!(visibility & PATH_RAY_DIFFUSE)) {
+ shader_id |= SHADER_EXCLUDE_DIFFUSE;
+ }
+ if (!(visibility & PATH_RAY_GLOSSY)) {
+ shader_id |= SHADER_EXCLUDE_GLOSSY;
+ }
+ if (!(visibility & PATH_RAY_TRANSMIT)) {
+ shader_id |= SHADER_EXCLUDE_TRANSMIT;
+ }
+ if (!(visibility & PATH_RAY_VOLUME_SCATTER)) {
+ shader_id |= SHADER_EXCLUDE_SCATTER;
+ }
+ }
+ else if (light->light_type == LIGHT_AREA) {
+ float3 axisu = light->axisu * (light->sizeu * light->size);
+ float3 axisv = light->axisv * (light->sizev * light->size);
+ float area = len(axisu) * len(axisv);
+ if (light->round) {
+ area *= -M_PI_4_F;
+ }
+ float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
+ float3 dir = light->dir;
+
+ /* Convert from spread angle 0..180 to 90..0, clamping to a minimum
+ * angle to avoid excessive noise. */
+ const float min_spread_angle = 1.0f * M_PI_F / 180.0f;
+ const float spread_angle = 0.5f * (M_PI_F - max(light->spread, min_spread_angle));
+ /* Normalization computed using:
+ * integrate cos(x) * (1 - tan(x) * tan(a)) * sin(x) from x = 0 to pi/2 - a. */
+ const float tan_spread = tanf(spread_angle);
+ const float normalize_spread = 2.0f / (2.0f + (2.0f * spread_angle - M_PI_F) * tan_spread);
+
+ dir = safe_normalize(dir);
+
+ if (light->use_mis && area != 0.0f)
+ shader_id |= SHADER_USE_MIS;
+
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].area.axisu[0] = axisu.x;
+ klights[light_index].area.axisu[1] = axisu.y;
+ klights[light_index].area.axisu[2] = axisu.z;
+ klights[light_index].area.axisv[0] = axisv.x;
+ klights[light_index].area.axisv[1] = axisv.y;
+ klights[light_index].area.axisv[2] = axisv.z;
+ klights[light_index].area.invarea = invarea;
+ klights[light_index].area.dir[0] = dir.x;
+ klights[light_index].area.dir[1] = dir.y;
+ klights[light_index].area.dir[2] = dir.z;
+ klights[light_index].area.tan_spread = tan_spread;
+ klights[light_index].area.normalize_spread = normalize_spread;
+ }
+ else if (light->light_type == LIGHT_SPOT) {
+ shader_id &= ~SHADER_AREA_LIGHT;
+
+ float radius = light->size;
+ float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f;
+ float spot_angle = cosf(light->spot_angle * 0.5f);
+ float spot_smooth = (1.0f - spot_angle) * light->spot_smooth;
+ float3 dir = light->dir;
+
+ dir = safe_normalize(dir);
+
+ if (light->use_mis && radius > 0.0f)
+ shader_id |= SHADER_USE_MIS;
+
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].spot.radius = radius;
+ klights[light_index].spot.invarea = invarea;
+ klights[light_index].spot.spot_angle = spot_angle;
+ klights[light_index].spot.spot_smooth = spot_smooth;
+ klights[light_index].spot.dir[0] = dir.x;
+ klights[light_index].spot.dir[1] = dir.y;
+ klights[light_index].spot.dir[2] = dir.z;
+ }
+
+ klights[light_index].shader_id = shader_id;
+
+ klights[light_index].max_bounces = max_bounces;
+ klights[light_index].random = random;
+
+ klights[light_index].tfm = light->tfm;
+ klights[light_index].itfm = transform_inverse(light->tfm);
+
+ light_index++;
+ }
+
+ /* TODO(sergey): Consider moving portals update to their own function
+ * keeping this one more manageable.
+ */
+ foreach (Light *light, scene->lights) {
+ if (!light->is_portal)
+ continue;
+ assert(light->light_type == LIGHT_AREA);
+
+ float3 co = light->co;
+ float3 axisu = light->axisu * (light->sizeu * light->size);
+ float3 axisv = light->axisv * (light->sizev * light->size);
+ float area = len(axisu) * len(axisv);
+ if (light->round) {
+ area *= -M_PI_4_F;
+ }
+ float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
+ float3 dir = light->dir;
+
+ dir = safe_normalize(dir);
+
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].area.axisu[0] = axisu.x;
+ klights[light_index].area.axisu[1] = axisu.y;
+ klights[light_index].area.axisu[2] = axisu.z;
+ klights[light_index].area.axisv[0] = axisv.x;
+ klights[light_index].area.axisv[1] = axisv.y;
+ klights[light_index].area.axisv[2] = axisv.z;
+ klights[light_index].area.invarea = invarea;
+ klights[light_index].area.dir[0] = dir.x;
+ klights[light_index].area.dir[1] = dir.y;
+ klights[light_index].area.dir[2] = dir.z;
+ klights[light_index].tfm = light->tfm;
+ klights[light_index].itfm = transform_inverse(light->tfm);
+
+ light_index++;
+ }
+
+ VLOG(1) << "Number of lights sent to the device: " << light_index;
+
+ VLOG(1) << "Number of lights without contribution: " << num_scene_lights - light_index;
+
+ dscene->lights.copy_to_device();
+}
+
+void LightManager::device_update(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ if (!need_update())
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->light.times.add_entry({"device_update", time});
+ }
+ });
+
+ VLOG(1) << "Total " << scene->lights.size() << " lights.";
+
+ /* Detect which lights are enabled, also determines if we need to update the background. */
+ test_enabled_lights(scene);
+
+ device_free(device, dscene, need_update_background);
+
+ device_update_points(device, dscene, scene);
+ if (progress.get_cancel())
+ return;
+
+ device_update_distribution(device, dscene, scene, progress);
+ if (progress.get_cancel())
+ return;
+
+ if (need_update_background) {
+ device_update_background(device, dscene, scene, progress);
+ if (progress.get_cancel())
+ return;
+ }
+
+ device_update_ies(dscene);
+ if (progress.get_cancel())
+ return;
+
+ update_flags = UPDATE_NONE;
+ need_update_background = false;
+}
+
+void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_background)
+{
+ dscene->light_distribution.free();
+ dscene->lights.free();
+ if (free_background) {
+ dscene->light_background_marginal_cdf.free();
+ dscene->light_background_conditional_cdf.free();
+ }
+ dscene->ies_lights.free();
+}
+
+void LightManager::tag_update(Scene * /*scene*/, uint32_t flag)
+{
+ update_flags |= flag;
+}
+
+bool LightManager::need_update() const
+{
+ return update_flags != UPDATE_NONE;
+}
+
+int LightManager::add_ies_from_file(const string &filename)
+{
+ string content;
+
+ /* If the file can't be opened, call with an empty line */
+ if (filename.empty() || !path_read_text(filename.c_str(), content)) {
+ content = "\n";
+ }
+
+ return add_ies(content);
+}
+
+int LightManager::add_ies(const string &content)
+{
+ uint hash = hash_string(content.c_str());
+
+ thread_scoped_lock ies_lock(ies_mutex);
+
+ /* Check whether this IES already has a slot. */
+ size_t slot;
+ for (slot = 0; slot < ies_slots.size(); slot++) {
+ if (ies_slots[slot]->hash == hash) {
+ ies_slots[slot]->users++;
+ return slot;
+ }
+ }
+
+ /* Try to find an empty slot for the new IES. */
+ for (slot = 0; slot < ies_slots.size(); slot++) {
+ if (ies_slots[slot]->users == 0 && ies_slots[slot]->hash == 0) {
+ break;
+ }
+ }
+
+ /* If there's no free slot, add one. */
+ if (slot == ies_slots.size()) {
+ ies_slots.push_back(new IESSlot());
+ }
+
+ ies_slots[slot]->ies.load(content);
+ ies_slots[slot]->users = 1;
+ ies_slots[slot]->hash = hash;
+
+ update_flags = UPDATE_ALL;
+ need_update_background = true;
+
+ return slot;
+}
+
+void LightManager::remove_ies(int slot)
+{
+ thread_scoped_lock ies_lock(ies_mutex);
+
+ if (slot < 0 || slot >= ies_slots.size()) {
+ assert(false);
+ return;
+ }
+
+ assert(ies_slots[slot]->users > 0);
+ ies_slots[slot]->users--;
+
+ /* If the slot has no more users, update the device to remove it. */
+ if (ies_slots[slot]->users == 0) {
+ update_flags |= UPDATE_ALL;
+ need_update_background = true;
+ }
+}
+
+void LightManager::device_update_ies(DeviceScene *dscene)
+{
+ /* Clear empty slots. */
+ foreach (IESSlot *slot, ies_slots) {
+ if (slot->users == 0) {
+ slot->hash = 0;
+ slot->ies.clear();
+ }
+ }
+
+ /* Shrink the slot table by removing empty slots at the end. */
+ int slot_end;
+ for (slot_end = ies_slots.size(); slot_end; slot_end--) {
+ if (ies_slots[slot_end - 1]->users > 0) {
+ /* If the preceding slot has users, we found the new end of the table. */
+ break;
+ }
+ else {
+ /* The slot will be past the new end of the table, so free it. */
+ delete ies_slots[slot_end - 1];
+ }
+ }
+ ies_slots.resize(slot_end);
+
+ if (ies_slots.size() > 0) {
+ int packed_size = 0;
+ foreach (IESSlot *slot, ies_slots) {
+ packed_size += slot->ies.packed_size();
+ }
+
+ /* ies_lights starts with an offset table that contains the offset of every slot,
+ * or -1 if the slot is invalid.
+ * Following that table, the packed valid IES lights are stored. */
+ float *data = dscene->ies_lights.alloc(ies_slots.size() + packed_size);
+
+ int offset = ies_slots.size();
+ for (int i = 0; i < ies_slots.size(); i++) {
+ int size = ies_slots[i]->ies.packed_size();
+ if (size > 0) {
+ data[i] = __int_as_float(offset);
+ ies_slots[i]->ies.pack(data + offset);
+ offset += size;
+ }
+ else {
+ data[i] = __int_as_float(-1);
+ }
+ }
+
+ dscene->ies_lights.copy_to_device();
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/light.h b/intern/cycles/scene/light.h
new file mode 100644
index 00000000000..97ec9792860
--- /dev/null
+++ b/intern/cycles/scene/light.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LIGHT_H__
+#define __LIGHT_H__
+
+#include "kernel/types.h"
+
+#include "graph/node.h"
+
+/* included as Light::set_shader defined through NODE_SOCKET_API does not select
+ * the right Node::set overload as it does not know that Shader is a Node */
+#include "scene/shader.h"
+
+#include "util/ies.h"
+#include "util/thread.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Object;
+class Progress;
+class Scene;
+class Shader;
+
+class Light : public Node {
+ public:
+ NODE_DECLARE;
+
+ Light();
+
+ NODE_SOCKET_API(LightType, light_type)
+ NODE_SOCKET_API(float3, strength)
+ NODE_SOCKET_API(float3, co)
+
+ NODE_SOCKET_API(float3, dir)
+ NODE_SOCKET_API(float, size)
+ NODE_SOCKET_API(float, angle)
+
+ NODE_SOCKET_API(float3, axisu)
+ NODE_SOCKET_API(float, sizeu)
+ NODE_SOCKET_API(float3, axisv)
+ NODE_SOCKET_API(float, sizev)
+ NODE_SOCKET_API(bool, round)
+ NODE_SOCKET_API(float, spread)
+
+ NODE_SOCKET_API(Transform, tfm)
+
+ NODE_SOCKET_API(int, map_resolution)
+
+ NODE_SOCKET_API(float, spot_angle)
+ NODE_SOCKET_API(float, spot_smooth)
+
+ NODE_SOCKET_API(bool, cast_shadow)
+ NODE_SOCKET_API(bool, use_mis)
+ NODE_SOCKET_API(bool, use_camera)
+ NODE_SOCKET_API(bool, use_diffuse)
+ NODE_SOCKET_API(bool, use_glossy)
+ NODE_SOCKET_API(bool, use_transmission)
+ NODE_SOCKET_API(bool, use_scatter)
+
+ NODE_SOCKET_API(bool, is_shadow_catcher)
+ NODE_SOCKET_API(bool, is_portal)
+ NODE_SOCKET_API(bool, is_enabled)
+
+ NODE_SOCKET_API(Shader *, shader)
+ NODE_SOCKET_API(int, max_bounces)
+ NODE_SOCKET_API(uint, random_id)
+
+ void tag_update(Scene *scene);
+
+ /* Check whether the light has contribution the scene. */
+ bool has_contribution(Scene *scene);
+
+ friend class LightManager;
+};
+
+class LightManager {
+ public:
+ enum : uint32_t {
+ MESH_NEED_REBUILD = (1 << 0),
+ EMISSIVE_MESH_MODIFIED = (1 << 1),
+ LIGHT_MODIFIED = (1 << 2),
+ LIGHT_ADDED = (1 << 3),
+ LIGHT_REMOVED = (1 << 4),
+ OBJECT_MANAGER = (1 << 5),
+ SHADER_COMPILED = (1 << 6),
+ SHADER_MODIFIED = (1 << 7),
+
+ /* tag everything in the manager for an update */
+ UPDATE_ALL = ~0u,
+
+ UPDATE_NONE = 0u,
+ };
+
+ /* Need to update background (including multiple importance map) */
+ bool need_update_background;
+
+ LightManager();
+ ~LightManager();
+
+ /* IES texture management */
+ int add_ies(const string &ies);
+ int add_ies_from_file(const string &filename);
+ void remove_ies(int slot);
+
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
+ void device_free(Device *device, DeviceScene *dscene, const bool free_background = true);
+
+ void tag_update(Scene *scene, uint32_t flag);
+
+ bool need_update() const;
+
+ /* Check whether there is a background light. */
+ bool has_background_light(Scene *scene);
+
+ protected:
+ /* Optimization: disable light which is either unsupported or
+ * which doesn't contribute to the scene or which is only used for MIS
+ * and scene doesn't need MIS.
+ */
+ void test_enabled_lights(Scene *scene);
+
+ void device_update_points(Device *device, DeviceScene *dscene, Scene *scene);
+ void device_update_distribution(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress);
+ void device_update_background(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress);
+ void device_update_ies(DeviceScene *dscene);
+
+ /* Check whether light manager can use the object as a light-emissive. */
+ bool object_usable_as_light(Object *object);
+
+ struct IESSlot {
+ IESFile ies;
+ uint hash;
+ int users;
+ };
+
+ vector<IESSlot *> ies_slots;
+ thread_mutex ies_mutex;
+
+ bool last_background_enabled;
+ int last_background_resolution;
+
+ uint32_t update_flags;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __LIGHT_H__ */
diff --git a/intern/cycles/scene/mesh.cpp b/intern/cycles/scene/mesh.cpp
new file mode 100644
index 00000000000..f47dab30869
--- /dev/null
+++ b/intern/cycles/scene/mesh.cpp
@@ -0,0 +1,812 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bvh/build.h"
+#include "bvh/bvh.h"
+
+#include "device/device.h"
+
+#include "scene/hair.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "scene/shader_graph.h"
+
+#include "subd/patch_table.h"
+#include "subd/split.h"
+
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/progress.h"
+#include "util/set.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Triangle */
+
+void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox &bounds) const
+{
+ bounds.grow(verts[v[0]]);
+ bounds.grow(verts[v[1]]);
+ bounds.grow(verts[v[2]]);
+}
+
+void Mesh::Triangle::motion_verts(const float3 *verts,
+ const float3 *vert_steps,
+ size_t num_verts,
+ size_t num_steps,
+ float time,
+ float3 r_verts[3]) const
+{
+ /* Figure out which steps we need to fetch and their interpolation factor. */
+ const size_t max_step = num_steps - 1;
+ const size_t step = min((int)(time * max_step), max_step - 1);
+ const float t = time * max_step - step;
+ /* Fetch vertex coordinates. */
+ float3 curr_verts[3];
+ float3 next_verts[3];
+ verts_for_step(verts, vert_steps, num_verts, num_steps, step, curr_verts);
+ verts_for_step(verts, vert_steps, num_verts, num_steps, step + 1, next_verts);
+ /* Interpolate between steps. */
+ r_verts[0] = (1.0f - t) * curr_verts[0] + t * next_verts[0];
+ r_verts[1] = (1.0f - t) * curr_verts[1] + t * next_verts[1];
+ r_verts[2] = (1.0f - t) * curr_verts[2] + t * next_verts[2];
+}
+
+void Mesh::Triangle::verts_for_step(const float3 *verts,
+ const float3 *vert_steps,
+ size_t num_verts,
+ size_t num_steps,
+ size_t step,
+ float3 r_verts[3]) const
+{
+ const size_t center_step = ((num_steps - 1) / 2);
+ if (step == center_step) {
+ /* Center step: regular vertex location. */
+ r_verts[0] = verts[v[0]];
+ r_verts[1] = verts[v[1]];
+ r_verts[2] = verts[v[2]];
+ }
+ else {
+ /* Center step not stored in the attribute array array. */
+ if (step > center_step) {
+ step--;
+ }
+ size_t offset = step * num_verts;
+ r_verts[0] = vert_steps[offset + v[0]];
+ r_verts[1] = vert_steps[offset + v[1]];
+ r_verts[2] = vert_steps[offset + v[2]];
+ }
+}
+
+float3 Mesh::Triangle::compute_normal(const float3 *verts) const
+{
+ const float3 &v0 = verts[v[0]];
+ const float3 &v1 = verts[v[1]];
+ const float3 &v2 = verts[v[2]];
+ const float3 norm = cross(v1 - v0, v2 - v0);
+ const float normlen = len(norm);
+ if (normlen == 0.0f) {
+ return make_float3(1.0f, 0.0f, 0.0f);
+ }
+ return norm / normlen;
+}
+
+bool Mesh::Triangle::valid(const float3 *verts) const
+{
+ return isfinite3_safe(verts[v[0]]) && isfinite3_safe(verts[v[1]]) && isfinite3_safe(verts[v[2]]);
+}
+
+/* SubdFace */
+
+float3 Mesh::SubdFace::normal(const Mesh *mesh) const
+{
+ float3 v0 = mesh->verts[mesh->subd_face_corners[start_corner + 0]];
+ float3 v1 = mesh->verts[mesh->subd_face_corners[start_corner + 1]];
+ float3 v2 = mesh->verts[mesh->subd_face_corners[start_corner + 2]];
+
+ return safe_normalize(cross(v1 - v0, v2 - v0));
+}
+
+/* Mesh */
+
+NODE_DEFINE(Mesh)
+{
+ NodeType *type = NodeType::add("mesh", create, NodeType::NONE, Geometry::get_node_base_type());
+
+ SOCKET_INT_ARRAY(triangles, "Triangles", array<int>());
+ SOCKET_POINT_ARRAY(verts, "Vertices", array<float3>());
+ SOCKET_INT_ARRAY(shader, "Shader", array<int>());
+ SOCKET_BOOLEAN_ARRAY(smooth, "Smooth", array<bool>());
+
+ SOCKET_INT_ARRAY(triangle_patch, "Triangle Patch", array<int>());
+ SOCKET_POINT2_ARRAY(vert_patch_uv, "Patch UVs", array<float2>());
+
+ static NodeEnum subdivision_type_enum;
+ subdivision_type_enum.insert("none", SUBDIVISION_NONE);
+ subdivision_type_enum.insert("linear", SUBDIVISION_LINEAR);
+ subdivision_type_enum.insert("catmull_clark", SUBDIVISION_CATMULL_CLARK);
+ SOCKET_ENUM(subdivision_type, "Subdivision Type", subdivision_type_enum, SUBDIVISION_NONE);
+
+ SOCKET_INT_ARRAY(subd_creases_edge, "Subdivision Crease Edges", array<int>());
+ SOCKET_FLOAT_ARRAY(subd_creases_weight, "Subdivision Crease Weights", array<float>());
+ SOCKET_INT_ARRAY(subd_face_corners, "Subdivision Face Corners", array<int>());
+ SOCKET_INT_ARRAY(subd_start_corner, "Subdivision Face Start Corner", array<int>());
+ SOCKET_INT_ARRAY(subd_num_corners, "Subdivision Face Corner Count", array<int>());
+ SOCKET_INT_ARRAY(subd_shader, "Subdivision Face Shader", array<int>());
+ SOCKET_BOOLEAN_ARRAY(subd_smooth, "Subdivision Face Smooth", array<bool>());
+ SOCKET_INT_ARRAY(subd_ptex_offset, "Subdivision Face PTex Offset", array<int>());
+ SOCKET_INT(num_ngons, "NGons Number", 0);
+
+ /* Subdivisions parameters */
+ SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 0.0f)
+ SOCKET_INT(subd_max_level, "Subdivision Dicing Rate", 0);
+ SOCKET_TRANSFORM(subd_objecttoworld, "Subdivision Object Transform", transform_identity());
+
+ return type;
+}
+
+SubdParams *Mesh::get_subd_params()
+{
+ if (subdivision_type == SubdivisionType::SUBDIVISION_NONE) {
+ return nullptr;
+ }
+
+ if (!subd_params) {
+ subd_params = new SubdParams(this);
+ }
+
+ subd_params->dicing_rate = subd_dicing_rate;
+ subd_params->max_level = subd_max_level;
+ subd_params->objecttoworld = subd_objecttoworld;
+
+ return subd_params;
+}
+
+bool Mesh::need_tesselation()
+{
+ return get_subd_params() && (verts_is_modified() || subd_dicing_rate_is_modified() ||
+ subd_objecttoworld_is_modified() || subd_max_level_is_modified());
+}
+
+Mesh::Mesh(const NodeType *node_type, Type geom_type_)
+ : Geometry(node_type, geom_type_), subd_attributes(this, ATTR_PRIM_SUBD)
+{
+ vert_offset = 0;
+
+ patch_offset = 0;
+ face_offset = 0;
+ corner_offset = 0;
+
+ num_subd_verts = 0;
+ num_subd_faces = 0;
+
+ num_ngons = 0;
+
+ subdivision_type = SUBDIVISION_NONE;
+ subd_params = NULL;
+
+ patch_table = NULL;
+}
+
+Mesh::Mesh() : Mesh(get_node_type(), Geometry::MESH)
+{
+}
+
+Mesh::~Mesh()
+{
+ delete patch_table;
+ delete subd_params;
+}
+
+void Mesh::resize_mesh(int numverts, int numtris)
+{
+ verts.resize(numverts);
+ triangles.resize(numtris * 3);
+ shader.resize(numtris);
+ smooth.resize(numtris);
+
+ if (get_num_subd_faces()) {
+ triangle_patch.resize(numtris);
+ vert_patch_uv.resize(numverts);
+ }
+
+ attributes.resize();
+}
+
+void Mesh::reserve_mesh(int numverts, int numtris)
+{
+ /* reserve space to add verts and triangles later */
+ verts.reserve(numverts);
+ triangles.reserve(numtris * 3);
+ shader.reserve(numtris);
+ smooth.reserve(numtris);
+
+ if (get_num_subd_faces()) {
+ triangle_patch.reserve(numtris);
+ vert_patch_uv.reserve(numverts);
+ }
+
+ attributes.resize(true);
+}
+
+void Mesh::resize_subd_faces(int numfaces, int num_ngons_, int numcorners)
+{
+ subd_start_corner.resize(numfaces);
+ subd_num_corners.resize(numfaces);
+ subd_shader.resize(numfaces);
+ subd_smooth.resize(numfaces);
+ subd_ptex_offset.resize(numfaces);
+ subd_face_corners.resize(numcorners);
+ num_ngons = num_ngons_;
+ num_subd_faces = numfaces;
+
+ subd_attributes.resize();
+}
+
+void Mesh::reserve_subd_faces(int numfaces, int num_ngons_, int numcorners)
+{
+ subd_start_corner.reserve(numfaces);
+ subd_num_corners.reserve(numfaces);
+ subd_shader.reserve(numfaces);
+ subd_smooth.reserve(numfaces);
+ subd_ptex_offset.reserve(numfaces);
+ subd_face_corners.reserve(numcorners);
+ num_ngons = num_ngons_;
+ num_subd_faces = numfaces;
+
+ subd_attributes.resize(true);
+}
+
+void Mesh::reserve_subd_creases(size_t num_creases)
+{
+ subd_creases_edge.reserve(num_creases * 2);
+ subd_creases_weight.reserve(num_creases);
+}
+
+void Mesh::clear_non_sockets()
+{
+ Geometry::clear(true);
+
+ num_subd_verts = 0;
+ num_subd_faces = 0;
+
+ vert_to_stitching_key_map.clear();
+ vert_stitching_map.clear();
+
+ delete patch_table;
+ patch_table = NULL;
+}
+
+void Mesh::clear(bool preserve_shaders, bool preserve_voxel_data)
+{
+ Geometry::clear(preserve_shaders);
+
+ /* clear all verts and triangles */
+ verts.clear();
+ triangles.clear();
+ shader.clear();
+ smooth.clear();
+
+ triangle_patch.clear();
+ vert_patch_uv.clear();
+
+ subd_start_corner.clear();
+ subd_num_corners.clear();
+ subd_shader.clear();
+ subd_smooth.clear();
+ subd_ptex_offset.clear();
+ subd_face_corners.clear();
+
+ subd_creases_edge.clear();
+ subd_creases_weight.clear();
+
+ subd_attributes.clear();
+ attributes.clear(preserve_voxel_data);
+
+ subdivision_type = SubdivisionType::SUBDIVISION_NONE;
+
+ clear_non_sockets();
+}
+
+void Mesh::clear(bool preserve_shaders)
+{
+ clear(preserve_shaders, false);
+}
+
+void Mesh::add_vertex(float3 P)
+{
+ verts.push_back_reserved(P);
+ tag_verts_modified();
+
+ if (get_num_subd_faces()) {
+ vert_patch_uv.push_back_reserved(zero_float2());
+ tag_vert_patch_uv_modified();
+ }
+}
+
+void Mesh::add_vertex_slow(float3 P)
+{
+ verts.push_back_slow(P);
+ tag_verts_modified();
+
+ if (get_num_subd_faces()) {
+ vert_patch_uv.push_back_slow(zero_float2());
+ tag_vert_patch_uv_modified();
+ }
+}
+
+void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
+{
+ triangles.push_back_reserved(v0);
+ triangles.push_back_reserved(v1);
+ triangles.push_back_reserved(v2);
+ shader.push_back_reserved(shader_);
+ smooth.push_back_reserved(smooth_);
+
+ tag_triangles_modified();
+ tag_shader_modified();
+ tag_smooth_modified();
+
+ if (get_num_subd_faces()) {
+ triangle_patch.push_back_reserved(-1);
+ tag_triangle_patch_modified();
+ }
+}
+
+void Mesh::add_subd_face(int *corners, int num_corners, int shader_, bool smooth_)
+{
+ int start_corner = subd_face_corners.size();
+
+ for (int i = 0; i < num_corners; i++) {
+ subd_face_corners.push_back_reserved(corners[i]);
+ }
+
+ int ptex_offset = 0;
+ // cannot use get_num_subd_faces here as it holds the total number of subd_faces, but we do not
+ // have the total amount of data yet
+ if (subd_shader.size()) {
+ SubdFace s = get_subd_face(subd_shader.size() - 1);
+ ptex_offset = s.ptex_offset + s.num_ptex_faces();
+ }
+
+ subd_start_corner.push_back_reserved(start_corner);
+ subd_num_corners.push_back_reserved(num_corners);
+ subd_shader.push_back_reserved(shader_);
+ subd_smooth.push_back_reserved(smooth_);
+ subd_ptex_offset.push_back_reserved(ptex_offset);
+
+ tag_subd_face_corners_modified();
+ tag_subd_start_corner_modified();
+ tag_subd_num_corners_modified();
+ tag_subd_shader_modified();
+ tag_subd_smooth_modified();
+ tag_subd_ptex_offset_modified();
+}
+
+Mesh::SubdFace Mesh::get_subd_face(size_t index) const
+{
+ Mesh::SubdFace s;
+ s.shader = subd_shader[index];
+ s.num_corners = subd_num_corners[index];
+ s.smooth = subd_smooth[index];
+ s.ptex_offset = subd_ptex_offset[index];
+ s.start_corner = subd_start_corner[index];
+ return s;
+}
+
+void Mesh::add_crease(int v0, int v1, float weight)
+{
+ subd_creases_edge.push_back_slow(v0);
+ subd_creases_edge.push_back_slow(v1);
+ subd_creases_weight.push_back_slow(weight);
+
+ tag_subd_creases_edge_modified();
+ tag_subd_creases_edge_modified();
+ tag_subd_creases_weight_modified();
+}
+
+void Mesh::copy_center_to_motion_step(const int motion_step)
+{
+ Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr_mP) {
+ Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
+ Attribute *attr_N = attributes.find(ATTR_STD_VERTEX_NORMAL);
+ float3 *P = &verts[0];
+ float3 *N = (attr_N) ? attr_N->data_float3() : NULL;
+ size_t numverts = verts.size();
+
+ memcpy(attr_mP->data_float3() + motion_step * numverts, P, sizeof(float3) * numverts);
+ if (attr_mN)
+ memcpy(attr_mN->data_float3() + motion_step * numverts, N, sizeof(float3) * numverts);
+ }
+}
+
+void Mesh::get_uv_tiles(ustring map, unordered_set<int> &tiles)
+{
+ Attribute *attr, *subd_attr;
+
+ if (map.empty()) {
+ attr = attributes.find(ATTR_STD_UV);
+ subd_attr = subd_attributes.find(ATTR_STD_UV);
+ }
+ else {
+ attr = attributes.find(map);
+ subd_attr = subd_attributes.find(map);
+ }
+
+ if (attr) {
+ attr->get_uv_tiles(this, ATTR_PRIM_GEOMETRY, tiles);
+ }
+ if (subd_attr) {
+ subd_attr->get_uv_tiles(this, ATTR_PRIM_SUBD, tiles);
+ }
+}
+
+void Mesh::compute_bounds()
+{
+ BoundBox bnds = BoundBox::empty;
+ size_t verts_size = verts.size();
+
+ if (verts_size > 0) {
+ for (size_t i = 0; i < verts_size; i++)
+ bnds.grow(verts[i]);
+
+ Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (use_motion_blur && attr) {
+ size_t steps_size = verts.size() * (motion_steps - 1);
+ float3 *vert_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps_size; i++)
+ bnds.grow(vert_steps[i]);
+ }
+
+ if (!bnds.valid()) {
+ bnds = BoundBox::empty;
+
+ /* skip nan or inf coordinates */
+ for (size_t i = 0; i < verts_size; i++)
+ bnds.grow_safe(verts[i]);
+
+ if (use_motion_blur && attr) {
+ size_t steps_size = verts.size() * (motion_steps - 1);
+ float3 *vert_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps_size; i++)
+ bnds.grow_safe(vert_steps[i]);
+ }
+ }
+ }
+
+ if (!bnds.valid()) {
+ /* empty mesh */
+ bnds.grow(zero_float3());
+ }
+
+ bounds = bnds;
+}
+
+void Mesh::apply_transform(const Transform &tfm, const bool apply_to_motion)
+{
+ transform_normal = transform_transposed_inverse(tfm);
+
+ /* apply to mesh vertices */
+ for (size_t i = 0; i < verts.size(); i++)
+ verts[i] = transform_point(&tfm, verts[i]);
+
+ tag_verts_modified();
+
+ if (apply_to_motion) {
+ Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ size_t steps_size = verts.size() * (motion_steps - 1);
+ float3 *vert_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps_size; i++)
+ vert_steps[i] = transform_point(&tfm, vert_steps[i]);
+ }
+
+ Attribute *attr_N = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
+
+ if (attr_N) {
+ Transform ntfm = transform_normal;
+ size_t steps_size = verts.size() * (motion_steps - 1);
+ float3 *normal_steps = attr_N->data_float3();
+
+ for (size_t i = 0; i < steps_size; i++)
+ normal_steps[i] = normalize(transform_direction(&ntfm, normal_steps[i]));
+ }
+ }
+}
+
+void Mesh::add_face_normals()
+{
+ /* don't compute if already there */
+ if (attributes.find(ATTR_STD_FACE_NORMAL))
+ return;
+
+ /* get attributes */
+ Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL);
+ float3 *fN = attr_fN->data_float3();
+
+ /* compute face normals */
+ size_t triangles_size = num_triangles();
+
+ if (triangles_size) {
+ float3 *verts_ptr = verts.data();
+
+ for (size_t i = 0; i < triangles_size; i++) {
+ fN[i] = get_triangle(i).compute_normal(verts_ptr);
+ }
+ }
+
+ /* expected to be in local space */
+ if (transform_applied) {
+ Transform ntfm = transform_inverse(transform_normal);
+
+ for (size_t i = 0; i < triangles_size; i++)
+ fN[i] = normalize(transform_direction(&ntfm, fN[i]));
+ }
+}
+
+void Mesh::add_vertex_normals()
+{
+ bool flip = transform_negative_scaled;
+ size_t verts_size = verts.size();
+ size_t triangles_size = num_triangles();
+
+ /* static vertex normals */
+ if (!attributes.find(ATTR_STD_VERTEX_NORMAL) && triangles_size) {
+ /* get attributes */
+ Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
+ Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL);
+
+ float3 *fN = attr_fN->data_float3();
+ float3 *vN = attr_vN->data_float3();
+
+ /* compute vertex normals */
+ memset(vN, 0, verts.size() * sizeof(float3));
+
+ for (size_t i = 0; i < triangles_size; i++) {
+ for (size_t j = 0; j < 3; j++) {
+ vN[get_triangle(i).v[j]] += fN[i];
+ }
+ }
+
+ for (size_t i = 0; i < verts_size; i++) {
+ vN[i] = normalize(vN[i]);
+ if (flip) {
+ vN[i] = -vN[i];
+ }
+ }
+ }
+
+ /* motion vertex normals */
+ Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
+
+ if (has_motion_blur() && attr_mP && !attr_mN && triangles_size) {
+ /* create attribute */
+ attr_mN = attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
+
+ for (int step = 0; step < motion_steps - 1; step++) {
+ float3 *mP = attr_mP->data_float3() + step * verts.size();
+ float3 *mN = attr_mN->data_float3() + step * verts.size();
+
+ /* compute */
+ memset(mN, 0, verts.size() * sizeof(float3));
+
+ for (size_t i = 0; i < triangles_size; i++) {
+ for (size_t j = 0; j < 3; j++) {
+ float3 fN = get_triangle(i).compute_normal(mP);
+ mN[get_triangle(i).v[j]] += fN;
+ }
+ }
+
+ for (size_t i = 0; i < verts_size; i++) {
+ mN[i] = normalize(mN[i]);
+ if (flip) {
+ mN[i] = -mN[i];
+ }
+ }
+ }
+ }
+
+ /* subd vertex normals */
+ if (!subd_attributes.find(ATTR_STD_VERTEX_NORMAL) && get_num_subd_faces()) {
+ /* get attributes */
+ Attribute *attr_vN = subd_attributes.add(ATTR_STD_VERTEX_NORMAL);
+ float3 *vN = attr_vN->data_float3();
+
+ /* compute vertex normals */
+ memset(vN, 0, verts.size() * sizeof(float3));
+
+ for (size_t i = 0; i < get_num_subd_faces(); i++) {
+ SubdFace face = get_subd_face(i);
+ float3 fN = face.normal(this);
+
+ for (size_t j = 0; j < face.num_corners; j++) {
+ size_t corner = subd_face_corners[face.start_corner + j];
+ vN[corner] += fN;
+ }
+ }
+
+ for (size_t i = 0; i < verts_size; i++) {
+ vN[i] = normalize(vN[i]);
+ if (flip) {
+ vN[i] = -vN[i];
+ }
+ }
+ }
+}
+
+void Mesh::add_undisplaced()
+{
+ AttributeSet &attrs = (subdivision_type == SUBDIVISION_NONE) ? attributes : subd_attributes;
+
+ /* don't compute if already there */
+ if (attrs.find(ATTR_STD_POSITION_UNDISPLACED)) {
+ return;
+ }
+
+ /* get attribute */
+ Attribute *attr = attrs.add(ATTR_STD_POSITION_UNDISPLACED);
+ attr->flags |= ATTR_SUBDIVIDED;
+
+ float3 *data = attr->data_float3();
+
+ /* copy verts */
+ size_t size = attr->buffer_size(this, ATTR_PRIM_GEOMETRY);
+
+ /* Center points for ngons aren't stored in Mesh::verts but are included in size since they will
+ * be calculated later, we subtract them from size here so we don't have an overflow while
+ * copying.
+ */
+ size -= num_ngons * attr->data_sizeof();
+
+ if (size) {
+ memcpy(data, verts.data(), size);
+ }
+}
+
+void Mesh::pack_shaders(Scene *scene, uint *tri_shader)
+{
+ uint shader_id = 0;
+ uint last_shader = -1;
+ bool last_smooth = false;
+
+ size_t triangles_size = num_triangles();
+ int *shader_ptr = shader.data();
+
+ for (size_t i = 0; i < triangles_size; i++) {
+ if (shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
+ last_shader = shader_ptr[i];
+ last_smooth = smooth[i];
+ Shader *shader = (last_shader < used_shaders.size()) ?
+ static_cast<Shader *>(used_shaders[last_shader]) :
+ scene->default_surface;
+ shader_id = scene->shader_manager->get_shader_id(shader, last_smooth);
+ }
+
+ tri_shader[i] = shader_id;
+ }
+}
+
+void Mesh::pack_normals(float4 *vnormal)
+{
+ Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
+ if (attr_vN == NULL) {
+ /* Happens on objects with just hair. */
+ return;
+ }
+
+ bool do_transform = transform_applied;
+ Transform ntfm = transform_normal;
+
+ float3 *vN = attr_vN->data_float3();
+ size_t verts_size = verts.size();
+
+ for (size_t i = 0; i < verts_size; i++) {
+ float3 vNi = vN[i];
+
+ if (do_transform)
+ vNi = safe_normalize(transform_direction(&ntfm, vNi));
+
+ vnormal[i] = make_float4(vNi.x, vNi.y, vNi.z, 0.0f);
+ }
+}
+
+void Mesh::pack_verts(float4 *tri_verts, uint4 *tri_vindex, uint *tri_patch, float2 *tri_patch_uv)
+{
+ size_t verts_size = verts.size();
+
+ if (verts_size && get_num_subd_faces()) {
+ float2 *vert_patch_uv_ptr = vert_patch_uv.data();
+
+ for (size_t i = 0; i < verts_size; i++) {
+ tri_patch_uv[i] = vert_patch_uv_ptr[i];
+ }
+ }
+
+ size_t triangles_size = num_triangles();
+
+ for (size_t i = 0; i < triangles_size; i++) {
+ const Triangle t = get_triangle(i);
+ tri_vindex[i] = make_uint4(
+ t.v[0] + vert_offset, t.v[1] + vert_offset, t.v[2] + vert_offset, 3 * (prim_offset + i));
+
+ tri_patch[i] = (!get_num_subd_faces()) ? -1 : (triangle_patch[i] * 8 + patch_offset);
+
+ tri_verts[i * 3] = float3_to_float4(verts[t.v[0]]);
+ tri_verts[i * 3 + 1] = float3_to_float4(verts[t.v[1]]);
+ tri_verts[i * 3 + 2] = float3_to_float4(verts[t.v[2]]);
+ }
+}
+
+void Mesh::pack_patches(uint *patch_data)
+{
+ size_t num_faces = get_num_subd_faces();
+ int ngons = 0;
+
+ for (size_t f = 0; f < num_faces; f++) {
+ SubdFace face = get_subd_face(f);
+
+ if (face.is_quad()) {
+ int c[4];
+ memcpy(c, &subd_face_corners[face.start_corner], sizeof(int) * 4);
+
+ *(patch_data++) = c[0] + vert_offset;
+ *(patch_data++) = c[1] + vert_offset;
+ *(patch_data++) = c[2] + vert_offset;
+ *(patch_data++) = c[3] + vert_offset;
+
+ *(patch_data++) = f + face_offset;
+ *(patch_data++) = face.num_corners;
+ *(patch_data++) = face.start_corner + corner_offset;
+ *(patch_data++) = 0;
+ }
+ else {
+ for (int i = 0; i < face.num_corners; i++) {
+ int c[4];
+ c[0] = subd_face_corners[face.start_corner + mod(i + 0, face.num_corners)];
+ c[1] = subd_face_corners[face.start_corner + mod(i + 1, face.num_corners)];
+ c[2] = verts.size() - num_subd_verts + ngons;
+ c[3] = subd_face_corners[face.start_corner + mod(i - 1, face.num_corners)];
+
+ *(patch_data++) = c[0] + vert_offset;
+ *(patch_data++) = c[1] + vert_offset;
+ *(patch_data++) = c[2] + vert_offset;
+ *(patch_data++) = c[3] + vert_offset;
+
+ *(patch_data++) = f + face_offset;
+ *(patch_data++) = face.num_corners | (i << 16);
+ *(patch_data++) = face.start_corner + corner_offset;
+ *(patch_data++) = subd_face_corners.size() + ngons + corner_offset;
+ }
+
+ ngons++;
+ }
+ }
+}
+
+PrimitiveType Mesh::primitive_type() const
+{
+ return has_motion_blur() ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/mesh.h b/intern/cycles/scene/mesh.h
new file mode 100644
index 00000000000..d13b3003164
--- /dev/null
+++ b/intern/cycles/scene/mesh.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MESH_H__
+#define __MESH_H__
+
+#include "graph/node.h"
+
+#include "bvh/params.h"
+#include "scene/attribute.h"
+#include "scene/geometry.h"
+#include "scene/shader.h"
+
+#include "util/array.h"
+#include "util/boundbox.h"
+#include "util/list.h"
+#include "util/map.h"
+#include "util/param.h"
+#include "util/set.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Attribute;
+class BVH;
+class Device;
+class DeviceScene;
+class Mesh;
+class Progress;
+class RenderStats;
+class Scene;
+class SceneParams;
+class AttributeRequest;
+struct SubdParams;
+class DiagSplit;
+struct PackedPatchTable;
+
+/* Mesh */
+
+class Mesh : public Geometry {
+ protected:
+ Mesh(const NodeType *node_type_, Type geom_type_);
+
+ public:
+ NODE_DECLARE
+
+ /* Mesh Triangle */
+ struct Triangle {
+ int v[3];
+
+ void bounds_grow(const float3 *verts, BoundBox &bounds) const;
+
+ void motion_verts(const float3 *verts,
+ const float3 *vert_steps,
+ size_t num_verts,
+ size_t num_steps,
+ float time,
+ float3 r_verts[3]) const;
+
+ void verts_for_step(const float3 *verts,
+ const float3 *vert_steps,
+ size_t num_verts,
+ size_t num_steps,
+ size_t step,
+ float3 r_verts[3]) const;
+
+ float3 compute_normal(const float3 *verts) const;
+
+ bool valid(const float3 *verts) const;
+ };
+
+ Triangle get_triangle(size_t i) const
+ {
+ Triangle tri = {{triangles[i * 3 + 0], triangles[i * 3 + 1], triangles[i * 3 + 2]}};
+ return tri;
+ }
+
+ size_t num_triangles() const
+ {
+ return triangles.size() / 3;
+ }
+
+ /* Mesh SubdFace */
+ struct SubdFace {
+ int start_corner;
+ int num_corners;
+ int shader;
+ bool smooth;
+ int ptex_offset;
+
+ bool is_quad()
+ {
+ return num_corners == 4;
+ }
+ float3 normal(const Mesh *mesh) const;
+ int num_ptex_faces() const
+ {
+ return num_corners == 4 ? 1 : num_corners;
+ }
+ };
+
+ struct SubdEdgeCrease {
+ int v[2];
+ float crease;
+ };
+
+ SubdEdgeCrease get_subd_crease(size_t i) const
+ {
+ SubdEdgeCrease s;
+ s.v[0] = subd_creases_edge[i * 2];
+ s.v[1] = subd_creases_edge[i * 2 + 1];
+ s.crease = subd_creases_weight[i];
+ return s;
+ }
+
+ bool need_tesselation();
+
+ enum SubdivisionType {
+ SUBDIVISION_NONE,
+ SUBDIVISION_LINEAR,
+ SUBDIVISION_CATMULL_CLARK,
+ };
+
+ NODE_SOCKET_API(SubdivisionType, subdivision_type)
+
+ /* Mesh Data */
+ NODE_SOCKET_API_ARRAY(array<int>, triangles)
+ NODE_SOCKET_API_ARRAY(array<float3>, verts)
+ NODE_SOCKET_API_ARRAY(array<int>, shader)
+ NODE_SOCKET_API_ARRAY(array<bool>, smooth)
+
+ /* used for storing patch info for subd triangles, only allocated if there are patches */
+ NODE_SOCKET_API_ARRAY(array<int>, triangle_patch) /* must be < 0 for non subd triangles */
+ NODE_SOCKET_API_ARRAY(array<float2>, vert_patch_uv)
+
+ /* SubdFaces */
+ NODE_SOCKET_API_ARRAY(array<int>, subd_start_corner)
+ NODE_SOCKET_API_ARRAY(array<int>, subd_num_corners)
+ NODE_SOCKET_API_ARRAY(array<int>, subd_shader)
+ NODE_SOCKET_API_ARRAY(array<bool>, subd_smooth)
+ NODE_SOCKET_API_ARRAY(array<int>, subd_ptex_offset)
+
+ NODE_SOCKET_API_ARRAY(array<int>, subd_face_corners)
+ NODE_SOCKET_API(int, num_ngons)
+
+ NODE_SOCKET_API_ARRAY(array<int>, subd_creases_edge)
+ NODE_SOCKET_API_ARRAY(array<float>, subd_creases_weight)
+
+ /* Subdivisions parameters */
+ NODE_SOCKET_API(float, subd_dicing_rate)
+ NODE_SOCKET_API(int, subd_max_level)
+ NODE_SOCKET_API(Transform, subd_objecttoworld)
+
+ AttributeSet subd_attributes;
+
+ private:
+ PackedPatchTable *patch_table;
+ /* BVH */
+ size_t vert_offset;
+
+ size_t patch_offset;
+ size_t patch_table_offset;
+ size_t face_offset;
+ size_t corner_offset;
+
+ size_t num_subd_verts;
+ size_t num_subd_faces;
+
+ unordered_map<int, int> vert_to_stitching_key_map; /* real vert index -> stitching index */
+ unordered_multimap<int, int>
+ vert_stitching_map; /* stitching index -> multiple real vert indices */
+
+ friend class BVH2;
+ friend class BVHBuild;
+ friend class BVHSpatialSplit;
+ friend class DiagSplit;
+ friend class EdgeDice;
+ friend class GeometryManager;
+ friend class ObjectManager;
+
+ SubdParams *subd_params = nullptr;
+
+ public:
+ /* Functions */
+ Mesh();
+ ~Mesh();
+
+ void resize_mesh(int numverts, int numfaces);
+ void reserve_mesh(int numverts, int numfaces);
+ void resize_subd_faces(int numfaces, int num_ngons, int numcorners);
+ void reserve_subd_faces(int numfaces, int num_ngons, int numcorners);
+ void reserve_subd_creases(size_t num_creases);
+ void clear_non_sockets();
+ void clear(bool preserve_shaders = false) override;
+ void add_vertex(float3 P);
+ void add_vertex_slow(float3 P);
+ void add_triangle(int v0, int v1, int v2, int shader, bool smooth);
+ void add_subd_face(int *corners, int num_corners, int shader_, bool smooth_);
+ void add_crease(int v0, int v1, float weight);
+
+ void copy_center_to_motion_step(const int motion_step);
+
+ void compute_bounds() override;
+ void apply_transform(const Transform &tfm, const bool apply_to_motion) override;
+ void add_face_normals();
+ void add_vertex_normals();
+ void add_undisplaced();
+
+ void get_uv_tiles(ustring map, unordered_set<int> &tiles) override;
+
+ void pack_shaders(Scene *scene, uint *shader);
+ void pack_normals(float4 *vnormal);
+ void pack_verts(float4 *tri_verts, uint4 *tri_vindex, uint *tri_patch, float2 *tri_patch_uv);
+ void pack_patches(uint *patch_data);
+
+ PrimitiveType primitive_type() const override;
+
+ void tessellate(DiagSplit *split);
+
+ SubdFace get_subd_face(size_t index) const;
+
+ SubdParams *get_subd_params();
+
+ size_t get_num_subd_faces() const
+ {
+ return num_subd_faces;
+ }
+
+ void set_num_subd_faces(size_t num_subd_faces_)
+ {
+ num_subd_faces = num_subd_faces_;
+ }
+
+ size_t get_num_subd_verts()
+ {
+ return num_subd_verts;
+ }
+
+ protected:
+ void clear(bool preserve_shaders, bool preserve_voxel_data);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __MESH_H__ */
diff --git a/intern/cycles/scene/mesh_displace.cpp b/intern/cycles/scene/mesh_displace.cpp
new file mode 100644
index 00000000000..e69c2d1c3be
--- /dev/null
+++ b/intern/cycles/scene/mesh_displace.cpp
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device/device.h"
+
+#include "integrator/shader_eval.h"
+
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+
+#include "util/foreach.h"
+#include "util/map.h"
+#include "util/progress.h"
+#include "util/set.h"
+
+CCL_NAMESPACE_BEGIN
+
+static float3 compute_face_normal(const Mesh::Triangle &t, float3 *verts)
+{
+ float3 v0 = verts[t.v[0]];
+ float3 v1 = verts[t.v[1]];
+ float3 v2 = verts[t.v[2]];
+
+ float3 norm = cross(v1 - v0, v2 - v0);
+ float normlen = len(norm);
+
+ if (normlen == 0.0f)
+ return make_float3(1.0f, 0.0f, 0.0f);
+
+ return norm / normlen;
+}
+
+/* Fill in coordinates for mesh displacement shader evaluation on device. */
+static int fill_shader_input(const Scene *scene,
+ const Mesh *mesh,
+ const int object_index,
+ device_vector<KernelShaderEvalInput> &d_input)
+{
+ int d_input_size = 0;
+ KernelShaderEvalInput *d_input_data = d_input.data();
+
+ const array<int> &mesh_shaders = mesh->get_shader();
+ const array<Node *> &mesh_used_shaders = mesh->get_used_shaders();
+ const array<float3> &mesh_verts = mesh->get_verts();
+
+ const int num_verts = mesh_verts.size();
+ vector<bool> done(num_verts, false);
+
+ int num_triangles = mesh->num_triangles();
+ for (int i = 0; i < num_triangles; i++) {
+ Mesh::Triangle t = mesh->get_triangle(i);
+ int shader_index = mesh_shaders[i];
+ Shader *shader = (shader_index < mesh_used_shaders.size()) ?
+ static_cast<Shader *>(mesh_used_shaders[shader_index]) :
+ scene->default_surface;
+
+ if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
+ continue;
+ }
+
+ for (int j = 0; j < 3; j++) {
+ if (done[t.v[j]])
+ continue;
+
+ done[t.v[j]] = true;
+
+ /* set up object, primitive and barycentric coordinates */
+ int object = object_index;
+ int prim = mesh->prim_offset + i;
+ float u, v;
+
+ switch (j) {
+ case 0:
+ u = 1.0f;
+ v = 0.0f;
+ break;
+ case 1:
+ u = 0.0f;
+ v = 1.0f;
+ break;
+ default:
+ u = 0.0f;
+ v = 0.0f;
+ break;
+ }
+
+ /* back */
+ KernelShaderEvalInput in;
+ in.object = object;
+ in.prim = prim;
+ in.u = u;
+ in.v = v;
+ d_input_data[d_input_size++] = in;
+ }
+ }
+
+ return d_input_size;
+}
+
+/* Read back mesh displacement shader output. */
+static void read_shader_output(const Scene *scene,
+ Mesh *mesh,
+ const device_vector<float> &d_output)
+{
+ const array<int> &mesh_shaders = mesh->get_shader();
+ const array<Node *> &mesh_used_shaders = mesh->get_used_shaders();
+ array<float3> &mesh_verts = mesh->get_verts();
+
+ const int num_verts = mesh_verts.size();
+ const int num_motion_steps = mesh->get_motion_steps();
+ vector<bool> done(num_verts, false);
+
+ const float *d_output_data = d_output.data();
+ int d_output_index = 0;
+
+ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ int num_triangles = mesh->num_triangles();
+ for (int i = 0; i < num_triangles; i++) {
+ Mesh::Triangle t = mesh->get_triangle(i);
+ int shader_index = mesh_shaders[i];
+ Shader *shader = (shader_index < mesh_used_shaders.size()) ?
+ static_cast<Shader *>(mesh_used_shaders[shader_index]) :
+ scene->default_surface;
+
+ if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
+ continue;
+ }
+
+ for (int j = 0; j < 3; j++) {
+ if (!done[t.v[j]]) {
+ done[t.v[j]] = true;
+ float3 off = make_float3(d_output_data[d_output_index + 0],
+ d_output_data[d_output_index + 1],
+ d_output_data[d_output_index + 2]);
+ d_output_index += 3;
+
+ /* Avoid illegal vertex coordinates. */
+ off = ensure_finite3(off);
+ mesh_verts[t.v[j]] += off;
+ if (attr_mP != NULL) {
+ for (int step = 0; step < num_motion_steps - 1; step++) {
+ float3 *mP = attr_mP->data_float3() + step * num_verts;
+ mP[t.v[j]] += off;
+ }
+ }
+ }
+ }
+ }
+}
+
+bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress &progress)
+{
+ /* verify if we have a displacement shader */
+ if (!mesh->has_true_displacement()) {
+ return false;
+ }
+
+ const size_t num_verts = mesh->verts.size();
+ const size_t num_triangles = mesh->num_triangles();
+
+ if (num_triangles == 0) {
+ return false;
+ }
+
+ string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
+ progress.set_status("Updating Mesh", msg);
+
+ /* find object index. todo: is arbitrary */
+ size_t object_index = OBJECT_NONE;
+
+ for (size_t i = 0; i < scene->objects.size(); i++) {
+ if (scene->objects[i]->get_geometry() == mesh) {
+ object_index = i;
+ break;
+ }
+ }
+
+ /* Evaluate shader on device. */
+ ShaderEval shader_eval(device, progress);
+ if (!shader_eval.eval(SHADER_EVAL_DISPLACE,
+ num_verts,
+ 3,
+ function_bind(&fill_shader_input, scene, mesh, object_index, _1),
+ function_bind(&read_shader_output, scene, mesh, _1))) {
+ return false;
+ }
+
+ /* stitch */
+ unordered_set<int> stitch_keys;
+ for (pair<int, int> i : mesh->vert_to_stitching_key_map) {
+ stitch_keys.insert(i.second); /* stitching index */
+ }
+
+ typedef unordered_multimap<int, int>::iterator map_it_t;
+
+ for (int key : stitch_keys) {
+ pair<map_it_t, map_it_t> verts = mesh->vert_stitching_map.equal_range(key);
+
+ float3 pos = zero_float3();
+ int num = 0;
+
+ for (map_it_t v = verts.first; v != verts.second; ++v) {
+ int vert = v->second;
+
+ pos += mesh->verts[vert];
+ num++;
+ }
+
+ if (num <= 1) {
+ continue;
+ }
+
+ pos *= 1.0f / num;
+
+ for (map_it_t v = verts.first; v != verts.second; ++v) {
+ mesh->verts[v->second] = pos;
+ }
+ }
+
+ /* for displacement method both, we only need to recompute the face
+ * normals, as bump mapping in the shader will already alter the
+ * vertex normal, so we start from the non-displaced vertex normals
+ * to avoid applying the perturbation twice. */
+ mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
+ mesh->add_face_normals();
+
+ bool need_recompute_vertex_normals = false;
+
+ foreach (Node *node, mesh->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->has_displacement && shader->get_displacement_method() == DISPLACE_TRUE) {
+ need_recompute_vertex_normals = true;
+ break;
+ }
+ }
+
+ if (need_recompute_vertex_normals) {
+ bool flip = mesh->transform_negative_scaled;
+ vector<bool> tri_has_true_disp(num_triangles, false);
+
+ for (size_t i = 0; i < num_triangles; i++) {
+ int shader_index = mesh->shader[i];
+ Shader *shader = (shader_index < mesh->used_shaders.size()) ?
+ static_cast<Shader *>(mesh->used_shaders[shader_index]) :
+ scene->default_surface;
+
+ tri_has_true_disp[i] = shader->has_displacement &&
+ shader->get_displacement_method() == DISPLACE_TRUE;
+ }
+
+ /* static vertex normals */
+
+ /* get attributes */
+ Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
+ Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
+
+ float3 *fN = attr_fN->data_float3();
+ float3 *vN = attr_vN->data_float3();
+
+ /* compute vertex normals */
+
+ /* zero vertex normals on triangles with true displacement */
+ for (size_t i = 0; i < num_triangles; i++) {
+ if (tri_has_true_disp[i]) {
+ for (size_t j = 0; j < 3; j++) {
+ vN[mesh->get_triangle(i).v[j]] = zero_float3();
+ }
+ }
+ }
+
+ /* add face normals to vertex normals */
+ for (size_t i = 0; i < num_triangles; i++) {
+ if (tri_has_true_disp[i]) {
+ for (size_t j = 0; j < 3; j++) {
+ int vert = mesh->get_triangle(i).v[j];
+ vN[vert] += fN[i];
+
+ /* add face normals to stitched vertices */
+ if (stitch_keys.size()) {
+ map_it_t key = mesh->vert_to_stitching_key_map.find(vert);
+
+ if (key != mesh->vert_to_stitching_key_map.end()) {
+ pair<map_it_t, map_it_t> verts = mesh->vert_stitching_map.equal_range(key->second);
+
+ for (map_it_t v = verts.first; v != verts.second; ++v) {
+ if (v->second == vert) {
+ continue;
+ }
+
+ vN[v->second] += fN[i];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* normalize vertex normals */
+ vector<bool> done(num_verts, false);
+
+ for (size_t i = 0; i < num_triangles; i++) {
+ if (tri_has_true_disp[i]) {
+ for (size_t j = 0; j < 3; j++) {
+ int vert = mesh->get_triangle(i).v[j];
+
+ if (done[vert]) {
+ continue;
+ }
+
+ vN[vert] = normalize(vN[vert]);
+ if (flip)
+ vN[vert] = -vN[vert];
+
+ done[vert] = true;
+ }
+ }
+ }
+
+ /* motion vertex normals */
+ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
+
+ if (mesh->has_motion_blur() && attr_mP && attr_mN) {
+ for (int step = 0; step < mesh->motion_steps - 1; step++) {
+ float3 *mP = attr_mP->data_float3() + step * mesh->verts.size();
+ float3 *mN = attr_mN->data_float3() + step * mesh->verts.size();
+
+ /* compute */
+
+ /* zero vertex normals on triangles with true displacement */
+ for (size_t i = 0; i < num_triangles; i++) {
+ if (tri_has_true_disp[i]) {
+ for (size_t j = 0; j < 3; j++) {
+ mN[mesh->get_triangle(i).v[j]] = zero_float3();
+ }
+ }
+ }
+
+ /* add face normals to vertex normals */
+ for (size_t i = 0; i < num_triangles; i++) {
+ if (tri_has_true_disp[i]) {
+ for (size_t j = 0; j < 3; j++) {
+ int vert = mesh->get_triangle(i).v[j];
+ float3 fN = compute_face_normal(mesh->get_triangle(i), mP);
+ mN[vert] += fN;
+
+ /* add face normals to stitched vertices */
+ if (stitch_keys.size()) {
+ map_it_t key = mesh->vert_to_stitching_key_map.find(vert);
+
+ if (key != mesh->vert_to_stitching_key_map.end()) {
+ pair<map_it_t, map_it_t> verts = mesh->vert_stitching_map.equal_range(
+ key->second);
+
+ for (map_it_t v = verts.first; v != verts.second; ++v) {
+ if (v->second == vert) {
+ continue;
+ }
+
+ mN[v->second] += fN;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* normalize vertex normals */
+ vector<bool> done(num_verts, false);
+
+ for (size_t i = 0; i < num_triangles; i++) {
+ if (tri_has_true_disp[i]) {
+ for (size_t j = 0; j < 3; j++) {
+ int vert = mesh->get_triangle(i).v[j];
+
+ if (done[vert]) {
+ continue;
+ }
+
+ mN[vert] = normalize(mN[vert]);
+ if (flip)
+ mN[vert] = -mN[vert];
+
+ done[vert] = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/mesh_subdivision.cpp b/intern/cycles/scene/mesh_subdivision.cpp
new file mode 100644
index 00000000000..a0c0bc68f8b
--- /dev/null
+++ b/intern/cycles/scene/mesh_subdivision.cpp
@@ -0,0 +1,648 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/attribute.h"
+#include "scene/camera.h"
+#include "scene/mesh.h"
+
+#include "subd/patch.h"
+#include "subd/patch_table.h"
+#include "subd/split.h"
+
+#include "util/algorithm.h"
+#include "util/foreach.h"
+#include "util/hash.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_OPENSUBDIV
+
+CCL_NAMESPACE_END
+
+# include <opensubdiv/far/patchMap.h>
+# include <opensubdiv/far/patchTableFactory.h>
+# include <opensubdiv/far/primvarRefiner.h>
+# include <opensubdiv/far/topologyRefinerFactory.h>
+
+/* specializations of TopologyRefinerFactory for ccl::Mesh */
+
+namespace OpenSubdiv {
+namespace OPENSUBDIV_VERSION {
+namespace Far {
+template<>
+bool TopologyRefinerFactory<ccl::Mesh>::resizeComponentTopology(TopologyRefiner &refiner,
+ ccl::Mesh const &mesh)
+{
+ setNumBaseVertices(refiner, mesh.get_verts().size());
+ setNumBaseFaces(refiner, mesh.get_num_subd_faces());
+
+ for (int i = 0; i < mesh.get_num_subd_faces(); i++) {
+ setNumBaseFaceVertices(refiner, i, mesh.get_subd_num_corners()[i]);
+ }
+
+ return true;
+}
+
+template<>
+bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTopology(TopologyRefiner &refiner,
+ ccl::Mesh const &mesh)
+{
+ const ccl::array<int> &subd_face_corners = mesh.get_subd_face_corners();
+ const ccl::array<int> &subd_start_corner = mesh.get_subd_start_corner();
+ const ccl::array<int> &subd_num_corners = mesh.get_subd_num_corners();
+
+ for (int i = 0; i < mesh.get_num_subd_faces(); i++) {
+ IndexArray face_verts = getBaseFaceVertices(refiner, i);
+
+ int start_corner = subd_start_corner[i];
+ int *corner = &subd_face_corners[start_corner];
+
+ for (int j = 0; j < subd_num_corners[i]; j++, corner++) {
+ face_verts[j] = *corner;
+ }
+ }
+
+ return true;
+}
+
+template<>
+bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner &refiner,
+ ccl::Mesh const &mesh)
+{
+ size_t num_creases = mesh.get_subd_creases_weight().size();
+
+ for (int i = 0; i < num_creases; i++) {
+ ccl::Mesh::SubdEdgeCrease crease = mesh.get_subd_crease(i);
+ Index edge = findBaseEdge(refiner, crease.v[0], crease.v[1]);
+
+ if (edge != INDEX_INVALID) {
+ setBaseEdgeSharpness(refiner, edge, crease.crease * 10.0f);
+ }
+ }
+
+ for (int i = 0; i < mesh.get_verts().size(); i++) {
+ ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i);
+
+ if (vert_edges.size() == 2) {
+ float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]);
+ sharpness = ccl::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1]));
+
+ setBaseVertexSharpness(refiner, i, sharpness);
+ }
+ }
+
+ return true;
+}
+
+template<>
+bool TopologyRefinerFactory<ccl::Mesh>::assignFaceVaryingTopology(TopologyRefiner & /*refiner*/,
+ ccl::Mesh const & /*mesh*/)
+{
+ return true;
+}
+
+template<>
+void TopologyRefinerFactory<ccl::Mesh>::reportInvalidTopology(TopologyError /*err_code*/,
+ char const * /*msg*/,
+ ccl::Mesh const & /*mesh*/)
+{
+}
+} /* namespace Far */
+} /* namespace OPENSUBDIV_VERSION */
+} /* namespace OpenSubdiv */
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OpenSubdiv;
+
+/* struct that implements OpenSubdiv's vertex interface */
+
+template<typename T> struct OsdValue {
+ T value;
+
+ OsdValue()
+ {
+ }
+
+ void Clear(void * = 0)
+ {
+ memset(&value, 0, sizeof(T));
+ }
+
+ void AddWithWeight(OsdValue<T> const &src, float weight)
+ {
+ value += src.value * weight;
+ }
+};
+
+template<> void OsdValue<uchar4>::AddWithWeight(OsdValue<uchar4> const &src, float weight)
+{
+ for (int i = 0; i < 4; i++) {
+ value[i] += (uchar)(src.value[i] * weight);
+ }
+}
+
+/* class for holding OpenSubdiv data used during tessellation */
+
+class OsdData {
+ Mesh *mesh;
+ vector<OsdValue<float3>> verts;
+ Far::TopologyRefiner *refiner;
+ Far::PatchTable *patch_table;
+ Far::PatchMap *patch_map;
+
+ public:
+ OsdData() : mesh(NULL), refiner(NULL), patch_table(NULL), patch_map(NULL)
+ {
+ }
+
+ ~OsdData()
+ {
+ delete refiner;
+ delete patch_table;
+ delete patch_map;
+ }
+
+ void build_from_mesh(Mesh *mesh_)
+ {
+ mesh = mesh_;
+
+ /* type and options */
+ Sdc::SchemeType type = Sdc::SCHEME_CATMARK;
+
+ Sdc::Options options;
+ options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
+
+ /* create refiner */
+ refiner = Far::TopologyRefinerFactory<Mesh>::Create(
+ *mesh, Far::TopologyRefinerFactory<Mesh>::Options(type, options));
+
+ /* adaptive refinement */
+ int max_isolation = calculate_max_isolation();
+ refiner->RefineAdaptive(Far::TopologyRefiner::AdaptiveOptions(max_isolation));
+
+ /* create patch table */
+ Far::PatchTableFactory::Options patch_options;
+ patch_options.endCapType = Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
+
+ patch_table = Far::PatchTableFactory::Create(*refiner, patch_options);
+
+ /* interpolate verts */
+ int num_refiner_verts = refiner->GetNumVerticesTotal();
+ int num_local_points = patch_table->GetNumLocalPoints();
+
+ verts.resize(num_refiner_verts + num_local_points);
+ for (int i = 0; i < mesh->get_verts().size(); i++) {
+ verts[i].value = mesh->get_verts()[i];
+ }
+
+ OsdValue<float3> *src = verts.data();
+ for (int i = 0; i < refiner->GetMaxLevel(); i++) {
+ OsdValue<float3> *dest = src + refiner->GetLevel(i).GetNumVertices();
+ Far::PrimvarRefiner(*refiner).Interpolate(i + 1, src, dest);
+ src = dest;
+ }
+
+ if (num_local_points) {
+ patch_table->ComputeLocalPointValues(&verts[0], &verts[num_refiner_verts]);
+ }
+
+ /* create patch map */
+ patch_map = new Far::PatchMap(*patch_table);
+ }
+
+ void subdivide_attribute(Attribute &attr)
+ {
+ Far::PrimvarRefiner primvar_refiner(*refiner);
+
+ if (attr.element == ATTR_ELEMENT_VERTEX) {
+ int num_refiner_verts = refiner->GetNumVerticesTotal();
+ int num_local_points = patch_table->GetNumLocalPoints();
+
+ attr.resize(num_refiner_verts + num_local_points);
+ attr.flags |= ATTR_FINAL_SIZE;
+
+ char *src = attr.buffer.data();
+
+ for (int i = 0; i < refiner->GetMaxLevel(); i++) {
+ char *dest = src + refiner->GetLevel(i).GetNumVertices() * attr.data_sizeof();
+
+ if (attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
+ primvar_refiner.Interpolate(i + 1, (OsdValue<float> *)src, (OsdValue<float> *&)dest);
+ }
+ else if (attr.same_storage(attr.type, TypeFloat2)) {
+ primvar_refiner.Interpolate(i + 1, (OsdValue<float2> *)src, (OsdValue<float2> *&)dest);
+ }
+ else {
+ primvar_refiner.Interpolate(i + 1, (OsdValue<float4> *)src, (OsdValue<float4> *&)dest);
+ }
+
+ src = dest;
+ }
+
+ if (num_local_points) {
+ if (attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
+ patch_table->ComputeLocalPointValues(
+ (OsdValue<float> *)&attr.buffer[0],
+ (OsdValue<float> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
+ }
+ else if (attr.same_storage(attr.type, TypeFloat2)) {
+ patch_table->ComputeLocalPointValues(
+ (OsdValue<float2> *)&attr.buffer[0],
+ (OsdValue<float2> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
+ }
+ else {
+ patch_table->ComputeLocalPointValues(
+ (OsdValue<float4> *)&attr.buffer[0],
+ (OsdValue<float4> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
+ }
+ }
+ }
+ else if (attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
+ // TODO(mai): fvar interpolation
+ }
+ }
+
+ int calculate_max_isolation()
+ {
+ /* loop over all edges to find longest in screen space */
+ const Far::TopologyLevel &level = refiner->GetLevel(0);
+ const SubdParams *subd_params = mesh->get_subd_params();
+ Transform objecttoworld = subd_params->objecttoworld;
+ Camera *cam = subd_params->camera;
+
+ float longest_edge = 0.0f;
+
+ for (size_t i = 0; i < level.GetNumEdges(); i++) {
+ Far::ConstIndexArray verts = level.GetEdgeVertices(i);
+
+ float3 a = mesh->get_verts()[verts[0]];
+ float3 b = mesh->get_verts()[verts[1]];
+
+ float edge_len;
+
+ if (cam) {
+ a = transform_point(&objecttoworld, a);
+ b = transform_point(&objecttoworld, b);
+
+ edge_len = len(a - b) / cam->world_to_raster_size((a + b) * 0.5f);
+ }
+ else {
+ edge_len = len(a - b);
+ }
+
+ longest_edge = max(longest_edge, edge_len);
+ }
+
+ /* calculate isolation level */
+ int isolation = (int)(log2f(max(longest_edge / subd_params->dicing_rate, 1.0f)) + 1.0f);
+
+ return min(isolation, 10);
+ }
+
+ friend struct OsdPatch;
+ friend class Mesh;
+};
+
+/* ccl::Patch implementation that uses OpenSubdiv for eval */
+
+struct OsdPatch : Patch {
+ OsdData *osd_data;
+
+ OsdPatch()
+ {
+ }
+ OsdPatch(OsdData *data) : osd_data(data)
+ {
+ }
+
+ void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
+ {
+ const Far::PatchTable::PatchHandle *handle = osd_data->patch_map->FindPatch(patch_index, u, v);
+ assert(handle);
+
+ float p_weights[20], du_weights[20], dv_weights[20];
+ osd_data->patch_table->EvaluateBasis(*handle, u, v, p_weights, du_weights, dv_weights);
+
+ Far::ConstIndexArray cv = osd_data->patch_table->GetPatchVertices(*handle);
+
+ float3 du, dv;
+ if (P)
+ *P = zero_float3();
+ du = zero_float3();
+ dv = zero_float3();
+
+ for (int i = 0; i < cv.size(); i++) {
+ float3 p = osd_data->verts[cv[i]].value;
+
+ if (P)
+ *P += p * p_weights[i];
+ du += p * du_weights[i];
+ dv += p * dv_weights[i];
+ }
+
+ if (dPdu)
+ *dPdu = du;
+ if (dPdv)
+ *dPdv = dv;
+ if (N) {
+ *N = cross(du, dv);
+
+ float t = len(*N);
+ *N = (t != 0.0f) ? *N / t : make_float3(0.0f, 0.0f, 1.0f);
+ }
+ }
+};
+
+#endif
+
+void Mesh::tessellate(DiagSplit *split)
+{
+ /* reset the number of subdivision vertices, in case the Mesh was not cleared
+ * between calls or data updates */
+ num_subd_verts = 0;
+
+#ifdef WITH_OPENSUBDIV
+ OsdData osd_data;
+ bool need_packed_patch_table = false;
+
+ if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
+ if (get_num_subd_faces()) {
+ osd_data.build_from_mesh(this);
+ }
+ }
+ else
+#endif
+ {
+ /* force linear subdivision if OpenSubdiv is unavailable to avoid
+ * falling into catmull-clark code paths by accident
+ */
+ subdivision_type = SUBDIVISION_LINEAR;
+
+ /* force disable attribute subdivision for same reason as above */
+ foreach (Attribute &attr, subd_attributes.attributes) {
+ attr.flags &= ~ATTR_SUBDIVIDED;
+ }
+ }
+
+ int num_faces = get_num_subd_faces();
+
+ Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL);
+ float3 *vN = (attr_vN) ? attr_vN->data_float3() : NULL;
+
+ /* count patches */
+ int num_patches = 0;
+ for (int f = 0; f < num_faces; f++) {
+ SubdFace face = get_subd_face(f);
+
+ if (face.is_quad()) {
+ num_patches++;
+ }
+ else {
+ num_patches += face.num_corners;
+ }
+ }
+
+ /* build patches from faces */
+#ifdef WITH_OPENSUBDIV
+ if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
+ vector<OsdPatch> osd_patches(num_patches, &osd_data);
+ OsdPatch *patch = osd_patches.data();
+
+ for (int f = 0; f < num_faces; f++) {
+ SubdFace face = get_subd_face(f);
+
+ if (face.is_quad()) {
+ patch->patch_index = face.ptex_offset;
+ patch->from_ngon = false;
+ patch->shader = face.shader;
+ patch++;
+ }
+ else {
+ for (int corner = 0; corner < face.num_corners; corner++) {
+ patch->patch_index = face.ptex_offset + corner;
+ patch->from_ngon = true;
+ patch->shader = face.shader;
+ patch++;
+ }
+ }
+ }
+
+ /* split patches */
+ split->split_patches(osd_patches.data(), sizeof(OsdPatch));
+ }
+ else
+#endif
+ {
+ vector<LinearQuadPatch> linear_patches(num_patches);
+ LinearQuadPatch *patch = linear_patches.data();
+
+ for (int f = 0; f < num_faces; f++) {
+ SubdFace face = get_subd_face(f);
+
+ if (face.is_quad()) {
+ float3 *hull = patch->hull;
+ float3 *normals = patch->normals;
+
+ patch->patch_index = face.ptex_offset;
+ patch->from_ngon = false;
+
+ for (int i = 0; i < 4; i++) {
+ hull[i] = verts[subd_face_corners[face.start_corner + i]];
+ }
+
+ if (face.smooth) {
+ for (int i = 0; i < 4; i++) {
+ normals[i] = vN[subd_face_corners[face.start_corner + i]];
+ }
+ }
+ else {
+ float3 N = face.normal(this);
+ for (int i = 0; i < 4; i++) {
+ normals[i] = N;
+ }
+ }
+
+ swap(hull[2], hull[3]);
+ swap(normals[2], normals[3]);
+
+ patch->shader = face.shader;
+ patch++;
+ }
+ else {
+ /* ngon */
+ float3 center_vert = zero_float3();
+ float3 center_normal = zero_float3();
+
+ float inv_num_corners = 1.0f / float(face.num_corners);
+ for (int corner = 0; corner < face.num_corners; corner++) {
+ center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
+ center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
+ }
+
+ for (int corner = 0; corner < face.num_corners; corner++) {
+ float3 *hull = patch->hull;
+ float3 *normals = patch->normals;
+
+ patch->patch_index = face.ptex_offset + corner;
+ patch->from_ngon = true;
+
+ patch->shader = face.shader;
+
+ hull[0] =
+ verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
+ hull[1] =
+ verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
+ hull[2] =
+ verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
+ hull[3] = center_vert;
+
+ hull[1] = (hull[1] + hull[0]) * 0.5;
+ hull[2] = (hull[2] + hull[0]) * 0.5;
+
+ if (face.smooth) {
+ normals[0] =
+ vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
+ normals[1] =
+ vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
+ normals[2] =
+ vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
+ normals[3] = center_normal;
+
+ normals[1] = (normals[1] + normals[0]) * 0.5;
+ normals[2] = (normals[2] + normals[0]) * 0.5;
+ }
+ else {
+ float3 N = face.normal(this);
+ for (int i = 0; i < 4; i++) {
+ normals[i] = N;
+ }
+ }
+
+ patch++;
+ }
+ }
+ }
+
+ /* split patches */
+ split->split_patches(linear_patches.data(), sizeof(LinearQuadPatch));
+ }
+
+ /* interpolate center points for attributes */
+ foreach (Attribute &attr, subd_attributes.attributes) {
+#ifdef WITH_OPENSUBDIV
+ if (subdivision_type == SUBDIVISION_CATMULL_CLARK && attr.flags & ATTR_SUBDIVIDED) {
+ if (attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
+ /* keep subdivision for corner attributes disabled for now */
+ attr.flags &= ~ATTR_SUBDIVIDED;
+ }
+ else if (get_num_subd_faces()) {
+ osd_data.subdivide_attribute(attr);
+
+ need_packed_patch_table = true;
+ continue;
+ }
+ }
+#endif
+
+ char *data = attr.data();
+ size_t stride = attr.data_sizeof();
+ int ngons = 0;
+
+ switch (attr.element) {
+ case ATTR_ELEMENT_VERTEX: {
+ for (int f = 0; f < num_faces; f++) {
+ SubdFace face = get_subd_face(f);
+
+ if (!face.is_quad()) {
+ char *center = data + (verts.size() - num_subd_verts + ngons) * stride;
+ attr.zero_data(center);
+
+ float inv_num_corners = 1.0f / float(face.num_corners);
+
+ for (int corner = 0; corner < face.num_corners; corner++) {
+ attr.add_with_weight(center,
+ data + subd_face_corners[face.start_corner + corner] * stride,
+ inv_num_corners);
+ }
+
+ ngons++;
+ }
+ }
+ } break;
+ case ATTR_ELEMENT_VERTEX_MOTION: {
+ // TODO(mai): implement
+ } break;
+ case ATTR_ELEMENT_CORNER: {
+ for (int f = 0; f < num_faces; f++) {
+ SubdFace face = get_subd_face(f);
+
+ if (!face.is_quad()) {
+ char *center = data + (subd_face_corners.size() + ngons) * stride;
+ attr.zero_data(center);
+
+ float inv_num_corners = 1.0f / float(face.num_corners);
+
+ for (int corner = 0; corner < face.num_corners; corner++) {
+ attr.add_with_weight(
+ center, data + (face.start_corner + corner) * stride, inv_num_corners);
+ }
+
+ ngons++;
+ }
+ }
+ } break;
+ case ATTR_ELEMENT_CORNER_BYTE: {
+ for (int f = 0; f < num_faces; f++) {
+ SubdFace face = get_subd_face(f);
+
+ if (!face.is_quad()) {
+ uchar *center = (uchar *)data + (subd_face_corners.size() + ngons) * stride;
+
+ float inv_num_corners = 1.0f / float(face.num_corners);
+ float4 val = zero_float4();
+
+ for (int corner = 0; corner < face.num_corners; corner++) {
+ for (int i = 0; i < 4; i++) {
+ val[i] += float(*(data + (face.start_corner + corner) * stride + i)) *
+ inv_num_corners;
+ }
+ }
+
+ for (int i = 0; i < 4; i++) {
+ center[i] = uchar(min(max(val[i], 0.0f), 255.0f));
+ }
+
+ ngons++;
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+
+#ifdef WITH_OPENSUBDIV
+ /* pack patch tables */
+ if (need_packed_patch_table) {
+ delete patch_table;
+ patch_table = new PackedPatchTable;
+ patch_table->pack(osd_data.patch_table);
+ }
+#endif
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
new file mode 100644
index 00000000000..69a2365f17c
--- /dev/null
+++ b/intern/cycles/scene/object.cpp
@@ -0,0 +1,984 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/object.h"
+#include "device/device.h"
+#include "scene/camera.h"
+#include "scene/curves.h"
+#include "scene/hair.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/particles.h"
+#include "scene/scene.h"
+#include "scene/stats.h"
+#include "scene/volume.h"
+
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/map.h"
+#include "util/murmurhash.h"
+#include "util/progress.h"
+#include "util/set.h"
+#include "util/task.h"
+#include "util/vector.h"
+
+#include "subd/patch_table.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Global state of object transform update. */
+
+struct UpdateObjectTransformState {
+ /* Global state used by device_update_object_transform().
+ * Common for both threaded and non-threaded update.
+ */
+
+ /* Type of the motion required by the scene settings. */
+ Scene::MotionType need_motion;
+
+ /* Mapping from particle system to a index in packed particle array.
+ * Only used for read.
+ */
+ map<ParticleSystem *, int> particle_offset;
+
+ /* Motion offsets for each object. */
+ array<uint> motion_offset;
+
+ /* Packed object arrays. Those will be filled in. */
+ uint *object_flag;
+ uint *object_visibility;
+ KernelObject *objects;
+ Transform *object_motion_pass;
+ DecomposedTransform *object_motion;
+ float *object_volume_step;
+
+ /* Flags which will be synchronized to Integrator. */
+ bool have_motion;
+ bool have_curves;
+
+ /* ** Scheduling queue. ** */
+ Scene *scene;
+
+ /* First unused object index in the queue. */
+ int queue_start_object;
+};
+
+/* Object */
+
+NODE_DEFINE(Object)
+{
+ NodeType *type = NodeType::add("object", create);
+
+ SOCKET_NODE(geometry, "Geometry", Geometry::get_node_base_type());
+ SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
+ SOCKET_UINT(visibility, "Visibility", ~0);
+ SOCKET_COLOR(color, "Color", zero_float3());
+ SOCKET_UINT(random_id, "Random ID", 0);
+ SOCKET_INT(pass_id, "Pass ID", 0);
+ SOCKET_BOOLEAN(use_holdout, "Use Holdout", false);
+ SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false);
+ SOCKET_POINT(dupli_generated, "Dupli Generated", zero_float3());
+ SOCKET_POINT2(dupli_uv, "Dupli UV", zero_float2());
+ SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
+ SOCKET_FLOAT(shadow_terminator_shading_offset, "Shadow Terminator Shading Offset", 0.0f);
+ SOCKET_FLOAT(shadow_terminator_geometry_offset, "Shadow Terminator Geometry Offset", 0.1f);
+ SOCKET_STRING(asset_name, "Asset Name", ustring());
+
+ SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);
+
+ SOCKET_NODE(particle_system, "Particle System", ParticleSystem::get_node_type());
+ SOCKET_INT(particle_index, "Particle Index", 0);
+
+ SOCKET_FLOAT(ao_distance, "AO Distance", 0.0f);
+
+ return type;
+}
+
+Object::Object() : Node(get_node_type())
+{
+ particle_system = NULL;
+ particle_index = 0;
+ attr_map_offset = 0;
+ bounds = BoundBox::empty;
+ intersects_volume = false;
+}
+
+Object::~Object()
+{
+}
+
+void Object::update_motion()
+{
+ if (!use_motion()) {
+ return;
+ }
+
+ bool have_motion = false;
+
+ for (size_t i = 0; i < motion.size(); i++) {
+ if (motion[i] == transform_empty()) {
+ if (hide_on_missing_motion) {
+ /* Hide objects that have no valid previous or next
+ * transform, for example particle that stop existing. It
+ * would be better to handle this in the kernel and make
+ * objects invisible outside certain motion steps. */
+ tfm = transform_empty();
+ motion.clear();
+ return;
+ }
+ else {
+ /* Otherwise just copy center motion. */
+ motion[i] = tfm;
+ }
+ }
+
+ /* Test if any of the transforms are actually different. */
+ have_motion = have_motion || motion[i] != tfm;
+ }
+
+ /* Clear motion array if there is no actual motion. */
+ if (!have_motion) {
+ motion.clear();
+ }
+}
+
+void Object::compute_bounds(bool motion_blur)
+{
+ BoundBox mbounds = geometry->bounds;
+
+ if (motion_blur && use_motion()) {
+ array<DecomposedTransform> decomp(motion.size());
+ transform_motion_decompose(decomp.data(), motion.data(), motion.size());
+
+ bounds = BoundBox::empty;
+
+ /* TODO: this is really terrible. according to PBRT there is a better
+ * way to find this iteratively, but did not find implementation yet
+ * or try to implement myself */
+ for (float t = 0.0f; t < 1.0f; t += (1.0f / 128.0f)) {
+ Transform ttfm;
+
+ transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t);
+ bounds.grow(mbounds.transformed(&ttfm));
+ }
+ }
+ else {
+ /* No motion blur case. */
+ if (geometry->transform_applied) {
+ bounds = mbounds;
+ }
+ else {
+ bounds = mbounds.transformed(&tfm);
+ }
+ }
+}
+
+void Object::apply_transform(bool apply_to_motion)
+{
+ if (!geometry || tfm == transform_identity())
+ return;
+
+ geometry->apply_transform(tfm, apply_to_motion);
+
+ /* we keep normals pointing in same direction on negative scale, notify
+ * geometry about this in it (re)calculates normals */
+ if (transform_negative_scale(tfm))
+ geometry->transform_negative_scaled = true;
+
+ if (bounds.valid()) {
+ geometry->compute_bounds();
+ compute_bounds(false);
+ }
+
+ /* tfm is not reset to identity, all code that uses it needs to check the
+ * transform_applied boolean */
+}
+
+void Object::tag_update(Scene *scene)
+{
+ uint32_t flag = ObjectManager::UPDATE_NONE;
+
+ if (is_modified()) {
+ flag |= ObjectManager::OBJECT_MODIFIED;
+
+ if (use_holdout_is_modified()) {
+ flag |= ObjectManager::HOLDOUT_MODIFIED;
+ }
+
+ if (is_shadow_catcher_is_modified()) {
+ scene->tag_shadow_catcher_modified();
+ }
+ }
+
+ if (geometry) {
+ if (tfm_is_modified()) {
+ flag |= ObjectManager::TRANSFORM_MODIFIED;
+ }
+
+ if (visibility_is_modified()) {
+ flag |= ObjectManager::VISIBILITY_MODIFIED;
+ }
+
+ foreach (Node *node, geometry->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->get_use_mis() && shader->has_surface_emission)
+ scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED);
+ }
+ }
+
+ scene->camera->need_flags_update = true;
+ scene->object_manager->tag_update(scene, flag);
+}
+
+bool Object::use_motion() const
+{
+ return (motion.size() > 1);
+}
+
+float Object::motion_time(int step) const
+{
+ return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
+}
+
+int Object::motion_step(float time) const
+{
+ if (use_motion()) {
+ for (size_t step = 0; step < motion.size(); step++) {
+ if (time == motion_time(step)) {
+ return step;
+ }
+ }
+ }
+
+ return -1;
+}
+
+bool Object::is_traceable() const
+{
+ /* Mesh itself can be empty,can skip all such objects. */
+ if (!bounds.valid() || bounds.size() == zero_float3()) {
+ return false;
+ }
+ /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */
+ return true;
+}
+
+uint Object::visibility_for_tracing() const
+{
+ return SHADOW_CATCHER_OBJECT_VISIBILITY(is_shadow_catcher, visibility & PATH_RAY_ALL_VISIBILITY);
+}
+
+float Object::compute_volume_step_size() const
+{
+ if (geometry->geometry_type != Geometry::MESH && geometry->geometry_type != Geometry::VOLUME) {
+ return FLT_MAX;
+ }
+
+ Mesh *mesh = static_cast<Mesh *>(geometry);
+
+ if (!mesh->has_volume) {
+ return FLT_MAX;
+ }
+
+ /* Compute step rate from shaders. */
+ float step_rate = FLT_MAX;
+
+ foreach (Node *node, mesh->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->has_volume) {
+ if ((shader->get_heterogeneous_volume() && shader->has_volume_spatial_varying) ||
+ (shader->has_volume_attribute_dependency)) {
+ step_rate = fminf(shader->get_volume_step_rate(), step_rate);
+ }
+ }
+ }
+
+ if (step_rate == FLT_MAX) {
+ return FLT_MAX;
+ }
+
+ /* Compute step size from voxel grids. */
+ float step_size = FLT_MAX;
+
+ if (geometry->geometry_type == Geometry::VOLUME) {
+ Volume *volume = static_cast<Volume *>(geometry);
+
+ foreach (Attribute &attr, volume->attributes.attributes) {
+ if (attr.element == ATTR_ELEMENT_VOXEL) {
+ ImageHandle &handle = attr.data_voxel();
+ const ImageMetaData &metadata = handle.metadata();
+ if (metadata.width == 0 || metadata.height == 0 || metadata.depth == 0) {
+ continue;
+ }
+
+ /* User specified step size. */
+ float voxel_step_size = volume->get_step_size();
+
+ if (voxel_step_size == 0.0f) {
+ /* Auto detect step size. */
+ float3 size = one_float3();
+#ifdef WITH_NANOVDB
+ /* Dimensions were not applied to image transform with NanOVDB (see image_vdb.cpp) */
+ if (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3)
+#endif
+ size /= make_float3(metadata.width, metadata.height, metadata.depth);
+
+ /* Step size is transformed from voxel to world space. */
+ Transform voxel_tfm = tfm;
+ if (metadata.use_transform_3d) {
+ voxel_tfm = tfm * transform_inverse(metadata.transform_3d);
+ }
+ voxel_step_size = min3(fabs(transform_direction(&voxel_tfm, size)));
+ }
+ else if (volume->get_object_space()) {
+ /* User specified step size in object space. */
+ float3 size = make_float3(voxel_step_size, voxel_step_size, voxel_step_size);
+ voxel_step_size = min3(fabs(transform_direction(&tfm, size)));
+ }
+
+ if (voxel_step_size > 0.0f) {
+ step_size = fminf(voxel_step_size, step_size);
+ }
+ }
+ }
+ }
+
+ if (step_size == FLT_MAX) {
+ /* Fall back to 1/10th of bounds for procedural volumes. */
+ step_size = 0.1f * average(bounds.size());
+ }
+
+ step_size *= step_rate;
+
+ return step_size;
+}
+
+int Object::get_device_index() const
+{
+ return index;
+}
+
+/* Object Manager */
+
+ObjectManager::ObjectManager()
+{
+ update_flags = UPDATE_ALL;
+ need_flags_update = true;
+}
+
+ObjectManager::~ObjectManager()
+{
+}
+
+static float object_volume_density(const Transform &tfm, Geometry *geom)
+{
+ if (geom->geometry_type == Geometry::VOLUME) {
+ /* Volume density automatically adjust to object scale. */
+ if (static_cast<Volume *>(geom)->get_object_space()) {
+ const float3 unit = normalize(one_float3());
+ return 1.0f / len(transform_direction(&tfm, unit));
+ }
+ }
+
+ return 1.0f;
+}
+
+void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state,
+ Object *ob,
+ bool update_all)
+{
+ KernelObject &kobject = state->objects[ob->index];
+ Transform *object_motion_pass = state->object_motion_pass;
+
+ Geometry *geom = ob->geometry;
+ uint flag = 0;
+
+ /* Compute transformations. */
+ Transform tfm = ob->tfm;
+ Transform itfm = transform_inverse(tfm);
+
+ float3 color = ob->color;
+ float pass_id = ob->pass_id;
+ float random_number = (float)ob->random_id * (1.0f / (float)0xFFFFFFFF);
+ int particle_index = (ob->particle_system) ?
+ ob->particle_index + state->particle_offset[ob->particle_system] :
+ 0;
+
+ kobject.tfm = tfm;
+ kobject.itfm = itfm;
+ kobject.volume_density = object_volume_density(tfm, geom);
+ kobject.color[0] = color.x;
+ kobject.color[1] = color.y;
+ kobject.color[2] = color.z;
+ kobject.pass_id = pass_id;
+ kobject.random_number = random_number;
+ kobject.particle_index = particle_index;
+ kobject.motion_offset = 0;
+ kobject.ao_distance = ob->ao_distance;
+
+ if (geom->get_use_motion_blur()) {
+ state->have_motion = true;
+ }
+
+ if (geom->geometry_type == Geometry::MESH) {
+ /* TODO: why only mesh? */
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
+ flag |= SD_OBJECT_HAS_VERTEX_MOTION;
+ }
+ }
+
+ if (state->need_motion == Scene::MOTION_PASS) {
+ /* Clear motion array if there is no actual motion. */
+ ob->update_motion();
+
+ /* Compute motion transforms. */
+ Transform tfm_pre, tfm_post;
+ if (ob->use_motion()) {
+ tfm_pre = ob->motion[0];
+ tfm_post = ob->motion[ob->motion.size() - 1];
+ }
+ else {
+ tfm_pre = tfm;
+ tfm_post = tfm;
+ }
+
+ /* Motion transformations, is world/object space depending if mesh
+ * comes with deformed position in object space, or if we transform
+ * the shading point in world space. */
+ if (!(flag & SD_OBJECT_HAS_VERTEX_MOTION)) {
+ tfm_pre = tfm_pre * itfm;
+ tfm_post = tfm_post * itfm;
+ }
+
+ int motion_pass_offset = ob->index * OBJECT_MOTION_PASS_SIZE;
+ object_motion_pass[motion_pass_offset + 0] = tfm_pre;
+ object_motion_pass[motion_pass_offset + 1] = tfm_post;
+ }
+ else if (state->need_motion == Scene::MOTION_BLUR) {
+ if (ob->use_motion()) {
+ kobject.motion_offset = state->motion_offset[ob->index];
+
+ /* Decompose transforms for interpolation. */
+ if (ob->tfm_is_modified() || update_all) {
+ DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
+ transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
+ }
+
+ flag |= SD_OBJECT_MOTION;
+ state->have_motion = true;
+ }
+ }
+
+ /* Dupli object coords and motion info. */
+ kobject.dupli_generated[0] = ob->dupli_generated[0];
+ kobject.dupli_generated[1] = ob->dupli_generated[1];
+ kobject.dupli_generated[2] = ob->dupli_generated[2];
+ kobject.numkeys = (geom->geometry_type == Geometry::HAIR) ?
+ static_cast<Hair *>(geom)->get_curve_keys().size() :
+ 0;
+ kobject.dupli_uv[0] = ob->dupli_uv[0];
+ kobject.dupli_uv[1] = ob->dupli_uv[1];
+ int totalsteps = geom->get_motion_steps();
+ kobject.numsteps = (totalsteps - 1) / 2;
+ kobject.numverts = (geom->geometry_type == Geometry::MESH ||
+ geom->geometry_type == Geometry::VOLUME) ?
+ static_cast<Mesh *>(geom)->get_verts().size() :
+ 0;
+ kobject.patch_map_offset = 0;
+ kobject.attribute_map_offset = 0;
+
+ if (ob->asset_name_is_modified() || update_all) {
+ uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0);
+ uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
+ kobject.cryptomatte_object = util_hash_to_float(hash_name);
+ kobject.cryptomatte_asset = util_hash_to_float(hash_asset);
+ }
+
+ kobject.shadow_terminator_shading_offset = 1.0f /
+ (1.0f - 0.5f * ob->shadow_terminator_shading_offset);
+ kobject.shadow_terminator_geometry_offset = ob->shadow_terminator_geometry_offset;
+
+ kobject.visibility = ob->visibility_for_tracing();
+ kobject.primitive_type = geom->primitive_type();
+
+ /* Object flag. */
+ if (ob->use_holdout) {
+ flag |= SD_OBJECT_HOLDOUT_MASK;
+ }
+ state->object_flag[ob->index] = flag;
+ state->object_volume_step[ob->index] = FLT_MAX;
+
+ /* Have curves. */
+ if (geom->geometry_type == Geometry::HAIR) {
+ state->have_curves = true;
+ }
+}
+
+void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress)
+{
+ UpdateObjectTransformState state;
+ state.need_motion = scene->need_motion();
+ state.have_motion = false;
+ state.have_curves = false;
+ state.scene = scene;
+ state.queue_start_object = 0;
+
+ state.objects = dscene->objects.alloc(scene->objects.size());
+ state.object_flag = dscene->object_flag.alloc(scene->objects.size());
+ state.object_volume_step = dscene->object_volume_step.alloc(scene->objects.size());
+ state.object_motion = NULL;
+ state.object_motion_pass = NULL;
+
+ if (state.need_motion == Scene::MOTION_PASS) {
+ state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE *
+ scene->objects.size());
+ }
+ else if (state.need_motion == Scene::MOTION_BLUR) {
+ /* Set object offsets into global object motion array. */
+ uint *motion_offsets = state.motion_offset.resize(scene->objects.size());
+ uint motion_offset = 0;
+
+ foreach (Object *ob, scene->objects) {
+ *motion_offsets = motion_offset;
+ motion_offsets++;
+
+ /* Clear motion array if there is no actual motion. */
+ ob->update_motion();
+ motion_offset += ob->motion.size();
+ }
+
+ state.object_motion = dscene->object_motion.alloc(motion_offset);
+ }
+
+ /* Particle system device offsets
+ * 0 is dummy particle, index starts at 1.
+ */
+ int numparticles = 1;
+ foreach (ParticleSystem *psys, scene->particle_systems) {
+ state.particle_offset[psys] = numparticles;
+ numparticles += psys->particles.size();
+ }
+
+ /* as all the arrays are the same size, checking only dscene.objects is sufficient */
+ const bool update_all = dscene->objects.need_realloc();
+
+ /* Parallel object update, with grain size to avoid too much threading overhead
+ * for individual objects. */
+ static const int OBJECTS_PER_TASK = 32;
+ parallel_for(blocked_range<size_t>(0, scene->objects.size(), OBJECTS_PER_TASK),
+ [&](const blocked_range<size_t> &r) {
+ for (size_t i = r.begin(); i != r.end(); i++) {
+ Object *ob = state.scene->objects[i];
+ device_update_object_transform(&state, ob, update_all);
+ }
+ });
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ dscene->objects.copy_to_device_if_modified();
+ if (state.need_motion == Scene::MOTION_PASS) {
+ dscene->object_motion_pass.copy_to_device();
+ }
+ else if (state.need_motion == Scene::MOTION_BLUR) {
+ dscene->object_motion.copy_to_device();
+ }
+
+ dscene->data.bvh.have_motion = state.have_motion;
+ dscene->data.bvh.have_curves = state.have_curves;
+
+ dscene->objects.clear_modified();
+ dscene->object_motion_pass.clear_modified();
+ dscene->object_motion.clear_modified();
+}
+
+void ObjectManager::device_update(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ if (!need_update())
+ return;
+
+ if (update_flags & (OBJECT_ADDED | OBJECT_REMOVED)) {
+ dscene->objects.tag_realloc();
+ dscene->object_motion_pass.tag_realloc();
+ dscene->object_motion.tag_realloc();
+ dscene->object_flag.tag_realloc();
+ dscene->object_volume_step.tag_realloc();
+ }
+
+ if (update_flags & HOLDOUT_MODIFIED) {
+ dscene->object_flag.tag_modified();
+ }
+
+ if (update_flags & PARTICLE_MODIFIED) {
+ dscene->objects.tag_modified();
+ }
+
+ VLOG(1) << "Total " << scene->objects.size() << " objects.";
+
+ device_free(device, dscene, false);
+
+ if (scene->objects.size() == 0)
+ return;
+
+ {
+ /* Assign object IDs. */
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->object.times.add_entry({"device_update (assign index)", time});
+ }
+ });
+
+ int index = 0;
+ foreach (Object *object, scene->objects) {
+ object->index = index++;
+
+ /* this is a bit too broad, however a bigger refactor might be needed to properly separate
+ * update each type of data (transform, flags, etc.) */
+ if (object->is_modified()) {
+ dscene->objects.tag_modified();
+ dscene->object_motion_pass.tag_modified();
+ dscene->object_motion.tag_modified();
+ dscene->object_flag.tag_modified();
+ dscene->object_volume_step.tag_modified();
+ }
+ }
+ }
+
+ {
+ /* set object transform matrices, before applying static transforms */
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->object.times.add_entry(
+ {"device_update (copy objects to device)", time});
+ }
+ });
+
+ progress.set_status("Updating Objects", "Copying Transformations to device");
+ device_update_transforms(dscene, scene, progress);
+ }
+
+ if (progress.get_cancel())
+ return;
+
+ /* prepare for static BVH building */
+ /* todo: do before to support getting object level coords? */
+ if (scene->params.bvh_type == BVH_TYPE_STATIC) {
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->object.times.add_entry(
+ {"device_update (apply static transforms)", time});
+ }
+ });
+
+ progress.set_status("Updating Objects", "Applying Static Transformations");
+ apply_static_transforms(dscene, scene, progress);
+ }
+
+ foreach (Object *object, scene->objects) {
+ object->clear_modified();
+ }
+}
+
+void ObjectManager::device_update_flags(
+ Device *, DeviceScene *dscene, Scene *scene, Progress & /*progress*/, bool bounds_valid)
+{
+ if (!need_update() && !need_flags_update)
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->object.times.add_entry({"device_update_flags", time});
+ }
+ });
+
+ update_flags = UPDATE_NONE;
+ need_flags_update = false;
+
+ if (scene->objects.size() == 0)
+ return;
+
+ /* Object info flag. */
+ uint *object_flag = dscene->object_flag.data();
+ float *object_volume_step = dscene->object_volume_step.data();
+
+ /* Object volume intersection. */
+ vector<Object *> volume_objects;
+ bool has_volume_objects = false;
+ foreach (Object *object, scene->objects) {
+ if (object->geometry->has_volume) {
+ if (bounds_valid) {
+ volume_objects.push_back(object);
+ }
+ has_volume_objects = true;
+ object_volume_step[object->index] = object->compute_volume_step_size();
+ }
+ else {
+ object_volume_step[object->index] = FLT_MAX;
+ }
+ }
+
+ foreach (Object *object, scene->objects) {
+ if (object->geometry->has_volume) {
+ object_flag[object->index] |= SD_OBJECT_HAS_VOLUME;
+ object_flag[object->index] &= ~SD_OBJECT_HAS_VOLUME_ATTRIBUTES;
+
+ foreach (Attribute &attr, object->geometry->attributes.attributes) {
+ if (attr.element == ATTR_ELEMENT_VOXEL) {
+ object_flag[object->index] |= SD_OBJECT_HAS_VOLUME_ATTRIBUTES;
+ }
+ }
+ }
+ else {
+ object_flag[object->index] &= ~(SD_OBJECT_HAS_VOLUME | SD_OBJECT_HAS_VOLUME_ATTRIBUTES);
+ }
+
+ if (object->is_shadow_catcher) {
+ object_flag[object->index] |= SD_OBJECT_SHADOW_CATCHER;
+ }
+ else {
+ object_flag[object->index] &= ~SD_OBJECT_SHADOW_CATCHER;
+ }
+
+ if (bounds_valid) {
+ object->intersects_volume = false;
+ foreach (Object *volume_object, volume_objects) {
+ if (object == volume_object) {
+ continue;
+ }
+ if (object->bounds.intersects(volume_object->bounds)) {
+ object_flag[object->index] |= SD_OBJECT_INTERSECTS_VOLUME;
+ object->intersects_volume = true;
+ break;
+ }
+ }
+ }
+ else if (has_volume_objects) {
+ /* Not really valid, but can't make more reliable in the case
+ * of bounds not being up to date.
+ */
+ object_flag[object->index] |= SD_OBJECT_INTERSECTS_VOLUME;
+ }
+ }
+
+ /* Copy object flag. */
+ dscene->object_flag.copy_to_device();
+ dscene->object_volume_step.copy_to_device();
+
+ dscene->object_flag.clear_modified();
+ dscene->object_volume_step.clear_modified();
+}
+
+void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene)
+{
+ if (dscene->objects.size() == 0) {
+ return;
+ }
+
+ KernelObject *kobjects = dscene->objects.data();
+
+ bool update = false;
+
+ foreach (Object *object, scene->objects) {
+ Geometry *geom = object->geometry;
+
+ if (geom->geometry_type == Geometry::MESH) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->patch_table) {
+ uint patch_map_offset = 2 * (mesh->patch_table_offset + mesh->patch_table->total_size() -
+ mesh->patch_table->num_nodes * PATCH_NODE_SIZE) -
+ mesh->patch_offset;
+
+ if (kobjects[object->index].patch_map_offset != patch_map_offset) {
+ kobjects[object->index].patch_map_offset = patch_map_offset;
+ update = true;
+ }
+ }
+ }
+
+ size_t attr_map_offset = object->attr_map_offset;
+
+ /* An object attribute map cannot have a zero offset because mesh maps come first. */
+ if (attr_map_offset == 0) {
+ attr_map_offset = geom->attr_map_offset;
+ }
+
+ if (kobjects[object->index].attribute_map_offset != attr_map_offset) {
+ kobjects[object->index].attribute_map_offset = attr_map_offset;
+ update = true;
+ }
+ }
+
+ if (update) {
+ dscene->objects.copy_to_device();
+ }
+}
+
+void ObjectManager::device_free(Device *, DeviceScene *dscene, bool force_free)
+{
+ dscene->objects.free_if_need_realloc(force_free);
+ dscene->object_motion_pass.free_if_need_realloc(force_free);
+ dscene->object_motion.free_if_need_realloc(force_free);
+ dscene->object_flag.free_if_need_realloc(force_free);
+ dscene->object_volume_step.free_if_need_realloc(force_free);
+}
+
+void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress)
+{
+ /* todo: normals and displacement should be done before applying transform! */
+ /* todo: create objects/geometry in right order! */
+
+ /* counter geometry users */
+ map<Geometry *, int> geometry_users;
+ Scene::MotionType need_motion = scene->need_motion();
+ bool motion_blur = need_motion == Scene::MOTION_BLUR;
+ bool apply_to_motion = need_motion != Scene::MOTION_PASS;
+ int i = 0;
+
+ foreach (Object *object, scene->objects) {
+ map<Geometry *, int>::iterator it = geometry_users.find(object->geometry);
+
+ if (it == geometry_users.end())
+ geometry_users[object->geometry] = 1;
+ else
+ it->second++;
+ }
+
+ if (progress.get_cancel())
+ return;
+
+ uint *object_flag = dscene->object_flag.data();
+
+ /* apply transforms for objects with single user geometry */
+ foreach (Object *object, scene->objects) {
+ /* Annoying feedback loop here: we can't use is_instanced() because
+ * it'll use uninitialized transform_applied flag.
+ *
+ * Could be solved by moving reference counter to Geometry.
+ */
+ Geometry *geom = object->geometry;
+ bool apply = (geometry_users[geom] == 1) && !geom->has_surface_bssrdf &&
+ !geom->has_true_displacement();
+
+ if (geom->geometry_type == Geometry::MESH) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ apply = apply && mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE;
+ }
+ else if (geom->geometry_type == Geometry::HAIR) {
+ /* Can't apply non-uniform scale to curves, this can't be represented by
+ * control points and radius alone. */
+ float scale;
+ apply = apply && transform_uniform_scale(object->tfm, scale);
+ }
+
+ if (apply) {
+ if (!(motion_blur && object->use_motion())) {
+ if (!geom->transform_applied) {
+ object->apply_transform(apply_to_motion);
+ geom->transform_applied = true;
+
+ if (progress.get_cancel())
+ return;
+ }
+
+ object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED;
+ if (geom->transform_negative_scaled)
+ object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED;
+ }
+ }
+
+ i++;
+ }
+}
+
+void ObjectManager::tag_update(Scene *scene, uint32_t flag)
+{
+ update_flags |= flag;
+
+ /* avoid infinite loops if the geometry manager tagged us for an update */
+ if ((flag & GEOMETRY_MANAGER) == 0) {
+ uint32_t geometry_flag = GeometryManager::OBJECT_MANAGER;
+
+ /* Also notify in case added or removed objects were instances, as no Geometry might have been
+ * added or removed, but the BVH still needs to updated. */
+ if ((flag & (OBJECT_ADDED | OBJECT_REMOVED)) != 0) {
+ geometry_flag |= (GeometryManager::GEOMETRY_ADDED | GeometryManager::GEOMETRY_REMOVED);
+ }
+
+ if ((flag & TRANSFORM_MODIFIED) != 0) {
+ geometry_flag |= GeometryManager::TRANSFORM_MODIFIED;
+ }
+
+ if ((flag & VISIBILITY_MODIFIED) != 0) {
+ geometry_flag |= GeometryManager::VISIBILITY_MODIFIED;
+ }
+
+ scene->geometry_manager->tag_update(scene, geometry_flag);
+ }
+
+ scene->light_manager->tag_update(scene, LightManager::OBJECT_MANAGER);
+
+ /* Integrator's shadow catcher settings depends on object visibility settings. */
+ if (flag & (OBJECT_ADDED | OBJECT_REMOVED | OBJECT_MODIFIED)) {
+ scene->integrator->tag_update(scene, Integrator::OBJECT_MANAGER);
+ }
+}
+
+bool ObjectManager::need_update() const
+{
+ return update_flags != UPDATE_NONE;
+}
+
+string ObjectManager::get_cryptomatte_objects(Scene *scene)
+{
+ string manifest = "{";
+
+ unordered_set<ustring, ustringHash> objects;
+ foreach (Object *object, scene->objects) {
+ if (objects.count(object->name)) {
+ continue;
+ }
+ objects.insert(object->name);
+ uint32_t hash_name = util_murmur_hash3(object->name.c_str(), object->name.length(), 0);
+ manifest += string_printf("\"%s\":\"%08x\",", object->name.c_str(), hash_name);
+ }
+ manifest[manifest.size() - 1] = '}';
+ return manifest;
+}
+
+string ObjectManager::get_cryptomatte_assets(Scene *scene)
+{
+ string manifest = "{";
+ unordered_set<ustring, ustringHash> assets;
+ foreach (Object *ob, scene->objects) {
+ if (assets.count(ob->asset_name)) {
+ continue;
+ }
+ assets.insert(ob->asset_name);
+ uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
+ manifest += string_printf("\"%s\":\"%08x\",", ob->asset_name.c_str(), hash_asset);
+ }
+ manifest[manifest.size() - 1] = '}';
+ return manifest;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/object.h b/intern/cycles/scene/object.h
new file mode 100644
index 00000000000..f6dc57ee8b9
--- /dev/null
+++ b/intern/cycles/scene/object.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __OBJECT_H__
+#define __OBJECT_H__
+
+#include "graph/node.h"
+
+/* included as Object::set_particle_system defined through NODE_SOCKET_API does
+ * not select the right Node::set overload as it does not know that ParticleSystem
+ * is a Node */
+#include "scene/particles.h"
+#include "scene/scene.h"
+
+#include "util/array.h"
+#include "util/boundbox.h"
+#include "util/param.h"
+#include "util/thread.h"
+#include "util/transform.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Geometry;
+class ParticleSystem;
+class Progress;
+class Scene;
+struct Transform;
+struct UpdateObjectTransformState;
+class ObjectManager;
+
+/* Object */
+
+class Object : public Node {
+ public:
+ NODE_DECLARE
+
+ NODE_SOCKET_API(Geometry *, geometry)
+ NODE_SOCKET_API(Transform, tfm)
+ BoundBox bounds;
+ NODE_SOCKET_API(uint, random_id)
+ NODE_SOCKET_API(int, pass_id)
+ NODE_SOCKET_API(float3, color)
+ NODE_SOCKET_API(ustring, asset_name)
+ vector<ParamValue> attributes;
+ NODE_SOCKET_API(uint, visibility)
+ NODE_SOCKET_API_ARRAY(array<Transform>, motion)
+ NODE_SOCKET_API(bool, hide_on_missing_motion)
+ NODE_SOCKET_API(bool, use_holdout)
+ NODE_SOCKET_API(bool, is_shadow_catcher)
+ NODE_SOCKET_API(float, shadow_terminator_shading_offset)
+ NODE_SOCKET_API(float, shadow_terminator_geometry_offset)
+
+ NODE_SOCKET_API(float3, dupli_generated)
+ NODE_SOCKET_API(float2, dupli_uv)
+
+ NODE_SOCKET_API(ParticleSystem *, particle_system);
+ NODE_SOCKET_API(int, particle_index);
+
+ NODE_SOCKET_API(float, ao_distance)
+
+ /* Set during device update. */
+ bool intersects_volume;
+
+ Object();
+ ~Object();
+
+ void tag_update(Scene *scene);
+
+ void compute_bounds(bool motion_blur);
+ void apply_transform(bool apply_to_motion);
+
+ /* Convert between normalized -1..1 motion time and index
+ * in the motion array. */
+ bool use_motion() const;
+ float motion_time(int step) const;
+ int motion_step(float time) const;
+ void update_motion();
+
+ /* Maximum number of motion steps supported (due to Embree). */
+ static const uint MAX_MOTION_STEPS = 129;
+
+ /* Check whether object is traceable and it worth adding it to
+ * kernel scene.
+ */
+ bool is_traceable() const;
+
+ /* Combine object's visibility with all possible internal run-time
+ * determined flags which denotes trace-time visibility.
+ */
+ uint visibility_for_tracing() const;
+
+ /* Returns the index that is used in the kernel for this object. */
+ int get_device_index() const;
+
+ /* Compute step size from attributes, shaders, transforms. */
+ float compute_volume_step_size() const;
+
+ protected:
+ /* Specifies the position of the object in scene->objects and
+ * in the device vectors. Gets set in device_update. */
+ int index;
+
+ /* Reference to the attribute map with object attributes,
+ * or 0 if none. Set in update_svm_attributes. */
+ size_t attr_map_offset;
+
+ friend class ObjectManager;
+ friend class GeometryManager;
+};
+
+/* Object Manager */
+
+class ObjectManager {
+ uint32_t update_flags;
+
+ public:
+ enum : uint32_t {
+ PARTICLE_MODIFIED = (1 << 0),
+ GEOMETRY_MANAGER = (1 << 1),
+ MOTION_BLUR_MODIFIED = (1 << 2),
+ OBJECT_ADDED = (1 << 3),
+ OBJECT_REMOVED = (1 << 4),
+ OBJECT_MODIFIED = (1 << 5),
+ HOLDOUT_MODIFIED = (1 << 6),
+ TRANSFORM_MODIFIED = (1 << 7),
+ VISIBILITY_MODIFIED = (1 << 8),
+
+ /* tag everything in the manager for an update */
+ UPDATE_ALL = ~0u,
+
+ UPDATE_NONE = 0u,
+ };
+
+ bool need_flags_update;
+
+ ObjectManager();
+ ~ObjectManager();
+
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
+ void device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress);
+
+ void device_update_flags(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress,
+ bool bounds_valid = true);
+ void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene);
+
+ void device_free(Device *device, DeviceScene *dscene, bool force_free);
+
+ void tag_update(Scene *scene, uint32_t flag);
+
+ bool need_update() const;
+
+ void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress);
+
+ string get_cryptomatte_objects(Scene *scene);
+ string get_cryptomatte_assets(Scene *scene);
+
+ protected:
+ void device_update_object_transform(UpdateObjectTransformState *state,
+ Object *ob,
+ bool update_all);
+ void device_update_object_transform_task(UpdateObjectTransformState *state);
+ bool device_update_object_transform_pop_work(UpdateObjectTransformState *state,
+ int *start_index,
+ int *num_objects);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __OBJECT_H__ */
diff --git a/intern/cycles/scene/osl.cpp b/intern/cycles/scene/osl.cpp
new file mode 100644
index 00000000000..c5f38d4f270
--- /dev/null
+++ b/intern/cycles/scene/osl.cpp
@@ -0,0 +1,1309 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device/device.h"
+
+#include "scene/background.h"
+#include "scene/colorspace.h"
+#include "scene/light.h"
+#include "scene/osl.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+#include "scene/stats.h"
+
+#ifdef WITH_OSL
+
+# include "kernel/osl/globals.h"
+# include "kernel/osl/services.h"
+# include "kernel/osl/shader.h"
+
+# include "util/aligned_malloc.h"
+# include "util/foreach.h"
+# include "util/log.h"
+# include "util/md5.h"
+# include "util/path.h"
+# include "util/progress.h"
+# include "util/projection.h"
+
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_OSL
+
+/* Shared Texture and Shading System */
+
+OSL::TextureSystem *OSLShaderManager::ts_shared = NULL;
+int OSLShaderManager::ts_shared_users = 0;
+thread_mutex OSLShaderManager::ts_shared_mutex;
+
+OSL::ShadingSystem *OSLShaderManager::ss_shared = NULL;
+OSLRenderServices *OSLShaderManager::services_shared = NULL;
+int OSLShaderManager::ss_shared_users = 0;
+thread_mutex OSLShaderManager::ss_shared_mutex;
+thread_mutex OSLShaderManager::ss_mutex;
+int OSLCompiler::texture_shared_unique_id = 0;
+
+/* Shader Manager */
+
+OSLShaderManager::OSLShaderManager()
+{
+ texture_system_init();
+ shading_system_init();
+}
+
+OSLShaderManager::~OSLShaderManager()
+{
+ shading_system_free();
+ texture_system_free();
+}
+
+void OSLShaderManager::free_memory()
+{
+# ifdef OSL_HAS_BLENDER_CLEANUP_FIX
+ /* There is a problem with LLVM+OSL: The order global destructors across
+ * different compilation units run cannot be guaranteed, on windows this means
+ * that the LLVM destructors run before the osl destructors, causing a crash
+ * when the process exits. the OSL in svn has a special cleanup hack to
+ * sidestep this behavior */
+ OSL::pvt::LLVM_Util::Cleanup();
+# endif
+}
+
+void OSLShaderManager::reset(Scene * /*scene*/)
+{
+ shading_system_free();
+ shading_system_init();
+}
+
+void OSLShaderManager::device_update_specific(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ if (!need_update())
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->osl.times.add_entry({"device_update", time});
+ }
+ });
+
+ VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
+
+ device_free(device, dscene, scene);
+
+ /* set texture system */
+ scene->image_manager->set_osl_texture_system((void *)ts);
+
+ /* create shaders */
+ OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
+ Shader *background_shader = scene->background->get_shader(scene);
+
+ foreach (Shader *shader, scene->shaders) {
+ assert(shader->graph);
+
+ if (progress.get_cancel())
+ return;
+
+ /* we can only compile one shader at the time as the OSL ShadingSytem
+ * has a single state, but we put the lock here so different renders can
+ * compile shaders alternating */
+ thread_scoped_lock lock(ss_mutex);
+
+ OSLCompiler compiler(this, services, ss, scene);
+ compiler.background = (shader == background_shader);
+ compiler.compile(og, shader);
+
+ if (shader->get_use_mis() && shader->has_surface_emission)
+ scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
+ }
+
+ /* setup shader engine */
+ og->ss = ss;
+ og->ts = ts;
+ og->services = services;
+
+ int background_id = scene->shader_manager->get_shader_id(background_shader);
+ og->background_state = og->surface_state[background_id & SHADER_MASK];
+ og->use = true;
+
+ foreach (Shader *shader, scene->shaders)
+ shader->clear_modified();
+
+ update_flags = UPDATE_NONE;
+
+ /* add special builtin texture types */
+ services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
+ services->textures.insert(ustring("@bevel"), new OSLTextureHandle(OSLTextureHandle::BEVEL));
+
+ device_update_common(device, dscene, scene, progress);
+
+ {
+ /* Perform greedyjit optimization.
+ *
+ * This might waste time on optimizing groups which are never actually
+ * used, but this prevents OSL from allocating data on TLS at render
+ * time.
+ *
+ * This is much better for us because this way we aren't required to
+ * stop task scheduler threads to make sure all TLS is clean and don't
+ * have issues with TLS data free accessing freed memory if task scheduler
+ * is being freed after the Session is freed.
+ */
+ thread_scoped_lock lock(ss_shared_mutex);
+ ss->optimize_all_groups();
+ }
+}
+
+void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
+{
+ OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
+
+ device_free_common(device, dscene, scene);
+
+ /* clear shader engine */
+ og->use = false;
+ og->ss = NULL;
+ og->ts = NULL;
+
+ og->surface_state.clear();
+ og->volume_state.clear();
+ og->displacement_state.clear();
+ og->bump_state.clear();
+ og->background_state.reset();
+}
+
+void OSLShaderManager::texture_system_init()
+{
+ /* create texture system, shared between different renders to reduce memory usage */
+ thread_scoped_lock lock(ts_shared_mutex);
+
+ if (ts_shared_users == 0) {
+ ts_shared = TextureSystem::create(true);
+
+ ts_shared->attribute("automip", 1);
+ ts_shared->attribute("autotile", 64);
+ ts_shared->attribute("gray_to_rgb", 1);
+
+ /* effectively unlimited for now, until we support proper mipmap lookups */
+ ts_shared->attribute("max_memory_MB", 16384);
+ }
+
+ ts = ts_shared;
+ ts_shared_users++;
+}
+
+void OSLShaderManager::texture_system_free()
+{
+ /* shared texture system decrease users and destroy if no longer used */
+ thread_scoped_lock lock(ts_shared_mutex);
+ ts_shared_users--;
+
+ if (ts_shared_users == 0) {
+ ts_shared->invalidate_all(true);
+ OSL::TextureSystem::destroy(ts_shared);
+ ts_shared = NULL;
+ }
+
+ ts = NULL;
+}
+
+void OSLShaderManager::shading_system_init()
+{
+ /* create shading system, shared between different renders to reduce memory usage */
+ thread_scoped_lock lock(ss_shared_mutex);
+
+ if (ss_shared_users == 0) {
+ /* Must use aligned new due to concurrent hash map. */
+ services_shared = util_aligned_new<OSLRenderServices>(ts_shared);
+
+ string shader_path = path_get("shader");
+# ifdef _WIN32
+ /* Annoying thing, Cycles stores paths in UTF-8 codepage, so it can
+ * operate with file paths with any character. This requires to use wide
+ * char functions, but OSL uses old fashioned ANSI functions which means:
+ *
+ * - We have to convert our paths to ANSI before passing to OSL
+ * - OSL can't be used when there's a multi-byte character in the path
+ * to the shaders folder.
+ */
+ shader_path = string_to_ansi(shader_path);
+# endif
+
+ ss_shared = new OSL::ShadingSystem(services_shared, ts_shared, &errhandler);
+ ss_shared->attribute("lockgeom", 1);
+ ss_shared->attribute("commonspace", "world");
+ ss_shared->attribute("searchpath:shader", shader_path);
+ ss_shared->attribute("greedyjit", 1);
+
+ VLOG(1) << "Using shader search path: " << shader_path;
+
+ /* our own ray types */
+ static const char *raytypes[] = {
+ "camera", /* PATH_RAY_CAMERA */
+ "reflection", /* PATH_RAY_REFLECT */
+ "refraction", /* PATH_RAY_TRANSMIT */
+ "diffuse", /* PATH_RAY_DIFFUSE */
+ "glossy", /* PATH_RAY_GLOSSY */
+ "singular", /* PATH_RAY_SINGULAR */
+ "transparent", /* PATH_RAY_TRANSPARENT */
+ "volume_scatter", /* PATH_RAY_VOLUME_SCATTER */
+
+ "shadow", /* PATH_RAY_SHADOW_OPAQUE */
+ "shadow", /* PATH_RAY_SHADOW_TRANSPARENT */
+
+ "__unused__", /* PATH_RAY_NODE_UNALIGNED */
+ "__unused__", /* PATH_RAY_MIS_SKIP */
+
+ "diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */
+
+ "__unused__", /* PATH_RAY_SINGLE_PASS_DONE */
+ "__unused__", /* PATH_RAY_TRANSPARENT_BACKGROUND */
+ "__unused__", /* PATH_RAY_TERMINATE_IMMEDIATE */
+ "__unused__", /* PATH_RAY_TERMINATE_AFTER_TRANSPARENT */
+ "__unused__", /* PATH_RAY_EMISSION */
+ "__unused__", /* PATH_RAY_SUBSURFACE */
+ "__unused__", /* PATH_RAY_DENOISING_FEATURES */
+ "__unused__", /* PATH_RAY_REFLECT_PASS */
+ "__unused__", /* PATH_RAY_TRANSMISSION_PASS */
+ "__unused__", /* PATH_RAY_VOLUME_PASS */
+ "__unused__", /* PATH_RAY_SHADOW_FOR_LIGHT */
+ "__unused__", /* PATH_RAY_SHADOW_CATCHER_HIT */
+ "__unused__", /* PATH_RAY_SHADOW_CATCHER_PASS */
+ };
+
+ const int nraytypes = sizeof(raytypes) / sizeof(raytypes[0]);
+ ss_shared->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes);
+
+ OSLShader::register_closures((OSLShadingSystem *)ss_shared);
+
+ loaded_shaders.clear();
+ }
+
+ ss = ss_shared;
+ services = services_shared;
+ ss_shared_users++;
+}
+
+void OSLShaderManager::shading_system_free()
+{
+ /* shared shading system decrease users and destroy if no longer used */
+ thread_scoped_lock lock(ss_shared_mutex);
+ ss_shared_users--;
+
+ if (ss_shared_users == 0) {
+ delete ss_shared;
+ ss_shared = NULL;
+
+ util_aligned_delete(services_shared);
+ services_shared = NULL;
+ }
+
+ ss = NULL;
+ services = NULL;
+}
+
+bool OSLShaderManager::osl_compile(const string &inputfile, const string &outputfile)
+{
+ vector<string> options;
+ string stdosl_path;
+ string shader_path = path_get("shader");
+
+ /* Specify output file name. */
+ options.push_back("-o");
+ options.push_back(outputfile);
+
+ /* Specify standard include path. */
+ string include_path_arg = string("-I") + shader_path;
+ options.push_back(include_path_arg);
+
+ stdosl_path = path_join(shader_path, "stdcycles.h");
+
+ /* Compile.
+ *
+ * Mutex protected because the OSL compiler does not appear to be thread safe, see T92503. */
+ static thread_mutex osl_compiler_mutex;
+ thread_scoped_lock lock(osl_compiler_mutex);
+
+ OSL::OSLCompiler *compiler = new OSL::OSLCompiler(&OSL::ErrorHandler::default_handler());
+ bool ok = compiler->compile(string_view(inputfile), options, string_view(stdosl_path));
+ delete compiler;
+
+ return ok;
+}
+
+bool OSLShaderManager::osl_query(OSL::OSLQuery &query, const string &filepath)
+{
+ string searchpath = path_user_get("shaders");
+ return query.open(filepath, searchpath);
+}
+
+static string shader_filepath_hash(const string &filepath, uint64_t modified_time)
+{
+ /* compute a hash from filepath and modified time to detect changes */
+ MD5Hash md5;
+ md5.append((const uint8_t *)filepath.c_str(), filepath.size());
+ md5.append((const uint8_t *)&modified_time, sizeof(modified_time));
+
+ return md5.get_hex();
+}
+
+const char *OSLShaderManager::shader_test_loaded(const string &hash)
+{
+ map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
+ return (it == loaded_shaders.end()) ? NULL : it->first.c_str();
+}
+
+OSLShaderInfo *OSLShaderManager::shader_loaded_info(const string &hash)
+{
+ map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
+ return (it == loaded_shaders.end()) ? NULL : &it->second;
+}
+
+const char *OSLShaderManager::shader_load_filepath(string filepath)
+{
+ size_t len = filepath.size();
+ string extension = filepath.substr(len - 4);
+ uint64_t modified_time = path_modified_time(filepath);
+
+ if (extension == ".osl") {
+ /* .OSL File */
+ string osopath = filepath.substr(0, len - 4) + ".oso";
+ uint64_t oso_modified_time = path_modified_time(osopath);
+
+ /* test if we have loaded the corresponding .OSO already */
+ if (oso_modified_time != 0) {
+ const char *hash = shader_test_loaded(shader_filepath_hash(osopath, oso_modified_time));
+
+ if (hash)
+ return hash;
+ }
+
+ /* Auto-compile .OSL to .OSO if needed. */
+ if (oso_modified_time == 0 || (oso_modified_time < modified_time)) {
+ OSLShaderManager::osl_compile(filepath, osopath);
+ modified_time = path_modified_time(osopath);
+ }
+ else
+ modified_time = oso_modified_time;
+
+ filepath = osopath;
+ }
+ else {
+ if (extension == ".oso") {
+ /* .OSO File, nothing to do */
+ }
+ else if (path_dirname(filepath) == "") {
+ /* .OSO File in search path */
+ filepath = path_join(path_user_get("shaders"), filepath + ".oso");
+ }
+ else {
+ /* unknown file */
+ return NULL;
+ }
+
+ /* test if we have loaded this .OSO already */
+ const char *hash = shader_test_loaded(shader_filepath_hash(filepath, modified_time));
+
+ if (hash)
+ return hash;
+ }
+
+ /* read oso bytecode from file */
+ string bytecode_hash = shader_filepath_hash(filepath, modified_time);
+ string bytecode;
+
+ if (!path_read_text(filepath, bytecode)) {
+ fprintf(stderr, "Cycles shader graph: failed to read file %s\n", filepath.c_str());
+ OSLShaderInfo info;
+ loaded_shaders[bytecode_hash] = info; /* to avoid repeat tries */
+ return NULL;
+ }
+
+ return shader_load_bytecode(bytecode_hash, bytecode);
+}
+
+const char *OSLShaderManager::shader_load_bytecode(const string &hash, const string &bytecode)
+{
+ ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str());
+
+ OSLShaderInfo info;
+
+ if (!info.query.open_bytecode(bytecode)) {
+ fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str());
+ }
+
+ /* this is a bit weak, but works */
+ info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
+ info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
+ info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
+
+ loaded_shaders[hash] = info;
+
+ return loaded_shaders.find(hash)->first.c_str();
+}
+
+/* This is a static function to avoid RTTI link errors with only this
+ * file being compiled without RTTI to match OSL and LLVM libraries. */
+OSLNode *OSLShaderManager::osl_node(ShaderGraph *graph,
+ ShaderManager *manager,
+ const std::string &filepath,
+ const std::string &bytecode_hash,
+ const std::string &bytecode)
+{
+ if (!manager->use_osl()) {
+ return NULL;
+ }
+
+ /* create query */
+ OSLShaderManager *osl_manager = static_cast<OSLShaderManager *>(manager);
+ const char *hash;
+
+ if (!filepath.empty()) {
+ hash = osl_manager->shader_load_filepath(filepath);
+ }
+ else {
+ hash = osl_manager->shader_test_loaded(bytecode_hash);
+ if (!hash)
+ hash = osl_manager->shader_load_bytecode(bytecode_hash, bytecode);
+ }
+
+ if (!hash) {
+ return NULL;
+ }
+
+ OSLShaderInfo *info = osl_manager->shader_loaded_info(hash);
+
+ /* count number of inputs */
+ size_t num_inputs = 0;
+
+ for (int i = 0; i < info->query.nparams(); i++) {
+ const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
+
+ /* skip unsupported types */
+ if (param->varlenarray || param->isstruct || param->type.arraylen > 1)
+ continue;
+
+ if (!param->isoutput)
+ num_inputs++;
+ }
+
+ /* create node */
+ OSLNode *node = OSLNode::create(graph, num_inputs);
+
+ /* add new sockets from parameters */
+ set<void *> used_sockets;
+
+ for (int i = 0; i < info->query.nparams(); i++) {
+ const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
+
+ /* skip unsupported types */
+ if (param->varlenarray || param->isstruct || param->type.arraylen > 1)
+ continue;
+
+ SocketType::Type socket_type;
+
+ if (param->isclosure) {
+ socket_type = SocketType::CLOSURE;
+ }
+ else if (param->type.vecsemantics != TypeDesc::NOSEMANTICS) {
+ if (param->type.vecsemantics == TypeDesc::COLOR)
+ socket_type = SocketType::COLOR;
+ else if (param->type.vecsemantics == TypeDesc::POINT)
+ socket_type = SocketType::POINT;
+ else if (param->type.vecsemantics == TypeDesc::VECTOR)
+ socket_type = SocketType::VECTOR;
+ else if (param->type.vecsemantics == TypeDesc::NORMAL)
+ socket_type = SocketType::NORMAL;
+ else
+ continue;
+
+ if (!param->isoutput && param->validdefault) {
+ float3 *default_value = (float3 *)node->input_default_value();
+ default_value->x = param->fdefault[0];
+ default_value->y = param->fdefault[1];
+ default_value->z = param->fdefault[2];
+ }
+ }
+ else if (param->type.aggregate == TypeDesc::SCALAR) {
+ if (param->type.basetype == TypeDesc::INT) {
+ socket_type = SocketType::INT;
+
+ if (!param->isoutput && param->validdefault) {
+ *(int *)node->input_default_value() = param->idefault[0];
+ }
+ }
+ else if (param->type.basetype == TypeDesc::FLOAT) {
+ socket_type = SocketType::FLOAT;
+
+ if (!param->isoutput && param->validdefault) {
+ *(float *)node->input_default_value() = param->fdefault[0];
+ }
+ }
+ else if (param->type.basetype == TypeDesc::STRING) {
+ socket_type = SocketType::STRING;
+
+ if (!param->isoutput && param->validdefault) {
+ *(ustring *)node->input_default_value() = param->sdefault[0];
+ }
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+
+ if (param->isoutput) {
+ node->add_output(param->name, socket_type);
+ }
+ else {
+ node->add_input(param->name, socket_type);
+ }
+ }
+
+ /* Set byte-code hash or file-path. */
+ if (!bytecode_hash.empty()) {
+ node->bytecode_hash = bytecode_hash;
+ }
+ else {
+ node->filepath = filepath;
+ }
+
+ /* Generate inputs and outputs */
+ node->create_inputs_outputs(node->type);
+
+ return node;
+}
+
+/* Graph Compiler */
+
+OSLCompiler::OSLCompiler(OSLShaderManager *manager,
+ OSLRenderServices *services,
+ OSL::ShadingSystem *ss,
+ Scene *scene)
+ : scene(scene), manager(manager), services(services), ss(ss)
+{
+ current_type = SHADER_TYPE_SURFACE;
+ current_shader = NULL;
+ background = false;
+}
+
+string OSLCompiler::id(ShaderNode *node)
+{
+ /* assign layer unique name based on pointer address + bump mode */
+ stringstream stream;
+ stream << "node_" << node->type->name << "_" << node;
+
+ return stream.str();
+}
+
+string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
+{
+ string sname(input->name().string());
+ size_t i;
+
+ /* Strip white-space. */
+ while ((i = sname.find(" ")) != string::npos)
+ sname.replace(i, 1, "");
+
+ /* if output exists with the same name, add "In" suffix */
+ foreach (ShaderOutput *output, node->outputs) {
+ if (input->name() == output->name()) {
+ sname += "In";
+ break;
+ }
+ }
+
+ return sname;
+}
+
+string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
+{
+ string sname(output->name().string());
+ size_t i;
+
+ /* Strip white-space. */
+ while ((i = sname.find(" ")) != string::npos)
+ sname.replace(i, 1, "");
+
+ /* if input exists with the same name, add "Out" suffix */
+ foreach (ShaderInput *input, node->inputs) {
+ if (input->name() == output->name()) {
+ sname += "Out";
+ break;
+ }
+ }
+
+ return sname;
+}
+
+bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
+{
+ /* exception for output node, only one input is actually used
+ * depending on the current shader type */
+
+ if (input->flags() & SocketType::SVM_INTERNAL)
+ return true;
+
+ if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) {
+ if (input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE)
+ return true;
+ if (input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME)
+ return true;
+ if (input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT)
+ return true;
+ if (input->name() == "Normal" && current_type != SHADER_TYPE_BUMP)
+ return true;
+ }
+ else if (node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
+ if (input->name() == "Height")
+ return true;
+ }
+ else if (current_type == SHADER_TYPE_DISPLACEMENT && input->link &&
+ input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
+ return true;
+
+ return false;
+}
+
+void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
+{
+ /* load filepath */
+ if (isfilepath) {
+ name = manager->shader_load_filepath(name);
+
+ if (name == NULL)
+ return;
+ }
+
+ /* pass in fixed parameter values */
+ foreach (ShaderInput *input, node->inputs) {
+ if (!input->link) {
+ /* checks to untangle graphs */
+ if (node_skip_input(node, input))
+ continue;
+
+ string param_name = compatible_name(node, input);
+ const SocketType &socket = input->socket_type;
+ switch (input->type()) {
+ case SocketType::COLOR:
+ parameter_color(param_name.c_str(), node->get_float3(socket));
+ break;
+ case SocketType::POINT:
+ parameter_point(param_name.c_str(), node->get_float3(socket));
+ break;
+ case SocketType::VECTOR:
+ parameter_vector(param_name.c_str(), node->get_float3(socket));
+ break;
+ case SocketType::NORMAL:
+ parameter_normal(param_name.c_str(), node->get_float3(socket));
+ break;
+ case SocketType::FLOAT:
+ parameter(param_name.c_str(), node->get_float(socket));
+ break;
+ case SocketType::INT:
+ parameter(param_name.c_str(), node->get_int(socket));
+ break;
+ case SocketType::STRING:
+ parameter(param_name.c_str(), node->get_string(socket));
+ break;
+ case SocketType::CLOSURE:
+ case SocketType::UNDEFINED:
+ default:
+ break;
+ }
+ }
+ }
+
+ /* Create shader of the appropriate type. OSL only distinguishes between "surface"
+ * and "displacement" at the moment. */
+ if (current_type == SHADER_TYPE_SURFACE)
+ ss->Shader("surface", name, id(node).c_str());
+ else if (current_type == SHADER_TYPE_VOLUME)
+ ss->Shader("surface", name, id(node).c_str());
+ else if (current_type == SHADER_TYPE_DISPLACEMENT)
+ ss->Shader("displacement", name, id(node).c_str());
+ else if (current_type == SHADER_TYPE_BUMP)
+ ss->Shader("displacement", name, id(node).c_str());
+ else
+ assert(0);
+
+ /* link inputs to other nodes */
+ foreach (ShaderInput *input, node->inputs) {
+ if (input->link) {
+ if (node_skip_input(node, input))
+ continue;
+
+ /* connect shaders */
+ string id_from = id(input->link->parent);
+ string id_to = id(node);
+ string param_from = compatible_name(input->link->parent, input->link);
+ string param_to = compatible_name(node, input);
+
+ ss->ConnectShaders(id_from.c_str(), param_from.c_str(), id_to.c_str(), param_to.c_str());
+ }
+ }
+
+ /* test if we shader contains specific closures */
+ OSLShaderInfo *info = manager->shader_loaded_info(name);
+
+ if (current_type == SHADER_TYPE_SURFACE) {
+ if (info) {
+ if (info->has_surface_emission)
+ current_shader->has_surface_emission = true;
+ if (info->has_surface_transparent)
+ current_shader->has_surface_transparent = true;
+ if (info->has_surface_bssrdf) {
+ current_shader->has_surface_bssrdf = true;
+ current_shader->has_bssrdf_bump = true; /* can't detect yet */
+ }
+ current_shader->has_bump = true; /* can't detect yet */
+ current_shader->has_surface_raytrace = true; /* can't detect yet */
+ }
+
+ if (node->has_spatial_varying()) {
+ current_shader->has_surface_spatial_varying = true;
+ }
+ }
+ else if (current_type == SHADER_TYPE_VOLUME) {
+ if (node->has_spatial_varying())
+ current_shader->has_volume_spatial_varying = true;
+ if (node->has_attribute_dependency())
+ current_shader->has_volume_attribute_dependency = true;
+ }
+
+ if (node->has_integrator_dependency()) {
+ current_shader->has_integrator_dependency = true;
+ }
+}
+
+static TypeDesc array_typedesc(TypeDesc typedesc, int arraylength)
+{
+ return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype,
+ (TypeDesc::AGGREGATE)typedesc.aggregate,
+ (TypeDesc::VECSEMANTICS)typedesc.vecsemantics,
+ arraylength);
+}
+
+void OSLCompiler::parameter(ShaderNode *node, const char *name)
+{
+ ustring uname = ustring(name);
+ const SocketType &socket = *(node->type->find_input(uname));
+
+ switch (socket.type) {
+ case SocketType::BOOLEAN: {
+ int value = node->get_bool(socket);
+ ss->Parameter(name, TypeDesc::TypeInt, &value);
+ break;
+ }
+ case SocketType::FLOAT: {
+ float value = node->get_float(socket);
+ ss->Parameter(uname, TypeDesc::TypeFloat, &value);
+ break;
+ }
+ case SocketType::INT: {
+ int value = node->get_int(socket);
+ ss->Parameter(uname, TypeDesc::TypeInt, &value);
+ break;
+ }
+ case SocketType::COLOR: {
+ float3 value = node->get_float3(socket);
+ ss->Parameter(uname, TypeDesc::TypeColor, &value);
+ break;
+ }
+ case SocketType::VECTOR: {
+ float3 value = node->get_float3(socket);
+ ss->Parameter(uname, TypeDesc::TypeVector, &value);
+ break;
+ }
+ case SocketType::POINT: {
+ float3 value = node->get_float3(socket);
+ ss->Parameter(uname, TypeDesc::TypePoint, &value);
+ break;
+ }
+ case SocketType::NORMAL: {
+ float3 value = node->get_float3(socket);
+ ss->Parameter(uname, TypeDesc::TypeNormal, &value);
+ break;
+ }
+ case SocketType::POINT2: {
+ float2 value = node->get_float2(socket);
+ ss->Parameter(uname, TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), &value);
+ break;
+ }
+ case SocketType::STRING: {
+ ustring value = node->get_string(socket);
+ ss->Parameter(uname, TypeDesc::TypeString, &value);
+ break;
+ }
+ case SocketType::ENUM: {
+ ustring value = node->get_string(socket);
+ ss->Parameter(uname, TypeDesc::TypeString, &value);
+ break;
+ }
+ case SocketType::TRANSFORM: {
+ Transform value = node->get_transform(socket);
+ ProjectionTransform projection(value);
+ projection = projection_transpose(projection);
+ ss->Parameter(uname, TypeDesc::TypeMatrix, &projection);
+ break;
+ }
+ case SocketType::BOOLEAN_ARRAY: {
+ // OSL does not support booleans, so convert to int
+ const array<bool> &value = node->get_bool_array(socket);
+ array<int> intvalue(value.size());
+ for (size_t i = 0; i < value.size(); i++)
+ intvalue[i] = value[i];
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), intvalue.data());
+ break;
+ }
+ case SocketType::FLOAT_ARRAY: {
+ const array<float> &value = node->get_float_array(socket);
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeFloat, value.size()), value.data());
+ break;
+ }
+ case SocketType::INT_ARRAY: {
+ const array<int> &value = node->get_int_array(socket);
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), value.data());
+ break;
+ }
+ case SocketType::COLOR_ARRAY:
+ case SocketType::VECTOR_ARRAY:
+ case SocketType::POINT_ARRAY:
+ case SocketType::NORMAL_ARRAY: {
+ TypeDesc typedesc;
+
+ switch (socket.type) {
+ case SocketType::COLOR_ARRAY:
+ typedesc = TypeDesc::TypeColor;
+ break;
+ case SocketType::VECTOR_ARRAY:
+ typedesc = TypeDesc::TypeVector;
+ break;
+ case SocketType::POINT_ARRAY:
+ typedesc = TypeDesc::TypePoint;
+ break;
+ case SocketType::NORMAL_ARRAY:
+ typedesc = TypeDesc::TypeNormal;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ // convert to tightly packed array since float3 has padding
+ const array<float3> &value = node->get_float3_array(socket);
+ array<float> fvalue(value.size() * 3);
+ for (size_t i = 0, j = 0; i < value.size(); i++) {
+ fvalue[j++] = value[i].x;
+ fvalue[j++] = value[i].y;
+ fvalue[j++] = value[i].z;
+ }
+
+ ss->Parameter(uname, array_typedesc(typedesc, value.size()), fvalue.data());
+ break;
+ }
+ case SocketType::POINT2_ARRAY: {
+ const array<float2> &value = node->get_float2_array(socket);
+ ss->Parameter(
+ uname,
+ array_typedesc(TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), value.size()),
+ value.data());
+ break;
+ }
+ case SocketType::STRING_ARRAY: {
+ const array<ustring> &value = node->get_string_array(socket);
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeString, value.size()), value.data());
+ break;
+ }
+ case SocketType::TRANSFORM_ARRAY: {
+ const array<Transform> &value = node->get_transform_array(socket);
+ array<ProjectionTransform> fvalue(value.size());
+ for (size_t i = 0; i < value.size(); i++) {
+ fvalue[i] = projection_transpose(ProjectionTransform(value[i]));
+ }
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, fvalue.size()), fvalue.data());
+ break;
+ }
+ case SocketType::CLOSURE:
+ case SocketType::NODE:
+ case SocketType::NODE_ARRAY:
+ case SocketType::UNDEFINED:
+ case SocketType::UINT: {
+ assert(0);
+ break;
+ }
+ }
+}
+
+void OSLCompiler::parameter(const char *name, float f)
+{
+ ss->Parameter(name, TypeDesc::TypeFloat, &f);
+}
+
+void OSLCompiler::parameter_color(const char *name, float3 f)
+{
+ ss->Parameter(name, TypeDesc::TypeColor, &f);
+}
+
+void OSLCompiler::parameter_point(const char *name, float3 f)
+{
+ ss->Parameter(name, TypeDesc::TypePoint, &f);
+}
+
+void OSLCompiler::parameter_normal(const char *name, float3 f)
+{
+ ss->Parameter(name, TypeDesc::TypeNormal, &f);
+}
+
+void OSLCompiler::parameter_vector(const char *name, float3 f)
+{
+ ss->Parameter(name, TypeDesc::TypeVector, &f);
+}
+
+void OSLCompiler::parameter(const char *name, int f)
+{
+ ss->Parameter(name, TypeDesc::TypeInt, &f);
+}
+
+void OSLCompiler::parameter(const char *name, const char *s)
+{
+ ss->Parameter(name, TypeDesc::TypeString, &s);
+}
+
+void OSLCompiler::parameter(const char *name, ustring s)
+{
+ const char *str = s.c_str();
+ ss->Parameter(name, TypeDesc::TypeString, &str);
+}
+
+void OSLCompiler::parameter(const char *name, const Transform &tfm)
+{
+ ProjectionTransform projection(tfm);
+ projection = projection_transpose(projection);
+ ss->Parameter(name, TypeDesc::TypeMatrix, (float *)&projection);
+}
+
+void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
+{
+ TypeDesc type = TypeDesc::TypeFloat;
+ type.arraylen = arraylen;
+ ss->Parameter(name, type, f);
+}
+
+void OSLCompiler::parameter_color_array(const char *name, const array<float3> &f)
+{
+ /* NOTE: cycles float3 type is actually 4 floats! need to use an explicit array. */
+ array<float[3]> table(f.size());
+
+ for (int i = 0; i < f.size(); ++i) {
+ table[i][0] = f[i].x;
+ table[i][1] = f[i].y;
+ table[i][2] = f[i].z;
+ }
+
+ TypeDesc type = TypeDesc::TypeColor;
+ type.arraylen = table.size();
+ ss->Parameter(name, type, table.data());
+}
+
+void OSLCompiler::parameter_attribute(const char *name, ustring s)
+{
+ if (Attribute::name_standard(s.c_str()))
+ parameter(name, (string("geom:") + s.c_str()).c_str());
+ else
+ parameter(name, s.c_str());
+}
+
+void OSLCompiler::find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input)
+{
+ ShaderNode *node = (input->link) ? input->link->parent : NULL;
+
+ if (node != NULL && dependencies.find(node) == dependencies.end()) {
+ foreach (ShaderInput *in, node->inputs)
+ if (!node_skip_input(node, in))
+ find_dependencies(dependencies, in);
+
+ dependencies.insert(node);
+ }
+}
+
+void OSLCompiler::generate_nodes(const ShaderNodeSet &nodes)
+{
+ ShaderNodeSet done;
+ bool nodes_done;
+
+ do {
+ nodes_done = true;
+
+ foreach (ShaderNode *node, nodes) {
+ if (done.find(node) == done.end()) {
+ bool inputs_done = true;
+
+ foreach (ShaderInput *input, node->inputs)
+ if (!node_skip_input(node, input))
+ if (input->link && done.find(input->link->parent) == done.end())
+ inputs_done = false;
+
+ if (inputs_done) {
+ node->compile(*this);
+ done.insert(node);
+
+ if (current_type == SHADER_TYPE_SURFACE) {
+ if (node->has_surface_emission())
+ current_shader->has_surface_emission = true;
+ if (node->has_surface_transparent())
+ current_shader->has_surface_transparent = true;
+ if (node->get_feature() & KERNEL_FEATURE_NODE_RAYTRACE)
+ current_shader->has_surface_raytrace = true;
+ if (node->has_spatial_varying())
+ current_shader->has_surface_spatial_varying = true;
+ if (node->has_surface_bssrdf()) {
+ current_shader->has_surface_bssrdf = true;
+ if (node->has_bssrdf_bump())
+ current_shader->has_bssrdf_bump = true;
+ }
+ if (node->has_bump()) {
+ current_shader->has_bump = true;
+ }
+ }
+ else if (current_type == SHADER_TYPE_VOLUME) {
+ if (node->has_spatial_varying())
+ current_shader->has_volume_spatial_varying = true;
+ }
+ }
+ else
+ nodes_done = false;
+ }
+ }
+ } while (!nodes_done);
+}
+
+OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
+{
+ current_type = type;
+
+ OSL::ShaderGroupRef group = ss->ShaderGroupBegin(shader->name.c_str());
+
+ ShaderNode *output = graph->output();
+ ShaderNodeSet dependencies;
+
+ if (type == SHADER_TYPE_SURFACE) {
+ /* generate surface shader */
+ find_dependencies(dependencies, output->input("Surface"));
+ generate_nodes(dependencies);
+ output->compile(*this);
+ }
+ else if (type == SHADER_TYPE_BUMP) {
+ /* generate bump shader */
+ find_dependencies(dependencies, output->input("Normal"));
+ generate_nodes(dependencies);
+ output->compile(*this);
+ }
+ else if (type == SHADER_TYPE_VOLUME) {
+ /* generate volume shader */
+ find_dependencies(dependencies, output->input("Volume"));
+ generate_nodes(dependencies);
+ output->compile(*this);
+ }
+ else if (type == SHADER_TYPE_DISPLACEMENT) {
+ /* generate displacement shader */
+ find_dependencies(dependencies, output->input("Displacement"));
+ generate_nodes(dependencies);
+ output->compile(*this);
+ }
+ else
+ assert(0);
+
+ ss->ShaderGroupEnd();
+
+ return group;
+}
+
+void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
+{
+ if (shader->is_modified()) {
+ ShaderGraph *graph = shader->graph;
+ ShaderNode *output = (graph) ? graph->output() : NULL;
+
+ bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) &&
+ output->input("Surface")->link && output->input("Displacement")->link;
+
+ /* finalize */
+ shader->graph->finalize(scene,
+ has_bump,
+ shader->has_integrator_dependency,
+ shader->get_displacement_method() == DISPLACE_BOTH);
+
+ current_shader = shader;
+
+ shader->has_surface = false;
+ shader->has_surface_emission = false;
+ shader->has_surface_transparent = false;
+ shader->has_surface_bssrdf = false;
+ shader->has_bump = has_bump;
+ shader->has_bssrdf_bump = has_bump;
+ shader->has_volume = false;
+ shader->has_displacement = false;
+ shader->has_surface_spatial_varying = false;
+ shader->has_volume_spatial_varying = false;
+ shader->has_volume_attribute_dependency = false;
+ shader->has_integrator_dependency = false;
+
+ /* generate surface shader */
+ if (shader->reference_count() && graph && output->input("Surface")->link) {
+ shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
+
+ if (has_bump)
+ shader->osl_surface_bump_ref = compile_type(shader, shader->graph, SHADER_TYPE_BUMP);
+ else
+ shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
+
+ shader->has_surface = true;
+ }
+ else {
+ shader->osl_surface_ref = OSL::ShaderGroupRef();
+ shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
+ }
+
+ /* generate volume shader */
+ if (shader->reference_count() && graph && output->input("Volume")->link) {
+ shader->osl_volume_ref = compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
+ shader->has_volume = true;
+ }
+ else
+ shader->osl_volume_ref = OSL::ShaderGroupRef();
+
+ /* generate displacement shader */
+ if (shader->reference_count() && graph && output->input("Displacement")->link) {
+ shader->osl_displacement_ref = compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
+ shader->has_displacement = true;
+ }
+ else
+ shader->osl_displacement_ref = OSL::ShaderGroupRef();
+ }
+
+ /* push state to array for lookup */
+ og->surface_state.push_back(shader->osl_surface_ref);
+ og->volume_state.push_back(shader->osl_volume_ref);
+ og->displacement_state.push_back(shader->osl_displacement_ref);
+ og->bump_state.push_back(shader->osl_surface_bump_ref);
+}
+
+void OSLCompiler::parameter_texture(const char *name, ustring filename, ustring colorspace)
+{
+ /* Textured loaded through the OpenImageIO texture cache. For this
+ * case we need to do runtime color space conversion. */
+ OSLTextureHandle *handle = new OSLTextureHandle(OSLTextureHandle::OIIO);
+ handle->processor = ColorSpaceManager::get_processor(colorspace);
+ services->textures.insert(filename, handle);
+ parameter(name, filename);
+}
+
+void OSLCompiler::parameter_texture(const char *name, int svm_slot)
+{
+ /* Texture loaded through SVM image texture system. We generate a unique
+ * name, which ends up being used in OSLRenderServices::get_texture_handle
+ * to get handle again. Note that this name must be unique between multiple
+ * render sessions as the render services are shared. */
+ ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
+ services->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::SVM, svm_slot));
+ parameter(name, filename);
+}
+
+void OSLCompiler::parameter_texture_ies(const char *name, int svm_slot)
+{
+ /* IES light textures stored in SVM. */
+ ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
+ services->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::IES, svm_slot));
+ parameter(name, filename);
+}
+
+#else
+
+void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfilepath*/)
+{
+}
+
+void OSLCompiler::parameter(ShaderNode * /*node*/, const char * /*name*/)
+{
+}
+
+void OSLCompiler::parameter(const char * /*name*/, float /*f*/)
+{
+}
+
+void OSLCompiler::parameter_color(const char * /*name*/, float3 /*f*/)
+{
+}
+
+void OSLCompiler::parameter_vector(const char * /*name*/, float3 /*f*/)
+{
+}
+
+void OSLCompiler::parameter_point(const char * /*name*/, float3 /*f*/)
+{
+}
+
+void OSLCompiler::parameter_normal(const char * /*name*/, float3 /*f*/)
+{
+}
+
+void OSLCompiler::parameter(const char * /*name*/, int /*f*/)
+{
+}
+
+void OSLCompiler::parameter(const char * /*name*/, const char * /*s*/)
+{
+}
+
+void OSLCompiler::parameter(const char * /*name*/, ustring /*s*/)
+{
+}
+
+void OSLCompiler::parameter(const char * /*name*/, const Transform & /*tfm*/)
+{
+}
+
+void OSLCompiler::parameter_array(const char * /*name*/, const float /*f*/[], int /*arraylen*/)
+{
+}
+
+void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float3> & /*f*/)
+{
+}
+
+void OSLCompiler::parameter_texture(const char * /* name */,
+ ustring /* filename */,
+ ustring /* colorspace */)
+{
+}
+
+void OSLCompiler::parameter_texture(const char * /* name */, int /* svm_slot */)
+{
+}
+
+void OSLCompiler::parameter_texture_ies(const char * /* name */, int /* svm_slot */)
+{
+}
+
+#endif /* WITH_OSL */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/osl.h b/intern/cycles/scene/osl.h
new file mode 100644
index 00000000000..d54040e1047
--- /dev/null
+++ b/intern/cycles/scene/osl.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __OSL_H__
+#define __OSL_H__
+
+#include "util/array.h"
+#include "util/set.h"
+#include "util/string.h"
+#include "util/thread.h"
+
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+
+#ifdef WITH_OSL
+# include <OSL/llvm_util.h>
+# include <OSL/oslcomp.h>
+# include <OSL/oslexec.h>
+# include <OSL/oslquery.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class ImageManager;
+class OSLRenderServices;
+struct OSLGlobals;
+class Scene;
+class ShaderGraph;
+class ShaderNode;
+class ShaderInput;
+class ShaderOutput;
+
+#ifdef WITH_OSL
+
+/* OSL Shader Info
+ * to auto detect closures in the shader for MIS and transparent shadows */
+
+struct OSLShaderInfo {
+ OSLShaderInfo()
+ : has_surface_emission(false), has_surface_transparent(false), has_surface_bssrdf(false)
+ {
+ }
+
+ OSL::OSLQuery query;
+ bool has_surface_emission;
+ bool has_surface_transparent;
+ bool has_surface_bssrdf;
+};
+
+/* Shader Manage */
+
+class OSLShaderManager : public ShaderManager {
+ public:
+ OSLShaderManager();
+ ~OSLShaderManager();
+
+ static void free_memory();
+
+ void reset(Scene *scene) override;
+
+ bool use_osl() override
+ {
+ return true;
+ }
+
+ void device_update_specific(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress) override;
+ void device_free(Device *device, DeviceScene *dscene, Scene *scene) override;
+
+ /* osl compile and query */
+ static bool osl_compile(const string &inputfile, const string &outputfile);
+ static bool osl_query(OSL::OSLQuery &query, const string &filepath);
+
+ /* shader file loading, all functions return pointer to hash string if found */
+ const char *shader_test_loaded(const string &hash);
+ const char *shader_load_bytecode(const string &hash, const string &bytecode);
+ const char *shader_load_filepath(string filepath);
+ OSLShaderInfo *shader_loaded_info(const string &hash);
+
+ /* create OSL node using OSLQuery */
+ static OSLNode *osl_node(ShaderGraph *graph,
+ ShaderManager *manager,
+ const std::string &filepath,
+ const std::string &bytecode_hash = "",
+ const std::string &bytecode = "");
+
+ protected:
+ void texture_system_init();
+ void texture_system_free();
+
+ void shading_system_init();
+ void shading_system_free();
+
+ OSL::ShadingSystem *ss;
+ OSL::TextureSystem *ts;
+ OSLRenderServices *services;
+ OSL::ErrorHandler errhandler;
+ map<string, OSLShaderInfo> loaded_shaders;
+
+ static OSL::TextureSystem *ts_shared;
+ static thread_mutex ts_shared_mutex;
+ static int ts_shared_users;
+
+ static OSL::ShadingSystem *ss_shared;
+ static OSLRenderServices *services_shared;
+ static thread_mutex ss_shared_mutex;
+ static thread_mutex ss_mutex;
+ static int ss_shared_users;
+};
+
+#endif
+
+/* Graph Compiler */
+
+class OSLCompiler {
+ public:
+#ifdef WITH_OSL
+ OSLCompiler(OSLShaderManager *manager,
+ OSLRenderServices *services,
+ OSL::ShadingSystem *shadingsys,
+ Scene *scene);
+#endif
+ void compile(OSLGlobals *og, Shader *shader);
+
+ void add(ShaderNode *node, const char *name, bool isfilepath = false);
+
+ void parameter(ShaderNode *node, const char *name);
+
+ void parameter(const char *name, float f);
+ void parameter_color(const char *name, float3 f);
+ void parameter_vector(const char *name, float3 f);
+ void parameter_normal(const char *name, float3 f);
+ void parameter_point(const char *name, float3 f);
+ void parameter(const char *name, int f);
+ void parameter(const char *name, const char *s);
+ void parameter(const char *name, ustring str);
+ void parameter(const char *name, const Transform &tfm);
+
+ void parameter_array(const char *name, const float f[], int arraylen);
+ void parameter_color_array(const char *name, const array<float3> &f);
+
+ void parameter_attribute(const char *name, ustring s);
+
+ void parameter_texture(const char *name, ustring filename, ustring colorspace);
+ void parameter_texture(const char *name, int svm_slot);
+ void parameter_texture_ies(const char *name, int svm_slot);
+
+ ShaderType output_type()
+ {
+ return current_type;
+ }
+
+ bool background;
+ Scene *scene;
+
+ private:
+#ifdef WITH_OSL
+ string id(ShaderNode *node);
+ OSL::ShaderGroupRef compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
+ bool node_skip_input(ShaderNode *node, ShaderInput *input);
+ string compatible_name(ShaderNode *node, ShaderInput *input);
+ string compatible_name(ShaderNode *node, ShaderOutput *output);
+
+ void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input);
+ void generate_nodes(const ShaderNodeSet &nodes);
+
+ OSLShaderManager *manager;
+ OSLRenderServices *services;
+ OSL::ShadingSystem *ss;
+#endif
+
+ ShaderType current_type;
+ Shader *current_shader;
+
+ static int texture_shared_unique_id;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __OSL_H__ */
diff --git a/intern/cycles/scene/particles.cpp b/intern/cycles/scene/particles.cpp
new file mode 100644
index 00000000000..92381171082
--- /dev/null
+++ b/intern/cycles/scene/particles.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/particles.h"
+#include "device/device.h"
+#include "scene/scene.h"
+#include "scene/stats.h"
+
+#include "util/foreach.h"
+#include "util/hash.h"
+#include "util/log.h"
+#include "util/map.h"
+#include "util/progress.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Particle System */
+
+NODE_DEFINE(ParticleSystem)
+{
+ NodeType *type = NodeType::add("particle_system", create);
+ return type;
+}
+
+ParticleSystem::ParticleSystem() : Node(get_node_type())
+{
+}
+
+ParticleSystem::~ParticleSystem()
+{
+}
+
+void ParticleSystem::tag_update(Scene *scene)
+{
+ scene->particle_system_manager->tag_update(scene);
+}
+
+/* Particle System Manager */
+
+ParticleSystemManager::ParticleSystemManager()
+{
+ need_update_ = true;
+}
+
+ParticleSystemManager::~ParticleSystemManager()
+{
+}
+
+void ParticleSystemManager::device_update_particles(Device *,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ /* count particles.
+ * adds one dummy particle at the beginning to avoid invalid lookups,
+ * in case a shader uses particle info without actual particle data. */
+ int num_particles = 1;
+ for (size_t j = 0; j < scene->particle_systems.size(); j++)
+ num_particles += scene->particle_systems[j]->particles.size();
+
+ KernelParticle *kparticles = dscene->particles.alloc(num_particles);
+
+ /* dummy particle */
+ memset(kparticles, 0, sizeof(KernelParticle));
+
+ int i = 1;
+ for (size_t j = 0; j < scene->particle_systems.size(); j++) {
+ ParticleSystem *psys = scene->particle_systems[j];
+
+ for (size_t k = 0; k < psys->particles.size(); k++) {
+ /* pack in texture */
+ Particle &pa = psys->particles[k];
+
+ kparticles[i].index = pa.index;
+ kparticles[i].age = pa.age;
+ kparticles[i].lifetime = pa.lifetime;
+ kparticles[i].size = pa.size;
+ kparticles[i].rotation = pa.rotation;
+ kparticles[i].location = float3_to_float4(pa.location);
+ kparticles[i].velocity = float3_to_float4(pa.velocity);
+ kparticles[i].angular_velocity = float3_to_float4(pa.angular_velocity);
+
+ i++;
+
+ if (progress.get_cancel())
+ return;
+ }
+ }
+
+ dscene->particles.copy_to_device();
+}
+
+void ParticleSystemManager::device_update(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ if (!need_update())
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->particles.times.add_entry({"device_update", time});
+ }
+ });
+
+ VLOG(1) << "Total " << scene->particle_systems.size() << " particle systems.";
+
+ device_free(device, dscene);
+
+ progress.set_status("Updating Particle Systems", "Copying Particles to device");
+ device_update_particles(device, dscene, scene, progress);
+
+ if (progress.get_cancel())
+ return;
+
+ need_update_ = false;
+}
+
+void ParticleSystemManager::device_free(Device *, DeviceScene *dscene)
+{
+ dscene->particles.free();
+}
+
+void ParticleSystemManager::tag_update(Scene * /*scene*/)
+{
+ need_update_ = true;
+}
+
+bool ParticleSystemManager::need_update() const
+{
+ return need_update_;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/particles.h b/intern/cycles/scene/particles.h
new file mode 100644
index 00000000000..b958d12e4e3
--- /dev/null
+++ b/intern/cycles/scene/particles.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __PARTICLES_H__
+#define __PARTICLES_H__
+
+#include "util/array.h"
+#include "util/types.h"
+
+#include "graph/node.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Progress;
+class Scene;
+
+/* Particle System */
+
+struct Particle {
+ int index;
+ float age;
+ float lifetime;
+ float3 location;
+ float4 rotation;
+ float size;
+ float3 velocity;
+ float3 angular_velocity;
+};
+
+class ParticleSystem : public Node {
+ public:
+ NODE_DECLARE
+
+ ParticleSystem();
+ ~ParticleSystem();
+
+ void tag_update(Scene *scene);
+
+ array<Particle> particles;
+};
+
+/* ParticleSystem Manager */
+
+class ParticleSystemManager {
+ bool need_update_;
+
+ public:
+ ParticleSystemManager();
+ ~ParticleSystemManager();
+
+ void device_update_particles(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress);
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
+ void device_free(Device *device, DeviceScene *dscene);
+
+ void tag_update(Scene *scene);
+
+ bool need_update() const;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __PARTICLES_H__ */
diff --git a/intern/cycles/scene/pass.cpp b/intern/cycles/scene/pass.cpp
new file mode 100644
index 00000000000..a885ede50a4
--- /dev/null
+++ b/intern/cycles/scene/pass.cpp
@@ -0,0 +1,427 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/pass.h"
+
+#include "util/algorithm.h"
+#include "util/log.h"
+
+CCL_NAMESPACE_BEGIN
+
+const char *pass_type_as_string(const PassType type)
+{
+ const int type_int = static_cast<int>(type);
+
+ const NodeEnum *type_enum = Pass::get_type_enum();
+
+ if (!type_enum->exists(type_int)) {
+ LOG(DFATAL) << "Unhandled pass type " << static_cast<int>(type) << ", not supposed to happen.";
+ return "UNKNOWN";
+ }
+
+ return (*type_enum)[type_int].c_str();
+}
+
+const char *pass_mode_as_string(PassMode mode)
+{
+ switch (mode) {
+ case PassMode::NOISY:
+ return "NOISY";
+ case PassMode::DENOISED:
+ return "DENOISED";
+ }
+
+ LOG(DFATAL) << "Unhandled pass mode " << static_cast<int>(mode) << ", should never happen.";
+ return "UNKNOWN";
+}
+
+std::ostream &operator<<(std::ostream &os, PassMode mode)
+{
+ os << pass_mode_as_string(mode);
+ return os;
+}
+
+const NodeEnum *Pass::get_type_enum()
+{
+ static NodeEnum pass_type_enum;
+
+ if (pass_type_enum.empty()) {
+
+ /* Light Passes. */
+ pass_type_enum.insert("combined", PASS_COMBINED);
+ pass_type_enum.insert("emission", PASS_EMISSION);
+ pass_type_enum.insert("background", PASS_BACKGROUND);
+ pass_type_enum.insert("ao", PASS_AO);
+ pass_type_enum.insert("shadow", PASS_SHADOW);
+ pass_type_enum.insert("diffuse", PASS_DIFFUSE);
+ pass_type_enum.insert("diffuse_direct", PASS_DIFFUSE_DIRECT);
+ pass_type_enum.insert("diffuse_indirect", PASS_DIFFUSE_INDIRECT);
+ pass_type_enum.insert("glossy", PASS_GLOSSY);
+ pass_type_enum.insert("glossy_direct", PASS_GLOSSY_DIRECT);
+ pass_type_enum.insert("glossy_indirect", PASS_GLOSSY_INDIRECT);
+ pass_type_enum.insert("transmission", PASS_TRANSMISSION);
+ pass_type_enum.insert("transmission_direct", PASS_TRANSMISSION_DIRECT);
+ pass_type_enum.insert("transmission_indirect", PASS_TRANSMISSION_INDIRECT);
+ pass_type_enum.insert("volume", PASS_VOLUME);
+ pass_type_enum.insert("volume_direct", PASS_VOLUME_DIRECT);
+ pass_type_enum.insert("volume_indirect", PASS_VOLUME_INDIRECT);
+
+ /* Data passes. */
+ pass_type_enum.insert("depth", PASS_DEPTH);
+ pass_type_enum.insert("position", PASS_POSITION);
+ pass_type_enum.insert("normal", PASS_NORMAL);
+ pass_type_enum.insert("roughness", PASS_ROUGHNESS);
+ pass_type_enum.insert("uv", PASS_UV);
+ pass_type_enum.insert("object_id", PASS_OBJECT_ID);
+ pass_type_enum.insert("material_id", PASS_MATERIAL_ID);
+ pass_type_enum.insert("motion", PASS_MOTION);
+ pass_type_enum.insert("motion_weight", PASS_MOTION_WEIGHT);
+ pass_type_enum.insert("cryptomatte", PASS_CRYPTOMATTE);
+ pass_type_enum.insert("aov_color", PASS_AOV_COLOR);
+ pass_type_enum.insert("aov_value", PASS_AOV_VALUE);
+ pass_type_enum.insert("adaptive_aux_buffer", PASS_ADAPTIVE_AUX_BUFFER);
+ pass_type_enum.insert("sample_count", PASS_SAMPLE_COUNT);
+ pass_type_enum.insert("diffuse_color", PASS_DIFFUSE_COLOR);
+ pass_type_enum.insert("glossy_color", PASS_GLOSSY_COLOR);
+ pass_type_enum.insert("transmission_color", PASS_TRANSMISSION_COLOR);
+ pass_type_enum.insert("mist", PASS_MIST);
+ pass_type_enum.insert("denoising_normal", PASS_DENOISING_NORMAL);
+ pass_type_enum.insert("denoising_albedo", PASS_DENOISING_ALBEDO);
+ pass_type_enum.insert("denoising_depth", PASS_DENOISING_DEPTH);
+
+ pass_type_enum.insert("shadow_catcher", PASS_SHADOW_CATCHER);
+ pass_type_enum.insert("shadow_catcher_sample_count", PASS_SHADOW_CATCHER_SAMPLE_COUNT);
+ pass_type_enum.insert("shadow_catcher_matte", PASS_SHADOW_CATCHER_MATTE);
+
+ pass_type_enum.insert("bake_primitive", PASS_BAKE_PRIMITIVE);
+ pass_type_enum.insert("bake_differential", PASS_BAKE_DIFFERENTIAL);
+ }
+
+ return &pass_type_enum;
+}
+
+const NodeEnum *Pass::get_mode_enum()
+{
+ static NodeEnum pass_mode_enum;
+
+ if (pass_mode_enum.empty()) {
+ pass_mode_enum.insert("noisy", static_cast<int>(PassMode::NOISY));
+ pass_mode_enum.insert("denoised", static_cast<int>(PassMode::DENOISED));
+ }
+
+ return &pass_mode_enum;
+}
+
+NODE_DEFINE(Pass)
+{
+ NodeType *type = NodeType::add("pass", create);
+
+ const NodeEnum *pass_type_enum = get_type_enum();
+ const NodeEnum *pass_mode_enum = get_mode_enum();
+
+ SOCKET_ENUM(type, "Type", *pass_type_enum, PASS_COMBINED);
+ SOCKET_ENUM(mode, "Mode", *pass_mode_enum, static_cast<int>(PassMode::DENOISED));
+ SOCKET_STRING(name, "Name", ustring());
+ SOCKET_BOOLEAN(include_albedo, "Include Albedo", false);
+
+ return type;
+}
+
+Pass::Pass() : Node(get_node_type()), is_auto_(false)
+{
+}
+
+PassInfo Pass::get_info() const
+{
+ return get_info(type, include_albedo);
+}
+
+bool Pass::is_written() const
+{
+ return get_info().is_written;
+}
+
+PassInfo Pass::get_info(const PassType type, const bool include_albedo)
+{
+ PassInfo pass_info;
+
+ pass_info.use_filter = true;
+ pass_info.use_exposure = false;
+ pass_info.divide_type = PASS_NONE;
+ pass_info.use_compositing = false;
+ pass_info.use_denoising_albedo = true;
+
+ switch (type) {
+ case PASS_NONE:
+ pass_info.num_components = 0;
+ break;
+ case PASS_COMBINED:
+ pass_info.num_components = 4;
+ pass_info.use_exposure = true;
+ pass_info.support_denoise = true;
+ break;
+ case PASS_DEPTH:
+ pass_info.num_components = 1;
+ pass_info.use_filter = false;
+ break;
+ case PASS_MIST:
+ pass_info.num_components = 1;
+ break;
+ case PASS_POSITION:
+ pass_info.num_components = 3;
+ pass_info.use_filter = false;
+ break;
+ case PASS_NORMAL:
+ pass_info.num_components = 3;
+ break;
+ case PASS_ROUGHNESS:
+ pass_info.num_components = 1;
+ break;
+ case PASS_UV:
+ pass_info.num_components = 3;
+ break;
+ case PASS_MOTION:
+ pass_info.num_components = 4;
+ pass_info.divide_type = PASS_MOTION_WEIGHT;
+ break;
+ case PASS_MOTION_WEIGHT:
+ pass_info.num_components = 1;
+ break;
+ case PASS_OBJECT_ID:
+ case PASS_MATERIAL_ID:
+ pass_info.num_components = 1;
+ pass_info.use_filter = false;
+ break;
+
+ case PASS_EMISSION:
+ case PASS_BACKGROUND:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ break;
+ case PASS_AO:
+ pass_info.num_components = 3;
+ break;
+ case PASS_SHADOW:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = false;
+ break;
+
+ case PASS_DIFFUSE_COLOR:
+ case PASS_GLOSSY_COLOR:
+ case PASS_TRANSMISSION_COLOR:
+ pass_info.num_components = 3;
+ break;
+ case PASS_DIFFUSE:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ pass_info.direct_type = PASS_DIFFUSE_DIRECT;
+ pass_info.indirect_type = PASS_DIFFUSE_INDIRECT;
+ pass_info.divide_type = (!include_albedo) ? PASS_DIFFUSE_COLOR : PASS_NONE;
+ pass_info.use_compositing = true;
+ pass_info.is_written = false;
+ break;
+ case PASS_DIFFUSE_DIRECT:
+ case PASS_DIFFUSE_INDIRECT:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ pass_info.divide_type = (!include_albedo) ? PASS_DIFFUSE_COLOR : PASS_NONE;
+ pass_info.use_compositing = true;
+ break;
+ case PASS_GLOSSY:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ pass_info.direct_type = PASS_GLOSSY_DIRECT;
+ pass_info.indirect_type = PASS_GLOSSY_INDIRECT;
+ pass_info.divide_type = (!include_albedo) ? PASS_GLOSSY_COLOR : PASS_NONE;
+ pass_info.use_compositing = true;
+ pass_info.is_written = false;
+ break;
+ case PASS_GLOSSY_DIRECT:
+ case PASS_GLOSSY_INDIRECT:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ pass_info.divide_type = (!include_albedo) ? PASS_GLOSSY_COLOR : PASS_NONE;
+ pass_info.use_compositing = true;
+ break;
+ case PASS_TRANSMISSION:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ pass_info.direct_type = PASS_TRANSMISSION_DIRECT;
+ pass_info.indirect_type = PASS_TRANSMISSION_INDIRECT;
+ pass_info.divide_type = (!include_albedo) ? PASS_TRANSMISSION_COLOR : PASS_NONE;
+ pass_info.use_compositing = true;
+ pass_info.is_written = false;
+ break;
+ case PASS_TRANSMISSION_DIRECT:
+ case PASS_TRANSMISSION_INDIRECT:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ pass_info.divide_type = (!include_albedo) ? PASS_TRANSMISSION_COLOR : PASS_NONE;
+ pass_info.use_compositing = true;
+ break;
+ case PASS_VOLUME:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ pass_info.direct_type = PASS_VOLUME_DIRECT;
+ pass_info.indirect_type = PASS_VOLUME_INDIRECT;
+ pass_info.use_compositing = true;
+ pass_info.is_written = false;
+ break;
+ case PASS_VOLUME_DIRECT:
+ case PASS_VOLUME_INDIRECT:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ break;
+
+ case PASS_CRYPTOMATTE:
+ pass_info.num_components = 4;
+ break;
+
+ case PASS_DENOISING_NORMAL:
+ pass_info.num_components = 3;
+ break;
+ case PASS_DENOISING_ALBEDO:
+ pass_info.num_components = 3;
+ break;
+ case PASS_DENOISING_DEPTH:
+ pass_info.num_components = 1;
+ break;
+
+ case PASS_SHADOW_CATCHER:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ pass_info.use_compositing = true;
+ pass_info.use_denoising_albedo = false;
+ pass_info.support_denoise = true;
+ break;
+ case PASS_SHADOW_CATCHER_SAMPLE_COUNT:
+ pass_info.num_components = 1;
+ break;
+ case PASS_SHADOW_CATCHER_MATTE:
+ pass_info.num_components = 4;
+ pass_info.use_exposure = true;
+ pass_info.support_denoise = true;
+ /* Without shadow catcher approximation compositing is not needed.
+ * Since we don't know here whether approximation is used or not, leave the decision up to
+ * the caller which will know that. */
+ break;
+
+ case PASS_ADAPTIVE_AUX_BUFFER:
+ pass_info.num_components = 4;
+ break;
+ case PASS_SAMPLE_COUNT:
+ pass_info.num_components = 1;
+ pass_info.use_exposure = false;
+ break;
+
+ case PASS_AOV_COLOR:
+ pass_info.num_components = 3;
+ break;
+ case PASS_AOV_VALUE:
+ pass_info.num_components = 1;
+ break;
+
+ case PASS_BAKE_PRIMITIVE:
+ case PASS_BAKE_DIFFERENTIAL:
+ pass_info.num_components = 4;
+ pass_info.use_exposure = false;
+ pass_info.use_filter = false;
+ break;
+
+ case PASS_CATEGORY_LIGHT_END:
+ case PASS_CATEGORY_DATA_END:
+ case PASS_CATEGORY_BAKE_END:
+ case PASS_NUM:
+ LOG(DFATAL) << "Unexpected pass type is used " << type;
+ pass_info.num_components = 0;
+ break;
+ }
+
+ return pass_info;
+}
+
+bool Pass::contains(const vector<Pass *> &passes, PassType type)
+{
+ for (const Pass *pass : passes) {
+ if (pass->get_type() != type) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+const Pass *Pass::find(const vector<Pass *> &passes, const string &name)
+{
+ for (const Pass *pass : passes) {
+ if (pass->get_name() == name) {
+ return pass;
+ }
+ }
+
+ return nullptr;
+}
+
+const Pass *Pass::find(const vector<Pass *> &passes, PassType type, PassMode mode)
+{
+ for (const Pass *pass : passes) {
+ if (pass->get_type() != type || pass->get_mode() != mode) {
+ continue;
+ }
+
+ return pass;
+ }
+
+ return nullptr;
+}
+
+int Pass::get_offset(const vector<Pass *> &passes, const Pass *pass)
+{
+ int pass_offset = 0;
+
+ for (const Pass *current_pass : passes) {
+ /* Note that pass name is allowed to be empty. This is why we check for type and mode. */
+ if (current_pass->get_type() == pass->get_type() &&
+ current_pass->get_mode() == pass->get_mode() &&
+ current_pass->get_name() == pass->get_name()) {
+ if (current_pass->is_written()) {
+ return pass_offset;
+ }
+ else {
+ return PASS_UNUSED;
+ }
+ }
+ if (current_pass->is_written()) {
+ pass_offset += current_pass->get_info().num_components;
+ }
+ }
+
+ return PASS_UNUSED;
+}
+
+std::ostream &operator<<(std::ostream &os, const Pass &pass)
+{
+ os << "type: " << pass_type_as_string(pass.get_type());
+ os << ", name: \"" << pass.get_name() << "\"";
+ os << ", mode: " << pass.get_mode();
+ os << ", is_written: " << string_from_bool(pass.is_written());
+
+ return os;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/pass.h b/intern/cycles/scene/pass.h
new file mode 100644
index 00000000000..7da07cfa562
--- /dev/null
+++ b/intern/cycles/scene/pass.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2011-2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ostream> // NOLINT
+
+#include "util/string.h"
+#include "util/vector.h"
+
+#include "kernel/types.h"
+
+#include "graph/node.h"
+
+CCL_NAMESPACE_BEGIN
+
+const char *pass_type_as_string(const PassType type);
+
+enum class PassMode {
+ NOISY,
+ DENOISED,
+};
+const char *pass_mode_as_string(PassMode mode);
+std::ostream &operator<<(std::ostream &os, PassMode mode);
+
+struct PassInfo {
+ int num_components = -1;
+ bool use_filter = false;
+ bool use_exposure = false;
+ bool is_written = true;
+ PassType divide_type = PASS_NONE;
+ PassType direct_type = PASS_NONE;
+ PassType indirect_type = PASS_NONE;
+
+ /* Pass access for read can not happen directly and needs some sort of compositing (for example,
+ * light passes due to divide_type, or shadow catcher pass. */
+ bool use_compositing = false;
+
+ /* Used to disable albedo pass for denoising.
+ * Light and shadow catcher passes should not have discontinuity in the denoised result based on
+ * the underlying albedo. */
+ bool use_denoising_albedo = true;
+
+ /* Pass supports denoising. */
+ bool support_denoise = false;
+};
+
+class Pass : public Node {
+ public:
+ NODE_DECLARE
+
+ NODE_SOCKET_API(PassType, type)
+ NODE_SOCKET_API(PassMode, mode)
+ NODE_SOCKET_API(ustring, name)
+ NODE_SOCKET_API(bool, include_albedo)
+
+ Pass();
+
+ PassInfo get_info() const;
+
+ /* The pass is written by the render pipeline (kernel or denoiser). If the pass is written it
+ * will have pixels allocated in a RenderBuffer. Passes which are not written do not have their
+ * pixels allocated to save memory. */
+ bool is_written() const;
+
+ protected:
+ /* The has been created automatically as a requirement to various rendering functionality (such
+ * as adaptive sampling). */
+ bool is_auto_;
+
+ public:
+ static const NodeEnum *get_type_enum();
+ static const NodeEnum *get_mode_enum();
+
+ static PassInfo get_info(PassType type, const bool include_albedo = false);
+
+ static bool contains(const vector<Pass *> &passes, PassType type);
+
+ /* Returns nullptr if there is no pass with the given name or type+mode. */
+ static const Pass *find(const vector<Pass *> &passes, const string &name);
+ static const Pass *find(const vector<Pass *> &passes,
+ PassType type,
+ PassMode mode = PassMode::NOISY);
+
+ /* Returns PASS_UNUSED if there is no corresponding pass. */
+ static int get_offset(const vector<Pass *> &passes, const Pass *pass);
+
+ friend class Film;
+};
+
+std::ostream &operator<<(std::ostream &os, const Pass &pass);
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/procedural.cpp b/intern/cycles/scene/procedural.cpp
new file mode 100644
index 00000000000..f038c8b1023
--- /dev/null
+++ b/intern/cycles/scene/procedural.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/procedural.h"
+#include "scene/scene.h"
+#include "scene/stats.h"
+
+#include "util/foreach.h"
+#include "util/progress.h"
+
+CCL_NAMESPACE_BEGIN
+
+NODE_ABSTRACT_DEFINE(Procedural)
+{
+ NodeType *type = NodeType::add("procedural_base", NULL);
+ return type;
+}
+
+Procedural::Procedural(const NodeType *type) : Node(type)
+{
+}
+
+Procedural::~Procedural()
+{
+}
+
+ProceduralManager::ProceduralManager()
+{
+ need_update_ = true;
+}
+
+ProceduralManager::~ProceduralManager()
+{
+}
+
+void ProceduralManager::update(Scene *scene, Progress &progress)
+{
+ if (!need_update()) {
+ return;
+ }
+
+ progress.set_status("Updating Procedurals");
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->procedurals.times.add_entry({"update", time});
+ }
+ });
+
+ foreach (Procedural *procedural, scene->procedurals) {
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ procedural->generate(scene, progress);
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ need_update_ = false;
+}
+
+void ProceduralManager::tag_update()
+{
+ need_update_ = true;
+}
+
+bool ProceduralManager::need_update() const
+{
+ return need_update_;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/procedural.h b/intern/cycles/scene/procedural.h
index 985b8d69979..985b8d69979 100644
--- a/intern/cycles/render/procedural.h
+++ b/intern/cycles/scene/procedural.h
diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp
new file mode 100644
index 00000000000..ef0ee0c6625
--- /dev/null
+++ b/intern/cycles/scene/scene.cpp
@@ -0,0 +1,961 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include "bvh/bvh.h"
+#include "device/device.h"
+#include "scene/alembic.h"
+#include "scene/background.h"
+#include "scene/bake.h"
+#include "scene/camera.h"
+#include "scene/curves.h"
+#include "scene/film.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/osl.h"
+#include "scene/particles.h"
+#include "scene/procedural.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/svm.h"
+#include "scene/tables.h"
+#include "scene/volume.h"
+#include "session/session.h"
+
+#include "util/foreach.h"
+#include "util/guarded_allocator.h"
+#include "util/log.h"
+#include "util/progress.h"
+
+CCL_NAMESPACE_BEGIN
+
+DeviceScene::DeviceScene(Device *device)
+ : bvh_nodes(device, "__bvh_nodes", MEM_GLOBAL),
+ bvh_leaf_nodes(device, "__bvh_leaf_nodes", MEM_GLOBAL),
+ object_node(device, "__object_node", MEM_GLOBAL),
+ prim_type(device, "__prim_type", MEM_GLOBAL),
+ prim_visibility(device, "__prim_visibility", MEM_GLOBAL),
+ prim_index(device, "__prim_index", MEM_GLOBAL),
+ prim_object(device, "__prim_object", MEM_GLOBAL),
+ prim_time(device, "__prim_time", MEM_GLOBAL),
+ tri_verts(device, "__tri_verts", MEM_GLOBAL),
+ tri_shader(device, "__tri_shader", MEM_GLOBAL),
+ tri_vnormal(device, "__tri_vnormal", MEM_GLOBAL),
+ tri_vindex(device, "__tri_vindex", MEM_GLOBAL),
+ tri_patch(device, "__tri_patch", MEM_GLOBAL),
+ tri_patch_uv(device, "__tri_patch_uv", MEM_GLOBAL),
+ curves(device, "__curves", MEM_GLOBAL),
+ curve_keys(device, "__curve_keys", MEM_GLOBAL),
+ curve_segments(device, "__curve_segments", MEM_GLOBAL),
+ patches(device, "__patches", MEM_GLOBAL),
+ objects(device, "__objects", MEM_GLOBAL),
+ object_motion_pass(device, "__object_motion_pass", MEM_GLOBAL),
+ object_motion(device, "__object_motion", MEM_GLOBAL),
+ object_flag(device, "__object_flag", MEM_GLOBAL),
+ object_volume_step(device, "__object_volume_step", MEM_GLOBAL),
+ camera_motion(device, "__camera_motion", MEM_GLOBAL),
+ attributes_map(device, "__attributes_map", MEM_GLOBAL),
+ attributes_float(device, "__attributes_float", MEM_GLOBAL),
+ attributes_float2(device, "__attributes_float2", MEM_GLOBAL),
+ attributes_float3(device, "__attributes_float3", MEM_GLOBAL),
+ attributes_uchar4(device, "__attributes_uchar4", MEM_GLOBAL),
+ light_distribution(device, "__light_distribution", MEM_GLOBAL),
+ lights(device, "__lights", MEM_GLOBAL),
+ light_background_marginal_cdf(device, "__light_background_marginal_cdf", MEM_GLOBAL),
+ light_background_conditional_cdf(device, "__light_background_conditional_cdf", MEM_GLOBAL),
+ particles(device, "__particles", MEM_GLOBAL),
+ svm_nodes(device, "__svm_nodes", MEM_GLOBAL),
+ shaders(device, "__shaders", MEM_GLOBAL),
+ lookup_table(device, "__lookup_table", MEM_GLOBAL),
+ sample_pattern_lut(device, "__sample_pattern_lut", MEM_GLOBAL),
+ ies_lights(device, "__ies", MEM_GLOBAL)
+{
+ memset((void *)&data, 0, sizeof(data));
+}
+
+Scene::Scene(const SceneParams &params_, Device *device)
+ : name("Scene"),
+ bvh(NULL),
+ default_surface(NULL),
+ default_volume(NULL),
+ default_light(NULL),
+ default_background(NULL),
+ default_empty(NULL),
+ device(device),
+ dscene(device),
+ params(params_),
+ update_stats(NULL),
+ kernels_loaded(false),
+ /* TODO(sergey): Check if it's indeed optimal value for the split kernel. */
+ max_closure_global(1)
+{
+ memset((void *)&dscene.data, 0, sizeof(dscene.data));
+
+ /* OSL only works on the CPU */
+ if (device->info.has_osl)
+ shader_manager = ShaderManager::create(params.shadingsystem);
+ else
+ shader_manager = ShaderManager::create(SHADINGSYSTEM_SVM);
+
+ light_manager = new LightManager();
+ geometry_manager = new GeometryManager();
+ object_manager = new ObjectManager();
+ image_manager = new ImageManager(device->info);
+ particle_system_manager = new ParticleSystemManager();
+ bake_manager = new BakeManager();
+ procedural_manager = new ProceduralManager();
+
+ /* Create nodes after managers, since create_node() can tag the managers. */
+ camera = create_node<Camera>();
+ dicing_camera = create_node<Camera>();
+ lookup_tables = new LookupTables();
+ film = create_node<Film>();
+ background = create_node<Background>();
+ integrator = create_node<Integrator>();
+
+ film->add_default(this);
+ shader_manager->add_default(this);
+}
+
+Scene::~Scene()
+{
+ free_memory(true);
+}
+
+void Scene::free_memory(bool final)
+{
+ delete bvh;
+ bvh = NULL;
+
+ /* The order of deletion is important to make sure data is freed based on possible dependencies
+ * as the Nodes' reference counts are decremented in the destructors:
+ *
+ * - Procedurals can create and hold pointers to any other types.
+ * - Objects can hold pointers to Geometries and ParticleSystems
+ * - Lights and Geometries can hold pointers to Shaders.
+ *
+ * Similarly, we first delete all nodes and their associated device data, and then the managers
+ * and their associated device data.
+ */
+ foreach (Procedural *p, procedurals)
+ delete p;
+ foreach (Object *o, objects)
+ delete o;
+ foreach (Geometry *g, geometry)
+ delete g;
+ foreach (ParticleSystem *p, particle_systems)
+ delete p;
+ foreach (Light *l, lights)
+ delete l;
+ foreach (Pass *p, passes)
+ delete p;
+
+ geometry.clear();
+ objects.clear();
+ lights.clear();
+ particle_systems.clear();
+ procedurals.clear();
+ passes.clear();
+
+ if (device) {
+ camera->device_free(device, &dscene, this);
+ film->device_free(device, &dscene, this);
+ background->device_free(device, &dscene);
+ integrator->device_free(device, &dscene, true);
+ }
+
+ if (final) {
+ delete camera;
+ delete dicing_camera;
+ delete film;
+ delete background;
+ delete integrator;
+ }
+
+ /* Delete Shaders after every other nodes to ensure that we do not try to decrement the reference
+ * count on some dangling pointer. */
+ foreach (Shader *s, shaders)
+ delete s;
+
+ shaders.clear();
+
+ /* Now that all nodes have been deleted, we can safely delete managers and device data. */
+ if (device) {
+ object_manager->device_free(device, &dscene, true);
+ geometry_manager->device_free(device, &dscene, true);
+ shader_manager->device_free(device, &dscene, this);
+ light_manager->device_free(device, &dscene);
+
+ particle_system_manager->device_free(device, &dscene);
+
+ bake_manager->device_free(device, &dscene);
+
+ if (final)
+ image_manager->device_free(device);
+ else
+ image_manager->device_free_builtin(device);
+
+ lookup_tables->device_free(device, &dscene);
+ }
+
+ if (final) {
+ delete lookup_tables;
+ delete object_manager;
+ delete geometry_manager;
+ delete shader_manager;
+ delete light_manager;
+ delete particle_system_manager;
+ delete image_manager;
+ delete bake_manager;
+ delete update_stats;
+ delete procedural_manager;
+ }
+}
+
+void Scene::device_update(Device *device_, Progress &progress)
+{
+ if (!device)
+ device = device_;
+
+ bool print_stats = need_data_update();
+
+ if (update_stats) {
+ update_stats->clear();
+ }
+
+ scoped_callback_timer timer([this, print_stats](double time) {
+ if (update_stats) {
+ update_stats->scene.times.add_entry({"device_update", time});
+
+ if (print_stats) {
+ printf("Update statistics:\n%s\n", update_stats->full_report().c_str());
+ }
+ }
+ });
+
+ /* The order of updates is important, because there's dependencies between
+ * the different managers, using data computed by previous managers.
+ *
+ * - Image manager uploads images used by shaders.
+ * - Camera may be used for adaptive subdivision.
+ * - Displacement shader must have all shader data available.
+ * - Light manager needs lookup tables and final mesh data to compute emission CDF.
+ * - Lookup tables are done a second time to handle film tables
+ */
+
+ progress.set_status("Updating Shaders");
+ shader_manager->device_update(device, &dscene, this, progress);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ procedural_manager->update(this, progress);
+
+ if (progress.get_cancel())
+ return;
+
+ progress.set_status("Updating Background");
+ background->device_update(device, &dscene, this);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Camera");
+ camera->device_update(device, &dscene, this);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ geometry_manager->device_update_preprocess(device, this, progress);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Objects");
+ object_manager->device_update(device, &dscene, this, progress);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Particle Systems");
+ particle_system_manager->device_update(device, &dscene, this, progress);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Meshes");
+ geometry_manager->device_update(device, &dscene, this, progress);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Objects Flags");
+ object_manager->device_update_flags(device, &dscene, this, progress);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Images");
+ image_manager->device_update(device, this, progress);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Camera Volume");
+ camera->device_update_volume(device, &dscene, this);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Lookup Tables");
+ lookup_tables->device_update(device, &dscene, this);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Lights");
+ light_manager->device_update(device, &dscene, this, progress);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Integrator");
+ integrator->device_update(device, &dscene, this);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Film");
+ film->device_update(device, &dscene, this);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Lookup Tables");
+ lookup_tables->device_update(device, &dscene, this);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ progress.set_status("Updating Baking");
+ bake_manager->device_update(device, &dscene, this, progress);
+
+ if (progress.get_cancel() || device->have_error())
+ return;
+
+ if (device->have_error() == false) {
+ dscene.data.volume_stack_size = get_volume_stack_size();
+
+ progress.set_status("Updating Device", "Writing constant memory");
+ device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
+ }
+
+ if (print_stats) {
+ size_t mem_used = util_guarded_get_mem_used();
+ size_t mem_peak = util_guarded_get_mem_peak();
+
+ VLOG(1) << "System memory statistics after full device sync:\n"
+ << " Usage: " << string_human_readable_number(mem_used) << " ("
+ << string_human_readable_size(mem_used) << ")\n"
+ << " Peak: " << string_human_readable_number(mem_peak) << " ("
+ << string_human_readable_size(mem_peak) << ")";
+ }
+}
+
+Scene::MotionType Scene::need_motion()
+{
+ if (integrator->get_motion_blur())
+ return MOTION_BLUR;
+ else if (Pass::contains(passes, PASS_MOTION))
+ return MOTION_PASS;
+ else
+ return MOTION_NONE;
+}
+
+float Scene::motion_shutter_time()
+{
+ if (need_motion() == Scene::MOTION_PASS)
+ return 2.0f;
+ else
+ return camera->get_shuttertime();
+}
+
+bool Scene::need_global_attribute(AttributeStandard std)
+{
+ if (std == ATTR_STD_UV)
+ return Pass::contains(passes, PASS_UV);
+ else if (std == ATTR_STD_MOTION_VERTEX_POSITION)
+ return need_motion() != MOTION_NONE;
+ else if (std == ATTR_STD_MOTION_VERTEX_NORMAL)
+ return need_motion() == MOTION_BLUR;
+
+ return false;
+}
+
+void Scene::need_global_attributes(AttributeRequestSet &attributes)
+{
+ for (int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++)
+ if (need_global_attribute((AttributeStandard)std))
+ attributes.add((AttributeStandard)std);
+}
+
+bool Scene::need_update()
+{
+ return (need_reset() || film->is_modified());
+}
+
+bool Scene::need_data_update()
+{
+ return (background->is_modified() || image_manager->need_update() ||
+ object_manager->need_update() || geometry_manager->need_update() ||
+ light_manager->need_update() || lookup_tables->need_update() ||
+ integrator->is_modified() || shader_manager->need_update() ||
+ particle_system_manager->need_update() || bake_manager->need_update() ||
+ film->is_modified() || procedural_manager->need_update());
+}
+
+bool Scene::need_reset()
+{
+ return need_data_update() || camera->is_modified();
+}
+
+void Scene::reset()
+{
+ shader_manager->reset(this);
+ shader_manager->add_default(this);
+
+ /* ensure all objects are updated */
+ camera->tag_modified();
+ dicing_camera->tag_modified();
+ film->tag_modified();
+ background->tag_modified();
+
+ background->tag_update(this);
+ integrator->tag_update(this, Integrator::UPDATE_ALL);
+ object_manager->tag_update(this, ObjectManager::UPDATE_ALL);
+ geometry_manager->tag_update(this, GeometryManager::UPDATE_ALL);
+ light_manager->tag_update(this, LightManager::UPDATE_ALL);
+ particle_system_manager->tag_update(this);
+ procedural_manager->tag_update();
+}
+
+void Scene::device_free()
+{
+ free_memory(false);
+}
+
+void Scene::collect_statistics(RenderStats *stats)
+{
+ geometry_manager->collect_statistics(this, stats);
+ image_manager->collect_statistics(stats);
+}
+
+void Scene::enable_update_stats()
+{
+ if (!update_stats) {
+ update_stats = new SceneUpdateStats();
+ }
+}
+
+void Scene::update_kernel_features()
+{
+ if (!need_update()) {
+ return;
+ }
+
+ /* These features are not being tweaked as often as shaders,
+ * so could be done selective magic for the viewport as well. */
+ uint kernel_features = shader_manager->get_kernel_features(this);
+
+ bool use_motion = need_motion() == Scene::MotionType::MOTION_BLUR;
+ kernel_features |= KERNEL_FEATURE_PATH_TRACING;
+ if (params.hair_shape == CURVE_THICK) {
+ kernel_features |= KERNEL_FEATURE_HAIR_THICK;
+ }
+ if (use_motion && camera->use_motion()) {
+ kernel_features |= KERNEL_FEATURE_CAMERA_MOTION;
+ }
+ foreach (Object *object, objects) {
+ Geometry *geom = object->get_geometry();
+ if (use_motion) {
+ if (object->use_motion() || geom->get_use_motion_blur()) {
+ kernel_features |= KERNEL_FEATURE_OBJECT_MOTION;
+ }
+ if (geom->get_use_motion_blur()) {
+ kernel_features |= KERNEL_FEATURE_CAMERA_MOTION;
+ }
+ }
+ if (object->get_is_shadow_catcher()) {
+ kernel_features |= KERNEL_FEATURE_SHADOW_CATCHER;
+ }
+ if (geom->is_mesh()) {
+#ifdef WITH_OPENSUBDIV
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
+ kernel_features |= KERNEL_FEATURE_PATCH_EVALUATION;
+ }
+#endif
+ }
+ else if (geom->is_hair()) {
+ kernel_features |= KERNEL_FEATURE_HAIR;
+ }
+ }
+
+ if (bake_manager->get_baking()) {
+ kernel_features |= KERNEL_FEATURE_BAKING;
+ }
+
+ kernel_features |= film->get_kernel_features(this);
+ kernel_features |= integrator->get_kernel_features();
+
+ dscene.data.kernel_features = kernel_features;
+
+ /* Currently viewport render is faster with higher max_closures, needs investigating. */
+ const uint max_closures = (params.background) ? get_max_closure_count() : MAX_CLOSURE;
+ dscene.data.max_closures = max_closures;
+ dscene.data.max_shaders = shaders.size();
+}
+
+bool Scene::update(Progress &progress)
+{
+ if (!need_update()) {
+ return false;
+ }
+
+ /* Load render kernels, before device update where we upload data to the GPU. */
+ load_kernels(progress, false);
+
+ /* Upload scene data to the GPU. */
+ progress.set_status("Updating Scene");
+ MEM_GUARDED_CALL(&progress, device_update, device, progress);
+
+ return true;
+}
+
+static void log_kernel_features(const uint features)
+{
+ VLOG(2) << "Requested features:\n";
+ VLOG(2) << "Use BSDF " << string_from_bool(features & KERNEL_FEATURE_NODE_BSDF) << "\n";
+ VLOG(2) << "Use Principled BSDF " << string_from_bool(features & KERNEL_FEATURE_PRINCIPLED)
+ << "\n";
+ VLOG(2) << "Use Emission " << string_from_bool(features & KERNEL_FEATURE_NODE_EMISSION) << "\n";
+ VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_NODE_VOLUME) << "\n";
+ VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_NODE_HAIR) << "\n";
+ VLOG(2) << "Use Bump " << string_from_bool(features & KERNEL_FEATURE_NODE_BUMP) << "\n";
+ VLOG(2) << "Use Voronoi " << string_from_bool(features & KERNEL_FEATURE_NODE_VORONOI_EXTRA)
+ << "\n";
+ VLOG(2) << "Use Shader Raytrace " << string_from_bool(features & KERNEL_FEATURE_NODE_RAYTRACE)
+ << "\n";
+ VLOG(2) << "Use Transparent " << string_from_bool(features & KERNEL_FEATURE_TRANSPARENT) << "\n";
+ VLOG(2) << "Use Denoising " << string_from_bool(features & KERNEL_FEATURE_DENOISING) << "\n";
+ VLOG(2) << "Use Path Tracing " << string_from_bool(features & KERNEL_FEATURE_PATH_TRACING)
+ << "\n";
+ VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_HAIR) << "\n";
+ VLOG(2) << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION)
+ << "\n";
+ VLOG(2) << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION)
+ << "\n";
+ VLOG(2) << "Use Baking " << string_from_bool(features & KERNEL_FEATURE_BAKING) << "\n";
+ VLOG(2) << "Use Subsurface " << string_from_bool(features & KERNEL_FEATURE_SUBSURFACE) << "\n";
+ VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_VOLUME) << "\n";
+ VLOG(2) << "Use Patch Evaluation "
+ << string_from_bool(features & KERNEL_FEATURE_PATCH_EVALUATION) << "\n";
+ VLOG(2) << "Use Shadow Catcher " << string_from_bool(features & KERNEL_FEATURE_SHADOW_CATCHER)
+ << "\n";
+}
+
+bool Scene::load_kernels(Progress &progress, bool lock_scene)
+{
+ thread_scoped_lock scene_lock;
+ if (lock_scene) {
+ scene_lock = thread_scoped_lock(mutex);
+ }
+
+ update_kernel_features();
+
+ const uint kernel_features = dscene.data.kernel_features;
+
+ if (!kernels_loaded || loaded_kernel_features != kernel_features) {
+ progress.set_status("Loading render kernels (may take a few minutes the first time)");
+
+ scoped_timer timer;
+
+ log_kernel_features(kernel_features);
+ if (!device->load_kernels(kernel_features)) {
+ string message = device->error_message();
+ if (message.empty())
+ message = "Failed loading render kernel, see console for errors";
+
+ progress.set_error(message);
+ progress.set_status(message);
+ progress.set_update();
+ return false;
+ }
+
+ kernels_loaded = true;
+ loaded_kernel_features = kernel_features;
+ return true;
+ }
+ return false;
+}
+
+int Scene::get_max_closure_count()
+{
+ if (shader_manager->use_osl()) {
+ /* OSL always needs the maximum as we can't predict the
+ * number of closures a shader might generate. */
+ return MAX_CLOSURE;
+ }
+
+ int max_closures = 0;
+ for (int i = 0; i < shaders.size(); i++) {
+ Shader *shader = shaders[i];
+ if (shader->reference_count()) {
+ int num_closures = shader->graph->get_num_closures();
+ max_closures = max(max_closures, num_closures);
+ }
+ }
+ max_closure_global = max(max_closure_global, max_closures);
+
+ if (max_closure_global > MAX_CLOSURE) {
+ /* This is usually harmless as more complex shader tend to get many
+ * closures discarded due to mixing or low weights. We need to limit
+ * to MAX_CLOSURE as this is hardcoded in CPU/mega kernels, and it
+ * avoids excessive memory usage for split kernels. */
+ VLOG(2) << "Maximum number of closures exceeded: " << max_closure_global << " > "
+ << MAX_CLOSURE;
+
+ max_closure_global = MAX_CLOSURE;
+ }
+
+ return max_closure_global;
+}
+
+int Scene::get_volume_stack_size() const
+{
+ int volume_stack_size = 0;
+
+ /* Space for background volume and terminator.
+ * Don't do optional here because camera ray initialization expects that there is space for
+ * at least those elements (avoiding extra condition to check if there is actual volume or not).
+ */
+ volume_stack_size += 2;
+
+ /* Quick non-expensive check. Can over-estimate maximum possible nested level, but does not
+ * require expensive calculation during pre-processing. */
+ bool has_volume_object = false;
+ for (const Object *object : objects) {
+ if (!object->get_geometry()->has_volume) {
+ continue;
+ }
+
+ if (object->intersects_volume) {
+ /* Object intersects another volume, assume it's possible to go deeper in the stack. */
+ /* TODO(sergey): This might count nesting twice (A intersects B and B intersects A), but
+ * can't think of a computationally cheap algorithm. Dividing my 2 doesn't work because of
+ * Venn diagram example with 3 circles. */
+ ++volume_stack_size;
+ }
+ else if (!has_volume_object) {
+ /* Allocate space for at least one volume object. */
+ ++volume_stack_size;
+ }
+
+ has_volume_object = true;
+
+ if (volume_stack_size == MAX_VOLUME_STACK_SIZE) {
+ break;
+ }
+ }
+
+ volume_stack_size = min(volume_stack_size, MAX_VOLUME_STACK_SIZE);
+
+ VLOG(3) << "Detected required volume stack size " << volume_stack_size;
+
+ return volume_stack_size;
+}
+
+bool Scene::has_shadow_catcher()
+{
+ if (shadow_catcher_modified_) {
+ has_shadow_catcher_ = false;
+ for (Object *object : objects) {
+ if (object->get_is_shadow_catcher()) {
+ has_shadow_catcher_ = true;
+ break;
+ }
+ }
+
+ shadow_catcher_modified_ = false;
+ }
+
+ return has_shadow_catcher_;
+}
+
+void Scene::tag_shadow_catcher_modified()
+{
+ shadow_catcher_modified_ = true;
+}
+
+template<> Light *Scene::create_node<Light>()
+{
+ Light *node = new Light();
+ node->set_owner(this);
+ lights.push_back(node);
+ light_manager->tag_update(this, LightManager::LIGHT_ADDED);
+ return node;
+}
+
+template<> Mesh *Scene::create_node<Mesh>()
+{
+ Mesh *node = new Mesh();
+ node->set_owner(this);
+ geometry.push_back(node);
+ geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
+ return node;
+}
+
+template<> Hair *Scene::create_node<Hair>()
+{
+ Hair *node = new Hair();
+ node->set_owner(this);
+ geometry.push_back(node);
+ geometry_manager->tag_update(this, GeometryManager::HAIR_ADDED);
+ return node;
+}
+
+template<> Volume *Scene::create_node<Volume>()
+{
+ Volume *node = new Volume();
+ node->set_owner(this);
+ geometry.push_back(node);
+ geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
+ return node;
+}
+
+template<> Object *Scene::create_node<Object>()
+{
+ Object *node = new Object();
+ node->set_owner(this);
+ objects.push_back(node);
+ object_manager->tag_update(this, ObjectManager::OBJECT_ADDED);
+ return node;
+}
+
+template<> ParticleSystem *Scene::create_node<ParticleSystem>()
+{
+ ParticleSystem *node = new ParticleSystem();
+ node->set_owner(this);
+ particle_systems.push_back(node);
+ particle_system_manager->tag_update(this);
+ return node;
+}
+
+template<> Shader *Scene::create_node<Shader>()
+{
+ Shader *node = new Shader();
+ node->set_owner(this);
+ shaders.push_back(node);
+ shader_manager->tag_update(this, ShaderManager::SHADER_ADDED);
+ return node;
+}
+
+template<> AlembicProcedural *Scene::create_node<AlembicProcedural>()
+{
+#ifdef WITH_ALEMBIC
+ AlembicProcedural *node = new AlembicProcedural();
+ node->set_owner(this);
+ procedurals.push_back(node);
+ procedural_manager->tag_update();
+ return node;
+#else
+ return nullptr;
+#endif
+}
+
+template<> Pass *Scene::create_node<Pass>()
+{
+ Pass *node = new Pass();
+ node->set_owner(this);
+ passes.push_back(node);
+ film->tag_modified();
+ return node;
+}
+
+template<typename T> void delete_node_from_array(vector<T> &nodes, T node)
+{
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ if (nodes[i] == node) {
+ std::swap(nodes[i], nodes[nodes.size() - 1]);
+ break;
+ }
+ }
+
+ nodes.resize(nodes.size() - 1);
+
+ delete node;
+}
+
+template<> void Scene::delete_node_impl(Light *node)
+{
+ delete_node_from_array(lights, node);
+ light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
+}
+
+template<> void Scene::delete_node_impl(Mesh *node)
+{
+ delete_node_from_array(geometry, static_cast<Geometry *>(node));
+ geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
+}
+
+template<> void Scene::delete_node_impl(Hair *node)
+{
+ delete_node_from_array(geometry, static_cast<Geometry *>(node));
+ geometry_manager->tag_update(this, GeometryManager::HAIR_REMOVED);
+}
+
+template<> void Scene::delete_node_impl(Volume *node)
+{
+ delete_node_from_array(geometry, static_cast<Geometry *>(node));
+ geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
+}
+
+template<> void Scene::delete_node_impl(Geometry *node)
+{
+ uint flag;
+ if (node->is_hair()) {
+ flag = GeometryManager::HAIR_REMOVED;
+ }
+ else {
+ flag = GeometryManager::MESH_REMOVED;
+ }
+
+ delete_node_from_array(geometry, node);
+ geometry_manager->tag_update(this, flag);
+}
+
+template<> void Scene::delete_node_impl(Object *node)
+{
+ delete_node_from_array(objects, node);
+ object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
+}
+
+template<> void Scene::delete_node_impl(ParticleSystem *node)
+{
+ delete_node_from_array(particle_systems, node);
+ particle_system_manager->tag_update(this);
+}
+
+template<> void Scene::delete_node_impl(Shader *shader)
+{
+ /* don't delete unused shaders, not supported */
+ shader->clear_reference_count();
+}
+
+template<> void Scene::delete_node_impl(Procedural *node)
+{
+ delete_node_from_array(procedurals, node);
+ procedural_manager->tag_update();
+}
+
+template<> void Scene::delete_node_impl(AlembicProcedural *node)
+{
+#ifdef WITH_ALEMBIC
+ delete_node_impl(static_cast<Procedural *>(node));
+#else
+ (void)node;
+#endif
+}
+
+template<> void Scene::delete_node_impl(Pass *node)
+{
+ delete_node_from_array(passes, node);
+ film->tag_modified();
+}
+
+template<typename T>
+static void remove_nodes_in_set(const set<T *> &nodes_set,
+ vector<T *> &nodes_array,
+ const NodeOwner *owner)
+{
+ size_t new_size = nodes_array.size();
+
+ for (size_t i = 0; i < new_size; ++i) {
+ T *node = nodes_array[i];
+
+ if (nodes_set.find(node) != nodes_set.end()) {
+ std::swap(nodes_array[i], nodes_array[new_size - 1]);
+
+ assert(node->get_owner() == owner);
+ delete node;
+
+ i -= 1;
+ new_size -= 1;
+ }
+ }
+
+ nodes_array.resize(new_size);
+ (void)owner;
+}
+
+template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner)
+{
+ remove_nodes_in_set(nodes, lights, owner);
+ light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
+}
+
+template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner)
+{
+ remove_nodes_in_set(nodes, geometry, owner);
+ geometry_manager->tag_update(this, GeometryManager::GEOMETRY_REMOVED);
+}
+
+template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner)
+{
+ remove_nodes_in_set(nodes, objects, owner);
+ object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
+}
+
+template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner)
+{
+ remove_nodes_in_set(nodes, particle_systems, owner);
+ particle_system_manager->tag_update(this);
+}
+
+template<> void Scene::delete_nodes(const set<Shader *> &nodes, const NodeOwner * /*owner*/)
+{
+ /* don't delete unused shaders, not supported */
+ for (Shader *shader : nodes) {
+ shader->clear_reference_count();
+ }
+}
+
+template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner)
+{
+ remove_nodes_in_set(nodes, procedurals, owner);
+ procedural_manager->tag_update();
+}
+
+template<> void Scene::delete_nodes(const set<Pass *> &nodes, const NodeOwner *owner)
+{
+ remove_nodes_in_set(nodes, passes, owner);
+ film->tag_modified();
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h
new file mode 100644
index 00000000000..fa7fc54602a
--- /dev/null
+++ b/intern/cycles/scene/scene.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SCENE_H__
+#define __SCENE_H__
+
+#include "bvh/params.h"
+
+#include "scene/film.h"
+#include "scene/image.h"
+#include "scene/shader.h"
+
+#include "device/device.h"
+#include "device/memory.h"
+
+#include "util/param.h"
+#include "util/string.h"
+#include "util/system.h"
+#include "util/texture.h"
+#include "util/thread.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class AlembicProcedural;
+class AttributeRequestSet;
+class Background;
+class BVH;
+class Camera;
+class Device;
+class DeviceInfo;
+class Film;
+class Integrator;
+class Light;
+class LightManager;
+class LookupTables;
+class Geometry;
+class GeometryManager;
+class Object;
+class ObjectManager;
+class ParticleSystemManager;
+class ParticleSystem;
+class Procedural;
+class ProceduralManager;
+class CurveSystemManager;
+class Shader;
+class ShaderManager;
+class Progress;
+class BakeManager;
+class BakeData;
+class RenderStats;
+class SceneUpdateStats;
+class Volume;
+
+/* Scene Device Data */
+
+class DeviceScene {
+ public:
+ /* BVH */
+ device_vector<int4> bvh_nodes;
+ device_vector<int4> bvh_leaf_nodes;
+ device_vector<int> object_node;
+ device_vector<int> prim_type;
+ device_vector<uint> prim_visibility;
+ device_vector<int> prim_index;
+ device_vector<int> prim_object;
+ device_vector<float2> prim_time;
+
+ /* mesh */
+ device_vector<float4> tri_verts;
+ device_vector<uint> tri_shader;
+ device_vector<float4> tri_vnormal;
+ device_vector<uint4> tri_vindex;
+ device_vector<uint> tri_patch;
+ device_vector<float2> tri_patch_uv;
+
+ device_vector<KernelCurve> curves;
+ device_vector<float4> curve_keys;
+ device_vector<KernelCurveSegment> curve_segments;
+
+ device_vector<uint> patches;
+
+ /* objects */
+ device_vector<KernelObject> objects;
+ device_vector<Transform> object_motion_pass;
+ device_vector<DecomposedTransform> object_motion;
+ device_vector<uint> object_flag;
+ device_vector<float> object_volume_step;
+
+ /* cameras */
+ device_vector<DecomposedTransform> camera_motion;
+
+ /* attributes */
+ device_vector<uint4> attributes_map;
+ device_vector<float> attributes_float;
+ device_vector<float2> attributes_float2;
+ device_vector<float4> attributes_float3;
+ device_vector<uchar4> attributes_uchar4;
+
+ /* lights */
+ device_vector<KernelLightDistribution> light_distribution;
+ device_vector<KernelLight> lights;
+ device_vector<float2> light_background_marginal_cdf;
+ device_vector<float2> light_background_conditional_cdf;
+
+ /* particles */
+ device_vector<KernelParticle> particles;
+
+ /* shaders */
+ device_vector<int4> svm_nodes;
+ device_vector<KernelShader> shaders;
+
+ /* lookup tables */
+ device_vector<float> lookup_table;
+
+ /* integrator */
+ device_vector<float> sample_pattern_lut;
+
+ /* ies lights */
+ device_vector<float> ies_lights;
+
+ KernelData data;
+
+ DeviceScene(Device *device);
+};
+
+/* Scene Parameters */
+
+class SceneParams {
+ public:
+ ShadingSystem shadingsystem;
+
+ /* Requested BVH layout.
+ *
+ * If it's not supported by the device, the widest one from supported ones
+ * will be used, but BVH wider than this one will never be used.
+ */
+ BVHLayout bvh_layout;
+
+ BVHType bvh_type;
+ bool use_bvh_spatial_split;
+ bool use_bvh_unaligned_nodes;
+ int num_bvh_time_steps;
+ int hair_subdivisions;
+ CurveShapeType hair_shape;
+ int texture_limit;
+
+ bool background;
+
+ SceneParams()
+ {
+ shadingsystem = SHADINGSYSTEM_SVM;
+ bvh_layout = BVH_LAYOUT_BVH2;
+ bvh_type = BVH_TYPE_DYNAMIC;
+ use_bvh_spatial_split = false;
+ use_bvh_unaligned_nodes = true;
+ num_bvh_time_steps = 0;
+ hair_subdivisions = 3;
+ hair_shape = CURVE_RIBBON;
+ texture_limit = 0;
+ background = true;
+ }
+
+ bool modified(const SceneParams &params) const
+ {
+ return !(shadingsystem == params.shadingsystem && bvh_layout == params.bvh_layout &&
+ bvh_type == params.bvh_type &&
+ use_bvh_spatial_split == params.use_bvh_spatial_split &&
+ use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes &&
+ num_bvh_time_steps == params.num_bvh_time_steps &&
+ hair_subdivisions == params.hair_subdivisions && hair_shape == params.hair_shape &&
+ texture_limit == params.texture_limit);
+ }
+
+ int curve_subdivisions()
+ {
+ /* Matching the tessellation rate limit in Embree. */
+ return clamp(1 << hair_subdivisions, 1, 16);
+ }
+};
+
+/* Scene */
+
+class Scene : public NodeOwner {
+ public:
+ /* Optional name. Is used for logging and reporting. */
+ string name;
+
+ /* data */
+ BVH *bvh;
+ Camera *camera;
+ Camera *dicing_camera;
+ LookupTables *lookup_tables;
+ Film *film;
+ Background *background;
+ Integrator *integrator;
+
+ /* data lists */
+ vector<Object *> objects;
+ vector<Geometry *> geometry;
+ vector<Shader *> shaders;
+ vector<Light *> lights;
+ vector<ParticleSystem *> particle_systems;
+ vector<Pass *> passes;
+ vector<Procedural *> procedurals;
+
+ /* data managers */
+ ImageManager *image_manager;
+ LightManager *light_manager;
+ ShaderManager *shader_manager;
+ GeometryManager *geometry_manager;
+ ObjectManager *object_manager;
+ ParticleSystemManager *particle_system_manager;
+ BakeManager *bake_manager;
+ ProceduralManager *procedural_manager;
+
+ /* default shaders */
+ Shader *default_surface;
+ Shader *default_volume;
+ Shader *default_light;
+ Shader *default_background;
+ Shader *default_empty;
+
+ /* device */
+ Device *device;
+ DeviceScene dscene;
+
+ /* parameters */
+ SceneParams params;
+
+ /* mutex must be locked manually by callers */
+ thread_mutex mutex;
+
+ /* scene update statistics */
+ SceneUpdateStats *update_stats;
+
+ Scene(const SceneParams &params, Device *device);
+ ~Scene();
+
+ void device_update(Device *device, Progress &progress);
+
+ bool need_global_attribute(AttributeStandard std);
+ void need_global_attributes(AttributeRequestSet &attributes);
+
+ enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR };
+ MotionType need_motion();
+ float motion_shutter_time();
+
+ bool need_update();
+ bool need_reset();
+
+ void reset();
+ void device_free();
+
+ void collect_statistics(RenderStats *stats);
+
+ void enable_update_stats();
+
+ bool update(Progress &progress);
+
+ bool has_shadow_catcher();
+ void tag_shadow_catcher_modified();
+
+ /* This function is used to create a node of a specified type instead of
+ * calling 'new', and sets the scene as the owner of the node.
+ * The function has overloads that will also add the created node to the right
+ * node array (e.g. Scene::geometry for Geometry nodes) and tag the appropriate
+ * manager for an update.
+ */
+ template<typename T, typename... Args> T *create_node(Args &&...args)
+ {
+ T *node = new T(args...);
+ node->set_owner(this);
+ return node;
+ }
+
+ /* This function is used to delete a node from the scene instead of calling 'delete'
+ * and manually removing the node from the data array. It also tags the
+ * appropriate manager for an update, if any, and checks that the scene is indeed
+ * the owner of the node. Calling this function on a node not owned by the scene
+ * will likely cause a crash which we want in order to detect such cases.
+ */
+ template<typename T> void delete_node(T *node)
+ {
+ assert(node->get_owner() == this);
+ delete_node_impl(node);
+ }
+
+ /* Same as above, but specify the actual owner.
+ */
+ template<typename T> void delete_node(T *node, const NodeOwner *owner)
+ {
+ assert(node->get_owner() == owner);
+ delete_node_impl(node);
+ (void)owner;
+ }
+
+ /* Remove all nodes in the set from the appropriate data arrays, and tag the
+ * specific managers for an update. This assumes that the scene owns the nodes.
+ */
+ template<typename T> void delete_nodes(const set<T *> &nodes)
+ {
+ delete_nodes(nodes, this);
+ }
+
+ /* Same as above, but specify the actual owner of all the nodes in the set.
+ */
+ template<typename T> void delete_nodes(const set<T *> &nodes, const NodeOwner *owner);
+
+ protected:
+ /* Check if some heavy data worth logging was updated.
+ * Mainly used to suppress extra annoying logging.
+ */
+ bool need_data_update();
+
+ void free_memory(bool final);
+
+ bool kernels_loaded;
+ uint loaded_kernel_features;
+
+ void update_kernel_features();
+ bool load_kernels(Progress &progress, bool lock_scene = true);
+
+ bool has_shadow_catcher_ = false;
+ bool shadow_catcher_modified_ = true;
+
+ /* Maximum number of closure during session lifetime. */
+ int max_closure_global;
+
+ /* Get maximum number of closures to be used in kernel. */
+ int get_max_closure_count();
+
+ /* Get size of a volume stack needed to render this scene. */
+ int get_volume_stack_size() const;
+
+ template<typename T> void delete_node_impl(T *node)
+ {
+ delete node;
+ }
+};
+
+template<> Light *Scene::create_node<Light>();
+
+template<> Mesh *Scene::create_node<Mesh>();
+
+template<> Object *Scene::create_node<Object>();
+
+template<> Hair *Scene::create_node<Hair>();
+
+template<> Volume *Scene::create_node<Volume>();
+
+template<> ParticleSystem *Scene::create_node<ParticleSystem>();
+
+template<> Shader *Scene::create_node<Shader>();
+
+template<> AlembicProcedural *Scene::create_node<AlembicProcedural>();
+
+template<> Pass *Scene::create_node<Pass>();
+
+template<> void Scene::delete_node_impl(Light *node);
+
+template<> void Scene::delete_node_impl(Mesh *node);
+
+template<> void Scene::delete_node_impl(Volume *node);
+
+template<> void Scene::delete_node_impl(Hair *node);
+
+template<> void Scene::delete_node_impl(Geometry *node);
+
+template<> void Scene::delete_node_impl(Object *node);
+
+template<> void Scene::delete_node_impl(ParticleSystem *node);
+
+template<> void Scene::delete_node_impl(Shader *node);
+
+template<> void Scene::delete_node_impl(Procedural *node);
+
+template<> void Scene::delete_node_impl(AlembicProcedural *node);
+
+template<> void Scene::delete_node_impl(Pass *node);
+
+template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner);
+
+template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner);
+
+template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner);
+
+template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner);
+
+template<> void Scene::delete_nodes(const set<Shader *> &nodes, const NodeOwner *owner);
+
+template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner);
+
+template<> void Scene::delete_nodes(const set<Pass *> &nodes, const NodeOwner *owner);
+
+CCL_NAMESPACE_END
+
+#endif /* __SCENE_H__ */
diff --git a/intern/cycles/scene/shader.cpp b/intern/cycles/scene/shader.cpp
new file mode 100644
index 00000000000..0b286aba9cf
--- /dev/null
+++ b/intern/cycles/scene/shader.cpp
@@ -0,0 +1,876 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device/device.h"
+
+#include "scene/background.h"
+#include "scene/camera.h"
+#include "scene/colorspace.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/osl.h"
+#include "scene/procedural.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+#include "scene/svm.h"
+#include "scene/tables.h"
+
+#include "util/foreach.h"
+#include "util/murmurhash.h"
+#include "util/task.h"
+#include "util/transform.h"
+
+#ifdef WITH_OCIO
+# include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+thread_mutex ShaderManager::lookup_table_mutex;
+vector<float> ShaderManager::beckmann_table;
+bool ShaderManager::beckmann_table_ready = false;
+
+/* Beckmann sampling precomputed table, see bsdf_microfacet.h */
+
+/* 2D slope distribution (alpha = 1.0) */
+static float beckmann_table_P22(const float slope_x, const float slope_y)
+{
+ return expf(-(slope_x * slope_x + slope_y * slope_y));
+}
+
+/* maximal slope amplitude (range that contains 99.99% of the distribution) */
+static float beckmann_table_slope_max()
+{
+ return 6.0;
+}
+
+/* MSVC 2015 needs this ugly hack to prevent a codegen bug on x86
+ * see T50176 for details
+ */
+#if defined(_MSC_VER) && (_MSC_VER == 1900)
+# define MSVC_VOLATILE volatile
+#else
+# define MSVC_VOLATILE
+#endif
+
+/* Paper used: Importance Sampling Microfacet-Based BSDFs with the
+ * Distribution of Visible Normals. Supplemental Material 2/2.
+ *
+ * http://hal.inria.fr/docs/01/00/66/20/ANNEX/supplemental2.pdf
+ */
+static void beckmann_table_rows(float *table, int row_from, int row_to)
+{
+ /* allocate temporary data */
+ const int DATA_TMP_SIZE = 512;
+ vector<double> slope_x(DATA_TMP_SIZE);
+ vector<double> CDF_P22_omega_i(DATA_TMP_SIZE);
+
+ /* loop over incident directions */
+ for (int index_theta = row_from; index_theta < row_to; index_theta++) {
+ /* incident vector */
+ const float cos_theta = index_theta / (BECKMANN_TABLE_SIZE - 1.0f);
+ const float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta);
+
+ /* for a given incident vector
+ * integrate P22_{omega_i}(x_slope, 1, 1), Eq. (10) */
+ slope_x[0] = (double)-beckmann_table_slope_max();
+ CDF_P22_omega_i[0] = 0;
+
+ for (MSVC_VOLATILE int index_slope_x = 1; index_slope_x < DATA_TMP_SIZE; ++index_slope_x) {
+ /* slope_x */
+ slope_x[index_slope_x] = (double)(-beckmann_table_slope_max() +
+ 2.0f * beckmann_table_slope_max() * index_slope_x /
+ (DATA_TMP_SIZE - 1.0f));
+
+ /* dot product with incident vector */
+ float dot_product = fmaxf(0.0f, -(float)slope_x[index_slope_x] * sin_theta + cos_theta);
+ /* marginalize P22_{omega_i}(x_slope, 1, 1), Eq. (10) */
+ float P22_omega_i = 0.0f;
+
+ for (int j = 0; j < 100; ++j) {
+ float slope_y = -beckmann_table_slope_max() +
+ 2.0f * beckmann_table_slope_max() * j * (1.0f / 99.0f);
+ P22_omega_i += dot_product * beckmann_table_P22((float)slope_x[index_slope_x], slope_y);
+ }
+
+ /* CDF of P22_{omega_i}(x_slope, 1, 1), Eq. (10) */
+ CDF_P22_omega_i[index_slope_x] = CDF_P22_omega_i[index_slope_x - 1] + (double)P22_omega_i;
+ }
+
+ /* renormalize CDF_P22_omega_i */
+ for (int index_slope_x = 1; index_slope_x < DATA_TMP_SIZE; ++index_slope_x)
+ CDF_P22_omega_i[index_slope_x] /= CDF_P22_omega_i[DATA_TMP_SIZE - 1];
+
+ /* loop over random number U1 */
+ int index_slope_x = 0;
+
+ for (int index_U = 0; index_U < BECKMANN_TABLE_SIZE; ++index_U) {
+ const double U = 0.0000001 + 0.9999998 * index_U / (double)(BECKMANN_TABLE_SIZE - 1);
+
+ /* inverse CDF_P22_omega_i, solve Eq.(11) */
+ while (CDF_P22_omega_i[index_slope_x] <= U)
+ ++index_slope_x;
+
+ const double interp = (CDF_P22_omega_i[index_slope_x] - U) /
+ (CDF_P22_omega_i[index_slope_x] - CDF_P22_omega_i[index_slope_x - 1]);
+
+ /* store value */
+ table[index_U + index_theta * BECKMANN_TABLE_SIZE] =
+ (float)(interp * slope_x[index_slope_x - 1] + (1.0 - interp) * slope_x[index_slope_x]);
+ }
+ }
+}
+
+#undef MSVC_VOLATILE
+
+static void beckmann_table_build(vector<float> &table)
+{
+ table.resize(BECKMANN_TABLE_SIZE * BECKMANN_TABLE_SIZE);
+
+ /* multithreaded build */
+ TaskPool pool;
+
+ for (int i = 0; i < BECKMANN_TABLE_SIZE; i += 8)
+ pool.push(function_bind(&beckmann_table_rows, &table[0], i, i + 8));
+
+ pool.wait_work();
+}
+
+/* Shader */
+
+NODE_DEFINE(Shader)
+{
+ NodeType *type = NodeType::add("shader", create);
+
+ SOCKET_BOOLEAN(use_mis, "Use MIS", true);
+ SOCKET_BOOLEAN(use_transparent_shadow, "Use Transparent Shadow", true);
+ SOCKET_BOOLEAN(heterogeneous_volume, "Heterogeneous Volume", true);
+
+ static NodeEnum volume_sampling_method_enum;
+ volume_sampling_method_enum.insert("distance", VOLUME_SAMPLING_DISTANCE);
+ volume_sampling_method_enum.insert("equiangular", VOLUME_SAMPLING_EQUIANGULAR);
+ volume_sampling_method_enum.insert("multiple_importance", VOLUME_SAMPLING_MULTIPLE_IMPORTANCE);
+ SOCKET_ENUM(volume_sampling_method,
+ "Volume Sampling Method",
+ volume_sampling_method_enum,
+ VOLUME_SAMPLING_MULTIPLE_IMPORTANCE);
+
+ static NodeEnum volume_interpolation_method_enum;
+ volume_interpolation_method_enum.insert("linear", VOLUME_INTERPOLATION_LINEAR);
+ volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC);
+ SOCKET_ENUM(volume_interpolation_method,
+ "Volume Interpolation Method",
+ volume_interpolation_method_enum,
+ VOLUME_INTERPOLATION_LINEAR);
+
+ SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
+
+ static NodeEnum displacement_method_enum;
+ displacement_method_enum.insert("bump", DISPLACE_BUMP);
+ displacement_method_enum.insert("true", DISPLACE_TRUE);
+ displacement_method_enum.insert("both", DISPLACE_BOTH);
+ SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
+
+ SOCKET_INT(pass_id, "Pass ID", 0);
+
+ return type;
+}
+
+Shader::Shader() : Node(get_node_type())
+{
+ pass_id = 0;
+
+ graph = NULL;
+
+ has_surface = false;
+ has_surface_transparent = false;
+ has_surface_emission = false;
+ has_surface_raytrace = false;
+ has_surface_bssrdf = false;
+ has_volume = false;
+ has_displacement = false;
+ has_bump = false;
+ has_bssrdf_bump = false;
+ has_surface_spatial_varying = false;
+ has_volume_spatial_varying = false;
+ has_volume_attribute_dependency = false;
+ has_integrator_dependency = false;
+ has_volume_connected = false;
+ prev_volume_step_rate = 0.0f;
+
+ displacement_method = DISPLACE_BUMP;
+
+ id = -1;
+
+ need_update_uvs = true;
+ need_update_attribute = true;
+ need_update_displacement = true;
+}
+
+Shader::~Shader()
+{
+ delete graph;
+}
+
+bool Shader::is_constant_emission(float3 *emission)
+{
+ /* If the shader has AOVs, they need to be evaluated, so we can't skip the shader. */
+ foreach (ShaderNode *node, graph->nodes) {
+ if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
+ return false;
+ }
+ }
+
+ ShaderInput *surf = graph->output()->input("Surface");
+
+ if (surf->link == NULL) {
+ return false;
+ }
+
+ if (surf->link->parent->type == EmissionNode::get_node_type()) {
+ EmissionNode *node = (EmissionNode *)surf->link->parent;
+
+ assert(node->input("Color"));
+ assert(node->input("Strength"));
+
+ if (node->input("Color")->link || node->input("Strength")->link) {
+ return false;
+ }
+
+ *emission = node->get_color() * node->get_strength();
+ }
+ else if (surf->link->parent->type == BackgroundNode::get_node_type()) {
+ BackgroundNode *node = (BackgroundNode *)surf->link->parent;
+
+ assert(node->input("Color"));
+ assert(node->input("Strength"));
+
+ if (node->input("Color")->link || node->input("Strength")->link) {
+ return false;
+ }
+
+ *emission = node->get_color() * node->get_strength();
+ }
+ else {
+ return false;
+ }
+
+ return true;
+}
+
+void Shader::set_graph(ShaderGraph *graph_)
+{
+ /* do this here already so that we can detect if mesh or object attributes
+ * are needed, since the node attribute callbacks check if their sockets
+ * are connected but proxy nodes should not count */
+ if (graph_) {
+ graph_->remove_proxy_nodes();
+
+ if (displacement_method != DISPLACE_BUMP) {
+ graph_->compute_displacement_hash();
+ }
+ }
+
+ /* update geometry if displacement changed */
+ if (displacement_method != DISPLACE_BUMP) {
+ const char *old_hash = (graph) ? graph->displacement_hash.c_str() : "";
+ const char *new_hash = (graph_) ? graph_->displacement_hash.c_str() : "";
+
+ if (strcmp(old_hash, new_hash) != 0) {
+ need_update_displacement = true;
+ }
+ }
+
+ /* assign graph */
+ delete graph;
+ graph = graph_;
+
+ /* Store info here before graph optimization to make sure that
+ * nodes that get optimized away still count. */
+ has_volume_connected = (graph->output()->input("Volume")->link != NULL);
+}
+
+void Shader::tag_update(Scene *scene)
+{
+ /* update tag */
+ tag_modified();
+
+ scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
+
+ /* if the shader previously was emissive, update light distribution,
+ * if the new shader is emissive, a light manager update tag will be
+ * done in the shader manager device update. */
+ if (use_mis && has_surface_emission)
+ scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
+
+ /* Special handle of background MIS light for now: for some reason it
+ * has use_mis set to false. We are quite close to release now, so
+ * better to be safe.
+ */
+ if (this == scene->background->get_shader(scene)) {
+ scene->light_manager->need_update_background = true;
+ if (scene->light_manager->has_background_light(scene)) {
+ scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
+ }
+ }
+
+ /* quick detection of which kind of shaders we have to avoid loading
+ * e.g. surface attributes when there is only a volume shader. this could
+ * be more fine grained but it's better than nothing */
+ OutputNode *output = graph->output();
+ bool prev_has_volume = has_volume;
+ has_surface = has_surface || output->input("Surface")->link;
+ has_volume = has_volume || output->input("Volume")->link;
+ has_displacement = has_displacement || output->input("Displacement")->link;
+
+ /* get requested attributes. this could be optimized by pruning unused
+ * nodes here already, but that's the job of the shader manager currently,
+ * and may not be so great for interactive rendering where you temporarily
+ * disconnect a node */
+
+ AttributeRequestSet prev_attributes = attributes;
+
+ attributes.clear();
+ foreach (ShaderNode *node, graph->nodes)
+ node->attributes(this, &attributes);
+
+ if (has_displacement) {
+ if (displacement_method == DISPLACE_BOTH) {
+ attributes.add(ATTR_STD_POSITION_UNDISPLACED);
+ }
+ if (displacement_method_is_modified()) {
+ need_update_displacement = true;
+ scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_DISPLACEMENT_MODIFIED);
+ scene->object_manager->need_flags_update = true;
+ }
+ }
+
+ /* compare if the attributes changed, mesh manager will check
+ * need_update_attribute, update the relevant meshes and clear it. */
+ if (attributes.modified(prev_attributes)) {
+ need_update_attribute = true;
+ scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_ATTRIBUTE_MODIFIED);
+ scene->procedural_manager->tag_update();
+ }
+
+ if (has_volume != prev_has_volume || volume_step_rate != prev_volume_step_rate) {
+ scene->geometry_manager->need_flags_update = true;
+ scene->object_manager->need_flags_update = true;
+ prev_volume_step_rate = volume_step_rate;
+ }
+}
+
+void Shader::tag_used(Scene *scene)
+{
+ /* if an unused shader suddenly gets used somewhere, it needs to be
+ * recompiled because it was skipped for compilation before */
+ if (!reference_count()) {
+ tag_modified();
+ /* We do not reference here as the shader will be referenced when added to a socket. */
+ scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
+ }
+}
+
+bool Shader::need_update_geometry() const
+{
+ return need_update_uvs || need_update_attribute || need_update_displacement;
+}
+
+/* Shader Manager */
+
+ShaderManager::ShaderManager()
+{
+ update_flags = UPDATE_ALL;
+ beckmann_table_offset = TABLE_OFFSET_INVALID;
+
+ init_xyz_transforms();
+}
+
+ShaderManager::~ShaderManager()
+{
+}
+
+ShaderManager *ShaderManager::create(int shadingsystem)
+{
+ ShaderManager *manager;
+
+ (void)shadingsystem; /* Ignored when built without OSL. */
+
+#ifdef WITH_OSL
+ if (shadingsystem == SHADINGSYSTEM_OSL) {
+ manager = new OSLShaderManager();
+ }
+ else
+#endif
+ {
+ manager = new SVMShaderManager();
+ }
+
+ return manager;
+}
+
+uint ShaderManager::get_attribute_id(ustring name)
+{
+ thread_scoped_spin_lock lock(attribute_lock_);
+
+ /* get a unique id for each name, for SVM attribute lookup */
+ AttributeIDMap::iterator it = unique_attribute_id.find(name);
+
+ if (it != unique_attribute_id.end())
+ return it->second;
+
+ uint id = (uint)ATTR_STD_NUM + unique_attribute_id.size();
+ unique_attribute_id[name] = id;
+ return id;
+}
+
+uint ShaderManager::get_attribute_id(AttributeStandard std)
+{
+ return (uint)std;
+}
+
+int ShaderManager::get_shader_id(Shader *shader, bool smooth)
+{
+ /* get a shader id to pass to the kernel */
+ int id = shader->id;
+
+ /* smooth flag */
+ if (smooth)
+ id |= SHADER_SMOOTH_NORMAL;
+
+ /* default flags */
+ id |= SHADER_CAST_SHADOW | SHADER_AREA_LIGHT;
+
+ return id;
+}
+
+void ShaderManager::device_update(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ if (!need_update()) {
+ return;
+ }
+
+ uint id = 0;
+ foreach (Shader *shader, scene->shaders) {
+ shader->id = id++;
+ }
+
+ /* Those shaders should always be compiled as they are used as fallback if a shader cannot be
+ * found, e.g. bad shader index for the triangle shaders on a Mesh. */
+ assert(scene->default_surface->reference_count() != 0);
+ assert(scene->default_light->reference_count() != 0);
+ assert(scene->default_background->reference_count() != 0);
+ assert(scene->default_empty->reference_count() != 0);
+
+ device_update_specific(device, dscene, scene, progress);
+}
+
+void ShaderManager::device_update_common(Device * /*device*/,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress & /*progress*/)
+{
+ dscene->shaders.free();
+
+ if (scene->shaders.size() == 0)
+ return;
+
+ KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size());
+ bool has_volumes = false;
+ bool has_transparent_shadow = false;
+
+ foreach (Shader *shader, scene->shaders) {
+ uint flag = 0;
+
+ if (shader->get_use_mis())
+ flag |= SD_USE_MIS;
+ if (shader->has_surface_emission)
+ flag |= SD_HAS_EMISSION;
+ if (shader->has_surface_transparent && shader->get_use_transparent_shadow())
+ flag |= SD_HAS_TRANSPARENT_SHADOW;
+ if (shader->has_surface_raytrace)
+ flag |= SD_HAS_RAYTRACE;
+ if (shader->has_volume) {
+ flag |= SD_HAS_VOLUME;
+ has_volumes = true;
+
+ /* todo: this could check more fine grained, to skip useless volumes
+ * enclosed inside an opaque bsdf.
+ */
+ flag |= SD_HAS_TRANSPARENT_SHADOW;
+ }
+ /* in this case we can assume transparent surface */
+ if (shader->has_volume_connected && !shader->has_surface)
+ flag |= SD_HAS_ONLY_VOLUME;
+ if (shader->has_volume) {
+ if (shader->get_heterogeneous_volume() && shader->has_volume_spatial_varying)
+ flag |= SD_HETEROGENEOUS_VOLUME;
+ }
+ if (shader->has_volume_attribute_dependency)
+ flag |= SD_NEED_VOLUME_ATTRIBUTES;
+ if (shader->has_bssrdf_bump)
+ flag |= SD_HAS_BSSRDF_BUMP;
+ if (shader->get_volume_sampling_method() == VOLUME_SAMPLING_EQUIANGULAR)
+ flag |= SD_VOLUME_EQUIANGULAR;
+ if (shader->get_volume_sampling_method() == VOLUME_SAMPLING_MULTIPLE_IMPORTANCE)
+ flag |= SD_VOLUME_MIS;
+ if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC)
+ flag |= SD_VOLUME_CUBIC;
+ if (shader->has_bump)
+ flag |= SD_HAS_BUMP;
+ if (shader->get_displacement_method() != DISPLACE_BUMP)
+ flag |= SD_HAS_DISPLACEMENT;
+
+ /* constant emission check */
+ float3 constant_emission = zero_float3();
+ if (shader->is_constant_emission(&constant_emission))
+ flag |= SD_HAS_CONSTANT_EMISSION;
+
+ uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0);
+
+ /* regular shader */
+ kshader->flags = flag;
+ kshader->pass_id = shader->get_pass_id();
+ kshader->constant_emission[0] = constant_emission.x;
+ kshader->constant_emission[1] = constant_emission.y;
+ kshader->constant_emission[2] = constant_emission.z;
+ kshader->cryptomatte_id = util_hash_to_float(cryptomatte_id);
+ kshader++;
+
+ has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
+ }
+
+ dscene->shaders.copy_to_device();
+
+ /* lookup tables */
+ KernelTables *ktables = &dscene->data.tables;
+
+ /* beckmann lookup table */
+ if (beckmann_table_offset == TABLE_OFFSET_INVALID) {
+ if (!beckmann_table_ready) {
+ thread_scoped_lock lock(lookup_table_mutex);
+ if (!beckmann_table_ready) {
+ beckmann_table_build(beckmann_table);
+ beckmann_table_ready = true;
+ }
+ }
+ beckmann_table_offset = scene->lookup_tables->add_table(dscene, beckmann_table);
+ }
+ ktables->beckmann_offset = (int)beckmann_table_offset;
+
+ /* integrator */
+ KernelIntegrator *kintegrator = &dscene->data.integrator;
+ kintegrator->use_volumes = has_volumes;
+ /* TODO(sergey): De-duplicate with flags set in integrator.cpp. */
+ kintegrator->transparent_shadows = has_transparent_shadow;
+
+ /* film */
+ KernelFilm *kfilm = &dscene->data.film;
+ /* color space, needs to be here because e.g. displacement shaders could depend on it */
+ kfilm->xyz_to_r = float3_to_float4(xyz_to_r);
+ kfilm->xyz_to_g = float3_to_float4(xyz_to_g);
+ kfilm->xyz_to_b = float3_to_float4(xyz_to_b);
+ kfilm->rgb_to_y = float3_to_float4(rgb_to_y);
+}
+
+void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *scene)
+{
+ scene->lookup_tables->remove_table(&beckmann_table_offset);
+
+ dscene->shaders.free();
+}
+
+void ShaderManager::add_default(Scene *scene)
+{
+ /* default surface */
+ {
+ ShaderGraph *graph = new ShaderGraph();
+
+ DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
+ diffuse->set_color(make_float3(0.8f, 0.8f, 0.8f));
+ graph->add(diffuse);
+
+ graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface"));
+
+ Shader *shader = scene->create_node<Shader>();
+ shader->name = "default_surface";
+ shader->set_graph(graph);
+ shader->reference();
+ scene->default_surface = shader;
+ shader->tag_update(scene);
+ }
+
+ /* default volume */
+ {
+ ShaderGraph *graph = new ShaderGraph();
+
+ PrincipledVolumeNode *principled = graph->create_node<PrincipledVolumeNode>();
+ graph->add(principled);
+
+ graph->connect(principled->output("Volume"), graph->output()->input("Volume"));
+
+ Shader *shader = scene->create_node<Shader>();
+ shader->name = "default_volume";
+ shader->set_graph(graph);
+ scene->default_volume = shader;
+ shader->tag_update(scene);
+ /* No default reference for the volume to avoid compiling volume kernels if there are no actual
+ * volumes in the scene */
+ }
+
+ /* default light */
+ {
+ ShaderGraph *graph = new ShaderGraph();
+
+ EmissionNode *emission = graph->create_node<EmissionNode>();
+ emission->set_color(make_float3(0.8f, 0.8f, 0.8f));
+ emission->set_strength(0.0f);
+ graph->add(emission);
+
+ graph->connect(emission->output("Emission"), graph->output()->input("Surface"));
+
+ Shader *shader = scene->create_node<Shader>();
+ shader->name = "default_light";
+ shader->set_graph(graph);
+ shader->reference();
+ scene->default_light = shader;
+ shader->tag_update(scene);
+ }
+
+ /* default background */
+ {
+ ShaderGraph *graph = new ShaderGraph();
+
+ Shader *shader = scene->create_node<Shader>();
+ shader->name = "default_background";
+ shader->set_graph(graph);
+ shader->reference();
+ scene->default_background = shader;
+ shader->tag_update(scene);
+ }
+
+ /* default empty */
+ {
+ ShaderGraph *graph = new ShaderGraph();
+
+ Shader *shader = scene->create_node<Shader>();
+ shader->name = "default_empty";
+ shader->set_graph(graph);
+ shader->reference();
+ scene->default_empty = shader;
+ shader->tag_update(scene);
+ }
+}
+
+uint ShaderManager::get_graph_kernel_features(ShaderGraph *graph)
+{
+ uint kernel_features = 0;
+
+ foreach (ShaderNode *node, graph->nodes) {
+ kernel_features |= node->get_feature();
+ if (node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) {
+ BsdfBaseNode *bsdf_node = static_cast<BsdfBaseNode *>(node);
+ if (CLOSURE_IS_VOLUME(bsdf_node->get_closure_type())) {
+ kernel_features |= KERNEL_FEATURE_NODE_VOLUME;
+ }
+ else if (CLOSURE_IS_PRINCIPLED(bsdf_node->get_closure_type())) {
+ kernel_features |= KERNEL_FEATURE_PRINCIPLED;
+ }
+ }
+ if (node->has_surface_bssrdf()) {
+ kernel_features |= KERNEL_FEATURE_SUBSURFACE;
+ }
+ if (node->has_surface_transparent()) {
+ kernel_features |= KERNEL_FEATURE_TRANSPARENT;
+ }
+ }
+
+ return kernel_features;
+}
+
+uint ShaderManager::get_kernel_features(Scene *scene)
+{
+ uint kernel_features = KERNEL_FEATURE_NODE_BSDF | KERNEL_FEATURE_NODE_EMISSION;
+ for (int i = 0; i < scene->shaders.size(); i++) {
+ Shader *shader = scene->shaders[i];
+ if (!shader->reference_count()) {
+ continue;
+ }
+
+ /* Gather requested features from all the nodes from the graph nodes. */
+ kernel_features |= get_graph_kernel_features(shader->graph);
+ ShaderNode *output_node = shader->graph->output();
+ if (output_node->input("Displacement")->link != NULL) {
+ kernel_features |= KERNEL_FEATURE_NODE_BUMP;
+ if (shader->get_displacement_method() == DISPLACE_BOTH) {
+ kernel_features |= KERNEL_FEATURE_NODE_BUMP_STATE;
+ }
+ }
+ /* On top of volume nodes, also check if we need volume sampling because
+ * e.g. an Emission node would slip through the KERNEL_FEATURE_NODE_VOLUME check */
+ if (shader->has_volume_connected) {
+ kernel_features |= KERNEL_FEATURE_VOLUME;
+ }
+ }
+
+ return kernel_features;
+}
+
+void ShaderManager::free_memory()
+{
+ beckmann_table.free_memory();
+
+#ifdef WITH_OSL
+ OSLShaderManager::free_memory();
+#endif
+
+ ColorSpaceManager::free_memory();
+}
+
+float ShaderManager::linear_rgb_to_gray(float3 c)
+{
+ return dot(c, rgb_to_y);
+}
+
+string ShaderManager::get_cryptomatte_materials(Scene *scene)
+{
+ string manifest = "{";
+ unordered_set<ustring, ustringHash> materials;
+ foreach (Shader *shader, scene->shaders) {
+ if (materials.count(shader->name)) {
+ continue;
+ }
+ materials.insert(shader->name);
+ uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0);
+ manifest += string_printf("\"%s\":\"%08x\",", shader->name.c_str(), cryptomatte_id);
+ }
+ manifest[manifest.size() - 1] = '}';
+ return manifest;
+}
+
+void ShaderManager::tag_update(Scene * /*scene*/, uint32_t /*flag*/)
+{
+ /* update everything for now */
+ update_flags = ShaderManager::UPDATE_ALL;
+}
+
+bool ShaderManager::need_update() const
+{
+ return update_flags != UPDATE_NONE;
+}
+
+#ifdef WITH_OCIO
+static bool to_scene_linear_transform(OCIO::ConstConfigRcPtr &config,
+ const char *colorspace,
+ Transform &to_scene_linear)
+{
+ OCIO::ConstProcessorRcPtr processor;
+ try {
+ processor = config->getProcessor(OCIO::ROLE_SCENE_LINEAR, colorspace);
+ }
+ catch (OCIO::Exception &) {
+ return false;
+ }
+
+ if (!processor) {
+ return false;
+ }
+
+ OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
+ if (!device_processor) {
+ return false;
+ }
+
+ to_scene_linear = transform_identity();
+ device_processor->applyRGB(&to_scene_linear.x.x);
+ device_processor->applyRGB(&to_scene_linear.y.x);
+ device_processor->applyRGB(&to_scene_linear.z.x);
+ to_scene_linear = transform_transposed_inverse(to_scene_linear);
+ return true;
+}
+#endif
+
+void ShaderManager::init_xyz_transforms()
+{
+ /* Default to ITU-BT.709 in case no appropriate transform found.
+ * Note XYZ here is defined as having a D65 white point. */
+ xyz_to_r = make_float3(3.2404542f, -1.5371385f, -0.4985314f);
+ xyz_to_g = make_float3(-0.9692660f, 1.8760108f, 0.0415560f);
+ xyz_to_b = make_float3(0.0556434f, -0.2040259f, 1.0572252f);
+ rgb_to_y = make_float3(0.2126729f, 0.7151522f, 0.0721750f);
+
+#ifdef WITH_OCIO
+ /* Get from OpenColorO config if it has the required roles. */
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ if (!(config && config->hasRole(OCIO::ROLE_SCENE_LINEAR))) {
+ return;
+ }
+
+ Transform xyz_to_rgb;
+
+ if (config->hasRole("aces_interchange")) {
+ /* Standard OpenColorIO role, defined as ACES2065-1. */
+ const Transform xyz_E_to_aces = make_transform(1.0498110175f,
+ 0.0f,
+ -0.0000974845f,
+ 0.0f,
+ -0.4959030231f,
+ 1.3733130458f,
+ 0.0982400361f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.9912520182f,
+ 0.0f);
+ const Transform xyz_D65_to_E = make_transform(
+ 1.0521111f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.9184170f, 0.0f);
+
+ Transform aces_to_rgb;
+ if (!to_scene_linear_transform(config, "aces_interchange", aces_to_rgb)) {
+ return;
+ }
+
+ xyz_to_rgb = aces_to_rgb * xyz_E_to_aces * xyz_D65_to_E;
+ }
+ else if (config->hasRole("XYZ")) {
+ /* Custom role used before the standard existed. */
+ if (!to_scene_linear_transform(config, "XYZ", xyz_to_rgb)) {
+ return;
+ }
+ }
+ else {
+ /* No reference role found to determine XYZ. */
+ return;
+ }
+
+ xyz_to_r = float4_to_float3(xyz_to_rgb.x);
+ xyz_to_g = float4_to_float3(xyz_to_rgb.y);
+ xyz_to_b = float4_to_float3(xyz_to_rgb.z);
+
+ const Transform rgb_to_xyz = transform_inverse(xyz_to_rgb);
+ rgb_to_y = float4_to_float3(rgb_to_xyz.y);
+#endif
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/shader.h b/intern/cycles/scene/shader.h
new file mode 100644
index 00000000000..e9d26412ae8
--- /dev/null
+++ b/intern/cycles/scene/shader.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SHADER_H__
+#define __SHADER_H__
+
+#ifdef WITH_OSL
+/* So no context pollution happens from indirectly included windows.h */
+# include "util/windows.h"
+# include <OSL/oslexec.h>
+#endif
+
+#include "kernel/types.h"
+#include "scene/attribute.h"
+
+#include "graph/node.h"
+
+#include "util/map.h"
+#include "util/param.h"
+#include "util/string.h"
+#include "util/thread.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Mesh;
+class Progress;
+class Scene;
+class ShaderGraph;
+struct float3;
+
+enum ShadingSystem { SHADINGSYSTEM_OSL, SHADINGSYSTEM_SVM };
+
+/* Keep those in sync with the python-defined enum. */
+enum VolumeSampling {
+ VOLUME_SAMPLING_DISTANCE = 0,
+ VOLUME_SAMPLING_EQUIANGULAR = 1,
+ VOLUME_SAMPLING_MULTIPLE_IMPORTANCE = 2,
+
+ VOLUME_NUM_SAMPLING,
+};
+
+enum VolumeInterpolation {
+ VOLUME_INTERPOLATION_LINEAR = 0,
+ VOLUME_INTERPOLATION_CUBIC = 1,
+
+ VOLUME_NUM_INTERPOLATION,
+};
+
+enum DisplacementMethod {
+ DISPLACE_BUMP = 0,
+ DISPLACE_TRUE = 1,
+ DISPLACE_BOTH = 2,
+
+ DISPLACE_NUM_METHODS,
+};
+
+/* Shader describing the appearance of a Mesh, Light or Background.
+ *
+ * While there is only a single shader graph, it has three outputs: surface,
+ * volume and displacement, that the shader manager will compile and execute
+ * separately. */
+
+class Shader : public Node {
+ public:
+ NODE_DECLARE
+
+ /* shader graph */
+ ShaderGraph *graph;
+
+ NODE_SOCKET_API(int, pass_id)
+
+ /* sampling */
+ NODE_SOCKET_API(bool, use_mis)
+ NODE_SOCKET_API(bool, use_transparent_shadow)
+ NODE_SOCKET_API(bool, heterogeneous_volume)
+ NODE_SOCKET_API(VolumeSampling, volume_sampling_method)
+ NODE_SOCKET_API(int, volume_interpolation_method)
+ NODE_SOCKET_API(float, volume_step_rate)
+
+ /* displacement */
+ NODE_SOCKET_API(DisplacementMethod, displacement_method)
+
+ float prev_volume_step_rate;
+
+ /* synchronization */
+ bool need_update_uvs;
+ bool need_update_attribute;
+ bool need_update_displacement;
+
+ /* If the shader has only volume components, the surface is assumed to
+ * be transparent.
+ * However, graph optimization might remove the volume subgraph, but
+ * since the user connected something to the volume output the surface
+ * should still be transparent.
+ * Therefore, has_volume_connected stores whether some volume sub-tree
+ * was connected before optimization. */
+ bool has_volume_connected;
+
+ /* information about shader after compiling */
+ bool has_surface;
+ bool has_surface_emission;
+ bool has_surface_transparent;
+ bool has_surface_raytrace;
+ bool has_volume;
+ bool has_displacement;
+ bool has_surface_bssrdf;
+ bool has_bump;
+ bool has_bssrdf_bump;
+ bool has_surface_spatial_varying;
+ bool has_volume_spatial_varying;
+ bool has_volume_attribute_dependency;
+ bool has_integrator_dependency;
+
+ /* requested mesh attributes */
+ AttributeRequestSet attributes;
+
+ /* determined before compiling */
+ uint id;
+
+#ifdef WITH_OSL
+ /* osl shading state references */
+ OSL::ShaderGroupRef osl_surface_ref;
+ OSL::ShaderGroupRef osl_surface_bump_ref;
+ OSL::ShaderGroupRef osl_volume_ref;
+ OSL::ShaderGroupRef osl_displacement_ref;
+#endif
+
+ Shader();
+ ~Shader();
+
+ /* Checks whether the shader consists of just a emission node with fixed inputs that's connected
+ * directly to the output.
+ * If yes, it sets the content of emission to the constant value (color * strength), which is
+ * then used for speeding up light evaluation. */
+ bool is_constant_emission(float3 *emission);
+
+ void set_graph(ShaderGraph *graph);
+ void tag_update(Scene *scene);
+ void tag_used(Scene *scene);
+
+ /* Return true when either of the surface or displacement socket of the output node is linked.
+ * This should be used to ensure that surface attributes are also requested even when only the
+ * displacement socket is linked. */
+ bool has_surface_link() const
+ {
+ return has_surface || has_displacement;
+ }
+
+ bool need_update_geometry() const;
+};
+
+/* Shader Manager virtual base class
+ *
+ * From this the SVM and OSL shader managers are derived, that do the actual
+ * shader compiling and device updating. */
+
+class ShaderManager {
+ public:
+ enum : uint32_t {
+ SHADER_ADDED = (1 << 0),
+ SHADER_MODIFIED = (1 << 2),
+ INTEGRATOR_MODIFIED = (1 << 3),
+
+ /* tag everything in the manager for an update */
+ UPDATE_ALL = ~0u,
+
+ UPDATE_NONE = 0u,
+ };
+
+ static ShaderManager *create(int shadingsystem);
+ virtual ~ShaderManager();
+
+ virtual void reset(Scene *scene) = 0;
+
+ virtual bool use_osl()
+ {
+ return false;
+ }
+
+ /* device update */
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
+ virtual void device_update_specific(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress) = 0;
+ virtual void device_free(Device *device, DeviceScene *dscene, Scene *scene) = 0;
+
+ void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
+ void device_free_common(Device *device, DeviceScene *dscene, Scene *scene);
+
+ /* get globally unique id for a type of attribute */
+ uint get_attribute_id(ustring name);
+ uint get_attribute_id(AttributeStandard std);
+
+ /* get shader id for mesh faces */
+ int get_shader_id(Shader *shader, bool smooth = false);
+
+ /* add default shaders to scene, to use as default for things that don't
+ * have any shader assigned explicitly */
+ static void add_default(Scene *scene);
+
+ /* Selective nodes compilation. */
+ uint get_kernel_features(Scene *scene);
+
+ static void free_memory();
+
+ float linear_rgb_to_gray(float3 c);
+
+ string get_cryptomatte_materials(Scene *scene);
+
+ void tag_update(Scene *scene, uint32_t flag);
+
+ bool need_update() const;
+
+ void init_xyz_transforms();
+
+ protected:
+ ShaderManager();
+
+ uint32_t update_flags;
+
+ typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap;
+ AttributeIDMap unique_attribute_id;
+
+ static thread_mutex lookup_table_mutex;
+ static vector<float> beckmann_table;
+ static bool beckmann_table_ready;
+
+ size_t beckmann_table_offset;
+
+ uint get_graph_kernel_features(ShaderGraph *graph);
+
+ thread_spin_lock attribute_lock_;
+
+ float3 xyz_to_r;
+ float3 xyz_to_g;
+ float3 xyz_to_b;
+ float3 rgb_to_y;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __SHADER_H__ */
diff --git a/intern/cycles/scene/shader_graph.cpp b/intern/cycles/scene/shader_graph.cpp
new file mode 100644
index 00000000000..f99dfa141f6
--- /dev/null
+++ b/intern/cycles/scene/shader_graph.cpp
@@ -0,0 +1,1239 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/shader_graph.h"
+#include "scene/attribute.h"
+#include "scene/constant_fold.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_nodes.h"
+
+#include "util/algorithm.h"
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/md5.h"
+#include "util/queue.h"
+
+CCL_NAMESPACE_BEGIN
+
+namespace {
+
+bool check_node_inputs_has_links(const ShaderNode *node)
+{
+ foreach (const ShaderInput *in, node->inputs) {
+ if (in->link) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool check_node_inputs_traversed(const ShaderNode *node, const ShaderNodeSet &done)
+{
+ foreach (const ShaderInput *in, node->inputs) {
+ if (in->link) {
+ if (done.find(in->link->parent) == done.end()) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+} /* namespace */
+
+/* Sockets */
+
+void ShaderInput::disconnect()
+{
+ if (link) {
+ link->links.erase(remove(link->links.begin(), link->links.end(), this), link->links.end());
+ }
+ link = NULL;
+}
+
+void ShaderOutput::disconnect()
+{
+ foreach (ShaderInput *sock, links) {
+ sock->link = NULL;
+ }
+
+ links.clear();
+}
+
+/* Node */
+
+ShaderNode::ShaderNode(const NodeType *type) : Node(type)
+{
+ name = type->name;
+ id = -1;
+ bump = SHADER_BUMP_NONE;
+ special_type = SHADER_SPECIAL_TYPE_NONE;
+
+ create_inputs_outputs(type);
+}
+
+ShaderNode::~ShaderNode()
+{
+ foreach (ShaderInput *socket, inputs)
+ delete socket;
+
+ foreach (ShaderOutput *socket, outputs)
+ delete socket;
+}
+
+void ShaderNode::create_inputs_outputs(const NodeType *type)
+{
+ foreach (const SocketType &socket, type->inputs) {
+ if (socket.flags & SocketType::LINKABLE) {
+ inputs.push_back(new ShaderInput(socket, this));
+ }
+ }
+
+ foreach (const SocketType &socket, type->outputs) {
+ outputs.push_back(new ShaderOutput(socket, this));
+ }
+}
+
+ShaderInput *ShaderNode::input(const char *name)
+{
+ foreach (ShaderInput *socket, inputs) {
+ if (socket->name() == name)
+ return socket;
+ }
+
+ return NULL;
+}
+
+ShaderOutput *ShaderNode::output(const char *name)
+{
+ foreach (ShaderOutput *socket, outputs)
+ if (socket->name() == name)
+ return socket;
+
+ return NULL;
+}
+
+ShaderInput *ShaderNode::input(ustring name)
+{
+ foreach (ShaderInput *socket, inputs) {
+ if (socket->name() == name)
+ return socket;
+ }
+
+ return NULL;
+}
+
+ShaderOutput *ShaderNode::output(ustring name)
+{
+ foreach (ShaderOutput *socket, outputs)
+ if (socket->name() == name)
+ return socket;
+
+ return NULL;
+}
+
+void ShaderNode::remove_input(ShaderInput *input)
+{
+ assert(input->link == NULL);
+ delete input;
+ inputs.erase(remove(inputs.begin(), inputs.end(), input), inputs.end());
+}
+
+void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ foreach (ShaderInput *input, inputs) {
+ if (!input->link) {
+ if (input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
+ if (shader->has_surface_link())
+ attributes->add(ATTR_STD_GENERATED);
+ if (shader->has_volume)
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+ }
+ else if (input->flags() & SocketType::LINK_TEXTURE_UV) {
+ if (shader->has_surface_link())
+ attributes->add(ATTR_STD_UV);
+ }
+ }
+ }
+}
+
+bool ShaderNode::equals(const ShaderNode &other)
+{
+ if (type != other.type || bump != other.bump) {
+ return false;
+ }
+
+ assert(inputs.size() == other.inputs.size());
+
+ /* Compare unlinkable sockets */
+ foreach (const SocketType &socket, type->inputs) {
+ if (!(socket.flags & SocketType::LINKABLE)) {
+ if (!Node::equals_value(other, socket)) {
+ return false;
+ }
+ }
+ }
+
+ /* Compare linkable input sockets */
+ for (int i = 0; i < inputs.size(); ++i) {
+ ShaderInput *input_a = inputs[i], *input_b = other.inputs[i];
+ if (input_a->link == NULL && input_b->link == NULL) {
+ /* Unconnected inputs are expected to have the same value. */
+ if (!Node::equals_value(other, input_a->socket_type)) {
+ return false;
+ }
+ }
+ else if (input_a->link != NULL && input_b->link != NULL) {
+ /* Expect links are to come from the same exact socket. */
+ if (input_a->link != input_b->link) {
+ return false;
+ }
+ }
+ else {
+ /* One socket has a link and another has not, inputs can't be
+ * considered equal.
+ */
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Graph */
+
+ShaderGraph::ShaderGraph()
+{
+ finalized = false;
+ simplified = false;
+ num_node_ids = 0;
+ add(create_node<OutputNode>());
+}
+
+ShaderGraph::~ShaderGraph()
+{
+ clear_nodes();
+}
+
+ShaderNode *ShaderGraph::add(ShaderNode *node)
+{
+ assert(!finalized);
+ simplified = false;
+
+ node->id = num_node_ids++;
+ nodes.push_back(node);
+ return node;
+}
+
+OutputNode *ShaderGraph::output()
+{
+ return (OutputNode *)nodes.front();
+}
+
+void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
+{
+ assert(!finalized);
+ assert(from && to);
+
+ if (to->link) {
+ fprintf(stderr, "Cycles shader graph connect: input already connected.\n");
+ return;
+ }
+
+ if (from->type() != to->type()) {
+ /* can't do automatic conversion from closure */
+ if (from->type() == SocketType::CLOSURE) {
+ fprintf(stderr,
+ "Cycles shader graph connect: can only connect closure to closure "
+ "(%s.%s to %s.%s).\n",
+ from->parent->name.c_str(),
+ from->name().c_str(),
+ to->parent->name.c_str(),
+ to->name().c_str());
+ return;
+ }
+
+ /* add automatic conversion node in case of type mismatch */
+ ShaderNode *convert;
+ ShaderInput *convert_in;
+
+ if (to->type() == SocketType::CLOSURE) {
+ EmissionNode *emission = create_node<EmissionNode>();
+ emission->set_color(one_float3());
+ emission->set_strength(1.0f);
+ convert = add(emission);
+ /* Connect float inputs to Strength to save an additional Value->Color conversion. */
+ if (from->type() == SocketType::FLOAT) {
+ convert_in = convert->input("Strength");
+ }
+ else {
+ convert_in = convert->input("Color");
+ }
+ }
+ else {
+ convert = add(create_node<ConvertNode>(from->type(), to->type(), true));
+ convert_in = convert->inputs[0];
+ }
+
+ connect(from, convert_in);
+ connect(convert->outputs[0], to);
+ }
+ else {
+ /* types match, just connect */
+ to->link = from;
+ from->links.push_back(to);
+ }
+}
+
+void ShaderGraph::disconnect(ShaderOutput *from)
+{
+ assert(!finalized);
+ simplified = false;
+
+ from->disconnect();
+}
+
+void ShaderGraph::disconnect(ShaderInput *to)
+{
+ assert(!finalized);
+ assert(to->link);
+ simplified = false;
+
+ to->disconnect();
+}
+
+void ShaderGraph::relink(ShaderInput *from, ShaderInput *to)
+{
+ ShaderOutput *out = from->link;
+ if (out) {
+ disconnect(from);
+ connect(out, to);
+ }
+ to->parent->copy_value(to->socket_type, *(from->parent), from->socket_type);
+}
+
+void ShaderGraph::relink(ShaderOutput *from, ShaderOutput *to)
+{
+ /* Copy because disconnect modifies this list. */
+ vector<ShaderInput *> outputs = from->links;
+
+ foreach (ShaderInput *sock, outputs) {
+ disconnect(sock);
+ if (to)
+ connect(to, sock);
+ }
+}
+
+void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to)
+{
+ simplified = false;
+
+ /* Copy because disconnect modifies this list */
+ vector<ShaderInput *> outputs = from->links;
+
+ /* Bypass node by moving all links from "from" to "to" */
+ foreach (ShaderInput *sock, node->inputs) {
+ if (sock->link)
+ disconnect(sock);
+ }
+
+ foreach (ShaderInput *sock, outputs) {
+ disconnect(sock);
+ if (to)
+ connect(to, sock);
+ }
+}
+
+void ShaderGraph::simplify(Scene *scene)
+{
+ if (!simplified) {
+ expand();
+ default_inputs(scene->shader_manager->use_osl());
+ clean(scene);
+ refine_bump_nodes();
+
+ simplified = true;
+ }
+}
+
+void ShaderGraph::finalize(Scene *scene, bool do_bump, bool do_simplify, bool bump_in_object_space)
+{
+ /* before compiling, the shader graph may undergo a number of modifications.
+ * currently we set default geometry shader inputs, and create automatic bump
+ * from displacement. a graph can be finalized only once, and should not be
+ * modified afterwards. */
+
+ if (!finalized) {
+ simplify(scene);
+
+ if (do_bump)
+ bump_from_displacement(bump_in_object_space);
+
+ ShaderInput *surface_in = output()->input("Surface");
+ ShaderInput *volume_in = output()->input("Volume");
+
+ /* todo: make this work when surface and volume closures are tangled up */
+
+ if (surface_in->link)
+ transform_multi_closure(surface_in->link->parent, NULL, false);
+ if (volume_in->link)
+ transform_multi_closure(volume_in->link->parent, NULL, true);
+
+ finalized = true;
+ }
+ else if (do_simplify) {
+ simplify_settings(scene);
+ }
+}
+
+void ShaderGraph::find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input)
+{
+ /* find all nodes that this input depends on directly and indirectly */
+ ShaderNode *node = (input->link) ? input->link->parent : NULL;
+
+ if (node != NULL && dependencies.find(node) == dependencies.end()) {
+ foreach (ShaderInput *in, node->inputs)
+ find_dependencies(dependencies, in);
+
+ dependencies.insert(node);
+ }
+}
+
+void ShaderGraph::clear_nodes()
+{
+ foreach (ShaderNode *node, nodes) {
+ delete_node(node);
+ }
+ nodes.clear();
+}
+
+void ShaderGraph::copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap)
+{
+ /* copy a set of nodes, and the links between them. the assumption is
+ * made that all nodes that inputs are linked to are in the set too. */
+
+ /* copy nodes */
+ foreach (ShaderNode *node, nodes) {
+ ShaderNode *nnode = node->clone(this);
+ nnodemap[node] = nnode;
+
+ /* create new inputs and outputs to recreate links and ensure
+ * that we still point to valid SocketType if the NodeType
+ * changed in cloning, as it does for OSL nodes */
+ nnode->inputs.clear();
+ nnode->outputs.clear();
+ nnode->create_inputs_outputs(nnode->type);
+ }
+
+ /* recreate links */
+ foreach (ShaderNode *node, nodes) {
+ foreach (ShaderInput *input, node->inputs) {
+ if (input->link) {
+ /* find new input and output */
+ ShaderNode *nfrom = nnodemap[input->link->parent];
+ ShaderNode *nto = nnodemap[input->parent];
+ ShaderOutput *noutput = nfrom->output(input->link->name());
+ ShaderInput *ninput = nto->input(input->name());
+
+ /* connect */
+ connect(noutput, ninput);
+ }
+ }
+ }
+}
+
+/* Graph simplification */
+/* ******************** */
+
+/* Remove proxy nodes.
+ *
+ * These only exists temporarily when exporting groups, and we must remove them
+ * early so that node->attributes() and default links do not see them.
+ */
+void ShaderGraph::remove_proxy_nodes()
+{
+ vector<bool> removed(num_node_ids, false);
+ bool any_node_removed = false;
+
+ foreach (ShaderNode *node, nodes) {
+ if (node->special_type == SHADER_SPECIAL_TYPE_PROXY) {
+ ConvertNode *proxy = static_cast<ConvertNode *>(node);
+ ShaderInput *input = proxy->inputs[0];
+ ShaderOutput *output = proxy->outputs[0];
+
+ /* bypass the proxy node */
+ if (input->link) {
+ relink(proxy, output, input->link);
+ }
+ else {
+ /* Copy because disconnect modifies this list */
+ vector<ShaderInput *> links(output->links);
+
+ foreach (ShaderInput *to, links) {
+ /* Remove any auto-convert nodes too if they lead to
+ * sockets with an automatically set default value. */
+ ShaderNode *tonode = to->parent;
+
+ if (tonode->special_type == SHADER_SPECIAL_TYPE_AUTOCONVERT) {
+ bool all_links_removed = true;
+ vector<ShaderInput *> links = tonode->outputs[0]->links;
+
+ foreach (ShaderInput *autoin, links) {
+ if (autoin->flags() & SocketType::DEFAULT_LINK_MASK)
+ disconnect(autoin);
+ else
+ all_links_removed = false;
+ }
+
+ if (all_links_removed)
+ removed[tonode->id] = true;
+ }
+
+ disconnect(to);
+
+ /* transfer the default input value to the target socket */
+ tonode->copy_value(to->socket_type, *proxy, input->socket_type);
+ }
+ }
+
+ removed[proxy->id] = true;
+ any_node_removed = true;
+ }
+ }
+
+ /* remove nodes */
+ if (any_node_removed) {
+ list<ShaderNode *> newnodes;
+
+ foreach (ShaderNode *node, nodes) {
+ if (!removed[node->id])
+ newnodes.push_back(node);
+ else
+ delete_node(node);
+ }
+
+ nodes = newnodes;
+ }
+}
+
+/* Constant folding.
+ *
+ * Try to constant fold some nodes, and pipe result directly to
+ * the input socket of connected nodes.
+ */
+void ShaderGraph::constant_fold(Scene *scene)
+{
+ ShaderNodeSet done, scheduled;
+ queue<ShaderNode *> traverse_queue;
+
+ bool has_displacement = (output()->input("Displacement")->link != NULL);
+
+ /* Schedule nodes which doesn't have any dependencies. */
+ foreach (ShaderNode *node, nodes) {
+ if (!check_node_inputs_has_links(node)) {
+ traverse_queue.push(node);
+ scheduled.insert(node);
+ }
+ }
+
+ while (!traverse_queue.empty()) {
+ ShaderNode *node = traverse_queue.front();
+ traverse_queue.pop();
+ done.insert(node);
+ foreach (ShaderOutput *output, node->outputs) {
+ if (output->links.size() == 0) {
+ continue;
+ }
+ /* Schedule node which was depending on the value,
+ * when possible. Do it before disconnect.
+ */
+ foreach (ShaderInput *input, output->links) {
+ if (scheduled.find(input->parent) != scheduled.end()) {
+ /* Node might not be optimized yet but scheduled already
+ * by other dependencies. No need to re-schedule it.
+ */
+ continue;
+ }
+ /* Schedule node if its inputs are fully done. */
+ if (check_node_inputs_traversed(input->parent, done)) {
+ traverse_queue.push(input->parent);
+ scheduled.insert(input->parent);
+ }
+ }
+ /* Optimize current node. */
+ ConstantFolder folder(this, node, output, scene);
+ node->constant_fold(folder);
+ }
+ }
+
+ /* Folding might have removed all nodes connected to the displacement output
+ * even tho there is displacement to be applied, so add in a value node if
+ * that happens to ensure there is still a valid graph for displacement.
+ */
+ if (has_displacement && !output()->input("Displacement")->link) {
+ ColorNode *value = (ColorNode *)add(create_node<ColorNode>());
+ value->set_value(output()->get_displacement());
+
+ connect(value->output("Color"), output()->input("Displacement"));
+ }
+}
+
+/* Simplification. */
+void ShaderGraph::simplify_settings(Scene *scene)
+{
+ foreach (ShaderNode *node, nodes) {
+ node->simplify_settings(scene);
+ }
+}
+
+/* Deduplicate nodes with same settings. */
+void ShaderGraph::deduplicate_nodes()
+{
+ /* NOTES:
+ * - Deduplication happens for nodes which has same exact settings and same
+ * exact input links configuration (either connected to same output or has
+ * the same exact default value).
+ * - Deduplication happens in the bottom-top manner, so we know for fact that
+ * all traversed nodes are either can not be deduplicated at all or were
+ * already deduplicated.
+ */
+
+ ShaderNodeSet scheduled, done;
+ map<ustring, ShaderNodeSet> candidates;
+ queue<ShaderNode *> traverse_queue;
+ int num_deduplicated = 0;
+
+ /* Schedule nodes which doesn't have any dependencies. */
+ foreach (ShaderNode *node, nodes) {
+ if (!check_node_inputs_has_links(node)) {
+ traverse_queue.push(node);
+ scheduled.insert(node);
+ }
+ }
+
+ while (!traverse_queue.empty()) {
+ ShaderNode *node = traverse_queue.front();
+ traverse_queue.pop();
+ done.insert(node);
+ /* Schedule the nodes which were depending on the current node. */
+ bool has_output_links = false;
+ foreach (ShaderOutput *output, node->outputs) {
+ foreach (ShaderInput *input, output->links) {
+ has_output_links = true;
+ if (scheduled.find(input->parent) != scheduled.end()) {
+ /* Node might not be optimized yet but scheduled already
+ * by other dependencies. No need to re-schedule it.
+ */
+ continue;
+ }
+ /* Schedule node if its inputs are fully done. */
+ if (check_node_inputs_traversed(input->parent, done)) {
+ traverse_queue.push(input->parent);
+ scheduled.insert(input->parent);
+ }
+ }
+ }
+ /* Only need to care about nodes that are actually used */
+ if (!has_output_links) {
+ continue;
+ }
+ /* Try to merge this node with another one. */
+ ShaderNode *merge_with = NULL;
+ foreach (ShaderNode *other_node, candidates[node->type->name]) {
+ if (node != other_node && node->equals(*other_node)) {
+ merge_with = other_node;
+ break;
+ }
+ }
+ /* If found an equivalent, merge; otherwise keep node for later merges */
+ if (merge_with != NULL) {
+ for (int i = 0; i < node->outputs.size(); ++i) {
+ relink(node, node->outputs[i], merge_with->outputs[i]);
+ }
+ num_deduplicated++;
+ }
+ else {
+ candidates[node->type->name].insert(node);
+ }
+ }
+
+ if (num_deduplicated > 0) {
+ VLOG(1) << "Deduplicated " << num_deduplicated << " nodes.";
+ }
+}
+
+/* Check whether volume output has meaningful nodes, otherwise
+ * disconnect the output.
+ */
+void ShaderGraph::verify_volume_output()
+{
+ /* Check whether we can optimize the whole volume graph out. */
+ ShaderInput *volume_in = output()->input("Volume");
+ if (volume_in->link == NULL) {
+ return;
+ }
+ bool has_valid_volume = false;
+ ShaderNodeSet scheduled;
+ queue<ShaderNode *> traverse_queue;
+ /* Schedule volume output. */
+ traverse_queue.push(volume_in->link->parent);
+ scheduled.insert(volume_in->link->parent);
+ /* Traverse down the tree. */
+ while (!traverse_queue.empty()) {
+ ShaderNode *node = traverse_queue.front();
+ traverse_queue.pop();
+ /* Node is fully valid for volume, can't optimize anything out. */
+ if (node->has_volume_support()) {
+ has_valid_volume = true;
+ break;
+ }
+ foreach (ShaderInput *input, node->inputs) {
+ if (input->link == NULL) {
+ continue;
+ }
+ if (scheduled.find(input->link->parent) != scheduled.end()) {
+ continue;
+ }
+ traverse_queue.push(input->link->parent);
+ scheduled.insert(input->link->parent);
+ }
+ }
+ if (!has_valid_volume) {
+ VLOG(1) << "Disconnect meaningless volume output.";
+ disconnect(volume_in->link);
+ }
+}
+
+void ShaderGraph::break_cycles(ShaderNode *node, vector<bool> &visited, vector<bool> &on_stack)
+{
+ visited[node->id] = true;
+ on_stack[node->id] = true;
+
+ foreach (ShaderInput *input, node->inputs) {
+ if (input->link) {
+ ShaderNode *depnode = input->link->parent;
+
+ if (on_stack[depnode->id]) {
+ /* break cycle */
+ disconnect(input);
+ fprintf(stderr, "Cycles shader graph: detected cycle in graph, connection removed.\n");
+ }
+ else if (!visited[depnode->id]) {
+ /* visit dependencies */
+ break_cycles(depnode, visited, on_stack);
+ }
+ }
+ }
+
+ on_stack[node->id] = false;
+}
+
+void ShaderGraph::compute_displacement_hash()
+{
+ /* Compute hash of all nodes linked to displacement, to detect if we need
+ * to recompute displacement when shader nodes change. */
+ ShaderInput *displacement_in = output()->input("Displacement");
+
+ if (!displacement_in->link) {
+ displacement_hash = "";
+ return;
+ }
+
+ ShaderNodeSet nodes_displace;
+ find_dependencies(nodes_displace, displacement_in);
+
+ MD5Hash md5;
+ foreach (ShaderNode *node, nodes_displace) {
+ node->hash(md5);
+ foreach (ShaderInput *input, node->inputs) {
+ int link_id = (input->link) ? input->link->parent->id : 0;
+ md5.append((uint8_t *)&link_id, sizeof(link_id));
+ md5.append((input->link) ? input->link->name().c_str() : "");
+ }
+
+ if (node->special_type == SHADER_SPECIAL_TYPE_OSL) {
+ /* Hash takes into account socket values, to detect changes
+ * in the code of the node we need an exception. */
+ OSLNode *oslnode = static_cast<OSLNode *>(node);
+ md5.append(oslnode->bytecode_hash);
+ }
+ }
+
+ displacement_hash = md5.get_hex();
+}
+
+void ShaderGraph::clean(Scene *scene)
+{
+ /* Graph simplification */
+
+ /* NOTE: Remove proxy nodes was already done. */
+ constant_fold(scene);
+ simplify_settings(scene);
+ deduplicate_nodes();
+ verify_volume_output();
+
+ /* we do two things here: find cycles and break them, and remove unused
+ * nodes that don't feed into the output. how cycles are broken is
+ * undefined, they are invalid input, the important thing is to not crash */
+
+ vector<bool> visited(num_node_ids, false);
+ vector<bool> on_stack(num_node_ids, false);
+
+ /* break cycles */
+ break_cycles(output(), visited, on_stack);
+ foreach (ShaderNode *node, nodes) {
+ if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
+ break_cycles(node, visited, on_stack);
+ }
+ }
+
+ /* disconnect unused nodes */
+ foreach (ShaderNode *node, nodes) {
+ if (!visited[node->id]) {
+ foreach (ShaderInput *to, node->inputs) {
+ ShaderOutput *from = to->link;
+
+ if (from) {
+ to->link = NULL;
+ from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
+ }
+ }
+ }
+ }
+
+ /* remove unused nodes */
+ list<ShaderNode *> newnodes;
+
+ foreach (ShaderNode *node, nodes) {
+ if (visited[node->id])
+ newnodes.push_back(node);
+ else
+ delete_node(node);
+ }
+
+ nodes = newnodes;
+}
+
+void ShaderGraph::expand()
+{
+ /* Call expand on all nodes, to generate additional nodes. */
+ foreach (ShaderNode *node, nodes) {
+ node->expand(this);
+ }
+}
+
+void ShaderGraph::default_inputs(bool do_osl)
+{
+ /* nodes can specify default texture coordinates, for now we give
+ * everything the position by default, except for the sky texture */
+
+ ShaderNode *geom = NULL;
+ ShaderNode *texco = NULL;
+
+ foreach (ShaderNode *node, nodes) {
+ foreach (ShaderInput *input, node->inputs) {
+ if (!input->link && (!(input->flags() & SocketType::OSL_INTERNAL) || do_osl)) {
+ if (input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
+ if (!texco)
+ texco = create_node<TextureCoordinateNode>();
+
+ connect(texco->output("Generated"), input);
+ }
+ if (input->flags() & SocketType::LINK_TEXTURE_NORMAL) {
+ if (!texco)
+ texco = create_node<TextureCoordinateNode>();
+
+ connect(texco->output("Normal"), input);
+ }
+ else if (input->flags() & SocketType::LINK_TEXTURE_UV) {
+ if (!texco)
+ texco = create_node<TextureCoordinateNode>();
+
+ connect(texco->output("UV"), input);
+ }
+ else if (input->flags() & SocketType::LINK_INCOMING) {
+ if (!geom)
+ geom = create_node<GeometryNode>();
+
+ connect(geom->output("Incoming"), input);
+ }
+ else if (input->flags() & SocketType::LINK_NORMAL) {
+ if (!geom)
+ geom = create_node<GeometryNode>();
+
+ connect(geom->output("Normal"), input);
+ }
+ else if (input->flags() & SocketType::LINK_POSITION) {
+ if (!geom)
+ geom = create_node<GeometryNode>();
+
+ connect(geom->output("Position"), input);
+ }
+ else if (input->flags() & SocketType::LINK_TANGENT) {
+ if (!geom)
+ geom = create_node<GeometryNode>();
+
+ connect(geom->output("Tangent"), input);
+ }
+ }
+ }
+ }
+
+ if (geom)
+ add(geom);
+ if (texco)
+ add(texco);
+}
+
+void ShaderGraph::refine_bump_nodes()
+{
+ /* we transverse the node graph looking for bump nodes, when we find them,
+ * like in bump_from_displacement(), we copy the sub-graph defined from "bump"
+ * input to the inputs "center","dx" and "dy" What is in "bump" input is moved
+ * to "center" input. */
+
+ foreach (ShaderNode *node, nodes) {
+ if (node->special_type == SHADER_SPECIAL_TYPE_BUMP && node->input("Height")->link) {
+ ShaderInput *bump_input = node->input("Height");
+ ShaderNodeSet nodes_bump;
+
+ /* make 2 extra copies of the subgraph defined in Bump input */
+ ShaderNodeMap nodes_dx;
+ ShaderNodeMap nodes_dy;
+
+ /* find dependencies for the given input */
+ find_dependencies(nodes_bump, bump_input);
+
+ copy_nodes(nodes_bump, nodes_dx);
+ copy_nodes(nodes_bump, nodes_dy);
+
+ /* mark nodes to indicate they are use for bump computation, so
+ that any texture coordinates are shifted by dx/dy when sampling */
+ foreach (ShaderNode *node, nodes_bump)
+ node->bump = SHADER_BUMP_CENTER;
+ foreach (NodePair &pair, nodes_dx)
+ pair.second->bump = SHADER_BUMP_DX;
+ foreach (NodePair &pair, nodes_dy)
+ pair.second->bump = SHADER_BUMP_DY;
+
+ ShaderOutput *out = bump_input->link;
+ ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
+ ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
+
+ connect(out_dx, node->input("SampleX"));
+ connect(out_dy, node->input("SampleY"));
+
+ /* add generated nodes */
+ foreach (NodePair &pair, nodes_dx)
+ add(pair.second);
+ foreach (NodePair &pair, nodes_dy)
+ add(pair.second);
+
+ /* Connect what is connected is bump to sample-center input. */
+ connect(out, node->input("SampleCenter"));
+
+ /* Bump input is just for connectivity purpose for the graph input,
+ * we re-connected this input to sample-center, so lets disconnect it
+ * from bump input. */
+ disconnect(bump_input);
+ }
+ }
+}
+
+void ShaderGraph::bump_from_displacement(bool use_object_space)
+{
+ /* generate bump mapping automatically from displacement. bump mapping is
+ * done using a 3-tap filter, computing the displacement at the center,
+ * and two other positions shifted by ray differentials.
+ *
+ * since the input to displacement is a node graph, we need to ensure that
+ * all texture coordinates use are shift by the ray differentials. for this
+ * reason we make 3 copies of the node subgraph defining the displacement,
+ * with each different geometry and texture coordinate nodes that generate
+ * different shifted coordinates.
+ *
+ * these 3 displacement values are then fed into the bump node, which will
+ * output the perturbed normal. */
+
+ ShaderInput *displacement_in = output()->input("Displacement");
+
+ if (!displacement_in->link)
+ return;
+
+ /* find dependencies for the given input */
+ ShaderNodeSet nodes_displace;
+ find_dependencies(nodes_displace, displacement_in);
+
+ /* copy nodes for 3 bump samples */
+ ShaderNodeMap nodes_center;
+ ShaderNodeMap nodes_dx;
+ ShaderNodeMap nodes_dy;
+
+ copy_nodes(nodes_displace, nodes_center);
+ copy_nodes(nodes_displace, nodes_dx);
+ copy_nodes(nodes_displace, nodes_dy);
+
+ /* mark nodes to indicate they are use for bump computation, so
+ * that any texture coordinates are shifted by dx/dy when sampling */
+ foreach (NodePair &pair, nodes_center)
+ pair.second->bump = SHADER_BUMP_CENTER;
+ foreach (NodePair &pair, nodes_dx)
+ pair.second->bump = SHADER_BUMP_DX;
+ foreach (NodePair &pair, nodes_dy)
+ pair.second->bump = SHADER_BUMP_DY;
+
+ /* add set normal node and connect the bump normal output to the set normal
+ * output, so it can finally set the shader normal, note we are only doing
+ * this for bump from displacement, this will be the only bump allowed to
+ * overwrite the shader normal */
+ ShaderNode *set_normal = add(create_node<SetNormalNode>());
+
+ /* add bump node and connect copied graphs to it */
+ BumpNode *bump = (BumpNode *)add(create_node<BumpNode>());
+ bump->set_use_object_space(use_object_space);
+ bump->set_distance(1.0f);
+
+ ShaderOutput *out = displacement_in->link;
+ ShaderOutput *out_center = nodes_center[out->parent]->output(out->name());
+ ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
+ ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
+
+ /* convert displacement vector to height */
+ VectorMathNode *dot_center = (VectorMathNode *)add(create_node<VectorMathNode>());
+ VectorMathNode *dot_dx = (VectorMathNode *)add(create_node<VectorMathNode>());
+ VectorMathNode *dot_dy = (VectorMathNode *)add(create_node<VectorMathNode>());
+
+ dot_center->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
+ dot_dx->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
+ dot_dy->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
+
+ GeometryNode *geom = (GeometryNode *)add(create_node<GeometryNode>());
+ connect(geom->output("Normal"), dot_center->input("Vector2"));
+ connect(geom->output("Normal"), dot_dx->input("Vector2"));
+ connect(geom->output("Normal"), dot_dy->input("Vector2"));
+
+ connect(out_center, dot_center->input("Vector1"));
+ connect(out_dx, dot_dx->input("Vector1"));
+ connect(out_dy, dot_dy->input("Vector1"));
+
+ connect(dot_center->output("Value"), bump->input("SampleCenter"));
+ connect(dot_dx->output("Value"), bump->input("SampleX"));
+ connect(dot_dy->output("Value"), bump->input("SampleY"));
+
+ /* connect the bump out to the set normal in: */
+ connect(bump->output("Normal"), set_normal->input("Direction"));
+
+ /* connect to output node */
+ connect(set_normal->output("Normal"), output()->input("Normal"));
+
+ /* finally, add the copied nodes to the graph. we can't do this earlier
+ * because we would create dependency cycles in the above loop */
+ foreach (NodePair &pair, nodes_center)
+ add(pair.second);
+ foreach (NodePair &pair, nodes_dx)
+ add(pair.second);
+ foreach (NodePair &pair, nodes_dy)
+ add(pair.second);
+}
+
+void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume)
+{
+ /* for SVM in multi closure mode, this transforms the shader mix/add part of
+ * the graph into nodes that feed weights into closure nodes. this is too
+ * avoid building a closure tree and then flattening it, and instead write it
+ * directly to an array */
+
+ if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) {
+ ShaderInput *fin = node->input("Fac");
+ ShaderInput *cl1in = node->input("Closure1");
+ ShaderInput *cl2in = node->input("Closure2");
+ ShaderOutput *weight1_out, *weight2_out;
+
+ if (fin) {
+ /* mix closure: add node to mix closure weights */
+ MixClosureWeightNode *mix_node = create_node<MixClosureWeightNode>();
+ add(mix_node);
+ ShaderInput *fac_in = mix_node->input("Fac");
+ ShaderInput *weight_in = mix_node->input("Weight");
+
+ if (fin->link)
+ connect(fin->link, fac_in);
+ else
+ mix_node->set_fac(node->get_float(fin->socket_type));
+
+ if (weight_out)
+ connect(weight_out, weight_in);
+
+ weight1_out = mix_node->output("Weight1");
+ weight2_out = mix_node->output("Weight2");
+ }
+ else {
+ /* add closure: just pass on any weights */
+ weight1_out = weight_out;
+ weight2_out = weight_out;
+ }
+
+ if (cl1in->link)
+ transform_multi_closure(cl1in->link->parent, weight1_out, volume);
+ if (cl2in->link)
+ transform_multi_closure(cl2in->link->parent, weight2_out, volume);
+ }
+ else {
+ ShaderInput *weight_in = node->input((volume) ? "VolumeMixWeight" : "SurfaceMixWeight");
+
+ /* not a closure node? */
+ if (!weight_in)
+ return;
+
+ /* already has a weight connected to it? add weights */
+ float weight_value = node->get_float(weight_in->socket_type);
+ if (weight_in->link || weight_value != 0.0f) {
+ MathNode *math_node = create_node<MathNode>();
+ add(math_node);
+
+ if (weight_in->link)
+ connect(weight_in->link, math_node->input("Value1"));
+ else
+ math_node->set_value1(weight_value);
+
+ if (weight_out)
+ connect(weight_out, math_node->input("Value2"));
+ else
+ math_node->set_value2(1.0f);
+
+ weight_out = math_node->output("Value");
+ if (weight_in->link)
+ disconnect(weight_in);
+ }
+
+ /* connected to closure mix weight */
+ if (weight_out)
+ connect(weight_out, weight_in);
+ else
+ node->set(weight_in->socket_type, weight_value + 1.0f);
+ }
+}
+
+int ShaderGraph::get_num_closures()
+{
+ int num_closures = 0;
+ foreach (ShaderNode *node, nodes) {
+ ClosureType closure_type = node->get_closure_type();
+ if (closure_type == CLOSURE_NONE_ID) {
+ continue;
+ }
+ else if (CLOSURE_IS_BSSRDF(closure_type)) {
+ num_closures += 3;
+ }
+ else if (CLOSURE_IS_GLASS(closure_type)) {
+ num_closures += 2;
+ }
+ else if (CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) {
+ num_closures += 2;
+ }
+ else if (CLOSURE_IS_PRINCIPLED(closure_type)) {
+ num_closures += 8;
+ }
+ else if (CLOSURE_IS_VOLUME(closure_type)) {
+ /* TODO(sergey): Verify this is still needed, since we have special minimized volume storage
+ * for the volume steps. */
+ num_closures += MAX_VOLUME_STACK_SIZE;
+ }
+ else if (closure_type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
+ num_closures += 4;
+ }
+ else {
+ ++num_closures;
+ }
+ }
+ return num_closures;
+}
+
+void ShaderGraph::dump_graph(const char *filename)
+{
+ FILE *fd = fopen(filename, "w");
+
+ if (fd == NULL) {
+ printf("Error opening file for dumping the graph: %s\n", filename);
+ return;
+ }
+
+ fprintf(fd, "digraph shader_graph {\n");
+ fprintf(fd, "ranksep=1.5\n");
+ fprintf(fd, "rankdir=LR\n");
+ fprintf(fd, "splines=false\n");
+
+ foreach (ShaderNode *node, nodes) {
+ fprintf(fd, "// NODE: %p\n", node);
+ fprintf(fd, "\"%p\" [shape=record,label=\"{", node);
+ if (node->inputs.size()) {
+ fprintf(fd, "{");
+ foreach (ShaderInput *socket, node->inputs) {
+ if (socket != node->inputs[0]) {
+ fprintf(fd, "|");
+ }
+ fprintf(fd, "<IN_%p>%s", socket, socket->name().c_str());
+ }
+ fprintf(fd, "}|");
+ }
+ fprintf(fd, "%s", node->name.c_str());
+ if (node->bump == SHADER_BUMP_CENTER) {
+ fprintf(fd, " (bump:center)");
+ }
+ else if (node->bump == SHADER_BUMP_DX) {
+ fprintf(fd, " (bump:dx)");
+ }
+ else if (node->bump == SHADER_BUMP_DY) {
+ fprintf(fd, " (bump:dy)");
+ }
+ if (node->outputs.size()) {
+ fprintf(fd, "|{");
+ foreach (ShaderOutput *socket, node->outputs) {
+ if (socket != node->outputs[0]) {
+ fprintf(fd, "|");
+ }
+ fprintf(fd, "<OUT_%p>%s", socket, socket->name().c_str());
+ }
+ fprintf(fd, "}");
+ }
+ fprintf(fd, "}\"]");
+ }
+
+ foreach (ShaderNode *node, nodes) {
+ foreach (ShaderOutput *output, node->outputs) {
+ foreach (ShaderInput *input, output->links) {
+ fprintf(fd,
+ "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n",
+ output,
+ input,
+ output->name().c_str(),
+ input->name().c_str());
+ fprintf(fd,
+ "\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n",
+ output->parent,
+ output,
+ input->parent,
+ input);
+ }
+ }
+ }
+
+ fprintf(fd, "}\n");
+ fclose(fd);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/shader_graph.h b/intern/cycles/scene/shader_graph.h
new file mode 100644
index 00000000000..8b525a7ec0b
--- /dev/null
+++ b/intern/cycles/scene/shader_graph.h
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GRAPH_H__
+#define __GRAPH_H__
+
+#include "graph/node.h"
+#include "graph/node_type.h"
+
+#include "kernel/types.h"
+
+#include "util/list.h"
+#include "util/map.h"
+#include "util/param.h"
+#include "util/set.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class AttributeRequestSet;
+class Scene;
+class Shader;
+class ShaderInput;
+class ShaderOutput;
+class ShaderNode;
+class ShaderGraph;
+class SVMCompiler;
+class OSLCompiler;
+class OutputNode;
+class ConstantFolder;
+class MD5Hash;
+
+/* Bump
+ *
+ * For bump mapping, a node may be evaluated multiple times, using different
+ * samples to reconstruct the normal, this indicates the sample position */
+
+enum ShaderBump { SHADER_BUMP_NONE, SHADER_BUMP_CENTER, SHADER_BUMP_DX, SHADER_BUMP_DY };
+
+/* Identifiers for some special node types.
+ *
+ * The graph needs to identify these in the clean function.
+ * Cannot use dynamic_cast, as this is disabled for OSL. */
+
+enum ShaderNodeSpecialType {
+ SHADER_SPECIAL_TYPE_NONE,
+ SHADER_SPECIAL_TYPE_PROXY,
+ SHADER_SPECIAL_TYPE_AUTOCONVERT,
+ SHADER_SPECIAL_TYPE_GEOMETRY,
+ SHADER_SPECIAL_TYPE_OSL,
+ SHADER_SPECIAL_TYPE_IMAGE_SLOT,
+ SHADER_SPECIAL_TYPE_CLOSURE,
+ SHADER_SPECIAL_TYPE_COMBINE_CLOSURE,
+ SHADER_SPECIAL_TYPE_OUTPUT,
+ SHADER_SPECIAL_TYPE_BUMP,
+ SHADER_SPECIAL_TYPE_OUTPUT_AOV,
+};
+
+/* Input
+ *
+ * Input socket for a shader node. May be linked to an output or not. If not
+ * linked, it will either get a fixed default value, or e.g. a texture
+ * coordinate. */
+
+class ShaderInput {
+ public:
+ ShaderInput(const SocketType &socket_type_, ShaderNode *parent_)
+ : socket_type(socket_type_),
+ parent(parent_),
+ link(NULL),
+ stack_offset(SVM_STACK_INVALID),
+ constant_folded_in(false)
+ {
+ }
+
+ ustring name()
+ {
+ return socket_type.ui_name;
+ }
+ int flags()
+ {
+ return socket_type.flags;
+ }
+ SocketType::Type type()
+ {
+ return socket_type.type;
+ }
+
+ void set(float f)
+ {
+ ((Node *)parent)->set(socket_type, f);
+ }
+ void set(float3 f)
+ {
+ ((Node *)parent)->set(socket_type, f);
+ }
+
+ void disconnect();
+
+ const SocketType &socket_type;
+ ShaderNode *parent;
+ ShaderOutput *link;
+ int stack_offset; /* for SVM compiler */
+
+ /* Keeps track of whether a constant was folded in this socket, to avoid over-optimizing when the
+ * link is null. */
+ bool constant_folded_in;
+};
+
+/* Output
+ *
+ * Output socket for a shader node. */
+
+class ShaderOutput {
+ public:
+ ShaderOutput(const SocketType &socket_type_, ShaderNode *parent_)
+ : socket_type(socket_type_), parent(parent_), stack_offset(SVM_STACK_INVALID)
+ {
+ }
+
+ ustring name()
+ {
+ return socket_type.ui_name;
+ }
+ SocketType::Type type()
+ {
+ return socket_type.type;
+ }
+
+ void disconnect();
+
+ const SocketType &socket_type;
+ ShaderNode *parent;
+ vector<ShaderInput *> links;
+ int stack_offset; /* for SVM compiler */
+};
+
+/* Node
+ *
+ * Shader node in graph, with input and output sockets. This is the virtual
+ * base class for all node types. */
+
+class ShaderNode : public Node {
+ public:
+ explicit ShaderNode(const NodeType *type);
+ virtual ~ShaderNode();
+
+ void create_inputs_outputs(const NodeType *type);
+ void remove_input(ShaderInput *input);
+
+ ShaderInput *input(const char *name);
+ ShaderOutput *output(const char *name);
+ ShaderInput *input(ustring name);
+ ShaderOutput *output(ustring name);
+
+ virtual ShaderNode *clone(ShaderGraph *graph) const = 0;
+ virtual void attributes(Shader *shader, AttributeRequestSet *attributes);
+ virtual void compile(SVMCompiler &compiler) = 0;
+ virtual void compile(OSLCompiler &compiler) = 0;
+
+ /* Expand node into additional nodes. */
+ virtual void expand(ShaderGraph * /* graph */)
+ {
+ }
+
+ /* ** Node optimization ** */
+ /* Check whether the node can be replaced with single constant. */
+ virtual void constant_fold(const ConstantFolder & /*folder*/)
+ {
+ }
+
+ /* Simplify settings used by artists to the ones which are simpler to
+ * evaluate in the kernel but keep the final result unchanged.
+ */
+ virtual void simplify_settings(Scene * /*scene*/){};
+
+ virtual bool has_surface_emission()
+ {
+ return false;
+ }
+ virtual bool has_surface_transparent()
+ {
+ return false;
+ }
+ virtual bool has_surface_bssrdf()
+ {
+ return false;
+ }
+ virtual bool has_bump()
+ {
+ return false;
+ }
+ virtual bool has_bssrdf_bump()
+ {
+ return false;
+ }
+ virtual bool has_spatial_varying()
+ {
+ return false;
+ }
+ virtual bool has_attribute_dependency()
+ {
+ return false;
+ }
+ virtual bool has_integrator_dependency()
+ {
+ return false;
+ }
+ virtual bool has_volume_support()
+ {
+ return false;
+ }
+ vector<ShaderInput *> inputs;
+ vector<ShaderOutput *> outputs;
+
+ int id; /* index in graph node array */
+ ShaderBump bump; /* for bump mapping utility */
+
+ ShaderNodeSpecialType special_type; /* special node type */
+
+ /* ** Selective nodes compilation ** */
+
+ /* TODO(sergey): More explicitly mention in the function names
+ * that those functions are for selective compilation only?
+ */
+
+ /* Node feature are used to disable huge nodes inside the group,
+ * so it's possible to disable huge nodes inside of the required
+ * nodes group.
+ */
+ virtual int get_feature()
+ {
+ return bump == SHADER_BUMP_NONE ? 0 : KERNEL_FEATURE_NODE_BUMP;
+ }
+
+ /* Get closure ID to which the node compiles into. */
+ virtual ClosureType get_closure_type()
+ {
+ return CLOSURE_NONE_ID;
+ }
+
+ /* Check whether settings of the node equals to another one.
+ *
+ * This is mainly used to check whether two nodes can be merged
+ * together. Meaning, runtime stuff like node id and unbound slots
+ * will be ignored for comparison.
+ *
+ * NOTE: If some node can't be de-duplicated for whatever reason it
+ * is to be handled in the subclass.
+ */
+ virtual bool equals(const ShaderNode &other);
+};
+
+/* Node definition utility macros */
+
+#define SHADER_NODE_CLASS(type) \
+ NODE_DECLARE \
+ type(); \
+ virtual ShaderNode *clone(ShaderGraph *graph) const \
+ { \
+ return graph->create_node<type>(*this); \
+ } \
+ virtual void compile(SVMCompiler &compiler); \
+ virtual void compile(OSLCompiler &compiler);
+
+#define SHADER_NODE_NO_CLONE_CLASS(type) \
+ NODE_DECLARE \
+ type(); \
+ virtual void compile(SVMCompiler &compiler); \
+ virtual void compile(OSLCompiler &compiler);
+
+#define SHADER_NODE_BASE_CLASS(type) \
+ virtual ShaderNode *clone(ShaderGraph *graph) const \
+ { \
+ return graph->create_node<type>(*this); \
+ } \
+ virtual void compile(SVMCompiler &compiler); \
+ virtual void compile(OSLCompiler &compiler);
+
+class ShaderNodeIDComparator {
+ public:
+ bool operator()(const ShaderNode *n1, const ShaderNode *n2) const
+ {
+ return n1->id < n2->id;
+ }
+};
+
+typedef set<ShaderNode *, ShaderNodeIDComparator> ShaderNodeSet;
+typedef map<ShaderNode *, ShaderNode *, ShaderNodeIDComparator> ShaderNodeMap;
+
+/* Graph
+ *
+ * Shader graph of nodes. Also does graph manipulations for default inputs,
+ * bump mapping from displacement, and possibly other things in the future. */
+
+class ShaderGraph : public NodeOwner {
+ public:
+ list<ShaderNode *> nodes;
+ size_t num_node_ids;
+ bool finalized;
+ bool simplified;
+ string displacement_hash;
+
+ ShaderGraph();
+ ~ShaderGraph();
+
+ ShaderNode *add(ShaderNode *node);
+ OutputNode *output();
+
+ void connect(ShaderOutput *from, ShaderInput *to);
+ void disconnect(ShaderOutput *from);
+ void disconnect(ShaderInput *to);
+ void relink(ShaderInput *from, ShaderInput *to);
+ void relink(ShaderOutput *from, ShaderOutput *to);
+ void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to);
+
+ void remove_proxy_nodes();
+ void compute_displacement_hash();
+ void simplify(Scene *scene);
+ void finalize(Scene *scene,
+ bool do_bump = false,
+ bool do_simplify = false,
+ bool bump_in_object_space = false);
+
+ int get_num_closures();
+
+ void dump_graph(const char *filename);
+
+ /* This function is used to create a node of a specified type instead of
+ * calling 'new', and sets the graph as the owner of the node.
+ */
+ template<typename T, typename... Args> T *create_node(Args &&...args)
+ {
+ T *node = new T(args...);
+ node->set_owner(this);
+ return node;
+ }
+
+ /* This function is used to delete a node created and owned by the graph.
+ */
+ template<typename T> void delete_node(T *node)
+ {
+ assert(node->get_owner() == this);
+ delete node;
+ }
+
+ protected:
+ typedef pair<ShaderNode *const, ShaderNode *> NodePair;
+
+ void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input);
+ void clear_nodes();
+ void copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap);
+
+ void break_cycles(ShaderNode *node, vector<bool> &visited, vector<bool> &on_stack);
+ void bump_from_displacement(bool use_object_space);
+ void refine_bump_nodes();
+ void expand();
+ void default_inputs(bool do_osl);
+ void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume);
+
+ /* Graph simplification routines. */
+ void clean(Scene *scene);
+ void constant_fold(Scene *scene);
+ void simplify_settings(Scene *scene);
+ void deduplicate_nodes();
+ void verify_volume_output();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __GRAPH_H__ */
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
new file mode 100644
index 00000000000..14d051350fb
--- /dev/null
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -0,0 +1,7171 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/shader_nodes.h"
+#include "scene/colorspace.h"
+#include "scene/constant_fold.h"
+#include "scene/film.h"
+#include "scene/image.h"
+#include "scene/image_sky.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/osl.h"
+#include "scene/scene.h"
+#include "scene/svm.h"
+
+#include "sky_model.h"
+
+#include "util/color.h"
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/transform.h"
+
+#include "kernel/svm/color_util.h"
+#include "kernel/svm/mapping_util.h"
+#include "kernel/svm/math_util.h"
+#include "kernel/svm/ramp_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Texture Mapping */
+
+#define TEXTURE_MAPPING_DEFINE(TextureNode) \
+ SOCKET_POINT(tex_mapping.translation, "Translation", zero_float3()); \
+ SOCKET_VECTOR(tex_mapping.rotation, "Rotation", zero_float3()); \
+ SOCKET_VECTOR(tex_mapping.scale, "Scale", one_float3()); \
+\
+ SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \
+ SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \
+ SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \
+\
+ static NodeEnum mapping_axis_enum; \
+ mapping_axis_enum.insert("none", TextureMapping::NONE); \
+ mapping_axis_enum.insert("x", TextureMapping::X); \
+ mapping_axis_enum.insert("y", TextureMapping::Y); \
+ mapping_axis_enum.insert("z", TextureMapping::Z); \
+ SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \
+ SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \
+ SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \
+\
+ static NodeEnum mapping_type_enum; \
+ mapping_type_enum.insert("point", TextureMapping::POINT); \
+ mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \
+ mapping_type_enum.insert("vector", TextureMapping::VECTOR); \
+ mapping_type_enum.insert("normal", TextureMapping::NORMAL); \
+ SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \
+\
+ static NodeEnum mapping_projection_enum; \
+ mapping_projection_enum.insert("flat", TextureMapping::FLAT); \
+ mapping_projection_enum.insert("cube", TextureMapping::CUBE); \
+ mapping_projection_enum.insert("tube", TextureMapping::TUBE); \
+ mapping_projection_enum.insert("sphere", TextureMapping::SPHERE); \
+ SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT);
+
+TextureMapping::TextureMapping()
+{
+}
+
+Transform TextureMapping::compute_transform()
+{
+ Transform mmat = transform_scale(zero_float3());
+
+ if (x_mapping != NONE)
+ mmat[0][x_mapping - 1] = 1.0f;
+ if (y_mapping != NONE)
+ mmat[1][y_mapping - 1] = 1.0f;
+ if (z_mapping != NONE)
+ mmat[2][z_mapping - 1] = 1.0f;
+
+ float3 scale_clamped = scale;
+
+ if (type == TEXTURE || type == NORMAL) {
+ /* keep matrix invertible */
+ if (fabsf(scale.x) < 1e-5f)
+ scale_clamped.x = signf(scale.x) * 1e-5f;
+ if (fabsf(scale.y) < 1e-5f)
+ scale_clamped.y = signf(scale.y) * 1e-5f;
+ if (fabsf(scale.z) < 1e-5f)
+ scale_clamped.z = signf(scale.z) * 1e-5f;
+ }
+
+ Transform smat = transform_scale(scale_clamped);
+ Transform rmat = transform_euler(rotation);
+ Transform tmat = transform_translate(translation);
+
+ Transform mat;
+
+ switch (type) {
+ case TEXTURE:
+ /* inverse transform on texture coordinate gives
+ * forward transform on texture */
+ mat = tmat * rmat * smat;
+ mat = transform_inverse(mat);
+ break;
+ case POINT:
+ /* full transform */
+ mat = tmat * rmat * smat;
+ break;
+ case VECTOR:
+ /* no translation for vectors */
+ mat = rmat * smat;
+ break;
+ case NORMAL:
+ /* no translation for normals, and inverse transpose */
+ mat = rmat * smat;
+ mat = transform_transposed_inverse(mat);
+ break;
+ }
+
+ /* projection last */
+ mat = mat * mmat;
+
+ return mat;
+}
+
+bool TextureMapping::skip()
+{
+ if (translation != zero_float3())
+ return false;
+ if (rotation != zero_float3())
+ return false;
+ if (scale != one_float3())
+ return false;
+
+ if (x_mapping != X || y_mapping != Y || z_mapping != Z)
+ return false;
+ if (use_minmax)
+ return false;
+
+ return true;
+}
+
+void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_out)
+{
+ compiler.add_node(NODE_TEXTURE_MAPPING, offset_in, offset_out);
+
+ Transform tfm = compute_transform();
+ compiler.add_node(tfm.x);
+ compiler.add_node(tfm.y);
+ compiler.add_node(tfm.z);
+
+ if (use_minmax) {
+ compiler.add_node(NODE_MIN_MAX, offset_out, offset_out);
+ compiler.add_node(float3_to_float4(min));
+ compiler.add_node(float3_to_float4(max));
+ }
+
+ if (type == NORMAL) {
+ compiler.add_node(NODE_VECTOR_MATH,
+ NODE_VECTOR_MATH_NORMALIZE,
+ compiler.encode_uchar4(offset_out, offset_out, offset_out),
+ compiler.encode_uchar4(SVM_STACK_INVALID, offset_out));
+ }
+}
+
+/* Convenience function for texture nodes, allocating stack space to output
+ * a modified vector and returning its offset */
+int TextureMapping::compile_begin(SVMCompiler &compiler, ShaderInput *vector_in)
+{
+ if (!skip()) {
+ int offset_in = compiler.stack_assign(vector_in);
+ int offset_out = compiler.stack_find_offset(SocketType::VECTOR);
+
+ compile(compiler, offset_in, offset_out);
+
+ return offset_out;
+ }
+
+ return compiler.stack_assign(vector_in);
+}
+
+void TextureMapping::compile_end(SVMCompiler &compiler, ShaderInput *vector_in, int vector_offset)
+{
+ if (!skip()) {
+ compiler.stack_clear_offset(vector_in->type(), vector_offset);
+ }
+}
+
+void TextureMapping::compile(OSLCompiler &compiler)
+{
+ if (!skip()) {
+ compiler.parameter("mapping", compute_transform());
+ compiler.parameter("use_mapping", 1);
+ }
+}
+
+/* Image Texture */
+
+NODE_DEFINE(ImageTextureNode)
+{
+ NodeType *type = NodeType::add("image_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(ImageTextureNode);
+
+ SOCKET_STRING(filename, "Filename", ustring());
+ SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
+
+ static NodeEnum alpha_type_enum;
+ alpha_type_enum.insert("auto", IMAGE_ALPHA_AUTO);
+ alpha_type_enum.insert("unassociated", IMAGE_ALPHA_UNASSOCIATED);
+ alpha_type_enum.insert("associated", IMAGE_ALPHA_ASSOCIATED);
+ alpha_type_enum.insert("channel_packed", IMAGE_ALPHA_CHANNEL_PACKED);
+ alpha_type_enum.insert("ignore", IMAGE_ALPHA_IGNORE);
+ SOCKET_ENUM(alpha_type, "Alpha Type", alpha_type_enum, IMAGE_ALPHA_AUTO);
+
+ static NodeEnum interpolation_enum;
+ interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
+ interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
+ interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
+ interpolation_enum.insert("smart", INTERPOLATION_SMART);
+ SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
+
+ static NodeEnum extension_enum;
+ extension_enum.insert("periodic", EXTENSION_REPEAT);
+ extension_enum.insert("clamp", EXTENSION_EXTEND);
+ extension_enum.insert("black", EXTENSION_CLIP);
+ SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT);
+
+ static NodeEnum projection_enum;
+ projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT);
+ projection_enum.insert("box", NODE_IMAGE_PROJ_BOX);
+ projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE);
+ projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE);
+ SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT);
+
+ SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f);
+
+ SOCKET_INT_ARRAY(tiles, "Tiles", array<int>());
+ SOCKET_BOOLEAN(animated, "Animated", false);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_UV);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
+
+ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(get_node_type())
+{
+ colorspace = u_colorspace_raw;
+ animated = false;
+ tiles.push_back_slow(1001);
+}
+
+ShaderNode *ImageTextureNode::clone(ShaderGraph *graph) const
+{
+ ImageTextureNode *node = graph->create_node<ImageTextureNode>(*this);
+ node->handle = handle;
+ return node;
+}
+
+ImageParams ImageTextureNode::image_params() const
+{
+ ImageParams params;
+ params.animated = animated;
+ params.interpolation = interpolation;
+ params.extension = extension;
+ params.alpha_type = alpha_type;
+ params.colorspace = colorspace;
+ return params;
+}
+
+void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph)
+{
+ /* Box projection computes its own UVs that always lie in the
+ * 1001 tile, so there's no point in loading any others. */
+ if (projection == NODE_IMAGE_PROJ_BOX) {
+ tiles.clear();
+ tiles.push_back_slow(1001);
+ return;
+ }
+
+ if (!scene->params.background) {
+ /* During interactive renders, all tiles are loaded.
+ * While we could support updating this when UVs change, that could lead
+ * to annoying interruptions when loading images while editing UVs. */
+ return;
+ }
+
+ /* Only check UVs for tile culling if there are multiple tiles. */
+ if (tiles.size() < 2) {
+ return;
+ }
+
+ ShaderInput *vector_in = input("Vector");
+ ustring attribute;
+ if (vector_in->link) {
+ ShaderNode *node = vector_in->link->parent;
+ if (node->type == UVMapNode::get_node_type()) {
+ UVMapNode *uvmap = (UVMapNode *)node;
+ attribute = uvmap->get_attribute();
+ }
+ else if (node->type == TextureCoordinateNode::get_node_type()) {
+ if (vector_in->link != node->output("UV")) {
+ return;
+ }
+ }
+ else {
+ return;
+ }
+ }
+
+ unordered_set<int> used_tiles;
+ /* TODO(lukas): This is quite inefficient. A fairly simple improvement would
+ * be to have a cache in each mesh that is indexed by attribute.
+ * Additionally, building a graph-to-meshes list once could help. */
+ foreach (Geometry *geom, scene->geometry) {
+ foreach (Node *node, geom->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ if (shader->graph == graph) {
+ geom->get_uv_tiles(attribute, used_tiles);
+ }
+ }
+ }
+
+ array<int> new_tiles;
+ foreach (int tile, tiles) {
+ if (used_tiles.count(tile)) {
+ new_tiles.push_back_slow(tile);
+ }
+ }
+ tiles.steal_data(new_tiles);
+}
+
+void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+#ifdef WITH_PTEX
+ /* todo: avoid loading other texture coordinates when using ptex,
+ * and hide texture coordinate socket in the UI */
+ if (shader->has_surface_link() && string_endswith(filename, ".ptx")) {
+ /* ptex */
+ attributes->add(ATTR_STD_PTEX_FACE_ID);
+ attributes->add(ATTR_STD_PTEX_UV);
+ }
+#endif
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void ImageTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *alpha_out = output("Alpha");
+
+ if (handle.empty()) {
+ cull_tiles(compiler.scene, compiler.current_graph);
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params(), tiles);
+ }
+
+ /* All tiles have the same metadata. */
+ const ImageMetaData metadata = handle.metadata();
+ const bool compress_as_srgb = metadata.compress_as_srgb;
+ const ustring known_colorspace = metadata.colorspace;
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+ uint flags = 0;
+
+ if (compress_as_srgb) {
+ flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
+ }
+ if (!alpha_out->links.empty()) {
+ const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
+ alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
+ alpha_type == IMAGE_ALPHA_IGNORE);
+
+ if (unassociate_alpha) {
+ flags |= NODE_IMAGE_ALPHA_UNASSOCIATE;
+ }
+ }
+
+ if (projection != NODE_IMAGE_PROJ_BOX) {
+ /* If there only is one image (a very common case), we encode it as a negative value. */
+ int num_nodes;
+ if (handle.num_tiles() == 1) {
+ num_nodes = -handle.svm_slot();
+ }
+ else {
+ num_nodes = divide_up(handle.num_tiles(), 2);
+ }
+
+ compiler.add_node(NODE_TEX_IMAGE,
+ num_nodes,
+ compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(alpha_out),
+ flags),
+ projection);
+
+ if (num_nodes > 0) {
+ for (int i = 0; i < num_nodes; i++) {
+ int4 node;
+ node.x = tiles[2 * i];
+ node.y = handle.svm_slot(2 * i);
+ if (2 * i + 1 < tiles.size()) {
+ node.z = tiles[2 * i + 1];
+ node.w = handle.svm_slot(2 * i + 1);
+ }
+ else {
+ node.z = -1;
+ node.w = -1;
+ }
+ compiler.add_node(node.x, node.y, node.z, node.w);
+ }
+ }
+ }
+ else {
+ assert(handle.num_tiles() == 1);
+ compiler.add_node(NODE_TEX_IMAGE_BOX,
+ handle.svm_slot(),
+ compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(alpha_out),
+ flags),
+ __float_as_int(projection_blend));
+ }
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
+}
+
+void ImageTextureNode::compile(OSLCompiler &compiler)
+{
+ ShaderOutput *alpha_out = output("Alpha");
+
+ tex_mapping.compile(compiler);
+
+ if (handle.empty()) {
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params());
+ }
+
+ const ImageMetaData metadata = handle.metadata();
+ const bool is_float = metadata.is_float();
+ const bool compress_as_srgb = metadata.compress_as_srgb;
+ const ustring known_colorspace = metadata.colorspace;
+
+ if (handle.svm_slot() == -1) {
+ compiler.parameter_texture(
+ "filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
+ }
+ else {
+ compiler.parameter_texture("filename", handle.svm_slot());
+ }
+
+ const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
+ alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
+ alpha_type == IMAGE_ALPHA_IGNORE);
+ const bool is_tiled = (filename.find("<UDIM>") != string::npos);
+
+ compiler.parameter(this, "projection");
+ compiler.parameter(this, "projection_blend");
+ compiler.parameter("compress_as_srgb", compress_as_srgb);
+ compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
+ compiler.parameter("unassociate_alpha", !alpha_out->links.empty() && unassociate_alpha);
+ compiler.parameter("is_float", is_float);
+ compiler.parameter("is_tiled", is_tiled);
+ compiler.parameter(this, "interpolation");
+ compiler.parameter(this, "extension");
+
+ compiler.add(this, "node_image_texture");
+}
+
+/* Environment Texture */
+
+NODE_DEFINE(EnvironmentTextureNode)
+{
+ NodeType *type = NodeType::add("environment_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
+
+ SOCKET_STRING(filename, "Filename", ustring());
+ SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
+
+ static NodeEnum alpha_type_enum;
+ alpha_type_enum.insert("auto", IMAGE_ALPHA_AUTO);
+ alpha_type_enum.insert("unassociated", IMAGE_ALPHA_UNASSOCIATED);
+ alpha_type_enum.insert("associated", IMAGE_ALPHA_ASSOCIATED);
+ alpha_type_enum.insert("channel_packed", IMAGE_ALPHA_CHANNEL_PACKED);
+ alpha_type_enum.insert("ignore", IMAGE_ALPHA_IGNORE);
+ SOCKET_ENUM(alpha_type, "Alpha Type", alpha_type_enum, IMAGE_ALPHA_AUTO);
+
+ static NodeEnum interpolation_enum;
+ interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
+ interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
+ interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
+ interpolation_enum.insert("smart", INTERPOLATION_SMART);
+ SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
+
+ static NodeEnum projection_enum;
+ projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR);
+ projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL);
+ SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR);
+
+ SOCKET_BOOLEAN(animated, "Animated", false);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_POSITION);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
+
+EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(get_node_type())
+{
+ colorspace = u_colorspace_raw;
+ animated = false;
+}
+
+ShaderNode *EnvironmentTextureNode::clone(ShaderGraph *graph) const
+{
+ EnvironmentTextureNode *node = graph->create_node<EnvironmentTextureNode>(*this);
+ node->handle = handle;
+ return node;
+}
+
+ImageParams EnvironmentTextureNode::image_params() const
+{
+ ImageParams params;
+ params.animated = animated;
+ params.interpolation = interpolation;
+ params.extension = EXTENSION_REPEAT;
+ params.alpha_type = alpha_type;
+ params.colorspace = colorspace;
+ return params;
+}
+
+void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+#ifdef WITH_PTEX
+ if (shader->has_surface_link() && string_endswith(filename, ".ptx")) {
+ /* ptex */
+ attributes->add(ATTR_STD_PTEX_FACE_ID);
+ attributes->add(ATTR_STD_PTEX_UV);
+ }
+#endif
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void EnvironmentTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *alpha_out = output("Alpha");
+
+ if (handle.empty()) {
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params());
+ }
+
+ const ImageMetaData metadata = handle.metadata();
+ const bool compress_as_srgb = metadata.compress_as_srgb;
+ const ustring known_colorspace = metadata.colorspace;
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+ uint flags = 0;
+
+ if (compress_as_srgb) {
+ flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
+ }
+
+ compiler.add_node(NODE_TEX_ENVIRONMENT,
+ handle.svm_slot(),
+ compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(alpha_out),
+ flags),
+ projection);
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
+}
+
+void EnvironmentTextureNode::compile(OSLCompiler &compiler)
+{
+ if (handle.empty()) {
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params());
+ }
+
+ tex_mapping.compile(compiler);
+
+ const ImageMetaData metadata = handle.metadata();
+ const bool is_float = metadata.is_float();
+ const bool compress_as_srgb = metadata.compress_as_srgb;
+ const ustring known_colorspace = metadata.colorspace;
+
+ if (handle.svm_slot() == -1) {
+ compiler.parameter_texture(
+ "filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
+ }
+ else {
+ compiler.parameter_texture("filename", handle.svm_slot());
+ }
+
+ compiler.parameter(this, "projection");
+ compiler.parameter(this, "interpolation");
+ compiler.parameter("compress_as_srgb", compress_as_srgb);
+ compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
+ compiler.parameter("is_float", is_float);
+ compiler.add(this, "node_environment_texture");
+}
+
+/* Sky Texture */
+
+static float2 sky_spherical_coordinates(float3 dir)
+{
+ return make_float2(acosf(dir.z), atan2f(dir.x, dir.y));
+}
+
+typedef struct SunSky {
+ /* sun direction in spherical and cartesian */
+ float theta, phi;
+
+ /* Parameter */
+ float radiance_x, radiance_y, radiance_z;
+ float config_x[9], config_y[9], config_z[9], nishita_data[10];
+} SunSky;
+
+/* Preetham model */
+static float sky_perez_function(float lam[6], float theta, float gamma)
+{
+ return (1.0f + lam[0] * expf(lam[1] / cosf(theta))) *
+ (1.0f + lam[2] * expf(lam[3] * gamma) + lam[4] * cosf(gamma) * cosf(gamma));
+}
+
+static void sky_texture_precompute_preetham(SunSky *sunsky, float3 dir, float turbidity)
+{
+ /*
+ * We re-use the SunSky struct of the new model, to avoid extra variables
+ * zenith_Y/x/y is now radiance_x/y/z
+ * perez_Y/x/y is now config_x/y/z
+ */
+
+ float2 spherical = sky_spherical_coordinates(dir);
+ float theta = spherical.x;
+ float phi = spherical.y;
+
+ sunsky->theta = theta;
+ sunsky->phi = phi;
+
+ float theta2 = theta * theta;
+ float theta3 = theta2 * theta;
+ float T = turbidity;
+ float T2 = T * T;
+
+ float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI_F - 2.0f * theta);
+ sunsky->radiance_x = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
+ sunsky->radiance_x *= 0.06f;
+
+ sunsky->radiance_y = (0.00166f * theta3 - 0.00375f * theta2 + 0.00209f * theta) * T2 +
+ (-0.02903f * theta3 + 0.06377f * theta2 - 0.03202f * theta + 0.00394f) * T +
+ (0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * theta + 0.25886f);
+
+ sunsky->radiance_z = (0.00275f * theta3 - 0.00610f * theta2 + 0.00317f * theta) * T2 +
+ (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * theta + 0.00516f) * T +
+ (0.15346f * theta3 - 0.26756f * theta2 + 0.06670f * theta + 0.26688f);
+
+ sunsky->config_x[0] = (0.1787f * T - 1.4630f);
+ sunsky->config_x[1] = (-0.3554f * T + 0.4275f);
+ sunsky->config_x[2] = (-0.0227f * T + 5.3251f);
+ sunsky->config_x[3] = (0.1206f * T - 2.5771f);
+ sunsky->config_x[4] = (-0.0670f * T + 0.3703f);
+
+ sunsky->config_y[0] = (-0.0193f * T - 0.2592f);
+ sunsky->config_y[1] = (-0.0665f * T + 0.0008f);
+ sunsky->config_y[2] = (-0.0004f * T + 0.2125f);
+ sunsky->config_y[3] = (-0.0641f * T - 0.8989f);
+ sunsky->config_y[4] = (-0.0033f * T + 0.0452f);
+
+ sunsky->config_z[0] = (-0.0167f * T - 0.2608f);
+ sunsky->config_z[1] = (-0.0950f * T + 0.0092f);
+ sunsky->config_z[2] = (-0.0079f * T + 0.2102f);
+ sunsky->config_z[3] = (-0.0441f * T - 1.6537f);
+ sunsky->config_z[4] = (-0.0109f * T + 0.0529f);
+
+ /* unused for old sky model */
+ for (int i = 5; i < 9; i++) {
+ sunsky->config_x[i] = 0.0f;
+ sunsky->config_y[i] = 0.0f;
+ sunsky->config_z[i] = 0.0f;
+ }
+
+ sunsky->radiance_x /= sky_perez_function(sunsky->config_x, 0, theta);
+ sunsky->radiance_y /= sky_perez_function(sunsky->config_y, 0, theta);
+ sunsky->radiance_z /= sky_perez_function(sunsky->config_z, 0, theta);
+}
+
+/* Hosek / Wilkie */
+static void sky_texture_precompute_hosek(SunSky *sunsky,
+ float3 dir,
+ float turbidity,
+ float ground_albedo)
+{
+ /* Calculate Sun Direction and save coordinates */
+ float2 spherical = sky_spherical_coordinates(dir);
+ float theta = spherical.x;
+ float phi = spherical.y;
+
+ /* Clamp Turbidity */
+ turbidity = clamp(turbidity, 0.0f, 10.0f);
+
+ /* Clamp to Horizon */
+ theta = clamp(theta, 0.0f, M_PI_2_F);
+
+ sunsky->theta = theta;
+ sunsky->phi = phi;
+
+ float solarElevation = M_PI_2_F - theta;
+
+ /* Initialize Sky Model */
+ SKY_ArHosekSkyModelState *sky_state;
+ sky_state = SKY_arhosek_xyz_skymodelstate_alloc_init(
+ (double)turbidity, (double)ground_albedo, (double)solarElevation);
+
+ /* Copy values from sky_state to SunSky */
+ for (int i = 0; i < 9; ++i) {
+ sunsky->config_x[i] = (float)sky_state->configs[0][i];
+ sunsky->config_y[i] = (float)sky_state->configs[1][i];
+ sunsky->config_z[i] = (float)sky_state->configs[2][i];
+ }
+ sunsky->radiance_x = (float)sky_state->radiances[0];
+ sunsky->radiance_y = (float)sky_state->radiances[1];
+ sunsky->radiance_z = (float)sky_state->radiances[2];
+
+ /* Free sky_state */
+ SKY_arhosekskymodelstate_free(sky_state);
+}
+
+/* Nishita improved */
+static void sky_texture_precompute_nishita(SunSky *sunsky,
+ bool sun_disc,
+ float sun_size,
+ float sun_intensity,
+ float sun_elevation,
+ float sun_rotation,
+ float altitude,
+ float air_density,
+ float dust_density)
+{
+ /* sample 2 sun pixels */
+ float pixel_bottom[3];
+ float pixel_top[3];
+ SKY_nishita_skymodel_precompute_sun(
+ sun_elevation, sun_size, altitude, air_density, dust_density, pixel_bottom, pixel_top);
+ /* limit sun rotation between 0 and 360 degrees */
+ sun_rotation = fmodf(sun_rotation, M_2PI_F);
+ if (sun_rotation < 0.0f) {
+ sun_rotation += M_2PI_F;
+ }
+ sun_rotation = M_2PI_F - sun_rotation;
+ /* send data to svm_sky */
+ sunsky->nishita_data[0] = pixel_bottom[0];
+ sunsky->nishita_data[1] = pixel_bottom[1];
+ sunsky->nishita_data[2] = pixel_bottom[2];
+ sunsky->nishita_data[3] = pixel_top[0];
+ sunsky->nishita_data[4] = pixel_top[1];
+ sunsky->nishita_data[5] = pixel_top[2];
+ sunsky->nishita_data[6] = sun_elevation;
+ sunsky->nishita_data[7] = sun_rotation;
+ sunsky->nishita_data[8] = sun_disc ? sun_size : -1.0f;
+ sunsky->nishita_data[9] = sun_intensity;
+}
+
+NODE_DEFINE(SkyTextureNode)
+{
+ NodeType *type = NodeType::add("sky_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(SkyTextureNode);
+
+ static NodeEnum type_enum;
+ type_enum.insert("preetham", NODE_SKY_PREETHAM);
+ type_enum.insert("hosek_wilkie", NODE_SKY_HOSEK);
+ type_enum.insert("nishita_improved", NODE_SKY_NISHITA);
+ SOCKET_ENUM(sky_type, "Type", type_enum, NODE_SKY_NISHITA);
+
+ SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f));
+ SOCKET_FLOAT(turbidity, "Turbidity", 2.2f);
+ SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f);
+ SOCKET_BOOLEAN(sun_disc, "Sun Disc", true);
+ SOCKET_FLOAT(sun_size, "Sun Size", 0.009512f);
+ SOCKET_FLOAT(sun_intensity, "Sun Intensity", 1.0f);
+ SOCKET_FLOAT(sun_elevation, "Sun Elevation", 15.0f * M_PI_F / 180.0f);
+ SOCKET_FLOAT(sun_rotation, "Sun Rotation", 0.0f);
+ SOCKET_FLOAT(altitude, "Altitude", 1.0f);
+ SOCKET_FLOAT(air_density, "Air", 1.0f);
+ SOCKET_FLOAT(dust_density, "Dust", 1.0f);
+ SOCKET_FLOAT(ozone_density, "Ozone", 1.0f);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+SkyTextureNode::SkyTextureNode() : TextureNode(get_node_type())
+{
+}
+
+void SkyTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *color_out = output("Color");
+
+ SunSky sunsky;
+ if (sky_type == NODE_SKY_PREETHAM)
+ sky_texture_precompute_preetham(&sunsky, sun_direction, turbidity);
+ else if (sky_type == NODE_SKY_HOSEK)
+ sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
+ else if (sky_type == NODE_SKY_NISHITA) {
+ /* Clamp altitude to reasonable values.
+ * Below 1m causes numerical issues and above 60km is space. */
+ float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
+
+ sky_texture_precompute_nishita(&sunsky,
+ sun_disc,
+ get_sun_size(),
+ sun_intensity,
+ sun_elevation,
+ sun_rotation,
+ clamped_altitude,
+ air_density,
+ dust_density);
+ /* precomputed texture image parameters */
+ ImageManager *image_manager = compiler.scene->image_manager;
+ ImageParams impar;
+ impar.interpolation = INTERPOLATION_LINEAR;
+ impar.extension = EXTENSION_EXTEND;
+
+ /* precompute sky texture */
+ if (handle.empty()) {
+ SkyLoader *loader = new SkyLoader(
+ sun_elevation, clamped_altitude, air_density, dust_density, ozone_density);
+ handle = image_manager->add_image(loader, impar);
+ }
+ }
+ else
+ assert(false);
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+
+ compiler.stack_assign(color_out);
+ compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_type);
+ /* nishita doesn't need this data */
+ if (sky_type != NODE_SKY_NISHITA) {
+ compiler.add_node(__float_as_uint(sunsky.phi),
+ __float_as_uint(sunsky.theta),
+ __float_as_uint(sunsky.radiance_x),
+ __float_as_uint(sunsky.radiance_y));
+ compiler.add_node(__float_as_uint(sunsky.radiance_z),
+ __float_as_uint(sunsky.config_x[0]),
+ __float_as_uint(sunsky.config_x[1]),
+ __float_as_uint(sunsky.config_x[2]));
+ compiler.add_node(__float_as_uint(sunsky.config_x[3]),
+ __float_as_uint(sunsky.config_x[4]),
+ __float_as_uint(sunsky.config_x[5]),
+ __float_as_uint(sunsky.config_x[6]));
+ compiler.add_node(__float_as_uint(sunsky.config_x[7]),
+ __float_as_uint(sunsky.config_x[8]),
+ __float_as_uint(sunsky.config_y[0]),
+ __float_as_uint(sunsky.config_y[1]));
+ compiler.add_node(__float_as_uint(sunsky.config_y[2]),
+ __float_as_uint(sunsky.config_y[3]),
+ __float_as_uint(sunsky.config_y[4]),
+ __float_as_uint(sunsky.config_y[5]));
+ compiler.add_node(__float_as_uint(sunsky.config_y[6]),
+ __float_as_uint(sunsky.config_y[7]),
+ __float_as_uint(sunsky.config_y[8]),
+ __float_as_uint(sunsky.config_z[0]));
+ compiler.add_node(__float_as_uint(sunsky.config_z[1]),
+ __float_as_uint(sunsky.config_z[2]),
+ __float_as_uint(sunsky.config_z[3]),
+ __float_as_uint(sunsky.config_z[4]));
+ compiler.add_node(__float_as_uint(sunsky.config_z[5]),
+ __float_as_uint(sunsky.config_z[6]),
+ __float_as_uint(sunsky.config_z[7]),
+ __float_as_uint(sunsky.config_z[8]));
+ }
+ else {
+ compiler.add_node(__float_as_uint(sunsky.nishita_data[0]),
+ __float_as_uint(sunsky.nishita_data[1]),
+ __float_as_uint(sunsky.nishita_data[2]),
+ __float_as_uint(sunsky.nishita_data[3]));
+ compiler.add_node(__float_as_uint(sunsky.nishita_data[4]),
+ __float_as_uint(sunsky.nishita_data[5]),
+ __float_as_uint(sunsky.nishita_data[6]),
+ __float_as_uint(sunsky.nishita_data[7]));
+ compiler.add_node(__float_as_uint(sunsky.nishita_data[8]),
+ __float_as_uint(sunsky.nishita_data[9]),
+ handle.svm_slot(),
+ 0);
+ }
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
+}
+
+void SkyTextureNode::compile(OSLCompiler &compiler)
+{
+ tex_mapping.compile(compiler);
+
+ SunSky sunsky;
+ if (sky_type == NODE_SKY_PREETHAM)
+ sky_texture_precompute_preetham(&sunsky, sun_direction, turbidity);
+ else if (sky_type == NODE_SKY_HOSEK)
+ sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
+ else if (sky_type == NODE_SKY_NISHITA) {
+ /* Clamp altitude to reasonable values.
+ * Below 1m causes numerical issues and above 60km is space. */
+ float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
+
+ sky_texture_precompute_nishita(&sunsky,
+ sun_disc,
+ get_sun_size(),
+ sun_intensity,
+ sun_elevation,
+ sun_rotation,
+ clamped_altitude,
+ air_density,
+ dust_density);
+ /* precomputed texture image parameters */
+ ImageManager *image_manager = compiler.scene->image_manager;
+ ImageParams impar;
+ impar.interpolation = INTERPOLATION_LINEAR;
+ impar.extension = EXTENSION_EXTEND;
+
+ /* precompute sky texture */
+ if (handle.empty()) {
+ SkyLoader *loader = new SkyLoader(
+ sun_elevation, clamped_altitude, air_density, dust_density, ozone_density);
+ handle = image_manager->add_image(loader, impar);
+ }
+ }
+ else
+ assert(false);
+
+ compiler.parameter(this, "sky_type");
+ compiler.parameter("theta", sunsky.theta);
+ compiler.parameter("phi", sunsky.phi);
+ compiler.parameter_color("radiance",
+ make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z));
+ compiler.parameter_array("config_x", sunsky.config_x, 9);
+ compiler.parameter_array("config_y", sunsky.config_y, 9);
+ compiler.parameter_array("config_z", sunsky.config_z, 9);
+ compiler.parameter_array("nishita_data", sunsky.nishita_data, 10);
+ /* nishita texture */
+ if (sky_type == NODE_SKY_NISHITA) {
+ compiler.parameter_texture("filename", handle.svm_slot());
+ }
+ compiler.add(this, "node_sky_texture");
+}
+
+/* Gradient Texture */
+
+NODE_DEFINE(GradientTextureNode)
+{
+ NodeType *type = NodeType::add("gradient_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(GradientTextureNode);
+
+ static NodeEnum type_enum;
+ type_enum.insert("linear", NODE_BLEND_LINEAR);
+ type_enum.insert("quadratic", NODE_BLEND_QUADRATIC);
+ type_enum.insert("easing", NODE_BLEND_EASING);
+ type_enum.insert("diagonal", NODE_BLEND_DIAGONAL);
+ type_enum.insert("radial", NODE_BLEND_RADIAL);
+ type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE);
+ type_enum.insert("spherical", NODE_BLEND_SPHERICAL);
+ SOCKET_ENUM(gradient_type, "Type", type_enum, NODE_BLEND_LINEAR);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+GradientTextureNode::GradientTextureNode() : TextureNode(get_node_type())
+{
+}
+
+void GradientTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *fac_out = output("Fac");
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+
+ compiler.add_node(NODE_TEX_GRADIENT,
+ compiler.encode_uchar4(gradient_type,
+ vector_offset,
+ compiler.stack_assign_if_linked(fac_out),
+ compiler.stack_assign_if_linked(color_out)));
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
+}
+
+void GradientTextureNode::compile(OSLCompiler &compiler)
+{
+ tex_mapping.compile(compiler);
+
+ compiler.parameter(this, "gradient_type");
+ compiler.add(this, "node_gradient_texture");
+}
+
+/* Noise Texture */
+
+NODE_DEFINE(NoiseTextureNode)
+{
+ NodeType *type = NodeType::add("noise_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(NoiseTextureNode);
+
+ static NodeEnum dimensions_enum;
+ dimensions_enum.insert("1D", 1);
+ dimensions_enum.insert("2D", 2);
+ dimensions_enum.insert("3D", 3);
+ dimensions_enum.insert("4D", 4);
+ SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_FLOAT(w, "W", 0.0f);
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+ SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
+ SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
+
+ SOCKET_OUT_FLOAT(fac, "Fac");
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+NoiseTextureNode::NoiseTextureNode() : TextureNode(get_node_type())
+{
+}
+
+void NoiseTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *w_in = input("W");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *detail_in = input("Detail");
+ ShaderInput *roughness_in = input("Roughness");
+ ShaderInput *distortion_in = input("Distortion");
+ ShaderOutput *fac_out = output("Fac");
+ ShaderOutput *color_out = output("Color");
+
+ int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
+ int w_stack_offset = compiler.stack_assign_if_linked(w_in);
+ int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
+ int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
+ int roughness_stack_offset = compiler.stack_assign_if_linked(roughness_in);
+ int distortion_stack_offset = compiler.stack_assign_if_linked(distortion_in);
+ int fac_stack_offset = compiler.stack_assign_if_linked(fac_out);
+ int color_stack_offset = compiler.stack_assign_if_linked(color_out);
+
+ compiler.add_node(
+ NODE_TEX_NOISE,
+ dimensions,
+ compiler.encode_uchar4(
+ vector_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset),
+ compiler.encode_uchar4(
+ roughness_stack_offset, distortion_stack_offset, fac_stack_offset, color_stack_offset));
+ compiler.add_node(
+ __float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(roughness));
+
+ compiler.add_node(
+ __float_as_int(distortion), SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID);
+
+ tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
+}
+
+void NoiseTextureNode::compile(OSLCompiler &compiler)
+{
+ tex_mapping.compile(compiler);
+ compiler.parameter(this, "dimensions");
+ compiler.add(this, "node_noise_texture");
+}
+
+/* Voronoi Texture */
+
+NODE_DEFINE(VoronoiTextureNode)
+{
+ NodeType *type = NodeType::add("voronoi_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
+
+ static NodeEnum dimensions_enum;
+ dimensions_enum.insert("1D", 1);
+ dimensions_enum.insert("2D", 2);
+ dimensions_enum.insert("3D", 3);
+ dimensions_enum.insert("4D", 4);
+ SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
+
+ static NodeEnum metric_enum;
+ metric_enum.insert("euclidean", NODE_VORONOI_EUCLIDEAN);
+ metric_enum.insert("manhattan", NODE_VORONOI_MANHATTAN);
+ metric_enum.insert("chebychev", NODE_VORONOI_CHEBYCHEV);
+ metric_enum.insert("minkowski", NODE_VORONOI_MINKOWSKI);
+ SOCKET_ENUM(metric, "Distance Metric", metric_enum, NODE_VORONOI_EUCLIDEAN);
+
+ static NodeEnum feature_enum;
+ feature_enum.insert("f1", NODE_VORONOI_F1);
+ feature_enum.insert("f2", NODE_VORONOI_F2);
+ feature_enum.insert("smooth_f1", NODE_VORONOI_SMOOTH_F1);
+ feature_enum.insert("distance_to_edge", NODE_VORONOI_DISTANCE_TO_EDGE);
+ feature_enum.insert("n_sphere_radius", NODE_VORONOI_N_SPHERE_RADIUS);
+ SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_F1);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_FLOAT(w, "W", 0.0f);
+ SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
+ SOCKET_IN_FLOAT(smoothness, "Smoothness", 5.0f);
+ SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
+ SOCKET_IN_FLOAT(randomness, "Randomness", 1.0f);
+
+ SOCKET_OUT_FLOAT(distance, "Distance");
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_POINT(position, "Position");
+ SOCKET_OUT_FLOAT(w, "W");
+ SOCKET_OUT_FLOAT(radius, "Radius");
+
+ return type;
+}
+
+VoronoiTextureNode::VoronoiTextureNode() : TextureNode(get_node_type())
+{
+}
+
+void VoronoiTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *w_in = input("W");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *smoothness_in = input("Smoothness");
+ ShaderInput *exponent_in = input("Exponent");
+ ShaderInput *randomness_in = input("Randomness");
+
+ ShaderOutput *distance_out = output("Distance");
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *position_out = output("Position");
+ ShaderOutput *w_out = output("W");
+ ShaderOutput *radius_out = output("Radius");
+
+ int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
+ int w_in_stack_offset = compiler.stack_assign_if_linked(w_in);
+ int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
+ int smoothness_stack_offset = compiler.stack_assign_if_linked(smoothness_in);
+ int exponent_stack_offset = compiler.stack_assign_if_linked(exponent_in);
+ int randomness_stack_offset = compiler.stack_assign_if_linked(randomness_in);
+ int distance_stack_offset = compiler.stack_assign_if_linked(distance_out);
+ int color_stack_offset = compiler.stack_assign_if_linked(color_out);
+ int position_stack_offset = compiler.stack_assign_if_linked(position_out);
+ int w_out_stack_offset = compiler.stack_assign_if_linked(w_out);
+ int radius_stack_offset = compiler.stack_assign_if_linked(radius_out);
+
+ compiler.add_node(NODE_TEX_VORONOI, dimensions, feature, metric);
+ compiler.add_node(
+ compiler.encode_uchar4(
+ vector_stack_offset, w_in_stack_offset, scale_stack_offset, smoothness_stack_offset),
+ compiler.encode_uchar4(exponent_stack_offset,
+ randomness_stack_offset,
+ distance_stack_offset,
+ color_stack_offset),
+ compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset),
+ __float_as_int(w));
+
+ compiler.add_node(__float_as_int(scale),
+ __float_as_int(smoothness),
+ __float_as_int(exponent),
+ __float_as_int(randomness));
+
+ tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
+}
+
+void VoronoiTextureNode::compile(OSLCompiler &compiler)
+{
+ tex_mapping.compile(compiler);
+
+ compiler.parameter(this, "dimensions");
+ compiler.parameter(this, "feature");
+ compiler.parameter(this, "metric");
+ compiler.add(this, "node_voronoi_texture");
+}
+
+/* IES Light */
+
+NODE_DEFINE(IESLightNode)
+{
+ NodeType *type = NodeType::add("ies_light", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(IESLightNode);
+
+ SOCKET_STRING(ies, "IES", ustring());
+ SOCKET_STRING(filename, "File Name", ustring());
+
+ SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_NORMAL);
+
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+IESLightNode::IESLightNode() : TextureNode(get_node_type())
+{
+ light_manager = NULL;
+ slot = -1;
+}
+
+ShaderNode *IESLightNode::clone(ShaderGraph *graph) const
+{
+ IESLightNode *node = graph->create_node<IESLightNode>(*this);
+
+ node->light_manager = NULL;
+ node->slot = -1;
+
+ return node;
+}
+
+IESLightNode::~IESLightNode()
+{
+ if (light_manager) {
+ light_manager->remove_ies(slot);
+ }
+}
+
+void IESLightNode::get_slot()
+{
+ assert(light_manager);
+
+ if (slot == -1) {
+ if (ies.empty()) {
+ slot = light_manager->add_ies_from_file(filename.string());
+ }
+ else {
+ slot = light_manager->add_ies(ies.string());
+ }
+ }
+}
+
+void IESLightNode::compile(SVMCompiler &compiler)
+{
+ light_manager = compiler.scene->light_manager;
+ get_slot();
+
+ ShaderInput *strength_in = input("Strength");
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *fac_out = output("Fac");
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+
+ compiler.add_node(NODE_IES,
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(strength_in),
+ vector_offset,
+ compiler.stack_assign(fac_out),
+ 0),
+ slot,
+ __float_as_int(strength));
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
+}
+
+void IESLightNode::compile(OSLCompiler &compiler)
+{
+ light_manager = compiler.scene->light_manager;
+ get_slot();
+
+ tex_mapping.compile(compiler);
+
+ compiler.parameter_texture_ies("filename", slot);
+ compiler.add(this, "node_ies_light");
+}
+
+/* White Noise Texture */
+
+NODE_DEFINE(WhiteNoiseTextureNode)
+{
+ NodeType *type = NodeType::add("white_noise_texture", create, NodeType::SHADER);
+
+ static NodeEnum dimensions_enum;
+ dimensions_enum.insert("1D", 1);
+ dimensions_enum.insert("2D", 2);
+ dimensions_enum.insert("3D", 3);
+ dimensions_enum.insert("4D", 4);
+ SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3());
+ SOCKET_IN_FLOAT(w, "W", 0.0f);
+
+ SOCKET_OUT_FLOAT(value, "Value");
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+WhiteNoiseTextureNode::WhiteNoiseTextureNode() : ShaderNode(get_node_type())
+{
+}
+
+void WhiteNoiseTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *w_in = input("W");
+ ShaderOutput *value_out = output("Value");
+ ShaderOutput *color_out = output("Color");
+
+ int vector_stack_offset = compiler.stack_assign(vector_in);
+ int w_stack_offset = compiler.stack_assign(w_in);
+ int value_stack_offset = compiler.stack_assign(value_out);
+ int color_stack_offset = compiler.stack_assign(color_out);
+
+ compiler.add_node(NODE_TEX_WHITE_NOISE,
+ dimensions,
+ compiler.encode_uchar4(vector_stack_offset, w_stack_offset),
+ compiler.encode_uchar4(value_stack_offset, color_stack_offset));
+}
+
+void WhiteNoiseTextureNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "dimensions");
+ compiler.add(this, "node_white_noise_texture");
+}
+
+/* Musgrave Texture */
+
+NODE_DEFINE(MusgraveTextureNode)
+{
+ NodeType *type = NodeType::add("musgrave_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(MusgraveTextureNode);
+
+ static NodeEnum dimensions_enum;
+ dimensions_enum.insert("1D", 1);
+ dimensions_enum.insert("2D", 2);
+ dimensions_enum.insert("3D", 3);
+ dimensions_enum.insert("4D", 4);
+ SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
+
+ static NodeEnum type_enum;
+ type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
+ type_enum.insert("fBM", NODE_MUSGRAVE_FBM);
+ type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL);
+ type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL);
+ type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
+ SOCKET_ENUM(musgrave_type, "Type", type_enum, NODE_MUSGRAVE_FBM);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_FLOAT(w, "W", 0.0f);
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+ SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
+ SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f);
+ SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 2.0f);
+ SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
+ SOCKET_IN_FLOAT(gain, "Gain", 1.0f);
+
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+MusgraveTextureNode::MusgraveTextureNode() : TextureNode(get_node_type())
+{
+}
+
+void MusgraveTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *w_in = input("W");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *detail_in = input("Detail");
+ ShaderInput *dimension_in = input("Dimension");
+ ShaderInput *lacunarity_in = input("Lacunarity");
+ ShaderInput *offset_in = input("Offset");
+ ShaderInput *gain_in = input("Gain");
+ ShaderOutput *fac_out = output("Fac");
+
+ int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
+ int w_stack_offset = compiler.stack_assign_if_linked(w_in);
+ int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
+ int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
+ int dimension_stack_offset = compiler.stack_assign_if_linked(dimension_in);
+ int lacunarity_stack_offset = compiler.stack_assign_if_linked(lacunarity_in);
+ int offset_stack_offset = compiler.stack_assign_if_linked(offset_in);
+ int gain_stack_offset = compiler.stack_assign_if_linked(gain_in);
+ int fac_stack_offset = compiler.stack_assign(fac_out);
+
+ compiler.add_node(
+ NODE_TEX_MUSGRAVE,
+ compiler.encode_uchar4(musgrave_type, dimensions, vector_stack_offset, w_stack_offset),
+ compiler.encode_uchar4(scale_stack_offset,
+ detail_stack_offset,
+ dimension_stack_offset,
+ lacunarity_stack_offset),
+ compiler.encode_uchar4(offset_stack_offset, gain_stack_offset, fac_stack_offset));
+ compiler.add_node(
+ __float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(dimension));
+ compiler.add_node(__float_as_int(lacunarity), __float_as_int(offset), __float_as_int(gain));
+
+ tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
+}
+
+void MusgraveTextureNode::compile(OSLCompiler &compiler)
+{
+ tex_mapping.compile(compiler);
+
+ compiler.parameter(this, "musgrave_type");
+ compiler.parameter(this, "dimensions");
+ compiler.add(this, "node_musgrave_texture");
+}
+
+/* Wave Texture */
+
+NODE_DEFINE(WaveTextureNode)
+{
+ NodeType *type = NodeType::add("wave_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(WaveTextureNode);
+
+ static NodeEnum type_enum;
+ type_enum.insert("bands", NODE_WAVE_BANDS);
+ type_enum.insert("rings", NODE_WAVE_RINGS);
+ SOCKET_ENUM(wave_type, "Type", type_enum, NODE_WAVE_BANDS);
+
+ static NodeEnum bands_direction_enum;
+ bands_direction_enum.insert("x", NODE_WAVE_BANDS_DIRECTION_X);
+ bands_direction_enum.insert("y", NODE_WAVE_BANDS_DIRECTION_Y);
+ bands_direction_enum.insert("z", NODE_WAVE_BANDS_DIRECTION_Z);
+ bands_direction_enum.insert("diagonal", NODE_WAVE_BANDS_DIRECTION_DIAGONAL);
+ SOCKET_ENUM(
+ bands_direction, "Bands Direction", bands_direction_enum, NODE_WAVE_BANDS_DIRECTION_X);
+
+ static NodeEnum rings_direction_enum;
+ rings_direction_enum.insert("x", NODE_WAVE_RINGS_DIRECTION_X);
+ rings_direction_enum.insert("y", NODE_WAVE_RINGS_DIRECTION_Y);
+ rings_direction_enum.insert("z", NODE_WAVE_RINGS_DIRECTION_Z);
+ rings_direction_enum.insert("spherical", NODE_WAVE_RINGS_DIRECTION_SPHERICAL);
+ SOCKET_ENUM(
+ rings_direction, "Rings Direction", rings_direction_enum, NODE_WAVE_BANDS_DIRECTION_X);
+
+ static NodeEnum profile_enum;
+ profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN);
+ profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW);
+ profile_enum.insert("tri", NODE_WAVE_PROFILE_TRI);
+ SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+ SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
+ SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
+ SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f);
+ SOCKET_IN_FLOAT(detail_roughness, "Detail Roughness", 0.5f);
+ SOCKET_IN_FLOAT(phase, "Phase Offset", 0.0f);
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+WaveTextureNode::WaveTextureNode() : TextureNode(get_node_type())
+{
+}
+
+void WaveTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *distortion_in = input("Distortion");
+ ShaderInput *detail_in = input("Detail");
+ ShaderInput *dscale_in = input("Detail Scale");
+ ShaderInput *droughness_in = input("Detail Roughness");
+ ShaderInput *phase_in = input("Phase Offset");
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *fac_out = output("Fac");
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+
+ compiler.add_node(NODE_TEX_WAVE,
+ compiler.encode_uchar4(wave_type, bands_direction, rings_direction, profile),
+ compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign_if_linked(scale_in),
+ compiler.stack_assign_if_linked(distortion_in)),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(detail_in),
+ compiler.stack_assign_if_linked(dscale_in),
+ compiler.stack_assign_if_linked(droughness_in),
+ compiler.stack_assign_if_linked(phase_in)));
+
+ compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(fac_out)),
+ __float_as_int(scale),
+ __float_as_int(distortion),
+ __float_as_int(detail));
+
+ compiler.add_node(__float_as_int(detail_scale),
+ __float_as_int(detail_roughness),
+ __float_as_int(phase),
+ SVM_STACK_INVALID);
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
+}
+
+void WaveTextureNode::compile(OSLCompiler &compiler)
+{
+ tex_mapping.compile(compiler);
+
+ compiler.parameter(this, "wave_type");
+ compiler.parameter(this, "bands_direction");
+ compiler.parameter(this, "rings_direction");
+ compiler.parameter(this, "profile");
+
+ compiler.add(this, "node_wave_texture");
+}
+
+/* Magic Texture */
+
+NODE_DEFINE(MagicTextureNode)
+{
+ NodeType *type = NodeType::add("magic_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(MagicTextureNode);
+
+ SOCKET_INT(depth, "Depth", 2);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
+ SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+MagicTextureNode::MagicTextureNode() : TextureNode(get_node_type())
+{
+}
+
+void MagicTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *distortion_in = input("Distortion");
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *fac_out = output("Fac");
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+
+ compiler.add_node(NODE_TEX_MAGIC,
+ compiler.encode_uchar4(depth,
+ compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(fac_out)),
+ compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign_if_linked(scale_in),
+ compiler.stack_assign_if_linked(distortion_in)));
+ compiler.add_node(__float_as_int(scale), __float_as_int(distortion));
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
+}
+
+void MagicTextureNode::compile(OSLCompiler &compiler)
+{
+ tex_mapping.compile(compiler);
+
+ compiler.parameter(this, "depth");
+ compiler.add(this, "node_magic_texture");
+}
+
+/* Checker Texture */
+
+NODE_DEFINE(CheckerTextureNode)
+{
+ NodeType *type = NodeType::add("checker_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(CheckerTextureNode);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_COLOR(color1, "Color1", zero_float3());
+ SOCKET_IN_COLOR(color2, "Color2", zero_float3());
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+CheckerTextureNode::CheckerTextureNode() : TextureNode(get_node_type())
+{
+}
+
+void CheckerTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *color1_in = input("Color1");
+ ShaderInput *color2_in = input("Color2");
+ ShaderInput *scale_in = input("Scale");
+
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *fac_out = output("Fac");
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+
+ compiler.add_node(NODE_TEX_CHECKER,
+ compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign(color1_in),
+ compiler.stack_assign(color2_in),
+ compiler.stack_assign_if_linked(scale_in)),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(fac_out)),
+ __float_as_int(scale));
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
+}
+
+void CheckerTextureNode::compile(OSLCompiler &compiler)
+{
+ tex_mapping.compile(compiler);
+
+ compiler.add(this, "node_checker_texture");
+}
+
+/* Brick Texture */
+
+NODE_DEFINE(BrickTextureNode)
+{
+ NodeType *type = NodeType::add("brick_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(BrickTextureNode);
+
+ SOCKET_FLOAT(offset, "Offset", 0.5f);
+ SOCKET_INT(offset_frequency, "Offset Frequency", 2);
+ SOCKET_FLOAT(squash, "Squash", 1.0f);
+ SOCKET_INT(squash_frequency, "Squash Frequency", 2);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
+
+ SOCKET_IN_COLOR(color1, "Color1", zero_float3());
+ SOCKET_IN_COLOR(color2, "Color2", zero_float3());
+ SOCKET_IN_COLOR(mortar, "Mortar", zero_float3());
+ SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
+ SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f);
+ SOCKET_IN_FLOAT(mortar_smooth, "Mortar Smooth", 0.0f);
+ SOCKET_IN_FLOAT(bias, "Bias", 0.0f);
+ SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f);
+ SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+BrickTextureNode::BrickTextureNode() : TextureNode(get_node_type())
+{
+}
+
+void BrickTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *color1_in = input("Color1");
+ ShaderInput *color2_in = input("Color2");
+ ShaderInput *mortar_in = input("Mortar");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *mortar_size_in = input("Mortar Size");
+ ShaderInput *mortar_smooth_in = input("Mortar Smooth");
+ ShaderInput *bias_in = input("Bias");
+ ShaderInput *brick_width_in = input("Brick Width");
+ ShaderInput *row_height_in = input("Row Height");
+
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *fac_out = output("Fac");
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+
+ compiler.add_node(NODE_TEX_BRICK,
+ compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign(color1_in),
+ compiler.stack_assign(color2_in),
+ compiler.stack_assign(mortar_in)),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(scale_in),
+ compiler.stack_assign_if_linked(mortar_size_in),
+ compiler.stack_assign_if_linked(bias_in),
+ compiler.stack_assign_if_linked(brick_width_in)),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(row_height_in),
+ compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(fac_out),
+ compiler.stack_assign_if_linked(mortar_smooth_in)));
+
+ compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
+ __float_as_int(scale),
+ __float_as_int(mortar_size),
+ __float_as_int(bias));
+
+ compiler.add_node(__float_as_int(brick_width),
+ __float_as_int(row_height),
+ __float_as_int(offset),
+ __float_as_int(squash));
+
+ compiler.add_node(
+ __float_as_int(mortar_smooth), SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID);
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
+}
+
+void BrickTextureNode::compile(OSLCompiler &compiler)
+{
+ tex_mapping.compile(compiler);
+
+ compiler.parameter(this, "offset");
+ compiler.parameter(this, "offset_frequency");
+ compiler.parameter(this, "squash");
+ compiler.parameter(this, "squash_frequency");
+ compiler.add(this, "node_brick_texture");
+}
+
+/* Point Density Texture */
+
+NODE_DEFINE(PointDensityTextureNode)
+{
+ NodeType *type = NodeType::add("point_density_texture", create, NodeType::SHADER);
+
+ SOCKET_STRING(filename, "Filename", ustring());
+
+ static NodeEnum space_enum;
+ space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT);
+ space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD);
+ SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT);
+
+ static NodeEnum interpolation_enum;
+ interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
+ interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
+ interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
+ interpolation_enum.insert("smart", INTERPOLATION_SMART);
+ SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
+
+ SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_POSITION);
+
+ SOCKET_OUT_FLOAT(density, "Density");
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+PointDensityTextureNode::PointDensityTextureNode() : ShaderNode(get_node_type())
+{
+}
+
+PointDensityTextureNode::~PointDensityTextureNode()
+{
+}
+
+ShaderNode *PointDensityTextureNode::clone(ShaderGraph *graph) const
+{
+ /* Increase image user count for new node. We need to ensure to not call
+ * add_image again, to work around access of freed data on the Blender
+ * side. A better solution should be found to avoid this. */
+ PointDensityTextureNode *node = graph->create_node<PointDensityTextureNode>(*this);
+ node->handle = handle; /* TODO: not needed? */
+ return node;
+}
+
+void PointDensityTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_volume)
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+ImageParams PointDensityTextureNode::image_params() const
+{
+ ImageParams params;
+ params.interpolation = interpolation;
+ return params;
+}
+
+void PointDensityTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *density_out = output("Density");
+ ShaderOutput *color_out = output("Color");
+
+ const bool use_density = !density_out->links.empty();
+ const bool use_color = !color_out->links.empty();
+
+ if (use_density || use_color) {
+ if (handle.empty()) {
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params());
+ }
+
+ const int slot = handle.svm_slot();
+ if (slot != -1) {
+ compiler.stack_assign(vector_in);
+ compiler.add_node(NODE_TEX_VOXEL,
+ slot,
+ compiler.encode_uchar4(compiler.stack_assign(vector_in),
+ compiler.stack_assign_if_linked(density_out),
+ compiler.stack_assign_if_linked(color_out),
+ space));
+ if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
+ compiler.add_node(tfm.x);
+ compiler.add_node(tfm.y);
+ compiler.add_node(tfm.z);
+ }
+ }
+ else {
+ if (use_density) {
+ compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(density_out));
+ }
+ if (use_color) {
+ compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
+ compiler.add_node(
+ NODE_VALUE_V,
+ make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B));
+ }
+ }
+ }
+}
+
+void PointDensityTextureNode::compile(OSLCompiler &compiler)
+{
+ ShaderOutput *density_out = output("Density");
+ ShaderOutput *color_out = output("Color");
+
+ const bool use_density = !density_out->links.empty();
+ const bool use_color = !color_out->links.empty();
+
+ if (use_density || use_color) {
+ if (handle.empty()) {
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params());
+ }
+
+ compiler.parameter_texture("filename", handle.svm_slot());
+ if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
+ compiler.parameter("mapping", tfm);
+ compiler.parameter("use_mapping", 1);
+ }
+ compiler.parameter(this, "interpolation");
+ compiler.add(this, "node_voxel_texture");
+ }
+}
+
+/* Normal */
+
+NODE_DEFINE(NormalNode)
+{
+ NodeType *type = NodeType::add("normal", create, NodeType::SHADER);
+
+ SOCKET_VECTOR(direction, "direction", zero_float3());
+
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3());
+
+ SOCKET_OUT_NORMAL(normal, "Normal");
+ SOCKET_OUT_FLOAT(dot, "Dot");
+
+ return type;
+}
+
+NormalNode::NormalNode() : ShaderNode(get_node_type())
+{
+}
+
+void NormalNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *normal_in = input("Normal");
+ ShaderOutput *normal_out = output("Normal");
+ ShaderOutput *dot_out = output("Dot");
+
+ compiler.add_node(NODE_NORMAL,
+ compiler.stack_assign(normal_in),
+ compiler.stack_assign(normal_out),
+ compiler.stack_assign(dot_out));
+ compiler.add_node(
+ __float_as_int(direction.x), __float_as_int(direction.y), __float_as_int(direction.z));
+}
+
+void NormalNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "direction");
+ compiler.add(this, "node_normal");
+}
+
+/* Mapping */
+
+NODE_DEFINE(MappingNode)
+{
+ NodeType *type = NodeType::add("mapping", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("point", NODE_MAPPING_TYPE_POINT);
+ type_enum.insert("texture", NODE_MAPPING_TYPE_TEXTURE);
+ type_enum.insert("vector", NODE_MAPPING_TYPE_VECTOR);
+ type_enum.insert("normal", NODE_MAPPING_TYPE_NORMAL);
+ SOCKET_ENUM(mapping_type, "Type", type_enum, NODE_MAPPING_TYPE_POINT);
+
+ SOCKET_IN_POINT(vector, "Vector", zero_float3());
+ SOCKET_IN_POINT(location, "Location", zero_float3());
+ SOCKET_IN_POINT(rotation, "Rotation", zero_float3());
+ SOCKET_IN_POINT(scale, "Scale", one_float3());
+
+ SOCKET_OUT_POINT(vector, "Vector");
+
+ return type;
+}
+
+MappingNode::MappingNode() : ShaderNode(get_node_type())
+{
+}
+
+void MappingNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ float3 result = svm_mapping((NodeMappingType)mapping_type, vector, location, rotation, scale);
+ folder.make_constant(result);
+ }
+ else {
+ folder.fold_mapping((NodeMappingType)mapping_type);
+ }
+}
+
+void MappingNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *location_in = input("Location");
+ ShaderInput *rotation_in = input("Rotation");
+ ShaderInput *scale_in = input("Scale");
+ ShaderOutput *vector_out = output("Vector");
+
+ int vector_stack_offset = compiler.stack_assign(vector_in);
+ int location_stack_offset = compiler.stack_assign(location_in);
+ int rotation_stack_offset = compiler.stack_assign(rotation_in);
+ int scale_stack_offset = compiler.stack_assign(scale_in);
+ int result_stack_offset = compiler.stack_assign(vector_out);
+
+ compiler.add_node(
+ NODE_MAPPING,
+ mapping_type,
+ compiler.encode_uchar4(
+ vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset),
+ result_stack_offset);
+}
+
+void MappingNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "mapping_type");
+ compiler.add(this, "node_mapping");
+}
+
+/* RGBToBW */
+
+NODE_DEFINE(RGBToBWNode)
+{
+ NodeType *type = NodeType::add("rgb_to_bw", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", zero_float3());
+ SOCKET_OUT_FLOAT(val, "Val");
+
+ return type;
+}
+
+RGBToBWNode::RGBToBWNode() : ShaderNode(get_node_type())
+{
+}
+
+void RGBToBWNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ float val = folder.scene->shader_manager->linear_rgb_to_gray(color);
+ folder.make_constant(val);
+ }
+}
+
+void RGBToBWNode::compile(SVMCompiler &compiler)
+{
+ compiler.add_node(NODE_CONVERT,
+ NODE_CONVERT_CF,
+ compiler.stack_assign(inputs[0]),
+ compiler.stack_assign(outputs[0]));
+}
+
+void RGBToBWNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_rgb_to_bw");
+}
+
+/* Convert */
+
+const NodeType *ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE];
+bool ConvertNode::initialized = ConvertNode::register_types();
+
+Node *ConvertNode::create(const NodeType *type)
+{
+ return new ConvertNode(type->inputs[0].type, type->outputs[0].type);
+}
+
+bool ConvertNode::register_types()
+{
+ const int num_types = 8;
+ SocketType::Type types[num_types] = {SocketType::FLOAT,
+ SocketType::INT,
+ SocketType::COLOR,
+ SocketType::VECTOR,
+ SocketType::POINT,
+ SocketType::NORMAL,
+ SocketType::STRING,
+ SocketType::CLOSURE};
+
+ for (size_t i = 0; i < num_types; i++) {
+ SocketType::Type from = types[i];
+ ustring from_name(SocketType::type_name(from));
+ ustring from_value_name("value_" + from_name.string());
+
+ for (size_t j = 0; j < num_types; j++) {
+ SocketType::Type to = types[j];
+ ustring to_name(SocketType::type_name(to));
+ ustring to_value_name("value_" + to_name.string());
+
+ string node_name = "convert_" + from_name.string() + "_to_" + to_name.string();
+ NodeType *type = NodeType::add(node_name.c_str(), create, NodeType::SHADER);
+
+ type->register_input(from_value_name,
+ from_value_name,
+ from,
+ SOCKET_OFFSETOF(ConvertNode, value_float),
+ SocketType::zero_default_value(),
+ NULL,
+ NULL,
+ SocketType::LINKABLE);
+ type->register_output(to_value_name, to_value_name, to);
+
+ assert(from < MAX_TYPE);
+ assert(to < MAX_TYPE);
+
+ node_types[from][to] = type;
+ }
+ }
+
+ return true;
+}
+
+ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert)
+ : ShaderNode(node_types[from_][to_])
+{
+ from = from_;
+ to = to_;
+
+ if (from == to)
+ special_type = SHADER_SPECIAL_TYPE_PROXY;
+ else if (autoconvert)
+ special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
+}
+
+/* Union usage requires a manual copy constructor. */
+ConvertNode::ConvertNode(const ConvertNode &other)
+ : ShaderNode(other),
+ from(other.from),
+ to(other.to),
+ value_color(other.value_color),
+ value_string(other.value_string)
+{
+}
+
+void ConvertNode::constant_fold(const ConstantFolder &folder)
+{
+ /* proxy nodes should have been removed at this point */
+ assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
+
+ /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
+
+ if (folder.all_inputs_constant()) {
+ if (from == SocketType::FLOAT) {
+ if (SocketType::is_float3(to)) {
+ folder.make_constant(make_float3(value_float, value_float, value_float));
+ }
+ }
+ else if (SocketType::is_float3(from)) {
+ if (to == SocketType::FLOAT) {
+ if (from == SocketType::COLOR) {
+ /* color to float */
+ float val = folder.scene->shader_manager->linear_rgb_to_gray(value_color);
+ folder.make_constant(val);
+ }
+ else {
+ /* vector/point/normal to float */
+ folder.make_constant(average(value_vector));
+ }
+ }
+ else if (SocketType::is_float3(to)) {
+ folder.make_constant(value_color);
+ }
+ }
+ }
+ else {
+ ShaderInput *in = inputs[0];
+ ShaderNode *prev = in->link->parent;
+
+ /* no-op conversion of A to B to A */
+ if (prev->type == node_types[to][from]) {
+ ShaderInput *prev_in = prev->inputs[0];
+
+ if (SocketType::is_float3(from) && (to == SocketType::FLOAT || SocketType::is_float3(to)) &&
+ prev_in->link) {
+ folder.bypass(prev_in->link);
+ }
+ }
+ }
+}
+
+void ConvertNode::compile(SVMCompiler &compiler)
+{
+ /* proxy nodes should have been removed at this point */
+ assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
+
+ ShaderInput *in = inputs[0];
+ ShaderOutput *out = outputs[0];
+
+ if (from == SocketType::FLOAT) {
+ if (to == SocketType::INT)
+ /* float to int */
+ compiler.add_node(
+ NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out));
+ else
+ /* float to float3 */
+ compiler.add_node(
+ NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out));
+ }
+ else if (from == SocketType::INT) {
+ if (to == SocketType::FLOAT)
+ /* int to float */
+ compiler.add_node(
+ NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out));
+ else
+ /* int to vector/point/normal */
+ compiler.add_node(
+ NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out));
+ }
+ else if (to == SocketType::FLOAT) {
+ if (from == SocketType::COLOR)
+ /* color to float */
+ compiler.add_node(
+ NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out));
+ else
+ /* vector/point/normal to float */
+ compiler.add_node(
+ NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out));
+ }
+ else if (to == SocketType::INT) {
+ if (from == SocketType::COLOR)
+ /* color to int */
+ compiler.add_node(
+ NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out));
+ else
+ /* vector/point/normal to int */
+ compiler.add_node(
+ NODE_CONVERT, NODE_CONVERT_VI, compiler.stack_assign(in), compiler.stack_assign(out));
+ }
+ else {
+ /* float3 to float3 */
+ if (in->link) {
+ /* no op in SVM */
+ compiler.stack_link(in, out);
+ }
+ else {
+ /* set 0,0,0 value */
+ compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out));
+ compiler.add_node(NODE_VALUE_V, value_color);
+ }
+ }
+}
+
+void ConvertNode::compile(OSLCompiler &compiler)
+{
+ /* proxy nodes should have been removed at this point */
+ assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
+
+ if (from == SocketType::FLOAT)
+ compiler.add(this, "node_convert_from_float");
+ else if (from == SocketType::INT)
+ compiler.add(this, "node_convert_from_int");
+ else if (from == SocketType::COLOR)
+ compiler.add(this, "node_convert_from_color");
+ else if (from == SocketType::VECTOR)
+ compiler.add(this, "node_convert_from_vector");
+ else if (from == SocketType::POINT)
+ compiler.add(this, "node_convert_from_point");
+ else if (from == SocketType::NORMAL)
+ compiler.add(this, "node_convert_from_normal");
+ else
+ assert(0);
+}
+
+/* Base type for all closure-type nodes */
+
+BsdfBaseNode::BsdfBaseNode(const NodeType *node_type) : ShaderNode(node_type)
+{
+ special_type = SHADER_SPECIAL_TYPE_CLOSURE;
+}
+
+bool BsdfBaseNode::has_bump()
+{
+ /* detect if anything is plugged into the normal input besides the default */
+ ShaderInput *normal_in = input("Normal");
+ return (normal_in && normal_in->link &&
+ normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY);
+}
+
+/* BSDF Closure */
+
+BsdfNode::BsdfNode(const NodeType *node_type) : BsdfBaseNode(node_type)
+{
+}
+
+void BsdfNode::compile(SVMCompiler &compiler,
+ ShaderInput *param1,
+ ShaderInput *param2,
+ ShaderInput *param3,
+ ShaderInput *param4)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *normal_in = input("Normal");
+ ShaderInput *tangent_in = input("Tangent");
+
+ if (color_in->link)
+ compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
+ else
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
+
+ int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID;
+ int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) :
+ SVM_STACK_INVALID;
+ int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID;
+ int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID;
+
+ compiler.add_node(
+ NODE_CLOSURE_BSDF,
+ compiler.encode_uchar4(closure,
+ (param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID,
+ (param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID,
+ compiler.closure_mix_weight_offset()),
+ __float_as_int((param1) ? get_float(param1->socket_type) : 0.0f),
+ __float_as_int((param2) ? get_float(param2->socket_type) : 0.0f));
+
+ compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset);
+}
+
+void BsdfNode::compile(SVMCompiler &compiler)
+{
+ compile(compiler, NULL, NULL);
+}
+
+void BsdfNode::compile(OSLCompiler & /*compiler*/)
+{
+ assert(0);
+}
+
+/* Anisotropic BSDF Closure */
+
+NODE_DEFINE(AnisotropicBsdfNode)
+{
+ NodeType *type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ static NodeEnum distribution_enum;
+ distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
+ distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
+ distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
+ distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
+ SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
+
+ SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
+
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
+ SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f);
+ SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+AnisotropicBsdfNode::AnisotropicBsdfNode() : BsdfNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
+}
+
+void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_surface_link()) {
+ ShaderInput *tangent_in = input("Tangent");
+
+ if (!tangent_in->link)
+ attributes->add(ATTR_STD_GENERATED);
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void AnisotropicBsdfNode::compile(SVMCompiler &compiler)
+{
+ closure = distribution;
+
+ if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
+ BsdfNode::compile(
+ compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
+ else
+ BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
+}
+
+void AnisotropicBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "distribution");
+ compiler.add(this, "node_anisotropic_bsdf");
+}
+
+/* Glossy BSDF Closure */
+
+NODE_DEFINE(GlossyBsdfNode)
+{
+ NodeType *type = NodeType::add("glossy_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ static NodeEnum distribution_enum;
+ distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID);
+ distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
+ distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
+ distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
+ distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
+ SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+GlossyBsdfNode::GlossyBsdfNode() : BsdfNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
+ distribution_orig = NBUILTIN_CLOSURES;
+}
+
+void GlossyBsdfNode::simplify_settings(Scene *scene)
+{
+ if (distribution_orig == NBUILTIN_CLOSURES) {
+ roughness_orig = roughness;
+ distribution_orig = distribution;
+ }
+ else {
+ /* By default we use original values, so we don't worry about restoring
+ * defaults later one and can only do override when needed.
+ */
+ roughness = roughness_orig;
+ distribution = distribution_orig;
+ }
+ Integrator *integrator = scene->integrator;
+ ShaderInput *roughness_input = input("Roughness");
+ if (integrator->get_filter_glossy() == 0.0f) {
+ /* Fallback to Sharp closure for Roughness close to 0.
+ * Note: Keep the epsilon in sync with kernel!
+ */
+ if (!roughness_input->link && roughness <= 1e-4f) {
+ VLOG(1) << "Using sharp glossy BSDF.";
+ distribution = CLOSURE_BSDF_REFLECTION_ID;
+ }
+ }
+ else {
+ /* If filter glossy is used we replace Sharp glossy with GGX so we can
+ * benefit from closure blur to remove unwanted noise.
+ */
+ if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFLECTION_ID) {
+ VLOG(1) << "Using GGX glossy with filter glossy.";
+ distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
+ roughness = 0.0f;
+ }
+ }
+ closure = distribution;
+}
+
+bool GlossyBsdfNode::has_integrator_dependency()
+{
+ ShaderInput *roughness_input = input("Roughness");
+ return !roughness_input->link &&
+ (distribution == CLOSURE_BSDF_REFLECTION_ID || roughness <= 1e-4f);
+}
+
+void GlossyBsdfNode::compile(SVMCompiler &compiler)
+{
+ closure = distribution;
+
+ if (closure == CLOSURE_BSDF_REFLECTION_ID)
+ BsdfNode::compile(compiler, NULL, NULL);
+ else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
+ BsdfNode::compile(compiler, input("Roughness"), NULL, NULL, input("Color"));
+ else
+ BsdfNode::compile(compiler, input("Roughness"), NULL);
+}
+
+void GlossyBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "distribution");
+ compiler.add(this, "node_glossy_bsdf");
+}
+
+/* Glass BSDF Closure */
+
+NODE_DEFINE(GlassBsdfNode)
+{
+ NodeType *type = NodeType::add("glass_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ static NodeEnum distribution_enum;
+ distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
+ distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
+ distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+ distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
+ SOCKET_ENUM(
+ distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
+ SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+GlassBsdfNode::GlassBsdfNode() : BsdfNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_SHARP_GLASS_ID;
+ distribution_orig = NBUILTIN_CLOSURES;
+}
+
+void GlassBsdfNode::simplify_settings(Scene *scene)
+{
+ if (distribution_orig == NBUILTIN_CLOSURES) {
+ roughness_orig = roughness;
+ distribution_orig = distribution;
+ }
+ else {
+ /* By default we use original values, so we don't worry about restoring
+ * defaults later one and can only do override when needed.
+ */
+ roughness = roughness_orig;
+ distribution = distribution_orig;
+ }
+ Integrator *integrator = scene->integrator;
+ ShaderInput *roughness_input = input("Roughness");
+ if (integrator->get_filter_glossy() == 0.0f) {
+ /* Fallback to Sharp closure for Roughness close to 0.
+ * Note: Keep the epsilon in sync with kernel!
+ */
+ if (!roughness_input->link && roughness <= 1e-4f) {
+ VLOG(1) << "Using sharp glass BSDF.";
+ distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
+ }
+ }
+ else {
+ /* If filter glossy is used we replace Sharp glossy with GGX so we can
+ * benefit from closure blur to remove unwanted noise.
+ */
+ if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_SHARP_GLASS_ID) {
+ VLOG(1) << "Using GGX glass with filter glossy.";
+ distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
+ roughness = 0.0f;
+ }
+ }
+ closure = distribution;
+}
+
+bool GlassBsdfNode::has_integrator_dependency()
+{
+ ShaderInput *roughness_input = input("Roughness");
+ return !roughness_input->link &&
+ (distribution == CLOSURE_BSDF_SHARP_GLASS_ID || roughness <= 1e-4f);
+}
+
+void GlassBsdfNode::compile(SVMCompiler &compiler)
+{
+ closure = distribution;
+
+ if (closure == CLOSURE_BSDF_SHARP_GLASS_ID)
+ BsdfNode::compile(compiler, NULL, input("IOR"));
+ else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
+ BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color"));
+ else
+ BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
+}
+
+void GlassBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "distribution");
+ compiler.add(this, "node_glass_bsdf");
+}
+
+/* Refraction BSDF Closure */
+
+NODE_DEFINE(RefractionBsdfNode)
+{
+ NodeType *type = NodeType::add("refraction_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ static NodeEnum distribution_enum;
+ distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID);
+ distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
+ distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+ SOCKET_ENUM(
+ distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
+ SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+RefractionBsdfNode::RefractionBsdfNode() : BsdfNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_REFRACTION_ID;
+ distribution_orig = NBUILTIN_CLOSURES;
+}
+
+void RefractionBsdfNode::simplify_settings(Scene *scene)
+{
+ if (distribution_orig == NBUILTIN_CLOSURES) {
+ roughness_orig = roughness;
+ distribution_orig = distribution;
+ }
+ else {
+ /* By default we use original values, so we don't worry about restoring
+ * defaults later one and can only do override when needed.
+ */
+ roughness = roughness_orig;
+ distribution = distribution_orig;
+ }
+ Integrator *integrator = scene->integrator;
+ ShaderInput *roughness_input = input("Roughness");
+ if (integrator->get_filter_glossy() == 0.0f) {
+ /* Fallback to Sharp closure for Roughness close to 0.
+ * Note: Keep the epsilon in sync with kernel!
+ */
+ if (!roughness_input->link && roughness <= 1e-4f) {
+ VLOG(1) << "Using sharp refraction BSDF.";
+ distribution = CLOSURE_BSDF_REFRACTION_ID;
+ }
+ }
+ else {
+ /* If filter glossy is used we replace Sharp glossy with GGX so we can
+ * benefit from closure blur to remove unwanted noise.
+ */
+ if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFRACTION_ID) {
+ VLOG(1) << "Using GGX refraction with filter glossy.";
+ distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
+ roughness = 0.0f;
+ }
+ }
+ closure = distribution;
+}
+
+bool RefractionBsdfNode::has_integrator_dependency()
+{
+ ShaderInput *roughness_input = input("Roughness");
+ return !roughness_input->link &&
+ (distribution == CLOSURE_BSDF_REFRACTION_ID || roughness <= 1e-4f);
+}
+
+void RefractionBsdfNode::compile(SVMCompiler &compiler)
+{
+ closure = distribution;
+
+ if (closure == CLOSURE_BSDF_REFRACTION_ID)
+ BsdfNode::compile(compiler, NULL, input("IOR"));
+ else
+ BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
+}
+
+void RefractionBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "distribution");
+ compiler.add(this, "node_refraction_bsdf");
+}
+
+/* Toon BSDF Closure */
+
+NODE_DEFINE(ToonBsdfNode)
+{
+ NodeType *type = NodeType::add("toon_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ static NodeEnum component_enum;
+ component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
+ component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
+ SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID);
+ SOCKET_IN_FLOAT(size, "Size", 0.5f);
+ SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+ToonBsdfNode::ToonBsdfNode() : BsdfNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
+}
+
+void ToonBsdfNode::compile(SVMCompiler &compiler)
+{
+ closure = component;
+
+ BsdfNode::compile(compiler, input("Size"), input("Smooth"));
+}
+
+void ToonBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "component");
+ compiler.add(this, "node_toon_bsdf");
+}
+
+/* Velvet BSDF Closure */
+
+NODE_DEFINE(VelvetBsdfNode)
+{
+ NodeType *type = NodeType::add("velvet_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+ SOCKET_IN_FLOAT(sigma, "Sigma", 1.0f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+VelvetBsdfNode::VelvetBsdfNode() : BsdfNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
+}
+
+void VelvetBsdfNode::compile(SVMCompiler &compiler)
+{
+ BsdfNode::compile(compiler, input("Sigma"), NULL);
+}
+
+void VelvetBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_velvet_bsdf");
+}
+
+/* Diffuse BSDF Closure */
+
+NODE_DEFINE(DiffuseBsdfNode)
+{
+ NodeType *type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+DiffuseBsdfNode::DiffuseBsdfNode() : BsdfNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_DIFFUSE_ID;
+}
+
+void DiffuseBsdfNode::compile(SVMCompiler &compiler)
+{
+ BsdfNode::compile(compiler, input("Roughness"), NULL);
+}
+
+void DiffuseBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_diffuse_bsdf");
+}
+
+/* Disney principled BSDF Closure */
+NODE_DEFINE(PrincipledBsdfNode)
+{
+ NodeType *type = NodeType::add("principled_bsdf", create, NodeType::SHADER);
+
+ static NodeEnum distribution_enum;
+ distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+ distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
+ SOCKET_ENUM(
+ distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
+
+ static NodeEnum subsurface_method_enum;
+ subsurface_method_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
+ subsurface_method_enum.insert("random_walk_fixed_radius",
+ CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
+ subsurface_method_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID);
+ SOCKET_ENUM(subsurface_method,
+ "Subsurface Method",
+ subsurface_method_enum,
+ CLOSURE_BSSRDF_RANDOM_WALK_ID);
+
+ SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_COLOR(subsurface_color, "Subsurface Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f);
+ SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f);
+ SOCKET_IN_VECTOR(subsurface_radius, "Subsurface Radius", make_float3(0.1f, 0.1f, 0.1f));
+ SOCKET_IN_FLOAT(subsurface_ior, "Subsurface IOR", 1.4f);
+ SOCKET_IN_FLOAT(subsurface_anisotropy, "Subsurface Anisotropy", 0.0f);
+ SOCKET_IN_FLOAT(specular, "Specular", 0.0f);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
+ SOCKET_IN_FLOAT(specular_tint, "Specular Tint", 0.0f);
+ SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f);
+ SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f);
+ SOCKET_IN_FLOAT(sheen_tint, "Sheen Tint", 0.0f);
+ SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f);
+ SOCKET_IN_FLOAT(clearcoat_roughness, "Clearcoat Roughness", 0.03f);
+ SOCKET_IN_FLOAT(ior, "IOR", 0.0f);
+ SOCKET_IN_FLOAT(transmission, "Transmission", 0.0f);
+ SOCKET_IN_FLOAT(transmission_roughness, "Transmission Roughness", 0.0f);
+ SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f);
+ SOCKET_IN_COLOR(emission, "Emission", zero_float3());
+ SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 1.0f);
+ SOCKET_IN_FLOAT(alpha, "Alpha", 1.0f);
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_NORMAL(clearcoat_normal, "Clearcoat Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_NORMAL(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_PRINCIPLED_ID;
+ distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
+ distribution_orig = NBUILTIN_CLOSURES;
+}
+
+void PrincipledBsdfNode::expand(ShaderGraph *graph)
+{
+ ShaderOutput *principled_out = output("BSDF");
+
+ ShaderInput *emission_in = input("Emission");
+ ShaderInput *emission_strength_in = input("Emission Strength");
+ if ((emission_in->link || emission != zero_float3()) &&
+ (emission_strength_in->link || emission_strength != 0.0f)) {
+ /* Create add closure and emission, and relink inputs. */
+ AddClosureNode *add = graph->create_node<AddClosureNode>();
+ EmissionNode *emission_node = graph->create_node<EmissionNode>();
+ ShaderOutput *new_out = add->output("Closure");
+
+ graph->add(add);
+ graph->add(emission_node);
+
+ graph->relink(emission_strength_in, emission_node->input("Strength"));
+ graph->relink(emission_in, emission_node->input("Color"));
+ graph->relink(principled_out, new_out);
+ graph->connect(emission_node->output("Emission"), add->input("Closure1"));
+ graph->connect(principled_out, add->input("Closure2"));
+
+ principled_out = new_out;
+ }
+ else {
+ /* Disconnect unused links if the other value is zero, required before
+ * we remove the input from the node entirely. */
+ if (emission_in->link) {
+ emission_in->disconnect();
+ }
+ if (emission_strength_in->link) {
+ emission_strength_in->disconnect();
+ }
+ }
+
+ ShaderInput *alpha_in = input("Alpha");
+ if (alpha_in->link || alpha != 1.0f) {
+ /* Create mix and transparent BSDF for alpha transparency. */
+ MixClosureNode *mix = graph->create_node<MixClosureNode>();
+ TransparentBsdfNode *transparent = graph->create_node<TransparentBsdfNode>();
+
+ graph->add(mix);
+ graph->add(transparent);
+
+ graph->relink(alpha_in, mix->input("Fac"));
+ graph->relink(principled_out, mix->output("Closure"));
+ graph->connect(transparent->output("BSDF"), mix->input("Closure1"));
+ graph->connect(principled_out, mix->input("Closure2"));
+ }
+
+ remove_input(emission_in);
+ remove_input(emission_strength_in);
+ remove_input(alpha_in);
+}
+
+bool PrincipledBsdfNode::has_surface_bssrdf()
+{
+ ShaderInput *subsurface_in = input("Subsurface");
+ return (subsurface_in->link != NULL || subsurface > CLOSURE_WEIGHT_CUTOFF);
+}
+
+void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_surface_link()) {
+ ShaderInput *tangent_in = input("Tangent");
+
+ if (!tangent_in->link)
+ attributes->add(ATTR_STD_GENERATED);
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void PrincipledBsdfNode::compile(SVMCompiler &compiler,
+ ShaderInput *p_metallic,
+ ShaderInput *p_subsurface,
+ ShaderInput *p_subsurface_radius,
+ ShaderInput *p_subsurface_ior,
+ ShaderInput *p_subsurface_anisotropy,
+ ShaderInput *p_specular,
+ ShaderInput *p_roughness,
+ ShaderInput *p_specular_tint,
+ ShaderInput *p_anisotropic,
+ ShaderInput *p_sheen,
+ ShaderInput *p_sheen_tint,
+ ShaderInput *p_clearcoat,
+ ShaderInput *p_clearcoat_roughness,
+ ShaderInput *p_ior,
+ ShaderInput *p_transmission,
+ ShaderInput *p_anisotropic_rotation,
+ ShaderInput *p_transmission_roughness)
+{
+ ShaderInput *base_color_in = input("Base Color");
+ ShaderInput *subsurface_color_in = input("Subsurface Color");
+ ShaderInput *normal_in = input("Normal");
+ ShaderInput *clearcoat_normal_in = input("Clearcoat Normal");
+ ShaderInput *tangent_in = input("Tangent");
+
+ float3 weight = one_float3();
+
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight);
+
+ int normal_offset = compiler.stack_assign_if_linked(normal_in);
+ int clearcoat_normal_offset = compiler.stack_assign_if_linked(clearcoat_normal_in);
+ int tangent_offset = compiler.stack_assign_if_linked(tangent_in);
+ int specular_offset = compiler.stack_assign(p_specular);
+ int roughness_offset = compiler.stack_assign(p_roughness);
+ int specular_tint_offset = compiler.stack_assign(p_specular_tint);
+ int anisotropic_offset = compiler.stack_assign(p_anisotropic);
+ int sheen_offset = compiler.stack_assign(p_sheen);
+ int sheen_tint_offset = compiler.stack_assign(p_sheen_tint);
+ int clearcoat_offset = compiler.stack_assign(p_clearcoat);
+ int clearcoat_roughness_offset = compiler.stack_assign(p_clearcoat_roughness);
+ int ior_offset = compiler.stack_assign(p_ior);
+ int transmission_offset = compiler.stack_assign(p_transmission);
+ int transmission_roughness_offset = compiler.stack_assign(p_transmission_roughness);
+ int anisotropic_rotation_offset = compiler.stack_assign(p_anisotropic_rotation);
+ int subsurface_radius_offset = compiler.stack_assign(p_subsurface_radius);
+ int subsurface_ior_offset = compiler.stack_assign(p_subsurface_ior);
+ int subsurface_anisotropy_offset = compiler.stack_assign(p_subsurface_anisotropy);
+
+ compiler.add_node(NODE_CLOSURE_BSDF,
+ compiler.encode_uchar4(closure,
+ compiler.stack_assign(p_metallic),
+ compiler.stack_assign(p_subsurface),
+ compiler.closure_mix_weight_offset()),
+ __float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f),
+ __float_as_int((p_subsurface) ? get_float(p_subsurface->socket_type) : 0.0f));
+
+ compiler.add_node(
+ normal_offset,
+ tangent_offset,
+ compiler.encode_uchar4(
+ specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset),
+ compiler.encode_uchar4(
+ sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset));
+
+ compiler.add_node(compiler.encode_uchar4(ior_offset,
+ transmission_offset,
+ anisotropic_rotation_offset,
+ transmission_roughness_offset),
+ distribution,
+ subsurface_method,
+ SVM_STACK_INVALID);
+
+ float3 bc_default = get_float3(base_color_in->socket_type);
+
+ compiler.add_node(
+ ((base_color_in->link) ? compiler.stack_assign(base_color_in) : SVM_STACK_INVALID),
+ __float_as_int(bc_default.x),
+ __float_as_int(bc_default.y),
+ __float_as_int(bc_default.z));
+
+ compiler.add_node(clearcoat_normal_offset,
+ subsurface_radius_offset,
+ subsurface_ior_offset,
+ subsurface_anisotropy_offset);
+
+ float3 ss_default = get_float3(subsurface_color_in->socket_type);
+
+ compiler.add_node(((subsurface_color_in->link) ? compiler.stack_assign(subsurface_color_in) :
+ SVM_STACK_INVALID),
+ __float_as_int(ss_default.x),
+ __float_as_int(ss_default.y),
+ __float_as_int(ss_default.z));
+}
+
+bool PrincipledBsdfNode::has_integrator_dependency()
+{
+ ShaderInput *roughness_input = input("Roughness");
+ return !roughness_input->link && roughness <= 1e-4f;
+}
+
+void PrincipledBsdfNode::compile(SVMCompiler &compiler)
+{
+ compile(compiler,
+ input("Metallic"),
+ input("Subsurface"),
+ input("Subsurface Radius"),
+ input("Subsurface IOR"),
+ input("Subsurface Anisotropy"),
+ input("Specular"),
+ input("Roughness"),
+ input("Specular Tint"),
+ input("Anisotropic"),
+ input("Sheen"),
+ input("Sheen Tint"),
+ input("Clearcoat"),
+ input("Clearcoat Roughness"),
+ input("IOR"),
+ input("Transmission"),
+ input("Anisotropic Rotation"),
+ input("Transmission Roughness"));
+}
+
+void PrincipledBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "distribution");
+ compiler.parameter(this, "subsurface_method");
+ compiler.add(this, "node_principled_bsdf");
+}
+
+bool PrincipledBsdfNode::has_bssrdf_bump()
+{
+ return has_surface_bssrdf() && has_bump();
+}
+
+/* Translucent BSDF Closure */
+
+NODE_DEFINE(TranslucentBsdfNode)
+{
+ NodeType *type = NodeType::add("translucent_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+TranslucentBsdfNode::TranslucentBsdfNode() : BsdfNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_TRANSLUCENT_ID;
+}
+
+void TranslucentBsdfNode::compile(SVMCompiler &compiler)
+{
+ BsdfNode::compile(compiler, NULL, NULL);
+}
+
+void TranslucentBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_translucent_bsdf");
+}
+
+/* Transparent BSDF Closure */
+
+NODE_DEFINE(TransparentBsdfNode)
+{
+ NodeType *type = NodeType::add("transparent_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", one_float3());
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+TransparentBsdfNode::TransparentBsdfNode() : BsdfNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_TRANSPARENT_ID;
+}
+
+void TransparentBsdfNode::compile(SVMCompiler &compiler)
+{
+ BsdfNode::compile(compiler, NULL, NULL);
+}
+
+void TransparentBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_transparent_bsdf");
+}
+
+/* Subsurface Scattering Closure */
+
+NODE_DEFINE(SubsurfaceScatteringNode)
+{
+ NodeType *type = NodeType::add("subsurface_scattering", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ static NodeEnum method_enum;
+ method_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
+ method_enum.insert("random_walk_fixed_radius", CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
+ method_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID);
+ SOCKET_ENUM(method, "Method", method_enum, CLOSURE_BSSRDF_RANDOM_WALK_ID);
+
+ SOCKET_IN_FLOAT(scale, "Scale", 0.01f);
+ SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f));
+
+ SOCKET_IN_FLOAT(subsurface_ior, "IOR", 1.4f);
+ SOCKET_IN_FLOAT(subsurface_anisotropy, "Anisotropy", 0.0f);
+
+ SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF");
+
+ return type;
+}
+
+SubsurfaceScatteringNode::SubsurfaceScatteringNode() : BsdfNode(get_node_type())
+{
+ closure = method;
+}
+
+void SubsurfaceScatteringNode::compile(SVMCompiler &compiler)
+{
+ closure = method;
+ BsdfNode::compile(compiler, input("Scale"), input("IOR"), input("Radius"), input("Anisotropy"));
+}
+
+void SubsurfaceScatteringNode::compile(OSLCompiler &compiler)
+{
+ closure = method;
+ compiler.parameter(this, "method");
+ compiler.add(this, "node_subsurface_scattering");
+}
+
+bool SubsurfaceScatteringNode::has_bssrdf_bump()
+{
+ /* detect if anything is plugged into the normal input besides the default */
+ ShaderInput *normal_in = input("Normal");
+ return (normal_in->link &&
+ normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY);
+}
+
+/* Emissive Closure */
+
+NODE_DEFINE(EmissionNode)
+{
+ NodeType *type = NodeType::add("emission", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(strength, "Strength", 10.0f);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(emission, "Emission");
+
+ return type;
+}
+
+EmissionNode::EmissionNode() : ShaderNode(get_node_type())
+{
+}
+
+void EmissionNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *strength_in = input("Strength");
+
+ if (color_in->link || strength_in->link) {
+ compiler.add_node(
+ NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), compiler.stack_assign(strength_in));
+ }
+ else
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
+
+ compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
+}
+
+void EmissionNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_emission");
+}
+
+void EmissionNode::constant_fold(const ConstantFolder &folder)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *strength_in = input("Strength");
+
+ if ((!color_in->link && color == zero_float3()) || (!strength_in->link && strength == 0.0f)) {
+ folder.discard();
+ }
+}
+
+/* Background Closure */
+
+NODE_DEFINE(BackgroundNode)
+{
+ NodeType *type = NodeType::add("background_shader", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(background, "Background");
+
+ return type;
+}
+
+BackgroundNode::BackgroundNode() : ShaderNode(get_node_type())
+{
+}
+
+void BackgroundNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *strength_in = input("Strength");
+
+ if (color_in->link || strength_in->link) {
+ compiler.add_node(
+ NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), compiler.stack_assign(strength_in));
+ }
+ else
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
+
+ compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset());
+}
+
+void BackgroundNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_background");
+}
+
+void BackgroundNode::constant_fold(const ConstantFolder &folder)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *strength_in = input("Strength");
+
+ if ((!color_in->link && color == zero_float3()) || (!strength_in->link && strength == 0.0f)) {
+ folder.discard();
+ }
+}
+
+/* Holdout Closure */
+
+NODE_DEFINE(HoldoutNode)
+{
+ NodeType *type = NodeType::add("holdout", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+ SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(holdout, "Holdout");
+
+ return type;
+}
+
+HoldoutNode::HoldoutNode() : ShaderNode(get_node_type())
+{
+}
+
+void HoldoutNode::compile(SVMCompiler &compiler)
+{
+ float3 value = one_float3();
+
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, value);
+ compiler.add_node(NODE_CLOSURE_HOLDOUT, compiler.closure_mix_weight_offset());
+}
+
+void HoldoutNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_holdout");
+}
+
+/* Ambient Occlusion */
+
+NODE_DEFINE(AmbientOcclusionNode)
+{
+ NodeType *type = NodeType::add("ambient_occlusion", create, NodeType::SHADER);
+
+ SOCKET_INT(samples, "Samples", 16);
+
+ SOCKET_IN_COLOR(color, "Color", one_float3());
+ SOCKET_IN_FLOAT(distance, "Distance", 1.0f);
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+
+ SOCKET_BOOLEAN(inside, "Inside", false);
+ SOCKET_BOOLEAN(only_local, "Only Local", false);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(ao, "AO");
+
+ return type;
+}
+
+AmbientOcclusionNode::AmbientOcclusionNode() : ShaderNode(get_node_type())
+{
+}
+
+void AmbientOcclusionNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *distance_in = input("Distance");
+ ShaderInput *normal_in = input("Normal");
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *ao_out = output("AO");
+
+ int flags = (inside ? NODE_AO_INSIDE : 0) | (only_local ? NODE_AO_ONLY_LOCAL : 0);
+
+ if (!distance_in->link && distance == 0.0f) {
+ flags |= NODE_AO_GLOBAL_RADIUS;
+ }
+
+ compiler.add_node(NODE_AMBIENT_OCCLUSION,
+ compiler.encode_uchar4(flags,
+ compiler.stack_assign_if_linked(distance_in),
+ compiler.stack_assign_if_linked(normal_in),
+ compiler.stack_assign(ao_out)),
+ compiler.encode_uchar4(compiler.stack_assign(color_in),
+ compiler.stack_assign(color_out),
+ samples),
+ __float_as_uint(distance));
+}
+
+void AmbientOcclusionNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "samples");
+ compiler.parameter(this, "inside");
+ compiler.parameter(this, "only_local");
+ compiler.add(this, "node_ambient_occlusion");
+}
+
+/* Volume Closure */
+
+VolumeNode::VolumeNode(const NodeType *node_type) : ShaderNode(node_type)
+{
+ closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
+}
+
+void VolumeNode::compile(SVMCompiler &compiler, ShaderInput *param1, ShaderInput *param2)
+{
+ ShaderInput *color_in = input("Color");
+
+ if (color_in->link)
+ compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
+ else
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
+
+ compiler.add_node(
+ NODE_CLOSURE_VOLUME,
+ compiler.encode_uchar4(closure,
+ (param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID,
+ (param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID,
+ compiler.closure_mix_weight_offset()),
+ __float_as_int((param1) ? get_float(param1->socket_type) : 0.0f),
+ __float_as_int((param2) ? get_float(param2->socket_type) : 0.0f));
+}
+
+void VolumeNode::compile(SVMCompiler &compiler)
+{
+ compile(compiler, NULL, NULL);
+}
+
+void VolumeNode::compile(OSLCompiler & /*compiler*/)
+{
+ assert(0);
+}
+
+/* Absorption Volume Closure */
+
+NODE_DEFINE(AbsorptionVolumeNode)
+{
+ NodeType *type = NodeType::add("absorption_volume", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(density, "Density", 1.0f);
+ SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(volume, "Volume");
+
+ return type;
+}
+
+AbsorptionVolumeNode::AbsorptionVolumeNode() : VolumeNode(get_node_type())
+{
+ closure = CLOSURE_VOLUME_ABSORPTION_ID;
+}
+
+void AbsorptionVolumeNode::compile(SVMCompiler &compiler)
+{
+ VolumeNode::compile(compiler, input("Density"), NULL);
+}
+
+void AbsorptionVolumeNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_absorption_volume");
+}
+
+/* Scatter Volume Closure */
+
+NODE_DEFINE(ScatterVolumeNode)
+{
+ NodeType *type = NodeType::add("scatter_volume", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(density, "Density", 1.0f);
+ SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
+ SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(volume, "Volume");
+
+ return type;
+}
+
+ScatterVolumeNode::ScatterVolumeNode() : VolumeNode(get_node_type())
+{
+ closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
+}
+
+void ScatterVolumeNode::compile(SVMCompiler &compiler)
+{
+ VolumeNode::compile(compiler, input("Density"), input("Anisotropy"));
+}
+
+void ScatterVolumeNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_scatter_volume");
+}
+
+/* Principled Volume Closure */
+
+NODE_DEFINE(PrincipledVolumeNode)
+{
+ NodeType *type = NodeType::add("principled_volume", create, NodeType::SHADER);
+
+ SOCKET_IN_STRING(density_attribute, "Density Attribute", ustring());
+ SOCKET_IN_STRING(color_attribute, "Color Attribute", ustring());
+ SOCKET_IN_STRING(temperature_attribute, "Temperature Attribute", ustring());
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 0.5f));
+ SOCKET_IN_FLOAT(density, "Density", 1.0f);
+ SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
+ SOCKET_IN_COLOR(absorption_color, "Absorption Color", zero_float3());
+ SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f);
+ SOCKET_IN_COLOR(emission_color, "Emission Color", one_float3());
+ SOCKET_IN_FLOAT(blackbody_intensity, "Blackbody Intensity", 0.0f);
+ SOCKET_IN_COLOR(blackbody_tint, "Blackbody Tint", one_float3());
+ SOCKET_IN_FLOAT(temperature, "Temperature", 1000.0f);
+ SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(volume, "Volume");
+
+ return type;
+}
+
+PrincipledVolumeNode::PrincipledVolumeNode() : VolumeNode(get_node_type())
+{
+ closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
+ density_attribute = ustring("density");
+ temperature_attribute = ustring("temperature");
+}
+
+void PrincipledVolumeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_volume) {
+ ShaderInput *density_in = input("Density");
+ ShaderInput *blackbody_in = input("Blackbody Intensity");
+
+ if (density_in->link || density > 0.0f) {
+ attributes->add_standard(density_attribute);
+ attributes->add_standard(color_attribute);
+ }
+
+ if (blackbody_in->link || blackbody_intensity > 0.0f) {
+ attributes->add_standard(temperature_attribute);
+ }
+
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void PrincipledVolumeNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *density_in = input("Density");
+ ShaderInput *anisotropy_in = input("Anisotropy");
+ ShaderInput *absorption_color_in = input("Absorption Color");
+ ShaderInput *emission_in = input("Emission Strength");
+ ShaderInput *emission_color_in = input("Emission Color");
+ ShaderInput *blackbody_in = input("Blackbody Intensity");
+ ShaderInput *blackbody_tint_in = input("Blackbody Tint");
+ ShaderInput *temperature_in = input("Temperature");
+
+ if (color_in->link)
+ compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
+ else
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
+
+ compiler.add_node(NODE_PRINCIPLED_VOLUME,
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(density_in),
+ compiler.stack_assign_if_linked(anisotropy_in),
+ compiler.stack_assign(absorption_color_in),
+ compiler.closure_mix_weight_offset()),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(emission_in),
+ compiler.stack_assign(emission_color_in),
+ compiler.stack_assign_if_linked(blackbody_in),
+ compiler.stack_assign(temperature_in)),
+ compiler.stack_assign(blackbody_tint_in));
+
+ int attr_density = compiler.attribute_standard(density_attribute);
+ int attr_color = compiler.attribute_standard(color_attribute);
+ int attr_temperature = compiler.attribute_standard(temperature_attribute);
+
+ compiler.add_node(__float_as_int(density),
+ __float_as_int(anisotropy),
+ __float_as_int(emission_strength),
+ __float_as_int(blackbody_intensity));
+
+ compiler.add_node(attr_density, attr_color, attr_temperature);
+}
+
+void PrincipledVolumeNode::compile(OSLCompiler &compiler)
+{
+ if (Attribute::name_standard(density_attribute.c_str())) {
+ density_attribute = ustring("geom:" + density_attribute.string());
+ }
+ if (Attribute::name_standard(color_attribute.c_str())) {
+ color_attribute = ustring("geom:" + color_attribute.string());
+ }
+ if (Attribute::name_standard(temperature_attribute.c_str())) {
+ temperature_attribute = ustring("geom:" + temperature_attribute.string());
+ }
+
+ compiler.add(this, "node_principled_volume");
+}
+
+/* Principled Hair BSDF Closure */
+
+NODE_DEFINE(PrincipledHairBsdfNode)
+{
+ NodeType *type = NodeType::add("principled_hair_bsdf", create, NodeType::SHADER);
+
+ /* Color parametrization specified as enum. */
+ static NodeEnum parametrization_enum;
+ parametrization_enum.insert("Direct coloring", NODE_PRINCIPLED_HAIR_REFLECTANCE);
+ parametrization_enum.insert("Melanin concentration", NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
+ parametrization_enum.insert("Absorption coefficient", NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION);
+ SOCKET_ENUM(
+ parametrization, "Parametrization", parametrization_enum, NODE_PRINCIPLED_HAIR_REFLECTANCE);
+
+ /* Initialize sockets to their default values. */
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.017513f, 0.005763f, 0.002059f));
+ SOCKET_IN_FLOAT(melanin, "Melanin", 0.8f);
+ SOCKET_IN_FLOAT(melanin_redness, "Melanin Redness", 1.0f);
+ SOCKET_IN_COLOR(tint, "Tint", make_float3(1.f, 1.f, 1.f));
+ SOCKET_IN_VECTOR(absorption_coefficient,
+ "Absorption Coefficient",
+ make_float3(0.245531f, 0.52f, 1.365f),
+ SocketType::VECTOR);
+
+ SOCKET_IN_FLOAT(offset, "Offset", 2.f * M_PI_F / 180.f);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.3f);
+ SOCKET_IN_FLOAT(radial_roughness, "Radial Roughness", 0.3f);
+ SOCKET_IN_FLOAT(coat, "Coat", 0.0f);
+ SOCKET_IN_FLOAT(ior, "IOR", 1.55f);
+
+ SOCKET_IN_FLOAT(random_roughness, "Random Roughness", 0.0f);
+ SOCKET_IN_FLOAT(random_color, "Random Color", 0.0f);
+ SOCKET_IN_FLOAT(random, "Random", 0.0f);
+
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+PrincipledHairBsdfNode::PrincipledHairBsdfNode() : BsdfBaseNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_HAIR_PRINCIPLED_ID;
+}
+
+/* Enable retrieving Hair Info -> Random if Random isn't linked. */
+void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (!input("Random")->link) {
+ attributes->add(ATTR_STD_CURVE_RANDOM);
+ }
+ ShaderNode::attributes(shader, attributes);
+}
+
+/* Prepares the input data for the SVM shader. */
+void PrincipledHairBsdfNode::compile(SVMCompiler &compiler)
+{
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, one_float3());
+
+ ShaderInput *roughness_in = input("Roughness");
+ ShaderInput *radial_roughness_in = input("Radial Roughness");
+ ShaderInput *random_roughness_in = input("Random Roughness");
+ ShaderInput *offset_in = input("Offset");
+ ShaderInput *coat_in = input("Coat");
+ ShaderInput *ior_in = input("IOR");
+ ShaderInput *melanin_in = input("Melanin");
+ ShaderInput *melanin_redness_in = input("Melanin Redness");
+ ShaderInput *random_color_in = input("Random Color");
+
+ int color_ofs = compiler.stack_assign(input("Color"));
+ int tint_ofs = compiler.stack_assign(input("Tint"));
+ int absorption_coefficient_ofs = compiler.stack_assign(input("Absorption Coefficient"));
+
+ ShaderInput *random_in = input("Random");
+ int attr_random = random_in->link ? SVM_STACK_INVALID :
+ compiler.attribute(ATTR_STD_CURVE_RANDOM);
+
+ /* Encode all parameters into data nodes. */
+ compiler.add_node(NODE_CLOSURE_BSDF,
+ /* Socket IDs can be packed 4 at a time into a single data packet */
+ compiler.encode_uchar4(closure,
+ compiler.stack_assign_if_linked(roughness_in),
+ compiler.stack_assign_if_linked(radial_roughness_in),
+ compiler.closure_mix_weight_offset()),
+ /* The rest are stored as unsigned integers */
+ __float_as_uint(roughness),
+ __float_as_uint(radial_roughness));
+
+ compiler.add_node(compiler.stack_assign_if_linked(input("Normal")),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(offset_in),
+ compiler.stack_assign_if_linked(ior_in),
+ color_ofs,
+ parametrization),
+ __float_as_uint(offset),
+ __float_as_uint(ior));
+
+ compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(coat_in),
+ compiler.stack_assign_if_linked(melanin_in),
+ compiler.stack_assign_if_linked(melanin_redness_in),
+ absorption_coefficient_ofs),
+ __float_as_uint(coat),
+ __float_as_uint(melanin),
+ __float_as_uint(melanin_redness));
+
+ compiler.add_node(compiler.encode_uchar4(tint_ofs,
+ compiler.stack_assign_if_linked(random_in),
+ compiler.stack_assign_if_linked(random_color_in),
+ compiler.stack_assign_if_linked(random_roughness_in)),
+ __float_as_uint(random),
+ __float_as_uint(random_color),
+ __float_as_uint(random_roughness));
+
+ compiler.add_node(
+ compiler.encode_uchar4(
+ SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID),
+ attr_random,
+ SVM_STACK_INVALID,
+ SVM_STACK_INVALID);
+}
+
+/* Prepares the input data for the OSL shader. */
+void PrincipledHairBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "parametrization");
+ compiler.add(this, "node_principled_hair_bsdf");
+}
+
+/* Hair BSDF Closure */
+
+NODE_DEFINE(HairBsdfNode)
+{
+ NodeType *type = NodeType::add("hair_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ static NodeEnum component_enum;
+ component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
+ component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
+ SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID);
+ SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
+ SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f);
+ SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f);
+ SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3());
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
+HairBsdfNode::HairBsdfNode() : BsdfNode(get_node_type())
+{
+ closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
+}
+
+void HairBsdfNode::compile(SVMCompiler &compiler)
+{
+ closure = component;
+
+ BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
+}
+
+void HairBsdfNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "component");
+ compiler.add(this, "node_hair_bsdf");
+}
+
+/* Geometry */
+
+NODE_DEFINE(GeometryNode)
+{
+ NodeType *type = NodeType::add("geometry", create, NodeType::SHADER);
+
+ SOCKET_IN_NORMAL(
+ normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+
+ SOCKET_OUT_POINT(position, "Position");
+ SOCKET_OUT_NORMAL(normal, "Normal");
+ SOCKET_OUT_NORMAL(tangent, "Tangent");
+ SOCKET_OUT_NORMAL(true_normal, "True Normal");
+ SOCKET_OUT_VECTOR(incoming, "Incoming");
+ SOCKET_OUT_POINT(parametric, "Parametric");
+ SOCKET_OUT_FLOAT(backfacing, "Backfacing");
+ SOCKET_OUT_FLOAT(pointiness, "Pointiness");
+ SOCKET_OUT_FLOAT(random_per_island, "Random Per Island");
+
+ return type;
+}
+
+GeometryNode::GeometryNode() : ShaderNode(get_node_type())
+{
+ special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
+}
+
+void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_surface_link()) {
+ if (!output("Tangent")->links.empty()) {
+ attributes->add(ATTR_STD_GENERATED);
+ }
+ if (!output("Pointiness")->links.empty()) {
+ attributes->add(ATTR_STD_POINTINESS);
+ }
+ if (!output("Random Per Island")->links.empty()) {
+ attributes->add(ATTR_STD_RANDOM_PER_ISLAND);
+ }
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void GeometryNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *out;
+ ShaderNodeType geom_node = NODE_GEOMETRY;
+ ShaderNodeType attr_node = NODE_ATTR;
+
+ if (bump == SHADER_BUMP_DX) {
+ geom_node = NODE_GEOMETRY_BUMP_DX;
+ attr_node = NODE_ATTR_BUMP_DX;
+ }
+ else if (bump == SHADER_BUMP_DY) {
+ geom_node = NODE_GEOMETRY_BUMP_DY;
+ attr_node = NODE_ATTR_BUMP_DY;
+ }
+
+ out = output("Position");
+ if (!out->links.empty()) {
+ compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
+ }
+
+ out = output("Normal");
+ if (!out->links.empty()) {
+ compiler.add_node(geom_node, NODE_GEOM_N, compiler.stack_assign(out));
+ }
+
+ out = output("Tangent");
+ if (!out->links.empty()) {
+ compiler.add_node(geom_node, NODE_GEOM_T, compiler.stack_assign(out));
+ }
+
+ out = output("True Normal");
+ if (!out->links.empty()) {
+ compiler.add_node(geom_node, NODE_GEOM_Ng, compiler.stack_assign(out));
+ }
+
+ out = output("Incoming");
+ if (!out->links.empty()) {
+ compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
+ }
+
+ out = output("Parametric");
+ if (!out->links.empty()) {
+ compiler.add_node(geom_node, NODE_GEOM_uv, compiler.stack_assign(out));
+ }
+
+ out = output("Backfacing");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, compiler.stack_assign(out));
+ }
+
+ out = output("Pointiness");
+ if (!out->links.empty()) {
+ if (compiler.output_type() != SHADER_TYPE_VOLUME) {
+ compiler.add_node(
+ attr_node, ATTR_STD_POINTINESS, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
+ }
+ else {
+ compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
+ }
+ }
+
+ out = output("Random Per Island");
+ if (!out->links.empty()) {
+ if (compiler.output_type() != SHADER_TYPE_VOLUME) {
+ compiler.add_node(attr_node,
+ ATTR_STD_RANDOM_PER_ISLAND,
+ compiler.stack_assign(out),
+ NODE_ATTR_OUTPUT_FLOAT);
+ }
+ else {
+ compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
+ }
+ }
+}
+
+void GeometryNode::compile(OSLCompiler &compiler)
+{
+ if (bump == SHADER_BUMP_DX)
+ compiler.parameter("bump_offset", "dx");
+ else if (bump == SHADER_BUMP_DY)
+ compiler.parameter("bump_offset", "dy");
+ else
+ compiler.parameter("bump_offset", "center");
+
+ compiler.add(this, "node_geometry");
+}
+
+/* TextureCoordinate */
+
+NODE_DEFINE(TextureCoordinateNode)
+{
+ NodeType *type = NodeType::add("texture_coordinate", create, NodeType::SHADER);
+
+ SOCKET_BOOLEAN(from_dupli, "From Dupli", false);
+ SOCKET_BOOLEAN(use_transform, "Use Transform", false);
+ SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity());
+
+ SOCKET_IN_NORMAL(
+ normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+
+ SOCKET_OUT_POINT(generated, "Generated");
+ SOCKET_OUT_NORMAL(normal, "Normal");
+ SOCKET_OUT_POINT(UV, "UV");
+ SOCKET_OUT_POINT(object, "Object");
+ SOCKET_OUT_POINT(camera, "Camera");
+ SOCKET_OUT_POINT(window, "Window");
+ SOCKET_OUT_NORMAL(reflection, "Reflection");
+
+ return type;
+}
+
+TextureCoordinateNode::TextureCoordinateNode() : ShaderNode(get_node_type())
+{
+}
+
+void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_surface_link()) {
+ if (!from_dupli) {
+ if (!output("Generated")->links.empty())
+ attributes->add(ATTR_STD_GENERATED);
+ if (!output("UV")->links.empty())
+ attributes->add(ATTR_STD_UV);
+ }
+ }
+
+ if (shader->has_volume) {
+ if (!from_dupli) {
+ if (!output("Generated")->links.empty()) {
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+ }
+ }
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void TextureCoordinateNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *out;
+ ShaderNodeType texco_node = NODE_TEX_COORD;
+ ShaderNodeType attr_node = NODE_ATTR;
+ ShaderNodeType geom_node = NODE_GEOMETRY;
+
+ if (bump == SHADER_BUMP_DX) {
+ texco_node = NODE_TEX_COORD_BUMP_DX;
+ attr_node = NODE_ATTR_BUMP_DX;
+ geom_node = NODE_GEOMETRY_BUMP_DX;
+ }
+ else if (bump == SHADER_BUMP_DY) {
+ texco_node = NODE_TEX_COORD_BUMP_DY;
+ attr_node = NODE_ATTR_BUMP_DY;
+ geom_node = NODE_GEOMETRY_BUMP_DY;
+ }
+
+ out = output("Generated");
+ if (!out->links.empty()) {
+ if (compiler.background) {
+ compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
+ }
+ else {
+ if (from_dupli) {
+ compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, compiler.stack_assign(out));
+ }
+ else if (compiler.output_type() == SHADER_TYPE_VOLUME) {
+ compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, compiler.stack_assign(out));
+ }
+ else {
+ int attr = compiler.attribute(ATTR_STD_GENERATED);
+ compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
+ }
+ }
+ }
+
+ out = output("Normal");
+ if (!out->links.empty()) {
+ compiler.add_node(texco_node, NODE_TEXCO_NORMAL, compiler.stack_assign(out));
+ }
+
+ out = output("UV");
+ if (!out->links.empty()) {
+ if (from_dupli) {
+ compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
+ }
+ else {
+ int attr = compiler.attribute(ATTR_STD_UV);
+ compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
+ }
+ }
+
+ out = output("Object");
+ if (!out->links.empty()) {
+ compiler.add_node(texco_node, NODE_TEXCO_OBJECT, compiler.stack_assign(out), use_transform);
+ if (use_transform) {
+ Transform ob_itfm = transform_inverse(ob_tfm);
+ compiler.add_node(ob_itfm.x);
+ compiler.add_node(ob_itfm.y);
+ compiler.add_node(ob_itfm.z);
+ }
+ }
+
+ out = output("Camera");
+ if (!out->links.empty()) {
+ compiler.add_node(texco_node, NODE_TEXCO_CAMERA, compiler.stack_assign(out));
+ }
+
+ out = output("Window");
+ if (!out->links.empty()) {
+ compiler.add_node(texco_node, NODE_TEXCO_WINDOW, compiler.stack_assign(out));
+ }
+
+ out = output("Reflection");
+ if (!out->links.empty()) {
+ if (compiler.background) {
+ compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
+ }
+ else {
+ compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, compiler.stack_assign(out));
+ }
+ }
+}
+
+void TextureCoordinateNode::compile(OSLCompiler &compiler)
+{
+ if (bump == SHADER_BUMP_DX)
+ compiler.parameter("bump_offset", "dx");
+ else if (bump == SHADER_BUMP_DY)
+ compiler.parameter("bump_offset", "dy");
+ else
+ compiler.parameter("bump_offset", "center");
+
+ if (compiler.background)
+ compiler.parameter("is_background", true);
+ if (compiler.output_type() == SHADER_TYPE_VOLUME)
+ compiler.parameter("is_volume", true);
+ compiler.parameter(this, "use_transform");
+ Transform ob_itfm = transform_inverse(ob_tfm);
+ compiler.parameter("object_itfm", ob_itfm);
+
+ compiler.parameter(this, "from_dupli");
+
+ compiler.add(this, "node_texture_coordinate");
+}
+
+/* UV Map */
+
+NODE_DEFINE(UVMapNode)
+{
+ NodeType *type = NodeType::add("uvmap", create, NodeType::SHADER);
+
+ SOCKET_STRING(attribute, "attribute", ustring());
+ SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false);
+
+ SOCKET_OUT_POINT(UV, "UV");
+
+ return type;
+}
+
+UVMapNode::UVMapNode() : ShaderNode(get_node_type())
+{
+}
+
+void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_surface) {
+ if (!from_dupli) {
+ if (!output("UV")->links.empty()) {
+ if (attribute != "")
+ attributes->add(attribute);
+ else
+ attributes->add(ATTR_STD_UV);
+ }
+ }
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void UVMapNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *out = output("UV");
+ ShaderNodeType texco_node = NODE_TEX_COORD;
+ ShaderNodeType attr_node = NODE_ATTR;
+ int attr;
+
+ if (bump == SHADER_BUMP_DX) {
+ texco_node = NODE_TEX_COORD_BUMP_DX;
+ attr_node = NODE_ATTR_BUMP_DX;
+ }
+ else if (bump == SHADER_BUMP_DY) {
+ texco_node = NODE_TEX_COORD_BUMP_DY;
+ attr_node = NODE_ATTR_BUMP_DY;
+ }
+
+ if (!out->links.empty()) {
+ if (from_dupli) {
+ compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
+ }
+ else {
+ if (attribute != "")
+ attr = compiler.attribute(attribute);
+ else
+ attr = compiler.attribute(ATTR_STD_UV);
+
+ compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
+ }
+ }
+}
+
+void UVMapNode::compile(OSLCompiler &compiler)
+{
+ if (bump == SHADER_BUMP_DX)
+ compiler.parameter("bump_offset", "dx");
+ else if (bump == SHADER_BUMP_DY)
+ compiler.parameter("bump_offset", "dy");
+ else
+ compiler.parameter("bump_offset", "center");
+
+ compiler.parameter(this, "from_dupli");
+ compiler.parameter(this, "attribute");
+ compiler.add(this, "node_uv_map");
+}
+
+/* Light Path */
+
+NODE_DEFINE(LightPathNode)
+{
+ NodeType *type = NodeType::add("light_path", create, NodeType::SHADER);
+
+ SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray");
+ SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray");
+ SOCKET_OUT_FLOAT(is_diffuse_ray, "Is Diffuse Ray");
+ SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray");
+ SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray");
+ SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray");
+ SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray");
+ SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray");
+ SOCKET_OUT_FLOAT(ray_length, "Ray Length");
+ SOCKET_OUT_FLOAT(ray_depth, "Ray Depth");
+ SOCKET_OUT_FLOAT(diffuse_depth, "Diffuse Depth");
+ SOCKET_OUT_FLOAT(glossy_depth, "Glossy Depth");
+ SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth");
+ SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth");
+
+ return type;
+}
+
+LightPathNode::LightPathNode() : ShaderNode(get_node_type())
+{
+}
+
+void LightPathNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *out;
+
+ out = output("Is Camera Ray");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_camera, compiler.stack_assign(out));
+ }
+
+ out = output("Is Shadow Ray");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_shadow, compiler.stack_assign(out));
+ }
+
+ out = output("Is Diffuse Ray");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_diffuse, compiler.stack_assign(out));
+ }
+
+ out = output("Is Glossy Ray");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, compiler.stack_assign(out));
+ }
+
+ out = output("Is Singular Ray");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_singular, compiler.stack_assign(out));
+ }
+
+ out = output("Is Reflection Ray");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, compiler.stack_assign(out));
+ }
+
+ out = output("Is Transmission Ray");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, compiler.stack_assign(out));
+ }
+
+ out = output("Is Volume Scatter Ray");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_volume_scatter, compiler.stack_assign(out));
+ }
+
+ out = output("Ray Length");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, compiler.stack_assign(out));
+ }
+
+ out = output("Ray Depth");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, compiler.stack_assign(out));
+ }
+
+ out = output("Diffuse Depth");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_diffuse, compiler.stack_assign(out));
+ }
+
+ out = output("Glossy Depth");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_glossy, compiler.stack_assign(out));
+ }
+
+ out = output("Transparent Depth");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, compiler.stack_assign(out));
+ }
+
+ out = output("Transmission Depth");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transmission, compiler.stack_assign(out));
+ }
+}
+
+void LightPathNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_light_path");
+}
+
+/* Light Falloff */
+
+NODE_DEFINE(LightFalloffNode)
+{
+ NodeType *type = NodeType::add("light_falloff", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(strength, "Strength", 100.0f);
+ SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
+
+ SOCKET_OUT_FLOAT(quadratic, "Quadratic");
+ SOCKET_OUT_FLOAT(linear, "Linear");
+ SOCKET_OUT_FLOAT(constant, "Constant");
+
+ return type;
+}
+
+LightFalloffNode::LightFalloffNode() : ShaderNode(get_node_type())
+{
+}
+
+void LightFalloffNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *strength_in = input("Strength");
+ ShaderInput *smooth_in = input("Smooth");
+
+ ShaderOutput *out = output("Quadratic");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_FALLOFF,
+ NODE_LIGHT_FALLOFF_QUADRATIC,
+ compiler.encode_uchar4(compiler.stack_assign(strength_in),
+ compiler.stack_assign(smooth_in),
+ compiler.stack_assign(out)));
+ }
+
+ out = output("Linear");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_FALLOFF,
+ NODE_LIGHT_FALLOFF_LINEAR,
+ compiler.encode_uchar4(compiler.stack_assign(strength_in),
+ compiler.stack_assign(smooth_in),
+ compiler.stack_assign(out)));
+ }
+
+ out = output("Constant");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_LIGHT_FALLOFF,
+ NODE_LIGHT_FALLOFF_CONSTANT,
+ compiler.encode_uchar4(compiler.stack_assign(strength_in),
+ compiler.stack_assign(smooth_in),
+ compiler.stack_assign(out)));
+ }
+}
+
+void LightFalloffNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_light_falloff");
+}
+
+/* Object Info */
+
+NODE_DEFINE(ObjectInfoNode)
+{
+ NodeType *type = NodeType::add("object_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_VECTOR(location, "Location");
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(object_index, "Object Index");
+ SOCKET_OUT_FLOAT(material_index, "Material Index");
+ SOCKET_OUT_FLOAT(random, "Random");
+
+ return type;
+}
+
+ObjectInfoNode::ObjectInfoNode() : ShaderNode(get_node_type())
+{
+}
+
+void ObjectInfoNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *out = output("Location");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, compiler.stack_assign(out));
+ }
+
+ out = output("Color");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_COLOR, compiler.stack_assign(out));
+ }
+
+ out = output("Object Index");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, compiler.stack_assign(out));
+ }
+
+ out = output("Material Index");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_MAT_INDEX, compiler.stack_assign(out));
+ }
+
+ out = output("Random");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_RANDOM, compiler.stack_assign(out));
+ }
+}
+
+void ObjectInfoNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_object_info");
+}
+
+/* Particle Info */
+
+NODE_DEFINE(ParticleInfoNode)
+{
+ NodeType *type = NodeType::add("particle_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_FLOAT(index, "Index");
+ SOCKET_OUT_FLOAT(random, "Random");
+ SOCKET_OUT_FLOAT(age, "Age");
+ SOCKET_OUT_FLOAT(lifetime, "Lifetime");
+ SOCKET_OUT_POINT(location, "Location");
+#if 0 /* not yet supported */
+ SOCKET_OUT_QUATERNION(rotation, "Rotation");
+#endif
+ SOCKET_OUT_FLOAT(size, "Size");
+ SOCKET_OUT_VECTOR(velocity, "Velocity");
+ SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity");
+
+ return type;
+}
+
+ParticleInfoNode::ParticleInfoNode() : ShaderNode(get_node_type())
+{
+}
+
+void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (!output("Index")->links.empty())
+ attributes->add(ATTR_STD_PARTICLE);
+ if (!output("Random")->links.empty())
+ attributes->add(ATTR_STD_PARTICLE);
+ if (!output("Age")->links.empty())
+ attributes->add(ATTR_STD_PARTICLE);
+ if (!output("Lifetime")->links.empty())
+ attributes->add(ATTR_STD_PARTICLE);
+ if (!output("Location")->links.empty())
+ attributes->add(ATTR_STD_PARTICLE);
+#if 0 /* not yet supported */
+ if (!output("Rotation")->links.empty())
+ attributes->add(ATTR_STD_PARTICLE);
+#endif
+ if (!output("Size")->links.empty())
+ attributes->add(ATTR_STD_PARTICLE);
+ if (!output("Velocity")->links.empty())
+ attributes->add(ATTR_STD_PARTICLE);
+ if (!output("Angular Velocity")->links.empty())
+ attributes->add(ATTR_STD_PARTICLE);
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void ParticleInfoNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *out;
+
+ out = output("Index");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_INDEX, compiler.stack_assign(out));
+ }
+
+ out = output("Random");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_RANDOM, compiler.stack_assign(out));
+ }
+
+ out = output("Age");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_AGE, compiler.stack_assign(out));
+ }
+
+ out = output("Lifetime");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LIFETIME, compiler.stack_assign(out));
+ }
+
+ out = output("Location");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LOCATION, compiler.stack_assign(out));
+ }
+
+ /* quaternion data is not yet supported by Cycles */
+#if 0
+ out = output("Rotation");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ROTATION, compiler.stack_assign(out));
+ }
+#endif
+
+ out = output("Size");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_SIZE, compiler.stack_assign(out));
+ }
+
+ out = output("Velocity");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_VELOCITY, compiler.stack_assign(out));
+ }
+
+ out = output("Angular Velocity");
+ if (!out->links.empty()) {
+ compiler.add_node(
+ NODE_PARTICLE_INFO, NODE_INFO_PAR_ANGULAR_VELOCITY, compiler.stack_assign(out));
+ }
+}
+
+void ParticleInfoNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_particle_info");
+}
+
+/* Hair Info */
+
+NODE_DEFINE(HairInfoNode)
+{
+ NodeType *type = NodeType::add("hair_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_FLOAT(is_strand, "Is Strand");
+ SOCKET_OUT_FLOAT(intercept, "Intercept");
+ SOCKET_OUT_FLOAT(size, "Length");
+ SOCKET_OUT_FLOAT(thickness, "Thickness");
+ SOCKET_OUT_NORMAL(tangent_normal, "Tangent Normal");
+#if 0 /* Output for minimum hair width transparency - deactivated. */
+ SOCKET_OUT_FLOAT(fade, "Fade");
+#endif
+ SOCKET_OUT_FLOAT(index, "Random");
+
+ return type;
+}
+
+HairInfoNode::HairInfoNode() : ShaderNode(get_node_type())
+{
+}
+
+void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_surface_link()) {
+ ShaderOutput *intercept_out = output("Intercept");
+
+ if (!intercept_out->links.empty())
+ attributes->add(ATTR_STD_CURVE_INTERCEPT);
+
+ if (!output("Length")->links.empty())
+ attributes->add(ATTR_STD_CURVE_LENGTH);
+
+ if (!output("Random")->links.empty())
+ attributes->add(ATTR_STD_CURVE_RANDOM);
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void HairInfoNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *out;
+
+ out = output("Is Strand");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, compiler.stack_assign(out));
+ }
+
+ out = output("Intercept");
+ if (!out->links.empty()) {
+ int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT);
+ compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
+ }
+
+ out = output("Length");
+ if (!out->links.empty()) {
+ int attr = compiler.attribute(ATTR_STD_CURVE_LENGTH);
+ compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
+ }
+
+ out = output("Thickness");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, compiler.stack_assign(out));
+ }
+
+ out = output("Tangent Normal");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, compiler.stack_assign(out));
+ }
+#if 0
+ out = output("Fade");
+ if(!out->links.empty()) {
+ compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_FADE, compiler.stack_assign(out));
+ }
+#endif
+ out = output("Random");
+ if (!out->links.empty()) {
+ int attr = compiler.attribute(ATTR_STD_CURVE_RANDOM);
+ compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
+ }
+}
+
+void HairInfoNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_hair_info");
+}
+
+/* Volume Info */
+
+NODE_DEFINE(VolumeInfoNode)
+{
+ NodeType *type = NodeType::add("volume_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(density, "Density");
+ SOCKET_OUT_FLOAT(flame, "Flame");
+ SOCKET_OUT_FLOAT(temperature, "Temperature");
+
+ return type;
+}
+
+VolumeInfoNode::VolumeInfoNode() : ShaderNode(get_node_type())
+{
+}
+
+/* The requested attributes are not updated after node expansion.
+ * So we explicitly request the required attributes.
+ */
+void VolumeInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_volume) {
+ if (!output("Color")->links.empty()) {
+ attributes->add(ATTR_STD_VOLUME_COLOR);
+ }
+ if (!output("Density")->links.empty()) {
+ attributes->add(ATTR_STD_VOLUME_DENSITY);
+ }
+ if (!output("Flame")->links.empty()) {
+ attributes->add(ATTR_STD_VOLUME_FLAME);
+ }
+ if (!output("Temperature")->links.empty()) {
+ attributes->add(ATTR_STD_VOLUME_TEMPERATURE);
+ }
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+ }
+ ShaderNode::attributes(shader, attributes);
+}
+
+void VolumeInfoNode::expand(ShaderGraph *graph)
+{
+ ShaderOutput *color_out = output("Color");
+ if (!color_out->links.empty()) {
+ AttributeNode *attr = graph->create_node<AttributeNode>();
+ attr->set_attribute(ustring("color"));
+ graph->add(attr);
+ graph->relink(color_out, attr->output("Color"));
+ }
+
+ ShaderOutput *density_out = output("Density");
+ if (!density_out->links.empty()) {
+ AttributeNode *attr = graph->create_node<AttributeNode>();
+ attr->set_attribute(ustring("density"));
+ graph->add(attr);
+ graph->relink(density_out, attr->output("Fac"));
+ }
+
+ ShaderOutput *flame_out = output("Flame");
+ if (!flame_out->links.empty()) {
+ AttributeNode *attr = graph->create_node<AttributeNode>();
+ attr->set_attribute(ustring("flame"));
+ graph->add(attr);
+ graph->relink(flame_out, attr->output("Fac"));
+ }
+
+ ShaderOutput *temperature_out = output("Temperature");
+ if (!temperature_out->links.empty()) {
+ AttributeNode *attr = graph->create_node<AttributeNode>();
+ attr->set_attribute(ustring("temperature"));
+ graph->add(attr);
+ graph->relink(temperature_out, attr->output("Fac"));
+ }
+}
+
+void VolumeInfoNode::compile(SVMCompiler &)
+{
+}
+
+void VolumeInfoNode::compile(OSLCompiler &)
+{
+}
+
+NODE_DEFINE(VertexColorNode)
+{
+ NodeType *type = NodeType::add("vertex_color", create, NodeType::SHADER);
+
+ SOCKET_STRING(layer_name, "Layer Name", ustring());
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
+
+VertexColorNode::VertexColorNode() : ShaderNode(get_node_type())
+{
+}
+
+void VertexColorNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (!(output("Color")->links.empty() && output("Alpha")->links.empty())) {
+ if (layer_name != "")
+ attributes->add_standard(layer_name);
+ else
+ attributes->add(ATTR_STD_VERTEX_COLOR);
+ }
+ ShaderNode::attributes(shader, attributes);
+}
+
+void VertexColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *alpha_out = output("Alpha");
+ int layer_id = 0;
+
+ if (layer_name != "") {
+ layer_id = compiler.attribute(layer_name);
+ }
+ else {
+ layer_id = compiler.attribute(ATTR_STD_VERTEX_COLOR);
+ }
+
+ ShaderNodeType node;
+
+ if (bump == SHADER_BUMP_DX)
+ node = NODE_VERTEX_COLOR_BUMP_DX;
+ else if (bump == SHADER_BUMP_DY)
+ node = NODE_VERTEX_COLOR_BUMP_DY;
+ else {
+ node = NODE_VERTEX_COLOR;
+ }
+
+ compiler.add_node(
+ node, layer_id, compiler.stack_assign(color_out), compiler.stack_assign(alpha_out));
+}
+
+void VertexColorNode::compile(OSLCompiler &compiler)
+{
+ if (bump == SHADER_BUMP_DX) {
+ compiler.parameter("bump_offset", "dx");
+ }
+ else if (bump == SHADER_BUMP_DY) {
+ compiler.parameter("bump_offset", "dy");
+ }
+ else {
+ compiler.parameter("bump_offset", "center");
+ }
+
+ if (layer_name.empty()) {
+ compiler.parameter("layer_name", ustring("geom:vertex_color"));
+ }
+ else {
+ if (Attribute::name_standard(layer_name.c_str()) != ATTR_STD_NONE) {
+ compiler.parameter("name", (string("geom:") + layer_name.c_str()).c_str());
+ }
+ else {
+ compiler.parameter("layer_name", layer_name.c_str());
+ }
+ }
+
+ compiler.add(this, "node_vertex_color");
+}
+
+/* Value */
+
+NODE_DEFINE(ValueNode)
+{
+ NodeType *type = NodeType::add("value", create, NodeType::SHADER);
+
+ SOCKET_FLOAT(value, "Value", 0.0f);
+ SOCKET_OUT_FLOAT(value, "Value");
+
+ return type;
+}
+
+ValueNode::ValueNode() : ShaderNode(get_node_type())
+{
+}
+
+void ValueNode::constant_fold(const ConstantFolder &folder)
+{
+ folder.make_constant(value);
+}
+
+void ValueNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *val_out = output("Value");
+
+ compiler.add_node(NODE_VALUE_F, __float_as_int(value), compiler.stack_assign(val_out));
+}
+
+void ValueNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter("value_value", value);
+ compiler.add(this, "node_value");
+}
+
+/* Color */
+
+NODE_DEFINE(ColorNode)
+{
+ NodeType *type = NodeType::add("color", create, NodeType::SHADER);
+
+ SOCKET_COLOR(value, "Value", zero_float3());
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+ColorNode::ColorNode() : ShaderNode(get_node_type())
+{
+}
+
+void ColorNode::constant_fold(const ConstantFolder &folder)
+{
+ folder.make_constant(value);
+}
+
+void ColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *color_out = output("Color");
+
+ if (!color_out->links.empty()) {
+ compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
+ compiler.add_node(NODE_VALUE_V, value);
+ }
+}
+
+void ColorNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter_color("color_value", value);
+
+ compiler.add(this, "node_value");
+}
+
+/* Add Closure */
+
+NODE_DEFINE(AddClosureNode)
+{
+ NodeType *type = NodeType::add("add_closure", create, NodeType::SHADER);
+
+ SOCKET_IN_CLOSURE(closure1, "Closure1");
+ SOCKET_IN_CLOSURE(closure2, "Closure2");
+ SOCKET_OUT_CLOSURE(closure, "Closure");
+
+ return type;
+}
+
+AddClosureNode::AddClosureNode() : ShaderNode(get_node_type())
+{
+ special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
+}
+
+void AddClosureNode::compile(SVMCompiler & /*compiler*/)
+{
+ /* handled in the SVM compiler */
+}
+
+void AddClosureNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_add_closure");
+}
+
+void AddClosureNode::constant_fold(const ConstantFolder &folder)
+{
+ ShaderInput *closure1_in = input("Closure1");
+ ShaderInput *closure2_in = input("Closure2");
+
+ /* remove useless add closures nodes */
+ if (!closure1_in->link) {
+ folder.bypass_or_discard(closure2_in);
+ }
+ else if (!closure2_in->link) {
+ folder.bypass_or_discard(closure1_in);
+ }
+}
+
+/* Mix Closure */
+
+NODE_DEFINE(MixClosureNode)
+{
+ NodeType *type = NodeType::add("mix_closure", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
+ SOCKET_IN_CLOSURE(closure1, "Closure1");
+ SOCKET_IN_CLOSURE(closure2, "Closure2");
+
+ SOCKET_OUT_CLOSURE(closure, "Closure");
+
+ return type;
+}
+
+MixClosureNode::MixClosureNode() : ShaderNode(get_node_type())
+{
+ special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
+}
+
+void MixClosureNode::compile(SVMCompiler & /*compiler*/)
+{
+ /* handled in the SVM compiler */
+}
+
+void MixClosureNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_mix_closure");
+}
+
+void MixClosureNode::constant_fold(const ConstantFolder &folder)
+{
+ ShaderInput *fac_in = input("Fac");
+ ShaderInput *closure1_in = input("Closure1");
+ ShaderInput *closure2_in = input("Closure2");
+
+ /* remove useless mix closures nodes */
+ if (closure1_in->link == closure2_in->link) {
+ folder.bypass_or_discard(closure1_in);
+ }
+ /* remove unused mix closure input when factor is 0.0 or 1.0
+ * check for closure links and make sure factor link is disconnected */
+ else if (!fac_in->link) {
+ /* factor 0.0 */
+ if (fac <= 0.0f) {
+ folder.bypass_or_discard(closure1_in);
+ }
+ /* factor 1.0 */
+ else if (fac >= 1.0f) {
+ folder.bypass_or_discard(closure2_in);
+ }
+ }
+}
+
+/* Mix Closure */
+
+NODE_DEFINE(MixClosureWeightNode)
+{
+ NodeType *type = NodeType::add("mix_closure_weight", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(weight, "Weight", 1.0f);
+ SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
+
+ SOCKET_OUT_FLOAT(weight1, "Weight1");
+ SOCKET_OUT_FLOAT(weight2, "Weight2");
+
+ return type;
+}
+
+MixClosureWeightNode::MixClosureWeightNode() : ShaderNode(get_node_type())
+{
+}
+
+void MixClosureWeightNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *weight_in = input("Weight");
+ ShaderInput *fac_in = input("Fac");
+ ShaderOutput *weight1_out = output("Weight1");
+ ShaderOutput *weight2_out = output("Weight2");
+
+ compiler.add_node(NODE_MIX_CLOSURE,
+ compiler.encode_uchar4(compiler.stack_assign(fac_in),
+ compiler.stack_assign(weight_in),
+ compiler.stack_assign(weight1_out),
+ compiler.stack_assign(weight2_out)));
+}
+
+void MixClosureWeightNode::compile(OSLCompiler & /*compiler*/)
+{
+ assert(0);
+}
+
+/* Invert */
+
+NODE_DEFINE(InvertNode)
+{
+ NodeType *type = NodeType::add("invert", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
+ SOCKET_IN_COLOR(color, "Color", zero_float3());
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+InvertNode::InvertNode() : ShaderNode(get_node_type())
+{
+}
+
+void InvertNode::constant_fold(const ConstantFolder &folder)
+{
+ ShaderInput *fac_in = input("Fac");
+ ShaderInput *color_in = input("Color");
+
+ if (!fac_in->link) {
+ /* evaluate fully constant node */
+ if (!color_in->link) {
+ folder.make_constant(interp(color, one_float3() - color, fac));
+ }
+ /* remove no-op node */
+ else if (fac == 0.0f) {
+ folder.bypass(color_in->link);
+ }
+ }
+}
+
+void InvertNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *fac_in = input("Fac");
+ ShaderInput *color_in = input("Color");
+ ShaderOutput *color_out = output("Color");
+
+ compiler.add_node(NODE_INVERT,
+ compiler.stack_assign(fac_in),
+ compiler.stack_assign(color_in),
+ compiler.stack_assign(color_out));
+}
+
+void InvertNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_invert");
+}
+
+/* Mix */
+
+NODE_DEFINE(MixNode)
+{
+ NodeType *type = NodeType::add("mix", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("mix", NODE_MIX_BLEND);
+ type_enum.insert("add", NODE_MIX_ADD);
+ type_enum.insert("multiply", NODE_MIX_MUL);
+ type_enum.insert("screen", NODE_MIX_SCREEN);
+ type_enum.insert("overlay", NODE_MIX_OVERLAY);
+ type_enum.insert("subtract", NODE_MIX_SUB);
+ type_enum.insert("divide", NODE_MIX_DIV);
+ type_enum.insert("difference", NODE_MIX_DIFF);
+ type_enum.insert("darken", NODE_MIX_DARK);
+ type_enum.insert("lighten", NODE_MIX_LIGHT);
+ type_enum.insert("dodge", NODE_MIX_DODGE);
+ type_enum.insert("burn", NODE_MIX_BURN);
+ type_enum.insert("hue", NODE_MIX_HUE);
+ type_enum.insert("saturation", NODE_MIX_SAT);
+ type_enum.insert("value", NODE_MIX_VAL);
+ type_enum.insert("color", NODE_MIX_COLOR);
+ type_enum.insert("soft_light", NODE_MIX_SOFT);
+ type_enum.insert("linear_light", NODE_MIX_LINEAR);
+ SOCKET_ENUM(mix_type, "Type", type_enum, NODE_MIX_BLEND);
+
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
+ SOCKET_IN_COLOR(color1, "Color1", zero_float3());
+ SOCKET_IN_COLOR(color2, "Color2", zero_float3());
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+MixNode::MixNode() : ShaderNode(get_node_type())
+{
+}
+
+void MixNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *fac_in = input("Fac");
+ ShaderInput *color1_in = input("Color1");
+ ShaderInput *color2_in = input("Color2");
+ ShaderOutput *color_out = output("Color");
+
+ compiler.add_node(NODE_MIX,
+ compiler.stack_assign(fac_in),
+ compiler.stack_assign(color1_in),
+ compiler.stack_assign(color2_in));
+ compiler.add_node(NODE_MIX, mix_type, compiler.stack_assign(color_out));
+
+ if (use_clamp) {
+ compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out));
+ compiler.add_node(NODE_MIX, NODE_MIX_CLAMP, compiler.stack_assign(color_out));
+ }
+}
+
+void MixNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "mix_type");
+ compiler.parameter(this, "use_clamp");
+ compiler.add(this, "node_mix");
+}
+
+void MixNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant_clamp(svm_mix(mix_type, fac, color1, color2), use_clamp);
+ }
+ else {
+ folder.fold_mix(mix_type, use_clamp);
+ }
+}
+
+/* Combine RGB */
+
+NODE_DEFINE(CombineRGBNode)
+{
+ NodeType *type = NodeType::add("combine_rgb", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(r, "R", 0.0f);
+ SOCKET_IN_FLOAT(g, "G", 0.0f);
+ SOCKET_IN_FLOAT(b, "B", 0.0f);
+
+ SOCKET_OUT_COLOR(image, "Image");
+
+ return type;
+}
+
+CombineRGBNode::CombineRGBNode() : ShaderNode(get_node_type())
+{
+}
+
+void CombineRGBNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(make_float3(r, g, b));
+ }
+}
+
+void CombineRGBNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *red_in = input("R");
+ ShaderInput *green_in = input("G");
+ ShaderInput *blue_in = input("B");
+ ShaderOutput *color_out = output("Image");
+
+ compiler.add_node(
+ NODE_COMBINE_VECTOR, compiler.stack_assign(red_in), 0, compiler.stack_assign(color_out));
+
+ compiler.add_node(
+ NODE_COMBINE_VECTOR, compiler.stack_assign(green_in), 1, compiler.stack_assign(color_out));
+
+ compiler.add_node(
+ NODE_COMBINE_VECTOR, compiler.stack_assign(blue_in), 2, compiler.stack_assign(color_out));
+}
+
+void CombineRGBNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_combine_rgb");
+}
+
+/* Combine XYZ */
+
+NODE_DEFINE(CombineXYZNode)
+{
+ NodeType *type = NodeType::add("combine_xyz", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(x, "X", 0.0f);
+ SOCKET_IN_FLOAT(y, "Y", 0.0f);
+ SOCKET_IN_FLOAT(z, "Z", 0.0f);
+
+ SOCKET_OUT_VECTOR(vector, "Vector");
+
+ return type;
+}
+
+CombineXYZNode::CombineXYZNode() : ShaderNode(get_node_type())
+{
+}
+
+void CombineXYZNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(make_float3(x, y, z));
+ }
+}
+
+void CombineXYZNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *x_in = input("X");
+ ShaderInput *y_in = input("Y");
+ ShaderInput *z_in = input("Z");
+ ShaderOutput *vector_out = output("Vector");
+
+ compiler.add_node(
+ NODE_COMBINE_VECTOR, compiler.stack_assign(x_in), 0, compiler.stack_assign(vector_out));
+
+ compiler.add_node(
+ NODE_COMBINE_VECTOR, compiler.stack_assign(y_in), 1, compiler.stack_assign(vector_out));
+
+ compiler.add_node(
+ NODE_COMBINE_VECTOR, compiler.stack_assign(z_in), 2, compiler.stack_assign(vector_out));
+}
+
+void CombineXYZNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_combine_xyz");
+}
+
+/* Combine HSV */
+
+NODE_DEFINE(CombineHSVNode)
+{
+ NodeType *type = NodeType::add("combine_hsv", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(h, "H", 0.0f);
+ SOCKET_IN_FLOAT(s, "S", 0.0f);
+ SOCKET_IN_FLOAT(v, "V", 0.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+CombineHSVNode::CombineHSVNode() : ShaderNode(get_node_type())
+{
+}
+
+void CombineHSVNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(hsv_to_rgb(make_float3(h, s, v)));
+ }
+}
+
+void CombineHSVNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *hue_in = input("H");
+ ShaderInput *saturation_in = input("S");
+ ShaderInput *value_in = input("V");
+ ShaderOutput *color_out = output("Color");
+
+ compiler.add_node(NODE_COMBINE_HSV,
+ compiler.stack_assign(hue_in),
+ compiler.stack_assign(saturation_in),
+ compiler.stack_assign(value_in));
+ compiler.add_node(NODE_COMBINE_HSV, compiler.stack_assign(color_out));
+}
+
+void CombineHSVNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_combine_hsv");
+}
+
+/* Gamma */
+
+NODE_DEFINE(GammaNode)
+{
+ NodeType *type = NodeType::add("gamma", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", zero_float3());
+ SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f);
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+GammaNode::GammaNode() : ShaderNode(get_node_type())
+{
+}
+
+void GammaNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(svm_math_gamma_color(color, gamma));
+ }
+ else {
+ ShaderInput *color_in = input("Color");
+ ShaderInput *gamma_in = input("Gamma");
+
+ /* 1 ^ X == X ^ 0 == 1 */
+ if (folder.is_one(color_in) || folder.is_zero(gamma_in)) {
+ folder.make_one();
+ }
+ /* X ^ 1 == X */
+ else if (folder.is_one(gamma_in)) {
+ folder.try_bypass_or_make_constant(color_in, false);
+ }
+ }
+}
+
+void GammaNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *gamma_in = input("Gamma");
+ ShaderOutput *color_out = output("Color");
+
+ compiler.add_node(NODE_GAMMA,
+ compiler.stack_assign(gamma_in),
+ compiler.stack_assign(color_in),
+ compiler.stack_assign(color_out));
+}
+
+void GammaNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_gamma");
+}
+
+/* Bright Contrast */
+
+NODE_DEFINE(BrightContrastNode)
+{
+ NodeType *type = NodeType::add("brightness_contrast", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", zero_float3());
+ SOCKET_IN_FLOAT(bright, "Bright", 0.0f);
+ SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+BrightContrastNode::BrightContrastNode() : ShaderNode(get_node_type())
+{
+}
+
+void BrightContrastNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(svm_brightness_contrast(color, bright, contrast));
+ }
+}
+
+void BrightContrastNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *bright_in = input("Bright");
+ ShaderInput *contrast_in = input("Contrast");
+ ShaderOutput *color_out = output("Color");
+
+ compiler.add_node(NODE_BRIGHTCONTRAST,
+ compiler.stack_assign(color_in),
+ compiler.stack_assign(color_out),
+ compiler.encode_uchar4(compiler.stack_assign(bright_in),
+ compiler.stack_assign(contrast_in)));
+}
+
+void BrightContrastNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_brightness");
+}
+
+/* Separate RGB */
+
+NODE_DEFINE(SeparateRGBNode)
+{
+ NodeType *type = NodeType::add("separate_rgb", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Image", zero_float3());
+
+ SOCKET_OUT_FLOAT(r, "R");
+ SOCKET_OUT_FLOAT(g, "G");
+ SOCKET_OUT_FLOAT(b, "B");
+
+ return type;
+}
+
+SeparateRGBNode::SeparateRGBNode() : ShaderNode(get_node_type())
+{
+}
+
+void SeparateRGBNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ for (int channel = 0; channel < 3; channel++) {
+ if (outputs[channel] == folder.output) {
+ folder.make_constant(color[channel]);
+ return;
+ }
+ }
+ }
+}
+
+void SeparateRGBNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Image");
+ ShaderOutput *red_out = output("R");
+ ShaderOutput *green_out = output("G");
+ ShaderOutput *blue_out = output("B");
+
+ compiler.add_node(
+ NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 0, compiler.stack_assign(red_out));
+
+ compiler.add_node(
+ NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 1, compiler.stack_assign(green_out));
+
+ compiler.add_node(
+ NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 2, compiler.stack_assign(blue_out));
+}
+
+void SeparateRGBNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_separate_rgb");
+}
+
+/* Separate XYZ */
+
+NODE_DEFINE(SeparateXYZNode)
+{
+ NodeType *type = NodeType::add("separate_xyz", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(vector, "Vector", zero_float3());
+
+ SOCKET_OUT_FLOAT(x, "X");
+ SOCKET_OUT_FLOAT(y, "Y");
+ SOCKET_OUT_FLOAT(z, "Z");
+
+ return type;
+}
+
+SeparateXYZNode::SeparateXYZNode() : ShaderNode(get_node_type())
+{
+}
+
+void SeparateXYZNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ for (int channel = 0; channel < 3; channel++) {
+ if (outputs[channel] == folder.output) {
+ folder.make_constant(vector[channel]);
+ return;
+ }
+ }
+ }
+}
+
+void SeparateXYZNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *x_out = output("X");
+ ShaderOutput *y_out = output("Y");
+ ShaderOutput *z_out = output("Z");
+
+ compiler.add_node(
+ NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 0, compiler.stack_assign(x_out));
+
+ compiler.add_node(
+ NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 1, compiler.stack_assign(y_out));
+
+ compiler.add_node(
+ NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 2, compiler.stack_assign(z_out));
+}
+
+void SeparateXYZNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_separate_xyz");
+}
+
+/* Separate HSV */
+
+NODE_DEFINE(SeparateHSVNode)
+{
+ NodeType *type = NodeType::add("separate_hsv", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", zero_float3());
+
+ SOCKET_OUT_FLOAT(h, "H");
+ SOCKET_OUT_FLOAT(s, "S");
+ SOCKET_OUT_FLOAT(v, "V");
+
+ return type;
+}
+
+SeparateHSVNode::SeparateHSVNode() : ShaderNode(get_node_type())
+{
+}
+
+void SeparateHSVNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ float3 hsv = rgb_to_hsv(color);
+
+ for (int channel = 0; channel < 3; channel++) {
+ if (outputs[channel] == folder.output) {
+ folder.make_constant(hsv[channel]);
+ return;
+ }
+ }
+ }
+}
+
+void SeparateHSVNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderOutput *hue_out = output("H");
+ ShaderOutput *saturation_out = output("S");
+ ShaderOutput *value_out = output("V");
+
+ compiler.add_node(NODE_SEPARATE_HSV,
+ compiler.stack_assign(color_in),
+ compiler.stack_assign(hue_out),
+ compiler.stack_assign(saturation_out));
+ compiler.add_node(NODE_SEPARATE_HSV, compiler.stack_assign(value_out));
+}
+
+void SeparateHSVNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_separate_hsv");
+}
+
+/* Hue Saturation Value */
+
+NODE_DEFINE(HSVNode)
+{
+ NodeType *type = NodeType::add("hsv", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(hue, "Hue", 0.5f);
+ SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f);
+ SOCKET_IN_FLOAT(value, "Value", 1.0f);
+ SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
+ SOCKET_IN_COLOR(color, "Color", zero_float3());
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+HSVNode::HSVNode() : ShaderNode(get_node_type())
+{
+}
+
+void HSVNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *hue_in = input("Hue");
+ ShaderInput *saturation_in = input("Saturation");
+ ShaderInput *value_in = input("Value");
+ ShaderInput *fac_in = input("Fac");
+ ShaderInput *color_in = input("Color");
+ ShaderOutput *color_out = output("Color");
+
+ compiler.add_node(NODE_HSV,
+ compiler.encode_uchar4(compiler.stack_assign(color_in),
+ compiler.stack_assign(fac_in),
+ compiler.stack_assign(color_out)),
+ compiler.encode_uchar4(compiler.stack_assign(hue_in),
+ compiler.stack_assign(saturation_in),
+ compiler.stack_assign(value_in)));
+}
+
+void HSVNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_hsv");
+}
+
+/* Attribute */
+
+NODE_DEFINE(AttributeNode)
+{
+ NodeType *type = NodeType::add("attribute", create, NodeType::SHADER);
+
+ SOCKET_STRING(attribute, "Attribute", ustring());
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_VECTOR(vector, "Vector");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
+
+AttributeNode::AttributeNode() : ShaderNode(get_node_type())
+{
+}
+
+void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *vector_out = output("Vector");
+ ShaderOutput *fac_out = output("Fac");
+ ShaderOutput *alpha_out = output("Alpha");
+
+ if (!color_out->links.empty() || !vector_out->links.empty() || !fac_out->links.empty() ||
+ !alpha_out->links.empty()) {
+ attributes->add_standard(attribute);
+ }
+
+ if (shader->has_volume) {
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void AttributeNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *vector_out = output("Vector");
+ ShaderOutput *fac_out = output("Fac");
+ ShaderOutput *alpha_out = output("Alpha");
+ ShaderNodeType attr_node = NODE_ATTR;
+ int attr = compiler.attribute_standard(attribute);
+
+ if (bump == SHADER_BUMP_DX)
+ attr_node = NODE_ATTR_BUMP_DX;
+ else if (bump == SHADER_BUMP_DY)
+ attr_node = NODE_ATTR_BUMP_DY;
+
+ if (!color_out->links.empty() || !vector_out->links.empty()) {
+ if (!color_out->links.empty()) {
+ compiler.add_node(
+ attr_node, attr, compiler.stack_assign(color_out), NODE_ATTR_OUTPUT_FLOAT3);
+ }
+ if (!vector_out->links.empty()) {
+ compiler.add_node(
+ attr_node, attr, compiler.stack_assign(vector_out), NODE_ATTR_OUTPUT_FLOAT3);
+ }
+ }
+
+ if (!fac_out->links.empty()) {
+ compiler.add_node(attr_node, attr, compiler.stack_assign(fac_out), NODE_ATTR_OUTPUT_FLOAT);
+ }
+
+ if (!alpha_out->links.empty()) {
+ compiler.add_node(
+ attr_node, attr, compiler.stack_assign(alpha_out), NODE_ATTR_OUTPUT_FLOAT_ALPHA);
+ }
+}
+
+void AttributeNode::compile(OSLCompiler &compiler)
+{
+ if (bump == SHADER_BUMP_DX)
+ compiler.parameter("bump_offset", "dx");
+ else if (bump == SHADER_BUMP_DY)
+ compiler.parameter("bump_offset", "dy");
+ else
+ compiler.parameter("bump_offset", "center");
+
+ if (Attribute::name_standard(attribute.c_str()) != ATTR_STD_NONE)
+ compiler.parameter("name", (string("geom:") + attribute.c_str()).c_str());
+ else
+ compiler.parameter("name", attribute.c_str());
+
+ compiler.add(this, "node_attribute");
+}
+
+/* Camera */
+
+NODE_DEFINE(CameraNode)
+{
+ NodeType *type = NodeType::add("camera_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_VECTOR(view_vector, "View Vector");
+ SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth");
+ SOCKET_OUT_FLOAT(view_distance, "View Distance");
+
+ return type;
+}
+
+CameraNode::CameraNode() : ShaderNode(get_node_type())
+{
+}
+
+void CameraNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *vector_out = output("View Vector");
+ ShaderOutput *z_depth_out = output("View Z Depth");
+ ShaderOutput *distance_out = output("View Distance");
+
+ compiler.add_node(NODE_CAMERA,
+ compiler.stack_assign(vector_out),
+ compiler.stack_assign(z_depth_out),
+ compiler.stack_assign(distance_out));
+}
+
+void CameraNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_camera");
+}
+
+/* Fresnel */
+
+NODE_DEFINE(FresnelNode)
+{
+ NodeType *type = NodeType::add("fresnel", create, NodeType::SHADER);
+
+ SOCKET_IN_NORMAL(
+ normal, "Normal", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ SOCKET_IN_FLOAT(IOR, "IOR", 1.45f);
+
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+FresnelNode::FresnelNode() : ShaderNode(get_node_type())
+{
+}
+
+void FresnelNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *normal_in = input("Normal");
+ ShaderInput *IOR_in = input("IOR");
+ ShaderOutput *fac_out = output("Fac");
+
+ compiler.add_node(NODE_FRESNEL,
+ compiler.stack_assign(IOR_in),
+ __float_as_int(IOR),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(normal_in),
+ compiler.stack_assign(fac_out)));
+}
+
+void FresnelNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_fresnel");
+}
+
+/* Layer Weight */
+
+NODE_DEFINE(LayerWeightNode)
+{
+ NodeType *type = NodeType::add("layer_weight", create, NodeType::SHADER);
+
+ SOCKET_IN_NORMAL(
+ normal, "Normal", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ SOCKET_IN_FLOAT(blend, "Blend", 0.5f);
+
+ SOCKET_OUT_FLOAT(fresnel, "Fresnel");
+ SOCKET_OUT_FLOAT(facing, "Facing");
+
+ return type;
+}
+
+LayerWeightNode::LayerWeightNode() : ShaderNode(get_node_type())
+{
+}
+
+void LayerWeightNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *normal_in = input("Normal");
+ ShaderInput *blend_in = input("Blend");
+ ShaderOutput *fresnel_out = output("Fresnel");
+ ShaderOutput *facing_out = output("Facing");
+
+ if (!fresnel_out->links.empty()) {
+ compiler.add_node(NODE_LAYER_WEIGHT,
+ compiler.stack_assign_if_linked(blend_in),
+ __float_as_int(blend),
+ compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL,
+ compiler.stack_assign_if_linked(normal_in),
+ compiler.stack_assign(fresnel_out)));
+ }
+
+ if (!facing_out->links.empty()) {
+ compiler.add_node(NODE_LAYER_WEIGHT,
+ compiler.stack_assign_if_linked(blend_in),
+ __float_as_int(blend),
+ compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING,
+ compiler.stack_assign_if_linked(normal_in),
+ compiler.stack_assign(facing_out)));
+ }
+}
+
+void LayerWeightNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_layer_weight");
+}
+
+/* Wireframe */
+
+NODE_DEFINE(WireframeNode)
+{
+ NodeType *type = NodeType::add("wireframe", create, NodeType::SHADER);
+
+ SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false);
+ SOCKET_IN_FLOAT(size, "Size", 0.01f);
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+WireframeNode::WireframeNode() : ShaderNode(get_node_type())
+{
+}
+
+void WireframeNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *size_in = input("Size");
+ ShaderOutput *fac_out = output("Fac");
+ NodeBumpOffset bump_offset = NODE_BUMP_OFFSET_CENTER;
+ if (bump == SHADER_BUMP_DX) {
+ bump_offset = NODE_BUMP_OFFSET_DX;
+ }
+ else if (bump == SHADER_BUMP_DY) {
+ bump_offset = NODE_BUMP_OFFSET_DY;
+ }
+ compiler.add_node(NODE_WIREFRAME,
+ compiler.stack_assign(size_in),
+ compiler.stack_assign(fac_out),
+ compiler.encode_uchar4(use_pixel_size, bump_offset, 0, 0));
+}
+
+void WireframeNode::compile(OSLCompiler &compiler)
+{
+ if (bump == SHADER_BUMP_DX) {
+ compiler.parameter("bump_offset", "dx");
+ }
+ else if (bump == SHADER_BUMP_DY) {
+ compiler.parameter("bump_offset", "dy");
+ }
+ else {
+ compiler.parameter("bump_offset", "center");
+ }
+ compiler.parameter(this, "use_pixel_size");
+ compiler.add(this, "node_wireframe");
+}
+
+/* Wavelength */
+
+NODE_DEFINE(WavelengthNode)
+{
+ NodeType *type = NodeType::add("wavelength", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f);
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+WavelengthNode::WavelengthNode() : ShaderNode(get_node_type())
+{
+}
+
+void WavelengthNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *wavelength_in = input("Wavelength");
+ ShaderOutput *color_out = output("Color");
+
+ compiler.add_node(
+ NODE_WAVELENGTH, compiler.stack_assign(wavelength_in), compiler.stack_assign(color_out));
+}
+
+void WavelengthNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_wavelength");
+}
+
+/* Blackbody */
+
+NODE_DEFINE(BlackbodyNode)
+{
+ NodeType *type = NodeType::add("blackbody", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f);
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+BlackbodyNode::BlackbodyNode() : ShaderNode(get_node_type())
+{
+}
+
+void BlackbodyNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(svm_math_blackbody_color(temperature));
+ }
+}
+
+void BlackbodyNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *temperature_in = input("Temperature");
+ ShaderOutput *color_out = output("Color");
+
+ compiler.add_node(
+ NODE_BLACKBODY, compiler.stack_assign(temperature_in), compiler.stack_assign(color_out));
+}
+
+void BlackbodyNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_blackbody");
+}
+
+/* Output */
+
+NODE_DEFINE(OutputNode)
+{
+ NodeType *type = NodeType::add("output", create, NodeType::SHADER);
+
+ SOCKET_IN_CLOSURE(surface, "Surface");
+ SOCKET_IN_CLOSURE(volume, "Volume");
+ SOCKET_IN_VECTOR(displacement, "Displacement", zero_float3());
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3());
+
+ return type;
+}
+
+OutputNode::OutputNode() : ShaderNode(get_node_type())
+{
+ special_type = SHADER_SPECIAL_TYPE_OUTPUT;
+}
+
+void OutputNode::compile(SVMCompiler &compiler)
+{
+ if (compiler.output_type() == SHADER_TYPE_DISPLACEMENT) {
+ ShaderInput *displacement_in = input("Displacement");
+
+ if (displacement_in->link) {
+ compiler.add_node(NODE_SET_DISPLACEMENT, compiler.stack_assign(displacement_in));
+ }
+ }
+}
+
+void OutputNode::compile(OSLCompiler &compiler)
+{
+ if (compiler.output_type() == SHADER_TYPE_SURFACE)
+ compiler.add(this, "node_output_surface");
+ else if (compiler.output_type() == SHADER_TYPE_VOLUME)
+ compiler.add(this, "node_output_volume");
+ else if (compiler.output_type() == SHADER_TYPE_DISPLACEMENT)
+ compiler.add(this, "node_output_displacement");
+}
+
+/* Map Range Node */
+
+NODE_DEFINE(MapRangeNode)
+{
+ NodeType *type = NodeType::add("map_range", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("linear", NODE_MAP_RANGE_LINEAR);
+ type_enum.insert("stepped", NODE_MAP_RANGE_STEPPED);
+ type_enum.insert("smoothstep", NODE_MAP_RANGE_SMOOTHSTEP);
+ type_enum.insert("smootherstep", NODE_MAP_RANGE_SMOOTHERSTEP);
+ SOCKET_ENUM(range_type, "Type", type_enum, NODE_MAP_RANGE_LINEAR);
+
+ SOCKET_IN_FLOAT(value, "Value", 1.0f);
+ SOCKET_IN_FLOAT(from_min, "From Min", 0.0f);
+ SOCKET_IN_FLOAT(from_max, "From Max", 1.0f);
+ SOCKET_IN_FLOAT(to_min, "To Min", 0.0f);
+ SOCKET_IN_FLOAT(to_max, "To Max", 1.0f);
+ SOCKET_IN_FLOAT(steps, "Steps", 4.0f);
+ SOCKET_IN_BOOLEAN(clamp, "Clamp", false);
+
+ SOCKET_OUT_FLOAT(result, "Result");
+
+ return type;
+}
+
+MapRangeNode::MapRangeNode() : ShaderNode(get_node_type())
+{
+}
+
+void MapRangeNode::expand(ShaderGraph *graph)
+{
+ if (clamp) {
+ ShaderOutput *result_out = output("Result");
+ if (!result_out->links.empty()) {
+ ClampNode *clamp_node = graph->create_node<ClampNode>();
+ clamp_node->set_clamp_type(NODE_CLAMP_RANGE);
+ graph->add(clamp_node);
+ graph->relink(result_out, clamp_node->output("Result"));
+ graph->connect(result_out, clamp_node->input("Value"));
+ if (input("To Min")->link) {
+ graph->connect(input("To Min")->link, clamp_node->input("Min"));
+ }
+ else {
+ clamp_node->set_min(to_min);
+ }
+ if (input("To Max")->link) {
+ graph->connect(input("To Max")->link, clamp_node->input("Max"));
+ }
+ else {
+ clamp_node->set_max(to_max);
+ }
+ }
+ }
+}
+
+void MapRangeNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *value_in = input("Value");
+ ShaderInput *from_min_in = input("From Min");
+ ShaderInput *from_max_in = input("From Max");
+ ShaderInput *to_min_in = input("To Min");
+ ShaderInput *to_max_in = input("To Max");
+ ShaderInput *steps_in = input("Steps");
+ ShaderOutput *result_out = output("Result");
+
+ int value_stack_offset = compiler.stack_assign(value_in);
+ int from_min_stack_offset = compiler.stack_assign_if_linked(from_min_in);
+ int from_max_stack_offset = compiler.stack_assign_if_linked(from_max_in);
+ int to_min_stack_offset = compiler.stack_assign_if_linked(to_min_in);
+ int to_max_stack_offset = compiler.stack_assign_if_linked(to_max_in);
+ int steps_stack_offset = compiler.stack_assign(steps_in);
+ int result_stack_offset = compiler.stack_assign(result_out);
+
+ compiler.add_node(
+ NODE_MAP_RANGE,
+ value_stack_offset,
+ compiler.encode_uchar4(
+ from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset),
+ compiler.encode_uchar4(range_type, steps_stack_offset, result_stack_offset));
+
+ compiler.add_node(__float_as_int(from_min),
+ __float_as_int(from_max),
+ __float_as_int(to_min),
+ __float_as_int(to_max));
+ compiler.add_node(__float_as_int(steps));
+}
+
+void MapRangeNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "range_type");
+ compiler.add(this, "node_map_range");
+}
+
+/* Clamp Node */
+
+NODE_DEFINE(ClampNode)
+{
+ NodeType *type = NodeType::add("clamp", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("minmax", NODE_CLAMP_MINMAX);
+ type_enum.insert("range", NODE_CLAMP_RANGE);
+ SOCKET_ENUM(clamp_type, "Type", type_enum, NODE_CLAMP_MINMAX);
+
+ SOCKET_IN_FLOAT(value, "Value", 1.0f);
+ SOCKET_IN_FLOAT(min, "Min", 0.0f);
+ SOCKET_IN_FLOAT(max, "Max", 1.0f);
+
+ SOCKET_OUT_FLOAT(result, "Result");
+
+ return type;
+}
+
+ClampNode::ClampNode() : ShaderNode(get_node_type())
+{
+}
+
+void ClampNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ if (clamp_type == NODE_CLAMP_RANGE && (min > max)) {
+ folder.make_constant(clamp(value, max, min));
+ }
+ else {
+ folder.make_constant(clamp(value, min, max));
+ }
+ }
+}
+
+void ClampNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *value_in = input("Value");
+ ShaderInput *min_in = input("Min");
+ ShaderInput *max_in = input("Max");
+ ShaderOutput *result_out = output("Result");
+
+ int value_stack_offset = compiler.stack_assign(value_in);
+ int min_stack_offset = compiler.stack_assign(min_in);
+ int max_stack_offset = compiler.stack_assign(max_in);
+ int result_stack_offset = compiler.stack_assign(result_out);
+
+ compiler.add_node(NODE_CLAMP,
+ value_stack_offset,
+ compiler.encode_uchar4(min_stack_offset, max_stack_offset, clamp_type),
+ result_stack_offset);
+ compiler.add_node(__float_as_int(min), __float_as_int(max));
+}
+
+void ClampNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "clamp_type");
+ compiler.add(this, "node_clamp");
+}
+
+/* AOV Output */
+
+NODE_DEFINE(OutputAOVNode)
+{
+ NodeType *type = NodeType::add("aov_output", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", zero_float3());
+ SOCKET_IN_FLOAT(value, "Value", 0.0f);
+
+ SOCKET_STRING(name, "AOV Name", ustring(""));
+
+ return type;
+}
+
+OutputAOVNode::OutputAOVNode() : ShaderNode(get_node_type())
+{
+ special_type = SHADER_SPECIAL_TYPE_OUTPUT_AOV;
+ offset = -1;
+}
+
+void OutputAOVNode::simplify_settings(Scene *scene)
+{
+ offset = scene->film->get_aov_offset(scene, name.string(), is_color);
+ if (offset == -1) {
+ offset = scene->film->get_aov_offset(scene, name.string(), is_color);
+ }
+
+ if (offset == -1 || is_color) {
+ input("Value")->disconnect();
+ }
+ if (offset == -1 || !is_color) {
+ input("Color")->disconnect();
+ }
+}
+
+void OutputAOVNode::compile(SVMCompiler &compiler)
+{
+ assert(offset >= 0);
+
+ if (is_color) {
+ compiler.add_node(NODE_AOV_COLOR, compiler.stack_assign(input("Color")), offset);
+ }
+ else {
+ compiler.add_node(NODE_AOV_VALUE, compiler.stack_assign(input("Value")), offset);
+ }
+}
+
+void OutputAOVNode::compile(OSLCompiler & /*compiler*/)
+{
+ /* TODO */
+}
+
+/* Math */
+
+NODE_DEFINE(MathNode)
+{
+ NodeType *type = NodeType::add("math", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("add", NODE_MATH_ADD);
+ type_enum.insert("subtract", NODE_MATH_SUBTRACT);
+ type_enum.insert("multiply", NODE_MATH_MULTIPLY);
+ type_enum.insert("divide", NODE_MATH_DIVIDE);
+ type_enum.insert("multiply_add", NODE_MATH_MULTIPLY_ADD);
+ type_enum.insert("sine", NODE_MATH_SINE);
+ type_enum.insert("cosine", NODE_MATH_COSINE);
+ type_enum.insert("tangent", NODE_MATH_TANGENT);
+ type_enum.insert("sinh", NODE_MATH_SINH);
+ type_enum.insert("cosh", NODE_MATH_COSH);
+ type_enum.insert("tanh", NODE_MATH_TANH);
+ type_enum.insert("arcsine", NODE_MATH_ARCSINE);
+ type_enum.insert("arccosine", NODE_MATH_ARCCOSINE);
+ type_enum.insert("arctangent", NODE_MATH_ARCTANGENT);
+ type_enum.insert("power", NODE_MATH_POWER);
+ type_enum.insert("logarithm", NODE_MATH_LOGARITHM);
+ type_enum.insert("minimum", NODE_MATH_MINIMUM);
+ type_enum.insert("maximum", NODE_MATH_MAXIMUM);
+ type_enum.insert("round", NODE_MATH_ROUND);
+ type_enum.insert("less_than", NODE_MATH_LESS_THAN);
+ type_enum.insert("greater_than", NODE_MATH_GREATER_THAN);
+ type_enum.insert("modulo", NODE_MATH_MODULO);
+ type_enum.insert("absolute", NODE_MATH_ABSOLUTE);
+ type_enum.insert("arctan2", NODE_MATH_ARCTAN2);
+ type_enum.insert("floor", NODE_MATH_FLOOR);
+ type_enum.insert("ceil", NODE_MATH_CEIL);
+ type_enum.insert("fraction", NODE_MATH_FRACTION);
+ type_enum.insert("trunc", NODE_MATH_TRUNC);
+ type_enum.insert("snap", NODE_MATH_SNAP);
+ type_enum.insert("wrap", NODE_MATH_WRAP);
+ type_enum.insert("pingpong", NODE_MATH_PINGPONG);
+ type_enum.insert("sqrt", NODE_MATH_SQRT);
+ type_enum.insert("inversesqrt", NODE_MATH_INV_SQRT);
+ type_enum.insert("sign", NODE_MATH_SIGN);
+ type_enum.insert("exponent", NODE_MATH_EXPONENT);
+ type_enum.insert("radians", NODE_MATH_RADIANS);
+ type_enum.insert("degrees", NODE_MATH_DEGREES);
+ type_enum.insert("smoothmin", NODE_MATH_SMOOTH_MIN);
+ type_enum.insert("smoothmax", NODE_MATH_SMOOTH_MAX);
+ type_enum.insert("compare", NODE_MATH_COMPARE);
+ SOCKET_ENUM(math_type, "Type", type_enum, NODE_MATH_ADD);
+
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
+
+ SOCKET_IN_FLOAT(value1, "Value1", 0.5f);
+ SOCKET_IN_FLOAT(value2, "Value2", 0.5f);
+ SOCKET_IN_FLOAT(value3, "Value3", 0.0f);
+
+ SOCKET_OUT_FLOAT(value, "Value");
+
+ return type;
+}
+
+MathNode::MathNode() : ShaderNode(get_node_type())
+{
+}
+
+void MathNode::expand(ShaderGraph *graph)
+{
+ if (use_clamp) {
+ ShaderOutput *result_out = output("Value");
+ if (!result_out->links.empty()) {
+ ClampNode *clamp_node = graph->create_node<ClampNode>();
+ clamp_node->set_clamp_type(NODE_CLAMP_MINMAX);
+ clamp_node->set_min(0.0f);
+ clamp_node->set_max(1.0f);
+ graph->add(clamp_node);
+ graph->relink(result_out, clamp_node->output("Result"));
+ graph->connect(result_out, clamp_node->input("Value"));
+ }
+ }
+}
+
+void MathNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(svm_math(math_type, value1, value2, value3));
+ }
+ else {
+ folder.fold_math(math_type);
+ }
+}
+
+void MathNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *value1_in = input("Value1");
+ ShaderInput *value2_in = input("Value2");
+ ShaderInput *value3_in = input("Value3");
+ ShaderOutput *value_out = output("Value");
+
+ int value1_stack_offset = compiler.stack_assign(value1_in);
+ int value2_stack_offset = compiler.stack_assign(value2_in);
+ int value3_stack_offset = compiler.stack_assign(value3_in);
+ int value_stack_offset = compiler.stack_assign(value_out);
+
+ compiler.add_node(
+ NODE_MATH,
+ math_type,
+ compiler.encode_uchar4(value1_stack_offset, value2_stack_offset, value3_stack_offset),
+ value_stack_offset);
+}
+
+void MathNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "math_type");
+ compiler.add(this, "node_math");
+}
+
+/* VectorMath */
+
+NODE_DEFINE(VectorMathNode)
+{
+ NodeType *type = NodeType::add("vector_math", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("add", NODE_VECTOR_MATH_ADD);
+ type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT);
+ type_enum.insert("multiply", NODE_VECTOR_MATH_MULTIPLY);
+ type_enum.insert("divide", NODE_VECTOR_MATH_DIVIDE);
+
+ type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT);
+ type_enum.insert("project", NODE_VECTOR_MATH_PROJECT);
+ type_enum.insert("reflect", NODE_VECTOR_MATH_REFLECT);
+ type_enum.insert("refract", NODE_VECTOR_MATH_REFRACT);
+ type_enum.insert("faceforward", NODE_VECTOR_MATH_FACEFORWARD);
+ type_enum.insert("multiply_add", NODE_VECTOR_MATH_MULTIPLY_ADD);
+
+ type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
+
+ type_enum.insert("distance", NODE_VECTOR_MATH_DISTANCE);
+ type_enum.insert("length", NODE_VECTOR_MATH_LENGTH);
+ type_enum.insert("scale", NODE_VECTOR_MATH_SCALE);
+ type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE);
+
+ type_enum.insert("snap", NODE_VECTOR_MATH_SNAP);
+ type_enum.insert("floor", NODE_VECTOR_MATH_FLOOR);
+ type_enum.insert("ceil", NODE_VECTOR_MATH_CEIL);
+ type_enum.insert("modulo", NODE_VECTOR_MATH_MODULO);
+ type_enum.insert("wrap", NODE_VECTOR_MATH_WRAP);
+ type_enum.insert("fraction", NODE_VECTOR_MATH_FRACTION);
+ type_enum.insert("absolute", NODE_VECTOR_MATH_ABSOLUTE);
+ type_enum.insert("minimum", NODE_VECTOR_MATH_MINIMUM);
+ type_enum.insert("maximum", NODE_VECTOR_MATH_MAXIMUM);
+
+ type_enum.insert("sine", NODE_VECTOR_MATH_SINE);
+ type_enum.insert("cosine", NODE_VECTOR_MATH_COSINE);
+ type_enum.insert("tangent", NODE_VECTOR_MATH_TANGENT);
+ SOCKET_ENUM(math_type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
+
+ SOCKET_IN_VECTOR(vector1, "Vector1", zero_float3());
+ SOCKET_IN_VECTOR(vector2, "Vector2", zero_float3());
+ SOCKET_IN_VECTOR(vector3, "Vector3", zero_float3());
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+
+ SOCKET_OUT_FLOAT(value, "Value");
+ SOCKET_OUT_VECTOR(vector, "Vector");
+
+ return type;
+}
+
+VectorMathNode::VectorMathNode() : ShaderNode(get_node_type())
+{
+}
+
+void VectorMathNode::constant_fold(const ConstantFolder &folder)
+{
+ float value = 0.0f;
+ float3 vector = zero_float3();
+
+ if (folder.all_inputs_constant()) {
+ svm_vector_math(&value, &vector, math_type, vector1, vector2, vector3, scale);
+ if (folder.output == output("Value")) {
+ folder.make_constant(value);
+ }
+ else if (folder.output == output("Vector")) {
+ folder.make_constant(vector);
+ }
+ }
+ else {
+ folder.fold_vector_math(math_type);
+ }
+}
+
+void VectorMathNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector1_in = input("Vector1");
+ ShaderInput *vector2_in = input("Vector2");
+ ShaderInput *param1_in = input("Scale");
+ ShaderOutput *value_out = output("Value");
+ ShaderOutput *vector_out = output("Vector");
+
+ int vector1_stack_offset = compiler.stack_assign(vector1_in);
+ int vector2_stack_offset = compiler.stack_assign(vector2_in);
+ int param1_stack_offset = compiler.stack_assign(param1_in);
+ int value_stack_offset = compiler.stack_assign_if_linked(value_out);
+ int vector_stack_offset = compiler.stack_assign_if_linked(vector_out);
+
+ /* 3 Vector Operators */
+ if (math_type == NODE_VECTOR_MATH_WRAP || math_type == NODE_VECTOR_MATH_FACEFORWARD ||
+ math_type == NODE_VECTOR_MATH_MULTIPLY_ADD) {
+ ShaderInput *vector3_in = input("Vector3");
+ int vector3_stack_offset = compiler.stack_assign(vector3_in);
+ compiler.add_node(
+ NODE_VECTOR_MATH,
+ math_type,
+ compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, param1_stack_offset),
+ compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
+ compiler.add_node(vector3_stack_offset);
+ }
+ else {
+ compiler.add_node(
+ NODE_VECTOR_MATH,
+ math_type,
+ compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, param1_stack_offset),
+ compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
+ }
+}
+
+void VectorMathNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "math_type");
+ compiler.add(this, "node_vector_math");
+}
+
+/* Vector Rotate */
+
+NODE_DEFINE(VectorRotateNode)
+{
+ NodeType *type = NodeType::add("vector_rotate", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("axis", NODE_VECTOR_ROTATE_TYPE_AXIS);
+ type_enum.insert("x_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_X);
+ type_enum.insert("y_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_Y);
+ type_enum.insert("z_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_Z);
+ type_enum.insert("euler_xyz", NODE_VECTOR_ROTATE_TYPE_EULER_XYZ);
+ SOCKET_ENUM(rotate_type, "Type", type_enum, NODE_VECTOR_ROTATE_TYPE_AXIS);
+
+ SOCKET_BOOLEAN(invert, "Invert", false);
+
+ SOCKET_IN_VECTOR(vector, "Vector", zero_float3());
+ SOCKET_IN_POINT(rotation, "Rotation", zero_float3());
+ SOCKET_IN_POINT(center, "Center", zero_float3());
+ SOCKET_IN_VECTOR(axis, "Axis", make_float3(0.0f, 0.0f, 1.0f));
+ SOCKET_IN_FLOAT(angle, "Angle", 0.0f);
+ SOCKET_OUT_VECTOR(vector, "Vector");
+
+ return type;
+}
+
+VectorRotateNode::VectorRotateNode() : ShaderNode(get_node_type())
+{
+}
+
+void VectorRotateNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *rotation_in = input("Rotation");
+ ShaderInput *center_in = input("Center");
+ ShaderInput *axis_in = input("Axis");
+ ShaderInput *angle_in = input("Angle");
+ ShaderOutput *vector_out = output("Vector");
+
+ compiler.add_node(NODE_VECTOR_ROTATE,
+ compiler.encode_uchar4(rotate_type,
+ compiler.stack_assign(vector_in),
+ compiler.stack_assign(rotation_in),
+ invert),
+ compiler.encode_uchar4(compiler.stack_assign(center_in),
+ compiler.stack_assign(axis_in),
+ compiler.stack_assign(angle_in)),
+ compiler.stack_assign(vector_out));
+}
+
+void VectorRotateNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "rotate_type");
+ compiler.parameter(this, "invert");
+ compiler.add(this, "node_vector_rotate");
+}
+
+/* VectorTransform */
+
+NODE_DEFINE(VectorTransformNode)
+{
+ NodeType *type = NodeType::add("vector_transform", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
+ type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
+ type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
+ SOCKET_ENUM(transform_type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
+
+ static NodeEnum space_enum;
+ space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
+ space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
+ space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA);
+ SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
+ SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
+
+ SOCKET_IN_VECTOR(vector, "Vector", zero_float3());
+ SOCKET_OUT_VECTOR(vector, "Vector");
+
+ return type;
+}
+
+VectorTransformNode::VectorTransformNode() : ShaderNode(get_node_type())
+{
+}
+
+void VectorTransformNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *vector_out = output("Vector");
+
+ compiler.add_node(
+ NODE_VECTOR_TRANSFORM,
+ compiler.encode_uchar4(transform_type, convert_from, convert_to),
+ compiler.encode_uchar4(compiler.stack_assign(vector_in), compiler.stack_assign(vector_out)));
+}
+
+void VectorTransformNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "transform_type");
+ compiler.parameter(this, "convert_from");
+ compiler.parameter(this, "convert_to");
+ compiler.add(this, "node_vector_transform");
+}
+
+/* BumpNode */
+
+NODE_DEFINE(BumpNode)
+{
+ NodeType *type = NodeType::add("bump", create, NodeType::SHADER);
+
+ SOCKET_BOOLEAN(invert, "Invert", false);
+ SOCKET_BOOLEAN(use_object_space, "UseObjectSpace", false);
+
+ /* this input is used by the user, but after graph transform it is no longer
+ * used and moved to sampler center/x/y instead */
+ SOCKET_IN_FLOAT(height, "Height", 1.0f);
+
+ SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f);
+ SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f);
+ SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f);
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+ SOCKET_IN_FLOAT(distance, "Distance", 0.1f);
+
+ SOCKET_OUT_NORMAL(normal, "Normal");
+
+ return type;
+}
+
+BumpNode::BumpNode() : ShaderNode(get_node_type())
+{
+ special_type = SHADER_SPECIAL_TYPE_BUMP;
+}
+
+void BumpNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *center_in = input("SampleCenter");
+ ShaderInput *dx_in = input("SampleX");
+ ShaderInput *dy_in = input("SampleY");
+ ShaderInput *normal_in = input("Normal");
+ ShaderInput *strength_in = input("Strength");
+ ShaderInput *distance_in = input("Distance");
+ ShaderOutput *normal_out = output("Normal");
+
+ /* pack all parameters in the node */
+ compiler.add_node(NODE_SET_BUMP,
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(normal_in),
+ compiler.stack_assign(distance_in),
+ invert,
+ use_object_space),
+ compiler.encode_uchar4(compiler.stack_assign(center_in),
+ compiler.stack_assign(dx_in),
+ compiler.stack_assign(dy_in),
+ compiler.stack_assign(strength_in)),
+ compiler.stack_assign(normal_out));
+}
+
+void BumpNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "invert");
+ compiler.parameter(this, "use_object_space");
+ compiler.add(this, "node_bump");
+}
+
+void BumpNode::constant_fold(const ConstantFolder &folder)
+{
+ ShaderInput *height_in = input("Height");
+ ShaderInput *normal_in = input("Normal");
+
+ if (height_in->link == NULL) {
+ if (normal_in->link == NULL) {
+ GeometryNode *geom = folder.graph->create_node<GeometryNode>();
+ folder.graph->add(geom);
+ folder.bypass(geom->output("Normal"));
+ }
+ else {
+ folder.bypass(normal_in->link);
+ }
+ }
+
+ /* TODO(sergey): Ignore bump with zero strength. */
+}
+
+/* Curves node */
+
+CurvesNode::CurvesNode(const NodeType *node_type) : ShaderNode(node_type)
+{
+}
+
+void CurvesNode::constant_fold(const ConstantFolder &folder, ShaderInput *value_in)
+{
+ ShaderInput *fac_in = input("Fac");
+
+ /* evaluate fully constant node */
+ if (folder.all_inputs_constant()) {
+ if (curves.size() == 0) {
+ return;
+ }
+
+ float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x);
+ float3 result;
+
+ result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x;
+ result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y;
+ result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z;
+
+ folder.make_constant(interp(value, result, fac));
+ }
+ /* remove no-op node */
+ else if (!fac_in->link && fac == 0.0f) {
+ /* link is not null because otherwise all inputs are constant */
+ folder.bypass(value_in->link);
+ }
+}
+
+void CurvesNode::compile(SVMCompiler &compiler,
+ int type,
+ ShaderInput *value_in,
+ ShaderOutput *value_out)
+{
+ if (curves.size() == 0)
+ return;
+
+ ShaderInput *fac_in = input("Fac");
+
+ compiler.add_node(type,
+ compiler.encode_uchar4(compiler.stack_assign(fac_in),
+ compiler.stack_assign(value_in),
+ compiler.stack_assign(value_out)),
+ __float_as_int(min_x),
+ __float_as_int(max_x));
+
+ compiler.add_node(curves.size());
+ for (int i = 0; i < curves.size(); i++)
+ compiler.add_node(float3_to_float4(curves[i]));
+}
+
+void CurvesNode::compile(OSLCompiler &compiler, const char *name)
+{
+ if (curves.size() == 0)
+ return;
+
+ compiler.parameter_color_array("ramp", curves);
+ compiler.parameter(this, "min_x");
+ compiler.parameter(this, "max_x");
+ compiler.add(this, name);
+}
+
+void CurvesNode::compile(SVMCompiler & /*compiler*/)
+{
+ assert(0);
+}
+
+void CurvesNode::compile(OSLCompiler & /*compiler*/)
+{
+ assert(0);
+}
+
+/* RGBCurvesNode */
+
+NODE_DEFINE(RGBCurvesNode)
+{
+ NodeType *type = NodeType::add("rgb_curves", create, NodeType::SHADER);
+
+ SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>());
+ SOCKET_FLOAT(min_x, "Min X", 0.0f);
+ SOCKET_FLOAT(max_x, "Max X", 1.0f);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
+ SOCKET_IN_COLOR(value, "Color", zero_float3());
+
+ SOCKET_OUT_COLOR(value, "Color");
+
+ return type;
+}
+
+RGBCurvesNode::RGBCurvesNode() : CurvesNode(get_node_type())
+{
+}
+
+void RGBCurvesNode::constant_fold(const ConstantFolder &folder)
+{
+ CurvesNode::constant_fold(folder, input("Color"));
+}
+
+void RGBCurvesNode::compile(SVMCompiler &compiler)
+{
+ CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color"));
+}
+
+void RGBCurvesNode::compile(OSLCompiler &compiler)
+{
+ CurvesNode::compile(compiler, "node_rgb_curves");
+}
+
+/* VectorCurvesNode */
+
+NODE_DEFINE(VectorCurvesNode)
+{
+ NodeType *type = NodeType::add("vector_curves", create, NodeType::SHADER);
+
+ SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>());
+ SOCKET_FLOAT(min_x, "Min X", 0.0f);
+ SOCKET_FLOAT(max_x, "Max X", 1.0f);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
+ SOCKET_IN_VECTOR(value, "Vector", zero_float3());
+
+ SOCKET_OUT_VECTOR(value, "Vector");
+
+ return type;
+}
+
+VectorCurvesNode::VectorCurvesNode() : CurvesNode(get_node_type())
+{
+}
+
+void VectorCurvesNode::constant_fold(const ConstantFolder &folder)
+{
+ CurvesNode::constant_fold(folder, input("Vector"));
+}
+
+void VectorCurvesNode::compile(SVMCompiler &compiler)
+{
+ CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector"));
+}
+
+void VectorCurvesNode::compile(OSLCompiler &compiler)
+{
+ CurvesNode::compile(compiler, "node_vector_curves");
+}
+
+/* FloatCurveNode */
+
+NODE_DEFINE(FloatCurveNode)
+{
+ NodeType *type = NodeType::add("float_curve", create, NodeType::SHADER);
+
+ SOCKET_FLOAT_ARRAY(curve, "Curve", array<float>());
+ SOCKET_FLOAT(min_x, "Min X", 0.0f);
+ SOCKET_FLOAT(max_x, "Max X", 1.0f);
+
+ SOCKET_IN_FLOAT(fac, "Factor", 0.0f);
+ SOCKET_IN_FLOAT(value, "Value", 0.0f);
+
+ SOCKET_OUT_FLOAT(value, "Value");
+
+ return type;
+}
+
+FloatCurveNode::FloatCurveNode() : ShaderNode(get_node_type())
+{
+}
+
+void FloatCurveNode::constant_fold(const ConstantFolder &folder)
+{
+ ShaderInput *value_in = input("Value");
+ ShaderInput *fac_in = input("Factor");
+
+ /* evaluate fully constant node */
+ if (folder.all_inputs_constant()) {
+ if (curve.size() == 0) {
+ return;
+ }
+
+ float pos = (value - min_x) / (max_x - min_x);
+ float result = float_ramp_lookup(curve.data(), pos, true, true, curve.size());
+
+ folder.make_constant(value + fac * (result - value));
+ }
+ /* remove no-op node */
+ else if (!fac_in->link && fac == 0.0f) {
+ /* link is not null because otherwise all inputs are constant */
+ folder.bypass(value_in->link);
+ }
+}
+
+void FloatCurveNode::compile(SVMCompiler &compiler)
+{
+ if (curve.size() == 0)
+ return;
+
+ ShaderInput *value_in = input("Value");
+ ShaderInput *fac_in = input("Factor");
+ ShaderOutput *value_out = output("Value");
+
+ compiler.add_node(NODE_FLOAT_CURVE,
+ compiler.encode_uchar4(compiler.stack_assign(fac_in),
+ compiler.stack_assign(value_in),
+ compiler.stack_assign(value_out)),
+ __float_as_int(min_x),
+ __float_as_int(max_x));
+
+ compiler.add_node(curve.size());
+ for (int i = 0; i < curve.size(); i++)
+ compiler.add_node(make_float4(curve[i]));
+}
+
+void FloatCurveNode::compile(OSLCompiler &compiler)
+{
+ if (curve.size() == 0)
+ return;
+
+ compiler.parameter_array("ramp", curve.data(), curve.size());
+ compiler.parameter(this, "min_x");
+ compiler.parameter(this, "max_x");
+ compiler.add(this, "node_float_curve");
+}
+
+/* RGBRampNode */
+
+NODE_DEFINE(RGBRampNode)
+{
+ NodeType *type = NodeType::add("rgb_ramp", create, NodeType::SHADER);
+
+ SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>());
+ SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>());
+ SOCKET_BOOLEAN(interpolate, "Interpolate", true);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
+
+RGBRampNode::RGBRampNode() : ShaderNode(get_node_type())
+{
+}
+
+void RGBRampNode::constant_fold(const ConstantFolder &folder)
+{
+ if (ramp.size() == 0 || ramp.size() != ramp_alpha.size())
+ return;
+
+ if (folder.all_inputs_constant()) {
+ float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1);
+
+ /* clamp int as well in case of NaN */
+ int i = clamp((int)f, 0, ramp.size() - 1);
+ float t = f - (float)i;
+
+ bool use_lerp = interpolate && t > 0.0f;
+
+ if (folder.output == output("Color")) {
+ float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size());
+ folder.make_constant(color);
+ }
+ else if (folder.output == output("Alpha")) {
+ float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size());
+ folder.make_constant(alpha);
+ }
+ }
+}
+
+void RGBRampNode::compile(SVMCompiler &compiler)
+{
+ if (ramp.size() == 0 || ramp.size() != ramp_alpha.size())
+ return;
+
+ ShaderInput *fac_in = input("Fac");
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *alpha_out = output("Alpha");
+
+ compiler.add_node(NODE_RGB_RAMP,
+ compiler.encode_uchar4(compiler.stack_assign(fac_in),
+ compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(alpha_out)),
+ interpolate);
+
+ compiler.add_node(ramp.size());
+ for (int i = 0; i < ramp.size(); i++)
+ compiler.add_node(make_float4(ramp[i].x, ramp[i].y, ramp[i].z, ramp_alpha[i]));
+}
+
+void RGBRampNode::compile(OSLCompiler &compiler)
+{
+ if (ramp.size() == 0 || ramp.size() != ramp_alpha.size())
+ return;
+
+ compiler.parameter_color_array("ramp_color", ramp);
+ compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size());
+ compiler.parameter(this, "interpolate");
+
+ compiler.add(this, "node_rgb_ramp");
+}
+
+/* Set Normal Node */
+
+NODE_DEFINE(SetNormalNode)
+{
+ NodeType *type = NodeType::add("set_normal", create, NodeType::SHADER);
+
+ SOCKET_IN_VECTOR(direction, "Direction", zero_float3());
+ SOCKET_OUT_NORMAL(normal, "Normal");
+
+ return type;
+}
+
+SetNormalNode::SetNormalNode() : ShaderNode(get_node_type())
+{
+}
+
+void SetNormalNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *direction_in = input("Direction");
+ ShaderOutput *normal_out = output("Normal");
+
+ compiler.add_node(NODE_CLOSURE_SET_NORMAL,
+ compiler.stack_assign(direction_in),
+ compiler.stack_assign(normal_out));
+}
+
+void SetNormalNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_set_normal");
+}
+
+/* OSLNode */
+
+OSLNode::OSLNode() : ShaderNode(new NodeType(NodeType::SHADER))
+{
+ special_type = SHADER_SPECIAL_TYPE_OSL;
+}
+
+OSLNode::~OSLNode()
+{
+ delete type;
+}
+
+ShaderNode *OSLNode::clone(ShaderGraph *graph) const
+{
+ return OSLNode::create(graph, this->inputs.size(), this);
+}
+
+OSLNode *OSLNode::create(ShaderGraph *graph, size_t num_inputs, const OSLNode *from)
+{
+ /* allocate space for the node itself and parameters, aligned to 16 bytes
+ * assuming that's the most parameter types need */
+ size_t node_size = align_up(sizeof(OSLNode), 16);
+ size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
+
+ char *node_memory = (char *)operator new(node_size + inputs_size);
+ memset(node_memory, 0, node_size + inputs_size);
+
+ if (!from) {
+ OSLNode *node = new (node_memory) OSLNode();
+ node->set_owner(graph);
+ return node;
+ }
+ else {
+ /* copy input default values and node type for cloning */
+ memcpy(node_memory + node_size, (char *)from + node_size, inputs_size);
+
+ OSLNode *node = new (node_memory) OSLNode(*from);
+ node->type = new NodeType(*(from->type));
+ node->set_owner(from->owner);
+ return node;
+ }
+}
+
+char *OSLNode::input_default_value()
+{
+ /* pointer to default value storage, which is the same as our actual value */
+ size_t num_inputs = type->inputs.size();
+ size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
+ return (char *)this + align_up(sizeof(OSLNode), 16) + inputs_size;
+}
+
+void OSLNode::add_input(ustring name, SocketType::Type socket_type)
+{
+ char *memory = input_default_value();
+ size_t offset = memory - (char *)this;
+ const_cast<NodeType *>(type)->register_input(
+ name, name, socket_type, offset, memory, NULL, NULL, SocketType::LINKABLE);
+}
+
+void OSLNode::add_output(ustring name, SocketType::Type socket_type)
+{
+ const_cast<NodeType *>(type)->register_output(name, name, socket_type);
+}
+
+void OSLNode::compile(SVMCompiler &)
+{
+ /* doesn't work for SVM, obviously ... */
+}
+
+void OSLNode::compile(OSLCompiler &compiler)
+{
+ if (!filepath.empty())
+ compiler.add(this, filepath.c_str(), true);
+ else
+ compiler.add(this, bytecode_hash.c_str(), false);
+}
+
+/* Normal Map */
+
+NODE_DEFINE(NormalMapNode)
+{
+ NodeType *type = NodeType::add("normal_map", create, NodeType::SHADER);
+
+ static NodeEnum space_enum;
+ space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
+ space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
+ space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
+ space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT);
+ space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD);
+ SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT);
+
+ SOCKET_STRING(attribute, "Attribute", ustring());
+
+ SOCKET_IN_NORMAL(
+ normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f));
+
+ SOCKET_OUT_NORMAL(normal, "Normal");
+
+ return type;
+}
+
+NormalMapNode::NormalMapNode() : ShaderNode(get_node_type())
+{
+}
+
+void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) {
+ if (attribute.empty()) {
+ attributes->add(ATTR_STD_UV_TANGENT);
+ attributes->add(ATTR_STD_UV_TANGENT_SIGN);
+ }
+ else {
+ attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
+ attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
+ }
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void NormalMapNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *strength_in = input("Strength");
+ ShaderOutput *normal_out = output("Normal");
+ int attr = 0, attr_sign = 0;
+
+ if (space == NODE_NORMAL_MAP_TANGENT) {
+ if (attribute.empty()) {
+ attr = compiler.attribute(ATTR_STD_UV_TANGENT);
+ attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
+ }
+ else {
+ attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
+ attr_sign = compiler.attribute(
+ ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
+ }
+ }
+
+ compiler.add_node(NODE_NORMAL_MAP,
+ compiler.encode_uchar4(compiler.stack_assign(color_in),
+ compiler.stack_assign(strength_in),
+ compiler.stack_assign(normal_out),
+ space),
+ attr,
+ attr_sign);
+}
+
+void NormalMapNode::compile(OSLCompiler &compiler)
+{
+ if (space == NODE_NORMAL_MAP_TANGENT) {
+ if (attribute.empty()) {
+ compiler.parameter("attr_name", ustring("geom:tangent"));
+ compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
+ }
+ else {
+ compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
+ compiler.parameter("attr_sign_name",
+ ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
+ }
+ }
+
+ compiler.parameter(this, "space");
+ compiler.add(this, "node_normal_map");
+}
+
+/* Tangent */
+
+NODE_DEFINE(TangentNode)
+{
+ NodeType *type = NodeType::add("tangent", create, NodeType::SHADER);
+
+ static NodeEnum direction_type_enum;
+ direction_type_enum.insert("radial", NODE_TANGENT_RADIAL);
+ direction_type_enum.insert("uv_map", NODE_TANGENT_UVMAP);
+ SOCKET_ENUM(direction_type, "Direction Type", direction_type_enum, NODE_TANGENT_RADIAL);
+
+ static NodeEnum axis_enum;
+ axis_enum.insert("x", NODE_TANGENT_AXIS_X);
+ axis_enum.insert("y", NODE_TANGENT_AXIS_Y);
+ axis_enum.insert("z", NODE_TANGENT_AXIS_Z);
+ SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X);
+
+ SOCKET_STRING(attribute, "Attribute", ustring());
+
+ SOCKET_IN_NORMAL(
+ normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ SOCKET_OUT_NORMAL(tangent, "Tangent");
+
+ return type;
+}
+
+TangentNode::TangentNode() : ShaderNode(get_node_type())
+{
+}
+
+void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_surface_link()) {
+ if (direction_type == NODE_TANGENT_UVMAP) {
+ if (attribute.empty())
+ attributes->add(ATTR_STD_UV_TANGENT);
+ else
+ attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
+ }
+ else
+ attributes->add(ATTR_STD_GENERATED);
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void TangentNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *tangent_out = output("Tangent");
+ int attr;
+
+ if (direction_type == NODE_TANGENT_UVMAP) {
+ if (attribute.empty())
+ attr = compiler.attribute(ATTR_STD_UV_TANGENT);
+ else
+ attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
+ }
+ else
+ attr = compiler.attribute(ATTR_STD_GENERATED);
+
+ compiler.add_node(
+ NODE_TANGENT,
+ compiler.encode_uchar4(compiler.stack_assign(tangent_out), direction_type, axis),
+ attr);
+}
+
+void TangentNode::compile(OSLCompiler &compiler)
+{
+ if (direction_type == NODE_TANGENT_UVMAP) {
+ if (attribute.empty())
+ compiler.parameter("attr_name", ustring("geom:tangent"));
+ else
+ compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
+ }
+
+ compiler.parameter(this, "direction_type");
+ compiler.parameter(this, "axis");
+ compiler.add(this, "node_tangent");
+}
+
+/* Bevel */
+
+NODE_DEFINE(BevelNode)
+{
+ NodeType *type = NodeType::add("bevel", create, NodeType::SHADER);
+
+ SOCKET_INT(samples, "Samples", 4);
+
+ SOCKET_IN_FLOAT(radius, "Radius", 0.05f);
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+
+ SOCKET_OUT_NORMAL(bevel, "Normal");
+
+ return type;
+}
+
+BevelNode::BevelNode() : ShaderNode(get_node_type())
+{
+}
+
+void BevelNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *radius_in = input("Radius");
+ ShaderInput *normal_in = input("Normal");
+ ShaderOutput *normal_out = output("Normal");
+
+ compiler.add_node(NODE_BEVEL,
+ compiler.encode_uchar4(samples,
+ compiler.stack_assign(radius_in),
+ compiler.stack_assign_if_linked(normal_in),
+ compiler.stack_assign(normal_out)));
+}
+
+void BevelNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "samples");
+ compiler.add(this, "node_bevel");
+}
+
+/* Displacement */
+
+NODE_DEFINE(DisplacementNode)
+{
+ NodeType *type = NodeType::add("displacement", create, NodeType::SHADER);
+
+ static NodeEnum space_enum;
+ space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
+ space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
+
+ SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_OBJECT);
+
+ SOCKET_IN_FLOAT(height, "Height", 0.0f);
+ SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.5f);
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+ SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
+
+ SOCKET_OUT_VECTOR(displacement, "Displacement");
+
+ return type;
+}
+
+DisplacementNode::DisplacementNode() : ShaderNode(get_node_type())
+{
+}
+
+void DisplacementNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ if ((height - midlevel == 0.0f) || (scale == 0.0f)) {
+ folder.make_zero();
+ }
+ }
+}
+
+void DisplacementNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *height_in = input("Height");
+ ShaderInput *midlevel_in = input("Midlevel");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *normal_in = input("Normal");
+ ShaderOutput *displacement_out = output("Displacement");
+
+ compiler.add_node(NODE_DISPLACEMENT,
+ compiler.encode_uchar4(compiler.stack_assign(height_in),
+ compiler.stack_assign(midlevel_in),
+ compiler.stack_assign(scale_in),
+ compiler.stack_assign_if_linked(normal_in)),
+ compiler.stack_assign(displacement_out),
+ space);
+}
+
+void DisplacementNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "space");
+ compiler.add(this, "node_displacement");
+}
+
+/* Vector Displacement */
+
+NODE_DEFINE(VectorDisplacementNode)
+{
+ NodeType *type = NodeType::add("vector_displacement", create, NodeType::SHADER);
+
+ static NodeEnum space_enum;
+ space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
+ space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
+ space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
+
+ SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT);
+ SOCKET_STRING(attribute, "Attribute", ustring());
+
+ SOCKET_IN_COLOR(vector, "Vector", zero_float3());
+ SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.0f);
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+
+ SOCKET_OUT_VECTOR(displacement, "Displacement");
+
+ return type;
+}
+
+VectorDisplacementNode::VectorDisplacementNode() : ShaderNode(get_node_type())
+{
+}
+
+void VectorDisplacementNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ if ((vector == zero_float3() && midlevel == 0.0f) || (scale == 0.0f)) {
+ folder.make_zero();
+ }
+ }
+}
+
+void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) {
+ if (attribute.empty()) {
+ attributes->add(ATTR_STD_UV_TANGENT);
+ attributes->add(ATTR_STD_UV_TANGENT_SIGN);
+ }
+ else {
+ attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
+ attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
+ }
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void VectorDisplacementNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *midlevel_in = input("Midlevel");
+ ShaderInput *scale_in = input("Scale");
+ ShaderOutput *displacement_out = output("Displacement");
+ int attr = 0, attr_sign = 0;
+
+ if (space == NODE_NORMAL_MAP_TANGENT) {
+ if (attribute.empty()) {
+ attr = compiler.attribute(ATTR_STD_UV_TANGENT);
+ attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
+ }
+ else {
+ attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
+ attr_sign = compiler.attribute(
+ ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
+ }
+ }
+
+ compiler.add_node(NODE_VECTOR_DISPLACEMENT,
+ compiler.encode_uchar4(compiler.stack_assign(vector_in),
+ compiler.stack_assign(midlevel_in),
+ compiler.stack_assign(scale_in),
+ compiler.stack_assign(displacement_out)),
+ attr,
+ attr_sign);
+
+ compiler.add_node(space);
+}
+
+void VectorDisplacementNode::compile(OSLCompiler &compiler)
+{
+ if (space == NODE_NORMAL_MAP_TANGENT) {
+ if (attribute.empty()) {
+ compiler.parameter("attr_name", ustring("geom:tangent"));
+ compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
+ }
+ else {
+ compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
+ compiler.parameter("attr_sign_name",
+ ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
+ }
+ }
+
+ compiler.parameter(this, "space");
+ compiler.add(this, "node_vector_displacement");
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h
new file mode 100644
index 00000000000..64a2b1c7843
--- /dev/null
+++ b/intern/cycles/scene/shader_nodes.h
@@ -0,0 +1,1569 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NODES_H__
+#define __NODES_H__
+
+#include "graph/node.h"
+#include "scene/image.h"
+#include "scene/shader_graph.h"
+
+#include "util/array.h"
+#include "util/string.h"
+
+CCL_NAMESPACE_BEGIN
+
+class ImageManager;
+class LightManager;
+class Scene;
+class Shader;
+
+/* Texture Mapping */
+
+class TextureMapping {
+ public:
+ TextureMapping();
+ Transform compute_transform();
+ bool skip();
+ void compile(SVMCompiler &compiler, int offset_in, int offset_out);
+ int compile(SVMCompiler &compiler, ShaderInput *vector_in);
+ void compile(OSLCompiler &compiler);
+
+ int compile_begin(SVMCompiler &compiler, ShaderInput *vector_in);
+ void compile_end(SVMCompiler &compiler, ShaderInput *vector_in, int vector_offset);
+
+ float3 translation;
+ float3 rotation;
+ float3 scale;
+
+ float3 min, max;
+ bool use_minmax;
+
+ enum Type { POINT = 0, TEXTURE = 1, VECTOR = 2, NORMAL = 3 };
+ Type type;
+
+ enum Mapping { NONE = 0, X = 1, Y = 2, Z = 3 };
+ Mapping x_mapping, y_mapping, z_mapping;
+
+ enum Projection { FLAT, CUBE, TUBE, SPHERE };
+ Projection projection;
+};
+
+/* Nodes */
+
+class TextureNode : public ShaderNode {
+ public:
+ explicit TextureNode(const NodeType *node_type) : ShaderNode(node_type)
+ {
+ }
+ TextureMapping tex_mapping;
+ NODE_SOCKET_API_STRUCT_MEMBER(float3, tex_mapping, translation)
+ NODE_SOCKET_API_STRUCT_MEMBER(float3, tex_mapping, rotation)
+ NODE_SOCKET_API_STRUCT_MEMBER(float3, tex_mapping, scale)
+ NODE_SOCKET_API_STRUCT_MEMBER(float3, tex_mapping, min)
+ NODE_SOCKET_API_STRUCT_MEMBER(float3, tex_mapping, max)
+ NODE_SOCKET_API_STRUCT_MEMBER(bool, tex_mapping, use_minmax)
+ NODE_SOCKET_API_STRUCT_MEMBER(TextureMapping::Type, tex_mapping, type)
+ NODE_SOCKET_API_STRUCT_MEMBER(TextureMapping::Mapping, tex_mapping, x_mapping)
+ NODE_SOCKET_API_STRUCT_MEMBER(TextureMapping::Mapping, tex_mapping, y_mapping)
+ NODE_SOCKET_API_STRUCT_MEMBER(TextureMapping::Mapping, tex_mapping, z_mapping)
+ NODE_SOCKET_API_STRUCT_MEMBER(TextureMapping::Projection, tex_mapping, projection)
+};
+
+/* Any node which uses image manager's slot should be a subclass of this one. */
+class ImageSlotTextureNode : public TextureNode {
+ public:
+ explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type)
+ {
+ special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
+ }
+
+ virtual bool equals(const ShaderNode &other)
+ {
+ const ImageSlotTextureNode &other_node = (const ImageSlotTextureNode &)other;
+ return TextureNode::equals(other) && handle == other_node.handle;
+ }
+
+ ImageHandle handle;
+};
+
+class ImageTextureNode : public ImageSlotTextureNode {
+ public:
+ SHADER_NODE_NO_CLONE_CLASS(ImageTextureNode)
+ ShaderNode *clone(ShaderGraph *graph) const;
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+
+ virtual bool equals(const ShaderNode &other)
+ {
+ const ImageTextureNode &other_node = (const ImageTextureNode &)other;
+ return ImageSlotTextureNode::equals(other) && animated == other_node.animated;
+ }
+
+ ImageParams image_params() const;
+
+ /* Parameters. */
+ NODE_SOCKET_API(ustring, filename)
+ NODE_SOCKET_API(ustring, colorspace)
+ NODE_SOCKET_API(ImageAlphaType, alpha_type)
+ NODE_SOCKET_API(NodeImageProjection, projection)
+ NODE_SOCKET_API(InterpolationType, interpolation)
+ NODE_SOCKET_API(ExtensionType, extension)
+ NODE_SOCKET_API(float, projection_blend)
+ NODE_SOCKET_API(bool, animated)
+ NODE_SOCKET_API(float3, vector)
+ NODE_SOCKET_API_ARRAY(array<int>, tiles)
+
+ protected:
+ void cull_tiles(Scene *scene, ShaderGraph *graph);
+};
+
+class EnvironmentTextureNode : public ImageSlotTextureNode {
+ public:
+ SHADER_NODE_NO_CLONE_CLASS(EnvironmentTextureNode)
+ ShaderNode *clone(ShaderGraph *graph) const;
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+
+ virtual bool equals(const ShaderNode &other)
+ {
+ const EnvironmentTextureNode &other_node = (const EnvironmentTextureNode &)other;
+ return ImageSlotTextureNode::equals(other) && animated == other_node.animated;
+ }
+
+ ImageParams image_params() const;
+
+ /* Parameters. */
+ NODE_SOCKET_API(ustring, filename)
+ NODE_SOCKET_API(ustring, colorspace)
+ NODE_SOCKET_API(ImageAlphaType, alpha_type)
+ NODE_SOCKET_API(NodeEnvironmentProjection, projection)
+ NODE_SOCKET_API(InterpolationType, interpolation)
+ NODE_SOCKET_API(bool, animated)
+ NODE_SOCKET_API(float3, vector)
+};
+
+class SkyTextureNode : public TextureNode {
+ public:
+ SHADER_NODE_CLASS(SkyTextureNode)
+
+ NODE_SOCKET_API(NodeSkyType, sky_type)
+ NODE_SOCKET_API(float3, sun_direction)
+ NODE_SOCKET_API(float, turbidity)
+ NODE_SOCKET_API(float, ground_albedo)
+ NODE_SOCKET_API(bool, sun_disc)
+ NODE_SOCKET_API(float, sun_size)
+ NODE_SOCKET_API(float, sun_intensity)
+ NODE_SOCKET_API(float, sun_elevation)
+ NODE_SOCKET_API(float, sun_rotation)
+ NODE_SOCKET_API(float, altitude)
+ NODE_SOCKET_API(float, air_density)
+ NODE_SOCKET_API(float, dust_density)
+ NODE_SOCKET_API(float, ozone_density)
+ NODE_SOCKET_API(float3, vector)
+ ImageHandle handle;
+
+ float get_sun_size()
+ {
+ /* Clamping for numerical precision. */
+ return fmaxf(sun_size, 0.0005f);
+ }
+};
+
+class OutputNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(OutputNode)
+
+ NODE_SOCKET_API(Node *, surface)
+ NODE_SOCKET_API(Node *, volume)
+ NODE_SOCKET_API(float3, displacement)
+ NODE_SOCKET_API(float3, normal)
+
+ /* Don't allow output node de-duplication. */
+ virtual bool equals(const ShaderNode & /*other*/)
+ {
+ return false;
+ }
+};
+
+class OutputAOVNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(OutputAOVNode)
+ virtual void simplify_settings(Scene *scene);
+
+ NODE_SOCKET_API(float, value)
+ NODE_SOCKET_API(float3, color)
+
+ NODE_SOCKET_API(ustring, name)
+
+ /* Don't allow output node de-duplication. */
+ virtual bool equals(const ShaderNode & /*other*/)
+ {
+ return false;
+ }
+
+ int offset;
+ bool is_color;
+};
+
+class GradientTextureNode : public TextureNode {
+ public:
+ SHADER_NODE_CLASS(GradientTextureNode)
+
+ NODE_SOCKET_API(NodeGradientType, gradient_type)
+ NODE_SOCKET_API(float3, vector)
+};
+
+class NoiseTextureNode : public TextureNode {
+ public:
+ SHADER_NODE_CLASS(NoiseTextureNode)
+
+ NODE_SOCKET_API(int, dimensions)
+ NODE_SOCKET_API(float, w)
+ NODE_SOCKET_API(float, scale)
+ NODE_SOCKET_API(float, detail)
+ NODE_SOCKET_API(float, roughness)
+ NODE_SOCKET_API(float, distortion)
+ NODE_SOCKET_API(float3, vector)
+};
+
+class VoronoiTextureNode : public TextureNode {
+ public:
+ SHADER_NODE_CLASS(VoronoiTextureNode)
+
+ virtual int get_feature()
+ {
+ int result = ShaderNode::get_feature();
+ if (dimensions == 4) {
+ result |= KERNEL_FEATURE_NODE_VORONOI_EXTRA;
+ }
+ else if (dimensions >= 2 && feature == NODE_VORONOI_SMOOTH_F1) {
+ result |= KERNEL_FEATURE_NODE_VORONOI_EXTRA;
+ }
+ return result;
+ }
+
+ NODE_SOCKET_API(int, dimensions)
+ NODE_SOCKET_API(NodeVoronoiDistanceMetric, metric)
+ NODE_SOCKET_API(NodeVoronoiFeature, feature)
+ NODE_SOCKET_API(float, w)
+ NODE_SOCKET_API(float, scale)
+ NODE_SOCKET_API(float, exponent)
+ NODE_SOCKET_API(float, smoothness)
+ NODE_SOCKET_API(float, randomness)
+ NODE_SOCKET_API(float3, vector)
+};
+
+class MusgraveTextureNode : public TextureNode {
+ public:
+ SHADER_NODE_CLASS(MusgraveTextureNode)
+
+ NODE_SOCKET_API(int, dimensions)
+ NODE_SOCKET_API(NodeMusgraveType, musgrave_type)
+ NODE_SOCKET_API(float, w)
+ NODE_SOCKET_API(float, scale)
+ NODE_SOCKET_API(float, detail)
+ NODE_SOCKET_API(float, dimension)
+ NODE_SOCKET_API(float, lacunarity)
+ NODE_SOCKET_API(float, offset)
+ NODE_SOCKET_API(float, gain)
+ NODE_SOCKET_API(float3, vector)
+};
+
+class WaveTextureNode : public TextureNode {
+ public:
+ SHADER_NODE_CLASS(WaveTextureNode)
+
+ NODE_SOCKET_API(NodeWaveType, wave_type)
+ NODE_SOCKET_API(NodeWaveBandsDirection, bands_direction)
+ NODE_SOCKET_API(NodeWaveRingsDirection, rings_direction)
+ NODE_SOCKET_API(NodeWaveProfile, profile)
+
+ NODE_SOCKET_API(float, scale)
+ NODE_SOCKET_API(float, distortion)
+ NODE_SOCKET_API(float, detail)
+ NODE_SOCKET_API(float, detail_scale)
+ NODE_SOCKET_API(float, detail_roughness)
+ NODE_SOCKET_API(float, phase)
+ NODE_SOCKET_API(float3, vector)
+};
+
+class MagicTextureNode : public TextureNode {
+ public:
+ SHADER_NODE_CLASS(MagicTextureNode)
+
+ NODE_SOCKET_API(int, depth)
+ NODE_SOCKET_API(float3, vector)
+ NODE_SOCKET_API(float, scale)
+ NODE_SOCKET_API(float, distortion)
+};
+
+class CheckerTextureNode : public TextureNode {
+ public:
+ SHADER_NODE_CLASS(CheckerTextureNode)
+
+ NODE_SOCKET_API(float3, vector)
+ NODE_SOCKET_API(float3, color1)
+ NODE_SOCKET_API(float3, color2)
+ NODE_SOCKET_API(float, scale)
+};
+
+class BrickTextureNode : public TextureNode {
+ public:
+ SHADER_NODE_CLASS(BrickTextureNode)
+
+ NODE_SOCKET_API(float, offset)
+ NODE_SOCKET_API(float, squash)
+ NODE_SOCKET_API(int, offset_frequency)
+ NODE_SOCKET_API(int, squash_frequency)
+
+ NODE_SOCKET_API(float3, color1)
+ NODE_SOCKET_API(float3, color2)
+ NODE_SOCKET_API(float3, mortar)
+ NODE_SOCKET_API(float, scale)
+ NODE_SOCKET_API(float, mortar_size)
+ NODE_SOCKET_API(float, mortar_smooth)
+ NODE_SOCKET_API(float, bias)
+ NODE_SOCKET_API(float, brick_width)
+ NODE_SOCKET_API(float, row_height)
+ NODE_SOCKET_API(float3, vector)
+};
+
+class PointDensityTextureNode : public ShaderNode {
+ public:
+ SHADER_NODE_NO_CLONE_CLASS(PointDensityTextureNode)
+
+ ~PointDensityTextureNode();
+ ShaderNode *clone(ShaderGraph *graph) const;
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ /* Parameters. */
+ NODE_SOCKET_API(ustring, filename)
+ NODE_SOCKET_API(NodeTexVoxelSpace, space)
+ NODE_SOCKET_API(InterpolationType, interpolation)
+ NODE_SOCKET_API(Transform, tfm)
+ NODE_SOCKET_API(float3, vector)
+
+ /* Runtime. */
+ ImageHandle handle;
+
+ ImageParams image_params() const;
+
+ virtual bool equals(const ShaderNode &other)
+ {
+ const PointDensityTextureNode &other_node = (const PointDensityTextureNode &)other;
+ return ShaderNode::equals(other) && handle == other_node.handle;
+ }
+};
+
+class IESLightNode : public TextureNode {
+ public:
+ SHADER_NODE_NO_CLONE_CLASS(IESLightNode)
+
+ ~IESLightNode();
+ ShaderNode *clone(ShaderGraph *graph) const;
+
+ NODE_SOCKET_API(ustring, filename)
+ NODE_SOCKET_API(ustring, ies)
+
+ NODE_SOCKET_API(float, strength)
+ NODE_SOCKET_API(float3, vector)
+
+ private:
+ LightManager *light_manager;
+ int slot;
+
+ void get_slot();
+};
+
+class WhiteNoiseTextureNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(WhiteNoiseTextureNode)
+
+ NODE_SOCKET_API(int, dimensions)
+ NODE_SOCKET_API(float3, vector)
+ NODE_SOCKET_API(float, w)
+};
+
+class MappingNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MappingNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, vector)
+ NODE_SOCKET_API(float3, location)
+ NODE_SOCKET_API(float3, rotation)
+ NODE_SOCKET_API(float3, scale)
+ NODE_SOCKET_API(NodeMappingType, mapping_type)
+};
+
+class RGBToBWNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(RGBToBWNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, color)
+};
+
+class ConvertNode : public ShaderNode {
+ public:
+ ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false);
+ ConvertNode(const ConvertNode &other);
+ SHADER_NODE_BASE_CLASS(ConvertNode)
+
+ void constant_fold(const ConstantFolder &folder);
+
+ private:
+ SocketType::Type from, to;
+
+ union {
+ float value_float;
+ int value_int;
+ float3 value_color;
+ float3 value_vector;
+ float3 value_point;
+ float3 value_normal;
+ };
+ ustring value_string;
+
+ static const int MAX_TYPE = 12;
+ static bool register_types();
+ static Node *create(const NodeType *type);
+ static const NodeType *node_types[MAX_TYPE][MAX_TYPE];
+ static bool initialized;
+};
+
+class BsdfBaseNode : public ShaderNode {
+ public:
+ BsdfBaseNode(const NodeType *node_type);
+
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+ virtual ClosureType get_closure_type()
+ {
+ return closure;
+ }
+ virtual bool has_bump();
+
+ virtual bool equals(const ShaderNode & /*other*/)
+ {
+ /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */
+ return false;
+ }
+
+ virtual int get_feature()
+ {
+ return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_BSDF;
+ }
+
+ protected:
+ ClosureType closure;
+};
+
+class BsdfNode : public BsdfBaseNode {
+ public:
+ explicit BsdfNode(const NodeType *node_type);
+ SHADER_NODE_BASE_CLASS(BsdfNode)
+
+ void compile(SVMCompiler &compiler,
+ ShaderInput *param1,
+ ShaderInput *param2,
+ ShaderInput *param3 = NULL,
+ ShaderInput *param4 = NULL);
+
+ NODE_SOCKET_API(float3, color)
+ NODE_SOCKET_API(float3, normal)
+ NODE_SOCKET_API(float, surface_mix_weight)
+};
+
+class AnisotropicBsdfNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(AnisotropicBsdfNode)
+
+ NODE_SOCKET_API(float3, tangent)
+ NODE_SOCKET_API(float, roughness)
+ NODE_SOCKET_API(float, anisotropy)
+ NODE_SOCKET_API(float, rotation)
+ NODE_SOCKET_API(ClosureType, distribution)
+
+ ClosureType get_closure_type()
+ {
+ return distribution;
+ }
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+};
+
+class DiffuseBsdfNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(DiffuseBsdfNode)
+
+ NODE_SOCKET_API(float, roughness)
+};
+
+/* Disney principled BRDF */
+class PrincipledBsdfNode : public BsdfBaseNode {
+ public:
+ SHADER_NODE_CLASS(PrincipledBsdfNode)
+
+ void expand(ShaderGraph *graph);
+ bool has_surface_bssrdf();
+ bool has_bssrdf_bump();
+ void compile(SVMCompiler &compiler,
+ ShaderInput *metallic,
+ ShaderInput *subsurface,
+ ShaderInput *subsurface_radius,
+ ShaderInput *subsurface_ior,
+ ShaderInput *subsurface_anisotropy,
+ ShaderInput *specular,
+ ShaderInput *roughness,
+ ShaderInput *specular_tint,
+ ShaderInput *anisotropic,
+ ShaderInput *sheen,
+ ShaderInput *sheen_tint,
+ ShaderInput *clearcoat,
+ ShaderInput *clearcoat_roughness,
+ ShaderInput *ior,
+ ShaderInput *transmission,
+ ShaderInput *anisotropic_rotation,
+ ShaderInput *transmission_roughness);
+
+ NODE_SOCKET_API(float3, base_color)
+ NODE_SOCKET_API(float3, subsurface_color)
+ NODE_SOCKET_API(float3, subsurface_radius)
+ NODE_SOCKET_API(float, subsurface_ior)
+ NODE_SOCKET_API(float, subsurface_anisotropy)
+ NODE_SOCKET_API(float, metallic)
+ NODE_SOCKET_API(float, subsurface)
+ NODE_SOCKET_API(float, specular)
+ NODE_SOCKET_API(float, roughness)
+ NODE_SOCKET_API(float, specular_tint)
+ NODE_SOCKET_API(float, anisotropic)
+ NODE_SOCKET_API(float, sheen)
+ NODE_SOCKET_API(float, sheen_tint)
+ NODE_SOCKET_API(float, clearcoat)
+ NODE_SOCKET_API(float, clearcoat_roughness)
+ NODE_SOCKET_API(float, ior)
+ NODE_SOCKET_API(float, transmission)
+ NODE_SOCKET_API(float, anisotropic_rotation)
+ NODE_SOCKET_API(float, transmission_roughness)
+ NODE_SOCKET_API(float3, normal)
+ NODE_SOCKET_API(float3, clearcoat_normal)
+ NODE_SOCKET_API(float3, tangent)
+ NODE_SOCKET_API(float, surface_mix_weight)
+ NODE_SOCKET_API(ClosureType, distribution)
+ NODE_SOCKET_API(ClosureType, subsurface_method)
+ NODE_SOCKET_API(float3, emission)
+ NODE_SOCKET_API(float, emission_strength)
+ NODE_SOCKET_API(float, alpha)
+
+ private:
+ ClosureType distribution_orig;
+
+ public:
+ bool has_integrator_dependency();
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+};
+
+class TranslucentBsdfNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(TranslucentBsdfNode)
+};
+
+class TransparentBsdfNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(TransparentBsdfNode)
+
+ bool has_surface_transparent()
+ {
+ return true;
+ }
+};
+
+class VelvetBsdfNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(VelvetBsdfNode)
+
+ NODE_SOCKET_API(float, sigma)
+};
+
+class GlossyBsdfNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(GlossyBsdfNode)
+
+ void simplify_settings(Scene *scene);
+ bool has_integrator_dependency();
+ ClosureType get_closure_type()
+ {
+ return distribution;
+ }
+
+ NODE_SOCKET_API(float, roughness)
+ NODE_SOCKET_API(ClosureType, distribution)
+
+ private:
+ float roughness_orig;
+ ClosureType distribution_orig;
+};
+
+class GlassBsdfNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(GlassBsdfNode)
+
+ void simplify_settings(Scene *scene);
+ bool has_integrator_dependency();
+ ClosureType get_closure_type()
+ {
+ return distribution;
+ }
+
+ NODE_SOCKET_API(float, roughness)
+ NODE_SOCKET_API(float, IOR)
+ NODE_SOCKET_API(ClosureType, distribution)
+
+ private:
+ float roughness_orig;
+ ClosureType distribution_orig;
+};
+
+class RefractionBsdfNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(RefractionBsdfNode)
+
+ void simplify_settings(Scene *scene);
+ bool has_integrator_dependency();
+ ClosureType get_closure_type()
+ {
+ return distribution;
+ }
+
+ NODE_SOCKET_API(float, roughness)
+ NODE_SOCKET_API(float, IOR)
+ NODE_SOCKET_API(ClosureType, distribution)
+
+ private:
+ float roughness_orig;
+ ClosureType distribution_orig;
+};
+
+class ToonBsdfNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(ToonBsdfNode)
+
+ NODE_SOCKET_API(float, smooth)
+ NODE_SOCKET_API(float, size)
+ NODE_SOCKET_API(ClosureType, component)
+};
+
+class SubsurfaceScatteringNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(SubsurfaceScatteringNode)
+ bool has_surface_bssrdf()
+ {
+ return true;
+ }
+ bool has_bssrdf_bump();
+ ClosureType get_closure_type()
+ {
+ return method;
+ }
+
+ NODE_SOCKET_API(float, scale)
+ NODE_SOCKET_API(float3, radius)
+ NODE_SOCKET_API(float, subsurface_ior)
+ NODE_SOCKET_API(float, subsurface_anisotropy)
+ NODE_SOCKET_API(ClosureType, method)
+};
+
+class EmissionNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(EmissionNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ bool has_surface_emission()
+ {
+ return true;
+ }
+ bool has_volume_support()
+ {
+ return true;
+ }
+
+ virtual int get_feature()
+ {
+ return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_EMISSION;
+ }
+
+ NODE_SOCKET_API(float3, color)
+ NODE_SOCKET_API(float, strength)
+ NODE_SOCKET_API(float, surface_mix_weight)
+};
+
+class BackgroundNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(BackgroundNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ virtual int get_feature()
+ {
+ return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_EMISSION;
+ }
+
+ NODE_SOCKET_API(float3, color)
+ NODE_SOCKET_API(float, strength)
+ NODE_SOCKET_API(float, surface_mix_weight)
+};
+
+class HoldoutNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(HoldoutNode)
+ virtual ClosureType get_closure_type()
+ {
+ return CLOSURE_HOLDOUT_ID;
+ }
+
+ NODE_SOCKET_API(float, surface_mix_weight)
+ NODE_SOCKET_API(float, volume_mix_weight)
+};
+
+class AmbientOcclusionNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(AmbientOcclusionNode)
+
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+ virtual int get_feature()
+ {
+ return KERNEL_FEATURE_NODE_RAYTRACE;
+ }
+
+ NODE_SOCKET_API(float3, color)
+ NODE_SOCKET_API(float, distance)
+ NODE_SOCKET_API(float3, normal)
+ NODE_SOCKET_API(int, samples)
+
+ NODE_SOCKET_API(bool, only_local)
+ NODE_SOCKET_API(bool, inside)
+};
+
+class VolumeNode : public ShaderNode {
+ public:
+ VolumeNode(const NodeType *node_type);
+ SHADER_NODE_BASE_CLASS(VolumeNode)
+
+ void compile(SVMCompiler &compiler, ShaderInput *param1, ShaderInput *param2);
+ virtual int get_feature()
+ {
+ return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_VOLUME;
+ }
+ virtual ClosureType get_closure_type()
+ {
+ return closure;
+ }
+ virtual bool has_volume_support()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(float3, color)
+ NODE_SOCKET_API(float, density)
+ NODE_SOCKET_API(float, volume_mix_weight)
+
+ protected:
+ ClosureType closure;
+
+ public:
+ virtual bool equals(const ShaderNode & /*other*/)
+ {
+ /* TODO(sergey): With some care Volume nodes can be de-duplicated. */
+ return false;
+ }
+};
+
+class AbsorptionVolumeNode : public VolumeNode {
+ public:
+ SHADER_NODE_CLASS(AbsorptionVolumeNode)
+};
+
+class ScatterVolumeNode : public VolumeNode {
+ public:
+ SHADER_NODE_CLASS(ScatterVolumeNode)
+
+ NODE_SOCKET_API(float, anisotropy)
+};
+
+class PrincipledVolumeNode : public VolumeNode {
+ public:
+ SHADER_NODE_CLASS(PrincipledVolumeNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(ustring, density_attribute)
+ NODE_SOCKET_API(ustring, color_attribute)
+ NODE_SOCKET_API(ustring, temperature_attribute)
+
+ NODE_SOCKET_API(float, anisotropy)
+ NODE_SOCKET_API(float3, absorption_color)
+ NODE_SOCKET_API(float, emission_strength)
+ NODE_SOCKET_API(float3, emission_color)
+ NODE_SOCKET_API(float, blackbody_intensity)
+ NODE_SOCKET_API(float3, blackbody_tint)
+ NODE_SOCKET_API(float, temperature)
+};
+
+/* Interface between the I/O sockets and the SVM/OSL backend. */
+class PrincipledHairBsdfNode : public BsdfBaseNode {
+ public:
+ SHADER_NODE_CLASS(PrincipledHairBsdfNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+
+ /* Longitudinal roughness. */
+ NODE_SOCKET_API(float, roughness)
+ /* Azimuthal roughness. */
+ NODE_SOCKET_API(float, radial_roughness)
+ /* Randomization factor for roughnesses. */
+ NODE_SOCKET_API(float, random_roughness)
+ /* Longitudinal roughness factor for only the diffuse bounce (shiny undercoat). */
+ NODE_SOCKET_API(float, coat)
+ /* Index of reflection. */
+ NODE_SOCKET_API(float, ior)
+ /* Cuticle tilt angle. */
+ NODE_SOCKET_API(float, offset)
+ /* Direct coloring's color. */
+ NODE_SOCKET_API(float3, color)
+ /* Melanin concentration. */
+ NODE_SOCKET_API(float, melanin)
+ /* Melanin redness ratio. */
+ NODE_SOCKET_API(float, melanin_redness)
+ /* Dye color. */
+ NODE_SOCKET_API(float3, tint)
+ /* Randomization factor for melanin quantities. */
+ NODE_SOCKET_API(float, random_color)
+ /* Absorption coefficient (unfiltered). */
+ NODE_SOCKET_API(float3, absorption_coefficient)
+
+ NODE_SOCKET_API(float3, normal)
+ NODE_SOCKET_API(float, surface_mix_weight)
+ /* If linked, here will be the given random number. */
+ NODE_SOCKET_API(float, random)
+ /* Selected coloring parametrization. */
+ NODE_SOCKET_API(NodePrincipledHairParametrization, parametrization)
+};
+
+class HairBsdfNode : public BsdfNode {
+ public:
+ SHADER_NODE_CLASS(HairBsdfNode)
+ ClosureType get_closure_type()
+ {
+ return component;
+ }
+
+ NODE_SOCKET_API(ClosureType, component)
+ NODE_SOCKET_API(float, offset)
+ NODE_SOCKET_API(float, roughness_u)
+ NODE_SOCKET_API(float, roughness_v)
+ NODE_SOCKET_API(float3, tangent)
+};
+
+class GeometryNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(GeometryNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+ int get_group();
+
+ NODE_SOCKET_API(float3, normal_osl)
+};
+
+class TextureCoordinateNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(TextureCoordinateNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(float3, normal_osl)
+ NODE_SOCKET_API(bool, from_dupli)
+ NODE_SOCKET_API(bool, use_transform)
+ NODE_SOCKET_API(Transform, ob_tfm)
+};
+
+class UVMapNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(UVMapNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(ustring, attribute)
+ NODE_SOCKET_API(bool, from_dupli)
+};
+
+class LightPathNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(LightPathNode)
+};
+
+class LightFalloffNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(LightFalloffNode)
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(float, strength)
+ NODE_SOCKET_API(float, smooth)
+};
+
+class ObjectInfoNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(ObjectInfoNode)
+};
+
+class ParticleInfoNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(ParticleInfoNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+};
+
+class HairInfoNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(HairInfoNode)
+
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+ virtual int get_feature()
+ {
+ return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_HAIR;
+ }
+};
+
+class VolumeInfoNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VolumeInfoNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+ void expand(ShaderGraph *graph);
+};
+
+class VertexColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VertexColorNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(ustring, layer_name)
+};
+
+class ValueNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(ValueNode)
+
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float, value)
+};
+
+class ColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(ColorNode)
+
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, value)
+};
+
+class AddClosureNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(AddClosureNode)
+ void constant_fold(const ConstantFolder &folder);
+};
+
+class MixClosureNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MixClosureNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float, fac)
+};
+
+class MixClosureWeightNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MixClosureWeightNode)
+
+ NODE_SOCKET_API(float, weight)
+ NODE_SOCKET_API(float, fac)
+};
+
+class InvertNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(InvertNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float, fac)
+ NODE_SOCKET_API(float3, color)
+};
+
+class MixNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MixNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(NodeMix, mix_type)
+ NODE_SOCKET_API(bool, use_clamp)
+ NODE_SOCKET_API(float3, color1)
+ NODE_SOCKET_API(float3, color2)
+ NODE_SOCKET_API(float, fac)
+};
+
+class CombineRGBNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(CombineRGBNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float, r)
+ NODE_SOCKET_API(float, g)
+ NODE_SOCKET_API(float, b)
+};
+
+class CombineHSVNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(CombineHSVNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float, h)
+ NODE_SOCKET_API(float, s)
+ NODE_SOCKET_API(float, v)
+};
+
+class CombineXYZNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(CombineXYZNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float, x)
+ NODE_SOCKET_API(float, y)
+ NODE_SOCKET_API(float, z)
+};
+
+class GammaNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(GammaNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, color)
+ NODE_SOCKET_API(float, gamma)
+};
+
+class BrightContrastNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(BrightContrastNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, color)
+ NODE_SOCKET_API(float, bright)
+ NODE_SOCKET_API(float, contrast)
+};
+
+class SeparateRGBNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(SeparateRGBNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, color)
+};
+
+class SeparateHSVNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(SeparateHSVNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, color)
+};
+
+class SeparateXYZNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(SeparateXYZNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, vector)
+};
+
+class HSVNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(HSVNode)
+
+ NODE_SOCKET_API(float, hue)
+ NODE_SOCKET_API(float, saturation)
+ NODE_SOCKET_API(float, value)
+ NODE_SOCKET_API(float, fac)
+ NODE_SOCKET_API(float3, color)
+};
+
+class AttributeNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(AttributeNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(ustring, attribute)
+};
+
+class CameraNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(CameraNode)
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+};
+
+class FresnelNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(FresnelNode)
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(float3, normal)
+ NODE_SOCKET_API(float, IOR)
+};
+
+class LayerWeightNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(LayerWeightNode)
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(float3, normal)
+ NODE_SOCKET_API(float, blend)
+};
+
+class WireframeNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(WireframeNode)
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(float, size)
+ NODE_SOCKET_API(bool, use_pixel_size)
+};
+
+class WavelengthNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(WavelengthNode)
+
+ NODE_SOCKET_API(float, wavelength)
+};
+
+class BlackbodyNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(BlackbodyNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float, temperature)
+};
+
+class MapRangeNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MapRangeNode)
+ void expand(ShaderGraph *graph);
+
+ NODE_SOCKET_API(float, value)
+ NODE_SOCKET_API(float, from_min)
+ NODE_SOCKET_API(float, from_max)
+ NODE_SOCKET_API(float, to_min)
+ NODE_SOCKET_API(float, to_max)
+ NODE_SOCKET_API(float, steps)
+ NODE_SOCKET_API(NodeMapRangeType, range_type)
+ NODE_SOCKET_API(bool, clamp)
+};
+
+class ClampNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(ClampNode)
+ void constant_fold(const ConstantFolder &folder);
+ NODE_SOCKET_API(float, value)
+ NODE_SOCKET_API(float, min)
+ NODE_SOCKET_API(float, max)
+ NODE_SOCKET_API(NodeClampType, clamp_type)
+};
+
+class MathNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MathNode)
+ void expand(ShaderGraph *graph);
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float, value1)
+ NODE_SOCKET_API(float, value2)
+ NODE_SOCKET_API(float, value3)
+ NODE_SOCKET_API(NodeMathType, math_type)
+ NODE_SOCKET_API(bool, use_clamp)
+};
+
+class NormalNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(NormalNode)
+
+ NODE_SOCKET_API(float3, direction)
+ NODE_SOCKET_API(float3, normal)
+};
+
+class VectorMathNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VectorMathNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, vector1)
+ NODE_SOCKET_API(float3, vector2)
+ NODE_SOCKET_API(float3, vector3)
+ NODE_SOCKET_API(float, scale)
+ NODE_SOCKET_API(NodeVectorMathType, math_type)
+};
+
+class VectorRotateNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VectorRotateNode)
+
+ NODE_SOCKET_API(NodeVectorRotateType, rotate_type)
+ NODE_SOCKET_API(bool, invert)
+ NODE_SOCKET_API(float3, vector)
+ NODE_SOCKET_API(float3, center)
+ NODE_SOCKET_API(float3, axis)
+ NODE_SOCKET_API(float, angle)
+ NODE_SOCKET_API(float3, rotation)
+};
+
+class VectorTransformNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VectorTransformNode)
+
+ NODE_SOCKET_API(NodeVectorTransformType, transform_type)
+ NODE_SOCKET_API(NodeVectorTransformConvertSpace, convert_from)
+ NODE_SOCKET_API(NodeVectorTransformConvertSpace, convert_to)
+ NODE_SOCKET_API(float3, vector)
+};
+
+class BumpNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(BumpNode)
+ void constant_fold(const ConstantFolder &folder);
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+ virtual int get_feature()
+ {
+ return KERNEL_FEATURE_NODE_BUMP;
+ }
+
+ NODE_SOCKET_API(bool, invert)
+ NODE_SOCKET_API(bool, use_object_space)
+ NODE_SOCKET_API(float, height)
+ NODE_SOCKET_API(float, sample_center)
+ NODE_SOCKET_API(float, sample_x)
+ NODE_SOCKET_API(float, sample_y)
+ NODE_SOCKET_API(float3, normal)
+ NODE_SOCKET_API(float, strength)
+ NODE_SOCKET_API(float, distance)
+};
+
+class CurvesNode : public ShaderNode {
+ public:
+ explicit CurvesNode(const NodeType *node_type);
+ SHADER_NODE_BASE_CLASS(CurvesNode)
+
+ NODE_SOCKET_API_ARRAY(array<float3>, curves)
+ NODE_SOCKET_API(float, min_x)
+ NODE_SOCKET_API(float, max_x)
+ NODE_SOCKET_API(float, fac)
+ NODE_SOCKET_API(float3, value)
+
+ protected:
+ using ShaderNode::constant_fold;
+ void constant_fold(const ConstantFolder &folder, ShaderInput *value_in);
+ void compile(SVMCompiler &compiler, int type, ShaderInput *value_in, ShaderOutput *value_out);
+ void compile(OSLCompiler &compiler, const char *name);
+};
+
+class RGBCurvesNode : public CurvesNode {
+ public:
+ SHADER_NODE_CLASS(RGBCurvesNode)
+ void constant_fold(const ConstantFolder &folder);
+};
+
+class VectorCurvesNode : public CurvesNode {
+ public:
+ SHADER_NODE_CLASS(VectorCurvesNode)
+ void constant_fold(const ConstantFolder &folder);
+};
+
+class FloatCurveNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(FloatCurveNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API_ARRAY(array<float>, curve)
+ NODE_SOCKET_API(float, min_x)
+ NODE_SOCKET_API(float, max_x)
+ NODE_SOCKET_API(float, fac)
+ NODE_SOCKET_API(float, value)
+};
+
+class RGBRampNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(RGBRampNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API_ARRAY(array<float3>, ramp)
+ NODE_SOCKET_API_ARRAY(array<float>, ramp_alpha)
+ NODE_SOCKET_API(float, fac)
+ NODE_SOCKET_API(bool, interpolate)
+};
+
+class SetNormalNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(SetNormalNode)
+ NODE_SOCKET_API(float3, direction)
+};
+
+class OSLNode final : public ShaderNode {
+ public:
+ static OSLNode *create(ShaderGraph *graph, size_t num_inputs, const OSLNode *from = NULL);
+ ~OSLNode();
+
+ static void operator delete(void *ptr)
+ {
+ /* Override delete operator to silence new-delete-type-mismatch ASAN warnings
+ * regarding size mismatch in the destructor. This is intentional as we allocate
+ * extra space at the end of the node. */
+ ::operator delete(ptr);
+ }
+ static void operator delete(void *, void *)
+ {
+ /* Deliberately empty placement delete operator, to avoid MSVC warning C4291. */
+ }
+
+ ShaderNode *clone(ShaderGraph *graph) const;
+
+ char *input_default_value();
+ void add_input(ustring name, SocketType::Type type);
+ void add_output(ustring name, SocketType::Type type);
+
+ SHADER_NODE_NO_CLONE_CLASS(OSLNode)
+
+ /* Ideally we could better detect this, but we can't query this now. */
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+ bool has_volume_support()
+ {
+ return true;
+ }
+
+ virtual bool equals(const ShaderNode & /*other*/)
+ {
+ return false;
+ }
+
+ string filepath;
+ string bytecode_hash;
+};
+
+class NormalMapNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(NormalMapNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(NodeNormalMapSpace, space)
+ NODE_SOCKET_API(ustring, attribute)
+ NODE_SOCKET_API(float, strength)
+ NODE_SOCKET_API(float3, color)
+ NODE_SOCKET_API(float3, normal_osl)
+};
+
+class TangentNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(TangentNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ NODE_SOCKET_API(NodeTangentDirectionType, direction_type)
+ NODE_SOCKET_API(NodeTangentAxis, axis)
+ NODE_SOCKET_API(ustring, attribute)
+ NODE_SOCKET_API(float3, normal_osl)
+};
+
+class BevelNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(BevelNode)
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+ virtual int get_feature()
+ {
+ return KERNEL_FEATURE_NODE_RAYTRACE;
+ }
+
+ NODE_SOCKET_API(float, radius)
+ NODE_SOCKET_API(float3, normal)
+ NODE_SOCKET_API(int, samples)
+};
+
+class DisplacementNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(DisplacementNode)
+ void constant_fold(const ConstantFolder &folder);
+ virtual int get_feature()
+ {
+ return KERNEL_FEATURE_NODE_BUMP;
+ }
+
+ NODE_SOCKET_API(NodeNormalMapSpace, space)
+ NODE_SOCKET_API(float, height)
+ NODE_SOCKET_API(float, midlevel)
+ NODE_SOCKET_API(float, scale)
+ NODE_SOCKET_API(float3, normal)
+};
+
+class VectorDisplacementNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VectorDisplacementNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ void constant_fold(const ConstantFolder &folder);
+ virtual int get_feature()
+ {
+ return KERNEL_FEATURE_NODE_BUMP;
+ }
+
+ NODE_SOCKET_API(NodeNormalMapSpace, space)
+ NODE_SOCKET_API(ustring, attribute)
+ NODE_SOCKET_API(float3, vector)
+ NODE_SOCKET_API(float, midlevel)
+ NODE_SOCKET_API(float, scale)
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __NODES_H__ */
diff --git a/intern/cycles/scene/sobol.cpp b/intern/cycles/scene/sobol.cpp
new file mode 100644
index 00000000000..09d10c3660e
--- /dev/null
+++ b/intern/cycles/scene/sobol.cpp
@@ -0,0 +1,94 @@
+/*
+ * Sobol sequence direction vectors.
+ *
+ * This file contains code to create direction vectors for generating sobol
+ * sequences in high dimensions. It is adapted from code on this webpage:
+ *
+ * http://web.maths.unsw.edu.au/~fkuo/sobol/
+ *
+ * From these papers:
+ *
+ * S. Joe and F. Y. Kuo, Remark on Algorithm 659: Implementing Sobol's quasirandom
+ * sequence generator, ACM Trans. Math. Softw. 29, 49-57 (2003)
+ *
+ * S. Joe and F. Y. Kuo, Constructing Sobol sequences with better two-dimensional
+ * projections, SIAM J. Sci. Comput. 30, 2635-2654 (2008)
+ */
+
+/* Copyright (c) 2008, Frances Y. Kuo and Stephen Joe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the names of the copyright holders nor the names of the
+ * University of New South Wales and the University of Waikato
+ * and its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "util/types.h"
+
+#include "scene/sobol.h"
+
+CCL_NAMESPACE_BEGIN
+
+#include "scene/sobol.tables"
+
+void sobol_generate_direction_vectors(uint vectors[][SOBOL_BITS], int dimensions)
+{
+ assert(dimensions <= SOBOL_MAX_DIMENSIONS);
+
+ const uint L = SOBOL_BITS;
+
+ /* first dimension is exception */
+ uint *v = vectors[0];
+
+ for (uint i = 0; i < L; i++)
+ v[i] = 1 << (31 - i); // all m's = 1
+
+ for (int dim = 1; dim < dimensions; dim++) {
+ const SobolDirectionNumbers *numbers = &SOBOL_NUMBERS[dim - 1];
+ const uint s = numbers->s;
+ const uint a = numbers->a;
+ const uint *m = numbers->m;
+
+ v = vectors[dim];
+
+ if (L <= s) {
+ for (uint i = 0; i < L; i++)
+ v[i] = m[i] << (31 - i);
+ }
+ else {
+ for (uint i = 0; i < s; i++)
+ v[i] = m[i] << (31 - i);
+
+ for (uint i = s; i < L; i++) {
+ v[i] = v[i - s] ^ (v[i - s] >> s);
+
+ for (uint k = 1; k < s; k++)
+ v[i] ^= (((a >> (s - 1 - k)) & 1) * v[i - k]);
+ }
+ }
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/sobol.h b/intern/cycles/scene/sobol.h
new file mode 100644
index 00000000000..86b2a1616b8
--- /dev/null
+++ b/intern/cycles/scene/sobol.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SOBOL_H__
+#define __SOBOL_H__
+
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+#define SOBOL_BITS 32
+#define SOBOL_MAX_DIMENSIONS 21201
+
+void sobol_generate_direction_vectors(uint vectors[][SOBOL_BITS], int dimensions);
+
+CCL_NAMESPACE_END
+
+#endif /* __SOBOL_H__ */
diff --git a/intern/cycles/scene/sobol.tables b/intern/cycles/scene/sobol.tables
new file mode 100644
index 00000000000..24f174dfae2
--- /dev/null
+++ b/intern/cycles/scene/sobol.tables
@@ -0,0 +1,21258 @@
+/*
+ * Sobol sequence direction vectors.
+ *
+ * This file contains code to create direction vectors for generating sobol
+ * sequences in high dimensions. It is adapted from code on this webpage:
+ *
+ * http://web.maths.unsw.edu.au/~fkuo/sobol/
+ *
+ * From these papers:
+ *
+ * S. Joe and F. Y. Kuo, Remark on Algorithm 659: Implementing Sobol's quasirandom
+ * sequence generator, ACM Trans. Math. Softw. 29, 49-57 (2003)
+ *
+ * S. Joe and F. Y. Kuo, Constructing Sobol sequences with better two-dimensional
+ * projections, SIAM J. Sci. Comput. 30, 2635-2654 (2008)
+ */
+
+/* Copyright (c) 2008, Frances Y. Kuo and Stephen Joe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the names of the copyright holders nor the names of the
+ * University of New South Wales and the University of Waikato
+ * and its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Note: this file has a non-standard extension so it is skipped by clang-format. */
+
+#define SOBOL_MAX_NUMBER 32
+
+typedef struct SobolDirectionNumbers {
+ uint d, s, a;
+ uint m[SOBOL_MAX_NUMBER];
+} SobolDirectionNumbers;
+
+static const SobolDirectionNumbers SOBOL_NUMBERS[SOBOL_MAX_DIMENSIONS - 1] = {
+{2, 1, 0, {1}},
+{3, 2, 1, {1, 3}},
+{4, 3, 1, {1, 3, 1}},
+{5, 3, 2, {1, 1, 1}},
+{6, 4, 1, {1, 1, 3, 3}},
+{7, 4, 4, {1, 3, 5, 13}},
+{8, 5, 2, {1, 1, 5, 5, 17}},
+{9, 5, 4, {1, 1, 5, 5, 5}},
+{10, 5, 7, {1, 1, 7, 11, 19}},
+{11, 5, 11, {1, 1, 5, 1, 1}},
+{12, 5, 13, {1, 1, 1, 3, 11}},
+{13, 5, 14, {1, 3, 5, 5, 31}},
+{14, 6, 1, {1, 3, 3, 9, 7, 49}},
+{15, 6, 13, {1, 1, 1, 15, 21, 21}},
+{16, 6, 16, {1, 3, 1, 13, 27, 49}},
+{17, 6, 19, {1, 1, 1, 15, 7, 5}},
+{18, 6, 22, {1, 3, 1, 15, 13, 25}},
+{19, 6, 25, {1, 1, 5, 5, 19, 61}},
+{20, 7, 1, {1, 3, 7, 11, 23, 15, 103}},
+{21, 7, 4, {1, 3, 7, 13, 13, 15, 69}},
+{22, 7, 7, {1, 1, 3, 13, 7, 35, 63}},
+{23, 7, 8, {1, 3, 5, 9, 1, 25, 53}},
+{24, 7, 14, {1, 3, 1, 13, 9, 35, 107}},
+{25, 7, 19, {1, 3, 1, 5, 27, 61, 31}},
+{26, 7, 21, {1, 1, 5, 11, 19, 41, 61}},
+{27, 7, 28, {1, 3, 5, 3, 3, 13, 69}},
+{28, 7, 31, {1, 1, 7, 13, 1, 19, 1}},
+{29, 7, 32, {1, 3, 7, 5, 13, 19, 59}},
+{30, 7, 37, {1, 1, 3, 9, 25, 29, 41}},
+{31, 7, 41, {1, 3, 5, 13, 23, 1, 55}},
+{32, 7, 42, {1, 3, 7, 3, 13, 59, 17}},
+{33, 7, 50, {1, 3, 1, 3, 5, 53, 69}},
+{34, 7, 55, {1, 1, 5, 5, 23, 33, 13}},
+{35, 7, 56, {1, 1, 7, 7, 1, 61, 123}},
+{36, 7, 59, {1, 1, 7, 9, 13, 61, 49}},
+{37, 7, 62, {1, 3, 3, 5, 3, 55, 33}},
+{38, 8, 14, {1, 3, 1, 15, 31, 13, 49, 245}},
+{39, 8, 21, {1, 3, 5, 15, 31, 59, 63, 97}},
+{40, 8, 22, {1, 3, 1, 11, 11, 11, 77, 249}},
+{41, 8, 38, {1, 3, 1, 11, 27, 43, 71, 9}},
+{42, 8, 47, {1, 1, 7, 15, 21, 11, 81, 45}},
+{43, 8, 49, {1, 3, 7, 3, 25, 31, 65, 79}},
+{44, 8, 50, {1, 3, 1, 1, 19, 11, 3, 205}},
+{45, 8, 52, {1, 1, 5, 9, 19, 21, 29, 157}},
+{46, 8, 56, {1, 3, 7, 11, 1, 33, 89, 185}},
+{47, 8, 67, {1, 3, 3, 3, 15, 9, 79, 71}},
+{48, 8, 70, {1, 3, 7, 11, 15, 39, 119, 27}},
+{49, 8, 84, {1, 1, 3, 1, 11, 31, 97, 225}},
+{50, 8, 97, {1, 1, 1, 3, 23, 43, 57, 177}},
+{51, 8, 103, {1, 3, 7, 7, 17, 17, 37, 71}},
+{52, 8, 115, {1, 3, 1, 5, 27, 63, 123, 213}},
+{53, 8, 122, {1, 1, 3, 5, 11, 43, 53, 133}},
+{54, 9, 8, {1, 3, 5, 5, 29, 17, 47, 173, 479}},
+{55, 9, 13, {1, 3, 3, 11, 3, 1, 109, 9, 69}},
+{56, 9, 16, {1, 1, 1, 5, 17, 39, 23, 5, 343}},
+{57, 9, 22, {1, 3, 1, 5, 25, 15, 31, 103, 499}},
+{58, 9, 25, {1, 1, 1, 11, 11, 17, 63, 105, 183}},
+{59, 9, 44, {1, 1, 5, 11, 9, 29, 97, 231, 363}},
+{60, 9, 47, {1, 1, 5, 15, 19, 45, 41, 7, 383}},
+{61, 9, 52, {1, 3, 7, 7, 31, 19, 83, 137, 221}},
+{62, 9, 55, {1, 1, 1, 3, 23, 15, 111, 223, 83}},
+{63, 9, 59, {1, 1, 5, 13, 31, 15, 55, 25, 161}},
+{64, 9, 62, {1, 1, 3, 13, 25, 47, 39, 87, 257}},
+{65, 9, 67, {1, 1, 1, 11, 21, 53, 125, 249, 293}},
+{66, 9, 74, {1, 1, 7, 11, 11, 7, 57, 79, 323}},
+{67, 9, 81, {1, 1, 5, 5, 17, 13, 81, 3, 131}},
+{68, 9, 82, {1, 1, 7, 13, 23, 7, 65, 251, 475}},
+{69, 9, 87, {1, 3, 5, 1, 9, 43, 3, 149, 11}},
+{70, 9, 91, {1, 1, 3, 13, 31, 13, 13, 255, 487}},
+{71, 9, 94, {1, 3, 3, 1, 5, 63, 89, 91, 127}},
+{72, 9, 103, {1, 1, 3, 3, 1, 19, 123, 127, 237}},
+{73, 9, 104, {1, 1, 5, 7, 23, 31, 37, 243, 289}},
+{74, 9, 109, {1, 1, 5, 11, 17, 53, 117, 183, 491}},
+{75, 9, 122, {1, 1, 1, 5, 1, 13, 13, 209, 345}},
+{76, 9, 124, {1, 1, 3, 15, 1, 57, 115, 7, 33}},
+{77, 9, 137, {1, 3, 1, 11, 7, 43, 81, 207, 175}},
+{78, 9, 138, {1, 3, 1, 1, 15, 27, 63, 255, 49}},
+{79, 9, 143, {1, 3, 5, 3, 27, 61, 105, 171, 305}},
+{80, 9, 145, {1, 1, 5, 3, 1, 3, 57, 249, 149}},
+{81, 9, 152, {1, 1, 3, 5, 5, 57, 15, 13, 159}},
+{82, 9, 157, {1, 1, 1, 11, 7, 11, 105, 141, 225}},
+{83, 9, 167, {1, 3, 3, 5, 27, 59, 121, 101, 271}},
+{84, 9, 173, {1, 3, 5, 9, 11, 49, 51, 59, 115}},
+{85, 9, 176, {1, 1, 7, 1, 23, 45, 125, 71, 419}},
+{86, 9, 181, {1, 1, 3, 5, 23, 5, 105, 109, 75}},
+{87, 9, 182, {1, 1, 7, 15, 7, 11, 67, 121, 453}},
+{88, 9, 185, {1, 3, 7, 3, 9, 13, 31, 27, 449}},
+{89, 9, 191, {1, 3, 1, 15, 19, 39, 39, 89, 15}},
+{90, 9, 194, {1, 1, 1, 1, 1, 33, 73, 145, 379}},
+{91, 9, 199, {1, 3, 1, 15, 15, 43, 29, 13, 483}},
+{92, 9, 218, {1, 1, 7, 3, 19, 27, 85, 131, 431}},
+{93, 9, 220, {1, 3, 3, 3, 5, 35, 23, 195, 349}},
+{94, 9, 227, {1, 3, 3, 7, 9, 27, 39, 59, 297}},
+{95, 9, 229, {1, 1, 3, 9, 11, 17, 13, 241, 157}},
+{96, 9, 230, {1, 3, 7, 15, 25, 57, 33, 189, 213}},
+{97, 9, 234, {1, 1, 7, 1, 9, 55, 73, 83, 217}},
+{98, 9, 236, {1, 3, 3, 13, 19, 27, 23, 113, 249}},
+{99, 9, 241, {1, 3, 5, 3, 23, 43, 3, 253, 479}},
+{100, 9, 244, {1, 1, 5, 5, 11, 5, 45, 117, 217}},
+{101, 9, 253, {1, 3, 3, 7, 29, 37, 33, 123, 147}},
+{102, 10, 4, {1, 3, 1, 15, 5, 5, 37, 227, 223, 459}},
+{103, 10, 13, {1, 1, 7, 5, 5, 39, 63, 255, 135, 487}},
+{104, 10, 19, {1, 3, 1, 7, 9, 7, 87, 249, 217, 599}},
+{105, 10, 22, {1, 1, 3, 13, 9, 47, 7, 225, 363, 247}},
+{106, 10, 50, {1, 3, 7, 13, 19, 13, 9, 67, 9, 737}},
+{107, 10, 55, {1, 3, 5, 5, 19, 59, 7, 41, 319, 677}},
+{108, 10, 64, {1, 1, 5, 3, 31, 63, 15, 43, 207, 789}},
+{109, 10, 69, {1, 1, 7, 9, 13, 39, 3, 47, 497, 169}},
+{110, 10, 98, {1, 3, 1, 7, 21, 17, 97, 19, 415, 905}},
+{111, 10, 107, {1, 3, 7, 1, 3, 31, 71, 111, 165, 127}},
+{112, 10, 115, {1, 1, 5, 11, 1, 61, 83, 119, 203, 847}},
+{113, 10, 121, {1, 3, 3, 13, 9, 61, 19, 97, 47, 35}},
+{114, 10, 127, {1, 1, 7, 7, 15, 29, 63, 95, 417, 469}},
+{115, 10, 134, {1, 3, 1, 9, 25, 9, 71, 57, 213, 385}},
+{116, 10, 140, {1, 3, 5, 13, 31, 47, 101, 57, 39, 341}},
+{117, 10, 145, {1, 1, 3, 3, 31, 57, 125, 173, 365, 551}},
+{118, 10, 152, {1, 3, 7, 1, 13, 57, 67, 157, 451, 707}},
+{119, 10, 158, {1, 1, 1, 7, 21, 13, 105, 89, 429, 965}},
+{120, 10, 161, {1, 1, 5, 9, 17, 51, 45, 119, 157, 141}},
+{121, 10, 171, {1, 3, 7, 7, 13, 45, 91, 9, 129, 741}},
+{122, 10, 181, {1, 3, 7, 1, 23, 57, 67, 141, 151, 571}},
+{123, 10, 194, {1, 1, 3, 11, 17, 47, 93, 107, 375, 157}},
+{124, 10, 199, {1, 3, 3, 5, 11, 21, 43, 51, 169, 915}},
+{125, 10, 203, {1, 1, 5, 3, 15, 55, 101, 67, 455, 625}},
+{126, 10, 208, {1, 3, 5, 9, 1, 23, 29, 47, 345, 595}},
+{127, 10, 227, {1, 3, 7, 7, 5, 49, 29, 155, 323, 589}},
+{128, 10, 242, {1, 3, 3, 7, 5, 41, 127, 61, 261, 717}},
+{129, 10, 251, {1, 3, 7, 7, 17, 23, 117, 67, 129, 1009}},
+{130, 10, 253, {1, 1, 3, 13, 11, 39, 21, 207, 123, 305}},
+{131, 10, 265, {1, 1, 3, 9, 29, 3, 95, 47, 231, 73}},
+{132, 10, 266, {1, 3, 1, 9, 1, 29, 117, 21, 441, 259}},
+{133, 10, 274, {1, 3, 1, 13, 21, 39, 125, 211, 439, 723}},
+{134, 10, 283, {1, 1, 7, 3, 17, 63, 115, 89, 49, 773}},
+{135, 10, 289, {1, 3, 7, 13, 11, 33, 101, 107, 63, 73}},
+{136, 10, 295, {1, 1, 5, 5, 13, 57, 63, 135, 437, 177}},
+{137, 10, 301, {1, 1, 3, 7, 27, 63, 93, 47, 417, 483}},
+{138, 10, 316, {1, 1, 3, 1, 23, 29, 1, 191, 49, 23}},
+{139, 10, 319, {1, 1, 3, 15, 25, 55, 9, 101, 219, 607}},
+{140, 10, 324, {1, 3, 1, 7, 7, 19, 51, 251, 393, 307}},
+{141, 10, 346, {1, 3, 3, 3, 25, 55, 17, 75, 337, 3}},
+{142, 10, 352, {1, 1, 1, 13, 25, 17, 65, 45, 479, 413}},
+{143, 10, 361, {1, 1, 7, 7, 27, 49, 99, 161, 213, 727}},
+{144, 10, 367, {1, 3, 5, 1, 23, 5, 43, 41, 251, 857}},
+{145, 10, 382, {1, 3, 3, 7, 11, 61, 39, 87, 383, 835}},
+{146, 10, 395, {1, 1, 3, 15, 13, 7, 29, 7, 505, 923}},
+{147, 10, 398, {1, 3, 7, 1, 5, 31, 47, 157, 445, 501}},
+{148, 10, 400, {1, 1, 3, 7, 1, 43, 9, 147, 115, 605}},
+{149, 10, 412, {1, 3, 3, 13, 5, 1, 119, 211, 455, 1001}},
+{150, 10, 419, {1, 1, 3, 5, 13, 19, 3, 243, 75, 843}},
+{151, 10, 422, {1, 3, 7, 7, 1, 19, 91, 249, 357, 589}},
+{152, 10, 426, {1, 1, 1, 9, 1, 25, 109, 197, 279, 411}},
+{153, 10, 428, {1, 3, 1, 15, 23, 57, 59, 135, 191, 75}},
+{154, 10, 433, {1, 1, 5, 15, 29, 21, 39, 253, 383, 349}},
+{155, 10, 446, {1, 3, 3, 5, 19, 45, 61, 151, 199, 981}},
+{156, 10, 454, {1, 3, 5, 13, 9, 61, 107, 141, 141, 1}},
+{157, 10, 457, {1, 3, 1, 11, 27, 25, 85, 105, 309, 979}},
+{158, 10, 472, {1, 3, 3, 11, 19, 7, 115, 223, 349, 43}},
+{159, 10, 493, {1, 1, 7, 9, 21, 39, 123, 21, 275, 927}},
+{160, 10, 505, {1, 1, 7, 13, 15, 41, 47, 243, 303, 437}},
+{161, 10, 508, {1, 1, 1, 7, 7, 3, 15, 99, 409, 719}},
+{162, 11, 2, {1, 3, 3, 15, 27, 49, 113, 123, 113, 67, 469}},
+{163, 11, 11, {1, 3, 7, 11, 3, 23, 87, 169, 119, 483, 199}},
+{164, 11, 21, {1, 1, 5, 15, 7, 17, 109, 229, 179, 213, 741}},
+{165, 11, 22, {1, 1, 5, 13, 11, 17, 25, 135, 403, 557, 1433}},
+{166, 11, 35, {1, 3, 1, 1, 1, 61, 67, 215, 189, 945, 1243}},
+{167, 11, 49, {1, 1, 7, 13, 17, 33, 9, 221, 429, 217, 1679}},
+{168, 11, 50, {1, 1, 3, 11, 27, 3, 15, 93, 93, 865, 1049}},
+{169, 11, 56, {1, 3, 7, 7, 25, 41, 121, 35, 373, 379, 1547}},
+{170, 11, 61, {1, 3, 3, 9, 11, 35, 45, 205, 241, 9, 59}},
+{171, 11, 70, {1, 3, 1, 7, 3, 51, 7, 177, 53, 975, 89}},
+{172, 11, 74, {1, 1, 3, 5, 27, 1, 113, 231, 299, 759, 861}},
+{173, 11, 79, {1, 3, 3, 15, 25, 29, 5, 255, 139, 891, 2031}},
+{174, 11, 84, {1, 3, 1, 1, 13, 9, 109, 193, 419, 95, 17}},
+{175, 11, 88, {1, 1, 7, 9, 3, 7, 29, 41, 135, 839, 867}},
+{176, 11, 103, {1, 1, 7, 9, 25, 49, 123, 217, 113, 909, 215}},
+{177, 11, 104, {1, 1, 7, 3, 23, 15, 43, 133, 217, 327, 901}},
+{178, 11, 112, {1, 1, 3, 3, 13, 53, 63, 123, 477, 711, 1387}},
+{179, 11, 115, {1, 1, 3, 15, 7, 29, 75, 119, 181, 957, 247}},
+{180, 11, 117, {1, 1, 1, 11, 27, 25, 109, 151, 267, 99, 1461}},
+{181, 11, 122, {1, 3, 7, 15, 5, 5, 53, 145, 11, 725, 1501}},
+{182, 11, 134, {1, 3, 7, 1, 9, 43, 71, 229, 157, 607, 1835}},
+{183, 11, 137, {1, 3, 3, 13, 25, 1, 5, 27, 471, 349, 127}},
+{184, 11, 146, {1, 1, 1, 1, 23, 37, 9, 221, 269, 897, 1685}},
+{185, 11, 148, {1, 1, 3, 3, 31, 29, 51, 19, 311, 553, 1969}},
+{186, 11, 157, {1, 3, 7, 5, 5, 55, 17, 39, 475, 671, 1529}},
+{187, 11, 158, {1, 1, 7, 1, 1, 35, 47, 27, 437, 395, 1635}},
+{188, 11, 162, {1, 1, 7, 3, 13, 23, 43, 135, 327, 139, 389}},
+{189, 11, 164, {1, 3, 7, 3, 9, 25, 91, 25, 429, 219, 513}},
+{190, 11, 168, {1, 1, 3, 5, 13, 29, 119, 201, 277, 157, 2043}},
+{191, 11, 173, {1, 3, 5, 3, 29, 57, 13, 17, 167, 739, 1031}},
+{192, 11, 185, {1, 3, 3, 5, 29, 21, 95, 27, 255, 679, 1531}},
+{193, 11, 186, {1, 3, 7, 15, 9, 5, 21, 71, 61, 961, 1201}},
+{194, 11, 191, {1, 3, 5, 13, 15, 57, 33, 93, 459, 867, 223}},
+{195, 11, 193, {1, 1, 1, 15, 17, 43, 127, 191, 67, 177, 1073}},
+{196, 11, 199, {1, 1, 1, 15, 23, 7, 21, 199, 75, 293, 1611}},
+{197, 11, 213, {1, 3, 7, 13, 15, 39, 21, 149, 65, 741, 319}},
+{198, 11, 214, {1, 3, 7, 11, 23, 13, 101, 89, 277, 519, 711}},
+{199, 11, 220, {1, 3, 7, 15, 19, 27, 85, 203, 441, 97, 1895}},
+{200, 11, 227, {1, 3, 1, 3, 29, 25, 21, 155, 11, 191, 197}},
+{201, 11, 236, {1, 1, 7, 5, 27, 11, 81, 101, 457, 675, 1687}},
+{202, 11, 242, {1, 3, 1, 5, 25, 5, 65, 193, 41, 567, 781}},
+{203, 11, 251, {1, 3, 1, 5, 11, 15, 113, 77, 411, 695, 1111}},
+{204, 11, 256, {1, 1, 3, 9, 11, 53, 119, 171, 55, 297, 509}},
+{205, 11, 259, {1, 1, 1, 1, 11, 39, 113, 139, 165, 347, 595}},
+{206, 11, 265, {1, 3, 7, 11, 9, 17, 101, 13, 81, 325, 1733}},
+{207, 11, 266, {1, 3, 1, 1, 21, 43, 115, 9, 113, 907, 645}},
+{208, 11, 276, {1, 1, 7, 3, 9, 25, 117, 197, 159, 471, 475}},
+{209, 11, 292, {1, 3, 1, 9, 11, 21, 57, 207, 485, 613, 1661}},
+{210, 11, 304, {1, 1, 7, 7, 27, 55, 49, 223, 89, 85, 1523}},
+{211, 11, 310, {1, 1, 5, 3, 19, 41, 45, 51, 447, 299, 1355}},
+{212, 11, 316, {1, 3, 1, 13, 1, 33, 117, 143, 313, 187, 1073}},
+{213, 11, 319, {1, 1, 7, 7, 5, 11, 65, 97, 377, 377, 1501}},
+{214, 11, 322, {1, 3, 1, 1, 21, 35, 95, 65, 99, 23, 1239}},
+{215, 11, 328, {1, 1, 5, 9, 3, 37, 95, 167, 115, 425, 867}},
+{216, 11, 334, {1, 3, 3, 13, 1, 37, 27, 189, 81, 679, 773}},
+{217, 11, 339, {1, 1, 3, 11, 1, 61, 99, 233, 429, 969, 49}},
+{218, 11, 341, {1, 1, 1, 7, 25, 63, 99, 165, 245, 793, 1143}},
+{219, 11, 345, {1, 1, 5, 11, 11, 43, 55, 65, 71, 283, 273}},
+{220, 11, 346, {1, 1, 5, 5, 9, 3, 101, 251, 355, 379, 1611}},
+{221, 11, 362, {1, 1, 1, 15, 21, 63, 85, 99, 49, 749, 1335}},
+{222, 11, 367, {1, 1, 5, 13, 27, 9, 121, 43, 255, 715, 289}},
+{223, 11, 372, {1, 3, 1, 5, 27, 19, 17, 223, 77, 571, 1415}},
+{224, 11, 375, {1, 1, 5, 3, 13, 59, 125, 251, 195, 551, 1737}},
+{225, 11, 376, {1, 3, 3, 15, 13, 27, 49, 105, 389, 971, 755}},
+{226, 11, 381, {1, 3, 5, 15, 23, 43, 35, 107, 447, 763, 253}},
+{227, 11, 385, {1, 3, 5, 11, 21, 3, 17, 39, 497, 407, 611}},
+{228, 11, 388, {1, 1, 7, 13, 15, 31, 113, 17, 23, 507, 1995}},
+{229, 11, 392, {1, 1, 7, 15, 3, 15, 31, 153, 423, 79, 503}},
+{230, 11, 409, {1, 1, 7, 9, 19, 25, 23, 171, 505, 923, 1989}},
+{231, 11, 415, {1, 1, 5, 9, 21, 27, 121, 223, 133, 87, 697}},
+{232, 11, 416, {1, 1, 5, 5, 9, 19, 107, 99, 319, 765, 1461}},
+{233, 11, 421, {1, 1, 3, 3, 19, 25, 3, 101, 171, 729, 187}},
+{234, 11, 428, {1, 1, 3, 1, 13, 23, 85, 93, 291, 209, 37}},
+{235, 11, 431, {1, 1, 1, 15, 25, 25, 77, 253, 333, 947, 1073}},
+{236, 11, 434, {1, 1, 3, 9, 17, 29, 55, 47, 255, 305, 2037}},
+{237, 11, 439, {1, 3, 3, 9, 29, 63, 9, 103, 489, 939, 1523}},
+{238, 11, 446, {1, 3, 7, 15, 7, 31, 89, 175, 369, 339, 595}},
+{239, 11, 451, {1, 3, 7, 13, 25, 5, 71, 207, 251, 367, 665}},
+{240, 11, 453, {1, 3, 3, 3, 21, 25, 75, 35, 31, 321, 1603}},
+{241, 11, 457, {1, 1, 1, 9, 11, 1, 65, 5, 11, 329, 535}},
+{242, 11, 458, {1, 1, 5, 3, 19, 13, 17, 43, 379, 485, 383}},
+{243, 11, 471, {1, 3, 5, 13, 13, 9, 85, 147, 489, 787, 1133}},
+{244, 11, 475, {1, 3, 1, 1, 5, 51, 37, 129, 195, 297, 1783}},
+{245, 11, 478, {1, 1, 3, 15, 19, 57, 59, 181, 455, 697, 2033}},
+{246, 11, 484, {1, 3, 7, 1, 27, 9, 65, 145, 325, 189, 201}},
+{247, 11, 493, {1, 3, 1, 15, 31, 23, 19, 5, 485, 581, 539}},
+{248, 11, 494, {1, 1, 7, 13, 11, 15, 65, 83, 185, 847, 831}},
+{249, 11, 499, {1, 3, 5, 7, 7, 55, 73, 15, 303, 511, 1905}},
+{250, 11, 502, {1, 3, 5, 9, 7, 21, 45, 15, 397, 385, 597}},
+{251, 11, 517, {1, 3, 7, 3, 23, 13, 73, 221, 511, 883, 1265}},
+{252, 11, 518, {1, 1, 3, 11, 1, 51, 73, 185, 33, 975, 1441}},
+{253, 11, 524, {1, 3, 3, 9, 19, 59, 21, 39, 339, 37, 143}},
+{254, 11, 527, {1, 1, 7, 1, 31, 33, 19, 167, 117, 635, 639}},
+{255, 11, 555, {1, 1, 1, 3, 5, 13, 59, 83, 355, 349, 1967}},
+{256, 11, 560, {1, 1, 1, 5, 19, 3, 53, 133, 97, 863, 983}},
+{257, 11, 565, {1, 3, 1, 13, 9, 41, 91, 105, 173, 97, 625}},
+{258, 11, 569, {1, 1, 5, 3, 7, 49, 115, 133, 71, 231, 1063}},
+{259, 11, 578, {1, 1, 7, 5, 17, 43, 47, 45, 497, 547, 757}},
+{260, 11, 580, {1, 3, 5, 15, 21, 61, 123, 191, 249, 31, 631}},
+{261, 11, 587, {1, 3, 7, 9, 17, 7, 11, 185, 127, 169, 1951}},
+{262, 11, 589, {1, 1, 5, 13, 11, 11, 9, 49, 29, 125, 791}},
+{263, 11, 590, {1, 1, 1, 15, 31, 41, 13, 167, 273, 429, 57}},
+{264, 11, 601, {1, 3, 5, 3, 27, 7, 35, 209, 65, 265, 1393}},
+{265, 11, 607, {1, 3, 1, 13, 31, 19, 53, 143, 135, 9, 1021}},
+{266, 11, 611, {1, 1, 7, 13, 31, 5, 115, 153, 143, 957, 623}},
+{267, 11, 614, {1, 1, 5, 11, 25, 19, 29, 31, 297, 943, 443}},
+{268, 11, 617, {1, 3, 3, 5, 21, 11, 127, 81, 479, 25, 699}},
+{269, 11, 618, {1, 1, 3, 11, 25, 31, 97, 19, 195, 781, 705}},
+{270, 11, 625, {1, 1, 5, 5, 31, 11, 75, 207, 197, 885, 2037}},
+{271, 11, 628, {1, 1, 1, 11, 9, 23, 29, 231, 307, 17, 1497}},
+{272, 11, 635, {1, 1, 5, 11, 11, 43, 111, 233, 307, 523, 1259}},
+{273, 11, 641, {1, 1, 7, 5, 1, 21, 107, 229, 343, 933, 217}},
+{274, 11, 647, {1, 1, 1, 11, 3, 21, 125, 131, 405, 599, 1469}},
+{275, 11, 654, {1, 3, 5, 5, 9, 39, 33, 81, 389, 151, 811}},
+{276, 11, 659, {1, 1, 7, 7, 7, 1, 59, 223, 265, 529, 2021}},
+{277, 11, 662, {1, 3, 1, 3, 9, 23, 85, 181, 47, 265, 49}},
+{278, 11, 672, {1, 3, 5, 11, 19, 23, 9, 7, 157, 299, 1983}},
+{279, 11, 675, {1, 3, 1, 5, 15, 5, 21, 105, 29, 339, 1041}},
+{280, 11, 682, {1, 1, 1, 1, 5, 33, 65, 85, 111, 705, 479}},
+{281, 11, 684, {1, 1, 1, 7, 9, 35, 77, 87, 151, 321, 101}},
+{282, 11, 689, {1, 1, 5, 7, 17, 1, 51, 197, 175, 811, 1229}},
+{283, 11, 695, {1, 3, 3, 15, 23, 37, 85, 185, 239, 543, 731}},
+{284, 11, 696, {1, 3, 1, 7, 7, 55, 111, 109, 289, 439, 243}},
+{285, 11, 713, {1, 1, 7, 11, 17, 53, 35, 217, 259, 853, 1667}},
+{286, 11, 719, {1, 3, 1, 9, 1, 63, 87, 17, 73, 565, 1091}},
+{287, 11, 724, {1, 1, 3, 3, 11, 41, 1, 57, 295, 263, 1029}},
+{288, 11, 733, {1, 1, 5, 1, 27, 45, 109, 161, 411, 421, 1395}},
+{289, 11, 734, {1, 3, 5, 11, 25, 35, 47, 191, 339, 417, 1727}},
+{290, 11, 740, {1, 1, 5, 15, 21, 1, 93, 251, 351, 217, 1767}},
+{291, 11, 747, {1, 3, 3, 11, 3, 7, 75, 155, 313, 211, 491}},
+{292, 11, 749, {1, 3, 3, 5, 11, 9, 101, 161, 453, 913, 1067}},
+{293, 11, 752, {1, 1, 3, 1, 15, 45, 127, 141, 163, 727, 1597}},
+{294, 11, 755, {1, 3, 3, 7, 1, 33, 63, 73, 73, 341, 1691}},
+{295, 11, 762, {1, 3, 5, 13, 15, 39, 53, 235, 77, 99, 949}},
+{296, 11, 770, {1, 1, 5, 13, 31, 17, 97, 13, 215, 301, 1927}},
+{297, 11, 782, {1, 1, 7, 1, 1, 37, 91, 93, 441, 251, 1131}},
+{298, 11, 784, {1, 3, 7, 9, 25, 5, 105, 69, 81, 943, 1459}},
+{299, 11, 787, {1, 3, 7, 11, 31, 43, 13, 209, 27, 1017, 501}},
+{300, 11, 789, {1, 1, 7, 15, 1, 33, 31, 233, 161, 507, 387}},
+{301, 11, 793, {1, 3, 3, 5, 5, 53, 33, 177, 503, 627, 1927}},
+{302, 11, 796, {1, 1, 7, 11, 7, 61, 119, 31, 457, 229, 1875}},
+{303, 11, 803, {1, 1, 5, 15, 19, 5, 53, 201, 157, 885, 1057}},
+{304, 11, 805, {1, 3, 7, 9, 1, 35, 51, 113, 249, 425, 1009}},
+{305, 11, 810, {1, 3, 5, 7, 21, 53, 37, 155, 119, 345, 631}},
+{306, 11, 815, {1, 3, 5, 7, 15, 31, 109, 69, 503, 595, 1879}},
+{307, 11, 824, {1, 3, 3, 1, 25, 35, 65, 131, 403, 705, 503}},
+{308, 11, 829, {1, 3, 7, 7, 19, 33, 11, 153, 45, 633, 499}},
+{309, 11, 830, {1, 3, 3, 5, 11, 3, 29, 93, 487, 33, 703}},
+{310, 11, 832, {1, 1, 3, 15, 21, 53, 107, 179, 387, 927, 1757}},
+{311, 11, 841, {1, 1, 3, 7, 21, 45, 51, 147, 175, 317, 361}},
+{312, 11, 847, {1, 1, 1, 7, 7, 13, 15, 243, 269, 795, 1965}},
+{313, 11, 849, {1, 1, 3, 5, 19, 33, 57, 115, 443, 537, 627}},
+{314, 11, 861, {1, 3, 3, 9, 3, 39, 25, 61, 185, 717, 1049}},
+{315, 11, 871, {1, 3, 7, 3, 7, 37, 107, 153, 7, 269, 1581}},
+{316, 11, 878, {1, 1, 7, 3, 7, 41, 91, 41, 145, 489, 1245}},
+{317, 11, 889, {1, 1, 5, 9, 7, 7, 105, 81, 403, 407, 283}},
+{318, 11, 892, {1, 1, 7, 9, 27, 55, 29, 77, 193, 963, 949}},
+{319, 11, 901, {1, 1, 5, 3, 25, 51, 107, 63, 403, 917, 815}},
+{320, 11, 908, {1, 1, 7, 3, 7, 61, 19, 51, 457, 599, 535}},
+{321, 11, 920, {1, 3, 7, 1, 23, 51, 105, 153, 239, 215, 1847}},
+{322, 11, 923, {1, 1, 3, 5, 27, 23, 79, 49, 495, 45, 1935}},
+{323, 11, 942, {1, 1, 1, 11, 11, 47, 55, 133, 495, 999, 1461}},
+{324, 11, 949, {1, 1, 3, 15, 27, 51, 93, 17, 355, 763, 1675}},
+{325, 11, 950, {1, 3, 1, 3, 1, 3, 79, 119, 499, 17, 995}},
+{326, 11, 954, {1, 1, 1, 1, 15, 43, 45, 17, 167, 973, 799}},
+{327, 11, 961, {1, 1, 1, 3, 27, 49, 89, 29, 483, 913, 2023}},
+{328, 11, 968, {1, 1, 3, 3, 5, 11, 75, 7, 41, 851, 611}},
+{329, 11, 971, {1, 3, 1, 3, 7, 57, 39, 123, 257, 283, 507}},
+{330, 11, 973, {1, 3, 3, 11, 27, 23, 113, 229, 187, 299, 133}},
+{331, 11, 979, {1, 1, 3, 13, 9, 63, 101, 77, 451, 169, 337}},
+{332, 11, 982, {1, 3, 7, 3, 3, 59, 45, 195, 229, 415, 409}},
+{333, 11, 986, {1, 3, 5, 3, 11, 19, 71, 93, 43, 857, 369}},
+{334, 11, 998, {1, 3, 7, 9, 19, 33, 115, 19, 241, 703, 247}},
+{335, 11, 1001, {1, 3, 5, 11, 5, 35, 21, 155, 463, 1005, 1073}},
+{336, 11, 1010, {1, 3, 7, 3, 25, 15, 109, 83, 93, 69, 1189}},
+{337, 11, 1012, {1, 3, 5, 7, 5, 21, 93, 133, 135, 167, 903}},
+{338, 12, 41, {1, 1, 7, 7, 3, 59, 121, 161, 285, 815, 1769, 3705}},
+{339, 12, 52, {1, 3, 1, 1, 3, 47, 103, 171, 381, 609, 185, 373}},
+{340, 12, 61, {1, 3, 3, 15, 23, 33, 107, 131, 441, 445, 689, 2059}},
+{341, 12, 62, {1, 3, 3, 11, 7, 53, 101, 167, 435, 803, 1255, 3781}},
+{342, 12, 76, {1, 1, 5, 11, 15, 59, 41, 19, 135, 835, 1263, 505}},
+{343, 12, 104, {1, 1, 7, 11, 21, 49, 23, 219, 127, 961, 1065, 385}},
+{344, 12, 117, {1, 3, 5, 15, 7, 47, 117, 217, 45, 731, 1639, 733}},
+{345, 12, 131, {1, 1, 7, 11, 27, 57, 91, 87, 81, 35, 1269, 1007}},
+{346, 12, 143, {1, 1, 3, 11, 15, 37, 53, 219, 193, 937, 1899, 3733}},
+{347, 12, 145, {1, 3, 5, 3, 13, 11, 27, 19, 199, 393, 965, 2195}},
+{348, 12, 157, {1, 3, 1, 3, 5, 1, 37, 173, 413, 1023, 553, 409}},
+{349, 12, 167, {1, 3, 1, 7, 15, 29, 123, 95, 255, 373, 1799, 3841}},
+{350, 12, 171, {1, 3, 5, 13, 21, 57, 51, 17, 511, 195, 1157, 1831}},
+{351, 12, 176, {1, 1, 1, 15, 29, 19, 7, 73, 295, 519, 587, 3523}},
+{352, 12, 181, {1, 1, 5, 13, 13, 35, 115, 191, 123, 535, 717, 1661}},
+{353, 12, 194, {1, 3, 3, 5, 23, 21, 47, 251, 379, 921, 1119, 297}},
+{354, 12, 217, {1, 3, 3, 9, 29, 53, 121, 201, 135, 193, 523, 2943}},
+{355, 12, 236, {1, 1, 1, 7, 29, 45, 125, 9, 99, 867, 425, 601}},
+{356, 12, 239, {1, 3, 1, 9, 13, 15, 67, 181, 109, 293, 1305, 3079}},
+{357, 12, 262, {1, 3, 3, 9, 5, 35, 15, 209, 305, 87, 767, 2795}},
+{358, 12, 283, {1, 3, 3, 11, 27, 57, 113, 123, 179, 643, 149, 523}},
+{359, 12, 286, {1, 1, 3, 15, 11, 17, 67, 223, 63, 657, 335, 3309}},
+{360, 12, 307, {1, 1, 1, 9, 25, 29, 109, 159, 39, 513, 571, 1761}},
+{361, 12, 313, {1, 1, 3, 1, 5, 63, 75, 19, 455, 601, 123, 691}},
+{362, 12, 319, {1, 1, 1, 3, 21, 5, 45, 169, 377, 513, 1951, 2565}},
+{363, 12, 348, {1, 1, 3, 11, 3, 33, 119, 69, 253, 907, 805, 1449}},
+{364, 12, 352, {1, 1, 5, 13, 31, 15, 17, 7, 499, 61, 687, 1867}},
+{365, 12, 357, {1, 3, 7, 11, 17, 33, 73, 77, 299, 243, 641, 2345}},
+{366, 12, 391, {1, 1, 7, 11, 9, 35, 31, 235, 359, 647, 379, 1161}},
+{367, 12, 398, {1, 3, 3, 15, 31, 25, 5, 67, 33, 45, 437, 4067}},
+{368, 12, 400, {1, 1, 3, 11, 7, 17, 37, 87, 333, 253, 1517, 2921}},
+{369, 12, 412, {1, 1, 7, 15, 7, 15, 107, 189, 153, 769, 1521, 3427}},
+{370, 12, 415, {1, 3, 5, 13, 5, 61, 113, 37, 293, 393, 113, 43}},
+{371, 12, 422, {1, 1, 1, 15, 29, 43, 107, 31, 167, 147, 301, 1021}},
+{372, 12, 440, {1, 1, 1, 13, 3, 1, 35, 93, 195, 181, 2027, 1491}},
+{373, 12, 460, {1, 3, 3, 3, 13, 33, 77, 199, 153, 221, 1699, 3671}},
+{374, 12, 465, {1, 3, 5, 13, 7, 49, 123, 155, 495, 681, 819, 809}},
+{375, 12, 468, {1, 3, 5, 15, 27, 61, 117, 189, 183, 887, 617, 4053}},
+{376, 12, 515, {1, 1, 1, 7, 31, 59, 125, 235, 389, 369, 447, 1039}},
+{377, 12, 536, {1, 3, 5, 1, 5, 39, 115, 89, 249, 377, 431, 3747}},
+{378, 12, 539, {1, 1, 1, 5, 7, 47, 59, 157, 77, 445, 699, 3439}},
+{379, 12, 551, {1, 1, 3, 5, 11, 21, 19, 75, 11, 599, 1575, 735}},
+{380, 12, 558, {1, 3, 5, 3, 19, 13, 41, 69, 199, 143, 1761, 3215}},
+{381, 12, 563, {1, 3, 5, 7, 19, 43, 25, 41, 41, 11, 1647, 2783}},
+{382, 12, 570, {1, 3, 1, 9, 19, 45, 111, 97, 405, 399, 457, 3219}},
+{383, 12, 595, {1, 1, 3, 1, 23, 15, 65, 121, 59, 985, 829, 2259}},
+{384, 12, 598, {1, 1, 3, 7, 17, 13, 107, 229, 75, 551, 1299, 2363}},
+{385, 12, 617, {1, 1, 5, 5, 21, 57, 23, 199, 509, 139, 2007, 3875}},
+{386, 12, 647, {1, 3, 1, 11, 19, 53, 15, 229, 215, 741, 695, 823}},
+{387, 12, 654, {1, 3, 7, 1, 29, 3, 17, 163, 417, 559, 549, 319}},
+{388, 12, 678, {1, 3, 1, 13, 17, 9, 47, 133, 365, 7, 1937, 1071}},
+{389, 12, 713, {1, 3, 5, 7, 19, 37, 55, 163, 301, 249, 689, 2327}},
+{390, 12, 738, {1, 3, 5, 13, 11, 23, 61, 205, 257, 377, 615, 1457}},
+{391, 12, 747, {1, 3, 5, 1, 23, 37, 13, 75, 331, 495, 579, 3367}},
+{392, 12, 750, {1, 1, 1, 9, 1, 23, 49, 129, 475, 543, 883, 2531}},
+{393, 12, 757, {1, 3, 1, 5, 23, 59, 51, 35, 343, 695, 219, 369}},
+{394, 12, 772, {1, 3, 3, 1, 27, 17, 63, 97, 71, 507, 1929, 613}},
+{395, 12, 803, {1, 1, 5, 1, 21, 31, 11, 109, 247, 409, 1817, 2173}},
+{396, 12, 810, {1, 1, 3, 15, 23, 9, 7, 209, 301, 23, 147, 1691}},
+{397, 12, 812, {1, 1, 7, 5, 5, 19, 37, 229, 249, 277, 1115, 2309}},
+{398, 12, 850, {1, 1, 1, 5, 5, 63, 5, 249, 285, 431, 343, 2467}},
+{399, 12, 862, {1, 1, 1, 11, 7, 45, 35, 75, 505, 537, 29, 2919}},
+{400, 12, 906, {1, 3, 5, 15, 11, 39, 15, 63, 263, 9, 199, 445}},
+{401, 12, 908, {1, 3, 3, 3, 27, 63, 53, 171, 227, 63, 1049, 827}},
+{402, 12, 929, {1, 1, 3, 13, 7, 11, 115, 183, 179, 937, 1785, 381}},
+{403, 12, 930, {1, 3, 1, 11, 13, 15, 107, 81, 53, 295, 1785, 3757}},
+{404, 12, 954, {1, 3, 3, 13, 11, 5, 109, 243, 3, 505, 323, 1373}},
+{405, 12, 964, {1, 3, 3, 11, 21, 51, 17, 177, 381, 937, 1263, 3889}},
+{406, 12, 982, {1, 3, 5, 9, 27, 25, 85, 193, 143, 573, 1189, 2995}},
+{407, 12, 985, {1, 3, 5, 11, 13, 9, 81, 21, 159, 953, 91, 1751}},
+{408, 12, 991, {1, 1, 3, 3, 27, 61, 11, 253, 391, 333, 1105, 635}},
+{409, 12, 992, {1, 3, 3, 15, 9, 57, 95, 81, 419, 735, 251, 1141}},
+{410, 12, 1067, {1, 1, 5, 9, 31, 39, 59, 13, 319, 807, 1241, 2433}},
+{411, 12, 1070, {1, 3, 3, 5, 27, 13, 107, 141, 423, 937, 2027, 3233}},
+{412, 12, 1096, {1, 3, 3, 9, 9, 25, 125, 23, 443, 835, 1245, 847}},
+{413, 12, 1099, {1, 1, 7, 15, 17, 17, 83, 107, 411, 285, 847, 1571}},
+{414, 12, 1116, {1, 1, 3, 13, 29, 61, 37, 81, 349, 727, 1453, 1957}},
+{415, 12, 1143, {1, 3, 7, 11, 31, 13, 59, 77, 273, 591, 1265, 1533}},
+{416, 12, 1165, {1, 1, 7, 7, 13, 17, 25, 25, 187, 329, 347, 1473}},
+{417, 12, 1178, {1, 3, 7, 7, 5, 51, 37, 99, 221, 153, 503, 2583}},
+{418, 12, 1184, {1, 3, 1, 13, 19, 27, 11, 69, 181, 479, 1183, 3229}},
+{419, 12, 1202, {1, 3, 3, 13, 23, 21, 103, 147, 323, 909, 947, 315}},
+{420, 12, 1213, {1, 3, 1, 3, 23, 1, 31, 59, 93, 513, 45, 2271}},
+{421, 12, 1221, {1, 3, 5, 1, 7, 43, 109, 59, 231, 41, 1515, 2385}},
+{422, 12, 1240, {1, 3, 1, 5, 31, 57, 49, 223, 283, 1013, 11, 701}},
+{423, 12, 1246, {1, 1, 5, 1, 19, 53, 55, 31, 31, 299, 495, 693}},
+{424, 12, 1252, {1, 3, 3, 9, 5, 33, 77, 253, 427, 791, 731, 1019}},
+{425, 12, 1255, {1, 3, 7, 11, 1, 9, 119, 203, 53, 877, 1707, 3499}},
+{426, 12, 1267, {1, 1, 3, 7, 13, 39, 55, 159, 423, 113, 1653, 3455}},
+{427, 12, 1293, {1, 1, 3, 5, 21, 47, 51, 59, 55, 411, 931, 251}},
+{428, 12, 1301, {1, 3, 7, 3, 31, 25, 81, 115, 405, 239, 741, 455}},
+{429, 12, 1305, {1, 1, 5, 1, 31, 3, 101, 83, 479, 491, 1779, 2225}},
+{430, 12, 1332, {1, 3, 3, 3, 9, 37, 107, 161, 203, 503, 767, 3435}},
+{431, 12, 1349, {1, 3, 7, 9, 1, 27, 61, 119, 233, 39, 1375, 4089}},
+{432, 12, 1384, {1, 1, 5, 9, 1, 31, 45, 51, 369, 587, 383, 2813}},
+{433, 12, 1392, {1, 3, 7, 5, 31, 7, 49, 119, 487, 591, 1627, 53}},
+{434, 12, 1402, {1, 1, 7, 1, 9, 47, 1, 223, 369, 711, 1603, 1917}},
+{435, 12, 1413, {1, 3, 5, 3, 21, 37, 111, 17, 483, 739, 1193, 2775}},
+{436, 12, 1417, {1, 3, 3, 7, 17, 11, 51, 117, 455, 191, 1493, 3821}},
+{437, 12, 1423, {1, 1, 5, 9, 23, 39, 99, 181, 343, 485, 99, 1931}},
+{438, 12, 1451, {1, 3, 1, 7, 29, 49, 31, 71, 489, 527, 1763, 2909}},
+{439, 12, 1480, {1, 1, 5, 11, 5, 5, 73, 189, 321, 57, 1191, 3685}},
+{440, 12, 1491, {1, 1, 5, 15, 13, 45, 125, 207, 371, 415, 315, 983}},
+{441, 12, 1503, {1, 3, 3, 5, 25, 59, 33, 31, 239, 919, 1859, 2709}},
+{442, 12, 1504, {1, 3, 5, 13, 27, 61, 23, 115, 61, 413, 1275, 3559}},
+{443, 12, 1513, {1, 3, 7, 15, 5, 59, 101, 81, 47, 967, 809, 3189}},
+{444, 12, 1538, {1, 1, 5, 11, 31, 15, 39, 25, 173, 505, 809, 2677}},
+{445, 12, 1544, {1, 1, 5, 9, 19, 13, 95, 89, 511, 127, 1395, 2935}},
+{446, 12, 1547, {1, 1, 5, 5, 31, 45, 9, 57, 91, 303, 1295, 3215}},
+{447, 12, 1555, {1, 3, 3, 3, 19, 15, 113, 187, 217, 489, 1285, 1803}},
+{448, 12, 1574, {1, 1, 3, 1, 13, 29, 57, 139, 255, 197, 537, 2183}},
+{449, 12, 1603, {1, 3, 1, 15, 11, 7, 53, 255, 467, 9, 757, 3167}},
+{450, 12, 1615, {1, 3, 3, 15, 21, 13, 9, 189, 359, 323, 49, 333}},
+{451, 12, 1618, {1, 3, 7, 11, 7, 37, 21, 119, 401, 157, 1659, 1069}},
+{452, 12, 1629, {1, 1, 5, 7, 17, 33, 115, 229, 149, 151, 2027, 279}},
+{453, 12, 1634, {1, 1, 5, 15, 5, 49, 77, 155, 383, 385, 1985, 945}},
+{454, 12, 1636, {1, 3, 7, 3, 7, 55, 85, 41, 357, 527, 1715, 1619}},
+{455, 12, 1639, {1, 1, 3, 1, 21, 45, 115, 21, 199, 967, 1581, 3807}},
+{456, 12, 1657, {1, 1, 3, 7, 21, 39, 117, 191, 169, 73, 413, 3417}},
+{457, 12, 1667, {1, 1, 1, 13, 1, 31, 57, 195, 231, 321, 367, 1027}},
+{458, 12, 1681, {1, 3, 7, 3, 11, 29, 47, 161, 71, 419, 1721, 437}},
+{459, 12, 1697, {1, 1, 7, 3, 11, 9, 43, 65, 157, 1, 1851, 823}},
+{460, 12, 1704, {1, 1, 1, 5, 21, 15, 31, 101, 293, 299, 127, 1321}},
+{461, 12, 1709, {1, 1, 7, 1, 27, 1, 11, 229, 241, 705, 43, 1475}},
+{462, 12, 1722, {1, 3, 7, 1, 5, 15, 73, 183, 193, 55, 1345, 49}},
+{463, 12, 1730, {1, 3, 3, 3, 19, 3, 55, 21, 169, 663, 1675, 137}},
+{464, 12, 1732, {1, 1, 1, 13, 7, 21, 69, 67, 373, 965, 1273, 2279}},
+{465, 12, 1802, {1, 1, 7, 7, 21, 23, 17, 43, 341, 845, 465, 3355}},
+{466, 12, 1804, {1, 3, 5, 5, 25, 5, 81, 101, 233, 139, 359, 2057}},
+{467, 12, 1815, {1, 1, 3, 11, 15, 39, 55, 3, 471, 765, 1143, 3941}},
+{468, 12, 1826, {1, 1, 7, 15, 9, 57, 81, 79, 215, 433, 333, 3855}},
+{469, 12, 1832, {1, 1, 5, 5, 19, 45, 83, 31, 209, 363, 701, 1303}},
+{470, 12, 1843, {1, 3, 7, 5, 1, 13, 55, 163, 435, 807, 287, 2031}},
+{471, 12, 1849, {1, 3, 3, 7, 3, 3, 17, 197, 39, 169, 489, 1769}},
+{472, 12, 1863, {1, 1, 3, 5, 29, 43, 87, 161, 289, 339, 1233, 2353}},
+{473, 12, 1905, {1, 3, 3, 9, 21, 9, 77, 1, 453, 167, 1643, 2227}},
+{474, 12, 1928, {1, 1, 7, 1, 15, 7, 67, 33, 193, 241, 1031, 2339}},
+{475, 12, 1933, {1, 3, 1, 11, 1, 63, 45, 65, 265, 661, 849, 1979}},
+{476, 12, 1939, {1, 3, 1, 13, 19, 49, 3, 11, 159, 213, 659, 2839}},
+{477, 12, 1976, {1, 3, 5, 11, 9, 29, 27, 227, 253, 449, 1403, 3427}},
+{478, 12, 1996, {1, 1, 3, 1, 7, 3, 77, 143, 277, 779, 1499, 475}},
+{479, 12, 2013, {1, 1, 1, 5, 11, 23, 87, 131, 393, 849, 193, 3189}},
+{480, 12, 2014, {1, 3, 5, 11, 3, 3, 89, 9, 449, 243, 1501, 1739}},
+{481, 12, 2020, {1, 3, 1, 9, 29, 29, 113, 15, 65, 611, 135, 3687}},
+{482, 13, 13, {1, 1, 1, 9, 21, 19, 39, 151, 395, 501, 1339, 959, 2725}},
+{483, 13, 19, {1, 3, 7, 1, 7, 35, 45, 33, 119, 225, 1631, 1695, 1459}},
+{484, 13, 26, {1, 1, 1, 3, 25, 55, 37, 79, 167, 907, 1075, 271, 4059}},
+{485, 13, 41, {1, 3, 5, 13, 5, 13, 53, 165, 437, 67, 1705, 3177, 8095}},
+{486, 13, 50, {1, 3, 3, 13, 27, 57, 95, 55, 443, 245, 1945, 1725, 1929}},
+{487, 13, 55, {1, 3, 1, 9, 5, 33, 109, 35, 99, 827, 341, 2401, 2411}},
+{488, 13, 69, {1, 1, 5, 9, 7, 33, 43, 39, 87, 799, 635, 3481, 7159}},
+{489, 13, 70, {1, 3, 1, 1, 31, 15, 45, 27, 337, 113, 987, 2065, 2529}},
+{490, 13, 79, {1, 1, 5, 9, 5, 15, 105, 123, 479, 289, 1609, 2177, 4629}},
+{491, 13, 82, {1, 3, 5, 11, 31, 47, 97, 87, 385, 195, 1041, 651, 3271}},
+{492, 13, 87, {1, 1, 3, 7, 17, 3, 101, 55, 87, 629, 1687, 1387, 2745}},
+{493, 13, 93, {1, 3, 5, 5, 7, 21, 9, 237, 313, 549, 1107, 117, 6183}},
+{494, 13, 94, {1, 1, 3, 9, 9, 5, 55, 201, 487, 851, 1103, 2993, 4055}},
+{495, 13, 97, {1, 1, 5, 9, 31, 19, 59, 7, 363, 381, 1167, 2057, 5715}},
+{496, 13, 100, {1, 3, 3, 15, 23, 63, 19, 227, 387, 827, 487, 1049, 7471}},
+{497, 13, 112, {1, 3, 1, 5, 23, 25, 61, 245, 363, 863, 963, 3583, 6475}},
+{498, 13, 121, {1, 1, 5, 1, 5, 27, 81, 85, 275, 49, 235, 3291, 1195}},
+{499, 13, 134, {1, 1, 5, 7, 23, 53, 85, 107, 511, 779, 1265, 1093, 7859}},
+{500, 13, 138, {1, 3, 3, 1, 9, 21, 75, 219, 59, 485, 1739, 3845, 1109}},
+{501, 13, 148, {1, 3, 5, 1, 13, 41, 19, 143, 293, 391, 2023, 1791, 4399}},
+{502, 13, 151, {1, 3, 7, 15, 21, 13, 21, 195, 215, 413, 523, 2099, 2341}},
+{503, 13, 157, {1, 1, 1, 3, 29, 51, 47, 57, 135, 575, 943, 1673, 541}},
+{504, 13, 161, {1, 3, 5, 1, 9, 13, 113, 175, 447, 115, 657, 4077, 5973}},
+{505, 13, 179, {1, 1, 1, 11, 17, 41, 37, 95, 297, 579, 911, 2207, 2387}},
+{506, 13, 181, {1, 3, 5, 3, 23, 11, 23, 231, 93, 667, 711, 1563, 7961}},
+{507, 13, 188, {1, 1, 7, 3, 17, 59, 13, 181, 141, 991, 1817, 457, 1711}},
+{508, 13, 196, {1, 3, 3, 5, 31, 59, 81, 205, 245, 537, 1049, 997, 1815}},
+{509, 13, 203, {1, 3, 7, 5, 17, 13, 9, 79, 17, 185, 5, 2211, 6263}},
+{510, 13, 206, {1, 3, 7, 13, 7, 53, 61, 145, 13, 285, 1203, 947, 2933}},
+{511, 13, 223, {1, 1, 7, 3, 31, 19, 69, 217, 47, 441, 1893, 673, 4451}},
+{512, 13, 224, {1, 1, 1, 1, 25, 9, 23, 225, 385, 629, 603, 3747, 4241}},
+{513, 13, 227, {1, 3, 1, 9, 5, 37, 31, 237, 431, 79, 1521, 459, 2523}},
+{514, 13, 230, {1, 3, 7, 3, 9, 43, 105, 179, 5, 225, 799, 1777, 4893}},
+{515, 13, 239, {1, 1, 3, 1, 29, 45, 29, 159, 267, 247, 455, 847, 3909}},
+{516, 13, 241, {1, 1, 3, 7, 25, 21, 121, 57, 467, 275, 719, 1521, 7319}},
+{517, 13, 248, {1, 3, 1, 3, 11, 35, 119, 123, 81, 979, 1187, 3623, 4293}},
+{518, 13, 253, {1, 1, 1, 7, 15, 25, 121, 235, 25, 487, 873, 1787, 1977}},
+{519, 13, 268, {1, 1, 1, 11, 3, 7, 17, 135, 345, 353, 383, 4011, 2573}},
+{520, 13, 274, {1, 3, 7, 15, 27, 13, 97, 123, 65, 675, 951, 1285, 6559}},
+{521, 13, 283, {1, 3, 7, 3, 7, 1, 71, 19, 325, 765, 337, 1197, 2697}},
+{522, 13, 286, {1, 3, 5, 1, 31, 37, 11, 71, 169, 283, 83, 3801, 7083}},
+{523, 13, 289, {1, 1, 3, 15, 17, 29, 83, 65, 275, 679, 1749, 4007, 7749}},
+{524, 13, 301, {1, 1, 3, 1, 21, 11, 41, 95, 237, 361, 1819, 2783, 2383}},
+{525, 13, 302, {1, 3, 7, 11, 29, 57, 111, 187, 465, 145, 605, 1987, 8109}},
+{526, 13, 316, {1, 1, 3, 3, 19, 15, 55, 83, 357, 1001, 643, 1517, 6529}},
+{527, 13, 319, {1, 3, 1, 5, 29, 35, 73, 23, 77, 619, 1523, 1725, 8145}},
+{528, 13, 324, {1, 1, 5, 5, 19, 23, 7, 197, 449, 337, 717, 2921, 315}},
+{529, 13, 331, {1, 3, 5, 9, 7, 63, 117, 97, 97, 813, 1925, 2817, 1579}},
+{530, 13, 333, {1, 1, 1, 11, 31, 7, 25, 235, 231, 133, 1007, 1371, 1553}},
+{531, 13, 345, {1, 1, 7, 5, 19, 7, 47, 171, 267, 243, 1331, 567, 6033}},
+{532, 13, 351, {1, 1, 5, 1, 7, 49, 55, 89, 109, 735, 1455, 3193, 6239}},
+{533, 13, 358, {1, 1, 1, 7, 1, 61, 9, 103, 3, 929, 1481, 2927, 2957}},
+{534, 13, 375, {1, 1, 5, 13, 17, 21, 75, 49, 255, 1019, 1161, 2133, 1177}},
+{535, 13, 379, {1, 3, 1, 3, 13, 15, 41, 247, 211, 409, 1163, 523, 2635}},
+{536, 13, 381, {1, 3, 7, 7, 21, 59, 91, 149, 479, 391, 681, 2311, 6249}},
+{537, 13, 386, {1, 1, 5, 11, 27, 53, 21, 211, 197, 815, 719, 1605, 255}},
+{538, 13, 403, {1, 1, 3, 3, 9, 33, 59, 3, 323, 1, 101, 1135, 8105}},
+{539, 13, 405, {1, 3, 3, 1, 29, 5, 17, 141, 51, 991, 841, 327, 3859}},
+{540, 13, 419, {1, 3, 1, 5, 11, 19, 23, 89, 175, 173, 165, 2881, 1881}},
+{541, 13, 426, {1, 1, 1, 15, 13, 51, 87, 39, 495, 611, 1341, 1531, 7029}},
+{542, 13, 428, {1, 1, 3, 11, 13, 55, 75, 185, 57, 61, 1917, 2051, 5965}},
+{543, 13, 439, {1, 1, 5, 5, 7, 53, 11, 217, 213, 933, 921, 3607, 5175}},
+{544, 13, 440, {1, 3, 3, 5, 17, 53, 103, 251, 369, 781, 1319, 3717, 4439}},
+{545, 13, 446, {1, 3, 5, 13, 1, 39, 25, 235, 321, 773, 251, 3111, 6397}},
+{546, 13, 451, {1, 1, 7, 3, 31, 5, 25, 29, 325, 385, 1313, 127, 4705}},
+{547, 13, 454, {1, 1, 5, 15, 15, 27, 15, 85, 239, 243, 1633, 3473, 2621}},
+{548, 13, 458, {1, 3, 3, 3, 9, 19, 113, 13, 137, 165, 25, 2957, 7549}},
+{549, 13, 465, {1, 3, 1, 3, 11, 21, 3, 97, 417, 183, 1205, 1437, 247}},
+{550, 13, 468, {1, 1, 7, 3, 17, 21, 125, 55, 67, 387, 385, 2323, 887}},
+{551, 13, 472, {1, 3, 5, 5, 29, 11, 103, 223, 233, 641, 133, 415, 1297}},
+{552, 13, 475, {1, 3, 3, 11, 1, 9, 5, 189, 235, 1007, 1363, 3985, 889}},
+{553, 13, 477, {1, 3, 7, 9, 23, 19, 19, 183, 269, 403, 1643, 3559, 5189}},
+{554, 13, 496, {1, 3, 7, 3, 29, 45, 17, 69, 475, 149, 1291, 2689, 7625}},
+{555, 13, 502, {1, 3, 7, 3, 27, 37, 41, 73, 253, 1001, 431, 1111, 7887}},
+{556, 13, 508, {1, 1, 7, 5, 3, 7, 87, 143, 289, 495, 631, 3011, 6151}},
+{557, 13, 517, {1, 1, 1, 13, 5, 45, 17, 167, 23, 975, 801, 1975, 6833}},
+{558, 13, 521, {1, 3, 1, 11, 7, 21, 39, 23, 213, 429, 1301, 2059, 197}},
+{559, 13, 527, {1, 3, 3, 15, 3, 57, 121, 133, 29, 711, 1961, 2497, 189}},
+{560, 13, 530, {1, 1, 3, 5, 11, 55, 115, 137, 233, 673, 985, 2849, 5911}},
+{561, 13, 532, {1, 1, 7, 15, 29, 45, 1, 241, 329, 323, 925, 2821, 3331}},
+{562, 13, 542, {1, 1, 5, 7, 13, 31, 81, 105, 199, 145, 195, 1365, 5119}},
+{563, 13, 552, {1, 3, 7, 11, 3, 55, 11, 31, 117, 343, 1265, 1837, 2451}},
+{564, 13, 555, {1, 1, 3, 7, 29, 57, 61, 179, 429, 591, 177, 1945, 2159}},
+{565, 13, 560, {1, 3, 5, 11, 23, 49, 101, 137, 339, 323, 1035, 1749, 7737}},
+{566, 13, 566, {1, 3, 1, 13, 21, 35, 55, 79, 19, 269, 1055, 2651, 7083}},
+{567, 13, 575, {1, 3, 3, 11, 9, 9, 95, 167, 437, 361, 1185, 4083, 603}},
+{568, 13, 577, {1, 1, 1, 7, 31, 61, 77, 65, 489, 657, 691, 2423, 4147}},
+{569, 13, 589, {1, 3, 5, 7, 21, 37, 87, 191, 311, 453, 2013, 829, 2619}},
+{570, 13, 590, {1, 1, 5, 9, 17, 47, 35, 101, 5, 813, 1157, 1279, 7365}},
+{571, 13, 602, {1, 1, 5, 3, 11, 35, 113, 199, 369, 721, 901, 1471, 7801}},
+{572, 13, 607, {1, 3, 1, 5, 9, 61, 83, 157, 391, 739, 1957, 2123, 4341}},
+{573, 13, 608, {1, 3, 5, 11, 19, 19, 111, 225, 383, 219, 997, 717, 7505}},
+{574, 13, 611, {1, 3, 1, 11, 13, 63, 35, 127, 209, 831, 501, 3017, 3507}},
+{575, 13, 613, {1, 3, 7, 9, 29, 7, 11, 163, 81, 563, 1445, 3215, 6377}},
+{576, 13, 625, {1, 3, 7, 11, 25, 3, 39, 195, 491, 45, 839, 4021, 4899}},
+{577, 13, 644, {1, 3, 7, 15, 13, 5, 67, 143, 117, 505, 1281, 3679, 5695}},
+{578, 13, 651, {1, 3, 7, 9, 9, 19, 21, 221, 147, 763, 683, 2211, 589}},
+{579, 13, 654, {1, 1, 3, 5, 21, 47, 53, 109, 299, 807, 1153, 1209, 7961}},
+{580, 13, 656, {1, 3, 7, 11, 9, 31, 45, 43, 505, 647, 1127, 2681, 4917}},
+{581, 13, 662, {1, 1, 5, 15, 31, 41, 63, 113, 399, 727, 673, 2587, 5259}},
+{582, 13, 668, {1, 1, 1, 13, 17, 53, 35, 99, 57, 243, 1447, 1919, 2831}},
+{583, 13, 681, {1, 3, 7, 11, 23, 51, 13, 9, 49, 449, 997, 3073, 4407}},
+{584, 13, 682, {1, 3, 5, 7, 23, 33, 89, 41, 415, 53, 697, 1113, 1489}},
+{585, 13, 689, {1, 1, 3, 7, 1, 13, 29, 13, 255, 749, 77, 3463, 1761}},
+{586, 13, 696, {1, 3, 3, 7, 13, 15, 93, 191, 309, 869, 739, 1041, 3053}},
+{587, 13, 699, {1, 3, 5, 13, 5, 19, 109, 211, 347, 839, 893, 2947, 7735}},
+{588, 13, 707, {1, 3, 1, 13, 27, 3, 119, 157, 485, 99, 1703, 3895, 573}},
+{589, 13, 709, {1, 3, 7, 11, 1, 23, 123, 105, 31, 359, 275, 1775, 3685}},
+{590, 13, 714, {1, 3, 3, 5, 27, 11, 125, 3, 413, 199, 2043, 2895, 2945}},
+{591, 13, 716, {1, 3, 3, 3, 15, 49, 121, 159, 233, 543, 193, 4007, 321}},
+{592, 13, 719, {1, 1, 3, 5, 9, 47, 87, 1, 51, 1011, 1595, 2239, 6467}},
+{593, 13, 727, {1, 3, 7, 9, 1, 33, 87, 137, 469, 749, 1413, 805, 6817}},
+{594, 13, 734, {1, 3, 1, 13, 19, 45, 95, 227, 29, 677, 1275, 3395, 4451}},
+{595, 13, 738, {1, 1, 7, 5, 7, 63, 33, 71, 443, 561, 1311, 3069, 6943}},
+{596, 13, 743, {1, 1, 1, 13, 9, 37, 23, 69, 13, 415, 1479, 1197, 861}},
+{597, 13, 747, {1, 3, 3, 13, 27, 21, 13, 233, 105, 777, 345, 2443, 1105}},
+{598, 13, 757, {1, 1, 7, 11, 23, 13, 21, 147, 221, 549, 73, 2729, 6279}},
+{599, 13, 769, {1, 1, 7, 7, 25, 27, 15, 45, 227, 39, 75, 1191, 3563}},
+{600, 13, 770, {1, 1, 5, 7, 13, 49, 99, 167, 227, 13, 353, 1047, 8075}},
+{601, 13, 776, {1, 1, 3, 13, 31, 9, 27, 7, 461, 737, 1559, 3243, 53}},
+{602, 13, 790, {1, 3, 1, 1, 21, 41, 97, 165, 171, 821, 587, 2137, 2293}},
+{603, 13, 799, {1, 3, 1, 11, 17, 41, 29, 187, 87, 599, 1467, 1395, 5931}},
+{604, 13, 805, {1, 1, 1, 9, 9, 49, 89, 205, 409, 453, 61, 1923, 1257}},
+{605, 13, 809, {1, 3, 7, 3, 9, 43, 89, 143, 431, 83, 1243, 1795, 3599}},
+{606, 13, 812, {1, 3, 5, 13, 3, 25, 59, 219, 43, 223, 797, 2651, 6015}},
+{607, 13, 820, {1, 1, 5, 15, 7, 55, 65, 207, 213, 311, 1287, 1269, 6467}},
+{608, 13, 827, {1, 3, 7, 11, 21, 57, 31, 183, 351, 857, 911, 1683, 7155}},
+{609, 13, 829, {1, 3, 5, 11, 27, 1, 21, 47, 387, 383, 1593, 115, 3805}},
+{610, 13, 835, {1, 3, 1, 1, 13, 23, 87, 173, 181, 619, 1653, 3931, 6073}},
+{611, 13, 841, {1, 1, 7, 5, 17, 43, 37, 61, 307, 621, 1785, 55, 115}},
+{612, 13, 844, {1, 3, 7, 15, 25, 61, 123, 15, 237, 671, 1473, 467, 1907}},
+{613, 13, 856, {1, 1, 7, 5, 29, 57, 75, 237, 85, 699, 159, 3577, 4771}},
+{614, 13, 859, {1, 1, 1, 11, 25, 19, 51, 1, 147, 31, 895, 2617, 625}},
+{615, 13, 862, {1, 3, 7, 5, 29, 15, 115, 175, 395, 391, 1141, 1827, 1181}},
+{616, 13, 865, {1, 3, 5, 7, 17, 7, 11, 193, 89, 243, 561, 3787, 4551}},
+{617, 13, 885, {1, 3, 1, 11, 7, 57, 7, 125, 403, 947, 1261, 409, 8083}},
+{618, 13, 890, {1, 1, 5, 13, 21, 63, 115, 233, 231, 921, 1747, 3635, 2519}},
+{619, 13, 905, {1, 1, 5, 11, 3, 27, 15, 91, 505, 591, 1451, 3881, 2997}},
+{620, 13, 916, {1, 1, 3, 11, 21, 9, 109, 153, 317, 533, 593, 3967, 2797}},
+{621, 13, 925, {1, 3, 3, 13, 9, 57, 121, 245, 219, 867, 967, 791, 7095}},
+{622, 13, 935, {1, 1, 1, 9, 29, 21, 99, 35, 375, 959, 329, 4087, 7171}},
+{623, 13, 939, {1, 1, 1, 9, 11, 17, 17, 97, 89, 135, 631, 3809, 3253}},
+{624, 13, 942, {1, 1, 1, 15, 21, 51, 91, 249, 459, 801, 757, 2353, 2033}},
+{625, 13, 949, {1, 3, 5, 9, 23, 29, 77, 53, 399, 767, 1817, 2171, 1629}},
+{626, 13, 953, {1, 1, 3, 5, 29, 5, 43, 121, 17, 859, 1479, 3785, 6641}},
+{627, 13, 956, {1, 1, 3, 7, 7, 61, 45, 109, 371, 833, 91, 153, 4553}},
+{628, 13, 961, {1, 1, 3, 11, 7, 55, 81, 123, 389, 139, 1933, 891, 1789}},
+{629, 13, 968, {1, 3, 7, 15, 25, 17, 93, 165, 503, 717, 1553, 1475, 1627}},
+{630, 13, 976, {1, 1, 1, 13, 13, 63, 13, 225, 357, 571, 33, 4073, 3795}},
+{631, 13, 988, {1, 1, 3, 11, 1, 31, 107, 145, 407, 961, 501, 2987, 103}},
+{632, 13, 995, {1, 1, 7, 1, 23, 63, 49, 193, 173, 281, 25, 2465, 5927}},
+{633, 13, 997, {1, 1, 7, 1, 1, 1, 85, 77, 273, 693, 349, 1239, 4503}},
+{634, 13, 1007, {1, 1, 5, 11, 7, 61, 9, 121, 25, 357, 1443, 405, 7827}},
+{635, 13, 1015, {1, 1, 7, 13, 11, 53, 11, 207, 145, 211, 1703, 1081, 2117}},
+{636, 13, 1016, {1, 1, 3, 11, 27, 23, 19, 9, 297, 279, 1481, 2273, 6387}},
+{637, 13, 1027, {1, 3, 3, 5, 15, 45, 3, 41, 305, 87, 1815, 3461, 5349}},
+{638, 13, 1036, {1, 3, 3, 13, 9, 37, 79, 125, 259, 561, 1087, 4091, 793}},
+{639, 13, 1039, {1, 3, 5, 7, 31, 55, 7, 145, 347, 929, 589, 2783, 5905}},
+{640, 13, 1041, {1, 1, 7, 15, 3, 25, 1, 181, 13, 243, 653, 2235, 7445}},
+{641, 13, 1048, {1, 3, 5, 5, 17, 53, 65, 7, 33, 583, 1363, 1313, 2319}},
+{642, 13, 1053, {1, 3, 3, 7, 27, 47, 97, 201, 187, 321, 63, 1515, 7917}},
+{643, 13, 1054, {1, 1, 3, 5, 23, 9, 3, 165, 61, 19, 1789, 3783, 3037}},
+{644, 13, 1058, {1, 3, 1, 13, 15, 43, 125, 191, 67, 273, 1551, 2227, 5253}},
+{645, 13, 1075, {1, 1, 1, 13, 25, 53, 107, 33, 299, 249, 1475, 2233, 907}},
+{646, 13, 1082, {1, 3, 5, 1, 23, 37, 85, 17, 207, 643, 665, 2933, 5199}},
+{647, 13, 1090, {1, 1, 7, 7, 25, 57, 59, 41, 15, 751, 751, 1749, 7053}},
+{648, 13, 1109, {1, 3, 3, 1, 13, 25, 127, 93, 281, 613, 875, 2223, 6345}},
+{649, 13, 1110, {1, 1, 5, 3, 29, 55, 79, 249, 43, 317, 533, 995, 1991}},
+{650, 13, 1119, {1, 3, 3, 15, 17, 49, 79, 31, 193, 233, 1437, 2615, 819}},
+{651, 13, 1126, {1, 1, 5, 15, 25, 3, 123, 145, 377, 9, 455, 1191, 3953}},
+{652, 13, 1130, {1, 3, 5, 3, 15, 19, 41, 231, 81, 393, 3, 19, 2409}},
+{653, 13, 1135, {1, 1, 3, 1, 27, 43, 113, 179, 7, 853, 947, 2731, 297}},
+{654, 13, 1137, {1, 1, 1, 11, 29, 39, 53, 191, 443, 689, 529, 3329, 7431}},
+{655, 13, 1140, {1, 3, 7, 5, 3, 29, 19, 67, 441, 113, 949, 2769, 4169}},
+{656, 13, 1149, {1, 3, 5, 11, 11, 55, 85, 169, 215, 815, 803, 2345, 3967}},
+{657, 13, 1156, {1, 1, 7, 9, 5, 45, 111, 5, 419, 375, 303, 1725, 4489}},
+{658, 13, 1159, {1, 3, 5, 15, 29, 43, 79, 19, 23, 417, 381, 541, 4923}},
+{659, 13, 1160, {1, 1, 3, 15, 3, 31, 117, 39, 117, 305, 1227, 1223, 143}},
+{660, 13, 1165, {1, 1, 5, 9, 5, 47, 87, 239, 181, 353, 1561, 3313, 1921}},
+{661, 13, 1173, {1, 3, 3, 1, 3, 15, 53, 221, 441, 987, 1997, 2529, 8059}},
+{662, 13, 1178, {1, 1, 7, 11, 15, 57, 111, 139, 137, 883, 1881, 2823, 5661}},
+{663, 13, 1183, {1, 3, 5, 5, 21, 11, 5, 13, 27, 973, 587, 1331, 1373}},
+{664, 13, 1184, {1, 1, 7, 11, 29, 51, 93, 29, 217, 221, 55, 2477, 1979}},
+{665, 13, 1189, {1, 3, 3, 13, 3, 11, 49, 75, 379, 371, 1441, 793, 7633}},
+{666, 13, 1194, {1, 1, 1, 13, 19, 45, 89, 249, 91, 649, 1695, 915, 5619}},
+{667, 13, 1211, {1, 3, 1, 7, 7, 29, 1, 77, 313, 895, 519, 771, 295}},
+{668, 13, 1214, {1, 3, 1, 15, 5, 3, 1, 57, 331, 109, 485, 2853, 6831}},
+{669, 13, 1216, {1, 1, 1, 15, 17, 3, 35, 99, 245, 971, 839, 2509, 2803}},
+{670, 13, 1225, {1, 3, 3, 3, 9, 37, 57, 251, 325, 317, 529, 1313, 6379}},
+{671, 13, 1231, {1, 1, 1, 15, 25, 59, 1, 119, 95, 15, 795, 2375, 6463}},
+{672, 13, 1239, {1, 3, 1, 5, 1, 49, 117, 21, 47, 179, 863, 85, 1669}},
+{673, 13, 1243, {1, 3, 7, 3, 9, 37, 19, 221, 455, 973, 571, 1427, 817}},
+{674, 13, 1246, {1, 1, 1, 15, 17, 9, 67, 213, 127, 887, 1299, 2913, 7451}},
+{675, 13, 1249, {1, 3, 1, 13, 27, 27, 41, 43, 171, 623, 691, 391, 4885}},
+{676, 13, 1259, {1, 3, 1, 13, 17, 17, 123, 239, 143, 227, 1151, 519, 6543}},
+{677, 13, 1273, {1, 3, 7, 5, 7, 63, 97, 39, 101, 555, 1057, 381, 7891}},
+{678, 13, 1274, {1, 3, 5, 1, 3, 27, 85, 129, 161, 875, 1945, 3541, 695}},
+{679, 13, 1281, {1, 3, 3, 5, 21, 59, 25, 183, 35, 25, 987, 1459, 181}},
+{680, 13, 1287, {1, 3, 5, 13, 1, 15, 127, 237, 349, 337, 1491, 2383, 7811}},
+{681, 13, 1294, {1, 3, 5, 5, 31, 5, 109, 51, 409, 733, 1395, 3207, 6049}},
+{682, 13, 1296, {1, 1, 5, 7, 13, 35, 113, 25, 263, 389, 299, 2521, 1783}},
+{683, 13, 1305, {1, 3, 7, 11, 15, 47, 97, 73, 55, 75, 113, 2695, 1023}},
+{684, 13, 1306, {1, 3, 1, 1, 3, 13, 69, 211, 289, 483, 1335, 787, 677}},
+{685, 13, 1318, {1, 1, 3, 3, 17, 7, 37, 77, 505, 137, 1113, 345, 2975}},
+{686, 13, 1332, {1, 1, 1, 13, 3, 11, 95, 199, 453, 109, 479, 3725, 239}},
+{687, 13, 1335, {1, 1, 7, 15, 19, 53, 3, 145, 359, 863, 347, 3833, 3043}},
+{688, 13, 1336, {1, 1, 7, 15, 25, 63, 127, 129, 125, 195, 155, 2211, 8153}},
+{689, 13, 1341, {1, 1, 7, 13, 9, 49, 121, 115, 73, 119, 1851, 727, 47}},
+{690, 13, 1342, {1, 3, 3, 13, 13, 11, 71, 7, 45, 591, 133, 2407, 5563}},
+{691, 13, 1362, {1, 1, 1, 13, 23, 29, 87, 89, 501, 71, 1759, 1119, 687}},
+{692, 13, 1364, {1, 1, 7, 7, 13, 7, 13, 183, 53, 951, 1877, 3991, 6771}},
+{693, 13, 1368, {1, 3, 7, 11, 7, 1, 27, 47, 61, 21, 919, 961, 1091}},
+{694, 13, 1378, {1, 3, 5, 5, 1, 27, 1, 5, 63, 157, 1297, 1049, 5893}},
+{695, 13, 1387, {1, 3, 7, 9, 19, 33, 17, 133, 425, 797, 1721, 153, 119}},
+{696, 13, 1389, {1, 3, 3, 7, 13, 37, 1, 215, 509, 1003, 61, 2353, 7511}},
+{697, 13, 1397, {1, 1, 7, 1, 29, 19, 31, 79, 199, 555, 1209, 1603, 6089}},
+{698, 13, 1401, {1, 3, 1, 1, 5, 31, 111, 127, 333, 429, 1863, 3925, 5411}},
+{699, 13, 1408, {1, 1, 7, 5, 5, 5, 123, 191, 47, 993, 269, 4051, 2111}},
+{700, 13, 1418, {1, 1, 5, 15, 1, 9, 87, 5, 47, 463, 865, 1813, 7357}},
+{701, 13, 1425, {1, 3, 1, 3, 23, 63, 123, 83, 511, 777, 63, 1285, 4537}},
+{702, 13, 1426, {1, 3, 3, 7, 27, 25, 31, 65, 441, 529, 1815, 1893, 323}},
+{703, 13, 1431, {1, 3, 7, 5, 11, 19, 7, 5, 397, 811, 755, 2883, 4217}},
+{704, 13, 1435, {1, 3, 1, 13, 9, 21, 13, 7, 271, 539, 1769, 3243, 5325}},
+{705, 13, 1441, {1, 1, 7, 1, 31, 13, 47, 131, 181, 457, 1559, 2663, 6653}},
+{706, 13, 1444, {1, 3, 3, 7, 29, 55, 25, 203, 419, 91, 437, 1159, 5691}},
+{707, 13, 1462, {1, 1, 3, 13, 29, 19, 71, 217, 337, 329, 501, 939, 2205}},
+{708, 13, 1471, {1, 1, 3, 1, 1, 27, 17, 201, 97, 285, 1269, 4043, 2207}},
+{709, 13, 1474, {1, 1, 1, 1, 3, 41, 13, 199, 141, 129, 1515, 3129, 5969}},
+{710, 13, 1483, {1, 3, 3, 9, 3, 17, 119, 41, 271, 933, 877, 701, 2197}},
+{711, 13, 1485, {1, 1, 1, 7, 15, 47, 3, 195, 115, 821, 725, 843, 6071}},
+{712, 13, 1494, {1, 3, 5, 15, 17, 33, 85, 65, 297, 571, 1123, 2743, 5727}},
+{713, 13, 1497, {1, 1, 5, 11, 27, 15, 37, 235, 415, 293, 1439, 2739, 4171}},
+{714, 13, 1516, {1, 3, 7, 7, 1, 55, 71, 35, 307, 11, 401, 1881, 933}},
+{715, 13, 1522, {1, 3, 1, 11, 21, 37, 3, 177, 119, 339, 559, 3991, 3437}},
+{716, 13, 1534, {1, 3, 3, 9, 17, 17, 97, 119, 301, 169, 157, 3267, 2261}},
+{717, 13, 1543, {1, 3, 3, 9, 29, 3, 111, 101, 355, 869, 375, 2609, 7377}},
+{718, 13, 1552, {1, 3, 5, 9, 7, 21, 123, 99, 343, 693, 1927, 1605, 4923}},
+{719, 13, 1557, {1, 1, 3, 5, 13, 31, 99, 17, 75, 385, 1539, 1553, 7077}},
+{720, 13, 1558, {1, 3, 3, 5, 31, 35, 107, 11, 407, 1019, 1317, 3593, 7203}},
+{721, 13, 1567, {1, 3, 3, 13, 17, 33, 99, 245, 401, 957, 157, 1949, 1571}},
+{722, 13, 1568, {1, 3, 1, 11, 27, 15, 11, 109, 429, 307, 1911, 2701, 861}},
+{723, 13, 1574, {1, 1, 5, 13, 13, 35, 55, 255, 311, 957, 1803, 2673, 5195}},
+{724, 13, 1592, {1, 1, 1, 11, 19, 3, 89, 37, 211, 783, 1355, 3567, 7135}},
+{725, 13, 1605, {1, 1, 5, 5, 21, 49, 79, 17, 509, 331, 183, 3831, 855}},
+{726, 13, 1606, {1, 3, 7, 5, 29, 19, 85, 109, 105, 523, 845, 3385, 7477}},
+{727, 13, 1610, {1, 1, 1, 7, 25, 17, 125, 131, 53, 757, 253, 2989, 2939}},
+{728, 13, 1617, {1, 3, 3, 9, 19, 23, 105, 39, 351, 677, 211, 401, 8103}},
+{729, 13, 1623, {1, 3, 5, 1, 5, 11, 17, 3, 405, 469, 1569, 2865, 3133}},
+{730, 13, 1630, {1, 1, 3, 13, 15, 5, 117, 179, 139, 145, 477, 1137, 2537}},
+{731, 13, 1634, {1, 1, 7, 9, 5, 21, 9, 93, 211, 963, 1207, 3343, 4911}},
+{732, 13, 1640, {1, 1, 1, 9, 13, 43, 17, 53, 81, 793, 1571, 2523, 3683}},
+{733, 13, 1643, {1, 3, 3, 13, 25, 21, 5, 59, 489, 987, 1941, 171, 6009}},
+{734, 13, 1648, {1, 3, 3, 7, 1, 39, 89, 171, 403, 467, 1767, 3423, 2791}},
+{735, 13, 1651, {1, 1, 3, 9, 19, 49, 91, 125, 163, 1013, 89, 2849, 6785}},
+{736, 13, 1653, {1, 1, 5, 9, 9, 11, 15, 241, 43, 297, 1719, 1541, 1821}},
+{737, 13, 1670, {1, 3, 7, 15, 29, 23, 103, 239, 191, 33, 1043, 3649, 6579}},
+{738, 13, 1676, {1, 3, 3, 9, 21, 51, 123, 55, 223, 645, 1463, 4021, 5891}},
+{739, 13, 1684, {1, 1, 5, 7, 3, 41, 27, 235, 391, 303, 2021, 3187, 7607}},
+{740, 13, 1687, {1, 1, 1, 9, 5, 49, 49, 29, 377, 251, 1887, 1017, 1301}},
+{741, 13, 1691, {1, 1, 3, 3, 13, 41, 27, 47, 223, 23, 517, 3227, 6731}},
+{742, 13, 1693, {1, 1, 7, 1, 31, 25, 47, 9, 511, 623, 2047, 1263, 1511}},
+{743, 13, 1698, {1, 1, 3, 15, 15, 23, 53, 1, 261, 595, 85, 241, 7047}},
+{744, 13, 1709, {1, 3, 3, 11, 17, 5, 81, 73, 149, 781, 2035, 3163, 4247}},
+{745, 13, 1715, {1, 3, 7, 7, 29, 59, 49, 79, 397, 901, 1105, 2191, 6277}},
+{746, 13, 1722, {1, 3, 3, 11, 13, 27, 25, 173, 107, 73, 1265, 585, 5251}},
+{747, 13, 1732, {1, 1, 7, 15, 29, 23, 73, 229, 235, 887, 1469, 4073, 2591}},
+{748, 13, 1735, {1, 1, 3, 9, 17, 15, 83, 173, 207, 879, 1701, 1509, 11}},
+{749, 13, 1747, {1, 1, 3, 5, 5, 37, 65, 161, 39, 421, 1153, 2007, 5355}},
+{750, 13, 1749, {1, 1, 7, 11, 23, 37, 5, 11, 9, 499, 17, 157, 5747}},
+{751, 13, 1754, {1, 3, 7, 13, 25, 9, 49, 7, 39, 945, 1349, 1759, 1441}},
+{752, 13, 1777, {1, 1, 5, 3, 21, 15, 113, 81, 265, 837, 333, 3625, 6133}},
+{753, 13, 1784, {1, 3, 1, 11, 13, 27, 73, 109, 297, 327, 299, 3253, 6957}},
+{754, 13, 1790, {1, 1, 3, 13, 19, 39, 123, 73, 65, 5, 1061, 2187, 5055}},
+{755, 13, 1795, {1, 1, 3, 1, 11, 31, 21, 115, 453, 857, 711, 495, 549}},
+{756, 13, 1801, {1, 3, 7, 7, 15, 29, 79, 103, 47, 713, 1735, 3121, 6321}},
+{757, 13, 1802, {1, 1, 5, 5, 29, 9, 97, 33, 471, 705, 329, 1501, 1349}},
+{758, 13, 1812, {1, 3, 3, 1, 21, 9, 111, 209, 71, 47, 491, 2143, 1797}},
+{759, 13, 1828, {1, 3, 3, 3, 11, 39, 21, 135, 445, 259, 607, 3811, 5449}},
+{760, 13, 1831, {1, 1, 7, 9, 11, 25, 113, 251, 395, 317, 317, 91, 1979}},
+{761, 13, 1837, {1, 3, 1, 9, 3, 21, 103, 133, 389, 943, 1235, 1749, 7063}},
+{762, 13, 1838, {1, 1, 3, 7, 1, 11, 5, 15, 497, 477, 479, 3079, 6969}},
+{763, 13, 1840, {1, 1, 3, 3, 15, 39, 105, 131, 475, 465, 181, 865, 3813}},
+{764, 13, 1845, {1, 1, 7, 9, 19, 63, 123, 131, 415, 525, 457, 2471, 3135}},
+{765, 13, 1863, {1, 3, 7, 15, 25, 35, 123, 45, 341, 805, 485, 4049, 7065}},
+{766, 13, 1864, {1, 1, 1, 5, 29, 9, 47, 227, 51, 867, 1873, 1593, 2271}},
+{767, 13, 1867, {1, 1, 7, 15, 31, 9, 71, 117, 285, 711, 837, 1435, 6275}},
+{768, 13, 1870, {1, 3, 1, 1, 5, 19, 79, 25, 301, 415, 1871, 645, 3251}},
+{769, 13, 1877, {1, 3, 1, 3, 17, 51, 99, 185, 447, 43, 523, 219, 429}},
+{770, 13, 1881, {1, 3, 1, 13, 29, 13, 51, 93, 7, 995, 757, 3017, 6865}},
+{771, 13, 1884, {1, 1, 3, 15, 7, 25, 75, 17, 155, 981, 1231, 1229, 1995}},
+{772, 13, 1903, {1, 3, 5, 3, 27, 45, 71, 73, 225, 763, 377, 1139, 2863}},
+{773, 13, 1917, {1, 1, 3, 1, 1, 39, 69, 113, 29, 371, 1051, 793, 3749}},
+{774, 13, 1918, {1, 1, 3, 13, 23, 61, 27, 183, 307, 431, 1345, 2757, 4031}},
+{775, 13, 1922, {1, 3, 7, 5, 5, 59, 117, 197, 303, 721, 877, 723, 1601}},
+{776, 13, 1924, {1, 3, 5, 1, 27, 33, 99, 237, 485, 711, 665, 3077, 5105}},
+{777, 13, 1928, {1, 1, 3, 1, 13, 9, 103, 201, 23, 951, 2029, 165, 2093}},
+{778, 13, 1931, {1, 3, 5, 13, 5, 29, 55, 85, 221, 677, 611, 3613, 4567}},
+{779, 13, 1951, {1, 1, 1, 1, 7, 61, 9, 233, 261, 561, 953, 4023, 2443}},
+{780, 13, 1952, {1, 3, 3, 13, 1, 17, 103, 71, 223, 213, 833, 1747, 6999}},
+{781, 13, 1957, {1, 3, 5, 15, 25, 53, 57, 187, 25, 695, 1207, 4089, 2877}},
+{782, 13, 1958, {1, 1, 7, 1, 7, 31, 87, 129, 493, 519, 1555, 1155, 4637}},
+{783, 13, 1964, {1, 1, 1, 15, 21, 17, 23, 29, 19, 255, 927, 1791, 3093}},
+{784, 13, 1967, {1, 1, 3, 9, 17, 33, 95, 129, 175, 461, 287, 2633, 2325}},
+{785, 13, 1970, {1, 3, 5, 7, 23, 19, 63, 209, 249, 583, 1373, 2039, 2225}},
+{786, 13, 1972, {1, 3, 3, 5, 5, 19, 79, 241, 459, 355, 1455, 3313, 3639}},
+{787, 13, 1994, {1, 1, 7, 9, 21, 41, 97, 119, 129, 769, 1541, 3495, 7741}},
+{788, 13, 2002, {1, 1, 7, 11, 9, 29, 35, 255, 141, 937, 1763, 41, 1393}},
+{789, 13, 2007, {1, 3, 7, 1, 13, 51, 61, 157, 177, 847, 1829, 3539, 285}},
+{790, 13, 2008, {1, 1, 1, 15, 21, 13, 9, 55, 397, 19, 1495, 1255, 7235}},
+{791, 13, 2023, {1, 1, 7, 7, 25, 37, 53, 237, 319, 197, 269, 1205, 1485}},
+{792, 13, 2030, {1, 1, 5, 15, 23, 17, 35, 247, 323, 807, 233, 3681, 4407}},
+{793, 13, 2035, {1, 1, 3, 7, 9, 59, 85, 105, 493, 763, 1639, 391, 1451}},
+{794, 13, 2038, {1, 3, 3, 9, 15, 33, 5, 253, 129, 625, 1527, 2793, 6057}},
+{795, 13, 2042, {1, 3, 1, 1, 7, 47, 21, 161, 235, 83, 397, 3563, 5953}},
+{796, 13, 2047, {1, 3, 7, 11, 3, 41, 25, 117, 375, 779, 1297, 3715, 8117}},
+{797, 13, 2051, {1, 1, 3, 7, 31, 19, 103, 173, 475, 189, 2035, 2921, 1107}},
+{798, 13, 2058, {1, 1, 7, 3, 25, 7, 93, 255, 307, 113, 1893, 2233, 6919}},
+{799, 13, 2060, {1, 3, 5, 15, 9, 57, 79, 143, 165, 5, 1389, 193, 693}},
+{800, 13, 2071, {1, 3, 5, 1, 29, 45, 91, 49, 189, 461, 439, 1283, 7835}},
+{801, 13, 2084, {1, 1, 3, 13, 11, 61, 41, 231, 373, 695, 395, 915, 5393}},
+{802, 13, 2087, {1, 3, 7, 11, 5, 51, 67, 53, 483, 95, 1943, 247, 5653}},
+{803, 13, 2099, {1, 3, 7, 5, 5, 57, 45, 235, 137, 793, 1069, 1661, 1557}},
+{804, 13, 2108, {1, 3, 5, 3, 25, 55, 103, 177, 81, 861, 1151, 143, 7655}},
+{805, 13, 2111, {1, 1, 3, 1, 21, 41, 67, 131, 253, 431, 1269, 3181, 3429}},
+{806, 13, 2120, {1, 3, 1, 1, 21, 7, 77, 221, 257, 663, 71, 2949, 2481}},
+{807, 13, 2128, {1, 3, 5, 3, 3, 23, 45, 107, 299, 739, 1013, 3, 3165}},
+{808, 13, 2138, {1, 1, 5, 1, 3, 37, 109, 37, 243, 983, 1221, 1691, 3869}},
+{809, 13, 2143, {1, 1, 5, 5, 31, 7, 5, 193, 397, 867, 1495, 3435, 7441}},
+{810, 13, 2144, {1, 1, 1, 1, 17, 59, 97, 233, 389, 597, 1013, 1631, 483}},
+{811, 13, 2153, {1, 1, 1, 11, 7, 41, 107, 53, 111, 125, 1513, 1921, 7647}},
+{812, 13, 2156, {1, 3, 3, 3, 31, 29, 117, 3, 365, 971, 1139, 2123, 5913}},
+{813, 13, 2162, {1, 1, 1, 13, 23, 3, 1, 167, 475, 639, 1811, 3841, 3081}},
+{814, 13, 2167, {1, 1, 5, 3, 5, 47, 65, 123, 275, 783, 95, 119, 7591}},
+{815, 13, 2178, {1, 3, 1, 15, 13, 33, 93, 237, 467, 431, 705, 4013, 4035}},
+{816, 13, 2183, {1, 3, 5, 1, 19, 7, 101, 231, 155, 737, 1381, 3343, 2051}},
+{817, 13, 2202, {1, 1, 5, 9, 15, 49, 45, 163, 433, 765, 2031, 201, 2589}},
+{818, 13, 2211, {1, 3, 7, 9, 19, 41, 31, 89, 93, 623, 105, 745, 4409}},
+{819, 13, 2214, {1, 1, 5, 1, 11, 45, 127, 85, 389, 439, 829, 477, 7965}},
+{820, 13, 2223, {1, 3, 3, 15, 13, 41, 1, 207, 435, 585, 311, 1725, 2737}},
+{821, 13, 2225, {1, 3, 3, 3, 13, 49, 21, 31, 197, 799, 1411, 2959, 7133}},
+{822, 13, 2232, {1, 3, 1, 3, 7, 43, 9, 141, 133, 579, 1059, 93, 957}},
+{823, 13, 2237, {1, 3, 7, 1, 15, 51, 23, 213, 381, 851, 699, 2261, 3419}},
+{824, 13, 2257, {1, 3, 5, 9, 25, 35, 67, 141, 35, 409, 1423, 365, 1645}},
+{825, 13, 2260, {1, 3, 3, 11, 15, 33, 27, 181, 93, 87, 1761, 3511, 1353}},
+{826, 13, 2267, {1, 3, 5, 3, 25, 63, 111, 137, 321, 819, 705, 1547, 7271}},
+{827, 13, 2274, {1, 3, 1, 1, 5, 57, 99, 59, 411, 757, 1371, 3953, 3695}},
+{828, 13, 2276, {1, 3, 5, 11, 11, 21, 25, 147, 239, 455, 709, 953, 7175}},
+{829, 13, 2285, {1, 3, 3, 15, 5, 53, 91, 205, 341, 63, 723, 1565, 7135}},
+{830, 13, 2288, {1, 1, 7, 15, 11, 21, 99, 79, 63, 593, 2007, 3629, 5271}},
+{831, 13, 2293, {1, 3, 3, 1, 9, 21, 45, 175, 453, 435, 1855, 2649, 6959}},
+{832, 13, 2294, {1, 1, 3, 15, 15, 33, 121, 121, 251, 431, 1127, 3305, 4199}},
+{833, 13, 2297, {1, 1, 1, 9, 31, 15, 71, 29, 345, 391, 1159, 2809, 345}},
+{834, 13, 2303, {1, 3, 7, 1, 23, 29, 95, 151, 327, 727, 647, 1623, 2971}},
+{835, 13, 2308, {1, 1, 7, 7, 9, 29, 79, 91, 127, 909, 1293, 1315, 5315}},
+{836, 13, 2311, {1, 1, 5, 11, 13, 37, 89, 73, 149, 477, 1909, 3343, 525}},
+{837, 13, 2318, {1, 3, 5, 7, 5, 59, 55, 255, 223, 459, 2027, 237, 4205}},
+{838, 13, 2323, {1, 1, 1, 7, 27, 11, 95, 65, 325, 835, 907, 3801, 3787}},
+{839, 13, 2332, {1, 1, 1, 11, 27, 33, 99, 175, 51, 913, 331, 1851, 4133}},
+{840, 13, 2341, {1, 3, 5, 5, 13, 37, 31, 99, 273, 409, 1827, 3845, 5491}},
+{841, 13, 2345, {1, 1, 3, 7, 23, 19, 107, 85, 283, 523, 509, 451, 421}},
+{842, 13, 2348, {1, 3, 5, 7, 13, 9, 51, 81, 87, 619, 61, 2803, 5271}},
+{843, 13, 2354, {1, 1, 1, 15, 9, 45, 35, 219, 401, 271, 953, 649, 6847}},
+{844, 13, 2368, {1, 1, 7, 11, 9, 45, 17, 219, 169, 837, 1483, 1605, 2901}},
+{845, 13, 2377, {1, 1, 7, 7, 21, 43, 37, 33, 291, 359, 71, 2899, 7037}},
+{846, 13, 2380, {1, 3, 3, 13, 31, 53, 37, 15, 149, 949, 551, 3445, 5455}},
+{847, 13, 2383, {1, 3, 1, 5, 19, 45, 81, 223, 193, 439, 2047, 3879, 789}},
+{848, 13, 2388, {1, 1, 7, 3, 11, 63, 35, 61, 255, 563, 459, 2991, 3359}},
+{849, 13, 2395, {1, 1, 5, 9, 13, 49, 47, 185, 239, 221, 1533, 3635, 2045}},
+{850, 13, 2397, {1, 3, 7, 3, 25, 37, 127, 223, 51, 357, 483, 3837, 6873}},
+{851, 13, 2401, {1, 1, 7, 9, 31, 37, 113, 31, 387, 833, 1243, 1543, 5535}},
+{852, 13, 2411, {1, 3, 1, 9, 23, 59, 119, 221, 73, 185, 2007, 2885, 2563}},
+{853, 13, 2413, {1, 1, 1, 13, 7, 33, 53, 179, 67, 185, 1541, 1807, 4659}},
+{854, 13, 2419, {1, 3, 1, 11, 31, 37, 23, 215, 269, 357, 207, 645, 4219}},
+{855, 13, 2435, {1, 3, 3, 13, 19, 27, 107, 55, 91, 71, 1695, 1815, 89}},
+{856, 13, 2442, {1, 1, 3, 15, 3, 19, 35, 247, 49, 529, 1523, 3317, 6151}},
+{857, 13, 2455, {1, 1, 7, 7, 23, 25, 107, 139, 483, 503, 1277, 243, 7879}},
+{858, 13, 2472, {1, 3, 3, 13, 3, 15, 11, 197, 135, 839, 985, 275, 5527}},
+{859, 13, 2478, {1, 3, 5, 3, 25, 47, 95, 21, 113, 307, 1001, 3065, 295}},
+{860, 13, 2490, {1, 1, 3, 9, 19, 19, 99, 213, 363, 449, 735, 2851, 2521}},
+{861, 13, 2507, {1, 1, 3, 9, 5, 49, 63, 61, 157, 857, 497, 2801, 6987}},
+{862, 13, 2509, {1, 1, 1, 9, 1, 41, 109, 119, 499, 939, 867, 3675, 8023}},
+{863, 13, 2517, {1, 3, 1, 1, 13, 33, 109, 123, 289, 3, 1271, 2773, 4265}},
+{864, 13, 2524, {1, 3, 1, 11, 9, 57, 83, 221, 95, 43, 1189, 457, 7133}},
+{865, 13, 2528, {1, 1, 7, 3, 11, 49, 33, 219, 229, 289, 685, 3359, 4495}},
+{866, 13, 2531, {1, 3, 1, 3, 19, 43, 67, 193, 41, 771, 407, 81, 3891}},
+{867, 13, 2538, {1, 1, 7, 11, 5, 29, 51, 175, 297, 539, 1, 2245, 6439}},
+{868, 13, 2545, {1, 3, 7, 15, 21, 33, 117, 183, 511, 489, 1283, 3281, 5979}},
+{869, 13, 2546, {1, 3, 7, 5, 9, 3, 125, 147, 359, 549, 369, 3049, 2405}},
+{870, 13, 2555, {1, 3, 5, 7, 19, 5, 65, 97, 483, 377, 1523, 1457, 2995}},
+{871, 13, 2557, {1, 1, 5, 1, 11, 21, 41, 113, 277, 131, 1475, 1043, 2367}},
+{872, 13, 2564, {1, 3, 3, 1, 15, 17, 101, 69, 443, 865, 817, 1421, 5231}},
+{873, 13, 2573, {1, 1, 3, 3, 3, 55, 95, 99, 75, 195, 1929, 3931, 5855}},
+{874, 13, 2579, {1, 3, 1, 3, 19, 23, 93, 213, 241, 551, 1307, 585, 7729}},
+{875, 13, 2592, {1, 3, 1, 11, 23, 15, 53, 249, 467, 519, 95, 741, 409}},
+{876, 13, 2598, {1, 1, 1, 15, 29, 37, 43, 203, 233, 877, 77, 1933, 2729}},
+{877, 13, 2607, {1, 3, 7, 11, 27, 39, 43, 161, 255, 15, 1463, 833, 495}},
+{878, 13, 2612, {1, 1, 7, 11, 3, 53, 81, 67, 375, 823, 1903, 3061, 395}},
+{879, 13, 2619, {1, 1, 1, 1, 15, 37, 93, 233, 247, 501, 1321, 3275, 5409}},
+{880, 13, 2621, {1, 3, 3, 7, 7, 11, 5, 105, 139, 983, 1239, 531, 3881}},
+{881, 13, 2627, {1, 1, 5, 3, 19, 49, 107, 227, 361, 101, 355, 2649, 7383}},
+{882, 13, 2633, {1, 1, 7, 5, 25, 41, 101, 121, 209, 293, 1937, 2259, 5557}},
+{883, 13, 2636, {1, 1, 3, 7, 7, 1, 9, 13, 463, 1019, 995, 3159, 107}},
+{884, 13, 2642, {1, 3, 5, 11, 5, 35, 127, 97, 261, 789, 807, 807, 6257}},
+{885, 13, 2654, {1, 1, 7, 5, 11, 13, 45, 91, 417, 101, 1973, 3645, 2107}},
+{886, 13, 2660, {1, 1, 3, 7, 5, 63, 57, 49, 203, 157, 115, 1393, 8117}},
+{887, 13, 2669, {1, 3, 5, 5, 3, 43, 15, 155, 127, 489, 1165, 3701, 4867}},
+{888, 13, 2675, {1, 1, 7, 7, 29, 29, 69, 215, 415, 367, 371, 1901, 6075}},
+{889, 13, 2684, {1, 1, 1, 3, 11, 33, 89, 149, 433, 705, 1437, 1597, 505}},
+{890, 13, 2694, {1, 3, 5, 1, 13, 37, 19, 119, 5, 581, 2037, 1633, 2099}},
+{891, 13, 2703, {1, 3, 7, 13, 5, 49, 103, 245, 215, 515, 133, 2007, 1933}},
+{892, 13, 2706, {1, 3, 1, 9, 1, 3, 25, 197, 253, 387, 1683, 2267, 221}},
+{893, 13, 2712, {1, 3, 5, 15, 21, 9, 73, 201, 405, 999, 437, 3877, 6045}},
+{894, 13, 2715, {1, 1, 3, 1, 31, 55, 25, 83, 421, 395, 1807, 2129, 7797}},
+{895, 13, 2722, {1, 1, 3, 1, 23, 21, 121, 183, 125, 347, 143, 3685, 4317}},
+{896, 13, 2727, {1, 3, 3, 3, 17, 45, 17, 223, 267, 795, 1815, 1309, 155}},
+{897, 13, 2734, {1, 1, 1, 15, 17, 59, 5, 133, 15, 715, 1503, 153, 2887}},
+{898, 13, 2742, {1, 1, 1, 1, 27, 13, 119, 77, 243, 995, 1851, 3719, 4695}},
+{899, 13, 2745, {1, 3, 1, 5, 31, 49, 43, 165, 49, 609, 1265, 1141, 505}},
+{900, 13, 2751, {1, 1, 7, 13, 11, 63, 21, 253, 229, 585, 1543, 3719, 4141}},
+{901, 13, 2766, {1, 3, 7, 11, 23, 27, 17, 131, 295, 895, 1493, 1411, 3247}},
+{902, 13, 2768, {1, 1, 5, 9, 29, 7, 97, 15, 113, 445, 859, 1483, 1121}},
+{903, 13, 2780, {1, 3, 1, 9, 13, 49, 99, 107, 323, 201, 681, 3071, 5281}},
+{904, 13, 2790, {1, 1, 1, 15, 9, 19, 61, 161, 7, 87, 587, 2199, 2811}},
+{905, 13, 2794, {1, 3, 3, 15, 15, 19, 95, 45, 299, 829, 981, 3479, 487}},
+{906, 13, 2796, {1, 1, 1, 9, 3, 37, 7, 19, 227, 13, 397, 513, 1257}},
+{907, 13, 2801, {1, 1, 5, 15, 15, 13, 17, 111, 135, 929, 1145, 811, 1801}},
+{908, 13, 2804, {1, 3, 1, 3, 27, 57, 31, 19, 279, 103, 693, 631, 3409}},
+{909, 13, 2807, {1, 1, 1, 1, 15, 13, 67, 83, 23, 799, 1735, 2063, 3363}},
+{910, 13, 2816, {1, 3, 3, 7, 3, 1, 61, 31, 41, 533, 2025, 4067, 6963}},
+{911, 13, 2821, {1, 1, 5, 7, 17, 27, 81, 79, 107, 205, 29, 97, 4883}},
+{912, 13, 2831, {1, 1, 1, 5, 19, 49, 91, 201, 283, 949, 651, 3819, 5073}},
+{913, 13, 2834, {1, 1, 7, 9, 11, 13, 73, 197, 37, 219, 1931, 3369, 6017}},
+{914, 13, 2839, {1, 1, 7, 15, 11, 7, 75, 205, 7, 819, 399, 661, 6487}},
+{915, 13, 2845, {1, 3, 3, 3, 27, 37, 95, 41, 307, 165, 1077, 3485, 563}},
+{916, 13, 2852, {1, 3, 5, 3, 21, 49, 57, 179, 109, 627, 1789, 431, 2941}},
+{917, 13, 2856, {1, 1, 7, 5, 11, 19, 43, 137, 149, 679, 1543, 245, 1381}},
+{918, 13, 2861, {1, 3, 5, 5, 15, 3, 69, 81, 135, 159, 1363, 3401, 6355}},
+{919, 13, 2873, {1, 3, 5, 1, 9, 61, 49, 53, 319, 25, 1647, 1297, 615}},
+{920, 13, 2874, {1, 3, 5, 11, 31, 43, 9, 101, 71, 919, 335, 3147, 5823}},
+{921, 13, 2888, {1, 3, 1, 1, 15, 5, 29, 109, 511, 945, 867, 3677, 6915}},
+{922, 13, 2893, {1, 3, 3, 15, 17, 49, 91, 111, 215, 29, 1879, 97, 2505}},
+{923, 13, 2894, {1, 3, 1, 13, 19, 61, 11, 111, 163, 777, 533, 1113, 5339}},
+{924, 13, 2902, {1, 1, 7, 9, 17, 55, 117, 91, 455, 289, 557, 913, 4455}},
+{925, 13, 2917, {1, 3, 1, 7, 25, 19, 123, 37, 1, 277, 717, 2965, 4469}},
+{926, 13, 2921, {1, 3, 7, 3, 19, 23, 87, 235, 209, 457, 2041, 2893, 1805}},
+{927, 13, 2922, {1, 3, 3, 5, 5, 43, 23, 61, 351, 791, 59, 2009, 2909}},
+{928, 13, 2929, {1, 1, 3, 7, 5, 1, 27, 231, 385, 257, 1261, 2701, 1807}},
+{929, 13, 2935, {1, 3, 1, 1, 27, 19, 87, 253, 131, 685, 1743, 3983, 2651}},
+{930, 13, 2946, {1, 3, 7, 11, 21, 17, 11, 81, 191, 641, 1821, 3005, 7251}},
+{931, 13, 2951, {1, 3, 3, 5, 15, 31, 41, 213, 55, 931, 1953, 49, 6037}},
+{932, 13, 2957, {1, 1, 7, 15, 7, 27, 65, 223, 113, 79, 1875, 911, 5445}},
+{933, 13, 2960, {1, 3, 7, 7, 23, 55, 51, 167, 495, 25, 1585, 3447, 799}},
+{934, 13, 2966, {1, 1, 3, 7, 27, 15, 95, 193, 337, 415, 975, 3085, 967}},
+{935, 13, 2972, {1, 1, 7, 15, 19, 7, 93, 41, 433, 551, 401, 3169, 3971}},
+{936, 13, 2976, {1, 1, 7, 11, 13, 15, 53, 69, 433, 59, 1117, 3359, 6231}},
+{937, 13, 2979, {1, 1, 7, 3, 23, 5, 115, 201, 225, 109, 1903, 3897, 6265}},
+{938, 13, 2985, {1, 1, 1, 11, 17, 1, 39, 143, 361, 659, 1105, 23, 4923}},
+{939, 13, 3000, {1, 1, 1, 9, 27, 57, 85, 227, 261, 119, 1881, 3965, 6999}},
+{940, 13, 3003, {1, 3, 7, 7, 15, 7, 107, 17, 315, 49, 1591, 905, 7789}},
+{941, 13, 3013, {1, 3, 1, 7, 29, 3, 47, 237, 157, 769, 839, 3199, 3195}},
+{942, 13, 3018, {1, 1, 3, 15, 25, 39, 63, 15, 111, 857, 881, 1505, 7671}},
+{943, 13, 3020, {1, 1, 7, 1, 3, 35, 41, 215, 99, 895, 1025, 1483, 4707}},
+{944, 13, 3025, {1, 3, 5, 1, 1, 31, 25, 247, 113, 841, 397, 1825, 6969}},
+{945, 13, 3042, {1, 1, 3, 5, 19, 41, 49, 243, 225, 973, 241, 175, 1041}},
+{946, 13, 3047, {1, 1, 1, 7, 15, 15, 105, 141, 83, 75, 1675, 3523, 5219}},
+{947, 13, 3048, {1, 1, 7, 5, 13, 27, 47, 199, 445, 841, 959, 1157, 2209}},
+{948, 13, 3051, {1, 3, 5, 15, 23, 31, 31, 81, 85, 33, 785, 2639, 7799}},
+{949, 13, 3054, {1, 1, 5, 13, 21, 3, 47, 99, 235, 943, 1731, 2467, 7891}},
+{950, 13, 3056, {1, 1, 1, 3, 17, 53, 85, 219, 73, 131, 1339, 875, 1191}},
+{951, 13, 3065, {1, 1, 5, 7, 17, 63, 113, 7, 185, 557, 749, 3563, 4973}},
+{952, 13, 3073, {1, 3, 3, 15, 15, 21, 43, 111, 155, 689, 345, 423, 3597}},
+{953, 13, 3074, {1, 1, 5, 1, 15, 29, 93, 5, 361, 713, 695, 3937, 425}},
+{954, 13, 3083, {1, 3, 7, 7, 13, 41, 115, 175, 315, 937, 123, 2841, 4457}},
+{955, 13, 3086, {1, 1, 3, 11, 25, 5, 103, 53, 423, 811, 657, 399, 7257}},
+{956, 13, 3091, {1, 1, 1, 1, 1, 13, 101, 211, 383, 325, 97, 1703, 4429}},
+{957, 13, 3097, {1, 3, 7, 9, 31, 45, 83, 157, 509, 701, 841, 1105, 3643}},
+{958, 13, 3109, {1, 1, 1, 7, 1, 9, 69, 17, 129, 281, 1161, 2945, 7693}},
+{959, 13, 3116, {1, 3, 7, 1, 11, 29, 51, 143, 77, 433, 1723, 2317, 5641}},
+{960, 13, 3124, {1, 1, 1, 1, 21, 43, 13, 67, 177, 505, 1629, 1267, 4885}},
+{961, 13, 3128, {1, 1, 3, 11, 27, 63, 111, 47, 233, 781, 453, 1679, 3209}},
+{962, 13, 3153, {1, 1, 3, 13, 29, 27, 119, 141, 493, 971, 461, 1159, 633}},
+{963, 13, 3160, {1, 1, 3, 15, 23, 5, 79, 215, 163, 149, 1805, 2399, 61}},
+{964, 13, 3165, {1, 3, 5, 13, 19, 5, 1, 39, 409, 561, 709, 829, 1357}},
+{965, 13, 3172, {1, 3, 3, 13, 19, 43, 9, 177, 449, 447, 73, 2107, 5669}},
+{966, 13, 3175, {1, 3, 5, 1, 23, 13, 63, 109, 203, 593, 829, 4017, 6881}},
+{967, 13, 3184, {1, 1, 5, 7, 3, 9, 53, 175, 391, 169, 1283, 3793, 4451}},
+{968, 13, 3193, {1, 1, 5, 7, 29, 43, 9, 5, 209, 77, 927, 2941, 8145}},
+{969, 13, 3196, {1, 3, 5, 15, 17, 49, 5, 143, 131, 771, 1685, 925, 2175}},
+{970, 13, 3200, {1, 1, 3, 11, 27, 27, 27, 159, 161, 1015, 1587, 4049, 1983}},
+{971, 13, 3203, {1, 3, 1, 3, 23, 57, 119, 67, 481, 577, 389, 3319, 5325}},
+{972, 13, 3205, {1, 3, 5, 1, 19, 39, 87, 61, 329, 657, 1773, 31, 1707}},
+{973, 13, 3209, {1, 1, 3, 1, 5, 25, 15, 241, 131, 815, 1751, 3029, 8039}},
+{974, 13, 3224, {1, 3, 3, 13, 27, 13, 77, 87, 437, 57, 621, 1031, 7891}},
+{975, 13, 3239, {1, 3, 1, 13, 23, 51, 117, 37, 331, 745, 605, 3179, 4713}},
+{976, 13, 3251, {1, 1, 5, 5, 19, 17, 99, 167, 87, 721, 737, 789, 2165}},
+{977, 13, 3254, {1, 3, 5, 13, 1, 51, 119, 211, 165, 299, 1327, 3053, 3343}},
+{978, 13, 3265, {1, 1, 5, 15, 29, 45, 17, 129, 67, 345, 1553, 2705, 7369}},
+{979, 13, 3266, {1, 1, 1, 9, 23, 7, 13, 209, 7, 407, 317, 3077, 7287}},
+{980, 13, 3275, {1, 1, 1, 5, 9, 59, 89, 3, 487, 451, 505, 2499, 7563}},
+{981, 13, 3280, {1, 3, 1, 7, 21, 1, 21, 203, 101, 417, 1389, 2751, 1397}},
+{982, 13, 3283, {1, 3, 7, 13, 7, 31, 3, 247, 349, 485, 1259, 549, 6321}},
+{983, 13, 3286, {1, 1, 7, 7, 27, 33, 107, 197, 293, 729, 1753, 2571, 103}},
+{984, 13, 3301, {1, 3, 5, 9, 25, 35, 5, 253, 137, 213, 2041, 3387, 1809}},
+{985, 13, 3302, {1, 1, 7, 13, 15, 35, 67, 83, 295, 175, 839, 2831, 839}},
+{986, 13, 3305, {1, 3, 3, 11, 3, 17, 55, 141, 247, 991, 117, 3799, 1221}},
+{987, 13, 3319, {1, 1, 5, 1, 11, 37, 87, 233, 457, 653, 899, 2933, 3105}},
+{988, 13, 3323, {1, 1, 3, 15, 3, 31, 67, 167, 437, 9, 651, 1109, 1139}},
+{989, 13, 3326, {1, 1, 3, 1, 7, 63, 67, 17, 11, 883, 1855, 1941, 4751}},
+{990, 13, 3331, {1, 3, 7, 9, 19, 33, 113, 117, 495, 39, 1795, 2561, 5519}},
+{991, 13, 3348, {1, 1, 7, 5, 1, 3, 103, 37, 201, 223, 1101, 877, 6483}},
+{992, 13, 3351, {1, 1, 5, 9, 29, 49, 51, 33, 439, 917, 861, 1321, 2135}},
+{993, 13, 3358, {1, 1, 3, 3, 1, 5, 17, 93, 217, 619, 613, 1357, 6095}},
+{994, 13, 3368, {1, 3, 1, 11, 3, 21, 5, 41, 15, 175, 843, 2937, 6849}},
+{995, 13, 3374, {1, 3, 3, 7, 9, 57, 55, 127, 79, 287, 445, 2205, 7989}},
+{996, 13, 3376, {1, 1, 7, 13, 23, 17, 93, 129, 157, 135, 1747, 1813, 4183}},
+{997, 13, 3379, {1, 1, 1, 5, 31, 59, 99, 33, 425, 329, 887, 367, 1761}},
+{998, 13, 3385, {1, 1, 7, 9, 17, 53, 77, 139, 435, 387, 49, 3649, 1773}},
+{999, 13, 3386, {1, 3, 3, 15, 21, 57, 45, 161, 331, 719, 273, 3479, 4173}},
+{1000, 13, 3396, {1, 1, 3, 9, 3, 3, 105, 201, 373, 877, 919, 1263, 6649}},
+{1001, 13, 3420, {1, 3, 1, 15, 13, 43, 13, 99, 73, 163, 353, 3569, 5601}},
+{1002, 13, 3423, {1, 3, 7, 3, 5, 9, 69, 177, 449, 47, 781, 1125, 4245}},
+{1003, 13, 3430, {1, 1, 1, 5, 3, 45, 1, 123, 409, 903, 205, 2057, 7637}},
+{1004, 13, 3433, {1, 3, 5, 9, 19, 47, 87, 135, 481, 799, 101, 3409, 2241}},
+{1005, 13, 3434, {1, 3, 1, 13, 3, 25, 15, 27, 181, 967, 669, 2577, 7249}},
+{1006, 13, 3439, {1, 1, 7, 3, 31, 5, 103, 53, 1, 911, 1209, 3697, 6685}},
+{1007, 13, 3442, {1, 1, 3, 1, 5, 5, 49, 135, 281, 747, 761, 2973, 7963}},
+{1008, 13, 3444, {1, 3, 3, 5, 19, 61, 125, 199, 299, 515, 1365, 369, 7027}},
+{1009, 13, 3453, {1, 3, 1, 7, 5, 41, 63, 229, 283, 571, 147, 447, 657}},
+{1010, 13, 3464, {1, 3, 1, 11, 5, 15, 55, 7, 259, 61, 27, 1429, 5631}},
+{1011, 13, 3477, {1, 1, 5, 1, 3, 53, 51, 253, 155, 553, 1293, 3735, 6567}},
+{1012, 13, 3478, {1, 3, 5, 9, 5, 41, 21, 159, 101, 785, 1981, 3799, 7693}},
+{1013, 13, 3482, {1, 3, 7, 7, 9, 3, 95, 105, 129, 213, 1215, 1027, 5699}},
+{1014, 13, 3487, {1, 1, 3, 3, 29, 13, 9, 253, 449, 321, 341, 2879, 171}},
+{1015, 13, 3497, {1, 3, 7, 11, 21, 11, 75, 35, 43, 965, 675, 2217, 7175}},
+{1016, 13, 3500, {1, 1, 5, 15, 31, 5, 29, 137, 311, 751, 47, 1367, 5921}},
+{1017, 13, 3505, {1, 1, 3, 15, 17, 1, 45, 69, 55, 649, 835, 569, 7615}},
+{1018, 13, 3506, {1, 3, 1, 13, 31, 7, 23, 15, 391, 145, 1845, 1825, 1403}},
+{1019, 13, 3511, {1, 1, 3, 15, 5, 9, 79, 77, 105, 399, 1933, 2503, 4781}},
+{1020, 13, 3512, {1, 3, 1, 3, 17, 47, 19, 13, 107, 475, 759, 2933, 3761}},
+{1021, 13, 3515, {1, 1, 7, 11, 3, 7, 121, 209, 397, 877, 293, 847, 7039}},
+{1022, 13, 3525, {1, 1, 1, 15, 29, 45, 5, 109, 335, 461, 143, 931, 4045}},
+{1023, 13, 3532, {1, 3, 1, 7, 11, 57, 73, 89, 201, 173, 803, 3953, 5205}},
+{1024, 13, 3538, {1, 1, 5, 11, 11, 33, 37, 29, 263, 1019, 657, 1453, 7807}},
+{1025, 13, 3540, {1, 3, 3, 13, 31, 25, 37, 47, 261, 607, 1703, 2603, 417}},
+{1026, 13, 3547, {1, 1, 1, 1, 31, 61, 45, 115, 275, 239, 1989, 1897, 4329}},
+{1027, 13, 3549, {1, 3, 5, 3, 31, 3, 11, 173, 335, 579, 1193, 2219, 7875}},
+{1028, 13, 3560, {1, 1, 7, 9, 29, 45, 13, 67, 399, 177, 1293, 3865, 2225}},
+{1029, 13, 3571, {1, 1, 7, 11, 11, 51, 121, 227, 469, 905, 929, 2635, 4165}},
+{1030, 13, 3577, {1, 3, 7, 9, 13, 39, 55, 167, 23, 147, 1603, 2083, 4645}},
+{1031, 13, 3583, {1, 1, 3, 15, 27, 53, 11, 155, 157, 629, 259, 3009, 4605}},
+{1032, 13, 3590, {1, 3, 1, 7, 15, 47, 51, 1, 259, 603, 887, 2833, 6581}},
+{1033, 13, 3593, {1, 3, 5, 3, 1, 47, 91, 43, 361, 571, 29, 1453, 4269}},
+{1034, 13, 3594, {1, 1, 3, 9, 11, 51, 55, 23, 415, 277, 1423, 3475, 1527}},
+{1035, 13, 3599, {1, 1, 3, 11, 29, 49, 101, 75, 299, 709, 805, 4037, 4389}},
+{1036, 13, 3601, {1, 1, 7, 3, 23, 1, 37, 51, 379, 771, 1301, 3717, 6673}},
+{1037, 13, 3602, {1, 1, 5, 3, 23, 11, 125, 177, 375, 665, 951, 1577, 2603}},
+{1038, 13, 3613, {1, 1, 1, 1, 1, 5, 71, 255, 21, 459, 467, 2083, 5415}},
+{1039, 13, 3623, {1, 1, 5, 13, 23, 29, 109, 157, 363, 971, 549, 647, 1177}},
+{1040, 13, 3630, {1, 1, 3, 9, 7, 15, 101, 3, 365, 213, 745, 1155, 6099}},
+{1041, 13, 3638, {1, 3, 5, 15, 15, 19, 47, 179, 303, 521, 1279, 219, 2415}},
+{1042, 13, 3649, {1, 3, 3, 13, 27, 11, 83, 165, 369, 989, 261, 3933, 4809}},
+{1043, 13, 3655, {1, 1, 3, 11, 31, 59, 1, 185, 53, 703, 1471, 2935, 1107}},
+{1044, 13, 3662, {1, 3, 3, 7, 25, 3, 81, 27, 93, 521, 433, 2859, 5861}},
+{1045, 13, 3667, {1, 3, 3, 11, 29, 15, 49, 167, 315, 927, 543, 3473, 4307}},
+{1046, 13, 3669, {1, 3, 1, 3, 29, 33, 53, 15, 183, 691, 703, 1311, 3393}},
+{1047, 13, 3676, {1, 3, 5, 13, 23, 49, 3, 11, 1, 357, 1407, 415, 7211}},
+{1048, 13, 3683, {1, 3, 7, 15, 1, 25, 91, 113, 323, 371, 189, 925, 1181}},
+{1049, 13, 3700, {1, 3, 3, 3, 17, 59, 119, 199, 115, 223, 877, 2193, 193}},
+{1050, 13, 3709, {1, 1, 1, 5, 5, 35, 31, 59, 437, 411, 37, 2405, 3797}},
+{1051, 13, 3710, {1, 3, 1, 13, 9, 37, 1, 241, 59, 157, 1785, 1223, 563}},
+{1052, 13, 3713, {1, 3, 5, 13, 3, 21, 25, 95, 15, 745, 85, 701, 5361}},
+{1053, 13, 3723, {1, 3, 7, 1, 31, 33, 111, 195, 35, 913, 2013, 2951, 6611}},
+{1054, 13, 3725, {1, 3, 5, 1, 19, 3, 75, 119, 111, 409, 951, 1457, 4957}},
+{1055, 13, 3728, {1, 3, 1, 15, 19, 59, 3, 155, 237, 657, 1967, 3323, 6235}},
+{1056, 13, 3734, {1, 1, 5, 1, 3, 19, 45, 105, 377, 881, 167, 2255, 4483}},
+{1057, 13, 3737, {1, 1, 7, 7, 13, 13, 99, 89, 201, 279, 161, 2483, 6001}},
+{1058, 13, 3738, {1, 1, 7, 3, 13, 17, 97, 129, 137, 377, 1519, 183, 3725}},
+{1059, 13, 3744, {1, 1, 7, 9, 9, 5, 45, 135, 115, 181, 1685, 3505, 4387}},
+{1060, 13, 3750, {1, 1, 1, 1, 19, 35, 69, 113, 305, 419, 949, 2969, 247}},
+{1061, 13, 3762, {1, 1, 5, 13, 23, 61, 13, 139, 501, 811, 67, 1501, 6493}},
+{1062, 13, 3764, {1, 1, 3, 13, 15, 41, 27, 217, 293, 13, 145, 2631, 6991}},
+{1063, 13, 3774, {1, 3, 3, 13, 15, 37, 71, 123, 285, 49, 627, 1283, 5993}},
+{1064, 13, 3776, {1, 3, 3, 11, 9, 25, 11, 1, 203, 353, 1347, 1999, 2799}},
+{1065, 13, 3786, {1, 3, 5, 1, 7, 49, 101, 231, 499, 63, 1977, 2207, 7829}},
+{1066, 13, 3800, {1, 1, 7, 1, 17, 15, 115, 139, 381, 943, 623, 4037, 2971}},
+{1067, 13, 3803, {1, 1, 3, 5, 13, 55, 23, 87, 139, 795, 1669, 1375, 1185}},
+{1068, 13, 3809, {1, 3, 3, 5, 5, 45, 97, 253, 241, 333, 645, 555, 7867}},
+{1069, 13, 3816, {1, 3, 5, 1, 1, 1, 89, 27, 407, 509, 1433, 609, 2355}},
+{1070, 13, 3821, {1, 3, 7, 1, 27, 29, 5, 157, 495, 811, 1293, 1143, 827}},
+{1071, 13, 3827, {1, 1, 3, 3, 25, 49, 127, 111, 191, 3, 845, 1383, 2521}},
+{1072, 13, 3829, {1, 1, 5, 7, 5, 51, 101, 155, 237, 461, 831, 3091, 3851}},
+{1073, 13, 3836, {1, 3, 7, 1, 29, 35, 105, 91, 285, 705, 131, 395, 6011}},
+{1074, 13, 3842, {1, 3, 5, 3, 13, 21, 83, 173, 221, 827, 1775, 1931, 6727}},
+{1075, 13, 3844, {1, 1, 3, 5, 3, 25, 95, 115, 205, 569, 1447, 933, 6425}},
+{1076, 13, 3847, {1, 1, 7, 9, 31, 3, 17, 175, 145, 447, 1321, 1069, 6527}},
+{1077, 13, 3853, {1, 1, 3, 3, 23, 1, 79, 51, 421, 419, 873, 3939, 1801}},
+{1078, 13, 3861, {1, 1, 5, 1, 3, 39, 15, 85, 169, 669, 919, 397, 5579}},
+{1079, 13, 3871, {1, 3, 5, 1, 21, 61, 87, 217, 251, 619, 1091, 4009, 229}},
+{1080, 13, 3872, {1, 1, 1, 11, 23, 55, 85, 121, 363, 867, 315, 447, 3373}},
+{1081, 13, 3881, {1, 3, 3, 13, 29, 19, 89, 85, 137, 469, 1873, 2765, 3975}},
+{1082, 13, 3890, {1, 3, 7, 13, 19, 63, 61, 77, 67, 361, 11, 1787, 4703}},
+{1083, 13, 3892, {1, 1, 3, 11, 7, 15, 127, 105, 179, 857, 1671, 3647, 3389}},
+{1084, 13, 3909, {1, 1, 1, 7, 19, 21, 99, 161, 499, 519, 1287, 2973, 479}},
+{1085, 13, 3921, {1, 1, 3, 13, 29, 51, 95, 251, 55, 519, 1955, 2881, 5951}},
+{1086, 13, 3934, {1, 1, 3, 11, 23, 63, 121, 237, 175, 311, 701, 1539, 2383}},
+{1087, 13, 3938, {1, 1, 7, 5, 5, 45, 73, 97, 5, 153, 715, 2037, 3353}},
+{1088, 13, 3947, {1, 1, 1, 3, 13, 7, 67, 173, 425, 843, 1497, 2729, 5193}},
+{1089, 13, 3950, {1, 1, 7, 1, 23, 3, 119, 11, 77, 141, 1905, 2269, 4269}},
+{1090, 13, 3952, {1, 1, 7, 15, 1, 23, 79, 251, 439, 603, 405, 2449, 6383}},
+{1091, 13, 3964, {1, 3, 7, 11, 29, 27, 47, 255, 47, 661, 1967, 1007, 3689}},
+{1092, 13, 3974, {1, 3, 7, 5, 19, 39, 35, 115, 417, 373, 291, 329, 603}},
+{1093, 13, 3980, {1, 3, 1, 9, 11, 33, 27, 193, 207, 423, 1311, 1369, 7307}},
+{1094, 13, 3983, {1, 1, 3, 11, 9, 29, 83, 17, 497, 493, 329, 3141, 5935}},
+{1095, 13, 3986, {1, 3, 1, 5, 31, 51, 29, 171, 51, 493, 1621, 3501, 4091}},
+{1096, 13, 3995, {1, 1, 5, 9, 21, 43, 105, 207, 245, 363, 1191, 699, 1139}},
+{1097, 13, 3998, {1, 1, 3, 11, 19, 5, 81, 119, 247, 169, 1337, 45, 6565}},
+{1098, 13, 4001, {1, 3, 1, 11, 3, 51, 3, 101, 159, 11, 253, 299, 5043}},
+{1099, 13, 4002, {1, 3, 1, 5, 11, 53, 85, 39, 57, 645, 2007, 1039, 3627}},
+{1100, 13, 4004, {1, 3, 5, 3, 17, 61, 97, 165, 415, 357, 283, 601, 5505}},
+{1101, 13, 4008, {1, 3, 7, 3, 9, 51, 49, 85, 3, 227, 137, 309, 243}},
+{1102, 13, 4011, {1, 1, 5, 3, 11, 59, 11, 131, 409, 703, 455, 123, 6727}},
+{1103, 13, 4016, {1, 3, 7, 9, 25, 49, 21, 171, 287, 379, 667, 313, 713}},
+{1104, 13, 4033, {1, 1, 3, 9, 7, 35, 47, 3, 367, 581, 1627, 1665, 3905}},
+{1105, 13, 4036, {1, 3, 1, 1, 29, 57, 35, 55, 255, 653, 823, 2197, 6179}},
+{1106, 13, 4040, {1, 3, 7, 15, 17, 15, 117, 83, 359, 163, 115, 2999, 5373}},
+{1107, 13, 4053, {1, 1, 5, 3, 21, 61, 35, 97, 71, 687, 207, 2917, 1049}},
+{1108, 13, 4058, {1, 1, 1, 15, 13, 15, 125, 81, 263, 661, 417, 3243, 1669}},
+{1109, 13, 4081, {1, 1, 7, 3, 3, 19, 111, 193, 443, 339, 659, 1211, 1557}},
+{1110, 13, 4091, {1, 3, 1, 3, 27, 3, 3, 173, 391, 213, 803, 3281, 3207}},
+{1111, 13, 4094, {1, 1, 5, 15, 19, 1, 7, 211, 157, 603, 403, 1387, 1583}},
+{1112, 14, 21, {1, 3, 5, 13, 17, 53, 125, 13, 339, 723, 521, 413, 5801, 10451}},
+{1113, 14, 28, {1, 1, 3, 13, 29, 9, 99, 77, 141, 609, 1533, 983, 2039, 51}},
+{1114, 14, 41, {1, 1, 3, 11, 21, 55, 5, 51, 423, 309, 525, 3715, 3025, 15055}},
+{1115, 14, 47, {1, 1, 3, 7, 9, 21, 77, 171, 239, 341, 1653, 1093, 2273, 10723}},
+{1116, 14, 61, {1, 1, 1, 15, 31, 15, 23, 35, 317, 869, 1917, 1415, 4313, 3687}},
+{1117, 14, 84, {1, 1, 1, 5, 21, 25, 99, 167, 439, 453, 473, 431, 6665, 4989}},
+{1118, 14, 87, {1, 1, 7, 9, 31, 47, 81, 83, 345, 43, 1363, 1885, 3155, 3185}},
+{1119, 14, 93, {1, 3, 7, 1, 31, 17, 61, 185, 341, 129, 547, 717, 2071, 9991}},
+{1120, 14, 94, {1, 3, 1, 13, 23, 61, 77, 217, 455, 77, 1263, 1601, 3501, 14953}},
+{1121, 14, 103, {1, 1, 7, 7, 19, 19, 1, 229, 431, 943, 1069, 1949, 1289, 15729}},
+{1122, 14, 117, {1, 1, 3, 5, 1, 35, 97, 251, 487, 459, 1265, 1739, 165, 10365}},
+{1123, 14, 121, {1, 3, 5, 3, 11, 25, 79, 175, 383, 545, 187, 197, 4329, 3363}},
+{1124, 14, 134, {1, 1, 3, 3, 29, 9, 63, 55, 175, 277, 431, 2549, 2629, 6409}},
+{1125, 14, 137, {1, 1, 3, 15, 17, 21, 79, 139, 99, 135, 1763, 1805, 3471, 5439}},
+{1126, 14, 157, {1, 1, 3, 9, 9, 15, 35, 119, 289, 835, 769, 3843, 4119, 4421}},
+{1127, 14, 161, {1, 1, 1, 5, 19, 19, 67, 199, 307, 815, 1367, 1231, 3927, 6593}},
+{1128, 14, 205, {1, 1, 3, 1, 29, 51, 121, 209, 431, 47, 1115, 907, 2535, 9755}},
+{1129, 14, 206, {1, 1, 3, 5, 17, 1, 5, 119, 121, 223, 1719, 1291, 3947, 15891}},
+{1130, 14, 211, {1, 3, 1, 15, 29, 25, 3, 131, 373, 307, 645, 3513, 1289, 1987}},
+{1131, 14, 214, {1, 3, 3, 11, 29, 45, 105, 179, 331, 465, 891, 1315, 403, 3057}},
+{1132, 14, 218, {1, 1, 5, 13, 17, 59, 77, 127, 485, 855, 1147, 3093, 891, 9869}},
+{1133, 14, 234, {1, 1, 1, 7, 23, 27, 31, 203, 285, 463, 827, 685, 1349, 15051}},
+{1134, 14, 236, {1, 1, 1, 5, 29, 5, 107, 195, 31, 425, 19, 2865, 3869, 11153}},
+{1135, 14, 248, {1, 1, 7, 5, 7, 47, 1, 73, 307, 347, 393, 2205, 7709, 15121}},
+{1136, 14, 262, {1, 1, 1, 13, 15, 61, 25, 131, 113, 369, 1995, 2527, 4475, 1745}},
+{1137, 14, 299, {1, 1, 1, 1, 31, 63, 21, 253, 307, 281, 859, 3319, 6721, 2891}},
+{1138, 14, 304, {1, 1, 3, 11, 1, 17, 5, 183, 301, 979, 651, 1685, 6343, 10067}},
+{1139, 14, 319, {1, 1, 5, 15, 23, 45, 99, 145, 263, 507, 1381, 3425, 2215, 1815}},
+{1140, 14, 322, {1, 3, 1, 5, 11, 63, 85, 203, 411, 881, 1369, 1237, 4657, 6541}},
+{1141, 14, 334, {1, 3, 3, 13, 17, 53, 121, 201, 269, 983, 215, 3187, 7121, 6111}},
+{1142, 14, 355, {1, 3, 5, 15, 15, 5, 13, 143, 3, 313, 1677, 1093, 3295, 3387}},
+{1143, 14, 357, {1, 1, 3, 13, 3, 23, 73, 17, 257, 965, 239, 1271, 2803, 7327}},
+{1144, 14, 358, {1, 3, 5, 13, 9, 57, 115, 37, 41, 467, 135, 1403, 3811, 4741}},
+{1145, 14, 369, {1, 3, 7, 15, 9, 33, 39, 203, 351, 367, 1355, 1403, 3685, 4757}},
+{1146, 14, 372, {1, 3, 5, 11, 31, 3, 113, 123, 203, 421, 1821, 3151, 2375, 4419}},
+{1147, 14, 375, {1, 1, 1, 7, 21, 63, 99, 23, 133, 79, 991, 1755, 4989, 4709}},
+{1148, 14, 388, {1, 3, 5, 1, 25, 63, 113, 239, 49, 443, 173, 1261, 3201, 10599}},
+{1149, 14, 400, {1, 3, 3, 13, 3, 25, 101, 169, 23, 585, 327, 1327, 111, 10059}},
+{1150, 14, 415, {1, 3, 3, 5, 19, 1, 33, 89, 437, 213, 1933, 1741, 2603, 5625}},
+{1151, 14, 446, {1, 3, 1, 3, 15, 15, 25, 139, 73, 335, 237, 2461, 3101, 14951}},
+{1152, 14, 451, {1, 3, 5, 1, 31, 15, 31, 187, 177, 659, 1339, 3767, 4975, 7123}},
+{1153, 14, 458, {1, 3, 1, 3, 25, 19, 47, 89, 107, 107, 649, 683, 3123, 11085}},
+{1154, 14, 471, {1, 3, 7, 9, 15, 21, 101, 25, 11, 625, 1555, 675, 3893, 5805}},
+{1155, 14, 484, {1, 1, 1, 5, 7, 49, 123, 21, 439, 369, 207, 535, 4619, 14665}},
+{1156, 14, 501, {1, 1, 5, 7, 1, 25, 103, 185, 99, 239, 1093, 1561, 6177, 4039}},
+{1157, 14, 502, {1, 3, 7, 5, 29, 21, 43, 103, 343, 973, 1561, 2975, 7467, 7947}},
+{1158, 14, 517, {1, 1, 7, 9, 19, 3, 13, 23, 461, 813, 1191, 985, 559, 3317}},
+{1159, 14, 545, {1, 3, 5, 5, 27, 31, 79, 15, 365, 901, 1949, 117, 3619, 13311}},
+{1160, 14, 569, {1, 3, 5, 7, 5, 33, 67, 199, 425, 189, 1691, 3099, 815, 1677}},
+{1161, 14, 617, {1, 1, 7, 11, 13, 29, 73, 137, 265, 601, 445, 3893, 2511, 8047}},
+{1162, 14, 618, {1, 1, 3, 1, 13, 5, 57, 101, 357, 391, 335, 601, 1359, 1065}},
+{1163, 14, 623, {1, 1, 1, 1, 25, 57, 27, 115, 31, 873, 611, 2125, 447, 13585}},
+{1164, 14, 625, {1, 3, 3, 13, 27, 17, 73, 11, 359, 33, 1153, 271, 4537, 15141}},
+{1165, 14, 637, {1, 3, 7, 3, 11, 63, 103, 61, 59, 629, 1629, 3279, 3919, 3177}},
+{1166, 14, 661, {1, 1, 5, 15, 3, 63, 85, 193, 381, 165, 175, 3247, 2501, 4209}},
+{1167, 14, 668, {1, 1, 5, 15, 1, 33, 59, 219, 487, 193, 1557, 703, 2907, 7953}},
+{1168, 14, 684, {1, 1, 7, 3, 9, 3, 105, 95, 389, 991, 21, 3841, 6983, 285}},
+{1169, 14, 695, {1, 1, 1, 1, 1, 31, 25, 137, 117, 67, 1283, 1963, 6591, 15541}},
+{1170, 14, 716, {1, 3, 5, 11, 7, 15, 127, 89, 453, 777, 1827, 2311, 7661, 11833}},
+{1171, 14, 719, {1, 1, 7, 13, 19, 29, 79, 165, 223, 453, 2039, 3961, 6467, 5481}},
+{1172, 14, 722, {1, 3, 3, 7, 17, 41, 43, 157, 323, 3, 1001, 2109, 4513, 12127}},
+{1173, 14, 731, {1, 1, 5, 9, 31, 57, 3, 217, 113, 271, 1663, 1367, 6949, 8165}},
+{1174, 14, 738, {1, 1, 7, 15, 27, 35, 81, 235, 61, 205, 525, 311, 6357, 2527}},
+{1175, 14, 747, {1, 3, 1, 9, 19, 29, 71, 207, 321, 1011, 1615, 1333, 3459, 6681}},
+{1176, 14, 755, {1, 3, 7, 7, 3, 57, 41, 19, 25, 397, 565, 1837, 7625, 11813}},
+{1177, 14, 761, {1, 3, 3, 1, 27, 47, 31, 79, 441, 961, 1255, 423, 2405, 913}},
+{1178, 14, 767, {1, 3, 3, 13, 3, 29, 69, 227, 85, 201, 395, 3199, 3869, 13099}},
+{1179, 14, 775, {1, 3, 3, 7, 29, 61, 99, 7, 27, 227, 945, 873, 475, 4363}},
+{1180, 14, 782, {1, 3, 5, 13, 19, 21, 57, 149, 217, 443, 565, 453, 5487, 10981}},
+{1181, 14, 787, {1, 3, 3, 1, 9, 27, 47, 191, 35, 395, 1429, 4079, 6871, 8013}},
+{1182, 14, 794, {1, 3, 5, 15, 5, 43, 9, 79, 279, 563, 1125, 985, 8117, 4099}},
+{1183, 14, 803, {1, 3, 5, 1, 13, 41, 21, 117, 287, 667, 701, 1483, 8167, 13283}},
+{1184, 14, 812, {1, 3, 1, 3, 15, 15, 59, 5, 383, 509, 1657, 3977, 7697, 10941}},
+{1185, 14, 817, {1, 3, 1, 1, 17, 29, 19, 23, 377, 45, 981, 1631, 3557, 6749}},
+{1186, 14, 824, {1, 3, 3, 9, 9, 51, 9, 193, 345, 361, 1679, 3333, 713, 5387}},
+{1187, 14, 829, {1, 3, 5, 5, 17, 45, 97, 17, 385, 349, 105, 2245, 7295, 14393}},
+{1188, 14, 850, {1, 3, 7, 3, 19, 51, 35, 99, 79, 301, 1563, 399, 5879, 14675}},
+{1189, 14, 866, {1, 1, 7, 15, 13, 53, 55, 203, 417, 161, 2033, 1845, 6763, 3585}},
+{1190, 14, 871, {1, 1, 3, 3, 7, 23, 11, 43, 241, 309, 1453, 3147, 2619, 3163}},
+{1191, 14, 877, {1, 1, 1, 11, 17, 1, 17, 137, 443, 465, 993, 3217, 7879, 14607}},
+{1192, 14, 920, {1, 1, 7, 13, 29, 49, 71, 217, 291, 793, 135, 21, 2503, 11091}},
+{1193, 14, 935, {1, 3, 1, 11, 31, 51, 121, 227, 377, 157, 1457, 1317, 5625, 6217}},
+{1194, 14, 959, {1, 1, 3, 7, 23, 61, 47, 93, 79, 617, 1805, 2403, 5513, 16335}},
+{1195, 14, 979, {1, 3, 5, 11, 23, 25, 41, 11, 495, 587, 1223, 3107, 1469, 15223}},
+{1196, 14, 992, {1, 3, 7, 7, 9, 1, 1, 49, 23, 723, 1761, 3717, 7375, 10875}},
+{1197, 14, 1010, {1, 3, 3, 11, 25, 37, 57, 63, 309, 603, 183, 285, 1663, 5627}},
+{1198, 14, 1012, {1, 3, 7, 11, 19, 25, 25, 201, 391, 257, 529, 1645, 1, 15111}},
+{1199, 14, 1015, {1, 3, 3, 9, 11, 43, 91, 65, 5, 959, 301, 1015, 6343, 3453}},
+{1200, 14, 1033, {1, 3, 3, 11, 17, 17, 103, 37, 77, 973, 575, 439, 49, 3639}},
+{1201, 14, 1036, {1, 1, 5, 7, 1, 15, 107, 237, 231, 967, 923, 1101, 6715, 1713}},
+{1202, 14, 1053, {1, 3, 1, 15, 9, 33, 29, 211, 245, 601, 1783, 887, 1209, 11785}},
+{1203, 14, 1057, {1, 3, 3, 7, 21, 43, 27, 89, 27, 141, 865, 367, 1379, 4063}},
+{1204, 14, 1069, {1, 3, 7, 7, 15, 17, 15, 15, 131, 649, 1955, 3289, 3983, 10689}},
+{1205, 14, 1072, {1, 3, 1, 5, 17, 7, 125, 69, 359, 981, 1345, 933, 5281, 7113}},
+{1206, 14, 1075, {1, 1, 5, 9, 17, 7, 41, 207, 497, 1015, 493, 891, 3563, 3541}},
+{1207, 14, 1087, {1, 3, 5, 11, 27, 3, 47, 31, 303, 1007, 2047, 2203, 6257, 8369}},
+{1208, 14, 1089, {1, 1, 1, 15, 25, 15, 89, 51, 217, 357, 1133, 1917, 213, 3365}},
+{1209, 14, 1137, {1, 1, 5, 13, 29, 23, 123, 207, 429, 805, 819, 2357, 6313, 11019}},
+{1210, 14, 1166, {1, 1, 3, 7, 19, 15, 41, 73, 279, 11, 1089, 3107, 7737, 15953}},
+{1211, 14, 1174, {1, 3, 5, 7, 7, 15, 41, 73, 493, 457, 1731, 1139, 2513, 12373}},
+{1212, 14, 1180, {1, 3, 5, 9, 17, 5, 55, 155, 173, 1005, 529, 3175, 7667, 4747}},
+{1213, 14, 1204, {1, 1, 7, 7, 5, 21, 105, 31, 205, 847, 1033, 3167, 2347, 8499}},
+{1214, 14, 1211, {1, 3, 5, 3, 11, 17, 59, 189, 179, 1007, 33, 3287, 4813, 8177}},
+{1215, 14, 1219, {1, 3, 3, 13, 27, 47, 47, 171, 413, 875, 1081, 1259, 7139, 8645}},
+{1216, 14, 1236, {1, 3, 5, 7, 25, 21, 51, 29, 361, 293, 51, 1119, 1453, 5283}},
+{1217, 14, 1255, {1, 3, 7, 7, 29, 55, 103, 199, 511, 341, 1957, 3987, 2855, 1279}},
+{1218, 14, 1264, {1, 1, 1, 9, 23, 51, 61, 63, 391, 37, 55, 3771, 6517, 15913}},
+{1219, 14, 1306, {1, 1, 1, 9, 3, 19, 13, 147, 453, 855, 1321, 189, 5043, 11215}},
+{1220, 14, 1330, {1, 3, 3, 13, 23, 3, 87, 155, 401, 981, 607, 3413, 995, 6473}},
+{1221, 14, 1341, {1, 3, 1, 9, 29, 47, 95, 123, 421, 353, 1867, 2609, 2569, 14083}},
+{1222, 14, 1344, {1, 1, 5, 13, 25, 39, 29, 111, 125, 545, 1493, 2371, 6361, 6307}},
+{1223, 14, 1347, {1, 3, 3, 11, 13, 31, 87, 75, 27, 393, 921, 3655, 3343, 16349}},
+{1224, 14, 1349, {1, 1, 5, 9, 19, 19, 7, 129, 223, 715, 433, 1627, 4463, 2951}},
+{1225, 14, 1361, {1, 1, 7, 1, 31, 13, 49, 33, 89, 43, 1529, 725, 3809, 3427}},
+{1226, 14, 1380, {1, 1, 7, 3, 1, 27, 45, 9, 309, 875, 659, 2661, 553, 7069}},
+{1227, 14, 1390, {1, 1, 7, 15, 13, 37, 61, 19, 125, 683, 1227, 2255, 1455, 9339}},
+{1228, 14, 1404, {1, 3, 5, 7, 19, 7, 71, 21, 465, 645, 1885, 873, 7405, 1913}},
+{1229, 14, 1435, {1, 3, 1, 11, 11, 35, 79, 61, 79, 57, 1603, 3719, 6323, 16371}},
+{1230, 14, 1444, {1, 1, 7, 1, 29, 57, 85, 21, 205, 37, 2045, 683, 4901, 8223}},
+{1231, 14, 1453, {1, 1, 5, 13, 31, 31, 65, 131, 259, 535, 967, 3943, 2605, 2089}},
+{1232, 14, 1461, {1, 1, 7, 9, 27, 61, 39, 243, 207, 41, 1909, 3279, 1331, 4635}},
+{1233, 14, 1462, {1, 3, 3, 5, 11, 63, 105, 19, 169, 95, 773, 3175, 1869, 1797}},
+{1234, 14, 1465, {1, 3, 3, 15, 13, 33, 107, 197, 153, 795, 1477, 105, 4965, 991}},
+{1235, 14, 1468, {1, 3, 7, 11, 11, 37, 23, 149, 197, 3, 1035, 3857, 553, 1059}},
+{1236, 14, 1474, {1, 3, 1, 3, 17, 29, 89, 189, 193, 59, 1477, 3517, 2565, 7739}},
+{1237, 14, 1483, {1, 1, 1, 9, 23, 3, 25, 163, 469, 305, 1791, 3393, 6141, 8119}},
+{1238, 14, 1488, {1, 3, 5, 7, 7, 41, 19, 101, 179, 487, 1071, 2761, 8043, 5103}},
+{1239, 14, 1493, {1, 1, 7, 9, 1, 21, 101, 103, 349, 85, 1841, 1033, 4473, 3563}},
+{1240, 14, 1500, {1, 1, 3, 13, 23, 61, 39, 27, 479, 13, 45, 1371, 7897, 10637}},
+{1241, 14, 1509, {1, 1, 5, 9, 17, 61, 71, 55, 355, 99, 1695, 3053, 839, 959}},
+{1242, 14, 1510, {1, 1, 3, 1, 7, 27, 87, 221, 327, 241, 461, 3177, 5933, 8299}},
+{1243, 14, 1514, {1, 3, 7, 9, 5, 41, 111, 245, 447, 263, 1363, 1767, 6331, 3355}},
+{1244, 14, 1519, {1, 3, 3, 13, 15, 11, 15, 169, 429, 149, 1965, 2477, 7733, 2499}},
+{1245, 14, 1528, {1, 1, 5, 15, 15, 47, 25, 33, 469, 701, 773, 2747, 1533, 14633}},
+{1246, 14, 1533, {1, 3, 1, 5, 19, 57, 37, 75, 423, 11, 685, 2487, 1779, 8797}},
+{1247, 14, 1540, {1, 3, 1, 5, 19, 41, 67, 99, 333, 991, 953, 3221, 939, 4197}},
+{1248, 14, 1550, {1, 3, 1, 15, 11, 39, 25, 1, 159, 679, 465, 1611, 5799, 2537}},
+{1249, 14, 1567, {1, 1, 5, 11, 5, 37, 37, 7, 101, 703, 235, 23, 2209, 12799}},
+{1250, 14, 1571, {1, 1, 7, 3, 11, 23, 71, 215, 45, 269, 1539, 3625, 5773, 6889}},
+{1251, 14, 1573, {1, 3, 5, 15, 27, 33, 105, 109, 205, 653, 821, 435, 1087, 2495}},
+{1252, 14, 1578, {1, 1, 3, 5, 11, 39, 53, 213, 41, 385, 1425, 25, 5553, 12523}},
+{1253, 14, 1598, {1, 3, 5, 15, 29, 49, 13, 253, 505, 407, 985, 2569, 6727, 4761}},
+{1254, 14, 1606, {1, 1, 1, 3, 29, 17, 69, 47, 25, 819, 1145, 2479, 1183, 3343}},
+{1255, 14, 1618, {1, 3, 1, 15, 25, 61, 43, 55, 279, 579, 361, 355, 6101, 3143}},
+{1256, 14, 1630, {1, 3, 5, 11, 3, 59, 125, 101, 451, 495, 1711, 3443, 3625, 15579}},
+{1257, 14, 1634, {1, 3, 1, 11, 25, 61, 49, 219, 23, 795, 481, 3609, 3691, 15419}},
+{1258, 14, 1640, {1, 3, 7, 5, 9, 59, 49, 233, 345, 143, 181, 3587, 3041, 1219}},
+{1259, 14, 1643, {1, 3, 7, 13, 9, 31, 39, 137, 261, 919, 1367, 3145, 4659, 5875}},
+{1260, 14, 1654, {1, 1, 3, 3, 27, 43, 95, 65, 301, 915, 31, 451, 7743, 7277}},
+{1261, 14, 1679, {1, 3, 1, 5, 23, 37, 53, 31, 203, 453, 71, 1585, 6011, 16369}},
+{1262, 14, 1688, {1, 1, 5, 1, 15, 47, 91, 227, 297, 45, 1415, 3647, 7811, 14015}},
+{1263, 14, 1698, {1, 1, 1, 1, 29, 27, 93, 121, 169, 69, 1361, 2907, 1867, 7017}},
+{1264, 14, 1703, {1, 3, 1, 7, 23, 53, 77, 41, 25, 873, 1333, 3889, 3239, 1771}},
+{1265, 14, 1704, {1, 1, 1, 7, 31, 27, 87, 81, 167, 343, 1981, 2499, 7749, 15747}},
+{1266, 14, 1722, {1, 3, 5, 13, 1, 17, 97, 37, 81, 645, 1167, 3547, 7769, 10731}},
+{1267, 14, 1735, {1, 1, 7, 5, 9, 17, 31, 55, 151, 463, 1041, 2303, 4015, 3737}},
+{1268, 14, 1750, {1, 1, 3, 11, 31, 9, 81, 213, 95, 215, 2031, 2129, 4299, 3021}},
+{1269, 14, 1753, {1, 1, 1, 3, 25, 25, 115, 229, 101, 441, 783, 1729, 7905, 2375}},
+{1270, 14, 1760, {1, 1, 5, 9, 3, 19, 73, 35, 379, 493, 1333, 1647, 13, 197}},
+{1271, 14, 1789, {1, 1, 7, 9, 3, 55, 99, 43, 281, 9, 73, 2477, 8183, 11055}},
+{1272, 14, 1792, {1, 3, 7, 13, 25, 19, 27, 195, 469, 175, 355, 1861, 7255, 15377}},
+{1273, 14, 1802, {1, 1, 3, 11, 15, 19, 115, 31, 413, 835, 697, 879, 6515, 13465}},
+{1274, 14, 1819, {1, 3, 3, 15, 3, 61, 105, 201, 151, 739, 49, 3963, 2573, 3303}},
+{1275, 14, 1825, {1, 3, 5, 7, 23, 5, 11, 215, 19, 591, 509, 2887, 1631, 4391}},
+{1276, 14, 1828, {1, 3, 3, 3, 25, 1, 109, 5, 363, 545, 1745, 503, 827, 4677}},
+{1277, 14, 1832, {1, 1, 3, 15, 1, 45, 121, 141, 497, 745, 1825, 2041, 2561, 8153}},
+{1278, 14, 1845, {1, 3, 1, 11, 29, 7, 71, 241, 7, 39, 1379, 2479, 7483, 7195}},
+{1279, 14, 1846, {1, 1, 7, 11, 3, 27, 39, 97, 339, 217, 1409, 1569, 4761, 1567}},
+{1280, 14, 1857, {1, 1, 5, 15, 11, 53, 87, 213, 297, 923, 393, 717, 3297, 16123}},
+{1281, 14, 1869, {1, 1, 1, 11, 27, 41, 121, 49, 225, 379, 1305, 319, 2461, 5445}},
+{1282, 14, 1897, {1, 1, 5, 5, 25, 3, 121, 23, 47, 843, 1679, 1427, 6393, 4199}},
+{1283, 14, 1906, {1, 1, 5, 13, 17, 3, 17, 25, 161, 487, 121, 361, 1375, 10745}},
+{1284, 14, 1908, {1, 1, 7, 3, 3, 37, 7, 245, 107, 107, 745, 2415, 2131, 11419}},
+{1285, 14, 1911, {1, 1, 5, 3, 3, 23, 67, 91, 281, 387, 465, 905, 883, 9775}},
+{1286, 14, 1934, {1, 3, 7, 15, 25, 55, 123, 49, 23, 983, 1903, 2589, 2073, 7823}},
+{1287, 14, 1962, {1, 1, 5, 11, 25, 17, 63, 229, 267, 175, 1759, 1947, 479, 11089}},
+{1288, 14, 1967, {1, 3, 7, 3, 11, 37, 83, 95, 415, 1003, 1175, 2361, 2117, 9809}},
+{1289, 14, 1972, {1, 3, 1, 9, 5, 39, 51, 129, 249, 161, 1981, 2755, 8057, 13641}},
+{1290, 14, 1975, {1, 1, 7, 1, 15, 47, 9, 197, 199, 549, 1091, 2853, 2331, 4535}},
+{1291, 14, 1999, {1, 3, 3, 13, 15, 21, 23, 111, 463, 719, 1667, 377, 5039, 10723}},
+{1292, 14, 2004, {1, 1, 3, 7, 23, 47, 39, 47, 307, 949, 1651, 2525, 5835, 1425}},
+{1293, 14, 2011, {1, 3, 3, 9, 23, 47, 111, 39, 251, 1001, 179, 3985, 535, 15435}},
+{1294, 14, 2013, {1, 1, 3, 13, 5, 45, 51, 123, 205, 651, 1583, 1691, 1631, 11975}},
+{1295, 14, 2037, {1, 1, 7, 9, 1, 29, 59, 27, 389, 497, 1459, 1633, 521, 14037}},
+{1296, 14, 2051, {1, 1, 3, 3, 3, 23, 35, 247, 371, 729, 931, 681, 1777, 8353}},
+{1297, 14, 2063, {1, 3, 3, 1, 19, 15, 17, 191, 495, 643, 319, 37, 5691, 7049}},
+{1298, 14, 2066, {1, 3, 5, 11, 5, 31, 123, 243, 335, 573, 113, 209, 4825, 7783}},
+{1299, 14, 2094, {1, 3, 7, 7, 29, 19, 25, 191, 89, 515, 55, 3013, 4523, 12913}},
+{1300, 14, 2128, {1, 1, 3, 3, 15, 3, 35, 37, 339, 7, 697, 359, 4553, 1431}},
+{1301, 14, 2154, {1, 3, 1, 1, 9, 15, 33, 77, 161, 13, 255, 1187, 6587, 11715}},
+{1302, 14, 2164, {1, 3, 7, 7, 25, 57, 61, 171, 231, 43, 1219, 903, 5623, 4781}},
+{1303, 14, 2198, {1, 1, 5, 15, 29, 47, 117, 23, 213, 907, 1423, 369, 4529, 9651}},
+{1304, 14, 2217, {1, 1, 5, 7, 15, 55, 105, 249, 401, 37, 1885, 3779, 3441, 9057}},
+{1305, 14, 2220, {1, 1, 5, 3, 3, 27, 49, 89, 335, 561, 1235, 3251, 2731, 12711}},
+{1306, 14, 2223, {1, 1, 1, 15, 29, 49, 37, 173, 25, 743, 1321, 821, 5899, 9213}},
+{1307, 14, 2238, {1, 1, 7, 3, 1, 41, 61, 209, 275, 925, 521, 3029, 1569, 9277}},
+{1308, 14, 2245, {1, 3, 5, 13, 17, 1, 11, 171, 441, 119, 1589, 299, 157, 11439}},
+{1309, 14, 2252, {1, 1, 5, 9, 13, 33, 27, 77, 363, 939, 1103, 2135, 1759, 5429}},
+{1310, 14, 2258, {1, 3, 7, 1, 17, 39, 49, 201, 49, 803, 2003, 1193, 7415, 13847}},
+{1311, 14, 2264, {1, 1, 5, 5, 17, 49, 39, 19, 311, 801, 1441, 3263, 7973, 14181}},
+{1312, 14, 2280, {1, 1, 3, 9, 9, 27, 59, 89, 81, 473, 1369, 3121, 7929, 10905}},
+{1313, 14, 2285, {1, 3, 3, 5, 17, 35, 35, 239, 379, 431, 501, 3561, 2059, 9679}},
+{1314, 14, 2293, {1, 3, 5, 15, 25, 29, 113, 179, 269, 891, 301, 2017, 7513, 9379}},
+{1315, 14, 2294, {1, 3, 1, 11, 17, 35, 49, 149, 135, 661, 1691, 3169, 3765, 9003}},
+{1316, 14, 2298, {1, 3, 7, 15, 5, 21, 53, 241, 475, 271, 683, 2351, 2181, 6333}},
+{1317, 14, 2303, {1, 1, 7, 13, 25, 33, 71, 153, 221, 507, 2017, 2401, 7545, 8489}},
+{1318, 14, 2306, {1, 1, 7, 5, 1, 49, 87, 1, 179, 331, 1597, 3713, 809, 11109}},
+{1319, 14, 2311, {1, 3, 1, 5, 5, 61, 93, 39, 479, 977, 1099, 1291, 7049, 2797}},
+{1320, 14, 2326, {1, 3, 1, 13, 19, 41, 57, 77, 5, 117, 125, 115, 3969, 1345}},
+{1321, 14, 2354, {1, 1, 1, 9, 15, 9, 57, 7, 219, 41, 767, 23, 5771, 14175}},
+{1322, 14, 2373, {1, 3, 7, 9, 17, 61, 1, 59, 227, 349, 63, 189, 3871, 7919}},
+{1323, 14, 2380, {1, 3, 5, 5, 9, 29, 33, 203, 413, 701, 1129, 2103, 1889, 8377}},
+{1324, 14, 2385, {1, 1, 3, 1, 9, 17, 69, 115, 123, 1001, 1, 2893, 3957, 8593}},
+{1325, 14, 2392, {1, 1, 3, 1, 31, 41, 83, 91, 113, 195, 1121, 2665, 6815, 1189}},
+{1326, 14, 2401, {1, 1, 1, 13, 3, 59, 13, 123, 95, 103, 1689, 2809, 5049, 4055}},
+{1327, 14, 2402, {1, 1, 1, 15, 21, 41, 11, 167, 375, 589, 207, 1631, 1597, 8091}},
+{1328, 14, 2408, {1, 3, 5, 5, 1, 33, 57, 89, 157, 921, 1353, 2777, 461, 14567}},
+{1329, 14, 2419, {1, 1, 5, 1, 25, 5, 51, 247, 1, 577, 463, 3741, 303, 16059}},
+{1330, 14, 2450, {1, 1, 7, 5, 13, 7, 17, 87, 51, 987, 835, 93, 5203, 3973}},
+{1331, 14, 2452, {1, 1, 7, 7, 3, 27, 7, 1, 135, 171, 231, 3349, 4459, 2925}},
+{1332, 14, 2477, {1, 1, 5, 5, 9, 51, 71, 153, 115, 315, 265, 2207, 4127, 12631}},
+{1333, 14, 2509, {1, 1, 3, 15, 23, 59, 35, 121, 425, 921, 1255, 2123, 5811, 15937}},
+{1334, 14, 2510, {1, 3, 7, 7, 11, 21, 45, 57, 269, 395, 555, 783, 6677, 2889}},
+{1335, 14, 2515, {1, 3, 5, 7, 31, 19, 73, 35, 465, 349, 1429, 863, 4707, 6121}},
+{1336, 14, 2524, {1, 3, 3, 9, 25, 27, 119, 159, 195, 949, 19, 73, 4511, 15711}},
+{1337, 14, 2527, {1, 3, 3, 7, 9, 59, 47, 57, 91, 749, 1579, 1297, 2445, 5167}},
+{1338, 14, 2531, {1, 3, 3, 3, 31, 57, 19, 203, 61, 927, 1477, 2863, 1305, 11673}},
+{1339, 14, 2552, {1, 3, 7, 11, 29, 13, 3, 111, 351, 79, 1863, 2213, 3273, 7049}},
+{1340, 14, 2561, {1, 3, 3, 9, 7, 23, 47, 237, 121, 877, 441, 119, 2723, 3989}},
+{1341, 14, 2567, {1, 3, 3, 11, 17, 23, 63, 177, 231, 363, 1451, 33, 2169, 7251}},
+{1342, 14, 2571, {1, 1, 5, 11, 31, 41, 93, 229, 39, 1009, 1061, 433, 2393, 15401}},
+{1343, 14, 2586, {1, 1, 5, 15, 31, 37, 25, 135, 135, 897, 33, 3713, 7663, 8079}},
+{1344, 14, 2588, {1, 1, 5, 7, 17, 49, 43, 89, 411, 731, 1431, 3893, 1635, 7063}},
+{1345, 14, 2595, {1, 1, 1, 13, 29, 27, 5, 77, 283, 913, 789, 817, 3309, 475}},
+{1346, 14, 2607, {1, 1, 3, 1, 19, 21, 67, 77, 423, 551, 5, 1057, 5469, 7859}},
+{1347, 14, 2621, {1, 1, 5, 1, 1, 21, 99, 237, 215, 759, 1505, 1983, 1517, 8923}},
+{1348, 14, 2630, {1, 3, 5, 7, 19, 61, 73, 215, 165, 127, 205, 259, 7755, 15395}},
+{1349, 14, 2639, {1, 1, 5, 9, 15, 23, 17, 111, 471, 751, 1923, 775, 6901, 13095}},
+{1350, 14, 2653, {1, 1, 7, 1, 25, 5, 63, 141, 461, 687, 1589, 1559, 7719, 11349}},
+{1351, 14, 2670, {1, 1, 1, 3, 11, 63, 11, 27, 253, 439, 297, 1315, 829, 3765}},
+{1352, 14, 2672, {1, 3, 1, 1, 9, 47, 127, 179, 173, 809, 241, 35, 7355, 5049}},
+{1353, 14, 2700, {1, 3, 1, 11, 19, 63, 93, 1, 205, 977, 303, 3409, 6529, 10927}},
+{1354, 14, 2711, {1, 3, 7, 9, 31, 63, 41, 79, 477, 91, 1801, 3487, 6885, 13341}},
+{1355, 14, 2715, {1, 1, 3, 7, 15, 59, 9, 101, 459, 247, 549, 2855, 5765, 7785}},
+{1356, 14, 2748, {1, 1, 7, 3, 13, 59, 71, 123, 93, 517, 1453, 2389, 4429, 5053}},
+{1357, 14, 2751, {1, 1, 5, 3, 19, 21, 77, 53, 81, 879, 1653, 1637, 3667, 2623}},
+{1358, 14, 2753, {1, 1, 1, 15, 17, 57, 65, 53, 407, 765, 417, 497, 5009, 2175}},
+{1359, 14, 2754, {1, 3, 3, 7, 31, 13, 5, 203, 263, 17, 119, 1607, 6773, 11195}},
+{1360, 14, 2760, {1, 3, 3, 13, 19, 13, 13, 147, 93, 735, 689, 781, 655, 6853}},
+{1361, 14, 2774, {1, 1, 1, 1, 1, 25, 63, 159, 493, 987, 71, 1249, 5859, 11717}},
+{1362, 14, 2784, {1, 1, 1, 15, 13, 23, 61, 61, 5, 947, 1853, 3331, 467, 8081}},
+{1363, 14, 2793, {1, 1, 3, 9, 19, 61, 65, 189, 95, 309, 283, 1725, 5683, 15463}},
+{1364, 14, 2804, {1, 1, 7, 5, 9, 33, 35, 75, 475, 831, 1445, 1485, 5047, 9631}},
+{1365, 14, 2811, {1, 1, 3, 15, 11, 23, 59, 87, 433, 221, 685, 3113, 4095, 13819}},
+{1366, 14, 2822, {1, 1, 7, 15, 25, 29, 67, 17, 349, 353, 1321, 563, 57, 533}},
+{1367, 14, 2826, {1, 3, 3, 3, 5, 43, 109, 217, 15, 185, 1895, 1015, 1831, 10623}},
+{1368, 14, 2836, {1, 1, 7, 1, 1, 47, 81, 185, 59, 691, 191, 3709, 1535, 13347}},
+{1369, 14, 2839, {1, 1, 5, 1, 23, 57, 83, 217, 457, 771, 1877, 2789, 8143, 4797}},
+{1370, 14, 2840, {1, 1, 3, 7, 23, 35, 79, 49, 227, 205, 1523, 3873, 4843, 10505}},
+{1371, 14, 2893, {1, 1, 1, 1, 17, 43, 121, 95, 205, 35, 189, 2061, 1693, 13273}},
+{1372, 14, 2901, {1, 1, 1, 15, 31, 49, 83, 249, 433, 497, 1949, 1845, 5215, 5971}},
+{1373, 14, 2902, {1, 3, 1, 1, 21, 53, 73, 211, 265, 929, 923, 279, 3621, 9469}},
+{1374, 14, 2905, {1, 3, 7, 7, 1, 57, 13, 45, 467, 705, 371, 1345, 1647, 3411}},
+{1375, 14, 2912, {1, 3, 1, 11, 27, 29, 117, 163, 143, 669, 489, 3913, 7891, 9031}},
+{1376, 14, 2915, {1, 3, 7, 15, 27, 15, 77, 217, 107, 839, 1517, 1543, 357, 10365}},
+{1377, 14, 2918, {1, 1, 1, 5, 31, 17, 107, 245, 345, 939, 1453, 3645, 6865, 16173}},
+{1378, 14, 2939, {1, 3, 5, 5, 9, 61, 43, 97, 453, 917, 945, 2143, 5473, 5611}},
+{1379, 14, 2965, {1, 1, 5, 11, 3, 33, 71, 97, 137, 549, 1605, 3839, 4883, 2677}},
+{1380, 14, 2966, {1, 3, 1, 11, 29, 23, 85, 47, 225, 633, 1613, 1297, 1415, 15813}},
+{1381, 14, 2975, {1, 1, 3, 3, 9, 19, 57, 107, 79, 449, 1951, 753, 6317, 10377}},
+{1382, 14, 2988, {1, 1, 1, 5, 21, 3, 39, 187, 299, 517, 1313, 741, 7259, 4197}},
+{1383, 14, 2993, {1, 1, 5, 13, 1, 39, 39, 41, 381, 123, 1257, 3185, 493, 3723}},
+{1384, 14, 3006, {1, 3, 7, 7, 3, 37, 15, 161, 129, 169, 555, 3605, 4287, 15831}},
+{1385, 14, 3017, {1, 3, 7, 15, 15, 23, 81, 163, 257, 791, 505, 1903, 2703, 11919}},
+{1386, 14, 3031, {1, 3, 7, 7, 27, 63, 17, 147, 111, 851, 1533, 1365, 5359, 3315}},
+{1387, 14, 3038, {1, 3, 7, 1, 15, 5, 61, 143, 385, 261, 1019, 1705, 1737, 14485}},
+{1388, 14, 3041, {1, 3, 5, 5, 25, 17, 49, 229, 431, 567, 1613, 3431, 2139, 2981}},
+{1389, 14, 3042, {1, 3, 5, 11, 17, 57, 71, 241, 31, 1007, 1695, 2965, 149, 14125}},
+{1390, 14, 3051, {1, 1, 3, 11, 7, 49, 39, 101, 5, 501, 1491, 3061, 225, 12255}},
+{1391, 14, 3073, {1, 3, 5, 7, 17, 35, 37, 97, 415, 15, 1349, 997, 2949, 4511}},
+{1392, 14, 3088, {1, 3, 1, 5, 25, 35, 99, 183, 161, 59, 1363, 515, 3767, 3641}},
+{1393, 14, 3097, {1, 1, 7, 15, 7, 15, 127, 137, 281, 67, 139, 2315, 3517, 13371}},
+{1394, 14, 3098, {1, 1, 5, 15, 23, 49, 19, 79, 425, 805, 1035, 429, 7707, 14195}},
+{1395, 14, 3103, {1, 3, 5, 3, 21, 25, 123, 11, 425, 475, 961, 2995, 7405, 5449}},
+{1396, 14, 3104, {1, 1, 7, 1, 21, 1, 75, 231, 451, 595, 719, 2369, 5907, 1227}},
+{1397, 14, 3146, {1, 1, 1, 9, 21, 57, 45, 255, 19, 79, 481, 3363, 3451, 8399}},
+{1398, 14, 3148, {1, 1, 7, 13, 31, 49, 95, 69, 483, 427, 37, 4047, 7057, 9111}},
+{1399, 14, 3153, {1, 3, 3, 11, 3, 61, 87, 79, 499, 91, 771, 1987, 2017, 3381}},
+{1400, 14, 3159, {1, 3, 1, 7, 5, 57, 1, 121, 155, 225, 501, 477, 6555, 9863}},
+{1401, 14, 3182, {1, 3, 7, 11, 27, 49, 83, 213, 61, 283, 1599, 3205, 2525, 8553}},
+{1402, 14, 3187, {1, 1, 1, 9, 9, 49, 3, 51, 141, 33, 301, 2167, 587, 15067}},
+{1403, 14, 3189, {1, 1, 1, 11, 7, 55, 99, 81, 191, 553, 953, 3753, 6731, 1093}},
+{1404, 14, 3199, {1, 1, 3, 3, 11, 59, 57, 235, 297, 197, 853, 1411, 3799, 7527}},
+{1405, 14, 3239, {1, 3, 5, 3, 7, 7, 5, 201, 393, 95, 91, 3273, 6285, 10661}},
+{1406, 14, 3263, {1, 1, 5, 7, 17, 57, 87, 3, 413, 915, 659, 369, 3593, 14429}},
+{1407, 14, 3271, {1, 3, 7, 1, 31, 31, 45, 115, 417, 427, 745, 4087, 953, 1119}},
+{1408, 14, 3275, {1, 3, 7, 3, 29, 43, 45, 221, 41, 641, 451, 173, 2999, 12103}},
+{1409, 14, 3278, {1, 1, 3, 11, 25, 57, 117, 201, 135, 787, 1525, 3879, 3247, 8907}},
+{1410, 14, 3280, {1, 1, 7, 11, 3, 35, 69, 157, 331, 615, 573, 2169, 3575, 289}},
+{1411, 14, 3283, {1, 3, 3, 13, 15, 51, 67, 127, 265, 495, 103, 3145, 2685, 15919}},
+{1412, 14, 3290, {1, 3, 5, 11, 31, 27, 65, 57, 153, 465, 1163, 467, 4103, 4713}},
+{1413, 14, 3311, {1, 3, 7, 3, 23, 31, 9, 51, 239, 417, 1597, 229, 2865, 15199}},
+{1414, 14, 3316, {1, 3, 5, 3, 11, 45, 123, 217, 31, 765, 1009, 2001, 3645, 9407}},
+{1415, 14, 3343, {1, 3, 3, 9, 5, 23, 117, 83, 237, 1017, 251, 1187, 2631, 5151}},
+{1416, 14, 3346, {1, 1, 1, 7, 23, 55, 97, 141, 501, 305, 467, 4061, 2369, 15973}},
+{1417, 14, 3357, {1, 1, 7, 5, 31, 51, 125, 191, 219, 495, 37, 3337, 813, 241}},
+{1418, 14, 3358, {1, 3, 1, 1, 11, 39, 93, 109, 285, 147, 1297, 737, 4051, 7223}},
+{1419, 14, 3361, {1, 3, 1, 15, 13, 17, 57, 171, 463, 163, 609, 1681, 7583, 9231}},
+{1420, 14, 3362, {1, 3, 1, 1, 23, 5, 51, 5, 205, 415, 419, 989, 4239, 10943}},
+{1421, 14, 3364, {1, 1, 3, 15, 3, 13, 65, 145, 387, 59, 395, 1067, 4143, 5649}},
+{1422, 14, 3386, {1, 3, 1, 13, 9, 59, 121, 127, 95, 71, 1541, 1423, 1753, 8041}},
+{1423, 14, 3418, {1, 1, 3, 15, 7, 5, 69, 167, 181, 991, 1189, 4017, 5935, 6669}},
+{1424, 14, 3424, {1, 3, 5, 7, 23, 41, 53, 21, 47, 261, 1231, 2011, 133, 2247}},
+{1425, 14, 3433, {1, 1, 1, 5, 17, 47, 77, 19, 331, 609, 1893, 3965, 3123, 9093}},
+{1426, 14, 3434, {1, 3, 1, 3, 9, 39, 103, 231, 249, 75, 373, 107, 1823, 10801}},
+{1427, 14, 3436, {1, 3, 3, 7, 1, 51, 35, 111, 137, 879, 1221, 225, 4285, 2287}},
+{1428, 14, 3463, {1, 1, 7, 9, 23, 17, 75, 245, 409, 163, 395, 3731, 7111, 6845}},
+{1429, 14, 3467, {1, 1, 3, 13, 29, 47, 75, 153, 497, 621, 1691, 3187, 2125, 10533}},
+{1430, 14, 3477, {1, 1, 7, 7, 9, 7, 55, 159, 255, 417, 1335, 643, 3843, 3733}},
+{1431, 14, 3484, {1, 3, 3, 1, 21, 41, 7, 21, 5, 679, 1655, 95, 5699, 5785}},
+{1432, 14, 3505, {1, 1, 1, 13, 19, 7, 85, 7, 195, 357, 1097, 2893, 2913, 9635}},
+{1433, 14, 3508, {1, 1, 5, 9, 25, 33, 41, 155, 39, 655, 1993, 3117, 3639, 7977}},
+{1434, 14, 3515, {1, 1, 1, 13, 3, 63, 121, 247, 151, 673, 609, 285, 2299, 7663}},
+{1435, 14, 3532, {1, 3, 7, 11, 17, 13, 49, 253, 245, 21, 273, 993, 911, 863}},
+{1436, 14, 3553, {1, 1, 5, 5, 23, 1, 121, 95, 225, 9, 1237, 1183, 6461, 559}},
+{1437, 14, 3554, {1, 3, 7, 13, 3, 7, 121, 151, 233, 561, 281, 3583, 897, 1767}},
+{1438, 14, 3568, {1, 1, 7, 7, 9, 47, 107, 41, 25, 569, 1697, 2299, 6231, 12209}},
+{1439, 14, 3573, {1, 3, 7, 7, 27, 43, 59, 37, 31, 51, 503, 149, 4043, 11847}},
+{1440, 14, 3587, {1, 3, 3, 11, 5, 1, 119, 181, 47, 641, 685, 4017, 637, 16251}},
+{1441, 14, 3589, {1, 3, 3, 7, 11, 1, 101, 7, 239, 747, 307, 1721, 5979, 4367}},
+{1442, 14, 3596, {1, 3, 5, 7, 1, 63, 19, 151, 469, 333, 1587, 2453, 897, 4711}},
+{1443, 14, 3608, {1, 3, 1, 5, 11, 61, 21, 253, 91, 993, 1347, 1993, 5607, 13031}},
+{1444, 14, 3620, {1, 3, 5, 5, 1, 39, 65, 71, 189, 389, 1437, 1055, 6439, 3989}},
+{1445, 14, 3630, {1, 1, 3, 3, 19, 15, 93, 3, 339, 165, 1675, 3953, 2145, 12113}},
+{1446, 14, 3644, {1, 1, 3, 13, 13, 45, 5, 175, 211, 993, 705, 2761, 3023, 13633}},
+{1447, 14, 3649, {1, 1, 3, 1, 19, 39, 121, 29, 287, 87, 281, 3491, 7107, 13007}},
+{1448, 14, 3664, {1, 1, 7, 1, 29, 49, 103, 187, 39, 923, 51, 1533, 3249, 4399}},
+{1449, 14, 3679, {1, 1, 5, 5, 5, 43, 25, 107, 453, 955, 115, 57, 4589, 14573}},
+{1450, 14, 3680, {1, 1, 3, 5, 21, 45, 103, 99, 183, 987, 1207, 1697, 8033, 13703}},
+{1451, 14, 3685, {1, 1, 5, 7, 11, 23, 9, 17, 261, 749, 1957, 935, 6283, 8625}},
+{1452, 14, 3686, {1, 1, 1, 9, 9, 51, 69, 225, 265, 323, 1161, 2993, 7305, 2249}},
+{1453, 14, 3698, {1, 3, 1, 9, 23, 19, 57, 205, 503, 489, 1499, 3277, 817, 11931}},
+{1454, 14, 3714, {1, 3, 3, 5, 1, 7, 49, 1, 313, 123, 643, 2027, 1469, 3585}},
+{1455, 14, 3726, {1, 3, 7, 11, 27, 47, 95, 111, 27, 213, 465, 3693, 3661, 7531}},
+{1456, 14, 3737, {1, 1, 7, 9, 3, 37, 115, 189, 31, 613, 1393, 1229, 4767, 12425}},
+{1457, 14, 3767, {1, 1, 3, 3, 25, 17, 99, 47, 161, 931, 959, 1293, 7095, 8325}},
+{1458, 14, 3782, {1, 1, 1, 7, 23, 9, 11, 51, 205, 419, 479, 1497, 2493, 13921}},
+{1459, 14, 3786, {1, 3, 1, 9, 17, 29, 51, 79, 159, 435, 477, 413, 3815, 5589}},
+{1460, 14, 3793, {1, 3, 7, 5, 7, 23, 99, 43, 169, 665, 403, 1163, 4337, 1335}},
+{1461, 14, 3796, {1, 3, 1, 5, 25, 27, 125, 249, 421, 267, 1259, 4089, 59, 9377}},
+{1462, 14, 3805, {1, 3, 3, 1, 27, 37, 91, 17, 123, 597, 1749, 3449, 6503, 11043}},
+{1463, 14, 3815, {1, 3, 7, 7, 23, 41, 19, 245, 109, 569, 547, 1917, 7943, 2697}},
+{1464, 14, 3841, {1, 3, 7, 7, 9, 1, 123, 105, 329, 435, 2013, 2745, 347, 11045}},
+{1465, 14, 3847, {1, 1, 1, 13, 29, 53, 51, 67, 105, 89, 1887, 3543, 963, 8159}},
+{1466, 14, 3853, {1, 1, 5, 3, 5, 27, 41, 67, 67, 883, 973, 1785, 901, 14969}},
+{1467, 14, 3862, {1, 3, 3, 13, 17, 11, 117, 115, 163, 939, 79, 641, 4365, 2267}},
+{1468, 14, 3875, {1, 1, 3, 3, 9, 5, 41, 123, 149, 9, 1533, 3939, 5995, 12701}},
+{1469, 14, 3902, {1, 1, 1, 15, 31, 1, 101, 229, 191, 965, 61, 2671, 4177, 15779}},
+{1470, 14, 3904, {1, 1, 5, 15, 1, 25, 49, 185, 33, 697, 1043, 2639, 7819, 3171}},
+{1471, 14, 3916, {1, 3, 5, 13, 19, 9, 111, 49, 47, 847, 1865, 717, 5287, 13417}},
+{1472, 14, 3947, {1, 3, 7, 11, 5, 61, 63, 111, 171, 735, 2003, 73, 5701, 647}},
+{1473, 14, 3949, {1, 3, 1, 11, 1, 49, 121, 79, 431, 671, 1241, 1161, 2057, 263}},
+{1474, 14, 3955, {1, 3, 3, 1, 1, 23, 75, 15, 117, 641, 313, 1525, 2041, 1409}},
+{1475, 14, 3962, {1, 3, 5, 11, 15, 57, 13, 67, 139, 131, 1339, 2419, 7945, 11877}},
+{1476, 14, 3971, {1, 3, 1, 1, 19, 39, 97, 83, 297, 595, 1611, 5, 4753, 3435}},
+{1477, 14, 3980, {1, 3, 1, 9, 7, 49, 125, 101, 383, 717, 63, 2295, 3873, 13461}},
+{1478, 14, 3985, {1, 1, 3, 3, 15, 29, 89, 77, 269, 689, 229, 1207, 7311, 8663}},
+{1479, 14, 3998, {1, 1, 1, 1, 1, 61, 25, 255, 203, 233, 271, 987, 2277, 8735}},
+{1480, 14, 4001, {1, 1, 5, 7, 21, 27, 63, 79, 337, 133, 1453, 3633, 6157, 15875}},
+{1481, 14, 4002, {1, 3, 1, 7, 7, 55, 31, 81, 203, 709, 1743, 1677, 4247, 11411}},
+{1482, 14, 4016, {1, 1, 3, 3, 29, 51, 37, 17, 487, 325, 1393, 1433, 3467, 2851}},
+{1483, 14, 4021, {1, 1, 7, 9, 3, 41, 99, 177, 241, 869, 739, 2729, 4585, 14801}},
+{1484, 14, 4026, {1, 1, 3, 1, 9, 43, 97, 65, 99, 295, 1693, 2083, 3241, 4073}},
+{1485, 14, 4043, {1, 1, 1, 9, 5, 39, 67, 119, 235, 543, 795, 2773, 3195, 6273}},
+{1486, 14, 4079, {1, 1, 5, 5, 21, 41, 89, 1, 85, 81, 57, 2951, 1531, 10101}},
+{1487, 14, 4102, {1, 1, 1, 7, 3, 35, 127, 69, 39, 265, 1643, 2973, 267, 12365}},
+{1488, 14, 4106, {1, 3, 1, 1, 21, 57, 99, 205, 119, 477, 1771, 1989, 2761, 12573}},
+{1489, 14, 4119, {1, 1, 3, 13, 1, 59, 93, 125, 279, 935, 1877, 2061, 4845, 7835}},
+{1490, 14, 4126, {1, 1, 7, 9, 7, 45, 69, 99, 273, 35, 1579, 2137, 7175, 6999}},
+{1491, 14, 4147, {1, 1, 7, 7, 29, 21, 127, 91, 9, 383, 787, 1783, 601, 5047}},
+{1492, 14, 4149, {1, 1, 7, 13, 7, 29, 35, 219, 43, 581, 2043, 2211, 6169, 12173}},
+{1493, 14, 4164, {1, 3, 5, 13, 29, 29, 39, 63, 411, 645, 415, 2383, 1989, 11411}},
+{1494, 14, 4174, {1, 1, 7, 9, 15, 9, 87, 95, 321, 709, 543, 3831, 2453, 4167}},
+{1495, 14, 4181, {1, 3, 1, 5, 31, 25, 5, 85, 239, 487, 1613, 3937, 4661, 3535}},
+{1496, 14, 4185, {1, 3, 5, 11, 27, 41, 3, 201, 39, 91, 1997, 237, 5639, 14703}},
+{1497, 14, 4188, {1, 1, 7, 3, 27, 49, 87, 71, 473, 247, 1007, 47, 475, 5413}},
+{1498, 14, 4202, {1, 3, 7, 15, 9, 57, 81, 149, 287, 333, 1911, 3417, 1081, 8995}},
+{1499, 14, 4228, {1, 1, 5, 1, 3, 63, 43, 151, 97, 431, 961, 1019, 5153, 2407}},
+{1500, 14, 4232, {1, 1, 5, 5, 27, 21, 127, 161, 507, 311, 129, 3489, 1133, 3241}},
+{1501, 14, 4246, {1, 3, 7, 15, 21, 33, 117, 83, 497, 667, 1399, 931, 1695, 8171}},
+{1502, 14, 4252, {1, 1, 1, 13, 3, 39, 53, 27, 193, 993, 671, 1871, 7579, 11457}},
+{1503, 14, 4256, {1, 1, 5, 11, 7, 39, 81, 107, 195, 387, 849, 395, 1317, 6487}},
+{1504, 14, 4286, {1, 3, 3, 3, 3, 15, 45, 127, 279, 111, 331, 357, 4637, 4697}},
+{1505, 14, 4303, {1, 1, 3, 9, 21, 49, 47, 97, 61, 101, 181, 1867, 1201, 14099}},
+{1506, 14, 4306, {1, 1, 5, 11, 25, 19, 51, 51, 101, 451, 545, 101, 7497, 9141}},
+{1507, 14, 4311, {1, 1, 1, 3, 13, 53, 119, 81, 377, 245, 765, 251, 3757, 16045}},
+{1508, 14, 4317, {1, 1, 1, 3, 5, 61, 65, 37, 331, 925, 1439, 3219, 2843, 11397}},
+{1509, 14, 4342, {1, 3, 5, 9, 23, 31, 95, 155, 83, 641, 1129, 135, 477, 1623}},
+{1510, 14, 4346, {1, 1, 3, 9, 9, 61, 93, 11, 331, 585, 799, 1417, 1533, 463}},
+{1511, 14, 4377, {1, 1, 7, 7, 21, 51, 61, 29, 467, 935, 11, 3357, 1087, 12337}},
+{1512, 14, 4401, {1, 3, 3, 11, 1, 39, 103, 153, 351, 893, 1823, 835, 2149, 4203}},
+{1513, 14, 4407, {1, 1, 1, 9, 31, 13, 61, 235, 369, 359, 835, 2067, 2697, 15289}},
+{1514, 14, 4414, {1, 1, 7, 1, 15, 1, 107, 27, 201, 451, 1521, 313, 3195, 3847}},
+{1515, 14, 4422, {1, 1, 5, 13, 1, 27, 63, 137, 355, 489, 2039, 1015, 2519, 13797}},
+{1516, 14, 4431, {1, 1, 7, 9, 29, 33, 23, 197, 49, 555, 1087, 3447, 7299, 15513}},
+{1517, 14, 4434, {1, 3, 5, 11, 7, 37, 55, 63, 443, 573, 1715, 631, 3405, 6155}},
+{1518, 14, 4436, {1, 3, 3, 3, 31, 35, 51, 167, 225, 617, 2007, 2555, 6819, 12709}},
+{1519, 14, 4443, {1, 1, 1, 13, 15, 5, 73, 85, 109, 43, 1067, 3941, 1125, 10269}},
+{1520, 14, 4459, {1, 1, 7, 11, 17, 3, 127, 145, 279, 19, 1007, 3287, 4751, 12507}},
+{1521, 14, 4461, {1, 3, 7, 3, 19, 1, 117, 111, 193, 435, 47, 1801, 529, 8547}},
+{1522, 14, 4462, {1, 3, 3, 13, 1, 19, 101, 19, 469, 187, 207, 1243, 8153, 3273}},
+{1523, 14, 4473, {1, 3, 1, 5, 11, 51, 69, 189, 453, 775, 241, 3331, 4067, 14759}},
+{1524, 14, 4497, {1, 1, 1, 1, 23, 55, 113, 133, 497, 731, 391, 2777, 3529, 955}},
+{1525, 14, 4504, {1, 3, 1, 11, 5, 49, 59, 35, 261, 949, 325, 3595, 7433, 11099}},
+{1526, 14, 4507, {1, 3, 5, 9, 13, 37, 103, 219, 329, 865, 1787, 2497, 7249, 9877}},
+{1527, 14, 4525, {1, 3, 7, 9, 11, 33, 19, 255, 191, 935, 1115, 1901, 1577, 9623}},
+{1528, 14, 4534, {1, 1, 5, 7, 29, 23, 77, 43, 283, 143, 1211, 73, 2835, 10235}},
+{1529, 14, 4538, {1, 1, 7, 3, 3, 27, 35, 173, 453, 425, 1225, 3023, 2159, 8433}},
+{1530, 14, 4548, {1, 1, 1, 5, 27, 21, 35, 25, 71, 145, 1545, 523, 4527, 7655}},
+{1531, 14, 4552, {1, 1, 5, 3, 13, 49, 61, 157, 113, 775, 763, 1785, 225, 11851}},
+{1532, 14, 4560, {1, 1, 3, 1, 31, 57, 97, 229, 291, 777, 213, 4067, 921, 8203}},
+{1533, 14, 4575, {1, 1, 5, 1, 25, 13, 125, 123, 263, 207, 119, 3111, 3841, 843}},
+{1534, 14, 4599, {1, 1, 7, 7, 25, 57, 81, 129, 31, 133, 1869, 2949, 5563, 14965}},
+{1535, 14, 4612, {1, 3, 3, 7, 3, 51, 33, 127, 281, 425, 1253, 405, 7941, 8799}},
+{1536, 14, 4619, {1, 1, 3, 9, 3, 63, 93, 173, 255, 609, 49, 111, 7785, 15865}},
+{1537, 14, 4640, {1, 1, 1, 3, 17, 59, 113, 55, 155, 789, 1335, 177, 3071, 1851}},
+{1538, 14, 4643, {1, 3, 7, 15, 15, 23, 35, 35, 131, 623, 47, 437, 1337, 9891}},
+{1539, 14, 4677, {1, 3, 7, 5, 29, 57, 39, 31, 111, 271, 59, 1473, 949, 3899}},
+{1540, 14, 4687, {1, 1, 3, 11, 17, 19, 41, 229, 259, 691, 1455, 3023, 7455, 9711}},
+{1541, 14, 4723, {1, 3, 5, 11, 29, 13, 9, 165, 499, 355, 1415, 1395, 7595, 15571}},
+{1542, 14, 4730, {1, 3, 1, 9, 5, 5, 25, 247, 185, 241, 1325, 3133, 7471, 2649}},
+{1543, 14, 4736, {1, 3, 3, 11, 17, 29, 57, 61, 51, 203, 993, 1837, 3785, 15163}},
+{1544, 14, 4741, {1, 1, 7, 7, 21, 57, 79, 165, 277, 133, 93, 1055, 7169, 15685}},
+{1545, 14, 4763, {1, 1, 5, 3, 5, 17, 25, 177, 95, 323, 367, 1359, 4915, 6409}},
+{1546, 14, 4765, {1, 1, 1, 1, 11, 25, 115, 45, 373, 221, 1483, 591, 6561, 4527}},
+{1547, 14, 4770, {1, 3, 5, 3, 5, 23, 69, 77, 313, 473, 1037, 4045, 3969, 5445}},
+{1548, 14, 4781, {1, 3, 1, 5, 1, 15, 73, 83, 439, 463, 203, 361, 6835, 1061}},
+{1549, 14, 4808, {1, 1, 3, 11, 21, 5, 89, 233, 405, 253, 773, 3901, 6085, 5677}},
+{1550, 14, 4822, {1, 1, 3, 9, 15, 53, 71, 29, 101, 599, 1073, 705, 4507, 12779}},
+{1551, 14, 4828, {1, 1, 3, 1, 3, 9, 27, 97, 207, 859, 417, 735, 2179, 5071}},
+{1552, 14, 4831, {1, 1, 1, 3, 13, 63, 65, 125, 195, 611, 649, 2221, 3143, 143}},
+{1553, 14, 4842, {1, 3, 3, 15, 17, 57, 99, 119, 243, 407, 1229, 813, 5245, 1893}},
+{1554, 14, 4855, {1, 1, 1, 5, 27, 27, 49, 13, 313, 287, 473, 2629, 3509, 11371}},
+{1555, 14, 4859, {1, 1, 7, 7, 23, 3, 75, 59, 245, 689, 1215, 2375, 3325, 1593}},
+{1556, 14, 4867, {1, 3, 1, 5, 21, 51, 43, 107, 91, 611, 1405, 677, 2087, 9565}},
+{1557, 14, 4870, {1, 3, 7, 11, 9, 27, 81, 101, 449, 201, 1507, 2217, 6767, 8059}},
+{1558, 14, 4881, {1, 1, 3, 9, 13, 41, 21, 195, 421, 315, 347, 2621, 2359, 9247}},
+{1559, 14, 4893, {1, 1, 5, 7, 31, 45, 77, 229, 455, 575, 1087, 1147, 2273, 13773}},
+{1560, 14, 4910, {1, 1, 1, 1, 9, 5, 87, 19, 207, 545, 1435, 495, 1299, 4947}},
+{1561, 14, 4917, {1, 1, 3, 3, 15, 9, 63, 67, 219, 735, 1911, 2361, 6503, 11977}},
+{1562, 14, 4929, {1, 3, 1, 9, 31, 27, 103, 153, 81, 939, 461, 2753, 697, 537}},
+{1563, 14, 4939, {1, 3, 3, 9, 21, 53, 49, 211, 415, 817, 321, 3775, 2921, 9473}},
+{1564, 14, 4947, {1, 1, 7, 3, 23, 55, 15, 51, 435, 1013, 73, 3967, 4575, 13099}},
+{1565, 14, 4949, {1, 1, 3, 7, 5, 27, 43, 225, 267, 21, 1261, 603, 6913, 4421}},
+{1566, 14, 4954, {1, 1, 7, 13, 25, 31, 101, 109, 237, 91, 1587, 1987, 2795, 6991}},
+{1567, 14, 4972, {1, 1, 3, 13, 23, 51, 91, 89, 287, 39, 1513, 463, 6135, 10469}},
+{1568, 14, 4975, {1, 3, 3, 1, 9, 43, 125, 157, 369, 495, 1849, 785, 6357, 6557}},
+{1569, 14, 5000, {1, 3, 1, 13, 5, 25, 107, 139, 367, 239, 1671, 1239, 7027, 5291}},
+{1570, 14, 5005, {1, 3, 5, 13, 11, 13, 35, 177, 45, 939, 251, 59, 333, 13105}},
+{1571, 14, 5029, {1, 3, 5, 7, 29, 57, 109, 227, 435, 739, 423, 1941, 3345, 12731}},
+{1572, 14, 5039, {1, 3, 3, 9, 23, 51, 19, 207, 69, 99, 955, 519, 7305, 2415}},
+{1573, 14, 5044, {1, 1, 5, 13, 17, 1, 67, 201, 61, 403, 1059, 2915, 2419, 12773}},
+{1574, 14, 5051, {1, 3, 1, 11, 17, 19, 25, 27, 207, 299, 143, 1955, 5669, 2301}},
+{1575, 14, 5056, {1, 1, 5, 3, 25, 57, 45, 255, 489, 1011, 1699, 2637, 5279, 12211}},
+{1576, 14, 5073, {1, 3, 3, 15, 7, 47, 113, 33, 511, 907, 1815, 1741, 2091, 13857}},
+{1577, 14, 5096, {1, 3, 3, 5, 5, 27, 95, 3, 353, 253, 947, 393, 1815, 14551}},
+{1578, 14, 5128, {1, 1, 5, 11, 29, 19, 63, 117, 293, 861, 2039, 9, 5999, 6909}},
+{1579, 14, 5134, {1, 3, 7, 3, 15, 63, 107, 173, 509, 817, 99, 2825, 131, 7917}},
+{1580, 14, 5161, {1, 3, 1, 1, 29, 49, 33, 153, 119, 777, 1315, 3581, 5675, 4043}},
+{1581, 14, 5179, {1, 3, 5, 15, 13, 11, 17, 147, 327, 305, 367, 3237, 5423, 13757}},
+{1582, 14, 5193, {1, 1, 5, 13, 1, 39, 35, 29, 25, 751, 1365, 2243, 8181, 7063}},
+{1583, 14, 5199, {1, 3, 7, 11, 25, 53, 11, 111, 289, 755, 1201, 691, 3679, 3725}},
+{1584, 14, 5202, {1, 1, 1, 11, 11, 37, 33, 211, 395, 691, 1817, 861, 6485, 12077}},
+{1585, 14, 5204, {1, 3, 3, 11, 21, 3, 111, 171, 305, 561, 1501, 2011, 7841, 10931}},
+{1586, 14, 5218, {1, 3, 7, 9, 9, 59, 109, 113, 31, 915, 103, 1861, 2779, 10619}},
+{1587, 14, 5247, {1, 1, 1, 1, 7, 25, 61, 97, 103, 723, 1145, 3105, 371, 339}},
+{1588, 14, 5260, {1, 1, 7, 13, 17, 9, 113, 51, 233, 209, 1117, 211, 6969, 2347}},
+{1589, 14, 5271, {1, 1, 5, 9, 25, 43, 21, 217, 327, 735, 197, 1063, 799, 801}},
+{1590, 14, 5301, {1, 1, 7, 13, 9, 13, 73, 33, 415, 923, 863, 1999, 5383, 8119}},
+{1591, 14, 5305, {1, 3, 1, 5, 7, 33, 51, 185, 289, 967, 1277, 1011, 767, 15505}},
+{1592, 14, 5319, {1, 3, 3, 13, 21, 11, 105, 235, 343, 1021, 2009, 2251, 3865, 6923}},
+{1593, 14, 5326, {1, 3, 5, 9, 29, 11, 33, 17, 149, 155, 1739, 3039, 7015, 2401}},
+{1594, 14, 5328, {1, 3, 7, 7, 17, 13, 89, 177, 297, 267, 545, 3861, 329, 13267}},
+{1595, 14, 5333, {1, 3, 5, 15, 27, 33, 1, 231, 181, 557, 447, 379, 7845, 1295}},
+{1596, 14, 5364, {1, 1, 5, 13, 3, 63, 59, 33, 263, 877, 1867, 1383, 641, 7139}},
+{1597, 14, 5376, {1, 3, 7, 5, 13, 51, 9, 113, 223, 605, 1189, 4063, 6925, 9563}},
+{1598, 14, 5399, {1, 1, 1, 13, 5, 35, 83, 107, 295, 231, 265, 5, 4087, 6407}},
+{1599, 14, 5416, {1, 1, 5, 1, 7, 25, 95, 137, 97, 987, 1753, 2781, 1369, 6903}},
+{1600, 14, 5421, {1, 1, 5, 13, 19, 61, 77, 229, 193, 165, 811, 249, 79, 10719}},
+{1601, 14, 5427, {1, 3, 7, 7, 27, 9, 119, 193, 459, 43, 1989, 2959, 3595, 6341}},
+{1602, 14, 5429, {1, 1, 5, 11, 5, 43, 35, 33, 25, 581, 897, 351, 4201, 3971}},
+{1603, 14, 5430, {1, 1, 7, 11, 21, 29, 53, 45, 359, 197, 313, 3825, 6717, 4077}},
+{1604, 14, 5434, {1, 1, 1, 15, 3, 45, 99, 133, 357, 315, 1159, 241, 2463, 11253}},
+{1605, 14, 5441, {1, 1, 7, 11, 9, 33, 111, 85, 443, 601, 447, 337, 6471, 7029}},
+{1606, 14, 5451, {1, 3, 7, 9, 13, 33, 25, 31, 9, 729, 1763, 4077, 7575, 7877}},
+{1607, 14, 5465, {1, 3, 5, 13, 13, 37, 29, 103, 53, 229, 591, 1073, 1323, 14405}},
+{1608, 14, 5466, {1, 1, 5, 1, 17, 33, 15, 183, 473, 297, 2003, 93, 4955, 1787}},
+{1609, 14, 5471, {1, 1, 5, 13, 5, 29, 113, 161, 267, 451, 1193, 149, 273, 11809}},
+{1610, 14, 5477, {1, 1, 1, 9, 17, 39, 47, 233, 165, 373, 955, 2891, 7523, 7235}},
+{1611, 14, 5492, {1, 1, 1, 3, 7, 21, 115, 205, 153, 449, 339, 2073, 1077, 5749}},
+{1612, 14, 5495, {1, 1, 7, 13, 9, 39, 117, 187, 37, 753, 227, 3519, 7391, 5751}},
+{1613, 14, 5505, {1, 1, 1, 9, 5, 19, 41, 161, 141, 195, 1719, 3321, 5, 12877}},
+{1614, 14, 5515, {1, 3, 7, 11, 21, 13, 83, 55, 299, 75, 1905, 3765, 4685, 12297}},
+{1615, 14, 5525, {1, 1, 7, 3, 3, 23, 111, 243, 187, 297, 1061, 2515, 977, 9555}},
+{1616, 14, 5529, {1, 3, 7, 3, 29, 11, 103, 177, 225, 875, 1649, 1401, 6383, 8309}},
+{1617, 14, 5532, {1, 3, 5, 3, 3, 41, 71, 3, 373, 757, 701, 2825, 1521, 13217}},
+{1618, 14, 5539, {1, 1, 5, 3, 11, 5, 103, 227, 209, 723, 1543, 3895, 6345, 7901}},
+{1619, 14, 5541, {1, 1, 5, 1, 9, 51, 77, 67, 359, 937, 557, 993, 3871, 3577}},
+{1620, 14, 5556, {1, 3, 7, 1, 1, 15, 121, 239, 29, 113, 1123, 3877, 6941, 14129}},
+{1621, 14, 5566, {1, 1, 5, 1, 27, 61, 83, 113, 185, 601, 947, 3933, 381, 13869}},
+{1622, 14, 5568, {1, 1, 5, 3, 5, 37, 97, 31, 81, 367, 747, 1811, 5313, 14151}},
+{1623, 14, 5574, {1, 3, 5, 9, 27, 61, 87, 31, 185, 521, 837, 959, 5001, 3957}},
+{1624, 14, 5595, {1, 3, 5, 3, 11, 61, 37, 19, 107, 749, 1345, 3829, 6701, 4315}},
+{1625, 14, 5602, {1, 3, 1, 15, 13, 45, 101, 113, 243, 963, 1861, 3283, 1419, 12131}},
+{1626, 14, 5611, {1, 1, 7, 1, 11, 63, 17, 117, 271, 819, 677, 669, 1991, 12511}},
+{1627, 14, 5616, {1, 1, 1, 13, 13, 33, 41, 73, 187, 537, 993, 3147, 1013, 16063}},
+{1628, 14, 5622, {1, 3, 1, 1, 25, 21, 107, 81, 117, 917, 113, 349, 4475, 9149}},
+{1629, 14, 5628, {1, 1, 1, 11, 21, 21, 29, 251, 125, 681, 141, 2893, 5843, 14359}},
+{1630, 14, 5655, {1, 3, 3, 1, 5, 41, 85, 163, 387, 29, 1593, 221, 2769, 10809}},
+{1631, 14, 5662, {1, 3, 5, 11, 1, 17, 69, 127, 273, 449, 1855, 2971, 7031, 10583}},
+{1632, 14, 5675, {1, 1, 5, 7, 1, 61, 9, 211, 123, 563, 111, 1883, 5801, 2191}},
+{1633, 14, 5689, {1, 1, 3, 11, 11, 51, 1, 81, 405, 803, 2017, 161, 5429, 731}},
+{1634, 14, 5722, {1, 1, 7, 9, 15, 55, 65, 51, 459, 485, 1539, 3135, 2929, 7867}},
+{1635, 14, 5724, {1, 1, 7, 11, 3, 45, 15, 7, 331, 417, 1813, 4009, 1341, 10965}},
+{1636, 14, 5728, {1, 1, 1, 5, 9, 29, 89, 121, 277, 509, 1989, 1293, 4787, 16097}},
+{1637, 14, 5731, {1, 1, 3, 9, 17, 45, 97, 197, 339, 943, 1377, 2947, 5833, 7}},
+{1638, 14, 5746, {1, 1, 7, 9, 15, 61, 75, 233, 401, 705, 825, 2521, 3787, 14387}},
+{1639, 14, 5764, {1, 1, 7, 15, 25, 57, 3, 43, 361, 459, 1551, 1859, 6787, 2293}},
+{1640, 14, 5771, {1, 3, 3, 11, 11, 35, 91, 65, 43, 509, 1829, 1149, 4801, 4109}},
+{1641, 14, 5781, {1, 3, 5, 9, 15, 3, 81, 109, 231, 481, 417, 2505, 315, 6693}},
+{1642, 14, 5801, {1, 1, 3, 9, 3, 7, 107, 221, 297, 543, 149, 579, 927, 79}},
+{1643, 14, 5809, {1, 3, 1, 11, 17, 3, 81, 137, 157, 587, 741, 1277, 2631, 3953}},
+{1644, 14, 5810, {1, 1, 7, 5, 13, 43, 117, 19, 495, 185, 1105, 605, 5249, 11099}},
+{1645, 14, 5812, {1, 1, 7, 9, 23, 55, 91, 213, 21, 779, 857, 2047, 7813, 10053}},
+{1646, 14, 5841, {1, 1, 1, 1, 27, 7, 39, 181, 63, 519, 1073, 3147, 4111, 363}},
+{1647, 14, 5848, {1, 3, 7, 9, 15, 61, 7, 139, 495, 805, 1545, 3789, 2411, 3989}},
+{1648, 14, 5853, {1, 1, 3, 1, 25, 11, 23, 241, 167, 607, 479, 153, 7787, 13929}},
+{1649, 14, 5854, {1, 3, 5, 15, 29, 35, 45, 71, 457, 297, 883, 3021, 5361, 15427}},
+{1650, 14, 5858, {1, 3, 1, 7, 29, 27, 93, 241, 427, 89, 1185, 37, 3863, 14095}},
+{1651, 14, 5892, {1, 3, 1, 5, 5, 45, 51, 15, 235, 889, 1649, 2331, 2713, 10943}},
+{1652, 14, 5907, {1, 1, 3, 11, 11, 15, 71, 85, 135, 163, 139, 1147, 1043, 3195}},
+{1653, 14, 5910, {1, 3, 5, 13, 3, 43, 71, 131, 473, 933, 569, 2491, 7751, 1865}},
+{1654, 14, 5913, {1, 1, 7, 9, 21, 37, 105, 227, 329, 509, 1319, 307, 1557, 14625}},
+{1655, 14, 5920, {1, 1, 3, 13, 15, 1, 25, 93, 335, 953, 769, 4039, 369, 10727}},
+{1656, 14, 5929, {1, 3, 7, 5, 17, 21, 59, 89, 437, 679, 437, 1543, 7663, 5005}},
+{1657, 14, 5949, {1, 1, 7, 15, 27, 49, 125, 13, 397, 877, 1087, 2191, 4711, 9065}},
+{1658, 14, 5952, {1, 1, 7, 5, 15, 47, 115, 125, 187, 31, 1003, 2575, 5397, 3883}},
+{1659, 14, 5955, {1, 1, 7, 11, 15, 1, 127, 207, 383, 707, 183, 1053, 3123, 14071}},
+{1660, 14, 5962, {1, 3, 3, 1, 31, 53, 15, 19, 477, 245, 777, 1613, 5813, 7443}},
+{1661, 14, 5975, {1, 3, 1, 11, 23, 59, 65, 23, 493, 157, 1389, 2833, 4535, 3907}},
+{1662, 14, 5985, {1, 1, 7, 1, 19, 7, 51, 135, 327, 441, 1841, 3091, 3451, 14381}},
+{1663, 14, 5997, {1, 1, 7, 7, 3, 37, 29, 249, 437, 319, 1693, 945, 7639, 5923}},
+{1664, 14, 5998, {1, 3, 7, 15, 7, 61, 81, 127, 383, 99, 23, 3833, 3973, 7651}},
+{1665, 14, 6012, {1, 3, 1, 7, 7, 21, 119, 185, 243, 619, 1363, 2033, 4835, 5089}},
+{1666, 14, 6016, {1, 3, 1, 1, 3, 27, 63, 145, 271, 735, 695, 3981, 3049, 5433}},
+{1667, 14, 6026, {1, 3, 3, 1, 3, 29, 79, 211, 279, 819, 501, 3665, 1455, 10455}},
+{1668, 14, 6036, {1, 1, 3, 3, 31, 61, 113, 5, 411, 91, 489, 3257, 5939, 6715}},
+{1669, 14, 6040, {1, 1, 5, 1, 23, 11, 103, 89, 377, 441, 43, 967, 3383, 8717}},
+{1670, 14, 6045, {1, 1, 5, 13, 29, 39, 97, 189, 197, 621, 1755, 333, 6783, 9711}},
+{1671, 14, 6055, {1, 1, 5, 13, 27, 17, 97, 197, 351, 799, 335, 765, 5329, 12549}},
+{1672, 14, 6059, {1, 1, 5, 11, 29, 17, 9, 211, 127, 633, 1187, 3965, 4145, 12667}},
+{1673, 14, 6088, {1, 1, 7, 5, 27, 29, 65, 115, 287, 325, 461, 5, 899, 2027}},
+{1674, 14, 6115, {1, 1, 1, 5, 27, 17, 31, 13, 231, 627, 1163, 649, 1693, 9975}},
+{1675, 14, 6124, {1, 3, 1, 15, 7, 49, 113, 123, 427, 603, 347, 2785, 7129, 4645}},
+{1676, 14, 6127, {1, 1, 3, 7, 1, 33, 113, 105, 411, 939, 205, 3965, 4361, 4649}},
+{1677, 14, 6132, {1, 1, 1, 1, 5, 21, 35, 159, 275, 929, 1193, 3205, 4787, 3515}},
+{1678, 14, 6146, {1, 1, 1, 5, 1, 21, 29, 191, 275, 233, 1239, 515, 4349, 14989}},
+{1679, 14, 6158, {1, 1, 5, 11, 27, 43, 111, 83, 153, 577, 1537, 149, 231, 839}},
+{1680, 14, 6169, {1, 3, 5, 13, 21, 19, 57, 69, 87, 163, 271, 3535, 1057, 8517}},
+{1681, 14, 6206, {1, 3, 3, 13, 17, 49, 65, 45, 457, 241, 391, 2033, 2507, 7771}},
+{1682, 14, 6228, {1, 1, 5, 7, 11, 19, 79, 133, 341, 761, 27, 3905, 4137, 14363}},
+{1683, 14, 6237, {1, 3, 3, 13, 19, 1, 11, 139, 249, 245, 1393, 2151, 2857, 1665}},
+{1684, 14, 6244, {1, 1, 3, 15, 11, 7, 127, 47, 385, 1007, 713, 2235, 5489, 8755}},
+{1685, 14, 6247, {1, 3, 5, 13, 19, 21, 21, 167, 405, 655, 1653, 889, 7367, 4177}},
+{1686, 14, 6256, {1, 1, 5, 3, 19, 63, 99, 39, 89, 415, 951, 2863, 6569, 3797}},
+{1687, 14, 6281, {1, 1, 1, 13, 31, 29, 119, 35, 311, 839, 1749, 941, 7487, 2385}},
+{1688, 14, 6282, {1, 3, 7, 3, 17, 3, 97, 143, 465, 345, 1457, 2201, 5329, 359}},
+{1689, 14, 6284, {1, 3, 7, 11, 1, 15, 3, 115, 335, 567, 1749, 1811, 3491, 15939}},
+{1690, 14, 6296, {1, 1, 3, 13, 3, 21, 7, 141, 149, 571, 1877, 473, 2143, 9569}},
+{1691, 14, 6299, {1, 3, 3, 11, 23, 61, 47, 179, 297, 453, 181, 3405, 2981, 13409}},
+{1692, 14, 6302, {1, 3, 1, 13, 1, 43, 5, 201, 371, 1003, 367, 2709, 7675, 14973}},
+{1693, 14, 6325, {1, 3, 3, 15, 29, 17, 19, 241, 495, 317, 1135, 2227, 6457, 4783}},
+{1694, 14, 6349, {1, 3, 3, 7, 29, 9, 57, 95, 261, 531, 1717, 3389, 7991, 3793}},
+{1695, 14, 6352, {1, 1, 1, 5, 31, 43, 73, 119, 499, 589, 1529, 3337, 4097, 15641}},
+{1696, 14, 6362, {1, 1, 7, 9, 29, 43, 127, 91, 243, 979, 1325, 2835, 2787, 9445}},
+{1697, 14, 6383, {1, 1, 7, 5, 9, 3, 115, 199, 219, 901, 747, 1077, 3197, 2443}},
+{1698, 14, 6386, {1, 3, 5, 1, 3, 43, 7, 117, 297, 313, 1043, 1579, 5099, 13289}},
+{1699, 14, 6395, {1, 1, 7, 11, 29, 33, 15, 121, 131, 579, 317, 1871, 1121, 11653}},
+{1700, 14, 6397, {1, 1, 5, 9, 25, 25, 43, 89, 355, 1011, 1385, 2901, 6387, 1653}},
+{1701, 14, 6415, {1, 1, 1, 9, 5, 47, 61, 165, 85, 757, 1397, 1177, 1657, 4899}},
+{1702, 14, 6424, {1, 1, 3, 9, 11, 49, 15, 139, 261, 613, 931, 1299, 2777, 2835}},
+{1703, 14, 6429, {1, 1, 1, 5, 3, 55, 83, 227, 125, 581, 1607, 1171, 6681, 14463}},
+{1704, 14, 6439, {1, 3, 5, 13, 5, 55, 3, 247, 493, 155, 1073, 3743, 5719, 4019}},
+{1705, 14, 6451, {1, 1, 7, 1, 11, 23, 13, 75, 399, 847, 499, 1643, 6977, 3699}},
+{1706, 14, 6489, {1, 3, 1, 9, 11, 41, 47, 131, 313, 627, 481, 2469, 3281, 979}},
+{1707, 14, 6496, {1, 3, 5, 13, 29, 3, 65, 101, 11, 29, 1807, 153, 1487, 16109}},
+{1708, 14, 6502, {1, 1, 5, 9, 13, 31, 83, 195, 351, 355, 467, 3871, 3085, 4441}},
+{1709, 14, 6511, {1, 3, 5, 3, 19, 21, 111, 179, 143, 361, 1619, 1547, 3409, 6905}},
+{1710, 14, 6514, {1, 1, 5, 9, 31, 1, 93, 199, 491, 135, 1627, 2559, 1389, 14561}},
+{1711, 14, 6520, {1, 3, 3, 9, 25, 53, 3, 105, 39, 445, 259, 1045, 1129, 9153}},
+{1712, 14, 6523, {1, 1, 5, 9, 19, 63, 71, 9, 73, 435, 1377, 4015, 1821, 6453}},
+{1713, 14, 6529, {1, 3, 7, 13, 19, 13, 37, 247, 391, 23, 1491, 1257, 6395, 237}},
+{1714, 14, 6532, {1, 1, 3, 3, 19, 55, 109, 23, 227, 747, 729, 2221, 727, 2209}},
+{1715, 14, 6547, {1, 1, 5, 11, 25, 21, 75, 37, 219, 355, 1005, 1895, 7039, 5225}},
+{1716, 14, 6549, {1, 3, 5, 13, 11, 43, 9, 67, 87, 797, 1077, 245, 4521, 11845}},
+{1717, 14, 6598, {1, 3, 5, 3, 15, 29, 127, 237, 277, 373, 1859, 3083, 587, 1123}},
+{1718, 14, 6601, {1, 1, 7, 15, 13, 7, 103, 53, 13, 965, 1497, 775, 3439, 1501}},
+{1719, 14, 6610, {1, 3, 3, 15, 17, 13, 97, 169, 67, 953, 189, 2739, 1459, 10543}},
+{1720, 14, 6622, {1, 1, 5, 1, 17, 39, 15, 127, 327, 989, 1471, 3235, 2801, 15311}},
+{1721, 14, 6632, {1, 1, 1, 15, 5, 37, 55, 155, 47, 463, 1851, 3467, 2765, 9359}},
+{1722, 14, 6655, {1, 3, 3, 15, 1, 13, 93, 239, 291, 115, 365, 61, 395, 15853}},
+{1723, 14, 6665, {1, 1, 5, 1, 19, 27, 61, 95, 105, 369, 1557, 961, 6917, 3621}},
+{1724, 14, 6666, {1, 3, 3, 9, 7, 35, 115, 53, 111, 345, 1145, 1687, 3401, 12107}},
+{1725, 14, 6695, {1, 1, 1, 5, 7, 31, 63, 19, 373, 79, 1369, 3037, 2835, 4439}},
+{1726, 14, 6701, {1, 3, 7, 9, 11, 17, 29, 33, 331, 447, 1981, 3333, 6535, 6557}},
+{1727, 14, 6709, {1, 3, 3, 5, 11, 41, 29, 43, 365, 279, 1919, 945, 179, 1987}},
+{1728, 14, 6710, {1, 3, 1, 13, 7, 7, 25, 33, 103, 367, 1267, 763, 5691, 8643}},
+{1729, 14, 6741, {1, 3, 1, 5, 11, 15, 3, 213, 511, 211, 1069, 4047, 3335, 12729}},
+{1730, 14, 6745, {1, 1, 3, 1, 5, 11, 27, 201, 361, 537, 679, 3709, 293, 2997}},
+{1731, 14, 6758, {1, 1, 3, 1, 25, 15, 19, 185, 369, 577, 1625, 655, 2363, 3861}},
+{1732, 14, 6767, {1, 1, 5, 5, 1, 47, 61, 45, 411, 597, 955, 1007, 3775, 5809}},
+{1733, 14, 6772, {1, 1, 5, 3, 27, 51, 101, 167, 429, 333, 1703, 3541, 2947, 3695}},
+{1734, 14, 6782, {1, 3, 5, 5, 1, 53, 17, 63, 141, 215, 1223, 3129, 635, 15919}},
+{1735, 14, 6797, {1, 3, 3, 1, 23, 31, 25, 11, 195, 241, 995, 3941, 573, 13855}},
+{1736, 14, 6800, {1, 3, 3, 7, 17, 13, 71, 203, 465, 479, 1857, 1493, 8067, 7113}},
+{1737, 14, 6843, {1, 1, 5, 3, 11, 57, 9, 59, 225, 691, 425, 2423, 6031, 6631}},
+{1738, 14, 6845, {1, 3, 7, 1, 29, 57, 103, 123, 401, 807, 471, 2759, 5113, 15937}},
+{1739, 14, 6860, {1, 3, 1, 1, 3, 1, 67, 123, 157, 655, 519, 323, 1853, 15041}},
+{1740, 14, 6865, {1, 1, 7, 5, 11, 11, 105, 135, 247, 689, 1141, 2347, 7113, 9347}},
+{1741, 14, 6878, {1, 1, 3, 11, 15, 37, 87, 3, 209, 575, 1521, 3863, 3893, 211}},
+{1742, 14, 6887, {1, 3, 1, 3, 29, 55, 115, 31, 19, 195, 985, 3275, 363, 9801}},
+{1743, 14, 6888, {1, 1, 3, 9, 13, 31, 57, 251, 201, 275, 1751, 389, 1463, 13159}},
+{1744, 14, 6901, {1, 3, 5, 15, 19, 51, 127, 255, 397, 243, 29, 3007, 7845, 4687}},
+{1745, 14, 6906, {1, 1, 7, 15, 9, 37, 39, 217, 509, 137, 1123, 3361, 6323, 5323}},
+{1746, 14, 6940, {1, 3, 7, 5, 25, 3, 93, 203, 345, 581, 261, 2811, 4829, 6977}},
+{1747, 14, 6947, {1, 1, 7, 1, 15, 41, 51, 227, 447, 893, 1209, 3865, 5229, 4277}},
+{1748, 14, 6953, {1, 1, 1, 5, 31, 19, 23, 195, 359, 853, 595, 337, 2503, 16371}},
+{1749, 14, 6954, {1, 3, 7, 5, 5, 13, 89, 157, 351, 777, 151, 3565, 4219, 7423}},
+{1750, 14, 6959, {1, 1, 1, 5, 7, 1, 9, 89, 175, 909, 1523, 2295, 7949, 6739}},
+{1751, 14, 6961, {1, 3, 5, 15, 27, 17, 11, 235, 19, 105, 457, 465, 3819, 11335}},
+{1752, 14, 6964, {1, 3, 1, 13, 3, 41, 85, 221, 451, 613, 543, 2265, 6831, 1725}},
+{1753, 14, 6991, {1, 1, 7, 7, 3, 29, 9, 197, 455, 665, 343, 1811, 5395, 393}},
+{1754, 14, 6993, {1, 1, 3, 13, 29, 55, 71, 95, 475, 615, 2029, 123, 413, 16127}},
+{1755, 14, 6999, {1, 1, 5, 9, 15, 61, 9, 51, 105, 271, 511, 2801, 693, 11839}},
+{1756, 14, 7016, {1, 1, 7, 13, 29, 9, 105, 59, 377, 635, 717, 4033, 6963, 10541}},
+{1757, 14, 7029, {1, 1, 1, 13, 7, 13, 59, 17, 335, 355, 77, 3665, 7003, 9521}},
+{1758, 14, 7036, {1, 3, 1, 1, 23, 43, 51, 209, 151, 365, 1021, 2859, 3937, 2899}},
+{1759, 14, 7045, {1, 1, 3, 3, 31, 41, 111, 107, 171, 433, 1233, 505, 2971, 6927}},
+{1760, 14, 7076, {1, 3, 7, 13, 17, 25, 127, 195, 257, 551, 1867, 2145, 3695, 14567}},
+{1761, 14, 7083, {1, 1, 5, 13, 13, 45, 39, 195, 55, 991, 1981, 1043, 5875, 581}},
+{1762, 14, 7094, {1, 3, 3, 11, 25, 31, 91, 153, 415, 449, 1301, 563, 7755, 10671}},
+{1763, 14, 7097, {1, 1, 3, 5, 31, 63, 1, 157, 229, 949, 971, 137, 6589, 8387}},
+{1764, 14, 7123, {1, 3, 7, 15, 25, 7, 89, 133, 73, 497, 1361, 613, 455, 1005}},
+{1765, 14, 7130, {1, 3, 3, 1, 13, 5, 119, 93, 175, 511, 1923, 763, 7573, 7545}},
+{1766, 14, 7139, {1, 1, 3, 15, 27, 59, 49, 205, 497, 485, 117, 2523, 4495, 15153}},
+{1767, 14, 7145, {1, 3, 7, 9, 15, 47, 111, 31, 363, 11, 475, 2931, 6813, 1259}},
+{1768, 14, 7146, {1, 1, 5, 5, 1, 35, 95, 225, 17, 991, 809, 2601, 6455, 13803}},
+{1769, 14, 7178, {1, 1, 5, 5, 15, 1, 1, 171, 433, 887, 1813, 3431, 2471, 7803}},
+{1770, 14, 7186, {1, 3, 3, 15, 1, 15, 43, 179, 15, 949, 1881, 1027, 6989, 8955}},
+{1771, 14, 7192, {1, 3, 7, 13, 1, 3, 49, 183, 373, 175, 1733, 913, 929, 1065}},
+{1772, 14, 7198, {1, 3, 5, 7, 15, 51, 107, 115, 323, 357, 167, 2069, 7541, 9601}},
+{1773, 14, 7222, {1, 1, 3, 5, 5, 21, 31, 107, 21, 299, 1937, 43, 3673, 8155}},
+{1774, 14, 7269, {1, 3, 5, 11, 9, 55, 35, 113, 29, 99, 161, 1607, 8141, 4951}},
+{1775, 14, 7270, {1, 3, 7, 15, 25, 7, 113, 179, 213, 19, 1717, 1027, 2021, 11263}},
+{1776, 14, 7276, {1, 1, 5, 1, 31, 33, 85, 111, 67, 95, 2013, 2217, 871, 5329}},
+{1777, 14, 7287, {1, 1, 1, 7, 7, 63, 67, 145, 495, 419, 1945, 3437, 6255, 151}},
+{1778, 14, 7307, {1, 3, 5, 7, 17, 37, 97, 187, 215, 399, 1603, 2195, 5923, 769}},
+{1779, 14, 7315, {1, 1, 3, 9, 25, 1, 119, 193, 385, 861, 2005, 2769, 675, 767}},
+{1780, 14, 7334, {1, 3, 1, 15, 19, 7, 5, 227, 173, 383, 289, 461, 579, 3689}},
+{1781, 14, 7340, {1, 3, 1, 11, 1, 37, 93, 239, 465, 891, 1479, 921, 4439, 15265}},
+{1782, 14, 7351, {1, 1, 1, 13, 27, 61, 99, 69, 279, 655, 1853, 1593, 6319, 9003}},
+{1783, 14, 7352, {1, 1, 1, 11, 5, 7, 19, 7, 387, 303, 321, 931, 5809, 16029}},
+{1784, 14, 7357, {1, 1, 1, 15, 21, 55, 43, 107, 217, 687, 19, 3225, 3419, 9991}},
+{1785, 14, 7360, {1, 1, 7, 5, 7, 55, 79, 41, 317, 357, 859, 1205, 191, 9395}},
+{1786, 14, 7363, {1, 1, 3, 11, 3, 43, 7, 133, 115, 995, 1205, 1055, 4153, 10481}},
+{1787, 14, 7384, {1, 1, 7, 11, 31, 57, 53, 9, 459, 223, 1969, 3513, 7033, 8505}},
+{1788, 14, 7396, {1, 1, 3, 7, 17, 11, 115, 255, 281, 97, 1685, 2039, 2845, 11637}},
+{1789, 14, 7403, {1, 3, 7, 1, 23, 41, 69, 199, 53, 105, 657, 1453, 4429, 1101}},
+{1790, 14, 7406, {1, 3, 1, 5, 11, 33, 91, 131, 191, 73, 823, 117, 1053, 127}},
+{1791, 14, 7425, {1, 3, 7, 11, 7, 3, 21, 65, 187, 103, 1393, 1797, 6673, 1409}},
+{1792, 14, 7437, {1, 3, 7, 1, 31, 25, 25, 161, 299, 275, 417, 2267, 6861, 1255}},
+{1793, 14, 7445, {1, 3, 5, 13, 5, 11, 61, 155, 115, 1001, 747, 889, 3235, 5709}},
+{1794, 14, 7450, {1, 3, 7, 7, 7, 1, 97, 177, 507, 273, 1781, 3455, 5123, 15607}},
+{1795, 14, 7455, {1, 1, 7, 5, 1, 7, 59, 49, 147, 343, 97, 3517, 5611, 8705}},
+{1796, 14, 7461, {1, 1, 5, 13, 21, 29, 13, 21, 503, 515, 1217, 3905, 5513, 15849}},
+{1797, 14, 7466, {1, 3, 1, 9, 9, 39, 65, 111, 385, 757, 583, 2225, 2039, 2817}},
+{1798, 14, 7488, {1, 3, 3, 15, 23, 17, 63, 169, 503, 949, 849, 461, 6799, 669}},
+{1799, 14, 7494, {1, 1, 1, 3, 1, 41, 63, 159, 251, 457, 521, 1653, 623, 3287}},
+{1800, 14, 7515, {1, 1, 7, 3, 9, 1, 41, 37, 441, 921, 1415, 2955, 5841, 1451}},
+{1801, 14, 7517, {1, 1, 5, 11, 23, 29, 89, 185, 413, 357, 1131, 2369, 3835, 6233}},
+{1802, 14, 7521, {1, 1, 5, 15, 27, 35, 17, 73, 315, 911, 1761, 797, 5349, 3219}},
+{1803, 14, 7536, {1, 3, 7, 11, 21, 9, 119, 233, 249, 901, 189, 3625, 2691, 16201}},
+{1804, 14, 7546, {1, 3, 3, 13, 29, 61, 105, 145, 187, 79, 609, 321, 4289, 3933}},
+{1805, 14, 7569, {1, 3, 1, 15, 19, 63, 13, 185, 115, 219, 1021, 1205, 4273, 11521}},
+{1806, 14, 7591, {1, 1, 3, 3, 23, 31, 93, 153, 87, 947, 1039, 469, 4047, 8869}},
+{1807, 14, 7592, {1, 1, 1, 1, 9, 1, 85, 3, 15, 995, 455, 2769, 6781, 16203}},
+{1808, 14, 7598, {1, 1, 3, 3, 13, 7, 55, 215, 185, 367, 765, 441, 4497, 1521}},
+{1809, 14, 7612, {1, 1, 1, 5, 1, 31, 13, 95, 417, 735, 975, 3407, 4871, 16133}},
+{1810, 14, 7623, {1, 1, 3, 3, 5, 43, 111, 107, 419, 515, 1075, 3597, 1187, 4143}},
+{1811, 14, 7632, {1, 1, 3, 13, 31, 51, 83, 163, 489, 887, 863, 599, 9, 13861}},
+{1812, 14, 7637, {1, 3, 3, 3, 19, 27, 91, 115, 103, 969, 593, 3667, 1867, 15433}},
+{1813, 14, 7644, {1, 3, 3, 13, 7, 25, 47, 141, 57, 553, 1785, 1709, 7453, 2209}},
+{1814, 14, 7657, {1, 3, 1, 13, 11, 13, 71, 219, 5, 451, 2043, 1605, 6439, 12203}},
+{1815, 14, 7665, {1, 3, 1, 13, 5, 57, 61, 223, 401, 413, 321, 1365, 619, 12477}},
+{1816, 14, 7672, {1, 3, 1, 5, 25, 57, 89, 211, 195, 455, 1165, 3979, 6313, 5751}},
+{1817, 14, 7682, {1, 1, 1, 9, 31, 23, 71, 145, 89, 285, 1593, 1171, 5685, 15459}},
+{1818, 14, 7699, {1, 3, 7, 7, 9, 41, 65, 251, 65, 137, 1577, 3027, 5555, 2865}},
+{1819, 14, 7702, {1, 1, 5, 13, 27, 5, 125, 21, 171, 647, 983, 2921, 6623, 5695}},
+{1820, 14, 7724, {1, 1, 1, 13, 15, 9, 117, 197, 123, 953, 1191, 3657, 5757, 15957}},
+{1821, 14, 7749, {1, 1, 3, 7, 29, 13, 5, 175, 395, 127, 679, 255, 6055, 7639}},
+{1822, 14, 7753, {1, 3, 7, 15, 15, 51, 77, 147, 319, 147, 1775, 3983, 3175, 5723}},
+{1823, 14, 7754, {1, 3, 3, 3, 7, 11, 119, 41, 43, 153, 975, 679, 3081, 10359}},
+{1824, 14, 7761, {1, 1, 5, 13, 3, 7, 65, 67, 63, 399, 1561, 2789, 2083, 12289}},
+{1825, 14, 7771, {1, 1, 7, 3, 19, 53, 103, 67, 35, 865, 161, 93, 2533, 3851}},
+{1826, 14, 7777, {1, 1, 1, 11, 31, 9, 29, 189, 199, 817, 1571, 395, 345, 3777}},
+{1827, 14, 7784, {1, 3, 5, 11, 31, 3, 9, 67, 277, 735, 181, 2777, 3009, 7233}},
+{1828, 14, 7804, {1, 1, 3, 3, 17, 7, 17, 3, 375, 933, 237, 3919, 5409, 3355}},
+{1829, 14, 7807, {1, 3, 3, 5, 9, 27, 19, 77, 221, 3, 1965, 309, 3001, 15977}},
+{1830, 14, 7808, {1, 1, 5, 1, 3, 33, 35, 133, 37, 709, 627, 1705, 2525, 4307}},
+{1831, 14, 7818, {1, 1, 7, 3, 25, 21, 105, 55, 375, 681, 881, 1299, 5879, 459}},
+{1832, 14, 7835, {1, 3, 7, 1, 13, 7, 113, 103, 313, 515, 1041, 3683, 4619, 5093}},
+{1833, 14, 7842, {1, 1, 3, 7, 19, 43, 83, 37, 39, 133, 1759, 1171, 1521, 13717}},
+{1834, 14, 7865, {1, 1, 7, 13, 7, 35, 15, 155, 293, 1001, 157, 3883, 405, 1797}},
+{1835, 14, 7868, {1, 1, 3, 3, 13, 19, 125, 49, 333, 387, 339, 1815, 4503, 7359}},
+{1836, 14, 7880, {1, 1, 3, 13, 19, 19, 105, 225, 151, 27, 1251, 885, 4815, 7863}},
+{1837, 14, 7883, {1, 1, 1, 5, 7, 59, 17, 145, 77, 117, 1355, 1429, 2301, 16177}},
+{1838, 14, 7891, {1, 3, 3, 13, 5, 31, 119, 167, 459, 727, 1799, 2537, 695, 13637}},
+{1839, 14, 7897, {1, 3, 3, 3, 27, 51, 107, 85, 267, 57, 1279, 823, 6247, 3603}},
+{1840, 14, 7907, {1, 1, 7, 15, 29, 17, 67, 197, 215, 465, 109, 3461, 5269, 15287}},
+{1841, 14, 7910, {1, 1, 3, 5, 11, 15, 123, 53, 293, 797, 1105, 1777, 6509, 217}},
+{1842, 14, 7924, {1, 3, 3, 13, 3, 5, 109, 53, 203, 693, 871, 135, 369, 11149}},
+{1843, 14, 7933, {1, 3, 5, 15, 17, 43, 81, 235, 119, 817, 1777, 261, 8049, 4251}},
+{1844, 14, 7934, {1, 1, 3, 7, 7, 13, 87, 99, 481, 931, 1507, 651, 5267, 8281}},
+{1845, 14, 7942, {1, 3, 1, 13, 27, 43, 77, 225, 341, 163, 933, 429, 4943, 7781}},
+{1846, 14, 7948, {1, 1, 7, 1, 1, 49, 85, 211, 449, 479, 1395, 787, 5653, 14891}},
+{1847, 14, 7959, {1, 1, 5, 9, 25, 13, 49, 85, 125, 85, 1281, 3365, 4305, 11791}},
+{1848, 14, 7984, {1, 3, 1, 13, 3, 31, 117, 39, 43, 151, 663, 669, 1571, 5207}},
+{1849, 14, 7994, {1, 3, 7, 15, 17, 7, 79, 163, 37, 841, 1799, 1787, 4501, 3785}},
+{1850, 14, 7999, {1, 1, 3, 9, 1, 23, 67, 191, 449, 931, 1521, 2705, 887, 7037}},
+{1851, 14, 8014, {1, 1, 1, 1, 5, 13, 55, 161, 419, 577, 1703, 2589, 2651, 2873}},
+{1852, 14, 8021, {1, 3, 3, 3, 5, 19, 37, 169, 69, 1003, 1755, 3101, 1469, 8583}},
+{1853, 14, 8041, {1, 1, 1, 1, 11, 33, 105, 79, 283, 91, 299, 835, 3193, 5593}},
+{1854, 14, 8049, {1, 3, 3, 13, 25, 21, 81, 213, 465, 475, 331, 457, 61, 9511}},
+{1855, 14, 8050, {1, 1, 3, 11, 1, 11, 77, 95, 455, 949, 1999, 1833, 1275, 5631}},
+{1856, 14, 8068, {1, 1, 1, 1, 15, 25, 51, 137, 275, 451, 1179, 3595, 5177, 7105}},
+{1857, 14, 8080, {1, 3, 3, 3, 3, 59, 79, 143, 393, 583, 349, 3039, 7079, 14245}},
+{1858, 14, 8095, {1, 1, 7, 9, 21, 11, 123, 105, 53, 297, 803, 4025, 5421, 14527}},
+{1859, 14, 8102, {1, 3, 7, 11, 21, 15, 103, 109, 311, 321, 1217, 2777, 5457, 1823}},
+{1860, 14, 8106, {1, 3, 5, 11, 19, 31, 79, 89, 295, 413, 817, 499, 3699, 14411}},
+{1861, 14, 8120, {1, 1, 1, 5, 11, 3, 81, 13, 315, 841, 1543, 411, 6883, 6347}},
+{1862, 14, 8133, {1, 3, 3, 11, 23, 43, 23, 131, 17, 517, 995, 2687, 7443, 15085}},
+{1863, 14, 8134, {1, 1, 1, 1, 11, 57, 73, 9, 123, 905, 1763, 1789, 3701, 7131}},
+{1864, 14, 8143, {1, 1, 3, 5, 9, 53, 99, 229, 43, 207, 625, 1583, 6727, 15249}},
+{1865, 14, 8162, {1, 1, 7, 7, 17, 39, 91, 1, 297, 711, 225, 513, 7391, 291}},
+{1866, 14, 8168, {1, 1, 7, 11, 7, 55, 111, 129, 423, 521, 1807, 3015, 1449, 12321}},
+{1867, 14, 8179, {1, 3, 7, 3, 13, 9, 125, 187, 11, 485, 647, 275, 3495, 11989}},
+{1868, 15, 1, {1, 1, 3, 11, 11, 25, 49, 33, 361, 105, 271, 3841, 4837, 2437, 30181}},
+{1869, 15, 8, {1, 3, 5, 1, 27, 15, 119, 35, 159, 273, 1489, 3157, 5433, 3337, 26859}},
+{1870, 15, 11, {1, 3, 5, 13, 23, 31, 97, 145, 41, 605, 1455, 59, 5389, 5527, 14447}},
+{1871, 15, 22, {1, 1, 7, 9, 7, 41, 61, 193, 353, 879, 1805, 581, 5447, 11177, 7331}},
+{1872, 15, 26, {1, 1, 7, 11, 29, 19, 55, 207, 361, 759, 63, 2255, 2119, 14671, 21783}},
+{1873, 15, 47, {1, 3, 1, 13, 17, 7, 73, 179, 103, 23, 917, 1205, 4925, 1691, 5419}},
+{1874, 15, 59, {1, 3, 5, 3, 15, 3, 9, 109, 227, 861, 867, 3529, 1535, 489, 22873}},
+{1875, 15, 64, {1, 3, 3, 9, 15, 15, 95, 193, 385, 997, 1525, 1865, 1425, 4079, 14771}},
+{1876, 15, 67, {1, 1, 3, 5, 5, 29, 49, 171, 171, 623, 1167, 3743, 1809, 12009, 7043}},
+{1877, 15, 73, {1, 3, 7, 5, 23, 11, 87, 183, 299, 555, 1857, 489, 3505, 9161, 28763}},
+{1878, 15, 82, {1, 3, 5, 9, 19, 21, 85, 127, 337, 439, 1183, 1891, 1877, 4373, 10451}},
+{1879, 15, 97, {1, 3, 7, 13, 27, 17, 29, 83, 463, 385, 1167, 3453, 4523, 4759, 9321}},
+{1880, 15, 103, {1, 1, 3, 7, 21, 59, 65, 83, 177, 763, 317, 2913, 7527, 5967, 17167}},
+{1881, 15, 110, {1, 1, 7, 15, 13, 27, 49, 35, 253, 101, 1699, 355, 2181, 10859, 24221}},
+{1882, 15, 115, {1, 1, 5, 1, 17, 17, 81, 91, 349, 655, 1373, 2225, 945, 899, 31801}},
+{1883, 15, 122, {1, 3, 7, 11, 5, 1, 81, 53, 215, 587, 167, 4045, 5671, 5597, 13529}},
+{1884, 15, 128, {1, 3, 5, 15, 1, 9, 59, 235, 315, 195, 909, 2237, 505, 10415, 28145}},
+{1885, 15, 138, {1, 1, 1, 3, 9, 31, 41, 43, 275, 921, 25, 671, 5737, 11241, 4193}},
+{1886, 15, 146, {1, 3, 3, 13, 29, 13, 95, 213, 317, 995, 1489, 3779, 3043, 8569, 28823}},
+{1887, 15, 171, {1, 1, 7, 5, 9, 49, 125, 241, 87, 153, 1673, 3849, 7253, 1715, 11627}},
+{1888, 15, 174, {1, 1, 3, 9, 27, 27, 19, 223, 63, 463, 1095, 1395, 6643, 11589, 2145}},
+{1889, 15, 176, {1, 1, 3, 15, 21, 17, 45, 23, 357, 11, 1307, 1791, 2481, 2123, 24341}},
+{1890, 15, 182, {1, 3, 5, 15, 31, 53, 117, 51, 433, 193, 1239, 3329, 2403, 12745, 32219}},
+{1891, 15, 194, {1, 1, 5, 9, 7, 27, 9, 115, 417, 579, 83, 173, 4717, 15665, 27463}},
+{1892, 15, 208, {1, 3, 5, 7, 9, 9, 31, 35, 249, 567, 331, 905, 5101, 14817, 14255}},
+{1893, 15, 211, {1, 3, 7, 3, 1, 61, 29, 129, 119, 421, 1597, 2987, 3041, 7629, 23451}},
+{1894, 15, 220, {1, 1, 7, 9, 13, 1, 99, 105, 107, 509, 989, 2259, 1009, 6827, 8903}},
+{1895, 15, 229, {1, 3, 5, 15, 11, 29, 85, 29, 265, 105, 2035, 3349, 3543, 13903, 10213}},
+{1896, 15, 230, {1, 3, 1, 1, 25, 19, 53, 139, 467, 485, 491, 3067, 7353, 13861, 25819}},
+{1897, 15, 239, {1, 1, 5, 3, 3, 43, 41, 185, 45, 463, 351, 2823, 2519, 6705, 11395}},
+{1898, 15, 254, {1, 3, 7, 13, 11, 15, 87, 221, 427, 673, 1631, 599, 3259, 10691, 31283}},
+{1899, 15, 265, {1, 3, 5, 11, 9, 9, 15, 49, 275, 335, 1613, 3587, 5309, 14849, 26475}},
+{1900, 15, 285, {1, 3, 7, 9, 29, 13, 79, 225, 381, 781, 1411, 2761, 7157, 14983, 19717}},
+{1901, 15, 290, {1, 1, 7, 11, 29, 25, 117, 183, 101, 651, 653, 3157, 445, 14389, 23293}},
+{1902, 15, 319, {1, 1, 1, 3, 5, 33, 73, 155, 473, 387, 591, 2045, 5965, 16299, 31499}},
+{1903, 15, 324, {1, 3, 1, 7, 11, 33, 29, 21, 491, 937, 729, 4075, 975, 2461, 18991}},
+{1904, 15, 327, {1, 3, 7, 15, 29, 39, 105, 111, 173, 943, 69, 295, 8175, 13037, 26131}},
+{1905, 15, 333, {1, 1, 5, 15, 7, 5, 97, 147, 105, 887, 443, 2595, 5889, 10753, 1619}},
+{1906, 15, 357, {1, 3, 3, 15, 11, 45, 87, 207, 353, 909, 1847, 323, 2283, 12885, 16415}},
+{1907, 15, 364, {1, 1, 5, 3, 19, 33, 43, 79, 115, 653, 359, 2873, 4609, 12439, 6339}},
+{1908, 15, 395, {1, 3, 7, 9, 17, 61, 49, 227, 291, 69, 1753, 3899, 483, 3187, 29041}},
+{1909, 15, 397, {1, 3, 5, 3, 25, 35, 61, 211, 393, 199, 691, 1779, 6295, 13371, 15817}},
+{1910, 15, 405, {1, 3, 7, 5, 7, 23, 37, 91, 245, 915, 579, 867, 6193, 1063, 17363}},
+{1911, 15, 409, {1, 3, 7, 7, 23, 51, 41, 63, 375, 3, 159, 1889, 4419, 1687, 17977}},
+{1912, 15, 419, {1, 1, 1, 7, 13, 11, 53, 43, 317, 325, 1749, 2423, 4123, 8595, 20773}},
+{1913, 15, 422, {1, 1, 7, 7, 9, 9, 61, 113, 437, 213, 1407, 645, 4345, 807, 30411}},
+{1914, 15, 431, {1, 3, 3, 11, 17, 39, 17, 113, 391, 385, 581, 2023, 7449, 10153, 22033}},
+{1915, 15, 433, {1, 1, 3, 5, 29, 31, 101, 215, 379, 377, 1113, 2855, 7147, 14377, 25515}},
+{1916, 15, 436, {1, 3, 5, 5, 13, 3, 121, 125, 227, 969, 11, 1115, 5657, 9209, 6117}},
+{1917, 15, 440, {1, 3, 7, 15, 29, 17, 33, 123, 317, 301, 749, 1365, 5619, 605, 1613}},
+{1918, 15, 453, {1, 3, 1, 15, 7, 53, 125, 249, 219, 655, 105, 2825, 1649, 12783, 19777}},
+{1919, 15, 460, {1, 1, 7, 1, 25, 53, 19, 53, 157, 373, 1855, 495, 5065, 9465, 2313}},
+{1920, 15, 471, {1, 3, 5, 13, 3, 57, 57, 161, 431, 415, 1859, 1033, 6349, 1577, 31579}},
+{1921, 15, 478, {1, 1, 7, 5, 23, 63, 29, 221, 13, 965, 1997, 2265, 1583, 10491, 9551}},
+{1922, 15, 482, {1, 1, 3, 13, 31, 25, 23, 61, 285, 5, 2005, 879, 795, 13299, 19685}},
+{1923, 15, 488, {1, 1, 7, 1, 21, 45, 121, 89, 263, 543, 1333, 2711, 219, 10823, 26139}},
+{1924, 15, 524, {1, 1, 3, 3, 27, 13, 19, 117, 161, 457, 1541, 295, 4953, 12125, 14503}},
+{1925, 15, 529, {1, 3, 5, 3, 7, 63, 13, 247, 439, 681, 977, 2537, 6923, 10323, 7349}},
+{1926, 15, 535, {1, 3, 5, 9, 3, 51, 81, 251, 349, 983, 581, 2515, 2281, 2849, 31915}},
+{1927, 15, 536, {1, 3, 5, 3, 11, 63, 47, 137, 303, 627, 91, 2269, 7097, 2145, 31059}},
+{1928, 15, 539, {1, 1, 3, 15, 13, 17, 53, 27, 133, 13, 117, 1837, 4103, 5843, 29153}},
+{1929, 15, 563, {1, 1, 5, 13, 21, 33, 37, 253, 465, 209, 309, 49, 3209, 15677, 14569}},
+{1930, 15, 566, {1, 1, 7, 15, 13, 21, 33, 203, 499, 141, 1155, 3893, 1663, 2115, 27459}},
+{1931, 15, 572, {1, 3, 5, 11, 21, 9, 39, 157, 257, 273, 1257, 1831, 515, 7969, 20133}},
+{1932, 15, 577, {1, 1, 3, 13, 19, 29, 15, 189, 103, 219, 1395, 517, 7425, 6585, 15865}},
+{1933, 15, 587, {1, 1, 5, 11, 21, 31, 49, 151, 39, 537, 1783, 3449, 6915, 223, 11587}},
+{1934, 15, 592, {1, 3, 3, 11, 7, 63, 69, 31, 27, 911, 1903, 2821, 7977, 12949, 32257}},
+{1935, 15, 602, {1, 1, 7, 9, 25, 45, 23, 233, 511, 595, 1383, 1721, 6789, 12055, 21179}},
+{1936, 15, 623, {1, 1, 7, 13, 1, 27, 123, 49, 439, 683, 501, 641, 1947, 6111, 25423}},
+{1937, 15, 635, {1, 3, 3, 5, 1, 23, 57, 241, 243, 593, 2039, 1617, 2209, 5171, 9675}},
+{1938, 15, 638, {1, 1, 1, 7, 5, 19, 83, 55, 481, 125, 177, 1021, 1139, 11403, 23099}},
+{1939, 15, 654, {1, 1, 3, 5, 29, 39, 33, 217, 461, 907, 733, 3795, 4811, 12939, 27715}},
+{1940, 15, 656, {1, 3, 7, 3, 7, 11, 39, 165, 495, 147, 999, 1827, 817, 603, 9293}},
+{1941, 15, 659, {1, 3, 7, 15, 25, 53, 35, 15, 431, 733, 1213, 2907, 8087, 3939, 27363}},
+{1942, 15, 665, {1, 3, 7, 13, 13, 9, 33, 27, 485, 183, 455, 3341, 2555, 4985, 8793}},
+{1943, 15, 675, {1, 1, 1, 15, 25, 47, 75, 21, 205, 15, 1639, 3067, 1295, 11693, 16903}},
+{1944, 15, 677, {1, 1, 1, 15, 3, 31, 93, 57, 43, 185, 251, 1899, 7885, 10829, 3609}},
+{1945, 15, 687, {1, 1, 3, 1, 29, 9, 69, 223, 221, 537, 365, 3411, 5771, 15279, 5309}},
+{1946, 15, 696, {1, 1, 7, 5, 1, 5, 125, 243, 213, 1003, 1571, 3355, 3981, 8781, 25993}},
+{1947, 15, 701, {1, 1, 1, 13, 7, 19, 53, 243, 301, 75, 1183, 2723, 6687, 13, 16581}},
+{1948, 15, 704, {1, 3, 1, 13, 17, 51, 91, 239, 437, 191, 1065, 2495, 5755, 3405, 8299}},
+{1949, 15, 710, {1, 1, 5, 5, 11, 59, 21, 169, 299, 123, 1845, 2199, 2157, 14461, 10327}},
+{1950, 15, 721, {1, 3, 7, 7, 19, 47, 51, 179, 41, 19, 1347, 2325, 8063, 5993, 15653}},
+{1951, 15, 728, {1, 1, 1, 9, 25, 27, 7, 133, 223, 533, 719, 353, 7093, 8285, 10375}},
+{1952, 15, 738, {1, 3, 5, 15, 31, 5, 67, 39, 441, 495, 977, 3699, 1435, 11385, 14567}},
+{1953, 15, 740, {1, 1, 3, 15, 15, 39, 25, 33, 91, 523, 249, 4035, 769, 5181, 9691}},
+{1954, 15, 749, {1, 1, 3, 3, 3, 57, 83, 187, 423, 165, 161, 3453, 2241, 981, 8429}},
+{1955, 15, 758, {1, 1, 7, 15, 1, 17, 57, 189, 283, 11, 823, 3505, 7025, 11879, 15441}},
+{1956, 15, 761, {1, 1, 3, 11, 1, 41, 7, 255, 385, 339, 607, 1405, 1473, 13697, 9491}},
+{1957, 15, 772, {1, 1, 7, 15, 5, 9, 91, 99, 211, 233, 51, 2663, 1165, 9283, 18495}},
+{1958, 15, 776, {1, 1, 3, 7, 21, 37, 13, 91, 39, 27, 1021, 2813, 5937, 6645, 3403}},
+{1959, 15, 782, {1, 3, 1, 1, 29, 29, 5, 69, 399, 665, 1407, 3921, 2653, 11753, 18925}},
+{1960, 15, 789, {1, 3, 7, 15, 13, 41, 39, 1, 437, 549, 161, 2315, 5631, 8335, 22661}},
+{1961, 15, 810, {1, 1, 3, 1, 7, 17, 115, 61, 69, 955, 475, 3763, 8035, 927, 17893}},
+{1962, 15, 812, {1, 3, 1, 13, 21, 59, 81, 145, 463, 145, 1941, 2777, 7453, 14229, 11281}},
+{1963, 15, 818, {1, 1, 1, 15, 15, 11, 27, 165, 461, 395, 1645, 3611, 7463, 12379, 26787}},
+{1964, 15, 830, {1, 1, 7, 9, 29, 19, 27, 123, 21, 149, 1643, 4001, 7207, 6769, 4647}},
+{1965, 15, 832, {1, 1, 1, 11, 13, 9, 103, 139, 185, 587, 591, 1113, 2223, 11667, 32671}},
+{1966, 15, 852, {1, 3, 1, 1, 31, 13, 19, 93, 229, 125, 1471, 2369, 3055, 10277, 28563}},
+{1967, 15, 855, {1, 3, 7, 5, 7, 53, 99, 175, 161, 851, 617, 4027, 2357, 11199, 1931}},
+{1968, 15, 859, {1, 3, 5, 11, 3, 31, 111, 179, 237, 845, 539, 1057, 259, 3417, 26637}},
+{1969, 15, 865, {1, 1, 5, 3, 21, 49, 125, 119, 463, 403, 737, 1811, 3941, 13015, 29081}},
+{1970, 15, 877, {1, 3, 5, 13, 5, 29, 69, 251, 313, 357, 663, 1097, 3307, 12845, 28495}},
+{1971, 15, 895, {1, 3, 3, 5, 29, 17, 89, 15, 411, 409, 2013, 757, 4085, 12521, 11131}},
+{1972, 15, 901, {1, 1, 1, 15, 7, 51, 3, 193, 493, 133, 381, 2027, 227, 6635, 12931}},
+{1973, 15, 902, {1, 1, 1, 15, 7, 23, 99, 203, 323, 1007, 1465, 2887, 2215, 1787, 22069}},
+{1974, 15, 906, {1, 1, 5, 9, 29, 59, 77, 151, 509, 313, 415, 3977, 5431, 8019, 8571}},
+{1975, 15, 916, {1, 3, 1, 15, 19, 13, 57, 217, 87, 119, 25, 1149, 5667, 3765, 6959}},
+{1976, 15, 920, {1, 3, 7, 13, 19, 31, 119, 3, 457, 117, 905, 361, 1483, 12405, 27005}},
+{1977, 15, 949, {1, 3, 5, 11, 15, 35, 61, 77, 119, 51, 1753, 2765, 1091, 10573, 23595}},
+{1978, 15, 962, {1, 3, 3, 7, 1, 35, 17, 93, 197, 511, 1253, 3031, 2739, 15127, 15147}},
+{1979, 15, 964, {1, 3, 3, 1, 11, 55, 55, 107, 161, 75, 129, 2195, 2023, 4877, 25797}},
+{1980, 15, 967, {1, 3, 5, 7, 23, 19, 113, 167, 167, 271, 1303, 125, 5057, 1323, 5165}},
+{1981, 15, 981, {1, 1, 5, 3, 21, 31, 11, 119, 215, 483, 1535, 407, 6485, 15401, 30297}},
+{1982, 15, 982, {1, 3, 5, 9, 21, 5, 77, 95, 443, 247, 913, 605, 365, 7465, 19707}},
+{1983, 15, 985, {1, 3, 1, 7, 17, 59, 9, 35, 391, 767, 1493, 475, 4725, 7529, 31579}},
+{1984, 15, 991, {1, 3, 3, 7, 31, 21, 61, 31, 421, 179, 273, 771, 5745, 10575, 32765}},
+{1985, 15, 1007, {1, 3, 5, 15, 27, 13, 125, 55, 423, 1021, 497, 3521, 6903, 15111, 8285}},
+{1986, 15, 1016, {1, 1, 5, 9, 13, 31, 105, 93, 421, 709, 643, 1079, 1533, 9149, 10799}},
+{1987, 15, 1024, {1, 3, 1, 11, 19, 29, 53, 199, 319, 247, 655, 3039, 6411, 12267, 14245}},
+{1988, 15, 1051, {1, 3, 1, 11, 9, 57, 5, 91, 469, 149, 259, 329, 5433, 6941, 15093}},
+{1989, 15, 1060, {1, 3, 1, 5, 5, 51, 59, 25, 455, 367, 1623, 441, 3155, 11695, 20767}},
+{1990, 15, 1070, {1, 3, 7, 7, 11, 49, 113, 95, 91, 389, 605, 1973, 2051, 2315, 22229}},
+{1991, 15, 1072, {1, 3, 5, 3, 19, 11, 99, 135, 433, 781, 1473, 885, 1105, 3573, 3739}},
+{1992, 15, 1084, {1, 3, 1, 11, 3, 25, 9, 227, 433, 723, 317, 139, 6627, 8067, 28439}},
+{1993, 15, 1089, {1, 1, 1, 9, 9, 9, 5, 63, 241, 215, 1991, 2949, 3943, 775, 31511}},
+{1994, 15, 1095, {1, 1, 3, 7, 17, 49, 35, 167, 131, 107, 1295, 2465, 4577, 11147, 29833}},
+{1995, 15, 1114, {1, 1, 5, 1, 5, 25, 119, 129, 391, 743, 1069, 2957, 349, 6891, 13635}},
+{1996, 15, 1123, {1, 3, 1, 7, 9, 31, 63, 253, 215, 51, 1347, 2361, 3125, 13049, 28461}},
+{1997, 15, 1132, {1, 1, 7, 9, 3, 31, 21, 163, 255, 47, 259, 535, 5461, 3349, 30649}},
+{1998, 15, 1154, {1, 3, 3, 13, 17, 33, 87, 47, 243, 709, 929, 3943, 3107, 3421, 13721}},
+{1999, 15, 1156, {1, 3, 5, 11, 25, 61, 61, 173, 397, 735, 2005, 3355, 8121, 11593, 27697}},
+{2000, 15, 1163, {1, 3, 5, 15, 17, 43, 63, 231, 275, 311, 1277, 2669, 7307, 2099, 9755}},
+{2001, 15, 1171, {1, 3, 5, 3, 25, 43, 71, 191, 9, 121, 1873, 3747, 7491, 14055, 24293}},
+{2002, 15, 1202, {1, 3, 5, 13, 17, 35, 113, 113, 385, 941, 39, 2705, 1225, 5167, 1373}},
+{2003, 15, 1228, {1, 3, 5, 5, 7, 35, 19, 105, 487, 71, 139, 627, 4187, 3183, 713}},
+{2004, 15, 1239, {1, 1, 5, 13, 29, 29, 103, 5, 157, 869, 1675, 423, 6689, 10697, 5303}},
+{2005, 15, 1255, {1, 1, 5, 1, 29, 31, 61, 111, 473, 963, 685, 1483, 2383, 8109, 8495}},
+{2006, 15, 1256, {1, 1, 5, 3, 19, 13, 95, 113, 217, 59, 1353, 1647, 3617, 3271, 2321}},
+{2007, 15, 1262, {1, 3, 5, 7, 25, 35, 59, 131, 309, 445, 415, 93, 1453, 8789, 30201}},
+{2008, 15, 1270, {1, 1, 5, 1, 5, 43, 71, 241, 123, 189, 831, 3469, 8093, 6187, 32721}},
+{2009, 15, 1279, {1, 3, 7, 5, 25, 31, 123, 171, 319, 379, 889, 2365, 4881, 12225, 16609}},
+{2010, 15, 1308, {1, 3, 1, 11, 27, 43, 121, 63, 291, 591, 811, 1995, 4777, 2083, 31385}},
+{2011, 15, 1322, {1, 1, 5, 11, 27, 53, 85, 187, 461, 823, 703, 399, 6925, 11517, 28697}},
+{2012, 15, 1329, {1, 1, 3, 5, 13, 11, 33, 121, 93, 717, 1275, 3877, 4247, 5845, 26909}},
+{2013, 15, 1330, {1, 3, 1, 9, 7, 5, 47, 199, 367, 561, 185, 2855, 5997, 2699, 7581}},
+{2014, 15, 1336, {1, 1, 5, 9, 23, 11, 71, 201, 61, 729, 1011, 3529, 663, 1413, 25675}},
+{2015, 15, 1341, {1, 3, 7, 13, 27, 21, 11, 127, 281, 487, 1217, 3129, 5541, 3129, 17783}},
+{2016, 15, 1347, {1, 1, 5, 9, 1, 29, 85, 193, 213, 743, 1473, 611, 391, 9405, 21137}},
+{2017, 15, 1349, {1, 3, 3, 3, 31, 63, 37, 147, 39, 351, 79, 3069, 2441, 8901, 8777}},
+{2018, 15, 1359, {1, 1, 7, 7, 25, 49, 55, 47, 441, 343, 1267, 1123, 5917, 14395, 10579}},
+{2019, 15, 1367, {1, 1, 7, 1, 13, 55, 55, 123, 103, 773, 125, 2145, 4743, 13347, 2589}},
+{2020, 15, 1368, {1, 3, 7, 3, 9, 33, 25, 183, 469, 213, 291, 75, 6725, 6847, 26745}},
+{2021, 15, 1390, {1, 3, 3, 7, 15, 43, 7, 79, 171, 21, 1767, 2537, 4285, 12007, 24039}},
+{2022, 15, 1413, {1, 3, 7, 13, 9, 61, 125, 23, 227, 879, 215, 1635, 2835, 883, 15939}},
+{2023, 15, 1414, {1, 1, 5, 13, 25, 45, 63, 43, 183, 829, 149, 989, 987, 3819, 12181}},
+{2024, 15, 1437, {1, 1, 3, 7, 19, 27, 35, 83, 135, 459, 785, 131, 2655, 3329, 3009}},
+{2025, 15, 1441, {1, 1, 7, 5, 11, 41, 9, 219, 475, 985, 1329, 3787, 1975, 4679, 8627}},
+{2026, 15, 1462, {1, 1, 7, 3, 1, 17, 91, 155, 3, 763, 1879, 233, 215, 2955, 25993}},
+{2027, 15, 1465, {1, 1, 1, 11, 25, 11, 23, 227, 453, 775, 1935, 3833, 4583, 269, 705}},
+{2028, 15, 1480, {1, 3, 3, 11, 7, 25, 105, 21, 449, 555, 1275, 3475, 5503, 15617, 813}},
+{2029, 15, 1486, {1, 3, 7, 13, 31, 37, 25, 255, 233, 663, 1155, 1563, 4775, 7449, 29949}},
+{2030, 15, 1504, {1, 1, 3, 1, 23, 51, 51, 137, 63, 809, 349, 2789, 6953, 10605, 18959}},
+{2031, 15, 1509, {1, 3, 3, 13, 21, 45, 15, 161, 393, 229, 437, 2967, 4019, 3893, 21305}},
+{2032, 15, 1514, {1, 1, 3, 7, 5, 11, 15, 211, 287, 131, 1847, 2569, 7881, 15669, 31037}},
+{2033, 15, 1522, {1, 3, 3, 15, 27, 19, 85, 251, 221, 639, 665, 3729, 5771, 7873, 28005}},
+{2034, 15, 1528, {1, 3, 7, 15, 15, 47, 93, 215, 343, 85, 1401, 1375, 2949, 13661, 25453}},
+{2035, 15, 1552, {1, 1, 1, 9, 7, 51, 53, 217, 471, 389, 551, 1141, 1767, 2237, 17797}},
+{2036, 15, 1555, {1, 1, 7, 9, 3, 29, 65, 29, 223, 591, 1719, 1049, 7643, 3853, 29867}},
+{2037, 15, 1571, {1, 1, 1, 11, 13, 41, 85, 29, 451, 387, 1783, 3733, 8033, 4711, 31643}},
+{2038, 15, 1578, {1, 3, 1, 11, 11, 57, 75, 153, 7, 373, 2011, 271, 469, 3267, 18969}},
+{2039, 15, 1585, {1, 1, 5, 3, 19, 43, 7, 243, 385, 293, 923, 843, 4895, 469, 8421}},
+{2040, 15, 1588, {1, 3, 1, 15, 29, 47, 17, 125, 471, 927, 349, 3859, 3059, 11483, 14791}},
+{2041, 15, 1603, {1, 3, 1, 11, 17, 17, 111, 109, 9, 213, 1313, 3903, 4411, 4329, 28277}},
+{2042, 15, 1609, {1, 3, 3, 15, 1, 55, 47, 69, 143, 789, 1149, 3833, 5053, 6949, 10569}},
+{2043, 15, 1617, {1, 3, 5, 7, 11, 15, 79, 83, 123, 937, 1115, 2775, 3041, 11869, 21167}},
+{2044, 15, 1620, {1, 3, 7, 13, 9, 47, 45, 221, 139, 923, 1661, 1379, 2485, 7233, 6035}},
+{2045, 15, 1629, {1, 1, 3, 3, 11, 55, 77, 3, 87, 693, 1991, 1145, 2783, 16207, 24569}},
+{2046, 15, 1636, {1, 1, 5, 11, 3, 35, 91, 9, 391, 927, 101, 1839, 3755, 10345, 16907}},
+{2047, 15, 1648, {1, 3, 5, 3, 5, 49, 79, 91, 205, 443, 1369, 197, 2537, 11219, 17765}},
+{2048, 15, 1667, {1, 1, 3, 15, 9, 7, 25, 25, 357, 247, 477, 421, 7679, 5987, 30079}},
+{2049, 15, 1669, {1, 1, 5, 3, 29, 5, 89, 117, 481, 491, 371, 389, 7101, 2253, 23617}},
+{2050, 15, 1682, {1, 1, 5, 13, 29, 59, 17, 181, 511, 291, 1991, 3499, 8177, 5559, 30045}},
+{2051, 15, 1697, {1, 3, 3, 11, 23, 31, 117, 217, 241, 115, 749, 945, 1897, 12253, 8473}},
+{2052, 15, 1704, {1, 1, 7, 15, 25, 47, 31, 1, 165, 311, 635, 3629, 1593, 8305, 30033}},
+{2053, 15, 1709, {1, 3, 5, 9, 3, 17, 101, 237, 379, 503, 49, 929, 1687, 3865, 26723}},
+{2054, 15, 1727, {1, 3, 5, 5, 15, 41, 1, 239, 53, 215, 1733, 827, 579, 4089, 6579}},
+{2055, 15, 1730, {1, 3, 1, 15, 15, 21, 35, 21, 403, 257, 1475, 2403, 4705, 11553, 203}},
+{2056, 15, 1732, {1, 3, 5, 11, 9, 53, 113, 9, 447, 511, 543, 3141, 7389, 11249, 431}},
+{2057, 15, 1741, {1, 3, 5, 9, 9, 11, 55, 93, 325, 411, 305, 2573, 6871, 12339, 6435}},
+{2058, 15, 1744, {1, 3, 3, 7, 31, 27, 21, 113, 99, 853, 365, 589, 3731, 10875, 12767}},
+{2059, 15, 1759, {1, 3, 1, 7, 15, 27, 31, 17, 275, 93, 1161, 2619, 1329, 7307, 587}},
+{2060, 15, 1765, {1, 3, 5, 9, 17, 47, 49, 237, 27, 193, 1237, 591, 5151, 5521, 31583}},
+{2061, 15, 1766, {1, 3, 5, 3, 13, 1, 27, 87, 43, 977, 305, 3293, 2475, 14571, 18321}},
+{2062, 15, 1778, {1, 1, 5, 7, 15, 13, 101, 1, 291, 807, 1711, 2277, 5573, 11051, 13133}},
+{2063, 15, 1780, {1, 3, 3, 1, 9, 3, 65, 81, 415, 733, 1527, 2747, 6069, 159, 7095}},
+{2064, 15, 1783, {1, 3, 3, 15, 27, 1, 71, 49, 231, 851, 2039, 613, 1899, 2537, 14511}},
+{2065, 15, 1797, {1, 1, 1, 11, 3, 41, 55, 23, 247, 1011, 581, 2363, 2745, 1337, 20931}},
+{2066, 15, 1807, {1, 1, 3, 11, 17, 61, 67, 255, 143, 357, 945, 3407, 5817, 4155, 23851}},
+{2067, 15, 1821, {1, 3, 5, 3, 23, 1, 75, 247, 265, 413, 1899, 2565, 6629, 15655, 16117}},
+{2068, 15, 1832, {1, 1, 1, 9, 11, 49, 11, 189, 223, 177, 1457, 1931, 163, 15905, 17297}},
+{2069, 15, 1835, {1, 3, 7, 13, 17, 1, 111, 189, 343, 961, 427, 2507, 2393, 8653, 6353}},
+{2070, 15, 1849, {1, 3, 7, 13, 23, 61, 59, 51, 313, 963, 791, 3681, 5637, 3965, 9263}},
+{2071, 15, 1850, {1, 3, 7, 7, 21, 53, 127, 141, 499, 859, 337, 2835, 3195, 4351, 32369}},
+{2072, 15, 1863, {1, 1, 7, 5, 1, 5, 53, 63, 497, 535, 35, 305, 4395, 9757, 13193}},
+{2073, 15, 1867, {1, 1, 5, 13, 13, 31, 59, 229, 211, 745, 1453, 3677, 3005, 7703, 23907}},
+{2074, 15, 1869, {1, 3, 5, 5, 7, 63, 17, 197, 493, 861, 499, 3015, 6349, 1815, 7437}},
+{2075, 15, 1872, {1, 1, 1, 13, 13, 37, 29, 189, 253, 1017, 321, 3145, 407, 7547, 17099}},
+{2076, 15, 1887, {1, 3, 3, 3, 23, 53, 69, 77, 175, 17, 1831, 841, 3851, 1295, 32107}},
+{2077, 15, 1888, {1, 3, 7, 13, 13, 39, 107, 237, 389, 729, 635, 3717, 3041, 3169, 14987}},
+{2078, 15, 1897, {1, 1, 3, 1, 25, 7, 69, 35, 495, 49, 659, 2783, 6051, 13875, 23927}},
+{2079, 15, 1906, {1, 3, 7, 5, 5, 25, 49, 7, 193, 493, 93, 657, 1515, 13975, 14155}},
+{2080, 15, 1917, {1, 3, 1, 1, 11, 15, 113, 45, 21, 595, 731, 3397, 4117, 9711, 16625}},
+{2081, 15, 1927, {1, 3, 3, 9, 19, 19, 59, 7, 105, 579, 599, 2859, 97, 14717, 15361}},
+{2082, 15, 1939, {1, 1, 1, 5, 27, 49, 113, 5, 367, 563, 1397, 2805, 3021, 3111, 20671}},
+{2083, 15, 1941, {1, 3, 3, 15, 27, 51, 99, 167, 109, 365, 1959, 1523, 6959, 14405, 18191}},
+{2084, 15, 1948, {1, 3, 1, 5, 21, 51, 125, 67, 123, 45, 1657, 51, 4825, 14081, 31049}},
+{2085, 15, 1970, {1, 1, 5, 7, 21, 59, 21, 249, 77, 793, 1687, 2561, 2241, 4321, 7477}},
+{2086, 15, 1979, {1, 1, 1, 7, 15, 35, 71, 29, 267, 611, 1813, 1823, 7039, 3299, 9919}},
+{2087, 15, 1982, {1, 3, 7, 11, 21, 59, 109, 213, 371, 785, 659, 1687, 4827, 6017, 19619}},
+{2088, 15, 2002, {1, 1, 3, 11, 27, 17, 1, 55, 367, 939, 333, 127, 5105, 2405, 28139}},
+{2089, 15, 2020, {1, 1, 7, 13, 5, 35, 59, 133, 509, 573, 625, 3857, 7935, 5279, 3727}},
+{2090, 15, 2024, {1, 1, 1, 7, 11, 47, 127, 157, 19, 403, 151, 1143, 7407, 8985, 32521}},
+{2091, 15, 2032, {1, 3, 1, 1, 5, 13, 105, 123, 63, 139, 1569, 1983, 563, 7175, 27705}},
+{2092, 15, 2053, {1, 1, 3, 13, 9, 35, 105, 227, 145, 21, 1369, 57, 393, 2921, 18511}},
+{2093, 15, 2060, {1, 3, 1, 7, 17, 61, 99, 187, 261, 281, 437, 2219, 5999, 1857, 18001}},
+{2094, 15, 2063, {1, 3, 3, 5, 1, 59, 67, 45, 451, 439, 2005, 3607, 3, 7167, 14227}},
+{2095, 15, 2066, {1, 3, 3, 3, 29, 19, 25, 251, 275, 733, 1749, 4021, 871, 3227, 13701}},
+{2096, 15, 2075, {1, 3, 3, 13, 27, 53, 57, 243, 491, 521, 1921, 1037, 5013, 5703, 15261}},
+{2097, 15, 2078, {1, 3, 1, 11, 13, 57, 1, 15, 123, 533, 785, 335, 1423, 14269, 3483}},
+{2098, 15, 2081, {1, 3, 7, 13, 15, 55, 5, 139, 385, 47, 1981, 1291, 7397, 12925, 29445}},
+{2099, 15, 2091, {1, 1, 7, 1, 23, 23, 59, 93, 117, 57, 63, 3047, 4849, 11637, 25311}},
+{2100, 15, 2096, {1, 1, 7, 13, 19, 37, 25, 203, 477, 447, 1345, 3485, 2099, 13347, 11621}},
+{2101, 15, 2102, {1, 1, 7, 3, 11, 23, 81, 17, 41, 735, 1149, 3253, 7665, 8291, 22293}},
+{2102, 15, 2106, {1, 1, 5, 3, 15, 9, 57, 167, 463, 493, 747, 1947, 6471, 1111, 31619}},
+{2103, 15, 2116, {1, 1, 5, 15, 7, 15, 107, 205, 325, 167, 1749, 927, 3589, 6127, 7617}},
+{2104, 15, 2120, {1, 1, 1, 13, 21, 25, 83, 147, 411, 399, 1423, 2279, 3661, 7591, 17429}},
+{2105, 15, 2125, {1, 1, 1, 9, 5, 17, 69, 205, 243, 647, 473, 1717, 1977, 10725, 2913}},
+{2106, 15, 2134, {1, 1, 3, 5, 5, 37, 103, 15, 485, 641, 1761, 3755, 6997, 10985, 11773}},
+{2107, 15, 2178, {1, 1, 5, 13, 9, 51, 87, 195, 97, 807, 1801, 961, 6341, 4307, 29105}},
+{2108, 15, 2180, {1, 3, 1, 13, 9, 35, 83, 61, 387, 817, 951, 3993, 7831, 8479, 23941}},
+{2109, 15, 2187, {1, 1, 7, 11, 19, 47, 75, 37, 91, 337, 953, 1169, 163, 2259, 24713}},
+{2110, 15, 2189, {1, 1, 1, 11, 13, 15, 83, 171, 159, 87, 619, 2973, 2653, 13725, 12499}},
+{2111, 15, 2190, {1, 3, 5, 3, 5, 63, 119, 25, 343, 269, 553, 2183, 959, 3825, 22189}},
+{2112, 15, 2208, {1, 1, 5, 15, 5, 37, 89, 109, 497, 1013, 265, 669, 1859, 2647, 3445}},
+{2113, 15, 2214, {1, 3, 3, 9, 21, 21, 15, 245, 107, 649, 367, 1601, 7279, 15783, 4943}},
+{2114, 15, 2237, {1, 3, 3, 15, 5, 41, 125, 113, 159, 161, 1191, 3491, 3531, 55, 20857}},
+{2115, 15, 2252, {1, 3, 5, 9, 21, 57, 21, 195, 99, 193, 1915, 2923, 6349, 15085, 24929}},
+{2116, 15, 2257, {1, 1, 1, 11, 31, 11, 73, 141, 361, 621, 1021, 2067, 5115, 12665, 26845}},
+{2117, 15, 2260, {1, 1, 1, 3, 29, 11, 43, 61, 209, 923, 1753, 1937, 843, 205, 8367}},
+{2118, 15, 2264, {1, 1, 1, 5, 15, 33, 119, 209, 215, 973, 1775, 815, 6693, 7957, 14517}},
+{2119, 15, 2270, {1, 1, 1, 5, 17, 57, 27, 147, 489, 59, 1439, 2279, 445, 11791, 19739}},
+{2120, 15, 2279, {1, 3, 1, 7, 11, 55, 1, 83, 305, 17, 1909, 405, 2325, 5293, 28559}},
+{2121, 15, 2288, {1, 3, 3, 7, 11, 27, 103, 157, 455, 1005, 2033, 3145, 1919, 15723, 25197}},
+{2122, 15, 2305, {1, 1, 5, 11, 15, 51, 37, 131, 503, 1007, 1795, 2421, 1335, 7413, 21741}},
+{2123, 15, 2312, {1, 1, 3, 1, 23, 63, 69, 83, 419, 283, 583, 123, 7725, 2243, 8403}},
+{2124, 15, 2317, {1, 1, 5, 5, 27, 45, 109, 17, 299, 65, 351, 947, 1165, 10723, 2053}},
+{2125, 15, 2323, {1, 1, 3, 3, 23, 61, 115, 253, 1, 931, 1481, 3187, 441, 14735, 27207}},
+{2126, 15, 2329, {1, 1, 5, 3, 25, 11, 83, 141, 359, 343, 901, 1629, 731, 12841, 14357}},
+{2127, 15, 2335, {1, 1, 3, 9, 7, 45, 97, 3, 299, 217, 663, 1527, 6379, 4527, 26147}},
+{2128, 15, 2342, {1, 1, 7, 9, 11, 53, 9, 203, 337, 713, 1517, 719, 4587, 11443, 26905}},
+{2129, 15, 2345, {1, 1, 7, 9, 11, 41, 125, 213, 237, 377, 361, 3231, 4223, 3263, 12655}},
+{2130, 15, 2365, {1, 3, 7, 7, 7, 33, 99, 19, 117, 273, 985, 107, 3831, 10135, 19423}},
+{2131, 15, 2371, {1, 1, 5, 15, 25, 41, 13, 125, 449, 169, 1149, 4021, 5663, 3077, 19163}},
+{2132, 15, 2378, {1, 3, 5, 9, 25, 57, 47, 103, 269, 51, 1805, 2503, 6687, 8065, 12045}},
+{2133, 15, 2385, {1, 3, 5, 7, 3, 35, 87, 225, 189, 229, 931, 3293, 1347, 1427, 3269}},
+{2134, 15, 2395, {1, 1, 1, 3, 5, 31, 61, 19, 247, 9, 1667, 343, 559, 2703, 3763}},
+{2135, 15, 2404, {1, 3, 5, 15, 31, 19, 57, 187, 109, 121, 1287, 2269, 659, 16235, 1273}},
+{2136, 15, 2414, {1, 1, 1, 3, 5, 47, 59, 243, 255, 97, 1959, 1723, 1347, 3019, 26989}},
+{2137, 15, 2426, {1, 3, 3, 15, 29, 35, 75, 67, 497, 731, 193, 3307, 3579, 12005, 7209}},
+{2138, 15, 2428, {1, 1, 5, 9, 13, 35, 79, 213, 51, 983, 1927, 1793, 5037, 5463, 965}},
+{2139, 15, 2441, {1, 1, 7, 11, 5, 41, 7, 83, 15, 411, 1775, 3515, 6755, 3249, 16425}},
+{2140, 15, 2456, {1, 3, 5, 1, 19, 61, 3, 19, 395, 819, 1331, 179, 5225, 5333, 3601}},
+{2141, 15, 2466, {1, 1, 3, 9, 7, 5, 87, 15, 387, 609, 1465, 277, 987, 8377, 903}},
+{2142, 15, 2468, {1, 1, 1, 3, 15, 11, 123, 107, 355, 333, 285, 1801, 6989, 1549, 25791}},
+{2143, 15, 2475, {1, 1, 7, 13, 27, 13, 73, 111, 481, 227, 1091, 365, 5713, 5087, 27217}},
+{2144, 15, 2489, {1, 3, 3, 15, 1, 55, 95, 213, 377, 405, 139, 1867, 2175, 4217, 28813}},
+{2145, 15, 2495, {1, 3, 5, 11, 21, 43, 109, 155, 181, 901, 1951, 507, 4389, 10815, 3141}},
+{2146, 15, 2497, {1, 1, 1, 15, 17, 11, 43, 215, 501, 19, 259, 3479, 6381, 6927, 31247}},
+{2147, 15, 2510, {1, 3, 5, 15, 19, 61, 75, 41, 391, 95, 865, 1441, 7993, 13979, 24663}},
+{2148, 15, 2512, {1, 3, 1, 3, 21, 15, 115, 213, 1, 645, 777, 1517, 2543, 11223, 3633}},
+{2149, 15, 2522, {1, 3, 5, 3, 9, 57, 39, 211, 407, 65, 1795, 2805, 2799, 8691, 1987}},
+{2150, 15, 2533, {1, 1, 3, 13, 17, 55, 47, 113, 29, 139, 1301, 3303, 1129, 13947, 29821}},
+{2151, 15, 2543, {1, 1, 3, 13, 5, 35, 97, 151, 477, 409, 1397, 3399, 4421, 15929, 6163}},
+{2152, 15, 2551, {1, 3, 1, 9, 21, 51, 99, 133, 149, 763, 623, 173, 4311, 11081, 1095}},
+{2153, 15, 2552, {1, 3, 7, 15, 13, 3, 99, 3, 195, 907, 1335, 1355, 7977, 5773, 32383}},
+{2154, 15, 2557, {1, 1, 3, 9, 17, 43, 43, 217, 475, 917, 1373, 1677, 4871, 9619, 16657}},
+{2155, 15, 2567, {1, 3, 3, 7, 31, 31, 55, 11, 73, 693, 25, 417, 1195, 6225, 32279}},
+{2156, 15, 2581, {1, 3, 5, 9, 21, 57, 127, 149, 79, 379, 1609, 2543, 6473, 16033, 27191}},
+{2157, 15, 2586, {1, 1, 5, 1, 13, 9, 81, 153, 297, 789, 1749, 2819, 3961, 11231, 24927}},
+{2158, 15, 2597, {1, 3, 5, 3, 23, 61, 45, 43, 43, 133, 1481, 1543, 2991, 13739, 10287}},
+{2159, 15, 2601, {1, 1, 3, 9, 25, 43, 31, 177, 337, 193, 1083, 1, 991, 9725, 8379}},
+{2160, 15, 2622, {1, 3, 5, 11, 13, 33, 65, 83, 421, 149, 409, 2443, 7423, 8847, 29599}},
+{2161, 15, 2633, {1, 1, 5, 11, 11, 1, 23, 225, 77, 585, 1505, 2525, 739, 10915, 25733}},
+{2162, 15, 2636, {1, 3, 7, 13, 7, 55, 3, 223, 415, 521, 1865, 2349, 5663, 7455, 16569}},
+{2163, 15, 2642, {1, 1, 7, 13, 1, 45, 121, 49, 463, 99, 1061, 2559, 5087, 13389, 11035}},
+{2164, 15, 2644, {1, 3, 7, 11, 31, 51, 35, 235, 385, 1023, 1771, 2013, 5437, 4877, 22119}},
+{2165, 15, 2653, {1, 3, 3, 11, 21, 3, 11, 119, 81, 737, 1093, 2377, 4055, 1121, 15767}},
+{2166, 15, 2667, {1, 1, 5, 13, 9, 3, 83, 217, 387, 249, 1047, 1861, 4103, 15367, 24545}},
+{2167, 15, 2669, {1, 3, 3, 1, 5, 37, 43, 183, 383, 463, 937, 1165, 1481, 959, 17047}},
+{2168, 15, 2672, {1, 1, 3, 5, 7, 43, 127, 243, 81, 1021, 165, 753, 4711, 12965, 22049}},
+{2169, 15, 2675, {1, 1, 5, 5, 3, 61, 65, 53, 425, 89, 5, 1467, 1395, 9579, 8961}},
+{2170, 15, 2682, {1, 3, 7, 13, 11, 35, 123, 21, 83, 689, 667, 1203, 5959, 15697, 26885}},
+{2171, 15, 2687, {1, 1, 5, 13, 9, 49, 41, 101, 291, 339, 1067, 657, 4453, 1137, 21131}},
+{2172, 15, 2691, {1, 3, 3, 3, 17, 61, 11, 213, 27, 805, 1691, 1057, 6011, 11941, 18883}},
+{2173, 15, 2698, {1, 3, 1, 7, 3, 51, 5, 63, 121, 3, 245, 2631, 3737, 16121, 26803}},
+{2174, 15, 2708, {1, 3, 1, 1, 23, 51, 79, 19, 161, 107, 609, 3489, 3389, 4035, 2427}},
+{2175, 15, 2712, {1, 3, 1, 1, 17, 11, 101, 101, 373, 63, 1641, 285, 1333, 165, 14025}},
+{2176, 15, 2718, {1, 1, 1, 5, 1, 51, 83, 137, 45, 1019, 821, 867, 6055, 10443, 9857}},
+{2177, 15, 2722, {1, 3, 1, 5, 17, 23, 25, 181, 429, 495, 317, 3219, 5963, 13945, 9969}},
+{2178, 15, 2736, {1, 3, 7, 3, 3, 15, 123, 191, 369, 177, 1697, 2113, 3889, 5201, 21839}},
+{2179, 15, 2741, {1, 3, 1, 11, 21, 39, 51, 139, 271, 605, 1007, 3513, 3365, 3781, 6799}},
+{2180, 15, 2756, {1, 1, 7, 5, 13, 19, 47, 165, 249, 405, 255, 1295, 4513, 14395, 5587}},
+{2181, 15, 2765, {1, 1, 3, 7, 5, 17, 99, 1, 393, 31, 621, 797, 6113, 16003, 32043}},
+{2182, 15, 2774, {1, 3, 5, 13, 11, 21, 65, 81, 147, 443, 775, 3671, 7029, 11749, 3339}},
+{2183, 15, 2799, {1, 3, 7, 1, 23, 33, 99, 177, 161, 577, 1729, 617, 3465, 11787, 17577}},
+{2184, 15, 2804, {1, 1, 5, 7, 15, 15, 53, 193, 97, 255, 1223, 545, 5153, 873, 24525}},
+{2185, 15, 2825, {1, 3, 5, 1, 7, 57, 47, 121, 383, 835, 1709, 2363, 4731, 12163, 7001}},
+{2186, 15, 2826, {1, 3, 3, 11, 19, 33, 63, 99, 387, 95, 783, 1009, 6373, 4021, 7685}},
+{2187, 15, 2840, {1, 1, 1, 15, 25, 33, 73, 135, 335, 785, 935, 1927, 5847, 10501, 7719}},
+{2188, 15, 2843, {1, 1, 5, 3, 27, 45, 71, 215, 489, 157, 1189, 2577, 6901, 10219, 3025}},
+{2189, 15, 2846, {1, 1, 7, 7, 21, 3, 97, 225, 101, 159, 293, 2789, 7955, 14829, 1209}},
+{2190, 15, 2849, {1, 3, 1, 5, 23, 41, 83, 63, 361, 195, 1707, 2081, 5363, 6327, 179}},
+{2191, 15, 2867, {1, 1, 3, 1, 21, 51, 59, 67, 175, 363, 825, 2971, 3321, 8837, 11805}},
+{2192, 15, 2876, {1, 3, 7, 1, 19, 3, 15, 21, 429, 675, 1589, 2615, 2575, 1537, 7139}},
+{2193, 15, 2891, {1, 3, 3, 5, 21, 29, 17, 115, 345, 397, 523, 1699, 7043, 11173, 3023}},
+{2194, 15, 2902, {1, 1, 5, 7, 19, 63, 99, 175, 91, 433, 153, 3749, 517, 13667, 7423}},
+{2195, 15, 2912, {1, 3, 7, 3, 25, 23, 53, 149, 65, 551, 1231, 365, 6637, 15137, 16319}},
+{2196, 15, 2917, {1, 3, 7, 13, 5, 45, 11, 151, 323, 31, 1749, 409, 6753, 10503, 14991}},
+{2197, 15, 2927, {1, 3, 7, 3, 5, 21, 29, 117, 321, 341, 1811, 3619, 4337, 12255, 8629}},
+{2198, 15, 2941, {1, 3, 7, 3, 7, 3, 5, 221, 407, 671, 1763, 3669, 2353, 8175, 23489}},
+{2199, 15, 2965, {1, 1, 3, 7, 11, 55, 53, 185, 247, 35, 1823, 513, 1379, 11827, 20069}},
+{2200, 15, 2970, {1, 3, 3, 5, 29, 51, 73, 191, 185, 961, 881, 2019, 5651, 1019, 15587}},
+{2201, 15, 2982, {1, 3, 7, 13, 7, 55, 59, 5, 417, 829, 453, 2339, 587, 13283, 797}},
+{2202, 15, 2993, {1, 3, 7, 3, 11, 41, 75, 85, 65, 149, 1583, 529, 2707, 11479, 7109}},
+{2203, 15, 3018, {1, 3, 7, 9, 13, 57, 37, 243, 91, 613, 665, 171, 1631, 13737, 2377}},
+{2204, 15, 3023, {1, 1, 3, 7, 5, 43, 97, 53, 477, 793, 999, 3647, 2555, 7371, 19295}},
+{2205, 15, 3025, {1, 1, 7, 1, 1, 9, 99, 253, 317, 817, 1559, 2081, 2529, 14611, 15997}},
+{2206, 15, 3026, {1, 3, 3, 1, 5, 41, 57, 121, 387, 441, 709, 1511, 7045, 8409, 13297}},
+{2207, 15, 3028, {1, 1, 1, 13, 29, 57, 63, 183, 327, 473, 1943, 213, 3973, 16289, 2739}},
+{2208, 15, 3032, {1, 3, 7, 9, 25, 15, 75, 185, 335, 881, 1041, 3339, 4471, 6823, 21121}},
+{2209, 15, 3053, {1, 3, 3, 13, 23, 3, 57, 117, 511, 927, 771, 3229, 949, 15487, 11963}},
+{2210, 15, 3054, {1, 1, 3, 7, 27, 19, 55, 207, 331, 705, 1945, 797, 7125, 10493, 16585}},
+{2211, 15, 3065, {1, 3, 1, 1, 29, 7, 91, 93, 459, 93, 1501, 1927, 6415, 16255, 9823}},
+{2212, 15, 3071, {1, 1, 5, 5, 31, 11, 97, 179, 505, 807, 877, 4003, 4377, 8851, 4239}},
+{2213, 15, 3076, {1, 1, 3, 5, 11, 25, 17, 131, 23, 95, 311, 1429, 2029, 13091, 23739}},
+{2214, 15, 3088, {1, 1, 3, 11, 13, 27, 33, 127, 481, 117, 1127, 1619, 6493, 8507, 6615}},
+{2215, 15, 3107, {1, 3, 1, 13, 19, 27, 89, 101, 27, 235, 1579, 1701, 4421, 16037, 16239}},
+{2216, 15, 3146, {1, 3, 1, 15, 1, 15, 3, 117, 317, 475, 1691, 2423, 5519, 1703, 2969}},
+{2217, 15, 3148, {1, 1, 3, 1, 13, 15, 19, 37, 237, 467, 1321, 453, 2169, 13313, 31499}},
+{2218, 15, 3159, {1, 1, 3, 15, 29, 55, 31, 199, 85, 285, 967, 367, 3941, 151, 20587}},
+{2219, 15, 3165, {1, 3, 7, 15, 7, 13, 31, 35, 117, 543, 1179, 3441, 3039, 11225, 30229}},
+{2220, 15, 3170, {1, 1, 3, 15, 3, 43, 1, 63, 353, 395, 1775, 3493, 5175, 13193, 25343}},
+{2221, 15, 3179, {1, 3, 3, 15, 17, 25, 57, 205, 411, 83, 1877, 2093, 5599, 12115, 8751}},
+{2222, 15, 3182, {1, 1, 1, 11, 15, 9, 115, 99, 85, 887, 987, 4015, 7077, 3739, 21505}},
+{2223, 15, 3205, {1, 3, 1, 11, 25, 39, 127, 37, 329, 273, 1531, 3211, 7115, 15501, 26575}},
+{2224, 15, 3212, {1, 1, 5, 13, 15, 3, 3, 101, 431, 645, 493, 723, 8083, 1423, 14879}},
+{2225, 15, 3218, {1, 3, 3, 5, 31, 35, 37, 131, 259, 849, 325, 3403, 3627, 3295, 30885}},
+{2226, 15, 3220, {1, 3, 7, 1, 9, 3, 31, 201, 379, 907, 1005, 3333, 7457, 2533, 30357}},
+{2227, 15, 3223, {1, 3, 1, 9, 7, 7, 95, 103, 121, 157, 895, 2683, 5839, 12403, 14327}},
+{2228, 15, 3227, {1, 3, 7, 3, 13, 5, 55, 233, 3, 855, 859, 1115, 3883, 8041, 3353}},
+{2229, 15, 3233, {1, 1, 5, 9, 3, 55, 99, 79, 263, 831, 1579, 205, 5673, 1999, 14879}},
+{2230, 15, 3234, {1, 3, 1, 5, 17, 25, 85, 19, 189, 141, 877, 667, 4461, 11915, 23247}},
+{2231, 15, 3254, {1, 1, 5, 5, 1, 35, 15, 219, 469, 725, 1793, 3683, 3661, 15627, 30197}},
+{2232, 15, 3263, {1, 1, 7, 5, 27, 3, 41, 153, 431, 487, 759, 1345, 6735, 9937, 26277}},
+{2233, 15, 3268, {1, 1, 1, 11, 11, 13, 41, 121, 265, 465, 1447, 5, 3407, 1907, 10037}},
+{2234, 15, 3272, {1, 3, 5, 9, 15, 63, 5, 7, 407, 83, 365, 3687, 7721, 6973, 16967}},
+{2235, 15, 3277, {1, 1, 7, 7, 5, 41, 75, 155, 417, 565, 1199, 1111, 2823, 10703, 22561}},
+{2236, 15, 3292, {1, 3, 7, 5, 7, 43, 39, 185, 105, 327, 1977, 1137, 3261, 10583, 11661}},
+{2237, 15, 3295, {1, 3, 7, 7, 19, 19, 103, 137, 169, 273, 1357, 3413, 7647, 10531, 32489}},
+{2238, 15, 3296, {1, 1, 3, 13, 13, 3, 81, 23, 161, 295, 735, 2031, 1027, 15513, 20165}},
+{2239, 15, 3301, {1, 1, 5, 1, 15, 1, 91, 35, 375, 207, 1417, 1115, 2237, 11749, 8509}},
+{2240, 15, 3306, {1, 3, 7, 3, 25, 51, 49, 219, 195, 417, 1523, 3953, 5739, 7499, 27071}},
+{2241, 15, 3313, {1, 1, 3, 11, 23, 29, 19, 81, 421, 633, 513, 547, 7545, 29, 11909}},
+{2242, 15, 3346, {1, 1, 1, 7, 13, 61, 33, 243, 221, 231, 111, 879, 2861, 1795, 27531}},
+{2243, 15, 3367, {1, 3, 7, 3, 19, 21, 1, 141, 159, 605, 969, 3013, 6583, 2447, 19919}},
+{2244, 15, 3371, {1, 3, 7, 3, 31, 9, 91, 83, 29, 873, 929, 43, 2253, 12539, 23951}},
+{2245, 15, 3373, {1, 1, 5, 3, 31, 15, 87, 105, 319, 973, 1489, 3417, 3377, 15749, 2357}},
+{2246, 15, 3374, {1, 1, 3, 15, 7, 23, 3, 81, 383, 419, 713, 997, 6873, 593, 285}},
+{2247, 15, 3376, {1, 3, 3, 1, 29, 13, 29, 101, 441, 693, 2039, 2951, 5921, 12129, 12053}},
+{2248, 15, 3382, {1, 1, 3, 15, 9, 29, 97, 117, 421, 433, 1017, 125, 3607, 9415, 6843}},
+{2249, 15, 3388, {1, 3, 5, 9, 11, 13, 75, 155, 413, 75, 109, 1599, 6161, 16115, 12621}},
+{2250, 15, 3391, {1, 3, 3, 3, 11, 13, 49, 225, 401, 599, 1815, 1643, 7853, 13305, 25195}},
+{2251, 15, 3403, {1, 3, 7, 5, 15, 11, 27, 95, 387, 931, 549, 2179, 3397, 15883, 16563}},
+{2252, 15, 3406, {1, 1, 7, 3, 9, 39, 121, 5, 453, 27, 1747, 657, 2593, 1289, 12577}},
+{2253, 15, 3413, {1, 3, 7, 5, 25, 25, 109, 49, 185, 985, 631, 803, 3865, 8955, 17901}},
+{2254, 15, 3420, {1, 1, 3, 13, 3, 59, 47, 49, 139, 275, 1471, 2995, 5593, 14011, 18741}},
+{2255, 15, 3427, {1, 1, 5, 15, 29, 11, 97, 225, 245, 291, 1873, 2365, 767, 3419, 14943}},
+{2256, 15, 3441, {1, 3, 3, 5, 15, 17, 19, 209, 359, 891, 1375, 2003, 7247, 5299, 28841}},
+{2257, 15, 3453, {1, 3, 7, 7, 9, 55, 105, 35, 77, 47, 1023, 13, 2901, 847, 10265}},
+{2258, 15, 3464, {1, 3, 7, 7, 7, 5, 65, 233, 141, 277, 1333, 2357, 443, 7257, 21979}},
+{2259, 15, 3469, {1, 3, 5, 11, 13, 63, 41, 87, 193, 737, 1085, 2317, 7869, 10149, 12163}},
+{2260, 15, 3481, {1, 3, 1, 1, 7, 57, 75, 235, 461, 857, 155, 2679, 5925, 2565, 10881}},
+{2261, 15, 3488, {1, 1, 7, 15, 13, 41, 63, 135, 433, 387, 1943, 2249, 5469, 11679, 28661}},
+{2262, 15, 3497, {1, 3, 3, 13, 5, 3, 103, 161, 367, 649, 789, 1179, 4163, 5699, 16787}},
+{2263, 15, 3503, {1, 3, 7, 7, 31, 13, 45, 141, 113, 769, 1035, 457, 6709, 14989, 27311}},
+{2264, 15, 3511, {1, 1, 3, 1, 1, 43, 119, 145, 111, 593, 1139, 417, 637, 4437, 17285}},
+{2265, 15, 3515, {1, 3, 5, 9, 9, 33, 19, 99, 201, 685, 1793, 2621, 6857, 8769, 5623}},
+{2266, 15, 3525, {1, 3, 5, 5, 23, 43, 27, 189, 325, 415, 215, 1253, 3599, 1215, 10093}},
+{2267, 15, 3529, {1, 1, 3, 13, 11, 35, 113, 173, 503, 19, 1459, 503, 5363, 3967, 13945}},
+{2268, 15, 3547, {1, 1, 5, 11, 31, 49, 13, 173, 199, 623, 1231, 2495, 6581, 7957, 25321}},
+{2269, 15, 3550, {1, 3, 1, 9, 23, 3, 79, 149, 505, 937, 1839, 3701, 1673, 8589, 8031}},
+{2270, 15, 3573, {1, 3, 3, 5, 21, 27, 107, 11, 505, 407, 177, 3593, 4729, 12773, 11685}},
+{2271, 15, 3583, {1, 3, 1, 11, 29, 49, 79, 53, 61, 895, 2035, 563, 5613, 6065, 6207}},
+{2272, 15, 3594, {1, 1, 3, 7, 1, 53, 3, 215, 99, 865, 1749, 3533, 4305, 1243, 28463}},
+{2273, 15, 3607, {1, 1, 1, 13, 31, 59, 115, 53, 403, 909, 847, 103, 4967, 10623, 30073}},
+{2274, 15, 3613, {1, 1, 7, 5, 27, 1, 119, 83, 457, 81, 395, 811, 6221, 14337, 541}},
+{2275, 15, 3624, {1, 1, 5, 5, 5, 53, 83, 117, 269, 327, 875, 101, 3343, 715, 26339}},
+{2276, 15, 3630, {1, 1, 1, 11, 31, 39, 121, 147, 305, 383, 1211, 1897, 7647, 11687, 18907}},
+{2277, 15, 3635, {1, 3, 3, 15, 23, 53, 17, 85, 395, 503, 61, 1745, 4713, 4641, 13787}},
+{2278, 15, 3642, {1, 1, 7, 7, 27, 1, 105, 29, 287, 37, 959, 975, 4427, 4705, 10175}},
+{2279, 15, 3644, {1, 3, 3, 5, 7, 63, 57, 199, 27, 107, 1095, 3923, 6969, 713, 11619}},
+{2280, 15, 3650, {1, 3, 5, 1, 5, 49, 85, 45, 449, 45, 49, 3419, 1109, 455, 15917}},
+{2281, 15, 3679, {1, 1, 1, 5, 13, 15, 39, 27, 467, 85, 1537, 3055, 1977, 8829, 25231}},
+{2282, 15, 3690, {1, 1, 1, 15, 1, 47, 23, 121, 147, 547, 1865, 1491, 779, 3515, 12667}},
+{2283, 15, 3698, {1, 3, 3, 1, 19, 5, 77, 101, 1, 721, 1149, 2967, 4925, 11889, 16655}},
+{2284, 15, 3704, {1, 1, 1, 7, 1, 35, 95, 239, 127, 855, 1031, 455, 7631, 6039, 21983}},
+{2285, 15, 3707, {1, 3, 7, 9, 23, 43, 75, 105, 335, 223, 1825, 3217, 413, 7473, 30005}},
+{2286, 15, 3713, {1, 1, 5, 15, 29, 9, 43, 145, 223, 523, 511, 323, 5955, 11141, 22533}},
+{2287, 15, 3754, {1, 1, 3, 1, 13, 61, 93, 133, 461, 233, 383, 693, 7347, 3165, 27493}},
+{2288, 15, 3756, {1, 3, 7, 1, 13, 45, 113, 207, 53, 1007, 815, 1145, 2937, 289, 22195}},
+{2289, 15, 3761, {1, 3, 5, 5, 19, 17, 113, 89, 19, 1023, 1625, 3277, 697, 5187, 15433}},
+{2290, 15, 3776, {1, 1, 3, 13, 21, 15, 15, 197, 409, 391, 1993, 2475, 3189, 4431, 29585}},
+{2291, 15, 3781, {1, 1, 5, 5, 31, 7, 111, 231, 187, 543, 45, 3863, 3811, 4573, 4437}},
+{2292, 15, 3788, {1, 3, 3, 7, 19, 7, 123, 23, 79, 513, 189, 3663, 1291, 13257, 8949}},
+{2293, 15, 3791, {1, 1, 5, 13, 3, 53, 109, 133, 157, 223, 651, 3059, 6055, 14455, 26903}},
+{2294, 15, 3794, {1, 1, 7, 1, 23, 63, 59, 229, 17, 199, 643, 637, 7631, 13647, 7399}},
+{2295, 15, 3806, {1, 1, 1, 3, 1, 51, 119, 67, 335, 543, 913, 3565, 4795, 13405, 7463}},
+{2296, 15, 3841, {1, 1, 5, 3, 31, 5, 91, 97, 23, 223, 837, 1353, 1929, 12043, 10039}},
+{2297, 15, 3848, {1, 3, 5, 7, 19, 3, 79, 171, 301, 687, 1545, 355, 4709, 12965, 16797}},
+{2298, 15, 3851, {1, 3, 5, 11, 11, 49, 111, 123, 251, 569, 1605, 401, 5439, 13519, 8847}},
+{2299, 15, 3856, {1, 3, 1, 3, 3, 53, 7, 55, 369, 633, 181, 4037, 2993, 15815, 8661}},
+{2300, 15, 3868, {1, 1, 1, 13, 31, 29, 75, 167, 279, 597, 539, 1791, 8013, 4387, 9717}},
+{2301, 15, 3875, {1, 1, 5, 7, 17, 15, 99, 183, 211, 49, 225, 3143, 4537, 13141, 23375}},
+{2302, 15, 3882, {1, 1, 3, 5, 3, 59, 25, 149, 467, 69, 1939, 1007, 2765, 4693, 29815}},
+{2303, 15, 3884, {1, 3, 1, 3, 17, 33, 119, 189, 447, 251, 879, 177, 5395, 13487, 9587}},
+{2304, 15, 3889, {1, 3, 3, 7, 15, 31, 115, 3, 21, 817, 475, 1849, 6041, 12541, 18701}},
+{2305, 15, 3892, {1, 1, 5, 13, 31, 33, 7, 115, 361, 587, 1919, 1007, 3537, 7493, 19357}},
+{2306, 15, 3919, {1, 3, 7, 13, 23, 35, 15, 111, 123, 633, 805, 1983, 2109, 14477, 4985}},
+{2307, 15, 3921, {1, 3, 3, 11, 25, 13, 11, 205, 97, 893, 927, 1291, 4007, 13593, 29693}},
+{2308, 15, 3958, {1, 3, 5, 15, 9, 13, 121, 89, 215, 823, 1389, 1581, 8095, 4707, 16061}},
+{2309, 15, 3961, {1, 3, 1, 3, 23, 39, 83, 23, 47, 941, 1419, 2389, 5699, 7519, 5829}},
+{2310, 15, 3973, {1, 3, 1, 9, 23, 43, 79, 237, 93, 203, 695, 225, 5645, 3591, 16775}},
+{2311, 15, 3977, {1, 3, 5, 3, 15, 19, 89, 129, 375, 125, 225, 1323, 2267, 11607, 17937}},
+{2312, 15, 3985, {1, 3, 3, 1, 31, 37, 93, 133, 377, 959, 707, 621, 7179, 15493, 30287}},
+{2313, 15, 3991, {1, 3, 7, 13, 5, 13, 15, 1, 37, 525, 1641, 2829, 6139, 4069, 19187}},
+{2314, 15, 4004, {1, 3, 3, 9, 17, 3, 67, 97, 375, 845, 403, 973, 3919, 2275, 31627}},
+{2315, 15, 4007, {1, 1, 3, 3, 25, 7, 91, 67, 271, 465, 481, 3477, 5229, 241, 8411}},
+{2316, 15, 4019, {1, 1, 1, 11, 1, 41, 109, 115, 75, 787, 309, 2887, 179, 9073, 13895}},
+{2317, 15, 4045, {1, 3, 3, 15, 11, 31, 113, 91, 303, 907, 1933, 2167, 7799, 11821, 20659}},
+{2318, 15, 4054, {1, 3, 1, 15, 27, 17, 21, 41, 99, 137, 1397, 929, 5819, 11977, 6201}},
+{2319, 15, 4057, {1, 1, 7, 13, 21, 29, 47, 239, 287, 305, 899, 2711, 1723, 3315, 199}},
+{2320, 15, 4058, {1, 1, 1, 3, 31, 21, 101, 149, 107, 761, 1197, 1703, 4803, 8411, 10649}},
+{2321, 15, 4070, {1, 1, 5, 15, 23, 45, 109, 221, 85, 619, 169, 1013, 3305, 9451, 26189}},
+{2322, 15, 4101, {1, 3, 5, 13, 7, 57, 19, 153, 231, 627, 565, 1595, 6309, 5037, 25505}},
+{2323, 15, 4113, {1, 1, 7, 7, 1, 45, 43, 79, 271, 59, 219, 2255, 1785, 7919, 24061}},
+{2324, 15, 4114, {1, 3, 7, 5, 31, 57, 57, 231, 33, 227, 531, 679, 1141, 85, 19777}},
+{2325, 15, 4119, {1, 1, 3, 15, 11, 59, 59, 169, 459, 693, 907, 1191, 3783, 12809, 6263}},
+{2326, 15, 4129, {1, 1, 7, 13, 19, 21, 105, 65, 267, 141, 1547, 781, 7295, 13565, 17775}},
+{2327, 15, 4141, {1, 3, 3, 5, 31, 63, 97, 155, 477, 661, 329, 797, 2539, 4061, 10537}},
+{2328, 15, 4142, {1, 3, 3, 7, 11, 17, 119, 89, 71, 103, 1043, 413, 6035, 12829, 11559}},
+{2329, 15, 4147, {1, 3, 1, 9, 5, 19, 53, 185, 103, 629, 2015, 1257, 5163, 10581, 13449}},
+{2330, 15, 4149, {1, 1, 1, 5, 23, 35, 25, 129, 179, 959, 677, 2249, 6315, 12151, 3459}},
+{2331, 15, 4150, {1, 1, 1, 1, 9, 47, 93, 45, 35, 45, 265, 2065, 6225, 25, 27135}},
+{2332, 15, 4164, {1, 3, 1, 11, 21, 53, 127, 163, 311, 667, 597, 1561, 4515, 23, 9551}},
+{2333, 15, 4168, {1, 1, 3, 3, 7, 47, 105, 211, 241, 95, 389, 899, 6001, 8129, 19889}},
+{2334, 15, 4186, {1, 1, 3, 15, 29, 45, 9, 27, 483, 799, 269, 1811, 4493, 7109, 22149}},
+{2335, 15, 4198, {1, 1, 3, 3, 29, 5, 57, 205, 187, 615, 1677, 3987, 4577, 8799, 16311}},
+{2336, 15, 4207, {1, 1, 5, 3, 15, 5, 91, 101, 319, 445, 1261, 2039, 4071, 8249, 11611}},
+{2337, 15, 4221, {1, 3, 7, 11, 19, 17, 1, 185, 153, 579, 1001, 2031, 2295, 16335, 24771}},
+{2338, 15, 4225, {1, 3, 3, 15, 13, 45, 93, 185, 319, 667, 1085, 93, 577, 11551, 11355}},
+{2339, 15, 4231, {1, 1, 7, 13, 3, 61, 45, 191, 51, 981, 1151, 2715, 2503, 4147, 4587}},
+{2340, 15, 4238, {1, 1, 3, 3, 27, 17, 71, 141, 57, 981, 1033, 333, 4639, 15885, 1039}},
+{2341, 15, 4243, {1, 3, 3, 15, 21, 55, 33, 123, 357, 893, 829, 4045, 5027, 11727, 13357}},
+{2342, 15, 4249, {1, 1, 1, 9, 31, 47, 27, 223, 311, 205, 179, 3411, 4019, 10997, 28115}},
+{2343, 15, 4250, {1, 3, 5, 1, 3, 39, 15, 7, 501, 641, 735, 295, 2005, 12641, 19779}},
+{2344, 15, 4252, {1, 3, 3, 1, 15, 1, 75, 243, 329, 267, 1323, 2285, 5389, 11881, 15737}},
+{2345, 15, 4259, {1, 1, 3, 3, 13, 17, 101, 99, 209, 939, 1147, 3221, 5159, 3435, 183}},
+{2346, 15, 4279, {1, 1, 1, 1, 27, 43, 29, 179, 179, 659, 807, 313, 4165, 963, 11317}},
+{2347, 15, 4285, {1, 1, 3, 13, 9, 51, 125, 245, 381, 555, 1383, 3887, 2045, 12829, 12029}},
+{2348, 15, 4288, {1, 1, 1, 9, 29, 39, 55, 127, 235, 617, 1553, 3133, 7735, 14725, 16733}},
+{2349, 15, 4303, {1, 1, 3, 5, 15, 9, 47, 217, 89, 987, 1083, 1045, 4745, 12915, 13719}},
+{2350, 15, 4312, {1, 3, 3, 7, 23, 3, 35, 79, 45, 435, 1549, 2645, 2831, 10359, 10041}},
+{2351, 15, 4322, {1, 1, 7, 15, 31, 61, 25, 223, 511, 319, 487, 1677, 739, 7097, 18417}},
+{2352, 15, 4327, {1, 1, 7, 5, 19, 21, 123, 237, 299, 367, 1341, 1449, 2949, 8629, 11051}},
+{2353, 15, 4336, {1, 3, 7, 7, 31, 53, 125, 33, 257, 719, 1297, 895, 5095, 10237, 12309}},
+{2354, 15, 4359, {1, 3, 1, 5, 31, 59, 73, 211, 97, 209, 1289, 4033, 6143, 14275, 7997}},
+{2355, 15, 4384, {1, 1, 5, 7, 31, 5, 75, 105, 389, 985, 9, 4033, 1185, 7821, 19083}},
+{2356, 15, 4387, {1, 1, 1, 15, 11, 39, 73, 253, 275, 813, 25, 3441, 2493, 5873, 3739}},
+{2357, 15, 4401, {1, 3, 7, 1, 31, 19, 119, 5, 109, 397, 1329, 3347, 5941, 12449, 2533}},
+{2358, 15, 4407, {1, 1, 1, 1, 5, 59, 61, 175, 435, 985, 65, 3781, 5425, 15073, 16361}},
+{2359, 15, 4428, {1, 3, 5, 7, 31, 13, 53, 87, 69, 305, 1455, 273, 2197, 4277, 24423}},
+{2360, 15, 4436, {1, 3, 3, 15, 13, 13, 91, 171, 71, 583, 15, 3599, 6801, 10041, 26097}},
+{2361, 15, 4450, {1, 3, 3, 5, 5, 13, 91, 225, 63, 69, 1795, 341, 461, 5015, 9471}},
+{2362, 15, 4452, {1, 3, 7, 5, 21, 55, 109, 39, 459, 925, 229, 2855, 5807, 2117, 31739}},
+{2363, 15, 4459, {1, 1, 3, 3, 1, 5, 17, 177, 401, 727, 1555, 3097, 1243, 5933, 14579}},
+{2364, 15, 4461, {1, 1, 7, 3, 19, 19, 37, 87, 105, 73, 197, 4067, 6237, 10553, 9207}},
+{2365, 15, 4470, {1, 1, 3, 15, 1, 55, 119, 115, 441, 3, 1003, 1631, 197, 12929, 25385}},
+{2366, 15, 4483, {1, 3, 7, 11, 31, 1, 119, 49, 467, 647, 685, 2771, 3689, 11049, 26787}},
+{2367, 15, 4485, {1, 1, 1, 11, 19, 19, 21, 73, 459, 935, 615, 371, 1099, 14407, 10375}},
+{2368, 15, 4486, {1, 3, 5, 13, 15, 3, 107, 179, 259, 677, 1101, 315, 7673, 14639, 11241}},
+{2369, 15, 4492, {1, 1, 7, 9, 15, 21, 93, 25, 349, 23, 1087, 27, 5691, 12997, 29301}},
+{2370, 15, 4497, {1, 3, 3, 5, 7, 43, 1, 195, 69, 753, 1315, 2629, 3259, 5595, 19439}},
+{2371, 15, 4514, {1, 3, 5, 5, 31, 9, 75, 217, 217, 197, 1925, 2033, 3585, 15219, 20251}},
+{2372, 15, 4533, {1, 1, 5, 11, 17, 31, 3, 209, 315, 49, 949, 2267, 4611, 4375, 16431}},
+{2373, 15, 4537, {1, 1, 7, 9, 17, 35, 13, 115, 119, 553, 1527, 2857, 3599, 391, 25101}},
+{2374, 15, 4546, {1, 3, 3, 15, 13, 59, 17, 177, 301, 719, 909, 1663, 5033, 1129, 529}},
+{2375, 15, 4551, {1, 1, 7, 5, 15, 13, 99, 157, 379, 975, 1019, 2251, 3807, 10621, 351}},
+{2376, 15, 4555, {1, 3, 3, 13, 5, 57, 5, 31, 361, 981, 883, 3723, 2259, 5151, 11783}},
+{2377, 15, 4560, {1, 1, 1, 13, 1, 43, 125, 19, 77, 509, 1817, 3795, 1863, 8401, 27253}},
+{2378, 15, 4569, {1, 1, 5, 7, 19, 41, 21, 151, 89, 189, 769, 1937, 4497, 13607, 24691}},
+{2379, 15, 4576, {1, 1, 1, 9, 21, 9, 1, 195, 31, 907, 1719, 1549, 809, 13629, 16597}},
+{2380, 15, 4582, {1, 1, 1, 3, 21, 61, 103, 219, 311, 849, 523, 21, 4533, 6367, 3935}},
+{2381, 15, 4586, {1, 1, 7, 9, 7, 33, 77, 19, 489, 933, 1729, 1813, 6741, 10701, 7}},
+{2382, 15, 4609, {1, 1, 1, 5, 23, 53, 43, 63, 453, 209, 1313, 2847, 2641, 13783, 14983}},
+{2383, 15, 4610, {1, 3, 7, 7, 15, 45, 83, 241, 509, 659, 213, 221, 5205, 6019, 18945}},
+{2384, 15, 4612, {1, 1, 5, 9, 25, 43, 37, 9, 191, 505, 765, 295, 953, 1045, 11203}},
+{2385, 15, 4649, {1, 3, 7, 11, 5, 49, 45, 177, 379, 695, 355, 1711, 7747, 497, 7597}},
+{2386, 15, 4652, {1, 1, 5, 13, 23, 47, 101, 145, 301, 207, 195, 2225, 8093, 15345, 14097}},
+{2387, 15, 4672, {1, 3, 7, 13, 9, 9, 55, 223, 343, 921, 1825, 3281, 2627, 855, 27651}},
+{2388, 15, 4677, {1, 1, 7, 1, 21, 1, 67, 149, 433, 111, 577, 3675, 495, 9043, 23613}},
+{2389, 15, 4684, {1, 3, 1, 13, 9, 39, 37, 73, 117, 559, 1131, 2511, 7599, 8393, 24747}},
+{2390, 15, 4690, {1, 3, 3, 7, 11, 15, 85, 229, 7, 21, 1649, 739, 375, 13991, 27053}},
+{2391, 15, 4695, {1, 1, 5, 5, 15, 41, 49, 117, 173, 825, 1343, 377, 1789, 12519, 30667}},
+{2392, 15, 4696, {1, 1, 7, 15, 9, 11, 97, 99, 347, 729, 9, 1703, 1177, 5189, 9061}},
+{2393, 15, 4702, {1, 1, 5, 11, 15, 25, 99, 63, 89, 675, 561, 215, 8111, 3955, 24635}},
+{2394, 15, 4705, {1, 1, 1, 1, 7, 53, 99, 193, 233, 731, 733, 1883, 7783, 14413, 14003}},
+{2395, 15, 4717, {1, 3, 5, 7, 31, 23, 45, 153, 337, 293, 443, 2301, 5135, 7455, 13123}},
+{2396, 15, 4726, {1, 3, 1, 3, 23, 53, 23, 165, 53, 875, 1543, 1035, 4247, 5101, 28445}},
+{2397, 15, 4736, {1, 1, 1, 15, 13, 41, 77, 93, 205, 743, 1101, 1413, 2371, 7183, 12337}},
+{2398, 15, 4753, {1, 1, 3, 15, 17, 63, 25, 101, 147, 149, 1207, 3525, 2661, 9539, 11145}},
+{2399, 15, 4754, {1, 3, 1, 9, 17, 5, 3, 35, 389, 909, 1017, 2803, 5243, 13025, 8851}},
+{2400, 15, 4756, {1, 1, 7, 15, 19, 27, 69, 91, 71, 547, 1421, 831, 6969, 5517, 28233}},
+{2401, 15, 4775, {1, 1, 3, 3, 17, 45, 55, 63, 263, 819, 1211, 2739, 655, 13269, 22281}},
+{2402, 15, 4801, {1, 3, 1, 5, 23, 13, 81, 251, 83, 551, 491, 1029, 3561, 357, 23393}},
+{2403, 15, 4819, {1, 3, 1, 13, 25, 27, 93, 143, 407, 403, 1395, 1733, 3187, 1917, 31453}},
+{2404, 15, 4828, {1, 1, 7, 13, 3, 21, 85, 113, 483, 461, 1343, 561, 2081, 10857, 24253}},
+{2405, 15, 4838, {1, 1, 1, 1, 11, 11, 53, 135, 25, 163, 1729, 617, 1533, 10881, 16041}},
+{2406, 15, 4852, {1, 1, 5, 1, 3, 49, 125, 139, 77, 891, 815, 3431, 4875, 12513, 4595}},
+{2407, 15, 4856, {1, 1, 1, 1, 27, 63, 111, 109, 421, 425, 345, 1613, 5447, 1357, 32413}},
+{2408, 15, 4873, {1, 3, 5, 3, 17, 5, 37, 171, 259, 281, 1003, 2901, 3241, 15557, 21415}},
+{2409, 15, 4887, {1, 1, 5, 11, 15, 55, 75, 199, 493, 215, 1625, 2345, 7873, 2325, 11003}},
+{2410, 15, 4891, {1, 3, 7, 1, 21, 33, 23, 5, 495, 941, 1185, 475, 5799, 15161, 10677}},
+{2411, 15, 4904, {1, 1, 5, 9, 31, 37, 37, 29, 217, 389, 297, 3097, 7319, 2601, 15307}},
+{2412, 15, 4912, {1, 3, 7, 5, 7, 45, 111, 167, 297, 275, 1669, 2489, 1511, 15753, 1289}},
+{2413, 15, 4921, {1, 3, 1, 7, 3, 45, 19, 11, 189, 199, 1227, 2647, 1897, 9077, 17189}},
+{2414, 15, 4936, {1, 1, 1, 13, 15, 39, 19, 179, 147, 341, 283, 3029, 7599, 8937, 18761}},
+{2415, 15, 4941, {1, 3, 3, 9, 3, 11, 41, 255, 365, 835, 921, 389, 919, 15223, 14541}},
+{2416, 15, 4942, {1, 1, 3, 3, 5, 37, 29, 203, 313, 271, 1207, 487, 3711, 3811, 26757}},
+{2417, 15, 4963, {1, 3, 7, 9, 19, 53, 49, 139, 351, 537, 1681, 1595, 5399, 13839, 28685}},
+{2418, 15, 4984, {1, 3, 1, 1, 15, 35, 21, 37, 247, 891, 1855, 1243, 3137, 10381, 30379}},
+{2419, 15, 4990, {1, 3, 7, 5, 9, 47, 91, 25, 479, 337, 781, 3545, 1045, 9491, 22853}},
+{2420, 15, 5005, {1, 1, 5, 15, 19, 31, 81, 5, 117, 923, 565, 2443, 7383, 1795, 11685}},
+{2421, 15, 5013, {1, 3, 3, 5, 17, 15, 21, 245, 489, 889, 2047, 2737, 7445, 14785, 13401}},
+{2422, 15, 5020, {1, 1, 1, 15, 19, 45, 67, 117, 299, 607, 953, 743, 6863, 12123, 6701}},
+{2423, 15, 5039, {1, 1, 3, 1, 1, 43, 19, 129, 345, 861, 209, 2387, 7205, 7131, 8235}},
+{2424, 15, 5048, {1, 3, 5, 1, 1, 13, 75, 99, 333, 157, 23, 1217, 1857, 15479, 16031}},
+{2425, 15, 5062, {1, 3, 3, 11, 7, 61, 119, 89, 491, 401, 227, 1739, 3807, 16003, 2875}},
+{2426, 15, 5080, {1, 3, 7, 15, 13, 55, 3, 159, 405, 593, 975, 361, 2563, 6061, 28087}},
+{2427, 15, 5085, {1, 1, 3, 13, 19, 5, 5, 9, 119, 41, 33, 1111, 4443, 4663, 28841}},
+{2428, 15, 5086, {1, 1, 7, 7, 25, 59, 125, 255, 49, 947, 1673, 2947, 6369, 2267, 8813}},
+{2429, 15, 5095, {1, 1, 5, 15, 25, 25, 111, 193, 217, 193, 821, 2779, 69, 2957, 27043}},
+{2430, 15, 5096, {1, 3, 5, 7, 21, 19, 51, 157, 203, 487, 1745, 1875, 911, 14071, 7557}},
+{2431, 15, 5102, {1, 1, 5, 9, 3, 15, 55, 73, 313, 245, 1061, 1929, 3035, 607, 11563}},
+{2432, 15, 5107, {1, 1, 5, 7, 3, 57, 105, 121, 461, 43, 803, 1801, 4059, 2157, 17547}},
+{2433, 15, 5141, {1, 3, 7, 7, 19, 11, 1, 121, 499, 841, 601, 3515, 2969, 13697, 8917}},
+{2434, 15, 5145, {1, 3, 3, 3, 13, 35, 113, 231, 391, 689, 697, 2871, 7387, 715, 27005}},
+{2435, 15, 5148, {1, 1, 1, 13, 19, 5, 17, 43, 175, 291, 987, 1917, 7635, 15655, 10689}},
+{2436, 15, 5157, {1, 1, 7, 15, 19, 37, 121, 243, 125, 623, 1231, 29, 2325, 5147, 21435}},
+{2437, 15, 5158, {1, 3, 5, 15, 25, 27, 57, 187, 77, 401, 1489, 2977, 5415, 3381, 2551}},
+{2438, 15, 5162, {1, 1, 1, 7, 1, 1, 85, 27, 115, 559, 9, 2365, 711, 5733, 2819}},
+{2439, 15, 5172, {1, 3, 1, 15, 9, 29, 61, 113, 169, 349, 591, 1061, 6041, 7613, 23691}},
+{2440, 15, 5182, {1, 1, 5, 1, 13, 45, 49, 227, 345, 563, 87, 3597, 3961, 7205, 8441}},
+{2441, 15, 5184, {1, 1, 1, 5, 3, 21, 121, 183, 463, 83, 1365, 539, 1485, 10063, 24867}},
+{2442, 15, 5193, {1, 3, 5, 5, 3, 61, 101, 237, 41, 147, 1907, 3049, 7583, 8283, 6099}},
+{2443, 15, 5199, {1, 3, 1, 15, 31, 57, 19, 155, 445, 805, 1793, 207, 1975, 3357, 14281}},
+{2444, 15, 5201, {1, 1, 7, 13, 9, 39, 27, 73, 165, 345, 543, 4095, 133, 10469, 11573}},
+{2445, 15, 5204, {1, 1, 7, 15, 17, 57, 99, 81, 359, 367, 1057, 1173, 4225, 15127, 2615}},
+{2446, 15, 5211, {1, 3, 5, 3, 31, 23, 113, 111, 495, 947, 1625, 1195, 2053, 1509, 1347}},
+{2447, 15, 5223, {1, 1, 5, 5, 9, 47, 25, 63, 455, 107, 771, 3815, 3827, 16287, 11615}},
+{2448, 15, 5230, {1, 1, 7, 9, 17, 61, 51, 215, 63, 123, 1253, 3927, 721, 9647, 3283}},
+{2449, 15, 5232, {1, 1, 5, 15, 11, 17, 83, 255, 473, 107, 681, 763, 7855, 8043, 31503}},
+{2450, 15, 5253, {1, 3, 1, 7, 7, 31, 37, 5, 253, 155, 2017, 609, 1421, 14927, 25241}},
+{2451, 15, 5257, {1, 3, 3, 13, 31, 25, 21, 241, 431, 193, 681, 2265, 5091, 11479, 21443}},
+{2452, 15, 5260, {1, 3, 5, 5, 15, 9, 49, 255, 157, 995, 631, 1995, 3605, 9085, 24245}},
+{2453, 15, 5284, {1, 3, 3, 7, 19, 31, 85, 153, 493, 951, 451, 1587, 6609, 3681, 13205}},
+{2454, 15, 5306, {1, 1, 5, 1, 17, 41, 107, 231, 307, 361, 575, 3239, 3443, 16159, 20625}},
+{2455, 15, 5331, {1, 1, 7, 9, 31, 49, 93, 79, 181, 117, 1241, 3645, 4901, 12599, 13247}},
+{2456, 15, 5334, {1, 3, 3, 9, 7, 31, 127, 201, 11, 199, 1851, 23, 5667, 8159, 20951}},
+{2457, 15, 5364, {1, 3, 3, 7, 3, 37, 29, 189, 65, 461, 769, 321, 6577, 16223, 16865}},
+{2458, 15, 5367, {1, 1, 5, 11, 1, 13, 91, 167, 33, 111, 1445, 1047, 2479, 12623, 22893}},
+{2459, 15, 5371, {1, 1, 3, 1, 3, 1, 47, 185, 329, 903, 1651, 3005, 907, 1255, 8303}},
+{2460, 15, 5382, {1, 3, 5, 13, 19, 31, 5, 233, 265, 769, 1303, 2503, 2229, 14019, 20257}},
+{2461, 15, 5386, {1, 3, 7, 3, 27, 11, 67, 195, 5, 661, 125, 3761, 7211, 16043, 7267}},
+{2462, 15, 5399, {1, 1, 1, 3, 27, 13, 115, 25, 473, 417, 1751, 2223, 2099, 5913, 14273}},
+{2463, 15, 5400, {1, 3, 7, 15, 13, 53, 99, 115, 225, 737, 1621, 539, 4131, 471, 31865}},
+{2464, 15, 5409, {1, 1, 5, 5, 25, 19, 39, 207, 153, 569, 1755, 2477, 3065, 7383, 29919}},
+{2465, 15, 5415, {1, 3, 5, 11, 13, 59, 33, 3, 435, 273, 701, 3819, 7291, 11803, 26111}},
+{2466, 15, 5416, {1, 1, 3, 9, 29, 19, 71, 59, 93, 1019, 887, 83, 4675, 7541, 26821}},
+{2467, 15, 5424, {1, 3, 1, 3, 21, 53, 71, 73, 43, 321, 1581, 1399, 4043, 12995, 16825}},
+{2468, 15, 5436, {1, 3, 7, 15, 3, 13, 37, 11, 93, 873, 1193, 3481, 451, 15869, 17879}},
+{2469, 15, 5454, {1, 3, 1, 11, 31, 19, 101, 57, 129, 753, 853, 463, 6757, 11083, 8667}},
+{2470, 15, 5462, {1, 3, 5, 15, 25, 41, 25, 197, 235, 609, 905, 993, 3233, 1935, 24661}},
+{2471, 15, 5468, {1, 3, 1, 5, 21, 7, 53, 107, 473, 77, 1135, 1045, 4933, 5615, 15931}},
+{2472, 15, 5481, {1, 3, 7, 11, 3, 9, 105, 183, 151, 527, 425, 975, 4073, 913, 2793}},
+{2473, 15, 5505, {1, 1, 7, 13, 19, 61, 81, 9, 413, 851, 1723, 1113, 1453, 8635, 3353}},
+{2474, 15, 5511, {1, 3, 7, 15, 19, 53, 83, 31, 441, 343, 575, 935, 4543, 1303, 12567}},
+{2475, 15, 5518, {1, 1, 1, 5, 29, 19, 119, 75, 3, 591, 845, 649, 1717, 13695, 26905}},
+{2476, 15, 5530, {1, 1, 7, 9, 5, 53, 127, 191, 15, 773, 1433, 2899, 21, 4977, 17839}},
+{2477, 15, 5532, {1, 1, 5, 9, 21, 9, 99, 115, 397, 99, 725, 3835, 973, 1219, 21159}},
+{2478, 15, 5539, {1, 3, 5, 3, 7, 39, 29, 93, 303, 913, 981, 3549, 5225, 10907, 393}},
+{2479, 15, 5553, {1, 3, 3, 11, 9, 25, 105, 101, 1, 867, 389, 2241, 773, 14123, 10015}},
+{2480, 15, 5573, {1, 1, 5, 1, 1, 37, 117, 213, 391, 779, 1851, 1485, 1277, 5607, 819}},
+{2481, 15, 5580, {1, 3, 7, 1, 3, 5, 43, 47, 483, 367, 749, 1693, 4961, 15257, 3775}},
+{2482, 15, 5597, {1, 3, 3, 1, 27, 11, 21, 83, 437, 379, 1041, 393, 5611, 2421, 31739}},
+{2483, 15, 5602, {1, 3, 5, 7, 19, 1, 79, 63, 53, 201, 1159, 2501, 6327, 11317, 9537}},
+{2484, 15, 5608, {1, 3, 5, 13, 9, 37, 61, 217, 427, 913, 1311, 3503, 5473, 10583, 19723}},
+{2485, 15, 5611, {1, 1, 3, 9, 11, 29, 121, 175, 141, 515, 925, 837, 6011, 10419, 32157}},
+{2486, 15, 5613, {1, 3, 5, 9, 27, 57, 97, 175, 365, 367, 1737, 3845, 1257, 12243, 2201}},
+{2487, 15, 5625, {1, 3, 3, 9, 23, 1, 53, 123, 127, 333, 1335, 707, 5747, 6541, 9809}},
+{2488, 15, 5632, {1, 3, 1, 9, 17, 37, 101, 41, 91, 61, 433, 979, 4345, 12351, 10829}},
+{2489, 15, 5635, {1, 3, 3, 13, 3, 21, 15, 49, 257, 99, 1793, 2987, 5233, 11625, 28069}},
+{2490, 15, 5638, {1, 1, 7, 11, 21, 13, 89, 11, 135, 153, 783, 2893, 6815, 12007, 15605}},
+{2491, 15, 5652, {1, 3, 7, 13, 5, 61, 73, 5, 269, 699, 925, 2925, 5919, 5841, 24875}},
+{2492, 15, 5659, {1, 3, 5, 5, 25, 45, 43, 93, 15, 927, 1253, 319, 1173, 14559, 20221}},
+{2493, 15, 5677, {1, 1, 3, 3, 27, 45, 9, 103, 447, 627, 1239, 3869, 2169, 49, 17917}},
+{2494, 15, 5686, {1, 3, 7, 7, 11, 9, 1, 1, 1, 527, 825, 3295, 623, 2095, 10537}},
+{2495, 15, 5689, {1, 3, 3, 11, 21, 11, 59, 165, 33, 743, 1461, 1535, 6393, 1301, 17823}},
+{2496, 15, 5698, {1, 1, 7, 3, 19, 43, 47, 245, 469, 551, 1447, 1963, 169, 1481, 31925}},
+{2497, 15, 5703, {1, 1, 3, 1, 11, 21, 51, 7, 251, 199, 1153, 767, 6417, 3417, 30171}},
+{2498, 15, 5707, {1, 3, 7, 1, 31, 5, 41, 103, 447, 263, 211, 2029, 8021, 4705, 10579}},
+{2499, 15, 5731, {1, 1, 3, 5, 17, 25, 55, 75, 393, 107, 2017, 2389, 1685, 14021, 9161}},
+{2500, 15, 5738, {1, 1, 1, 9, 13, 1, 75, 237, 205, 461, 689, 2531, 2839, 13925, 23351}},
+{2501, 15, 5743, {1, 3, 7, 1, 23, 39, 33, 189, 157, 571, 239, 1053, 1559, 1685, 23059}},
+{2502, 15, 5748, {1, 3, 3, 3, 27, 61, 71, 121, 49, 157, 1341, 1707, 2417, 11689, 26507}},
+{2503, 15, 5758, {1, 3, 7, 7, 19, 63, 47, 53, 95, 791, 1467, 1273, 2045, 755, 8555}},
+{2504, 15, 5762, {1, 1, 3, 15, 27, 33, 21, 253, 317, 153, 1509, 1765, 3809, 601, 5907}},
+{2505, 15, 5768, {1, 3, 5, 15, 11, 17, 97, 91, 165, 199, 1751, 2135, 1315, 3077, 29995}},
+{2506, 15, 5773, {1, 3, 1, 5, 3, 33, 93, 49, 39, 743, 341, 2549, 7603, 3369, 30889}},
+{2507, 15, 5776, {1, 1, 3, 13, 3, 5, 87, 63, 293, 785, 1591, 675, 3915, 2209, 18201}},
+{2508, 15, 5815, {1, 3, 3, 11, 3, 15, 69, 231, 241, 127, 429, 2201, 8173, 12549, 25745}},
+{2509, 15, 5841, {1, 1, 5, 11, 15, 39, 3, 29, 125, 685, 643, 1385, 829, 7347, 28793}},
+{2510, 15, 5847, {1, 1, 7, 15, 27, 15, 59, 237, 299, 773, 1097, 3875, 6503, 7129, 28495}},
+{2511, 15, 5860, {1, 3, 5, 13, 9, 17, 31, 227, 69, 443, 1633, 525, 1659, 14681, 15209}},
+{2512, 15, 5870, {1, 3, 5, 5, 13, 51, 69, 173, 111, 433, 279, 2145, 2091, 9741, 24881}},
+{2513, 15, 5875, {1, 3, 1, 7, 7, 35, 55, 51, 357, 99, 1789, 333, 2073, 10151, 14527}},
+{2514, 15, 5877, {1, 3, 3, 7, 13, 41, 101, 87, 425, 701, 1143, 2733, 6473, 8667, 17419}},
+{2515, 15, 5884, {1, 1, 5, 5, 25, 29, 63, 31, 385, 537, 563, 607, 6723, 9251, 6531}},
+{2516, 15, 5892, {1, 3, 5, 5, 9, 63, 111, 131, 239, 723, 705, 2805, 6579, 12691, 17521}},
+{2517, 15, 5902, {1, 3, 1, 7, 31, 55, 101, 225, 477, 271, 611, 3179, 7859, 9835, 2165}},
+{2518, 15, 5910, {1, 1, 3, 3, 5, 15, 81, 127, 391, 333, 419, 1091, 5997, 12315, 31521}},
+{2519, 15, 5916, {1, 3, 5, 15, 23, 7, 35, 109, 181, 295, 825, 419, 969, 15753, 9365}},
+{2520, 15, 5919, {1, 3, 5, 5, 25, 23, 69, 177, 325, 359, 1577, 619, 6233, 11753, 8103}},
+{2521, 15, 5935, {1, 3, 5, 11, 31, 13, 79, 61, 241, 1011, 1961, 949, 6211, 497, 7099}},
+{2522, 15, 5937, {1, 3, 5, 3, 25, 19, 67, 235, 337, 1015, 1485, 355, 3653, 12735, 14503}},
+{2523, 15, 5944, {1, 3, 5, 7, 31, 23, 35, 231, 147, 15, 263, 1995, 431, 5941, 18931}},
+{2524, 15, 5947, {1, 3, 3, 7, 1, 35, 37, 7, 85, 443, 715, 743, 2189, 12537, 17427}},
+{2525, 15, 5958, {1, 1, 3, 1, 7, 41, 1, 209, 121, 929, 661, 3999, 955, 5123, 31115}},
+{2526, 15, 5962, {1, 1, 3, 5, 11, 43, 127, 125, 107, 293, 273, 2071, 3003, 11631, 7769}},
+{2527, 15, 5969, {1, 1, 1, 13, 13, 29, 39, 217, 111, 779, 1287, 1675, 4201, 4869, 20403}},
+{2528, 15, 5981, {1, 1, 3, 15, 25, 53, 25, 135, 389, 925, 1971, 663, 7545, 2673, 7725}},
+{2529, 15, 5995, {1, 1, 5, 13, 3, 59, 97, 91, 357, 45, 947, 3031, 8095, 6269, 13975}},
+{2530, 15, 5998, {1, 1, 5, 15, 25, 31, 1, 171, 375, 939, 507, 3591, 1089, 13605, 2813}},
+{2531, 15, 6003, {1, 1, 3, 7, 25, 21, 41, 131, 147, 737, 9, 1603, 1859, 11573, 28397}},
+{2532, 15, 6010, {1, 3, 3, 9, 21, 9, 59, 27, 169, 875, 711, 1389, 2899, 7937, 4173}},
+{2533, 15, 6016, {1, 1, 5, 9, 13, 29, 71, 39, 51, 337, 1067, 2661, 1203, 5967, 19249}},
+{2534, 15, 6025, {1, 3, 7, 1, 17, 21, 43, 79, 181, 741, 1901, 3445, 7171, 2109, 1589}},
+{2535, 15, 6031, {1, 1, 3, 9, 23, 37, 105, 51, 227, 775, 1265, 2987, 2197, 13903, 28891}},
+{2536, 15, 6036, {1, 1, 1, 13, 23, 47, 111, 41, 93, 261, 75, 2155, 4301, 11517, 16101}},
+{2537, 15, 6039, {1, 1, 3, 3, 27, 27, 123, 125, 501, 775, 413, 1065, 7607, 15065, 26013}},
+{2538, 15, 6045, {1, 3, 7, 3, 27, 11, 59, 87, 207, 743, 1765, 2969, 913, 8101, 11583}},
+{2539, 15, 6049, {1, 3, 3, 1, 23, 7, 113, 17, 285, 993, 695, 2399, 5019, 4779, 28917}},
+{2540, 15, 6052, {1, 3, 1, 5, 11, 51, 49, 139, 213, 435, 1475, 2209, 6695, 12981, 9851}},
+{2541, 15, 6067, {1, 3, 5, 7, 1, 63, 31, 151, 173, 767, 1453, 1497, 6911, 9597, 25551}},
+{2542, 15, 6074, {1, 1, 7, 7, 21, 53, 39, 159, 389, 231, 309, 359, 7701, 14819, 5175}},
+{2543, 15, 6087, {1, 1, 1, 1, 11, 47, 83, 29, 247, 89, 369, 2727, 3103, 14421, 17369}},
+{2544, 15, 6101, {1, 3, 1, 5, 25, 25, 111, 245, 239, 755, 113, 1765, 3583, 917, 403}},
+{2545, 15, 6121, {1, 3, 3, 3, 5, 59, 85, 151, 463, 591, 743, 3767, 121, 2927, 11031}},
+{2546, 15, 6129, {1, 3, 5, 9, 11, 39, 77, 161, 275, 233, 1991, 2683, 6545, 2423, 32113}},
+{2547, 15, 6142, {1, 3, 5, 11, 5, 57, 13, 229, 329, 757, 1863, 3959, 4243, 7265, 15599}},
+{2548, 15, 6151, {1, 1, 1, 1, 1, 23, 19, 67, 453, 593, 2011, 1813, 4695, 8903, 9623}},
+{2549, 15, 6157, {1, 3, 3, 7, 1, 29, 103, 255, 493, 647, 1709, 4065, 4199, 949, 28829}},
+{2550, 15, 6166, {1, 1, 7, 9, 3, 55, 53, 33, 5, 223, 423, 3347, 7647, 7211, 25157}},
+{2551, 15, 6170, {1, 3, 5, 13, 3, 43, 79, 255, 471, 573, 1007, 2119, 6731, 10047, 23179}},
+{2552, 15, 6175, {1, 1, 1, 3, 7, 39, 55, 61, 53, 377, 435, 401, 3307, 12621, 14299}},
+{2553, 15, 6186, {1, 3, 3, 7, 21, 31, 67, 17, 243, 425, 747, 2995, 1389, 2557, 18415}},
+{2554, 15, 6203, {1, 3, 1, 3, 3, 39, 75, 11, 447, 249, 1135, 1011, 1657, 10767, 19501}},
+{2555, 15, 6217, {1, 3, 1, 11, 17, 51, 117, 129, 17, 143, 785, 103, 5049, 14703, 28479}},
+{2556, 15, 6231, {1, 3, 7, 5, 13, 17, 75, 255, 75, 661, 1175, 477, 1811, 1479, 15783}},
+{2557, 15, 6241, {1, 3, 7, 9, 11, 57, 101, 77, 431, 247, 997, 3657, 5117, 6815, 3841}},
+{2558, 15, 6242, {1, 1, 5, 1, 17, 21, 101, 183, 209, 69, 299, 1585, 6381, 12983, 10053}},
+{2559, 15, 6248, {1, 1, 7, 3, 5, 13, 21, 63, 83, 857, 749, 1251, 5363, 9629, 16563}},
+{2560, 15, 6256, {1, 3, 3, 9, 3, 59, 9, 45, 55, 489, 137, 2423, 2661, 12111, 4375}},
+{2561, 15, 6265, {1, 1, 5, 9, 23, 9, 41, 177, 447, 671, 1631, 3115, 4215, 14435, 8743}},
+{2562, 15, 6275, {1, 3, 7, 11, 19, 23, 15, 221, 413, 783, 1247, 2343, 4397, 3145, 32043}},
+{2563, 15, 6277, {1, 3, 3, 1, 31, 55, 31, 87, 333, 849, 1777, 343, 5199, 1507, 11621}},
+{2564, 15, 6302, {1, 3, 7, 3, 17, 57, 63, 63, 111, 977, 631, 3019, 2953, 14273, 29209}},
+{2565, 15, 6315, {1, 3, 1, 13, 9, 39, 87, 15, 397, 185, 701, 1487, 3807, 13727, 19883}},
+{2566, 15, 6318, {1, 3, 7, 1, 17, 57, 57, 157, 119, 181, 899, 353, 3603, 15041, 7421}},
+{2567, 15, 6330, {1, 1, 7, 3, 29, 13, 29, 191, 105, 373, 961, 1991, 5531, 6793, 29497}},
+{2568, 15, 6343, {1, 3, 3, 11, 7, 61, 65, 39, 215, 187, 191, 1651, 2481, 3951, 24965}},
+{2569, 15, 6347, {1, 1, 7, 5, 25, 11, 105, 23, 257, 771, 1359, 2837, 7821, 12223, 28033}},
+{2570, 15, 6350, {1, 3, 5, 11, 3, 3, 23, 139, 407, 885, 1679, 2979, 8149, 14281, 12487}},
+{2571, 15, 6352, {1, 3, 7, 3, 21, 45, 13, 85, 249, 1015, 2023, 1429, 965, 7091, 31721}},
+{2572, 15, 6371, {1, 1, 1, 13, 19, 5, 119, 47, 91, 285, 211, 2607, 4287, 9197, 455}},
+{2573, 15, 6383, {1, 3, 1, 1, 9, 59, 25, 137, 121, 287, 577, 3325, 2365, 8823, 5033}},
+{2574, 15, 6386, {1, 3, 3, 13, 25, 63, 99, 43, 15, 855, 245, 3189, 59, 5181, 21299}},
+{2575, 15, 6405, {1, 3, 5, 11, 7, 9, 41, 157, 359, 773, 1347, 2049, 4589, 13731, 32133}},
+{2576, 15, 6409, {1, 1, 7, 11, 31, 37, 83, 105, 183, 375, 79, 1821, 1989, 15199, 22207}},
+{2577, 15, 6410, {1, 1, 5, 3, 23, 37, 127, 9, 467, 651, 993, 69, 6943, 4093, 20871}},
+{2578, 15, 6433, {1, 1, 3, 15, 31, 49, 123, 149, 211, 371, 1825, 3011, 485, 1251, 17343}},
+{2579, 15, 6436, {1, 1, 1, 15, 11, 33, 127, 251, 89, 317, 1869, 219, 2275, 14201, 27063}},
+{2580, 15, 6439, {1, 1, 5, 5, 19, 5, 81, 35, 233, 95, 9, 863, 725, 11095, 16217}},
+{2581, 15, 6463, {1, 1, 1, 15, 23, 47, 51, 43, 169, 637, 865, 57, 1509, 1683, 7587}},
+{2582, 15, 6468, {1, 3, 1, 3, 7, 7, 117, 187, 273, 303, 717, 3091, 2083, 3315, 647}},
+{2583, 15, 6477, {1, 1, 5, 15, 13, 27, 23, 227, 145, 547, 1783, 987, 6895, 7135, 11023}},
+{2584, 15, 6496, {1, 1, 5, 11, 21, 39, 57, 203, 477, 17, 985, 1729, 4297, 7483, 13263}},
+{2585, 15, 6511, {1, 3, 7, 9, 3, 49, 71, 45, 143, 967, 39, 583, 2123, 5165, 17437}},
+{2586, 15, 6516, {1, 1, 1, 9, 21, 51, 71, 163, 441, 709, 397, 445, 6167, 7753, 11513}},
+{2587, 15, 6519, {1, 1, 7, 7, 27, 35, 5, 181, 449, 53, 621, 3401, 5263, 4557, 9141}},
+{2588, 15, 6523, {1, 1, 5, 7, 7, 37, 83, 111, 485, 881, 465, 3371, 5603, 371, 29393}},
+{2589, 15, 6530, {1, 3, 1, 15, 7, 47, 41, 245, 377, 823, 309, 3929, 2159, 13917, 13365}},
+{2590, 15, 6539, {1, 3, 7, 7, 7, 29, 25, 141, 19, 611, 79, 2689, 109, 12321, 8345}},
+{2591, 15, 6547, {1, 1, 1, 13, 3, 53, 113, 151, 381, 791, 137, 3185, 3567, 211, 597}},
+{2592, 15, 6589, {1, 1, 3, 9, 7, 53, 87, 89, 491, 861, 467, 3763, 2025, 4187, 9637}},
+{2593, 15, 6592, {1, 1, 7, 1, 27, 33, 71, 41, 63, 1011, 741, 1135, 175, 3739, 21493}},
+{2594, 15, 6601, {1, 3, 3, 5, 9, 19, 55, 175, 325, 55, 1193, 1423, 2049, 9633, 17515}},
+{2595, 15, 6610, {1, 1, 3, 1, 27, 55, 69, 103, 401, 707, 825, 399, 6799, 13199, 6295}},
+{2596, 15, 6616, {1, 3, 7, 3, 19, 63, 25, 151, 17, 159, 1673, 615, 6317, 13261, 26267}},
+{2597, 15, 6619, {1, 3, 7, 9, 27, 1, 77, 129, 423, 647, 707, 2579, 3525, 6723, 31615}},
+{2598, 15, 6626, {1, 3, 3, 7, 7, 31, 35, 241, 309, 369, 895, 3683, 4795, 11319, 451}},
+{2599, 15, 6635, {1, 3, 5, 7, 17, 7, 117, 141, 267, 713, 569, 1915, 4369, 7793, 30853}},
+{2600, 15, 6637, {1, 3, 7, 1, 29, 61, 81, 73, 413, 13, 1977, 3229, 5853, 8451, 15539}},
+{2601, 15, 6638, {1, 3, 7, 1, 5, 45, 109, 21, 431, 487, 2019, 2647, 927, 16015, 10711}},
+{2602, 15, 6652, {1, 3, 1, 3, 11, 19, 37, 183, 451, 377, 269, 3993, 3229, 4899, 26561}},
+{2603, 15, 6656, {1, 3, 1, 11, 5, 19, 121, 55, 57, 117, 687, 83, 3047, 1367, 17595}},
+{2604, 15, 6662, {1, 3, 1, 7, 17, 31, 41, 219, 239, 963, 199, 2895, 5599, 7639, 17201}},
+{2605, 15, 6689, {1, 3, 3, 5, 27, 53, 71, 183, 509, 771, 1809, 1539, 2229, 4893, 17115}},
+{2606, 15, 6699, {1, 1, 3, 9, 9, 9, 13, 49, 265, 643, 1929, 859, 497, 9797, 27771}},
+{2607, 15, 6710, {1, 3, 7, 11, 19, 39, 115, 139, 207, 903, 963, 1849, 4403, 6229, 10021}},
+{2608, 15, 6714, {1, 3, 7, 13, 3, 57, 99, 223, 503, 423, 1755, 807, 1885, 213, 18723}},
+{2609, 15, 6719, {1, 3, 7, 15, 11, 15, 111, 193, 243, 599, 593, 3385, 5393, 15073, 17777}},
+{2610, 15, 6739, {1, 1, 5, 3, 19, 63, 121, 207, 99, 435, 1961, 2747, 6405, 3971, 23481}},
+{2611, 15, 6751, {1, 3, 5, 13, 9, 29, 79, 131, 415, 49, 229, 1003, 3263, 12975, 15987}},
+{2612, 15, 6775, {1, 1, 3, 7, 1, 41, 127, 155, 29, 73, 963, 659, 2741, 3465, 2595}},
+{2613, 15, 6779, {1, 1, 3, 5, 23, 23, 93, 233, 113, 521, 427, 1557, 6917, 12953, 22441}},
+{2614, 15, 6788, {1, 1, 5, 13, 5, 25, 85, 191, 387, 69, 955, 243, 4473, 9813, 21711}},
+{2615, 15, 6798, {1, 3, 3, 7, 1, 53, 95, 65, 231, 995, 539, 2103, 5513, 14087, 28655}},
+{2616, 15, 6815, {1, 3, 5, 3, 17, 13, 19, 227, 197, 91, 1437, 1121, 3307, 6903, 3297}},
+{2617, 15, 6819, {1, 1, 5, 11, 31, 29, 109, 171, 257, 783, 861, 9, 4895, 1859, 10909}},
+{2618, 15, 6825, {1, 1, 7, 13, 5, 47, 61, 5, 363, 351, 1525, 823, 2883, 12435, 17629}},
+{2619, 15, 6826, {1, 1, 5, 11, 9, 3, 69, 159, 371, 477, 1223, 1973, 2757, 413, 31223}},
+{2620, 15, 6836, {1, 1, 3, 5, 23, 45, 43, 195, 423, 829, 1673, 1563, 6633, 14775, 21097}},
+{2621, 15, 6843, {1, 1, 3, 3, 13, 9, 107, 209, 49, 609, 1047, 3691, 7483, 4269, 7557}},
+{2622, 15, 6845, {1, 1, 3, 15, 3, 43, 73, 161, 53, 813, 325, 3439, 7009, 8691, 11711}},
+{2623, 15, 6858, {1, 1, 3, 3, 23, 45, 99, 61, 407, 15, 1515, 1557, 953, 8567, 13729}},
+{2624, 15, 6868, {1, 1, 5, 9, 31, 35, 117, 57, 227, 923, 1373, 1811, 3405, 11979, 10149}},
+{2625, 15, 6877, {1, 1, 3, 9, 15, 53, 105, 209, 153, 67, 1477, 667, 3077, 4911, 3871}},
+{2626, 15, 6881, {1, 1, 3, 3, 21, 53, 93, 101, 183, 1023, 3, 3041, 5815, 9043, 5801}},
+{2627, 15, 6891, {1, 3, 3, 5, 17, 49, 127, 161, 321, 869, 1369, 923, 3235, 711, 30007}},
+{2628, 15, 6896, {1, 1, 3, 3, 15, 17, 97, 229, 389, 159, 1075, 2001, 7905, 15191, 14693}},
+{2629, 15, 6899, {1, 1, 5, 11, 5, 5, 121, 173, 95, 173, 1883, 3915, 1439, 9981, 24375}},
+{2630, 15, 6901, {1, 3, 3, 1, 31, 53, 29, 189, 37, 623, 217, 949, 3959, 7189, 25427}},
+{2631, 15, 6908, {1, 3, 5, 9, 21, 45, 101, 23, 355, 729, 797, 2317, 2931, 7433, 29175}},
+{2632, 15, 6914, {1, 3, 7, 1, 1, 63, 63, 155, 237, 865, 1169, 43, 7335, 6445, 7979}},
+{2633, 15, 6916, {1, 3, 7, 7, 11, 51, 37, 199, 503, 991, 319, 3013, 7885, 12837, 32419}},
+{2634, 15, 6923, {1, 3, 7, 7, 27, 31, 101, 243, 37, 811, 1909, 109, 6455, 7903, 11821}},
+{2635, 15, 6925, {1, 1, 3, 13, 23, 21, 89, 99, 243, 605, 1017, 1871, 1101, 12825, 8227}},
+{2636, 15, 6928, {1, 3, 3, 13, 19, 3, 51, 59, 501, 605, 385, 2189, 3229, 7981, 31407}},
+{2637, 15, 6931, {1, 1, 1, 1, 25, 11, 127, 215, 295, 237, 1245, 3657, 7803, 3897, 655}},
+{2638, 15, 6934, {1, 1, 7, 7, 5, 9, 63, 129, 143, 417, 795, 3409, 2847, 5887, 3093}},
+{2639, 15, 6937, {1, 3, 3, 13, 7, 57, 67, 57, 5, 847, 1185, 3349, 4841, 11457, 8857}},
+{2640, 15, 6938, {1, 1, 3, 3, 9, 53, 51, 43, 85, 437, 13, 2543, 3651, 15493, 767}},
+{2641, 15, 6949, {1, 1, 7, 9, 1, 49, 97, 115, 133, 1011, 1399, 2653, 7765, 13999, 12097}},
+{2642, 15, 6956, {1, 1, 5, 1, 3, 27, 123, 107, 389, 401, 1759, 1333, 1371, 5277, 14865}},
+{2643, 15, 6973, {1, 1, 5, 1, 13, 23, 3, 123, 137, 821, 399, 1671, 3095, 3121, 31387}},
+{2644, 15, 6976, {1, 1, 5, 3, 7, 35, 57, 237, 509, 753, 1783, 2815, 6495, 13283, 7091}},
+{2645, 15, 6981, {1, 1, 7, 11, 5, 37, 77, 109, 7, 969, 1087, 3705, 1695, 14223, 28959}},
+{2646, 15, 6988, {1, 3, 1, 11, 25, 5, 25, 163, 179, 185, 671, 1031, 4537, 11601, 9323}},
+{2647, 15, 6999, {1, 1, 3, 7, 17, 25, 49, 221, 183, 619, 1953, 343, 4523, 14883, 6833}},
+{2648, 15, 7016, {1, 3, 7, 5, 27, 19, 59, 153, 11, 807, 513, 3019, 6875, 5307, 8405}},
+{2649, 15, 7027, {1, 1, 1, 13, 25, 41, 21, 109, 321, 135, 497, 1235, 5177, 5167, 18609}},
+{2650, 15, 7029, {1, 1, 7, 5, 21, 53, 25, 197, 411, 503, 1009, 1921, 4305, 2633, 31415}},
+{2651, 15, 7055, {1, 3, 5, 1, 25, 45, 27, 227, 271, 903, 639, 3805, 657, 8683, 29585}},
+{2652, 15, 7058, {1, 1, 5, 3, 9, 49, 37, 35, 351, 491, 851, 2983, 31, 5619, 6919}},
+{2653, 15, 7074, {1, 1, 5, 3, 11, 49, 33, 153, 393, 1017, 1561, 2795, 4435, 12589, 22349}},
+{2654, 15, 7083, {1, 1, 1, 15, 17, 29, 49, 245, 217, 359, 1133, 393, 3317, 415, 16407}},
+{2655, 15, 7093, {1, 1, 3, 5, 3, 9, 95, 63, 319, 319, 1009, 19, 6453, 16279, 6975}},
+{2656, 15, 7100, {1, 1, 5, 9, 3, 25, 67, 95, 369, 237, 285, 2409, 671, 5143, 121}},
+{2657, 15, 7105, {1, 1, 3, 1, 9, 49, 35, 87, 317, 185, 445, 2263, 7923, 10183, 26615}},
+{2658, 15, 7112, {1, 3, 3, 11, 9, 59, 29, 135, 129, 477, 353, 3571, 1057, 16329, 23523}},
+{2659, 15, 7118, {1, 1, 1, 15, 13, 11, 19, 5, 133, 827, 1799, 1893, 1939, 1101, 12147}},
+{2660, 15, 7120, {1, 1, 3, 3, 15, 49, 33, 185, 511, 1013, 41, 3499, 6235, 7643, 16725}},
+{2661, 15, 7129, {1, 1, 5, 11, 27, 45, 89, 157, 63, 137, 2047, 1275, 4995, 625, 6111}},
+{2662, 15, 7166, {1, 3, 7, 11, 3, 1, 121, 1, 341, 33, 1895, 3033, 3929, 10257, 21037}},
+{2663, 15, 7207, {1, 3, 3, 11, 7, 11, 117, 5, 115, 287, 335, 3415, 5397, 15065, 19121}},
+{2664, 15, 7216, {1, 3, 3, 13, 21, 25, 15, 125, 277, 125, 801, 3761, 2623, 11333, 16867}},
+{2665, 15, 7226, {1, 3, 5, 11, 19, 33, 21, 71, 499, 747, 1515, 185, 1759, 14623, 895}},
+{2666, 15, 7234, {1, 3, 7, 1, 29, 35, 9, 203, 277, 299, 1509, 2017, 2897, 14175, 1643}},
+{2667, 15, 7236, {1, 3, 5, 11, 7, 47, 111, 197, 459, 941, 1619, 2119, 2191, 11049, 6811}},
+{2668, 15, 7246, {1, 1, 5, 9, 7, 43, 103, 115, 87, 269, 1235, 77, 5887, 1611, 29041}},
+{2669, 15, 7248, {1, 1, 5, 7, 1, 61, 83, 225, 179, 81, 1145, 2403, 1485, 8967, 20607}},
+{2670, 15, 7254, {1, 3, 3, 1, 25, 47, 27, 157, 359, 803, 1683, 1995, 6445, 13113, 17899}},
+{2671, 15, 7263, {1, 3, 1, 7, 21, 37, 43, 119, 245, 49, 1581, 2275, 3311, 4087, 29765}},
+{2672, 15, 7273, {1, 1, 3, 13, 5, 33, 49, 191, 455, 105, 665, 3855, 3207, 2671, 32203}},
+{2673, 15, 7274, {1, 3, 1, 1, 25, 63, 19, 217, 17, 353, 947, 1951, 4097, 9041, 11921}},
+{2674, 15, 7293, {1, 3, 1, 7, 21, 31, 113, 97, 347, 993, 1799, 3831, 3711, 6193, 1235}},
+{2675, 15, 7297, {1, 1, 1, 5, 3, 63, 11, 203, 425, 445, 1361, 531, 1265, 1755, 11685}},
+{2676, 15, 7310, {1, 3, 1, 7, 13, 29, 23, 85, 57, 467, 1835, 133, 7961, 4175, 2445}},
+{2677, 15, 7315, {1, 1, 1, 15, 23, 27, 37, 5, 123, 913, 1293, 1633, 3113, 5413, 26407}},
+{2678, 15, 7317, {1, 1, 5, 13, 27, 1, 121, 151, 303, 931, 375, 3679, 1863, 12301, 30907}},
+{2679, 15, 7331, {1, 3, 1, 9, 31, 9, 49, 203, 177, 937, 1503, 933, 5867, 12533, 13621}},
+{2680, 15, 7338, {1, 3, 3, 15, 1, 41, 23, 191, 191, 931, 837, 3553, 2611, 4735, 18105}},
+{2681, 15, 7340, {1, 1, 5, 7, 27, 49, 51, 111, 435, 195, 1229, 711, 7145, 14571, 31707}},
+{2682, 15, 7346, {1, 1, 7, 7, 3, 41, 59, 203, 291, 903, 1727, 2757, 1463, 6287, 31535}},
+{2683, 15, 7355, {1, 1, 7, 13, 23, 5, 75, 3, 207, 525, 411, 2133, 2231, 477, 7155}},
+{2684, 15, 7366, {1, 3, 5, 7, 13, 19, 111, 225, 489, 83, 1177, 4077, 4617, 14413, 7133}},
+{2685, 15, 7383, {1, 3, 1, 7, 9, 59, 3, 113, 379, 803, 1289, 3347, 4127, 6669, 14867}},
+{2686, 15, 7389, {1, 3, 7, 3, 31, 37, 87, 79, 399, 749, 995, 1611, 3137, 12543, 31955}},
+{2687, 15, 7393, {1, 1, 5, 7, 21, 59, 49, 45, 511, 639, 1033, 2169, 3265, 15001, 10745}},
+{2688, 15, 7396, {1, 1, 5, 1, 25, 19, 23, 203, 11, 883, 1031, 4087, 5059, 11321, 21675}},
+{2689, 15, 7400, {1, 3, 7, 5, 11, 27, 33, 205, 163, 289, 501, 3505, 1515, 1895, 15889}},
+{2690, 15, 7414, {1, 3, 1, 1, 23, 7, 39, 239, 29, 119, 1499, 2071, 6495, 12107, 5339}},
+{2691, 15, 7417, {1, 3, 1, 1, 23, 29, 55, 181, 327, 905, 427, 1033, 427, 3687, 5367}},
+{2692, 15, 7426, {1, 3, 3, 7, 21, 27, 115, 127, 393, 855, 1291, 2121, 381, 9995, 29757}},
+{2693, 15, 7432, {1, 3, 5, 1, 25, 13, 15, 183, 269, 1005, 1531, 3451, 3975, 9479, 23695}},
+{2694, 15, 7452, {1, 3, 7, 7, 19, 31, 111, 97, 33, 179, 1343, 2069, 977, 5043, 9129}},
+{2695, 15, 7468, {1, 3, 1, 5, 17, 57, 99, 129, 379, 829, 837, 1845, 3613, 7351, 19291}},
+{2696, 15, 7488, {1, 3, 3, 5, 31, 23, 119, 229, 135, 389, 9, 705, 6697, 15441, 5303}},
+{2697, 15, 7491, {1, 1, 1, 11, 25, 31, 105, 95, 5, 931, 789, 375, 7543, 9957, 28627}},
+{2698, 15, 7494, {1, 1, 7, 15, 21, 17, 19, 103, 389, 545, 1725, 2867, 4251, 3829, 6907}},
+{2699, 15, 7497, {1, 3, 7, 7, 15, 37, 97, 65, 337, 409, 1649, 2869, 7929, 8905, 21989}},
+{2700, 15, 7515, {1, 3, 5, 3, 11, 15, 69, 29, 353, 207, 233, 411, 2047, 10303, 31655}},
+{2701, 15, 7531, {1, 3, 3, 7, 27, 43, 125, 107, 69, 981, 215, 1955, 3589, 597, 12703}},
+{2702, 15, 7552, {1, 1, 7, 9, 25, 13, 109, 73, 227, 663, 1115, 285, 471, 3359, 15787}},
+{2703, 15, 7562, {1, 3, 7, 5, 1, 45, 7, 79, 441, 149, 701, 1457, 6595, 14829, 20865}},
+{2704, 15, 7564, {1, 3, 7, 15, 15, 47, 83, 239, 295, 23, 1085, 813, 1209, 3573, 2855}},
+{2705, 15, 7569, {1, 1, 3, 15, 13, 7, 59, 67, 255, 537, 1841, 3857, 6821, 15175, 13997}},
+{2706, 15, 7582, {1, 3, 1, 1, 9, 57, 59, 21, 21, 41, 1693, 2805, 7953, 1389, 14105}},
+{2707, 15, 7585, {1, 3, 5, 15, 19, 49, 107, 117, 99, 607, 145, 53, 1863, 9383, 12029}},
+{2708, 15, 7588, {1, 3, 3, 13, 1, 39, 5, 141, 503, 265, 281, 1785, 2673, 6597, 6333}},
+{2709, 15, 7592, {1, 1, 5, 3, 3, 19, 3, 181, 169, 269, 955, 2399, 3157, 11053, 8563}},
+{2710, 15, 7597, {1, 3, 3, 13, 11, 1, 95, 43, 179, 507, 443, 209, 3239, 14239, 21829}},
+{2711, 15, 7603, {1, 1, 7, 9, 3, 17, 99, 179, 445, 479, 1897, 1507, 5753, 4757, 2135}},
+{2712, 15, 7610, {1, 3, 3, 1, 9, 51, 29, 13, 295, 291, 927, 85, 5707, 7447, 32319}},
+{2713, 15, 7624, {1, 1, 1, 3, 13, 11, 21, 157, 213, 327, 1071, 591, 2639, 15405, 6617}},
+{2714, 15, 7642, {1, 3, 5, 1, 7, 25, 55, 47, 495, 681, 727, 2707, 2955, 705, 7489}},
+{2715, 15, 7647, {1, 1, 3, 9, 17, 3, 73, 67, 465, 367, 1473, 3195, 7825, 5299, 1817}},
+{2716, 15, 7653, {1, 1, 1, 1, 19, 31, 77, 253, 71, 599, 1601, 871, 2243, 6699, 13013}},
+{2717, 15, 7654, {1, 1, 7, 9, 21, 1, 71, 115, 5, 65, 767, 925, 7901, 10761, 19431}},
+{2718, 15, 7666, {1, 3, 1, 7, 23, 31, 31, 15, 105, 391, 585, 2995, 2635, 10607, 24951}},
+{2719, 15, 7668, {1, 3, 3, 1, 19, 25, 71, 211, 41, 197, 787, 225, 6781, 813, 10117}},
+{2720, 15, 7684, {1, 3, 3, 3, 17, 29, 3, 153, 231, 643, 1151, 447, 3699, 9625, 26677}},
+{2721, 15, 7705, {1, 1, 5, 9, 1, 25, 71, 21, 395, 297, 557, 3841, 233, 1877, 4569}},
+{2722, 15, 7732, {1, 1, 3, 13, 1, 45, 115, 61, 5, 937, 173, 2109, 2927, 9599, 9155}},
+{2723, 15, 7741, {1, 1, 3, 3, 15, 21, 61, 121, 253, 285, 1083, 3545, 5537, 6773, 2629}},
+{2724, 15, 7749, {1, 3, 3, 15, 13, 63, 33, 77, 49, 849, 1795, 2771, 5481, 9833, 603}},
+{2725, 15, 7750, {1, 1, 7, 5, 1, 39, 113, 237, 225, 1005, 1687, 2297, 3213, 2605, 14669}},
+{2726, 15, 7759, {1, 1, 3, 1, 11, 1, 39, 23, 67, 441, 1235, 2545, 3139, 15901, 29243}},
+{2727, 15, 7764, {1, 3, 1, 3, 15, 49, 39, 57, 311, 345, 525, 223, 4923, 6311, 25275}},
+{2728, 15, 7777, {1, 1, 5, 7, 9, 13, 69, 11, 349, 423, 1773, 1055, 1001, 9359, 17025}},
+{2729, 15, 7790, {1, 1, 1, 13, 15, 63, 89, 207, 335, 591, 1223, 2701, 55, 12471, 13127}},
+{2730, 15, 7817, {1, 1, 3, 5, 15, 19, 83, 67, 407, 113, 1961, 779, 5803, 12417, 21751}},
+{2731, 15, 7826, {1, 3, 3, 1, 21, 53, 81, 95, 405, 427, 1047, 2443, 4153, 5843, 22511}},
+{2732, 15, 7831, {1, 1, 7, 7, 7, 25, 115, 155, 453, 537, 741, 2379, 2343, 16035, 19587}},
+{2733, 15, 7859, {1, 3, 3, 11, 27, 21, 111, 121, 503, 437, 803, 3399, 5303, 10163, 18199}},
+{2734, 15, 7871, {1, 1, 5, 13, 19, 27, 7, 81, 259, 545, 965, 743, 4533, 8813, 21253}},
+{2735, 15, 7873, {1, 1, 5, 5, 1, 59, 37, 11, 105, 343, 75, 1319, 6317, 9593, 1699}},
+{2736, 15, 7876, {1, 3, 1, 9, 13, 9, 115, 131, 387, 1023, 253, 693, 5191, 12777, 10565}},
+{2737, 15, 7900, {1, 3, 1, 15, 7, 35, 111, 195, 287, 305, 533, 1901, 3363, 10085, 30791}},
+{2738, 15, 7904, {1, 1, 3, 9, 27, 51, 21, 77, 413, 925, 717, 791, 4147, 585, 5649}},
+{2739, 15, 7913, {1, 3, 3, 5, 25, 59, 79, 249, 185, 567, 71, 1997, 7373, 2327, 18637}},
+{2740, 15, 7916, {1, 3, 3, 11, 15, 21, 97, 99, 391, 57, 1973, 29, 7451, 2529, 25737}},
+{2741, 15, 7922, {1, 3, 7, 5, 7, 59, 93, 5, 287, 469, 1639, 3637, 5465, 14431, 32265}},
+{2742, 15, 7946, {1, 1, 3, 11, 3, 1, 71, 75, 427, 299, 811, 3697, 3529, 5433, 26957}},
+{2743, 15, 7953, {1, 3, 1, 9, 19, 59, 37, 255, 165, 1005, 19, 2851, 4309, 455, 9485}},
+{2744, 15, 7956, {1, 1, 1, 5, 1, 55, 15, 233, 133, 47, 1831, 713, 2601, 1017, 3201}},
+{2745, 15, 7963, {1, 1, 5, 5, 21, 55, 127, 69, 377, 41, 25, 2295, 7595, 4733, 11615}},
+{2746, 15, 7979, {1, 1, 5, 3, 23, 5, 7, 181, 161, 775, 1095, 2271, 6637, 14489, 6873}},
+{2747, 15, 7981, {1, 3, 5, 9, 9, 15, 5, 133, 357, 21, 127, 2685, 6299, 4363, 17573}},
+{2748, 15, 7984, {1, 3, 3, 9, 13, 39, 51, 223, 201, 401, 1839, 2461, 7633, 6039, 10445}},
+{2749, 15, 7989, {1, 1, 5, 1, 9, 21, 19, 249, 227, 359, 255, 2895, 4117, 2073, 27687}},
+{2750, 15, 7999, {1, 1, 5, 15, 5, 61, 113, 161, 95, 3, 877, 2775, 293, 6655, 4023}},
+{2751, 15, 8001, {1, 3, 7, 1, 7, 55, 73, 39, 295, 403, 985, 2315, 1667, 13525, 1453}},
+{2752, 15, 8021, {1, 1, 5, 1, 27, 1, 85, 195, 11, 713, 1841, 3895, 3131, 2193, 17607}},
+{2753, 15, 8056, {1, 3, 5, 13, 25, 1, 119, 97, 239, 167, 1393, 1753, 6989, 12155, 12509}},
+{2754, 15, 8080, {1, 1, 7, 15, 31, 21, 41, 255, 425, 445, 165, 2097, 5627, 4971, 13207}},
+{2755, 15, 8083, {1, 1, 1, 15, 13, 33, 81, 105, 453, 197, 13, 1547, 7381, 8709, 15103}},
+{2756, 15, 8089, {1, 1, 3, 11, 11, 33, 107, 123, 483, 367, 121, 995, 1911, 8205, 22577}},
+{2757, 15, 8090, {1, 1, 1, 9, 9, 43, 71, 49, 273, 431, 1705, 3313, 4259, 16291, 14345}},
+{2758, 15, 8114, {1, 1, 1, 7, 3, 1, 43, 213, 97, 547, 1559, 1149, 2791, 3751, 887}},
+{2759, 15, 8128, {1, 1, 3, 15, 25, 47, 49, 251, 425, 35, 295, 3767, 6305, 9633, 5045}},
+{2760, 15, 8133, {1, 3, 3, 1, 5, 55, 91, 245, 27, 981, 331, 555, 6553, 11017, 15289}},
+{2761, 15, 8145, {1, 1, 3, 7, 1, 23, 23, 155, 223, 565, 1005, 3211, 3847, 7479, 3643}},
+{2762, 15, 8155, {1, 1, 5, 1, 17, 7, 47, 95, 35, 779, 1685, 2099, 7505, 15425, 18089}},
+{2763, 15, 8161, {1, 3, 3, 7, 3, 63, 83, 151, 211, 147, 611, 1171, 1681, 7687, 13423}},
+{2764, 15, 8182, {1, 3, 3, 1, 3, 27, 107, 117, 497, 537, 195, 3075, 2753, 1665, 19399}},
+{2765, 15, 8186, {1, 1, 1, 7, 23, 5, 103, 209, 117, 845, 1243, 1283, 4253, 9723, 20937}},
+{2766, 15, 8191, {1, 3, 1, 1, 5, 49, 7, 13, 419, 125, 287, 1599, 8161, 1275, 24661}},
+{2767, 15, 8192, {1, 3, 3, 3, 13, 63, 23, 183, 39, 979, 1301, 2349, 905, 15805, 30151}},
+{2768, 15, 8195, {1, 1, 3, 9, 17, 11, 97, 189, 189, 511, 1779, 2077, 6891, 11623, 23949}},
+{2769, 15, 8201, {1, 1, 7, 11, 13, 45, 15, 37, 11, 853, 915, 1569, 6103, 10633, 3137}},
+{2770, 15, 8207, {1, 3, 3, 5, 15, 61, 91, 255, 131, 821, 1755, 1501, 2663, 1747, 941}},
+{2771, 15, 8210, {1, 1, 3, 7, 19, 19, 65, 95, 499, 239, 2023, 3185, 4649, 3861, 3767}},
+{2772, 15, 8228, {1, 3, 5, 15, 15, 63, 55, 93, 127, 303, 171, 1763, 4991, 9479, 9917}},
+{2773, 15, 8249, {1, 3, 7, 5, 31, 53, 111, 35, 433, 163, 1903, 3991, 3585, 643, 21941}},
+{2774, 15, 8252, {1, 3, 1, 9, 27, 39, 67, 89, 487, 349, 587, 1723, 4311, 11321, 25785}},
+{2775, 15, 8258, {1, 3, 5, 7, 1, 63, 23, 237, 507, 689, 1341, 441, 1721, 843, 20335}},
+{2776, 15, 8267, {1, 1, 3, 3, 31, 63, 83, 103, 25, 799, 1379, 1817, 3809, 12285, 16673}},
+{2777, 15, 8270, {1, 1, 5, 3, 25, 29, 99, 193, 21, 549, 33, 3109, 4135, 10071, 32355}},
+{2778, 15, 8275, {1, 3, 1, 7, 13, 27, 83, 189, 121, 167, 379, 1503, 7955, 13189, 313}},
+{2779, 15, 8284, {1, 3, 5, 15, 25, 19, 83, 87, 257, 237, 709, 1169, 1561, 7117, 4785}},
+{2780, 15, 8293, {1, 1, 1, 7, 9, 55, 21, 5, 439, 367, 403, 2311, 6243, 8349, 13127}},
+{2781, 15, 8298, {1, 3, 7, 3, 5, 35, 51, 67, 453, 767, 29, 3293, 6665, 11459, 2799}},
+{2782, 15, 8305, {1, 3, 3, 3, 5, 19, 59, 7, 367, 683, 783, 1317, 7119, 6129, 19525}},
+{2783, 15, 8317, {1, 1, 5, 5, 5, 19, 61, 67, 381, 291, 875, 2179, 2481, 9325, 11253}},
+{2784, 15, 8328, {1, 3, 5, 5, 7, 47, 107, 9, 141, 667, 1989, 821, 3909, 1733, 10187}},
+{2785, 15, 8336, {1, 1, 7, 7, 31, 61, 1, 71, 477, 689, 1539, 3617, 8105, 6535, 3293}},
+{2786, 15, 8345, {1, 1, 5, 5, 23, 9, 103, 197, 241, 249, 297, 3607, 6217, 1673, 30103}},
+{2787, 15, 8351, {1, 3, 1, 5, 23, 15, 115, 105, 365, 51, 825, 2687, 359, 16325, 15083}},
+{2788, 15, 8367, {1, 1, 3, 11, 29, 45, 65, 251, 169, 189, 1243, 2345, 1345, 14471, 25631}},
+{2789, 15, 8379, {1, 1, 5, 9, 7, 63, 81, 167, 309, 539, 1169, 3949, 4193, 12047, 1491}},
+{2790, 15, 8381, {1, 3, 1, 9, 29, 33, 89, 167, 67, 73, 1885, 477, 5745, 13365, 6819}},
+{2791, 15, 8382, {1, 3, 7, 9, 9, 49, 95, 13, 157, 997, 1725, 935, 7543, 6349, 18277}},
+{2792, 15, 8393, {1, 1, 5, 5, 11, 59, 97, 17, 303, 469, 93, 2761, 7395, 9021, 24299}},
+{2793, 15, 8402, {1, 1, 7, 3, 27, 63, 71, 99, 407, 139, 711, 2589, 4715, 5405, 3277}},
+{2794, 15, 8414, {1, 3, 7, 3, 11, 15, 49, 57, 271, 493, 1165, 2839, 8191, 2609, 14759}},
+{2795, 15, 8417, {1, 1, 1, 7, 21, 15, 71, 245, 413, 473, 1321, 1165, 1027, 6983, 12867}},
+{2796, 15, 8420, {1, 1, 5, 3, 15, 21, 19, 197, 401, 627, 2047, 2761, 5807, 5751, 28025}},
+{2797, 15, 8429, {1, 1, 3, 3, 5, 57, 19, 209, 341, 165, 489, 455, 231, 14385, 12457}},
+{2798, 15, 8435, {1, 3, 3, 11, 13, 63, 79, 129, 17, 315, 1881, 1069, 177, 12013, 29567}},
+{2799, 15, 8438, {1, 1, 3, 7, 31, 29, 51, 235, 475, 375, 617, 437, 6379, 8505, 23079}},
+{2800, 15, 8450, {1, 1, 3, 7, 27, 3, 3, 137, 203, 959, 363, 371, 2899, 13491, 22979}},
+{2801, 15, 8452, {1, 3, 3, 3, 9, 1, 57, 7, 363, 537, 713, 2417, 509, 7747, 22135}},
+{2802, 15, 8459, {1, 3, 3, 3, 13, 21, 79, 121, 487, 921, 113, 281, 2853, 14855, 19747}},
+{2803, 15, 8470, {1, 1, 1, 11, 3, 53, 89, 123, 307, 585, 567, 1925, 505, 15935, 20419}},
+{2804, 15, 8486, {1, 1, 3, 3, 15, 45, 77, 197, 499, 683, 1405, 3573, 981, 14135, 19763}},
+{2805, 15, 8490, {1, 1, 1, 11, 27, 31, 61, 191, 29, 601, 373, 2011, 6193, 3599, 4387}},
+{2806, 15, 8500, {1, 3, 5, 9, 7, 13, 1, 193, 469, 603, 1315, 3329, 3761, 8355, 10425}},
+{2807, 15, 8524, {1, 1, 3, 9, 29, 61, 103, 17, 117, 251, 2029, 2963, 3763, 16117, 6627}},
+{2808, 15, 8536, {1, 3, 1, 3, 7, 51, 91, 145, 497, 657, 871, 3707, 5905, 10449, 14901}},
+{2809, 15, 8552, {1, 1, 3, 1, 3, 53, 23, 149, 461, 333, 1809, 1315, 1815, 8223, 13297}},
+{2810, 15, 8558, {1, 1, 1, 7, 15, 31, 3, 47, 443, 829, 1305, 893, 4191, 9681, 32661}},
+{2811, 15, 8570, {1, 3, 1, 3, 27, 43, 51, 221, 295, 825, 649, 2953, 6203, 8237, 20253}},
+{2812, 15, 8576, {1, 3, 1, 3, 9, 35, 41, 195, 249, 225, 387, 3789, 1499, 2559, 28413}},
+{2813, 15, 8582, {1, 1, 5, 15, 19, 29, 13, 115, 333, 787, 787, 723, 2987, 6227, 10865}},
+{2814, 15, 8594, {1, 3, 5, 13, 5, 59, 5, 251, 79, 387, 11, 3167, 6619, 13317, 18979}},
+{2815, 15, 8606, {1, 1, 7, 11, 31, 51, 43, 1, 189, 519, 1945, 2129, 4365, 14059, 3139}},
+{2816, 15, 8619, {1, 1, 7, 5, 31, 9, 43, 19, 151, 533, 1061, 3849, 6871, 6941, 14935}},
+{2817, 15, 8621, {1, 3, 7, 5, 19, 57, 7, 129, 25, 353, 17, 1739, 6513, 399, 28835}},
+{2818, 15, 8624, {1, 3, 5, 15, 25, 15, 37, 125, 39, 239, 271, 65, 2189, 10449, 11815}},
+{2819, 15, 8633, {1, 3, 7, 15, 19, 57, 47, 245, 509, 945, 385, 3987, 3585, 14711, 9655}},
+{2820, 15, 8641, {1, 1, 3, 13, 21, 31, 13, 81, 9, 489, 1321, 63, 1363, 2219, 19541}},
+{2821, 15, 8653, {1, 1, 5, 7, 3, 57, 25, 147, 23, 553, 889, 307, 6429, 15807, 12861}},
+{2822, 15, 8654, {1, 1, 3, 15, 29, 21, 99, 237, 151, 881, 675, 3625, 1159, 11759, 21347}},
+{2823, 15, 8662, {1, 1, 7, 1, 9, 13, 111, 239, 235, 609, 1569, 3271, 2837, 13807, 7301}},
+{2824, 15, 8675, {1, 3, 1, 15, 7, 59, 27, 81, 129, 9, 647, 3595, 1877, 1067, 1859}},
+{2825, 15, 8689, {1, 3, 7, 1, 3, 25, 119, 57, 145, 441, 1045, 789, 215, 1265, 9369}},
+{2826, 15, 8695, {1, 3, 7, 3, 17, 25, 87, 211, 441, 229, 223, 2795, 7241, 7007, 20575}},
+{2827, 15, 8702, {1, 1, 3, 1, 13, 1, 55, 227, 389, 141, 1097, 2487, 7603, 4161, 5025}},
+{2828, 15, 8706, {1, 1, 3, 5, 15, 29, 29, 145, 233, 209, 891, 89, 8097, 2897, 26685}},
+{2829, 15, 8720, {1, 1, 3, 1, 29, 53, 19, 95, 161, 359, 435, 3313, 4955, 7965, 21015}},
+{2830, 15, 8729, {1, 3, 5, 9, 19, 3, 109, 77, 29, 937, 1663, 125, 2453, 1069, 20639}},
+{2831, 15, 8739, {1, 3, 7, 13, 5, 23, 43, 231, 347, 591, 1963, 2491, 4045, 16029, 8149}},
+{2832, 15, 8741, {1, 1, 5, 1, 13, 3, 75, 211, 419, 929, 901, 3453, 8121, 799, 8897}},
+{2833, 15, 8751, {1, 1, 7, 15, 11, 11, 123, 111, 309, 415, 1071, 975, 2009, 12945, 19617}},
+{2834, 15, 8759, {1, 1, 1, 7, 31, 35, 81, 255, 89, 643, 451, 513, 497, 11751, 24215}},
+{2835, 15, 8766, {1, 3, 5, 5, 25, 17, 5, 165, 139, 929, 1927, 1353, 7427, 9719, 17087}},
+{2836, 15, 8777, {1, 3, 5, 1, 21, 55, 79, 85, 333, 847, 1305, 851, 5057, 8361, 18269}},
+{2837, 15, 8783, {1, 3, 7, 15, 27, 17, 55, 125, 395, 223, 271, 781, 1639, 10569, 11143}},
+{2838, 15, 8786, {1, 1, 7, 9, 7, 33, 127, 85, 209, 339, 483, 241, 2523, 14951, 6855}},
+{2839, 15, 8795, {1, 1, 3, 9, 5, 19, 9, 183, 435, 343, 1105, 3139, 7617, 1311, 267}},
+{2840, 15, 8802, {1, 1, 5, 1, 15, 53, 11, 63, 113, 241, 855, 3123, 4777, 3495, 23345}},
+{2841, 15, 8814, {1, 3, 1, 5, 19, 29, 119, 205, 167, 683, 289, 1629, 4977, 8981, 6867}},
+{2842, 15, 8821, {1, 3, 1, 1, 31, 63, 95, 159, 267, 231, 863, 3385, 5315, 7267, 13757}},
+{2843, 15, 8828, {1, 3, 5, 11, 19, 21, 53, 41, 125, 179, 533, 1279, 3759, 7073, 13905}},
+{2844, 15, 8831, {1, 3, 5, 9, 17, 7, 27, 67, 97, 809, 1423, 2743, 2859, 16121, 329}},
+{2845, 15, 8837, {1, 3, 1, 15, 1, 41, 59, 155, 509, 51, 1827, 3739, 3879, 13369, 30821}},
+{2846, 15, 8842, {1, 3, 3, 7, 21, 31, 7, 13, 347, 919, 1225, 497, 5051, 3769, 20211}},
+{2847, 15, 8855, {1, 3, 7, 13, 31, 9, 127, 195, 123, 387, 3, 3593, 6623, 9827, 29319}},
+{2848, 15, 8856, {1, 1, 3, 9, 7, 27, 95, 211, 287, 189, 1683, 1999, 7641, 14983, 4699}},
+{2849, 15, 8868, {1, 1, 5, 3, 7, 21, 29, 189, 101, 423, 885, 3275, 6569, 11023, 22265}},
+{2850, 15, 8877, {1, 3, 5, 3, 9, 33, 79, 75, 327, 975, 287, 3025, 2157, 7301, 24447}},
+{2851, 15, 8890, {1, 3, 3, 15, 31, 27, 63, 1, 71, 119, 1151, 517, 6131, 11055, 179}},
+{2852, 15, 8892, {1, 3, 7, 11, 23, 15, 101, 247, 349, 735, 673, 997, 6451, 229, 32103}},
+{2853, 15, 8900, {1, 3, 5, 15, 7, 1, 51, 135, 207, 741, 1831, 1235, 4747, 11915, 22009}},
+{2854, 15, 8909, {1, 3, 1, 13, 9, 31, 19, 221, 465, 681, 627, 2595, 5617, 14201, 30355}},
+{2855, 15, 8912, {1, 1, 3, 1, 13, 49, 55, 155, 11, 885, 1275, 3591, 2217, 6659, 30885}},
+{2856, 15, 8921, {1, 1, 7, 11, 27, 57, 93, 95, 243, 63, 1405, 2049, 7689, 15943, 18503}},
+{2857, 15, 8922, {1, 1, 7, 7, 5, 11, 47, 189, 467, 631, 1665, 2717, 4285, 2087, 1435}},
+{2858, 15, 8927, {1, 1, 3, 11, 7, 27, 127, 3, 231, 757, 435, 2545, 3537, 9127, 19915}},
+{2859, 15, 8943, {1, 1, 5, 13, 5, 29, 85, 127, 339, 875, 497, 1573, 6553, 11983, 18029}},
+{2860, 15, 8948, {1, 3, 1, 1, 21, 3, 15, 91, 231, 683, 1529, 2651, 4147, 13437, 23861}},
+{2861, 15, 8951, {1, 3, 1, 7, 27, 17, 19, 179, 243, 223, 1037, 1501, 5935, 2259, 25185}},
+{2862, 15, 8958, {1, 1, 3, 15, 11, 19, 127, 27, 483, 219, 583, 2555, 531, 3451, 17875}},
+{2863, 15, 8984, {1, 1, 1, 13, 31, 39, 89, 149, 363, 741, 1355, 4067, 3171, 6783, 1799}},
+{2864, 15, 8994, {1, 1, 3, 11, 25, 51, 45, 235, 379, 123, 1701, 725, 1991, 7471, 9833}},
+{2865, 15, 9000, {1, 1, 5, 13, 15, 47, 13, 201, 263, 57, 375, 2963, 7475, 15929, 13775}},
+{2866, 15, 9013, {1, 1, 3, 1, 29, 29, 11, 161, 345, 253, 97, 255, 7267, 2379, 3933}},
+{2867, 15, 9018, {1, 3, 1, 15, 3, 47, 11, 69, 347, 747, 795, 2401, 3367, 2383, 6125}},
+{2868, 15, 9020, {1, 1, 7, 3, 1, 49, 101, 47, 71, 761, 1503, 2619, 191, 8895, 873}},
+{2869, 15, 9031, {1, 3, 3, 5, 25, 41, 93, 85, 427, 109, 1675, 2409, 4317, 9233, 30283}},
+{2870, 15, 9035, {1, 1, 3, 9, 11, 3, 67, 159, 425, 751, 887, 1415, 403, 15977, 10739}},
+{2871, 15, 9045, {1, 1, 5, 13, 9, 1, 9, 103, 481, 601, 931, 1957, 5763, 7095, 27141}},
+{2872, 15, 9052, {1, 1, 3, 15, 29, 13, 43, 33, 297, 269, 1041, 1411, 3461, 12043, 10045}},
+{2873, 15, 9056, {1, 3, 5, 3, 3, 3, 5, 7, 185, 753, 133, 1561, 5595, 13777, 25795}},
+{2874, 15, 9059, {1, 3, 5, 5, 1, 19, 29, 145, 163, 149, 619, 2603, 7757, 10035, 10189}},
+{2875, 15, 9066, {1, 3, 7, 15, 27, 15, 111, 173, 135, 117, 157, 2601, 7919, 12111, 22795}},
+{2876, 15, 9076, {1, 3, 1, 1, 29, 27, 65, 31, 101, 715, 289, 3643, 2335, 6789, 23397}},
+{2877, 15, 9089, {1, 3, 1, 3, 11, 45, 71, 109, 321, 423, 1695, 169, 3075, 12423, 11391}},
+{2878, 15, 9129, {1, 1, 3, 9, 13, 51, 35, 121, 203, 279, 433, 2725, 7951, 2105, 27333}},
+{2879, 15, 9132, {1, 1, 1, 15, 23, 31, 25, 105, 501, 441, 1511, 3133, 2811, 10595, 21779}},
+{2880, 15, 9147, {1, 1, 5, 13, 7, 1, 97, 193, 121, 993, 1347, 1903, 1883, 6583, 24535}},
+{2881, 15, 9164, {1, 1, 7, 9, 7, 29, 17, 41, 101, 447, 1289, 387, 1891, 2723, 26091}},
+{2882, 15, 9167, {1, 1, 3, 3, 3, 53, 81, 81, 177, 165, 195, 3413, 8177, 3817, 8453}},
+{2883, 15, 9185, {1, 3, 7, 15, 15, 31, 23, 31, 337, 439, 1773, 63, 5351, 5491, 1767}},
+{2884, 15, 9195, {1, 3, 1, 11, 5, 15, 23, 75, 437, 553, 429, 2705, 3625, 13851, 19865}},
+{2885, 15, 9197, {1, 3, 3, 9, 13, 15, 33, 235, 215, 415, 1737, 1409, 2101, 14623, 14717}},
+{2886, 15, 9210, {1, 3, 7, 7, 13, 51, 101, 217, 175, 813, 1639, 4009, 1625, 4991, 17525}},
+{2887, 15, 9217, {1, 1, 5, 13, 23, 33, 29, 175, 39, 673, 557, 3239, 5129, 11049, 27227}},
+{2888, 15, 9229, {1, 3, 7, 13, 1, 37, 33, 139, 493, 891, 1883, 2525, 5741, 15795, 5875}},
+{2889, 15, 9248, {1, 3, 1, 15, 15, 27, 127, 111, 147, 363, 725, 3077, 4341, 9131, 24635}},
+{2890, 15, 9254, {1, 1, 7, 3, 17, 25, 59, 135, 177, 635, 73, 3455, 3083, 6009, 13033}},
+{2891, 15, 9263, {1, 1, 1, 5, 15, 53, 93, 161, 215, 459, 1087, 179, 2235, 8885, 15309}},
+{2892, 15, 9266, {1, 1, 7, 13, 7, 17, 75, 173, 449, 855, 103, 2739, 3421, 11811, 18805}},
+{2893, 15, 9268, {1, 1, 7, 9, 5, 11, 53, 75, 247, 249, 1201, 953, 2455, 4589, 6027}},
+{2894, 15, 9290, {1, 1, 5, 13, 27, 51, 119, 39, 137, 11, 1435, 3773, 3889, 6081, 11829}},
+{2895, 15, 9310, {1, 1, 5, 5, 5, 35, 1, 197, 501, 185, 1039, 1563, 6421, 14373, 25655}},
+{2896, 15, 9316, {1, 1, 3, 13, 31, 55, 115, 183, 483, 655, 1351, 3203, 725, 3299, 22579}},
+{2897, 15, 9338, {1, 3, 5, 11, 31, 31, 83, 59, 395, 21, 1881, 2821, 2251, 11781, 26265}},
+{2898, 15, 9340, {1, 3, 7, 13, 21, 19, 103, 21, 403, 443, 1951, 55, 985, 15983, 15087}},
+{2899, 15, 9343, {1, 1, 5, 15, 29, 11, 51, 53, 255, 183, 1475, 1491, 259, 387, 10303}},
+{2900, 15, 9344, {1, 3, 5, 7, 21, 37, 45, 39, 479, 637, 1325, 3753, 3319, 7403, 31759}},
+{2901, 15, 9350, {1, 1, 3, 5, 7, 43, 89, 53, 269, 187, 995, 141, 119, 8139, 29699}},
+{2902, 15, 9354, {1, 1, 1, 5, 1, 53, 3, 23, 379, 223, 1889, 4035, 1437, 12425, 9051}},
+{2903, 15, 9359, {1, 3, 1, 13, 3, 31, 61, 43, 249, 449, 901, 1921, 3495, 8599, 5263}},
+{2904, 15, 9361, {1, 1, 3, 5, 3, 25, 35, 133, 25, 597, 915, 3663, 5147, 11831, 24269}},
+{2905, 15, 9364, {1, 1, 1, 9, 21, 27, 93, 93, 217, 299, 1881, 3647, 4825, 7989, 24121}},
+{2906, 15, 9368, {1, 3, 1, 15, 5, 15, 49, 129, 315, 631, 2037, 1567, 4043, 15589, 30905}},
+{2907, 15, 9371, {1, 3, 3, 7, 25, 5, 123, 51, 47, 471, 1563, 3947, 7975, 3681, 9611}},
+{2908, 15, 9373, {1, 3, 7, 15, 1, 17, 73, 245, 465, 95, 95, 1159, 1319, 4675, 8841}},
+{2909, 15, 9389, {1, 1, 3, 15, 5, 51, 35, 71, 423, 651, 753, 173, 2131, 15799, 29601}},
+{2910, 15, 9390, {1, 1, 1, 1, 3, 53, 83, 187, 445, 827, 1549, 979, 5363, 1701, 2149}},
+{2911, 15, 9409, {1, 1, 7, 9, 3, 15, 65, 161, 37, 233, 771, 3749, 727, 6857, 17175}},
+{2912, 15, 9443, {1, 1, 7, 7, 27, 29, 107, 247, 249, 353, 773, 3677, 7273, 5419, 29397}},
+{2913, 15, 9445, {1, 3, 3, 7, 31, 49, 87, 159, 145, 497, 1715, 2115, 5035, 6431, 7245}},
+{2914, 15, 9446, {1, 3, 3, 5, 7, 31, 51, 117, 101, 617, 557, 2551, 6589, 13295, 31975}},
+{2915, 15, 9452, {1, 1, 3, 3, 15, 27, 125, 163, 169, 893, 1771, 25, 5787, 10267, 10297}},
+{2916, 15, 9490, {1, 1, 1, 5, 9, 47, 85, 65, 289, 783, 1105, 4035, 4111, 2589, 24575}},
+{2917, 15, 9492, {1, 3, 3, 13, 23, 33, 7, 49, 301, 531, 1713, 2755, 5543, 8153, 24099}},
+{2918, 15, 9495, {1, 1, 5, 9, 7, 39, 101, 67, 417, 923, 757, 1537, 5553, 12233, 20881}},
+{2919, 15, 9508, {1, 1, 5, 1, 19, 7, 25, 123, 125, 183, 573, 3317, 6867, 871, 17631}},
+{2920, 15, 9523, {1, 1, 3, 15, 19, 13, 117, 41, 129, 715, 1525, 2257, 2179, 10807, 23271}},
+{2921, 15, 9543, {1, 3, 1, 5, 25, 53, 19, 169, 289, 569, 1135, 1967, 7001, 15883, 15113}},
+{2922, 15, 9558, {1, 3, 7, 15, 7, 37, 127, 147, 415, 313, 1541, 1889, 3763, 16199, 12681}},
+{2923, 15, 9567, {1, 1, 3, 9, 1, 35, 95, 137, 237, 951, 899, 3177, 6073, 10655, 31687}},
+{2924, 15, 9580, {1, 1, 5, 5, 29, 57, 45, 253, 297, 529, 1553, 467, 8035, 15675, 21691}},
+{2925, 15, 9585, {1, 3, 7, 15, 25, 41, 59, 81, 87, 985, 1001, 2369, 661, 7551, 11829}},
+{2926, 15, 9591, {1, 1, 7, 9, 27, 21, 7, 233, 309, 67, 701, 2737, 4261, 2467, 15691}},
+{2927, 15, 9611, {1, 3, 7, 1, 19, 55, 47, 155, 333, 101, 517, 1991, 4619, 10435, 27241}},
+{2928, 15, 9613, {1, 1, 7, 3, 23, 35, 7, 125, 157, 537, 933, 3281, 4975, 8969, 27581}},
+{2929, 15, 9614, {1, 1, 3, 7, 19, 53, 81, 103, 461, 435, 777, 335, 5261, 12249, 9695}},
+{2930, 15, 9621, {1, 3, 1, 7, 19, 9, 75, 245, 355, 37, 1855, 1339, 3107, 7251, 16543}},
+{2931, 15, 9631, {1, 1, 1, 3, 5, 35, 39, 223, 113, 423, 1423, 713, 6113, 349, 24147}},
+{2932, 15, 9642, {1, 3, 1, 1, 15, 31, 11, 75, 499, 345, 1253, 2629, 2551, 7483, 25395}},
+{2933, 15, 9656, {1, 1, 3, 11, 25, 25, 3, 211, 185, 45, 1865, 1805, 3303, 11091, 529}},
+{2934, 15, 9661, {1, 3, 1, 1, 9, 21, 7, 165, 107, 641, 1083, 2805, 2099, 5855, 18477}},
+{2935, 15, 9667, {1, 3, 5, 3, 9, 21, 77, 103, 505, 277, 335, 797, 3869, 2957, 1979}},
+{2936, 15, 9694, {1, 3, 5, 15, 31, 23, 77, 247, 303, 891, 1261, 3233, 3495, 13111, 13185}},
+{2937, 15, 9715, {1, 3, 5, 11, 11, 35, 49, 229, 149, 931, 881, 775, 2949, 3141, 29157}},
+{2938, 15, 9722, {1, 1, 3, 5, 19, 57, 23, 95, 347, 221, 195, 3561, 1481, 2063, 3979}},
+{2939, 15, 9738, {1, 3, 5, 3, 13, 1, 23, 173, 431, 29, 421, 3235, 2751, 4447, 28283}},
+{2940, 15, 9745, {1, 1, 5, 13, 23, 3, 1, 9, 327, 855, 1251, 2997, 6129, 4223, 11555}},
+{2941, 15, 9758, {1, 3, 7, 13, 29, 21, 37, 229, 217, 353, 1239, 3955, 491, 12183, 14777}},
+{2942, 15, 9764, {1, 1, 5, 5, 1, 33, 103, 187, 183, 939, 1873, 2633, 6143, 15405, 17353}},
+{2943, 15, 9782, {1, 1, 1, 9, 21, 27, 71, 129, 499, 279, 1181, 4053, 2485, 1961, 30603}},
+{2944, 15, 9791, {1, 1, 3, 15, 21, 37, 45, 201, 221, 187, 727, 1241, 6171, 1383, 22277}},
+{2945, 15, 9793, {1, 3, 7, 5, 21, 17, 67, 177, 323, 601, 633, 865, 6131, 10329, 8689}},
+{2946, 15, 9794, {1, 3, 5, 9, 15, 45, 71, 43, 359, 651, 103, 403, 3249, 11769, 6567}},
+{2947, 15, 9805, {1, 3, 3, 13, 3, 23, 101, 145, 367, 999, 1489, 3673, 2959, 10855, 16029}},
+{2948, 15, 9808, {1, 3, 7, 3, 13, 43, 123, 87, 55, 1015, 141, 2917, 6567, 16025, 25555}},
+{2949, 15, 9811, {1, 3, 1, 3, 17, 7, 21, 161, 41, 889, 1315, 1897, 639, 15451, 3049}},
+{2950, 15, 9817, {1, 3, 5, 15, 27, 33, 55, 17, 81, 431, 325, 909, 3547, 10121, 17815}},
+{2951, 15, 9824, {1, 1, 3, 1, 15, 37, 43, 137, 203, 191, 1129, 1585, 435, 3177, 769}},
+{2952, 15, 9836, {1, 3, 7, 11, 21, 23, 125, 41, 17, 951, 465, 3691, 3465, 13247, 13779}},
+{2953, 15, 9851, {1, 3, 3, 1, 31, 23, 43, 101, 405, 739, 1061, 2955, 5643, 16137, 8763}},
+{2954, 15, 9853, {1, 1, 5, 1, 19, 33, 99, 109, 203, 65, 395, 2775, 1373, 2557, 5875}},
+{2955, 15, 9854, {1, 3, 3, 3, 27, 51, 79, 63, 331, 365, 1071, 1661, 4549, 8561, 1719}},
+{2956, 15, 9877, {1, 3, 3, 9, 3, 17, 53, 161, 141, 489, 1325, 1709, 1381, 5093, 171}},
+{2957, 15, 9881, {1, 1, 7, 15, 9, 3, 95, 237, 197, 949, 7, 1837, 729, 10111, 6637}},
+{2958, 15, 9923, {1, 1, 3, 3, 19, 31, 57, 173, 483, 861, 1001, 1919, 3389, 11777, 20693}},
+{2959, 15, 9935, {1, 3, 1, 9, 27, 13, 113, 177, 75, 925, 949, 119, 4759, 7775, 23033}},
+{2960, 15, 9937, {1, 1, 7, 15, 23, 15, 65, 61, 137, 653, 1843, 323, 379, 15157, 29885}},
+{2961, 15, 9954, {1, 3, 3, 7, 29, 3, 11, 205, 347, 745, 1477, 3929, 5749, 4735, 29435}},
+{2962, 15, 9959, {1, 3, 5, 9, 1, 11, 111, 15, 7, 69, 45, 3607, 1099, 9203, 21301}},
+{2963, 15, 9963, {1, 3, 3, 3, 23, 3, 83, 173, 73, 485, 681, 1867, 3839, 11823, 13339}},
+{2964, 15, 9968, {1, 1, 3, 11, 31, 43, 107, 127, 465, 389, 1595, 427, 1571, 5885, 29569}},
+{2965, 15, 9973, {1, 1, 7, 9, 27, 25, 117, 27, 287, 391, 279, 3247, 35, 12973, 5483}},
+{2966, 15, 9974, {1, 3, 7, 11, 19, 55, 45, 127, 245, 945, 305, 3907, 2455, 3163, 31}},
+{2967, 15, 9980, {1, 1, 7, 11, 15, 17, 65, 15, 37, 207, 1447, 3027, 2281, 6557, 16717}},
+{2968, 15, 9983, {1, 1, 1, 13, 5, 27, 33, 213, 29, 603, 1171, 3235, 2255, 2017, 30999}},
+{2969, 15, 9985, {1, 3, 1, 5, 11, 1, 73, 233, 69, 125, 397, 297, 3337, 6191, 31055}},
+{2970, 15, 10003, {1, 1, 1, 15, 1, 1, 65, 145, 201, 917, 1891, 2999, 4069, 10413, 15819}},
+{2971, 15, 10010, {1, 3, 5, 13, 15, 51, 115, 167, 311, 375, 1069, 2595, 3337, 753, 11903}},
+{2972, 15, 10034, {1, 1, 3, 1, 1, 23, 69, 125, 147, 915, 1945, 411, 979, 13863, 30443}},
+{2973, 15, 10040, {1, 3, 1, 11, 5, 1, 93, 23, 135, 93, 1689, 23, 3519, 4491, 24673}},
+{2974, 15, 10063, {1, 1, 7, 3, 11, 59, 93, 153, 487, 475, 1191, 1455, 5963, 8259, 18811}},
+{2975, 15, 10077, {1, 1, 3, 1, 13, 15, 55, 71, 433, 33, 491, 1835, 5695, 10509, 347}},
+{2976, 15, 10081, {1, 1, 1, 15, 19, 1, 23, 47, 235, 101, 1057, 901, 5477, 7079, 30885}},
+{2977, 15, 10082, {1, 1, 5, 13, 11, 43, 119, 77, 441, 121, 783, 827, 1757, 12751, 31593}},
+{2978, 15, 10084, {1, 3, 7, 11, 19, 17, 37, 225, 329, 231, 515, 1541, 7371, 6355, 10905}},
+{2979, 15, 10088, {1, 1, 5, 13, 7, 11, 35, 215, 345, 577, 147, 2803, 3291, 4631, 5329}},
+{2980, 15, 10091, {1, 1, 3, 9, 21, 55, 113, 251, 25, 221, 1445, 3385, 1589, 4109, 29897}},
+{2981, 15, 10105, {1, 1, 5, 7, 9, 45, 5, 33, 331, 285, 1101, 3131, 2713, 5653, 3823}},
+{2982, 15, 10111, {1, 3, 7, 7, 5, 39, 43, 167, 481, 629, 777, 1827, 4653, 403, 4781}},
+{2983, 15, 10118, {1, 3, 3, 7, 31, 33, 31, 159, 313, 673, 1425, 663, 5819, 1297, 26627}},
+{2984, 15, 10127, {1, 3, 3, 1, 19, 61, 117, 93, 373, 491, 1031, 757, 4185, 771, 7265}},
+{2985, 15, 10135, {1, 1, 7, 9, 3, 45, 65, 223, 437, 41, 1139, 2733, 5963, 2709, 25429}},
+{2986, 15, 10169, {1, 3, 5, 11, 21, 27, 31, 127, 255, 761, 1865, 1319, 6583, 9235, 10717}},
+{2987, 15, 10172, {1, 1, 1, 5, 21, 1, 63, 43, 413, 557, 567, 2893, 8017, 2307, 29525}},
+{2988, 15, 10183, {1, 1, 7, 3, 31, 1, 15, 235, 215, 395, 1971, 469, 5275, 431, 5349}},
+{2989, 15, 10190, {1, 1, 1, 13, 25, 59, 71, 245, 389, 279, 1293, 89, 6551, 10285, 14495}},
+{2990, 15, 10192, {1, 1, 5, 5, 9, 63, 17, 229, 425, 939, 877, 3689, 7229, 6707, 30771}},
+{2991, 15, 10211, {1, 3, 7, 7, 11, 29, 43, 41, 25, 237, 1585, 3735, 2617, 7541, 26243}},
+{2992, 15, 10218, {1, 1, 7, 9, 21, 5, 69, 231, 361, 39, 1695, 3043, 2973, 5487, 12857}},
+{2993, 15, 10228, {1, 1, 5, 3, 17, 63, 91, 217, 407, 133, 1373, 4021, 1737, 10043, 4561}},
+{2994, 15, 10235, {1, 3, 7, 9, 31, 13, 101, 231, 175, 457, 89, 2167, 2725, 8505, 375}},
+{2995, 15, 10242, {1, 1, 3, 15, 31, 11, 27, 211, 347, 291, 1881, 3091, 3307, 5117, 13341}},
+{2996, 15, 10244, {1, 3, 5, 5, 13, 25, 5, 197, 237, 135, 635, 1175, 5085, 14737, 10807}},
+{2997, 15, 10271, {1, 3, 3, 9, 7, 63, 107, 127, 147, 477, 1813, 2619, 8089, 2651, 26549}},
+{2998, 15, 10278, {1, 1, 5, 11, 15, 45, 27, 133, 45, 621, 707, 2679, 5929, 19, 9599}},
+{2999, 15, 10296, {1, 3, 7, 9, 21, 37, 41, 255, 69, 1009, 1999, 367, 6177, 10017, 3549}},
+{3000, 15, 10299, {1, 1, 1, 15, 19, 55, 73, 189, 423, 983, 1811, 2551, 4765, 12077, 18205}},
+{3001, 15, 10307, {1, 1, 5, 7, 17, 13, 25, 225, 463, 471, 631, 1811, 5797, 3235, 32253}},
+{3002, 15, 10309, {1, 3, 7, 1, 29, 7, 123, 187, 331, 735, 1757, 1115, 2077, 15725, 2183}},
+{3003, 15, 10310, {1, 3, 7, 9, 17, 61, 111, 93, 21, 1003, 1905, 3719, 2111, 11845, 6427}},
+{3004, 15, 10314, {1, 3, 7, 7, 17, 21, 51, 59, 115, 723, 2039, 2833, 5969, 5737, 18407}},
+{3005, 15, 10316, {1, 3, 3, 13, 9, 47, 95, 233, 13, 281, 1049, 619, 405, 16205, 20097}},
+{3006, 15, 10321, {1, 3, 7, 13, 9, 41, 11, 171, 453, 713, 587, 1669, 2489, 10277, 18599}},
+{3007, 15, 10328, {1, 3, 3, 13, 21, 41, 123, 173, 511, 399, 859, 1515, 5773, 12535, 26289}},
+{3008, 15, 10338, {1, 1, 7, 15, 11, 3, 113, 111, 73, 7, 1191, 2573, 7713, 465, 27615}},
+{3009, 15, 10343, {1, 1, 7, 15, 5, 5, 39, 11, 489, 13, 1041, 1639, 7879, 11899, 6899}},
+{3010, 15, 10344, {1, 1, 5, 9, 27, 31, 15, 237, 401, 795, 1675, 2361, 7333, 12507, 14627}},
+{3011, 15, 10347, {1, 3, 1, 7, 21, 53, 31, 81, 189, 683, 1283, 419, 7585, 9207, 15053}},
+{3012, 15, 10352, {1, 3, 5, 11, 21, 1, 49, 251, 403, 489, 1235, 429, 4855, 4081, 17575}},
+{3013, 15, 10364, {1, 3, 1, 15, 29, 33, 77, 53, 105, 731, 749, 2677, 3967, 7967, 18723}},
+{3014, 15, 10373, {1, 3, 3, 11, 9, 47, 11, 95, 137, 923, 599, 1585, 1969, 9625, 19171}},
+{3015, 15, 10386, {1, 1, 1, 5, 7, 7, 85, 49, 339, 883, 261, 2125, 3831, 9797, 16395}},
+{3016, 15, 10391, {1, 3, 3, 3, 5, 9, 33, 99, 75, 889, 101, 2099, 6635, 11511, 21573}},
+{3017, 15, 10398, {1, 1, 5, 11, 1, 11, 79, 49, 7, 131, 471, 1235, 3287, 14777, 12053}},
+{3018, 15, 10408, {1, 1, 5, 15, 9, 9, 83, 15, 21, 899, 1785, 2349, 3471, 6723, 1405}},
+{3019, 15, 10413, {1, 3, 5, 11, 1, 7, 121, 223, 509, 859, 1037, 491, 5529, 481, 17029}},
+{3020, 15, 10422, {1, 1, 7, 5, 17, 35, 91, 171, 113, 65, 423, 2371, 5105, 12827, 31087}},
+{3021, 15, 10445, {1, 1, 3, 3, 21, 47, 55, 11, 159, 51, 263, 2113, 661, 9147, 28929}},
+{3022, 15, 10460, {1, 1, 1, 9, 19, 7, 43, 223, 207, 787, 543, 2141, 4247, 7369, 29031}},
+{3023, 15, 10463, {1, 1, 7, 11, 11, 51, 121, 9, 211, 905, 687, 889, 1827, 13395, 3507}},
+{3024, 15, 10464, {1, 3, 1, 7, 15, 23, 5, 139, 469, 569, 33, 3477, 5391, 13665, 17011}},
+{3025, 15, 10474, {1, 1, 1, 15, 29, 29, 29, 201, 63, 1019, 97, 1671, 9, 4617, 19833}},
+{3026, 15, 10476, {1, 1, 5, 15, 25, 5, 67, 225, 189, 919, 1471, 1451, 5017, 16189, 31555}},
+{3027, 15, 10487, {1, 3, 5, 5, 15, 51, 89, 221, 149, 863, 43, 2381, 1767, 8037, 5319}},
+{3028, 15, 10494, {1, 3, 3, 1, 15, 17, 5, 77, 69, 27, 1883, 63, 5987, 1497, 3723}},
+{3029, 15, 10499, {1, 3, 7, 11, 7, 5, 113, 229, 123, 709, 1531, 641, 6655, 14923, 22947}},
+{3030, 15, 10506, {1, 3, 1, 13, 21, 15, 45, 175, 81, 499, 1113, 587, 7573, 11689, 15651}},
+{3031, 15, 10513, {1, 3, 1, 1, 29, 43, 101, 37, 131, 757, 465, 743, 2737, 8063, 23967}},
+{3032, 15, 10516, {1, 1, 7, 13, 9, 21, 39, 177, 51, 691, 2047, 1519, 6137, 5271, 8703}},
+{3033, 15, 10523, {1, 1, 3, 3, 5, 55, 63, 21, 3, 317, 461, 527, 2673, 16211, 6721}},
+{3034, 15, 10539, {1, 3, 5, 5, 5, 47, 7, 241, 387, 589, 323, 203, 7241, 14761, 13287}},
+{3035, 15, 10549, {1, 3, 5, 3, 23, 63, 55, 61, 231, 1023, 1315, 1181, 243, 7389, 25639}},
+{3036, 15, 10550, {1, 1, 7, 13, 31, 43, 41, 81, 127, 887, 1513, 4055, 1361, 2443, 6963}},
+{3037, 15, 10567, {1, 1, 1, 5, 7, 43, 43, 33, 323, 911, 1373, 3053, 6503, 513, 6457}},
+{3038, 15, 10576, {1, 1, 7, 11, 25, 61, 21, 149, 205, 349, 1433, 1587, 149, 7275, 5465}},
+{3039, 15, 10625, {1, 3, 5, 5, 11, 9, 31, 217, 119, 511, 209, 3325, 2023, 2877, 463}},
+{3040, 15, 10635, {1, 3, 5, 15, 21, 47, 89, 41, 347, 849, 1375, 3311, 807, 11443, 27643}},
+{3041, 15, 10643, {1, 1, 5, 7, 29, 43, 123, 191, 321, 373, 447, 2145, 1221, 2071, 12689}},
+{3042, 15, 10656, {1, 3, 5, 15, 1, 21, 43, 141, 461, 779, 1109, 2915, 909, 8585, 19859}},
+{3043, 15, 10671, {1, 3, 3, 11, 5, 17, 57, 13, 393, 661, 1761, 2455, 43, 8593, 20505}},
+{3044, 15, 10676, {1, 3, 5, 1, 31, 47, 65, 249, 77, 513, 851, 2381, 3447, 693, 7729}},
+{3045, 15, 10683, {1, 3, 5, 15, 31, 19, 83, 47, 369, 697, 1815, 819, 7573, 9245, 8013}},
+{3046, 15, 10685, {1, 3, 5, 5, 11, 25, 27, 151, 107, 339, 299, 3869, 3393, 5661, 2947}},
+{3047, 15, 10688, {1, 1, 3, 1, 1, 59, 85, 57, 175, 465, 239, 3115, 7157, 7035, 11463}},
+{3048, 15, 10697, {1, 1, 7, 5, 31, 41, 53, 149, 121, 743, 189, 159, 5289, 2945, 1179}},
+{3049, 15, 10700, {1, 3, 3, 15, 23, 51, 83, 25, 159, 163, 61, 713, 4529, 5253, 1603}},
+{3050, 15, 10712, {1, 3, 5, 11, 7, 29, 15, 177, 507, 695, 1305, 1863, 7525, 3063, 27433}},
+{3051, 15, 10724, {1, 1, 3, 11, 5, 41, 115, 227, 409, 951, 591, 4003, 7717, 4369, 15637}},
+{3052, 15, 10728, {1, 1, 7, 11, 23, 55, 71, 135, 51, 411, 2003, 2375, 6823, 1711, 4443}},
+{3053, 15, 10734, {1, 3, 1, 3, 31, 47, 31, 233, 243, 3, 313, 1649, 6955, 13679, 32327}},
+{3054, 15, 10739, {1, 1, 3, 11, 29, 9, 1, 79, 247, 677, 685, 3107, 5987, 9675, 29523}},
+{3055, 15, 10762, {1, 1, 1, 7, 25, 31, 39, 241, 483, 839, 1143, 437, 2317, 2437, 173}},
+{3056, 15, 10772, {1, 1, 5, 1, 17, 19, 83, 57, 39, 479, 715, 1911, 1091, 10937, 22145}},
+{3057, 15, 10781, {1, 1, 7, 1, 27, 45, 35, 55, 477, 719, 217, 3349, 7717, 6853, 9699}},
+{3058, 15, 10800, {1, 3, 1, 11, 9, 39, 25, 223, 303, 713, 151, 2611, 4629, 5855, 31729}},
+{3059, 15, 10805, {1, 1, 1, 11, 13, 35, 53, 39, 167, 779, 1673, 1221, 6281, 15113, 32027}},
+{3060, 15, 10827, {1, 1, 5, 9, 19, 63, 89, 113, 199, 107, 1015, 835, 2879, 9499, 25597}},
+{3061, 15, 10830, {1, 1, 7, 3, 19, 37, 15, 23, 449, 641, 1811, 3407, 6775, 6283, 31157}},
+{3062, 15, 10837, {1, 1, 3, 1, 19, 15, 31, 99, 511, 897, 1693, 2093, 955, 15897, 26693}},
+{3063, 15, 10841, {1, 1, 5, 1, 5, 15, 47, 19, 441, 541, 1621, 3877, 6407, 15991, 1931}},
+{3064, 15, 10847, {1, 3, 5, 9, 21, 61, 15, 77, 265, 351, 879, 3835, 6555, 2349, 23235}},
+{3065, 15, 10848, {1, 1, 5, 11, 25, 37, 29, 181, 341, 641, 1213, 1319, 6359, 6231, 32573}},
+{3066, 15, 10857, {1, 1, 1, 7, 1, 37, 87, 123, 33, 913, 111, 2613, 4895, 12595, 26633}},
+{3067, 15, 10866, {1, 3, 5, 3, 27, 11, 45, 89, 183, 241, 1355, 783, 3343, 239, 8643}},
+{3068, 15, 10868, {1, 3, 7, 7, 9, 35, 67, 187, 233, 577, 1445, 3063, 6039, 16233, 1453}},
+{3069, 15, 10872, {1, 1, 3, 13, 27, 11, 23, 15, 95, 63, 1931, 911, 8149, 6833, 3051}},
+{3070, 15, 10887, {1, 3, 3, 5, 29, 49, 125, 117, 47, 143, 423, 3215, 3605, 3677, 17155}},
+{3071, 15, 10899, {1, 3, 1, 1, 31, 1, 123, 195, 83, 893, 1947, 339, 2927, 7183, 15443}},
+{3072, 15, 10901, {1, 1, 7, 13, 31, 15, 91, 207, 39, 275, 439, 2617, 3093, 11041, 24997}},
+{3073, 15, 10915, {1, 1, 5, 3, 3, 41, 13, 67, 361, 497, 25, 3807, 3551, 9681, 21043}},
+{3074, 15, 10924, {1, 3, 3, 3, 11, 27, 103, 59, 427, 327, 1705, 29, 8127, 1641, 20847}},
+{3075, 15, 10929, {1, 3, 7, 5, 3, 37, 81, 137, 225, 101, 187, 3067, 2491, 12687, 16227}},
+{3076, 15, 10942, {1, 3, 5, 15, 15, 33, 69, 223, 225, 771, 1917, 2293, 2889, 12083, 23971}},
+{3077, 15, 10971, {1, 1, 3, 5, 11, 9, 121, 81, 203, 425, 1189, 2011, 3041, 3247, 739}},
+{3078, 15, 10992, {1, 3, 1, 1, 13, 9, 39, 169, 437, 571, 1481, 3355, 3895, 8975, 31031}},
+{3079, 15, 10995, {1, 3, 1, 11, 1, 43, 35, 35, 293, 11, 657, 1415, 5021, 14463, 17945}},
+{3080, 15, 11002, {1, 1, 5, 5, 13, 47, 91, 15, 159, 23, 971, 3575, 757, 13477, 31757}},
+{3081, 15, 11010, {1, 1, 7, 1, 5, 63, 69, 27, 71, 129, 123, 3767, 89, 7865, 1189}},
+{3082, 15, 11027, {1, 3, 3, 5, 23, 1, 83, 3, 487, 491, 217, 2583, 3889, 15009, 9227}},
+{3083, 15, 11029, {1, 3, 5, 15, 25, 1, 73, 107, 245, 191, 1449, 571, 1403, 6953, 17457}},
+{3084, 15, 11045, {1, 3, 3, 3, 27, 19, 25, 105, 207, 857, 1161, 3657, 2107, 7955, 517}},
+{3085, 15, 11057, {1, 3, 3, 9, 21, 29, 5, 103, 219, 35, 3, 1635, 4815, 15797, 29839}},
+{3086, 15, 11070, {1, 1, 7, 7, 3, 63, 75, 77, 13, 57, 603, 2333, 7761, 14397, 10875}},
+{3087, 15, 11092, {1, 3, 7, 13, 3, 11, 5, 255, 1, 947, 1695, 1927, 7447, 7407, 20797}},
+{3088, 15, 11099, {1, 1, 5, 1, 1, 21, 105, 73, 429, 973, 1801, 3943, 6161, 1309, 3359}},
+{3089, 15, 11106, {1, 1, 3, 15, 27, 9, 9, 129, 117, 545, 9, 1983, 6351, 10925, 27337}},
+{3090, 15, 11115, {1, 3, 3, 5, 5, 5, 13, 155, 503, 875, 1243, 2259, 3445, 11953, 6517}},
+{3091, 15, 11120, {1, 1, 7, 3, 29, 21, 121, 147, 413, 423, 1887, 2429, 2765, 16335, 3071}},
+{3092, 15, 11126, {1, 1, 7, 9, 5, 53, 41, 137, 463, 583, 1627, 1731, 6675, 3703, 8177}},
+{3093, 15, 11153, {1, 3, 5, 11, 31, 29, 67, 159, 425, 25, 1457, 139, 5019, 701, 7357}},
+{3094, 15, 11190, {1, 3, 1, 5, 25, 15, 123, 123, 245, 859, 249, 2175, 2137, 5765, 4873}},
+{3095, 15, 11199, {1, 1, 3, 5, 23, 1, 111, 111, 111, 469, 1473, 1777, 3579, 13503, 2569}},
+{3096, 15, 11222, {1, 1, 7, 3, 17, 23, 51, 23, 499, 135, 713, 3317, 807, 9589, 11349}},
+{3097, 15, 11225, {1, 1, 1, 15, 9, 51, 75, 159, 359, 773, 1521, 2913, 5901, 3047, 14649}},
+{3098, 15, 11226, {1, 1, 3, 1, 13, 61, 117, 195, 49, 267, 57, 1769, 3621, 9415, 29443}},
+{3099, 15, 11231, {1, 3, 7, 11, 3, 25, 33, 31, 315, 191, 359, 3399, 2481, 13831, 20205}},
+{3100, 15, 11244, {1, 3, 3, 5, 31, 43, 35, 125, 291, 51, 1469, 3857, 1707, 2641, 32137}},
+{3101, 15, 11259, {1, 3, 5, 1, 25, 11, 113, 137, 211, 159, 1667, 939, 6439, 5337, 32059}},
+{3102, 15, 11261, {1, 3, 3, 11, 31, 61, 99, 49, 383, 343, 395, 51, 6931, 16039, 5901}},
+{3103, 15, 11270, {1, 1, 3, 5, 9, 63, 63, 49, 405, 915, 1505, 2141, 6749, 7799, 17313}},
+{3104, 15, 11273, {1, 3, 7, 11, 15, 11, 49, 161, 155, 869, 121, 301, 6561, 4279, 15233}},
+{3105, 15, 11300, {1, 1, 5, 13, 19, 13, 103, 59, 503, 293, 701, 2527, 5327, 13927, 5025}},
+{3106, 15, 11307, {1, 1, 7, 1, 1, 37, 55, 155, 485, 399, 855, 2677, 5927, 9657, 2795}},
+{3107, 15, 11318, {1, 1, 1, 5, 19, 15, 121, 69, 385, 75, 1567, 2649, 5601, 12981, 15903}},
+{3108, 15, 11332, {1, 1, 1, 11, 19, 21, 45, 59, 505, 737, 15, 1383, 1177, 8375, 15557}},
+{3109, 15, 11335, {1, 1, 7, 13, 29, 19, 123, 127, 469, 773, 733, 3289, 8087, 5803, 27897}},
+{3110, 15, 11341, {1, 3, 3, 11, 19, 55, 101, 67, 485, 939, 607, 1521, 6161, 12235, 16499}},
+{3111, 15, 11347, {1, 3, 5, 13, 29, 31, 31, 9, 453, 151, 1055, 3873, 405, 12877, 29829}},
+{3112, 15, 11354, {1, 3, 5, 1, 17, 1, 17, 131, 107, 1003, 1749, 1849, 6207, 2153, 21275}},
+{3113, 15, 11360, {1, 3, 7, 15, 7, 25, 51, 143, 51, 517, 1841, 1771, 5389, 4633, 11123}},
+{3114, 15, 11369, {1, 3, 7, 11, 23, 7, 89, 95, 403, 361, 835, 585, 2783, 8091, 5141}},
+{3115, 15, 11372, {1, 3, 1, 9, 1, 53, 115, 11, 493, 587, 305, 3605, 1711, 4169, 20013}},
+{3116, 15, 11378, {1, 3, 7, 3, 17, 59, 55, 251, 49, 759, 1227, 3685, 7765, 1445, 20385}},
+{3117, 15, 11396, {1, 1, 5, 7, 29, 55, 19, 157, 129, 927, 893, 1235, 1955, 8153, 2865}},
+{3118, 15, 11405, {1, 3, 1, 15, 21, 35, 81, 53, 175, 939, 1635, 3597, 747, 14011, 12867}},
+{3119, 15, 11417, {1, 3, 7, 1, 27, 61, 91, 73, 405, 677, 603, 2715, 7099, 941, 24523}},
+{3120, 15, 11424, {1, 3, 5, 9, 13, 45, 35, 167, 57, 483, 735, 2777, 7847, 6257, 13109}},
+{3121, 15, 11427, {1, 3, 5, 7, 1, 3, 97, 13, 159, 533, 1791, 1061, 981, 10795, 26165}},
+{3122, 15, 11430, {1, 1, 5, 13, 27, 5, 125, 25, 251, 221, 1909, 197, 6987, 11537, 15287}},
+{3123, 15, 11439, {1, 3, 5, 5, 27, 15, 1, 131, 375, 923, 81, 3153, 6071, 2515, 23729}},
+{3124, 15, 11442, {1, 3, 3, 9, 9, 23, 71, 13, 465, 261, 937, 1549, 5993, 11325, 15065}},
+{3125, 15, 11448, {1, 3, 1, 3, 7, 63, 17, 129, 435, 23, 215, 2251, 1561, 9703, 26483}},
+{3126, 15, 11461, {1, 1, 3, 1, 5, 53, 77, 109, 9, 605, 371, 2081, 6023, 7145, 15837}},
+{3127, 15, 11468, {1, 3, 7, 11, 27, 39, 115, 47, 259, 337, 1857, 3465, 1549, 7747, 8525}},
+{3128, 15, 11471, {1, 3, 7, 7, 29, 29, 75, 77, 29, 661, 899, 3137, 2661, 15271, 28093}},
+{3129, 15, 11473, {1, 1, 1, 3, 3, 3, 11, 219, 39, 757, 1465, 249, 7445, 7013, 15187}},
+{3130, 15, 11476, {1, 3, 7, 15, 15, 1, 39, 245, 427, 1003, 1493, 1913, 6435, 14787, 13481}},
+{3131, 15, 11480, {1, 1, 7, 3, 3, 37, 5, 97, 343, 833, 1379, 1551, 5403, 1843, 5877}},
+{3132, 15, 11489, {1, 3, 1, 1, 3, 17, 17, 163, 339, 691, 1707, 1845, 5941, 4259, 24531}},
+{3133, 15, 11499, {1, 1, 1, 1, 27, 21, 85, 221, 71, 949, 1753, 391, 6349, 15901, 20811}},
+{3134, 15, 11516, {1, 1, 1, 5, 31, 19, 45, 99, 469, 783, 1747, 3807, 5889, 9485, 13715}},
+{3135, 15, 11522, {1, 3, 1, 9, 23, 21, 39, 25, 421, 713, 461, 2857, 5023, 5341, 6409}},
+{3136, 15, 11531, {1, 3, 7, 5, 25, 19, 59, 147, 387, 857, 375, 3103, 1261, 13697, 25675}},
+{3137, 15, 11539, {1, 3, 5, 5, 31, 21, 49, 251, 463, 441, 473, 3487, 3915, 11151, 17721}},
+{3138, 15, 11546, {1, 1, 3, 9, 15, 47, 81, 219, 143, 141, 81, 1705, 5847, 3437, 30521}},
+{3139, 15, 11551, {1, 1, 7, 3, 25, 19, 97, 41, 77, 105, 1337, 695, 7589, 8587, 7509}},
+{3140, 15, 11564, {1, 1, 5, 13, 3, 11, 61, 19, 139, 667, 963, 1567, 5715, 7079, 15967}},
+{3141, 15, 11582, {1, 1, 5, 5, 5, 29, 67, 57, 477, 173, 1163, 727, 823, 15635, 17705}},
+{3142, 15, 11589, {1, 3, 7, 11, 13, 39, 57, 193, 73, 617, 535, 1623, 4581, 4451, 2589}},
+{3143, 15, 11593, {1, 1, 5, 5, 9, 27, 75, 127, 325, 413, 1669, 1749, 8045, 16199, 12237}},
+{3144, 15, 11601, {1, 1, 3, 1, 17, 23, 27, 189, 319, 953, 347, 909, 4401, 12791, 25077}},
+{3145, 15, 11608, {1, 1, 3, 3, 17, 51, 37, 79, 301, 607, 885, 1169, 3275, 3327, 20013}},
+{3146, 15, 11617, {1, 3, 5, 3, 21, 9, 99, 213, 387, 889, 575, 3591, 5377, 2981, 23989}},
+{3147, 15, 11630, {1, 3, 3, 13, 11, 7, 23, 255, 279, 853, 453, 2377, 8123, 15393, 9669}},
+{3148, 15, 11663, {1, 3, 1, 7, 11, 9, 109, 35, 405, 449, 1967, 2943, 3485, 5031, 14273}},
+{3149, 15, 11666, {1, 3, 3, 1, 25, 27, 43, 115, 435, 675, 1937, 1477, 4831, 9417, 7017}},
+{3150, 15, 11668, {1, 1, 7, 13, 19, 45, 83, 241, 487, 215, 1453, 209, 4061, 1765, 15623}},
+{3151, 15, 11677, {1, 1, 7, 7, 21, 31, 95, 9, 287, 1005, 1933, 3405, 6913, 7733, 18975}},
+{3152, 15, 11682, {1, 1, 1, 11, 13, 11, 25, 39, 283, 57, 255, 2809, 5767, 6127, 6705}},
+{3153, 15, 11687, {1, 3, 1, 11, 1, 51, 73, 181, 261, 215, 385, 2777, 5169, 12431, 23563}},
+{3154, 15, 11696, {1, 3, 3, 9, 9, 39, 123, 197, 501, 679, 109, 3369, 4817, 8855, 7997}},
+{3155, 15, 11713, {1, 1, 5, 1, 29, 61, 15, 183, 453, 999, 1211, 3217, 8035, 5153, 19975}},
+{3156, 15, 11728, {1, 3, 7, 11, 11, 21, 51, 45, 379, 793, 289, 309, 1229, 7159, 581}},
+{3157, 15, 11747, {1, 1, 3, 9, 17, 11, 75, 67, 289, 191, 1083, 2949, 6063, 6611, 21595}},
+{3158, 15, 11750, {1, 3, 7, 3, 27, 45, 59, 193, 485, 277, 27, 1219, 2389, 15875, 6273}},
+{3159, 15, 11754, {1, 1, 5, 3, 31, 29, 65, 197, 115, 163, 9, 783, 5573, 2833, 12603}},
+{3160, 15, 11759, {1, 1, 3, 7, 5, 53, 115, 181, 175, 749, 1335, 1151, 2131, 12467, 15811}},
+{3161, 15, 11761, {1, 1, 1, 9, 27, 39, 11, 1, 443, 677, 777, 1857, 7459, 3177, 3875}},
+{3162, 15, 11764, {1, 1, 7, 7, 17, 3, 23, 161, 105, 603, 1991, 3845, 465, 11467, 2077}},
+{3163, 15, 11767, {1, 1, 3, 13, 5, 23, 39, 35, 399, 795, 265, 207, 1823, 15069, 31839}},
+{3164, 15, 11797, {1, 1, 1, 1, 29, 61, 89, 193, 41, 99, 315, 1021, 6109, 12507, 19973}},
+{3165, 15, 11804, {1, 1, 5, 3, 13, 57, 119, 251, 215, 695, 1521, 4081, 2481, 657, 855}},
+{3166, 15, 11808, {1, 1, 7, 3, 25, 5, 3, 133, 111, 385, 773, 1027, 4327, 3031, 3537}},
+{3167, 15, 11831, {1, 3, 7, 5, 5, 27, 43, 117, 479, 83, 1421, 2791, 6551, 6231, 10353}},
+{3168, 15, 11832, {1, 1, 1, 13, 3, 29, 35, 71, 85, 821, 1671, 3057, 797, 13683, 7025}},
+{3169, 15, 11849, {1, 3, 7, 1, 1, 47, 117, 233, 141, 993, 1381, 2551, 1031, 11765, 18429}},
+{3170, 15, 11855, {1, 3, 1, 3, 13, 3, 77, 29, 35, 807, 1109, 695, 5605, 5477, 449}},
+{3171, 15, 11863, {1, 1, 1, 15, 21, 37, 117, 105, 273, 311, 1287, 1415, 1221, 1847, 19487}},
+{3172, 15, 11880, {1, 3, 1, 11, 21, 61, 107, 225, 335, 501, 1995, 2399, 5475, 12613, 18877}},
+{3173, 15, 11883, {1, 3, 3, 1, 31, 41, 27, 205, 103, 837, 639, 2007, 2759, 12471, 1457}},
+{3174, 15, 11885, {1, 1, 7, 13, 29, 39, 71, 245, 105, 235, 1277, 1515, 6129, 15947, 26653}},
+{3175, 15, 11898, {1, 1, 7, 5, 7, 13, 87, 251, 315, 1017, 587, 2917, 5911, 2919, 29715}},
+{3176, 15, 11916, {1, 1, 1, 3, 7, 19, 81, 243, 177, 917, 2023, 2365, 7465, 4901, 29841}},
+{3177, 15, 11924, {1, 3, 5, 15, 1, 31, 15, 147, 285, 1003, 1757, 47, 6925, 1197, 19633}},
+{3178, 15, 11928, {1, 1, 5, 7, 27, 25, 47, 209, 85, 403, 1399, 2331, 3663, 595, 13407}},
+{3179, 15, 11947, {1, 3, 5, 9, 7, 25, 7, 139, 389, 817, 1153, 1421, 5735, 9577, 10269}},
+{3180, 15, 11955, {1, 1, 1, 9, 5, 61, 49, 117, 389, 541, 433, 1405, 2575, 223, 7265}},
+{3181, 15, 11961, {1, 1, 5, 7, 15, 1, 81, 207, 435, 843, 835, 3797, 7637, 5333, 31115}},
+{3182, 15, 11962, {1, 3, 7, 11, 13, 3, 47, 249, 301, 715, 2015, 3049, 8155, 10989, 26051}},
+{3183, 15, 11982, {1, 1, 7, 7, 3, 33, 119, 113, 381, 575, 367, 41, 3317, 11727, 4351}},
+{3184, 15, 11990, {1, 3, 3, 13, 9, 3, 51, 37, 173, 137, 533, 1827, 631, 10047, 6267}},
+{3185, 15, 12010, {1, 3, 3, 11, 17, 39, 61, 245, 13, 139, 1281, 1319, 1233, 13629, 32269}},
+{3186, 15, 12018, {1, 1, 1, 7, 15, 17, 91, 109, 163, 609, 11, 3251, 7653, 14035, 31755}},
+{3187, 15, 12027, {1, 3, 3, 15, 13, 21, 55, 231, 385, 133, 1833, 2637, 6935, 14303, 26745}},
+{3188, 15, 12029, {1, 1, 1, 7, 17, 41, 125, 141, 89, 823, 1411, 3637, 6211, 13323, 6111}},
+{3189, 15, 12035, {1, 1, 1, 11, 1, 21, 9, 43, 97, 685, 1223, 1491, 121, 1793, 2397}},
+{3190, 15, 12055, {1, 3, 5, 5, 17, 17, 5, 223, 129, 865, 1839, 1137, 6391, 4377, 9233}},
+{3191, 15, 12062, {1, 3, 7, 15, 21, 55, 5, 77, 341, 637, 1853, 1435, 1195, 9283, 21257}},
+{3192, 15, 12068, {1, 3, 5, 1, 9, 49, 43, 211, 127, 655, 1397, 1235, 5279, 2351, 24229}},
+{3193, 15, 12071, {1, 3, 5, 3, 25, 29, 13, 229, 25, 675, 837, 2753, 2125, 9863, 11293}},
+{3194, 15, 12072, {1, 3, 5, 7, 23, 43, 127, 1, 163, 237, 337, 3019, 7747, 16227, 2881}},
+{3195, 15, 12086, {1, 3, 5, 5, 25, 9, 43, 171, 421, 521, 1885, 337, 7873, 6347, 13181}},
+{3196, 15, 12097, {1, 3, 5, 5, 7, 47, 107, 173, 163, 191, 625, 3389, 2833, 7945, 24787}},
+{3197, 15, 12098, {1, 1, 7, 3, 27, 57, 27, 209, 253, 815, 301, 1633, 3945, 5051, 28851}},
+{3198, 15, 12100, {1, 3, 7, 9, 9, 51, 103, 213, 437, 189, 1857, 1331, 5551, 10641, 27405}},
+{3199, 15, 12112, {1, 1, 5, 5, 15, 1, 25, 105, 117, 347, 161, 3369, 3589, 12903, 23559}},
+{3200, 15, 12118, {1, 1, 1, 5, 3, 61, 93, 51, 81, 281, 1383, 745, 4137, 2005, 3635}},
+{3201, 15, 12133, {1, 3, 7, 5, 13, 57, 111, 211, 303, 477, 359, 4019, 6779, 5129, 22035}},
+{3202, 15, 12134, {1, 1, 1, 7, 17, 29, 113, 113, 201, 531, 749, 739, 2879, 3315, 18733}},
+{3203, 15, 12137, {1, 3, 7, 13, 21, 55, 21, 183, 359, 75, 377, 2211, 4281, 14317, 28307}},
+{3204, 15, 12161, {1, 3, 7, 1, 21, 1, 49, 213, 317, 75, 113, 1741, 7963, 12785, 11571}},
+{3205, 15, 12162, {1, 3, 7, 9, 11, 31, 29, 101, 261, 141, 715, 2727, 8187, 2075, 32433}},
+{3206, 15, 12171, {1, 3, 7, 3, 23, 9, 17, 143, 385, 211, 593, 241, 6567, 10777, 6677}},
+{3207, 15, 12174, {1, 1, 3, 15, 3, 17, 117, 99, 91, 793, 989, 2421, 5643, 16103, 9759}},
+{3208, 15, 12185, {1, 3, 7, 11, 23, 43, 107, 35, 421, 431, 743, 853, 7939, 12169, 4199}},
+{3209, 15, 12204, {1, 1, 1, 11, 21, 53, 17, 203, 123, 395, 59, 929, 255, 7585, 10945}},
+{3210, 15, 12212, {1, 3, 3, 15, 17, 57, 57, 133, 67, 71, 1685, 903, 4079, 15423, 26495}},
+{3211, 15, 12215, {1, 1, 1, 15, 3, 47, 95, 39, 405, 407, 1557, 3001, 6225, 15187, 5663}},
+{3212, 15, 12216, {1, 3, 5, 5, 13, 47, 33, 61, 375, 1023, 1981, 2773, 2375, 11321, 17731}},
+{3213, 15, 12253, {1, 3, 5, 9, 17, 59, 117, 95, 493, 149, 1269, 2865, 369, 2109, 24601}},
+{3214, 15, 12260, {1, 3, 5, 13, 17, 63, 67, 247, 95, 721, 67, 305, 6179, 15399, 32559}},
+{3215, 15, 12277, {1, 1, 5, 1, 3, 21, 41, 15, 453, 475, 2017, 3193, 5903, 897, 4237}},
+{3216, 15, 12289, {1, 1, 5, 3, 15, 41, 1, 141, 441, 575, 155, 3791, 7711, 11231, 24611}},
+{3217, 15, 12295, {1, 3, 7, 1, 17, 53, 27, 169, 31, 437, 963, 1793, 7777, 1917, 29311}},
+{3218, 15, 12314, {1, 3, 3, 13, 9, 27, 77, 87, 329, 885, 749, 1713, 6013, 6921, 629}},
+{3219, 15, 12323, {1, 3, 5, 13, 3, 7, 53, 27, 353, 267, 925, 2141, 439, 15175, 30851}},
+{3220, 15, 12325, {1, 3, 3, 13, 17, 57, 35, 101, 265, 901, 1825, 2159, 6149, 5967, 24023}},
+{3221, 15, 12335, {1, 1, 5, 11, 13, 51, 99, 111, 193, 415, 1541, 2929, 5045, 3147, 12587}},
+{3222, 15, 12349, {1, 3, 7, 11, 15, 9, 33, 17, 511, 815, 299, 1077, 6171, 10451, 15039}},
+{3223, 15, 12358, {1, 1, 1, 15, 25, 63, 51, 137, 449, 951, 1051, 1101, 4725, 2463, 7355}},
+{3224, 15, 12372, {1, 1, 1, 7, 27, 63, 29, 179, 317, 521, 1459, 827, 6599, 13459, 15439}},
+{3225, 15, 12376, {1, 3, 3, 15, 17, 31, 37, 191, 229, 245, 181, 941, 5761, 1849, 31599}},
+{3226, 15, 12379, {1, 1, 1, 9, 27, 45, 67, 239, 481, 615, 1667, 3751, 8141, 10013, 2125}},
+{3227, 15, 12386, {1, 1, 1, 1, 13, 51, 117, 135, 73, 151, 1291, 2541, 1411, 3767, 26949}},
+{3228, 15, 12395, {1, 3, 1, 9, 7, 11, 21, 187, 243, 857, 1951, 865, 7273, 2041, 8155}},
+{3229, 15, 12416, {1, 1, 3, 3, 19, 33, 89, 115, 455, 137, 707, 1867, 4221, 2433, 9119}},
+{3230, 15, 12421, {1, 1, 3, 11, 5, 3, 121, 1, 71, 951, 603, 3873, 723, 3285, 19289}},
+{3231, 15, 12440, {1, 3, 7, 15, 21, 1, 117, 17, 455, 519, 731, 3003, 5741, 9557, 29163}},
+{3232, 15, 12452, {1, 1, 3, 13, 25, 5, 43, 147, 209, 895, 255, 1231, 241, 487, 15593}},
+{3233, 15, 12455, {1, 1, 3, 13, 7, 1, 89, 187, 217, 927, 2029, 3521, 2777, 8103, 22819}},
+{3234, 15, 12456, {1, 1, 7, 11, 7, 33, 3, 73, 5, 489, 227, 2259, 7031, 6425, 26135}},
+{3235, 15, 12462, {1, 3, 3, 7, 31, 19, 97, 201, 455, 819, 945, 2771, 8083, 8711, 2835}},
+{3236, 15, 12467, {1, 1, 1, 5, 15, 45, 43, 157, 245, 967, 877, 2289, 4499, 9891, 18827}},
+{3237, 15, 12479, {1, 3, 1, 7, 21, 59, 123, 63, 231, 485, 1781, 1211, 4597, 5269, 1607}},
+{3238, 15, 12505, {1, 1, 1, 13, 23, 39, 105, 55, 249, 991, 1625, 3089, 3825, 4275, 29139}},
+{3239, 15, 12521, {1, 3, 3, 1, 29, 29, 55, 169, 13, 895, 1355, 1101, 6063, 12935, 23215}},
+{3240, 15, 12535, {1, 1, 5, 5, 31, 49, 99, 137, 209, 1017, 1179, 3931, 637, 14131, 19285}},
+{3241, 15, 12547, {1, 1, 1, 1, 3, 11, 119, 11, 215, 337, 243, 3883, 3807, 7335, 11901}},
+{3242, 15, 12556, {1, 3, 7, 3, 7, 27, 71, 225, 219, 367, 1213, 2739, 1185, 10175, 21313}},
+{3243, 15, 12561, {1, 3, 7, 13, 7, 49, 23, 223, 61, 1011, 797, 1335, 6711, 5961, 5605}},
+{3244, 15, 12568, {1, 3, 3, 11, 19, 37, 1, 149, 39, 661, 929, 2125, 2299, 5181, 28083}},
+{3245, 15, 12578, {1, 3, 3, 13, 13, 9, 67, 21, 463, 279, 529, 523, 6705, 11011, 31695}},
+{3246, 15, 12583, {1, 3, 1, 5, 13, 1, 123, 3, 291, 625, 1949, 2713, 5917, 10343, 13627}},
+{3247, 15, 12595, {1, 1, 3, 9, 27, 41, 3, 207, 103, 265, 811, 549, 6109, 313, 8889}},
+{3248, 15, 12604, {1, 3, 3, 13, 23, 43, 99, 33, 279, 463, 955, 793, 4113, 10615, 16957}},
+{3249, 15, 12610, {1, 1, 5, 7, 11, 49, 79, 45, 17, 937, 359, 1037, 1099, 3003, 31561}},
+{3250, 15, 12621, {1, 1, 1, 7, 3, 45, 111, 35, 109, 983, 53, 4057, 7349, 3599, 2209}},
+{3251, 15, 12622, {1, 3, 7, 11, 9, 43, 27, 9, 85, 529, 1497, 347, 759, 12449, 11373}},
+{3252, 15, 12624, {1, 1, 3, 9, 17, 1, 49, 31, 367, 813, 1385, 2025, 773, 4679, 4543}},
+{3253, 15, 12629, {1, 1, 5, 15, 15, 9, 43, 97, 239, 995, 1037, 841, 4167, 12113, 23765}},
+{3254, 15, 12630, {1, 3, 5, 9, 29, 53, 123, 49, 221, 113, 1157, 73, 6087, 1363, 11029}},
+{3255, 15, 12639, {1, 3, 1, 13, 3, 15, 69, 199, 279, 919, 5, 161, 4817, 15031, 121}},
+{3256, 15, 12640, {1, 3, 1, 9, 3, 31, 117, 77, 393, 241, 645, 3181, 1067, 15879, 2037}},
+{3257, 15, 12650, {1, 3, 3, 15, 3, 63, 57, 33, 117, 789, 941, 1301, 5865, 12693, 3523}},
+{3258, 15, 12679, {1, 1, 5, 13, 3, 61, 51, 151, 175, 305, 95, 1557, 6567, 7841, 13903}},
+{3259, 15, 12680, {1, 3, 3, 5, 15, 25, 127, 79, 245, 767, 645, 3933, 1357, 12579, 4067}},
+{3260, 15, 12698, {1, 3, 5, 11, 21, 31, 13, 251, 127, 231, 1795, 2627, 1191, 3363, 23543}},
+{3261, 15, 12716, {1, 1, 3, 5, 7, 49, 121, 57, 131, 481, 1879, 525, 5225, 337, 1957}},
+{3262, 15, 12721, {1, 1, 5, 13, 9, 55, 27, 37, 211, 125, 119, 3373, 251, 12357, 13975}},
+{3263, 15, 12722, {1, 3, 3, 15, 1, 51, 91, 119, 233, 993, 203, 1635, 1167, 6327, 29119}},
+{3264, 15, 12731, {1, 1, 7, 1, 13, 5, 23, 253, 121, 989, 1105, 3321, 3221, 6073, 21185}},
+{3265, 15, 12742, {1, 1, 3, 15, 13, 49, 121, 247, 247, 133, 485, 1067, 7875, 411, 7647}},
+{3266, 15, 12745, {1, 3, 7, 13, 31, 37, 127, 241, 145, 133, 53, 267, 2029, 3703, 16123}},
+{3267, 15, 12751, {1, 3, 1, 15, 15, 9, 15, 89, 35, 367, 401, 61, 1953, 7873, 17861}},
+{3268, 15, 12759, {1, 1, 1, 1, 1, 41, 71, 249, 213, 779, 1385, 1767, 999, 15151, 16647}},
+{3269, 15, 12763, {1, 3, 7, 13, 31, 23, 123, 235, 343, 949, 309, 3777, 3587, 853, 19779}},
+{3270, 15, 12769, {1, 1, 3, 13, 29, 35, 5, 37, 63, 757, 303, 1579, 3443, 243, 11873}},
+{3271, 15, 12781, {1, 3, 1, 9, 19, 49, 81, 53, 11, 901, 1857, 147, 3103, 14019, 21}},
+{3272, 15, 12793, {1, 3, 7, 13, 3, 39, 99, 99, 45, 91, 1567, 551, 3129, 4809, 29057}},
+{3273, 15, 12799, {1, 3, 7, 3, 3, 27, 17, 231, 377, 381, 1479, 2525, 2595, 2799, 25737}},
+{3274, 15, 12815, {1, 3, 5, 15, 15, 25, 103, 215, 301, 59, 1417, 981, 7579, 12731, 22329}},
+{3275, 15, 12824, {1, 1, 1, 13, 5, 31, 61, 31, 349, 925, 1301, 685, 435, 11567, 10715}},
+{3276, 15, 12836, {1, 1, 7, 9, 19, 57, 109, 1, 37, 377, 1015, 2273, 6741, 3191, 15949}},
+{3277, 15, 12845, {1, 3, 3, 13, 3, 23, 103, 127, 11, 59, 1847, 1175, 425, 3423, 20643}},
+{3278, 15, 12853, {1, 3, 3, 7, 3, 11, 105, 141, 55, 217, 1427, 477, 667, 9403, 11905}},
+{3279, 15, 12854, {1, 3, 3, 5, 3, 27, 11, 187, 495, 907, 1925, 445, 6639, 8159, 15225}},
+{3280, 15, 12857, {1, 3, 1, 5, 27, 31, 77, 213, 73, 343, 1123, 3609, 2431, 15329, 32165}},
+{3281, 15, 12866, {1, 1, 7, 5, 1, 11, 105, 139, 485, 1007, 709, 3509, 5231, 11717, 31433}},
+{3282, 15, 12872, {1, 1, 3, 15, 23, 49, 95, 169, 399, 1019, 19, 2013, 5311, 7951, 22609}},
+{3283, 15, 12875, {1, 3, 1, 7, 13, 3, 29, 203, 209, 701, 1791, 2615, 5351, 4237, 12565}},
+{3284, 15, 12878, {1, 3, 1, 15, 27, 11, 91, 31, 205, 205, 1683, 901, 5129, 6049, 11865}},
+{3285, 15, 12880, {1, 1, 7, 7, 27, 59, 21, 3, 209, 79, 769, 4013, 2041, 2645, 11561}},
+{3286, 15, 12885, {1, 3, 7, 11, 5, 45, 39, 243, 185, 871, 795, 1845, 8043, 6285, 20991}},
+{3287, 15, 12901, {1, 1, 5, 7, 13, 7, 15, 165, 349, 179, 789, 1269, 3787, 5429, 26567}},
+{3288, 15, 12902, {1, 3, 3, 13, 31, 23, 75, 41, 177, 735, 1889, 4039, 3519, 15003, 965}},
+{3289, 15, 12920, {1, 3, 1, 7, 15, 57, 15, 139, 27, 469, 1003, 691, 7893, 9643, 30983}},
+{3290, 15, 12926, {1, 3, 1, 13, 23, 27, 3, 237, 233, 875, 99, 883, 6167, 5463, 6245}},
+{3291, 15, 12929, {1, 1, 5, 13, 25, 57, 79, 51, 147, 619, 1147, 279, 6583, 1939, 477}},
+{3292, 15, 12939, {1, 3, 5, 5, 31, 61, 125, 163, 213, 699, 583, 3865, 615, 9707, 11651}},
+{3293, 15, 12941, {1, 1, 5, 1, 5, 21, 93, 239, 31, 641, 777, 27, 5247, 8993, 21053}},
+{3294, 15, 12950, {1, 3, 7, 9, 1, 13, 61, 57, 503, 453, 83, 3271, 2845, 1121, 18639}},
+{3295, 15, 12953, {1, 1, 7, 5, 29, 53, 13, 219, 379, 441, 821, 3179, 4877, 2535, 7557}},
+{3296, 15, 12992, {1, 1, 7, 13, 9, 53, 17, 183, 265, 393, 587, 2753, 6453, 7135, 24737}},
+{3297, 15, 13002, {1, 1, 1, 13, 11, 23, 73, 109, 393, 1013, 559, 755, 7291, 6631, 26509}},
+{3298, 15, 13010, {1, 3, 1, 5, 5, 15, 107, 103, 355, 307, 1559, 837, 5413, 5285, 17489}},
+{3299, 15, 13058, {1, 1, 5, 7, 17, 21, 21, 23, 109, 709, 1947, 3585, 3629, 4669, 949}},
+{3300, 15, 13072, {1, 3, 7, 1, 9, 33, 85, 147, 467, 259, 1913, 199, 7399, 9551, 22387}},
+{3301, 15, 13084, {1, 3, 5, 11, 15, 53, 23, 41, 249, 515, 1161, 2467, 1299, 7449, 2613}},
+{3302, 15, 13087, {1, 1, 5, 5, 5, 29, 91, 139, 487, 545, 321, 3035, 4545, 6747, 21673}},
+{3303, 15, 13091, {1, 1, 3, 13, 23, 49, 95, 103, 25, 119, 469, 2515, 2551, 841, 25089}},
+{3304, 15, 13097, {1, 1, 5, 7, 11, 31, 31, 197, 245, 715, 257, 4043, 8099, 11531, 5617}},
+{3305, 15, 13108, {1, 1, 3, 3, 19, 7, 9, 179, 103, 995, 191, 179, 3843, 5215, 27639}},
+{3306, 15, 13123, {1, 3, 1, 7, 23, 59, 25, 65, 399, 211, 1453, 3511, 7203, 16015, 32197}},
+{3307, 15, 13149, {1, 3, 3, 5, 9, 35, 109, 67, 197, 449, 643, 519, 5751, 15551, 11331}},
+{3308, 15, 13150, {1, 3, 5, 3, 1, 17, 53, 201, 265, 351, 467, 911, 1117, 7183, 20371}},
+{3309, 15, 13163, {1, 1, 7, 7, 27, 17, 93, 81, 227, 619, 1191, 735, 815, 12615, 2719}},
+{3310, 15, 13166, {1, 3, 1, 15, 19, 3, 83, 75, 343, 297, 1019, 3469, 4383, 13299, 29755}},
+{3311, 15, 13178, {1, 1, 5, 3, 13, 55, 119, 169, 85, 595, 299, 2469, 5625, 2877, 16117}},
+{3312, 15, 13180, {1, 1, 3, 5, 15, 17, 61, 161, 47, 393, 143, 867, 5517, 9495, 12795}},
+{3313, 15, 13184, {1, 3, 5, 1, 27, 31, 113, 125, 251, 687, 969, 1473, 2245, 6355, 13655}},
+{3314, 15, 13204, {1, 1, 1, 5, 5, 37, 29, 133, 443, 899, 277, 2353, 7223, 4459, 19159}},
+{3315, 15, 13238, {1, 1, 3, 9, 19, 27, 53, 145, 195, 167, 2045, 447, 1803, 1895, 8431}},
+{3316, 15, 13242, {1, 1, 3, 9, 5, 27, 91, 147, 233, 451, 475, 27, 4629, 16181, 16437}},
+{3317, 15, 13249, {1, 3, 5, 3, 29, 17, 53, 167, 433, 689, 1131, 2985, 1553, 11697, 6993}},
+{3318, 15, 13255, {1, 3, 3, 13, 21, 43, 69, 229, 399, 525, 179, 237, 7017, 5703, 17653}},
+{3319, 15, 13269, {1, 1, 3, 15, 13, 39, 75, 163, 229, 875, 197, 477, 3667, 15501, 15801}},
+{3320, 15, 13270, {1, 1, 7, 15, 15, 51, 81, 187, 487, 673, 865, 1915, 1009, 5935, 8097}},
+{3321, 15, 13274, {1, 3, 5, 5, 7, 3, 63, 77, 495, 815, 391, 2321, 1007, 15661, 30715}},
+{3322, 15, 13285, {1, 1, 7, 3, 17, 25, 83, 173, 173, 911, 1373, 2957, 4549, 15977, 17695}},
+{3323, 15, 13289, {1, 1, 7, 13, 13, 23, 77, 147, 497, 1003, 1687, 1795, 1393, 1881, 8479}},
+{3324, 15, 13298, {1, 3, 7, 11, 27, 43, 97, 25, 61, 457, 203, 2573, 5943, 15021, 4003}},
+{3325, 15, 13307, {1, 3, 3, 13, 9, 37, 37, 25, 219, 889, 1535, 2791, 4531, 13679, 12663}},
+{3326, 15, 13312, {1, 1, 3, 1, 17, 7, 51, 123, 89, 887, 1467, 1645, 3767, 6383, 30837}},
+{3327, 15, 13335, {1, 3, 3, 1, 21, 47, 5, 151, 83, 257, 569, 2711, 637, 12569, 16893}},
+{3328, 15, 13345, {1, 3, 7, 1, 31, 37, 73, 3, 115, 919, 1817, 2483, 4811, 15245, 4375}},
+{3329, 15, 13357, {1, 1, 1, 5, 1, 39, 39, 231, 9, 733, 455, 3383, 4777, 7235, 12631}},
+{3330, 15, 13366, {1, 1, 7, 9, 13, 25, 55, 25, 73, 59, 1699, 929, 755, 1279, 5583}},
+{3331, 15, 13372, {1, 3, 5, 3, 9, 49, 79, 55, 479, 179, 1159, 4079, 3503, 11603, 12361}},
+{3332, 15, 13380, {1, 1, 5, 9, 21, 45, 31, 163, 377, 817, 219, 147, 2581, 12769, 30783}},
+{3333, 15, 13384, {1, 3, 1, 7, 15, 27, 39, 189, 493, 259, 1663, 1213, 961, 11089, 16079}},
+{3334, 15, 13395, {1, 1, 5, 9, 5, 41, 13, 153, 313, 337, 1027, 1267, 4249, 13071, 27043}},
+{3335, 15, 13407, {1, 3, 7, 3, 13, 11, 23, 255, 51, 527, 317, 3217, 5037, 12723, 17411}},
+{3336, 15, 13408, {1, 1, 5, 1, 25, 57, 83, 97, 233, 513, 1283, 2675, 4111, 4111, 32141}},
+{3337, 15, 13413, {1, 3, 3, 15, 25, 33, 103, 81, 155, 189, 139, 1179, 2691, 15119, 13959}},
+{3338, 15, 13414, {1, 3, 3, 1, 25, 55, 67, 19, 19, 9, 437, 579, 4273, 10733, 7125}},
+{3339, 15, 13417, {1, 1, 1, 7, 23, 41, 47, 5, 435, 749, 595, 199, 3941, 7199, 4795}},
+{3340, 15, 13437, {1, 3, 1, 15, 5, 49, 35, 9, 199, 703, 1769, 3269, 5689, 13063, 22771}},
+{3341, 15, 13441, {1, 1, 5, 5, 21, 55, 125, 55, 63, 149, 1167, 3577, 1051, 3921, 20545}},
+{3342, 15, 13447, {1, 3, 7, 13, 29, 53, 107, 193, 163, 339, 1335, 1573, 5809, 5681, 29487}},
+{3343, 15, 13456, {1, 1, 1, 9, 17, 9, 91, 177, 211, 453, 1807, 1881, 6051, 225, 6021}},
+{3344, 15, 13459, {1, 1, 1, 13, 15, 1, 29, 43, 181, 105, 1945, 2313, 6429, 2901, 6221}},
+{3345, 15, 13461, {1, 3, 5, 11, 29, 55, 115, 115, 187, 1013, 697, 1885, 121, 12387, 32443}},
+{3346, 15, 13466, {1, 1, 1, 7, 19, 51, 21, 107, 55, 125, 1655, 2281, 3293, 15749, 27521}},
+{3347, 15, 13484, {1, 1, 7, 9, 19, 9, 81, 93, 139, 401, 193, 73, 5159, 9323, 6019}},
+{3348, 15, 13487, {1, 1, 7, 9, 15, 51, 115, 69, 247, 599, 1163, 2251, 1211, 8827, 15581}},
+{3349, 15, 13489, {1, 1, 7, 9, 5, 39, 75, 185, 321, 911, 849, 843, 6791, 10407, 10513}},
+{3350, 15, 13492, {1, 1, 5, 5, 15, 9, 21, 47, 459, 681, 2001, 1545, 5939, 7073, 29043}},
+{3351, 15, 13496, {1, 3, 1, 11, 13, 25, 53, 97, 487, 797, 567, 3757, 5597, 6313, 18531}},
+{3352, 15, 13510, {1, 1, 3, 3, 29, 55, 11, 219, 325, 591, 2015, 383, 2595, 11855, 22501}},
+{3353, 15, 13531, {1, 1, 1, 5, 15, 57, 33, 125, 323, 749, 1843, 4019, 2075, 6673, 6957}},
+{3354, 15, 13538, {1, 1, 5, 7, 19, 7, 47, 239, 51, 107, 1081, 467, 5493, 7617, 10355}},
+{3355, 15, 13543, {1, 3, 1, 1, 11, 3, 67, 199, 175, 421, 935, 309, 4449, 6363, 9183}},
+{3356, 15, 13547, {1, 1, 1, 7, 9, 33, 3, 219, 481, 513, 417, 1267, 2863, 765, 18431}},
+{3357, 15, 13572, {1, 3, 1, 1, 19, 1, 89, 109, 415, 105, 487, 3241, 7465, 9233, 16307}},
+{3358, 15, 13581, {1, 1, 3, 13, 9, 43, 25, 231, 383, 789, 1855, 691, 3465, 2387, 11715}},
+{3359, 15, 13590, {1, 3, 3, 3, 13, 39, 63, 107, 33, 265, 437, 117, 3179, 5543, 28179}},
+{3360, 15, 13605, {1, 3, 3, 13, 21, 5, 31, 111, 321, 425, 253, 3501, 3209, 15429, 18383}},
+{3361, 15, 13612, {1, 3, 5, 9, 1, 27, 117, 187, 433, 459, 1999, 1069, 4857, 8591, 26343}},
+{3362, 15, 13624, {1, 1, 7, 3, 15, 43, 11, 193, 391, 341, 1203, 1259, 7265, 1783, 13161}},
+{3363, 15, 13630, {1, 1, 7, 1, 5, 15, 45, 143, 193, 985, 1105, 3483, 2421, 9687, 22347}},
+{3364, 15, 13632, {1, 3, 7, 13, 21, 17, 79, 231, 487, 663, 1101, 1025, 5779, 14681, 29181}},
+{3365, 15, 13638, {1, 1, 3, 9, 15, 19, 55, 219, 27, 963, 1513, 1017, 3907, 12279, 32655}},
+{3366, 15, 13661, {1, 3, 7, 3, 31, 27, 17, 1, 51, 861, 529, 1225, 6395, 15787, 5231}},
+{3367, 15, 13665, {1, 3, 3, 11, 27, 7, 101, 143, 21, 191, 1437, 2393, 4097, 14319, 6977}},
+{3368, 15, 13668, {1, 3, 3, 3, 25, 35, 105, 141, 433, 269, 1469, 2939, 5387, 7373, 7863}},
+{3369, 15, 13686, {1, 3, 7, 5, 5, 21, 23, 11, 217, 357, 1847, 101, 1161, 5297, 14879}},
+{3370, 15, 13699, {1, 3, 1, 3, 25, 23, 81, 217, 505, 161, 1667, 1343, 1751, 2463, 26431}},
+{3371, 15, 13701, {1, 1, 3, 1, 17, 51, 125, 205, 385, 351, 731, 2911, 2749, 2689, 27031}},
+{3372, 15, 13708, {1, 1, 5, 5, 5, 17, 31, 171, 477, 671, 167, 1797, 8047, 10123, 4325}},
+{3373, 15, 13716, {1, 1, 7, 1, 11, 23, 123, 161, 99, 1007, 765, 1965, 5395, 16193, 17751}},
+{3374, 15, 13725, {1, 3, 1, 9, 13, 11, 111, 217, 31, 753, 377, 2267, 7893, 7195, 24999}},
+{3375, 15, 13730, {1, 3, 1, 9, 21, 53, 127, 121, 151, 395, 1447, 1411, 5179, 12043, 27607}},
+{3376, 15, 13742, {1, 1, 5, 3, 11, 37, 97, 139, 113, 835, 229, 3741, 827, 5527, 5779}},
+{3377, 15, 13747, {1, 1, 7, 7, 27, 55, 11, 55, 429, 269, 1179, 233, 1053, 10225, 16703}},
+{3378, 15, 13749, {1, 1, 1, 3, 15, 9, 67, 119, 95, 753, 511, 2507, 3953, 6403, 27635}},
+{3379, 15, 13753, {1, 3, 3, 7, 27, 57, 25, 27, 249, 515, 193, 4043, 2017, 751, 10949}},
+{3380, 15, 13754, {1, 3, 1, 9, 31, 57, 67, 21, 177, 573, 1835, 2015, 6201, 2383, 31087}},
+{3381, 15, 13771, {1, 1, 5, 1, 19, 3, 89, 243, 69, 387, 1905, 3465, 2775, 7713, 30081}},
+{3382, 15, 13773, {1, 1, 3, 3, 9, 59, 15, 89, 85, 605, 881, 263, 2551, 797, 16541}},
+{3383, 15, 13782, {1, 3, 7, 11, 25, 41, 59, 139, 405, 571, 1147, 2963, 4175, 12901, 6309}},
+{3384, 15, 13785, {1, 3, 1, 5, 29, 29, 11, 243, 183, 281, 807, 1, 7079, 10079, 13865}},
+{3385, 15, 13798, {1, 3, 7, 5, 5, 1, 89, 55, 423, 157, 675, 1849, 241, 6467, 15459}},
+{3386, 15, 13802, {1, 1, 7, 11, 15, 63, 89, 109, 501, 549, 317, 3043, 1151, 3895, 19851}},
+{3387, 15, 13809, {1, 3, 1, 15, 7, 23, 97, 97, 225, 737, 1117, 3325, 209, 14169, 10813}},
+{3388, 15, 13828, {1, 3, 7, 13, 13, 39, 91, 153, 395, 879, 1041, 3753, 5577, 1985, 25247}},
+{3389, 15, 13832, {1, 1, 1, 3, 17, 15, 113, 143, 101, 901, 1119, 1819, 3577, 3441, 31511}},
+{3390, 15, 13840, {1, 3, 1, 11, 15, 27, 21, 37, 287, 121, 451, 1353, 2173, 299, 18791}},
+{3391, 15, 13850, {1, 3, 3, 5, 23, 1, 49, 145, 315, 769, 99, 1385, 5961, 9121, 1465}},
+{3392, 15, 13861, {1, 3, 3, 13, 21, 39, 39, 233, 271, 113, 615, 2257, 3765, 5921, 313}},
+{3393, 15, 13874, {1, 3, 7, 7, 25, 45, 11, 237, 83, 203, 929, 1819, 2679, 11583, 30091}},
+{3394, 15, 13876, {1, 1, 1, 7, 21, 63, 85, 251, 133, 991, 1515, 2547, 6051, 7279, 3569}},
+{3395, 15, 13886, {1, 3, 7, 15, 11, 19, 87, 17, 313, 283, 1021, 2743, 4855, 13741, 17955}},
+{3396, 15, 13897, {1, 1, 7, 13, 29, 13, 61, 93, 81, 91, 995, 907, 4847, 2599, 20041}},
+{3397, 15, 13900, {1, 1, 3, 11, 13, 45, 103, 33, 243, 109, 2029, 121, 231, 16179, 13741}},
+{3398, 15, 13915, {1, 3, 5, 9, 9, 5, 73, 225, 199, 723, 611, 1909, 2345, 10257, 9909}},
+{3399, 15, 13927, {1, 1, 3, 11, 7, 5, 33, 89, 431, 899, 803, 3173, 6131, 16097, 20561}},
+{3400, 15, 13951, {1, 3, 3, 7, 7, 47, 23, 47, 411, 69, 239, 661, 5591, 10457, 24245}},
+{3401, 15, 13955, {1, 1, 5, 15, 25, 35, 87, 23, 115, 939, 1579, 119, 4001, 13791, 9729}},
+{3402, 15, 13962, {1, 3, 5, 11, 25, 45, 29, 195, 369, 237, 735, 155, 123, 4415, 32255}},
+{3403, 15, 13969, {1, 3, 3, 9, 13, 53, 15, 77, 313, 75, 529, 925, 5679, 14585, 19889}},
+{3404, 15, 13979, {1, 1, 7, 15, 15, 27, 105, 13, 31, 669, 563, 1809, 4321, 7797, 4177}},
+{3405, 15, 13988, {1, 1, 5, 9, 3, 29, 111, 177, 33, 235, 1951, 1561, 141, 4803, 16327}},
+{3406, 15, 13998, {1, 1, 1, 7, 9, 41, 1, 149, 95, 933, 115, 1619, 771, 8189, 8781}},
+{3407, 15, 14000, {1, 1, 5, 3, 13, 41, 33, 159, 355, 159, 1243, 1439, 6571, 14397, 31321}},
+{3408, 15, 14005, {1, 1, 7, 11, 9, 15, 91, 145, 457, 255, 1449, 611, 1449, 2521, 28949}},
+{3409, 15, 14027, {1, 3, 7, 5, 27, 57, 35, 99, 447, 287, 743, 1163, 4379, 7361, 3831}},
+{3410, 15, 14037, {1, 3, 3, 7, 15, 53, 41, 83, 133, 571, 1739, 531, 2921, 11527, 21941}},
+{3411, 15, 14051, {1, 1, 1, 13, 9, 27, 39, 113, 429, 447, 595, 3171, 5245, 4095, 14847}},
+{3412, 15, 14054, {1, 1, 3, 7, 19, 19, 21, 101, 489, 1011, 265, 3899, 3225, 11701, 5193}},
+{3413, 15, 14060, {1, 3, 7, 3, 15, 25, 103, 213, 441, 215, 1483, 263, 3561, 7915, 7969}},
+{3414, 15, 14063, {1, 3, 3, 3, 11, 47, 97, 29, 489, 867, 1347, 2155, 4871, 8001, 18305}},
+{3415, 15, 14071, {1, 3, 1, 9, 25, 15, 61, 17, 343, 775, 1765, 3803, 4577, 8437, 12605}},
+{3416, 15, 14078, {1, 1, 5, 3, 11, 39, 69, 23, 23, 65, 1967, 2429, 1703, 6671, 14981}},
+{3417, 15, 14080, {1, 1, 5, 15, 23, 59, 125, 51, 225, 439, 2019, 2589, 7781, 13111, 2911}},
+{3418, 15, 14085, {1, 1, 1, 3, 1, 31, 37, 245, 203, 305, 821, 367, 5211, 9791, 21777}},
+{3419, 15, 14086, {1, 1, 5, 9, 9, 31, 97, 25, 271, 83, 343, 2461, 1805, 14383, 10059}},
+{3420, 15, 14095, {1, 1, 5, 13, 15, 33, 127, 109, 137, 963, 961, 1647, 7881, 8133, 22359}},
+{3421, 15, 14138, {1, 1, 3, 7, 25, 31, 123, 241, 283, 1, 1781, 23, 971, 6485, 127}},
+{3422, 15, 14145, {1, 1, 5, 15, 15, 27, 25, 145, 395, 679, 979, 571, 1585, 14787, 7465}},
+{3423, 15, 14158, {1, 1, 5, 7, 13, 11, 7, 131, 511, 597, 379, 1513, 6267, 16039, 1503}},
+{3424, 15, 14166, {1, 1, 1, 13, 15, 49, 73, 217, 353, 577, 1913, 1127, 961, 11557, 24993}},
+{3425, 15, 14179, {1, 3, 3, 9, 7, 3, 105, 141, 377, 687, 1917, 485, 983, 11149, 23303}},
+{3426, 15, 14181, {1, 1, 3, 15, 11, 7, 117, 179, 505, 67, 1817, 913, 5757, 1981, 1637}},
+{3427, 15, 14188, {1, 1, 1, 7, 5, 29, 3, 43, 223, 295, 1895, 3425, 5355, 5155, 17197}},
+{3428, 15, 14193, {1, 1, 7, 9, 21, 59, 121, 245, 73, 233, 1527, 869, 4145, 7995, 6473}},
+{3429, 15, 14200, {1, 1, 5, 13, 17, 21, 89, 179, 495, 669, 453, 2603, 5969, 6161, 4743}},
+{3430, 15, 14203, {1, 1, 7, 11, 25, 21, 103, 131, 391, 249, 1633, 2603, 2207, 8987, 15487}},
+{3431, 15, 14215, {1, 3, 7, 9, 13, 45, 99, 251, 115, 597, 1505, 2421, 1231, 10015, 24295}},
+{3432, 15, 14224, {1, 1, 5, 5, 31, 49, 17, 67, 463, 813, 1491, 3309, 7881, 8109, 7289}},
+{3433, 15, 14230, {1, 3, 1, 15, 23, 35, 123, 21, 169, 499, 95, 603, 1829, 7865, 26313}},
+{3434, 15, 14233, {1, 1, 7, 1, 9, 29, 45, 65, 95, 97, 673, 3673, 2969, 2317, 22209}},
+{3435, 15, 14236, {1, 1, 3, 7, 29, 33, 121, 17, 331, 487, 1901, 1951, 5383, 9375, 4029}},
+{3436, 15, 14246, {1, 3, 7, 9, 25, 43, 91, 147, 141, 401, 1647, 2697, 4645, 7179, 31857}},
+{3437, 15, 14267, {1, 3, 5, 11, 9, 31, 127, 105, 39, 883, 1635, 919, 5069, 2875, 24519}},
+{3438, 15, 14282, {1, 1, 5, 9, 1, 63, 73, 135, 95, 503, 385, 3903, 545, 12635, 27569}},
+{3439, 15, 14287, {1, 1, 3, 11, 27, 31, 47, 173, 55, 339, 1255, 1947, 793, 14133, 13963}},
+{3440, 15, 14301, {1, 1, 3, 15, 17, 33, 113, 249, 401, 743, 1307, 3123, 627, 1253, 13285}},
+{3441, 15, 14323, {1, 1, 3, 1, 9, 7, 39, 65, 281, 107, 833, 193, 2987, 12267, 31335}},
+{3442, 15, 14325, {1, 1, 7, 3, 15, 21, 99, 211, 39, 179, 587, 1169, 6455, 8225, 2049}},
+{3443, 15, 14329, {1, 3, 5, 13, 5, 13, 123, 1, 223, 273, 731, 2967, 4793, 4229, 26031}},
+{3444, 15, 14339, {1, 1, 1, 1, 3, 17, 7, 23, 225, 757, 743, 1257, 2047, 12509, 25467}},
+{3445, 15, 14342, {1, 1, 7, 15, 29, 3, 15, 113, 227, 675, 1295, 2777, 2921, 5485, 2577}},
+{3446, 15, 14351, {1, 3, 7, 13, 19, 21, 85, 129, 45, 599, 317, 1513, 4953, 10383, 25253}},
+{3447, 15, 14356, {1, 1, 7, 11, 13, 47, 127, 67, 219, 131, 905, 2005, 851, 15243, 5777}},
+{3448, 15, 14359, {1, 1, 5, 3, 23, 57, 57, 189, 153, 37, 955, 2049, 1295, 15119, 27213}},
+{3449, 15, 14370, {1, 3, 7, 11, 13, 61, 3, 241, 269, 789, 1595, 2369, 4843, 11347, 21543}},
+{3450, 15, 14402, {1, 1, 5, 5, 25, 21, 19, 237, 3, 605, 1343, 3965, 3511, 7889, 27759}},
+{3451, 15, 14411, {1, 3, 1, 15, 21, 15, 123, 5, 345, 945, 283, 1313, 335, 2085, 19505}},
+{3452, 15, 14421, {1, 1, 3, 3, 5, 21, 123, 89, 67, 11, 1247, 1155, 287, 13455, 5693}},
+{3453, 15, 14431, {1, 3, 3, 13, 1, 53, 101, 27, 387, 379, 19, 751, 2445, 11737, 975}},
+{3454, 15, 14435, {1, 3, 3, 3, 9, 29, 81, 117, 443, 145, 1619, 1813, 8125, 5829, 28617}},
+{3455, 15, 14442, {1, 1, 5, 15, 27, 15, 83, 83, 61, 715, 1655, 1631, 3457, 2727, 2163}},
+{3456, 15, 14447, {1, 3, 1, 5, 11, 11, 121, 7, 135, 883, 927, 1817, 6839, 12361, 24119}},
+{3457, 15, 14456, {1, 3, 7, 11, 23, 59, 39, 165, 109, 355, 1303, 381, 5697, 275, 3771}},
+{3458, 15, 14459, {1, 3, 5, 11, 11, 5, 81, 157, 55, 435, 613, 127, 4087, 3791, 21627}},
+{3459, 15, 14472, {1, 3, 7, 15, 13, 37, 83, 195, 207, 771, 51, 3685, 6389, 1229, 11101}},
+{3460, 15, 14477, {1, 3, 7, 13, 31, 3, 9, 13, 487, 95, 77, 809, 5809, 12887, 29933}},
+{3461, 15, 14490, {1, 1, 3, 7, 25, 9, 13, 29, 353, 659, 1785, 3825, 3729, 13109, 12973}},
+{3462, 15, 14496, {1, 1, 1, 5, 21, 3, 97, 1, 245, 917, 29, 1429, 8141, 7569, 32493}},
+{3463, 15, 14501, {1, 3, 1, 9, 19, 13, 13, 109, 377, 1007, 1737, 1939, 1419, 1145, 5065}},
+{3464, 15, 14505, {1, 1, 7, 9, 27, 57, 53, 69, 423, 43, 1629, 1003, 1473, 10809, 5659}},
+{3465, 15, 14513, {1, 1, 1, 9, 1, 45, 11, 231, 351, 155, 663, 2783, 3491, 5725, 25207}},
+{3466, 15, 14520, {1, 1, 1, 3, 15, 25, 77, 89, 231, 813, 657, 2603, 4885, 1383, 14499}},
+{3467, 15, 14534, {1, 3, 5, 5, 9, 21, 101, 181, 449, 491, 737, 803, 659, 11771, 545}},
+{3468, 15, 14562, {1, 3, 7, 9, 7, 19, 27, 199, 265, 329, 1031, 1235, 3191, 10071, 16281}},
+{3469, 15, 14576, {1, 1, 7, 11, 27, 55, 3, 127, 503, 1003, 1041, 1953, 5835, 4851, 13485}},
+{3470, 15, 14579, {1, 1, 7, 15, 5, 45, 97, 61, 221, 497, 1949, 3163, 4707, 8441, 1437}},
+{3471, 15, 14585, {1, 3, 5, 1, 3, 35, 107, 9, 473, 971, 227, 2225, 3999, 3095, 18879}},
+{3472, 15, 14586, {1, 1, 1, 9, 21, 59, 21, 1, 41, 435, 575, 491, 1839, 1095, 9727}},
+{3473, 15, 14606, {1, 3, 5, 9, 13, 29, 123, 251, 465, 701, 1105, 829, 573, 11503, 11861}},
+{3474, 15, 14627, {1, 3, 3, 13, 27, 59, 29, 111, 225, 973, 561, 1481, 835, 9261, 13831}},
+{3475, 15, 14630, {1, 1, 1, 7, 17, 3, 97, 211, 333, 315, 571, 3523, 7305, 6461, 20139}},
+{3476, 15, 14634, {1, 3, 7, 11, 31, 21, 105, 247, 113, 863, 1767, 381, 4623, 8935, 7911}},
+{3477, 15, 14636, {1, 1, 5, 7, 29, 45, 17, 155, 69, 17, 655, 1983, 6385, 6177, 7961}},
+{3478, 15, 14647, {1, 3, 3, 15, 31, 15, 63, 81, 309, 115, 393, 3445, 689, 13963, 18887}},
+{3479, 15, 14653, {1, 1, 5, 1, 19, 39, 127, 61, 357, 53, 195, 2745, 7853, 5753, 3669}},
+{3480, 15, 14659, {1, 3, 7, 7, 17, 51, 57, 145, 451, 365, 1517, 909, 4265, 10737, 9579}},
+{3481, 15, 14671, {1, 1, 3, 13, 3, 37, 121, 103, 257, 47, 1685, 2951, 5753, 15379, 8899}},
+{3482, 15, 14674, {1, 1, 5, 7, 31, 63, 61, 197, 97, 773, 133, 1517, 3093, 14879, 22941}},
+{3483, 15, 14701, {1, 1, 5, 1, 3, 9, 27, 53, 97, 663, 1915, 409, 471, 1391, 24853}},
+{3484, 15, 14716, {1, 1, 1, 7, 21, 53, 69, 5, 187, 571, 2023, 997, 323, 12059, 7071}},
+{3485, 15, 14719, {1, 3, 3, 1, 7, 59, 55, 157, 101, 123, 1301, 3709, 4673, 3897, 28791}},
+{3486, 15, 14720, {1, 3, 7, 5, 5, 23, 39, 139, 365, 415, 1481, 3415, 6323, 11109, 5719}},
+{3487, 15, 14725, {1, 3, 5, 3, 5, 11, 23, 143, 243, 229, 183, 3367, 3187, 8151, 28351}},
+{3488, 15, 14730, {1, 3, 7, 9, 5, 37, 29, 23, 437, 827, 985, 2879, 7611, 1391, 19087}},
+{3489, 15, 14743, {1, 3, 3, 5, 7, 9, 5, 143, 217, 757, 1697, 2459, 453, 8679, 4513}},
+{3490, 15, 14747, {1, 3, 5, 5, 11, 33, 3, 143, 293, 921, 185, 2461, 5547, 12247, 28591}},
+{3491, 15, 14786, {1, 3, 7, 5, 3, 53, 43, 179, 235, 417, 1307, 1367, 3695, 12809, 1807}},
+{3492, 15, 14788, {1, 3, 1, 11, 15, 43, 115, 229, 157, 25, 687, 3347, 271, 5777, 8557}},
+{3493, 15, 14792, {1, 3, 7, 5, 27, 37, 55, 135, 209, 47, 1603, 957, 5785, 11141, 10407}},
+{3494, 15, 14795, {1, 1, 1, 15, 17, 17, 103, 29, 489, 493, 119, 1707, 3463, 1815, 32055}},
+{3495, 15, 14809, {1, 3, 7, 11, 17, 13, 115, 145, 77, 515, 1911, 477, 5997, 8731, 3143}},
+{3496, 15, 14831, {1, 3, 1, 13, 31, 41, 73, 91, 231, 1, 455, 2023, 4691, 3613, 16329}},
+{3497, 15, 14834, {1, 1, 5, 15, 15, 39, 17, 117, 131, 657, 1939, 2245, 2575, 195, 25209}},
+{3498, 15, 14850, {1, 3, 7, 15, 5, 51, 69, 141, 499, 931, 1165, 2119, 1703, 10867, 28443}},
+{3499, 15, 14855, {1, 1, 1, 15, 13, 45, 45, 103, 115, 177, 651, 2545, 1417, 5349, 3385}},
+{3500, 15, 14859, {1, 3, 3, 1, 1, 41, 117, 15, 225, 861, 843, 2775, 4543, 6275, 14671}},
+{3501, 15, 14864, {1, 3, 5, 15, 5, 35, 87, 193, 341, 55, 1131, 945, 6865, 11271, 18705}},
+{3502, 15, 14876, {1, 3, 5, 9, 13, 35, 71, 197, 79, 351, 3, 3939, 1105, 12455, 28921}},
+{3503, 15, 14889, {1, 3, 1, 13, 9, 23, 89, 165, 59, 257, 1369, 161, 6255, 2997, 19175}},
+{3504, 15, 14890, {1, 3, 5, 3, 5, 41, 107, 231, 111, 207, 1865, 2079, 5891, 2487, 5863}},
+{3505, 15, 14898, {1, 3, 7, 15, 3, 3, 105, 235, 263, 991, 367, 1885, 1769, 7805, 11909}},
+{3506, 15, 14909, {1, 3, 3, 5, 15, 59, 67, 247, 77, 367, 1641, 1959, 1921, 5939, 17355}},
+{3507, 15, 14917, {1, 1, 7, 1, 3, 53, 37, 5, 221, 779, 1353, 1633, 2769, 6355, 8505}},
+{3508, 15, 14924, {1, 1, 7, 13, 11, 13, 73, 227, 115, 523, 355, 3127, 7545, 8409, 22335}},
+{3509, 15, 14929, {1, 1, 5, 11, 21, 15, 91, 115, 427, 683, 461, 2433, 6313, 4595, 24401}},
+{3510, 15, 14942, {1, 3, 7, 5, 29, 21, 57, 215, 423, 717, 1455, 705, 6835, 4503, 26077}},
+{3511, 15, 14951, {1, 1, 1, 15, 3, 33, 25, 227, 381, 477, 1023, 2751, 2229, 631, 16903}},
+{3512, 15, 14969, {1, 3, 1, 11, 9, 17, 59, 73, 53, 671, 251, 1729, 7593, 12473, 22533}},
+{3513, 15, 14970, {1, 3, 3, 1, 3, 35, 37, 173, 459, 143, 135, 3871, 2689, 8007, 4379}},
+{3514, 15, 14972, {1, 3, 5, 9, 23, 19, 43, 45, 493, 509, 1851, 1615, 5675, 13793, 6973}},
+{3515, 15, 14982, {1, 3, 3, 15, 5, 17, 77, 85, 451, 753, 579, 1057, 4851, 6017, 4195}},
+{3516, 15, 14988, {1, 3, 3, 5, 31, 29, 81, 159, 103, 391, 15, 899, 4623, 5957, 31961}},
+{3517, 15, 14994, {1, 1, 1, 7, 17, 57, 81, 17, 177, 633, 49, 2793, 5229, 5995, 9491}},
+{3518, 15, 15005, {1, 1, 7, 15, 17, 19, 65, 57, 189, 239, 1229, 929, 2681, 12845, 29311}},
+{3519, 15, 15016, {1, 3, 1, 11, 13, 47, 61, 203, 383, 875, 943, 139, 4217, 8279, 1047}},
+{3520, 15, 15024, {1, 3, 7, 13, 23, 7, 1, 69, 47, 537, 1325, 3101, 685, 14057, 19953}},
+{3521, 15, 15030, {1, 3, 3, 1, 1, 7, 39, 77, 47, 755, 527, 2985, 5433, 15095, 27741}},
+{3522, 15, 15048, {1, 1, 7, 5, 23, 57, 79, 155, 81, 937, 1071, 3929, 1655, 3831, 17351}},
+{3523, 15, 15054, {1, 3, 7, 1, 3, 41, 13, 235, 207, 487, 1883, 2247, 1231, 2751, 15615}},
+{3524, 15, 15066, {1, 1, 7, 1, 21, 57, 95, 191, 119, 483, 283, 2221, 5665, 14819, 26097}},
+{3525, 15, 15071, {1, 3, 1, 1, 9, 59, 27, 51, 393, 31, 925, 715, 7705, 14885, 28767}},
+{3526, 15, 15072, {1, 1, 3, 3, 3, 61, 109, 131, 113, 249, 1331, 2521, 2973, 6375, 20093}},
+{3527, 15, 15075, {1, 3, 7, 9, 31, 37, 125, 245, 237, 245, 111, 379, 7495, 15531, 2325}},
+{3528, 15, 15119, {1, 3, 7, 13, 21, 21, 57, 21, 449, 969, 417, 2999, 509, 639, 7797}},
+{3529, 15, 15121, {1, 3, 7, 7, 7, 29, 11, 175, 55, 705, 891, 863, 3021, 10071, 10267}},
+{3530, 15, 15133, {1, 1, 3, 13, 19, 17, 127, 57, 449, 579, 337, 899, 1235, 11269, 4245}},
+{3531, 15, 15138, {1, 1, 1, 11, 29, 61, 35, 75, 249, 683, 287, 45, 3277, 7521, 2073}},
+{3532, 15, 15143, {1, 3, 5, 5, 15, 25, 77, 63, 63, 801, 1387, 1533, 2185, 10899, 28381}},
+{3533, 15, 15170, {1, 3, 1, 1, 21, 49, 3, 249, 419, 575, 87, 3749, 2523, 16125, 9483}},
+{3534, 15, 15194, {1, 1, 1, 11, 21, 43, 85, 211, 449, 439, 1495, 1841, 4765, 15253, 1467}},
+{3535, 15, 15212, {1, 3, 3, 15, 3, 37, 31, 243, 187, 995, 1103, 2723, 1523, 15967, 28649}},
+{3536, 15, 15223, {1, 1, 5, 11, 9, 11, 17, 87, 335, 125, 1079, 1657, 1237, 8059, 29833}},
+{3537, 15, 15229, {1, 3, 1, 3, 3, 41, 35, 37, 33, 61, 505, 3203, 5, 101, 8571}},
+{3538, 15, 15254, {1, 1, 3, 11, 9, 11, 85, 235, 261, 473, 109, 2127, 5745, 6389, 7431}},
+{3539, 15, 15263, {1, 1, 5, 15, 3, 55, 77, 97, 17, 193, 1267, 3063, 6531, 9797, 8639}},
+{3540, 15, 15270, {1, 1, 5, 5, 25, 41, 79, 83, 485, 697, 149, 1023, 89, 6115, 15227}},
+{3541, 15, 15273, {1, 1, 3, 15, 1, 9, 73, 251, 33, 599, 1017, 353, 4305, 16033, 29663}},
+{3542, 15, 15287, {1, 3, 7, 15, 3, 1, 89, 39, 125, 337, 1445, 3131, 3685, 9849, 25829}},
+{3543, 15, 15299, {1, 3, 7, 3, 19, 1, 63, 179, 349, 135, 185, 2977, 2527, 15087, 18133}},
+{3544, 15, 15301, {1, 1, 3, 3, 23, 7, 91, 221, 325, 723, 345, 81, 8077, 5501, 8453}},
+{3545, 15, 15306, {1, 1, 3, 9, 7, 3, 13, 173, 479, 161, 1989, 3255, 2069, 6717, 559}},
+{3546, 15, 15313, {1, 3, 3, 5, 9, 61, 93, 203, 277, 367, 1141, 981, 4745, 12625, 21003}},
+{3547, 15, 15320, {1, 3, 5, 5, 27, 17, 5, 211, 403, 701, 5, 3091, 4611, 5615, 23667}},
+{3548, 15, 15323, {1, 1, 3, 1, 21, 61, 125, 77, 57, 463, 1499, 791, 2087, 2805, 18829}},
+{3549, 15, 15329, {1, 3, 5, 3, 11, 41, 125, 231, 119, 837, 831, 1331, 7439, 2381, 3759}},
+{3550, 15, 15332, {1, 3, 1, 11, 19, 59, 117, 107, 443, 699, 315, 1491, 2581, 15871, 17159}},
+{3551, 15, 15341, {1, 3, 5, 11, 5, 9, 121, 35, 209, 877, 527, 3493, 4657, 16093, 17589}},
+{3552, 15, 15359, {1, 1, 7, 15, 9, 43, 119, 29, 381, 479, 1443, 3171, 5053, 9625, 21161}},
+{3553, 15, 15361, {1, 1, 3, 5, 15, 21, 31, 223, 83, 399, 1529, 3605, 6343, 10469, 10099}},
+{3554, 15, 15364, {1, 1, 3, 5, 5, 45, 23, 123, 353, 971, 85, 3069, 3245, 6569, 13241}},
+{3555, 15, 15367, {1, 1, 1, 3, 25, 49, 5, 77, 491, 881, 993, 1195, 7677, 5709, 10807}},
+{3556, 15, 15379, {1, 3, 3, 3, 5, 49, 127, 255, 183, 583, 1599, 987, 7281, 7149, 28507}},
+{3557, 15, 15391, {1, 1, 5, 1, 13, 55, 55, 157, 197, 25, 1971, 3161, 3903, 8919, 13563}},
+{3558, 15, 15415, {1, 3, 7, 9, 3, 37, 79, 193, 25, 103, 843, 2651, 6341, 2653, 24337}},
+{3559, 15, 15416, {1, 1, 7, 3, 25, 49, 99, 139, 45, 211, 2033, 2331, 7037, 7177, 1755}},
+{3560, 15, 15419, {1, 3, 7, 3, 5, 19, 127, 135, 403, 221, 141, 1065, 3935, 2745, 25979}},
+{3561, 15, 15433, {1, 1, 3, 3, 31, 23, 111, 37, 261, 7, 835, 2379, 7927, 8181, 23751}},
+{3562, 15, 15469, {1, 3, 7, 15, 1, 39, 79, 3, 103, 427, 1917, 809, 5039, 689, 1939}},
+{3563, 15, 15478, {1, 1, 1, 15, 29, 37, 39, 243, 149, 353, 763, 3405, 5751, 9441, 6653}},
+{3564, 15, 15481, {1, 3, 3, 11, 1, 57, 125, 151, 445, 423, 841, 2265, 5017, 15863, 13057}},
+{3565, 15, 15482, {1, 3, 5, 13, 11, 49, 61, 159, 211, 917, 561, 1903, 3985, 11117, 28969}},
+{3566, 15, 15498, {1, 3, 5, 13, 29, 5, 35, 51, 91, 291, 9, 3713, 3341, 4551, 12085}},
+{3567, 15, 15505, {1, 3, 3, 1, 1, 39, 111, 141, 319, 179, 1709, 1605, 5063, 13279, 10003}},
+{3568, 15, 15517, {1, 1, 3, 9, 7, 59, 91, 41, 343, 475, 1669, 2311, 5141, 12661, 25847}},
+{3569, 15, 15518, {1, 3, 5, 9, 9, 11, 49, 221, 1, 243, 791, 229, 503, 373, 19189}},
+{3570, 15, 15527, {1, 1, 5, 11, 17, 13, 45, 57, 215, 491, 1601, 2183, 3713, 429, 22007}},
+{3571, 15, 15528, {1, 1, 3, 11, 31, 61, 23, 237, 261, 955, 1085, 1541, 2601, 909, 7749}},
+{3572, 15, 15545, {1, 1, 3, 9, 13, 11, 121, 173, 177, 551, 1757, 2745, 2265, 4611, 743}},
+{3573, 15, 15548, {1, 1, 3, 15, 23, 43, 107, 239, 463, 369, 1857, 1073, 1247, 1029, 22557}},
+{3574, 15, 15554, {1, 1, 3, 11, 23, 35, 89, 93, 41, 941, 1141, 2339, 1423, 8007, 28685}},
+{3575, 15, 15565, {1, 3, 5, 13, 29, 7, 79, 15, 59, 145, 1237, 2215, 1257, 12621, 31101}},
+{3576, 15, 15577, {1, 1, 3, 7, 13, 55, 57, 229, 205, 1009, 341, 3901, 5189, 957, 32587}},
+{3577, 15, 15580, {1, 3, 7, 11, 1, 1, 41, 7, 365, 407, 1609, 1423, 6483, 5171, 32519}},
+{3578, 15, 15587, {1, 3, 7, 3, 17, 31, 125, 27, 125, 335, 1395, 2639, 329, 2549, 14449}},
+{3579, 15, 15601, {1, 3, 3, 7, 19, 45, 11, 73, 123, 179, 1685, 3385, 2379, 3387, 16793}},
+{3580, 15, 15604, {1, 3, 7, 5, 31, 25, 47, 153, 121, 453, 935, 3953, 2081, 12145, 24979}},
+{3581, 15, 15611, {1, 1, 7, 13, 25, 11, 65, 3, 277, 237, 1129, 1801, 4165, 9065, 18747}},
+{3582, 15, 15616, {1, 1, 7, 7, 13, 5, 37, 253, 507, 645, 1355, 3401, 6707, 6329, 11237}},
+{3583, 15, 15619, {1, 1, 3, 15, 17, 49, 3, 233, 407, 451, 69, 3859, 3171, 12303, 21031}},
+{3584, 15, 15625, {1, 1, 3, 3, 9, 53, 119, 117, 401, 903, 1449, 3639, 4083, 2095, 22085}},
+{3585, 15, 15633, {1, 3, 7, 15, 5, 61, 117, 193, 137, 431, 195, 4019, 3047, 5049, 14281}},
+{3586, 15, 15674, {1, 1, 1, 15, 17, 19, 29, 83, 449, 257, 1105, 1949, 1749, 3459, 6343}},
+{3587, 15, 15681, {1, 1, 1, 15, 23, 39, 61, 219, 109, 365, 863, 1813, 6673, 15999, 5101}},
+{3588, 15, 15691, {1, 1, 5, 5, 13, 11, 37, 151, 365, 719, 1233, 2425, 1285, 1721, 1205}},
+{3589, 15, 15693, {1, 3, 3, 3, 7, 53, 109, 153, 45, 425, 1741, 1229, 4405, 8071, 25155}},
+{3590, 15, 15696, {1, 3, 1, 1, 1, 13, 39, 49, 413, 77, 1367, 2553, 5563, 7659, 3467}},
+{3591, 15, 15712, {1, 1, 5, 9, 3, 49, 23, 11, 445, 121, 1505, 877, 4137, 1809, 2429}},
+{3592, 15, 15717, {1, 1, 1, 11, 21, 13, 93, 33, 493, 805, 775, 2939, 2961, 13625, 31879}},
+{3593, 15, 15724, {1, 1, 7, 5, 1, 59, 63, 131, 373, 23, 337, 2107, 5315, 4889, 22851}},
+{3594, 15, 15727, {1, 1, 3, 13, 21, 47, 15, 131, 353, 793, 1891, 1757, 5793, 1147, 23697}},
+{3595, 15, 15730, {1, 3, 5, 13, 7, 59, 25, 135, 259, 109, 1835, 429, 8153, 7355, 145}},
+{3596, 15, 15746, {1, 3, 3, 13, 9, 47, 121, 89, 89, 635, 1079, 2353, 4803, 11369, 12653}},
+{3597, 15, 15751, {1, 3, 5, 9, 23, 39, 49, 231, 105, 603, 613, 2021, 6073, 11819, 10595}},
+{3598, 15, 15760, {1, 3, 7, 7, 7, 19, 19, 155, 347, 387, 1459, 3793, 619, 14437, 2455}},
+{3599, 15, 15770, {1, 1, 1, 15, 21, 35, 19, 185, 483, 425, 479, 3429, 5403, 10791, 14219}},
+{3600, 15, 15782, {1, 1, 3, 11, 5, 51, 105, 63, 493, 677, 1457, 2865, 5619, 9321, 19583}},
+{3601, 15, 15791, {1, 1, 3, 3, 23, 1, 77, 177, 263, 289, 1567, 3837, 5359, 3269, 16023}},
+{3602, 15, 15796, {1, 1, 7, 3, 13, 61, 79, 77, 51, 953, 1417, 795, 4467, 2981, 25131}},
+{3603, 15, 15808, {1, 1, 5, 13, 23, 13, 29, 185, 337, 7, 149, 3609, 8119, 9545, 16579}},
+{3604, 15, 15814, {1, 3, 1, 5, 23, 9, 123, 15, 99, 55, 1021, 3709, 1521, 15189, 22193}},
+{3605, 15, 15825, {1, 3, 7, 9, 13, 41, 39, 45, 49, 181, 1587, 3213, 1037, 14775, 3333}},
+{3606, 15, 15828, {1, 1, 1, 7, 29, 55, 59, 31, 411, 601, 191, 283, 3211, 7951, 7919}},
+{3607, 15, 15835, {1, 1, 7, 7, 21, 47, 7, 193, 343, 831, 1267, 3289, 1015, 13093, 2717}},
+{3608, 15, 15844, {1, 3, 7, 1, 17, 9, 97, 19, 279, 827, 1699, 3573, 3137, 3535, 17791}},
+{3609, 15, 15847, {1, 1, 5, 11, 27, 15, 103, 135, 35, 625, 1575, 97, 7013, 13353, 19333}},
+{3610, 15, 15853, {1, 3, 3, 7, 17, 13, 49, 135, 435, 743, 1799, 2655, 4839, 2893, 31153}},
+{3611, 15, 15856, {1, 1, 5, 1, 3, 41, 1, 195, 53, 803, 1575, 2939, 3873, 10495, 5211}},
+{3612, 15, 15877, {1, 3, 1, 15, 19, 19, 37, 59, 355, 483, 685, 3899, 4645, 15127, 3479}},
+{3613, 15, 15878, {1, 1, 5, 3, 25, 9, 9, 229, 101, 631, 1165, 4091, 3723, 10655, 9463}},
+{3614, 15, 15887, {1, 3, 5, 15, 5, 13, 91, 61, 19, 469, 1675, 3331, 3121, 3435, 4111}},
+{3615, 15, 15908, {1, 1, 7, 1, 31, 61, 23, 83, 165, 551, 1097, 3825, 5385, 4723, 3635}},
+{3616, 15, 15917, {1, 3, 7, 15, 9, 31, 11, 121, 503, 855, 561, 1647, 1229, 1147, 15997}},
+{3617, 15, 15923, {1, 3, 7, 13, 21, 47, 41, 195, 197, 719, 1263, 3609, 7515, 2659, 30713}},
+{3618, 15, 15930, {1, 1, 1, 7, 31, 61, 101, 101, 479, 571, 605, 301, 6633, 15587, 23665}},
+{3619, 15, 15937, {1, 3, 7, 3, 25, 39, 35, 225, 135, 463, 53, 709, 5129, 4135, 10421}},
+{3620, 15, 15958, {1, 1, 5, 13, 19, 55, 107, 15, 163, 287, 673, 899, 5197, 4619, 3465}},
+{3621, 15, 15977, {1, 3, 3, 5, 21, 49, 15, 105, 283, 877, 1875, 1079, 3431, 13053, 26599}},
+{3622, 15, 15991, {1, 1, 7, 1, 1, 1, 95, 113, 119, 575, 1159, 2325, 6895, 12177, 4369}},
+{3623, 15, 16007, {1, 1, 1, 11, 25, 25, 83, 207, 301, 729, 1947, 2321, 3621, 15707, 11303}},
+{3624, 15, 16011, {1, 1, 5, 5, 7, 63, 83, 105, 211, 175, 1817, 2883, 5385, 7437, 24865}},
+{3625, 15, 16014, {1, 3, 7, 5, 23, 39, 19, 211, 151, 295, 573, 223, 5065, 6345, 23187}},
+{3626, 15, 16021, {1, 1, 7, 11, 15, 31, 89, 123, 57, 695, 685, 1799, 659, 9929, 22933}},
+{3627, 15, 16022, {1, 1, 7, 7, 19, 17, 27, 137, 117, 141, 1481, 869, 7061, 3073, 19671}},
+{3628, 15, 16028, {1, 3, 3, 11, 9, 19, 123, 93, 39, 517, 883, 3769, 2267, 8089, 6617}},
+{3629, 15, 16035, {1, 3, 1, 7, 9, 61, 51, 241, 319, 853, 1239, 899, 105, 1677, 29351}},
+{3630, 15, 16041, {1, 1, 7, 15, 13, 59, 85, 175, 223, 87, 905, 3175, 3405, 3489, 18475}},
+{3631, 15, 16056, {1, 1, 1, 15, 1, 55, 79, 97, 315, 605, 851, 4015, 3689, 9371, 31523}},
+{3632, 15, 16069, {1, 1, 5, 15, 1, 39, 91, 27, 211, 881, 1375, 2307, 5791, 10185, 23093}},
+{3633, 15, 16076, {1, 3, 1, 5, 3, 17, 59, 219, 105, 623, 21, 2843, 3427, 4799, 3793}},
+{3634, 15, 16081, {1, 3, 3, 7, 21, 55, 17, 29, 397, 93, 1981, 4047, 935, 5971, 14589}},
+{3635, 15, 16087, {1, 1, 3, 9, 5, 57, 63, 27, 373, 815, 167, 205, 367, 4945, 30041}},
+{3636, 15, 16088, {1, 1, 5, 9, 7, 3, 69, 35, 197, 309, 1729, 3735, 1523, 10427, 26253}},
+{3637, 15, 16110, {1, 1, 3, 7, 7, 49, 35, 189, 297, 311, 2025, 305, 3863, 14393, 2533}},
+{3638, 15, 16112, {1, 3, 3, 9, 17, 31, 5, 17, 167, 601, 909, 3149, 2533, 12123, 25325}},
+{3639, 15, 16117, {1, 3, 5, 3, 11, 41, 69, 199, 79, 611, 133, 3519, 5955, 4609, 27403}},
+{3640, 15, 16150, {1, 3, 3, 13, 3, 17, 53, 165, 361, 797, 1447, 869, 6707, 6541, 32249}},
+{3641, 15, 16153, {1, 3, 1, 1, 29, 47, 17, 45, 473, 199, 1595, 3095, 3635, 6965, 21859}},
+{3642, 15, 16160, {1, 1, 3, 9, 1, 15, 59, 163, 91, 811, 1087, 1707, 6743, 12643, 29901}},
+{3643, 15, 16166, {1, 1, 1, 3, 19, 21, 7, 209, 121, 821, 709, 1085, 5333, 7689, 28355}},
+{3644, 15, 16172, {1, 3, 1, 15, 5, 27, 115, 31, 37, 79, 1347, 155, 3709, 13251, 32151}},
+{3645, 15, 16190, {1, 3, 7, 15, 27, 27, 127, 231, 137, 205, 1665, 1461, 299, 2797, 879}},
+{3646, 15, 16195, {1, 1, 1, 7, 13, 3, 127, 13, 253, 481, 1435, 1895, 2665, 7611, 17761}},
+{3647, 15, 16204, {1, 1, 3, 7, 7, 21, 71, 247, 301, 183, 1785, 331, 4835, 2251, 4493}},
+{3648, 15, 16216, {1, 3, 7, 9, 9, 1, 77, 169, 103, 647, 1959, 1847, 5803, 3421, 15915}},
+{3649, 15, 16222, {1, 3, 1, 7, 19, 17, 81, 45, 263, 549, 1607, 2177, 1117, 14427, 16451}},
+{3650, 15, 16228, {1, 1, 7, 15, 27, 25, 27, 27, 33, 813, 1667, 253, 2749, 927, 29707}},
+{3651, 15, 16245, {1, 1, 7, 3, 17, 29, 13, 67, 417, 303, 19, 3809, 7225, 12775, 3933}},
+{3652, 15, 16255, {1, 1, 1, 11, 13, 41, 77, 217, 281, 659, 1099, 3047, 1619, 525, 4313}},
+{3653, 15, 16265, {1, 3, 3, 9, 23, 47, 5, 33, 219, 531, 77, 2307, 1893, 8335, 8281}},
+{3654, 15, 16273, {1, 3, 7, 3, 3, 35, 27, 249, 159, 495, 431, 3001, 1475, 11505, 15693}},
+{3655, 15, 16276, {1, 1, 5, 9, 21, 49, 43, 159, 465, 959, 179, 993, 121, 11569, 21027}},
+{3656, 15, 16283, {1, 3, 1, 5, 1, 61, 9, 221, 231, 55, 191, 2829, 3331, 8911, 15109}},
+{3657, 15, 16295, {1, 1, 7, 1, 7, 35, 67, 97, 159, 191, 935, 3151, 6397, 10751, 1835}},
+{3658, 15, 16304, {1, 1, 1, 7, 15, 39, 127, 163, 437, 333, 829, 753, 8151, 13239, 523}},
+{3659, 15, 16313, {1, 1, 3, 13, 9, 25, 73, 155, 445, 239, 2035, 15, 5243, 15531, 1733}},
+{3660, 15, 16319, {1, 3, 7, 15, 5, 25, 3, 55, 117, 57, 783, 1509, 7043, 13159, 8557}},
+{3661, 15, 16328, {1, 3, 5, 1, 21, 55, 89, 119, 199, 79, 161, 1597, 3263, 3335, 5757}},
+{3662, 15, 16345, {1, 3, 7, 5, 27, 23, 85, 113, 111, 211, 389, 1513, 2759, 7945, 931}},
+{3663, 15, 16355, {1, 1, 1, 7, 1, 5, 17, 177, 357, 619, 5, 2583, 621, 2973, 28845}},
+{3664, 15, 16364, {1, 3, 7, 13, 11, 21, 47, 99, 421, 279, 1541, 1305, 4571, 6127, 20735}},
+{3665, 15, 16372, {1, 3, 5, 5, 23, 43, 19, 137, 425, 409, 1625, 2671, 4385, 3197, 25753}},
+{3666, 15, 16375, {1, 1, 7, 5, 27, 17, 57, 15, 383, 181, 951, 2115, 5237, 1495, 9671}},
+{3667, 15, 16382, {1, 3, 3, 11, 9, 1, 53, 127, 375, 499, 1487, 121, 1465, 3175, 24337}},
+{3668, 16, 22, {1, 3, 7, 11, 29, 35, 67, 129, 221, 439, 1159, 3501, 7741, 8885, 11381, 20707}},
+{3669, 16, 28, {1, 3, 5, 11, 29, 59, 23, 117, 343, 637, 1825, 1687, 2823, 11641, 3311, 23603}},
+{3670, 16, 31, {1, 1, 5, 11, 1, 35, 103, 155, 233, 575, 1761, 503, 4175, 6105, 29737, 32681}},
+{3671, 16, 41, {1, 3, 3, 1, 5, 63, 27, 71, 245, 433, 1779, 2475, 5479, 4705, 10795, 34247}},
+{3672, 16, 94, {1, 3, 5, 7, 29, 45, 117, 5, 393, 849, 843, 3131, 6995, 9979, 28907, 30115}},
+{3673, 16, 107, {1, 3, 5, 9, 27, 29, 69, 5, 395, 561, 1531, 409, 2779, 8785, 16405, 27315}},
+{3674, 16, 151, {1, 3, 1, 9, 15, 29, 85, 3, 331, 19, 1941, 567, 6957, 747, 1627, 11347}},
+{3675, 16, 158, {1, 1, 3, 9, 27, 45, 47, 127, 133, 921, 1817, 2231, 6333, 14371, 12799, 9831}},
+{3676, 16, 167, {1, 1, 5, 15, 31, 7, 125, 13, 455, 159, 331, 3629, 4705, 11261, 3657, 36307}},
+{3677, 16, 174, {1, 1, 5, 9, 11, 53, 51, 35, 87, 885, 1975, 3899, 1013, 7667, 32385, 33635}},
+{3678, 16, 203, {1, 1, 1, 3, 7, 45, 107, 177, 193, 765, 731, 139, 5563, 623, 16485, 54999}},
+{3679, 16, 208, {1, 1, 5, 9, 17, 53, 117, 69, 385, 587, 1483, 149, 2769, 3013, 18183, 10173}},
+{3680, 16, 214, {1, 1, 5, 11, 5, 3, 25, 153, 351, 749, 801, 3077, 3209, 11189, 25241, 14115}},
+{3681, 16, 223, {1, 1, 7, 9, 1, 47, 41, 247, 135, 163, 899, 1517, 5647, 10595, 32531, 12497}},
+{3682, 16, 227, {1, 3, 5, 11, 5, 61, 111, 215, 251, 279, 825, 2155, 3527, 173, 10973, 59257}},
+{3683, 16, 266, {1, 3, 5, 11, 25, 15, 71, 83, 135, 231, 1415, 3761, 7513, 8337, 28979, 43615}},
+{3684, 16, 268, {1, 3, 5, 13, 19, 5, 55, 165, 141, 119, 1891, 2255, 4735, 16217, 26195, 50527}},
+{3685, 16, 274, {1, 1, 7, 15, 23, 59, 59, 191, 1, 855, 453, 2619, 5013, 14749, 24335, 44339}},
+{3686, 16, 279, {1, 1, 1, 13, 15, 41, 51, 147, 229, 495, 1191, 867, 1525, 581, 29713, 26391}},
+{3687, 16, 302, {1, 1, 1, 9, 29, 5, 59, 127, 105, 417, 301, 2249, 6335, 3513, 17373, 52977}},
+{3688, 16, 310, {1, 1, 3, 7, 21, 27, 109, 143, 63, 347, 1429, 2889, 2597, 10243, 9913, 22687}},
+{3689, 16, 322, {1, 3, 5, 5, 7, 3, 125, 147, 313, 351, 1163, 415, 5615, 5571, 7089, 55621}},
+{3690, 16, 328, {1, 3, 3, 3, 31, 43, 101, 93, 9, 671, 135, 333, 2169, 11169, 7403, 50707}},
+{3691, 16, 336, {1, 1, 7, 13, 15, 33, 125, 155, 227, 827, 1047, 2441, 3007, 10881, 19969, 63805}},
+{3692, 16, 370, {1, 3, 3, 5, 31, 33, 29, 249, 159, 797, 1475, 841, 6933, 6417, 25629, 61865}},
+{3693, 16, 398, {1, 3, 3, 15, 11, 55, 11, 117, 149, 911, 1589, 3133, 6477, 6123, 10471, 41099}},
+{3694, 16, 421, {1, 3, 3, 9, 27, 37, 1, 119, 509, 969, 831, 3771, 2093, 13621, 31737, 43269}},
+{3695, 16, 436, {1, 1, 1, 1, 9, 23, 119, 109, 487, 753, 1673, 2163, 3349, 4741, 29971, 3407}},
+{3696, 16, 440, {1, 3, 3, 7, 25, 7, 67, 9, 461, 631, 651, 2271, 5663, 2621, 3953, 20975}},
+{3697, 16, 451, {1, 1, 5, 11, 13, 31, 29, 255, 371, 517, 845, 3649, 1187, 10061, 22887, 58417}},
+{3698, 16, 454, {1, 3, 5, 13, 29, 1, 11, 137, 151, 249, 167, 1243, 997, 11023, 11875, 42315}},
+{3699, 16, 463, {1, 1, 5, 5, 5, 55, 103, 71, 255, 1023, 209, 1005, 2147, 11527, 17863, 6661}},
+{3700, 16, 465, {1, 1, 3, 3, 31, 39, 7, 151, 353, 775, 1313, 1257, 4197, 2625, 9571, 27269}},
+{3701, 16, 494, {1, 1, 1, 3, 7, 17, 3, 127, 501, 503, 1879, 2329, 3049, 10603, 2111, 33189}},
+{3702, 16, 508, {1, 3, 3, 7, 13, 59, 93, 13, 375, 483, 1991, 2257, 3003, 1699, 4339, 51827}},
+{3703, 16, 532, {1, 3, 7, 15, 27, 41, 59, 225, 405, 807, 1545, 2581, 1173, 14137, 3413, 39299}},
+{3704, 16, 555, {1, 1, 1, 3, 9, 23, 37, 123, 465, 1023, 1065, 1455, 5107, 3839, 20451, 11461}},
+{3705, 16, 563, {1, 1, 1, 11, 19, 55, 91, 121, 317, 199, 215, 3031, 7223, 11891, 21463, 64921}},
+{3706, 16, 577, {1, 3, 7, 11, 19, 5, 5, 115, 399, 219, 71, 1465, 281, 14451, 26807, 42541}},
+{3707, 16, 580, {1, 3, 5, 13, 3, 33, 75, 35, 19, 559, 761, 947, 7479, 15325, 31453, 20561}},
+{3708, 16, 584, {1, 3, 3, 13, 23, 47, 99, 73, 331, 353, 401, 1737, 6235, 13781, 5547, 56443}},
+{3709, 16, 607, {1, 3, 3, 13, 21, 37, 41, 205, 87, 399, 51, 3175, 7403, 12875, 21129, 7079}},
+{3710, 16, 608, {1, 3, 5, 11, 15, 47, 33, 39, 465, 871, 277, 2351, 695, 1953, 24293, 20595}},
+{3711, 16, 665, {1, 1, 7, 11, 13, 15, 115, 59, 469, 715, 191, 1927, 905, 13463, 29005, 46789}},
+{3712, 16, 675, {1, 3, 5, 9, 13, 55, 79, 17, 265, 887, 905, 3985, 6907, 3379, 20055, 58569}},
+{3713, 16, 692, {1, 1, 7, 11, 21, 29, 23, 109, 17, 427, 1623, 2219, 3857, 3709, 25033, 63823}},
+{3714, 16, 707, {1, 3, 5, 15, 19, 27, 113, 15, 25, 63, 1885, 2693, 5301, 9385, 14137, 26097}},
+{3715, 16, 737, {1, 3, 3, 11, 17, 5, 73, 143, 79, 957, 461, 1709, 4909, 2285, 18113, 8401}},
+{3716, 16, 750, {1, 1, 3, 7, 9, 9, 101, 127, 137, 755, 1359, 1965, 83, 13335, 27763, 7941}},
+{3717, 16, 757, {1, 1, 1, 3, 13, 61, 95, 61, 295, 615, 555, 2163, 8155, 14043, 21465, 46741}},
+{3718, 16, 800, {1, 1, 1, 13, 29, 19, 111, 17, 373, 153, 1703, 2199, 7209, 15845, 1879, 7493}},
+{3719, 16, 805, {1, 3, 1, 13, 21, 51, 49, 51, 255, 151, 207, 1915, 7629, 2705, 8739, 7467}},
+{3720, 16, 809, {1, 3, 7, 5, 21, 21, 23, 193, 467, 739, 519, 2315, 2953, 10633, 9163, 6007}},
+{3721, 16, 837, {1, 3, 1, 5, 23, 19, 23, 247, 93, 297, 1089, 2349, 4683, 13609, 7615, 18647}},
+{3722, 16, 865, {1, 1, 3, 3, 21, 39, 19, 71, 93, 1, 133, 3531, 7503, 2819, 24211, 1739}},
+{3723, 16, 949, {1, 3, 5, 13, 9, 43, 31, 111, 493, 739, 705, 2715, 3613, 11877, 27945, 46053}},
+{3724, 16, 950, {1, 1, 7, 13, 27, 59, 103, 129, 53, 531, 1379, 1441, 5341, 14937, 5079, 39881}},
+{3725, 16, 956, {1, 1, 3, 3, 11, 63, 91, 95, 433, 393, 715, 809, 591, 4141, 17417, 54107}},
+{3726, 16, 961, {1, 3, 5, 1, 7, 25, 25, 175, 205, 803, 183, 1441, 1279, 2753, 20001, 56677}},
+{3727, 16, 1016, {1, 1, 5, 3, 13, 23, 77, 25, 133, 137, 1907, 1313, 2463, 14339, 13, 57757}},
+{3728, 16, 1030, {1, 1, 5, 9, 23, 35, 1, 119, 111, 61, 403, 1815, 1985, 5651, 10883, 55943}},
+{3729, 16, 1072, {1, 3, 1, 7, 21, 43, 115, 7, 107, 719, 759, 1521, 467, 8735, 29785, 63821}},
+{3730, 16, 1119, {1, 1, 3, 13, 19, 17, 51, 141, 399, 569, 703, 2221, 2809, 13355, 1907, 15837}},
+{3731, 16, 1130, {1, 1, 5, 15, 15, 53, 57, 31, 481, 69, 1439, 4049, 6727, 11307, 20683, 63517}},
+{3732, 16, 1135, {1, 1, 1, 3, 13, 27, 9, 255, 363, 131, 1745, 2489, 6451, 6585, 12873, 35405}},
+{3733, 16, 1137, {1, 3, 5, 1, 17, 31, 113, 135, 449, 915, 1017, 2317, 6821, 5483, 30707, 45279}},
+{3734, 16, 1144, {1, 3, 5, 1, 13, 47, 25, 53, 413, 545, 1777, 3049, 7527, 9689, 25935, 9919}},
+{3735, 16, 1149, {1, 3, 7, 11, 17, 39, 13, 131, 295, 517, 1755, 2977, 6267, 12351, 8957, 17765}},
+{3736, 16, 1180, {1, 1, 7, 5, 27, 57, 47, 21, 125, 429, 1169, 1717, 5455, 16359, 29065, 6671}},
+{3737, 16, 1214, {1, 1, 5, 5, 21, 15, 79, 241, 83, 515, 859, 2351, 3125, 7465, 30475, 19759}},
+{3738, 16, 1221, {1, 3, 1, 9, 11, 5, 81, 11, 7, 221, 141, 3329, 3435, 323, 18999, 54735}},
+{3739, 16, 1234, {1, 1, 1, 15, 7, 57, 87, 251, 63, 561, 929, 1367, 2511, 14527, 9335, 38775}},
+{3740, 16, 1239, {1, 3, 3, 9, 23, 37, 59, 105, 179, 515, 235, 2445, 433, 13039, 27005, 48829}},
+{3741, 16, 1249, {1, 1, 1, 1, 23, 37, 103, 31, 89, 921, 1687, 831, 387, 10237, 1241, 19295}},
+{3742, 16, 1250, {1, 3, 3, 7, 25, 23, 57, 251, 309, 579, 603, 807, 7383, 8579, 4025, 16757}},
+{3743, 16, 1267, {1, 1, 3, 15, 23, 59, 29, 33, 467, 641, 1271, 2915, 2549, 14767, 26557, 43483}},
+{3744, 16, 1273, {1, 1, 7, 13, 1, 57, 23, 129, 321, 75, 189, 4087, 5011, 4355, 25759, 37153}},
+{3745, 16, 1342, {1, 1, 5, 1, 21, 57, 25, 183, 37, 669, 259, 1381, 877, 10245, 16643, 61035}},
+{3746, 16, 1344, {1, 1, 7, 5, 11, 11, 85, 141, 393, 957, 1745, 2243, 1681, 5583, 16527, 12017}},
+{3747, 16, 1373, {1, 1, 5, 15, 23, 31, 5, 169, 287, 527, 1831, 2937, 7533, 9739, 24305, 2239}},
+{3748, 16, 1378, {1, 1, 7, 1, 7, 13, 3, 243, 189, 309, 607, 3659, 6369, 7649, 24255, 55373}},
+{3749, 16, 1408, {1, 1, 1, 3, 3, 59, 103, 209, 287, 913, 1223, 1063, 7715, 6073, 26697, 25671}},
+{3750, 16, 1417, {1, 3, 7, 5, 19, 19, 117, 191, 275, 637, 991, 2199, 2921, 10553, 21211, 25981}},
+{3751, 16, 1418, {1, 3, 3, 5, 29, 59, 17, 13, 127, 57, 1405, 3181, 2237, 1795, 21419, 43421}},
+{3752, 16, 1448, {1, 1, 1, 15, 25, 41, 11, 117, 463, 425, 305, 1441, 4307, 7967, 17529, 4043}},
+{3753, 16, 1454, {1, 3, 5, 5, 19, 53, 69, 73, 453, 611, 1583, 1721, 6303, 10561, 18527, 48973}},
+{3754, 16, 1510, {1, 1, 7, 11, 15, 61, 87, 69, 463, 771, 819, 469, 8165, 8897, 29657, 55161}},
+{3755, 16, 1513, {1, 1, 5, 1, 15, 25, 23, 47, 287, 457, 1219, 473, 4127, 3349, 9425, 41541}},
+{3756, 16, 1522, {1, 3, 7, 5, 17, 17, 33, 161, 239, 231, 241, 1297, 4879, 12761, 20939, 65261}},
+{3757, 16, 1543, {1, 3, 3, 9, 19, 53, 95, 89, 117, 333, 1815, 2217, 7779, 8213, 4667, 58395}},
+{3758, 16, 1550, {1, 3, 3, 9, 17, 7, 41, 99, 371, 797, 729, 2851, 2003, 4463, 20793, 54315}},
+{3759, 16, 1552, {1, 3, 5, 5, 23, 39, 19, 235, 163, 365, 141, 791, 455, 2761, 9115, 53351}},
+{3760, 16, 1588, {1, 3, 3, 3, 9, 27, 29, 139, 165, 867, 2023, 1333, 3771, 10451, 9141, 41177}},
+{3761, 16, 1592, {1, 1, 3, 7, 3, 11, 125, 157, 355, 519, 187, 3381, 1151, 1629, 25247, 42797}},
+{3762, 16, 1597, {1, 3, 3, 3, 21, 25, 37, 155, 257, 311, 961, 1945, 1383, 5679, 7857, 7183}},
+{3763, 16, 1606, {1, 3, 3, 5, 29, 11, 49, 125, 171, 605, 1923, 2781, 2555, 5063, 5075, 43301}},
+{3764, 16, 1610, {1, 3, 5, 9, 27, 1, 27, 149, 253, 205, 1299, 2901, 2891, 975, 7641, 8115}},
+{3765, 16, 1617, {1, 3, 5, 3, 31, 7, 49, 215, 81, 791, 1485, 837, 5051, 1947, 7521, 25723}},
+{3766, 16, 1623, {1, 3, 5, 7, 23, 25, 69, 13, 3, 859, 441, 3577, 1687, 6559, 8687, 46757}},
+{3767, 16, 1657, {1, 1, 1, 9, 1, 59, 3, 31, 251, 187, 617, 2607, 4635, 6121, 8565, 8871}},
+{3768, 16, 1697, {1, 3, 3, 9, 29, 37, 127, 87, 153, 633, 1691, 2729, 3167, 3219, 21237, 25573}},
+{3769, 16, 1729, {1, 1, 5, 13, 19, 63, 93, 235, 299, 621, 405, 663, 6639, 12265, 9303, 42719}},
+{3770, 16, 1735, {1, 1, 3, 9, 25, 11, 9, 231, 101, 335, 1793, 1497, 7069, 4171, 30199, 63}},
+{3771, 16, 1769, {1, 1, 1, 1, 5, 19, 17, 217, 165, 413, 925, 1409, 6559, 14537, 22057, 44331}},
+{3772, 16, 1778, {1, 1, 3, 7, 11, 51, 45, 217, 57, 795, 951, 2933, 6705, 137, 30525, 9679}},
+{3773, 16, 1826, {1, 1, 3, 15, 27, 47, 35, 125, 363, 619, 1027, 2861, 3923, 10459, 16789, 27277}},
+{3774, 16, 1858, {1, 1, 7, 7, 13, 37, 33, 29, 385, 851, 143, 119, 7345, 4251, 25121, 31609}},
+{3775, 16, 1870, {1, 3, 1, 1, 17, 25, 119, 7, 365, 397, 601, 2087, 6903, 15345, 14671, 37889}},
+{3776, 16, 1875, {1, 3, 1, 13, 19, 51, 41, 139, 133, 723, 25, 2621, 1257, 7037, 9527, 50037}},
+{3777, 16, 1922, {1, 1, 5, 11, 5, 59, 119, 75, 397, 545, 1095, 585, 3271, 1049, 123, 33029}},
+{3778, 16, 1924, {1, 1, 7, 11, 9, 27, 21, 197, 177, 31, 453, 2457, 2733, 7787, 1923, 24639}},
+{3779, 16, 1933, {1, 1, 7, 13, 29, 13, 91, 91, 243, 279, 601, 1699, 7169, 4727, 7815, 29099}},
+{3780, 16, 1972, {1, 3, 7, 5, 1, 35, 27, 235, 163, 913, 1479, 769, 7179, 1983, 25977, 55373}},
+{3781, 16, 1979, {1, 3, 5, 11, 9, 33, 99, 141, 301, 109, 1785, 129, 1707, 5181, 4797, 9979}},
+{3782, 16, 1987, {1, 1, 1, 13, 3, 47, 89, 43, 293, 87, 1689, 3885, 7747, 5607, 477, 31887}},
+{3783, 16, 1994, {1, 1, 5, 1, 9, 21, 73, 37, 45, 621, 1855, 3691, 4899, 2191, 13459, 23543}},
+{3784, 16, 2008, {1, 1, 1, 1, 7, 39, 61, 125, 341, 905, 213, 1755, 241, 13407, 8791, 10165}},
+{3785, 16, 2023, {1, 1, 1, 1, 19, 31, 79, 19, 55, 875, 1017, 1787, 4879, 533, 15029, 52295}},
+{3786, 16, 2029, {1, 3, 1, 1, 9, 59, 113, 71, 113, 649, 561, 71, 5253, 783, 7389, 19361}},
+{3787, 16, 2053, {1, 1, 1, 11, 5, 39, 61, 225, 291, 907, 795, 1099, 597, 11829, 15137, 42865}},
+{3788, 16, 2081, {1, 3, 1, 5, 25, 11, 71, 155, 271, 309, 1981, 1253, 463, 1133, 20833, 48625}},
+{3789, 16, 2087, {1, 3, 5, 9, 7, 41, 87, 241, 457, 899, 1493, 3675, 3025, 10607, 22569, 52813}},
+{3790, 16, 2094, {1, 3, 7, 13, 7, 37, 37, 103, 281, 915, 1259, 4049, 559, 173, 4123, 63767}},
+{3791, 16, 2111, {1, 3, 7, 15, 13, 57, 9, 51, 39, 549, 1431, 2887, 1081, 4643, 16331, 14221}},
+{3792, 16, 2113, {1, 3, 5, 7, 13, 1, 101, 125, 25, 713, 1423, 513, 3323, 9951, 7163, 20969}},
+{3793, 16, 2114, {1, 1, 7, 15, 11, 25, 25, 3, 47, 531, 1529, 471, 6191, 10051, 29671, 49085}},
+{3794, 16, 2123, {1, 1, 3, 5, 23, 51, 117, 141, 55, 275, 761, 1923, 6267, 2291, 3701, 26615}},
+{3795, 16, 2190, {1, 1, 7, 9, 15, 19, 111, 65, 137, 373, 1753, 3591, 1137, 11639, 28591, 27265}},
+{3796, 16, 2231, {1, 3, 1, 15, 29, 5, 67, 13, 425, 961, 453, 2481, 1407, 3479, 23303, 30407}},
+{3797, 16, 2276, {1, 1, 5, 3, 19, 39, 39, 123, 351, 77, 1339, 1765, 3767, 1907, 13627, 23877}},
+{3798, 16, 2285, {1, 3, 5, 9, 23, 7, 103, 177, 221, 197, 561, 2121, 7231, 12053, 30127, 29849}},
+{3799, 16, 2297, {1, 1, 5, 7, 15, 1, 3, 123, 197, 493, 171, 2425, 3865, 4061, 31883, 2491}},
+{3800, 16, 2336, {1, 1, 3, 13, 29, 33, 99, 67, 327, 969, 1793, 1871, 1839, 13059, 7605, 16797}},
+{3801, 16, 2345, {1, 3, 5, 11, 25, 53, 25, 93, 303, 623, 1889, 1471, 1213, 14459, 8527, 25095}},
+{3802, 16, 2353, {1, 1, 1, 13, 15, 3, 115, 3, 289, 743, 1855, 359, 2375, 13765, 19711, 40765}},
+{3803, 16, 2363, {1, 1, 7, 11, 27, 51, 85, 163, 219, 871, 637, 2011, 5981, 587, 17521, 17333}},
+{3804, 16, 2368, {1, 3, 5, 1, 21, 59, 49, 39, 305, 513, 2017, 285, 5817, 13123, 27765, 46741}},
+{3805, 16, 2373, {1, 3, 3, 7, 21, 39, 71, 163, 423, 845, 783, 397, 7319, 10677, 13407, 47471}},
+{3806, 16, 2391, {1, 3, 7, 5, 21, 59, 99, 179, 473, 687, 1393, 723, 2245, 2933, 25943, 7769}},
+{3807, 16, 2402, {1, 1, 5, 9, 5, 45, 71, 189, 165, 555, 643, 2289, 3133, 12319, 22209, 1533}},
+{3808, 16, 2413, {1, 1, 3, 9, 7, 43, 1, 155, 323, 169, 339, 2561, 4049, 4953, 5289, 8783}},
+{3809, 16, 2422, {1, 3, 1, 11, 15, 5, 25, 201, 267, 891, 561, 501, 575, 15147, 1743, 45237}},
+{3810, 16, 2425, {1, 3, 5, 13, 25, 27, 105, 205, 165, 795, 975, 943, 7413, 10299, 14839, 54895}},
+{3811, 16, 2461, {1, 1, 5, 1, 17, 43, 69, 103, 449, 917, 103, 945, 513, 709, 11647, 28065}},
+{3812, 16, 2462, {1, 1, 3, 15, 23, 51, 23, 7, 159, 743, 177, 3457, 415, 1775, 25353, 36385}},
+{3813, 16, 2490, {1, 3, 5, 13, 9, 63, 121, 19, 165, 449, 1523, 1959, 6901, 12281, 29149, 45999}},
+{3814, 16, 2492, {1, 3, 7, 11, 17, 19, 9, 155, 373, 753, 1313, 2205, 3571, 16317, 16151, 15325}},
+{3815, 16, 2510, {1, 3, 3, 7, 15, 43, 65, 183, 407, 123, 1151, 375, 3461, 6673, 12985, 21005}},
+{3816, 16, 2564, {1, 3, 7, 7, 9, 1, 87, 247, 489, 123, 1677, 1947, 7961, 13497, 27919, 28993}},
+{3817, 16, 2573, {1, 3, 3, 7, 19, 21, 95, 227, 217, 133, 69, 1535, 699, 3521, 29255, 34733}},
+{3818, 16, 2598, {1, 3, 5, 3, 7, 57, 45, 251, 407, 81, 1259, 2425, 2217, 13097, 12773, 14643}},
+{3819, 16, 2627, {1, 1, 1, 11, 23, 37, 13, 229, 467, 591, 1521, 469, 3763, 2289, 14233, 24053}},
+{3820, 16, 2633, {1, 3, 5, 1, 27, 53, 105, 5, 85, 765, 1973, 2597, 5725, 1063, 18145, 961}},
+{3821, 16, 2647, {1, 3, 7, 1, 21, 47, 115, 95, 403, 3, 1593, 3379, 7371, 15553, 12503, 57979}},
+{3822, 16, 2660, {1, 1, 3, 1, 1, 35, 121, 29, 379, 245, 919, 2673, 3503, 14197, 31193, 8355}},
+{3823, 16, 2664, {1, 3, 5, 11, 19, 49, 97, 7, 195, 1013, 1671, 3415, 2009, 13389, 4837, 27453}},
+{3824, 16, 2678, {1, 1, 5, 13, 9, 15, 115, 97, 463, 449, 303, 2681, 1215, 12559, 15685, 21321}},
+{3825, 16, 2684, {1, 3, 5, 13, 23, 5, 113, 193, 419, 301, 1121, 317, 5503, 4683, 25519, 65}},
+{3826, 16, 2691, {1, 3, 3, 7, 15, 29, 45, 97, 323, 475, 143, 1173, 4033, 8939, 31849, 3575}},
+{3827, 16, 2759, {1, 1, 7, 7, 21, 1, 101, 143, 197, 409, 855, 1753, 5211, 3763, 11139, 37309}},
+{3828, 16, 2768, {1, 1, 3, 13, 25, 33, 55, 45, 381, 349, 991, 535, 4823, 3701, 31629, 48037}},
+{3829, 16, 2773, {1, 3, 1, 11, 17, 51, 27, 57, 409, 551, 949, 365, 8093, 10831, 19697, 39437}},
+{3830, 16, 2794, {1, 3, 5, 3, 31, 33, 81, 49, 91, 865, 469, 2115, 377, 8237, 31907, 38239}},
+{3831, 16, 2813, {1, 1, 3, 7, 29, 59, 57, 17, 121, 889, 1557, 1797, 5001, 14209, 21355, 59739}},
+{3832, 16, 2831, {1, 1, 5, 9, 11, 45, 89, 87, 397, 785, 525, 1593, 5251, 12449, 23579, 54265}},
+{3833, 16, 2843, {1, 3, 5, 11, 5, 31, 19, 47, 207, 331, 91, 1691, 5171, 53, 15945, 33349}},
+{3834, 16, 2846, {1, 1, 1, 15, 11, 41, 91, 177, 505, 871, 815, 3673, 5631, 9915, 1133, 37861}},
+{3835, 16, 2849, {1, 3, 5, 5, 25, 63, 53, 231, 55, 51, 481, 303, 1859, 11973, 28557, 22045}},
+{3836, 16, 2856, {1, 1, 5, 3, 27, 11, 37, 91, 363, 411, 1131, 3369, 377, 6585, 7353, 42949}},
+{3837, 16, 2893, {1, 3, 1, 9, 31, 63, 83, 23, 405, 941, 119, 1471, 2509, 15507, 29239, 49613}},
+{3838, 16, 2901, {1, 1, 5, 1, 11, 63, 117, 237, 407, 231, 1425, 71, 8005, 4023, 9029, 59819}},
+{3839, 16, 2924, {1, 1, 5, 7, 1, 9, 43, 87, 351, 63, 1075, 3381, 5447, 2437, 24983, 26905}},
+{3840, 16, 2942, {1, 3, 7, 5, 5, 35, 33, 89, 251, 819, 1735, 2625, 6363, 6837, 27603, 26669}},
+{3841, 16, 2975, {1, 3, 7, 13, 29, 63, 51, 245, 371, 791, 907, 3499, 3033, 8443, 20023, 1805}},
+{3842, 16, 2979, {1, 1, 5, 7, 13, 15, 109, 197, 451, 709, 929, 3193, 5727, 11185, 29479, 1671}},
+{3843, 16, 2985, {1, 1, 7, 13, 19, 23, 97, 9, 359, 635, 777, 39, 893, 2531, 13563, 19295}},
+{3844, 16, 3020, {1, 1, 5, 1, 31, 63, 55, 7, 157, 877, 991, 1317, 1595, 2019, 21435, 52255}},
+{3845, 16, 3025, {1, 1, 5, 3, 19, 37, 23, 13, 335, 431, 483, 615, 2431, 505, 26245, 63323}},
+{3846, 16, 3028, {1, 3, 7, 5, 5, 9, 37, 65, 303, 423, 1907, 2661, 7213, 2975, 29045, 16243}},
+{3847, 16, 3051, {1, 3, 1, 5, 13, 37, 115, 217, 227, 159, 707, 1387, 943, 4935, 5503, 35171}},
+{3848, 16, 3127, {1, 3, 7, 9, 19, 15, 87, 233, 453, 159, 169, 1077, 2129, 413, 19773, 629}},
+{3849, 16, 3142, {1, 1, 5, 15, 29, 39, 37, 243, 233, 365, 1843, 2219, 1255, 15287, 603, 13511}},
+{3850, 16, 3145, {1, 1, 3, 3, 31, 53, 33, 125, 497, 597, 127, 1829, 3905, 2611, 4263, 40971}},
+{3851, 16, 3156, {1, 3, 5, 9, 11, 47, 71, 215, 383, 321, 1445, 135, 5953, 8791, 22073, 16537}},
+{3852, 16, 3165, {1, 3, 3, 13, 15, 7, 7, 133, 401, 459, 1117, 3165, 4105, 11943, 22431, 56821}},
+{3853, 16, 3196, {1, 1, 7, 9, 31, 39, 19, 7, 19, 401, 79, 3641, 6815, 1489, 7537, 49467}},
+{3854, 16, 3199, {1, 3, 7, 7, 17, 11, 91, 205, 251, 321, 515, 3521, 311, 3169, 271, 34749}},
+{3855, 16, 3217, {1, 3, 3, 7, 29, 15, 5, 153, 83, 603, 1373, 997, 4939, 9811, 243, 5375}},
+{3856, 16, 3218, {1, 1, 3, 11, 21, 47, 25, 221, 237, 177, 535, 2819, 6213, 7877, 26795, 36609}},
+{3857, 16, 3253, {1, 3, 7, 3, 31, 1, 69, 73, 47, 653, 139, 1649, 7183, 1293, 26507, 38415}},
+{3858, 16, 3258, {1, 1, 1, 13, 17, 41, 23, 73, 115, 509, 787, 3733, 1871, 171, 29967, 39941}},
+{3859, 16, 3260, {1, 3, 5, 1, 9, 7, 61, 23, 105, 381, 1421, 2887, 3717, 643, 26375, 57991}},
+{3860, 16, 3289, {1, 3, 3, 3, 19, 3, 101, 117, 393, 83, 1255, 3331, 6481, 8661, 20855, 28875}},
+{3861, 16, 3314, {1, 3, 5, 11, 21, 13, 111, 193, 51, 899, 159, 1989, 7931, 10511, 3933, 447}},
+{3862, 16, 3326, {1, 1, 5, 15, 23, 35, 49, 139, 397, 145, 597, 1847, 7077, 715, 20227, 42183}},
+{3863, 16, 3331, {1, 3, 3, 3, 17, 3, 87, 233, 35, 317, 337, 237, 6901, 3439, 20033, 10307}},
+{3864, 16, 3371, {1, 3, 5, 3, 11, 35, 13, 171, 7, 963, 1443, 1501, 7617, 963, 25453, 62589}},
+{3865, 16, 3381, {1, 1, 1, 5, 11, 9, 39, 175, 409, 411, 1407, 2743, 4255, 989, 15823, 1707}},
+{3866, 16, 3396, {1, 1, 7, 13, 27, 55, 63, 239, 355, 417, 2007, 2299, 2921, 1637, 10687, 60615}},
+{3867, 16, 3441, {1, 1, 7, 9, 5, 61, 57, 73, 263, 307, 2003, 1763, 639, 5885, 14709, 16985}},
+{3868, 16, 3442, {1, 1, 3, 3, 21, 55, 19, 249, 509, 533, 1361, 1397, 2777, 15523, 4389, 13339}},
+{3869, 16, 3460, {1, 3, 5, 15, 9, 3, 91, 237, 451, 299, 1541, 4083, 879, 7859, 21585, 14833}},
+{3870, 16, 3477, {1, 1, 7, 3, 31, 47, 49, 231, 123, 391, 1633, 2567, 5577, 1631, 27951, 22913}},
+{3871, 16, 3491, {1, 3, 7, 13, 11, 13, 1, 111, 183, 87, 839, 1915, 5523, 3677, 13065, 38225}},
+{3872, 16, 3493, {1, 1, 3, 7, 15, 15, 63, 241, 167, 345, 653, 701, 4725, 12911, 11545, 24475}},
+{3873, 16, 3543, {1, 1, 3, 7, 25, 15, 49, 235, 331, 639, 965, 1117, 7147, 3789, 3309, 20255}},
+{3874, 16, 3549, {1, 3, 5, 7, 7, 63, 93, 241, 253, 31, 951, 3723, 3359, 7303, 191, 36427}},
+{3875, 16, 3550, {1, 3, 7, 9, 9, 59, 5, 107, 181, 413, 1269, 3121, 1929, 11921, 8931, 47459}},
+{3876, 16, 3553, {1, 3, 1, 15, 25, 27, 13, 47, 295, 111, 1287, 2551, 4887, 4145, 17063, 42037}},
+{3877, 16, 3563, {1, 3, 3, 13, 17, 17, 21, 17, 491, 845, 1463, 1305, 1375, 16149, 19331, 25043}},
+{3878, 16, 3568, {1, 3, 5, 1, 27, 5, 93, 139, 283, 711, 1141, 1743, 5001, 8851, 19351, 12275}},
+{3879, 16, 3604, {1, 1, 1, 1, 23, 25, 51, 63, 429, 735, 201, 3785, 6677, 16375, 19681, 17857}},
+{3880, 16, 3632, {1, 3, 3, 3, 9, 63, 71, 147, 463, 465, 1163, 1045, 6967, 12537, 31853, 38391}},
+{3881, 16, 3650, {1, 3, 7, 1, 5, 51, 79, 239, 389, 3, 601, 3787, 7635, 16295, 1681, 63971}},
+{3882, 16, 3662, {1, 3, 1, 3, 5, 31, 103, 89, 321, 971, 783, 3685, 1155, 10353, 2167, 35423}},
+{3883, 16, 3674, {1, 1, 5, 15, 25, 19, 93, 59, 361, 217, 1141, 597, 5877, 15961, 1593, 22925}},
+{3884, 16, 3685, {1, 3, 1, 9, 25, 59, 69, 89, 477, 89, 487, 237, 5625, 9579, 30421, 21883}},
+{3885, 16, 3686, {1, 1, 3, 7, 1, 5, 13, 225, 9, 981, 1081, 1407, 6855, 15215, 21713, 62313}},
+{3886, 16, 3700, {1, 1, 7, 15, 11, 13, 119, 109, 151, 245, 1195, 3741, 755, 8047, 15431, 21001}},
+{3887, 16, 3703, {1, 3, 7, 3, 17, 47, 107, 137, 99, 255, 1597, 3281, 5779, 13487, 15061, 19199}},
+{3888, 16, 3704, {1, 1, 3, 3, 9, 39, 77, 227, 511, 839, 1375, 3887, 25, 14763, 13259, 217}},
+{3889, 16, 3723, {1, 3, 5, 7, 17, 3, 87, 61, 439, 287, 709, 4085, 4251, 8945, 28203, 24011}},
+{3890, 16, 3743, {1, 3, 1, 1, 29, 25, 49, 101, 209, 359, 285, 1593, 4161, 2943, 23225, 6381}},
+{3891, 16, 3753, {1, 1, 3, 13, 1, 45, 87, 7, 491, 399, 905, 1403, 4791, 7419, 14355, 47767}},
+{3892, 16, 3756, {1, 1, 7, 15, 13, 25, 111, 197, 297, 301, 499, 4007, 2235, 7681, 4641, 32447}},
+{3893, 16, 3759, {1, 1, 3, 3, 27, 41, 97, 83, 405, 353, 1609, 201, 1503, 10673, 29377, 20445}},
+{3894, 16, 3762, {1, 1, 7, 3, 9, 47, 65, 191, 207, 545, 377, 3011, 7361, 3467, 14073, 46769}},
+{3895, 16, 3771, {1, 1, 7, 5, 7, 39, 9, 91, 187, 949, 1829, 161, 3689, 4145, 32675, 23263}},
+{3896, 16, 3776, {1, 1, 5, 9, 29, 9, 83, 113, 77, 673, 613, 3645, 6671, 8583, 27701, 18615}},
+{3897, 16, 3779, {1, 3, 5, 9, 29, 13, 127, 247, 285, 845, 463, 539, 4441, 1867, 12469, 16213}},
+{3898, 16, 3839, {1, 3, 7, 15, 1, 29, 47, 157, 239, 595, 563, 1103, 3431, 2849, 28125, 19969}},
+{3899, 16, 3856, {1, 1, 1, 15, 25, 13, 1, 131, 57, 257, 2021, 169, 7603, 10721, 21675, 63171}},
+{3900, 16, 3871, {1, 3, 5, 3, 5, 19, 31, 57, 275, 381, 775, 681, 1145, 12237, 5141, 29375}},
+{3901, 16, 3887, {1, 3, 5, 13, 27, 13, 47, 201, 267, 581, 1563, 3845, 951, 7209, 27253, 19755}},
+{3902, 16, 3896, {1, 3, 5, 15, 19, 35, 57, 17, 61, 273, 967, 3029, 1747, 1753, 31321, 23711}},
+{3903, 16, 3901, {1, 1, 1, 5, 13, 13, 7, 177, 335, 393, 1401, 1411, 4703, 8259, 1281, 39835}},
+{3904, 16, 3916, {1, 1, 3, 15, 25, 27, 27, 121, 183, 105, 663, 1375, 6987, 7151, 13763, 39323}},
+{3905, 16, 3919, {1, 3, 7, 5, 15, 1, 81, 129, 455, 163, 675, 81, 3735, 14409, 7269, 16425}},
+{3906, 16, 3937, {1, 3, 3, 11, 13, 7, 79, 157, 165, 663, 229, 3539, 1837, 6485, 30729, 42157}},
+{3907, 16, 3943, {1, 1, 5, 15, 9, 9, 9, 47, 133, 863, 43, 1461, 511, 13991, 24781, 19221}},
+{3908, 16, 3955, {1, 3, 1, 7, 31, 33, 103, 13, 159, 689, 1353, 4025, 6051, 7683, 1741, 30047}},
+{3909, 16, 3961, {1, 1, 3, 11, 5, 45, 71, 219, 475, 585, 1207, 3163, 4661, 4713, 12729, 30445}},
+{3910, 16, 3988, {1, 3, 7, 5, 5, 53, 101, 227, 129, 521, 91, 1129, 4683, 11235, 24697, 45055}},
+{3911, 16, 3997, {1, 1, 3, 13, 1, 43, 7, 1, 73, 857, 1713, 185, 1685, 2369, 24187, 40419}},
+{3912, 16, 4011, {1, 1, 7, 7, 21, 7, 13, 177, 503, 1003, 1091, 2411, 1433, 9063, 13901, 3329}},
+{3913, 16, 4026, {1, 1, 7, 1, 7, 41, 99, 203, 325, 249, 1763, 545, 2981, 14125, 7815, 11385}},
+{3914, 16, 4033, {1, 3, 7, 11, 3, 11, 95, 137, 325, 701, 1177, 1631, 4483, 2955, 30229, 25577}},
+{3915, 16, 4045, {1, 1, 7, 7, 17, 45, 77, 103, 143, 97, 1963, 3635, 1539, 10491, 23483, 22767}},
+{3916, 16, 4060, {1, 1, 7, 15, 7, 5, 81, 63, 243, 55, 39, 207, 2315, 8285, 8155, 11631}},
+{3917, 16, 4063, {1, 3, 5, 15, 23, 19, 115, 9, 125, 851, 161, 3767, 3513, 1855, 11139, 1719}},
+{3918, 16, 4064, {1, 3, 7, 11, 11, 23, 15, 13, 235, 5, 1039, 1425, 6485, 5539, 8967, 64809}},
+{3919, 16, 4126, {1, 3, 5, 7, 19, 11, 83, 135, 45, 905, 1081, 1857, 3185, 13555, 21365, 38143}},
+{3920, 16, 4136, {1, 1, 5, 1, 25, 27, 119, 109, 167, 847, 1539, 2653, 797, 11185, 23501, 22389}},
+{3921, 16, 4167, {1, 1, 7, 7, 11, 3, 51, 97, 277, 557, 207, 3645, 825, 8521, 26653, 60071}},
+{3922, 16, 4173, {1, 3, 3, 15, 17, 35, 57, 7, 267, 549, 97, 243, 1137, 10311, 6737, 19077}},
+{3923, 16, 4188, {1, 1, 1, 15, 23, 33, 27, 203, 415, 1023, 1145, 1881, 7715, 4413, 3727, 5185}},
+{3924, 16, 4195, {1, 1, 3, 3, 13, 47, 63, 13, 75, 505, 595, 2911, 4029, 14187, 23151, 42877}},
+{3925, 16, 4226, {1, 1, 5, 15, 23, 5, 11, 65, 147, 675, 1961, 2177, 727, 15077, 23759, 10195}},
+{3926, 16, 4291, {1, 3, 5, 9, 9, 39, 69, 229, 341, 627, 1331, 3139, 3921, 9219, 14887, 4659}},
+{3927, 16, 4298, {1, 1, 7, 3, 1, 35, 49, 71, 165, 83, 719, 2771, 6475, 7821, 16709, 4449}},
+{3928, 16, 4308, {1, 3, 5, 5, 23, 15, 3, 57, 465, 77, 121, 3767, 6841, 13601, 12035, 14075}},
+{3929, 16, 4312, {1, 1, 7, 3, 3, 23, 45, 131, 287, 941, 713, 415, 6865, 14209, 29555, 55493}},
+{3930, 16, 4336, {1, 3, 5, 11, 29, 35, 55, 75, 225, 779, 569, 1795, 1377, 12765, 19081, 47287}},
+{3931, 16, 4371, {1, 3, 7, 3, 31, 47, 127, 89, 157, 737, 1395, 3615, 7923, 14731, 15797, 40061}},
+{3932, 16, 4378, {1, 1, 1, 11, 21, 37, 21, 59, 9, 141, 193, 3095, 3435, 12371, 26931, 61861}},
+{3933, 16, 4384, {1, 1, 3, 7, 13, 51, 15, 153, 77, 1013, 651, 3949, 6229, 14297, 1039, 46139}},
+{3934, 16, 4393, {1, 3, 3, 13, 7, 43, 95, 61, 217, 3, 549, 739, 123, 3661, 15375, 13919}},
+{3935, 16, 4421, {1, 3, 5, 9, 13, 37, 101, 89, 55, 413, 1089, 775, 7575, 13063, 31393, 29583}},
+{3936, 16, 4425, {1, 1, 3, 9, 25, 63, 119, 143, 499, 145, 603, 2067, 4713, 13457, 14053, 117}},
+{3937, 16, 4439, {1, 1, 5, 9, 7, 23, 57, 253, 115, 591, 2003, 63, 7615, 11493, 28519, 47087}},
+{3938, 16, 4440, {1, 1, 7, 3, 7, 53, 121, 33, 233, 645, 1093, 1697, 7213, 2603, 10743, 51303}},
+{3939, 16, 4500, {1, 3, 5, 7, 13, 31, 17, 125, 93, 969, 159, 1529, 7165, 7371, 8707, 56953}},
+{3940, 16, 4514, {1, 3, 3, 1, 13, 9, 91, 25, 171, 843, 1635, 2043, 1043, 15893, 11409, 53689}},
+{3941, 16, 4523, {1, 3, 5, 7, 13, 19, 89, 97, 203, 923, 1109, 2061, 463, 11703, 8925, 56015}},
+{3942, 16, 4534, {1, 3, 5, 11, 5, 21, 79, 237, 195, 649, 717, 211, 919, 12855, 3045, 39659}},
+{3943, 16, 4593, {1, 1, 1, 15, 13, 19, 21, 69, 393, 257, 1263, 309, 3209, 8403, 24467, 6467}},
+{3944, 16, 4615, {1, 1, 1, 11, 7, 27, 59, 117, 379, 353, 943, 2513, 3869, 4567, 12989, 13139}},
+{3945, 16, 4630, {1, 1, 1, 3, 13, 43, 11, 15, 149, 237, 1555, 71, 2357, 15773, 21419, 40571}},
+{3946, 16, 4636, {1, 3, 1, 9, 19, 23, 59, 215, 15, 921, 1729, 249, 3785, 7171, 1233, 3449}},
+{3947, 16, 4645, {1, 1, 1, 7, 7, 37, 63, 205, 75, 599, 951, 2513, 3347, 2497, 8019, 5433}},
+{3948, 16, 4684, {1, 3, 3, 15, 27, 17, 25, 201, 23, 699, 1525, 465, 1115, 12299, 14747, 40363}},
+{3949, 16, 4687, {1, 1, 1, 3, 29, 59, 115, 233, 107, 815, 291, 3821, 7325, 7381, 21445, 33917}},
+{3950, 16, 4723, {1, 3, 1, 11, 11, 33, 107, 171, 421, 893, 587, 3373, 4101, 3885, 25383, 12035}},
+{3951, 16, 4735, {1, 3, 3, 7, 5, 23, 43, 51, 357, 77, 1327, 2995, 1321, 1571, 26419, 23603}},
+{3952, 16, 4746, {1, 3, 7, 9, 27, 57, 101, 51, 215, 215, 469, 303, 723, 2903, 30569, 42631}},
+{3953, 16, 4779, {1, 3, 3, 13, 1, 7, 63, 205, 143, 321, 1439, 253, 2667, 1271, 11761, 55631}},
+{3954, 16, 4782, {1, 1, 7, 9, 3, 7, 7, 15, 503, 875, 1619, 1715, 5047, 5665, 5503, 17745}},
+{3955, 16, 4793, {1, 1, 7, 15, 19, 49, 65, 31, 245, 371, 377, 2963, 6185, 5519, 10743, 33231}},
+{3956, 16, 4796, {1, 1, 7, 3, 25, 27, 115, 51, 299, 451, 285, 1709, 6153, 14881, 17861, 22071}},
+{3957, 16, 4813, {1, 3, 1, 5, 21, 21, 127, 185, 325, 995, 213, 3279, 4769, 15943, 2589, 29567}},
+{3958, 16, 4850, {1, 3, 7, 5, 21, 9, 63, 59, 159, 743, 663, 2965, 97, 8993, 25633, 29033}},
+{3959, 16, 4867, {1, 3, 7, 13, 3, 35, 59, 101, 21, 659, 1531, 3995, 795, 2143, 21749, 52715}},
+{3960, 16, 4874, {1, 3, 3, 15, 27, 29, 95, 1, 501, 425, 417, 2351, 7877, 4127, 3633, 23347}},
+{3961, 16, 4881, {1, 3, 5, 7, 7, 49, 55, 19, 329, 467, 425, 1609, 6987, 16123, 26879, 42883}},
+{3962, 16, 4894, {1, 1, 1, 15, 17, 21, 13, 13, 85, 7, 677, 3739, 5491, 6299, 29957, 55765}},
+{3963, 16, 4904, {1, 1, 1, 7, 31, 21, 1, 5, 193, 659, 979, 3409, 3151, 6615, 7445, 8151}},
+{3964, 16, 4927, {1, 3, 1, 1, 11, 61, 27, 205, 263, 805, 955, 3469, 1233, 1609, 15329, 13353}},
+{3965, 16, 4929, {1, 3, 3, 9, 3, 29, 59, 75, 149, 557, 663, 3887, 3369, 3397, 10611, 9511}},
+{3966, 16, 4989, {1, 1, 7, 13, 29, 21, 101, 139, 99, 411, 569, 2343, 6901, 1685, 20599, 49543}},
+{3967, 16, 5000, {1, 3, 3, 15, 11, 3, 87, 89, 5, 293, 291, 1405, 1489, 9877, 32505, 32263}},
+{3968, 16, 5020, {1, 1, 5, 5, 19, 45, 89, 5, 381, 253, 1339, 707, 4645, 14177, 29441, 8965}},
+{3969, 16, 5036, {1, 3, 7, 15, 27, 45, 25, 177, 81, 229, 1339, 2143, 6547, 6841, 23449, 14813}},
+{3970, 16, 5041, {1, 1, 1, 3, 27, 23, 81, 157, 53, 513, 1435, 277, 2353, 3545, 21461, 51479}},
+{3971, 16, 5059, {1, 3, 1, 3, 3, 17, 75, 139, 283, 881, 1157, 2081, 937, 14549, 10215, 13053}},
+{3972, 16, 5074, {1, 1, 7, 9, 25, 27, 27, 133, 21, 559, 225, 613, 6931, 11785, 23413, 35757}},
+{3973, 16, 5090, {1, 1, 3, 13, 19, 9, 65, 49, 453, 779, 621, 1151, 1807, 13269, 6515, 17113}},
+{3974, 16, 5110, {1, 1, 1, 13, 21, 49, 39, 79, 119, 401, 903, 493, 3779, 7389, 29425, 28091}},
+{3975, 16, 5134, {1, 3, 1, 3, 23, 57, 59, 213, 463, 839, 1201, 1951, 5197, 13035, 29657, 35517}},
+{3976, 16, 5152, {1, 3, 7, 7, 3, 49, 29, 181, 367, 101, 1277, 3329, 3563, 10373, 29757, 62555}},
+{3977, 16, 5176, {1, 3, 1, 7, 31, 31, 117, 213, 373, 57, 1095, 2733, 3431, 3915, 7665, 44459}},
+{3978, 16, 5181, {1, 1, 7, 5, 9, 25, 47, 117, 355, 495, 1367, 2579, 5617, 787, 27655, 18885}},
+{3979, 16, 5204, {1, 1, 1, 3, 9, 39, 113, 87, 107, 477, 891, 2273, 4239, 7521, 147, 1737}},
+{3980, 16, 5218, {1, 1, 1, 3, 13, 61, 81, 225, 113, 441, 889, 1915, 3897, 15179, 4053, 5925}},
+{3981, 16, 5242, {1, 1, 5, 3, 15, 47, 59, 187, 475, 197, 1381, 33, 4605, 1487, 14359, 33769}},
+{3982, 16, 5253, {1, 3, 7, 15, 23, 45, 53, 215, 129, 465, 795, 53, 7077, 9517, 2663, 55397}},
+{3983, 16, 5260, {1, 1, 7, 13, 25, 49, 105, 255, 245, 153, 1093, 2123, 2823, 5125, 17483, 49003}},
+{3984, 16, 5281, {1, 1, 1, 13, 31, 5, 7, 243, 255, 231, 1663, 1007, 7573, 405, 29183, 11367}},
+{3985, 16, 5282, {1, 1, 5, 13, 15, 15, 115, 91, 63, 1013, 1713, 1945, 6397, 14213, 24417, 40807}},
+{3986, 16, 5313, {1, 1, 5, 3, 19, 49, 91, 25, 43, 601, 25, 2405, 1973, 629, 497, 12625}},
+{3987, 16, 5316, {1, 1, 3, 5, 13, 45, 11, 81, 251, 545, 1155, 1409, 7187, 847, 2835, 32909}},
+{3988, 16, 5326, {1, 3, 1, 13, 27, 57, 1, 103, 465, 809, 1727, 3721, 3347, 3791, 17247, 8377}},
+{3989, 16, 5340, {1, 3, 3, 15, 25, 31, 91, 91, 119, 205, 1431, 703, 5327, 7323, 30415, 61955}},
+{3990, 16, 5347, {1, 3, 5, 11, 19, 39, 79, 243, 109, 463, 1869, 2133, 4139, 10461, 14793, 24025}},
+{3991, 16, 5354, {1, 3, 5, 7, 23, 41, 5, 7, 249, 3, 1743, 489, 4921, 397, 30955, 22207}},
+{3992, 16, 5368, {1, 3, 5, 15, 3, 7, 115, 19, 217, 231, 1183, 3723, 5055, 12967, 7855, 5067}},
+{3993, 16, 5394, {1, 3, 3, 3, 11, 31, 113, 41, 429, 797, 557, 1199, 1819, 1933, 9917, 32229}},
+{3994, 16, 5396, {1, 1, 5, 3, 13, 63, 31, 183, 465, 915, 723, 3227, 4125, 2813, 26313, 34287}},
+{3995, 16, 5400, {1, 1, 7, 5, 31, 55, 117, 243, 37, 885, 85, 1067, 3895, 15655, 28527, 32109}},
+{3996, 16, 5405, {1, 3, 7, 15, 17, 43, 43, 173, 119, 187, 1161, 599, 4595, 1681, 11981, 681}},
+{3997, 16, 5439, {1, 1, 7, 7, 29, 47, 25, 93, 411, 103, 783, 1029, 1927, 3569, 27647, 8281}},
+{3998, 16, 5442, {1, 3, 3, 9, 19, 57, 31, 183, 141, 889, 157, 2267, 5701, 6273, 25739, 34039}},
+{3999, 16, 5459, {1, 3, 5, 1, 29, 35, 105, 165, 505, 299, 1149, 2397, 2013, 11591, 15917, 4791}},
+{4000, 16, 5478, {1, 3, 3, 9, 7, 35, 47, 77, 69, 335, 585, 1131, 531, 8597, 307, 55985}},
+{4001, 16, 5484, {1, 3, 7, 1, 29, 9, 25, 155, 149, 845, 567, 3735, 3501, 9365, 12025, 19131}},
+{4002, 16, 5508, {1, 3, 5, 3, 11, 31, 25, 9, 411, 519, 1611, 1441, 1487, 10049, 14373, 24605}},
+{4003, 16, 5523, {1, 3, 3, 5, 3, 7, 101, 107, 339, 155, 1843, 2529, 443, 8177, 28655, 8151}},
+{4004, 16, 5545, {1, 1, 7, 5, 29, 37, 73, 131, 125, 451, 947, 797, 5053, 10155, 30801, 27235}},
+{4005, 16, 5565, {1, 1, 7, 13, 19, 47, 101, 45, 495, 457, 1293, 1971, 5495, 12737, 17687, 26123}},
+{4006, 16, 5566, {1, 1, 7, 7, 11, 11, 75, 177, 251, 553, 1883, 3379, 1429, 12227, 10301, 16467}},
+{4007, 16, 5580, {1, 3, 3, 9, 3, 61, 95, 35, 97, 551, 233, 2045, 4873, 9109, 10019, 64523}},
+{4008, 16, 5608, {1, 3, 1, 5, 11, 3, 15, 177, 301, 573, 2029, 191, 5551, 12083, 27287, 57235}},
+{4009, 16, 5613, {1, 3, 5, 1, 21, 9, 121, 169, 347, 187, 57, 3163, 5609, 1921, 17581, 28351}},
+{4010, 16, 5647, {1, 3, 3, 1, 31, 51, 15, 45, 429, 245, 573, 1595, 5343, 7519, 17009, 1299}},
+{4011, 16, 5661, {1, 1, 7, 3, 13, 47, 109, 65, 389, 867, 963, 145, 1089, 9749, 19625, 43121}},
+{4012, 16, 5671, {1, 3, 1, 7, 21, 61, 77, 67, 143, 579, 625, 2007, 6343, 4259, 21233, 237}},
+{4013, 16, 5678, {1, 3, 5, 9, 27, 15, 107, 91, 399, 895, 645, 2301, 439, 6789, 18299, 47285}},
+{4014, 16, 5680, {1, 3, 3, 5, 13, 11, 43, 199, 505, 409, 25, 2057, 479, 6031, 9561, 51613}},
+{4015, 16, 5685, {1, 1, 7, 13, 15, 55, 105, 53, 171, 925, 1849, 2881, 6951, 13069, 865, 41019}},
+{4016, 16, 5689, {1, 3, 1, 9, 17, 31, 45, 23, 411, 185, 189, 2123, 2583, 12713, 12681, 2231}},
+{4017, 16, 5692, {1, 3, 7, 9, 3, 63, 11, 253, 177, 127, 545, 3293, 4449, 15995, 10223, 33529}},
+{4018, 16, 5724, {1, 1, 5, 11, 13, 7, 53, 161, 421, 551, 697, 627, 3879, 1639, 24419, 3337}},
+{4019, 16, 5745, {1, 1, 7, 7, 27, 7, 37, 205, 429, 407, 1133, 3563, 2921, 6173, 11173, 3009}},
+{4020, 16, 5755, {1, 3, 3, 15, 31, 39, 117, 81, 337, 729, 567, 2299, 1481, 3189, 1795, 40299}},
+{4021, 16, 5757, {1, 3, 5, 15, 15, 47, 91, 127, 275, 55, 951, 3423, 2879, 6115, 1549, 2287}},
+{4022, 16, 5786, {1, 3, 3, 11, 17, 3, 127, 207, 141, 889, 185, 1095, 4567, 1371, 30545, 54445}},
+{4023, 16, 5792, {1, 1, 7, 3, 25, 11, 11, 139, 43, 1, 1977, 397, 5775, 6913, 13249, 46767}},
+{4024, 16, 5810, {1, 1, 7, 7, 27, 13, 31, 251, 191, 1015, 161, 3719, 5321, 13013, 25187, 51881}},
+{4025, 16, 5824, {1, 1, 1, 1, 3, 3, 13, 19, 423, 349, 1955, 2103, 6395, 3315, 23809, 25925}},
+{4026, 16, 5869, {1, 3, 5, 13, 3, 59, 41, 167, 423, 93, 1299, 2623, 5829, 8537, 8701, 43757}},
+{4027, 16, 5872, {1, 3, 5, 11, 9, 19, 127, 119, 329, 819, 7, 3809, 5305, 3643, 27369, 61827}},
+{4028, 16, 5895, {1, 3, 1, 15, 25, 43, 55, 159, 205, 911, 983, 2825, 3751, 7845, 12023, 18431}},
+{4029, 16, 5923, {1, 3, 3, 13, 11, 1, 65, 133, 479, 181, 679, 981, 3317, 6241, 11693, 9619}},
+{4030, 16, 5925, {1, 3, 3, 3, 21, 25, 117, 183, 127, 73, 703, 1469, 257, 11229, 10167, 50847}},
+{4031, 16, 5926, {1, 1, 5, 13, 5, 5, 113, 15, 231, 269, 989, 465, 3267, 15239, 29503, 42855}},
+{4032, 16, 5944, {1, 3, 3, 15, 9, 63, 79, 27, 21, 709, 1969, 3761, 1015, 13619, 4205, 40591}},
+{4033, 16, 5986, {1, 1, 7, 11, 29, 3, 5, 45, 107, 131, 1287, 3551, 849, 2003, 27451, 47103}},
+{4034, 16, 6012, {1, 3, 5, 11, 3, 47, 59, 53, 369, 249, 915, 2475, 7539, 763, 7063, 63971}},
+{4035, 16, 6015, {1, 1, 5, 1, 7, 53, 45, 127, 321, 341, 635, 2277, 1383, 10951, 29055, 45087}},
+{4036, 16, 6046, {1, 3, 7, 3, 5, 1, 119, 79, 487, 93, 25, 491, 4085, 6403, 27779, 8753}},
+{4037, 16, 6049, {1, 1, 1, 3, 9, 59, 49, 141, 323, 703, 1175, 423, 4323, 10083, 4289, 28931}},
+{4038, 16, 6061, {1, 3, 3, 15, 31, 31, 73, 15, 187, 653, 91, 1707, 1431, 9861, 19071, 8137}},
+{4039, 16, 6067, {1, 1, 1, 5, 27, 63, 93, 1, 329, 353, 863, 473, 7681, 10653, 15819, 8495}},
+{4040, 16, 6099, {1, 1, 1, 5, 25, 57, 119, 167, 219, 319, 231, 1065, 6217, 5131, 1513, 49281}},
+{4041, 16, 6121, {1, 3, 7, 3, 17, 3, 113, 91, 201, 179, 1907, 3423, 821, 12927, 24827, 49403}},
+{4042, 16, 6155, {1, 1, 5, 7, 19, 63, 75, 151, 387, 489, 777, 2049, 1151, 1351, 25687, 4143}},
+{4043, 16, 6163, {1, 3, 5, 7, 9, 37, 9, 3, 87, 385, 1667, 2139, 7527, 16133, 30023, 28783}},
+{4044, 16, 6203, {1, 1, 5, 9, 11, 55, 95, 73, 413, 867, 589, 2901, 3021, 413, 5955, 38921}},
+{4045, 16, 6208, {1, 3, 5, 15, 1, 17, 17, 7, 485, 323, 519, 2325, 2255, 4211, 20661, 28931}},
+{4046, 16, 6231, {1, 1, 5, 13, 21, 19, 85, 189, 167, 645, 1475, 3095, 7123, 3351, 7961, 20967}},
+{4047, 16, 6241, {1, 1, 7, 13, 3, 47, 13, 213, 237, 291, 285, 1465, 1765, 12361, 32651, 54205}},
+{4048, 16, 6254, {1, 3, 7, 13, 13, 27, 71, 35, 67, 117, 647, 2359, 3295, 8445, 24761, 29379}},
+{4049, 16, 6262, {1, 1, 1, 3, 3, 19, 23, 37, 5, 1019, 5, 1605, 2291, 14015, 9311, 39751}},
+{4050, 16, 6266, {1, 3, 3, 3, 31, 1, 65, 159, 221, 675, 1061, 971, 2333, 8265, 14361, 3263}},
+{4051, 16, 6275, {1, 1, 3, 7, 3, 5, 81, 17, 101, 991, 753, 2883, 4977, 4409, 1757, 26803}},
+{4052, 16, 6278, {1, 1, 5, 9, 13, 25, 45, 43, 199, 967, 829, 713, 4547, 7223, 6497, 53895}},
+{4053, 16, 6292, {1, 1, 7, 5, 23, 15, 89, 179, 509, 147, 315, 133, 111, 15577, 23427, 5229}},
+{4054, 16, 6329, {1, 3, 3, 7, 27, 7, 113, 65, 315, 135, 1309, 1179, 5755, 7513, 6815, 5137}},
+{4055, 16, 6355, {1, 1, 3, 7, 1, 13, 29, 155, 477, 721, 71, 865, 3897, 3331, 30641, 65471}},
+{4056, 16, 6357, {1, 1, 7, 3, 29, 45, 83, 3, 461, 109, 1545, 1365, 6633, 16137, 23859, 5995}},
+{4057, 16, 6374, {1, 3, 1, 1, 3, 33, 77, 83, 459, 187, 879, 3731, 6939, 6707, 23409, 24245}},
+{4058, 16, 6380, {1, 3, 5, 5, 13, 43, 127, 41, 29, 735, 1391, 2947, 4873, 4627, 15, 41719}},
+{4059, 16, 6423, {1, 3, 1, 3, 17, 17, 51, 93, 189, 227, 449, 2809, 825, 2009, 9563, 41435}},
+{4060, 16, 6427, {1, 3, 3, 11, 25, 47, 113, 173, 141, 919, 677, 117, 5293, 815, 23749, 19789}},
+{4061, 16, 6430, {1, 1, 1, 13, 15, 61, 121, 223, 53, 389, 489, 1527, 4771, 8975, 8005, 14275}},
+{4062, 16, 6436, {1, 1, 3, 15, 31, 57, 111, 145, 279, 991, 489, 3239, 7647, 473, 31279, 33447}},
+{4063, 16, 6443, {1, 1, 7, 5, 31, 13, 75, 185, 395, 611, 609, 159, 7931, 9887, 4115, 53121}},
+{4064, 16, 6445, {1, 3, 5, 5, 13, 39, 103, 237, 77, 913, 511, 1583, 6763, 14523, 4247, 63403}},
+{4065, 16, 6458, {1, 1, 1, 15, 11, 5, 43, 43, 297, 827, 747, 5, 3785, 15021, 11291, 36743}},
+{4066, 16, 6478, {1, 1, 7, 9, 9, 53, 113, 95, 403, 53, 1335, 4033, 8147, 11963, 6523, 23675}},
+{4067, 16, 6490, {1, 1, 5, 9, 27, 29, 69, 79, 327, 409, 1147, 1579, 2625, 12227, 30933, 9057}},
+{4068, 16, 6508, {1, 1, 1, 7, 1, 33, 29, 173, 5, 517, 437, 2035, 57, 12825, 22095, 65519}},
+{4069, 16, 6519, {1, 1, 3, 7, 27, 29, 53, 79, 429, 707, 589, 2605, 339, 7039, 19319, 17649}},
+{4070, 16, 6520, {1, 3, 3, 11, 9, 57, 43, 117, 39, 193, 1427, 2553, 6877, 7653, 29041, 44865}},
+{4071, 16, 6530, {1, 3, 3, 7, 23, 45, 29, 151, 265, 739, 365, 3565, 6447, 9761, 24021, 679}},
+{4072, 16, 6541, {1, 3, 5, 1, 1, 43, 73, 55, 131, 175, 959, 659, 7315, 15145, 18301, 14865}},
+{4073, 16, 6556, {1, 1, 3, 5, 15, 15, 91, 113, 359, 241, 1627, 1069, 1761, 211, 32671, 58833}},
+{4074, 16, 6607, {1, 3, 3, 7, 29, 27, 79, 53, 409, 81, 693, 3137, 7385, 11007, 28459, 28621}},
+{4075, 16, 6612, {1, 1, 7, 5, 29, 7, 67, 195, 77, 773, 1361, 2153, 4459, 7301, 5129, 17797}},
+{4076, 16, 6626, {1, 3, 3, 7, 25, 27, 91, 223, 115, 91, 1645, 2167, 1955, 9601, 22127, 13055}},
+{4077, 16, 6632, {1, 3, 7, 3, 27, 53, 67, 249, 51, 151, 663, 3231, 895, 6777, 3037, 56755}},
+{4078, 16, 6649, {1, 1, 5, 1, 25, 63, 71, 179, 375, 301, 1127, 2125, 783, 14481, 7293, 47883}},
+{4079, 16, 6666, {1, 1, 3, 9, 25, 3, 39, 69, 1, 85, 1271, 1571, 1953, 5077, 20369, 44827}},
+{4080, 16, 6674, {1, 3, 1, 13, 11, 61, 77, 59, 127, 475, 1609, 3553, 2553, 15589, 9351, 59787}},
+{4081, 16, 6733, {1, 3, 1, 5, 21, 7, 61, 27, 199, 653, 1243, 2481, 5369, 12903, 30229, 39453}},
+{4082, 16, 6782, {1, 3, 7, 3, 13, 15, 107, 153, 501, 573, 863, 3179, 6019, 15177, 16075, 43767}},
+{4083, 16, 6786, {1, 1, 7, 1, 23, 55, 17, 35, 5, 137, 1707, 1377, 6857, 15361, 27299, 61871}},
+{4084, 16, 6798, {1, 3, 5, 7, 27, 17, 87, 213, 95, 125, 1239, 3923, 4193, 11049, 12783, 45017}},
+{4085, 16, 6821, {1, 1, 5, 15, 9, 55, 11, 217, 7, 249, 369, 205, 4251, 13785, 24781, 48929}},
+{4086, 16, 6840, {1, 3, 7, 1, 15, 35, 33, 107, 503, 563, 1591, 3487, 7495, 1767, 24791, 31281}},
+{4087, 16, 6846, {1, 3, 1, 11, 3, 15, 47, 193, 289, 253, 909, 1105, 5119, 1415, 7737, 4341}},
+{4088, 16, 6865, {1, 1, 1, 3, 23, 33, 53, 187, 469, 573, 835, 2049, 791, 1177, 31051, 30955}},
+{4089, 16, 6884, {1, 3, 3, 11, 15, 51, 77, 143, 369, 991, 1103, 1293, 6019, 6361, 26301, 20741}},
+{4090, 16, 6891, {1, 1, 1, 5, 17, 19, 85, 135, 113, 593, 579, 1063, 7173, 2491, 9355, 19223}},
+{4091, 16, 6925, {1, 1, 5, 15, 25, 51, 107, 193, 31, 1, 1693, 125, 6223, 14619, 22683, 26321}},
+{4092, 16, 6938, {1, 1, 7, 1, 17, 45, 87, 39, 87, 499, 1185, 2763, 3989, 2863, 24555, 33817}},
+{4093, 16, 6967, {1, 3, 1, 11, 31, 5, 121, 231, 185, 793, 255, 2785, 5261, 3687, 21711, 3941}},
+{4094, 16, 6988, {1, 3, 7, 15, 5, 59, 73, 227, 365, 937, 893, 2155, 4385, 14345, 6813, 28461}},
+{4095, 16, 6996, {1, 1, 5, 7, 7, 23, 7, 239, 431, 45, 1015, 1663, 1893, 5035, 24075, 2119}},
+{4096, 16, 7009, {1, 3, 5, 1, 3, 15, 63, 103, 119, 801, 1681, 3463, 6083, 6453, 11379, 8205}},
+{4097, 16, 7016, {1, 3, 7, 9, 21, 61, 9, 9, 433, 541, 603, 3905, 3787, 10187, 3643, 21319}},
+{4098, 16, 7030, {1, 3, 5, 3, 11, 1, 101, 243, 363, 559, 561, 1163, 455, 4657, 1147, 39961}},
+{4099, 16, 7043, {1, 3, 5, 13, 17, 37, 57, 47, 483, 571, 1579, 1137, 8125, 12271, 23279, 1615}},
+{4100, 16, 7045, {1, 3, 5, 1, 21, 5, 13, 155, 75, 705, 389, 2855, 6345, 2279, 12627, 49451}},
+{4101, 16, 7052, {1, 1, 3, 9, 15, 51, 73, 99, 445, 227, 1705, 2175, 8111, 9381, 31555, 48491}},
+{4102, 16, 7073, {1, 3, 3, 5, 9, 63, 107, 51, 461, 979, 1033, 421, 4807, 11707, 13261, 26015}},
+{4103, 16, 7142, {1, 1, 5, 3, 13, 53, 117, 249, 57, 851, 1391, 3245, 35, 16043, 24399, 63667}},
+{4104, 16, 7153, {1, 3, 1, 11, 23, 33, 57, 125, 385, 495, 871, 199, 4269, 2269, 22897, 23597}},
+{4105, 16, 7168, {1, 3, 5, 15, 29, 11, 77, 21, 479, 369, 723, 3721, 1121, 9463, 19775, 54525}},
+{4106, 16, 7174, {1, 3, 5, 7, 7, 45, 29, 153, 395, 223, 1917, 3713, 5087, 10827, 1383, 36823}},
+{4107, 16, 7183, {1, 3, 1, 3, 31, 19, 111, 55, 275, 923, 917, 2925, 673, 6579, 18783, 5137}},
+{4108, 16, 7195, {1, 3, 1, 15, 25, 31, 59, 255, 31, 697, 1751, 381, 299, 295, 14037, 40953}},
+{4109, 16, 7204, {1, 3, 1, 7, 15, 23, 69, 219, 351, 183, 1083, 2227, 6249, 9385, 13167, 2901}},
+{4110, 16, 7214, {1, 3, 7, 1, 5, 61, 117, 13, 67, 521, 41, 2929, 3937, 1215, 25593, 32627}},
+{4111, 16, 7222, {1, 3, 5, 1, 9, 47, 63, 39, 371, 657, 491, 2243, 4049, 10517, 12409, 40597}},
+{4112, 16, 7267, {1, 3, 7, 15, 17, 3, 77, 13, 275, 225, 487, 2055, 1293, 15927, 31773, 18275}},
+{4113, 16, 7269, {1, 1, 5, 13, 11, 57, 113, 27, 191, 363, 1341, 3487, 8031, 13801, 7563, 40675}},
+{4114, 16, 7279, {1, 1, 3, 3, 27, 31, 103, 143, 271, 305, 2033, 3623, 4219, 9307, 7501, 8959}},
+{4115, 16, 7293, {1, 1, 1, 13, 1, 3, 27, 97, 475, 143, 333, 2997, 1807, 4231, 27437, 59717}},
+{4116, 16, 7312, {1, 3, 7, 5, 5, 3, 69, 233, 309, 511, 1429, 1887, 2745, 4969, 17595, 5451}},
+{4117, 16, 7327, {1, 1, 7, 3, 23, 17, 115, 89, 265, 467, 257, 2027, 5331, 1195, 4451, 8621}},
+{4118, 16, 7334, {1, 1, 7, 13, 29, 35, 117, 155, 99, 327, 853, 3595, 2997, 10745, 21619, 26549}},
+{4119, 16, 7337, {1, 3, 3, 13, 1, 13, 75, 151, 67, 271, 1609, 1117, 4293, 4645, 12005, 55983}},
+{4120, 16, 7343, {1, 1, 1, 13, 1, 61, 101, 63, 161, 261, 1759, 567, 665, 2339, 9157, 55603}},
+{4121, 16, 7346, {1, 1, 7, 11, 25, 19, 71, 27, 255, 435, 227, 4087, 4309, 14903, 14513, 30207}},
+{4122, 16, 7372, {1, 3, 3, 3, 11, 41, 1, 67, 383, 403, 45, 1521, 1535, 3353, 27361, 7549}},
+{4123, 16, 7387, {1, 1, 1, 1, 13, 51, 31, 137, 147, 907, 19, 3639, 3739, 877, 15005, 60357}},
+{4124, 16, 7390, {1, 1, 3, 11, 11, 23, 29, 173, 105, 873, 1727, 2761, 2015, 7491, 17491, 41065}},
+{4125, 16, 7396, {1, 1, 5, 3, 31, 1, 119, 53, 11, 731, 393, 4031, 4421, 15715, 6431, 18089}},
+{4126, 16, 7423, {1, 1, 3, 5, 15, 37, 55, 147, 307, 521, 711, 3085, 5989, 8081, 23351, 35259}},
+{4127, 16, 7428, {1, 3, 5, 13, 21, 19, 47, 107, 447, 713, 1655, 2809, 4741, 2105, 9255, 103}},
+{4128, 16, 7437, {1, 3, 1, 3, 17, 47, 63, 125, 343, 763, 1777, 607, 5625, 9517, 7221, 27257}},
+{4129, 16, 7466, {1, 1, 7, 5, 31, 13, 67, 255, 41, 947, 99, 721, 7367, 11427, 1357, 12383}},
+{4130, 16, 7474, {1, 1, 7, 3, 23, 27, 73, 185, 189, 545, 1877, 3169, 5419, 15873, 29059, 23983}},
+{4131, 16, 7476, {1, 1, 3, 1, 5, 13, 81, 45, 79, 717, 819, 3539, 7561, 7319, 5113, 27273}},
+{4132, 16, 7483, {1, 3, 7, 9, 21, 25, 71, 247, 41, 583, 771, 3745, 1883, 5717, 755, 14549}},
+{4133, 16, 7518, {1, 1, 3, 7, 23, 25, 87, 143, 499, 515, 1753, 1229, 173, 10629, 30579, 29643}},
+{4134, 16, 7527, {1, 3, 1, 13, 29, 33, 31, 69, 503, 117, 1717, 101, 7647, 1567, 28677, 3079}},
+{4135, 16, 7545, {1, 3, 1, 15, 29, 45, 57, 81, 171, 813, 505, 3647, 3913, 5557, 2477, 42429}},
+{4136, 16, 7572, {1, 1, 5, 13, 21, 13, 81, 5, 471, 221, 1563, 1741, 7269, 16327, 22687, 5291}},
+{4137, 16, 7586, {1, 3, 5, 3, 23, 41, 107, 61, 95, 79, 467, 1533, 739, 6791, 26911, 20309}},
+{4138, 16, 7597, {1, 3, 7, 7, 3, 53, 71, 163, 459, 975, 687, 1115, 5241, 299, 26361, 38583}},
+{4139, 16, 7630, {1, 3, 1, 9, 3, 63, 7, 133, 421, 325, 823, 1175, 6201, 5707, 31539, 34645}},
+{4140, 16, 7653, {1, 3, 7, 5, 27, 27, 107, 239, 247, 257, 1367, 3685, 7839, 11693, 3237, 13085}},
+{4141, 16, 7657, {1, 1, 1, 3, 27, 41, 51, 69, 271, 809, 1453, 519, 1301, 2367, 637, 5267}},
+{4142, 16, 7671, {1, 3, 7, 13, 19, 17, 3, 69, 369, 447, 1685, 4075, 6143, 11387, 5411, 29825}},
+{4143, 16, 7672, {1, 1, 3, 1, 25, 61, 79, 163, 1, 905, 1969, 2735, 7709, 16121, 20441, 4543}},
+{4144, 16, 7715, {1, 3, 7, 5, 15, 29, 7, 245, 343, 803, 1719, 3993, 983, 2925, 10393, 6053}},
+{4145, 16, 7717, {1, 3, 1, 7, 17, 55, 63, 29, 441, 387, 885, 3269, 1977, 1927, 3657, 47043}},
+{4146, 16, 7732, {1, 1, 3, 1, 17, 59, 51, 9, 173, 327, 1185, 3241, 3785, 10907, 19429, 22209}},
+{4147, 16, 7735, {1, 1, 3, 13, 21, 57, 125, 5, 359, 437, 1231, 2441, 5813, 9991, 283, 52555}},
+{4148, 16, 7753, {1, 3, 1, 7, 15, 19, 39, 125, 405, 381, 1757, 4075, 5565, 2065, 295, 8867}},
+{4149, 16, 7811, {1, 3, 3, 11, 7, 33, 95, 19, 253, 141, 1093, 1787, 7495, 5229, 15923, 44157}},
+{4150, 16, 7817, {1, 3, 7, 15, 1, 49, 69, 163, 85, 345, 901, 2329, 8003, 9915, 2209, 33979}},
+{4151, 16, 7825, {1, 1, 1, 9, 23, 51, 125, 163, 257, 681, 565, 945, 6375, 8679, 5985, 28919}},
+{4152, 16, 7832, {1, 3, 5, 7, 11, 23, 123, 231, 377, 121, 1519, 2061, 2957, 14537, 17625, 37773}},
+{4153, 16, 7838, {1, 3, 5, 1, 17, 43, 89, 119, 455, 279, 1857, 3405, 5225, 13035, 6055, 30861}},
+{4154, 16, 7841, {1, 3, 7, 15, 31, 63, 25, 225, 3, 527, 355, 1435, 5763, 15203, 26579, 45659}},
+{4155, 16, 7844, {1, 1, 1, 3, 27, 43, 71, 193, 135, 5, 683, 925, 7023, 7711, 2807, 56003}},
+{4156, 16, 7859, {1, 1, 1, 11, 3, 3, 109, 29, 109, 683, 419, 3295, 1961, 5953, 8887, 1523}},
+{4157, 16, 7861, {1, 3, 3, 11, 17, 39, 19, 225, 103, 249, 81, 3875, 4515, 3969, 24745, 60031}},
+{4158, 16, 7873, {1, 1, 3, 3, 3, 23, 15, 149, 305, 399, 1347, 1001, 597, 10003, 22123, 29919}},
+{4159, 16, 7880, {1, 3, 5, 1, 23, 35, 123, 7, 283, 283, 759, 3061, 2011, 7771, 32201, 40667}},
+{4160, 16, 7897, {1, 3, 7, 15, 23, 5, 81, 51, 357, 79, 133, 285, 425, 7743, 13499, 18983}},
+{4161, 16, 7904, {1, 3, 3, 5, 17, 37, 75, 221, 473, 111, 335, 683, 7353, 2283, 13457, 61171}},
+{4162, 16, 7910, {1, 3, 1, 7, 13, 45, 13, 223, 149, 209, 727, 3553, 2573, 177, 855, 44139}},
+{4163, 16, 7960, {1, 1, 3, 15, 23, 5, 103, 139, 17, 29, 1961, 3021, 5745, 12963, 30669, 44171}},
+{4164, 16, 7969, {1, 3, 1, 1, 3, 33, 67, 203, 29, 785, 71, 1693, 4487, 10221, 24523, 51223}},
+{4165, 16, 7970, {1, 1, 5, 7, 7, 27, 17, 183, 229, 669, 1675, 3751, 3233, 10677, 7509, 52313}},
+{4166, 16, 7976, {1, 1, 5, 5, 25, 35, 21, 163, 483, 399, 195, 3465, 6349, 545, 18861, 31759}},
+{4167, 16, 7979, {1, 3, 1, 5, 15, 39, 13, 157, 71, 841, 447, 3625, 53, 12745, 2719, 27617}},
+{4168, 16, 8007, {1, 1, 5, 5, 3, 45, 113, 121, 263, 887, 709, 2189, 3811, 1409, 10451, 48777}},
+{4169, 16, 8041, {1, 1, 5, 15, 9, 41, 31, 95, 377, 215, 437, 3633, 433, 11935, 15283, 55451}},
+{4170, 16, 8047, {1, 1, 7, 7, 13, 23, 79, 3, 451, 409, 1103, 1771, 553, 3175, 28703, 49357}},
+{4171, 16, 8052, {1, 3, 1, 1, 13, 33, 95, 133, 419, 851, 955, 3985, 5869, 14219, 253, 46883}},
+{4172, 16, 8061, {1, 3, 3, 3, 23, 55, 91, 207, 281, 355, 361, 261, 6837, 4401, 25455, 25313}},
+{4173, 16, 8078, {1, 3, 5, 9, 27, 9, 107, 51, 69, 555, 835, 3541, 1827, 5737, 31225, 55619}},
+{4174, 16, 8128, {1, 1, 1, 11, 27, 51, 79, 85, 447, 447, 9, 2803, 377, 4347, 2183, 61257}},
+{4175, 16, 8146, {1, 1, 1, 3, 23, 21, 51, 217, 297, 135, 573, 689, 4947, 14143, 26247, 43061}},
+{4176, 16, 8162, {1, 3, 1, 7, 15, 13, 27, 151, 463, 707, 43, 3641, 4999, 3783, 9083, 22085}},
+{4177, 16, 8250, {1, 3, 3, 5, 3, 1, 15, 119, 343, 605, 105, 2939, 2259, 889, 21759, 34073}},
+{4178, 16, 8270, {1, 1, 1, 7, 3, 63, 103, 1, 235, 317, 263, 2701, 7331, 15921, 17295, 613}},
+{4179, 16, 8294, {1, 1, 7, 3, 19, 3, 5, 17, 105, 491, 755, 233, 5397, 12365, 16325, 59377}},
+{4180, 16, 8324, {1, 3, 3, 15, 15, 27, 37, 151, 481, 949, 1473, 233, 1925, 15471, 24957, 3241}},
+{4181, 16, 8351, {1, 1, 7, 5, 9, 61, 49, 91, 169, 179, 701, 3957, 473, 15087, 6109, 25083}},
+{4182, 16, 8357, {1, 3, 3, 11, 27, 43, 5, 33, 69, 705, 733, 2675, 2677, 4235, 11109, 15557}},
+{4183, 16, 8361, {1, 3, 1, 3, 17, 19, 101, 119, 289, 341, 1395, 563, 6859, 10359, 10077, 26905}},
+{4184, 16, 8364, {1, 1, 1, 15, 21, 47, 41, 145, 439, 583, 1755, 1977, 5235, 15961, 21315, 60577}},
+{4185, 16, 8393, {1, 1, 5, 3, 9, 59, 71, 143, 27, 1007, 313, 1567, 1685, 11063, 28889, 44253}},
+{4186, 16, 8396, {1, 1, 5, 5, 29, 29, 43, 127, 13, 585, 1245, 187, 2697, 8791, 19561, 6463}},
+{4187, 16, 8407, {1, 1, 3, 11, 29, 39, 127, 75, 23, 521, 421, 3115, 139, 5429, 23341, 58035}},
+{4188, 16, 8413, {1, 1, 3, 1, 27, 35, 27, 9, 185, 653, 887, 2715, 3775, 1753, 22105, 62095}},
+{4189, 16, 8414, {1, 1, 5, 5, 5, 63, 23, 31, 317, 1001, 1751, 1185, 7933, 525, 30501, 15565}},
+{4190, 16, 8432, {1, 1, 1, 5, 9, 27, 79, 91, 453, 995, 1041, 3213, 8027, 5855, 7435, 64079}},
+{4191, 16, 8435, {1, 1, 3, 11, 1, 51, 27, 195, 139, 41, 1891, 1437, 1033, 11671, 3235, 35083}},
+{4192, 16, 8441, {1, 3, 1, 3, 11, 25, 33, 249, 373, 497, 1631, 293, 3657, 10741, 15831, 59545}},
+{4193, 16, 8447, {1, 1, 1, 1, 15, 63, 13, 165, 113, 559, 1615, 3579, 1993, 1907, 22335, 47791}},
+{4194, 16, 8449, {1, 1, 3, 15, 13, 49, 63, 235, 31, 811, 1729, 221, 5143, 11547, 30029, 52003}},
+{4195, 16, 8456, {1, 1, 5, 13, 29, 61, 25, 221, 421, 221, 583, 373, 2341, 7493, 13981, 54141}},
+{4196, 16, 8485, {1, 1, 5, 11, 21, 49, 71, 249, 237, 369, 1273, 1067, 4411, 409, 7219, 52933}},
+{4197, 16, 8504, {1, 3, 1, 1, 13, 23, 53, 15, 137, 553, 401, 2247, 5591, 14021, 445, 20433}},
+{4198, 16, 8512, {1, 1, 7, 7, 7, 23, 19, 189, 119, 643, 847, 2123, 5343, 11839, 4575, 60461}},
+{4199, 16, 8532, {1, 1, 5, 5, 11, 19, 111, 219, 185, 499, 595, 723, 3519, 10891, 27603, 29261}},
+{4200, 16, 8551, {1, 3, 3, 1, 9, 13, 95, 227, 459, 133, 1535, 3481, 7187, 14797, 16511, 6737}},
+{4201, 16, 8560, {1, 1, 7, 7, 19, 57, 117, 7, 455, 941, 455, 797, 6313, 10071, 18651, 25013}},
+{4202, 16, 8566, {1, 3, 7, 3, 25, 25, 79, 19, 383, 971, 1625, 2803, 2461, 633, 32317, 48407}},
+{4203, 16, 8581, {1, 1, 7, 7, 25, 43, 93, 135, 155, 685, 2001, 3007, 7315, 15555, 30401, 36291}},
+{4204, 16, 8609, {1, 1, 1, 5, 13, 33, 123, 221, 341, 105, 1075, 3125, 5323, 14293, 29875, 52215}},
+{4205, 16, 8639, {1, 1, 3, 9, 29, 51, 25, 59, 171, 563, 1695, 2845, 6067, 10671, 2909, 33977}},
+{4206, 16, 8641, {1, 3, 3, 7, 25, 21, 39, 65, 485, 949, 1773, 2775, 6019, 14587, 6715, 54793}},
+{4207, 16, 8671, {1, 1, 7, 11, 17, 57, 125, 17, 111, 167, 289, 3939, 7357, 2289, 1717, 45225}},
+{4208, 16, 8695, {1, 1, 7, 7, 21, 55, 3, 139, 471, 747, 1437, 1353, 7657, 13133, 14193, 38191}},
+{4209, 16, 8701, {1, 3, 5, 7, 25, 57, 55, 17, 315, 159, 437, 933, 7493, 6025, 2775, 24287}},
+{4210, 16, 8711, {1, 1, 7, 1, 15, 45, 67, 191, 355, 681, 1763, 1237, 105, 1425, 26089, 42879}},
+{4211, 16, 8739, {1, 1, 5, 13, 13, 53, 25, 127, 103, 155, 935, 2561, 475, 4341, 30541, 43835}},
+{4212, 16, 8763, {1, 1, 5, 15, 27, 59, 99, 173, 189, 41, 105, 3287, 4071, 15005, 18301, 34487}},
+{4213, 16, 8778, {1, 1, 5, 11, 21, 9, 57, 115, 495, 561, 579, 397, 3049, 2007, 5041, 37345}},
+{4214, 16, 8783, {1, 1, 5, 11, 15, 11, 101, 241, 69, 483, 1007, 4069, 5221, 5323, 20177, 24397}},
+{4215, 16, 8785, {1, 1, 1, 7, 29, 15, 119, 161, 21, 517, 847, 2217, 4487, 4817, 24053, 21683}},
+{4216, 16, 8797, {1, 3, 1, 3, 3, 51, 85, 63, 345, 799, 1699, 3961, 7109, 3931, 28173, 46851}},
+{4217, 16, 8802, {1, 1, 5, 7, 15, 25, 97, 139, 331, 969, 1129, 2451, 3107, 12235, 12949, 29837}},
+{4218, 16, 8816, {1, 3, 7, 1, 19, 21, 51, 155, 295, 565, 29, 2107, 341, 14611, 15281, 50727}},
+{4219, 16, 8828, {1, 3, 1, 11, 3, 37, 13, 217, 429, 217, 301, 1217, 5655, 13845, 32465, 23559}},
+{4220, 16, 8837, {1, 3, 3, 9, 9, 57, 79, 231, 433, 703, 699, 3813, 7035, 5885, 19185, 52551}},
+{4221, 16, 8852, {1, 1, 1, 5, 19, 17, 31, 209, 49, 515, 279, 909, 5881, 2673, 23635, 23101}},
+{4222, 16, 8859, {1, 1, 5, 7, 3, 3, 119, 139, 245, 775, 1009, 1157, 1405, 9737, 17671, 62981}},
+{4223, 16, 8889, {1, 3, 7, 11, 17, 21, 105, 21, 67, 871, 233, 3607, 571, 9141, 9751, 28093}},
+{4224, 16, 8900, {1, 1, 3, 13, 5, 53, 91, 181, 143, 375, 1113, 705, 837, 10505, 11459, 57753}},
+{4225, 16, 8903, {1, 3, 5, 11, 9, 19, 107, 229, 305, 107, 1027, 691, 4677, 8987, 7931, 951}},
+{4226, 16, 8909, {1, 1, 7, 9, 9, 17, 39, 195, 103, 315, 517, 123, 7167, 7039, 3571, 40469}},
+{4227, 16, 8910, {1, 1, 1, 5, 1, 21, 121, 53, 427, 111, 717, 1065, 2843, 5873, 28411, 42443}},
+{4228, 16, 8922, {1, 1, 3, 11, 27, 7, 37, 255, 429, 363, 997, 2429, 6871, 1271, 29375, 62897}},
+{4229, 16, 8924, {1, 3, 3, 13, 23, 23, 123, 119, 213, 51, 771, 1603, 1621, 1497, 23667, 13443}},
+{4230, 16, 8955, {1, 1, 3, 13, 17, 21, 81, 17, 211, 815, 1751, 3875, 4001, 3927, 6185, 28753}},
+{4231, 16, 8958, {1, 3, 1, 5, 13, 41, 23, 187, 475, 353, 1307, 543, 5077, 3459, 20553, 29119}},
+{4232, 16, 8980, {1, 1, 1, 7, 1, 39, 3, 247, 375, 101, 81, 1515, 1079, 15307, 18865, 63115}},
+{4233, 16, 8994, {1, 1, 5, 9, 23, 7, 61, 45, 379, 553, 435, 1805, 4147, 2289, 22081, 40041}},
+{4234, 16, 9006, {1, 1, 7, 3, 17, 13, 107, 169, 119, 981, 1825, 3329, 7779, 12245, 28367, 6749}},
+{4235, 16, 9017, {1, 3, 3, 13, 29, 13, 93, 155, 331, 507, 1073, 279, 6615, 14077, 3005, 10171}},
+{4236, 16, 9032, {1, 1, 5, 7, 29, 23, 81, 181, 321, 921, 1531, 2607, 7291, 1255, 29889, 30095}},
+{4237, 16, 9040, {1, 1, 1, 5, 7, 1, 9, 231, 203, 559, 243, 3999, 3649, 7939, 14729, 34771}},
+{4238, 16, 9061, {1, 3, 7, 3, 17, 29, 79, 251, 305, 641, 1125, 1155, 7139, 6721, 43, 34927}},
+{4239, 16, 9066, {1, 1, 5, 13, 21, 39, 55, 103, 143, 487, 849, 1111, 1105, 8483, 5417, 10521}},
+{4240, 16, 9071, {1, 1, 5, 5, 19, 5, 111, 49, 95, 917, 843, 2539, 6831, 9019, 16045, 59363}},
+{4241, 16, 9076, {1, 3, 3, 11, 7, 45, 87, 51, 49, 615, 603, 1623, 5351, 11939, 21945, 40539}},
+{4242, 16, 9086, {1, 1, 5, 9, 9, 33, 113, 37, 163, 853, 1313, 4021, 965, 11465, 8573, 24425}},
+{4243, 16, 9104, {1, 3, 3, 9, 17, 19, 121, 95, 93, 441, 1951, 3335, 6279, 16087, 14763, 60771}},
+{4244, 16, 9150, {1, 3, 3, 9, 13, 15, 19, 129, 257, 641, 533, 1667, 5959, 2259, 10439, 29745}},
+{4245, 16, 9161, {1, 1, 7, 7, 11, 31, 45, 247, 233, 101, 899, 2033, 7803, 11423, 30645, 7723}},
+{4246, 16, 9164, {1, 3, 5, 11, 23, 3, 69, 79, 319, 125, 1463, 2047, 7311, 5819, 445, 13725}},
+{4247, 16, 9185, {1, 1, 1, 3, 7, 43, 83, 89, 467, 709, 1993, 3773, 7805, 305, 15701, 51101}},
+{4248, 16, 9188, {1, 1, 7, 5, 19, 53, 77, 237, 27, 853, 1003, 2041, 5739, 4663, 9783, 23761}},
+{4249, 16, 9212, {1, 1, 3, 7, 19, 31, 71, 33, 479, 693, 1503, 9, 2779, 1481, 9413, 36227}},
+{4250, 16, 9230, {1, 3, 1, 11, 9, 23, 1, 99, 247, 33, 1987, 1577, 8029, 7785, 29947, 38751}},
+{4251, 16, 9242, {1, 1, 1, 3, 15, 57, 23, 53, 431, 553, 1433, 2447, 1871, 10701, 30961, 12281}},
+{4252, 16, 9247, {1, 3, 5, 9, 11, 49, 123, 91, 87, 155, 301, 3339, 6183, 15895, 17309, 45927}},
+{4253, 16, 9260, {1, 1, 1, 9, 9, 41, 79, 123, 261, 547, 1931, 2553, 7405, 14431, 24079, 20769}},
+{4254, 16, 9280, {1, 3, 1, 3, 31, 17, 17, 137, 419, 591, 1693, 3977, 861, 16025, 189, 60995}},
+{4255, 16, 9300, {1, 3, 7, 11, 19, 47, 107, 243, 87, 135, 507, 189, 1397, 3841, 22999, 50781}},
+{4256, 16, 9313, {1, 3, 5, 5, 15, 11, 19, 239, 133, 295, 673, 2389, 4753, 4363, 21669, 25579}},
+{4257, 16, 9325, {1, 3, 5, 7, 19, 43, 55, 129, 239, 89, 1731, 1381, 5483, 11773, 9201, 17745}},
+{4258, 16, 9343, {1, 3, 1, 13, 3, 15, 77, 131, 417, 845, 1953, 2871, 1789, 10343, 11363, 20699}},
+{4259, 16, 9349, {1, 3, 7, 1, 9, 43, 55, 223, 239, 317, 1951, 2725, 209, 3853, 2201, 6839}},
+{4260, 16, 9354, {1, 3, 1, 3, 7, 35, 29, 21, 149, 779, 467, 65, 811, 4859, 14021, 38429}},
+{4261, 16, 9367, {1, 3, 7, 1, 19, 31, 97, 9, 11, 415, 689, 1513, 2475, 5039, 5669, 65103}},
+{4262, 16, 9368, {1, 3, 3, 3, 11, 25, 37, 247, 189, 911, 429, 2395, 3653, 79, 28115, 23513}},
+{4263, 16, 9455, {1, 1, 5, 5, 5, 27, 25, 45, 291, 455, 741, 2259, 8131, 11779, 14693, 58729}},
+{4264, 16, 9458, {1, 3, 3, 7, 21, 33, 67, 49, 153, 491, 1811, 1955, 925, 15555, 13801, 48717}},
+{4265, 16, 9469, {1, 3, 1, 3, 11, 53, 105, 129, 457, 225, 497, 1123, 973, 2901, 26655, 3643}},
+{4266, 16, 9481, {1, 1, 7, 13, 29, 49, 71, 37, 321, 865, 735, 357, 7629, 6011, 28221, 39041}},
+{4267, 16, 9482, {1, 3, 5, 3, 19, 59, 65, 199, 69, 391, 1735, 3075, 287, 16213, 3211, 22425}},
+{4268, 16, 9495, {1, 1, 1, 5, 15, 61, 67, 255, 5, 689, 759, 155, 7245, 5881, 21685, 3863}},
+{4269, 16, 9526, {1, 1, 3, 11, 23, 63, 69, 241, 359, 735, 371, 603, 2707, 15833, 31795, 14901}},
+{4270, 16, 9530, {1, 1, 1, 7, 19, 33, 83, 19, 13, 667, 317, 3891, 5497, 8213, 4913, 22387}},
+{4271, 16, 9558, {1, 3, 5, 9, 13, 21, 11, 187, 249, 647, 349, 605, 2199, 5033, 29773, 48953}},
+{4272, 16, 9562, {1, 3, 3, 11, 3, 3, 93, 235, 441, 933, 383, 2007, 4015, 4175, 3937, 20623}},
+{4273, 16, 9573, {1, 3, 7, 13, 3, 61, 87, 219, 263, 651, 1343, 2709, 31, 16249, 4749, 28909}},
+{4274, 16, 9583, {1, 3, 1, 1, 17, 19, 101, 107, 499, 127, 13, 2123, 5597, 3751, 14527, 12009}},
+{4275, 16, 9595, {1, 3, 5, 13, 27, 57, 1, 195, 107, 947, 1475, 2831, 6449, 16117, 20555, 61513}},
+{4276, 16, 9597, {1, 3, 1, 9, 9, 47, 89, 187, 401, 299, 637, 197, 1235, 12655, 25025, 24443}},
+{4277, 16, 9616, {1, 1, 3, 5, 9, 57, 33, 41, 451, 983, 391, 2707, 705, 13913, 28843, 34091}},
+{4278, 16, 9638, {1, 3, 5, 3, 29, 19, 61, 31, 349, 253, 1267, 3345, 2151, 11309, 19623, 62407}},
+{4279, 16, 9649, {1, 1, 1, 3, 11, 37, 31, 59, 1, 253, 103, 2811, 1871, 4239, 26311, 32507}},
+{4280, 16, 9662, {1, 1, 5, 7, 7, 7, 69, 63, 281, 901, 1785, 2131, 4265, 253, 13997, 30177}},
+{4281, 16, 9691, {1, 3, 1, 11, 3, 27, 111, 67, 411, 751, 241, 293, 6271, 4187, 22119, 63737}},
+{4282, 16, 9700, {1, 3, 5, 5, 27, 19, 45, 203, 81, 59, 1839, 935, 4847, 1869, 12037, 30971}},
+{4283, 16, 9703, {1, 1, 3, 9, 19, 25, 9, 27, 373, 875, 1735, 689, 2957, 7873, 29771, 4093}},
+{4284, 16, 9710, {1, 1, 7, 11, 13, 39, 11, 129, 53, 433, 1731, 899, 5855, 10221, 24165, 50205}},
+{4285, 16, 9721, {1, 3, 1, 15, 25, 31, 85, 49, 325, 299, 183, 287, 2425, 15353, 25999, 59129}},
+{4286, 16, 9724, {1, 1, 5, 5, 17, 25, 23, 5, 287, 677, 591, 981, 429, 15297, 14573, 61095}},
+{4287, 16, 9727, {1, 1, 5, 15, 5, 15, 67, 195, 209, 341, 1621, 1379, 3031, 5469, 31563, 49291}},
+{4288, 16, 9743, {1, 1, 1, 1, 25, 33, 61, 201, 15, 125, 969, 1965, 2021, 10253, 23801, 28165}},
+{4289, 16, 9779, {1, 1, 5, 5, 13, 17, 5, 245, 11, 133, 287, 1929, 4331, 15919, 29663, 10243}},
+{4290, 16, 9785, {1, 1, 7, 9, 19, 33, 39, 191, 489, 631, 69, 1883, 2183, 14993, 32715, 62217}},
+{4291, 16, 9811, {1, 3, 3, 13, 23, 61, 103, 193, 501, 431, 437, 417, 6557, 11701, 27577, 42943}},
+{4292, 16, 9820, {1, 3, 3, 9, 9, 27, 69, 247, 469, 841, 733, 813, 2673, 7145, 5385, 44917}},
+{4293, 16, 9827, {1, 1, 7, 9, 5, 13, 19, 71, 323, 923, 1885, 3031, 4507, 13787, 14149, 1483}},
+{4294, 16, 9851, {1, 3, 1, 5, 1, 15, 89, 229, 301, 733, 1343, 2415, 6463, 1875, 9293, 6037}},
+{4295, 16, 9854, {1, 3, 1, 5, 29, 57, 67, 121, 311, 441, 1079, 1963, 7137, 6745, 9893, 22811}},
+{4296, 16, 9863, {1, 1, 7, 7, 25, 13, 27, 61, 331, 361, 481, 3783, 3061, 7827, 18885, 27583}},
+{4297, 16, 9884, {1, 3, 1, 5, 17, 47, 19, 83, 309, 65, 1573, 3437, 5623, 12691, 21075, 27789}},
+{4298, 16, 9894, {1, 1, 7, 9, 13, 51, 7, 209, 131, 111, 1143, 53, 7277, 9297, 20869, 33121}},
+{4299, 16, 9903, {1, 1, 3, 9, 13, 17, 57, 89, 239, 281, 775, 333, 5631, 2805, 10195, 9665}},
+{4300, 16, 9908, {1, 1, 3, 7, 19, 39, 71, 79, 63, 551, 103, 3169, 2761, 13929, 20751, 18951}},
+{4301, 16, 9912, {1, 1, 7, 11, 5, 23, 7, 249, 447, 483, 433, 3117, 1421, 14991, 5397, 19813}},
+{4302, 16, 9925, {1, 3, 1, 13, 3, 9, 109, 241, 181, 33, 853, 3939, 3751, 2151, 28375, 64443}},
+{4303, 16, 9926, {1, 1, 7, 7, 3, 33, 65, 211, 251, 631, 1819, 3913, 3353, 12975, 19117, 51515}},
+{4304, 16, 9971, {1, 1, 1, 13, 3, 21, 9, 203, 223, 229, 1399, 117, 6297, 11535, 16383, 12541}},
+{4305, 16, 9973, {1, 1, 5, 7, 25, 9, 53, 27, 497, 103, 1915, 2179, 3679, 11375, 18907, 63385}},
+{4306, 16, 9977, {1, 3, 1, 5, 1, 53, 91, 169, 87, 387, 377, 1121, 7241, 5133, 1949, 13433}},
+{4307, 16, 10021, {1, 1, 1, 3, 27, 35, 61, 189, 241, 445, 287, 325, 127, 2363, 30663, 43557}},
+{4308, 16, 10039, {1, 3, 1, 3, 17, 47, 59, 237, 213, 979, 807, 85, 4621, 9915, 13631, 55657}},
+{4309, 16, 10048, {1, 3, 5, 7, 27, 5, 101, 89, 495, 675, 1181, 2295, 1913, 3731, 32639, 58297}},
+{4310, 16, 10051, {1, 3, 3, 11, 5, 41, 49, 229, 93, 659, 927, 3425, 4083, 11859, 10603, 20631}},
+{4311, 16, 10065, {1, 3, 5, 11, 31, 51, 67, 69, 253, 497, 1665, 1985, 5439, 15999, 4175, 62175}},
+{4312, 16, 10071, {1, 1, 7, 11, 1, 21, 95, 19, 205, 513, 1329, 1821, 1251, 2381, 32623, 23923}},
+{4313, 16, 10072, {1, 1, 5, 13, 3, 1, 29, 175, 315, 865, 599, 1695, 1391, 2313, 31035, 19159}},
+{4314, 16, 10101, {1, 3, 3, 1, 3, 45, 109, 93, 481, 285, 869, 3441, 3715, 1355, 9581, 50173}},
+{4315, 16, 10106, {1, 3, 7, 7, 15, 35, 107, 107, 315, 213, 281, 2073, 4689, 5877, 31, 40967}},
+{4316, 16, 10130, {1, 1, 3, 11, 11, 3, 73, 41, 79, 37, 481, 1993, 931, 7677, 11321, 45735}},
+{4317, 16, 10136, {1, 1, 7, 1, 15, 21, 65, 237, 263, 849, 863, 4039, 3171, 13381, 30373, 51639}},
+{4318, 16, 10148, {1, 1, 1, 3, 21, 57, 113, 3, 487, 41, 1277, 633, 2839, 4977, 14537, 31749}},
+{4319, 16, 10155, {1, 1, 5, 1, 1, 55, 71, 181, 147, 895, 1839, 2157, 3187, 6403, 30367, 48915}},
+{4320, 16, 10157, {1, 1, 5, 3, 9, 17, 19, 127, 115, 875, 831, 2439, 7475, 1921, 18657, 27709}},
+{4321, 16, 10160, {1, 3, 3, 13, 29, 11, 35, 81, 291, 483, 625, 3957, 6017, 12543, 18773, 2471}},
+{4322, 16, 10166, {1, 3, 3, 13, 11, 39, 7, 85, 493, 209, 819, 3277, 4275, 8997, 22943, 33199}},
+{4323, 16, 10183, {1, 1, 1, 7, 11, 25, 1, 57, 505, 135, 1713, 3051, 5893, 10711, 10681, 12235}},
+{4324, 16, 10192, {1, 3, 5, 11, 23, 33, 13, 107, 289, 251, 235, 1747, 4097, 12237, 17559, 5063}},
+{4325, 16, 10225, {1, 3, 3, 9, 19, 17, 23, 45, 297, 147, 1301, 2057, 7871, 9971, 1965, 62449}},
+{4326, 16, 10241, {1, 1, 7, 3, 17, 21, 19, 203, 289, 897, 1967, 3519, 3261, 8199, 24181, 23273}},
+{4327, 16, 10247, {1, 1, 7, 11, 1, 17, 25, 63, 509, 969, 47, 1329, 701, 5227, 419, 14839}},
+{4328, 16, 10284, {1, 3, 5, 11, 1, 41, 81, 157, 395, 97, 1919, 3043, 6015, 15, 23733, 55485}},
+{4329, 16, 10304, {1, 1, 3, 11, 17, 37, 17, 181, 179, 297, 1007, 1559, 6275, 11645, 7535, 28941}},
+{4330, 16, 10322, {1, 3, 7, 15, 5, 47, 31, 237, 215, 563, 207, 1867, 6635, 6857, 11837, 22865}},
+{4331, 16, 10331, {1, 3, 1, 7, 7, 39, 51, 179, 57, 987, 893, 2715, 1045, 5799, 19805, 54275}},
+{4332, 16, 10333, {1, 1, 7, 15, 25, 9, 127, 243, 323, 1013, 929, 2891, 7549, 1071, 17663, 15247}},
+{4333, 16, 10340, {1, 1, 1, 5, 25, 23, 101, 9, 371, 89, 1749, 3559, 8071, 13887, 14807, 42825}},
+{4334, 16, 10347, {1, 3, 3, 11, 21, 41, 3, 77, 3, 709, 1745, 3615, 4141, 5275, 28329, 59739}},
+{4335, 16, 10357, {1, 1, 7, 13, 1, 11, 73, 183, 363, 241, 863, 3983, 3235, 293, 649, 441}},
+{4336, 16, 10371, {1, 1, 5, 3, 13, 27, 13, 191, 57, 639, 1803, 2353, 3143, 12763, 5771, 36155}},
+{4337, 16, 10386, {1, 1, 5, 3, 1, 53, 85, 45, 283, 823, 1213, 3261, 4599, 13267, 4613, 12657}},
+{4338, 16, 10404, {1, 3, 5, 15, 27, 49, 59, 123, 357, 527, 337, 2751, 3999, 8525, 12501, 40621}},
+{4339, 16, 10414, {1, 1, 1, 7, 1, 55, 85, 17, 447, 599, 1315, 2313, 1649, 907, 25647, 3251}},
+{4340, 16, 10422, {1, 3, 5, 13, 9, 1, 37, 121, 143, 1, 631, 2273, 1673, 3649, 27533, 28731}},
+{4341, 16, 10448, {1, 1, 7, 13, 9, 31, 57, 249, 397, 815, 501, 895, 1217, 11387, 8635, 65193}},
+{4342, 16, 10451, {1, 1, 5, 5, 9, 35, 95, 193, 133, 513, 1929, 3841, 3063, 2383, 24413, 51185}},
+{4343, 16, 10473, {1, 1, 1, 13, 3, 49, 45, 191, 15, 181, 1819, 3741, 1227, 12775, 9461, 44951}},
+{4344, 16, 10479, {1, 1, 1, 1, 3, 45, 121, 19, 269, 829, 517, 3913, 183, 11019, 24969, 21973}},
+{4345, 16, 10501, {1, 1, 5, 11, 31, 39, 125, 189, 401, 57, 1557, 1727, 1415, 4025, 30353, 36589}},
+{4346, 16, 10530, {1, 1, 3, 9, 3, 55, 125, 187, 409, 499, 1853, 2781, 4323, 16159, 16345, 34659}},
+{4347, 16, 10542, {1, 3, 5, 11, 31, 5, 125, 137, 197, 475, 2003, 617, 1289, 8365, 28981, 57537}},
+{4348, 16, 10544, {1, 1, 1, 5, 19, 29, 83, 127, 311, 177, 1635, 2187, 5377, 12841, 7591, 6095}},
+{4349, 16, 10571, {1, 3, 5, 5, 21, 39, 65, 197, 115, 411, 1457, 3011, 7021, 14119, 61, 21107}},
+{4350, 16, 10628, {1, 3, 3, 9, 19, 57, 99, 23, 451, 507, 973, 415, 7123, 11367, 29767, 23763}},
+{4351, 16, 10643, {1, 1, 5, 7, 29, 23, 47, 11, 267, 873, 591, 373, 7097, 3783, 23289, 5547}},
+{4352, 16, 10673, {1, 1, 5, 15, 7, 7, 7, 91, 389, 841, 1995, 459, 7013, 3109, 23615, 21519}},
+{4353, 16, 10683, {1, 3, 1, 1, 13, 25, 87, 235, 193, 201, 713, 1633, 3117, 13609, 17211, 573}},
+{4354, 16, 10736, {1, 1, 1, 9, 27, 53, 105, 39, 217, 781, 997, 661, 6243, 6427, 17739, 62239}},
+{4355, 16, 10795, {1, 1, 7, 3, 3, 49, 75, 125, 239, 195, 215, 2983, 1185, 4743, 12069, 55509}},
+{4356, 16, 10797, {1, 1, 5, 15, 31, 11, 9, 91, 253, 361, 571, 1589, 2425, 4279, 3765, 46519}},
+{4357, 16, 10815, {1, 1, 3, 3, 21, 49, 49, 213, 399, 253, 1565, 2447, 453, 7957, 24799, 58503}},
+{4358, 16, 10817, {1, 1, 7, 1, 5, 59, 81, 97, 209, 477, 17, 3085, 3655, 599, 24011, 14981}},
+{4359, 16, 10842, {1, 3, 3, 13, 19, 49, 7, 35, 111, 169, 629, 1587, 5345, 13699, 21187, 30199}},
+{4360, 16, 10844, {1, 1, 3, 13, 19, 59, 73, 127, 475, 509, 9, 2661, 711, 15835, 31429, 33885}},
+{4361, 16, 10863, {1, 3, 5, 3, 31, 15, 43, 185, 29, 897, 1041, 1057, 6285, 13925, 4023, 25741}},
+{4362, 16, 10899, {1, 3, 5, 11, 1, 33, 63, 155, 175, 501, 1147, 3395, 3285, 16237, 22315, 50945}},
+{4363, 16, 10902, {1, 3, 3, 3, 5, 13, 77, 227, 85, 139, 139, 1, 7147, 2023, 32705, 38753}},
+{4364, 16, 10917, {1, 3, 5, 11, 31, 59, 35, 179, 489, 537, 1537, 2877, 4937, 10825, 2445, 34907}},
+{4365, 16, 10953, {1, 3, 7, 11, 17, 17, 95, 223, 165, 925, 829, 3971, 1, 7393, 8825, 25705}},
+{4366, 16, 10967, {1, 1, 1, 1, 25, 17, 25, 143, 385, 907, 1381, 1823, 3819, 8475, 5321, 12037}},
+{4367, 16, 11002, {1, 1, 5, 11, 7, 47, 97, 85, 105, 23, 263, 1329, 1905, 12121, 29635, 41249}},
+{4368, 16, 11024, {1, 1, 7, 11, 1, 51, 13, 13, 5, 143, 83, 3831, 959, 6083, 16997, 59887}},
+{4369, 16, 11029, {1, 3, 3, 13, 25, 9, 31, 5, 215, 791, 767, 1733, 2715, 14283, 25795, 54249}},
+{4370, 16, 11030, {1, 3, 7, 5, 11, 19, 125, 81, 71, 131, 1869, 1111, 6763, 5275, 23095, 1139}},
+{4371, 16, 11043, {1, 3, 3, 9, 25, 43, 119, 49, 133, 217, 521, 1367, 5867, 6829, 29871, 60383}},
+{4372, 16, 11087, {1, 1, 7, 9, 5, 11, 59, 157, 279, 301, 481, 3273, 7943, 3273, 27783, 17271}},
+{4373, 16, 11106, {1, 3, 3, 13, 11, 57, 13, 5, 435, 169, 541, 517, 2359, 9121, 27911, 15679}},
+{4374, 16, 11130, {1, 1, 3, 9, 9, 55, 65, 113, 21, 807, 373, 2825, 1527, 15565, 8339, 7227}},
+{4375, 16, 11156, {1, 3, 5, 9, 1, 1, 49, 255, 477, 821, 1647, 713, 6841, 3187, 22649, 51469}},
+{4376, 16, 11176, {1, 3, 3, 11, 13, 43, 63, 139, 71, 809, 993, 2429, 833, 6545, 10987, 39567}},
+{4377, 16, 11221, {1, 1, 1, 9, 19, 23, 47, 199, 191, 827, 391, 837, 1209, 2493, 24071, 46589}},
+{4378, 16, 11267, {1, 1, 5, 13, 25, 51, 39, 43, 103, 899, 1729, 2389, 2965, 189, 3063, 50609}},
+{4379, 16, 11282, {1, 1, 3, 1, 5, 29, 105, 201, 503, 199, 507, 205, 2389, 695, 15233, 50353}},
+{4380, 16, 11294, {1, 3, 1, 7, 19, 53, 45, 21, 89, 545, 1885, 765, 6673, 13485, 9987, 2609}},
+{4381, 16, 11332, {1, 3, 7, 13, 17, 7, 59, 23, 159, 309, 1407, 2483, 1807, 15733, 5603, 52989}},
+{4382, 16, 11353, {1, 1, 1, 11, 13, 19, 123, 185, 413, 745, 361, 2391, 6697, 2281, 11999, 13175}},
+{4383, 16, 11369, {1, 3, 5, 5, 11, 49, 123, 173, 325, 667, 895, 1067, 8121, 10577, 30561, 17391}},
+{4384, 16, 11372, {1, 1, 5, 5, 23, 21, 77, 223, 281, 161, 141, 345, 3879, 11393, 26907, 53805}},
+{4385, 16, 11375, {1, 3, 3, 5, 3, 47, 17, 109, 185, 139, 957, 1417, 4553, 6101, 29537, 34821}},
+{4386, 16, 11413, {1, 1, 5, 3, 29, 49, 89, 61, 45, 593, 269, 1483, 2971, 991, 21239, 29301}},
+{4387, 16, 11429, {1, 1, 3, 13, 29, 45, 33, 253, 291, 783, 737, 2363, 2651, 8627, 21785, 58419}},
+{4388, 16, 11430, {1, 3, 7, 15, 29, 15, 81, 185, 363, 681, 1737, 3789, 4365, 3295, 23205, 4457}},
+{4389, 16, 11444, {1, 3, 3, 11, 15, 39, 67, 167, 197, 357, 871, 2201, 5377, 6299, 20873, 59283}},
+{4390, 16, 11462, {1, 3, 3, 5, 9, 15, 127, 49, 21, 719, 357, 425, 5507, 9639, 275, 47503}},
+{4391, 16, 11465, {1, 1, 7, 1, 13, 63, 111, 121, 21, 481, 247, 3147, 5783, 8947, 20809, 42039}},
+{4392, 16, 11471, {1, 1, 3, 3, 31, 33, 9, 69, 187, 517, 2029, 2205, 7661, 4757, 27525, 9665}},
+{4393, 16, 11473, {1, 1, 1, 13, 7, 41, 103, 161, 233, 221, 693, 213, 4609, 7771, 28703, 17407}},
+{4394, 16, 11495, {1, 3, 7, 15, 31, 47, 27, 111, 479, 1003, 1687, 347, 2179, 11861, 8169, 31941}},
+{4395, 16, 11499, {1, 1, 3, 5, 5, 63, 25, 125, 199, 147, 589, 3565, 3449, 8331, 8923, 31207}},
+{4396, 16, 11519, {1, 1, 3, 11, 19, 25, 77, 99, 299, 19, 1641, 2193, 4299, 3635, 20621, 267}},
+{4397, 16, 11562, {1, 3, 7, 11, 9, 59, 7, 167, 1, 775, 29, 1935, 3723, 11835, 2887, 65285}},
+{4398, 16, 11576, {1, 1, 7, 13, 5, 47, 101, 155, 235, 93, 465, 3581, 1837, 7675, 10789, 45167}},
+{4399, 16, 11582, {1, 1, 3, 5, 9, 59, 121, 109, 59, 821, 1625, 343, 1591, 3875, 13729, 56381}},
+{4400, 16, 11596, {1, 1, 1, 9, 27, 53, 93, 215, 133, 561, 39, 2591, 1041, 11913, 24493, 37921}},
+{4401, 16, 11602, {1, 1, 1, 7, 23, 7, 81, 107, 219, 943, 563, 1083, 5803, 5687, 32559, 62727}},
+{4402, 16, 11611, {1, 3, 7, 7, 21, 53, 3, 5, 231, 601, 1561, 103, 3837, 2675, 5263, 23375}},
+{4403, 16, 11627, {1, 1, 3, 13, 15, 27, 89, 7, 251, 887, 951, 3001, 5687, 4921, 5091, 59337}},
+{4404, 16, 11682, {1, 3, 7, 15, 25, 53, 19, 155, 185, 503, 547, 1917, 7633, 15167, 14177, 46761}},
+{4405, 16, 11687, {1, 3, 5, 15, 21, 49, 13, 163, 471, 281, 1141, 3013, 6847, 9261, 15955, 9397}},
+{4406, 16, 11691, {1, 3, 3, 3, 1, 21, 19, 239, 479, 609, 65, 2735, 5337, 6293, 19351, 34135}},
+{4407, 16, 11733, {1, 1, 7, 1, 9, 1, 119, 23, 411, 535, 101, 1597, 2379, 2421, 31471, 36473}},
+{4408, 16, 11747, {1, 3, 1, 11, 31, 63, 17, 225, 45, 409, 59, 3943, 8043, 11759, 10667, 58793}},
+{4409, 16, 11759, {1, 1, 3, 3, 9, 49, 61, 239, 245, 765, 1945, 3567, 5355, 14799, 7141, 59511}},
+{4410, 16, 11778, {1, 3, 7, 9, 3, 33, 103, 99, 35, 799, 1347, 2253, 8189, 14177, 13479, 13749}},
+{4411, 16, 11852, {1, 3, 1, 15, 15, 51, 7, 179, 471, 265, 1571, 2983, 701, 15133, 7885, 29977}},
+{4412, 16, 11857, {1, 1, 5, 9, 15, 37, 49, 213, 113, 729, 1115, 2727, 2635, 8433, 11145, 46779}},
+{4413, 16, 11858, {1, 3, 5, 11, 7, 3, 115, 151, 133, 723, 7, 4063, 5807, 9845, 25829, 29315}},
+{4414, 16, 11893, {1, 3, 5, 9, 25, 55, 17, 135, 145, 379, 1603, 3459, 5773, 6545, 17509, 25847}},
+{4415, 16, 11907, {1, 1, 7, 11, 1, 61, 113, 147, 489, 775, 1347, 2199, 299, 9589, 19931, 1335}},
+{4416, 16, 11928, {1, 3, 1, 3, 1, 7, 27, 243, 355, 425, 1215, 3723, 3489, 9285, 12739, 24797}},
+{4417, 16, 11931, {1, 3, 5, 11, 15, 25, 57, 221, 247, 647, 259, 1665, 7055, 2835, 16411, 42999}},
+{4418, 16, 11933, {1, 1, 3, 7, 9, 25, 61, 233, 73, 235, 1539, 1865, 5671, 1329, 5767, 43039}},
+{4419, 16, 11967, {1, 1, 7, 9, 21, 11, 123, 7, 41, 407, 1485, 1723, 585, 10597, 16215, 63403}},
+{4420, 16, 11976, {1, 1, 5, 7, 27, 9, 123, 101, 273, 673, 1141, 3841, 4041, 13169, 8221, 12915}},
+{4421, 16, 11989, {1, 3, 1, 13, 3, 17, 105, 17, 237, 321, 855, 2821, 2467, 3503, 15187, 1689}},
+{4422, 16, 12003, {1, 1, 5, 5, 19, 23, 9, 205, 87, 153, 1543, 1193, 6619, 6845, 8459, 37533}},
+{4423, 16, 12024, {1, 1, 7, 15, 13, 29, 79, 9, 203, 211, 239, 2349, 3447, 7797, 19311, 58071}},
+{4424, 16, 12030, {1, 3, 5, 11, 5, 49, 71, 151, 333, 895, 1095, 2471, 2477, 14493, 16711, 14393}},
+{4425, 16, 12037, {1, 1, 5, 13, 17, 19, 25, 149, 111, 631, 763, 2535, 3631, 1809, 8163, 18037}},
+{4426, 16, 12044, {1, 3, 3, 13, 23, 61, 25, 179, 351, 247, 1021, 2413, 2585, 3731, 5435, 52723}},
+{4427, 16, 12052, {1, 1, 5, 11, 1, 39, 65, 59, 21, 927, 1989, 2823, 4857, 15521, 30495, 16067}},
+{4428, 16, 12059, {1, 3, 3, 7, 17, 5, 17, 125, 379, 875, 1565, 2435, 933, 6809, 20129, 26339}},
+{4429, 16, 12075, {1, 1, 7, 5, 3, 57, 51, 213, 455, 663, 2007, 3995, 4889, 9527, 23507, 3261}},
+{4430, 16, 12083, {1, 3, 7, 5, 1, 29, 85, 151, 165, 123, 1425, 2851, 4427, 7683, 21085, 28925}},
+{4431, 16, 12117, {1, 1, 5, 3, 11, 33, 127, 3, 41, 591, 1539, 3823, 125, 421, 9051, 55025}},
+{4432, 16, 12138, {1, 3, 1, 5, 7, 9, 69, 35, 59, 477, 1207, 1245, 6423, 11329, 26535, 37621}},
+{4433, 16, 12146, {1, 3, 1, 1, 15, 35, 17, 123, 303, 193, 1489, 2587, 1883, 4063, 1921, 60413}},
+{4434, 16, 12202, {1, 1, 5, 1, 7, 61, 39, 247, 139, 1015, 757, 823, 4757, 9307, 32287, 37241}},
+{4435, 16, 12230, {1, 1, 7, 15, 3, 5, 85, 93, 457, 999, 1331, 919, 5271, 11687, 24233, 38803}},
+{4436, 16, 12254, {1, 3, 3, 9, 5, 43, 37, 13, 505, 603, 1857, 2675, 2017, 9481, 10873, 54755}},
+{4437, 16, 12304, {1, 1, 5, 15, 13, 3, 7, 239, 471, 835, 553, 413, 4029, 8613, 15533, 58987}},
+{4438, 16, 12316, {1, 3, 1, 5, 19, 27, 21, 43, 57, 755, 1245, 2805, 3799, 2013, 21145, 10317}},
+{4439, 16, 12337, {1, 3, 5, 13, 9, 23, 35, 5, 315, 169, 399, 2641, 1525, 10561, 11917, 33009}},
+{4440, 16, 12347, {1, 3, 5, 7, 23, 53, 101, 105, 451, 207, 1271, 3067, 6725, 15525, 7951, 1283}},
+{4441, 16, 12367, {1, 1, 5, 5, 27, 21, 77, 143, 213, 443, 149, 2667, 5269, 10359, 25287, 5843}},
+{4442, 16, 12398, {1, 3, 5, 5, 25, 27, 109, 157, 459, 767, 765, 2667, 1833, 3781, 9077, 64321}},
+{4443, 16, 12421, {1, 3, 3, 13, 31, 25, 97, 237, 279, 431, 1713, 809, 1989, 10431, 5867, 42197}},
+{4444, 16, 12428, {1, 3, 7, 3, 9, 5, 5, 191, 73, 521, 787, 903, 3073, 2067, 24741, 57029}},
+{4445, 16, 12446, {1, 3, 3, 1, 3, 41, 125, 53, 125, 781, 865, 3677, 6279, 357, 10667, 1127}},
+{4446, 16, 12449, {1, 1, 5, 11, 25, 19, 99, 121, 359, 73, 607, 2149, 5739, 15669, 29457, 57549}},
+{4447, 16, 12467, {1, 1, 5, 3, 23, 5, 35, 55, 369, 239, 329, 3057, 3757, 12523, 5017, 52185}},
+{4448, 16, 12479, {1, 3, 3, 13, 17, 61, 69, 165, 267, 323, 2007, 2025, 4423, 15975, 31897, 37013}},
+{4449, 16, 12502, {1, 3, 7, 13, 19, 19, 87, 111, 389, 611, 1523, 963, 4671, 12569, 21839, 10919}},
+{4450, 16, 12521, {1, 1, 1, 3, 1, 27, 13, 227, 29, 457, 221, 127, 5335, 16247, 19559, 19185}},
+{4451, 16, 12553, {1, 3, 5, 7, 29, 21, 23, 157, 197, 87, 1591, 1829, 407, 15885, 14933, 1997}},
+{4452, 16, 12568, {1, 1, 1, 9, 3, 35, 43, 187, 195, 325, 197, 2905, 7323, 1563, 7659, 45185}},
+{4453, 16, 12573, {1, 1, 1, 15, 3, 23, 105, 33, 73, 495, 1409, 2583, 1099, 1041, 28955, 60293}},
+{4454, 16, 12592, {1, 3, 7, 13, 25, 19, 99, 137, 139, 719, 529, 1147, 5813, 11551, 30183, 14593}},
+{4455, 16, 12597, {1, 3, 3, 5, 17, 25, 73, 193, 309, 887, 1655, 1641, 2091, 12087, 21881, 1145}},
+{4456, 16, 12601, {1, 3, 1, 1, 27, 41, 13, 151, 83, 645, 327, 1795, 2717, 12433, 22751, 9823}},
+{4457, 16, 12615, {1, 1, 3, 7, 1, 43, 77, 229, 59, 499, 1883, 135, 3461, 9821, 219, 6111}},
+{4458, 16, 12619, {1, 3, 3, 3, 23, 7, 17, 67, 361, 565, 1621, 3253, 7973, 281, 3209, 48215}},
+{4459, 16, 12694, {1, 1, 3, 7, 31, 15, 97, 141, 197, 883, 1689, 269, 7487, 10403, 18903, 58147}},
+{4460, 16, 12697, {1, 3, 3, 3, 23, 9, 87, 125, 359, 527, 1251, 637, 1145, 12721, 14693, 6021}},
+{4461, 16, 12698, {1, 1, 3, 5, 13, 43, 105, 173, 205, 859, 1237, 1227, 1409, 15513, 25317, 30745}},
+{4462, 16, 12713, {1, 3, 3, 15, 31, 43, 125, 149, 145, 109, 975, 1167, 7629, 8373, 5923, 64117}},
+{4463, 16, 12722, {1, 3, 1, 15, 3, 33, 89, 173, 379, 615, 1401, 1567, 4453, 7461, 32555, 64369}},
+{4464, 16, 12733, {1, 3, 7, 11, 27, 23, 45, 7, 15, 21, 1663, 3327, 5611, 8535, 27669, 25525}},
+{4465, 16, 12736, {1, 1, 3, 15, 15, 61, 127, 145, 151, 41, 629, 767, 5801, 3395, 1157, 30033}},
+{4466, 16, 12790, {1, 1, 1, 5, 9, 63, 73, 9, 299, 237, 369, 1295, 4869, 6821, 19961, 32129}},
+{4467, 16, 12794, {1, 1, 5, 13, 19, 7, 119, 35, 319, 405, 1255, 1299, 4311, 14999, 24567, 4001}},
+{4468, 16, 12803, {1, 1, 1, 13, 9, 39, 13, 207, 355, 691, 37, 3137, 6073, 16179, 28661, 41}},
+{4469, 16, 12815, {1, 1, 3, 7, 21, 3, 123, 27, 187, 183, 769, 2367, 2957, 7065, 17855, 60805}},
+{4470, 16, 12829, {1, 1, 1, 1, 19, 31, 71, 85, 303, 617, 1007, 283, 8087, 11079, 11463, 65295}},
+{4471, 16, 12833, {1, 1, 3, 13, 25, 63, 61, 187, 401, 465, 1485, 801, 3649, 7763, 8495, 54479}},
+{4472, 16, 12840, {1, 3, 7, 3, 13, 51, 41, 119, 311, 699, 1113, 3631, 1981, 3259, 25871, 45659}},
+{4473, 16, 12875, {1, 3, 7, 13, 31, 27, 57, 181, 325, 107, 1745, 635, 3941, 3305, 14563, 29855}},
+{4474, 16, 12877, {1, 3, 7, 15, 5, 55, 5, 147, 365, 485, 1841, 3673, 6513, 11121, 5725, 18027}},
+{4475, 16, 12916, {1, 3, 5, 11, 13, 45, 35, 79, 109, 683, 1171, 3015, 2163, 4823, 4365, 42931}},
+{4476, 16, 12923, {1, 1, 7, 7, 13, 45, 57, 39, 297, 985, 1559, 487, 5071, 2657, 9401, 41889}},
+{4477, 16, 12935, {1, 1, 5, 9, 29, 33, 79, 237, 509, 537, 549, 3657, 7141, 15189, 30853, 36089}},
+{4478, 16, 12949, {1, 3, 5, 7, 31, 15, 75, 73, 237, 273, 865, 743, 2607, 7611, 18441, 12703}},
+{4479, 16, 12954, {1, 1, 1, 9, 27, 9, 35, 137, 265, 181, 1341, 1945, 5615, 161, 18369, 4791}},
+{4480, 16, 12956, {1, 3, 7, 11, 27, 29, 29, 43, 489, 177, 1489, 2927, 623, 14571, 22447, 46905}},
+{4481, 16, 12959, {1, 3, 3, 3, 19, 41, 107, 53, 239, 263, 1433, 1655, 7991, 7405, 2735, 25519}},
+{4482, 16, 12978, {1, 3, 5, 7, 19, 37, 73, 243, 215, 445, 1781, 3223, 187, 8443, 18185, 45093}},
+{4483, 16, 13001, {1, 1, 3, 13, 9, 57, 111, 111, 221, 505, 1261, 3045, 1655, 16247, 21033, 17993}},
+{4484, 16, 13010, {1, 1, 7, 5, 7, 55, 77, 5, 131, 969, 1481, 2883, 2645, 3003, 5601, 37063}},
+{4485, 16, 13043, {1, 1, 5, 15, 29, 55, 39, 197, 349, 29, 341, 67, 1977, 425, 4063, 42705}},
+{4486, 16, 13049, {1, 1, 7, 13, 1, 57, 81, 81, 129, 681, 1407, 2465, 3627, 2325, 31649, 18449}},
+{4487, 16, 13058, {1, 3, 5, 5, 23, 59, 35, 217, 393, 155, 1315, 105, 2285, 5167, 27997, 55193}},
+{4488, 16, 13112, {1, 1, 7, 3, 11, 59, 53, 179, 319, 819, 947, 3881, 765, 4219, 16405, 48055}},
+{4489, 16, 13140, {1, 1, 3, 9, 23, 9, 67, 67, 137, 523, 1585, 2441, 167, 5217, 12031, 14297}},
+{4490, 16, 13149, {1, 1, 5, 13, 31, 63, 121, 91, 439, 917, 203, 1519, 4363, 2391, 25755, 26677}},
+{4491, 16, 13163, {1, 1, 3, 5, 25, 31, 11, 95, 339, 817, 35, 3923, 7365, 10537, 5521, 54579}},
+{4492, 16, 13187, {1, 3, 7, 1, 3, 33, 47, 13, 139, 445, 1357, 3907, 7495, 8789, 26589, 43479}},
+{4493, 16, 13196, {1, 1, 1, 11, 5, 45, 61, 13, 167, 287, 931, 881, 5713, 12937, 12951, 21597}},
+{4494, 16, 13237, {1, 3, 5, 1, 29, 23, 7, 117, 503, 897, 733, 1113, 7205, 11507, 561, 34011}},
+{4495, 16, 13244, {1, 3, 5, 7, 3, 51, 21, 147, 35, 259, 689, 3801, 2481, 9673, 4065, 595}},
+{4496, 16, 13264, {1, 3, 3, 9, 9, 29, 5, 191, 393, 979, 1627, 937, 75, 2339, 24007, 30555}},
+{4497, 16, 13279, {1, 1, 5, 7, 9, 35, 111, 23, 113, 563, 1689, 1575, 6127, 9919, 2555, 52261}},
+{4498, 16, 13292, {1, 3, 1, 5, 31, 21, 117, 159, 473, 279, 1281, 311, 159, 3343, 27761, 59989}},
+{4499, 16, 13295, {1, 1, 5, 1, 23, 31, 67, 241, 401, 69, 933, 777, 267, 12411, 23767, 9047}},
+{4500, 16, 13307, {1, 1, 5, 1, 15, 49, 99, 15, 267, 913, 1581, 3713, 651, 14275, 10103, 57619}},
+{4501, 16, 13312, {1, 3, 5, 9, 19, 23, 95, 5, 449, 153, 1195, 1315, 2347, 12683, 10865, 50703}},
+{4502, 16, 13317, {1, 1, 1, 13, 17, 17, 115, 31, 135, 725, 795, 1695, 6199, 4179, 5223, 48457}},
+{4503, 16, 13327, {1, 3, 5, 15, 31, 15, 3, 247, 385, 269, 1665, 581, 2809, 6333, 7459, 14815}},
+{4504, 16, 13348, {1, 3, 7, 5, 15, 35, 117, 85, 11, 621, 1523, 981, 511, 14113, 4673, 22683}},
+{4505, 16, 13390, {1, 1, 7, 1, 27, 61, 119, 249, 431, 147, 173, 423, 1353, 4747, 12761, 32947}},
+{4506, 16, 13413, {1, 3, 7, 1, 23, 39, 15, 153, 219, 359, 1233, 169, 2817, 11043, 12435, 30135}},
+{4507, 16, 13417, {1, 1, 5, 1, 1, 55, 39, 1, 151, 865, 125, 2351, 6315, 1165, 20163, 43991}},
+{4508, 16, 13418, {1, 1, 3, 9, 25, 41, 115, 221, 129, 265, 1887, 4057, 7523, 13591, 5735, 59645}},
+{4509, 16, 13451, {1, 1, 5, 5, 19, 15, 9, 77, 511, 627, 153, 2015, 247, 15949, 9715, 45411}},
+{4510, 16, 13475, {1, 1, 7, 7, 17, 17, 107, 183, 39, 647, 1339, 3915, 4937, 537, 27011, 58937}},
+{4511, 16, 13482, {1, 3, 3, 13, 3, 3, 69, 201, 431, 65, 683, 121, 7017, 2791, 16713, 62555}},
+{4512, 16, 13510, {1, 3, 7, 3, 7, 41, 117, 237, 23, 757, 545, 3899, 1837, 5555, 7891, 29151}},
+{4513, 16, 13527, {1, 1, 1, 3, 27, 15, 39, 195, 353, 299, 1431, 2279, 1795, 13773, 24915, 49701}},
+{4514, 16, 13543, {1, 1, 5, 5, 7, 7, 125, 5, 401, 523, 1967, 2471, 7279, 7559, 12025, 60599}},
+{4515, 16, 13547, {1, 1, 1, 13, 13, 59, 13, 249, 465, 847, 1483, 975, 7729, 2773, 15745, 51237}},
+{4516, 16, 13627, {1, 1, 7, 9, 31, 41, 115, 141, 247, 355, 1109, 3239, 6495, 4515, 30145, 47705}},
+{4517, 16, 13650, {1, 1, 3, 13, 29, 41, 69, 179, 45, 271, 1909, 3095, 7199, 14049, 9903, 33383}},
+{4518, 16, 13683, {1, 1, 3, 13, 7, 45, 105, 105, 243, 121, 67, 3169, 237, 137, 4175, 54325}},
+{4519, 16, 13696, {1, 3, 3, 11, 19, 51, 93, 155, 79, 579, 1621, 1251, 7639, 15875, 25815, 56063}},
+{4520, 16, 13702, {1, 3, 3, 9, 27, 27, 77, 45, 217, 965, 1045, 875, 4515, 11261, 27859, 757}},
+{4521, 16, 13713, {1, 1, 3, 11, 17, 7, 81, 37, 299, 765, 977, 3371, 3163, 13267, 18345, 9239}},
+{4522, 16, 13739, {1, 1, 1, 3, 15, 23, 115, 11, 183, 511, 557, 3253, 153, 8465, 22659, 42143}},
+{4523, 16, 13749, {1, 1, 5, 13, 17, 61, 127, 219, 225, 981, 615, 731, 4069, 12637, 11601, 38257}},
+{4524, 16, 13767, {1, 1, 5, 3, 29, 3, 73, 79, 393, 779, 823, 2473, 3811, 4417, 9399, 50011}},
+{4525, 16, 13774, {1, 3, 3, 9, 21, 35, 61, 99, 115, 657, 629, 1129, 2355, 12665, 459, 40831}},
+{4526, 16, 13781, {1, 3, 1, 7, 25, 61, 53, 249, 15, 649, 665, 595, 1441, 8035, 5381, 7147}},
+{4527, 16, 13795, {1, 3, 1, 7, 19, 9, 27, 207, 205, 461, 1069, 4039, 6549, 2333, 29, 50067}},
+{4528, 16, 13821, {1, 1, 5, 3, 15, 7, 115, 205, 71, 73, 53, 71, 6049, 15293, 17041, 20313}},
+{4529, 16, 13825, {1, 1, 7, 7, 9, 7, 119, 99, 357, 729, 2041, 3355, 5333, 1263, 30521, 64867}},
+{4530, 16, 13838, {1, 1, 1, 7, 31, 63, 63, 159, 281, 295, 913, 2161, 8033, 13789, 17711, 14915}},
+{4531, 16, 13852, {1, 1, 7, 9, 29, 55, 69, 129, 453, 361, 1883, 17, 1765, 111, 10311, 55019}},
+{4532, 16, 13879, {1, 1, 5, 9, 21, 15, 31, 57, 291, 915, 945, 1775, 5905, 9073, 3271, 15571}},
+{4533, 16, 13888, {1, 1, 1, 7, 21, 11, 1, 9, 167, 143, 1535, 1267, 6675, 13037, 19513, 52027}},
+{4534, 16, 13897, {1, 3, 3, 7, 31, 45, 57, 105, 63, 121, 631, 679, 3873, 16333, 32069, 64725}},
+{4535, 16, 13906, {1, 1, 1, 9, 23, 41, 29, 207, 489, 319, 905, 3147, 4195, 2697, 5281, 1771}},
+{4536, 16, 13939, {1, 1, 1, 9, 25, 33, 57, 201, 405, 111, 407, 3489, 449, 8601, 1273, 42105}},
+{4537, 16, 13962, {1, 1, 1, 3, 19, 45, 123, 159, 237, 173, 781, 787, 7537, 15453, 25567, 53729}},
+{4538, 16, 13981, {1, 1, 7, 3, 29, 9, 89, 207, 345, 685, 1701, 2859, 8065, 9289, 2459, 28367}},
+{4539, 16, 13985, {1, 3, 1, 3, 31, 41, 55, 241, 81, 1001, 595, 1725, 853, 11427, 20617, 1717}},
+{4540, 16, 14020, {1, 1, 3, 3, 9, 45, 121, 69, 177, 1017, 211, 2753, 6923, 1387, 32063, 45337}},
+{4541, 16, 14030, {1, 1, 5, 15, 21, 23, 95, 61, 485, 403, 619, 3035, 4881, 13423, 17815, 35221}},
+{4542, 16, 14041, {1, 1, 3, 3, 3, 59, 23, 69, 77, 309, 227, 2877, 3739, 3539, 20083, 23415}},
+{4543, 16, 14047, {1, 3, 7, 3, 17, 43, 95, 239, 223, 353, 1237, 3239, 1369, 7245, 32401, 63889}},
+{4544, 16, 14048, {1, 1, 1, 5, 25, 63, 123, 3, 291, 819, 793, 241, 5619, 8871, 18341, 2757}},
+{4545, 16, 14066, {1, 3, 7, 15, 3, 21, 17, 97, 395, 333, 909, 3783, 3635, 751, 24227, 44281}},
+{4546, 16, 14092, {1, 3, 7, 13, 29, 49, 123, 195, 191, 159, 211, 1887, 3047, 4871, 2607, 32425}},
+{4547, 16, 14120, {1, 1, 7, 7, 15, 57, 91, 255, 267, 897, 441, 1581, 953, 6951, 17275, 50229}},
+{4548, 16, 14126, {1, 3, 7, 15, 1, 35, 91, 219, 7, 117, 119, 2687, 1215, 9517, 10849, 28347}},
+{4549, 16, 14131, {1, 1, 1, 1, 21, 55, 67, 221, 503, 883, 1037, 2965, 1485, 8557, 28091, 25459}},
+{4550, 16, 14143, {1, 3, 5, 9, 19, 3, 73, 123, 95, 307, 1339, 3669, 5077, 12049, 523, 21457}},
+{4551, 16, 14146, {1, 3, 1, 13, 3, 1, 111, 97, 371, 697, 1989, 3715, 7875, 6841, 7009, 17809}},
+{4552, 16, 14152, {1, 1, 1, 9, 25, 21, 19, 43, 329, 531, 491, 1147, 1469, 12841, 29651, 29517}},
+{4553, 16, 14155, {1, 1, 5, 1, 15, 63, 101, 197, 477, 245, 341, 61, 3803, 10001, 5519, 19083}},
+{4554, 16, 14157, {1, 3, 7, 5, 13, 43, 7, 143, 291, 531, 1727, 871, 7091, 5737, 24285, 51017}},
+{4555, 16, 14188, {1, 3, 5, 1, 17, 13, 15, 85, 361, 153, 989, 1367, 4705, 3599, 4441, 52471}},
+{4556, 16, 14206, {1, 1, 7, 13, 21, 43, 111, 29, 299, 439, 1929, 283, 5901, 14113, 3929, 55843}},
+{4557, 16, 14243, {1, 3, 3, 9, 31, 59, 63, 43, 91, 171, 733, 1359, 425, 8505, 19777, 54723}},
+{4558, 16, 14278, {1, 1, 5, 7, 31, 1, 97, 253, 331, 307, 1749, 2115, 2535, 9945, 11013, 14231}},
+{4559, 16, 14308, {1, 1, 5, 11, 13, 7, 109, 237, 301, 383, 683, 1603, 6393, 2437, 12101, 1767}},
+{4560, 16, 14317, {1, 1, 3, 11, 15, 61, 119, 199, 109, 265, 1431, 1729, 3409, 10129, 16945, 34681}},
+{4561, 16, 14335, {1, 3, 7, 9, 13, 59, 121, 73, 29, 513, 279, 457, 7985, 15199, 10185, 33621}},
+{4562, 16, 14354, {1, 3, 7, 7, 23, 17, 27, 65, 387, 487, 1803, 2789, 461, 11201, 7001, 40229}},
+{4563, 16, 14356, {1, 1, 3, 15, 9, 13, 55, 127, 33, 513, 1055, 643, 505, 3005, 6121, 64147}},
+{4564, 16, 14379, {1, 3, 5, 15, 5, 11, 77, 233, 175, 691, 171, 2491, 6915, 14195, 7845, 36499}},
+{4565, 16, 14381, {1, 1, 5, 11, 19, 45, 103, 207, 99, 645, 1739, 1517, 5907, 16035, 14559, 44007}},
+{4566, 16, 14384, {1, 3, 7, 15, 21, 27, 53, 107, 89, 291, 983, 3527, 1025, 2985, 13747, 32715}},
+{4567, 16, 14389, {1, 1, 3, 15, 23, 17, 27, 209, 77, 959, 813, 3597, 5809, 693, 10325, 16855}},
+{4568, 16, 14390, {1, 1, 7, 11, 23, 53, 123, 99, 211, 935, 1371, 1657, 4699, 2683, 27933, 21451}},
+{4569, 16, 14414, {1, 3, 3, 3, 17, 21, 93, 201, 423, 351, 1639, 227, 5719, 13111, 5993, 44615}},
+{4570, 16, 14425, {1, 1, 7, 3, 13, 49, 59, 255, 213, 147, 1441, 3593, 6419, 15657, 1947, 62713}},
+{4571, 16, 14462, {1, 3, 1, 7, 7, 41, 79, 135, 275, 585, 925, 3139, 4351, 1827, 23533, 63031}},
+{4572, 16, 14472, {1, 1, 7, 3, 11, 1, 13, 149, 29, 897, 1043, 2393, 3931, 6741, 19973, 46303}},
+{4573, 16, 14508, {1, 1, 1, 13, 13, 57, 9, 253, 149, 67, 1531, 4049, 3013, 13947, 3371, 35317}},
+{4574, 16, 14511, {1, 3, 1, 1, 15, 19, 11, 125, 179, 383, 1273, 1551, 6441, 6579, 19659, 31005}},
+{4575, 16, 14519, {1, 1, 3, 15, 29, 37, 11, 199, 273, 663, 549, 3167, 2049, 8815, 30719, 47905}},
+{4576, 16, 14528, {1, 1, 1, 15, 7, 9, 113, 231, 155, 27, 419, 1303, 4493, 5633, 5743, 51335}},
+{4577, 16, 14561, {1, 3, 5, 13, 21, 35, 7, 63, 391, 637, 2011, 841, 5933, 10563, 7593, 34767}},
+{4578, 16, 14574, {1, 3, 1, 15, 19, 13, 89, 127, 507, 715, 1305, 2989, 7551, 1953, 26101, 54913}},
+{4579, 16, 14588, {1, 1, 5, 1, 1, 33, 101, 211, 173, 761, 177, 2721, 6949, 15801, 6639, 21405}},
+{4580, 16, 14594, {1, 3, 1, 13, 15, 23, 113, 177, 43, 743, 57, 3875, 7833, 13619, 17637, 5547}},
+{4581, 16, 14606, {1, 1, 3, 13, 21, 7, 123, 83, 391, 731, 597, 2595, 1949, 14619, 17141, 60595}},
+{4582, 16, 14614, {1, 3, 7, 13, 31, 55, 15, 43, 17, 855, 233, 1411, 1063, 12977, 22159, 59185}},
+{4583, 16, 14639, {1, 3, 7, 7, 17, 53, 67, 37, 245, 941, 1213, 1965, 6635, 10189, 12979, 63503}},
+{4584, 16, 14641, {1, 1, 5, 15, 31, 23, 15, 175, 177, 643, 1705, 3541, 2009, 12005, 27281, 16821}},
+{4585, 16, 14648, {1, 3, 1, 13, 27, 37, 1, 171, 255, 445, 171, 3555, 8169, 399, 20975, 36195}},
+{4586, 16, 14668, {1, 3, 7, 11, 13, 15, 123, 65, 173, 317, 1991, 2093, 8073, 12831, 15455, 30175}},
+{4587, 16, 14673, {1, 3, 1, 7, 5, 53, 59, 219, 407, 501, 875, 2627, 1335, 14387, 25523, 28337}},
+{4588, 16, 14679, {1, 3, 3, 13, 13, 41, 93, 125, 41, 461, 887, 1085, 3393, 11945, 16329, 43531}},
+{4589, 16, 14695, {1, 3, 1, 11, 21, 39, 1, 185, 429, 285, 443, 1165, 451, 10903, 31511, 50555}},
+{4590, 16, 14702, {1, 1, 7, 5, 11, 25, 61, 171, 493, 733, 215, 1871, 7783, 14113, 2061, 58961}},
+{4591, 16, 14704, {1, 1, 7, 7, 27, 23, 53, 45, 131, 301, 275, 3855, 4883, 6303, 25269, 12697}},
+{4592, 16, 14740, {1, 3, 5, 7, 11, 15, 71, 101, 377, 803, 1369, 3741, 633, 10571, 30659, 31101}},
+{4593, 16, 14754, {1, 1, 5, 15, 19, 53, 3, 153, 411, 685, 1405, 109, 5755, 13311, 3713, 24579}},
+{4594, 16, 14774, {1, 1, 3, 3, 27, 7, 89, 39, 5, 853, 1757, 2927, 2889, 9735, 17959, 39301}},
+{4595, 16, 14792, {1, 3, 1, 3, 13, 41, 57, 71, 187, 285, 825, 1807, 7261, 2645, 21861, 1839}},
+{4596, 16, 14797, {1, 3, 3, 5, 15, 21, 23, 7, 341, 981, 891, 721, 7221, 3137, 28725, 54993}},
+{4597, 16, 14806, {1, 1, 5, 3, 3, 61, 59, 97, 205, 359, 185, 3361, 7637, 15473, 6351, 62097}},
+{4598, 16, 14812, {1, 1, 1, 9, 13, 11, 123, 71, 199, 251, 535, 371, 1605, 12107, 13833, 2019}},
+{4599, 16, 14856, {1, 1, 7, 13, 27, 1, 43, 73, 409, 601, 1481, 649, 3293, 12257, 23377, 17225}},
+{4600, 16, 14876, {1, 1, 7, 11, 15, 55, 99, 45, 261, 461, 1507, 3575, 4425, 9895, 20191, 61863}},
+{4601, 16, 14900, {1, 3, 7, 1, 3, 7, 19, 85, 139, 691, 1685, 137, 7547, 16143, 14193, 52479}},
+{4602, 16, 14910, {1, 3, 5, 9, 17, 61, 7, 189, 31, 641, 1381, 3999, 4909, 8463, 31761, 54493}},
+{4603, 16, 14912, {1, 1, 5, 15, 17, 15, 69, 111, 55, 1011, 1859, 2643, 6043, 5125, 15875, 611}},
+{4604, 16, 14915, {1, 1, 3, 5, 3, 33, 73, 227, 327, 369, 189, 1841, 5625, 1179, 18651, 34951}},
+{4605, 16, 14922, {1, 3, 7, 13, 1, 17, 109, 149, 89, 889, 799, 3423, 2599, 14525, 12763, 23855}},
+{4606, 16, 14939, {1, 1, 3, 15, 5, 63, 87, 7, 63, 171, 1215, 557, 3009, 16305, 23517, 40101}},
+{4607, 16, 14946, {1, 1, 3, 3, 29, 31, 79, 183, 401, 813, 41, 1111, 5669, 15697, 7813, 10215}},
+{4608, 16, 14955, {1, 1, 5, 7, 9, 25, 25, 57, 343, 375, 535, 3405, 1909, 3201, 2417, 52285}},
+{4609, 16, 14966, {1, 1, 5, 9, 25, 19, 33, 183, 29, 991, 1045, 2249, 2933, 12525, 13943, 10423}},
+{4610, 16, 14976, {1, 3, 1, 7, 3, 45, 49, 37, 429, 67, 821, 1289, 7311, 16165, 25861, 57715}},
+{4611, 16, 14986, {1, 1, 7, 3, 19, 3, 33, 153, 505, 683, 611, 1691, 6421, 15517, 19161, 49013}},
+{4612, 16, 14993, {1, 3, 7, 7, 21, 21, 85, 55, 293, 199, 1671, 1881, 7147, 8241, 16173, 51873}},
+{4613, 16, 15012, {1, 3, 1, 15, 3, 61, 97, 191, 435, 511, 1599, 2705, 1897, 2607, 1801, 48583}},
+{4614, 16, 15041, {1, 1, 5, 3, 9, 23, 23, 185, 401, 947, 33, 385, 7491, 14129, 14561, 13759}},
+{4615, 16, 15053, {1, 3, 5, 15, 19, 21, 37, 233, 149, 673, 29, 1315, 3487, 6705, 28283, 43135}},
+{4616, 16, 15056, {1, 1, 1, 11, 9, 35, 101, 255, 345, 829, 689, 2747, 2145, 2101, 24863, 35529}},
+{4617, 16, 15059, {1, 3, 7, 9, 5, 5, 53, 247, 157, 729, 1621, 129, 2485, 5371, 11115, 47771}},
+{4618, 16, 15110, {1, 1, 3, 9, 29, 29, 13, 229, 87, 281, 1119, 1085, 4423, 1667, 27067, 50397}},
+{4619, 16, 15116, {1, 1, 3, 7, 11, 29, 77, 85, 121, 495, 501, 3209, 3531, 2307, 11367, 34135}},
+{4620, 16, 15133, {1, 1, 7, 9, 3, 37, 33, 209, 493, 869, 367, 3221, 1643, 3353, 22851, 4313}},
+{4621, 16, 15134, {1, 1, 1, 7, 15, 53, 27, 17, 29, 345, 821, 1831, 1963, 10089, 5101, 32689}},
+{4622, 16, 15137, {1, 1, 3, 9, 9, 61, 31, 215, 497, 591, 1301, 157, 3329, 13877, 9017, 34673}},
+{4623, 16, 15147, {1, 1, 5, 1, 29, 49, 93, 139, 279, 167, 143, 279, 6145, 6247, 519, 8869}},
+{4624, 16, 15182, {1, 3, 3, 1, 25, 41, 81, 219, 505, 335, 1941, 2963, 413, 775, 4181, 55269}},
+{4625, 16, 15203, {1, 1, 1, 11, 27, 23, 91, 9, 497, 811, 1469, 1999, 5377, 2943, 17635, 11151}},
+{4626, 16, 15215, {1, 1, 5, 15, 17, 23, 15, 235, 271, 749, 1873, 3805, 5405, 7421, 24339, 14351}},
+{4627, 16, 15245, {1, 3, 7, 1, 5, 61, 81, 9, 269, 43, 1391, 2711, 6973, 11299, 2263, 8715}},
+{4628, 16, 15246, {1, 1, 5, 13, 11, 1, 69, 235, 25, 227, 63, 2591, 913, 12555, 6263, 38981}},
+{4629, 16, 15264, {1, 3, 1, 7, 17, 7, 97, 251, 149, 959, 1895, 1179, 4031, 15975, 20313, 64067}},
+{4630, 16, 15269, {1, 3, 7, 15, 3, 17, 85, 229, 149, 925, 585, 3755, 2359, 13131, 12665, 28861}},
+{4631, 16, 15296, {1, 3, 3, 9, 5, 31, 107, 93, 347, 851, 1249, 2161, 6095, 8315, 20259, 39527}},
+{4632, 16, 15314, {1, 3, 7, 7, 21, 63, 85, 241, 501, 627, 1211, 1713, 6907, 4229, 7557, 55719}},
+{4633, 16, 15323, {1, 1, 1, 13, 19, 43, 21, 177, 13, 353, 679, 511, 5565, 993, 25345, 25087}},
+{4634, 16, 15364, {1, 3, 3, 15, 21, 15, 87, 83, 381, 547, 1429, 2417, 2425, 2097, 20889, 12353}},
+{4635, 16, 15386, {1, 3, 1, 11, 23, 21, 69, 147, 427, 271, 1829, 525, 2951, 10773, 32425, 17685}},
+{4636, 16, 15391, {1, 3, 1, 7, 15, 55, 21, 131, 195, 927, 635, 3505, 3817, 14883, 1149, 10079}},
+{4637, 16, 15436, {1, 3, 3, 9, 23, 15, 45, 147, 249, 87, 377, 1551, 4343, 15373, 2895, 44973}},
+{4638, 16, 15460, {1, 3, 1, 7, 31, 63, 67, 107, 109, 1019, 815, 231, 8135, 559, 8175, 21735}},
+{4639, 16, 15464, {1, 1, 5, 7, 7, 63, 103, 133, 167, 883, 1647, 2827, 6015, 8541, 16963, 37129}},
+{4640, 16, 15469, {1, 3, 5, 9, 27, 25, 59, 147, 29, 943, 865, 1233, 2165, 15259, 2235, 25831}},
+{4641, 16, 15470, {1, 1, 5, 7, 25, 5, 67, 89, 493, 111, 359, 1115, 7963, 6545, 7749, 29179}},
+{4642, 16, 15477, {1, 3, 7, 5, 19, 17, 89, 195, 337, 115, 1417, 3837, 4761, 1959, 16205, 61597}},
+{4643, 16, 15488, {1, 1, 5, 11, 25, 43, 3, 111, 491, 897, 1541, 909, 4751, 739, 7827, 64485}},
+{4644, 16, 15494, {1, 1, 5, 15, 19, 61, 39, 111, 451, 419, 1657, 2427, 4589, 5577, 23967, 19259}},
+{4645, 16, 15548, {1, 3, 3, 1, 31, 15, 7, 131, 329, 847, 537, 1775, 3833, 5683, 17267, 16389}},
+{4646, 16, 15551, {1, 1, 7, 1, 9, 29, 13, 25, 409, 513, 1695, 2175, 5099, 727, 5723, 43547}},
+{4647, 16, 15560, {1, 1, 5, 7, 13, 11, 29, 123, 127, 193, 1647, 3157, 2149, 16209, 19909, 14473}},
+{4648, 16, 15563, {1, 1, 1, 15, 15, 37, 125, 157, 487, 143, 1891, 2895, 4397, 10685, 1463, 55027}},
+{4649, 16, 15604, {1, 3, 7, 1, 1, 15, 115, 105, 479, 529, 1095, 2687, 4483, 15027, 15487, 7113}},
+{4650, 16, 15607, {1, 1, 3, 9, 23, 63, 113, 211, 155, 931, 175, 3037, 2359, 10413, 24561, 21099}},
+{4651, 16, 15616, {1, 3, 3, 11, 5, 15, 13, 37, 257, 447, 203, 545, 2467, 9979, 17543, 62703}},
+{4652, 16, 15631, {1, 1, 3, 7, 17, 31, 83, 91, 79, 265, 1415, 2347, 5337, 7615, 27739, 33841}},
+{4653, 16, 15699, {1, 3, 5, 7, 17, 63, 37, 153, 347, 909, 1945, 7, 2071, 15195, 32083, 26713}},
+{4654, 16, 15701, {1, 1, 3, 11, 19, 51, 69, 21, 323, 635, 443, 1685, 6275, 13787, 20921, 45553}},
+{4655, 16, 15708, {1, 3, 3, 7, 15, 35, 67, 247, 257, 429, 2029, 523, 3219, 3893, 26677, 53273}},
+{4656, 16, 15739, {1, 1, 7, 9, 9, 3, 119, 121, 445, 149, 1539, 1887, 2995, 14867, 809, 48065}},
+{4657, 16, 15746, {1, 3, 5, 13, 15, 27, 75, 9, 217, 35, 1363, 2383, 4357, 1153, 20565, 62277}},
+{4658, 16, 15772, {1, 1, 7, 1, 21, 1, 11, 53, 331, 765, 407, 453, 2725, 11199, 645, 14915}},
+{4659, 16, 15793, {1, 1, 5, 1, 29, 11, 5, 159, 395, 53, 323, 1347, 5529, 8525, 24003, 20535}},
+{4660, 16, 15832, {1, 3, 3, 15, 9, 19, 87, 181, 391, 639, 703, 611, 997, 359, 2471, 58465}},
+{4661, 16, 15837, {1, 3, 5, 9, 27, 9, 117, 47, 223, 509, 1537, 1235, 3885, 6767, 17131, 63421}},
+{4662, 16, 15866, {1, 1, 5, 1, 15, 15, 113, 67, 477, 597, 1795, 3065, 4565, 3609, 16419, 19667}},
+{4663, 16, 15899, {1, 1, 7, 11, 1, 63, 33, 211, 271, 773, 499, 2309, 1303, 14015, 30377, 53195}},
+{4664, 16, 15911, {1, 1, 7, 11, 5, 23, 17, 183, 321, 315, 203, 3371, 907, 9331, 21031, 33765}},
+{4665, 16, 15918, {1, 3, 3, 7, 7, 53, 111, 69, 441, 283, 195, 2415, 7293, 7659, 2731, 5417}},
+{4666, 16, 15952, {1, 3, 5, 15, 3, 61, 5, 241, 427, 463, 1729, 653, 7671, 10979, 7247, 36931}},
+{4667, 16, 15962, {1, 3, 1, 9, 3, 5, 105, 117, 465, 853, 2005, 3925, 4419, 4441, 3701, 50747}},
+{4668, 16, 15967, {1, 1, 3, 7, 1, 3, 3, 149, 65, 405, 299, 99, 481, 14323, 11565, 6227}},
+{4669, 16, 15973, {1, 3, 7, 5, 29, 3, 19, 3, 253, 895, 879, 2435, 2151, 10673, 11013, 43055}},
+{4670, 16, 15977, {1, 3, 1, 11, 15, 57, 127, 197, 319, 913, 1039, 811, 7767, 5791, 31725, 8733}},
+{4671, 16, 16016, {1, 1, 7, 3, 13, 25, 25, 81, 229, 185, 39, 2789, 579, 4973, 28617, 60871}},
+{4672, 16, 16035, {1, 1, 7, 3, 25, 17, 41, 7, 103, 269, 55, 2651, 7579, 10935, 8917, 14323}},
+{4673, 16, 16044, {1, 3, 7, 7, 13, 7, 99, 205, 293, 877, 1893, 3013, 2389, 6021, 2645, 18175}},
+{4674, 16, 16067, {1, 1, 3, 7, 9, 39, 59, 187, 191, 761, 339, 3381, 2921, 5197, 16963, 43019}},
+{4675, 16, 16082, {1, 3, 3, 13, 7, 23, 41, 203, 311, 981, 323, 1675, 6689, 579, 3885, 64475}},
+{4676, 16, 16084, {1, 3, 5, 15, 21, 39, 35, 193, 167, 1009, 493, 829, 6571, 1299, 13061, 1163}},
+{4677, 16, 16098, {1, 1, 3, 5, 3, 19, 123, 123, 111, 599, 193, 3419, 7173, 5595, 12449, 52247}},
+{4678, 16, 16107, {1, 3, 5, 11, 9, 25, 65, 49, 239, 953, 481, 3455, 4335, 305, 22469, 11949}},
+{4679, 16, 16142, {1, 1, 3, 7, 15, 1, 13, 77, 147, 49, 1445, 931, 3405, 15951, 15215, 26451}},
+{4680, 16, 16149, {1, 3, 1, 1, 21, 53, 17, 7, 247, 243, 805, 795, 489, 13351, 13493, 30937}},
+{4681, 16, 16165, {1, 3, 7, 5, 5, 13, 39, 115, 397, 757, 423, 2559, 1677, 9449, 24563, 869}},
+{4682, 16, 16172, {1, 1, 3, 11, 23, 9, 27, 233, 165, 853, 1721, 599, 551, 11657, 27623, 40119}},
+{4683, 16, 16178, {1, 1, 3, 1, 3, 47, 75, 207, 113, 417, 1317, 2215, 2395, 1841, 23125, 50401}},
+{4684, 16, 16197, {1, 3, 3, 1, 13, 55, 103, 55, 351, 785, 1665, 3603, 7705, 4811, 21129, 38115}},
+{4685, 16, 16201, {1, 1, 1, 5, 5, 49, 93, 189, 317, 701, 1545, 1017, 4133, 7655, 19827, 52155}},
+{4686, 16, 16215, {1, 3, 3, 13, 17, 37, 7, 249, 139, 529, 235, 3801, 7871, 459, 15127, 13231}},
+{4687, 16, 16221, {1, 3, 7, 5, 7, 63, 99, 241, 131, 455, 1287, 3539, 8029, 12661, 23313, 54029}},
+{4688, 16, 16226, {1, 3, 1, 3, 29, 63, 51, 227, 497, 685, 1351, 449, 7851, 10815, 17379, 62097}},
+{4689, 16, 16232, {1, 3, 1, 11, 25, 61, 73, 29, 467, 533, 855, 853, 5557, 10953, 18307, 27135}},
+{4690, 16, 16246, {1, 1, 7, 3, 13, 49, 63, 171, 177, 283, 1365, 3087, 5445, 15109, 12523, 25193}},
+{4691, 16, 16261, {1, 3, 5, 15, 9, 39, 95, 81, 417, 199, 1653, 3673, 2663, 8101, 12199, 22759}},
+{4692, 16, 16279, {1, 1, 3, 9, 29, 15, 29, 215, 21, 721, 245, 1197, 7251, 5721, 6735, 7751}},
+{4693, 16, 16280, {1, 3, 5, 5, 21, 7, 81, 61, 157, 707, 819, 1689, 4203, 5559, 25483, 43325}},
+{4694, 16, 16290, {1, 1, 7, 13, 15, 51, 47, 197, 269, 921, 353, 2865, 6227, 537, 20015, 53823}},
+{4695, 16, 16314, {1, 1, 3, 5, 13, 25, 91, 221, 111, 587, 1119, 2343, 4651, 4641, 15915, 36323}},
+{4696, 16, 16345, {1, 1, 7, 11, 1, 45, 7, 215, 483, 545, 731, 3041, 3121, 8681, 20651, 4069}},
+{4697, 16, 16355, {1, 3, 7, 13, 13, 27, 109, 65, 103, 805, 299, 2069, 6017, 14565, 20505, 16161}},
+{4698, 16, 16361, {1, 1, 7, 5, 11, 33, 105, 213, 237, 583, 1033, 2333, 845, 6493, 505, 2563}},
+{4699, 16, 16393, {1, 1, 5, 7, 3, 5, 11, 173, 373, 341, 269, 177, 3175, 9413, 601, 13591}},
+{4700, 16, 16394, {1, 1, 5, 13, 7, 57, 61, 187, 121, 405, 665, 111, 7535, 3355, 14051, 511}},
+{4701, 16, 16438, {1, 1, 1, 3, 3, 29, 15, 253, 227, 123, 333, 1343, 7313, 1955, 17741, 30831}},
+{4702, 16, 16450, {1, 3, 5, 1, 5, 47, 65, 183, 199, 839, 925, 2711, 4609, 201, 15177, 29817}},
+{4703, 16, 16507, {1, 3, 7, 9, 21, 63, 5, 163, 265, 581, 1795, 3937, 4641, 2073, 32225, 60831}},
+{4704, 16, 16523, {1, 1, 1, 5, 7, 47, 125, 203, 511, 841, 1937, 3431, 1495, 12827, 5893, 19265}},
+{4705, 16, 16533, {1, 1, 5, 5, 9, 49, 17, 247, 391, 241, 3, 2253, 6319, 89, 4449, 6371}},
+{4706, 16, 16603, {1, 3, 1, 1, 31, 7, 51, 61, 461, 391, 273, 1609, 5825, 16029, 3851, 39213}},
+{4707, 16, 16648, {1, 3, 3, 7, 29, 21, 65, 75, 317, 925, 1319, 3827, 965, 5685, 17007, 64365}},
+{4708, 16, 16653, {1, 3, 1, 5, 23, 23, 109, 59, 31, 659, 635, 2209, 857, 9847, 2507, 18325}},
+{4709, 16, 16672, {1, 1, 1, 1, 17, 51, 53, 77, 461, 147, 229, 2821, 2405, 1259, 1121, 17429}},
+{4710, 16, 16682, {1, 3, 5, 3, 31, 3, 57, 157, 321, 731, 1609, 2139, 899, 12599, 19803, 51083}},
+{4711, 16, 16709, {1, 1, 3, 11, 27, 43, 73, 209, 431, 587, 1247, 2803, 3593, 1351, 18701, 33423}},
+{4712, 16, 16713, {1, 3, 5, 13, 27, 19, 67, 245, 339, 879, 2035, 1801, 5845, 3883, 22057, 15771}},
+{4713, 16, 16719, {1, 1, 3, 11, 11, 55, 93, 51, 57, 127, 1325, 3975, 3989, 2347, 18831, 2979}},
+{4714, 16, 16733, {1, 1, 1, 13, 17, 1, 17, 103, 303, 777, 1973, 2943, 7439, 8953, 27227, 10229}},
+{4715, 16, 16740, {1, 3, 3, 15, 1, 41, 53, 219, 415, 399, 995, 205, 7719, 10937, 31879, 755}},
+{4716, 16, 16761, {1, 3, 7, 9, 13, 7, 99, 93, 419, 1019, 1605, 161, 3831, 9147, 7877, 1333}},
+{4717, 16, 16767, {1, 3, 7, 15, 5, 51, 37, 115, 259, 549, 353, 2067, 7657, 1283, 20333, 2325}},
+{4718, 16, 16771, {1, 1, 3, 3, 23, 33, 63, 233, 363, 719, 1099, 471, 3079, 10577, 19063, 31535}},
+{4719, 16, 16788, {1, 3, 7, 15, 23, 19, 109, 105, 497, 881, 1055, 537, 4607, 239, 22785, 60201}},
+{4720, 16, 16811, {1, 3, 3, 5, 19, 11, 1, 207, 163, 437, 713, 667, 1427, 7505, 28055, 43101}},
+{4721, 16, 16814, {1, 3, 5, 5, 25, 45, 75, 9, 109, 545, 573, 2685, 1013, 2973, 18619, 55945}},
+{4722, 16, 16816, {1, 1, 1, 3, 27, 27, 39, 33, 285, 453, 613, 2707, 2155, 4355, 21105, 7969}},
+{4723, 16, 16828, {1, 3, 3, 9, 1, 31, 71, 101, 491, 409, 65, 1479, 5743, 525, 2863, 53657}},
+{4724, 16, 16834, {1, 1, 3, 1, 17, 63, 55, 11, 125, 447, 275, 2243, 6827, 5753, 32401, 13819}},
+{4725, 16, 16863, {1, 1, 3, 9, 21, 47, 5, 127, 285, 471, 1681, 945, 6141, 5651, 10273, 30811}},
+{4726, 16, 16864, {1, 3, 3, 1, 13, 53, 91, 3, 255, 429, 107, 2937, 2971, 10251, 15009, 37477}},
+{4727, 16, 16879, {1, 1, 7, 13, 21, 63, 73, 3, 63, 491, 101, 1981, 7457, 879, 6243, 22275}},
+{4728, 16, 16888, {1, 3, 1, 1, 11, 43, 121, 101, 293, 639, 645, 2723, 2075, 3629, 22105, 18199}},
+{4729, 16, 16904, {1, 1, 3, 1, 31, 9, 69, 97, 511, 663, 1147, 1237, 389, 255, 8661, 38533}},
+{4730, 16, 16909, {1, 3, 3, 7, 3, 13, 23, 71, 197, 439, 2003, 1771, 8073, 1549, 29089, 5409}},
+{4731, 16, 16921, {1, 3, 1, 1, 9, 23, 1, 221, 159, 699, 593, 3385, 3869, 10105, 22097, 34753}},
+{4732, 16, 16934, {1, 1, 7, 1, 29, 47, 41, 137, 333, 357, 325, 3151, 6641, 3823, 8763, 28327}},
+{4733, 16, 16951, {1, 3, 1, 7, 19, 19, 39, 225, 477, 619, 583, 229, 6177, 9615, 1203, 13711}},
+{4734, 16, 16983, {1, 1, 3, 13, 9, 41, 127, 147, 13, 301, 861, 2019, 3517, 1147, 21587, 42387}},
+{4735, 16, 16999, {1, 1, 5, 11, 9, 63, 11, 121, 251, 199, 483, 2287, 4667, 3887, 10611, 6019}},
+{4736, 16, 17000, {1, 1, 3, 13, 23, 19, 89, 73, 355, 399, 749, 687, 5707, 11443, 817, 38967}},
+{4737, 16, 17006, {1, 3, 5, 9, 3, 23, 115, 207, 373, 541, 73, 1285, 7245, 12505, 5787, 61207}},
+{4738, 16, 17020, {1, 3, 5, 15, 27, 37, 115, 203, 195, 793, 1577, 1283, 7299, 4025, 5319, 5375}},
+{4739, 16, 17030, {1, 1, 7, 15, 25, 19, 61, 11, 215, 771, 1057, 451, 1965, 13693, 25617, 42657}},
+{4740, 16, 17033, {1, 3, 3, 7, 1, 19, 23, 217, 175, 901, 2009, 2989, 5111, 5027, 4805, 37843}},
+{4741, 16, 17044, {1, 3, 1, 11, 11, 37, 3, 131, 459, 769, 201, 3979, 3009, 8691, 27005, 32175}},
+{4742, 16, 17051, {1, 3, 5, 7, 27, 27, 117, 23, 403, 1003, 1501, 785, 6313, 10187, 5085, 30751}},
+{4743, 16, 17072, {1, 1, 7, 3, 11, 41, 73, 151, 19, 657, 131, 1901, 3879, 14995, 24085, 56621}},
+{4744, 16, 17078, {1, 3, 7, 15, 23, 3, 61, 199, 67, 483, 1961, 3583, 5937, 5749, 16685, 11831}},
+{4745, 16, 17084, {1, 1, 3, 15, 25, 15, 97, 9, 299, 641, 883, 2901, 123, 1523, 7055, 15609}},
+{4746, 16, 17087, {1, 3, 5, 5, 31, 55, 19, 45, 239, 543, 2005, 1041, 1711, 11059, 19927, 17475}},
+{4747, 16, 17090, {1, 1, 3, 9, 5, 59, 105, 209, 323, 613, 1963, 2227, 2947, 11761, 21375, 13265}},
+{4748, 16, 17123, {1, 3, 3, 15, 1, 5, 117, 37, 93, 243, 305, 2299, 5163, 9205, 28761, 35987}},
+{4749, 16, 17132, {1, 1, 1, 5, 5, 29, 13, 147, 457, 187, 1729, 1547, 7745, 13155, 7833, 57449}},
+{4750, 16, 17140, {1, 3, 3, 13, 1, 51, 49, 253, 23, 389, 1611, 3045, 5909, 3947, 25105, 3327}},
+{4751, 16, 17149, {1, 3, 1, 11, 15, 47, 19, 15, 231, 57, 763, 1879, 1765, 14861, 22893, 19437}},
+{4752, 16, 17157, {1, 1, 3, 15, 1, 19, 85, 65, 139, 629, 361, 3513, 3807, 799, 8349, 29247}},
+{4753, 16, 17164, {1, 3, 3, 13, 9, 11, 65, 201, 471, 89, 355, 121, 3947, 10775, 3599, 6041}},
+{4754, 16, 17170, {1, 3, 7, 3, 5, 53, 33, 167, 431, 129, 1449, 3263, 7691, 12569, 7551, 41101}},
+{4755, 16, 17179, {1, 1, 3, 15, 9, 41, 5, 239, 361, 773, 955, 3663, 6051, 12889, 5841, 59615}},
+{4756, 16, 17237, {1, 1, 7, 5, 5, 33, 97, 9, 495, 845, 1953, 3533, 5715, 15055, 25211, 9351}},
+{4757, 16, 17248, {1, 3, 1, 11, 25, 37, 83, 153, 289, 739, 353, 1121, 7641, 2081, 28439, 38085}},
+{4758, 16, 17260, {1, 3, 1, 1, 27, 9, 63, 135, 395, 641, 1759, 3727, 4371, 5193, 2783, 12389}},
+{4759, 16, 17272, {1, 3, 3, 15, 3, 9, 5, 153, 111, 675, 1957, 3817, 4269, 10787, 3413, 34199}},
+{4760, 16, 17275, {1, 3, 5, 9, 23, 23, 97, 137, 255, 249, 333, 2329, 1055, 13769, 13109, 33443}},
+{4761, 16, 17287, {1, 1, 1, 15, 7, 37, 99, 219, 483, 755, 263, 3523, 6179, 4817, 29873, 12771}},
+{4762, 16, 17294, {1, 1, 3, 5, 23, 7, 77, 97, 105, 631, 175, 1911, 7271, 1009, 24081, 61207}},
+{4763, 16, 17296, {1, 3, 5, 3, 1, 31, 71, 91, 265, 669, 1839, 3989, 8127, 15001, 1419, 8895}},
+{4764, 16, 17305, {1, 3, 1, 13, 27, 51, 93, 155, 49, 991, 653, 203, 3863, 5363, 31969, 36083}},
+{4765, 16, 17312, {1, 3, 3, 7, 31, 27, 21, 73, 21, 675, 407, 1215, 2963, 6799, 15259, 13125}},
+{4766, 16, 17321, {1, 3, 5, 13, 5, 53, 19, 215, 243, 487, 689, 2519, 6393, 3987, 30847, 37919}},
+{4767, 16, 17367, {1, 3, 3, 7, 5, 31, 115, 231, 255, 955, 2023, 1487, 6575, 9873, 22585, 29951}},
+{4768, 16, 17368, {1, 3, 5, 11, 11, 57, 109, 203, 417, 29, 1311, 893, 1047, 2413, 9305, 38219}},
+{4769, 16, 17378, {1, 3, 1, 7, 23, 51, 113, 3, 105, 915, 1145, 3431, 7331, 3323, 31669, 21485}},
+{4770, 16, 17433, {1, 1, 7, 13, 9, 29, 119, 205, 403, 1023, 257, 863, 2983, 1895, 16539, 23385}},
+{4771, 16, 17455, {1, 1, 7, 13, 27, 21, 47, 139, 341, 509, 1107, 2197, 3649, 14301, 30789, 48783}},
+{4772, 16, 17457, {1, 3, 3, 7, 25, 19, 99, 11, 309, 919, 1809, 3015, 1587, 3779, 1289, 30207}},
+{4773, 16, 17508, {1, 3, 5, 11, 9, 43, 57, 171, 9, 151, 173, 2301, 7723, 2083, 319, 52883}},
+{4774, 16, 17559, {1, 1, 3, 1, 3, 13, 63, 11, 231, 117, 1257, 237, 581, 13871, 15501, 8741}},
+{4775, 16, 17560, {1, 3, 5, 9, 13, 63, 55, 155, 291, 721, 123, 929, 3351, 11651, 12513, 1779}},
+{4776, 16, 17582, {1, 3, 7, 3, 31, 5, 61, 81, 465, 639, 1363, 3157, 2401, 9513, 32559, 34477}},
+{4777, 16, 17596, {1, 3, 1, 15, 27, 25, 3, 117, 277, 13, 707, 3825, 7287, 10181, 30127, 57247}},
+{4778, 16, 17599, {1, 1, 7, 11, 21, 21, 53, 17, 407, 851, 1191, 285, 6815, 1595, 25507, 8099}},
+{4779, 16, 17613, {1, 3, 5, 9, 9, 61, 83, 61, 65, 671, 63, 311, 6897, 15327, 29809, 4899}},
+{4780, 16, 17619, {1, 1, 7, 1, 21, 45, 99, 235, 477, 461, 1119, 4087, 2057, 14861, 31969, 24357}},
+{4781, 16, 17622, {1, 1, 7, 9, 31, 9, 65, 123, 281, 273, 1059, 1625, 6265, 9635, 11563, 45053}},
+{4782, 16, 17655, {1, 3, 3, 7, 1, 41, 15, 23, 43, 727, 1271, 1741, 765, 13265, 4145, 1335}},
+{4783, 16, 17661, {1, 1, 3, 7, 17, 55, 107, 231, 263, 197, 659, 3621, 2789, 5171, 28635, 13595}},
+{4784, 16, 17698, {1, 1, 5, 1, 27, 23, 13, 83, 431, 507, 1571, 1573, 1733, 12171, 8181, 30843}},
+{4785, 16, 17712, {1, 3, 7, 11, 1, 53, 107, 39, 497, 579, 453, 1339, 1415, 10317, 2741, 34599}},
+{4786, 16, 17715, {1, 3, 3, 5, 31, 41, 49, 41, 33, 665, 1783, 87, 317, 6603, 22603, 22879}},
+{4787, 16, 17721, {1, 3, 1, 15, 5, 47, 41, 87, 231, 853, 1615, 2299, 4643, 9249, 15641, 14323}},
+{4788, 16, 17722, {1, 3, 7, 9, 5, 45, 55, 153, 31, 247, 67, 2335, 6057, 4379, 27579, 38437}},
+{4789, 16, 17742, {1, 1, 5, 7, 9, 3, 73, 81, 479, 909, 1097, 3945, 4485, 7815, 22855, 20825}},
+{4790, 16, 17778, {1, 3, 1, 15, 19, 43, 97, 57, 339, 167, 135, 1777, 7681, 9715, 13863, 6347}},
+{4791, 16, 17818, {1, 1, 1, 1, 5, 53, 33, 123, 449, 165, 1283, 2977, 5919, 12929, 32073, 61851}},
+{4792, 16, 17836, {1, 1, 5, 15, 27, 27, 19, 157, 267, 651, 1319, 3841, 7739, 9947, 16801, 41325}},
+{4793, 16, 17841, {1, 3, 7, 9, 19, 7, 83, 95, 401, 293, 437, 1983, 119, 7553, 11097, 11925}},
+{4794, 16, 17856, {1, 1, 3, 5, 21, 1, 53, 201, 385, 843, 1801, 99, 2697, 9659, 28789, 31417}},
+{4795, 16, 17883, {1, 1, 5, 5, 29, 57, 103, 89, 77, 597, 1849, 3433, 4267, 11167, 3841, 44023}},
+{4796, 16, 17896, {1, 1, 7, 1, 21, 47, 113, 253, 249, 431, 1899, 2859, 7345, 5725, 14805, 19999}},
+{4797, 16, 17901, {1, 3, 3, 5, 1, 11, 77, 213, 359, 665, 1855, 2743, 2407, 14677, 17957, 63257}},
+{4798, 16, 17926, {1, 3, 7, 13, 23, 29, 127, 183, 275, 849, 1005, 3159, 3867, 13029, 7527, 13035}},
+{4799, 16, 17937, {1, 1, 1, 15, 29, 47, 81, 225, 77, 879, 1279, 1929, 1457, 2025, 32229, 2847}},
+{4800, 16, 17992, {1, 1, 1, 3, 29, 45, 37, 189, 217, 53, 281, 1785, 1929, 763, 5875, 34303}},
+{4801, 16, 17995, {1, 3, 1, 9, 21, 61, 21, 149, 215, 13, 1221, 5, 7153, 14089, 3119, 33115}},
+{4802, 16, 17998, {1, 3, 7, 11, 7, 57, 89, 185, 485, 649, 1765, 747, 2983, 6791, 25015, 13627}},
+{4803, 16, 18021, {1, 1, 1, 9, 11, 53, 77, 203, 425, 237, 487, 2317, 1047, 8277, 23405, 30445}},
+{4804, 16, 18039, {1, 1, 3, 5, 7, 29, 39, 195, 109, 381, 655, 931, 4469, 16215, 10627, 64171}},
+{4805, 16, 18067, {1, 3, 1, 3, 5, 9, 89, 131, 509, 275, 489, 3161, 3701, 11951, 6579, 42839}},
+{4806, 16, 18122, {1, 3, 7, 13, 15, 37, 65, 91, 305, 433, 1815, 169, 3117, 47, 30331, 34863}},
+{4807, 16, 18129, {1, 3, 3, 9, 21, 3, 21, 113, 25, 833, 1579, 4021, 3481, 55, 20833, 46277}},
+{4808, 16, 18130, {1, 1, 1, 5, 19, 37, 61, 229, 61, 363, 817, 1235, 6235, 7261, 29917, 43057}},
+{4809, 16, 18142, {1, 3, 1, 9, 7, 59, 119, 189, 341, 945, 633, 3683, 2589, 15453, 4989, 40055}},
+{4810, 16, 18148, {1, 1, 1, 5, 25, 63, 61, 73, 207, 205, 1011, 2857, 8137, 2121, 26731, 46011}},
+{4811, 16, 18163, {1, 3, 7, 11, 13, 59, 107, 57, 49, 555, 441, 1771, 4939, 12107, 8263, 16243}},
+{4812, 16, 18192, {1, 3, 5, 13, 15, 49, 89, 217, 83, 225, 2001, 2727, 4651, 619, 16473, 47525}},
+{4813, 16, 18211, {1, 3, 5, 9, 5, 63, 115, 91, 337, 757, 703, 559, 1683, 14875, 30769, 30331}},
+{4814, 16, 18228, {1, 3, 1, 15, 3, 3, 119, 79, 487, 519, 523, 1177, 7105, 12343, 24671, 31711}},
+{4815, 16, 18264, {1, 1, 7, 15, 25, 63, 87, 23, 59, 277, 849, 953, 4567, 11309, 26181, 749}},
+{4816, 16, 18347, {1, 3, 7, 15, 5, 33, 21, 127, 3, 239, 839, 997, 7253, 8183, 19779, 4185}},
+{4817, 16, 18372, {1, 1, 5, 15, 25, 37, 99, 51, 465, 137, 1339, 541, 4319, 9883, 17425, 30743}},
+{4818, 16, 18409, {1, 3, 3, 5, 13, 7, 3, 249, 365, 749, 527, 3675, 3005, 12905, 9621, 899}},
+{4819, 16, 18412, {1, 3, 3, 7, 29, 31, 69, 21, 365, 1021, 1329, 2623, 3549, 5491, 21293, 63771}},
+{4820, 16, 18418, {1, 1, 5, 9, 5, 35, 53, 247, 193, 17, 227, 381, 5233, 821, 3991, 4439}},
+{4821, 16, 18423, {1, 1, 7, 15, 5, 59, 27, 167, 489, 335, 1565, 2999, 1777, 5009, 519, 57967}},
+{4822, 16, 18433, {1, 1, 1, 11, 25, 47, 23, 155, 419, 863, 1905, 355, 1089, 5871, 10149, 53341}},
+{4823, 16, 18439, {1, 1, 7, 7, 29, 55, 127, 83, 33, 309, 2017, 1021, 5987, 1101, 13657, 60587}},
+{4824, 16, 18445, {1, 1, 1, 7, 3, 1, 9, 75, 257, 407, 659, 529, 2087, 14759, 14483, 36425}},
+{4825, 16, 18451, {1, 3, 7, 3, 11, 29, 113, 255, 301, 799, 1171, 3721, 135, 3467, 7109, 50339}},
+{4826, 16, 18467, {1, 1, 1, 7, 21, 25, 15, 31, 61, 491, 57, 189, 2033, 4363, 31295, 16313}},
+{4827, 16, 18502, {1, 1, 5, 1, 5, 17, 33, 77, 483, 469, 355, 2245, 4165, 459, 30411, 29507}},
+{4828, 16, 18514, {1, 1, 3, 13, 1, 27, 29, 85, 491, 787, 1157, 1299, 4743, 14795, 32587, 12807}},
+{4829, 16, 18547, {1, 3, 3, 1, 23, 45, 35, 129, 3, 55, 969, 2387, 3929, 10397, 19879, 2723}},
+{4830, 16, 18575, {1, 1, 1, 7, 19, 3, 9, 23, 497, 347, 2039, 913, 5925, 7965, 5789, 40949}},
+{4831, 16, 18593, {1, 1, 7, 1, 29, 61, 89, 3, 133, 647, 1585, 2661, 1875, 1859, 3937, 12707}},
+{4832, 16, 18613, {1, 3, 3, 7, 25, 11, 41, 149, 427, 463, 901, 2433, 2617, 13511, 3443, 39867}},
+{4833, 16, 18620, {1, 1, 1, 5, 27, 33, 103, 251, 201, 1023, 1979, 3745, 6365, 14945, 22153, 55535}},
+{4834, 16, 18637, {1, 3, 1, 15, 23, 25, 57, 215, 111, 181, 385, 1123, 3095, 7085, 31863, 37393}},
+{4835, 16, 18640, {1, 3, 5, 13, 17, 35, 27, 159, 255, 241, 413, 1823, 5329, 1825, 28489, 58763}},
+{4836, 16, 18712, {1, 3, 1, 15, 3, 33, 97, 27, 409, 889, 409, 2315, 4743, 14827, 3037, 57149}},
+{4837, 16, 18728, {1, 1, 3, 5, 19, 63, 93, 51, 233, 715, 1571, 1101, 2751, 14805, 25683, 13323}},
+{4838, 16, 18742, {1, 3, 7, 3, 21, 15, 117, 179, 263, 229, 199, 2597, 3999, 3037, 3801, 4775}},
+{4839, 16, 18748, {1, 3, 3, 15, 1, 15, 49, 91, 383, 21, 1955, 773, 1213, 5971, 19525, 8699}},
+{4840, 16, 18753, {1, 3, 1, 15, 29, 49, 11, 101, 261, 761, 709, 3811, 4055, 15675, 32305, 15173}},
+{4841, 16, 18756, {1, 1, 1, 3, 9, 41, 127, 23, 413, 461, 237, 1595, 2257, 2971, 31845, 61485}},
+{4842, 16, 18771, {1, 1, 1, 11, 23, 13, 63, 21, 23, 209, 1317, 1071, 3619, 7275, 9343, 21455}},
+{4843, 16, 18814, {1, 1, 5, 9, 31, 35, 41, 249, 477, 569, 1175, 1571, 4679, 10337, 3507, 23415}},
+{4844, 16, 18818, {1, 3, 5, 11, 29, 3, 117, 65, 301, 913, 1709, 1765, 1801, 15513, 31495, 38131}},
+{4845, 16, 18827, {1, 3, 5, 11, 27, 3, 71, 195, 81, 313, 505, 3941, 3797, 2031, 24151, 65085}},
+{4846, 16, 18835, {1, 1, 1, 5, 13, 17, 59, 151, 191, 489, 1267, 3207, 4495, 15145, 12789, 46313}},
+{4847, 16, 18842, {1, 3, 1, 7, 29, 9, 25, 31, 33, 527, 1939, 4089, 333, 757, 8895, 25331}},
+{4848, 16, 18854, {1, 1, 1, 1, 9, 27, 11, 205, 211, 141, 1171, 1881, 4029, 10587, 30103, 39661}},
+{4849, 16, 18858, {1, 1, 3, 3, 23, 3, 23, 175, 355, 753, 183, 1331, 6403, 3369, 29891, 11109}},
+{4850, 16, 18895, {1, 3, 7, 3, 17, 25, 95, 145, 135, 525, 1073, 1841, 3951, 2027, 23053, 19699}},
+{4851, 16, 18914, {1, 1, 5, 3, 11, 43, 117, 67, 299, 885, 1095, 2777, 8185, 14331, 29543, 655}},
+{4852, 16, 18925, {1, 3, 7, 7, 3, 59, 127, 147, 323, 713, 99, 1179, 6395, 1821, 12673, 35587}},
+{4853, 16, 18933, {1, 3, 5, 3, 7, 11, 33, 87, 99, 967, 1443, 1585, 6215, 15125, 30747, 21513}},
+{4854, 16, 18937, {1, 3, 7, 11, 23, 5, 91, 171, 229, 601, 833, 3157, 1691, 15081, 20607, 7643}},
+{4855, 16, 18944, {1, 1, 3, 1, 5, 1, 39, 59, 157, 7, 601, 2079, 3045, 3693, 26511, 13245}},
+{4856, 16, 18973, {1, 3, 5, 9, 9, 27, 83, 135, 185, 379, 2027, 1407, 7409, 7363, 26471, 35907}},
+{4857, 16, 19001, {1, 3, 7, 15, 29, 49, 1, 69, 383, 915, 183, 3809, 4511, 8751, 4715, 7033}},
+{4858, 16, 19012, {1, 3, 3, 3, 1, 17, 71, 233, 243, 933, 1165, 3089, 3565, 6521, 13203, 13065}},
+{4859, 16, 19016, {1, 1, 5, 9, 9, 55, 53, 129, 331, 943, 587, 2573, 2247, 15101, 4987, 62983}},
+{4860, 16, 19027, {1, 3, 1, 13, 11, 43, 45, 127, 129, 857, 669, 321, 3915, 4477, 26973, 19911}},
+{4861, 16, 19040, {1, 3, 1, 13, 15, 3, 83, 23, 13, 441, 953, 2373, 3539, 4895, 26327, 61961}},
+{4862, 16, 19074, {1, 1, 5, 13, 23, 11, 125, 83, 339, 901, 1809, 2691, 3789, 15007, 10569, 65399}},
+{4863, 16, 19085, {1, 3, 1, 1, 17, 27, 105, 199, 435, 245, 1227, 3029, 3911, 1021, 2931, 24957}},
+{4864, 16, 19093, {1, 3, 1, 11, 17, 5, 123, 39, 413, 627, 1149, 3925, 6635, 8959, 31387, 65047}},
+{4865, 16, 19100, {1, 3, 5, 1, 23, 41, 93, 217, 21, 115, 1311, 3901, 2559, 2925, 30755, 7575}},
+{4866, 16, 19107, {1, 1, 3, 9, 13, 11, 63, 171, 135, 983, 1679, 395, 7349, 5153, 26405, 40589}},
+{4867, 16, 19128, {1, 3, 7, 13, 27, 47, 53, 169, 85, 871, 1087, 619, 7399, 9719, 6349, 59211}},
+{4868, 16, 19141, {1, 3, 3, 15, 31, 45, 3, 33, 11, 879, 929, 1977, 1939, 1049, 16159, 41515}},
+{4869, 16, 19142, {1, 3, 5, 11, 9, 27, 13, 23, 127, 747, 1121, 2497, 8141, 8601, 12431, 3243}},
+{4870, 16, 19156, {1, 3, 7, 15, 23, 43, 23, 225, 283, 13, 1837, 2089, 6435, 10121, 22307, 58767}},
+{4871, 16, 19169, {1, 1, 5, 11, 17, 3, 41, 221, 143, 669, 261, 1367, 7813, 15265, 32751, 62007}},
+{4872, 16, 19176, {1, 1, 1, 1, 5, 45, 41, 161, 327, 185, 1403, 485, 2831, 10025, 12555, 47661}},
+{4873, 16, 19222, {1, 3, 7, 1, 31, 55, 87, 83, 439, 929, 653, 4095, 5443, 7361, 27801, 12979}},
+{4874, 16, 19226, {1, 3, 1, 7, 1, 57, 11, 145, 55, 269, 711, 1889, 8023, 7171, 3247, 35691}},
+{4875, 16, 19247, {1, 1, 1, 3, 15, 1, 15, 131, 479, 797, 815, 2343, 1603, 10775, 21341, 20825}},
+{4876, 16, 19259, {1, 3, 5, 9, 3, 27, 31, 117, 441, 177, 215, 3991, 3197, 8397, 19195, 3883}},
+{4877, 16, 19262, {1, 1, 5, 13, 1, 19, 13, 27, 157, 1001, 43, 251, 7997, 7495, 16515, 44287}},
+{4878, 16, 19291, {1, 1, 3, 5, 17, 57, 117, 53, 413, 905, 551, 149, 7531, 14885, 32493, 34961}},
+{4879, 16, 19309, {1, 3, 3, 7, 27, 1, 7, 13, 259, 21, 189, 451, 6171, 3603, 12053, 45619}},
+{4880, 16, 19324, {1, 1, 7, 11, 5, 41, 59, 119, 419, 93, 1399, 629, 1269, 3789, 17035, 61583}},
+{4881, 16, 19334, {1, 3, 5, 11, 1, 11, 59, 83, 473, 273, 839, 3111, 3081, 10159, 6143, 16297}},
+{4882, 16, 19338, {1, 1, 5, 15, 25, 15, 17, 63, 275, 927, 189, 89, 6595, 4399, 27201, 57205}},
+{4883, 16, 19343, {1, 1, 7, 3, 31, 17, 63, 203, 321, 655, 1751, 2985, 3291, 11567, 15135, 49747}},
+{4884, 16, 19376, {1, 3, 5, 13, 27, 25, 89, 39, 299, 833, 1269, 271, 6481, 3045, 7203, 20279}},
+{4885, 16, 19408, {1, 3, 1, 1, 29, 13, 13, 37, 33, 563, 1825, 3257, 3153, 963, 25801, 15861}},
+{4886, 16, 19413, {1, 3, 5, 11, 15, 7, 49, 117, 479, 221, 579, 2995, 1673, 14927, 2869, 35547}},
+{4887, 16, 19420, {1, 3, 1, 11, 31, 11, 77, 161, 183, 187, 1967, 3037, 4441, 10547, 1443, 8619}},
+{4888, 16, 19441, {1, 1, 3, 11, 27, 41, 83, 179, 293, 421, 1395, 1673, 6375, 9801, 14265, 18117}},
+{4889, 16, 19444, {1, 1, 3, 7, 9, 19, 55, 235, 499, 637, 1121, 3583, 8007, 3749, 20903, 6179}},
+{4890, 16, 19454, {1, 3, 7, 13, 9, 55, 125, 77, 395, 9, 2005, 2247, 1609, 6805, 13099, 26367}},
+{4891, 16, 19461, {1, 3, 5, 13, 9, 41, 49, 133, 443, 995, 209, 341, 8013, 11037, 29663, 21161}},
+{4892, 16, 19473, {1, 3, 1, 1, 1, 47, 45, 243, 161, 433, 129, 39, 4885, 8777, 6395, 16953}},
+{4893, 16, 19479, {1, 3, 3, 15, 11, 13, 41, 113, 279, 657, 763, 2411, 7115, 463, 10759, 50493}},
+{4894, 16, 19489, {1, 1, 5, 5, 31, 5, 25, 181, 385, 445, 625, 313, 4983, 11763, 6065, 63835}},
+{4895, 16, 19591, {1, 3, 3, 15, 13, 25, 103, 5, 205, 223, 1327, 73, 677, 6751, 2071, 24963}},
+{4896, 16, 19605, {1, 1, 7, 15, 21, 61, 21, 11, 47, 775, 113, 991, 1943, 1459, 18049, 45025}},
+{4897, 16, 19616, {1, 3, 3, 1, 11, 43, 27, 89, 49, 711, 173, 181, 1261, 2751, 21321, 5467}},
+{4898, 16, 19619, {1, 3, 3, 7, 17, 7, 57, 61, 87, 973, 985, 1849, 559, 7319, 11457, 46071}},
+{4899, 16, 19653, {1, 1, 1, 1, 9, 37, 99, 157, 423, 189, 1355, 3983, 6357, 10825, 26517, 45815}},
+{4900, 16, 19654, {1, 1, 3, 11, 23, 33, 57, 55, 59, 831, 339, 725, 359, 14859, 17523, 36149}},
+{4901, 16, 19681, {1, 1, 5, 5, 27, 29, 47, 147, 153, 801, 1737, 3617, 5447, 8011, 30631, 7921}},
+{4902, 16, 19711, {1, 1, 5, 1, 11, 43, 35, 105, 69, 453, 1023, 875, 6755, 6015, 12449, 50235}},
+{4903, 16, 19719, {1, 3, 1, 5, 29, 31, 43, 89, 369, 891, 1447, 353, 8103, 2555, 1197, 64005}},
+{4904, 16, 19726, {1, 3, 3, 9, 21, 33, 117, 205, 473, 289, 1699, 2361, 7083, 13001, 24127, 48611}},
+{4905, 16, 19738, {1, 3, 3, 15, 3, 23, 79, 139, 475, 511, 181, 1331, 6137, 2653, 14071, 16947}},
+{4906, 16, 19767, {1, 3, 3, 1, 11, 47, 51, 217, 305, 599, 1609, 237, 4537, 5377, 717, 13269}},
+{4907, 16, 19819, {1, 1, 7, 3, 19, 31, 1, 173, 509, 817, 785, 1223, 5585, 8911, 643, 44575}},
+{4908, 16, 19864, {1, 1, 3, 11, 5, 11, 31, 129, 269, 369, 1833, 2885, 441, 11517, 2323, 26735}},
+{4909, 16, 19867, {1, 1, 5, 9, 7, 51, 31, 21, 5, 157, 541, 2939, 4569, 1679, 17467, 27995}},
+{4910, 16, 19885, {1, 1, 7, 3, 21, 33, 85, 213, 41, 851, 1947, 3205, 5065, 6079, 30789, 63677}},
+{4911, 16, 19894, {1, 1, 5, 3, 9, 53, 3, 179, 157, 407, 537, 1193, 4645, 13791, 28153, 11349}},
+{4912, 16, 19900, {1, 1, 7, 13, 25, 61, 9, 151, 263, 143, 1583, 2859, 6617, 8861, 4163, 40695}},
+{4913, 16, 19903, {1, 1, 1, 1, 7, 25, 19, 207, 335, 1019, 1919, 3893, 831, 12421, 4667, 38967}},
+{4914, 16, 19941, {1, 3, 5, 3, 5, 51, 81, 9, 425, 333, 451, 2569, 2771, 12145, 26065, 14385}},
+{4915, 16, 19951, {1, 1, 3, 7, 3, 49, 17, 147, 327, 331, 1197, 7, 3703, 15247, 9723, 52819}},
+{4916, 16, 19959, {1, 3, 3, 7, 27, 21, 117, 229, 255, 603, 195, 1049, 6243, 13593, 14553, 8267}},
+{4917, 16, 19966, {1, 1, 5, 15, 9, 53, 1, 187, 79, 151, 321, 1883, 6105, 13879, 8201, 53213}},
+{4918, 16, 20009, {1, 1, 1, 7, 21, 27, 103, 147, 351, 901, 1927, 2145, 2685, 453, 15173, 7371}},
+{4919, 16, 20018, {1, 1, 3, 5, 21, 27, 125, 77, 395, 27, 827, 3617, 6033, 1511, 29461, 18907}},
+{4920, 16, 20020, {1, 3, 5, 3, 3, 27, 75, 129, 441, 831, 1213, 2499, 5829, 12181, 7991, 58167}},
+{4921, 16, 20038, {1, 1, 1, 9, 3, 33, 85, 135, 45, 405, 1731, 551, 1251, 7895, 3975, 41621}},
+{4922, 16, 20049, {1, 3, 5, 7, 19, 19, 25, 7, 477, 569, 1089, 2705, 6157, 10279, 14029, 36229}},
+{4923, 16, 20066, {1, 3, 7, 3, 5, 19, 99, 137, 67, 361, 2021, 2891, 1957, 14961, 22673, 45707}},
+{4924, 16, 20108, {1, 3, 7, 1, 21, 11, 81, 225, 151, 235, 1761, 3875, 7427, 11213, 27023, 17945}},
+{4925, 16, 20130, {1, 1, 7, 1, 3, 1, 3, 123, 39, 769, 1467, 1907, 7833, 2099, 19, 54653}},
+{4926, 16, 20132, {1, 1, 1, 3, 25, 35, 33, 111, 407, 497, 1527, 3999, 3083, 6221, 8319, 56959}},
+{4927, 16, 20167, {1, 1, 3, 15, 21, 49, 113, 11, 191, 801, 1835, 3413, 3379, 13129, 3655, 23885}},
+{4928, 16, 20219, {1, 3, 1, 5, 21, 57, 87, 133, 409, 325, 569, 2099, 8143, 315, 23287, 21905}},
+{4929, 16, 20227, {1, 1, 5, 5, 21, 43, 25, 169, 265, 123, 81, 2683, 6137, 7341, 16383, 26435}},
+{4930, 16, 20263, {1, 3, 1, 5, 23, 17, 125, 173, 3, 829, 693, 751, 8021, 3701, 32643, 35405}},
+{4931, 16, 20267, {1, 1, 3, 1, 31, 13, 1, 195, 435, 487, 961, 1681, 1233, 6001, 3113, 29515}},
+{4932, 16, 20272, {1, 1, 7, 5, 9, 41, 81, 137, 257, 337, 1837, 145, 4191, 6313, 9991, 25541}},
+{4933, 16, 20289, {1, 1, 5, 13, 29, 13, 1, 117, 501, 991, 571, 793, 1433, 6005, 19, 61135}},
+{4934, 16, 20296, {1, 1, 7, 1, 9, 43, 65, 69, 297, 331, 1777, 1843, 6477, 13943, 1301, 51001}},
+{4935, 16, 20307, {1, 1, 1, 3, 7, 35, 23, 211, 33, 649, 255, 1831, 635, 9965, 16679, 14531}},
+{4936, 16, 20316, {1, 1, 1, 13, 23, 57, 113, 247, 321, 401, 1761, 4001, 1823, 14457, 5251, 4965}},
+{4937, 16, 20323, {1, 1, 5, 5, 31, 5, 53, 103, 297, 575, 1577, 2217, 977, 14415, 16953, 14793}},
+{4938, 16, 20335, {1, 1, 5, 7, 9, 19, 25, 29, 121, 563, 1707, 901, 6167, 10799, 11897, 31187}},
+{4939, 16, 20344, {1, 1, 5, 9, 17, 39, 89, 29, 251, 259, 411, 819, 6037, 4601, 11481, 46141}},
+{4940, 16, 20354, {1, 1, 1, 15, 23, 9, 65, 95, 189, 93, 1485, 2417, 5183, 5513, 26623, 42637}},
+{4941, 16, 20360, {1, 1, 5, 5, 3, 3, 113, 161, 463, 225, 1089, 2023, 2341, 14931, 28097, 56365}},
+{4942, 16, 20368, {1, 1, 5, 9, 9, 3, 109, 141, 27, 473, 107, 4023, 3279, 7595, 13289, 35649}},
+{4943, 16, 20390, {1, 1, 5, 3, 9, 37, 73, 153, 487, 57, 2035, 3583, 239, 2183, 10903, 171}},
+{4944, 16, 20402, {1, 3, 3, 15, 23, 39, 87, 217, 451, 597, 1817, 2883, 145, 11341, 16015, 16765}},
+{4945, 16, 20413, {1, 1, 7, 5, 19, 61, 45, 37, 473, 883, 277, 2801, 13, 7021, 3851, 53223}},
+{4946, 16, 20425, {1, 3, 3, 9, 1, 35, 97, 237, 279, 541, 1911, 661, 7603, 8183, 22071, 37317}},
+{4947, 16, 20428, {1, 3, 3, 11, 11, 63, 101, 71, 227, 259, 1545, 2779, 3859, 4859, 18957, 31749}},
+{4948, 16, 20434, {1, 3, 3, 1, 27, 29, 91, 215, 381, 607, 1701, 1709, 247, 12403, 29943, 59533}},
+{4949, 16, 20443, {1, 1, 7, 1, 11, 23, 47, 141, 37, 881, 1443, 3921, 3281, 7417, 1549, 50653}},
+{4950, 16, 20488, {1, 1, 7, 11, 23, 61, 17, 39, 373, 871, 1107, 1875, 1419, 3981, 1333, 11485}},
+{4951, 16, 20502, {1, 1, 7, 11, 21, 51, 127, 145, 129, 425, 1263, 1989, 699, 7317, 24827, 15049}},
+{4952, 16, 20505, {1, 1, 1, 11, 9, 59, 59, 67, 329, 841, 905, 467, 1905, 895, 29711, 25585}},
+{4953, 16, 20535, {1, 1, 1, 15, 3, 39, 11, 205, 297, 383, 445, 2139, 2935, 2399, 22237, 20355}},
+{4954, 16, 20541, {1, 3, 7, 7, 17, 9, 17, 205, 369, 1019, 1703, 755, 5507, 14749, 16461, 14519}},
+{4955, 16, 20554, {1, 3, 7, 3, 5, 31, 97, 35, 43, 249, 773, 4033, 6085, 1241, 24743, 22415}},
+{4956, 16, 20577, {1, 3, 7, 3, 17, 11, 45, 203, 251, 669, 1463, 1897, 7913, 2315, 30307, 15431}},
+{4957, 16, 20583, {1, 1, 5, 5, 7, 53, 83, 13, 1, 841, 423, 1059, 3951, 14209, 11113, 13931}},
+{4958, 16, 20602, {1, 3, 3, 5, 5, 15, 11, 71, 237, 553, 829, 3653, 4991, 1003, 8353, 52173}},
+{4959, 16, 20611, {1, 3, 3, 9, 27, 39, 83, 137, 315, 883, 1155, 3541, 3815, 10633, 13277, 20269}},
+{4960, 16, 20614, {1, 3, 3, 15, 13, 55, 43, 19, 345, 351, 1117, 1747, 1949, 3195, 12241, 52441}},
+{4961, 16, 20626, {1, 1, 3, 5, 1, 11, 113, 117, 37, 103, 1681, 3269, 1659, 14779, 30479, 31123}},
+{4962, 16, 20628, {1, 3, 7, 13, 1, 63, 9, 63, 65, 737, 785, 1713, 8123, 10053, 29871, 17647}},
+{4963, 16, 20635, {1, 1, 3, 5, 17, 45, 71, 37, 283, 145, 1927, 75, 7355, 4681, 2777, 31465}},
+{4964, 16, 20642, {1, 1, 3, 7, 21, 19, 113, 89, 67, 751, 99, 421, 201, 6345, 9473, 39849}},
+{4965, 16, 20674, {1, 1, 5, 11, 31, 57, 75, 79, 393, 745, 1435, 3039, 1175, 983, 923, 42867}},
+{4966, 16, 20716, {1, 1, 5, 9, 31, 47, 31, 61, 85, 651, 1733, 3973, 1979, 7223, 13817, 30593}},
+{4967, 16, 20734, {1, 1, 1, 11, 31, 21, 23, 177, 401, 55, 537, 3775, 3241, 15157, 11849, 15629}},
+{4968, 16, 20765, {1, 1, 1, 13, 31, 53, 79, 57, 35, 617, 61, 89, 6917, 6045, 23879, 45485}},
+{4969, 16, 20801, {1, 3, 7, 7, 3, 43, 57, 243, 107, 321, 273, 2171, 2069, 6171, 29181, 8281}},
+{4970, 16, 20804, {1, 1, 1, 11, 3, 27, 51, 57, 81, 795, 1673, 2601, 7335, 16243, 863, 20663}},
+{4971, 16, 20808, {1, 1, 5, 9, 7, 19, 31, 87, 509, 899, 1133, 1609, 2163, 7595, 10523, 43181}},
+{4972, 16, 20831, {1, 1, 1, 7, 21, 53, 103, 43, 507, 317, 685, 1329, 7057, 7275, 2277, 28271}},
+{4973, 16, 20832, {1, 1, 7, 7, 3, 35, 81, 81, 261, 587, 1571, 2771, 4653, 6517, 25101, 56753}},
+{4974, 16, 20862, {1, 3, 1, 11, 17, 61, 29, 137, 7, 929, 393, 2513, 2423, 5457, 6285, 12525}},
+{4975, 16, 20877, {1, 3, 1, 9, 25, 63, 17, 45, 439, 591, 273, 877, 7741, 8381, 32277, 24635}},
+{4976, 16, 20880, {1, 3, 1, 5, 19, 11, 17, 175, 297, 77, 961, 3331, 5193, 14347, 12713, 32067}},
+{4977, 16, 20885, {1, 1, 5, 11, 3, 17, 13, 21, 219, 653, 1279, 1657, 7659, 14459, 27661, 38093}},
+{4978, 16, 20889, {1, 3, 7, 7, 29, 17, 67, 35, 451, 91, 919, 3163, 7459, 14971, 4317, 42503}},
+{4979, 16, 20905, {1, 3, 3, 15, 7, 61, 69, 211, 349, 97, 911, 503, 3903, 12327, 11049, 29387}},
+{4980, 16, 20914, {1, 1, 7, 3, 5, 7, 63, 237, 387, 931, 693, 1143, 6545, 8529, 25217, 53087}},
+{4981, 16, 20967, {1, 1, 5, 7, 1, 13, 21, 169, 259, 289, 437, 649, 4905, 15261, 29997, 34043}},
+{4982, 16, 21028, {1, 1, 1, 9, 25, 13, 19, 229, 29, 213, 1941, 1501, 3463, 15761, 15635, 39687}},
+{4983, 16, 21031, {1, 1, 5, 7, 13, 29, 101, 57, 483, 913, 1025, 2139, 4327, 7847, 12455, 41797}},
+{4984, 16, 21043, {1, 1, 3, 11, 17, 27, 97, 79, 411, 9, 1797, 3721, 5291, 859, 8889, 6151}},
+{4985, 16, 21052, {1, 1, 1, 5, 17, 61, 45, 187, 157, 301, 1017, 1507, 6031, 4271, 32593, 23739}},
+{4986, 16, 21058, {1, 1, 3, 11, 31, 39, 7, 169, 15, 799, 1585, 2055, 4683, 13247, 23743, 50399}},
+{4987, 16, 21087, {1, 1, 1, 9, 25, 37, 15, 39, 339, 383, 1153, 1211, 5745, 15249, 26021, 39871}},
+{4988, 16, 21088, {1, 1, 3, 13, 17, 51, 27, 137, 231, 877, 309, 3633, 2575, 12259, 2743, 14781}},
+{4989, 16, 21093, {1, 1, 5, 7, 5, 33, 95, 19, 37, 829, 1489, 3525, 3887, 8277, 21867, 3581}},
+{4990, 16, 21106, {1, 1, 1, 15, 11, 33, 99, 213, 365, 549, 1603, 777, 3787, 12209, 14999, 50607}},
+{4991, 16, 21108, {1, 3, 1, 9, 23, 25, 57, 147, 73, 285, 1229, 1763, 4579, 14771, 4003, 38197}},
+{4992, 16, 21118, {1, 1, 5, 1, 15, 55, 25, 209, 135, 895, 311, 139, 2445, 6903, 12129, 27907}},
+{4993, 16, 21122, {1, 1, 5, 7, 23, 29, 33, 135, 325, 517, 2021, 1721, 4235, 2363, 12905, 18811}},
+{4994, 16, 21131, {1, 1, 1, 9, 3, 19, 69, 29, 157, 787, 1969, 3711, 8179, 5691, 4059, 25541}},
+{4995, 16, 21139, {1, 1, 5, 15, 1, 61, 11, 195, 317, 13, 923, 2149, 4001, 12843, 27109, 30625}},
+{4996, 16, 21141, {1, 3, 1, 7, 3, 13, 45, 187, 445, 859, 53, 3227, 4381, 8273, 32699, 48719}},
+{4997, 16, 21146, {1, 1, 7, 7, 21, 19, 47, 101, 119, 311, 577, 3309, 4585, 12109, 15153, 22915}},
+{4998, 16, 21162, {1, 3, 5, 15, 21, 39, 15, 211, 349, 237, 1873, 3333, 7837, 12811, 14321, 20227}},
+{4999, 16, 21164, {1, 1, 5, 5, 19, 47, 15, 239, 23, 763, 537, 1477, 2231, 10885, 19487, 47385}},
+{5000, 16, 21184, {1, 1, 3, 1, 19, 37, 67, 85, 11, 817, 869, 2249, 4111, 12411, 10405, 20055}},
+{5001, 16, 21208, {1, 1, 3, 3, 1, 41, 85, 137, 91, 369, 1863, 759, 303, 15859, 8063, 12811}},
+{5002, 16, 21211, {1, 3, 1, 11, 23, 1, 11, 219, 201, 573, 1573, 619, 2959, 6485, 7483, 46099}},
+{5003, 16, 21213, {1, 3, 3, 9, 13, 9, 9, 255, 47, 375, 409, 1435, 1665, 14967, 3247, 18193}},
+{5004, 16, 21230, {1, 1, 1, 5, 9, 61, 121, 173, 51, 415, 1621, 3947, 1379, 847, 23187, 39259}},
+{5005, 16, 21270, {1, 1, 1, 7, 3, 19, 95, 59, 187, 453, 1533, 445, 2699, 4817, 25983, 50925}},
+{5006, 16, 21276, {1, 3, 5, 13, 25, 25, 33, 5, 497, 1, 535, 1653, 6541, 10939, 17721, 43829}},
+{5007, 16, 21285, {1, 3, 7, 11, 9, 59, 115, 127, 85, 505, 541, 3243, 5853, 12673, 25275, 39577}},
+{5008, 16, 21297, {1, 3, 7, 1, 17, 25, 83, 127, 225, 295, 1823, 2051, 847, 4249, 13763, 5723}},
+{5009, 16, 21304, {1, 1, 1, 5, 3, 63, 39, 131, 191, 983, 119, 3287, 3335, 7969, 31347, 39439}},
+{5010, 16, 21310, {1, 3, 7, 9, 19, 31, 19, 91, 35, 677, 1229, 1371, 6497, 3315, 15239, 54235}},
+{5011, 16, 21330, {1, 1, 1, 15, 3, 49, 113, 199, 135, 35, 709, 385, 7923, 3711, 18351, 12711}},
+{5012, 16, 21339, {1, 1, 3, 15, 31, 13, 41, 1, 183, 95, 1625, 1675, 7881, 6607, 4165, 27151}},
+{5013, 16, 21346, {1, 3, 3, 15, 21, 57, 81, 49, 5, 297, 131, 883, 1113, 2497, 32129, 39139}},
+{5014, 16, 21391, {1, 3, 5, 7, 29, 47, 101, 173, 299, 879, 143, 3341, 3929, 6797, 8753, 47963}},
+{5015, 16, 21427, {1, 3, 3, 13, 11, 39, 27, 187, 27, 763, 1515, 1903, 5897, 10061, 14595, 12713}},
+{5016, 16, 21451, {1, 3, 5, 11, 27, 35, 37, 213, 45, 867, 1591, 3083, 8123, 5045, 31703, 61487}},
+{5017, 16, 21465, {1, 1, 3, 5, 3, 31, 23, 89, 369, 371, 1165, 3673, 6821, 333, 10881, 4153}},
+{5018, 16, 21468, {1, 1, 7, 13, 1, 33, 49, 195, 223, 197, 1799, 2427, 6171, 493, 13503, 23619}},
+{5019, 16, 21471, {1, 1, 3, 9, 5, 59, 105, 215, 449, 527, 1661, 2643, 309, 11239, 11633, 63459}},
+{5020, 16, 21533, {1, 1, 3, 11, 13, 11, 15, 99, 409, 807, 1911, 883, 1323, 9037, 6401, 545}},
+{5021, 16, 21610, {1, 1, 5, 7, 7, 7, 1, 167, 353, 923, 1403, 3109, 4981, 3877, 25451, 4667}},
+{5022, 16, 21615, {1, 1, 5, 11, 11, 25, 121, 153, 111, 785, 1301, 1497, 6267, 14919, 24125, 52029}},
+{5023, 16, 21630, {1, 3, 3, 5, 29, 55, 63, 177, 305, 41, 111, 1065, 1127, 113, 2815, 12979}},
+{5024, 16, 21633, {1, 3, 5, 7, 23, 39, 17, 179, 267, 917, 511, 3923, 915, 14173, 10689, 50749}},
+{5025, 16, 21657, {1, 1, 5, 3, 9, 45, 15, 157, 495, 625, 407, 2769, 3267, 7593, 17957, 54597}},
+{5026, 16, 21658, {1, 3, 3, 11, 21, 13, 5, 207, 107, 965, 1803, 1541, 3487, 3483, 109, 26923}},
+{5027, 16, 21669, {1, 1, 5, 11, 25, 49, 99, 135, 109, 371, 1307, 1815, 1095, 2329, 27101, 52269}},
+{5028, 16, 21670, {1, 3, 5, 5, 13, 9, 109, 79, 151, 47, 311, 3873, 3645, 3773, 1083, 31599}},
+{5029, 16, 21673, {1, 3, 5, 15, 1, 9, 87, 21, 145, 583, 159, 2435, 587, 10123, 24803, 19993}},
+{5030, 16, 21701, {1, 3, 1, 1, 23, 11, 5, 45, 373, 1011, 1353, 277, 7051, 3845, 12391, 25313}},
+{5031, 16, 21719, {1, 1, 1, 9, 13, 13, 109, 251, 97, 483, 1723, 2555, 813, 9345, 11351, 44705}},
+{5032, 16, 21720, {1, 3, 5, 7, 21, 49, 63, 13, 119, 813, 1559, 983, 499, 15159, 24163, 59903}},
+{5033, 16, 21747, {1, 1, 3, 5, 27, 33, 27, 165, 207, 693, 1401, 1357, 7637, 337, 10163, 43273}},
+{5034, 16, 21819, {1, 1, 5, 13, 29, 7, 71, 187, 1, 655, 1829, 2645, 6969, 5435, 28415, 33199}},
+{5035, 16, 21839, {1, 1, 1, 13, 17, 21, 13, 141, 41, 267, 1165, 1893, 3455, 10737, 16693, 33065}},
+{5036, 16, 21854, {1, 1, 5, 1, 7, 27, 7, 67, 107, 11, 763, 2529, 3023, 15745, 17023, 51911}},
+{5037, 16, 21857, {1, 3, 3, 3, 7, 57, 123, 249, 309, 511, 1655, 1379, 725, 7325, 20261, 65039}},
+{5038, 16, 21864, {1, 1, 5, 11, 3, 27, 23, 27, 285, 771, 2017, 1727, 4847, 2665, 30655, 47625}},
+{5039, 16, 21882, {1, 3, 7, 7, 17, 3, 93, 133, 427, 1021, 1135, 341, 6711, 11713, 24157, 1561}},
+{5040, 16, 21900, {1, 1, 3, 7, 15, 55, 11, 247, 65, 115, 1967, 535, 841, 15131, 28381, 31337}},
+{5041, 16, 21903, {1, 3, 1, 7, 9, 45, 73, 151, 127, 125, 767, 2003, 6893, 3875, 451, 30275}},
+{5042, 16, 21928, {1, 1, 7, 3, 5, 55, 127, 123, 163, 763, 1165, 1637, 6267, 7215, 23403, 20961}},
+{5043, 16, 21931, {1, 1, 1, 13, 1, 21, 65, 141, 369, 413, 1675, 27, 7357, 6929, 18083, 829}},
+{5044, 16, 21946, {1, 3, 5, 13, 1, 17, 97, 107, 249, 931, 47, 3537, 2245, 9827, 13673, 23217}},
+{5045, 16, 21971, {1, 1, 1, 11, 13, 19, 43, 31, 51, 727, 1001, 927, 771, 11853, 5761, 60537}},
+{5046, 16, 21974, {1, 3, 1, 7, 23, 27, 115, 5, 201, 431, 1021, 585, 6069, 12511, 6129, 2105}},
+{5047, 16, 21978, {1, 1, 3, 11, 3, 25, 75, 129, 389, 131, 223, 2263, 5377, 5561, 15633, 39527}},
+{5048, 16, 21993, {1, 3, 3, 1, 27, 43, 101, 55, 319, 549, 1971, 2255, 353, 93, 25661, 59077}},
+{5049, 16, 21994, {1, 1, 5, 11, 29, 57, 27, 135, 341, 913, 1637, 1781, 457, 11293, 1013, 53863}},
+{5050, 16, 22030, {1, 1, 1, 11, 3, 51, 79, 251, 443, 651, 393, 3635, 7397, 5443, 4225, 991}},
+{5051, 16, 22035, {1, 3, 7, 13, 31, 9, 3, 109, 427, 735, 891, 2789, 2169, 6459, 355, 43177}},
+{5052, 16, 22063, {1, 3, 3, 3, 13, 7, 93, 195, 293, 37, 75, 2467, 933, 8017, 9925, 61397}},
+{5053, 16, 22068, {1, 1, 5, 7, 25, 15, 69, 199, 161, 769, 387, 1491, 4553, 4173, 25631, 37089}},
+{5054, 16, 22086, {1, 3, 1, 3, 7, 59, 53, 93, 103, 413, 531, 887, 6149, 2901, 22611, 27135}},
+{5055, 16, 22104, {1, 1, 1, 13, 31, 39, 71, 215, 385, 821, 1603, 3043, 4967, 10953, 11543, 64433}},
+{5056, 16, 22119, {1, 3, 1, 7, 7, 63, 5, 143, 1, 339, 1165, 3809, 4257, 12879, 21581, 21307}},
+{5057, 16, 22153, {1, 1, 1, 15, 1, 35, 67, 227, 277, 879, 513, 3423, 6153, 11573, 12809, 34335}},
+{5058, 16, 22168, {1, 3, 7, 9, 9, 39, 47, 17, 101, 179, 631, 1307, 481, 871, 16807, 39811}},
+{5059, 16, 22183, {1, 3, 1, 1, 13, 25, 53, 179, 285, 267, 407, 3781, 3267, 3545, 525, 15733}},
+{5060, 16, 22189, {1, 1, 1, 13, 11, 35, 45, 181, 319, 767, 283, 3021, 5405, 403, 3587, 7291}},
+{5061, 16, 22204, {1, 1, 7, 3, 5, 9, 67, 129, 101, 117, 267, 1925, 1209, 13095, 7123, 62941}},
+{5062, 16, 22230, {1, 1, 7, 3, 5, 63, 109, 199, 95, 421, 193, 3519, 6551, 955, 1679, 16627}},
+{5063, 16, 22240, {1, 1, 5, 13, 1, 47, 71, 157, 343, 653, 981, 1335, 3737, 7185, 28861, 22883}},
+{5064, 16, 22246, {1, 1, 3, 15, 7, 63, 7, 81, 481, 5, 1159, 1361, 4167, 2575, 7437, 16917}},
+{5065, 16, 22269, {1, 3, 7, 1, 27, 17, 61, 193, 317, 841, 1149, 955, 5161, 4275, 1955, 15665}},
+{5066, 16, 22282, {1, 1, 1, 7, 19, 63, 77, 57, 367, 237, 579, 3701, 5763, 4951, 24151, 45215}},
+{5067, 16, 22302, {1, 1, 5, 11, 29, 7, 119, 155, 431, 999, 757, 2433, 5811, 3709, 29573, 23639}},
+{5068, 16, 22330, {1, 3, 3, 3, 15, 35, 125, 13, 275, 507, 1719, 1537, 2349, 12909, 8107, 9845}},
+{5069, 16, 22347, {1, 3, 1, 13, 27, 27, 11, 69, 15, 1017, 207, 625, 809, 2921, 8939, 30293}},
+{5070, 16, 22349, {1, 1, 7, 11, 31, 51, 113, 193, 69, 845, 73, 919, 3523, 3987, 23665, 36527}},
+{5071, 16, 22383, {1, 3, 7, 11, 21, 31, 103, 29, 5, 81, 1081, 3847, 4697, 8857, 30769, 40053}},
+{5072, 16, 22386, {1, 1, 1, 1, 5, 11, 5, 169, 13, 899, 769, 3823, 5405, 5991, 3821, 27767}},
+{5073, 16, 22432, {1, 1, 3, 15, 1, 35, 9, 83, 23, 701, 1807, 1681, 4009, 127, 31751, 38059}},
+{5074, 16, 22450, {1, 3, 3, 7, 9, 61, 73, 111, 193, 607, 2001, 413, 3751, 16337, 16597, 23959}},
+{5075, 16, 22473, {1, 1, 7, 7, 21, 29, 53, 253, 187, 507, 1191, 3521, 463, 2167, 23785, 19867}},
+{5076, 16, 22487, {1, 3, 5, 3, 19, 43, 101, 93, 257, 61, 1589, 3883, 1975, 7283, 5253, 23257}},
+{5077, 16, 22527, {1, 3, 1, 9, 1, 63, 25, 101, 377, 571, 1701, 3385, 243, 12051, 32619, 10459}},
+{5078, 16, 22537, {1, 1, 1, 5, 17, 11, 37, 197, 205, 879, 625, 959, 7389, 7857, 20615, 20405}},
+{5079, 16, 22557, {1, 3, 5, 5, 27, 41, 9, 109, 197, 623, 1045, 63, 7977, 11355, 28613, 5131}},
+{5080, 16, 22561, {1, 1, 5, 11, 5, 29, 27, 85, 131, 247, 433, 3981, 2677, 15415, 869, 6045}},
+{5081, 16, 22568, {1, 3, 1, 13, 9, 49, 25, 79, 135, 719, 93, 631, 2149, 5929, 29833, 38673}},
+{5082, 16, 22573, {1, 3, 7, 11, 15, 13, 37, 233, 227, 205, 1579, 65, 1429, 13499, 26355, 63821}},
+{5083, 16, 22591, {1, 1, 5, 11, 21, 19, 7, 183, 409, 275, 899, 3665, 6207, 849, 24339, 1617}},
+{5084, 16, 22593, {1, 3, 1, 3, 21, 61, 23, 125, 463, 489, 1265, 2975, 3907, 11881, 7533, 43331}},
+{5085, 16, 22605, {1, 3, 1, 15, 15, 51, 83, 31, 175, 47, 1791, 3651, 6735, 5013, 723, 24141}},
+{5086, 16, 22620, {1, 3, 1, 9, 17, 41, 57, 43, 469, 911, 1251, 2105, 3133, 3437, 10097, 26687}},
+{5087, 16, 22627, {1, 1, 3, 3, 9, 9, 125, 201, 141, 943, 1509, 1239, 6575, 8707, 363, 23309}},
+{5088, 16, 22636, {1, 1, 5, 3, 19, 37, 43, 141, 413, 149, 1449, 1003, 4473, 12395, 4101, 61201}},
+{5089, 16, 22647, {1, 1, 5, 11, 17, 37, 41, 33, 57, 627, 325, 1895, 1773, 1339, 24859, 587}},
+{5090, 16, 22697, {1, 1, 1, 3, 5, 49, 127, 109, 361, 853, 1437, 3451, 4031, 5379, 27463, 47425}},
+{5091, 16, 22715, {1, 3, 5, 7, 9, 57, 71, 219, 347, 791, 797, 73, 6241, 12717, 24429, 40977}},
+{5092, 16, 22725, {1, 1, 5, 9, 27, 43, 43, 227, 433, 413, 1109, 2589, 4535, 8947, 8121, 43479}},
+{5093, 16, 22732, {1, 3, 7, 1, 9, 21, 81, 23, 157, 313, 197, 2845, 8059, 15957, 28657, 28093}},
+{5094, 16, 22749, {1, 3, 1, 11, 15, 17, 115, 27, 421, 743, 1885, 2089, 5011, 7137, 7395, 36853}},
+{5095, 16, 22766, {1, 1, 5, 15, 5, 53, 69, 255, 63, 29, 1011, 3201, 1467, 15441, 26255, 62895}},
+{5096, 16, 22768, {1, 3, 1, 11, 3, 47, 35, 195, 149, 849, 1317, 439, 3539, 845, 15295, 42183}},
+{5097, 16, 22771, {1, 1, 5, 15, 15, 37, 67, 105, 495, 985, 1777, 3137, 8039, 11795, 29771, 35045}},
+{5098, 16, 22788, {1, 1, 3, 1, 25, 17, 67, 227, 229, 419, 1319, 3325, 1293, 8585, 28425, 34013}},
+{5099, 16, 22797, {1, 1, 5, 1, 27, 51, 71, 197, 375, 407, 259, 4005, 3309, 5475, 13421, 60065}},
+{5100, 16, 22822, {1, 3, 1, 5, 11, 17, 89, 45, 311, 425, 1629, 773, 7267, 8699, 27547, 37081}},
+{5101, 16, 22828, {1, 3, 1, 7, 9, 25, 101, 105, 489, 217, 103, 1959, 4049, 5793, 31201, 11947}},
+{5102, 16, 22851, {1, 1, 5, 5, 19, 3, 63, 55, 431, 49, 273, 3253, 5357, 13801, 9735, 21883}},
+{5103, 16, 22888, {1, 1, 1, 11, 13, 3, 75, 201, 477, 201, 1875, 657, 6217, 8651, 2207, 16421}},
+{5104, 16, 22893, {1, 1, 5, 13, 5, 31, 75, 113, 25, 171, 1147, 3089, 7095, 4405, 26155, 42323}},
+{5105, 16, 22901, {1, 3, 5, 5, 5, 49, 99, 171, 445, 1023, 1793, 3159, 5809, 12509, 31723, 60411}},
+{5106, 16, 22902, {1, 3, 7, 3, 23, 51, 111, 27, 103, 159, 433, 293, 1741, 3599, 4067, 40667}},
+{5107, 16, 22921, {1, 3, 3, 13, 11, 9, 11, 21, 453, 35, 1649, 1261, 3539, 14081, 5581, 57105}},
+{5108, 16, 22929, {1, 3, 3, 13, 7, 9, 113, 87, 391, 647, 223, 1345, 4481, 9855, 20129, 10807}},
+{5109, 16, 22946, {1, 3, 7, 15, 3, 61, 15, 117, 97, 495, 985, 819, 181, 1363, 13111, 35857}},
+{5110, 16, 22948, {1, 3, 1, 9, 3, 27, 125, 151, 217, 961, 707, 2647, 5307, 621, 12581, 13941}},
+{5111, 16, 22951, {1, 3, 1, 11, 17, 37, 35, 211, 179, 29, 627, 3623, 6429, 16237, 24699, 14385}},
+{5112, 16, 22958, {1, 3, 3, 9, 3, 57, 35, 3, 85, 1017, 1739, 2241, 7297, 15637, 27085, 41237}},
+{5113, 16, 22975, {1, 1, 3, 7, 7, 13, 5, 85, 505, 51, 409, 867, 677, 12451, 13633, 47883}},
+{5114, 16, 22983, {1, 3, 5, 13, 5, 51, 37, 79, 237, 133, 1331, 3263, 349, 4971, 16067, 62485}},
+{5115, 16, 22990, {1, 1, 7, 11, 29, 41, 101, 219, 391, 1023, 1681, 3163, 4071, 14665, 11041, 14523}},
+{5116, 16, 23032, {1, 1, 3, 3, 13, 55, 37, 119, 471, 665, 1315, 3071, 5993, 12005, 13549, 63425}},
+{5117, 16, 23047, {1, 3, 5, 7, 5, 25, 59, 71, 77, 841, 91, 1841, 6997, 1139, 11843, 52209}},
+{5118, 16, 23053, {1, 3, 7, 15, 17, 25, 85, 173, 373, 459, 1713, 1055, 5337, 9921, 15213, 44235}},
+{5119, 16, 23054, {1, 1, 1, 15, 7, 11, 89, 237, 131, 565, 745, 457, 4447, 5581, 11053, 43819}},
+{5120, 16, 23082, {1, 3, 5, 1, 29, 21, 11, 7, 125, 851, 2023, 3321, 1885, 67, 8809, 43291}},
+{5121, 16, 23095, {1, 3, 5, 11, 11, 43, 41, 97, 353, 813, 85, 2453, 769, 11709, 4697, 2849}},
+{5122, 16, 23116, {1, 1, 5, 5, 21, 29, 87, 179, 157, 981, 129, 2139, 6841, 5479, 27111, 20749}},
+{5123, 16, 23197, {1, 1, 3, 9, 31, 59, 61, 15, 423, 33, 467, 1817, 6535, 7341, 31061, 20937}},
+{5124, 16, 23221, {1, 1, 7, 3, 1, 21, 127, 135, 321, 699, 727, 3079, 753, 3971, 5611, 28345}},
+{5125, 16, 23257, {1, 3, 7, 11, 27, 3, 39, 63, 389, 433, 43, 1443, 6241, 10769, 20485, 58823}},
+{5126, 16, 23260, {1, 1, 1, 11, 3, 13, 5, 57, 503, 707, 677, 3355, 6691, 8841, 20041, 11867}},
+{5127, 16, 23263, {1, 1, 3, 11, 31, 39, 107, 221, 81, 125, 1439, 2429, 2109, 3931, 31007, 10915}},
+{5128, 16, 23267, {1, 3, 3, 9, 17, 53, 13, 121, 127, 15, 1825, 1909, 5951, 13503, 31565, 56163}},
+{5129, 16, 23282, {1, 1, 1, 1, 19, 55, 3, 153, 385, 277, 1297, 3655, 6027, 3057, 11341, 46989}},
+{5130, 16, 23284, {1, 1, 5, 9, 3, 55, 37, 223, 353, 141, 1917, 3827, 2255, 7617, 10971, 10641}},
+{5131, 16, 23314, {1, 3, 7, 9, 29, 41, 71, 19, 137, 243, 2047, 395, 6981, 15887, 9479, 60199}},
+{5132, 16, 23326, {1, 1, 1, 9, 17, 43, 51, 191, 405, 727, 485, 987, 1855, 15801, 22529, 10165}},
+{5133, 16, 23335, {1, 3, 1, 7, 27, 31, 69, 255, 153, 793, 1353, 1981, 83, 11387, 6747, 23379}},
+{5134, 16, 23368, {1, 1, 5, 5, 31, 49, 83, 157, 63, 647, 1367, 3995, 5899, 8429, 18317, 3471}},
+{5135, 16, 23373, {1, 3, 5, 13, 19, 15, 99, 13, 143, 887, 529, 2855, 573, 9799, 13585, 59263}},
+{5136, 16, 23401, {1, 3, 5, 3, 13, 47, 103, 87, 11, 381, 397, 899, 71, 15539, 13005, 38297}},
+{5137, 16, 23415, {1, 1, 1, 3, 1, 53, 45, 141, 1, 941, 261, 3291, 5177, 9843, 6309, 62799}},
+{5138, 16, 23432, {1, 1, 5, 9, 29, 31, 107, 57, 135, 229, 1147, 247, 265, 12757, 21365, 7219}},
+{5139, 16, 23476, {1, 1, 1, 3, 1, 49, 55, 247, 495, 449, 141, 1349, 7393, 2589, 23587, 1097}},
+{5140, 16, 23479, {1, 3, 5, 1, 9, 11, 73, 153, 89, 575, 1805, 137, 435, 3687, 32169, 24275}},
+{5141, 16, 23497, {1, 1, 7, 15, 25, 61, 51, 21, 109, 139, 611, 3907, 6721, 5081, 6665, 51463}},
+{5142, 16, 23505, {1, 1, 1, 9, 13, 23, 59, 203, 33, 1013, 1533, 291, 6171, 15463, 8581, 9497}},
+{5143, 16, 23508, {1, 3, 3, 9, 7, 25, 51, 189, 49, 265, 1163, 1141, 2467, 7839, 7083, 65527}},
+{5144, 16, 23531, {1, 1, 3, 9, 19, 33, 77, 9, 181, 919, 623, 1521, 7853, 2199, 24115, 60607}},
+{5145, 16, 23536, {1, 1, 3, 11, 9, 11, 27, 57, 355, 313, 151, 3391, 4869, 12541, 30031, 29455}},
+{5146, 16, 23542, {1, 3, 5, 9, 17, 13, 91, 123, 235, 841, 1113, 1451, 501, 3863, 32483, 9445}},
+{5147, 16, 23565, {1, 3, 7, 3, 13, 25, 87, 243, 449, 293, 1279, 3571, 2693, 13459, 5895, 38127}},
+{5148, 16, 23573, {1, 1, 3, 15, 27, 61, 7, 57, 255, 971, 131, 2585, 2187, 7191, 17779, 34587}},
+{5149, 16, 23590, {1, 3, 3, 7, 23, 29, 55, 41, 463, 873, 1781, 2851, 4731, 9819, 25587, 32199}},
+{5150, 16, 23593, {1, 1, 1, 9, 29, 39, 25, 143, 171, 141, 223, 467, 4417, 9575, 23159, 33819}},
+{5151, 16, 23604, {1, 1, 5, 13, 19, 61, 19, 75, 25, 361, 585, 1627, 2231, 1831, 24885, 37917}},
+{5152, 16, 23621, {1, 3, 7, 7, 23, 19, 59, 55, 323, 55, 143, 131, 27, 15363, 26423, 43963}},
+{5153, 16, 23622, {1, 1, 5, 5, 25, 9, 33, 17, 427, 481, 315, 3999, 4757, 4545, 7695, 56733}},
+{5154, 16, 23636, {1, 3, 5, 13, 5, 59, 45, 117, 115, 263, 1441, 3307, 1085, 3875, 25869, 19725}},
+{5155, 16, 23662, {1, 3, 3, 15, 13, 39, 31, 243, 293, 345, 343, 1911, 6123, 12577, 32081, 59993}},
+{5156, 16, 23667, {1, 3, 5, 13, 17, 37, 105, 201, 205, 929, 435, 1467, 8063, 6963, 13709, 53275}},
+{5157, 16, 23703, {1, 3, 7, 15, 31, 3, 65, 221, 191, 413, 427, 2579, 377, 2793, 26943, 61299}},
+{5158, 16, 23725, {1, 3, 5, 3, 11, 61, 75, 107, 53, 689, 1845, 859, 333, 889, 27607, 48795}},
+{5159, 16, 23734, {1, 1, 5, 7, 1, 11, 37, 181, 323, 187, 1511, 25, 5517, 11957, 7093, 429}},
+{5160, 16, 23738, {1, 3, 3, 1, 25, 31, 125, 139, 433, 583, 683, 587, 5389, 1225, 26047, 18717}},
+{5161, 16, 23752, {1, 3, 1, 15, 23, 33, 23, 147, 279, 513, 157, 4023, 2669, 7543, 2111, 9191}},
+{5162, 16, 23800, {1, 3, 1, 1, 5, 39, 55, 127, 257, 649, 347, 3001, 2215, 15579, 29665, 10337}},
+{5163, 16, 23803, {1, 1, 1, 15, 19, 55, 105, 183, 505, 1003, 1311, 2253, 1861, 3561, 19581, 46183}},
+{5164, 16, 23818, {1, 3, 1, 9, 23, 5, 127, 215, 195, 817, 719, 1285, 919, 8627, 20427, 2723}},
+{5165, 16, 23832, {1, 1, 1, 5, 15, 31, 43, 131, 377, 57, 1531, 915, 2871, 1805, 19765, 60529}},
+{5166, 16, 23842, {1, 3, 3, 3, 15, 1, 93, 55, 477, 221, 643, 1319, 959, 475, 14015, 48823}},
+{5167, 16, 23851, {1, 3, 3, 7, 19, 13, 13, 191, 421, 751, 1103, 2129, 1973, 14935, 26485, 41269}},
+{5168, 16, 23873, {1, 1, 5, 13, 17, 43, 81, 83, 67, 643, 1799, 1157, 4365, 2815, 29871, 5351}},
+{5169, 16, 23883, {1, 3, 1, 9, 21, 31, 87, 177, 25, 403, 1357, 4047, 959, 5133, 7307, 4333}},
+{5170, 16, 23888, {1, 1, 7, 7, 29, 39, 27, 139, 159, 529, 1323, 3823, 4569, 12711, 30263, 10961}},
+{5171, 16, 23910, {1, 3, 1, 13, 27, 15, 59, 1, 107, 723, 497, 43, 143, 16119, 29177, 5653}},
+{5172, 16, 23934, {1, 1, 5, 9, 15, 41, 23, 109, 101, 639, 277, 1687, 1311, 1995, 5403, 6867}},
+{5173, 16, 23938, {1, 1, 5, 3, 13, 1, 95, 177, 379, 545, 789, 3479, 4135, 445, 5869, 38923}},
+{5174, 16, 23949, {1, 1, 3, 9, 21, 31, 23, 65, 209, 383, 271, 367, 6605, 1169, 27267, 9331}},
+{5175, 16, 23955, {1, 1, 1, 1, 27, 39, 121, 29, 155, 465, 947, 2675, 6753, 11647, 29781, 30251}},
+{5176, 16, 23967, {1, 3, 1, 5, 7, 45, 7, 21, 223, 363, 1021, 751, 2257, 14423, 19629, 64867}},
+{5177, 16, 23973, {1, 3, 1, 9, 31, 53, 13, 99, 49, 389, 867, 327, 4145, 3265, 15423, 14985}},
+{5178, 16, 23991, {1, 1, 1, 15, 11, 11, 27, 41, 333, 161, 1343, 2023, 3789, 13563, 16957, 26849}},
+{5179, 16, 24024, {1, 3, 7, 1, 7, 51, 7, 163, 239, 393, 231, 3985, 309, 875, 837, 24791}},
+{5180, 16, 24030, {1, 1, 1, 7, 1, 43, 105, 7, 351, 755, 1781, 1925, 4961, 2961, 13427, 44317}},
+{5181, 16, 24039, {1, 3, 1, 9, 17, 39, 81, 75, 201, 931, 1547, 1857, 7251, 11687, 14437, 12603}},
+{5182, 16, 24067, {1, 3, 3, 15, 15, 23, 95, 7, 193, 9, 1749, 809, 5083, 14645, 24893, 35979}},
+{5183, 16, 24069, {1, 1, 7, 1, 9, 9, 127, 149, 433, 985, 1347, 3379, 2881, 681, 20777, 30703}},
+{5184, 16, 24084, {1, 3, 1, 11, 1, 27, 121, 111, 251, 45, 1341, 1709, 3733, 11297, 29063, 57119}},
+{5185, 16, 24112, {1, 3, 3, 1, 19, 3, 77, 127, 187, 831, 1125, 3119, 4665, 9857, 5301, 36755}},
+{5186, 16, 24115, {1, 3, 3, 3, 29, 29, 61, 225, 257, 635, 665, 1279, 3019, 2401, 8253, 40251}},
+{5187, 16, 24184, {1, 1, 7, 9, 29, 43, 47, 95, 221, 823, 257, 1485, 5183, 225, 27675, 60479}},
+{5188, 16, 24187, {1, 1, 5, 3, 15, 49, 25, 69, 101, 393, 901, 305, 4917, 13479, 30209, 9199}},
+{5189, 16, 24262, {1, 1, 3, 15, 1, 9, 47, 243, 403, 341, 143, 1365, 1817, 6017, 3853, 58625}},
+{5190, 16, 24276, {1, 3, 3, 11, 9, 49, 93, 149, 39, 177, 1863, 1027, 659, 9253, 2131, 26943}},
+{5191, 16, 24279, {1, 3, 1, 3, 25, 1, 43, 255, 217, 353, 957, 39, 4607, 15761, 24291, 33619}},
+{5192, 16, 24313, {1, 1, 1, 7, 29, 51, 71, 237, 1, 703, 19, 213, 6429, 11783, 22049, 30597}},
+{5193, 16, 24331, {1, 3, 1, 7, 31, 63, 105, 203, 473, 731, 257, 91, 5749, 4099, 30125, 40171}},
+{5194, 16, 24336, {1, 3, 7, 9, 7, 29, 119, 181, 225, 743, 1031, 55, 3997, 16221, 11663, 14847}},
+{5195, 16, 24348, {1, 3, 3, 11, 5, 21, 43, 17, 473, 981, 125, 2077, 6141, 4757, 7585, 29207}},
+{5196, 16, 24367, {1, 1, 7, 1, 27, 61, 27, 45, 267, 483, 119, 767, 957, 3411, 2653, 53967}},
+{5197, 16, 24372, {1, 1, 1, 3, 9, 41, 43, 17, 485, 253, 825, 3605, 5919, 9285, 1815, 6095}},
+{5198, 16, 24402, {1, 1, 1, 11, 7, 5, 53, 107, 309, 609, 1389, 2035, 861, 15565, 9375, 42363}},
+{5199, 16, 24420, {1, 3, 5, 3, 27, 57, 7, 177, 183, 227, 865, 183, 2903, 6325, 4393, 5257}},
+{5200, 16, 24444, {1, 3, 1, 5, 21, 29, 79, 107, 365, 427, 813, 3563, 7713, 3865, 4289, 28555}},
+{5201, 16, 24465, {1, 3, 5, 7, 11, 27, 1, 197, 425, 769, 1737, 3627, 1273, 4469, 11967, 823}},
+{5202, 16, 24466, {1, 1, 1, 13, 3, 31, 127, 159, 471, 367, 2047, 949, 1591, 12429, 21497, 27153}},
+{5203, 16, 24471, {1, 3, 1, 3, 3, 31, 31, 87, 243, 413, 1777, 1361, 4575, 1147, 17451, 33985}},
+{5204, 16, 24475, {1, 3, 3, 5, 13, 47, 45, 3, 165, 329, 743, 397, 2479, 4999, 12921, 26689}},
+{5205, 16, 24481, {1, 1, 5, 7, 17, 59, 25, 117, 217, 601, 235, 2691, 5569, 7853, 31063, 28281}},
+{5206, 16, 24488, {1, 3, 1, 11, 11, 39, 71, 77, 481, 39, 363, 1921, 3263, 12849, 13325, 41803}},
+{5207, 16, 24501, {1, 3, 7, 5, 19, 1, 59, 197, 239, 787, 1657, 1449, 4245, 1317, 19609, 53583}},
+{5208, 16, 24514, {1, 1, 7, 1, 13, 33, 81, 53, 223, 323, 477, 2421, 4045, 1855, 5823, 9661}},
+{5209, 16, 24531, {1, 3, 1, 7, 1, 3, 121, 19, 329, 569, 481, 3443, 499, 12407, 19625, 4627}},
+{5210, 16, 24534, {1, 1, 1, 7, 3, 33, 91, 241, 69, 581, 1635, 1025, 4677, 14651, 5229, 19555}},
+{5211, 16, 24559, {1, 3, 1, 15, 9, 11, 99, 47, 489, 755, 601, 1221, 4251, 4377, 20567, 33839}},
+{5212, 16, 24602, {1, 3, 3, 5, 21, 21, 127, 151, 499, 971, 1627, 609, 2365, 3183, 7413, 697}},
+{5213, 16, 24614, {1, 3, 7, 13, 5, 35, 61, 121, 51, 297, 29, 1825, 495, 1299, 12741, 3253}},
+{5214, 16, 24637, {1, 1, 1, 1, 13, 15, 49, 205, 235, 9, 849, 1101, 4533, 10221, 32419, 50151}},
+{5215, 16, 24664, {1, 1, 3, 13, 29, 31, 57, 77, 217, 195, 1951, 189, 981, 6169, 22677, 64415}},
+{5216, 16, 24676, {1, 3, 1, 5, 15, 37, 25, 233, 43, 843, 1205, 153, 6339, 3767, 16725, 32699}},
+{5217, 16, 24679, {1, 3, 3, 1, 19, 37, 11, 217, 461, 897, 1181, 2815, 295, 15153, 25351, 57211}},
+{5218, 16, 24697, {1, 3, 5, 11, 15, 9, 5, 179, 353, 769, 1457, 2919, 1201, 14871, 29549, 52265}},
+{5219, 16, 24709, {1, 1, 3, 3, 5, 51, 127, 221, 329, 543, 1537, 2701, 2709, 9311, 2715, 42669}},
+{5220, 16, 24714, {1, 3, 5, 15, 5, 41, 79, 233, 445, 265, 2001, 935, 3133, 3977, 3601, 21389}},
+{5221, 16, 24716, {1, 3, 5, 11, 3, 7, 115, 45, 311, 827, 1897, 3399, 4251, 5341, 22621, 25519}},
+{5222, 16, 24731, {1, 3, 7, 1, 11, 57, 117, 103, 401, 505, 1683, 2161, 4363, 11189, 20263, 13065}},
+{5223, 16, 24744, {1, 1, 1, 7, 23, 29, 31, 77, 63, 179, 195, 2747, 579, 11701, 5101, 11497}},
+{5224, 16, 24762, {1, 3, 7, 3, 9, 33, 81, 165, 433, 545, 1893, 3709, 3813, 6615, 1485, 6395}},
+{5225, 16, 24764, {1, 3, 1, 15, 9, 5, 27, 157, 389, 683, 1919, 509, 455, 3865, 2303, 6993}},
+{5226, 16, 24769, {1, 3, 3, 9, 5, 5, 3, 5, 299, 59, 539, 1199, 2443, 10821, 3359, 44345}},
+{5227, 16, 24806, {1, 3, 5, 9, 21, 37, 87, 35, 501, 943, 1313, 3929, 351, 9851, 22971, 35659}},
+{5228, 16, 24812, {1, 3, 7, 11, 11, 33, 77, 175, 411, 315, 1797, 2731, 4611, 1809, 22027, 50595}},
+{5229, 16, 24872, {1, 3, 7, 13, 15, 11, 13, 189, 209, 1015, 1869, 1593, 6887, 8571, 7217, 2641}},
+{5230, 16, 24878, {1, 1, 3, 13, 29, 15, 119, 127, 329, 275, 865, 1693, 225, 15735, 11071, 37127}},
+{5231, 16, 24883, {1, 3, 7, 13, 9, 31, 85, 25, 281, 401, 1923, 2391, 3875, 2079, 2055, 53275}},
+{5232, 16, 24909, {1, 3, 1, 5, 23, 57, 79, 127, 209, 901, 315, 1165, 3393, 15095, 1981, 34993}},
+{5233, 16, 24943, {1, 3, 7, 7, 25, 13, 15, 223, 157, 335, 1061, 395, 6895, 6283, 18375, 4887}},
+{5234, 16, 24946, {1, 3, 7, 13, 9, 15, 99, 201, 105, 643, 117, 3027, 641, 13353, 4343, 11875}},
+{5235, 16, 24964, {1, 1, 3, 11, 5, 51, 5, 77, 281, 207, 1201, 1187, 8107, 6625, 7517, 34377}},
+{5236, 16, 24992, {1, 1, 1, 5, 29, 61, 3, 181, 297, 151, 565, 2713, 6611, 8665, 32425, 50399}},
+{5237, 16, 25016, {1, 3, 1, 5, 1, 61, 41, 245, 95, 647, 49, 2195, 5927, 15531, 28547, 51075}},
+{5238, 16, 25022, {1, 3, 3, 15, 15, 63, 123, 63, 77, 813, 423, 715, 91, 3793, 20901, 54927}},
+{5239, 16, 25024, {1, 3, 7, 9, 15, 35, 31, 161, 127, 13, 1667, 1225, 5279, 15487, 18769, 24887}},
+{5240, 16, 25039, {1, 1, 3, 5, 27, 25, 61, 21, 447, 175, 1419, 2691, 1993, 13059, 30809, 38325}},
+{5241, 16, 25051, {1, 3, 1, 3, 15, 21, 15, 193, 233, 435, 1993, 4003, 4581, 13837, 16535, 43781}},
+{5242, 16, 25060, {1, 1, 1, 5, 1, 11, 21, 253, 59, 59, 497, 77, 2165, 8197, 5933, 25743}},
+{5243, 16, 25072, {1, 1, 3, 9, 25, 61, 29, 217, 95, 269, 799, 409, 801, 421, 19065, 53443}},
+{5244, 16, 25097, {1, 1, 7, 1, 1, 41, 71, 59, 191, 867, 223, 1467, 6679, 16031, 4451, 15313}},
+{5245, 16, 25122, {1, 1, 1, 11, 13, 27, 7, 241, 167, 969, 1267, 2953, 3769, 2415, 30065, 39483}},
+{5246, 16, 25148, {1, 1, 1, 3, 25, 61, 103, 23, 53, 799, 989, 3859, 7299, 13613, 12007, 37535}},
+{5247, 16, 25194, {1, 1, 7, 1, 29, 19, 121, 57, 355, 663, 643, 3723, 1775, 10363, 1389, 16039}},
+{5248, 16, 25201, {1, 3, 7, 3, 21, 55, 51, 67, 363, 843, 1187, 1983, 7757, 5413, 26575, 53329}},
+{5249, 16, 25204, {1, 3, 1, 3, 31, 55, 73, 55, 75, 533, 197, 1463, 2933, 6033, 24397, 41579}},
+{5250, 16, 25238, {1, 3, 1, 11, 9, 15, 107, 141, 473, 825, 901, 937, 7433, 13119, 20047, 6695}},
+{5251, 16, 25241, {1, 3, 5, 7, 19, 27, 3, 149, 507, 137, 1025, 1841, 33, 3113, 15101, 28187}},
+{5252, 16, 25248, {1, 3, 5, 7, 31, 27, 53, 45, 177, 129, 1241, 1525, 991, 4141, 17681, 39435}},
+{5253, 16, 25257, {1, 1, 1, 15, 31, 57, 29, 137, 395, 563, 101, 3367, 1277, 5431, 1169, 44321}},
+{5254, 16, 25275, {1, 3, 5, 7, 21, 15, 123, 181, 113, 313, 1763, 1429, 2985, 715, 26129, 549}},
+{5255, 16, 25278, {1, 3, 3, 1, 15, 27, 27, 139, 507, 79, 1999, 2505, 485, 7011, 13369, 7159}},
+{5256, 16, 25304, {1, 3, 3, 11, 27, 53, 109, 179, 399, 657, 697, 421, 5467, 4273, 7837, 11631}},
+{5257, 16, 25307, {1, 1, 1, 15, 1, 57, 91, 199, 443, 569, 1945, 2531, 6349, 4851, 3931, 20537}},
+{5258, 16, 25320, {1, 1, 3, 13, 3, 3, 107, 237, 261, 377, 135, 2809, 7239, 1613, 24035, 26053}},
+{5259, 16, 25334, {1, 3, 3, 5, 3, 59, 65, 197, 411, 363, 1729, 967, 3963, 4535, 111, 7273}},
+{5260, 16, 25348, {1, 1, 7, 3, 13, 39, 105, 235, 203, 1015, 1031, 3127, 1209, 10817, 22177, 44117}},
+{5261, 16, 25357, {1, 3, 3, 13, 19, 21, 123, 31, 59, 185, 1007, 1115, 1965, 13087, 18489, 34063}},
+{5262, 16, 25372, {1, 1, 7, 5, 27, 7, 33, 159, 245, 57, 2003, 3229, 2095, 4939, 31355, 23121}},
+{5263, 16, 25394, {1, 3, 3, 9, 9, 41, 49, 203, 397, 915, 821, 3685, 2269, 11159, 25441, 46377}},
+{5264, 16, 25454, {1, 3, 7, 5, 29, 33, 29, 227, 361, 961, 1905, 1149, 2799, 8115, 28235, 25685}},
+{5265, 16, 25465, {1, 3, 1, 1, 19, 13, 73, 103, 11, 183, 853, 2425, 3809, 2391, 18615, 32735}},
+{5266, 16, 25472, {1, 1, 3, 3, 21, 57, 47, 57, 157, 43, 1085, 3319, 461, 11499, 6809, 10435}},
+{5267, 16, 25492, {1, 1, 5, 5, 17, 21, 55, 17, 421, 865, 159, 1643, 4523, 1485, 11937, 8287}},
+{5268, 16, 25505, {1, 1, 3, 11, 7, 43, 39, 37, 187, 797, 1273, 1227, 2683, 1249, 3375, 44499}},
+{5269, 16, 25517, {1, 1, 5, 11, 17, 35, 27, 73, 97, 59, 921, 2171, 7577, 2847, 93, 35911}},
+{5270, 16, 25530, {1, 1, 5, 1, 5, 17, 117, 189, 357, 581, 1945, 2141, 1679, 12019, 11249, 6809}},
+{5271, 16, 25558, {1, 1, 5, 7, 15, 53, 9, 191, 153, 257, 533, 493, 2389, 4657, 20757, 57275}},
+{5272, 16, 25562, {1, 1, 1, 11, 13, 35, 85, 37, 501, 525, 543, 4057, 2001, 6183, 949, 18465}},
+{5273, 16, 25598, {1, 1, 1, 3, 15, 7, 39, 169, 359, 671, 731, 1523, 211, 1233, 29515, 57787}},
+{5274, 16, 25609, {1, 1, 3, 7, 27, 7, 41, 15, 71, 733, 1919, 401, 1915, 4815, 10571, 839}},
+{5275, 16, 25612, {1, 1, 7, 13, 27, 61, 5, 25, 293, 779, 477, 1537, 6695, 7435, 1281, 64369}},
+{5276, 16, 25627, {1, 1, 7, 7, 19, 11, 101, 45, 449, 883, 1181, 3521, 6019, 16305, 23429, 43789}},
+{5277, 16, 25651, {1, 1, 7, 5, 1, 49, 121, 89, 275, 367, 461, 1717, 2733, 4403, 9123, 35217}},
+{5278, 16, 25653, {1, 1, 7, 1, 1, 37, 41, 221, 281, 531, 357, 3783, 3561, 8135, 18405, 56045}},
+{5279, 16, 25668, {1, 3, 5, 7, 29, 9, 127, 37, 13, 519, 1059, 3973, 7253, 15159, 19337, 57103}},
+{5280, 16, 25711, {1, 3, 3, 15, 3, 41, 91, 7, 63, 747, 1649, 3367, 5945, 3603, 28465, 511}},
+{5281, 16, 25765, {1, 3, 3, 15, 27, 19, 67, 179, 505, 131, 149, 1753, 3603, 1135, 15811, 5305}},
+{5282, 16, 25770, {1, 1, 1, 5, 5, 63, 71, 235, 151, 651, 1383, 249, 3223, 14559, 26809, 4551}},
+{5283, 16, 25775, {1, 3, 3, 9, 29, 41, 67, 111, 175, 515, 1123, 1707, 6653, 8233, 22775, 61029}},
+{5284, 16, 25777, {1, 3, 3, 9, 23, 1, 75, 145, 159, 785, 537, 1995, 2241, 8641, 30709, 41373}},
+{5285, 16, 25783, {1, 1, 5, 9, 21, 1, 87, 233, 401, 643, 197, 3437, 8163, 6363, 6537, 17283}},
+{5286, 16, 25801, {1, 3, 5, 3, 23, 19, 55, 243, 405, 369, 1221, 1959, 5455, 11729, 26117, 9097}},
+{5287, 16, 25802, {1, 1, 3, 13, 3, 57, 71, 235, 125, 263, 873, 1079, 2627, 1343, 1979, 49519}},
+{5288, 16, 25812, {1, 3, 1, 11, 21, 15, 27, 7, 425, 935, 305, 2593, 4437, 9517, 26207, 4229}},
+{5289, 16, 25821, {1, 1, 3, 13, 11, 53, 1, 149, 97, 939, 147, 3365, 5023, 607, 2083, 8715}},
+{5290, 16, 25897, {1, 1, 5, 3, 13, 13, 113, 51, 263, 837, 1145, 3621, 5697, 2867, 7975, 22839}},
+{5291, 16, 25906, {1, 1, 3, 15, 31, 9, 91, 231, 399, 295, 1935, 4021, 7669, 3867, 28015, 9865}},
+{5292, 16, 25929, {1, 1, 1, 1, 13, 59, 51, 35, 407, 733, 1629, 2429, 291, 11923, 32129, 28847}},
+{5293, 16, 25940, {1, 3, 3, 11, 25, 21, 13, 117, 31, 547, 327, 2801, 2247, 4051, 27523, 4257}},
+{5294, 16, 25950, {1, 1, 7, 7, 15, 33, 15, 17, 255, 363, 1013, 1463, 7537, 14093, 21883, 35389}},
+{5295, 16, 25968, {1, 1, 5, 9, 11, 61, 7, 161, 121, 413, 515, 413, 4439, 15405, 30265, 23939}},
+{5296, 16, 25971, {1, 3, 7, 7, 11, 15, 5, 181, 315, 231, 1567, 2985, 1653, 12251, 269, 37317}},
+{5297, 16, 25977, {1, 3, 1, 11, 3, 15, 91, 45, 489, 571, 11, 1239, 7705, 4303, 12535, 21359}},
+{5298, 16, 25994, {1, 1, 7, 15, 29, 43, 81, 63, 483, 851, 389, 1719, 6111, 15293, 2513, 44397}},
+{5299, 16, 25996, {1, 1, 5, 15, 25, 33, 97, 131, 183, 269, 1903, 2733, 7197, 4507, 24471, 36871}},
+{5300, 16, 25999, {1, 3, 3, 13, 17, 33, 73, 83, 247, 207, 79, 1139, 581, 12147, 3539, 45423}},
+{5301, 16, 26001, {1, 1, 1, 15, 29, 49, 79, 151, 267, 393, 1995, 105, 2873, 3981, 19147, 53987}},
+{5302, 16, 26030, {1, 1, 5, 1, 31, 25, 39, 203, 459, 181, 661, 717, 6235, 13413, 1197, 40665}},
+{5303, 16, 26069, {1, 1, 5, 9, 19, 33, 65, 239, 463, 133, 461, 3601, 7755, 1771, 20683, 7417}},
+{5304, 16, 26100, {1, 1, 1, 1, 25, 19, 25, 155, 431, 33, 341, 959, 5679, 1205, 2599, 37499}},
+{5305, 16, 26109, {1, 1, 3, 5, 25, 5, 83, 87, 91, 991, 1833, 4063, 147, 14497, 25725, 4617}},
+{5306, 16, 26131, {1, 3, 5, 7, 31, 7, 73, 51, 339, 313, 1593, 2089, 7387, 15759, 3249, 7953}},
+{5307, 16, 26144, {1, 3, 7, 1, 27, 49, 35, 11, 21, 45, 1689, 1665, 4591, 3713, 12781, 4805}},
+{5308, 16, 26149, {1, 1, 3, 9, 29, 51, 73, 51, 303, 179, 67, 3917, 7615, 6131, 26225, 55991}},
+{5309, 16, 26162, {1, 3, 7, 11, 9, 63, 29, 47, 153, 883, 1859, 1913, 3563, 11451, 6333, 51367}},
+{5310, 16, 26167, {1, 3, 1, 3, 5, 25, 69, 87, 389, 613, 989, 3557, 1339, 12503, 14505, 63209}},
+{5311, 16, 26173, {1, 1, 3, 1, 5, 13, 37, 163, 499, 163, 2025, 1467, 5059, 8479, 2889, 62957}},
+{5312, 16, 26179, {1, 1, 7, 9, 23, 31, 109, 49, 73, 197, 337, 2763, 4789, 8983, 9691, 32155}},
+{5313, 16, 26193, {1, 3, 1, 3, 31, 25, 121, 91, 371, 339, 833, 2217, 4997, 9425, 10685, 60037}},
+{5314, 16, 26230, {1, 1, 7, 11, 31, 3, 105, 125, 255, 175, 803, 1787, 6231, 4441, 5031, 29737}},
+{5315, 16, 26234, {1, 1, 1, 11, 21, 63, 75, 209, 393, 437, 495, 2397, 4759, 15703, 29869, 62685}},
+{5316, 16, 26246, {1, 1, 7, 7, 25, 33, 117, 7, 293, 623, 2001, 2409, 2487, 14803, 3329, 38277}},
+{5317, 16, 26267, {1, 1, 7, 9, 31, 51, 75, 151, 487, 85, 639, 3529, 4491, 1957, 22099, 20263}},
+{5318, 16, 26283, {1, 1, 7, 5, 3, 29, 11, 1, 255, 555, 1269, 779, 1525, 7689, 25847, 39347}},
+{5319, 16, 26300, {1, 1, 7, 7, 19, 21, 9, 123, 3, 943, 1627, 2979, 919, 4565, 31435, 59789}},
+{5320, 16, 26341, {1, 3, 7, 5, 29, 13, 57, 221, 9, 893, 1685, 1879, 4575, 7369, 26191, 6067}},
+{5321, 16, 26356, {1, 3, 7, 9, 13, 11, 9, 27, 313, 751, 1377, 1121, 3799, 1673, 16305, 30665}},
+{5322, 16, 26377, {1, 3, 3, 13, 23, 17, 59, 47, 499, 525, 681, 3195, 1611, 7003, 7325, 53019}},
+{5323, 16, 26397, {1, 3, 1, 7, 23, 51, 59, 127, 67, 263, 1305, 2479, 637, 9441, 6329, 12857}},
+{5324, 16, 26404, {1, 1, 7, 7, 9, 3, 51, 193, 205, 503, 19, 2513, 7489, 9241, 15371, 20875}},
+{5325, 16, 26411, {1, 3, 3, 1, 1, 57, 17, 181, 23, 549, 769, 2325, 3669, 7017, 25601, 64479}},
+{5326, 16, 26422, {1, 3, 1, 15, 5, 55, 53, 13, 327, 447, 1031, 1599, 3639, 15305, 1387, 16035}},
+{5327, 16, 26451, {1, 3, 7, 15, 9, 41, 53, 113, 97, 99, 1377, 4047, 3713, 8891, 5601, 5853}},
+{5328, 16, 26454, {1, 1, 7, 9, 9, 7, 29, 249, 411, 315, 181, 2153, 6135, 6947, 27595, 15553}},
+{5329, 16, 26463, {1, 1, 7, 11, 3, 57, 35, 55, 165, 313, 577, 3049, 4259, 4231, 7225, 58973}},
+{5330, 16, 26488, {1, 1, 1, 1, 15, 43, 53, 143, 157, 843, 465, 3897, 4797, 12305, 28807, 46381}},
+{5331, 16, 26498, {1, 3, 7, 9, 17, 3, 99, 61, 475, 507, 831, 2207, 367, 27, 23205, 2303}},
+{5332, 16, 26509, {1, 1, 3, 11, 27, 29, 99, 237, 43, 955, 361, 3231, 1863, 7973, 8969, 58663}},
+{5333, 16, 26512, {1, 3, 1, 7, 15, 15, 11, 251, 135, 261, 675, 3723, 7675, 7993, 1725, 41149}},
+{5334, 16, 26517, {1, 3, 3, 9, 29, 11, 105, 37, 151, 215, 1911, 4051, 5427, 11019, 9073, 33129}},
+{5335, 16, 26534, {1, 3, 3, 1, 19, 7, 103, 81, 371, 253, 1043, 1231, 6497, 10377, 2349, 29047}},
+{5336, 16, 26545, {1, 3, 7, 9, 15, 11, 85, 61, 507, 629, 811, 3883, 1435, 13035, 31913, 2153}},
+{5337, 16, 26546, {1, 1, 5, 11, 13, 7, 63, 147, 117, 223, 1217, 3317, 3275, 6851, 2917, 55901}},
+{5338, 16, 26636, {1, 3, 3, 9, 7, 21, 1, 63, 117, 297, 405, 797, 337, 10173, 8327, 29157}},
+{5339, 16, 26749, {1, 1, 7, 11, 31, 63, 97, 191, 259, 421, 1829, 2117, 4203, 11919, 18001, 55791}},
+{5340, 16, 26753, {1, 3, 7, 9, 21, 13, 125, 247, 133, 611, 463, 227, 7815, 8877, 17961, 3641}},
+{5341, 16, 26759, {1, 1, 7, 9, 27, 21, 97, 165, 371, 715, 491, 3929, 3067, 12501, 5511, 18217}},
+{5342, 16, 26774, {1, 3, 3, 15, 27, 17, 81, 161, 263, 273, 135, 1159, 7535, 4581, 16065, 11493}},
+{5343, 16, 26789, {1, 3, 3, 7, 11, 59, 111, 47, 381, 413, 243, 2173, 4957, 2451, 15669, 22071}},
+{5344, 16, 26808, {1, 3, 7, 5, 3, 31, 65, 131, 111, 141, 1891, 2983, 3331, 769, 24075, 40865}},
+{5345, 16, 26825, {1, 3, 7, 11, 11, 63, 7, 213, 333, 111, 1235, 961, 3749, 9123, 5067, 9657}},
+{5346, 16, 26831, {1, 3, 3, 1, 9, 33, 1, 225, 37, 951, 1995, 3215, 3117, 3723, 15013, 64525}},
+{5347, 16, 26859, {1, 3, 3, 13, 29, 19, 103, 65, 67, 423, 1679, 3791, 5551, 11711, 195, 52291}},
+{5348, 16, 26888, {1, 3, 1, 15, 31, 7, 65, 249, 489, 287, 1385, 1075, 1357, 13593, 20853, 46221}},
+{5349, 16, 26918, {1, 1, 1, 13, 23, 45, 29, 175, 147, 101, 1007, 1867, 5387, 12683, 29609, 55861}},
+{5350, 16, 26929, {1, 3, 5, 13, 21, 31, 85, 187, 183, 179, 1337, 481, 71, 6117, 2177, 27915}},
+{5351, 16, 26950, {1, 3, 5, 1, 15, 5, 11, 141, 205, 177, 891, 3591, 4371, 889, 12957, 61083}},
+{5352, 16, 26954, {1, 3, 7, 7, 11, 39, 81, 241, 13, 757, 521, 3029, 2345, 12385, 20683, 64053}},
+{5353, 16, 26973, {1, 1, 5, 13, 7, 3, 77, 211, 215, 97, 1409, 1021, 1267, 4785, 27231, 2877}},
+{5354, 16, 26997, {1, 3, 5, 3, 11, 57, 93, 39, 415, 179, 1033, 3267, 5383, 10451, 27117, 10711}},
+{5355, 16, 26998, {1, 1, 1, 1, 3, 45, 93, 179, 453, 995, 1423, 3849, 4381, 15789, 20789, 18775}},
+{5356, 16, 27008, {1, 3, 1, 3, 13, 25, 33, 165, 351, 887, 1109, 195, 8131, 3061, 16743, 22997}},
+{5357, 16, 27038, {1, 3, 1, 5, 23, 35, 93, 155, 333, 603, 1571, 229, 2979, 6295, 20793, 40901}},
+{5358, 16, 27109, {1, 3, 3, 11, 29, 57, 101, 61, 487, 719, 1009, 1933, 7815, 15329, 12489, 26105}},
+{5359, 16, 27127, {1, 3, 3, 9, 23, 59, 73, 13, 141, 815, 1819, 3557, 2555, 5901, 23039, 62321}},
+{5360, 16, 27150, {1, 1, 3, 5, 19, 49, 27, 139, 35, 995, 565, 323, 6439, 15679, 27017, 30889}},
+{5361, 16, 27168, {1, 3, 7, 3, 1, 3, 27, 153, 235, 59, 989, 2763, 4197, 3931, 31227, 27129}},
+{5362, 16, 27178, {1, 3, 1, 15, 23, 45, 71, 205, 465, 451, 347, 1909, 3287, 8363, 9081, 35641}},
+{5363, 16, 27212, {1, 1, 5, 1, 25, 29, 17, 201, 463, 903, 1729, 3435, 2483, 10835, 14315, 52505}},
+{5364, 16, 27224, {1, 1, 1, 15, 13, 23, 3, 175, 273, 305, 1945, 3319, 7777, 9411, 4209, 4047}},
+{5365, 16, 27229, {1, 1, 5, 15, 25, 5, 71, 35, 307, 89, 301, 3465, 1497, 13467, 21911, 13611}},
+{5366, 16, 27246, {1, 3, 1, 7, 11, 7, 33, 241, 349, 751, 633, 3281, 6733, 13833, 23605, 34307}},
+{5367, 16, 27251, {1, 1, 1, 15, 17, 27, 45, 13, 259, 843, 1207, 1735, 4063, 6259, 1751, 45107}},
+{5368, 16, 27257, {1, 1, 5, 15, 29, 51, 73, 95, 5, 31, 933, 423, 5505, 2193, 14919, 2715}},
+{5369, 16, 27258, {1, 3, 1, 3, 23, 5, 29, 7, 271, 485, 827, 1159, 77, 16337, 27933, 18741}},
+{5370, 16, 27260, {1, 3, 7, 9, 23, 33, 47, 191, 59, 301, 1277, 3745, 7837, 799, 2861, 25853}},
+{5371, 16, 27287, {1, 3, 7, 13, 13, 39, 33, 91, 279, 855, 1917, 3601, 3971, 6193, 16951, 6115}},
+{5372, 16, 27300, {1, 1, 3, 13, 15, 59, 89, 239, 313, 545, 431, 3823, 5741, 14981, 2647, 42813}},
+{5373, 16, 27315, {1, 1, 1, 3, 17, 21, 45, 37, 343, 737, 1795, 2659, 2897, 7683, 15191, 1393}},
+{5374, 16, 27329, {1, 1, 3, 3, 19, 55, 27, 201, 459, 953, 1531, 671, 5667, 11695, 149, 14605}},
+{5375, 16, 27332, {1, 3, 7, 13, 9, 63, 67, 229, 69, 819, 859, 2035, 5725, 13403, 24197, 2599}},
+{5376, 16, 27349, {1, 1, 7, 7, 1, 59, 45, 105, 327, 779, 59, 791, 7593, 8189, 28161, 13339}},
+{5377, 16, 27350, {1, 3, 3, 15, 25, 55, 125, 189, 327, 733, 115, 3541, 5227, 12143, 32719, 15785}},
+{5378, 16, 27354, {1, 3, 3, 7, 19, 51, 35, 63, 507, 89, 1441, 2369, 4927, 7953, 10193, 8331}},
+{5379, 16, 27359, {1, 1, 5, 5, 21, 1, 41, 49, 217, 1001, 1649, 2789, 5267, 1525, 3811, 40785}},
+{5380, 16, 27377, {1, 1, 7, 15, 31, 21, 33, 183, 425, 393, 367, 3253, 3047, 465, 28229, 44743}},
+{5381, 16, 27378, {1, 3, 7, 5, 1, 23, 11, 71, 269, 707, 5, 2931, 1959, 15089, 9299, 43927}},
+{5382, 16, 27383, {1, 3, 5, 15, 21, 51, 31, 15, 49, 481, 297, 3871, 751, 10661, 26401, 62923}},
+{5383, 16, 27384, {1, 3, 1, 7, 17, 27, 35, 255, 205, 865, 1659, 1921, 5457, 11633, 2825, 13549}},
+{5384, 16, 27387, {1, 1, 5, 15, 17, 35, 83, 237, 437, 7, 2001, 2225, 2601, 10841, 7953, 20651}},
+{5385, 16, 27392, {1, 1, 1, 3, 3, 37, 43, 135, 451, 203, 1319, 261, 3889, 14489, 9635, 52545}},
+{5386, 16, 27402, {1, 3, 3, 13, 15, 41, 95, 207, 43, 997, 207, 3459, 5995, 5187, 15851, 28551}},
+{5387, 16, 27438, {1, 1, 1, 5, 23, 57, 49, 101, 303, 921, 745, 1407, 7071, 2765, 18703, 32671}},
+{5388, 16, 27481, {1, 1, 7, 13, 9, 59, 65, 157, 209, 295, 107, 3175, 3401, 1197, 1875, 9033}},
+{5389, 16, 27482, {1, 1, 3, 3, 17, 9, 101, 75, 177, 905, 1013, 397, 3421, 6475, 15897, 11269}},
+{5390, 16, 27494, {1, 3, 1, 5, 29, 53, 105, 83, 383, 137, 1169, 1245, 6973, 8701, 317, 10073}},
+{5391, 16, 27531, {1, 1, 1, 3, 15, 55, 69, 219, 507, 707, 945, 397, 779, 4157, 10333, 7869}},
+{5392, 16, 27542, {1, 3, 1, 3, 9, 21, 125, 153, 107, 969, 1979, 651, 1199, 11419, 17043, 32269}},
+{5393, 16, 27546, {1, 1, 1, 7, 1, 29, 71, 127, 209, 853, 1515, 1169, 5055, 9981, 30291, 29569}},
+{5394, 16, 27564, {1, 3, 1, 11, 1, 1, 109, 251, 329, 633, 2021, 1237, 2147, 11471, 26025, 19649}},
+{5395, 16, 27567, {1, 1, 5, 1, 5, 7, 77, 175, 251, 143, 711, 1241, 2133, 9993, 9203, 24949}},
+{5396, 16, 27582, {1, 3, 5, 11, 19, 11, 101, 83, 91, 595, 753, 2389, 1887, 11569, 29759, 55785}},
+{5397, 16, 27608, {1, 1, 1, 3, 29, 47, 49, 249, 495, 451, 1887, 2547, 543, 2755, 17207, 24379}},
+{5398, 16, 27611, {1, 3, 7, 7, 19, 15, 95, 143, 109, 221, 2041, 3593, 4571, 14547, 14217, 16711}},
+{5399, 16, 27624, {1, 3, 5, 13, 27, 55, 31, 209, 39, 989, 1435, 1665, 7265, 14127, 13517, 37647}},
+{5400, 16, 27629, {1, 1, 3, 7, 1, 49, 63, 71, 249, 371, 435, 3591, 2677, 143, 28897, 38981}},
+{5401, 16, 27655, {1, 1, 7, 7, 21, 9, 53, 221, 23, 515, 1971, 3759, 3511, 10207, 12929, 42021}},
+{5402, 16, 27667, {1, 3, 1, 13, 25, 21, 3, 85, 421, 19, 663, 3219, 3541, 13021, 5765, 39623}},
+{5403, 16, 27676, {1, 3, 1, 7, 11, 5, 125, 169, 293, 715, 1111, 2965, 4815, 6047, 27207, 23093}},
+{5404, 16, 27710, {1, 1, 5, 13, 11, 15, 37, 201, 457, 551, 821, 25, 435, 14307, 25855, 1811}},
+{5405, 16, 27724, {1, 3, 3, 9, 27, 15, 1, 253, 217, 549, 1013, 2277, 4171, 3813, 19857, 8641}},
+{5406, 16, 27745, {1, 3, 5, 5, 29, 37, 71, 49, 163, 949, 425, 2459, 945, 13125, 13981, 21669}},
+{5407, 16, 27752, {1, 3, 3, 9, 17, 23, 53, 235, 83, 887, 439, 1939, 7601, 15275, 15739, 17623}},
+{5408, 16, 27770, {1, 3, 5, 13, 7, 51, 73, 67, 167, 849, 2021, 2977, 6591, 3721, 5827, 40897}},
+{5409, 16, 27779, {1, 1, 5, 11, 27, 19, 81, 181, 383, 23, 1061, 3327, 1671, 7113, 7435, 17591}},
+{5410, 16, 27781, {1, 3, 3, 7, 25, 33, 73, 23, 103, 821, 917, 1425, 4739, 7227, 12365, 29509}},
+{5411, 16, 27791, {1, 1, 1, 7, 3, 37, 81, 231, 135, 663, 1983, 399, 6881, 14991, 4957, 20913}},
+{5412, 16, 27809, {1, 3, 7, 15, 25, 41, 65, 215, 301, 471, 1669, 65, 227, 9307, 29867, 9503}},
+{5413, 16, 27810, {1, 1, 7, 3, 25, 47, 31, 63, 53, 995, 33, 1297, 3423, 12301, 16255, 14467}},
+{5414, 16, 27815, {1, 3, 1, 1, 31, 25, 79, 131, 353, 169, 1425, 2257, 2631, 1559, 793, 48383}},
+{5415, 16, 27827, {1, 3, 3, 5, 31, 9, 93, 35, 503, 243, 595, 2939, 771, 7333, 13429, 59457}},
+{5416, 16, 27834, {1, 3, 1, 7, 5, 51, 21, 237, 453, 743, 775, 2207, 453, 12077, 12283, 9735}},
+{5417, 16, 27865, {1, 3, 1, 15, 5, 47, 59, 239, 87, 97, 885, 3191, 2547, 13227, 7433, 4989}},
+{5418, 16, 27899, {1, 3, 5, 15, 21, 33, 41, 155, 509, 317, 517, 1101, 133, 1897, 8235, 57673}},
+{5419, 16, 27901, {1, 1, 5, 15, 7, 9, 59, 155, 415, 831, 1173, 1263, 5451, 7181, 7233, 51483}},
+{5420, 16, 27914, {1, 1, 7, 3, 31, 43, 71, 39, 155, 529, 895, 827, 3203, 4625, 32185, 53507}},
+{5421, 16, 27950, {1, 3, 1, 11, 15, 17, 85, 141, 277, 439, 1775, 4015, 4457, 281, 22455, 47591}},
+{5422, 16, 27994, {1, 3, 5, 11, 25, 41, 93, 39, 51, 655, 1347, 3109, 2479, 9057, 18939, 26217}},
+{5423, 16, 28005, {1, 3, 3, 11, 31, 41, 7, 189, 241, 443, 65, 1723, 4817, 13405, 9641, 63965}},
+{5424, 16, 28009, {1, 1, 5, 3, 19, 29, 111, 11, 399, 277, 425, 1331, 5365, 14521, 16449, 29411}},
+{5425, 16, 28033, {1, 1, 3, 9, 25, 53, 91, 175, 481, 307, 1025, 71, 7425, 10667, 4053, 25605}},
+{5426, 16, 28039, {1, 3, 7, 7, 3, 13, 75, 175, 467, 363, 1889, 1759, 1155, 5511, 13047, 39637}},
+{5427, 16, 28060, {1, 3, 7, 9, 5, 21, 65, 43, 223, 97, 835, 2253, 3313, 9817, 23015, 55365}},
+{5428, 16, 28067, {1, 1, 1, 13, 9, 63, 95, 61, 417, 713, 1469, 1815, 795, 13609, 1567, 33535}},
+{5429, 16, 28069, {1, 3, 7, 1, 25, 45, 41, 27, 53, 407, 1633, 1317, 6267, 3293, 8899, 45235}},
+{5430, 16, 28099, {1, 3, 5, 11, 23, 47, 91, 211, 41, 775, 1301, 1407, 7931, 4491, 7579, 62321}},
+{5431, 16, 28113, {1, 1, 1, 7, 23, 15, 57, 31, 437, 293, 1999, 2589, 5453, 2519, 15533, 26949}},
+{5432, 16, 28114, {1, 3, 1, 9, 1, 27, 41, 165, 129, 297, 1887, 1171, 201, 5817, 24503, 38911}},
+{5433, 16, 28139, {1, 3, 1, 7, 1, 11, 63, 225, 191, 623, 1281, 3275, 167, 14697, 4905, 47289}},
+{5434, 16, 28142, {1, 3, 7, 7, 15, 47, 87, 177, 303, 391, 355, 3997, 7557, 6201, 20531, 22483}},
+{5435, 16, 28153, {1, 3, 3, 15, 17, 31, 111, 87, 61, 477, 1581, 3787, 5919, 10511, 2607, 62951}},
+{5436, 16, 28166, {1, 3, 3, 9, 29, 19, 63, 27, 205, 915, 1131, 3821, 673, 2875, 12703, 14367}},
+{5437, 16, 28172, {1, 3, 7, 1, 21, 19, 25, 97, 281, 635, 629, 181, 5207, 11133, 3687, 3489}},
+{5438, 16, 28183, {1, 3, 3, 9, 5, 63, 3, 21, 385, 713, 1805, 3583, 2807, 15455, 13057, 39771}},
+{5439, 16, 28194, {1, 3, 5, 9, 3, 59, 1, 253, 123, 405, 575, 3911, 4609, 11869, 23593, 947}},
+{5440, 16, 28232, {1, 1, 7, 5, 21, 27, 101, 221, 413, 153, 1647, 3637, 803, 5697, 20761, 61137}},
+{5441, 16, 28245, {1, 3, 7, 13, 31, 35, 111, 253, 187, 499, 465, 157, 5551, 10417, 323, 34913}},
+{5442, 16, 28246, {1, 1, 1, 7, 11, 41, 29, 65, 393, 69, 1373, 2291, 7807, 13159, 13735, 31001}},
+{5443, 16, 28252, {1, 3, 7, 13, 31, 49, 1, 35, 377, 11, 427, 2803, 1725, 9165, 22633, 63985}},
+{5444, 16, 28265, {1, 3, 7, 13, 3, 41, 27, 43, 269, 599, 1035, 3681, 309, 6011, 1065, 27901}},
+{5445, 16, 28301, {1, 3, 5, 13, 1, 19, 105, 143, 425, 883, 1669, 155, 189, 8573, 10759, 25507}},
+{5446, 16, 28323, {1, 3, 5, 1, 15, 37, 115, 9, 149, 79, 1733, 1045, 1849, 3289, 13957, 63171}},
+{5447, 16, 28344, {1, 1, 3, 9, 17, 27, 49, 201, 155, 901, 47, 1585, 4419, 8117, 25425, 14699}},
+{5448, 16, 28362, {1, 1, 7, 13, 19, 55, 19, 21, 427, 77, 1295, 1471, 6271, 7985, 19337, 12701}},
+{5449, 16, 28400, {1, 1, 1, 1, 11, 49, 101, 53, 175, 157, 839, 2713, 6149, 6391, 8089, 27739}},
+{5450, 16, 28417, {1, 3, 1, 1, 5, 21, 121, 199, 107, 221, 993, 1737, 409, 2545, 9287, 54605}},
+{5451, 16, 28454, {1, 1, 1, 3, 25, 25, 51, 121, 371, 861, 967, 3257, 6221, 11701, 27897, 42509}},
+{5452, 16, 28466, {1, 1, 1, 3, 17, 25, 101, 191, 313, 817, 815, 1855, 7999, 12649, 23385, 26081}},
+{5453, 16, 28468, {1, 1, 5, 1, 25, 55, 51, 237, 63, 943, 455, 619, 2381, 9773, 14575, 34205}},
+{5454, 16, 28477, {1, 3, 3, 3, 13, 49, 101, 37, 457, 727, 1009, 2389, 4841, 16303, 9599, 17773}},
+{5455, 16, 28498, {1, 1, 7, 9, 19, 59, 111, 205, 19, 229, 1755, 1169, 7767, 13335, 19669, 33269}},
+{5456, 16, 28510, {1, 3, 1, 15, 29, 1, 51, 167, 7, 415, 1295, 3165, 1241, 12859, 5531, 20083}},
+{5457, 16, 28513, {1, 1, 3, 7, 7, 51, 31, 221, 57, 643, 1461, 3951, 6237, 5757, 1907, 40471}},
+{5458, 16, 28571, {1, 3, 3, 5, 23, 39, 49, 177, 183, 117, 1379, 3803, 771, 12723, 22291, 32667}},
+{5459, 16, 28573, {1, 1, 3, 13, 27, 17, 39, 27, 313, 141, 1421, 2967, 2213, 1915, 23219, 15113}},
+{5460, 16, 28578, {1, 1, 1, 11, 5, 55, 51, 55, 389, 895, 57, 1447, 1497, 2799, 19585, 11587}},
+{5461, 16, 28587, {1, 1, 5, 13, 11, 55, 91, 77, 69, 131, 93, 1383, 3321, 10487, 15087, 8539}},
+{5462, 16, 28601, {1, 1, 3, 9, 23, 49, 107, 131, 363, 733, 1189, 3575, 7815, 10071, 20291, 7533}},
+{5463, 16, 28646, {1, 1, 3, 15, 31, 31, 73, 15, 199, 17, 761, 3271, 1419, 12985, 32717, 37317}},
+{5464, 16, 28663, {1, 3, 1, 13, 23, 9, 3, 59, 109, 729, 1321, 4023, 7041, 14445, 22205, 8993}},
+{5465, 16, 28681, {1, 1, 3, 15, 19, 43, 99, 59, 491, 479, 715, 2235, 7493, 889, 31465, 1375}},
+{5466, 16, 28682, {1, 3, 3, 15, 9, 47, 35, 115, 227, 615, 605, 1143, 5923, 10939, 9497, 24911}},
+{5467, 16, 28699, {1, 1, 3, 15, 23, 53, 111, 87, 423, 497, 85, 3525, 7341, 8885, 21543, 30083}},
+{5468, 16, 28706, {1, 1, 5, 3, 21, 5, 117, 157, 407, 743, 715, 1883, 4425, 10187, 6395, 43673}},
+{5469, 16, 28708, {1, 3, 3, 3, 31, 39, 119, 77, 269, 891, 1391, 3085, 2881, 10639, 3391, 44911}},
+{5470, 16, 28717, {1, 3, 7, 5, 7, 5, 115, 91, 5, 107, 1401, 1409, 1811, 737, 5399, 9119}},
+{5471, 16, 28720, {1, 1, 5, 9, 17, 45, 107, 15, 397, 299, 1219, 1675, 963, 10111, 31679, 13809}},
+{5472, 16, 28735, {1, 1, 3, 7, 29, 17, 43, 95, 261, 601, 1091, 3633, 1357, 13461, 16583, 12183}},
+{5473, 16, 28761, {1, 1, 5, 1, 19, 55, 5, 195, 187, 427, 421, 1717, 4223, 2943, 23147, 32985}},
+{5474, 16, 28783, {1, 3, 1, 3, 3, 23, 69, 95, 347, 273, 1223, 3061, 1587, 4707, 32415, 53991}},
+{5475, 16, 28788, {1, 1, 7, 13, 15, 13, 29, 151, 325, 949, 2029, 813, 5339, 14165, 1159, 56917}},
+{5476, 16, 28811, {1, 1, 1, 13, 9, 33, 67, 109, 215, 313, 1407, 3543, 2403, 5051, 20367, 13527}},
+{5477, 16, 28825, {1, 3, 1, 9, 5, 1, 9, 195, 497, 495, 1107, 745, 1647, 10637, 1933, 44965}},
+{5478, 16, 28838, {1, 1, 3, 9, 13, 19, 49, 183, 497, 519, 1433, 519, 4317, 2359, 10349, 63789}},
+{5479, 16, 28850, {1, 3, 5, 9, 29, 45, 55, 163, 189, 533, 275, 237, 5453, 8895, 6377, 14117}},
+{5480, 16, 28891, {1, 3, 7, 5, 25, 3, 111, 241, 139, 383, 689, 3481, 2557, 11163, 5275, 14671}},
+{5481, 16, 28897, {1, 3, 3, 9, 3, 5, 5, 141, 507, 331, 645, 1957, 5857, 2083, 24717, 11131}},
+{5482, 16, 28932, {1, 1, 5, 1, 11, 49, 113, 45, 491, 945, 1467, 3485, 6369, 15983, 14489, 12679}},
+{5483, 16, 28975, {1, 3, 7, 9, 11, 41, 77, 127, 147, 635, 1757, 587, 7423, 4233, 14875, 30531}},
+{5484, 16, 28998, {1, 3, 3, 9, 17, 29, 21, 249, 155, 441, 1443, 2093, 1967, 2117, 5815, 3857}},
+{5485, 16, 29052, {1, 3, 5, 3, 11, 55, 75, 157, 105, 507, 309, 3737, 2645, 7547, 29373, 62775}},
+{5486, 16, 29090, {1, 1, 3, 3, 11, 29, 49, 241, 21, 653, 1273, 715, 8123, 14241, 25257, 1681}},
+{5487, 16, 29096, {1, 1, 7, 5, 11, 31, 33, 215, 243, 369, 247, 3365, 4065, 9389, 32457, 58393}},
+{5488, 16, 29104, {1, 3, 5, 3, 31, 55, 51, 201, 439, 835, 1805, 25, 7987, 10611, 26893, 43663}},
+{5489, 16, 29113, {1, 1, 5, 9, 27, 51, 29, 31, 17, 163, 71, 603, 3083, 12439, 11043, 6471}},
+{5490, 16, 29133, {1, 1, 5, 7, 13, 1, 91, 109, 213, 721, 1345, 3037, 3047, 5209, 15559, 17467}},
+{5491, 16, 29142, {1, 1, 3, 9, 19, 37, 93, 185, 107, 859, 501, 3843, 1631, 4389, 2215, 52225}},
+{5492, 16, 29170, {1, 1, 3, 3, 25, 5, 119, 17, 33, 841, 997, 439, 6135, 7405, 8445, 40087}},
+{5493, 16, 29192, {1, 1, 7, 15, 19, 17, 101, 43, 423, 647, 29, 1143, 3259, 7807, 15929, 809}},
+{5494, 16, 29221, {1, 1, 7, 13, 21, 57, 83, 101, 183, 309, 171, 3173, 7919, 7263, 29403, 11055}},
+{5495, 16, 29236, {1, 1, 1, 13, 3, 1, 57, 15, 435, 713, 459, 847, 3115, 191, 19809, 43037}},
+{5496, 16, 29246, {1, 1, 7, 7, 17, 45, 91, 117, 157, 647, 121, 4091, 3611, 14169, 19883, 9069}},
+{5497, 16, 29293, {1, 1, 7, 7, 1, 47, 21, 253, 419, 157, 549, 2105, 4475, 3127, 3939, 5809}},
+{5498, 16, 29305, {1, 1, 5, 7, 15, 7, 71, 195, 87, 757, 77, 1391, 151, 12995, 26403, 17789}},
+{5499, 16, 29312, {1, 1, 1, 15, 15, 3, 79, 43, 475, 263, 1195, 2385, 5955, 7039, 15625, 19263}},
+{5500, 16, 29339, {1, 1, 5, 13, 13, 29, 5, 29, 489, 929, 2027, 2771, 6899, 14173, 13747, 1019}},
+{5501, 16, 29365, {1, 1, 7, 1, 5, 45, 37, 85, 221, 871, 627, 3445, 4853, 4243, 21651, 30201}},
+{5502, 16, 29389, {1, 3, 7, 11, 9, 49, 73, 245, 161, 321, 579, 2641, 6653, 5513, 11555, 53091}},
+{5503, 16, 29402, {1, 1, 7, 7, 25, 63, 101, 179, 497, 113, 9, 549, 5341, 6097, 13305, 52421}},
+{5504, 16, 29423, {1, 3, 3, 7, 21, 7, 89, 79, 137, 651, 189, 3025, 1403, 4559, 32611, 1857}},
+{5505, 16, 29443, {1, 3, 1, 13, 27, 55, 61, 135, 81, 195, 799, 3477, 4873, 2691, 29769, 59033}},
+{5506, 16, 29445, {1, 3, 3, 15, 29, 11, 7, 11, 151, 649, 1511, 2327, 6921, 12911, 3571, 35039}},
+{5507, 16, 29463, {1, 1, 5, 11, 25, 19, 49, 133, 455, 373, 1827, 3619, 2127, 3365, 11327, 52785}},
+{5508, 16, 29473, {1, 3, 5, 1, 9, 19, 107, 171, 205, 93, 1557, 2693, 4297, 4415, 20407, 19221}},
+{5509, 16, 29493, {1, 3, 3, 11, 15, 45, 37, 143, 61, 759, 2047, 2465, 3923, 9477, 30831, 46377}},
+{5510, 16, 29506, {1, 3, 7, 11, 17, 51, 117, 129, 77, 579, 1167, 1575, 1967, 10099, 22137, 31431}},
+{5511, 16, 29518, {1, 1, 5, 13, 31, 61, 67, 37, 49, 283, 235, 783, 7353, 5149, 12245, 18725}},
+{5512, 16, 29532, {1, 1, 5, 3, 17, 33, 35, 83, 359, 253, 1911, 913, 6481, 4635, 24223, 19693}},
+{5513, 16, 29560, {1, 1, 1, 13, 19, 15, 81, 131, 417, 969, 1911, 2829, 3097, 5333, 11175, 52269}},
+{5514, 16, 29590, {1, 3, 7, 15, 5, 39, 19, 205, 329, 83, 1473, 3259, 6409, 12297, 30557, 40917}},
+{5515, 16, 29594, {1, 3, 1, 15, 17, 33, 123, 185, 501, 299, 621, 929, 5797, 10539, 12321, 61043}},
+{5516, 16, 29637, {1, 3, 3, 1, 7, 51, 119, 19, 17, 203, 373, 2145, 2367, 9965, 28071, 50083}},
+{5517, 16, 29647, {1, 1, 1, 5, 1, 35, 43, 243, 91, 793, 1299, 2705, 7987, 1291, 10147, 17863}},
+{5518, 16, 29650, {1, 3, 5, 15, 27, 13, 99, 33, 179, 479, 897, 1113, 1639, 12321, 23987, 36219}},
+{5519, 16, 29655, {1, 1, 5, 9, 29, 41, 85, 9, 389, 583, 293, 1727, 2575, 13767, 15443, 40027}},
+{5520, 16, 29661, {1, 1, 7, 11, 29, 33, 93, 115, 51, 747, 1569, 3557, 869, 1991, 29877, 44131}},
+{5521, 16, 29680, {1, 3, 7, 7, 29, 11, 33, 137, 411, 689, 1815, 1789, 6557, 5973, 19445, 49449}},
+{5522, 16, 29721, {1, 1, 5, 1, 17, 3, 77, 55, 351, 325, 983, 3935, 819, 14127, 18893, 62553}},
+{5523, 16, 29751, {1, 3, 3, 1, 15, 33, 25, 159, 135, 385, 837, 3615, 1649, 1687, 3421, 47579}},
+{5524, 16, 29755, {1, 3, 1, 7, 17, 25, 125, 169, 469, 919, 1789, 863, 2827, 949, 21347, 10517}},
+{5525, 16, 29760, {1, 3, 1, 11, 27, 19, 45, 255, 175, 483, 1073, 3779, 611, 2809, 179, 19767}},
+{5526, 16, 29772, {1, 1, 3, 1, 21, 61, 47, 171, 179, 85, 61, 1209, 4005, 11439, 8477, 27229}},
+{5527, 16, 29778, {1, 1, 1, 1, 3, 1, 43, 159, 261, 411, 1449, 1621, 3681, 3465, 24029, 3493}},
+{5528, 16, 29799, {1, 3, 1, 11, 5, 13, 9, 23, 369, 769, 363, 3329, 409, 13151, 30269, 9621}},
+{5529, 16, 29824, {1, 1, 5, 1, 13, 39, 121, 39, 295, 981, 1151, 4039, 8179, 5007, 25527, 1249}},
+{5530, 16, 29841, {1, 3, 7, 5, 17, 21, 47, 233, 211, 349, 643, 109, 7553, 11453, 30967, 30959}},
+{5531, 16, 29842, {1, 1, 5, 3, 31, 39, 105, 137, 487, 855, 107, 1567, 2385, 2889, 25777, 33709}},
+{5532, 16, 29853, {1, 1, 1, 9, 1, 7, 9, 69, 465, 965, 355, 299, 3327, 14997, 14599, 2241}},
+{5533, 16, 29867, {1, 3, 5, 11, 5, 39, 69, 203, 367, 611, 199, 3931, 5039, 8683, 8675, 49151}},
+{5534, 16, 29949, {1, 1, 7, 13, 31, 35, 101, 213, 273, 827, 203, 2773, 4131, 1397, 15311, 62903}},
+{5535, 16, 29950, {1, 3, 7, 9, 23, 41, 33, 213, 411, 965, 563, 3035, 247, 15019, 20429, 61081}},
+{5536, 16, 29964, {1, 1, 5, 5, 5, 1, 1, 203, 27, 199, 67, 1301, 7831, 12839, 2777, 6325}},
+{5537, 16, 29967, {1, 3, 1, 11, 27, 3, 11, 173, 9, 121, 1701, 2741, 29, 16319, 15849, 11989}},
+{5538, 16, 29985, {1, 1, 5, 13, 17, 49, 125, 153, 261, 603, 1617, 3967, 6083, 7745, 19683, 49885}},
+{5539, 16, 29992, {1, 3, 3, 7, 23, 13, 39, 169, 135, 361, 579, 1443, 7615, 2389, 5669, 651}},
+{5540, 16, 30000, {1, 3, 5, 9, 31, 19, 81, 83, 483, 93, 1895, 2285, 7771, 8281, 8353, 39677}},
+{5541, 16, 30020, {1, 1, 7, 7, 23, 51, 127, 25, 101, 611, 1095, 3013, 2685, 8153, 22629, 53355}},
+{5542, 16, 30024, {1, 1, 1, 11, 11, 37, 35, 127, 317, 877, 1591, 401, 4121, 9945, 12121, 28257}},
+{5543, 16, 30030, {1, 3, 5, 11, 23, 9, 43, 135, 37, 405, 2009, 2903, 3065, 6591, 8473, 58231}},
+{5544, 16, 30066, {1, 1, 3, 11, 21, 45, 21, 205, 425, 891, 357, 2609, 495, 7541, 2161, 37853}},
+{5545, 16, 30071, {1, 3, 1, 1, 25, 9, 113, 243, 317, 491, 997, 2023, 5869, 13643, 11483, 6733}},
+{5546, 16, 30078, {1, 3, 1, 15, 13, 3, 75, 25, 409, 421, 1817, 857, 4575, 12559, 1211, 62177}},
+{5547, 16, 30082, {1, 1, 3, 7, 17, 35, 115, 195, 217, 223, 1195, 749, 5619, 7265, 7369, 46907}},
+{5548, 16, 30096, {1, 1, 1, 13, 5, 57, 117, 161, 121, 533, 987, 3959, 5047, 15213, 15811, 41841}},
+{5549, 16, 30101, {1, 3, 7, 1, 19, 55, 97, 191, 217, 75, 1881, 3351, 3737, 12179, 22875, 28767}},
+{5550, 16, 30102, {1, 3, 1, 9, 15, 41, 9, 97, 491, 31, 1191, 963, 875, 8259, 2723, 9503}},
+{5551, 16, 30122, {1, 3, 7, 9, 3, 17, 21, 71, 1, 523, 2031, 3469, 3181, 8707, 6093, 8837}},
+{5552, 16, 30141, {1, 3, 5, 3, 5, 1, 11, 91, 33, 37, 643, 85, 4325, 4293, 8351, 28311}},
+{5553, 16, 30159, {1, 3, 7, 5, 15, 45, 47, 183, 391, 113, 493, 3607, 2541, 13521, 31613, 36049}},
+{5554, 16, 30168, {1, 1, 3, 9, 15, 33, 115, 69, 289, 217, 1875, 1339, 4995, 9073, 6909, 15977}},
+{5555, 16, 30177, {1, 1, 7, 3, 9, 29, 39, 219, 119, 369, 893, 1293, 4511, 15703, 11093, 30259}},
+{5556, 16, 30183, {1, 1, 5, 13, 19, 9, 17, 75, 149, 415, 35, 97, 563, 1689, 18311, 54291}},
+{5557, 16, 30197, {1, 1, 7, 3, 17, 15, 71, 29, 25, 883, 1801, 1675, 5585, 9413, 3813, 26673}},
+{5558, 16, 30213, {1, 1, 3, 15, 5, 13, 31, 41, 311, 411, 573, 281, 8075, 7163, 11817, 29121}},
+{5559, 16, 30231, {1, 1, 7, 9, 7, 57, 15, 141, 337, 123, 269, 3737, 6455, 2539, 13655, 59809}},
+{5560, 16, 30232, {1, 3, 1, 15, 15, 23, 111, 51, 429, 483, 1567, 1317, 8057, 1609, 30181, 35687}},
+{5561, 16, 30241, {1, 3, 7, 9, 25, 43, 67, 13, 319, 587, 1827, 443, 2031, 8563, 16173, 58667}},
+{5562, 16, 30253, {1, 3, 5, 13, 11, 63, 89, 105, 377, 257, 7, 4077, 5091, 5125, 25, 39033}},
+{5563, 16, 30259, {1, 3, 3, 1, 9, 29, 7, 87, 239, 469, 1851, 1711, 5797, 7137, 11405, 20175}},
+{5564, 16, 30262, {1, 3, 3, 1, 13, 17, 101, 209, 301, 95, 1181, 3091, 4451, 1241, 17057, 335}},
+{5565, 16, 30268, {1, 1, 1, 9, 31, 7, 81, 161, 391, 677, 115, 141, 5375, 7279, 1887, 1645}},
+{5566, 16, 30297, {1, 1, 1, 11, 27, 61, 3, 195, 189, 409, 1747, 331, 2931, 9535, 1369, 47233}},
+{5567, 16, 30316, {1, 3, 5, 15, 7, 15, 105, 255, 491, 689, 97, 1131, 3459, 7147, 27541, 62307}},
+{5568, 16, 30322, {1, 3, 5, 9, 5, 23, 1, 209, 233, 717, 1919, 1835, 5073, 10403, 28979, 1945}},
+{5569, 16, 30344, {1, 1, 3, 9, 3, 35, 107, 209, 255, 447, 227, 273, 443, 9367, 24105, 34095}},
+{5570, 16, 30350, {1, 1, 3, 11, 3, 33, 5, 165, 83, 787, 1555, 31, 4351, 16301, 27453, 56739}},
+{5571, 16, 30355, {1, 1, 5, 5, 29, 9, 127, 253, 281, 487, 441, 1129, 2811, 9113, 28855, 57117}},
+{5572, 16, 30429, {1, 1, 1, 13, 13, 1, 17, 143, 121, 917, 1571, 3777, 2297, 3691, 3001, 42327}},
+{5573, 16, 30445, {1, 1, 5, 1, 25, 7, 41, 245, 241, 929, 1203, 3755, 7113, 9333, 22549, 12253}},
+{5574, 16, 30477, {1, 3, 1, 11, 1, 13, 69, 73, 285, 975, 1331, 3411, 7777, 3489, 2763, 44297}},
+{5575, 16, 30513, {1, 3, 5, 11, 3, 37, 21, 105, 153, 307, 989, 627, 3127, 6169, 10573, 22139}},
+{5576, 16, 30520, {1, 3, 5, 15, 11, 11, 39, 21, 355, 437, 547, 2283, 6443, 5561, 6367, 53899}},
+{5577, 16, 30540, {1, 1, 1, 9, 25, 51, 97, 175, 131, 207, 1367, 2561, 7455, 8289, 5877, 4383}},
+{5578, 16, 30551, {1, 3, 7, 1, 29, 17, 7, 1, 43, 831, 591, 2145, 975, 909, 23107, 43987}},
+{5579, 16, 30573, {1, 3, 5, 13, 5, 47, 65, 65, 439, 807, 271, 1615, 1873, 10905, 30537, 3337}},
+{5580, 16, 30609, {1, 1, 1, 13, 29, 1, 53, 5, 307, 347, 1059, 545, 1129, 11883, 5969, 50433}},
+{5581, 16, 30622, {1, 1, 3, 5, 31, 29, 63, 201, 255, 803, 677, 1499, 1691, 14037, 18251, 6881}},
+{5582, 16, 30635, {1, 3, 1, 5, 5, 13, 13, 121, 505, 855, 467, 2803, 3297, 4689, 18443, 60757}},
+{5583, 16, 30658, {1, 1, 5, 13, 11, 19, 11, 201, 101, 431, 693, 1267, 6909, 7759, 2265, 6125}},
+{5584, 16, 30667, {1, 1, 7, 13, 9, 3, 37, 209, 269, 27, 1041, 2587, 4667, 11077, 27009, 27967}},
+{5585, 16, 30681, {1, 1, 5, 5, 1, 5, 127, 179, 463, 949, 1525, 231, 1201, 3283, 9929, 46677}},
+{5586, 16, 30684, {1, 3, 1, 15, 9, 11, 89, 129, 331, 833, 1415, 229, 2059, 13145, 30525, 33773}},
+{5587, 16, 30703, {1, 1, 7, 15, 7, 43, 95, 177, 313, 989, 483, 825, 1885, 4535, 8213, 39835}},
+{5588, 16, 30705, {1, 1, 7, 3, 19, 27, 45, 163, 17, 523, 1565, 3753, 7433, 14117, 8499, 40177}},
+{5589, 16, 30715, {1, 3, 3, 15, 23, 45, 95, 31, 55, 469, 383, 237, 6287, 5561, 20901, 48259}},
+{5590, 16, 30742, {1, 1, 3, 1, 23, 61, 101, 185, 35, 553, 463, 1169, 2875, 12491, 14327, 47999}},
+{5591, 16, 30748, {1, 3, 3, 13, 23, 29, 77, 21, 19, 3, 769, 1943, 2081, 9135, 29767, 11367}},
+{5592, 16, 30758, {1, 1, 5, 15, 5, 11, 59, 163, 355, 993, 375, 3181, 2675, 8515, 17007, 38467}},
+{5593, 16, 30767, {1, 1, 5, 13, 19, 5, 107, 83, 123, 843, 413, 2137, 7531, 3833, 6149, 55925}},
+{5594, 16, 30770, {1, 3, 1, 13, 23, 9, 41, 145, 265, 591, 1899, 3145, 5255, 13653, 12245, 25367}},
+{5595, 16, 30772, {1, 1, 3, 15, 1, 45, 119, 79, 121, 137, 1945, 2041, 2409, 1377, 29501, 29885}},
+{5596, 16, 30807, {1, 1, 7, 11, 27, 57, 75, 183, 341, 237, 1909, 2785, 5973, 9965, 21729, 45089}},
+{5597, 16, 30814, {1, 3, 5, 7, 21, 1, 41, 189, 131, 1021, 1375, 1463, 5985, 12499, 4115, 9131}},
+{5598, 16, 30824, {1, 3, 7, 15, 21, 19, 59, 171, 339, 841, 1725, 2909, 6437, 2499, 17191, 43275}},
+{5599, 16, 30857, {1, 3, 1, 1, 15, 55, 31, 199, 351, 183, 1819, 1873, 7877, 12407, 7881, 1663}},
+{5600, 16, 30875, {1, 1, 3, 15, 1, 61, 111, 61, 115, 243, 1281, 3195, 1229, 10973, 189, 36049}},
+{5601, 16, 30931, {1, 1, 3, 15, 13, 13, 3, 49, 61, 839, 1615, 1853, 3619, 7805, 25441, 8789}},
+{5602, 16, 30933, {1, 3, 1, 9, 27, 43, 7, 193, 397, 869, 1079, 1785, 6535, 1801, 29363, 59269}},
+{5603, 16, 30949, {1, 3, 5, 5, 31, 57, 37, 53, 41, 871, 809, 1235, 1011, 12979, 8749, 52151}},
+{5604, 16, 30953, {1, 1, 7, 13, 25, 59, 69, 117, 463, 587, 513, 297, 6991, 5905, 25737, 37249}},
+{5605, 16, 30982, {1, 1, 5, 1, 27, 19, 121, 97, 349, 793, 1971, 3057, 4781, 15841, 22625, 58637}},
+{5606, 16, 31010, {1, 1, 5, 5, 25, 31, 11, 133, 411, 239, 1071, 3473, 1733, 7175, 31841, 46665}},
+{5607, 16, 31012, {1, 3, 3, 13, 19, 25, 99, 175, 271, 175, 1755, 3597, 4615, 15207, 25573, 16089}},
+{5608, 16, 31039, {1, 1, 7, 11, 17, 19, 119, 91, 505, 791, 55, 2979, 7463, 10147, 23647, 33283}},
+{5609, 16, 31041, {1, 3, 1, 1, 21, 11, 43, 173, 239, 839, 1533, 1559, 549, 15621, 22133, 46387}},
+{5610, 16, 31061, {1, 1, 3, 13, 31, 15, 73, 15, 209, 267, 701, 2899, 1163, 10093, 7727, 44211}},
+{5611, 16, 31082, {1, 3, 1, 11, 29, 21, 5, 39, 421, 375, 411, 3693, 3901, 8507, 10883, 16189}},
+{5612, 16, 31087, {1, 3, 1, 7, 13, 13, 73, 167, 149, 677, 1435, 621, 2511, 13813, 13129, 55327}},
+{5613, 16, 31096, {1, 3, 5, 15, 7, 59, 83, 221, 77, 357, 281, 2689, 5629, 5837, 1701, 30811}},
+{5614, 16, 31115, {1, 3, 3, 11, 17, 1, 43, 95, 473, 981, 1487, 1337, 905, 3307, 22357, 181}},
+{5615, 16, 31130, {1, 1, 3, 7, 1, 27, 9, 3, 489, 1, 1265, 2463, 539, 12769, 825, 6149}},
+{5616, 16, 31168, {1, 3, 3, 3, 11, 27, 81, 237, 411, 241, 1613, 931, 6397, 4325, 29651, 49003}},
+{5617, 16, 31171, {1, 3, 3, 13, 1, 19, 55, 73, 47, 203, 1661, 1245, 6847, 2457, 25427, 33069}},
+{5618, 16, 31177, {1, 3, 7, 3, 7, 47, 11, 165, 391, 457, 301, 1213, 1913, 14531, 7847, 14811}},
+{5619, 16, 31180, {1, 3, 1, 9, 1, 9, 57, 203, 15, 733, 1131, 2751, 5869, 3165, 21497, 28881}},
+{5620, 16, 31191, {1, 3, 1, 5, 9, 7, 29, 85, 71, 571, 469, 2395, 2819, 8443, 2281, 50489}},
+{5621, 16, 31207, {1, 3, 5, 11, 13, 63, 47, 47, 349, 21, 861, 2217, 2945, 6967, 6605, 16459}},
+{5622, 16, 31247, {1, 1, 7, 5, 13, 3, 41, 53, 409, 289, 1225, 2965, 5283, 1785, 14443, 51755}},
+{5623, 16, 31249, {1, 3, 7, 13, 19, 1, 29, 191, 119, 37, 697, 1909, 481, 14157, 13425, 60581}},
+{5624, 16, 31285, {1, 3, 1, 13, 1, 15, 105, 79, 505, 681, 1741, 3683, 5775, 7479, 11387, 1321}},
+{5625, 16, 31303, {1, 1, 1, 11, 9, 35, 77, 73, 351, 217, 2029, 2845, 5143, 5677, 15465, 33123}},
+{5626, 16, 31310, {1, 1, 3, 3, 19, 49, 63, 109, 335, 743, 741, 1673, 3311, 3139, 25197, 13793}},
+{5627, 16, 31337, {1, 3, 1, 3, 29, 63, 79, 1, 493, 13, 1487, 4015, 6983, 1433, 26023, 55591}},
+{5628, 16, 31352, {1, 3, 3, 11, 1, 25, 57, 207, 309, 201, 1513, 1749, 3785, 9217, 11531, 40597}},
+{5629, 16, 31357, {1, 3, 7, 13, 3, 23, 69, 253, 311, 773, 807, 1063, 745, 4843, 25221, 55885}},
+{5630, 16, 31374, {1, 1, 3, 11, 29, 47, 67, 183, 11, 259, 5, 1935, 2295, 8105, 19139, 11707}},
+{5631, 16, 31379, {1, 1, 3, 3, 23, 3, 53, 165, 255, 501, 1547, 3649, 5631, 13307, 8869, 5595}},
+{5632, 16, 31388, {1, 1, 3, 5, 7, 29, 37, 223, 289, 925, 959, 309, 1479, 3141, 18661, 52123}},
+{5633, 16, 31410, {1, 3, 1, 1, 7, 59, 101, 219, 91, 793, 1103, 1485, 7547, 12889, 19097, 15613}},
+{5634, 16, 31416, {1, 1, 5, 15, 1, 17, 79, 83, 131, 683, 1611, 1635, 5405, 9621, 29489, 4801}},
+{5635, 16, 31467, {1, 1, 5, 7, 31, 63, 59, 125, 401, 261, 1445, 33, 187, 12913, 8639, 48413}},
+{5636, 16, 31495, {1, 3, 3, 13, 27, 37, 27, 99, 379, 851, 1311, 4051, 5483, 13935, 29679, 30905}},
+{5637, 16, 31504, {1, 1, 3, 1, 7, 57, 79, 23, 97, 561, 1083, 2327, 1545, 5387, 12119, 29717}},
+{5638, 16, 31507, {1, 1, 7, 7, 9, 41, 63, 165, 315, 247, 89, 2055, 7399, 1399, 2057, 39851}},
+{5639, 16, 31509, {1, 1, 1, 15, 9, 23, 7, 15, 457, 669, 661, 3269, 915, 3475, 15845, 59769}},
+{5640, 16, 31514, {1, 3, 7, 15, 17, 53, 83, 5, 457, 103, 1297, 2413, 1095, 7711, 27935, 56357}},
+{5641, 16, 31516, {1, 1, 3, 5, 17, 3, 81, 23, 165, 341, 781, 3583, 1751, 6763, 13937, 35331}},
+{5642, 16, 31530, {1, 1, 5, 11, 31, 21, 7, 63, 369, 867, 573, 45, 2781, 4507, 21553, 51933}},
+{5643, 16, 31555, {1, 1, 5, 15, 1, 37, 85, 133, 489, 733, 1471, 2089, 979, 7723, 7339, 59595}},
+{5644, 16, 31567, {1, 1, 1, 1, 7, 3, 3, 77, 137, 1009, 481, 1343, 397, 15865, 21701, 37509}},
+{5645, 16, 31570, {1, 3, 7, 5, 17, 57, 19, 245, 249, 289, 1847, 3057, 4905, 5905, 32459, 41305}},
+{5646, 16, 31586, {1, 1, 5, 1, 23, 23, 1, 177, 115, 337, 983, 421, 3135, 6319, 27109, 59641}},
+{5647, 16, 31598, {1, 3, 1, 5, 25, 1, 63, 73, 61, 967, 1567, 2645, 7347, 11877, 28777, 38507}},
+{5648, 16, 31605, {1, 1, 3, 9, 5, 41, 39, 101, 339, 337, 1079, 3861, 5049, 5601, 14377, 34093}},
+{5649, 16, 31609, {1, 3, 7, 7, 3, 47, 95, 157, 167, 1011, 1117, 3669, 7993, 11735, 8505, 64713}},
+{5650, 16, 31612, {1, 3, 1, 9, 3, 33, 11, 33, 65, 329, 401, 2659, 2851, 3903, 29791, 41613}},
+{5651, 16, 31626, {1, 1, 1, 15, 15, 17, 9, 69, 359, 41, 1475, 1919, 5829, 2189, 21295, 33255}},
+{5652, 16, 31634, {1, 3, 1, 3, 9, 23, 73, 247, 399, 775, 419, 3033, 865, 12595, 16345, 15079}},
+{5653, 16, 31655, {1, 3, 1, 5, 1, 17, 33, 23, 419, 585, 673, 929, 6955, 10247, 12647, 29107}},
+{5654, 16, 31681, {1, 3, 3, 13, 9, 33, 11, 13, 127, 529, 1219, 2401, 6459, 14745, 5123, 53023}},
+{5655, 16, 31705, {1, 3, 5, 11, 23, 11, 5, 19, 281, 121, 1671, 2171, 4545, 10691, 24875, 28849}},
+{5656, 16, 31706, {1, 3, 1, 3, 13, 25, 85, 131, 127, 977, 1599, 3319, 3107, 3185, 4879, 3455}},
+{5657, 16, 31718, {1, 1, 5, 1, 3, 13, 77, 15, 133, 185, 1319, 727, 2181, 12175, 28017, 28023}},
+{5658, 16, 31735, {1, 3, 7, 5, 29, 51, 113, 203, 331, 847, 1, 3445, 3669, 7711, 13647, 58651}},
+{5659, 16, 31741, {1, 3, 1, 3, 31, 27, 35, 199, 491, 839, 1275, 3385, 4743, 821, 26259, 11345}},
+{5660, 16, 31744, {1, 1, 7, 9, 21, 47, 9, 67, 119, 985, 127, 1987, 5451, 6403, 26183, 8349}},
+{5661, 16, 31762, {1, 3, 5, 1, 19, 3, 91, 217, 301, 595, 1789, 735, 4993, 229, 18033, 59625}},
+{5662, 16, 31774, {1, 3, 3, 3, 11, 25, 103, 211, 117, 9, 773, 1521, 2265, 8277, 23179, 22433}},
+{5663, 16, 31864, {1, 1, 7, 9, 3, 27, 63, 255, 175, 699, 293, 2409, 3155, 285, 8663, 53503}},
+{5664, 16, 31874, {1, 1, 5, 7, 27, 23, 63, 213, 323, 697, 1541, 3497, 2985, 12389, 11155, 26217}},
+{5665, 16, 31900, {1, 3, 1, 3, 31, 7, 47, 207, 185, 873, 1063, 1055, 205, 12469, 23505, 56245}},
+{5666, 16, 31910, {1, 3, 7, 13, 31, 17, 47, 95, 91, 483, 1997, 3273, 445, 2601, 15219, 10997}},
+{5667, 16, 31928, {1, 3, 3, 5, 29, 45, 29, 83, 457, 823, 1395, 1411, 1879, 9409, 11609, 32001}},
+{5668, 16, 31965, {1, 3, 5, 11, 21, 11, 43, 73, 159, 137, 29, 1957, 815, 5077, 16127, 42199}},
+{5669, 16, 31976, {1, 3, 5, 13, 9, 59, 47, 215, 293, 807, 309, 1951, 2285, 9287, 1019, 49501}},
+{5670, 16, 32016, {1, 1, 7, 13, 31, 7, 95, 189, 233, 363, 1039, 1675, 1715, 9049, 8537, 31051}},
+{5671, 16, 32032, {1, 3, 7, 9, 23, 35, 125, 251, 107, 401, 1113, 3585, 6331, 2363, 27889, 28877}},
+{5672, 16, 32037, {1, 1, 7, 13, 9, 1, 13, 69, 257, 369, 547, 1595, 1823, 9553, 25653, 31181}},
+{5673, 16, 32062, {1, 1, 7, 11, 9, 43, 3, 93, 69, 1019, 1935, 3297, 47, 7101, 1037, 63473}},
+{5674, 16, 32069, {1, 1, 7, 5, 21, 9, 97, 105, 405, 893, 1673, 3783, 2965, 7329, 4549, 25433}},
+{5675, 16, 32115, {1, 1, 5, 13, 5, 17, 31, 123, 415, 173, 1333, 2245, 1557, 16011, 28321, 4039}},
+{5676, 16, 32128, {1, 1, 5, 9, 15, 3, 27, 79, 511, 39, 945, 49, 3231, 9199, 21327, 11183}},
+{5677, 16, 32171, {1, 3, 3, 9, 3, 15, 115, 141, 387, 341, 953, 399, 6109, 12037, 21079, 26745}},
+{5678, 16, 32173, {1, 3, 3, 1, 5, 5, 31, 195, 477, 755, 687, 3811, 805, 679, 20687, 46299}},
+{5679, 16, 32182, {1, 1, 7, 15, 1, 31, 67, 159, 205, 141, 1667, 3077, 451, 13161, 16211, 6887}},
+{5680, 16, 32191, {1, 3, 3, 1, 7, 43, 87, 5, 49, 205, 231, 3957, 2947, 13199, 15743, 4681}},
+{5681, 16, 32193, {1, 3, 3, 15, 25, 37, 95, 11, 439, 553, 59, 1241, 7407, 13467, 22403, 44441}},
+{5682, 16, 32194, {1, 1, 1, 3, 21, 3, 127, 239, 491, 139, 1411, 3417, 4247, 6247, 13809, 31609}},
+{5683, 16, 32229, {1, 1, 5, 1, 9, 13, 5, 155, 109, 593, 119, 4091, 1911, 8301, 4239, 50081}},
+{5684, 16, 32230, {1, 3, 5, 13, 27, 3, 99, 225, 253, 169, 801, 3741, 1905, 12073, 31831, 17997}},
+{5685, 16, 32248, {1, 3, 7, 15, 9, 23, 93, 171, 453, 983, 1657, 1133, 6381, 5229, 32303, 17439}},
+{5686, 16, 32263, {1, 1, 7, 11, 7, 5, 125, 141, 63, 763, 1293, 1007, 4579, 1479, 11977, 59261}},
+{5687, 16, 32264, {1, 3, 1, 7, 1, 15, 49, 41, 367, 639, 1933, 401, 2335, 2441, 13653, 55555}},
+{5688, 16, 32269, {1, 3, 1, 7, 15, 23, 5, 213, 45, 721, 543, 2133, 4525, 9719, 28053, 54075}},
+{5689, 16, 32298, {1, 3, 7, 3, 11, 7, 23, 35, 169, 829, 1957, 2423, 3583, 4951, 28957, 29753}},
+{5690, 16, 32335, {1, 1, 3, 3, 1, 5, 19, 235, 175, 969, 229, 2335, 7215, 10195, 7487, 64191}},
+{5691, 16, 32340, {1, 1, 7, 3, 27, 1, 73, 49, 445, 863, 69, 3555, 993, 9553, 31941, 29901}},
+{5692, 16, 32356, {1, 3, 5, 11, 9, 25, 59, 177, 23, 997, 1041, 1135, 3879, 767, 2263, 51267}},
+{5693, 16, 32374, {1, 1, 7, 3, 1, 63, 49, 51, 237, 569, 1293, 1143, 3125, 16315, 17009, 24821}},
+{5694, 16, 32390, {1, 3, 3, 15, 11, 17, 121, 25, 349, 833, 557, 1975, 5405, 15189, 31243, 53541}},
+{5695, 16, 32401, {1, 3, 7, 9, 11, 15, 39, 15, 75, 87, 55, 2069, 3291, 507, 16925, 57751}},
+{5696, 16, 32414, {1, 1, 3, 15, 1, 21, 61, 139, 357, 931, 647, 947, 2291, 15557, 6739, 5881}},
+{5697, 16, 32417, {1, 3, 1, 9, 1, 47, 73, 59, 115, 497, 733, 1777, 905, 16181, 4351, 7345}},
+{5698, 16, 32442, {1, 3, 3, 7, 5, 21, 67, 113, 71, 743, 757, 1851, 7899, 10315, 15437, 61803}},
+{5699, 16, 32450, {1, 3, 7, 1, 9, 23, 77, 131, 395, 767, 1229, 2629, 5731, 11907, 32217, 18473}},
+{5700, 16, 32461, {1, 3, 5, 15, 1, 23, 123, 207, 291, 565, 1211, 501, 2111, 11381, 5171, 54841}},
+{5701, 16, 32473, {1, 1, 1, 15, 21, 13, 3, 175, 405, 109, 1353, 2495, 7619, 14971, 28179, 34737}},
+{5702, 16, 32479, {1, 3, 5, 3, 17, 25, 53, 71, 229, 729, 1953, 3119, 7747, 1551, 23417, 35563}},
+{5703, 16, 32530, {1, 1, 7, 7, 11, 31, 81, 43, 149, 537, 1253, 2759, 431, 4813, 8375, 46329}},
+{5704, 16, 32536, {1, 1, 1, 5, 11, 27, 61, 199, 239, 889, 723, 2353, 5663, 7385, 28165, 14675}},
+{5705, 16, 32548, {1, 3, 1, 7, 3, 3, 83, 247, 247, 57, 579, 1163, 2615, 4051, 2809, 46413}},
+{5706, 16, 32577, {1, 1, 3, 11, 13, 47, 11, 235, 475, 35, 843, 2329, 3519, 8899, 14533, 24889}},
+{5707, 16, 32628, {1, 3, 1, 1, 7, 31, 15, 101, 327, 499, 471, 1001, 339, 11863, 24787, 47191}},
+{5708, 16, 32642, {1, 1, 7, 1, 3, 55, 93, 43, 11, 65, 289, 1249, 5325, 13867, 29841, 34333}},
+{5709, 16, 32665, {1, 3, 3, 1, 25, 61, 87, 113, 115, 265, 1007, 1129, 7633, 6109, 5733, 22649}},
+{5710, 16, 32666, {1, 3, 1, 11, 31, 59, 127, 83, 33, 419, 1037, 3777, 6383, 2711, 2113, 17233}},
+{5711, 16, 32668, {1, 1, 5, 13, 11, 17, 73, 41, 257, 223, 359, 3821, 4617, 1943, 11331, 40153}},
+{5712, 16, 32696, {1, 1, 1, 1, 9, 25, 43, 179, 17, 1021, 1323, 761, 5861, 11547, 26017, 5165}},
+{5713, 16, 32722, {1, 3, 5, 3, 29, 21, 53, 111, 213, 717, 1101, 3215, 3021, 16343, 23387, 33439}},
+{5714, 16, 32757, {1, 3, 5, 13, 29, 11, 21, 89, 107, 111, 1121, 2785, 3493, 9873, 13, 40863}},
+{5715, 16, 32758, {1, 1, 5, 13, 15, 15, 111, 219, 59, 43, 333, 3581, 1311, 2799, 23987, 21637}},
+{5716, 17, 4, {1, 3, 1, 11, 21, 57, 115, 247, 499, 525, 1629, 3679, 2109, 6607, 27435, 1745, 71201}},
+{5717, 17, 7, {1, 3, 3, 3, 31, 17, 113, 165, 189, 361, 103, 1775, 3001, 3865, 30591, 2873, 17129}},
+{5718, 17, 16, {1, 1, 5, 5, 15, 47, 47, 85, 247, 471, 713, 3571, 2407, 9811, 8187, 32133, 8541}},
+{5719, 17, 22, {1, 3, 3, 1, 15, 1, 59, 151, 469, 351, 671, 2925, 7207, 5061, 28691, 4363, 50767}},
+{5720, 17, 25, {1, 1, 5, 7, 11, 35, 67, 45, 193, 3, 627, 3333, 6497, 12307, 28807, 13997, 108645}},
+{5721, 17, 31, {1, 3, 1, 1, 17, 63, 125, 185, 485, 759, 717, 1993, 6707, 3993, 2181, 8173, 18057}},
+{5722, 17, 32, {1, 1, 3, 13, 7, 15, 113, 207, 103, 191, 1895, 2595, 3873, 12021, 19259, 12553, 119119}},
+{5723, 17, 42, {1, 3, 7, 1, 17, 11, 101, 209, 315, 9, 901, 2303, 7623, 7459, 26391, 45143, 5753}},
+{5724, 17, 52, {1, 1, 5, 15, 1, 5, 71, 155, 167, 89, 145, 3483, 2385, 15205, 9193, 20637, 58473}},
+{5725, 17, 61, {1, 1, 5, 7, 25, 55, 57, 51, 333, 299, 1721, 1667, 6513, 10191, 29405, 21923, 76593}},
+{5726, 17, 70, {1, 1, 5, 1, 7, 37, 107, 91, 241, 137, 627, 2749, 5573, 11243, 26197, 4545, 105599}},
+{5727, 17, 76, {1, 3, 1, 5, 25, 37, 73, 61, 57, 249, 1953, 1385, 6479, 3701, 10693, 617, 62535}},
+{5728, 17, 81, {1, 1, 1, 15, 5, 63, 41, 151, 395, 681, 227, 3027, 8123, 15091, 15475, 35671, 21129}},
+{5729, 17, 87, {1, 3, 5, 11, 29, 21, 15, 233, 103, 463, 1829, 2257, 1717, 2249, 9599, 5097, 55705}},
+{5730, 17, 93, {1, 3, 5, 1, 29, 3, 35, 151, 193, 105, 1107, 827, 7169, 1843, 15225, 29025, 43165}},
+{5731, 17, 98, {1, 1, 7, 15, 17, 51, 93, 199, 205, 41, 113, 1081, 1571, 11471, 11057, 16149, 66905}},
+{5732, 17, 122, {1, 1, 3, 11, 5, 25, 107, 195, 51, 675, 1683, 3739, 1653, 611, 23249, 53157, 127785}},
+{5733, 17, 133, {1, 1, 7, 5, 7, 3, 25, 145, 453, 735, 441, 77, 8171, 9281, 22749, 36973, 106237}},
+{5734, 17, 134, {1, 1, 3, 13, 13, 5, 95, 33, 223, 369, 453, 2031, 3531, 6931, 8977, 54109, 115487}},
+{5735, 17, 140, {1, 1, 7, 7, 1, 61, 33, 183, 245, 623, 529, 1831, 1867, 2845, 8311, 10143, 67897}},
+{5736, 17, 146, {1, 3, 7, 11, 27, 23, 93, 9, 61, 451, 67, 1695, 4227, 2415, 19249, 44765, 24611}},
+{5737, 17, 158, {1, 3, 3, 11, 29, 57, 65, 117, 349, 149, 363, 1095, 4989, 3071, 17519, 18079, 7277}},
+{5738, 17, 171, {1, 3, 5, 9, 1, 7, 59, 87, 307, 111, 1291, 789, 7361, 6477, 11229, 36785, 33303}},
+{5739, 17, 176, {1, 3, 5, 1, 19, 47, 53, 81, 127, 849, 1479, 1459, 1889, 15087, 22115, 20587, 121005}},
+{5740, 17, 179, {1, 1, 7, 15, 31, 31, 71, 55, 253, 927, 277, 2087, 1313, 3721, 22729, 34709, 9821}},
+{5741, 17, 182, {1, 3, 5, 13, 13, 63, 73, 41, 165, 315, 1907, 2005, 691, 725, 22685, 8673, 76011}},
+{5742, 17, 191, {1, 1, 5, 9, 23, 61, 47, 167, 279, 683, 683, 1261, 4037, 15251, 9421, 45359, 38001}},
+{5743, 17, 193, {1, 1, 7, 3, 17, 33, 69, 139, 235, 709, 1475, 2483, 7559, 8581, 23965, 31153, 5097}},
+{5744, 17, 224, {1, 1, 7, 15, 23, 61, 43, 5, 433, 531, 761, 2749, 2881, 5225, 13491, 16479, 50203}},
+{5745, 17, 227, {1, 1, 3, 9, 29, 7, 9, 23, 339, 315, 1723, 779, 2983, 6571, 16025, 63055, 111103}},
+{5746, 17, 229, {1, 1, 7, 13, 23, 55, 71, 121, 297, 193, 41, 3165, 4419, 5853, 28127, 56151, 16597}},
+{5747, 17, 236, {1, 1, 5, 7, 7, 23, 93, 11, 261, 297, 1769, 1239, 2579, 531, 4423, 7891, 21729}},
+{5748, 17, 248, {1, 3, 5, 1, 13, 35, 83, 85, 125, 887, 161, 3311, 7261, 9557, 28975, 28643, 21479}},
+{5749, 17, 262, {1, 3, 5, 3, 27, 5, 47, 175, 287, 867, 141, 3079, 7583, 4997, 18271, 24097, 96319}},
+{5750, 17, 273, {1, 3, 5, 1, 21, 51, 47, 67, 211, 281, 1861, 1169, 6403, 4229, 3995, 9921, 41515}},
+{5751, 17, 276, {1, 3, 3, 11, 23, 23, 81, 55, 441, 211, 169, 3197, 7213, 7205, 15, 11771, 129091}},
+{5752, 17, 280, {1, 3, 7, 3, 23, 39, 23, 163, 253, 1005, 1775, 3393, 7659, 8065, 30021, 61065, 35171}},
+{5753, 17, 283, {1, 3, 1, 1, 29, 29, 39, 143, 191, 711, 1077, 13, 4137, 15425, 11139, 1269, 71915}},
+{5754, 17, 290, {1, 3, 3, 5, 11, 41, 101, 127, 301, 335, 45, 2065, 5835, 7801, 2639, 5735, 63445}},
+{5755, 17, 309, {1, 3, 5, 9, 3, 39, 51, 53, 489, 663, 951, 3931, 3075, 753, 22179, 20573, 10775}},
+{5756, 17, 316, {1, 3, 3, 15, 13, 31, 1, 237, 79, 587, 395, 591, 607, 13105, 21301, 26829, 112181}},
+{5757, 17, 319, {1, 1, 7, 7, 5, 55, 31, 117, 247, 229, 247, 307, 3821, 6483, 31317, 22975, 40535}},
+{5758, 17, 321, {1, 3, 7, 15, 15, 59, 101, 17, 437, 373, 1727, 471, 2783, 7825, 24555, 58765, 5097}},
+{5759, 17, 328, {1, 1, 3, 9, 31, 27, 71, 147, 71, 871, 793, 2363, 3213, 13383, 29801, 53187, 70021}},
+{5760, 17, 346, {1, 3, 1, 1, 19, 47, 121, 61, 303, 565, 1371, 3703, 2201, 6835, 26041, 56039, 80227}},
+{5761, 17, 355, {1, 1, 5, 5, 3, 45, 91, 61, 257, 947, 1449, 4031, 4925, 8627, 11909, 9529, 3429}},
+{5762, 17, 367, {1, 1, 1, 7, 9, 63, 69, 233, 141, 361, 1443, 2157, 2877, 643, 2779, 8109, 126911}},
+{5763, 17, 369, {1, 1, 5, 1, 5, 3, 67, 157, 21, 1, 361, 35, 1475, 12877, 22169, 6653, 85005}},
+{5764, 17, 372, {1, 1, 7, 9, 25, 1, 7, 175, 47, 963, 405, 3955, 3905, 8429, 8483, 62037, 11323}},
+{5765, 17, 382, {1, 1, 5, 11, 29, 23, 77, 211, 319, 745, 1935, 2429, 1687, 2173, 1571, 19457, 117777}},
+{5766, 17, 388, {1, 1, 7, 5, 15, 57, 121, 189, 303, 79, 527, 1801, 71, 9857, 14197, 59007, 75341}},
+{5767, 17, 392, {1, 3, 3, 5, 25, 3, 19, 141, 155, 157, 287, 769, 5789, 8443, 31823, 1019, 79111}},
+{5768, 17, 395, {1, 1, 5, 11, 27, 27, 117, 141, 355, 1023, 869, 995, 6311, 6573, 11721, 1565, 35517}},
+{5769, 17, 397, {1, 1, 1, 9, 1, 33, 107, 51, 41, 889, 1191, 1055, 503, 14779, 6641, 58117, 74157}},
+{5770, 17, 403, {1, 1, 7, 5, 13, 39, 39, 33, 293, 75, 963, 3379, 1847, 12371, 9005, 38107, 69753}},
+{5771, 17, 409, {1, 1, 5, 5, 7, 37, 19, 241, 427, 635, 1711, 3835, 773, 10525, 17207, 1675, 127255}},
+{5772, 17, 410, {1, 1, 3, 7, 17, 19, 11, 113, 191, 947, 1133, 3173, 213, 10125, 1373, 56797, 111011}},
+{5773, 17, 425, {1, 3, 1, 1, 29, 45, 65, 237, 223, 695, 697, 3197, 6887, 8079, 22099, 12079, 54847}},
+{5774, 17, 443, {1, 3, 3, 7, 5, 47, 19, 215, 341, 863, 1879, 571, 7113, 2465, 23407, 52555, 44375}},
+{5775, 17, 472, {1, 3, 5, 11, 25, 31, 109, 73, 429, 553, 1905, 1753, 6733, 4433, 13785, 32041, 27115}},
+{5776, 17, 475, {1, 1, 1, 3, 27, 5, 97, 47, 343, 977, 1241, 721, 3355, 3559, 28349, 56389, 63103}},
+{5777, 17, 481, {1, 3, 3, 9, 21, 53, 57, 211, 73, 155, 1855, 715, 3179, 5963, 10061, 35141, 63131}},
+{5778, 17, 488, {1, 3, 1, 15, 21, 25, 51, 73, 31, 25, 1385, 637, 6585, 49, 2105, 6829, 9353}},
+{5779, 17, 493, {1, 1, 7, 5, 11, 55, 31, 69, 145, 637, 1131, 2175, 3547, 13031, 2131, 12361, 74737}},
+{5780, 17, 501, {1, 3, 3, 5, 31, 7, 119, 119, 309, 925, 895, 3813, 1131, 4765, 17865, 48707, 113577}},
+{5781, 17, 515, {1, 3, 3, 9, 13, 33, 127, 177, 323, 727, 1881, 775, 7329, 11881, 28309, 987, 116093}},
+{5782, 17, 522, {1, 1, 3, 5, 31, 55, 39, 41, 511, 157, 1655, 2991, 3633, 8521, 27049, 18771, 54015}},
+{5783, 17, 524, {1, 3, 5, 13, 11, 45, 113, 185, 375, 661, 1331, 4013, 5521, 1037, 23365, 30239, 76957}},
+{5784, 17, 527, {1, 3, 3, 7, 19, 7, 23, 17, 435, 913, 1985, 353, 6049, 7549, 3371, 60867, 41099}},
+{5785, 17, 535, {1, 3, 3, 15, 17, 9, 53, 127, 149, 849, 1181, 2237, 1345, 539, 19715, 26277, 125445}},
+{5786, 17, 542, {1, 1, 1, 3, 1, 9, 67, 79, 79, 795, 1793, 3167, 5917, 5323, 22043, 22007, 3917}},
+{5787, 17, 545, {1, 3, 5, 9, 15, 19, 59, 37, 141, 145, 413, 1095, 7709, 669, 27061, 40171, 101499}},
+{5788, 17, 555, {1, 3, 1, 1, 9, 49, 109, 7, 119, 861, 875, 1049, 4125, 6113, 15699, 6105, 48799}},
+{5789, 17, 558, {1, 1, 3, 9, 11, 29, 43, 175, 371, 357, 1181, 3933, 43, 4559, 10333, 23603, 83095}},
+{5790, 17, 560, {1, 3, 3, 9, 9, 7, 57, 61, 409, 143, 591, 761, 4107, 8117, 1051, 4471, 91771}},
+{5791, 17, 563, {1, 1, 3, 11, 3, 53, 119, 21, 213, 219, 51, 3491, 7143, 937, 24693, 3211, 99463}},
+{5792, 17, 570, {1, 1, 3, 3, 1, 47, 53, 153, 211, 523, 1637, 3351, 3753, 12489, 31825, 27613, 96431}},
+{5793, 17, 578, {1, 1, 5, 15, 23, 57, 81, 231, 147, 9, 1043, 3157, 1463, 4835, 22435, 57407, 59615}},
+{5794, 17, 583, {1, 3, 3, 13, 15, 63, 111, 5, 449, 957, 1175, 2887, 7741, 8975, 28775, 4067, 69283}},
+{5795, 17, 590, {1, 3, 1, 1, 5, 61, 109, 211, 349, 179, 951, 153, 3147, 7555, 27037, 59829, 16077}},
+{5796, 17, 597, {1, 3, 3, 7, 15, 33, 53, 61, 309, 991, 227, 3437, 3983, 14559, 13065, 46387, 49105}},
+{5797, 17, 604, {1, 3, 5, 3, 25, 23, 97, 139, 315, 601, 1179, 1083, 6799, 1813, 15511, 60433, 65641}},
+{5798, 17, 608, {1, 1, 7, 1, 11, 43, 87, 87, 173, 161, 91, 3011, 1869, 2313, 13691, 3509, 39433}},
+{5799, 17, 614, {1, 3, 5, 7, 15, 5, 39, 251, 269, 819, 815, 2283, 5635, 6953, 27017, 65143, 45281}},
+{5800, 17, 635, {1, 3, 7, 9, 1, 37, 9, 57, 467, 37, 1743, 4031, 3751, 8105, 23789, 46847, 21911}},
+{5801, 17, 637, {1, 1, 7, 1, 23, 47, 63, 99, 59, 951, 1837, 2829, 161, 857, 4045, 9945, 53487}},
+{5802, 17, 653, {1, 3, 7, 7, 11, 47, 43, 99, 279, 945, 1189, 2091, 4597, 183, 15527, 7151, 112403}},
+{5803, 17, 654, {1, 3, 3, 15, 9, 53, 63, 135, 119, 95, 131, 2461, 157, 10631, 20847, 51699, 58865}},
+{5804, 17, 659, {1, 1, 3, 1, 25, 3, 115, 29, 303, 361, 1529, 3993, 5899, 11501, 4463, 47121, 75333}},
+{5805, 17, 666, {1, 3, 1, 15, 9, 39, 31, 199, 305, 279, 15, 611, 561, 6593, 3189, 1863, 61875}},
+{5806, 17, 671, {1, 3, 5, 15, 5, 49, 87, 17, 87, 5, 1179, 1351, 7647, 7529, 15901, 30351, 31959}},
+{5807, 17, 689, {1, 3, 3, 9, 31, 57, 127, 239, 349, 773, 547, 2649, 1309, 8071, 10741, 57645, 14423}},
+{5808, 17, 690, {1, 1, 5, 9, 5, 15, 59, 185, 315, 411, 1425, 3905, 853, 12393, 21, 15195, 114291}},
+{5809, 17, 695, {1, 3, 1, 5, 29, 47, 19, 203, 319, 673, 1169, 2413, 5295, 6251, 19883, 2725, 28937}},
+{5810, 17, 713, {1, 3, 1, 5, 21, 55, 19, 185, 103, 827, 117, 341, 3315, 5625, 345, 63845, 49081}},
+{5811, 17, 722, {1, 1, 7, 9, 27, 51, 105, 15, 243, 735, 1221, 1641, 293, 14423, 5363, 60873, 66223}},
+{5812, 17, 733, {1, 1, 5, 1, 19, 5, 109, 131, 131, 67, 231, 2907, 4389, 5079, 20503, 59045, 33625}},
+{5813, 17, 758, {1, 3, 1, 5, 5, 15, 79, 67, 287, 225, 519, 1543, 2389, 671, 7767, 62625, 61639}},
+{5814, 17, 770, {1, 1, 1, 9, 25, 35, 83, 15, 291, 207, 1757, 3691, 5669, 11255, 27939, 57813, 46251}},
+{5815, 17, 782, {1, 3, 1, 1, 29, 3, 83, 109, 323, 179, 1855, 3205, 7665, 16201, 13863, 16347, 98977}},
+{5816, 17, 784, {1, 3, 1, 13, 17, 1, 101, 183, 153, 985, 125, 999, 855, 15897, 19491, 8953, 23277}},
+{5817, 17, 793, {1, 1, 7, 11, 9, 33, 45, 229, 411, 155, 537, 3037, 1785, 11719, 8589, 16617, 47339}},
+{5818, 17, 803, {1, 1, 5, 5, 9, 11, 7, 163, 305, 621, 1647, 2609, 7901, 14421, 23447, 1205, 52681}},
+{5819, 17, 805, {1, 3, 3, 1, 7, 29, 39, 227, 419, 561, 129, 3299, 3123, 4243, 18689, 12335, 71783}},
+{5820, 17, 812, {1, 3, 1, 9, 11, 61, 65, 207, 123, 763, 485, 1943, 3617, 415, 22397, 58597, 128017}},
+{5821, 17, 838, {1, 1, 5, 13, 25, 43, 115, 73, 269, 137, 1765, 705, 1705, 16137, 22751, 60021, 4333}},
+{5822, 17, 849, {1, 1, 5, 13, 3, 57, 9, 141, 75, 695, 597, 3435, 1085, 4905, 19625, 16061, 12111}},
+{5823, 17, 875, {1, 1, 5, 9, 29, 13, 119, 251, 353, 421, 1955, 3503, 2605, 2587, 12503, 46419, 128815}},
+{5824, 17, 877, {1, 3, 5, 7, 7, 29, 67, 25, 37, 327, 1607, 1899, 1691, 5801, 17441, 9755, 24993}},
+{5825, 17, 880, {1, 1, 3, 11, 17, 29, 121, 201, 371, 597, 213, 2361, 6615, 169, 24801, 56175, 129241}},
+{5826, 17, 892, {1, 3, 5, 1, 31, 63, 85, 77, 151, 599, 103, 677, 4431, 12897, 6373, 40349, 100819}},
+{5827, 17, 895, {1, 3, 5, 9, 25, 9, 119, 219, 379, 939, 1907, 945, 5819, 7433, 32519, 56493, 50441}},
+{5828, 17, 899, {1, 1, 3, 9, 13, 1, 63, 189, 135, 839, 1821, 2247, 2547, 965, 6847, 63335, 32921}},
+{5829, 17, 919, {1, 3, 5, 13, 21, 25, 111, 37, 319, 469, 1999, 1637, 8167, 2641, 24615, 63713, 115923}},
+{5830, 17, 920, {1, 3, 5, 9, 9, 27, 1, 63, 275, 223, 1675, 3833, 7377, 9755, 6279, 37161, 108805}},
+{5831, 17, 932, {1, 3, 3, 13, 29, 23, 21, 73, 401, 863, 701, 2527, 4557, 5549, 22493, 6651, 39167}},
+{5832, 17, 935, {1, 1, 3, 15, 25, 21, 97, 25, 83, 925, 2029, 3789, 3241, 7617, 13699, 31123, 124619}},
+{5833, 17, 936, {1, 3, 7, 5, 23, 7, 95, 227, 123, 215, 359, 2099, 4505, 8477, 32665, 18211, 99679}},
+{5834, 17, 941, {1, 3, 1, 9, 11, 57, 75, 17, 105, 175, 831, 1033, 5425, 8419, 16163, 23901, 33889}},
+{5835, 17, 950, {1, 1, 7, 1, 17, 49, 71, 23, 129, 413, 333, 2547, 4627, 14961, 16745, 53649, 73059}},
+{5836, 17, 961, {1, 3, 5, 3, 13, 33, 121, 147, 443, 187, 1949, 319, 8141, 14359, 11203, 53569, 70415}},
+{5837, 17, 962, {1, 3, 1, 11, 15, 1, 23, 29, 509, 985, 1217, 3755, 385, 3697, 24631, 37619, 62435}},
+{5838, 17, 971, {1, 3, 3, 3, 17, 11, 107, 37, 227, 913, 259, 2799, 3249, 2347, 9703, 52741, 101187}},
+{5839, 17, 982, {1, 1, 5, 13, 25, 25, 47, 77, 405, 415, 1947, 1675, 5079, 1333, 10059, 32033, 88975}},
+{5840, 17, 986, {1, 3, 5, 9, 27, 7, 19, 241, 445, 205, 333, 285, 7997, 6339, 29643, 10229, 29965}},
+{5841, 17, 1012, {1, 3, 5, 11, 17, 9, 91, 223, 173, 1013, 779, 3967, 781, 5471, 4309, 24795, 99203}},
+{5842, 17, 1021, {1, 1, 1, 3, 19, 53, 7, 159, 351, 515, 223, 3375, 1, 4985, 16729, 43333, 85917}},
+{5843, 17, 1024, {1, 3, 3, 1, 19, 35, 95, 69, 19, 157, 1177, 579, 7109, 3499, 3219, 26641, 49491}},
+{5844, 17, 1029, {1, 3, 3, 5, 25, 21, 125, 5, 39, 857, 615, 2925, 2005, 5503, 25523, 36711, 30939}},
+{5845, 17, 1030, {1, 3, 1, 5, 11, 33, 29, 5, 425, 125, 939, 1641, 321, 1023, 12551, 4587, 116617}},
+{5846, 17, 1051, {1, 3, 3, 13, 9, 59, 93, 137, 103, 517, 1555, 13, 7965, 13629, 14339, 37425, 65891}},
+{5847, 17, 1054, {1, 3, 7, 1, 31, 31, 87, 237, 365, 951, 267, 2019, 5085, 6133, 29371, 50319, 94313}},
+{5848, 17, 1064, {1, 3, 5, 7, 17, 19, 23, 225, 501, 189, 1291, 603, 6873, 8633, 11425, 30565, 26355}},
+{5849, 17, 1067, {1, 3, 7, 11, 23, 17, 91, 111, 415, 225, 1287, 2081, 4683, 12069, 3627, 32281, 17995}},
+{5850, 17, 1082, {1, 1, 5, 15, 25, 59, 75, 203, 179, 405, 1711, 3147, 7483, 5583, 3729, 11765, 61019}},
+{5851, 17, 1096, {1, 3, 3, 9, 3, 43, 65, 7, 269, 33, 829, 1789, 967, 13119, 26329, 16937, 18533}},
+{5852, 17, 1116, {1, 1, 3, 15, 11, 39, 73, 11, 31, 143, 1913, 1227, 1363, 11831, 28687, 50489, 106373}},
+{5853, 17, 1119, {1, 1, 3, 3, 25, 19, 15, 11, 349, 1011, 421, 3193, 3665, 6149, 20729, 6997, 51437}},
+{5854, 17, 1129, {1, 3, 5, 9, 13, 63, 73, 55, 417, 223, 1753, 2913, 4809, 3947, 10769, 5751, 93867}},
+{5855, 17, 1130, {1, 3, 7, 13, 31, 39, 39, 133, 483, 839, 1137, 3303, 7285, 4309, 24079, 60529, 103337}},
+{5856, 17, 1132, {1, 1, 3, 7, 1, 55, 3, 253, 435, 589, 1949, 1461, 513, 381, 29455, 4263, 16831}},
+{5857, 17, 1137, {1, 1, 1, 15, 25, 19, 77, 101, 299, 187, 1021, 1533, 8021, 4165, 2277, 18927, 110439}},
+{5858, 17, 1147, {1, 1, 1, 11, 9, 35, 71, 159, 409, 527, 15, 4073, 5749, 8563, 2503, 53015, 111581}},
+{5859, 17, 1150, {1, 1, 7, 5, 21, 47, 113, 23, 477, 559, 543, 409, 4701, 11479, 30761, 8373, 87777}},
+{5860, 17, 1154, {1, 3, 5, 13, 9, 27, 25, 137, 81, 37, 799, 857, 3539, 4471, 15753, 59015, 48589}},
+{5861, 17, 1165, {1, 1, 3, 7, 11, 57, 103, 83, 209, 71, 193, 3251, 4839, 13959, 32009, 6471, 23631}},
+{5862, 17, 1166, {1, 1, 7, 11, 25, 33, 85, 31, 371, 253, 1667, 1627, 6159, 10039, 15177, 52121, 39475}},
+{5863, 17, 1174, {1, 1, 5, 9, 13, 55, 37, 13, 95, 113, 1895, 1525, 1907, 6361, 5863, 27767, 108143}},
+{5864, 17, 1177, {1, 1, 3, 13, 21, 5, 53, 39, 485, 171, 1355, 2117, 3127, 6467, 31697, 45343, 111477}},
+{5865, 17, 1184, {1, 1, 7, 15, 13, 57, 11, 231, 329, 703, 1823, 2983, 215, 2835, 19719, 56637, 126169}},
+{5866, 17, 1194, {1, 3, 5, 15, 13, 51, 13, 173, 301, 867, 127, 2391, 2795, 4945, 13293, 49947, 10765}},
+{5867, 17, 1204, {1, 3, 3, 9, 23, 5, 29, 165, 467, 599, 1181, 3213, 4069, 5473, 8937, 51495, 42611}},
+{5868, 17, 1208, {1, 1, 7, 15, 5, 5, 31, 125, 397, 519, 1465, 115, 7877, 7025, 14213, 50343, 85827}},
+{5869, 17, 1213, {1, 3, 7, 3, 25, 59, 95, 103, 101, 347, 95, 3, 1251, 15109, 12615, 7511, 56789}},
+{5870, 17, 1219, {1, 3, 5, 9, 13, 59, 71, 19, 107, 73, 345, 3177, 6519, 2407, 18033, 31075, 113185}},
+{5871, 17, 1233, {1, 1, 1, 3, 27, 37, 5, 219, 169, 149, 355, 549, 1811, 11351, 22627, 53931, 88619}},
+{5872, 17, 1264, {1, 3, 1, 3, 27, 7, 9, 97, 399, 947, 1393, 3917, 5439, 15845, 19465, 30123, 69099}},
+{5873, 17, 1267, {1, 1, 7, 9, 13, 25, 107, 45, 111, 409, 967, 3359, 2499, 1703, 20763, 45187, 16265}},
+{5874, 17, 1281, {1, 1, 1, 13, 5, 49, 43, 249, 49, 947, 597, 1773, 2387, 2693, 15297, 57969, 53385}},
+{5875, 17, 1312, {1, 1, 7, 15, 27, 25, 27, 121, 421, 781, 143, 817, 7335, 14211, 139, 55601, 56671}},
+{5876, 17, 1321, {1, 3, 1, 5, 29, 47, 77, 23, 413, 931, 785, 1221, 769, 13131, 26955, 56441, 85745}},
+{5877, 17, 1330, {1, 1, 1, 11, 27, 3, 53, 21, 467, 43, 1533, 1053, 691, 6369, 8325, 51087, 71261}},
+{5878, 17, 1332, {1, 1, 3, 15, 7, 9, 43, 225, 293, 143, 1049, 3095, 6119, 3165, 9913, 26023, 62657}},
+{5879, 17, 1335, {1, 3, 7, 9, 11, 39, 99, 193, 217, 941, 259, 3811, 6757, 281, 10377, 46961, 48949}},
+{5880, 17, 1341, {1, 1, 1, 1, 25, 1, 99, 61, 495, 861, 2013, 487, 2821, 12921, 30111, 27213, 97363}},
+{5881, 17, 1356, {1, 1, 5, 9, 23, 33, 103, 237, 161, 721, 2021, 159, 995, 475, 20615, 30961, 31767}},
+{5882, 17, 1371, {1, 3, 1, 1, 5, 59, 63, 139, 451, 789, 1285, 655, 5501, 273, 21061, 35937, 20811}},
+{5883, 17, 1377, {1, 3, 3, 9, 9, 15, 121, 233, 287, 929, 1605, 1243, 417, 1695, 29903, 28699, 85981}},
+{5884, 17, 1380, {1, 3, 3, 5, 7, 25, 27, 253, 469, 255, 285, 2467, 4897, 4079, 29759, 50351, 76451}},
+{5885, 17, 1384, {1, 1, 3, 3, 5, 33, 29, 209, 291, 967, 1429, 1953, 5957, 14065, 8875, 32675, 4629}},
+{5886, 17, 1395, {1, 3, 5, 9, 7, 31, 97, 21, 177, 485, 1115, 4051, 6683, 7761, 30181, 37531, 51789}},
+{5887, 17, 1397, {1, 1, 7, 3, 25, 51, 23, 183, 57, 699, 1245, 2519, 2783, 4457, 6381, 43199, 40071}},
+{5888, 17, 1411, {1, 3, 5, 5, 19, 55, 45, 101, 299, 461, 1009, 319, 7335, 7769, 5479, 61113, 7937}},
+{5889, 17, 1414, {1, 1, 7, 3, 29, 21, 55, 55, 437, 771, 363, 683, 4299, 15569, 13813, 40663, 86285}},
+{5890, 17, 1426, {1, 1, 1, 13, 31, 35, 93, 175, 451, 387, 1145, 3367, 3833, 13495, 11019, 48925, 85721}},
+{5891, 17, 1432, {1, 1, 7, 15, 31, 21, 55, 205, 117, 895, 535, 2627, 1473, 10779, 24493, 42999, 130805}},
+{5892, 17, 1435, {1, 1, 3, 13, 27, 11, 45, 37, 193, 237, 1505, 1405, 3613, 9565, 3037, 53643, 85211}},
+{5893, 17, 1437, {1, 1, 3, 13, 9, 17, 19, 27, 117, 503, 65, 1033, 7891, 4005, 9229, 20999, 96601}},
+{5894, 17, 1442, {1, 3, 3, 5, 17, 3, 71, 79, 145, 985, 935, 3997, 6239, 12511, 13895, 65031, 126383}},
+{5895, 17, 1454, {1, 1, 5, 1, 23, 55, 3, 105, 71, 243, 1479, 111, 7103, 10753, 26193, 35833, 14583}},
+{5896, 17, 1468, {1, 3, 3, 3, 15, 3, 73, 125, 267, 29, 1775, 1437, 8091, 10891, 25731, 54381, 12821}},
+{5897, 17, 1473, {1, 1, 1, 3, 23, 15, 67, 123, 401, 347, 807, 1097, 31, 11209, 8727, 58149, 129099}},
+{5898, 17, 1488, {1, 3, 3, 7, 7, 61, 49, 129, 423, 535, 135, 3587, 233, 4509, 23209, 59203, 41297}},
+{5899, 17, 1491, {1, 3, 1, 7, 5, 29, 65, 31, 335, 855, 835, 1421, 3081, 14219, 16321, 48269, 41603}},
+{5900, 17, 1509, {1, 1, 1, 13, 3, 21, 5, 117, 163, 603, 1519, 3789, 7873, 10981, 4615, 9165, 83929}},
+{5901, 17, 1524, {1, 3, 5, 11, 15, 21, 75, 151, 193, 757, 647, 1603, 333, 10515, 22771, 55459, 3315}},
+{5902, 17, 1533, {1, 1, 7, 1, 27, 3, 63, 197, 271, 175, 1599, 2119, 1031, 8671, 10893, 35641, 94535}},
+{5903, 17, 1555, {1, 1, 1, 15, 1, 59, 93, 17, 5, 213, 1663, 941, 435, 8107, 1963, 34951, 106181}},
+{5904, 17, 1567, {1, 1, 5, 11, 13, 35, 111, 97, 267, 737, 2023, 1301, 7407, 11249, 31785, 31933, 20673}},
+{5905, 17, 1571, {1, 3, 3, 15, 5, 15, 29, 63, 189, 687, 27, 2005, 7129, 11377, 23175, 42389, 30933}},
+{5906, 17, 1586, {1, 1, 1, 9, 13, 63, 7, 155, 67, 291, 1419, 755, 2623, 4749, 22971, 7545, 55711}},
+{5907, 17, 1592, {1, 3, 7, 7, 23, 29, 83, 151, 213, 201, 157, 3051, 6553, 6401, 15931, 47941, 22869}},
+{5908, 17, 1595, {1, 3, 5, 5, 7, 45, 33, 155, 225, 25, 49, 2419, 4241, 6835, 11401, 50725, 118343}},
+{5909, 17, 1600, {1, 1, 3, 13, 31, 27, 37, 41, 19, 375, 1771, 1789, 2313, 2577, 12615, 22715, 22179}},
+{5910, 17, 1606, {1, 3, 1, 11, 17, 53, 55, 229, 235, 837, 143, 3583, 2789, 5471, 6515, 44565, 8619}},
+{5911, 17, 1627, {1, 1, 5, 15, 5, 17, 23, 95, 217, 551, 353, 27, 3973, 2547, 27903, 50611, 72277}},
+{5912, 17, 1648, {1, 1, 3, 7, 5, 13, 41, 111, 157, 215, 1327, 3073, 1871, 11875, 24239, 40527, 97637}},
+{5913, 17, 1651, {1, 3, 1, 1, 29, 63, 111, 187, 369, 395, 1197, 3229, 4353, 14715, 29671, 50503, 89321}},
+{5914, 17, 1654, {1, 3, 1, 1, 5, 63, 11, 39, 171, 209, 463, 3421, 3451, 4453, 14397, 2219, 98261}},
+{5915, 17, 1667, {1, 3, 3, 5, 1, 1, 13, 101, 67, 815, 1521, 1543, 7221, 7337, 10765, 30029, 47881}},
+{5916, 17, 1669, {1, 1, 5, 7, 9, 9, 33, 197, 439, 893, 961, 11, 4319, 14265, 24839, 33581, 35531}},
+{5917, 17, 1674, {1, 3, 3, 15, 29, 35, 43, 229, 313, 369, 955, 1069, 2939, 12623, 20373, 1533, 9105}},
+{5918, 17, 1687, {1, 3, 1, 7, 21, 7, 127, 243, 103, 353, 859, 3789, 4369, 12063, 22369, 14531, 94289}},
+{5919, 17, 1698, {1, 3, 5, 15, 1, 27, 65, 127, 229, 99, 627, 2693, 7173, 7305, 29971, 7097, 10113}},
+{5920, 17, 1710, {1, 1, 5, 15, 3, 47, 61, 29, 155, 725, 1727, 2667, 7003, 16277, 21983, 21365, 129365}},
+{5921, 17, 1717, {1, 1, 5, 7, 27, 61, 115, 133, 137, 661, 1201, 2151, 367, 3567, 12885, 62143, 53955}},
+{5922, 17, 1722, {1, 1, 1, 11, 9, 41, 113, 103, 469, 687, 1541, 3679, 6833, 10493, 32747, 39909, 121445}},
+{5923, 17, 1735, {1, 1, 7, 5, 5, 5, 91, 91, 5, 405, 529, 3999, 6783, 2387, 16621, 12919, 8659}},
+{5924, 17, 1741, {1, 1, 7, 13, 21, 47, 125, 155, 83, 913, 1833, 4027, 6657, 7031, 31231, 58201, 88943}},
+{5925, 17, 1749, {1, 3, 7, 3, 17, 55, 25, 29, 181, 205, 1173, 1081, 6475, 5037, 18461, 22487, 114131}},
+{5926, 17, 1750, {1, 1, 7, 7, 25, 63, 101, 103, 171, 191, 1863, 3441, 2515, 14179, 30123, 19145, 31669}},
+{5927, 17, 1769, {1, 3, 7, 11, 29, 49, 73, 163, 415, 821, 1809, 723, 7049, 14565, 4829, 19395, 61131}},
+{5928, 17, 1775, {1, 1, 7, 9, 5, 25, 103, 167, 381, 757, 813, 471, 3021, 6619, 20929, 38133, 129505}},
+{5929, 17, 1777, {1, 1, 5, 13, 25, 61, 59, 199, 257, 999, 169, 3289, 7181, 2049, 2185, 39045, 102703}},
+{5930, 17, 1778, {1, 1, 3, 1, 21, 1, 111, 125, 289, 33, 701, 3491, 5569, 8055, 23149, 26793, 102563}},
+{5931, 17, 1792, {1, 1, 7, 3, 25, 15, 105, 235, 307, 201, 1947, 699, 2519, 10615, 29345, 17061, 112949}},
+{5932, 17, 1797, {1, 3, 3, 15, 19, 1, 93, 173, 399, 13, 269, 1189, 523, 5145, 32731, 54087, 94123}},
+{5933, 17, 1802, {1, 3, 1, 15, 9, 41, 59, 79, 217, 833, 1993, 2429, 3599, 6919, 30911, 12615, 67947}},
+{5934, 17, 1822, {1, 3, 3, 13, 31, 9, 95, 37, 343, 955, 1363, 3851, 4091, 13165, 15241, 14853, 35747}},
+{5935, 17, 1825, {1, 1, 3, 5, 27, 39, 37, 217, 385, 473, 1997, 2247, 7353, 1503, 9003, 15055, 27289}},
+{5936, 17, 1831, {1, 3, 7, 11, 1, 13, 21, 243, 375, 91, 1295, 1661, 203, 15251, 15355, 16065, 24183}},
+{5937, 17, 1838, {1, 3, 1, 13, 11, 45, 85, 5, 275, 741, 1395, 4011, 7987, 16087, 24113, 50555, 128147}},
+{5938, 17, 1852, {1, 1, 1, 7, 3, 11, 13, 189, 55, 151, 395, 657, 807, 11973, 26297, 13043, 109641}},
+{5939, 17, 1855, {1, 1, 7, 13, 31, 19, 33, 235, 491, 647, 1115, 2299, 6381, 7525, 2237, 36197, 126457}},
+{5940, 17, 1860, {1, 3, 5, 1, 21, 15, 53, 231, 77, 347, 969, 141, 4501, 9429, 1815, 50887, 74581}},
+{5941, 17, 1867, {1, 1, 1, 9, 29, 43, 47, 103, 327, 131, 927, 441, 7517, 7277, 21065, 409, 50351}},
+{5942, 17, 1869, {1, 1, 5, 1, 11, 13, 103, 157, 239, 69, 1347, 477, 5017, 9723, 28133, 65135, 12359}},
+{5943, 17, 1875, {1, 1, 1, 13, 17, 63, 117, 189, 323, 565, 927, 1727, 5337, 13243, 5739, 31241, 14209}},
+{5944, 17, 1882, {1, 1, 3, 9, 29, 9, 103, 61, 467, 217, 1367, 2405, 5355, 5743, 31469, 30149, 98775}},
+{5945, 17, 1903, {1, 1, 1, 15, 23, 23, 17, 229, 103, 583, 179, 115, 7081, 9437, 32623, 62639, 72391}},
+{5946, 17, 1908, {1, 1, 5, 11, 11, 39, 97, 209, 115, 107, 593, 2347, 1445, 6179, 32011, 8435, 65847}},
+{5947, 17, 1917, {1, 3, 7, 3, 29, 27, 55, 111, 27, 731, 995, 1871, 5017, 1485, 11313, 2559, 6561}},
+{5948, 17, 1927, {1, 3, 1, 3, 27, 9, 103, 247, 83, 197, 517, 1629, 2189, 7255, 183, 35111, 15077}},
+{5949, 17, 1941, {1, 3, 7, 5, 31, 37, 87, 223, 343, 331, 1361, 3371, 2007, 13235, 10897, 63839, 109837}},
+{5950, 17, 1945, {1, 1, 7, 11, 17, 5, 41, 197, 489, 625, 1595, 2663, 5941, 14029, 30999, 16781, 116001}},
+{5951, 17, 1948, {1, 3, 3, 7, 19, 19, 61, 175, 125, 609, 1391, 147, 3001, 4189, 10133, 24031, 46219}},
+{5952, 17, 1962, {1, 1, 3, 13, 13, 57, 117, 181, 299, 939, 583, 3151, 829, 6561, 30449, 12211, 107879}},
+{5953, 17, 1975, {1, 1, 5, 11, 23, 45, 87, 115, 259, 613, 1001, 171, 57, 13789, 22173, 56837, 26263}},
+{5954, 17, 1976, {1, 1, 3, 3, 7, 43, 45, 131, 87, 251, 1411, 2737, 2739, 4595, 12561, 12043, 82885}},
+{5955, 17, 1987, {1, 3, 3, 7, 19, 39, 87, 223, 461, 37, 283, 3937, 6193, 10887, 11509, 41131, 38359}},
+{5956, 17, 1993, {1, 3, 1, 11, 11, 37, 25, 133, 105, 1013, 925, 3301, 239, 16295, 4831, 8649, 125767}},
+{5957, 17, 2004, {1, 3, 3, 11, 25, 11, 41, 155, 1, 717, 1587, 635, 279, 1803, 14817, 28669, 88835}},
+{5958, 17, 2020, {1, 3, 3, 11, 29, 17, 39, 51, 13, 871, 1197, 2561, 6671, 8465, 22709, 15933, 15923}},
+{5959, 17, 2029, {1, 3, 7, 1, 13, 17, 57, 43, 267, 261, 901, 241, 3767, 15053, 11017, 36321, 72497}},
+{5960, 17, 2030, {1, 3, 1, 15, 23, 13, 17, 63, 171, 919, 1387, 2673, 7605, 8523, 14807, 21187, 56057}},
+{5961, 17, 2038, {1, 3, 7, 15, 23, 41, 85, 95, 53, 629, 1877, 3167, 2411, 9619, 24621, 31213, 30069}},
+{5962, 17, 2041, {1, 1, 5, 3, 3, 25, 99, 39, 321, 549, 599, 1279, 2401, 2335, 8227, 59429, 94549}},
+{5963, 17, 2048, {1, 3, 3, 11, 9, 21, 29, 55, 477, 19, 1275, 29, 2253, 11421, 30401, 57059, 93219}},
+{5964, 17, 2054, {1, 1, 7, 1, 27, 13, 117, 249, 463, 769, 281, 515, 7467, 11507, 1621, 39765, 31109}},
+{5965, 17, 2057, {1, 3, 5, 7, 19, 7, 77, 107, 23, 895, 1013, 2701, 3805, 7327, 27247, 6119, 102395}},
+{5966, 17, 2058, {1, 1, 3, 13, 21, 49, 99, 15, 163, 641, 1703, 3061, 163, 4265, 32571, 13957, 75005}},
+{5967, 17, 2068, {1, 1, 5, 11, 27, 17, 87, 169, 427, 959, 361, 1023, 5727, 16279, 1099, 39081, 67215}},
+{5968, 17, 2072, {1, 3, 3, 9, 23, 13, 1, 91, 173, 325, 1881, 1385, 8023, 935, 9221, 19673, 36949}},
+{5969, 17, 2075, {1, 3, 1, 7, 7, 25, 119, 189, 107, 249, 811, 973, 6499, 101, 11281, 55227, 32361}},
+{5970, 17, 2077, {1, 1, 5, 13, 19, 37, 117, 95, 463, 587, 1419, 445, 4019, 7257, 29757, 50773, 52247}},
+{5971, 17, 2082, {1, 1, 1, 1, 17, 57, 81, 57, 43, 789, 1035, 625, 1707, 9683, 3681, 12411, 110623}},
+{5972, 17, 2084, {1, 1, 7, 5, 7, 57, 49, 91, 459, 513, 1869, 3377, 139, 10037, 24091, 54247, 41279}},
+{5973, 17, 2087, {1, 3, 3, 9, 9, 33, 29, 51, 355, 415, 1907, 809, 6543, 349, 18507, 12919, 41667}},
+{5974, 17, 2101, {1, 1, 5, 11, 3, 17, 73, 201, 121, 909, 1623, 799, 3271, 9051, 5717, 15169, 127861}},
+{5975, 17, 2111, {1, 1, 7, 7, 23, 31, 1, 155, 475, 87, 2001, 2459, 1285, 5931, 6803, 56757, 71671}},
+{5976, 17, 2113, {1, 1, 5, 13, 5, 1, 21, 109, 263, 841, 723, 1539, 7529, 433, 23721, 33195, 57001}},
+{5977, 17, 2119, {1, 3, 3, 13, 29, 55, 105, 231, 405, 265, 671, 351, 4693, 9033, 21963, 52073, 125131}},
+{5978, 17, 2147, {1, 3, 1, 13, 25, 51, 55, 227, 245, 983, 251, 2553, 2017, 1381, 31461, 3953, 75775}},
+{5979, 17, 2154, {1, 1, 1, 11, 31, 11, 91, 91, 287, 749, 1019, 4055, 3237, 6965, 14765, 1663, 82987}},
+{5980, 17, 2161, {1, 1, 7, 3, 11, 15, 67, 161, 79, 729, 1115, 3713, 2715, 9361, 9365, 26093, 63409}},
+{5981, 17, 2164, {1, 3, 1, 7, 1, 51, 125, 15, 457, 433, 405, 2329, 157, 4817, 25867, 38177, 45319}},
+{5982, 17, 2177, {1, 3, 7, 9, 25, 57, 5, 233, 481, 781, 1313, 3179, 7219, 8717, 14825, 16079, 127149}},
+{5983, 17, 2178, {1, 1, 7, 15, 27, 51, 5, 65, 77, 313, 1751, 1489, 4307, 10541, 11345, 52577, 18143}},
+{5984, 17, 2184, {1, 1, 1, 15, 21, 5, 113, 71, 411, 327, 1681, 1023, 5661, 15815, 5387, 10351, 21121}},
+{5985, 17, 2198, {1, 1, 5, 5, 29, 55, 25, 255, 69, 879, 501, 1915, 3731, 633, 12197, 5249, 31129}},
+{5986, 17, 2201, {1, 3, 5, 7, 3, 23, 107, 163, 485, 853, 359, 3069, 4353, 371, 6027, 53239, 105541}},
+{5987, 17, 2213, {1, 3, 5, 15, 7, 41, 9, 47, 33, 327, 621, 147, 577, 29, 14623, 3403, 9791}},
+{5988, 17, 2217, {1, 3, 3, 15, 29, 47, 41, 149, 477, 127, 573, 877, 3101, 5963, 28457, 14231, 67425}},
+{5989, 17, 2228, {1, 1, 1, 15, 31, 7, 55, 191, 101, 259, 1071, 219, 2233, 3583, 21969, 32745, 80529}},
+{5990, 17, 2240, {1, 3, 7, 13, 17, 53, 115, 69, 241, 71, 1475, 191, 509, 3721, 15537, 53773, 18005}},
+{5991, 17, 2245, {1, 1, 3, 9, 5, 57, 13, 95, 103, 871, 2043, 2239, 7833, 10727, 6513, 55273, 3781}},
+{5992, 17, 2250, {1, 1, 5, 5, 9, 11, 55, 151, 239, 537, 135, 2779, 7393, 15393, 11097, 58593, 100745}},
+{5993, 17, 2263, {1, 1, 1, 9, 15, 39, 29, 105, 441, 181, 1113, 2125, 8145, 11045, 6589, 33603, 83377}},
+{5994, 17, 2267, {1, 3, 1, 1, 11, 63, 69, 153, 225, 845, 675, 407, 4691, 13383, 27359, 38881, 5509}},
+{5995, 17, 2285, {1, 3, 7, 11, 23, 31, 69, 3, 41, 57, 683, 887, 6861, 12161, 14537, 27293, 113001}},
+{5996, 17, 2286, {1, 1, 1, 11, 5, 1, 101, 175, 437, 3, 1477, 1005, 6607, 7429, 7213, 4025, 66479}},
+{5997, 17, 2291, {1, 1, 7, 5, 19, 7, 99, 131, 273, 977, 1717, 3831, 175, 5673, 12577, 36787, 30945}},
+{5998, 17, 2298, {1, 3, 1, 1, 15, 37, 105, 195, 61, 869, 255, 2625, 7401, 9361, 13217, 52811, 130811}},
+{5999, 17, 2306, {1, 3, 5, 3, 29, 27, 105, 23, 511, 813, 1311, 2859, 1647, 1949, 1329, 27589, 125209}},
+{6000, 17, 2325, {1, 3, 3, 1, 21, 11, 119, 247, 123, 401, 409, 1845, 2133, 10793, 221, 43217, 14069}},
+{6001, 17, 2329, {1, 1, 5, 1, 29, 21, 51, 73, 501, 861, 725, 249, 4249, 8029, 15767, 11985, 18637}},
+{6002, 17, 2332, {1, 1, 5, 11, 19, 39, 97, 65, 13, 283, 489, 2307, 5239, 4161, 18639, 60035, 22405}},
+{6003, 17, 2335, {1, 3, 5, 1, 3, 7, 109, 27, 429, 663, 1569, 3001, 3453, 8627, 9719, 23941, 110451}},
+{6004, 17, 2339, {1, 3, 7, 5, 17, 13, 125, 209, 347, 95, 1937, 1419, 5661, 7171, 20607, 9777, 68343}},
+{6005, 17, 2346, {1, 1, 1, 1, 7, 41, 43, 229, 57, 49, 1863, 2819, 3735, 915, 1571, 11603, 116275}},
+{6006, 17, 2351, {1, 1, 7, 9, 21, 27, 5, 199, 181, 521, 303, 1097, 5427, 8899, 30325, 55457, 16189}},
+{6007, 17, 2353, {1, 3, 3, 7, 19, 41, 3, 205, 279, 223, 971, 633, 2617, 13191, 10193, 23375, 62563}},
+{6008, 17, 2363, {1, 3, 3, 13, 23, 59, 85, 25, 253, 405, 65, 1625, 4401, 4679, 14381, 57833, 30001}},
+{6009, 17, 2378, {1, 3, 3, 3, 13, 35, 11, 157, 123, 397, 119, 2513, 1919, 14583, 5469, 11463, 94711}},
+{6010, 17, 2383, {1, 1, 1, 7, 17, 37, 83, 211, 451, 939, 449, 13, 6671, 1457, 19855, 15053, 52327}},
+{6011, 17, 2391, {1, 1, 5, 3, 9, 57, 39, 183, 331, 451, 1391, 1865, 7801, 14293, 29069, 705, 109497}},
+{6012, 17, 2401, {1, 3, 7, 7, 23, 21, 85, 81, 255, 9, 1685, 2879, 6327, 12675, 31657, 38877, 74131}},
+{6013, 17, 2408, {1, 1, 5, 9, 25, 19, 41, 195, 31, 555, 927, 1445, 593, 11067, 10819, 17205, 82037}},
+{6014, 17, 2414, {1, 3, 1, 13, 1, 35, 29, 71, 323, 705, 53, 3885, 6223, 1319, 30853, 59935, 35949}},
+{6015, 17, 2419, {1, 1, 7, 3, 27, 63, 67, 31, 149, 61, 1611, 77, 4271, 3161, 12493, 38341, 53837}},
+{6016, 17, 2428, {1, 1, 1, 15, 27, 53, 31, 249, 429, 925, 1485, 1855, 4421, 5703, 10097, 14827, 36685}},
+{6017, 17, 2441, {1, 3, 7, 13, 7, 63, 53, 9, 317, 485, 1679, 3631, 3745, 5643, 21615, 45129, 48027}},
+{6018, 17, 2444, {1, 1, 1, 1, 17, 43, 19, 163, 441, 847, 937, 959, 6649, 13071, 1065, 55193, 129509}},
+{6019, 17, 2461, {1, 1, 1, 11, 29, 47, 9, 215, 397, 637, 961, 3139, 2007, 12603, 27657, 22825, 72873}},
+{6020, 17, 2480, {1, 3, 3, 15, 7, 45, 55, 163, 259, 899, 951, 3245, 4191, 15813, 20195, 8361, 54025}},
+{6021, 17, 2483, {1, 1, 5, 11, 3, 17, 13, 223, 289, 255, 875, 2937, 1593, 9729, 21569, 63199, 83875}},
+{6022, 17, 2486, {1, 1, 1, 15, 19, 31, 17, 129, 267, 9, 2015, 3233, 6799, 12891, 18473, 37865, 19547}},
+{6023, 17, 2489, {1, 1, 5, 5, 5, 29, 81, 37, 357, 539, 1525, 2839, 8041, 5569, 4423, 8907, 35461}},
+{6024, 17, 2490, {1, 1, 5, 5, 29, 11, 85, 61, 333, 521, 1111, 3627, 325, 9805, 17889, 25655, 39537}},
+{6025, 17, 2518, {1, 3, 5, 11, 11, 53, 81, 25, 79, 253, 1963, 287, 7487, 15045, 21431, 35417, 102391}},
+{6026, 17, 2527, {1, 1, 1, 5, 11, 33, 45, 45, 425, 773, 1817, 4077, 1471, 11655, 683, 7115, 92651}},
+{6027, 17, 2540, {1, 1, 3, 3, 21, 13, 101, 215, 311, 853, 41, 1007, 5511, 2581, 25565, 13155, 117225}},
+{6028, 17, 2558, {1, 1, 3, 11, 19, 9, 125, 59, 273, 691, 499, 1547, 567, 10259, 21963, 48725, 3601}},
+{6029, 17, 2567, {1, 1, 3, 7, 27, 31, 39, 125, 317, 625, 1329, 3947, 3943, 6889, 2811, 34055, 1449}},
+{6030, 17, 2571, {1, 1, 1, 3, 29, 45, 73, 239, 319, 611, 647, 1839, 5277, 7807, 3107, 14683, 20203}},
+{6031, 17, 2574, {1, 3, 3, 3, 5, 5, 107, 139, 103, 809, 1343, 4041, 3273, 1789, 16205, 47873, 27803}},
+{6032, 17, 2579, {1, 3, 1, 9, 21, 23, 13, 131, 105, 741, 1773, 981, 5633, 14609, 12281, 50343, 14317}},
+{6033, 17, 2585, {1, 1, 1, 5, 11, 5, 125, 171, 109, 555, 159, 905, 691, 12401, 22817, 41411, 70113}},
+{6034, 17, 2615, {1, 3, 3, 9, 31, 37, 109, 231, 59, 615, 799, 319, 2459, 4521, 8525, 4827, 22969}},
+{6035, 17, 2639, {1, 3, 1, 5, 11, 7, 49, 237, 345, 473, 981, 2073, 6525, 8805, 13403, 3659, 69897}},
+{6036, 17, 2641, {1, 3, 1, 5, 9, 37, 13, 203, 141, 573, 745, 2613, 5589, 607, 24483, 38427, 95775}},
+{6037, 17, 2644, {1, 1, 3, 1, 23, 61, 75, 57, 299, 191, 805, 2993, 5175, 12037, 13649, 58831, 48791}},
+{6038, 17, 2663, {1, 3, 7, 13, 31, 57, 13, 219, 185, 717, 1607, 3785, 4719, 11583, 29285, 48207, 92021}},
+{6039, 17, 2667, {1, 3, 7, 15, 23, 35, 23, 69, 411, 773, 1549, 1087, 1685, 15703, 27193, 62675, 43505}},
+{6040, 17, 2669, {1, 1, 5, 3, 25, 19, 97, 75, 493, 549, 1655, 2881, 4989, 2765, 4797, 43143, 113955}},
+{6041, 17, 2672, {1, 1, 5, 7, 21, 5, 65, 37, 383, 133, 1907, 3747, 1525, 5803, 19977, 50551, 23157}},
+{6042, 17, 2687, {1, 1, 1, 11, 15, 61, 59, 109, 489, 901, 1787, 1611, 6101, 10653, 3071, 35643, 56227}},
+{6043, 17, 2700, {1, 3, 1, 5, 15, 25, 121, 111, 25, 251, 1467, 1795, 1631, 13753, 32391, 14831, 90739}},
+{6044, 17, 2705, {1, 1, 1, 13, 23, 55, 119, 147, 45, 871, 1389, 1929, 1023, 16131, 10041, 40055, 23337}},
+{6045, 17, 2724, {1, 3, 1, 15, 27, 33, 23, 41, 463, 603, 1633, 3445, 2007, 5999, 11175, 18343, 13159}},
+{6046, 17, 2728, {1, 3, 1, 9, 17, 15, 107, 63, 493, 411, 293, 3669, 6143, 3057, 8253, 25491, 58907}},
+{6047, 17, 2733, {1, 3, 5, 11, 1, 43, 5, 117, 127, 813, 1881, 3711, 2567, 7819, 5809, 64471, 104221}},
+{6048, 17, 2741, {1, 3, 5, 9, 25, 27, 49, 93, 77, 705, 1773, 1745, 4605, 16137, 14621, 62893, 81637}},
+{6049, 17, 2748, {1, 3, 1, 15, 9, 29, 41, 101, 291, 763, 1475, 3185, 3661, 10351, 26645, 50375, 59373}},
+{6050, 17, 2751, {1, 1, 5, 15, 9, 31, 107, 159, 125, 471, 1023, 2361, 4805, 8073, 21563, 14903, 77801}},
+{6051, 17, 2756, {1, 3, 7, 1, 27, 17, 75, 129, 71, 697, 551, 1969, 6597, 13821, 2605, 61783, 74791}},
+{6052, 17, 2771, {1, 1, 7, 15, 17, 27, 49, 47, 59, 47, 1671, 2535, 1299, 2387, 24349, 23661, 91123}},
+{6053, 17, 2774, {1, 1, 5, 15, 21, 61, 45, 37, 415, 189, 143, 351, 1815, 3479, 2399, 56753, 123893}},
+{6054, 17, 2793, {1, 1, 3, 7, 7, 19, 93, 249, 335, 305, 1437, 1329, 2693, 13201, 9589, 61513, 115995}},
+{6055, 17, 2796, {1, 1, 1, 11, 21, 57, 33, 205, 235, 253, 751, 259, 6029, 9811, 10231, 36899, 78035}},
+{6056, 17, 2804, {1, 1, 1, 11, 13, 25, 115, 195, 111, 913, 1851, 3283, 6083, 11717, 2773, 40727, 493}},
+{6057, 17, 2814, {1, 3, 3, 9, 9, 17, 83, 137, 465, 671, 1277, 325, 2767, 12413, 21977, 47525, 23041}},
+{6058, 17, 2822, {1, 1, 1, 11, 15, 47, 65, 219, 271, 197, 297, 3195, 1325, 9991, 26385, 46055, 43151}},
+{6059, 17, 2845, {1, 1, 1, 13, 31, 21, 39, 89, 127, 629, 367, 2935, 6259, 6627, 15691, 55781, 97251}},
+{6060, 17, 2846, {1, 1, 7, 13, 11, 45, 65, 75, 211, 785, 1221, 2087, 7751, 15619, 25489, 28195, 69007}},
+{6061, 17, 2850, {1, 3, 5, 15, 27, 37, 75, 111, 487, 219, 233, 583, 6433, 15105, 355, 28331, 21105}},
+{6062, 17, 2855, {1, 3, 3, 15, 31, 53, 33, 95, 27, 197, 1727, 1467, 7115, 15479, 26873, 31075, 12793}},
+{6063, 17, 2856, {1, 3, 7, 1, 19, 3, 19, 105, 225, 599, 737, 107, 7951, 10193, 31699, 59207, 85619}},
+{6064, 17, 2867, {1, 3, 1, 3, 7, 17, 73, 191, 247, 421, 537, 1473, 189, 4219, 29993, 25491, 21189}},
+{6065, 17, 2891, {1, 3, 7, 7, 13, 21, 33, 95, 147, 699, 943, 2275, 4093, 6067, 9063, 25503, 111085}},
+{6066, 17, 2894, {1, 1, 7, 9, 13, 47, 123, 121, 347, 467, 225, 957, 2329, 14075, 29843, 61753, 97179}},
+{6067, 17, 2902, {1, 3, 3, 7, 17, 55, 37, 167, 215, 819, 163, 1747, 4485, 15991, 28011, 36351, 106495}},
+{6068, 17, 2908, {1, 1, 3, 9, 25, 5, 83, 199, 209, 395, 1757, 1967, 5739, 2573, 13989, 32145, 4847}},
+{6069, 17, 2951, {1, 3, 3, 13, 11, 21, 25, 223, 239, 569, 1877, 299, 8089, 3697, 801, 64775, 26827}},
+{6070, 17, 2970, {1, 3, 5, 7, 17, 9, 127, 9, 65, 919, 1073, 2661, 1337, 10065, 30099, 30929, 90067}},
+{6071, 17, 2972, {1, 3, 1, 13, 25, 41, 35, 251, 279, 351, 111, 3917, 2815, 7989, 9895, 54859, 126355}},
+{6072, 17, 2975, {1, 1, 3, 7, 17, 61, 13, 73, 335, 831, 703, 37, 2765, 13169, 12513, 56301, 13907}},
+{6073, 17, 2976, {1, 1, 5, 13, 11, 15, 33, 45, 505, 127, 1723, 17, 4927, 11453, 28859, 9671, 80041}},
+{6074, 17, 2981, {1, 3, 1, 5, 9, 1, 25, 147, 281, 601, 243, 2687, 5533, 6725, 11075, 34807, 24619}},
+{6075, 17, 2986, {1, 1, 3, 1, 7, 21, 71, 31, 485, 561, 1361, 1237, 8171, 15885, 7941, 4583, 32851}},
+{6076, 17, 2999, {1, 3, 7, 1, 5, 35, 95, 155, 283, 959, 577, 1343, 4269, 13481, 30819, 40273, 8711}},
+{6077, 17, 3000, {1, 3, 7, 3, 1, 53, 77, 45, 215, 537, 1045, 77, 2791, 3553, 13273, 23819, 62263}},
+{6078, 17, 3006, {1, 3, 1, 15, 29, 59, 7, 145, 85, 3, 251, 2691, 7547, 11241, 32295, 24645, 75739}},
+{6079, 17, 3014, {1, 1, 5, 9, 19, 9, 39, 163, 303, 233, 2039, 2027, 7169, 2773, 28649, 38317, 66761}},
+{6080, 17, 3028, {1, 3, 7, 5, 21, 27, 93, 227, 131, 1019, 1619, 1497, 4043, 1131, 25761, 20173, 99957}},
+{6081, 17, 3031, {1, 3, 7, 5, 19, 33, 15, 173, 435, 399, 531, 2001, 3221, 12627, 10153, 24421, 61805}},
+{6082, 17, 3035, {1, 3, 1, 9, 11, 3, 69, 105, 289, 183, 1103, 831, 2297, 1613, 18801, 54395, 54243}},
+{6083, 17, 3037, {1, 3, 3, 9, 3, 53, 113, 183, 79, 355, 1629, 1061, 3713, 4563, 14365, 43529, 56073}},
+{6084, 17, 3053, {1, 3, 7, 11, 31, 39, 107, 139, 187, 873, 225, 33, 4943, 15837, 225, 6407, 85967}},
+{6085, 17, 3059, {1, 3, 1, 11, 17, 47, 93, 233, 119, 699, 1429, 2845, 2061, 8887, 20665, 45497, 33107}},
+{6086, 17, 3065, {1, 3, 5, 1, 25, 11, 55, 75, 91, 1009, 1887, 3167, 515, 15929, 11659, 57953, 63401}},
+{6087, 17, 3080, {1, 1, 3, 15, 27, 59, 103, 53, 353, 553, 2021, 1543, 2785, 9373, 14609, 21213, 19911}},
+{6088, 17, 3091, {1, 3, 7, 9, 3, 1, 101, 133, 437, 773, 1399, 1067, 7419, 1793, 16589, 3483, 42065}},
+{6089, 17, 3094, {1, 3, 7, 1, 25, 57, 127, 113, 65, 577, 1865, 1527, 6485, 11273, 15803, 39625, 75219}},
+{6090, 17, 3109, {1, 3, 5, 9, 7, 63, 29, 89, 155, 45, 1029, 2407, 6783, 4749, 4849, 26639, 54059}},
+{6091, 17, 3110, {1, 3, 7, 9, 25, 13, 113, 41, 267, 767, 1071, 1689, 269, 14437, 21255, 39473, 65771}},
+{6092, 17, 3113, {1, 3, 1, 15, 5, 3, 77, 43, 391, 763, 59, 1027, 6263, 3715, 31061, 43311, 130725}},
+{6093, 17, 3116, {1, 3, 7, 7, 21, 51, 127, 71, 229, 171, 397, 1099, 871, 2717, 1643, 17363, 125979}},
+{6094, 17, 3136, {1, 1, 5, 15, 25, 11, 11, 113, 203, 795, 1703, 3901, 1113, 12819, 25345, 46691, 112313}},
+{6095, 17, 3139, {1, 3, 7, 5, 1, 59, 91, 81, 325, 483, 595, 1491, 7455, 6699, 199, 35597, 59851}},
+{6096, 17, 3141, {1, 3, 5, 1, 3, 33, 43, 195, 201, 575, 1395, 1305, 7001, 2023, 22419, 15233, 120355}},
+{6097, 17, 3154, {1, 1, 3, 3, 15, 37, 81, 59, 87, 675, 199, 3231, 4473, 5023, 16753, 51475, 102113}},
+{6098, 17, 3160, {1, 1, 7, 9, 13, 39, 65, 9, 51, 565, 1171, 119, 7875, 12149, 6565, 56849, 123235}},
+{6099, 17, 3169, {1, 3, 3, 7, 15, 45, 53, 93, 111, 533, 1849, 643, 2265, 10241, 24741, 11559, 74333}},
+{6100, 17, 3182, {1, 3, 1, 1, 11, 61, 75, 51, 5, 199, 535, 279, 5821, 6005, 2907, 32521, 74121}},
+{6101, 17, 3187, {1, 1, 3, 15, 3, 21, 29, 193, 71, 993, 1719, 1865, 6135, 7683, 12171, 29275, 14539}},
+{6102, 17, 3189, {1, 1, 1, 7, 7, 13, 1, 61, 315, 431, 1145, 2067, 5745, 1641, 1047, 55111, 129477}},
+{6103, 17, 3190, {1, 1, 5, 1, 21, 43, 115, 193, 153, 573, 1181, 3947, 7809, 11317, 30649, 56891, 47741}},
+{6104, 17, 3203, {1, 1, 5, 7, 19, 15, 61, 239, 109, 683, 395, 2869, 3103, 1531, 12019, 45159, 37525}},
+{6105, 17, 3217, {1, 1, 5, 7, 29, 55, 45, 7, 353, 659, 591, 3371, 5777, 8475, 2743, 47483, 11983}},
+{6106, 17, 3229, {1, 3, 1, 3, 13, 17, 39, 195, 43, 5, 1749, 2559, 5843, 8719, 21421, 58511, 105637}},
+{6107, 17, 3236, {1, 3, 5, 5, 5, 21, 29, 63, 387, 301, 567, 3325, 2109, 403, 23053, 24851, 14493}},
+{6108, 17, 3248, {1, 1, 3, 3, 17, 57, 107, 131, 85, 855, 1101, 3199, 7159, 14739, 4197, 27943, 113009}},
+{6109, 17, 3257, {1, 1, 3, 11, 1, 61, 31, 79, 33, 123, 1509, 507, 6679, 2279, 8465, 37279, 17553}},
+{6110, 17, 3278, {1, 3, 1, 15, 7, 33, 11, 71, 217, 609, 1661, 3437, 5497, 13365, 6247, 649, 26407}},
+{6111, 17, 3283, {1, 1, 3, 1, 19, 45, 49, 125, 5, 455, 1669, 4083, 253, 10101, 27327, 16401, 120399}},
+{6112, 17, 3289, {1, 3, 1, 1, 27, 19, 117, 137, 261, 341, 1697, 457, 7553, 12169, 30049, 49281, 36937}},
+{6113, 17, 3292, {1, 1, 1, 3, 9, 49, 33, 13, 461, 545, 1537, 2623, 883, 10921, 5583, 58997, 114183}},
+{6114, 17, 3302, {1, 1, 7, 9, 29, 53, 29, 165, 205, 989, 1347, 2343, 7505, 7609, 18503, 51677, 105993}},
+{6115, 17, 3316, {1, 1, 1, 13, 1, 29, 59, 121, 297, 659, 1965, 1765, 5255, 10971, 32613, 18763, 41983}},
+{6116, 17, 3328, {1, 3, 7, 11, 21, 41, 19, 47, 125, 485, 475, 2745, 4075, 8101, 31227, 4679, 115473}},
+{6117, 17, 3333, {1, 3, 3, 7, 21, 23, 55, 65, 223, 1001, 317, 1459, 183, 5139, 26553, 41471, 116373}},
+{6118, 17, 3337, {1, 1, 7, 3, 1, 9, 29, 139, 343, 913, 1993, 3139, 3791, 5869, 6057, 23863, 35737}},
+{6119, 17, 3340, {1, 3, 3, 3, 7, 21, 77, 197, 239, 467, 35, 591, 1061, 3417, 31811, 38825, 124981}},
+{6120, 17, 3368, {1, 3, 3, 1, 21, 29, 5, 213, 417, 111, 1681, 1409, 2899, 16233, 1053, 51235, 87767}},
+{6121, 17, 3371, {1, 1, 5, 3, 13, 47, 61, 203, 223, 73, 1947, 3613, 5885, 13567, 7593, 34329, 68597}},
+{6122, 17, 3376, {1, 3, 1, 1, 17, 9, 11, 187, 361, 973, 781, 1835, 1539, 12917, 21725, 48279, 115037}},
+{6123, 17, 3385, {1, 3, 1, 1, 9, 25, 117, 157, 433, 395, 403, 2183, 3327, 5427, 7505, 2673, 77137}},
+{6124, 17, 3386, {1, 1, 7, 15, 31, 15, 27, 155, 441, 837, 1877, 3829, 5139, 16331, 31183, 15803, 95699}},
+{6125, 17, 3393, {1, 1, 7, 15, 5, 51, 77, 179, 289, 727, 1763, 2529, 6715, 3967, 29267, 27293, 67953}},
+{6126, 17, 3399, {1, 3, 7, 13, 7, 3, 3, 17, 311, 547, 1465, 1413, 3937, 2725, 24523, 12321, 109763}},
+{6127, 17, 3405, {1, 3, 5, 15, 9, 5, 87, 135, 281, 97, 2021, 1903, 8007, 10321, 27989, 18993, 110407}},
+{6128, 17, 3414, {1, 1, 1, 13, 25, 61, 89, 107, 233, 823, 1375, 3531, 1757, 1577, 29457, 1461, 17217}},
+{6129, 17, 3433, {1, 1, 1, 13, 17, 17, 27, 193, 485, 759, 145, 3943, 4183, 14119, 11217, 3793, 1935}},
+{6130, 17, 3436, {1, 1, 1, 3, 13, 31, 101, 227, 311, 363, 1925, 1525, 5275, 2385, 15093, 48769, 121189}},
+{6131, 17, 3448, {1, 1, 5, 13, 11, 61, 89, 141, 117, 229, 417, 3935, 7249, 13869, 30591, 62763, 67521}},
+{6132, 17, 3467, {1, 1, 3, 15, 7, 59, 105, 239, 453, 221, 1101, 395, 2031, 8941, 23155, 7077, 125593}},
+{6133, 17, 3469, {1, 1, 1, 11, 7, 55, 99, 31, 305, 371, 1035, 577, 4473, 577, 371, 46093, 69157}},
+{6134, 17, 3472, {1, 3, 1, 9, 9, 33, 35, 245, 95, 47, 1623, 2965, 6849, 7269, 5321, 31641, 73321}},
+{6135, 17, 3477, {1, 1, 1, 15, 21, 61, 65, 65, 159, 151, 625, 2281, 2993, 1311, 29757, 24703, 71029}},
+{6136, 17, 3484, {1, 3, 5, 15, 29, 59, 29, 69, 351, 901, 631, 3501, 7031, 703, 20805, 36437, 94931}},
+{6137, 17, 3494, {1, 3, 7, 1, 21, 11, 19, 125, 237, 807, 1651, 2389, 7347, 11759, 27151, 38669, 965}},
+{6138, 17, 3505, {1, 1, 5, 1, 15, 41, 1, 105, 89, 127, 895, 29, 2339, 15951, 18633, 2781, 67269}},
+{6139, 17, 3515, {1, 1, 5, 15, 25, 7, 3, 33, 375, 447, 203, 2579, 6145, 14015, 9939, 52777, 123181}},
+{6140, 17, 3523, {1, 3, 1, 15, 29, 7, 7, 27, 451, 869, 107, 2457, 5557, 11601, 28957, 36181, 41419}},
+{6141, 17, 3530, {1, 1, 1, 7, 1, 57, 33, 213, 329, 763, 815, 169, 623, 155, 20529, 20603, 73311}},
+{6142, 17, 3543, {1, 3, 5, 7, 25, 21, 7, 217, 159, 89, 1373, 1735, 705, 4093, 13083, 3855, 55875}},
+{6143, 17, 3559, {1, 3, 1, 1, 29, 33, 105, 127, 95, 543, 235, 67, 691, 5015, 22139, 18251, 89945}},
+{6144, 17, 3568, {1, 1, 3, 11, 27, 53, 105, 83, 337, 331, 1571, 1145, 745, 1845, 17881, 17697, 88139}},
+{6145, 17, 3577, {1, 3, 7, 15, 19, 37, 119, 35, 35, 463, 1925, 1665, 673, 12193, 12137, 62371, 10957}},
+{6146, 17, 3578, {1, 3, 3, 3, 19, 21, 113, 29, 459, 467, 623, 2661, 857, 16265, 27509, 46555, 18867}},
+{6147, 17, 3594, {1, 3, 7, 5, 17, 49, 123, 41, 85, 673, 41, 1871, 7649, 8687, 28269, 64423, 93675}},
+{6148, 17, 3601, {1, 3, 3, 3, 7, 23, 101, 171, 181, 527, 65, 2387, 6629, 6089, 17387, 46551, 36143}},
+{6149, 17, 3607, {1, 1, 5, 1, 13, 51, 21, 251, 139, 429, 1993, 3767, 1089, 5459, 19407, 41747, 41033}},
+{6150, 17, 3608, {1, 1, 1, 11, 15, 9, 81, 91, 73, 969, 1513, 2067, 7959, 2605, 26641, 37631, 124571}},
+{6151, 17, 3620, {1, 1, 3, 15, 29, 15, 5, 57, 247, 901, 527, 3325, 5859, 11299, 9871, 63947, 125247}},
+{6152, 17, 3629, {1, 3, 1, 5, 1, 35, 75, 21, 307, 43, 1111, 3299, 1647, 3585, 31045, 18217, 95169}},
+{6153, 17, 3644, {1, 3, 1, 7, 23, 35, 11, 103, 3, 461, 1915, 4019, 453, 13111, 26941, 43091, 22917}},
+{6154, 17, 3656, {1, 1, 5, 5, 1, 61, 121, 167, 475, 5, 1749, 887, 2237, 5055, 7077, 29453, 17691}},
+{6155, 17, 3664, {1, 3, 3, 15, 15, 15, 9, 15, 171, 787, 1965, 577, 4507, 7325, 20901, 8557, 111909}},
+{6156, 17, 3670, {1, 3, 5, 1, 27, 15, 123, 141, 63, 55, 599, 4095, 1245, 13919, 27485, 49977, 74551}},
+{6157, 17, 3680, {1, 3, 5, 9, 21, 61, 79, 119, 7, 573, 1923, 2775, 3127, 12689, 12135, 53429, 130163}},
+{6158, 17, 3685, {1, 3, 3, 13, 27, 41, 67, 249, 447, 277, 311, 775, 8187, 10161, 12953, 22885, 121247}},
+{6159, 17, 3686, {1, 3, 5, 9, 21, 55, 115, 65, 45, 395, 481, 2063, 6493, 4199, 19219, 27119, 62255}},
+{6160, 17, 3695, {1, 1, 3, 13, 7, 41, 3, 127, 383, 923, 1725, 1033, 7731, 11971, 3089, 46459, 98369}},
+{6161, 17, 3698, {1, 1, 3, 11, 13, 39, 39, 149, 309, 311, 1491, 807, 2109, 363, 14637, 65429, 124731}},
+{6162, 17, 3703, {1, 1, 7, 13, 13, 35, 67, 81, 493, 859, 1177, 237, 4605, 15319, 16669, 16661, 21385}},
+{6163, 17, 3710, {1, 1, 3, 7, 7, 39, 57, 103, 239, 753, 221, 1611, 1557, 13317, 27453, 10245, 33839}},
+{6164, 17, 3714, {1, 1, 5, 13, 27, 53, 97, 41, 123, 253, 535, 1839, 5827, 7587, 1261, 20313, 65961}},
+{6165, 17, 3726, {1, 1, 7, 1, 11, 47, 93, 135, 223, 591, 1087, 3329, 3293, 14207, 6187, 54789, 23781}},
+{6166, 17, 3731, {1, 3, 7, 7, 25, 21, 97, 105, 269, 515, 1805, 3711, 3295, 7307, 21065, 65205, 116969}},
+{6167, 17, 3733, {1, 3, 1, 11, 25, 37, 21, 89, 109, 581, 1055, 2393, 1291, 1115, 25545, 36383, 93605}},
+{6168, 17, 3737, {1, 3, 7, 1, 27, 13, 113, 11, 395, 473, 943, 4045, 5507, 15051, 25203, 2971, 31961}},
+{6169, 17, 3756, {1, 1, 5, 5, 27, 35, 57, 219, 67, 949, 659, 203, 5235, 6509, 13731, 61533, 54963}},
+{6170, 17, 3759, {1, 3, 1, 1, 15, 39, 85, 13, 347, 99, 25, 3595, 3081, 13617, 14373, 58909, 102181}},
+{6171, 17, 3767, {1, 1, 7, 13, 3, 25, 97, 91, 287, 389, 665, 2981, 2301, 12625, 4495, 57489, 68677}},
+{6172, 17, 3776, {1, 1, 5, 1, 15, 57, 77, 55, 299, 713, 1457, 3699, 2807, 5549, 467, 47367, 8163}},
+{6173, 17, 3785, {1, 1, 7, 3, 23, 45, 91, 251, 501, 193, 1121, 2359, 4781, 12797, 13713, 55171, 927}},
+{6174, 17, 3793, {1, 3, 3, 7, 7, 31, 87, 163, 249, 163, 937, 1293, 4827, 10299, 31935, 58787, 80589}},
+{6175, 17, 3812, {1, 3, 1, 9, 7, 1, 73, 65, 475, 791, 1429, 3319, 7149, 433, 10373, 44061, 121195}},
+{6176, 17, 3815, {1, 1, 5, 9, 9, 61, 27, 249, 435, 437, 1329, 2163, 5859, 13663, 623, 55569, 94283}},
+{6177, 17, 3824, {1, 3, 7, 11, 1, 29, 117, 195, 399, 999, 1705, 1325, 6043, 9823, 27335, 30377, 16627}},
+{6178, 17, 3844, {1, 1, 1, 15, 5, 11, 63, 185, 15, 741, 1061, 2961, 3455, 5, 26587, 54081, 18107}},
+{6179, 17, 3859, {1, 1, 5, 7, 29, 57, 17, 203, 501, 177, 49, 2773, 8069, 12513, 14437, 64489, 58661}},
+{6180, 17, 3866, {1, 3, 3, 9, 11, 23, 121, 3, 415, 447, 1773, 135, 5901, 4951, 2683, 437, 126251}},
+{6181, 17, 3872, {1, 3, 3, 1, 7, 23, 17, 23, 115, 591, 1075, 3133, 49, 15183, 10615, 37857, 122609}},
+{6182, 17, 3884, {1, 1, 3, 3, 13, 49, 63, 37, 275, 763, 1135, 2913, 1563, 11037, 6693, 18799, 32089}},
+{6183, 17, 3889, {1, 3, 5, 11, 7, 29, 59, 45, 227, 941, 1947, 2733, 797, 10485, 7071, 14741, 11451}},
+{6184, 17, 3899, {1, 1, 1, 9, 21, 19, 77, 97, 75, 991, 187, 1003, 5619, 11013, 3931, 19907, 79723}},
+{6185, 17, 3902, {1, 1, 7, 13, 1, 57, 61, 177, 443, 227, 1347, 2665, 2011, 12329, 14137, 37795, 63331}},
+{6186, 17, 3909, {1, 3, 3, 9, 31, 59, 87, 93, 485, 635, 901, 1845, 6153, 10797, 1289, 8989, 41717}},
+{6187, 17, 3913, {1, 1, 1, 1, 3, 7, 85, 17, 67, 309, 1891, 435, 303, 8011, 32127, 54309, 21457}},
+{6188, 17, 3933, {1, 3, 7, 1, 29, 27, 41, 239, 293, 717, 1331, 917, 6145, 7131, 28199, 35093, 103683}},
+{6189, 17, 3938, {1, 3, 7, 3, 21, 63, 65, 233, 257, 789, 1095, 505, 4557, 16259, 7397, 24815, 89529}},
+{6190, 17, 3949, {1, 3, 3, 11, 29, 41, 55, 17, 335, 715, 779, 2121, 6393, 8887, 32753, 45647, 82665}},
+{6191, 17, 3952, {1, 1, 1, 11, 27, 47, 71, 13, 141, 283, 967, 3359, 4309, 6661, 20481, 23175, 50835}},
+{6192, 17, 3980, {1, 3, 3, 7, 3, 25, 19, 241, 409, 573, 1565, 3355, 1307, 12205, 18017, 8271, 117007}},
+{6193, 17, 3991, {1, 3, 3, 9, 21, 39, 21, 253, 439, 963, 341, 3637, 2275, 1845, 11015, 481, 83369}},
+{6194, 17, 3992, {1, 3, 7, 9, 31, 29, 29, 163, 111, 983, 571, 713, 2621, 11569, 13341, 28341, 130381}},
+{6195, 17, 4002, {1, 3, 7, 7, 11, 35, 89, 49, 81, 115, 113, 1857, 3527, 14819, 6909, 14659, 23557}},
+{6196, 17, 4008, {1, 3, 3, 15, 29, 41, 85, 241, 317, 737, 213, 1667, 5789, 16321, 13991, 36165, 124151}},
+{6197, 17, 4011, {1, 3, 1, 3, 31, 1, 75, 99, 495, 241, 1499, 1535, 2033, 2135, 6699, 58893, 37031}},
+{6198, 17, 4016, {1, 1, 7, 9, 25, 15, 101, 23, 477, 563, 1691, 2655, 2321, 2323, 4255, 22055, 99661}},
+{6199, 17, 4034, {1, 3, 7, 5, 7, 7, 49, 221, 51, 83, 279, 2205, 2939, 2119, 14073, 32839, 108075}},
+{6200, 17, 4036, {1, 3, 5, 11, 17, 39, 3, 127, 87, 501, 799, 401, 4439, 9895, 13017, 64975, 67177}},
+{6201, 17, 4063, {1, 3, 3, 9, 17, 41, 59, 95, 283, 309, 83, 1293, 6385, 5783, 30115, 33997, 12531}},
+{6202, 17, 4067, {1, 3, 5, 3, 7, 31, 69, 171, 225, 409, 1237, 3343, 835, 8039, 16723, 37203, 129047}},
+{6203, 17, 4073, {1, 3, 3, 15, 17, 23, 107, 1, 105, 135, 1245, 993, 4101, 7325, 7425, 17379, 98121}},
+{6204, 17, 4082, {1, 1, 7, 9, 27, 5, 67, 111, 75, 531, 243, 2239, 2527, 4513, 27059, 40533, 88169}},
+{6205, 17, 4091, {1, 3, 5, 7, 21, 63, 57, 15, 75, 679, 1729, 1845, 6259, 8531, 18691, 49321, 101599}},
+{6206, 17, 4093, {1, 1, 5, 9, 3, 35, 7, 201, 351, 885, 669, 2339, 5009, 279, 26469, 54597, 67933}},
+{6207, 17, 4101, {1, 3, 5, 13, 27, 5, 85, 161, 141, 733, 1017, 2021, 6951, 15595, 21817, 17243, 88607}},
+{6208, 17, 4113, {1, 3, 5, 1, 11, 31, 117, 97, 175, 629, 995, 1207, 2941, 5825, 5319, 48191, 9505}},
+{6209, 17, 4120, {1, 3, 3, 7, 25, 39, 45, 79, 21, 607, 1593, 1749, 7951, 10425, 17491, 16617, 56903}},
+{6210, 17, 4125, {1, 1, 1, 5, 15, 41, 107, 115, 79, 693, 919, 3513, 6793, 6541, 5545, 58583, 27963}},
+{6211, 17, 4126, {1, 3, 7, 11, 21, 19, 123, 1, 441, 531, 359, 2117, 2465, 11389, 13489, 32755, 4577}},
+{6212, 17, 4139, {1, 1, 5, 13, 7, 7, 7, 127, 201, 377, 1423, 269, 2611, 3339, 19153, 25659, 33069}},
+{6213, 17, 4142, {1, 3, 7, 1, 13, 35, 45, 5, 313, 739, 1779, 2983, 1815, 8817, 14239, 3921, 57975}},
+{6214, 17, 4144, {1, 3, 1, 11, 9, 39, 33, 111, 39, 255, 159, 2345, 2193, 11475, 12841, 47579, 90309}},
+{6215, 17, 4147, {1, 1, 1, 3, 27, 49, 85, 157, 243, 247, 1473, 323, 4631, 1787, 15193, 5533, 104999}},
+{6216, 17, 4153, {1, 1, 7, 9, 11, 29, 23, 219, 57, 339, 1797, 409, 6025, 10569, 27409, 15147, 130281}},
+{6217, 17, 4154, {1, 1, 7, 1, 31, 31, 113, 229, 63, 877, 319, 2655, 3335, 7743, 19593, 10089, 28215}},
+{6218, 17, 4164, {1, 1, 3, 11, 23, 3, 71, 235, 329, 751, 159, 2579, 5363, 12681, 20233, 53855, 16407}},
+{6219, 17, 4174, {1, 1, 5, 1, 7, 61, 21, 235, 379, 849, 61, 2969, 6399, 2655, 21635, 16955, 58675}},
+{6220, 17, 4182, {1, 3, 7, 7, 29, 15, 5, 11, 143, 699, 1875, 2115, 6633, 6195, 5829, 53633, 111221}},
+{6221, 17, 4185, {1, 3, 7, 11, 19, 41, 17, 219, 483, 829, 1233, 3183, 6283, 2363, 25245, 63075, 82733}},
+{6222, 17, 4188, {1, 3, 7, 13, 21, 17, 1, 207, 443, 575, 521, 2585, 6875, 14871, 14739, 10211, 127435}},
+{6223, 17, 4191, {1, 3, 7, 7, 15, 39, 99, 197, 219, 259, 1723, 3737, 6625, 849, 887, 41293, 53825}},
+{6224, 17, 4195, {1, 3, 3, 3, 5, 3, 75, 155, 189, 935, 85, 2273, 1375, 4217, 10709, 58047, 81689}},
+{6225, 17, 4219, {1, 3, 5, 5, 27, 27, 107, 229, 179, 887, 91, 421, 7313, 6495, 451, 43859, 40033}},
+{6226, 17, 4225, {1, 3, 5, 11, 25, 49, 121, 73, 169, 311, 1387, 1037, 6519, 9317, 26975, 50627, 46805}},
+{6227, 17, 4228, {1, 1, 5, 11, 17, 21, 19, 125, 387, 697, 1017, 1759, 7295, 9869, 28241, 9367, 119255}},
+{6228, 17, 4232, {1, 1, 7, 5, 29, 27, 87, 187, 95, 625, 933, 1751, 5253, 313, 30841, 16349, 67347}},
+{6229, 17, 4246, {1, 1, 3, 3, 15, 51, 23, 101, 183, 267, 243, 711, 983, 12461, 17801, 1429, 47273}},
+{6230, 17, 4255, {1, 1, 1, 3, 17, 3, 73, 67, 49, 449, 879, 2559, 401, 11983, 13697, 12023, 78855}},
+{6231, 17, 4274, {1, 3, 7, 15, 25, 25, 43, 81, 141, 161, 595, 621, 1165, 10869, 22875, 6741, 90017}},
+{6232, 17, 4283, {1, 3, 5, 11, 13, 57, 53, 219, 145, 937, 769, 1961, 4725, 3335, 12623, 8335, 46305}},
+{6233, 17, 4286, {1, 1, 3, 5, 7, 39, 19, 101, 313, 583, 483, 2515, 125, 5211, 2559, 11937, 126717}},
+{6234, 17, 4306, {1, 3, 1, 7, 7, 1, 117, 49, 231, 133, 381, 697, 927, 8263, 26529, 64881, 25059}},
+{6235, 17, 4311, {1, 1, 1, 15, 11, 25, 77, 149, 233, 215, 1239, 3045, 99, 11183, 30279, 32271, 100943}},
+{6236, 17, 4317, {1, 1, 5, 7, 31, 25, 1, 51, 221, 607, 1733, 2145, 6765, 7011, 16927, 29257, 2445}},
+{6237, 17, 4321, {1, 3, 5, 1, 19, 23, 123, 93, 381, 295, 765, 2335, 8025, 14003, 4801, 54243, 57297}},
+{6238, 17, 4324, {1, 1, 7, 9, 9, 31, 63, 191, 495, 527, 251, 2119, 1663, 209, 7445, 1441, 4075}},
+{6239, 17, 4331, {1, 3, 5, 5, 13, 17, 97, 79, 369, 55, 677, 2031, 7315, 4769, 31659, 21975, 22061}},
+{6240, 17, 4333, {1, 3, 3, 7, 3, 63, 121, 243, 39, 917, 1917, 297, 7241, 1565, 31675, 14443, 67239}},
+{6241, 17, 4359, {1, 3, 7, 1, 13, 25, 51, 65, 145, 475, 1853, 4023, 5121, 14411, 15993, 42165, 13615}},
+{6242, 17, 4360, {1, 3, 3, 1, 3, 51, 75, 29, 169, 311, 1309, 2929, 7669, 1507, 14605, 32667, 103861}},
+{6243, 17, 4368, {1, 3, 7, 1, 23, 37, 89, 211, 137, 495, 1469, 3425, 1167, 12429, 27301, 46857, 83007}},
+{6244, 17, 4373, {1, 3, 7, 7, 27, 37, 33, 129, 73, 23, 761, 119, 6217, 4749, 20835, 47477, 33665}},
+{6245, 17, 4389, {1, 1, 3, 5, 29, 35, 79, 21, 183, 933, 43, 3149, 5273, 12159, 20695, 5387, 23569}},
+{6246, 17, 4394, {1, 1, 5, 5, 3, 11, 57, 205, 349, 657, 1509, 3693, 5495, 11865, 13861, 62215, 94141}},
+{6247, 17, 4413, {1, 3, 1, 7, 17, 43, 117, 119, 75, 849, 1247, 643, 2691, 2289, 9759, 18683, 68649}},
+{6248, 17, 4422, {1, 1, 1, 15, 5, 55, 89, 177, 427, 701, 735, 2993, 5293, 15395, 567, 5501, 102393}},
+{6249, 17, 4431, {1, 3, 3, 15, 5, 37, 73, 111, 9, 141, 407, 1579, 6691, 11843, 6377, 64181, 97347}},
+{6250, 17, 4436, {1, 1, 5, 1, 9, 17, 71, 127, 285, 929, 1243, 2605, 359, 14589, 32603, 39879, 115901}},
+{6251, 17, 4440, {1, 3, 7, 15, 3, 27, 91, 121, 47, 631, 1589, 385, 5997, 14077, 21285, 33895, 36985}},
+{6252, 17, 4445, {1, 3, 3, 9, 1, 47, 89, 79, 213, 27, 547, 1703, 4035, 13205, 4341, 21895, 34247}},
+{6253, 17, 4452, {1, 3, 5, 7, 9, 9, 47, 89, 231, 857, 297, 2949, 2715, 1275, 14427, 20227, 21569}},
+{6254, 17, 4462, {1, 3, 1, 3, 15, 57, 61, 183, 377, 477, 1135, 1729, 2863, 8607, 29241, 34983, 84443}},
+{6255, 17, 4469, {1, 1, 7, 7, 5, 53, 91, 149, 71, 41, 1025, 3945, 3989, 15853, 20903, 26943, 99841}},
+{6256, 17, 4470, {1, 3, 3, 3, 29, 21, 59, 217, 483, 257, 331, 657, 2935, 945, 9821, 42501, 98087}},
+{6257, 17, 4473, {1, 3, 5, 3, 17, 39, 123, 103, 109, 957, 853, 3821, 555, 10869, 27673, 38315, 83105}},
+{6258, 17, 4479, {1, 3, 1, 3, 27, 7, 97, 57, 429, 53, 1791, 1405, 4113, 8435, 12845, 21567, 91559}},
+{6259, 17, 4480, {1, 3, 3, 1, 17, 61, 125, 77, 225, 395, 945, 3213, 1363, 15947, 27049, 4389, 64037}},
+{6260, 17, 4483, {1, 1, 1, 3, 15, 51, 15, 189, 449, 989, 939, 985, 6929, 13779, 25011, 22277, 72543}},
+{6261, 17, 4489, {1, 3, 3, 1, 25, 53, 5, 219, 195, 703, 163, 1405, 821, 6797, 14329, 1675, 96653}},
+{6262, 17, 4503, {1, 1, 7, 13, 7, 1, 45, 135, 369, 125, 711, 2509, 131, 13663, 29769, 19497, 116779}},
+{6263, 17, 4519, {1, 1, 7, 15, 23, 25, 7, 225, 435, 835, 1981, 2537, 5727, 15961, 30089, 58905, 100339}},
+{6264, 17, 4520, {1, 3, 7, 3, 19, 9, 79, 63, 371, 419, 1357, 3649, 7987, 14541, 6631, 50555, 84217}},
+{6265, 17, 4525, {1, 3, 3, 9, 7, 61, 11, 157, 99, 95, 945, 2803, 1703, 117, 12891, 21817, 84259}},
+{6266, 17, 4526, {1, 3, 7, 7, 25, 37, 111, 99, 65, 599, 1313, 2557, 5489, 3625, 7429, 19309, 78111}},
+{6267, 17, 4533, {1, 3, 1, 1, 19, 15, 85, 253, 347, 315, 1349, 983, 2507, 4155, 15311, 43535, 101409}},
+{6268, 17, 4552, {1, 3, 3, 3, 1, 55, 3, 57, 375, 107, 177, 1673, 6871, 7137, 10297, 65363, 42293}},
+{6269, 17, 4581, {1, 1, 1, 3, 9, 5, 83, 45, 139, 893, 63, 2859, 6333, 15591, 18491, 26387, 25573}},
+{6270, 17, 4585, {1, 1, 7, 15, 1, 39, 113, 127, 503, 617, 1367, 1855, 185, 4233, 5787, 8265, 42097}},
+{6271, 17, 4591, {1, 1, 3, 11, 11, 41, 119, 165, 331, 625, 81, 2495, 7247, 9139, 15269, 31447, 128425}},
+{6272, 17, 4594, {1, 1, 5, 5, 17, 35, 39, 1, 91, 563, 1841, 2975, 1233, 3837, 22145, 36719, 104503}},
+{6273, 17, 4596, {1, 1, 7, 3, 23, 35, 77, 69, 271, 487, 921, 2597, 8011, 13037, 6001, 20519, 32673}},
+{6274, 17, 4599, {1, 1, 1, 1, 29, 17, 11, 145, 473, 877, 813, 727, 6805, 3563, 13371, 22169, 17239}},
+{6275, 17, 4612, {1, 1, 1, 13, 17, 13, 1, 125, 313, 423, 1079, 2401, 2325, 2219, 24071, 25613, 34163}},
+{6276, 17, 4621, {1, 1, 5, 7, 29, 33, 53, 215, 11, 555, 555, 1965, 3643, 5433, 12923, 59655, 25339}},
+{6277, 17, 4630, {1, 3, 3, 3, 23, 37, 119, 117, 459, 359, 1849, 1019, 433, 15391, 5625, 52649, 81313}},
+{6278, 17, 4636, {1, 3, 3, 1, 21, 31, 121, 161, 113, 667, 863, 105, 3805, 14459, 28235, 24543, 89755}},
+{6279, 17, 4640, {1, 1, 5, 15, 17, 37, 15, 111, 511, 477, 611, 955, 2591, 16137, 14179, 30995, 129575}},
+{6280, 17, 4649, {1, 3, 3, 3, 21, 49, 25, 37, 287, 263, 851, 1015, 8133, 9429, 10959, 64483, 82533}},
+{6281, 17, 4650, {1, 1, 5, 1, 25, 19, 49, 159, 155, 443, 975, 1413, 321, 7871, 22935, 57303, 124027}},
+{6282, 17, 4660, {1, 3, 1, 1, 19, 45, 47, 89, 409, 509, 1249, 2445, 2053, 3781, 7517, 61869, 125137}},
+{6283, 17, 4677, {1, 1, 5, 13, 27, 57, 45, 43, 361, 329, 1321, 771, 4665, 12245, 18993, 15121, 127485}},
+{6284, 17, 4687, {1, 3, 3, 7, 3, 41, 127, 75, 485, 821, 497, 2649, 6423, 12419, 31421, 9441, 63645}},
+{6285, 17, 4696, {1, 1, 3, 5, 19, 61, 91, 35, 311, 287, 449, 3955, 5805, 5631, 25613, 55409, 104545}},
+{6286, 17, 4701, {1, 3, 7, 11, 27, 19, 27, 53, 19, 35, 1687, 3923, 3379, 10435, 15053, 12343, 89077}},
+{6287, 17, 4705, {1, 3, 5, 13, 31, 41, 15, 239, 349, 533, 1771, 737, 6503, 14355, 18781, 27805, 79049}},
+{6288, 17, 4706, {1, 3, 1, 3, 13, 11, 69, 227, 169, 873, 533, 2217, 1047, 12415, 12271, 22447, 14163}},
+{6289, 17, 4711, {1, 1, 3, 9, 7, 31, 23, 155, 133, 305, 1569, 521, 201, 10339, 16999, 29163, 32817}},
+{6290, 17, 4720, {1, 1, 1, 5, 31, 57, 43, 223, 121, 803, 357, 1855, 4321, 10245, 25725, 2543, 47395}},
+{6291, 17, 4723, {1, 3, 5, 9, 3, 5, 47, 189, 217, 899, 1455, 691, 1277, 7861, 3627, 14895, 41109}},
+{6292, 17, 4732, {1, 3, 7, 3, 29, 9, 37, 63, 453, 709, 921, 771, 8069, 239, 22639, 59937, 10635}},
+{6293, 17, 4736, {1, 3, 7, 1, 11, 51, 79, 131, 225, 757, 549, 1605, 3921, 1849, 16307, 29809, 120597}},
+{6294, 17, 4742, {1, 3, 7, 7, 1, 45, 33, 185, 23, 881, 1941, 4093, 4741, 11633, 2059, 32007, 11103}},
+{6295, 17, 4748, {1, 3, 5, 11, 17, 21, 43, 205, 363, 559, 697, 4057, 631, 6697, 883, 61705, 102791}},
+{6296, 17, 4754, {1, 1, 7, 9, 29, 35, 109, 85, 373, 321, 415, 2969, 6163, 6999, 9999, 36435, 125267}},
+{6297, 17, 4759, {1, 1, 7, 11, 25, 9, 113, 91, 337, 889, 947, 2093, 5289, 1367, 13297, 36155, 21825}},
+{6298, 17, 4769, {1, 1, 3, 9, 17, 25, 35, 79, 275, 687, 335, 1181, 7327, 3729, 1561, 27441, 114355}},
+{6299, 17, 4787, {1, 3, 3, 11, 25, 41, 27, 89, 115, 361, 871, 1497, 5735, 6365, 1737, 14277, 63847}},
+{6300, 17, 4807, {1, 3, 7, 7, 1, 63, 31, 73, 289, 67, 277, 1821, 4883, 10795, 11755, 15471, 105871}},
+{6301, 17, 4814, {1, 3, 7, 9, 23, 17, 37, 179, 409, 957, 373, 2393, 2363, 6735, 28737, 41927, 115735}},
+{6302, 17, 4837, {1, 1, 3, 9, 15, 43, 111, 61, 455, 181, 1643, 3063, 4311, 13705, 29993, 21731, 25243}},
+{6303, 17, 4867, {1, 1, 1, 15, 13, 13, 69, 187, 91, 395, 209, 3477, 4649, 7727, 30557, 14719, 1953}},
+{6304, 17, 4873, {1, 1, 1, 15, 9, 39, 119, 193, 459, 135, 567, 25, 4583, 8401, 22161, 14771, 74165}},
+{6305, 17, 4879, {1, 1, 3, 7, 5, 39, 77, 149, 293, 585, 1245, 3615, 357, 11613, 13865, 40227, 41023}},
+{6306, 17, 4884, {1, 1, 7, 9, 9, 37, 5, 177, 121, 181, 771, 733, 7683, 4855, 13629, 8349, 46137}},
+{6307, 17, 4898, {1, 1, 3, 13, 3, 37, 73, 69, 281, 109, 563, 1427, 5127, 8957, 16749, 41489, 49531}},
+{6308, 17, 4907, {1, 1, 7, 11, 29, 63, 79, 127, 95, 809, 1175, 1567, 6353, 7505, 26551, 5073, 53733}},
+{6309, 17, 4910, {1, 1, 1, 5, 25, 41, 59, 103, 59, 365, 1111, 3909, 3749, 14889, 3639, 10435, 45407}},
+{6310, 17, 4918, {1, 1, 1, 5, 3, 61, 93, 199, 97, 779, 67, 241, 6197, 6785, 16869, 7573, 46745}},
+{6311, 17, 4924, {1, 1, 5, 9, 27, 29, 21, 69, 165, 661, 1245, 1265, 2979, 9685, 17781, 23329, 48029}},
+{6312, 17, 4953, {1, 1, 1, 7, 7, 23, 39, 197, 169, 561, 499, 2197, 4371, 157, 6837, 44635, 94861}},
+{6313, 17, 4956, {1, 1, 5, 13, 7, 5, 9, 207, 321, 243, 899, 2967, 3553, 15413, 8961, 55039, 6459}},
+{6314, 17, 4965, {1, 3, 5, 3, 13, 25, 33, 145, 45, 979, 33, 2211, 7003, 11147, 11327, 55151, 30697}},
+{6315, 17, 4966, {1, 1, 3, 13, 7, 51, 25, 229, 231, 115, 1815, 3867, 1533, 15259, 8067, 64803, 87535}},
+{6316, 17, 4970, {1, 1, 3, 3, 21, 51, 101, 49, 227, 393, 1659, 955, 545, 7395, 31563, 5499, 130541}},
+{6317, 17, 4972, {1, 3, 1, 1, 21, 41, 57, 161, 269, 35, 893, 1817, 857, 7027, 973, 12529, 46659}},
+{6318, 17, 4983, {1, 1, 3, 7, 17, 35, 23, 29, 335, 725, 453, 1051, 6019, 7595, 29451, 1853, 116615}},
+{6319, 17, 4989, {1, 3, 3, 1, 3, 55, 73, 187, 213, 329, 997, 703, 5829, 7903, 1081, 33359, 119123}},
+{6320, 17, 4994, {1, 3, 3, 15, 29, 55, 15, 17, 245, 117, 1735, 767, 4457, 8803, 17621, 26925, 72487}},
+{6321, 17, 5000, {1, 3, 5, 3, 25, 7, 119, 139, 159, 199, 317, 3875, 8115, 7581, 29239, 50225, 48459}},
+{6322, 17, 5005, {1, 3, 7, 11, 11, 41, 107, 225, 395, 545, 259, 2379, 6709, 11669, 14545, 43663, 69979}},
+{6323, 17, 5014, {1, 3, 5, 13, 23, 45, 73, 137, 447, 305, 117, 2659, 7989, 233, 31991, 60495, 571}},
+{6324, 17, 5018, {1, 3, 7, 9, 1, 37, 31, 1, 433, 701, 159, 3811, 4529, 6697, 7121, 31107, 61555}},
+{6325, 17, 5023, {1, 3, 5, 5, 13, 21, 81, 63, 95, 741, 1189, 1567, 1223, 12371, 28435, 10537, 53785}},
+{6326, 17, 5039, {1, 1, 1, 11, 17, 31, 67, 121, 281, 593, 561, 1759, 387, 9639, 28595, 22473, 4935}},
+{6327, 17, 5053, {1, 3, 7, 3, 5, 43, 59, 151, 351, 263, 297, 423, 1681, 3785, 15171, 7145, 57531}},
+{6328, 17, 5054, {1, 3, 7, 15, 9, 35, 105, 189, 261, 175, 1669, 1289, 5401, 12801, 19585, 48169, 93195}},
+{6329, 17, 5061, {1, 1, 7, 1, 31, 41, 23, 237, 151, 549, 1079, 2933, 5509, 15593, 1791, 15757, 44607}},
+{6330, 17, 5065, {1, 1, 1, 3, 29, 1, 59, 115, 13, 999, 1179, 3561, 2749, 10059, 12861, 6797, 11793}},
+{6331, 17, 5080, {1, 3, 3, 7, 11, 5, 23, 217, 101, 775, 1497, 4047, 2427, 5117, 9683, 28895, 27557}},
+{6332, 17, 5083, {1, 3, 7, 5, 31, 55, 99, 65, 55, 587, 1271, 2277, 7947, 12995, 13149, 4463, 37625}},
+{6333, 17, 5107, {1, 1, 7, 11, 3, 63, 23, 191, 125, 365, 1153, 2657, 6763, 4557, 21643, 26885, 36753}},
+{6334, 17, 5119, {1, 1, 1, 15, 25, 15, 111, 135, 507, 745, 1947, 2545, 4329, 14325, 8187, 52021, 63401}},
+{6335, 17, 5146, {1, 1, 3, 3, 27, 25, 19, 211, 393, 467, 1015, 2495, 7135, 495, 10385, 26961, 49325}},
+{6336, 17, 5151, {1, 1, 3, 5, 15, 35, 3, 203, 337, 337, 703, 1989, 6869, 6055, 21095, 4749, 125669}},
+{6337, 17, 5152, {1, 1, 5, 1, 31, 39, 57, 101, 419, 717, 1489, 199, 5729, 3003, 2607, 64593, 11515}},
+{6338, 17, 5155, {1, 3, 7, 13, 15, 3, 33, 61, 17, 433, 1097, 957, 5351, 3043, 3679, 44881, 126909}},
+{6339, 17, 5169, {1, 1, 3, 11, 5, 1, 121, 175, 119, 367, 399, 2527, 2157, 2667, 31069, 24797, 119621}},
+{6340, 17, 5170, {1, 3, 1, 7, 27, 47, 115, 229, 455, 775, 73, 837, 1181, 3457, 4057, 33907, 67151}},
+{6341, 17, 5176, {1, 3, 3, 1, 7, 51, 71, 177, 463, 921, 393, 3137, 1225, 5709, 303, 20597, 77581}},
+{6342, 17, 5179, {1, 3, 5, 3, 31, 1, 93, 53, 177, 433, 1471, 2191, 4471, 9211, 19397, 57727, 60367}},
+{6343, 17, 5182, {1, 1, 3, 11, 29, 55, 121, 89, 67, 869, 1631, 2657, 7357, 7159, 22449, 16357, 20077}},
+{6344, 17, 5189, {1, 3, 7, 15, 11, 39, 127, 63, 211, 359, 971, 1221, 1909, 9963, 7827, 60923, 98495}},
+{6345, 17, 5193, {1, 1, 7, 9, 23, 47, 47, 85, 307, 471, 1287, 3825, 5451, 15151, 15647, 63043, 92443}},
+{6346, 17, 5196, {1, 3, 7, 5, 19, 11, 11, 27, 307, 695, 99, 1037, 1997, 13673, 591, 8183, 82197}},
+{6347, 17, 5204, {1, 3, 5, 5, 3, 53, 109, 227, 503, 855, 1269, 3903, 5049, 10647, 21751, 58707, 78311}},
+{6348, 17, 5207, {1, 1, 3, 11, 31, 3, 51, 211, 285, 919, 487, 3393, 3463, 2271, 8053, 56791, 33763}},
+{6349, 17, 5211, {1, 3, 3, 5, 21, 15, 5, 5, 327, 809, 915, 1365, 7323, 4247, 31603, 26261, 80389}},
+{6350, 17, 5220, {1, 3, 7, 7, 15, 33, 31, 221, 291, 815, 1307, 929, 3249, 14573, 13613, 59509, 59741}},
+{6351, 17, 5258, {1, 3, 7, 15, 19, 41, 61, 27, 353, 965, 1901, 87, 2669, 12757, 29723, 47165, 16521}},
+{6352, 17, 5265, {1, 3, 5, 3, 11, 43, 97, 215, 361, 901, 1425, 4063, 5327, 14119, 457, 43145, 107401}},
+{6353, 17, 5271, {1, 1, 3, 15, 19, 37, 101, 69, 131, 927, 897, 477, 7641, 4299, 21213, 26017, 123801}},
+{6354, 17, 5277, {1, 3, 7, 7, 19, 5, 11, 51, 277, 985, 1071, 3437, 6595, 9547, 11855, 64249, 30957}},
+{6355, 17, 5278, {1, 1, 7, 9, 21, 41, 89, 113, 61, 235, 685, 1419, 7619, 9863, 21221, 28685, 53409}},
+{6356, 17, 5282, {1, 1, 1, 1, 27, 1, 19, 3, 473, 827, 269, 1659, 2621, 12347, 13359, 64687, 99293}},
+{6357, 17, 5296, {1, 3, 7, 7, 29, 37, 61, 49, 215, 883, 625, 2671, 3743, 4517, 2075, 64865, 58611}},
+{6358, 17, 5299, {1, 3, 3, 7, 15, 11, 35, 37, 255, 781, 613, 3587, 7643, 13081, 32467, 14427, 15235}},
+{6359, 17, 5319, {1, 1, 1, 11, 31, 47, 107, 65, 489, 377, 425, 3453, 2901, 9999, 7687, 13311, 103947}},
+{6360, 17, 5328, {1, 3, 3, 7, 9, 17, 7, 107, 33, 545, 407, 3335, 7563, 14315, 32725, 8483, 69093}},
+{6361, 17, 5343, {1, 1, 1, 5, 17, 9, 87, 229, 417, 769, 423, 569, 7073, 8705, 24487, 63743, 69807}},
+{6362, 17, 5353, {1, 3, 1, 9, 1, 29, 75, 25, 483, 259, 1941, 1533, 8147, 14127, 24087, 37475, 130961}},
+{6363, 17, 5364, {1, 3, 3, 11, 15, 15, 51, 45, 215, 283, 1687, 185, 4521, 12205, 13041, 33283, 77007}},
+{6364, 17, 5368, {1, 1, 3, 3, 5, 47, 107, 67, 325, 87, 1831, 2845, 1645, 1741, 10811, 8983, 58515}},
+{6365, 17, 5379, {1, 3, 1, 13, 19, 17, 1, 151, 411, 915, 1739, 3781, 4939, 15767, 25897, 7205, 17285}},
+{6366, 17, 5381, {1, 3, 5, 15, 19, 1, 125, 33, 321, 325, 639, 4013, 967, 4347, 19743, 13445, 61229}},
+{6367, 17, 5399, {1, 3, 3, 13, 13, 37, 71, 85, 51, 775, 973, 739, 4341, 15707, 12221, 24321, 48073}},
+{6368, 17, 5415, {1, 1, 7, 13, 15, 13, 9, 211, 331, 429, 1323, 3027, 1091, 13311, 289, 57789, 93261}},
+{6369, 17, 5422, {1, 1, 1, 1, 27, 7, 13, 27, 67, 573, 455, 2353, 113, 11831, 9069, 4503, 89291}},
+{6370, 17, 5441, {1, 1, 1, 7, 21, 63, 47, 39, 419, 991, 1623, 11, 3153, 12633, 9425, 65087, 44935}},
+{6371, 17, 5451, {1, 3, 1, 7, 23, 11, 15, 11, 99, 543, 1739, 3955, 5883, 12469, 7529, 14177, 1945}},
+{6372, 17, 5456, {1, 3, 1, 3, 5, 17, 31, 251, 387, 311, 725, 3827, 6835, 5065, 3141, 43441, 87955}},
+{6373, 17, 5462, {1, 1, 1, 11, 25, 7, 75, 135, 67, 589, 889, 3429, 155, 9081, 28653, 8059, 57251}},
+{6374, 17, 5490, {1, 3, 5, 15, 21, 15, 103, 149, 311, 407, 1391, 717, 1765, 14887, 14381, 37483, 29587}},
+{6375, 17, 5495, {1, 3, 5, 5, 19, 31, 93, 5, 507, 193, 1735, 3841, 7895, 9853, 10317, 14867, 49529}},
+{6376, 17, 5501, {1, 3, 7, 7, 19, 3, 99, 201, 479, 313, 693, 3435, 5453, 1157, 23127, 49005, 20167}},
+{6377, 17, 5502, {1, 3, 7, 9, 15, 21, 123, 41, 19, 281, 1837, 2589, 1003, 1993, 18345, 10039, 89325}},
+{6378, 17, 5505, {1, 3, 5, 1, 19, 21, 77, 151, 145, 951, 2017, 609, 5847, 4475, 12439, 6357, 108277}},
+{6379, 17, 5512, {1, 1, 1, 9, 17, 21, 91, 91, 111, 951, 497, 1759, 503, 12787, 25117, 24323, 96447}},
+{6380, 17, 5523, {1, 1, 3, 11, 13, 9, 73, 205, 329, 243, 1187, 829, 2821, 5563, 14391, 771, 116441}},
+{6381, 17, 5529, {1, 1, 1, 1, 11, 57, 39, 221, 41, 521, 1541, 3515, 2367, 4179, 21039, 52943, 11627}},
+{6382, 17, 5548, {1, 3, 3, 3, 23, 13, 103, 125, 67, 217, 863, 3755, 213, 12657, 31399, 3771, 54107}},
+{6383, 17, 5551, {1, 3, 3, 7, 3, 9, 107, 217, 497, 935, 519, 3041, 323, 14895, 5695, 28789, 36085}},
+{6384, 17, 5553, {1, 1, 5, 11, 23, 33, 81, 23, 167, 3, 1683, 2279, 5365, 847, 14717, 9689, 64481}},
+{6385, 17, 5565, {1, 3, 1, 7, 1, 15, 107, 93, 429, 363, 1745, 1459, 5879, 8351, 17527, 44001, 70293}},
+{6386, 17, 5568, {1, 3, 3, 9, 27, 55, 125, 211, 141, 827, 1239, 663, 4803, 11067, 32039, 28091, 56421}},
+{6387, 17, 5577, {1, 3, 5, 5, 7, 13, 125, 231, 427, 483, 967, 549, 3105, 13919, 3017, 39207, 23253}},
+{6388, 17, 5578, {1, 3, 7, 3, 21, 29, 79, 67, 39, 451, 157, 337, 3585, 3621, 9545, 31205, 63201}},
+{6389, 17, 5583, {1, 3, 1, 1, 29, 25, 77, 57, 167, 899, 95, 2487, 3743, 5381, 3637, 56289, 39453}},
+{6390, 17, 5585, {1, 1, 1, 9, 29, 19, 41, 97, 75, 199, 1709, 483, 4099, 3113, 10953, 20659, 109273}},
+{6391, 17, 5588, {1, 3, 5, 15, 13, 9, 83, 43, 111, 789, 965, 4061, 1239, 14577, 10113, 26359, 52609}},
+{6392, 17, 5613, {1, 3, 5, 5, 11, 39, 113, 31, 457, 119, 725, 831, 4143, 5675, 27431, 12431, 94977}},
+{6393, 17, 5614, {1, 1, 3, 3, 25, 17, 93, 253, 307, 625, 143, 1061, 4415, 3563, 3313, 53527, 29537}},
+{6394, 17, 5616, {1, 3, 5, 3, 29, 41, 43, 109, 147, 919, 1675, 465, 6101, 12251, 28915, 15397, 85233}},
+{6395, 17, 5622, {1, 1, 1, 1, 31, 25, 59, 187, 439, 561, 559, 413, 1917, 9319, 27475, 49715, 32953}},
+{6396, 17, 5631, {1, 1, 7, 13, 23, 31, 95, 231, 141, 207, 1373, 2173, 2905, 169, 23825, 55071, 6147}},
+{6397, 17, 5637, {1, 1, 7, 13, 15, 39, 43, 117, 321, 297, 661, 2941, 7359, 11675, 15483, 24093, 7269}},
+{6398, 17, 5638, {1, 3, 3, 13, 9, 59, 51, 49, 81, 563, 745, 1843, 295, 4689, 19847, 42137, 63197}},
+{6399, 17, 5668, {1, 3, 1, 9, 5, 33, 21, 199, 509, 927, 1777, 1349, 3593, 1065, 24943, 55667, 73539}},
+{6400, 17, 5675, {1, 3, 1, 11, 17, 15, 91, 21, 59, 587, 1207, 543, 6669, 10861, 24755, 1789, 91249}},
+{6401, 17, 5683, {1, 3, 7, 15, 13, 47, 57, 147, 381, 1021, 921, 1347, 3847, 5969, 9075, 39081, 127241}},
+{6402, 17, 5695, {1, 3, 3, 15, 19, 15, 1, 97, 203, 409, 1745, 1217, 2199, 7945, 24361, 41771, 123127}},
+{6403, 17, 5703, {1, 3, 3, 5, 17, 17, 43, 255, 179, 717, 1993, 645, 6527, 1533, 32719, 27481, 122425}},
+{6404, 17, 5710, {1, 3, 5, 9, 13, 59, 15, 157, 373, 937, 27, 3325, 2297, 89, 10861, 48615, 16083}},
+{6405, 17, 5715, {1, 3, 1, 3, 19, 27, 109, 243, 189, 17, 99, 1879, 695, 11329, 12467, 6053, 41749}},
+{6406, 17, 5727, {1, 1, 5, 5, 23, 41, 103, 69, 171, 917, 1303, 2101, 617, 10017, 26525, 11009, 66137}},
+{6407, 17, 5738, {1, 1, 1, 9, 21, 45, 47, 171, 455, 257, 411, 4021, 6995, 12881, 4793, 51193, 60775}},
+{6408, 17, 5752, {1, 3, 7, 5, 25, 31, 89, 53, 321, 593, 1795, 2435, 3833, 2767, 17241, 63373, 25457}},
+{6409, 17, 5767, {1, 3, 1, 1, 3, 45, 19, 255, 179, 991, 1407, 3683, 1435, 6803, 12215, 12835, 2005}},
+{6410, 17, 5773, {1, 3, 7, 3, 17, 5, 117, 251, 71, 983, 1391, 3499, 5119, 7257, 7325, 16565, 6321}},
+{6411, 17, 5776, {1, 3, 5, 7, 5, 49, 47, 201, 297, 485, 1879, 2205, 4903, 13619, 22537, 5479, 121625}},
+{6412, 17, 5781, {1, 1, 3, 5, 27, 27, 87, 61, 145, 943, 343, 1639, 6307, 4549, 20765, 33479, 113697}},
+{6413, 17, 5791, {1, 1, 3, 9, 17, 5, 101, 129, 305, 653, 1901, 3901, 6361, 2369, 7449, 55259, 75215}},
+{6414, 17, 5792, {1, 1, 7, 5, 31, 45, 117, 55, 335, 827, 1309, 2603, 2111, 11005, 14747, 56999, 97373}},
+{6415, 17, 5795, {1, 1, 7, 11, 29, 29, 81, 175, 169, 453, 293, 2589, 1057, 15795, 32397, 65433, 79455}},
+{6416, 17, 5798, {1, 1, 1, 5, 11, 7, 13, 249, 29, 407, 1289, 2385, 8113, 15327, 4029, 32005, 105901}},
+{6417, 17, 5801, {1, 1, 5, 5, 7, 61, 103, 141, 109, 391, 631, 821, 1479, 14771, 25057, 1415, 8081}},
+{6418, 17, 5810, {1, 3, 1, 1, 9, 37, 17, 231, 501, 745, 1695, 45, 7797, 2945, 5529, 34747, 39069}},
+{6419, 17, 5812, {1, 1, 7, 9, 21, 59, 103, 103, 33, 875, 723, 3477, 4729, 7311, 29979, 60901, 72187}},
+{6420, 17, 5836, {1, 3, 3, 3, 15, 63, 93, 237, 203, 635, 1189, 2035, 6499, 9943, 9133, 62977, 29657}},
+{6421, 17, 5839, {1, 1, 1, 9, 3, 11, 63, 207, 95, 563, 775, 3009, 7125, 13141, 4489, 16343, 120951}},
+{6422, 17, 5841, {1, 1, 3, 1, 21, 57, 15, 217, 185, 305, 463, 1597, 6529, 4989, 14011, 11265, 131031}},
+{6423, 17, 5867, {1, 3, 5, 15, 17, 61, 35, 127, 411, 579, 1349, 615, 3293, 8475, 9773, 30635, 117639}},
+{6424, 17, 5870, {1, 1, 7, 9, 11, 3, 55, 105, 305, 223, 1899, 2217, 1261, 9831, 23693, 3013, 30489}},
+{6425, 17, 5877, {1, 3, 7, 15, 15, 29, 1, 99, 67, 293, 499, 1941, 5303, 1329, 24547, 14065, 7927}},
+{6426, 17, 5881, {1, 1, 5, 11, 17, 55, 71, 49, 499, 435, 985, 2803, 6139, 1503, 24167, 47181, 102529}},
+{6427, 17, 5899, {1, 3, 5, 1, 19, 53, 71, 17, 63, 469, 1871, 2051, 357, 11661, 5689, 36373, 13379}},
+{6428, 17, 5914, {1, 1, 5, 1, 27, 47, 23, 247, 59, 381, 1895, 2453, 3665, 5487, 24081, 50501, 91659}},
+{6429, 17, 5925, {1, 1, 5, 7, 29, 19, 3, 33, 83, 301, 133, 3603, 5133, 16171, 22905, 36271, 10405}},
+{6430, 17, 5929, {1, 3, 7, 9, 11, 23, 57, 87, 9, 731, 631, 3703, 2593, 12851, 7115, 8801, 108919}},
+{6431, 17, 5943, {1, 3, 3, 3, 23, 35, 33, 99, 343, 837, 231, 3921, 6975, 15093, 15049, 64623, 123523}},
+{6432, 17, 5949, {1, 1, 7, 11, 15, 61, 113, 103, 501, 57, 1345, 3155, 2965, 4433, 10605, 43765, 42169}},
+{6433, 17, 5962, {1, 1, 7, 13, 7, 53, 91, 121, 229, 127, 103, 833, 7829, 1571, 10847, 20861, 101155}},
+{6434, 17, 5969, {1, 3, 7, 1, 9, 25, 71, 103, 37, 473, 1133, 1129, 1651, 6965, 6937, 16597, 20439}},
+{6435, 17, 5976, {1, 1, 5, 9, 1, 9, 47, 131, 285, 967, 1869, 1075, 8127, 135, 15575, 38569, 123729}},
+{6436, 17, 5988, {1, 1, 7, 9, 5, 31, 33, 227, 347, 41, 2025, 3755, 857, 7805, 13121, 38307, 125825}},
+{6437, 17, 5997, {1, 3, 5, 7, 11, 11, 19, 55, 23, 627, 1477, 3093, 2779, 7653, 7165, 23053, 76123}},
+{6438, 17, 6006, {1, 1, 3, 1, 3, 47, 83, 89, 177, 381, 1247, 141, 7051, 6443, 27369, 34323, 43063}},
+{6439, 17, 6010, {1, 1, 7, 7, 13, 15, 55, 223, 351, 525, 1051, 3009, 5443, 11499, 8335, 37949, 69149}},
+{6440, 17, 6016, {1, 1, 1, 3, 13, 61, 89, 33, 129, 921, 1905, 201, 3141, 5531, 135, 34103, 56883}},
+{6441, 17, 6022, {1, 1, 5, 13, 17, 27, 13, 163, 169, 471, 1263, 1421, 7015, 7927, 21027, 58001, 26739}},
+{6442, 17, 6026, {1, 1, 1, 15, 19, 49, 109, 207, 245, 49, 1271, 3635, 2561, 5091, 24415, 59195, 67701}},
+{6443, 17, 6031, {1, 3, 5, 7, 27, 57, 99, 155, 461, 595, 1859, 1727, 857, 4993, 31733, 42141, 10035}},
+{6444, 17, 6040, {1, 1, 1, 15, 11, 11, 85, 9, 251, 375, 155, 379, 7501, 12559, 32583, 36317, 4675}},
+{6445, 17, 6043, {1, 1, 5, 13, 19, 57, 81, 69, 201, 293, 593, 3169, 4519, 9057, 16685, 12847, 123797}},
+{6446, 17, 6050, {1, 3, 1, 5, 5, 1, 19, 243, 345, 661, 561, 3549, 2541, 5887, 25879, 41467, 72799}},
+{6447, 17, 6059, {1, 1, 5, 13, 15, 51, 67, 61, 79, 89, 447, 1471, 4915, 10637, 10901, 48157, 103545}},
+{6448, 17, 6079, {1, 3, 5, 13, 31, 25, 73, 129, 435, 659, 1851, 3595, 753, 7717, 10927, 30115, 109221}},
+{6449, 17, 6099, {1, 1, 1, 3, 25, 3, 121, 43, 349, 205, 1209, 2671, 6445, 8755, 7171, 58631, 74319}},
+{6450, 17, 6101, {1, 1, 3, 1, 11, 15, 83, 37, 483, 65, 759, 1835, 3883, 1693, 30051, 61077, 1187}},
+{6451, 17, 6105, {1, 3, 7, 15, 29, 23, 85, 77, 139, 903, 1821, 943, 6453, 1523, 18539, 49039, 110787}},
+{6452, 17, 6108, {1, 1, 7, 15, 15, 17, 69, 253, 507, 921, 523, 79, 747, 4011, 25795, 42029, 88309}},
+{6453, 17, 6124, {1, 1, 7, 3, 25, 47, 119, 83, 313, 45, 985, 145, 205, 3407, 9013, 64517, 115811}},
+{6454, 17, 6132, {1, 1, 7, 1, 29, 21, 9, 123, 97, 545, 1987, 2979, 6901, 12667, 23325, 63635, 70593}},
+{6455, 17, 6145, {1, 3, 7, 3, 23, 45, 81, 255, 41, 29, 1493, 4065, 3201, 10479, 17193, 39999, 55493}},
+{6456, 17, 6146, {1, 3, 1, 3, 9, 43, 43, 135, 235, 603, 481, 3139, 2729, 14759, 7269, 7995, 110351}},
+{6457, 17, 6151, {1, 3, 1, 11, 17, 35, 113, 93, 417, 967, 755, 659, 3115, 16163, 22997, 38205, 126961}},
+{6458, 17, 6152, {1, 1, 7, 11, 29, 57, 81, 235, 93, 869, 475, 825, 6269, 15819, 14977, 53057, 116021}},
+{6459, 17, 6158, {1, 1, 7, 13, 5, 61, 5, 241, 245, 673, 1651, 3367, 2355, 713, 20107, 30133, 735}},
+{6460, 17, 6160, {1, 1, 5, 9, 21, 3, 121, 241, 129, 703, 1435, 1943, 5087, 13123, 30023, 58287, 50377}},
+{6461, 17, 6163, {1, 1, 1, 15, 23, 27, 67, 197, 123, 629, 169, 3303, 1679, 11051, 16875, 28055, 12379}},
+{6462, 17, 6165, {1, 1, 3, 3, 7, 63, 97, 43, 89, 739, 779, 2893, 7763, 6351, 26135, 44647, 127987}},
+{6463, 17, 6170, {1, 3, 3, 9, 31, 59, 95, 131, 131, 321, 1125, 127, 4865, 145, 26237, 47871, 114549}},
+{6464, 17, 6182, {1, 3, 3, 13, 21, 3, 33, 17, 445, 693, 1599, 2517, 1679, 2237, 15053, 30983, 106755}},
+{6465, 17, 6196, {1, 1, 5, 13, 31, 37, 49, 67, 403, 27, 575, 1795, 3385, 1067, 585, 60277, 123189}},
+{6466, 17, 6199, {1, 3, 1, 15, 13, 35, 23, 247, 493, 305, 363, 451, 4011, 3679, 18281, 31751, 127933}},
+{6467, 17, 6200, {1, 1, 7, 5, 21, 45, 123, 253, 469, 267, 985, 2349, 3427, 7653, 25685, 13747, 531}},
+{6468, 17, 6205, {1, 1, 5, 11, 7, 59, 105, 209, 27, 847, 593, 3775, 6165, 1655, 29867, 28465, 92193}},
+{6469, 17, 6226, {1, 3, 1, 11, 7, 25, 101, 81, 233, 311, 9, 2735, 3951, 485, 10105, 24489, 649}},
+{6470, 17, 6228, {1, 3, 1, 7, 27, 5, 115, 243, 295, 659, 215, 1787, 5131, 2513, 29201, 21195, 103383}},
+{6471, 17, 6237, {1, 3, 5, 13, 29, 21, 7, 57, 345, 467, 1297, 207, 5115, 335, 6153, 32959, 125697}},
+{6472, 17, 6247, {1, 1, 1, 9, 3, 63, 63, 5, 373, 123, 1265, 2365, 1623, 1561, 14805, 17487, 104787}},
+{6473, 17, 6251, {1, 3, 1, 5, 15, 13, 55, 69, 251, 341, 463, 2611, 4793, 12157, 4669, 11613, 128705}},
+{6474, 17, 6253, {1, 3, 7, 13, 19, 7, 93, 149, 453, 693, 1731, 861, 6971, 943, 18891, 56547, 34411}},
+{6475, 17, 6256, {1, 1, 7, 1, 27, 49, 27, 9, 281, 121, 581, 393, 2583, 1159, 26989, 39955, 100765}},
+{6476, 17, 6268, {1, 1, 3, 9, 3, 43, 97, 207, 311, 617, 1987, 2559, 2101, 15791, 30085, 40713, 41909}},
+{6477, 17, 6272, {1, 3, 1, 3, 15, 19, 53, 183, 375, 867, 397, 3203, 4207, 5381, 25065, 60357, 88739}},
+{6478, 17, 6275, {1, 3, 3, 3, 27, 51, 85, 231, 19, 559, 567, 4049, 4875, 14201, 11623, 39763, 57339}},
+{6479, 17, 6281, {1, 1, 5, 1, 19, 7, 81, 249, 41, 789, 985, 3725, 4053, 4255, 9861, 1609, 29511}},
+{6480, 17, 6289, {1, 3, 5, 5, 21, 13, 49, 41, 367, 283, 1161, 2753, 4733, 3691, 27931, 53055, 83625}},
+{6481, 17, 6335, {1, 3, 5, 11, 29, 47, 95, 51, 265, 85, 385, 833, 7957, 14985, 7017, 41937, 41377}},
+{6482, 17, 6338, {1, 1, 7, 5, 1, 23, 17, 191, 185, 323, 515, 3183, 7685, 7361, 21143, 5227, 110297}},
+{6483, 17, 6355, {1, 3, 3, 7, 11, 39, 31, 97, 237, 497, 1649, 3529, 6153, 5055, 29021, 35125, 121581}},
+{6484, 17, 6362, {1, 3, 5, 3, 17, 47, 105, 75, 55, 343, 595, 2447, 5575, 10673, 32015, 37541, 127867}},
+{6485, 17, 6373, {1, 3, 1, 7, 19, 39, 31, 135, 167, 979, 219, 1353, 489, 9667, 27107, 55565, 72291}},
+{6486, 17, 6386, {1, 1, 3, 13, 31, 49, 87, 93, 235, 577, 1551, 2663, 387, 1129, 26683, 31285, 15913}},
+{6487, 17, 6388, {1, 3, 3, 7, 15, 29, 61, 33, 115, 511, 1781, 2029, 4265, 6745, 1467, 34415, 40907}},
+{6488, 17, 6391, {1, 1, 7, 5, 1, 55, 13, 129, 167, 937, 79, 2047, 3589, 1979, 4153, 15229, 85745}},
+{6489, 17, 6397, {1, 1, 7, 15, 15, 25, 89, 129, 31, 435, 1359, 49, 2659, 2829, 8741, 25215, 4239}},
+{6490, 17, 6405, {1, 3, 5, 3, 11, 39, 95, 239, 187, 615, 1481, 3509, 1133, 13497, 24833, 59635, 45695}},
+{6491, 17, 6406, {1, 1, 5, 3, 19, 17, 17, 235, 315, 943, 883, 1381, 7129, 15709, 9847, 41183, 116071}},
+{6492, 17, 6410, {1, 1, 1, 3, 9, 63, 109, 209, 309, 1015, 1391, 2617, 1481, 6483, 4151, 28063, 49887}},
+{6493, 17, 6417, {1, 1, 5, 13, 23, 37, 31, 89, 501, 461, 41, 931, 7863, 15499, 25635, 16995, 41651}},
+{6494, 17, 6443, {1, 1, 1, 9, 29, 29, 125, 161, 219, 439, 1465, 1615, 7483, 7497, 1121, 49693, 30269}},
+{6495, 17, 6457, {1, 3, 1, 5, 7, 43, 27, 161, 431, 375, 419, 2995, 527, 8207, 747, 18491, 15351}},
+{6496, 17, 6468, {1, 1, 3, 13, 25, 21, 67, 177, 9, 453, 1171, 65, 2845, 16147, 12699, 30905, 122255}},
+{6497, 17, 6475, {1, 3, 1, 5, 29, 47, 77, 251, 473, 385, 947, 3239, 5375, 13617, 10639, 36005, 95821}},
+{6498, 17, 6486, {1, 3, 1, 15, 13, 1, 75, 223, 509, 19, 175, 1541, 637, 5711, 1097, 44901, 35277}},
+{6499, 17, 6489, {1, 3, 3, 7, 3, 27, 17, 151, 39, 583, 391, 2739, 7339, 2051, 17005, 49573, 85969}},
+{6500, 17, 6495, {1, 3, 1, 11, 3, 25, 119, 125, 17, 629, 201, 2347, 2923, 1273, 14871, 58299, 97667}},
+{6501, 17, 6499, {1, 1, 7, 1, 31, 39, 11, 121, 339, 667, 1863, 3479, 1895, 11319, 5683, 64969, 9261}},
+{6502, 17, 6505, {1, 1, 5, 9, 27, 61, 101, 221, 221, 583, 287, 707, 5931, 4225, 29537, 46097, 114361}},
+{6503, 17, 6511, {1, 1, 1, 9, 23, 47, 1, 35, 85, 1021, 151, 3153, 3867, 971, 31573, 4745, 107639}},
+{6504, 17, 6520, {1, 1, 7, 13, 15, 15, 63, 37, 291, 907, 411, 1571, 6415, 7443, 26635, 27945, 130909}},
+{6505, 17, 6529, {1, 3, 1, 9, 21, 13, 77, 147, 485, 107, 235, 481, 2389, 957, 11493, 53033, 46373}},
+{6506, 17, 6542, {1, 3, 5, 7, 3, 55, 125, 237, 205, 411, 1911, 4053, 5983, 15489, 29333, 44727, 62167}},
+{6507, 17, 6547, {1, 1, 3, 3, 17, 3, 59, 239, 209, 495, 447, 3427, 3425, 2347, 10057, 26147, 52243}},
+{6508, 17, 6550, {1, 1, 3, 1, 11, 31, 3, 139, 441, 997, 295, 1267, 2181, 6047, 32419, 62657, 24921}},
+{6509, 17, 6554, {1, 3, 7, 15, 5, 3, 11, 9, 211, 701, 1987, 2611, 6195, 14379, 22919, 15785, 52149}},
+{6510, 17, 6556, {1, 1, 7, 9, 7, 27, 35, 253, 343, 679, 103, 1217, 3983, 8677, 17671, 41347, 89355}},
+{6511, 17, 6560, {1, 1, 1, 5, 7, 55, 111, 115, 231, 999, 773, 2111, 3617, 2469, 16967, 60735, 24557}},
+{6512, 17, 6569, {1, 3, 5, 1, 29, 5, 77, 217, 131, 307, 473, 3595, 2713, 6503, 18459, 57245, 91897}},
+{6513, 17, 6572, {1, 3, 5, 13, 9, 33, 93, 31, 59, 343, 1337, 1971, 7593, 15629, 22693, 19885, 4139}},
+{6514, 17, 6590, {1, 3, 3, 3, 21, 33, 115, 205, 373, 587, 739, 669, 8065, 5339, 16507, 29455, 15863}},
+{6515, 17, 6592, {1, 3, 5, 11, 9, 43, 45, 41, 91, 87, 19, 1523, 5059, 9403, 6739, 36893, 6395}},
+{6516, 17, 6601, {1, 1, 5, 15, 19, 43, 81, 3, 401, 621, 1839, 1443, 179, 8085, 27021, 7757, 95011}},
+{6517, 17, 6610, {1, 3, 5, 15, 19, 21, 45, 167, 77, 977, 309, 431, 3437, 8327, 12895, 50521, 68473}},
+{6518, 17, 6632, {1, 3, 3, 15, 7, 21, 49, 169, 327, 271, 7, 785, 1767, 14747, 7083, 65223, 24213}},
+{6519, 17, 6635, {1, 1, 5, 9, 9, 51, 101, 197, 507, 839, 1413, 3131, 331, 15725, 32293, 60433, 86759}},
+{6520, 17, 6640, {1, 1, 7, 1, 17, 39, 127, 201, 341, 607, 1565, 1615, 1367, 16043, 28265, 29139, 63813}},
+{6521, 17, 6643, {1, 3, 5, 7, 9, 1, 107, 73, 121, 649, 1385, 3203, 2897, 8479, 28519, 34041, 1359}},
+{6522, 17, 6649, {1, 1, 7, 7, 21, 55, 19, 13, 415, 647, 2015, 107, 4167, 5033, 16849, 41407, 94387}},
+{6523, 17, 6659, {1, 3, 5, 13, 31, 27, 107, 95, 425, 679, 55, 3521, 6737, 11459, 19995, 64189, 44323}},
+{6524, 17, 6662, {1, 1, 3, 9, 17, 47, 29, 167, 17, 63, 5, 2505, 6483, 14089, 7127, 7907, 68555}},
+{6525, 17, 6666, {1, 1, 5, 3, 29, 3, 87, 107, 227, 893, 1821, 341, 5481, 13317, 10637, 8611, 28625}},
+{6526, 17, 6690, {1, 1, 1, 13, 11, 19, 59, 157, 397, 103, 1821, 3913, 3083, 6053, 1015, 25475, 94813}},
+{6527, 17, 6692, {1, 3, 1, 3, 15, 45, 1, 209, 335, 1015, 539, 2959, 1711, 2567, 30169, 147, 25383}},
+{6528, 17, 6704, {1, 3, 7, 1, 17, 5, 99, 121, 91, 531, 865, 1667, 5615, 4729, 7473, 21445, 37925}},
+{6529, 17, 6713, {1, 1, 7, 13, 3, 51, 27, 115, 439, 761, 1121, 1503, 3047, 2127, 29253, 48147, 10813}},
+{6530, 17, 6728, {1, 3, 7, 15, 1, 51, 33, 161, 509, 159, 1705, 3365, 7953, 14027, 3873, 29609, 33101}},
+{6531, 17, 6731, {1, 1, 5, 15, 15, 53, 119, 115, 433, 75, 497, 1259, 1681, 7715, 24767, 34647, 82007}},
+{6532, 17, 6734, {1, 1, 5, 3, 27, 63, 41, 181, 393, 439, 95, 2765, 7617, 817, 1311, 18595, 16921}},
+{6533, 17, 6746, {1, 3, 1, 15, 31, 7, 57, 89, 371, 745, 475, 3211, 6893, 10681, 18547, 28373, 127787}},
+{6534, 17, 6755, {1, 3, 5, 13, 5, 55, 45, 167, 147, 833, 765, 1153, 4037, 8503, 10751, 49541, 77489}},
+{6535, 17, 6757, {1, 3, 1, 11, 11, 7, 45, 167, 431, 759, 1035, 1367, 1649, 11711, 4915, 58915, 72479}},
+{6536, 17, 6764, {1, 1, 5, 1, 11, 3, 15, 135, 427, 637, 879, 1667, 6139, 14759, 25665, 13083, 67961}},
+{6537, 17, 6772, {1, 3, 3, 9, 1, 3, 73, 167, 269, 51, 1481, 3659, 7863, 7187, 3951, 10711, 5909}},
+{6538, 17, 6792, {1, 1, 3, 3, 9, 53, 101, 209, 109, 691, 1641, 919, 1083, 6247, 23041, 44681, 130105}},
+{6539, 17, 6797, {1, 3, 7, 5, 21, 55, 127, 9, 437, 225, 1599, 2575, 5407, 8099, 20009, 40339, 110581}},
+{6540, 17, 6821, {1, 3, 3, 13, 7, 41, 15, 137, 363, 337, 995, 1215, 3651, 11011, 27209, 53927, 78065}},
+{6541, 17, 6822, {1, 1, 1, 7, 11, 17, 27, 9, 481, 79, 905, 1297, 811, 10221, 463, 12979, 114731}},
+{6542, 17, 6831, {1, 1, 3, 13, 7, 59, 105, 79, 253, 699, 139, 3823, 4939, 12955, 32069, 7255, 18159}},
+{6543, 17, 6834, {1, 3, 5, 7, 29, 7, 79, 79, 147, 921, 425, 1423, 5967, 6397, 17393, 30009, 84075}},
+{6544, 17, 6851, {1, 3, 7, 13, 23, 45, 51, 141, 237, 443, 1101, 309, 4533, 7479, 22415, 31517, 120407}},
+{6545, 17, 6858, {1, 1, 5, 13, 3, 19, 97, 185, 59, 179, 1343, 2537, 3165, 16295, 25005, 49769, 78007}},
+{6546, 17, 6860, {1, 3, 7, 15, 11, 53, 127, 195, 309, 121, 1741, 1415, 225, 15645, 16365, 38729, 70061}},
+{6547, 17, 6871, {1, 3, 7, 11, 29, 35, 47, 109, 179, 3, 849, 2305, 3035, 15289, 31569, 28851, 90057}},
+{6548, 17, 6875, {1, 1, 7, 1, 13, 27, 93, 119, 439, 45, 623, 1263, 6595, 6669, 12981, 64721, 130109}},
+{6549, 17, 6884, {1, 1, 7, 13, 5, 43, 43, 99, 395, 417, 795, 3991, 5601, 13115, 12803, 52247, 39245}},
+{6550, 17, 6888, {1, 3, 3, 3, 15, 61, 85, 91, 407, 391, 359, 3885, 1925, 4873, 169, 41727, 129471}},
+{6551, 17, 6894, {1, 3, 3, 9, 11, 47, 3, 33, 355, 853, 1329, 1347, 1995, 8197, 10015, 787, 66773}},
+{6552, 17, 6919, {1, 3, 3, 13, 31, 31, 49, 195, 55, 185, 1743, 3523, 1781, 8469, 7623, 55933, 74953}},
+{6553, 17, 6940, {1, 3, 5, 15, 29, 31, 5, 45, 149, 71, 2033, 3171, 4601, 9941, 15005, 55709, 74403}},
+{6554, 17, 6950, {1, 3, 5, 3, 1, 27, 105, 7, 139, 805, 1877, 915, 1843, 11897, 29485, 19275, 44711}},
+{6555, 17, 6959, {1, 1, 5, 7, 25, 57, 111, 57, 401, 935, 1685, 2985, 2015, 13501, 14581, 53579, 117011}},
+{6556, 17, 6968, {1, 1, 5, 11, 13, 47, 63, 137, 145, 77, 1727, 2629, 7377, 6311, 537, 13703, 129503}},
+{6557, 17, 6981, {1, 1, 7, 9, 5, 49, 67, 51, 163, 989, 845, 7, 2141, 14467, 3197, 57581, 121087}},
+{6558, 17, 6988, {1, 1, 5, 3, 31, 49, 57, 103, 171, 491, 1109, 1255, 4353, 11927, 29525, 16685, 48469}},
+{6559, 17, 6996, {1, 1, 1, 3, 7, 29, 17, 111, 339, 747, 763, 179, 7747, 2483, 18415, 45301, 25155}},
+{6560, 17, 6999, {1, 1, 7, 7, 1, 41, 71, 109, 401, 815, 1311, 3933, 1349, 13327, 20847, 44391, 49721}},
+{6561, 17, 7015, {1, 1, 1, 15, 27, 57, 39, 129, 391, 701, 619, 3925, 701, 403, 11821, 30517, 22035}},
+{6562, 17, 7019, {1, 1, 5, 11, 21, 49, 109, 101, 497, 417, 73, 2727, 2899, 2777, 22161, 35561, 70211}},
+{6563, 17, 7022, {1, 1, 3, 3, 15, 43, 1, 159, 41, 833, 55, 2415, 5009, 9663, 31295, 29397, 3187}},
+{6564, 17, 7040, {1, 1, 3, 7, 27, 5, 113, 187, 453, 753, 1649, 1605, 2405, 11791, 4239, 20915, 54033}},
+{6565, 17, 7045, {1, 3, 1, 11, 1, 57, 49, 229, 283, 113, 345, 785, 8009, 11977, 30169, 63787, 32011}},
+{6566, 17, 7049, {1, 1, 7, 3, 5, 59, 57, 91, 327, 685, 219, 1949, 3095, 8389, 2035, 11903, 73461}},
+{6567, 17, 7055, {1, 1, 3, 3, 19, 59, 19, 37, 453, 1, 1811, 3263, 1807, 16147, 24861, 14003, 31747}},
+{6568, 17, 7073, {1, 1, 3, 11, 1, 53, 93, 203, 429, 629, 1931, 1487, 3301, 8805, 4901, 2459, 98555}},
+{6569, 17, 7076, {1, 1, 7, 5, 21, 5, 37, 135, 159, 749, 1589, 2631, 8145, 7279, 28397, 47113, 82309}},
+{6570, 17, 7085, {1, 1, 5, 15, 25, 61, 19, 51, 217, 495, 109, 1179, 2743, 12107, 12509, 13003, 94375}},
+{6571, 17, 7091, {1, 3, 3, 15, 11, 7, 67, 165, 57, 925, 427, 2549, 7189, 5917, 13113, 30933, 62703}},
+{6572, 17, 7103, {1, 1, 5, 5, 9, 5, 43, 5, 485, 159, 757, 3979, 4963, 3389, 29731, 48477, 113429}},
+{6573, 17, 7112, {1, 3, 5, 1, 5, 5, 81, 163, 493, 357, 2005, 1093, 5951, 1045, 10569, 40321, 56881}},
+{6574, 17, 7117, {1, 3, 1, 5, 7, 29, 11, 7, 7, 13, 1641, 1031, 4025, 16337, 24333, 9589, 37779}},
+{6575, 17, 7118, {1, 3, 5, 11, 15, 3, 69, 19, 141, 79, 749, 391, 4505, 6939, 3079, 3647, 22363}},
+{6576, 17, 7123, {1, 3, 3, 3, 29, 3, 7, 189, 183, 513, 1225, 239, 4203, 9197, 23507, 33089, 124433}},
+{6577, 17, 7126, {1, 3, 3, 13, 27, 37, 81, 221, 287, 891, 1197, 3501, 539, 2053, 20509, 48635, 50269}},
+{6578, 17, 7154, {1, 1, 5, 7, 13, 3, 35, 79, 3, 885, 343, 3527, 1043, 7197, 6973, 8515, 39315}},
+{6579, 17, 7180, {1, 3, 3, 9, 21, 53, 79, 225, 229, 759, 457, 293, 953, 12857, 20483, 3677, 93839}},
+{6580, 17, 7192, {1, 3, 5, 3, 5, 17, 45, 107, 153, 279, 761, 1923, 7013, 2989, 10137, 19107, 126897}},
+{6581, 17, 7195, {1, 3, 1, 3, 23, 53, 91, 1, 133, 729, 13, 2017, 6933, 7405, 1255, 49509, 105571}},
+{6582, 17, 7207, {1, 3, 5, 1, 9, 45, 35, 153, 209, 289, 1779, 2557, 315, 981, 15347, 30391, 16027}},
+{6583, 17, 7208, {1, 3, 3, 5, 17, 3, 51, 105, 263, 959, 1255, 1177, 8143, 10541, 7687, 38731, 93561}},
+{6584, 17, 7214, {1, 1, 1, 13, 19, 1, 15, 135, 447, 847, 663, 3893, 3539, 6833, 13265, 62923, 8375}},
+{6585, 17, 7222, {1, 3, 1, 15, 31, 11, 105, 1, 91, 523, 1583, 3493, 2665, 117, 10757, 29845, 127201}},
+{6586, 17, 7234, {1, 1, 1, 3, 29, 49, 9, 103, 309, 605, 1751, 1981, 833, 3653, 14001, 16545, 58513}},
+{6587, 17, 7254, {1, 1, 5, 9, 1, 19, 117, 71, 237, 765, 249, 1983, 2289, 6019, 26505, 31427, 64333}},
+{6588, 17, 7258, {1, 1, 3, 11, 15, 31, 5, 207, 347, 143, 11, 1987, 3569, 2051, 31051, 22193, 93289}},
+{6589, 17, 7264, {1, 1, 3, 5, 13, 15, 5, 73, 457, 611, 673, 2675, 8071, 13245, 19443, 14399, 99599}},
+{6590, 17, 7279, {1, 1, 1, 9, 11, 5, 103, 231, 31, 457, 1031, 2257, 3159, 8323, 31585, 26163, 45159}},
+{6591, 17, 7282, {1, 3, 1, 11, 29, 51, 29, 7, 89, 331, 783, 951, 6353, 15421, 12801, 8337, 119171}},
+{6592, 17, 7293, {1, 1, 3, 13, 23, 57, 63, 43, 505, 1, 657, 4005, 6327, 7545, 15455, 27097, 53649}},
+{6593, 17, 7297, {1, 1, 1, 5, 31, 7, 51, 107, 175, 461, 1893, 305, 157, 4819, 18549, 33087, 9499}},
+{6594, 17, 7322, {1, 3, 1, 3, 19, 45, 37, 9, 459, 143, 1327, 3611, 1899, 15109, 30151, 17911, 13233}},
+{6595, 17, 7324, {1, 1, 5, 15, 19, 49, 11, 227, 375, 661, 665, 259, 3659, 13723, 28239, 48159, 59209}},
+{6596, 17, 7351, {1, 3, 7, 7, 17, 49, 77, 161, 505, 713, 1521, 935, 3629, 5033, 26717, 47199, 3693}},
+{6597, 17, 7363, {1, 3, 5, 9, 17, 61, 1, 201, 259, 179, 1637, 2485, 4995, 2813, 19923, 43739, 32183}},
+{6598, 17, 7380, {1, 1, 3, 5, 1, 23, 125, 61, 225, 703, 2011, 1013, 6651, 14029, 27375, 23301, 80269}},
+{6599, 17, 7384, {1, 1, 3, 9, 11, 57, 37, 49, 321, 443, 1055, 1989, 4755, 8467, 22001, 18647, 112617}},
+{6600, 17, 7389, {1, 3, 1, 5, 5, 39, 21, 139, 101, 583, 1881, 2599, 4185, 15679, 22215, 19093, 76737}},
+{6601, 17, 7396, {1, 3, 1, 11, 31, 51, 85, 91, 159, 421, 2005, 1075, 7757, 12653, 25489, 3545, 62961}},
+{6602, 17, 7413, {1, 1, 1, 15, 27, 57, 75, 151, 357, 571, 395, 299, 5607, 12865, 2149, 21059, 120753}},
+{6603, 17, 7417, {1, 1, 1, 3, 15, 57, 63, 171, 265, 709, 1089, 677, 7243, 10207, 9789, 38431, 130415}},
+{6604, 17, 7431, {1, 3, 7, 5, 21, 9, 73, 149, 197, 773, 773, 3931, 4135, 5671, 2733, 57173, 90693}},
+{6605, 17, 7443, {1, 1, 5, 1, 23, 1, 47, 201, 33, 167, 1643, 4009, 2687, 5725, 28733, 27859, 55163}},
+{6606, 17, 7445, {1, 1, 5, 15, 25, 11, 57, 139, 471, 625, 1067, 3647, 6213, 15605, 23537, 5005, 32593}},
+{6607, 17, 7450, {1, 3, 1, 11, 17, 11, 25, 163, 199, 21, 1775, 3721, 2845, 15769, 2381, 27643, 19909}},
+{6608, 17, 7456, {1, 3, 5, 5, 21, 41, 23, 125, 401, 483, 535, 925, 7065, 1727, 3761, 8485, 3519}},
+{6609, 17, 7466, {1, 1, 3, 15, 27, 31, 11, 7, 93, 237, 611, 3635, 4747, 9751, 20607, 20473, 73935}},
+{6610, 17, 7468, {1, 1, 7, 3, 15, 19, 69, 169, 387, 291, 1981, 635, 3387, 15817, 20357, 47537, 107311}},
+{6611, 17, 7474, {1, 3, 7, 15, 13, 59, 31, 235, 399, 343, 1265, 2975, 6839, 13335, 5397, 58915, 31313}},
+{6612, 17, 7479, {1, 1, 7, 1, 3, 35, 81, 243, 387, 421, 1533, 799, 2615, 13219, 9041, 26967, 22677}},
+{6613, 17, 7486, {1, 1, 7, 15, 17, 41, 89, 115, 67, 569, 1647, 1831, 5533, 4629, 1413, 20037, 97343}},
+{6614, 17, 7497, {1, 1, 5, 1, 23, 41, 11, 149, 319, 377, 439, 1237, 4819, 14303, 14657, 61711, 129235}},
+{6615, 17, 7508, {1, 3, 3, 7, 9, 11, 79, 219, 249, 607, 1453, 2931, 3407, 13725, 28289, 42869, 96759}},
+{6616, 17, 7515, {1, 1, 5, 11, 7, 9, 101, 51, 11, 893, 697, 1221, 4237, 1873, 11191, 25517, 119861}},
+{6617, 17, 7533, {1, 1, 3, 11, 23, 23, 19, 245, 485, 317, 1945, 2339, 193, 9389, 30709, 33927, 95089}},
+{6618, 17, 7542, {1, 1, 3, 1, 27, 55, 5, 81, 63, 185, 223, 3639, 6093, 10053, 1793, 11885, 29307}},
+{6619, 17, 7546, {1, 1, 7, 13, 15, 41, 33, 133, 467, 457, 213, 3687, 1313, 2555, 19487, 44257, 108667}},
+{6620, 17, 7551, {1, 1, 3, 5, 31, 51, 53, 115, 449, 273, 1043, 2743, 1759, 2013, 28171, 57091, 76837}},
+{6621, 17, 7569, {1, 1, 5, 15, 21, 43, 11, 215, 151, 253, 913, 1889, 2799, 13787, 3869, 54413, 50991}},
+{6622, 17, 7572, {1, 1, 3, 13, 29, 19, 81, 123, 461, 203, 81, 555, 6601, 15689, 12637, 41467, 105343}},
+{6623, 17, 7595, {1, 1, 3, 13, 7, 21, 75, 111, 47, 481, 1519, 3299, 6199, 3501, 31323, 29215, 45607}},
+{6624, 17, 7603, {1, 3, 1, 3, 17, 51, 45, 223, 321, 233, 267, 3333, 3803, 3099, 4601, 29061, 88441}},
+{6625, 17, 7605, {1, 1, 5, 13, 23, 27, 7, 57, 273, 893, 773, 239, 6357, 15875, 5497, 21775, 108291}},
+{6626, 17, 7629, {1, 3, 1, 15, 25, 17, 11, 229, 175, 909, 691, 3507, 5247, 2933, 1741, 35059, 62841}},
+{6627, 17, 7632, {1, 3, 5, 1, 29, 7, 11, 69, 345, 87, 99, 3243, 5669, 11053, 1185, 6979, 117069}},
+{6628, 17, 7638, {1, 3, 5, 11, 13, 33, 23, 183, 89, 475, 643, 2773, 7899, 15219, 133, 5073, 129355}},
+{6629, 17, 7648, {1, 3, 7, 9, 23, 17, 31, 53, 455, 193, 1695, 2557, 1645, 12675, 27857, 50447, 121335}},
+{6630, 17, 7654, {1, 1, 3, 11, 15, 19, 41, 57, 305, 235, 1131, 1165, 1857, 13667, 19285, 29755, 118885}},
+{6631, 17, 7663, {1, 3, 7, 3, 9, 43, 107, 3, 275, 673, 677, 3769, 3097, 5497, 24911, 4617, 80505}},
+{6632, 17, 7675, {1, 1, 7, 9, 21, 39, 107, 155, 471, 753, 579, 2929, 4951, 4245, 25035, 41795, 86955}},
+{6633, 17, 7693, {1, 3, 1, 7, 31, 51, 27, 165, 147, 751, 709, 399, 45, 947, 9893, 32721, 122127}},
+{6634, 17, 7705, {1, 3, 3, 1, 31, 31, 73, 59, 351, 293, 845, 3139, 4177, 3537, 9465, 20689, 65837}},
+{6635, 17, 7717, {1, 3, 5, 9, 27, 29, 13, 115, 417, 435, 465, 1291, 5225, 11687, 29207, 39895, 55443}},
+{6636, 17, 7724, {1, 3, 3, 15, 29, 49, 111, 179, 221, 565, 787, 1811, 4055, 7863, 27273, 32975, 26985}},
+{6637, 17, 7727, {1, 1, 1, 7, 15, 49, 121, 145, 277, 27, 149, 965, 4903, 3497, 32333, 37217, 105073}},
+{6638, 17, 7735, {1, 1, 7, 1, 23, 29, 31, 77, 353, 349, 755, 2081, 4291, 567, 641, 41751, 20397}},
+{6639, 17, 7761, {1, 1, 5, 3, 25, 31, 97, 3, 405, 607, 965, 2981, 3217, 14695, 25977, 22457, 113539}},
+{6640, 17, 7767, {1, 3, 3, 15, 25, 3, 91, 125, 269, 825, 1163, 2181, 4247, 6813, 4699, 35091, 87771}},
+{6641, 17, 7783, {1, 1, 5, 9, 25, 23, 113, 145, 71, 31, 1115, 3729, 6793, 11869, 26509, 18779, 99499}},
+{6642, 17, 7784, {1, 1, 1, 9, 31, 51, 77, 217, 247, 599, 1541, 3217, 1383, 5203, 27971, 23647, 71823}},
+{6643, 17, 7798, {1, 1, 5, 7, 17, 35, 113, 73, 475, 511, 35, 1961, 5311, 2257, 1935, 58963, 94349}},
+{6644, 17, 7802, {1, 3, 1, 7, 27, 31, 67, 253, 95, 883, 1213, 855, 3429, 15049, 26715, 56099, 101797}},
+{6645, 17, 7811, {1, 1, 3, 5, 9, 9, 61, 57, 511, 537, 1803, 949, 1327, 3921, 11297, 13807, 64629}},
+{6646, 17, 7817, {1, 1, 5, 1, 31, 57, 105, 161, 309, 283, 1291, 2737, 7141, 7497, 25893, 14453, 35375}},
+{6647, 17, 7823, {1, 1, 3, 1, 21, 3, 77, 37, 13, 211, 1863, 1895, 8035, 5801, 25981, 12317, 48375}},
+{6648, 17, 7832, {1, 3, 7, 7, 25, 45, 13, 77, 185, 553, 1501, 1349, 5951, 15581, 32657, 18467, 128363}},
+{6649, 17, 7837, {1, 3, 5, 9, 23, 63, 105, 239, 213, 935, 1331, 3653, 2775, 6591, 6067, 34597, 19217}},
+{6650, 17, 7842, {1, 3, 7, 13, 15, 19, 79, 91, 391, 637, 1685, 2263, 3507, 2025, 2111, 15875, 14831}},
+{6651, 17, 7853, {1, 3, 3, 5, 7, 29, 81, 69, 511, 399, 343, 737, 2833, 1021, 10471, 18689, 36181}},
+{6652, 17, 7854, {1, 1, 5, 11, 21, 17, 39, 137, 145, 857, 583, 789, 8057, 15995, 32113, 64163, 37153}},
+{6653, 17, 7856, {1, 3, 3, 11, 9, 61, 87, 131, 487, 667, 1295, 493, 4629, 7719, 18157, 49715, 2051}},
+{6654, 17, 7861, {1, 3, 5, 9, 19, 5, 85, 3, 491, 353, 571, 2829, 4411, 343, 24781, 62325, 123959}},
+{6655, 17, 7862, {1, 1, 7, 13, 13, 39, 11, 31, 413, 285, 27, 2433, 3307, 6165, 26565, 40065, 102655}},
+{6656, 17, 7873, {1, 1, 5, 11, 25, 45, 7, 97, 9, 973, 1833, 2537, 1457, 7389, 24087, 38061, 122805}},
+{6657, 17, 7874, {1, 3, 5, 3, 21, 63, 77, 21, 249, 525, 1145, 1421, 8011, 3357, 15051, 30293, 127017}},
+{6658, 17, 7886, {1, 1, 5, 3, 13, 53, 81, 185, 303, 307, 1579, 841, 2277, 607, 10899, 34209, 215}},
+{6659, 17, 7914, {1, 3, 3, 13, 17, 1, 125, 145, 205, 763, 127, 1865, 4129, 849, 27247, 29845, 36515}},
+{6660, 17, 7927, {1, 3, 7, 13, 5, 59, 19, 71, 227, 111, 365, 1309, 5857, 6035, 32379, 11303, 127329}},
+{6661, 17, 7936, {1, 1, 1, 1, 19, 61, 79, 253, 459, 23, 725, 3615, 4583, 429, 13215, 31879, 4523}},
+{6662, 17, 7951, {1, 1, 1, 7, 19, 13, 53, 41, 243, 107, 1767, 983, 3483, 2249, 2209, 58895, 14805}},
+{6663, 17, 7963, {1, 1, 1, 9, 5, 63, 31, 85, 119, 307, 633, 3295, 841, 3495, 22965, 57587, 108271}},
+{6664, 17, 7966, {1, 3, 5, 9, 17, 13, 57, 49, 97, 613, 405, 2637, 3229, 14253, 4663, 61345, 33415}},
+{6665, 17, 7976, {1, 3, 1, 1, 17, 37, 63, 3, 5, 375, 1073, 3971, 665, 4445, 153, 20437, 38513}},
+{6666, 17, 7993, {1, 3, 3, 15, 5, 9, 77, 161, 409, 461, 443, 567, 5581, 8623, 27735, 9041, 5517}},
+{6667, 17, 8001, {1, 3, 5, 13, 13, 5, 19, 53, 263, 155, 557, 3973, 6841, 4829, 30751, 30025, 121973}},
+{6668, 17, 8004, {1, 3, 7, 9, 27, 37, 49, 243, 107, 1013, 1743, 1509, 4465, 15415, 4741, 41409, 72695}},
+{6669, 17, 8013, {1, 1, 3, 5, 11, 49, 39, 45, 21, 463, 875, 3681, 1901, 15325, 24553, 51369, 82227}},
+{6670, 17, 8021, {1, 1, 3, 15, 11, 35, 21, 91, 383, 149, 1815, 911, 4633, 12027, 12413, 22307, 120049}},
+{6671, 17, 8026, {1, 3, 5, 7, 7, 3, 15, 83, 477, 687, 145, 1705, 6893, 5233, 20171, 43337, 72603}},
+{6672, 17, 8028, {1, 1, 3, 9, 25, 35, 19, 173, 67, 5, 561, 2139, 4557, 4911, 26273, 38409, 22801}},
+{6673, 17, 8031, {1, 1, 3, 13, 15, 39, 85, 91, 91, 187, 1851, 1181, 4049, 16353, 26525, 43703, 19415}},
+{6674, 17, 8035, {1, 3, 1, 9, 13, 41, 77, 179, 415, 705, 693, 3017, 5847, 16191, 11435, 28979, 51839}},
+{6675, 17, 8042, {1, 1, 3, 5, 23, 15, 3, 159, 269, 67, 625, 4043, 4701, 1599, 6467, 10949, 80073}},
+{6676, 17, 8071, {1, 3, 3, 15, 7, 43, 81, 157, 393, 321, 1875, 2801, 4359, 11703, 1063, 64015, 109997}},
+{6677, 17, 8085, {1, 1, 7, 3, 25, 21, 37, 123, 133, 691, 973, 3115, 2291, 10519, 13339, 22751, 85445}},
+{6678, 17, 8092, {1, 3, 1, 1, 21, 21, 9, 23, 431, 679, 1873, 289, 4503, 3939, 14417, 36081, 18709}},
+{6679, 17, 8102, {1, 3, 5, 5, 1, 53, 109, 133, 33, 279, 727, 2233, 3065, 8557, 7487, 25797, 109177}},
+{6680, 17, 8105, {1, 1, 7, 7, 1, 9, 47, 127, 179, 757, 1985, 547, 169, 13393, 22669, 58795, 92897}},
+{6681, 17, 8114, {1, 3, 5, 11, 17, 21, 95, 219, 263, 579, 1493, 3283, 5461, 1235, 1749, 33325, 36033}},
+{6682, 17, 8123, {1, 1, 3, 11, 21, 49, 45, 143, 511, 983, 1933, 965, 7905, 1925, 27857, 40723, 68251}},
+{6683, 17, 8131, {1, 3, 7, 3, 27, 9, 73, 7, 441, 877, 107, 1599, 4795, 7251, 6819, 7671, 21137}},
+{6684, 17, 8140, {1, 1, 3, 3, 21, 25, 49, 43, 247, 949, 627, 2859, 2507, 4787, 11269, 53221, 126387}},
+{6685, 17, 8145, {1, 1, 5, 3, 5, 53, 127, 65, 353, 521, 1701, 2981, 3201, 611, 13475, 58015, 2605}},
+{6686, 17, 8157, {1, 1, 5, 13, 9, 39, 55, 103, 53, 281, 705, 2433, 6179, 3381, 31973, 30267, 91307}},
+{6687, 17, 8158, {1, 1, 7, 13, 31, 23, 29, 161, 347, 449, 123, 3427, 5731, 12691, 15175, 20487, 74695}},
+{6688, 17, 8185, {1, 3, 3, 15, 13, 19, 83, 137, 437, 317, 921, 913, 7979, 6665, 5313, 1435, 60271}},
+{6689, 17, 8186, {1, 3, 5, 7, 19, 23, 31, 131, 421, 95, 1999, 897, 4839, 1815, 12387, 45009, 2609}},
+{6690, 17, 8188, {1, 1, 1, 7, 3, 53, 121, 33, 47, 283, 813, 3841, 4449, 2543, 15211, 59285, 42551}},
+{6691, 17, 8192, {1, 3, 1, 13, 9, 43, 37, 167, 93, 417, 213, 2721, 3395, 2089, 13743, 32925, 91147}},
+{6692, 17, 8212, {1, 3, 7, 5, 31, 25, 97, 25, 19, 11, 543, 1889, 455, 5765, 9517, 56963, 131069}},
+{6693, 17, 8219, {1, 3, 1, 7, 3, 7, 87, 61, 209, 39, 1303, 1637, 6687, 8001, 5003, 47911, 110657}},
+{6694, 17, 8221, {1, 1, 5, 3, 11, 25, 99, 77, 379, 843, 1423, 2933, 7535, 4181, 32223, 49327, 48041}},
+{6695, 17, 8235, {1, 3, 3, 13, 9, 7, 85, 59, 47, 777, 401, 2449, 2795, 11289, 25023, 7725, 73887}},
+{6696, 17, 8237, {1, 1, 3, 5, 11, 51, 93, 57, 369, 871, 1175, 2705, 1253, 5169, 24691, 14243, 119667}},
+{6697, 17, 8249, {1, 3, 1, 3, 5, 7, 33, 171, 359, 115, 1909, 2003, 1413, 13829, 3471, 36185, 118399}},
+{6698, 17, 8260, {1, 1, 1, 11, 5, 49, 97, 145, 415, 731, 671, 2309, 7211, 11359, 22757, 15415, 70951}},
+{6699, 17, 8264, {1, 1, 3, 5, 7, 51, 61, 101, 375, 575, 1321, 2835, 7569, 9599, 4707, 7655, 53417}},
+{6700, 17, 8270, {1, 3, 1, 15, 9, 63, 25, 117, 203, 5, 1345, 2571, 5273, 2059, 4689, 27237, 23199}},
+{6701, 17, 8282, {1, 1, 3, 15, 15, 23, 69, 49, 349, 995, 5, 1565, 903, 10165, 9565, 6343, 16653}},
+{6702, 17, 8291, {1, 1, 3, 9, 21, 15, 69, 9, 463, 69, 1447, 2347, 5125, 7479, 18257, 14405, 51321}},
+{6703, 17, 8293, {1, 1, 7, 11, 23, 57, 57, 179, 17, 129, 999, 777, 6281, 1693, 31885, 31085, 29237}},
+{6704, 17, 8297, {1, 3, 5, 1, 25, 55, 15, 21, 199, 271, 1645, 1719, 2023, 10049, 15215, 11959, 44875}},
+{6705, 17, 8298, {1, 3, 1, 3, 29, 43, 83, 11, 281, 27, 429, 685, 7189, 9151, 8665, 9553, 115293}},
+{6706, 17, 8305, {1, 3, 1, 7, 17, 43, 125, 11, 189, 803, 713, 683, 7285, 4455, 18195, 45333, 32281}},
+{6707, 17, 8306, {1, 3, 3, 3, 11, 55, 21, 59, 173, 283, 709, 1561, 5391, 5097, 24725, 19217, 13769}},
+{6708, 17, 8311, {1, 3, 5, 13, 7, 29, 117, 207, 415, 525, 567, 1741, 3553, 6729, 433, 17619, 45971}},
+{6709, 17, 8318, {1, 1, 7, 7, 3, 23, 43, 43, 213, 823, 609, 1037, 3797, 4733, 30717, 61067, 89581}},
+{6710, 17, 8327, {1, 3, 5, 7, 11, 7, 7, 241, 379, 217, 739, 2815, 2549, 14297, 10283, 1509, 80613}},
+{6711, 17, 8345, {1, 1, 1, 1, 17, 45, 53, 229, 193, 893, 1881, 227, 6751, 7135, 20823, 36939, 27667}},
+{6712, 17, 8379, {1, 3, 3, 1, 15, 39, 27, 217, 101, 949, 1963, 2213, 2357, 4129, 11925, 841, 59259}},
+{6713, 17, 8390, {1, 1, 3, 3, 5, 53, 59, 255, 421, 1009, 683, 2171, 6691, 12489, 20865, 29363, 70611}},
+{6714, 17, 8394, {1, 1, 7, 15, 7, 31, 105, 141, 153, 401, 549, 3045, 5443, 11147, 18159, 24283, 21859}},
+{6715, 17, 8414, {1, 3, 7, 1, 11, 17, 17, 231, 175, 603, 1915, 111, 3203, 10627, 9687, 47235, 87057}},
+{6716, 17, 8417, {1, 1, 1, 11, 19, 21, 115, 41, 45, 727, 1523, 739, 3025, 10321, 27353, 63139, 16051}},
+{6717, 17, 8432, {1, 3, 7, 11, 13, 9, 33, 121, 237, 565, 2043, 2131, 3079, 12575, 2187, 14427, 85939}},
+{6718, 17, 8437, {1, 3, 1, 15, 21, 19, 91, 227, 485, 49, 101, 15, 1903, 4039, 23819, 40001, 66405}},
+{6719, 17, 8441, {1, 3, 1, 5, 15, 25, 65, 25, 393, 287, 1435, 1851, 6437, 5983, 13769, 37847, 120907}},
+{6720, 17, 8449, {1, 3, 7, 15, 15, 21, 97, 37, 359, 155, 807, 1421, 517, 13135, 2955, 56979, 52299}},
+{6721, 17, 8456, {1, 1, 5, 1, 27, 53, 79, 27, 467, 605, 267, 1193, 31, 6177, 12369, 32621, 38319}},
+{6722, 17, 8473, {1, 1, 1, 11, 27, 15, 15, 231, 205, 677, 331, 133, 3313, 7193, 8059, 36449, 21671}},
+{6723, 17, 8489, {1, 3, 3, 11, 19, 57, 113, 83, 399, 801, 1843, 2119, 2779, 14061, 30901, 28745, 120903}},
+{6724, 17, 8495, {1, 1, 1, 11, 5, 27, 121, 247, 467, 251, 1487, 251, 897, 3171, 28383, 22473, 1709}},
+{6725, 17, 8522, {1, 1, 1, 15, 7, 59, 123, 165, 123, 373, 167, 1323, 5239, 9027, 13791, 55593, 78785}},
+{6726, 17, 8524, {1, 3, 1, 11, 31, 11, 81, 229, 123, 183, 461, 1751, 5713, 2615, 27795, 1657, 39253}},
+{6727, 17, 8529, {1, 1, 7, 1, 21, 45, 107, 3, 283, 149, 549, 3731, 6435, 3595, 32753, 16079, 84257}},
+{6728, 17, 8545, {1, 3, 3, 15, 19, 9, 81, 37, 51, 341, 909, 985, 1503, 12787, 16129, 37789, 113515}},
+{6729, 17, 8557, {1, 3, 5, 13, 3, 33, 127, 219, 369, 341, 1191, 1305, 567, 2339, 31221, 49435, 114927}},
+{6730, 17, 8565, {1, 1, 7, 15, 29, 47, 103, 107, 257, 15, 2029, 2133, 2129, 11235, 29553, 49139, 33809}},
+{6731, 17, 8572, {1, 3, 3, 13, 23, 33, 105, 43, 155, 815, 1087, 2261, 2781, 3461, 7371, 4479, 123093}},
+{6732, 17, 8576, {1, 1, 1, 13, 17, 7, 89, 107, 143, 349, 637, 3651, 4153, 12131, 28393, 45781, 84133}},
+{6733, 17, 8582, {1, 3, 5, 11, 31, 47, 105, 101, 267, 403, 1853, 3977, 3277, 1737, 15503, 47365, 14361}},
+{6734, 17, 8594, {1, 1, 1, 13, 1, 63, 125, 107, 123, 183, 1027, 3491, 3597, 15949, 5779, 34665, 81257}},
+{6735, 17, 8629, {1, 3, 1, 9, 13, 5, 125, 41, 389, 73, 1487, 1983, 957, 12645, 13983, 7675, 72711}},
+{6736, 17, 8636, {1, 3, 7, 5, 17, 5, 25, 63, 211, 591, 261, 2345, 3883, 4403, 773, 43963, 93509}},
+{6737, 17, 8668, {1, 3, 3, 1, 11, 35, 15, 251, 225, 643, 537, 3769, 7593, 6113, 1377, 52185, 81459}},
+{6738, 17, 8678, {1, 3, 5, 15, 27, 27, 51, 35, 389, 853, 1437, 2803, 5739, 1887, 15099, 3299, 111827}},
+{6739, 17, 8701, {1, 1, 3, 15, 25, 63, 31, 201, 79, 131, 31, 3929, 4195, 13045, 8681, 48121, 110723}},
+{6740, 17, 8702, {1, 1, 5, 7, 11, 43, 101, 57, 69, 271, 189, 3087, 4893, 11365, 6945, 14285, 41961}},
+{6741, 17, 8708, {1, 1, 7, 9, 21, 61, 41, 123, 25, 947, 1619, 2895, 7879, 12397, 17405, 48139, 71519}},
+{6742, 17, 8712, {1, 3, 1, 15, 1, 27, 113, 225, 441, 855, 541, 357, 3111, 4867, 20571, 30627, 70123}},
+{6743, 17, 8745, {1, 3, 5, 3, 5, 33, 103, 1, 21, 93, 383, 407, 5145, 7857, 20289, 51943, 16223}},
+{6744, 17, 8754, {1, 1, 7, 15, 1, 13, 41, 215, 463, 417, 513, 3417, 1755, 16165, 7271, 3101, 54353}},
+{6745, 17, 8759, {1, 3, 3, 13, 19, 29, 5, 205, 245, 927, 1249, 773, 3653, 9959, 357, 40863, 37289}},
+{6746, 17, 8763, {1, 3, 3, 7, 3, 5, 85, 241, 29, 627, 1963, 3133, 1369, 503, 11449, 4699, 2573}},
+{6747, 17, 8766, {1, 1, 7, 15, 3, 35, 47, 157, 413, 437, 1627, 3953, 947, 12721, 22209, 34303, 81237}},
+{6748, 17, 8780, {1, 1, 5, 5, 1, 45, 47, 245, 253, 349, 1853, 3481, 6105, 7267, 3159, 38833, 117889}},
+{6749, 17, 8783, {1, 3, 7, 15, 23, 43, 25, 181, 121, 681, 479, 1239, 6155, 3317, 9419, 28717, 44643}},
+{6750, 17, 8786, {1, 3, 3, 15, 31, 43, 111, 99, 405, 991, 301, 1689, 7107, 16131, 16703, 24059, 40345}},
+{6751, 17, 8798, {1, 1, 3, 9, 25, 5, 107, 91, 117, 351, 1595, 163, 3007, 13743, 24535, 38671, 29745}},
+{6752, 17, 8804, {1, 3, 3, 5, 27, 47, 15, 195, 119, 919, 665, 1903, 1981, 7753, 21709, 33699, 15963}},
+{6753, 17, 8819, {1, 3, 1, 11, 23, 23, 75, 115, 477, 105, 541, 1111, 209, 13939, 17129, 7565, 75415}},
+{6754, 17, 8826, {1, 1, 1, 11, 7, 61, 123, 201, 305, 713, 779, 2059, 4899, 13733, 20529, 15617, 39833}},
+{6755, 17, 8835, {1, 1, 7, 11, 21, 7, 63, 113, 213, 871, 375, 29, 1925, 15237, 7091, 12229, 8457}},
+{6756, 17, 8838, {1, 1, 1, 7, 19, 57, 83, 91, 297, 255, 1993, 63, 5337, 4569, 21243, 40867, 46969}},
+{6757, 17, 8856, {1, 1, 3, 7, 13, 63, 91, 191, 281, 259, 1367, 3505, 5885, 10557, 12423, 56303, 14731}},
+{6758, 17, 8862, {1, 1, 5, 15, 27, 15, 29, 67, 115, 287, 253, 1497, 3739, 2183, 14427, 44931, 11547}},
+{6759, 17, 8871, {1, 3, 1, 9, 25, 61, 25, 113, 137, 819, 781, 3741, 2457, 7817, 31209, 20707, 93007}},
+{6760, 17, 8875, {1, 1, 7, 3, 5, 13, 23, 3, 365, 77, 1117, 3061, 4707, 3013, 27899, 10887, 78677}},
+{6761, 17, 8890, {1, 3, 1, 15, 1, 39, 85, 107, 483, 83, 603, 3121, 1995, 5241, 32319, 9515, 94551}},
+{6762, 17, 8892, {1, 1, 7, 3, 27, 13, 105, 41, 285, 237, 1589, 517, 2009, 10833, 1459, 26217, 50759}},
+{6763, 17, 8898, {1, 1, 3, 11, 27, 1, 127, 83, 355, 107, 1003, 657, 4997, 4123, 13151, 56601, 122307}},
+{6764, 17, 8927, {1, 1, 1, 7, 13, 17, 93, 75, 481, 473, 131, 1359, 4859, 1319, 23919, 50079, 128849}},
+{6765, 17, 8928, {1, 1, 3, 7, 9, 33, 111, 229, 11, 283, 1089, 3049, 1635, 959, 19109, 62821, 105391}},
+{6766, 17, 8945, {1, 3, 1, 3, 9, 47, 49, 169, 343, 929, 1379, 1985, 5867, 6053, 12179, 39727, 116053}},
+{6767, 17, 8952, {1, 3, 3, 15, 27, 39, 61, 113, 439, 719, 1313, 3701, 4793, 10275, 2943, 32405, 95457}},
+{6768, 17, 8955, {1, 1, 1, 1, 27, 49, 121, 171, 319, 365, 1593, 1655, 63, 6257, 18097, 35285, 112245}},
+{6769, 17, 8965, {1, 3, 1, 1, 19, 33, 89, 235, 281, 519, 1867, 525, 4475, 12059, 26611, 14789, 59541}},
+{6770, 17, 8972, {1, 3, 1, 15, 1, 51, 65, 71, 131, 599, 117, 2459, 7421, 7157, 24393, 48139, 53701}},
+{6771, 17, 8977, {1, 1, 7, 7, 1, 41, 57, 191, 207, 329, 43, 1235, 5671, 12243, 22549, 40751, 104513}},
+{6772, 17, 8990, {1, 3, 5, 13, 15, 21, 55, 187, 283, 209, 1511, 1329, 6665, 15953, 4521, 16879, 57625}},
+{6773, 17, 8996, {1, 1, 5, 3, 3, 53, 75, 123, 291, 663, 1893, 3669, 4903, 8575, 27971, 46977, 56357}},
+{6774, 17, 9025, {1, 3, 1, 5, 27, 41, 19, 199, 489, 197, 439, 3299, 6315, 6957, 15809, 35297, 5559}},
+{6775, 17, 9037, {1, 3, 5, 1, 3, 25, 109, 191, 33, 543, 125, 2309, 429, 14059, 3149, 45747, 47357}},
+{6776, 17, 9040, {1, 1, 3, 11, 15, 61, 109, 103, 305, 1, 1479, 2781, 6521, 8921, 23681, 9583, 87257}},
+{6777, 17, 9049, {1, 1, 7, 15, 5, 19, 121, 139, 177, 967, 1363, 705, 211, 11877, 22457, 34563, 7801}},
+{6778, 17, 9062, {1, 1, 7, 13, 9, 21, 103, 95, 483, 567, 5, 2095, 4659, 2447, 23521, 27273, 85867}},
+{6779, 17, 9068, {1, 3, 5, 15, 23, 55, 13, 237, 275, 113, 1431, 2931, 5165, 5317, 5625, 51865, 42177}},
+{6780, 17, 9076, {1, 3, 3, 7, 1, 23, 15, 171, 303, 43, 1137, 1255, 3843, 9049, 1799, 7075, 2115}},
+{6781, 17, 9079, {1, 1, 7, 5, 23, 53, 75, 129, 1, 511, 793, 265, 6535, 9641, 25173, 9449, 46949}},
+{6782, 17, 9099, {1, 3, 3, 1, 19, 39, 51, 173, 5, 281, 2047, 4065, 3225, 14587, 16947, 1459, 87227}},
+{6783, 17, 9107, {1, 3, 7, 13, 13, 53, 39, 115, 403, 37, 1533, 2727, 2229, 8291, 18687, 59553, 37629}},
+{6784, 17, 9114, {1, 3, 1, 9, 3, 55, 63, 191, 147, 321, 1287, 2419, 6881, 2249, 11141, 54839, 50263}},
+{6785, 17, 9123, {1, 1, 5, 3, 9, 61, 85, 139, 1, 409, 633, 53, 163, 14677, 13043, 12253, 106939}},
+{6786, 17, 9126, {1, 1, 7, 3, 19, 3, 7, 165, 497, 621, 1563, 1267, 8113, 2383, 17205, 13337, 102547}},
+{6787, 17, 9137, {1, 3, 3, 13, 15, 29, 23, 31, 481, 535, 471, 2125, 331, 9421, 29799, 27097, 5307}},
+{6788, 17, 9149, {1, 1, 1, 1, 31, 45, 47, 139, 235, 509, 889, 685, 1855, 13599, 24431, 62105, 109509}},
+{6789, 17, 9150, {1, 3, 1, 7, 3, 13, 25, 197, 111, 45, 1815, 1031, 4803, 349, 32369, 40837, 111529}},
+{6790, 17, 9155, {1, 1, 7, 1, 27, 9, 3, 73, 403, 321, 967, 2713, 6953, 16123, 8611, 48651, 120635}},
+{6791, 17, 9161, {1, 3, 5, 3, 3, 25, 69, 231, 249, 393, 1141, 1721, 7071, 3711, 15627, 21815, 104735}},
+{6792, 17, 9162, {1, 3, 1, 11, 19, 63, 77, 5, 55, 481, 1021, 119, 3941, 1227, 10997, 29513, 18923}},
+{6793, 17, 9167, {1, 3, 7, 5, 1, 11, 13, 99, 365, 797, 1993, 699, 3091, 11401, 3659, 15339, 90395}},
+{6794, 17, 9172, {1, 3, 5, 7, 31, 43, 55, 143, 273, 379, 1189, 1689, 4811, 5159, 3281, 63819, 57065}},
+{6795, 17, 9186, {1, 1, 1, 13, 9, 25, 9, 3, 461, 281, 959, 2439, 3187, 4837, 13857, 20221, 29733}},
+{6796, 17, 9188, {1, 1, 7, 11, 31, 17, 13, 101, 81, 921, 1329, 2421, 2747, 9435, 23313, 7093, 7547}},
+{6797, 17, 9191, {1, 1, 3, 3, 9, 51, 67, 95, 511, 1011, 1519, 4089, 5001, 1351, 15367, 50665, 92111}},
+{6798, 17, 9198, {1, 1, 5, 13, 27, 43, 115, 77, 439, 589, 31, 915, 7027, 697, 25143, 1443, 59093}},
+{6799, 17, 9200, {1, 1, 7, 3, 17, 5, 107, 117, 133, 649, 1309, 2979, 969, 9789, 12597, 24507, 106825}},
+{6800, 17, 9205, {1, 1, 7, 13, 1, 27, 97, 35, 431, 183, 199, 2619, 515, 89, 20281, 30291, 97977}},
+{6801, 17, 9206, {1, 1, 7, 1, 31, 9, 35, 11, 359, 21, 1875, 3227, 1307, 15691, 17343, 21163, 84671}},
+{6802, 17, 9215, {1, 3, 1, 11, 29, 21, 47, 137, 441, 841, 1641, 3283, 1371, 8835, 16287, 45009, 13779}},
+{6803, 17, 9227, {1, 1, 3, 9, 23, 53, 1, 99, 473, 649, 447, 2589, 5667, 15579, 6497, 44321, 46993}},
+{6804, 17, 9232, {1, 1, 7, 9, 31, 63, 95, 81, 197, 373, 1027, 3959, 7189, 13369, 17287, 53643, 12673}},
+{6805, 17, 9241, {1, 3, 1, 5, 25, 61, 79, 183, 489, 725, 1077, 1147, 113, 7357, 27505, 529, 61855}},
+{6806, 17, 9244, {1, 1, 7, 11, 19, 35, 73, 223, 125, 765, 1303, 2887, 7861, 14839, 9537, 27027, 94327}},
+{6807, 17, 9251, {1, 3, 1, 3, 17, 35, 63, 233, 317, 133, 1837, 3339, 4351, 10071, 5005, 13245, 34327}},
+{6808, 17, 9254, {1, 3, 1, 3, 17, 13, 59, 113, 247, 1015, 1831, 3391, 6337, 6853, 7145, 64309, 40109}},
+{6809, 17, 9275, {1, 3, 5, 13, 15, 23, 65, 203, 241, 545, 1521, 1253, 3171, 7777, 21145, 565, 87813}},
+{6810, 17, 9283, {1, 1, 5, 15, 31, 9, 9, 145, 409, 155, 409, 2935, 5817, 11427, 32617, 38167, 69465}},
+{6811, 17, 9285, {1, 1, 5, 11, 19, 31, 43, 85, 97, 931, 687, 1501, 3991, 2215, 11091, 64735, 56999}},
+{6812, 17, 9303, {1, 1, 1, 3, 7, 11, 101, 21, 345, 829, 531, 1475, 6617, 1187, 26885, 32135, 9733}},
+{6813, 17, 9304, {1, 3, 5, 11, 7, 49, 79, 197, 57, 15, 1845, 1485, 6167, 10887, 17083, 59367, 7411}},
+{6814, 17, 9313, {1, 3, 7, 5, 9, 33, 7, 91, 311, 847, 1435, 3573, 3693, 5369, 26817, 30105, 115337}},
+{6815, 17, 9314, {1, 3, 1, 9, 25, 43, 65, 69, 225, 337, 575, 1979, 5555, 8499, 8127, 33035, 52549}},
+{6816, 17, 9320, {1, 1, 3, 11, 17, 29, 71, 99, 379, 145, 1067, 2561, 7635, 5647, 32491, 56621, 93603}},
+{6817, 17, 9328, {1, 1, 5, 13, 25, 43, 75, 237, 407, 393, 1219, 3651, 7719, 11685, 26123, 62767, 1043}},
+{6818, 17, 9333, {1, 1, 7, 15, 13, 59, 9, 163, 273, 225, 873, 3201, 633, 6121, 18777, 58763, 77731}},
+{6819, 17, 9337, {1, 3, 7, 7, 3, 7, 99, 155, 279, 991, 799, 753, 7205, 9567, 23643, 38263, 19083}},
+{6820, 17, 9338, {1, 3, 7, 11, 11, 29, 65, 3, 207, 575, 253, 2407, 7935, 11323, 23239, 1923, 47737}},
+{6821, 17, 9340, {1, 1, 5, 9, 25, 47, 1, 25, 397, 1009, 193, 4031, 3023, 2029, 10561, 32363, 104405}},
+{6822, 17, 9353, {1, 3, 7, 9, 19, 55, 63, 179, 385, 97, 461, 3393, 8137, 8929, 17621, 9611, 58925}},
+{6823, 17, 9356, {1, 1, 1, 7, 1, 17, 127, 45, 157, 529, 809, 3545, 5173, 5083, 13325, 52295, 91261}},
+{6824, 17, 9364, {1, 1, 7, 9, 25, 49, 99, 79, 157, 535, 1569, 2195, 1725, 1187, 18423, 47957, 10043}},
+{6825, 17, 9373, {1, 1, 3, 7, 3, 31, 83, 45, 199, 665, 1261, 3497, 7885, 5761, 17187, 12041, 12867}},
+{6826, 17, 9374, {1, 3, 1, 7, 3, 55, 73, 215, 41, 1011, 1883, 1051, 7293, 1881, 27435, 29459, 130933}},
+{6827, 17, 9378, {1, 1, 3, 9, 21, 31, 113, 209, 35, 771, 365, 3151, 787, 3845, 26555, 13823, 36951}},
+{6828, 17, 9380, {1, 3, 7, 15, 13, 21, 119, 91, 15, 251, 1337, 2715, 1665, 3451, 8309, 11033, 127159}},
+{6829, 17, 9389, {1, 3, 1, 9, 9, 63, 5, 145, 357, 9, 859, 1565, 1141, 14689, 25121, 41337, 83357}},
+{6830, 17, 9395, {1, 1, 7, 11, 13, 63, 57, 151, 33, 595, 2025, 571, 4713, 11019, 26771, 16221, 92439}},
+{6831, 17, 9412, {1, 3, 3, 15, 29, 49, 93, 131, 167, 835, 33, 263, 93, 8475, 16139, 61237, 95081}},
+{6832, 17, 9422, {1, 1, 7, 13, 1, 57, 43, 91, 485, 841, 1415, 3083, 2665, 8521, 9825, 59955, 21763}},
+{6833, 17, 9439, {1, 1, 1, 1, 29, 47, 63, 107, 439, 847, 537, 2011, 7571, 3699, 23961, 54887, 92681}},
+{6834, 17, 9450, {1, 3, 7, 5, 27, 41, 105, 161, 95, 821, 451, 2627, 4687, 1899, 18851, 35167, 6869}},
+{6835, 17, 9452, {1, 1, 1, 11, 7, 7, 13, 163, 399, 471, 1587, 2561, 1241, 5365, 27189, 49883, 68101}},
+{6836, 17, 9482, {1, 3, 7, 9, 19, 5, 119, 251, 151, 359, 235, 2387, 3919, 7135, 17591, 1053, 6265}},
+{6837, 17, 9487, {1, 1, 5, 9, 13, 25, 43, 23, 453, 693, 517, 1235, 1045, 4299, 27877, 3733, 72269}},
+{6838, 17, 9489, {1, 1, 7, 1, 27, 43, 103, 249, 487, 67, 855, 3239, 2157, 8121, 4701, 37803, 49971}},
+{6839, 17, 9499, {1, 1, 3, 13, 1, 37, 125, 115, 365, 57, 1419, 4085, 7039, 10079, 14991, 48861, 61979}},
+{6840, 17, 9501, {1, 1, 5, 5, 3, 35, 109, 19, 219, 653, 1219, 1625, 6847, 11271, 4525, 56341, 57801}},
+{6841, 17, 9508, {1, 3, 7, 5, 31, 19, 37, 73, 185, 13, 1723, 1139, 5919, 11717, 27161, 13635, 51765}},
+{6842, 17, 9515, {1, 1, 1, 1, 19, 61, 53, 111, 215, 189, 1199, 591, 943, 2111, 17171, 15621, 128459}},
+{6843, 17, 9518, {1, 1, 7, 9, 17, 61, 101, 159, 85, 537, 15, 1427, 6139, 4091, 32639, 28655, 115385}},
+{6844, 17, 9520, {1, 1, 7, 5, 23, 31, 125, 7, 151, 967, 1079, 4059, 3287, 11673, 19307, 49469, 65981}},
+{6845, 17, 9526, {1, 3, 3, 1, 29, 59, 95, 119, 31, 427, 1653, 721, 5509, 6385, 17043, 45133, 74155}},
+{6846, 17, 9537, {1, 1, 3, 9, 13, 61, 35, 189, 1, 559, 119, 3719, 4137, 1369, 19147, 10923, 43909}},
+{6847, 17, 9552, {1, 3, 3, 13, 1, 41, 31, 185, 451, 379, 29, 153, 4121, 13153, 4171, 36993, 109241}},
+{6848, 17, 9571, {1, 1, 1, 9, 15, 41, 99, 17, 21, 93, 649, 2765, 6955, 10843, 12547, 64989, 63713}},
+{6849, 17, 9588, {1, 1, 7, 5, 5, 5, 73, 187, 473, 235, 1907, 409, 7335, 4429, 7493, 20703, 14505}},
+{6850, 17, 9613, {1, 1, 3, 11, 27, 59, 17, 103, 337, 117, 1241, 951, 3701, 10407, 16741, 46531, 56485}},
+{6851, 17, 9619, {1, 1, 3, 15, 11, 51, 111, 189, 137, 939, 97, 1563, 851, 13949, 1375, 41463, 61445}},
+{6852, 17, 9622, {1, 1, 7, 9, 19, 39, 117, 173, 165, 547, 483, 361, 6819, 15093, 13631, 29785, 29593}},
+{6853, 17, 9637, {1, 3, 3, 5, 15, 39, 41, 249, 455, 79, 233, 3133, 405, 9487, 23161, 32751, 117743}},
+{6854, 17, 9652, {1, 1, 5, 15, 7, 63, 7, 57, 127, 349, 1913, 1145, 3371, 3733, 30971, 35717, 60935}},
+{6855, 17, 9655, {1, 1, 7, 11, 7, 57, 49, 63, 51, 233, 855, 2125, 6961, 15011, 28503, 40549, 47175}},
+{6856, 17, 9661, {1, 3, 7, 1, 25, 49, 35, 39, 237, 545, 1637, 1401, 3279, 10499, 14463, 34973, 29485}},
+{6857, 17, 9664, {1, 3, 3, 13, 7, 13, 79, 141, 55, 277, 843, 3087, 2339, 6855, 10635, 13021, 11273}},
+{6858, 17, 9669, {1, 3, 1, 1, 11, 39, 51, 255, 119, 691, 559, 3287, 5485, 791, 19283, 51027, 8061}},
+{6859, 17, 9681, {1, 3, 7, 7, 3, 59, 119, 241, 185, 81, 1843, 2313, 7471, 15689, 2271, 59781, 107439}},
+{6860, 17, 9682, {1, 3, 3, 3, 17, 63, 93, 217, 329, 39, 583, 3031, 4315, 4623, 12557, 42063, 11877}},
+{6861, 17, 9688, {1, 1, 1, 1, 15, 57, 37, 233, 387, 639, 37, 425, 637, 1577, 16449, 33665, 80417}},
+{6862, 17, 9697, {1, 1, 1, 15, 25, 1, 67, 159, 423, 961, 959, 417, 5657, 8417, 8127, 29251, 105893}},
+{6863, 17, 9700, {1, 3, 5, 15, 31, 9, 87, 217, 259, 771, 1663, 2899, 1531, 7849, 1961, 61487, 55399}},
+{6864, 17, 9715, {1, 1, 3, 9, 21, 13, 39, 107, 89, 811, 449, 2569, 4617, 8977, 1649, 37721, 48943}},
+{6865, 17, 9722, {1, 3, 7, 15, 15, 59, 63, 195, 287, 677, 269, 1715, 3545, 3269, 5231, 46433, 25921}},
+{6866, 17, 9727, {1, 1, 5, 7, 19, 27, 57, 221, 243, 47, 1791, 2309, 2751, 4403, 7083, 34223, 64905}},
+{6867, 17, 9734, {1, 1, 1, 15, 1, 63, 119, 155, 383, 649, 429, 3857, 7309, 9823, 9539, 8933, 128573}},
+{6868, 17, 9740, {1, 3, 7, 11, 17, 19, 99, 19, 321, 415, 1501, 2123, 6119, 9705, 11397, 39521, 34327}},
+{6869, 17, 9743, {1, 1, 5, 15, 29, 37, 9, 95, 417, 19, 1637, 2949, 4961, 10743, 9619, 16045, 48083}},
+{6870, 17, 9745, {1, 1, 1, 11, 21, 17, 57, 23, 247, 201, 1781, 779, 2207, 2511, 4829, 13847, 77593}},
+{6871, 17, 9757, {1, 3, 1, 13, 7, 1, 95, 87, 223, 73, 1129, 383, 1355, 4965, 29645, 63465, 76281}},
+{6872, 17, 9761, {1, 3, 3, 13, 3, 47, 33, 123, 155, 621, 1019, 1817, 4083, 4723, 24701, 47503, 18007}},
+{6873, 17, 9762, {1, 1, 7, 15, 13, 41, 73, 93, 379, 923, 1183, 2475, 5901, 10599, 10053, 9941, 112107}},
+{6874, 17, 9767, {1, 1, 3, 3, 13, 35, 59, 231, 45, 1011, 1101, 2467, 2703, 10305, 12575, 7587, 25737}},
+{6875, 17, 9768, {1, 3, 7, 1, 21, 31, 9, 55, 373, 779, 397, 1551, 5139, 16339, 1769, 10413, 74059}},
+{6876, 17, 9774, {1, 1, 7, 15, 7, 3, 67, 179, 411, 217, 1219, 13, 1577, 13463, 12263, 41465, 83001}},
+{6877, 17, 9786, {1, 3, 7, 1, 21, 53, 7, 187, 395, 777, 391, 737, 47, 12681, 16749, 26507, 49415}},
+{6878, 17, 9796, {1, 1, 5, 7, 5, 57, 93, 53, 419, 731, 825, 487, 45, 9199, 20947, 56067, 45343}},
+{6879, 17, 9820, {1, 3, 3, 9, 31, 41, 35, 133, 63, 293, 1503, 51, 3111, 15711, 15051, 1965, 64951}},
+{6880, 17, 9823, {1, 1, 5, 9, 9, 47, 53, 229, 405, 621, 1795, 1923, 6609, 6983, 1695, 18021, 71893}},
+{6881, 17, 9839, {1, 1, 5, 9, 23, 13, 107, 13, 149, 759, 1113, 1329, 1747, 14159, 16705, 61841, 82955}},
+{6882, 17, 9844, {1, 3, 3, 9, 25, 49, 31, 145, 481, 609, 1847, 1485, 6345, 7859, 21231, 37303, 69975}},
+{6883, 17, 9851, {1, 3, 1, 15, 13, 49, 59, 221, 27, 517, 431, 3961, 6401, 8483, 10161, 37453, 128237}},
+{6884, 17, 9853, {1, 1, 3, 1, 3, 55, 37, 111, 263, 735, 655, 2831, 2219, 9449, 8413, 49585, 91355}},
+{6885, 17, 9863, {1, 3, 7, 1, 31, 33, 7, 55, 261, 977, 1215, 1967, 7297, 14815, 27009, 35001, 89671}},
+{6886, 17, 9864, {1, 1, 7, 11, 13, 21, 33, 151, 195, 373, 181, 1631, 355, 7857, 12555, 7531, 50417}},
+{6887, 17, 9877, {1, 3, 1, 15, 19, 25, 79, 195, 237, 385, 1531, 2509, 4371, 16103, 3575, 62265, 124251}},
+{6888, 17, 9884, {1, 3, 1, 11, 5, 61, 21, 159, 51, 37, 845, 3075, 8039, 14269, 10505, 36369, 73793}},
+{6889, 17, 9888, {1, 3, 5, 9, 11, 43, 67, 57, 271, 451, 989, 3705, 2481, 10717, 10861, 63785, 10183}},
+{6890, 17, 9897, {1, 3, 3, 5, 13, 29, 119, 171, 439, 459, 479, 3173, 3781, 11131, 6827, 53925, 119939}},
+{6891, 17, 9915, {1, 3, 7, 3, 27, 21, 1, 167, 79, 305, 1283, 1903, 5483, 5727, 17911, 16075, 97629}},
+{6892, 17, 9925, {1, 3, 1, 3, 23, 21, 29, 185, 227, 295, 915, 2033, 6269, 2089, 20785, 15207, 115675}},
+{6893, 17, 9949, {1, 3, 7, 15, 11, 15, 65, 103, 249, 27, 1805, 2079, 4797, 2535, 16865, 61449, 90923}},
+{6894, 17, 9954, {1, 3, 7, 9, 27, 41, 77, 181, 457, 677, 633, 1601, 8085, 2431, 7957, 55913, 38677}},
+{6895, 17, 9960, {1, 1, 5, 7, 11, 37, 3, 221, 79, 895, 1023, 653, 3925, 12755, 19729, 18221, 91123}},
+{6896, 17, 9965, {1, 3, 1, 5, 23, 61, 119, 191, 425, 41, 853, 3497, 6915, 1927, 5513, 55303, 4895}},
+{6897, 17, 9978, {1, 3, 5, 3, 7, 35, 47, 243, 167, 821, 267, 2149, 5797, 6329, 32495, 51037, 18313}},
+{6898, 17, 9986, {1, 1, 7, 9, 23, 29, 79, 205, 115, 839, 1217, 479, 1601, 9681, 1, 35293, 28731}},
+{6899, 17, 9992, {1, 3, 3, 5, 31, 17, 31, 161, 35, 953, 377, 451, 7985, 11371, 15115, 60131, 27033}},
+{6900, 17, 9995, {1, 1, 3, 9, 15, 19, 43, 215, 327, 429, 145, 1837, 725, 14775, 10465, 7367, 21271}},
+{6901, 17, 10005, {1, 3, 7, 13, 31, 17, 85, 49, 487, 795, 1679, 599, 3783, 3195, 2683, 53475, 38603}},
+{6902, 17, 10026, {1, 1, 1, 7, 19, 11, 71, 143, 443, 199, 1117, 3445, 6429, 12037, 13751, 43609, 101563}},
+{6903, 17, 10031, {1, 3, 5, 7, 29, 63, 65, 87, 305, 721, 851, 2235, 4987, 3051, 23015, 1281, 15755}},
+{6904, 17, 10040, {1, 1, 3, 9, 17, 3, 57, 47, 223, 305, 1409, 235, 4379, 5779, 27695, 22535, 9387}},
+{6905, 17, 10051, {1, 1, 3, 11, 25, 33, 75, 141, 155, 699, 85, 1729, 2551, 7101, 7739, 18025, 100819}},
+{6906, 17, 10057, {1, 3, 3, 13, 5, 45, 63, 83, 141, 383, 1931, 3343, 7397, 4823, 28893, 41279, 67805}},
+{6907, 17, 10072, {1, 3, 5, 7, 19, 29, 97, 67, 177, 583, 1783, 4007, 5087, 805, 30999, 23197, 117553}},
+{6908, 17, 10096, {1, 3, 5, 1, 25, 41, 33, 109, 511, 449, 653, 995, 5881, 2163, 13689, 54385, 97419}},
+{6909, 17, 10102, {1, 3, 3, 13, 25, 17, 49, 77, 497, 659, 783, 3513, 3735, 3541, 573, 50237, 99247}},
+{6910, 17, 10105, {1, 3, 1, 7, 17, 13, 37, 169, 19, 965, 289, 455, 6855, 11233, 7553, 7007, 57389}},
+{6911, 17, 10115, {1, 1, 7, 11, 5, 15, 11, 177, 75, 243, 453, 3861, 3091, 4625, 12489, 11537, 74199}},
+{6912, 17, 10124, {1, 1, 5, 13, 17, 21, 23, 57, 343, 985, 1755, 3947, 3899, 11847, 19321, 62295, 51265}},
+{6913, 17, 10139, {1, 1, 3, 9, 19, 37, 31, 243, 433, 725, 535, 3733, 33, 7885, 1425, 41919, 66507}},
+{6914, 17, 10145, {1, 3, 5, 11, 15, 11, 25, 255, 93, 33, 71, 2389, 1855, 317, 12773, 13311, 81927}},
+{6915, 17, 10148, {1, 3, 1, 3, 7, 55, 21, 175, 357, 235, 1679, 931, 2051, 14213, 20539, 38049, 122513}},
+{6916, 17, 10157, {1, 1, 5, 15, 5, 51, 127, 79, 297, 135, 1423, 2783, 7229, 14451, 27619, 7299, 49189}},
+{6917, 17, 10158, {1, 1, 1, 3, 5, 13, 9, 209, 455, 483, 1745, 323, 789, 7645, 26373, 61659, 23671}},
+{6918, 17, 10163, {1, 1, 1, 9, 23, 63, 99, 91, 377, 275, 275, 3005, 1563, 5945, 23825, 33211, 52753}},
+{6919, 17, 10180, {1, 1, 1, 1, 31, 55, 31, 109, 481, 581, 771, 197, 6155, 3465, 8451, 25925, 41159}},
+{6920, 17, 10187, {1, 3, 7, 13, 5, 33, 113, 161, 265, 493, 1723, 513, 5111, 10177, 21755, 5321, 58831}},
+{6921, 17, 10198, {1, 1, 7, 1, 21, 33, 117, 183, 89, 689, 1253, 2215, 6565, 3079, 16343, 22427, 96447}},
+{6922, 17, 10208, {1, 1, 1, 5, 15, 61, 5, 139, 111, 463, 573, 1907, 4615, 14975, 5715, 51017, 69827}},
+{6923, 17, 10214, {1, 1, 1, 13, 3, 3, 117, 249, 25, 361, 1177, 2901, 1601, 11381, 18981, 44811, 47117}},
+{6924, 17, 10220, {1, 1, 5, 3, 29, 5, 49, 221, 247, 57, 553, 1889, 479, 15581, 7035, 7293, 53065}},
+{6925, 17, 10237, {1, 3, 3, 3, 15, 49, 91, 187, 213, 981, 1417, 211, 3719, 13693, 17671, 16691, 57147}},
+{6926, 17, 10238, {1, 1, 7, 9, 7, 17, 109, 185, 459, 769, 1783, 899, 885, 2291, 30023, 26315, 7337}},
+{6927, 17, 10241, {1, 1, 5, 11, 11, 31, 73, 191, 95, 25, 1953, 1387, 1077, 7547, 9661, 57739, 76799}},
+{6928, 17, 10244, {1, 1, 7, 13, 23, 41, 69, 177, 407, 699, 1055, 3653, 1239, 8113, 12823, 1803, 117815}},
+{6929, 17, 10251, {1, 1, 1, 15, 1, 55, 71, 133, 401, 593, 605, 2855, 4569, 3533, 14141, 65457, 125655}},
+{6930, 17, 10253, {1, 1, 7, 9, 31, 55, 53, 11, 65, 17, 561, 925, 1561, 8929, 19859, 57111, 12777}},
+{6931, 17, 10256, {1, 3, 3, 11, 7, 59, 125, 205, 473, 655, 1429, 337, 6829, 7551, 27873, 11667, 39231}},
+{6932, 17, 10259, {1, 3, 3, 9, 13, 23, 25, 161, 443, 545, 1967, 1895, 6929, 5975, 17801, 41769, 30429}},
+{6933, 17, 10266, {1, 3, 7, 13, 15, 1, 99, 43, 45, 451, 21, 639, 7121, 4781, 2813, 419, 17761}},
+{6934, 17, 10284, {1, 1, 5, 13, 11, 9, 53, 83, 443, 441, 1601, 3177, 1913, 12211, 25835, 1733, 4793}},
+{6935, 17, 10290, {1, 3, 3, 1, 13, 15, 11, 187, 471, 699, 1751, 3279, 2305, 15259, 31541, 21357, 73763}},
+{6936, 17, 10331, {1, 3, 5, 9, 23, 11, 125, 57, 261, 479, 879, 719, 3221, 2943, 10593, 11521, 83979}},
+{6937, 17, 10334, {1, 3, 7, 13, 3, 39, 119, 135, 85, 417, 1675, 971, 7577, 12709, 20407, 26105, 97021}},
+{6938, 17, 10350, {1, 1, 5, 11, 15, 63, 83, 141, 281, 663, 1745, 2775, 5605, 9127, 553, 7177, 115969}},
+{6939, 17, 10355, {1, 1, 7, 1, 19, 47, 7, 165, 87, 95, 361, 1879, 6351, 2861, 9103, 37489, 24525}},
+{6940, 17, 10357, {1, 3, 3, 11, 9, 21, 51, 149, 375, 967, 1583, 1427, 1223, 11611, 7481, 36619, 128429}},
+{6941, 17, 10367, {1, 1, 5, 1, 3, 31, 7, 217, 453, 565, 1517, 2847, 6937, 1197, 24339, 44311, 66843}},
+{6942, 17, 10368, {1, 1, 5, 3, 3, 17, 127, 59, 3, 905, 531, 1179, 3559, 5175, 24627, 60941, 129457}},
+{6943, 17, 10377, {1, 1, 1, 7, 15, 15, 1, 31, 373, 643, 279, 3831, 4881, 9763, 17641, 43219, 83109}},
+{6944, 17, 10388, {1, 3, 3, 9, 5, 21, 41, 71, 371, 201, 573, 1481, 3631, 10783, 6679, 1089, 117347}},
+{6945, 17, 10407, {1, 1, 7, 7, 5, 25, 73, 63, 173, 197, 147, 981, 1491, 1597, 11733, 14285, 74021}},
+{6946, 17, 10421, {1, 1, 5, 11, 17, 15, 3, 175, 391, 503, 1745, 319, 791, 5607, 18173, 37319, 92025}},
+{6947, 17, 10434, {1, 3, 1, 1, 9, 37, 43, 81, 439, 951, 805, 251, 4625, 15617, 13715, 62263, 3827}},
+{6948, 17, 10439, {1, 3, 1, 1, 25, 21, 67, 191, 499, 205, 1355, 105, 1637, 563, 22291, 9045, 6545}},
+{6949, 17, 10440, {1, 1, 5, 5, 9, 3, 75, 75, 287, 303, 1767, 1789, 3437, 4637, 9605, 2537, 64935}},
+{6950, 17, 10443, {1, 1, 3, 3, 1, 51, 27, 155, 375, 149, 885, 187, 1551, 13109, 27011, 57301, 41047}},
+{6951, 17, 10446, {1, 1, 7, 5, 21, 23, 1, 81, 163, 231, 2039, 1519, 1279, 15379, 25549, 6711, 81499}},
+{6952, 17, 10457, {1, 1, 3, 5, 3, 37, 71, 243, 165, 365, 379, 351, 4649, 4287, 13395, 30329, 78383}},
+{6953, 17, 10469, {1, 3, 1, 1, 25, 63, 27, 215, 223, 699, 2029, 3737, 5947, 7287, 20813, 4931, 19345}},
+{6954, 17, 10476, {1, 1, 3, 15, 21, 7, 25, 187, 219, 53, 1749, 1797, 3533, 14307, 53, 11095, 75469}},
+{6955, 17, 10479, {1, 1, 3, 13, 27, 31, 91, 121, 481, 291, 915, 535, 4291, 5271, 12181, 55921, 125917}},
+{6956, 17, 10481, {1, 3, 1, 1, 3, 29, 21, 251, 361, 747, 997, 2989, 1809, 7235, 17855, 31027, 100689}},
+{6957, 17, 10494, {1, 3, 7, 1, 21, 13, 49, 93, 183, 673, 881, 1931, 7009, 2565, 26021, 53815, 19807}},
+{6958, 17, 10501, {1, 1, 7, 13, 9, 23, 47, 237, 487, 843, 1357, 919, 1753, 903, 2911, 31527, 73027}},
+{6959, 17, 10505, {1, 1, 1, 1, 25, 33, 97, 241, 421, 375, 73, 2541, 6231, 14659, 15335, 5915, 110791}},
+{6960, 17, 10516, {1, 3, 3, 7, 21, 17, 97, 125, 7, 271, 167, 475, 4887, 1847, 30173, 25913, 36659}},
+{6961, 17, 10532, {1, 1, 3, 15, 15, 37, 67, 5, 463, 423, 823, 941, 1551, 14175, 15377, 6017, 118297}},
+{6962, 17, 10541, {1, 1, 1, 7, 31, 51, 71, 127, 73, 517, 881, 3205, 6219, 11213, 14783, 64275, 70033}},
+{6963, 17, 10547, {1, 3, 1, 5, 17, 17, 57, 107, 359, 999, 1415, 757, 4743, 7775, 14111, 20075, 73269}},
+{6964, 17, 10550, {1, 3, 5, 3, 21, 57, 87, 43, 307, 777, 717, 3329, 4159, 12545, 31355, 31329, 41377}},
+{6965, 17, 10591, {1, 3, 7, 15, 25, 43, 19, 147, 487, 517, 977, 3625, 2311, 14173, 15167, 56563, 110417}},
+{6966, 17, 10597, {1, 3, 3, 11, 23, 1, 67, 157, 461, 169, 231, 1977, 5657, 865, 711, 24213, 76895}},
+{6967, 17, 10602, {1, 1, 7, 13, 5, 37, 51, 165, 331, 97, 431, 3819, 1379, 12083, 27521, 19689, 100119}},
+{6968, 17, 10610, {1, 1, 7, 15, 29, 21, 59, 193, 397, 467, 951, 3037, 2955, 13235, 20981, 63865, 30069}},
+{6969, 17, 10619, {1, 3, 3, 5, 7, 49, 41, 143, 319, 71, 353, 2159, 3043, 15317, 24095, 12017, 64393}},
+{6970, 17, 10631, {1, 1, 5, 13, 25, 45, 57, 153, 311, 805, 953, 1763, 5655, 3961, 12085, 58761, 76533}},
+{6971, 17, 10646, {1, 1, 3, 15, 29, 19, 71, 107, 203, 221, 1173, 1597, 1179, 9649, 21659, 10463, 8195}},
+{6972, 17, 10655, {1, 1, 3, 9, 31, 29, 53, 151, 247, 577, 543, 459, 8141, 5613, 12029, 24199, 118603}},
+{6973, 17, 10665, {1, 3, 1, 5, 1, 55, 103, 23, 405, 5, 181, 3805, 1103, 13389, 6725, 48733, 99639}},
+{6974, 17, 10673, {1, 1, 5, 9, 1, 47, 115, 231, 151, 885, 427, 2849, 361, 12969, 705, 41711, 53587}},
+{6975, 17, 10674, {1, 1, 3, 11, 9, 3, 11, 231, 77, 775, 657, 2721, 3431, 11919, 10425, 29405, 91561}},
+{6976, 17, 10680, {1, 1, 1, 5, 5, 7, 79, 41, 181, 333, 963, 3117, 7703, 2259, 16671, 51139, 27997}},
+{6977, 17, 10693, {1, 3, 7, 7, 13, 55, 59, 157, 377, 711, 1475, 1509, 1375, 6825, 13729, 28613, 109199}},
+{6978, 17, 10700, {1, 3, 3, 3, 13, 11, 51, 1, 67, 609, 467, 2161, 7693, 9019, 1847, 27969, 74863}},
+{6979, 17, 10721, {1, 1, 3, 3, 11, 33, 87, 217, 239, 505, 1451, 2801, 1417, 695, 29883, 15877, 99969}},
+{6980, 17, 10727, {1, 3, 3, 5, 3, 61, 9, 171, 57, 547, 2003, 2335, 2259, 3205, 5639, 21721, 25893}},
+{6981, 17, 10746, {1, 3, 1, 3, 19, 15, 83, 69, 47, 897, 627, 2839, 7123, 8567, 14707, 13159, 125139}},
+{6982, 17, 10748, {1, 3, 7, 11, 1, 59, 53, 33, 135, 1009, 1829, 3011, 1245, 421, 28909, 45517, 55071}},
+{6983, 17, 10757, {1, 1, 5, 9, 3, 27, 11, 243, 235, 683, 1329, 3145, 2141, 14027, 3707, 5933, 51965}},
+{6984, 17, 10761, {1, 1, 5, 7, 13, 63, 79, 105, 27, 195, 1657, 3107, 1245, 1681, 29619, 10589, 78197}},
+{6985, 17, 10770, {1, 3, 3, 7, 21, 1, 5, 79, 73, 125, 1587, 3053, 5977, 10745, 28343, 39023, 56201}},
+{6986, 17, 10776, {1, 1, 3, 15, 23, 21, 39, 41, 173, 913, 1267, 1323, 2967, 1979, 16763, 53753, 21905}},
+{6987, 17, 10782, {1, 1, 5, 7, 11, 11, 117, 151, 409, 345, 1461, 1703, 687, 557, 31651, 35507, 54909}},
+{6988, 17, 10791, {1, 1, 1, 15, 15, 49, 55, 223, 289, 765, 1737, 1117, 3717, 15465, 31949, 55061, 97091}},
+{6989, 17, 10792, {1, 1, 5, 9, 21, 29, 99, 13, 119, 35, 1461, 61, 5155, 6785, 15957, 11295, 52203}},
+{6990, 17, 10805, {1, 3, 5, 7, 23, 39, 73, 161, 465, 715, 153, 3529, 2243, 13773, 16573, 26233, 130263}},
+{6991, 17, 10810, {1, 3, 7, 9, 11, 51, 5, 149, 501, 119, 2047, 3417, 3955, 15055, 31633, 473, 127305}},
+{6992, 17, 10832, {1, 1, 1, 9, 31, 57, 91, 119, 215, 11, 1013, 3969, 1285, 11521, 8039, 36737, 86365}},
+{6993, 17, 10835, {1, 1, 5, 3, 7, 17, 9, 27, 59, 883, 541, 3027, 6219, 1091, 2453, 38247, 21323}},
+{6994, 17, 10841, {1, 1, 1, 1, 25, 39, 55, 249, 61, 313, 467, 1763, 4067, 8367, 32431, 44463, 66439}},
+{6995, 17, 10842, {1, 3, 3, 1, 13, 3, 37, 209, 21, 653, 1971, 3649, 6165, 3789, 12793, 56327, 60351}},
+{6996, 17, 10847, {1, 1, 7, 9, 31, 33, 21, 51, 313, 631, 515, 1761, 4149, 2601, 12481, 25975, 94061}},
+{6997, 17, 10853, {1, 1, 7, 15, 3, 7, 55, 129, 297, 735, 779, 633, 3265, 11713, 3893, 61197, 113991}},
+{6998, 17, 10860, {1, 3, 5, 13, 1, 15, 27, 253, 435, 595, 1163, 2753, 7399, 15225, 26215, 59753, 74933}},
+{6999, 17, 10871, {1, 1, 7, 7, 15, 23, 111, 43, 467, 957, 1687, 2893, 2315, 2025, 1475, 9061, 101611}},
+{7000, 17, 10878, {1, 1, 3, 3, 29, 41, 53, 169, 125, 415, 361, 869, 3399, 8821, 18193, 38575, 73979}},
+{7001, 17, 10881, {1, 1, 1, 15, 3, 5, 27, 5, 293, 765, 1809, 1961, 955, 12441, 10915, 2363, 49617}},
+{7002, 17, 10888, {1, 1, 5, 15, 19, 11, 3, 91, 59, 323, 545, 1177, 7967, 2729, 14085, 3283, 79859}},
+{7003, 17, 10894, {1, 1, 7, 13, 11, 17, 29, 163, 295, 951, 311, 3471, 1339, 10719, 701, 32377, 41685}},
+{7004, 17, 10901, {1, 3, 5, 7, 21, 19, 81, 247, 495, 767, 251, 3455, 6383, 7221, 19943, 64865, 33193}},
+{7005, 17, 10915, {1, 1, 7, 15, 23, 41, 63, 195, 311, 619, 211, 743, 889, 7627, 12527, 15865, 40103}},
+{7006, 17, 10918, {1, 1, 3, 1, 23, 23, 57, 221, 153, 27, 939, 3949, 411, 6357, 31985, 939, 91001}},
+{7007, 17, 10922, {1, 3, 5, 15, 7, 5, 35, 135, 245, 921, 307, 823, 775, 4891, 24575, 53503, 48147}},
+{7008, 17, 10936, {1, 1, 5, 7, 9, 31, 23, 139, 477, 495, 287, 807, 1855, 8321, 13963, 52197, 78509}},
+{7009, 17, 10954, {1, 3, 3, 3, 29, 59, 33, 83, 211, 65, 623, 1269, 1745, 16383, 10759, 57199, 14035}},
+{7010, 17, 10968, {1, 3, 3, 15, 25, 55, 69, 171, 411, 937, 731, 2275, 2597, 4133, 5089, 50507, 39989}},
+{7011, 17, 10971, {1, 3, 1, 9, 5, 47, 51, 21, 171, 913, 233, 43, 2673, 471, 27077, 57039, 32579}},
+{7012, 17, 10973, {1, 3, 5, 3, 29, 35, 5, 105, 233, 379, 77, 1775, 2409, 4597, 19879, 12691, 49739}},
+{7013, 17, 10978, {1, 3, 7, 13, 17, 29, 117, 177, 163, 927, 45, 3227, 7263, 5551, 9219, 32101, 122473}},
+{7014, 17, 10998, {1, 1, 7, 5, 31, 39, 75, 147, 311, 991, 1431, 3821, 6891, 9637, 17887, 661, 23067}},
+{7015, 17, 11009, {1, 3, 5, 13, 31, 53, 69, 79, 153, 329, 207, 479, 2395, 6505, 29553, 52023, 31531}},
+{7016, 17, 11021, {1, 3, 1, 7, 15, 7, 87, 233, 25, 275, 981, 1207, 3083, 16349, 30185, 60611, 120607}},
+{7017, 17, 11029, {1, 1, 5, 3, 21, 7, 47, 173, 291, 965, 65, 545, 7465, 4471, 2249, 34281, 107217}},
+{7018, 17, 11030, {1, 1, 3, 11, 19, 53, 17, 243, 193, 297, 1937, 1513, 4979, 14867, 15497, 10049, 9135}},
+{7019, 17, 11034, {1, 3, 1, 3, 25, 39, 29, 63, 231, 145, 247, 1745, 3439, 8635, 26687, 18595, 67123}},
+{7020, 17, 11050, {1, 1, 7, 9, 29, 33, 89, 175, 429, 675, 891, 1739, 3567, 5453, 30427, 33671, 83395}},
+{7021, 17, 11063, {1, 3, 1, 5, 31, 25, 69, 237, 235, 307, 1217, 3805, 153, 13387, 6209, 14179, 128725}},
+{7022, 17, 11064, {1, 1, 3, 3, 19, 45, 117, 135, 67, 601, 369, 3369, 5505, 2049, 24099, 22515, 96575}},
+{7023, 17, 11077, {1, 1, 1, 3, 3, 45, 29, 255, 327, 77, 1103, 4067, 2875, 6487, 5903, 26625, 19631}},
+{7024, 17, 11078, {1, 3, 5, 1, 31, 63, 115, 7, 255, 855, 913, 1779, 7001, 14387, 26765, 51987, 3191}},
+{7025, 17, 11105, {1, 1, 3, 11, 15, 43, 71, 247, 303, 231, 445, 3963, 3699, 11851, 18941, 43465, 63431}},
+{7026, 17, 11106, {1, 1, 3, 5, 31, 33, 93, 127, 267, 399, 653, 1997, 5005, 14535, 4813, 64065, 2159}},
+{7027, 17, 11126, {1, 3, 7, 13, 31, 39, 61, 155, 141, 515, 1217, 161, 4309, 3697, 22445, 43599, 43329}},
+{7028, 17, 11129, {1, 3, 3, 3, 7, 51, 103, 147, 511, 971, 195, 3731, 6629, 12125, 12053, 34951, 60059}},
+{7029, 17, 11135, {1, 1, 5, 11, 21, 49, 99, 31, 55, 309, 1805, 2253, 7095, 15265, 28445, 54813, 48615}},
+{7030, 17, 11151, {1, 3, 1, 15, 9, 41, 61, 125, 65, 143, 1567, 3259, 6757, 653, 31601, 63127, 52179}},
+{7031, 17, 11159, {1, 1, 5, 3, 29, 5, 19, 197, 153, 447, 7, 1713, 469, 6043, 1259, 63641, 29171}},
+{7032, 17, 11165, {1, 3, 3, 7, 3, 41, 95, 245, 445, 15, 607, 565, 2361, 2673, 21077, 20153, 6199}},
+{7033, 17, 11176, {1, 1, 5, 1, 5, 59, 93, 127, 485, 663, 683, 635, 1599, 16377, 31819, 6539, 27789}},
+{7034, 17, 11179, {1, 3, 1, 3, 31, 3, 11, 215, 441, 1005, 1815, 3945, 5109, 5539, 23935, 62671, 90731}},
+{7035, 17, 11182, {1, 3, 3, 1, 13, 47, 19, 229, 191, 427, 1141, 2321, 7105, 1587, 26347, 63265, 23377}},
+{7036, 17, 11189, {1, 1, 5, 15, 31, 55, 61, 93, 89, 945, 1203, 3631, 4457, 15097, 32019, 41747, 46009}},
+{7037, 17, 11204, {1, 1, 5, 13, 5, 33, 69, 59, 93, 247, 503, 421, 1923, 9855, 9825, 14257, 98663}},
+{7038, 17, 11216, {1, 3, 1, 13, 27, 21, 91, 39, 131, 571, 1527, 2715, 2061, 627, 19705, 47165, 84345}},
+{7039, 17, 11232, {1, 1, 1, 7, 3, 3, 7, 251, 225, 959, 1017, 2423, 6163, 1549, 7473, 3193, 104259}},
+{7040, 17, 11235, {1, 3, 3, 1, 5, 5, 115, 221, 505, 649, 1525, 2459, 167, 1899, 23939, 29253, 122835}},
+{7041, 17, 11242, {1, 3, 1, 5, 15, 9, 123, 221, 133, 43, 31, 1211, 4737, 5001, 20065, 6369, 93865}},
+{7042, 17, 11250, {1, 1, 5, 11, 11, 5, 23, 29, 333, 133, 1469, 1895, 5879, 15599, 2131, 25005, 96271}},
+{7043, 17, 11264, {1, 1, 3, 11, 25, 11, 19, 57, 397, 645, 1233, 2433, 6371, 10577, 15489, 60709, 3957}},
+{7044, 17, 11273, {1, 3, 1, 1, 19, 3, 33, 131, 429, 835, 1363, 2213, 3185, 14385, 8831, 43159, 32975}},
+{7045, 17, 11282, {1, 1, 5, 5, 23, 11, 127, 139, 213, 259, 897, 1913, 5737, 1287, 26617, 4885, 30193}},
+{7046, 17, 11288, {1, 3, 5, 13, 3, 27, 99, 31, 11, 27, 1003, 2473, 7055, 12923, 4269, 41433, 90637}},
+{7047, 17, 11291, {1, 3, 1, 7, 17, 25, 95, 151, 199, 237, 207, 1879, 2943, 9845, 3765, 53533, 111191}},
+{7048, 17, 11293, {1, 3, 1, 9, 19, 27, 5, 249, 85, 185, 1883, 1401, 2041, 12721, 20593, 30993, 2601}},
+{7049, 17, 11318, {1, 3, 3, 9, 23, 1, 15, 133, 387, 779, 707, 2723, 4485, 989, 27125, 37295, 125319}},
+{7050, 17, 11321, {1, 1, 7, 3, 9, 41, 81, 151, 349, 941, 357, 3817, 7123, 10079, 27519, 107, 102281}},
+{7051, 17, 11329, {1, 1, 1, 1, 13, 5, 111, 167, 73, 85, 1185, 1213, 333, 153, 13101, 38087, 39389}},
+{7052, 17, 11336, {1, 3, 3, 15, 11, 41, 99, 231, 377, 539, 1335, 1059, 5373, 9611, 27927, 29801, 85749}},
+{7053, 17, 11339, {1, 3, 1, 9, 19, 37, 125, 27, 15, 699, 1867, 2711, 1589, 1675, 32007, 61339, 96919}},
+{7054, 17, 11342, {1, 3, 3, 3, 3, 27, 21, 159, 249, 783, 1517, 2923, 2609, 1207, 13705, 57371, 43603}},
+{7055, 17, 11356, {1, 1, 5, 15, 17, 55, 77, 1, 401, 897, 987, 345, 5283, 5827, 17755, 44371, 13253}},
+{7056, 17, 11383, {1, 3, 1, 7, 3, 3, 99, 237, 487, 405, 771, 3503, 1199, 4779, 26893, 45821, 46383}},
+{7057, 17, 11389, {1, 1, 7, 3, 9, 47, 81, 27, 459, 989, 1891, 3997, 4081, 4075, 15079, 65081, 125185}},
+{7058, 17, 11405, {1, 3, 5, 9, 25, 23, 71, 251, 251, 197, 353, 3553, 2165, 2953, 3733, 52369, 100641}},
+{7059, 17, 11411, {1, 1, 1, 5, 25, 43, 63, 187, 495, 345, 1547, 2293, 7327, 7797, 14001, 61865, 40329}},
+{7060, 17, 11423, {1, 1, 5, 15, 25, 37, 67, 23, 315, 801, 71, 1235, 7293, 7207, 30929, 9417, 94735}},
+{7061, 17, 11424, {1, 1, 1, 3, 23, 29, 87, 171, 337, 457, 1597, 3933, 4151, 1237, 19563, 56997, 81497}},
+{7062, 17, 11430, {1, 3, 3, 11, 3, 33, 79, 239, 277, 611, 205, 2283, 7459, 425, 21999, 26491, 58681}},
+{7063, 17, 11444, {1, 1, 7, 1, 5, 37, 53, 93, 205, 97, 779, 3623, 7777, 521, 21915, 46539, 128811}},
+{7064, 17, 11447, {1, 1, 5, 7, 19, 7, 39, 183, 299, 193, 1351, 3867, 5709, 11655, 1231, 15555, 128023}},
+{7065, 17, 11459, {1, 3, 7, 11, 31, 13, 113, 57, 197, 841, 921, 2087, 2195, 8279, 8353, 1955, 22121}},
+{7066, 17, 11465, {1, 3, 3, 11, 21, 55, 61, 105, 357, 747, 363, 3511, 2547, 16283, 25747, 56041, 33695}},
+{7067, 17, 11473, {1, 3, 3, 13, 27, 13, 5, 27, 93, 691, 1869, 2331, 3131, 14411, 2355, 37195, 129273}},
+{7068, 17, 11479, {1, 3, 3, 7, 27, 9, 11, 165, 435, 811, 215, 1617, 347, 4289, 29373, 15749, 91445}},
+{7069, 17, 11501, {1, 1, 7, 13, 29, 3, 95, 53, 457, 633, 959, 3705, 7461, 9307, 21963, 51599, 6751}},
+{7070, 17, 11510, {1, 1, 1, 15, 29, 25, 95, 1, 125, 61, 683, 2067, 6485, 9095, 5571, 61281, 70865}},
+{7071, 17, 11514, {1, 1, 7, 7, 1, 35, 119, 107, 247, 991, 237, 1865, 3961, 12583, 11417, 14913, 90897}},
+{7072, 17, 11522, {1, 3, 7, 15, 11, 51, 73, 193, 289, 381, 1767, 3803, 3197, 3797, 15059, 19393, 98947}},
+{7073, 17, 11527, {1, 1, 5, 3, 13, 7, 91, 223, 347, 59, 1721, 1501, 6391, 4141, 14495, 47283, 47237}},
+{7074, 17, 11533, {1, 3, 7, 11, 17, 39, 43, 247, 35, 423, 1859, 3199, 5343, 7061, 8609, 6819, 88575}},
+{7075, 17, 11536, {1, 1, 5, 13, 31, 27, 57, 19, 499, 1007, 1965, 795, 1231, 12755, 24631, 53343, 82305}},
+{7076, 17, 11548, {1, 1, 1, 9, 13, 23, 127, 161, 245, 467, 2025, 2545, 3085, 13035, 27087, 14461, 35971}},
+{7077, 17, 11551, {1, 3, 5, 1, 7, 3, 99, 159, 75, 341, 1755, 2337, 5981, 5055, 19445, 30043, 61427}},
+{7078, 17, 11552, {1, 1, 1, 7, 13, 33, 41, 73, 267, 21, 961, 3509, 6839, 13215, 8471, 46735, 93071}},
+{7079, 17, 11555, {1, 3, 7, 7, 3, 25, 81, 239, 357, 445, 1483, 389, 3891, 5131, 21357, 34757, 111063}},
+{7080, 17, 11572, {1, 3, 7, 1, 1, 37, 119, 121, 195, 935, 1711, 2049, 7001, 7117, 9957, 7309, 102293}},
+{7081, 17, 11587, {1, 1, 7, 11, 1, 49, 107, 95, 149, 329, 289, 1121, 7217, 15091, 19071, 13801, 13}},
+{7082, 17, 11601, {1, 1, 1, 13, 17, 17, 7, 105, 81, 1017, 1867, 1567, 5133, 7325, 19797, 16301, 40471}},
+{7083, 17, 11613, {1, 3, 5, 5, 27, 45, 117, 135, 499, 53, 973, 121, 53, 8771, 11893, 35827, 57691}},
+{7084, 17, 11614, {1, 1, 1, 1, 7, 23, 11, 163, 17, 871, 129, 2959, 5583, 12253, 1419, 28367, 32539}},
+{7085, 17, 11618, {1, 1, 3, 5, 23, 31, 127, 33, 115, 799, 331, 1873, 1729, 1383, 23601, 51145, 72027}},
+{7086, 17, 11624, {1, 1, 1, 9, 15, 49, 105, 163, 51, 539, 451, 3983, 6509, 1073, 30757, 13971, 51371}},
+{7087, 17, 11630, {1, 1, 7, 1, 1, 57, 71, 135, 5, 171, 983, 951, 777, 9257, 3607, 3239, 76237}},
+{7088, 17, 11663, {1, 1, 7, 7, 21, 17, 49, 175, 9, 807, 289, 2777, 7309, 14911, 28349, 43871, 96019}},
+{7089, 17, 11682, {1, 3, 1, 13, 5, 7, 83, 215, 297, 319, 347, 633, 7285, 8293, 18811, 31065, 114077}},
+{7090, 17, 11684, {1, 3, 1, 11, 3, 29, 91, 231, 161, 601, 355, 2719, 2941, 6065, 21849, 58051, 46515}},
+{7091, 17, 11702, {1, 1, 3, 9, 25, 41, 111, 135, 71, 755, 29, 131, 1339, 5053, 15713, 14557, 106777}},
+{7092, 17, 11705, {1, 1, 7, 13, 21, 59, 13, 45, 503, 71, 1611, 4021, 2359, 11653, 7261, 14537, 33031}},
+{7093, 17, 11713, {1, 1, 1, 11, 5, 31, 1, 181, 37, 527, 1345, 1979, 4899, 3289, 25181, 49959, 44609}},
+{7094, 17, 11731, {1, 3, 3, 13, 21, 25, 33, 105, 57, 637, 841, 1595, 3881, 5053, 9441, 58717, 127255}},
+{7095, 17, 11734, {1, 3, 5, 7, 23, 57, 9, 117, 281, 769, 1573, 2857, 1139, 6413, 14001, 21097, 55215}},
+{7096, 17, 11740, {1, 1, 7, 7, 3, 5, 75, 149, 269, 353, 437, 61, 2451, 11987, 17243, 5649, 105107}},
+{7097, 17, 11747, {1, 1, 3, 3, 25, 61, 53, 21, 113, 57, 1415, 2825, 11, 14977, 6159, 4181, 96765}},
+{7098, 17, 11754, {1, 1, 7, 5, 15, 25, 121, 159, 71, 773, 601, 147, 6507, 16171, 16607, 32017, 77845}},
+{7099, 17, 11761, {1, 3, 1, 1, 27, 19, 59, 109, 347, 991, 165, 683, 6147, 493, 22017, 19069, 52857}},
+{7100, 17, 11762, {1, 1, 5, 5, 21, 1, 93, 115, 407, 15, 421, 1305, 3495, 14287, 31831, 65347, 35339}},
+{7101, 17, 11787, {1, 3, 5, 11, 29, 35, 87, 27, 453, 769, 1991, 2757, 2607, 9225, 293, 49441, 18185}},
+{7102, 17, 11792, {1, 1, 5, 3, 23, 41, 67, 195, 499, 903, 197, 1121, 4691, 9277, 29225, 34597, 37395}},
+{7103, 17, 11814, {1, 1, 7, 7, 21, 7, 65, 245, 241, 909, 1063, 2271, 1979, 10287, 1747, 61523, 72969}},
+{7104, 17, 11823, {1, 3, 1, 13, 23, 25, 3, 89, 385, 481, 1463, 3431, 6907, 1129, 3519, 35789, 82585}},
+{7105, 17, 11825, {1, 3, 5, 3, 31, 17, 11, 209, 77, 991, 885, 3341, 6895, 3429, 21611, 38555, 35475}},
+{7106, 17, 11837, {1, 1, 3, 1, 9, 61, 27, 219, 433, 787, 281, 1155, 2915, 4449, 30881, 34461, 15357}},
+{7107, 17, 11838, {1, 1, 3, 15, 27, 55, 51, 101, 117, 799, 1475, 4013, 5145, 14991, 27847, 49537, 57339}},
+{7108, 17, 11846, {1, 3, 7, 13, 13, 9, 13, 167, 283, 883, 1501, 2635, 1463, 3353, 14961, 30349, 62043}},
+{7109, 17, 11855, {1, 1, 7, 3, 3, 47, 119, 37, 389, 655, 701, 2471, 5749, 6645, 845, 27065, 82299}},
+{7110, 17, 11864, {1, 1, 7, 15, 27, 5, 95, 195, 227, 991, 1137, 3715, 4901, 9459, 1917, 43857, 126505}},
+{7111, 17, 11876, {1, 3, 7, 5, 29, 35, 45, 165, 361, 257, 641, 1265, 6533, 11333, 26081, 12621, 66909}},
+{7112, 17, 11885, {1, 1, 1, 11, 19, 55, 73, 137, 29, 355, 725, 1161, 6717, 2035, 19769, 43531, 72577}},
+{7113, 17, 11904, {1, 3, 7, 5, 19, 3, 99, 17, 387, 621, 137, 117, 6567, 7667, 14979, 17981, 68319}},
+{7114, 17, 11909, {1, 1, 5, 5, 7, 53, 31, 33, 245, 371, 691, 2763, 95, 16369, 7853, 29839, 34957}},
+{7115, 17, 11913, {1, 1, 3, 1, 9, 1, 83, 177, 17, 141, 1739, 1791, 3849, 3093, 22271, 53755, 7817}},
+{7116, 17, 11916, {1, 3, 3, 1, 3, 51, 71, 69, 439, 987, 807, 3353, 4747, 16031, 29591, 61091, 95675}},
+{7117, 17, 11940, {1, 3, 5, 1, 17, 47, 51, 211, 7, 5, 1751, 1735, 1647, 13389, 13861, 49427, 13577}},
+{7118, 17, 11943, {1, 3, 7, 5, 11, 23, 17, 55, 11, 61, 809, 927, 6533, 1509, 29261, 21555, 55075}},
+{7119, 17, 11972, {1, 3, 1, 1, 15, 51, 37, 47, 183, 117, 597, 3225, 1435, 13359, 19127, 17339, 17345}},
+{7120, 17, 11981, {1, 1, 5, 3, 5, 11, 33, 179, 295, 129, 29, 713, 1561, 27, 21087, 50305, 39253}},
+{7121, 17, 11990, {1, 1, 5, 7, 17, 25, 105, 241, 41, 915, 1223, 2625, 617, 10983, 10749, 2137, 101831}},
+{7122, 17, 11993, {1, 3, 5, 7, 15, 15, 85, 23, 193, 625, 1803, 2903, 1935, 523, 8377, 12165, 105851}},
+{7123, 17, 12000, {1, 3, 3, 7, 3, 35, 5, 107, 191, 855, 405, 1659, 5523, 5011, 6401, 45187, 31345}},
+{7124, 17, 12005, {1, 3, 3, 1, 9, 21, 103, 75, 501, 669, 547, 3685, 411, 2663, 14743, 13869, 124389}},
+{7125, 17, 12015, {1, 3, 5, 13, 15, 37, 39, 79, 19, 165, 1685, 1367, 5951, 12303, 13423, 51083, 119933}},
+{7126, 17, 12020, {1, 1, 3, 1, 7, 25, 1, 221, 415, 591, 859, 1457, 1789, 2269, 15947, 31913, 86397}},
+{7127, 17, 12038, {1, 3, 7, 15, 11, 49, 15, 171, 45, 925, 407, 1719, 4505, 5695, 17397, 28849, 77}},
+{7128, 17, 12042, {1, 1, 3, 11, 21, 33, 91, 115, 263, 141, 753, 3335, 7695, 1981, 6029, 22629, 2467}},
+{7129, 17, 12056, {1, 3, 5, 3, 25, 5, 21, 67, 429, 323, 223, 2395, 761, 14817, 12387, 37905, 19551}},
+{7130, 17, 12065, {1, 3, 1, 15, 31, 43, 35, 255, 73, 533, 1093, 965, 557, 607, 6913, 35283, 12261}},
+{7131, 17, 12066, {1, 3, 1, 15, 25, 13, 39, 83, 77, 269, 1205, 1577, 4095, 6669, 8643, 48807, 98227}},
+{7132, 17, 12072, {1, 3, 3, 7, 31, 57, 25, 177, 441, 973, 1255, 675, 5579, 4899, 27925, 52555, 70845}},
+{7133, 17, 12080, {1, 3, 1, 5, 13, 47, 15, 75, 387, 461, 1909, 841, 7, 9567, 913, 41411, 12565}},
+{7134, 17, 12083, {1, 1, 5, 7, 5, 21, 17, 189, 319, 645, 403, 2723, 6747, 15471, 26533, 12709, 49417}},
+{7135, 17, 12090, {1, 1, 5, 7, 7, 41, 99, 179, 137, 435, 1061, 3987, 4583, 4101, 23781, 54263, 36695}},
+{7136, 17, 12092, {1, 3, 1, 11, 19, 37, 125, 177, 111, 921, 1003, 1433, 1399, 3991, 28193, 40471, 97041}},
+{7137, 17, 12103, {1, 1, 7, 1, 5, 33, 7, 139, 127, 413, 1171, 2237, 265, 10145, 18793, 28957, 25037}},
+{7138, 17, 12109, {1, 3, 1, 1, 25, 37, 13, 17, 471, 195, 1645, 3165, 5635, 8433, 28507, 453, 107709}},
+{7139, 17, 12112, {1, 3, 3, 11, 1, 55, 119, 97, 243, 371, 95, 97, 7833, 777, 12177, 1861, 56323}},
+{7140, 17, 12117, {1, 1, 7, 5, 7, 29, 59, 219, 405, 411, 275, 111, 4899, 10367, 24331, 57295, 47065}},
+{7141, 17, 12121, {1, 1, 3, 3, 19, 23, 91, 111, 221, 195, 1013, 3001, 3227, 6359, 30383, 49699, 49157}},
+{7142, 17, 12137, {1, 1, 5, 7, 1, 21, 125, 23, 177, 291, 249, 861, 1899, 14101, 5079, 5211, 14373}},
+{7143, 17, 12143, {1, 1, 7, 11, 11, 59, 33, 41, 291, 919, 253, 609, 1657, 14633, 15189, 22245, 99815}},
+{7144, 17, 12145, {1, 3, 5, 3, 23, 49, 71, 137, 393, 343, 1845, 343, 5853, 6639, 17435, 62143, 76041}},
+{7145, 17, 12148, {1, 1, 5, 3, 9, 27, 55, 193, 25, 965, 1453, 2739, 3785, 12497, 29607, 11111, 25145}},
+{7146, 17, 12168, {1, 1, 1, 1, 29, 11, 111, 73, 491, 629, 405, 2779, 5313, 589, 1459, 47555, 67945}},
+{7147, 17, 12174, {1, 3, 1, 7, 13, 21, 99, 75, 79, 963, 207, 1725, 6875, 8359, 10573, 45219, 130463}},
+{7148, 17, 12188, {1, 3, 7, 13, 1, 17, 105, 227, 487, 891, 1053, 1333, 7651, 5415, 18661, 22085, 82055}},
+{7149, 17, 12191, {1, 1, 3, 3, 31, 27, 91, 93, 383, 331, 965, 3035, 4931, 13265, 9729, 28985, 118227}},
+{7150, 17, 12192, {1, 3, 1, 1, 11, 9, 59, 191, 253, 909, 301, 3811, 255, 14937, 28627, 54509, 95993}},
+{7151, 17, 12201, {1, 3, 3, 5, 11, 5, 105, 77, 323, 713, 637, 1857, 2697, 12473, 12261, 2933, 101287}},
+{7152, 17, 12224, {1, 3, 3, 11, 9, 63, 19, 19, 213, 859, 1479, 2849, 1067, 5749, 13511, 14933, 11125}},
+{7153, 17, 12230, {1, 1, 5, 9, 19, 19, 13, 49, 237, 511, 533, 543, 575, 8095, 27335, 18847, 18173}},
+{7154, 17, 12239, {1, 3, 5, 5, 9, 53, 47, 157, 35, 827, 637, 2327, 787, 5269, 5145, 10135, 111273}},
+{7155, 17, 12242, {1, 3, 3, 7, 27, 41, 69, 173, 53, 655, 809, 481, 6999, 3101, 20781, 2481, 94957}},
+{7156, 17, 12251, {1, 1, 5, 11, 17, 23, 95, 201, 363, 613, 863, 1365, 1131, 15417, 20705, 8283, 55235}},
+{7157, 17, 12258, {1, 1, 5, 13, 3, 15, 37, 219, 291, 595, 1665, 1861, 1953, 15385, 20569, 46085, 15163}},
+{7158, 17, 12264, {1, 3, 3, 11, 23, 43, 125, 133, 85, 45, 819, 243, 7325, 8723, 1499, 58139, 120353}},
+{7159, 17, 12310, {1, 1, 1, 11, 21, 49, 91, 145, 175, 619, 1817, 3533, 8155, 7521, 30361, 45431, 130175}},
+{7160, 17, 12319, {1, 1, 3, 1, 11, 59, 57, 51, 37, 903, 1221, 3813, 8043, 14165, 31503, 7905, 61515}},
+{7161, 17, 12323, {1, 1, 1, 1, 15, 9, 115, 175, 285, 839, 97, 3119, 719, 15283, 22947, 25417, 40665}},
+{7162, 17, 12325, {1, 3, 1, 7, 5, 49, 127, 111, 373, 747, 393, 2351, 4577, 15227, 23149, 16901, 80253}},
+{7163, 17, 12332, {1, 1, 5, 3, 15, 5, 95, 197, 251, 275, 831, 1389, 3907, 12343, 11599, 24369, 65361}},
+{7164, 17, 12343, {1, 3, 7, 5, 25, 37, 11, 75, 417, 789, 745, 811, 2189, 15381, 4785, 41657, 2897}},
+{7165, 17, 12344, {1, 3, 1, 13, 29, 55, 55, 33, 279, 383, 1645, 975, 4683, 1357, 1149, 30271, 90527}},
+{7166, 17, 12352, {1, 3, 5, 3, 5, 3, 79, 61, 371, 225, 141, 369, 1037, 12249, 29431, 37253, 9899}},
+{7167, 17, 12370, {1, 1, 3, 13, 13, 7, 127, 147, 507, 119, 1085, 1949, 6289, 10179, 10107, 55989, 74395}},
+{7168, 17, 12388, {1, 3, 1, 7, 21, 35, 53, 209, 103, 365, 683, 553, 4977, 14371, 24037, 11453, 45369}},
+{7169, 17, 12395, {1, 1, 5, 11, 27, 39, 41, 145, 437, 55, 893, 2375, 4977, 5451, 21225, 46815, 1423}},
+{7170, 17, 12403, {1, 3, 5, 1, 23, 53, 113, 75, 209, 323, 1975, 3809, 1829, 14625, 3821, 53773, 129173}},
+{7171, 17, 12409, {1, 1, 5, 3, 7, 51, 97, 73, 289, 481, 339, 1375, 3101, 4395, 13933, 33267, 68115}},
+{7172, 17, 12410, {1, 3, 5, 1, 5, 45, 83, 57, 3, 667, 109, 3979, 6447, 8603, 20147, 49291, 18023}},
+{7173, 17, 12415, {1, 3, 7, 1, 11, 7, 45, 233, 65, 745, 1009, 2979, 5965, 10681, 3499, 23077, 87479}},
+{7174, 17, 12419, {1, 3, 3, 3, 13, 25, 25, 189, 197, 83, 1429, 2857, 2877, 8577, 24811, 33049, 46009}},
+{7175, 17, 12426, {1, 1, 1, 7, 11, 47, 47, 255, 89, 625, 449, 3747, 2035, 3509, 4901, 2961, 14073}},
+{7176, 17, 12439, {1, 1, 1, 13, 9, 55, 35, 47, 389, 573, 847, 1037, 1345, 5487, 7575, 57435, 77303}},
+{7177, 17, 12445, {1, 1, 5, 11, 25, 51, 113, 109, 79, 339, 95, 2049, 5881, 13209, 20041, 26419, 110319}},
+{7178, 17, 12459, {1, 1, 7, 1, 27, 15, 93, 145, 253, 917, 1211, 2221, 1087, 14209, 32097, 20083, 67841}},
+{7179, 17, 12464, {1, 1, 3, 15, 13, 19, 67, 107, 75, 919, 2047, 3675, 6231, 1243, 14335, 35939, 17281}},
+{7180, 17, 12474, {1, 3, 7, 5, 27, 47, 53, 239, 475, 231, 1645, 825, 4039, 15985, 10853, 32951, 34985}},
+{7181, 17, 12484, {1, 1, 7, 5, 15, 61, 107, 93, 51, 221, 717, 2859, 7885, 9571, 11841, 45143, 33723}},
+{7182, 17, 12491, {1, 1, 7, 7, 9, 25, 63, 25, 47, 55, 2041, 3965, 215, 14857, 31669, 54775, 42157}},
+{7183, 17, 12501, {1, 3, 5, 1, 5, 45, 123, 109, 471, 599, 479, 475, 3499, 11963, 23709, 18851, 66861}},
+{7184, 17, 12505, {1, 3, 3, 3, 5, 29, 71, 81, 315, 329, 1471, 3995, 623, 5871, 11171, 15645, 97251}},
+{7185, 17, 12508, {1, 1, 7, 11, 15, 15, 101, 173, 445, 871, 765, 1121, 1937, 13055, 7309, 54175, 85559}},
+{7186, 17, 12511, {1, 3, 5, 7, 7, 13, 43, 237, 361, 981, 19, 3113, 4681, 3313, 19147, 35193, 87281}},
+{7187, 17, 12521, {1, 3, 5, 3, 27, 13, 37, 51, 233, 573, 1599, 2807, 7149, 12083, 28927, 7797, 130879}},
+{7188, 17, 12522, {1, 1, 1, 13, 31, 63, 127, 89, 209, 717, 1075, 3887, 1427, 87, 18565, 39973, 55025}},
+{7189, 17, 12530, {1, 3, 1, 5, 15, 11, 121, 247, 273, 613, 1857, 2059, 7399, 13951, 9025, 39523, 68121}},
+{7190, 17, 12544, {1, 3, 7, 13, 31, 9, 61, 143, 375, 433, 471, 1315, 5299, 1167, 10099, 11445, 51693}},
+{7191, 17, 12547, {1, 1, 7, 9, 25, 31, 125, 5, 13, 595, 621, 3551, 7959, 10643, 14345, 37683, 118377}},
+{7192, 17, 12561, {1, 1, 5, 11, 1, 33, 45, 31, 447, 229, 893, 3777, 4101, 2505, 4855, 14057, 20133}},
+{7193, 17, 12571, {1, 1, 1, 1, 7, 23, 89, 53, 483, 873, 521, 2115, 1461, 11241, 1003, 28749, 68227}},
+{7194, 17, 12580, {1, 3, 5, 5, 3, 17, 23, 219, 281, 975, 895, 4043, 6505, 5991, 27401, 38791, 89239}},
+{7195, 17, 12597, {1, 1, 1, 7, 29, 41, 63, 151, 195, 495, 469, 305, 7437, 1107, 31147, 30755, 116551}},
+{7196, 17, 12607, {1, 3, 7, 3, 13, 25, 33, 193, 23, 135, 3, 513, 4169, 15355, 2255, 32167, 68691}},
+{7197, 17, 12609, {1, 3, 3, 11, 29, 19, 125, 177, 83, 361, 393, 663, 1859, 1333, 17507, 10661, 72387}},
+{7198, 17, 12610, {1, 1, 5, 11, 23, 13, 61, 33, 149, 145, 995, 649, 7587, 6743, 25225, 54997, 10193}},
+{7199, 17, 12616, {1, 1, 7, 13, 29, 51, 107, 79, 467, 881, 1227, 1083, 3277, 2559, 26819, 57311, 48095}},
+{7200, 17, 12621, {1, 3, 1, 1, 1, 19, 23, 25, 239, 703, 119, 2525, 8079, 5433, 8989, 42517, 116755}},
+{7201, 17, 12624, {1, 1, 7, 11, 31, 9, 9, 113, 381, 363, 447, 3751, 7523, 15995, 3853, 42069, 81455}},
+{7202, 17, 12639, {1, 1, 5, 9, 29, 41, 103, 179, 477, 527, 1593, 3003, 1095, 6823, 6911, 44987, 32445}},
+{7203, 17, 12645, {1, 1, 7, 15, 5, 31, 55, 181, 149, 127, 1745, 2753, 801, 285, 20199, 33707, 118397}},
+{7204, 17, 12652, {1, 3, 7, 7, 11, 29, 89, 215, 351, 303, 1519, 2593, 2045, 14699, 1657, 40799, 39641}},
+{7205, 17, 12655, {1, 1, 7, 13, 3, 35, 73, 111, 15, 803, 1819, 3453, 3611, 8337, 14239, 14875, 83983}},
+{7206, 17, 12660, {1, 1, 5, 15, 15, 49, 27, 101, 149, 3, 717, 2229, 7397, 6579, 10965, 35997, 28823}},
+{7207, 17, 12667, {1, 1, 5, 7, 3, 17, 49, 245, 343, 657, 15, 749, 6413, 10811, 2909, 47309, 34613}},
+{7208, 17, 12686, {1, 3, 5, 15, 13, 35, 67, 99, 481, 379, 2003, 3367, 3065, 5845, 7799, 43931, 15263}},
+{7209, 17, 12688, {1, 1, 5, 13, 21, 49, 81, 77, 395, 919, 1931, 661, 123, 9965, 10487, 55131, 1567}},
+{7210, 17, 12697, {1, 3, 5, 11, 23, 39, 41, 121, 159, 473, 191, 1983, 6411, 10503, 10523, 40601, 64153}},
+{7211, 17, 12700, {1, 1, 5, 7, 9, 37, 73, 207, 497, 789, 1671, 325, 1697, 11281, 31185, 4961, 124431}},
+{7212, 17, 12707, {1, 1, 5, 15, 7, 51, 71, 91, 449, 707, 621, 2427, 627, 1747, 12779, 17569, 98289}},
+{7213, 17, 12710, {1, 1, 5, 5, 31, 3, 89, 163, 77, 647, 1747, 2965, 1669, 3311, 17651, 8111, 30739}},
+{7214, 17, 12719, {1, 1, 3, 11, 15, 31, 77, 173, 405, 913, 459, 2955, 6153, 13391, 20439, 64433, 12371}},
+{7215, 17, 12739, {1, 1, 3, 11, 13, 55, 29, 37, 379, 689, 407, 1373, 397, 5027, 15497, 25687, 48193}},
+{7216, 17, 12742, {1, 3, 3, 15, 13, 7, 81, 207, 395, 901, 779, 1683, 2491, 3807, 31979, 32403, 81113}},
+{7217, 17, 12746, {1, 3, 3, 13, 29, 31, 25, 81, 459, 991, 793, 3285, 2775, 16199, 11423, 52597, 86041}},
+{7218, 17, 12754, {1, 3, 3, 13, 17, 17, 101, 183, 19, 735, 671, 1097, 2461, 9863, 25985, 31915, 73047}},
+{7219, 17, 12765, {1, 3, 3, 3, 3, 11, 71, 63, 429, 899, 351, 1275, 3907, 14241, 19135, 14875, 43325}},
+{7220, 17, 12772, {1, 1, 7, 11, 11, 61, 15, 213, 411, 13, 1409, 1741, 5257, 8729, 28351, 6381, 77501}},
+{7221, 17, 12784, {1, 1, 7, 7, 29, 27, 51, 217, 411, 261, 599, 3027, 7871, 9133, 32423, 44275, 34701}},
+{7222, 17, 12789, {1, 3, 7, 7, 1, 1, 127, 209, 151, 845, 1421, 3115, 7775, 10133, 6163, 41165, 91187}},
+{7223, 17, 12800, {1, 3, 1, 9, 1, 35, 75, 3, 81, 477, 131, 1383, 1377, 6857, 3863, 12583, 7855}},
+{7224, 17, 12805, {1, 3, 1, 3, 3, 11, 1, 167, 347, 317, 557, 3763, 7175, 13341, 759, 23275, 78039}},
+{7225, 17, 12809, {1, 3, 5, 11, 19, 53, 85, 139, 67, 757, 487, 919, 6001, 16031, 24959, 28013, 65771}},
+{7226, 17, 12815, {1, 1, 1, 1, 23, 9, 83, 55, 249, 305, 1305, 109, 5559, 5129, 30973, 19889, 6691}},
+{7227, 17, 12827, {1, 1, 1, 3, 21, 19, 85, 89, 213, 847, 861, 1651, 6613, 6001, 8157, 2555, 98673}},
+{7228, 17, 12830, {1, 1, 1, 15, 25, 15, 125, 133, 177, 295, 549, 1763, 2811, 4381, 1079, 7813, 87909}},
+{7229, 17, 12833, {1, 1, 1, 5, 5, 17, 25, 225, 353, 997, 1565, 2225, 7265, 16227, 28209, 9011, 97193}},
+{7230, 17, 12840, {1, 3, 7, 15, 13, 13, 35, 239, 331, 965, 1547, 1627, 6409, 7745, 30899, 36915, 59293}},
+{7231, 17, 12851, {1, 1, 1, 13, 27, 45, 23, 179, 193, 801, 381, 3783, 3551, 11855, 11041, 49911, 62101}},
+{7232, 17, 12868, {1, 1, 7, 3, 3, 31, 61, 5, 421, 939, 1637, 217, 389, 1797, 32141, 28817, 6997}},
+{7233, 17, 12871, {1, 3, 3, 5, 21, 31, 83, 65, 421, 577, 1137, 2561, 2943, 4171, 2803, 23325, 92315}},
+{7234, 17, 12886, {1, 1, 3, 3, 27, 33, 75, 81, 477, 3, 1903, 773, 5551, 10069, 7285, 58103, 98311}},
+{7235, 17, 12899, {1, 3, 7, 15, 1, 17, 95, 209, 65, 747, 1633, 581, 7395, 1393, 21795, 15735, 129757}},
+{7236, 17, 12923, {1, 3, 5, 3, 17, 3, 9, 131, 51, 693, 1571, 1865, 8137, 915, 13345, 35137, 59005}},
+{7237, 17, 12926, {1, 1, 3, 7, 23, 27, 61, 163, 449, 87, 717, 1075, 4309, 4887, 11741, 24549, 96729}},
+{7238, 17, 12932, {1, 3, 7, 13, 21, 5, 3, 97, 191, 999, 1193, 1215, 5907, 10491, 2281, 6455, 68625}},
+{7239, 17, 12935, {1, 1, 5, 7, 9, 9, 101, 5, 375, 137, 1473, 1265, 5307, 259, 20699, 25367, 129393}},
+{7240, 17, 12939, {1, 3, 7, 7, 21, 1, 77, 65, 23, 139, 945, 491, 1069, 253, 12335, 26861, 129467}},
+{7241, 17, 12942, {1, 1, 3, 9, 15, 33, 85, 225, 45, 311, 281, 1601, 7325, 12265, 2591, 51955, 130681}},
+{7242, 17, 12953, {1, 1, 1, 3, 27, 33, 17, 89, 495, 91, 527, 3347, 7883, 9481, 28731, 54729, 15265}},
+{7243, 17, 12959, {1, 1, 3, 3, 9, 47, 115, 161, 299, 493, 1857, 3597, 7175, 15603, 11523, 33837, 57557}},
+{7244, 17, 12960, {1, 3, 7, 3, 15, 47, 127, 195, 391, 869, 99, 429, 7125, 10413, 5063, 61845, 71843}},
+{7245, 17, 13002, {1, 3, 3, 1, 7, 31, 27, 69, 7, 83, 315, 2749, 5693, 13377, 28091, 13065, 111029}},
+{7246, 17, 13004, {1, 1, 3, 15, 15, 45, 125, 229, 459, 611, 1167, 3375, 3587, 81, 9275, 45327, 39749}},
+{7247, 17, 13016, {1, 3, 7, 11, 9, 3, 43, 161, 221, 209, 51, 1475, 3577, 13973, 15285, 35553, 83935}},
+{7248, 17, 13021, {1, 1, 7, 9, 15, 55, 25, 119, 39, 537, 317, 1331, 2161, 1791, 19221, 63459, 124595}},
+{7249, 17, 13035, {1, 1, 1, 11, 9, 7, 113, 187, 295, 67, 1795, 113, 119, 9127, 32119, 7719, 67591}},
+{7250, 17, 13038, {1, 3, 7, 13, 1, 53, 17, 19, 331, 711, 359, 2945, 5847, 7237, 23617, 17411, 2203}},
+{7251, 17, 13052, {1, 3, 3, 7, 21, 63, 115, 159, 225, 161, 1255, 2381, 7411, 95, 1625, 30493, 56685}},
+{7252, 17, 13058, {1, 1, 5, 9, 13, 57, 5, 107, 195, 271, 677, 2081, 6027, 11091, 14171, 19007, 102119}},
+{7253, 17, 13069, {1, 3, 3, 3, 19, 13, 31, 155, 209, 89, 955, 523, 615, 5319, 16079, 9289, 49135}},
+{7254, 17, 13082, {1, 3, 1, 13, 1, 31, 69, 143, 329, 813, 635, 891, 2967, 5563, 19643, 35813, 14345}},
+{7255, 17, 13093, {1, 1, 5, 5, 17, 47, 97, 49, 123, 997, 15, 3685, 3925, 4973, 11195, 17115, 63709}},
+{7256, 17, 13094, {1, 1, 7, 13, 13, 17, 99, 149, 309, 281, 329, 905, 6487, 4495, 31831, 24413, 26431}},
+{7257, 17, 13100, {1, 1, 5, 5, 5, 47, 113, 115, 61, 157, 955, 2323, 4445, 229, 24049, 14753, 15189}},
+{7258, 17, 13115, {1, 3, 7, 15, 25, 21, 13, 137, 377, 45, 629, 1339, 8037, 5073, 24741, 48589, 28953}},
+{7259, 17, 13125, {1, 3, 3, 9, 3, 41, 7, 101, 333, 59, 1213, 1871, 3993, 11261, 4403, 42785, 58753}},
+{7260, 17, 13132, {1, 3, 1, 7, 5, 33, 87, 73, 317, 575, 1459, 905, 1033, 14179, 19595, 30269, 103853}},
+{7261, 17, 13143, {1, 1, 1, 1, 19, 49, 63, 181, 227, 401, 695, 1811, 2383, 3835, 14379, 30685, 114731}},
+{7262, 17, 13144, {1, 1, 5, 15, 9, 41, 35, 91, 357, 659, 155, 3725, 6509, 405, 25449, 37719, 6013}},
+{7263, 17, 13153, {1, 1, 7, 3, 11, 59, 33, 151, 291, 393, 741, 3961, 2787, 993, 10361, 11737, 42047}},
+{7264, 17, 13160, {1, 3, 7, 3, 15, 15, 55, 59, 419, 203, 55, 801, 2719, 15487, 13213, 58473, 50315}},
+{7265, 17, 13165, {1, 3, 7, 13, 17, 21, 113, 111, 159, 163, 711, 1135, 1133, 15519, 30515, 55777, 25025}},
+{7266, 17, 13173, {1, 1, 3, 5, 13, 25, 23, 3, 93, 873, 559, 1815, 3381, 5311, 14365, 34349, 17333}},
+{7267, 17, 13174, {1, 3, 5, 7, 15, 43, 85, 33, 23, 903, 1247, 3279, 1393, 12059, 19251, 19389, 5097}},
+{7268, 17, 13187, {1, 3, 1, 11, 21, 59, 3, 153, 403, 95, 1939, 2679, 419, 9035, 31219, 2897, 15727}},
+{7269, 17, 13190, {1, 3, 5, 1, 11, 21, 35, 169, 453, 15, 791, 3931, 1021, 16321, 6033, 10639, 16173}},
+{7270, 17, 13204, {1, 3, 1, 11, 7, 57, 39, 61, 381, 465, 451, 2863, 575, 5597, 31041, 8625, 82373}},
+{7271, 17, 13218, {1, 1, 3, 5, 13, 5, 63, 1, 75, 245, 1305, 285, 3367, 10107, 5853, 35275, 128255}},
+{7272, 17, 13247, {1, 1, 1, 3, 1, 57, 21, 91, 139, 669, 765, 1867, 2153, 10347, 26119, 35517, 4725}},
+{7273, 17, 13250, {1, 3, 5, 1, 21, 41, 59, 247, 473, 1015, 975, 485, 2161, 11941, 10341, 35245, 55587}},
+{7274, 17, 13262, {1, 1, 5, 9, 7, 59, 33, 149, 97, 619, 393, 3613, 6037, 10895, 19461, 15975, 47919}},
+{7275, 17, 13267, {1, 3, 3, 15, 7, 17, 95, 13, 147, 361, 915, 2585, 4483, 3159, 12255, 44685, 116163}},
+{7276, 17, 13274, {1, 3, 1, 15, 27, 31, 75, 31, 423, 233, 1453, 2815, 3633, 6531, 25721, 29649, 80645}},
+{7277, 17, 13304, {1, 3, 3, 3, 19, 7, 73, 33, 163, 495, 1483, 2277, 6455, 6523, 9331, 21869, 52175}},
+{7278, 17, 13309, {1, 3, 5, 13, 5, 1, 63, 35, 335, 189, 713, 2997, 3277, 10049, 4681, 16753, 17107}},
+{7279, 17, 13315, {1, 3, 5, 9, 3, 55, 29, 171, 395, 585, 671, 1875, 4449, 12895, 5455, 11023, 106189}},
+{7280, 17, 13317, {1, 3, 5, 3, 25, 53, 33, 169, 109, 285, 787, 861, 5549, 5171, 15293, 2977, 14559}},
+{7281, 17, 13324, {1, 3, 7, 1, 21, 25, 97, 115, 1, 999, 1033, 3471, 129, 16093, 495, 16859, 34615}},
+{7282, 17, 13332, {1, 3, 5, 9, 13, 5, 109, 41, 57, 957, 231, 3771, 2917, 15649, 8869, 14857, 64943}},
+{7283, 17, 13342, {1, 1, 7, 7, 21, 41, 101, 59, 167, 441, 997, 2951, 7891, 16325, 12669, 53829, 100705}},
+{7284, 17, 13346, {1, 1, 7, 9, 19, 59, 23, 141, 193, 237, 1067, 1823, 3351, 3239, 3135, 9275, 37069}},
+{7285, 17, 13355, {1, 3, 3, 9, 3, 17, 95, 73, 19, 231, 779, 3065, 2245, 2967, 24971, 62589, 16729}},
+{7286, 17, 13358, {1, 3, 3, 13, 25, 19, 117, 147, 443, 123, 157, 2037, 327, 14715, 5693, 54641, 33325}},
+{7287, 17, 13360, {1, 3, 1, 9, 21, 21, 21, 125, 49, 787, 767, 2831, 511, 2461, 31537, 27155, 44053}},
+{7288, 17, 13369, {1, 3, 7, 9, 31, 19, 125, 67, 119, 465, 287, 1869, 3979, 15723, 21069, 8581, 66939}},
+{7289, 17, 13372, {1, 1, 1, 11, 7, 37, 123, 237, 353, 499, 113, 3829, 217, 4751, 7385, 20343, 83699}},
+{7290, 17, 13398, {1, 3, 7, 13, 9, 3, 53, 27, 487, 87, 35, 2645, 3481, 14409, 27875, 31695, 78489}},
+{7291, 17, 13404, {1, 3, 3, 13, 9, 43, 67, 51, 153, 83, 591, 1991, 1787, 11973, 7273, 34801, 47199}},
+{7292, 17, 13407, {1, 3, 7, 1, 15, 53, 71, 11, 205, 853, 2011, 581, 1281, 7819, 23083, 33731, 74951}},
+{7293, 17, 13414, {1, 1, 5, 5, 17, 63, 109, 219, 225, 997, 1251, 3287, 1441, 13489, 22723, 45191, 50249}},
+{7294, 17, 13426, {1, 1, 5, 3, 13, 1, 43, 53, 293, 685, 1369, 1515, 7479, 3233, 20007, 65235, 102467}},
+{7295, 17, 13432, {1, 3, 5, 7, 29, 45, 63, 45, 219, 445, 2047, 317, 7553, 325, 1465, 949, 35163}},
+{7296, 17, 13466, {1, 1, 3, 9, 7, 31, 73, 211, 501, 233, 1495, 701, 5857, 10763, 9743, 10289, 23801}},
+{7297, 17, 13481, {1, 3, 7, 3, 23, 47, 99, 61, 179, 833, 1425, 1275, 4467, 4367, 5567, 23513, 68677}},
+{7298, 17, 13490, {1, 1, 5, 5, 27, 33, 119, 229, 329, 51, 1025, 3167, 3405, 4039, 4135, 6655, 43771}},
+{7299, 17, 13496, {1, 3, 7, 15, 5, 49, 91, 55, 425, 15, 2003, 1571, 3539, 10375, 29645, 5889, 51887}},
+{7300, 17, 13504, {1, 1, 7, 3, 13, 55, 85, 91, 181, 723, 1941, 75, 4443, 11507, 7027, 14189, 50685}},
+{7301, 17, 13516, {1, 3, 5, 5, 29, 49, 13, 3, 97, 165, 41, 3039, 3325, 2161, 775, 38501, 42381}},
+{7302, 17, 13527, {1, 1, 5, 11, 9, 57, 47, 109, 9, 585, 375, 1839, 937, 6877, 29847, 60163, 103081}},
+{7303, 17, 13533, {1, 1, 3, 13, 5, 47, 11, 195, 253, 235, 275, 2313, 163, 14683, 5681, 13381, 84553}},
+{7304, 17, 13537, {1, 3, 3, 15, 15, 1, 93, 157, 437, 557, 307, 1179, 6857, 3101, 16723, 50579, 69603}},
+{7305, 17, 13552, {1, 1, 5, 9, 11, 29, 23, 219, 337, 689, 1155, 2007, 6853, 6749, 20127, 13199, 48433}},
+{7306, 17, 13561, {1, 1, 1, 13, 1, 61, 73, 213, 335, 539, 903, 2719, 775, 2775, 29109, 33367, 3281}},
+{7307, 17, 13567, {1, 3, 1, 5, 15, 31, 65, 231, 439, 623, 1871, 2299, 5365, 10333, 9147, 2781, 63813}},
+{7308, 17, 13582, {1, 1, 3, 1, 1, 25, 23, 229, 173, 279, 181, 1299, 2893, 15475, 12473, 46097, 123387}},
+{7309, 17, 13587, {1, 1, 7, 13, 7, 43, 17, 187, 467, 113, 1293, 2013, 6091, 14621, 22195, 24079, 45379}},
+{7310, 17, 13589, {1, 3, 1, 7, 1, 7, 119, 159, 377, 11, 705, 2853, 3767, 13739, 23375, 25563, 73987}},
+{7311, 17, 13593, {1, 1, 3, 15, 21, 13, 111, 119, 401, 1005, 777, 1699, 2431, 15139, 27887, 28415, 71519}},
+{7312, 17, 13596, {1, 1, 7, 9, 1, 49, 19, 171, 297, 77, 1343, 1249, 5769, 13889, 21401, 24915, 17641}},
+{7313, 17, 13615, {1, 1, 7, 11, 31, 45, 51, 231, 123, 817, 13, 791, 6235, 2787, 475, 1717, 5071}},
+{7314, 17, 13617, {1, 3, 3, 13, 5, 9, 21, 129, 253, 731, 785, 2275, 7343, 7841, 5477, 8973, 101033}},
+{7315, 17, 13623, {1, 1, 7, 13, 23, 1, 119, 221, 293, 709, 2031, 3019, 1529, 2007, 10823, 43193, 82661}},
+{7316, 17, 13641, {1, 3, 1, 11, 29, 29, 87, 79, 415, 679, 1899, 3453, 7355, 8627, 28225, 41857, 106645}},
+{7317, 17, 13647, {1, 1, 5, 15, 9, 13, 21, 241, 491, 927, 999, 2131, 3501, 11063, 28595, 54691, 21297}},
+{7318, 17, 13650, {1, 1, 1, 3, 5, 41, 85, 89, 483, 309, 791, 825, 3043, 2715, 16573, 6551, 77875}},
+{7319, 17, 13659, {1, 3, 1, 1, 25, 21, 107, 123, 79, 1019, 821, 1251, 4943, 1429, 17843, 37013, 53285}},
+{7320, 17, 13671, {1, 1, 5, 3, 7, 5, 35, 123, 445, 315, 627, 2543, 1261, 13737, 15991, 36591, 18309}},
+{7321, 17, 13677, {1, 3, 3, 5, 25, 43, 65, 249, 309, 1023, 737, 1933, 4735, 7725, 12063, 53023, 126677}},
+{7322, 17, 13678, {1, 3, 1, 9, 13, 37, 77, 61, 179, 275, 277, 1431, 2869, 14563, 665, 60553, 7661}},
+{7323, 17, 13680, {1, 3, 5, 3, 29, 1, 127, 73, 363, 311, 1591, 3863, 6481, 4725, 8287, 61311, 39011}},
+{7324, 17, 13685, {1, 3, 1, 7, 13, 23, 115, 215, 385, 563, 1033, 2343, 5023, 11013, 12131, 26997, 48645}},
+{7325, 17, 13689, {1, 1, 5, 13, 3, 59, 41, 155, 263, 507, 1175, 2967, 7929, 8237, 11841, 15365, 51881}},
+{7326, 17, 13701, {1, 1, 3, 11, 19, 35, 89, 115, 121, 315, 1697, 2121, 1867, 6865, 23639, 26525, 44687}},
+{7327, 17, 13706, {1, 3, 5, 15, 9, 5, 125, 183, 149, 447, 309, 1743, 6089, 369, 16153, 63799, 57657}},
+{7328, 17, 13720, {1, 1, 1, 7, 7, 39, 89, 139, 457, 741, 1613, 2883, 5057, 12495, 18669, 55469, 97941}},
+{7329, 17, 13729, {1, 1, 5, 7, 29, 39, 97, 9, 481, 667, 1353, 3387, 2813, 16205, 8353, 22121, 92965}},
+{7330, 17, 13735, {1, 3, 7, 9, 11, 55, 79, 159, 349, 717, 829, 3157, 1457, 6199, 5861, 2553, 20387}},
+{7331, 17, 13736, {1, 1, 1, 11, 3, 51, 113, 53, 287, 109, 1717, 2405, 7207, 4473, 11145, 2549, 591}},
+{7332, 17, 13756, {1, 1, 3, 13, 3, 61, 31, 141, 217, 487, 299, 2755, 3389, 10053, 1105, 21129, 74203}},
+{7333, 17, 13759, {1, 1, 1, 3, 11, 55, 7, 113, 413, 449, 787, 3279, 5123, 16025, 15005, 12175, 6795}},
+{7334, 17, 13761, {1, 3, 1, 1, 25, 23, 107, 191, 3, 3, 49, 1083, 3275, 10385, 7989, 53739, 25505}},
+{7335, 17, 13771, {1, 1, 5, 13, 7, 17, 59, 13, 471, 147, 1627, 2119, 3555, 15555, 10333, 49363, 80959}},
+{7336, 17, 13782, {1, 1, 1, 15, 23, 33, 61, 191, 207, 939, 45, 2781, 71, 9661, 28433, 13089, 76419}},
+{7337, 17, 13786, {1, 3, 3, 7, 29, 47, 111, 19, 315, 381, 851, 1303, 2627, 6255, 30369, 37723, 12949}},
+{7338, 17, 13798, {1, 1, 1, 13, 31, 43, 3, 193, 5, 99, 769, 2523, 1949, 129, 9693, 60535, 67059}},
+{7339, 17, 13810, {1, 1, 3, 15, 5, 33, 73, 149, 253, 985, 863, 1551, 4369, 5911, 8269, 35463, 117055}},
+{7340, 17, 13819, {1, 3, 1, 5, 27, 57, 3, 105, 253, 731, 119, 3287, 613, 4627, 22003, 56027, 123005}},
+{7341, 17, 13826, {1, 1, 3, 3, 27, 47, 67, 147, 495, 865, 1233, 3707, 2511, 2951, 7367, 15625, 86417}},
+{7342, 17, 13831, {1, 1, 7, 1, 7, 7, 13, 255, 457, 529, 953, 1481, 5565, 12495, 4723, 41615, 121829}},
+{7343, 17, 13837, {1, 3, 5, 11, 1, 51, 91, 153, 323, 609, 1353, 2995, 4035, 13835, 28619, 46217, 4967}},
+{7344, 17, 13846, {1, 1, 5, 7, 25, 59, 81, 101, 185, 709, 1249, 2285, 6579, 8655, 17563, 9707, 63845}},
+{7345, 17, 13856, {1, 3, 3, 9, 31, 25, 17, 19, 111, 627, 1187, 2621, 6529, 9457, 25027, 18069, 47559}},
+{7346, 17, 13862, {1, 3, 7, 15, 7, 15, 103, 201, 391, 1023, 817, 535, 2713, 1317, 13469, 56043, 70847}},
+{7347, 17, 13866, {1, 1, 3, 7, 17, 57, 35, 99, 439, 367, 27, 2695, 3519, 8337, 14047, 58489, 69}},
+{7348, 17, 13885, {1, 1, 1, 3, 17, 23, 71, 189, 57, 39, 715, 1779, 3081, 14657, 21895, 59203, 31005}},
+{7349, 17, 13891, {1, 1, 7, 13, 1, 47, 69, 159, 353, 517, 271, 973, 5077, 15707, 11095, 19671, 3389}},
+{7350, 17, 13893, {1, 1, 7, 13, 25, 55, 115, 21, 43, 939, 1697, 101, 4751, 1993, 2389, 28353, 45251}},
+{7351, 17, 13905, {1, 3, 1, 15, 11, 57, 17, 49, 121, 419, 909, 121, 5047, 4235, 13051, 21529, 42097}},
+{7352, 17, 13908, {1, 1, 1, 3, 19, 37, 31, 233, 251, 175, 929, 1527, 7527, 3605, 17075, 61053, 56235}},
+{7353, 17, 13912, {1, 1, 1, 3, 9, 5, 117, 131, 251, 475, 1695, 1381, 2445, 5921, 14921, 937, 80791}},
+{7354, 17, 13917, {1, 1, 3, 9, 11, 5, 31, 215, 37, 567, 1537, 2183, 3291, 1601, 14025, 48807, 7243}},
+{7355, 17, 13918, {1, 3, 1, 9, 7, 13, 81, 249, 321, 473, 1419, 3977, 7037, 14191, 10865, 56131, 43225}},
+{7356, 17, 13946, {1, 1, 1, 13, 15, 23, 31, 69, 449, 491, 1461, 729, 7955, 4003, 16817, 37273, 72025}},
+{7357, 17, 13948, {1, 1, 5, 13, 7, 41, 93, 169, 347, 1013, 301, 2813, 1455, 13187, 10769, 60807, 46333}},
+{7358, 17, 13964, {1, 1, 5, 3, 23, 15, 1, 161, 29, 35, 415, 235, 93, 14543, 29585, 29657, 36489}},
+{7359, 17, 13970, {1, 3, 1, 3, 31, 63, 39, 235, 153, 549, 43, 147, 2317, 3537, 25561, 58287, 58725}},
+{7360, 17, 13975, {1, 1, 3, 5, 5, 11, 59, 97, 349, 307, 501, 1701, 4243, 13717, 17419, 23387, 29533}},
+{7361, 17, 13979, {1, 3, 1, 7, 7, 19, 33, 243, 67, 353, 2023, 3111, 7173, 10979, 28117, 40175, 45337}},
+{7362, 17, 13997, {1, 1, 1, 5, 15, 59, 55, 135, 107, 543, 1743, 2695, 3293, 111, 32629, 8249, 52273}},
+{7363, 17, 14000, {1, 3, 5, 13, 15, 57, 39, 79, 5, 451, 571, 1445, 1393, 2125, 31713, 59655, 20897}},
+{7364, 17, 14006, {1, 1, 3, 11, 29, 61, 1, 37, 173, 513, 1779, 2649, 3289, 4679, 2039, 47587, 28973}},
+{7365, 17, 14020, {1, 1, 5, 5, 15, 19, 17, 143, 387, 359, 275, 625, 7383, 15537, 10311, 40005, 20729}},
+{7366, 17, 14023, {1, 1, 3, 9, 7, 23, 71, 179, 85, 447, 345, 3459, 2857, 8331, 5489, 62207, 64933}},
+{7367, 17, 14024, {1, 1, 1, 1, 11, 61, 47, 131, 213, 611, 701, 713, 1269, 9563, 25223, 50697, 88679}},
+{7368, 17, 14029, {1, 1, 5, 15, 21, 5, 77, 59, 455, 243, 459, 2809, 13, 9325, 32047, 3939, 48389}},
+{7369, 17, 14035, {1, 3, 7, 1, 21, 53, 111, 225, 407, 119, 713, 3635, 1539, 15321, 29827, 36069, 74483}},
+{7370, 17, 14044, {1, 1, 5, 13, 7, 45, 75, 43, 191, 715, 169, 759, 33, 11329, 1069, 36103, 28055}},
+{7371, 17, 14047, {1, 3, 7, 5, 7, 13, 7, 35, 27, 391, 517, 1439, 5699, 1067, 23857, 7293, 66167}},
+{7372, 17, 14058, {1, 1, 7, 11, 3, 31, 1, 83, 299, 345, 65, 669, 1529, 7569, 28959, 50561, 69493}},
+{7373, 17, 14066, {1, 3, 1, 5, 25, 25, 43, 149, 83, 225, 1589, 1691, 7777, 773, 10421, 49523, 23533}},
+{7374, 17, 14075, {1, 1, 5, 11, 25, 29, 81, 11, 497, 43, 951, 2551, 821, 13805, 12315, 61299, 81397}},
+{7375, 17, 14080, {1, 3, 1, 9, 29, 23, 109, 123, 235, 255, 1519, 3289, 7761, 14575, 11851, 1719, 51655}},
+{7376, 17, 14095, {1, 3, 5, 15, 21, 49, 13, 43, 87, 517, 687, 1457, 1501, 15959, 31907, 13771, 69379}},
+{7377, 17, 14100, {1, 1, 5, 3, 21, 11, 87, 9, 343, 317, 845, 1663, 7933, 14063, 24915, 31487, 17445}},
+{7378, 17, 14114, {1, 1, 3, 13, 21, 31, 87, 99, 185, 333, 993, 3899, 971, 2851, 23643, 195, 66957}},
+{7379, 17, 14116, {1, 1, 1, 15, 19, 47, 23, 1, 67, 57, 165, 3903, 421, 10561, 11621, 13815, 10349}},
+{7380, 17, 14123, {1, 3, 5, 11, 9, 19, 73, 17, 229, 913, 459, 3809, 2667, 9775, 3693, 52945, 90837}},
+{7381, 17, 14134, {1, 1, 5, 15, 3, 25, 109, 131, 507, 637, 1615, 859, 6785, 14891, 24801, 39095, 79557}},
+{7382, 17, 14143, {1, 1, 5, 7, 1, 51, 71, 251, 19, 799, 835, 1119, 2349, 15083, 16509, 55621, 123501}},
+{7383, 17, 14151, {1, 3, 5, 9, 13, 39, 127, 1, 233, 37, 735, 3307, 5163, 4529, 5961, 12893, 103641}},
+{7384, 17, 14160, {1, 1, 7, 5, 23, 15, 49, 123, 511, 201, 2025, 289, 3847, 15755, 24279, 52543, 42017}},
+{7385, 17, 14163, {1, 1, 5, 3, 9, 61, 19, 37, 3, 361, 1065, 2971, 2517, 1259, 27359, 3823, 60181}},
+{7386, 17, 14179, {1, 3, 1, 7, 15, 17, 57, 249, 57, 979, 147, 2407, 2579, 3159, 8467, 8433, 72873}},
+{7387, 17, 14181, {1, 1, 3, 1, 25, 7, 47, 117, 449, 321, 143, 3867, 165, 7961, 27597, 10033, 2437}},
+{7388, 17, 14193, {1, 3, 5, 13, 19, 49, 1, 83, 477, 549, 509, 2911, 1559, 14017, 10469, 62171, 82829}},
+{7389, 17, 14209, {1, 3, 3, 7, 27, 21, 15, 63, 31, 45, 1223, 3903, 5469, 11983, 29627, 27453, 32019}},
+{7390, 17, 14210, {1, 1, 7, 7, 9, 9, 7, 77, 349, 467, 61, 3465, 6921, 15761, 15179, 38649, 2469}},
+{7391, 17, 14224, {1, 3, 1, 13, 9, 59, 55, 67, 271, 617, 643, 4071, 7963, 8153, 5121, 43917, 26219}},
+{7392, 17, 14245, {1, 1, 3, 7, 29, 21, 63, 103, 327, 623, 931, 1511, 3125, 229, 28949, 61315, 72667}},
+{7393, 17, 14249, {1, 3, 7, 1, 19, 37, 49, 63, 403, 885, 161, 121, 1447, 9227, 15019, 50049, 26939}},
+{7394, 17, 14255, {1, 3, 3, 3, 23, 57, 95, 79, 485, 173, 93, 835, 7161, 11247, 3485, 5759, 36393}},
+{7395, 17, 14267, {1, 3, 7, 13, 23, 33, 5, 97, 235, 531, 313, 2925, 2223, 847, 18591, 15477, 3129}},
+{7396, 17, 14270, {1, 1, 3, 13, 25, 25, 101, 183, 477, 947, 1251, 2631, 7987, 13417, 23759, 55305, 123817}},
+{7397, 17, 14277, {1, 1, 5, 9, 27, 63, 49, 137, 179, 861, 33, 2375, 3827, 6485, 19689, 7867, 124429}},
+{7398, 17, 14305, {1, 3, 7, 3, 15, 43, 63, 103, 45, 947, 1837, 833, 7055, 7487, 19669, 12045, 78377}},
+{7399, 17, 14308, {1, 3, 5, 3, 29, 35, 57, 19, 471, 985, 1147, 741, 5403, 10057, 25375, 50889, 82719}},
+{7400, 17, 14312, {1, 3, 3, 1, 17, 19, 111, 13, 121, 821, 1831, 4043, 123, 9529, 1511, 10917, 105961}},
+{7401, 17, 14325, {1, 1, 3, 11, 1, 43, 23, 75, 345, 9, 1379, 2157, 5887, 1197, 14849, 17103, 91925}},
+{7402, 17, 14332, {1, 1, 3, 3, 19, 11, 1, 179, 343, 1023, 1801, 915, 255, 519, 5787, 32913, 43471}},
+{7403, 17, 14345, {1, 3, 5, 5, 3, 3, 3, 211, 461, 55, 851, 3165, 2903, 15077, 8537, 2037, 109057}},
+{7404, 17, 14354, {1, 1, 7, 15, 7, 7, 43, 249, 27, 511, 1369, 735, 6093, 12575, 26675, 21745, 117053}},
+{7405, 17, 14372, {1, 1, 5, 7, 21, 53, 45, 83, 415, 645, 325, 4027, 5181, 8485, 1917, 55623, 45203}},
+{7406, 17, 14387, {1, 1, 3, 15, 7, 1, 121, 221, 387, 403, 1877, 1671, 2113, 2379, 5667, 39867, 8079}},
+{7407, 17, 14390, {1, 1, 1, 7, 5, 29, 35, 77, 197, 661, 1859, 2539, 4045, 13497, 305, 44987, 31215}},
+{7408, 17, 14402, {1, 1, 5, 5, 13, 37, 13, 85, 287, 347, 579, 2283, 7911, 5463, 21141, 9035, 105067}},
+{7409, 17, 14408, {1, 1, 1, 9, 17, 17, 63, 97, 57, 629, 1917, 1133, 779, 12365, 17127, 52549, 18755}},
+{7410, 17, 14413, {1, 1, 7, 11, 7, 17, 65, 137, 485, 841, 653, 2921, 4935, 16273, 23333, 7399, 43129}},
+{7411, 17, 14431, {1, 3, 1, 11, 31, 55, 93, 225, 319, 35, 947, 1909, 7733, 8303, 20739, 55713, 6633}},
+{7412, 17, 14438, {1, 1, 1, 3, 11, 25, 1, 165, 305, 275, 607, 3845, 5203, 1989, 13803, 597, 39751}},
+{7413, 17, 14447, {1, 1, 5, 11, 31, 43, 83, 237, 453, 59, 457, 741, 411, 15895, 18891, 30133, 66767}},
+{7414, 17, 14455, {1, 3, 5, 11, 3, 23, 65, 81, 299, 527, 1057, 2731, 3839, 6023, 28887, 64929, 41405}},
+{7415, 17, 14461, {1, 3, 1, 1, 3, 5, 11, 169, 123, 957, 1495, 1717, 4079, 13239, 28339, 33677, 30591}},
+{7416, 17, 14466, {1, 1, 7, 15, 3, 1, 37, 245, 169, 273, 2039, 415, 6555, 13131, 11181, 62179, 36885}},
+{7417, 17, 14480, {1, 1, 3, 11, 1, 55, 19, 19, 425, 113, 1367, 2101, 5581, 985, 2475, 53983, 68999}},
+{7418, 17, 14490, {1, 1, 5, 9, 5, 33, 101, 193, 303, 579, 1265, 2791, 479, 12083, 17609, 31801, 113089}},
+{7419, 17, 14492, {1, 1, 3, 3, 17, 61, 59, 249, 81, 821, 1, 431, 5327, 8675, 23469, 15349, 67711}},
+{7420, 17, 14508, {1, 1, 7, 9, 31, 51, 89, 19, 469, 843, 561, 559, 4823, 7803, 31699, 44537, 56835}},
+{7421, 17, 14513, {1, 3, 7, 9, 11, 57, 27, 43, 469, 655, 433, 3081, 6719, 6651, 30823, 61503, 110711}},
+{7422, 17, 14516, {1, 3, 5, 11, 9, 53, 25, 147, 61, 533, 1369, 879, 7935, 13829, 26655, 17327, 52983}},
+{7423, 17, 14519, {1, 3, 7, 11, 15, 27, 97, 175, 435, 53, 75, 807, 549, 5277, 1831, 19421, 55669}},
+{7424, 17, 14525, {1, 1, 7, 15, 23, 5, 99, 133, 485, 587, 65, 2585, 7667, 2783, 19437, 52769, 1587}},
+{7425, 17, 14534, {1, 1, 7, 7, 13, 39, 111, 165, 489, 355, 1963, 333, 2993, 5233, 9173, 18951, 93737}},
+{7426, 17, 14537, {1, 1, 5, 7, 1, 29, 67, 135, 427, 91, 53, 3109, 3745, 9529, 17567, 42361, 84577}},
+{7427, 17, 14543, {1, 3, 5, 1, 31, 35, 59, 181, 87, 345, 1975, 781, 603, 16365, 19453, 9933, 112739}},
+{7428, 17, 14545, {1, 3, 3, 1, 31, 41, 127, 35, 263, 403, 1811, 383, 1523, 8477, 5973, 41569, 99309}},
+{7429, 17, 14552, {1, 3, 7, 7, 5, 25, 11, 201, 231, 679, 519, 2481, 7415, 12397, 21265, 49419, 13903}},
+{7430, 17, 14562, {1, 1, 7, 5, 1, 11, 63, 221, 327, 509, 419, 871, 7891, 11835, 11099, 10669, 43853}},
+{7431, 17, 14571, {1, 1, 5, 11, 19, 11, 37, 105, 265, 513, 1013, 707, 6083, 14571, 17573, 7645, 5363}},
+{7432, 17, 14574, {1, 1, 1, 13, 19, 19, 67, 93, 113, 509, 1013, 4037, 1939, 7015, 24487, 57183, 123463}},
+{7433, 17, 14582, {1, 1, 1, 1, 21, 17, 95, 25, 261, 1005, 685, 691, 4467, 14723, 24043, 32287, 19651}},
+{7434, 17, 14611, {1, 3, 1, 15, 15, 15, 57, 191, 27, 719, 229, 1977, 241, 9021, 21335, 30967, 81207}},
+{7435, 17, 14614, {1, 3, 1, 9, 23, 61, 103, 67, 361, 925, 811, 1007, 5707, 11479, 5907, 3897, 65141}},
+{7436, 17, 14620, {1, 3, 5, 9, 17, 61, 11, 15, 351, 715, 939, 2141, 4857, 8397, 9693, 26845, 120007}},
+{7437, 17, 14633, {1, 3, 1, 5, 19, 55, 99, 19, 291, 309, 287, 1969, 4341, 7579, 30909, 37277, 54927}},
+{7438, 17, 14641, {1, 3, 7, 3, 19, 29, 43, 163, 367, 753, 1733, 1463, 7927, 10671, 16817, 41229, 113887}},
+{7439, 17, 14648, {1, 3, 7, 1, 11, 51, 39, 207, 283, 73, 1423, 2473, 7593, 3581, 30179, 6369, 112217}},
+{7440, 17, 14671, {1, 1, 3, 15, 15, 25, 43, 5, 271, 611, 959, 537, 303, 3659, 18073, 8147, 81531}},
+{7441, 17, 14674, {1, 3, 7, 1, 27, 55, 77, 11, 367, 209, 1967, 3409, 935, 5309, 18857, 46225, 8367}},
+{7442, 17, 14689, {1, 1, 5, 11, 11, 63, 75, 73, 43, 869, 2021, 3285, 269, 9113, 32699, 2091, 17327}},
+{7443, 17, 14690, {1, 1, 5, 11, 9, 25, 31, 245, 109, 805, 1645, 3607, 817, 9571, 12767, 65441, 129977}},
+{7444, 17, 14692, {1, 3, 7, 5, 11, 61, 67, 223, 433, 387, 935, 1615, 7915, 6133, 24087, 55323, 100619}},
+{7445, 17, 14699, {1, 1, 1, 15, 25, 61, 7, 39, 311, 353, 183, 33, 2591, 4951, 31377, 9081, 9707}},
+{7446, 17, 14710, {1, 1, 3, 3, 1, 9, 65, 229, 185, 47, 1255, 1365, 2231, 6843, 26927, 27195, 60651}},
+{7447, 17, 14719, {1, 1, 7, 5, 7, 25, 91, 133, 159, 737, 1767, 3117, 7321, 6159, 3361, 27793, 33473}},
+{7448, 17, 14730, {1, 3, 7, 3, 11, 7, 5, 125, 369, 951, 1277, 65, 7703, 1817, 11773, 25657, 67045}},
+{7449, 17, 14732, {1, 1, 3, 9, 21, 27, 21, 41, 131, 605, 1, 119, 1553, 1361, 31973, 43135, 119321}},
+{7450, 17, 14743, {1, 3, 7, 1, 25, 63, 55, 173, 323, 403, 1401, 1367, 3455, 15335, 13045, 20759, 8309}},
+{7451, 17, 14744, {1, 1, 3, 5, 3, 61, 59, 7, 39, 439, 721, 2829, 3035, 2293, 32015, 28509, 104831}},
+{7452, 17, 14750, {1, 3, 5, 1, 29, 35, 71, 87, 351, 917, 1661, 547, 4501, 7107, 5493, 17833, 130729}},
+{7453, 17, 14759, {1, 1, 5, 5, 7, 5, 69, 57, 319, 595, 1749, 3789, 1437, 6327, 24089, 7387, 125109}},
+{7454, 17, 14763, {1, 3, 5, 9, 15, 53, 95, 59, 217, 37, 1561, 401, 5259, 4361, 1049, 3437, 30559}},
+{7455, 17, 14768, {1, 3, 7, 13, 15, 15, 107, 167, 475, 157, 1565, 2219, 1891, 1433, 11829, 43433, 48111}},
+{7456, 17, 14773, {1, 1, 1, 3, 11, 41, 25, 211, 243, 355, 1831, 2093, 2747, 2523, 9885, 9503, 120089}},
+{7457, 17, 14777, {1, 3, 7, 5, 11, 3, 1, 231, 243, 541, 341, 887, 3567, 14759, 26763, 35705, 29417}},
+{7458, 17, 14786, {1, 1, 7, 13, 17, 35, 117, 177, 81, 361, 1425, 2437, 6821, 1061, 15019, 19135, 106007}},
+{7459, 17, 14795, {1, 3, 3, 11, 19, 5, 39, 23, 367, 9, 879, 3583, 2527, 14375, 28359, 27393, 55041}},
+{7460, 17, 14800, {1, 1, 7, 11, 9, 41, 63, 125, 33, 337, 587, 3939, 2635, 4559, 1007, 38991, 35651}},
+{7461, 17, 14812, {1, 1, 3, 1, 19, 11, 83, 13, 227, 649, 415, 1661, 3285, 55, 3683, 22319, 2127}},
+{7462, 17, 14816, {1, 3, 7, 13, 19, 49, 113, 129, 83, 5, 19, 1095, 6561, 11049, 3805, 11355, 84265}},
+{7463, 17, 14836, {1, 3, 1, 9, 19, 41, 111, 193, 429, 319, 67, 1717, 1819, 12959, 31449, 21035, 113161}},
+{7464, 17, 14840, {1, 1, 5, 11, 19, 19, 115, 237, 145, 681, 1525, 2215, 7915, 15529, 7533, 45981, 85461}},
+{7465, 17, 14856, {1, 1, 1, 1, 25, 3, 73, 207, 15, 69, 43, 1643, 7707, 12505, 27101, 40735, 6091}},
+{7466, 17, 14859, {1, 1, 5, 11, 21, 61, 119, 7, 37, 147, 1379, 3165, 6555, 3867, 24027, 45161, 93015}},
+{7467, 17, 14870, {1, 1, 3, 9, 9, 25, 51, 125, 511, 209, 75, 2849, 2299, 2901, 25157, 13079, 67733}},
+{7468, 17, 14873, {1, 3, 7, 9, 31, 49, 99, 21, 89, 1, 1391, 1741, 2733, 7283, 12087, 9287, 39713}},
+{7469, 17, 14879, {1, 1, 5, 5, 1, 5, 89, 109, 499, 343, 431, 401, 2023, 5541, 16615, 40059, 119195}},
+{7470, 17, 14880, {1, 3, 5, 15, 27, 27, 9, 159, 395, 31, 865, 2793, 55, 10961, 23123, 63731, 54385}},
+{7471, 17, 14889, {1, 3, 7, 1, 11, 47, 123, 239, 399, 383, 1497, 4075, 4659, 2911, 2101, 8295, 115717}},
+{7472, 17, 14892, {1, 1, 3, 1, 11, 63, 125, 171, 65, 15, 349, 753, 2981, 6713, 6219, 14093, 78797}},
+{7473, 17, 14895, {1, 1, 1, 13, 9, 15, 1, 113, 221, 867, 1907, 103, 1411, 27, 22743, 377, 116907}},
+{7474, 17, 14900, {1, 3, 1, 5, 27, 5, 27, 245, 221, 575, 2009, 1561, 4263, 11843, 28331, 12865, 10483}},
+{7475, 17, 14903, {1, 3, 7, 9, 1, 51, 119, 241, 439, 913, 1191, 2343, 2055, 10247, 18283, 40175, 63321}},
+{7476, 17, 14910, {1, 1, 3, 15, 21, 59, 45, 151, 485, 293, 981, 3523, 7689, 2789, 5003, 62383, 126221}},
+{7477, 17, 14912, {1, 1, 1, 1, 13, 15, 39, 201, 405, 513, 1721, 2077, 5995, 2433, 20421, 12695, 20393}},
+{7478, 17, 14942, {1, 3, 5, 15, 11, 35, 113, 133, 187, 583, 577, 291, 7563, 12959, 9383, 44255, 81763}},
+{7479, 17, 14948, {1, 3, 7, 15, 9, 55, 57, 227, 189, 595, 1311, 1131, 1323, 11347, 12777, 50963, 13827}},
+{7480, 17, 14957, {1, 3, 5, 3, 11, 49, 77, 157, 107, 959, 761, 1457, 7121, 3027, 9269, 26291, 125261}},
+{7481, 17, 14963, {1, 1, 5, 9, 23, 53, 125, 211, 303, 433, 1103, 41, 2643, 5325, 11885, 23825, 80415}},
+{7482, 17, 14975, {1, 1, 7, 1, 29, 25, 51, 107, 209, 165, 707, 1855, 7429, 1583, 5941, 47509, 90105}},
+{7483, 17, 14985, {1, 1, 3, 3, 1, 15, 121, 165, 181, 259, 1949, 3049, 3545, 3093, 5967, 49207, 37129}},
+{7484, 17, 14993, {1, 1, 5, 13, 9, 59, 93, 87, 57, 343, 389, 1995, 4001, 11495, 12909, 13491, 61759}},
+{7485, 17, 15003, {1, 3, 1, 5, 11, 27, 27, 133, 459, 733, 1845, 1795, 4613, 3397, 12313, 52839, 129583}},
+{7486, 17, 15010, {1, 3, 5, 3, 19, 1, 7, 145, 255, 337, 1649, 1473, 4113, 4425, 12233, 55477, 69157}},
+{7487, 17, 15022, {1, 1, 3, 1, 25, 27, 93, 59, 415, 437, 25, 1565, 319, 8981, 2453, 53579, 45033}},
+{7488, 17, 15039, {1, 3, 7, 1, 27, 49, 47, 233, 341, 101, 2017, 2827, 8085, 237, 6363, 61139, 88903}},
+{7489, 17, 15041, {1, 1, 1, 5, 23, 47, 65, 251, 423, 957, 1751, 3541, 5405, 1335, 22703, 12587, 60201}},
+{7490, 17, 15047, {1, 1, 3, 3, 5, 51, 85, 195, 423, 519, 1797, 3821, 5915, 12257, 5377, 62733, 41197}},
+{7491, 17, 15048, {1, 3, 7, 15, 3, 47, 97, 1, 5, 175, 1449, 1609, 6873, 12017, 5579, 2665, 58389}},
+{7492, 17, 15056, {1, 3, 3, 15, 19, 37, 35, 29, 79, 767, 21, 1279, 1997, 11611, 14381, 35607, 127701}},
+{7493, 17, 15066, {1, 3, 7, 7, 7, 43, 47, 33, 69, 155, 703, 1373, 1589, 6997, 8627, 50647, 16989}},
+{7494, 17, 15068, {1, 3, 1, 5, 13, 33, 69, 133, 399, 361, 1633, 321, 2077, 8857, 13419, 23227, 40003}},
+{7495, 17, 15075, {1, 1, 1, 15, 15, 9, 45, 181, 427, 1005, 341, 1697, 6423, 5727, 7163, 10401, 38957}},
+{7496, 17, 15077, {1, 1, 7, 1, 17, 5, 17, 95, 279, 171, 825, 2459, 5243, 10683, 1849, 32809, 8995}},
+{7497, 17, 15082, {1, 3, 5, 15, 27, 47, 103, 69, 69, 255, 961, 2173, 5297, 5987, 5863, 14311, 117569}},
+{7498, 17, 15096, {1, 1, 1, 11, 21, 27, 61, 239, 183, 1013, 1955, 3171, 4183, 965, 14885, 49605, 87851}},
+{7499, 17, 15102, {1, 1, 7, 9, 9, 53, 99, 211, 267, 803, 1545, 4011, 7613, 13889, 28277, 6817, 26515}},
+{7500, 17, 15116, {1, 1, 3, 9, 1, 19, 33, 227, 461, 679, 499, 1069, 837, 12129, 20779, 12937, 104367}},
+{7501, 17, 15122, {1, 3, 3, 15, 7, 3, 29, 245, 179, 1015, 1651, 3753, 4185, 15357, 17379, 52835, 51953}},
+{7502, 17, 15127, {1, 3, 3, 3, 3, 25, 95, 239, 263, 427, 1749, 183, 5251, 361, 32549, 24331, 30789}},
+{7503, 17, 15133, {1, 1, 7, 1, 5, 3, 79, 9, 403, 195, 1433, 385, 8105, 7893, 16415, 23253, 127837}},
+{7504, 17, 15137, {1, 3, 7, 3, 23, 45, 115, 27, 473, 241, 361, 1787, 4247, 13451, 5627, 32923, 29375}},
+{7505, 17, 15138, {1, 3, 7, 1, 5, 55, 43, 37, 481, 899, 51, 2459, 5005, 12365, 19261, 32797, 45843}},
+{7506, 17, 15149, {1, 3, 7, 5, 9, 41, 83, 163, 241, 899, 567, 231, 4897, 15175, 10329, 6625, 95927}},
+{7507, 17, 15152, {1, 3, 1, 1, 7, 51, 61, 55, 253, 315, 1893, 2635, 4061, 257, 14147, 36639, 24893}},
+{7508, 17, 15155, {1, 1, 5, 1, 13, 63, 115, 119, 205, 309, 277, 2191, 341, 4715, 13111, 58043, 51241}},
+{7509, 17, 15158, {1, 3, 1, 15, 17, 23, 89, 121, 205, 15, 295, 667, 421, 14071, 27719, 1335, 9887}},
+{7510, 17, 15187, {1, 3, 5, 5, 17, 49, 5, 93, 251, 613, 1029, 945, 1547, 10479, 20183, 26787, 120441}},
+{7511, 17, 15189, {1, 3, 3, 15, 17, 11, 63, 97, 499, 313, 881, 2233, 4287, 5141, 13841, 40725, 49285}},
+{7512, 17, 15190, {1, 3, 3, 11, 19, 33, 105, 203, 325, 337, 353, 1923, 7157, 8623, 23881, 4513, 71495}},
+{7513, 17, 15196, {1, 1, 5, 1, 3, 15, 119, 43, 85, 869, 1597, 2433, 845, 5065, 12813, 64849, 58491}},
+{7514, 17, 15199, {1, 3, 7, 7, 25, 63, 119, 93, 303, 665, 571, 1795, 5853, 13527, 12715, 36483, 57723}},
+{7515, 17, 15205, {1, 3, 7, 13, 19, 43, 55, 85, 189, 627, 1457, 3185, 3491, 1913, 13399, 30681, 69015}},
+{7516, 17, 15212, {1, 3, 5, 9, 5, 41, 51, 65, 147, 425, 569, 1317, 1557, 7631, 17243, 37847, 51161}},
+{7517, 17, 15236, {1, 1, 3, 7, 29, 39, 61, 127, 489, 89, 749, 2073, 195, 14367, 13533, 27403, 16365}},
+{7518, 17, 15243, {1, 3, 7, 15, 13, 35, 45, 157, 373, 415, 725, 779, 3559, 7489, 11369, 36501, 60761}},
+{7519, 17, 15246, {1, 3, 1, 3, 13, 45, 25, 215, 385, 709, 499, 3861, 761, 15597, 3335, 37013, 13173}},
+{7520, 17, 15260, {1, 1, 7, 1, 13, 49, 89, 135, 175, 1015, 67, 957, 4893, 9843, 13027, 14709, 59721}},
+{7521, 17, 15267, {1, 3, 3, 11, 19, 37, 109, 143, 135, 535, 1543, 3991, 189, 6739, 28087, 18845, 41819}},
+{7522, 17, 15274, {1, 1, 7, 5, 1, 7, 11, 5, 211, 251, 1593, 2527, 3539, 10471, 25595, 60119, 89213}},
+{7523, 17, 15279, {1, 1, 5, 7, 13, 51, 121, 167, 299, 403, 977, 521, 279, 15521, 15901, 935, 14065}},
+{7524, 17, 15281, {1, 1, 7, 13, 7, 21, 27, 205, 377, 801, 1365, 1567, 6651, 139, 14229, 30827, 50429}},
+{7525, 17, 15282, {1, 1, 1, 1, 17, 11, 75, 87, 217, 413, 1923, 1765, 2037, 14061, 12433, 30671, 24883}},
+{7526, 17, 15284, {1, 1, 5, 13, 17, 51, 91, 241, 95, 505, 349, 2689, 1117, 4435, 1713, 44501, 125619}},
+{7527, 17, 15291, {1, 1, 3, 15, 11, 21, 25, 59, 511, 353, 799, 91, 4517, 16005, 17061, 21841, 46311}},
+{7528, 17, 15293, {1, 1, 1, 5, 19, 53, 109, 177, 213, 373, 761, 453, 5753, 69, 3503, 49411, 111105}},
+{7529, 17, 15302, {1, 3, 1, 5, 21, 27, 103, 167, 109, 55, 1849, 3999, 7801, 4185, 9789, 7515, 124983}},
+{7530, 17, 15319, {1, 3, 7, 7, 25, 9, 65, 127, 141, 169, 1079, 3377, 691, 5119, 6629, 3517, 28963}},
+{7531, 17, 15329, {1, 1, 3, 11, 15, 61, 127, 35, 87, 891, 1459, 483, 6763, 16173, 5633, 6939, 63411}},
+{7532, 17, 15336, {1, 3, 5, 3, 7, 63, 111, 85, 415, 273, 1705, 4045, 5551, 2377, 29025, 16831, 90203}},
+{7533, 17, 15347, {1, 3, 5, 13, 7, 23, 103, 227, 477, 985, 1059, 1489, 7233, 1917, 10409, 38759, 86761}},
+{7534, 17, 15353, {1, 3, 5, 7, 31, 33, 75, 41, 355, 577, 225, 5, 897, 15653, 27415, 83, 14911}},
+{7535, 17, 15361, {1, 3, 5, 5, 23, 13, 5, 43, 165, 53, 149, 2005, 4545, 477, 17885, 21343, 35751}},
+{7536, 17, 15371, {1, 3, 3, 3, 25, 51, 33, 203, 291, 835, 241, 3255, 3709, 3573, 9859, 33027, 122801}},
+{7537, 17, 15397, {1, 3, 5, 7, 13, 7, 3, 141, 455, 67, 2003, 3411, 4717, 157, 29491, 14429, 44849}},
+{7538, 17, 15404, {1, 1, 1, 11, 3, 33, 101, 93, 219, 371, 1191, 1521, 1663, 8485, 24815, 38283, 120867}},
+{7539, 17, 15407, {1, 1, 3, 9, 25, 61, 71, 173, 69, 181, 1525, 2129, 2979, 19, 13489, 627, 72619}},
+{7540, 17, 15421, {1, 3, 1, 7, 25, 33, 39, 247, 221, 7, 683, 1837, 8037, 9125, 4259, 63049, 63021}},
+{7541, 17, 15433, {1, 3, 3, 9, 17, 15, 9, 189, 357, 707, 521, 711, 8189, 12945, 29675, 11851, 126813}},
+{7542, 17, 15441, {1, 3, 1, 1, 23, 3, 57, 133, 245, 301, 957, 239, 3139, 7949, 27133, 18229, 93015}},
+{7543, 17, 15442, {1, 1, 3, 1, 29, 23, 35, 87, 231, 257, 1997, 271, 3019, 3409, 10613, 42245, 111309}},
+{7544, 17, 15463, {1, 1, 3, 3, 1, 21, 17, 37, 393, 943, 791, 3101, 6715, 11907, 25369, 9061, 75381}},
+{7545, 17, 15472, {1, 1, 7, 7, 17, 31, 25, 7, 183, 819, 1265, 3343, 6845, 2039, 3779, 41861, 38309}},
+{7546, 17, 15478, {1, 1, 1, 5, 17, 25, 1, 41, 173, 995, 863, 3515, 1779, 2159, 28223, 64661, 40697}},
+{7547, 17, 15488, {1, 1, 3, 15, 29, 49, 81, 241, 511, 817, 1301, 3593, 6759, 7483, 8859, 30339, 106137}},
+{7548, 17, 15493, {1, 3, 1, 11, 17, 61, 95, 231, 3, 693, 37, 1091, 3111, 11941, 17475, 8073, 62373}},
+{7549, 17, 15498, {1, 1, 1, 3, 7, 25, 93, 7, 291, 957, 859, 2519, 241, 10963, 10403, 933, 50599}},
+{7550, 17, 15511, {1, 1, 7, 1, 7, 33, 121, 91, 369, 333, 229, 4073, 6063, 6491, 31711, 65061, 107843}},
+{7551, 17, 15521, {1, 1, 5, 15, 17, 1, 117, 195, 445, 547, 867, 2893, 4835, 6513, 29091, 60367, 33409}},
+{7552, 17, 15534, {1, 3, 3, 7, 15, 5, 125, 131, 165, 127, 207, 853, 5927, 3605, 17083, 44481, 111333}},
+{7553, 17, 15539, {1, 1, 1, 9, 3, 43, 75, 191, 319, 889, 1513, 3301, 1535, 4693, 10367, 12491, 43175}},
+{7554, 17, 15541, {1, 3, 5, 5, 29, 19, 75, 221, 393, 977, 1373, 1571, 7377, 1763, 18073, 11381, 101241}},
+{7555, 17, 15560, {1, 3, 1, 15, 3, 15, 73, 91, 165, 213, 1077, 1267, 2411, 15807, 3979, 12731, 86597}},
+{7556, 17, 15563, {1, 1, 3, 7, 3, 21, 5, 135, 95, 337, 1853, 1675, 2449, 12535, 18505, 60127, 76949}},
+{7557, 17, 15574, {1, 1, 7, 3, 15, 11, 63, 127, 329, 169, 1569, 675, 4801, 5859, 3243, 25811, 77841}},
+{7558, 17, 15578, {1, 1, 1, 9, 19, 13, 73, 119, 105, 537, 951, 1033, 5303, 5775, 815, 19277, 57607}},
+{7559, 17, 15584, {1, 3, 5, 5, 23, 21, 91, 231, 117, 1007, 1603, 841, 2595, 11223, 17171, 25963, 17049}},
+{7560, 17, 15593, {1, 1, 5, 11, 15, 43, 7, 229, 55, 129, 599, 993, 563, 15677, 16703, 36253, 17847}},
+{7561, 17, 15604, {1, 3, 1, 9, 25, 3, 109, 21, 87, 721, 1927, 3219, 3395, 3267, 9117, 13591, 89267}},
+{7562, 17, 15614, {1, 1, 1, 15, 11, 17, 47, 49, 125, 925, 333, 945, 2411, 10907, 12021, 47857, 84303}},
+{7563, 17, 15619, {1, 1, 1, 1, 23, 11, 99, 215, 105, 417, 823, 1289, 421, 12285, 17711, 35389, 1935}},
+{7564, 17, 15622, {1, 1, 1, 15, 27, 7, 23, 141, 7, 929, 147, 681, 5473, 4173, 28645, 42053, 83573}},
+{7565, 17, 15633, {1, 1, 1, 11, 5, 61, 71, 65, 287, 697, 1183, 3257, 7251, 14011, 21349, 42445, 4701}},
+{7566, 17, 15639, {1, 3, 5, 9, 5, 23, 45, 217, 369, 189, 1495, 107, 425, 10467, 4909, 64293, 17885}},
+{7567, 17, 15646, {1, 1, 3, 11, 21, 45, 75, 65, 57, 893, 783, 3429, 409, 13617, 483, 62489, 2919}},
+{7568, 17, 15673, {1, 1, 7, 3, 5, 61, 51, 255, 501, 839, 367, 1165, 7055, 8139, 23891, 18807, 20739}},
+{7569, 17, 15674, {1, 1, 3, 7, 23, 15, 97, 139, 323, 463, 921, 1529, 6655, 8697, 23577, 56761, 62023}},
+{7570, 17, 15684, {1, 1, 5, 11, 13, 11, 57, 225, 277, 713, 1427, 95, 1135, 7721, 30731, 32625, 107891}},
+{7571, 17, 15691, {1, 1, 5, 7, 23, 35, 39, 91, 291, 609, 919, 3325, 6843, 7659, 5603, 37471, 41495}},
+{7572, 17, 15694, {1, 1, 1, 1, 25, 11, 117, 15, 389, 589, 1345, 423, 6531, 9903, 20243, 9523, 22991}},
+{7573, 17, 15696, {1, 3, 5, 15, 29, 7, 57, 113, 387, 883, 1141, 3295, 2973, 4129, 16973, 33429, 109997}},
+{7574, 17, 15701, {1, 3, 5, 3, 25, 1, 73, 207, 353, 203, 1479, 985, 6373, 3079, 28403, 63675, 21787}},
+{7575, 17, 15705, {1, 3, 1, 5, 31, 39, 107, 197, 359, 45, 203, 559, 4721, 6579, 11305, 12957, 10061}},
+{7576, 17, 15715, {1, 3, 7, 15, 9, 3, 55, 153, 373, 981, 575, 827, 4757, 15743, 14295, 43875, 17847}},
+{7577, 17, 15729, {1, 3, 5, 1, 17, 1, 93, 87, 207, 997, 1695, 3643, 6973, 9507, 29309, 58531, 6849}},
+{7578, 17, 15730, {1, 3, 1, 11, 3, 39, 17, 241, 83, 931, 39, 3839, 6437, 5159, 28869, 61859, 96873}},
+{7579, 17, 15741, {1, 1, 5, 13, 29, 43, 71, 159, 261, 563, 695, 1205, 2273, 8077, 12569, 17187, 54369}},
+{7580, 17, 15745, {1, 3, 7, 5, 11, 57, 17, 31, 311, 1001, 1419, 3899, 6679, 15531, 28877, 28221, 105413}},
+{7581, 17, 15748, {1, 3, 3, 13, 23, 29, 127, 19, 345, 1003, 1571, 2219, 3199, 9903, 18701, 31865, 108879}},
+{7582, 17, 15757, {1, 3, 7, 13, 23, 51, 95, 43, 35, 439, 25, 323, 2365, 12407, 27525, 57795, 74495}},
+{7583, 17, 15765, {1, 1, 1, 1, 17, 43, 57, 185, 439, 929, 69, 813, 6205, 3139, 3853, 56967, 19073}},
+{7584, 17, 15766, {1, 3, 7, 1, 27, 5, 43, 211, 395, 113, 1675, 1505, 6171, 5169, 9991, 21641, 27101}},
+{7585, 17, 15775, {1, 3, 3, 1, 17, 41, 59, 131, 131, 339, 955, 1145, 5301, 4585, 20441, 43227, 23123}},
+{7586, 17, 15776, {1, 1, 7, 9, 9, 55, 61, 31, 71, 229, 963, 3247, 4677, 9595, 21715, 36391, 86997}},
+{7587, 17, 15779, {1, 1, 7, 5, 9, 17, 55, 179, 27, 229, 79, 1335, 5887, 1003, 22085, 34377, 51367}},
+{7588, 17, 15786, {1, 1, 1, 5, 11, 45, 15, 219, 411, 27, 1003, 1553, 303, 13571, 13985, 6801, 52407}},
+{7589, 17, 15788, {1, 3, 3, 7, 7, 55, 111, 255, 453, 409, 1863, 1449, 4103, 8725, 26923, 5017, 43657}},
+{7590, 17, 15813, {1, 1, 1, 15, 23, 3, 95, 57, 29, 727, 1111, 3309, 1089, 471, 16099, 11517, 51563}},
+{7591, 17, 15814, {1, 3, 1, 15, 17, 57, 83, 163, 251, 987, 1159, 2079, 3463, 13109, 7443, 8665, 123397}},
+{7592, 17, 15842, {1, 1, 7, 1, 27, 13, 35, 209, 471, 843, 1029, 1383, 5413, 2085, 13431, 26557, 47033}},
+{7593, 17, 15851, {1, 3, 1, 1, 21, 21, 83, 135, 303, 27, 1407, 1751, 331, 9207, 31891, 59287, 120687}},
+{7594, 17, 15862, {1, 1, 1, 9, 11, 35, 103, 157, 1, 855, 175, 3203, 4381, 3113, 27589, 4567, 31897}},
+{7595, 17, 15875, {1, 1, 3, 5, 21, 5, 123, 161, 301, 101, 909, 947, 6893, 15459, 29139, 49377, 94901}},
+{7596, 17, 15878, {1, 3, 7, 7, 21, 27, 5, 69, 427, 409, 1389, 3737, 847, 2775, 603, 1001, 87651}},
+{7597, 17, 15889, {1, 1, 3, 5, 1, 57, 109, 89, 99, 593, 581, 3527, 1557, 4971, 27523, 26909, 35787}},
+{7598, 17, 15896, {1, 1, 7, 3, 31, 19, 83, 65, 239, 919, 15, 2289, 4117, 9127, 6033, 49667, 89343}},
+{7599, 17, 15901, {1, 3, 7, 7, 9, 31, 87, 117, 195, 681, 1711, 1753, 2221, 10053, 1985, 6273, 21801}},
+{7600, 17, 15908, {1, 3, 1, 7, 21, 61, 53, 231, 309, 115, 1729, 3883, 6085, 4825, 31455, 50097, 59779}},
+{7601, 17, 15911, {1, 1, 1, 9, 29, 25, 45, 91, 145, 927, 147, 371, 2603, 12537, 17267, 59895, 128009}},
+{7602, 17, 15915, {1, 1, 1, 1, 15, 41, 63, 43, 167, 215, 15, 3387, 1811, 12391, 25721, 6961, 13701}},
+{7603, 17, 15938, {1, 1, 7, 1, 27, 63, 25, 85, 337, 799, 87, 2237, 4085, 14529, 11493, 60149, 86399}},
+{7604, 17, 15944, {1, 3, 1, 11, 1, 41, 103, 145, 279, 805, 1201, 823, 5411, 4227, 25999, 14373, 36295}},
+{7605, 17, 15950, {1, 1, 7, 3, 27, 51, 83, 105, 155, 657, 1879, 3869, 2559, 2939, 19785, 47167, 34503}},
+{7606, 17, 15955, {1, 3, 1, 5, 3, 31, 47, 241, 257, 15, 983, 4095, 3745, 3901, 1639, 5421, 81585}},
+{7607, 17, 15974, {1, 3, 3, 5, 31, 13, 127, 125, 175, 577, 1103, 3573, 6229, 13969, 6267, 19067, 3933}},
+{7608, 17, 15978, {1, 1, 7, 1, 31, 17, 15, 15, 411, 553, 1929, 3731, 1955, 11749, 21991, 39189, 124427}},
+{7609, 17, 15980, {1, 3, 5, 5, 19, 63, 93, 201, 491, 599, 1093, 767, 3411, 13087, 23569, 42981, 35757}},
+{7610, 17, 15983, {1, 1, 1, 15, 27, 7, 51, 101, 429, 939, 111, 781, 2055, 14227, 17821, 42097, 32485}},
+{7611, 17, 15991, {1, 3, 7, 13, 11, 21, 3, 161, 353, 389, 285, 2633, 6245, 7089, 21907, 40765, 88869}},
+{7612, 17, 16004, {1, 1, 5, 9, 7, 27, 101, 203, 243, 897, 1375, 1619, 5275, 12935, 22103, 38005, 65603}},
+{7613, 17, 16011, {1, 1, 5, 9, 13, 25, 15, 21, 447, 7, 947, 1613, 5055, 129, 18057, 58551, 6603}},
+{7614, 17, 16016, {1, 3, 7, 15, 17, 41, 11, 55, 103, 339, 349, 1813, 7423, 11837, 20641, 51951, 61615}},
+{7615, 17, 16019, {1, 3, 3, 15, 21, 59, 113, 3, 123, 689, 465, 3039, 4109, 3241, 30317, 65053, 117845}},
+{7616, 17, 16025, {1, 3, 3, 1, 31, 33, 73, 155, 245, 401, 473, 51, 1387, 489, 10573, 55401, 106733}},
+{7617, 17, 16041, {1, 3, 3, 1, 31, 37, 15, 139, 127, 201, 229, 1753, 7287, 9045, 18321, 63485, 26399}},
+{7618, 17, 16064, {1, 3, 5, 5, 5, 23, 93, 3, 125, 715, 1827, 419, 1213, 9031, 25139, 20771, 41345}},
+{7619, 17, 16067, {1, 3, 5, 15, 23, 15, 13, 145, 105, 477, 1131, 2699, 1929, 10447, 9655, 26791, 80101}},
+{7620, 17, 16074, {1, 1, 1, 13, 1, 35, 75, 73, 269, 851, 737, 1909, 6805, 11359, 28991, 52435, 83767}},
+{7621, 17, 16082, {1, 1, 7, 5, 11, 31, 31, 91, 111, 161, 1865, 2545, 133, 12215, 8957, 20671, 92975}},
+{7622, 17, 16103, {1, 1, 7, 5, 25, 53, 55, 121, 53, 457, 831, 2493, 339, 10955, 30783, 9095, 97921}},
+{7623, 17, 16109, {1, 1, 5, 3, 25, 33, 81, 51, 211, 737, 1865, 4039, 6931, 8473, 22459, 24885, 96355}},
+{7624, 17, 16122, {1, 3, 7, 13, 23, 5, 101, 171, 65, 793, 443, 411, 7629, 14791, 28633, 9055, 123763}},
+{7625, 17, 16149, {1, 3, 3, 1, 11, 7, 99, 79, 461, 481, 1689, 3777, 2125, 4783, 13061, 19537, 68109}},
+{7626, 17, 16170, {1, 1, 3, 11, 31, 53, 109, 7, 49, 925, 1017, 2371, 1537, 13557, 75, 40677, 49181}},
+{7627, 17, 16175, {1, 3, 3, 3, 9, 1, 95, 113, 189, 389, 377, 393, 6523, 3183, 6461, 30201, 66549}},
+{7628, 17, 16178, {1, 1, 7, 15, 13, 19, 41, 171, 475, 157, 949, 3245, 5581, 2783, 25263, 53023, 11155}},
+{7629, 17, 16189, {1, 3, 5, 7, 29, 63, 61, 65, 315, 595, 905, 899, 5059, 4243, 27287, 14023, 64213}},
+{7630, 17, 16202, {1, 3, 1, 3, 15, 37, 109, 161, 9, 867, 1023, 2513, 4593, 7747, 1505, 4801, 127091}},
+{7631, 17, 16204, {1, 3, 1, 7, 11, 59, 75, 129, 469, 695, 63, 2757, 6357, 8675, 6193, 23439, 66445}},
+{7632, 17, 16222, {1, 1, 3, 13, 17, 9, 47, 91, 161, 265, 139, 129, 6707, 9659, 8917, 54757, 77835}},
+{7633, 17, 16231, {1, 1, 3, 13, 19, 37, 113, 255, 99, 913, 1445, 487, 337, 1001, 16395, 37141, 66595}},
+{7634, 17, 16238, {1, 1, 1, 15, 3, 63, 69, 43, 185, 293, 1137, 2061, 2377, 8741, 26817, 5833, 7807}},
+{7635, 17, 16262, {1, 1, 1, 5, 3, 29, 39, 33, 263, 355, 597, 539, 5055, 13075, 8977, 19829, 88171}},
+{7636, 17, 16265, {1, 3, 7, 9, 17, 49, 125, 101, 447, 597, 1337, 559, 2807, 7925, 12421, 17427, 34815}},
+{7637, 17, 16276, {1, 3, 1, 9, 11, 57, 31, 163, 503, 925, 911, 3721, 2515, 8429, 25749, 55209, 90105}},
+{7638, 17, 16285, {1, 3, 5, 3, 21, 57, 119, 233, 319, 745, 563, 3057, 2683, 7063, 11513, 49157, 64561}},
+{7639, 17, 16313, {1, 1, 3, 9, 15, 21, 93, 99, 227, 479, 965, 51, 6941, 9887, 32409, 23171, 98387}},
+{7640, 17, 16314, {1, 3, 5, 5, 19, 1, 47, 49, 233, 931, 971, 2369, 2827, 1291, 18653, 725, 19791}},
+{7641, 17, 16321, {1, 1, 5, 15, 3, 7, 71, 251, 341, 861, 1203, 793, 7627, 10929, 10717, 10677, 49743}},
+{7642, 17, 16327, {1, 3, 1, 7, 3, 43, 9, 187, 247, 621, 1069, 2875, 1525, 4221, 18813, 35807, 117609}},
+{7643, 17, 16333, {1, 3, 3, 3, 29, 39, 83, 201, 205, 337, 231, 547, 2893, 2483, 6197, 26869, 18921}},
+{7644, 17, 16334, {1, 1, 7, 3, 23, 29, 33, 137, 491, 691, 979, 65, 5711, 11685, 5137, 37993, 37075}},
+{7645, 17, 16364, {1, 3, 3, 1, 11, 3, 99, 119, 203, 901, 1887, 879, 7547, 4613, 31233, 13279, 105089}},
+{7646, 17, 16369, {1, 1, 1, 13, 25, 23, 111, 167, 313, 141, 127, 1223, 5711, 4101, 10977, 34695, 128303}},
+{7647, 17, 16370, {1, 1, 7, 15, 5, 3, 89, 151, 289, 769, 539, 2883, 8121, 15403, 22345, 63765, 117015}},
+{7648, 17, 16375, {1, 1, 1, 13, 15, 9, 71, 95, 37, 705, 1575, 3735, 7445, 2027, 27523, 53321, 106085}},
+{7649, 17, 16376, {1, 3, 5, 7, 5, 29, 7, 25, 181, 491, 1173, 1947, 3321, 9233, 17265, 26999, 97783}},
+{7650, 17, 16379, {1, 1, 3, 15, 1, 63, 111, 113, 279, 123, 345, 1529, 2725, 8643, 8551, 30073, 26689}},
+{7651, 17, 16393, {1, 3, 7, 7, 5, 55, 117, 211, 293, 851, 1491, 3265, 4009, 14949, 10297, 16219, 69983}},
+{7652, 17, 16402, {1, 1, 3, 11, 23, 45, 35, 91, 97, 191, 417, 3545, 1733, 3955, 10763, 10229, 75027}},
+{7653, 17, 16408, {1, 1, 3, 13, 3, 61, 69, 205, 379, 627, 295, 3979, 85, 11305, 2493, 35583, 3133}},
+{7654, 17, 16418, {1, 3, 5, 9, 5, 63, 67, 201, 351, 367, 1009, 739, 5409, 8715, 28939, 31511, 34599}},
+{7655, 17, 16438, {1, 1, 1, 5, 3, 25, 21, 25, 477, 301, 623, 157, 563, 9457, 24515, 30135, 107165}},
+{7656, 17, 16441, {1, 1, 3, 15, 5, 41, 49, 171, 469, 427, 857, 2165, 1437, 2151, 24061, 63243, 105331}},
+{7657, 17, 16447, {1, 3, 5, 11, 21, 25, 59, 167, 29, 653, 1503, 2223, 3889, 4605, 28381, 36075, 74907}},
+{7658, 17, 16450, {1, 3, 7, 7, 17, 55, 73, 127, 33, 319, 1565, 2761, 6473, 2187, 19939, 56687, 112137}},
+{7659, 17, 16455, {1, 1, 1, 9, 7, 53, 105, 3, 299, 15, 1009, 607, 6885, 12875, 20719, 16841, 70471}},
+{7660, 17, 16459, {1, 3, 5, 9, 7, 33, 23, 163, 279, 739, 1541, 3017, 2309, 11827, 3875, 44337, 82063}},
+{7661, 17, 16483, {1, 1, 1, 5, 19, 53, 109, 193, 331, 339, 477, 4093, 5177, 13527, 25731, 64137, 81411}},
+{7662, 17, 16490, {1, 3, 7, 13, 15, 63, 101, 145, 127, 13, 1431, 3581, 4993, 14287, 12125, 60217, 102563}},
+{7663, 17, 16492, {1, 3, 1, 7, 17, 27, 127, 81, 223, 763, 761, 2061, 1031, 12251, 14141, 23587, 124813}},
+{7664, 17, 16495, {1, 3, 5, 13, 27, 21, 9, 249, 285, 875, 65, 4075, 6749, 13417, 3079, 29343, 87075}},
+{7665, 17, 16523, {1, 3, 5, 13, 1, 31, 61, 21, 169, 145, 1681, 1229, 5059, 13555, 21373, 35597, 70669}},
+{7666, 17, 16528, {1, 3, 7, 15, 23, 31, 43, 237, 139, 9, 1905, 3197, 801, 14205, 13323, 18717, 88523}},
+{7667, 17, 16543, {1, 1, 1, 11, 1, 7, 21, 83, 15, 459, 537, 4029, 6973, 4019, 1, 35147, 16329}},
+{7668, 17, 16553, {1, 3, 7, 15, 23, 11, 17, 101, 235, 683, 913, 3529, 4363, 13899, 3603, 27741, 74143}},
+{7669, 17, 16562, {1, 1, 7, 7, 3, 3, 91, 107, 499, 723, 315, 2805, 5909, 11041, 18281, 54981, 76041}},
+{7670, 17, 16564, {1, 3, 7, 9, 15, 7, 93, 171, 275, 647, 655, 3565, 2199, 14795, 21945, 9373, 122299}},
+{7671, 17, 16576, {1, 1, 1, 5, 27, 53, 73, 27, 431, 707, 53, 1281, 49, 13199, 1973, 18935, 114821}},
+{7672, 17, 16588, {1, 1, 3, 3, 25, 1, 17, 159, 217, 413, 1393, 2119, 5611, 7659, 6003, 19927, 22287}},
+{7673, 17, 16612, {1, 1, 7, 15, 29, 59, 77, 9, 205, 795, 627, 2167, 2477, 6841, 17663, 34871, 79823}},
+{7674, 17, 16630, {1, 3, 5, 9, 13, 35, 79, 237, 11, 335, 789, 2291, 13, 853, 20373, 39049, 407}},
+{7675, 17, 16654, {1, 1, 5, 7, 13, 27, 21, 173, 137, 659, 123, 2677, 2153, 14879, 26737, 56291, 47613}},
+{7676, 17, 16656, {1, 3, 5, 15, 23, 47, 15, 109, 311, 597, 261, 2407, 8139, 3215, 28169, 60731, 79937}},
+{7677, 17, 16668, {1, 3, 3, 5, 11, 61, 71, 29, 189, 741, 1171, 397, 2669, 10627, 20037, 51703, 6697}},
+{7678, 17, 16672, {1, 3, 3, 3, 9, 41, 125, 1, 381, 399, 349, 3265, 6337, 8113, 14869, 5305, 83409}},
+{7679, 17, 16675, {1, 1, 3, 13, 5, 19, 33, 225, 45, 55, 1809, 1037, 5443, 15719, 9963, 363, 15145}},
+{7680, 17, 16678, {1, 3, 7, 1, 31, 25, 103, 29, 207, 169, 305, 913, 7501, 15323, 10575, 13477, 65245}},
+{7681, 17, 16681, {1, 3, 3, 15, 13, 23, 69, 255, 333, 157, 279, 1989, 3439, 12955, 13649, 52431, 90009}},
+{7682, 17, 16689, {1, 3, 7, 5, 23, 61, 111, 121, 79, 469, 89, 1545, 3405, 12393, 2035, 15989, 84855}},
+{7683, 17, 16699, {1, 1, 7, 5, 17, 21, 127, 151, 283, 521, 5, 3023, 5365, 11633, 21177, 42207, 48925}},
+{7684, 17, 16719, {1, 3, 7, 5, 21, 21, 61, 17, 415, 879, 1485, 3727, 935, 9899, 23241, 651, 103701}},
+{7685, 17, 16734, {1, 3, 5, 15, 31, 47, 19, 245, 249, 467, 253, 1575, 337, 863, 19353, 13153, 125453}},
+{7686, 17, 16737, {1, 1, 7, 15, 9, 41, 39, 63, 139, 875, 1011, 1961, 1627, 7461, 28961, 47195, 16239}},
+{7687, 17, 16750, {1, 3, 3, 7, 27, 55, 51, 245, 231, 619, 43, 91, 2125, 2685, 23661, 10189, 43085}},
+{7688, 17, 16752, {1, 1, 7, 9, 27, 55, 35, 139, 187, 143, 1545, 2685, 3173, 12065, 21607, 42619, 105279}},
+{7689, 17, 16757, {1, 1, 5, 3, 29, 63, 15, 197, 49, 995, 389, 1959, 2441, 11509, 31753, 40539, 26989}},
+{7690, 17, 16761, {1, 3, 7, 15, 19, 37, 17, 37, 305, 469, 945, 2335, 1493, 13843, 19905, 49031, 107893}},
+{7691, 17, 16773, {1, 3, 1, 11, 3, 35, 113, 181, 223, 27, 485, 2435, 3423, 11321, 1687, 45755, 18017}},
+{7692, 17, 16774, {1, 3, 3, 13, 17, 47, 109, 145, 287, 769, 1373, 3423, 1251, 14357, 3209, 28363, 97987}},
+{7693, 17, 16801, {1, 1, 3, 13, 7, 25, 93, 11, 23, 331, 517, 1705, 1957, 291, 763, 10411, 120367}},
+{7694, 17, 16802, {1, 3, 7, 15, 25, 9, 1, 33, 83, 61, 97, 509, 5387, 8701, 14243, 31883, 7375}},
+{7695, 17, 16822, {1, 3, 1, 5, 19, 11, 59, 95, 265, 205, 533, 1857, 693, 12469, 24445, 19449, 130623}},
+{7696, 17, 16831, {1, 1, 7, 7, 1, 5, 15, 159, 333, 361, 391, 1889, 2645, 15115, 30709, 60515, 13315}},
+{7697, 17, 16840, {1, 3, 5, 15, 25, 61, 69, 213, 183, 575, 1573, 3147, 1753, 2387, 23063, 12853, 108507}},
+{7698, 17, 16854, {1, 1, 1, 15, 17, 31, 11, 177, 411, 23, 469, 3985, 2159, 2273, 14175, 20425, 107741}},
+{7699, 17, 16858, {1, 1, 3, 9, 5, 35, 55, 225, 263, 641, 1393, 1277, 595, 2671, 7039, 64999, 114387}},
+{7700, 17, 16863, {1, 1, 3, 3, 11, 23, 1, 161, 77, 755, 1325, 1773, 4291, 13119, 29677, 27295, 81713}},
+{7701, 17, 16867, {1, 1, 5, 13, 31, 45, 115, 141, 449, 171, 1413, 2411, 7937, 10859, 19453, 64403, 45169}},
+{7702, 17, 16876, {1, 3, 5, 7, 1, 27, 117, 157, 99, 119, 1281, 2633, 5117, 16009, 19545, 7421, 30807}},
+{7703, 17, 16891, {1, 1, 3, 13, 19, 11, 61, 239, 331, 731, 1723, 1773, 2623, 15255, 17197, 63793, 100433}},
+{7704, 17, 16894, {1, 3, 7, 11, 11, 7, 119, 33, 195, 521, 811, 2599, 3113, 5497, 16751, 2541, 21813}},
+{7705, 17, 16898, {1, 1, 1, 15, 23, 47, 25, 73, 429, 213, 557, 1613, 7055, 7211, 2225, 1345, 58033}},
+{7706, 17, 16907, {1, 1, 1, 13, 15, 39, 69, 71, 11, 543, 267, 2803, 4853, 9819, 603, 4629, 78343}},
+{7707, 17, 16915, {1, 1, 7, 1, 15, 55, 47, 223, 63, 679, 1135, 3225, 3845, 12031, 6761, 20337, 29021}},
+{7708, 17, 16917, {1, 1, 3, 3, 3, 51, 127, 103, 43, 379, 169, 2549, 7775, 2553, 27415, 30671, 34043}},
+{7709, 17, 16922, {1, 1, 3, 11, 1, 31, 89, 113, 475, 857, 499, 3901, 5343, 8819, 4503, 58757, 60513}},
+{7710, 17, 16924, {1, 3, 5, 11, 27, 49, 97, 217, 91, 971, 1835, 3447, 2021, 3747, 20533, 13659, 84007}},
+{7711, 17, 16933, {1, 1, 5, 1, 31, 39, 49, 21, 135, 983, 579, 3509, 3611, 15101, 29781, 49941, 14353}},
+{7712, 17, 16938, {1, 1, 1, 9, 7, 17, 55, 233, 295, 161, 823, 3823, 4771, 13531, 24197, 42629, 60269}},
+{7713, 17, 16952, {1, 1, 3, 15, 23, 5, 101, 167, 55, 297, 1733, 3819, 7041, 9915, 27803, 60359, 10249}},
+{7714, 17, 16960, {1, 1, 7, 9, 25, 47, 67, 253, 303, 313, 1389, 3785, 2729, 11471, 27267, 42783, 111595}},
+{7715, 17, 16963, {1, 1, 5, 13, 25, 63, 17, 195, 457, 793, 1553, 1673, 6799, 12171, 9003, 22195, 90229}},
+{7716, 17, 16969, {1, 1, 3, 15, 11, 43, 43, 221, 423, 985, 873, 599, 1753, 4875, 7149, 34625, 8941}},
+{7717, 17, 16978, {1, 3, 5, 11, 1, 7, 109, 163, 309, 477, 1291, 3019, 1933, 14055, 15005, 1141, 66867}},
+{7718, 17, 17014, {1, 3, 3, 15, 21, 35, 95, 131, 413, 1009, 147, 2165, 6333, 8313, 20873, 18377, 23579}},
+{7719, 17, 17020, {1, 3, 1, 5, 21, 49, 29, 187, 67, 419, 253, 2345, 3179, 12331, 23127, 8799, 102493}},
+{7720, 17, 17034, {1, 1, 7, 5, 29, 59, 13, 189, 377, 595, 1893, 527, 7993, 14867, 24671, 14585, 38645}},
+{7721, 17, 17036, {1, 3, 5, 13, 3, 11, 99, 69, 253, 833, 1961, 2719, 3953, 8143, 21277, 16257, 26929}},
+{7722, 17, 17042, {1, 3, 7, 3, 3, 19, 19, 57, 393, 187, 945, 2107, 669, 14785, 13895, 26907, 92439}},
+{7723, 17, 17047, {1, 3, 5, 15, 11, 5, 73, 167, 99, 887, 1213, 2019, 3781, 14345, 30249, 16215, 1893}},
+{7724, 17, 17051, {1, 1, 5, 1, 17, 11, 69, 145, 97, 393, 1587, 2513, 1011, 6933, 7945, 41387, 34361}},
+{7725, 17, 17054, {1, 1, 5, 1, 5, 59, 57, 1, 501, 855, 1485, 977, 4981, 7631, 31853, 30737, 103023}},
+{7726, 17, 17063, {1, 3, 1, 5, 3, 27, 55, 171, 317, 641, 1875, 2523, 1631, 4971, 18743, 25119, 118913}},
+{7727, 17, 17069, {1, 1, 3, 15, 7, 39, 73, 209, 125, 29, 1031, 1569, 1793, 5461, 985, 59441, 92997}},
+{7728, 17, 17075, {1, 3, 5, 11, 27, 23, 57, 13, 65, 555, 1309, 1149, 5125, 11573, 3835, 57913, 78699}},
+{7729, 17, 17077, {1, 3, 7, 5, 29, 7, 51, 131, 443, 623, 1491, 1067, 6647, 6277, 25799, 54843, 90869}},
+{7730, 17, 17089, {1, 1, 1, 11, 7, 33, 67, 113, 319, 665, 11, 1225, 3137, 16269, 20101, 40263, 31091}},
+{7731, 17, 17090, {1, 3, 5, 15, 7, 5, 101, 153, 165, 173, 97, 1651, 6633, 6071, 29079, 35641, 77305}},
+{7732, 17, 17107, {1, 3, 7, 13, 9, 45, 103, 55, 121, 1021, 1841, 315, 8127, 6547, 1093, 7181, 39575}},
+{7733, 17, 17126, {1, 3, 3, 11, 15, 17, 27, 55, 341, 443, 377, 681, 3635, 1091, 16719, 49403, 85507}},
+{7734, 17, 17135, {1, 3, 5, 5, 29, 53, 51, 213, 273, 475, 981, 549, 539, 14989, 4037, 23911, 45997}},
+{7735, 17, 17150, {1, 3, 5, 3, 27, 37, 73, 115, 331, 911, 991, 4049, 6299, 3919, 10231, 31507, 98651}},
+{7736, 17, 17162, {1, 1, 5, 13, 21, 13, 1, 175, 137, 837, 1067, 2845, 307, 4399, 15671, 1309, 107409}},
+{7737, 17, 17169, {1, 1, 3, 1, 5, 47, 111, 75, 193, 389, 157, 3731, 6237, 5053, 9933, 28413, 32939}},
+{7738, 17, 17172, {1, 1, 7, 5, 29, 1, 51, 85, 267, 935, 1021, 3135, 3135, 9263, 32597, 6779, 71473}},
+{7739, 17, 17175, {1, 3, 5, 9, 21, 59, 27, 99, 155, 507, 1911, 3501, 4307, 6755, 17127, 29815, 1577}},
+{7740, 17, 17176, {1, 1, 5, 1, 15, 63, 45, 105, 125, 299, 689, 3935, 7229, 5007, 25003, 30453, 27819}},
+{7741, 17, 17191, {1, 1, 7, 15, 19, 9, 67, 151, 45, 985, 2015, 833, 5435, 15383, 25881, 46735, 56717}},
+{7742, 17, 17209, {1, 1, 5, 15, 27, 59, 119, 163, 293, 63, 1251, 1309, 485, 4937, 27207, 47481, 114357}},
+{7743, 17, 17218, {1, 3, 5, 13, 23, 11, 111, 87, 329, 467, 1657, 3309, 3421, 12013, 23163, 14105, 88761}},
+{7744, 17, 17220, {1, 1, 5, 11, 17, 63, 9, 61, 299, 585, 341, 3375, 3213, 15953, 11455, 5333, 66889}},
+{7745, 17, 17227, {1, 3, 5, 5, 5, 35, 57, 235, 137, 543, 77, 2811, 857, 12793, 10791, 55711, 93353}},
+{7746, 17, 17229, {1, 3, 7, 3, 23, 37, 19, 81, 321, 23, 1625, 2359, 3569, 4685, 7385, 32677, 18073}},
+{7747, 17, 17238, {1, 3, 3, 7, 21, 35, 81, 229, 207, 547, 1397, 2709, 7159, 1265, 16823, 9921, 29159}},
+{7748, 17, 17251, {1, 3, 7, 13, 27, 13, 107, 241, 395, 317, 307, 3927, 1153, 15915, 25179, 25173, 21503}},
+{7749, 17, 17257, {1, 3, 1, 5, 1, 51, 25, 135, 381, 229, 1491, 2009, 3331, 16165, 8169, 65161, 9335}},
+{7750, 17, 17258, {1, 1, 5, 5, 17, 15, 57, 221, 183, 225, 1649, 3701, 299, 12349, 4691, 64479, 82237}},
+{7751, 17, 17272, {1, 3, 7, 7, 31, 39, 65, 183, 149, 67, 1697, 3933, 3709, 15501, 12583, 60117, 88691}},
+{7752, 17, 17277, {1, 1, 5, 15, 17, 49, 117, 233, 161, 891, 789, 1347, 4887, 10713, 10613, 4389, 42619}},
+{7753, 17, 17308, {1, 3, 5, 9, 13, 3, 83, 69, 381, 777, 743, 2843, 7233, 3285, 8931, 48667, 120777}},
+{7754, 17, 17311, {1, 3, 1, 3, 11, 7, 55, 107, 165, 533, 1897, 3385, 1069, 12805, 30125, 42729, 123977}},
+{7755, 17, 17321, {1, 1, 1, 5, 13, 17, 103, 237, 77, 537, 1843, 2817, 7467, 13647, 15259, 3525, 18313}},
+{7756, 17, 17329, {1, 1, 7, 7, 13, 59, 29, 197, 309, 917, 1173, 2605, 4313, 12007, 25611, 60409, 104931}},
+{7757, 17, 17342, {1, 3, 3, 3, 27, 57, 7, 207, 491, 467, 1973, 3075, 8043, 3977, 14517, 13179, 47111}},
+{7758, 17, 17344, {1, 1, 7, 5, 31, 33, 125, 235, 79, 847, 1893, 3875, 7513, 1435, 24959, 46813, 82053}},
+{7759, 17, 17350, {1, 3, 7, 5, 3, 53, 103, 1, 215, 71, 787, 223, 1399, 6793, 11281, 39201, 122119}},
+{7760, 17, 17356, {1, 3, 3, 3, 3, 57, 7, 151, 319, 463, 685, 2917, 4037, 14929, 11971, 41827, 57449}},
+{7761, 17, 17371, {1, 1, 7, 3, 5, 11, 15, 139, 379, 563, 135, 65, 5633, 7535, 1451, 18289, 62457}},
+{7762, 17, 17374, {1, 1, 1, 15, 11, 23, 37, 57, 205, 107, 995, 151, 3279, 2015, 28927, 40731, 95551}},
+{7763, 17, 17392, {1, 3, 5, 9, 15, 43, 95, 217, 203, 215, 203, 2207, 8189, 465, 2175, 29285, 25375}},
+{7764, 17, 17402, {1, 3, 3, 5, 19, 59, 51, 123, 285, 721, 1335, 1777, 1645, 15811, 16539, 14637, 123323}},
+{7765, 17, 17410, {1, 3, 5, 5, 11, 35, 23, 23, 259, 789, 567, 1921, 4743, 6635, 6965, 43025, 43175}},
+{7766, 17, 17421, {1, 3, 7, 3, 7, 27, 77, 121, 285, 65, 647, 591, 2553, 7163, 12057, 43675, 24227}},
+{7767, 17, 17424, {1, 1, 5, 9, 3, 25, 17, 85, 235, 715, 1913, 2391, 3719, 11029, 18359, 6323, 4703}},
+{7768, 17, 17427, {1, 1, 1, 3, 25, 31, 37, 31, 89, 311, 1797, 3409, 6785, 9627, 29721, 58591, 111429}},
+{7769, 17, 17434, {1, 3, 1, 5, 9, 37, 47, 45, 419, 115, 1009, 1359, 65, 1161, 15673, 16075, 63895}},
+{7770, 17, 17449, {1, 1, 3, 5, 25, 47, 27, 87, 441, 547, 1801, 3589, 3773, 12215, 14509, 12669, 99983}},
+{7771, 17, 17452, {1, 1, 1, 3, 19, 33, 51, 91, 447, 577, 491, 539, 3177, 7033, 21633, 51737, 47089}},
+{7772, 17, 17463, {1, 1, 3, 15, 23, 53, 93, 113, 143, 973, 999, 2355, 1489, 3451, 29821, 23769, 74633}},
+{7773, 17, 17470, {1, 3, 7, 11, 27, 1, 35, 109, 111, 51, 425, 3203, 2585, 11255, 20939, 281, 92133}},
+{7774, 17, 17477, {1, 1, 1, 11, 13, 37, 13, 149, 421, 655, 79, 3093, 6429, 1145, 27663, 52861, 81431}},
+{7775, 17, 17482, {1, 1, 5, 13, 19, 23, 105, 39, 97, 239, 469, 1047, 4727, 12009, 8055, 45557, 124219}},
+{7776, 17, 17490, {1, 1, 1, 7, 7, 7, 5, 53, 269, 391, 1893, 2263, 2109, 11531, 12109, 31437, 20445}},
+{7777, 17, 17496, {1, 1, 3, 11, 9, 35, 69, 209, 93, 455, 1117, 3297, 2597, 15035, 17943, 19955, 829}},
+{7778, 17, 17508, {1, 1, 5, 7, 23, 23, 101, 71, 339, 553, 1653, 2997, 1191, 3121, 4575, 49979, 17353}},
+{7779, 17, 17511, {1, 3, 3, 13, 13, 9, 51, 181, 33, 185, 111, 589, 3117, 10105, 28811, 31529, 79657}},
+{7780, 17, 17536, {1, 1, 5, 3, 9, 57, 103, 65, 211, 473, 519, 3815, 4087, 2767, 10213, 37829, 9523}},
+{7781, 17, 17563, {1, 1, 5, 7, 7, 31, 81, 161, 311, 617, 1689, 3133, 57, 14595, 22783, 18475, 85811}},
+{7782, 17, 17570, {1, 3, 5, 5, 21, 51, 99, 249, 7, 525, 885, 3981, 2851, 529, 947, 29885, 122901}},
+{7783, 17, 17581, {1, 3, 1, 5, 1, 23, 85, 91, 309, 747, 183, 1347, 2399, 15777, 16205, 15687, 117333}},
+{7784, 17, 17590, {1, 3, 7, 3, 29, 21, 99, 137, 297, 229, 1063, 2747, 6415, 7791, 4775, 62863, 50849}},
+{7785, 17, 17608, {1, 3, 1, 3, 11, 3, 53, 153, 103, 911, 1595, 1899, 1049, 11643, 21105, 61587, 92399}},
+{7786, 17, 17616, {1, 1, 5, 15, 29, 55, 99, 101, 181, 453, 1917, 2081, 4687, 4335, 2817, 11861, 103167}},
+{7787, 17, 17621, {1, 3, 7, 15, 11, 7, 9, 3, 477, 281, 1141, 453, 4993, 7843, 6169, 49785, 53827}},
+{7788, 17, 17628, {1, 3, 7, 11, 25, 61, 77, 159, 83, 95, 1223, 85, 6309, 16145, 18729, 133, 14193}},
+{7789, 17, 17644, {1, 3, 3, 1, 7, 27, 97, 183, 263, 59, 915, 3857, 3349, 8123, 11251, 55163, 125703}},
+{7790, 17, 17649, {1, 3, 5, 5, 17, 33, 57, 55, 503, 811, 953, 349, 1949, 9127, 31015, 14475, 116769}},
+{7791, 17, 17652, {1, 3, 1, 1, 3, 53, 59, 131, 421, 971, 89, 3047, 3513, 13599, 4569, 54525, 54779}},
+{7792, 17, 17679, {1, 1, 3, 11, 9, 45, 95, 123, 197, 257, 1073, 1461, 5, 12701, 12559, 34989, 71631}},
+{7793, 17, 17691, {1, 3, 3, 7, 1, 27, 55, 191, 447, 561, 1975, 2665, 1341, 8969, 18519, 47389, 70847}},
+{7794, 17, 17693, {1, 1, 5, 5, 3, 31, 15, 165, 95, 423, 233, 2309, 7777, 3503, 20105, 3085, 92349}},
+{7795, 17, 17697, {1, 3, 1, 13, 23, 61, 7, 55, 157, 1, 83, 515, 2169, 14397, 18149, 56855, 117265}},
+{7796, 17, 17698, {1, 3, 3, 3, 3, 59, 69, 95, 127, 241, 65, 3145, 491, 13809, 17529, 20223, 96579}},
+{7797, 17, 17700, {1, 1, 1, 5, 13, 43, 117, 163, 305, 955, 2007, 3337, 807, 16019, 5721, 5479, 90937}},
+{7798, 17, 17704, {1, 3, 3, 1, 19, 9, 127, 5, 113, 491, 1873, 2127, 7949, 5207, 32531, 775, 131065}},
+{7799, 17, 17707, {1, 1, 7, 3, 1, 3, 91, 187, 37, 873, 1039, 4075, 5645, 243, 15127, 45615, 3813}},
+{7800, 17, 17715, {1, 1, 3, 11, 3, 37, 67, 59, 439, 763, 213, 1099, 1659, 12783, 30297, 60713, 43497}},
+{7801, 17, 17718, {1, 3, 3, 13, 23, 49, 47, 191, 245, 985, 487, 3165, 7803, 2437, 19073, 30605, 119641}},
+{7802, 17, 17721, {1, 3, 7, 7, 19, 43, 7, 253, 93, 99, 145, 219, 699, 2433, 3009, 565, 99671}},
+{7803, 17, 17722, {1, 1, 3, 13, 7, 5, 9, 23, 219, 155, 925, 3427, 6631, 16353, 4115, 20831, 49525}},
+{7804, 17, 17727, {1, 1, 7, 11, 15, 45, 41, 35, 301, 273, 241, 4031, 5441, 8281, 9341, 8499, 73841}},
+{7805, 17, 17729, {1, 3, 7, 13, 9, 19, 79, 3, 163, 197, 509, 2301, 6971, 11525, 8805, 33805, 111595}},
+{7806, 17, 17747, {1, 3, 3, 1, 15, 45, 69, 253, 155, 639, 1045, 749, 3619, 14871, 18063, 49763, 66687}},
+{7807, 17, 17754, {1, 3, 3, 3, 29, 5, 41, 171, 265, 677, 1719, 2623, 1721, 12243, 18741, 39595, 92873}},
+{7808, 17, 17756, {1, 3, 5, 7, 27, 23, 69, 61, 453, 399, 1857, 3901, 6565, 15595, 1083, 15065, 91249}},
+{7809, 17, 17760, {1, 1, 5, 7, 1, 27, 9, 145, 95, 983, 685, 2079, 5117, 5037, 22695, 53135, 43569}},
+{7810, 17, 17765, {1, 1, 3, 5, 5, 7, 69, 59, 331, 409, 179, 333, 1293, 3863, 9473, 12537, 55605}},
+{7811, 17, 17778, {1, 3, 5, 1, 1, 19, 1, 49, 317, 769, 91, 2073, 1765, 1197, 15029, 52553, 57361}},
+{7812, 17, 17784, {1, 1, 5, 1, 23, 13, 11, 69, 345, 877, 41, 817, 617, 14415, 8337, 53973, 50007}},
+{7813, 17, 17794, {1, 1, 7, 3, 19, 27, 69, 103, 115, 893, 219, 2891, 2813, 9933, 26401, 63323, 30909}},
+{7814, 17, 17805, {1, 1, 5, 5, 27, 15, 119, 3, 11, 783, 541, 2431, 2395, 3921, 15471, 34657, 100295}},
+{7815, 17, 17806, {1, 1, 7, 11, 15, 25, 39, 191, 345, 1001, 1773, 715, 1627, 15957, 30085, 34097, 58747}},
+{7816, 17, 17817, {1, 1, 1, 5, 17, 43, 65, 81, 487, 387, 1359, 145, 2231, 6693, 15857, 59539, 79615}},
+{7817, 17, 17824, {1, 1, 3, 5, 15, 19, 17, 233, 247, 611, 587, 2587, 2321, 2835, 1477, 41991, 88143}},
+{7818, 17, 17839, {1, 3, 3, 15, 27, 15, 53, 61, 359, 989, 283, 3569, 5551, 11849, 20995, 34065, 69407}},
+{7819, 17, 17842, {1, 3, 3, 11, 13, 31, 41, 87, 379, 47, 1289, 3143, 4213, 8643, 17065, 10707, 62773}},
+{7820, 17, 17844, {1, 3, 7, 1, 9, 61, 59, 121, 453, 663, 27, 793, 4501, 7713, 285, 13279, 11633}},
+{7821, 17, 17851, {1, 1, 7, 5, 29, 51, 57, 15, 233, 743, 879, 2317, 3399, 15741, 605, 57529, 87427}},
+{7822, 17, 17862, {1, 1, 1, 1, 19, 59, 51, 119, 273, 403, 1649, 3877, 3561, 10931, 21139, 2599, 77957}},
+{7823, 17, 17868, {1, 3, 1, 3, 5, 1, 79, 131, 251, 585, 359, 2073, 7041, 13611, 22937, 24645, 72827}},
+{7824, 17, 17871, {1, 3, 7, 9, 19, 39, 93, 137, 359, 565, 1123, 1301, 4111, 13683, 1361, 25147, 38315}},
+{7825, 17, 17873, {1, 1, 5, 13, 27, 31, 11, 243, 111, 243, 1615, 1649, 2999, 15873, 19161, 57485, 35819}},
+{7826, 17, 17896, {1, 3, 3, 5, 25, 57, 61, 207, 219, 969, 303, 1165, 6753, 13473, 10789, 52883, 45205}},
+{7827, 17, 17904, {1, 1, 7, 11, 9, 53, 55, 175, 399, 981, 255, 2499, 373, 13131, 26803, 48017, 25599}},
+{7828, 17, 17909, {1, 1, 3, 3, 11, 23, 73, 25, 83, 39, 1813, 747, 3287, 795, 11917, 55509, 105057}},
+{7829, 17, 17920, {1, 3, 7, 15, 29, 59, 47, 171, 219, 875, 71, 123, 8131, 15595, 12471, 62439, 131}},
+{7830, 17, 17923, {1, 3, 5, 13, 9, 27, 119, 233, 323, 943, 375, 3647, 185, 1639, 431, 27225, 130175}},
+{7831, 17, 17947, {1, 3, 7, 3, 7, 17, 31, 155, 89, 835, 1015, 2019, 3973, 7087, 16899, 29591, 40797}},
+{7832, 17, 17950, {1, 3, 3, 1, 3, 11, 83, 231, 209, 537, 1227, 1519, 1059, 14027, 18591, 34031, 125755}},
+{7833, 17, 17956, {1, 3, 3, 1, 7, 39, 19, 99, 169, 961, 385, 1621, 7373, 7459, 8979, 23643, 17101}},
+{7834, 17, 17959, {1, 1, 3, 11, 11, 23, 61, 37, 359, 981, 209, 2555, 2673, 6501, 12731, 10735, 97321}},
+{7835, 17, 17966, {1, 1, 3, 13, 15, 61, 115, 119, 99, 755, 1933, 345, 3133, 12071, 26657, 7133, 18553}},
+{7836, 17, 17971, {1, 3, 1, 5, 17, 7, 29, 119, 445, 911, 89, 19, 6137, 8037, 19527, 22467, 29253}},
+{7837, 17, 17973, {1, 1, 3, 11, 31, 21, 119, 21, 249, 371, 343, 4037, 7539, 14473, 23829, 46415, 60911}},
+{7838, 17, 17992, {1, 1, 7, 9, 21, 53, 29, 149, 467, 893, 479, 359, 1007, 13955, 9667, 10245, 74761}},
+{7839, 17, 18006, {1, 3, 1, 7, 7, 45, 7, 77, 289, 271, 1329, 261, 5675, 8275, 7443, 57945, 117825}},
+{7840, 17, 18009, {1, 1, 1, 3, 21, 57, 117, 77, 287, 119, 1073, 915, 2521, 455, 7433, 56953, 84433}},
+{7841, 17, 18010, {1, 1, 1, 9, 27, 47, 1, 189, 303, 375, 215, 3117, 4541, 12877, 15523, 32317, 104213}},
+{7842, 17, 18022, {1, 1, 3, 1, 13, 39, 37, 249, 371, 159, 1073, 1351, 4703, 2715, 17463, 3945, 51523}},
+{7843, 17, 18039, {1, 3, 5, 5, 29, 15, 79, 25, 61, 995, 1081, 3377, 345, 13773, 4205, 20589, 83591}},
+{7844, 17, 18046, {1, 1, 3, 1, 9, 1, 41, 39, 389, 509, 561, 3273, 1911, 15271, 22655, 34713, 2045}},
+{7845, 17, 18069, {1, 3, 1, 15, 17, 1, 55, 55, 119, 707, 843, 2657, 3687, 11557, 18331, 4935, 110639}},
+{7846, 17, 18074, {1, 3, 5, 1, 23, 35, 119, 215, 471, 643, 1581, 1965, 2627, 2991, 3361, 6737, 111657}},
+{7847, 17, 18076, {1, 3, 5, 7, 9, 19, 33, 197, 33, 993, 1795, 595, 7113, 14721, 12647, 41035, 13669}},
+{7848, 17, 18085, {1, 1, 7, 15, 31, 39, 51, 157, 373, 473, 665, 3541, 6695, 11741, 5617, 17189, 129851}},
+{7849, 17, 18086, {1, 3, 3, 7, 15, 37, 33, 175, 391, 159, 717, 593, 113, 9331, 10685, 59003, 26975}},
+{7850, 17, 18095, {1, 1, 3, 5, 13, 41, 11, 109, 9, 899, 1503, 901, 6237, 7789, 9963, 14923, 63665}},
+{7851, 17, 18100, {1, 3, 7, 7, 25, 61, 3, 231, 235, 29, 1049, 1997, 5371, 9047, 29595, 49239, 108649}},
+{7852, 17, 18109, {1, 1, 3, 5, 27, 1, 53, 209, 315, 747, 1803, 11, 1815, 6539, 8839, 18385, 88681}},
+{7853, 17, 18121, {1, 1, 5, 13, 25, 55, 117, 197, 13, 689, 751, 1203, 2277, 1763, 23453, 54459, 118023}},
+{7854, 17, 18127, {1, 3, 3, 11, 21, 1, 51, 101, 429, 723, 273, 3021, 1491, 9923, 6629, 63741, 98813}},
+{7855, 17, 18129, {1, 1, 1, 15, 17, 25, 111, 251, 43, 403, 465, 17, 787, 6045, 32185, 22921, 115851}},
+{7856, 17, 18132, {1, 1, 5, 11, 11, 13, 13, 93, 489, 941, 1391, 383, 7735, 1921, 16199, 53099, 25181}},
+{7857, 17, 18141, {1, 3, 3, 7, 15, 1, 3, 159, 507, 867, 1589, 2111, 3839, 8989, 12589, 37657, 97055}},
+{7858, 17, 18146, {1, 3, 3, 13, 25, 23, 7, 95, 489, 1001, 105, 2737, 5013, 14465, 25383, 57551, 77425}},
+{7859, 17, 18151, {1, 3, 5, 3, 3, 7, 81, 15, 255, 297, 1183, 655, 741, 3081, 2141, 34493, 103707}},
+{7860, 17, 18157, {1, 1, 7, 9, 27, 57, 49, 121, 21, 239, 829, 2001, 613, 9569, 4419, 20007, 59109}},
+{7861, 17, 18160, {1, 3, 7, 1, 3, 21, 109, 255, 45, 333, 915, 1245, 5893, 765, 28289, 53927, 15335}},
+{7862, 17, 18183, {1, 3, 3, 7, 5, 35, 33, 79, 111, 509, 347, 3915, 2017, 6461, 11847, 17807, 48601}},
+{7863, 17, 18204, {1, 3, 5, 1, 13, 63, 87, 65, 507, 277, 339, 3637, 6289, 719, 9383, 38887, 55061}},
+{7864, 17, 18218, {1, 1, 5, 15, 17, 5, 59, 107, 355, 1021, 1849, 1807, 7679, 305, 31533, 1221, 98165}},
+{7865, 17, 18226, {1, 1, 1, 13, 19, 7, 37, 63, 267, 399, 1451, 2149, 1003, 13635, 18693, 215, 15887}},
+{7866, 17, 18238, {1, 1, 3, 7, 11, 63, 81, 251, 253, 963, 635, 1697, 6393, 9775, 24189, 9099, 106277}},
+{7867, 17, 18245, {1, 3, 3, 13, 17, 47, 63, 47, 279, 879, 271, 1655, 1897, 10743, 2607, 16695, 32779}},
+{7868, 17, 18249, {1, 3, 5, 15, 3, 1, 121, 181, 303, 973, 19, 3327, 3827, 2197, 31857, 22835, 122611}},
+{7869, 17, 18260, {1, 1, 5, 13, 25, 41, 105, 197, 195, 85, 1515, 2735, 7539, 7557, 24297, 38721, 46895}},
+{7870, 17, 18267, {1, 1, 1, 1, 15, 63, 33, 7, 43, 971, 781, 1461, 4483, 2113, 32459, 37653, 68017}},
+{7871, 17, 18270, {1, 3, 3, 9, 7, 1, 65, 183, 171, 695, 191, 3675, 6749, 6823, 3577, 45031, 81597}},
+{7872, 17, 18273, {1, 3, 3, 3, 9, 61, 13, 159, 295, 329, 943, 3293, 79, 14497, 21461, 4667, 96435}},
+{7873, 17, 18274, {1, 1, 7, 9, 29, 37, 117, 215, 295, 591, 1139, 3093, 7469, 7995, 13581, 48075, 5943}},
+{7874, 17, 18276, {1, 3, 1, 9, 11, 11, 117, 255, 419, 551, 1445, 1987, 1169, 14227, 31095, 36041, 63739}},
+{7875, 17, 18283, {1, 1, 7, 15, 17, 25, 81, 27, 87, 463, 1871, 551, 7449, 12231, 28645, 32663, 43037}},
+{7876, 17, 18307, {1, 3, 5, 11, 3, 49, 109, 123, 397, 113, 1269, 2433, 4463, 1257, 2127, 6677, 96009}},
+{7877, 17, 18314, {1, 1, 1, 11, 27, 19, 83, 123, 297, 867, 941, 3929, 3483, 4641, 32505, 48999, 66169}},
+{7878, 17, 18321, {1, 1, 5, 11, 5, 21, 11, 255, 369, 859, 657, 587, 5245, 12973, 22403, 47935, 121375}},
+{7879, 17, 18334, {1, 3, 1, 13, 17, 43, 83, 51, 339, 967, 499, 1485, 5203, 10053, 31707, 31443, 75033}},
+{7880, 17, 18355, {1, 1, 5, 13, 11, 5, 121, 121, 73, 101, 1751, 3805, 1333, 14043, 26957, 27557, 110899}},
+{7881, 17, 18364, {1, 3, 7, 11, 9, 7, 125, 237, 437, 177, 841, 175, 5509, 9157, 3129, 54119, 109315}},
+{7882, 17, 18372, {1, 3, 7, 15, 1, 59, 87, 121, 43, 475, 1589, 1267, 1501, 1585, 31705, 33959, 27247}},
+{7883, 17, 18390, {1, 1, 5, 3, 27, 63, 117, 205, 169, 701, 1081, 2835, 8049, 11875, 4143, 17663, 90043}},
+{7884, 17, 18399, {1, 3, 1, 9, 23, 27, 31, 141, 411, 145, 1177, 3681, 3403, 6943, 10729, 47219, 102713}},
+{7885, 17, 18415, {1, 1, 7, 11, 5, 49, 33, 27, 121, 865, 471, 1871, 6945, 10051, 4493, 7121, 65551}},
+{7886, 17, 18420, {1, 1, 5, 1, 17, 27, 53, 13, 31, 403, 1319, 1381, 1371, 11693, 18805, 54683, 30137}},
+{7887, 17, 18434, {1, 1, 7, 11, 9, 21, 71, 155, 79, 145, 943, 3891, 641, 3163, 28493, 14729, 83391}},
+{7888, 17, 18443, {1, 3, 3, 13, 3, 53, 21, 189, 245, 803, 1625, 4005, 1163, 16033, 5549, 14301, 115859}},
+{7889, 17, 18446, {1, 3, 1, 5, 17, 59, 61, 31, 293, 677, 1753, 1803, 1671, 14619, 22361, 61453, 78203}},
+{7890, 17, 18460, {1, 3, 3, 1, 5, 51, 99, 231, 175, 97, 1335, 689, 1913, 6157, 22757, 52395, 118347}},
+{7891, 17, 18467, {1, 3, 3, 7, 25, 11, 113, 19, 289, 507, 1143, 3437, 7965, 12551, 27603, 8423, 46713}},
+{7892, 17, 18482, {1, 1, 3, 9, 13, 1, 73, 9, 425, 407, 363, 2915, 4269, 2903, 9251, 17733, 80321}},
+{7893, 17, 18484, {1, 1, 3, 11, 31, 47, 37, 211, 433, 237, 1069, 1891, 6175, 9305, 30385, 2497, 94775}},
+{7894, 17, 18501, {1, 1, 3, 1, 23, 5, 113, 103, 427, 587, 1863, 1863, 679, 2575, 13059, 16163, 42289}},
+{7895, 17, 18506, {1, 1, 5, 3, 7, 17, 45, 33, 209, 609, 1897, 95, 5123, 2239, 5483, 60715, 126497}},
+{7896, 17, 18516, {1, 1, 5, 11, 1, 55, 67, 223, 41, 967, 337, 2511, 7879, 1157, 17635, 64081, 421}},
+{7897, 17, 18519, {1, 3, 3, 9, 27, 33, 87, 97, 231, 895, 1337, 829, 47, 8481, 14059, 57209, 109159}},
+{7898, 17, 18547, {1, 3, 7, 1, 25, 5, 41, 161, 393, 523, 1623, 3761, 1933, 8319, 17309, 46717, 97299}},
+{7899, 17, 18569, {1, 1, 1, 11, 5, 55, 19, 191, 41, 791, 1611, 59, 2633, 13873, 25859, 42879, 54807}},
+{7900, 17, 18575, {1, 3, 1, 11, 11, 33, 5, 13, 199, 411, 895, 759, 2735, 16225, 31469, 24081, 31857}},
+{7901, 17, 18589, {1, 1, 7, 13, 27, 57, 21, 191, 389, 977, 1013, 3493, 6401, 15957, 23181, 52461, 41853}},
+{7902, 17, 18590, {1, 3, 7, 5, 23, 19, 117, 117, 427, 923, 1347, 3099, 247, 8879, 5309, 53277, 100625}},
+{7903, 17, 18605, {1, 1, 5, 13, 11, 23, 69, 37, 119, 329, 1935, 2851, 5127, 6907, 24651, 11135, 118287}},
+{7904, 17, 18611, {1, 1, 3, 15, 23, 1, 69, 107, 253, 771, 1697, 4035, 3219, 15011, 6995, 19255, 39909}},
+{7905, 17, 18625, {1, 3, 1, 1, 5, 21, 35, 173, 407, 603, 27, 3589, 2879, 2755, 17679, 6145, 95989}},
+{7906, 17, 18652, {1, 1, 5, 13, 31, 23, 61, 139, 341, 593, 1673, 4031, 4809, 1107, 22657, 29073, 53401}},
+{7907, 17, 18665, {1, 3, 1, 15, 13, 37, 39, 61, 443, 417, 1125, 1529, 1943, 7317, 2985, 50285, 107069}},
+{7908, 17, 18673, {1, 1, 3, 9, 5, 51, 87, 91, 31, 491, 1455, 1685, 2579, 6023, 10989, 64635, 130147}},
+{7909, 17, 18674, {1, 3, 5, 5, 31, 23, 15, 163, 357, 161, 1597, 1571, 5039, 13213, 32221, 4405, 88079}},
+{7910, 17, 18683, {1, 1, 1, 15, 13, 43, 7, 109, 243, 389, 683, 2671, 8003, 4187, 6507, 11171, 116727}},
+{7911, 17, 18688, {1, 3, 7, 1, 17, 31, 53, 5, 227, 755, 1755, 2939, 1789, 8951, 16777, 30203, 79005}},
+{7912, 17, 18691, {1, 3, 3, 9, 27, 5, 111, 241, 89, 333, 371, 1035, 5719, 2433, 29343, 50829, 25131}},
+{7913, 17, 18698, {1, 1, 3, 13, 7, 37, 125, 69, 79, 397, 1595, 123, 255, 2257, 10881, 27085, 99411}},
+{7914, 17, 18717, {1, 1, 3, 15, 1, 35, 61, 73, 507, 775, 1631, 2005, 4277, 8421, 5669, 39221, 19053}},
+{7915, 17, 18733, {1, 1, 3, 7, 15, 17, 65, 157, 19, 997, 861, 1249, 4059, 7975, 955, 5833, 97733}},
+{7916, 17, 18754, {1, 1, 5, 5, 21, 43, 1, 181, 1, 17, 1337, 3333, 3761, 12283, 20941, 231, 30457}},
+{7917, 17, 18759, {1, 3, 3, 7, 7, 23, 105, 101, 101, 757, 1407, 565, 2187, 1529, 29385, 22847, 57675}},
+{7918, 17, 18760, {1, 3, 3, 1, 11, 3, 65, 93, 201, 773, 1037, 1325, 673, 6625, 2909, 63435, 114311}},
+{7919, 17, 18771, {1, 3, 5, 1, 21, 43, 87, 37, 491, 323, 1093, 2493, 4755, 7225, 12037, 9483, 70351}},
+{7920, 17, 18777, {1, 1, 7, 9, 23, 39, 59, 117, 103, 645, 1975, 1177, 55, 325, 23781, 64365, 94915}},
+{7921, 17, 18796, {1, 3, 7, 15, 21, 29, 109, 35, 307, 847, 777, 3457, 7899, 17, 24065, 10517, 35651}},
+{7922, 17, 18799, {1, 1, 7, 9, 25, 35, 49, 131, 377, 429, 1773, 2107, 6305, 15209, 9567, 17685, 5599}},
+{7923, 17, 18807, {1, 1, 3, 11, 13, 27, 47, 125, 483, 229, 921, 2733, 2217, 2615, 24135, 28759, 109411}},
+{7924, 17, 18813, {1, 3, 1, 7, 19, 45, 23, 195, 445, 955, 853, 2877, 6889, 9507, 2009, 18747, 50545}},
+{7925, 17, 18817, {1, 1, 1, 5, 15, 35, 75, 177, 145, 683, 309, 893, 4999, 827, 26563, 30819, 111115}},
+{7926, 17, 18820, {1, 3, 3, 11, 5, 45, 49, 39, 93, 653, 1053, 2553, 863, 12185, 30261, 16459, 121061}},
+{7927, 17, 18827, {1, 3, 7, 5, 11, 29, 57, 43, 409, 71, 67, 3537, 263, 13237, 8825, 58411, 44629}},
+{7928, 17, 18829, {1, 1, 5, 13, 1, 37, 23, 171, 13, 309, 239, 2023, 6233, 8751, 11371, 5825, 77355}},
+{7929, 17, 18838, {1, 3, 1, 13, 5, 1, 47, 217, 369, 609, 453, 879, 4337, 4441, 8785, 51963, 53819}},
+{7930, 17, 18842, {1, 3, 5, 5, 23, 1, 67, 147, 27, 121, 1369, 569, 1519, 11585, 18193, 30889, 78055}},
+{7931, 17, 18848, {1, 1, 1, 13, 11, 53, 33, 37, 419, 111, 1649, 2495, 6105, 12385, 30865, 3683, 63813}},
+{7932, 17, 18853, {1, 3, 3, 5, 17, 35, 107, 235, 471, 735, 1093, 1007, 567, 173, 9623, 39533, 56455}},
+{7933, 17, 18885, {1, 1, 7, 15, 27, 13, 123, 211, 407, 857, 801, 3951, 8153, 4427, 15333, 13217, 92675}},
+{7934, 17, 18890, {1, 1, 1, 7, 11, 61, 99, 131, 121, 119, 1483, 1485, 3521, 13163, 24899, 56849, 111943}},
+{7935, 17, 18898, {1, 3, 3, 1, 19, 1, 29, 139, 127, 557, 1913, 1487, 1381, 185, 11195, 52499, 45059}},
+{7936, 17, 18903, {1, 3, 7, 11, 5, 29, 95, 111, 235, 55, 1101, 2631, 1219, 9867, 22209, 3095, 56793}},
+{7937, 17, 18910, {1, 3, 7, 1, 31, 61, 37, 125, 241, 985, 1079, 1439, 433, 2779, 8463, 59985, 39667}},
+{7938, 17, 18913, {1, 3, 7, 15, 5, 7, 71, 7, 435, 727, 1611, 135, 1421, 8329, 29995, 64243, 58285}},
+{7939, 17, 18931, {1, 3, 3, 15, 27, 11, 121, 27, 281, 499, 267, 2651, 7575, 9499, 5051, 49475, 79573}},
+{7940, 17, 18934, {1, 3, 3, 15, 29, 47, 11, 183, 235, 537, 79, 2467, 3751, 831, 6725, 52173, 108645}},
+{7941, 17, 18956, {1, 3, 5, 13, 23, 31, 23, 19, 477, 511, 727, 183, 5955, 7613, 31979, 8441, 39835}},
+{7942, 17, 18961, {1, 1, 5, 7, 17, 31, 53, 133, 387, 787, 1573, 89, 1975, 1825, 19963, 27203, 124923}},
+{7943, 17, 18968, {1, 1, 1, 9, 3, 15, 125, 135, 89, 37, 517, 3931, 2013, 2143, 25413, 18421, 6097}},
+{7944, 17, 18978, {1, 1, 3, 11, 23, 29, 89, 45, 53, 135, 223, 3523, 7921, 3271, 1819, 40931, 65471}},
+{7945, 17, 18983, {1, 1, 1, 13, 17, 3, 121, 25, 509, 61, 1009, 2009, 7813, 8499, 5807, 63171, 75991}},
+{7946, 17, 18987, {1, 3, 5, 13, 15, 35, 37, 45, 161, 683, 1665, 59, 6297, 9595, 10193, 46745, 105411}},
+{7947, 17, 18992, {1, 3, 1, 7, 21, 19, 85, 107, 3, 845, 673, 1271, 7581, 15971, 27085, 35375, 29027}},
+{7948, 17, 18997, {1, 3, 3, 9, 5, 17, 79, 137, 123, 809, 583, 3507, 7559, 2857, 13911, 57083, 8595}},
+{7949, 17, 19002, {1, 1, 7, 5, 31, 29, 77, 33, 439, 787, 1223, 2471, 5851, 15891, 27925, 51661, 82645}},
+{7950, 17, 19004, {1, 1, 7, 15, 19, 35, 35, 37, 197, 245, 799, 3971, 277, 11289, 20111, 13857, 104571}},
+{7951, 17, 19010, {1, 3, 5, 15, 19, 3, 65, 17, 201, 1007, 1665, 107, 2409, 1469, 23265, 24547, 8189}},
+{7952, 17, 19012, {1, 3, 1, 13, 29, 45, 109, 243, 43, 383, 631, 265, 6671, 15333, 21931, 30675, 103077}},
+{7953, 17, 19030, {1, 1, 5, 1, 25, 25, 77, 189, 109, 777, 1485, 2265, 1403, 2627, 13843, 27263, 14263}},
+{7954, 17, 19043, {1, 3, 5, 1, 13, 49, 73, 107, 225, 243, 1253, 3503, 735, 2605, 27165, 45467, 93001}},
+{7955, 17, 19049, {1, 1, 5, 9, 15, 17, 1, 33, 69, 321, 1375, 3635, 8131, 6579, 1225, 38699, 17447}},
+{7956, 17, 19079, {1, 3, 5, 3, 25, 49, 15, 149, 483, 37, 1929, 1219, 5841, 11975, 805, 31339, 130971}},
+{7957, 17, 19086, {1, 3, 3, 3, 15, 29, 3, 143, 291, 593, 1769, 3603, 1693, 151, 27701, 9015, 25847}},
+{7958, 17, 19100, {1, 3, 1, 11, 5, 35, 55, 127, 137, 71, 967, 2501, 1023, 2061, 31387, 44011, 130121}},
+{7959, 17, 19103, {1, 1, 7, 1, 29, 13, 93, 41, 125, 263, 521, 2633, 4361, 12153, 30647, 55883, 65185}},
+{7960, 17, 19107, {1, 3, 7, 9, 23, 19, 61, 197, 139, 463, 1867, 3627, 5185, 8251, 26977, 48027, 66301}},
+{7961, 17, 19109, {1, 3, 3, 7, 27, 53, 25, 137, 175, 155, 1843, 2253, 4797, 4989, 32613, 55779, 91625}},
+{7962, 17, 19113, {1, 3, 3, 11, 1, 5, 21, 233, 295, 675, 47, 2995, 8075, 8201, 3845, 23925, 82559}},
+{7963, 17, 19116, {1, 1, 3, 7, 31, 53, 93, 21, 307, 709, 9, 3061, 3935, 11009, 13411, 3657, 30251}},
+{7964, 17, 19127, {1, 3, 7, 13, 13, 25, 51, 205, 391, 897, 275, 333, 6831, 9383, 16101, 14301, 99101}},
+{7965, 17, 19134, {1, 1, 5, 15, 17, 47, 119, 7, 189, 765, 753, 2909, 3373, 2379, 20331, 61535, 51345}},
+{7966, 17, 19141, {1, 1, 3, 1, 27, 43, 9, 185, 9, 197, 1179, 67, 7689, 9679, 29683, 29905, 29393}},
+{7967, 17, 19179, {1, 1, 5, 5, 31, 55, 69, 9, 477, 91, 1705, 1877, 5463, 15401, 13449, 27541, 125521}},
+{7968, 17, 19193, {1, 1, 7, 15, 15, 33, 11, 233, 69, 771, 845, 2715, 5293, 10351, 19557, 15319, 36857}},
+{7969, 17, 19194, {1, 3, 7, 7, 15, 9, 123, 47, 165, 739, 361, 1675, 2743, 8021, 10241, 48275, 51935}},
+{7970, 17, 19201, {1, 1, 5, 1, 9, 25, 99, 83, 487, 627, 343, 3233, 6697, 13197, 19771, 38337, 89139}},
+{7971, 17, 19208, {1, 3, 7, 13, 1, 31, 15, 63, 463, 621, 935, 1093, 6043, 14051, 13665, 43413, 104893}},
+{7972, 17, 19214, {1, 1, 1, 3, 27, 1, 47, 151, 127, 357, 689, 3263, 141, 4459, 9847, 205, 88493}},
+{7973, 17, 19225, {1, 3, 7, 15, 29, 13, 41, 113, 495, 421, 195, 197, 6857, 10555, 22861, 30229, 31707}},
+{7974, 17, 19226, {1, 3, 5, 11, 11, 1, 89, 227, 425, 623, 1605, 1901, 7933, 7211, 16301, 3403, 59651}},
+{7975, 17, 19235, {1, 1, 3, 3, 27, 41, 37, 89, 395, 903, 1641, 2739, 5599, 11371, 8683, 61125, 105231}},
+{7976, 17, 19242, {1, 3, 7, 9, 1, 17, 51, 233, 507, 783, 459, 1187, 7281, 15809, 27637, 6067, 125877}},
+{7977, 17, 19264, {1, 3, 1, 3, 13, 57, 5, 199, 261, 357, 1255, 1849, 8013, 10313, 9375, 1271, 64117}},
+{7978, 17, 19267, {1, 3, 1, 11, 9, 59, 55, 95, 401, 423, 1657, 513, 3565, 12957, 19243, 53027, 11323}},
+{7979, 17, 19293, {1, 3, 7, 13, 27, 35, 121, 215, 397, 991, 191, 3443, 3829, 6107, 5381, 48497, 107997}},
+{7980, 17, 19309, {1, 1, 5, 5, 19, 15, 21, 53, 165, 835, 1599, 3245, 5609, 5991, 18141, 28075, 102809}},
+{7981, 17, 19318, {1, 3, 5, 9, 25, 21, 71, 15, 453, 475, 915, 3097, 5869, 699, 13883, 34919, 127211}},
+{7982, 17, 19324, {1, 1, 3, 7, 21, 53, 27, 207, 373, 703, 593, 17, 6991, 15013, 10125, 34801, 129245}},
+{7983, 17, 19337, {1, 3, 3, 13, 17, 9, 89, 95, 291, 681, 1415, 2323, 2885, 11381, 7703, 3691, 51505}},
+{7984, 17, 19340, {1, 1, 1, 11, 15, 63, 55, 153, 373, 665, 983, 3987, 5997, 6873, 27031, 65449, 22021}},
+{7985, 17, 19345, {1, 1, 5, 5, 1, 55, 119, 61, 159, 889, 225, 709, 1879, 2521, 69, 7815, 18733}},
+{7986, 17, 19346, {1, 3, 5, 11, 23, 53, 23, 61, 71, 993, 633, 1829, 3465, 12465, 30205, 40723, 74499}},
+{7987, 17, 19352, {1, 3, 3, 1, 17, 37, 19, 43, 55, 133, 1171, 3101, 3963, 5177, 24791, 7255, 10263}},
+{7988, 17, 19364, {1, 3, 7, 1, 21, 13, 21, 87, 237, 629, 1167, 3699, 597, 6251, 11545, 34429, 104393}},
+{7989, 17, 19382, {1, 1, 7, 1, 11, 53, 105, 111, 463, 869, 549, 2423, 17, 917, 879, 49367, 72235}},
+{7990, 17, 19391, {1, 1, 5, 15, 17, 51, 69, 55, 309, 867, 257, 573, 4821, 5245, 28033, 61801, 18253}},
+{7991, 17, 19405, {1, 1, 5, 3, 1, 23, 103, 241, 13, 267, 21, 1751, 6637, 12537, 26741, 40651, 94493}},
+{7992, 17, 19411, {1, 3, 3, 13, 25, 35, 21, 83, 337, 363, 1111, 1865, 7889, 985, 465, 40287, 64469}},
+{7993, 17, 19439, {1, 1, 7, 5, 27, 1, 99, 95, 209, 211, 1445, 1577, 6097, 13813, 22463, 64395, 106383}},
+{7994, 17, 19442, {1, 3, 1, 15, 1, 45, 77, 247, 273, 1023, 1377, 1989, 5787, 15267, 24363, 42717, 125617}},
+{7995, 17, 19444, {1, 1, 1, 3, 9, 49, 79, 171, 427, 439, 1725, 3179, 6263, 12437, 31353, 22077, 94455}},
+{7996, 17, 19451, {1, 3, 5, 11, 11, 45, 57, 97, 409, 935, 967, 2509, 3431, 5707, 19473, 15853, 129059}},
+{7997, 17, 19465, {1, 1, 7, 5, 7, 21, 105, 29, 359, 145, 1691, 131, 6721, 10971, 16173, 38193, 37091}},
+{7998, 17, 19471, {1, 1, 1, 15, 15, 35, 5, 185, 455, 507, 681, 3355, 2091, 3437, 27231, 28527, 5383}},
+{7999, 17, 19474, {1, 3, 5, 3, 7, 29, 33, 127, 57, 495, 1069, 3635, 7461, 9861, 18757, 39039, 92421}},
+{8000, 17, 19476, {1, 3, 5, 5, 11, 31, 51, 59, 413, 417, 1577, 2837, 5229, 4501, 18645, 37613, 31325}},
+{8001, 17, 19479, {1, 1, 5, 13, 15, 61, 17, 247, 413, 817, 907, 2249, 3901, 11275, 7469, 33403, 30629}},
+{8002, 17, 19485, {1, 3, 5, 7, 31, 7, 109, 177, 277, 75, 449, 3029, 7135, 427, 26641, 43157, 47671}},
+{8003, 17, 19489, {1, 3, 7, 13, 29, 63, 21, 187, 471, 289, 835, 3885, 6111, 8721, 9841, 24017, 18673}},
+{8004, 17, 19496, {1, 1, 5, 13, 25, 37, 15, 35, 227, 623, 47, 189, 3443, 1911, 8579, 50911, 10895}},
+{8005, 17, 19507, {1, 3, 1, 1, 29, 53, 89, 101, 251, 203, 821, 2485, 633, 7943, 27563, 58735, 72057}},
+{8006, 17, 19513, {1, 3, 7, 9, 23, 61, 121, 199, 19, 165, 131, 1373, 637, 7307, 7109, 42475, 126669}},
+{8007, 17, 19514, {1, 3, 7, 13, 7, 5, 125, 173, 365, 65, 565, 751, 3343, 13421, 6177, 39095, 97375}},
+{8008, 17, 19521, {1, 1, 7, 3, 1, 59, 65, 39, 307, 793, 887, 3291, 3405, 4497, 19351, 1821, 67861}},
+{8009, 17, 19524, {1, 1, 1, 3, 19, 9, 101, 183, 163, 819, 769, 49, 5293, 3715, 4055, 32403, 90763}},
+{8010, 17, 19546, {1, 3, 3, 1, 27, 31, 21, 123, 457, 1021, 1791, 2217, 6171, 11445, 15605, 59945, 19663}},
+{8011, 17, 19552, {1, 1, 1, 9, 13, 53, 61, 201, 457, 111, 1217, 377, 5871, 4591, 16379, 42817, 129807}},
+{8012, 17, 19555, {1, 3, 1, 5, 23, 37, 25, 7, 125, 651, 349, 3727, 1487, 5103, 31407, 40215, 16065}},
+{8013, 17, 19557, {1, 1, 3, 11, 19, 29, 1, 193, 13, 287, 331, 985, 5391, 7307, 28075, 9939, 84999}},
+{8014, 17, 19575, {1, 1, 1, 11, 21, 37, 117, 241, 229, 957, 2019, 819, 459, 6185, 21533, 64725, 24709}},
+{8015, 17, 19579, {1, 3, 5, 13, 11, 25, 107, 245, 175, 519, 629, 537, 2227, 15123, 10619, 32611, 118697}},
+{8016, 17, 19591, {1, 3, 1, 11, 5, 53, 119, 253, 489, 181, 1365, 3465, 1323, 949, 3657, 2467, 38545}},
+{8017, 17, 19595, {1, 1, 3, 9, 27, 17, 109, 19, 297, 541, 89, 3021, 761, 5577, 907, 21405, 128029}},
+{8018, 17, 19605, {1, 1, 3, 9, 31, 9, 61, 149, 267, 707, 671, 2733, 1247, 14623, 6395, 42579, 30845}},
+{8019, 17, 19615, {1, 1, 7, 7, 25, 29, 63, 41, 309, 275, 2019, 1373, 1003, 13891, 16571, 16209, 30115}},
+{8020, 17, 19616, {1, 3, 7, 1, 5, 21, 53, 97, 475, 799, 1963, 1181, 4187, 8767, 24779, 10403, 98349}},
+{8021, 17, 19626, {1, 3, 3, 13, 19, 9, 125, 227, 347, 535, 353, 3087, 769, 9049, 20145, 27433, 23105}},
+{8022, 17, 19631, {1, 1, 1, 15, 7, 61, 51, 113, 403, 501, 1767, 2785, 7151, 14517, 17533, 24913, 7121}},
+{8023, 17, 19634, {1, 1, 1, 9, 7, 21, 27, 169, 425, 567, 31, 35, 7859, 929, 6545, 33983, 13227}},
+{8024, 17, 19640, {1, 1, 5, 15, 11, 15, 69, 33, 127, 1005, 1947, 989, 6333, 15587, 18523, 53547, 115613}},
+{8025, 17, 19645, {1, 3, 5, 3, 1, 55, 7, 99, 213, 737, 363, 3167, 3949, 3723, 15777, 23207, 22901}},
+{8026, 17, 19678, {1, 1, 1, 9, 9, 29, 121, 85, 467, 811, 1, 3543, 6259, 4477, 31371, 27633, 22995}},
+{8027, 17, 19681, {1, 3, 5, 3, 11, 21, 95, 19, 55, 71, 803, 3655, 3749, 5113, 13611, 38097, 20943}},
+{8028, 17, 19682, {1, 3, 3, 11, 19, 25, 127, 105, 447, 499, 485, 881, 2649, 10297, 22283, 18305, 128919}},
+{8029, 17, 19706, {1, 3, 7, 1, 11, 45, 21, 87, 481, 645, 815, 793, 5763, 3945, 14379, 19623, 103199}},
+{8030, 17, 19708, {1, 3, 5, 1, 3, 45, 39, 229, 359, 151, 1079, 3955, 2107, 9593, 6701, 2811, 55215}},
+{8031, 17, 19713, {1, 3, 7, 7, 27, 59, 69, 211, 373, 643, 977, 3545, 2647, 10473, 27919, 10719, 24823}},
+{8032, 17, 19714, {1, 1, 3, 11, 7, 27, 117, 21, 59, 679, 969, 3813, 2701, 7363, 17525, 31229, 100665}},
+{8033, 17, 19720, {1, 3, 3, 5, 29, 53, 113, 141, 197, 991, 81, 2701, 6831, 7949, 16569, 44185, 29631}},
+{8034, 17, 19725, {1, 1, 1, 3, 1, 31, 9, 101, 347, 585, 577, 2529, 7461, 11921, 29475, 34505, 74911}},
+{8035, 17, 19743, {1, 1, 1, 15, 25, 19, 95, 37, 93, 755, 1891, 2309, 623, 13503, 5811, 45863, 106501}},
+{8036, 17, 19753, {1, 1, 5, 3, 15, 23, 51, 225, 87, 679, 1225, 4015, 3971, 163, 3185, 12921, 51267}},
+{8037, 17, 19756, {1, 1, 5, 1, 1, 37, 105, 181, 379, 657, 571, 2775, 5905, 8391, 32069, 18713, 125833}},
+{8038, 17, 19759, {1, 1, 7, 11, 11, 19, 109, 125, 371, 321, 629, 2165, 2861, 7883, 15503, 37679, 33057}},
+{8039, 17, 19762, {1, 1, 3, 5, 7, 5, 21, 5, 169, 321, 1145, 2243, 6143, 2537, 4429, 56493, 39391}},
+{8040, 17, 19776, {1, 3, 5, 5, 31, 7, 15, 175, 441, 663, 921, 3113, 2261, 13033, 19135, 28657, 92225}},
+{8041, 17, 19786, {1, 3, 1, 11, 13, 9, 25, 57, 297, 3, 1561, 825, 2803, 11327, 2699, 28631, 57277}},
+{8042, 17, 19799, {1, 1, 3, 9, 15, 25, 81, 197, 345, 341, 1557, 1375, 2509, 11949, 30201, 6807, 95199}},
+{8043, 17, 19800, {1, 3, 5, 3, 15, 23, 91, 147, 277, 59, 495, 1423, 1775, 12065, 8401, 22639, 111199}},
+{8044, 17, 19803, {1, 1, 5, 1, 1, 59, 35, 255, 229, 293, 187, 2663, 3967, 6493, 20103, 36703, 108939}},
+{8045, 17, 19806, {1, 3, 7, 11, 15, 1, 23, 39, 27, 281, 11, 3119, 2791, 1691, 16521, 39715, 32145}},
+{8046, 17, 19815, {1, 3, 5, 5, 9, 53, 43, 49, 107, 1015, 431, 3017, 3317, 9655, 19193, 45621, 56861}},
+{8047, 17, 19816, {1, 3, 1, 15, 27, 63, 127, 31, 21, 245, 1503, 3339, 6375, 5411, 12369, 35973, 9473}},
+{8048, 17, 19857, {1, 1, 3, 13, 31, 61, 19, 99, 25, 593, 539, 1807, 673, 12339, 23567, 22005, 130341}},
+{8049, 17, 19860, {1, 1, 5, 3, 3, 3, 13, 183, 255, 41, 641, 581, 6509, 1891, 19195, 28277, 51725}},
+{8050, 17, 19874, {1, 1, 3, 5, 3, 59, 17, 227, 9, 345, 1303, 1535, 3089, 2653, 20647, 63159, 124677}},
+{8051, 17, 19883, {1, 3, 1, 11, 25, 19, 117, 29, 221, 461, 1285, 1427, 7183, 3051, 10839, 47491, 92613}},
+{8052, 17, 19885, {1, 1, 3, 5, 27, 19, 1, 235, 51, 215, 783, 2325, 1191, 4679, 14365, 35479, 65083}},
+{8053, 17, 19886, {1, 3, 3, 5, 27, 17, 79, 185, 259, 369, 1399, 1029, 2219, 10975, 30487, 15247, 39789}},
+{8054, 17, 19893, {1, 3, 3, 1, 13, 13, 59, 119, 249, 471, 1433, 1165, 5345, 4431, 375, 64999, 85577}},
+{8055, 17, 19932, {1, 1, 1, 3, 1, 19, 13, 243, 35, 675, 321, 3625, 7835, 6403, 651, 48283, 91819}},
+{8056, 17, 19960, {1, 3, 3, 1, 27, 13, 73, 159, 145, 59, 287, 2419, 8115, 7923, 18933, 36109, 123879}},
+{8057, 17, 19972, {1, 3, 1, 7, 21, 1, 83, 245, 477, 623, 391, 129, 6897, 3447, 11109, 17017, 68277}},
+{8058, 17, 19975, {1, 1, 3, 11, 13, 43, 119, 93, 99, 393, 1219, 995, 1881, 7929, 4337, 33579, 103211}},
+{8059, 17, 20005, {1, 1, 7, 7, 31, 5, 39, 25, 119, 819, 409, 2395, 151, 12763, 28265, 28909, 35685}},
+{8060, 17, 20009, {1, 1, 1, 1, 3, 13, 59, 205, 19, 843, 1691, 955, 1859, 1791, 22083, 37843, 63615}},
+{8061, 17, 20010, {1, 1, 1, 3, 11, 63, 41, 243, 103, 875, 1337, 3731, 6317, 12951, 31743, 56935, 55975}},
+{8062, 17, 20012, {1, 1, 3, 13, 19, 11, 51, 97, 469, 279, 1621, 3521, 853, 11849, 3331, 27907, 119081}},
+{8063, 17, 20023, {1, 1, 5, 1, 23, 55, 9, 141, 449, 41, 167, 2441, 6783, 2785, 3547, 35379, 74973}},
+{8064, 17, 20024, {1, 1, 5, 3, 15, 55, 13, 75, 107, 153, 1841, 3991, 3229, 6523, 18541, 21571, 31539}},
+{8065, 17, 20030, {1, 3, 1, 1, 27, 37, 35, 201, 401, 867, 1861, 1783, 6255, 14001, 29543, 25843, 39719}},
+{8066, 17, 20038, {1, 1, 7, 15, 3, 43, 113, 173, 297, 457, 1369, 4053, 5033, 5513, 27387, 14725, 79937}},
+{8067, 17, 20041, {1, 1, 5, 13, 5, 27, 109, 93, 187, 833, 1551, 2899, 1681, 6979, 1289, 3507, 66499}},
+{8068, 17, 20055, {1, 1, 3, 11, 11, 47, 121, 29, 129, 807, 2037, 1527, 6083, 14803, 10669, 46047, 70241}},
+{8069, 17, 20059, {1, 3, 1, 9, 29, 3, 19, 191, 461, 527, 1389, 3359, 81, 6773, 12185, 49207, 19091}},
+{8070, 17, 20061, {1, 3, 7, 7, 5, 47, 33, 27, 445, 1, 149, 343, 4827, 91, 29233, 37775, 89321}},
+{8071, 17, 20080, {1, 3, 5, 1, 13, 55, 107, 99, 259, 591, 983, 3863, 1231, 3457, 29645, 10709, 16543}},
+{8072, 17, 20086, {1, 3, 7, 9, 29, 5, 9, 165, 337, 187, 219, 97, 6511, 193, 23947, 36329, 35317}},
+{8073, 17, 20089, {1, 3, 7, 1, 31, 25, 5, 175, 409, 1021, 1873, 289, 7143, 15341, 31501, 25707, 106453}},
+{8074, 17, 20095, {1, 3, 7, 7, 27, 1, 15, 221, 341, 987, 1739, 1183, 8139, 11081, 29721, 42991, 72805}},
+{8075, 17, 20111, {1, 1, 1, 9, 11, 1, 13, 17, 501, 543, 1485, 987, 1861, 8527, 1621, 30461, 23057}},
+{8076, 17, 20116, {1, 3, 7, 7, 9, 41, 1, 253, 71, 1009, 427, 3347, 6987, 3303, 30535, 33345, 126459}},
+{8077, 17, 20130, {1, 1, 1, 7, 11, 11, 15, 11, 305, 559, 1805, 1111, 377, 1495, 13471, 34831, 123125}},
+{8078, 17, 20136, {1, 1, 5, 7, 9, 37, 27, 45, 61, 705, 263, 3181, 7077, 5227, 28121, 42865, 3809}},
+{8079, 17, 20147, {1, 1, 5, 1, 23, 25, 29, 199, 259, 959, 661, 43, 6157, 1547, 1497, 24077, 129939}},
+{8080, 17, 20153, {1, 3, 5, 3, 13, 49, 33, 19, 367, 891, 1777, 3119, 5673, 8383, 14487, 1763, 63495}},
+{8081, 17, 20156, {1, 1, 1, 13, 9, 57, 35, 181, 7, 225, 449, 3843, 6257, 4983, 31307, 16559, 27633}},
+{8082, 17, 20167, {1, 3, 1, 11, 7, 33, 55, 81, 41, 61, 1711, 3273, 7629, 11283, 9103, 24105, 107547}},
+{8083, 17, 20173, {1, 3, 5, 5, 13, 17, 13, 51, 235, 869, 1543, 1249, 7749, 14773, 21751, 53497, 108709}},
+{8084, 17, 20182, {1, 1, 3, 9, 3, 63, 89, 43, 23, 479, 115, 3917, 7943, 7323, 5659, 64507, 46941}},
+{8085, 17, 20185, {1, 1, 3, 1, 25, 63, 25, 169, 459, 633, 1785, 1059, 5113, 4799, 29281, 24561, 17017}},
+{8086, 17, 20202, {1, 1, 3, 3, 15, 3, 11, 173, 493, 5, 1575, 653, 7391, 7453, 8297, 28653, 6213}},
+{8087, 17, 20209, {1, 1, 7, 5, 29, 5, 1, 57, 75, 479, 787, 3417, 3349, 111, 17787, 41141, 97597}},
+{8088, 17, 20229, {1, 3, 7, 1, 11, 7, 107, 159, 435, 159, 1401, 803, 7065, 5923, 4005, 37271, 113791}},
+{8089, 17, 20233, {1, 1, 5, 1, 23, 55, 7, 59, 351, 801, 1279, 3231, 4561, 2857, 20563, 46115, 79489}},
+{8090, 17, 20236, {1, 3, 3, 15, 19, 13, 113, 33, 149, 175, 1127, 3815, 4357, 12645, 4449, 61355, 83023}},
+{8091, 17, 20241, {1, 1, 7, 15, 3, 17, 41, 57, 243, 319, 1631, 2751, 7853, 5977, 28367, 20023, 56049}},
+{8092, 17, 20242, {1, 3, 1, 7, 27, 59, 7, 13, 497, 241, 1827, 2861, 1331, 1759, 6037, 18967, 42849}},
+{8093, 17, 20248, {1, 3, 1, 1, 31, 43, 41, 183, 241, 219, 335, 2331, 755, 10589, 29431, 29007, 66667}},
+{8094, 17, 20278, {1, 1, 3, 1, 27, 37, 61, 117, 471, 39, 139, 3821, 2945, 7035, 23673, 20167, 56169}},
+{8095, 17, 20282, {1, 3, 1, 1, 9, 29, 123, 61, 171, 1015, 1029, 1695, 1039, 11883, 259, 10879, 97709}},
+{8096, 17, 20299, {1, 3, 3, 5, 29, 39, 65, 193, 285, 635, 999, 717, 5465, 1849, 4293, 19775, 79121}},
+{8097, 17, 20307, {1, 1, 7, 1, 3, 3, 103, 15, 451, 307, 1027, 263, 6585, 11651, 14457, 62695, 38407}},
+{8098, 17, 20313, {1, 3, 7, 11, 13, 13, 29, 83, 267, 561, 2041, 13, 3167, 3475, 14735, 34455, 117533}},
+{8099, 17, 20314, {1, 3, 1, 15, 5, 1, 35, 225, 151, 637, 1347, 833, 7077, 13145, 10285, 46583, 14351}},
+{8100, 17, 20320, {1, 1, 3, 15, 27, 63, 119, 159, 209, 421, 1413, 2727, 1607, 7175, 6133, 29051, 97387}},
+{8101, 17, 20326, {1, 1, 3, 5, 9, 29, 35, 93, 353, 903, 1037, 469, 5473, 7193, 21883, 14709, 89023}},
+{8102, 17, 20332, {1, 1, 1, 11, 9, 17, 51, 155, 145, 443, 1985, 423, 4721, 15721, 9747, 10303, 21909}},
+{8103, 17, 20350, {1, 3, 7, 15, 19, 49, 53, 153, 241, 739, 1585, 3945, 4869, 11, 15845, 17937, 69397}},
+{8104, 17, 20360, {1, 1, 5, 7, 19, 53, 43, 211, 327, 723, 1513, 1569, 919, 1771, 11309, 50787, 7459}},
+{8105, 17, 20371, {1, 1, 1, 9, 7, 29, 49, 89, 409, 685, 201, 1327, 2807, 13101, 2485, 62909, 102595}},
+{8106, 17, 20373, {1, 3, 1, 13, 21, 51, 37, 231, 271, 475, 855, 3703, 4447, 5161, 17937, 14471, 47173}},
+{8107, 17, 20377, {1, 1, 7, 3, 9, 7, 121, 197, 71, 147, 1669, 1745, 6589, 15029, 1529, 12625, 121925}},
+{8108, 17, 20390, {1, 1, 1, 3, 7, 47, 63, 61, 187, 341, 919, 307, 389, 14141, 12941, 17917, 104289}},
+{8109, 17, 20396, {1, 3, 5, 13, 19, 43, 57, 11, 383, 311, 1229, 3527, 3301, 12473, 24377, 16279, 92733}},
+{8110, 17, 20404, {1, 3, 3, 5, 25, 35, 63, 23, 131, 481, 809, 3627, 5685, 13695, 14121, 64751, 66181}},
+{8111, 17, 20413, {1, 3, 1, 5, 11, 43, 89, 55, 103, 219, 1861, 3223, 5111, 5879, 31399, 1395, 87419}},
+{8112, 17, 20434, {1, 3, 1, 11, 21, 27, 123, 205, 47, 923, 7, 1635, 4019, 8431, 28313, 24275, 129617}},
+{8113, 17, 20436, {1, 1, 1, 3, 1, 11, 91, 215, 393, 999, 1071, 3225, 4415, 759, 24499, 16109, 33791}},
+{8114, 17, 20440, {1, 1, 3, 13, 19, 45, 77, 103, 105, 395, 529, 3631, 8179, 4467, 30263, 39379, 70507}},
+{8115, 17, 20443, {1, 3, 3, 9, 17, 45, 101, 219, 433, 971, 471, 1243, 6955, 5941, 20641, 16119, 129383}},
+{8116, 17, 20445, {1, 1, 7, 7, 9, 9, 91, 95, 503, 171, 129, 1509, 7179, 5367, 2219, 50445, 112459}},
+{8117, 17, 20464, {1, 3, 7, 1, 17, 17, 19, 173, 229, 519, 147, 1835, 3797, 8091, 20335, 33177, 90197}},
+{8118, 17, 20476, {1, 3, 3, 5, 23, 29, 107, 205, 43, 969, 799, 1239, 1353, 5221, 15175, 42945, 34043}},
+{8119, 17, 20494, {1, 1, 5, 7, 31, 63, 67, 87, 189, 301, 1719, 3937, 965, 2505, 24781, 25133, 91675}},
+{8120, 17, 20496, {1, 3, 1, 7, 15, 25, 11, 39, 281, 35, 1149, 1445, 6451, 12069, 20959, 29895, 60059}},
+{8121, 17, 20501, {1, 1, 5, 1, 1, 17, 65, 213, 359, 561, 2015, 1629, 3521, 6877, 8099, 62483, 103903}},
+{8122, 17, 20518, {1, 1, 7, 9, 7, 49, 1, 227, 49, 823, 1141, 2419, 2697, 13293, 14143, 6323, 16081}},
+{8123, 17, 20527, {1, 3, 3, 1, 9, 13, 99, 235, 343, 601, 927, 183, 4545, 14529, 5521, 55571, 90675}},
+{8124, 17, 20529, {1, 1, 5, 1, 13, 49, 95, 153, 131, 955, 283, 2951, 3651, 7743, 4285, 42621, 110577}},
+{8125, 17, 20535, {1, 1, 1, 9, 19, 59, 97, 181, 67, 357, 497, 287, 3523, 3729, 28981, 59687, 39463}},
+{8126, 17, 20544, {1, 1, 3, 7, 5, 19, 107, 55, 393, 225, 1953, 669, 8063, 6537, 15983, 59891, 95079}},
+{8127, 17, 20568, {1, 3, 1, 5, 29, 21, 17, 169, 447, 697, 1613, 3483, 3139, 11175, 28865, 12065, 130241}},
+{8128, 17, 20589, {1, 3, 5, 7, 5, 49, 35, 181, 85, 505, 1537, 1345, 773, 3255, 27405, 3959, 126377}},
+{8129, 17, 20592, {1, 1, 7, 15, 9, 9, 17, 99, 409, 319, 807, 1721, 4023, 2171, 32657, 51663, 23253}},
+{8130, 17, 20601, {1, 3, 5, 1, 5, 3, 37, 219, 89, 263, 397, 573, 6147, 9525, 2521, 11153, 94319}},
+{8131, 17, 20617, {1, 1, 5, 5, 11, 39, 55, 205, 209, 239, 1443, 2477, 1941, 8337, 2883, 54593, 129859}},
+{8132, 17, 20625, {1, 1, 1, 7, 11, 13, 127, 65, 127, 413, 1553, 413, 3395, 9451, 7517, 34103, 57029}},
+{8133, 17, 20626, {1, 1, 1, 15, 5, 25, 109, 181, 399, 1023, 277, 3365, 6209, 827, 13933, 27483, 63835}},
+{8134, 17, 20632, {1, 1, 3, 3, 21, 57, 95, 127, 481, 365, 197, 3631, 7443, 4925, 31277, 35061, 35875}},
+{8135, 17, 20638, {1, 1, 7, 13, 3, 31, 59, 127, 441, 967, 1049, 1281, 3553, 375, 9683, 45755, 18889}},
+{8136, 17, 20644, {1, 1, 1, 13, 11, 39, 49, 43, 383, 607, 157, 1887, 3623, 13335, 31949, 49843, 96781}},
+{8137, 17, 20647, {1, 3, 7, 13, 19, 35, 21, 9, 299, 425, 1921, 3481, 6849, 4149, 5227, 56737, 27559}},
+{8138, 17, 20662, {1, 3, 7, 5, 21, 11, 79, 97, 1, 849, 819, 1133, 3393, 5429, 10621, 38787, 120785}},
+{8139, 17, 20671, {1, 1, 1, 13, 21, 29, 3, 239, 399, 619, 759, 2655, 3691, 655, 30979, 15507, 114791}},
+{8140, 17, 20674, {1, 3, 5, 3, 1, 61, 79, 43, 273, 965, 1759, 3901, 2437, 1703, 20205, 46291, 23679}},
+{8141, 17, 20683, {1, 1, 1, 9, 19, 57, 75, 245, 377, 261, 231, 3683, 6745, 7797, 28471, 56269, 109969}},
+{8142, 17, 20704, {1, 3, 1, 11, 9, 55, 53, 87, 33, 431, 1805, 2933, 455, 12479, 16235, 2667, 70105}},
+{8143, 17, 20724, {1, 3, 5, 1, 29, 1, 101, 17, 377, 499, 1365, 209, 4819, 15099, 8769, 37003, 53003}},
+{8144, 17, 20742, {1, 3, 5, 11, 11, 39, 109, 235, 337, 393, 35, 1071, 7085, 7165, 25143, 24223, 71493}},
+{8145, 17, 20748, {1, 3, 1, 5, 13, 49, 9, 205, 305, 943, 799, 2405, 319, 10755, 9785, 32023, 48015}},
+{8146, 17, 20765, {1, 3, 1, 9, 29, 35, 123, 101, 73, 747, 1257, 407, 5871, 4271, 14837, 52727, 13339}},
+{8147, 17, 20776, {1, 3, 3, 9, 31, 7, 113, 27, 89, 123, 1117, 531, 5531, 7897, 11209, 35267, 123457}},
+{8148, 17, 20789, {1, 1, 1, 1, 29, 19, 93, 11, 61, 743, 267, 13, 6561, 7667, 20537, 12675, 10481}},
+{8149, 17, 20796, {1, 1, 5, 13, 27, 47, 103, 171, 349, 139, 1709, 961, 783, 7147, 5569, 53395, 80797}},
+{8150, 17, 20802, {1, 3, 1, 9, 21, 49, 41, 175, 507, 861, 1157, 1033, 6795, 5795, 603, 12485, 75263}},
+{8151, 17, 20807, {1, 1, 5, 7, 23, 3, 21, 165, 123, 951, 785, 2065, 8001, 7009, 22981, 10011, 9807}},
+{8152, 17, 20814, {1, 3, 7, 15, 1, 53, 49, 197, 231, 351, 141, 3465, 7907, 10695, 30913, 26753, 71079}},
+{8153, 17, 20821, {1, 3, 5, 3, 29, 45, 23, 131, 65, 507, 75, 275, 7287, 187, 1093, 52657, 31533}},
+{8154, 17, 20832, {1, 3, 5, 9, 9, 7, 113, 125, 441, 75, 663, 4081, 3147, 1469, 28375, 35747, 122965}},
+{8155, 17, 20835, {1, 1, 7, 3, 3, 57, 5, 17, 183, 237, 965, 3709, 4161, 9513, 217, 58835, 78789}},
+{8156, 17, 20847, {1, 1, 3, 1, 7, 25, 13, 29, 173, 319, 1723, 57, 2401, 10405, 15541, 52915, 93747}},
+{8157, 17, 20859, {1, 1, 7, 5, 1, 31, 11, 61, 341, 97, 1199, 2585, 5909, 3707, 31507, 51233, 2389}},
+{8158, 17, 20871, {1, 1, 5, 15, 15, 21, 127, 155, 229, 203, 1303, 3215, 1965, 9481, 31909, 52307, 112207}},
+{8159, 17, 20883, {1, 3, 1, 13, 9, 45, 91, 39, 113, 587, 895, 637, 2475, 1695, 9347, 53255, 75797}},
+{8160, 17, 20886, {1, 3, 5, 13, 17, 11, 35, 83, 69, 255, 741, 3927, 153, 11001, 29145, 37107, 51873}},
+{8161, 17, 20892, {1, 1, 7, 5, 5, 37, 35, 219, 153, 1005, 973, 2555, 893, 5931, 23857, 34631, 74561}},
+{8162, 17, 20906, {1, 3, 1, 11, 21, 63, 113, 29, 115, 307, 957, 407, 879, 4819, 2865, 1773, 116825}},
+{8163, 17, 20908, {1, 3, 7, 3, 19, 55, 87, 21, 139, 571, 311, 2295, 2729, 6371, 11845, 30223, 19247}},
+{8164, 17, 20957, {1, 3, 7, 5, 23, 9, 59, 25, 357, 863, 435, 2509, 5599, 14039, 25731, 41645, 255}},
+{8165, 17, 20962, {1, 3, 7, 13, 9, 3, 63, 115, 503, 489, 1585, 813, 5419, 691, 23973, 18677, 59979}},
+{8166, 17, 20968, {1, 1, 1, 1, 13, 3, 55, 23, 185, 731, 459, 1497, 433, 16243, 29995, 20777, 59513}},
+{8167, 17, 20979, {1, 1, 7, 3, 27, 55, 77, 57, 349, 5, 617, 385, 6225, 7025, 23335, 877, 21973}},
+{8168, 17, 20991, {1, 3, 3, 5, 3, 37, 105, 197, 153, 639, 1643, 1093, 801, 4605, 4551, 46081, 7739}},
+{8169, 17, 20998, {1, 1, 5, 11, 29, 23, 5, 91, 39, 489, 2029, 887, 4451, 11463, 5641, 56299, 34027}},
+{8170, 17, 21007, {1, 1, 7, 3, 17, 11, 25, 161, 317, 701, 155, 1989, 7549, 11529, 9945, 18395, 61251}},
+{8171, 17, 21010, {1, 1, 7, 13, 23, 55, 113, 91, 17, 149, 1893, 2793, 8185, 81, 29487, 47925, 51837}},
+{8172, 17, 21026, {1, 3, 7, 7, 9, 29, 103, 161, 215, 129, 113, 1987, 919, 9639, 20715, 6541, 15041}},
+{8173, 17, 21037, {1, 1, 5, 9, 19, 19, 127, 43, 263, 997, 1687, 3801, 4249, 6309, 25889, 1787, 122771}},
+{8174, 17, 21038, {1, 3, 5, 13, 17, 3, 91, 183, 349, 467, 333, 3299, 3085, 12135, 16801, 31471, 37227}},
+{8175, 17, 21045, {1, 1, 5, 3, 7, 53, 11, 221, 407, 545, 237, 3631, 1791, 3729, 19737, 921, 57303}},
+{8176, 17, 21057, {1, 3, 7, 15, 3, 27, 71, 45, 219, 9, 1135, 2267, 6841, 8637, 30317, 9397, 115425}},
+{8177, 17, 21082, {1, 1, 3, 5, 29, 59, 121, 225, 419, 813, 1725, 3969, 3451, 8457, 31803, 57659, 33263}},
+{8178, 17, 21093, {1, 3, 3, 3, 17, 3, 65, 249, 423, 293, 1333, 3947, 1477, 4005, 30445, 28171, 95823}},
+{8179, 17, 21094, {1, 3, 3, 11, 29, 45, 67, 89, 75, 95, 555, 1823, 2795, 11929, 1995, 30013, 116241}},
+{8180, 17, 21105, {1, 3, 3, 3, 23, 35, 87, 221, 385, 275, 803, 387, 7765, 15637, 27953, 20913, 25279}},
+{8181, 17, 21117, {1, 3, 7, 15, 15, 43, 21, 179, 393, 95, 1913, 1715, 4467, 15093, 13613, 50775, 37133}},
+{8182, 17, 21121, {1, 1, 7, 7, 31, 27, 49, 71, 323, 123, 597, 2395, 4449, 7249, 20197, 19789, 92685}},
+{8183, 17, 21124, {1, 1, 5, 13, 31, 37, 89, 225, 357, 201, 1887, 3915, 2165, 10809, 21623, 34375, 110905}},
+{8184, 17, 21136, {1, 1, 5, 7, 11, 53, 37, 55, 61, 679, 1465, 1587, 2215, 16237, 14985, 50507, 128637}},
+{8185, 17, 21139, {1, 1, 7, 1, 15, 53, 115, 21, 279, 555, 43, 2429, 7251, 2141, 4813, 47047, 119551}},
+{8186, 17, 21142, {1, 1, 5, 13, 11, 41, 59, 245, 337, 117, 1125, 4007, 947, 10591, 17795, 48535, 72171}},
+{8187, 17, 21145, {1, 1, 5, 15, 27, 41, 71, 43, 505, 539, 975, 1567, 795, 4433, 11689, 53051, 98819}},
+{8188, 17, 21167, {1, 1, 7, 9, 1, 57, 57, 137, 323, 311, 759, 3027, 3713, 13, 24133, 21451, 1153}},
+{8189, 17, 21170, {1, 1, 5, 15, 31, 49, 23, 123, 271, 549, 1995, 5, 6065, 3797, 1085, 50137, 19741}},
+{8190, 17, 21175, {1, 3, 3, 13, 5, 15, 21, 117, 487, 43, 1759, 2899, 4239, 9729, 16711, 31559, 34553}},
+{8191, 17, 21179, {1, 1, 5, 13, 5, 23, 83, 49, 147, 267, 923, 1377, 1687, 1793, 30383, 19537, 66989}},
+{8192, 17, 21182, {1, 1, 1, 13, 9, 41, 105, 241, 499, 891, 885, 3349, 4703, 5609, 11999, 58025, 69089}},
+{8193, 17, 21193, {1, 1, 7, 9, 21, 11, 121, 69, 115, 895, 91, 3745, 41, 12787, 26181, 31399, 30463}},
+{8194, 17, 21194, {1, 1, 7, 13, 11, 3, 23, 173, 5, 907, 45, 3465, 2807, 3731, 14347, 27973, 8567}},
+{8195, 17, 21207, {1, 3, 7, 5, 27, 47, 43, 25, 499, 57, 649, 705, 6223, 4213, 4549, 23213, 13657}},
+{8196, 17, 21217, {1, 1, 7, 11, 21, 35, 5, 79, 295, 359, 1993, 99, 7917, 14917, 2131, 45527, 31451}},
+{8197, 17, 21224, {1, 1, 5, 15, 1, 39, 85, 93, 65, 991, 389, 585, 4835, 11671, 10913, 41787, 84953}},
+{8198, 17, 21244, {1, 1, 1, 5, 27, 5, 1, 15, 11, 83, 1191, 3945, 4697, 7703, 6929, 6057, 88721}},
+{8199, 17, 21247, {1, 1, 3, 7, 27, 39, 71, 181, 191, 997, 419, 1671, 7771, 15305, 18677, 45033, 64745}},
+{8200, 17, 21252, {1, 3, 7, 3, 15, 41, 33, 239, 93, 307, 153, 2701, 1549, 5011, 6913, 19257, 55829}},
+{8201, 17, 21264, {1, 3, 3, 11, 21, 47, 69, 223, 365, 877, 431, 1629, 4803, 11591, 13973, 56359, 11897}},
+{8202, 17, 21273, {1, 3, 7, 7, 1, 59, 63, 129, 251, 873, 603, 2707, 2847, 8739, 31343, 63291, 5607}},
+{8203, 17, 21289, {1, 3, 5, 5, 19, 13, 79, 235, 151, 571, 953, 2191, 5973, 4751, 11119, 14439, 97755}},
+{8204, 17, 21290, {1, 1, 5, 1, 27, 3, 105, 139, 13, 821, 221, 2025, 7303, 1891, 28193, 45537, 92703}},
+{8205, 17, 21295, {1, 3, 7, 9, 13, 63, 27, 149, 51, 121, 587, 3695, 4115, 3955, 22493, 34903, 51669}},
+{8206, 17, 21297, {1, 1, 5, 7, 19, 5, 89, 87, 269, 585, 421, 3827, 315, 14739, 109, 43009, 94969}},
+{8207, 17, 21309, {1, 1, 5, 15, 9, 53, 125, 83, 159, 917, 1583, 585, 6839, 14957, 20007, 60467, 96309}},
+{8208, 17, 21318, {1, 3, 5, 1, 23, 49, 109, 91, 17, 731, 1083, 3153, 1825, 14293, 25639, 44599, 47541}},
+{8209, 17, 21322, {1, 1, 3, 7, 21, 51, 45, 25, 367, 925, 799, 1673, 6977, 7155, 829, 25899, 104615}},
+{8210, 17, 21324, {1, 3, 3, 13, 13, 49, 95, 239, 195, 353, 1967, 1419, 929, 503, 11717, 9485, 62885}},
+{8211, 17, 21329, {1, 1, 1, 15, 3, 41, 109, 91, 327, 789, 1429, 1159, 2801, 4845, 19663, 47737, 11029}},
+{8212, 17, 21332, {1, 3, 5, 1, 21, 63, 57, 107, 229, 771, 1911, 647, 6989, 12615, 23191, 64941, 97595}},
+{8213, 17, 21336, {1, 1, 1, 15, 5, 13, 15, 109, 459, 447, 1625, 1269, 7629, 7929, 4405, 12143, 40481}},
+{8214, 17, 21342, {1, 3, 3, 1, 23, 3, 95, 229, 363, 379, 1149, 1615, 5125, 3645, 27535, 58791, 38091}},
+{8215, 17, 21351, {1, 1, 1, 1, 9, 45, 119, 85, 151, 171, 1123, 41, 6517, 8067, 17845, 23301, 95383}},
+{8216, 17, 21355, {1, 3, 1, 15, 17, 31, 103, 71, 35, 1019, 1687, 1175, 6119, 14075, 26601, 28873, 36617}},
+{8217, 17, 21363, {1, 3, 3, 9, 13, 39, 7, 17, 207, 219, 637, 3025, 1709, 4031, 563, 14865, 129389}},
+{8218, 17, 21372, {1, 3, 7, 1, 21, 11, 121, 85, 111, 641, 1163, 3173, 5189, 13261, 19471, 39635, 76545}},
+{8219, 17, 21382, {1, 3, 7, 15, 3, 45, 3, 37, 121, 967, 1861, 3257, 3699, 6881, 11905, 8413, 59397}},
+{8220, 17, 21388, {1, 3, 3, 13, 25, 53, 85, 181, 1, 979, 2045, 297, 1739, 8139, 17897, 35251, 7193}},
+{8221, 17, 21394, {1, 1, 1, 3, 5, 49, 77, 115, 377, 209, 1415, 3747, 485, 803, 2507, 27729, 52201}},
+{8222, 17, 21403, {1, 3, 1, 5, 31, 55, 85, 171, 135, 893, 1423, 3693, 6155, 5321, 8297, 39183, 88377}},
+{8223, 17, 21409, {1, 3, 3, 15, 1, 35, 73, 239, 181, 101, 509, 2449, 4955, 13049, 27631, 16871, 40151}},
+{8224, 17, 21416, {1, 1, 7, 13, 27, 7, 109, 71, 437, 835, 563, 1355, 3681, 7431, 32743, 59693, 125055}},
+{8225, 17, 21421, {1, 1, 7, 5, 19, 23, 29, 147, 291, 507, 1943, 2069, 3309, 11569, 1031, 49345, 86735}},
+{8226, 17, 21424, {1, 1, 3, 13, 17, 45, 91, 167, 19, 137, 527, 961, 4435, 2277, 6863, 57917, 129407}},
+{8227, 17, 21444, {1, 3, 5, 7, 11, 31, 79, 207, 43, 871, 1121, 2929, 6899, 4099, 29533, 45333, 33299}},
+{8228, 17, 21453, {1, 1, 7, 5, 5, 49, 13, 95, 475, 91, 337, 3531, 3157, 1331, 32655, 46169, 3549}},
+{8229, 17, 21466, {1, 3, 1, 5, 5, 9, 73, 177, 123, 251, 717, 541, 7083, 6907, 1417, 31203, 9755}},
+{8230, 17, 21471, {1, 3, 1, 11, 21, 11, 91, 155, 447, 165, 1525, 2073, 5103, 193, 2677, 43673, 70579}},
+{8231, 17, 21495, {1, 3, 7, 1, 7, 27, 115, 247, 211, 779, 1999, 209, 3215, 111, 25567, 34641, 130873}},
+{8232, 17, 21499, {1, 1, 5, 9, 25, 7, 15, 19, 217, 831, 1577, 2051, 3533, 2337, 7675, 2845, 69135}},
+{8233, 17, 21504, {1, 3, 5, 15, 29, 11, 91, 59, 221, 383, 1235, 1261, 2967, 14989, 11455, 6459, 58047}},
+{8234, 17, 21507, {1, 3, 5, 1, 3, 35, 5, 127, 99, 981, 493, 3001, 5651, 3125, 27789, 57389, 115631}},
+{8235, 17, 21521, {1, 3, 5, 5, 29, 63, 123, 161, 247, 177, 1653, 2665, 3903, 11129, 20961, 49429, 44075}},
+{8236, 17, 21527, {1, 3, 1, 1, 13, 9, 57, 167, 291, 765, 1929, 397, 5503, 5601, 6957, 62003, 104631}},
+{8237, 17, 21555, {1, 1, 7, 15, 9, 43, 57, 85, 157, 361, 1931, 2183, 8045, 14939, 2169, 25733, 29095}},
+{8238, 17, 21558, {1, 1, 3, 15, 13, 35, 47, 123, 13, 667, 1373, 4069, 6259, 13453, 13439, 25349, 99437}},
+{8239, 17, 21562, {1, 3, 7, 1, 31, 15, 69, 45, 355, 919, 415, 793, 3987, 8785, 4905, 8177, 123989}},
+{8240, 17, 21570, {1, 3, 7, 13, 29, 27, 69, 57, 385, 185, 171, 2499, 3983, 13437, 23585, 21501, 88079}},
+{8241, 17, 21576, {1, 1, 5, 11, 27, 3, 77, 99, 221, 997, 1653, 1963, 2251, 15505, 26347, 51933, 100679}},
+{8242, 17, 21579, {1, 1, 1, 7, 19, 39, 49, 69, 193, 235, 959, 2823, 2573, 8001, 4389, 13217, 60975}},
+{8243, 17, 21581, {1, 1, 7, 5, 1, 3, 3, 189, 199, 293, 1225, 1913, 7271, 2255, 661, 23293, 82069}},
+{8244, 17, 21587, {1, 1, 5, 5, 21, 31, 35, 113, 47, 479, 325, 1663, 7409, 8975, 14151, 56317, 79663}},
+{8245, 17, 21590, {1, 1, 5, 9, 15, 63, 99, 135, 277, 715, 667, 387, 6929, 12873, 12913, 2599, 84939}},
+{8246, 17, 21599, {1, 1, 7, 15, 23, 39, 67, 25, 179, 313, 459, 295, 1103, 1737, 7529, 29463, 104693}},
+{8247, 17, 21605, {1, 1, 3, 13, 23, 11, 111, 67, 105, 191, 1967, 3497, 7621, 487, 18545, 59521, 115315}},
+{8248, 17, 21612, {1, 1, 1, 7, 25, 45, 83, 61, 231, 569, 155, 2817, 6985, 5289, 6731, 3087, 89749}},
+{8249, 17, 21618, {1, 3, 7, 1, 1, 61, 103, 49, 135, 411, 659, 1735, 4461, 8077, 12885, 62791, 114769}},
+{8250, 17, 21630, {1, 1, 7, 13, 3, 53, 21, 81, 433, 563, 857, 891, 195, 11669, 24769, 56539, 47601}},
+{8251, 17, 21639, {1, 3, 1, 13, 3, 41, 59, 101, 67, 803, 1209, 3267, 1255, 5763, 5483, 36339, 38451}},
+{8252, 17, 21640, {1, 3, 5, 3, 25, 51, 53, 213, 329, 11, 483, 81, 2151, 7623, 26309, 15289, 85103}},
+{8253, 17, 21643, {1, 3, 3, 13, 23, 17, 9, 161, 417, 207, 39, 3615, 7567, 15207, 20383, 58885, 121765}},
+{8254, 17, 21648, {1, 3, 1, 7, 15, 59, 9, 195, 187, 583, 341, 2737, 3891, 331, 18055, 60455, 113271}},
+{8255, 17, 21669, {1, 1, 3, 3, 19, 25, 95, 37, 281, 59, 1613, 2733, 5715, 4067, 5509, 5851, 35189}},
+{8256, 17, 21679, {1, 3, 1, 3, 31, 43, 125, 107, 341, 109, 1991, 849, 7795, 13607, 20421, 3339, 78979}},
+{8257, 17, 21681, {1, 3, 7, 13, 15, 57, 87, 151, 479, 99, 479, 447, 7407, 303, 16397, 15699, 122273}},
+{8258, 17, 21687, {1, 1, 3, 1, 27, 61, 79, 195, 5, 839, 1411, 3451, 4627, 13715, 18401, 24325, 44027}},
+{8259, 17, 21688, {1, 1, 7, 15, 21, 39, 57, 207, 213, 367, 547, 1203, 6385, 2555, 31465, 15675, 7133}},
+{8260, 17, 21706, {1, 1, 5, 15, 27, 3, 75, 123, 337, 1019, 1525, 3065, 1919, 10779, 27409, 6291, 86291}},
+{8261, 17, 21713, {1, 1, 7, 11, 15, 27, 67, 145, 125, 521, 647, 2957, 6337, 14973, 24139, 29107, 27151}},
+{8262, 17, 21714, {1, 1, 1, 13, 25, 57, 103, 83, 321, 111, 131, 2051, 5267, 4723, 1939, 40389, 4803}},
+{8263, 17, 21716, {1, 3, 1, 7, 29, 7, 35, 133, 349, 855, 613, 2563, 2261, 2119, 13939, 24727, 26719}},
+{8264, 17, 21730, {1, 3, 3, 1, 11, 61, 25, 177, 427, 1005, 2027, 649, 7871, 7803, 4717, 59207, 57945}},
+{8265, 17, 21732, {1, 1, 7, 1, 15, 45, 75, 133, 193, 745, 485, 197, 6001, 13837, 615, 43629, 127321}},
+{8266, 17, 21749, {1, 3, 3, 13, 5, 7, 101, 183, 211, 283, 1327, 1395, 8175, 13359, 18361, 54243, 3555}},
+{8267, 17, 21756, {1, 1, 7, 13, 7, 43, 19, 41, 319, 701, 795, 1407, 7113, 9149, 31953, 17075, 53975}},
+{8268, 17, 21774, {1, 3, 5, 13, 11, 19, 101, 125, 327, 75, 1471, 3465, 2247, 5107, 11519, 45161, 71373}},
+{8269, 17, 21779, {1, 3, 7, 13, 23, 59, 53, 57, 137, 575, 59, 3829, 963, 11259, 25771, 29223, 79535}},
+{8270, 17, 21781, {1, 3, 3, 11, 17, 31, 111, 147, 499, 441, 1385, 769, 6901, 8349, 1427, 16561, 7485}},
+{8271, 17, 21786, {1, 1, 7, 9, 21, 7, 47, 83, 351, 867, 265, 1329, 7853, 6959, 11821, 44947, 42275}},
+{8272, 17, 21792, {1, 1, 7, 15, 3, 17, 79, 143, 449, 577, 1007, 1101, 3229, 6861, 23921, 37551, 117309}},
+{8273, 17, 21810, {1, 3, 5, 11, 27, 63, 107, 15, 289, 821, 1723, 1945, 1373, 14469, 30985, 55987, 21255}},
+{8274, 17, 21819, {1, 3, 5, 3, 21, 39, 79, 85, 485, 733, 2031, 1573, 6873, 12225, 30471, 54233, 26967}},
+{8275, 17, 21829, {1, 3, 5, 7, 17, 29, 93, 251, 437, 583, 825, 551, 6545, 10905, 27863, 37037, 52129}},
+{8276, 17, 21830, {1, 3, 7, 9, 23, 1, 23, 85, 195, 319, 1759, 3985, 2413, 16205, 22197, 48821, 94907}},
+{8277, 17, 21844, {1, 1, 3, 7, 17, 47, 3, 195, 167, 925, 11, 3431, 1767, 5917, 13915, 54565, 64625}},
+{8278, 17, 21853, {1, 3, 1, 13, 23, 43, 97, 93, 313, 773, 591, 127, 6005, 11497, 32573, 8173, 92053}},
+{8279, 17, 21867, {1, 1, 5, 9, 17, 47, 115, 237, 389, 619, 377, 561, 1333, 6433, 9743, 32673, 98039}},
+{8280, 17, 21869, {1, 3, 7, 15, 23, 17, 99, 225, 145, 191, 2041, 581, 841, 9377, 18123, 32773, 66849}},
+{8281, 17, 21882, {1, 3, 7, 15, 21, 49, 97, 41, 357, 527, 2019, 2083, 2611, 12449, 20037, 52503, 105991}},
+{8282, 17, 21891, {1, 1, 5, 13, 17, 53, 41, 75, 355, 207, 1675, 591, 5797, 9217, 16443, 3205, 81905}},
+{8283, 17, 21898, {1, 3, 7, 11, 1, 61, 29, 207, 449, 103, 1527, 2327, 7895, 10137, 25223, 51607, 60809}},
+{8284, 17, 21917, {1, 3, 3, 5, 15, 57, 87, 233, 301, 989, 485, 2143, 7411, 5475, 23377, 56005, 59721}},
+{8285, 17, 21934, {1, 3, 1, 15, 29, 7, 95, 141, 369, 231, 735, 1103, 1565, 11575, 571, 3257, 62961}},
+{8286, 17, 21946, {1, 1, 5, 15, 27, 19, 25, 35, 303, 555, 95, 1323, 6139, 5079, 21763, 59591, 103537}},
+{8287, 17, 21948, {1, 1, 1, 13, 25, 23, 85, 151, 135, 349, 1753, 1061, 7697, 1723, 5213, 12581, 103995}},
+{8288, 17, 21963, {1, 3, 1, 9, 29, 51, 101, 195, 59, 809, 1527, 2179, 63, 3681, 29823, 57537, 121371}},
+{8289, 17, 21966, {1, 1, 7, 11, 27, 61, 85, 213, 245, 261, 1649, 2423, 6127, 5687, 4247, 56061, 109793}},
+{8290, 17, 21968, {1, 3, 5, 15, 11, 33, 127, 31, 269, 857, 2027, 2611, 1729, 11783, 16459, 31083, 30671}},
+{8291, 17, 21973, {1, 1, 7, 9, 11, 29, 127, 177, 505, 227, 1499, 1309, 6855, 9999, 21815, 32987, 79109}},
+{8292, 17, 21977, {1, 3, 7, 11, 7, 21, 107, 1, 493, 459, 867, 3199, 7985, 12957, 28197, 41133, 105985}},
+{8293, 17, 21980, {1, 1, 3, 15, 1, 57, 113, 97, 213, 547, 1017, 2961, 461, 16125, 10621, 4243, 58277}},
+{8294, 17, 21984, {1, 1, 3, 5, 11, 57, 61, 47, 209, 961, 333, 795, 4491, 15115, 25745, 62633, 66269}},
+{8295, 17, 21994, {1, 1, 7, 3, 19, 13, 49, 167, 455, 863, 581, 1407, 4247, 15023, 2247, 19981, 125891}},
+{8296, 17, 21999, {1, 1, 7, 15, 17, 55, 27, 35, 33, 349, 879, 1781, 1075, 2475, 30689, 42043, 29423}},
+{8297, 17, 22018, {1, 1, 1, 11, 25, 53, 121, 117, 117, 845, 447, 3927, 1951, 8643, 24497, 44833, 99533}},
+{8298, 17, 22020, {1, 1, 7, 13, 3, 59, 117, 9, 359, 453, 327, 3419, 5957, 97, 20541, 49441, 5673}},
+{8299, 17, 22029, {1, 3, 5, 5, 31, 35, 95, 107, 435, 733, 827, 1361, 6627, 8905, 2681, 25473, 46093}},
+{8300, 17, 22032, {1, 3, 3, 5, 7, 23, 75, 137, 231, 915, 637, 2963, 4409, 12799, 31587, 65363, 69539}},
+{8301, 17, 22041, {1, 1, 1, 7, 15, 35, 19, 233, 189, 837, 243, 2525, 6185, 565, 8133, 4265, 3089}},
+{8302, 17, 22047, {1, 1, 5, 5, 19, 59, 103, 201, 287, 449, 21, 2331, 341, 13145, 18607, 46407, 2767}},
+{8303, 17, 22048, {1, 3, 3, 15, 19, 41, 49, 179, 109, 367, 1185, 1045, 1635, 9647, 16613, 25357, 34291}},
+{8304, 17, 22071, {1, 3, 5, 1, 13, 11, 89, 25, 159, 637, 1979, 549, 3553, 9163, 227, 50553, 46307}},
+{8305, 17, 22075, {1, 1, 3, 1, 17, 33, 73, 239, 261, 751, 1267, 2643, 2549, 8331, 25083, 9715, 67289}},
+{8306, 17, 22078, {1, 1, 1, 13, 3, 49, 7, 35, 367, 293, 903, 1045, 569, 6017, 27635, 51833, 32963}},
+{8307, 17, 22083, {1, 3, 5, 3, 31, 3, 69, 137, 57, 87, 719, 3977, 3031, 7675, 24605, 8757, 93173}},
+{8308, 17, 22089, {1, 3, 3, 1, 7, 45, 97, 35, 233, 69, 1525, 4047, 2599, 13679, 4389, 49079, 121465}},
+{8309, 17, 22097, {1, 1, 7, 13, 7, 25, 57, 211, 337, 189, 1825, 2451, 7651, 11277, 27763, 40671, 57223}},
+{8310, 17, 22110, {1, 1, 1, 1, 15, 59, 55, 169, 461, 907, 407, 803, 3349, 4727, 20983, 47717, 51647}},
+{8311, 17, 22113, {1, 3, 7, 1, 15, 51, 25, 119, 439, 593, 1289, 3959, 5489, 13283, 31837, 8441, 58373}},
+{8312, 17, 22119, {1, 3, 1, 9, 5, 1, 81, 45, 13, 537, 1091, 3861, 6781, 5679, 2807, 29757, 40917}},
+{8313, 17, 22120, {1, 3, 5, 3, 27, 41, 19, 235, 207, 697, 775, 837, 3431, 3175, 10807, 42775, 67987}},
+{8314, 17, 22126, {1, 3, 7, 3, 29, 33, 35, 119, 271, 609, 1747, 2839, 3415, 2275, 30979, 41293, 99341}},
+{8315, 17, 22133, {1, 3, 3, 3, 5, 17, 13, 169, 269, 709, 1449, 3169, 1545, 16075, 8937, 39705, 19609}},
+{8316, 17, 22134, {1, 3, 5, 15, 29, 13, 1, 199, 65, 385, 977, 797, 1181, 10979, 241, 40393, 73663}},
+{8317, 17, 22140, {1, 1, 3, 7, 17, 35, 47, 63, 193, 451, 151, 3415, 99, 14557, 26025, 31361, 112639}},
+{8318, 17, 22147, {1, 1, 3, 5, 19, 13, 29, 33, 365, 311, 1241, 217, 6205, 13067, 18585, 21693, 97127}},
+{8319, 17, 22161, {1, 1, 3, 15, 19, 7, 87, 25, 91, 13, 1839, 1445, 957, 9779, 25557, 37027, 38987}},
+{8320, 17, 22164, {1, 1, 5, 1, 21, 5, 79, 67, 481, 455, 37, 1321, 7723, 1413, 7919, 11035, 5739}},
+{8321, 17, 22173, {1, 1, 1, 15, 9, 55, 111, 1, 383, 439, 1037, 4055, 4243, 10443, 26737, 21039, 130847}},
+{8322, 17, 22197, {1, 1, 7, 9, 13, 25, 71, 137, 307, 717, 1009, 2477, 3861, 14145, 14549, 59589, 93401}},
+{8323, 17, 22207, {1, 1, 7, 5, 29, 63, 77, 49, 471, 267, 1457, 1743, 1915, 14793, 17899, 28011, 92183}},
+{8324, 17, 22210, {1, 3, 7, 7, 7, 41, 47, 251, 75, 749, 1915, 1015, 5869, 3211, 24097, 14349, 130571}},
+{8325, 17, 22216, {1, 1, 1, 1, 31, 63, 105, 83, 345, 147, 975, 135, 7299, 15801, 19311, 26143, 80293}},
+{8326, 17, 22234, {1, 1, 3, 1, 7, 1, 47, 45, 251, 635, 583, 3515, 5233, 6281, 7797, 37949, 75877}},
+{8327, 17, 22257, {1, 1, 3, 3, 5, 53, 99, 175, 155, 327, 1841, 211, 2811, 16099, 17255, 34253, 124141}},
+{8328, 17, 22264, {1, 3, 1, 3, 13, 27, 81, 217, 115, 245, 101, 1641, 29, 1441, 4829, 28399, 102303}},
+{8329, 17, 22278, {1, 3, 1, 5, 11, 55, 31, 91, 337, 203, 987, 977, 4929, 14933, 25149, 20493, 19783}},
+{8330, 17, 22284, {1, 1, 5, 9, 9, 37, 103, 211, 349, 165, 1421, 3015, 5133, 4615, 28173, 45787, 10711}},
+{8331, 17, 22287, {1, 1, 1, 1, 1, 17, 29, 117, 421, 651, 1617, 1677, 7841, 16303, 8843, 1321, 90701}},
+{8332, 17, 22299, {1, 1, 1, 15, 27, 23, 49, 195, 139, 319, 1277, 901, 63, 14677, 21815, 19497, 24883}},
+{8333, 17, 22301, {1, 3, 3, 13, 1, 23, 17, 189, 293, 765, 1503, 1485, 7427, 11807, 17629, 61739, 111365}},
+{8334, 17, 22308, {1, 1, 5, 5, 15, 41, 25, 53, 221, 449, 1597, 2763, 4119, 6319, 17509, 23493, 104707}},
+{8335, 17, 22337, {1, 3, 7, 11, 29, 21, 101, 197, 161, 457, 331, 3817, 5139, 14307, 23225, 55567, 62535}},
+{8336, 17, 22349, {1, 1, 7, 5, 9, 57, 39, 101, 5, 847, 1311, 313, 2877, 14811, 21969, 31741, 8075}},
+{8337, 17, 22350, {1, 3, 5, 3, 1, 11, 45, 163, 251, 775, 1031, 1957, 1631, 1691, 3191, 6255, 13037}},
+{8338, 17, 22357, {1, 1, 3, 13, 7, 11, 95, 97, 409, 835, 707, 1579, 2409, 9451, 15069, 62425, 106499}},
+{8339, 17, 22364, {1, 3, 3, 11, 5, 25, 23, 207, 429, 299, 537, 1467, 6309, 891, 15009, 56733, 60397}},
+{8340, 17, 22373, {1, 3, 5, 3, 29, 47, 95, 115, 207, 177, 543, 427, 145, 11169, 7441, 10911, 87413}},
+{8341, 17, 22377, {1, 3, 7, 11, 25, 53, 15, 225, 115, 295, 919, 39, 513, 9989, 11045, 24015, 102387}},
+{8342, 17, 22380, {1, 1, 7, 15, 13, 31, 103, 143, 357, 825, 183, 137, 2671, 9803, 14777, 48333, 79483}},
+{8343, 17, 22386, {1, 3, 5, 1, 25, 13, 65, 9, 461, 307, 1289, 1035, 7253, 14223, 16829, 23361, 84987}},
+{8344, 17, 22391, {1, 3, 5, 7, 5, 57, 47, 251, 5, 9, 965, 2883, 3105, 13931, 807, 31977, 119035}},
+{8345, 17, 22392, {1, 1, 3, 5, 3, 7, 55, 165, 3, 787, 1587, 989, 6049, 14021, 30789, 15283, 92851}},
+{8346, 17, 22411, {1, 1, 5, 5, 3, 17, 11, 167, 487, 885, 193, 3485, 8179, 9485, 24913, 40267, 70625}},
+{8347, 17, 22422, {1, 1, 7, 1, 27, 31, 9, 139, 73, 137, 783, 321, 691, 6157, 19905, 45525, 84877}},
+{8348, 17, 22425, {1, 3, 1, 9, 17, 39, 127, 177, 301, 579, 1065, 3899, 281, 9177, 16295, 51217, 120293}},
+{8349, 17, 22431, {1, 1, 7, 9, 31, 59, 17, 93, 247, 779, 847, 1183, 3453, 1073, 18597, 2655, 121633}},
+{8350, 17, 22438, {1, 1, 7, 1, 25, 43, 47, 253, 23, 999, 973, 1201, 1061, 5947, 5619, 36311, 1545}},
+{8351, 17, 22441, {1, 3, 5, 7, 11, 5, 103, 119, 229, 657, 1993, 1991, 1597, 13165, 19137, 7161, 83487}},
+{8352, 17, 22442, {1, 1, 1, 1, 11, 23, 105, 183, 467, 83, 899, 2447, 4949, 4171, 28943, 4829, 13033}},
+{8353, 17, 22449, {1, 3, 1, 7, 15, 7, 47, 215, 253, 109, 1975, 3337, 1553, 13575, 16835, 61525, 26423}},
+{8354, 17, 22452, {1, 1, 7, 1, 21, 17, 53, 79, 175, 267, 999, 249, 6177, 10453, 12475, 59801, 47351}},
+{8355, 17, 22461, {1, 3, 5, 11, 3, 57, 5, 193, 421, 799, 1833, 2635, 6537, 4669, 9597, 40661, 12113}},
+{8356, 17, 22467, {1, 1, 7, 11, 9, 11, 69, 103, 139, 167, 159, 2469, 703, 1519, 21553, 62875, 60449}},
+{8357, 17, 22479, {1, 1, 5, 3, 9, 11, 17, 183, 499, 301, 1275, 605, 7655, 12141, 7783, 39413, 116263}},
+{8358, 17, 22484, {1, 1, 1, 7, 31, 55, 23, 79, 49, 247, 761, 3573, 8187, 4879, 27379, 15725, 81415}},
+{8359, 17, 22487, {1, 3, 5, 5, 5, 49, 23, 205, 509, 383, 1165, 3839, 7663, 1539, 19967, 55901, 4351}},
+{8360, 17, 22493, {1, 1, 1, 11, 7, 15, 3, 159, 235, 735, 391, 2231, 5043, 9759, 4569, 35601, 71989}},
+{8361, 17, 22510, {1, 3, 3, 15, 23, 3, 49, 97, 99, 517, 1097, 3517, 1035, 2319, 27705, 25547, 101555}},
+{8362, 17, 22521, {1, 3, 7, 11, 27, 29, 33, 241, 205, 113, 291, 1993, 3277, 13155, 1039, 42367, 130477}},
+{8363, 17, 22533, {1, 1, 1, 3, 29, 19, 15, 159, 35, 153, 1177, 3011, 6271, 8203, 8971, 19183, 102871}},
+{8364, 17, 22534, {1, 1, 1, 5, 5, 51, 19, 175, 209, 895, 229, 2355, 499, 7877, 4935, 22737, 35587}},
+{8365, 17, 22543, {1, 3, 7, 11, 15, 9, 7, 113, 41, 835, 1593, 3933, 7165, 10959, 15487, 30019, 114505}},
+{8366, 17, 22548, {1, 1, 7, 5, 31, 21, 27, 11, 421, 165, 1605, 1859, 29, 13051, 3273, 3893, 56089}},
+{8367, 17, 22552, {1, 3, 5, 5, 17, 51, 55, 187, 401, 977, 95, 2617, 727, 9609, 5075, 48989, 120299}},
+{8368, 17, 22558, {1, 1, 5, 7, 21, 31, 127, 87, 379, 125, 247, 3607, 2555, 11873, 32535, 16677, 122273}},
+{8369, 17, 22561, {1, 1, 1, 5, 19, 21, 51, 185, 203, 145, 1073, 167, 235, 12753, 17315, 14683, 44101}},
+{8370, 17, 22562, {1, 3, 3, 1, 5, 61, 71, 17, 63, 151, 823, 17, 5315, 4861, 17279, 23049, 84971}},
+{8371, 17, 22568, {1, 3, 3, 5, 21, 63, 21, 235, 295, 467, 1661, 2487, 335, 6107, 28709, 55875, 129085}},
+{8372, 17, 22571, {1, 3, 3, 5, 1, 55, 35, 187, 5, 687, 1633, 2999, 4513, 10105, 15249, 22591, 102857}},
+{8373, 17, 22574, {1, 3, 1, 5, 19, 1, 113, 27, 261, 623, 831, 3011, 4091, 11967, 17191, 17433, 99925}},
+{8374, 17, 22581, {1, 3, 5, 5, 25, 59, 81, 249, 463, 523, 183, 3049, 3675, 2705, 28379, 1279, 25579}},
+{8375, 17, 22594, {1, 1, 3, 9, 19, 19, 71, 127, 189, 613, 647, 1449, 7755, 1415, 9067, 30683, 79703}},
+{8376, 17, 22603, {1, 1, 7, 1, 27, 33, 61, 135, 233, 633, 1969, 2245, 5841, 14069, 6497, 63617, 101483}},
+{8377, 17, 22605, {1, 3, 3, 9, 23, 3, 17, 163, 309, 741, 2023, 2647, 5847, 7871, 22311, 38377, 70663}},
+{8378, 17, 22606, {1, 3, 5, 15, 31, 33, 51, 243, 209, 273, 1305, 1599, 6115, 6249, 8639, 5903, 17215}},
+{8379, 17, 22623, {1, 1, 1, 1, 21, 11, 107, 185, 463, 435, 149, 3789, 6283, 1327, 20893, 10417, 78673}},
+{8380, 17, 22630, {1, 1, 1, 13, 5, 53, 121, 129, 493, 419, 1711, 2765, 7673, 8979, 25845, 62759, 9669}},
+{8381, 17, 22651, {1, 3, 5, 5, 1, 39, 123, 47, 449, 639, 625, 2355, 511, 1685, 1415, 32417, 76529}},
+{8382, 17, 22657, {1, 3, 1, 11, 1, 49, 67, 237, 203, 967, 1401, 2773, 4951, 13889, 14147, 41031, 71897}},
+{8383, 17, 22669, {1, 3, 5, 11, 13, 49, 17, 113, 315, 207, 1057, 3395, 6151, 2767, 16571, 1811, 66403}},
+{8384, 17, 22670, {1, 1, 7, 7, 29, 63, 49, 115, 327, 987, 1853, 3355, 8139, 2703, 30039, 51343, 86999}},
+{8385, 17, 22677, {1, 1, 3, 9, 1, 3, 45, 35, 509, 483, 159, 1795, 8023, 6989, 3755, 20887, 13587}},
+{8386, 17, 22682, {1, 1, 3, 7, 1, 27, 39, 159, 283, 843, 317, 3229, 2297, 15031, 22039, 21721, 70583}},
+{8387, 17, 22698, {1, 1, 3, 11, 9, 23, 1, 35, 79, 77, 1671, 2583, 647, 12313, 16271, 2959, 108389}},
+{8388, 17, 22712, {1, 1, 1, 7, 5, 55, 1, 233, 429, 231, 833, 1279, 7815, 1051, 30627, 4435, 25997}},
+{8389, 17, 22715, {1, 3, 1, 15, 19, 53, 9, 165, 307, 437, 551, 2477, 1841, 11799, 18477, 5871, 20065}},
+{8390, 17, 22729, {1, 1, 1, 1, 21, 5, 65, 41, 77, 909, 93, 751, 2973, 7341, 30427, 60075, 71457}},
+{8391, 17, 22732, {1, 1, 3, 11, 25, 51, 49, 63, 165, 263, 1915, 747, 8053, 6361, 4843, 20189, 110147}},
+{8392, 17, 22735, {1, 3, 1, 9, 29, 9, 45, 177, 415, 557, 1555, 2967, 1239, 8115, 12853, 19193, 73681}},
+{8393, 17, 22738, {1, 1, 5, 5, 11, 5, 51, 157, 325, 517, 1601, 3911, 1487, 13631, 7483, 61515, 48937}},
+{8394, 17, 22740, {1, 3, 7, 5, 29, 31, 107, 47, 437, 837, 1791, 477, 1717, 7, 25855, 48793, 16385}},
+{8395, 17, 22750, {1, 1, 1, 3, 29, 49, 31, 255, 233, 935, 1993, 125, 2255, 12785, 2807, 54697, 62591}},
+{8396, 17, 22753, {1, 3, 1, 7, 15, 13, 9, 245, 79, 289, 841, 253, 5259, 16123, 29189, 63837, 127915}},
+{8397, 17, 22760, {1, 3, 7, 15, 15, 55, 91, 103, 445, 289, 1471, 423, 3387, 15609, 19311, 28993, 23473}},
+{8398, 17, 22765, {1, 1, 3, 11, 31, 39, 69, 125, 115, 309, 397, 3417, 5693, 10301, 1489, 25955, 2699}},
+{8399, 17, 22768, {1, 3, 3, 5, 13, 21, 51, 207, 239, 311, 1601, 2925, 6285, 9597, 30579, 62957, 6153}},
+{8400, 17, 22778, {1, 1, 7, 1, 27, 21, 63, 143, 399, 971, 1385, 1875, 5143, 6423, 6223, 27009, 14237}},
+{8401, 17, 22785, {1, 3, 5, 1, 5, 59, 125, 133, 151, 997, 1315, 3007, 8173, 16289, 13409, 839, 103519}},
+{8402, 17, 22809, {1, 1, 1, 13, 7, 57, 83, 33, 191, 121, 939, 3927, 6089, 10083, 5903, 52229, 78325}},
+{8403, 17, 22810, {1, 1, 3, 5, 9, 61, 43, 107, 279, 135, 1109, 3779, 5305, 15333, 12217, 41257, 20265}},
+{8404, 17, 22812, {1, 3, 7, 1, 31, 59, 83, 43, 219, 119, 511, 2973, 4587, 10701, 30959, 21489, 124077}},
+{8405, 17, 22828, {1, 1, 7, 9, 17, 3, 59, 151, 281, 209, 1405, 173, 3589, 7679, 29803, 53947, 68291}},
+{8406, 17, 22840, {1, 1, 7, 7, 5, 19, 53, 91, 1, 513, 1495, 231, 3627, 1115, 16121, 12953, 108343}},
+{8407, 17, 22845, {1, 3, 1, 13, 17, 3, 35, 35, 211, 481, 2029, 1035, 3131, 5653, 18097, 10735, 102453}},
+{8408, 17, 22848, {1, 3, 1, 11, 29, 7, 121, 135, 51, 837, 681, 1497, 7435, 2215, 26527, 33029, 93241}},
+{8409, 17, 22857, {1, 3, 3, 15, 29, 43, 17, 243, 195, 315, 499, 3801, 5691, 12119, 4061, 51769, 80497}},
+{8410, 17, 22877, {1, 1, 3, 1, 11, 1, 113, 11, 387, 579, 275, 2995, 895, 11859, 4017, 1543, 11853}},
+{8411, 17, 22882, {1, 1, 7, 9, 31, 27, 63, 217, 97, 275, 435, 1355, 5205, 6587, 32589, 46485, 103587}},
+{8412, 17, 22887, {1, 3, 7, 3, 7, 19, 51, 41, 81, 261, 1909, 1475, 425, 3173, 5679, 34701, 34977}},
+{8413, 17, 22894, {1, 1, 7, 3, 27, 15, 35, 49, 387, 471, 1997, 3643, 2701, 11853, 21311, 36027, 104357}},
+{8414, 17, 22912, {1, 3, 1, 9, 5, 47, 73, 163, 309, 891, 229, 2433, 6715, 6721, 25233, 37043, 29367}},
+{8415, 17, 22930, {1, 1, 1, 7, 27, 15, 9, 185, 421, 597, 565, 143, 1531, 15585, 17057, 54309, 82915}},
+{8416, 17, 22936, {1, 1, 7, 1, 5, 43, 87, 61, 121, 341, 25, 3795, 7161, 11985, 32197, 789, 69543}},
+{8417, 17, 22939, {1, 3, 5, 13, 29, 39, 81, 39, 263, 729, 1833, 365, 1073, 9869, 1845, 52621, 5}},
+{8418, 17, 22957, {1, 1, 7, 7, 5, 33, 117, 11, 371, 161, 1303, 629, 2285, 5827, 32355, 43359, 115595}},
+{8419, 17, 22970, {1, 3, 5, 5, 13, 57, 63, 9, 243, 533, 173, 2197, 717, 13441, 22131, 17783, 3319}},
+{8420, 17, 22980, {1, 1, 7, 11, 15, 31, 87, 255, 183, 273, 805, 2347, 5881, 15401, 273, 17397, 41827}},
+{8421, 17, 22984, {1, 3, 1, 13, 7, 17, 121, 49, 47, 121, 333, 3629, 5337, 4117, 2735, 36581, 61345}},
+{8422, 17, 22992, {1, 3, 3, 11, 9, 7, 25, 223, 379, 119, 385, 1217, 4803, 2947, 30665, 7733, 77893}},
+{8423, 17, 22998, {1, 3, 3, 7, 31, 35, 127, 97, 5, 373, 7, 3035, 843, 5991, 9265, 34289, 42785}},
+{8424, 17, 23001, {1, 3, 7, 3, 27, 19, 95, 253, 349, 871, 807, 413, 5847, 10467, 4277, 12429, 75773}},
+{8425, 17, 23044, {1, 3, 3, 7, 21, 1, 79, 89, 219, 505, 41, 505, 5159, 12839, 3317, 49873, 73705}},
+{8426, 17, 23061, {1, 3, 1, 7, 21, 43, 121, 113, 477, 559, 1831, 3759, 3315, 6367, 7149, 16395, 44703}},
+{8427, 17, 23062, {1, 1, 1, 7, 13, 53, 35, 53, 489, 975, 631, 863, 3067, 1905, 21351, 14705, 80041}},
+{8428, 17, 23071, {1, 1, 1, 5, 13, 27, 121, 65, 351, 123, 1731, 367, 8061, 5229, 8537, 20897, 130373}},
+{8429, 17, 23075, {1, 1, 5, 11, 15, 63, 101, 107, 105, 619, 1771, 3549, 7191, 9083, 16827, 29639, 34219}},
+{8430, 17, 23089, {1, 3, 1, 9, 15, 13, 87, 157, 379, 433, 217, 815, 5079, 1797, 26707, 35165, 92305}},
+{8431, 17, 23090, {1, 1, 5, 13, 27, 35, 31, 65, 313, 629, 375, 1391, 5373, 3497, 7311, 23105, 45293}},
+{8432, 17, 23096, {1, 3, 1, 3, 5, 39, 91, 37, 401, 419, 949, 2431, 3685, 6671, 20789, 8597, 44215}},
+{8433, 17, 23101, {1, 1, 7, 11, 7, 15, 3, 181, 363, 913, 309, 2009, 3805, 6651, 27677, 37711, 40813}},
+{8434, 17, 23114, {1, 3, 5, 5, 17, 11, 47, 9, 27, 459, 773, 1403, 7069, 12651, 8163, 42425, 126697}},
+{8435, 17, 23121, {1, 3, 1, 3, 11, 21, 65, 103, 405, 843, 59, 3653, 1759, 5265, 401, 58019, 124999}},
+{8436, 17, 23124, {1, 1, 3, 7, 11, 25, 61, 211, 199, 849, 1835, 1181, 5003, 3873, 23743, 45451, 54901}},
+{8437, 17, 23127, {1, 3, 5, 3, 29, 25, 43, 199, 481, 991, 699, 3937, 7601, 1253, 24399, 6625, 93917}},
+{8438, 17, 23128, {1, 1, 7, 3, 29, 33, 33, 151, 3, 825, 743, 773, 7825, 8157, 22121, 50095, 16435}},
+{8439, 17, 23137, {1, 3, 1, 1, 27, 15, 81, 151, 271, 167, 1755, 1289, 7473, 8525, 12525, 63139, 48787}},
+{8440, 17, 23138, {1, 1, 7, 13, 27, 33, 87, 125, 211, 631, 149, 3451, 643, 6975, 2659, 12629, 33187}},
+{8441, 17, 23150, {1, 1, 3, 3, 5, 49, 99, 99, 85, 647, 351, 2829, 7005, 7283, 5857, 46157, 52061}},
+{8442, 17, 23155, {1, 1, 3, 5, 11, 37, 43, 129, 21, 639, 187, 2279, 8189, 12877, 28707, 7133, 93639}},
+{8443, 17, 23168, {1, 1, 3, 7, 19, 13, 35, 51, 77, 811, 1553, 2769, 763, 4965, 4643, 37639, 44229}},
+{8444, 17, 23173, {1, 3, 5, 15, 11, 29, 103, 203, 435, 1017, 531, 1453, 1407, 6569, 619, 52103, 45213}},
+{8445, 17, 23174, {1, 1, 7, 5, 25, 25, 47, 229, 201, 843, 473, 2637, 2265, 4627, 20013, 41217, 76095}},
+{8446, 17, 23195, {1, 3, 3, 15, 23, 61, 109, 31, 57, 595, 1303, 3915, 67, 8205, 3553, 9543, 103385}},
+{8447, 17, 23202, {1, 1, 3, 3, 21, 19, 21, 41, 137, 905, 2045, 491, 1783, 151, 20963, 38009, 735}},
+{8448, 17, 23225, {1, 1, 7, 11, 13, 33, 95, 251, 179, 211, 1687, 3189, 6213, 3905, 2117, 15153, 4855}},
+{8449, 17, 23226, {1, 1, 5, 3, 19, 9, 67, 243, 23, 611, 1007, 1317, 7303, 11065, 21157, 56677, 81683}},
+{8450, 17, 23239, {1, 1, 3, 5, 19, 41, 63, 129, 233, 15, 37, 1445, 1095, 11309, 30181, 49199, 85113}},
+{8451, 17, 23253, {1, 3, 7, 1, 21, 53, 83, 79, 155, 379, 773, 1823, 1003, 2787, 31107, 36115, 40987}},
+{8452, 17, 23263, {1, 3, 3, 5, 3, 19, 7, 247, 417, 573, 407, 3577, 6079, 10275, 29791, 35149, 102565}},
+{8453, 17, 23264, {1, 3, 3, 9, 21, 49, 57, 223, 125, 671, 655, 2995, 5849, 5355, 21171, 54857, 114841}},
+{8454, 17, 23281, {1, 3, 7, 3, 27, 23, 125, 103, 485, 955, 963, 1865, 2321, 2263, 32497, 47973, 122111}},
+{8455, 17, 23282, {1, 1, 3, 15, 3, 1, 37, 19, 287, 165, 1717, 851, 3619, 13623, 24295, 48253, 13143}},
+{8456, 17, 23288, {1, 1, 7, 9, 13, 59, 69, 97, 113, 163, 871, 1795, 2719, 13675, 11767, 23687, 65841}},
+{8457, 17, 23294, {1, 1, 5, 3, 21, 31, 41, 115, 469, 177, 137, 2129, 1385, 10835, 16471, 59411, 30795}},
+{8458, 17, 23302, {1, 1, 7, 7, 13, 45, 73, 119, 457, 673, 1481, 3735, 2675, 11413, 9069, 34741, 8757}},
+{8459, 17, 23311, {1, 3, 5, 3, 15, 9, 11, 191, 499, 51, 1963, 3957, 1341, 7129, 13491, 65369, 4339}},
+{8460, 17, 23320, {1, 3, 7, 1, 5, 45, 103, 209, 183, 205, 525, 2417, 847, 10801, 10699, 16723, 36421}},
+{8461, 17, 23325, {1, 3, 7, 13, 3, 57, 37, 75, 299, 359, 2017, 125, 6737, 4859, 18443, 20765, 40319}},
+{8462, 17, 23356, {1, 1, 3, 5, 5, 17, 43, 141, 31, 141, 1019, 1685, 6831, 9433, 31245, 29227, 64083}},
+{8463, 17, 23374, {1, 3, 1, 13, 25, 47, 107, 69, 459, 595, 1759, 3391, 1531, 15197, 25975, 16971, 70861}},
+{8464, 17, 23388, {1, 1, 3, 11, 3, 53, 63, 211, 69, 469, 1407, 1435, 2763, 917, 19943, 16591, 97101}},
+{8465, 17, 23402, {1, 3, 5, 13, 25, 41, 39, 61, 319, 809, 1109, 169, 3101, 8801, 21697, 50759, 130985}},
+{8466, 17, 23415, {1, 3, 1, 9, 23, 1, 11, 249, 243, 605, 1419, 269, 1601, 2063, 5365, 38077, 106161}},
+{8467, 17, 23421, {1, 1, 7, 7, 19, 55, 97, 155, 477, 845, 61, 263, 1337, 8857, 31611, 44417, 43111}},
+{8468, 17, 23426, {1, 3, 3, 15, 7, 63, 45, 239, 291, 279, 1875, 3769, 1571, 15857, 13335, 17209, 34399}},
+{8469, 17, 23443, {1, 1, 7, 11, 19, 19, 69, 111, 217, 927, 1643, 1077, 4763, 15893, 17491, 39737, 10705}},
+{8470, 17, 23446, {1, 1, 5, 11, 3, 3, 31, 199, 109, 403, 973, 3833, 2729, 7285, 26743, 53915, 96203}},
+{8471, 17, 23455, {1, 3, 3, 11, 9, 7, 19, 145, 495, 805, 381, 919, 1323, 4343, 15887, 5163, 68267}},
+{8472, 17, 23461, {1, 1, 3, 11, 15, 31, 27, 201, 251, 279, 1377, 1313, 7143, 9731, 10451, 63431, 31307}},
+{8473, 17, 23468, {1, 1, 7, 1, 1, 55, 35, 249, 133, 645, 425, 279, 6401, 11687, 751, 947, 21791}},
+{8474, 17, 23471, {1, 3, 5, 9, 5, 43, 89, 31, 419, 573, 1087, 2197, 3451, 2393, 6569, 4859, 36607}},
+{8475, 17, 23485, {1, 3, 5, 15, 25, 51, 11, 149, 483, 789, 661, 967, 3537, 15511, 26587, 29861, 120337}},
+{8476, 17, 23486, {1, 3, 5, 13, 21, 39, 75, 111, 57, 321, 1591, 381, 7399, 10807, 26651, 62489, 78341}},
+{8477, 17, 23488, {1, 3, 1, 13, 1, 1, 49, 137, 193, 967, 805, 221, 803, 11381, 27803, 51013, 10475}},
+{8478, 17, 23498, {1, 3, 7, 5, 3, 13, 47, 195, 123, 753, 397, 1203, 981, 12863, 20845, 36155, 19055}},
+{8479, 17, 23500, {1, 1, 1, 9, 9, 11, 53, 203, 3, 163, 1537, 2061, 941, 12629, 16053, 34881, 31489}},
+{8480, 17, 23515, {1, 1, 1, 15, 5, 23, 51, 197, 459, 21, 1989, 2529, 4267, 1505, 8951, 15777, 20493}},
+{8481, 17, 23521, {1, 1, 7, 3, 31, 55, 9, 55, 217, 695, 1563, 4077, 3207, 7029, 10881, 39581, 82511}},
+{8482, 17, 23527, {1, 3, 1, 5, 1, 11, 81, 1, 505, 631, 1093, 3655, 2085, 7349, 5009, 49381, 30527}},
+{8483, 17, 23534, {1, 1, 7, 1, 27, 51, 25, 235, 213, 59, 611, 3883, 2909, 6411, 19605, 49001, 114529}},
+{8484, 17, 23546, {1, 3, 5, 3, 25, 29, 19, 137, 199, 681, 1625, 2711, 4873, 14677, 9767, 30441, 54673}},
+{8485, 17, 23559, {1, 1, 1, 9, 27, 43, 109, 161, 139, 675, 741, 2839, 1425, 5701, 19897, 12787, 33069}},
+{8486, 17, 23560, {1, 3, 5, 11, 21, 19, 77, 107, 197, 591, 1899, 1311, 3347, 6369, 26891, 3771, 32455}},
+{8487, 17, 23566, {1, 1, 7, 15, 31, 13, 109, 69, 207, 349, 249, 971, 7891, 10919, 31579, 38453, 124601}},
+{8488, 17, 23584, {1, 3, 5, 5, 27, 61, 67, 193, 53, 259, 1729, 4033, 2637, 8217, 22351, 4001, 118527}},
+{8489, 17, 23587, {1, 1, 3, 5, 9, 45, 55, 73, 189, 131, 1947, 1889, 837, 4085, 10393, 64359, 1037}},
+{8490, 17, 23594, {1, 3, 7, 3, 13, 51, 55, 37, 335, 939, 35, 461, 5057, 2595, 3305, 58823, 3941}},
+{8491, 17, 23602, {1, 1, 7, 11, 7, 3, 121, 139, 241, 477, 615, 2707, 5391, 7611, 11563, 41083, 16719}},
+{8492, 17, 23607, {1, 3, 3, 15, 27, 55, 13, 221, 195, 543, 215, 4035, 1647, 8111, 26425, 43571, 79893}},
+{8493, 17, 23616, {1, 1, 1, 5, 31, 5, 35, 145, 481, 339, 1951, 2155, 1309, 9851, 31505, 37371, 21247}},
+{8494, 17, 23621, {1, 1, 7, 9, 7, 5, 73, 119, 3, 741, 1351, 2855, 2207, 1465, 12047, 13507, 129173}},
+{8495, 17, 23631, {1, 1, 7, 13, 5, 57, 119, 63, 367, 327, 1257, 3191, 6929, 9593, 16565, 54397, 100305}},
+{8496, 17, 23634, {1, 3, 1, 11, 9, 1, 85, 53, 65, 945, 17, 1963, 4819, 16173, 11669, 53579, 33701}},
+{8497, 17, 23636, {1, 1, 3, 15, 25, 27, 3, 25, 23, 429, 197, 2717, 6107, 6719, 12457, 31793, 78647}},
+{8498, 17, 23649, {1, 1, 3, 1, 7, 63, 111, 235, 299, 91, 369, 1423, 7083, 4229, 18535, 33793, 19943}},
+{8499, 17, 23652, {1, 1, 7, 13, 9, 11, 123, 9, 169, 895, 1989, 1047, 6139, 11773, 19381, 9593, 14809}},
+{8500, 17, 23679, {1, 3, 1, 3, 29, 31, 63, 91, 59, 391, 1695, 2459, 3301, 5615, 3425, 8029, 16069}},
+{8501, 17, 23686, {1, 1, 7, 1, 25, 25, 79, 49, 131, 695, 987, 2911, 1109, 8237, 18227, 37287, 22443}},
+{8502, 17, 23697, {1, 3, 3, 3, 25, 21, 33, 207, 187, 381, 129, 445, 2967, 5119, 18777, 14849, 97115}},
+{8503, 17, 23703, {1, 1, 7, 13, 19, 9, 93, 185, 391, 579, 1509, 3245, 3921, 9473, 4795, 6685, 49549}},
+{8504, 17, 23714, {1, 1, 5, 11, 1, 49, 57, 127, 363, 811, 1383, 2869, 7625, 15177, 2581, 64253, 53677}},
+{8505, 17, 23719, {1, 1, 7, 3, 7, 27, 73, 187, 31, 1011, 1013, 3269, 6625, 5001, 20805, 13331, 93725}},
+{8506, 17, 23723, {1, 3, 7, 1, 23, 61, 123, 9, 141, 113, 1009, 3713, 4947, 9929, 24125, 1101, 104249}},
+{8507, 17, 23726, {1, 3, 7, 3, 23, 17, 25, 187, 189, 875, 1435, 163, 4197, 6619, 29031, 23117, 45347}},
+{8508, 17, 23728, {1, 1, 5, 7, 11, 17, 9, 55, 117, 223, 417, 3993, 1843, 5817, 20435, 56705, 98337}},
+{8509, 17, 23733, {1, 1, 7, 3, 21, 59, 3, 77, 297, 61, 407, 1603, 3209, 1611, 30185, 50275, 56139}},
+{8510, 17, 23740, {1, 1, 1, 5, 31, 3, 101, 167, 367, 543, 339, 1885, 7855, 9989, 30969, 6735, 108123}},
+{8511, 17, 23751, {1, 1, 3, 9, 27, 63, 9, 79, 335, 351, 673, 3107, 3955, 1799, 16879, 57631, 109073}},
+{8512, 17, 23755, {1, 1, 1, 3, 27, 17, 107, 115, 155, 371, 379, 2837, 6213, 2663, 1101, 451, 69517}},
+{8513, 17, 23765, {1, 1, 3, 9, 13, 3, 55, 9, 449, 43, 1011, 3281, 5311, 223, 10715, 6639, 79949}},
+{8514, 17, 23766, {1, 3, 3, 11, 23, 9, 43, 185, 271, 1005, 1041, 2633, 377, 4247, 10417, 51903, 19239}},
+{8515, 17, 23769, {1, 3, 1, 9, 15, 39, 115, 233, 33, 425, 1979, 583, 1901, 8943, 1527, 56065, 50159}},
+{8516, 17, 23779, {1, 1, 3, 1, 13, 1, 105, 149, 13, 625, 671, 1811, 3701, 241, 27357, 25835, 127265}},
+{8517, 17, 23794, {1, 3, 1, 9, 11, 23, 107, 197, 21, 589, 1065, 2591, 1163, 15013, 8931, 6355, 87079}},
+{8518, 17, 23796, {1, 3, 5, 3, 17, 5, 121, 61, 99, 987, 2033, 2237, 2299, 14689, 19785, 9599, 101035}},
+{8519, 17, 23803, {1, 1, 1, 1, 17, 25, 5, 97, 55, 75, 1419, 2793, 7215, 3185, 7029, 23023, 89089}},
+{8520, 17, 23813, {1, 3, 3, 3, 11, 57, 103, 191, 405, 463, 1421, 253, 6069, 10905, 18193, 719, 17337}},
+{8521, 17, 23820, {1, 3, 5, 11, 23, 37, 39, 169, 295, 527, 1671, 3913, 6057, 689, 27719, 47245, 95895}},
+{8522, 17, 23841, {1, 3, 7, 5, 13, 9, 43, 189, 411, 155, 559, 3701, 1623, 2401, 10359, 22675, 41897}},
+{8523, 17, 23853, {1, 1, 1, 11, 17, 55, 47, 101, 357, 669, 857, 2745, 6425, 11839, 13095, 10757, 52383}},
+{8524, 17, 23861, {1, 1, 7, 5, 11, 13, 53, 151, 93, 455, 133, 3353, 1417, 7917, 12913, 2615, 34281}},
+{8525, 17, 23862, {1, 1, 3, 5, 29, 57, 43, 35, 203, 423, 311, 3133, 1757, 1291, 2019, 3115, 126939}},
+{8526, 17, 23873, {1, 1, 3, 11, 9, 43, 119, 95, 135, 351, 1865, 2821, 717, 6275, 19713, 42315, 97935}},
+{8527, 17, 23876, {1, 3, 7, 7, 31, 51, 7, 29, 405, 31, 1765, 3231, 1315, 1307, 26469, 62033, 35619}},
+{8528, 17, 23897, {1, 1, 5, 7, 5, 17, 49, 137, 501, 631, 1401, 2851, 6971, 14721, 4329, 26483, 120007}},
+{8529, 17, 23898, {1, 1, 5, 13, 21, 19, 95, 93, 125, 331, 1797, 1653, 1891, 11081, 30989, 24671, 95421}},
+{8530, 17, 23903, {1, 3, 3, 11, 13, 29, 61, 157, 165, 39, 661, 89, 637, 1397, 12561, 62399, 129107}},
+{8531, 17, 23904, {1, 3, 1, 15, 13, 19, 5, 115, 345, 903, 531, 4069, 6775, 7433, 569, 21779, 13271}},
+{8532, 17, 23910, {1, 3, 3, 9, 5, 53, 17, 115, 67, 939, 1907, 3979, 4311, 3573, 857, 34931, 112397}},
+{8533, 17, 23931, {1, 3, 7, 11, 9, 47, 83, 85, 277, 219, 1701, 3013, 3037, 3473, 3797, 40713, 118573}},
+{8534, 17, 23933, {1, 1, 3, 13, 25, 33, 117, 115, 179, 119, 487, 3213, 2873, 17, 20865, 20043, 64381}},
+{8535, 17, 23934, {1, 1, 1, 3, 1, 45, 73, 103, 75, 579, 981, 2449, 2141, 8697, 22995, 59693, 104461}},
+{8536, 17, 23943, {1, 3, 1, 1, 29, 9, 9, 201, 55, 389, 1069, 2057, 4149, 9217, 10753, 7889, 95849}},
+{8537, 17, 23952, {1, 3, 7, 9, 27, 39, 19, 223, 7, 253, 55, 503, 3339, 6049, 32603, 34807, 115403}},
+{8538, 17, 23955, {1, 1, 5, 3, 13, 21, 67, 87, 205, 309, 1371, 1579, 281, 16135, 28403, 25951, 24109}},
+{8539, 17, 23962, {1, 3, 1, 3, 17, 21, 49, 77, 393, 943, 1701, 2661, 5173, 12875, 2731, 40531, 19301}},
+{8540, 17, 23971, {1, 3, 1, 5, 23, 29, 61, 161, 373, 389, 1699, 359, 2513, 4717, 30397, 24395, 20881}},
+{8541, 17, 23978, {1, 3, 5, 5, 29, 3, 115, 251, 277, 487, 7, 3301, 7945, 14233, 20497, 62035, 21537}},
+{8542, 17, 23998, {1, 1, 1, 9, 7, 59, 23, 85, 367, 109, 1761, 4011, 6535, 8263, 2081, 63647, 69807}},
+{8543, 17, 24003, {1, 1, 7, 11, 21, 41, 29, 219, 271, 617, 929, 407, 2899, 14299, 7645, 44815, 58817}},
+{8544, 17, 24009, {1, 3, 5, 7, 11, 29, 119, 33, 261, 571, 2013, 3327, 2181, 12767, 93, 2437, 76533}},
+{8545, 17, 24017, {1, 1, 7, 13, 17, 39, 55, 203, 261, 917, 967, 3651, 7235, 13751, 14439, 7591, 96553}},
+{8546, 17, 24045, {1, 1, 1, 1, 11, 39, 19, 21, 125, 93, 1773, 1155, 6213, 7173, 9057, 6219, 4643}},
+{8547, 17, 24046, {1, 3, 1, 5, 1, 31, 55, 143, 425, 539, 61, 3377, 7647, 257, 15007, 24511, 8707}},
+{8548, 17, 24060, {1, 3, 3, 11, 27, 51, 103, 197, 427, 139, 181, 1169, 3123, 11803, 5285, 1321, 62267}},
+{8549, 17, 24064, {1, 3, 5, 9, 11, 3, 13, 149, 197, 37, 31, 927, 3313, 16149, 14209, 60177, 46525}},
+{8550, 17, 24076, {1, 1, 5, 13, 15, 29, 103, 49, 355, 797, 1253, 1833, 621, 3877, 9981, 49207, 91035}},
+{8551, 17, 24079, {1, 1, 3, 3, 13, 19, 27, 51, 151, 275, 35, 3755, 7511, 14197, 26141, 43765, 104327}},
+{8552, 17, 24087, {1, 3, 5, 15, 23, 47, 101, 213, 97, 957, 831, 1533, 7913, 15763, 29717, 60425, 38559}},
+{8553, 17, 24094, {1, 1, 7, 9, 29, 31, 49, 245, 361, 299, 151, 2969, 1487, 1761, 11697, 4043, 100909}},
+{8554, 17, 24100, {1, 1, 1, 3, 17, 49, 99, 159, 3, 525, 1527, 3435, 5113, 459, 13341, 54103, 85813}},
+{8555, 17, 24118, {1, 3, 1, 1, 5, 59, 35, 75, 107, 91, 1621, 3261, 619, 3271, 10813, 29857, 1547}},
+{8556, 17, 24121, {1, 1, 5, 9, 9, 33, 85, 245, 39, 879, 1621, 2587, 3825, 12939, 30113, 24611, 68491}},
+{8557, 17, 24132, {1, 3, 1, 3, 9, 39, 93, 241, 307, 237, 3, 1763, 7729, 9257, 31911, 32591, 77333}},
+{8558, 17, 24147, {1, 3, 1, 3, 27, 7, 51, 121, 317, 361, 1027, 95, 7035, 3097, 21007, 38311, 88287}},
+{8559, 17, 24165, {1, 3, 7, 3, 19, 3, 111, 115, 339, 793, 1571, 3101, 1911, 14929, 12841, 45871, 119905}},
+{8560, 17, 24172, {1, 1, 5, 7, 31, 61, 37, 143, 279, 941, 1215, 2411, 7617, 1657, 10189, 19139, 6307}},
+{8561, 17, 24177, {1, 1, 3, 9, 21, 35, 13, 157, 187, 79, 689, 1085, 37, 4549, 5901, 15321, 61627}},
+{8562, 17, 24184, {1, 3, 1, 13, 15, 39, 21, 231, 39, 327, 801, 2321, 587, 1877, 3489, 54467, 95773}},
+{8563, 17, 24187, {1, 1, 5, 7, 1, 9, 53, 1, 243, 365, 789, 3833, 317, 10697, 26567, 65187, 22507}},
+{8564, 17, 24213, {1, 3, 3, 7, 9, 41, 31, 135, 425, 939, 15, 2043, 6593, 7651, 25467, 62549, 35847}},
+{8565, 17, 24217, {1, 1, 1, 7, 15, 23, 19, 57, 421, 25, 1037, 3055, 6173, 12451, 485, 54567, 109561}},
+{8566, 17, 24223, {1, 3, 5, 1, 3, 29, 67, 233, 157, 677, 1711, 513, 4673, 2895, 1983, 31075, 1861}},
+{8567, 17, 24230, {1, 1, 1, 1, 7, 39, 115, 251, 275, 791, 15, 1685, 6835, 14685, 12607, 28213, 121475}},
+{8568, 17, 24234, {1, 1, 5, 5, 13, 11, 103, 93, 489, 709, 1339, 2407, 1663, 10195, 3135, 15531, 88427}},
+{8569, 17, 24241, {1, 1, 7, 7, 17, 1, 123, 143, 31, 721, 1739, 2273, 3785, 10261, 14741, 52573, 113677}},
+{8570, 17, 24248, {1, 3, 7, 3, 9, 21, 77, 13, 241, 429, 165, 3399, 7543, 2633, 21129, 13537, 84473}},
+{8571, 17, 24259, {1, 1, 1, 11, 21, 33, 125, 123, 189, 337, 163, 3727, 2101, 14113, 1719, 46017, 68601}},
+{8572, 17, 24262, {1, 1, 7, 9, 9, 53, 101, 111, 125, 605, 1419, 3901, 1769, 4585, 20063, 20857, 21901}},
+{8573, 17, 24271, {1, 3, 7, 11, 1, 19, 51, 7, 457, 119, 871, 3847, 57, 11437, 28763, 58831, 675}},
+{8574, 17, 24279, {1, 3, 1, 15, 25, 63, 69, 25, 405, 823, 1701, 2441, 7561, 8679, 31643, 29325, 25563}},
+{8575, 17, 24286, {1, 1, 3, 9, 15, 5, 89, 13, 73, 951, 959, 2693, 4565, 13095, 991, 12419, 8267}},
+{8576, 17, 24289, {1, 1, 7, 1, 15, 1, 119, 223, 213, 585, 1047, 2623, 4141, 2043, 1583, 59155, 5133}},
+{8577, 17, 24295, {1, 3, 3, 3, 17, 37, 81, 233, 87, 843, 1597, 1251, 4713, 10813, 24357, 48499, 84465}},
+{8578, 17, 24296, {1, 1, 1, 1, 11, 55, 125, 5, 255, 809, 543, 2351, 7079, 7801, 29247, 23937, 97405}},
+{8579, 17, 24299, {1, 3, 3, 5, 17, 55, 87, 245, 371, 679, 943, 655, 5857, 261, 28229, 22519, 35191}},
+{8580, 17, 24314, {1, 1, 7, 15, 9, 49, 25, 155, 13, 893, 1303, 2317, 2903, 15601, 1433, 20397, 70125}},
+{8581, 17, 24336, {1, 3, 5, 3, 11, 47, 99, 63, 253, 95, 1023, 397, 4307, 4771, 17027, 19833, 18269}},
+{8582, 17, 24342, {1, 3, 3, 7, 25, 17, 69, 119, 475, 575, 1637, 3785, 649, 11557, 22457, 38633, 96153}},
+{8583, 17, 24346, {1, 1, 1, 5, 31, 55, 85, 83, 307, 201, 1543, 727, 977, 15779, 21907, 31025, 38969}},
+{8584, 17, 24357, {1, 3, 5, 1, 7, 53, 107, 239, 341, 237, 1567, 2717, 3197, 12419, 23733, 42119, 86619}},
+{8585, 17, 24367, {1, 1, 5, 13, 3, 7, 105, 95, 201, 953, 781, 2043, 5263, 13427, 10303, 60027, 19297}},
+{8586, 17, 24370, {1, 1, 5, 15, 25, 51, 5, 77, 165, 297, 1281, 1635, 4139, 11569, 32325, 23135, 27013}},
+{8587, 17, 24372, {1, 1, 3, 9, 3, 59, 107, 137, 251, 715, 1477, 511, 5629, 12205, 7541, 62559, 4253}},
+{8588, 17, 24387, {1, 1, 7, 11, 31, 29, 7, 251, 119, 547, 1179, 3063, 1625, 8941, 30515, 13601, 72741}},
+{8589, 17, 24389, {1, 3, 7, 13, 27, 43, 31, 43, 465, 355, 1063, 2305, 1425, 11963, 27327, 53335, 127517}},
+{8590, 17, 24402, {1, 3, 1, 3, 21, 17, 53, 171, 269, 783, 349, 1879, 575, 13537, 16931, 61171, 23499}},
+{8591, 17, 24414, {1, 3, 5, 3, 11, 5, 121, 227, 237, 841, 431, 3209, 3241, 6071, 23465, 39533, 102391}},
+{8592, 17, 24420, {1, 3, 5, 11, 9, 1, 59, 143, 181, 869, 1859, 1543, 6419, 13305, 29075, 28051, 105799}},
+{8593, 17, 24435, {1, 1, 7, 13, 31, 1, 105, 169, 67, 693, 1667, 2181, 4127, 4605, 3701, 36467, 19631}},
+{8594, 17, 24437, {1, 1, 7, 5, 31, 15, 119, 161, 55, 549, 1195, 4051, 1923, 2497, 8289, 60393, 96181}},
+{8595, 17, 24442, {1, 1, 3, 3, 5, 43, 13, 123, 469, 603, 2047, 2347, 815, 3457, 7503, 25261, 71951}},
+{8596, 17, 24444, {1, 1, 7, 3, 13, 25, 85, 141, 497, 405, 957, 1407, 2075, 12445, 6675, 9993, 40429}},
+{8597, 17, 24447, {1, 1, 5, 13, 29, 43, 99, 113, 307, 1003, 859, 723, 7513, 12249, 12653, 57685, 89551}},
+{8598, 17, 24468, {1, 3, 7, 3, 11, 3, 9, 141, 501, 113, 69, 2285, 4525, 9049, 24765, 11585, 53787}},
+{8599, 17, 24475, {1, 1, 3, 1, 25, 41, 103, 159, 215, 871, 77, 1849, 609, 15877, 32515, 22931, 11933}},
+{8600, 17, 24484, {1, 1, 5, 11, 3, 27, 27, 111, 479, 861, 1041, 3777, 4443, 3095, 30379, 6293, 30823}},
+{8601, 17, 24493, {1, 3, 5, 5, 27, 45, 9, 25, 451, 845, 1153, 897, 325, 15679, 30151, 37695, 54593}},
+{8602, 17, 24494, {1, 3, 7, 1, 15, 47, 87, 135, 87, 567, 221, 3173, 769, 8173, 2957, 51287, 20961}},
+{8603, 17, 24496, {1, 3, 1, 9, 3, 33, 1, 71, 147, 983, 1485, 3531, 213, 2353, 28269, 49353, 88343}},
+{8604, 17, 24514, {1, 1, 3, 11, 11, 63, 109, 255, 35, 127, 1777, 791, 1379, 9539, 4915, 21593, 98901}},
+{8605, 17, 24519, {1, 1, 7, 5, 3, 47, 93, 219, 381, 963, 359, 2461, 7629, 2803, 17345, 54311, 79057}},
+{8606, 17, 24533, {1, 3, 5, 13, 13, 21, 1, 65, 455, 203, 29, 3717, 4495, 1285, 25289, 38597, 42431}},
+{8607, 17, 24538, {1, 1, 3, 3, 27, 57, 7, 171, 65, 469, 1921, 3855, 1637, 5517, 14907, 48239, 117573}},
+{8608, 17, 24559, {1, 3, 5, 1, 11, 35, 105, 251, 19, 219, 1191, 2177, 7885, 8399, 30527, 61415, 122215}},
+{8609, 17, 24568, {1, 3, 5, 5, 21, 25, 59, 193, 509, 147, 1805, 561, 3505, 9639, 14221, 31, 99261}},
+{8610, 17, 24573, {1, 1, 5, 13, 31, 23, 35, 143, 367, 385, 1335, 2497, 3573, 8113, 16661, 16147, 8763}},
+{8611, 17, 24577, {1, 1, 7, 13, 15, 27, 35, 15, 7, 539, 633, 1145, 2267, 11527, 20975, 16689, 58227}},
+{8612, 17, 24587, {1, 1, 1, 15, 9, 11, 51, 121, 381, 331, 1445, 187, 519, 15827, 27611, 32891, 113671}},
+{8613, 17, 24592, {1, 3, 1, 5, 19, 3, 77, 67, 107, 105, 1025, 3229, 6869, 5717, 4227, 28489, 59759}},
+{8614, 17, 24601, {1, 1, 5, 15, 25, 23, 7, 25, 103, 733, 525, 453, 6467, 2901, 7197, 33267, 68177}},
+{8615, 17, 24602, {1, 1, 5, 7, 27, 27, 41, 93, 449, 733, 571, 411, 1709, 9557, 549, 5925, 24123}},
+{8616, 17, 24608, {1, 1, 7, 5, 31, 57, 119, 227, 105, 533, 717, 3357, 2495, 6467, 7211, 38169, 44603}},
+{8617, 17, 24645, {1, 1, 5, 7, 29, 9, 125, 241, 471, 571, 1271, 2911, 8087, 5067, 31139, 39681, 28579}},
+{8618, 17, 24650, {1, 3, 5, 11, 25, 53, 109, 35, 183, 109, 1961, 1681, 7773, 6935, 28049, 37279, 96829}},
+{8619, 17, 24657, {1, 1, 1, 11, 1, 17, 47, 245, 231, 747, 1395, 1635, 5129, 3165, 627, 34463, 38967}},
+{8620, 17, 24664, {1, 3, 5, 1, 9, 41, 25, 215, 251, 525, 1399, 3405, 7399, 11041, 5599, 51167, 38697}},
+{8621, 17, 24670, {1, 3, 3, 13, 11, 15, 121, 95, 139, 611, 633, 3941, 2619, 15123, 28535, 64823, 17527}},
+{8622, 17, 24673, {1, 3, 7, 13, 21, 53, 65, 175, 81, 5, 699, 1525, 7397, 2465, 4479, 58225, 26387}},
+{8623, 17, 24676, {1, 1, 5, 7, 9, 31, 31, 149, 359, 613, 397, 153, 4861, 8195, 22969, 26003, 124423}},
+{8624, 17, 24680, {1, 3, 1, 13, 27, 17, 107, 27, 19, 13, 1481, 573, 7701, 6273, 30255, 16125, 11809}},
+{8625, 17, 24686, {1, 3, 1, 9, 15, 1, 45, 105, 287, 901, 667, 3197, 3493, 12259, 1511, 63361, 94257}},
+{8626, 17, 24700, {1, 3, 1, 3, 25, 53, 19, 87, 365, 585, 1569, 1731, 3747, 11985, 22673, 17767, 113779}},
+{8627, 17, 24704, {1, 3, 3, 9, 7, 21, 103, 201, 501, 149, 1939, 3111, 4739, 8389, 27127, 55889, 54487}},
+{8628, 17, 24714, {1, 3, 5, 7, 25, 53, 75, 57, 19, 505, 849, 2631, 6999, 11269, 24541, 17695, 97671}},
+{8629, 17, 24728, {1, 1, 7, 15, 5, 51, 123, 93, 445, 379, 1729, 2747, 5821, 10779, 29335, 57419, 109339}},
+{8630, 17, 24731, {1, 1, 7, 3, 7, 57, 117, 65, 297, 891, 487, 1535, 2361, 10457, 30759, 34571, 129949}},
+{8631, 17, 24733, {1, 3, 5, 5, 17, 51, 27, 103, 55, 925, 947, 1237, 1629, 12687, 14775, 49627, 100939}},
+{8632, 17, 24747, {1, 3, 3, 15, 1, 11, 75, 177, 399, 55, 1705, 1165, 7525, 8909, 13071, 60703, 11561}},
+{8633, 17, 24749, {1, 1, 1, 7, 13, 29, 23, 65, 279, 853, 637, 3947, 4099, 6465, 7061, 50417, 35015}},
+{8634, 17, 24750, {1, 1, 3, 3, 15, 11, 111, 169, 135, 279, 1941, 3035, 3027, 6813, 13363, 20387, 3257}},
+{8635, 17, 24764, {1, 3, 3, 11, 3, 5, 95, 181, 405, 313, 39, 1503, 2443, 3221, 17021, 23485, 43909}},
+{8636, 17, 24782, {1, 1, 1, 3, 17, 63, 27, 247, 441, 533, 449, 3845, 4021, 14269, 31477, 7013, 37473}},
+{8637, 17, 24784, {1, 1, 5, 13, 29, 39, 41, 95, 417, 21, 685, 609, 5787, 13145, 32677, 6121, 50919}},
+{8638, 17, 24793, {1, 1, 5, 3, 17, 5, 93, 143, 171, 681, 1143, 2875, 805, 15823, 29649, 63327, 12041}},
+{8639, 17, 24794, {1, 1, 1, 11, 3, 53, 123, 105, 59, 485, 1799, 2939, 657, 2485, 29563, 36221, 89095}},
+{8640, 17, 24810, {1, 1, 5, 5, 15, 13, 127, 87, 211, 579, 175, 793, 6895, 9051, 17681, 28831, 31783}},
+{8641, 17, 24817, {1, 3, 7, 5, 11, 37, 9, 219, 453, 697, 139, 335, 6411, 8495, 4203, 29065, 114837}},
+{8642, 17, 24820, {1, 1, 3, 5, 31, 25, 89, 215, 249, 271, 1731, 3133, 3947, 10227, 9679, 51303, 82833}},
+{8643, 17, 24823, {1, 3, 5, 1, 31, 15, 7, 131, 369, 757, 1963, 3223, 35, 13967, 31807, 5093, 113743}},
+{8644, 17, 24832, {1, 1, 7, 3, 15, 23, 21, 173, 295, 929, 1137, 3943, 1985, 13015, 8523, 59117, 127}},
+{8645, 17, 24855, {1, 3, 7, 1, 31, 1, 115, 229, 345, 859, 1757, 1835, 7491, 4545, 1483, 40149, 122321}},
+{8646, 17, 24859, {1, 1, 1, 3, 13, 5, 3, 133, 177, 47, 1515, 17, 5663, 3185, 2775, 31389, 37409}},
+{8647, 17, 24862, {1, 1, 3, 3, 31, 3, 43, 137, 185, 803, 709, 391, 3513, 8117, 32593, 46593, 61037}},
+{8648, 17, 24877, {1, 1, 1, 7, 29, 27, 13, 35, 61, 961, 777, 2725, 7379, 7053, 21781, 60285, 49221}},
+{8649, 17, 24890, {1, 3, 7, 15, 7, 7, 15, 123, 109, 97, 361, 791, 4773, 8111, 4319, 13981, 92505}},
+{8650, 17, 24900, {1, 1, 3, 11, 21, 33, 113, 221, 453, 981, 341, 4041, 5129, 5981, 11051, 17243, 19023}},
+{8651, 17, 24904, {1, 3, 1, 1, 19, 7, 75, 213, 467, 221, 1829, 1275, 5729, 6843, 23855, 44805, 89269}},
+{8652, 17, 24909, {1, 1, 3, 7, 5, 29, 39, 125, 147, 329, 1485, 2793, 2329, 14979, 18395, 37951, 58699}},
+{8653, 17, 24910, {1, 3, 1, 3, 11, 37, 117, 189, 103, 381, 39, 31, 5205, 5601, 17127, 49073, 121417}},
+{8654, 17, 24915, {1, 3, 3, 13, 23, 49, 57, 187, 441, 189, 349, 2559, 3313, 1321, 7731, 57309, 80195}},
+{8655, 17, 24922, {1, 3, 7, 1, 17, 9, 21, 15, 447, 333, 959, 3471, 5301, 8573, 9761, 23183, 57997}},
+{8656, 17, 24937, {1, 3, 1, 9, 19, 1, 101, 71, 325, 309, 85, 2097, 8003, 12249, 1887, 2097, 68375}},
+{8657, 17, 24945, {1, 1, 7, 7, 11, 39, 85, 241, 293, 205, 387, 1539, 6583, 1395, 8869, 48843, 49983}},
+{8658, 17, 24962, {1, 3, 7, 13, 11, 23, 83, 125, 55, 429, 169, 1893, 4657, 643, 3405, 9943, 128753}},
+{8659, 17, 24964, {1, 1, 3, 11, 19, 43, 13, 171, 495, 117, 437, 3697, 6723, 6199, 1859, 39637, 111499}},
+{8660, 17, 24991, {1, 1, 1, 5, 1, 31, 83, 199, 129, 941, 1637, 1997, 5011, 14957, 32427, 60797, 4989}},
+{8661, 17, 24992, {1, 3, 3, 3, 5, 61, 33, 225, 315, 157, 1709, 807, 7809, 11063, 319, 20901, 73599}},
+{8662, 17, 24995, {1, 1, 7, 3, 27, 3, 1, 173, 125, 769, 1203, 3357, 4899, 13115, 7081, 42459, 18525}},
+{8663, 17, 25001, {1, 1, 7, 9, 9, 27, 43, 115, 229, 867, 661, 1825, 2883, 4285, 22393, 65141, 24699}},
+{8664, 17, 25009, {1, 1, 3, 7, 5, 9, 93, 47, 33, 823, 309, 2977, 5791, 9177, 27645, 35683, 57455}},
+{8665, 17, 25019, {1, 1, 5, 7, 9, 53, 9, 77, 499, 1023, 917, 209, 7311, 249, 773, 18303, 41447}},
+{8666, 17, 25021, {1, 1, 3, 5, 7, 9, 33, 73, 325, 369, 1657, 2257, 2893, 13911, 10797, 21055, 103511}},
+{8667, 17, 25029, {1, 3, 1, 3, 21, 31, 125, 29, 149, 513, 979, 2271, 989, 9541, 4179, 13215, 71369}},
+{8668, 17, 25034, {1, 1, 7, 7, 19, 41, 39, 165, 59, 79, 137, 3479, 3389, 6635, 21467, 51073, 20765}},
+{8669, 17, 25036, {1, 3, 3, 5, 7, 13, 109, 53, 335, 627, 339, 3825, 287, 6077, 11319, 2377, 112693}},
+{8670, 17, 25039, {1, 3, 3, 1, 3, 57, 9, 47, 437, 717, 563, 1219, 6191, 9081, 21533, 2651, 17275}},
+{8671, 17, 25057, {1, 1, 1, 5, 21, 9, 109, 109, 339, 947, 1699, 1487, 6477, 12601, 12327, 39427, 80937}},
+{8672, 17, 25063, {1, 1, 7, 9, 1, 5, 55, 43, 95, 733, 1151, 3657, 2119, 11947, 21279, 21581, 22053}},
+{8673, 17, 25064, {1, 3, 5, 11, 7, 9, 97, 149, 55, 523, 1911, 1389, 5343, 5533, 15439, 65313, 73421}},
+{8674, 17, 25075, {1, 1, 3, 7, 19, 15, 119, 141, 57, 243, 423, 981, 1407, 12633, 20455, 53069, 98593}},
+{8675, 17, 25077, {1, 1, 3, 3, 15, 57, 71, 203, 15, 133, 601, 805, 2821, 11623, 147, 4333, 97681}},
+{8676, 17, 25084, {1, 1, 5, 7, 17, 61, 15, 251, 53, 699, 105, 1195, 3979, 41, 9077, 5145, 80057}},
+{8677, 17, 25088, {1, 1, 5, 15, 29, 33, 53, 19, 41, 471, 1143, 65, 5833, 8417, 17263, 35859, 45035}},
+{8678, 17, 25091, {1, 1, 1, 1, 15, 51, 73, 131, 181, 147, 1863, 3777, 1749, 10135, 11591, 12395, 85163}},
+{8679, 17, 25105, {1, 3, 1, 9, 23, 63, 83, 199, 87, 499, 2025, 863, 4665, 3941, 17647, 52463, 108615}},
+{8680, 17, 25134, {1, 3, 5, 7, 11, 39, 65, 161, 367, 593, 699, 1807, 7217, 5221, 22093, 44933, 6201}},
+{8681, 17, 25165, {1, 1, 7, 13, 9, 41, 35, 77, 353, 291, 1267, 3923, 5397, 15401, 30317, 14945, 8715}},
+{8682, 17, 25183, {1, 3, 1, 15, 11, 3, 29, 25, 505, 945, 1425, 2297, 1133, 4675, 8069, 55115, 114177}},
+{8683, 17, 25184, {1, 3, 1, 5, 27, 63, 25, 7, 5, 399, 473, 1325, 7391, 5953, 27755, 65407, 89435}},
+{8684, 17, 25202, {1, 3, 3, 13, 21, 61, 5, 119, 23, 999, 849, 1225, 3077, 821, 12059, 43223, 45427}},
+{8685, 17, 25204, {1, 3, 7, 13, 1, 5, 93, 173, 181, 453, 1449, 3823, 1713, 14737, 8891, 43643, 1983}},
+{8686, 17, 25211, {1, 1, 3, 3, 29, 53, 31, 163, 321, 539, 1283, 429, 3449, 15617, 4761, 21187, 120725}},
+{8687, 17, 25223, {1, 1, 1, 1, 13, 27, 49, 37, 33, 631, 375, 425, 2465, 8773, 2777, 2115, 35633}},
+{8688, 17, 25224, {1, 3, 5, 3, 25, 25, 27, 201, 63, 259, 1571, 1143, 2325, 6773, 11941, 28897, 19719}},
+{8689, 17, 25235, {1, 1, 3, 5, 11, 39, 59, 203, 37, 899, 559, 2599, 4397, 12159, 29579, 51251, 83213}},
+{8690, 17, 25241, {1, 1, 1, 7, 9, 19, 63, 169, 257, 921, 381, 3605, 3479, 1739, 26599, 20599, 29617}},
+{8691, 17, 25253, {1, 1, 1, 9, 7, 29, 123, 35, 419, 963, 855, 1903, 6199, 2727, 29811, 49279, 101673}},
+{8692, 17, 25258, {1, 3, 5, 11, 29, 23, 73, 13, 467, 935, 181, 3837, 8117, 11501, 18361, 26803, 99471}},
+{8693, 17, 25277, {1, 1, 1, 5, 31, 41, 109, 45, 115, 113, 1893, 727, 2453, 13463, 22339, 13495, 11473}},
+{8694, 17, 25278, {1, 1, 5, 9, 5, 31, 109, 145, 511, 243, 57, 2219, 1601, 1821, 12787, 48239, 89645}},
+{8695, 17, 25280, {1, 3, 1, 7, 19, 41, 25, 57, 45, 489, 1531, 3959, 2007, 14247, 13445, 1991, 114977}},
+{8696, 17, 25290, {1, 3, 7, 15, 7, 17, 107, 27, 249, 207, 183, 2483, 5817, 8927, 10715, 63631, 51947}},
+{8697, 17, 25295, {1, 3, 1, 3, 13, 21, 57, 113, 171, 885, 1335, 783, 7575, 4443, 19497, 13827, 130727}},
+{8698, 17, 25300, {1, 1, 5, 7, 19, 33, 95, 13, 387, 297, 1597, 767, 7543, 16063, 10367, 51683, 119811}},
+{8699, 17, 25307, {1, 3, 7, 9, 27, 57, 111, 209, 305, 139, 179, 25, 2295, 2593, 31361, 23677, 74501}},
+{8700, 17, 25319, {1, 3, 7, 3, 21, 63, 97, 189, 3, 693, 209, 2227, 7169, 9, 32575, 61521, 115155}},
+{8701, 17, 25323, {1, 1, 1, 11, 13, 21, 125, 249, 193, 895, 139, 1207, 5941, 5821, 6623, 7753, 80939}},
+{8702, 17, 25326, {1, 3, 5, 5, 11, 49, 17, 21, 423, 497, 835, 539, 6195, 12783, 1271, 20069, 2657}},
+{8703, 17, 25333, {1, 1, 7, 15, 13, 39, 83, 191, 77, 95, 661, 3627, 1853, 1349, 23109, 43583, 104121}},
+{8704, 17, 25334, {1, 3, 1, 15, 31, 15, 71, 255, 489, 91, 351, 367, 309, 6275, 18325, 51231, 52159}},
+{8705, 17, 25337, {1, 1, 7, 13, 21, 49, 37, 135, 355, 421, 507, 2563, 4955, 4095, 1933, 29517, 119699}},
+{8706, 17, 25348, {1, 1, 1, 1, 27, 41, 15, 161, 475, 635, 863, 3773, 6015, 6197, 24261, 26271, 42375}},
+{8707, 17, 25351, {1, 1, 7, 13, 25, 7, 23, 185, 129, 597, 1561, 3003, 2879, 15187, 4913, 24589, 12927}},
+{8708, 17, 25372, {1, 1, 3, 3, 9, 23, 49, 233, 345, 83, 823, 2627, 5019, 2365, 23755, 9855, 48515}},
+{8709, 17, 25381, {1, 3, 1, 1, 11, 7, 117, 213, 27, 923, 375, 2597, 8173, 8935, 16487, 49283, 104569}},
+{8710, 17, 25403, {1, 1, 7, 7, 23, 13, 61, 131, 313, 883, 495, 1105, 6207, 1473, 21655, 51883, 403}},
+{8711, 17, 25406, {1, 3, 3, 1, 25, 5, 5, 159, 243, 929, 1429, 1151, 5043, 11551, 21231, 38767, 105299}},
+{8712, 17, 25431, {1, 3, 7, 7, 15, 37, 49, 219, 67, 147, 873, 2391, 455, 9565, 8977, 64759, 40347}},
+{8713, 17, 25437, {1, 1, 1, 13, 21, 13, 13, 243, 303, 333, 187, 3591, 871, 2501, 30853, 5247, 48855}},
+{8714, 17, 25453, {1, 1, 1, 5, 1, 5, 127, 249, 23, 79, 789, 3507, 8119, 5025, 26545, 54009, 100633}},
+{8715, 17, 25459, {1, 3, 3, 11, 3, 31, 27, 115, 423, 309, 1805, 169, 789, 4081, 28139, 35355, 47991}},
+{8716, 17, 25462, {1, 3, 1, 5, 19, 13, 43, 165, 165, 241, 309, 1703, 7631, 5899, 12041, 21235, 97045}},
+{8717, 17, 25466, {1, 3, 1, 13, 15, 49, 29, 199, 93, 611, 77, 2681, 191, 10215, 8115, 11895, 108687}},
+{8718, 17, 25477, {1, 1, 3, 3, 13, 45, 15, 151, 345, 111, 1829, 1357, 6317, 5239, 26193, 46763, 73101}},
+{8719, 17, 25484, {1, 3, 7, 3, 1, 19, 119, 63, 23, 759, 173, 307, 967, 2731, 9353, 14479, 119}},
+{8720, 17, 25495, {1, 3, 5, 15, 5, 21, 127, 21, 419, 575, 991, 3465, 7365, 5711, 30657, 43513, 22447}},
+{8721, 17, 25501, {1, 3, 7, 1, 19, 5, 49, 7, 45, 963, 1755, 3745, 4061, 4619, 9089, 59953, 100265}},
+{8722, 17, 25506, {1, 1, 1, 3, 25, 53, 97, 97, 347, 749, 823, 1499, 8151, 9957, 731, 22317, 121623}},
+{8723, 17, 25511, {1, 3, 5, 5, 19, 3, 121, 127, 313, 457, 1737, 4065, 5295, 7957, 16373, 62085, 5711}},
+{8724, 17, 25515, {1, 1, 7, 13, 7, 37, 97, 43, 179, 837, 161, 477, 5095, 4985, 111, 58743, 24049}},
+{8725, 17, 25525, {1, 3, 1, 13, 27, 13, 91, 241, 339, 235, 111, 369, 3361, 15105, 11097, 23955, 53561}},
+{8726, 17, 25529, {1, 3, 5, 3, 9, 17, 103, 133, 309, 683, 71, 3329, 7229, 8763, 4165, 9649, 8529}},
+{8727, 17, 25532, {1, 3, 5, 13, 29, 55, 29, 205, 433, 1007, 1173, 731, 5653, 89, 18447, 37911, 65603}},
+{8728, 17, 25538, {1, 3, 5, 1, 15, 1, 7, 195, 397, 877, 1433, 3487, 1581, 1539, 3361, 7453, 46451}},
+{8729, 17, 25549, {1, 1, 5, 13, 23, 1, 47, 245, 19, 859, 681, 2971, 2531, 11393, 32765, 4595, 45213}},
+{8730, 17, 25552, {1, 3, 1, 3, 1, 11, 85, 185, 467, 413, 25, 3677, 881, 1791, 14655, 44811, 50819}},
+{8731, 17, 25564, {1, 3, 5, 9, 9, 21, 65, 99, 441, 215, 1453, 2873, 5883, 485, 20883, 1303, 11837}},
+{8732, 17, 25567, {1, 3, 3, 5, 9, 37, 87, 211, 247, 535, 1163, 1785, 4219, 12559, 17419, 48201, 21725}},
+{8733, 17, 25574, {1, 1, 1, 11, 29, 11, 9, 215, 375, 601, 627, 2641, 6961, 6175, 10995, 49299, 102891}},
+{8734, 17, 25577, {1, 3, 1, 3, 7, 7, 23, 139, 89, 1005, 1815, 947, 1507, 10349, 35, 43595, 104697}},
+{8735, 17, 25583, {1, 1, 5, 13, 29, 47, 77, 255, 341, 333, 1211, 3473, 1303, 11237, 28371, 43283, 77617}},
+{8736, 17, 25588, {1, 3, 3, 13, 27, 17, 73, 95, 227, 241, 1369, 833, 6683, 2193, 309, 64249, 6731}},
+{8737, 17, 25603, {1, 3, 3, 3, 15, 29, 45, 209, 401, 725, 1123, 1659, 6099, 15941, 5797, 30563, 119385}},
+{8738, 17, 25610, {1, 1, 1, 1, 7, 55, 95, 151, 351, 373, 1131, 2357, 7535, 3899, 19047, 17879, 34623}},
+{8739, 17, 25615, {1, 3, 1, 5, 31, 5, 33, 97, 477, 399, 1255, 1073, 1513, 11651, 2951, 31351, 102635}},
+{8740, 17, 25624, {1, 1, 3, 13, 17, 63, 51, 209, 57, 87, 977, 3663, 6717, 15441, 10709, 607, 48297}},
+{8741, 17, 25636, {1, 1, 5, 1, 9, 29, 1, 105, 343, 19, 977, 3401, 3873, 4259, 23057, 13071, 105771}},
+{8742, 17, 25639, {1, 1, 1, 5, 1, 33, 59, 17, 115, 225, 853, 3295, 965, 12547, 26971, 50097, 54999}},
+{8743, 17, 25643, {1, 3, 3, 13, 1, 51, 29, 19, 245, 781, 493, 1121, 2937, 4177, 3267, 47463, 101195}},
+{8744, 17, 25645, {1, 3, 7, 5, 3, 51, 25, 131, 451, 997, 1809, 1583, 355, 15383, 28159, 39141, 109379}},
+{8745, 17, 25648, {1, 1, 5, 7, 3, 19, 75, 103, 401, 115, 1627, 423, 2485, 7281, 6177, 54677, 31499}},
+{8746, 17, 25671, {1, 1, 1, 11, 23, 7, 57, 121, 5, 921, 1191, 1779, 1979, 3427, 25617, 19423, 73835}},
+{8747, 17, 25678, {1, 3, 3, 11, 17, 51, 15, 163, 265, 665, 1399, 1977, 3097, 7109, 14741, 24291, 79239}},
+{8748, 17, 25689, {1, 1, 7, 3, 25, 61, 69, 77, 341, 23, 713, 2879, 8075, 14855, 9691, 58241, 113277}},
+{8749, 17, 25708, {1, 3, 7, 9, 27, 43, 95, 11, 239, 445, 951, 3869, 1049, 6493, 9569, 9285, 29183}},
+{8750, 17, 25716, {1, 1, 3, 1, 1, 23, 27, 101, 337, 171, 1977, 3181, 2693, 8591, 32309, 24909, 106535}},
+{8751, 17, 25725, {1, 1, 1, 7, 23, 59, 79, 115, 49, 351, 871, 1209, 1045, 5985, 28427, 23047, 113571}},
+{8752, 17, 25730, {1, 1, 7, 13, 27, 3, 35, 7, 319, 503, 977, 3747, 4859, 16315, 30375, 25999, 24341}},
+{8753, 17, 25739, {1, 3, 3, 7, 23, 43, 67, 21, 399, 349, 1541, 2991, 5781, 14501, 5609, 65093, 12789}},
+{8754, 17, 25747, {1, 3, 1, 11, 5, 21, 17, 157, 311, 663, 469, 4033, 1557, 7569, 31163, 14079, 127771}},
+{8755, 17, 25753, {1, 1, 7, 15, 15, 31, 15, 183, 365, 35, 1433, 2793, 6685, 10565, 30409, 46815, 14173}},
+{8756, 17, 25790, {1, 1, 7, 7, 7, 45, 61, 163, 99, 353, 1535, 3185, 4023, 7999, 26173, 12675, 98073}},
+{8757, 17, 25797, {1, 1, 5, 13, 1, 11, 107, 41, 171, 773, 1513, 883, 2117, 14449, 32323, 58271, 97173}},
+{8758, 17, 25804, {1, 1, 3, 13, 27, 15, 123, 247, 281, 851, 233, 1173, 6863, 14805, 12401, 30729, 104127}},
+{8759, 17, 25809, {1, 1, 7, 11, 25, 9, 97, 215, 217, 51, 1865, 3897, 725, 4779, 21661, 11853, 72225}},
+{8760, 17, 25816, {1, 1, 5, 3, 5, 31, 125, 81, 367, 705, 325, 519, 3879, 5607, 3247, 7149, 33177}},
+{8761, 17, 25825, {1, 3, 3, 7, 17, 17, 19, 113, 331, 277, 317, 1893, 1287, 8965, 27523, 61355, 45331}},
+{8762, 17, 25831, {1, 3, 7, 9, 27, 15, 87, 21, 343, 479, 11, 2945, 1235, 1591, 28195, 40559, 42773}},
+{8763, 17, 25845, {1, 3, 3, 13, 1, 45, 115, 41, 263, 569, 71, 4051, 739, 1031, 19213, 23961, 110767}},
+{8764, 17, 25846, {1, 3, 7, 1, 9, 41, 21, 131, 3, 617, 191, 4051, 2445, 13451, 11889, 25075, 82631}},
+{8765, 17, 25867, {1, 3, 3, 15, 7, 55, 65, 67, 443, 1023, 1445, 1467, 3907, 11449, 2247, 65085, 102161}},
+{8766, 17, 25870, {1, 3, 5, 15, 19, 27, 97, 181, 51, 591, 99, 1443, 4927, 9809, 29693, 44293, 29369}},
+{8767, 17, 25897, {1, 1, 7, 7, 17, 59, 69, 163, 37, 171, 107, 2581, 3567, 9455, 19707, 6329, 27755}},
+{8768, 17, 25908, {1, 1, 1, 11, 15, 17, 83, 223, 183, 861, 1047, 3739, 3509, 5571, 28259, 42781, 130657}},
+{8769, 17, 25937, {1, 3, 3, 7, 15, 11, 33, 115, 297, 841, 1629, 1559, 2261, 11763, 22255, 63819, 55831}},
+{8770, 17, 25940, {1, 3, 3, 5, 19, 49, 17, 251, 507, 251, 805, 1041, 3947, 2219, 19977, 65449, 25031}},
+{8771, 17, 25944, {1, 1, 1, 11, 3, 7, 81, 17, 219, 729, 949, 3257, 6495, 4701, 2181, 7009, 106465}},
+{8772, 17, 25949, {1, 3, 7, 5, 27, 35, 15, 83, 43, 1013, 1427, 1943, 7555, 6613, 26879, 42685, 22071}},
+{8773, 17, 25954, {1, 1, 3, 13, 23, 55, 15, 87, 15, 579, 717, 777, 149, 11431, 26197, 17711, 7337}},
+{8774, 17, 25960, {1, 1, 5, 1, 31, 45, 113, 253, 211, 915, 1855, 4043, 2159, 1803, 5061, 40473, 3657}},
+{8775, 17, 25963, {1, 1, 3, 7, 25, 15, 37, 73, 467, 969, 1123, 4053, 4837, 10091, 25461, 40803, 91157}},
+{8776, 17, 25966, {1, 1, 5, 1, 7, 31, 77, 207, 21, 623, 577, 1195, 5839, 13013, 11189, 61691, 33327}},
+{8777, 17, 25978, {1, 3, 7, 7, 13, 3, 9, 55, 47, 779, 599, 3747, 1533, 14705, 23185, 4011, 36003}},
+{8778, 17, 25996, {1, 1, 5, 5, 31, 17, 99, 253, 103, 957, 241, 1893, 7435, 14907, 9089, 23205, 70639}},
+{8779, 17, 26007, {1, 3, 7, 15, 7, 55, 53, 101, 227, 541, 2017, 275, 577, 15621, 1799, 50373, 43197}},
+{8780, 17, 26011, {1, 3, 1, 15, 29, 23, 69, 193, 429, 359, 1045, 4091, 6551, 1673, 29113, 43247, 80993}},
+{8781, 17, 26027, {1, 3, 7, 11, 5, 37, 13, 27, 277, 65, 565, 2631, 6919, 5593, 8481, 14703, 9719}},
+{8782, 17, 26032, {1, 3, 1, 15, 5, 7, 83, 51, 77, 307, 1299, 1373, 5281, 15359, 15569, 50093, 59661}},
+{8783, 17, 26038, {1, 3, 5, 11, 13, 31, 99, 123, 263, 319, 2033, 4055, 2427, 103, 2009, 27517, 112467}},
+{8784, 17, 26049, {1, 1, 7, 3, 13, 1, 51, 131, 17, 861, 459, 3925, 5511, 5255, 28553, 36437, 54591}},
+{8785, 17, 26052, {1, 3, 7, 5, 9, 57, 49, 119, 291, 727, 1611, 4035, 4517, 10979, 28445, 26905, 57517}},
+{8786, 17, 26055, {1, 1, 5, 9, 9, 55, 43, 209, 411, 137, 1619, 3965, 5253, 8217, 7569, 42043, 104163}},
+{8787, 17, 26085, {1, 3, 3, 7, 21, 3, 107, 255, 353, 735, 71, 1789, 3351, 755, 22805, 53537, 126859}},
+{8788, 17, 26089, {1, 1, 7, 5, 15, 55, 13, 167, 165, 289, 1231, 2547, 8135, 5475, 2361, 49019, 110579}},
+{8789, 17, 26090, {1, 3, 1, 11, 17, 21, 59, 37, 177, 517, 499, 4035, 749, 14297, 22415, 54975, 29769}},
+{8790, 17, 26098, {1, 3, 7, 3, 3, 59, 55, 17, 483, 625, 875, 1465, 7583, 2969, 2741, 36965, 80367}},
+{8791, 17, 26104, {1, 1, 3, 13, 31, 5, 11, 149, 7, 297, 1485, 735, 4095, 10089, 5757, 64997, 56629}},
+{8792, 17, 26110, {1, 3, 1, 13, 19, 43, 77, 209, 309, 739, 1765, 3297, 8167, 6523, 27987, 25235, 80555}},
+{8793, 17, 26113, {1, 1, 3, 9, 31, 57, 125, 75, 3, 633, 85, 3339, 1691, 9721, 17465, 36801, 106147}},
+{8794, 17, 26126, {1, 3, 5, 15, 27, 7, 111, 7, 475, 523, 1825, 1367, 1549, 15533, 13827, 14471, 100271}},
+{8795, 17, 26133, {1, 1, 5, 3, 5, 61, 1, 221, 163, 183, 1701, 3549, 349, 10057, 26169, 20725, 55305}},
+{8796, 17, 26138, {1, 1, 3, 1, 15, 41, 13, 71, 269, 909, 1253, 2553, 83, 10055, 1057, 39841, 20437}},
+{8797, 17, 26140, {1, 3, 3, 5, 29, 39, 113, 23, 137, 601, 361, 1779, 279, 15803, 8993, 2633, 114847}},
+{8798, 17, 26156, {1, 1, 3, 7, 29, 45, 35, 27, 71, 253, 231, 3449, 1955, 9109, 9043, 50593, 15023}},
+{8799, 17, 26159, {1, 3, 1, 11, 17, 45, 85, 255, 341, 957, 769, 3009, 3997, 6435, 1161, 34219, 97077}},
+{8800, 17, 26176, {1, 1, 5, 1, 1, 19, 9, 51, 477, 129, 1411, 3223, 5069, 3237, 15947, 27215, 70401}},
+{8801, 17, 26186, {1, 1, 3, 1, 1, 1, 73, 31, 301, 227, 119, 607, 3379, 3907, 1263, 2651, 43769}},
+{8802, 17, 26203, {1, 1, 1, 15, 21, 59, 109, 155, 473, 361, 1871, 3085, 513, 12607, 12747, 41067, 44977}},
+{8803, 17, 26210, {1, 1, 7, 3, 27, 21, 89, 71, 437, 671, 1469, 2191, 4225, 6343, 1131, 29141, 25221}},
+{8804, 17, 26222, {1, 1, 7, 9, 7, 45, 95, 197, 391, 11, 1913, 3107, 5247, 959, 30395, 32809, 20893}},
+{8805, 17, 26224, {1, 3, 7, 15, 13, 49, 77, 245, 463, 769, 1807, 1311, 2715, 14819, 27595, 57521, 105221}},
+{8806, 17, 26229, {1, 1, 1, 5, 23, 45, 119, 77, 325, 405, 1631, 461, 6357, 7037, 31699, 46295, 118577}},
+{8807, 17, 26233, {1, 3, 5, 1, 21, 3, 31, 13, 7, 571, 633, 425, 6547, 3423, 19355, 49481, 76289}},
+{8808, 17, 26236, {1, 1, 3, 9, 7, 51, 113, 173, 169, 97, 1821, 979, 2553, 11505, 20047, 39277, 122905}},
+{8809, 17, 26239, {1, 1, 5, 13, 17, 9, 111, 205, 261, 671, 657, 507, 3903, 10767, 4387, 3045, 102617}},
+{8810, 17, 26267, {1, 1, 3, 3, 5, 11, 19, 61, 401, 605, 455, 2457, 4471, 7255, 18435, 49673, 97289}},
+{8811, 17, 26291, {1, 3, 1, 1, 31, 25, 77, 35, 65, 127, 929, 2325, 2315, 13819, 5509, 12515, 36991}},
+{8812, 17, 26293, {1, 1, 7, 5, 21, 49, 33, 119, 181, 645, 1425, 2411, 245, 13755, 18775, 50061, 47119}},
+{8813, 17, 26298, {1, 3, 7, 5, 27, 43, 81, 191, 233, 435, 829, 3881, 713, 11153, 4637, 37721, 115567}},
+{8814, 17, 26303, {1, 3, 7, 1, 27, 59, 51, 165, 59, 931, 1921, 3059, 6843, 813, 22063, 29445, 114765}},
+{8815, 17, 26308, {1, 1, 5, 11, 31, 53, 89, 69, 29, 893, 1241, 7, 1707, 16167, 8371, 14021, 103281}},
+{8816, 17, 26312, {1, 3, 1, 1, 23, 21, 3, 35, 73, 769, 1417, 4051, 3223, 813, 1141, 18823, 31951}},
+{8817, 17, 26315, {1, 3, 7, 11, 9, 17, 89, 85, 407, 137, 1865, 2881, 1495, 3757, 3711, 36651, 1797}},
+{8818, 17, 26342, {1, 3, 5, 1, 25, 29, 29, 217, 15, 173, 479, 2363, 2341, 6193, 16403, 64097, 1173}},
+{8819, 17, 26354, {1, 3, 3, 3, 11, 29, 113, 167, 333, 573, 1467, 2223, 5693, 1063, 20299, 40993, 69055}},
+{8820, 17, 26363, {1, 1, 3, 7, 3, 51, 45, 139, 79, 393, 1251, 1087, 1423, 1827, 23445, 41635, 78511}},
+{8821, 17, 26365, {1, 3, 3, 13, 29, 45, 85, 229, 33, 373, 113, 1205, 997, 11777, 7663, 18513, 5797}},
+{8822, 17, 26383, {1, 1, 5, 5, 15, 5, 127, 85, 49, 345, 901, 3215, 2347, 2329, 19597, 39555, 25031}},
+{8823, 17, 26391, {1, 1, 7, 11, 9, 25, 71, 183, 341, 1011, 439, 3649, 2859, 10183, 7635, 45297, 38581}},
+{8824, 17, 26398, {1, 1, 1, 11, 23, 13, 1, 69, 461, 77, 1641, 2851, 1889, 2413, 1131, 39009, 33773}},
+{8825, 17, 26416, {1, 3, 7, 7, 25, 19, 67, 233, 141, 207, 1501, 453, 4773, 7411, 22839, 25365, 53189}},
+{8826, 17, 26421, {1, 1, 7, 3, 3, 17, 13, 167, 73, 1005, 887, 2595, 4351, 3249, 5653, 36025, 33733}},
+{8827, 17, 26425, {1, 1, 7, 15, 11, 1, 105, 215, 329, 601, 1477, 723, 4597, 3525, 26235, 63957, 26677}},
+{8828, 17, 26434, {1, 1, 1, 11, 27, 15, 111, 133, 327, 567, 845, 2135, 7905, 7297, 29255, 14947, 104885}},
+{8829, 17, 26439, {1, 1, 7, 9, 21, 11, 67, 179, 459, 423, 295, 3445, 1681, 12907, 29281, 7445, 35539}},
+{8830, 17, 26453, {1, 1, 3, 11, 23, 61, 111, 123, 81, 439, 299, 3557, 2821, 705, 15393, 37175, 11533}},
+{8831, 17, 26454, {1, 1, 3, 1, 13, 15, 113, 227, 285, 313, 687, 2085, 6363, 8003, 32661, 36461, 68759}},
+{8832, 17, 26470, {1, 3, 3, 1, 27, 7, 101, 177, 363, 461, 1519, 2339, 473, 7469, 4335, 30951, 130987}},
+{8833, 17, 26491, {1, 1, 1, 3, 31, 39, 59, 159, 207, 93, 581, 1973, 945, 11343, 15901, 22001, 3515}},
+{8834, 17, 26493, {1, 3, 7, 5, 11, 53, 125, 57, 389, 985, 1055, 3803, 3879, 5537, 28221, 36805, 16025}},
+{8835, 17, 26500, {1, 1, 1, 9, 1, 63, 81, 57, 59, 813, 865, 3491, 3771, 6121, 6847, 14765, 68567}},
+{8836, 17, 26509, {1, 1, 7, 7, 13, 17, 23, 211, 435, 167, 933, 357, 3567, 3019, 28439, 17701, 119937}},
+{8837, 17, 26518, {1, 1, 1, 9, 7, 53, 103, 155, 211, 719, 413, 3673, 2795, 15687, 1737, 50855, 129133}},
+{8838, 17, 26531, {1, 1, 3, 13, 11, 23, 53, 121, 497, 383, 1655, 937, 5563, 2549, 23183, 46149, 78875}},
+{8839, 17, 26533, {1, 3, 5, 11, 25, 1, 45, 139, 437, 729, 2009, 3245, 4091, 551, 25993, 31655, 33641}},
+{8840, 17, 26540, {1, 3, 1, 13, 7, 23, 87, 111, 471, 501, 1767, 1051, 7037, 3199, 19609, 43227, 53667}},
+{8841, 17, 26552, {1, 3, 7, 1, 25, 1, 49, 189, 55, 375, 601, 2065, 2991, 7697, 25739, 14951, 43705}},
+{8842, 17, 26566, {1, 1, 7, 5, 29, 21, 51, 111, 81, 809, 1963, 2143, 5529, 15701, 4719, 11857, 88207}},
+{8843, 17, 26569, {1, 1, 5, 11, 27, 27, 7, 145, 281, 939, 537, 1255, 1475, 11383, 15081, 9105, 102775}},
+{8844, 17, 26583, {1, 1, 5, 7, 9, 45, 67, 23, 65, 139, 1871, 3975, 6357, 6515, 25423, 23915, 76289}},
+{8845, 17, 26590, {1, 1, 5, 11, 31, 31, 89, 65, 451, 341, 819, 2439, 6753, 15113, 9085, 32687, 5055}},
+{8846, 17, 26596, {1, 1, 5, 1, 15, 29, 123, 83, 495, 185, 303, 315, 6015, 5257, 2467, 4903, 78269}},
+{8847, 17, 26624, {1, 1, 3, 5, 31, 51, 49, 199, 501, 407, 733, 1181, 8023, 7321, 14765, 17535, 19893}},
+{8848, 17, 26636, {1, 1, 5, 5, 19, 15, 103, 183, 13, 969, 1537, 3053, 3173, 12983, 21761, 33733, 67799}},
+{8849, 17, 26667, {1, 3, 1, 1, 27, 55, 37, 149, 379, 11, 1655, 2317, 3135, 6459, 25941, 12679, 60245}},
+{8850, 17, 26669, {1, 1, 3, 9, 9, 13, 33, 243, 337, 741, 1685, 1147, 5465, 4865, 559, 23993, 47273}},
+{8851, 17, 26672, {1, 3, 5, 13, 21, 11, 39, 169, 135, 209, 1909, 3655, 3117, 1075, 8165, 54633, 28189}},
+{8852, 17, 26675, {1, 3, 1, 15, 9, 23, 11, 123, 63, 133, 947, 907, 3853, 10291, 22905, 4561, 92497}},
+{8853, 17, 26687, {1, 1, 3, 13, 17, 9, 5, 209, 429, 3, 2035, 1497, 6765, 5991, 24991, 8155, 103417}},
+{8854, 17, 26689, {1, 1, 5, 13, 27, 47, 79, 11, 41, 791, 1939, 3099, 4069, 4665, 20801, 18659, 72163}},
+{8855, 17, 26696, {1, 3, 1, 13, 25, 37, 79, 131, 233, 647, 291, 1419, 5157, 4261, 27715, 611, 83157}},
+{8856, 17, 26702, {1, 1, 5, 1, 17, 61, 45, 163, 137, 937, 91, 1695, 1553, 543, 28615, 6855, 75201}},
+{8857, 17, 26714, {1, 1, 3, 13, 7, 63, 109, 13, 351, 159, 1111, 2791, 4701, 5805, 9707, 18361, 98091}},
+{8858, 17, 26716, {1, 1, 3, 11, 11, 21, 55, 247, 111, 801, 93, 3091, 1043, 9761, 23679, 5555, 195}},
+{8859, 17, 26729, {1, 1, 1, 1, 13, 43, 123, 113, 265, 561, 659, 3755, 6605, 10949, 30511, 29495, 9075}},
+{8860, 17, 26732, {1, 3, 1, 7, 23, 63, 19, 73, 233, 1017, 851, 1971, 3999, 7407, 25309, 63991, 92867}},
+{8861, 17, 26737, {1, 3, 3, 3, 19, 63, 127, 107, 465, 463, 1507, 1323, 4729, 14717, 9129, 24859, 117565}},
+{8862, 17, 26747, {1, 1, 7, 1, 19, 11, 13, 85, 339, 939, 895, 887, 765, 15501, 8783, 65087, 77899}},
+{8863, 17, 26773, {1, 3, 7, 3, 7, 15, 43, 153, 365, 223, 1947, 2295, 787, 5549, 20089, 29203, 4807}},
+{8864, 17, 26780, {1, 3, 7, 3, 31, 27, 51, 217, 483, 623, 633, 2123, 1211, 9173, 17949, 54251, 89161}},
+{8865, 17, 26801, {1, 3, 3, 11, 3, 11, 111, 73, 283, 23, 1925, 253, 5141, 12545, 24913, 16847, 13067}},
+{8866, 17, 26811, {1, 3, 5, 5, 31, 39, 35, 235, 135, 85, 191, 999, 6633, 12527, 21401, 61339, 81239}},
+{8867, 17, 26813, {1, 1, 3, 15, 9, 13, 39, 125, 137, 639, 555, 813, 2821, 1199, 32075, 15079, 104609}},
+{8868, 17, 26831, {1, 3, 7, 7, 15, 43, 99, 51, 245, 25, 147, 89, 6841, 5523, 28493, 13967, 113109}},
+{8869, 17, 26836, {1, 1, 3, 13, 7, 5, 27, 121, 269, 231, 1011, 1365, 5055, 11619, 27393, 48033, 65725}},
+{8870, 17, 26839, {1, 1, 7, 5, 9, 23, 41, 71, 327, 339, 1681, 3303, 4143, 421, 15213, 48405, 98067}},
+{8871, 17, 26849, {1, 3, 7, 15, 15, 33, 73, 33, 351, 131, 1051, 3909, 7535, 7659, 9443, 35015, 329}},
+{8872, 17, 26862, {1, 1, 3, 9, 19, 55, 97, 223, 265, 877, 235, 867, 4961, 3137, 19885, 10955, 7655}},
+{8873, 17, 26869, {1, 3, 5, 13, 1, 11, 75, 215, 271, 793, 1691, 1437, 1317, 10977, 1311, 64865, 92361}},
+{8874, 17, 26873, {1, 1, 1, 5, 23, 23, 35, 53, 187, 345, 115, 929, 3919, 4523, 31709, 16771, 33399}},
+{8875, 17, 26874, {1, 3, 5, 11, 17, 7, 75, 57, 351, 359, 1737, 2665, 4259, 13905, 6999, 45359, 117891}},
+{8876, 17, 26888, {1, 1, 5, 3, 23, 29, 49, 209, 417, 843, 531, 1649, 7829, 6271, 3759, 39727, 47415}},
+{8877, 17, 26891, {1, 1, 7, 1, 21, 45, 101, 105, 385, 797, 985, 1447, 3757, 3287, 583, 29283, 96821}},
+{8878, 17, 26896, {1, 1, 7, 9, 1, 29, 15, 207, 289, 465, 815, 2289, 449, 9403, 19197, 13797, 102651}},
+{8879, 17, 26899, {1, 3, 7, 15, 5, 45, 81, 187, 21, 433, 679, 2759, 3375, 6935, 22595, 50149, 13557}},
+{8880, 17, 26912, {1, 3, 3, 5, 11, 55, 69, 219, 95, 21, 645, 1955, 7527, 6037, 29427, 36297, 62013}},
+{8881, 17, 26921, {1, 1, 7, 15, 13, 35, 25, 67, 383, 13, 539, 2399, 4611, 8065, 3815, 27771, 50411}},
+{8882, 17, 26935, {1, 3, 1, 3, 27, 47, 65, 33, 393, 895, 1663, 1289, 1057, 11887, 1259, 53611, 36811}},
+{8883, 17, 26941, {1, 3, 5, 3, 5, 1, 27, 65, 379, 15, 1643, 1461, 3009, 8177, 15589, 5889, 1103}},
+{8884, 17, 26949, {1, 1, 5, 15, 27, 53, 43, 173, 377, 665, 581, 1061, 1363, 15015, 26709, 29507, 28075}},
+{8885, 17, 26954, {1, 1, 7, 3, 9, 11, 45, 71, 23, 995, 1277, 855, 1001, 12927, 19753, 46639, 16949}},
+{8886, 17, 26967, {1, 1, 7, 5, 15, 33, 27, 27, 437, 415, 1785, 2091, 279, 8041, 2209, 15821, 122363}},
+{8887, 17, 26977, {1, 1, 7, 1, 21, 1, 47, 215, 463, 959, 849, 1703, 5175, 10043, 16991, 11023, 52201}},
+{8888, 17, 27011, {1, 1, 1, 11, 21, 7, 121, 31, 95, 631, 1717, 3017, 2083, 2047, 12051, 63117, 25949}},
+{8889, 17, 27018, {1, 1, 5, 5, 9, 5, 105, 121, 205, 643, 1721, 2601, 2991, 2381, 4873, 12049, 20043}},
+{8890, 17, 27026, {1, 3, 5, 11, 7, 11, 97, 187, 253, 571, 101, 3077, 1479, 9513, 15451, 37105, 34445}},
+{8891, 17, 27028, {1, 1, 7, 11, 19, 19, 39, 115, 221, 13, 217, 369, 6855, 14529, 143, 13461, 62927}},
+{8892, 17, 27032, {1, 3, 3, 7, 29, 27, 9, 171, 419, 571, 837, 3829, 1871, 12691, 30693, 4195, 38905}},
+{8893, 17, 27044, {1, 1, 1, 11, 5, 55, 17, 41, 241, 419, 337, 897, 4663, 14469, 18701, 18009, 44605}},
+{8894, 17, 27053, {1, 1, 7, 7, 1, 33, 63, 197, 257, 655, 1287, 2571, 57, 13275, 29669, 8501, 61389}},
+{8895, 17, 27062, {1, 3, 5, 3, 29, 39, 101, 215, 101, 271, 1373, 2171, 841, 9865, 28951, 20369, 42413}},
+{8896, 17, 27065, {1, 3, 5, 1, 31, 23, 119, 137, 263, 633, 1239, 281, 4965, 14913, 30229, 14147, 37183}},
+{8897, 17, 27068, {1, 3, 1, 3, 11, 55, 33, 45, 69, 913, 269, 1021, 4005, 15191, 11187, 45917, 76905}},
+{8898, 17, 27080, {1, 1, 1, 13, 27, 11, 75, 139, 243, 221, 1289, 2195, 7041, 10053, 5731, 35245, 41317}},
+{8899, 17, 27083, {1, 1, 7, 9, 25, 11, 81, 243, 233, 137, 831, 2825, 6007, 7305, 31733, 64343, 7047}},
+{8900, 17, 27093, {1, 3, 5, 9, 17, 61, 25, 245, 285, 969, 1397, 1331, 5393, 3653, 15533, 9121, 111115}},
+{8901, 17, 27098, {1, 1, 5, 9, 1, 9, 61, 205, 285, 849, 1071, 1013, 2655, 10121, 15165, 25189, 56207}},
+{8902, 17, 27107, {1, 3, 5, 7, 19, 45, 121, 19, 237, 711, 1523, 3251, 693, 13567, 31993, 11239, 64127}},
+{8903, 17, 27110, {1, 1, 1, 11, 23, 25, 33, 211, 321, 1021, 1855, 291, 2911, 11841, 21929, 64147, 63201}},
+{8904, 17, 27114, {1, 1, 7, 3, 27, 21, 119, 219, 431, 819, 83, 2487, 7533, 10697, 3129, 53301, 104999}},
+{8905, 17, 27121, {1, 3, 5, 15, 9, 25, 89, 65, 293, 411, 989, 3103, 5563, 15703, 8757, 32595, 43409}},
+{8906, 17, 27127, {1, 3, 3, 1, 31, 31, 45, 173, 231, 171, 1185, 1499, 1713, 9945, 11575, 37113, 103989}},
+{8907, 17, 27137, {1, 1, 5, 13, 27, 3, 93, 253, 23, 71, 1963, 2571, 6259, 15757, 9709, 42835, 42047}},
+{8908, 17, 27144, {1, 1, 7, 11, 5, 11, 123, 117, 39, 559, 111, 527, 6253, 781, 9177, 47189, 94031}},
+{8909, 17, 27155, {1, 1, 5, 15, 5, 49, 93, 185, 167, 787, 1553, 3291, 3723, 1651, 23225, 5643, 42967}},
+{8910, 17, 27171, {1, 3, 1, 13, 15, 35, 19, 193, 505, 127, 661, 1943, 1249, 5103, 8233, 64319, 76955}},
+{8911, 17, 27178, {1, 3, 7, 7, 17, 13, 97, 185, 415, 331, 283, 3341, 2903, 2927, 7729, 4095, 103083}},
+{8912, 17, 27180, {1, 1, 3, 15, 15, 25, 65, 45, 413, 521, 747, 2605, 5845, 12909, 7651, 45937, 99043}},
+{8913, 17, 27185, {1, 1, 5, 9, 9, 21, 3, 75, 335, 745, 1493, 1721, 1977, 11105, 22621, 49281, 107113}},
+{8914, 17, 27191, {1, 3, 1, 11, 25, 11, 99, 53, 239, 831, 655, 615, 7565, 14039, 29115, 26165, 127159}},
+{8915, 17, 27192, {1, 1, 7, 5, 31, 35, 75, 157, 441, 815, 119, 565, 2703, 14059, 7867, 42487, 93647}},
+{8916, 17, 27195, {1, 3, 7, 3, 3, 59, 101, 223, 257, 989, 363, 1059, 5157, 11129, 1481, 19287, 117623}},
+{8917, 17, 27212, {1, 1, 1, 1, 29, 27, 1, 129, 253, 673, 103, 1881, 7053, 1261, 32003, 23345, 102503}},
+{8918, 17, 27215, {1, 3, 1, 9, 11, 37, 3, 99, 303, 519, 1175, 3021, 2275, 9919, 25011, 45865, 71351}},
+{8919, 17, 27218, {1, 1, 7, 15, 27, 9, 107, 61, 385, 21, 861, 2119, 4643, 8379, 25455, 22425, 113387}},
+{8920, 17, 27230, {1, 1, 1, 7, 27, 15, 73, 211, 497, 527, 873, 329, 2213, 415, 13987, 56581, 27829}},
+{8921, 17, 27234, {1, 3, 5, 1, 31, 43, 107, 149, 209, 211, 2029, 2793, 2213, 12389, 27177, 51375, 51983}},
+{8922, 17, 27245, {1, 3, 3, 7, 25, 57, 67, 101, 127, 43, 1775, 801, 3343, 12203, 8667, 58387, 10735}},
+{8923, 17, 27248, {1, 1, 7, 5, 13, 47, 101, 123, 133, 593, 1409, 3525, 2545, 13009, 11873, 38463, 1075}},
+{8924, 17, 27263, {1, 3, 3, 1, 3, 19, 75, 221, 157, 67, 397, 1141, 5073, 10795, 9857, 35459, 62701}},
+{8925, 17, 27279, {1, 1, 7, 7, 23, 17, 41, 179, 83, 543, 1839, 3709, 131, 15681, 9147, 18685, 90389}},
+{8926, 17, 27288, {1, 1, 5, 7, 17, 15, 31, 217, 79, 687, 1927, 2889, 6127, 15095, 28437, 16403, 123275}},
+{8927, 17, 27294, {1, 3, 7, 15, 13, 17, 123, 75, 45, 635, 525, 3897, 6769, 13855, 16695, 18039, 37479}},
+{8928, 17, 27303, {1, 1, 5, 1, 23, 15, 69, 161, 503, 339, 1061, 839, 9, 10013, 24493, 32711, 50147}},
+{8929, 17, 27304, {1, 3, 3, 11, 5, 45, 9, 233, 131, 629, 1111, 3311, 2211, 9079, 19763, 23793, 85389}},
+{8930, 17, 27312, {1, 1, 7, 7, 7, 27, 15, 85, 291, 925, 1545, 3061, 4867, 1613, 13467, 53731, 92811}},
+{8931, 17, 27330, {1, 3, 5, 1, 21, 21, 71, 33, 141, 675, 1519, 3275, 1491, 10717, 28199, 14983, 18961}},
+{8932, 17, 27341, {1, 3, 5, 5, 31, 13, 109, 239, 369, 373, 257, 3765, 2531, 13281, 11877, 29439, 106939}},
+{8933, 17, 27342, {1, 3, 7, 15, 13, 39, 111, 203, 109, 179, 789, 3849, 433, 5745, 2343, 15795, 92603}},
+{8934, 17, 27344, {1, 3, 5, 5, 11, 57, 3, 245, 289, 249, 713, 315, 2261, 1249, 6963, 44507, 100829}},
+{8935, 17, 27353, {1, 3, 5, 11, 5, 49, 97, 245, 363, 315, 509, 17, 4485, 15393, 28491, 17945, 65663}},
+{8936, 17, 27356, {1, 3, 5, 1, 5, 13, 15, 17, 141, 119, 1393, 581, 2439, 2015, 11527, 8537, 103005}},
+{8937, 17, 27366, {1, 3, 5, 1, 25, 9, 117, 25, 99, 777, 985, 1159, 99, 3013, 21429, 19027, 61833}},
+{8938, 17, 27369, {1, 1, 1, 5, 1, 47, 37, 83, 159, 29, 281, 3789, 2525, 15999, 8965, 11145, 14453}},
+{8939, 17, 27377, {1, 1, 3, 1, 11, 63, 77, 207, 267, 473, 241, 629, 6969, 9093, 839, 3875, 18873}},
+{8940, 17, 27387, {1, 3, 5, 7, 31, 57, 103, 65, 349, 321, 717, 2403, 105, 643, 27999, 2509, 123061}},
+{8941, 17, 27409, {1, 1, 5, 7, 3, 31, 7, 113, 17, 995, 1211, 1749, 6757, 3391, 8011, 47715, 24301}},
+{8942, 17, 27437, {1, 3, 7, 11, 7, 55, 29, 155, 373, 81, 1255, 2205, 3233, 9537, 22129, 24505, 79021}},
+{8943, 17, 27443, {1, 1, 7, 5, 3, 49, 5, 51, 89, 107, 585, 3933, 745, 11685, 20663, 12521, 24357}},
+{8944, 17, 27446, {1, 1, 7, 1, 17, 17, 83, 215, 357, 581, 2025, 3411, 7287, 11925, 2253, 43513, 98655}},
+{8945, 17, 27450, {1, 3, 5, 3, 27, 27, 51, 147, 471, 509, 423, 3807, 677, 8429, 581, 47999, 35913}},
+{8946, 17, 27452, {1, 3, 3, 9, 15, 31, 1, 93, 207, 759, 1991, 473, 2273, 43, 12547, 58085, 20953}},
+{8947, 17, 27457, {1, 1, 3, 3, 1, 27, 39, 219, 381, 187, 159, 2333, 6141, 3775, 5693, 14853, 38765}},
+{8948, 17, 27472, {1, 3, 1, 5, 19, 1, 19, 237, 231, 975, 1609, 723, 241, 10105, 18817, 58373, 118889}},
+{8949, 17, 27475, {1, 1, 5, 7, 7, 43, 99, 181, 109, 529, 421, 1493, 1075, 12219, 24287, 33479, 29987}},
+{8950, 17, 27487, {1, 1, 7, 1, 17, 11, 79, 85, 157, 851, 1429, 3355, 139, 14327, 30025, 60303, 109015}},
+{8951, 17, 27488, {1, 3, 5, 9, 11, 15, 37, 79, 5, 169, 999, 815, 6255, 11763, 16299, 49891, 101917}},
+{8952, 17, 27493, {1, 3, 5, 9, 29, 45, 51, 211, 159, 771, 1631, 2871, 4877, 4941, 18127, 15669, 57515}},
+{8953, 17, 27506, {1, 1, 3, 3, 19, 29, 9, 205, 253, 399, 303, 2441, 3187, 641, 23341, 52951, 57559}},
+{8954, 17, 27508, {1, 3, 3, 15, 11, 29, 121, 227, 69, 935, 365, 217, 4617, 13193, 27663, 46903, 107843}},
+{8955, 17, 27521, {1, 1, 5, 11, 13, 31, 13, 243, 275, 685, 1613, 1915, 2775, 11225, 4729, 45549, 103875}},
+{8956, 17, 27522, {1, 1, 5, 1, 9, 61, 35, 143, 165, 441, 517, 1735, 5281, 10139, 21107, 11713, 130483}},
+{8957, 17, 27527, {1, 3, 5, 5, 13, 21, 7, 219, 97, 887, 1845, 469, 2523, 1569, 9959, 4397, 15823}},
+{8958, 17, 27536, {1, 3, 7, 11, 15, 27, 73, 223, 365, 939, 331, 145, 683, 6441, 23421, 59177, 31763}},
+{8959, 17, 27539, {1, 3, 1, 5, 9, 59, 85, 113, 343, 831, 121, 3157, 6059, 14923, 27401, 19759, 14223}},
+{8960, 17, 27541, {1, 3, 1, 7, 17, 25, 3, 39, 471, 759, 2041, 609, 4293, 7491, 8041, 50857, 25601}},
+{8961, 17, 27546, {1, 1, 5, 15, 19, 45, 21, 5, 269, 197, 527, 1839, 1719, 15105, 18671, 42167, 9617}},
+{8962, 17, 27557, {1, 3, 1, 3, 5, 35, 3, 105, 395, 113, 1945, 3945, 3951, 12207, 32135, 34121, 10237}},
+{8963, 17, 27564, {1, 1, 5, 13, 21, 43, 51, 255, 57, 399, 1937, 1573, 363, 11589, 26989, 54345, 94341}},
+{8964, 17, 27572, {1, 3, 3, 3, 5, 45, 83, 125, 179, 923, 39, 3617, 7683, 8191, 31469, 23633, 79179}},
+{8965, 17, 27576, {1, 3, 7, 9, 9, 37, 107, 65, 423, 77, 1779, 1375, 2085, 11779, 6535, 2973, 29425}},
+{8966, 17, 27584, {1, 1, 7, 3, 11, 39, 101, 137, 407, 855, 1767, 1717, 2821, 10447, 31187, 6329, 124111}},
+{8967, 17, 27608, {1, 1, 5, 11, 27, 27, 45, 103, 225, 681, 725, 1791, 2881, 2923, 14473, 12269, 58743}},
+{8968, 17, 27611, {1, 1, 3, 11, 15, 39, 113, 167, 143, 677, 1189, 1571, 5339, 6065, 30187, 19639, 42227}},
+{8969, 17, 27618, {1, 1, 1, 3, 13, 7, 113, 75, 129, 619, 1741, 1495, 4751, 11085, 22391, 199, 105463}},
+{8970, 17, 27620, {1, 1, 3, 3, 19, 47, 77, 195, 209, 453, 495, 1605, 5255, 15327, 8941, 18239, 54511}},
+{8971, 17, 27627, {1, 1, 7, 7, 21, 29, 95, 175, 3, 689, 611, 2467, 6919, 12399, 18869, 16171, 102753}},
+{8972, 17, 27630, {1, 1, 5, 1, 27, 43, 61, 133, 37, 603, 315, 1915, 813, 15769, 27447, 29589, 122281}},
+{8973, 17, 27637, {1, 1, 7, 3, 11, 1, 119, 235, 93, 481, 1811, 1643, 4853, 11313, 8991, 6153, 68985}},
+{8974, 17, 27638, {1, 1, 1, 7, 1, 13, 99, 83, 221, 775, 1345, 219, 4445, 11837, 10405, 43563, 122111}},
+{8975, 17, 27641, {1, 1, 5, 13, 21, 33, 105, 19, 343, 571, 703, 429, 2485, 15531, 9801, 24101, 88275}},
+{8976, 17, 27647, {1, 3, 5, 1, 27, 55, 73, 49, 33, 773, 1411, 1227, 6827, 1271, 28897, 24265, 32383}},
+{8977, 17, 27650, {1, 3, 7, 3, 9, 45, 59, 5, 157, 669, 261, 2077, 1425, 8221, 5849, 40857, 121029}},
+{8978, 17, 27676, {1, 3, 7, 11, 23, 5, 87, 113, 279, 611, 1195, 1775, 5813, 6737, 18051, 41341, 93331}},
+{8979, 17, 27683, {1, 1, 7, 7, 9, 55, 113, 3, 167, 295, 1579, 2833, 4003, 7583, 22833, 44427, 34781}},
+{8980, 17, 27690, {1, 1, 5, 13, 21, 33, 127, 175, 153, 961, 819, 143, 3969, 6159, 29437, 14123, 65317}},
+{8981, 17, 27695, {1, 1, 1, 15, 31, 27, 1, 17, 329, 963, 1907, 421, 535, 2323, 22749, 44375, 115531}},
+{8982, 17, 27700, {1, 1, 5, 15, 15, 23, 57, 171, 253, 401, 1577, 3855, 197, 7979, 17577, 25275, 88831}},
+{8983, 17, 27704, {1, 1, 7, 9, 27, 9, 7, 13, 381, 847, 533, 357, 6551, 13441, 5717, 20209, 64347}},
+{8984, 17, 27709, {1, 1, 7, 9, 1, 1, 31, 245, 315, 901, 1857, 497, 4285, 13227, 3937, 45025, 59627}},
+{8985, 17, 27715, {1, 1, 7, 3, 5, 23, 119, 147, 479, 71, 113, 3379, 863, 8285, 31259, 15863, 47267}},
+{8986, 17, 27727, {1, 3, 5, 1, 5, 7, 77, 163, 421, 353, 1757, 1335, 4975, 3011, 11703, 56075, 12045}},
+{8987, 17, 27745, {1, 1, 5, 3, 31, 25, 81, 59, 211, 463, 1693, 609, 3307, 3641, 19643, 29361, 8399}},
+{8988, 17, 27763, {1, 1, 7, 13, 19, 47, 43, 43, 275, 735, 535, 3689, 3987, 10695, 17243, 60565, 72299}},
+{8989, 17, 27769, {1, 3, 3, 5, 25, 35, 75, 63, 305, 127, 189, 1785, 731, 12089, 27811, 43259, 28191}},
+{8990, 17, 27770, {1, 3, 7, 11, 17, 17, 59, 107, 139, 355, 1055, 3181, 4743, 14785, 26323, 441, 35613}},
+{8991, 17, 27796, {1, 3, 1, 1, 17, 17, 39, 203, 373, 601, 449, 1837, 835, 7061, 14655, 61765, 80735}},
+{8992, 17, 27810, {1, 3, 5, 7, 27, 17, 25, 41, 125, 895, 1843, 3167, 1527, 4707, 6477, 33575, 97247}},
+{8993, 17, 27812, {1, 3, 3, 3, 13, 39, 25, 15, 279, 347, 1121, 3603, 3019, 9577, 16863, 61483, 15995}},
+{8994, 17, 27834, {1, 3, 5, 11, 15, 33, 15, 81, 185, 289, 909, 1237, 3623, 3983, 24211, 62719, 79685}},
+{8995, 17, 27847, {1, 1, 1, 7, 29, 1, 53, 17, 137, 269, 1209, 3937, 4167, 14057, 8061, 38863, 101477}},
+{8996, 17, 27848, {1, 1, 1, 9, 5, 45, 95, 127, 507, 159, 1763, 1527, 5689, 11007, 549, 22837, 99207}},
+{8997, 17, 27862, {1, 3, 3, 1, 15, 57, 127, 39, 73, 397, 67, 3159, 119, 8929, 29425, 57687, 68063}},
+{8998, 17, 27868, {1, 3, 1, 3, 27, 7, 111, 209, 291, 17, 1381, 1597, 5389, 4577, 20463, 28325, 23743}},
+{8999, 17, 27881, {1, 3, 3, 7, 23, 41, 83, 81, 213, 537, 1037, 2371, 1485, 8391, 12471, 58541, 27559}},
+{9000, 17, 27884, {1, 3, 1, 15, 21, 43, 87, 75, 451, 851, 1917, 2739, 2167, 12531, 29931, 8017, 15163}},
+{9001, 17, 27890, {1, 1, 3, 9, 27, 19, 41, 145, 401, 759, 527, 3085, 187, 10615, 4995, 22421, 69867}},
+{9002, 17, 27895, {1, 3, 3, 13, 29, 51, 65, 47, 157, 609, 1061, 1913, 6195, 12503, 10375, 55819, 122091}},
+{9003, 17, 27904, {1, 1, 3, 7, 1, 19, 3, 149, 453, 279, 569, 3429, 331, 711, 26773, 21163, 129339}},
+{9004, 17, 27914, {1, 1, 5, 3, 7, 47, 39, 181, 115, 771, 2037, 411, 2697, 7501, 6393, 19461, 74967}},
+{9005, 17, 27919, {1, 3, 3, 5, 5, 17, 89, 161, 409, 49, 1447, 3977, 4777, 15553, 3521, 32553, 126385}},
+{9006, 17, 27921, {1, 3, 1, 3, 25, 59, 73, 105, 505, 1009, 1147, 317, 3457, 13743, 8337, 38077, 7709}},
+{9007, 17, 27931, {1, 3, 3, 15, 23, 37, 25, 123, 413, 911, 637, 2345, 691, 15199, 22927, 52467, 126715}},
+{9008, 17, 27933, {1, 1, 5, 1, 9, 51, 93, 123, 269, 45, 1947, 179, 5091, 3743, 31491, 39771, 119175}},
+{9009, 17, 27938, {1, 3, 1, 5, 29, 23, 107, 183, 25, 115, 187, 857, 7337, 469, 8755, 17281, 45941}},
+{9010, 17, 27943, {1, 3, 1, 13, 25, 61, 85, 115, 181, 955, 1365, 837, 5941, 13209, 27009, 58865, 115149}},
+{9011, 17, 27949, {1, 1, 1, 11, 31, 63, 101, 29, 37, 185, 465, 2651, 6249, 6887, 25021, 60539, 50037}},
+{9012, 17, 28005, {1, 3, 1, 7, 7, 61, 57, 243, 143, 223, 1759, 4085, 6765, 13293, 31929, 29579, 35053}},
+{9013, 17, 28012, {1, 3, 1, 3, 29, 9, 121, 3, 285, 199, 1439, 3151, 5059, 8535, 17049, 38917, 46347}},
+{9014, 17, 28017, {1, 3, 1, 3, 17, 43, 63, 87, 427, 341, 1251, 3775, 7729, 3183, 10579, 917, 49035}},
+{9015, 17, 28024, {1, 1, 7, 3, 5, 59, 119, 227, 495, 345, 841, 2021, 2483, 15987, 24663, 9819, 33009}},
+{9016, 17, 28030, {1, 1, 5, 11, 19, 57, 23, 181, 63, 991, 1, 2927, 4785, 9645, 17435, 55627, 1069}},
+{9017, 17, 28034, {1, 1, 7, 1, 31, 11, 57, 123, 279, 815, 1407, 3509, 3963, 8503, 20345, 7777, 103701}},
+{9018, 17, 28045, {1, 1, 5, 5, 19, 51, 37, 15, 363, 939, 1863, 3485, 7073, 3035, 31279, 7289, 39811}},
+{9019, 17, 28048, {1, 1, 3, 3, 3, 41, 29, 37, 311, 535, 1993, 3937, 309, 13055, 22595, 59641, 95317}},
+{9020, 17, 28054, {1, 3, 7, 9, 19, 29, 23, 181, 503, 223, 1655, 997, 7861, 5867, 16979, 4559, 7447}},
+{9021, 17, 28063, {1, 3, 5, 3, 13, 13, 3, 137, 361, 101, 1005, 2339, 609, 11891, 15245, 9653, 63579}},
+{9022, 17, 28069, {1, 1, 1, 15, 31, 15, 117, 151, 51, 805, 1403, 3243, 4007, 11979, 3945, 61935, 43225}},
+{9023, 17, 28070, {1, 1, 7, 3, 1, 43, 93, 105, 9, 555, 731, 655, 2097, 8015, 27557, 27985, 11323}},
+{9024, 17, 28073, {1, 3, 3, 9, 23, 35, 59, 217, 437, 755, 685, 1431, 2965, 5269, 25621, 21735, 1397}},
+{9025, 17, 28084, {1, 1, 5, 1, 9, 61, 41, 53, 101, 111, 531, 3385, 4771, 9535, 15995, 29687, 99035}},
+{9026, 17, 28096, {1, 1, 7, 7, 1, 3, 25, 251, 463, 99, 677, 1889, 3697, 5579, 11429, 38301, 57917}},
+{9027, 17, 28114, {1, 1, 5, 9, 11, 15, 65, 31, 369, 825, 1229, 1595, 3891, 5235, 16973, 25307, 7805}},
+{9028, 17, 28126, {1, 3, 7, 15, 27, 37, 35, 103, 393, 781, 1713, 2009, 1973, 15461, 6801, 17557, 105139}},
+{9029, 17, 28141, {1, 3, 7, 7, 17, 51, 83, 29, 113, 173, 1733, 2137, 3041, 11361, 15999, 25779, 112493}},
+{9030, 17, 28149, {1, 3, 5, 11, 19, 3, 89, 103, 449, 375, 437, 4077, 889, 12163, 29323, 48845, 7783}},
+{9031, 17, 28165, {1, 3, 7, 1, 19, 25, 83, 35, 203, 27, 507, 25, 6629, 13941, 6187, 17533, 83349}},
+{9032, 17, 28177, {1, 3, 5, 9, 15, 59, 3, 87, 473, 733, 1263, 1733, 4275, 9283, 32535, 20807, 59487}},
+{9033, 17, 28189, {1, 3, 3, 9, 19, 11, 27, 83, 355, 949, 1339, 171, 921, 14171, 16271, 41485, 20405}},
+{9034, 17, 28190, {1, 1, 3, 11, 25, 51, 9, 241, 367, 519, 1895, 429, 7689, 9469, 32709, 46363, 75767}},
+{9035, 17, 28203, {1, 1, 7, 7, 27, 59, 85, 87, 467, 273, 1763, 391, 451, 16165, 7501, 44779, 68281}},
+{9036, 17, 28206, {1, 1, 7, 5, 1, 35, 5, 217, 31, 145, 1151, 2255, 3543, 401, 17141, 5981, 25183}},
+{9037, 17, 28208, {1, 1, 1, 13, 11, 11, 19, 93, 95, 751, 31, 1091, 2733, 10517, 2553, 5247, 42651}},
+{9038, 17, 28220, {1, 3, 7, 5, 15, 1, 67, 21, 303, 137, 355, 1989, 5211, 4985, 645, 6867, 126931}},
+{9039, 17, 28226, {1, 1, 3, 15, 21, 23, 59, 209, 121, 623, 575, 2447, 6149, 10481, 4959, 22913, 64963}},
+{9040, 17, 28231, {1, 3, 1, 1, 25, 55, 47, 95, 215, 609, 639, 1023, 1579, 5953, 3063, 13721, 17607}},
+{9041, 17, 28249, {1, 1, 1, 11, 7, 61, 127, 173, 307, 623, 453, 3827, 4847, 16085, 4407, 4043, 14881}},
+{9042, 17, 28256, {1, 1, 7, 11, 5, 15, 51, 125, 439, 795, 203, 91, 3543, 6925, 32055, 52277, 26841}},
+{9043, 17, 28259, {1, 1, 1, 13, 15, 9, 107, 183, 391, 751, 243, 1105, 8031, 7443, 137, 45695, 80163}},
+{9044, 17, 28265, {1, 3, 5, 9, 5, 61, 117, 113, 121, 291, 225, 1705, 4017, 13113, 11035, 28613, 25927}},
+{9045, 17, 28266, {1, 1, 3, 11, 27, 9, 45, 85, 309, 991, 1639, 1183, 8013, 14587, 7563, 21111, 48497}},
+{9046, 17, 28271, {1, 3, 1, 9, 21, 61, 123, 189, 265, 593, 163, 3681, 2271, 2795, 753, 48019, 129507}},
+{9047, 17, 28274, {1, 1, 1, 5, 31, 51, 127, 79, 333, 177, 1723, 1365, 2055, 3063, 10693, 61223, 60659}},
+{9048, 17, 28280, {1, 3, 7, 15, 9, 11, 11, 223, 31, 397, 319, 3283, 3765, 4729, 4711, 58323, 114063}},
+{9049, 17, 28296, {1, 1, 7, 11, 7, 63, 107, 215, 19, 491, 131, 2491, 6373, 11081, 2159, 1311, 109547}},
+{9050, 17, 28316, {1, 3, 5, 5, 21, 13, 105, 21, 193, 447, 1331, 2439, 4165, 15689, 21273, 4007, 55161}},
+{9051, 17, 28319, {1, 3, 5, 11, 19, 47, 25, 211, 335, 437, 1041, 2093, 7239, 2869, 18273, 40505, 13681}},
+{9052, 17, 28343, {1, 3, 3, 15, 7, 13, 127, 59, 439, 163, 1841, 1945, 4915, 16269, 18315, 15057, 43197}},
+{9053, 17, 28344, {1, 1, 3, 3, 15, 33, 101, 241, 131, 353, 1749, 3965, 1231, 8167, 9309, 40337, 4419}},
+{9054, 17, 28357, {1, 3, 1, 1, 1, 43, 33, 129, 137, 889, 799, 2937, 3633, 4769, 2411, 56059, 585}},
+{9055, 17, 28358, {1, 1, 3, 9, 25, 31, 45, 199, 229, 175, 1099, 1143, 1721, 11811, 22757, 59843, 117813}},
+{9056, 17, 28364, {1, 1, 7, 7, 19, 45, 43, 101, 219, 209, 1169, 599, 5523, 2463, 15161, 16675, 85111}},
+{9057, 17, 28370, {1, 1, 3, 15, 23, 27, 91, 51, 397, 705, 651, 2345, 3875, 10005, 29523, 42805, 76891}},
+{9058, 17, 28372, {1, 3, 3, 5, 29, 49, 17, 233, 149, 821, 1953, 1931, 7127, 957, 6477, 21259, 126657}},
+{9059, 17, 28379, {1, 3, 3, 3, 27, 49, 57, 145, 143, 1, 583, 3987, 651, 12285, 20139, 51063, 21449}},
+{9060, 17, 28388, {1, 1, 3, 5, 29, 61, 41, 93, 277, 111, 395, 2929, 5325, 15183, 3981, 23799, 72781}},
+{9061, 17, 28392, {1, 1, 7, 5, 25, 43, 85, 137, 401, 261, 1183, 3959, 1983, 16209, 30523, 429, 109181}},
+{9062, 17, 28395, {1, 1, 1, 5, 7, 19, 79, 237, 373, 929, 907, 1771, 6991, 211, 5269, 2135, 32051}},
+{9063, 17, 28406, {1, 1, 7, 5, 17, 15, 41, 49, 363, 15, 1483, 1017, 2439, 11713, 19983, 26275, 11945}},
+{9064, 17, 28418, {1, 1, 7, 7, 19, 5, 55, 15, 15, 573, 1075, 3225, 6815, 11893, 18417, 50833, 71903}},
+{9065, 17, 28423, {1, 1, 7, 9, 23, 37, 75, 3, 477, 291, 37, 1861, 2697, 13369, 24573, 27285, 96757}},
+{9066, 17, 28435, {1, 1, 1, 13, 5, 29, 65, 195, 365, 465, 865, 2705, 5249, 7051, 3795, 56611, 72317}},
+{9067, 17, 28444, {1, 1, 3, 9, 19, 9, 85, 239, 509, 313, 1137, 2221, 5475, 71, 11901, 1877, 68701}},
+{9068, 17, 28454, {1, 3, 3, 7, 3, 53, 55, 223, 441, 159, 933, 2573, 3441, 3295, 25005, 29021, 97145}},
+{9069, 17, 28468, {1, 3, 5, 5, 3, 11, 101, 181, 293, 319, 47, 2971, 387, 4697, 26613, 8531, 20461}},
+{9070, 17, 28477, {1, 3, 3, 13, 17, 11, 41, 233, 455, 353, 1817, 3065, 4657, 1717, 3039, 10937, 107085}},
+{9071, 17, 28478, {1, 1, 7, 1, 17, 23, 85, 5, 291, 725, 1791, 3525, 7705, 6561, 25311, 44679, 21419}},
+{9072, 17, 28480, {1, 1, 7, 1, 23, 41, 97, 117, 435, 261, 2007, 965, 6913, 12245, 25723, 8445, 30871}},
+{9073, 17, 28486, {1, 1, 1, 15, 29, 39, 101, 33, 55, 1019, 1431, 2601, 3837, 14873, 11785, 12449, 30815}},
+{9074, 17, 28489, {1, 1, 5, 3, 15, 35, 101, 7, 479, 535, 1875, 2435, 1461, 13967, 2755, 45879, 93561}},
+{9075, 17, 28500, {1, 3, 1, 5, 29, 57, 89, 209, 473, 289, 1843, 2051, 3997, 1753, 18179, 41355, 89301}},
+{9076, 17, 28507, {1, 3, 1, 11, 17, 45, 47, 57, 109, 309, 1009, 653, 5175, 15599, 21617, 35353, 55253}},
+{9077, 17, 28519, {1, 3, 5, 3, 1, 11, 57, 83, 385, 765, 1887, 785, 2115, 8689, 14783, 14841, 122221}},
+{9078, 17, 28523, {1, 3, 5, 11, 11, 5, 77, 115, 189, 371, 887, 3653, 8159, 15737, 6763, 52807, 128841}},
+{9079, 17, 28534, {1, 1, 1, 11, 11, 33, 9, 145, 439, 565, 171, 3867, 7149, 4369, 15073, 3277, 25873}},
+{9080, 17, 28547, {1, 1, 3, 1, 11, 9, 17, 255, 129, 835, 1705, 1551, 877, 4831, 12717, 2549, 62723}},
+{9081, 17, 28549, {1, 1, 7, 11, 17, 33, 21, 195, 143, 153, 1855, 1323, 1225, 16359, 16479, 8883, 76449}},
+{9082, 17, 28562, {1, 1, 1, 5, 31, 23, 61, 53, 77, 465, 1983, 4019, 4865, 14721, 18601, 48179, 100453}},
+{9083, 17, 28571, {1, 3, 1, 13, 19, 53, 83, 63, 165, 393, 469, 1465, 2669, 10155, 7029, 26185, 121223}},
+{9084, 17, 28583, {1, 1, 1, 3, 3, 3, 123, 23, 45, 359, 1063, 847, 3943, 6113, 23749, 30323, 10583}},
+{9085, 17, 28584, {1, 3, 5, 15, 1, 55, 65, 149, 139, 217, 141, 2425, 7019, 14127, 11725, 50821, 52643}},
+{9086, 17, 28595, {1, 3, 5, 15, 13, 13, 15, 93, 457, 869, 117, 585, 7159, 5957, 15073, 21861, 118119}},
+{9087, 17, 28597, {1, 3, 1, 15, 3, 31, 29, 245, 47, 895, 197, 1169, 945, 11503, 26615, 14079, 27175}},
+{9088, 17, 28604, {1, 3, 5, 5, 31, 1, 107, 109, 253, 999, 1451, 2243, 6675, 10779, 26181, 64597, 16443}},
+{9089, 17, 28607, {1, 3, 7, 15, 9, 53, 25, 41, 151, 197, 1955, 2365, 5305, 2901, 24825, 9595, 57377}},
+{9090, 17, 28609, {1, 3, 1, 3, 25, 37, 37, 193, 417, 373, 1127, 3239, 4583, 2861, 14501, 64163, 30055}},
+{9091, 17, 28612, {1, 3, 7, 9, 7, 21, 49, 231, 241, 95, 1757, 2281, 2679, 1611, 11115, 31743, 26851}},
+{9092, 17, 28630, {1, 3, 5, 5, 1, 1, 23, 173, 195, 593, 1639, 1449, 4733, 2451, 12677, 31959, 128217}},
+{9093, 17, 28640, {1, 1, 1, 7, 17, 49, 117, 253, 167, 721, 889, 3027, 7781, 13521, 15477, 17981, 95487}},
+{9094, 17, 28669, {1, 1, 1, 15, 13, 47, 125, 9, 33, 567, 1733, 1263, 307, 10285, 6325, 55827, 39823}},
+{9095, 17, 28677, {1, 1, 1, 15, 23, 3, 11, 169, 369, 667, 313, 2287, 6655, 16067, 5915, 8605, 92177}},
+{9096, 17, 28682, {1, 3, 3, 15, 13, 21, 125, 111, 171, 785, 79, 2281, 1247, 11321, 30397, 28555, 84863}},
+{9097, 17, 28690, {1, 1, 5, 13, 1, 31, 123, 97, 127, 245, 1213, 2381, 3545, 13545, 28657, 54087, 79039}},
+{9098, 17, 28695, {1, 1, 7, 9, 9, 21, 87, 111, 27, 33, 843, 199, 1465, 6555, 8019, 39521, 98883}},
+{9099, 17, 28696, {1, 3, 3, 5, 5, 55, 61, 219, 279, 207, 1811, 667, 2989, 3133, 25213, 51979, 87695}},
+{9100, 17, 28717, {1, 1, 7, 3, 17, 11, 31, 97, 277, 385, 229, 3045, 557, 13521, 32733, 36831, 43003}},
+{9101, 17, 28730, {1, 3, 5, 13, 27, 57, 31, 207, 147, 405, 1495, 2471, 4889, 14861, 4861, 28185, 62363}},
+{9102, 17, 28737, {1, 1, 5, 13, 23, 19, 5, 21, 509, 299, 1077, 1747, 6229, 2375, 17903, 58473, 72637}},
+{9103, 17, 28752, {1, 3, 7, 11, 15, 61, 63, 165, 27, 461, 1359, 3375, 3029, 9907, 17393, 11097, 43593}},
+{9104, 17, 28761, {1, 3, 5, 1, 17, 29, 15, 5, 419, 19, 1981, 3169, 2389, 9169, 31697, 26201, 6997}},
+{9105, 17, 28774, {1, 3, 3, 1, 29, 31, 89, 79, 347, 707, 505, 2087, 2163, 5465, 8677, 11421, 93217}},
+{9106, 17, 28783, {1, 3, 7, 9, 3, 23, 75, 215, 7, 971, 925, 3223, 7825, 12347, 19763, 10927, 41245}},
+{9107, 17, 28791, {1, 3, 5, 5, 3, 43, 119, 79, 373, 761, 709, 1897, 3953, 13895, 13421, 16939, 112449}},
+{9108, 17, 28801, {1, 1, 3, 15, 11, 25, 65, 101, 315, 1005, 1319, 1163, 161, 15331, 4845, 40375, 121361}},
+{9109, 17, 28802, {1, 1, 3, 7, 1, 57, 63, 131, 145, 1007, 549, 2327, 1513, 3591, 10839, 56297, 80613}},
+{9110, 17, 28814, {1, 1, 3, 5, 1, 19, 79, 81, 505, 945, 65, 319, 6105, 5491, 13257, 4651, 48247}},
+{9111, 17, 28837, {1, 3, 1, 9, 27, 41, 61, 41, 421, 707, 1279, 3699, 2403, 4075, 16947, 53435, 2917}},
+{9112, 17, 28838, {1, 1, 5, 13, 11, 29, 35, 141, 313, 769, 749, 4025, 2597, 12197, 32265, 32159, 37003}},
+{9113, 17, 28842, {1, 3, 7, 11, 25, 63, 121, 15, 273, 877, 637, 409, 5001, 4723, 27985, 55501, 43495}},
+{9114, 17, 28844, {1, 3, 1, 13, 27, 29, 127, 65, 275, 967, 1723, 4007, 6147, 13277, 8361, 12305, 95433}},
+{9115, 17, 28849, {1, 3, 3, 13, 11, 45, 7, 101, 169, 361, 517, 2897, 4283, 7587, 7495, 31549, 29113}},
+{9116, 17, 28864, {1, 3, 3, 1, 9, 27, 65, 15, 279, 127, 1039, 829, 5739, 1949, 24789, 30433, 54503}},
+{9117, 17, 28867, {1, 3, 7, 5, 13, 19, 95, 133, 25, 271, 1527, 3571, 101, 15987, 10985, 55761, 39833}},
+{9118, 17, 28881, {1, 3, 5, 9, 27, 5, 37, 219, 249, 947, 1063, 4081, 1763, 15003, 23753, 3975, 109803}},
+{9119, 17, 28882, {1, 3, 3, 5, 21, 37, 35, 145, 323, 573, 1939, 885, 4645, 4515, 16815, 28783, 76017}},
+{9120, 17, 28893, {1, 3, 7, 13, 27, 41, 39, 123, 423, 949, 1487, 2207, 8069, 15337, 20671, 20163, 70667}},
+{9121, 17, 28903, {1, 1, 3, 3, 15, 29, 69, 15, 151, 729, 35, 2067, 6715, 12759, 27611, 54133, 16561}},
+{9122, 17, 28907, {1, 3, 7, 13, 21, 13, 7, 161, 327, 339, 535, 2059, 413, 11161, 18415, 12415, 63713}},
+{9123, 17, 28909, {1, 3, 5, 5, 23, 49, 9, 181, 417, 339, 1013, 1707, 5097, 13319, 18951, 56415, 14397}},
+{9124, 17, 28921, {1, 1, 5, 7, 29, 23, 117, 159, 287, 695, 71, 2393, 2655, 6417, 24349, 20441, 77987}},
+{9125, 17, 28927, {1, 1, 5, 7, 31, 23, 81, 125, 145, 141, 1459, 4095, 713, 1817, 9263, 21025, 91983}},
+{9126, 17, 28929, {1, 1, 1, 9, 17, 23, 91, 39, 459, 299, 1951, 3229, 6229, 3267, 15883, 31719, 96573}},
+{9127, 17, 28935, {1, 1, 1, 15, 3, 51, 9, 7, 455, 653, 1447, 153, 8117, 723, 2177, 9107, 7757}},
+{9128, 17, 28941, {1, 3, 1, 15, 27, 47, 49, 245, 499, 807, 175, 1653, 1693, 3931, 27479, 30095, 62353}},
+{9129, 17, 28942, {1, 1, 5, 5, 23, 7, 15, 193, 499, 193, 201, 2771, 4153, 11533, 25883, 23337, 126685}},
+{9130, 17, 28954, {1, 1, 1, 7, 9, 43, 125, 181, 425, 557, 1401, 2593, 1933, 6803, 20021, 32687, 126465}},
+{9131, 17, 28959, {1, 3, 3, 13, 27, 19, 99, 29, 395, 765, 1137, 2963, 7397, 9695, 19259, 27965, 83157}},
+{9132, 17, 28960, {1, 3, 7, 7, 17, 29, 7, 241, 5, 281, 1489, 1599, 5567, 4579, 7739, 41413, 110571}},
+{9133, 17, 28990, {1, 3, 3, 9, 7, 5, 83, 1, 231, 1003, 631, 2557, 831, 6495, 30409, 53519, 79331}},
+{9134, 17, 28992, {1, 1, 5, 1, 7, 49, 45, 241, 201, 551, 1645, 2003, 1455, 3317, 23639, 7841, 100765}},
+{9135, 17, 29004, {1, 3, 5, 13, 25, 47, 103, 37, 81, 263, 1143, 801, 5863, 6871, 8615, 57363, 90161}},
+{9136, 17, 29010, {1, 3, 7, 11, 27, 23, 119, 211, 473, 207, 605, 637, 3369, 7287, 27827, 25003, 65925}},
+{9137, 17, 29012, {1, 3, 1, 15, 27, 31, 97, 247, 75, 893, 1099, 3609, 6807, 4393, 10253, 62759, 89971}},
+{9138, 17, 29021, {1, 1, 7, 15, 27, 19, 43, 59, 419, 263, 387, 3193, 5589, 4197, 19143, 64749, 103093}},
+{9139, 17, 29035, {1, 1, 7, 11, 21, 51, 97, 227, 251, 869, 1927, 2331, 7741, 8207, 12885, 13267, 17945}},
+{9140, 17, 29040, {1, 1, 7, 7, 5, 53, 41, 147, 75, 709, 607, 1073, 2853, 8081, 12797, 5279, 86083}},
+{9141, 17, 29059, {1, 1, 5, 5, 15, 21, 77, 189, 269, 595, 197, 3117, 5073, 14277, 26867, 49505, 75755}},
+{9142, 17, 29068, {1, 3, 5, 15, 13, 55, 1, 223, 135, 367, 735, 3139, 4851, 9773, 11699, 19081, 26011}},
+{9143, 17, 29080, {1, 3, 5, 7, 9, 3, 89, 103, 321, 727, 1809, 3527, 6881, 2399, 13593, 27867, 16219}},
+{9144, 17, 29086, {1, 3, 3, 1, 23, 5, 53, 51, 403, 753, 2037, 1261, 7575, 2725, 11341, 18533, 98767}},
+{9145, 17, 29089, {1, 1, 1, 11, 1, 13, 37, 141, 477, 689, 1789, 1913, 5753, 6069, 6965, 55209, 77329}},
+{9146, 17, 29090, {1, 3, 7, 3, 17, 59, 79, 249, 381, 163, 1773, 1645, 7295, 2359, 21889, 28429, 117073}},
+{9147, 17, 29095, {1, 3, 5, 15, 7, 45, 59, 3, 93, 259, 1257, 2967, 1175, 10171, 873, 51423, 67437}},
+{9148, 17, 29113, {1, 1, 7, 13, 17, 33, 53, 217, 159, 683, 1169, 3363, 4591, 3959, 10089, 35443, 99677}},
+{9149, 17, 29127, {1, 3, 7, 9, 3, 1, 5, 171, 17, 635, 369, 1529, 4861, 4977, 29303, 42357, 69309}},
+{9150, 17, 29131, {1, 3, 7, 9, 21, 17, 77, 127, 105, 427, 525, 1123, 2365, 7487, 6315, 64773, 122747}},
+{9151, 17, 29148, {1, 1, 1, 15, 19, 63, 65, 83, 219, 987, 169, 2589, 3809, 8807, 22473, 6479, 44617}},
+{9152, 17, 29161, {1, 3, 1, 7, 11, 51, 107, 19, 379, 191, 1013, 3145, 1501, 11871, 14111, 18269, 98247}},
+{9153, 17, 29172, {1, 1, 7, 5, 17, 63, 23, 231, 423, 855, 1955, 907, 4553, 16173, 7701, 40329, 42047}},
+{9154, 17, 29179, {1, 3, 7, 1, 7, 45, 103, 127, 185, 721, 1035, 839, 691, 6823, 23819, 50781, 92767}},
+{9155, 17, 29188, {1, 1, 1, 3, 9, 21, 57, 253, 285, 85, 1227, 365, 2347, 7491, 15183, 8619, 108819}},
+{9156, 17, 29192, {1, 1, 3, 15, 27, 13, 5, 85, 45, 1009, 1315, 1749, 2797, 3941, 19367, 50855, 60693}},
+{9157, 17, 29195, {1, 3, 5, 15, 29, 63, 115, 197, 317, 601, 711, 377, 7489, 4247, 4843, 56549, 108447}},
+{9158, 17, 29206, {1, 3, 7, 15, 11, 25, 7, 145, 371, 395, 1743, 267, 2609, 15707, 13909, 55031, 71115}},
+{9159, 17, 29210, {1, 3, 1, 1, 1, 53, 111, 245, 433, 309, 245, 15, 2091, 9051, 11095, 31821, 104535}},
+{9160, 17, 29215, {1, 3, 1, 15, 25, 31, 99, 89, 259, 595, 1095, 3681, 5105, 8671, 23663, 29717, 126429}},
+{9161, 17, 29221, {1, 3, 7, 7, 5, 31, 15, 59, 109, 527, 257, 1785, 6799, 1283, 11741, 34589, 102397}},
+{9162, 17, 29222, {1, 3, 3, 15, 9, 27, 55, 35, 291, 587, 1281, 779, 4615, 373, 24037, 64671, 124019}},
+{9163, 17, 29236, {1, 1, 5, 5, 13, 51, 49, 19, 37, 857, 539, 1291, 6021, 8645, 30351, 33839, 111515}},
+{9164, 17, 29246, {1, 1, 5, 13, 3, 47, 9, 197, 19, 337, 2025, 3003, 7179, 5755, 31187, 59317, 69753}},
+{9165, 17, 29248, {1, 1, 7, 3, 3, 43, 11, 3, 123, 29, 857, 3349, 791, 11157, 23967, 33729, 28445}},
+{9166, 17, 29253, {1, 1, 5, 1, 1, 11, 73, 231, 173, 925, 331, 161, 3303, 11015, 17507, 21271, 56865}},
+{9167, 17, 29272, {1, 1, 3, 9, 21, 21, 115, 145, 421, 981, 1789, 3343, 7591, 12043, 5795, 17737, 106501}},
+{9168, 17, 29288, {1, 1, 7, 13, 7, 15, 51, 75, 497, 637, 1073, 1505, 5613, 1415, 30861, 26159, 79573}},
+{9169, 17, 29293, {1, 1, 3, 15, 17, 35, 17, 129, 169, 283, 1383, 149, 211, 1381, 22205, 28367, 831}},
+{9170, 17, 29294, {1, 3, 5, 5, 17, 11, 127, 183, 503, 499, 2011, 2721, 2717, 3105, 4731, 60319, 9361}},
+{9171, 17, 29308, {1, 1, 1, 7, 27, 55, 77, 203, 255, 761, 1159, 2915, 4479, 13671, 19757, 65497, 4461}},
+{9172, 17, 29318, {1, 3, 1, 9, 9, 51, 67, 205, 445, 35, 371, 1837, 3623, 10365, 19463, 59005, 3185}},
+{9173, 17, 29321, {1, 3, 7, 3, 23, 5, 51, 141, 293, 489, 263, 2187, 1259, 2729, 1779, 61027, 53931}},
+{9174, 17, 29322, {1, 1, 1, 15, 27, 7, 15, 109, 475, 839, 175, 953, 4531, 437, 22475, 24167, 19051}},
+{9175, 17, 29339, {1, 1, 7, 9, 25, 23, 41, 107, 299, 115, 1713, 1559, 5701, 5427, 28813, 39913, 15941}},
+{9176, 17, 29365, {1, 3, 5, 7, 5, 25, 99, 9, 307, 591, 1303, 3501, 1589, 12095, 26629, 52127, 60635}},
+{9177, 17, 29369, {1, 3, 7, 3, 9, 23, 3, 29, 113, 49, 1601, 541, 1415, 11601, 19165, 46595, 111623}},
+{9178, 17, 29372, {1, 1, 3, 11, 5, 53, 37, 153, 51, 41, 1267, 545, 2055, 13137, 7749, 30721, 119591}},
+{9179, 17, 29377, {1, 3, 5, 11, 1, 15, 65, 17, 155, 65, 745, 2547, 6351, 2347, 13553, 5785, 129857}},
+{9180, 17, 29392, {1, 3, 7, 13, 5, 53, 11, 59, 453, 467, 1275, 3669, 4481, 5229, 2953, 23369, 100161}},
+{9181, 17, 29401, {1, 3, 1, 1, 13, 41, 91, 179, 331, 547, 1571, 1787, 6467, 12375, 4579, 45023, 119149}},
+{9182, 17, 29402, {1, 3, 3, 5, 17, 55, 105, 57, 227, 323, 1517, 1215, 3149, 13919, 18595, 5525, 82445}},
+{9183, 17, 29418, {1, 3, 1, 13, 19, 23, 17, 239, 81, 481, 1625, 2003, 7295, 2185, 7021, 19357, 37867}},
+{9184, 17, 29437, {1, 3, 5, 9, 11, 15, 61, 223, 153, 139, 2023, 2579, 495, 14319, 2835, 26541, 113115}},
+{9185, 17, 29445, {1, 1, 3, 13, 29, 9, 13, 149, 325, 87, 697, 2345, 2205, 5069, 9939, 61351, 127313}},
+{9186, 17, 29446, {1, 1, 7, 11, 13, 53, 45, 197, 167, 551, 439, 3715, 4587, 8549, 28193, 35827, 96721}},
+{9187, 17, 29460, {1, 3, 1, 1, 17, 7, 31, 205, 219, 739, 1165, 243, 3877, 15943, 15207, 43857, 120565}},
+{9188, 17, 29467, {1, 3, 7, 9, 7, 43, 81, 203, 295, 553, 279, 2717, 9, 751, 24715, 21591, 11485}},
+{9189, 17, 29473, {1, 1, 1, 11, 15, 17, 41, 121, 355, 157, 955, 3875, 7595, 235, 4937, 20607, 11401}},
+{9190, 17, 29476, {1, 1, 7, 7, 13, 49, 33, 161, 65, 251, 1895, 2665, 3017, 9725, 10797, 46313, 43407}},
+{9191, 17, 29488, {1, 1, 3, 9, 23, 17, 127, 69, 385, 875, 461, 3305, 3001, 5875, 13547, 61239, 113571}},
+{9192, 17, 29511, {1, 3, 7, 5, 15, 47, 113, 131, 465, 89, 733, 433, 799, 5689, 723, 63479, 106945}},
+{9193, 17, 29512, {1, 3, 3, 15, 29, 1, 51, 115, 317, 1021, 1219, 1797, 4005, 10435, 28935, 49467, 66833}},
+{9194, 17, 29517, {1, 1, 3, 11, 15, 9, 51, 209, 477, 479, 1099, 2781, 5525, 12715, 9067, 18317, 121671}},
+{9195, 17, 29523, {1, 3, 1, 7, 19, 35, 61, 27, 479, 815, 1639, 2825, 7449, 13697, 3079, 49833, 35119}},
+{9196, 17, 29526, {1, 3, 7, 3, 17, 53, 95, 155, 505, 185, 717, 3419, 3857, 2369, 14525, 22797, 38553}},
+{9197, 17, 29535, {1, 3, 1, 13, 27, 5, 11, 21, 507, 65, 39, 2841, 7887, 2783, 18767, 34171, 40527}},
+{9198, 17, 29539, {1, 3, 1, 7, 9, 47, 69, 217, 251, 775, 631, 1967, 5541, 10679, 16439, 33533, 57817}},
+{9199, 17, 29545, {1, 1, 5, 11, 27, 57, 103, 255, 359, 745, 63, 3725, 4113, 10943, 7833, 46857, 99239}},
+{9200, 17, 29559, {1, 3, 1, 5, 31, 41, 69, 245, 401, 451, 959, 351, 6999, 6187, 21437, 55067, 53547}},
+{9201, 17, 29560, {1, 1, 1, 13, 25, 49, 85, 181, 457, 731, 743, 1901, 7013, 12027, 14729, 24193, 89685}},
+{9202, 17, 29589, {1, 3, 3, 1, 31, 29, 101, 137, 117, 135, 345, 1419, 7133, 2695, 3631, 53049, 45875}},
+{9203, 17, 29593, {1, 1, 1, 13, 11, 51, 95, 221, 339, 655, 201, 3007, 8179, 8093, 22399, 59123, 127319}},
+{9204, 17, 29599, {1, 3, 7, 3, 31, 37, 23, 199, 191, 649, 817, 1959, 893, 2333, 21477, 29087, 115667}},
+{9205, 17, 29603, {1, 3, 3, 5, 9, 55, 123, 67, 39, 533, 797, 2575, 3955, 14585, 28587, 13079, 60053}},
+{9206, 17, 29610, {1, 3, 1, 1, 17, 19, 15, 219, 185, 21, 967, 667, 3361, 3883, 8059, 26199, 80913}},
+{9207, 17, 29629, {1, 3, 3, 11, 23, 5, 99, 57, 379, 151, 271, 3735, 7087, 12731, 2949, 54831, 37835}},
+{9208, 17, 29644, {1, 3, 1, 7, 21, 25, 9, 195, 497, 585, 901, 19, 7675, 13611, 31155, 14567, 20545}},
+{9209, 17, 29656, {1, 1, 3, 3, 27, 45, 51, 169, 397, 531, 673, 2935, 3779, 7169, 23479, 16157, 100237}},
+{9210, 17, 29662, {1, 1, 1, 1, 19, 49, 3, 75, 455, 805, 591, 1929, 2883, 2797, 31379, 12025, 120929}},
+{9211, 17, 29675, {1, 3, 5, 3, 17, 39, 115, 93, 341, 329, 1857, 2753, 4923, 12539, 25589, 19437, 29027}},
+{9212, 17, 29692, {1, 3, 5, 9, 27, 37, 21, 235, 499, 369, 1341, 3719, 6819, 3153, 30619, 50901, 52999}},
+{9213, 17, 29704, {1, 3, 1, 11, 3, 55, 43, 219, 83, 771, 783, 3569, 7879, 2363, 30605, 5965, 126855}},
+{9214, 17, 29707, {1, 3, 7, 13, 7, 25, 111, 63, 355, 317, 1579, 1523, 2733, 11963, 25205, 20545, 67389}},
+{9215, 17, 29715, {1, 3, 5, 7, 3, 17, 55, 99, 321, 633, 2013, 1991, 1019, 9223, 21117, 23337, 90589}},
+{9216, 17, 29717, {1, 3, 1, 1, 17, 25, 79, 171, 303, 403, 2037, 2595, 3951, 8021, 8669, 9363, 20345}},
+{9217, 17, 29722, {1, 1, 1, 7, 13, 7, 11, 7, 347, 53, 1763, 3097, 3353, 3769, 22947, 20919, 92247}},
+{9218, 17, 29731, {1, 3, 5, 11, 19, 29, 91, 191, 511, 705, 1317, 3367, 7, 4999, 30251, 18299, 66983}},
+{9219, 17, 29740, {1, 1, 3, 7, 19, 17, 71, 77, 285, 189, 853, 2305, 4205, 15603, 15501, 48073, 11411}},
+{9220, 17, 29743, {1, 3, 7, 5, 21, 15, 47, 13, 277, 969, 1861, 3493, 6723, 11521, 22145, 43779, 44713}},
+{9221, 17, 29752, {1, 1, 3, 5, 19, 47, 51, 207, 229, 957, 709, 267, 8081, 611, 26403, 14871, 111841}},
+{9222, 17, 29760, {1, 3, 7, 1, 19, 43, 71, 73, 405, 351, 1131, 3527, 5949, 14363, 20041, 48123, 68123}},
+{9223, 17, 29766, {1, 3, 3, 7, 23, 51, 81, 13, 161, 453, 365, 1089, 3505, 12359, 14277, 56113, 19717}},
+{9224, 17, 29770, {1, 1, 1, 7, 29, 35, 103, 137, 317, 417, 1465, 2787, 6935, 9885, 12943, 43937, 28353}},
+{9225, 17, 29794, {1, 1, 3, 13, 19, 37, 97, 5, 115, 89, 1005, 3033, 2011, 2633, 10615, 6641, 73385}},
+{9226, 17, 29796, {1, 3, 7, 7, 31, 39, 107, 165, 61, 1009, 1159, 865, 3469, 11093, 10425, 43959, 37395}},
+{9227, 17, 29814, {1, 3, 5, 9, 7, 51, 99, 91, 37, 457, 39, 2455, 7481, 4929, 29755, 50603, 48943}},
+{9228, 17, 29817, {1, 1, 5, 13, 5, 39, 47, 149, 341, 303, 843, 3619, 7527, 8739, 5893, 42623, 99899}},
+{9229, 17, 29829, {1, 1, 1, 1, 1, 41, 73, 71, 409, 351, 131, 515, 6657, 337, 23913, 583, 21665}},
+{9230, 17, 29841, {1, 1, 3, 3, 11, 45, 39, 113, 315, 965, 1605, 2779, 501, 7429, 2567, 7011, 71445}},
+{9231, 17, 29851, {1, 3, 7, 13, 21, 13, 45, 105, 385, 281, 1683, 3997, 6391, 10943, 22349, 37261, 57555}},
+{9232, 17, 29860, {1, 1, 3, 5, 17, 55, 109, 71, 393, 561, 433, 1091, 1923, 13861, 12981, 5523, 15467}},
+{9233, 17, 29864, {1, 3, 7, 5, 17, 11, 113, 119, 37, 989, 1609, 2191, 1511, 11835, 25423, 793, 15227}},
+{9234, 17, 29869, {1, 3, 1, 5, 5, 55, 105, 225, 349, 351, 1259, 1309, 821, 2733, 1357, 3665, 38863}},
+{9235, 17, 29870, {1, 3, 5, 1, 23, 61, 49, 113, 169, 319, 85, 1581, 97, 5271, 30625, 37693, 7297}},
+{9236, 17, 29889, {1, 3, 5, 1, 1, 25, 31, 125, 307, 731, 1815, 1047, 7251, 12481, 20781, 63275, 51985}},
+{9237, 17, 29896, {1, 3, 5, 9, 11, 9, 121, 111, 45, 751, 793, 2593, 6409, 4355, 30183, 36959, 105161}},
+{9238, 17, 29901, {1, 1, 3, 9, 25, 37, 95, 253, 401, 481, 1521, 3555, 231, 15459, 1581, 36661, 121727}},
+{9239, 17, 29913, {1, 3, 5, 3, 27, 11, 107, 115, 213, 813, 27, 1789, 603, 383, 1129, 63365, 51147}},
+{9240, 17, 29919, {1, 1, 3, 13, 25, 7, 33, 1, 97, 907, 35, 4069, 5001, 507, 911, 62037, 22019}},
+{9241, 17, 29920, {1, 1, 3, 5, 7, 55, 35, 95, 261, 217, 1565, 3473, 3475, 12181, 569, 27389, 81771}},
+{9242, 17, 29947, {1, 1, 3, 5, 11, 33, 95, 121, 453, 711, 361, 3927, 5231, 15685, 31143, 56915, 23707}},
+{9243, 17, 29958, {1, 1, 3, 11, 25, 15, 53, 155, 469, 647, 1547, 335, 3753, 12873, 13639, 25129, 79287}},
+{9244, 17, 29975, {1, 3, 3, 3, 1, 21, 21, 121, 105, 903, 83, 2287, 4295, 14369, 29183, 26841, 38115}},
+{9245, 17, 29981, {1, 1, 7, 11, 5, 29, 65, 191, 389, 419, 1315, 739, 3485, 10587, 2399, 36377, 28789}},
+{9246, 17, 29985, {1, 3, 3, 11, 3, 29, 71, 169, 265, 747, 395, 1211, 3487, 15705, 25611, 18183, 85771}},
+{9247, 17, 29998, {1, 1, 7, 3, 23, 5, 45, 47, 337, 571, 33, 1221, 5671, 1233, 28361, 36945, 911}},
+{9248, 17, 30010, {1, 1, 5, 11, 17, 15, 57, 97, 185, 999, 1277, 3371, 2785, 3341, 13395, 11925, 86777}},
+{9249, 17, 30012, {1, 1, 3, 1, 31, 37, 23, 105, 503, 869, 1309, 3733, 4629, 8263, 11763, 30669, 26179}},
+{9250, 17, 30044, {1, 1, 3, 15, 25, 61, 37, 27, 325, 413, 809, 2959, 8137, 3397, 21185, 27995, 84297}},
+{9251, 17, 30048, {1, 3, 5, 5, 1, 55, 95, 41, 493, 469, 331, 1789, 7037, 7947, 14239, 16109, 51795}},
+{9252, 17, 30051, {1, 1, 1, 1, 19, 33, 111, 237, 261, 331, 871, 3539, 1731, 6953, 11345, 37901, 5623}},
+{9253, 17, 30063, {1, 1, 5, 7, 21, 41, 49, 179, 49, 797, 231, 1299, 145, 7743, 725, 60595, 19581}},
+{9254, 17, 30065, {1, 3, 7, 15, 7, 43, 67, 219, 133, 641, 1657, 2301, 1591, 12309, 6395, 3999, 92961}},
+{9255, 17, 30072, {1, 1, 1, 5, 1, 49, 37, 81, 219, 323, 461, 1379, 1797, 14825, 21811, 7347, 35643}},
+{9256, 17, 30077, {1, 1, 1, 11, 1, 3, 83, 31, 307, 83, 1169, 3277, 1875, 13397, 20265, 46707, 15205}},
+{9257, 17, 30087, {1, 3, 7, 11, 29, 41, 69, 33, 405, 991, 1937, 1217, 2137, 8657, 4319, 41119, 43371}},
+{9258, 17, 30088, {1, 3, 3, 3, 25, 49, 107, 197, 347, 923, 1585, 3023, 4087, 13875, 22015, 35733, 33755}},
+{9259, 17, 30101, {1, 3, 3, 5, 15, 61, 89, 249, 141, 853, 1469, 999, 7425, 10015, 12341, 51535, 61619}},
+{9260, 17, 30112, {1, 1, 7, 13, 31, 61, 89, 113, 117, 429, 1011, 1589, 1419, 5083, 4843, 26759, 47401}},
+{9261, 17, 30121, {1, 1, 7, 9, 17, 37, 119, 39, 499, 93, 1155, 3069, 2033, 12483, 29849, 40077, 11103}},
+{9262, 17, 30122, {1, 3, 1, 15, 11, 5, 23, 121, 283, 717, 1573, 3911, 2031, 2617, 20387, 33157, 301}},
+{9263, 17, 30130, {1, 3, 5, 7, 17, 61, 109, 3, 205, 617, 1171, 223, 6609, 15027, 2629, 15801, 73749}},
+{9264, 17, 30135, {1, 1, 3, 7, 5, 49, 9, 73, 333, 401, 675, 2765, 993, 77, 19237, 60929, 88703}},
+{9265, 17, 30139, {1, 1, 1, 9, 21, 25, 53, 249, 241, 43, 1959, 545, 3729, 11395, 3027, 12661, 87729}},
+{9266, 17, 30142, {1, 3, 3, 15, 15, 61, 33, 59, 155, 773, 1043, 3111, 6549, 5397, 29099, 57851, 107671}},
+{9267, 17, 30164, {1, 3, 7, 1, 29, 29, 1, 161, 273, 883, 1913, 2389, 401, 9425, 17613, 50443, 84601}},
+{9268, 17, 30167, {1, 3, 7, 11, 15, 63, 41, 53, 371, 153, 1491, 3013, 6635, 4955, 30145, 20175, 16541}},
+{9269, 17, 30180, {1, 3, 3, 11, 31, 27, 127, 207, 11, 313, 1067, 3445, 3075, 4071, 28305, 58911, 85273}},
+{9270, 17, 30202, {1, 1, 7, 11, 17, 47, 77, 119, 209, 657, 1181, 459, 5821, 4267, 5757, 53703, 35621}},
+{9271, 17, 30211, {1, 3, 1, 15, 27, 41, 3, 217, 457, 531, 1749, 2847, 4715, 11451, 25071, 53999, 93503}},
+{9272, 17, 30214, {1, 3, 5, 3, 19, 29, 9, 177, 355, 265, 883, 1113, 2397, 1819, 20757, 50389, 95551}},
+{9273, 17, 30217, {1, 1, 3, 15, 3, 45, 85, 211, 377, 293, 1791, 1193, 1117, 9383, 28039, 27155, 129513}},
+{9274, 17, 30223, {1, 1, 7, 5, 1, 17, 59, 215, 161, 933, 1653, 2407, 2693, 3655, 7515, 2239, 88985}},
+{9275, 17, 30228, {1, 1, 3, 11, 31, 3, 1, 77, 459, 817, 651, 603, 1711, 9391, 20607, 48195, 127153}},
+{9276, 17, 30235, {1, 1, 5, 13, 11, 49, 25, 13, 51, 443, 1877, 1257, 163, 4673, 30313, 18841, 24547}},
+{9277, 17, 30256, {1, 1, 7, 7, 15, 33, 43, 79, 127, 625, 1991, 1311, 2095, 14659, 3477, 56023, 57955}},
+{9278, 17, 30265, {1, 3, 7, 15, 29, 7, 119, 183, 123, 323, 1723, 959, 2733, 2097, 2927, 57595, 86067}},
+{9279, 17, 30286, {1, 3, 5, 5, 29, 57, 93, 139, 495, 739, 1715, 713, 243, 2027, 11223, 44143, 119155}},
+{9280, 17, 30293, {1, 3, 1, 9, 3, 63, 113, 29, 19, 439, 869, 1101, 4947, 2191, 14737, 57049, 93505}},
+{9281, 17, 30298, {1, 1, 7, 1, 11, 39, 27, 29, 281, 829, 1979, 2185, 2207, 14969, 7447, 55541, 59593}},
+{9282, 17, 30310, {1, 1, 7, 13, 11, 15, 15, 143, 383, 469, 1439, 2823, 7489, 7675, 15433, 26203, 80433}},
+{9283, 17, 30314, {1, 1, 1, 7, 15, 45, 23, 93, 477, 1, 1431, 3173, 7879, 12211, 13051, 56971, 114289}},
+{9284, 17, 30327, {1, 3, 1, 1, 27, 55, 61, 185, 323, 569, 1063, 1357, 7373, 14947, 15967, 64517, 104625}},
+{9285, 17, 30333, {1, 1, 5, 11, 25, 1, 127, 163, 419, 657, 911, 361, 3675, 10765, 24565, 2661, 61979}},
+{9286, 17, 30334, {1, 3, 7, 15, 29, 53, 29, 149, 465, 535, 1865, 2243, 4783, 9327, 24843, 52313, 15683}},
+{9287, 17, 30337, {1, 1, 7, 7, 17, 7, 85, 187, 91, 1013, 1917, 2959, 3571, 12047, 25267, 34095, 9877}},
+{9288, 17, 30338, {1, 1, 1, 7, 5, 27, 111, 107, 313, 571, 1081, 3193, 1025, 2589, 1523, 40453, 77065}},
+{9289, 17, 30344, {1, 3, 7, 1, 19, 27, 1, 103, 479, 405, 583, 1737, 3495, 9093, 20397, 16429, 45609}},
+{9290, 17, 30349, {1, 1, 3, 11, 17, 1, 125, 97, 261, 651, 901, 1245, 1181, 14469, 16229, 31935, 100227}},
+{9291, 17, 30352, {1, 1, 7, 11, 15, 1, 19, 151, 453, 833, 1371, 1109, 5373, 25, 5619, 58351, 26349}},
+{9292, 17, 30362, {1, 1, 7, 15, 17, 55, 51, 67, 123, 13, 1873, 1035, 5871, 11943, 11543, 43261, 62587}},
+{9293, 17, 30374, {1, 3, 1, 13, 21, 15, 83, 205, 333, 379, 2021, 1389, 861, 10395, 20587, 38207, 49109}},
+{9294, 17, 30380, {1, 1, 5, 3, 13, 49, 89, 85, 463, 1005, 1367, 3487, 581, 12145, 22445, 35343, 65745}},
+{9295, 17, 30388, {1, 3, 3, 3, 29, 27, 99, 195, 89, 793, 1677, 3989, 4811, 8303, 9165, 50349, 96947}},
+{9296, 17, 30391, {1, 1, 3, 5, 29, 11, 91, 107, 13, 659, 213, 1613, 2245, 11567, 28157, 2937, 53275}},
+{9297, 17, 30395, {1, 3, 7, 5, 3, 41, 65, 27, 93, 747, 1143, 505, 3881, 2123, 2903, 54137, 96185}},
+{9298, 17, 30403, {1, 1, 3, 15, 9, 49, 3, 25, 77, 681, 1709, 915, 2243, 2127, 18243, 13915, 67399}},
+{9299, 17, 30409, {1, 3, 5, 7, 13, 49, 89, 67, 63, 271, 1651, 897, 4035, 1067, 13743, 56791, 44371}},
+{9300, 17, 30424, {1, 1, 7, 9, 25, 19, 125, 15, 125, 705, 1359, 817, 1241, 12447, 19097, 33209, 89091}},
+{9301, 17, 30427, {1, 3, 7, 3, 19, 43, 127, 197, 39, 709, 257, 3547, 3069, 1187, 21255, 6453, 40763}},
+{9302, 17, 30430, {1, 3, 3, 5, 3, 53, 37, 65, 415, 183, 991, 533, 7805, 9905, 18925, 52665, 100987}},
+{9303, 17, 30451, {1, 3, 3, 11, 17, 41, 17, 137, 143, 277, 945, 1531, 7427, 7287, 30869, 27651, 116507}},
+{9304, 17, 30460, {1, 1, 1, 3, 13, 3, 9, 163, 113, 373, 1909, 1051, 97, 10729, 28615, 40081, 129297}},
+{9305, 17, 30475, {1, 3, 3, 9, 11, 47, 113, 27, 307, 339, 1319, 3083, 7383, 1551, 26691, 28769, 114313}},
+{9306, 17, 30480, {1, 3, 7, 7, 25, 49, 31, 231, 485, 629, 59, 283, 7463, 6603, 23055, 63643, 10121}},
+{9307, 17, 30485, {1, 3, 7, 9, 5, 55, 53, 127, 147, 103, 1697, 485, 7051, 14153, 21631, 35561, 10393}},
+{9308, 17, 30486, {1, 3, 3, 7, 23, 7, 83, 17, 135, 487, 315, 719, 7003, 3919, 13255, 24031, 110493}},
+{9309, 17, 30489, {1, 3, 1, 15, 27, 55, 121, 177, 205, 733, 933, 1535, 2925, 4259, 22203, 59059, 89209}},
+{9310, 17, 30492, {1, 1, 1, 11, 9, 11, 127, 47, 493, 349, 1415, 3089, 4739, 14347, 31579, 20739, 72997}},
+{9311, 17, 30499, {1, 3, 1, 7, 9, 31, 121, 111, 163, 733, 1699, 1507, 5467, 13499, 25269, 6303, 70201}},
+{9312, 17, 30511, {1, 3, 1, 5, 7, 23, 123, 203, 329, 387, 577, 2331, 2283, 14029, 19409, 103, 2477}},
+{9313, 17, 30533, {1, 1, 7, 15, 11, 29, 29, 153, 289, 333, 1669, 2065, 5465, 8835, 28753, 21209, 34283}},
+{9314, 17, 30534, {1, 3, 5, 11, 15, 33, 45, 81, 241, 461, 1167, 1073, 5511, 795, 30955, 49121, 42805}},
+{9315, 17, 30540, {1, 1, 1, 13, 7, 33, 11, 201, 161, 475, 1359, 2329, 177, 9883, 8967, 21399, 73045}},
+{9316, 17, 30545, {1, 3, 3, 1, 25, 59, 85, 51, 481, 751, 1213, 3019, 421, 9903, 30071, 50661, 94715}},
+{9317, 17, 30552, {1, 3, 3, 1, 5, 61, 3, 179, 131, 233, 1627, 3577, 6323, 14161, 21595, 44963, 20215}},
+{9318, 17, 30557, {1, 1, 1, 5, 9, 53, 45, 105, 275, 769, 105, 2757, 6769, 14987, 19955, 18291, 81707}},
+{9319, 17, 30558, {1, 1, 7, 1, 1, 59, 33, 19, 385, 775, 423, 1799, 1325, 13545, 16027, 58347, 102397}},
+{9320, 17, 30567, {1, 1, 3, 11, 15, 61, 63, 59, 355, 659, 1483, 3781, 7383, 5563, 32537, 34175, 40303}},
+{9321, 17, 30568, {1, 3, 5, 7, 5, 37, 19, 223, 323, 129, 287, 2655, 3767, 16201, 4147, 315, 54885}},
+{9322, 17, 30581, {1, 1, 7, 13, 13, 23, 43, 129, 405, 205, 1691, 2189, 3313, 11789, 10263, 16367, 65547}},
+{9323, 17, 30597, {1, 3, 5, 1, 15, 21, 85, 233, 427, 71, 475, 3731, 3335, 11483, 28613, 4335, 35669}},
+{9324, 17, 30607, {1, 1, 3, 3, 31, 47, 27, 109, 373, 451, 1459, 3103, 1941, 10405, 20233, 30517, 122787}},
+{9325, 17, 30621, {1, 3, 1, 7, 3, 11, 113, 49, 355, 465, 1959, 1355, 6521, 10863, 11481, 13385, 31787}},
+{9326, 17, 30632, {1, 3, 1, 1, 9, 45, 125, 69, 267, 413, 717, 2767, 833, 317, 23019, 37753, 3081}},
+{9327, 17, 30650, {1, 1, 7, 7, 13, 55, 75, 105, 71, 505, 239, 3739, 4873, 4257, 18841, 41711, 24045}},
+{9328, 17, 30655, {1, 1, 5, 13, 21, 59, 107, 229, 421, 441, 1079, 3727, 7941, 8443, 30433, 56419, 105751}},
+{9329, 17, 30657, {1, 1, 1, 9, 15, 59, 29, 49, 117, 1009, 1971, 115, 2899, 1069, 29145, 11855, 35277}},
+{9330, 17, 30660, {1, 3, 7, 15, 19, 55, 111, 77, 169, 537, 1695, 2687, 3871, 14017, 15119, 27313, 112807}},
+{9331, 17, 30669, {1, 1, 3, 7, 29, 5, 41, 201, 211, 127, 1877, 643, 2441, 8743, 29393, 6077, 52597}},
+{9332, 17, 30675, {1, 3, 1, 11, 7, 1, 95, 15, 229, 339, 475, 3463, 7827, 9943, 30903, 65013, 1145}},
+{9333, 17, 30678, {1, 1, 1, 5, 23, 19, 81, 23, 475, 169, 373, 1147, 1805, 12779, 13173, 8945, 28175}},
+{9334, 17, 30682, {1, 3, 5, 9, 3, 53, 127, 33, 237, 803, 121, 307, 4981, 8765, 12761, 23601, 92921}},
+{9335, 17, 30687, {1, 1, 3, 7, 17, 63, 11, 37, 213, 619, 1095, 1693, 6747, 7373, 17355, 5987, 97923}},
+{9336, 17, 30688, {1, 1, 3, 15, 11, 37, 109, 175, 503, 339, 591, 2745, 2387, 7419, 13915, 4769, 48229}},
+{9337, 17, 30698, {1, 3, 5, 7, 19, 17, 5, 81, 471, 989, 249, 437, 7309, 5747, 25277, 31911, 87907}},
+{9338, 17, 30711, {1, 3, 1, 7, 15, 25, 49, 243, 423, 911, 1957, 911, 6331, 9831, 26021, 58877, 99257}},
+{9339, 17, 30728, {1, 3, 5, 11, 3, 55, 39, 129, 271, 145, 1973, 3391, 2905, 9229, 7989, 15641, 67933}},
+{9340, 17, 30733, {1, 3, 5, 9, 13, 13, 43, 135, 183, 319, 1391, 2953, 2207, 14205, 31203, 6329, 98907}},
+{9341, 17, 30741, {1, 3, 1, 9, 27, 41, 27, 155, 11, 191, 1747, 975, 7043, 13139, 30387, 47099, 120321}},
+{9342, 17, 30746, {1, 1, 5, 9, 25, 27, 53, 235, 437, 77, 371, 2413, 4867, 14245, 27199, 37387, 88217}},
+{9343, 17, 30752, {1, 1, 7, 7, 11, 59, 103, 15, 109, 65, 1987, 3695, 7737, 7341, 26963, 16075, 6301}},
+{9344, 17, 30764, {1, 3, 7, 5, 7, 59, 109, 159, 121, 377, 1851, 3983, 5421, 7633, 7321, 14869, 54633}},
+{9345, 17, 30769, {1, 1, 3, 15, 21, 51, 35, 243, 397, 411, 1107, 3689, 7913, 14715, 26349, 23361, 90665}},
+{9346, 17, 30784, {1, 1, 1, 3, 5, 11, 77, 205, 187, 981, 1969, 1749, 6295, 8267, 16073, 54451, 103603}},
+{9347, 17, 30796, {1, 3, 3, 9, 11, 13, 113, 83, 243, 1021, 2003, 2277, 6457, 10535, 13461, 52741, 9385}},
+{9348, 17, 30799, {1, 3, 3, 11, 19, 9, 103, 13, 219, 269, 1805, 2689, 5219, 11497, 4909, 57985, 40141}},
+{9349, 17, 30804, {1, 1, 1, 1, 29, 25, 15, 217, 69, 567, 839, 1515, 3627, 9837, 21433, 37177, 10487}},
+{9350, 17, 30811, {1, 1, 7, 15, 15, 23, 119, 217, 277, 447, 551, 825, 7571, 3083, 16573, 1189, 64959}},
+{9351, 17, 30814, {1, 1, 3, 11, 9, 13, 63, 77, 313, 195, 941, 1621, 165, 8905, 20265, 53761, 25091}},
+{9352, 17, 30818, {1, 3, 3, 9, 17, 5, 9, 183, 175, 1015, 253, 233, 2883, 15587, 27175, 38517, 22707}},
+{9353, 17, 30827, {1, 3, 3, 11, 23, 63, 83, 17, 49, 671, 749, 3249, 7821, 7189, 26735, 28995, 101737}},
+{9354, 17, 30838, {1, 1, 7, 5, 25, 15, 97, 247, 161, 585, 1307, 3803, 1105, 9093, 23523, 1383, 65671}},
+{9355, 17, 30842, {1, 1, 3, 15, 29, 51, 65, 237, 349, 709, 799, 1425, 6267, 6283, 4773, 18123, 74833}},
+{9356, 17, 30854, {1, 1, 5, 5, 11, 13, 9, 251, 373, 189, 467, 945, 7279, 11349, 10917, 6581, 83967}},
+{9357, 17, 30863, {1, 1, 7, 15, 23, 27, 1, 197, 41, 325, 757, 1229, 6295, 345, 26147, 40135, 123063}},
+{9358, 17, 30865, {1, 1, 7, 9, 23, 9, 93, 225, 191, 837, 103, 3367, 5411, 8289, 7057, 55391, 10669}},
+{9359, 17, 30877, {1, 1, 5, 15, 21, 17, 49, 221, 487, 23, 1943, 1563, 6157, 4035, 27769, 14933, 56913}},
+{9360, 17, 30881, {1, 1, 5, 13, 13, 43, 67, 245, 457, 365, 1115, 2205, 6229, 4173, 25167, 56333, 55605}},
+{9361, 17, 30887, {1, 1, 5, 11, 15, 59, 109, 83, 17, 913, 497, 1299, 5221, 321, 32139, 13717, 94311}},
+{9362, 17, 30908, {1, 3, 3, 3, 31, 11, 5, 203, 3, 843, 2039, 25, 6211, 14927, 6015, 46269, 90369}},
+{9363, 17, 30916, {1, 1, 3, 9, 21, 51, 91, 203, 149, 147, 197, 1771, 2921, 6609, 2343, 35249, 12963}},
+{9364, 17, 30919, {1, 3, 1, 7, 17, 43, 91, 229, 107, 521, 737, 2355, 5855, 6707, 21217, 47041, 81833}},
+{9365, 17, 30925, {1, 3, 3, 7, 7, 31, 97, 135, 503, 665, 1799, 2937, 6867, 4125, 7375, 34401, 18111}},
+{9366, 17, 30928, {1, 1, 7, 1, 11, 29, 89, 185, 495, 633, 507, 3727, 5999, 5871, 5911, 24877, 10259}},
+{9367, 17, 30944, {1, 1, 1, 13, 25, 3, 25, 65, 91, 411, 147, 3699, 7003, 3017, 25635, 56619, 101491}},
+{9368, 17, 30947, {1, 3, 5, 7, 31, 1, 63, 255, 115, 179, 87, 735, 1649, 4767, 31093, 60149, 49829}},
+{9369, 17, 30950, {1, 1, 3, 1, 21, 63, 67, 85, 399, 279, 1963, 1759, 4679, 15423, 11533, 54387, 36563}},
+{9370, 17, 30968, {1, 3, 5, 3, 31, 53, 73, 73, 481, 443, 1393, 2763, 1199, 5375, 8977, 5369, 114603}},
+{9371, 17, 30971, {1, 1, 1, 3, 29, 47, 73, 205, 469, 187, 815, 2787, 1431, 4705, 11455, 53643, 89269}},
+{9372, 17, 30973, {1, 3, 3, 9, 27, 57, 93, 55, 287, 539, 1259, 3279, 1563, 11399, 22975, 27077, 41031}},
+{9373, 17, 30976, {1, 1, 3, 15, 7, 27, 67, 25, 169, 263, 621, 1921, 509, 11715, 15363, 27447, 75535}},
+{9374, 17, 30986, {1, 1, 1, 9, 29, 63, 31, 99, 321, 361, 1693, 763, 5593, 10815, 741, 31257, 70843}},
+{9375, 17, 30993, {1, 1, 1, 9, 1, 17, 73, 141, 401, 549, 415, 1289, 1697, 1903, 8919, 59563, 60017}},
+{9376, 17, 30994, {1, 3, 7, 3, 5, 51, 127, 221, 9, 929, 153, 1045, 6587, 13653, 5343, 14043, 116125}},
+{9377, 17, 31012, {1, 3, 3, 13, 13, 17, 29, 93, 465, 59, 1207, 3121, 6331, 8647, 5047, 41869, 51969}},
+{9378, 17, 31016, {1, 1, 1, 15, 23, 29, 47, 149, 119, 855, 367, 1419, 7739, 1141, 19787, 38185, 84403}},
+{9379, 17, 31029, {1, 3, 1, 9, 29, 63, 5, 63, 435, 401, 1023, 1981, 6819, 7547, 30065, 33833, 7471}},
+{9380, 17, 31039, {1, 3, 1, 15, 1, 47, 35, 161, 243, 225, 935, 2179, 7737, 7841, 28523, 11505, 103741}},
+{9381, 17, 31041, {1, 1, 7, 3, 7, 57, 73, 55, 101, 905, 1705, 4057, 3781, 8213, 18997, 17185, 33265}},
+{9382, 17, 31042, {1, 1, 5, 1, 7, 57, 31, 77, 323, 395, 927, 1969, 6973, 9013, 30789, 757, 84075}},
+{9383, 17, 31044, {1, 1, 3, 7, 15, 53, 51, 205, 401, 679, 1295, 1955, 7739, 11423, 23207, 55449, 60419}},
+{9384, 17, 31053, {1, 3, 5, 11, 23, 21, 67, 141, 157, 767, 219, 3607, 1847, 11051, 31499, 8461, 106353}},
+{9385, 17, 31059, {1, 1, 3, 9, 17, 19, 123, 169, 1, 31, 1019, 1823, 6043, 1895, 17293, 62079, 16945}},
+{9386, 17, 31062, {1, 3, 5, 9, 3, 15, 49, 27, 183, 293, 989, 2161, 1845, 1103, 20149, 11121, 31935}},
+{9387, 17, 31077, {1, 3, 1, 3, 17, 39, 103, 45, 491, 91, 413, 487, 1381, 5457, 22503, 40477, 94297}},
+{9388, 17, 31095, {1, 1, 3, 7, 29, 11, 87, 79, 349, 437, 945, 3753, 6691, 4373, 24875, 54397, 33697}},
+{9389, 17, 31101, {1, 1, 7, 1, 9, 31, 105, 121, 97, 947, 129, 1909, 2371, 5493, 29523, 52685, 24325}},
+{9390, 17, 31105, {1, 1, 5, 9, 19, 21, 63, 115, 511, 525, 49, 1879, 6075, 8181, 10135, 56785, 53309}},
+{9391, 17, 31118, {1, 1, 5, 15, 3, 55, 75, 135, 451, 697, 1407, 2765, 2443, 11589, 24863, 47187, 98477}},
+{9392, 17, 31129, {1, 1, 1, 13, 27, 37, 77, 157, 121, 603, 491, 2201, 619, 9157, 32511, 19843, 49919}},
+{9393, 17, 31132, {1, 1, 3, 1, 23, 17, 23, 115, 119, 349, 987, 2587, 1847, 12099, 31955, 31685, 1989}},
+{9394, 17, 31141, {1, 3, 7, 7, 5, 47, 63, 209, 69, 921, 1041, 1391, 7485, 11121, 30993, 5691, 74551}},
+{9395, 17, 31159, {1, 3, 1, 3, 23, 61, 55, 253, 355, 299, 971, 279, 3543, 10073, 5199, 50539, 88303}},
+{9396, 17, 31183, {1, 1, 1, 11, 13, 19, 7, 255, 189, 267, 2021, 93, 219, 10537, 28627, 58141, 53675}},
+{9397, 17, 31185, {1, 3, 3, 7, 27, 61, 83, 95, 163, 777, 1533, 2485, 7211, 6979, 4013, 20797, 91411}},
+{9398, 17, 31195, {1, 1, 7, 13, 15, 37, 5, 109, 133, 225, 59, 3855, 3351, 659, 24321, 63531, 15573}},
+{9399, 17, 31202, {1, 1, 5, 1, 7, 55, 59, 213, 45, 77, 2003, 2921, 1105, 11089, 17197, 45459, 67681}},
+{9400, 17, 31213, {1, 1, 1, 5, 13, 21, 107, 245, 505, 409, 1453, 1201, 6945, 2103, 7377, 59413, 8785}},
+{9401, 17, 31238, {1, 1, 1, 13, 5, 37, 73, 55, 39, 219, 225, 3877, 6583, 3105, 25355, 14839, 23435}},
+{9402, 17, 31241, {1, 1, 7, 1, 21, 35, 87, 227, 487, 767, 609, 1685, 2731, 10135, 381, 24021, 122137}},
+{9403, 17, 31252, {1, 1, 1, 3, 29, 13, 19, 255, 355, 505, 1757, 3537, 3029, 11403, 22685, 61169, 397}},
+{9404, 17, 31262, {1, 1, 7, 1, 29, 43, 11, 207, 83, 97, 435, 1453, 4709, 4193, 18517, 47203, 3255}},
+{9405, 17, 31265, {1, 1, 1, 1, 21, 49, 39, 163, 459, 849, 561, 1207, 4109, 1435, 17519, 14839, 1331}},
+{9406, 17, 31295, {1, 1, 3, 11, 27, 35, 65, 219, 135, 559, 1111, 2959, 7835, 5165, 26641, 22765, 121829}},
+{9407, 17, 31300, {1, 3, 5, 3, 23, 31, 57, 149, 431, 451, 189, 1771, 5877, 3503, 7531, 46485, 129031}},
+{9408, 17, 31303, {1, 1, 3, 11, 1, 13, 47, 17, 331, 1003, 215, 2797, 689, 6289, 12719, 37139, 35827}},
+{9409, 17, 31317, {1, 3, 5, 9, 19, 13, 11, 29, 275, 165, 783, 313, 2153, 6009, 2247, 5699, 128753}},
+{9410, 17, 31318, {1, 1, 7, 13, 5, 43, 51, 75, 411, 743, 335, 217, 559, 15389, 6567, 41193, 127443}},
+{9411, 17, 31324, {1, 3, 5, 15, 5, 63, 7, 145, 445, 835, 825, 35, 5951, 5121, 16365, 36789, 2941}},
+{9412, 17, 31338, {1, 3, 5, 5, 29, 1, 61, 19, 427, 245, 445, 3505, 3647, 8817, 8031, 64577, 60745}},
+{9413, 17, 31340, {1, 1, 3, 9, 29, 9, 35, 225, 55, 535, 1537, 831, 6483, 16123, 26079, 32809, 62227}},
+{9414, 17, 31345, {1, 3, 7, 7, 25, 33, 15, 61, 343, 749, 1963, 2763, 3171, 6755, 6529, 49449, 88903}},
+{9415, 17, 31355, {1, 1, 7, 13, 17, 35, 91, 119, 87, 1023, 1101, 1785, 2005, 15947, 21679, 63179, 3389}},
+{9416, 17, 31362, {1, 3, 1, 1, 1, 1, 123, 195, 315, 681, 153, 1621, 5097, 3669, 20505, 39305, 127065}},
+{9417, 17, 31371, {1, 1, 5, 11, 1, 17, 73, 251, 185, 59, 1723, 2321, 2103, 6331, 29571, 63811, 66651}},
+{9418, 17, 31373, {1, 1, 7, 13, 15, 19, 111, 91, 211, 85, 711, 2197, 3107, 2717, 16725, 52995, 65791}},
+{9419, 17, 31381, {1, 3, 3, 9, 21, 41, 53, 145, 459, 155, 93, 2833, 6747, 737, 30625, 40581, 65825}},
+{9420, 17, 31391, {1, 3, 3, 3, 1, 45, 119, 81, 185, 431, 1221, 3043, 7277, 10537, 12355, 42261, 126117}},
+{9421, 17, 31409, {1, 3, 7, 7, 11, 47, 37, 41, 123, 643, 707, 2963, 6183, 15527, 10951, 24031, 38187}},
+{9422, 17, 31410, {1, 3, 1, 7, 13, 57, 1, 149, 117, 627, 1999, 2805, 4857, 12805, 31453, 25699, 109447}},
+{9423, 17, 31412, {1, 3, 5, 3, 9, 37, 83, 221, 77, 573, 661, 465, 1279, 7355, 24061, 36151, 96595}},
+{9424, 17, 31434, {1, 1, 7, 15, 29, 31, 125, 205, 449, 563, 1263, 3427, 8013, 14025, 15235, 11833, 25601}},
+{9425, 17, 31458, {1, 3, 7, 11, 31, 35, 99, 193, 163, 527, 1455, 395, 4853, 2561, 11909, 57311, 101007}},
+{9426, 17, 31467, {1, 1, 5, 3, 17, 39, 99, 173, 497, 245, 1671, 3457, 83, 11959, 2963, 3401, 102259}},
+{9427, 17, 31470, {1, 1, 1, 5, 25, 41, 119, 81, 301, 797, 661, 2543, 1195, 2111, 1785, 41533, 51947}},
+{9428, 17, 31475, {1, 3, 3, 13, 5, 59, 61, 153, 213, 541, 1849, 249, 3897, 3877, 17095, 6857, 76781}},
+{9429, 17, 31481, {1, 3, 7, 1, 19, 13, 57, 47, 359, 165, 1085, 2263, 3261, 12825, 17405, 25853, 20731}},
+{9430, 17, 31482, {1, 1, 1, 7, 7, 43, 7, 65, 51, 503, 173, 1023, 283, 14809, 1183, 33497, 110683}},
+{9431, 17, 31484, {1, 3, 5, 11, 19, 51, 29, 157, 159, 191, 1293, 2951, 6569, 12433, 14587, 30631, 30485}},
+{9432, 17, 31492, {1, 3, 7, 5, 1, 27, 25, 221, 255, 471, 779, 3991, 6985, 1803, 28451, 33403, 5567}},
+{9433, 17, 31507, {1, 1, 5, 5, 7, 29, 55, 241, 457, 863, 1715, 3393, 4127, 13985, 6313, 13683, 114837}},
+{9434, 17, 31514, {1, 3, 5, 5, 11, 27, 55, 109, 247, 199, 1593, 2881, 307, 97, 24751, 35921, 121931}},
+{9435, 17, 31538, {1, 3, 1, 13, 3, 59, 17, 161, 47, 467, 1019, 3629, 3017, 15645, 3983, 32393, 79213}},
+{9436, 17, 31547, {1, 1, 3, 11, 19, 57, 67, 199, 319, 107, 2043, 2045, 4025, 5733, 29979, 37721, 117031}},
+{9437, 17, 31549, {1, 3, 7, 11, 9, 23, 31, 81, 177, 801, 1177, 3451, 7777, 15351, 7579, 39033, 23847}},
+{9438, 17, 31555, {1, 1, 3, 5, 17, 61, 63, 7, 371, 905, 1147, 1383, 4075, 6721, 17503, 32015, 112547}},
+{9439, 17, 31557, {1, 1, 3, 13, 13, 25, 69, 159, 49, 133, 227, 2155, 1603, 10077, 3429, 39131, 18949}},
+{9440, 17, 31597, {1, 3, 5, 3, 29, 5, 115, 93, 243, 791, 1113, 2841, 4733, 3041, 31733, 28539, 84567}},
+{9441, 17, 31598, {1, 3, 3, 7, 21, 9, 5, 95, 489, 517, 1453, 2697, 7951, 12369, 19571, 29811, 51805}},
+{9442, 17, 31610, {1, 1, 5, 9, 1, 29, 97, 191, 73, 357, 745, 2787, 7815, 4565, 19761, 33729, 86849}},
+{9443, 17, 31625, {1, 3, 5, 13, 3, 5, 35, 79, 387, 813, 1673, 3187, 337, 5539, 6761, 46903, 122967}},
+{9444, 17, 31634, {1, 1, 7, 11, 1, 15, 125, 175, 255, 35, 145, 2391, 887, 10505, 11587, 53941, 5089}},
+{9445, 17, 31643, {1, 1, 7, 13, 9, 13, 15, 215, 361, 227, 1665, 3345, 3615, 14031, 16281, 4457, 52037}},
+{9446, 17, 31645, {1, 3, 5, 9, 31, 21, 3, 189, 211, 855, 1781, 2097, 1345, 6763, 27651, 54137, 52689}},
+{9447, 17, 31659, {1, 3, 1, 5, 29, 9, 99, 183, 183, 205, 149, 53, 7179, 3387, 9603, 4281, 47145}},
+{9448, 17, 31669, {1, 3, 1, 11, 13, 35, 97, 21, 29, 877, 191, 1621, 2501, 4283, 1707, 48957, 129029}},
+{9449, 17, 31670, {1, 3, 1, 9, 5, 19, 57, 219, 105, 467, 1179, 3155, 7743, 4835, 14845, 35671, 47655}},
+{9450, 17, 31682, {1, 3, 1, 7, 27, 41, 27, 185, 271, 611, 1173, 2875, 529, 11619, 20231, 18741, 41799}},
+{9451, 17, 31694, {1, 3, 7, 13, 9, 3, 35, 71, 467, 689, 1797, 319, 6657, 13193, 15861, 7567, 12891}},
+{9452, 17, 31717, {1, 1, 7, 13, 19, 57, 25, 141, 195, 995, 859, 811, 4685, 6711, 8963, 49657, 54751}},
+{9453, 17, 31718, {1, 1, 1, 11, 27, 25, 9, 91, 97, 251, 757, 2783, 5447, 3617, 26801, 32501, 55245}},
+{9454, 17, 31729, {1, 3, 7, 1, 5, 1, 103, 129, 127, 593, 857, 3957, 3665, 10279, 26211, 2095, 15869}},
+{9455, 17, 31736, {1, 1, 7, 1, 25, 49, 3, 139, 25, 545, 615, 1353, 4103, 1099, 21729, 45383, 110611}},
+{9456, 17, 31742, {1, 3, 5, 3, 7, 49, 83, 41, 209, 357, 939, 849, 5851, 3945, 831, 8131, 105897}},
+{9457, 17, 31749, {1, 1, 1, 3, 27, 19, 123, 71, 195, 1019, 1021, 1287, 5665, 5277, 8647, 27033, 89539}},
+{9458, 17, 31773, {1, 1, 1, 9, 27, 51, 49, 159, 401, 1013, 763, 653, 1449, 12441, 21191, 28871, 106181}},
+{9459, 17, 31777, {1, 1, 5, 7, 31, 7, 105, 137, 331, 367, 1305, 2761, 863, 3915, 12633, 32251, 82867}},
+{9460, 17, 31778, {1, 3, 7, 11, 9, 47, 35, 57, 137, 269, 443, 79, 11, 11817, 28995, 46681, 104263}},
+{9461, 17, 31784, {1, 3, 1, 5, 3, 25, 89, 179, 183, 835, 367, 2215, 295, 5365, 1899, 10785, 88979}},
+{9462, 17, 31801, {1, 3, 7, 13, 3, 5, 93, 43, 409, 363, 267, 2077, 3745, 445, 25957, 34103, 29475}},
+{9463, 17, 31812, {1, 1, 1, 7, 27, 21, 121, 29, 171, 783, 553, 265, 6835, 3929, 18127, 33463, 70999}},
+{9464, 17, 31821, {1, 3, 3, 15, 15, 55, 13, 1, 297, 935, 1307, 1779, 2239, 15471, 32453, 30649, 45973}},
+{9465, 17, 31822, {1, 3, 7, 5, 25, 41, 3, 171, 347, 607, 1873, 1087, 2433, 8377, 7959, 19941, 117319}},
+{9466, 17, 31836, {1, 1, 1, 3, 5, 47, 107, 69, 431, 63, 325, 1241, 3487, 11249, 28559, 30001, 93789}},
+{9467, 17, 31850, {1, 1, 1, 5, 15, 17, 9, 145, 335, 169, 1099, 3637, 5397, 6711, 16095, 27053, 124247}},
+{9468, 17, 31855, {1, 3, 3, 5, 3, 9, 65, 97, 421, 951, 2003, 2837, 7095, 15685, 5147, 56801, 98679}},
+{9469, 17, 31858, {1, 3, 7, 15, 1, 33, 115, 45, 215, 253, 361, 555, 787, 15483, 25531, 53273, 8933}},
+{9470, 17, 31860, {1, 3, 1, 9, 3, 63, 47, 205, 457, 977, 991, 3189, 1369, 14899, 10937, 56999, 11525}},
+{9471, 17, 31886, {1, 1, 7, 5, 11, 61, 53, 55, 231, 357, 1695, 2489, 2355, 7583, 14097, 50039, 96595}},
+{9472, 17, 31891, {1, 3, 7, 7, 3, 57, 115, 245, 259, 573, 1275, 2971, 1793, 13683, 8683, 51815, 26807}},
+{9473, 17, 31909, {1, 1, 5, 3, 17, 59, 55, 237, 491, 757, 1447, 2941, 2641, 14175, 4401, 4367, 36853}},
+{9474, 17, 31928, {1, 3, 1, 15, 3, 63, 67, 1, 403, 79, 1161, 2379, 3337, 14447, 5877, 40759, 12573}},
+{9475, 17, 31931, {1, 1, 7, 15, 17, 1, 91, 5, 173, 215, 1567, 1851, 3309, 9813, 21215, 19151, 96785}},
+{9476, 17, 31934, {1, 1, 1, 9, 31, 45, 123, 221, 397, 51, 1489, 3247, 923, 10423, 10461, 51231, 92909}},
+{9477, 17, 31941, {1, 1, 1, 13, 27, 17, 105, 163, 403, 193, 1487, 2421, 4415, 14303, 6419, 24105, 29997}},
+{9478, 17, 31942, {1, 1, 5, 13, 31, 55, 17, 125, 341, 219, 401, 1611, 891, 12909, 13949, 46245, 26769}},
+{9479, 17, 31945, {1, 3, 7, 3, 31, 41, 65, 207, 311, 643, 1617, 271, 3749, 14635, 26385, 55251, 50719}},
+{9480, 17, 31951, {1, 3, 3, 13, 7, 55, 69, 241, 413, 399, 137, 2255, 5395, 12625, 26583, 64603, 22571}},
+{9481, 17, 31959, {1, 3, 5, 3, 31, 15, 15, 161, 153, 445, 595, 273, 6631, 12845, 23331, 16963, 52099}},
+{9482, 17, 31963, {1, 3, 3, 1, 27, 39, 71, 41, 455, 841, 831, 1719, 3531, 5113, 29183, 1933, 42227}},
+{9483, 17, 31970, {1, 3, 7, 3, 1, 15, 31, 183, 429, 557, 1747, 1059, 2079, 16361, 29103, 43207, 921}},
+{9484, 17, 31984, {1, 3, 1, 1, 31, 39, 97, 73, 339, 405, 1423, 2215, 5435, 9205, 1889, 58249, 61517}},
+{9485, 17, 31987, {1, 3, 7, 1, 23, 59, 127, 245, 11, 627, 1555, 2497, 6427, 7205, 22675, 62847, 69691}},
+{9486, 17, 31990, {1, 1, 3, 5, 1, 13, 95, 9, 167, 481, 947, 3181, 8057, 5559, 7537, 33757, 72419}},
+{9487, 17, 32001, {1, 1, 7, 3, 15, 9, 105, 205, 287, 375, 115, 1731, 1063, 11551, 12077, 41013, 88853}},
+{9488, 17, 32007, {1, 3, 3, 9, 5, 63, 127, 33, 409, 279, 1379, 4069, 4091, 14703, 27435, 19525, 71261}},
+{9489, 17, 32008, {1, 3, 1, 13, 31, 31, 59, 205, 167, 131, 891, 1259, 6909, 211, 31517, 8085, 112065}},
+{9490, 17, 32025, {1, 1, 5, 11, 17, 25, 119, 77, 449, 569, 381, 825, 2459, 983, 2959, 51611, 90721}},
+{9491, 17, 32035, {1, 3, 1, 7, 17, 55, 91, 231, 133, 541, 499, 3609, 4237, 11627, 30007, 58911, 43443}},
+{9492, 17, 32038, {1, 3, 7, 7, 29, 5, 47, 187, 71, 695, 1389, 2855, 5815, 11605, 3643, 24961, 25793}},
+{9493, 17, 32047, {1, 3, 3, 5, 11, 31, 43, 31, 185, 1021, 795, 3585, 3981, 8627, 18117, 42351, 19513}},
+{9494, 17, 32049, {1, 1, 5, 13, 9, 3, 115, 45, 39, 577, 1847, 653, 2625, 9367, 27923, 35661, 113613}},
+{9495, 17, 32062, {1, 3, 7, 7, 17, 9, 69, 233, 367, 673, 11, 2215, 1177, 4501, 9693, 62013, 45647}},
+{9496, 17, 32067, {1, 3, 5, 7, 7, 53, 11, 227, 465, 843, 2017, 689, 6767, 10321, 25163, 56561, 6865}},
+{9497, 17, 32070, {1, 3, 3, 5, 13, 43, 119, 9, 185, 893, 133, 863, 7137, 6653, 7875, 23167, 13893}},
+{9498, 17, 32073, {1, 3, 5, 9, 1, 47, 17, 85, 273, 901, 493, 2411, 983, 15717, 25151, 21323, 57939}},
+{9499, 17, 32074, {1, 1, 7, 5, 19, 17, 49, 37, 425, 443, 781, 2593, 4929, 12313, 12727, 42285, 88451}},
+{9500, 17, 32079, {1, 3, 3, 11, 9, 53, 17, 67, 237, 463, 1509, 2153, 3715, 7909, 21151, 64517, 87695}},
+{9501, 17, 32081, {1, 3, 7, 1, 29, 39, 25, 83, 413, 1005, 2011, 3933, 2911, 7041, 10537, 23135, 22671}},
+{9502, 17, 32082, {1, 1, 3, 9, 23, 61, 117, 33, 431, 181, 1819, 683, 1809, 1723, 27041, 29113, 99347}},
+{9503, 17, 32107, {1, 1, 5, 11, 11, 7, 101, 181, 51, 857, 923, 3495, 7123, 7775, 30081, 48513, 116137}},
+{9504, 17, 32127, {1, 1, 3, 11, 15, 31, 97, 127, 365, 799, 715, 2101, 6081, 11607, 1055, 35027, 62967}},
+{9505, 17, 32145, {1, 3, 5, 7, 3, 31, 109, 247, 225, 221, 1093, 2633, 1847, 7427, 8767, 16581, 32145}},
+{9506, 17, 32151, {1, 3, 1, 7, 15, 23, 43, 109, 327, 417, 1895, 2333, 6265, 6599, 6623, 47375, 92731}},
+{9507, 17, 32152, {1, 3, 7, 1, 29, 29, 45, 217, 163, 941, 1327, 3685, 5481, 15783, 26281, 60339, 34277}},
+{9508, 17, 32173, {1, 1, 7, 11, 1, 7, 119, 201, 29, 193, 1805, 1395, 267, 2011, 637, 26765, 48883}},
+{9509, 17, 32174, {1, 1, 3, 7, 11, 63, 41, 89, 365, 729, 25, 3185, 2143, 1737, 29693, 7443, 78079}},
+{9510, 17, 32186, {1, 3, 1, 13, 25, 27, 63, 233, 79, 1007, 1357, 679, 7581, 8333, 2469, 31787, 128531}},
+{9511, 17, 32194, {1, 3, 1, 3, 23, 39, 53, 99, 219, 475, 931, 507, 3615, 10613, 14663, 1151, 123459}},
+{9512, 17, 32196, {1, 1, 1, 1, 13, 15, 67, 45, 393, 791, 415, 2731, 1151, 8935, 28983, 7239, 106247}},
+{9513, 17, 32200, {1, 3, 7, 7, 11, 35, 95, 153, 421, 193, 1997, 2587, 3183, 9229, 17663, 28221, 6759}},
+{9514, 17, 32208, {1, 3, 1, 7, 5, 5, 123, 55, 509, 973, 261, 463, 2723, 15225, 1925, 62283, 86329}},
+{9515, 17, 32218, {1, 1, 3, 13, 5, 47, 123, 239, 273, 407, 1725, 717, 1229, 1387, 11743, 13739, 104503}},
+{9516, 17, 32236, {1, 3, 3, 13, 23, 35, 43, 113, 299, 847, 1903, 3445, 3395, 641, 11271, 61517, 40747}},
+{9517, 17, 32260, {1, 3, 1, 15, 17, 49, 97, 9, 335, 731, 151, 167, 8129, 11845, 18285, 20113, 122397}},
+{9518, 17, 32263, {1, 1, 5, 11, 11, 63, 3, 153, 345, 511, 1939, 1815, 7231, 10555, 14293, 50753, 14681}},
+{9519, 17, 32288, {1, 3, 7, 5, 21, 31, 127, 223, 241, 783, 887, 3519, 4743, 3541, 4143, 57461, 27791}},
+{9520, 17, 32298, {1, 1, 5, 7, 13, 15, 83, 225, 201, 979, 145, 769, 1491, 12155, 21307, 64877, 113277}},
+{9521, 17, 32315, {1, 1, 7, 1, 27, 25, 105, 69, 239, 323, 1059, 573, 4913, 14215, 27007, 42351, 66315}},
+{9522, 17, 32332, {1, 1, 3, 11, 21, 33, 93, 23, 363, 633, 935, 637, 6171, 12695, 14077, 17505, 69681}},
+{9523, 17, 32340, {1, 3, 1, 5, 15, 11, 93, 211, 175, 377, 33, 1403, 5097, 1503, 8483, 2881, 85877}},
+{9524, 17, 32354, {1, 1, 5, 3, 5, 51, 5, 255, 429, 661, 625, 3015, 4813, 3573, 22917, 45967, 70559}},
+{9525, 17, 32359, {1, 1, 7, 3, 11, 41, 3, 197, 181, 897, 767, 1385, 7395, 15543, 4655, 40309, 73169}},
+{9526, 17, 32366, {1, 1, 5, 9, 15, 35, 71, 119, 509, 817, 1169, 75, 1337, 2959, 611, 38243, 46987}},
+{9527, 17, 32368, {1, 1, 1, 9, 1, 7, 43, 65, 479, 625, 1685, 1309, 5619, 14163, 13633, 18169, 8311}},
+{9528, 17, 32377, {1, 3, 5, 9, 19, 39, 95, 105, 273, 1023, 79, 229, 6895, 2931, 5717, 27911, 22139}},
+{9529, 17, 32384, {1, 3, 5, 7, 1, 55, 15, 15, 297, 731, 2029, 2789, 11, 1333, 26571, 62595, 15131}},
+{9530, 17, 32399, {1, 1, 5, 7, 29, 35, 3, 125, 381, 709, 2047, 2395, 6315, 2301, 7175, 19857, 75085}},
+{9531, 17, 32417, {1, 1, 5, 15, 23, 45, 95, 117, 49, 635, 1525, 1105, 7335, 4653, 18159, 29729, 62627}},
+{9532, 17, 32424, {1, 3, 3, 11, 29, 19, 29, 169, 141, 243, 1765, 1829, 4555, 16299, 3053, 58933, 44605}},
+{9533, 17, 32427, {1, 1, 3, 15, 5, 45, 35, 213, 385, 993, 1521, 9, 3561, 10497, 12601, 38163, 86501}},
+{9534, 17, 32429, {1, 3, 3, 13, 9, 23, 109, 95, 491, 1003, 473, 3325, 6577, 14617, 17765, 33391, 82927}},
+{9535, 17, 32438, {1, 3, 3, 11, 25, 31, 93, 111, 231, 71, 1233, 3581, 6789, 4569, 16741, 61967, 32249}},
+{9536, 17, 32442, {1, 3, 3, 15, 15, 63, 39, 247, 79, 923, 327, 2639, 2013, 12325, 18133, 60623, 2215}},
+{9537, 17, 32447, {1, 3, 5, 1, 5, 49, 121, 53, 283, 529, 37, 3233, 6285, 12447, 4355, 9343, 45631}},
+{9538, 17, 32469, {1, 1, 7, 11, 11, 11, 111, 139, 429, 279, 1019, 2139, 2033, 6809, 8847, 22535, 107005}},
+{9539, 17, 32479, {1, 3, 5, 1, 1, 21, 35, 97, 167, 57, 491, 511, 4065, 11699, 16851, 6847, 40929}},
+{9540, 17, 32483, {1, 3, 1, 15, 3, 55, 113, 33, 255, 537, 835, 1867, 3927, 839, 955, 29079, 93727}},
+{9541, 17, 32498, {1, 1, 7, 3, 5, 7, 35, 111, 165, 885, 115, 3051, 4541, 1701, 22827, 361, 91843}},
+{9542, 17, 32503, {1, 1, 7, 11, 7, 55, 81, 43, 237, 725, 1761, 1599, 639, 14189, 31241, 52827, 107943}},
+{9543, 17, 32507, {1, 3, 1, 3, 29, 35, 67, 119, 369, 877, 1861, 123, 8121, 13861, 31155, 60245, 79799}},
+{9544, 17, 32521, {1, 1, 3, 13, 7, 49, 63, 19, 253, 723, 639, 1677, 291, 13697, 22231, 46893, 90069}},
+{9545, 17, 32532, {1, 3, 5, 1, 7, 57, 29, 233, 35, 715, 515, 3221, 2715, 13839, 18321, 4445, 103843}},
+{9546, 17, 32539, {1, 3, 1, 7, 1, 63, 33, 7, 481, 461, 1923, 2679, 2441, 5449, 13233, 2245, 48667}},
+{9547, 17, 32551, {1, 1, 7, 11, 11, 9, 95, 151, 441, 333, 1871, 1181, 3027, 12887, 11923, 63847, 6953}},
+{9548, 17, 32572, {1, 3, 5, 5, 15, 33, 53, 47, 351, 387, 55, 393, 5475, 3027, 18565, 37997, 120877}},
+{9549, 17, 32577, {1, 3, 5, 9, 23, 43, 67, 97, 445, 783, 1499, 1977, 1441, 10159, 13479, 149, 4939}},
+{9550, 17, 32578, {1, 3, 7, 3, 15, 41, 119, 55, 139, 25, 849, 857, 53, 10421, 2683, 24839, 107797}},
+{9551, 17, 32587, {1, 1, 7, 13, 25, 51, 51, 13, 333, 93, 95, 1755, 3055, 12585, 3519, 44857, 11257}},
+{9552, 17, 32592, {1, 1, 5, 11, 29, 55, 13, 235, 419, 327, 823, 2675, 8031, 9303, 8749, 20215, 12111}},
+{9553, 17, 32602, {1, 1, 3, 5, 7, 31, 103, 19, 467, 255, 583, 419, 2845, 12179, 63, 51693, 9755}},
+{9554, 17, 32604, {1, 1, 1, 13, 15, 29, 109, 81, 381, 659, 601, 3867, 7663, 7307, 16445, 56327, 48559}},
+{9555, 17, 32613, {1, 3, 3, 15, 31, 35, 29, 153, 423, 247, 55, 3259, 6199, 4199, 13931, 14433, 52645}},
+{9556, 17, 32625, {1, 1, 5, 11, 9, 17, 17, 191, 231, 977, 721, 2817, 2485, 4965, 32341, 55131, 4547}},
+{9557, 17, 32631, {1, 1, 7, 7, 7, 7, 89, 69, 299, 503, 597, 311, 1321, 2335, 30193, 45347, 126631}},
+{9558, 17, 32641, {1, 1, 7, 11, 13, 43, 105, 153, 89, 229, 1573, 1549, 3699, 15981, 28911, 45011, 83759}},
+{9559, 17, 32642, {1, 3, 7, 3, 1, 3, 121, 137, 263, 325, 1449, 3793, 5795, 7715, 7449, 26453, 85081}},
+{9560, 17, 32644, {1, 3, 1, 7, 23, 15, 39, 217, 99, 873, 1641, 1411, 4627, 283, 20707, 41795, 62239}},
+{9561, 17, 32656, {1, 3, 5, 9, 15, 15, 35, 255, 501, 945, 79, 799, 2361, 4495, 27825, 27699, 129335}},
+{9562, 17, 32678, {1, 3, 1, 7, 9, 19, 89, 31, 65, 905, 1475, 1353, 7253, 12825, 20723, 47757, 12007}},
+{9563, 17, 32681, {1, 1, 3, 3, 15, 35, 83, 239, 463, 835, 1249, 2521, 3429, 14073, 13569, 6161, 71309}},
+{9564, 17, 32701, {1, 1, 7, 11, 31, 43, 15, 57, 461, 917, 339, 3787, 2925, 1879, 7217, 17091, 108819}},
+{9565, 17, 32713, {1, 3, 7, 3, 17, 51, 29, 105, 221, 941, 1291, 835, 1563, 15623, 2953, 62985, 63037}},
+{9566, 17, 32721, {1, 1, 7, 3, 1, 39, 83, 41, 399, 465, 587, 2011, 137, 6017, 5067, 52389, 71053}},
+{9567, 17, 32727, {1, 1, 7, 11, 17, 55, 103, 239, 173, 181, 1219, 2671, 5183, 3799, 19589, 31247, 68889}},
+{9568, 17, 32731, {1, 1, 3, 3, 21, 43, 123, 253, 281, 627, 353, 3077, 1685, 12143, 19723, 57775, 70761}},
+{9569, 17, 32734, {1, 1, 7, 15, 31, 13, 101, 159, 311, 305, 1783, 3523, 149, 9269, 7103, 40315, 30569}},
+{9570, 17, 32740, {1, 1, 5, 3, 29, 47, 11, 219, 301, 207, 1361, 563, 7831, 14469, 18983, 54535, 64647}},
+{9571, 17, 32773, {1, 1, 3, 15, 11, 37, 85, 237, 225, 1009, 1065, 985, 6849, 5395, 22853, 43965, 51363}},
+{9572, 17, 32774, {1, 3, 3, 1, 11, 61, 45, 131, 201, 609, 757, 2539, 3817, 9309, 24759, 26789, 41437}},
+{9573, 17, 32785, {1, 1, 7, 3, 21, 5, 19, 137, 75, 573, 583, 2499, 41, 3429, 24273, 36711, 110015}},
+{9574, 17, 32788, {1, 3, 7, 9, 1, 51, 39, 75, 115, 269, 1983, 2709, 6989, 6521, 5551, 43675, 1019}},
+{9575, 17, 32792, {1, 1, 3, 9, 27, 1, 125, 7, 67, 821, 275, 1253, 4635, 3557, 4155, 13831, 1523}},
+{9576, 17, 32797, {1, 1, 5, 15, 23, 15, 79, 43, 275, 791, 1867, 2495, 2933, 2167, 22819, 52913, 88871}},
+{9577, 17, 32801, {1, 1, 1, 5, 31, 59, 27, 153, 159, 919, 219, 3373, 3227, 6321, 27559, 33905, 126145}},
+{9578, 17, 32811, {1, 3, 3, 13, 23, 21, 119, 175, 119, 741, 1745, 3985, 3847, 5163, 13699, 32373, 75201}},
+{9579, 17, 32821, {1, 3, 7, 15, 1, 47, 101, 89, 425, 269, 713, 3587, 3373, 13315, 16481, 40031, 50353}},
+{9580, 17, 32828, {1, 3, 7, 3, 19, 29, 5, 69, 385, 979, 1893, 1849, 8007, 14415, 18343, 60555, 109117}},
+{9581, 17, 32839, {1, 1, 3, 13, 5, 35, 111, 239, 489, 395, 1565, 1607, 543, 89, 8971, 22311, 899}},
+{9582, 17, 32854, {1, 1, 7, 7, 11, 51, 105, 211, 341, 85, 991, 1275, 3995, 12611, 2363, 29501, 44217}},
+{9583, 17, 32867, {1, 1, 5, 13, 9, 17, 93, 69, 145, 917, 469, 1109, 7405, 12903, 8341, 50383, 20133}},
+{9584, 17, 32870, {1, 3, 1, 7, 27, 45, 45, 85, 101, 161, 1117, 2757, 7847, 359, 17155, 27073, 123535}},
+{9585, 17, 32873, {1, 3, 1, 3, 9, 11, 67, 205, 109, 257, 1635, 141, 3969, 11571, 211, 48683, 108671}},
+{9586, 17, 32881, {1, 1, 3, 7, 13, 9, 29, 251, 113, 851, 1549, 981, 5553, 6095, 28885, 32953, 112563}},
+{9587, 17, 32891, {1, 1, 5, 7, 11, 5, 13, 83, 343, 499, 587, 3887, 3859, 11459, 7361, 25665, 86151}},
+{9588, 17, 32900, {1, 1, 5, 1, 13, 43, 3, 37, 273, 749, 1707, 2069, 3083, 1095, 3081, 23919, 21939}},
+{9589, 17, 32903, {1, 3, 5, 13, 13, 49, 115, 99, 357, 95, 699, 2615, 1911, 12675, 8607, 12535, 118651}},
+{9590, 17, 32910, {1, 1, 7, 7, 29, 43, 17, 131, 271, 895, 1427, 3659, 1843, 8247, 1175, 48239, 54435}},
+{9591, 17, 32917, {1, 1, 1, 9, 1, 27, 85, 163, 353, 669, 745, 317, 2505, 7685, 14831, 31131, 106687}},
+{9592, 17, 32922, {1, 1, 7, 9, 1, 23, 121, 53, 289, 651, 303, 3049, 6819, 6733, 17485, 20023, 110009}},
+{9593, 17, 32928, {1, 3, 7, 3, 5, 47, 93, 75, 363, 479, 825, 1801, 6807, 3341, 6419, 9889, 5557}},
+{9594, 17, 32945, {1, 1, 3, 15, 23, 5, 7, 25, 73, 811, 1597, 2041, 6707, 6817, 20427, 50749, 46255}},
+{9595, 17, 32946, {1, 3, 7, 9, 1, 11, 61, 63, 435, 977, 1937, 93, 2685, 643, 20113, 25873, 63829}},
+{9596, 17, 32951, {1, 1, 3, 15, 5, 41, 31, 53, 143, 271, 27, 3899, 5045, 1063, 17229, 52715, 67689}},
+{9597, 17, 32958, {1, 1, 3, 11, 1, 57, 121, 13, 291, 861, 1547, 3899, 7949, 15401, 29807, 52307, 104359}},
+{9598, 17, 32965, {1, 3, 5, 15, 23, 3, 95, 43, 377, 437, 1687, 3075, 5131, 11791, 3637, 12621, 105575}},
+{9599, 17, 32978, {1, 3, 1, 3, 27, 1, 117, 11, 153, 401, 1971, 2097, 3227, 14603, 4757, 56281, 112263}},
+{9600, 17, 32980, {1, 3, 3, 5, 13, 25, 51, 209, 367, 327, 1941, 1943, 1347, 14393, 31997, 16001, 129047}},
+{9601, 17, 32983, {1, 1, 5, 11, 19, 51, 109, 229, 71, 923, 1741, 1193, 4657, 6043, 26703, 17757, 75009}},
+{9602, 17, 32987, {1, 1, 7, 3, 23, 3, 125, 165, 137, 999, 1583, 3493, 859, 15603, 7143, 28791, 28201}},
+{9603, 17, 33023, {1, 1, 5, 11, 29, 57, 65, 41, 295, 729, 635, 1871, 6347, 3509, 59, 40765, 42673}},
+{9604, 17, 33031, {1, 3, 3, 3, 15, 59, 53, 97, 15, 131, 891, 1105, 841, 6065, 14427, 4721, 106433}},
+{9605, 17, 33032, {1, 1, 1, 7, 19, 37, 101, 121, 141, 613, 1363, 691, 1731, 12477, 8339, 55669, 99379}},
+{9606, 17, 33035, {1, 3, 5, 13, 17, 49, 75, 25, 447, 113, 1853, 3465, 5225, 4531, 14287, 1039, 17399}},
+{9607, 17, 33038, {1, 3, 5, 3, 3, 49, 101, 79, 117, 939, 1161, 1991, 2343, 7183, 12599, 52877, 94337}},
+{9608, 17, 33040, {1, 3, 1, 1, 19, 47, 73, 195, 475, 435, 1807, 2723, 7885, 15469, 26057, 37325, 57005}},
+{9609, 17, 33043, {1, 1, 1, 11, 17, 7, 111, 143, 357, 977, 719, 553, 4559, 7225, 10405, 26895, 8385}},
+{9610, 17, 33050, {1, 3, 3, 9, 17, 5, 1, 73, 125, 913, 1275, 2387, 5153, 13611, 20585, 8465, 27545}},
+{9611, 17, 33059, {1, 1, 7, 5, 27, 51, 107, 147, 503, 699, 851, 1729, 2875, 16331, 28025, 26451, 92705}},
+{9612, 17, 33080, {1, 1, 5, 9, 3, 37, 21, 139, 13, 427, 225, 1345, 2491, 15495, 25847, 3095, 128879}},
+{9613, 17, 33098, {1, 1, 3, 11, 7, 47, 113, 133, 99, 871, 1151, 1953, 7931, 6389, 28715, 36861, 60017}},
+{9614, 17, 33108, {1, 1, 7, 1, 21, 47, 35, 83, 137, 945, 2047, 3491, 3719, 3001, 20563, 51243, 14491}},
+{9615, 17, 33115, {1, 1, 5, 15, 1, 13, 85, 61, 479, 853, 813, 805, 4931, 12651, 22757, 29531, 92861}},
+{9616, 17, 33117, {1, 3, 7, 7, 27, 63, 31, 169, 43, 185, 637, 729, 7231, 2381, 23539, 53885, 90215}},
+{9617, 17, 33133, {1, 1, 3, 13, 5, 51, 69, 111, 357, 277, 1889, 3809, 8031, 13341, 14261, 34001, 63317}},
+{9618, 17, 33134, {1, 1, 7, 3, 11, 59, 1, 43, 227, 503, 1407, 3917, 7077, 847, 4513, 53007, 66721}},
+{9619, 17, 33157, {1, 1, 5, 11, 15, 25, 109, 169, 25, 391, 597, 2997, 2377, 9045, 15239, 25291, 5451}},
+{9620, 17, 33169, {1, 3, 3, 11, 15, 11, 1, 59, 347, 707, 239, 2473, 8057, 4787, 32247, 17955, 79151}},
+{9621, 17, 33170, {1, 3, 7, 11, 9, 59, 9, 117, 137, 713, 451, 1105, 4485, 14979, 26271, 46017, 89211}},
+{9622, 17, 33176, {1, 3, 3, 3, 3, 19, 95, 131, 413, 291, 1179, 3265, 7107, 10419, 13527, 19905, 8059}},
+{9623, 17, 33182, {1, 3, 7, 9, 29, 43, 19, 243, 443, 27, 1401, 3469, 6925, 2833, 19715, 39667, 11983}},
+{9624, 17, 33192, {1, 3, 3, 7, 23, 33, 115, 59, 29, 61, 1085, 1115, 4007, 12673, 26479, 22397, 95609}},
+{9625, 17, 33205, {1, 3, 3, 5, 1, 47, 43, 83, 21, 621, 59, 1, 891, 12285, 31855, 48641, 52479}},
+{9626, 17, 33212, {1, 3, 3, 5, 3, 9, 17, 181, 15, 315, 1705, 2461, 1853, 14007, 17665, 40593, 126179}},
+{9627, 17, 33215, {1, 3, 5, 3, 3, 23, 83, 163, 29, 293, 1891, 2631, 2989, 7295, 2441, 21689, 8187}},
+{9628, 17, 33217, {1, 3, 1, 1, 1, 23, 53, 215, 185, 843, 1083, 2603, 3857, 4981, 25079, 20249, 93717}},
+{9629, 17, 33227, {1, 3, 5, 11, 7, 61, 127, 13, 449, 395, 1909, 3967, 2441, 3073, 8159, 33979, 26345}},
+{9630, 17, 33229, {1, 1, 5, 1, 15, 5, 93, 87, 319, 173, 1729, 1395, 1019, 5139, 10819, 29877, 81025}},
+{9631, 17, 33238, {1, 3, 3, 7, 17, 55, 61, 227, 299, 245, 849, 211, 895, 2999, 18215, 37069, 32821}},
+{9632, 17, 33241, {1, 1, 5, 3, 17, 49, 115, 55, 447, 533, 1463, 2983, 3245, 9345, 11955, 49145, 128035}},
+{9633, 17, 33260, {1, 3, 1, 7, 5, 17, 61, 71, 101, 529, 1761, 827, 7887, 5713, 31039, 18087, 82277}},
+{9634, 17, 33271, {1, 3, 1, 11, 27, 59, 1, 231, 303, 431, 1279, 3647, 1333, 3675, 29401, 55533, 65997}},
+{9635, 17, 33278, {1, 1, 5, 9, 7, 9, 111, 245, 269, 919, 1147, 1601, 6219, 4931, 3035, 12231, 4011}},
+{9636, 17, 33293, {1, 3, 5, 15, 3, 19, 83, 25, 129, 979, 79, 3027, 3983, 7703, 16859, 12085, 83115}},
+{9637, 17, 33294, {1, 1, 5, 11, 31, 41, 99, 3, 383, 943, 1579, 2435, 1209, 161, 31733, 11755, 95697}},
+{9638, 17, 33296, {1, 1, 1, 9, 9, 55, 115, 187, 499, 165, 1081, 813, 2545, 8065, 10501, 15475, 85107}},
+{9639, 17, 33302, {1, 1, 1, 3, 1, 31, 81, 213, 301, 575, 605, 543, 3347, 12759, 21645, 37173, 36127}},
+{9640, 17, 33305, {1, 3, 3, 9, 21, 29, 51, 91, 307, 617, 1839, 443, 1013, 4473, 3885, 57669, 123271}},
+{9641, 17, 33329, {1, 3, 1, 15, 31, 43, 83, 187, 51, 513, 1505, 3895, 3557, 9527, 27537, 6173, 99595}},
+{9642, 17, 33330, {1, 3, 3, 1, 3, 53, 113, 27, 431, 505, 219, 2143, 6691, 3219, 9589, 9885, 24037}},
+{9643, 17, 33332, {1, 1, 5, 9, 13, 3, 53, 145, 49, 411, 691, 289, 6443, 4963, 13815, 23663, 95497}},
+{9644, 17, 33354, {1, 3, 5, 9, 19, 7, 53, 101, 199, 69, 1821, 3233, 3267, 5947, 4869, 30095, 21255}},
+{9645, 17, 33383, {1, 1, 5, 11, 29, 7, 79, 11, 451, 585, 987, 2333, 1891, 1853, 14739, 34399, 62895}},
+{9646, 17, 33387, {1, 3, 1, 7, 29, 43, 103, 219, 139, 359, 1663, 3453, 7469, 1943, 11457, 19227, 62211}},
+{9647, 17, 33397, {1, 3, 3, 11, 9, 47, 17, 237, 87, 881, 583, 3473, 2579, 975, 1531, 50997, 76219}},
+{9648, 17, 33408, {1, 1, 7, 15, 31, 37, 79, 115, 95, 515, 2003, 2595, 4077, 4537, 9171, 31183, 41219}},
+{9649, 17, 33417, {1, 1, 1, 9, 21, 41, 93, 33, 211, 341, 233, 2217, 6657, 12913, 8329, 3881, 42563}},
+{9650, 17, 33420, {1, 3, 3, 11, 25, 3, 23, 197, 49, 339, 877, 1117, 7817, 14143, 1575, 50301, 92367}},
+{9651, 17, 33423, {1, 3, 5, 5, 19, 45, 69, 179, 447, 861, 1633, 1941, 5821, 1843, 4085, 23501, 109047}},
+{9652, 17, 33431, {1, 3, 1, 3, 31, 29, 49, 183, 311, 133, 345, 1541, 111, 5571, 1943, 11039, 127673}},
+{9653, 17, 33438, {1, 3, 1, 5, 3, 13, 63, 5, 59, 789, 71, 3271, 3871, 9105, 22525, 31, 117803}},
+{9654, 17, 33442, {1, 3, 1, 13, 31, 43, 97, 133, 313, 729, 287, 2971, 5623, 13183, 15179, 47271, 28853}},
+{9655, 17, 33444, {1, 1, 3, 13, 27, 15, 35, 37, 507, 139, 1933, 2847, 361, 10261, 21031, 3889, 56875}},
+{9656, 17, 33448, {1, 3, 1, 15, 31, 13, 45, 73, 279, 331, 471, 3881, 3295, 12035, 28329, 899, 47397}},
+{9657, 17, 33456, {1, 1, 3, 13, 1, 7, 81, 255, 315, 595, 43, 3919, 5229, 7953, 25711, 19509, 107181}},
+{9658, 17, 33459, {1, 1, 3, 15, 7, 33, 117, 169, 71, 577, 629, 3665, 7761, 13529, 26375, 17181, 22125}},
+{9659, 17, 33466, {1, 3, 5, 7, 5, 7, 1, 93, 489, 289, 329, 2273, 685, 14835, 11433, 26041, 112735}},
+{9660, 17, 33473, {1, 3, 3, 3, 9, 39, 45, 23, 171, 35, 571, 551, 7815, 6169, 24283, 61477, 71877}},
+{9661, 17, 33476, {1, 1, 5, 7, 23, 15, 81, 215, 297, 269, 655, 2059, 3643, 12741, 11955, 41085, 46047}},
+{9662, 17, 33491, {1, 1, 7, 5, 3, 35, 125, 141, 419, 137, 1031, 2053, 7925, 7267, 6267, 34323, 77495}},
+{9663, 17, 33494, {1, 1, 7, 11, 3, 57, 91, 43, 139, 691, 1569, 1825, 7855, 1093, 19263, 31601, 16019}},
+{9664, 17, 33507, {1, 3, 1, 5, 21, 7, 11, 225, 105, 757, 1493, 455, 4757, 12007, 5139, 3545, 79717}},
+{9665, 17, 33514, {1, 3, 1, 13, 17, 29, 125, 249, 475, 79, 1271, 341, 863, 853, 2105, 32897, 121261}},
+{9666, 17, 33521, {1, 3, 1, 11, 17, 59, 3, 29, 61, 399, 1465, 4029, 2103, 12481, 28495, 34363, 63781}},
+{9667, 17, 33528, {1, 3, 3, 15, 29, 13, 101, 191, 435, 215, 1355, 2263, 6059, 4545, 7535, 15041, 84091}},
+{9668, 17, 33534, {1, 1, 3, 9, 29, 23, 99, 55, 91, 145, 235, 2847, 725, 209, 24565, 16545, 103669}},
+{9669, 17, 33536, {1, 1, 1, 1, 31, 15, 93, 197, 207, 357, 667, 3511, 3865, 5329, 6491, 9027, 125979}},
+{9670, 17, 33551, {1, 3, 3, 13, 17, 35, 99, 187, 153, 589, 1633, 4053, 1023, 9541, 9841, 39585, 24885}},
+{9671, 17, 33554, {1, 3, 7, 11, 23, 5, 71, 89, 455, 665, 1221, 1821, 591, 11459, 503, 56777, 65691}},
+{9672, 17, 33563, {1, 3, 1, 1, 9, 33, 51, 203, 223, 709, 1263, 3535, 7753, 8279, 8673, 60259, 2671}},
+{9673, 17, 33575, {1, 1, 7, 9, 17, 63, 5, 229, 495, 435, 1711, 3359, 399, 15901, 28519, 56627, 8079}},
+{9674, 17, 33579, {1, 3, 5, 11, 9, 25, 49, 143, 275, 989, 461, 447, 1917, 9253, 28421, 1803, 119725}},
+{9675, 17, 33582, {1, 3, 3, 7, 25, 3, 39, 171, 303, 905, 1353, 2561, 7347, 7339, 15271, 61945, 26343}},
+{9676, 17, 33601, {1, 1, 1, 3, 5, 63, 9, 229, 107, 815, 1705, 3621, 2345, 3065, 16315, 17017, 33667}},
+{9677, 17, 33602, {1, 3, 5, 13, 29, 13, 91, 111, 475, 561, 443, 3825, 5331, 11211, 27639, 28305, 101831}},
+{9678, 17, 33614, {1, 3, 1, 9, 15, 33, 17, 47, 249, 89, 429, 3819, 1959, 14317, 10737, 28151, 40395}},
+{9679, 17, 33625, {1, 3, 7, 13, 19, 29, 83, 81, 511, 783, 823, 2865, 5823, 9459, 27413, 63297, 44181}},
+{9680, 17, 33628, {1, 3, 1, 1, 19, 53, 45, 227, 193, 631, 289, 1227, 6241, 6915, 16051, 31237, 50201}},
+{9681, 17, 33637, {1, 3, 7, 7, 15, 49, 77, 147, 421, 515, 927, 1561, 4391, 12943, 6807, 36889, 70249}},
+{9682, 17, 33656, {1, 3, 7, 7, 17, 15, 63, 123, 101, 283, 59, 977, 5185, 16161, 5007, 36255, 11537}},
+{9683, 17, 33665, {1, 1, 7, 1, 13, 17, 79, 35, 193, 947, 767, 1365, 2145, 13267, 30561, 51949, 37591}},
+{9684, 17, 33683, {1, 1, 1, 13, 11, 13, 91, 129, 355, 549, 295, 673, 209, 15953, 14703, 30857, 47967}},
+{9685, 17, 33695, {1, 3, 5, 9, 17, 17, 83, 161, 189, 585, 21, 1019, 4879, 15943, 17281, 46013, 94839}},
+{9686, 17, 33696, {1, 3, 5, 9, 23, 39, 65, 25, 181, 3, 2005, 635, 201, 9391, 8755, 38535, 88697}},
+{9687, 17, 33702, {1, 3, 1, 15, 13, 35, 47, 125, 429, 901, 895, 3495, 327, 397, 7847, 62157, 3489}},
+{9688, 17, 33708, {1, 3, 5, 3, 19, 21, 81, 39, 85, 169, 1981, 3323, 113, 2057, 16617, 58051, 55059}},
+{9689, 17, 33711, {1, 3, 1, 13, 9, 1, 101, 81, 129, 717, 1495, 4077, 5555, 93, 12957, 14805, 110219}},
+{9690, 17, 33716, {1, 3, 5, 5, 5, 47, 107, 111, 387, 987, 2009, 179, 1111, 3443, 25579, 12293, 123035}},
+{9691, 17, 33728, {1, 1, 7, 13, 21, 25, 33, 211, 9, 783, 1785, 2691, 6835, 2867, 22469, 17853, 90685}},
+{9692, 17, 33737, {1, 1, 3, 3, 19, 57, 59, 203, 197, 347, 553, 1361, 7593, 91, 15303, 30045, 86605}},
+{9693, 17, 33761, {1, 3, 5, 7, 29, 23, 1, 235, 159, 277, 1227, 1727, 1853, 9717, 2377, 13597, 18119}},
+{9694, 17, 33774, {1, 1, 1, 11, 15, 29, 5, 15, 349, 685, 197, 3127, 1075, 8847, 27873, 539, 57149}},
+{9695, 17, 33782, {1, 1, 7, 9, 23, 25, 121, 239, 219, 747, 1981, 2683, 5319, 75, 22569, 29697, 27627}},
+{9696, 17, 33788, {1, 3, 7, 5, 31, 43, 95, 131, 423, 547, 1437, 127, 1953, 861, 839, 54503, 20465}},
+{9697, 17, 33791, {1, 1, 5, 3, 29, 29, 71, 237, 275, 493, 513, 4067, 393, 9415, 20511, 29257, 86267}},
+{9698, 17, 33793, {1, 1, 1, 1, 25, 11, 59, 185, 211, 175, 37, 2999, 4919, 10225, 16727, 60447, 59985}},
+{9699, 17, 33811, {1, 1, 3, 3, 1, 9, 69, 195, 197, 677, 229, 599, 5613, 4537, 5495, 58801, 14297}},
+{9700, 17, 33813, {1, 3, 1, 15, 17, 23, 5, 101, 331, 943, 1433, 2199, 313, 469, 3651, 3281, 100119}},
+{9701, 17, 33818, {1, 1, 5, 15, 13, 25, 87, 45, 229, 821, 59, 761, 6259, 15159, 3197, 39763, 87301}},
+{9702, 17, 33829, {1, 3, 5, 7, 19, 21, 89, 15, 19, 623, 603, 4069, 3531, 13353, 21267, 6355, 53821}},
+{9703, 17, 33842, {1, 1, 5, 9, 13, 13, 111, 77, 439, 599, 1577, 959, 4567, 3117, 7127, 49265, 35667}},
+{9704, 17, 33854, {1, 3, 7, 9, 27, 61, 1, 19, 43, 475, 221, 655, 4351, 15827, 30489, 22245, 41077}},
+{9705, 17, 33856, {1, 1, 3, 13, 17, 17, 111, 85, 253, 11, 367, 2349, 4103, 12517, 27037, 42481, 84451}},
+{9706, 17, 33868, {1, 3, 5, 7, 7, 25, 53, 27, 429, 503, 893, 2923, 2539, 15849, 30157, 12111, 108893}},
+{9707, 17, 33879, {1, 1, 7, 9, 13, 29, 51, 113, 273, 745, 759, 263, 3031, 705, 23203, 64245, 127183}},
+{9708, 17, 33885, {1, 1, 1, 9, 29, 5, 25, 165, 261, 319, 645, 2199, 3135, 10263, 10711, 18713, 63337}},
+{9709, 17, 33886, {1, 1, 5, 1, 23, 41, 43, 71, 365, 683, 1107, 1671, 7079, 8933, 12815, 8095, 97955}},
+{9710, 17, 33892, {1, 3, 1, 15, 9, 43, 105, 217, 131, 299, 1459, 1087, 3493, 15297, 11741, 43383, 35021}},
+{9711, 17, 33907, {1, 3, 1, 3, 3, 57, 69, 7, 73, 977, 1163, 3591, 243, 13129, 23247, 20609, 22489}},
+{9712, 17, 33913, {1, 3, 7, 5, 1, 57, 65, 27, 121, 575, 903, 3527, 5601, 5597, 1941, 60079, 88121}},
+{9713, 17, 33923, {1, 3, 1, 3, 15, 3, 23, 87, 233, 389, 1671, 1557, 4825, 1017, 17697, 26735, 53421}},
+{9714, 17, 33925, {1, 3, 5, 3, 5, 43, 61, 249, 273, 251, 1383, 2415, 1061, 12363, 3071, 23785, 127909}},
+{9715, 17, 33935, {1, 3, 3, 13, 5, 63, 15, 165, 353, 603, 1627, 2037, 487, 11603, 719, 54693, 52645}},
+{9716, 17, 33937, {1, 3, 5, 11, 31, 41, 41, 83, 481, 251, 1903, 2655, 5237, 6073, 20201, 14069, 91649}},
+{9717, 17, 33954, {1, 3, 1, 15, 21, 41, 99, 61, 55, 63, 1595, 1805, 7625, 12261, 23275, 43471, 5147}},
+{9718, 17, 33963, {1, 3, 1, 5, 23, 21, 71, 169, 197, 51, 1653, 3053, 4663, 293, 12751, 15641, 83993}},
+{9719, 17, 33966, {1, 3, 5, 15, 29, 45, 55, 199, 275, 103, 1093, 3569, 5997, 9445, 2291, 30973, 68589}},
+{9720, 17, 33977, {1, 3, 5, 7, 15, 3, 15, 3, 287, 961, 1759, 1153, 7613, 9885, 8981, 5109, 112865}},
+{9721, 17, 33978, {1, 1, 1, 9, 1, 37, 111, 61, 309, 581, 875, 2121, 1035, 4345, 1351, 59743, 34955}},
+{9722, 17, 33991, {1, 3, 7, 7, 11, 23, 51, 235, 23, 697, 991, 1995, 3615, 6665, 15885, 18555, 11711}},
+{9723, 17, 33998, {1, 3, 7, 13, 3, 59, 87, 129, 405, 689, 1189, 2071, 877, 12347, 18381, 28367, 27247}},
+{9724, 17, 34012, {1, 1, 1, 9, 23, 29, 113, 71, 479, 421, 215, 1029, 6125, 13575, 10823, 45303, 3153}},
+{9725, 17, 34016, {1, 1, 3, 11, 13, 5, 31, 29, 279, 597, 791, 319, 1391, 14487, 3811, 36913, 11513}},
+{9726, 17, 34025, {1, 3, 7, 11, 9, 11, 55, 167, 69, 519, 1887, 145, 6133, 1307, 14465, 17419, 18319}},
+{9727, 17, 34033, {1, 1, 3, 1, 29, 25, 57, 75, 19, 187, 1591, 421, 959, 7499, 8377, 42811, 53423}},
+{9728, 17, 34036, {1, 3, 1, 3, 7, 9, 73, 217, 383, 755, 1561, 3923, 3891, 16129, 13195, 62097, 67493}},
+{9729, 17, 34045, {1, 3, 7, 9, 5, 7, 47, 29, 319, 243, 405, 2867, 5803, 2273, 4913, 54777, 88301}},
+{9730, 17, 34065, {1, 3, 7, 1, 25, 11, 51, 183, 387, 863, 39, 2119, 2395, 10175, 20833, 3235, 108197}},
+{9731, 17, 34078, {1, 1, 7, 13, 25, 43, 21, 67, 103, 709, 603, 1045, 7079, 8867, 29039, 61499, 39533}},
+{9732, 17, 34093, {1, 1, 7, 5, 7, 55, 77, 115, 409, 287, 1149, 1535, 7459, 5525, 27129, 43659, 86953}},
+{9733, 17, 34101, {1, 3, 5, 3, 21, 41, 47, 147, 267, 473, 1501, 2663, 5381, 41, 18265, 53845, 16039}},
+{9734, 17, 34108, {1, 1, 7, 15, 27, 63, 95, 103, 169, 1, 133, 3103, 7539, 5765, 11453, 4133, 95133}},
+{9735, 17, 34111, {1, 3, 3, 15, 3, 53, 121, 135, 385, 475, 889, 2557, 4937, 11129, 18461, 16757, 30339}},
+{9736, 17, 34120, {1, 3, 1, 13, 11, 39, 111, 13, 475, 201, 1973, 2151, 6973, 4083, 12593, 44093, 108037}},
+{9737, 17, 34123, {1, 3, 7, 9, 31, 31, 97, 235, 179, 689, 403, 1995, 7697, 7511, 29333, 11005, 50723}},
+{9738, 17, 34125, {1, 1, 7, 13, 23, 5, 7, 171, 441, 921, 1455, 3865, 7089, 5469, 10423, 53013, 80559}},
+{9739, 17, 34153, {1, 3, 5, 3, 25, 43, 105, 157, 507, 143, 297, 1111, 2761, 14103, 4965, 36733, 11741}},
+{9740, 17, 34171, {1, 3, 7, 9, 29, 61, 49, 239, 271, 697, 211, 1633, 2991, 14933, 12347, 44291, 12219}},
+{9741, 17, 34174, {1, 1, 7, 7, 17, 61, 29, 43, 87, 633, 937, 1931, 3541, 12259, 23045, 5923, 48479}},
+{9742, 17, 34178, {1, 3, 3, 3, 15, 25, 105, 17, 159, 863, 1377, 331, 1475, 10573, 28947, 8141, 26671}},
+{9743, 17, 34183, {1, 1, 7, 7, 31, 59, 81, 23, 467, 241, 1257, 1337, 7731, 9071, 3417, 51191, 78369}},
+{9744, 17, 34190, {1, 1, 5, 9, 11, 45, 49, 227, 319, 63, 1339, 885, 4571, 11649, 5607, 10509, 55055}},
+{9745, 17, 34201, {1, 3, 3, 9, 29, 17, 7, 235, 191, 927, 575, 1115, 4111, 14179, 2041, 13331, 29825}},
+{9746, 17, 34211, {1, 1, 5, 9, 27, 61, 71, 201, 341, 577, 221, 1371, 1135, 4347, 24211, 36171, 23435}},
+{9747, 17, 34220, {1, 3, 3, 1, 1, 29, 75, 121, 193, 647, 1429, 275, 5243, 783, 28533, 13941, 68035}},
+{9748, 17, 34225, {1, 3, 5, 15, 21, 27, 117, 183, 251, 991, 935, 3119, 5133, 2765, 7423, 28867, 120565}},
+{9749, 17, 34237, {1, 3, 5, 5, 13, 23, 29, 101, 299, 699, 1249, 1225, 1335, 6079, 17825, 60467, 87787}},
+{9750, 17, 34249, {1, 1, 1, 9, 15, 19, 11, 163, 433, 553, 1487, 813, 3293, 1195, 895, 28431, 62905}},
+{9751, 17, 34250, {1, 1, 1, 13, 25, 37, 111, 129, 391, 813, 1061, 4065, 7339, 10731, 23799, 41463, 99673}},
+{9752, 17, 34264, {1, 1, 7, 15, 3, 21, 45, 77, 471, 155, 967, 711, 4947, 13983, 27827, 28653, 117839}},
+{9753, 17, 34269, {1, 1, 5, 9, 13, 39, 107, 237, 233, 881, 297, 2189, 8085, 1221, 18659, 299, 90951}},
+{9754, 17, 34276, {1, 1, 1, 13, 21, 53, 83, 17, 487, 215, 1203, 3017, 7887, 3759, 10521, 31223, 87917}},
+{9755, 17, 34279, {1, 1, 7, 1, 13, 31, 123, 219, 127, 743, 1325, 3907, 129, 8901, 4855, 22509, 47331}},
+{9756, 17, 34293, {1, 1, 7, 11, 29, 37, 11, 157, 401, 35, 2037, 2873, 7409, 7837, 1247, 33911, 3979}},
+{9757, 17, 34303, {1, 1, 5, 15, 1, 13, 35, 253, 287, 1007, 1417, 1613, 6019, 11617, 6323, 56263, 45073}},
+{9758, 17, 34310, {1, 3, 1, 15, 1, 59, 41, 239, 373, 443, 897, 275, 5783, 8619, 18559, 16279, 92063}},
+{9759, 17, 34340, {1, 3, 1, 9, 23, 33, 83, 43, 231, 819, 1657, 1031, 5507, 12621, 8961, 23059, 63453}},
+{9760, 17, 34349, {1, 1, 7, 5, 29, 49, 21, 251, 267, 43, 729, 4013, 1497, 15489, 16761, 49689, 122755}},
+{9761, 17, 34352, {1, 3, 7, 1, 31, 21, 11, 149, 127, 711, 1249, 49, 5503, 677, 12313, 61301, 16279}},
+{9762, 17, 34355, {1, 1, 5, 11, 9, 15, 41, 61, 81, 991, 1387, 3567, 221, 15835, 8609, 28265, 98199}},
+{9763, 17, 34358, {1, 3, 1, 7, 21, 35, 13, 59, 173, 637, 107, 393, 4551, 6523, 27389, 33129, 45579}},
+{9764, 17, 34362, {1, 1, 1, 9, 29, 51, 65, 199, 417, 553, 1321, 2513, 4749, 8477, 19721, 24301, 16301}},
+{9765, 17, 34376, {1, 3, 5, 1, 25, 13, 7, 55, 163, 581, 1677, 2313, 6843, 15697, 3055, 53171, 59899}},
+{9766, 17, 34381, {1, 3, 1, 5, 31, 13, 101, 195, 235, 359, 911, 1017, 2575, 12801, 997, 7819, 73243}},
+{9767, 17, 34387, {1, 1, 7, 1, 9, 39, 59, 83, 57, 885, 317, 2689, 5741, 11833, 25563, 62581, 62239}},
+{9768, 17, 34389, {1, 1, 5, 15, 25, 25, 55, 207, 223, 907, 913, 387, 5599, 15567, 8859, 13703, 66071}},
+{9769, 17, 34394, {1, 1, 5, 15, 19, 39, 83, 177, 333, 531, 1257, 2687, 7793, 15967, 19175, 1381, 106629}},
+{9770, 17, 34410, {1, 3, 5, 13, 29, 29, 77, 1, 273, 483, 725, 3825, 5115, 4043, 11571, 8693, 49761}},
+{9771, 17, 34423, {1, 1, 7, 3, 5, 45, 37, 65, 267, 191, 301, 2863, 167, 9303, 14563, 41553, 119561}},
+{9772, 17, 34434, {1, 1, 7, 5, 21, 41, 107, 213, 267, 427, 699, 1485, 2125, 16011, 29243, 4691, 50545}},
+{9773, 17, 34436, {1, 3, 3, 9, 15, 29, 81, 53, 289, 689, 933, 2667, 5175, 10409, 28221, 56375, 49109}},
+{9774, 17, 34448, {1, 1, 1, 15, 3, 11, 77, 107, 353, 349, 219, 1961, 7559, 10081, 25119, 46041, 103827}},
+{9775, 17, 34453, {1, 3, 3, 1, 5, 27, 109, 17, 271, 543, 565, 397, 2649, 12037, 4525, 37835, 107071}},
+{9776, 17, 34454, {1, 1, 5, 15, 3, 37, 123, 157, 389, 619, 1379, 4093, 6107, 4419, 21011, 36189, 21269}},
+{9777, 17, 34460, {1, 3, 1, 7, 25, 17, 37, 133, 247, 113, 985, 815, 441, 7869, 25121, 49459, 429}},
+{9778, 17, 34464, {1, 3, 3, 11, 7, 23, 59, 51, 403, 685, 2019, 1167, 7973, 6915, 10819, 43807, 127793}},
+{9779, 17, 34479, {1, 1, 3, 1, 29, 3, 125, 107, 305, 101, 391, 2733, 6883, 5867, 5139, 16025, 112439}},
+{9780, 17, 34491, {1, 1, 5, 5, 23, 23, 89, 33, 275, 451, 1033, 649, 3761, 4735, 26021, 9627, 102747}},
+{9781, 17, 34501, {1, 1, 5, 13, 3, 17, 117, 251, 425, 917, 759, 3047, 8171, 14421, 27765, 11085, 64889}},
+{9782, 17, 34508, {1, 3, 1, 9, 7, 23, 107, 143, 123, 413, 2045, 655, 6283, 8783, 20263, 55463, 33271}},
+{9783, 17, 34516, {1, 3, 7, 11, 5, 49, 73, 55, 465, 43, 587, 3943, 521, 12357, 16273, 26603, 23219}},
+{9784, 17, 34529, {1, 3, 5, 13, 9, 3, 127, 171, 271, 227, 993, 1427, 2235, 6325, 13501, 1411, 44393}},
+{9785, 17, 34530, {1, 1, 1, 3, 13, 27, 19, 37, 175, 423, 5, 3403, 5427, 16345, 30297, 11909, 104647}},
+{9786, 17, 34553, {1, 3, 1, 3, 3, 39, 111, 179, 487, 923, 1945, 1609, 4689, 11807, 13725, 3081, 48163}},
+{9787, 17, 34564, {1, 3, 1, 1, 9, 35, 7, 151, 109, 925, 1249, 3171, 1207, 2053, 5135, 34821, 57291}},
+{9788, 17, 34568, {1, 1, 5, 13, 31, 35, 101, 199, 499, 725, 1229, 2857, 6437, 503, 14437, 35721, 24971}},
+{9789, 17, 34571, {1, 1, 1, 15, 3, 49, 75, 101, 373, 119, 875, 245, 15, 12937, 4731, 13037, 1555}},
+{9790, 17, 34582, {1, 1, 1, 7, 15, 5, 53, 5, 423, 69, 73, 2139, 383, 4035, 6723, 59941, 124503}},
+{9791, 17, 34586, {1, 1, 3, 13, 1, 23, 29, 47, 145, 785, 1013, 1579, 4579, 107, 17571, 46311, 27777}},
+{9792, 17, 34598, {1, 1, 1, 5, 23, 25, 97, 75, 105, 183, 827, 3871, 2005, 6453, 28729, 42583, 62979}},
+{9793, 17, 34604, {1, 3, 5, 9, 11, 49, 29, 201, 333, 441, 429, 1955, 5301, 11775, 22915, 58693, 111917}},
+{9794, 17, 34610, {1, 3, 3, 1, 15, 37, 117, 223, 319, 181, 61, 177, 507, 14871, 16419, 34261, 106937}},
+{9795, 17, 34619, {1, 3, 3, 9, 25, 27, 81, 253, 459, 5, 693, 1271, 485, 16171, 427, 17917, 4393}},
+{9796, 17, 34621, {1, 3, 3, 1, 27, 47, 11, 57, 269, 95, 569, 2733, 3275, 1599, 15073, 58071, 86805}},
+{9797, 17, 34633, {1, 3, 7, 13, 21, 57, 75, 63, 53, 487, 251, 3193, 4279, 2311, 6613, 38319, 93557}},
+{9798, 17, 34634, {1, 3, 5, 5, 31, 35, 39, 255, 11, 81, 605, 1457, 6367, 14121, 8069, 46653, 79945}},
+{9799, 17, 34657, {1, 1, 1, 7, 17, 19, 19, 247, 13, 757, 1069, 2811, 4969, 10943, 29399, 4153, 120817}},
+{9800, 17, 34682, {1, 1, 1, 15, 31, 13, 1, 247, 157, 785, 1565, 897, 4825, 8375, 4933, 60671, 88403}},
+{9801, 17, 34688, {1, 3, 3, 7, 31, 53, 117, 207, 243, 603, 625, 1039, 5725, 5021, 20227, 28613, 123759}},
+{9802, 17, 34691, {1, 1, 5, 1, 7, 29, 65, 153, 393, 821, 295, 2705, 5999, 15801, 31301, 15545, 52917}},
+{9803, 17, 34694, {1, 1, 1, 1, 11, 51, 97, 143, 27, 279, 1005, 1235, 5539, 1523, 26293, 35015, 47835}},
+{9804, 17, 34706, {1, 3, 3, 13, 27, 17, 123, 147, 39, 35, 567, 961, 5431, 5557, 17849, 46675, 102181}},
+{9805, 17, 34708, {1, 1, 7, 11, 7, 25, 73, 223, 459, 207, 1637, 647, 2057, 685, 24539, 48809, 26877}},
+{9806, 17, 34724, {1, 3, 1, 3, 21, 43, 121, 11, 431, 383, 1703, 1451, 2349, 11845, 13801, 20589, 43125}},
+{9807, 17, 34727, {1, 1, 5, 1, 27, 29, 89, 233, 437, 303, 853, 3425, 263, 2073, 14111, 39129, 59547}},
+{9808, 17, 34751, {1, 1, 1, 3, 3, 47, 99, 207, 261, 179, 1761, 2657, 4339, 6567, 25455, 18729, 51431}},
+{9809, 17, 34753, {1, 3, 3, 13, 5, 5, 109, 125, 123, 233, 1713, 1539, 4375, 12187, 18355, 49597, 109959}},
+{9810, 17, 34759, {1, 3, 7, 7, 9, 23, 45, 193, 363, 837, 855, 1413, 7587, 9091, 27907, 17809, 63249}},
+{9811, 17, 34763, {1, 3, 3, 9, 19, 23, 63, 85, 419, 1007, 1753, 539, 1471, 2171, 9239, 36289, 105503}},
+{9812, 17, 34777, {1, 3, 1, 11, 23, 5, 105, 79, 473, 879, 1623, 3155, 5157, 4699, 697, 41919, 15441}},
+{9813, 17, 34778, {1, 1, 7, 11, 5, 21, 43, 207, 491, 355, 857, 2325, 819, 15849, 24529, 5789, 110661}},
+{9814, 17, 34780, {1, 1, 5, 15, 19, 33, 81, 137, 473, 853, 1681, 3841, 5617, 13715, 1987, 52983, 66327}},
+{9815, 17, 34796, {1, 3, 5, 7, 11, 31, 69, 85, 33, 197, 1771, 1957, 1311, 169, 14159, 7327, 8577}},
+{9816, 17, 34799, {1, 1, 3, 9, 11, 23, 19, 143, 9, 579, 111, 2973, 3567, 8561, 10447, 55875, 64305}},
+{9817, 17, 34801, {1, 1, 5, 7, 1, 17, 93, 11, 423, 1007, 839, 719, 3965, 14531, 17301, 29577, 4083}},
+{9818, 17, 34817, {1, 3, 5, 13, 19, 17, 123, 61, 59, 115, 1165, 579, 2545, 633, 5597, 21865, 109167}},
+{9819, 17, 34824, {1, 1, 5, 3, 29, 29, 99, 163, 321, 367, 1523, 3719, 665, 15843, 28831, 63823, 113533}},
+{9820, 17, 34827, {1, 1, 1, 3, 15, 7, 85, 1, 181, 759, 537, 3315, 7159, 4363, 4183, 53775, 8801}},
+{9821, 17, 34837, {1, 3, 1, 1, 15, 53, 9, 35, 459, 417, 1169, 2055, 1175, 10923, 335, 24269, 93001}},
+{9822, 17, 34841, {1, 3, 1, 5, 31, 43, 51, 149, 175, 541, 629, 1147, 7585, 9725, 18623, 13345, 65391}},
+{9823, 17, 34853, {1, 3, 7, 1, 13, 39, 13, 217, 507, 765, 721, 1491, 5037, 6267, 2871, 19181, 123751}},
+{9824, 17, 34858, {1, 1, 3, 5, 21, 9, 123, 195, 63, 347, 7, 531, 3015, 9457, 29543, 51479, 26607}},
+{9825, 17, 34877, {1, 1, 1, 1, 21, 15, 81, 127, 429, 15, 901, 1503, 1919, 6515, 2477, 53571, 113447}},
+{9826, 17, 34886, {1, 3, 1, 13, 9, 33, 79, 169, 499, 767, 441, 2085, 2429, 10213, 4125, 2611, 26137}},
+{9827, 17, 34895, {1, 1, 3, 1, 19, 23, 83, 179, 447, 513, 913, 1201, 1861, 11595, 29037, 7775, 116417}},
+{9828, 17, 34897, {1, 3, 3, 7, 3, 57, 47, 183, 413, 319, 1375, 1401, 2231, 14331, 28625, 43839, 102717}},
+{9829, 17, 34898, {1, 1, 5, 11, 31, 27, 111, 85, 191, 155, 2025, 1501, 4991, 4655, 3451, 10219, 60391}},
+{9830, 17, 34916, {1, 3, 3, 7, 17, 19, 113, 37, 423, 479, 709, 3659, 6567, 1709, 13483, 61821, 77101}},
+{9831, 17, 34923, {1, 3, 1, 13, 3, 17, 73, 61, 275, 359, 1341, 449, 1373, 12047, 11207, 52651, 83305}},
+{9832, 17, 34928, {1, 1, 7, 9, 9, 45, 15, 121, 15, 51, 509, 2189, 5057, 6119, 11669, 14559, 108323}},
+{9833, 17, 34934, {1, 1, 7, 7, 25, 13, 13, 141, 157, 249, 823, 821, 1909, 5925, 3505, 13187, 19237}},
+{9834, 17, 34940, {1, 3, 3, 1, 9, 51, 79, 91, 5, 709, 787, 2427, 4613, 7307, 20141, 1675, 49779}},
+{9835, 17, 34944, {1, 1, 1, 11, 11, 13, 33, 81, 413, 981, 907, 2709, 4113, 10607, 2587, 12845, 11103}},
+{9836, 17, 34947, {1, 1, 7, 9, 13, 25, 37, 81, 375, 1013, 2027, 321, 3947, 2269, 10687, 7537, 67495}},
+{9837, 17, 34953, {1, 3, 5, 11, 9, 43, 53, 111, 339, 841, 503, 3209, 6437, 10893, 13627, 51809, 57229}},
+{9838, 17, 34956, {1, 3, 1, 1, 21, 15, 71, 93, 453, 405, 1099, 2979, 7471, 10173, 17875, 13179, 48615}},
+{9839, 17, 34967, {1, 3, 5, 9, 9, 1, 121, 117, 275, 157, 57, 3459, 4787, 15005, 24591, 23963, 45077}},
+{9840, 17, 34968, {1, 1, 5, 3, 21, 57, 113, 207, 169, 603, 637, 1455, 6281, 6527, 17219, 32307, 18617}},
+{9841, 17, 34971, {1, 3, 7, 5, 25, 15, 99, 91, 253, 267, 537, 713, 3929, 895, 7999, 47989, 118731}},
+{9842, 17, 34974, {1, 3, 7, 15, 23, 17, 5, 129, 121, 251, 219, 2547, 7291, 1079, 14577, 56229, 35253}},
+{9843, 17, 34977, {1, 3, 1, 15, 5, 61, 35, 135, 497, 681, 751, 2303, 6697, 11225, 30389, 61673, 87313}},
+{9844, 17, 34980, {1, 3, 1, 7, 7, 37, 9, 85, 257, 805, 1325, 3597, 6065, 727, 18203, 57077, 437}},
+{9845, 17, 34983, {1, 3, 5, 7, 5, 43, 29, 179, 73, 173, 1441, 1233, 1779, 7893, 10629, 27547, 7775}},
+{9846, 17, 34998, {1, 1, 7, 5, 31, 29, 21, 35, 289, 423, 449, 3331, 2929, 6827, 15569, 9873, 76889}},
+{9847, 17, 35004, {1, 1, 7, 13, 13, 37, 55, 99, 135, 797, 1263, 2539, 893, 4225, 16689, 38259, 50857}},
+{9848, 17, 35010, {1, 1, 3, 1, 5, 3, 95, 29, 15, 539, 825, 3931, 4809, 8299, 29891, 61357, 97523}},
+{9849, 17, 35012, {1, 3, 1, 9, 27, 25, 115, 239, 387, 163, 1153, 31, 2375, 7943, 31929, 1121, 33085}},
+{9850, 17, 35030, {1, 3, 5, 9, 3, 53, 121, 159, 165, 81, 317, 3051, 1991, 493, 2029, 43305, 130209}},
+{9851, 17, 35039, {1, 1, 1, 5, 9, 57, 39, 247, 73, 613, 1047, 3289, 2569, 5363, 18475, 32749, 39415}},
+{9852, 17, 35058, {1, 3, 1, 5, 19, 23, 39, 33, 151, 463, 153, 737, 2501, 7531, 2769, 35595, 71799}},
+{9853, 17, 35063, {1, 3, 5, 5, 29, 49, 105, 81, 67, 441, 1101, 2241, 6243, 6177, 7157, 51635, 81241}},
+{9854, 17, 35082, {1, 3, 3, 3, 29, 53, 13, 239, 487, 503, 97, 1323, 1817, 13021, 12881, 26943, 21011}},
+{9855, 17, 35095, {1, 1, 1, 15, 25, 9, 5, 205, 85, 635, 789, 2495, 5069, 4987, 847, 26857, 84225}},
+{9856, 17, 35096, {1, 1, 3, 15, 9, 51, 79, 13, 377, 637, 159, 3407, 2057, 13967, 31781, 40869, 52987}},
+{9857, 17, 35101, {1, 3, 1, 13, 11, 27, 103, 207, 383, 887, 749, 1119, 285, 4269, 31745, 57539, 5671}},
+{9858, 17, 35102, {1, 3, 1, 13, 23, 19, 41, 43, 455, 425, 1653, 4091, 4855, 16321, 169, 59289, 82397}},
+{9859, 17, 35105, {1, 3, 3, 15, 31, 39, 51, 127, 391, 989, 1831, 3327, 6487, 6077, 17277, 52093, 20389}},
+{9860, 17, 35112, {1, 3, 5, 15, 19, 1, 21, 241, 15, 543, 1529, 2355, 1503, 12795, 17321, 41219, 61115}},
+{9861, 17, 35118, {1, 1, 3, 11, 9, 33, 21, 197, 307, 141, 1663, 371, 1663, 8307, 3617, 56941, 62477}},
+{9862, 17, 35120, {1, 3, 7, 9, 19, 53, 123, 3, 29, 635, 1795, 2471, 2491, 15847, 9169, 2561, 101515}},
+{9863, 17, 35130, {1, 1, 5, 3, 19, 11, 117, 231, 475, 837, 1833, 3499, 4415, 9961, 28285, 37821, 81497}},
+{9864, 17, 35143, {1, 1, 3, 5, 7, 11, 57, 89, 345, 157, 1519, 3021, 7157, 2159, 32557, 31559, 128907}},
+{9865, 17, 35147, {1, 1, 7, 3, 27, 1, 15, 177, 489, 405, 811, 3597, 4939, 15595, 7279, 58097, 84703}},
+{9866, 17, 35152, {1, 3, 1, 9, 25, 61, 119, 219, 111, 339, 1091, 759, 6087, 16001, 6757, 15627, 1691}},
+{9867, 17, 35157, {1, 3, 7, 9, 1, 39, 107, 139, 143, 917, 421, 1623, 7135, 4851, 6687, 6177, 102425}},
+{9868, 17, 35164, {1, 1, 7, 13, 23, 17, 19, 167, 317, 331, 743, 3737, 2195, 545, 2185, 9125, 30503}},
+{9869, 17, 35178, {1, 1, 5, 13, 27, 33, 117, 141, 493, 129, 1553, 2335, 4161, 14205, 24177, 35163, 84869}},
+{9870, 17, 35195, {1, 3, 7, 1, 11, 9, 75, 133, 113, 507, 2007, 2473, 4769, 14655, 17967, 17709, 90653}},
+{9871, 17, 35197, {1, 1, 7, 11, 17, 11, 83, 23, 387, 61, 29, 3905, 4351, 15173, 28375, 9129, 111939}},
+{9872, 17, 35201, {1, 1, 5, 15, 15, 53, 81, 125, 189, 937, 1607, 2595, 2847, 7229, 22241, 26269, 64781}},
+{9873, 17, 35207, {1, 3, 1, 7, 5, 11, 61, 111, 13, 423, 885, 2329, 6003, 16331, 11207, 25743, 54619}},
+{9874, 17, 35231, {1, 3, 5, 9, 1, 13, 95, 241, 237, 629, 263, 1629, 1063, 12695, 14501, 5455, 121483}},
+{9875, 17, 35249, {1, 1, 7, 15, 5, 17, 45, 255, 143, 79, 87, 1755, 6215, 5095, 32411, 8695, 85511}},
+{9876, 17, 35250, {1, 3, 7, 7, 21, 11, 117, 135, 333, 73, 1471, 2749, 5801, 4209, 9353, 46171, 90645}},
+{9877, 17, 35256, {1, 1, 7, 13, 11, 35, 77, 149, 159, 783, 1527, 2881, 1409, 3455, 26991, 3225, 30693}},
+{9878, 17, 35259, {1, 1, 3, 15, 19, 55, 21, 245, 207, 103, 775, 2041, 4637, 7333, 11267, 60509, 43099}},
+{9879, 17, 35262, {1, 3, 3, 15, 17, 63, 23, 81, 183, 923, 75, 391, 615, 13343, 20839, 56529, 115747}},
+{9880, 17, 35273, {1, 3, 1, 13, 5, 5, 15, 27, 263, 497, 1365, 2733, 5395, 7461, 2725, 24735, 89251}},
+{9881, 17, 35282, {1, 1, 7, 7, 29, 17, 39, 117, 363, 915, 123, 283, 4575, 3497, 20995, 37883, 16645}},
+{9882, 17, 35298, {1, 3, 3, 9, 1, 25, 79, 181, 331, 617, 393, 1807, 5145, 8007, 9173, 45189, 37945}},
+{9883, 17, 35307, {1, 3, 1, 5, 1, 9, 127, 137, 379, 371, 367, 3237, 581, 15295, 18191, 37689, 103495}},
+{9884, 17, 35328, {1, 1, 7, 1, 29, 53, 103, 173, 171, 973, 933, 3847, 3185, 10107, 31701, 45021, 106251}},
+{9885, 17, 35334, {1, 1, 1, 7, 23, 9, 61, 25, 343, 471, 2041, 2179, 7647, 1885, 15353, 50379, 67681}},
+{9886, 17, 35343, {1, 1, 5, 11, 31, 13, 51, 185, 83, 917, 85, 1317, 8185, 14949, 32455, 57939, 1217}},
+{9887, 17, 35345, {1, 1, 7, 5, 23, 45, 101, 227, 497, 941, 985, 167, 6847, 9611, 20011, 40069, 83285}},
+{9888, 17, 35355, {1, 1, 5, 13, 17, 33, 61, 197, 433, 255, 67, 1479, 5663, 6501, 30695, 27235, 80141}},
+{9889, 17, 35388, {1, 1, 3, 5, 11, 45, 123, 49, 327, 893, 1963, 2225, 2611, 8925, 22811, 2313, 8411}},
+{9890, 17, 35399, {1, 3, 7, 7, 15, 39, 75, 235, 13, 847, 575, 3947, 6947, 2061, 13467, 103, 86285}},
+{9891, 17, 35403, {1, 1, 7, 3, 21, 43, 113, 197, 141, 873, 1139, 2707, 7235, 10683, 10831, 33695, 57063}},
+{9892, 17, 35408, {1, 3, 5, 1, 3, 27, 45, 43, 119, 979, 1933, 1851, 6497, 14937, 4965, 41285, 120221}},
+{9893, 17, 35413, {1, 1, 3, 1, 23, 59, 67, 7, 49, 351, 1053, 1837, 501, 7671, 26239, 51951, 95119}},
+{9894, 17, 35418, {1, 3, 5, 11, 3, 19, 33, 33, 219, 175, 1439, 197, 1841, 159, 11229, 20463, 81797}},
+{9895, 17, 35434, {1, 1, 7, 1, 13, 11, 79, 75, 53, 525, 91, 233, 5999, 2921, 21295, 56831, 116049}},
+{9896, 17, 35436, {1, 3, 3, 13, 29, 7, 71, 207, 193, 635, 1393, 3093, 3775, 12445, 23281, 29401, 103225}},
+{9897, 17, 35448, {1, 1, 7, 3, 29, 57, 111, 163, 63, 593, 881, 1587, 3027, 12599, 30977, 38891, 95495}},
+{9898, 17, 35460, {1, 1, 5, 15, 17, 57, 111, 169, 149, 767, 377, 765, 7533, 1539, 22979, 55489, 29799}},
+{9899, 17, 35475, {1, 3, 5, 15, 25, 7, 127, 71, 319, 389, 497, 1513, 1287, 7359, 12311, 45457, 45897}},
+{9900, 17, 35494, {1, 1, 5, 3, 3, 35, 45, 17, 49, 483, 197, 727, 5355, 7201, 3035, 14313, 40933}},
+{9901, 17, 35497, {1, 1, 7, 15, 1, 9, 27, 59, 455, 653, 1907, 281, 1435, 14593, 18909, 37655, 87603}},
+{9902, 17, 35503, {1, 1, 7, 11, 29, 9, 67, 17, 353, 709, 859, 3687, 7741, 4251, 12263, 41717, 79393}},
+{9903, 17, 35508, {1, 3, 3, 3, 1, 15, 113, 187, 255, 851, 503, 4089, 7923, 1701, 305, 8353, 16357}},
+{9904, 17, 35511, {1, 1, 5, 3, 17, 31, 29, 233, 377, 215, 1889, 3459, 2443, 3907, 4193, 16519, 49089}},
+{9905, 17, 35518, {1, 1, 3, 1, 17, 39, 11, 255, 247, 305, 669, 1769, 1355, 12055, 2275, 51681, 112337}},
+{9906, 17, 35520, {1, 3, 1, 1, 17, 17, 75, 95, 409, 21, 1513, 1443, 4931, 6491, 1587, 62979, 90395}},
+{9907, 17, 35530, {1, 1, 3, 5, 3, 19, 125, 175, 279, 911, 301, 407, 7773, 949, 32107, 13571, 58717}},
+{9908, 17, 35537, {1, 3, 3, 15, 31, 35, 11, 223, 125, 209, 1719, 1725, 3387, 14879, 32243, 7219, 126791}},
+{9909, 17, 35543, {1, 1, 3, 1, 31, 29, 67, 79, 93, 193, 1573, 2285, 3209, 8397, 17717, 5657, 61545}},
+{9910, 17, 35560, {1, 3, 1, 9, 11, 33, 85, 121, 193, 63, 461, 1835, 889, 10687, 19831, 49551, 59087}},
+{9911, 17, 35566, {1, 3, 3, 7, 11, 3, 9, 87, 91, 487, 289, 1113, 8135, 7971, 16693, 31009, 81197}},
+{9912, 17, 35571, {1, 3, 3, 1, 23, 23, 61, 209, 409, 845, 547, 1493, 465, 6399, 17633, 53647, 52425}},
+{9913, 17, 35598, {1, 1, 7, 7, 21, 31, 71, 249, 63, 895, 653, 93, 4429, 8951, 16873, 48089, 33947}},
+{9914, 17, 35609, {1, 3, 5, 11, 3, 35, 49, 15, 379, 645, 855, 3657, 8019, 2141, 11233, 60731, 80455}},
+{9915, 17, 35612, {1, 3, 1, 3, 1, 53, 101, 157, 255, 765, 1575, 1615, 7677, 9699, 13351, 2207, 90939}},
+{9916, 17, 35615, {1, 3, 7, 7, 5, 43, 123, 109, 119, 391, 1889, 1991, 3151, 1457, 16321, 65245, 75891}},
+{9917, 17, 35616, {1, 3, 1, 15, 9, 1, 113, 249, 1, 675, 501, 487, 2209, 4411, 6609, 29243, 100177}},
+{9918, 17, 35622, {1, 1, 1, 7, 9, 23, 9, 197, 341, 191, 453, 3733, 5475, 15515, 28979, 36077, 17801}},
+{9919, 17, 35626, {1, 1, 3, 13, 5, 35, 85, 121, 59, 429, 1251, 3437, 3121, 12411, 14713, 28125, 31921}},
+{9920, 17, 35633, {1, 3, 5, 3, 27, 17, 61, 255, 485, 709, 83, 3201, 2191, 3371, 2941, 10931, 22141}},
+{9921, 17, 35636, {1, 1, 1, 1, 19, 19, 25, 177, 397, 579, 529, 1619, 3887, 4537, 8123, 52481, 8305}},
+{9922, 17, 35645, {1, 1, 3, 15, 3, 15, 77, 51, 31, 881, 203, 2359, 4947, 6321, 14705, 16471, 84395}},
+{9923, 17, 35653, {1, 3, 7, 9, 13, 53, 67, 41, 289, 721, 1743, 2725, 435, 1327, 14953, 14283, 113211}},
+{9924, 17, 35663, {1, 3, 1, 5, 19, 23, 73, 181, 187, 675, 125, 1877, 6167, 7919, 3955, 25007, 28299}},
+{9925, 17, 35665, {1, 1, 3, 1, 5, 11, 123, 189, 173, 123, 499, 2175, 483, 13017, 14709, 5797, 36327}},
+{9926, 17, 35682, {1, 3, 7, 5, 21, 39, 79, 229, 19, 203, 375, 3901, 1053, 14209, 13535, 63155, 99727}},
+{9927, 17, 35687, {1, 1, 1, 13, 11, 29, 29, 173, 441, 271, 1147, 2891, 965, 10777, 16325, 37135, 101601}},
+{9928, 17, 35688, {1, 1, 3, 3, 25, 13, 79, 233, 75, 191, 987, 3231, 3667, 1525, 14193, 62027, 77441}},
+{9929, 17, 35691, {1, 3, 1, 1, 15, 53, 17, 45, 367, 263, 425, 1565, 6139, 13833, 12547, 61103, 75361}},
+{9930, 17, 35696, {1, 1, 5, 15, 5, 57, 123, 47, 407, 887, 375, 1181, 5367, 10283, 24799, 33121, 76373}},
+{9931, 17, 35727, {1, 1, 7, 3, 11, 17, 65, 133, 3, 609, 601, 3391, 7801, 4137, 32095, 55983, 23037}},
+{9932, 17, 35741, {1, 3, 1, 3, 25, 5, 125, 5, 297, 571, 145, 3601, 1929, 13457, 16977, 21049, 92169}},
+{9933, 17, 35742, {1, 3, 5, 13, 23, 29, 13, 143, 507, 187, 857, 427, 5125, 1377, 10947, 58473, 110541}},
+{9934, 17, 35746, {1, 3, 3, 15, 15, 49, 39, 103, 193, 507, 639, 2399, 3829, 12105, 15993, 52975, 115935}},
+{9935, 17, 35748, {1, 3, 7, 3, 7, 41, 95, 127, 193, 923, 1729, 3039, 7959, 3345, 7725, 35293, 34361}},
+{9936, 17, 35752, {1, 3, 5, 13, 17, 53, 111, 141, 151, 389, 1955, 3333, 4523, 6331, 21239, 57447, 113325}},
+{9937, 17, 35770, {1, 3, 7, 15, 31, 7, 11, 35, 105, 607, 1665, 3281, 487, 9417, 26205, 26963, 81537}},
+{9938, 17, 35811, {1, 3, 1, 1, 17, 15, 3, 55, 451, 691, 1525, 2009, 6443, 4629, 15091, 46961, 83361}},
+{9939, 17, 35817, {1, 3, 1, 15, 1, 29, 99, 79, 225, 665, 623, 2389, 3303, 7221, 20567, 15917, 24677}},
+{9940, 17, 35832, {1, 1, 3, 15, 3, 17, 125, 239, 485, 849, 327, 1459, 3911, 2145, 14475, 24337, 19695}},
+{9941, 17, 35838, {1, 3, 5, 7, 7, 37, 19, 51, 373, 587, 147, 563, 7623, 7781, 18289, 37239, 6803}},
+{9942, 17, 35850, {1, 3, 5, 1, 9, 63, 5, 87, 171, 5, 1553, 429, 5001, 7881, 1493, 20425, 57727}},
+{9943, 17, 35863, {1, 3, 5, 9, 25, 43, 17, 71, 87, 869, 1219, 2661, 4571, 9689, 18799, 62467, 128531}},
+{9944, 17, 35870, {1, 1, 3, 3, 19, 53, 61, 9, 55, 433, 1555, 2369, 1423, 9081, 19185, 8513, 111079}},
+{9945, 17, 35879, {1, 3, 5, 15, 11, 61, 1, 147, 17, 71, 1563, 1113, 4809, 16229, 23743, 59757, 64699}},
+{9946, 17, 35880, {1, 1, 5, 11, 29, 23, 61, 43, 203, 97, 1119, 237, 6445, 14507, 9799, 18447, 14745}},
+{9947, 17, 35891, {1, 3, 5, 15, 11, 17, 117, 139, 117, 537, 251, 149, 2731, 15863, 1381, 25435, 25501}},
+{9948, 17, 35893, {1, 3, 3, 15, 31, 57, 53, 43, 95, 445, 1423, 3833, 2485, 11789, 16011, 8101, 39165}},
+{9949, 17, 35903, {1, 1, 3, 11, 15, 37, 117, 3, 245, 57, 593, 2771, 7181, 11397, 5691, 3217, 44139}},
+{9950, 17, 35905, {1, 3, 5, 1, 11, 13, 121, 85, 85, 511, 1837, 611, 237, 4893, 24025, 28903, 102025}},
+{9951, 17, 35926, {1, 3, 1, 11, 5, 45, 43, 45, 393, 741, 1157, 1511, 1665, 2359, 19071, 24537, 122879}},
+{9952, 17, 35930, {1, 3, 3, 3, 9, 59, 27, 11, 257, 203, 1535, 2729, 2313, 3539, 1689, 31901, 42949}},
+{9953, 17, 35941, {1, 1, 1, 11, 17, 7, 21, 35, 479, 697, 107, 1317, 6585, 705, 3789, 20439, 33375}},
+{9954, 17, 35956, {1, 1, 3, 11, 19, 37, 123, 233, 253, 733, 901, 3047, 3595, 2357, 24533, 40519, 109171}},
+{9955, 17, 35963, {1, 3, 3, 13, 29, 51, 25, 149, 57, 253, 2001, 351, 7367, 15361, 4955, 60951, 19449}},
+{9956, 17, 35970, {1, 1, 3, 15, 21, 53, 25, 239, 257, 437, 711, 3599, 5441, 7405, 15039, 19207, 63841}},
+{9957, 17, 35984, {1, 3, 1, 9, 17, 41, 43, 231, 413, 747, 1447, 1407, 2615, 14529, 10781, 20001, 82713}},
+{9958, 17, 35996, {1, 3, 7, 7, 9, 29, 25, 55, 53, 423, 1711, 2871, 2675, 421, 31703, 57099, 2955}},
+{9959, 17, 36005, {1, 3, 1, 7, 31, 17, 113, 83, 387, 611, 1815, 2137, 3453, 4409, 20377, 60263, 81205}},
+{9960, 17, 36012, {1, 1, 5, 3, 11, 1, 7, 225, 367, 267, 95, 939, 3801, 2619, 1207, 62695, 116407}},
+{9961, 17, 36015, {1, 3, 3, 9, 5, 39, 85, 45, 247, 483, 491, 865, 3493, 8243, 8411, 26449, 50473}},
+{9962, 17, 36030, {1, 3, 3, 9, 1, 53, 23, 127, 13, 529, 1925, 2629, 3451, 15073, 16075, 29909, 34101}},
+{9963, 17, 36035, {1, 3, 1, 11, 1, 9, 125, 57, 79, 633, 979, 3843, 325, 883, 7769, 40155, 104057}},
+{9964, 17, 36042, {1, 1, 7, 13, 23, 53, 27, 157, 493, 901, 1077, 1079, 1327, 15903, 20603, 64377, 103335}},
+{9965, 17, 36047, {1, 3, 3, 3, 3, 35, 37, 167, 73, 301, 385, 1045, 6913, 2269, 22491, 19735, 70125}},
+{9966, 17, 36049, {1, 1, 1, 11, 5, 23, 23, 85, 267, 845, 207, 77, 1245, 16209, 25579, 12417, 48723}},
+{9967, 17, 36059, {1, 1, 5, 15, 11, 17, 43, 83, 373, 1005, 541, 115, 163, 2165, 8181, 35839, 44471}},
+{9968, 17, 36071, {1, 3, 5, 7, 27, 41, 101, 13, 213, 235, 2037, 2179, 2121, 4481, 8127, 20011, 3981}},
+{9969, 17, 36080, {1, 1, 5, 11, 7, 43, 59, 129, 127, 387, 489, 1985, 623, 13307, 19765, 62155, 93271}},
+{9970, 17, 36085, {1, 1, 7, 5, 23, 63, 23, 177, 211, 233, 101, 1809, 7411, 8003, 25101, 32601, 75071}},
+{9971, 17, 36097, {1, 1, 1, 11, 3, 25, 9, 91, 459, 611, 867, 3639, 5457, 9101, 15333, 40069, 67723}},
+{9972, 17, 36110, {1, 3, 7, 5, 3, 29, 111, 75, 459, 195, 1405, 2281, 6085, 4425, 29061, 57335, 87449}},
+{9973, 17, 36115, {1, 3, 7, 11, 21, 45, 53, 81, 77, 863, 1901, 3355, 5253, 10897, 26289, 48399, 26877}},
+{9974, 17, 36118, {1, 3, 3, 13, 21, 37, 69, 87, 259, 101, 1203, 167, 6229, 145, 9355, 15347, 68047}},
+{9975, 17, 36124, {1, 1, 3, 1, 31, 1, 15, 229, 429, 915, 929, 381, 1857, 8441, 22207, 47071, 127853}},
+{9976, 17, 36137, {1, 3, 7, 3, 15, 9, 13, 161, 173, 573, 405, 3253, 7331, 13965, 3061, 40687, 130185}},
+{9977, 17, 36138, {1, 3, 5, 5, 29, 29, 9, 115, 393, 377, 909, 321, 2861, 9881, 17863, 52033, 55133}},
+{9978, 17, 36155, {1, 1, 7, 7, 27, 53, 101, 213, 199, 301, 1995, 2549, 5037, 13639, 18423, 23547, 79359}},
+{9979, 17, 36160, {1, 3, 1, 7, 21, 51, 29, 151, 301, 665, 571, 53, 2637, 7229, 12517, 33647, 49413}},
+{9980, 17, 36189, {1, 3, 3, 13, 13, 49, 49, 131, 325, 273, 1127, 2981, 2365, 14287, 23185, 26915, 81755}},
+{9981, 17, 36190, {1, 1, 5, 3, 17, 45, 25, 79, 37, 265, 1205, 1805, 6707, 11525, 16473, 39525, 9571}},
+{9982, 17, 36203, {1, 3, 3, 15, 9, 43, 55, 101, 469, 939, 365, 3443, 5759, 4751, 28893, 46727, 74569}},
+{9983, 17, 36211, {1, 3, 7, 9, 5, 33, 11, 201, 263, 227, 1475, 2795, 1489, 11129, 18053, 31009, 73105}},
+{9984, 17, 36218, {1, 3, 5, 5, 5, 25, 41, 151, 393, 237, 2017, 3811, 953, 13835, 28761, 22439, 76355}},
+{9985, 17, 36230, {1, 1, 5, 13, 21, 37, 29, 11, 289, 67, 1317, 511, 685, 15227, 8731, 15039, 79491}},
+{9986, 17, 36241, {1, 3, 1, 9, 31, 59, 123, 169, 473, 139, 575, 1057, 3213, 8213, 21845, 28123, 105335}},
+{9987, 17, 36244, {1, 1, 1, 5, 21, 47, 23, 121, 403, 5, 1457, 2137, 569, 9267, 6367, 6991, 3113}},
+{9988, 17, 36253, {1, 3, 3, 7, 13, 7, 25, 215, 81, 1003, 2041, 1317, 3913, 14705, 30551, 50889, 83441}},
+{9989, 17, 36257, {1, 3, 3, 3, 13, 17, 63, 229, 83, 901, 953, 2603, 4685, 6961, 7519, 52441, 33223}},
+{9990, 17, 36264, {1, 3, 7, 5, 7, 57, 65, 73, 243, 531, 261, 2517, 4083, 5889, 22913, 49603, 67135}},
+{9991, 17, 36272, {1, 3, 5, 11, 15, 47, 81, 83, 35, 1021, 1313, 1109, 5103, 5469, 18149, 15307, 34939}},
+{9992, 17, 36290, {1, 3, 7, 5, 21, 13, 105, 157, 435, 23, 931, 3565, 1, 4987, 8829, 7327, 51049}},
+{9993, 17, 36292, {1, 1, 3, 11, 29, 9, 59, 49, 261, 1009, 1953, 2683, 8125, 10937, 16683, 36013, 5967}},
+{9994, 17, 36301, {1, 1, 1, 1, 19, 29, 57, 9, 307, 457, 675, 3023, 495, 15257, 7945, 10449, 30155}},
+{9995, 17, 36309, {1, 1, 7, 13, 25, 9, 51, 135, 491, 205, 1715, 3253, 1031, 4137, 14885, 39925, 6061}},
+{9996, 17, 36313, {1, 1, 7, 7, 3, 13, 111, 91, 469, 133, 1221, 1035, 919, 3697, 26387, 41675, 487}},
+{9997, 17, 36316, {1, 1, 3, 1, 19, 53, 11, 113, 245, 747, 189, 4051, 87, 1767, 3595, 10259, 100097}},
+{9998, 17, 36319, {1, 1, 5, 3, 23, 49, 31, 47, 341, 1019, 723, 2353, 6191, 3809, 3297, 39443, 73529}},
+{9999, 17, 36330, {1, 3, 3, 9, 25, 27, 123, 49, 51, 85, 1063, 2633, 6549, 14493, 7367, 3557, 60651}},
+{10000, 17, 36335, {1, 3, 7, 5, 13, 27, 127, 65, 115, 731, 1147, 283, 91, 14205, 2457, 57083, 35815}},
+{10001, 17, 36347, {1, 3, 3, 3, 25, 63, 99, 249, 25, 951, 733, 3621, 7139, 14223, 23641, 20287, 30743}},
+{10002, 17, 36353, {1, 3, 3, 7, 21, 23, 83, 207, 235, 467, 1857, 2661, 1391, 10097, 12297, 54825, 5035}},
+{10003, 17, 36356, {1, 1, 5, 3, 31, 17, 77, 9, 215, 553, 989, 3643, 729, 2057, 32053, 50305, 5499}},
+{10004, 17, 36368, {1, 1, 7, 1, 23, 5, 111, 195, 431, 947, 403, 1781, 943, 15073, 67, 52225, 98987}},
+{10005, 17, 36374, {1, 1, 5, 11, 23, 1, 41, 33, 457, 767, 275, 801, 5119, 3781, 14805, 52789, 41775}},
+{10006, 17, 36377, {1, 1, 5, 3, 9, 53, 15, 183, 281, 691, 165, 3277, 7673, 1509, 16605, 53799, 100185}},
+{10007, 17, 36384, {1, 3, 5, 11, 19, 45, 29, 159, 167, 67, 1259, 879, 7787, 8855, 24153, 42667, 102855}},
+{10008, 17, 36407, {1, 1, 7, 13, 31, 19, 43, 133, 295, 287, 1985, 2451, 2297, 3853, 22401, 27659, 11149}},
+{10009, 17, 36413, {1, 1, 7, 13, 31, 39, 125, 21, 173, 103, 1119, 3739, 6467, 2113, 4465, 26537, 129949}},
+{10010, 17, 36419, {1, 1, 5, 15, 21, 47, 35, 125, 199, 335, 421, 31, 185, 12769, 30659, 33427, 106981}},
+{10011, 17, 36425, {1, 3, 5, 13, 25, 35, 53, 253, 325, 921, 1705, 2735, 6437, 2287, 20479, 61107, 91453}},
+{10012, 17, 36426, {1, 3, 7, 13, 25, 63, 83, 183, 5, 401, 329, 525, 3141, 393, 30469, 16529, 9605}},
+{10013, 17, 36446, {1, 3, 3, 13, 19, 23, 15, 85, 323, 545, 149, 3645, 6269, 15595, 18453, 39, 128169}},
+{10014, 17, 36461, {1, 3, 7, 15, 17, 5, 61, 61, 91, 353, 1039, 2959, 4147, 13205, 12599, 53281, 39509}},
+{10015, 17, 36467, {1, 1, 3, 7, 21, 9, 97, 111, 249, 775, 845, 1789, 667, 489, 6689, 29217, 56527}},
+{10016, 17, 36474, {1, 3, 5, 7, 11, 5, 59, 219, 29, 803, 923, 3861, 7953, 8969, 1819, 43501, 20513}},
+{10017, 17, 36480, {1, 1, 5, 11, 7, 53, 63, 231, 193, 293, 1467, 1409, 6397, 13237, 15903, 19271, 66257}},
+{10018, 17, 36486, {1, 3, 1, 15, 23, 15, 37, 123, 189, 63, 1121, 751, 6711, 10095, 6493, 40709, 47641}},
+{10019, 17, 36489, {1, 3, 7, 3, 23, 59, 99, 183, 249, 479, 771, 1087, 7979, 409, 4819, 4337, 33345}},
+{10020, 17, 36495, {1, 1, 5, 1, 17, 7, 15, 167, 305, 411, 1429, 3127, 23, 9123, 7185, 44405, 114841}},
+{10021, 17, 36525, {1, 1, 5, 11, 3, 29, 29, 31, 399, 777, 251, 1841, 3607, 211, 23543, 29111, 54565}},
+{10022, 17, 36526, {1, 3, 3, 9, 27, 33, 79, 27, 469, 67, 1327, 183, 5783, 10039, 13165, 20443, 4913}},
+{10023, 17, 36533, {1, 3, 7, 15, 21, 23, 5, 227, 141, 1021, 69, 3347, 7221, 13837, 20921, 20525, 32567}},
+{10024, 17, 36534, {1, 1, 5, 5, 25, 53, 73, 111, 319, 311, 1597, 1809, 5343, 13963, 6613, 14471, 53871}},
+{10025, 17, 36540, {1, 3, 3, 1, 15, 57, 47, 205, 53, 471, 185, 273, 8077, 5031, 31195, 30859, 15979}},
+{10026, 17, 36555, {1, 1, 3, 5, 23, 15, 87, 211, 83, 265, 1629, 2979, 69, 12559, 30455, 36363, 61461}},
+{10027, 17, 36563, {1, 1, 7, 7, 1, 47, 5, 199, 95, 17, 57, 1887, 6847, 9501, 21361, 57763, 77069}},
+{10028, 17, 36565, {1, 1, 3, 5, 9, 15, 15, 149, 141, 605, 639, 2197, 7237, 5753, 9415, 4677, 129947}},
+{10029, 17, 36588, {1, 3, 7, 1, 7, 9, 29, 249, 275, 461, 1667, 4093, 5763, 3205, 24079, 11883, 86455}},
+{10030, 17, 36593, {1, 1, 3, 5, 15, 39, 117, 145, 153, 671, 1819, 111, 3607, 12279, 4927, 63759, 42905}},
+{10031, 17, 36596, {1, 1, 1, 5, 31, 5, 35, 183, 189, 839, 1811, 1877, 6545, 11373, 27947, 27183, 29857}},
+{10032, 17, 36606, {1, 3, 5, 7, 29, 47, 3, 183, 511, 145, 1953, 3419, 6385, 7745, 12823, 59783, 69399}},
+{10033, 17, 36614, {1, 3, 5, 9, 5, 39, 85, 145, 33, 899, 1009, 2035, 6145, 3855, 20583, 4329, 95231}},
+{10034, 17, 36626, {1, 1, 3, 3, 15, 61, 85, 181, 247, 705, 413, 1633, 7489, 1785, 30397, 42851, 80197}},
+{10035, 17, 36628, {1, 3, 3, 13, 23, 11, 3, 97, 307, 183, 113, 3881, 7455, 8327, 6749, 23977, 101629}},
+{10036, 17, 36641, {1, 1, 7, 13, 1, 23, 59, 219, 125, 789, 1401, 707, 6915, 6275, 25813, 46595, 54119}},
+{10037, 17, 36642, {1, 3, 7, 9, 5, 7, 37, 33, 165, 181, 833, 1993, 4541, 5799, 23323, 39825, 44575}},
+{10038, 17, 36651, {1, 3, 1, 13, 13, 43, 69, 219, 437, 521, 503, 2293, 3607, 6845, 22583, 291, 65645}},
+{10039, 17, 36653, {1, 1, 7, 9, 29, 13, 123, 67, 191, 933, 1875, 1223, 5525, 13797, 29771, 58191, 84469}},
+{10040, 17, 36673, {1, 1, 7, 7, 3, 57, 101, 69, 23, 239, 1023, 3289, 1541, 6245, 23379, 161, 61155}},
+{10041, 17, 36676, {1, 3, 7, 13, 25, 33, 49, 145, 487, 681, 451, 1719, 109, 16273, 20009, 3003, 115815}},
+{10042, 17, 36679, {1, 1, 5, 11, 11, 59, 41, 133, 303, 469, 1975, 847, 5291, 13947, 8759, 8533, 25099}},
+{10043, 17, 36694, {1, 1, 1, 1, 29, 31, 53, 11, 239, 57, 1627, 1247, 1577, 3269, 20751, 4627, 40499}},
+{10044, 17, 36698, {1, 3, 7, 15, 1, 1, 51, 39, 383, 203, 1841, 3867, 4975, 9937, 1863, 52611, 83189}},
+{10045, 17, 36704, {1, 3, 7, 7, 13, 59, 15, 217, 355, 945, 1317, 815, 2413, 10985, 30647, 37745, 126553}},
+{10046, 17, 36714, {1, 1, 3, 11, 7, 29, 101, 137, 97, 119, 927, 3269, 6977, 4253, 10741, 61907, 122815}},
+{10047, 17, 36721, {1, 3, 3, 1, 29, 5, 49, 137, 411, 349, 905, 2481, 4961, 4513, 29409, 19503, 77915}},
+{10048, 17, 36722, {1, 1, 7, 13, 29, 59, 93, 61, 393, 29, 257, 3601, 6281, 5105, 17339, 53827, 83137}},
+{10049, 17, 36727, {1, 1, 1, 13, 5, 23, 61, 7, 51, 161, 737, 1549, 6021, 3385, 5539, 21261, 69995}},
+{10050, 17, 36749, {1, 1, 1, 15, 31, 1, 21, 113, 481, 7, 175, 717, 1593, 5937, 12347, 51835, 66649}},
+{10051, 17, 36758, {1, 1, 3, 7, 9, 51, 9, 199, 39, 607, 1157, 3913, 7767, 14195, 28721, 27655, 34709}},
+{10052, 17, 36761, {1, 3, 5, 5, 1, 15, 49, 33, 441, 721, 1749, 1497, 2023, 8351, 12641, 11861, 78545}},
+{10053, 17, 36771, {1, 3, 1, 7, 7, 17, 103, 113, 243, 25, 889, 1419, 3163, 12401, 22459, 39037, 101719}},
+{10054, 17, 36788, {1, 1, 7, 11, 17, 45, 121, 215, 3, 409, 1871, 2149, 4249, 5071, 14277, 55869, 91233}},
+{10055, 17, 36797, {1, 1, 3, 7, 19, 31, 47, 241, 175, 749, 1709, 355, 6037, 10555, 24107, 64683, 42673}},
+{10056, 17, 36805, {1, 3, 7, 11, 5, 21, 105, 137, 307, 101, 417, 1903, 1027, 10257, 27767, 9755, 92105}},
+{10057, 17, 36830, {1, 1, 3, 13, 9, 59, 11, 63, 295, 923, 401, 1471, 3517, 7761, 28855, 11525, 72455}},
+{10058, 17, 36833, {1, 1, 7, 15, 31, 51, 77, 29, 323, 579, 1313, 3441, 2903, 1683, 20605, 8185, 29753}},
+{10059, 17, 36839, {1, 1, 5, 15, 11, 59, 119, 109, 233, 1001, 1527, 2709, 73, 5311, 18313, 27155, 85999}},
+{10060, 17, 36843, {1, 3, 1, 5, 9, 59, 105, 93, 213, 401, 839, 3225, 3263, 13501, 2413, 60367, 121281}},
+{10061, 17, 36860, {1, 1, 7, 3, 19, 25, 75, 27, 325, 435, 527, 1465, 3601, 5785, 6135, 32841, 60129}},
+{10062, 17, 36866, {1, 1, 3, 7, 31, 19, 37, 157, 189, 51, 869, 2963, 5269, 9151, 14845, 30441, 89685}},
+{10063, 17, 36871, {1, 3, 3, 9, 17, 51, 23, 177, 417, 255, 1739, 3085, 7811, 15177, 25433, 38487, 51021}},
+{10064, 17, 36875, {1, 1, 3, 7, 27, 1, 45, 235, 59, 491, 1327, 3967, 7585, 4313, 29669, 47193, 89427}},
+{10065, 17, 36877, {1, 1, 3, 9, 19, 5, 27, 63, 263, 593, 1599, 1311, 1029, 603, 25291, 51391, 98915}},
+{10066, 17, 36880, {1, 3, 3, 15, 11, 7, 97, 99, 263, 155, 437, 3849, 2665, 3371, 8179, 51883, 3601}},
+{10067, 17, 36892, {1, 1, 3, 15, 7, 35, 37, 149, 251, 619, 1423, 553, 4453, 16365, 22543, 6951, 34655}},
+{10068, 17, 36911, {1, 3, 3, 11, 15, 21, 95, 143, 31, 425, 179, 2383, 4799, 7655, 26945, 9273, 103469}},
+{10069, 17, 36914, {1, 3, 1, 9, 13, 49, 3, 117, 361, 459, 227, 2067, 4909, 13461, 22505, 10259, 59697}},
+{10070, 17, 36916, {1, 1, 7, 7, 7, 23, 67, 217, 313, 965, 1747, 995, 579, 6217, 8915, 49329, 851}},
+{10071, 17, 36923, {1, 1, 3, 1, 17, 19, 7, 99, 281, 207, 1685, 2401, 967, 9399, 28741, 28839, 6003}},
+{10072, 17, 36940, {1, 3, 3, 5, 31, 61, 105, 251, 499, 319, 1167, 2203, 1195, 2663, 11797, 12981, 125523}},
+{10073, 17, 36943, {1, 3, 1, 5, 23, 19, 99, 101, 85, 837, 501, 2737, 4051, 2413, 9275, 38995, 21633}},
+{10074, 17, 36948, {1, 3, 7, 13, 17, 17, 119, 75, 281, 527, 1477, 1515, 7765, 5573, 10143, 6219, 57817}},
+{10075, 17, 36957, {1, 1, 5, 11, 19, 35, 85, 171, 107, 905, 1395, 1199, 7345, 15719, 14021, 47425, 36081}},
+{10076, 17, 36958, {1, 1, 3, 9, 9, 63, 109, 15, 323, 73, 1541, 2227, 5197, 12617, 23379, 53415, 105291}},
+{10077, 17, 36967, {1, 3, 3, 5, 5, 41, 85, 99, 3, 895, 1383, 3627, 3897, 1893, 23673, 56501, 78411}},
+{10078, 17, 36974, {1, 1, 7, 1, 25, 27, 45, 185, 475, 577, 1619, 727, 1407, 2383, 9215, 55295, 27349}},
+{10079, 17, 36981, {1, 3, 7, 11, 3, 51, 53, 53, 399, 711, 1075, 511, 5369, 10777, 14419, 63217, 130181}},
+{10080, 17, 37001, {1, 1, 7, 13, 25, 19, 107, 71, 151, 73, 735, 3837, 5307, 10229, 10529, 9989, 111925}},
+{10081, 17, 37012, {1, 1, 1, 15, 19, 59, 65, 77, 465, 957, 1085, 1359, 3959, 15823, 6273, 12565, 126167}},
+{10082, 17, 37015, {1, 1, 5, 5, 31, 53, 23, 173, 407, 795, 41, 3275, 1953, 13673, 26625, 33477, 14149}},
+{10083, 17, 37019, {1, 1, 7, 7, 1, 11, 121, 139, 77, 321, 1939, 2597, 621, 9579, 11629, 13119, 30505}},
+{10084, 17, 37035, {1, 1, 1, 5, 3, 33, 45, 127, 169, 581, 1521, 1019, 6489, 1069, 2469, 40255, 66619}},
+{10085, 17, 37040, {1, 3, 7, 5, 29, 47, 7, 245, 459, 417, 1027, 857, 4905, 11255, 3267, 9491, 78013}},
+{10086, 17, 37063, {1, 3, 5, 9, 25, 49, 61, 215, 19, 731, 303, 1001, 6031, 3705, 7797, 31957, 119383}},
+{10087, 17, 37064, {1, 3, 5, 5, 1, 9, 37, 187, 235, 453, 963, 2833, 3501, 605, 2763, 41215, 93547}},
+{10088, 17, 37069, {1, 3, 1, 1, 21, 3, 41, 53, 425, 687, 1051, 2365, 7835, 3981, 5557, 61993, 127417}},
+{10089, 17, 37077, {1, 3, 3, 7, 13, 61, 41, 189, 261, 163, 1931, 1803, 2379, 16379, 25453, 17911, 123431}},
+{10090, 17, 37093, {1, 1, 7, 15, 23, 21, 95, 7, 27, 897, 721, 3917, 7971, 4643, 5223, 46583, 32453}},
+{10091, 17, 37097, {1, 1, 7, 7, 1, 25, 83, 109, 223, 573, 533, 449, 6477, 10719, 28705, 8283, 94963}},
+{10092, 17, 37106, {1, 1, 5, 13, 21, 45, 63, 31, 21, 223, 31, 1249, 425, 7199, 11539, 7731, 44333}},
+{10093, 17, 37115, {1, 1, 5, 15, 29, 5, 87, 215, 287, 567, 297, 451, 5867, 15511, 1005, 57469, 87257}},
+{10094, 17, 37118, {1, 3, 5, 11, 13, 51, 117, 139, 377, 1015, 1237, 2053, 7625, 1003, 22673, 64345, 16203}},
+{10095, 17, 37123, {1, 1, 3, 15, 19, 39, 73, 205, 185, 331, 869, 857, 5043, 7247, 25253, 5799, 64857}},
+{10096, 17, 37129, {1, 3, 7, 1, 25, 63, 125, 47, 161, 289, 373, 1603, 1663, 1123, 28907, 37855, 47935}},
+{10097, 17, 37130, {1, 1, 7, 15, 9, 17, 97, 63, 79, 123, 1357, 3055, 2323, 16083, 21861, 38743, 81291}},
+{10098, 17, 37135, {1, 1, 3, 15, 5, 23, 7, 159, 127, 511, 55, 2691, 6823, 16151, 8059, 43021, 18911}},
+{10099, 17, 37137, {1, 1, 3, 9, 27, 19, 41, 75, 375, 921, 1745, 35, 1189, 5857, 29869, 43827, 16899}},
+{10100, 17, 37138, {1, 1, 1, 5, 3, 21, 13, 235, 51, 529, 291, 2619, 5419, 12573, 10907, 8865, 54987}},
+{10101, 17, 37140, {1, 3, 1, 13, 7, 9, 85, 131, 159, 743, 1671, 3001, 4559, 12343, 27563, 49941, 68447}},
+{10102, 17, 37144, {1, 1, 7, 5, 17, 61, 99, 63, 199, 383, 485, 2569, 5329, 645, 18805, 20421, 101229}},
+{10103, 17, 37149, {1, 1, 1, 15, 3, 59, 41, 247, 213, 843, 2003, 125, 7755, 4203, 20277, 47195, 48249}},
+{10104, 17, 37156, {1, 1, 5, 15, 15, 17, 113, 101, 27, 811, 1791, 1777, 749, 14317, 17267, 54467, 118369}},
+{10105, 17, 37159, {1, 3, 3, 3, 19, 37, 23, 117, 275, 733, 1259, 567, 1769, 12071, 5413, 49411, 99259}},
+{10106, 17, 37163, {1, 3, 1, 11, 3, 27, 103, 113, 251, 731, 481, 2771, 3205, 14151, 19403, 30307, 114691}},
+{10107, 17, 37165, {1, 1, 5, 15, 19, 15, 103, 25, 357, 197, 1437, 3621, 4747, 773, 5769, 33465, 28307}},
+{10108, 17, 37183, {1, 1, 5, 15, 5, 17, 89, 87, 423, 611, 549, 2549, 1275, 14545, 2931, 3853, 24577}},
+{10109, 17, 37185, {1, 3, 5, 1, 15, 13, 29, 49, 279, 495, 697, 1015, 4899, 15977, 10765, 47979, 40237}},
+{10110, 17, 37195, {1, 3, 3, 9, 31, 51, 21, 5, 279, 947, 1871, 3075, 5433, 1631, 30075, 30517, 99609}},
+{10111, 17, 37198, {1, 1, 1, 15, 19, 63, 79, 81, 19, 629, 617, 1887, 4015, 15501, 10551, 56419, 108739}},
+{10112, 17, 37203, {1, 1, 3, 9, 31, 15, 45, 37, 43, 349, 1357, 189, 4551, 9363, 15683, 48445, 89279}},
+{10113, 17, 37212, {1, 1, 1, 1, 17, 19, 121, 119, 397, 947, 1797, 613, 1627, 9591, 15779, 62295, 118843}},
+{10114, 17, 37233, {1, 1, 1, 7, 25, 55, 71, 227, 507, 497, 1209, 2919, 5733, 15785, 21437, 40043, 2325}},
+{10115, 17, 37236, {1, 1, 1, 15, 11, 1, 59, 93, 69, 859, 67, 1831, 6345, 5643, 29515, 20337, 77281}},
+{10116, 17, 37240, {1, 3, 5, 9, 19, 53, 59, 63, 161, 853, 697, 1441, 3457, 951, 29659, 15337, 38443}},
+{10117, 17, 37256, {1, 3, 1, 9, 7, 21, 73, 81, 89, 291, 411, 3793, 4639, 2829, 6855, 38113, 32875}},
+{10118, 17, 37264, {1, 1, 7, 1, 15, 3, 79, 35, 363, 459, 907, 1157, 5165, 8021, 10135, 36367, 111991}},
+{10119, 17, 37267, {1, 3, 5, 13, 21, 23, 63, 155, 393, 869, 1553, 3345, 2711, 8249, 24907, 28111, 36667}},
+{10120, 17, 37273, {1, 1, 7, 11, 15, 25, 29, 93, 45, 637, 1473, 2053, 313, 8047, 23411, 8643, 2925}},
+{10121, 17, 37295, {1, 3, 7, 9, 11, 5, 73, 69, 311, 949, 2017, 259, 2861, 10547, 12017, 34125, 74101}},
+{10122, 17, 37315, {1, 3, 1, 13, 19, 61, 115, 59, 447, 787, 1621, 2221, 7841, 5329, 18137, 13857, 51889}},
+{10123, 17, 37330, {1, 3, 7, 13, 1, 23, 117, 49, 449, 541, 7, 3269, 1725, 6677, 15979, 4319, 40919}},
+{10124, 17, 37336, {1, 3, 5, 5, 17, 29, 35, 123, 3, 481, 305, 1589, 4319, 5183, 31907, 53019, 49375}},
+{10125, 17, 37339, {1, 3, 1, 7, 11, 59, 79, 89, 479, 821, 763, 3597, 7457, 13775, 11213, 22777, 80379}},
+{10126, 17, 37342, {1, 1, 3, 7, 13, 17, 65, 155, 335, 671, 331, 895, 7459, 1719, 10675, 60109, 63143}},
+{10127, 17, 37357, {1, 3, 5, 1, 29, 33, 105, 249, 61, 469, 1629, 3777, 4393, 14457, 11701, 6065, 2635}},
+{10128, 17, 37365, {1, 3, 7, 3, 13, 13, 21, 15, 363, 63, 1263, 1479, 1459, 6577, 7481, 30393, 19831}},
+{10129, 17, 37372, {1, 1, 3, 7, 29, 25, 71, 247, 501, 815, 1697, 2457, 4975, 3821, 25759, 24901, 120603}},
+{10130, 17, 37381, {1, 1, 1, 5, 19, 3, 59, 163, 367, 779, 47, 905, 897, 3293, 13951, 25497, 99151}},
+{10131, 17, 37399, {1, 3, 1, 5, 11, 47, 21, 171, 123, 215, 1797, 3741, 4921, 7213, 4847, 3239, 114839}},
+{10132, 17, 37416, {1, 3, 3, 5, 23, 63, 57, 31, 409, 431, 1337, 3301, 4695, 7401, 9383, 12639, 34347}},
+{10133, 17, 37429, {1, 3, 3, 5, 27, 57, 29, 147, 111, 1015, 815, 1509, 3967, 7255, 15109, 26001, 90775}},
+{10134, 17, 37436, {1, 1, 7, 13, 31, 45, 21, 99, 377, 399, 255, 459, 6043, 11055, 5675, 3333, 32813}},
+{10135, 17, 37442, {1, 3, 1, 7, 1, 55, 121, 77, 429, 433, 297, 3181, 3029, 6777, 22795, 61515, 58553}},
+{10136, 17, 37451, {1, 3, 5, 9, 1, 19, 121, 1, 499, 589, 1597, 2219, 1029, 4223, 31613, 45685, 53517}},
+{10137, 17, 37453, {1, 3, 1, 9, 29, 39, 83, 193, 43, 41, 467, 1711, 2761, 10635, 15503, 38043, 120615}},
+{10138, 17, 37475, {1, 1, 7, 13, 27, 61, 1, 181, 163, 613, 221, 63, 6147, 8215, 15093, 2417, 71489}},
+{10139, 17, 37482, {1, 1, 7, 15, 31, 63, 47, 139, 427, 847, 53, 1275, 1019, 9455, 12537, 22467, 129947}},
+{10140, 17, 37489, {1, 1, 5, 3, 7, 1, 67, 189, 501, 319, 37, 2849, 2535, 10917, 11115, 48083, 67255}},
+{10141, 17, 37490, {1, 1, 3, 13, 7, 31, 69, 137, 19, 73, 1553, 3945, 2381, 8761, 3977, 24291, 128189}},
+{10142, 17, 37523, {1, 3, 5, 11, 1, 59, 43, 229, 301, 771, 559, 195, 1675, 12605, 22211, 2915, 90351}},
+{10143, 17, 37525, {1, 3, 3, 9, 13, 27, 97, 33, 273, 229, 1537, 1179, 6985, 11679, 17889, 44673, 126641}},
+{10144, 17, 37530, {1, 1, 7, 3, 31, 29, 41, 123, 491, 639, 269, 45, 2155, 14103, 6725, 50781, 42785}},
+{10145, 17, 37535, {1, 3, 5, 9, 9, 11, 89, 249, 475, 701, 1029, 985, 8167, 439, 31897, 24529, 45759}},
+{10146, 17, 37539, {1, 1, 5, 11, 9, 39, 127, 179, 15, 135, 1437, 3331, 5553, 939, 15319, 64937, 110783}},
+{10147, 17, 37548, {1, 3, 1, 5, 7, 61, 1, 219, 111, 801, 85, 3427, 2533, 12861, 5395, 28969, 48091}},
+{10148, 17, 37559, {1, 1, 1, 9, 23, 57, 77, 41, 61, 635, 457, 231, 8121, 5349, 27021, 64807, 87563}},
+{10149, 17, 37560, {1, 3, 5, 7, 31, 31, 101, 155, 255, 199, 1973, 903, 7681, 15379, 12845, 47943, 60663}},
+{10150, 17, 37566, {1, 1, 5, 7, 1, 7, 71, 121, 323, 669, 193, 1209, 267, 9, 21223, 22037, 121567}},
+{10151, 17, 37597, {1, 3, 1, 5, 17, 29, 97, 189, 219, 813, 187, 1763, 5817, 13185, 467, 40159, 18037}},
+{10152, 17, 37601, {1, 1, 7, 9, 7, 59, 3, 189, 379, 843, 631, 3945, 2909, 4191, 30343, 11223, 105629}},
+{10153, 17, 37602, {1, 3, 1, 3, 15, 17, 23, 73, 439, 699, 657, 451, 6139, 15869, 4101, 32327, 55485}},
+{10154, 17, 37604, {1, 3, 3, 5, 21, 37, 87, 157, 205, 493, 705, 1539, 2193, 13539, 2797, 49063, 55595}},
+{10155, 17, 37616, {1, 1, 5, 11, 11, 41, 5, 131, 445, 781, 1153, 1371, 6763, 3101, 32449, 16065, 86579}},
+{10156, 17, 37622, {1, 3, 5, 1, 23, 51, 97, 87, 161, 261, 269, 2035, 2139, 3049, 32217, 25189, 93571}},
+{10157, 17, 37658, {1, 3, 1, 11, 23, 1, 111, 45, 19, 19, 1767, 3571, 6027, 3593, 17453, 53821, 28121}},
+{10158, 17, 37660, {1, 3, 3, 5, 17, 5, 17, 247, 5, 73, 29, 443, 7713, 15803, 22311, 56755, 100119}},
+{10159, 17, 37667, {1, 3, 1, 13, 7, 1, 41, 139, 317, 977, 1529, 1217, 529, 3231, 21491, 28461, 96699}},
+{10160, 17, 37684, {1, 3, 1, 13, 11, 41, 103, 99, 81, 849, 231, 1729, 761, 711, 11499, 25581, 59433}},
+{10161, 17, 37693, {1, 1, 5, 5, 13, 33, 79, 175, 89, 29, 295, 2867, 1197, 6137, 32063, 23471, 21721}},
+{10162, 17, 37694, {1, 1, 5, 15, 17, 29, 123, 249, 273, 437, 443, 2601, 3957, 11955, 261, 54863, 85727}},
+{10163, 17, 37696, {1, 1, 5, 13, 3, 31, 57, 205, 3, 903, 905, 3851, 757, 13761, 28615, 48185, 33227}},
+{10164, 17, 37706, {1, 3, 7, 1, 1, 1, 107, 15, 307, 405, 45, 297, 4365, 1569, 9263, 13685, 36027}},
+{10165, 17, 37711, {1, 3, 1, 9, 17, 61, 113, 121, 249, 743, 191, 2523, 6621, 5395, 23797, 57975, 51675}},
+{10166, 17, 37730, {1, 3, 5, 3, 27, 21, 49, 113, 59, 989, 501, 2651, 3827, 5121, 29667, 32903, 84199}},
+{10167, 17, 37735, {1, 1, 7, 7, 19, 43, 11, 191, 143, 93, 1167, 2521, 2569, 12187, 28575, 13073, 113545}},
+{10168, 17, 37742, {1, 1, 7, 3, 27, 39, 11, 85, 61, 979, 49, 2191, 2607, 13967, 28123, 48903, 16327}},
+{10169, 17, 37744, {1, 1, 5, 3, 17, 17, 1, 149, 189, 1017, 705, 3119, 6441, 1595, 30533, 18795, 34265}},
+{10170, 17, 37759, {1, 1, 3, 11, 31, 11, 125, 109, 39, 41, 191, 2615, 1377, 16089, 8793, 31425, 90507}},
+{10171, 17, 37777, {1, 1, 1, 1, 23, 15, 21, 245, 337, 649, 585, 2893, 927, 883, 15119, 2595, 127963}},
+{10172, 17, 37783, {1, 3, 5, 3, 13, 17, 123, 167, 471, 5, 1671, 2787, 5081, 12903, 4257, 19213, 2503}},
+{10173, 17, 37784, {1, 1, 5, 7, 21, 57, 75, 171, 509, 591, 85, 407, 1747, 6375, 19641, 55683, 111289}},
+{10174, 17, 37793, {1, 1, 7, 7, 3, 31, 121, 111, 19, 361, 1033, 4033, 2359, 13451, 15095, 61817, 69683}},
+{10175, 17, 37800, {1, 1, 5, 9, 21, 33, 83, 179, 387, 69, 1085, 2147, 2751, 10899, 16971, 40623, 110891}},
+{10176, 17, 37818, {1, 1, 7, 9, 11, 45, 81, 71, 73, 551, 145, 159, 7519, 3459, 5197, 48913, 59045}},
+{10177, 17, 37823, {1, 3, 1, 3, 7, 35, 17, 249, 207, 767, 1189, 1451, 4351, 3673, 28807, 671, 69271}},
+{10178, 17, 37825, {1, 3, 1, 15, 21, 27, 81, 243, 55, 191, 1497, 3205, 1601, 705, 14891, 14403, 130729}},
+{10179, 17, 37828, {1, 3, 1, 7, 17, 43, 41, 123, 507, 201, 1873, 3547, 5681, 1819, 4251, 39661, 57923}},
+{10180, 17, 37832, {1, 3, 1, 9, 3, 59, 57, 235, 445, 479, 961, 1937, 2229, 2511, 15235, 59707, 72261}},
+{10181, 17, 37849, {1, 1, 5, 13, 9, 63, 67, 217, 63, 259, 175, 2469, 3075, 12365, 7727, 42215, 12635}},
+{10182, 17, 37856, {1, 1, 3, 13, 11, 9, 125, 131, 17, 399, 675, 767, 7349, 10433, 21615, 46823, 3955}},
+{10183, 17, 37861, {1, 1, 3, 15, 19, 53, 73, 171, 125, 531, 1093, 1449, 2931, 10897, 12263, 9799, 98251}},
+{10184, 17, 37862, {1, 1, 5, 5, 11, 27, 33, 9, 503, 545, 339, 1099, 1973, 13261, 26871, 14569, 22755}},
+{10185, 17, 37886, {1, 3, 7, 1, 19, 5, 79, 133, 247, 1021, 1431, 3707, 4603, 3285, 5469, 46963, 98203}},
+{10186, 17, 37893, {1, 3, 5, 7, 15, 11, 87, 169, 495, 763, 1295, 2533, 4213, 8671, 21683, 12521, 90071}},
+{10187, 17, 37915, {1, 1, 3, 1, 17, 55, 7, 165, 313, 659, 49, 377, 6675, 15255, 9881, 11751, 87789}},
+{10188, 17, 37922, {1, 3, 1, 15, 3, 49, 27, 109, 145, 1011, 1939, 3201, 6141, 7229, 20741, 59285, 129365}},
+{10189, 17, 37936, {1, 1, 5, 5, 5, 51, 117, 17, 363, 795, 1343, 2637, 6209, 1045, 22515, 10687, 48487}},
+{10190, 17, 37939, {1, 1, 5, 15, 1, 37, 91, 241, 245, 703, 505, 3369, 6163, 10265, 12497, 46301, 109523}},
+{10191, 17, 37945, {1, 1, 7, 11, 3, 37, 67, 35, 229, 823, 193, 913, 3331, 4475, 9271, 11859, 52709}},
+{10192, 17, 37956, {1, 1, 3, 3, 7, 25, 61, 159, 81, 1011, 1491, 1439, 1031, 765, 9839, 61891, 20969}},
+{10193, 17, 37960, {1, 3, 3, 7, 25, 39, 73, 59, 101, 101, 225, 1105, 5943, 5223, 12585, 16411, 62699}},
+{10194, 17, 37971, {1, 1, 7, 5, 25, 19, 27, 113, 465, 319, 2035, 2127, 1319, 11793, 26821, 44805, 28217}},
+{10195, 17, 37980, {1, 3, 5, 11, 7, 9, 81, 107, 67, 31, 1503, 3303, 4451, 11417, 32681, 26861, 54845}},
+{10196, 17, 38002, {1, 3, 1, 1, 3, 51, 93, 235, 93, 247, 2027, 1517, 6797, 1703, 10233, 45313, 60771}},
+{10197, 17, 38007, {1, 3, 3, 15, 25, 11, 83, 77, 413, 189, 119, 597, 2199, 12347, 7935, 40191, 125569}},
+{10198, 17, 38018, {1, 3, 7, 9, 11, 3, 77, 31, 89, 163, 1993, 3017, 3973, 10943, 22247, 45565, 7261}},
+{10199, 17, 38020, {1, 3, 7, 7, 15, 13, 7, 155, 373, 893, 607, 3521, 7455, 13809, 6145, 31743, 86329}},
+{10200, 17, 38038, {1, 1, 1, 15, 25, 41, 111, 65, 11, 627, 59, 2725, 995, 3761, 25361, 45189, 48355}},
+{10201, 17, 38041, {1, 1, 7, 5, 29, 43, 91, 139, 323, 503, 679, 4079, 403, 1899, 1425, 26989, 117057}},
+{10202, 17, 38044, {1, 3, 5, 13, 1, 17, 19, 61, 205, 833, 345, 1031, 7995, 999, 27469, 15943, 88011}},
+{10203, 17, 38048, {1, 3, 1, 7, 23, 49, 123, 9, 11, 761, 1163, 669, 3837, 15225, 23393, 19513, 9457}},
+{10204, 17, 38051, {1, 1, 5, 9, 9, 33, 29, 123, 277, 433, 1799, 1583, 3133, 13461, 26443, 15807, 80173}},
+{10205, 17, 38054, {1, 3, 7, 3, 31, 29, 77, 105, 297, 617, 491, 647, 6541, 5033, 31841, 48405, 126985}},
+{10206, 17, 38065, {1, 1, 5, 5, 31, 39, 17, 25, 3, 279, 89, 3985, 3333, 5681, 3701, 36319, 12585}},
+{10207, 17, 38066, {1, 1, 7, 13, 13, 19, 93, 129, 51, 875, 1083, 1739, 5193, 6217, 10033, 51839, 66071}},
+{10208, 17, 38077, {1, 1, 7, 9, 15, 23, 93, 121, 507, 115, 707, 3181, 1521, 9609, 4577, 54389, 19167}},
+{10209, 17, 38090, {1, 3, 3, 7, 17, 51, 19, 29, 387, 711, 1105, 1627, 4421, 15183, 14149, 26485, 106425}},
+{10210, 17, 38109, {1, 3, 3, 15, 25, 59, 11, 45, 259, 1019, 1997, 3373, 5083, 5701, 30217, 44845, 67559}},
+{10211, 17, 38119, {1, 3, 3, 9, 17, 47, 5, 103, 477, 785, 235, 1523, 1505, 8811, 15255, 53493, 4383}},
+{10212, 17, 38120, {1, 3, 7, 3, 7, 37, 73, 247, 397, 409, 1065, 525, 5665, 8533, 30627, 19035, 22937}},
+{10213, 17, 38123, {1, 3, 3, 15, 15, 47, 123, 215, 413, 249, 55, 2563, 8033, 8743, 18659, 7947, 56057}},
+{10214, 17, 38146, {1, 1, 7, 3, 11, 61, 103, 109, 313, 293, 149, 999, 901, 13387, 15351, 52973, 68385}},
+{10215, 17, 38155, {1, 1, 1, 5, 31, 13, 57, 43, 263, 141, 335, 2777, 3435, 4231, 20623, 2597, 33481}},
+{10216, 17, 38160, {1, 1, 7, 13, 21, 53, 101, 75, 237, 275, 1903, 3501, 8023, 3651, 19609, 44417, 60287}},
+{10217, 17, 38181, {1, 1, 1, 1, 13, 43, 83, 255, 355, 567, 1781, 2943, 1061, 2701, 24861, 58381, 60255}},
+{10218, 17, 38188, {1, 1, 3, 9, 25, 5, 81, 85, 445, 857, 517, 3687, 2641, 6699, 19273, 4481, 8715}},
+{10219, 17, 38199, {1, 1, 3, 7, 17, 39, 33, 31, 29, 269, 379, 3149, 4731, 10387, 7941, 49199, 18423}},
+{10220, 17, 38203, {1, 1, 7, 15, 19, 37, 105, 157, 185, 1023, 1865, 53, 6765, 3, 22897, 17019, 109521}},
+{10221, 17, 38225, {1, 3, 7, 5, 5, 7, 117, 211, 19, 149, 1091, 3721, 201, 4455, 18965, 51401, 67225}},
+{10222, 17, 38226, {1, 3, 5, 11, 1, 55, 101, 41, 469, 271, 1251, 949, 861, 11903, 14773, 25675, 114161}},
+{10223, 17, 38231, {1, 1, 7, 7, 23, 13, 103, 185, 137, 575, 797, 1195, 5301, 13307, 12043, 26003, 31719}},
+{10224, 17, 38244, {1, 1, 5, 7, 11, 51, 17, 71, 321, 559, 1461, 3571, 1033, 15575, 7097, 14703, 52359}},
+{10225, 17, 38248, {1, 1, 1, 5, 21, 9, 123, 211, 233, 81, 111, 1433, 7825, 11771, 30743, 23993, 48717}},
+{10226, 17, 38259, {1, 3, 5, 15, 7, 3, 109, 33, 99, 135, 393, 3463, 7271, 14387, 30723, 19079, 83073}},
+{10227, 17, 38268, {1, 3, 3, 15, 3, 51, 77, 219, 409, 11, 67, 3787, 5155, 9259, 7185, 21611, 32577}},
+{10228, 17, 38271, {1, 3, 7, 1, 5, 49, 125, 85, 151, 301, 887, 1765, 5, 12849, 11775, 11319, 29547}},
+{10229, 17, 38272, {1, 1, 7, 11, 17, 15, 105, 29, 327, 637, 1493, 3361, 1823, 14709, 18355, 741, 57807}},
+{10230, 17, 38278, {1, 1, 7, 7, 3, 27, 15, 113, 227, 617, 1543, 1719, 8065, 13627, 23525, 20511, 64759}},
+{10231, 17, 38292, {1, 1, 3, 3, 21, 47, 89, 177, 381, 711, 1367, 2405, 887, 2351, 22957, 49679, 5963}},
+{10232, 17, 38296, {1, 3, 7, 9, 7, 1, 39, 71, 9, 275, 875, 1385, 6215, 10419, 25921, 63427, 18031}},
+{10233, 17, 38318, {1, 1, 7, 5, 23, 57, 27, 7, 445, 111, 953, 37, 2769, 1967, 8165, 35417, 36471}},
+{10234, 17, 38326, {1, 3, 3, 11, 23, 17, 119, 113, 275, 625, 1957, 2795, 3815, 7937, 11049, 31939, 128053}},
+{10235, 17, 38338, {1, 3, 3, 5, 7, 35, 45, 41, 251, 491, 1953, 3201, 751, 5705, 595, 27003, 77917}},
+{10236, 17, 38347, {1, 3, 5, 3, 25, 17, 55, 137, 299, 541, 289, 2225, 4667, 3569, 13687, 36193, 75705}},
+{10237, 17, 38373, {1, 1, 7, 15, 21, 9, 27, 157, 469, 441, 193, 2097, 4863, 2147, 31197, 24283, 102039}},
+{10238, 17, 38378, {1, 1, 1, 11, 17, 39, 73, 37, 91, 121, 1283, 367, 1875, 14365, 28349, 60993, 10791}},
+{10239, 17, 38380, {1, 3, 5, 9, 13, 63, 89, 53, 459, 347, 343, 2321, 5237, 2497, 279, 63833, 10709}},
+{10240, 17, 38388, {1, 1, 1, 15, 11, 23, 41, 79, 45, 567, 1217, 1669, 1679, 2561, 16191, 49041, 4081}},
+{10241, 17, 38392, {1, 3, 1, 5, 3, 9, 103, 245, 47, 561, 229, 2945, 6563, 797, 21571, 25769, 12995}},
+{10242, 17, 38397, {1, 3, 5, 7, 5, 47, 99, 55, 49, 951, 765, 2095, 8021, 4389, 20501, 26047, 119967}},
+{10243, 17, 38398, {1, 1, 5, 3, 15, 47, 81, 121, 379, 527, 419, 1093, 367, 10939, 17181, 13905, 49859}},
+{10244, 17, 38401, {1, 3, 3, 5, 7, 59, 53, 255, 131, 685, 1677, 3757, 3601, 89, 6225, 32705, 28287}},
+{10245, 17, 38404, {1, 3, 7, 1, 7, 55, 85, 47, 425, 793, 605, 2313, 791, 4247, 9693, 10633, 82915}},
+{10246, 17, 38422, {1, 3, 5, 13, 13, 49, 127, 213, 27, 657, 419, 55, 6289, 295, 4211, 8899, 120237}},
+{10247, 17, 38432, {1, 1, 7, 11, 11, 7, 75, 35, 315, 125, 517, 3677, 2323, 6897, 11535, 36789, 20179}},
+{10248, 17, 38469, {1, 1, 5, 9, 11, 3, 77, 43, 323, 647, 383, 485, 3937, 9081, 27745, 59149, 103433}},
+{10249, 17, 38482, {1, 3, 3, 13, 3, 47, 91, 81, 115, 625, 2003, 3601, 531, 113, 20719, 47391, 111039}},
+{10250, 17, 38493, {1, 1, 3, 13, 5, 49, 123, 189, 109, 325, 497, 923, 3861, 14029, 22651, 19857, 104801}},
+{10251, 17, 38507, {1, 1, 5, 3, 29, 23, 25, 23, 501, 371, 1983, 1303, 2261, 11865, 13281, 2587, 75741}},
+{10252, 17, 38518, {1, 3, 5, 13, 27, 61, 45, 11, 157, 615, 897, 1529, 2213, 757, 30105, 2011, 27267}},
+{10253, 17, 38521, {1, 3, 5, 13, 29, 31, 95, 159, 449, 307, 1575, 1897, 2301, 14023, 6921, 30543, 31843}},
+{10254, 17, 38527, {1, 3, 3, 5, 1, 1, 79, 147, 437, 623, 1161, 3407, 3073, 15425, 4329, 19651, 90597}},
+{10255, 17, 38533, {1, 1, 1, 11, 17, 7, 43, 171, 447, 841, 573, 3775, 5517, 3629, 18241, 31907, 51423}},
+{10256, 17, 38534, {1, 1, 3, 7, 15, 53, 111, 203, 171, 963, 1983, 2017, 6067, 12281, 3417, 7431, 33803}},
+{10257, 17, 38552, {1, 3, 1, 1, 31, 49, 125, 65, 7, 579, 1709, 1815, 2643, 11537, 30093, 11813, 65157}},
+{10258, 17, 38561, {1, 3, 7, 15, 1, 3, 61, 21, 163, 809, 1263, 2577, 7811, 12611, 6921, 18529, 25709}},
+{10259, 17, 38576, {1, 1, 3, 5, 17, 43, 13, 81, 29, 905, 1975, 589, 5875, 15683, 29447, 46453, 127911}},
+{10260, 17, 38581, {1, 1, 5, 3, 19, 29, 11, 67, 375, 771, 755, 3939, 1465, 3275, 1119, 24695, 105105}},
+{10261, 17, 38585, {1, 1, 3, 11, 23, 37, 33, 135, 329, 733, 245, 2353, 2547, 7823, 16265, 5975, 37877}},
+{10262, 17, 38594, {1, 3, 7, 13, 15, 9, 47, 181, 239, 723, 1219, 409, 1685, 5493, 14189, 18107, 26231}},
+{10263, 17, 38606, {1, 1, 5, 1, 9, 1, 65, 125, 439, 591, 1499, 3797, 5879, 4231, 18655, 9643, 42265}},
+{10264, 17, 38613, {1, 1, 7, 7, 11, 51, 111, 47, 169, 39, 45, 2211, 6729, 10987, 22367, 27257, 112711}},
+{10265, 17, 38617, {1, 3, 5, 3, 19, 61, 89, 185, 23, 793, 1457, 1743, 3743, 15063, 14053, 50201, 109175}},
+{10266, 17, 38634, {1, 1, 5, 13, 31, 51, 69, 135, 427, 527, 1673, 2393, 5829, 683, 1509, 56617, 105735}},
+{10267, 17, 38644, {1, 1, 1, 15, 31, 51, 3, 105, 125, 593, 1589, 3217, 7449, 525, 30599, 11689, 14781}},
+{10268, 17, 38651, {1, 1, 1, 11, 9, 37, 113, 45, 487, 961, 87, 1461, 3521, 8645, 19771, 43817, 43277}},
+{10269, 17, 38661, {1, 1, 7, 3, 7, 11, 45, 97, 11, 593, 319, 2597, 37, 4157, 6669, 29929, 17213}},
+{10270, 17, 38665, {1, 3, 7, 3, 29, 21, 101, 93, 289, 975, 1937, 3423, 757, 7075, 12575, 26801, 90989}},
+{10271, 17, 38668, {1, 1, 7, 15, 25, 49, 49, 149, 503, 365, 1359, 2155, 7977, 14955, 18439, 44269, 88995}},
+{10272, 17, 38674, {1, 3, 7, 13, 25, 27, 15, 67, 157, 873, 339, 2143, 1405, 12209, 30939, 36109, 107699}},
+{10273, 17, 38689, {1, 3, 5, 5, 21, 33, 121, 95, 61, 159, 1423, 2899, 3811, 263, 9139, 54481, 107375}},
+{10274, 17, 38695, {1, 1, 7, 7, 13, 49, 83, 53, 267, 131, 673, 3945, 5255, 2009, 21017, 41749, 44817}},
+{10275, 17, 38696, {1, 3, 1, 13, 25, 57, 125, 5, 323, 653, 221, 2013, 7225, 8719, 28049, 41953, 14725}},
+{10276, 17, 38707, {1, 3, 7, 7, 5, 13, 35, 161, 221, 951, 769, 717, 267, 2233, 23387, 47411, 95739}},
+{10277, 17, 38710, {1, 3, 7, 11, 23, 47, 37, 67, 501, 159, 763, 4045, 5125, 5667, 9895, 33041, 101171}},
+{10278, 17, 38716, {1, 1, 7, 1, 31, 31, 111, 183, 33, 895, 1819, 3593, 1285, 10145, 3679, 36615, 82863}},
+{10279, 17, 38733, {1, 3, 5, 7, 21, 59, 55, 163, 139, 855, 1903, 3229, 3745, 10289, 28831, 46895, 12647}},
+{10280, 17, 38736, {1, 3, 7, 9, 25, 31, 113, 177, 459, 201, 565, 2089, 725, 9273, 26249, 5987, 49573}},
+{10281, 17, 38742, {1, 1, 7, 15, 3, 37, 49, 145, 121, 803, 1197, 2797, 21, 833, 2277, 28189, 93171}},
+{10282, 17, 38751, {1, 1, 7, 7, 13, 31, 93, 153, 345, 363, 1825, 1481, 3347, 13277, 26119, 63153, 118231}},
+{10283, 17, 38752, {1, 3, 1, 11, 31, 9, 33, 95, 433, 595, 1131, 465, 1797, 15453, 32527, 40789, 37799}},
+{10284, 17, 38775, {1, 1, 5, 11, 31, 29, 83, 33, 243, 633, 1325, 3843, 7717, 851, 29789, 48827, 89209}},
+{10285, 17, 38779, {1, 1, 3, 7, 25, 31, 127, 219, 281, 51, 1843, 3363, 5985, 1697, 3083, 18967, 117421}},
+{10286, 17, 38792, {1, 3, 7, 9, 1, 19, 125, 199, 41, 117, 903, 1131, 7731, 14431, 24753, 62841, 50251}},
+{10287, 17, 38798, {1, 3, 5, 5, 11, 37, 19, 249, 97, 59, 1849, 1151, 2171, 1217, 31277, 26547, 86601}},
+{10288, 17, 38819, {1, 3, 3, 7, 29, 35, 21, 7, 93, 971, 1155, 1847, 89, 6759, 29611, 40793, 88327}},
+{10289, 17, 38822, {1, 3, 5, 5, 29, 23, 91, 71, 479, 943, 1839, 3699, 2491, 9603, 15061, 43221, 20435}},
+{10290, 17, 38839, {1, 3, 3, 7, 29, 11, 15, 83, 21, 585, 501, 161, 4797, 11243, 14879, 12519, 19069}},
+{10291, 17, 38851, {1, 1, 5, 15, 13, 37, 9, 215, 433, 925, 987, 3253, 8027, 7013, 20801, 12891, 36497}},
+{10292, 17, 38854, {1, 3, 7, 1, 15, 31, 95, 85, 355, 1013, 1963, 2943, 1925, 13691, 15237, 28943, 63873}},
+{10293, 17, 38863, {1, 3, 3, 1, 17, 21, 99, 201, 465, 819, 665, 901, 2671, 2457, 29603, 35275, 28339}},
+{10294, 17, 38865, {1, 1, 1, 9, 5, 23, 111, 107, 27, 433, 1341, 91, 6879, 1933, 25433, 37435, 99061}},
+{10295, 17, 38887, {1, 3, 5, 13, 11, 55, 27, 151, 397, 591, 89, 1221, 5581, 2701, 15033, 41879, 71415}},
+{10296, 17, 38896, {1, 3, 3, 5, 17, 35, 15, 119, 487, 903, 875, 3391, 7731, 12181, 27823, 32561, 59133}},
+{10297, 17, 38901, {1, 1, 5, 7, 15, 33, 67, 53, 307, 947, 857, 2713, 803, 765, 4175, 15513, 23985}},
+{10298, 17, 38912, {1, 3, 1, 15, 23, 11, 15, 101, 467, 429, 153, 3205, 5627, 7555, 22515, 12721, 7905}},
+{10299, 17, 38918, {1, 1, 3, 7, 19, 61, 55, 187, 413, 49, 1031, 3415, 3903, 6933, 20017, 50429, 116407}},
+{10300, 17, 38929, {1, 3, 1, 13, 13, 15, 33, 1, 403, 441, 1969, 775, 2209, 15061, 15657, 28819, 62705}},
+{10301, 17, 38941, {1, 1, 5, 13, 13, 47, 67, 97, 87, 677, 1639, 3281, 1395, 8499, 18449, 49935, 25775}},
+{10302, 17, 38948, {1, 3, 3, 13, 7, 13, 77, 45, 405, 881, 293, 2263, 6517, 15415, 25809, 5681, 31327}},
+{10303, 17, 38965, {1, 3, 7, 5, 5, 51, 63, 171, 401, 671, 1631, 1735, 7361, 8741, 31933, 44761, 12209}},
+{10304, 17, 38969, {1, 1, 7, 3, 13, 3, 39, 223, 105, 781, 241, 2895, 5165, 12135, 5683, 63009, 58399}},
+{10305, 17, 38977, {1, 1, 5, 11, 29, 11, 37, 1, 445, 157, 219, 2269, 3025, 5721, 24539, 41879, 128445}},
+{10306, 17, 38987, {1, 3, 7, 15, 23, 21, 125, 105, 141, 101, 1981, 3765, 5349, 13781, 10055, 7069, 77721}},
+{10307, 17, 38992, {1, 1, 7, 9, 3, 37, 111, 95, 33, 53, 1021, 1629, 6945, 4657, 19977, 36715, 101401}},
+{10308, 17, 38995, {1, 3, 3, 1, 9, 5, 65, 77, 459, 471, 1045, 2351, 2787, 13001, 16211, 22585, 116205}},
+{10309, 17, 39001, {1, 1, 7, 9, 25, 41, 21, 187, 471, 997, 583, 2243, 6537, 11837, 21089, 51051, 98517}},
+{10310, 17, 39004, {1, 1, 7, 5, 13, 15, 81, 39, 223, 935, 951, 5, 4315, 11789, 18365, 49647, 92461}},
+{10311, 17, 39011, {1, 3, 3, 5, 11, 15, 97, 245, 43, 819, 1415, 3287, 2051, 15879, 21727, 54467, 53875}},
+{10312, 17, 39018, {1, 3, 1, 11, 7, 47, 125, 155, 301, 469, 805, 3789, 6967, 12117, 30369, 55183, 12671}},
+{10313, 17, 39025, {1, 1, 3, 13, 17, 25, 45, 199, 69, 1015, 581, 3891, 7743, 9273, 7639, 59055, 93923}},
+{10314, 17, 39031, {1, 1, 5, 11, 9, 47, 39, 251, 489, 47, 83, 2147, 943, 1959, 21361, 5325, 106079}},
+{10315, 17, 39032, {1, 3, 5, 13, 27, 59, 35, 1, 155, 367, 165, 2665, 3021, 1127, 28585, 45347, 66763}},
+{10316, 17, 39044, {1, 3, 1, 5, 31, 31, 15, 125, 485, 581, 1987, 2293, 4573, 11431, 20773, 58661, 79869}},
+{10317, 17, 39056, {1, 3, 5, 15, 31, 11, 109, 229, 11, 831, 1545, 919, 6125, 9337, 4169, 58041, 67577}},
+{10318, 17, 39065, {1, 1, 1, 3, 1, 43, 13, 89, 89, 863, 1607, 1897, 4831, 5239, 24503, 51853, 126983}},
+{10319, 17, 39066, {1, 1, 5, 11, 11, 37, 11, 253, 495, 83, 941, 3665, 5187, 13679, 11811, 29563, 80571}},
+{10320, 17, 39084, {1, 3, 7, 15, 3, 45, 45, 157, 477, 321, 1401, 1133, 271, 12455, 31543, 18223, 116701}},
+{10321, 17, 39095, {1, 1, 5, 3, 7, 5, 17, 127, 195, 583, 715, 3975, 6865, 7617, 6749, 15687, 42375}},
+{10322, 17, 39099, {1, 1, 1, 7, 5, 7, 21, 163, 303, 45, 1435, 1345, 2489, 15333, 18459, 60837, 104339}},
+{10323, 17, 39101, {1, 3, 1, 1, 7, 23, 39, 93, 347, 947, 345, 1713, 6383, 15411, 10849, 32559, 126431}},
+{10324, 17, 39102, {1, 3, 1, 5, 19, 41, 119, 213, 3, 991, 1745, 3989, 155, 7761, 28179, 59805, 106759}},
+{10325, 17, 39104, {1, 1, 7, 5, 25, 11, 105, 89, 505, 711, 1213, 2831, 8087, 8855, 31171, 49749, 921}},
+{10326, 17, 39109, {1, 1, 5, 5, 23, 61, 49, 101, 209, 805, 123, 17, 805, 9033, 25753, 33261, 33753}},
+{10327, 17, 39114, {1, 1, 3, 5, 5, 17, 93, 223, 179, 307, 869, 1851, 4313, 477, 12925, 21365, 103999}},
+{10328, 17, 39121, {1, 1, 7, 13, 21, 23, 105, 53, 393, 939, 291, 2407, 4815, 4961, 30305, 8613, 62599}},
+{10329, 17, 39122, {1, 1, 1, 11, 9, 55, 55, 135, 411, 225, 205, 3357, 4553, 10139, 17649, 51209, 94037}},
+{10330, 17, 39127, {1, 3, 5, 15, 17, 17, 119, 15, 121, 581, 169, 2495, 3673, 7173, 13099, 7683, 53397}},
+{10331, 17, 39150, {1, 3, 1, 11, 29, 29, 119, 255, 447, 85, 845, 1015, 2793, 2471, 12639, 32155, 99193}},
+{10332, 17, 39172, {1, 3, 3, 3, 9, 33, 77, 251, 425, 1007, 1003, 2697, 4989, 7799, 26581, 15963, 50443}},
+{10333, 17, 39181, {1, 3, 1, 5, 13, 47, 13, 203, 473, 529, 147, 2061, 343, 4029, 14615, 51355, 27863}},
+{10334, 17, 39184, {1, 1, 3, 15, 19, 63, 39, 25, 241, 487, 461, 3021, 3545, 4537, 8991, 17689, 77131}},
+{10335, 17, 39193, {1, 3, 5, 5, 7, 1, 61, 89, 495, 943, 1061, 405, 449, 12785, 25151, 24497, 65709}},
+{10336, 17, 39199, {1, 1, 5, 3, 7, 43, 51, 55, 193, 615, 37, 1377, 2541, 3861, 29447, 32269, 106335}},
+{10337, 17, 39200, {1, 1, 5, 11, 21, 55, 103, 43, 421, 673, 175, 979, 5175, 1301, 8617, 55875, 111095}},
+{10338, 17, 39206, {1, 3, 5, 13, 29, 31, 33, 241, 129, 473, 201, 2015, 447, 99, 23781, 33517, 107851}},
+{10339, 17, 39209, {1, 3, 5, 3, 13, 27, 125, 205, 287, 957, 1609, 2907, 5481, 14239, 19719, 22459, 75365}},
+{10340, 17, 39235, {1, 3, 3, 5, 27, 23, 53, 39, 329, 381, 745, 517, 7853, 5333, 2773, 29119, 7049}},
+{10341, 17, 39238, {1, 3, 5, 15, 29, 11, 89, 3, 503, 755, 485, 2669, 6737, 16241, 7345, 50991, 107291}},
+{10342, 17, 39242, {1, 1, 7, 3, 17, 45, 11, 3, 157, 715, 577, 1309, 3323, 9401, 10573, 55135, 100067}},
+{10343, 17, 39244, {1, 1, 5, 9, 19, 21, 49, 103, 349, 503, 1447, 675, 4273, 7673, 27507, 57697, 80875}},
+{10344, 17, 39280, {1, 1, 5, 1, 9, 53, 19, 99, 225, 915, 431, 781, 3291, 4383, 26505, 50339, 99799}},
+{10345, 17, 39290, {1, 3, 1, 5, 7, 37, 87, 201, 481, 991, 1553, 1867, 7893, 13147, 18647, 10373, 51951}},
+{10346, 17, 39292, {1, 1, 3, 13, 17, 37, 19, 199, 253, 901, 759, 3545, 3565, 10461, 11867, 57605, 75555}},
+{10347, 17, 39296, {1, 1, 1, 5, 15, 23, 115, 69, 363, 673, 201, 2451, 3197, 10059, 1667, 47145, 89}},
+{10348, 17, 39305, {1, 1, 7, 13, 19, 31, 63, 35, 93, 939, 1057, 3221, 951, 3575, 9659, 7005, 2087}},
+{10349, 17, 39308, {1, 1, 7, 15, 15, 21, 79, 7, 23, 595, 1123, 1909, 6863, 7383, 28067, 30113, 107497}},
+{10350, 17, 39311, {1, 3, 5, 7, 11, 47, 41, 177, 163, 855, 1853, 3837, 6995, 9727, 27285, 62667, 77531}},
+{10351, 17, 39326, {1, 3, 7, 3, 3, 29, 99, 163, 95, 893, 1049, 2001, 2961, 601, 4613, 59745, 61203}},
+{10352, 17, 39329, {1, 3, 5, 1, 27, 5, 5, 47, 119, 631, 1171, 3467, 2115, 8581, 24863, 64193, 52093}},
+{10353, 17, 39330, {1, 1, 1, 5, 9, 51, 49, 251, 97, 177, 311, 993, 1103, 7875, 25273, 51587, 9081}},
+{10354, 17, 39336, {1, 3, 7, 5, 31, 21, 43, 137, 143, 779, 691, 2331, 5073, 5409, 13335, 999, 127765}},
+{10355, 17, 39339, {1, 1, 7, 1, 31, 33, 27, 193, 175, 755, 1559, 659, 5663, 10491, 29209, 50979, 116683}},
+{10356, 17, 39353, {1, 3, 1, 7, 23, 49, 1, 39, 117, 45, 1767, 3503, 4901, 5699, 23613, 44195, 17867}},
+{10357, 17, 39359, {1, 3, 7, 13, 3, 5, 105, 89, 343, 627, 1117, 3419, 2081, 5747, 7919, 44329, 125133}},
+{10358, 17, 39374, {1, 3, 1, 9, 13, 33, 53, 203, 17, 927, 127, 2195, 415, 11301, 15115, 54467, 128777}},
+{10359, 17, 39391, {1, 3, 7, 1, 9, 41, 15, 89, 403, 333, 57, 1159, 1325, 2335, 10609, 20485, 110317}},
+{10360, 17, 39392, {1, 3, 3, 5, 3, 61, 25, 155, 477, 907, 359, 359, 5119, 8157, 29945, 38955, 106485}},
+{10361, 17, 39402, {1, 1, 7, 5, 19, 47, 91, 89, 367, 703, 761, 431, 6813, 2983, 29739, 52453, 125935}},
+{10362, 17, 39409, {1, 1, 1, 7, 7, 61, 127, 239, 277, 649, 1111, 2319, 1737, 5071, 13469, 52119, 48899}},
+{10363, 17, 39410, {1, 3, 5, 15, 7, 17, 21, 209, 265, 895, 719, 263, 6871, 5835, 28483, 49859, 67619}},
+{10364, 17, 39415, {1, 3, 3, 15, 3, 7, 113, 109, 333, 545, 597, 1193, 7593, 3961, 25169, 64673, 47839}},
+{10365, 17, 39419, {1, 1, 1, 3, 15, 45, 55, 41, 317, 719, 1587, 2953, 2441, 1127, 9183, 21637, 69075}},
+{10366, 17, 39431, {1, 3, 1, 9, 25, 57, 59, 29, 89, 833, 379, 1085, 763, 14747, 30797, 24089, 83367}},
+{10367, 17, 39432, {1, 1, 5, 13, 29, 3, 117, 239, 453, 595, 243, 3103, 6047, 631, 22739, 41669, 11683}},
+{10368, 17, 39438, {1, 1, 3, 1, 9, 53, 81, 21, 67, 735, 827, 3519, 7991, 16249, 4183, 61295, 4531}},
+{10369, 17, 39443, {1, 3, 5, 3, 1, 57, 47, 99, 91, 71, 1421, 2949, 5951, 15439, 25239, 26453, 50199}},
+{10370, 17, 39445, {1, 1, 3, 15, 21, 3, 93, 21, 41, 809, 855, 727, 7797, 6957, 15835, 27175, 60617}},
+{10371, 17, 39449, {1, 1, 1, 13, 1, 3, 83, 135, 197, 171, 1459, 2841, 5021, 6961, 30675, 38295, 39555}},
+{10372, 17, 39461, {1, 1, 7, 5, 7, 49, 83, 83, 117, 73, 639, 2717, 651, 3253, 31635, 14427, 116509}},
+{10373, 17, 39462, {1, 3, 1, 3, 23, 63, 15, 23, 433, 539, 903, 2655, 1787, 12901, 12013, 41315, 128217}},
+{10374, 17, 39485, {1, 3, 1, 7, 5, 19, 3, 137, 493, 681, 775, 3725, 4855, 10817, 25277, 3631, 60779}},
+{10375, 17, 39508, {1, 3, 3, 5, 1, 7, 67, 39, 309, 77, 1679, 2853, 3803, 2065, 7461, 1555, 88219}},
+{10376, 17, 39515, {1, 1, 3, 5, 3, 47, 17, 193, 429, 789, 1525, 969, 7905, 6523, 10149, 64689, 40037}},
+{10377, 17, 39522, {1, 3, 5, 7, 21, 17, 65, 61, 255, 517, 1765, 2603, 4929, 11073, 7871, 29313, 84739}},
+{10378, 17, 39533, {1, 1, 5, 7, 13, 55, 111, 63, 499, 9, 1715, 957, 6951, 15839, 13531, 45483, 17923}},
+{10379, 17, 39541, {1, 1, 1, 1, 27, 7, 13, 135, 27, 259, 1735, 3847, 7931, 14777, 15249, 62367, 45773}},
+{10380, 17, 39542, {1, 1, 5, 3, 5, 7, 99, 171, 491, 1007, 195, 2223, 2657, 13557, 6549, 47125, 25117}},
+{10381, 17, 39557, {1, 1, 1, 9, 13, 21, 59, 205, 205, 951, 1707, 3387, 2901, 5463, 13403, 1917, 90591}},
+{10382, 17, 39570, {1, 3, 3, 5, 21, 37, 71, 91, 297, 885, 1415, 355, 2877, 9261, 6485, 45855, 90081}},
+{10383, 17, 39575, {1, 1, 5, 9, 23, 51, 107, 75, 93, 1015, 439, 3589, 3307, 337, 17247, 42285, 85417}},
+{10384, 17, 39576, {1, 1, 7, 15, 29, 33, 51, 23, 269, 35, 1241, 1137, 729, 14531, 14603, 47547, 17151}},
+{10385, 17, 39591, {1, 3, 3, 1, 25, 21, 51, 229, 55, 561, 653, 3289, 7629, 15445, 21115, 35941, 113669}},
+{10386, 17, 39597, {1, 1, 5, 15, 1, 33, 119, 171, 75, 621, 2025, 3235, 1895, 8279, 13205, 61085, 105401}},
+{10387, 17, 39603, {1, 3, 1, 7, 25, 33, 73, 25, 1, 531, 603, 77, 4939, 5957, 28065, 59467, 66659}},
+{10388, 17, 39610, {1, 1, 7, 3, 17, 61, 103, 47, 289, 39, 917, 2515, 6607, 1129, 23361, 46321, 81929}},
+{10389, 17, 39612, {1, 1, 7, 5, 29, 53, 5, 191, 151, 19, 895, 1215, 5401, 9861, 24751, 15481, 34179}},
+{10390, 17, 39617, {1, 3, 7, 9, 5, 3, 29, 205, 173, 547, 727, 947, 5619, 4181, 30621, 5553, 37587}},
+{10391, 17, 39620, {1, 1, 3, 9, 13, 59, 95, 145, 287, 849, 1483, 3375, 3531, 6585, 29565, 4243, 88333}},
+{10392, 17, 39624, {1, 1, 7, 11, 21, 23, 59, 223, 71, 743, 443, 697, 7789, 10371, 28565, 45127, 37967}},
+{10393, 17, 39627, {1, 3, 5, 11, 15, 25, 79, 71, 21, 817, 751, 189, 1769, 3835, 21465, 17991, 102043}},
+{10394, 17, 39635, {1, 1, 7, 11, 3, 19, 25, 5, 261, 181, 49, 261, 7715, 2195, 19771, 43463, 36533}},
+{10395, 17, 39641, {1, 1, 7, 13, 21, 21, 15, 235, 191, 197, 1305, 1351, 4511, 625, 6613, 37053, 59491}},
+{10396, 17, 39666, {1, 1, 1, 13, 15, 13, 93, 239, 251, 1009, 527, 1347, 4173, 14753, 27389, 20397, 13101}},
+{10397, 17, 39668, {1, 1, 3, 1, 15, 11, 127, 141, 277, 775, 1419, 2353, 6929, 2265, 7253, 19807, 74853}},
+{10398, 17, 39686, {1, 3, 3, 15, 15, 49, 9, 183, 407, 377, 675, 871, 347, 3417, 4409, 7805, 40507}},
+{10399, 17, 39692, {1, 3, 5, 3, 23, 11, 81, 53, 343, 681, 1777, 3411, 757, 10875, 3581, 56105, 79907}},
+{10400, 17, 39700, {1, 3, 5, 1, 25, 9, 109, 55, 283, 311, 1607, 2479, 5675, 8819, 10853, 38719, 44471}},
+{10401, 17, 39709, {1, 1, 7, 7, 9, 53, 33, 195, 503, 167, 993, 3203, 3885, 1921, 1039, 25785, 47411}},
+{10402, 17, 39726, {1, 3, 3, 3, 31, 3, 11, 85, 475, 743, 1825, 2649, 2373, 12177, 21481, 35579, 85803}},
+{10403, 17, 39728, {1, 3, 7, 3, 23, 45, 45, 207, 369, 773, 1579, 783, 2491, 7441, 21203, 57091, 107413}},
+{10404, 17, 39737, {1, 1, 1, 5, 19, 7, 97, 213, 431, 533, 637, 1767, 4945, 4693, 977, 64781, 111811}},
+{10405, 17, 39738, {1, 3, 7, 7, 1, 55, 101, 251, 153, 95, 1043, 3219, 3499, 6297, 11571, 9131, 61899}},
+{10406, 17, 39755, {1, 3, 5, 5, 25, 53, 121, 255, 69, 661, 799, 3559, 2029, 11701, 14151, 37897, 18333}},
+{10407, 17, 39757, {1, 1, 1, 9, 21, 19, 97, 21, 321, 957, 1115, 251, 5131, 8465, 24215, 34423, 12747}},
+{10408, 17, 39758, {1, 3, 5, 7, 17, 19, 99, 135, 429, 625, 1401, 1025, 4193, 2911, 7349, 34135, 9341}},
+{10409, 17, 39765, {1, 3, 5, 1, 5, 63, 97, 121, 307, 547, 1967, 641, 487, 4627, 30899, 62049, 94343}},
+{10410, 17, 39766, {1, 3, 5, 13, 1, 1, 109, 23, 267, 843, 271, 2277, 855, 4245, 2177, 33633, 113835}},
+{10411, 17, 39769, {1, 1, 3, 7, 3, 27, 91, 79, 27, 855, 2025, 443, 4797, 9005, 27533, 20497, 100431}},
+{10412, 17, 39779, {1, 3, 3, 5, 23, 7, 73, 35, 395, 649, 881, 2923, 4065, 853, 10829, 19461, 82383}},
+{10413, 17, 39785, {1, 3, 1, 5, 25, 13, 85, 93, 369, 259, 393, 3233, 799, 12409, 26631, 64291, 110133}},
+{10414, 17, 39794, {1, 3, 5, 5, 31, 35, 25, 239, 455, 893, 573, 1449, 3359, 12077, 17149, 12921, 66931}},
+{10415, 17, 39796, {1, 1, 7, 3, 25, 39, 67, 87, 215, 325, 627, 3609, 4417, 10021, 12047, 64593, 116525}},
+{10416, 17, 39809, {1, 1, 5, 5, 23, 51, 125, 247, 83, 419, 655, 635, 7053, 4907, 12887, 18083, 49481}},
+{10417, 17, 39815, {1, 1, 7, 11, 5, 25, 65, 139, 235, 331, 1885, 1851, 1061, 13265, 14371, 23067, 56757}},
+{10418, 17, 39829, {1, 1, 7, 9, 11, 15, 29, 255, 509, 869, 561, 2201, 487, 2989, 14943, 65373, 35789}},
+{10419, 17, 39834, {1, 1, 1, 3, 3, 33, 23, 121, 129, 351, 1481, 65, 321, 15927, 23849, 2813, 98547}},
+{10420, 17, 39839, {1, 1, 1, 3, 23, 55, 121, 35, 339, 87, 1147, 401, 1477, 10617, 15943, 20535, 89321}},
+{10421, 17, 39850, {1, 3, 5, 15, 25, 59, 111, 185, 305, 47, 523, 2801, 5485, 625, 30191, 58153, 9019}},
+{10422, 17, 39857, {1, 1, 7, 13, 15, 51, 105, 55, 77, 419, 1011, 1117, 2705, 15093, 15629, 51429, 58487}},
+{10423, 17, 39881, {1, 3, 7, 5, 15, 27, 19, 7, 401, 295, 1841, 1167, 2133, 1967, 6941, 13571, 29467}},
+{10424, 17, 39905, {1, 1, 5, 15, 25, 43, 23, 253, 173, 927, 1299, 2779, 5489, 16135, 1503, 51097, 105751}},
+{10425, 17, 39912, {1, 3, 3, 5, 9, 13, 5, 13, 411, 639, 1323, 1495, 2539, 15087, 21489, 49653, 76229}},
+{10426, 17, 39938, {1, 1, 1, 11, 7, 51, 47, 99, 247, 541, 1355, 2373, 4121, 13621, 7715, 16763, 127985}},
+{10427, 17, 39940, {1, 1, 3, 9, 7, 1, 85, 45, 269, 769, 581, 2229, 7143, 5203, 22483, 18511, 30997}},
+{10428, 17, 39944, {1, 3, 5, 7, 21, 41, 97, 225, 109, 195, 1197, 3417, 7613, 13225, 29157, 18969, 82045}},
+{10429, 17, 39955, {1, 3, 3, 3, 17, 41, 13, 77, 129, 679, 1659, 1299, 4809, 8537, 19081, 1281, 70793}},
+{10430, 17, 39961, {1, 1, 5, 5, 5, 49, 5, 15, 313, 941, 775, 259, 6579, 7745, 20531, 51669, 35257}},
+{10431, 17, 39977, {1, 1, 5, 5, 17, 35, 13, 235, 169, 699, 1365, 3907, 4231, 10965, 7737, 6735, 4253}},
+{10432, 17, 39980, {1, 1, 5, 3, 29, 3, 1, 197, 133, 935, 571, 3977, 2467, 2029, 12803, 64559, 6427}},
+{10433, 17, 39986, {1, 3, 5, 5, 27, 5, 69, 57, 439, 925, 1695, 827, 4685, 10971, 3011, 56821, 92187}},
+{10434, 17, 39988, {1, 1, 1, 3, 9, 45, 77, 179, 173, 1023, 907, 1999, 3913, 6973, 26987, 30237, 62987}},
+{10435, 17, 39991, {1, 3, 7, 3, 5, 21, 17, 97, 433, 277, 1515, 2923, 8025, 14119, 11243, 3983, 33943}},
+{10436, 17, 39998, {1, 1, 5, 7, 15, 13, 119, 169, 21, 927, 439, 361, 2655, 2237, 19775, 4157, 84245}},
+{10437, 17, 40003, {1, 3, 5, 5, 31, 41, 117, 159, 421, 505, 1617, 3855, 7835, 8105, 29525, 56735, 82335}},
+{10438, 17, 40005, {1, 1, 5, 5, 1, 33, 51, 3, 79, 933, 389, 493, 5969, 12493, 26723, 61159, 116951}},
+{10439, 17, 40023, {1, 3, 7, 13, 17, 23, 75, 13, 355, 111, 675, 3191, 3931, 5651, 17495, 4595, 49869}},
+{10440, 17, 40024, {1, 1, 7, 7, 15, 21, 35, 125, 89, 903, 697, 3493, 4043, 6631, 4793, 45655, 86969}},
+{10441, 17, 40045, {1, 3, 1, 15, 13, 43, 113, 213, 451, 473, 191, 2913, 6391, 1321, 29615, 24791, 26979}},
+{10442, 17, 40046, {1, 3, 3, 13, 17, 25, 9, 163, 163, 161, 1647, 3949, 1343, 12881, 10931, 31365, 70013}},
+{10443, 17, 40058, {1, 3, 7, 3, 3, 19, 1, 121, 387, 543, 1655, 1797, 6727, 2951, 21925, 21595, 73207}},
+{10444, 17, 40088, {1, 1, 5, 9, 7, 19, 91, 9, 83, 893, 1393, 163, 2219, 7763, 32395, 29569, 98645}},
+{10445, 17, 40091, {1, 1, 5, 7, 13, 63, 91, 115, 247, 387, 87, 3239, 7561, 297, 32615, 48817, 41761}},
+{10446, 17, 40098, {1, 3, 5, 3, 21, 23, 27, 141, 257, 377, 1745, 443, 897, 9033, 1715, 9225, 110181}},
+{10447, 17, 40109, {1, 1, 7, 9, 23, 49, 125, 131, 225, 253, 139, 2057, 3273, 4049, 6861, 4463, 11659}},
+{10448, 17, 40112, {1, 1, 5, 11, 5, 41, 97, 213, 133, 481, 2009, 2039, 1533, 10765, 22427, 23297, 80661}},
+{10449, 17, 40124, {1, 1, 5, 15, 9, 11, 77, 129, 421, 219, 1623, 703, 1611, 13377, 9859, 42869, 101943}},
+{10450, 17, 40130, {1, 3, 3, 3, 17, 63, 55, 29, 317, 973, 1159, 11, 1733, 14551, 25911, 39151, 45861}},
+{10451, 17, 40153, {1, 3, 7, 11, 29, 63, 107, 193, 263, 799, 1171, 543, 553, 12591, 21965, 8165, 64347}},
+{10452, 17, 40166, {1, 1, 7, 15, 23, 49, 65, 65, 401, 897, 681, 1113, 6737, 9157, 1557, 55891, 129175}},
+{10453, 17, 40175, {1, 3, 3, 1, 15, 23, 107, 123, 313, 633, 1009, 2615, 1155, 11701, 21945, 7939, 28111}},
+{10454, 17, 40183, {1, 3, 1, 11, 15, 11, 47, 137, 299, 393, 877, 1989, 5903, 6505, 9599, 4129, 23073}},
+{10455, 17, 40184, {1, 1, 7, 15, 9, 49, 67, 15, 79, 125, 505, 17, 8071, 12957, 13855, 23611, 66465}},
+{10456, 17, 40207, {1, 1, 5, 13, 31, 49, 1, 161, 121, 145, 711, 1347, 5297, 11309, 9871, 43075, 95541}},
+{10457, 17, 40215, {1, 3, 3, 13, 19, 7, 55, 199, 469, 471, 1269, 3779, 6251, 3513, 1775, 19501, 94055}},
+{10458, 17, 40225, {1, 3, 3, 13, 9, 41, 109, 211, 197, 227, 1211, 3327, 1247, 12253, 4493, 31507, 38677}},
+{10459, 17, 40235, {1, 1, 7, 3, 11, 45, 11, 103, 325, 849, 1817, 3971, 1059, 9047, 27237, 32211, 121165}},
+{10460, 17, 40240, {1, 3, 3, 3, 13, 43, 7, 35, 293, 3, 679, 1441, 5189, 7585, 32009, 6151, 89803}},
+{10461, 17, 40255, {1, 1, 7, 9, 29, 41, 127, 255, 363, 913, 2027, 3891, 5187, 10233, 8871, 48085, 125609}},
+{10462, 17, 40263, {1, 3, 1, 5, 21, 23, 59, 145, 171, 775, 535, 3803, 6981, 15901, 20255, 63199, 92905}},
+{10463, 17, 40270, {1, 3, 5, 9, 7, 63, 53, 7, 145, 547, 1753, 3351, 1273, 8175, 24103, 42133, 87459}},
+{10464, 17, 40277, {1, 3, 7, 7, 25, 33, 5, 217, 469, 473, 1573, 2525, 7345, 5261, 7023, 50893, 124129}},
+{10465, 17, 40282, {1, 3, 5, 13, 5, 51, 23, 61, 429, 775, 519, 2671, 1979, 9005, 21617, 33611, 120487}},
+{10466, 17, 40297, {1, 3, 3, 15, 23, 1, 73, 187, 47, 369, 943, 99, 2529, 5569, 13649, 51481, 128949}},
+{10467, 17, 40306, {1, 3, 1, 5, 25, 55, 35, 191, 327, 845, 1353, 261, 6297, 6067, 22241, 32381, 17749}},
+{10468, 17, 40315, {1, 1, 5, 15, 31, 5, 29, 129, 15, 47, 739, 755, 7595, 14743, 14705, 34347, 11805}},
+{10469, 17, 40333, {1, 3, 1, 3, 15, 49, 119, 47, 185, 63, 2003, 2847, 5393, 855, 7699, 29521, 67011}},
+{10470, 17, 40334, {1, 3, 7, 15, 11, 41, 37, 149, 173, 1015, 29, 1805, 1269, 16199, 32337, 11023, 60065}},
+{10471, 17, 40336, {1, 1, 1, 7, 31, 19, 65, 81, 255, 875, 1379, 2347, 1873, 14427, 29523, 38413, 65583}},
+{10472, 17, 40342, {1, 1, 1, 15, 13, 59, 3, 219, 127, 479, 1029, 3385, 563, 11825, 10081, 17423, 26431}},
+{10473, 17, 40345, {1, 1, 1, 1, 25, 27, 79, 87, 489, 281, 457, 3527, 5117, 4705, 21167, 46211, 90383}},
+{10474, 17, 40348, {1, 3, 7, 13, 7, 5, 67, 111, 53, 439, 1483, 3639, 7781, 9471, 10957, 60711, 64957}},
+{10475, 17, 40355, {1, 3, 7, 9, 7, 7, 41, 137, 159, 245, 551, 4007, 1277, 4743, 4863, 48689, 123289}},
+{10476, 17, 40372, {1, 3, 7, 9, 15, 49, 55, 77, 41, 475, 1563, 3569, 5993, 301, 14831, 44095, 22641}},
+{10477, 17, 40381, {1, 1, 1, 1, 15, 33, 39, 135, 81, 533, 869, 305, 1125, 6399, 14321, 37217, 121081}},
+{10478, 17, 40390, {1, 1, 7, 15, 21, 59, 43, 7, 225, 1, 115, 1531, 2931, 2593, 15935, 61973, 106899}},
+{10479, 17, 40407, {1, 1, 1, 1, 13, 13, 99, 191, 437, 367, 641, 1933, 5807, 11677, 13557, 46475, 34875}},
+{10480, 17, 40435, {1, 3, 7, 9, 21, 7, 119, 209, 31, 919, 901, 1229, 5823, 11439, 18151, 18991, 114743}},
+{10481, 17, 40437, {1, 3, 3, 3, 19, 37, 109, 53, 411, 617, 1841, 2769, 1271, 5719, 22359, 1199, 72405}},
+{10482, 17, 40441, {1, 1, 1, 5, 29, 3, 51, 59, 141, 897, 1907, 3799, 1463, 5661, 181, 50565, 95085}},
+{10483, 17, 40444, {1, 1, 1, 7, 1, 35, 77, 225, 341, 587, 137, 35, 2177, 15177, 12869, 35013, 39471}},
+{10484, 17, 40458, {1, 1, 3, 13, 15, 63, 45, 33, 337, 1, 1133, 263, 4985, 11591, 1085, 31197, 67897}},
+{10485, 17, 40460, {1, 1, 5, 13, 23, 11, 123, 21, 185, 639, 145, 3865, 2999, 6261, 23247, 23055, 32755}},
+{10486, 17, 40481, {1, 1, 5, 9, 19, 21, 47, 133, 281, 431, 1661, 3719, 3637, 973, 9727, 52627, 60035}},
+{10487, 17, 40484, {1, 1, 3, 5, 3, 19, 19, 89, 63, 549, 551, 3357, 5665, 4781, 22437, 1149, 10825}},
+{10488, 17, 40487, {1, 3, 5, 15, 3, 25, 81, 193, 11, 711, 1481, 1767, 1159, 4967, 16915, 3387, 26245}},
+{10489, 17, 40493, {1, 1, 1, 3, 29, 39, 23, 131, 473, 107, 765, 2249, 6087, 9145, 20751, 21085, 42989}},
+{10490, 17, 40494, {1, 3, 1, 9, 7, 39, 13, 199, 475, 333, 269, 1041, 5927, 14039, 19081, 9045, 119645}},
+{10491, 17, 40501, {1, 1, 5, 13, 11, 61, 99, 71, 151, 175, 1327, 3397, 5063, 10683, 7895, 62255, 85749}},
+{10492, 17, 40502, {1, 3, 7, 9, 1, 57, 21, 217, 423, 467, 1435, 2887, 1567, 8819, 19961, 36507, 110309}},
+{10493, 17, 40525, {1, 3, 3, 11, 11, 35, 77, 127, 153, 357, 865, 1943, 1947, 10995, 13617, 44347, 26851}},
+{10494, 17, 40550, {1, 3, 1, 11, 9, 43, 31, 81, 123, 813, 995, 169, 6593, 13621, 32195, 51125, 53509}},
+{10495, 17, 40553, {1, 1, 5, 5, 27, 29, 77, 35, 93, 545, 377, 2345, 6475, 15729, 15103, 49591, 101121}},
+{10496, 17, 40559, {1, 1, 5, 13, 1, 17, 97, 187, 129, 173, 641, 2937, 3277, 15087, 28111, 46905, 112367}},
+{10497, 17, 40562, {1, 3, 7, 7, 1, 27, 75, 43, 305, 431, 571, 1327, 7419, 3093, 2691, 23417, 11975}},
+{10498, 17, 40573, {1, 1, 5, 15, 17, 3, 91, 57, 417, 87, 1891, 1973, 5765, 5521, 21931, 60011, 20883}},
+{10499, 17, 40574, {1, 3, 1, 3, 27, 13, 105, 153, 495, 371, 453, 1295, 5675, 6377, 8971, 40505, 41149}},
+{10500, 17, 40578, {1, 1, 1, 15, 1, 17, 105, 177, 41, 455, 611, 3585, 2307, 2603, 20985, 5581, 14033}},
+{10501, 17, 40583, {1, 3, 3, 9, 7, 41, 33, 145, 307, 293, 1321, 2151, 3265, 14845, 15687, 38715, 8041}},
+{10502, 17, 40584, {1, 3, 3, 3, 5, 47, 127, 253, 129, 337, 1467, 5, 2743, 1921, 26979, 11737, 41479}},
+{10503, 17, 40587, {1, 1, 1, 5, 15, 35, 37, 9, 5, 405, 1041, 1903, 3655, 14315, 9441, 20577, 50715}},
+{10504, 17, 40597, {1, 1, 5, 15, 7, 5, 53, 61, 409, 353, 87, 1805, 4523, 11417, 24105, 21451, 56387}},
+{10505, 17, 40620, {1, 3, 3, 5, 5, 9, 25, 249, 511, 795, 559, 2695, 3071, 3971, 29421, 46593, 96563}},
+{10506, 17, 40623, {1, 1, 3, 1, 3, 39, 61, 85, 399, 105, 1253, 3787, 3065, 10553, 8195, 5637, 129579}},
+{10507, 17, 40631, {1, 3, 3, 7, 23, 23, 23, 197, 263, 687, 943, 1977, 5767, 15373, 17995, 24509, 81293}},
+{10508, 17, 40643, {1, 3, 1, 11, 15, 37, 15, 67, 207, 985, 895, 509, 3435, 11563, 2055, 19253, 42649}},
+{10509, 17, 40660, {1, 1, 7, 3, 1, 51, 59, 133, 241, 569, 1575, 3633, 2243, 11939, 5501, 11249, 86013}},
+{10510, 17, 40667, {1, 1, 7, 13, 25, 59, 97, 191, 385, 179, 1195, 1537, 1837, 11953, 14231, 37025, 49803}},
+{10511, 17, 40676, {1, 3, 5, 5, 13, 49, 19, 171, 503, 433, 1633, 553, 2759, 4379, 18313, 62437, 37453}},
+{10512, 17, 40693, {1, 3, 3, 15, 29, 49, 107, 239, 21, 913, 1095, 989, 4749, 10657, 27169, 15913, 1573}},
+{10513, 17, 40697, {1, 1, 1, 1, 3, 3, 53, 241, 287, 149, 557, 2665, 2027, 449, 29231, 23025, 102521}},
+{10514, 17, 40708, {1, 3, 5, 7, 23, 21, 9, 1, 11, 837, 1337, 2815, 7883, 16053, 10031, 43405, 5037}},
+{10515, 17, 40718, {1, 3, 7, 1, 23, 53, 113, 125, 337, 491, 1125, 3083, 4941, 951, 15805, 1571, 79779}},
+{10516, 17, 40726, {1, 3, 7, 13, 1, 3, 95, 105, 431, 723, 1771, 3773, 177, 2045, 24719, 57727, 79005}},
+{10517, 17, 40735, {1, 3, 1, 1, 7, 17, 107, 171, 213, 437, 409, 2015, 7543, 12693, 23597, 44477, 72543}},
+{10518, 17, 40739, {1, 3, 5, 9, 7, 21, 27, 167, 473, 901, 1245, 3737, 3485, 14593, 7619, 18753, 14209}},
+{10519, 17, 40748, {1, 1, 1, 3, 25, 37, 51, 21, 363, 73, 711, 3749, 5147, 8495, 30151, 14275, 128217}},
+{10520, 17, 40760, {1, 3, 1, 13, 17, 35, 69, 15, 293, 331, 301, 691, 7315, 6495, 315, 62909, 105047}},
+{10521, 17, 40763, {1, 3, 5, 3, 25, 23, 105, 111, 213, 887, 1701, 2085, 5931, 9217, 4009, 2321, 103631}},
+{10522, 17, 40773, {1, 1, 7, 15, 17, 57, 59, 249, 267, 941, 777, 2509, 6587, 12033, 24969, 31563, 129049}},
+{10523, 17, 40774, {1, 1, 1, 5, 31, 23, 31, 217, 509, 973, 659, 673, 7759, 3865, 21221, 4319, 117411}},
+{10524, 17, 40786, {1, 1, 3, 7, 13, 13, 103, 179, 107, 233, 753, 3121, 835, 13595, 9271, 31421, 45275}},
+{10525, 17, 40791, {1, 3, 5, 13, 23, 61, 125, 189, 283, 83, 1087, 755, 3697, 14845, 27901, 16389, 82993}},
+{10526, 17, 40798, {1, 3, 1, 3, 1, 55, 25, 139, 435, 681, 1913, 975, 3109, 6699, 12943, 50865, 71811}},
+{10527, 17, 40801, {1, 3, 1, 5, 15, 61, 17, 219, 29, 805, 1881, 3761, 3535, 473, 15629, 26301, 51085}},
+{10528, 17, 40808, {1, 3, 1, 1, 7, 43, 87, 93, 355, 247, 641, 2851, 4565, 9293, 6025, 1945, 112549}},
+{10529, 17, 40811, {1, 3, 7, 5, 19, 55, 69, 227, 107, 443, 1587, 2457, 2873, 953, 27529, 57527, 54145}},
+{10530, 17, 40813, {1, 1, 5, 9, 1, 33, 31, 241, 339, 791, 399, 3435, 1711, 10815, 32657, 59875, 31291}},
+{10531, 17, 40825, {1, 1, 1, 7, 25, 59, 87, 115, 435, 47, 1907, 193, 6069, 10933, 9877, 46443, 3451}},
+{10532, 17, 40831, {1, 3, 3, 15, 25, 33, 19, 121, 133, 253, 1227, 75, 2839, 3341, 30727, 52451, 44883}},
+{10533, 17, 40835, {1, 1, 7, 11, 5, 47, 97, 255, 235, 565, 1701, 529, 839, 15473, 24471, 5749, 73135}},
+{10534, 17, 40856, {1, 1, 3, 7, 21, 15, 31, 81, 389, 957, 603, 3879, 2875, 11987, 24625, 53667, 77775}},
+{10535, 17, 40861, {1, 1, 5, 11, 29, 29, 31, 233, 107, 541, 561, 2533, 1421, 13587, 6943, 45635, 71315}},
+{10536, 17, 40880, {1, 3, 1, 9, 25, 19, 33, 53, 509, 485, 1637, 2877, 5927, 16059, 195, 17279, 127025}},
+{10537, 17, 40889, {1, 1, 1, 3, 9, 23, 97, 101, 337, 43, 1979, 1139, 3693, 2601, 8225, 53037, 63709}},
+{10538, 17, 40912, {1, 1, 7, 7, 17, 25, 121, 253, 63, 105, 527, 1397, 121, 9665, 29151, 10795, 79077}},
+{10539, 17, 40918, {1, 3, 3, 1, 27, 33, 123, 69, 209, 25, 1677, 1569, 4441, 7817, 5165, 29517, 117165}},
+{10540, 17, 40924, {1, 1, 5, 15, 3, 59, 13, 25, 359, 71, 179, 3925, 6899, 6007, 9121, 36297, 88541}},
+{10541, 17, 40927, {1, 1, 3, 11, 23, 17, 55, 133, 27, 277, 1055, 1057, 807, 1221, 1665, 64129, 102395}},
+{10542, 17, 40928, {1, 3, 1, 15, 13, 15, 105, 141, 329, 73, 609, 1663, 3277, 1767, 6371, 34325, 109563}},
+{10543, 17, 40938, {1, 1, 5, 1, 17, 21, 37, 81, 187, 403, 291, 1495, 5071, 14289, 29075, 44089, 95001}},
+{10544, 17, 40952, {1, 3, 3, 3, 15, 33, 49, 155, 41, 853, 15, 3571, 1433, 8469, 18711, 59007, 98703}},
+{10545, 17, 40957, {1, 3, 1, 13, 17, 47, 61, 151, 127, 87, 207, 3157, 5141, 14745, 32567, 18401, 7497}},
+{10546, 17, 40961, {1, 3, 5, 1, 19, 25, 49, 147, 137, 603, 1223, 3195, 5965, 11335, 20343, 10109, 63975}},
+{10547, 17, 40968, {1, 1, 7, 13, 29, 59, 1, 33, 157, 765, 961, 641, 7303, 3279, 20287, 37553, 114573}},
+{10548, 17, 40974, {1, 3, 5, 1, 11, 63, 63, 41, 15, 717, 1037, 227, 7875, 8681, 26943, 11761, 28005}},
+{10549, 17, 40986, {1, 3, 1, 3, 19, 5, 67, 169, 209, 293, 343, 2033, 7669, 1077, 15513, 54475, 15459}},
+{10550, 17, 40992, {1, 1, 3, 3, 17, 47, 49, 187, 341, 767, 1463, 301, 2083, 9265, 12313, 14763, 126627}},
+{10551, 17, 41001, {1, 3, 5, 13, 11, 15, 45, 237, 445, 55, 319, 2989, 5043, 1053, 22809, 23111, 7617}},
+{10552, 17, 41004, {1, 1, 7, 9, 7, 15, 41, 185, 511, 701, 1279, 1995, 7829, 2947, 3431, 45799, 1709}},
+{10553, 17, 41022, {1, 3, 7, 15, 5, 15, 85, 29, 487, 811, 1653, 483, 1193, 11331, 21815, 57215, 8373}},
+{10554, 17, 41033, {1, 3, 1, 15, 27, 19, 111, 161, 19, 373, 419, 1547, 2415, 10705, 17283, 56663, 73625}},
+{10555, 17, 41036, {1, 1, 3, 11, 27, 7, 75, 57, 411, 35, 685, 1249, 5227, 7313, 3167, 30537, 40655}},
+{10556, 17, 41039, {1, 3, 1, 9, 7, 37, 9, 209, 353, 319, 843, 657, 2069, 6523, 611, 16291, 107121}},
+{10557, 17, 41044, {1, 1, 5, 11, 11, 51, 25, 171, 315, 63, 207, 2279, 2379, 3583, 31927, 62451, 109911}},
+{10558, 17, 41064, {1, 1, 7, 11, 15, 41, 19, 175, 103, 605, 1889, 3161, 1217, 3259, 29655, 11715, 35551}},
+{10559, 17, 41078, {1, 3, 5, 13, 23, 11, 121, 147, 179, 397, 659, 3753, 2355, 1093, 25863, 39751, 112381}},
+{10560, 17, 41091, {1, 3, 5, 7, 1, 23, 37, 117, 7, 361, 991, 661, 4427, 15333, 5307, 55171, 96959}},
+{10561, 17, 41103, {1, 3, 1, 5, 17, 9, 77, 147, 289, 79, 295, 1271, 7809, 6387, 31785, 26489, 9335}},
+{10562, 17, 41108, {1, 1, 1, 7, 17, 33, 63, 147, 17, 515, 1349, 1907, 7703, 5511, 27773, 54025, 30019}},
+{10563, 17, 41112, {1, 3, 5, 3, 27, 57, 75, 129, 219, 533, 207, 3569, 5799, 6943, 12271, 53115, 120389}},
+{10564, 17, 41127, {1, 1, 1, 13, 11, 25, 101, 251, 289, 215, 1875, 1821, 703, 15395, 27167, 43187, 63401}},
+{10565, 17, 41128, {1, 1, 7, 15, 7, 39, 125, 41, 57, 513, 17, 965, 3225, 12833, 21131, 53243, 60377}},
+{10566, 17, 41136, {1, 3, 5, 3, 21, 19, 43, 195, 259, 523, 587, 3393, 6621, 43, 10951, 51877, 79967}},
+{10567, 17, 41141, {1, 3, 3, 7, 7, 19, 11, 89, 321, 821, 99, 2201, 1297, 949, 11539, 6295, 19721}},
+{10568, 17, 41146, {1, 1, 5, 3, 29, 27, 123, 111, 441, 441, 337, 3849, 1677, 14403, 17203, 50661, 92177}},
+{10569, 17, 41156, {1, 3, 5, 9, 23, 23, 73, 153, 241, 841, 371, 1503, 5815, 14117, 4679, 17997, 112269}},
+{10570, 17, 41159, {1, 1, 1, 1, 7, 37, 105, 185, 453, 905, 15, 57, 6963, 9665, 3371, 2391, 96023}},
+{10571, 17, 41163, {1, 3, 7, 1, 1, 21, 35, 43, 449, 111, 191, 2163, 3249, 15049, 30215, 43569, 127973}},
+{10572, 17, 41165, {1, 3, 3, 3, 17, 13, 77, 123, 471, 929, 1797, 2061, 355, 4441, 1101, 24631, 128711}},
+{10573, 17, 41166, {1, 3, 7, 7, 17, 51, 1, 69, 23, 1003, 535, 3751, 765, 5253, 21027, 52901, 61951}},
+{10574, 17, 41184, {1, 1, 7, 9, 25, 13, 33, 13, 423, 787, 223, 729, 4443, 227, 11487, 14259, 52951}},
+{10575, 17, 41193, {1, 3, 5, 5, 25, 27, 113, 93, 13, 679, 1295, 3773, 7253, 14629, 8907, 45885, 85387}},
+{10576, 17, 41202, {1, 3, 3, 13, 15, 55, 99, 31, 119, 955, 1477, 3745, 6777, 973, 4723, 62133, 65093}},
+{10577, 17, 41211, {1, 3, 3, 9, 13, 51, 105, 37, 477, 579, 765, 2573, 6869, 3891, 30969, 63413, 56603}},
+{10578, 17, 41216, {1, 3, 1, 3, 15, 23, 67, 109, 75, 721, 523, 1433, 3455, 6377, 23795, 13711, 121349}},
+{10579, 17, 41239, {1, 1, 3, 11, 5, 5, 99, 117, 233, 621, 509, 3235, 7483, 12325, 13203, 20075, 27537}},
+{10580, 17, 41243, {1, 3, 3, 9, 23, 51, 93, 245, 307, 689, 1993, 3607, 1985, 11839, 25553, 54941, 68741}},
+{10581, 17, 41249, {1, 1, 3, 5, 19, 21, 33, 71, 447, 539, 351, 2549, 87, 4317, 1287, 62289, 121065}},
+{10582, 17, 41262, {1, 3, 5, 5, 9, 23, 37, 189, 449, 263, 37, 3127, 1709, 10793, 7379, 38565, 8267}},
+{10583, 17, 41267, {1, 1, 7, 7, 7, 33, 23, 79, 457, 947, 1275, 2755, 3747, 9225, 31385, 8785, 76945}},
+{10584, 17, 41276, {1, 3, 1, 9, 17, 33, 29, 59, 505, 649, 1679, 3609, 1361, 5987, 26455, 17295, 98697}},
+{10585, 17, 41279, {1, 1, 3, 11, 7, 47, 127, 79, 419, 143, 349, 985, 6397, 10271, 29427, 19661, 32629}},
+{10586, 17, 41305, {1, 1, 5, 13, 15, 5, 79, 171, 491, 223, 1601, 705, 623, 4405, 10065, 28057, 105737}},
+{10587, 17, 41306, {1, 1, 7, 3, 29, 7, 81, 69, 265, 669, 1763, 2109, 6275, 7683, 19561, 26737, 54449}},
+{10588, 17, 41312, {1, 1, 1, 7, 1, 1, 5, 9, 65, 487, 1663, 1021, 1819, 9971, 22065, 40407, 4187}},
+{10589, 17, 41317, {1, 3, 5, 5, 21, 33, 11, 213, 309, 575, 427, 1421, 6435, 981, 31533, 16751, 47813}},
+{10590, 17, 41321, {1, 3, 3, 13, 7, 59, 65, 65, 401, 195, 211, 421, 1139, 11729, 19717, 20699, 111863}},
+{10591, 17, 41332, {1, 3, 7, 5, 17, 51, 25, 217, 223, 935, 431, 1703, 4869, 5635, 199, 5485, 37311}},
+{10592, 17, 41335, {1, 1, 3, 11, 23, 25, 15, 37, 187, 1007, 857, 3327, 5471, 10089, 13745, 1741, 37769}},
+{10593, 17, 41345, {1, 3, 5, 15, 31, 17, 75, 125, 1, 449, 1293, 3427, 709, 8285, 31143, 50655, 130793}},
+{10594, 17, 41346, {1, 1, 7, 3, 25, 55, 105, 255, 319, 183, 1571, 2425, 5429, 7151, 8569, 37447, 23055}},
+{10595, 17, 41351, {1, 3, 1, 1, 23, 37, 17, 61, 161, 559, 1025, 2651, 5861, 5231, 1365, 4853, 127301}},
+{10596, 17, 41365, {1, 3, 1, 9, 17, 37, 87, 241, 411, 53, 1555, 3805, 6867, 125, 9829, 53581, 117413}},
+{10597, 17, 41388, {1, 3, 3, 3, 23, 55, 121, 109, 441, 623, 1345, 3055, 2591, 11329, 16891, 61347, 125643}},
+{10598, 17, 41399, {1, 3, 1, 1, 5, 29, 53, 97, 15, 275, 1587, 1245, 379, 16117, 24369, 26873, 39547}},
+{10599, 17, 41405, {1, 3, 1, 5, 3, 63, 85, 167, 301, 45, 1357, 1185, 3939, 945, 24961, 59427, 128129}},
+{10600, 17, 41414, {1, 3, 1, 7, 23, 25, 109, 253, 37, 151, 17, 1241, 787, 15895, 7947, 65071, 14765}},
+{10601, 17, 41432, {1, 3, 3, 1, 7, 3, 103, 35, 73, 533, 1055, 823, 7403, 8117, 28813, 42457, 56037}},
+{10602, 17, 41454, {1, 3, 5, 15, 1, 15, 97, 109, 293, 259, 935, 2977, 5257, 14563, 28871, 17647, 34185}},
+{10603, 17, 41461, {1, 1, 1, 3, 29, 21, 101, 163, 173, 1019, 1025, 553, 945, 3781, 1097, 58025, 124819}},
+{10604, 17, 41462, {1, 1, 3, 9, 7, 35, 65, 61, 31, 547, 75, 3515, 6719, 12809, 23287, 14609, 30341}},
+{10605, 17, 41471, {1, 3, 7, 9, 3, 53, 21, 207, 383, 917, 1383, 2873, 1663, 15665, 1787, 50741, 35145}},
+{10606, 17, 41478, {1, 3, 7, 5, 3, 35, 113, 191, 171, 635, 1597, 2943, 2421, 5555, 6457, 22087, 104221}},
+{10607, 17, 41490, {1, 1, 1, 1, 29, 25, 3, 225, 175, 807, 1325, 215, 6475, 10729, 18619, 45401, 20627}},
+{10608, 17, 41506, {1, 1, 5, 11, 23, 25, 39, 207, 81, 633, 403, 3369, 1295, 1289, 20853, 48899, 16613}},
+{10609, 17, 41508, {1, 1, 7, 15, 5, 23, 17, 77, 169, 969, 1459, 3795, 3121, 5501, 32323, 46743, 124175}},
+{10610, 17, 41512, {1, 1, 7, 13, 3, 25, 77, 153, 105, 1017, 1599, 237, 4691, 1993, 6707, 50265, 13529}},
+{10611, 17, 41517, {1, 3, 3, 15, 7, 11, 81, 223, 61, 589, 1263, 3999, 7643, 12101, 19853, 49279, 29999}},
+{10612, 17, 41520, {1, 3, 1, 13, 3, 31, 61, 59, 41, 313, 115, 561, 3973, 13513, 6359, 29395, 34565}},
+{10613, 17, 41529, {1, 1, 7, 7, 7, 61, 91, 181, 307, 875, 2045, 1367, 3743, 6497, 2443, 12153, 96431}},
+{10614, 17, 41530, {1, 1, 3, 7, 19, 63, 97, 211, 157, 945, 891, 3747, 5483, 3081, 28939, 11179, 15935}},
+{10615, 17, 41544, {1, 3, 7, 3, 23, 39, 51, 137, 91, 179, 1515, 1397, 2783, 9343, 11483, 52407, 111725}},
+{10616, 17, 41550, {1, 3, 3, 11, 11, 25, 111, 61, 115, 329, 485, 1713, 565, 8607, 18869, 6595, 18605}},
+{10617, 17, 41571, {1, 1, 5, 1, 13, 59, 67, 231, 443, 695, 1185, 393, 6393, 12957, 15817, 37219, 113127}},
+{10618, 17, 41577, {1, 3, 5, 3, 15, 57, 25, 97, 321, 627, 15, 2005, 3813, 10399, 26779, 24243, 66463}},
+{10619, 17, 41580, {1, 3, 7, 7, 17, 43, 117, 179, 447, 1005, 2007, 1753, 7685, 13331, 5187, 49341, 111927}},
+{10620, 17, 41595, {1, 1, 3, 3, 5, 53, 35, 185, 93, 847, 1523, 3039, 25, 3351, 23195, 41133, 38547}},
+{10621, 17, 41613, {1, 1, 7, 5, 27, 59, 95, 137, 55, 129, 331, 127, 7421, 5633, 557, 18137, 89055}},
+{10622, 17, 41622, {1, 3, 3, 11, 5, 53, 93, 137, 175, 191, 1645, 2047, 2569, 8177, 22691, 4037, 31823}},
+{10623, 17, 41635, {1, 3, 3, 11, 11, 45, 77, 7, 21, 541, 49, 1689, 171, 829, 28917, 45095, 1807}},
+{10624, 17, 41642, {1, 3, 7, 5, 21, 5, 113, 81, 33, 681, 361, 1107, 1597, 115, 11503, 27413, 9199}},
+{10625, 17, 41661, {1, 1, 3, 11, 29, 57, 15, 249, 105, 683, 833, 2579, 3517, 16153, 17373, 32587, 124333}},
+{10626, 17, 41676, {1, 3, 7, 13, 3, 35, 55, 23, 293, 5, 2003, 2741, 4237, 8117, 20569, 63967, 106041}},
+{10627, 17, 41681, {1, 3, 3, 1, 1, 15, 57, 119, 135, 967, 1495, 801, 4959, 5037, 10051, 53915, 116891}},
+{10628, 17, 41684, {1, 1, 7, 9, 15, 29, 53, 139, 505, 473, 1179, 3289, 369, 13147, 15739, 16739, 54949}},
+{10629, 17, 41687, {1, 1, 5, 7, 7, 45, 17, 213, 381, 63, 437, 3099, 3765, 175, 13521, 11689, 58675}},
+{10630, 17, 41688, {1, 1, 7, 1, 15, 35, 55, 43, 147, 873, 1193, 3801, 2301, 14569, 31789, 50443, 62577}},
+{10631, 17, 41694, {1, 1, 5, 7, 21, 41, 3, 45, 43, 303, 1465, 1461, 5295, 13397, 30439, 7103, 87505}},
+{10632, 17, 41698, {1, 1, 1, 15, 19, 27, 81, 141, 307, 259, 521, 1785, 6917, 15635, 27781, 64809, 53297}},
+{10633, 17, 41710, {1, 1, 1, 7, 27, 15, 53, 99, 377, 935, 1869, 3835, 741, 8447, 18947, 10727, 72179}},
+{10634, 17, 41712, {1, 1, 3, 5, 15, 51, 91, 207, 7, 997, 935, 591, 7325, 3025, 11335, 32087, 109535}},
+{10635, 17, 41721, {1, 3, 1, 5, 11, 13, 1, 57, 45, 307, 1839, 1735, 2247, 13117, 17471, 16599, 103063}},
+{10636, 17, 41722, {1, 3, 5, 11, 19, 7, 121, 3, 325, 731, 1945, 4025, 7649, 8939, 11147, 59065, 49971}},
+{10637, 17, 41729, {1, 3, 1, 5, 29, 63, 95, 121, 467, 7, 1857, 2389, 5213, 3931, 21187, 43529, 6767}},
+{10638, 17, 41744, {1, 1, 7, 7, 9, 53, 31, 227, 95, 827, 927, 3501, 2003, 12853, 2595, 33223, 125799}},
+{10639, 17, 41747, {1, 3, 3, 3, 27, 25, 105, 143, 233, 887, 1135, 3449, 5767, 11447, 10251, 34621, 102113}},
+{10640, 17, 41753, {1, 3, 3, 15, 3, 63, 85, 119, 103, 835, 443, 3861, 4957, 5389, 6137, 48851, 51887}},
+{10641, 17, 41766, {1, 3, 7, 9, 23, 23, 45, 129, 463, 653, 1309, 3533, 1303, 2955, 18023, 37457, 114765}},
+{10642, 17, 41783, {1, 3, 7, 1, 23, 17, 31, 151, 71, 515, 781, 1793, 3507, 6051, 30279, 29461, 48271}},
+{10643, 17, 41790, {1, 3, 5, 15, 1, 31, 9, 187, 131, 571, 1309, 965, 7561, 16113, 23209, 54615, 16969}},
+{10644, 17, 41810, {1, 3, 5, 11, 11, 9, 109, 161, 9, 697, 1683, 1245, 2223, 3571, 18117, 13085, 99315}},
+{10645, 17, 41819, {1, 3, 3, 1, 13, 21, 27, 17, 11, 11, 1095, 1447, 6941, 3399, 21245, 36661, 54283}},
+{10646, 17, 41825, {1, 3, 1, 3, 21, 51, 21, 197, 161, 689, 1219, 1337, 6623, 5765, 11579, 2679, 23889}},
+{10647, 17, 41828, {1, 1, 5, 11, 7, 31, 101, 25, 231, 719, 1677, 1545, 459, 14735, 25153, 65079, 15141}},
+{10648, 17, 41843, {1, 1, 7, 9, 17, 7, 49, 1, 83, 829, 815, 307, 3405, 15189, 23699, 50889, 70391}},
+{10649, 17, 41846, {1, 1, 3, 15, 21, 57, 97, 191, 415, 899, 197, 2635, 7507, 14009, 8633, 48997, 93925}},
+{10650, 17, 41862, {1, 3, 5, 15, 23, 13, 67, 127, 33, 551, 911, 3933, 2027, 10665, 19509, 18485, 76111}},
+{10651, 17, 41871, {1, 1, 5, 7, 23, 63, 19, 149, 139, 155, 1621, 3391, 2337, 2809, 21161, 38565, 401}},
+{10652, 17, 41874, {1, 1, 1, 7, 19, 23, 81, 49, 339, 879, 1903, 657, 2677, 2273, 10853, 3225, 57933}},
+{10653, 17, 41876, {1, 3, 5, 5, 13, 31, 19, 203, 269, 1015, 997, 2151, 4471, 11331, 5363, 46519, 51709}},
+{10654, 17, 41892, {1, 1, 5, 11, 29, 19, 17, 169, 511, 389, 1429, 2707, 1341, 10511, 6779, 43345, 68693}},
+{10655, 17, 41899, {1, 1, 5, 11, 19, 25, 29, 37, 423, 345, 953, 2525, 5937, 6595, 31389, 39347, 36343}},
+{10656, 17, 41916, {1, 3, 1, 3, 15, 25, 45, 95, 111, 207, 19, 1723, 4113, 421, 3297, 46771, 8639}},
+{10657, 17, 41928, {1, 1, 3, 9, 9, 47, 27, 99, 327, 393, 1547, 1587, 4463, 719, 14609, 24347, 68107}},
+{10658, 17, 41957, {1, 3, 7, 7, 29, 19, 57, 229, 131, 497, 109, 251, 6599, 8947, 10255, 12875, 83831}},
+{10659, 17, 41964, {1, 3, 3, 7, 17, 5, 17, 45, 423, 393, 1793, 3, 603, 15221, 13141, 40585, 37489}},
+{10660, 17, 41969, {1, 1, 1, 11, 5, 1, 53, 147, 129, 135, 1473, 17, 7539, 13513, 16045, 17375, 41261}},
+{10661, 17, 41981, {1, 3, 1, 5, 3, 15, 75, 57, 47, 581, 739, 3529, 4323, 10225, 27861, 14431, 106811}},
+{10662, 17, 41996, {1, 3, 3, 13, 23, 57, 41, 39, 217, 67, 595, 1381, 6281, 10125, 30605, 7935, 124219}},
+{10663, 17, 41999, {1, 1, 7, 15, 15, 45, 1, 135, 495, 271, 2023, 3267, 39, 15025, 32763, 39023, 20041}},
+{10664, 17, 42001, {1, 3, 7, 13, 23, 53, 75, 147, 187, 633, 1989, 1885, 6581, 12169, 13639, 19707, 96429}},
+{10665, 17, 42017, {1, 1, 5, 9, 13, 55, 13, 41, 305, 105, 1983, 273, 35, 5185, 22569, 54203, 31641}},
+{10666, 17, 42023, {1, 1, 3, 15, 21, 19, 59, 35, 165, 575, 1961, 1443, 4803, 2339, 28329, 47695, 21505}},
+{10667, 17, 42027, {1, 3, 1, 3, 23, 45, 95, 85, 55, 457, 1957, 1243, 4091, 14669, 13213, 53901, 122605}},
+{10668, 17, 42032, {1, 3, 7, 1, 13, 1, 61, 253, 195, 839, 181, 1153, 1391, 205, 6725, 1757, 86817}},
+{10669, 17, 42035, {1, 1, 3, 9, 7, 13, 115, 137, 169, 851, 299, 509, 6709, 6331, 51, 31833, 25217}},
+{10670, 17, 42044, {1, 1, 5, 15, 29, 23, 119, 15, 41, 585, 1713, 1203, 1653, 3287, 25333, 58873, 71853}},
+{10671, 17, 42050, {1, 3, 5, 15, 1, 45, 35, 79, 97, 381, 2027, 3795, 2127, 4775, 4579, 63267, 24719}},
+{10672, 17, 42061, {1, 1, 5, 7, 17, 21, 123, 75, 3, 887, 1537, 2017, 1623, 16315, 12535, 64281, 54925}},
+{10673, 17, 42062, {1, 1, 3, 13, 5, 23, 117, 43, 305, 365, 775, 1599, 5917, 13995, 6353, 3113, 106317}},
+{10674, 17, 42073, {1, 1, 3, 11, 21, 19, 9, 11, 129, 349, 579, 3523, 5259, 8083, 24513, 15077, 115377}},
+{10675, 17, 42098, {1, 1, 7, 9, 19, 31, 107, 3, 185, 821, 907, 2389, 7015, 3161, 13603, 35063, 60641}},
+{10676, 17, 42104, {1, 1, 3, 1, 19, 35, 105, 245, 363, 745, 1287, 4051, 5201, 7787, 20919, 26567, 37357}},
+{10677, 17, 42109, {1, 3, 1, 1, 23, 31, 1, 149, 61, 489, 371, 987, 3689, 14275, 8581, 48221, 44183}},
+{10678, 17, 42120, {1, 1, 5, 3, 9, 35, 51, 17, 439, 355, 461, 2129, 1567, 13261, 22347, 17013, 53857}},
+{10679, 17, 42125, {1, 3, 3, 15, 3, 33, 59, 185, 157, 933, 1489, 647, 4839, 12139, 3145, 57819, 11731}},
+{10680, 17, 42131, {1, 3, 5, 15, 17, 31, 59, 51, 117, 1001, 1585, 2861, 2785, 9579, 28013, 4481, 126723}},
+{10681, 17, 42143, {1, 3, 7, 13, 27, 1, 41, 119, 179, 879, 1617, 4053, 3537, 15389, 16381, 40153, 68019}},
+{10682, 17, 42153, {1, 1, 3, 13, 13, 35, 45, 203, 333, 337, 1415, 1889, 2361, 4207, 10411, 21013, 44009}},
+{10683, 17, 42176, {1, 3, 3, 5, 27, 9, 17, 85, 331, 369, 1219, 247, 1977, 12267, 1181, 18811, 54017}},
+{10684, 17, 42182, {1, 3, 5, 9, 21, 57, 57, 175, 283, 639, 1155, 1595, 8187, 9981, 21451, 7525, 52751}},
+{10685, 17, 42188, {1, 3, 1, 5, 27, 61, 95, 25, 271, 81, 1335, 2821, 7805, 10167, 13197, 58341, 62325}},
+{10686, 17, 42203, {1, 1, 7, 3, 15, 31, 75, 5, 211, 663, 551, 963, 6015, 11907, 17045, 22863, 32389}},
+{10687, 17, 42216, {1, 1, 7, 5, 21, 53, 67, 71, 251, 135, 1153, 2247, 2499, 15431, 21419, 46737, 2827}},
+{10688, 17, 42219, {1, 1, 5, 3, 31, 25, 39, 209, 437, 791, 1595, 637, 1581, 6575, 26407, 24043, 11277}},
+{10689, 17, 42227, {1, 3, 3, 5, 21, 15, 13, 19, 259, 949, 1237, 239, 5739, 4661, 3405, 55775, 58781}},
+{10690, 17, 42234, {1, 1, 3, 5, 1, 63, 5, 197, 329, 625, 981, 913, 3957, 2765, 8801, 56675, 129511}},
+{10691, 17, 42251, {1, 3, 3, 3, 29, 53, 65, 145, 435, 937, 787, 2043, 4945, 14585, 2789, 15771, 112335}},
+{10692, 17, 42254, {1, 3, 7, 13, 3, 23, 33, 141, 131, 375, 739, 711, 897, 469, 3635, 43335, 3069}},
+{10693, 17, 42256, {1, 1, 7, 11, 29, 13, 111, 149, 197, 793, 1541, 1879, 7683, 9397, 6873, 43733, 118507}},
+{10694, 17, 42259, {1, 3, 7, 7, 29, 21, 97, 113, 139, 573, 1099, 2615, 5123, 13021, 9533, 57673, 79283}},
+{10695, 17, 42282, {1, 3, 1, 5, 11, 9, 59, 89, 469, 797, 1119, 1037, 1667, 5947, 6051, 65045, 98275}},
+{10696, 17, 42289, {1, 3, 3, 9, 11, 7, 51, 191, 321, 677, 1601, 681, 3579, 14441, 26579, 18019, 43065}},
+{10697, 17, 42302, {1, 3, 5, 11, 7, 11, 79, 21, 335, 537, 801, 3553, 4311, 375, 7333, 64839, 88841}},
+{10698, 17, 42307, {1, 3, 1, 7, 5, 11, 15, 163, 69, 645, 57, 3685, 5143, 8275, 12763, 25035, 68949}},
+{10699, 17, 42310, {1, 1, 3, 13, 29, 33, 125, 179, 431, 129, 1367, 951, 5843, 13419, 13897, 17315, 58083}},
+{10700, 17, 42322, {1, 1, 3, 11, 31, 33, 3, 7, 185, 821, 231, 869, 6147, 15243, 32029, 20295, 60871}},
+{10701, 17, 42328, {1, 1, 1, 1, 31, 43, 21, 103, 275, 573, 805, 225, 2049, 8375, 32595, 53201, 126487}},
+{10702, 17, 42338, {1, 1, 1, 9, 31, 29, 7, 91, 277, 937, 1223, 2435, 4335, 7861, 9647, 13577, 30059}},
+{10703, 17, 42349, {1, 1, 1, 1, 23, 25, 69, 175, 293, 905, 765, 1527, 6655, 15431, 2511, 3147, 75431}},
+{10704, 17, 42367, {1, 3, 3, 3, 15, 53, 109, 195, 87, 557, 1277, 1471, 7401, 14127, 11479, 41505, 769}},
+{10705, 17, 42386, {1, 1, 5, 11, 23, 37, 121, 181, 199, 359, 1521, 2561, 3641, 7621, 14219, 6959, 77529}},
+{10706, 17, 42398, {1, 3, 1, 11, 5, 7, 69, 199, 501, 251, 707, 1485, 8125, 3209, 30883, 40259, 85087}},
+{10707, 17, 42404, {1, 3, 5, 13, 9, 35, 5, 133, 505, 39, 581, 1605, 6303, 1211, 27211, 55591, 31689}},
+{10708, 17, 42413, {1, 1, 5, 3, 17, 7, 11, 61, 483, 59, 1569, 2583, 759, 5759, 3575, 44547, 89783}},
+{10709, 17, 42419, {1, 1, 7, 15, 5, 27, 107, 5, 471, 421, 383, 3591, 3609, 13817, 633, 22043, 83119}},
+{10710, 17, 42421, {1, 1, 3, 7, 27, 55, 61, 249, 37, 241, 1483, 2839, 1231, 4765, 1551, 55801, 129679}},
+{10711, 17, 42422, {1, 1, 1, 3, 11, 1, 19, 207, 143, 351, 409, 721, 4597, 13389, 30297, 43253, 129923}},
+{10712, 17, 42431, {1, 3, 3, 7, 7, 53, 83, 27, 167, 163, 537, 3871, 2459, 12813, 30019, 41131, 56109}},
+{10713, 17, 42445, {1, 1, 5, 1, 23, 37, 11, 67, 161, 751, 123, 307, 3341, 12983, 21565, 58529, 94503}},
+{10714, 17, 42448, {1, 3, 3, 15, 11, 33, 39, 195, 467, 647, 1479, 1197, 7949, 6501, 18375, 15263, 21121}},
+{10715, 17, 42451, {1, 3, 5, 13, 3, 35, 9, 253, 299, 679, 69, 165, 2735, 14725, 4217, 16391, 107017}},
+{10716, 17, 42454, {1, 1, 1, 15, 3, 11, 87, 87, 391, 515, 843, 3957, 1365, 13201, 15983, 53647, 35643}},
+{10717, 17, 42458, {1, 1, 3, 7, 9, 53, 45, 221, 209, 855, 169, 2729, 1219, 5229, 14111, 28877, 114653}},
+{10718, 17, 42470, {1, 1, 5, 3, 11, 17, 5, 93, 303, 785, 1895, 2483, 7399, 14031, 1007, 2743, 47307}},
+{10719, 17, 42476, {1, 1, 7, 11, 9, 13, 115, 31, 223, 1011, 723, 1291, 5183, 559, 15881, 43045, 28131}},
+{10720, 17, 42500, {1, 3, 7, 11, 7, 59, 85, 111, 79, 227, 691, 1597, 2453, 10023, 19255, 47781, 88351}},
+{10721, 17, 42509, {1, 3, 3, 7, 21, 33, 39, 35, 253, 743, 563, 2455, 8015, 13403, 24883, 47881, 115559}},
+{10722, 17, 42538, {1, 3, 1, 1, 5, 33, 69, 37, 225, 157, 1347, 3241, 4981, 15985, 9949, 49189, 21267}},
+{10723, 17, 42543, {1, 1, 3, 11, 9, 33, 123, 133, 215, 297, 961, 1571, 1133, 1, 31871, 25253, 100097}},
+{10724, 17, 42545, {1, 1, 1, 7, 13, 29, 101, 127, 113, 785, 1257, 525, 7397, 13143, 30315, 5969, 37829}},
+{10725, 17, 42546, {1, 1, 1, 7, 29, 33, 17, 95, 439, 577, 1857, 423, 63, 15365, 4777, 59073, 7773}},
+{10726, 17, 42563, {1, 1, 5, 15, 3, 17, 89, 133, 217, 601, 1979, 391, 105, 13709, 10081, 37725, 40957}},
+{10727, 17, 42570, {1, 1, 1, 15, 25, 7, 85, 197, 155, 367, 1927, 2007, 2563, 13147, 2345, 28735, 88243}},
+{10728, 17, 42580, {1, 3, 5, 3, 5, 33, 87, 153, 153, 779, 825, 2163, 385, 11663, 2005, 51261, 25893}},
+{10729, 17, 42584, {1, 3, 5, 5, 23, 15, 19, 99, 71, 723, 523, 3683, 7773, 191, 17423, 30497, 129889}},
+{10730, 17, 42589, {1, 1, 7, 11, 1, 3, 49, 119, 39, 661, 297, 27, 1575, 12145, 18519, 57285, 50059}},
+{10731, 17, 42608, {1, 3, 7, 5, 7, 37, 75, 235, 403, 743, 603, 1689, 5031, 8871, 28241, 16917, 16947}},
+{10732, 17, 42618, {1, 1, 5, 13, 17, 41, 67, 219, 237, 365, 833, 3521, 3211, 1037, 5657, 34789, 119739}},
+{10733, 17, 42629, {1, 1, 5, 7, 3, 61, 89, 107, 335, 825, 803, 2445, 6861, 5421, 14585, 44037, 92711}},
+{10734, 17, 42636, {1, 3, 7, 3, 19, 25, 81, 51, 101, 477, 1653, 2841, 6597, 9261, 30609, 15681, 48897}},
+{10735, 17, 42639, {1, 1, 7, 11, 17, 1, 43, 39, 133, 513, 1839, 553, 6379, 4865, 28161, 7249, 80073}},
+{10736, 17, 42644, {1, 1, 5, 5, 13, 45, 19, 225, 399, 679, 195, 3613, 413, 2901, 26749, 39971, 31435}},
+{10737, 17, 42647, {1, 3, 7, 3, 23, 55, 57, 77, 447, 721, 677, 271, 6211, 12631, 5843, 35991, 82653}},
+{10738, 17, 42651, {1, 1, 1, 1, 3, 63, 23, 195, 1, 1019, 723, 3865, 5913, 5491, 5495, 27483, 73637}},
+{10739, 17, 42654, {1, 3, 1, 11, 17, 31, 27, 211, 411, 789, 1049, 2487, 2203, 6457, 7275, 4833, 14131}},
+{10740, 17, 42658, {1, 1, 5, 15, 15, 13, 65, 155, 127, 753, 1605, 1859, 2873, 9197, 1763, 11969, 82971}},
+{10741, 17, 42669, {1, 1, 3, 11, 11, 63, 13, 29, 31, 851, 251, 3231, 1227, 5513, 9785, 34659, 123811}},
+{10742, 17, 42678, {1, 3, 5, 1, 19, 57, 41, 205, 91, 39, 989, 1897, 4789, 16071, 6507, 29363, 75773}},
+{10743, 17, 42689, {1, 1, 1, 1, 5, 29, 113, 203, 53, 599, 1529, 1417, 7017, 9609, 4867, 17659, 80719}},
+{10744, 17, 42695, {1, 3, 7, 9, 27, 17, 77, 25, 461, 511, 781, 2977, 7601, 3551, 23615, 57669, 119723}},
+{10745, 17, 42696, {1, 3, 3, 9, 23, 43, 115, 21, 125, 237, 893, 1431, 7423, 3717, 4371, 36193, 30481}},
+{10746, 17, 42710, {1, 1, 5, 13, 3, 37, 13, 239, 267, 665, 205, 2745, 3865, 12167, 26689, 999, 9355}},
+{10747, 17, 42716, {1, 1, 1, 1, 31, 35, 55, 115, 387, 217, 657, 2827, 2963, 3687, 24271, 41701, 5911}},
+{10748, 17, 42730, {1, 1, 3, 3, 27, 57, 41, 183, 351, 841, 1327, 719, 7043, 12503, 17953, 60719, 98223}},
+{10749, 17, 42732, {1, 3, 1, 1, 27, 1, 119, 85, 197, 673, 1951, 2949, 4783, 561, 12807, 43355, 63397}},
+{10750, 17, 42747, {1, 1, 7, 7, 17, 63, 109, 87, 303, 439, 529, 685, 111, 8405, 21249, 33803, 77927}},
+{10751, 17, 42750, {1, 1, 7, 9, 11, 63, 27, 185, 445, 25, 1313, 3979, 4229, 8797, 10671, 33995, 84463}},
+{10752, 17, 42752, {1, 1, 1, 15, 27, 63, 67, 237, 39, 993, 851, 4075, 3417, 1077, 11939, 31737, 93897}},
+{10753, 17, 42761, {1, 1, 3, 5, 25, 9, 51, 241, 213, 661, 1135, 213, 7027, 5933, 24485, 65029, 8583}},
+{10754, 17, 42772, {1, 3, 5, 11, 31, 1, 17, 237, 107, 1021, 279, 181, 1741, 11099, 7871, 63231, 64445}},
+{10755, 17, 42776, {1, 3, 5, 9, 17, 21, 11, 45, 23, 409, 519, 1703, 5467, 9591, 13555, 23739, 73837}},
+{10756, 17, 42779, {1, 3, 3, 15, 3, 39, 11, 157, 273, 241, 413, 1723, 3179, 2125, 16859, 5231, 122969}},
+{10757, 17, 42797, {1, 3, 5, 11, 21, 27, 29, 243, 255, 1011, 1179, 3545, 3557, 8091, 31569, 10217, 108361}},
+{10758, 17, 42815, {1, 1, 5, 9, 25, 33, 29, 67, 395, 123, 1405, 3855, 7481, 5601, 21231, 17099, 13399}},
+{10759, 17, 42824, {1, 1, 5, 5, 13, 17, 111, 47, 77, 827, 577, 1767, 3367, 11719, 8801, 22431, 85451}},
+{10760, 17, 42837, {1, 3, 7, 11, 11, 31, 17, 141, 149, 293, 55, 3459, 19, 13709, 29135, 62765, 66455}},
+{10761, 17, 42844, {1, 1, 7, 15, 13, 19, 59, 211, 189, 773, 1791, 2089, 2857, 1635, 17777, 46585, 70115}},
+{10762, 17, 42868, {1, 1, 5, 11, 29, 29, 15, 7, 93, 733, 1605, 3731, 2381, 1063, 15565, 25081, 46651}},
+{10763, 17, 42877, {1, 3, 1, 9, 25, 5, 87, 113, 25, 93, 881, 1137, 3237, 10983, 14317, 25945, 121493}},
+{10764, 17, 42888, {1, 1, 5, 11, 29, 47, 99, 111, 165, 453, 259, 2001, 7715, 2609, 15633, 40273, 2065}},
+{10765, 17, 42891, {1, 1, 7, 13, 11, 29, 33, 255, 149, 361, 89, 2837, 49, 3033, 1917, 9029, 38123}},
+{10766, 17, 42912, {1, 1, 1, 7, 27, 31, 105, 61, 469, 497, 1919, 3005, 3651, 2143, 24359, 8053, 103647}},
+{10767, 17, 42918, {1, 1, 3, 13, 31, 63, 101, 47, 397, 89, 1915, 2385, 5399, 8897, 21001, 42997, 110333}},
+{10768, 17, 42921, {1, 3, 7, 5, 29, 1, 5, 119, 493, 349, 153, 1839, 283, 14343, 12975, 55597, 89467}},
+{10769, 17, 42927, {1, 3, 5, 3, 5, 51, 71, 227, 63, 799, 745, 1387, 2435, 1003, 27937, 43421, 12279}},
+{10770, 17, 42949, {1, 3, 3, 7, 7, 31, 37, 61, 11, 175, 581, 1583, 4737, 3087, 10335, 60683, 57085}},
+{10771, 17, 42953, {1, 3, 1, 1, 1, 63, 59, 47, 417, 35, 1673, 3277, 1873, 14981, 22463, 26835, 91115}},
+{10772, 17, 42967, {1, 1, 7, 5, 15, 23, 115, 13, 253, 583, 219, 1307, 1189, 9891, 641, 20841, 87133}},
+{10773, 17, 42974, {1, 1, 5, 11, 1, 3, 71, 235, 429, 335, 1649, 1775, 3077, 13723, 3209, 19807, 7283}},
+{10774, 17, 42989, {1, 1, 7, 1, 31, 49, 39, 141, 127, 63, 1561, 2559, 7661, 4825, 9419, 15327, 87145}},
+{10775, 17, 42995, {1, 1, 5, 3, 17, 33, 51, 219, 467, 151, 161, 3301, 7509, 2235, 30371, 64031, 62741}},
+{10776, 17, 42997, {1, 3, 1, 3, 23, 63, 43, 29, 399, 279, 271, 3537, 1863, 1811, 14917, 28247, 34807}},
+{10777, 17, 43007, {1, 1, 3, 5, 13, 29, 37, 151, 129, 19, 149, 2145, 5363, 6835, 19655, 1207, 74527}},
+{10778, 17, 43018, {1, 3, 5, 7, 27, 35, 63, 53, 247, 987, 1767, 483, 3489, 1711, 10763, 6981, 78251}},
+{10779, 17, 43025, {1, 1, 3, 1, 15, 47, 83, 147, 375, 539, 1623, 29, 4599, 7981, 23533, 64659, 48753}},
+{10780, 17, 43031, {1, 1, 1, 9, 21, 17, 85, 45, 167, 469, 1319, 2969, 1605, 1405, 9961, 28829, 125757}},
+{10781, 17, 43032, {1, 3, 1, 11, 3, 45, 43, 159, 301, 579, 1821, 701, 1149, 457, 16601, 49377, 99845}},
+{10782, 17, 43038, {1, 1, 7, 13, 11, 7, 37, 227, 345, 973, 1167, 1247, 5109, 10917, 3029, 60065, 127347}},
+{10783, 17, 43041, {1, 1, 3, 5, 3, 63, 95, 233, 495, 225, 1225, 3451, 7731, 14677, 10437, 1417, 33293}},
+{10784, 17, 43054, {1, 1, 7, 15, 1, 3, 3, 171, 201, 1009, 1481, 587, 7661, 10085, 4961, 46415, 28573}},
+{10785, 17, 43074, {1, 1, 5, 1, 3, 45, 67, 79, 463, 733, 2007, 2811, 2943, 14857, 23469, 14479, 97875}},
+{10786, 17, 43085, {1, 1, 1, 5, 19, 1, 29, 29, 447, 173, 1081, 153, 5343, 5707, 1357, 30169, 122527}},
+{10787, 17, 43097, {1, 1, 1, 5, 15, 57, 33, 129, 71, 717, 173, 3271, 4741, 13211, 28321, 56793, 119833}},
+{10788, 17, 43098, {1, 3, 3, 9, 9, 41, 47, 71, 103, 713, 725, 1335, 5261, 13835, 17619, 47429, 69815}},
+{10789, 17, 43110, {1, 3, 3, 15, 7, 3, 71, 25, 75, 967, 1037, 3585, 3407, 9979, 2195, 51087, 126535}},
+{10790, 17, 43119, {1, 3, 3, 11, 25, 7, 25, 249, 473, 339, 1211, 3503, 4343, 9707, 26127, 62061, 52479}},
+{10791, 17, 43131, {1, 1, 3, 3, 27, 9, 79, 197, 207, 845, 377, 3231, 5177, 899, 19497, 41187, 105897}},
+{10792, 17, 43143, {1, 3, 5, 15, 5, 27, 65, 151, 207, 677, 713, 2495, 681, 15341, 5389, 51965, 43761}},
+{10793, 17, 43144, {1, 3, 3, 11, 19, 11, 55, 189, 291, 183, 1345, 2677, 791, 2391, 25771, 55147, 24223}},
+{10794, 17, 43152, {1, 1, 3, 11, 31, 59, 29, 5, 275, 483, 1361, 1527, 3019, 245, 17667, 57905, 41329}},
+{10795, 17, 43157, {1, 3, 3, 9, 7, 19, 83, 71, 147, 999, 793, 3535, 1931, 12817, 2707, 45735, 31311}},
+{10796, 17, 43178, {1, 1, 5, 7, 5, 1, 117, 247, 127, 1011, 1441, 2449, 4095, 12239, 4743, 64781, 32621}},
+{10797, 17, 43180, {1, 3, 1, 11, 19, 57, 43, 39, 97, 485, 951, 989, 5975, 5219, 14421, 43681, 37305}},
+{10798, 17, 43192, {1, 1, 5, 15, 7, 49, 113, 161, 199, 545, 1113, 3821, 2019, 8747, 4085, 50823, 31955}},
+{10799, 17, 43197, {1, 3, 3, 3, 19, 41, 47, 191, 403, 25, 2043, 3489, 6263, 4843, 12961, 63791, 5027}},
+{10800, 17, 43203, {1, 1, 7, 1, 25, 55, 5, 51, 121, 273, 973, 3893, 1771, 9373, 21927, 29353, 95935}},
+{10801, 17, 43220, {1, 3, 3, 3, 27, 1, 97, 63, 445, 179, 481, 2995, 3123, 4687, 24359, 35973, 74535}},
+{10802, 17, 43236, {1, 1, 5, 1, 29, 23, 117, 183, 197, 819, 695, 641, 4155, 13593, 30965, 41407, 42433}},
+{10803, 17, 43245, {1, 3, 5, 1, 23, 53, 61, 253, 87, 487, 1995, 1281, 3367, 15047, 3493, 41711, 53407}},
+{10804, 17, 43246, {1, 1, 1, 9, 27, 49, 83, 21, 63, 181, 1661, 1649, 281, 12141, 25771, 35563, 42643}},
+{10805, 17, 43260, {1, 3, 5, 13, 15, 59, 121, 113, 379, 487, 1929, 3725, 2477, 6527, 8619, 64869, 57103}},
+{10806, 17, 43265, {1, 3, 1, 7, 27, 39, 69, 93, 193, 395, 433, 2091, 151, 6921, 11599, 36143, 41179}},
+{10807, 17, 43271, {1, 1, 7, 1, 31, 33, 73, 199, 57, 37, 1387, 3505, 7919, 3507, 2855, 8239, 84527}},
+{10808, 17, 43285, {1, 1, 7, 5, 15, 5, 119, 253, 263, 785, 1409, 1485, 3675, 5515, 13057, 30323, 98015}},
+{10809, 17, 43286, {1, 3, 1, 1, 11, 5, 57, 83, 365, 703, 1923, 1397, 1103, 4015, 13123, 47093, 113793}},
+{10810, 17, 43290, {1, 3, 3, 1, 5, 61, 29, 173, 189, 999, 897, 3389, 6745, 1487, 2349, 59105, 107407}},
+{10811, 17, 43299, {1, 1, 1, 1, 17, 51, 65, 1, 249, 863, 399, 3819, 2485, 12215, 12365, 58909, 25559}},
+{10812, 17, 43314, {1, 3, 7, 1, 31, 39, 43, 219, 51, 13, 779, 505, 2259, 14571, 9049, 21555, 11869}},
+{10813, 17, 43323, {1, 1, 7, 7, 13, 5, 97, 85, 111, 511, 587, 63, 2395, 8099, 26223, 757, 119821}},
+{10814, 17, 43337, {1, 3, 3, 5, 5, 19, 113, 35, 101, 41, 499, 1313, 6489, 6793, 31435, 45007, 95691}},
+{10815, 17, 43348, {1, 3, 5, 15, 19, 37, 103, 187, 347, 667, 1957, 1825, 7447, 12359, 21779, 52749, 18679}},
+{10816, 17, 43355, {1, 3, 5, 5, 17, 19, 19, 193, 435, 379, 439, 2093, 725, 2133, 15659, 54645, 59567}},
+{10817, 17, 43357, {1, 3, 7, 3, 23, 35, 33, 13, 23, 349, 231, 1635, 1625, 5039, 21299, 36413, 104681}},
+{10818, 17, 43358, {1, 1, 3, 13, 23, 49, 15, 253, 509, 9, 411, 2157, 3737, 11227, 6021, 42919, 100375}},
+{10819, 17, 43361, {1, 1, 7, 1, 17, 11, 33, 167, 219, 63, 137, 741, 4193, 16149, 9657, 50223, 85213}},
+{10820, 17, 43362, {1, 3, 7, 11, 23, 59, 113, 149, 427, 697, 1723, 255, 201, 10081, 1079, 323, 109091}},
+{10821, 17, 43364, {1, 3, 3, 15, 11, 9, 89, 39, 67, 249, 1939, 1737, 3719, 10515, 16517, 22345, 83959}},
+{10822, 17, 43368, {1, 3, 3, 13, 5, 33, 127, 9, 329, 429, 563, 1579, 4427, 8343, 22083, 5035, 124915}},
+{10823, 17, 43376, {1, 1, 1, 5, 15, 57, 121, 171, 315, 983, 743, 2015, 2421, 12431, 2561, 13331, 73163}},
+{10824, 17, 43385, {1, 1, 3, 9, 1, 39, 85, 159, 23, 979, 1467, 231, 4231, 3669, 16747, 24195, 46745}},
+{10825, 17, 43386, {1, 1, 3, 7, 3, 11, 65, 67, 85, 455, 365, 2279, 3471, 12771, 14443, 42773, 28723}},
+{10826, 17, 43391, {1, 3, 5, 1, 13, 9, 105, 237, 103, 59, 1301, 3125, 509, 12669, 3893, 9775, 81303}},
+{10827, 17, 43397, {1, 1, 3, 11, 19, 9, 125, 23, 191, 979, 533, 429, 3239, 15013, 13833, 40689, 102827}},
+{10828, 17, 43431, {1, 3, 3, 7, 15, 5, 83, 243, 467, 913, 1279, 3889, 8049, 8357, 5957, 39073, 93521}},
+{10829, 17, 43438, {1, 3, 3, 3, 19, 5, 123, 77, 289, 57, 2001, 807, 5257, 1671, 20273, 10183, 128439}},
+{10830, 17, 43440, {1, 1, 7, 13, 19, 45, 25, 47, 135, 929, 1353, 2731, 3351, 7637, 27037, 58835, 50285}},
+{10831, 17, 43452, {1, 3, 1, 1, 13, 55, 55, 197, 409, 93, 1351, 161, 1885, 5913, 27937, 49793, 84541}},
+{10832, 17, 43463, {1, 1, 3, 7, 29, 21, 113, 179, 203, 533, 1471, 2035, 447, 6781, 28729, 31099, 23027}},
+{10833, 17, 43470, {1, 1, 3, 11, 27, 3, 5, 209, 367, 945, 749, 3637, 2881, 8139, 27875, 34223, 97263}},
+{10834, 17, 43478, {1, 3, 5, 13, 25, 27, 35, 3, 13, 707, 303, 3663, 6617, 13501, 25537, 33077, 71485}},
+{10835, 17, 43481, {1, 1, 7, 15, 11, 29, 65, 47, 235, 635, 133, 153, 6175, 2961, 8171, 28641, 122589}},
+{10836, 17, 43488, {1, 1, 5, 15, 17, 41, 85, 147, 323, 673, 1629, 3477, 3341, 16373, 13901, 60961, 39451}},
+{10837, 17, 43491, {1, 3, 1, 15, 29, 15, 37, 109, 293, 863, 1835, 1173, 2263, 13815, 24995, 6989, 103417}},
+{10838, 17, 43506, {1, 3, 3, 15, 3, 31, 23, 47, 15, 717, 1457, 1067, 6229, 7051, 21771, 54815, 115827}},
+{10839, 17, 43512, {1, 1, 1, 13, 21, 3, 45, 239, 89, 603, 407, 781, 8095, 7389, 18035, 32229, 39867}},
+{10840, 17, 43539, {1, 1, 3, 7, 7, 59, 79, 51, 411, 917, 803, 2455, 2623, 12413, 23957, 44199, 67903}},
+{10841, 17, 43567, {1, 3, 1, 9, 17, 37, 117, 47, 101, 733, 1861, 1111, 6785, 13743, 24371, 49427, 54711}},
+{10842, 17, 43579, {1, 3, 1, 15, 27, 63, 107, 33, 351, 287, 1765, 1947, 6209, 8127, 30007, 18757, 31453}},
+{10843, 17, 43584, {1, 3, 5, 13, 11, 13, 29, 247, 7, 609, 1235, 1767, 5365, 12673, 10151, 51579, 106407}},
+{10844, 17, 43601, {1, 3, 7, 15, 5, 25, 81, 197, 51, 615, 1695, 259, 7983, 1403, 7903, 21441, 73263}},
+{10845, 17, 43614, {1, 1, 5, 1, 13, 61, 55, 175, 445, 3, 1957, 1171, 6823, 4285, 11847, 12789, 79787}},
+{10846, 17, 43617, {1, 1, 5, 15, 17, 51, 111, 201, 45, 97, 45, 2533, 1125, 3663, 13685, 45719, 51497}},
+{10847, 17, 43623, {1, 3, 3, 13, 29, 59, 111, 97, 381, 477, 1229, 3709, 5185, 7055, 32729, 32881, 25539}},
+{10848, 17, 43630, {1, 3, 1, 9, 1, 39, 57, 143, 189, 625, 1717, 1755, 3129, 807, 27975, 15511, 66123}},
+{10849, 17, 43647, {1, 3, 3, 1, 5, 41, 25, 27, 163, 397, 1595, 2325, 1803, 12439, 25743, 24509, 72613}},
+{10850, 17, 43658, {1, 1, 5, 13, 29, 41, 125, 113, 367, 709, 1911, 669, 831, 5375, 31145, 26197, 33543}},
+{10851, 17, 43663, {1, 1, 5, 1, 1, 5, 91, 199, 133, 273, 393, 1179, 717, 12791, 17693, 6905, 20433}},
+{10852, 17, 43665, {1, 1, 3, 15, 29, 35, 9, 127, 383, 673, 1821, 2765, 2425, 11789, 19741, 43189, 99557}},
+{10853, 17, 43691, {1, 1, 7, 13, 9, 19, 119, 103, 11, 983, 623, 391, 1609, 2333, 19843, 28269, 41237}},
+{10854, 17, 43701, {1, 3, 7, 5, 29, 3, 13, 213, 387, 361, 749, 669, 1625, 5687, 11369, 38119, 38389}},
+{10855, 17, 43705, {1, 3, 5, 13, 13, 51, 47, 33, 1, 979, 1817, 2633, 7181, 47, 3603, 49211, 4377}},
+{10856, 17, 43708, {1, 3, 1, 1, 11, 63, 5, 249, 13, 805, 1097, 1449, 5235, 16299, 25855, 30949, 3013}},
+{10857, 17, 43719, {1, 3, 7, 9, 29, 35, 89, 135, 475, 945, 999, 771, 6023, 13317, 32611, 43971, 10393}},
+{10858, 17, 43731, {1, 1, 1, 5, 23, 3, 37, 117, 95, 985, 1599, 2191, 3617, 5831, 31113, 10873, 112219}},
+{10859, 17, 43737, {1, 3, 5, 7, 11, 15, 55, 65, 239, 365, 1209, 3509, 8101, 8619, 24775, 65291, 50589}},
+{10860, 17, 43740, {1, 1, 7, 9, 21, 19, 123, 83, 317, 717, 433, 31, 2597, 14723, 28839, 7817, 126123}},
+{10861, 17, 43747, {1, 1, 7, 11, 3, 33, 99, 39, 227, 279, 353, 1921, 7883, 16187, 5157, 41121, 89425}},
+{10862, 17, 43749, {1, 3, 5, 9, 25, 7, 29, 165, 129, 77, 159, 923, 1357, 1159, 23537, 58087, 56443}},
+{10863, 17, 43750, {1, 1, 7, 3, 13, 51, 45, 161, 27, 41, 1295, 2937, 7223, 5271, 17927, 23311, 2543}},
+{10864, 17, 43754, {1, 1, 1, 1, 11, 53, 119, 165, 409, 785, 1649, 3587, 259, 10997, 3171, 31271, 104631}},
+{10865, 17, 43764, {1, 1, 5, 7, 5, 7, 49, 201, 373, 825, 1755, 3751, 8041, 8133, 21347, 12039, 3049}},
+{10866, 17, 43767, {1, 1, 1, 3, 7, 29, 103, 1, 473, 65, 761, 1611, 5121, 14345, 32535, 16679, 11321}},
+{10867, 17, 43768, {1, 3, 3, 11, 21, 57, 35, 63, 237, 415, 1943, 483, 5377, 14647, 23433, 45459, 32535}},
+{10868, 17, 43773, {1, 1, 1, 15, 21, 57, 7, 103, 493, 279, 665, 3699, 169, 7619, 3571, 11539, 31983}},
+{10869, 17, 43785, {1, 1, 1, 1, 9, 5, 81, 159, 105, 927, 379, 1133, 1805, 14341, 9833, 63151, 70877}},
+{10870, 17, 43788, {1, 1, 7, 5, 19, 5, 63, 127, 129, 43, 757, 2215, 3899, 643, 19731, 17345, 102611}},
+{10871, 17, 43810, {1, 3, 7, 7, 27, 21, 3, 69, 475, 283, 319, 833, 3683, 11275, 18191, 44027, 24901}},
+{10872, 17, 43819, {1, 1, 5, 5, 31, 25, 63, 33, 505, 765, 257, 1147, 779, 12505, 19971, 24695, 65935}},
+{10873, 17, 43834, {1, 1, 1, 15, 23, 33, 31, 107, 59, 639, 1307, 3211, 6171, 15665, 16775, 61671, 25569}},
+{10874, 17, 43853, {1, 3, 3, 9, 31, 3, 113, 199, 425, 895, 1051, 2125, 1525, 15199, 14845, 4213, 18449}},
+{10875, 17, 43866, {1, 3, 5, 3, 3, 11, 75, 121, 33, 265, 459, 3879, 909, 6533, 18451, 32421, 117427}},
+{10876, 17, 43871, {1, 1, 1, 9, 11, 9, 125, 175, 309, 847, 959, 2013, 1557, 9291, 2963, 43275, 9917}},
+{10877, 17, 43872, {1, 1, 5, 3, 15, 39, 67, 35, 373, 601, 463, 1263, 1615, 15059, 31011, 36059, 114493}},
+{10878, 17, 43881, {1, 1, 5, 15, 5, 43, 49, 239, 461, 171, 1863, 2249, 2923, 15897, 22941, 29925, 21429}},
+{10879, 17, 43889, {1, 1, 1, 15, 13, 31, 127, 205, 361, 149, 1641, 1443, 5959, 13183, 13861, 9533, 1011}},
+{10880, 17, 43902, {1, 1, 3, 13, 9, 49, 39, 67, 165, 695, 611, 2261, 3425, 6247, 23575, 51833, 106167}},
+{10881, 17, 43926, {1, 1, 7, 9, 29, 21, 75, 251, 87, 263, 2035, 1007, 3821, 12719, 8889, 47901, 39037}},
+{10882, 17, 43935, {1, 3, 1, 3, 15, 51, 79, 127, 201, 497, 1881, 3841, 1821, 14435, 4933, 6853, 104305}},
+{10883, 17, 43946, {1, 1, 5, 11, 23, 47, 33, 109, 481, 585, 333, 2525, 593, 1625, 5787, 23839, 30647}},
+{10884, 17, 43951, {1, 1, 5, 1, 17, 3, 7, 43, 113, 873, 1433, 3377, 45, 831, 17015, 21479, 7257}},
+{10885, 17, 43953, {1, 1, 1, 1, 13, 21, 59, 159, 279, 871, 53, 3647, 2599, 12417, 25807, 6867, 18251}},
+{10886, 17, 43971, {1, 1, 5, 9, 29, 61, 7, 81, 353, 761, 269, 4047, 3051, 8385, 2919, 18875, 15239}},
+{10887, 17, 44008, {1, 1, 7, 13, 31, 17, 71, 103, 107, 655, 1263, 849, 1809, 349, 3239, 45381, 117451}},
+{10888, 17, 44011, {1, 1, 5, 9, 27, 45, 83, 207, 117, 77, 437, 523, 851, 13595, 12381, 27271, 59951}},
+{10889, 17, 44026, {1, 3, 3, 15, 3, 33, 103, 217, 61, 443, 1077, 2887, 1751, 11111, 465, 37051, 89687}},
+{10890, 17, 44033, {1, 1, 1, 5, 15, 15, 13, 115, 275, 565, 1257, 1067, 6561, 8143, 2149, 53169, 123637}},
+{10891, 17, 44048, {1, 3, 3, 15, 27, 63, 25, 191, 143, 103, 1247, 1053, 2469, 9823, 4437, 18195, 91751}},
+{10892, 17, 44057, {1, 1, 7, 11, 1, 63, 31, 103, 249, 861, 983, 335, 35, 4291, 16307, 43669, 68065}},
+{10893, 17, 44058, {1, 3, 1, 15, 13, 29, 51, 145, 177, 851, 39, 3531, 4477, 4243, 3301, 64293, 15741}},
+{10894, 17, 44067, {1, 1, 7, 3, 29, 45, 5, 85, 185, 191, 1007, 3085, 2177, 14911, 18319, 265, 25435}},
+{10895, 17, 44081, {1, 1, 5, 9, 9, 57, 47, 143, 217, 947, 2021, 1835, 4773, 15145, 26519, 46407, 103667}},
+{10896, 17, 44087, {1, 3, 1, 11, 1, 7, 51, 75, 207, 757, 89, 1289, 39, 15641, 9477, 28503, 47113}},
+{10897, 17, 44099, {1, 3, 1, 11, 9, 19, 21, 197, 429, 121, 813, 3447, 6091, 3167, 5401, 27791, 26499}},
+{10898, 17, 44105, {1, 1, 7, 15, 1, 15, 85, 247, 3, 111, 433, 3103, 5049, 7929, 22645, 53247, 53417}},
+{10899, 17, 44106, {1, 1, 7, 7, 27, 19, 125, 101, 269, 7, 777, 1289, 1429, 11561, 18043, 3601, 125857}},
+{10900, 17, 44114, {1, 1, 1, 13, 11, 9, 127, 231, 239, 435, 1291, 4025, 1049, 15549, 7577, 51147, 38121}},
+{10901, 17, 44116, {1, 1, 7, 3, 9, 55, 57, 137, 387, 565, 873, 1417, 5993, 4849, 1731, 51653, 105697}},
+{10902, 17, 44130, {1, 1, 7, 9, 7, 47, 115, 119, 325, 881, 1687, 1009, 7007, 12541, 6737, 28471, 7369}},
+{10903, 17, 44139, {1, 3, 1, 1, 11, 47, 25, 163, 399, 977, 1777, 727, 5575, 1311, 23843, 2199, 93229}},
+{10904, 17, 44141, {1, 1, 7, 5, 13, 19, 53, 123, 439, 585, 1977, 3387, 5305, 1463, 14307, 9519, 537}},
+{10905, 17, 44153, {1, 1, 7, 15, 1, 53, 13, 213, 323, 699, 1585, 3499, 2441, 3055, 31263, 63923, 9779}},
+{10906, 17, 44159, {1, 1, 5, 5, 21, 43, 123, 43, 475, 521, 1301, 3185, 5627, 7443, 1195, 39485, 113125}},
+{10907, 17, 44160, {1, 1, 5, 7, 9, 3, 39, 5, 237, 719, 1743, 1153, 6401, 14701, 5503, 38491, 24123}},
+{10908, 17, 44170, {1, 3, 5, 9, 17, 33, 117, 23, 409, 63, 1829, 2587, 3489, 3209, 4775, 40069, 4721}},
+{10909, 17, 44172, {1, 3, 3, 5, 21, 63, 95, 231, 25, 167, 1181, 813, 4591, 5227, 21999, 19633, 37547}},
+{10910, 17, 44187, {1, 1, 7, 11, 13, 9, 13, 147, 239, 951, 1247, 1199, 7907, 12493, 25371, 1917, 107499}},
+{10911, 17, 44190, {1, 1, 5, 15, 3, 49, 31, 103, 189, 561, 1763, 3941, 3525, 3165, 7789, 57729, 92635}},
+{10912, 17, 44193, {1, 1, 1, 5, 3, 61, 107, 163, 465, 631, 1519, 169, 4469, 8153, 11039, 247, 37657}},
+{10913, 17, 44199, {1, 3, 1, 5, 9, 37, 51, 195, 465, 975, 169, 1077, 995, 2669, 7663, 28997, 25779}},
+{10914, 17, 44213, {1, 1, 7, 13, 7, 37, 3, 117, 147, 335, 629, 4077, 5855, 2893, 5629, 55075, 83359}},
+{10915, 17, 44218, {1, 1, 5, 9, 9, 25, 53, 63, 315, 287, 1833, 1397, 2395, 5719, 6719, 18003, 101073}},
+{10916, 17, 44223, {1, 1, 7, 1, 13, 19, 13, 81, 497, 399, 413, 2411, 3915, 14037, 19735, 4587, 69655}},
+{10917, 17, 44235, {1, 3, 1, 7, 5, 61, 101, 209, 299, 729, 1359, 4013, 2057, 8439, 8113, 57417, 8951}},
+{10918, 17, 44243, {1, 3, 5, 7, 29, 21, 67, 73, 107, 359, 1655, 3729, 4403, 10467, 28103, 10261, 74651}},
+{10919, 17, 44262, {1, 1, 1, 9, 3, 39, 25, 91, 287, 497, 1743, 339, 4739, 1709, 16351, 45385, 64693}},
+{10920, 17, 44283, {1, 3, 1, 1, 7, 13, 41, 93, 49, 285, 997, 891, 4353, 4249, 11269, 36935, 71249}},
+{10921, 17, 44291, {1, 3, 3, 13, 13, 23, 97, 231, 101, 93, 1183, 201, 6795, 16287, 30707, 20845, 105873}},
+{10922, 17, 44293, {1, 1, 1, 9, 7, 57, 123, 167, 451, 245, 1887, 1839, 2967, 2387, 15075, 11877, 629}},
+{10923, 17, 44308, {1, 3, 3, 1, 13, 13, 83, 41, 219, 313, 1743, 1265, 4435, 11731, 17625, 64235, 24865}},
+{10924, 17, 44327, {1, 3, 1, 9, 13, 17, 109, 235, 387, 581, 887, 1071, 603, 10955, 5001, 8419, 20997}},
+{10925, 17, 44341, {1, 3, 1, 5, 31, 55, 1, 219, 27, 623, 1425, 1309, 5409, 9633, 3231, 15029, 22989}},
+{10926, 17, 44346, {1, 3, 3, 13, 25, 47, 23, 223, 283, 189, 1665, 3743, 387, 1807, 16919, 8511, 15933}},
+{10927, 17, 44348, {1, 1, 1, 1, 13, 11, 81, 59, 423, 1007, 317, 2761, 2617, 9715, 24853, 63585, 77083}},
+{10928, 17, 44354, {1, 3, 1, 3, 3, 11, 103, 123, 401, 467, 1159, 2725, 3275, 15513, 2281, 21617, 87211}},
+{10929, 17, 44366, {1, 1, 5, 7, 23, 17, 25, 83, 11, 901, 809, 3233, 3929, 8685, 7609, 50949, 104841}},
+{10930, 17, 44368, {1, 3, 7, 1, 15, 33, 37, 245, 275, 453, 729, 721, 1589, 5417, 29839, 57315, 67227}},
+{10931, 17, 44373, {1, 3, 7, 3, 21, 17, 51, 213, 225, 471, 1201, 931, 1229, 9503, 5507, 4057, 7737}},
+{10932, 17, 44384, {1, 3, 1, 11, 29, 55, 19, 193, 9, 151, 597, 1377, 827, 8549, 1293, 10963, 86183}},
+{10933, 17, 44390, {1, 3, 3, 15, 17, 23, 89, 47, 195, 333, 2001, 1001, 6715, 9797, 21631, 5723, 88847}},
+{10934, 17, 44393, {1, 3, 5, 9, 21, 33, 111, 101, 503, 513, 785, 1947, 1139, 7921, 13189, 34831, 80963}},
+{10935, 17, 44394, {1, 3, 3, 13, 9, 61, 35, 39, 451, 485, 661, 1993, 4705, 9477, 32541, 16553, 33167}},
+{10936, 17, 44399, {1, 3, 3, 9, 29, 37, 115, 87, 367, 325, 539, 1975, 6769, 1453, 31099, 3335, 16939}},
+{10937, 17, 44401, {1, 1, 1, 7, 15, 21, 113, 203, 97, 847, 625, 847, 1819, 1109, 14503, 25319, 100259}},
+{10938, 17, 44408, {1, 1, 5, 11, 9, 13, 65, 21, 429, 865, 513, 2183, 3785, 11817, 6283, 23041, 7969}},
+{10939, 17, 44411, {1, 1, 5, 13, 1, 41, 109, 43, 91, 211, 1477, 3543, 5217, 3133, 12503, 15523, 12917}},
+{10940, 17, 44417, {1, 3, 7, 9, 23, 53, 109, 89, 229, 939, 1211, 2771, 541, 15915, 5411, 47273, 54453}},
+{10941, 17, 44420, {1, 1, 1, 3, 3, 45, 31, 63, 99, 347, 17, 523, 441, 12325, 15673, 1887, 15289}},
+{10942, 17, 44424, {1, 1, 1, 7, 29, 61, 35, 115, 345, 1011, 5, 595, 465, 3897, 28147, 791, 98757}},
+{10943, 17, 44444, {1, 1, 5, 9, 27, 1, 21, 155, 467, 469, 1565, 1439, 5809, 851, 32503, 3025, 97231}},
+{10944, 17, 44451, {1, 1, 1, 9, 3, 17, 15, 73, 487, 1011, 63, 2605, 6647, 9385, 4527, 21993, 19783}},
+{10945, 17, 44453, {1, 1, 3, 9, 17, 17, 65, 75, 175, 897, 1317, 2593, 1495, 15835, 12025, 57457, 29577}},
+{10946, 17, 44466, {1, 1, 1, 13, 7, 1, 13, 145, 491, 427, 375, 1235, 3045, 2991, 26607, 30581, 43377}},
+{10947, 17, 44472, {1, 1, 1, 1, 31, 1, 75, 235, 345, 75, 1505, 1401, 6921, 6207, 13729, 21545, 34703}},
+{10948, 17, 44475, {1, 3, 7, 9, 31, 35, 53, 233, 85, 385, 2045, 1401, 5365, 827, 13093, 41097, 97381}},
+{10949, 17, 44486, {1, 3, 7, 15, 5, 9, 19, 125, 49, 29, 1553, 675, 3947, 4775, 8161, 12321, 55191}},
+{10950, 17, 44500, {1, 3, 3, 7, 17, 17, 27, 237, 87, 927, 275, 1965, 4993, 1429, 31613, 38403, 119319}},
+{10951, 17, 44510, {1, 3, 7, 13, 25, 61, 87, 133, 37, 725, 697, 371, 7607, 13861, 8015, 63997, 25745}},
+{10952, 17, 44531, {1, 1, 5, 3, 1, 29, 115, 53, 355, 533, 1711, 3863, 6983, 4849, 15787, 38933, 100299}},
+{10953, 17, 44534, {1, 1, 3, 5, 7, 11, 95, 21, 363, 1005, 425, 3497, 841, 8251, 11933, 47783, 122699}},
+{10954, 17, 44553, {1, 1, 1, 11, 15, 41, 23, 159, 191, 433, 919, 3151, 5311, 2061, 11277, 4947, 10549}},
+{10955, 17, 44559, {1, 1, 5, 1, 29, 57, 23, 239, 179, 821, 1825, 1745, 4357, 4041, 27517, 8557, 86969}},
+{10956, 17, 44564, {1, 3, 1, 13, 3, 45, 91, 21, 221, 203, 683, 1787, 375, 4101, 13555, 43269, 8063}},
+{10957, 17, 44580, {1, 1, 5, 15, 17, 61, 95, 95, 285, 597, 1967, 4061, 389, 3813, 6061, 50261, 56035}},
+{10958, 17, 44583, {1, 1, 7, 9, 9, 35, 103, 255, 239, 77, 145, 4089, 757, 16151, 29963, 1229, 31895}},
+{10959, 17, 44589, {1, 1, 7, 7, 29, 51, 63, 105, 55, 609, 665, 2101, 4605, 7085, 18543, 64221, 102503}},
+{10960, 17, 44592, {1, 1, 3, 9, 23, 49, 83, 71, 191, 917, 39, 1013, 4689, 2407, 1733, 31113, 31263}},
+{10961, 17, 44609, {1, 1, 5, 11, 31, 51, 17, 223, 325, 829, 541, 3561, 5319, 15397, 12479, 57199, 38611}},
+{10962, 17, 44627, {1, 3, 1, 3, 19, 57, 19, 191, 427, 905, 1111, 695, 5447, 4061, 25543, 45699, 113283}},
+{10963, 17, 44633, {1, 1, 3, 7, 5, 11, 59, 249, 375, 889, 563, 2757, 5857, 3595, 23183, 1785, 105017}},
+{10964, 17, 44643, {1, 3, 5, 7, 11, 55, 95, 167, 27, 823, 903, 2403, 1137, 3209, 6313, 61871, 129865}},
+{10965, 17, 44646, {1, 1, 3, 11, 25, 3, 89, 171, 209, 409, 1357, 3825, 5261, 10805, 13493, 3303, 129987}},
+{10966, 17, 44650, {1, 1, 5, 1, 23, 21, 3, 207, 471, 375, 1785, 2555, 1613, 16235, 1585, 48221, 10197}},
+{10967, 17, 44674, {1, 1, 1, 15, 13, 33, 89, 185, 331, 239, 1401, 789, 2687, 15193, 20911, 18935, 28751}},
+{10968, 17, 44676, {1, 1, 1, 13, 27, 19, 111, 139, 385, 531, 1069, 2343, 7405, 10305, 7049, 48215, 77591}},
+{10969, 17, 44680, {1, 3, 7, 13, 23, 9, 113, 107, 441, 265, 1617, 63, 7629, 5505, 7059, 47307, 82527}},
+{10970, 17, 44683, {1, 3, 1, 9, 27, 27, 35, 233, 189, 517, 1285, 1843, 1569, 14921, 6617, 44337, 46917}},
+{10971, 17, 44703, {1, 1, 3, 15, 7, 15, 9, 255, 109, 629, 437, 3601, 6591, 10873, 1765, 46459, 110991}},
+{10972, 17, 44704, {1, 1, 5, 15, 17, 13, 115, 97, 401, 979, 1139, 2607, 6537, 5369, 17775, 7657, 57175}},
+{10973, 17, 44716, {1, 1, 5, 15, 27, 15, 43, 95, 271, 945, 1205, 3505, 7403, 13203, 27259, 24821, 62921}},
+{10974, 17, 44733, {1, 1, 7, 15, 9, 13, 53, 177, 93, 169, 1933, 1101, 4847, 15477, 22107, 13009, 93675}},
+{10975, 17, 44748, {1, 3, 1, 3, 13, 57, 121, 229, 353, 449, 769, 1207, 557, 5673, 13129, 29383, 35925}},
+{10976, 17, 44759, {1, 3, 3, 1, 31, 33, 5, 87, 461, 873, 795, 2715, 1421, 14723, 17917, 20681, 46103}},
+{10977, 17, 44763, {1, 1, 7, 3, 29, 5, 49, 215, 341, 25, 1473, 177, 1443, 14181, 26723, 49143, 73461}},
+{10978, 17, 44781, {1, 3, 1, 5, 17, 53, 5, 27, 1, 325, 1335, 2941, 7195, 8179, 26971, 63469, 49357}},
+{10979, 17, 44782, {1, 3, 5, 3, 3, 5, 29, 241, 119, 415, 1371, 3201, 2815, 15567, 32521, 18635, 2101}},
+{10980, 17, 44789, {1, 3, 1, 3, 7, 13, 127, 157, 271, 403, 187, 3663, 4073, 12613, 1305, 31061, 48361}},
+{10981, 17, 44794, {1, 1, 3, 5, 1, 39, 41, 201, 113, 923, 621, 497, 3823, 12543, 27273, 58509, 21613}},
+{10982, 17, 44799, {1, 1, 1, 11, 5, 51, 93, 39, 345, 175, 679, 617, 3445, 8591, 4017, 5147, 88847}},
+{10983, 17, 44804, {1, 1, 7, 7, 7, 9, 63, 7, 89, 711, 487, 69, 447, 3355, 31929, 34719, 93629}},
+{10984, 17, 44813, {1, 3, 1, 3, 27, 11, 51, 11, 471, 889, 1935, 2185, 1277, 3127, 8853, 17839, 40279}},
+{10985, 17, 44822, {1, 3, 3, 15, 25, 35, 71, 213, 121, 935, 1601, 537, 5753, 8743, 15243, 59545, 60399}},
+{10986, 17, 44838, {1, 1, 3, 15, 31, 41, 51, 205, 123, 215, 305, 3777, 4103, 7275, 21603, 56853, 54575}},
+{10987, 17, 44842, {1, 3, 7, 9, 17, 19, 37, 59, 193, 303, 1079, 3627, 6503, 14649, 10283, 64469, 83677}},
+{10988, 17, 44849, {1, 3, 1, 5, 11, 3, 115, 139, 213, 307, 721, 1611, 5093, 11817, 32503, 38559, 38449}},
+{10989, 17, 44856, {1, 3, 1, 1, 17, 31, 41, 113, 135, 733, 723, 2021, 7397, 15917, 15741, 7295, 69885}},
+{10990, 17, 44870, {1, 1, 7, 11, 31, 3, 125, 77, 89, 793, 1441, 1527, 457, 9457, 13581, 62979, 125279}},
+{10991, 17, 44887, {1, 1, 1, 5, 9, 17, 19, 115, 43, 395, 183, 2091, 7021, 7555, 20165, 45165, 58925}},
+{10992, 17, 44904, {1, 1, 1, 15, 23, 37, 97, 45, 357, 201, 425, 3605, 5305, 10079, 16397, 40635, 15355}},
+{10993, 17, 44915, {1, 1, 3, 7, 3, 43, 65, 89, 51, 801, 917, 2835, 5675, 2347, 16587, 19701, 68655}},
+{10994, 17, 44917, {1, 3, 7, 13, 11, 59, 93, 155, 53, 435, 165, 3231, 429, 12757, 27033, 14081, 12625}},
+{10995, 17, 44921, {1, 3, 1, 15, 15, 33, 121, 157, 271, 295, 901, 1689, 709, 13395, 17773, 14397, 37743}},
+{10996, 17, 44928, {1, 1, 1, 3, 7, 17, 125, 113, 223, 603, 425, 3213, 2781, 2921, 15181, 18649, 93493}},
+{10997, 17, 44933, {1, 3, 3, 5, 1, 25, 3, 101, 151, 435, 1339, 1207, 7687, 12579, 29331, 4653, 67353}},
+{10998, 17, 44934, {1, 1, 7, 1, 29, 53, 101, 61, 31, 633, 1899, 3919, 1879, 3143, 25319, 45809, 77425}},
+{10999, 17, 44937, {1, 1, 5, 1, 17, 31, 79, 247, 77, 197, 1693, 313, 2183, 14343, 4511, 26009, 44943}},
+{11000, 17, 44940, {1, 1, 7, 5, 31, 29, 119, 251, 345, 867, 271, 165, 6425, 8343, 11251, 28125, 34849}},
+{11001, 17, 44951, {1, 3, 1, 1, 13, 35, 9, 103, 365, 675, 1653, 4095, 3123, 8245, 4679, 18951, 88543}},
+{11002, 17, 44961, {1, 1, 1, 1, 23, 29, 109, 157, 253, 751, 145, 2077, 4555, 7523, 30099, 37709, 97369}},
+{11003, 17, 44962, {1, 3, 3, 11, 5, 1, 51, 11, 203, 963, 1961, 351, 6697, 8137, 25933, 53505, 28531}},
+{11004, 17, 44971, {1, 1, 7, 15, 27, 1, 31, 159, 447, 501, 1873, 2845, 875, 1671, 5049, 38901, 32559}},
+{11005, 17, 44982, {1, 1, 3, 3, 29, 19, 33, 83, 71, 703, 1861, 3683, 3589, 15339, 21075, 40399, 47853}},
+{11006, 17, 44985, {1, 3, 3, 7, 5, 41, 61, 181, 319, 77, 777, 2537, 3887, 2687, 29227, 55217, 55813}},
+{11007, 17, 44996, {1, 3, 3, 1, 25, 41, 23, 31, 31, 775, 693, 891, 861, 7613, 9557, 43275, 36311}},
+{11008, 17, 44999, {1, 1, 7, 13, 11, 5, 99, 217, 81, 441, 765, 3981, 2921, 9657, 6905, 30657, 18395}},
+{11009, 17, 45014, {1, 3, 1, 11, 21, 55, 25, 209, 13, 1021, 1373, 785, 3243, 1541, 12033, 17309, 116517}},
+{11010, 17, 45029, {1, 1, 1, 7, 3, 3, 61, 113, 453, 405, 1321, 2327, 3529, 12779, 11707, 55795, 105137}},
+{11011, 17, 45033, {1, 3, 1, 13, 15, 53, 17, 189, 197, 459, 1999, 935, 7835, 9563, 31231, 47757, 80807}},
+{11012, 17, 45036, {1, 3, 5, 13, 11, 15, 91, 115, 427, 723, 1815, 3527, 5917, 4931, 28297, 12257, 5587}},
+{11013, 17, 45047, {1, 1, 5, 9, 31, 5, 77, 201, 373, 143, 581, 1199, 6807, 6059, 3133, 57069, 4895}},
+{11014, 17, 45065, {1, 3, 1, 9, 17, 13, 127, 61, 235, 991, 279, 1545, 2875, 8453, 13329, 39763, 66897}},
+{11015, 17, 45076, {1, 1, 3, 15, 31, 51, 3, 95, 221, 685, 635, 1747, 177, 9781, 4859, 45345, 37607}},
+{11016, 17, 45085, {1, 3, 5, 1, 3, 55, 63, 51, 63, 707, 883, 2985, 3699, 3881, 8159, 41775, 41411}},
+{11017, 17, 45086, {1, 1, 1, 11, 3, 41, 69, 181, 413, 33, 525, 1883, 6063, 13787, 1259, 19497, 8119}},
+{11018, 17, 45090, {1, 1, 5, 15, 13, 27, 65, 63, 117, 831, 855, 369, 1005, 9069, 16179, 32027, 6527}},
+{11019, 17, 45107, {1, 3, 7, 5, 25, 51, 63, 163, 101, 299, 1637, 641, 2077, 9195, 11181, 59783, 109481}},
+{11020, 17, 45119, {1, 3, 5, 13, 27, 13, 117, 253, 257, 919, 709, 411, 5525, 1247, 19951, 51423, 34605}},
+{11021, 17, 45121, {1, 1, 5, 5, 1, 37, 49, 125, 87, 291, 339, 3235, 1477, 9787, 19637, 22855, 103013}},
+{11022, 17, 45128, {1, 3, 7, 15, 25, 17, 77, 23, 303, 739, 1921, 1425, 6451, 9521, 6311, 38551, 123683}},
+{11023, 17, 45139, {1, 3, 1, 7, 13, 19, 33, 73, 347, 85, 1693, 3671, 713, 1191, 3285, 6815, 61833}},
+{11024, 17, 45151, {1, 1, 3, 3, 13, 53, 81, 177, 305, 967, 551, 1177, 2315, 4899, 5733, 11147, 128895}},
+{11025, 17, 45157, {1, 3, 5, 3, 17, 17, 93, 173, 417, 645, 1631, 1817, 6127, 3545, 6127, 22331, 59751}},
+{11026, 17, 45162, {1, 1, 5, 11, 7, 53, 61, 117, 133, 141, 283, 3351, 6745, 599, 7221, 50583, 9067}},
+{11027, 17, 45164, {1, 3, 7, 3, 29, 45, 71, 177, 97, 897, 589, 3319, 1821, 7207, 25715, 13043, 96695}},
+{11028, 17, 45176, {1, 3, 3, 1, 13, 39, 19, 49, 419, 905, 1063, 4023, 145, 1479, 22197, 43883, 45503}},
+{11029, 17, 45179, {1, 3, 3, 15, 9, 45, 45, 201, 61, 193, 375, 2439, 2339, 15981, 5197, 6285, 109389}},
+{11030, 17, 45198, {1, 1, 7, 13, 29, 51, 93, 223, 509, 1003, 1861, 3715, 2511, 13843, 25297, 1241, 12157}},
+{11031, 17, 45209, {1, 3, 5, 15, 19, 17, 95, 243, 251, 485, 1837, 1829, 2081, 15117, 29635, 63861, 100397}},
+{11032, 17, 45231, {1, 1, 7, 3, 1, 37, 31, 53, 483, 849, 1197, 3069, 2539, 2529, 12749, 64331, 45757}},
+{11033, 17, 45234, {1, 3, 7, 7, 1, 19, 25, 243, 335, 99, 1507, 2155, 6085, 2253, 32439, 16141, 6781}},
+{11034, 17, 45236, {1, 3, 7, 15, 9, 13, 35, 63, 371, 373, 1891, 3913, 4577, 15553, 13079, 60251, 71193}},
+{11035, 17, 45251, {1, 3, 1, 7, 15, 13, 105, 113, 409, 289, 57, 1095, 791, 15675, 21471, 42851, 29203}},
+{11036, 17, 45260, {1, 1, 1, 13, 1, 57, 65, 7, 153, 929, 1325, 229, 3841, 8967, 29889, 49427, 46853}},
+{11037, 17, 45268, {1, 1, 3, 11, 29, 1, 79, 111, 479, 931, 1619, 505, 4503, 4055, 18849, 3979, 46091}},
+{11038, 17, 45277, {1, 1, 7, 3, 31, 27, 127, 63, 219, 43, 883, 1265, 5733, 9051, 17059, 61625, 93843}},
+{11039, 17, 45299, {1, 1, 7, 7, 23, 21, 35, 211, 243, 399, 1225, 1415, 5923, 2143, 25303, 36171, 126349}},
+{11040, 17, 45301, {1, 3, 1, 3, 3, 13, 77, 205, 271, 393, 769, 2101, 4045, 6159, 3409, 44065, 102799}},
+{11041, 17, 45338, {1, 1, 5, 15, 19, 1, 67, 199, 367, 51, 495, 2051, 3195, 15239, 10525, 45319, 50489}},
+{11042, 17, 45344, {1, 1, 1, 9, 3, 19, 105, 147, 417, 399, 373, 1025, 2727, 13779, 30079, 22723, 41551}},
+{11043, 17, 45349, {1, 1, 3, 1, 9, 15, 105, 95, 267, 995, 275, 2627, 3883, 10785, 8075, 40591, 54647}},
+{11044, 17, 45364, {1, 1, 1, 5, 31, 37, 117, 185, 55, 273, 525, 445, 4221, 2081, 16017, 19859, 3297}},
+{11045, 17, 45367, {1, 3, 5, 13, 21, 13, 105, 231, 461, 831, 393, 3253, 1213, 2625, 3393, 36715, 104889}},
+{11046, 17, 45371, {1, 3, 5, 15, 1, 17, 103, 129, 257, 1003, 285, 2927, 3967, 53, 5197, 39665, 50751}},
+{11047, 17, 45373, {1, 1, 1, 13, 1, 61, 47, 255, 137, 849, 213, 301, 681, 9547, 28209, 32941, 72109}},
+{11048, 17, 45376, {1, 1, 7, 11, 31, 15, 81, 117, 327, 289, 1861, 861, 6189, 13425, 18279, 7635, 116969}},
+{11049, 17, 45381, {1, 3, 3, 3, 9, 11, 13, 181, 183, 621, 329, 2751, 3989, 6345, 20319, 52267, 79695}},
+{11050, 17, 45400, {1, 1, 7, 13, 9, 1, 5, 125, 1, 735, 691, 13, 3961, 2273, 18299, 65221, 20115}},
+{11051, 17, 45406, {1, 3, 7, 1, 7, 3, 87, 115, 241, 101, 523, 3019, 7571, 7721, 27409, 49751, 97859}},
+{11052, 17, 45416, {1, 3, 5, 11, 9, 5, 33, 59, 299, 191, 307, 2115, 2823, 10187, 10437, 34137, 93217}},
+{11053, 17, 45422, {1, 3, 3, 7, 21, 31, 5, 113, 77, 215, 177, 2029, 7241, 4465, 31489, 10165, 19035}},
+{11054, 17, 45427, {1, 3, 5, 1, 27, 63, 11, 161, 435, 941, 1593, 1765, 1519, 9111, 12787, 35961, 105263}},
+{11055, 17, 45440, {1, 1, 1, 9, 11, 57, 41, 229, 387, 617, 1991, 221, 2857, 4337, 13851, 23185, 111031}},
+{11056, 17, 45458, {1, 1, 3, 5, 21, 27, 125, 83, 129, 919, 65, 403, 2981, 10111, 17017, 24829, 12205}},
+{11057, 17, 45467, {1, 3, 3, 9, 25, 19, 109, 47, 199, 395, 1909, 2819, 5361, 6629, 7067, 18755, 17921}},
+{11058, 17, 45474, {1, 1, 3, 15, 25, 37, 111, 129, 409, 291, 1403, 2785, 3819, 10245, 24647, 64799, 64951}},
+{11059, 17, 45476, {1, 3, 5, 11, 1, 7, 105, 223, 427, 661, 1817, 1023, 145, 927, 6507, 13235, 30147}},
+{11060, 17, 45488, {1, 3, 5, 13, 7, 15, 65, 125, 121, 113, 923, 2729, 1397, 14247, 8487, 54907, 41921}},
+{11061, 17, 45494, {1, 1, 5, 1, 13, 15, 47, 111, 453, 375, 1705, 1539, 4103, 601, 7499, 33287, 123689}},
+{11062, 17, 45497, {1, 1, 5, 3, 21, 11, 87, 115, 483, 617, 1593, 2817, 6519, 16203, 361, 34415, 100829}},
+{11063, 17, 45500, {1, 3, 7, 15, 23, 25, 41, 193, 473, 517, 1195, 3627, 1089, 13391, 3653, 25637, 5643}},
+{11064, 17, 45512, {1, 3, 1, 1, 13, 57, 29, 175, 35, 107, 5, 3641, 1843, 1507, 7591, 39967, 66859}},
+{11065, 17, 45515, {1, 1, 3, 13, 1, 39, 31, 11, 493, 123, 523, 843, 133, 7971, 14131, 51927, 97943}},
+{11066, 17, 45523, {1, 1, 3, 7, 23, 45, 5, 195, 195, 683, 497, 1215, 5855, 14569, 20441, 29541, 30431}},
+{11067, 17, 45542, {1, 3, 1, 11, 31, 39, 127, 187, 187, 17, 817, 907, 4657, 8223, 13305, 36489, 28909}},
+{11068, 17, 45553, {1, 1, 7, 13, 9, 1, 59, 27, 449, 887, 39, 191, 803, 2339, 5213, 2611, 93175}},
+{11069, 17, 45559, {1, 1, 1, 1, 29, 17, 105, 13, 175, 401, 1145, 297, 6873, 889, 10301, 48993, 49959}},
+{11070, 17, 45589, {1, 3, 5, 5, 1, 57, 81, 81, 403, 719, 1887, 2597, 1069, 5219, 29767, 46905, 8025}},
+{11071, 17, 45594, {1, 1, 5, 11, 13, 37, 41, 3, 487, 895, 343, 1729, 3777, 8681, 24737, 34179, 15015}},
+{11072, 17, 45596, {1, 1, 1, 15, 9, 43, 67, 203, 71, 399, 23, 529, 2375, 15373, 21013, 17389, 93809}},
+{11073, 17, 45603, {1, 3, 7, 7, 9, 23, 81, 27, 39, 529, 631, 199, 3555, 953, 4249, 39297, 88107}},
+{11074, 17, 45605, {1, 3, 1, 3, 31, 45, 33, 63, 319, 245, 1567, 3359, 2051, 11523, 30177, 20293, 13245}},
+{11075, 17, 45610, {1, 1, 1, 13, 9, 61, 39, 127, 453, 1019, 2037, 3541, 6983, 10717, 19587, 8981, 99637}},
+{11076, 17, 45630, {1, 3, 5, 9, 15, 7, 55, 79, 93, 303, 1423, 499, 5499, 795, 14553, 16945, 46161}},
+{11077, 17, 45638, {1, 1, 7, 5, 21, 21, 27, 201, 147, 461, 363, 267, 2963, 3409, 17835, 40777, 71879}},
+{11078, 17, 45641, {1, 1, 7, 9, 23, 63, 115, 243, 103, 119, 2023, 2223, 7989, 1365, 26181, 4631, 88001}},
+{11079, 17, 45647, {1, 3, 5, 5, 27, 57, 101, 199, 461, 853, 449, 2733, 2225, 8609, 19461, 15265, 54079}},
+{11080, 17, 45655, {1, 3, 3, 15, 29, 59, 115, 105, 145, 391, 303, 901, 5481, 1491, 30441, 22331, 3841}},
+{11081, 17, 45659, {1, 1, 3, 1, 27, 45, 11, 167, 73, 181, 253, 1947, 1731, 15269, 16971, 12299, 46439}},
+{11082, 17, 45665, {1, 1, 7, 13, 11, 21, 83, 157, 75, 705, 1709, 487, 5029, 9879, 27589, 21601, 50575}},
+{11083, 17, 45689, {1, 1, 5, 3, 27, 37, 101, 163, 115, 903, 1137, 3807, 2899, 3407, 27935, 14203, 31009}},
+{11084, 17, 45695, {1, 3, 5, 9, 31, 33, 63, 69, 159, 737, 1973, 3661, 6159, 1781, 9239, 12989, 82947}},
+{11085, 17, 45702, {1, 3, 5, 9, 15, 33, 41, 89, 183, 933, 1305, 1013, 7245, 16225, 10891, 6641, 61699}},
+{11086, 17, 45708, {1, 1, 5, 3, 25, 41, 91, 183, 45, 553, 1817, 3305, 5169, 9051, 24917, 52431, 52505}},
+{11087, 17, 45726, {1, 3, 3, 9, 3, 9, 127, 59, 117, 1001, 1255, 3435, 3797, 8507, 28593, 24119, 75569}},
+{11088, 17, 45729, {1, 3, 1, 5, 17, 43, 45, 21, 461, 339, 1127, 2213, 7351, 14585, 2001, 32619, 33825}},
+{11089, 17, 45739, {1, 1, 5, 11, 3, 37, 61, 83, 101, 707, 861, 3037, 1867, 7747, 16313, 58745, 14387}},
+{11090, 17, 45744, {1, 1, 5, 3, 27, 25, 99, 17, 293, 867, 1655, 2301, 2007, 7379, 14487, 18233, 3625}},
+{11091, 17, 45747, {1, 1, 7, 13, 25, 29, 21, 133, 207, 119, 423, 1561, 6587, 1221, 27295, 48141, 125473}},
+{11092, 17, 45762, {1, 3, 3, 1, 19, 45, 39, 85, 127, 249, 157, 1307, 7343, 6309, 31073, 16909, 93223}},
+{11093, 17, 45764, {1, 1, 5, 13, 19, 43, 111, 109, 385, 847, 1071, 1009, 2783, 8471, 5719, 50459, 110507}},
+{11094, 17, 45773, {1, 1, 5, 15, 1, 45, 39, 197, 209, 839, 485, 3943, 5939, 11835, 18297, 61217, 85015}},
+{11095, 17, 45774, {1, 1, 1, 15, 5, 61, 1, 195, 415, 355, 1593, 151, 8143, 3527, 11633, 44337, 99749}},
+{11096, 17, 45781, {1, 1, 5, 13, 11, 11, 117, 109, 91, 663, 1351, 2361, 1409, 9317, 31133, 17577, 123919}},
+{11097, 17, 45785, {1, 3, 3, 9, 3, 5, 115, 173, 459, 937, 1581, 781, 1069, 573, 24025, 30721, 116837}},
+{11098, 17, 45792, {1, 1, 1, 5, 21, 37, 47, 51, 21, 169, 119, 3285, 2543, 14023, 29179, 13407, 130491}},
+{11099, 17, 45801, {1, 3, 5, 5, 25, 27, 41, 147, 485, 79, 737, 699, 6763, 16347, 9265, 52129, 41431}},
+{11100, 17, 45802, {1, 1, 1, 3, 5, 33, 115, 187, 311, 717, 1897, 2215, 2639, 4167, 1429, 26359, 52703}},
+{11101, 17, 45812, {1, 3, 5, 5, 13, 51, 103, 5, 47, 683, 319, 2969, 7701, 11031, 9257, 16725, 80825}},
+{11102, 17, 45816, {1, 3, 1, 11, 31, 47, 17, 205, 11, 411, 523, 4053, 6743, 3095, 3219, 63163, 84547}},
+{11103, 17, 45829, {1, 1, 7, 15, 9, 55, 109, 225, 273, 595, 1697, 2059, 21, 11319, 23277, 60613, 4539}},
+{11104, 17, 45833, {1, 1, 5, 13, 3, 59, 49, 239, 509, 847, 975, 3361, 5443, 1941, 29277, 56379, 38997}},
+{11105, 17, 45847, {1, 3, 1, 7, 15, 5, 49, 19, 235, 437, 1309, 827, 4123, 5839, 22409, 42535, 98041}},
+{11106, 17, 45851, {1, 1, 5, 15, 9, 33, 57, 153, 165, 215, 177, 1271, 1861, 15489, 4183, 43701, 114169}},
+{11107, 17, 45854, {1, 3, 5, 5, 13, 3, 119, 89, 17, 421, 1205, 835, 4917, 6113, 28991, 26839, 114871}},
+{11108, 17, 45863, {1, 3, 5, 1, 7, 49, 49, 159, 205, 601, 1939, 4063, 5975, 11747, 10329, 21103, 16779}},
+{11109, 17, 45870, {1, 1, 5, 15, 13, 33, 89, 21, 113, 639, 891, 989, 829, 1435, 11475, 42711, 67049}},
+{11110, 17, 45901, {1, 1, 5, 5, 9, 59, 57, 105, 385, 733, 1175, 329, 6809, 7175, 27267, 9941, 14203}},
+{11111, 17, 45910, {1, 3, 1, 13, 21, 53, 83, 139, 287, 659, 1991, 3225, 4153, 4325, 16803, 27719, 86263}},
+{11112, 17, 45920, {1, 3, 5, 13, 27, 21, 111, 105, 29, 573, 405, 2781, 1737, 12057, 25263, 16903, 45389}},
+{11113, 17, 45932, {1, 1, 5, 5, 23, 23, 61, 27, 335, 279, 937, 2509, 4751, 2993, 28069, 30187, 3595}},
+{11114, 17, 45938, {1, 1, 5, 7, 29, 37, 117, 71, 221, 875, 1987, 2329, 5953, 15901, 29813, 17419, 4745}},
+{11115, 17, 45940, {1, 3, 3, 13, 21, 51, 77, 85, 53, 573, 1129, 3415, 2283, 5221, 29991, 46091, 65843}},
+{11116, 17, 45943, {1, 1, 1, 3, 17, 51, 89, 211, 463, 743, 1189, 4083, 1437, 5219, 8373, 15559, 18557}},
+{11117, 17, 45949, {1, 1, 5, 3, 29, 27, 1, 207, 285, 739, 505, 1587, 6565, 14195, 4995, 39453, 61023}},
+{11118, 17, 45953, {1, 3, 3, 15, 7, 57, 19, 45, 39, 881, 1207, 2829, 3265, 2637, 7843, 62889, 53289}},
+{11119, 17, 45963, {1, 1, 1, 11, 31, 21, 73, 245, 87, 457, 1523, 2397, 1157, 8237, 26195, 23149, 106523}},
+{11120, 17, 45971, {1, 3, 5, 13, 3, 55, 3, 179, 107, 85, 639, 2711, 6359, 1599, 2325, 59573, 111941}},
+{11121, 17, 45989, {1, 1, 1, 13, 17, 61, 45, 253, 45, 149, 1251, 139, 7113, 6503, 27675, 37301, 21713}},
+{11122, 17, 45999, {1, 3, 5, 9, 31, 31, 67, 79, 355, 225, 1187, 761, 4927, 5481, 9139, 13399, 35653}},
+{11123, 17, 46001, {1, 1, 5, 3, 7, 3, 95, 119, 161, 529, 1443, 1099, 609, 3919, 10935, 37779, 92993}},
+{11124, 17, 46008, {1, 1, 7, 9, 13, 21, 13, 7, 165, 173, 989, 2315, 2305, 13115, 6933, 56233, 112113}},
+{11125, 17, 46022, {1, 1, 7, 3, 9, 11, 25, 45, 493, 119, 839, 3907, 2273, 14113, 29453, 55181, 667}},
+{11126, 17, 46026, {1, 3, 5, 15, 25, 33, 15, 23, 245, 517, 1883, 2865, 1483, 7043, 32615, 12261, 49297}},
+{11127, 17, 46034, {1, 3, 7, 9, 31, 35, 89, 103, 245, 441, 1709, 1321, 3743, 3767, 23885, 43587, 18017}},
+{11128, 17, 46040, {1, 3, 7, 5, 23, 43, 103, 7, 47, 187, 1257, 3517, 591, 16263, 12047, 16699, 81633}},
+{11129, 17, 46043, {1, 1, 5, 15, 5, 5, 79, 11, 327, 719, 37, 2913, 6107, 3463, 25901, 6125, 100647}},
+{11130, 17, 46045, {1, 1, 1, 11, 13, 29, 83, 251, 41, 125, 1137, 2627, 4643, 29, 24631, 51435, 98643}},
+{11131, 17, 46061, {1, 1, 7, 3, 27, 3, 69, 245, 365, 599, 1575, 2969, 3441, 12327, 18951, 56167, 13861}},
+{11132, 17, 46062, {1, 3, 3, 11, 5, 47, 103, 233, 351, 821, 867, 3199, 6133, 4627, 22663, 14775, 83205}},
+{11133, 17, 46076, {1, 3, 1, 13, 9, 35, 27, 251, 281, 727, 873, 3713, 5247, 8407, 17739, 57207, 126201}},
+{11134, 17, 46084, {1, 1, 7, 11, 11, 35, 53, 115, 93, 663, 625, 565, 3137, 7869, 18845, 49155, 83395}},
+{11135, 17, 46094, {1, 3, 3, 5, 21, 13, 99, 151, 319, 9, 1363, 1489, 2545, 1963, 1271, 24815, 43355}},
+{11136, 17, 46102, {1, 3, 5, 9, 15, 51, 109, 85, 67, 131, 1947, 181, 7331, 15163, 2255, 33449, 78107}},
+{11137, 17, 46118, {1, 1, 7, 9, 27, 61, 1, 163, 309, 739, 453, 1837, 2093, 16021, 8485, 19755, 61335}},
+{11138, 17, 46149, {1, 3, 5, 7, 3, 13, 11, 195, 91, 143, 203, 2785, 7319, 7153, 19265, 11597, 63365}},
+{11139, 17, 46154, {1, 3, 1, 9, 29, 1, 123, 247, 253, 757, 191, 1699, 6625, 1785, 29199, 29409, 32577}},
+{11140, 17, 46167, {1, 3, 5, 11, 23, 21, 31, 35, 383, 587, 65, 1695, 4045, 12305, 12437, 5919, 51465}},
+{11141, 17, 46173, {1, 1, 5, 9, 11, 13, 123, 171, 499, 877, 1785, 561, 2547, 1797, 27679, 56305, 93223}},
+{11142, 17, 46177, {1, 3, 1, 3, 25, 41, 63, 243, 219, 533, 753, 1903, 3257, 11901, 4777, 28629, 111141}},
+{11143, 17, 46192, {1, 3, 3, 5, 31, 47, 1, 253, 283, 995, 1787, 1767, 6599, 11913, 21515, 39259, 117727}},
+{11144, 17, 46197, {1, 1, 7, 7, 31, 35, 39, 255, 463, 763, 881, 2583, 347, 14343, 22761, 45821, 119155}},
+{11145, 17, 46201, {1, 3, 5, 9, 5, 37, 43, 55, 423, 525, 157, 3593, 2831, 11539, 15675, 11695, 100609}},
+{11146, 17, 46214, {1, 3, 3, 5, 11, 9, 27, 57, 409, 201, 1029, 2461, 5823, 2593, 32031, 4203, 55327}},
+{11147, 17, 46217, {1, 1, 7, 15, 15, 25, 69, 83, 309, 687, 1607, 819, 7381, 3697, 5289, 33153, 48157}},
+{11148, 17, 46223, {1, 1, 5, 5, 31, 57, 41, 195, 201, 59, 2045, 2213, 6695, 3839, 17331, 4981, 26803}},
+{11149, 17, 46226, {1, 1, 1, 11, 7, 53, 109, 169, 387, 181, 391, 19, 4159, 299, 29059, 27781, 110193}},
+{11150, 17, 46228, {1, 3, 7, 15, 5, 31, 95, 155, 47, 601, 1463, 1799, 8027, 3003, 18067, 24589, 108171}},
+{11151, 17, 46237, {1, 3, 3, 7, 11, 61, 21, 121, 117, 149, 1037, 3829, 3581, 15223, 17051, 34539, 37263}},
+{11152, 17, 46241, {1, 3, 3, 3, 15, 15, 115, 91, 443, 309, 1073, 2053, 789, 7415, 26253, 62657, 49729}},
+{11153, 17, 46251, {1, 3, 5, 5, 31, 19, 23, 221, 19, 105, 1105, 2025, 4209, 7531, 30191, 40777, 46069}},
+{11154, 17, 46259, {1, 1, 1, 7, 29, 45, 29, 215, 33, 21, 1147, 1725, 3711, 2759, 12731, 57031, 42361}},
+{11155, 17, 46262, {1, 1, 5, 15, 13, 59, 111, 169, 317, 841, 1387, 3513, 3137, 8265, 31789, 26963, 126219}},
+{11156, 17, 46266, {1, 1, 3, 1, 23, 21, 13, 113, 71, 177, 345, 3149, 1461, 12945, 3971, 59759, 61839}},
+{11157, 17, 46294, {1, 3, 5, 13, 9, 19, 103, 17, 95, 617, 1477, 263, 4259, 12899, 24351, 47431, 11583}},
+{11158, 17, 46300, {1, 3, 5, 11, 13, 11, 7, 61, 13, 63, 1687, 631, 381, 5899, 10225, 19657, 37087}},
+{11159, 17, 46303, {1, 3, 5, 3, 7, 53, 11, 193, 103, 427, 1097, 299, 2905, 5019, 31803, 28931, 47495}},
+{11160, 17, 46309, {1, 3, 3, 11, 21, 31, 125, 249, 233, 941, 975, 2287, 7837, 6481, 11021, 52829, 63023}},
+{11161, 17, 46321, {1, 1, 7, 15, 13, 17, 33, 85, 503, 11, 689, 637, 4063, 12223, 1835, 17161, 35213}},
+{11162, 17, 46331, {1, 3, 5, 13, 25, 37, 21, 135, 377, 623, 895, 2547, 2757, 9055, 17337, 65457, 24737}},
+{11163, 17, 46339, {1, 1, 1, 15, 25, 11, 17, 95, 65, 271, 1791, 841, 1441, 11177, 10087, 63963, 71481}},
+{11164, 17, 46342, {1, 3, 5, 11, 31, 1, 37, 107, 109, 459, 1185, 2155, 271, 11775, 23243, 53517, 103669}},
+{11165, 17, 46354, {1, 3, 1, 9, 1, 49, 23, 141, 169, 475, 469, 2271, 1379, 13139, 1765, 63625, 14143}},
+{11166, 17, 46370, {1, 1, 1, 9, 13, 7, 23, 219, 381, 105, 743, 1745, 2999, 661, 7245, 39653, 99913}},
+{11167, 17, 46372, {1, 3, 1, 11, 7, 35, 9, 215, 41, 537, 1569, 1803, 3613, 667, 15089, 39485, 85457}},
+{11168, 17, 46379, {1, 1, 1, 15, 9, 49, 75, 235, 119, 97, 273, 209, 2707, 2071, 21943, 60249, 57737}},
+{11169, 17, 46382, {1, 1, 5, 15, 31, 19, 33, 49, 279, 461, 143, 3001, 3539, 1015, 27597, 35389, 36483}},
+{11170, 17, 46393, {1, 3, 7, 1, 23, 51, 123, 247, 485, 343, 1365, 593, 6465, 12305, 29375, 30641, 43165}},
+{11171, 17, 46402, {1, 1, 7, 13, 15, 11, 125, 51, 235, 717, 1427, 3203, 1711, 12607, 8805, 5773, 27467}},
+{11172, 17, 46407, {1, 3, 5, 5, 5, 13, 51, 181, 133, 977, 469, 2513, 6819, 12985, 8917, 47317, 47557}},
+{11173, 17, 46416, {1, 1, 5, 7, 3, 7, 71, 17, 345, 921, 1621, 2801, 5825, 827, 17711, 33701, 113503}},
+{11174, 17, 46425, {1, 3, 1, 1, 17, 7, 99, 83, 73, 349, 567, 713, 5639, 4969, 11549, 35317, 28995}},
+{11175, 17, 46437, {1, 3, 3, 9, 11, 53, 123, 227, 391, 775, 1013, 3971, 6183, 14453, 6403, 57063, 7123}},
+{11176, 17, 46444, {1, 1, 1, 15, 27, 13, 51, 147, 151, 535, 2017, 3019, 6791, 3931, 12529, 30855, 33243}},
+{11177, 17, 46447, {1, 3, 1, 1, 27, 43, 103, 85, 135, 207, 621, 251, 3723, 10893, 29533, 31023, 11043}},
+{11178, 17, 46449, {1, 3, 7, 5, 7, 39, 55, 133, 141, 63, 237, 3299, 861, 15123, 11859, 13271, 32893}},
+{11179, 17, 46456, {1, 3, 7, 9, 23, 17, 73, 197, 113, 725, 137, 2835, 2877, 6913, 22949, 56071, 67597}},
+{11180, 17, 46462, {1, 3, 7, 7, 15, 3, 15, 253, 51, 443, 15, 2549, 7833, 4713, 29211, 22339, 6009}},
+{11181, 17, 46472, {1, 3, 5, 15, 19, 55, 35, 59, 281, 995, 1113, 605, 2345, 10009, 14629, 11757, 53241}},
+{11182, 17, 46475, {1, 1, 1, 11, 3, 31, 11, 193, 437, 1003, 873, 909, 6513, 2045, 10495, 17387, 25461}},
+{11183, 17, 46486, {1, 1, 3, 5, 21, 61, 47, 177, 379, 773, 951, 419, 4455, 10171, 17403, 19045, 87327}},
+{11184, 17, 46490, {1, 3, 3, 11, 31, 41, 69, 229, 207, 299, 1743, 1417, 4785, 1327, 26967, 43077, 124319}},
+{11185, 17, 46495, {1, 3, 7, 15, 19, 37, 65, 219, 33, 691, 205, 1577, 4775, 8427, 28315, 53559, 100789}},
+{11186, 17, 46501, {1, 3, 5, 11, 5, 39, 55, 147, 139, 871, 1563, 3661, 4791, 423, 30007, 1589, 20255}},
+{11187, 17, 46514, {1, 1, 3, 15, 5, 61, 89, 83, 261, 519, 1367, 2019, 3799, 8237, 9011, 28995, 1587}},
+{11188, 17, 46526, {1, 1, 7, 15, 17, 55, 49, 41, 353, 507, 1565, 3365, 7947, 10391, 1323, 61591, 126305}},
+{11189, 17, 46528, {1, 3, 3, 5, 13, 19, 49, 195, 355, 915, 1867, 3513, 1239, 4809, 16925, 22947, 92641}},
+{11190, 17, 46538, {1, 1, 7, 3, 31, 51, 45, 241, 55, 195, 1233, 3675, 8077, 4981, 17679, 53025, 77927}},
+{11191, 17, 46551, {1, 3, 5, 11, 23, 5, 93, 49, 277, 979, 1093, 3031, 6131, 8085, 19121, 45305, 6705}},
+{11192, 17, 46552, {1, 1, 7, 13, 29, 25, 83, 105, 469, 729, 1495, 2607, 2681, 13959, 101, 1913, 2671}},
+{11193, 17, 46564, {1, 1, 1, 15, 7, 19, 63, 105, 253, 807, 1889, 2433, 1591, 16267, 11997, 18939, 113313}},
+{11194, 17, 46579, {1, 1, 5, 3, 13, 23, 29, 227, 337, 115, 783, 475, 6949, 9485, 1797, 18713, 123981}},
+{11195, 17, 46586, {1, 3, 3, 9, 21, 43, 115, 225, 147, 753, 919, 1157, 2901, 14813, 30035, 52553, 30225}},
+{11196, 17, 46602, {1, 1, 3, 15, 23, 19, 65, 83, 457, 965, 579, 2133, 291, 2033, 7533, 52995, 92243}},
+{11197, 17, 46615, {1, 1, 1, 5, 11, 3, 23, 245, 255, 373, 1119, 3695, 6449, 13497, 817, 32215, 103599}},
+{11198, 17, 46616, {1, 3, 1, 5, 5, 19, 57, 53, 145, 441, 1253, 929, 1299, 11491, 29457, 11245, 55717}},
+{11199, 17, 46621, {1, 1, 7, 13, 9, 13, 73, 85, 127, 29, 629, 409, 2487, 13079, 3767, 27985, 110139}},
+{11200, 17, 46635, {1, 1, 5, 11, 29, 39, 27, 9, 487, 623, 757, 2879, 669, 12521, 23471, 47933, 41721}},
+{11201, 17, 46643, {1, 1, 7, 15, 21, 9, 59, 39, 325, 787, 1347, 3039, 7333, 9793, 19337, 41285, 48339}},
+{11202, 17, 46645, {1, 3, 3, 11, 11, 21, 127, 45, 173, 981, 483, 3707, 3651, 10545, 16865, 62105, 114847}},
+{11203, 17, 46649, {1, 3, 5, 11, 11, 49, 89, 179, 393, 455, 1775, 1903, 8173, 12589, 17281, 57687, 56153}},
+{11204, 17, 46667, {1, 3, 1, 3, 7, 7, 59, 223, 255, 559, 375, 2427, 6921, 3709, 24767, 16213, 60373}},
+{11205, 17, 46670, {1, 1, 7, 15, 3, 31, 37, 129, 307, 1023, 1807, 519, 6779, 8997, 15383, 4391, 61161}},
+{11206, 17, 46672, {1, 1, 1, 1, 9, 25, 53, 27, 263, 459, 1015, 417, 4195, 10931, 20507, 19299, 82371}},
+{11207, 17, 46678, {1, 1, 3, 1, 7, 7, 49, 221, 47, 7, 1747, 1533, 3089, 14369, 32609, 64157, 78139}},
+{11208, 17, 46681, {1, 3, 7, 5, 5, 13, 101, 231, 227, 19, 1359, 3017, 1405, 3715, 3541, 933, 1117}},
+{11209, 17, 46684, {1, 1, 7, 15, 5, 63, 59, 253, 269, 781, 1639, 2247, 1041, 667, 7055, 21221, 84447}},
+{11210, 17, 46687, {1, 1, 7, 3, 9, 13, 115, 247, 215, 173, 457, 1125, 5613, 13171, 17847, 26323, 68461}},
+{11211, 17, 46705, {1, 3, 5, 9, 15, 19, 95, 213, 425, 567, 1625, 1659, 6961, 10569, 20985, 17255, 89919}},
+{11212, 17, 46708, {1, 3, 5, 5, 3, 11, 107, 123, 265, 743, 499, 1885, 6079, 7791, 24953, 30925, 112517}},
+{11213, 17, 46721, {1, 1, 5, 15, 29, 27, 103, 195, 119, 873, 1751, 2091, 6623, 7583, 20413, 52367, 16831}},
+{11214, 17, 46724, {1, 1, 7, 7, 21, 15, 111, 197, 89, 107, 1317, 2107, 1951, 189, 31663, 63007, 21405}},
+{11215, 17, 46739, {1, 3, 1, 13, 27, 15, 93, 251, 209, 93, 1419, 3785, 1899, 3143, 3205, 16309, 121455}},
+{11216, 17, 46757, {1, 1, 7, 7, 17, 43, 23, 251, 425, 591, 1101, 1317, 6369, 14209, 10257, 33813, 59557}},
+{11217, 17, 46762, {1, 1, 7, 3, 5, 41, 65, 59, 327, 369, 1867, 1045, 4953, 3155, 25679, 8545, 22753}},
+{11218, 17, 46764, {1, 1, 5, 3, 5, 25, 117, 97, 369, 721, 1459, 2501, 4899, 5299, 3859, 2509, 127723}},
+{11219, 17, 46776, {1, 3, 3, 1, 27, 13, 65, 185, 255, 543, 2013, 2027, 1131, 4067, 1327, 44639, 53275}},
+{11220, 17, 46784, {1, 1, 7, 3, 11, 15, 53, 67, 265, 477, 971, 3201, 51, 10599, 23691, 10493, 130347}},
+{11221, 17, 46790, {1, 3, 7, 7, 19, 35, 47, 61, 375, 547, 1867, 1147, 7775, 12757, 15101, 63243, 89817}},
+{11222, 17, 46796, {1, 1, 5, 3, 5, 21, 57, 59, 145, 901, 835, 1093, 6487, 12727, 20585, 6309, 67803}},
+{11223, 17, 46799, {1, 1, 1, 11, 13, 31, 75, 171, 189, 741, 1923, 3503, 4887, 15423, 2499, 39125, 4125}},
+{11224, 17, 46802, {1, 3, 7, 1, 29, 31, 103, 207, 383, 631, 1017, 1693, 6251, 9429, 17491, 60959, 68131}},
+{11225, 17, 46813, {1, 1, 1, 1, 19, 45, 127, 105, 451, 287, 657, 3521, 2021, 15793, 8993, 34837, 65441}},
+{11226, 17, 46814, {1, 1, 7, 9, 17, 15, 13, 189, 255, 753, 1779, 3047, 1179, 13201, 28249, 5909, 35775}},
+{11227, 17, 46824, {1, 3, 3, 3, 5, 11, 125, 207, 375, 375, 135, 2939, 1141, 12211, 727, 16137, 52253}},
+{11228, 17, 46832, {1, 3, 7, 9, 29, 3, 83, 221, 281, 299, 667, 3435, 589, 8039, 7991, 24289, 13079}},
+{11229, 17, 46841, {1, 3, 5, 13, 9, 11, 11, 99, 337, 155, 233, 2497, 3385, 15045, 5783, 40915, 19201}},
+{11230, 17, 46856, {1, 1, 7, 5, 5, 23, 25, 223, 341, 149, 505, 893, 4933, 14899, 29899, 207, 125359}},
+{11231, 17, 46862, {1, 3, 3, 15, 3, 5, 43, 165, 21, 993, 1091, 3849, 6005, 1905, 7199, 13495, 76915}},
+{11232, 17, 46864, {1, 1, 1, 15, 1, 19, 55, 217, 179, 431, 935, 2219, 8135, 15071, 17437, 43271, 115963}},
+{11233, 17, 46869, {1, 1, 7, 15, 7, 61, 45, 157, 441, 107, 1955, 2877, 5285, 12157, 21783, 60999, 102949}},
+{11234, 17, 46874, {1, 1, 1, 3, 9, 29, 41, 75, 81, 73, 1859, 2923, 3009, 10847, 30257, 44527, 21933}},
+{11235, 17, 46895, {1, 1, 3, 3, 29, 29, 103, 3, 401, 197, 237, 3727, 7919, 13669, 26869, 64987, 1581}},
+{11236, 17, 46900, {1, 1, 5, 13, 13, 47, 99, 209, 45, 745, 1239, 663, 5535, 3777, 10479, 15327, 1441}},
+{11237, 17, 46903, {1, 3, 1, 9, 1, 49, 31, 231, 15, 1001, 773, 2113, 1957, 15271, 25355, 7461, 33089}},
+{11238, 17, 46927, {1, 1, 1, 5, 13, 31, 123, 123, 439, 373, 1817, 2555, 7905, 3151, 2311, 62083, 45535}},
+{11239, 17, 46946, {1, 3, 1, 3, 31, 37, 83, 117, 177, 483, 1285, 1725, 821, 2115, 12893, 54301, 36491}},
+{11240, 17, 46948, {1, 3, 3, 3, 9, 13, 87, 7, 467, 287, 1173, 2739, 3293, 883, 9123, 30799, 110221}},
+{11241, 17, 46955, {1, 3, 1, 15, 3, 5, 119, 235, 393, 789, 67, 1193, 1613, 8607, 17371, 16723, 103747}},
+{11242, 17, 46965, {1, 3, 1, 13, 13, 47, 61, 51, 447, 1, 1221, 1619, 3785, 5851, 10557, 51181, 6535}},
+{11243, 17, 46972, {1, 3, 5, 11, 1, 1, 85, 119, 195, 177, 805, 1161, 4851, 15765, 24405, 41757, 110081}},
+{11244, 17, 46976, {1, 1, 7, 1, 17, 21, 89, 13, 59, 169, 1847, 2401, 6243, 2841, 6153, 16039, 47407}},
+{11245, 17, 46985, {1, 1, 3, 15, 21, 53, 103, 187, 143, 897, 65, 3677, 213, 4027, 22365, 53703, 82951}},
+{11246, 17, 46999, {1, 3, 5, 5, 25, 5, 39, 49, 55, 71, 825, 2123, 2345, 5683, 18027, 29897, 53023}},
+{11247, 17, 47003, {1, 1, 3, 5, 13, 55, 27, 77, 327, 429, 1219, 2103, 7095, 13461, 31027, 15383, 98485}},
+{11248, 17, 47006, {1, 3, 1, 3, 9, 41, 33, 241, 487, 229, 1743, 951, 2319, 15595, 3213, 5959, 90721}},
+{11249, 17, 47016, {1, 1, 7, 1, 29, 45, 45, 163, 123, 227, 305, 1577, 5465, 5639, 14507, 65155, 71425}},
+{11250, 17, 47030, {1, 1, 5, 1, 3, 5, 33, 15, 203, 141, 465, 3509, 6653, 14193, 7073, 22525, 22951}},
+{11251, 17, 47034, {1, 1, 7, 3, 27, 39, 3, 27, 75, 821, 1329, 3655, 4715, 7659, 31957, 60219, 79123}},
+{11252, 17, 47053, {1, 3, 5, 13, 29, 45, 111, 19, 207, 387, 87, 3731, 7427, 13351, 9497, 34285, 25623}},
+{11253, 17, 47056, {1, 1, 3, 11, 19, 39, 79, 219, 97, 125, 947, 1397, 3645, 1021, 9403, 38695, 54985}},
+{11254, 17, 47059, {1, 3, 3, 7, 3, 3, 45, 93, 65, 289, 1843, 1599, 897, 16159, 23485, 24699, 43123}},
+{11255, 17, 47072, {1, 3, 5, 3, 15, 1, 81, 219, 299, 429, 1115, 1763, 6381, 869, 7817, 143, 23583}},
+{11256, 17, 47077, {1, 1, 3, 5, 1, 35, 95, 147, 425, 1011, 1039, 2875, 3089, 3685, 9995, 13279, 60923}},
+{11257, 17, 47099, {1, 1, 5, 7, 5, 59, 105, 241, 151, 307, 735, 1541, 3115, 12331, 19535, 56965, 127015}},
+{11258, 17, 47105, {1, 3, 5, 7, 5, 33, 83, 179, 65, 397, 787, 3425, 1305, 10713, 6973, 9007, 112081}},
+{11259, 17, 47108, {1, 3, 7, 13, 29, 11, 37, 31, 271, 501, 897, 1383, 5333, 13627, 22091, 38421, 94575}},
+{11260, 17, 47112, {1, 3, 1, 1, 9, 61, 87, 115, 13, 79, 391, 2385, 7157, 3369, 26035, 883, 34705}},
+{11261, 17, 47115, {1, 1, 3, 9, 21, 29, 15, 165, 53, 719, 1509, 1295, 4437, 8229, 17961, 55297, 62635}},
+{11262, 17, 47117, {1, 1, 7, 5, 27, 21, 23, 141, 341, 423, 9, 2693, 5555, 5797, 13179, 1107, 33489}},
+{11263, 17, 47120, {1, 3, 1, 13, 27, 33, 101, 29, 379, 119, 1259, 861, 6843, 69, 3253, 61977, 80061}},
+{11264, 17, 47129, {1, 1, 3, 11, 1, 37, 35, 43, 105, 655, 221, 873, 91, 9095, 8999, 44033, 24807}},
+{11265, 17, 47135, {1, 3, 3, 7, 29, 15, 23, 227, 399, 305, 2007, 747, 2717, 14767, 6515, 40617, 7873}},
+{11266, 17, 47151, {1, 1, 5, 15, 21, 43, 39, 7, 261, 421, 505, 1433, 1155, 5621, 2337, 54027, 54039}},
+{11267, 17, 47154, {1, 1, 1, 9, 15, 39, 49, 185, 503, 895, 1321, 375, 4245, 4929, 9637, 50561, 65733}},
+{11268, 17, 47156, {1, 1, 5, 15, 7, 29, 27, 155, 423, 631, 1295, 973, 4227, 2637, 8479, 29527, 70505}},
+{11269, 17, 47166, {1, 3, 1, 3, 31, 33, 13, 67, 195, 335, 1577, 3715, 559, 7251, 7215, 46443, 125359}},
+{11270, 17, 47171, {1, 3, 1, 9, 17, 37, 15, 119, 79, 851, 911, 3549, 99, 9221, 29897, 63489, 34937}},
+{11271, 17, 47195, {1, 3, 5, 9, 31, 11, 125, 1, 265, 467, 835, 2997, 2401, 9615, 19397, 50947, 29963}},
+{11272, 17, 47204, {1, 1, 5, 3, 11, 21, 63, 15, 471, 763, 1963, 2815, 4419, 11457, 7151, 27009, 124847}},
+{11273, 17, 47213, {1, 1, 7, 3, 19, 9, 97, 59, 375, 109, 519, 305, 2787, 3001, 14199, 27415, 35403}},
+{11274, 17, 47222, {1, 1, 1, 3, 13, 47, 3, 93, 307, 979, 419, 2817, 3741, 305, 1813, 34549, 116959}},
+{11275, 17, 47228, {1, 3, 5, 13, 13, 19, 35, 231, 493, 973, 895, 1583, 1843, 9057, 27705, 32333, 130347}},
+{11276, 17, 47241, {1, 1, 1, 13, 31, 35, 81, 11, 363, 229, 1865, 2849, 7805, 877, 3965, 45337, 33239}},
+{11277, 17, 47242, {1, 3, 5, 1, 15, 3, 125, 93, 191, 405, 1359, 929, 3085, 7907, 7777, 7815, 103717}},
+{11278, 17, 47247, {1, 1, 3, 7, 15, 33, 61, 235, 283, 141, 817, 1611, 665, 13113, 4197, 45831, 44505}},
+{11279, 17, 47249, {1, 1, 5, 5, 25, 3, 63, 159, 223, 531, 1147, 2323, 2715, 10319, 32203, 23943, 95407}},
+{11280, 17, 47250, {1, 3, 3, 3, 3, 33, 37, 99, 317, 811, 515, 339, 6527, 11149, 13071, 7177, 1549}},
+{11281, 17, 47261, {1, 3, 1, 11, 31, 53, 9, 17, 297, 259, 1235, 53, 7065, 1721, 8191, 21663, 13393}},
+{11282, 17, 47266, {1, 3, 7, 7, 29, 41, 127, 179, 113, 191, 783, 861, 6509, 5199, 3369, 18327, 30647}},
+{11283, 17, 47268, {1, 3, 1, 7, 23, 41, 49, 155, 135, 513, 1127, 1443, 8081, 2553, 10389, 35459, 122513}},
+{11284, 17, 47278, {1, 1, 7, 3, 25, 3, 117, 125, 283, 165, 1409, 1587, 7915, 12899, 12239, 48161, 7385}},
+{11285, 17, 47286, {1, 3, 7, 3, 23, 19, 29, 47, 7, 723, 455, 4013, 2739, 12303, 29883, 51485, 1571}},
+{11286, 17, 47312, {1, 1, 1, 11, 1, 31, 111, 199, 207, 209, 1163, 2865, 5335, 2647, 9125, 6737, 99881}},
+{11287, 17, 47315, {1, 3, 1, 11, 31, 19, 59, 153, 65, 133, 1399, 2709, 905, 3257, 13603, 46299, 15139}},
+{11288, 17, 47321, {1, 3, 1, 1, 23, 19, 123, 115, 59, 667, 333, 2461, 1843, 16049, 12353, 17297, 107779}},
+{11289, 17, 47322, {1, 1, 5, 1, 5, 29, 91, 241, 97, 557, 1701, 2441, 2995, 13103, 9261, 55833, 843}},
+{11290, 17, 47324, {1, 1, 1, 5, 15, 19, 23, 189, 69, 91, 427, 3149, 5199, 13073, 32273, 41503, 98749}},
+{11291, 17, 47331, {1, 3, 5, 11, 19, 3, 71, 125, 307, 241, 861, 681, 5657, 5189, 7555, 2037, 72921}},
+{11292, 17, 47338, {1, 1, 5, 5, 29, 61, 93, 61, 421, 685, 883, 1559, 5875, 10561, 11761, 18879, 31577}},
+{11293, 17, 47366, {1, 3, 7, 15, 9, 29, 41, 241, 365, 941, 1087, 3743, 6781, 9467, 1409, 20605, 2361}},
+{11294, 17, 47372, {1, 1, 5, 13, 25, 29, 7, 21, 41, 621, 1751, 3731, 2667, 8613, 20999, 3851, 39677}},
+{11295, 17, 47375, {1, 1, 7, 5, 17, 23, 25, 43, 401, 749, 975, 91, 5277, 2711, 19847, 41419, 11851}},
+{11296, 17, 47378, {1, 1, 7, 9, 13, 37, 113, 89, 435, 749, 1553, 1853, 7709, 5449, 25055, 45207, 2269}},
+{11297, 17, 47387, {1, 3, 1, 11, 3, 59, 79, 13, 35, 901, 165, 907, 7579, 12739, 24679, 54163, 61059}},
+{11298, 17, 47389, {1, 1, 5, 7, 9, 47, 101, 61, 25, 461, 1737, 2825, 4439, 5363, 28433, 61979, 120401}},
+{11299, 17, 47390, {1, 3, 3, 3, 1, 55, 103, 1, 449, 473, 375, 2609, 4933, 3411, 19663, 6067, 61129}},
+{11300, 17, 47396, {1, 1, 3, 9, 27, 29, 53, 151, 391, 507, 425, 3469, 6605, 5783, 31747, 37677, 116037}},
+{11301, 17, 47400, {1, 1, 1, 5, 5, 43, 61, 67, 319, 553, 1163, 3095, 4447, 7505, 15617, 26167, 11145}},
+{11302, 17, 47405, {1, 1, 5, 7, 3, 3, 9, 161, 155, 869, 337, 3693, 6847, 8449, 15077, 54769, 123335}},
+{11303, 17, 47408, {1, 3, 3, 7, 11, 19, 17, 71, 105, 649, 323, 3033, 1695, 15973, 6361, 3163, 17669}},
+{11304, 17, 47411, {1, 3, 7, 13, 13, 9, 3, 251, 149, 513, 637, 2211, 6397, 1741, 8547, 3165, 38241}},
+{11305, 17, 47431, {1, 1, 5, 5, 1, 57, 73, 35, 287, 347, 221, 3261, 7693, 5443, 6175, 18181, 23733}},
+{11306, 17, 47443, {1, 3, 7, 5, 5, 19, 1, 167, 5, 825, 815, 1369, 7657, 6169, 9583, 34761, 81003}},
+{11307, 17, 47459, {1, 3, 3, 5, 15, 17, 23, 157, 475, 297, 1495, 811, 8135, 11453, 9683, 55505, 84361}},
+{11308, 17, 47466, {1, 1, 1, 11, 1, 63, 59, 189, 205, 1023, 1065, 1095, 2293, 14629, 29399, 2925, 28327}},
+{11309, 17, 47479, {1, 3, 1, 3, 31, 33, 85, 183, 383, 731, 1223, 3353, 3703, 5655, 31265, 12249, 22127}},
+{11310, 17, 47480, {1, 3, 5, 7, 7, 29, 61, 3, 375, 95, 1815, 4065, 6287, 3797, 32397, 50581, 123371}},
+{11311, 17, 47495, {1, 3, 1, 9, 13, 37, 57, 139, 43, 561, 425, 3603, 1167, 10281, 31825, 32673, 106169}},
+{11312, 17, 47504, {1, 3, 5, 3, 15, 41, 29, 223, 79, 851, 1741, 2241, 5659, 9773, 18369, 37239, 14831}},
+{11313, 17, 47519, {1, 3, 1, 1, 7, 11, 83, 63, 51, 521, 1911, 475, 5207, 3219, 10257, 40461, 9087}},
+{11314, 17, 47520, {1, 3, 5, 7, 23, 17, 97, 195, 5, 451, 1971, 1881, 921, 8729, 3443, 64529, 67747}},
+{11315, 17, 47530, {1, 1, 3, 9, 21, 63, 45, 181, 429, 605, 169, 3493, 2381, 2887, 19515, 53151, 60147}},
+{11316, 17, 47537, {1, 3, 3, 7, 15, 11, 117, 161, 333, 139, 587, 2331, 3175, 12093, 12649, 52381, 107117}},
+{11317, 17, 47555, {1, 1, 5, 15, 23, 57, 19, 57, 507, 461, 799, 611, 1589, 10909, 7649, 17817, 24677}},
+{11318, 17, 47558, {1, 1, 3, 15, 1, 61, 9, 201, 401, 387, 527, 2855, 2339, 3813, 11825, 14273, 73745}},
+{11319, 17, 47567, {1, 3, 1, 5, 1, 37, 27, 105, 475, 335, 1169, 3233, 3225, 12861, 10133, 36673, 55025}},
+{11320, 17, 47569, {1, 1, 1, 9, 27, 53, 55, 197, 229, 5, 93, 1157, 7929, 9745, 5295, 15359, 75567}},
+{11321, 17, 47572, {1, 1, 7, 5, 11, 3, 109, 81, 457, 159, 1899, 557, 1067, 295, 2661, 1145, 8745}},
+{11322, 17, 47582, {1, 1, 1, 15, 31, 29, 77, 171, 411, 425, 1041, 2791, 2567, 5357, 21871, 27689, 103485}},
+{11323, 17, 47591, {1, 3, 5, 11, 19, 47, 23, 97, 405, 667, 2045, 2951, 2063, 7775, 20629, 34283, 26925}},
+{11324, 17, 47595, {1, 3, 5, 7, 5, 51, 125, 67, 165, 145, 733, 1649, 5787, 4333, 24355, 33397, 101001}},
+{11325, 17, 47598, {1, 3, 7, 11, 13, 7, 117, 147, 449, 201, 953, 553, 1839, 6903, 10417, 42751, 36823}},
+{11326, 17, 47609, {1, 1, 3, 5, 3, 21, 109, 35, 95, 953, 211, 2849, 5681, 16287, 16553, 30345, 69729}},
+{11327, 17, 47612, {1, 3, 7, 5, 25, 37, 21, 143, 317, 621, 1417, 283, 3801, 15375, 3799, 13345, 59727}},
+{11328, 17, 47616, {1, 3, 3, 9, 3, 37, 113, 127, 123, 979, 1225, 2585, 2055, 2571, 16727, 38863, 74347}},
+{11329, 17, 47625, {1, 3, 3, 3, 23, 13, 49, 111, 277, 143, 1171, 605, 91, 13693, 1971, 18209, 114203}},
+{11330, 17, 47640, {1, 1, 1, 9, 27, 33, 73, 9, 93, 343, 55, 3045, 2029, 3665, 28483, 6601, 72085}},
+{11331, 17, 47649, {1, 1, 1, 15, 17, 55, 87, 231, 103, 1005, 1451, 3617, 7477, 2045, 10683, 39053, 1289}},
+{11332, 17, 47655, {1, 3, 7, 7, 25, 55, 39, 89, 489, 609, 1969, 159, 7485, 10713, 28371, 14935, 95347}},
+{11333, 17, 47661, {1, 3, 3, 13, 25, 9, 83, 167, 25, 135, 2017, 3313, 1493, 7799, 22479, 49471, 20149}},
+{11334, 17, 47688, {1, 1, 1, 15, 25, 13, 63, 117, 97, 449, 1331, 229, 6027, 1023, 26705, 15283, 60385}},
+{11335, 17, 47711, {1, 1, 7, 5, 5, 37, 3, 79, 337, 861, 1549, 915, 7303, 1503, 19245, 60721, 45313}},
+{11336, 17, 47717, {1, 3, 7, 15, 19, 1, 11, 39, 505, 757, 1627, 2137, 3209, 7651, 31291, 45913, 26851}},
+{11337, 17, 47721, {1, 3, 1, 5, 25, 21, 85, 233, 171, 269, 367, 1651, 3961, 2487, 1977, 7027, 2725}},
+{11338, 17, 47724, {1, 1, 5, 15, 13, 23, 81, 145, 201, 323, 425, 2785, 1149, 12617, 11451, 23205, 117691}},
+{11339, 17, 47727, {1, 1, 7, 11, 29, 37, 69, 141, 15, 773, 1299, 2147, 8129, 12227, 27811, 58701, 103637}},
+{11340, 17, 47730, {1, 3, 5, 13, 3, 33, 29, 227, 261, 221, 823, 1399, 5107, 2423, 23809, 42175, 28207}},
+{11341, 17, 47739, {1, 3, 1, 15, 21, 1, 121, 255, 259, 441, 45, 1899, 2489, 4155, 18317, 52695, 607}},
+{11342, 17, 47745, {1, 3, 5, 9, 25, 43, 115, 111, 329, 997, 753, 1513, 6949, 3197, 28275, 48855, 25089}},
+{11343, 17, 47752, {1, 3, 3, 3, 25, 9, 21, 213, 111, 173, 913, 1465, 4437, 9725, 1455, 53517, 81843}},
+{11344, 17, 47758, {1, 3, 5, 5, 5, 25, 3, 159, 19, 203, 181, 3447, 6395, 2145, 11289, 16797, 59567}},
+{11345, 17, 47765, {1, 3, 3, 1, 29, 25, 43, 115, 257, 833, 379, 941, 4389, 5795, 12593, 2471, 127149}},
+{11346, 17, 47770, {1, 3, 1, 9, 3, 15, 81, 141, 155, 515, 1677, 2569, 1105, 15653, 24143, 3439, 17317}},
+{11347, 17, 47782, {1, 3, 1, 13, 27, 13, 103, 87, 27, 971, 671, 629, 4943, 13897, 4003, 21507, 40193}},
+{11348, 17, 47786, {1, 3, 5, 9, 1, 49, 11, 15, 511, 837, 1953, 1585, 1867, 9095, 543, 16993, 115187}},
+{11349, 17, 47791, {1, 1, 5, 11, 21, 49, 37, 61, 9, 629, 1025, 1635, 4047, 15491, 28481, 43235, 53165}},
+{11350, 17, 47793, {1, 1, 5, 7, 15, 57, 121, 119, 405, 29, 655, 3085, 7131, 14761, 2273, 47113, 8603}},
+{11351, 17, 47796, {1, 1, 3, 3, 11, 45, 51, 107, 367, 235, 675, 3777, 6081, 16319, 19499, 36893, 25579}},
+{11352, 17, 47814, {1, 1, 7, 11, 1, 13, 43, 159, 415, 423, 1223, 2201, 1089, 10189, 12457, 26691, 3603}},
+{11353, 17, 47823, {1, 1, 3, 3, 3, 37, 109, 67, 487, 785, 637, 3931, 929, 14153, 25283, 483, 14371}},
+{11354, 17, 47826, {1, 1, 7, 9, 31, 59, 9, 245, 479, 113, 1419, 3265, 8131, 11123, 32519, 12141, 82059}},
+{11355, 17, 47837, {1, 1, 1, 7, 25, 25, 31, 13, 81, 217, 997, 1161, 1049, 5487, 8487, 57807, 126115}},
+{11356, 17, 47854, {1, 1, 3, 15, 1, 23, 63, 39, 503, 933, 1915, 687, 547, 779, 7689, 38607, 125229}},
+{11357, 17, 47856, {1, 1, 3, 3, 31, 49, 51, 87, 99, 327, 783, 3487, 7307, 2759, 22781, 56343, 126805}},
+{11358, 17, 47871, {1, 3, 3, 11, 27, 43, 99, 197, 275, 19, 775, 329, 3815, 14277, 3363, 26375, 75427}},
+{11359, 17, 47879, {1, 1, 5, 15, 15, 19, 65, 109, 103, 411, 1591, 2569, 1981, 4773, 7861, 6303, 127421}},
+{11360, 17, 47880, {1, 3, 1, 13, 1, 53, 107, 151, 317, 201, 1053, 2701, 5039, 2179, 10085, 31727, 85579}},
+{11361, 17, 47885, {1, 3, 1, 9, 5, 55, 71, 143, 187, 29, 1363, 2403, 2675, 2187, 12123, 32825, 56461}},
+{11362, 17, 47886, {1, 1, 7, 11, 5, 57, 91, 95, 85, 597, 925, 11, 1915, 9159, 9997, 29565, 111655}},
+{11363, 17, 47903, {1, 1, 5, 9, 25, 57, 79, 189, 205, 687, 471, 601, 5343, 9031, 7853, 6079, 40567}},
+{11364, 17, 47907, {1, 1, 3, 1, 31, 53, 67, 191, 511, 369, 1273, 3859, 4253, 14469, 3427, 17691, 22599}},
+{11365, 17, 47913, {1, 1, 3, 9, 17, 53, 101, 219, 41, 663, 635, 3889, 2197, 8125, 8313, 14957, 111445}},
+{11366, 17, 47916, {1, 1, 5, 5, 7, 49, 113, 9, 399, 257, 617, 63, 2773, 4411, 1193, 54449, 89003}},
+{11367, 17, 47928, {1, 1, 7, 11, 13, 29, 77, 73, 161, 419, 985, 303, 2237, 15217, 26621, 20441, 113955}},
+{11368, 17, 47936, {1, 3, 3, 9, 17, 39, 37, 139, 289, 421, 1021, 2635, 2805, 5815, 9101, 48077, 114009}},
+{11369, 17, 47945, {1, 1, 1, 15, 25, 43, 71, 35, 103, 827, 1301, 3567, 3425, 3689, 14453, 10733, 81257}},
+{11370, 17, 47948, {1, 3, 5, 5, 15, 31, 41, 161, 481, 231, 1135, 3045, 439, 11785, 14863, 39729, 59539}},
+{11371, 17, 47956, {1, 1, 5, 7, 27, 9, 81, 141, 395, 105, 41, 3719, 3105, 13685, 7451, 31381, 82907}},
+{11372, 17, 47965, {1, 3, 1, 13, 15, 25, 127, 231, 433, 837, 1923, 1301, 2479, 3243, 21605, 55789, 11311}},
+{11373, 17, 47970, {1, 3, 5, 7, 17, 5, 27, 111, 217, 445, 1245, 1029, 7663, 10291, 16483, 37503, 110205}},
+{11374, 17, 47972, {1, 1, 1, 7, 31, 21, 51, 235, 487, 457, 1687, 2947, 5067, 13779, 7671, 7257, 119141}},
+{11375, 17, 47981, {1, 1, 5, 13, 25, 31, 59, 183, 33, 887, 469, 813, 7939, 11775, 5795, 26227, 57703}},
+{11376, 17, 47987, {1, 3, 3, 15, 17, 7, 19, 87, 365, 177, 1157, 1023, 3055, 15439, 27187, 32593, 112507}},
+{11377, 17, 48010, {1, 1, 1, 9, 19, 49, 103, 239, 207, 409, 1613, 2793, 5477, 11221, 21611, 19963, 99333}},
+{11378, 17, 48012, {1, 3, 3, 11, 17, 1, 103, 77, 93, 197, 1883, 4053, 4613, 11571, 1841, 23189, 4235}},
+{11379, 17, 48023, {1, 3, 5, 9, 9, 49, 29, 231, 167, 593, 1909, 2457, 323, 10549, 6551, 45597, 96591}},
+{11380, 17, 48033, {1, 1, 7, 11, 15, 39, 33, 61, 13, 879, 1589, 2169, 125, 2427, 13029, 24919, 14147}},
+{11381, 17, 48051, {1, 3, 5, 5, 25, 53, 49, 255, 263, 917, 1997, 171, 2945, 14243, 12983, 21821, 119547}},
+{11382, 17, 48071, {1, 1, 1, 15, 5, 25, 113, 235, 311, 377, 1059, 1365, 3457, 8699, 18617, 25119, 110659}},
+{11383, 17, 48075, {1, 1, 5, 1, 9, 61, 1, 137, 301, 85, 1527, 3831, 923, 13753, 20909, 14007, 22939}},
+{11384, 17, 48077, {1, 1, 7, 9, 23, 17, 31, 107, 55, 293, 425, 3513, 3503, 10075, 6299, 40007, 54355}},
+{11385, 17, 48080, {1, 3, 5, 5, 27, 39, 95, 187, 239, 949, 531, 3541, 99, 6339, 32295, 10377, 111287}},
+{11386, 17, 48099, {1, 1, 5, 15, 19, 39, 23, 89, 185, 47, 87, 1721, 2471, 13221, 13201, 31, 12897}},
+{11387, 17, 48106, {1, 3, 1, 9, 7, 7, 109, 241, 39, 687, 175, 139, 583, 1629, 19775, 6371, 121879}},
+{11388, 17, 48114, {1, 1, 1, 13, 13, 9, 73, 153, 367, 425, 217, 3981, 5203, 1111, 12333, 59799, 105259}},
+{11389, 17, 48120, {1, 1, 3, 5, 7, 33, 27, 123, 335, 727, 1619, 3999, 7799, 2807, 2251, 45835, 113193}},
+{11390, 17, 48128, {1, 3, 1, 7, 25, 3, 49, 163, 447, 555, 647, 1461, 5881, 15755, 32233, 48915, 96203}},
+{11391, 17, 48145, {1, 3, 7, 7, 21, 11, 61, 101, 323, 165, 1489, 2933, 3363, 8471, 4311, 65279, 123813}},
+{11392, 17, 48152, {1, 3, 1, 1, 15, 1, 101, 225, 473, 479, 1237, 113, 7591, 2883, 3891, 53703, 14607}},
+{11393, 17, 48155, {1, 3, 5, 3, 17, 51, 23, 31, 487, 957, 1623, 2329, 2801, 6213, 7523, 14131, 23893}},
+{11394, 17, 48182, {1, 1, 5, 7, 9, 39, 93, 105, 13, 481, 53, 3785, 5621, 11889, 993, 23611, 73651}},
+{11395, 17, 48188, {1, 3, 7, 15, 21, 57, 97, 69, 339, 289, 1805, 2661, 1165, 6079, 1127, 51285, 54453}},
+{11396, 17, 48203, {1, 1, 3, 3, 3, 3, 1, 179, 123, 1011, 1363, 231, 6983, 9499, 91, 52573, 32565}},
+{11397, 17, 48217, {1, 3, 3, 15, 5, 37, 97, 7, 189, 547, 1965, 3821, 4907, 8181, 12857, 7907, 19361}},
+{11398, 17, 48218, {1, 1, 5, 3, 29, 33, 45, 99, 359, 337, 1377, 577, 3117, 9545, 30093, 26147, 128509}},
+{11399, 17, 48236, {1, 3, 5, 11, 7, 49, 99, 249, 37, 755, 383, 2845, 4153, 695, 11099, 33653, 105155}},
+{11400, 17, 48241, {1, 3, 1, 1, 19, 3, 3, 177, 97, 323, 1367, 213, 4391, 11223, 26497, 12289, 39047}},
+{11401, 17, 48244, {1, 1, 3, 7, 3, 33, 73, 199, 339, 479, 1797, 3905, 2849, 5667, 18015, 36653, 83491}},
+{11402, 17, 48264, {1, 1, 5, 3, 27, 59, 27, 241, 49, 161, 451, 3993, 2489, 10681, 11895, 60405, 47021}},
+{11403, 17, 48269, {1, 1, 7, 5, 9, 23, 115, 131, 383, 895, 1591, 585, 2571, 7485, 31535, 12871, 95717}},
+{11404, 17, 48278, {1, 1, 1, 15, 13, 49, 3, 157, 311, 159, 1239, 159, 5643, 6405, 11763, 34609, 75259}},
+{11405, 17, 48282, {1, 1, 1, 13, 11, 41, 119, 3, 165, 943, 2035, 179, 357, 14591, 20099, 4787, 12659}},
+{11406, 17, 48288, {1, 1, 5, 11, 13, 9, 67, 139, 259, 947, 1559, 283, 1557, 11297, 29753, 21953, 100317}},
+{11407, 17, 48311, {1, 1, 7, 11, 13, 39, 105, 83, 109, 723, 1643, 3599, 1471, 13653, 4583, 18595, 91935}},
+{11408, 17, 48315, {1, 1, 5, 9, 25, 5, 69, 189, 209, 779, 1421, 467, 849, 12887, 10317, 3005, 100813}},
+{11409, 17, 48317, {1, 3, 7, 11, 19, 1, 93, 239, 333, 713, 1525, 813, 5913, 10811, 7077, 20573, 86999}},
+{11410, 17, 48329, {1, 3, 1, 5, 25, 1, 107, 153, 225, 889, 1319, 497, 2193, 11511, 17553, 23733, 83179}},
+{11411, 17, 48330, {1, 3, 3, 3, 5, 45, 51, 37, 443, 851, 263, 4067, 2629, 10887, 29081, 30489, 1161}},
+{11412, 17, 48337, {1, 1, 3, 9, 25, 19, 115, 31, 347, 641, 1103, 1121, 7051, 14071, 16663, 48517, 24655}},
+{11413, 17, 48350, {1, 1, 3, 15, 11, 33, 123, 181, 225, 437, 875, 1997, 209, 5487, 1989, 6745, 38423}},
+{11414, 17, 48353, {1, 3, 7, 5, 27, 5, 105, 203, 51, 683, 1523, 347, 6881, 4353, 4531, 29589, 108053}},
+{11415, 17, 48360, {1, 1, 3, 9, 15, 33, 127, 145, 125, 429, 915, 1307, 1495, 3553, 26797, 36819, 121375}},
+{11416, 17, 48374, {1, 3, 5, 15, 7, 1, 55, 99, 7, 405, 885, 59, 5359, 13969, 32037, 53399, 77293}},
+{11417, 17, 48380, {1, 1, 7, 1, 29, 31, 89, 69, 405, 837, 1949, 2337, 1139, 14129, 16867, 15167, 21117}},
+{11418, 17, 48405, {1, 1, 3, 5, 3, 25, 61, 175, 135, 109, 959, 501, 13, 16057, 25031, 16321, 27617}},
+{11419, 17, 48406, {1, 3, 1, 5, 17, 39, 59, 113, 25, 707, 1641, 3489, 6193, 10085, 13837, 57851, 77475}},
+{11420, 17, 48409, {1, 1, 3, 5, 17, 35, 111, 163, 253, 641, 715, 1101, 4411, 10771, 20241, 46415, 114719}},
+{11421, 17, 48412, {1, 3, 1, 1, 7, 11, 77, 59, 71, 869, 1505, 751, 4367, 9603, 29735, 7333, 62487}},
+{11422, 17, 48416, {1, 3, 7, 9, 3, 51, 93, 195, 497, 659, 1563, 3801, 6933, 9089, 10891, 9853, 93611}},
+{11423, 17, 48419, {1, 3, 1, 7, 21, 47, 61, 117, 293, 281, 1547, 3437, 4947, 12119, 21425, 5591, 23951}},
+{11424, 17, 48425, {1, 1, 7, 13, 19, 59, 121, 249, 147, 759, 1963, 465, 7785, 7015, 81, 47869, 123845}},
+{11425, 17, 48434, {1, 1, 7, 13, 5, 35, 45, 69, 167, 263, 979, 2855, 1845, 5531, 17167, 7363, 89233}},
+{11426, 17, 48443, {1, 3, 3, 3, 17, 43, 109, 193, 389, 867, 1403, 1271, 7127, 13977, 22547, 53997, 24475}},
+{11427, 17, 48445, {1, 1, 1, 5, 25, 43, 47, 163, 417, 967, 819, 2433, 439, 8499, 29705, 32697, 109963}},
+{11428, 17, 48453, {1, 1, 1, 15, 19, 5, 83, 237, 431, 697, 1383, 2499, 6907, 9033, 12147, 23479, 17649}},
+{11429, 17, 48454, {1, 3, 5, 13, 27, 35, 103, 95, 239, 903, 537, 601, 417, 15859, 16533, 16753, 128229}},
+{11430, 17, 48482, {1, 1, 3, 1, 11, 55, 57, 9, 229, 135, 805, 2745, 2023, 12645, 29135, 39051, 17065}},
+{11431, 17, 48491, {1, 3, 5, 3, 13, 25, 77, 29, 449, 31, 1733, 1451, 3895, 11551, 1011, 22817, 35959}},
+{11432, 17, 48501, {1, 3, 3, 3, 1, 31, 93, 47, 255, 393, 571, 443, 6079, 6245, 11773, 42087, 40651}},
+{11433, 17, 48517, {1, 3, 1, 5, 17, 49, 119, 219, 375, 337, 29, 3409, 3187, 15243, 25853, 44385, 103675}},
+{11434, 17, 48518, {1, 3, 7, 15, 15, 21, 79, 109, 81, 119, 603, 1665, 7813, 3485, 11801, 48693, 108307}},
+{11435, 17, 48545, {1, 1, 1, 15, 9, 5, 103, 141, 181, 841, 7, 1217, 7713, 4843, 9089, 53641, 3029}},
+{11436, 17, 48548, {1, 3, 3, 1, 29, 47, 13, 179, 439, 387, 1553, 3141, 947, 4893, 29119, 30865, 14207}},
+{11437, 17, 48552, {1, 1, 1, 15, 29, 1, 41, 135, 43, 673, 1527, 883, 3211, 5195, 30219, 47133, 56819}},
+{11438, 17, 48569, {1, 3, 5, 13, 13, 47, 97, 219, 277, 397, 1901, 821, 1961, 705, 7291, 19435, 123563}},
+{11439, 17, 48575, {1, 1, 7, 15, 5, 49, 93, 59, 221, 205, 115, 559, 5633, 5819, 6923, 18301, 72639}},
+{11440, 17, 48580, {1, 3, 5, 13, 29, 49, 25, 203, 125, 385, 487, 1897, 2177, 6859, 6105, 763, 36673}},
+{11441, 17, 48584, {1, 3, 3, 9, 23, 63, 9, 115, 489, 89, 1113, 1351, 8181, 2569, 18263, 32619, 24795}},
+{11442, 17, 48590, {1, 1, 5, 11, 25, 51, 97, 155, 15, 139, 1275, 3479, 5851, 3099, 7417, 57155, 90185}},
+{11443, 17, 48595, {1, 3, 1, 11, 1, 37, 67, 221, 493, 475, 1881, 2277, 4365, 9411, 16629, 65229, 28803}},
+{11444, 17, 48602, {1, 3, 1, 1, 15, 53, 39, 141, 453, 151, 335, 795, 1515, 2719, 24197, 21153, 129549}},
+{11445, 17, 48604, {1, 1, 1, 7, 19, 31, 59, 123, 73, 149, 469, 1199, 3603, 1539, 29157, 50031, 22109}},
+{11446, 17, 48618, {1, 1, 3, 15, 23, 51, 45, 211, 423, 553, 1289, 1125, 6347, 6711, 23761, 14109, 17261}},
+{11447, 17, 48625, {1, 3, 5, 13, 5, 7, 35, 185, 263, 791, 161, 325, 4771, 11913, 31595, 56675, 68615}},
+{11448, 17, 48626, {1, 1, 5, 9, 19, 27, 89, 147, 55, 197, 1695, 99, 755, 15115, 1933, 41439, 85063}},
+{11449, 17, 48638, {1, 1, 7, 7, 17, 11, 103, 55, 281, 707, 1973, 2055, 5015, 5713, 3717, 44149, 8033}},
+{11450, 17, 48668, {1, 3, 1, 5, 21, 49, 55, 93, 161, 565, 81, 3241, 3709, 8185, 16935, 60369, 118127}},
+{11451, 17, 48677, {1, 3, 7, 9, 27, 1, 105, 133, 397, 351, 1021, 739, 161, 9971, 24733, 29239, 68853}},
+{11452, 17, 48678, {1, 1, 7, 1, 1, 19, 97, 243, 73, 969, 313, 399, 2955, 2467, 18265, 60637, 35457}},
+{11453, 17, 48687, {1, 3, 1, 11, 29, 25, 35, 35, 469, 143, 1195, 911, 1023, 14685, 10933, 16449, 102113}},
+{11454, 17, 48692, {1, 1, 5, 3, 31, 21, 65, 181, 13, 235, 501, 3621, 3567, 8771, 32747, 59231, 91551}},
+{11455, 17, 48696, {1, 1, 1, 13, 29, 21, 13, 33, 193, 565, 203, 3927, 4749, 9897, 26109, 14221, 27733}},
+{11456, 17, 48704, {1, 1, 1, 5, 29, 41, 7, 125, 391, 295, 533, 2135, 3107, 7711, 27811, 55767, 78821}},
+{11457, 17, 48707, {1, 1, 7, 3, 19, 25, 117, 195, 155, 685, 147, 2049, 3751, 4585, 24893, 36895, 80371}},
+{11458, 17, 48714, {1, 3, 5, 5, 23, 41, 9, 125, 315, 809, 1019, 1453, 4605, 13753, 30641, 50677, 94781}},
+{11459, 17, 48731, {1, 1, 1, 7, 27, 45, 103, 199, 37, 291, 651, 185, 6715, 15387, 30873, 63051, 123231}},
+{11460, 17, 48740, {1, 1, 5, 7, 17, 5, 75, 129, 401, 107, 1681, 2039, 299, 12399, 30947, 26327, 91589}},
+{11461, 17, 48750, {1, 3, 3, 15, 17, 19, 109, 19, 493, 797, 209, 929, 2821, 395, 22173, 27803, 87953}},
+{11462, 17, 48761, {1, 3, 7, 5, 7, 5, 71, 159, 483, 389, 1817, 4093, 963, 4253, 31267, 63919, 62113}},
+{11463, 17, 48785, {1, 3, 3, 15, 9, 49, 89, 49, 15, 61, 2041, 2357, 2173, 3349, 32565, 23207, 21177}},
+{11464, 17, 48786, {1, 1, 1, 13, 15, 21, 31, 143, 387, 371, 567, 1903, 3793, 9559, 7055, 31251, 13663}},
+{11465, 17, 48798, {1, 1, 3, 13, 3, 7, 49, 31, 255, 581, 627, 1947, 2965, 2787, 8275, 59785, 19979}},
+{11466, 17, 48807, {1, 3, 3, 13, 29, 47, 53, 133, 301, 253, 1215, 3409, 5745, 247, 31585, 5555, 31011}},
+{11467, 17, 48808, {1, 3, 7, 15, 23, 49, 1, 89, 141, 423, 707, 645, 7955, 10485, 27223, 35867, 45461}},
+{11468, 17, 48814, {1, 1, 3, 3, 29, 25, 123, 63, 197, 429, 169, 3229, 3797, 4029, 29947, 52781, 16065}},
+{11469, 17, 48826, {1, 3, 3, 7, 29, 17, 83, 95, 199, 253, 133, 265, 6723, 6207, 12863, 61311, 21937}},
+{11470, 17, 48828, {1, 3, 7, 13, 19, 61, 89, 151, 249, 597, 1389, 717, 5111, 3285, 6251, 50237, 108703}},
+{11471, 17, 48834, {1, 3, 5, 11, 1, 23, 35, 61, 143, 45, 625, 1693, 4943, 2213, 9317, 7601, 28359}},
+{11472, 17, 48840, {1, 3, 3, 15, 29, 43, 115, 23, 167, 355, 977, 439, 4767, 9967, 22997, 54725, 125637}},
+{11473, 17, 48845, {1, 3, 7, 1, 29, 45, 83, 71, 395, 247, 1, 113, 6393, 12445, 16137, 35125, 102053}},
+{11474, 17, 48858, {1, 1, 1, 7, 17, 55, 17, 159, 33, 237, 207, 1297, 5611, 6023, 17709, 60905, 3533}},
+{11475, 17, 48864, {1, 3, 1, 13, 27, 57, 27, 235, 141, 917, 1655, 659, 939, 559, 2651, 705, 80141}},
+{11476, 17, 48869, {1, 3, 7, 3, 3, 17, 111, 117, 467, 129, 1105, 3457, 2093, 8513, 19941, 22111, 54597}},
+{11477, 17, 48870, {1, 3, 7, 3, 5, 17, 59, 195, 23, 547, 1799, 1427, 391, 4043, 10407, 31055, 38495}},
+{11478, 17, 48879, {1, 1, 1, 7, 21, 9, 71, 33, 209, 773, 1243, 3239, 3763, 15229, 9609, 24395, 56145}},
+{11479, 17, 48887, {1, 3, 5, 13, 13, 45, 71, 91, 23, 553, 665, 1753, 5173, 4355, 14317, 42517, 32307}},
+{11480, 17, 48899, {1, 3, 5, 11, 31, 3, 37, 95, 63, 425, 1611, 2983, 5075, 1375, 14305, 11099, 101203}},
+{11481, 17, 48911, {1, 1, 3, 1, 21, 7, 15, 141, 389, 871, 617, 271, 1037, 13569, 13019, 58899, 54097}},
+{11482, 17, 48920, {1, 3, 7, 1, 13, 25, 21, 251, 467, 373, 1539, 4065, 1871, 791, 26315, 64187, 119455}},
+{11483, 17, 48926, {1, 3, 1, 3, 25, 37, 43, 9, 187, 323, 409, 443, 2861, 14145, 26185, 24049, 109613}},
+{11484, 17, 48929, {1, 1, 3, 7, 21, 61, 3, 81, 445, 673, 1269, 613, 1279, 8209, 22911, 48017, 54181}},
+{11485, 17, 48971, {1, 1, 1, 15, 25, 63, 71, 147, 217, 491, 183, 977, 4967, 3471, 8791, 11843, 68005}},
+{11486, 17, 48974, {1, 1, 1, 5, 25, 43, 13, 237, 57, 919, 1641, 399, 4269, 7357, 3465, 63901, 61329}},
+{11487, 17, 48981, {1, 1, 7, 15, 27, 57, 47, 187, 295, 117, 1223, 2963, 4995, 13279, 25107, 56089, 37293}},
+{11488, 17, 48998, {1, 1, 5, 13, 29, 19, 83, 121, 129, 931, 1933, 1141, 3125, 3321, 22019, 52729, 119643}},
+{11489, 17, 49007, {1, 1, 1, 1, 21, 19, 49, 241, 227, 57, 1919, 113, 6993, 4687, 1043, 5247, 15565}},
+{11490, 17, 49028, {1, 3, 3, 15, 5, 21, 65, 129, 485, 173, 1663, 2419, 4279, 4167, 25827, 28457, 68219}},
+{11491, 17, 49031, {1, 1, 3, 1, 17, 9, 65, 21, 487, 875, 1111, 1679, 6451, 14825, 23931, 16053, 79687}},
+{11492, 17, 49056, {1, 3, 3, 5, 13, 5, 49, 15, 267, 389, 1111, 1505, 5815, 6285, 26075, 167, 70325}},
+{11493, 17, 49065, {1, 1, 3, 11, 5, 15, 57, 171, 407, 497, 1979, 2819, 1267, 6893, 6601, 30971, 24477}},
+{11494, 17, 49079, {1, 1, 1, 15, 7, 5, 69, 181, 195, 847, 1245, 4019, 2469, 1407, 17013, 43437, 16307}},
+{11495, 17, 49083, {1, 3, 1, 11, 15, 17, 115, 197, 215, 35, 1489, 659, 4725, 11339, 30259, 52539, 13365}},
+{11496, 17, 49088, {1, 1, 1, 13, 23, 43, 21, 33, 17, 969, 1321, 2469, 4371, 7685, 6817, 20179, 113483}},
+{11497, 17, 49093, {1, 3, 7, 3, 31, 11, 79, 55, 123, 263, 1061, 2087, 183, 11623, 20703, 60291, 115261}},
+{11498, 17, 49100, {1, 1, 5, 13, 5, 53, 21, 71, 399, 165, 1997, 2667, 7361, 8863, 27859, 17235, 77623}},
+{11499, 17, 49103, {1, 3, 3, 15, 21, 55, 27, 31, 371, 289, 253, 1453, 105, 7035, 14787, 2281, 128359}},
+{11500, 17, 49124, {1, 1, 3, 15, 23, 29, 3, 143, 47, 255, 115, 2741, 6773, 16267, 5975, 3689, 97497}},
+{11501, 17, 49136, {1, 1, 1, 15, 9, 57, 109, 43, 359, 365, 1577, 4091, 7399, 10521, 7983, 56119, 65451}},
+{11502, 17, 49139, {1, 3, 7, 7, 29, 55, 115, 155, 121, 679, 663, 2345, 3765, 4493, 9555, 24043, 41467}},
+{11503, 17, 49142, {1, 1, 3, 1, 19, 55, 67, 255, 355, 701, 2027, 3703, 7839, 1701, 7657, 36429, 36623}},
+{11504, 17, 49145, {1, 3, 5, 5, 29, 7, 31, 123, 21, 901, 1581, 3993, 5105, 9715, 18347, 27415, 19253}},
+{11505, 17, 49146, {1, 3, 5, 3, 3, 53, 121, 105, 51, 577, 157, 2151, 5105, 7855, 8595, 24457, 55931}},
+{11506, 17, 49171, {1, 3, 1, 9, 23, 25, 67, 115, 79, 809, 1215, 943, 1075, 7103, 729, 18791, 115977}},
+{11507, 17, 49187, {1, 3, 1, 13, 3, 57, 105, 161, 277, 393, 1671, 2765, 5781, 13429, 24075, 10931, 50951}},
+{11508, 17, 49190, {1, 3, 5, 9, 19, 61, 9, 227, 455, 541, 721, 2855, 949, 10159, 13801, 48199, 26747}},
+{11509, 17, 49194, {1, 3, 1, 3, 25, 61, 53, 177, 441, 697, 1845, 3573, 6673, 9691, 911, 46387, 64727}},
+{11510, 17, 49196, {1, 1, 1, 11, 7, 13, 95, 221, 455, 967, 869, 883, 6301, 5261, 18401, 35745, 114645}},
+{11511, 17, 49207, {1, 3, 1, 11, 15, 7, 115, 217, 235, 539, 491, 603, 2201, 241, 25445, 29773, 122695}},
+{11512, 17, 49216, {1, 1, 5, 3, 19, 9, 71, 193, 131, 927, 1931, 3981, 7537, 10811, 27285, 45865, 106171}},
+{11513, 17, 49219, {1, 1, 7, 5, 5, 21, 107, 77, 363, 733, 1011, 3259, 5263, 15043, 19153, 32117, 129409}},
+{11514, 17, 49222, {1, 1, 3, 13, 21, 5, 9, 103, 369, 699, 329, 1065, 895, 13211, 19017, 5359, 38335}},
+{11515, 17, 49240, {1, 1, 7, 15, 21, 11, 73, 153, 371, 753, 805, 3519, 5839, 1809, 7201, 8189, 68361}},
+{11516, 17, 49250, {1, 3, 7, 9, 27, 45, 25, 175, 317, 381, 961, 619, 4827, 15161, 19091, 29369, 21097}},
+{11517, 17, 49262, {1, 1, 5, 5, 7, 7, 21, 69, 23, 589, 1413, 653, 911, 13599, 18349, 47307, 64047}},
+{11518, 17, 49276, {1, 1, 1, 13, 27, 23, 87, 249, 135, 727, 375, 3641, 1489, 13053, 5151, 62689, 101347}},
+{11519, 17, 49289, {1, 1, 5, 11, 7, 39, 1, 109, 203, 961, 973, 1181, 2357, 5123, 31481, 58345, 52705}},
+{11520, 17, 49292, {1, 1, 1, 15, 25, 15, 85, 49, 77, 235, 1761, 2731, 4157, 2057, 27587, 30299, 52997}},
+{11521, 17, 49298, {1, 1, 5, 3, 1, 13, 47, 219, 51, 521, 625, 3243, 7093, 10823, 9559, 58191, 95573}},
+{11522, 17, 49319, {1, 3, 5, 13, 27, 63, 13, 7, 167, 909, 1559, 2103, 1807, 943, 28997, 31015, 85407}},
+{11523, 17, 49320, {1, 1, 3, 5, 17, 21, 101, 163, 477, 223, 175, 3435, 7071, 5121, 28015, 33365, 121057}},
+{11524, 17, 49325, {1, 3, 7, 1, 11, 35, 111, 41, 261, 45, 1009, 2827, 4019, 5029, 22289, 20235, 13481}},
+{11525, 17, 49333, {1, 3, 5, 5, 15, 41, 109, 7, 329, 447, 65, 1317, 6169, 15947, 31191, 47091, 60643}},
+{11526, 17, 49340, {1, 3, 7, 7, 21, 13, 29, 113, 511, 407, 1211, 2065, 455, 10049, 5745, 48589, 48669}},
+{11527, 17, 49343, {1, 1, 5, 5, 21, 45, 89, 19, 279, 165, 1897, 957, 8045, 565, 4959, 37173, 100773}},
+{11528, 17, 49352, {1, 3, 1, 15, 9, 17, 99, 143, 489, 633, 1721, 1255, 3655, 10083, 29079, 17109, 10035}},
+{11529, 17, 49363, {1, 1, 3, 3, 3, 23, 47, 9, 255, 169, 1103, 1799, 7899, 7673, 19259, 61919, 112831}},
+{11530, 17, 49375, {1, 1, 5, 5, 31, 37, 83, 229, 93, 575, 1589, 2353, 185, 7783, 9413, 9617, 123197}},
+{11531, 17, 49391, {1, 3, 5, 7, 31, 7, 113, 255, 231, 309, 1215, 737, 3635, 14631, 28737, 45127, 111399}},
+{11532, 17, 49405, {1, 1, 7, 1, 11, 5, 55, 235, 369, 983, 873, 655, 6277, 11425, 11191, 38231, 88941}},
+{11533, 17, 49413, {1, 3, 1, 9, 3, 1, 119, 93, 245, 167, 853, 2543, 203, 5313, 14129, 6283, 107117}},
+{11534, 17, 49420, {1, 3, 3, 13, 21, 33, 59, 167, 435, 163, 1873, 3341, 2895, 13205, 14147, 19567, 100127}},
+{11535, 17, 49425, {1, 1, 5, 9, 7, 15, 39, 81, 475, 511, 1585, 63, 6861, 10055, 3577, 48999, 80979}},
+{11536, 17, 49431, {1, 1, 5, 13, 21, 29, 17, 3, 499, 739, 1257, 2925, 8179, 13367, 18879, 19917, 109907}},
+{11537, 17, 49432, {1, 3, 7, 13, 15, 57, 109, 19, 265, 579, 233, 2507, 5059, 14713, 9549, 41915, 56199}},
+{11538, 17, 49441, {1, 3, 3, 5, 31, 25, 85, 163, 187, 795, 1597, 1963, 473, 4673, 4555, 51365, 73817}},
+{11539, 17, 49456, {1, 3, 3, 13, 25, 35, 71, 251, 33, 971, 235, 1919, 6705, 14657, 23417, 56377, 21071}},
+{11540, 17, 49476, {1, 3, 3, 11, 3, 29, 85, 193, 11, 831, 29, 1233, 6199, 11991, 9205, 3323, 23749}},
+{11541, 17, 49479, {1, 3, 7, 7, 11, 15, 1, 17, 87, 665, 1593, 2331, 845, 7821, 89, 7057, 114975}},
+{11542, 17, 49504, {1, 1, 5, 11, 9, 37, 39, 79, 455, 397, 1431, 1541, 7629, 15133, 21395, 35619, 123801}},
+{11543, 17, 49514, {1, 1, 1, 7, 11, 59, 67, 45, 169, 869, 1547, 2947, 3025, 12967, 29927, 22181, 44783}},
+{11544, 17, 49528, {1, 1, 5, 7, 3, 57, 123, 253, 369, 537, 83, 1147, 3469, 9775, 14137, 38899, 101143}},
+{11545, 17, 49543, {1, 3, 5, 3, 19, 35, 11, 215, 343, 677, 1873, 1211, 3129, 9017, 29595, 1291, 39397}},
+{11546, 17, 49544, {1, 1, 7, 3, 25, 7, 61, 229, 187, 839, 747, 3347, 4321, 13201, 19665, 56951, 85273}},
+{11547, 17, 49550, {1, 1, 1, 1, 11, 5, 51, 41, 227, 895, 553, 2673, 6581, 6583, 15429, 33211, 100599}},
+{11548, 17, 49558, {1, 3, 3, 5, 21, 27, 91, 65, 213, 341, 723, 567, 4761, 11549, 15041, 23079, 55245}},
+{11549, 17, 49568, {1, 1, 3, 1, 15, 43, 83, 57, 473, 453, 1351, 2055, 5769, 3887, 29481, 57915, 14017}},
+{11550, 17, 49578, {1, 3, 3, 3, 21, 29, 121, 137, 99, 527, 711, 1169, 7869, 6245, 25423, 38989, 87019}},
+{11551, 17, 49600, {1, 1, 5, 11, 9, 61, 125, 7, 207, 245, 1019, 635, 7099, 13133, 11809, 56705, 18801}},
+{11552, 17, 49612, {1, 3, 7, 9, 15, 31, 37, 205, 439, 651, 255, 971, 4311, 7137, 11821, 45041, 31081}},
+{11553, 17, 49633, {1, 1, 5, 9, 7, 55, 51, 147, 371, 881, 359, 3021, 1141, 14515, 14605, 64067, 98231}},
+{11554, 17, 49634, {1, 3, 1, 3, 29, 9, 109, 21, 437, 321, 753, 3227, 2929, 14787, 2451, 54331, 115921}},
+{11555, 17, 49636, {1, 3, 5, 7, 1, 29, 13, 167, 89, 185, 409, 209, 6625, 5237, 22513, 2095, 26427}},
+{11556, 17, 49643, {1, 1, 1, 3, 3, 31, 25, 145, 27, 345, 957, 823, 7873, 9469, 29115, 12455, 39447}},
+{11557, 17, 49654, {1, 1, 3, 3, 31, 15, 99, 181, 247, 165, 441, 59, 1181, 2851, 1337, 4929, 31079}},
+{11558, 17, 49657, {1, 1, 3, 11, 3, 47, 41, 53, 41, 435, 945, 3839, 8083, 4927, 26919, 24689, 61015}},
+{11559, 17, 49663, {1, 3, 3, 9, 7, 21, 121, 233, 493, 271, 549, 1627, 5861, 377, 20751, 52927, 3649}},
+{11560, 17, 49667, {1, 1, 1, 7, 15, 49, 29, 149, 57, 513, 873, 93, 337, 12559, 24287, 27771, 28207}},
+{11561, 17, 49693, {1, 1, 5, 7, 7, 7, 75, 161, 419, 601, 55, 2599, 5325, 12419, 26755, 5103, 10231}},
+{11562, 17, 49700, {1, 3, 5, 15, 3, 55, 67, 183, 7, 371, 141, 4093, 4567, 13971, 3327, 20701, 78819}},
+{11563, 17, 49703, {1, 1, 1, 13, 15, 41, 45, 29, 375, 235, 1985, 1051, 5863, 7043, 11143, 59381, 55007}},
+{11564, 17, 49712, {1, 3, 1, 15, 15, 29, 15, 101, 395, 39, 1839, 1689, 429, 405, 29337, 28573, 10599}},
+{11565, 17, 49717, {1, 3, 3, 11, 7, 5, 11, 153, 235, 227, 561, 1037, 2283, 6657, 6729, 17939, 29809}},
+{11566, 17, 49718, {1, 1, 1, 5, 15, 59, 33, 69, 275, 447, 661, 2071, 5811, 10463, 32707, 64503, 106313}},
+{11567, 17, 49721, {1, 1, 7, 1, 21, 53, 21, 235, 497, 309, 1207, 1613, 7739, 12785, 7743, 37671, 29197}},
+{11568, 17, 49727, {1, 3, 5, 9, 9, 51, 33, 105, 275, 917, 1911, 3607, 865, 899, 5405, 59593, 113965}},
+{11569, 17, 49730, {1, 3, 1, 7, 7, 63, 51, 83, 481, 347, 1323, 3549, 2873, 12527, 16515, 61077, 63239}},
+{11570, 17, 49735, {1, 1, 1, 1, 13, 21, 87, 139, 461, 215, 1173, 1197, 2091, 11247, 25647, 23443, 105761}},
+{11571, 17, 49739, {1, 1, 1, 1, 27, 33, 21, 27, 365, 75, 351, 2111, 3897, 13325, 4821, 41355, 95681}},
+{11572, 17, 49747, {1, 3, 5, 5, 15, 41, 15, 93, 397, 461, 1993, 321, 4375, 1205, 18417, 37549, 30181}},
+{11573, 17, 49765, {1, 3, 5, 15, 1, 49, 101, 129, 215, 773, 1265, 2245, 2517, 16261, 32149, 3545, 27631}},
+{11574, 17, 49770, {1, 1, 1, 15, 5, 5, 3, 127, 265, 721, 875, 3117, 2177, 7843, 15871, 22687, 89347}},
+{11575, 17, 49772, {1, 3, 7, 11, 29, 23, 69, 41, 155, 257, 563, 509, 6105, 9169, 18341, 25373, 127397}},
+{11576, 17, 49777, {1, 1, 5, 13, 31, 23, 65, 131, 131, 61, 1979, 2737, 3793, 3617, 14385, 189, 84567}},
+{11577, 17, 49789, {1, 1, 1, 13, 21, 33, 43, 97, 83, 903, 1971, 3209, 5391, 7703, 13795, 3895, 78045}},
+{11578, 17, 49817, {1, 3, 3, 5, 17, 53, 113, 237, 269, 83, 589, 4029, 3309, 14531, 11359, 25803, 25525}},
+{11579, 17, 49829, {1, 1, 7, 1, 21, 35, 43, 73, 251, 705, 1737, 3341, 1581, 9663, 6251, 16329, 44491}},
+{11580, 17, 49839, {1, 3, 3, 7, 17, 5, 65, 19, 203, 717, 807, 1759, 6907, 15801, 30369, 2655, 69565}},
+{11581, 17, 49844, {1, 1, 1, 1, 31, 21, 75, 221, 115, 395, 1495, 2739, 1745, 5981, 28045, 56581, 130695}},
+{11582, 17, 49851, {1, 3, 1, 9, 27, 5, 113, 123, 367, 701, 647, 117, 2389, 12309, 1747, 23421, 21583}},
+{11583, 17, 49854, {1, 1, 1, 15, 27, 57, 95, 81, 347, 765, 1435, 1727, 153, 6051, 27085, 62787, 40903}},
+{11584, 17, 49874, {1, 1, 3, 11, 23, 29, 23, 29, 169, 653, 835, 357, 5113, 5293, 11779, 23567, 64569}},
+{11585, 17, 49883, {1, 1, 7, 13, 31, 7, 101, 235, 99, 247, 1267, 509, 3927, 14317, 3217, 24389, 34215}},
+{11586, 17, 49886, {1, 3, 3, 5, 21, 27, 33, 229, 33, 551, 815, 3551, 4261, 13325, 31117, 40689, 66549}},
+{11587, 17, 49892, {1, 3, 7, 1, 23, 1, 99, 11, 139, 569, 365, 1233, 3281, 7817, 8833, 47699, 97825}},
+{11588, 17, 49895, {1, 1, 3, 1, 19, 39, 19, 151, 25, 73, 1271, 1435, 3109, 2571, 9191, 48257, 61001}},
+{11589, 17, 49914, {1, 3, 7, 1, 23, 63, 1, 115, 159, 943, 1637, 1443, 809, 10705, 12563, 63111, 96343}},
+{11590, 17, 49931, {1, 1, 7, 15, 5, 17, 65, 157, 45, 199, 371, 2497, 4367, 9109, 31955, 64253, 69279}},
+{11591, 17, 49933, {1, 3, 3, 15, 29, 45, 103, 183, 87, 543, 97, 1545, 2719, 5619, 28871, 4049, 111825}},
+{11592, 17, 49934, {1, 1, 5, 7, 27, 63, 65, 241, 103, 483, 579, 3589, 5673, 13283, 24193, 31993, 72713}},
+{11593, 17, 49941, {1, 3, 7, 9, 21, 35, 59, 183, 459, 211, 753, 3941, 5389, 10535, 2895, 44307, 26577}},
+{11594, 17, 49952, {1, 3, 1, 3, 9, 11, 15, 141, 159, 853, 1975, 4027, 8053, 16129, 32687, 29117, 67507}},
+{11595, 17, 49967, {1, 3, 3, 1, 19, 51, 55, 167, 85, 869, 437, 457, 7879, 2097, 4403, 2139, 10589}},
+{11596, 17, 49969, {1, 3, 3, 15, 19, 33, 63, 229, 197, 269, 1189, 317, 5087, 3147, 787, 64317, 43293}},
+{11597, 17, 49972, {1, 3, 5, 11, 25, 25, 121, 37, 371, 117, 1683, 2921, 671, 11353, 32273, 57597, 56901}},
+{11598, 17, 49976, {1, 3, 7, 7, 9, 37, 91, 159, 195, 1, 77, 2085, 985, 9999, 5639, 25041, 66393}},
+{11599, 17, 49979, {1, 1, 7, 5, 11, 17, 67, 21, 301, 971, 591, 3809, 4795, 12301, 16977, 27495, 98539}},
+{11600, 17, 49999, {1, 3, 1, 9, 13, 53, 83, 205, 111, 609, 631, 23, 1781, 15401, 1563, 34367, 40345}},
+{11601, 17, 50008, {1, 3, 7, 1, 31, 23, 101, 47, 55, 905, 953, 733, 5173, 5937, 17703, 31077, 49707}},
+{11602, 17, 50030, {1, 3, 5, 3, 5, 3, 127, 171, 511, 289, 685, 1157, 6521, 3301, 3017, 58857, 55289}},
+{11603, 17, 50041, {1, 1, 5, 1, 1, 29, 59, 7, 423, 83, 797, 2633, 2015, 1657, 7575, 39819, 181}},
+{11604, 17, 50042, {1, 3, 5, 15, 25, 27, 39, 99, 83, 381, 401, 1033, 867, 15645, 28643, 34917, 53215}},
+{11605, 17, 50044, {1, 3, 5, 15, 17, 1, 67, 63, 355, 841, 681, 2807, 531, 15295, 7859, 64031, 121519}},
+{11606, 17, 50057, {1, 3, 1, 5, 21, 57, 63, 247, 467, 101, 129, 2627, 4763, 479, 11145, 8861, 69803}},
+{11607, 17, 50060, {1, 3, 1, 15, 13, 13, 77, 39, 297, 401, 1653, 659, 3909, 13179, 10477, 45967, 1665}},
+{11608, 17, 50075, {1, 3, 7, 5, 29, 17, 35, 157, 309, 747, 1717, 1279, 6103, 3509, 17499, 22989, 43157}},
+{11609, 17, 50077, {1, 1, 1, 7, 11, 51, 55, 119, 145, 505, 179, 3979, 1237, 12801, 15921, 13561, 69161}},
+{11610, 17, 50091, {1, 1, 5, 7, 13, 9, 73, 203, 247, 257, 1607, 1183, 6237, 12327, 5059, 51645, 88781}},
+{11611, 17, 50096, {1, 3, 5, 9, 1, 9, 27, 59, 235, 81, 689, 2457, 893, 6107, 27643, 40145, 2329}},
+{11612, 17, 50099, {1, 1, 1, 11, 11, 19, 65, 63, 27, 513, 1473, 2955, 8037, 4991, 22035, 41965, 82589}},
+{11613, 17, 50106, {1, 3, 1, 1, 9, 53, 97, 95, 247, 379, 259, 2789, 1433, 15299, 18309, 51813, 63271}},
+{11614, 17, 50116, {1, 1, 5, 1, 11, 41, 69, 193, 391, 27, 1511, 1575, 1161, 14741, 25193, 31149, 79573}},
+{11615, 17, 50133, {1, 3, 7, 15, 19, 31, 101, 9, 111, 427, 531, 1335, 767, 15075, 28373, 54015, 108021}},
+{11616, 17, 50144, {1, 3, 1, 3, 29, 17, 83, 163, 179, 703, 2027, 3027, 5267, 16111, 23929, 9653, 38633}},
+{11617, 17, 50153, {1, 3, 5, 9, 3, 7, 111, 1, 311, 143, 1563, 2605, 301, 2447, 5009, 63767, 37529}},
+{11618, 17, 50154, {1, 3, 5, 5, 23, 23, 97, 11, 475, 741, 1385, 2491, 1717, 14587, 6289, 27651, 21873}},
+{11619, 17, 50168, {1, 1, 5, 1, 31, 31, 119, 93, 209, 861, 1591, 1233, 3469, 9799, 5969, 35965, 110841}},
+{11620, 17, 50179, {1, 1, 5, 13, 19, 31, 69, 107, 423, 651, 757, 665, 1297, 9985, 14983, 3153, 26425}},
+{11621, 17, 50188, {1, 1, 5, 3, 23, 5, 89, 77, 461, 799, 683, 2885, 845, 12847, 26721, 13145, 88689}},
+{11622, 17, 50194, {1, 1, 3, 3, 19, 3, 41, 71, 247, 293, 1047, 2349, 6815, 2413, 13683, 51421, 110737}},
+{11623, 17, 50203, {1, 3, 3, 9, 19, 51, 91, 193, 447, 305, 751, 1757, 1547, 12683, 4645, 39767, 6433}},
+{11624, 17, 50212, {1, 1, 7, 1, 11, 51, 83, 175, 461, 259, 1337, 175, 877, 15895, 22487, 8079, 71291}},
+{11625, 17, 50216, {1, 1, 1, 11, 13, 23, 19, 69, 285, 629, 563, 2433, 815, 4851, 10617, 59949, 59119}},
+{11626, 17, 50222, {1, 3, 5, 5, 19, 49, 47, 27, 343, 579, 197, 35, 7051, 2441, 30091, 9645, 101899}},
+{11627, 17, 50229, {1, 1, 3, 3, 21, 25, 125, 215, 159, 259, 1915, 2193, 4213, 16157, 8665, 10967, 112793}},
+{11628, 17, 50230, {1, 1, 5, 11, 29, 11, 53, 45, 121, 533, 257, 1749, 6311, 7715, 12037, 12003, 38987}},
+{11629, 17, 50234, {1, 3, 1, 11, 25, 31, 93, 191, 231, 801, 361, 1275, 5031, 7927, 26333, 39795, 45875}},
+{11630, 17, 50251, {1, 1, 5, 1, 7, 37, 117, 35, 257, 225, 1769, 1805, 1593, 1507, 27741, 31561, 52107}},
+{11631, 17, 50253, {1, 1, 3, 3, 27, 23, 55, 5, 137, 677, 459, 2821, 1331, 5845, 17751, 17557, 60495}},
+{11632, 17, 50262, {1, 1, 7, 7, 5, 47, 85, 17, 287, 757, 2013, 2233, 2975, 13769, 23199, 32117, 84429}},
+{11633, 17, 50266, {1, 3, 3, 11, 1, 15, 39, 133, 79, 915, 147, 1489, 2319, 13715, 31317, 46785, 64147}},
+{11634, 17, 50272, {1, 1, 3, 11, 1, 25, 83, 69, 395, 537, 895, 565, 2781, 12685, 7831, 36369, 27871}},
+{11635, 17, 50287, {1, 1, 1, 1, 13, 17, 59, 179, 509, 979, 315, 3495, 1773, 16375, 27873, 18065, 20285}},
+{11636, 17, 50295, {1, 1, 5, 1, 27, 31, 39, 251, 121, 899, 751, 1603, 7501, 425, 25791, 35407, 110405}},
+{11637, 17, 50305, {1, 1, 7, 11, 11, 3, 107, 247, 79, 349, 405, 3469, 2201, 8007, 22891, 7901, 11413}},
+{11638, 17, 50306, {1, 1, 1, 11, 15, 55, 121, 151, 127, 239, 115, 611, 6191, 15435, 19831, 64745, 110473}},
+{11639, 17, 50311, {1, 1, 7, 1, 21, 25, 57, 11, 31, 823, 1855, 2337, 7655, 10845, 22167, 36977, 94265}},
+{11640, 17, 50320, {1, 3, 5, 1, 31, 11, 117, 97, 341, 953, 1499, 2487, 559, 8609, 6321, 20669, 28945}},
+{11641, 17, 50323, {1, 3, 7, 1, 5, 27, 15, 161, 83, 139, 75, 3645, 5227, 16199, 1833, 21767, 67579}},
+{11642, 17, 50325, {1, 1, 7, 5, 31, 35, 75, 115, 451, 773, 1987, 1069, 651, 961, 16317, 18391, 56519}},
+{11643, 17, 50339, {1, 1, 1, 1, 31, 11, 23, 255, 215, 251, 867, 2381, 2351, 13189, 17705, 33569, 102361}},
+{11644, 17, 50356, {1, 3, 7, 1, 17, 49, 49, 125, 445, 947, 1985, 2113, 3025, 6277, 1981, 33329, 99413}},
+{11645, 17, 50365, {1, 3, 3, 3, 27, 7, 59, 109, 37, 777, 1359, 2157, 3185, 7317, 30887, 10499, 126563}},
+{11646, 17, 50366, {1, 3, 3, 9, 27, 5, 99, 167, 457, 363, 2031, 1805, 4661, 8695, 4667, 61129, 81143}},
+{11647, 17, 50368, {1, 1, 5, 13, 5, 47, 95, 249, 289, 631, 1739, 2947, 7169, 13019, 10429, 16197, 11539}},
+{11648, 17, 50377, {1, 3, 7, 15, 27, 45, 93, 131, 269, 835, 399, 1133, 6509, 1279, 3635, 17977, 38667}},
+{11649, 17, 50386, {1, 1, 5, 3, 17, 51, 1, 77, 105, 237, 995, 2643, 6921, 6707, 30129, 1543, 94501}},
+{11650, 17, 50397, {1, 1, 1, 7, 29, 1, 117, 33, 141, 805, 1553, 3943, 45, 8911, 24191, 45191, 36525}},
+{11651, 17, 50411, {1, 1, 7, 7, 31, 21, 97, 29, 179, 345, 1059, 701, 7709, 15831, 22923, 57233, 58961}},
+{11652, 17, 50414, {1, 1, 3, 15, 15, 5, 85, 227, 13, 351, 1167, 3283, 6833, 565, 21019, 53249, 4639}},
+{11653, 17, 50425, {1, 3, 3, 5, 27, 1, 5, 89, 101, 295, 481, 2397, 1459, 3729, 3703, 25109, 69237}},
+{11654, 17, 50451, {1, 3, 7, 13, 31, 37, 69, 147, 505, 487, 1701, 1145, 2061, 10067, 18269, 13049, 92091}},
+{11655, 17, 50463, {1, 3, 3, 1, 29, 39, 33, 199, 499, 377, 1081, 3787, 4843, 16287, 23397, 19083, 91381}},
+{11656, 17, 50467, {1, 1, 1, 13, 21, 61, 121, 251, 511, 615, 625, 2245, 5951, 16165, 2155, 37301, 68319}},
+{11657, 17, 50473, {1, 1, 1, 15, 19, 35, 57, 99, 1, 97, 1177, 3109, 7213, 5447, 25251, 24803, 107449}},
+{11658, 17, 50487, {1, 3, 1, 11, 11, 59, 95, 135, 329, 931, 843, 2847, 463, 10725, 3933, 32325, 44545}},
+{11659, 17, 50501, {1, 1, 7, 13, 13, 57, 29, 175, 11, 701, 231, 2907, 5555, 16159, 1249, 38049, 40115}},
+{11660, 17, 50505, {1, 1, 5, 15, 23, 37, 47, 221, 465, 631, 57, 1189, 2083, 6561, 10725, 8015, 21231}},
+{11661, 17, 50514, {1, 3, 7, 5, 9, 25, 31, 47, 139, 639, 999, 2909, 39, 16227, 16967, 30555, 125541}},
+{11662, 17, 50516, {1, 3, 3, 9, 5, 3, 9, 9, 43, 999, 159, 3063, 3661, 7089, 28929, 55305, 105521}},
+{11663, 17, 50536, {1, 3, 1, 11, 17, 7, 3, 57, 457, 753, 135, 3721, 1111, 7267, 12603, 50511, 85433}},
+{11664, 17, 50547, {1, 3, 5, 1, 27, 3, 107, 187, 247, 891, 1311, 423, 1767, 14769, 22119, 36225, 94267}},
+{11665, 17, 50566, {1, 3, 5, 15, 1, 13, 65, 35, 435, 557, 1755, 1343, 2647, 179, 7781, 62903, 18741}},
+{11666, 17, 50572, {1, 1, 7, 15, 29, 57, 63, 227, 407, 163, 1207, 2717, 2731, 1737, 6379, 14937, 46683}},
+{11667, 17, 50583, {1, 1, 1, 9, 25, 35, 93, 1, 77, 677, 875, 3787, 3075, 14033, 23017, 3487, 14999}},
+{11668, 17, 50593, {1, 3, 3, 9, 3, 45, 115, 61, 437, 823, 1401, 459, 301, 5519, 31003, 64499, 1757}},
+{11669, 17, 50599, {1, 3, 1, 11, 23, 37, 69, 215, 197, 961, 1501, 2953, 3679, 6775, 24679, 44215, 52357}},
+{11670, 17, 50613, {1, 3, 1, 15, 29, 23, 1, 133, 451, 677, 687, 1269, 5987, 11975, 11929, 63691, 48683}},
+{11671, 17, 50617, {1, 1, 1, 7, 13, 31, 13, 71, 355, 345, 1193, 3421, 7601, 7413, 6719, 28681, 97605}},
+{11672, 17, 50618, {1, 1, 5, 13, 23, 3, 15, 253, 109, 17, 341, 471, 1131, 14901, 31783, 41369, 64139}},
+{11673, 17, 50620, {1, 1, 3, 1, 25, 25, 85, 157, 443, 83, 269, 3789, 7977, 7783, 28433, 30563, 82805}},
+{11674, 17, 50628, {1, 1, 7, 5, 3, 11, 83, 63, 253, 349, 217, 2733, 4183, 2759, 7617, 41749, 14015}},
+{11675, 17, 50638, {1, 1, 5, 7, 7, 7, 91, 201, 449, 247, 889, 3829, 3529, 14253, 24091, 33521, 6049}},
+{11676, 17, 50652, {1, 1, 3, 7, 25, 7, 123, 161, 227, 965, 511, 619, 4359, 11833, 12859, 26091, 3867}},
+{11677, 17, 50655, {1, 1, 7, 9, 5, 41, 71, 111, 95, 261, 1809, 3835, 7625, 12085, 28885, 64829, 48981}},
+{11678, 17, 50662, {1, 1, 5, 3, 13, 55, 57, 79, 457, 785, 653, 1429, 3879, 13559, 3953, 18205, 5777}},
+{11679, 17, 50665, {1, 3, 5, 9, 23, 25, 107, 255, 151, 191, 119, 3367, 1081, 12691, 3575, 38171, 42573}},
+{11680, 17, 50673, {1, 1, 7, 15, 3, 23, 115, 233, 265, 187, 1961, 1303, 5101, 1035, 6803, 14557, 4527}},
+{11681, 17, 50683, {1, 1, 3, 11, 19, 37, 45, 167, 17, 793, 1361, 3571, 5889, 14421, 20453, 5093, 59927}},
+{11682, 17, 50689, {1, 1, 7, 15, 3, 53, 1, 11, 159, 389, 171, 2351, 7189, 3109, 1541, 53595, 24247}},
+{11683, 17, 50690, {1, 1, 7, 1, 7, 43, 75, 175, 253, 687, 1811, 3277, 447, 8711, 14281, 53265, 7379}},
+{11684, 17, 50692, {1, 1, 5, 3, 21, 45, 113, 25, 309, 31, 1765, 305, 1423, 115, 26421, 50267, 122115}},
+{11685, 17, 50696, {1, 3, 5, 13, 15, 47, 17, 17, 445, 775, 243, 3959, 7263, 9375, 12017, 57399, 58203}},
+{11686, 17, 50704, {1, 3, 3, 1, 31, 37, 37, 213, 125, 929, 243, 1011, 2841, 4499, 16961, 12639, 23381}},
+{11687, 17, 50713, {1, 3, 1, 3, 7, 53, 31, 165, 311, 239, 731, 1759, 1769, 203, 23201, 20267, 33381}},
+{11688, 17, 50719, {1, 3, 3, 11, 1, 1, 73, 57, 497, 693, 693, 861, 5587, 16307, 8559, 28785, 91147}},
+{11689, 17, 50738, {1, 3, 1, 3, 11, 61, 11, 241, 473, 479, 1831, 1771, 25, 10217, 32683, 40165, 98433}},
+{11690, 17, 50757, {1, 1, 5, 3, 17, 51, 39, 27, 189, 631, 689, 2849, 1849, 9143, 19263, 32729, 23031}},
+{11691, 17, 50761, {1, 1, 5, 9, 15, 39, 103, 83, 485, 689, 1561, 55, 5219, 12069, 32225, 7781, 114299}},
+{11692, 17, 50764, {1, 1, 1, 1, 31, 49, 71, 145, 485, 907, 1551, 3931, 4081, 2159, 24747, 6953, 15887}},
+{11693, 17, 50770, {1, 1, 3, 7, 27, 61, 57, 153, 15, 881, 271, 267, 5827, 7625, 18179, 3769, 42211}},
+{11694, 17, 50776, {1, 3, 1, 3, 21, 49, 65, 177, 341, 851, 1825, 3347, 113, 8077, 1117, 9463, 115821}},
+{11695, 17, 50803, {1, 3, 5, 11, 27, 17, 75, 35, 475, 389, 313, 2187, 7005, 911, 21921, 10979, 13705}},
+{11696, 17, 50805, {1, 1, 5, 9, 1, 49, 15, 21, 163, 355, 193, 3473, 4451, 5325, 28343, 251, 125963}},
+{11697, 17, 50806, {1, 3, 7, 1, 9, 63, 9, 129, 453, 887, 1841, 597, 1989, 14755, 7847, 7581, 251}},
+{11698, 17, 50816, {1, 3, 7, 13, 31, 15, 123, 3, 427, 101, 1039, 1355, 3653, 2871, 28937, 31243, 108827}},
+{11699, 17, 50826, {1, 3, 7, 13, 3, 17, 71, 243, 145, 747, 1933, 1105, 455, 6355, 20321, 60075, 31575}},
+{11700, 17, 50840, {1, 3, 5, 5, 11, 25, 95, 85, 461, 459, 313, 173, 1413, 15761, 31481, 63793, 29047}},
+{11701, 17, 50845, {1, 3, 7, 7, 3, 5, 3, 95, 107, 995, 1203, 2965, 2419, 5325, 17667, 40205, 91059}},
+{11702, 17, 50852, {1, 1, 3, 9, 25, 3, 113, 79, 359, 69, 93, 1539, 483, 12701, 19075, 35021, 17929}},
+{11703, 17, 50855, {1, 3, 5, 1, 31, 35, 67, 97, 105, 381, 973, 1355, 3901, 3847, 12343, 64309, 29835}},
+{11704, 17, 50862, {1, 3, 7, 1, 11, 33, 117, 237, 449, 101, 317, 23, 5157, 8187, 28839, 29465, 97485}},
+{11705, 17, 50876, {1, 3, 5, 5, 1, 49, 93, 71, 89, 607, 1143, 3271, 5825, 8529, 18479, 23859, 40571}},
+{11706, 17, 50879, {1, 3, 1, 3, 13, 35, 79, 9, 315, 943, 1199, 1521, 2023, 11745, 8273, 27643, 89545}},
+{11707, 17, 50882, {1, 3, 5, 1, 21, 3, 15, 111, 19, 895, 1539, 3331, 6741, 9087, 5231, 13435, 60645}},
+{11708, 17, 50894, {1, 3, 1, 9, 25, 9, 109, 253, 263, 425, 915, 1955, 659, 6249, 11803, 34523, 22645}},
+{11709, 17, 50899, {1, 1, 1, 9, 15, 23, 13, 79, 369, 689, 565, 743, 3897, 8837, 13753, 17213, 86801}},
+{11710, 17, 50905, {1, 1, 1, 5, 31, 27, 111, 231, 25, 617, 897, 1325, 4885, 5731, 2027, 34639, 67863}},
+{11711, 17, 50924, {1, 1, 3, 13, 1, 9, 29, 23, 95, 113, 1035, 2729, 6555, 335, 24795, 35387, 31301}},
+{11712, 17, 50936, {1, 1, 1, 7, 3, 53, 91, 143, 167, 773, 207, 31, 4993, 7953, 26997, 40031, 113939}},
+{11713, 17, 50944, {1, 1, 3, 5, 17, 43, 121, 231, 411, 575, 1621, 3079, 535, 3313, 19443, 58271, 54207}},
+{11714, 17, 50973, {1, 1, 1, 7, 11, 41, 61, 81, 97, 91, 1987, 981, 3745, 819, 23785, 48331, 63761}},
+{11715, 17, 50974, {1, 1, 5, 13, 7, 29, 25, 73, 355, 669, 241, 65, 2249, 5551, 5217, 58573, 34049}},
+{11716, 17, 51002, {1, 1, 7, 11, 1, 45, 125, 107, 127, 639, 1989, 2727, 2103, 8985, 30249, 40037, 40931}},
+{11717, 17, 51007, {1, 1, 5, 13, 21, 59, 99, 131, 359, 615, 665, 577, 2559, 3555, 11355, 26213, 76427}},
+{11718, 17, 51009, {1, 3, 3, 1, 19, 9, 85, 111, 381, 661, 561, 3419, 1355, 8473, 329, 4989, 9087}},
+{11719, 17, 51029, {1, 1, 7, 5, 11, 23, 33, 95, 343, 9, 1579, 2663, 6245, 267, 7187, 25381, 103181}},
+{11720, 17, 51036, {1, 1, 7, 11, 23, 7, 113, 49, 89, 587, 1221, 409, 873, 15531, 2721, 44519, 25349}},
+{11721, 17, 51063, {1, 3, 3, 1, 17, 17, 45, 239, 453, 639, 1433, 2829, 6009, 12447, 9393, 59979, 93343}},
+{11722, 17, 51067, {1, 1, 3, 15, 19, 61, 125, 101, 219, 327, 1551, 1623, 951, 8379, 21009, 64089, 21891}},
+{11723, 17, 51070, {1, 1, 5, 7, 23, 5, 111, 43, 57, 71, 407, 4027, 4869, 12033, 19941, 51969, 120115}},
+{11724, 17, 51074, {1, 3, 7, 15, 17, 49, 31, 145, 185, 169, 1559, 4011, 5293, 7559, 23487, 12213, 2757}},
+{11725, 17, 51079, {1, 3, 7, 3, 3, 59, 119, 3, 509, 539, 1623, 539, 1405, 3913, 213, 30293, 68497}},
+{11726, 17, 51083, {1, 1, 1, 9, 15, 43, 67, 171, 397, 233, 379, 1681, 6877, 9169, 19667, 1971, 115347}},
+{11727, 17, 51093, {1, 1, 5, 15, 1, 45, 25, 133, 99, 181, 1825, 3485, 5633, 4629, 30181, 15761, 87161}},
+{11728, 17, 51094, {1, 1, 5, 3, 5, 55, 97, 117, 303, 591, 733, 3631, 4305, 169, 5361, 64491, 71793}},
+{11729, 17, 51124, {1, 1, 5, 11, 19, 9, 5, 147, 223, 51, 1763, 3899, 7393, 8107, 19619, 60509, 61427}},
+{11730, 17, 51131, {1, 1, 1, 15, 15, 3, 103, 15, 423, 649, 613, 1387, 6229, 4147, 17517, 225, 35697}},
+{11731, 17, 51151, {1, 3, 1, 3, 21, 57, 77, 193, 203, 649, 631, 3753, 4259, 3983, 27707, 33623, 83857}},
+{11732, 17, 51153, {1, 3, 3, 5, 11, 37, 95, 201, 83, 643, 1639, 153, 7683, 15249, 23859, 27021, 43321}},
+{11733, 17, 51156, {1, 3, 5, 13, 23, 31, 69, 215, 303, 433, 1325, 1013, 2903, 12659, 3813, 34497, 59651}},
+{11734, 17, 51165, {1, 3, 1, 9, 15, 39, 113, 253, 173, 393, 19, 2343, 2939, 8871, 29741, 2141, 121675}},
+{11735, 17, 51175, {1, 1, 7, 9, 7, 9, 91, 211, 169, 299, 507, 2849, 1321, 15397, 23949, 32387, 108691}},
+{11736, 17, 51184, {1, 1, 7, 13, 1, 21, 119, 127, 229, 253, 39, 323, 1831, 121, 17385, 45511, 43743}},
+{11737, 17, 51187, {1, 1, 1, 15, 25, 25, 97, 209, 375, 945, 1343, 2205, 1701, 13085, 25547, 55555, 129395}},
+{11738, 17, 51203, {1, 1, 1, 5, 31, 25, 91, 255, 163, 169, 703, 1607, 4731, 7413, 10013, 10925, 109151}},
+{11739, 17, 51220, {1, 3, 3, 9, 15, 47, 71, 219, 9, 37, 231, 3227, 3447, 8129, 23421, 30113, 120725}},
+{11740, 17, 51224, {1, 3, 3, 11, 15, 47, 93, 203, 299, 865, 151, 3999, 1245, 8487, 13355, 27373, 93583}},
+{11741, 17, 51233, {1, 3, 7, 5, 13, 7, 97, 81, 271, 95, 513, 365, 5039, 403, 5285, 29475, 129347}},
+{11742, 17, 51234, {1, 1, 7, 7, 9, 27, 25, 207, 161, 785, 1453, 3031, 763, 2313, 29347, 61457, 52561}},
+{11743, 17, 51239, {1, 3, 3, 11, 25, 25, 39, 61, 165, 803, 1435, 3643, 299, 13751, 24239, 53955, 94889}},
+{11744, 17, 51246, {1, 3, 5, 9, 9, 13, 63, 221, 123, 947, 905, 913, 953, 7429, 25409, 43017, 2217}},
+{11745, 17, 51248, {1, 1, 3, 3, 31, 19, 107, 211, 503, 675, 1921, 3027, 1273, 5699, 20683, 55605, 119803}},
+{11746, 17, 51251, {1, 1, 3, 3, 9, 17, 115, 183, 325, 259, 2013, 1505, 6999, 11573, 5315, 18731, 9405}},
+{11747, 17, 51257, {1, 3, 1, 5, 29, 37, 81, 145, 5, 851, 1803, 2011, 6655, 3601, 11325, 17137, 68501}},
+{11748, 17, 51266, {1, 3, 5, 1, 25, 51, 111, 19, 75, 765, 1843, 139, 7253, 12967, 13387, 48631, 124881}},
+{11749, 17, 51280, {1, 3, 3, 7, 15, 29, 7, 231, 13, 901, 1913, 3817, 3993, 3049, 32367, 4201, 90837}},
+{11750, 17, 51285, {1, 3, 1, 11, 27, 5, 109, 57, 81, 147, 1141, 2153, 5255, 6367, 189, 5959, 88843}},
+{11751, 17, 51286, {1, 3, 5, 5, 19, 35, 17, 149, 407, 889, 1583, 1727, 465, 10785, 6043, 21785, 80935}},
+{11752, 17, 51289, {1, 1, 3, 7, 15, 21, 105, 249, 427, 491, 923, 3189, 8103, 3875, 18347, 35799, 36703}},
+{11753, 17, 51295, {1, 1, 3, 15, 3, 45, 93, 197, 265, 309, 1909, 1635, 1743, 9499, 21897, 36889, 67449}},
+{11754, 17, 51296, {1, 3, 1, 11, 15, 57, 31, 231, 363, 879, 1377, 1941, 6969, 10721, 21933, 33419, 102939}},
+{11755, 17, 51311, {1, 1, 3, 9, 3, 57, 49, 51, 71, 991, 885, 1367, 2937, 9301, 29893, 9867, 113711}},
+{11756, 17, 51329, {1, 3, 7, 7, 11, 59, 123, 247, 51, 659, 1323, 3371, 3417, 12295, 2021, 62753, 28059}},
+{11757, 17, 51350, {1, 1, 7, 11, 3, 57, 53, 1, 203, 287, 219, 3531, 1365, 6235, 30187, 4479, 29567}},
+{11758, 17, 51356, {1, 1, 7, 9, 5, 41, 41, 39, 137, 495, 149, 2421, 7365, 11381, 25403, 16063, 47491}},
+{11759, 17, 51363, {1, 1, 5, 13, 25, 25, 47, 25, 213, 661, 1345, 883, 7573, 3291, 21303, 8033, 102639}},
+{11760, 17, 51365, {1, 1, 5, 3, 9, 49, 75, 221, 455, 139, 1533, 3155, 1023, 7249, 10129, 63165, 1713}},
+{11761, 17, 51370, {1, 3, 5, 11, 17, 1, 23, 241, 83, 359, 1243, 2791, 2975, 6271, 19035, 55057, 7625}},
+{11762, 17, 51372, {1, 3, 1, 9, 17, 61, 109, 255, 447, 939, 899, 551, 7049, 4247, 17333, 43369, 30105}},
+{11763, 17, 51377, {1, 1, 3, 5, 3, 31, 79, 39, 225, 605, 1893, 3523, 5391, 6879, 18619, 2339, 108295}},
+{11764, 17, 51383, {1, 1, 5, 1, 29, 15, 123, 39, 239, 57, 843, 2799, 4755, 4993, 23383, 45559, 48359}},
+{11765, 17, 51384, {1, 1, 5, 5, 7, 5, 99, 1, 351, 213, 1061, 721, 343, 16071, 29641, 55607, 76727}},
+{11766, 17, 51397, {1, 3, 1, 7, 9, 9, 15, 25, 87, 595, 71, 3769, 2583, 10105, 28639, 48899, 49753}},
+{11767, 17, 51407, {1, 3, 5, 3, 31, 29, 99, 77, 323, 615, 581, 1725, 2471, 16263, 4903, 205, 55441}},
+{11768, 17, 51422, {1, 1, 5, 11, 17, 53, 47, 53, 125, 717, 867, 1251, 4009, 13981, 10165, 4769, 117431}},
+{11769, 17, 51435, {1, 1, 3, 7, 7, 19, 119, 27, 163, 11, 693, 3197, 3981, 12591, 26017, 62113, 48391}},
+{11770, 17, 51440, {1, 1, 3, 15, 13, 17, 13, 81, 19, 821, 677, 233, 5227, 14855, 18269, 18895, 90041}},
+{11771, 17, 51446, {1, 1, 3, 9, 27, 61, 125, 221, 415, 183, 1137, 1879, 3451, 3599, 27317, 53449, 35499}},
+{11772, 17, 51463, {1, 3, 3, 15, 3, 27, 53, 93, 17, 405, 373, 2531, 3121, 2299, 1593, 34623, 102389}},
+{11773, 17, 51467, {1, 1, 1, 11, 23, 19, 85, 87, 209, 17, 1805, 4067, 7401, 6097, 5865, 61383, 42971}},
+{11774, 17, 51491, {1, 1, 7, 9, 29, 43, 99, 125, 385, 347, 97, 1121, 1533, 10545, 17383, 48649, 78443}},
+{11775, 17, 51493, {1, 3, 3, 13, 7, 9, 95, 105, 463, 911, 357, 423, 5701, 2389, 16307, 17817, 108775}},
+{11776, 17, 51494, {1, 3, 5, 11, 21, 21, 79, 53, 511, 995, 1709, 1715, 6031, 10507, 10735, 48817, 28569}},
+{11777, 17, 51508, {1, 3, 5, 7, 31, 49, 43, 109, 267, 981, 1529, 3611, 3379, 1295, 27489, 46721, 58423}},
+{11778, 17, 51518, {1, 3, 3, 11, 3, 31, 21, 3, 79, 31, 1885, 3029, 6337, 15457, 8995, 9955, 95019}},
+{11779, 17, 51520, {1, 1, 7, 13, 9, 9, 77, 73, 111, 769, 813, 1599, 5925, 1063, 12151, 54125, 67723}},
+{11780, 17, 51526, {1, 1, 1, 7, 13, 5, 43, 201, 379, 199, 769, 3227, 3995, 1543, 21903, 10651, 122007}},
+{11781, 17, 51529, {1, 3, 7, 13, 11, 53, 83, 201, 231, 137, 617, 2395, 2513, 6659, 9387, 15653, 96927}},
+{11782, 17, 51530, {1, 3, 1, 13, 29, 19, 97, 57, 231, 985, 805, 1169, 831, 15867, 20195, 53533, 99735}},
+{11783, 17, 51537, {1, 1, 3, 13, 19, 15, 19, 39, 99, 31, 421, 755, 7439, 4927, 19893, 15449, 47937}},
+{11784, 17, 51547, {1, 3, 3, 9, 1, 17, 71, 37, 289, 537, 69, 3687, 6537, 12295, 28403, 6627, 72991}},
+{11785, 17, 51559, {1, 3, 3, 15, 31, 53, 21, 223, 451, 309, 895, 3923, 3149, 5167, 1979, 31425, 53485}},
+{11786, 17, 51565, {1, 3, 1, 1, 29, 7, 5, 197, 445, 455, 185, 633, 897, 4561, 28833, 39477, 46665}},
+{11787, 17, 51568, {1, 1, 3, 9, 29, 19, 45, 239, 323, 1005, 101, 2083, 7403, 10401, 987, 32301, 58141}},
+{11788, 17, 51580, {1, 3, 3, 5, 31, 17, 7, 141, 245, 301, 1607, 3381, 7517, 6663, 6327, 15321, 19963}},
+{11789, 17, 51583, {1, 1, 7, 5, 5, 37, 109, 31, 285, 767, 1689, 2961, 5511, 15415, 32011, 14889, 7237}},
+{11790, 17, 51584, {1, 1, 3, 7, 31, 35, 47, 157, 407, 719, 1213, 1241, 2475, 10321, 11547, 52641, 21603}},
+{11791, 17, 51593, {1, 1, 1, 7, 5, 45, 35, 137, 403, 321, 1151, 529, 6297, 3059, 27791, 18387, 101431}},
+{11792, 17, 51594, {1, 1, 3, 11, 21, 19, 97, 121, 377, 325, 741, 1601, 1115, 6233, 19089, 40491, 53259}},
+{11793, 17, 51607, {1, 1, 1, 9, 3, 13, 83, 243, 443, 91, 1455, 1875, 3327, 7245, 12735, 14943, 44163}},
+{11794, 17, 51608, {1, 3, 5, 11, 1, 15, 107, 211, 25, 125, 623, 1319, 6133, 12177, 1377, 32547, 110919}},
+{11795, 17, 51620, {1, 1, 3, 3, 7, 39, 23, 99, 433, 581, 53, 3421, 733, 12767, 23595, 22957, 88821}},
+{11796, 17, 51624, {1, 1, 1, 13, 5, 53, 103, 127, 409, 379, 1155, 3097, 6529, 11685, 22147, 46003, 59771}},
+{11797, 17, 51642, {1, 3, 3, 3, 15, 37, 9, 67, 237, 79, 697, 1943, 1021, 3217, 16013, 14727, 105729}},
+{11798, 17, 51649, {1, 1, 7, 1, 9, 43, 55, 79, 63, 553, 871, 2881, 6487, 4667, 24263, 41995, 60907}},
+{11799, 17, 51652, {1, 1, 7, 7, 23, 31, 55, 23, 451, 593, 85, 43, 965, 12491, 15121, 16129, 90639}},
+{11800, 17, 51659, {1, 1, 7, 13, 11, 53, 21, 123, 237, 147, 511, 2105, 5961, 4465, 4015, 19069, 89203}},
+{11801, 17, 51661, {1, 3, 5, 1, 1, 39, 59, 239, 391, 91, 923, 85, 1047, 1489, 31119, 58485, 129171}},
+{11802, 17, 51670, {1, 3, 5, 13, 3, 21, 35, 205, 219, 795, 901, 2465, 5887, 275, 22003, 29659, 50589}},
+{11803, 17, 51674, {1, 3, 1, 5, 1, 35, 127, 147, 159, 791, 1643, 1811, 1199, 3851, 9681, 19845, 127075}},
+{11804, 17, 51698, {1, 3, 3, 7, 17, 19, 13, 223, 395, 971, 125, 181, 4455, 13305, 30433, 46161, 122277}},
+{11805, 17, 51707, {1, 3, 1, 3, 19, 1, 15, 71, 425, 459, 655, 2251, 5525, 7611, 5819, 1255, 43107}},
+{11806, 17, 51725, {1, 1, 5, 15, 3, 9, 83, 191, 439, 663, 399, 2263, 1857, 15421, 2079, 2381, 59193}},
+{11807, 17, 51737, {1, 3, 5, 5, 1, 7, 9, 77, 347, 419, 1329, 3173, 7295, 3631, 13435, 3217, 18053}},
+{11808, 17, 51753, {1, 3, 3, 7, 29, 39, 35, 71, 119, 745, 603, 2247, 377, 3297, 30983, 27857, 105739}},
+{11809, 17, 51754, {1, 1, 5, 13, 9, 59, 57, 239, 247, 921, 1383, 2315, 241, 4435, 24661, 6129, 122727}},
+{11810, 17, 51779, {1, 1, 5, 7, 3, 15, 39, 165, 27, 803, 609, 3081, 6009, 12665, 24155, 51647, 3857}},
+{11811, 17, 51791, {1, 3, 5, 11, 27, 41, 61, 255, 195, 169, 557, 1739, 4029, 1791, 471, 16321, 49801}},
+{11812, 17, 51796, {1, 3, 7, 13, 17, 45, 35, 177, 109, 113, 551, 219, 4065, 303, 15489, 25427, 12349}},
+{11813, 17, 51809, {1, 3, 5, 5, 25, 15, 79, 165, 231, 867, 483, 3563, 6611, 11277, 3193, 37455, 127373}},
+{11814, 17, 51816, {1, 3, 3, 11, 25, 21, 47, 255, 27, 543, 485, 2675, 5893, 3029, 3857, 50967, 14681}},
+{11815, 17, 51819, {1, 3, 7, 11, 3, 23, 81, 135, 77, 227, 417, 1733, 5175, 15295, 15985, 50329, 48641}},
+{11816, 17, 51827, {1, 3, 5, 1, 3, 47, 33, 67, 201, 235, 1299, 3703, 1959, 8091, 11115, 10869, 9595}},
+{11817, 17, 51829, {1, 3, 7, 13, 1, 45, 61, 49, 471, 923, 1827, 2175, 1433, 3473, 3781, 7923, 121525}},
+{11818, 17, 51834, {1, 3, 5, 7, 25, 59, 113, 19, 415, 839, 167, 3549, 7435, 6573, 767, 2751, 18383}},
+{11819, 17, 51836, {1, 3, 3, 1, 5, 11, 125, 241, 395, 423, 955, 2551, 963, 8197, 30253, 10473, 28505}},
+{11820, 17, 51846, {1, 1, 1, 3, 5, 31, 69, 103, 153, 505, 1507, 2827, 165, 4943, 8343, 54253, 87593}},
+{11821, 17, 51849, {1, 3, 3, 1, 7, 37, 27, 75, 251, 623, 965, 1907, 6063, 761, 765, 10103, 43479}},
+{11822, 17, 51855, {1, 1, 1, 13, 7, 21, 53, 219, 267, 57, 959, 579, 2951, 13797, 3249, 29895, 47467}},
+{11823, 17, 51858, {1, 1, 5, 9, 13, 7, 85, 107, 3, 635, 1235, 1339, 3263, 3895, 25911, 7521, 34149}},
+{11824, 17, 51869, {1, 1, 5, 15, 29, 37, 73, 43, 413, 993, 499, 719, 1557, 14397, 11245, 58197, 127901}},
+{11825, 17, 51870, {1, 1, 5, 15, 9, 37, 87, 57, 63, 337, 927, 1887, 6407, 11237, 23233, 53567, 120449}},
+{11826, 17, 51874, {1, 1, 3, 7, 27, 11, 85, 227, 159, 849, 647, 1977, 4623, 7343, 8089, 4251, 26609}},
+{11827, 17, 51918, {1, 1, 5, 11, 11, 3, 105, 191, 189, 627, 367, 3935, 6647, 13069, 26195, 23137, 56427}},
+{11828, 17, 51926, {1, 1, 3, 3, 29, 51, 39, 3, 437, 1011, 1061, 1747, 3051, 11165, 8155, 9723, 41035}},
+{11829, 17, 51932, {1, 3, 7, 15, 9, 43, 79, 195, 265, 395, 1349, 337, 911, 15767, 3593, 42859, 70181}},
+{11830, 17, 51936, {1, 3, 7, 7, 11, 47, 11, 85, 489, 801, 1177, 3861, 3517, 9209, 27505, 12291, 35691}},
+{11831, 17, 51948, {1, 1, 3, 9, 15, 61, 71, 123, 287, 419, 1079, 3489, 3519, 12739, 21341, 24323, 33961}},
+{11832, 17, 51954, {1, 3, 7, 3, 9, 17, 119, 137, 389, 391, 601, 1875, 2197, 5271, 13289, 43597, 43279}},
+{11833, 17, 51959, {1, 3, 7, 15, 29, 35, 41, 171, 183, 701, 1673, 981, 5479, 21, 11353, 64953, 88189}},
+{11834, 17, 51971, {1, 3, 3, 13, 15, 35, 35, 81, 297, 245, 475, 393, 5401, 12369, 21129, 65213, 125013}},
+{11835, 17, 51983, {1, 1, 7, 13, 15, 57, 25, 143, 389, 111, 1219, 2195, 769, 9005, 10367, 39435, 3631}},
+{11836, 17, 51992, {1, 3, 3, 13, 9, 29, 9, 47, 127, 377, 1195, 1221, 5751, 15481, 10537, 29909, 112691}},
+{11837, 17, 51997, {1, 1, 3, 5, 17, 47, 29, 1, 299, 651, 1023, 1601, 5917, 3781, 18421, 42393, 51789}},
+{11838, 17, 52016, {1, 3, 3, 15, 31, 51, 101, 147, 367, 159, 359, 705, 3773, 8649, 31373, 5733, 58287}},
+{11839, 17, 52021, {1, 3, 5, 11, 11, 51, 55, 79, 147, 917, 1945, 1725, 289, 12777, 30099, 3013, 91527}},
+{11840, 17, 52031, {1, 1, 7, 13, 1, 51, 33, 27, 169, 573, 117, 2479, 761, 1283, 32723, 13589, 88821}},
+{11841, 17, 52033, {1, 1, 1, 3, 23, 13, 33, 207, 137, 391, 1309, 4093, 6889, 827, 9331, 57113, 110193}},
+{11842, 17, 52034, {1, 1, 1, 13, 15, 57, 115, 53, 59, 443, 1, 3545, 6923, 6603, 8631, 41703, 8519}},
+{11843, 17, 52048, {1, 1, 5, 5, 25, 29, 53, 153, 107, 423, 1829, 2469, 1843, 889, 31727, 20701, 6343}},
+{11844, 17, 52053, {1, 1, 7, 13, 11, 41, 7, 219, 77, 663, 329, 2639, 1111, 1293, 16771, 20731, 46973}},
+{11845, 17, 52057, {1, 3, 3, 15, 23, 19, 45, 107, 111, 155, 1595, 1821, 471, 6089, 21587, 49259, 85393}},
+{11846, 17, 52067, {1, 3, 1, 3, 27, 21, 39, 227, 359, 885, 449, 2615, 3519, 5377, 16017, 57159, 82399}},
+{11847, 17, 52076, {1, 3, 3, 15, 31, 33, 77, 33, 87, 821, 701, 2859, 1777, 3007, 16757, 5447, 3557}},
+{11848, 17, 52079, {1, 1, 1, 15, 11, 31, 127, 79, 363, 341, 169, 3451, 6351, 6867, 13511, 833, 103151}},
+{11849, 17, 52081, {1, 3, 5, 7, 27, 23, 5, 67, 159, 535, 103, 843, 8187, 6891, 19169, 22565, 95255}},
+{11850, 17, 52109, {1, 3, 5, 5, 15, 27, 53, 49, 343, 815, 1203, 1031, 6359, 1337, 1629, 47783, 103391}},
+{11851, 17, 52127, {1, 3, 1, 1, 13, 19, 51, 185, 45, 549, 619, 2247, 2541, 10421, 31507, 60785, 87139}},
+{11852, 17, 52128, {1, 3, 1, 15, 29, 9, 47, 127, 41, 767, 1375, 2183, 7169, 12855, 15021, 377, 69327}},
+{11853, 17, 52133, {1, 1, 3, 9, 5, 23, 23, 203, 101, 809, 1155, 2885, 3901, 3081, 1827, 65373, 106133}},
+{11854, 17, 52148, {1, 3, 3, 13, 3, 21, 73, 135, 353, 905, 1757, 1361, 3801, 15541, 2261, 17159, 18037}},
+{11855, 17, 52155, {1, 1, 7, 7, 27, 23, 57, 33, 225, 407, 1709, 1159, 6353, 13341, 15883, 17339, 50423}},
+{11856, 17, 52157, {1, 1, 3, 15, 13, 21, 33, 91, 183, 975, 1623, 3187, 5495, 8947, 7031, 19687, 104483}},
+{11857, 17, 52172, {1, 3, 5, 7, 17, 25, 77, 1, 335, 85, 1783, 2617, 4463, 3807, 12883, 24487, 66205}},
+{11858, 17, 52178, {1, 1, 3, 15, 23, 37, 83, 93, 211, 757, 903, 2681, 49, 435, 21057, 63635, 36489}},
+{11859, 17, 52184, {1, 3, 1, 13, 3, 45, 63, 57, 65, 21, 627, 1467, 51, 15887, 27465, 59227, 108233}},
+{11860, 17, 52199, {1, 1, 7, 5, 15, 41, 53, 57, 301, 677, 803, 1675, 6937, 3159, 14281, 22355, 37783}},
+{11861, 17, 52200, {1, 1, 5, 13, 15, 43, 39, 245, 191, 875, 1505, 2085, 3903, 185, 24461, 28939, 98771}},
+{11862, 17, 52205, {1, 1, 7, 9, 17, 25, 29, 31, 439, 159, 533, 3177, 4155, 403, 23735, 61817, 121909}},
+{11863, 17, 52206, {1, 1, 3, 15, 29, 43, 111, 47, 483, 513, 63, 2423, 4979, 5159, 15499, 33391, 51575}},
+{11864, 17, 52232, {1, 1, 5, 15, 15, 43, 13, 41, 445, 929, 1365, 2023, 6173, 6067, 30969, 51457, 51179}},
+{11865, 17, 52237, {1, 3, 3, 11, 15, 17, 93, 235, 159, 599, 635, 1113, 1017, 7413, 7737, 20051, 79127}},
+{11866, 17, 52243, {1, 1, 1, 15, 5, 19, 81, 65, 479, 119, 1831, 2515, 2929, 15395, 31607, 29969, 49935}},
+{11867, 17, 52246, {1, 3, 1, 13, 23, 47, 45, 151, 51, 217, 803, 3265, 5907, 14371, 8287, 25659, 27655}},
+{11868, 17, 52252, {1, 1, 1, 13, 13, 53, 11, 63, 501, 487, 1683, 1147, 4693, 2761, 19359, 2215, 112393}},
+{11869, 17, 52261, {1, 3, 3, 1, 31, 15, 61, 237, 129, 119, 135, 39, 6509, 3753, 16997, 3841, 24521}},
+{11870, 17, 52265, {1, 3, 5, 7, 5, 27, 113, 251, 217, 923, 229, 2259, 5241, 6331, 6773, 41929, 89605}},
+{11871, 17, 52266, {1, 1, 5, 9, 17, 41, 21, 185, 95, 137, 1151, 195, 913, 531, 15731, 22893, 93521}},
+{11872, 17, 52273, {1, 1, 5, 1, 29, 57, 123, 11, 345, 581, 227, 1539, 7527, 8537, 16429, 8437, 18953}},
+{11873, 17, 52274, {1, 1, 3, 7, 7, 21, 103, 239, 115, 513, 1287, 3717, 331, 5453, 18943, 17247, 64975}},
+{11874, 17, 52288, {1, 3, 7, 11, 21, 37, 79, 83, 93, 155, 1297, 1371, 1109, 6569, 21137, 29237, 24007}},
+{11875, 17, 52300, {1, 1, 1, 13, 17, 11, 127, 89, 397, 497, 1017, 721, 2837, 5623, 31745, 52243, 107225}},
+{11876, 17, 52303, {1, 1, 7, 9, 15, 43, 29, 215, 449, 233, 313, 2587, 2903, 2735, 4539, 50481, 85279}},
+{11877, 17, 52321, {1, 1, 3, 15, 13, 35, 109, 211, 299, 255, 1595, 533, 1801, 13965, 25277, 52347, 13447}},
+{11878, 17, 52322, {1, 1, 1, 15, 9, 23, 115, 119, 207, 973, 1339, 1315, 6465, 9917, 4593, 65435, 2515}},
+{11879, 17, 52328, {1, 3, 3, 3, 7, 25, 115, 115, 213, 845, 1445, 1217, 1563, 12491, 5197, 44409, 79895}},
+{11880, 17, 52333, {1, 1, 1, 3, 9, 33, 31, 203, 19, 895, 1145, 2893, 4807, 7501, 6999, 54883, 13797}},
+{11881, 17, 52351, {1, 1, 3, 1, 19, 51, 73, 29, 451, 533, 83, 2477, 335, 9703, 9747, 57427, 69443}},
+{11882, 17, 52357, {1, 1, 7, 5, 21, 11, 53, 133, 165, 291, 591, 1419, 3661, 4697, 21363, 53467, 84063}},
+{11883, 17, 52372, {1, 1, 7, 3, 13, 7, 85, 49, 193, 289, 1531, 709, 2351, 12085, 28553, 57145, 129517}},
+{11884, 17, 52381, {1, 1, 1, 1, 17, 19, 13, 213, 75, 977, 811, 1813, 7293, 13795, 28569, 28133, 11949}},
+{11885, 17, 52386, {1, 1, 5, 1, 27, 11, 47, 89, 271, 65, 1651, 2331, 3289, 6227, 15027, 19959, 22945}},
+{11886, 17, 52395, {1, 3, 7, 9, 17, 37, 17, 245, 249, 501, 405, 951, 3005, 9757, 10265, 35575, 70529}},
+{11887, 17, 52403, {1, 3, 1, 15, 21, 47, 15, 75, 113, 45, 125, 1393, 3361, 13477, 24325, 39743, 67409}},
+{11888, 17, 52423, {1, 3, 5, 1, 13, 3, 33, 51, 463, 241, 1421, 1607, 3937, 3405, 26653, 33955, 97915}},
+{11889, 17, 52427, {1, 3, 7, 13, 29, 17, 41, 193, 461, 787, 459, 4019, 1887, 13831, 9387, 25215, 69801}},
+{11890, 17, 52432, {1, 3, 1, 11, 31, 55, 13, 235, 85, 953, 109, 233, 1893, 13225, 26165, 59237, 15845}},
+{11891, 17, 52438, {1, 1, 1, 13, 11, 43, 127, 193, 143, 831, 875, 2471, 7011, 3063, 21979, 42113, 80581}},
+{11892, 17, 52444, {1, 3, 7, 1, 5, 1, 63, 55, 349, 525, 441, 2695, 3301, 15737, 13355, 16727, 25001}},
+{11893, 17, 52457, {1, 3, 7, 7, 31, 23, 87, 99, 331, 101, 1341, 3, 1447, 9507, 18627, 2503, 57597}},
+{11894, 17, 52468, {1, 1, 1, 9, 11, 19, 89, 141, 269, 31, 1933, 429, 7765, 5905, 15327, 25913, 17281}},
+{11895, 17, 52480, {1, 3, 1, 9, 23, 61, 75, 15, 121, 635, 1409, 615, 7841, 11993, 1637, 26073, 70763}},
+{11896, 17, 52498, {1, 3, 3, 1, 5, 63, 85, 3, 443, 87, 1201, 275, 3457, 16187, 26839, 16593, 36335}},
+{11897, 17, 52516, {1, 1, 5, 5, 27, 61, 1, 145, 287, 563, 1135, 2703, 733, 10209, 3937, 23807, 56857}},
+{11898, 17, 52520, {1, 3, 3, 7, 1, 41, 97, 155, 305, 395, 1607, 1171, 1061, 12301, 8041, 12111, 66831}},
+{11899, 17, 52525, {1, 3, 7, 15, 9, 61, 127, 225, 125, 231, 87, 2433, 6951, 2999, 24859, 61685, 111943}},
+{11900, 17, 52531, {1, 3, 5, 15, 13, 39, 87, 57, 305, 469, 1929, 1559, 1383, 2779, 3883, 845, 45181}},
+{11901, 17, 52540, {1, 1, 1, 15, 19, 1, 23, 41, 207, 731, 501, 1147, 6543, 5011, 483, 56889, 48993}},
+{11902, 17, 52545, {1, 3, 3, 15, 21, 35, 75, 129, 441, 497, 953, 201, 6849, 2893, 6351, 62163, 84127}},
+{11903, 17, 52546, {1, 1, 1, 9, 21, 31, 91, 79, 345, 649, 1529, 805, 4931, 12887, 30167, 52305, 92561}},
+{11904, 17, 52552, {1, 1, 5, 1, 3, 21, 121, 223, 67, 185, 801, 889, 7443, 8419, 19929, 11451, 11487}},
+{11905, 17, 52557, {1, 1, 3, 15, 21, 51, 119, 31, 197, 773, 617, 2055, 799, 9105, 12353, 33635, 27589}},
+{11906, 17, 52569, {1, 3, 5, 3, 27, 11, 41, 105, 289, 877, 1175, 3111, 3161, 12537, 18001, 38061, 59089}},
+{11907, 17, 52575, {1, 3, 3, 5, 3, 27, 101, 253, 225, 915, 1757, 1601, 3391, 10443, 3983, 58427, 93391}},
+{11908, 17, 52582, {1, 3, 1, 7, 9, 43, 85, 115, 169, 285, 1267, 3791, 2701, 5599, 10099, 48105, 45219}},
+{11909, 17, 52594, {1, 1, 7, 13, 25, 57, 35, 223, 265, 451, 1913, 2715, 8017, 3725, 7079, 34611, 61159}},
+{11910, 17, 52615, {1, 1, 3, 7, 23, 27, 93, 195, 449, 845, 865, 655, 4263, 12743, 7467, 7929, 7095}},
+{11911, 17, 52619, {1, 3, 5, 5, 29, 51, 109, 123, 227, 693, 2033, 3829, 7187, 4027, 17861, 45093, 7355}},
+{11912, 17, 52624, {1, 1, 1, 11, 27, 31, 127, 75, 443, 479, 865, 1377, 711, 3791, 27235, 17405, 25975}},
+{11913, 17, 52645, {1, 3, 5, 7, 1, 49, 79, 167, 471, 453, 211, 265, 8163, 6517, 3413, 17283, 51961}},
+{11914, 17, 52663, {1, 3, 1, 5, 17, 29, 15, 239, 385, 239, 425, 2197, 3553, 14913, 14889, 31645, 67477}},
+{11915, 17, 52664, {1, 3, 3, 5, 1, 11, 25, 105, 367, 253, 1395, 2077, 2613, 4535, 18215, 37657, 48283}},
+{11916, 17, 52675, {1, 3, 3, 1, 1, 41, 7, 161, 437, 659, 833, 3175, 2063, 14497, 6655, 8817, 127321}},
+{11917, 17, 52687, {1, 3, 1, 11, 17, 27, 3, 51, 75, 183, 1889, 287, 5429, 14007, 14445, 47395, 94543}},
+{11918, 17, 52696, {1, 1, 7, 13, 29, 9, 109, 19, 73, 3, 1529, 457, 6413, 4113, 14733, 24455, 44623}},
+{11919, 17, 52701, {1, 3, 1, 15, 15, 31, 83, 25, 263, 229, 1801, 377, 1703, 8571, 10393, 52021, 100937}},
+{11920, 17, 52706, {1, 3, 5, 9, 25, 57, 79, 19, 117, 437, 275, 3439, 6393, 2111, 8317, 3521, 96927}},
+{11921, 17, 52708, {1, 3, 1, 13, 27, 43, 103, 171, 361, 949, 347, 809, 5819, 2763, 10447, 35129, 46985}},
+{11922, 17, 52711, {1, 3, 5, 11, 17, 1, 27, 37, 473, 851, 1057, 831, 4373, 5179, 18193, 48731, 64317}},
+{11923, 17, 52726, {1, 3, 1, 7, 17, 5, 19, 217, 439, 549, 1983, 2473, 6059, 5271, 10279, 7793, 114357}},
+{11924, 17, 52748, {1, 3, 1, 5, 25, 19, 99, 65, 507, 527, 825, 2517, 2299, 1725, 9913, 5779, 12207}},
+{11925, 17, 52754, {1, 3, 1, 1, 29, 41, 119, 27, 411, 475, 461, 1885, 2339, 4945, 24665, 13621, 78129}},
+{11926, 17, 52756, {1, 3, 1, 11, 27, 29, 119, 155, 487, 29, 1545, 675, 1417, 6119, 12451, 21345, 39377}},
+{11927, 17, 52759, {1, 1, 3, 7, 19, 5, 111, 227, 49, 307, 549, 737, 4793, 13885, 22971, 18653, 69573}},
+{11928, 17, 52769, {1, 3, 3, 1, 27, 59, 87, 7, 379, 497, 903, 591, 6105, 1957, 25849, 55957, 120181}},
+{11929, 17, 52784, {1, 3, 5, 15, 19, 31, 43, 1, 35, 341, 311, 1343, 3625, 16181, 31047, 59679, 89231}},
+{11930, 17, 52790, {1, 1, 1, 15, 21, 19, 93, 229, 49, 597, 1465, 2027, 5935, 12269, 20239, 17861, 26311}},
+{11931, 17, 52804, {1, 1, 1, 1, 3, 31, 115, 87, 129, 419, 871, 2469, 3807, 4473, 25025, 36923, 67959}},
+{11932, 17, 52807, {1, 1, 1, 3, 23, 31, 41, 247, 295, 369, 1131, 2183, 8097, 7609, 4387, 37565, 50177}},
+{11933, 17, 52808, {1, 3, 1, 11, 9, 17, 111, 249, 417, 775, 217, 1435, 6295, 5065, 2967, 55361, 91933}},
+{11934, 17, 52819, {1, 3, 5, 7, 19, 21, 71, 219, 411, 31, 335, 2915, 3687, 5691, 12405, 34659, 76721}},
+{11935, 17, 52826, {1, 3, 5, 13, 29, 31, 95, 203, 149, 399, 547, 2529, 2485, 3371, 20219, 33647, 34217}},
+{11936, 17, 52828, {1, 3, 5, 13, 31, 41, 97, 115, 427, 35, 1319, 2335, 715, 2541, 4507, 49395, 33895}},
+{11937, 17, 52832, {1, 3, 7, 15, 3, 49, 3, 49, 153, 93, 1343, 1035, 5685, 15855, 15751, 27663, 99553}},
+{11938, 17, 52835, {1, 1, 7, 5, 27, 7, 53, 135, 453, 981, 1767, 3503, 1259, 11973, 23259, 41051, 96593}},
+{11939, 17, 52849, {1, 1, 7, 9, 5, 59, 57, 141, 41, 639, 1681, 145, 7019, 6621, 14221, 12051, 71871}},
+{11940, 17, 52859, {1, 1, 3, 1, 13, 39, 7, 187, 7, 919, 1555, 2111, 6507, 2099, 10643, 22851, 82033}},
+{11941, 17, 52877, {1, 3, 7, 9, 25, 59, 27, 225, 239, 715, 1115, 2309, 7785, 11849, 8991, 54305, 107305}},
+{11942, 17, 52880, {1, 1, 7, 11, 21, 51, 1, 223, 481, 195, 2005, 2651, 6797, 12201, 11013, 1843, 65167}},
+{11943, 17, 52896, {1, 3, 3, 11, 27, 3, 117, 5, 255, 595, 399, 1329, 1437, 12061, 32679, 16655, 76235}},
+{11944, 17, 52899, {1, 1, 7, 13, 21, 1, 35, 159, 329, 37, 1247, 2663, 3889, 14603, 25799, 45363, 87963}},
+{11945, 17, 52905, {1, 1, 7, 7, 7, 11, 53, 215, 351, 329, 1039, 969, 4449, 14785, 28617, 25953, 78663}},
+{11946, 17, 52913, {1, 1, 7, 7, 27, 17, 19, 223, 143, 433, 789, 1941, 5527, 711, 25097, 4571, 121975}},
+{11947, 17, 52933, {1, 3, 1, 13, 11, 47, 31, 249, 325, 1003, 509, 2741, 3953, 1691, 12661, 16097, 80211}},
+{11948, 17, 52934, {1, 3, 7, 9, 27, 11, 21, 129, 25, 57, 1523, 3631, 2639, 2541, 14249, 34539, 70551}},
+{11949, 17, 52938, {1, 1, 5, 3, 31, 47, 47, 73, 71, 783, 1353, 2157, 2563, 14015, 997, 31611, 118649}},
+{11950, 17, 52957, {1, 1, 5, 5, 25, 35, 25, 207, 349, 503, 121, 3455, 5783, 10899, 12745, 35117, 36679}},
+{11951, 17, 52979, {1, 3, 1, 3, 11, 39, 123, 177, 19, 441, 1979, 1257, 1351, 4253, 15145, 44559, 59379}},
+{11952, 17, 52981, {1, 3, 7, 3, 7, 35, 41, 203, 439, 1013, 1055, 1165, 1043, 11183, 1795, 31253, 113693}},
+{11953, 17, 52986, {1, 3, 1, 13, 7, 43, 57, 1, 229, 345, 631, 841, 7923, 5971, 20489, 47917, 66833}},
+{11954, 17, 53005, {1, 1, 1, 15, 27, 5, 31, 117, 153, 755, 1207, 619, 8185, 4329, 9979, 57255, 79045}},
+{11955, 17, 53008, {1, 3, 3, 7, 23, 1, 7, 227, 337, 417, 1895, 765, 7799, 13599, 27253, 4485, 112391}},
+{11956, 17, 53024, {1, 3, 5, 13, 27, 63, 5, 87, 101, 351, 953, 2235, 1587, 5479, 26529, 34165, 83303}},
+{11957, 17, 53029, {1, 1, 5, 15, 1, 43, 63, 193, 143, 711, 1779, 3531, 1355, 16253, 14595, 32343, 131021}},
+{11958, 17, 53054, {1, 1, 1, 9, 29, 37, 29, 71, 11, 877, 1301, 2415, 5593, 1855, 25223, 6805, 12901}},
+{11959, 17, 53073, {1, 1, 7, 9, 31, 5, 49, 63, 185, 373, 129, 1695, 7841, 4477, 17809, 42771, 120221}},
+{11960, 17, 53083, {1, 1, 5, 3, 15, 43, 49, 45, 47, 775, 699, 2787, 7831, 4189, 18317, 63933, 83669}},
+{11961, 17, 53086, {1, 3, 5, 3, 23, 33, 85, 255, 119, 685, 1245, 1647, 1999, 13063, 9241, 49017, 32619}},
+{11962, 17, 53095, {1, 1, 7, 15, 29, 15, 125, 233, 189, 411, 1251, 3459, 7213, 10081, 4403, 56819, 17103}},
+{11963, 17, 53102, {1, 3, 3, 11, 21, 13, 93, 125, 213, 793, 1057, 2363, 661, 12213, 2259, 3787, 91451}},
+{11964, 17, 53107, {1, 3, 5, 5, 19, 35, 5, 153, 507, 691, 1743, 1777, 7579, 14229, 10155, 18529, 35945}},
+{11965, 17, 53126, {1, 3, 7, 5, 27, 35, 13, 77, 189, 793, 877, 643, 2787, 5817, 22589, 58363, 49059}},
+{11966, 17, 53130, {1, 3, 7, 9, 9, 37, 21, 251, 119, 895, 1023, 91, 4317, 10943, 7355, 36961, 36903}},
+{11967, 17, 53138, {1, 3, 3, 13, 19, 49, 15, 105, 399, 29, 1903, 3503, 3453, 15429, 31503, 57815, 34009}},
+{11968, 17, 53144, {1, 1, 5, 1, 19, 35, 49, 97, 335, 665, 1871, 887, 4713, 517, 9571, 41601, 9673}},
+{11969, 17, 53156, {1, 3, 5, 13, 29, 45, 111, 233, 251, 407, 1135, 2791, 6525, 11633, 22295, 65381, 117511}},
+{11970, 17, 53163, {1, 1, 3, 3, 17, 7, 65, 43, 391, 91, 315, 3559, 479, 7337, 25629, 785, 19855}},
+{11971, 17, 53165, {1, 1, 5, 9, 29, 31, 67, 17, 381, 875, 1001, 415, 2263, 4415, 11263, 309, 117623}},
+{11972, 17, 53173, {1, 1, 7, 11, 25, 1, 59, 61, 247, 649, 687, 907, 1037, 13935, 7229, 39769, 92755}},
+{11973, 17, 53177, {1, 3, 5, 15, 21, 51, 27, 79, 343, 785, 1567, 1349, 7991, 8531, 11243, 61351, 21297}},
+{11974, 17, 53183, {1, 1, 1, 3, 31, 41, 67, 169, 83, 959, 813, 1953, 2467, 12369, 31431, 50761, 75731}},
+{11975, 17, 53192, {1, 1, 5, 11, 25, 37, 83, 163, 3, 161, 1249, 3009, 7167, 5473, 10561, 44899, 130879}},
+{11976, 17, 53195, {1, 1, 7, 11, 9, 61, 61, 113, 81, 205, 731, 3887, 5525, 13415, 25181, 11557, 59343}},
+{11977, 17, 53200, {1, 3, 7, 5, 19, 27, 107, 89, 295, 715, 1439, 1285, 5813, 8895, 7233, 32905, 3273}},
+{11978, 17, 53212, {1, 1, 5, 1, 29, 11, 125, 253, 445, 295, 1721, 1271, 2203, 2215, 7613, 55655, 112157}},
+{11979, 17, 53219, {1, 1, 5, 11, 11, 13, 111, 55, 19, 551, 1365, 477, 2513, 12311, 22485, 23291, 92447}},
+{11980, 17, 53221, {1, 1, 7, 11, 9, 5, 3, 109, 507, 441, 1767, 1781, 3077, 219, 29293, 21237, 71159}},
+{11981, 17, 53245, {1, 1, 3, 11, 3, 45, 99, 113, 367, 569, 1907, 1281, 51, 13693, 14639, 32999, 77461}},
+{11982, 17, 53254, {1, 3, 5, 11, 5, 19, 97, 11, 473, 937, 1623, 1507, 3245, 9331, 16005, 37505, 40085}},
+{11983, 17, 53257, {1, 1, 7, 13, 21, 61, 103, 111, 35, 141, 61, 1043, 1989, 1311, 29021, 2617, 89915}},
+{11984, 17, 53265, {1, 3, 7, 15, 19, 31, 39, 175, 371, 459, 1293, 1645, 1125, 1199, 4811, 55721, 76071}},
+{11985, 17, 53266, {1, 1, 7, 3, 3, 35, 17, 7, 91, 317, 1615, 3559, 191, 2579, 15027, 58711, 36009}},
+{11986, 17, 53268, {1, 1, 1, 13, 1, 27, 45, 87, 443, 443, 853, 3917, 1437, 4053, 14861, 2897, 109853}},
+{11987, 17, 53275, {1, 1, 5, 3, 21, 47, 73, 195, 115, 517, 1781, 2341, 805, 5679, 12053, 29113, 100479}},
+{11988, 17, 53277, {1, 1, 7, 1, 25, 27, 61, 167, 203, 57, 527, 1071, 7131, 8403, 9943, 11503, 33081}},
+{11989, 17, 53284, {1, 1, 5, 13, 31, 43, 35, 195, 177, 229, 1401, 4011, 2363, 15787, 21125, 32103, 62337}},
+{11990, 17, 53294, {1, 1, 5, 11, 19, 13, 3, 249, 119, 35, 747, 1419, 5451, 13043, 19813, 54859, 94825}},
+{11991, 17, 53308, {1, 3, 1, 9, 17, 13, 51, 125, 391, 157, 1199, 1805, 1763, 11831, 20915, 38547, 14221}},
+{11992, 17, 53314, {1, 1, 7, 1, 23, 61, 25, 69, 435, 183, 1379, 1211, 5529, 9447, 4575, 14127, 91867}},
+{11993, 17, 53319, {1, 3, 3, 15, 11, 15, 101, 135, 419, 685, 1097, 787, 2045, 3393, 26221, 23653, 116917}},
+{11994, 17, 53326, {1, 3, 1, 11, 29, 23, 13, 153, 27, 683, 1569, 413, 261, 10291, 23763, 15579, 39337}},
+{11995, 17, 53328, {1, 3, 7, 7, 19, 23, 121, 23, 339, 165, 1137, 2791, 319, 16111, 14847, 28171, 79237}},
+{11996, 17, 53340, {1, 3, 1, 5, 9, 59, 33, 19, 191, 707, 1883, 1683, 1161, 12905, 12299, 22201, 19811}},
+{11997, 17, 53364, {1, 3, 1, 3, 27, 11, 69, 199, 415, 251, 1079, 1709, 4539, 7867, 21321, 33617, 53459}},
+{11998, 17, 53367, {1, 1, 3, 9, 19, 59, 21, 95, 275, 213, 1819, 721, 6271, 11845, 9573, 16105, 12755}},
+{11999, 17, 53377, {1, 1, 1, 15, 23, 7, 91, 235, 43, 95, 913, 715, 3229, 12339, 23089, 30963, 129525}},
+{12000, 17, 53395, {1, 1, 7, 9, 7, 41, 43, 131, 485, 621, 1293, 1955, 5215, 6545, 29225, 53587, 46901}},
+{12001, 17, 53398, {1, 3, 1, 5, 7, 57, 97, 199, 225, 707, 1223, 1829, 497, 12587, 24551, 12907, 82411}},
+{12002, 17, 53407, {1, 1, 3, 7, 21, 9, 63, 15, 263, 957, 155, 4021, 4455, 2025, 16981, 19743, 88619}},
+{12003, 17, 53413, {1, 1, 7, 5, 31, 3, 27, 45, 369, 747, 1559, 1429, 8049, 15069, 19897, 50067, 52861}},
+{12004, 17, 53414, {1, 1, 5, 13, 23, 35, 91, 139, 73, 275, 207, 2709, 3801, 12755, 19155, 61629, 5513}},
+{12005, 17, 53417, {1, 1, 5, 7, 5, 25, 33, 45, 325, 847, 81, 891, 3191, 14115, 25095, 39867, 3839}},
+{12006, 17, 53443, {1, 3, 5, 13, 9, 31, 31, 113, 507, 833, 691, 2041, 4873, 81, 21365, 35265, 37627}},
+{12007, 17, 53473, {1, 1, 5, 13, 9, 51, 127, 131, 285, 683, 593, 3411, 6685, 3601, 12255, 8337, 80597}},
+{12008, 17, 53476, {1, 1, 5, 15, 29, 13, 79, 199, 157, 421, 1697, 2063, 2213, 4141, 21045, 45785, 124023}},
+{12009, 17, 53480, {1, 3, 1, 11, 19, 5, 79, 57, 71, 373, 487, 671, 3671, 9093, 20989, 48477, 104951}},
+{12010, 17, 53486, {1, 3, 5, 15, 13, 7, 39, 243, 507, 739, 1905, 3431, 4141, 9345, 27877, 64735, 112997}},
+{12011, 17, 53506, {1, 3, 3, 5, 17, 25, 31, 243, 393, 61, 199, 2825, 6981, 5887, 22289, 9201, 77689}},
+{12012, 17, 53542, {1, 3, 5, 15, 15, 63, 77, 39, 463, 883, 671, 3285, 6925, 15085, 1665, 64005, 130619}},
+{12013, 17, 53546, {1, 3, 3, 11, 21, 15, 7, 115, 9, 879, 1097, 3993, 3929, 9809, 22105, 9549, 31819}},
+{12014, 17, 53554, {1, 1, 7, 15, 3, 9, 19, 97, 327, 105, 1915, 205, 3873, 1229, 29915, 57375, 108217}},
+{12015, 17, 53563, {1, 1, 3, 11, 29, 41, 77, 11, 183, 73, 1651, 3739, 3911, 8695, 15339, 19293, 1827}},
+{12016, 17, 53580, {1, 1, 1, 5, 23, 49, 35, 175, 99, 49, 615, 1733, 6901, 2351, 18765, 55553, 99791}},
+{12017, 17, 53591, {1, 3, 7, 3, 25, 17, 67, 161, 507, 941, 35, 2619, 339, 791, 6485, 64277, 123867}},
+{12018, 17, 53598, {1, 1, 3, 13, 11, 9, 79, 193, 75, 391, 1753, 3537, 6971, 6607, 11933, 4447, 87793}},
+{12019, 17, 53611, {1, 1, 1, 5, 19, 9, 63, 203, 51, 395, 1365, 2393, 7265, 11709, 13721, 4519, 118765}},
+{12020, 17, 53621, {1, 1, 3, 9, 17, 53, 29, 103, 325, 973, 903, 785, 7535, 9951, 8121, 12603, 38679}},
+{12021, 17, 53625, {1, 3, 1, 7, 7, 63, 1, 123, 439, 181, 1373, 2705, 995, 10789, 7495, 54543, 120109}},
+{12022, 17, 53628, {1, 1, 7, 3, 17, 13, 79, 179, 165, 965, 1537, 3753, 3497, 12127, 6983, 48605, 113057}},
+{12023, 17, 53632, {1, 1, 5, 7, 3, 7, 41, 25, 267, 633, 19, 1317, 3445, 12377, 27881, 55249, 40841}},
+{12024, 17, 53650, {1, 3, 5, 1, 31, 55, 43, 129, 411, 281, 1, 851, 2419, 7943, 13721, 39371, 114557}},
+{12025, 17, 53655, {1, 1, 7, 7, 23, 19, 83, 37, 9, 161, 125, 3179, 7973, 9703, 23199, 32723, 130915}},
+{12026, 17, 53675, {1, 1, 7, 5, 27, 21, 11, 219, 403, 239, 1723, 2957, 3029, 9911, 10981, 35421, 74025}},
+{12027, 17, 53677, {1, 3, 1, 1, 31, 59, 69, 77, 395, 1, 157, 1259, 4913, 2089, 17619, 51033, 130899}},
+{12028, 17, 53680, {1, 3, 3, 3, 19, 11, 83, 237, 103, 921, 487, 1833, 8187, 3811, 18887, 9389, 80927}},
+{12029, 17, 53683, {1, 3, 7, 3, 17, 51, 107, 209, 187, 831, 1501, 1337, 803, 10361, 11347, 65291, 42219}},
+{12030, 17, 53700, {1, 3, 3, 15, 7, 29, 61, 25, 413, 257, 1185, 4009, 7463, 1839, 6645, 28389, 14449}},
+{12031, 17, 53709, {1, 3, 1, 9, 5, 31, 83, 55, 375, 399, 945, 997, 7649, 12631, 7691, 53325, 50173}},
+{12032, 17, 53724, {1, 1, 5, 9, 13, 9, 83, 37, 487, 975, 487, 3587, 7285, 7505, 10155, 673, 126505}},
+{12033, 17, 53731, {1, 3, 5, 7, 21, 3, 35, 21, 367, 323, 1579, 3351, 5465, 13719, 17033, 42573, 55079}},
+{12034, 17, 53733, {1, 3, 3, 15, 11, 27, 121, 109, 267, 855, 1417, 3839, 6535, 1051, 29355, 23815, 76031}},
+{12035, 17, 53738, {1, 1, 7, 9, 5, 31, 35, 53, 369, 137, 1545, 927, 825, 1333, 13637, 11003, 96963}},
+{12036, 17, 53762, {1, 1, 5, 3, 29, 41, 31, 85, 35, 477, 227, 3325, 1213, 681, 14591, 31325, 12199}},
+{12037, 17, 53767, {1, 3, 7, 11, 11, 11, 33, 255, 335, 747, 855, 31, 6101, 293, 20423, 47521, 62573}},
+{12038, 17, 53785, {1, 1, 1, 15, 31, 15, 33, 175, 321, 441, 1197, 3579, 4989, 9275, 30485, 1077, 122947}},
+{12039, 17, 53786, {1, 3, 5, 15, 23, 21, 127, 223, 249, 373, 1309, 1469, 5701, 9097, 29897, 26627, 38489}},
+{12040, 17, 53795, {1, 3, 7, 3, 3, 35, 83, 149, 259, 315, 1467, 1953, 6035, 7961, 10901, 25171, 130713}},
+{12041, 17, 53802, {1, 1, 3, 9, 7, 63, 55, 33, 375, 421, 151, 1721, 1999, 14937, 17539, 48323, 97345}},
+{12042, 17, 53812, {1, 1, 5, 5, 3, 21, 47, 19, 227, 131, 1591, 3779, 929, 13879, 13489, 19805, 20135}},
+{12043, 17, 53821, {1, 1, 7, 1, 31, 25, 87, 125, 213, 135, 809, 3067, 5035, 7407, 2193, 31423, 123973}},
+{12044, 17, 53827, {1, 3, 5, 13, 17, 19, 77, 169, 345, 115, 227, 649, 3609, 15063, 1895, 17533, 95859}},
+{12045, 17, 53833, {1, 3, 5, 15, 17, 29, 17, 11, 145, 601, 1871, 851, 8161, 14029, 10039, 4247, 62393}},
+{12046, 17, 53841, {1, 1, 7, 13, 25, 5, 49, 231, 261, 71, 335, 4081, 7915, 11367, 17087, 26041, 128737}},
+{12047, 17, 53848, {1, 1, 1, 13, 13, 21, 77, 113, 373, 1005, 109, 2877, 3001, 15011, 2465, 37015, 69049}},
+{12048, 17, 53869, {1, 1, 3, 15, 31, 33, 119, 121, 41, 9, 1567, 577, 1687, 12117, 17049, 675, 10729}},
+{12049, 17, 53897, {1, 3, 5, 11, 31, 7, 47, 41, 127, 81, 273, 1649, 975, 3953, 17021, 24163, 12599}},
+{12050, 17, 53905, {1, 3, 1, 3, 27, 41, 75, 237, 317, 85, 1995, 2255, 2191, 6441, 26629, 25797, 97681}},
+{12051, 17, 53912, {1, 1, 1, 3, 11, 5, 31, 109, 227, 977, 59, 793, 3305, 10905, 16529, 21345, 2403}},
+{12052, 17, 53921, {1, 3, 5, 9, 9, 37, 107, 129, 421, 383, 1415, 885, 3383, 9547, 7303, 41745, 59919}},
+{12053, 17, 53928, {1, 1, 7, 7, 29, 27, 59, 177, 97, 299, 1019, 1393, 7763, 5715, 9253, 58035, 23431}},
+{12054, 17, 53948, {1, 3, 3, 3, 23, 13, 51, 101, 75, 857, 1699, 2687, 3983, 10427, 19845, 49503, 96033}},
+{12055, 17, 53954, {1, 1, 1, 7, 21, 51, 25, 71, 265, 999, 1259, 625, 775, 11045, 20769, 42597, 115521}},
+{12056, 17, 53968, {1, 3, 1, 13, 25, 47, 21, 245, 201, 667, 1193, 1087, 407, 6057, 14929, 35291, 57615}},
+{12057, 17, 53977, {1, 1, 1, 7, 27, 25, 93, 85, 321, 1009, 1045, 1901, 349, 11393, 10917, 10413, 94125}},
+{12058, 17, 53983, {1, 1, 1, 15, 3, 63, 59, 51, 307, 135, 785, 1921, 6921, 5689, 8487, 21061, 69903}},
+{12059, 17, 53984, {1, 3, 7, 1, 13, 47, 59, 155, 107, 573, 843, 2849, 6685, 5927, 31747, 21541, 94271}},
+{12060, 17, 54002, {1, 1, 7, 15, 23, 7, 85, 169, 209, 527, 1027, 3745, 4773, 14893, 10789, 1243, 87133}},
+{12061, 17, 54007, {1, 1, 5, 9, 1, 1, 53, 57, 245, 899, 1785, 1951, 7651, 10909, 30167, 40789, 66965}},
+{12062, 17, 54013, {1, 1, 1, 7, 17, 33, 65, 79, 455, 677, 157, 1313, 1573, 9697, 4161, 4609, 42783}},
+{12063, 17, 54014, {1, 3, 7, 7, 27, 15, 109, 113, 239, 521, 563, 2493, 1471, 15817, 14515, 48465, 66009}},
+{12064, 17, 54021, {1, 3, 5, 3, 29, 33, 125, 169, 483, 593, 1665, 657, 3799, 15829, 29591, 25813, 40987}},
+{12065, 17, 54026, {1, 3, 1, 11, 15, 25, 21, 215, 341, 241, 1599, 3807, 6633, 15137, 15377, 56881, 47499}},
+{12066, 17, 54028, {1, 3, 3, 3, 15, 49, 89, 117, 191, 641, 675, 2671, 4243, 1617, 20261, 42669, 119173}},
+{12067, 17, 54031, {1, 1, 1, 13, 13, 43, 73, 103, 183, 239, 555, 2121, 4889, 1431, 20601, 21545, 11809}},
+{12068, 17, 54036, {1, 3, 1, 9, 9, 9, 121, 51, 77, 455, 1481, 427, 1961, 12149, 21273, 16295, 21909}},
+{12069, 17, 54067, {1, 1, 5, 11, 19, 55, 37, 63, 493, 663, 945, 2191, 2491, 11545, 7407, 36295, 94293}},
+{12070, 17, 54069, {1, 3, 5, 15, 25, 35, 103, 33, 171, 425, 409, 5, 2519, 2239, 30557, 20007, 69079}},
+{12071, 17, 54074, {1, 1, 5, 11, 13, 29, 71, 21, 35, 833, 191, 365, 7013, 12413, 10227, 56705, 61705}},
+{12072, 17, 54076, {1, 1, 1, 1, 21, 13, 87, 113, 63, 537, 283, 925, 2147, 1683, 31239, 2775, 131021}},
+{12073, 17, 54105, {1, 1, 3, 9, 23, 1, 117, 19, 487, 235, 877, 149, 369, 9615, 12501, 60175, 35741}},
+{12074, 17, 54111, {1, 1, 7, 9, 5, 25, 107, 199, 339, 755, 245, 2861, 1119, 14683, 2221, 5227, 81479}},
+{12075, 17, 54118, {1, 1, 1, 15, 5, 15, 37, 63, 511, 219, 783, 3245, 5563, 13231, 22311, 16803, 10393}},
+{12076, 17, 54129, {1, 3, 7, 5, 1, 15, 9, 21, 287, 991, 555, 771, 7683, 1661, 6553, 43735, 118713}},
+{12077, 17, 54145, {1, 3, 1, 3, 3, 29, 119, 157, 13, 599, 537, 2921, 5207, 11621, 1515, 6351, 118429}},
+{12078, 17, 54157, {1, 1, 5, 1, 27, 39, 111, 117, 481, 25, 549, 913, 6427, 7703, 23099, 50501, 7617}},
+{12079, 17, 54158, {1, 1, 7, 5, 29, 63, 43, 151, 63, 43, 197, 3165, 3879, 12435, 461, 64475, 60597}},
+{12080, 17, 54163, {1, 3, 1, 11, 31, 35, 59, 207, 387, 441, 1293, 2117, 3751, 12653, 2811, 42585, 33297}},
+{12081, 17, 54166, {1, 3, 7, 15, 27, 47, 13, 15, 135, 433, 615, 1, 171, 11503, 27117, 64635, 122191}},
+{12082, 17, 54172, {1, 1, 7, 1, 23, 23, 107, 135, 311, 395, 373, 2771, 81, 12513, 16739, 6715, 94999}},
+{12083, 17, 54185, {1, 3, 5, 7, 19, 9, 21, 139, 307, 231, 65, 59, 7767, 2897, 3503, 58163, 48807}},
+{12084, 17, 54186, {1, 3, 5, 13, 23, 5, 51, 247, 125, 911, 1395, 1337, 3215, 15811, 12729, 21495, 22597}},
+{12085, 17, 54188, {1, 3, 5, 5, 1, 19, 123, 125, 197, 533, 1699, 1397, 3473, 15201, 24493, 3395, 98261}},
+{12086, 17, 54208, {1, 1, 3, 7, 29, 39, 69, 97, 353, 293, 1103, 543, 5015, 9913, 6965, 61921, 122073}},
+{12087, 17, 54223, {1, 1, 3, 13, 19, 41, 117, 253, 449, 231, 865, 3055, 4751, 3277, 22863, 3249, 38359}},
+{12088, 17, 54237, {1, 3, 5, 13, 9, 7, 107, 17, 251, 501, 1925, 3733, 5035, 13213, 12535, 13705, 73047}},
+{12089, 17, 54241, {1, 3, 7, 5, 23, 5, 83, 45, 457, 667, 913, 1167, 7063, 10915, 10911, 20501, 61823}},
+{12090, 17, 54244, {1, 3, 3, 13, 7, 15, 29, 223, 503, 713, 667, 3989, 5927, 5909, 27633, 17615, 97931}},
+{12091, 17, 54259, {1, 3, 7, 13, 19, 53, 25, 41, 311, 327, 1323, 3361, 1095, 12701, 1065, 34155, 34705}},
+{12092, 17, 54273, {1, 1, 7, 7, 11, 35, 63, 73, 179, 477, 467, 4043, 3097, 16089, 12749, 18233, 50299}},
+{12093, 17, 54276, {1, 3, 3, 13, 5, 27, 31, 207, 357, 469, 607, 961, 7393, 6707, 25833, 22337, 119083}},
+{12094, 17, 54280, {1, 1, 3, 3, 7, 53, 47, 55, 267, 107, 1307, 2151, 793, 15605, 12153, 13075, 76529}},
+{12095, 17, 54294, {1, 3, 5, 1, 13, 35, 63, 191, 375, 221, 1603, 2049, 5363, 1481, 32271, 22635, 118603}},
+{12096, 17, 54298, {1, 1, 1, 11, 17, 63, 13, 3, 353, 943, 443, 141, 7441, 12335, 4499, 15923, 63677}},
+{12097, 17, 54303, {1, 3, 7, 13, 21, 51, 125, 61, 203, 1, 707, 3893, 4627, 3125, 14629, 62721, 85101}},
+{12098, 17, 54304, {1, 1, 3, 5, 31, 23, 63, 241, 41, 721, 599, 1761, 2593, 1685, 31247, 7811, 87561}},
+{12099, 17, 54309, {1, 1, 7, 9, 7, 53, 51, 9, 303, 675, 1261, 1591, 4363, 15, 29723, 54533, 103869}},
+{12100, 17, 54310, {1, 3, 5, 7, 27, 21, 103, 113, 463, 379, 635, 2363, 607, 11445, 22475, 58433, 93071}},
+{12101, 17, 54316, {1, 1, 5, 5, 5, 63, 23, 67, 399, 279, 829, 945, 6545, 14951, 5135, 22889, 87625}},
+{12102, 17, 54336, {1, 1, 7, 15, 1, 59, 69, 123, 169, 821, 1125, 2051, 3375, 11691, 1379, 57461, 124209}},
+{12103, 17, 54354, {1, 1, 5, 15, 31, 57, 51, 59, 297, 459, 701, 241, 2801, 11893, 4007, 13165, 79403}},
+{12104, 17, 54359, {1, 1, 5, 9, 11, 41, 79, 47, 19, 529, 21, 1871, 371, 6269, 7433, 36183, 96113}},
+{12105, 17, 54375, {1, 1, 7, 5, 29, 3, 33, 191, 119, 501, 1637, 2903, 3347, 4581, 17407, 18169, 10595}},
+{12106, 17, 54376, {1, 3, 5, 11, 9, 35, 95, 193, 413, 727, 1157, 3331, 5993, 1781, 22653, 3975, 110557}},
+{12107, 17, 54381, {1, 1, 1, 1, 23, 5, 35, 65, 57, 515, 569, 4031, 7983, 4603, 29419, 44847, 63601}},
+{12108, 17, 54390, {1, 3, 1, 7, 21, 5, 77, 23, 317, 803, 723, 3229, 7171, 2883, 10943, 50323, 108579}},
+{12109, 17, 54396, {1, 3, 5, 11, 15, 53, 75, 127, 177, 19, 501, 1201, 5113, 9069, 8817, 14725, 104737}},
+{12110, 17, 54399, {1, 3, 7, 9, 7, 39, 5, 121, 409, 103, 1075, 451, 7603, 16023, 32557, 43159, 94385}},
+{12111, 17, 54409, {1, 3, 1, 11, 29, 57, 123, 141, 57, 945, 1777, 2427, 2359, 12839, 7325, 7945, 129811}},
+{12112, 17, 54424, {1, 3, 5, 15, 5, 3, 17, 55, 467, 61, 131, 2891, 6331, 5859, 20437, 49425, 80731}},
+{12113, 17, 54434, {1, 1, 1, 15, 29, 13, 127, 181, 361, 1019, 1675, 2755, 6533, 8957, 14691, 4285, 65459}},
+{12114, 17, 54436, {1, 1, 7, 11, 23, 43, 111, 183, 103, 269, 229, 3291, 1873, 11349, 29319, 64829, 19639}},
+{12115, 17, 54439, {1, 3, 7, 11, 15, 63, 1, 253, 489, 863, 1707, 2769, 3201, 7901, 18161, 12515, 130237}},
+{12116, 17, 54445, {1, 3, 1, 7, 1, 25, 43, 159, 505, 511, 1745, 1421, 6779, 11103, 23535, 61129, 124571}},
+{12117, 17, 54448, {1, 1, 3, 13, 19, 33, 17, 243, 481, 617, 1061, 1891, 7165, 6821, 18505, 8965, 70179}},
+{12118, 17, 54457, {1, 1, 7, 13, 17, 17, 65, 23, 255, 361, 1873, 1605, 2041, 11119, 11419, 63131, 49207}},
+{12119, 17, 54465, {1, 1, 5, 13, 15, 57, 27, 223, 199, 529, 1115, 1513, 8083, 11713, 21005, 50741, 122223}},
+{12120, 17, 54471, {1, 3, 5, 15, 29, 35, 107, 85, 141, 505, 1553, 1283, 4581, 5077, 9461, 59853, 23219}},
+{12121, 17, 54472, {1, 3, 5, 11, 11, 45, 53, 195, 199, 773, 1911, 721, 1563, 3769, 3267, 30673, 80313}},
+{12122, 17, 54485, {1, 3, 7, 7, 21, 37, 9, 129, 431, 79, 1559, 2125, 7781, 6441, 23533, 46919, 25315}},
+{12123, 17, 54508, {1, 1, 5, 15, 11, 61, 77, 231, 349, 647, 225, 85, 6789, 12557, 6505, 21985, 54965}},
+{12124, 17, 54513, {1, 1, 5, 1, 19, 21, 33, 211, 347, 491, 1119, 1619, 3739, 11255, 26705, 59691, 35337}},
+{12125, 17, 54528, {1, 1, 3, 3, 29, 15, 7, 23, 279, 145, 699, 289, 475, 1681, 3201, 64477, 24919}},
+{12126, 17, 54534, {1, 1, 7, 7, 23, 53, 75, 71, 315, 403, 1521, 1417, 3749, 11243, 3951, 61039, 51143}},
+{12127, 17, 54537, {1, 3, 7, 3, 15, 21, 81, 219, 249, 387, 1405, 3495, 7143, 2599, 25435, 15259, 66069}},
+{12128, 17, 54540, {1, 1, 5, 7, 31, 9, 63, 55, 409, 421, 1851, 847, 1593, 10447, 2833, 13209, 47285}},
+{12129, 17, 54551, {1, 1, 3, 7, 15, 3, 35, 49, 253, 21, 1705, 357, 2751, 9671, 12429, 4549, 118691}},
+{12130, 17, 54561, {1, 1, 5, 15, 1, 3, 97, 197, 43, 923, 1273, 663, 4291, 12357, 28221, 15291, 60989}},
+{12131, 17, 54573, {1, 1, 7, 7, 15, 3, 35, 115, 449, 641, 743, 1855, 359, 10983, 2831, 43983, 56465}},
+{12132, 17, 54579, {1, 3, 7, 11, 1, 51, 69, 27, 29, 187, 1673, 1273, 7987, 1223, 8971, 53805, 4413}},
+{12133, 17, 54586, {1, 1, 3, 11, 1, 55, 91, 241, 35, 97, 1027, 3967, 703, 3535, 21681, 55825, 50423}},
+{12134, 17, 54591, {1, 1, 7, 11, 21, 53, 111, 125, 11, 355, 1585, 3603, 1705, 16311, 7045, 15503, 63625}},
+{12135, 17, 54596, {1, 1, 5, 15, 25, 47, 31, 29, 333, 361, 1831, 1545, 7751, 8679, 32453, 61755, 94637}},
+{12136, 17, 54599, {1, 1, 3, 3, 23, 3, 79, 11, 367, 551, 281, 1273, 5097, 12527, 473, 33855, 85783}},
+{12137, 17, 54605, {1, 1, 1, 15, 27, 21, 107, 121, 187, 495, 1877, 1957, 3647, 13263, 30729, 18131, 33689}},
+{12138, 17, 54613, {1, 1, 5, 13, 3, 43, 41, 53, 127, 299, 839, 3327, 7929, 9921, 29471, 18075, 34283}},
+{12139, 17, 54623, {1, 1, 7, 13, 31, 5, 59, 75, 335, 929, 379, 139, 7121, 9281, 31161, 3177, 2615}},
+{12140, 17, 54654, {1, 3, 7, 1, 11, 19, 81, 199, 425, 639, 497, 693, 1271, 7363, 10543, 52513, 130549}},
+{12141, 17, 54667, {1, 3, 3, 7, 21, 41, 101, 67, 363, 5, 1455, 1433, 81, 15609, 16231, 13285, 38995}},
+{12142, 17, 54681, {1, 1, 3, 15, 11, 19, 123, 177, 429, 27, 141, 3095, 5379, 2241, 29877, 59383, 25199}},
+{12143, 17, 54684, {1, 1, 7, 7, 19, 63, 93, 217, 279, 349, 149, 2479, 2355, 6475, 29993, 37941, 58715}},
+{12144, 17, 54687, {1, 3, 7, 3, 21, 23, 59, 177, 489, 817, 1209, 1629, 5805, 3137, 23767, 62967, 16609}},
+{12145, 17, 54694, {1, 3, 3, 7, 9, 55, 59, 31, 191, 891, 833, 1059, 3007, 2331, 385, 58247, 110697}},
+{12146, 17, 54706, {1, 1, 3, 3, 11, 61, 9, 189, 79, 621, 209, 2785, 2959, 4133, 20691, 45605, 117089}},
+{12147, 17, 54712, {1, 3, 3, 5, 5, 47, 31, 1, 451, 765, 2027, 2327, 1725, 14341, 7997, 6449, 77893}},
+{12148, 17, 54715, {1, 1, 7, 1, 7, 27, 27, 129, 227, 505, 1461, 783, 945, 12653, 17913, 61631, 41875}},
+{12149, 17, 54723, {1, 1, 1, 11, 13, 41, 41, 221, 483, 825, 451, 493, 1717, 10389, 7805, 37707, 30733}},
+{12150, 17, 54725, {1, 1, 5, 3, 31, 31, 75, 3, 323, 83, 563, 919, 7387, 1673, 6157, 7415, 14947}},
+{12151, 17, 54726, {1, 1, 7, 13, 19, 37, 29, 93, 153, 491, 1033, 1389, 6361, 11133, 20049, 24585, 107325}},
+{12152, 17, 54740, {1, 1, 1, 15, 3, 35, 79, 251, 383, 665, 2033, 3165, 3411, 15965, 28281, 56521, 56479}},
+{12153, 17, 54750, {1, 3, 1, 15, 23, 1, 87, 145, 443, 405, 635, 1597, 1455, 5983, 12741, 55133, 2815}},
+{12154, 17, 54760, {1, 1, 1, 13, 11, 25, 19, 129, 23, 913, 1121, 223, 1991, 13449, 30443, 50573, 108467}},
+{12155, 17, 54768, {1, 1, 7, 11, 29, 31, 49, 51, 415, 293, 173, 4091, 159, 2679, 30643, 58725, 109287}},
+{12156, 17, 54771, {1, 1, 1, 7, 15, 53, 69, 231, 387, 693, 1299, 1383, 7935, 10313, 22403, 59341, 3347}},
+{12157, 17, 54773, {1, 3, 3, 5, 9, 21, 111, 11, 469, 109, 1565, 3107, 2975, 12491, 26773, 33245, 27589}},
+{12158, 17, 54796, {1, 1, 3, 5, 3, 9, 103, 127, 345, 301, 857, 2035, 3269, 13819, 7555, 5197, 94557}},
+{12159, 17, 54801, {1, 3, 7, 3, 31, 3, 61, 253, 221, 359, 1281, 1405, 4819, 1329, 17773, 29539, 127043}},
+{12160, 17, 54808, {1, 1, 7, 11, 17, 47, 105, 253, 253, 531, 119, 2009, 6125, 9387, 13141, 29079, 28361}},
+{12161, 17, 54814, {1, 1, 3, 5, 21, 13, 21, 223, 79, 819, 1425, 1001, 6517, 8883, 29997, 30637, 7717}},
+{12162, 17, 54837, {1, 3, 1, 3, 1, 23, 113, 69, 235, 95, 1873, 689, 4611, 13209, 12681, 16057, 114071}},
+{12163, 17, 54847, {1, 3, 3, 13, 25, 21, 93, 55, 253, 373, 1659, 829, 6539, 7453, 28195, 33131, 92559}},
+{12164, 17, 54849, {1, 1, 3, 11, 25, 29, 81, 235, 429, 811, 1867, 2923, 5949, 4423, 93, 64631, 48357}},
+{12165, 17, 54864, {1, 3, 5, 13, 29, 27, 35, 15, 105, 849, 247, 3999, 6441, 12443, 19817, 49897, 21515}},
+{12166, 17, 54867, {1, 1, 5, 15, 13, 59, 3, 199, 267, 463, 655, 3875, 2895, 13411, 5081, 22069, 6053}},
+{12167, 17, 54889, {1, 1, 5, 9, 5, 13, 111, 83, 281, 543, 629, 1349, 1863, 9523, 19201, 39229, 78265}},
+{12168, 17, 54895, {1, 3, 7, 1, 29, 23, 109, 75, 347, 643, 97, 1981, 2797, 11201, 28355, 54105, 45551}},
+{12169, 17, 54907, {1, 3, 1, 7, 9, 5, 77, 17, 179, 957, 621, 779, 7117, 1491, 11563, 10131, 98335}},
+{12170, 17, 54919, {1, 3, 3, 1, 3, 53, 39, 217, 309, 105, 485, 3123, 3143, 2359, 4923, 22307, 120319}},
+{12171, 17, 54923, {1, 1, 7, 7, 11, 5, 65, 165, 321, 455, 625, 2417, 999, 14999, 6777, 13319, 43399}},
+{12172, 17, 54926, {1, 1, 7, 3, 11, 55, 43, 119, 135, 129, 581, 3593, 3475, 14667, 30509, 5007, 120135}},
+{12173, 17, 54940, {1, 1, 1, 11, 7, 17, 95, 169, 401, 87, 1425, 1821, 7619, 3605, 10993, 35837, 87311}},
+{12174, 17, 54950, {1, 1, 7, 11, 11, 35, 29, 63, 395, 301, 373, 2457, 6859, 1915, 11215, 41075, 78219}},
+{12175, 17, 54954, {1, 3, 5, 7, 25, 3, 97, 43, 273, 459, 103, 3441, 71, 10269, 29893, 46053, 104801}},
+{12176, 17, 54961, {1, 3, 3, 7, 31, 3, 121, 255, 73, 783, 977, 513, 6527, 1189, 8925, 23245, 22287}},
+{12177, 17, 54973, {1, 3, 3, 13, 15, 53, 51, 135, 465, 341, 263, 1687, 4085, 14257, 18745, 46945, 115475}},
+{12178, 17, 54974, {1, 3, 1, 5, 31, 1, 1, 91, 511, 771, 1501, 2613, 991, 3859, 28911, 65417, 201}},
+{12179, 17, 54976, {1, 1, 7, 1, 27, 21, 107, 153, 163, 949, 811, 3087, 3443, 5621, 28795, 58311, 63763}},
+{12180, 17, 54986, {1, 1, 7, 5, 29, 29, 57, 175, 29, 821, 1545, 2643, 725, 16225, 29111, 19675, 129995}},
+{12181, 17, 54993, {1, 1, 7, 3, 31, 31, 61, 155, 265, 323, 1829, 3891, 6393, 8573, 10627, 10839, 78683}},
+{12182, 17, 55000, {1, 3, 5, 7, 29, 7, 67, 181, 313, 731, 1761, 1681, 3673, 8939, 811, 48931, 82021}},
+{12183, 17, 55010, {1, 3, 1, 3, 11, 51, 81, 67, 173, 881, 855, 3627, 1613, 4825, 7035, 36261, 64899}},
+{12184, 17, 55019, {1, 3, 7, 7, 15, 53, 123, 41, 265, 817, 807, 3875, 7675, 16225, 13313, 62217, 47647}},
+{12185, 17, 55021, {1, 1, 3, 13, 23, 47, 125, 155, 403, 651, 1693, 2185, 5565, 9947, 20893, 11287, 118943}},
+{12186, 17, 55030, {1, 3, 7, 3, 19, 47, 69, 5, 209, 259, 367, 3929, 7579, 12687, 18109, 51885, 128281}},
+{12187, 17, 55033, {1, 1, 7, 5, 27, 41, 45, 41, 205, 1001, 1509, 2649, 1141, 5355, 10265, 34131, 112111}},
+{12188, 17, 55039, {1, 3, 7, 5, 19, 41, 103, 63, 49, 25, 271, 793, 3217, 4741, 2563, 61333, 113205}},
+{12189, 17, 55047, {1, 3, 3, 15, 15, 35, 13, 233, 277, 673, 545, 545, 7419, 6707, 1867, 58873, 110027}},
+{12190, 17, 55048, {1, 1, 7, 3, 9, 23, 67, 55, 3, 1019, 2001, 2909, 7311, 9295, 26953, 43217, 54597}},
+{12191, 17, 55054, {1, 3, 5, 7, 13, 33, 67, 27, 75, 569, 1777, 791, 1223, 1805, 19167, 60537, 60039}},
+{12192, 17, 55059, {1, 1, 5, 13, 15, 61, 49, 59, 289, 907, 1055, 3579, 8169, 12119, 25479, 32867, 65343}},
+{12193, 17, 55068, {1, 3, 5, 9, 5, 63, 91, 225, 377, 469, 891, 891, 5115, 11487, 30151, 44357, 120077}},
+{12194, 17, 55071, {1, 1, 1, 15, 29, 59, 19, 51, 295, 585, 149, 497, 5837, 11629, 7825, 18129, 113797}},
+{12195, 17, 55075, {1, 1, 3, 7, 31, 25, 77, 209, 183, 337, 1753, 2703, 2559, 11847, 17349, 27359, 21771}},
+{12196, 17, 55077, {1, 1, 7, 7, 13, 23, 69, 61, 353, 339, 833, 1935, 4333, 10521, 20331, 62145, 59245}},
+{12197, 17, 55081, {1, 1, 5, 13, 19, 57, 35, 59, 203, 99, 487, 2747, 637, 8213, 27053, 29, 64335}},
+{12198, 17, 55095, {1, 3, 5, 7, 27, 5, 71, 147, 339, 313, 913, 2845, 5713, 4383, 18969, 54871, 51931}},
+{12199, 17, 55099, {1, 1, 1, 5, 7, 23, 19, 11, 111, 543, 311, 1519, 387, 10175, 18209, 14115, 123421}},
+{12200, 17, 55110, {1, 3, 7, 11, 7, 7, 123, 193, 417, 65, 1317, 3821, 2315, 14527, 14113, 25873, 23977}},
+{12201, 17, 55116, {1, 1, 3, 15, 21, 11, 3, 37, 115, 395, 877, 1227, 6997, 4357, 11397, 52855, 24899}},
+{12202, 17, 55122, {1, 1, 7, 5, 15, 45, 45, 17, 441, 605, 429, 739, 4759, 5249, 11311, 55049, 56909}},
+{12203, 17, 55134, {1, 1, 1, 5, 3, 5, 77, 31, 407, 703, 385, 235, 7751, 617, 16013, 27269, 66971}},
+{12204, 17, 55144, {1, 3, 3, 15, 25, 27, 19, 251, 465, 197, 1039, 3261, 4557, 4821, 16083, 43997, 61371}},
+{12205, 17, 55147, {1, 3, 3, 15, 21, 45, 13, 139, 213, 797, 619, 2125, 3805, 4149, 11427, 59807, 104587}},
+{12206, 17, 55158, {1, 3, 1, 1, 29, 27, 25, 7, 371, 535, 1613, 1083, 4221, 8913, 10601, 6447, 17619}},
+{12207, 17, 55162, {1, 1, 3, 3, 13, 35, 37, 127, 285, 899, 307, 123, 129, 14035, 26503, 64103, 27155}},
+{12208, 17, 55171, {1, 1, 7, 7, 27, 25, 45, 245, 271, 281, 69, 3505, 7087, 1529, 7121, 30327, 89131}},
+{12209, 17, 55185, {1, 1, 3, 11, 13, 57, 31, 23, 455, 427, 1683, 3019, 5827, 8817, 12943, 321, 39951}},
+{12210, 17, 55192, {1, 3, 1, 3, 31, 41, 69, 211, 385, 275, 1569, 2265, 4017, 11057, 15, 16619, 126967}},
+{12211, 17, 55197, {1, 3, 3, 1, 27, 27, 21, 145, 125, 929, 1371, 1469, 1591, 5283, 4651, 1265, 17161}},
+{12212, 17, 55207, {1, 3, 7, 5, 29, 31, 41, 141, 49, 967, 1421, 663, 6089, 3831, 11353, 38809, 108605}},
+{12213, 17, 55228, {1, 1, 7, 15, 11, 23, 91, 31, 9, 717, 265, 1729, 3563, 8145, 20441, 22933, 103683}},
+{12214, 17, 55246, {1, 1, 7, 3, 17, 13, 47, 13, 241, 1017, 1803, 2091, 7379, 2941, 11783, 36189, 53513}},
+{12215, 17, 55253, {1, 3, 1, 11, 31, 63, 107, 79, 427, 385, 1497, 1265, 5135, 13597, 27343, 56733, 100595}},
+{12216, 17, 55254, {1, 3, 7, 3, 9, 15, 119, 29, 205, 151, 1453, 3575, 3627, 7815, 3553, 31457, 14267}},
+{12217, 17, 55281, {1, 3, 1, 7, 15, 21, 73, 47, 417, 29, 1231, 2477, 161, 15997, 4457, 3939, 43929}},
+{12218, 17, 55300, {1, 1, 5, 5, 19, 49, 103, 251, 359, 69, 669, 299, 8161, 10579, 13999, 26859, 92199}},
+{12219, 17, 55303, {1, 1, 3, 1, 9, 27, 81, 7, 115, 29, 1067, 1933, 3061, 2885, 27883, 65227, 59365}},
+{12220, 17, 55307, {1, 1, 1, 5, 23, 17, 1, 113, 495, 155, 1673, 3945, 8053, 7935, 3537, 65141, 11809}},
+{12221, 17, 55312, {1, 1, 1, 15, 15, 59, 61, 213, 303, 851, 1893, 615, 6659, 9351, 16621, 6097, 114383}},
+{12222, 17, 55328, {1, 3, 1, 7, 19, 11, 95, 127, 277, 677, 1631, 2563, 3295, 7029, 4059, 44079, 128857}},
+{12223, 17, 55331, {1, 3, 7, 11, 27, 49, 99, 43, 279, 771, 123, 2969, 699, 12915, 22039, 62257, 79359}},
+{12224, 17, 55337, {1, 1, 7, 3, 19, 45, 45, 113, 251, 883, 715, 1541, 1573, 3345, 23855, 62681, 57591}},
+{12225, 17, 55348, {1, 1, 5, 15, 11, 1, 51, 15, 135, 519, 961, 1447, 4425, 2139, 3309, 35111, 74143}},
+{12226, 17, 55352, {1, 3, 7, 7, 17, 39, 109, 25, 11, 549, 315, 2175, 685, 11837, 9151, 6277, 45011}},
+{12227, 17, 55357, {1, 1, 1, 9, 27, 7, 95, 1, 385, 167, 453, 1027, 4105, 16351, 19, 10375, 62833}},
+{12228, 17, 55372, {1, 3, 7, 13, 17, 19, 107, 11, 441, 171, 185, 3567, 1245, 12161, 30257, 48105, 87105}},
+{12229, 17, 55375, {1, 3, 3, 9, 15, 5, 109, 225, 85, 919, 513, 3559, 5411, 9009, 27391, 25115, 84875}},
+{12230, 17, 55377, {1, 3, 3, 7, 11, 37, 81, 51, 121, 25, 1897, 2121, 6425, 16087, 4259, 29501, 118067}},
+{12231, 17, 55394, {1, 1, 7, 3, 5, 53, 73, 127, 137, 739, 543, 1723, 1163, 2791, 18519, 1459, 50869}},
+{12232, 17, 55406, {1, 1, 3, 11, 29, 51, 101, 189, 193, 839, 25, 3109, 3035, 3917, 23929, 38577, 129705}},
+{12233, 17, 55424, {1, 3, 7, 15, 9, 29, 93, 101, 271, 791, 1257, 1843, 2701, 8205, 15195, 9109, 120835}},
+{12234, 17, 55429, {1, 3, 3, 5, 29, 47, 31, 135, 483, 385, 1395, 2955, 7291, 12885, 9491, 14581, 66293}},
+{12235, 17, 55430, {1, 1, 7, 1, 5, 37, 105, 149, 63, 617, 1611, 3025, 3177, 15463, 3373, 3503, 95001}},
+{12236, 17, 55436, {1, 1, 5, 13, 1, 57, 19, 35, 127, 423, 1221, 1547, 4083, 347, 17131, 60087, 27437}},
+{12237, 17, 55439, {1, 3, 7, 9, 25, 1, 105, 39, 25, 921, 1897, 1729, 2207, 7761, 24197, 457, 64241}},
+{12238, 17, 55447, {1, 3, 7, 9, 15, 21, 13, 113, 379, 1021, 489, 1757, 5869, 4833, 24717, 52227, 3209}},
+{12239, 17, 55453, {1, 3, 1, 5, 9, 61, 25, 41, 183, 473, 383, 2259, 6939, 3, 32161, 6319, 93099}},
+{12240, 17, 55458, {1, 1, 5, 13, 13, 47, 97, 3, 357, 837, 1655, 485, 4251, 12153, 9013, 25121, 51877}},
+{12241, 17, 55460, {1, 1, 1, 15, 7, 59, 65, 119, 467, 313, 1333, 2007, 5165, 13935, 13679, 3999, 81811}},
+{12242, 17, 55478, {1, 1, 5, 13, 13, 1, 63, 117, 449, 13, 1017, 1583, 7599, 3669, 32699, 59455, 32363}},
+{12243, 17, 55489, {1, 1, 7, 9, 7, 15, 37, 251, 167, 25, 1085, 2067, 2771, 5737, 20661, 19231, 59547}},
+{12244, 17, 55501, {1, 1, 5, 13, 29, 11, 63, 37, 281, 657, 1567, 2879, 7601, 15617, 16527, 51695, 5583}},
+{12245, 17, 55502, {1, 1, 5, 3, 31, 17, 19, 65, 315, 413, 927, 3617, 4089, 11899, 3759, 47991, 1685}},
+{12246, 17, 55519, {1, 1, 1, 1, 13, 47, 89, 91, 379, 429, 283, 3765, 2923, 14955, 26399, 9579, 39817}},
+{12247, 17, 55525, {1, 1, 1, 9, 1, 17, 91, 119, 327, 291, 39, 2883, 6265, 553, 7559, 60577, 34393}},
+{12248, 17, 55530, {1, 3, 5, 5, 9, 33, 123, 219, 103, 529, 181, 1321, 6815, 2411, 10555, 43911, 18889}},
+{12249, 17, 55544, {1, 1, 5, 7, 9, 13, 7, 45, 427, 523, 1189, 255, 2103, 7217, 16249, 14631, 90409}},
+{12250, 17, 55550, {1, 1, 1, 9, 11, 35, 55, 71, 89, 637, 1417, 411, 5305, 10125, 20715, 62927, 4993}},
+{12251, 17, 55558, {1, 3, 1, 9, 1, 59, 27, 221, 267, 797, 1081, 951, 1369, 2677, 20763, 63301, 61963}},
+{12252, 17, 55561, {1, 3, 5, 5, 17, 9, 67, 177, 89, 953, 1329, 1649, 989, 7773, 28747, 26231, 42331}},
+{12253, 17, 55569, {1, 3, 3, 9, 23, 35, 17, 145, 53, 519, 1173, 2079, 2593, 3633, 32005, 30573, 55651}},
+{12254, 17, 55586, {1, 1, 7, 7, 17, 41, 47, 253, 107, 843, 9, 323, 2391, 3267, 25813, 1741, 93493}},
+{12255, 17, 55591, {1, 1, 1, 9, 31, 43, 47, 91, 235, 569, 2017, 2385, 5055, 5747, 26471, 48819, 47315}},
+{12256, 17, 55598, {1, 3, 5, 9, 1, 17, 87, 91, 55, 287, 995, 2577, 1151, 9119, 22791, 50899, 16423}},
+{12257, 17, 55605, {1, 3, 7, 1, 3, 29, 9, 193, 269, 201, 325, 2209, 1061, 7957, 23265, 65083, 27575}},
+{12258, 17, 55609, {1, 3, 7, 15, 27, 23, 37, 239, 165, 959, 1965, 2105, 1581, 6621, 17315, 49255, 62487}},
+{12259, 17, 55618, {1, 3, 7, 7, 11, 31, 73, 145, 429, 421, 571, 3375, 2797, 15889, 26523, 12315, 48061}},
+{12260, 17, 55630, {1, 3, 3, 15, 23, 27, 105, 75, 497, 137, 475, 1343, 537, 10499, 27807, 46623, 32435}},
+{12261, 17, 55642, {1, 1, 7, 15, 15, 11, 51, 107, 225, 557, 1461, 3447, 1243, 13827, 23675, 26139, 54603}},
+{12262, 17, 55644, {1, 3, 5, 5, 7, 25, 51, 3, 85, 371, 1503, 3217, 1779, 7141, 29471, 42247, 107699}},
+{12263, 17, 55653, {1, 3, 7, 15, 23, 53, 127, 229, 241, 165, 1985, 1921, 5917, 15743, 18349, 23981, 58241}},
+{12264, 17, 55654, {1, 1, 3, 13, 9, 63, 49, 67, 21, 57, 377, 1807, 5603, 13651, 28039, 3745, 4903}},
+{12265, 17, 55660, {1, 3, 7, 11, 1, 43, 17, 95, 79, 343, 1939, 2349, 5195, 3047, 4325, 27829, 53809}},
+{12266, 17, 55671, {1, 1, 5, 9, 7, 43, 111, 221, 493, 151, 1635, 3949, 6661, 4861, 17661, 61909, 4975}},
+{12267, 17, 55693, {1, 3, 1, 3, 31, 47, 63, 45, 401, 153, 1139, 2125, 6639, 14093, 31607, 20645, 52245}},
+{12268, 17, 55706, {1, 1, 3, 1, 19, 31, 59, 139, 285, 749, 751, 775, 7795, 14917, 30295, 61037, 12315}},
+{12269, 17, 55712, {1, 3, 3, 9, 15, 55, 79, 183, 373, 663, 497, 2589, 4955, 5409, 23527, 2683, 5487}},
+{12270, 17, 55718, {1, 3, 7, 11, 25, 47, 53, 225, 197, 109, 1937, 1375, 7347, 7353, 2335, 21775, 14877}},
+{12271, 17, 55739, {1, 3, 1, 9, 23, 61, 51, 221, 129, 57, 115, 1031, 6793, 14773, 3331, 24951, 94761}},
+{12272, 17, 55747, {1, 1, 5, 15, 31, 9, 69, 117, 295, 147, 673, 3627, 7167, 13835, 20593, 53163, 83033}},
+{12273, 17, 55754, {1, 3, 7, 9, 15, 63, 111, 225, 147, 863, 691, 629, 7485, 483, 21835, 46251, 94645}},
+{12274, 17, 55771, {1, 3, 3, 3, 11, 41, 23, 159, 133, 787, 1617, 629, 5047, 4465, 29051, 47499, 7211}},
+{12275, 17, 55774, {1, 1, 3, 13, 21, 61, 29, 159, 73, 165, 917, 2577, 7237, 11807, 3767, 56861, 51395}},
+{12276, 17, 55780, {1, 1, 5, 3, 15, 31, 37, 233, 283, 265, 1645, 3843, 1971, 4989, 26823, 15243, 74931}},
+{12277, 17, 55783, {1, 3, 7, 11, 9, 51, 7, 119, 237, 905, 1211, 3041, 7641, 3387, 8373, 38961, 68925}},
+{12278, 17, 55784, {1, 1, 7, 3, 17, 53, 55, 195, 57, 957, 2027, 3965, 2993, 411, 13947, 58349, 32169}},
+{12279, 17, 55789, {1, 1, 7, 9, 7, 37, 55, 93, 173, 769, 1381, 3977, 5293, 5051, 21455, 45547, 64653}},
+{12280, 17, 55798, {1, 3, 5, 7, 1, 41, 89, 161, 315, 361, 1675, 2993, 3281, 13043, 19003, 22129, 130379}},
+{12281, 17, 55802, {1, 3, 1, 9, 13, 37, 85, 197, 465, 177, 661, 943, 541, 11117, 9751, 4193, 98291}},
+{12282, 17, 55823, {1, 1, 3, 7, 21, 7, 67, 17, 41, 817, 1159, 1483, 6937, 10079, 3639, 27887, 14541}},
+{12283, 17, 55828, {1, 3, 3, 15, 17, 63, 69, 215, 437, 883, 1857, 3319, 3107, 16279, 10709, 30433, 52551}},
+{12284, 17, 55837, {1, 1, 3, 11, 1, 5, 69, 37, 419, 999, 1711, 875, 3807, 10811, 16345, 61155, 116043}},
+{12285, 17, 55838, {1, 3, 7, 13, 17, 7, 57, 237, 81, 691, 1143, 4075, 2481, 643, 8091, 8243, 80111}},
+{12286, 17, 55847, {1, 1, 7, 7, 17, 61, 73, 215, 113, 885, 159, 2243, 1177, 10981, 10123, 48995, 123349}},
+{12287, 17, 55848, {1, 1, 1, 7, 31, 47, 99, 15, 371, 343, 1483, 1985, 25, 11125, 8357, 10677, 130895}},
+{12288, 17, 55885, {1, 3, 1, 13, 25, 41, 83, 37, 129, 493, 641, 185, 6607, 7213, 13285, 10439, 73227}},
+{12289, 17, 55897, {1, 1, 5, 7, 17, 15, 93, 53, 281, 91, 115, 3675, 3081, 9825, 23653, 40095, 91803}},
+{12290, 17, 55904, {1, 1, 1, 5, 3, 25, 39, 207, 419, 361, 953, 2823, 8105, 15763, 29199, 61607, 32633}},
+{12291, 17, 55910, {1, 1, 3, 1, 31, 51, 55, 3, 277, 639, 191, 1783, 139, 29, 16659, 30199, 69109}},
+{12292, 17, 55919, {1, 1, 1, 7, 31, 59, 25, 13, 239, 617, 115, 1787, 5757, 9927, 2417, 37313, 115135}},
+{12293, 17, 55922, {1, 1, 3, 5, 19, 35, 5, 187, 483, 823, 1875, 163, 4235, 853, 23679, 50899, 94981}},
+{12294, 17, 55931, {1, 3, 3, 11, 9, 39, 121, 201, 189, 543, 1493, 1215, 351, 16063, 1701, 56559, 108053}},
+{12295, 17, 55933, {1, 3, 1, 7, 1, 39, 31, 163, 347, 307, 349, 4081, 1729, 16265, 363, 28297, 50631}},
+{12296, 17, 55937, {1, 3, 7, 13, 21, 55, 127, 161, 75, 9, 1285, 1839, 5283, 5667, 10979, 22185, 7581}},
+{12297, 17, 55943, {1, 1, 3, 5, 13, 45, 17, 181, 117, 395, 1685, 663, 3441, 5359, 7157, 27759, 102343}},
+{12298, 17, 55955, {1, 3, 1, 7, 7, 31, 97, 187, 383, 769, 1469, 4007, 5521, 13973, 49, 43823, 75649}},
+{12299, 17, 55957, {1, 3, 5, 7, 31, 13, 47, 11, 335, 961, 321, 3367, 1903, 503, 8409, 1101, 58215}},
+{12300, 17, 55968, {1, 1, 7, 7, 25, 49, 39, 1, 453, 419, 333, 1759, 2287, 6243, 10723, 13687, 56853}},
+{12301, 17, 55980, {1, 3, 3, 7, 11, 55, 125, 197, 19, 591, 1969, 511, 2501, 8429, 29467, 27917, 63457}},
+{12302, 17, 55986, {1, 1, 3, 11, 11, 43, 35, 213, 231, 119, 379, 3761, 4891, 5677, 20317, 5459, 55487}},
+{12303, 17, 55992, {1, 1, 5, 7, 21, 9, 127, 59, 97, 963, 847, 2131, 7907, 11409, 8785, 48197, 96907}},
+{12304, 17, 56005, {1, 3, 5, 3, 23, 7, 45, 95, 179, 691, 1571, 3091, 6359, 9105, 26021, 26925, 43}},
+{12305, 17, 56034, {1, 3, 3, 7, 21, 7, 11, 219, 439, 465, 1983, 117, 4639, 8387, 27637, 15883, 5567}},
+{12306, 17, 56051, {1, 1, 7, 3, 1, 3, 51, 205, 425, 133, 563, 1317, 533, 1227, 8361, 23407, 39825}},
+{12307, 17, 56054, {1, 1, 5, 3, 3, 39, 19, 69, 477, 605, 3, 1887, 2077, 13673, 2763, 64415, 104519}},
+{12308, 17, 56065, {1, 1, 5, 15, 11, 45, 89, 245, 177, 591, 1313, 587, 4781, 5103, 26401, 12643, 38959}},
+{12309, 17, 56080, {1, 1, 1, 5, 11, 13, 15, 95, 271, 99, 2001, 2701, 6065, 3527, 7423, 37525, 117161}},
+{12310, 17, 56101, {1, 3, 7, 7, 21, 17, 111, 149, 373, 591, 1461, 809, 3877, 8635, 13209, 31439, 64285}},
+{12311, 17, 56113, {1, 3, 1, 15, 25, 51, 55, 161, 357, 181, 41, 2345, 3553, 9917, 30123, 40683, 122497}},
+{12312, 17, 56126, {1, 3, 7, 15, 5, 55, 119, 239, 291, 665, 1537, 3309, 2519, 12397, 25897, 51529, 28673}},
+{12313, 17, 56131, {1, 1, 1, 9, 25, 45, 21, 119, 19, 145, 313, 2509, 1031, 3319, 14863, 10759, 22577}},
+{12314, 17, 56134, {1, 3, 1, 15, 1, 61, 87, 229, 511, 83, 79, 51, 1407, 16293, 26217, 25839, 86207}},
+{12315, 17, 56143, {1, 3, 7, 7, 23, 43, 89, 11, 43, 801, 569, 3273, 315, 9537, 681, 34783, 97101}},
+{12316, 17, 56148, {1, 1, 5, 1, 13, 31, 77, 115, 501, 669, 27, 3765, 6789, 9139, 30587, 45995, 102433}},
+{12317, 17, 56152, {1, 1, 7, 1, 15, 21, 57, 197, 243, 353, 71, 341, 7319, 8467, 9779, 15755, 4185}},
+{12318, 17, 56174, {1, 1, 1, 1, 17, 21, 3, 185, 277, 585, 265, 3189, 3975, 353, 8541, 23905, 21881}},
+{12319, 17, 56181, {1, 3, 5, 3, 5, 23, 113, 253, 343, 73, 1419, 2529, 4333, 2007, 14307, 60591, 55411}},
+{12320, 17, 56182, {1, 1, 7, 3, 25, 35, 109, 173, 351, 487, 1551, 3207, 1189, 5091, 3581, 4699, 22085}},
+{12321, 17, 56185, {1, 1, 3, 11, 9, 9, 71, 173, 17, 595, 2015, 2543, 4889, 6025, 15265, 6459, 3977}},
+{12322, 17, 56192, {1, 3, 5, 15, 11, 13, 11, 189, 431, 307, 317, 3131, 1421, 10863, 5311, 25273, 43187}},
+{12323, 17, 56201, {1, 1, 1, 7, 7, 41, 103, 231, 321, 327, 1849, 2485, 6461, 10259, 4577, 52951, 33053}},
+{12324, 17, 56215, {1, 3, 3, 15, 11, 33, 73, 155, 453, 597, 575, 2119, 327, 4227, 32271, 7429, 102007}},
+{12325, 17, 56219, {1, 1, 3, 7, 15, 9, 95, 177, 21, 245, 257, 3637, 821, 16351, 1733, 10635, 59885}},
+{12326, 17, 56222, {1, 1, 3, 7, 23, 41, 107, 147, 57, 877, 1609, 3275, 339, 12997, 5989, 62293, 21549}},
+{12327, 17, 56258, {1, 1, 7, 13, 19, 39, 111, 229, 321, 487, 873, 3365, 4915, 251, 30629, 45775, 73549}},
+{12328, 17, 56264, {1, 1, 1, 13, 25, 61, 43, 111, 135, 463, 1921, 1723, 7505, 13805, 30633, 51683, 7353}},
+{12329, 17, 56269, {1, 1, 1, 1, 31, 41, 35, 205, 375, 189, 635, 3589, 3507, 8131, 13437, 22823, 68451}},
+{12330, 17, 56272, {1, 3, 7, 5, 31, 47, 13, 229, 105, 195, 685, 529, 39, 2651, 6821, 11043, 112123}},
+{12331, 17, 56278, {1, 3, 7, 13, 3, 23, 21, 203, 89, 957, 1577, 1711, 585, 3937, 17681, 55577, 61075}},
+{12332, 17, 56282, {1, 3, 3, 3, 17, 37, 49, 7, 287, 183, 1185, 2979, 2103, 1217, 22105, 11677, 19603}},
+{12333, 17, 56306, {1, 1, 1, 9, 29, 35, 93, 179, 403, 563, 441, 3485, 6909, 12647, 3885, 60089, 29275}},
+{12334, 17, 56308, {1, 3, 3, 9, 15, 37, 49, 103, 509, 77, 495, 921, 2599, 14735, 30951, 22779, 47747}},
+{12335, 17, 56318, {1, 3, 3, 11, 17, 45, 43, 235, 379, 51, 925, 89, 2241, 10273, 27649, 8101, 93977}},
+{12336, 17, 56329, {1, 3, 3, 3, 11, 7, 25, 163, 405, 997, 847, 2743, 4705, 7041, 10997, 50189, 10775}},
+{12337, 17, 56356, {1, 1, 1, 13, 19, 43, 3, 125, 37, 41, 5, 965, 2681, 3737, 29057, 37777, 119537}},
+{12338, 17, 56360, {1, 1, 1, 1, 11, 27, 101, 67, 73, 199, 1739, 2835, 5837, 10595, 9865, 38493, 99323}},
+{12339, 17, 56383, {1, 3, 1, 13, 27, 43, 21, 79, 419, 847, 843, 2563, 8133, 10295, 10127, 30839, 104863}},
+{12340, 17, 56388, {1, 3, 3, 11, 15, 37, 71, 251, 157, 971, 165, 1647, 2583, 205, 23555, 55297, 106893}},
+{12341, 17, 56391, {1, 1, 5, 15, 1, 21, 113, 107, 287, 727, 71, 2655, 1435, 11125, 15257, 18899, 37737}},
+{12342, 17, 56405, {1, 1, 3, 3, 27, 49, 17, 85, 57, 237, 349, 4049, 1103, 2523, 3919, 36587, 128595}},
+{12343, 17, 56406, {1, 3, 5, 9, 13, 1, 65, 13, 361, 409, 413, 2153, 5953, 10651, 25383, 49777, 65399}},
+{12344, 17, 56416, {1, 1, 7, 9, 19, 47, 69, 127, 121, 925, 57, 2775, 4981, 3643, 4077, 3081, 56093}},
+{12345, 17, 56426, {1, 3, 3, 13, 1, 53, 45, 13, 489, 445, 623, 3547, 1659, 1899, 11971, 3725, 12445}},
+{12346, 17, 56439, {1, 3, 7, 11, 13, 9, 59, 157, 125, 975, 1283, 297, 3609, 3179, 31341, 54727, 112515}},
+{12347, 17, 56446, {1, 1, 1, 13, 23, 63, 69, 249, 159, 593, 47, 3957, 757, 14693, 26345, 18839, 111263}},
+{12348, 17, 56450, {1, 1, 1, 1, 31, 37, 37, 199, 7, 425, 337, 1475, 271, 16215, 12089, 16765, 13519}},
+{12349, 17, 56459, {1, 1, 7, 11, 31, 59, 121, 139, 413, 807, 737, 1235, 3505, 5859, 14205, 31939, 4713}},
+{12350, 17, 56461, {1, 1, 1, 9, 21, 51, 113, 159, 345, 807, 635, 523, 5535, 13307, 4239, 14847, 23711}},
+{12351, 17, 56464, {1, 3, 5, 13, 31, 7, 33, 1, 293, 271, 1829, 2535, 6333, 12037, 29401, 35009, 37789}},
+{12352, 17, 56469, {1, 1, 7, 3, 7, 57, 31, 45, 177, 475, 843, 1265, 585, 16099, 29293, 52407, 56131}},
+{12353, 17, 56489, {1, 3, 3, 11, 1, 25, 117, 205, 139, 141, 1229, 903, 1883, 11269, 30493, 3979, 4263}},
+{12354, 17, 56490, {1, 1, 5, 13, 25, 43, 9, 237, 347, 869, 1765, 1389, 1931, 13331, 17325, 45999, 121201}},
+{12355, 17, 56497, {1, 3, 3, 11, 3, 13, 95, 49, 389, 53, 491, 1467, 5105, 16053, 6305, 15759, 51991}},
+{12356, 17, 56509, {1, 3, 5, 15, 1, 53, 85, 69, 75, 409, 1299, 1245, 7951, 10709, 9157, 3509, 103975}},
+{12357, 17, 56515, {1, 1, 1, 13, 1, 33, 97, 235, 463, 413, 1759, 1891, 1781, 5261, 5759, 201, 69199}},
+{12358, 17, 56518, {1, 1, 3, 13, 21, 27, 101, 143, 123, 705, 969, 2461, 6057, 13091, 6077, 38311, 30379}},
+{12359, 17, 56524, {1, 3, 3, 1, 13, 11, 73, 33, 495, 513, 763, 3089, 421, 13663, 30169, 56599, 38847}},
+{12360, 17, 56535, {1, 1, 7, 13, 13, 31, 91, 63, 233, 137, 859, 2449, 539, 12461, 13477, 31605, 58919}},
+{12361, 17, 56542, {1, 1, 1, 9, 13, 49, 107, 45, 451, 707, 1735, 1881, 3451, 9131, 25481, 10841, 116067}},
+{12362, 17, 56545, {1, 3, 7, 1, 27, 21, 51, 117, 63, 53, 575, 3325, 1099, 11181, 23609, 47141, 115421}},
+{12363, 17, 56551, {1, 3, 1, 13, 25, 29, 53, 135, 165, 319, 1695, 341, 8157, 10671, 7095, 60749, 31513}},
+{12364, 17, 56555, {1, 1, 7, 5, 3, 53, 123, 137, 449, 87, 951, 693, 6943, 15331, 1515, 24019, 56613}},
+{12365, 17, 56560, {1, 3, 7, 5, 25, 17, 43, 251, 301, 203, 633, 1271, 6253, 4475, 10773, 25003, 67599}},
+{12366, 17, 56569, {1, 1, 3, 9, 1, 25, 117, 159, 13, 155, 851, 2497, 6155, 6549, 27909, 24423, 82357}},
+{12367, 17, 56580, {1, 1, 1, 1, 21, 59, 103, 43, 291, 111, 1355, 401, 5129, 16017, 25947, 15391, 46745}},
+{12368, 17, 56584, {1, 1, 1, 13, 13, 51, 95, 111, 17, 963, 1535, 3003, 6163, 11377, 6787, 57275, 109559}},
+{12369, 17, 56598, {1, 1, 5, 11, 11, 3, 85, 207, 489, 117, 269, 747, 5719, 8501, 7307, 59223, 18941}},
+{12370, 17, 56601, {1, 1, 5, 1, 9, 53, 41, 255, 271, 995, 1939, 2739, 2221, 14841, 22617, 10643, 6427}},
+{12371, 17, 56602, {1, 3, 3, 9, 7, 55, 109, 143, 427, 45, 579, 115, 2061, 8447, 29469, 5523, 129063}},
+{12372, 17, 56623, {1, 3, 7, 5, 23, 63, 119, 31, 53, 821, 135, 2677, 807, 4685, 24391, 55165, 88079}},
+{12373, 17, 56637, {1, 3, 5, 9, 15, 11, 73, 177, 243, 375, 115, 1633, 7983, 15039, 21169, 25325, 128479}},
+{12374, 17, 56638, {1, 3, 3, 5, 21, 51, 13, 51, 75, 993, 77, 209, 2761, 451, 11987, 40297, 2383}},
+{12375, 17, 56643, {1, 3, 7, 1, 19, 9, 11, 161, 19, 851, 1313, 1169, 4405, 7493, 23935, 37323, 107387}},
+{12376, 17, 56650, {1, 3, 5, 15, 5, 11, 79, 129, 507, 247, 811, 1145, 3893, 5205, 11309, 38205, 2051}},
+{12377, 17, 56673, {1, 1, 5, 1, 11, 13, 33, 155, 21, 185, 771, 3261, 981, 743, 12479, 22611, 25321}},
+{12378, 17, 56676, {1, 1, 5, 9, 7, 25, 11, 235, 429, 563, 1647, 1429, 1385, 14411, 3831, 19769, 67599}},
+{12379, 17, 56686, {1, 3, 3, 5, 5, 7, 109, 117, 251, 823, 669, 2043, 1843, 11829, 27051, 35865, 11461}},
+{12380, 17, 56704, {1, 3, 5, 5, 7, 3, 45, 63, 305, 99, 393, 1765, 1711, 15569, 27295, 16555, 77631}},
+{12381, 17, 56710, {1, 3, 5, 11, 23, 33, 49, 125, 85, 677, 1589, 2667, 5723, 15619, 30415, 39561, 122763}},
+{12382, 17, 56721, {1, 3, 7, 13, 27, 21, 99, 209, 481, 123, 1285, 115, 6517, 11753, 11365, 44959, 89}},
+{12383, 17, 56731, {1, 1, 1, 7, 15, 15, 45, 151, 489, 169, 933, 2987, 657, 3095, 6745, 131, 37767}},
+{12384, 17, 56738, {1, 3, 1, 15, 1, 37, 99, 137, 151, 891, 715, 383, 1293, 719, 10957, 5557, 92841}},
+{12385, 17, 56747, {1, 1, 1, 3, 27, 59, 93, 49, 473, 313, 431, 1129, 5995, 13101, 13185, 7091, 109677}},
+{12386, 17, 56750, {1, 3, 3, 7, 1, 41, 55, 135, 271, 527, 1919, 1093, 2579, 3725, 22853, 31613, 4729}},
+{12387, 17, 56752, {1, 1, 7, 1, 7, 13, 63, 255, 219, 837, 117, 2323, 4295, 15697, 8607, 47047, 117869}},
+{12388, 17, 56757, {1, 1, 1, 7, 29, 29, 55, 171, 437, 733, 491, 1037, 7221, 5705, 31819, 19583, 103991}},
+{12389, 17, 56787, {1, 3, 7, 1, 31, 19, 65, 39, 151, 517, 1985, 2251, 6147, 12983, 28263, 35891, 7545}},
+{12390, 17, 56796, {1, 1, 7, 7, 21, 41, 97, 253, 427, 391, 849, 611, 4827, 10807, 6267, 22513, 62803}},
+{12391, 17, 56803, {1, 3, 7, 7, 25, 9, 49, 245, 491, 39, 603, 1853, 5655, 3517, 10745, 55069, 121497}},
+{12392, 17, 56812, {1, 3, 1, 5, 9, 39, 109, 195, 283, 141, 2007, 3, 1267, 13053, 8387, 48665, 48877}},
+{12393, 17, 56815, {1, 1, 3, 7, 27, 61, 49, 43, 229, 497, 2015, 1345, 3195, 7139, 13453, 56993, 15099}},
+{12394, 17, 56824, {1, 3, 5, 11, 31, 53, 87, 97, 385, 387, 1107, 3287, 2517, 7421, 1007, 37421, 124113}},
+{12395, 17, 56829, {1, 3, 3, 11, 9, 55, 51, 215, 181, 419, 863, 3149, 5815, 15579, 28527, 34715, 61375}},
+{12396, 17, 56833, {1, 3, 3, 3, 31, 57, 5, 35, 445, 957, 1897, 105, 2533, 10255, 19795, 49127, 38491}},
+{12397, 17, 56839, {1, 3, 3, 13, 25, 53, 1, 159, 443, 541, 439, 3377, 5511, 9667, 26777, 32599, 36981}},
+{12398, 17, 56840, {1, 1, 1, 3, 23, 29, 97, 131, 59, 143, 1601, 2765, 4569, 11081, 6027, 38641, 100745}},
+{12399, 17, 56845, {1, 3, 3, 15, 9, 15, 19, 35, 321, 935, 465, 2707, 4799, 7455, 12743, 31029, 114149}},
+{12400, 17, 56853, {1, 1, 1, 1, 11, 51, 23, 79, 387, 701, 107, 623, 231, 12571, 7719, 3061, 79605}},
+{12401, 17, 56854, {1, 3, 5, 15, 17, 49, 109, 83, 185, 295, 853, 219, 3615, 535, 32001, 6655, 4185}},
+{12402, 17, 56858, {1, 3, 3, 15, 15, 7, 35, 151, 305, 705, 1383, 1595, 5595, 11995, 15491, 49119, 83383}},
+{12403, 17, 56863, {1, 3, 7, 9, 3, 25, 57, 47, 359, 719, 1937, 1403, 1399, 10827, 24181, 29141, 79017}},
+{12404, 17, 56864, {1, 3, 5, 1, 1, 21, 21, 245, 361, 485, 1521, 3935, 1587, 8653, 25871, 49449, 103413}},
+{12405, 17, 56881, {1, 3, 3, 3, 9, 61, 31, 69, 401, 261, 1217, 3069, 4045, 12437, 32017, 15113, 10769}},
+{12406, 17, 56882, {1, 3, 1, 1, 21, 33, 123, 87, 481, 793, 625, 4087, 1361, 11077, 18835, 13287, 40107}},
+{12407, 17, 56896, {1, 3, 7, 3, 9, 49, 101, 213, 467, 77, 1691, 2621, 4411, 8025, 30247, 13691, 20559}},
+{12408, 17, 56901, {1, 1, 1, 9, 29, 49, 47, 135, 1, 337, 1649, 389, 3845, 7213, 19527, 2619, 78841}},
+{12409, 17, 56902, {1, 3, 7, 9, 23, 23, 47, 97, 493, 767, 137, 1467, 7015, 2883, 12749, 9267, 12441}},
+{12410, 17, 56908, {1, 1, 3, 15, 9, 57, 53, 19, 401, 385, 1159, 1185, 6977, 14027, 3183, 59119, 42065}},
+{12411, 17, 56923, {1, 1, 1, 15, 21, 33, 83, 251, 147, 395, 321, 443, 6893, 1877, 6687, 28863, 86531}},
+{12412, 17, 56925, {1, 3, 3, 1, 3, 47, 27, 247, 121, 827, 1399, 4079, 7545, 11691, 27915, 28811, 17099}},
+{12413, 17, 56926, {1, 3, 5, 7, 5, 59, 73, 69, 117, 897, 905, 3273, 2935, 11077, 32443, 60959, 16081}},
+{12414, 17, 56932, {1, 1, 7, 5, 27, 49, 107, 169, 75, 435, 1913, 2089, 5733, 2361, 5163, 52239, 87411}},
+{12415, 17, 56939, {1, 1, 7, 13, 1, 13, 123, 89, 427, 301, 1217, 1491, 5361, 10381, 28971, 57655, 108607}},
+{12416, 17, 56947, {1, 1, 7, 11, 13, 5, 23, 151, 117, 369, 623, 2263, 2609, 109, 32485, 52133, 69391}},
+{12417, 17, 56954, {1, 3, 7, 11, 7, 33, 127, 43, 123, 203, 775, 3215, 5115, 1805, 14581, 46791, 128781}},
+{12418, 17, 56970, {1, 3, 3, 1, 7, 23, 37, 99, 1, 719, 293, 2727, 6859, 683, 13241, 17839, 4215}},
+{12419, 17, 56972, {1, 1, 1, 13, 27, 41, 93, 25, 59, 947, 971, 1523, 4443, 1209, 32317, 58651, 11121}},
+{12420, 17, 56977, {1, 1, 1, 3, 31, 33, 23, 87, 349, 265, 445, 3489, 783, 7833, 5767, 59295, 45057}},
+{12421, 17, 56980, {1, 1, 1, 1, 15, 47, 19, 15, 217, 837, 2043, 2805, 4701, 5873, 1517, 46743, 61655}},
+{12422, 17, 56993, {1, 3, 7, 1, 27, 27, 9, 107, 25, 897, 955, 3763, 821, 1535, 14557, 38537, 128737}},
+{12423, 17, 57013, {1, 3, 3, 7, 19, 49, 121, 217, 401, 975, 1189, 715, 3113, 4219, 4885, 57861, 6833}},
+{12424, 17, 57017, {1, 3, 3, 1, 17, 59, 53, 15, 259, 791, 2035, 499, 7707, 13685, 14367, 20155, 91033}},
+{12425, 17, 57018, {1, 3, 5, 5, 11, 11, 69, 237, 139, 73, 541, 1135, 2647, 14109, 18113, 8051, 31917}},
+{12426, 17, 57031, {1, 1, 1, 15, 11, 23, 89, 181, 295, 743, 29, 4009, 4683, 13989, 4575, 38865, 30449}},
+{12427, 17, 57059, {1, 1, 1, 11, 21, 63, 31, 121, 55, 153, 1143, 4059, 3247, 11725, 17659, 48935, 118369}},
+{12428, 17, 57062, {1, 1, 7, 9, 17, 29, 27, 167, 69, 957, 2009, 2795, 3161, 3493, 16365, 43637, 102321}},
+{12429, 17, 57065, {1, 3, 5, 13, 27, 23, 17, 7, 345, 253, 631, 1389, 2523, 9993, 32619, 46731, 4757}},
+{12430, 17, 57071, {1, 1, 1, 11, 17, 1, 41, 107, 25, 183, 1361, 1211, 3607, 12713, 16011, 42987, 36415}},
+{12431, 17, 57083, {1, 1, 7, 5, 13, 29, 33, 69, 261, 213, 73, 3737, 3867, 503, 28225, 53735, 91695}},
+{12432, 17, 57093, {1, 3, 7, 7, 21, 63, 75, 39, 259, 367, 487, 2087, 5411, 1925, 29589, 39019, 73283}},
+{12433, 17, 57097, {1, 3, 1, 7, 29, 29, 25, 191, 91, 509, 1485, 853, 7011, 13321, 27769, 10249, 87341}},
+{12434, 17, 57106, {1, 1, 7, 7, 1, 9, 115, 71, 321, 913, 1679, 2129, 771, 9217, 4731, 24353, 35631}},
+{12435, 17, 57118, {1, 3, 1, 13, 5, 45, 53, 255, 429, 805, 1983, 1437, 2677, 6337, 22221, 55455, 39855}},
+{12436, 17, 57133, {1, 1, 1, 1, 1, 5, 111, 231, 321, 961, 371, 3825, 3623, 3985, 32151, 6113, 130687}},
+{12437, 17, 57134, {1, 3, 7, 3, 15, 29, 103, 181, 261, 149, 1161, 1745, 1765, 1677, 20051, 47033, 84997}},
+{12438, 17, 57141, {1, 3, 7, 1, 25, 21, 7, 229, 407, 673, 1525, 1207, 3099, 14849, 22103, 45695, 85951}},
+{12439, 17, 57146, {1, 3, 7, 1, 9, 5, 105, 149, 181, 81, 1589, 3477, 5387, 7943, 29203, 50355, 39001}},
+{12440, 17, 57156, {1, 3, 7, 1, 21, 31, 39, 121, 397, 1023, 711, 623, 6193, 12315, 11101, 11911, 50033}},
+{12441, 17, 57174, {1, 3, 7, 3, 7, 19, 73, 69, 201, 337, 1037, 3663, 2679, 5153, 28171, 24455, 74685}},
+{12442, 17, 57183, {1, 3, 1, 1, 21, 35, 121, 111, 217, 809, 507, 1347, 4439, 4601, 26371, 23595, 3583}},
+{12443, 17, 57189, {1, 3, 3, 7, 1, 51, 83, 231, 419, 597, 305, 3405, 5831, 11845, 1861, 48671, 105315}},
+{12444, 17, 57190, {1, 3, 1, 15, 25, 37, 103, 141, 495, 727, 1919, 2821, 4689, 6727, 27117, 2259, 54559}},
+{12445, 17, 57193, {1, 3, 5, 3, 27, 55, 5, 117, 199, 979, 1745, 401, 7967, 5345, 29747, 54085, 124765}},
+{12446, 17, 57196, {1, 3, 3, 15, 23, 61, 1, 29, 489, 131, 583, 389, 6033, 8007, 22933, 44513, 111845}},
+{12447, 17, 57207, {1, 1, 7, 13, 3, 55, 119, 147, 181, 485, 793, 3593, 6971, 2227, 28507, 62393, 127303}},
+{12448, 17, 57211, {1, 1, 5, 3, 29, 53, 37, 59, 213, 283, 1809, 3685, 2677, 5761, 19705, 47079, 3477}},
+{12449, 17, 57214, {1, 1, 1, 7, 21, 63, 91, 13, 347, 605, 589, 415, 5737, 10281, 30941, 25609, 67973}},
+{12450, 17, 57218, {1, 1, 3, 1, 27, 49, 87, 161, 507, 693, 59, 1375, 6737, 1029, 14731, 32335, 51961}},
+{12451, 17, 57230, {1, 3, 3, 9, 11, 15, 121, 121, 151, 335, 221, 3099, 1999, 1047, 20891, 23015, 95809}},
+{12452, 17, 57235, {1, 1, 7, 7, 1, 49, 63, 227, 113, 161, 863, 801, 2559, 7737, 27619, 27419, 128009}},
+{12453, 17, 57241, {1, 1, 7, 1, 25, 59, 67, 111, 435, 309, 807, 2107, 8077, 9671, 6739, 53757, 41259}},
+{12454, 17, 57251, {1, 3, 7, 3, 3, 19, 7, 111, 237, 981, 1717, 3131, 6631, 467, 13103, 61435, 126469}},
+{12455, 17, 57260, {1, 1, 7, 9, 19, 31, 59, 185, 199, 111, 351, 611, 6355, 1095, 28549, 32871, 44537}},
+{12456, 17, 57263, {1, 1, 3, 11, 23, 25, 31, 1, 461, 83, 1723, 1711, 3679, 10963, 14927, 17377, 911}},
+{12457, 17, 57265, {1, 1, 5, 13, 3, 37, 127, 159, 199, 223, 1097, 3033, 5825, 13777, 22189, 44305, 20509}},
+{12458, 17, 57271, {1, 1, 5, 15, 13, 49, 17, 79, 289, 601, 1023, 657, 1687, 14477, 15929, 4279, 68007}},
+{12459, 17, 57272, {1, 1, 5, 7, 29, 3, 45, 225, 65, 711, 1039, 3585, 4957, 9041, 22761, 26649, 95627}},
+{12460, 17, 57290, {1, 3, 5, 5, 13, 29, 33, 211, 461, 799, 1437, 1057, 485, 9535, 8133, 57527, 12873}},
+{12461, 17, 57295, {1, 1, 3, 3, 15, 43, 53, 15, 395, 561, 1371, 3543, 7707, 2399, 13311, 25641, 58865}},
+{12462, 17, 57298, {1, 3, 1, 7, 1, 9, 115, 39, 249, 87, 835, 97, 8137, 6665, 11951, 21045, 76387}},
+{12463, 17, 57325, {1, 3, 3, 9, 5, 63, 115, 163, 331, 1007, 733, 4027, 2911, 5329, 6967, 3535, 107293}},
+{12464, 17, 57328, {1, 3, 1, 11, 5, 55, 81, 63, 345, 535, 1093, 207, 4053, 9129, 10397, 26641, 95171}},
+{12465, 17, 57340, {1, 1, 3, 3, 13, 27, 65, 37, 255, 69, 19, 2565, 4329, 11223, 18131, 18701, 31111}},
+{12466, 17, 57344, {1, 3, 7, 7, 25, 57, 81, 189, 227, 377, 829, 1583, 1343, 4643, 23485, 47463, 83535}},
+{12467, 17, 57353, {1, 3, 5, 9, 13, 33, 103, 75, 501, 803, 427, 1171, 1187, 2655, 24187, 32907, 120239}},
+{12468, 17, 57368, {1, 3, 1, 7, 31, 63, 21, 137, 241, 63, 1925, 2193, 1135, 11159, 14685, 28397, 59}},
+{12469, 17, 57371, {1, 1, 7, 1, 15, 7, 85, 87, 493, 63, 561, 1069, 5481, 12253, 25149, 35283, 16123}},
+{12470, 17, 57383, {1, 3, 3, 5, 19, 17, 23, 95, 429, 805, 1343, 2243, 233, 7219, 6549, 21477, 83679}},
+{12471, 17, 57402, {1, 3, 3, 1, 3, 55, 83, 107, 131, 311, 741, 781, 6227, 10059, 3903, 235, 45971}},
+{12472, 17, 57407, {1, 1, 3, 13, 21, 43, 79, 149, 367, 755, 463, 221, 5117, 7015, 17599, 64665, 37443}},
+{12473, 17, 57419, {1, 1, 7, 15, 3, 59, 107, 13, 213, 287, 1505, 2131, 6965, 12873, 23973, 8449, 24829}},
+{12474, 17, 57424, {1, 3, 5, 11, 25, 45, 39, 17, 175, 749, 1179, 3349, 6723, 12543, 3557, 34521, 103197}},
+{12475, 17, 57433, {1, 1, 3, 13, 23, 41, 21, 25, 91, 941, 879, 4015, 137, 12949, 17245, 41903, 39803}},
+{12476, 17, 57452, {1, 1, 7, 15, 11, 33, 45, 127, 321, 895, 1543, 4013, 6179, 14209, 13317, 46803, 99891}},
+{12477, 17, 57458, {1, 3, 3, 13, 13, 11, 101, 11, 177, 869, 509, 2323, 449, 16379, 31965, 2899, 59229}},
+{12478, 17, 57467, {1, 1, 5, 7, 15, 37, 113, 237, 463, 489, 1145, 1629, 3101, 10305, 31705, 29957, 99665}},
+{12479, 17, 57470, {1, 3, 5, 7, 21, 29, 45, 133, 367, 657, 1315, 537, 6069, 8141, 31479, 32983, 57}},
+{12480, 17, 57473, {1, 1, 3, 9, 13, 39, 109, 125, 467, 975, 829, 4007, 773, 6639, 8793, 4579, 60547}},
+{12481, 17, 57479, {1, 1, 1, 15, 21, 5, 113, 51, 159, 501, 1921, 4095, 5603, 16055, 16649, 50229, 49863}},
+{12482, 17, 57480, {1, 1, 5, 13, 9, 21, 77, 187, 355, 299, 1017, 491, 6725, 4177, 16739, 15909, 84069}},
+{12483, 17, 57486, {1, 3, 7, 5, 13, 13, 51, 19, 159, 339, 735, 933, 2523, 11435, 20793, 21975, 19007}},
+{12484, 17, 57491, {1, 1, 7, 5, 1, 11, 61, 111, 129, 643, 1741, 945, 7349, 11579, 24793, 1751, 2367}},
+{12485, 17, 57493, {1, 1, 5, 5, 29, 45, 63, 177, 507, 277, 1789, 729, 4277, 10099, 28985, 43009, 2319}},
+{12486, 17, 57524, {1, 3, 3, 13, 19, 53, 73, 227, 487, 131, 1227, 3735, 3979, 7383, 6923, 31979, 6651}},
+{12487, 17, 57528, {1, 3, 3, 15, 7, 47, 31, 255, 317, 621, 497, 4069, 5249, 15093, 18013, 6891, 81893}},
+{12488, 17, 57534, {1, 1, 7, 5, 17, 23, 119, 27, 55, 555, 221, 2693, 1757, 11117, 23409, 21135, 122977}},
+{12489, 17, 57542, {1, 1, 5, 1, 15, 17, 127, 109, 75, 1017, 1167, 2975, 3249, 5399, 12599, 50779, 78215}},
+{12490, 17, 57560, {1, 3, 5, 5, 1, 13, 65, 199, 101, 75, 513, 493, 6931, 9363, 5607, 16331, 69219}},
+{12491, 17, 57565, {1, 1, 1, 15, 19, 37, 63, 177, 397, 645, 905, 1599, 609, 14291, 14681, 46719, 117745}},
+{12492, 17, 57570, {1, 3, 7, 13, 3, 57, 63, 49, 67, 913, 1659, 1857, 3595, 9219, 11341, 39735, 82275}},
+{12493, 17, 57579, {1, 1, 5, 11, 19, 1, 5, 181, 55, 763, 469, 2417, 2349, 12437, 22589, 17867, 95701}},
+{12494, 17, 57590, {1, 3, 7, 13, 1, 9, 11, 159, 103, 737, 1989, 59, 4711, 8093, 31703, 45663, 92913}},
+{12495, 17, 57601, {1, 3, 3, 11, 15, 9, 35, 217, 299, 479, 1539, 2605, 2003, 8841, 27261, 28853, 98877}},
+{12496, 17, 57604, {1, 1, 5, 5, 15, 45, 73, 159, 205, 1017, 159, 3659, 2377, 3651, 6489, 19711, 109959}},
+{12497, 17, 57607, {1, 1, 3, 15, 7, 41, 7, 47, 357, 433, 211, 111, 2565, 8637, 15917, 47887, 128513}},
+{12498, 17, 57621, {1, 3, 7, 3, 25, 9, 33, 33, 5, 805, 1541, 3333, 7257, 9011, 4813, 53195, 52469}},
+{12499, 17, 57635, {1, 1, 7, 15, 27, 3, 11, 57, 415, 371, 563, 2515, 149, 6555, 31273, 51465, 2989}},
+{12500, 17, 57642, {1, 1, 1, 11, 3, 41, 25, 175, 499, 879, 1145, 1083, 7857, 10497, 16991, 23351, 115353}},
+{12501, 17, 57650, {1, 1, 3, 15, 15, 9, 39, 239, 285, 413, 989, 2927, 7205, 79, 20101, 30115, 113933}},
+{12502, 17, 57655, {1, 1, 7, 5, 13, 29, 29, 69, 25, 533, 1731, 1391, 4065, 12597, 19167, 51989, 101273}},
+{12503, 17, 57670, {1, 1, 5, 3, 9, 41, 83, 127, 197, 627, 173, 273, 593, 15733, 19285, 26517, 107877}},
+{12504, 17, 57676, {1, 1, 1, 5, 29, 17, 89, 163, 125, 473, 1577, 2435, 3379, 3057, 1829, 64325, 111719}},
+{12505, 17, 57682, {1, 3, 1, 11, 1, 29, 97, 53, 421, 941, 1737, 3337, 2715, 1633, 28485, 30369, 116047}},
+{12506, 17, 57687, {1, 1, 5, 13, 25, 43, 39, 85, 385, 129, 819, 1647, 3527, 12319, 573, 58703, 29463}},
+{12507, 17, 57691, {1, 3, 3, 9, 23, 59, 31, 215, 49, 451, 645, 3687, 4507, 9359, 28161, 34609, 123409}},
+{12508, 17, 57700, {1, 3, 1, 9, 13, 25, 97, 239, 203, 31, 1465, 1089, 7665, 3007, 22465, 28389, 119869}},
+{12509, 17, 57704, {1, 3, 3, 1, 29, 51, 19, 83, 443, 193, 647, 3125, 7269, 3031, 9967, 40447, 102179}},
+{12510, 17, 57707, {1, 3, 5, 15, 5, 63, 125, 55, 295, 787, 559, 3309, 7491, 9907, 5775, 15155, 41793}},
+{12511, 17, 57721, {1, 3, 7, 7, 21, 61, 125, 207, 43, 159, 539, 435, 1945, 725, 797, 47489, 43099}},
+{12512, 17, 57731, {1, 1, 5, 7, 11, 11, 61, 103, 23, 693, 493, 1045, 4435, 9009, 22075, 24839, 125431}},
+{12513, 17, 57733, {1, 3, 1, 9, 13, 61, 83, 181, 373, 949, 1397, 247, 5079, 10933, 31887, 14147, 55121}},
+{12514, 17, 57738, {1, 1, 7, 15, 31, 47, 87, 219, 357, 409, 943, 2993, 7615, 7071, 14179, 41489, 104401}},
+{12515, 17, 57745, {1, 3, 3, 1, 11, 15, 87, 241, 389, 761, 1523, 3049, 2111, 11581, 5493, 11301, 32017}},
+{12516, 17, 57748, {1, 1, 7, 11, 29, 39, 37, 63, 411, 671, 1789, 3541, 5651, 11721, 10871, 53867, 112895}},
+{12517, 17, 57751, {1, 3, 3, 1, 23, 21, 99, 161, 467, 197, 1263, 451, 5469, 7667, 22139, 31599, 8345}},
+{12518, 17, 57757, {1, 3, 1, 3, 11, 41, 13, 79, 3, 377, 1865, 2297, 1383, 14033, 17141, 24787, 127911}},
+{12519, 17, 57761, {1, 1, 1, 1, 5, 11, 5, 181, 323, 853, 831, 1599, 3939, 6391, 22817, 37969, 9997}},
+{12520, 17, 57774, {1, 1, 3, 11, 29, 61, 11, 171, 181, 631, 757, 3879, 4779, 16183, 5969, 7909, 42855}},
+{12521, 17, 57779, {1, 3, 3, 15, 19, 17, 107, 187, 19, 743, 909, 1963, 2131, 2107, 659, 35829, 57905}},
+{12522, 17, 57786, {1, 1, 7, 1, 31, 29, 67, 99, 353, 715, 65, 3907, 1931, 1289, 9217, 60635, 32737}},
+{12523, 17, 57808, {1, 3, 3, 13, 3, 17, 19, 173, 263, 203, 1233, 1407, 933, 8905, 26905, 63343, 64963}},
+{12524, 17, 57814, {1, 3, 1, 13, 21, 43, 97, 79, 163, 529, 1571, 1027, 4339, 16235, 9189, 29203, 36789}},
+{12525, 17, 57817, {1, 1, 7, 1, 31, 1, 117, 247, 193, 333, 1797, 3515, 285, 2803, 25345, 9101, 110569}},
+{12526, 17, 57824, {1, 1, 5, 11, 17, 63, 45, 167, 35, 925, 569, 3687, 6739, 12453, 26171, 28249, 73827}},
+{12527, 17, 57827, {1, 1, 5, 1, 19, 49, 107, 183, 435, 305, 1191, 2711, 891, 15813, 13449, 23489, 89749}},
+{12528, 17, 57848, {1, 1, 1, 11, 7, 53, 105, 17, 433, 351, 1151, 4077, 5371, 10183, 18895, 13229, 101219}},
+{12529, 17, 57853, {1, 3, 7, 9, 21, 33, 27, 125, 177, 607, 817, 2689, 2123, 2037, 29643, 27219, 44591}},
+{12530, 17, 57857, {1, 3, 5, 11, 27, 51, 29, 161, 469, 349, 1445, 3613, 1487, 961, 29017, 2235, 45905}},
+{12531, 17, 57858, {1, 1, 3, 11, 7, 15, 37, 195, 329, 875, 559, 1361, 7373, 7143, 15059, 59205, 37167}},
+{12532, 17, 57867, {1, 1, 5, 1, 7, 25, 27, 211, 301, 369, 227, 123, 4415, 15993, 4829, 43801, 83639}},
+{12533, 17, 57872, {1, 1, 3, 5, 25, 37, 31, 205, 69, 275, 855, 1407, 2989, 11001, 16963, 31497, 3505}},
+{12534, 17, 57887, {1, 1, 7, 7, 25, 33, 81, 181, 197, 717, 207, 535, 8083, 5765, 2523, 40347, 27245}},
+{12535, 17, 57894, {1, 3, 1, 5, 13, 3, 107, 143, 233, 419, 1831, 2149, 7277, 13449, 31609, 48345, 82621}},
+{12536, 17, 57915, {1, 3, 5, 9, 31, 35, 39, 113, 415, 803, 1479, 3169, 8015, 4659, 2445, 9159, 91625}},
+{12537, 17, 57920, {1, 3, 1, 5, 27, 25, 83, 165, 459, 955, 1535, 377, 5531, 2945, 18285, 18097, 21589}},
+{12538, 17, 57923, {1, 1, 1, 15, 13, 23, 11, 159, 471, 951, 1971, 677, 2641, 3227, 14761, 39421, 29841}},
+{12539, 17, 57932, {1, 1, 7, 11, 19, 37, 101, 97, 373, 559, 105, 905, 897, 15309, 14979, 52029, 38989}},
+{12540, 17, 57937, {1, 1, 5, 15, 31, 43, 71, 75, 481, 997, 5, 1005, 4987, 7907, 16237, 43075, 94827}},
+{12541, 17, 57943, {1, 3, 5, 11, 23, 55, 123, 91, 183, 307, 97, 1999, 3341, 4717, 19643, 9455, 26555}},
+{12542, 17, 57950, {1, 1, 7, 3, 29, 61, 75, 197, 125, 579, 145, 1333, 85, 15655, 28177, 6169, 43289}},
+{12543, 17, 57960, {1, 3, 7, 13, 21, 15, 1, 221, 293, 991, 35, 2701, 2909, 7333, 27319, 32281, 77861}},
+{12544, 17, 57971, {1, 1, 3, 1, 17, 11, 81, 209, 499, 125, 105, 2987, 3891, 9531, 27963, 39611, 43633}},
+{12545, 17, 57974, {1, 3, 3, 3, 29, 45, 51, 63, 209, 75, 1321, 4055, 7851, 12329, 8371, 59513, 49105}},
+{12546, 17, 57983, {1, 1, 7, 5, 9, 63, 59, 127, 445, 899, 1857, 3737, 625, 15021, 25177, 21007, 25935}},
+{12547, 17, 57987, {1, 1, 5, 9, 9, 57, 25, 63, 235, 191, 1527, 1783, 1401, 1813, 2553, 1241, 100029}},
+{12548, 17, 57994, {1, 3, 1, 11, 27, 5, 49, 39, 505, 653, 1083, 921, 1045, 11337, 25499, 36211, 75851}},
+{12549, 17, 58001, {1, 3, 3, 1, 29, 19, 71, 93, 223, 153, 561, 1657, 5821, 14181, 1275, 24633, 114787}},
+{12550, 17, 58002, {1, 1, 1, 9, 7, 13, 17, 239, 457, 731, 1811, 3015, 4465, 5865, 2387, 30455, 17405}},
+{12551, 17, 58013, {1, 3, 5, 1, 7, 45, 117, 207, 7, 645, 131, 863, 6443, 14455, 11885, 39257, 126431}},
+{12552, 17, 58023, {1, 1, 3, 5, 17, 23, 3, 27, 475, 731, 431, 1967, 981, 12727, 1301, 17647, 62481}},
+{12553, 17, 58027, {1, 1, 1, 13, 11, 53, 105, 109, 105, 461, 1787, 2851, 1299, 9925, 13055, 58301, 24483}},
+{12554, 17, 58029, {1, 1, 1, 11, 7, 35, 11, 173, 247, 289, 1269, 361, 2059, 5051, 25731, 58085, 21387}},
+{12555, 17, 58032, {1, 3, 1, 5, 9, 31, 59, 151, 435, 519, 1863, 2255, 2585, 10033, 29189, 27189, 25023}},
+{12556, 17, 58041, {1, 1, 5, 5, 25, 17, 53, 189, 187, 847, 369, 3287, 6047, 2385, 26045, 48821, 23335}},
+{12557, 17, 58047, {1, 1, 1, 9, 15, 55, 79, 21, 433, 131, 1677, 3681, 6173, 9189, 15053, 12971, 81135}},
+{12558, 17, 58062, {1, 1, 3, 5, 29, 5, 11, 213, 151, 77, 1493, 3959, 7675, 7689, 10381, 15871, 123463}},
+{12559, 17, 58086, {1, 3, 7, 11, 19, 47, 31, 81, 207, 789, 1945, 2671, 1987, 6363, 26401, 9799, 59531}},
+{12560, 17, 58092, {1, 1, 1, 7, 17, 7, 83, 181, 339, 423, 267, 2251, 1847, 14883, 13423, 27223, 81799}},
+{12561, 17, 58095, {1, 3, 5, 15, 9, 9, 73, 95, 197, 267, 743, 2369, 6417, 3555, 9885, 6373, 87651}},
+{12562, 17, 58097, {1, 1, 3, 13, 21, 29, 57, 59, 395, 631, 993, 17, 2939, 14117, 27521, 61387, 74927}},
+{12563, 17, 58100, {1, 1, 3, 13, 1, 29, 23, 151, 381, 591, 1217, 2295, 4403, 15865, 4325, 31329, 56989}},
+{12564, 17, 58117, {1, 3, 5, 1, 27, 7, 111, 79, 287, 945, 1237, 2857, 1461, 2477, 10929, 17117, 98677}},
+{12565, 17, 58121, {1, 1, 1, 5, 15, 35, 109, 39, 391, 57, 1783, 3133, 5563, 7721, 12651, 3437, 46697}},
+{12566, 17, 58132, {1, 3, 5, 5, 13, 47, 123, 51, 383, 91, 641, 1607, 4461, 7, 6427, 42755, 130097}},
+{12567, 17, 58142, {1, 1, 5, 5, 25, 49, 33, 59, 351, 1003, 301, 2721, 7705, 5447, 21367, 63007, 112465}},
+{12568, 17, 58145, {1, 1, 5, 13, 31, 11, 73, 1, 359, 201, 1465, 187, 7385, 12817, 12911, 17775, 77937}},
+{12569, 17, 58152, {1, 3, 1, 15, 29, 5, 117, 69, 79, 93, 947, 133, 1049, 13907, 3611, 42123, 8041}},
+{12570, 17, 58155, {1, 1, 7, 7, 29, 17, 71, 171, 357, 619, 1199, 3817, 6889, 9607, 19075, 15539, 54939}},
+{12571, 17, 58163, {1, 1, 1, 7, 23, 29, 91, 227, 119, 865, 943, 381, 5289, 189, 15917, 13875, 31095}},
+{12572, 17, 58166, {1, 1, 7, 1, 9, 49, 93, 175, 105, 61, 1285, 3659, 2383, 505, 12337, 43801, 67035}},
+{12573, 17, 58170, {1, 3, 5, 1, 31, 47, 75, 17, 455, 231, 1887, 2295, 2533, 733, 29001, 22001, 119423}},
+{12574, 17, 58175, {1, 3, 7, 3, 5, 5, 69, 205, 459, 805, 1257, 3283, 3305, 6845, 1405, 56051, 63453}},
+{12575, 17, 58184, {1, 3, 3, 3, 19, 57, 65, 149, 175, 683, 1719, 637, 4951, 13645, 30455, 22379, 105369}},
+{12576, 17, 58197, {1, 3, 1, 11, 31, 27, 69, 13, 191, 645, 1563, 3897, 2387, 2269, 12999, 42217, 100853}},
+{12577, 17, 58202, {1, 3, 1, 13, 31, 7, 11, 227, 267, 373, 1249, 2591, 4769, 303, 5865, 59911, 4991}},
+{12578, 17, 58204, {1, 3, 7, 11, 7, 31, 87, 205, 45, 785, 1947, 1965, 5851, 7501, 89, 38897, 91939}},
+{12579, 17, 58208, {1, 3, 5, 9, 21, 37, 79, 181, 163, 355, 1129, 3439, 5103, 15903, 2935, 22505, 97451}},
+{12580, 17, 58213, {1, 1, 3, 9, 7, 37, 107, 255, 69, 133, 551, 1357, 31, 7059, 29195, 30151, 81785}},
+{12581, 17, 58220, {1, 3, 3, 5, 3, 51, 3, 143, 305, 697, 1041, 1267, 7635, 1483, 649, 28275, 65059}},
+{12582, 17, 58226, {1, 3, 1, 7, 11, 13, 113, 81, 159, 993, 797, 3207, 3787, 13005, 29393, 51107, 42709}},
+{12583, 17, 58231, {1, 1, 3, 13, 7, 11, 113, 195, 349, 377, 2033, 197, 147, 13839, 5405, 29577, 64535}},
+{12584, 17, 58235, {1, 3, 1, 9, 1, 1, 77, 73, 383, 463, 1871, 1589, 1805, 2085, 5195, 17805, 33159}},
+{12585, 17, 58254, {1, 1, 1, 9, 25, 37, 123, 119, 507, 515, 1547, 139, 7501, 4725, 30195, 18199, 41145}},
+{12586, 17, 58261, {1, 3, 3, 7, 17, 33, 99, 11, 487, 343, 403, 337, 3831, 6031, 20375, 2071, 39795}},
+{12587, 17, 58271, {1, 1, 5, 1, 13, 57, 59, 11, 391, 953, 597, 1411, 3929, 13963, 15003, 59385, 12293}},
+{12588, 17, 58278, {1, 3, 1, 15, 23, 61, 67, 129, 63, 555, 433, 631, 2725, 317, 10121, 9217, 124371}},
+{12589, 17, 58287, {1, 1, 5, 7, 19, 23, 17, 45, 75, 819, 1879, 2315, 1439, 2643, 26561, 19209, 16081}},
+{12590, 17, 58327, {1, 3, 5, 7, 5, 35, 121, 233, 91, 89, 1741, 3015, 4223, 9605, 22795, 55845, 47167}},
+{12591, 17, 58333, {1, 3, 7, 7, 13, 23, 11, 51, 91, 367, 773, 1303, 2151, 14423, 22263, 28413, 107461}},
+{12592, 17, 58337, {1, 1, 1, 11, 29, 17, 49, 53, 379, 819, 1551, 2907, 5805, 2167, 16123, 9263, 43903}},
+{12593, 17, 58357, {1, 3, 1, 13, 19, 27, 33, 127, 131, 697, 489, 3289, 1895, 3243, 19497, 32419, 55741}},
+{12594, 17, 58362, {1, 3, 1, 15, 7, 51, 91, 45, 251, 829, 2015, 2659, 151, 3327, 25281, 49291, 106343}},
+{12595, 17, 58364, {1, 1, 5, 5, 27, 11, 85, 45, 203, 413, 293, 3067, 4109, 959, 22337, 38767, 75829}},
+{12596, 17, 58375, {1, 1, 3, 5, 21, 35, 65, 173, 315, 423, 171, 3837, 817, 10153, 5517, 18115, 117437}},
+{12597, 17, 58384, {1, 1, 1, 7, 9, 29, 101, 55, 253, 37, 1717, 7, 3181, 1067, 20637, 54773, 106777}},
+{12598, 17, 58387, {1, 3, 7, 11, 13, 11, 87, 83, 83, 969, 589, 3625, 3373, 3921, 24487, 34235, 96289}},
+{12599, 17, 58405, {1, 3, 1, 11, 25, 35, 65, 131, 491, 167, 449, 2949, 5807, 5649, 7569, 37363, 106819}},
+{12600, 17, 58406, {1, 1, 5, 1, 9, 37, 33, 237, 79, 163, 1791, 3499, 4951, 2009, 16183, 10121, 40221}},
+{12601, 17, 58417, {1, 1, 5, 15, 21, 49, 123, 53, 27, 273, 1655, 3713, 5699, 1659, 31985, 6779, 10195}},
+{12602, 17, 58424, {1, 3, 5, 11, 27, 37, 93, 17, 263, 41, 1583, 703, 7689, 6667, 15497, 15255, 67153}},
+{12603, 17, 58435, {1, 1, 5, 9, 19, 13, 121, 39, 321, 177, 711, 3223, 3859, 14775, 19061, 40587, 97199}},
+{12604, 17, 58450, {1, 3, 7, 9, 23, 11, 93, 243, 3, 811, 679, 1103, 7579, 14147, 20255, 22485, 117179}},
+{12605, 17, 58452, {1, 3, 3, 5, 23, 9, 21, 243, 27, 501, 1273, 1501, 5331, 15663, 19483, 10637, 90905}},
+{12606, 17, 58459, {1, 3, 1, 15, 13, 11, 89, 37, 63, 463, 731, 3615, 3923, 4677, 21329, 1069, 57565}},
+{12607, 17, 58461, {1, 1, 1, 13, 19, 39, 63, 59, 389, 367, 1285, 2005, 8103, 4179, 3805, 55475, 126589}},
+{12608, 17, 58466, {1, 3, 5, 11, 27, 57, 27, 63, 365, 171, 665, 2035, 2831, 15955, 11551, 26741, 121059}},
+{12609, 17, 58468, {1, 3, 3, 3, 23, 19, 13, 7, 331, 613, 1783, 733, 7465, 1089, 4683, 15695, 31125}},
+{12610, 17, 58485, {1, 1, 5, 3, 3, 23, 95, 157, 303, 987, 307, 2679, 6173, 6633, 17727, 30901, 76109}},
+{12611, 17, 58489, {1, 1, 1, 1, 11, 21, 111, 81, 31, 727, 1133, 4083, 5811, 2707, 31749, 42939, 92225}},
+{12612, 17, 58492, {1, 3, 1, 11, 29, 21, 31, 115, 351, 213, 201, 3511, 3707, 12821, 8845, 59789, 59721}},
+{12613, 17, 58495, {1, 3, 5, 9, 7, 27, 65, 1, 305, 937, 1201, 2045, 2431, 12275, 24431, 3317, 119671}},
+{12614, 17, 58505, {1, 1, 7, 11, 19, 43, 107, 107, 261, 933, 1125, 1875, 1943, 7477, 20759, 57853, 29459}},
+{12615, 17, 58523, {1, 1, 3, 3, 17, 43, 79, 19, 167, 341, 237, 677, 725, 2353, 12003, 48921, 20707}},
+{12616, 17, 58535, {1, 3, 3, 5, 31, 39, 91, 81, 121, 59, 737, 1767, 4407, 9159, 10237, 25361, 38891}},
+{12617, 17, 58536, {1, 1, 5, 7, 31, 47, 37, 47, 171, 623, 597, 2807, 4875, 15139, 18809, 24279, 36563}},
+{12618, 17, 58549, {1, 3, 5, 3, 3, 7, 31, 135, 81, 777, 1055, 337, 4309, 9575, 11075, 54429, 30097}},
+{12619, 17, 58550, {1, 1, 5, 1, 3, 57, 53, 25, 117, 961, 947, 257, 2645, 6935, 27511, 54051, 129095}},
+{12620, 17, 58561, {1, 1, 1, 15, 23, 45, 11, 173, 407, 373, 1051, 3519, 1875, 1291, 4393, 9047, 102159}},
+{12621, 17, 58562, {1, 1, 3, 5, 9, 51, 23, 253, 261, 339, 505, 3601, 265, 8375, 7241, 40715, 114439}},
+{12622, 17, 58573, {1, 1, 7, 7, 3, 63, 5, 233, 259, 947, 1367, 2699, 6029, 9371, 6567, 39961, 31621}},
+{12623, 17, 58576, {1, 1, 3, 3, 25, 43, 73, 61, 305, 257, 235, 421, 6621, 1025, 18831, 44525, 87665}},
+{12624, 17, 58592, {1, 3, 5, 7, 19, 33, 77, 163, 191, 115, 1275, 3551, 3521, 6767, 30209, 48895, 114185}},
+{12625, 17, 58601, {1, 1, 3, 3, 29, 37, 3, 165, 267, 807, 967, 2893, 3287, 12249, 21411, 19291, 91781}},
+{12626, 17, 58622, {1, 1, 5, 5, 27, 55, 51, 137, 429, 775, 1525, 3911, 5367, 5981, 24373, 16331, 31887}},
+{12627, 17, 58627, {1, 1, 5, 11, 17, 49, 37, 243, 509, 563, 1381, 2013, 7341, 10509, 10049, 29135, 32709}},
+{12628, 17, 58629, {1, 1, 3, 13, 1, 33, 119, 5, 477, 701, 1329, 1023, 2091, 12895, 6443, 1053, 44741}},
+{12629, 17, 58634, {1, 3, 5, 7, 13, 19, 1, 113, 3, 481, 1555, 2857, 3519, 7903, 16153, 62909, 78877}},
+{12630, 17, 58639, {1, 1, 7, 11, 7, 27, 47, 175, 87, 605, 411, 4065, 8059, 5023, 27719, 3111, 62247}},
+{12631, 17, 58641, {1, 3, 1, 15, 27, 37, 71, 77, 297, 647, 1651, 2543, 3925, 4827, 28587, 49663, 56581}},
+{12632, 17, 58644, {1, 3, 5, 1, 19, 49, 63, 9, 43, 243, 931, 3577, 2371, 10513, 13691, 27739, 61011}},
+{12633, 17, 58654, {1, 1, 3, 1, 23, 27, 53, 149, 157, 735, 1087, 1529, 6613, 2493, 4879, 26771, 123711}},
+{12634, 17, 58663, {1, 3, 7, 13, 5, 3, 43, 3, 343, 497, 943, 3443, 4335, 4779, 4033, 25871, 10965}},
+{12635, 17, 58667, {1, 3, 5, 1, 5, 11, 93, 73, 199, 455, 421, 3495, 4381, 717, 21033, 41287, 44743}},
+{12636, 17, 58677, {1, 1, 3, 9, 13, 33, 77, 143, 81, 57, 1061, 3205, 2411, 1347, 23149, 21913, 119331}},
+{12637, 17, 58682, {1, 3, 1, 7, 1, 15, 45, 247, 119, 905, 457, 3939, 4865, 11191, 27705, 46315, 68367}},
+{12638, 17, 58690, {1, 3, 3, 15, 31, 5, 55, 169, 381, 1009, 1893, 2751, 411, 8653, 30367, 54919, 23541}},
+{12639, 17, 58692, {1, 3, 7, 1, 29, 27, 77, 239, 109, 125, 355, 2759, 2229, 3435, 16241, 53309, 613}},
+{12640, 17, 58695, {1, 3, 1, 3, 11, 27, 33, 167, 311, 1003, 1635, 2479, 1831, 6225, 17711, 30185, 87043}},
+{12641, 17, 58710, {1, 3, 7, 13, 7, 61, 3, 243, 55, 259, 461, 3357, 121, 9107, 19393, 3719, 71403}},
+{12642, 17, 58713, {1, 1, 7, 15, 23, 25, 55, 89, 241, 297, 113, 59, 4799, 381, 29127, 811, 91149}},
+{12643, 17, 58723, {1, 1, 3, 3, 13, 35, 43, 163, 69, 69, 1949, 2383, 887, 2349, 12539, 167, 23697}},
+{12644, 17, 58740, {1, 3, 3, 11, 3, 45, 23, 149, 55, 963, 1293, 2715, 1401, 16081, 12821, 2129, 26835}},
+{12645, 17, 58749, {1, 3, 3, 13, 29, 47, 21, 249, 141, 179, 627, 329, 6377, 12049, 11715, 1447, 119359}},
+{12646, 17, 58760, {1, 1, 5, 13, 7, 59, 103, 189, 401, 169, 455, 1197, 1881, 12679, 4533, 25561, 79281}},
+{12647, 17, 58766, {1, 1, 7, 15, 21, 59, 97, 77, 397, 487, 647, 2277, 269, 713, 17741, 37387, 100143}},
+{12648, 17, 58773, {1, 3, 5, 1, 1, 43, 31, 201, 21, 805, 1533, 1407, 4719, 2673, 22757, 7605, 72485}},
+{12649, 17, 58780, {1, 1, 3, 11, 27, 25, 99, 135, 225, 367, 1311, 683, 7193, 8209, 17081, 55709, 3029}},
+{12650, 17, 58787, {1, 3, 5, 5, 17, 9, 59, 27, 153, 353, 647, 2919, 1877, 5359, 19787, 46237, 7}},
+{12651, 17, 58796, {1, 3, 3, 15, 11, 39, 75, 223, 489, 57, 1355, 3941, 6603, 12883, 20909, 24065, 53543}},
+{12652, 17, 58816, {1, 1, 3, 9, 17, 47, 61, 49, 397, 23, 2019, 37, 23, 8967, 10357, 54419, 27279}},
+{12653, 17, 58822, {1, 1, 1, 7, 31, 43, 87, 111, 293, 969, 1431, 2275, 3131, 2915, 24595, 63049, 71517}},
+{12654, 17, 58831, {1, 1, 3, 11, 11, 63, 89, 33, 95, 299, 593, 3353, 7389, 841, 1895, 64835, 19915}},
+{12655, 17, 58839, {1, 1, 1, 3, 13, 63, 51, 3, 327, 401, 1289, 2699, 5599, 5101, 3189, 23415, 53429}},
+{12656, 17, 58849, {1, 1, 7, 13, 27, 15, 57, 201, 365, 643, 171, 2417, 1763, 7567, 5323, 50911, 24281}},
+{12657, 17, 58859, {1, 3, 3, 13, 31, 37, 31, 243, 225, 431, 379, 1565, 1567, 11477, 4641, 58823, 88565}},
+{12658, 17, 58870, {1, 3, 3, 7, 13, 39, 79, 169, 401, 177, 2023, 1703, 5563, 15619, 21445, 59287, 30141}},
+{12659, 17, 58879, {1, 3, 3, 15, 17, 47, 13, 163, 361, 353, 1435, 2083, 4109, 14105, 28585, 1721, 119133}},
+{12660, 17, 58889, {1, 3, 3, 3, 29, 41, 97, 131, 501, 415, 1735, 2315, 6499, 11417, 3879, 3957, 47117}},
+{12661, 17, 58904, {1, 1, 3, 13, 5, 25, 29, 65, 235, 949, 1571, 927, 515, 7519, 23123, 4127, 71019}},
+{12662, 17, 58914, {1, 1, 5, 13, 1, 41, 5, 137, 487, 711, 561, 2495, 5367, 6955, 9453, 54499, 118373}},
+{12663, 17, 58923, {1, 3, 3, 5, 27, 15, 23, 237, 95, 873, 1949, 1579, 7089, 8837, 30463, 9903, 61919}},
+{12664, 17, 58940, {1, 3, 1, 13, 5, 5, 15, 5, 429, 617, 383, 2495, 409, 15541, 11209, 20625, 58493}},
+{12665, 17, 58945, {1, 1, 7, 11, 25, 21, 113, 219, 459, 777, 289, 2435, 6665, 83, 22997, 6561, 82923}},
+{12666, 17, 58952, {1, 1, 1, 7, 19, 53, 37, 249, 273, 639, 2007, 1463, 7819, 9013, 19539, 41235, 58059}},
+{12667, 17, 58960, {1, 1, 3, 11, 13, 51, 97, 55, 237, 159, 1305, 3705, 2527, 13065, 13873, 10275, 3769}},
+{12668, 17, 58965, {1, 1, 5, 7, 13, 49, 41, 13, 301, 461, 1169, 3805, 7163, 4133, 17255, 48283, 87059}},
+{12669, 17, 58986, {1, 3, 7, 15, 9, 19, 45, 195, 445, 145, 543, 2839, 315, 10991, 3317, 46501, 29209}},
+{12670, 17, 59000, {1, 1, 3, 5, 23, 51, 53, 119, 217, 747, 1307, 3039, 5523, 5891, 21035, 56471, 80305}},
+{12671, 17, 59006, {1, 3, 1, 3, 23, 17, 97, 71, 7, 839, 229, 3407, 3025, 1989, 16599, 38755, 11139}},
+{12672, 17, 59027, {1, 1, 7, 7, 7, 19, 67, 43, 293, 191, 1549, 1621, 7083, 11633, 1899, 4515, 89753}},
+{12673, 17, 59034, {1, 3, 7, 11, 1, 23, 17, 63, 265, 709, 453, 1309, 6861, 7257, 17705, 28565, 15231}},
+{12674, 17, 59052, {1, 3, 5, 13, 1, 53, 99, 79, 241, 771, 497, 987, 2353, 6931, 227, 57781, 109583}},
+{12675, 17, 59058, {1, 3, 3, 5, 31, 47, 17, 97, 93, 119, 2045, 3597, 7983, 4993, 30659, 3419, 32803}},
+{12676, 17, 59081, {1, 3, 7, 1, 11, 41, 3, 7, 155, 627, 979, 2405, 7467, 6763, 28523, 56493, 1291}},
+{12677, 17, 59082, {1, 1, 1, 7, 3, 43, 13, 187, 415, 1001, 667, 1371, 8075, 12855, 27215, 9399, 70657}},
+{12678, 17, 59089, {1, 3, 1, 9, 29, 53, 117, 17, 443, 381, 507, 643, 5891, 10725, 20251, 497, 101313}},
+{12679, 17, 59096, {1, 3, 3, 1, 31, 47, 59, 75, 173, 347, 1, 117, 3639, 10231, 863, 56795, 56107}},
+{12680, 17, 59118, {1, 3, 1, 15, 11, 41, 97, 251, 177, 275, 1849, 1281, 3659, 9709, 16239, 7445, 47661}},
+{12681, 17, 59123, {1, 3, 3, 5, 13, 1, 27, 251, 89, 863, 685, 3915, 2201, 4313, 32083, 37171, 120885}},
+{12682, 17, 59126, {1, 3, 3, 3, 3, 11, 77, 135, 147, 475, 505, 611, 4763, 9445, 28639, 51343, 119093}},
+{12683, 17, 59132, {1, 3, 7, 1, 11, 9, 67, 73, 375, 977, 1011, 1621, 6623, 8077, 26321, 7461, 130637}},
+{12684, 17, 59135, {1, 3, 5, 15, 15, 59, 63, 217, 117, 375, 1151, 3451, 5843, 13221, 20673, 10817, 57711}},
+{12685, 17, 59150, {1, 1, 3, 5, 19, 5, 9, 101, 321, 815, 451, 719, 523, 1299, 27823, 48041, 45939}},
+{12686, 17, 59174, {1, 1, 1, 9, 5, 49, 59, 59, 409, 5, 1075, 21, 7837, 4543, 3085, 55473, 89309}},
+{12687, 17, 59177, {1, 3, 3, 13, 9, 31, 93, 181, 153, 795, 713, 933, 6001, 9075, 29781, 14029, 46361}},
+{12688, 17, 59185, {1, 3, 5, 3, 9, 21, 79, 129, 361, 627, 743, 3041, 5381, 3627, 12581, 35183, 83183}},
+{12689, 17, 59195, {1, 3, 3, 3, 29, 29, 93, 187, 341, 727, 181, 133, 6525, 5673, 2739, 23349, 62505}},
+{12690, 17, 59203, {1, 3, 5, 13, 27, 59, 127, 149, 321, 613, 1543, 1537, 2909, 5139, 3755, 49285, 35183}},
+{12691, 17, 59206, {1, 3, 3, 9, 5, 31, 19, 173, 137, 19, 799, 1847, 3897, 15775, 22411, 55405, 95713}},
+{12692, 17, 59234, {1, 3, 5, 5, 31, 1, 87, 97, 481, 797, 459, 793, 4339, 5443, 31717, 6691, 68841}},
+{12693, 17, 59248, {1, 3, 3, 5, 3, 9, 123, 21, 393, 683, 1007, 971, 729, 7113, 2811, 51183, 37093}},
+{12694, 17, 59258, {1, 3, 5, 5, 27, 31, 19, 227, 123, 937, 763, 2117, 3825, 9151, 95, 54963, 62919}},
+{12695, 17, 59260, {1, 3, 1, 3, 23, 21, 21, 7, 7, 165, 99, 3073, 91, 8725, 17613, 47119, 41441}},
+{12696, 17, 59270, {1, 3, 7, 9, 29, 49, 117, 49, 205, 605, 1567, 3323, 1559, 10949, 14349, 34951, 99901}},
+{12697, 17, 59284, {1, 1, 1, 1, 15, 41, 31, 133, 439, 305, 719, 147, 6849, 5947, 31749, 45171, 15265}},
+{12698, 17, 59291, {1, 1, 5, 11, 19, 37, 13, 253, 385, 625, 1801, 1191, 547, 12025, 17971, 54127, 97323}},
+{12699, 17, 59293, {1, 3, 5, 5, 27, 9, 57, 245, 59, 211, 1195, 763, 6743, 6309, 25759, 26633, 27497}},
+{12700, 17, 59297, {1, 3, 5, 5, 9, 51, 49, 29, 213, 855, 305, 3961, 3187, 6815, 19015, 2539, 81705}},
+{12701, 17, 59312, {1, 1, 5, 7, 11, 61, 123, 163, 127, 871, 463, 2279, 5931, 2913, 23215, 40215, 91373}},
+{12702, 17, 59315, {1, 1, 7, 1, 29, 57, 55, 189, 285, 603, 747, 3753, 3359, 10277, 25319, 17569, 80125}},
+{12703, 17, 59327, {1, 3, 1, 9, 7, 53, 9, 55, 117, 495, 2045, 2487, 1625, 775, 17773, 62159, 79537}},
+{12704, 17, 59332, {1, 1, 5, 1, 1, 11, 67, 79, 57, 677, 2045, 3913, 853, 3581, 10509, 35097, 24585}},
+{12705, 17, 59347, {1, 3, 7, 7, 19, 15, 13, 237, 297, 807, 657, 2229, 2931, 10283, 49, 56485, 113889}},
+{12706, 17, 59354, {1, 3, 5, 13, 11, 23, 37, 229, 253, 411, 39, 1069, 3683, 12141, 11087, 64875, 62991}},
+{12707, 17, 59363, {1, 1, 1, 1, 13, 11, 21, 227, 305, 1021, 1039, 3095, 4621, 5723, 31989, 30681, 58487}},
+{12708, 17, 59369, {1, 3, 3, 5, 17, 47, 127, 65, 85, 961, 277, 549, 2111, 4183, 771, 11921, 111489}},
+{12709, 17, 59377, {1, 3, 3, 5, 31, 39, 89, 51, 277, 705, 375, 1603, 2793, 7425, 25065, 44945, 48391}},
+{12710, 17, 59406, {1, 1, 5, 7, 9, 45, 21, 217, 183, 65, 625, 1239, 4241, 8043, 13615, 5611, 82501}},
+{12711, 17, 59413, {1, 1, 7, 13, 15, 51, 29, 35, 73, 601, 233, 3117, 3031, 4229, 4299, 62761, 45291}},
+{12712, 17, 59423, {1, 3, 5, 5, 27, 55, 7, 1, 333, 501, 913, 1939, 5131, 5597, 1271, 30195, 20947}},
+{12713, 17, 59434, {1, 3, 5, 15, 19, 27, 43, 111, 435, 615, 811, 2113, 2503, 7553, 1619, 24773, 40881}},
+{12714, 17, 59441, {1, 3, 5, 11, 11, 31, 21, 147, 151, 141, 527, 1839, 339, 1225, 29621, 19691, 22031}},
+{12715, 17, 59442, {1, 1, 3, 13, 23, 35, 61, 181, 221, 837, 241, 3033, 1849, 12563, 11387, 3027, 33419}},
+{12716, 17, 59456, {1, 3, 3, 7, 1, 39, 125, 249, 231, 575, 1847, 197, 3969, 12945, 10257, 27227, 94097}},
+{12717, 17, 59465, {1, 3, 1, 11, 19, 7, 85, 119, 37, 253, 1575, 447, 6947, 14399, 32095, 15385, 62917}},
+{12718, 17, 59479, {1, 3, 7, 11, 23, 53, 113, 193, 253, 651, 1717, 447, 4055, 13675, 18479, 28375, 66475}},
+{12719, 17, 59501, {1, 1, 7, 3, 17, 27, 13, 209, 67, 271, 121, 1565, 2589, 8033, 3939, 14181, 111787}},
+{12720, 17, 59504, {1, 1, 3, 3, 5, 57, 75, 87, 165, 947, 967, 3353, 2055, 16195, 3701, 62637, 58343}},
+{12721, 17, 59507, {1, 1, 7, 13, 31, 41, 125, 111, 253, 257, 57, 679, 3333, 8259, 26331, 15883, 95023}},
+{12722, 17, 59514, {1, 3, 7, 11, 1, 47, 5, 249, 353, 271, 1121, 1935, 4971, 8447, 9983, 55959, 66179}},
+{12723, 17, 59523, {1, 3, 5, 11, 1, 61, 101, 43, 97, 241, 687, 4027, 4319, 4905, 12357, 51099, 97093}},
+{12724, 17, 59525, {1, 1, 3, 15, 25, 25, 117, 139, 475, 961, 1585, 2795, 2411, 11049, 18209, 15511, 43193}},
+{12725, 17, 59526, {1, 3, 3, 9, 9, 11, 107, 15, 189, 27, 289, 3111, 851, 3401, 31981, 7181, 47533}},
+{12726, 17, 59537, {1, 1, 5, 15, 31, 57, 37, 77, 205, 707, 1505, 1343, 629, 13335, 6719, 35405, 38905}},
+{12727, 17, 59543, {1, 3, 7, 7, 21, 63, 35, 125, 507, 285, 621, 2257, 3009, 13703, 9761, 54927, 16925}},
+{12728, 17, 59560, {1, 1, 1, 11, 11, 53, 37, 17, 167, 663, 1349, 1395, 7721, 9329, 2161, 37093, 52425}},
+{12729, 17, 59563, {1, 1, 7, 9, 1, 15, 113, 53, 87, 133, 131, 847, 609, 14737, 1639, 15511, 46987}},
+{12730, 17, 59566, {1, 1, 7, 7, 25, 21, 125, 149, 201, 791, 1323, 2817, 1141, 289, 14349, 64461, 76575}},
+{12731, 17, 59577, {1, 3, 3, 7, 15, 1, 123, 227, 83, 967, 2039, 3205, 715, 10787, 11235, 50375, 66911}},
+{12732, 17, 59580, {1, 3, 3, 11, 9, 45, 41, 57, 327, 903, 1705, 3947, 3173, 1035, 25529, 15217, 80795}},
+{12733, 17, 59586, {1, 3, 1, 13, 15, 63, 69, 57, 479, 277, 1641, 3465, 2629, 9901, 5781, 55101, 33049}},
+{12734, 17, 59597, {1, 1, 3, 3, 31, 25, 57, 189, 491, 335, 373, 3069, 1623, 10781, 6559, 27057, 111491}},
+{12735, 17, 59612, {1, 3, 3, 15, 19, 57, 67, 225, 343, 93, 315, 1011, 4437, 10371, 27927, 51269, 65653}},
+{12736, 17, 59615, {1, 3, 5, 5, 21, 43, 105, 153, 65, 167, 369, 3167, 785, 7509, 3753, 9035, 29039}},
+{12737, 17, 59622, {1, 1, 7, 3, 17, 9, 113, 21, 175, 967, 13, 2701, 5667, 9761, 20267, 33497, 88819}},
+{12738, 17, 59631, {1, 1, 1, 7, 9, 61, 121, 205, 283, 259, 2027, 2361, 3995, 6787, 26867, 61681, 96149}},
+{12739, 17, 59657, {1, 3, 3, 13, 31, 37, 125, 151, 317, 947, 423, 2907, 6905, 13247, 27997, 4755, 73173}},
+{12740, 17, 59660, {1, 1, 7, 13, 1, 63, 85, 75, 33, 483, 85, 1583, 4783, 14003, 31147, 12643, 99447}},
+{12741, 17, 59665, {1, 1, 1, 7, 31, 5, 93, 179, 213, 857, 3, 1015, 1481, 2413, 28759, 13941, 24851}},
+{12742, 17, 59671, {1, 1, 5, 5, 5, 35, 73, 57, 469, 885, 1951, 3599, 5555, 7259, 22599, 7627, 109227}},
+{12743, 17, 59675, {1, 1, 5, 13, 1, 1, 69, 107, 473, 793, 1851, 887, 2241, 7851, 21821, 25431, 118565}},
+{12744, 17, 59688, {1, 1, 1, 3, 15, 51, 57, 175, 91, 113, 1671, 925, 2187, 1097, 28793, 45819, 41855}},
+{12745, 17, 59706, {1, 1, 3, 3, 15, 51, 99, 177, 379, 713, 1273, 3245, 5515, 14657, 28981, 1197, 29283}},
+{12746, 17, 59708, {1, 3, 3, 15, 13, 27, 29, 7, 17, 373, 779, 1589, 3077, 13673, 31029, 43765, 74339}},
+{12747, 17, 59713, {1, 1, 3, 1, 25, 17, 15, 223, 219, 569, 155, 1307, 7143, 7975, 22581, 53223, 44271}},
+{12748, 17, 59714, {1, 1, 1, 7, 11, 23, 67, 177, 189, 267, 1799, 2453, 2367, 4193, 1827, 10191, 12265}},
+{12749, 17, 59720, {1, 3, 3, 11, 3, 29, 121, 231, 211, 191, 1803, 1171, 6801, 4007, 14111, 42951, 8311}},
+{12750, 17, 59737, {1, 3, 3, 11, 9, 23, 11, 231, 349, 47, 1645, 345, 3681, 12227, 29955, 32131, 391}},
+{12751, 17, 59743, {1, 1, 3, 11, 27, 17, 17, 49, 463, 173, 1993, 2339, 3763, 1931, 29969, 55579, 114805}},
+{12752, 17, 59744, {1, 3, 5, 15, 5, 21, 105, 69, 173, 771, 815, 3807, 577, 12589, 32193, 37601, 23961}},
+{12753, 17, 59749, {1, 1, 3, 9, 21, 63, 57, 213, 327, 765, 333, 2065, 719, 6159, 15769, 49335, 2289}},
+{12754, 17, 59756, {1, 3, 3, 1, 27, 51, 13, 87, 465, 729, 507, 2811, 6721, 14279, 31733, 56165, 78169}},
+{12755, 17, 59783, {1, 1, 1, 9, 25, 1, 47, 37, 407, 623, 1409, 3703, 4491, 3037, 8129, 13547, 50517}},
+{12756, 17, 59784, {1, 3, 5, 13, 5, 51, 127, 225, 215, 377, 1013, 2387, 4237, 1317, 5245, 17535, 100707}},
+{12757, 17, 59787, {1, 3, 5, 13, 31, 25, 123, 243, 317, 505, 483, 1743, 3097, 4139, 4525, 63143, 47665}},
+{12758, 17, 59795, {1, 3, 3, 13, 27, 19, 21, 187, 211, 471, 1931, 2877, 3635, 9233, 12385, 15741, 50843}},
+{12759, 17, 59804, {1, 1, 3, 13, 23, 33, 71, 45, 371, 621, 1057, 1605, 6329, 3763, 8613, 2965, 8141}},
+{12760, 17, 59811, {1, 1, 5, 7, 7, 17, 33, 209, 293, 35, 1665, 3721, 6245, 14567, 15349, 16195, 59757}},
+{12761, 17, 59814, {1, 1, 7, 7, 31, 19, 47, 83, 277, 323, 1225, 969, 2193, 10175, 27657, 50265, 9817}},
+{12762, 17, 59823, {1, 1, 5, 7, 15, 21, 103, 95, 189, 737, 309, 357, 5953, 9701, 15757, 20753, 88647}},
+{12763, 17, 59838, {1, 1, 5, 13, 5, 13, 61, 235, 333, 889, 1559, 1653, 1871, 10631, 18067, 47037, 9507}},
+{12764, 17, 59840, {1, 3, 7, 1, 31, 61, 69, 159, 41, 107, 807, 1517, 3551, 3435, 6151, 50025, 126949}},
+{12765, 17, 59846, {1, 1, 7, 15, 7, 41, 55, 103, 9, 105, 1397, 3955, 7723, 3389, 32435, 36005, 73733}},
+{12766, 17, 59849, {1, 1, 1, 13, 15, 59, 43, 151, 321, 215, 411, 3103, 7455, 14041, 1673, 56425, 59085}},
+{12767, 17, 59855, {1, 1, 1, 1, 5, 39, 81, 183, 509, 455, 753, 3743, 227, 7807, 23747, 42289, 122765}},
+{12768, 17, 59860, {1, 1, 7, 3, 9, 29, 89, 131, 141, 851, 1221, 67, 3117, 1329, 13151, 36827, 34313}},
+{12769, 17, 59867, {1, 3, 1, 5, 9, 29, 11, 189, 389, 79, 1903, 835, 6043, 8953, 18985, 8305, 51939}},
+{12770, 17, 59869, {1, 3, 5, 3, 9, 49, 47, 43, 193, 917, 795, 2719, 5709, 9993, 30637, 26841, 93113}},
+{12771, 17, 59885, {1, 3, 7, 5, 13, 15, 85, 169, 315, 963, 617, 1191, 6739, 11535, 3423, 6695, 2047}},
+{12772, 17, 59888, {1, 3, 1, 3, 5, 49, 41, 255, 131, 255, 825, 1485, 7005, 10107, 3913, 4731, 33199}},
+{12773, 17, 59893, {1, 3, 1, 9, 27, 63, 109, 29, 183, 381, 591, 617, 1187, 4381, 30543, 9933, 109785}},
+{12774, 17, 59904, {1, 3, 7, 7, 13, 29, 125, 105, 353, 677, 623, 1553, 5435, 10853, 16663, 42277, 64333}},
+{12775, 17, 59919, {1, 3, 3, 11, 3, 47, 49, 41, 249, 497, 963, 237, 625, 11303, 6871, 60441, 39559}},
+{12776, 17, 59922, {1, 3, 3, 1, 1, 27, 107, 253, 59, 445, 1761, 2865, 7117, 2363, 4007, 46047, 10811}},
+{12777, 17, 59927, {1, 3, 5, 5, 25, 13, 17, 107, 321, 691, 351, 577, 5001, 9437, 12451, 44997, 42727}},
+{12778, 17, 59937, {1, 3, 1, 9, 1, 31, 87, 117, 111, 379, 1989, 1155, 4777, 8563, 14585, 33375, 66985}},
+{12779, 17, 59940, {1, 3, 5, 5, 9, 51, 79, 135, 89, 929, 277, 763, 5569, 15545, 28393, 56921, 102093}},
+{12780, 17, 59944, {1, 1, 3, 7, 7, 55, 15, 37, 3, 439, 577, 2051, 101, 13655, 11959, 38127, 6639}},
+{12781, 17, 59947, {1, 1, 3, 9, 21, 11, 27, 221, 465, 565, 1313, 1405, 2421, 10543, 18369, 33751, 87785}},
+{12782, 17, 59949, {1, 3, 5, 11, 21, 39, 105, 231, 469, 711, 997, 427, 5797, 3249, 15141, 29413, 66509}},
+{12783, 17, 59961, {1, 3, 7, 5, 25, 31, 111, 37, 229, 773, 193, 553, 673, 4693, 24441, 8713, 121203}},
+{12784, 17, 59975, {1, 3, 1, 9, 23, 27, 103, 7, 183, 549, 1433, 2831, 3383, 13229, 10005, 14135, 15967}},
+{12785, 17, 59981, {1, 3, 3, 11, 11, 59, 11, 251, 373, 399, 255, 1177, 5493, 13559, 29037, 23405, 79495}},
+{12786, 17, 59994, {1, 3, 1, 11, 25, 45, 69, 115, 153, 259, 527, 9, 5807, 6015, 3765, 61621, 8645}},
+{12787, 17, 59999, {1, 3, 3, 9, 19, 5, 113, 191, 345, 655, 429, 3975, 4297, 5723, 5345, 64457, 79031}},
+{12788, 17, 60018, {1, 3, 7, 7, 15, 59, 5, 87, 289, 1005, 931, 2403, 485, 16043, 15623, 39253, 61377}},
+{12789, 17, 60023, {1, 3, 3, 9, 17, 53, 31, 9, 217, 711, 1007, 1375, 2733, 13735, 19825, 59741, 83827}},
+{12790, 17, 60024, {1, 1, 3, 15, 11, 11, 41, 195, 79, 1013, 1353, 1961, 7365, 7533, 13315, 8441, 90705}},
+{12791, 17, 60039, {1, 1, 5, 7, 23, 17, 93, 165, 371, 495, 865, 2753, 15, 10729, 16553, 6039, 96721}},
+{12792, 17, 60043, {1, 3, 3, 3, 25, 25, 67, 119, 485, 63, 75, 2365, 4711, 16129, 5589, 50621, 1203}},
+{12793, 17, 60048, {1, 1, 7, 1, 27, 57, 49, 79, 479, 79, 683, 753, 345, 2007, 18983, 42729, 56369}},
+{12794, 17, 60054, {1, 1, 7, 7, 1, 23, 9, 155, 425, 735, 1625, 2271, 7875, 11219, 12147, 52351, 55845}},
+{12795, 17, 60073, {1, 1, 1, 9, 13, 11, 67, 139, 259, 59, 1593, 1207, 237, 11683, 24719, 27689, 115617}},
+{12796, 17, 60079, {1, 1, 5, 7, 7, 15, 9, 171, 35, 131, 133, 3939, 1401, 6347, 4051, 64235, 68581}},
+{12797, 17, 60082, {1, 3, 3, 1, 27, 21, 29, 119, 201, 527, 763, 203, 1139, 3951, 3341, 17023, 13493}},
+{12798, 17, 60102, {1, 1, 1, 15, 27, 31, 97, 203, 255, 573, 781, 4095, 3381, 363, 32733, 34517, 77973}},
+{12799, 17, 60108, {1, 1, 3, 9, 29, 9, 115, 207, 267, 513, 1071, 3943, 5045, 10071, 6627, 18043, 44289}},
+{12800, 17, 60111, {1, 1, 7, 7, 29, 25, 51, 31, 305, 239, 197, 3825, 2363, 4903, 16237, 37571, 66545}},
+{12801, 17, 60120, {1, 1, 5, 11, 29, 11, 63, 145, 185, 359, 249, 1179, 105, 1745, 28819, 40513, 74525}},
+{12802, 17, 60149, {1, 1, 7, 1, 15, 35, 39, 5, 139, 119, 2047, 3369, 2857, 11037, 30523, 24813, 89209}},
+{12803, 17, 60153, {1, 1, 5, 11, 9, 41, 97, 15, 357, 95, 361, 3, 3227, 8445, 16541, 30661, 84215}},
+{12804, 17, 60161, {1, 1, 7, 5, 11, 55, 77, 19, 331, 621, 893, 577, 1025, 1561, 32331, 59469, 67065}},
+{12805, 17, 60168, {1, 3, 7, 7, 17, 53, 55, 65, 295, 391, 445, 33, 5361, 669, 6447, 3833, 129463}},
+{12806, 17, 60176, {1, 3, 7, 5, 21, 5, 83, 207, 485, 597, 1429, 581, 6831, 2885, 24669, 35211, 69549}},
+{12807, 17, 60182, {1, 3, 3, 1, 3, 33, 69, 199, 427, 893, 1823, 1291, 4533, 11779, 18515, 17597, 79159}},
+{12808, 17, 60185, {1, 3, 1, 1, 17, 41, 91, 21, 509, 875, 777, 639, 4009, 12103, 12947, 58395, 36625}},
+{12809, 17, 60204, {1, 1, 7, 15, 13, 11, 19, 243, 365, 661, 1193, 279, 6055, 13921, 5811, 14337, 105375}},
+{12810, 17, 60212, {1, 3, 7, 3, 3, 51, 101, 175, 83, 921, 523, 3909, 8003, 1295, 4153, 4757, 107881}},
+{12811, 17, 60215, {1, 1, 1, 3, 19, 15, 39, 125, 401, 399, 381, 1123, 2339, 12231, 13387, 50829, 79263}},
+{12812, 17, 60219, {1, 3, 1, 1, 15, 13, 55, 181, 53, 671, 1929, 1003, 521, 15279, 1837, 11877, 79241}},
+{12813, 17, 60222, {1, 3, 3, 9, 23, 45, 21, 37, 1, 701, 1253, 2595, 6261, 4139, 24443, 6655, 109755}},
+{12814, 17, 60229, {1, 3, 7, 1, 1, 13, 57, 41, 95, 985, 1613, 3487, 7509, 213, 32139, 27869, 123589}},
+{12815, 17, 60234, {1, 3, 7, 11, 15, 27, 27, 97, 167, 755, 1331, 3961, 3067, 13827, 8983, 8755, 77847}},
+{12816, 17, 60241, {1, 1, 5, 13, 5, 59, 51, 193, 339, 837, 137, 3807, 2617, 14449, 11035, 16827, 24531}},
+{12817, 17, 60248, {1, 1, 7, 15, 17, 37, 67, 99, 261, 743, 275, 33, 8107, 4959, 9683, 19757, 36471}},
+{12818, 17, 60277, {1, 3, 5, 5, 29, 7, 107, 95, 235, 761, 1205, 3125, 4791, 4645, 25623, 6463, 121887}},
+{12819, 17, 60282, {1, 3, 1, 1, 19, 19, 73, 189, 243, 669, 489, 1927, 1651, 11391, 30699, 64719, 60359}},
+{12820, 17, 60287, {1, 3, 7, 3, 29, 47, 7, 21, 299, 739, 1605, 749, 5755, 11579, 793, 36845, 14695}},
+{12821, 17, 60303, {1, 1, 5, 15, 17, 53, 107, 49, 103, 505, 1191, 2881, 7435, 7515, 24237, 5397, 47003}},
+{12822, 17, 60306, {1, 1, 7, 15, 25, 45, 121, 157, 313, 709, 1519, 2195, 5487, 1789, 32401, 4197, 9329}},
+{12823, 17, 60327, {1, 3, 3, 11, 21, 17, 77, 153, 275, 765, 1943, 3395, 5807, 12809, 29891, 42579, 75565}},
+{12824, 17, 60333, {1, 3, 5, 11, 11, 3, 63, 9, 223, 441, 1047, 441, 867, 3399, 15813, 13, 25293}},
+{12825, 17, 60334, {1, 1, 7, 1, 17, 25, 1, 7, 211, 117, 1417, 1057, 3369, 13211, 11437, 20877, 114867}},
+{12826, 17, 60336, {1, 1, 1, 15, 5, 41, 89, 165, 343, 447, 55, 1013, 8179, 12295, 18615, 23885, 46149}},
+{12827, 17, 60345, {1, 1, 5, 1, 15, 37, 109, 141, 323, 151, 1669, 1365, 3047, 13145, 30355, 12377, 102467}},
+{12828, 17, 60359, {1, 1, 3, 15, 15, 49, 83, 127, 285, 715, 981, 1153, 3019, 11071, 24229, 63807, 16315}},
+{12829, 17, 60368, {1, 1, 3, 1, 23, 35, 21, 179, 83, 929, 1033, 643, 3591, 10363, 7739, 259, 106879}},
+{12830, 17, 60380, {1, 1, 5, 7, 19, 9, 63, 241, 387, 851, 1709, 1161, 7469, 2093, 6169, 6085, 29851}},
+{12831, 17, 60389, {1, 3, 7, 5, 17, 59, 99, 87, 189, 853, 193, 1191, 5683, 15865, 27791, 55575, 13479}},
+{12832, 17, 60390, {1, 3, 3, 3, 25, 51, 81, 129, 365, 319, 179, 2863, 511, 14471, 3689, 59505, 80105}},
+{12833, 17, 60394, {1, 1, 1, 15, 5, 33, 69, 35, 429, 715, 1781, 783, 1089, 8969, 26987, 23519, 34227}},
+{12834, 17, 60407, {1, 3, 5, 9, 1, 51, 9, 121, 325, 945, 2025, 1985, 7337, 10837, 21299, 20591, 76905}},
+{12835, 17, 60414, {1, 3, 7, 3, 15, 51, 19, 109, 297, 491, 15, 1905, 1479, 1997, 18129, 43861, 84925}},
+{12836, 17, 60419, {1, 1, 3, 5, 7, 21, 1, 137, 207, 943, 1171, 2019, 6687, 10683, 20937, 34033, 43907}},
+{12837, 17, 60426, {1, 1, 1, 11, 25, 21, 47, 227, 247, 933, 471, 955, 4299, 5605, 18469, 62357, 98273}},
+{12838, 17, 60428, {1, 1, 5, 13, 21, 39, 41, 23, 493, 311, 1401, 537, 2919, 11519, 12597, 58321, 41401}},
+{12839, 17, 60431, {1, 1, 7, 5, 31, 55, 93, 151, 219, 765, 1247, 2775, 7167, 13413, 17071, 57969, 114069}},
+{12840, 17, 60440, {1, 3, 1, 15, 31, 41, 85, 161, 379, 337, 1639, 933, 3511, 925, 3523, 52379, 18421}},
+{12841, 17, 60450, {1, 3, 3, 11, 17, 17, 71, 11, 291, 305, 1295, 1175, 1803, 6247, 26523, 46467, 126999}},
+{12842, 17, 60469, {1, 1, 1, 13, 9, 43, 113, 7, 1, 443, 719, 3045, 2527, 5233, 13969, 50463, 115629}},
+{12843, 17, 60473, {1, 1, 1, 13, 9, 31, 87, 119, 351, 53, 985, 2017, 1187, 10429, 13719, 41383, 12749}},
+{12844, 17, 60474, {1, 1, 1, 15, 23, 17, 5, 215, 383, 299, 305, 3577, 7707, 6927, 28591, 44287, 65697}},
+{12845, 17, 60484, {1, 1, 5, 7, 23, 61, 89, 235, 97, 463, 237, 2117, 5503, 13693, 28231, 7745, 73631}},
+{12846, 17, 60496, {1, 3, 7, 3, 17, 43, 73, 245, 145, 267, 855, 187, 6167, 3999, 9935, 14347, 57727}},
+{12847, 17, 60502, {1, 1, 7, 3, 25, 47, 11, 221, 425, 527, 1341, 3973, 4635, 16321, 30021, 48547, 109409}},
+{12848, 17, 60508, {1, 3, 1, 13, 5, 11, 41, 191, 121, 219, 1315, 583, 2997, 5883, 31689, 64835, 35351}},
+{12849, 17, 60511, {1, 1, 3, 3, 15, 47, 49, 115, 107, 757, 329, 1653, 4633, 14605, 1579, 62413, 88685}},
+{12850, 17, 60522, {1, 1, 1, 5, 19, 47, 63, 131, 427, 335, 269, 3581, 7613, 15685, 16957, 30487, 94965}},
+{12851, 17, 60529, {1, 1, 3, 15, 31, 11, 77, 115, 467, 249, 247, 651, 3769, 3701, 21627, 36219, 77309}},
+{12852, 17, 60530, {1, 3, 1, 5, 5, 29, 45, 21, 37, 733, 1773, 2467, 2747, 9391, 5449, 23285, 20089}},
+{12853, 17, 60536, {1, 3, 5, 13, 29, 31, 51, 199, 77, 711, 1313, 3303, 2675, 177, 7915, 37129, 123641}},
+{12854, 17, 60551, {1, 3, 7, 15, 17, 17, 99, 43, 9, 699, 491, 669, 1313, 1377, 30015, 59261, 97321}},
+{12855, 17, 60557, {1, 3, 1, 13, 9, 13, 21, 199, 249, 775, 399, 897, 2205, 15357, 17281, 3193, 255}},
+{12856, 17, 60566, {1, 3, 1, 13, 7, 23, 7, 181, 65, 253, 199, 333, 6507, 4409, 13319, 30165, 95191}},
+{12857, 17, 60576, {1, 3, 3, 1, 31, 9, 31, 71, 301, 867, 1655, 2065, 597, 15247, 3019, 31763, 91889}},
+{12858, 17, 60579, {1, 3, 5, 5, 3, 35, 113, 133, 39, 1013, 991, 3521, 5805, 87, 32393, 28619, 34325}},
+{12859, 17, 60585, {1, 3, 1, 9, 15, 27, 45, 85, 61, 99, 1085, 3251, 7085, 4137, 27443, 42581, 94031}},
+{12860, 17, 60588, {1, 1, 5, 7, 11, 49, 97, 129, 339, 259, 821, 165, 833, 11383, 21629, 17473, 2947}},
+{12861, 17, 60600, {1, 3, 3, 3, 11, 7, 27, 231, 169, 847, 1767, 1823, 3855, 14277, 12457, 55825, 14377}},
+{12862, 17, 60613, {1, 1, 7, 3, 27, 5, 47, 193, 207, 747, 271, 3155, 1097, 2229, 4919, 22327, 12659}},
+{12863, 17, 60628, {1, 1, 5, 3, 27, 29, 105, 199, 31, 73, 1741, 2173, 4577, 3917, 31513, 45983, 118015}},
+{12864, 17, 60631, {1, 1, 3, 1, 19, 5, 23, 249, 35, 891, 1105, 1907, 5453, 1877, 1965, 3169, 107091}},
+{12865, 17, 60648, {1, 1, 7, 9, 11, 47, 57, 171, 255, 661, 1925, 2223, 525, 4775, 12327, 8067, 47083}},
+{12866, 17, 60651, {1, 3, 3, 11, 29, 43, 37, 33, 459, 117, 7, 1739, 3585, 7429, 2217, 9533, 95299}},
+{12867, 17, 60653, {1, 1, 5, 11, 23, 3, 33, 13, 45, 201, 467, 597, 4891, 2673, 32407, 56935, 121991}},
+{12868, 17, 60671, {1, 1, 7, 5, 29, 63, 7, 59, 417, 547, 17, 3701, 5775, 1079, 26527, 47187, 14827}},
+{12869, 17, 60673, {1, 1, 5, 3, 27, 11, 85, 129, 377, 497, 1659, 1965, 581, 15075, 31265, 195, 62307}},
+{12870, 17, 60691, {1, 1, 3, 9, 3, 57, 33, 57, 279, 955, 741, 955, 6501, 8069, 27305, 15363, 34715}},
+{12871, 17, 60697, {1, 3, 7, 13, 29, 23, 25, 171, 201, 529, 661, 4089, 5755, 12459, 31269, 9763, 53217}},
+{12872, 17, 60700, {1, 3, 7, 1, 3, 19, 27, 201, 261, 421, 1487, 2907, 547, 15791, 7661, 42871, 116343}},
+{12873, 17, 60714, {1, 3, 7, 9, 5, 59, 51, 91, 7, 399, 2001, 661, 6577, 7473, 5439, 29073, 3391}},
+{12874, 17, 60724, {1, 1, 7, 1, 23, 39, 119, 105, 113, 913, 1097, 2547, 8143, 11409, 23197, 59527, 55677}},
+{12875, 17, 60728, {1, 3, 3, 15, 31, 35, 103, 207, 247, 801, 1821, 1995, 4437, 12891, 659, 15687, 53}},
+{12876, 17, 60733, {1, 3, 3, 5, 13, 5, 45, 187, 231, 661, 1553, 2909, 3715, 4499, 14773, 5957, 24171}},
+{12877, 17, 60736, {1, 1, 1, 11, 3, 53, 93, 29, 379, 713, 299, 445, 2815, 9825, 30941, 22413, 91563}},
+{12878, 17, 60745, {1, 3, 1, 1, 27, 31, 111, 83, 349, 895, 1007, 2649, 7139, 5863, 27739, 53099, 6837}},
+{12879, 17, 60746, {1, 3, 1, 5, 23, 57, 121, 229, 487, 405, 2001, 2761, 3011, 2219, 10711, 31139, 83809}},
+{12880, 17, 60753, {1, 3, 7, 5, 13, 51, 37, 181, 359, 909, 2001, 793, 1143, 9219, 5111, 23021, 126081}},
+{12881, 17, 60754, {1, 3, 1, 13, 27, 27, 99, 25, 189, 129, 1831, 1005, 8119, 2557, 26985, 63447, 89693}},
+{12882, 17, 60782, {1, 1, 7, 5, 1, 21, 79, 33, 99, 7, 433, 1343, 3121, 3705, 477, 41191, 13749}},
+{12883, 17, 60784, {1, 1, 5, 5, 29, 53, 75, 243, 35, 461, 1399, 129, 177, 6533, 22209, 23503, 43819}},
+{12884, 17, 60790, {1, 3, 7, 7, 31, 37, 109, 9, 255, 263, 35, 3451, 7629, 9849, 10387, 3165, 120623}},
+{12885, 17, 60793, {1, 3, 5, 3, 27, 53, 93, 111, 239, 723, 293, 1481, 4427, 13623, 1989, 47705, 122069}},
+{12886, 17, 60805, {1, 3, 7, 7, 31, 37, 37, 213, 191, 627, 1821, 3621, 2875, 15759, 17525, 50969, 35311}},
+{12887, 17, 60830, {1, 3, 5, 5, 11, 41, 87, 233, 79, 251, 25, 1385, 3527, 7853, 5541, 36519, 42779}},
+{12888, 17, 60836, {1, 3, 1, 5, 9, 1, 117, 11, 61, 879, 553, 383, 6237, 15207, 3057, 28051, 59149}},
+{12889, 17, 60846, {1, 1, 1, 15, 15, 7, 37, 133, 81, 815, 893, 2281, 2459, 15325, 20107, 2289, 34535}},
+{12890, 17, 60851, {1, 1, 5, 11, 17, 3, 45, 159, 409, 643, 969, 1289, 4353, 10465, 16233, 55561, 111667}},
+{12891, 17, 60880, {1, 1, 5, 13, 23, 1, 79, 127, 485, 1013, 629, 791, 853, 9247, 26333, 1123, 17313}},
+{12892, 17, 60896, {1, 1, 5, 11, 27, 17, 97, 157, 479, 421, 1739, 3257, 2419, 6673, 2759, 19399, 120305}},
+{12893, 17, 60905, {1, 3, 5, 1, 3, 43, 71, 55, 111, 949, 1957, 3777, 3409, 8229, 26585, 49221, 33639}},
+{12894, 17, 60923, {1, 3, 7, 9, 17, 45, 71, 71, 417, 1007, 213, 1069, 2693, 5065, 23489, 33363, 120459}},
+{12895, 17, 60925, {1, 1, 1, 1, 25, 47, 81, 251, 341, 101, 1941, 1133, 3205, 4141, 26561, 56095, 37193}},
+{12896, 17, 60932, {1, 1, 3, 7, 25, 45, 97, 95, 135, 871, 949, 3489, 7593, 10717, 26163, 12711, 76989}},
+{12897, 17, 60939, {1, 3, 1, 9, 3, 11, 35, 7, 471, 509, 1335, 385, 1297, 11201, 28553, 51609, 45351}},
+{12898, 17, 60942, {1, 1, 5, 11, 21, 23, 105, 31, 125, 5, 1721, 1503, 7807, 13093, 24873, 18467, 30183}},
+{12899, 17, 60953, {1, 3, 7, 15, 15, 57, 61, 213, 79, 655, 517, 1031, 6719, 4807, 12805, 2605, 35407}},
+{12900, 17, 60956, {1, 1, 3, 15, 21, 5, 93, 61, 103, 945, 935, 115, 1281, 7735, 20723, 37211, 50039}},
+{12901, 17, 60959, {1, 3, 3, 15, 19, 51, 79, 187, 127, 205, 121, 701, 6065, 15185, 29343, 58249, 25331}},
+{12902, 17, 60963, {1, 3, 3, 15, 17, 49, 23, 163, 201, 809, 1203, 687, 1777, 695, 18779, 31571, 118383}},
+{12903, 17, 60969, {1, 1, 1, 5, 25, 45, 121, 223, 233, 193, 1459, 1889, 5537, 4421, 13659, 4591, 112563}},
+{12904, 17, 60978, {1, 3, 5, 3, 31, 37, 109, 15, 381, 373, 993, 3633, 641, 4411, 32265, 46481, 49195}},
+{12905, 17, 60980, {1, 3, 3, 11, 19, 21, 39, 67, 447, 829, 1163, 55, 2153, 15045, 6643, 48235, 59261}},
+{12906, 17, 60987, {1, 3, 3, 1, 7, 63, 37, 71, 35, 601, 1719, 447, 8009, 7235, 13225, 44103, 82409}},
+{12907, 17, 61007, {1, 3, 3, 7, 13, 33, 69, 115, 207, 807, 109, 2989, 3727, 9017, 29095, 11377, 122401}},
+{12908, 17, 61012, {1, 1, 3, 15, 9, 9, 57, 197, 115, 73, 1277, 1727, 5275, 11897, 12157, 34763, 58273}},
+{12909, 17, 61015, {1, 1, 3, 15, 19, 19, 127, 105, 289, 663, 877, 1303, 4901, 8897, 4803, 36853, 93361}},
+{12910, 17, 61025, {1, 1, 3, 7, 23, 29, 121, 29, 439, 795, 1469, 523, 7767, 12061, 15613, 57343, 21291}},
+{12911, 17, 61026, {1, 1, 1, 9, 25, 29, 15, 165, 383, 233, 91, 2065, 2741, 7809, 5325, 48581, 65551}},
+{12912, 17, 61038, {1, 1, 5, 15, 29, 19, 103, 143, 283, 597, 1055, 3525, 6115, 11083, 22497, 42893, 86849}},
+{12913, 17, 61040, {1, 1, 1, 15, 13, 43, 75, 157, 267, 519, 1231, 929, 1585, 16137, 1045, 4353, 63473}},
+{12914, 17, 61052, {1, 1, 1, 9, 17, 25, 73, 227, 145, 921, 1845, 2057, 3099, 15523, 8993, 14135, 37811}},
+{12915, 17, 61061, {1, 3, 3, 15, 17, 57, 107, 215, 271, 841, 1543, 2803, 625, 15359, 13341, 36879, 83191}},
+{12916, 17, 61074, {1, 3, 5, 13, 3, 17, 127, 81, 193, 253, 71, 3205, 1157, 1313, 27341, 49657, 96539}},
+{12917, 17, 61083, {1, 3, 1, 5, 27, 43, 1, 111, 23, 963, 1853, 925, 7401, 13999, 29797, 47125, 59955}},
+{12918, 17, 61085, {1, 3, 3, 1, 31, 55, 107, 121, 37, 159, 61, 577, 5711, 6745, 20077, 42333, 37105}},
+{12919, 17, 61086, {1, 1, 5, 3, 31, 11, 1, 7, 295, 515, 203, 707, 2919, 9619, 8877, 45143, 101861}},
+{12920, 17, 61096, {1, 3, 7, 11, 5, 23, 71, 9, 99, 947, 1141, 1651, 1903, 13607, 15433, 55005, 127639}},
+{12921, 17, 61119, {1, 1, 7, 3, 13, 61, 25, 111, 239, 243, 1069, 3551, 3339, 743, 29921, 21313, 54953}},
+{12922, 17, 61124, {1, 1, 3, 3, 23, 7, 21, 47, 367, 871, 1647, 2183, 2615, 2257, 30447, 25761, 110221}},
+{12923, 17, 61127, {1, 3, 7, 15, 13, 51, 115, 19, 277, 463, 475, 3467, 7313, 2477, 10841, 13585, 61449}},
+{12924, 17, 61128, {1, 1, 7, 9, 1, 27, 111, 209, 391, 621, 1047, 549, 2013, 549, 24213, 6369, 68691}},
+{12925, 17, 61133, {1, 1, 1, 11, 19, 59, 11, 107, 79, 1013, 357, 1729, 889, 12823, 6537, 35717, 42761}},
+{12926, 17, 61134, {1, 1, 3, 15, 29, 41, 49, 177, 309, 293, 1035, 1481, 1395, 2009, 7917, 365, 28981}},
+{12927, 17, 61146, {1, 3, 7, 11, 31, 19, 51, 113, 479, 347, 353, 929, 1089, 3373, 2807, 55201, 23137}},
+{12928, 17, 61155, {1, 3, 1, 15, 7, 55, 79, 191, 267, 701, 1885, 1241, 7085, 9835, 24239, 7609, 13967}},
+{12929, 17, 61161, {1, 1, 3, 15, 25, 33, 69, 5, 93, 375, 435, 2401, 1591, 8173, 17293, 20281, 63809}},
+{12930, 17, 61162, {1, 3, 5, 3, 9, 49, 63, 47, 217, 773, 1241, 1131, 7521, 15607, 24341, 20353, 122801}},
+{12931, 17, 61169, {1, 3, 7, 15, 21, 1, 57, 159, 279, 987, 1641, 3883, 1659, 7875, 24857, 33273, 88933}},
+{12932, 17, 61179, {1, 1, 3, 11, 3, 23, 45, 31, 279, 643, 1285, 471, 137, 15871, 13927, 52361, 118901}},
+{12933, 17, 61182, {1, 3, 1, 15, 27, 51, 83, 19, 299, 213, 1001, 897, 2751, 13085, 20841, 24891, 113173}},
+{12934, 17, 61190, {1, 1, 7, 5, 5, 27, 77, 77, 165, 489, 359, 1607, 3903, 16241, 641, 25999, 29279}},
+{12935, 17, 61201, {1, 3, 3, 7, 15, 23, 103, 49, 259, 519, 641, 1577, 3713, 12181, 287, 29483, 58505}},
+{12936, 17, 61208, {1, 1, 7, 13, 11, 29, 125, 45, 45, 167, 261, 2735, 2421, 15457, 5965, 44005, 82141}},
+{12937, 17, 61238, {1, 1, 3, 9, 25, 21, 9, 3, 57, 1017, 1359, 79, 6789, 7805, 20683, 25695, 38893}},
+{12938, 17, 61241, {1, 1, 7, 1, 29, 53, 87, 171, 51, 5, 9, 3033, 787, 10611, 15913, 35703, 70459}},
+{12939, 17, 61247, {1, 1, 3, 5, 1, 33, 111, 139, 477, 33, 1287, 3615, 5235, 15491, 2915, 47821, 55257}},
+{12940, 17, 61259, {1, 1, 1, 13, 5, 23, 55, 225, 303, 587, 1595, 307, 3809, 8093, 13297, 63213, 104317}},
+{12941, 17, 61267, {1, 1, 3, 15, 31, 29, 13, 33, 267, 481, 1039, 3805, 2549, 861, 12483, 61829, 127725}},
+{12942, 17, 61269, {1, 3, 5, 11, 23, 17, 23, 117, 333, 167, 1965, 1387, 5453, 15545, 123, 12991, 36281}},
+{12943, 17, 61295, {1, 3, 5, 1, 3, 9, 25, 55, 497, 951, 1377, 993, 6089, 4801, 32719, 31579, 126663}},
+{12944, 17, 61304, {1, 3, 5, 11, 15, 37, 103, 51, 509, 585, 769, 425, 835, 14027, 30265, 55735, 36655}},
+{12945, 17, 61309, {1, 1, 1, 13, 9, 49, 105, 61, 493, 3, 1663, 815, 8105, 16361, 32477, 30437, 61519}},
+{12946, 17, 61310, {1, 3, 7, 11, 29, 23, 105, 87, 119, 399, 1405, 1515, 7017, 12729, 13769, 29741, 30921}},
+{12947, 17, 61313, {1, 3, 7, 13, 13, 7, 93, 227, 489, 843, 923, 3373, 759, 5105, 9059, 21079, 101335}},
+{12948, 17, 61320, {1, 1, 1, 1, 29, 53, 119, 227, 171, 363, 289, 827, 425, 12827, 25791, 21587, 109567}},
+{12949, 17, 61325, {1, 1, 5, 11, 29, 29, 53, 127, 441, 219, 1049, 275, 525, 5535, 20907, 9299, 76319}},
+{12950, 17, 61334, {1, 3, 7, 15, 3, 53, 109, 61, 275, 391, 1147, 2953, 1439, 4417, 679, 10949, 35101}},
+{12951, 17, 61337, {1, 1, 5, 13, 9, 1, 109, 137, 249, 835, 721, 129, 2883, 13043, 31827, 36741, 107167}},
+{12952, 17, 61386, {1, 1, 5, 9, 27, 17, 117, 121, 111, 433, 743, 1987, 6839, 8439, 2533, 62135, 54281}},
+{12953, 17, 61399, {1, 3, 5, 15, 11, 61, 117, 103, 409, 485, 1047, 469, 2245, 7193, 2541, 9399, 88127}},
+{12954, 17, 61422, {1, 3, 1, 9, 3, 49, 111, 201, 87, 181, 1243, 3261, 1827, 10385, 13045, 58331, 107729}},
+{12955, 17, 61429, {1, 3, 5, 15, 13, 29, 61, 223, 227, 733, 1757, 755, 4231, 13537, 1509, 54623, 120221}},
+{12956, 17, 61436, {1, 1, 1, 15, 13, 9, 7, 233, 391, 689, 355, 1203, 5811, 7759, 2647, 54949, 51891}},
+{12957, 17, 61439, {1, 1, 3, 1, 3, 27, 95, 51, 497, 315, 915, 1055, 2917, 167, 1849, 26591, 102729}},
+{12958, 17, 61466, {1, 3, 7, 13, 1, 51, 3, 113, 437, 449, 1889, 2887, 4735, 5693, 8191, 12847, 52651}},
+{12959, 17, 61477, {1, 1, 7, 13, 1, 45, 41, 221, 403, 185, 1653, 1809, 6405, 9193, 1381, 36677, 43255}},
+{12960, 17, 61478, {1, 1, 5, 1, 25, 51, 109, 245, 291, 809, 1381, 3235, 5933, 10185, 18663, 15589, 39539}},
+{12961, 17, 61490, {1, 3, 3, 1, 27, 29, 3, 227, 275, 705, 489, 681, 323, 7453, 26005, 13791, 115219}},
+{12962, 17, 61495, {1, 3, 5, 1, 3, 51, 101, 75, 157, 529, 45, 3105, 3617, 13081, 21665, 50065, 117823}},
+{12963, 17, 61504, {1, 3, 5, 15, 9, 43, 41, 169, 391, 455, 1375, 253, 1257, 14427, 16325, 11571, 26361}},
+{12964, 17, 61514, {1, 1, 5, 7, 5, 41, 81, 173, 275, 225, 301, 335, 5473, 1509, 20897, 21951, 103967}},
+{12965, 17, 61516, {1, 3, 5, 1, 13, 27, 107, 19, 221, 609, 823, 1193, 665, 4947, 11967, 57373, 21665}},
+{12966, 17, 61521, {1, 3, 7, 13, 7, 11, 109, 59, 193, 103, 943, 595, 5121, 6159, 2103, 52863, 57541}},
+{12967, 17, 61527, {1, 3, 5, 3, 5, 51, 85, 227, 465, 1013, 601, 1687, 7615, 5991, 8635, 64487, 69967}},
+{12968, 17, 61531, {1, 3, 1, 11, 29, 49, 79, 25, 447, 119, 569, 383, 5261, 6209, 21965, 40863, 96593}},
+{12969, 17, 61540, {1, 1, 3, 13, 9, 49, 59, 93, 369, 789, 1373, 425, 3565, 13357, 17783, 46435, 129653}},
+{12970, 17, 61550, {1, 3, 7, 5, 5, 39, 51, 15, 421, 531, 1855, 2105, 5335, 8509, 20841, 44997, 48235}},
+{12971, 17, 61557, {1, 3, 7, 3, 27, 47, 113, 1, 453, 565, 1843, 243, 7663, 10697, 7725, 24485, 49435}},
+{12972, 17, 61562, {1, 1, 1, 11, 25, 25, 47, 1, 475, 831, 1833, 391, 5173, 14873, 14263, 36061, 26781}},
+{12973, 17, 61577, {1, 1, 7, 15, 21, 13, 5, 169, 241, 235, 547, 1565, 2053, 6877, 12811, 22213, 106907}},
+{12974, 17, 61583, {1, 3, 7, 1, 21, 11, 101, 115, 243, 985, 1389, 2189, 563, 12453, 14951, 58889, 48079}},
+{12975, 17, 61597, {1, 1, 5, 7, 9, 37, 33, 241, 337, 453, 1955, 1731, 4445, 8887, 27715, 63975, 95891}},
+{12976, 17, 61602, {1, 1, 5, 1, 23, 21, 95, 237, 241, 991, 1159, 2417, 2279, 8941, 20987, 39773, 79327}},
+{12977, 17, 61604, {1, 3, 3, 1, 19, 39, 73, 253, 137, 1009, 1793, 4007, 2017, 7503, 16689, 29013, 41571}},
+{12978, 17, 61607, {1, 3, 7, 15, 3, 63, 77, 11, 293, 495, 339, 3525, 5747, 1807, 11705, 55807, 54163}},
+{12979, 17, 61622, {1, 3, 7, 3, 25, 41, 127, 23, 113, 807, 387, 3529, 2173, 11217, 21257, 61169, 47749}},
+{12980, 17, 61625, {1, 3, 3, 5, 27, 5, 43, 55, 207, 995, 811, 1473, 481, 4317, 2015, 49161, 94711}},
+{12981, 17, 61633, {1, 3, 1, 9, 21, 61, 41, 147, 425, 353, 1943, 2455, 379, 10729, 3045, 16013, 44527}},
+{12982, 17, 61640, {1, 3, 1, 5, 17, 43, 109, 231, 313, 277, 939, 3491, 5883, 2297, 4763, 33403, 62395}},
+{12983, 17, 61643, {1, 1, 3, 9, 1, 49, 37, 145, 383, 467, 621, 2873, 873, 6163, 16475, 49045, 115599}},
+{12984, 17, 61651, {1, 1, 1, 9, 5, 15, 125, 157, 459, 727, 807, 2769, 5531, 11531, 4277, 42301, 16969}},
+{12985, 17, 61658, {1, 1, 3, 1, 15, 23, 39, 121, 163, 537, 409, 1217, 8007, 5671, 19681, 25371, 69227}},
+{12986, 17, 61670, {1, 3, 7, 9, 23, 1, 93, 41, 267, 995, 1917, 3441, 6237, 7233, 30215, 31945, 33967}},
+{12987, 17, 61674, {1, 1, 1, 15, 7, 5, 123, 53, 359, 677, 1061, 1649, 651, 14079, 30211, 14827, 123175}},
+{12988, 17, 61676, {1, 3, 1, 5, 11, 19, 121, 135, 167, 293, 493, 949, 5459, 11785, 21445, 57161, 129737}},
+{12989, 17, 61679, {1, 1, 3, 13, 19, 39, 43, 55, 149, 549, 479, 925, 341, 1151, 12007, 23473, 10671}},
+{12990, 17, 61688, {1, 3, 5, 9, 7, 41, 37, 103, 381, 373, 1767, 3959, 3001, 7903, 24033, 55123, 93627}},
+{12991, 17, 61693, {1, 3, 3, 3, 31, 27, 93, 175, 393, 575, 703, 3715, 6043, 11763, 7613, 15907, 56821}},
+{12992, 17, 61701, {1, 3, 3, 13, 3, 13, 75, 85, 89, 851, 1171, 3075, 5265, 10293, 14745, 32153, 89877}},
+{12993, 17, 61711, {1, 1, 7, 11, 1, 25, 101, 149, 187, 197, 1485, 1555, 1599, 7413, 23275, 27093, 73483}},
+{12994, 17, 61714, {1, 3, 1, 1, 19, 15, 63, 111, 211, 197, 77, 1683, 3159, 235, 32601, 35715, 59537}},
+{12995, 17, 61723, {1, 3, 5, 11, 23, 61, 91, 135, 403, 669, 267, 2507, 2931, 7813, 5047, 40027, 111705}},
+{12996, 17, 61725, {1, 1, 5, 13, 7, 5, 65, 37, 87, 405, 335, 1095, 3717, 1717, 31551, 28181, 47407}},
+{12997, 17, 61726, {1, 1, 5, 13, 3, 43, 67, 99, 507, 861, 1063, 3003, 6095, 11079, 6919, 41597, 97709}},
+{12998, 17, 61729, {1, 1, 3, 1, 7, 23, 109, 161, 321, 499, 549, 363, 2061, 6519, 1531, 1969, 83845}},
+{12999, 17, 61741, {1, 3, 7, 5, 17, 39, 55, 59, 455, 433, 601, 365, 7987, 2207, 3463, 31755, 94203}},
+{13000, 17, 61761, {1, 3, 5, 5, 29, 61, 79, 101, 125, 1011, 867, 2935, 3269, 13601, 21935, 50355, 65883}},
+{13001, 17, 61779, {1, 1, 1, 5, 3, 41, 101, 107, 299, 125, 81, 2421, 2937, 787, 19479, 25803, 74473}},
+{13002, 17, 61781, {1, 3, 3, 1, 3, 15, 73, 13, 167, 387, 75, 601, 415, 6927, 32277, 16709, 12477}},
+{13003, 17, 61782, {1, 1, 5, 1, 19, 37, 53, 45, 139, 737, 159, 2299, 6219, 11613, 22873, 18303, 56875}},
+{13004, 17, 61797, {1, 1, 3, 9, 23, 15, 17, 37, 373, 445, 1369, 2997, 49, 13901, 13155, 37375, 29063}},
+{13005, 17, 61809, {1, 3, 3, 11, 17, 1, 45, 91, 445, 631, 1297, 1907, 3765, 13893, 29379, 17939, 36573}},
+{13006, 17, 61810, {1, 1, 7, 13, 11, 31, 101, 165, 413, 305, 361, 4019, 3183, 2321, 7819, 49275, 101041}},
+{13007, 17, 61816, {1, 1, 7, 1, 13, 43, 125, 165, 357, 293, 1343, 2219, 4189, 6095, 28509, 27763, 53871}},
+{13008, 17, 61822, {1, 3, 3, 11, 29, 33, 105, 71, 297, 637, 1493, 3797, 5525, 15093, 21647, 57647, 1467}},
+{13009, 17, 61849, {1, 1, 1, 13, 19, 7, 5, 141, 71, 221, 923, 1039, 4777, 9481, 1267, 55345, 116061}},
+{13010, 17, 61876, {1, 1, 7, 11, 19, 43, 57, 243, 21, 217, 1075, 569, 3735, 10477, 18595, 34133, 70391}},
+{13011, 17, 61893, {1, 3, 3, 1, 21, 61, 7, 135, 401, 101, 321, 2959, 7371, 3303, 23023, 28163, 19833}},
+{13012, 17, 61905, {1, 1, 3, 9, 31, 43, 27, 243, 297, 145, 663, 3951, 4283, 10421, 9355, 30381, 68317}},
+{13013, 17, 61908, {1, 3, 7, 13, 29, 53, 101, 253, 49, 129, 831, 513, 5567, 5063, 157, 6465, 90983}},
+{13014, 17, 61911, {1, 1, 5, 15, 27, 29, 3, 231, 503, 173, 913, 3971, 7685, 9679, 32243, 967, 73195}},
+{13015, 17, 61912, {1, 1, 1, 15, 19, 55, 127, 3, 405, 239, 1063, 3473, 7543, 4049, 14509, 22657, 5611}},
+{13016, 17, 61928, {1, 3, 7, 1, 21, 39, 61, 249, 421, 401, 1667, 1981, 5503, 9191, 24027, 35049, 12199}},
+{13017, 17, 61934, {1, 3, 5, 5, 27, 1, 99, 83, 287, 997, 721, 1345, 2197, 6335, 4245, 42575, 102635}},
+{13018, 17, 61957, {1, 3, 3, 1, 31, 7, 103, 107, 387, 273, 951, 2475, 1275, 15607, 2159, 55083, 86107}},
+{13019, 17, 61961, {1, 3, 3, 5, 21, 59, 69, 55, 121, 601, 5, 1871, 7161, 4583, 23867, 7933, 3125}},
+{13020, 17, 61969, {1, 1, 1, 15, 17, 41, 51, 45, 383, 579, 713, 275, 1395, 11665, 30521, 11683, 126493}},
+{13021, 17, 61979, {1, 1, 1, 15, 17, 47, 15, 139, 175, 283, 1377, 827, 5753, 8855, 26437, 59219, 105601}},
+{13022, 17, 61982, {1, 1, 7, 11, 13, 3, 27, 141, 137, 851, 767, 2575, 7685, 11719, 24401, 52547, 127299}},
+{13023, 17, 62003, {1, 3, 3, 9, 11, 41, 75, 69, 167, 897, 1213, 3723, 6773, 12141, 28033, 19695, 128545}},
+{13024, 17, 62006, {1, 1, 5, 13, 7, 61, 55, 131, 465, 169, 1669, 711, 5901, 10769, 11273, 23809, 63625}},
+{13025, 17, 62010, {1, 1, 5, 1, 27, 25, 35, 167, 83, 921, 251, 2571, 6723, 14767, 26715, 21699, 60779}},
+{13026, 17, 62015, {1, 3, 1, 9, 15, 5, 59, 241, 405, 323, 1917, 1161, 6079, 13443, 13079, 58617, 63381}},
+{13027, 17, 62020, {1, 3, 1, 5, 9, 5, 79, 123, 87, 395, 667, 2787, 3711, 3613, 1803, 17885, 78975}},
+{13028, 17, 62024, {1, 3, 3, 5, 17, 45, 61, 107, 485, 163, 33, 1491, 7131, 59, 27327, 8043, 14907}},
+{13029, 17, 62029, {1, 3, 1, 11, 27, 37, 5, 251, 115, 339, 1621, 2013, 3517, 2213, 10145, 47121, 84485}},
+{13030, 17, 62032, {1, 3, 3, 1, 9, 11, 71, 25, 363, 867, 1485, 3897, 3339, 7599, 20777, 52009, 127097}},
+{13031, 17, 62035, {1, 1, 3, 9, 25, 37, 29, 231, 183, 315, 399, 879, 6169, 6355, 3729, 9187, 19405}},
+{13032, 17, 62038, {1, 3, 5, 3, 31, 37, 127, 71, 171, 687, 1237, 151, 7391, 2395, 11979, 23381, 117879}},
+{13033, 17, 62047, {1, 1, 1, 13, 13, 43, 71, 235, 131, 79, 1321, 235, 2221, 1133, 13509, 12205, 44771}},
+{13034, 17, 62068, {1, 3, 7, 5, 29, 51, 125, 191, 153, 35, 1657, 2141, 3701, 7177, 31723, 15189, 55441}},
+{13035, 17, 62071, {1, 1, 5, 1, 5, 35, 13, 165, 461, 255, 1825, 1531, 6195, 7717, 973, 12367, 71747}},
+{13036, 17, 62082, {1, 3, 1, 9, 13, 57, 25, 83, 389, 405, 227, 1037, 3805, 15653, 25365, 47991, 54315}},
+{13037, 17, 62088, {1, 1, 1, 13, 17, 55, 113, 151, 145, 951, 1849, 2205, 6513, 7845, 7947, 59429, 44911}},
+{13038, 17, 62096, {1, 3, 5, 3, 25, 9, 99, 159, 183, 445, 153, 3053, 2537, 1787, 19029, 60047, 128203}},
+{13039, 17, 62108, {1, 1, 5, 5, 31, 37, 13, 11, 271, 491, 1141, 1827, 3751, 9471, 7579, 35969, 95245}},
+{13040, 17, 62124, {1, 3, 3, 15, 1, 43, 9, 109, 13, 991, 345, 1577, 947, 3197, 16747, 8127, 116937}},
+{13041, 17, 62142, {1, 3, 3, 15, 11, 17, 103, 89, 33, 741, 1855, 2879, 3899, 9535, 15119, 56165, 86055}},
+{13042, 17, 62147, {1, 3, 5, 1, 31, 41, 57, 205, 69, 163, 1383, 2087, 6483, 6281, 32079, 40825, 28709}},
+{13043, 17, 62153, {1, 1, 1, 13, 23, 57, 103, 247, 421, 773, 1733, 3249, 6681, 9675, 11669, 51673, 86189}},
+{13044, 17, 62159, {1, 1, 5, 15, 7, 37, 63, 123, 77, 941, 277, 1061, 803, 2135, 15745, 47413, 73843}},
+{13045, 17, 62161, {1, 1, 3, 5, 19, 15, 35, 59, 321, 527, 1669, 2929, 513, 4453, 20521, 19781, 115501}},
+{13046, 17, 62171, {1, 1, 7, 3, 23, 1, 99, 251, 129, 271, 1555, 1191, 2445, 11533, 11921, 19131, 80653}},
+{13047, 17, 62189, {1, 1, 7, 15, 15, 33, 79, 89, 113, 517, 1655, 43, 6255, 15415, 19559, 63309, 16857}},
+{13048, 17, 62207, {1, 3, 5, 1, 13, 61, 87, 159, 65, 875, 163, 663, 7651, 8775, 32505, 39313, 83331}},
+{13049, 17, 62227, {1, 1, 7, 15, 27, 19, 63, 117, 427, 233, 1243, 755, 3201, 5153, 31959, 64545, 69219}},
+{13050, 17, 62230, {1, 1, 5, 3, 3, 27, 15, 11, 427, 431, 107, 2433, 6923, 7503, 31347, 64849, 14541}},
+{13051, 17, 62234, {1, 1, 3, 11, 7, 23, 53, 253, 483, 63, 1749, 2989, 5219, 7361, 6423, 1503, 95431}},
+{13052, 17, 62236, {1, 1, 5, 9, 1, 19, 23, 25, 301, 665, 1457, 2423, 6623, 9771, 2755, 8963, 51037}},
+{13053, 17, 62239, {1, 3, 3, 7, 21, 1, 3, 131, 377, 897, 15, 437, 4075, 7669, 31529, 64123, 101249}},
+{13054, 17, 62257, {1, 3, 5, 3, 31, 41, 99, 27, 397, 393, 1895, 2249, 3925, 6393, 2839, 375, 56721}},
+{13055, 17, 62270, {1, 3, 7, 15, 1, 45, 65, 113, 85, 557, 857, 2281, 1395, 2055, 2405, 34541, 63719}},
+{13056, 17, 62278, {1, 3, 1, 15, 7, 43, 21, 29, 15, 229, 1287, 3005, 339, 5833, 21867, 21643, 37557}},
+{13057, 17, 62287, {1, 3, 7, 3, 3, 51, 67, 119, 423, 539, 1995, 4039, 2999, 2787, 29327, 62687, 11893}},
+{13058, 17, 62295, {1, 3, 7, 3, 25, 23, 85, 11, 105, 523, 889, 2983, 2031, 2049, 16119, 41925, 38345}},
+{13059, 17, 62301, {1, 3, 7, 3, 13, 63, 59, 65, 183, 695, 293, 3301, 7895, 13915, 25847, 22819, 92189}},
+{13060, 17, 62306, {1, 1, 3, 3, 7, 27, 101, 229, 435, 227, 1759, 1275, 5781, 6079, 25125, 64833, 69577}},
+{13061, 17, 62312, {1, 1, 3, 1, 29, 1, 61, 45, 193, 441, 687, 841, 4491, 10683, 13989, 60461, 78071}},
+{13062, 17, 62317, {1, 3, 1, 9, 5, 33, 99, 229, 181, 675, 1629, 1855, 4719, 9585, 8059, 26363, 31161}},
+{13063, 17, 62330, {1, 3, 1, 11, 11, 37, 79, 53, 163, 49, 1173, 1715, 8087, 6535, 14985, 24069, 118597}},
+{13064, 17, 62342, {1, 1, 7, 15, 9, 59, 123, 79, 237, 131, 1693, 2525, 6339, 9843, 24309, 24969, 37645}},
+{13065, 17, 62359, {1, 3, 3, 7, 19, 49, 85, 133, 415, 239, 555, 2581, 6523, 2733, 19665, 19989, 105585}},
+{13066, 17, 62365, {1, 3, 3, 7, 23, 37, 31, 121, 59, 7, 2031, 2893, 6429, 10305, 21221, 20105, 38879}},
+{13067, 17, 62366, {1, 3, 1, 13, 23, 21, 93, 93, 343, 641, 411, 971, 1777, 2135, 22895, 9055, 114457}},
+{13068, 17, 62370, {1, 3, 5, 3, 15, 33, 23, 7, 59, 413, 277, 3551, 7737, 2285, 7951, 5013, 94469}},
+{13069, 17, 62375, {1, 3, 1, 15, 25, 1, 109, 245, 153, 187, 1099, 1071, 145, 6735, 10327, 3921, 62123}},
+{13070, 17, 62376, {1, 1, 7, 11, 11, 53, 51, 123, 277, 281, 1763, 3161, 7639, 14515, 29725, 3919, 5525}},
+{13071, 17, 62387, {1, 3, 3, 15, 27, 47, 109, 121, 317, 221, 187, 617, 1331, 5401, 861, 62465, 9227}},
+{13072, 17, 62404, {1, 3, 3, 15, 27, 25, 101, 111, 469, 85, 1285, 1621, 5393, 1367, 17115, 35141, 126989}},
+{13073, 17, 62411, {1, 3, 5, 1, 15, 23, 25, 249, 69, 17, 1103, 2603, 59, 15637, 22051, 29243, 53113}},
+{13074, 17, 62435, {1, 3, 1, 9, 17, 49, 73, 13, 207, 963, 379, 3561, 6447, 7895, 18651, 8109, 3943}},
+{13075, 17, 62441, {1, 3, 5, 11, 7, 41, 55, 85, 481, 831, 593, 4093, 1151, 12353, 24231, 46091, 80967}},
+{13076, 17, 62442, {1, 3, 7, 7, 5, 39, 47, 187, 427, 1007, 813, 3617, 6063, 12981, 18573, 34061, 85741}},
+{13077, 17, 62452, {1, 3, 3, 11, 9, 17, 29, 141, 341, 485, 1075, 4067, 7247, 11295, 31803, 18347, 54985}},
+{13078, 17, 62459, {1, 1, 3, 7, 17, 25, 7, 29, 355, 35, 1753, 669, 4123, 4293, 22875, 36677, 61201}},
+{13079, 17, 62461, {1, 1, 5, 9, 13, 45, 29, 153, 169, 387, 1275, 3161, 4937, 5331, 16203, 43925, 129231}},
+{13080, 17, 62473, {1, 3, 3, 9, 19, 27, 109, 95, 499, 929, 1627, 3215, 6097, 15837, 5655, 29877, 122513}},
+{13081, 17, 62474, {1, 3, 7, 11, 1, 25, 15, 41, 65, 411, 289, 883, 5069, 8405, 11159, 57357, 114253}},
+{13082, 17, 62493, {1, 1, 3, 11, 31, 57, 39, 89, 77, 321, 1667, 871, 6429, 1005, 18905, 13877, 9305}},
+{13083, 17, 62510, {1, 1, 7, 7, 27, 57, 23, 37, 281, 625, 1871, 565, 5979, 13925, 22591, 2375, 8577}},
+{13084, 17, 62518, {1, 1, 1, 7, 31, 35, 91, 221, 495, 811, 1321, 2235, 4287, 3009, 5745, 35013, 93715}},
+{13085, 17, 62524, {1, 1, 7, 3, 11, 53, 17, 13, 319, 225, 117, 3365, 537, 5249, 14219, 23879, 4321}},
+{13086, 17, 62549, {1, 3, 5, 1, 31, 57, 35, 95, 257, 933, 471, 627, 6733, 8707, 25173, 44291, 105041}},
+{13087, 17, 62556, {1, 1, 3, 3, 31, 53, 69, 19, 277, 669, 497, 3957, 2781, 14107, 27741, 53519, 41057}},
+{13088, 17, 62565, {1, 1, 3, 15, 11, 21, 11, 25, 257, 665, 491, 2119, 3893, 14401, 29147, 3369, 116569}},
+{13089, 17, 62566, {1, 3, 1, 1, 13, 49, 31, 231, 217, 711, 1987, 1487, 7073, 473, 28781, 51283, 86049}},
+{13090, 17, 62580, {1, 1, 1, 5, 23, 31, 119, 115, 381, 179, 1725, 2323, 8013, 15191, 13255, 57813, 95437}},
+{13091, 17, 62584, {1, 1, 3, 15, 15, 37, 83, 223, 259, 605, 2013, 4089, 395, 2063, 11735, 51931, 74677}},
+{13092, 17, 62589, {1, 1, 7, 3, 1, 61, 107, 169, 213, 789, 425, 2309, 225, 1305, 20697, 26281, 60129}},
+{13093, 17, 62596, {1, 1, 5, 15, 27, 15, 69, 169, 289, 931, 1491, 3711, 6875, 7723, 21103, 31795, 53955}},
+{13094, 17, 62608, {1, 1, 1, 3, 3, 43, 49, 205, 247, 817, 2037, 2305, 7935, 255, 18835, 49423, 90727}},
+{13095, 17, 62636, {1, 3, 7, 9, 17, 3, 95, 239, 431, 665, 1271, 3559, 5703, 14607, 9723, 11807, 122937}},
+{13096, 17, 62642, {1, 3, 5, 13, 5, 15, 13, 111, 375, 895, 833, 813, 5451, 13841, 1321, 25273, 25443}},
+{13097, 17, 62651, {1, 1, 3, 1, 11, 49, 3, 97, 467, 631, 51, 3577, 1777, 15965, 6837, 38827, 68627}},
+{13098, 17, 62654, {1, 1, 7, 1, 3, 11, 73, 155, 77, 623, 811, 337, 6837, 10925, 2097, 28325, 97487}},
+{13099, 17, 62659, {1, 1, 1, 3, 29, 35, 9, 215, 415, 143, 1837, 3723, 73, 11305, 23187, 19995, 52987}},
+{13100, 17, 62666, {1, 1, 7, 1, 25, 39, 35, 67, 245, 295, 1143, 2043, 1049, 629, 14111, 62893, 86899}},
+{13101, 17, 62680, {1, 3, 7, 5, 3, 41, 123, 97, 241, 743, 259, 3163, 2289, 6363, 24033, 10789, 44117}},
+{13102, 17, 62692, {1, 3, 1, 7, 25, 33, 33, 17, 359, 567, 901, 3595, 179, 8671, 841, 24787, 4367}},
+{13103, 17, 62701, {1, 3, 1, 13, 5, 13, 57, 185, 321, 727, 789, 3081, 5345, 9721, 32029, 11663, 55695}},
+{13104, 17, 62702, {1, 1, 7, 7, 5, 51, 85, 255, 329, 263, 297, 1687, 6799, 10973, 8265, 19615, 115333}},
+{13105, 17, 62714, {1, 1, 1, 5, 29, 27, 55, 167, 465, 73, 661, 137, 7831, 2571, 15373, 64223, 27335}},
+{13106, 17, 62716, {1, 3, 7, 13, 5, 23, 77, 15, 345, 21, 1729, 3231, 967, 12573, 31415, 24249, 110525}},
+{13107, 17, 62733, {1, 1, 7, 9, 31, 37, 41, 119, 169, 891, 1845, 2139, 1747, 1147, 21983, 11617, 25963}},
+{13108, 17, 62762, {1, 3, 3, 7, 23, 5, 1, 11, 95, 795, 1371, 2631, 3241, 6935, 17353, 25013, 89765}},
+{13109, 17, 62769, {1, 3, 1, 7, 19, 3, 121, 19, 389, 117, 1905, 3135, 7601, 12541, 20855, 38613, 15005}},
+{13110, 17, 62770, {1, 3, 3, 5, 17, 43, 91, 99, 113, 545, 1955, 37, 3411, 15173, 24961, 28761, 15245}},
+{13111, 17, 62787, {1, 3, 3, 13, 25, 9, 83, 17, 17, 271, 1133, 3851, 4607, 11017, 14867, 20677, 42881}},
+{13112, 17, 62794, {1, 1, 5, 15, 5, 9, 99, 179, 263, 623, 441, 2577, 189, 11595, 21505, 27215, 54081}},
+{13113, 17, 62801, {1, 1, 7, 1, 1, 63, 123, 119, 245, 467, 169, 3075, 909, 3581, 14571, 33071, 6261}},
+{13114, 17, 62807, {1, 1, 1, 13, 9, 35, 47, 161, 47, 893, 57, 703, 3373, 4167, 26555, 51265, 1391}},
+{13115, 17, 62808, {1, 3, 1, 13, 9, 61, 9, 5, 47, 259, 579, 113, 355, 14539, 25757, 10119, 96869}},
+{13116, 17, 62813, {1, 1, 5, 11, 3, 5, 61, 231, 291, 21, 1711, 2981, 4727, 14287, 12149, 40275, 51809}},
+{13117, 17, 62817, {1, 3, 5, 3, 21, 5, 87, 251, 373, 679, 949, 1023, 5183, 14549, 4135, 54927, 20369}},
+{13118, 17, 62818, {1, 3, 3, 11, 7, 43, 127, 97, 469, 81, 1843, 3955, 125, 8607, 27185, 50761, 122753}},
+{13119, 17, 62832, {1, 3, 5, 5, 25, 61, 1, 55, 333, 949, 1005, 1051, 6291, 8343, 9627, 37739, 116911}},
+{13120, 17, 62841, {1, 3, 3, 13, 21, 9, 67, 225, 179, 837, 2009, 3171, 217, 5629, 23451, 63171, 53225}},
+{13121, 17, 62857, {1, 3, 7, 1, 23, 15, 91, 163, 351, 883, 579, 3923, 2641, 12735, 24955, 1131, 65119}},
+{13122, 17, 62860, {1, 1, 1, 11, 29, 5, 113, 217, 171, 535, 913, 2419, 3843, 12365, 8287, 27367, 57369}},
+{13123, 17, 62871, {1, 1, 5, 11, 9, 41, 57, 243, 123, 159, 1517, 2653, 4307, 4243, 2801, 43131, 18435}},
+{13124, 17, 62882, {1, 1, 7, 9, 23, 59, 83, 159, 57, 723, 1635, 7, 1463, 121, 541, 7657, 83917}},
+{13125, 17, 62888, {1, 3, 7, 7, 23, 27, 125, 103, 247, 1019, 1063, 3979, 8085, 6449, 12443, 63427, 106235}},
+{13126, 17, 62913, {1, 1, 7, 5, 9, 31, 23, 83, 503, 605, 1731, 3341, 7427, 14571, 5981, 39043, 42965}},
+{13127, 17, 62919, {1, 3, 5, 1, 17, 49, 109, 171, 301, 951, 1879, 1317, 457, 8085, 6803, 62521, 67871}},
+{13128, 17, 62920, {1, 1, 7, 11, 11, 27, 1, 71, 335, 137, 265, 1267, 6399, 14823, 925, 49895, 19731}},
+{13129, 17, 62925, {1, 3, 1, 13, 3, 35, 75, 253, 211, 483, 1495, 3695, 3033, 14643, 1861, 51269, 32655}},
+{13130, 17, 62933, {1, 3, 7, 1, 5, 17, 63, 1, 83, 435, 2007, 2023, 57, 8639, 27067, 4039, 1955}},
+{13131, 17, 62938, {1, 3, 5, 15, 27, 51, 59, 47, 77, 131, 507, 559, 645, 16067, 20989, 15565, 39925}},
+{13132, 17, 62940, {1, 3, 3, 5, 11, 15, 63, 121, 39, 1019, 1027, 2821, 3297, 13769, 18587, 14199, 82251}},
+{13133, 17, 62949, {1, 1, 5, 1, 31, 11, 89, 75, 147, 1007, 917, 3519, 5097, 5695, 15185, 14819, 38597}},
+{13134, 17, 62956, {1, 3, 3, 3, 15, 7, 127, 55, 83, 887, 1901, 75, 639, 713, 13631, 27447, 106707}},
+{13135, 17, 62971, {1, 3, 3, 15, 27, 25, 85, 163, 187, 959, 815, 1403, 6129, 6515, 31597, 28307, 30077}},
+{13136, 17, 62978, {1, 3, 1, 13, 5, 19, 117, 89, 11, 489, 845, 2899, 3695, 3279, 22355, 38759, 85849}},
+{13137, 17, 62990, {1, 3, 1, 7, 25, 59, 109, 185, 87, 591, 825, 1119, 7439, 5451, 17959, 51299, 76693}},
+{13138, 17, 62995, {1, 1, 7, 5, 25, 29, 115, 249, 185, 529, 593, 103, 1739, 4769, 25925, 3317, 102445}},
+{13139, 17, 62997, {1, 1, 3, 1, 3, 35, 19, 255, 279, 295, 1075, 2817, 3513, 7501, 15885, 21653, 113447}},
+{13140, 17, 63004, {1, 3, 1, 5, 27, 1, 21, 137, 303, 981, 631, 2339, 397, 13075, 28815, 50925, 44379}},
+{13141, 17, 63011, {1, 1, 7, 7, 31, 31, 59, 129, 105, 181, 1041, 2685, 1061, 1721, 30365, 6873, 30011}},
+{13142, 17, 63032, {1, 1, 3, 1, 19, 31, 125, 39, 9, 631, 1239, 1061, 6313, 9639, 5991, 27293, 84635}},
+{13143, 17, 63038, {1, 3, 3, 11, 17, 59, 17, 241, 195, 175, 1845, 251, 3323, 13399, 20493, 15241, 69303}},
+{13144, 17, 63067, {1, 1, 5, 3, 9, 19, 59, 25, 49, 359, 263, 4045, 1527, 6703, 555, 26413, 42757}},
+{13145, 17, 63069, {1, 1, 5, 9, 23, 5, 7, 223, 247, 407, 1079, 1069, 3417, 14795, 5015, 2965, 99059}},
+{13146, 17, 63076, {1, 3, 7, 5, 27, 47, 9, 37, 47, 181, 819, 2049, 2643, 9231, 8173, 33495, 91321}},
+{13147, 17, 63083, {1, 3, 5, 11, 5, 27, 5, 237, 349, 653, 1443, 137, 7969, 5961, 24749, 37523, 88921}},
+{13148, 17, 63088, {1, 3, 7, 13, 11, 51, 49, 71, 339, 195, 1239, 3479, 2771, 15217, 23729, 7839, 32633}},
+{13149, 17, 63094, {1, 1, 5, 5, 5, 13, 103, 185, 13, 273, 1793, 761, 5327, 8659, 32599, 38181, 121115}},
+{13150, 17, 63097, {1, 3, 7, 15, 17, 55, 69, 151, 231, 421, 1679, 3657, 8001, 12599, 13761, 13517, 130199}},
+{13151, 17, 63100, {1, 1, 5, 3, 5, 15, 15, 61, 489, 219, 925, 2329, 3415, 10779, 31297, 63805, 13375}},
+{13152, 17, 63104, {1, 1, 7, 9, 7, 11, 87, 45, 39, 885, 87, 1877, 8135, 1247, 25685, 23631, 65579}},
+{13153, 17, 63114, {1, 3, 3, 7, 1, 17, 31, 75, 455, 535, 509, 2151, 1737, 7579, 12727, 25139, 32659}},
+{13154, 17, 63116, {1, 3, 5, 7, 15, 27, 111, 145, 99, 767, 167, 3391, 2155, 7895, 3405, 47451, 65185}},
+{13155, 17, 63122, {1, 1, 1, 3, 23, 31, 15, 53, 59, 787, 431, 2691, 71, 2843, 13469, 54029, 2233}},
+{13156, 17, 63128, {1, 1, 5, 1, 5, 39, 57, 31, 75, 507, 811, 2747, 317, 13545, 7395, 65161, 87987}},
+{13157, 17, 63149, {1, 3, 5, 5, 13, 17, 11, 89, 371, 337, 913, 2775, 27, 4923, 24013, 62955, 65185}},
+{13158, 17, 63150, {1, 3, 3, 7, 9, 27, 91, 187, 17, 443, 807, 853, 6243, 12351, 8123, 4203, 61021}},
+{13159, 17, 63157, {1, 1, 1, 5, 9, 33, 101, 211, 205, 701, 1289, 1253, 653, 8591, 13009, 48525, 77051}},
+{13160, 17, 63167, {1, 3, 5, 11, 5, 19, 1, 67, 259, 355, 15, 2169, 6785, 2019, 8675, 1019, 85903}},
+{13161, 17, 63187, {1, 3, 7, 5, 27, 31, 103, 163, 369, 685, 659, 2009, 5819, 10437, 17311, 35083, 122125}},
+{13162, 17, 63200, {1, 3, 5, 7, 19, 13, 93, 113, 377, 359, 1697, 4063, 4379, 9321, 7335, 25491, 85939}},
+{13163, 17, 63220, {1, 3, 3, 5, 7, 25, 41, 225, 355, 257, 743, 2067, 7627, 14317, 7385, 25187, 63103}},
+{13164, 17, 63223, {1, 1, 7, 7, 17, 43, 75, 1, 95, 547, 1937, 2263, 1709, 5067, 22651, 55733, 44619}},
+{13165, 17, 63229, {1, 1, 7, 3, 5, 27, 45, 23, 107, 547, 1733, 1169, 6709, 861, 4439, 55381, 96447}},
+{13166, 17, 63235, {1, 1, 7, 11, 25, 23, 127, 159, 489, 945, 843, 3715, 5215, 2131, 9681, 35515, 108109}},
+{13167, 17, 63247, {1, 1, 3, 7, 5, 1, 67, 59, 83, 745, 1337, 855, 6087, 14319, 13405, 36261, 49091}},
+{13168, 17, 63252, {1, 3, 1, 1, 13, 27, 41, 155, 463, 709, 1111, 2017, 4701, 8663, 29703, 45311, 113347}},
+{13169, 17, 63255, {1, 1, 7, 5, 1, 11, 83, 101, 283, 505, 893, 705, 2331, 5127, 21793, 28095, 59055}},
+{13170, 17, 63289, {1, 1, 5, 9, 25, 7, 97, 155, 71, 569, 1481, 897, 6177, 13367, 12163, 18171, 24785}},
+{13171, 17, 63298, {1, 3, 5, 11, 19, 25, 7, 15, 511, 369, 957, 1247, 6097, 11181, 17265, 24777, 87377}},
+{13172, 17, 63303, {1, 3, 1, 7, 11, 9, 39, 191, 9, 793, 867, 2779, 3447, 3805, 21025, 64719, 15669}},
+{13173, 17, 63327, {1, 1, 3, 1, 31, 43, 107, 103, 175, 131, 1525, 993, 635, 14383, 26835, 15929, 109977}},
+{13174, 17, 63328, {1, 1, 1, 3, 19, 17, 99, 249, 47, 467, 853, 2805, 3155, 1565, 17291, 18865, 11039}},
+{13175, 17, 63348, {1, 1, 5, 13, 25, 61, 91, 67, 361, 947, 1909, 3403, 945, 3481, 16703, 50227, 43963}},
+{13176, 17, 63355, {1, 3, 1, 3, 19, 27, 31, 219, 185, 579, 1539, 315, 4421, 9473, 30289, 48477, 61365}},
+{13177, 17, 63357, {1, 1, 3, 1, 23, 11, 101, 1, 133, 305, 1107, 1145, 1733, 13275, 221, 5071, 81987}},
+{13178, 17, 63368, {1, 1, 1, 13, 7, 61, 47, 5, 137, 979, 1183, 2049, 5263, 6515, 5585, 6093, 119689}},
+{13179, 17, 63391, {1, 3, 1, 5, 19, 47, 83, 115, 215, 901, 1685, 755, 2327, 13297, 6847, 40329, 19225}},
+{13180, 17, 63402, {1, 1, 3, 3, 3, 13, 31, 127, 199, 655, 55, 2183, 5031, 945, 6073, 54729, 108281}},
+{13181, 17, 63409, {1, 1, 1, 1, 11, 51, 37, 19, 73, 205, 1377, 1881, 3679, 4487, 14693, 41735, 27349}},
+{13182, 17, 63416, {1, 3, 7, 13, 1, 35, 37, 73, 45, 973, 209, 529, 5283, 9765, 26367, 12697, 8685}},
+{13183, 17, 63419, {1, 3, 3, 9, 3, 45, 115, 35, 475, 663, 487, 3613, 4151, 15623, 3057, 31519, 87545}},
+{13184, 17, 63430, {1, 3, 7, 5, 23, 13, 25, 255, 355, 433, 1671, 667, 7463, 14189, 14107, 1531, 11695}},
+{13185, 17, 63442, {1, 1, 7, 3, 15, 25, 37, 127, 265, 493, 1763, 2721, 4335, 13753, 5947, 18375, 29911}},
+{13186, 17, 63457, {1, 1, 3, 15, 1, 55, 25, 69, 335, 157, 1923, 1757, 5689, 6731, 723, 6471, 57415}},
+{13187, 17, 63458, {1, 3, 3, 3, 1, 15, 127, 227, 401, 395, 503, 3783, 1737, 8785, 16287, 34949, 91683}},
+{13188, 17, 63482, {1, 3, 5, 15, 23, 29, 55, 119, 115, 855, 657, 3729, 5309, 14773, 5647, 25953, 67303}},
+{13189, 17, 63487, {1, 3, 5, 13, 23, 25, 1, 187, 67, 389, 359, 619, 2523, 11203, 11049, 60345, 53931}},
+{13190, 17, 63488, {1, 3, 1, 7, 7, 45, 99, 123, 495, 797, 939, 3387, 7563, 16289, 8309, 14917, 99867}},
+{13191, 17, 63500, {1, 3, 5, 11, 29, 49, 89, 205, 447, 541, 1279, 1153, 7277, 5393, 8743, 41057, 100119}},
+{13192, 17, 63511, {1, 1, 1, 9, 1, 7, 43, 165, 259, 311, 993, 1381, 3363, 577, 4023, 443, 101785}},
+{13193, 17, 63517, {1, 1, 7, 9, 25, 55, 93, 63, 423, 787, 549, 1039, 383, 15855, 6013, 51399, 60007}},
+{13194, 17, 63528, {1, 3, 3, 1, 5, 17, 103, 91, 309, 85, 1319, 3869, 559, 3993, 18111, 17753, 66681}},
+{13195, 17, 63531, {1, 3, 7, 9, 1, 11, 87, 151, 311, 597, 811, 3955, 275, 6555, 17005, 26763, 31227}},
+{13196, 17, 63559, {1, 1, 3, 11, 19, 51, 41, 101, 183, 1003, 1635, 2061, 3305, 12925, 7223, 4859, 24433}},
+{13197, 17, 63566, {1, 3, 7, 11, 7, 43, 79, 53, 43, 429, 947, 2533, 7005, 15147, 13435, 33997, 21201}},
+{13198, 17, 63578, {1, 1, 3, 5, 15, 17, 61, 41, 383, 465, 1439, 3503, 3981, 14469, 5075, 25953, 70461}},
+{13199, 17, 63580, {1, 1, 1, 13, 21, 53, 25, 59, 59, 195, 665, 3367, 2777, 9179, 24207, 56729, 94241}},
+{13200, 17, 63584, {1, 3, 7, 15, 27, 13, 41, 147, 415, 351, 961, 3811, 1605, 14231, 31789, 41189, 50265}},
+{13201, 17, 63587, {1, 3, 3, 7, 31, 39, 85, 219, 323, 657, 423, 1579, 3623, 7663, 14631, 47169, 88795}},
+{13202, 17, 63594, {1, 3, 1, 3, 1, 3, 125, 65, 259, 3, 1897, 2203, 347, 4101, 23841, 20217, 117407}},
+{13203, 17, 63607, {1, 1, 3, 7, 29, 1, 75, 255, 413, 237, 1531, 2103, 6847, 10395, 9817, 9383, 60679}},
+{13204, 17, 63611, {1, 3, 5, 3, 7, 63, 17, 83, 375, 835, 1707, 3227, 327, 2205, 25025, 47471, 39967}},
+{13205, 17, 63630, {1, 3, 7, 7, 9, 51, 23, 189, 157, 351, 755, 2695, 3923, 3481, 12159, 1041, 94563}},
+{13206, 17, 63632, {1, 1, 3, 11, 25, 27, 39, 19, 221, 795, 523, 695, 3257, 8045, 2643, 43239, 13291}},
+{13207, 17, 63641, {1, 3, 3, 5, 29, 1, 33, 117, 477, 147, 1117, 1943, 7967, 15999, 10673, 13349, 89471}},
+{13208, 17, 63647, {1, 1, 3, 9, 17, 51, 55, 115, 147, 687, 1751, 3685, 3099, 15369, 371, 55673, 67951}},
+{13209, 17, 63651, {1, 1, 7, 1, 5, 25, 67, 31, 103, 439, 1581, 705, 3855, 15985, 7151, 56511, 23697}},
+{13210, 17, 63666, {1, 3, 5, 3, 21, 7, 11, 123, 121, 1009, 277, 623, 7913, 7525, 4759, 19245, 16735}},
+{13211, 17, 63668, {1, 1, 5, 11, 7, 57, 103, 147, 199, 209, 233, 3665, 4215, 13511, 16393, 37873, 120857}},
+{13212, 17, 63695, {1, 1, 7, 9, 27, 45, 29, 97, 279, 379, 1683, 1965, 1183, 11389, 20445, 38435, 56893}},
+{13213, 17, 63697, {1, 3, 5, 5, 27, 23, 89, 169, 329, 659, 393, 903, 6217, 6459, 27327, 2843, 44889}},
+{13214, 17, 63709, {1, 1, 1, 15, 3, 53, 109, 83, 195, 5, 1865, 729, 3627, 13307, 20761, 50375, 60379}},
+{13215, 17, 63723, {1, 1, 1, 13, 25, 57, 17, 185, 359, 797, 469, 2637, 973, 2731, 25299, 15169, 90187}},
+{13216, 17, 63737, {1, 3, 5, 1, 19, 39, 87, 161, 117, 565, 1737, 3995, 6487, 5067, 18531, 38803, 45453}},
+{13217, 17, 63746, {1, 1, 1, 5, 19, 3, 93, 85, 479, 369, 469, 1407, 475, 7775, 12273, 34417, 65611}},
+{13218, 17, 63752, {1, 1, 3, 15, 31, 11, 105, 19, 281, 711, 713, 3423, 797, 11215, 31409, 44891, 110413}},
+{13219, 17, 63755, {1, 1, 3, 11, 13, 17, 59, 111, 59, 431, 1517, 2159, 1697, 12309, 16293, 2097, 107273}},
+{13220, 17, 63775, {1, 3, 5, 15, 25, 19, 97, 107, 97, 563, 247, 3691, 2775, 10631, 15113, 25721, 12995}},
+{13221, 17, 63781, {1, 1, 5, 3, 31, 25, 47, 201, 231, 123, 1923, 2287, 1711, 12271, 1573, 6605, 72991}},
+{13222, 17, 63794, {1, 1, 5, 5, 27, 17, 109, 125, 423, 1, 819, 3041, 685, 8791, 19697, 13107, 67681}},
+{13223, 17, 63796, {1, 1, 5, 3, 5, 63, 115, 95, 117, 715, 1523, 1231, 8171, 1615, 9819, 14361, 87075}},
+{13224, 17, 63808, {1, 1, 7, 7, 7, 35, 35, 175, 349, 853, 1665, 3101, 6051, 10737, 933, 40591, 9419}},
+{13225, 17, 63817, {1, 1, 1, 3, 23, 49, 65, 23, 103, 837, 403, 3799, 6515, 15363, 28079, 36381, 59523}},
+{13226, 17, 63820, {1, 3, 1, 15, 15, 25, 119, 181, 229, 685, 1047, 2397, 4855, 15393, 2371, 42441, 30151}},
+{13227, 17, 63826, {1, 3, 7, 11, 15, 5, 13, 93, 219, 203, 475, 523, 5827, 6579, 26759, 29795, 108463}},
+{13228, 17, 63838, {1, 1, 7, 13, 25, 53, 75, 195, 443, 1003, 501, 2543, 5453, 3119, 19225, 59631, 16413}},
+{13229, 17, 63848, {1, 1, 7, 13, 13, 25, 93, 211, 191, 1005, 1567, 3057, 3001, 1125, 6237, 35725, 108257}},
+{13230, 17, 63861, {1, 1, 3, 7, 21, 11, 57, 205, 487, 263, 1801, 3235, 1819, 10875, 6063, 26211, 54699}},
+{13231, 17, 63862, {1, 3, 3, 7, 11, 59, 89, 217, 15, 991, 1343, 1247, 277, 13377, 18499, 64987, 26053}},
+{13232, 17, 63866, {1, 3, 3, 1, 15, 51, 111, 69, 137, 817, 1207, 1729, 3877, 9873, 18449, 50749, 57457}},
+{13233, 17, 63878, {1, 3, 3, 5, 3, 39, 97, 147, 327, 257, 1547, 769, 7077, 5221, 13679, 44237, 70053}},
+{13234, 17, 63889, {1, 1, 5, 11, 19, 15, 79, 187, 335, 645, 1235, 4041, 4831, 10847, 28135, 48353, 64921}},
+{13235, 17, 63892, {1, 1, 7, 9, 3, 43, 41, 149, 71, 205, 1513, 2801, 6785, 3187, 25401, 55367, 114491}},
+{13236, 17, 63901, {1, 1, 7, 1, 25, 11, 37, 205, 365, 435, 147, 1303, 587, 14563, 32461, 28983, 86157}},
+{13237, 17, 63915, {1, 1, 7, 1, 31, 11, 51, 37, 401, 343, 1677, 991, 501, 11993, 14781, 37055, 30161}},
+{13238, 17, 63917, {1, 3, 5, 9, 9, 21, 95, 45, 447, 957, 943, 3997, 4033, 8371, 25007, 52827, 50207}},
+{13239, 17, 63926, {1, 1, 7, 1, 9, 45, 3, 255, 297, 341, 215, 3631, 7049, 7625, 4145, 50109, 48615}},
+{13240, 17, 63932, {1, 3, 3, 9, 27, 49, 41, 143, 291, 343, 719, 311, 3819, 7699, 17631, 64785, 49239}},
+{13241, 17, 63937, {1, 1, 7, 3, 27, 35, 61, 183, 153, 781, 979, 1465, 3315, 14893, 29847, 18461, 74949}},
+{13242, 17, 63938, {1, 3, 5, 15, 19, 61, 39, 219, 279, 909, 1295, 1681, 8021, 957, 7675, 14001, 77669}},
+{13243, 17, 63943, {1, 3, 1, 5, 15, 59, 127, 85, 229, 649, 503, 3267, 2465, 5637, 2729, 24831, 44791}},
+{13244, 17, 63944, {1, 3, 7, 11, 23, 55, 61, 191, 345, 255, 105, 1361, 3913, 7655, 8865, 1825, 80619}},
+{13245, 17, 63950, {1, 3, 3, 13, 29, 15, 53, 19, 1, 651, 917, 2043, 2333, 13695, 28225, 16457, 11287}},
+{13246, 17, 63952, {1, 1, 3, 13, 15, 53, 41, 211, 13, 287, 383, 3923, 665, 10343, 4803, 22199, 90521}},
+{13247, 17, 63955, {1, 3, 7, 11, 23, 27, 127, 241, 11, 451, 495, 2779, 319, 13119, 5575, 43043, 11659}},
+{13248, 17, 63957, {1, 1, 1, 7, 17, 53, 55, 39, 233, 273, 1873, 843, 7885, 329, 6809, 33119, 116017}},
+{13249, 17, 63961, {1, 1, 1, 7, 21, 41, 23, 113, 283, 265, 1535, 2371, 3975, 6293, 22497, 65349, 48653}},
+{13250, 17, 63962, {1, 3, 7, 9, 25, 21, 61, 135, 245, 777, 679, 2603, 565, 3251, 32469, 12707, 40297}},
+{13251, 17, 63978, {1, 1, 1, 5, 31, 49, 35, 215, 445, 669, 779, 2231, 5399, 5853, 17941, 33973, 126141}},
+{13252, 17, 63983, {1, 3, 5, 5, 3, 31, 45, 235, 51, 65, 295, 3755, 8101, 821, 28331, 38837, 55235}},
+{13253, 17, 63988, {1, 1, 5, 15, 23, 15, 37, 197, 59, 455, 1875, 1745, 7565, 8039, 15901, 63129, 36095}},
+{13254, 17, 64008, {1, 1, 5, 11, 7, 1, 77, 235, 309, 245, 1539, 1421, 3401, 1477, 12655, 19851, 86147}},
+{13255, 17, 64013, {1, 1, 3, 9, 27, 9, 113, 127, 167, 213, 161, 4065, 1275, 10699, 26111, 26213, 129091}},
+{13256, 17, 64019, {1, 3, 5, 9, 9, 17, 109, 205, 23, 145, 1261, 51, 5855, 7411, 20551, 5801, 47841}},
+{13257, 17, 64026, {1, 1, 3, 3, 15, 1, 1, 39, 431, 601, 177, 525, 6951, 6271, 27031, 37157, 73979}},
+{13258, 17, 64028, {1, 3, 1, 3, 19, 61, 11, 131, 31, 223, 959, 3531, 2433, 15675, 29201, 49277, 43977}},
+{13259, 17, 64032, {1, 1, 5, 9, 5, 27, 57, 3, 503, 755, 1261, 3659, 6685, 10041, 24739, 12201, 19753}},
+{13260, 17, 64042, {1, 1, 7, 3, 31, 27, 7, 191, 7, 415, 1665, 1413, 7493, 2645, 23577, 46331, 9481}},
+{13261, 17, 64044, {1, 1, 5, 1, 29, 59, 99, 231, 33, 613, 1347, 2671, 1767, 15685, 26583, 44699, 73511}},
+{13262, 17, 64055, {1, 1, 3, 3, 9, 47, 93, 87, 45, 549, 219, 2141, 233, 10239, 30325, 14985, 70325}},
+{13263, 17, 64070, {1, 1, 3, 3, 21, 39, 81, 179, 319, 853, 93, 2869, 59, 6675, 22391, 16089, 33949}},
+{13264, 17, 64079, {1, 1, 3, 7, 31, 19, 73, 249, 175, 57, 1717, 3557, 2307, 4595, 22045, 33291, 123003}},
+{13265, 17, 64084, {1, 1, 1, 3, 7, 23, 81, 229, 387, 1001, 1371, 17, 667, 3043, 30507, 44613, 32239}},
+{13266, 17, 64087, {1, 1, 7, 15, 15, 59, 83, 99, 101, 863, 333, 845, 7547, 13345, 7599, 51, 10963}},
+{13267, 17, 64093, {1, 1, 1, 3, 15, 55, 73, 37, 429, 711, 1315, 2911, 5109, 953, 14721, 25551, 33527}},
+{13268, 17, 64100, {1, 1, 5, 9, 11, 57, 75, 107, 449, 293, 1267, 2633, 5291, 9939, 12365, 1975, 75705}},
+{13269, 17, 64104, {1, 3, 3, 7, 19, 51, 111, 233, 369, 873, 1419, 425, 6587, 11371, 29613, 28041, 77405}},
+{13270, 17, 64109, {1, 3, 1, 15, 11, 1, 65, 185, 301, 25, 75, 1353, 6879, 11519, 24093, 65223, 130659}},
+{13271, 17, 64140, {1, 1, 3, 3, 17, 17, 33, 177, 467, 841, 949, 1119, 7869, 5835, 22175, 20439, 98923}},
+{13272, 17, 64148, {1, 3, 1, 9, 1, 19, 1, 9, 487, 425, 1095, 1995, 693, 12661, 27717, 56167, 34829}},
+{13273, 17, 64151, {1, 1, 7, 7, 27, 57, 85, 159, 109, 801, 477, 3953, 3195, 11079, 26885, 59833, 4971}},
+{13274, 17, 64152, {1, 1, 1, 15, 25, 9, 89, 231, 499, 623, 1385, 3753, 4781, 15263, 12721, 17511, 67327}},
+{13275, 17, 64171, {1, 1, 3, 7, 9, 11, 103, 65, 319, 681, 1423, 2355, 6243, 399, 8483, 23697, 107995}},
+{13276, 17, 64179, {1, 1, 1, 1, 5, 7, 63, 117, 151, 905, 163, 3813, 6931, 13161, 15131, 63067, 15649}},
+{13277, 17, 64186, {1, 3, 3, 3, 13, 57, 69, 199, 283, 153, 617, 123, 3125, 3057, 8121, 14483, 28085}},
+{13278, 17, 64203, {1, 3, 7, 15, 25, 45, 25, 179, 91, 457, 681, 537, 243, 4369, 11395, 17565, 47875}},
+{13279, 17, 64206, {1, 3, 1, 13, 29, 51, 101, 23, 143, 715, 1725, 791, 6001, 4283, 10689, 49237, 5231}},
+{13280, 17, 64213, {1, 3, 3, 5, 27, 41, 39, 17, 501, 587, 1067, 1859, 9, 13449, 31257, 17675, 99769}},
+{13281, 17, 64214, {1, 1, 1, 3, 15, 57, 119, 195, 15, 779, 761, 733, 3505, 4815, 23167, 411, 52303}},
+{13282, 17, 64220, {1, 3, 1, 13, 9, 31, 5, 141, 19, 487, 739, 577, 4383, 1951, 24293, 45503, 111923}},
+{13283, 17, 64233, {1, 3, 1, 11, 25, 37, 107, 245, 89, 107, 1969, 1569, 7475, 11795, 6123, 45311, 52251}},
+{13284, 17, 64239, {1, 1, 7, 11, 15, 9, 67, 141, 199, 91, 819, 3721, 6251, 6107, 9393, 14941, 98545}},
+{13285, 17, 64248, {1, 3, 3, 11, 23, 9, 31, 211, 339, 665, 1507, 2255, 3589, 11495, 28393, 2017, 106735}},
+{13286, 17, 64251, {1, 3, 5, 11, 27, 13, 105, 217, 173, 337, 1573, 837, 3771, 8645, 28749, 27501, 45045}},
+{13287, 17, 64259, {1, 1, 5, 1, 11, 43, 99, 217, 131, 545, 1323, 3089, 5689, 785, 9043, 29961, 17855}},
+{13288, 17, 64268, {1, 1, 3, 9, 31, 41, 61, 239, 271, 123, 1583, 397, 4243, 12197, 9847, 12341, 130533}},
+{13289, 17, 64273, {1, 3, 5, 3, 27, 11, 33, 31, 77, 403, 823, 2791, 3475, 4201, 15967, 39149, 107137}},
+{13290, 17, 64279, {1, 3, 1, 11, 9, 5, 103, 145, 85, 341, 1615, 729, 7209, 10289, 20807, 54167, 15613}},
+{13291, 17, 64283, {1, 3, 7, 1, 29, 33, 91, 219, 171, 367, 907, 3645, 1059, 9031, 247, 13231, 14323}},
+{13292, 17, 64292, {1, 1, 1, 7, 19, 15, 65, 61, 221, 941, 1005, 1447, 3513, 8917, 17399, 52471, 64245}},
+{13293, 17, 64296, {1, 1, 5, 7, 5, 35, 15, 253, 325, 313, 2015, 3239, 1633, 9745, 11617, 10575, 35877}},
+{13294, 17, 64301, {1, 3, 5, 3, 13, 1, 115, 207, 227, 637, 1119, 781, 2897, 1573, 16499, 43167, 20631}},
+{13295, 17, 64302, {1, 3, 5, 9, 17, 47, 117, 7, 303, 719, 975, 1167, 2463, 5255, 28237, 33495, 57133}},
+{13296, 17, 64324, {1, 3, 5, 11, 5, 43, 123, 63, 19, 97, 1423, 695, 5985, 5923, 5755, 22721, 5411}},
+{13297, 17, 64331, {1, 3, 1, 9, 9, 25, 87, 197, 325, 827, 1679, 1561, 101, 3951, 17453, 33537, 121431}},
+{13298, 17, 64346, {1, 1, 7, 5, 13, 33, 3, 191, 171, 37, 619, 1917, 7525, 14103, 25807, 25455, 57455}},
+{13299, 17, 64364, {1, 3, 3, 1, 9, 35, 93, 159, 455, 115, 479, 665, 477, 4483, 29751, 45047, 41251}},
+{13300, 17, 64382, {1, 3, 1, 3, 11, 47, 41, 199, 511, 475, 151, 1163, 239, 6731, 4461, 39845, 99555}},
+{13301, 17, 64386, {1, 1, 5, 7, 9, 5, 49, 221, 503, 637, 1323, 3303, 4137, 6675, 17709, 49233, 38325}},
+{13302, 17, 64400, {1, 1, 5, 15, 1, 43, 55, 67, 291, 393, 237, 3555, 4171, 909, 8655, 46309, 61799}},
+{13303, 17, 64409, {1, 3, 5, 3, 3, 37, 125, 249, 509, 611, 983, 4093, 1633, 10063, 10811, 60033, 40999}},
+{13304, 17, 64419, {1, 3, 5, 11, 1, 37, 75, 255, 279, 545, 1999, 833, 2789, 14601, 16707, 64703, 53545}},
+{13305, 17, 64433, {1, 1, 5, 7, 3, 15, 59, 11, 17, 711, 721, 765, 3747, 13549, 28641, 47437, 42261}},
+{13306, 17, 64454, {1, 3, 7, 1, 3, 45, 65, 45, 279, 929, 933, 2215, 7095, 14593, 6047, 40747, 109789}},
+{13307, 17, 64458, {1, 3, 7, 15, 15, 55, 89, 155, 345, 515, 1005, 2921, 1761, 1095, 28463, 20971, 62451}},
+{13308, 17, 64482, {1, 3, 3, 1, 1, 41, 35, 149, 481, 171, 305, 1411, 237, 4515, 32375, 22645, 741}},
+{13309, 17, 64494, {1, 1, 1, 15, 17, 1, 123, 235, 221, 495, 1693, 3109, 6453, 8827, 23775, 9303, 30237}},
+{13310, 17, 64496, {1, 3, 3, 5, 7, 63, 37, 13, 457, 159, 1683, 2207, 1731, 3341, 7415, 21073, 119417}},
+{13311, 17, 64505, {1, 1, 7, 15, 21, 27, 5, 67, 267, 919, 203, 1129, 4029, 3407, 16767, 35485, 66903}},
+{13312, 17, 64514, {1, 1, 1, 5, 15, 29, 99, 5, 219, 677, 443, 3799, 2461, 747, 20885, 32661, 44079}},
+{13313, 17, 64519, {1, 1, 1, 1, 3, 55, 53, 151, 195, 587, 1155, 2439, 3817, 8735, 30849, 54107, 14113}},
+{13314, 17, 64525, {1, 1, 1, 9, 29, 15, 89, 175, 373, 925, 301, 3749, 5439, 2653, 22819, 41201, 77043}},
+{13315, 17, 64528, {1, 1, 1, 1, 25, 49, 29, 129, 331, 539, 1247, 773, 7891, 5905, 19571, 17919, 6815}},
+{13316, 17, 64534, {1, 1, 3, 15, 5, 63, 123, 133, 141, 383, 1893, 573, 629, 3939, 9455, 50433, 111415}},
+{13317, 17, 64561, {1, 1, 7, 9, 15, 33, 119, 159, 17, 511, 1841, 427, 3911, 8609, 4215, 9799, 84397}},
+{13318, 17, 64571, {1, 1, 7, 3, 9, 25, 63, 247, 235, 635, 915, 3423, 5421, 7021, 9203, 18121, 3683}},
+{13319, 17, 64579, {1, 3, 1, 1, 25, 11, 105, 1, 491, 137, 1923, 103, 3371, 3543, 5173, 36777, 23417}},
+{13320, 17, 64591, {1, 3, 3, 13, 19, 37, 93, 191, 101, 193, 351, 839, 7147, 5477, 29225, 45307, 1455}},
+{13321, 17, 64606, {1, 3, 1, 5, 11, 17, 95, 239, 105, 407, 395, 919, 3317, 14825, 23447, 4897, 128363}},
+{13322, 17, 64616, {1, 1, 1, 11, 27, 47, 83, 137, 163, 673, 1291, 3041, 4559, 7217, 23613, 19477, 93805}},
+{13323, 17, 64619, {1, 1, 1, 15, 25, 51, 37, 9, 23, 757, 1921, 2649, 5677, 11421, 10231, 1775, 124709}},
+{13324, 17, 64640, {1, 3, 1, 13, 31, 37, 37, 163, 59, 975, 1203, 1425, 1255, 3259, 16681, 38101, 118165}},
+{13325, 17, 64645, {1, 1, 3, 11, 17, 17, 31, 23, 169, 305, 3, 1631, 6853, 7019, 14539, 57663, 70377}},
+{13326, 17, 64649, {1, 1, 7, 3, 15, 61, 113, 31, 497, 935, 473, 819, 1223, 13907, 5075, 45177, 20255}},
+{13327, 17, 64652, {1, 3, 7, 13, 9, 41, 123, 121, 497, 877, 915, 3323, 4815, 4175, 25979, 38751, 107099}},
+{13328, 17, 64670, {1, 1, 3, 7, 13, 33, 31, 167, 331, 595, 517, 1237, 1947, 1905, 28155, 52431, 93065}},
+{13329, 17, 64673, {1, 3, 1, 1, 11, 51, 7, 151, 323, 211, 523, 2929, 233, 3633, 2785, 6043, 100101}},
+{13330, 17, 64674, {1, 1, 7, 13, 29, 3, 125, 247, 121, 567, 857, 3225, 7461, 15413, 773, 54939, 67443}},
+{13331, 17, 64683, {1, 1, 1, 15, 19, 29, 101, 179, 369, 115, 1777, 3223, 1499, 12487, 41, 50607, 111137}},
+{13332, 17, 64697, {1, 1, 3, 1, 9, 59, 21, 25, 173, 357, 1143, 1353, 3907, 10743, 30325, 39211, 116671}},
+{13333, 17, 64703, {1, 1, 7, 15, 9, 63, 67, 229, 7, 399, 2037, 3531, 6393, 4273, 9365, 52009, 118093}},
+{13334, 17, 64711, {1, 1, 7, 1, 31, 21, 5, 251, 433, 1, 481, 4041, 6179, 825, 8671, 20597, 103257}},
+{13335, 17, 64723, {1, 1, 7, 1, 15, 41, 69, 93, 47, 17, 1901, 2671, 4739, 1883, 30239, 50763, 108295}},
+{13336, 17, 64736, {1, 3, 7, 15, 29, 19, 63, 213, 475, 133, 43, 955, 2001, 555, 10479, 1333, 52807}},
+{13337, 17, 64739, {1, 3, 3, 15, 27, 13, 91, 109, 71, 333, 1971, 3355, 2175, 11457, 31101, 30217, 68263}},
+{13338, 17, 64741, {1, 1, 5, 1, 21, 33, 51, 169, 365, 475, 1015, 985, 7217, 15453, 7727, 49843, 57733}},
+{13339, 17, 64748, {1, 1, 7, 1, 11, 37, 67, 135, 429, 403, 1663, 2037, 7849, 3757, 6373, 38703, 46393}},
+{13340, 17, 64759, {1, 1, 1, 3, 15, 3, 29, 101, 327, 643, 47, 1805, 6873, 1659, 31097, 34847, 46843}},
+{13341, 17, 64768, {1, 3, 1, 15, 9, 45, 7, 189, 175, 955, 45, 3545, 3595, 7443, 2913, 54501, 63279}},
+{13342, 17, 64771, {1, 3, 7, 11, 1, 39, 59, 179, 209, 121, 445, 4077, 4851, 15161, 29133, 13543, 106247}},
+{13343, 17, 64778, {1, 3, 7, 7, 5, 53, 73, 107, 409, 639, 1731, 1921, 999, 14445, 17629, 3667, 74819}},
+{13344, 17, 64792, {1, 3, 3, 9, 23, 41, 117, 195, 497, 425, 627, 1599, 7715, 1401, 7217, 61113, 67135}},
+{13345, 17, 64821, {1, 1, 5, 13, 9, 33, 97, 115, 233, 833, 1041, 1755, 5317, 12703, 25709, 62293, 2569}},
+{13346, 17, 64831, {1, 1, 1, 11, 1, 7, 27, 151, 325, 905, 1279, 4093, 7495, 9803, 17339, 7977, 24009}},
+{13347, 17, 64839, {1, 3, 1, 11, 25, 59, 89, 175, 67, 139, 1507, 411, 7863, 9585, 14869, 46655, 126021}},
+{13348, 17, 64848, {1, 3, 3, 15, 29, 5, 111, 251, 69, 177, 519, 901, 4331, 5341, 22031, 3851, 114369}},
+{13349, 17, 64860, {1, 3, 5, 3, 19, 9, 83, 69, 411, 673, 1549, 3429, 3647, 12601, 17177, 16161, 114561}},
+{13350, 17, 64867, {1, 1, 5, 5, 21, 15, 65, 179, 405, 571, 1245, 3693, 7471, 12109, 20177, 28783, 124339}},
+{13351, 17, 64870, {1, 1, 5, 5, 9, 61, 69, 99, 9, 829, 1823, 3803, 1181, 3073, 10069, 28689, 21347}},
+{13352, 17, 64874, {1, 1, 5, 1, 3, 11, 25, 99, 241, 957, 1137, 7, 3809, 7073, 21217, 49447, 41425}},
+{13353, 17, 64879, {1, 3, 1, 9, 15, 59, 13, 29, 467, 893, 1667, 31, 3269, 12599, 28673, 17101, 81591}},
+{13354, 17, 64887, {1, 3, 7, 3, 15, 55, 79, 177, 1, 891, 217, 2725, 6171, 7779, 16173, 1003, 37093}},
+{13355, 17, 64894, {1, 3, 7, 11, 15, 61, 13, 181, 421, 83, 905, 1089, 4597, 3291, 23243, 53123, 21315}},
+{13356, 17, 64897, {1, 1, 3, 3, 21, 63, 113, 149, 203, 379, 583, 1955, 8087, 9155, 23019, 17757, 1537}},
+{13357, 17, 64898, {1, 3, 5, 9, 27, 41, 61, 207, 213, 253, 693, 273, 1835, 14135, 11519, 40819, 50999}},
+{13358, 17, 64921, {1, 3, 5, 3, 1, 51, 71, 237, 355, 327, 1903, 133, 6075, 4685, 29689, 48723, 67791}},
+{13359, 17, 64933, {1, 3, 5, 9, 21, 13, 101, 23, 95, 369, 1657, 989, 4081, 1373, 29005, 7247, 53923}},
+{13360, 17, 64940, {1, 1, 7, 13, 15, 3, 71, 189, 345, 771, 251, 937, 1041, 3017, 27279, 1635, 32581}},
+{13361, 17, 64957, {1, 1, 5, 7, 23, 63, 99, 43, 237, 189, 1549, 25, 63, 14089, 14387, 51423, 57193}},
+{13362, 17, 64969, {1, 1, 7, 15, 13, 55, 89, 87, 95, 241, 827, 501, 2341, 14357, 831, 27101, 98285}},
+{13363, 17, 64972, {1, 1, 1, 9, 29, 29, 125, 81, 73, 123, 329, 2617, 1259, 4415, 30007, 19467, 117847}},
+{13364, 17, 64978, {1, 3, 1, 11, 15, 63, 85, 121, 409, 885, 1197, 423, 2673, 12107, 1127, 14119, 90541}},
+{13365, 17, 64984, {1, 3, 1, 3, 1, 35, 117, 149, 213, 925, 923, 1013, 3547, 6877, 3467, 47893, 38645}},
+{13366, 17, 64993, {1, 1, 3, 15, 3, 21, 87, 199, 197, 851, 1711, 3449, 1771, 1727, 11651, 51903, 99835}},
+{13367, 17, 64999, {1, 3, 3, 1, 5, 27, 57, 243, 465, 173, 697, 4011, 6177, 3019, 31317, 24699, 53151}},
+{13368, 17, 65000, {1, 3, 5, 7, 7, 51, 61, 177, 489, 381, 493, 1975, 3143, 8003, 7735, 46363, 110705}},
+{13369, 17, 65006, {1, 1, 7, 5, 27, 45, 69, 33, 229, 725, 2033, 3655, 3027, 11795, 2941, 7921, 117605}},
+{13370, 17, 65011, {1, 3, 1, 7, 3, 37, 91, 255, 13, 651, 49, 309, 7425, 11641, 3661, 3929, 94199}},
+{13371, 17, 65014, {1, 3, 7, 5, 7, 47, 121, 203, 297, 941, 1585, 3659, 265, 159, 30729, 31825, 343}},
+{13372, 17, 65036, {1, 3, 5, 9, 3, 25, 95, 215, 125, 105, 37, 943, 4095, 8169, 26763, 20975, 122307}},
+{13373, 17, 65044, {1, 1, 3, 15, 9, 13, 81, 25, 51, 15, 599, 835, 6723, 9487, 25219, 60401, 48749}},
+{13374, 17, 65063, {1, 3, 3, 15, 15, 47, 41, 219, 77, 43, 1705, 2363, 7005, 7137, 17687, 665, 116097}},
+{13375, 17, 65067, {1, 3, 5, 1, 17, 33, 71, 3, 253, 355, 117, 1995, 3339, 11789, 13563, 58889, 18553}},
+{13376, 17, 65075, {1, 3, 5, 1, 21, 33, 89, 177, 9, 951, 1593, 1419, 3295, 9617, 31661, 7841, 119939}},
+{13377, 17, 65077, {1, 3, 3, 1, 31, 35, 25, 9, 379, 271, 923, 2387, 3351, 5869, 4501, 6855, 28273}},
+{13378, 17, 65082, {1, 1, 5, 9, 11, 15, 127, 79, 405, 579, 395, 2469, 5847, 7589, 17577, 61717, 6493}},
+{13379, 17, 65095, {1, 3, 7, 13, 29, 13, 99, 209, 79, 469, 5, 2231, 89, 1557, 5123, 47169, 46529}},
+{13380, 17, 65101, {1, 3, 7, 9, 13, 35, 119, 53, 7, 351, 601, 901, 5407, 13673, 6929, 38311, 2659}},
+{13381, 17, 65104, {1, 3, 7, 9, 13, 23, 61, 255, 113, 331, 367, 2979, 2741, 6971, 26447, 6861, 116267}},
+{13382, 17, 65109, {1, 1, 3, 3, 25, 57, 93, 5, 387, 87, 1765, 1277, 8175, 11185, 4377, 9779, 95569}},
+{13383, 17, 65110, {1, 1, 7, 11, 29, 43, 31, 155, 111, 409, 733, 1919, 2681, 8435, 5877, 35439, 15435}},
+{13384, 17, 65116, {1, 1, 1, 7, 19, 33, 109, 125, 51, 733, 997, 3467, 5081, 8371, 263, 31461, 46117}},
+{13385, 17, 65126, {1, 3, 3, 7, 27, 61, 57, 75, 317, 247, 1535, 3757, 4617, 15627, 11191, 3581, 64475}},
+{13386, 17, 65129, {1, 3, 3, 1, 31, 7, 95, 151, 159, 475, 559, 379, 361, 5953, 5551, 20313, 64015}},
+{13387, 17, 65138, {1, 1, 5, 1, 11, 31, 71, 77, 493, 697, 345, 1809, 611, 14319, 6591, 23657, 44071}},
+{13388, 17, 65160, {1, 1, 1, 13, 5, 1, 9, 233, 229, 397, 1201, 1817, 7409, 11521, 3753, 35611, 123037}},
+{13389, 17, 65171, {1, 3, 7, 15, 9, 15, 85, 163, 99, 867, 265, 1021, 129, 11059, 123, 27185, 68435}},
+{13390, 17, 65173, {1, 3, 1, 11, 25, 43, 105, 165, 291, 977, 463, 2699, 5361, 9951, 29735, 63501, 86235}},
+{13391, 17, 65180, {1, 3, 7, 13, 9, 33, 39, 145, 441, 233, 373, 193, 1451, 7975, 2871, 64431, 43339}},
+{13392, 17, 65189, {1, 1, 7, 13, 15, 25, 45, 27, 319, 719, 1801, 447, 3027, 769, 271, 37227, 26447}},
+{13393, 17, 65193, {1, 1, 5, 1, 29, 1, 59, 59, 121, 251, 387, 55, 5957, 10527, 24227, 38841, 29115}},
+{13394, 17, 65208, {1, 3, 1, 5, 31, 25, 67, 191, 137, 849, 631, 953, 3103, 9737, 28993, 49413, 60709}},
+{13395, 17, 65214, {1, 3, 3, 15, 7, 5, 37, 179, 357, 961, 1649, 441, 5287, 4161, 24013, 39661, 76233}},
+{13396, 17, 65216, {1, 1, 5, 1, 9, 1, 47, 209, 219, 1021, 969, 2343, 5675, 7137, 14247, 50305, 72613}},
+{13397, 17, 65225, {1, 1, 3, 1, 9, 43, 43, 47, 35, 97, 617, 1033, 2387, 14155, 17049, 53333, 108619}},
+{13398, 17, 65236, {1, 3, 1, 3, 1, 45, 11, 171, 349, 65, 909, 1801, 1075, 10905, 7395, 19997, 128205}},
+{13399, 17, 65239, {1, 1, 7, 11, 19, 39, 117, 175, 459, 791, 1383, 3473, 6937, 8447, 10077, 13353, 122063}},
+{13400, 17, 65273, {1, 3, 3, 9, 3, 27, 115, 29, 135, 305, 1023, 2517, 1981, 4969, 18149, 35565, 120785}},
+{13401, 17, 65274, {1, 3, 3, 11, 15, 23, 27, 115, 411, 805, 841, 2205, 5997, 5141, 10679, 25235, 81989}},
+{13402, 17, 65281, {1, 1, 3, 9, 11, 63, 27, 185, 337, 891, 1447, 1397, 8009, 4453, 23077, 37599, 93389}},
+{13403, 17, 65294, {1, 1, 5, 13, 27, 11, 77, 11, 447, 81, 1603, 2317, 6499, 6631, 27305, 51049, 40967}},
+{13404, 17, 65324, {1, 3, 7, 1, 7, 43, 83, 33, 69, 119, 139, 1391, 4879, 3759, 31211, 29203, 110229}},
+{13405, 17, 65335, {1, 3, 7, 15, 31, 59, 53, 97, 135, 233, 1421, 587, 2985, 3627, 7355, 53829, 51581}},
+{13406, 17, 65354, {1, 3, 7, 15, 1, 37, 39, 225, 147, 37, 327, 2819, 6081, 4337, 22063, 21177, 91065}},
+{13407, 17, 65359, {1, 1, 3, 1, 13, 31, 61, 133, 433, 243, 131, 3625, 6389, 335, 24029, 33217, 80833}},
+{13408, 17, 65373, {1, 1, 7, 11, 21, 39, 95, 181, 35, 499, 677, 3935, 1379, 6791, 12633, 13671, 28317}},
+{13409, 17, 65383, {1, 3, 1, 5, 7, 57, 5, 229, 389, 197, 1523, 1221, 609, 10449, 6389, 9279, 53871}},
+{13410, 17, 65387, {1, 3, 5, 7, 1, 39, 69, 131, 387, 839, 1375, 3841, 81, 7395, 5837, 32067, 51183}},
+{13411, 17, 65397, {1, 1, 5, 3, 5, 27, 107, 171, 53, 923, 345, 445, 1101, 11201, 20563, 30889, 72361}},
+{13412, 17, 65411, {1, 3, 7, 11, 19, 7, 99, 219, 485, 403, 293, 3967, 7517, 4765, 11331, 55, 92641}},
+{13413, 17, 65413, {1, 1, 7, 13, 19, 9, 73, 31, 405, 513, 941, 3645, 7075, 8109, 21431, 52791, 120927}},
+{13414, 17, 65418, {1, 1, 1, 15, 29, 33, 75, 65, 479, 47, 35, 4023, 4853, 2793, 29895, 2711, 83779}},
+{13415, 17, 65441, {1, 1, 3, 15, 11, 1, 9, 149, 503, 845, 647, 1233, 4355, 3623, 3197, 36015, 24839}},
+{13416, 17, 65444, {1, 1, 7, 1, 31, 35, 59, 25, 393, 503, 227, 3243, 301, 11121, 32463, 38185, 69969}},
+{13417, 17, 65447, {1, 1, 1, 7, 9, 15, 11, 89, 19, 605, 1657, 3335, 1967, 29, 28619, 42301, 79909}},
+{13418, 17, 65448, {1, 3, 7, 7, 19, 29, 111, 55, 299, 733, 547, 395, 4831, 1991, 7357, 25781, 115129}},
+{13419, 17, 65473, {1, 1, 3, 7, 5, 33, 31, 101, 163, 389, 1163, 1843, 4105, 14209, 29261, 5821, 17929}},
+{13420, 17, 65476, {1, 3, 5, 1, 11, 23, 53, 227, 497, 695, 313, 3305, 6549, 15401, 9339, 40283, 60531}},
+{13421, 17, 65480, {1, 3, 5, 5, 3, 29, 77, 149, 509, 747, 85, 2561, 4435, 14475, 22887, 38177, 24535}},
+{13422, 17, 65494, {1, 1, 7, 1, 1, 33, 7, 77, 153, 369, 689, 3325, 1173, 16203, 1499, 36627, 66915}},
+{13423, 17, 65509, {1, 1, 5, 11, 23, 61, 95, 61, 289, 71, 653, 2817, 365, 7391, 1613, 48901, 57471}},
+{13424, 17, 65519, {1, 3, 3, 7, 15, 29, 65, 133, 15, 921, 1601, 1941, 6917, 10945, 20101, 59809, 9017}},
+{13425, 17, 65527, {1, 3, 3, 15, 7, 51, 95, 53, 87, 1017, 1039, 3405, 1967, 9855, 4905, 4651, 83487}},
+{13426, 18, 19, {1, 3, 5, 13, 23, 27, 31, 179, 121, 597, 829, 4003, 2487, 3977, 3087, 26791, 28305, 138357}},
+{13427, 18, 31, {1, 1, 5, 5, 5, 39, 95, 117, 461, 117, 109, 2571, 7651, 12361, 17921, 555, 33353, 186427}},
+{13428, 18, 38, {1, 1, 3, 13, 23, 47, 89, 125, 271, 609, 215, 3861, 6883, 3217, 2547, 54943, 60565, 215939}},
+{13429, 18, 61, {1, 1, 7, 15, 25, 61, 47, 93, 219, 919, 1551, 1417, 2753, 4353, 9201, 46423, 31227, 150649}},
+{13430, 18, 64, {1, 1, 1, 3, 29, 39, 11, 61, 137, 809, 147, 2715, 5455, 9431, 5725, 46135, 118193, 54099}},
+{13431, 18, 109, {1, 1, 3, 1, 25, 37, 83, 211, 423, 779, 1731, 2827, 883, 10477, 28771, 21723, 114333, 56293}},
+{13432, 18, 115, {1, 1, 5, 5, 27, 17, 21, 125, 495, 655, 1803, 3555, 1997, 15593, 29705, 48537, 53935, 179773}},
+{13433, 18, 118, {1, 1, 7, 5, 19, 63, 55, 15, 469, 769, 967, 3047, 1713, 11655, 15313, 29965, 78857, 223391}},
+{13434, 18, 131, {1, 3, 3, 5, 27, 33, 51, 171, 417, 243, 1203, 3505, 2533, 2695, 219, 57423, 5145, 143165}},
+{13435, 18, 167, {1, 3, 5, 9, 5, 19, 95, 97, 1, 863, 693, 2977, 4839, 6649, 22587, 40745, 113839, 69131}},
+{13436, 18, 200, {1, 3, 5, 1, 31, 39, 53, 85, 509, 5, 359, 1947, 3279, 5433, 21763, 46713, 37289, 35911}},
+{13437, 18, 241, {1, 3, 7, 13, 17, 35, 59, 63, 95, 667, 1775, 2165, 7861, 15731, 12159, 36179, 115457, 184819}},
+{13438, 18, 244, {1, 3, 3, 15, 19, 51, 7, 83, 367, 573, 503, 535, 333, 13041, 7187, 14479, 57473, 242951}},
+{13439, 18, 247, {1, 3, 5, 1, 7, 27, 65, 201, 365, 445, 985, 1175, 6391, 7345, 19935, 29085, 103001, 231855}},
+{13440, 18, 261, {1, 3, 5, 13, 15, 61, 95, 125, 135, 217, 1787, 417, 7641, 11825, 14531, 48497, 125087, 73279}},
+{13441, 18, 265, {1, 1, 5, 13, 7, 25, 77, 99, 341, 447, 1711, 137, 2749, 3465, 26255, 719, 102595, 112825}},
+{13442, 18, 304, {1, 1, 7, 7, 15, 13, 127, 57, 359, 591, 713, 409, 1293, 4979, 7035, 11369, 85255, 207241}},
+{13443, 18, 314, {1, 3, 3, 5, 1, 45, 123, 183, 297, 375, 1269, 1197, 2389, 6269, 24549, 44643, 75893, 161509}},
+{13444, 18, 341, {1, 1, 5, 7, 17, 55, 67, 51, 449, 383, 2037, 871, 1359, 15317, 22055, 4655, 18065, 258271}},
+{13445, 18, 376, {1, 1, 3, 11, 21, 27, 59, 205, 145, 195, 1747, 1121, 1061, 8879, 31455, 56541, 74765, 183047}},
+{13446, 18, 395, {1, 1, 5, 15, 1, 11, 69, 157, 13, 185, 1355, 467, 4383, 13103, 21679, 35169, 33427, 32113}},
+{13447, 18, 405, {1, 3, 1, 3, 29, 41, 15, 209, 313, 61, 1749, 2457, 1897, 15595, 24441, 39913, 40499, 5179}},
+{13448, 18, 406, {1, 3, 7, 15, 25, 41, 87, 125, 239, 73, 207, 2043, 1133, 12845, 8533, 16339, 117913, 118677}},
+{13449, 18, 443, {1, 1, 3, 15, 25, 9, 15, 97, 395, 99, 2017, 1003, 847, 2535, 11753, 54769, 54011, 73541}},
+{13450, 18, 451, {1, 1, 7, 15, 11, 61, 13, 49, 319, 871, 893, 165, 3957, 8683, 31197, 39491, 58705, 213411}},
+{13451, 18, 458, {1, 3, 7, 3, 17, 43, 29, 81, 461, 595, 541, 243, 5587, 13083, 29981, 16187, 124601, 89543}},
+{13452, 18, 460, {1, 1, 5, 11, 7, 5, 61, 43, 445, 115, 1705, 419, 4627, 15063, 16053, 26249, 112243, 208711}},
+{13453, 18, 468, {1, 3, 3, 9, 27, 21, 89, 49, 41, 859, 681, 2043, 7445, 9591, 13443, 36981, 66785, 227899}},
+{13454, 18, 472, {1, 1, 3, 5, 11, 55, 51, 45, 41, 739, 1199, 191, 4563, 4035, 3657, 12189, 52879, 33961}},
+{13455, 18, 482, {1, 1, 1, 3, 17, 59, 47, 217, 389, 783, 1501, 517, 6311, 7903, 1371, 50617, 41723, 116473}},
+{13456, 18, 491, {1, 1, 5, 13, 29, 39, 101, 203, 101, 479, 1337, 2647, 6447, 563, 2593, 16533, 122535, 25587}},
+{13457, 18, 496, {1, 1, 3, 3, 27, 21, 75, 173, 289, 279, 665, 3177, 559, 8539, 10903, 16779, 128219, 125907}},
+{13458, 18, 524, {1, 1, 1, 11, 27, 1, 61, 247, 113, 585, 331, 3443, 5939, 5213, 27289, 57057, 17349, 62359}},
+{13459, 18, 536, {1, 3, 5, 15, 21, 41, 67, 47, 121, 11, 545, 3609, 7745, 3669, 9045, 8377, 97655, 99631}},
+{13460, 18, 542, {1, 3, 5, 9, 11, 15, 111, 61, 67, 775, 579, 3421, 7827, 13607, 32373, 43531, 86149, 238827}},
+{13461, 18, 557, {1, 1, 1, 1, 9, 45, 79, 153, 331, 399, 1777, 3515, 3363, 3499, 13461, 48651, 21731, 220611}},
+{13462, 18, 572, {1, 1, 1, 1, 31, 57, 117, 223, 139, 725, 1115, 3203, 8185, 11983, 20245, 55913, 36803, 68101}},
+{13463, 18, 580, {1, 1, 1, 3, 31, 57, 53, 79, 225, 307, 1645, 3311, 643, 6587, 12037, 12453, 83461, 195503}},
+{13464, 18, 592, {1, 3, 1, 7, 23, 25, 65, 233, 273, 97, 37, 1563, 3635, 9299, 24367, 42761, 55, 128675}},
+{13465, 18, 656, {1, 3, 3, 11, 29, 21, 97, 143, 447, 345, 389, 381, 1403, 685, 309, 11103, 69769, 194441}},
+{13466, 18, 713, {1, 3, 3, 11, 23, 55, 119, 71, 23, 291, 1241, 1723, 5025, 4499, 26617, 22875, 62185, 240321}},
+{13467, 18, 719, {1, 1, 7, 11, 19, 63, 31, 131, 393, 99, 1061, 3805, 7477, 15357, 8269, 26067, 113349, 239333}},
+{13468, 18, 738, {1, 3, 5, 1, 5, 37, 77, 83, 37, 759, 1297, 3067, 5369, 5977, 7531, 49079, 94503, 192765}},
+{13469, 18, 749, {1, 1, 7, 1, 23, 9, 119, 137, 469, 73, 2001, 2629, 2681, 2295, 2055, 44027, 47627, 45283}},
+{13470, 18, 752, {1, 3, 1, 7, 31, 17, 61, 137, 241, 325, 1417, 2383, 4171, 2495, 215, 59593, 98495, 74727}},
+{13471, 18, 767, {1, 1, 7, 13, 7, 5, 59, 189, 131, 865, 1963, 1811, 5629, 16189, 16397, 58069, 72081, 191457}},
+{13472, 18, 772, {1, 1, 7, 15, 23, 33, 93, 247, 395, 643, 693, 3587, 4375, 5519, 9449, 37515, 11455, 218337}},
+{13473, 18, 782, {1, 1, 3, 1, 27, 63, 113, 91, 477, 55, 1461, 1547, 4743, 699, 21639, 1815, 169, 34239}},
+{13474, 18, 789, {1, 1, 5, 15, 29, 37, 19, 19, 247, 771, 695, 319, 1779, 10553, 16165, 60507, 87161, 86967}},
+{13475, 18, 830, {1, 1, 7, 1, 25, 61, 13, 167, 251, 861, 1717, 1533, 7323, 3945, 20879, 37759, 129689, 35901}},
+{13476, 18, 838, {1, 3, 3, 7, 7, 61, 11, 25, 187, 949, 1393, 1743, 745, 16313, 5293, 16921, 17619, 237705}},
+{13477, 18, 916, {1, 3, 5, 11, 7, 27, 11, 107, 299, 711, 149, 1581, 7747, 14285, 6411, 52209, 79043, 61117}},
+{13478, 18, 920, {1, 1, 5, 1, 17, 19, 91, 185, 53, 699, 1185, 4007, 1099, 1965, 20239, 19547, 120859, 234149}},
+{13479, 18, 936, {1, 1, 5, 5, 13, 61, 117, 187, 149, 957, 837, 3549, 6221, 501, 24755, 47975, 67007, 12329}},
+{13480, 18, 991, {1, 1, 3, 15, 21, 41, 55, 81, 397, 403, 1699, 1057, 6125, 11987, 3103, 43361, 21277, 156577}},
+{13481, 18, 998, {1, 1, 5, 11, 5, 27, 5, 177, 387, 859, 809, 3919, 4085, 1535, 6009, 13265, 3065, 217945}},
+{13482, 18, 1016, {1, 3, 1, 13, 15, 57, 107, 81, 437, 305, 879, 1691, 3685, 11415, 3749, 46999, 113933, 10515}},
+{13483, 18, 1024, {1, 1, 7, 13, 9, 43, 59, 223, 189, 329, 829, 2033, 1835, 8255, 8121, 46463, 61433, 86453}},
+{13484, 18, 1053, {1, 3, 1, 9, 11, 49, 63, 125, 11, 987, 2017, 2623, 4753, 13889, 57, 24755, 108489, 175383}},
+{13485, 18, 1081, {1, 1, 1, 3, 25, 33, 39, 151, 405, 657, 1755, 957, 5557, 7611, 25839, 51385, 92713, 64009}},
+{13486, 18, 1090, {1, 3, 7, 9, 17, 17, 115, 89, 225, 715, 1085, 543, 1047, 15053, 14359, 43301, 31455, 156555}},
+{13487, 18, 1125, {1, 1, 7, 11, 11, 21, 115, 5, 371, 1003, 1053, 1713, 5921, 7277, 799, 62483, 28079, 222319}},
+{13488, 18, 1135, {1, 1, 3, 3, 31, 15, 127, 213, 459, 229, 1477, 1863, 1021, 14881, 16299, 5953, 121455, 49659}},
+{13489, 18, 1143, {1, 1, 5, 9, 3, 39, 87, 219, 57, 479, 69, 2777, 8105, 11975, 14743, 26205, 93303, 45311}},
+{13490, 18, 1150, {1, 1, 5, 13, 3, 43, 55, 139, 19, 715, 2035, 2993, 2945, 9075, 6275, 32233, 103127, 49523}},
+{13491, 18, 1154, {1, 3, 1, 13, 19, 31, 109, 211, 261, 231, 697, 383, 2173, 14617, 11877, 37009, 5485, 236549}},
+{13492, 18, 1171, {1, 1, 5, 3, 5, 23, 91, 115, 369, 11, 1021, 519, 655, 4461, 23743, 56981, 51687, 114845}},
+{13493, 18, 1174, {1, 3, 7, 9, 29, 23, 19, 127, 17, 369, 1537, 2705, 4993, 1869, 15447, 28127, 73609, 97683}},
+{13494, 18, 1202, {1, 1, 3, 9, 17, 61, 97, 187, 213, 861, 725, 3205, 103, 12729, 2915, 28389, 83123, 124065}},
+{13495, 18, 1213, {1, 3, 1, 1, 5, 61, 47, 187, 471, 137, 1595, 707, 2449, 14315, 16409, 41467, 37533, 1649}},
+{13496, 18, 1225, {1, 3, 5, 5, 7, 39, 1, 245, 361, 43, 1259, 3149, 3449, 15723, 6225, 27445, 80529, 215349}},
+{13497, 18, 1233, {1, 3, 3, 11, 17, 27, 37, 47, 157, 345, 1437, 3219, 5663, 7299, 23925, 34067, 102379, 42767}},
+{13498, 18, 1234, {1, 3, 5, 13, 21, 59, 43, 189, 17, 303, 1949, 3627, 3495, 7981, 18115, 34221, 43511, 255257}},
+{13499, 18, 1252, {1, 3, 7, 15, 3, 29, 81, 243, 321, 853, 595, 2451, 1713, 11859, 27689, 12849, 24505, 9547}},
+{13500, 18, 1255, {1, 3, 1, 3, 7, 7, 89, 183, 51, 901, 253, 2421, 7453, 15827, 21451, 58653, 51933, 239113}},
+{13501, 18, 1294, {1, 1, 7, 3, 21, 59, 93, 25, 219, 805, 1699, 3777, 3683, 5351, 5481, 44797, 651, 32161}},
+{13502, 18, 1349, {1, 3, 7, 5, 31, 15, 15, 167, 305, 545, 331, 3765, 8191, 5763, 16965, 7239, 73735, 1049}},
+{13503, 18, 1354, {1, 3, 1, 15, 13, 19, 59, 107, 213, 39, 1547, 3413, 6175, 16195, 4635, 8945, 60301, 196697}},
+{13504, 18, 1378, {1, 1, 3, 1, 29, 17, 51, 61, 261, 951, 643, 2329, 2235, 9171, 11265, 3523, 89781, 227125}},
+{13505, 18, 1383, {1, 3, 5, 1, 1, 51, 75, 199, 479, 899, 1425, 3697, 2039, 4503, 11789, 16853, 94607, 236887}},
+{13506, 18, 1387, {1, 3, 1, 9, 19, 43, 111, 41, 385, 677, 1067, 3391, 7819, 13663, 17713, 10155, 124243, 56005}},
+{13507, 18, 1392, {1, 3, 5, 3, 15, 3, 105, 23, 307, 955, 843, 1277, 6697, 11903, 8901, 36129, 51685, 251115}},
+{13508, 18, 1402, {1, 3, 1, 5, 27, 35, 95, 57, 207, 49, 1559, 171, 4703, 511, 4169, 23241, 111447, 173109}},
+{13509, 18, 1420, {1, 3, 1, 13, 23, 5, 31, 15, 223, 673, 1333, 2243, 2479, 7489, 31891, 33909, 96803, 227027}},
+{13510, 18, 1428, {1, 3, 5, 11, 5, 45, 19, 13, 367, 475, 1719, 3947, 5295, 2319, 20697, 181, 16925, 80239}},
+{13511, 18, 1437, {1, 1, 5, 13, 15, 47, 89, 15, 153, 73, 523, 3529, 5401, 15881, 13779, 32123, 82347, 58749}},
+{13512, 18, 1448, {1, 3, 5, 7, 5, 7, 123, 217, 261, 65, 685, 2175, 3289, 7473, 17857, 48335, 94183, 216857}},
+{13513, 18, 1459, {1, 3, 7, 13, 7, 23, 85, 25, 231, 19, 1179, 2705, 6433, 10827, 1969, 51521, 76775, 260291}},
+{13514, 18, 1473, {1, 3, 3, 13, 9, 39, 5, 141, 475, 777, 1809, 1975, 2347, 12611, 28303, 15239, 45429, 170015}},
+{13515, 18, 1507, {1, 1, 7, 7, 31, 31, 39, 19, 317, 897, 739, 275, 2261, 16013, 1123, 33181, 96603, 37563}},
+{13516, 18, 1516, {1, 1, 7, 13, 31, 55, 87, 239, 193, 435, 625, 2153, 3979, 15537, 19937, 50621, 48273, 31381}},
+{13517, 18, 1528, {1, 1, 1, 15, 1, 57, 73, 237, 361, 749, 379, 2511, 501, 10783, 2787, 36983, 12393, 14345}},
+{13518, 18, 1573, {1, 1, 1, 3, 25, 33, 85, 25, 83, 939, 139, 2601, 6385, 16041, 28463, 38977, 28163, 232165}},
+{13519, 18, 1592, {1, 3, 5, 3, 9, 19, 119, 171, 499, 19, 569, 353, 1619, 6235, 24431, 47401, 48125, 168819}},
+{13520, 18, 1597, {1, 1, 1, 3, 9, 27, 121, 137, 411, 391, 1437, 1339, 7475, 3889, 15451, 34809, 69807, 162851}},
+{13521, 18, 1654, {1, 3, 5, 11, 31, 39, 41, 3, 171, 35, 81, 2713, 1077, 10697, 12343, 52133, 52825, 152255}},
+{13522, 18, 1663, {1, 1, 3, 11, 17, 51, 83, 19, 357, 207, 897, 2167, 1333, 4111, 29295, 65371, 73447, 61765}},
+{13523, 18, 1730, {1, 1, 3, 7, 9, 59, 17, 135, 365, 931, 1203, 277, 5531, 4213, 12969, 2617, 591, 154539}},
+{13524, 18, 1739, {1, 3, 7, 11, 1, 53, 31, 49, 135, 603, 227, 911, 7371, 8559, 27195, 33065, 71351, 245255}},
+{13525, 18, 1741, {1, 1, 7, 1, 15, 5, 31, 135, 197, 791, 1531, 2567, 2545, 15515, 25417, 27431, 15571, 176829}},
+{13526, 18, 1753, {1, 3, 1, 1, 15, 7, 89, 217, 505, 859, 1329, 2285, 7921, 11839, 7699, 56867, 112483, 3895}},
+{13527, 18, 1783, {1, 3, 1, 3, 27, 57, 37, 117, 491, 815, 275, 381, 7443, 3297, 1523, 34211, 97589, 232261}},
+{13528, 18, 1804, {1, 1, 3, 3, 29, 63, 69, 153, 297, 423, 1435, 3927, 7265, 13223, 17607, 21201, 57929, 73037}},
+{13529, 18, 1807, {1, 3, 1, 3, 23, 41, 1, 167, 121, 217, 973, 2149, 3807, 9895, 29635, 1625, 99829, 218541}},
+{13530, 18, 1832, {1, 3, 5, 7, 31, 33, 53, 165, 51, 119, 7, 1655, 6521, 5481, 9503, 6833, 80483, 252111}},
+{13531, 18, 1850, {1, 1, 7, 1, 5, 63, 25, 219, 165, 893, 1665, 2789, 1113, 9277, 3151, 12625, 82403, 59749}},
+{13532, 18, 1852, {1, 3, 7, 3, 21, 13, 127, 127, 145, 993, 715, 1947, 7501, 4385, 11759, 2179, 26039, 28027}},
+{13533, 18, 1881, {1, 3, 5, 9, 23, 27, 123, 1, 231, 709, 1615, 1433, 5991, 1045, 16269, 123, 110249, 154819}},
+{13534, 18, 1894, {1, 1, 1, 5, 17, 11, 123, 151, 387, 905, 991, 1571, 4463, 6765, 31905, 59307, 75175, 204571}},
+{13535, 18, 1927, {1, 3, 1, 11, 27, 49, 1, 181, 77, 1023, 807, 3479, 7965, 4633, 17495, 5991, 77081, 249343}},
+{13536, 18, 1952, {1, 3, 1, 1, 13, 53, 105, 79, 269, 173, 1319, 1695, 1215, 3651, 25063, 34949, 77243, 214671}},
+{13537, 18, 1969, {1, 1, 1, 1, 3, 19, 103, 233, 1, 507, 721, 1797, 5025, 405, 13027, 23693, 89963, 25771}},
+{13538, 18, 1999, {1, 3, 5, 9, 21, 53, 1, 241, 405, 707, 1807, 3615, 1199, 11155, 27741, 53931, 55091, 248677}},
+{13539, 18, 2018, {1, 3, 5, 7, 27, 27, 39, 77, 475, 845, 1393, 3779, 5261, 13017, 13517, 18595, 64485, 180577}},
+{13540, 18, 2047, {1, 1, 3, 5, 7, 21, 95, 59, 203, 233, 1167, 3457, 3965, 4321, 14885, 6335, 78353, 39341}},
+{13541, 18, 2066, {1, 1, 7, 13, 27, 19, 27, 133, 419, 507, 945, 3595, 131, 7981, 31451, 62347, 19151, 256127}},
+{13542, 18, 2068, {1, 3, 7, 3, 7, 15, 9, 173, 257, 983, 223, 2881, 6911, 3681, 26183, 38943, 112171, 148627}},
+{13543, 18, 2093, {1, 3, 3, 15, 5, 49, 91, 205, 303, 183, 775, 3841, 4943, 14417, 23013, 59337, 85835, 181771}},
+{13544, 18, 2105, {1, 3, 5, 9, 21, 1, 117, 27, 509, 263, 1215, 893, 6677, 3275, 20831, 5045, 127323, 62589}},
+{13545, 18, 2116, {1, 1, 1, 3, 17, 61, 77, 239, 379, 649, 1151, 2359, 2659, 13853, 30589, 55873, 50359, 184125}},
+{13546, 18, 2149, {1, 1, 7, 5, 17, 33, 95, 111, 245, 873, 1721, 3079, 7753, 12889, 27107, 8267, 119413, 249045}},
+{13547, 18, 2201, {1, 1, 1, 15, 13, 23, 59, 169, 449, 283, 913, 2099, 5337, 4307, 3701, 16395, 112987, 14183}},
+{13548, 18, 2228, {1, 1, 5, 3, 5, 15, 3, 249, 97, 849, 1551, 3437, 1247, 10915, 24073, 53723, 40345, 37215}},
+{13549, 18, 2245, {1, 1, 1, 5, 21, 59, 109, 79, 9, 827, 1329, 405, 3821, 8415, 11239, 1003, 78967, 112627}},
+{13550, 18, 2246, {1, 1, 1, 11, 21, 7, 21, 45, 327, 365, 865, 1409, 1273, 15675, 21425, 45367, 22279, 240943}},
+{13551, 18, 2283, {1, 3, 3, 7, 3, 19, 83, 163, 381, 547, 195, 1537, 7905, 9057, 1309, 41135, 118857, 101725}},
+{13552, 18, 2288, {1, 1, 5, 9, 11, 19, 107, 247, 309, 343, 1697, 699, 7137, 12815, 18405, 42673, 505, 104801}},
+{13553, 18, 2320, {1, 3, 5, 3, 13, 43, 55, 15, 441, 843, 1153, 3739, 67, 11053, 30985, 55329, 57301, 190991}},
+{13554, 18, 2326, {1, 1, 5, 3, 23, 41, 9, 239, 227, 145, 1895, 2645, 945, 6421, 2859, 16173, 97043, 234649}},
+{13555, 18, 2386, {1, 3, 1, 3, 23, 47, 57, 207, 441, 279, 1951, 3041, 2465, 6143, 27669, 41171, 89627, 2489}},
+{13556, 18, 2392, {1, 3, 1, 11, 7, 9, 19, 51, 345, 187, 1699, 1483, 15, 10321, 25277, 34889, 85225, 259071}},
+{13557, 18, 2395, {1, 1, 1, 15, 27, 15, 79, 51, 407, 757, 611, 3955, 1123, 14659, 11273, 56639, 64727, 183077}},
+{13558, 18, 2413, {1, 3, 7, 1, 13, 61, 89, 157, 29, 561, 791, 995, 4233, 11351, 16335, 47041, 108671, 120115}},
+{13559, 18, 2419, {1, 3, 3, 15, 17, 35, 15, 223, 57, 7, 961, 3327, 7287, 5537, 26231, 3289, 106555, 109781}},
+{13560, 18, 2441, {1, 3, 7, 15, 17, 3, 25, 121, 349, 995, 1353, 2991, 3071, 3583, 26173, 42343, 60495, 44035}},
+{13561, 18, 2466, {1, 3, 1, 11, 5, 5, 83, 249, 427, 173, 1733, 45, 3277, 7911, 18091, 61305, 130251, 31849}},
+{13562, 18, 2477, {1, 1, 1, 9, 3, 23, 23, 127, 371, 1011, 573, 1769, 1707, 15351, 30077, 61139, 122963, 203481}},
+{13563, 18, 2485, {1, 1, 1, 13, 27, 41, 97, 29, 461, 207, 1393, 707, 5633, 7155, 13455, 7305, 107539, 136413}},
+{13564, 18, 2492, {1, 1, 1, 9, 3, 13, 61, 115, 297, 333, 1679, 127, 8049, 3129, 31845, 40039, 77087, 6831}},
+{13565, 18, 2495, {1, 3, 3, 11, 27, 25, 49, 29, 423, 193, 1955, 2927, 5679, 3537, 16911, 47065, 126803, 129957}},
+{13566, 18, 2498, {1, 1, 1, 3, 21, 31, 25, 187, 301, 883, 1301, 415, 1515, 14761, 227, 24377, 54415, 64553}},
+{13567, 18, 2504, {1, 3, 7, 7, 3, 5, 69, 221, 357, 587, 1387, 3719, 5355, 10569, 14731, 22515, 107237, 1673}},
+{13568, 18, 2515, {1, 1, 3, 15, 27, 7, 89, 23, 213, 655, 779, 1641, 1793, 1499, 27279, 59423, 56715, 90313}},
+{13569, 18, 2521, {1, 3, 3, 7, 3, 33, 85, 181, 509, 327, 353, 1625, 4995, 15627, 17071, 31885, 122423, 100337}},
+{13570, 18, 2561, {1, 3, 5, 9, 7, 39, 45, 157, 279, 211, 1163, 3283, 4419, 10187, 22397, 42119, 25105, 163925}},
+{13571, 18, 2579, {1, 3, 3, 15, 17, 37, 75, 65, 501, 765, 1171, 2451, 309, 551, 15573, 65497, 106435, 20817}},
+{13572, 18, 2604, {1, 1, 3, 1, 13, 1, 79, 117, 5, 285, 953, 2401, 2479, 15765, 25677, 63611, 91807, 78153}},
+{13573, 18, 2657, {1, 1, 5, 15, 1, 7, 123, 159, 217, 307, 1779, 2625, 101, 13887, 31721, 55769, 94899, 183427}},
+{13574, 18, 2681, {1, 3, 5, 5, 11, 13, 59, 205, 221, 871, 753, 823, 547, 11055, 31621, 54379, 23631, 137027}},
+{13575, 18, 2691, {1, 3, 3, 7, 5, 17, 7, 31, 37, 237, 1633, 969, 4123, 6643, 28499, 3277, 130223, 37465}},
+{13576, 18, 2731, {1, 3, 7, 5, 29, 41, 65, 159, 487, 61, 1217, 4093, 487, 15257, 13379, 46641, 88043, 107425}},
+{13577, 18, 2739, {1, 1, 7, 7, 19, 29, 87, 119, 13, 877, 467, 2661, 7733, 9303, 20069, 8445, 126159, 69421}},
+{13578, 18, 2765, {1, 3, 1, 13, 1, 57, 77, 241, 185, 479, 859, 2397, 1167, 6545, 20715, 50701, 107781, 149965}},
+{13579, 18, 2790, {1, 1, 5, 1, 1, 3, 19, 31, 473, 685, 1455, 1537, 1843, 4051, 17475, 56717, 70257, 112815}},
+{13580, 18, 2802, {1, 3, 7, 15, 9, 21, 19, 201, 13, 551, 1053, 1291, 3793, 7923, 30425, 55513, 30033, 70597}},
+{13581, 18, 2819, {1, 3, 1, 15, 21, 47, 127, 117, 199, 655, 1979, 1291, 8017, 11769, 9071, 12029, 112369, 2529}},
+{13582, 18, 2891, {1, 3, 5, 1, 15, 3, 25, 199, 101, 997, 597, 2485, 6509, 11913, 19573, 13985, 56165, 249}},
+{13583, 18, 2905, {1, 1, 7, 3, 19, 45, 107, 229, 241, 747, 1219, 3133, 3675, 4441, 13933, 64571, 95445, 250713}},
+{13584, 18, 2911, {1, 3, 1, 5, 11, 31, 89, 119, 503, 99, 75, 349, 7479, 15161, 6365, 62461, 39443, 188455}},
+{13585, 18, 2912, {1, 1, 5, 13, 25, 31, 65, 237, 259, 329, 89, 1283, 6033, 4401, 7655, 38837, 62367, 76555}},
+{13586, 18, 2921, {1, 1, 1, 7, 19, 61, 109, 41, 361, 89, 171, 2319, 3625, 8905, 24461, 36135, 28515, 101547}},
+{13587, 18, 2924, {1, 3, 5, 3, 5, 45, 123, 227, 339, 79, 309, 2619, 1621, 1295, 6395, 6717, 119933, 187231}},
+{13588, 18, 2945, {1, 1, 1, 3, 3, 45, 91, 225, 269, 475, 1159, 2599, 5087, 4141, 28375, 22413, 56235, 256559}},
+{13589, 18, 2952, {1, 1, 1, 13, 7, 51, 27, 65, 65, 381, 169, 1759, 4653, 9885, 25839, 19851, 4965, 249097}},
+{13590, 18, 2972, {1, 3, 7, 11, 25, 11, 83, 137, 419, 277, 503, 2823, 2759, 8173, 9405, 23731, 116087, 9735}},
+{13591, 18, 2986, {1, 1, 5, 5, 27, 17, 123, 145, 41, 85, 1099, 1087, 1465, 7063, 8585, 39427, 15479, 243967}},
+{13592, 18, 3000, {1, 1, 7, 3, 21, 53, 105, 185, 101, 763, 593, 2649, 3273, 5655, 12233, 11761, 27093, 121347}},
+{13593, 18, 3008, {1, 1, 1, 5, 11, 55, 107, 167, 179, 681, 741, 1821, 4297, 14677, 9949, 9647, 60465, 36999}},
+{13594, 18, 3011, {1, 1, 1, 7, 25, 43, 95, 71, 161, 517, 1475, 1989, 6273, 13295, 19681, 51773, 93523, 33441}},
+{13595, 18, 3018, {1, 3, 1, 13, 23, 59, 95, 177, 73, 707, 37, 421, 3747, 14207, 17159, 4957, 20161, 26185}},
+{13596, 18, 3047, {1, 1, 7, 13, 13, 1, 19, 153, 445, 429, 1911, 3515, 639, 16015, 833, 54347, 87717, 82175}},
+{13597, 18, 3071, {1, 3, 5, 9, 1, 9, 115, 87, 341, 651, 1583, 807, 559, 13579, 9647, 37277, 125555, 169655}},
+{13598, 18, 3079, {1, 1, 3, 5, 13, 23, 117, 229, 205, 803, 1381, 2773, 7099, 4031, 597, 37135, 11643, 92325}},
+{13599, 18, 3083, {1, 3, 7, 9, 27, 15, 33, 147, 1, 799, 1511, 2609, 1419, 5991, 15571, 56995, 97695, 223969}},
+{13600, 18, 3086, {1, 3, 1, 3, 17, 9, 17, 189, 407, 355, 765, 2545, 1079, 15253, 4785, 5187, 80775, 238775}},
+{13601, 18, 3148, {1, 1, 3, 1, 31, 29, 3, 159, 263, 325, 125, 2221, 6369, 5717, 13985, 33829, 21375, 134249}},
+{13602, 18, 3156, {1, 3, 7, 3, 5, 29, 39, 75, 183, 155, 1017, 637, 921, 9561, 14893, 59695, 38325, 15503}},
+{13603, 18, 3194, {1, 1, 3, 13, 9, 31, 43, 71, 241, 661, 325, 357, 431, 903, 5039, 24535, 94241, 228605}},
+{13604, 18, 3230, {1, 3, 1, 1, 17, 37, 93, 47, 25, 207, 611, 415, 6473, 15979, 2025, 19003, 8941, 248779}},
+{13605, 18, 3233, {1, 1, 7, 15, 19, 17, 81, 201, 121, 11, 1975, 1289, 4405, 7851, 9707, 20057, 33749, 187161}},
+{13606, 18, 3254, {1, 1, 3, 5, 29, 31, 47, 99, 435, 795, 947, 1299, 4011, 8315, 12827, 48071, 86567, 154655}},
+{13607, 18, 3268, {1, 1, 5, 3, 9, 59, 115, 191, 177, 65, 1835, 3989, 1819, 14325, 8939, 25337, 16099, 200577}},
+{13608, 18, 3305, {1, 3, 7, 9, 15, 47, 7, 195, 413, 1013, 1607, 3317, 6979, 13243, 275, 34125, 66069, 90201}},
+{13609, 18, 3323, {1, 1, 3, 3, 29, 3, 51, 137, 341, 393, 897, 351, 1937, 6793, 12551, 18873, 110949, 133925}},
+{13610, 18, 3326, {1, 3, 5, 9, 29, 41, 79, 169, 113, 123, 1229, 1885, 6153, 1549, 31729, 41949, 74083, 41387}},
+{13611, 18, 3343, {1, 3, 1, 15, 31, 49, 7, 233, 305, 435, 1299, 3037, 2387, 15431, 817, 11783, 24067, 116527}},
+{13612, 18, 3345, {1, 3, 5, 13, 7, 17, 49, 33, 133, 45, 689, 2381, 2649, 2433, 27535, 21755, 88611, 200585}},
+{13613, 18, 3382, {1, 1, 5, 11, 1, 61, 87, 97, 91, 433, 313, 2541, 5289, 5769, 17963, 5719, 12165, 146849}},
+{13614, 18, 3413, {1, 3, 7, 13, 17, 21, 37, 191, 489, 847, 841, 3567, 7339, 15233, 23973, 1209, 99741, 243303}},
+{13615, 18, 3420, {1, 3, 1, 1, 5, 21, 11, 39, 69, 751, 1679, 143, 6187, 2963, 695, 45763, 126749, 243841}},
+{13616, 18, 3434, {1, 3, 3, 9, 21, 55, 43, 73, 133, 417, 495, 2899, 5681, 13049, 30241, 44519, 19095, 30673}},
+{13617, 18, 3453, {1, 1, 5, 9, 17, 51, 121, 205, 273, 597, 1325, 3755, 5113, 12287, 21323, 17947, 23807, 20025}},
+{13618, 18, 3472, {1, 1, 7, 7, 21, 11, 25, 33, 207, 13, 1639, 1971, 7401, 11771, 7879, 59027, 111981, 65451}},
+{13619, 18, 3488, {1, 3, 5, 15, 3, 15, 121, 23, 199, 839, 937, 3659, 5379, 2139, 31631, 17215, 65349, 157413}},
+{13620, 18, 3503, {1, 1, 1, 7, 3, 7, 81, 49, 17, 693, 1819, 2737, 7329, 49, 1655, 42317, 31385, 11435}},
+{13621, 18, 3506, {1, 3, 5, 15, 25, 51, 121, 133, 457, 159, 869, 855, 3529, 2691, 147, 58621, 78379, 148519}},
+{13622, 18, 3518, {1, 1, 3, 7, 1, 53, 109, 81, 37, 553, 1921, 3081, 2665, 12665, 13887, 1035, 16987, 48883}},
+{13623, 18, 3532, {1, 1, 5, 1, 19, 1, 121, 97, 143, 871, 1401, 2879, 5657, 5479, 14011, 65131, 56011, 241055}},
+{13624, 18, 3543, {1, 1, 7, 5, 9, 21, 9, 43, 331, 183, 1313, 2495, 6905, 2763, 29567, 7579, 95169, 130937}},
+{13625, 18, 3547, {1, 3, 7, 3, 3, 37, 65, 195, 339, 527, 1383, 3063, 7749, 11109, 8097, 27257, 107615, 134241}},
+{13626, 18, 3573, {1, 1, 1, 5, 25, 25, 63, 179, 135, 65, 169, 2709, 5435, 12119, 21549, 59847, 129639, 220163}},
+{13627, 18, 3574, {1, 3, 5, 1, 3, 17, 87, 181, 9, 923, 731, 3397, 7079, 3281, 10455, 35471, 20439, 206209}},
+{13628, 18, 3587, {1, 1, 1, 5, 31, 25, 15, 89, 381, 675, 1217, 3175, 707, 585, 1695, 57771, 92433, 203523}},
+{13629, 18, 3632, {1, 3, 5, 15, 5, 7, 9, 87, 461, 1017, 869, 1541, 7833, 3117, 24917, 13917, 104797, 149045}},
+{13630, 18, 3664, {1, 1, 7, 15, 13, 49, 9, 89, 165, 827, 657, 1977, 7471, 15437, 25785, 1455, 52803, 198793}},
+{13631, 18, 3713, {1, 3, 1, 15, 3, 39, 27, 205, 325, 345, 965, 1439, 4403, 10717, 9591, 46845, 123983, 76181}},
+{13632, 18, 3726, {1, 3, 1, 1, 25, 23, 97, 135, 367, 179, 1563, 75, 455, 3517, 21539, 59565, 43449, 139495}},
+{13633, 18, 3768, {1, 1, 5, 15, 13, 27, 55, 21, 1, 505, 1349, 409, 2491, 5299, 15771, 59389, 110377, 209275}},
+{13634, 18, 3771, {1, 1, 7, 9, 31, 15, 63, 91, 3, 559, 419, 1237, 1157, 5811, 24335, 19215, 12581, 148813}},
+{13635, 18, 3810, {1, 1, 7, 13, 23, 3, 81, 127, 33, 931, 867, 2905, 1011, 16207, 1543, 54309, 10611, 152733}},
+{13636, 18, 3848, {1, 3, 5, 7, 21, 19, 45, 101, 439, 537, 267, 945, 8007, 9383, 13211, 21867, 5731, 150203}},
+{13637, 18, 3868, {1, 1, 3, 9, 29, 3, 31, 219, 217, 775, 1011, 445, 2663, 1691, 9837, 5727, 116283, 128627}},
+{13638, 18, 3896, {1, 3, 3, 3, 21, 1, 97, 239, 457, 925, 1923, 1693, 1187, 13437, 8529, 22081, 633, 76109}},
+{13639, 18, 3910, {1, 3, 7, 7, 19, 5, 9, 15, 337, 855, 1563, 3159, 2799, 4103, 2013, 47789, 77027, 22425}},
+{13640, 18, 3921, {1, 1, 3, 15, 15, 41, 27, 77, 489, 377, 1953, 305, 5081, 1895, 5117, 51455, 71859, 190289}},
+{13641, 18, 3928, {1, 1, 5, 7, 7, 7, 13, 25, 115, 657, 223, 3185, 5327, 2559, 5147, 22237, 91933, 195429}},
+{13642, 18, 3940, {1, 1, 3, 5, 5, 19, 3, 197, 371, 237, 555, 2873, 3401, 3329, 29165, 4593, 111677, 244025}},
+{13643, 18, 3947, {1, 3, 5, 15, 15, 55, 29, 75, 329, 623, 279, 2831, 4489, 7803, 24119, 12959, 59783, 135213}},
+{13644, 18, 3949, {1, 3, 5, 13, 31, 21, 93, 77, 401, 353, 893, 917, 4813, 8027, 7847, 55315, 60213, 102763}},
+{13645, 18, 4001, {1, 1, 5, 13, 29, 49, 91, 35, 79, 625, 1539, 509, 823, 2239, 30867, 21729, 33195, 38189}},
+{13646, 18, 4004, {1, 3, 3, 3, 19, 11, 39, 145, 5, 329, 1653, 3205, 4431, 9291, 30369, 63173, 72317, 236103}},
+{13647, 18, 4022, {1, 3, 3, 15, 27, 9, 111, 191, 249, 845, 1845, 2097, 6529, 9559, 25757, 29085, 2615, 175759}},
+{13648, 18, 4026, {1, 3, 7, 1, 17, 59, 119, 125, 213, 995, 601, 2517, 1225, 2301, 13031, 40881, 31623, 165799}},
+{13649, 18, 4036, {1, 3, 3, 13, 25, 61, 97, 157, 347, 931, 1731, 3697, 5815, 7309, 30605, 3853, 72395, 103609}},
+{13650, 18, 4073, {1, 1, 7, 5, 23, 13, 51, 117, 495, 683, 777, 1629, 5683, 801, 4907, 24935, 9457, 214131}},
+{13651, 18, 4093, {1, 1, 5, 9, 1, 29, 107, 253, 195, 921, 345, 1451, 2253, 12723, 571, 12009, 34149, 140659}},
+{13652, 18, 4099, {1, 1, 5, 9, 31, 17, 93, 5, 455, 205, 1439, 1199, 7371, 12973, 16455, 675, 60561, 99575}},
+{13653, 18, 4120, {1, 3, 3, 3, 31, 37, 115, 49, 31, 285, 2029, 1369, 3443, 2411, 10367, 44859, 26737, 195703}},
+{13654, 18, 4136, {1, 1, 3, 1, 15, 39, 113, 37, 257, 3, 817, 2901, 4029, 12595, 30475, 34883, 109133, 92159}},
+{13655, 18, 4156, {1, 1, 7, 5, 9, 1, 9, 101, 317, 167, 1975, 411, 6875, 6951, 4401, 59483, 129813, 78289}},
+{13656, 18, 4176, {1, 1, 7, 9, 9, 5, 73, 7, 57, 907, 1887, 2923, 961, 8521, 873, 33791, 114485, 43081}},
+{13657, 18, 4182, {1, 1, 5, 7, 13, 45, 91, 179, 499, 197, 1337, 1321, 5307, 15503, 20449, 60813, 97393, 255741}},
+{13658, 18, 4191, {1, 1, 1, 5, 25, 13, 69, 221, 207, 823, 845, 3845, 6743, 5123, 27447, 2079, 100635, 124157}},
+{13659, 18, 4198, {1, 3, 5, 11, 13, 39, 121, 209, 137, 63, 1479, 323, 5347, 9797, 17785, 55541, 108713, 243347}},
+{13660, 18, 4252, {1, 1, 3, 9, 29, 45, 43, 81, 115, 979, 727, 423, 1133, 8757, 27833, 39907, 104663, 33067}},
+{13661, 18, 4259, {1, 3, 5, 1, 13, 61, 49, 17, 409, 567, 1035, 2299, 3711, 15485, 7767, 27809, 1275, 96455}},
+{13662, 18, 4261, {1, 1, 5, 9, 5, 33, 13, 9, 505, 459, 747, 4079, 4271, 6925, 13933, 31349, 5793, 68381}},
+{13663, 18, 4294, {1, 3, 3, 11, 15, 47, 15, 187, 349, 847, 817, 3551, 6059, 6451, 32615, 1635, 108889, 48003}},
+{13664, 18, 4341, {1, 3, 5, 7, 3, 31, 11, 255, 367, 295, 1079, 2981, 5583, 10771, 25359, 16083, 24163, 111201}},
+{13665, 18, 4348, {1, 3, 5, 5, 7, 5, 127, 19, 343, 849, 287, 1471, 7299, 1209, 31349, 33473, 4989, 229181}},
+{13666, 18, 4356, {1, 1, 3, 9, 25, 61, 7, 65, 77, 745, 1871, 2427, 3669, 8965, 11177, 5531, 115801, 34327}},
+{13667, 18, 4384, {1, 3, 3, 15, 1, 57, 125, 167, 173, 875, 347, 2317, 6687, 4339, 10573, 7841, 16241, 192225}},
+{13668, 18, 4389, {1, 3, 1, 3, 15, 37, 45, 189, 75, 1017, 1919, 3401, 329, 2539, 32697, 60801, 52017, 192611}},
+{13669, 18, 4401, {1, 3, 1, 5, 1, 23, 43, 55, 1, 443, 1769, 1633, 5225, 6855, 5419, 65139, 22237, 17415}},
+{13670, 18, 4428, {1, 3, 5, 15, 25, 7, 107, 209, 325, 367, 373, 1855, 1313, 12899, 30137, 19007, 9911, 11791}},
+{13671, 18, 4431, {1, 3, 7, 13, 3, 57, 123, 93, 279, 469, 1817, 3409, 565, 3997, 14119, 58341, 59691, 163323}},
+{13672, 18, 4445, {1, 1, 3, 9, 3, 3, 69, 109, 47, 487, 1895, 2003, 7309, 9803, 9527, 52211, 31213, 41521}},
+{13673, 18, 4470, {1, 1, 7, 7, 9, 15, 101, 227, 75, 501, 25, 1481, 4847, 13279, 28673, 11069, 61987, 5365}},
+{13674, 18, 4473, {1, 3, 1, 1, 25, 5, 47, 125, 97, 969, 1077, 1185, 6033, 13927, 18149, 34255, 14353, 66323}},
+{13675, 18, 4474, {1, 1, 3, 1, 25, 41, 19, 69, 385, 585, 1049, 3497, 3615, 13211, 18855, 61303, 115739, 42639}},
+{13676, 18, 4490, {1, 3, 7, 7, 13, 15, 13, 133, 497, 265, 1809, 4073, 5673, 7543, 30823, 13505, 76167, 98683}},
+{13677, 18, 4509, {1, 1, 5, 5, 3, 59, 47, 191, 419, 505, 2035, 329, 553, 1561, 27885, 39767, 102611, 12689}},
+{13678, 18, 4510, {1, 3, 7, 3, 27, 49, 27, 133, 305, 537, 385, 335, 2417, 14891, 31299, 26201, 124655, 150545}},
+{13679, 18, 4533, {1, 1, 1, 9, 7, 1, 27, 105, 347, 481, 2043, 1645, 4367, 10335, 16457, 48713, 64699, 63595}},
+{13680, 18, 4548, {1, 1, 3, 3, 7, 57, 125, 209, 299, 525, 591, 1265, 7557, 15113, 19319, 56269, 43919, 215435}},
+{13681, 18, 4558, {1, 1, 1, 11, 29, 59, 119, 245, 63, 919, 1913, 3969, 545, 1033, 20975, 61327, 36783, 124303}},
+{13682, 18, 4594, {1, 1, 7, 7, 11, 63, 45, 135, 405, 931, 753, 2559, 5475, 2107, 6437, 6055, 43497, 133571}},
+{13683, 18, 4596, {1, 3, 1, 13, 31, 39, 39, 141, 231, 83, 69, 473, 1095, 13617, 10909, 49861, 98029, 235003}},
+{13684, 18, 4603, {1, 3, 7, 13, 13, 41, 73, 107, 505, 359, 957, 1599, 7617, 1843, 25531, 63755, 96295, 167955}},
+{13685, 18, 4610, {1, 3, 3, 11, 13, 41, 61, 65, 165, 507, 1007, 1695, 91, 8781, 15017, 12063, 95331, 179853}},
+{13686, 18, 4619, {1, 3, 7, 7, 29, 19, 7, 95, 303, 641, 581, 3539, 4495, 13549, 20195, 20845, 16961, 95053}},
+{13687, 18, 4630, {1, 1, 7, 5, 15, 27, 13, 155, 345, 341, 1583, 2207, 2497, 6509, 24343, 3109, 71431, 184871}},
+{13688, 18, 4652, {1, 1, 3, 15, 31, 35, 37, 249, 71, 1005, 681, 3457, 3387, 13797, 8781, 11789, 16825, 11133}},
+{13689, 18, 4658, {1, 3, 7, 11, 5, 29, 121, 139, 77, 859, 163, 2749, 6401, 16303, 22659, 11817, 61667, 119993}},
+{13690, 18, 4682, {1, 1, 7, 11, 15, 45, 71, 87, 293, 981, 1581, 2789, 4117, 12791, 13611, 489, 74823, 71263}},
+{13691, 18, 4708, {1, 1, 3, 9, 15, 21, 59, 167, 469, 723, 1609, 2111, 6359, 10781, 1043, 51039, 24429, 14605}},
+{13692, 18, 4736, {1, 3, 3, 9, 13, 25, 1, 43, 61, 869, 1919, 601, 8003, 15841, 10141, 33187, 124991, 94205}},
+{13693, 18, 4753, {1, 1, 7, 5, 23, 13, 67, 43, 167, 667, 1743, 2523, 2245, 9287, 8115, 64995, 121371, 188321}},
+{13694, 18, 4760, {1, 1, 1, 9, 13, 19, 45, 249, 21, 751, 239, 4035, 4549, 8905, 9377, 47535, 78135, 210429}},
+{13695, 18, 4781, {1, 1, 3, 7, 5, 43, 13, 227, 75, 785, 631, 205, 3475, 9735, 17867, 61407, 75897, 51151}},
+{13696, 18, 4784, {1, 3, 3, 9, 31, 21, 11, 53, 247, 717, 1505, 3903, 3249, 3185, 29007, 48795, 43413, 158653}},
+{13697, 18, 4799, {1, 1, 5, 11, 19, 9, 37, 159, 183, 521, 743, 2877, 2291, 10317, 1211, 17951, 16335, 66439}},
+{13698, 18, 4807, {1, 1, 3, 7, 3, 41, 15, 113, 125, 391, 201, 3841, 255, 15381, 16801, 47219, 119691, 51811}},
+{13699, 18, 4808, {1, 1, 3, 1, 1, 29, 79, 181, 481, 969, 297, 625, 7449, 5813, 5915, 20011, 44853, 231933}},
+{13700, 18, 4842, {1, 1, 1, 5, 5, 49, 63, 171, 93, 107, 1083, 1277, 121, 4421, 18951, 61155, 66643, 120049}},
+{13701, 18, 4882, {1, 3, 7, 5, 25, 59, 111, 197, 459, 217, 1819, 1603, 5581, 11361, 17721, 57475, 11171, 186577}},
+{13702, 18, 4897, {1, 3, 3, 1, 25, 19, 29, 157, 25, 595, 501, 2145, 7513, 10323, 11107, 13269, 21763, 9427}},
+{13703, 18, 4900, {1, 3, 7, 3, 9, 49, 119, 117, 445, 91, 227, 1203, 6245, 9575, 30653, 65429, 64987, 81249}},
+{13704, 18, 4922, {1, 1, 5, 5, 5, 5, 77, 77, 425, 789, 467, 3931, 4815, 11195, 21939, 59513, 78547, 238035}},
+{13705, 18, 4936, {1, 3, 1, 11, 11, 29, 115, 37, 423, 997, 1231, 3987, 5057, 14533, 18005, 51513, 71851, 258137}},
+{13706, 18, 4960, {1, 3, 1, 1, 27, 31, 7, 223, 23, 59, 1465, 2045, 6677, 15707, 25101, 22269, 46995, 89141}},
+{13707, 18, 4970, {1, 1, 1, 5, 21, 7, 115, 133, 407, 373, 1495, 2551, 6947, 3309, 14903, 5683, 67345, 139381}},
+{13708, 18, 4978, {1, 1, 5, 3, 13, 31, 5, 221, 187, 9, 165, 2295, 1239, 5665, 14543, 3963, 4931, 8269}},
+{13709, 18, 4994, {1, 3, 5, 13, 15, 5, 37, 171, 419, 665, 765, 1619, 1561, 1661, 5873, 25595, 34827, 215599}},
+{13710, 18, 5003, {1, 3, 1, 15, 13, 33, 45, 107, 275, 771, 1105, 2895, 187, 5173, 21179, 35047, 50825, 176775}},
+{13711, 18, 5044, {1, 3, 7, 5, 17, 5, 59, 195, 441, 625, 1205, 207, 4703, 10627, 17123, 61785, 100779, 258597}},
+{13712, 18, 5061, {1, 1, 1, 13, 17, 3, 13, 201, 241, 657, 153, 289, 5213, 2129, 13447, 28807, 25405, 33803}},
+{13713, 18, 5107, {1, 3, 1, 9, 19, 9, 51, 133, 159, 743, 1023, 291, 7137, 6949, 30419, 13449, 111505, 212393}},
+{13714, 18, 5127, {1, 3, 5, 7, 31, 29, 79, 211, 425, 93, 1173, 1957, 6737, 1725, 30703, 43237, 119747, 157395}},
+{13715, 18, 5131, {1, 1, 7, 3, 17, 21, 39, 19, 485, 663, 19, 761, 1525, 11059, 12833, 17567, 61123, 124801}},
+{13716, 18, 5136, {1, 1, 7, 3, 7, 25, 17, 199, 413, 821, 1561, 3855, 1871, 14041, 7525, 19383, 51017, 213357}},
+{13717, 18, 5145, {1, 3, 3, 9, 25, 11, 63, 83, 217, 587, 47, 3775, 767, 9191, 5127, 9133, 97689, 122949}},
+{13718, 18, 5146, {1, 1, 1, 9, 19, 7, 89, 125, 23, 813, 1277, 2965, 1939, 1453, 6349, 53127, 109813, 63767}},
+{13719, 18, 5175, {1, 1, 5, 15, 29, 63, 117, 37, 185, 69, 1823, 2791, 4125, 11757, 14847, 15567, 126141, 185951}},
+{13720, 18, 5218, {1, 3, 7, 1, 23, 11, 15, 113, 209, 785, 229, 3207, 97, 2489, 4587, 14253, 30421, 51027}},
+{13721, 18, 5223, {1, 3, 1, 7, 7, 33, 57, 51, 219, 233, 89, 3781, 2055, 4163, 10935, 51913, 63507, 18645}},
+{13722, 18, 5248, {1, 3, 1, 7, 7, 55, 107, 187, 109, 867, 955, 139, 4979, 8627, 5835, 28761, 72061, 99413}},
+{13723, 18, 5294, {1, 1, 1, 3, 5, 59, 17, 121, 511, 29, 1009, 2875, 2459, 1817, 11741, 13869, 72543, 70485}},
+{13724, 18, 5299, {1, 1, 5, 1, 27, 19, 125, 65, 379, 803, 411, 2403, 719, 10683, 23351, 18113, 66773, 252223}},
+{13725, 18, 5301, {1, 1, 7, 9, 31, 51, 65, 233, 171, 357, 1465, 1609, 4263, 15207, 18825, 48831, 69459, 211321}},
+{13726, 18, 5311, {1, 1, 3, 3, 5, 35, 53, 245, 469, 1011, 759, 455, 4487, 9835, 10349, 61755, 73279, 186049}},
+{13727, 18, 5343, {1, 1, 7, 3, 27, 19, 105, 193, 403, 907, 295, 1445, 1867, 8867, 7821, 45309, 129069, 83953}},
+{13728, 18, 5344, {1, 1, 7, 7, 7, 51, 85, 97, 473, 837, 201, 501, 2929, 9457, 6473, 3653, 126991, 218069}},
+{13729, 18, 5396, {1, 3, 3, 5, 25, 49, 85, 223, 127, 563, 239, 1975, 119, 6029, 19349, 59533, 44173, 142229}},
+{13730, 18, 5406, {1, 1, 3, 7, 23, 11, 27, 49, 467, 701, 2037, 2367, 5829, 12533, 9641, 38629, 90505, 132013}},
+{13731, 18, 5410, {1, 1, 7, 1, 13, 25, 79, 107, 37, 331, 355, 3639, 4875, 6635, 21703, 18289, 36257, 201857}},
+{13732, 18, 5424, {1, 1, 5, 1, 3, 39, 25, 101, 199, 401, 1495, 3683, 5447, 12313, 19707, 20853, 66821, 73959}},
+{13733, 18, 5447, {1, 1, 1, 9, 15, 9, 3, 231, 479, 97, 221, 973, 839, 1757, 8759, 45625, 44691, 139803}},
+{13734, 18, 5461, {1, 1, 7, 15, 9, 51, 23, 233, 311, 83, 287, 4035, 2087, 4245, 25457, 43105, 104903, 132811}},
+{13735, 18, 5468, {1, 1, 1, 9, 5, 13, 33, 167, 363, 67, 601, 2143, 5495, 1277, 14615, 32759, 34935, 158625}},
+{13736, 18, 5475, {1, 1, 5, 11, 5, 63, 35, 49, 183, 705, 377, 2607, 2947, 10119, 15631, 60247, 99309, 25747}},
+{13737, 18, 5478, {1, 3, 7, 5, 7, 3, 127, 109, 165, 767, 1873, 3825, 441, 11957, 2581, 38309, 129623, 77451}},
+{13738, 18, 5523, {1, 3, 1, 7, 19, 53, 101, 117, 505, 363, 1399, 1015, 631, 8309, 17507, 28941, 42585, 116283}},
+{13739, 18, 5530, {1, 1, 7, 7, 9, 27, 127, 195, 499, 225, 153, 517, 3909, 9801, 3787, 32829, 6599, 190807}},
+{13740, 18, 5535, {1, 1, 5, 1, 3, 49, 125, 235, 255, 329, 909, 1685, 759, 2287, 3479, 23491, 71157, 81457}},
+{13741, 18, 5548, {1, 1, 3, 9, 19, 21, 93, 37, 259, 69, 219, 1943, 4747, 13951, 14945, 46099, 87189, 222287}},
+{13742, 18, 5559, {1, 1, 7, 5, 21, 33, 61, 227, 167, 569, 1355, 2997, 4917, 10765, 7015, 54335, 125543, 112867}},
+{13743, 18, 5580, {1, 1, 5, 3, 25, 35, 97, 23, 365, 159, 1211, 1283, 979, 8993, 21323, 6863, 46869, 36169}},
+{13744, 18, 5604, {1, 1, 7, 13, 15, 49, 45, 209, 397, 785, 47, 2307, 4749, 2735, 29525, 54921, 23321, 216197}},
+{13745, 18, 5622, {1, 1, 1, 11, 31, 23, 27, 127, 197, 595, 29, 773, 3291, 6355, 11891, 6635, 99871, 177531}},
+{13746, 18, 5641, {1, 1, 7, 11, 9, 49, 85, 59, 211, 307, 1821, 3947, 4175, 11287, 27889, 107, 46463, 237129}},
+{13747, 18, 5649, {1, 3, 3, 7, 31, 31, 9, 49, 365, 189, 1211, 943, 337, 13809, 16941, 17053, 70125, 149865}},
+{13748, 18, 5656, {1, 3, 1, 13, 9, 21, 67, 1, 365, 77, 1701, 559, 3461, 8961, 13801, 16111, 65239, 157713}},
+{13749, 18, 5671, {1, 3, 7, 13, 19, 49, 29, 233, 361, 1011, 1617, 2989, 2387, 14027, 4021, 28791, 33155, 171449}},
+{13750, 18, 5689, {1, 1, 5, 13, 31, 19, 77, 69, 49, 513, 1411, 77, 4993, 907, 23483, 20129, 29491, 138187}},
+{13751, 18, 5721, {1, 3, 3, 11, 23, 33, 19, 55, 307, 455, 1783, 3997, 6411, 3355, 8815, 39883, 124381, 49667}},
+{13752, 18, 5731, {1, 3, 3, 15, 27, 7, 25, 243, 275, 27, 23, 3039, 6497, 15975, 5877, 58611, 6317, 209119}},
+{13753, 18, 5734, {1, 3, 1, 5, 7, 21, 97, 247, 297, 181, 773, 3095, 2441, 15683, 29609, 50431, 92813, 723}},
+{13754, 18, 5738, {1, 1, 1, 3, 17, 25, 69, 171, 27, 83, 173, 163, 7915, 13547, 5915, 20275, 101613, 225081}},
+{13755, 18, 5740, {1, 1, 7, 15, 19, 13, 53, 95, 171, 889, 131, 1979, 2537, 7749, 77, 49293, 68875, 159125}},
+{13756, 18, 5748, {1, 1, 1, 5, 11, 7, 7, 29, 397, 435, 1495, 2263, 3677, 11121, 1269, 5415, 44427, 249943}},
+{13757, 18, 5791, {1, 3, 1, 5, 23, 21, 13, 185, 231, 757, 1647, 663, 1273, 11641, 25563, 46793, 54231, 113143}},
+{13758, 18, 5801, {1, 3, 3, 7, 11, 21, 83, 109, 409, 923, 1541, 2805, 1781, 6903, 9093, 37327, 60923, 167271}},
+{13759, 18, 5807, {1, 3, 7, 5, 29, 37, 87, 85, 93, 749, 875, 2869, 1023, 13303, 26865, 30971, 40863, 237075}},
+{13760, 18, 5822, {1, 1, 7, 13, 21, 25, 39, 213, 303, 265, 1251, 2963, 3819, 8507, 23239, 52625, 123375, 58553}},
+{13761, 18, 5829, {1, 1, 1, 1, 3, 1, 7, 67, 339, 583, 3, 2489, 5481, 12241, 21695, 31351, 39389, 131925}},
+{13762, 18, 5834, {1, 1, 5, 11, 11, 3, 95, 23, 133, 415, 77, 1891, 4083, 7097, 26455, 28689, 83047, 49759}},
+{13763, 18, 5847, {1, 3, 7, 15, 19, 31, 65, 189, 489, 461, 1255, 1897, 3361, 12223, 9721, 45937, 102695, 113431}},
+{13764, 18, 5854, {1, 3, 1, 5, 9, 57, 3, 225, 241, 769, 1003, 2255, 7655, 4837, 25267, 35845, 49545, 24931}},
+{13765, 18, 5878, {1, 1, 1, 1, 1, 43, 3, 217, 397, 419, 1189, 2037, 5941, 4341, 19851, 13773, 15225, 167581}},
+{13766, 18, 5882, {1, 1, 1, 9, 3, 27, 65, 49, 115, 787, 1637, 1867, 7265, 8541, 1587, 58987, 82161, 19997}},
+{13767, 18, 5919, {1, 3, 7, 11, 17, 17, 93, 103, 309, 159, 781, 3179, 5759, 7661, 5693, 48531, 127375, 141449}},
+{13768, 18, 5947, {1, 3, 7, 5, 13, 39, 79, 241, 7, 137, 219, 523, 541, 4787, 23327, 41665, 111017, 118901}},
+{13769, 18, 5981, {1, 1, 3, 15, 31, 23, 107, 221, 295, 935, 1165, 2463, 1635, 10205, 18057, 28217, 51755, 85579}},
+{13770, 18, 5982, {1, 3, 1, 11, 23, 47, 7, 59, 75, 603, 1237, 2601, 6873, 12735, 32181, 46849, 106363, 171753}},
+{13771, 18, 6025, {1, 1, 7, 13, 15, 31, 3, 113, 355, 955, 919, 1807, 7903, 5485, 1733, 64759, 15817, 93829}},
+{13772, 18, 6028, {1, 1, 3, 15, 11, 33, 95, 67, 511, 971, 343, 41, 2849, 10695, 24487, 8971, 129279, 197635}},
+{13773, 18, 6039, {1, 3, 1, 13, 13, 47, 77, 127, 193, 191, 1185, 3321, 1685, 1421, 28675, 12593, 86689, 186763}},
+{13774, 18, 6056, {1, 3, 7, 13, 1, 11, 123, 91, 287, 751, 11, 2753, 7153, 5253, 21817, 10459, 122225, 105775}},
+{13775, 18, 6064, {1, 3, 3, 13, 1, 17, 121, 13, 391, 253, 1323, 1515, 2067, 8009, 5173, 59543, 109511, 156821}},
+{13776, 18, 6073, {1, 1, 5, 3, 7, 1, 119, 151, 281, 859, 675, 2923, 6627, 16071, 24653, 41325, 118413, 191981}},
+{13777, 18, 6081, {1, 3, 5, 3, 31, 17, 57, 255, 473, 455, 203, 173, 345, 1477, 27939, 39289, 105081, 136179}},
+{13778, 18, 6088, {1, 3, 3, 7, 1, 35, 29, 81, 337, 483, 951, 955, 4343, 14827, 17427, 59919, 81883, 114289}},
+{13779, 18, 6101, {1, 3, 5, 11, 3, 39, 49, 177, 335, 57, 173, 1827, 5729, 2689, 12109, 13247, 117559, 31735}},
+{13780, 18, 6139, {1, 3, 1, 3, 9, 9, 41, 97, 37, 897, 545, 2289, 7917, 5701, 21953, 1863, 33727, 28451}},
+{13781, 18, 6142, {1, 1, 5, 3, 29, 61, 59, 129, 387, 965, 285, 3503, 1651, 10423, 24861, 31853, 38491, 155187}},
+{13782, 18, 6194, {1, 3, 1, 13, 23, 33, 13, 161, 133, 29, 1073, 1491, 3687, 6821, 24153, 3675, 33771, 230087}},
+{13783, 18, 6199, {1, 1, 7, 7, 29, 23, 23, 55, 189, 203, 641, 3391, 1217, 3199, 32531, 43103, 24007, 85613}},
+{13784, 18, 6200, {1, 1, 1, 11, 7, 57, 117, 245, 467, 861, 1265, 2827, 2761, 2817, 15679, 53223, 47245, 139871}},
+{13785, 18, 6203, {1, 1, 3, 15, 25, 1, 125, 237, 489, 1003, 515, 1117, 4427, 4877, 8685, 46211, 19889, 82491}},
+{13786, 18, 6214, {1, 1, 3, 3, 25, 3, 63, 217, 485, 699, 161, 1459, 2973, 15949, 30681, 30991, 13933, 86505}},
+{13787, 18, 6238, {1, 1, 7, 9, 27, 57, 23, 217, 401, 613, 277, 2827, 7111, 2133, 17489, 62059, 7273, 170917}},
+{13788, 18, 6241, {1, 1, 3, 13, 7, 19, 39, 63, 203, 1001, 279, 879, 4293, 10121, 969, 11571, 96427, 218969}},
+{13789, 18, 6244, {1, 3, 7, 7, 5, 21, 113, 203, 77, 971, 1351, 1097, 2581, 7519, 16049, 10565, 5055, 241561}},
+{13790, 18, 6248, {1, 3, 3, 11, 1, 21, 93, 111, 221, 31, 1245, 1499, 2289, 2299, 23457, 49221, 68879, 125029}},
+{13791, 18, 6256, {1, 1, 7, 3, 15, 19, 57, 189, 243, 785, 399, 3147, 6107, 2327, 6275, 9993, 53051, 34053}},
+{13792, 18, 6266, {1, 3, 7, 15, 5, 63, 7, 193, 115, 579, 1987, 765, 7871, 14179, 26383, 61455, 14241, 123515}},
+{13793, 18, 6271, {1, 3, 7, 13, 19, 13, 91, 225, 295, 675, 1995, 1145, 4929, 5163, 1101, 60681, 76777, 146875}},
+{13794, 18, 6275, {1, 3, 7, 15, 21, 37, 57, 89, 297, 143, 717, 4021, 3259, 8869, 21189, 39333, 125045, 94469}},
+{13795, 18, 6295, {1, 1, 5, 9, 27, 35, 69, 121, 433, 39, 889, 915, 4055, 11479, 24757, 53455, 17503, 113295}},
+{13796, 18, 6315, {1, 1, 3, 3, 23, 19, 81, 191, 33, 865, 59, 603, 2819, 4919, 22495, 25089, 73905, 44971}},
+{13797, 18, 6364, {1, 3, 3, 11, 19, 45, 125, 229, 143, 167, 867, 671, 2225, 16099, 14909, 14937, 78063, 135143}},
+{13798, 18, 6368, {1, 1, 7, 11, 21, 55, 73, 247, 211, 895, 1147, 17, 2119, 3261, 19815, 28055, 50139, 178459}},
+{13799, 18, 6377, {1, 1, 3, 1, 19, 3, 37, 221, 243, 459, 1539, 3899, 4597, 5503, 23015, 57019, 62637, 177821}},
+{13800, 18, 6400, {1, 3, 1, 3, 9, 5, 91, 3, 319, 609, 1241, 3953, 5569, 8757, 6453, 8083, 55285, 38297}},
+{13801, 18, 6430, {1, 3, 5, 15, 9, 51, 37, 53, 137, 95, 123, 157, 15, 7421, 22469, 49787, 96245, 199309}},
+{13802, 18, 6477, {1, 3, 1, 1, 29, 61, 85, 211, 437, 1013, 1251, 61, 157, 4325, 24247, 1065, 24875, 31509}},
+{13803, 18, 6480, {1, 3, 1, 13, 7, 43, 13, 171, 53, 567, 77, 3781, 5077, 6691, 32485, 24253, 83919, 159371}},
+{13804, 18, 6490, {1, 1, 1, 13, 15, 15, 19, 53, 325, 309, 53, 1857, 7361, 8831, 31751, 44749, 109265, 227875}},
+{13805, 18, 6526, {1, 3, 7, 3, 31, 19, 113, 253, 361, 697, 1137, 2029, 3673, 10323, 10455, 24935, 7325, 43673}},
+{13806, 18, 6539, {1, 3, 1, 1, 17, 31, 3, 55, 121, 967, 1701, 2171, 4393, 11937, 3987, 5139, 68913, 134233}},
+{13807, 18, 6556, {1, 1, 7, 15, 23, 37, 121, 241, 297, 419, 373, 1219, 739, 4567, 28593, 61267, 95711, 201299}},
+{13808, 18, 6584, {1, 1, 1, 9, 23, 31, 101, 243, 163, 333, 1707, 2553, 5285, 12827, 5051, 14165, 505, 253585}},
+{13809, 18, 6598, {1, 1, 1, 9, 11, 29, 81, 45, 101, 235, 1079, 4091, 1069, 3439, 23599, 6699, 71783, 236943}},
+{13810, 18, 6601, {1, 3, 7, 11, 29, 49, 99, 59, 1, 267, 887, 2941, 6717, 7501, 22549, 53393, 34569, 34671}},
+{13811, 18, 6609, {1, 3, 1, 15, 23, 13, 113, 47, 11, 79, 989, 1025, 35, 10475, 8079, 33121, 32477, 178595}},
+{13812, 18, 6612, {1, 3, 7, 1, 21, 19, 51, 31, 393, 171, 553, 2221, 7017, 8567, 21803, 51803, 83737, 196409}},
+{13813, 18, 6645, {1, 1, 3, 3, 1, 27, 117, 207, 37, 733, 2001, 2575, 4849, 5609, 743, 35987, 109993, 227663}},
+{13814, 18, 6655, {1, 1, 7, 15, 29, 47, 85, 213, 335, 633, 849, 3269, 7723, 4651, 355, 54565, 58829, 22781}},
+{13815, 18, 6679, {1, 3, 7, 5, 5, 3, 91, 243, 17, 85, 1983, 3909, 1839, 10403, 503, 28451, 3221, 215397}},
+{13816, 18, 6683, {1, 1, 1, 15, 13, 3, 9, 25, 249, 113, 1619, 2313, 6461, 2323, 14319, 59635, 9569, 220583}},
+{13817, 18, 6719, {1, 3, 5, 7, 31, 59, 41, 43, 43, 921, 647, 2141, 7011, 2749, 24711, 19067, 107895, 107145}},
+{13818, 18, 6727, {1, 1, 3, 3, 15, 63, 41, 241, 181, 729, 843, 3569, 2645, 2727, 25331, 23067, 115421, 86025}},
+{13819, 18, 6734, {1, 3, 1, 15, 11, 47, 9, 183, 341, 775, 1067, 1317, 6835, 7873, 2653, 33517, 103979, 196761}},
+{13820, 18, 6770, {1, 1, 3, 13, 29, 11, 105, 9, 49, 823, 1343, 759, 1263, 12413, 26047, 54285, 57319, 215387}},
+{13821, 18, 6776, {1, 1, 5, 13, 21, 55, 75, 149, 63, 737, 1305, 929, 4149, 2793, 24505, 11541, 74765, 8207}},
+{13822, 18, 6791, {1, 3, 5, 9, 25, 1, 43, 157, 303, 395, 301, 1561, 5963, 3501, 2259, 59777, 100953, 16051}},
+{13823, 18, 6798, {1, 3, 1, 13, 19, 25, 33, 209, 11, 95, 655, 595, 3081, 10345, 26615, 45129, 84023, 158079}},
+{13824, 18, 6800, {1, 3, 1, 9, 31, 61, 103, 203, 471, 215, 1103, 759, 1197, 3333, 15859, 36103, 31563, 5987}},
+{13825, 18, 6826, {1, 1, 1, 7, 1, 49, 121, 227, 153, 793, 1723, 1033, 6875, 6683, 2503, 57213, 97967, 120383}},
+{13826, 18, 6833, {1, 3, 7, 11, 3, 15, 35, 181, 19, 249, 755, 1385, 3297, 4665, 2761, 22717, 126199, 85065}},
+{13827, 18, 6836, {1, 3, 7, 15, 5, 45, 17, 55, 111, 597, 553, 1203, 7183, 8465, 28523, 50073, 90889, 187205}},
+{13828, 18, 6858, {1, 3, 3, 9, 31, 57, 13, 139, 291, 881, 501, 2051, 617, 5151, 28225, 44777, 31645, 6805}},
+{13829, 18, 6882, {1, 3, 5, 13, 1, 23, 107, 1, 201, 35, 1673, 2281, 7663, 1115, 25061, 59615, 127955, 169685}},
+{13830, 18, 6901, {1, 1, 3, 15, 15, 5, 17, 75, 307, 591, 1661, 855, 4239, 13359, 20027, 51871, 35241, 32769}},
+{13831, 18, 6923, {1, 1, 1, 15, 5, 23, 59, 205, 223, 103, 1889, 141, 6157, 9187, 23571, 15267, 1941, 119173}},
+{13832, 18, 6967, {1, 3, 5, 9, 27, 63, 59, 11, 279, 493, 209, 4087, 1055, 9841, 31753, 37459, 27757, 213151}},
+{13833, 18, 6979, {1, 1, 3, 11, 31, 33, 13, 87, 285, 847, 2005, 3431, 253, 15157, 31359, 45303, 114337, 42541}},
+{13834, 18, 7022, {1, 1, 1, 7, 7, 3, 17, 203, 133, 321, 241, 1323, 5639, 10953, 10069, 4941, 17077, 54493}},
+{13835, 18, 7060, {1, 1, 7, 1, 9, 5, 125, 5, 421, 609, 645, 1927, 3785, 2295, 1491, 23019, 85497, 161231}},
+{13836, 18, 7064, {1, 3, 3, 11, 19, 35, 115, 95, 353, 773, 2025, 2621, 2821, 6361, 29589, 20989, 99645, 90387}},
+{13837, 18, 7083, {1, 3, 1, 15, 23, 3, 71, 253, 467, 307, 1109, 2695, 7175, 15087, 1587, 48229, 104307, 218905}},
+{13838, 18, 7093, {1, 3, 3, 5, 17, 29, 107, 153, 371, 205, 7, 597, 7393, 2345, 20149, 47417, 37983, 200683}},
+{13839, 18, 7094, {1, 1, 7, 1, 3, 55, 113, 117, 241, 923, 1217, 3825, 2635, 8007, 12673, 9533, 7121, 3825}},
+{13840, 18, 7120, {1, 1, 1, 3, 21, 63, 25, 111, 31, 151, 67, 3735, 7833, 749, 28743, 59291, 4989, 93329}},
+{13841, 18, 7125, {1, 3, 5, 13, 31, 5, 91, 153, 235, 1019, 431, 1951, 7501, 8483, 19625, 57789, 13203, 36693}},
+{13842, 18, 7142, {1, 1, 7, 3, 15, 51, 99, 29, 403, 343, 1903, 907, 3255, 4149, 29551, 18885, 74391, 96119}},
+{13843, 18, 7151, {1, 1, 7, 11, 31, 11, 63, 213, 437, 879, 359, 555, 7549, 14269, 31489, 51001, 76857, 237305}},
+{13844, 18, 7165, {1, 1, 1, 15, 23, 21, 31, 227, 311, 273, 253, 2439, 7217, 2191, 31743, 47669, 62279, 201305}},
+{13845, 18, 7173, {1, 3, 5, 11, 3, 43, 97, 121, 363, 91, 201, 1095, 5267, 633, 19111, 36099, 23035, 205655}},
+{13846, 18, 7188, {1, 3, 1, 9, 21, 31, 39, 11, 227, 699, 473, 2109, 2757, 13821, 31181, 40493, 57279, 260085}},
+{13847, 18, 7191, {1, 1, 5, 7, 27, 57, 65, 11, 173, 709, 1139, 3735, 5291, 16053, 32579, 25275, 79865, 196033}},
+{13848, 18, 7202, {1, 1, 1, 9, 19, 35, 83, 153, 287, 207, 593, 2177, 3243, 10433, 24583, 881, 71865, 250223}},
+{13849, 18, 7216, {1, 3, 3, 9, 3, 35, 107, 3, 193, 1011, 463, 1643, 2733, 2157, 6329, 24583, 116901, 226385}},
+{13850, 18, 7219, {1, 3, 1, 11, 3, 47, 39, 33, 495, 137, 1591, 1335, 1347, 4527, 389, 43341, 80163, 5219}},
+{13851, 18, 7267, {1, 3, 3, 5, 19, 51, 121, 135, 93, 891, 13, 1339, 5187, 5005, 12823, 14465, 73845, 119685}},
+{13852, 18, 7358, {1, 3, 7, 7, 19, 1, 57, 193, 325, 49, 813, 5, 4431, 1119, 13625, 43613, 127989, 42669}},
+{13853, 18, 7383, {1, 3, 5, 15, 11, 33, 7, 45, 215, 469, 1059, 4095, 3549, 11839, 5463, 21383, 4831, 188345}},
+{13854, 18, 7387, {1, 1, 1, 13, 5, 61, 7, 161, 99, 623, 1589, 1045, 2385, 8899, 19327, 41373, 109241, 111895}},
+{13855, 18, 7396, {1, 1, 5, 7, 11, 39, 115, 41, 21, 491, 1221, 2805, 4311, 7137, 3151, 1387, 24633, 94679}},
+{13856, 18, 7408, {1, 1, 3, 7, 3, 39, 71, 175, 443, 187, 1727, 2535, 5099, 1881, 21639, 5717, 48589, 95037}},
+{13857, 18, 7432, {1, 1, 1, 11, 25, 21, 37, 227, 407, 73, 721, 3515, 381, 981, 21389, 5205, 31851, 140457}},
+{13858, 18, 7462, {1, 3, 3, 3, 27, 35, 13, 129, 457, 315, 253, 2545, 5469, 6695, 25223, 20115, 38039, 133655}},
+{13859, 18, 7480, {1, 1, 3, 11, 21, 47, 77, 231, 87, 245, 2039, 2515, 2873, 1711, 3361, 62123, 67117, 239047}},
+{13860, 18, 7488, {1, 1, 7, 7, 29, 21, 39, 175, 477, 813, 447, 1109, 7391, 14631, 4437, 42539, 13003, 75403}},
+{13861, 18, 7497, {1, 3, 1, 11, 11, 9, 119, 19, 99, 483, 61, 1883, 3415, 2137, 30415, 34519, 115191, 24437}},
+{13862, 18, 7531, {1, 1, 1, 9, 7, 47, 115, 233, 419, 427, 1605, 3821, 6243, 10861, 28495, 48265, 80811, 147701}},
+{13863, 18, 7561, {1, 3, 5, 5, 11, 61, 51, 155, 279, 463, 31, 1559, 2837, 8795, 4049, 13651, 109227, 52131}},
+{13864, 18, 7582, {1, 1, 7, 9, 25, 33, 97, 79, 477, 83, 923, 3293, 6381, 3063, 23293, 35381, 82867, 233189}},
+{13865, 18, 7591, {1, 1, 1, 9, 11, 39, 109, 189, 219, 1021, 137, 2041, 2719, 1763, 31787, 29377, 96287, 179685}},
+{13866, 18, 7612, {1, 3, 7, 5, 3, 15, 37, 179, 77, 751, 709, 893, 7705, 1563, 7843, 29843, 1107, 35919}},
+{13867, 18, 7677, {1, 3, 3, 3, 29, 17, 123, 201, 275, 487, 1979, 1361, 7523, 13783, 10129, 16877, 127049, 163221}},
+{13868, 18, 7687, {1, 1, 1, 9, 27, 35, 69, 167, 509, 133, 1073, 3773, 265, 8455, 12341, 127, 115075, 94537}},
+{13869, 18, 7701, {1, 3, 7, 9, 13, 35, 57, 83, 123, 211, 739, 253, 3907, 5405, 3229, 46837, 77483, 5915}},
+{13870, 18, 7705, {1, 1, 7, 3, 7, 27, 71, 235, 133, 803, 611, 529, 4449, 16113, 8151, 36519, 34561, 36361}},
+{13871, 18, 7712, {1, 1, 3, 1, 31, 9, 123, 85, 407, 415, 353, 3239, 673, 4641, 25883, 61117, 7669, 240851}},
+{13872, 18, 7721, {1, 1, 5, 11, 29, 9, 49, 31, 3, 249, 1769, 3325, 503, 1397, 30677, 22515, 81279, 90309}},
+{13873, 18, 7736, {1, 3, 5, 3, 15, 63, 121, 253, 421, 279, 497, 3881, 6977, 11061, 5883, 38347, 8351, 118123}},
+{13874, 18, 7756, {1, 1, 1, 13, 1, 27, 3, 91, 281, 563, 1283, 1893, 7593, 12171, 27041, 7769, 95691, 13791}},
+{13875, 18, 7777, {1, 1, 3, 3, 29, 59, 87, 153, 337, 819, 787, 2631, 1889, 13869, 29237, 57097, 91621, 4011}},
+{13876, 18, 7783, {1, 1, 1, 15, 7, 49, 1, 83, 299, 353, 131, 1635, 3723, 16209, 1061, 50669, 68083, 133443}},
+{13877, 18, 7792, {1, 3, 5, 5, 27, 17, 5, 239, 285, 831, 1487, 721, 4891, 4265, 23753, 43921, 116709, 105027}},
+{13878, 18, 7797, {1, 1, 7, 7, 5, 35, 63, 97, 215, 447, 353, 495, 8119, 12537, 9679, 58641, 65057, 21999}},
+{13879, 18, 7802, {1, 3, 7, 5, 23, 43, 69, 115, 59, 603, 493, 1665, 5003, 13607, 28491, 4439, 11855, 228183}},
+{13880, 18, 7808, {1, 3, 3, 3, 15, 35, 19, 63, 241, 357, 979, 2891, 3105, 14085, 10539, 62335, 130903, 163153}},
+{13881, 18, 7866, {1, 3, 5, 3, 23, 51, 23, 193, 129, 171, 1913, 1025, 6397, 15657, 19611, 57455, 87531, 51039}},
+{13882, 18, 7885, {1, 1, 3, 9, 1, 9, 7, 239, 87, 527, 1401, 2703, 4021, 3845, 29269, 48217, 61091, 131949}},
+{13883, 18, 7891, {1, 3, 1, 5, 17, 45, 59, 223, 287, 295, 1959, 3985, 3671, 14605, 18949, 34147, 51251, 10271}},
+{13884, 18, 7913, {1, 3, 5, 9, 5, 49, 63, 105, 43, 157, 1827, 495, 5823, 6323, 6601, 51379, 64411, 204103}},
+{13885, 18, 7936, {1, 1, 7, 1, 11, 31, 117, 9, 13, 965, 177, 1247, 2487, 9849, 20367, 49287, 2193, 235689}},
+{13886, 18, 7946, {1, 1, 3, 11, 19, 31, 23, 215, 489, 657, 801, 3937, 379, 12083, 14969, 37857, 39027, 63985}},
+{13887, 18, 7963, {1, 1, 5, 1, 9, 59, 53, 187, 341, 65, 1251, 767, 4897, 13263, 17439, 26625, 122107, 163653}},
+{13888, 18, 7996, {1, 1, 3, 13, 31, 41, 125, 253, 481, 107, 233, 2305, 3321, 7303, 28585, 12787, 83307, 31497}},
+{13889, 18, 7999, {1, 1, 3, 13, 25, 41, 55, 83, 101, 115, 549, 531, 3085, 9497, 27989, 28257, 121075, 189671}},
+{13890, 18, 8011, {1, 3, 5, 11, 13, 53, 121, 85, 355, 275, 1925, 2117, 1349, 5903, 2041, 20963, 60803, 1121}},
+{13891, 18, 8014, {1, 1, 5, 5, 13, 7, 125, 63, 311, 187, 1127, 643, 6137, 845, 23945, 9403, 451, 53027}},
+{13892, 18, 8028, {1, 1, 3, 7, 19, 31, 27, 239, 337, 61, 641, 1693, 7289, 5675, 30067, 41091, 124607, 36971}},
+{13893, 18, 8047, {1, 3, 1, 13, 25, 61, 11, 81, 165, 129, 241, 711, 5193, 13017, 30821, 35239, 110809, 60909}},
+{13894, 18, 8077, {1, 3, 3, 13, 15, 13, 71, 19, 87, 499, 1395, 1191, 1445, 2687, 4691, 16773, 114269, 186237}},
+{13895, 18, 8101, {1, 3, 3, 15, 1, 49, 33, 109, 241, 5, 431, 461, 3865, 14029, 9827, 54455, 52159, 211585}},
+{13896, 18, 8119, {1, 3, 5, 7, 31, 27, 115, 113, 367, 591, 873, 1447, 6819, 7011, 14095, 55243, 4039, 226985}},
+{13897, 18, 8125, {1, 1, 7, 3, 1, 19, 69, 239, 417, 833, 1867, 3111, 2617, 12781, 5531, 17345, 75717, 139667}},
+{13898, 18, 8140, {1, 1, 5, 11, 11, 63, 23, 141, 221, 897, 1269, 2185, 6057, 8865, 20449, 58255, 27073, 158305}},
+{13899, 18, 8152, {1, 3, 3, 5, 23, 23, 121, 39, 457, 935, 691, 2329, 7055, 2821, 12669, 28713, 82321, 245783}},
+{13900, 18, 8209, {1, 1, 1, 9, 27, 9, 35, 23, 139, 823, 703, 917, 1281, 12155, 11681, 26083, 119445, 181489}},
+{13901, 18, 8212, {1, 1, 3, 7, 27, 21, 35, 243, 17, 633, 1665, 3419, 6301, 16099, 17477, 24983, 128455, 127501}},
+{13902, 18, 8231, {1, 3, 1, 1, 17, 19, 59, 165, 487, 985, 597, 689, 7103, 14475, 6985, 29755, 115977, 105943}},
+{13903, 18, 8258, {1, 1, 5, 5, 23, 41, 67, 175, 3, 571, 1501, 3315, 6111, 1847, 28975, 54117, 66605, 69997}},
+{13904, 18, 8275, {1, 3, 5, 5, 13, 37, 113, 75, 383, 297, 1187, 2055, 3433, 14651, 30393, 29647, 126403, 32265}},
+{13905, 18, 8303, {1, 1, 3, 5, 31, 29, 25, 169, 465, 219, 81, 2019, 4255, 6003, 7425, 53269, 31105, 211937}},
+{13906, 18, 8308, {1, 3, 7, 11, 13, 7, 11, 195, 327, 883, 1295, 3721, 1197, 7585, 5693, 993, 125017, 12007}},
+{13907, 18, 8312, {1, 3, 3, 7, 5, 37, 71, 37, 63, 651, 669, 3445, 3959, 249, 10599, 22329, 107701, 107729}},
+{13908, 18, 8345, {1, 1, 1, 9, 7, 47, 21, 181, 395, 345, 757, 481, 2759, 8157, 19847, 55743, 63137, 224765}},
+{13909, 18, 8346, {1, 3, 5, 9, 29, 3, 61, 35, 271, 157, 549, 843, 2907, 91, 16325, 4241, 94495, 78861}},
+{13910, 18, 8370, {1, 3, 1, 9, 17, 11, 53, 243, 49, 911, 1193, 793, 901, 3727, 21849, 33987, 565, 154171}},
+{13911, 18, 8402, {1, 1, 5, 1, 9, 5, 89, 81, 65, 111, 781, 3775, 591, 4987, 29833, 58159, 7253, 206447}},
+{13912, 18, 8411, {1, 3, 1, 7, 3, 59, 77, 83, 173, 545, 103, 2541, 8095, 10797, 11111, 62351, 88827, 55081}},
+{13913, 18, 8414, {1, 1, 3, 11, 29, 37, 19, 47, 145, 19, 513, 3269, 2205, 5317, 19207, 38051, 5413, 78089}},
+{13914, 18, 8424, {1, 1, 5, 9, 21, 57, 75, 249, 21, 879, 1377, 3407, 6123, 11917, 12493, 44873, 113539, 114717}},
+{13915, 18, 8435, {1, 3, 3, 9, 7, 55, 121, 57, 491, 39, 1561, 2625, 639, 13553, 1159, 43071, 68869, 248837}},
+{13916, 18, 8452, {1, 1, 1, 11, 25, 19, 107, 239, 171, 1001, 69, 4095, 49, 9569, 22613, 59865, 54959, 70031}},
+{13917, 18, 8462, {1, 1, 3, 13, 27, 15, 105, 205, 205, 581, 1965, 1535, 6531, 15935, 7623, 33695, 9317, 44257}},
+{13918, 18, 8479, {1, 1, 1, 3, 3, 51, 115, 185, 315, 763, 211, 339, 7083, 4895, 23277, 14165, 101731, 218903}},
+{13919, 18, 8509, {1, 1, 3, 13, 29, 1, 69, 55, 423, 781, 183, 1417, 151, 14507, 5217, 27757, 52447, 145913}},
+{13920, 18, 8515, {1, 3, 1, 11, 29, 39, 29, 151, 85, 387, 885, 507, 133, 9819, 12627, 30951, 79839, 206267}},
+{13921, 18, 8522, {1, 3, 3, 7, 1, 53, 99, 141, 91, 51, 143, 1751, 3989, 6811, 7339, 52141, 43473, 18615}},
+{13922, 18, 8541, {1, 3, 3, 15, 27, 11, 29, 37, 387, 655, 2019, 1135, 3619, 12995, 12755, 26063, 109419, 103875}},
+{13923, 18, 8560, {1, 3, 3, 13, 31, 15, 93, 231, 195, 261, 1055, 2363, 1123, 3927, 6907, 365, 27043, 157049}},
+{13924, 18, 8563, {1, 1, 1, 15, 7, 29, 105, 199, 507, 437, 117, 2963, 7801, 6291, 19261, 30377, 92205, 20723}},
+{13925, 18, 8585, {1, 1, 1, 9, 29, 19, 75, 189, 3, 387, 1491, 2291, 7739, 12993, 11835, 10873, 54583, 207963}},
+{13926, 18, 8594, {1, 3, 7, 3, 23, 11, 25, 105, 57, 713, 1291, 3293, 4693, 13859, 27541, 31529, 65929, 245143}},
+{13927, 18, 8596, {1, 1, 7, 7, 19, 13, 19, 189, 253, 337, 351, 1751, 6173, 12207, 24483, 31381, 82035, 157143}},
+{13928, 18, 8603, {1, 3, 3, 11, 11, 49, 117, 177, 301, 417, 855, 2433, 5619, 7339, 30361, 29251, 20411, 184981}},
+{13929, 18, 8610, {1, 1, 1, 1, 11, 55, 77, 99, 209, 781, 1193, 2841, 783, 1485, 19413, 52255, 19529, 253927}},
+{13930, 18, 8647, {1, 3, 1, 3, 15, 49, 85, 191, 389, 411, 479, 341, 4985, 6193, 19099, 11497, 103285, 162333}},
+{13931, 18, 8661, {1, 3, 1, 3, 11, 31, 71, 91, 357, 615, 2007, 3601, 5393, 8079, 16811, 54127, 26049, 116341}},
+{13932, 18, 8662, {1, 1, 3, 15, 9, 39, 121, 53, 43, 617, 905, 3629, 6327, 13453, 1435, 24113, 7523, 228523}},
+{13933, 18, 8672, {1, 3, 5, 11, 21, 51, 11, 125, 33, 935, 1069, 2807, 4951, 13261, 17611, 38779, 62203, 135759}},
+{13934, 18, 8690, {1, 1, 1, 13, 29, 59, 53, 245, 219, 423, 809, 1109, 7255, 14679, 25247, 43235, 129565, 72649}},
+{13935, 18, 8696, {1, 3, 5, 7, 27, 29, 119, 91, 297, 407, 187, 2829, 5637, 13851, 14073, 461, 64081, 33971}},
+{13936, 18, 8739, {1, 1, 5, 11, 15, 27, 29, 233, 487, 859, 1021, 3117, 1439, 16021, 31315, 35775, 117363, 131635}},
+{13937, 18, 8783, {1, 1, 5, 3, 3, 1, 91, 229, 327, 777, 393, 3853, 3455, 1785, 13749, 25173, 51575, 167237}},
+{13938, 18, 8811, {1, 3, 7, 9, 27, 7, 15, 71, 283, 71, 1783, 1357, 5581, 3143, 26075, 47751, 71001, 157107}},
+{13939, 18, 8813, {1, 3, 3, 7, 23, 9, 69, 21, 333, 223, 1735, 1057, 8091, 1927, 8507, 40901, 40233, 164115}},
+{13940, 18, 8821, {1, 3, 7, 3, 11, 49, 29, 81, 215, 289, 1137, 765, 6385, 5935, 3435, 11991, 30867, 60745}},
+{13941, 18, 8856, {1, 1, 1, 1, 7, 39, 33, 173, 225, 533, 1927, 3607, 1059, 8779, 2649, 6801, 103963, 167471}},
+{13942, 18, 8877, {1, 3, 3, 15, 27, 51, 107, 3, 195, 87, 739, 1425, 747, 1501, 22245, 59233, 124867, 79753}},
+{13943, 18, 8885, {1, 1, 3, 3, 13, 41, 125, 101, 225, 749, 221, 2735, 6441, 11353, 3943, 35329, 53437, 149063}},
+{13944, 18, 8897, {1, 3, 3, 15, 3, 53, 75, 77, 1, 907, 573, 1909, 363, 6913, 559, 58489, 1053, 25513}},
+{13945, 18, 8898, {1, 1, 7, 11, 7, 15, 91, 155, 447, 555, 473, 3625, 7529, 16307, 32241, 64077, 46943, 85717}},
+{13946, 18, 8934, {1, 1, 1, 13, 9, 61, 91, 41, 101, 107, 1081, 2511, 2881, 14095, 3861, 22771, 32687, 77287}},
+{13947, 18, 8955, {1, 3, 3, 7, 21, 3, 51, 177, 203, 861, 1507, 1177, 2369, 11735, 1667, 28607, 97671, 123263}},
+{13948, 18, 8972, {1, 1, 1, 3, 5, 57, 13, 127, 353, 65, 663, 3849, 3579, 5521, 11765, 63427, 76349, 102517}},
+{13949, 18, 8977, {1, 1, 7, 11, 27, 55, 79, 249, 397, 77, 1543, 3787, 4889, 11145, 18691, 62899, 66425, 116195}},
+{13950, 18, 9038, {1, 1, 1, 3, 5, 3, 1, 143, 73, 999, 2013, 2001, 4001, 6563, 30811, 61445, 2645, 203631}},
+{13951, 18, 9045, {1, 1, 1, 15, 1, 49, 35, 61, 493, 101, 1407, 2211, 7467, 12321, 15901, 15479, 62939, 14643}},
+{13952, 18, 9071, {1, 1, 3, 11, 21, 33, 123, 95, 449, 355, 1501, 1627, 1411, 6183, 17457, 2199, 96313, 25023}},
+{13953, 18, 9085, {1, 1, 5, 5, 13, 49, 73, 203, 83, 3, 137, 119, 3001, 10685, 18231, 60727, 31785, 158605}},
+{13954, 18, 9110, {1, 3, 1, 11, 23, 19, 123, 9, 269, 501, 2005, 3695, 3327, 5353, 12619, 12987, 18213, 29355}},
+{13955, 18, 9120, {1, 3, 1, 5, 1, 25, 99, 197, 327, 575, 773, 2009, 6653, 1807, 20381, 55725, 124359, 176893}},
+{13956, 18, 9157, {1, 1, 7, 15, 27, 9, 81, 175, 73, 727, 1907, 1237, 4983, 16123, 16479, 2283, 57805, 13593}},
+{13957, 18, 9164, {1, 1, 3, 13, 7, 13, 13, 139, 283, 721, 487, 1821, 4257, 5105, 8057, 27193, 46857, 169927}},
+{13958, 18, 9185, {1, 1, 5, 5, 29, 5, 81, 211, 441, 685, 981, 3097, 6253, 10673, 12253, 54943, 69401, 147769}},
+{13959, 18, 9203, {1, 3, 3, 1, 13, 35, 73, 145, 139, 781, 37, 803, 3607, 4327, 1153, 11325, 131025, 168729}},
+{13960, 18, 9235, {1, 3, 1, 13, 17, 41, 19, 59, 23, 561, 315, 719, 3325, 275, 12715, 59843, 16597, 81691}},
+{13961, 18, 9278, {1, 3, 1, 11, 1, 53, 11, 237, 363, 345, 331, 129, 6885, 3105, 12487, 53803, 8897, 193777}},
+{13962, 18, 9290, {1, 3, 7, 15, 3, 53, 55, 101, 389, 839, 413, 2851, 3989, 12857, 25723, 16595, 94145, 193049}},
+{13963, 18, 9292, {1, 3, 1, 7, 15, 31, 3, 115, 197, 753, 1035, 1369, 4925, 4497, 1641, 63743, 127089, 114097}},
+{13964, 18, 9319, {1, 3, 5, 5, 23, 1, 35, 99, 277, 769, 895, 581, 6969, 15339, 10309, 27101, 22611, 86179}},
+{13965, 18, 9334, {1, 1, 1, 11, 19, 17, 45, 35, 257, 313, 815, 1469, 3651, 15101, 22775, 51729, 75401, 123653}},
+{13966, 18, 9362, {1, 3, 1, 15, 5, 11, 83, 141, 373, 935, 1123, 1849, 1267, 15427, 10615, 63303, 109771, 188601}},
+{13967, 18, 9387, {1, 3, 5, 3, 29, 23, 79, 193, 261, 29, 1857, 789, 4359, 14211, 22181, 64901, 129089, 65587}},
+{13968, 18, 9404, {1, 3, 1, 3, 29, 15, 19, 239, 497, 771, 239, 2853, 2391, 8153, 31899, 53759, 127219, 78833}},
+{13969, 18, 9407, {1, 1, 7, 7, 5, 57, 9, 93, 69, 993, 193, 3629, 5761, 9339, 28073, 50035, 81635, 83119}},
+{13970, 18, 9410, {1, 1, 5, 13, 7, 35, 79, 247, 43, 1011, 1189, 2881, 1963, 8889, 9929, 50043, 112581, 224139}},
+{13971, 18, 9422, {1, 3, 3, 7, 15, 63, 85, 33, 107, 37, 45, 1271, 4735, 1151, 19793, 6589, 50875, 185061}},
+{13972, 18, 9478, {1, 3, 1, 15, 1, 63, 1, 201, 207, 179, 67, 3703, 2629, 10517, 1, 39645, 119733, 6449}},
+{13973, 18, 9512, {1, 3, 5, 1, 3, 7, 97, 101, 233, 71, 255, 3767, 8127, 8041, 25001, 7601, 129595, 131657}},
+{13974, 18, 9535, {1, 1, 7, 1, 25, 29, 105, 25, 267, 191, 267, 3141, 4445, 5043, 25203, 32055, 11035, 229031}},
+{13975, 18, 9604, {1, 1, 1, 13, 3, 1, 1, 147, 63, 259, 1171, 401, 6289, 13577, 28129, 1349, 85027, 178123}},
+{13976, 18, 9616, {1, 1, 1, 13, 1, 59, 109, 95, 49, 309, 1141, 1355, 3415, 11237, 21619, 12039, 1795, 57775}},
+{13977, 18, 9622, {1, 3, 1, 11, 19, 3, 51, 227, 277, 49, 703, 2701, 515, 8893, 20163, 65297, 114781, 225687}},
+{13978, 18, 9631, {1, 3, 7, 11, 19, 47, 121, 199, 173, 905, 1903, 1781, 2425, 13381, 25843, 23279, 87701, 10723}},
+{13979, 18, 9656, {1, 3, 1, 13, 7, 21, 17, 15, 85, 241, 119, 2361, 7921, 6077, 955, 34221, 78179, 35511}},
+{13980, 18, 9710, {1, 1, 7, 11, 9, 1, 1, 29, 445, 557, 241, 959, 6077, 3547, 30987, 48129, 79699, 236611}},
+{13981, 18, 9721, {1, 3, 1, 15, 13, 29, 57, 117, 347, 719, 1435, 307, 5209, 4009, 10517, 3373, 67667, 260101}},
+{13982, 18, 9728, {1, 1, 7, 13, 11, 41, 17, 143, 467, 993, 779, 3991, 623, 8915, 21615, 56477, 59721, 164241}},
+{13983, 18, 9733, {1, 1, 3, 7, 15, 37, 53, 33, 395, 547, 1815, 2517, 6575, 14035, 1, 10919, 25467, 117521}},
+{13984, 18, 9738, {1, 1, 3, 9, 17, 47, 45, 3, 509, 53, 1245, 883, 7917, 15445, 4169, 49637, 90933, 109469}},
+{13985, 18, 9774, {1, 3, 1, 3, 27, 37, 3, 95, 31, 665, 701, 1979, 3735, 3257, 18943, 41201, 95721, 69451}},
+{13986, 18, 9791, {1, 1, 1, 15, 19, 49, 61, 5, 115, 801, 805, 2723, 1387, 13165, 20717, 40767, 88857, 28207}},
+{13987, 18, 9803, {1, 1, 5, 9, 21, 25, 23, 179, 59, 29, 547, 1829, 4411, 6689, 22363, 43975, 52259, 187563}},
+{13988, 18, 9805, {1, 1, 5, 11, 13, 31, 97, 131, 135, 415, 53, 4015, 3629, 6613, 25541, 47221, 66483, 224545}},
+{13989, 18, 9817, {1, 3, 1, 11, 19, 13, 65, 95, 381, 759, 1319, 2997, 6321, 9203, 24483, 9925, 10799, 117119}},
+{13990, 18, 9823, {1, 3, 5, 13, 27, 17, 39, 225, 199, 125, 1125, 2673, 6787, 8861, 13139, 13849, 65459, 40183}},
+{13991, 18, 9839, {1, 1, 5, 3, 17, 55, 23, 75, 457, 959, 1507, 1267, 6857, 16141, 1889, 10779, 41331, 166075}},
+{13992, 18, 9847, {1, 3, 1, 15, 7, 55, 109, 59, 241, 431, 1281, 183, 1029, 14617, 4003, 41871, 36007, 129617}},
+{13993, 18, 9854, {1, 3, 1, 1, 27, 61, 79, 93, 217, 251, 671, 989, 7031, 10035, 15455, 13685, 95471, 997}},
+{13994, 18, 9863, {1, 1, 3, 13, 1, 5, 125, 179, 357, 537, 1303, 2653, 7319, 2075, 3861, 11743, 89659, 221705}},
+{13995, 18, 9872, {1, 1, 1, 7, 3, 55, 5, 201, 153, 639, 835, 1913, 3331, 10727, 30365, 15133, 67911, 17851}},
+{13996, 18, 9884, {1, 1, 3, 13, 21, 1, 67, 71, 265, 43, 279, 2009, 873, 4447, 32001, 50783, 76613, 63919}},
+{13997, 18, 9935, {1, 1, 3, 11, 17, 43, 19, 195, 233, 17, 1855, 1227, 3435, 4313, 6417, 51019, 130091, 124947}},
+{13998, 18, 9937, {1, 1, 7, 9, 19, 9, 95, 87, 297, 817, 1217, 3637, 2371, 7073, 387, 62121, 43507, 93927}},
+{13999, 18, 9974, {1, 3, 5, 13, 1, 15, 29, 123, 137, 425, 531, 2659, 2077, 1345, 2803, 49469, 29031, 170825}},
+{14000, 18, 9980, {1, 1, 5, 7, 15, 13, 119, 231, 139, 673, 1105, 2355, 3023, 4437, 17491, 47367, 12751, 183319}},
+{14001, 18, 10003, {1, 1, 5, 15, 19, 5, 125, 121, 509, 539, 473, 2087, 4421, 4205, 23457, 34481, 111231, 145035}},
+{14002, 18, 10015, {1, 3, 7, 5, 23, 21, 85, 23, 415, 715, 1579, 3447, 2373, 233, 19401, 54869, 15977, 138119}},
+{14003, 18, 10016, {1, 1, 3, 11, 21, 1, 37, 127, 101, 943, 79, 2119, 5679, 10749, 16209, 16715, 29421, 259735}},
+{14004, 18, 10066, {1, 3, 7, 7, 23, 25, 1, 73, 505, 979, 535, 87, 4165, 9353, 20075, 57597, 74651, 22133}},
+{14005, 18, 10093, {1, 1, 7, 3, 11, 19, 75, 213, 293, 15, 1981, 1259, 5455, 2897, 18861, 6317, 10339, 123967}},
+{14006, 18, 10118, {1, 3, 1, 3, 29, 5, 93, 169, 51, 519, 1649, 2789, 1251, 8359, 11489, 62443, 91549, 148357}},
+{14007, 18, 10132, {1, 3, 3, 13, 5, 47, 39, 163, 341, 755, 737, 2335, 2389, 8351, 26193, 58111, 18425, 129313}},
+{14008, 18, 10135, {1, 1, 3, 1, 31, 49, 101, 69, 345, 291, 1257, 1801, 1613, 1479, 4403, 21307, 44947, 68591}},
+{14009, 18, 10151, {1, 3, 3, 9, 5, 23, 65, 65, 187, 709, 883, 2199, 1037, 8679, 31527, 23561, 92225, 254215}},
+{14010, 18, 10158, {1, 3, 7, 7, 23, 13, 87, 209, 163, 705, 1199, 3007, 5469, 2453, 2691, 17841, 97045, 174149}},
+{14011, 18, 10169, {1, 1, 1, 9, 5, 35, 21, 91, 145, 559, 131, 3911, 1777, 8225, 6077, 58223, 100827, 3641}},
+{14012, 18, 10172, {1, 1, 5, 5, 7, 5, 31, 189, 117, 785, 1493, 3899, 471, 10971, 4607, 21063, 67225, 195367}},
+{14013, 18, 10180, {1, 1, 7, 5, 31, 61, 63, 163, 417, 655, 2033, 1255, 1139, 6867, 28655, 55295, 100519, 166629}},
+{14014, 18, 10187, {1, 3, 3, 3, 7, 35, 83, 55, 7, 607, 253, 915, 6801, 7505, 15929, 16829, 78469, 150947}},
+{14015, 18, 10189, {1, 3, 3, 9, 29, 3, 127, 235, 347, 3, 193, 1547, 8073, 14963, 20351, 28951, 53855, 261375}},
+{14016, 18, 10192, {1, 1, 7, 3, 31, 19, 75, 87, 23, 419, 75, 1677, 2371, 8875, 31993, 4465, 76085, 86499}},
+{14017, 18, 10197, {1, 3, 5, 7, 1, 51, 47, 161, 415, 521, 1099, 1295, 2545, 15167, 13983, 7347, 60631, 4089}},
+{14018, 18, 10211, {1, 1, 1, 9, 7, 59, 71, 187, 441, 273, 769, 2649, 3261, 12661, 23045, 32035, 104573, 120589}},
+{14019, 18, 10214, {1, 3, 7, 13, 23, 51, 113, 205, 443, 291, 475, 2961, 7615, 105, 22099, 6045, 22667, 65515}},
+{14020, 18, 10256, {1, 1, 5, 11, 1, 1, 23, 231, 413, 371, 1285, 2695, 2751, 4235, 15779, 1903, 24469, 259157}},
+{14021, 18, 10278, {1, 3, 3, 7, 7, 47, 87, 105, 311, 251, 573, 3221, 5757, 11107, 11161, 8809, 14467, 33153}},
+{14022, 18, 10290, {1, 1, 7, 1, 31, 49, 51, 31, 305, 315, 547, 1159, 2741, 3773, 13299, 40115, 62523, 108487}},
+{14023, 18, 10301, {1, 3, 1, 11, 11, 43, 33, 213, 107, 467, 1509, 4081, 4723, 2409, 1447, 42759, 64717, 161991}},
+{14024, 18, 10310, {1, 3, 7, 3, 31, 23, 25, 159, 95, 721, 1981, 3659, 4819, 10119, 25451, 10165, 31281, 238319}},
+{14025, 18, 10344, {1, 3, 1, 5, 19, 27, 67, 125, 481, 585, 43, 3697, 4997, 581, 6439, 33477, 115023, 51759}},
+{14026, 18, 10473, {1, 3, 7, 7, 15, 53, 89, 173, 369, 365, 91, 1583, 4611, 7189, 30383, 47397, 73657, 158695}},
+{14027, 18, 10474, {1, 1, 1, 15, 1, 21, 125, 13, 243, 729, 1397, 2451, 3233, 15593, 2815, 56215, 22685, 167343}},
+{14028, 18, 10482, {1, 3, 1, 13, 13, 29, 119, 223, 51, 695, 273, 2381, 4431, 4891, 29875, 49511, 111003, 174413}},
+{14029, 18, 10499, {1, 3, 3, 15, 9, 13, 19, 177, 371, 957, 255, 115, 4701, 6089, 7237, 17077, 87949, 3111}},
+{14030, 18, 10525, {1, 1, 7, 11, 29, 49, 59, 201, 145, 219, 1159, 3863, 715, 10489, 25883, 56445, 122103, 149877}},
+{14031, 18, 10532, {1, 3, 1, 13, 15, 51, 91, 109, 433, 45, 2045, 3121, 1109, 14713, 2667, 40463, 52185, 64743}},
+{14032, 18, 10535, {1, 3, 3, 7, 21, 31, 7, 155, 347, 305, 1557, 1311, 3315, 1363, 403, 62063, 114195, 44623}},
+{14033, 18, 10556, {1, 3, 5, 11, 9, 11, 11, 245, 49, 21, 239, 3043, 3525, 1055, 21891, 19153, 123689, 170195}},
+{14034, 18, 10568, {1, 1, 1, 11, 17, 51, 83, 249, 483, 489, 1063, 469, 6153, 15551, 13783, 27945, 103775, 68175}},
+{14035, 18, 10579, {1, 3, 3, 13, 11, 61, 107, 113, 503, 819, 1593, 2851, 6711, 14623, 3709, 10931, 8743, 62321}},
+{14036, 18, 10586, {1, 1, 5, 15, 5, 37, 23, 131, 329, 499, 1765, 1273, 819, 11573, 3307, 46933, 22087, 173459}},
+{14037, 18, 10609, {1, 1, 1, 3, 31, 5, 49, 57, 239, 981, 1863, 3233, 2727, 7389, 7923, 63259, 62873, 113607}},
+{14038, 18, 10612, {1, 1, 7, 7, 11, 27, 119, 137, 115, 211, 1239, 2153, 2579, 11501, 747, 31141, 129793, 151589}},
+{14039, 18, 10650, {1, 3, 3, 9, 9, 55, 121, 199, 91, 835, 521, 2433, 8123, 2045, 32553, 48993, 9935, 220537}},
+{14040, 18, 10665, {1, 3, 7, 11, 15, 57, 53, 145, 299, 623, 691, 1557, 785, 15851, 27075, 5983, 18043, 22241}},
+{14041, 18, 10685, {1, 1, 3, 1, 1, 57, 57, 195, 381, 913, 167, 333, 5541, 2323, 17001, 34817, 30795, 144051}},
+{14042, 18, 10686, {1, 3, 3, 3, 31, 1, 83, 31, 91, 855, 195, 3449, 8057, 11061, 29089, 1597, 127581, 189033}},
+{14043, 18, 10688, {1, 3, 1, 1, 21, 59, 113, 179, 13, 523, 629, 3693, 7155, 893, 17449, 46535, 18051, 9191}},
+{14044, 18, 10711, {1, 1, 1, 3, 27, 19, 75, 229, 181, 653, 1849, 501, 5871, 14769, 27461, 59193, 115013, 72227}},
+{14045, 18, 10728, {1, 3, 3, 13, 17, 41, 111, 107, 453, 299, 1699, 2871, 2955, 4215, 13919, 19785, 30339, 148445}},
+{14046, 18, 10748, {1, 3, 3, 11, 5, 19, 21, 87, 173, 439, 1651, 2393, 4137, 16285, 16093, 22953, 105663, 226575}},
+{14047, 18, 10751, {1, 3, 5, 7, 19, 61, 101, 251, 295, 89, 1695, 1359, 5797, 8587, 18753, 65223, 51079, 96169}},
+{14048, 18, 10781, {1, 1, 1, 5, 3, 1, 79, 63, 221, 601, 1385, 1963, 4601, 15217, 4861, 58295, 61043, 88523}},
+{14049, 18, 10805, {1, 3, 3, 7, 31, 63, 73, 177, 455, 487, 1009, 2103, 4753, 3143, 10121, 36509, 24753, 230869}},
+{14050, 18, 10823, {1, 1, 5, 1, 17, 27, 103, 63, 475, 665, 1189, 3513, 89, 2669, 1227, 20635, 121549, 248851}},
+{14051, 18, 10838, {1, 1, 3, 7, 25, 19, 117, 243, 337, 207, 903, 3751, 3309, 11955, 12651, 25359, 83419, 19701}},
+{14052, 18, 10857, {1, 1, 7, 15, 19, 21, 3, 235, 289, 185, 1175, 2291, 4003, 7753, 4775, 65321, 48957, 220261}},
+{14053, 18, 10865, {1, 3, 5, 11, 23, 21, 107, 65, 117, 329, 1085, 3555, 1183, 15241, 32663, 50985, 66753, 38023}},
+{14054, 18, 10872, {1, 1, 7, 9, 11, 49, 65, 17, 291, 435, 1221, 3829, 5467, 5181, 19891, 7091, 80673, 90495}},
+{14055, 18, 10893, {1, 1, 1, 15, 17, 47, 119, 173, 297, 477, 859, 3661, 8081, 8257, 20841, 55123, 11231, 193669}},
+{14056, 18, 10899, {1, 1, 7, 7, 27, 11, 119, 109, 199, 727, 1569, 3749, 4067, 11675, 30213, 58091, 64303, 92785}},
+{14057, 18, 10917, {1, 3, 7, 15, 15, 39, 101, 149, 299, 449, 1017, 723, 7731, 7929, 22465, 61583, 69851, 150507}},
+{14058, 18, 10935, {1, 3, 5, 15, 5, 13, 97, 127, 21, 673, 353, 3885, 5761, 11443, 10089, 23701, 85879, 42217}},
+{14059, 18, 11001, {1, 3, 1, 5, 27, 55, 31, 167, 69, 453, 925, 555, 5135, 2759, 27077, 14497, 94333, 108729}},
+{14060, 18, 11072, {1, 1, 7, 15, 11, 55, 9, 241, 55, 611, 149, 2605, 653, 1631, 15059, 6349, 12321, 124561}},
+{14061, 18, 11089, {1, 1, 1, 9, 3, 11, 95, 67, 443, 103, 1687, 2667, 4567, 4271, 15601, 27859, 4757, 53289}},
+{14062, 18, 11090, {1, 1, 5, 9, 23, 21, 1, 125, 105, 975, 1879, 1821, 5273, 7079, 25009, 10471, 29119, 73249}},
+{14063, 18, 11108, {1, 1, 7, 1, 31, 61, 17, 23, 485, 565, 1325, 1559, 4131, 751, 2071, 4719, 15925, 101207}},
+{14064, 18, 11117, {1, 1, 5, 5, 13, 53, 13, 93, 149, 139, 1429, 3605, 3545, 11193, 14139, 6093, 115727, 183105}},
+{14065, 18, 11136, {1, 1, 1, 7, 15, 37, 51, 77, 177, 967, 405, 563, 3047, 8499, 26787, 27609, 23613, 239679}},
+{14066, 18, 11148, {1, 1, 1, 5, 27, 37, 1, 129, 197, 133, 1329, 3673, 3143, 1059, 19209, 39027, 43787, 42821}},
+{14067, 18, 11153, {1, 3, 7, 5, 5, 47, 105, 121, 219, 777, 1569, 1359, 1955, 13207, 14895, 7829, 40499, 182911}},
+{14068, 18, 11181, {1, 3, 5, 7, 11, 41, 41, 155, 245, 383, 405, 2415, 5809, 5117, 31523, 16927, 76785, 113731}},
+{14069, 18, 11190, {1, 3, 3, 9, 9, 21, 13, 197, 409, 931, 305, 1129, 865, 12961, 5239, 35823, 82565, 226765}},
+{14070, 18, 11201, {1, 1, 5, 3, 17, 27, 59, 79, 359, 601, 979, 1355, 1657, 10479, 4741, 36391, 111527, 105139}},
+{14071, 18, 11204, {1, 3, 5, 9, 13, 43, 31, 1, 309, 723, 1049, 803, 1653, 2551, 26317, 49731, 67799, 129225}},
+{14072, 18, 11216, {1, 1, 5, 3, 1, 39, 95, 243, 499, 809, 1515, 981, 585, 7907, 16801, 43381, 117537, 99787}},
+{14073, 18, 11237, {1, 1, 5, 5, 25, 23, 15, 127, 33, 799, 647, 2923, 7805, 2681, 14773, 42751, 106861, 119657}},
+{14074, 18, 11259, {1, 3, 1, 1, 1, 47, 11, 179, 179, 659, 1061, 2511, 3601, 7107, 27887, 48427, 40559, 106043}},
+{14075, 18, 11279, {1, 1, 7, 11, 5, 33, 115, 195, 431, 383, 1571, 3485, 5741, 5775, 14891, 26389, 71723, 198861}},
+{14076, 18, 11282, {1, 1, 5, 5, 11, 55, 37, 57, 381, 607, 2017, 1981, 6113, 3771, 8827, 13335, 88587, 102791}},
+{14077, 18, 11304, {1, 1, 1, 11, 29, 23, 73, 149, 405, 581, 721, 281, 5315, 4675, 13013, 39003, 20335, 109855}},
+{14078, 18, 11312, {1, 1, 7, 15, 17, 57, 39, 51, 403, 979, 1543, 1235, 797, 5949, 26647, 15125, 33255, 152861}},
+{14079, 18, 11332, {1, 1, 5, 3, 25, 27, 7, 147, 257, 163, 1297, 2289, 693, 7771, 6341, 22323, 1653, 177669}},
+{14080, 18, 11341, {1, 1, 3, 9, 1, 39, 47, 231, 15, 705, 897, 3943, 6281, 6679, 21695, 29553, 39509, 83135}},
+{14081, 18, 11354, {1, 3, 3, 15, 17, 43, 15, 195, 31, 501, 529, 3117, 6031, 12101, 30687, 52465, 66171, 149591}},
+{14082, 18, 11356, {1, 1, 3, 5, 13, 17, 63, 41, 303, 671, 1225, 1761, 6159, 3203, 23611, 18309, 115027, 116325}},
+{14083, 18, 11365, {1, 1, 5, 13, 17, 5, 97, 155, 479, 525, 1403, 4063, 8167, 6443, 20627, 41399, 26897, 102841}},
+{14084, 18, 11377, {1, 3, 5, 9, 9, 27, 59, 177, 453, 659, 765, 431, 4209, 12679, 10719, 22473, 81597, 20057}},
+{14085, 18, 11417, {1, 3, 3, 1, 3, 37, 91, 97, 159, 845, 519, 2603, 6979, 6711, 29781, 53639, 103357, 111671}},
+{14086, 18, 11427, {1, 1, 3, 3, 25, 15, 27, 9, 503, 719, 153, 3071, 281, 5341, 32595, 13069, 6461, 160319}},
+{14087, 18, 11433, {1, 3, 3, 5, 29, 7, 119, 229, 117, 925, 465, 1703, 7277, 10631, 9429, 41011, 45181, 229239}},
+{14088, 18, 11434, {1, 1, 7, 7, 31, 63, 67, 55, 445, 39, 1363, 1369, 1061, 8555, 29263, 47341, 49563, 80445}},
+{14089, 18, 11439, {1, 1, 7, 1, 23, 23, 49, 205, 371, 101, 1963, 2763, 3475, 835, 20371, 51343, 9771, 69713}},
+{14090, 18, 11444, {1, 3, 3, 7, 3, 29, 7, 185, 511, 93, 1077, 3971, 2981, 16367, 12703, 36179, 47755, 42767}},
+{14091, 18, 11448, {1, 1, 1, 11, 27, 47, 43, 39, 129, 337, 1249, 3557, 2871, 13565, 19525, 46263, 49203, 148235}},
+{14092, 18, 11461, {1, 3, 5, 11, 19, 3, 83, 151, 425, 199, 847, 3751, 1729, 12457, 21819, 295, 53627, 17555}},
+{14093, 18, 11466, {1, 1, 3, 5, 7, 43, 21, 221, 93, 785, 1851, 3891, 2103, 5219, 31845, 58943, 42461, 160149}},
+{14094, 18, 11468, {1, 3, 5, 9, 25, 11, 43, 171, 445, 335, 1907, 3401, 815, 10341, 17779, 24895, 7727, 168143}},
+{14095, 18, 11473, {1, 3, 1, 5, 27, 25, 41, 13, 239, 233, 1861, 3409, 4325, 2227, 30197, 59329, 48501, 168799}},
+{14096, 18, 11489, {1, 3, 5, 13, 9, 55, 83, 185, 287, 83, 1545, 2803, 2177, 6195, 14455, 30541, 75731, 98915}},
+{14097, 18, 11499, {1, 3, 3, 5, 25, 19, 5, 203, 303, 703, 1861, 3867, 2683, 8223, 11107, 54785, 106053, 135543}},
+{14098, 18, 11516, {1, 1, 1, 13, 19, 7, 11, 197, 303, 541, 977, 2083, 4739, 7971, 2245, 11029, 77333, 16573}},
+{14099, 18, 11531, {1, 1, 1, 3, 11, 33, 77, 59, 283, 791, 365, 4027, 487, 10559, 4543, 58111, 91861, 102905}},
+{14100, 18, 11533, {1, 3, 7, 7, 15, 3, 19, 51, 339, 377, 929, 693, 1617, 14057, 7107, 27181, 7411, 202843}},
+{14101, 18, 11557, {1, 3, 3, 9, 19, 9, 73, 109, 333, 917, 1227, 2871, 4893, 11029, 5619, 27091, 9381, 213403}},
+{14102, 18, 11572, {1, 1, 1, 9, 9, 13, 77, 131, 163, 619, 169, 315, 1277, 13705, 16853, 1179, 86433, 135427}},
+{14103, 18, 11608, {1, 3, 5, 9, 15, 47, 57, 119, 325, 529, 893, 2395, 5159, 5481, 18689, 6457, 114733, 159999}},
+{14104, 18, 11635, {1, 3, 7, 5, 15, 9, 113, 235, 475, 93, 495, 2983, 2769, 5209, 7481, 49699, 46961, 246393}},
+{14105, 18, 11638, {1, 1, 7, 1, 5, 31, 113, 27, 359, 635, 955, 2795, 6289, 11621, 11059, 2259, 57443, 243143}},
+{14106, 18, 11644, {1, 3, 3, 13, 19, 33, 53, 141, 437, 415, 919, 1375, 2703, 13731, 31559, 14115, 50101, 85199}},
+{14107, 18, 11684, {1, 1, 7, 13, 27, 57, 111, 89, 89, 313, 1107, 4049, 2485, 269, 10197, 36995, 71381, 112795}},
+{14108, 18, 11702, {1, 1, 3, 7, 17, 23, 119, 123, 145, 213, 1273, 1707, 4005, 13815, 23495, 36359, 14391, 94287}},
+{14109, 18, 11740, {1, 1, 7, 1, 5, 49, 81, 193, 105, 1003, 413, 2975, 1725, 5647, 25447, 43501, 4431, 115489}},
+{14110, 18, 11749, {1, 3, 1, 5, 29, 13, 47, 37, 441, 955, 611, 853, 7225, 4959, 8739, 31703, 48095, 124085}},
+{14111, 18, 11754, {1, 1, 5, 15, 31, 9, 125, 53, 229, 631, 1031, 3923, 4417, 12637, 22093, 46985, 103417, 193443}},
+{14112, 18, 11764, {1, 1, 7, 1, 7, 9, 77, 11, 451, 615, 1259, 3097, 1513, 13641, 26845, 17399, 63661, 9231}},
+{14113, 18, 11767, {1, 1, 7, 13, 25, 47, 125, 1, 333, 599, 1133, 3527, 7451, 2849, 27227, 40015, 118185, 24737}},
+{14114, 18, 11784, {1, 1, 5, 5, 31, 15, 85, 37, 121, 677, 593, 2757, 739, 839, 3939, 36339, 116663, 955}},
+{14115, 18, 11789, {1, 3, 1, 11, 19, 13, 87, 109, 149, 215, 1811, 3813, 7699, 16189, 12841, 52081, 104545, 245819}},
+{14116, 18, 11795, {1, 1, 7, 3, 31, 17, 99, 23, 377, 131, 821, 1167, 4437, 15727, 20753, 8163, 43719, 7243}},
+{14117, 18, 11798, {1, 3, 7, 13, 21, 5, 5, 167, 9, 1009, 1013, 797, 6145, 2855, 19969, 59887, 3419, 238661}},
+{14118, 18, 11804, {1, 1, 7, 1, 5, 39, 47, 91, 185, 139, 959, 3149, 3423, 8909, 2045, 18187, 71935, 238605}},
+{14119, 18, 11818, {1, 3, 5, 11, 29, 63, 105, 43, 27, 221, 879, 181, 1499, 10343, 27135, 823, 4893, 101707}},
+{14120, 18, 11820, {1, 3, 5, 11, 5, 13, 59, 83, 315, 999, 1205, 939, 3661, 3081, 15551, 13791, 49027, 26843}},
+{14121, 18, 11860, {1, 1, 1, 5, 3, 57, 105, 169, 123, 463, 1471, 445, 743, 13353, 17661, 23437, 35451, 115919}},
+{14122, 18, 11869, {1, 1, 5, 11, 9, 3, 41, 63, 501, 861, 153, 1591, 1379, 5189, 24483, 8073, 43319, 248959}},
+{14123, 18, 11874, {1, 1, 7, 3, 29, 45, 51, 177, 1, 961, 1493, 2179, 3723, 1923, 1517, 44823, 81613, 194641}},
+{14124, 18, 11903, {1, 1, 5, 11, 17, 17, 61, 141, 5, 529, 379, 2509, 1487, 13141, 10877, 18603, 40569, 69639}},
+{14125, 18, 11916, {1, 1, 5, 15, 1, 15, 33, 219, 269, 557, 7, 3627, 183, 6975, 4627, 15235, 51863, 172393}},
+{14126, 18, 11927, {1, 3, 7, 9, 1, 37, 13, 75, 151, 153, 1693, 2835, 3093, 8847, 6721, 44135, 128931, 230745}},
+{14127, 18, 11933, {1, 1, 3, 13, 29, 63, 33, 153, 503, 137, 401, 2315, 2223, 10843, 4235, 37295, 103249, 183899}},
+{14128, 18, 11962, {1, 1, 7, 11, 15, 25, 49, 55, 39, 13, 269, 3119, 3445, 8265, 16781, 57239, 97489, 204841}},
+{14129, 18, 12009, {1, 1, 1, 1, 25, 57, 117, 199, 41, 351, 477, 1891, 7913, 14439, 25305, 64811, 57731, 184265}},
+{14130, 18, 12020, {1, 3, 3, 1, 13, 41, 33, 53, 381, 31, 1861, 2207, 1497, 15539, 23589, 53215, 36887, 134007}},
+{14131, 18, 12035, {1, 1, 5, 7, 15, 37, 13, 99, 17, 325, 643, 2943, 7967, 11531, 21301, 5125, 63201, 101203}},
+{14132, 18, 12041, {1, 1, 7, 11, 23, 21, 119, 151, 457, 929, 1917, 3123, 1133, 11861, 27889, 40421, 90949, 113237}},
+{14133, 18, 12049, {1, 3, 5, 9, 13, 35, 111, 83, 371, 589, 1507, 3559, 773, 5895, 31453, 40865, 124103, 250473}},
+{14134, 18, 12065, {1, 3, 3, 15, 11, 7, 93, 163, 285, 763, 2023, 1047, 3349, 13575, 22571, 21513, 56081, 204765}},
+{14135, 18, 12072, {1, 3, 3, 5, 19, 19, 47, 25, 49, 717, 1155, 3901, 407, 2699, 30961, 55647, 96043, 185559}},
+{14136, 18, 12098, {1, 1, 1, 7, 29, 1, 49, 87, 311, 435, 1235, 1041, 6595, 1639, 32495, 44245, 6593, 236331}},
+{14137, 18, 12100, {1, 3, 7, 9, 27, 13, 1, 41, 75, 953, 1635, 101, 7231, 13019, 14773, 17315, 120993, 111215}},
+{14138, 18, 12107, {1, 1, 5, 9, 23, 31, 87, 47, 83, 791, 1239, 1453, 5459, 4847, 7285, 32667, 45991, 103593}},
+{14139, 18, 12167, {1, 3, 1, 3, 27, 47, 97, 191, 5, 961, 1191, 3897, 6821, 4257, 22047, 31557, 52603, 251405}},
+{14140, 18, 12202, {1, 1, 5, 3, 23, 45, 103, 115, 287, 47, 93, 2761, 6467, 14031, 21881, 31631, 47605, 237635}},
+{14141, 18, 12207, {1, 3, 7, 15, 23, 41, 63, 239, 115, 655, 1949, 1969, 3145, 91, 16735, 49295, 117995, 40537}},
+{14142, 18, 12233, {1, 1, 7, 11, 5, 25, 99, 247, 11, 707, 1497, 785, 6055, 8521, 12179, 56363, 110131, 55449}},
+{14143, 18, 12269, {1, 1, 1, 7, 5, 31, 99, 7, 285, 281, 1207, 1173, 7637, 9595, 31413, 16597, 96157, 39059}},
+{14144, 18, 12290, {1, 3, 7, 7, 3, 49, 79, 69, 57, 523, 65, 2785, 2907, 11295, 16199, 25845, 51801, 67417}},
+{14145, 18, 12304, {1, 1, 3, 1, 1, 53, 57, 117, 1, 927, 1787, 3059, 7441, 14663, 10881, 2225, 29375, 93717}},
+{14146, 18, 12314, {1, 1, 5, 5, 29, 17, 67, 35, 475, 367, 155, 3463, 2339, 6239, 31073, 56169, 130309, 28981}},
+{14147, 18, 12340, {1, 1, 1, 5, 7, 53, 61, 105, 355, 817, 869, 2863, 6041, 11459, 4151, 61115, 100689, 32917}},
+{14148, 18, 12416, {1, 3, 5, 11, 31, 11, 33, 105, 437, 767, 101, 2979, 3911, 4859, 15551, 23545, 10705, 6271}},
+{14149, 18, 12425, {1, 1, 7, 5, 1, 17, 109, 205, 409, 893, 889, 2181, 6167, 14273, 25389, 50279, 5497, 191755}},
+{14150, 18, 12428, {1, 3, 7, 15, 29, 11, 79, 101, 123, 399, 1159, 1263, 3513, 13169, 2199, 41057, 98639, 227107}},
+{14151, 18, 12446, {1, 1, 3, 11, 13, 31, 51, 119, 257, 829, 337, 3267, 7673, 15459, 26681, 4041, 89429, 198607}},
+{14152, 18, 12462, {1, 3, 7, 11, 23, 29, 49, 159, 327, 415, 857, 2411, 2429, 11839, 20263, 61813, 31811, 225443}},
+{14153, 18, 12476, {1, 1, 3, 11, 7, 61, 61, 119, 431, 299, 1815, 2857, 7605, 7517, 15137, 13727, 73021, 199325}},
+{14154, 18, 12496, {1, 1, 7, 3, 5, 19, 51, 19, 59, 637, 591, 2999, 5997, 13487, 807, 4887, 112189, 226597}},
+{14155, 18, 12511, {1, 1, 1, 13, 21, 5, 55, 167, 463, 679, 891, 3597, 785, 7717, 17495, 51681, 55957, 48561}},
+{14156, 18, 12518, {1, 1, 5, 5, 9, 55, 55, 143, 193, 839, 785, 1713, 7457, 11591, 15803, 2479, 124663, 72631}},
+{14157, 18, 12530, {1, 3, 5, 9, 21, 27, 109, 91, 483, 905, 1369, 2573, 7173, 13977, 20131, 17637, 127477, 66457}},
+{14158, 18, 12532, {1, 1, 5, 7, 31, 17, 43, 153, 505, 413, 867, 769, 6947, 10815, 18805, 5957, 27715, 24529}},
+{14159, 18, 12539, {1, 3, 5, 9, 13, 41, 107, 199, 69, 1019, 2037, 3221, 1081, 15051, 6713, 46379, 17223, 85453}},
+{14160, 18, 12567, {1, 3, 3, 7, 23, 51, 45, 133, 227, 373, 1815, 3795, 5567, 7153, 25003, 64951, 75377, 174115}},
+{14161, 18, 12597, {1, 1, 7, 15, 7, 51, 33, 239, 113, 133, 1213, 327, 4841, 11297, 1093, 40013, 60843, 99845}},
+{14162, 18, 12601, {1, 1, 1, 11, 3, 37, 33, 107, 275, 747, 1451, 1787, 5029, 3101, 11575, 36555, 46181, 221643}},
+{14163, 18, 12602, {1, 1, 3, 3, 29, 53, 57, 67, 209, 153, 345, 2897, 5657, 8907, 14159, 9899, 102487, 237721}},
+{14164, 18, 12622, {1, 3, 1, 7, 7, 59, 17, 151, 423, 903, 2035, 861, 1057, 2399, 28547, 3659, 29583, 100651}},
+{14165, 18, 12693, {1, 1, 5, 15, 27, 53, 101, 17, 405, 869, 1253, 1923, 999, 7787, 23621, 4351, 48611, 47129}},
+{14166, 18, 12707, {1, 3, 7, 11, 13, 43, 61, 161, 43, 831, 2021, 579, 5353, 12451, 32261, 39885, 90051, 34407}},
+{14167, 18, 12713, {1, 1, 1, 5, 25, 19, 37, 33, 37, 59, 1399, 1587, 1517, 4261, 31215, 33777, 50447, 87049}},
+{14168, 18, 12716, {1, 1, 3, 1, 19, 17, 113, 31, 385, 135, 143, 3997, 1365, 2625, 22591, 8887, 31353, 240603}},
+{14169, 18, 12734, {1, 3, 7, 11, 21, 7, 55, 171, 233, 1007, 1321, 2903, 2457, 3941, 19667, 49115, 99119, 185989}},
+{14170, 18, 12763, {1, 3, 7, 9, 3, 31, 83, 99, 303, 443, 99, 2285, 1491, 15897, 21735, 1575, 74449, 59615}},
+{14171, 18, 12765, {1, 3, 1, 5, 29, 37, 125, 213, 277, 115, 255, 137, 6071, 13561, 23871, 48129, 120211, 168603}},
+{14172, 18, 12799, {1, 1, 7, 3, 9, 21, 93, 239, 399, 21, 9, 409, 3403, 9517, 6421, 17121, 65697, 251985}},
+{14173, 18, 12843, {1, 1, 1, 15, 27, 35, 17, 113, 471, 357, 1703, 871, 1803, 3495, 27437, 48343, 86425, 155245}},
+{14174, 18, 12853, {1, 3, 7, 11, 19, 45, 51, 195, 345, 77, 1403, 2527, 3405, 14057, 31965, 17375, 35107, 246545}},
+{14175, 18, 12865, {1, 3, 5, 7, 7, 5, 115, 39, 51, 261, 1883, 1793, 3423, 3613, 20399, 27267, 99875, 119719}},
+{14176, 18, 12866, {1, 3, 3, 9, 21, 23, 65, 69, 261, 79, 151, 3387, 7789, 13275, 30135, 52229, 40787, 181297}},
+{14177, 18, 12919, {1, 1, 5, 13, 19, 49, 111, 125, 433, 99, 1673, 2091, 5447, 9377, 9085, 4659, 75121, 105809}},
+{14178, 18, 12926, {1, 3, 7, 1, 3, 27, 107, 109, 245, 431, 1727, 3269, 2099, 10777, 21843, 63377, 47343, 126269}},
+{14179, 18, 12936, {1, 3, 1, 15, 7, 17, 107, 153, 37, 287, 1873, 573, 5025, 3735, 32545, 35693, 38083, 89569}},
+{14180, 18, 12944, {1, 3, 1, 3, 9, 51, 99, 247, 45, 703, 1231, 1895, 6309, 12137, 14697, 25441, 129701, 198811}},
+{14181, 18, 12959, {1, 3, 3, 11, 5, 43, 1, 31, 359, 563, 1013, 3475, 3935, 7855, 10085, 15279, 25109, 225643}},
+{14182, 18, 12965, {1, 3, 3, 3, 9, 47, 49, 193, 223, 23, 391, 847, 7233, 14955, 10645, 50535, 5415, 119791}},
+{14183, 18, 12980, {1, 3, 1, 7, 3, 7, 57, 189, 219, 287, 401, 1767, 5585, 13983, 18485, 56725, 71905, 33779}},
+{14184, 18, 13004, {1, 3, 5, 15, 23, 17, 115, 223, 35, 263, 345, 3459, 857, 1467, 30255, 50127, 72985, 62509}},
+{14185, 18, 13016, {1, 3, 1, 9, 3, 27, 125, 43, 47, 183, 1421, 319, 4273, 10701, 21761, 23947, 22531, 10855}},
+{14186, 18, 13019, {1, 1, 3, 15, 13, 55, 77, 1, 295, 841, 1115, 4093, 7993, 13309, 24851, 35411, 105201, 188543}},
+{14187, 18, 13037, {1, 3, 3, 5, 19, 39, 101, 19, 225, 997, 1999, 407, 3147, 15393, 30379, 26221, 21685, 114167}},
+{14188, 18, 13055, {1, 3, 3, 3, 23, 15, 3, 57, 45, 381, 47, 1839, 5491, 6775, 18477, 51443, 757, 183111}},
+{14189, 18, 13063, {1, 3, 3, 7, 31, 27, 107, 229, 1, 977, 125, 1137, 4873, 14381, 8705, 64641, 38447, 239887}},
+{14190, 18, 13098, {1, 1, 3, 13, 9, 35, 49, 187, 459, 407, 1677, 2007, 1091, 12385, 8911, 38221, 108681, 171641}},
+{14191, 18, 13103, {1, 1, 3, 5, 7, 61, 115, 155, 437, 829, 1041, 2191, 1489, 1269, 27613, 48713, 40095, 206057}},
+{14192, 18, 13106, {1, 3, 7, 1, 23, 1, 17, 215, 363, 119, 845, 987, 5619, 5857, 11307, 63171, 76921, 201767}},
+{14193, 18, 13115, {1, 1, 7, 9, 29, 23, 63, 247, 37, 199, 103, 1215, 913, 12865, 24089, 35101, 117677, 261393}},
+{14194, 18, 13143, {1, 1, 1, 1, 3, 19, 7, 159, 183, 275, 467, 3629, 6575, 3351, 26955, 29247, 119007, 67895}},
+{14195, 18, 13144, {1, 1, 7, 13, 1, 33, 31, 211, 103, 495, 417, 817, 7129, 10169, 11445, 41511, 73101, 185357}},
+{14196, 18, 13153, {1, 1, 3, 5, 3, 27, 99, 1, 425, 295, 131, 835, 1833, 4547, 8777, 29489, 60303, 191437}},
+{14197, 18, 13171, {1, 1, 5, 5, 31, 63, 71, 189, 317, 61, 385, 891, 2257, 8281, 17325, 12207, 125847, 28259}},
+{14198, 18, 13184, {1, 1, 3, 3, 19, 19, 97, 83, 495, 551, 1339, 1699, 3047, 13623, 27731, 28999, 101225, 146139}},
+{14199, 18, 13193, {1, 3, 5, 7, 25, 9, 37, 73, 239, 47, 583, 3337, 1329, 79, 30109, 12451, 10163, 62943}},
+{14200, 18, 13199, {1, 1, 3, 1, 9, 1, 31, 181, 231, 441, 1241, 233, 6049, 2401, 9867, 58911, 20599, 26321}},
+{14201, 18, 13207, {1, 3, 1, 15, 21, 43, 21, 43, 273, 865, 79, 2069, 3375, 16069, 12355, 56355, 9735, 243719}},
+{14202, 18, 13217, {1, 3, 5, 11, 13, 21, 5, 73, 423, 761, 1947, 2935, 3931, 5573, 83, 58251, 113115, 245767}},
+{14203, 18, 13227, {1, 3, 7, 7, 15, 49, 73, 211, 309, 635, 1257, 2185, 7151, 11959, 26885, 45955, 103503, 161709}},
+{14204, 18, 13232, {1, 3, 1, 15, 31, 53, 29, 35, 343, 87, 1833, 2483, 1847, 4709, 6105, 21961, 106541, 46741}},
+{14205, 18, 13276, {1, 1, 7, 7, 21, 43, 41, 51, 29, 521, 713, 3693, 483, 11777, 10453, 43691, 97585, 133193}},
+{14206, 18, 13283, {1, 3, 3, 11, 5, 45, 3, 179, 183, 255, 1291, 1795, 5721, 10911, 18395, 64349, 23141, 99481}},
+{14207, 18, 13307, {1, 1, 1, 5, 5, 25, 61, 169, 475, 953, 617, 559, 5945, 16377, 30063, 30079, 83305, 81745}},
+{14208, 18, 13317, {1, 1, 5, 11, 29, 59, 113, 37, 153, 807, 135, 2639, 4535, 7079, 6387, 63523, 89669, 198803}},
+{14209, 18, 13330, {1, 1, 7, 7, 19, 23, 71, 51, 165, 733, 1427, 2473, 331, 5027, 9299, 20617, 126775, 91619}},
+{14210, 18, 13345, {1, 3, 5, 7, 31, 35, 117, 235, 29, 677, 1243, 281, 6287, 535, 4783, 37781, 130929, 14193}},
+{14211, 18, 13363, {1, 1, 5, 3, 25, 1, 29, 109, 289, 631, 41, 361, 5537, 9657, 7475, 63749, 50325, 169791}},
+{14212, 18, 13387, {1, 3, 3, 15, 21, 53, 85, 43, 341, 907, 475, 3257, 2541, 10397, 30847, 63681, 121427, 192135}},
+{14213, 18, 13426, {1, 1, 1, 1, 9, 59, 59, 233, 335, 345, 1749, 4007, 1833, 7789, 21015, 48939, 15967, 201321}},
+{14214, 18, 13428, {1, 1, 1, 5, 11, 9, 101, 243, 391, 1003, 1019, 311, 3707, 10223, 21627, 8237, 53861, 159785}},
+{14215, 18, 13431, {1, 3, 7, 15, 5, 3, 109, 197, 507, 947, 833, 1161, 4021, 5575, 8081, 45381, 112597, 70407}},
+{14216, 18, 13489, {1, 1, 3, 1, 7, 63, 63, 53, 481, 1003, 43, 2503, 2303, 12593, 21403, 2965, 5377, 91491}},
+{14217, 18, 13501, {1, 1, 1, 1, 29, 45, 49, 73, 253, 197, 1245, 1509, 4747, 6207, 28321, 59193, 112687, 83719}},
+{14218, 18, 13533, {1, 1, 7, 3, 11, 51, 23, 83, 185, 643, 1427, 227, 2261, 12521, 27033, 5129, 53111, 34975}},
+{14219, 18, 13589, {1, 1, 7, 3, 5, 41, 55, 175, 447, 603, 723, 2141, 1189, 4921, 16905, 2463, 83641, 247241}},
+{14220, 18, 13600, {1, 3, 3, 13, 5, 11, 95, 59, 391, 319, 1675, 329, 7559, 11585, 28905, 27843, 106667, 15531}},
+{14221, 18, 13603, {1, 3, 3, 3, 27, 17, 103, 115, 447, 657, 267, 2541, 665, 7819, 4155, 32191, 60999, 48737}},
+{14222, 18, 13623, {1, 1, 5, 7, 7, 49, 87, 171, 457, 149, 1699, 4081, 3913, 7889, 29517, 3339, 33139, 8925}},
+{14223, 18, 13665, {1, 1, 1, 9, 11, 51, 87, 115, 429, 505, 1665, 2361, 5811, 1621, 12727, 33703, 52255, 93835}},
+{14224, 18, 13672, {1, 3, 3, 5, 27, 11, 35, 49, 281, 607, 1791, 4065, 5103, 5253, 975, 20353, 38253, 139363}},
+{14225, 18, 13675, {1, 1, 5, 9, 29, 15, 37, 141, 445, 751, 1219, 2217, 7207, 14981, 21113, 3313, 107127, 135567}},
+{14226, 18, 13708, {1, 3, 3, 15, 1, 41, 23, 27, 167, 609, 913, 631, 923, 6939, 9793, 57869, 126577, 145271}},
+{14227, 18, 13713, {1, 1, 3, 7, 27, 47, 127, 5, 213, 575, 559, 2541, 3457, 2903, 19529, 53395, 105353, 212607}},
+{14228, 18, 13720, {1, 3, 1, 13, 27, 41, 31, 111, 371, 1019, 241, 2075, 2571, 10739, 28163, 16093, 41127, 69783}},
+{14229, 18, 13730, {1, 1, 5, 1, 21, 9, 15, 141, 287, 675, 1721, 2291, 6587, 7503, 6363, 9109, 33547, 259627}},
+{14230, 18, 13735, {1, 3, 7, 3, 3, 53, 7, 153, 183, 761, 191, 3735, 2619, 11153, 19601, 33855, 82345, 72755}},
+{14231, 18, 13767, {1, 3, 1, 9, 19, 21, 41, 105, 281, 833, 981, 2733, 7179, 14691, 18365, 56283, 53719, 191601}},
+{14232, 18, 13773, {1, 1, 7, 11, 23, 1, 55, 213, 105, 517, 809, 4087, 825, 7011, 15701, 54047, 123831, 49833}},
+{14233, 18, 13792, {1, 1, 7, 13, 27, 9, 111, 57, 357, 95, 1489, 887, 5273, 2833, 8757, 9371, 44637, 94939}},
+{14234, 18, 13843, {1, 1, 3, 5, 1, 17, 43, 31, 509, 353, 401, 1077, 7567, 9657, 15065, 32017, 8491, 214477}},
+{14235, 18, 13891, {1, 1, 1, 15, 7, 59, 41, 99, 101, 845, 1479, 2153, 4281, 12839, 237, 54095, 125873, 57165}},
+{14236, 18, 13946, {1, 3, 7, 13, 5, 17, 1, 249, 309, 351, 709, 3943, 7775, 6449, 26611, 54019, 121015, 213535}},
+{14237, 18, 13967, {1, 1, 1, 5, 7, 25, 33, 149, 291, 777, 161, 2729, 117, 4999, 16781, 23383, 85161, 71689}},
+{14238, 18, 13976, {1, 1, 3, 11, 5, 63, 119, 165, 45, 135, 1723, 811, 1259, 11055, 28625, 37559, 128401, 100715}},
+{14239, 18, 14017, {1, 3, 7, 1, 1, 39, 11, 255, 423, 289, 1359, 2827, 4637, 4089, 26659, 58701, 117403, 133971}},
+{14240, 18, 14030, {1, 1, 7, 1, 25, 9, 127, 121, 147, 831, 17, 3521, 1535, 10931, 17305, 56671, 22425, 157341}},
+{14241, 18, 14041, {1, 3, 1, 15, 5, 55, 95, 95, 169, 497, 739, 2031, 339, 13461, 20619, 24553, 81805, 90789}},
+{14242, 18, 14054, {1, 1, 7, 7, 7, 19, 15, 203, 287, 673, 1033, 3857, 2761, 10835, 11039, 62329, 37893, 6119}},
+{14243, 18, 14058, {1, 1, 3, 11, 19, 35, 55, 9, 399, 443, 583, 89, 2387, 747, 9551, 9907, 96871, 175457}},
+{14244, 18, 14060, {1, 1, 3, 1, 11, 57, 121, 89, 491, 133, 545, 683, 5751, 839, 25975, 44725, 59863, 142671}},
+{14245, 18, 14063, {1, 1, 3, 1, 23, 1, 111, 177, 1, 103, 1933, 2783, 6857, 51, 14547, 5945, 14757, 39783}},
+{14246, 18, 14078, {1, 3, 7, 13, 25, 13, 51, 247, 325, 361, 1225, 15, 1929, 1729, 25293, 59495, 82111, 101809}},
+{14247, 18, 14080, {1, 3, 3, 1, 19, 37, 67, 85, 105, 589, 1273, 2995, 8017, 1613, 22189, 2549, 22671, 72813}},
+{14248, 18, 14089, {1, 3, 7, 9, 15, 41, 25, 43, 411, 663, 387, 2861, 3627, 5839, 733, 53479, 76241, 116763}},
+{14249, 18, 14131, {1, 3, 3, 3, 17, 5, 73, 153, 133, 247, 881, 2853, 6059, 2259, 10181, 63251, 107089, 22579}},
+{14250, 18, 14134, {1, 3, 1, 5, 11, 15, 17, 235, 23, 15, 521, 235, 4137, 12705, 24775, 18197, 56295, 28035}},
+{14251, 18, 14137, {1, 3, 5, 5, 13, 9, 77, 69, 19, 755, 1663, 1499, 1049, 12935, 28835, 55413, 71511, 221223}},
+{14252, 18, 14188, {1, 1, 1, 1, 27, 31, 21, 39, 197, 519, 1621, 3703, 2541, 8865, 21947, 53605, 114551, 205697}},
+{14253, 18, 14215, {1, 1, 1, 13, 11, 53, 41, 245, 495, 275, 385, 3071, 1913, 11135, 8571, 58551, 39049, 5459}},
+{14254, 18, 14222, {1, 3, 5, 5, 11, 63, 25, 173, 57, 441, 1749, 79, 3191, 7733, 13111, 23453, 118399, 101845}},
+{14255, 18, 14249, {1, 1, 3, 11, 29, 25, 119, 39, 65, 623, 517, 1325, 5981, 8381, 32031, 25585, 105537, 214241}},
+{14256, 18, 14292, {1, 3, 5, 9, 21, 43, 13, 69, 109, 311, 1893, 1941, 2491, 7815, 4067, 56749, 33761, 191145}},
+{14257, 18, 14320, {1, 1, 1, 7, 9, 5, 123, 149, 65, 729, 1967, 3089, 3757, 2333, 24587, 36047, 118105, 146277}},
+{14258, 18, 14339, {1, 3, 7, 13, 9, 35, 39, 219, 161, 93, 275, 3619, 353, 14595, 24673, 54753, 117175, 81891}},
+{14259, 18, 14346, {1, 3, 3, 13, 15, 61, 95, 135, 271, 595, 1103, 877, 747, 2535, 7733, 25509, 65673, 62089}},
+{14260, 18, 14353, {1, 3, 3, 5, 21, 21, 67, 5, 373, 377, 61, 2337, 489, 5801, 23203, 42377, 7801, 178095}},
+{14261, 18, 14365, {1, 1, 7, 5, 25, 17, 61, 133, 181, 261, 1627, 1615, 6851, 4763, 30353, 53349, 7545, 66733}},
+{14262, 18, 14384, {1, 3, 5, 7, 29, 3, 85, 231, 121, 669, 1925, 403, 777, 10605, 24125, 60819, 8253, 81209}},
+{14263, 18, 14414, {1, 1, 5, 3, 5, 5, 1, 53, 9, 445, 1339, 2643, 5527, 13757, 9409, 31993, 80845, 97863}},
+{14264, 18, 14428, {1, 1, 7, 13, 29, 49, 97, 89, 319, 349, 1739, 3615, 1113, 11791, 17429, 37195, 1159, 32211}},
+{14265, 18, 14435, {1, 3, 5, 11, 9, 61, 109, 167, 119, 499, 1157, 3615, 5773, 8839, 27915, 47837, 14945, 187225}},
+{14266, 18, 14483, {1, 1, 5, 1, 9, 3, 7, 179, 323, 279, 43, 1337, 4813, 9917, 2033, 34657, 130769, 208089}},
+{14267, 18, 14486, {1, 1, 3, 1, 31, 57, 57, 73, 21, 661, 1861, 1661, 7619, 12155, 23123, 49751, 130697, 74143}},
+{14268, 18, 14506, {1, 3, 3, 13, 11, 61, 95, 75, 227, 491, 463, 597, 2721, 12323, 26195, 53657, 44413, 68965}},
+{14269, 18, 14513, {1, 1, 7, 11, 5, 51, 103, 123, 203, 911, 203, 1641, 7009, 9479, 303, 37649, 32751, 172777}},
+{14270, 18, 14520, {1, 1, 3, 7, 11, 59, 111, 5, 271, 863, 269, 3457, 489, 10877, 8645, 62567, 24893, 201587}},
+{14271, 18, 14526, {1, 1, 5, 7, 29, 23, 127, 151, 371, 121, 1103, 3951, 3107, 15563, 6243, 1631, 75065, 107681}},
+{14272, 18, 14528, {1, 1, 7, 15, 27, 45, 43, 83, 461, 673, 715, 3245, 313, 13731, 21981, 58853, 46569, 165463}},
+{14273, 18, 14533, {1, 1, 1, 9, 7, 53, 63, 43, 3, 187, 1325, 447, 5113, 4993, 21807, 24329, 4499, 30067}},
+{14274, 18, 14576, {1, 3, 1, 9, 21, 45, 111, 231, 407, 213, 1977, 2269, 2323, 4595, 30427, 54753, 95049, 195409}},
+{14275, 18, 14599, {1, 1, 1, 9, 29, 43, 89, 201, 499, 329, 847, 3831, 5403, 13001, 6037, 14371, 25805, 169237}},
+{14276, 18, 14613, {1, 1, 1, 11, 29, 61, 61, 203, 91, 189, 1603, 939, 6575, 3195, 4731, 44923, 33627, 21683}},
+{14277, 18, 14639, {1, 3, 3, 11, 7, 57, 93, 181, 479, 99, 681, 2875, 7649, 5555, 27087, 6841, 69859, 153689}},
+{14278, 18, 14644, {1, 1, 1, 9, 17, 45, 97, 47, 91, 879, 1463, 3041, 2917, 769, 13675, 26489, 88559, 120991}},
+{14279, 18, 14653, {1, 3, 7, 1, 11, 13, 43, 9, 483, 399, 793, 3965, 2375, 4957, 17747, 50905, 56987, 231265}},
+{14280, 18, 14662, {1, 3, 3, 13, 23, 45, 69, 67, 397, 437, 1993, 2569, 8035, 8531, 27623, 53567, 123189, 242515}},
+{14281, 18, 14695, {1, 1, 1, 3, 5, 9, 21, 227, 499, 205, 431, 3711, 5307, 15773, 11337, 6349, 123507, 95941}},
+{14282, 18, 14704, {1, 3, 7, 1, 13, 15, 101, 91, 209, 611, 537, 1427, 101, 2619, 10513, 44323, 92745, 249127}},
+{14283, 18, 14713, {1, 3, 3, 1, 21, 7, 79, 241, 273, 567, 605, 2371, 5427, 15147, 20139, 40987, 75551, 236213}},
+{14284, 18, 14725, {1, 1, 7, 11, 25, 19, 77, 209, 313, 663, 115, 3697, 3641, 12461, 9877, 18331, 70809, 78923}},
+{14285, 18, 14783, {1, 1, 5, 5, 29, 45, 7, 207, 1, 357, 1089, 3861, 4161, 3209, 27845, 20947, 68909, 125179}},
+{14286, 18, 14810, {1, 3, 1, 13, 17, 11, 27, 165, 179, 489, 1611, 2801, 2385, 2971, 6777, 16149, 59811, 151043}},
+{14287, 18, 14816, {1, 1, 3, 3, 17, 53, 121, 227, 7, 71, 1855, 639, 5135, 6349, 7163, 22997, 112551, 44167}},
+{14288, 18, 14822, {1, 3, 1, 11, 15, 9, 125, 213, 485, 291, 1781, 3621, 7529, 13353, 13903, 24151, 130253, 187097}},
+{14289, 18, 14828, {1, 3, 1, 3, 1, 61, 39, 157, 455, 945, 739, 589, 7259, 7149, 16455, 12649, 72003, 152419}},
+{14290, 18, 14883, {1, 1, 3, 3, 31, 23, 17, 255, 319, 907, 563, 2571, 2149, 15323, 20289, 46061, 32769, 184353}},
+{14291, 18, 14889, {1, 3, 7, 9, 21, 51, 27, 13, 495, 909, 2039, 1435, 4791, 10037, 30119, 3405, 22535, 42247}},
+{14292, 18, 14904, {1, 1, 3, 15, 11, 25, 123, 149, 185, 635, 473, 527, 433, 10373, 18205, 853, 94619, 202507}},
+{14293, 18, 14917, {1, 1, 7, 15, 7, 39, 7, 69, 157, 533, 369, 4031, 1335, 4279, 8049, 28491, 103753, 257477}},
+{14294, 18, 14927, {1, 3, 1, 15, 29, 51, 113, 77, 5, 961, 1863, 1477, 5009, 9519, 32029, 2367, 55705, 149597}},
+{14295, 18, 14941, {1, 3, 1, 5, 19, 43, 49, 107, 59, 693, 867, 3011, 2703, 3633, 24567, 52621, 35839, 134823}},
+{14296, 18, 14946, {1, 3, 3, 7, 19, 15, 81, 105, 23, 375, 451, 3017, 1263, 7589, 24453, 21885, 57651, 52613}},
+{14297, 18, 14952, {1, 1, 3, 7, 3, 59, 19, 1, 3, 243, 1891, 2041, 4707, 15557, 28885, 5959, 22517, 237131}},
+{14298, 18, 15010, {1, 3, 7, 11, 25, 33, 105, 15, 245, 247, 1357, 1255, 7463, 4815, 13727, 41687, 112425, 58827}},
+{14299, 18, 15012, {1, 1, 7, 1, 19, 31, 37, 201, 217, 127, 927, 763, 6359, 9951, 2581, 49171, 104305, 215923}},
+{14300, 18, 15033, {1, 1, 7, 7, 13, 9, 9, 139, 363, 85, 1703, 3615, 2545, 15991, 20677, 12109, 54951, 2171}},
+{14301, 18, 15041, {1, 3, 1, 13, 27, 3, 37, 195, 185, 829, 815, 1621, 2917, 8643, 29071, 45523, 38475, 243505}},
+{14302, 18, 15047, {1, 1, 7, 3, 19, 29, 91, 85, 331, 231, 1609, 2583, 1091, 4191, 29929, 55377, 105077, 168425}},
+{14303, 18, 15066, {1, 1, 5, 3, 29, 35, 3, 61, 389, 339, 705, 473, 2075, 7373, 9699, 38809, 60415, 66423}},
+{14304, 18, 15068, {1, 3, 1, 5, 17, 25, 17, 37, 335, 787, 1891, 1861, 4325, 12721, 9675, 13671, 18655, 235443}},
+{14305, 18, 15072, {1, 3, 3, 5, 23, 13, 83, 191, 263, 325, 1847, 1717, 7089, 15709, 26567, 44489, 66523, 3107}},
+{14306, 18, 15095, {1, 3, 7, 7, 25, 29, 63, 55, 9, 481, 899, 669, 5481, 11227, 1637, 17017, 124509, 102775}},
+{14307, 18, 15150, {1, 1, 1, 5, 21, 41, 101, 93, 129, 1023, 561, 2969, 1525, 2929, 32729, 54513, 4359, 28745}},
+{14308, 18, 15152, {1, 1, 5, 13, 15, 13, 79, 9, 257, 535, 861, 2703, 6161, 6659, 10369, 7, 117467, 146651}},
+{14309, 18, 15175, {1, 1, 3, 13, 31, 11, 43, 95, 441, 921, 1323, 343, 5339, 13149, 19643, 24253, 32055, 180327}},
+{14310, 18, 15176, {1, 1, 5, 15, 11, 27, 109, 149, 255, 1021, 249, 1913, 5213, 301, 9939, 49779, 26097, 66007}},
+{14311, 18, 15210, {1, 3, 1, 11, 15, 33, 53, 159, 433, 167, 1107, 3577, 6231, 8309, 28125, 55381, 127309, 14459}},
+{14312, 18, 15245, {1, 3, 5, 9, 7, 3, 45, 139, 133, 359, 537, 805, 3931, 5181, 915, 63317, 86227, 231573}},
+{14313, 18, 15258, {1, 1, 1, 3, 11, 31, 97, 127, 117, 151, 711, 2457, 2777, 3855, 21829, 7913, 30785, 141449}},
+{14314, 18, 15263, {1, 3, 7, 13, 11, 17, 65, 63, 289, 851, 1929, 4021, 105, 5207, 17085, 64119, 48659, 31687}},
+{14315, 18, 15264, {1, 1, 7, 11, 31, 57, 63, 251, 341, 727, 505, 1851, 783, 16191, 9335, 39421, 14793, 238215}},
+{14316, 18, 15279, {1, 3, 3, 11, 23, 13, 119, 195, 117, 579, 693, 3059, 2967, 12791, 26905, 28527, 13393, 11869}},
+{14317, 18, 15301, {1, 3, 7, 11, 23, 7, 61, 143, 409, 309, 651, 3321, 4027, 1351, 10339, 18451, 18447, 235665}},
+{14318, 18, 15306, {1, 1, 1, 9, 13, 21, 7, 65, 103, 789, 973, 475, 2831, 13337, 18989, 40573, 105375, 2221}},
+{14319, 18, 15313, {1, 3, 5, 15, 3, 59, 115, 61, 365, 653, 523, 3927, 8175, 6751, 32561, 55919, 64903, 139005}},
+{14320, 18, 15329, {1, 3, 3, 13, 1, 7, 51, 63, 179, 525, 1899, 373, 3797, 6329, 5539, 32669, 65903, 154993}},
+{14321, 18, 15341, {1, 3, 1, 1, 31, 53, 87, 39, 317, 71, 1899, 925, 4719, 11645, 27125, 50391, 116491, 219271}},
+{14322, 18, 15367, {1, 3, 7, 13, 7, 23, 1, 57, 333, 277, 893, 3245, 1417, 13115, 21835, 25879, 91305, 54691}},
+{14323, 18, 15368, {1, 3, 1, 11, 27, 5, 109, 69, 221, 453, 299, 517, 609, 11959, 27789, 33107, 46559, 121673}},
+{14324, 18, 15386, {1, 3, 5, 7, 27, 7, 119, 169, 129, 643, 173, 2479, 6163, 11159, 11897, 57153, 11347, 135337}},
+{14325, 18, 15404, {1, 1, 5, 13, 13, 59, 21, 13, 429, 601, 267, 1635, 2579, 12053, 31583, 14847, 78187, 217099}},
+{14326, 18, 15422, {1, 3, 5, 9, 5, 3, 125, 159, 411, 15, 479, 933, 6307, 9707, 23491, 6501, 70993, 161365}},
+{14327, 18, 15436, {1, 1, 7, 7, 3, 33, 87, 177, 283, 825, 1935, 1545, 7071, 9975, 1795, 48277, 115725, 173439}},
+{14328, 18, 15444, {1, 3, 3, 9, 19, 63, 17, 119, 13, 337, 2021, 2221, 3237, 3253, 18661, 15479, 59377, 76095}},
+{14329, 18, 15467, {1, 1, 1, 11, 17, 15, 93, 249, 333, 171, 575, 3251, 5413, 3587, 22807, 29273, 56461, 97801}},
+{14330, 18, 15498, {1, 3, 3, 11, 13, 7, 27, 167, 389, 693, 1473, 555, 1603, 3167, 3985, 3841, 100283, 195253}},
+{14331, 18, 15503, {1, 3, 7, 1, 23, 7, 89, 231, 85, 797, 1935, 2557, 4365, 2221, 21069, 44055, 77723, 226547}},
+{14332, 18, 15528, {1, 3, 1, 5, 5, 49, 47, 187, 71, 903, 1279, 3219, 8041, 10915, 5249, 17755, 80077, 3479}},
+{14333, 18, 15534, {1, 1, 3, 13, 5, 53, 35, 25, 183, 791, 1651, 1041, 1221, 2171, 26221, 20649, 126851, 163047}},
+{14334, 18, 15536, {1, 1, 5, 9, 29, 3, 75, 31, 385, 293, 171, 3023, 2075, 14541, 30879, 13895, 67637, 87831}},
+{14335, 18, 15559, {1, 3, 5, 7, 3, 41, 115, 213, 23, 895, 361, 27, 5839, 12447, 13829, 29183, 106539, 134891}},
+{14336, 18, 15565, {1, 3, 7, 7, 11, 39, 99, 229, 195, 633, 837, 3697, 1161, 15119, 20831, 27371, 92195, 26993}},
+{14337, 18, 15583, {1, 1, 5, 9, 25, 17, 5, 169, 475, 73, 1451, 2057, 3671, 12801, 9671, 57427, 25321, 154969}},
+{14338, 18, 15599, {1, 3, 5, 11, 25, 23, 9, 145, 341, 339, 1855, 981, 8041, 569, 19851, 29521, 21767, 136505}},
+{14339, 18, 15602, {1, 1, 1, 1, 3, 9, 101, 253, 475, 529, 387, 1893, 5509, 5763, 29555, 13307, 30001, 105057}},
+{14340, 18, 15616, {1, 3, 3, 5, 17, 23, 127, 161, 375, 817, 1229, 1197, 1097, 3053, 14351, 21213, 12501, 137397}},
+{14341, 18, 15626, {1, 1, 1, 9, 7, 1, 57, 185, 281, 65, 181, 2483, 4739, 4353, 29837, 40613, 32489, 23317}},
+{14342, 18, 15667, {1, 1, 3, 9, 5, 35, 43, 191, 409, 95, 537, 2465, 515, 1633, 20887, 32535, 43863, 199885}},
+{14343, 18, 15684, {1, 3, 3, 13, 19, 49, 41, 51, 3, 979, 1623, 3323, 7711, 3707, 29417, 58011, 114467, 227499}},
+{14344, 18, 15711, {1, 1, 1, 11, 21, 7, 23, 51, 39, 25, 1971, 213, 369, 9149, 12845, 57631, 16597, 22031}},
+{14345, 18, 15745, {1, 3, 3, 11, 27, 59, 71, 37, 461, 353, 2041, 1961, 4643, 6953, 18129, 60337, 82769, 20819}},
+{14346, 18, 15763, {1, 1, 3, 11, 25, 19, 17, 5, 503, 227, 2021, 733, 2867, 201, 25779, 49811, 81167, 95437}},
+{14347, 18, 15779, {1, 3, 3, 15, 7, 53, 35, 143, 27, 937, 215, 3249, 4151, 1933, 25267, 18047, 35131, 25903}},
+{14348, 18, 15811, {1, 1, 1, 3, 3, 39, 71, 99, 291, 97, 1389, 3803, 2881, 9765, 11277, 20071, 15133, 37349}},
+{14349, 18, 15814, {1, 1, 7, 11, 9, 55, 1, 241, 391, 935, 1555, 3585, 1807, 10057, 2633, 14023, 14409, 199643}},
+{14350, 18, 15817, {1, 3, 3, 3, 19, 9, 57, 237, 107, 869, 147, 2673, 5271, 8999, 20723, 63017, 75989, 20131}},
+{14351, 18, 15853, {1, 3, 3, 3, 25, 11, 61, 77, 119, 657, 2011, 3489, 7835, 4473, 2531, 65231, 104797, 161443}},
+{14352, 18, 15881, {1, 1, 5, 5, 11, 63, 25, 93, 181, 797, 367, 3357, 5291, 5087, 28661, 34093, 75195, 165345}},
+{14353, 18, 15890, {1, 1, 1, 7, 17, 1, 77, 149, 59, 633, 1551, 1305, 7677, 8671, 17457, 64037, 104451, 112387}},
+{14354, 18, 15899, {1, 3, 1, 1, 15, 33, 37, 187, 247, 261, 1101, 3451, 7747, 12197, 22465, 30589, 12573, 204517}},
+{14355, 18, 15905, {1, 3, 3, 11, 3, 39, 71, 139, 145, 139, 101, 2815, 3457, 14033, 4531, 42133, 54147, 71259}},
+{14356, 18, 15915, {1, 3, 1, 1, 23, 37, 19, 113, 443, 57, 439, 2929, 3835, 5431, 11189, 4539, 72531, 124453}},
+{14357, 18, 15937, {1, 3, 3, 5, 3, 17, 21, 217, 41, 665, 1565, 3753, 5289, 9789, 29205, 16453, 88979, 171387}},
+{14358, 18, 15950, {1, 3, 3, 13, 27, 15, 15, 223, 231, 311, 311, 1143, 8113, 13863, 3191, 51103, 109437, 245557}},
+{14359, 18, 16002, {1, 1, 3, 13, 11, 59, 7, 191, 477, 683, 353, 2845, 7623, 9035, 453, 48429, 40111, 162859}},
+{14360, 18, 16041, {1, 3, 7, 5, 29, 37, 55, 59, 259, 851, 861, 1951, 7847, 8537, 30107, 2999, 59137, 155615}},
+{14361, 18, 16042, {1, 3, 7, 11, 3, 13, 73, 147, 393, 327, 1289, 37, 795, 1413, 19215, 28345, 124301, 23135}},
+{14362, 18, 16052, {1, 1, 5, 11, 29, 17, 107, 69, 433, 845, 1351, 2551, 807, 15315, 15511, 39475, 84879, 129405}},
+{14363, 18, 16121, {1, 3, 3, 9, 15, 3, 23, 5, 211, 871, 689, 2319, 39, 2215, 25171, 43169, 113715, 186049}},
+{14364, 18, 16132, {1, 1, 3, 7, 3, 37, 23, 9, 453, 649, 373, 1273, 1539, 6221, 27469, 44675, 13513, 131179}},
+{14365, 18, 16136, {1, 3, 1, 5, 29, 41, 119, 133, 37, 761, 1193, 2311, 4945, 7337, 17027, 12873, 51489, 160633}},
+{14366, 18, 16150, {1, 3, 1, 3, 21, 63, 75, 115, 105, 223, 933, 445, 5789, 4611, 13609, 2873, 16679, 222895}},
+{14367, 18, 16153, {1, 1, 7, 5, 17, 13, 15, 217, 193, 863, 1319, 2337, 3055, 14879, 8669, 5705, 42965, 166443}},
+{14368, 18, 16180, {1, 1, 7, 11, 3, 55, 57, 131, 289, 843, 1693, 881, 6737, 5557, 18365, 12393, 38479, 189177}},
+{14369, 18, 16190, {1, 1, 3, 5, 3, 59, 13, 123, 397, 479, 79, 569, 535, 2529, 26225, 43475, 76925, 187763}},
+{14370, 18, 16192, {1, 1, 5, 15, 15, 37, 1, 97, 489, 331, 1499, 1759, 3621, 5373, 1425, 6477, 45805, 235511}},
+{14371, 18, 16195, {1, 3, 1, 3, 7, 51, 55, 157, 61, 751, 1881, 4093, 2557, 11129, 23239, 16335, 8949, 205007}},
+{14372, 18, 16210, {1, 1, 1, 1, 13, 21, 67, 141, 85, 1023, 223, 747, 1951, 10279, 6399, 49887, 100437, 76757}},
+{14373, 18, 16225, {1, 1, 3, 11, 1, 51, 29, 33, 173, 769, 879, 2883, 417, 15031, 13377, 63919, 118803, 87969}},
+{14374, 18, 16256, {1, 1, 1, 5, 1, 1, 17, 153, 81, 691, 961, 3399, 5005, 10617, 18467, 13775, 34905, 241349}},
+{14375, 18, 16266, {1, 1, 1, 13, 7, 37, 57, 187, 389, 575, 1827, 2017, 4541, 10513, 23409, 30945, 126855, 239657}},
+{14376, 18, 16274, {1, 1, 5, 5, 17, 41, 83, 177, 285, 695, 29, 1653, 953, 6377, 13571, 58663, 9265, 100759}},
+{14377, 18, 16302, {1, 3, 5, 3, 5, 13, 27, 153, 207, 699, 1805, 947, 979, 2719, 389, 61953, 16991, 160073}},
+{14378, 18, 16310, {1, 1, 7, 13, 17, 37, 113, 185, 239, 455, 1557, 3201, 1111, 4875, 23197, 41883, 70507, 255047}},
+{14379, 18, 16322, {1, 3, 5, 11, 9, 51, 47, 137, 413, 1015, 259, 1829, 6043, 11757, 22317, 15155, 107827, 171003}},
+{14380, 18, 16339, {1, 1, 1, 13, 27, 7, 49, 91, 285, 13, 2007, 3469, 1223, 2483, 16155, 8413, 10529, 224195}},
+{14381, 18, 16345, {1, 1, 7, 3, 9, 49, 119, 81, 331, 187, 1695, 1729, 533, 6359, 7053, 34665, 37541, 100225}},
+{14382, 18, 16348, {1, 3, 7, 1, 7, 35, 115, 91, 479, 515, 1249, 121, 2885, 16383, 1777, 44205, 86459, 255885}},
+{14383, 18, 16357, {1, 1, 7, 13, 13, 27, 11, 49, 221, 829, 1787, 2889, 3875, 1679, 25333, 1323, 9813, 189373}},
+{14384, 18, 16382, {1, 3, 7, 5, 31, 5, 117, 77, 209, 619, 191, 2969, 2221, 15339, 11461, 64201, 130461, 204467}},
+{14385, 18, 16402, {1, 3, 1, 1, 29, 5, 91, 31, 313, 901, 1501, 2837, 3615, 7765, 341, 13873, 21663, 260637}},
+{14386, 18, 16461, {1, 1, 1, 9, 1, 41, 97, 15, 141, 901, 1309, 3341, 4871, 16033, 12343, 1555, 94989, 78295}},
+{14387, 18, 16469, {1, 1, 7, 3, 3, 15, 1, 29, 445, 59, 475, 3033, 4227, 3219, 6093, 58953, 92179, 49343}},
+{14388, 18, 16474, {1, 1, 5, 3, 27, 25, 109, 13, 219, 983, 131, 2517, 1161, 16063, 32737, 6077, 91183, 37457}},
+{14389, 18, 16483, {1, 3, 3, 1, 3, 1, 85, 147, 17, 543, 1475, 3873, 3719, 2737, 30977, 15953, 66077, 258979}},
+{14390, 18, 16497, {1, 3, 5, 1, 29, 9, 21, 51, 5, 985, 1177, 3287, 2183, 7301, 13713, 53403, 38439, 195863}},
+{14391, 18, 16523, {1, 1, 7, 15, 31, 53, 47, 173, 477, 439, 751, 1019, 3371, 9319, 17995, 29029, 90657, 209277}},
+{14392, 18, 16534, {1, 1, 5, 5, 17, 5, 59, 115, 375, 231, 1891, 1321, 3639, 16117, 32639, 28793, 68213, 41091}},
+{14393, 18, 16550, {1, 3, 5, 11, 17, 15, 13, 11, 459, 767, 849, 1407, 6611, 6409, 21515, 63175, 127155, 171959}},
+{14394, 18, 16564, {1, 1, 5, 1, 17, 49, 61, 161, 399, 137, 845, 2673, 2431, 15343, 389, 42337, 23031, 94811}},
+{14395, 18, 16582, {1, 1, 1, 9, 21, 23, 75, 177, 351, 197, 1619, 2443, 6829, 3773, 16399, 31949, 44975, 221363}},
+{14396, 18, 16591, {1, 1, 3, 1, 11, 19, 103, 61, 135, 863, 1427, 2657, 4553, 1277, 20249, 3973, 25467, 18847}},
+{14397, 18, 16609, {1, 3, 3, 13, 17, 31, 19, 163, 323, 195, 603, 4069, 3181, 12069, 22117, 44229, 23585, 202785}},
+{14398, 18, 16642, {1, 1, 7, 5, 17, 3, 77, 111, 491, 829, 1375, 2829, 5599, 14057, 21387, 52345, 108281, 211285}},
+{14399, 18, 16648, {1, 3, 3, 1, 17, 43, 71, 13, 321, 393, 1803, 727, 5101, 13485, 8693, 60505, 13893, 3467}},
+{14400, 18, 16656, {1, 1, 5, 1, 23, 31, 121, 15, 215, 215, 1113, 3335, 7431, 4863, 31429, 49903, 59403, 60797}},
+{14401, 18, 16662, {1, 3, 3, 9, 21, 43, 61, 171, 361, 323, 1895, 3647, 729, 8809, 9351, 14573, 93593, 17485}},
+{14402, 18, 16665, {1, 3, 3, 7, 7, 19, 45, 247, 203, 757, 1941, 3753, 5317, 13239, 18945, 26173, 43929, 66889}},
+{14403, 18, 16678, {1, 1, 1, 15, 5, 17, 11, 21, 193, 941, 517, 191, 6067, 8403, 27339, 31035, 34767, 28675}},
+{14404, 18, 16701, {1, 3, 1, 7, 27, 59, 27, 7, 491, 551, 867, 3693, 391, 9799, 11051, 28347, 57555, 23079}},
+{14405, 18, 16713, {1, 3, 3, 1, 25, 21, 63, 253, 459, 603, 107, 1229, 1433, 4263, 24341, 20493, 40165, 254725}},
+{14406, 18, 16716, {1, 3, 5, 3, 9, 7, 63, 195, 19, 973, 47, 811, 2207, 3613, 8911, 17495, 62403, 77951}},
+{14407, 18, 16758, {1, 3, 5, 11, 5, 13, 83, 125, 467, 111, 1819, 3807, 4259, 2885, 29577, 13539, 69859, 97379}},
+{14408, 18, 16768, {1, 1, 5, 15, 5, 33, 109, 203, 129, 587, 9, 3025, 2839, 11405, 11257, 7779, 30311, 14015}},
+{14409, 18, 16797, {1, 1, 7, 15, 5, 47, 103, 199, 391, 61, 129, 3511, 1295, 15067, 23919, 2941, 120463, 21665}},
+{14410, 18, 16804, {1, 1, 5, 5, 7, 7, 125, 153, 365, 815, 1423, 4053, 875, 2405, 21291, 26785, 31371, 211045}},
+{14411, 18, 16811, {1, 3, 3, 9, 31, 47, 1, 247, 197, 1019, 985, 2277, 875, 3969, 15093, 15561, 110101, 156547}},
+{14412, 18, 16813, {1, 1, 3, 1, 9, 47, 71, 125, 17, 501, 1783, 2337, 483, 12719, 22453, 16701, 102639, 152955}},
+{14413, 18, 16881, {1, 1, 3, 11, 13, 31, 9, 63, 261, 257, 319, 1443, 5011, 9799, 18639, 53081, 56879, 102335}},
+{14414, 18, 16888, {1, 3, 3, 1, 5, 59, 127, 163, 323, 997, 1755, 1445, 2285, 4935, 22123, 815, 115131, 1009}},
+{14415, 18, 16893, {1, 1, 3, 11, 11, 43, 65, 127, 137, 583, 173, 2601, 5809, 15773, 16129, 2543, 68281, 96107}},
+{14416, 18, 16922, {1, 3, 5, 9, 25, 25, 95, 73, 313, 893, 1805, 2301, 5917, 15159, 8637, 25505, 66053, 31627}},
+{14417, 18, 16937, {1, 1, 3, 7, 25, 59, 55, 13, 297, 849, 187, 359, 3745, 12655, 29293, 58581, 89799, 195867}},
+{14418, 18, 16958, {1, 1, 5, 13, 19, 5, 51, 85, 259, 59, 1003, 2991, 6605, 8405, 5221, 45607, 130729, 99641}},
+{14419, 18, 16965, {1, 3, 5, 5, 25, 61, 51, 211, 143, 233, 1465, 1165, 1769, 3021, 9491, 30335, 34787, 142605}},
+{14420, 18, 16978, {1, 3, 5, 13, 23, 9, 89, 249, 71, 179, 841, 3375, 21, 6757, 27495, 7531, 123725, 253855}},
+{14421, 18, 16980, {1, 3, 7, 13, 9, 33, 109, 103, 475, 781, 493, 2079, 6529, 13443, 2181, 26925, 31345, 142863}},
+{14422, 18, 16989, {1, 1, 7, 9, 15, 41, 17, 85, 503, 839, 533, 731, 2735, 12949, 11395, 22539, 130147, 40045}},
+{14423, 18, 17011, {1, 1, 5, 9, 25, 21, 29, 79, 405, 383, 1271, 385, 7629, 3889, 5319, 57739, 51411, 50895}},
+{14424, 18, 17014, {1, 3, 7, 5, 13, 35, 17, 97, 261, 437, 951, 1403, 2407, 11447, 13565, 10165, 100001, 253093}},
+{14425, 18, 17023, {1, 3, 1, 3, 11, 39, 31, 187, 473, 565, 351, 4007, 2621, 14463, 9009, 40679, 81069, 51131}},
+{14426, 18, 17063, {1, 3, 5, 5, 9, 17, 11, 151, 59, 249, 281, 203, 6423, 4977, 18557, 65383, 88361, 87437}},
+{14427, 18, 17081, {1, 3, 5, 7, 15, 25, 3, 157, 179, 439, 1627, 3493, 6641, 6403, 2361, 3613, 33817, 22585}},
+{14428, 18, 17084, {1, 3, 5, 1, 13, 63, 77, 195, 233, 175, 631, 1021, 637, 13231, 26187, 131, 127379, 256183}},
+{14429, 18, 17099, {1, 1, 7, 9, 5, 13, 15, 187, 55, 37, 1113, 2191, 3439, 1073, 26239, 3049, 19807, 250869}},
+{14430, 18, 17126, {1, 1, 7, 3, 13, 15, 77, 47, 317, 285, 753, 2419, 7795, 11423, 6043, 2913, 42819, 50603}},
+{14431, 18, 17129, {1, 3, 7, 15, 21, 17, 63, 71, 97, 535, 1085, 1531, 5165, 13717, 1537, 26797, 111787, 189403}},
+{14432, 18, 17138, {1, 1, 1, 7, 9, 3, 43, 209, 385, 851, 1411, 4039, 3259, 13387, 24505, 33325, 83741, 241255}},
+{14433, 18, 17164, {1, 1, 1, 1, 3, 41, 13, 43, 303, 445, 1097, 3517, 7753, 8459, 3017, 16385, 13775, 248655}},
+{14434, 18, 17170, {1, 3, 5, 15, 5, 61, 31, 57, 269, 931, 1071, 1137, 6181, 13005, 18493, 1345, 105203, 117309}},
+{14435, 18, 17203, {1, 1, 3, 13, 21, 29, 3, 179, 367, 155, 993, 117, 5849, 10181, 1175, 55769, 16025, 67669}},
+{14436, 18, 17206, {1, 1, 3, 9, 11, 9, 33, 131, 181, 1003, 253, 2759, 1877, 11851, 22959, 37823, 82737, 110329}},
+{14437, 18, 17224, {1, 1, 1, 5, 7, 5, 107, 191, 385, 129, 567, 2585, 7295, 3005, 28185, 7095, 54851, 257587}},
+{14438, 18, 17305, {1, 3, 7, 9, 21, 61, 103, 155, 503, 307, 993, 683, 1491, 14895, 9213, 34535, 17765, 12457}},
+{14439, 18, 17322, {1, 3, 3, 1, 7, 47, 27, 173, 97, 889, 853, 3995, 4943, 71, 20479, 16741, 35479, 35307}},
+{14440, 18, 17327, {1, 1, 5, 3, 15, 35, 29, 207, 117, 267, 1835, 2565, 1199, 3813, 13999, 10537, 129915, 210651}},
+{14441, 18, 17332, {1, 3, 3, 13, 5, 57, 77, 193, 11, 279, 745, 2511, 5775, 13527, 26329, 16303, 111511, 70025}},
+{14442, 18, 17342, {1, 3, 7, 9, 17, 1, 73, 1, 125, 939, 863, 2763, 1951, 3191, 5567, 59729, 32149, 149417}},
+{14443, 18, 17387, {1, 3, 3, 1, 19, 25, 119, 63, 101, 33, 77, 3587, 6367, 8275, 24957, 32087, 7031, 217291}},
+{14444, 18, 17410, {1, 1, 1, 13, 7, 25, 75, 161, 143, 353, 973, 2957, 749, 13519, 11295, 34287, 60727, 83731}},
+{14445, 18, 17419, {1, 3, 7, 7, 17, 9, 59, 45, 97, 619, 895, 1955, 8143, 2507, 4673, 39425, 35679, 152069}},
+{14446, 18, 17429, {1, 1, 5, 9, 31, 19, 115, 177, 349, 877, 525, 305, 2187, 12195, 13529, 61641, 102293, 69941}},
+{14447, 18, 17439, {1, 3, 7, 11, 23, 59, 15, 243, 511, 465, 905, 1979, 2263, 2105, 9009, 3691, 22241, 97765}},
+{14448, 18, 17440, {1, 1, 7, 9, 29, 13, 3, 207, 51, 405, 1703, 1923, 1781, 14723, 8103, 10707, 64799, 99349}},
+{14449, 18, 17457, {1, 1, 7, 5, 23, 29, 51, 63, 489, 273, 1577, 2807, 5427, 9949, 1929, 19791, 109405, 241465}},
+{14450, 18, 17458, {1, 3, 3, 7, 29, 61, 103, 55, 29, 17, 1081, 21, 5791, 9803, 19385, 45091, 118069, 61383}},
+{14451, 18, 17469, {1, 3, 1, 7, 3, 15, 75, 47, 475, 87, 1541, 3933, 1081, 12361, 29213, 64333, 7229, 226909}},
+{14452, 18, 17477, {1, 1, 5, 7, 21, 45, 19, 137, 351, 229, 1773, 1829, 5025, 12661, 18745, 54917, 10419, 176667}},
+{14453, 18, 17512, {1, 1, 1, 3, 9, 37, 81, 25, 11, 327, 1653, 2751, 2823, 12575, 30287, 46265, 17299, 93595}},
+{14454, 18, 17518, {1, 1, 1, 3, 15, 17, 43, 163, 223, 731, 631, 2813, 1723, 6089, 14245, 64339, 114291, 40331}},
+{14455, 18, 17532, {1, 3, 7, 5, 21, 45, 41, 17, 495, 61, 1369, 369, 4493, 12071, 3813, 41455, 62561, 174399}},
+{14456, 18, 17536, {1, 1, 1, 5, 9, 41, 95, 113, 109, 519, 1683, 2265, 2875, 12649, 15575, 53511, 100707, 224035}},
+{14457, 18, 17559, {1, 3, 7, 9, 29, 7, 109, 109, 283, 111, 1167, 3679, 369, 11597, 19459, 759, 128667, 172427}},
+{14458, 18, 17569, {1, 1, 1, 3, 13, 31, 97, 31, 477, 507, 835, 465, 7501, 2485, 19485, 51055, 56363, 229341}},
+{14459, 18, 17641, {1, 3, 5, 11, 3, 23, 67, 173, 99, 963, 977, 1949, 1263, 2427, 15181, 23571, 23509, 26481}},
+{14460, 18, 17667, {1, 3, 3, 1, 29, 3, 35, 191, 197, 277, 397, 205, 5945, 1069, 31789, 3551, 101901, 222609}},
+{14461, 18, 17674, {1, 1, 5, 9, 11, 23, 109, 81, 295, 7, 755, 2345, 2823, 11133, 22623, 14515, 57059, 231099}},
+{14462, 18, 17693, {1, 3, 1, 3, 21, 29, 37, 71, 111, 737, 1881, 871, 5843, 5889, 14615, 49909, 7105, 48335}},
+{14463, 18, 17710, {1, 3, 1, 15, 23, 31, 87, 181, 483, 225, 2003, 365, 1569, 11153, 14673, 30085, 56497, 203723}},
+{14464, 18, 17729, {1, 1, 3, 15, 17, 47, 99, 167, 485, 431, 1481, 2225, 1537, 8513, 19407, 34165, 27289, 84393}},
+{14465, 18, 17754, {1, 3, 7, 3, 11, 17, 115, 205, 403, 831, 1869, 3623, 5215, 15511, 11297, 25181, 127491, 155887}},
+{14466, 18, 17763, {1, 1, 7, 5, 31, 37, 23, 21, 403, 529, 1185, 3363, 6319, 2435, 2687, 39407, 121891, 133047}},
+{14467, 18, 17780, {1, 3, 7, 1, 21, 31, 43, 61, 371, 987, 1783, 3811, 6227, 13199, 31799, 28863, 49329, 73947}},
+{14468, 18, 17784, {1, 3, 1, 1, 13, 1, 5, 99, 35, 793, 483, 2573, 2249, 6345, 12793, 61917, 49419, 58011}},
+{14469, 18, 17790, {1, 3, 1, 15, 3, 45, 35, 189, 67, 447, 1455, 3575, 8191, 7907, 21559, 38211, 26945, 240679}},
+{14470, 18, 17830, {1, 1, 3, 11, 27, 49, 9, 109, 93, 473, 1465, 271, 7389, 47, 8101, 6219, 17437, 220461}},
+{14471, 18, 17851, {1, 1, 7, 3, 23, 31, 75, 61, 375, 901, 1329, 2603, 3469, 12957, 23949, 62183, 126763, 68965}},
+{14472, 18, 17868, {1, 1, 7, 9, 13, 59, 75, 233, 339, 29, 1117, 1693, 593, 15317, 29753, 3079, 43583, 79939}},
+{14473, 18, 17879, {1, 1, 5, 1, 17, 57, 81, 123, 101, 765, 1941, 3143, 7403, 9105, 23197, 28983, 128059, 5931}},
+{14474, 18, 17896, {1, 3, 5, 11, 19, 31, 89, 165, 213, 251, 965, 3203, 1621, 4323, 26877, 17109, 18321, 162413}},
+{14475, 18, 17901, {1, 3, 3, 9, 11, 59, 123, 213, 335, 267, 1767, 3317, 5189, 10149, 27921, 19331, 71541, 170501}},
+{14476, 18, 17916, {1, 3, 3, 15, 3, 3, 115, 235, 305, 219, 265, 1535, 4925, 5597, 20857, 32381, 117237, 197533}},
+{14477, 18, 17935, {1, 3, 5, 13, 13, 59, 93, 85, 419, 337, 513, 2131, 5665, 12229, 1389, 34355, 65485, 81141}},
+{14478, 18, 17953, {1, 3, 7, 7, 11, 59, 111, 219, 293, 289, 325, 623, 3853, 3775, 14771, 5945, 119451, 162861}},
+{14479, 18, 17991, {1, 3, 1, 11, 19, 33, 119, 239, 431, 803, 1119, 2445, 3203, 7219, 31963, 34519, 104953, 254491}},
+{14480, 18, 18009, {1, 3, 7, 9, 21, 53, 21, 115, 365, 419, 11, 3803, 4283, 417, 8937, 64533, 56433, 166025}},
+{14481, 18, 18016, {1, 1, 7, 3, 17, 5, 99, 143, 485, 309, 1255, 2641, 3427, 1681, 3301, 64531, 38629, 20945}},
+{14482, 18, 18034, {1, 1, 5, 1, 31, 3, 115, 217, 451, 5, 1447, 2317, 1725, 12931, 25799, 23569, 51747, 28821}},
+{14483, 18, 18061, {1, 3, 7, 3, 31, 55, 109, 107, 211, 381, 1067, 3973, 5007, 8939, 8605, 55221, 124603, 47115}},
+{14484, 18, 18070, {1, 1, 1, 11, 19, 13, 99, 241, 103, 711, 1823, 2671, 653, 10217, 14195, 39735, 54807, 105599}},
+{14485, 18, 18079, {1, 3, 3, 7, 9, 33, 43, 131, 493, 141, 827, 2909, 2847, 12879, 7879, 6263, 25981, 57323}},
+{14486, 18, 18132, {1, 1, 1, 1, 1, 41, 55, 175, 479, 725, 157, 3403, 5809, 10685, 20433, 21729, 9493, 205685}},
+{14487, 18, 18145, {1, 1, 7, 5, 1, 33, 31, 245, 109, 711, 1047, 941, 449, 1055, 16249, 45211, 48311, 171339}},
+{14488, 18, 18169, {1, 3, 3, 9, 27, 9, 113, 69, 269, 643, 1371, 3521, 4969, 5373, 11133, 63109, 42725, 126969}},
+{14489, 18, 18170, {1, 1, 5, 15, 9, 21, 1, 195, 421, 429, 1103, 2727, 463, 9801, 8955, 62841, 94687, 114509}},
+{14490, 18, 18190, {1, 1, 5, 5, 5, 47, 9, 221, 59, 115, 359, 1147, 749, 1009, 23129, 641, 39471, 23073}},
+{14491, 18, 18192, {1, 3, 5, 13, 27, 29, 19, 3, 121, 773, 625, 2757, 6377, 15867, 14563, 40391, 4351, 21153}},
+{14492, 18, 18201, {1, 1, 5, 9, 11, 25, 51, 101, 273, 541, 1761, 593, 7111, 4369, 30095, 34867, 103989, 19855}},
+{14493, 18, 18228, {1, 1, 3, 13, 27, 55, 79, 115, 105, 855, 627, 2227, 2927, 8757, 8713, 54607, 43671, 130153}},
+{14494, 18, 18243, {1, 1, 3, 5, 7, 45, 21, 71, 157, 773, 1265, 841, 2463, 2217, 6087, 28683, 21251, 72377}},
+{14495, 18, 18260, {1, 1, 3, 1, 15, 11, 117, 211, 223, 713, 545, 907, 6907, 41, 17039, 23079, 86657, 5765}},
+{14496, 18, 18279, {1, 1, 5, 3, 27, 33, 77, 137, 401, 585, 911, 1189, 2749, 3427, 2701, 2453, 84857, 176585}},
+{14497, 18, 18285, {1, 1, 1, 3, 7, 39, 73, 143, 29, 569, 939, 301, 7827, 7691, 11513, 64517, 113679, 234165}},
+{14498, 18, 18297, {1, 3, 1, 11, 29, 57, 127, 181, 175, 973, 1537, 761, 5205, 13641, 32649, 8621, 77509, 261235}},
+{14499, 18, 18300, {1, 3, 5, 5, 13, 19, 117, 225, 477, 297, 1807, 2357, 5653, 3791, 6325, 54877, 120659, 91013}},
+{14500, 18, 18321, {1, 3, 1, 1, 3, 55, 19, 99, 321, 877, 541, 511, 141, 15047, 26377, 9, 2765, 223533}},
+{14501, 18, 18344, {1, 1, 1, 11, 13, 59, 121, 147, 215, 117, 1047, 3055, 2129, 15191, 14425, 28327, 108541, 114275}},
+{14502, 18, 18358, {1, 1, 1, 15, 3, 21, 105, 61, 501, 899, 195, 2745, 5989, 4433, 19525, 35477, 22997, 241657}},
+{14503, 18, 18364, {1, 1, 3, 5, 19, 47, 77, 247, 413, 317, 1255, 2087, 4493, 2211, 9003, 22145, 94001, 50579}},
+{14504, 18, 18376, {1, 3, 7, 11, 31, 47, 25, 191, 65, 409, 1349, 2481, 7619, 223, 18051, 63609, 77187, 75483}},
+{14505, 18, 18390, {1, 1, 1, 9, 21, 59, 115, 251, 401, 91, 627, 3273, 2393, 2949, 11475, 23669, 16171, 77507}},
+{14506, 18, 18399, {1, 3, 5, 1, 19, 7, 65, 253, 217, 493, 227, 3269, 4261, 2295, 32037, 5773, 12925, 41821}},
+{14507, 18, 18400, {1, 1, 5, 11, 5, 31, 71, 205, 285, 37, 1863, 1873, 191, 16137, 2955, 51993, 91401, 206967}},
+{14508, 18, 18427, {1, 3, 1, 7, 23, 31, 21, 81, 37, 903, 817, 3447, 8067, 3087, 25831, 46247, 77255, 68365}},
+{14509, 18, 18443, {1, 1, 7, 11, 7, 43, 21, 243, 431, 633, 2047, 577, 7297, 8151, 15951, 30313, 121569, 241687}},
+{14510, 18, 18487, {1, 1, 3, 5, 7, 45, 35, 189, 381, 849, 1869, 1193, 6815, 9017, 29053, 63605, 113623, 249097}},
+{14511, 18, 18493, {1, 3, 3, 11, 13, 1, 73, 151, 197, 591, 1101, 2437, 6695, 8337, 26539, 40147, 45673, 57727}},
+{14512, 18, 18508, {1, 1, 5, 1, 19, 15, 61, 151, 37, 893, 1819, 2317, 6299, 13097, 5109, 32613, 123685, 128173}},
+{14513, 18, 18532, {1, 1, 1, 7, 25, 29, 29, 203, 179, 211, 1483, 3315, 7125, 6931, 609, 849, 117571, 26829}},
+{14514, 18, 18535, {1, 3, 3, 11, 11, 47, 33, 101, 181, 431, 183, 2777, 5269, 4177, 15727, 717, 111243, 34825}},
+{14515, 18, 18580, {1, 3, 5, 11, 17, 19, 19, 143, 137, 537, 1249, 2889, 1911, 3895, 15433, 60165, 83815, 205569}},
+{14516, 18, 18587, {1, 3, 3, 7, 9, 59, 13, 159, 307, 625, 1, 2887, 3307, 16371, 4269, 56253, 71171, 55543}},
+{14517, 18, 18606, {1, 1, 1, 11, 7, 63, 15, 53, 409, 7, 1317, 473, 7481, 10321, 27941, 4941, 40003, 194153}},
+{14518, 18, 18659, {1, 1, 1, 1, 11, 53, 93, 157, 289, 231, 31, 273, 8131, 7861, 31041, 55221, 58305, 203403}},
+{14519, 18, 18662, {1, 1, 5, 11, 15, 53, 103, 41, 439, 601, 1949, 1087, 4275, 4675, 31879, 40909, 22365, 124781}},
+{14520, 18, 18679, {1, 3, 5, 9, 1, 47, 81, 47, 197, 499, 329, 2387, 5455, 15571, 2289, 44121, 12105, 11883}},
+{14521, 18, 18694, {1, 1, 3, 3, 7, 47, 93, 33, 265, 149, 845, 723, 7783, 6651, 22939, 58027, 66959, 3991}},
+{14522, 18, 18697, {1, 1, 5, 11, 23, 35, 123, 143, 35, 981, 1269, 2853, 4547, 7877, 16181, 17155, 57605, 11589}},
+{14523, 18, 18706, {1, 1, 7, 11, 9, 57, 87, 151, 333, 743, 1939, 3273, 1047, 5033, 16061, 37237, 12013, 17669}},
+{14524, 18, 18708, {1, 3, 7, 5, 29, 15, 109, 185, 51, 159, 1353, 3041, 7821, 14053, 13643, 62045, 78475, 43603}},
+{14525, 18, 18728, {1, 3, 1, 9, 29, 25, 121, 49, 415, 561, 325, 1139, 1993, 6437, 6025, 25225, 20761, 250589}},
+{14526, 18, 18731, {1, 3, 5, 3, 15, 39, 33, 43, 437, 605, 1081, 2397, 3821, 10961, 4853, 19517, 95817, 142023}},
+{14527, 18, 18733, {1, 1, 3, 11, 23, 51, 119, 13, 227, 981, 2017, 3265, 1215, 8737, 10719, 48027, 43239, 19425}},
+{14528, 18, 18751, {1, 3, 1, 15, 5, 5, 33, 175, 509, 611, 451, 2653, 1553, 1941, 25221, 31259, 6027, 159847}},
+{14529, 18, 18766, {1, 3, 7, 11, 7, 25, 71, 61, 89, 775, 609, 2363, 4261, 10677, 1243, 44895, 49113, 209603}},
+{14530, 18, 18773, {1, 3, 5, 15, 23, 23, 3, 15, 489, 455, 1303, 745, 5311, 1639, 18317, 33729, 119303, 255359}},
+{14531, 18, 18796, {1, 3, 7, 5, 13, 53, 29, 127, 159, 67, 469, 1735, 3497, 6985, 24735, 32957, 1225, 24447}},
+{14532, 18, 18811, {1, 3, 5, 5, 9, 13, 119, 83, 387, 777, 361, 3183, 6351, 9071, 13699, 53873, 54663, 67453}},
+{14533, 18, 18823, {1, 1, 5, 9, 17, 33, 9, 159, 143, 193, 1055, 2903, 2719, 12521, 5231, 37639, 94963, 105673}},
+{14534, 18, 18832, {1, 3, 3, 1, 27, 53, 87, 49, 465, 517, 1333, 411, 4089, 9985, 12989, 59511, 49939, 223481}},
+{14535, 18, 18854, {1, 1, 5, 9, 27, 59, 35, 125, 393, 271, 1565, 2847, 8139, 15627, 16059, 55319, 11131, 35141}},
+{14536, 18, 18858, {1, 1, 1, 1, 25, 1, 27, 195, 113, 539, 1281, 2273, 4793, 695, 25599, 41145, 107431, 160137}},
+{14537, 18, 18883, {1, 3, 3, 7, 13, 7, 35, 137, 83, 995, 1671, 1701, 3157, 15583, 7637, 18947, 59675, 9421}},
+{14538, 18, 18900, {1, 1, 7, 15, 23, 37, 109, 93, 377, 885, 1843, 1867, 2013, 10535, 5717, 55463, 18307, 125537}},
+{14539, 18, 18967, {1, 3, 7, 11, 25, 33, 91, 213, 109, 599, 131, 1879, 1375, 2911, 4649, 8809, 41199, 61629}},
+{14540, 18, 18974, {1, 3, 1, 1, 11, 17, 117, 243, 427, 913, 495, 527, 4277, 8867, 3131, 14143, 81677, 177369}},
+{14541, 18, 18990, {1, 3, 7, 11, 11, 37, 71, 185, 487, 161, 1773, 837, 243, 14105, 6881, 2155, 63679, 220387}},
+{14542, 18, 19009, {1, 1, 5, 3, 11, 41, 33, 99, 495, 757, 1083, 1987, 1997, 11057, 18445, 61903, 78163, 121701}},
+{14543, 18, 19055, {1, 1, 1, 1, 23, 37, 9, 19, 411, 11, 1487, 1279, 2129, 7449, 29631, 34559, 129753, 112627}},
+{14544, 18, 19058, {1, 1, 3, 11, 31, 39, 41, 207, 141, 383, 723, 3053, 743, 4479, 12395, 56659, 130303, 152005}},
+{14545, 18, 19074, {1, 3, 1, 7, 27, 25, 19, 37, 29, 781, 1115, 2569, 4113, 14033, 18653, 1055, 50639, 70413}},
+{14546, 18, 19079, {1, 1, 3, 1, 9, 15, 109, 7, 221, 161, 569, 2915, 2717, 2439, 4257, 61851, 113183, 63139}},
+{14547, 18, 19086, {1, 3, 5, 1, 17, 45, 3, 147, 207, 769, 321, 11, 2747, 7189, 8067, 34951, 50851, 42625}},
+{14548, 18, 19128, {1, 1, 7, 11, 15, 53, 117, 161, 219, 937, 1661, 3767, 959, 10351, 26685, 40095, 109821, 140139}},
+{14549, 18, 19145, {1, 3, 3, 9, 15, 47, 61, 35, 289, 743, 1723, 2189, 749, 13499, 22897, 55385, 114953, 67191}},
+{14550, 18, 19163, {1, 3, 7, 3, 23, 19, 123, 217, 393, 889, 1665, 13, 5663, 8695, 29767, 13433, 65133, 226713}},
+{14551, 18, 19175, {1, 1, 7, 11, 5, 57, 59, 171, 321, 519, 1333, 1975, 5331, 2383, 26863, 8989, 82167, 6915}},
+{14552, 18, 19189, {1, 1, 3, 3, 7, 17, 105, 79, 7, 827, 1277, 3805, 5943, 3161, 28953, 15657, 615, 149131}},
+{14553, 18, 19196, {1, 1, 5, 1, 5, 7, 99, 65, 295, 933, 365, 1867, 1959, 10733, 26947, 29659, 121889, 200379}},
+{14554, 18, 19204, {1, 3, 1, 13, 25, 21, 89, 247, 251, 43, 1539, 1317, 1875, 9237, 20693, 58433, 16757, 25451}},
+{14555, 18, 19213, {1, 3, 3, 13, 11, 47, 73, 21, 467, 337, 1881, 2723, 7023, 2767, 12553, 65533, 20517, 203749}},
+{14556, 18, 19237, {1, 1, 1, 1, 1, 17, 85, 133, 369, 577, 71, 859, 8151, 919, 10843, 44017, 10097, 199893}},
+{14557, 18, 19276, {1, 3, 5, 5, 23, 19, 21, 233, 475, 123, 621, 687, 6945, 2373, 6447, 31243, 3525, 256545}},
+{14558, 18, 19287, {1, 1, 7, 5, 9, 5, 35, 21, 33, 353, 1429, 3249, 6159, 8757, 6213, 855, 75863, 74507}},
+{14559, 18, 19291, {1, 1, 5, 11, 29, 21, 45, 155, 369, 769, 1041, 3929, 7377, 1621, 5285, 55213, 66143, 110251}},
+{14560, 18, 19293, {1, 3, 7, 11, 13, 57, 45, 207, 259, 907, 573, 663, 7727, 12677, 5949, 57625, 42183, 217491}},
+{14561, 18, 19304, {1, 3, 5, 3, 21, 63, 113, 159, 87, 551, 1405, 2867, 239, 10941, 27633, 13947, 69689, 225771}},
+{14562, 18, 19371, {1, 1, 3, 1, 1, 59, 5, 41, 125, 707, 1457, 1, 4263, 5519, 26101, 46339, 44949, 63689}},
+{14563, 18, 19379, {1, 1, 1, 1, 11, 9, 65, 155, 3, 85, 273, 2287, 6059, 3289, 19045, 14705, 112465, 202019}},
+{14564, 18, 19381, {1, 3, 3, 3, 21, 49, 95, 75, 479, 519, 1511, 1609, 2421, 14435, 11749, 49627, 16221, 98351}},
+{14565, 18, 19405, {1, 1, 3, 5, 25, 57, 1, 39, 377, 523, 529, 701, 6749, 10109, 15845, 53301, 70979, 210997}},
+{14566, 18, 19417, {1, 3, 1, 3, 27, 29, 101, 87, 361, 1, 229, 2653, 769, 16121, 18221, 31937, 12187, 63801}},
+{14567, 18, 19420, {1, 3, 3, 1, 25, 27, 49, 235, 309, 23, 1625, 589, 1251, 10305, 26943, 38949, 82539, 135491}},
+{14568, 18, 19424, {1, 1, 7, 7, 13, 13, 13, 61, 509, 73, 201, 2309, 1601, 3145, 19867, 5623, 117455, 180681}},
+{14569, 18, 19462, {1, 3, 3, 13, 13, 47, 71, 9, 123, 719, 701, 353, 1877, 3103, 20017, 64731, 72729, 147631}},
+{14570, 18, 19474, {1, 3, 1, 7, 29, 29, 53, 97, 409, 67, 1033, 2403, 2471, 10869, 2837, 43459, 117415, 213371}},
+{14571, 18, 19492, {1, 1, 7, 1, 7, 23, 103, 157, 315, 335, 375, 3493, 4095, 5331, 7773, 64173, 23167, 21259}},
+{14572, 18, 19501, {1, 3, 5, 13, 13, 55, 107, 147, 447, 281, 401, 1897, 7887, 15005, 21645, 26007, 19673, 238931}},
+{14573, 18, 19504, {1, 3, 1, 7, 17, 39, 109, 113, 143, 59, 1095, 225, 1455, 5021, 5011, 2039, 4381, 219847}},
+{14574, 18, 19516, {1, 3, 3, 7, 1, 35, 121, 145, 297, 251, 1153, 1955, 7881, 15461, 26961, 915, 30253, 15289}},
+{14575, 18, 19519, {1, 3, 5, 15, 5, 57, 43, 157, 49, 17, 993, 4085, 5639, 9405, 28661, 30191, 73291, 76913}},
+{14576, 18, 19534, {1, 1, 7, 1, 25, 63, 117, 55, 63, 649, 1635, 2505, 2765, 2715, 30241, 62699, 19567, 65953}},
+{14577, 18, 19555, {1, 3, 5, 13, 21, 49, 111, 127, 179, 819, 1737, 2519, 815, 10541, 15821, 54203, 71767, 7091}},
+{14578, 18, 19597, {1, 1, 1, 3, 27, 41, 101, 139, 39, 995, 819, 319, 1481, 15265, 20611, 22445, 53733, 82871}},
+{14579, 18, 19600, {1, 3, 3, 13, 7, 61, 103, 203, 353, 205, 1927, 2665, 757, 12277, 31217, 22247, 14527, 26385}},
+{14580, 18, 19615, {1, 1, 7, 3, 5, 35, 87, 235, 139, 785, 417, 3975, 6753, 4267, 15201, 8747, 12491, 159979}},
+{14581, 18, 19621, {1, 3, 1, 9, 9, 11, 117, 231, 503, 933, 1461, 2657, 7771, 2161, 26723, 4853, 23215, 162315}},
+{14582, 18, 19646, {1, 1, 7, 15, 27, 25, 115, 9, 257, 89, 571, 41, 2169, 10619, 2695, 2107, 64747, 40489}},
+{14583, 18, 19651, {1, 3, 7, 9, 29, 61, 91, 117, 279, 721, 233, 177, 5509, 7599, 2379, 20297, 75425, 25051}},
+{14584, 18, 19693, {1, 1, 1, 15, 31, 41, 3, 57, 59, 47, 963, 2831, 1885, 1989, 26803, 48243, 112065, 27753}},
+{14585, 18, 19702, {1, 1, 5, 15, 9, 57, 41, 255, 179, 719, 1463, 2857, 285, 9623, 13111, 20415, 28819, 149441}},
+{14586, 18, 19726, {1, 3, 1, 9, 17, 63, 21, 79, 473, 525, 1557, 3205, 7097, 14379, 28039, 30731, 62383, 247429}},
+{14587, 18, 19754, {1, 3, 3, 13, 25, 45, 97, 213, 11, 801, 1519, 1085, 6167, 13701, 6707, 47223, 69923, 66239}},
+{14588, 18, 19759, {1, 1, 1, 13, 1, 1, 9, 21, 363, 729, 1715, 1249, 5299, 11357, 20627, 33559, 84255, 133743}},
+{14589, 18, 19764, {1, 3, 3, 13, 17, 33, 23, 255, 309, 605, 1177, 1305, 2717, 6561, 29193, 7971, 117525, 79139}},
+{14590, 18, 19788, {1, 3, 1, 1, 7, 15, 73, 171, 11, 791, 241, 2641, 5397, 10403, 22207, 64123, 124507, 63855}},
+{14591, 18, 19793, {1, 3, 1, 11, 11, 7, 109, 103, 321, 1009, 1237, 3347, 287, 2389, 16529, 7789, 3347, 97827}},
+{14592, 18, 19836, {1, 3, 3, 3, 1, 27, 17, 9, 223, 755, 559, 3811, 2997, 1543, 23197, 42371, 5837, 13809}},
+{14593, 18, 19855, {1, 3, 1, 3, 7, 57, 31, 23, 35, 329, 1155, 2525, 3029, 5495, 12005, 18045, 4539, 75789}},
+{14594, 18, 19858, {1, 1, 5, 13, 3, 31, 121, 161, 325, 869, 715, 851, 1273, 1871, 22711, 61499, 36291, 11663}},
+{14595, 18, 19880, {1, 1, 5, 11, 7, 39, 23, 139, 197, 47, 513, 373, 6859, 11217, 17725, 60949, 19299, 91425}},
+{14596, 18, 19883, {1, 1, 3, 7, 15, 63, 123, 11, 109, 829, 231, 2591, 7997, 9061, 18647, 3209, 38509, 211219}},
+{14597, 18, 19917, {1, 1, 1, 11, 13, 35, 73, 223, 325, 49, 1317, 4063, 4127, 2755, 555, 51057, 44909, 205723}},
+{14598, 18, 19918, {1, 3, 3, 13, 17, 41, 115, 141, 503, 525, 63, 2487, 3225, 959, 10623, 28577, 89127, 157269}},
+{14599, 18, 19936, {1, 3, 1, 9, 25, 9, 43, 43, 279, 111, 1141, 3033, 7229, 5725, 8277, 59141, 116811, 127945}},
+{14600, 18, 19946, {1, 3, 7, 11, 27, 27, 93, 243, 135, 333, 1475, 1259, 1583, 7191, 6831, 53485, 128819, 174211}},
+{14601, 18, 19954, {1, 3, 3, 3, 17, 17, 43, 251, 433, 1011, 1817, 2835, 7721, 2449, 9463, 23779, 31427, 88127}},
+{14602, 18, 19979, {1, 1, 3, 3, 11, 49, 61, 41, 211, 559, 1761, 1303, 2119, 5743, 25515, 60705, 54405, 241063}},
+{14603, 18, 19993, {1, 1, 3, 11, 7, 61, 15, 115, 29, 35, 187, 3137, 6177, 1449, 32723, 15917, 107851, 101077}},
+{14604, 18, 19994, {1, 3, 5, 13, 21, 7, 11, 231, 417, 73, 1175, 735, 627, 7393, 7233, 39883, 129481, 106733}},
+{14605, 18, 20006, {1, 3, 1, 15, 27, 61, 63, 201, 27, 431, 1127, 1555, 1953, 13051, 18701, 30097, 95549, 198465}},
+{14606, 18, 20017, {1, 1, 3, 1, 23, 25, 43, 85, 291, 85, 1861, 675, 7451, 14701, 3929, 10835, 25569, 154687}},
+{14607, 18, 20032, {1, 3, 7, 15, 5, 43, 91, 225, 283, 259, 1311, 3977, 585, 14803, 14117, 2121, 106981, 157577}},
+{14608, 18, 20038, {1, 1, 1, 11, 7, 51, 49, 115, 477, 861, 1115, 743, 5109, 959, 7105, 9245, 66297, 188751}},
+{14609, 18, 20050, {1, 3, 3, 11, 23, 1, 11, 111, 163, 643, 1907, 3613, 2967, 10071, 6023, 1307, 62341, 241025}},
+{14610, 18, 20080, {1, 3, 5, 5, 15, 29, 31, 43, 445, 219, 1261, 421, 6035, 6461, 25583, 817, 100509, 239637}},
+{14611, 18, 20135, {1, 1, 7, 3, 27, 51, 121, 93, 349, 125, 2013, 1671, 8049, 7807, 7291, 64413, 93625, 245611}},
+{14612, 18, 20142, {1, 3, 3, 9, 11, 1, 91, 137, 501, 617, 1513, 799, 1705, 15737, 14989, 53611, 48781, 64481}},
+{14613, 18, 20159, {1, 3, 3, 1, 21, 55, 95, 79, 383, 617, 1589, 2671, 4057, 13525, 9269, 23539, 13317, 87701}},
+{14614, 18, 20173, {1, 1, 3, 1, 29, 17, 121, 45, 91, 215, 325, 2853, 1213, 10221, 7233, 34063, 21887, 142943}},
+{14615, 18, 20186, {1, 3, 3, 11, 27, 53, 55, 149, 107, 379, 441, 585, 5697, 16353, 5613, 4323, 55315, 197603}},
+{14616, 18, 20229, {1, 3, 7, 3, 31, 9, 71, 175, 485, 35, 675, 2091, 2351, 7985, 14207, 52687, 8559, 1067}},
+{14617, 18, 20234, {1, 1, 5, 15, 29, 37, 9, 73, 357, 961, 489, 875, 7465, 3231, 27821, 42499, 127837, 117215}},
+{14618, 18, 20263, {1, 3, 7, 7, 19, 43, 75, 153, 27, 291, 2039, 2661, 5513, 13429, 27307, 5305, 44771, 200621}},
+{14619, 18, 20270, {1, 1, 1, 15, 5, 39, 61, 107, 201, 485, 319, 335, 5537, 14195, 31861, 63637, 68497, 45637}},
+{14620, 18, 20299, {1, 3, 7, 7, 23, 49, 95, 225, 25, 933, 667, 2993, 2181, 15659, 31343, 20249, 57039, 43399}},
+{14621, 18, 20304, {1, 3, 3, 7, 17, 25, 29, 243, 511, 91, 1409, 203, 2749, 7067, 12471, 41737, 32761, 7535}},
+{14622, 18, 20319, {1, 1, 7, 9, 27, 43, 63, 65, 325, 817, 1127, 2039, 6171, 5867, 10593, 17205, 95913, 207417}},
+{14623, 18, 20329, {1, 1, 7, 3, 3, 51, 107, 153, 193, 579, 593, 2915, 7641, 5157, 1131, 29793, 66579, 81903}},
+{14624, 18, 20337, {1, 1, 5, 15, 19, 61, 125, 107, 235, 513, 1897, 875, 6341, 1817, 10631, 63905, 42993, 150699}},
+{14625, 18, 20353, {1, 1, 3, 11, 27, 1, 93, 107, 325, 459, 1733, 2527, 4557, 2277, 19345, 8205, 67337, 242559}},
+{14626, 18, 20401, {1, 1, 7, 3, 3, 45, 27, 227, 201, 99, 589, 1665, 4851, 2655, 9915, 41321, 59865, 71501}},
+{14627, 18, 20434, {1, 3, 1, 9, 3, 25, 117, 199, 125, 849, 135, 1771, 4743, 13475, 23711, 17389, 52711, 200143}},
+{14628, 18, 20436, {1, 3, 1, 3, 11, 23, 67, 155, 133, 557, 1933, 3169, 1707, 16045, 11039, 13889, 71045, 245885}},
+{14629, 18, 20473, {1, 1, 5, 9, 1, 7, 99, 13, 315, 251, 1289, 225, 2847, 8451, 3139, 46829, 124745, 64825}},
+{14630, 18, 20488, {1, 3, 7, 13, 19, 45, 87, 161, 271, 401, 1995, 935, 1803, 4051, 11709, 26993, 120139, 147895}},
+{14631, 18, 20512, {1, 1, 7, 5, 15, 11, 47, 215, 51, 1019, 2039, 3767, 929, 3845, 3939, 64077, 48115, 61845}},
+{14632, 18, 20515, {1, 1, 1, 5, 1, 39, 15, 77, 179, 13, 1099, 203, 3363, 9071, 12033, 49159, 71137, 124177}},
+{14633, 18, 20517, {1, 3, 5, 5, 1, 31, 83, 219, 387, 347, 1099, 925, 4423, 5081, 15981, 35881, 79131, 248301}},
+{14634, 18, 20530, {1, 3, 7, 3, 25, 19, 53, 43, 347, 845, 1735, 3237, 2795, 2253, 2997, 43729, 122833, 124869}},
+{14635, 18, 20571, {1, 3, 5, 11, 5, 19, 93, 55, 297, 231, 239, 3335, 253, 13607, 16769, 48879, 61439, 54827}},
+{14636, 18, 20574, {1, 3, 7, 11, 11, 55, 121, 73, 19, 1017, 727, 579, 8011, 9559, 15051, 7895, 17609, 103061}},
+{14637, 18, 20589, {1, 1, 7, 5, 19, 47, 85, 195, 75, 1003, 439, 3069, 2107, 12751, 26729, 2329, 1191, 86547}},
+{14638, 18, 20592, {1, 3, 3, 9, 5, 31, 63, 227, 481, 793, 1853, 1491, 2109, 4199, 32149, 45229, 54685, 124819}},
+{14639, 18, 20611, {1, 1, 1, 3, 15, 15, 41, 45, 153, 429, 1691, 1897, 7253, 7239, 26133, 36527, 90319, 186097}},
+{14640, 18, 20613, {1, 3, 1, 13, 15, 33, 103, 113, 121, 387, 177, 1943, 3181, 5483, 18515, 38807, 22655, 59787}},
+{14641, 18, 20628, {1, 1, 5, 7, 15, 3, 53, 155, 99, 133, 579, 2129, 6881, 11091, 26715, 15485, 108071, 230881}},
+{14642, 18, 20637, {1, 1, 3, 13, 25, 61, 91, 81, 9, 1011, 1993, 2485, 3707, 11127, 21279, 15853, 104081, 203769}},
+{14643, 18, 20638, {1, 1, 7, 3, 17, 23, 37, 171, 315, 247, 275, 3215, 7139, 11739, 25859, 34803, 124601, 9169}},
+{14644, 18, 20719, {1, 3, 7, 9, 21, 29, 97, 213, 309, 865, 597, 1811, 5547, 3741, 31927, 53379, 43293, 23589}},
+{14645, 18, 20724, {1, 3, 7, 9, 7, 43, 107, 187, 485, 977, 1329, 3037, 3701, 9667, 13581, 6283, 39221, 63841}},
+{14646, 18, 20772, {1, 1, 3, 11, 3, 51, 117, 45, 293, 409, 689, 153, 1163, 10921, 22709, 30415, 120475, 120751}},
+{14647, 18, 20796, {1, 3, 5, 15, 31, 59, 57, 63, 249, 763, 1627, 3039, 4309, 14115, 25489, 35009, 126609, 146041}},
+{14648, 18, 20799, {1, 1, 1, 9, 3, 47, 21, 183, 495, 361, 1439, 407, 5757, 12645, 11425, 1923, 94511, 205127}},
+{14649, 18, 20816, {1, 3, 1, 9, 15, 5, 101, 107, 385, 175, 791, 901, 4427, 10415, 8163, 14417, 62997, 139309}},
+{14650, 18, 20841, {1, 3, 5, 3, 13, 57, 9, 99, 77, 123, 1607, 3643, 3879, 503, 6021, 60211, 106471, 221801}},
+{14651, 18, 20844, {1, 1, 7, 5, 27, 35, 11, 33, 415, 387, 1461, 741, 55, 15095, 21177, 5715, 109893, 204843}},
+{14652, 18, 20862, {1, 1, 1, 15, 7, 49, 51, 81, 157, 421, 279, 1951, 6847, 10259, 31925, 60761, 12395, 49511}},
+{14653, 18, 20865, {1, 3, 7, 11, 5, 33, 27, 135, 247, 813, 1889, 2547, 2359, 9535, 4141, 59713, 88685, 214641}},
+{14654, 18, 20902, {1, 1, 5, 15, 17, 61, 99, 103, 39, 151, 1033, 2743, 6639, 5271, 22059, 12681, 22763, 88255}},
+{14655, 18, 20938, {1, 1, 7, 13, 5, 11, 39, 139, 353, 989, 1391, 169, 3709, 735, 22965, 227, 103623, 153893}},
+{14656, 18, 20957, {1, 1, 7, 3, 9, 51, 53, 87, 411, 617, 671, 681, 5057, 6003, 23137, 30881, 2289, 187133}},
+{14657, 18, 20971, {1, 1, 7, 7, 17, 59, 77, 219, 25, 53, 145, 129, 4289, 14257, 7159, 44833, 22131, 53393}},
+{14658, 18, 20973, {1, 3, 7, 1, 9, 59, 79, 177, 149, 637, 1641, 3713, 2709, 12321, 5691, 18239, 8617, 225979}},
+{14659, 18, 20981, {1, 1, 7, 5, 9, 9, 67, 51, 451, 815, 295, 813, 1257, 179, 28769, 57241, 51753, 164873}},
+{14660, 18, 20982, {1, 3, 1, 9, 19, 61, 53, 65, 29, 503, 715, 1837, 7487, 16187, 27303, 54681, 98753, 100471}},
+{14661, 18, 20985, {1, 1, 3, 1, 15, 51, 1, 79, 179, 367, 841, 1313, 797, 4777, 1369, 13317, 65059, 204877}},
+{14662, 18, 20991, {1, 3, 5, 9, 15, 19, 109, 45, 473, 517, 1139, 15, 1997, 4245, 11169, 56417, 75017, 37957}},
+{14663, 18, 21012, {1, 1, 7, 1, 3, 41, 75, 95, 59, 503, 1439, 2633, 3527, 5363, 24357, 43659, 10387, 208319}},
+{14664, 18, 21022, {1, 1, 5, 1, 31, 7, 71, 231, 505, 241, 1579, 3517, 3995, 8269, 6793, 15883, 102779, 75589}},
+{14665, 18, 21026, {1, 3, 5, 1, 13, 61, 87, 213, 501, 307, 1629, 2715, 7245, 747, 20601, 28105, 79249, 76231}},
+{14666, 18, 21028, {1, 1, 7, 11, 5, 13, 69, 221, 485, 59, 2027, 483, 6851, 11719, 16787, 54111, 47579, 49959}},
+{14667, 18, 21050, {1, 1, 3, 15, 3, 33, 57, 75, 375, 45, 851, 1673, 8167, 867, 32087, 34157, 96701, 72893}},
+{14668, 18, 21075, {1, 1, 3, 1, 21, 31, 65, 85, 181, 453, 815, 3139, 205, 429, 7451, 50855, 41085, 137927}},
+{14669, 18, 21077, {1, 3, 1, 9, 3, 57, 99, 183, 305, 991, 809, 4021, 3131, 4459, 5839, 32493, 116541, 59329}},
+{14670, 18, 21078, {1, 3, 7, 1, 5, 19, 3, 91, 297, 715, 1081, 445, 393, 12685, 4457, 61437, 103701, 75917}},
+{14671, 18, 21106, {1, 1, 7, 15, 17, 39, 19, 255, 247, 391, 1055, 1241, 4515, 10217, 23363, 40301, 115053, 234349}},
+{14672, 18, 21122, {1, 3, 5, 1, 21, 9, 33, 243, 501, 793, 219, 3595, 2585, 5083, 15377, 35761, 90609, 93761}},
+{14673, 18, 21127, {1, 1, 5, 13, 3, 1, 5, 77, 265, 525, 1107, 1879, 1119, 2277, 30557, 43547, 81947, 134075}},
+{14674, 18, 21155, {1, 1, 7, 5, 11, 47, 71, 83, 255, 183, 515, 2591, 3933, 16025, 16727, 43421, 18725, 106675}},
+{14675, 18, 21167, {1, 3, 1, 1, 5, 17, 57, 209, 509, 421, 1247, 3153, 1835, 8777, 13285, 27699, 34001, 186553}},
+{14676, 18, 21169, {1, 1, 3, 11, 27, 19, 73, 65, 179, 115, 845, 2507, 7673, 14429, 10553, 4999, 82323, 247379}},
+{14677, 18, 21204, {1, 3, 7, 7, 17, 59, 97, 183, 407, 697, 1423, 123, 6479, 3997, 729, 31587, 114383, 61673}},
+{14678, 18, 21230, {1, 1, 5, 9, 21, 23, 21, 153, 187, 255, 125, 1469, 2639, 8099, 29689, 36415, 103959, 231621}},
+{14679, 18, 21256, {1, 1, 3, 11, 19, 59, 115, 205, 123, 133, 1953, 3471, 2495, 329, 32385, 21931, 9691, 51405}},
+{14680, 18, 21285, {1, 3, 3, 13, 7, 7, 115, 65, 301, 621, 1091, 2137, 5729, 5027, 21331, 24803, 114789, 142039}},
+{14681, 18, 21312, {1, 1, 7, 5, 31, 19, 103, 69, 503, 663, 1497, 2867, 5295, 893, 15927, 37513, 94553, 72369}},
+{14682, 18, 21329, {1, 3, 3, 15, 17, 33, 99, 249, 277, 259, 9, 99, 3073, 12017, 14847, 7685, 102499, 26489}},
+{14683, 18, 21351, {1, 1, 1, 1, 5, 23, 31, 45, 29, 483, 1977, 1129, 6925, 2273, 16573, 53039, 90251, 137191}},
+{14684, 18, 21372, {1, 3, 1, 13, 27, 47, 29, 51, 473, 895, 671, 3917, 6905, 15769, 9019, 28879, 120591, 220753}},
+{14685, 18, 21376, {1, 3, 1, 13, 27, 29, 53, 255, 507, 819, 1251, 2463, 1717, 14461, 31997, 30829, 8803, 115539}},
+{14686, 18, 21424, {1, 3, 3, 15, 27, 1, 109, 225, 451, 409, 2025, 2701, 4121, 9949, 1551, 13625, 73577, 211549}},
+{14687, 18, 21448, {1, 1, 1, 3, 23, 57, 49, 35, 365, 711, 2001, 997, 1853, 2913, 15667, 30255, 19535, 2171}},
+{14688, 18, 21465, {1, 1, 7, 1, 21, 37, 127, 3, 117, 449, 1689, 1391, 1427, 12641, 15199, 23769, 66553, 34669}},
+{14689, 18, 21495, {1, 3, 7, 9, 31, 45, 51, 137, 181, 469, 573, 89, 7257, 10991, 30705, 37827, 75071, 152885}},
+{14690, 18, 21509, {1, 3, 1, 1, 19, 13, 55, 223, 261, 353, 1497, 183, 8173, 14421, 9977, 24095, 47215, 155189}},
+{14691, 18, 21550, {1, 1, 3, 15, 15, 41, 31, 105, 459, 27, 299, 159, 2167, 14809, 9983, 2755, 121715, 35921}},
+{14692, 18, 21562, {1, 1, 3, 7, 31, 5, 85, 137, 431, 849, 1479, 2681, 167, 5727, 3211, 30765, 63295, 39509}},
+{14693, 18, 21575, {1, 1, 5, 7, 5, 51, 21, 103, 175, 927, 1115, 1507, 505, 8093, 25831, 54303, 40397, 61249}},
+{14694, 18, 21579, {1, 1, 7, 3, 23, 53, 49, 225, 7, 425, 403, 3949, 1081, 15335, 21737, 647, 107875, 236183}},
+{14695, 18, 21582, {1, 1, 5, 7, 17, 21, 85, 229, 325, 57, 601, 2785, 6417, 5135, 17917, 12861, 97675, 115457}},
+{14696, 18, 21600, {1, 1, 3, 3, 13, 23, 73, 111, 385, 47, 605, 1169, 1729, 2335, 18739, 61293, 41915, 237645}},
+{14697, 18, 21615, {1, 1, 1, 5, 31, 11, 123, 13, 465, 755, 1073, 1885, 2105, 5971, 2347, 10911, 125823, 156037}},
+{14698, 18, 21617, {1, 3, 7, 11, 17, 47, 3, 165, 227, 355, 87, 839, 7741, 12275, 28579, 25337, 87671, 224847}},
+{14699, 18, 21624, {1, 1, 5, 15, 23, 33, 9, 1, 257, 121, 1049, 1009, 187, 9935, 26093, 21921, 130247, 240291}},
+{14700, 18, 21633, {1, 1, 3, 13, 13, 27, 87, 221, 27, 117, 551, 2533, 7611, 5333, 14635, 9911, 37555, 250621}},
+{14701, 18, 21636, {1, 3, 7, 15, 29, 39, 33, 1, 495, 889, 1397, 3415, 7193, 11533, 27379, 36425, 13739, 146635}},
+{14702, 18, 21645, {1, 1, 7, 11, 1, 23, 85, 127, 79, 989, 321, 1913, 7571, 9889, 11803, 1307, 120513, 218077}},
+{14703, 18, 21654, {1, 1, 7, 5, 5, 15, 35, 9, 351, 973, 1455, 2043, 5527, 9431, 16059, 53915, 105785, 180579}},
+{14704, 18, 21660, {1, 1, 1, 13, 13, 45, 15, 41, 131, 463, 1011, 3559, 6393, 4737, 6041, 33073, 60989, 56761}},
+{14705, 18, 21667, {1, 1, 3, 9, 31, 35, 23, 133, 33, 233, 543, 957, 4913, 12441, 10293, 31611, 83383, 154551}},
+{14706, 18, 21702, {1, 3, 3, 1, 29, 37, 117, 247, 345, 197, 1617, 3333, 7901, 8343, 55, 16529, 34627, 172703}},
+{14707, 18, 21714, {1, 1, 1, 13, 23, 51, 7, 219, 503, 215, 375, 2275, 5467, 13953, 13987, 22735, 67505, 185977}},
+{14708, 18, 21719, {1, 3, 5, 5, 29, 53, 85, 147, 167, 409, 853, 667, 4431, 5227, 15535, 34375, 107135, 220637}},
+{14709, 18, 21736, {1, 3, 7, 7, 19, 3, 73, 123, 455, 539, 1735, 1423, 5337, 16311, 15469, 36071, 126437, 219249}},
+{14710, 18, 21767, {1, 1, 1, 3, 19, 49, 17, 133, 101, 1013, 683, 869, 6267, 409, 31379, 2535, 8039, 63205}},
+{14711, 18, 21781, {1, 1, 1, 13, 13, 53, 25, 31, 501, 629, 645, 1811, 3675, 13317, 17009, 7359, 85475, 249823}},
+{14712, 18, 21795, {1, 1, 3, 11, 5, 1, 41, 17, 159, 361, 1439, 2083, 1425, 7221, 9117, 59543, 59285, 188615}},
+{14713, 18, 21841, {1, 3, 7, 1, 11, 27, 71, 121, 471, 749, 1983, 3715, 6463, 5793, 1063, 18201, 189, 243751}},
+{14714, 18, 21853, {1, 3, 3, 11, 19, 17, 15, 175, 379, 683, 1491, 2385, 6981, 1183, 16829, 2103, 9309, 46119}},
+{14715, 18, 21867, {1, 1, 7, 5, 17, 39, 109, 9, 279, 309, 1, 1523, 4551, 3855, 13277, 36125, 54191, 45085}},
+{14716, 18, 21878, {1, 3, 5, 3, 9, 59, 51, 5, 431, 657, 161, 2725, 2401, 9743, 12925, 43501, 51551, 163737}},
+{14717, 18, 21891, {1, 1, 5, 3, 9, 13, 7, 177, 121, 795, 1169, 3169, 3793, 3995, 29027, 32967, 82273, 207939}},
+{14718, 18, 21897, {1, 3, 7, 13, 1, 1, 31, 91, 245, 775, 1589, 2263, 6303, 15787, 3111, 52553, 52507, 183971}},
+{14719, 18, 21954, {1, 3, 5, 11, 15, 49, 73, 191, 67, 449, 1245, 2445, 5617, 8625, 27971, 35939, 76907, 76207}},
+{14720, 18, 21956, {1, 3, 1, 11, 15, 47, 29, 91, 437, 895, 1941, 249, 2739, 15479, 29699, 7257, 39897, 65985}},
+{14721, 18, 21965, {1, 3, 5, 7, 13, 23, 45, 113, 297, 373, 1505, 2317, 7509, 12059, 13737, 29081, 87337, 221917}},
+{14722, 18, 21977, {1, 3, 3, 3, 1, 5, 13, 215, 221, 461, 1337, 3569, 2257, 12135, 14685, 39721, 16723, 234791}},
+{14723, 18, 21978, {1, 1, 7, 5, 11, 25, 71, 103, 87, 533, 779, 379, 6695, 13451, 24801, 49235, 35109, 100865}},
+{14724, 18, 21983, {1, 3, 3, 15, 13, 51, 27, 11, 279, 847, 135, 1119, 2765, 3805, 20273, 29089, 83379, 190353}},
+{14725, 18, 22002, {1, 3, 7, 5, 17, 29, 111, 35, 189, 273, 503, 541, 6691, 9051, 10403, 7559, 54787, 25403}},
+{14726, 18, 22013, {1, 3, 5, 9, 21, 29, 85, 235, 223, 677, 71, 1313, 6587, 10983, 199, 27721, 78627, 105505}},
+{14727, 18, 22014, {1, 3, 1, 3, 13, 3, 123, 115, 173, 907, 1555, 1489, 2745, 6451, 25347, 24105, 66471, 181009}},
+{14728, 18, 22054, {1, 1, 7, 1, 31, 15, 13, 97, 511, 827, 1193, 3081, 1517, 13511, 24887, 39239, 85175, 150213}},
+{14729, 18, 22058, {1, 1, 1, 5, 17, 39, 121, 67, 207, 877, 1885, 171, 2687, 13081, 27267, 58699, 118575, 213025}},
+{14730, 18, 22066, {1, 1, 3, 9, 9, 27, 101, 215, 31, 37, 1629, 3631, 3225, 9667, 31547, 41939, 38683, 150805}},
+{14731, 18, 22085, {1, 3, 1, 11, 11, 59, 17, 15, 187, 667, 747, 2193, 6749, 6019, 31805, 52433, 4141, 52613}},
+{14732, 18, 22103, {1, 3, 3, 13, 9, 1, 51, 101, 213, 881, 899, 2197, 3017, 1591, 9271, 44017, 99893, 192005}},
+{14733, 18, 22138, {1, 3, 7, 13, 23, 41, 79, 83, 123, 585, 49, 849, 2133, 12473, 6907, 15487, 45783, 46609}},
+{14734, 18, 22140, {1, 3, 7, 13, 27, 23, 71, 13, 319, 903, 1123, 933, 2603, 11631, 19953, 47001, 127751, 84547}},
+{14735, 18, 22153, {1, 1, 1, 15, 3, 61, 79, 231, 43, 217, 801, 997, 6545, 13657, 25589, 30435, 49497, 1037}},
+{14736, 18, 22164, {1, 3, 3, 3, 21, 29, 121, 35, 129, 239, 1645, 3147, 7647, 1201, 19287, 7075, 67961, 62481}},
+{14737, 18, 22167, {1, 3, 7, 7, 3, 23, 45, 177, 469, 897, 359, 2521, 2079, 985, 14993, 56813, 20667, 187341}},
+{14738, 18, 22189, {1, 3, 5, 7, 23, 53, 15, 45, 297, 93, 247, 1165, 2683, 5899, 7113, 14859, 22733, 173835}},
+{14739, 18, 22202, {1, 1, 3, 15, 23, 17, 43, 179, 103, 197, 1857, 323, 267, 12417, 2343, 41527, 12243, 112023}},
+{14740, 18, 22212, {1, 3, 7, 13, 7, 43, 75, 19, 169, 621, 735, 141, 3087, 765, 5901, 34029, 117603, 5137}},
+{14741, 18, 22234, {1, 1, 3, 5, 15, 17, 67, 177, 371, 249, 99, 1651, 3701, 343, 435, 50307, 33915, 115391}},
+{14742, 18, 22239, {1, 1, 3, 13, 19, 53, 69, 1, 435, 71, 339, 2289, 1591, 8783, 8087, 25855, 115311, 191115}},
+{14743, 18, 22245, {1, 3, 5, 11, 1, 55, 59, 7, 101, 655, 353, 483, 5681, 12721, 15973, 51377, 94921, 246365}},
+{14744, 18, 22272, {1, 3, 5, 3, 25, 23, 99, 145, 277, 741, 595, 2653, 1393, 2867, 271, 49131, 111973, 118869}},
+{14745, 18, 22308, {1, 1, 7, 13, 11, 51, 127, 27, 305, 265, 1755, 3189, 4679, 9721, 24409, 46941, 94353, 95643}},
+{14746, 18, 22318, {1, 1, 5, 11, 1, 63, 53, 149, 459, 155, 1431, 3969, 3417, 12121, 14535, 52089, 110745, 57}},
+{14747, 18, 22320, {1, 1, 5, 9, 23, 33, 17, 175, 313, 185, 101, 531, 2941, 14999, 31413, 12103, 33709, 260555}},
+{14748, 18, 22338, {1, 1, 3, 13, 3, 11, 67, 95, 211, 673, 23, 2379, 6985, 12101, 13021, 9255, 116437, 228877}},
+{14749, 18, 22350, {1, 1, 3, 15, 7, 51, 25, 109, 45, 691, 869, 485, 111, 11465, 27953, 54375, 10805, 221023}},
+{14750, 18, 22374, {1, 3, 7, 7, 17, 53, 59, 101, 221, 593, 587, 873, 931, 14617, 12067, 58655, 102437, 31675}},
+{14751, 18, 22388, {1, 1, 3, 15, 25, 57, 35, 231, 491, 671, 933, 3525, 1237, 10155, 27501, 50781, 23183, 108283}},
+{14752, 18, 22391, {1, 3, 5, 5, 31, 63, 117, 205, 199, 841, 1455, 3901, 2127, 13573, 20667, 49489, 60217, 197421}},
+{14753, 18, 22422, {1, 1, 3, 7, 15, 21, 73, 211, 421, 873, 607, 709, 9, 10985, 28653, 64579, 118145, 3095}},
+{14754, 18, 22426, {1, 1, 1, 13, 17, 53, 27, 105, 201, 399, 737, 3235, 1287, 13859, 6049, 62249, 88259, 52991}},
+{14755, 18, 22441, {1, 3, 7, 7, 25, 45, 67, 147, 275, 315, 1675, 2289, 4611, 6325, 26617, 38079, 125219, 23569}},
+{14756, 18, 22481, {1, 1, 7, 7, 9, 61, 115, 251, 297, 691, 1881, 1815, 7229, 10859, 8257, 38097, 87927, 162845}},
+{14757, 18, 22488, {1, 3, 3, 9, 9, 59, 17, 207, 433, 825, 93, 697, 7263, 15983, 14829, 47471, 17579, 151519}},
+{14758, 18, 22500, {1, 1, 1, 11, 21, 31, 7, 41, 383, 731, 2033, 3417, 4187, 5515, 10093, 15875, 78551, 2057}},
+{14759, 18, 22517, {1, 3, 7, 15, 5, 29, 7, 171, 129, 727, 1815, 1361, 6137, 10333, 22203, 361, 92437, 6545}},
+{14760, 18, 22531, {1, 1, 3, 13, 25, 45, 111, 69, 333, 365, 765, 2755, 3485, 2729, 23467, 64809, 120755, 169279}},
+{14761, 18, 22552, {1, 1, 3, 1, 19, 13, 33, 165, 157, 429, 1175, 3435, 7523, 5055, 12295, 34309, 36933, 164037}},
+{14762, 18, 22574, {1, 1, 3, 11, 31, 49, 37, 161, 465, 311, 1839, 689, 6837, 13473, 29883, 61587, 86077, 156921}},
+{14763, 18, 22579, {1, 3, 3, 1, 3, 23, 69, 159, 501, 303, 1495, 9, 6055, 545, 12247, 23413, 67247, 38137}},
+{14764, 18, 22582, {1, 1, 5, 15, 5, 39, 107, 121, 295, 167, 1055, 2703, 147, 7291, 3981, 51989, 92953, 225987}},
+{14765, 18, 22586, {1, 3, 1, 1, 21, 5, 91, 129, 57, 53, 365, 2497, 5017, 13535, 19305, 60447, 115467, 225317}},
+{14766, 18, 22594, {1, 3, 1, 7, 25, 17, 51, 15, 119, 1013, 719, 991, 2655, 12587, 15749, 11723, 18461, 155937}},
+{14767, 18, 22611, {1, 3, 7, 3, 25, 33, 59, 135, 501, 813, 235, 3775, 2781, 13137, 32673, 31643, 78881, 207651}},
+{14768, 18, 22614, {1, 1, 7, 13, 27, 51, 99, 189, 187, 577, 941, 1275, 7297, 14731, 12599, 49049, 96439, 35093}},
+{14769, 18, 22700, {1, 3, 1, 15, 9, 45, 1, 149, 305, 231, 935, 1377, 6345, 14795, 20969, 26263, 5711, 146949}},
+{14770, 18, 22711, {1, 1, 5, 9, 5, 9, 47, 127, 105, 517, 671, 67, 4639, 2477, 23109, 56707, 72131, 100709}},
+{14771, 18, 22749, {1, 3, 5, 3, 21, 23, 7, 193, 491, 197, 319, 3207, 2183, 2133, 3127, 34555, 53707, 170875}},
+{14772, 18, 22759, {1, 1, 3, 9, 5, 23, 109, 91, 359, 913, 179, 1031, 3617, 12497, 23299, 53293, 114603, 9931}},
+{14773, 18, 22774, {1, 3, 1, 5, 1, 47, 73, 103, 333, 483, 1015, 3085, 5229, 3171, 16539, 13493, 68957, 177645}},
+{14774, 18, 22777, {1, 1, 1, 9, 27, 15, 25, 255, 383, 501, 831, 2463, 237, 16065, 6991, 56503, 117303, 140573}},
+{14775, 18, 22780, {1, 1, 3, 5, 9, 25, 15, 179, 415, 729, 1163, 2649, 2907, 9591, 29129, 42775, 80537, 139897}},
+{14776, 18, 22783, {1, 1, 3, 7, 31, 15, 113, 1, 263, 685, 1953, 1479, 5143, 8585, 9057, 61479, 122065, 191541}},
+{14777, 18, 22785, {1, 3, 1, 11, 25, 47, 25, 229, 463, 197, 1123, 2665, 2345, 11701, 10435, 15205, 35437, 137619}},
+{14778, 18, 22840, {1, 3, 3, 5, 19, 57, 89, 101, 373, 283, 57, 1701, 5025, 6677, 20321, 58459, 9319, 161501}},
+{14779, 18, 22878, {1, 1, 1, 13, 3, 51, 111, 23, 325, 813, 441, 2371, 1993, 6839, 359, 9873, 33719, 208163}},
+{14780, 18, 22884, {1, 3, 1, 11, 23, 53, 35, 89, 91, 601, 433, 1671, 1919, 2115, 6355, 10639, 87305, 194185}},
+{14781, 18, 22888, {1, 1, 5, 9, 29, 31, 43, 153, 209, 835, 865, 2431, 1085, 9771, 14483, 19551, 98673, 146881}},
+{14782, 18, 22927, {1, 1, 7, 3, 7, 33, 49, 111, 111, 843, 479, 2113, 4575, 14911, 5161, 7153, 37525, 217887}},
+{14783, 18, 22941, {1, 1, 7, 9, 27, 5, 23, 217, 11, 79, 1637, 2047, 6697, 5601, 2877, 63497, 100127, 157833}},
+{14784, 18, 22951, {1, 1, 7, 11, 31, 41, 91, 39, 207, 185, 1163, 2115, 2963, 7605, 12597, 54175, 7221, 117129}},
+{14785, 18, 22958, {1, 3, 7, 13, 9, 15, 3, 47, 281, 451, 1111, 3585, 4505, 9465, 8047, 45893, 27179, 124373}},
+{14786, 18, 22980, {1, 3, 5, 11, 27, 29, 11, 221, 483, 29, 17, 1067, 6761, 39, 13419, 7263, 127547, 178951}},
+{14787, 18, 23007, {1, 3, 5, 5, 19, 3, 51, 155, 41, 251, 851, 1191, 4445, 8337, 25339, 32931, 4743, 31883}},
+{14788, 18, 23032, {1, 3, 7, 15, 9, 3, 113, 151, 239, 611, 381, 1141, 2865, 3071, 7293, 61997, 2891, 14533}},
+{14789, 18, 23041, {1, 3, 5, 3, 15, 59, 3, 37, 385, 587, 837, 2483, 5493, 10571, 26129, 44835, 63425, 246953}},
+{14790, 18, 23044, {1, 3, 5, 13, 9, 9, 93, 11, 139, 619, 581, 2859, 5481, 11941, 20661, 37463, 95369, 177009}},
+{14791, 18, 23059, {1, 1, 7, 11, 7, 17, 89, 7, 479, 377, 1631, 509, 7429, 13733, 24011, 24191, 98409, 180761}},
+{14792, 18, 23065, {1, 3, 7, 1, 5, 17, 51, 113, 181, 75, 1787, 2221, 6181, 16069, 3031, 32531, 107833, 239907}},
+{14793, 18, 23072, {1, 1, 5, 11, 3, 25, 13, 35, 311, 865, 873, 1811, 3101, 4445, 18155, 18647, 55693, 144963}},
+{14794, 18, 23137, {1, 3, 7, 13, 1, 9, 73, 189, 255, 301, 1579, 597, 6027, 15621, 27287, 14615, 76051, 143445}},
+{14795, 18, 23144, {1, 3, 1, 13, 19, 59, 11, 97, 501, 857, 1071, 3633, 8059, 2469, 16803, 49395, 73631, 114297}},
+{14796, 18, 23155, {1, 1, 1, 5, 19, 3, 59, 179, 343, 745, 497, 2965, 3841, 3119, 17707, 31577, 39801, 108819}},
+{14797, 18, 23162, {1, 3, 3, 9, 11, 17, 19, 199, 283, 229, 493, 631, 8133, 1531, 25271, 11353, 114759, 70655}},
+{14798, 18, 23167, {1, 1, 7, 7, 3, 11, 1, 95, 167, 863, 1009, 1695, 2773, 11667, 23515, 12927, 87883, 28773}},
+{14799, 18, 23183, {1, 3, 1, 15, 9, 1, 31, 243, 57, 349, 483, 659, 1971, 7971, 23797, 4403, 83837, 239261}},
+{14800, 18, 23192, {1, 3, 7, 5, 11, 17, 55, 5, 209, 233, 1969, 925, 695, 1321, 11965, 29849, 120519, 195105}},
+{14801, 18, 23197, {1, 3, 7, 11, 9, 45, 27, 9, 57, 649, 1801, 2653, 1535, 45, 8901, 28755, 26475, 112341}},
+{14802, 18, 23216, {1, 1, 3, 13, 11, 57, 103, 213, 193, 779, 541, 3685, 4191, 6105, 7199, 63659, 49673, 208361}},
+{14803, 18, 23221, {1, 3, 3, 7, 15, 15, 9, 207, 387, 429, 1213, 1703, 5753, 10261, 8705, 62783, 9643, 248591}},
+{14804, 18, 23228, {1, 3, 3, 15, 23, 17, 5, 83, 295, 685, 2003, 1723, 2799, 14699, 25171, 20275, 45597, 214107}},
+{14805, 18, 23233, {1, 1, 1, 15, 13, 33, 111, 69, 329, 273, 1303, 3377, 4151, 12547, 20411, 54845, 7839, 173939}},
+{14806, 18, 23234, {1, 1, 5, 15, 25, 31, 11, 75, 69, 501, 1485, 3659, 3889, 9715, 9633, 45313, 112377, 27799}},
+{14807, 18, 23251, {1, 1, 3, 11, 31, 27, 7, 25, 315, 593, 315, 275, 1453, 9429, 10023, 17939, 37651, 217435}},
+{14808, 18, 23257, {1, 3, 7, 7, 27, 41, 69, 95, 19, 763, 1733, 2097, 6723, 7051, 15209, 53047, 56117, 87639}},
+{14809, 18, 23258, {1, 3, 7, 5, 15, 61, 31, 19, 361, 571, 727, 405, 835, 4847, 26777, 50311, 104125, 127197}},
+{14810, 18, 23288, {1, 1, 1, 11, 11, 61, 59, 63, 409, 219, 1135, 3385, 5583, 16143, 22709, 31247, 19871, 68557}},
+{14811, 18, 23302, {1, 3, 7, 1, 11, 3, 121, 41, 135, 427, 1267, 2169, 507, 757, 12411, 50655, 75625, 1199}},
+{14812, 18, 23341, {1, 1, 7, 5, 17, 21, 89, 119, 55, 395, 979, 909, 1711, 3289, 8433, 9, 12743, 109027}},
+{14813, 18, 23373, {1, 1, 1, 13, 5, 11, 93, 35, 437, 173, 1157, 2749, 6855, 8307, 26145, 22593, 125415, 65509}},
+{14814, 18, 23402, {1, 1, 5, 3, 25, 27, 1, 173, 113, 373, 1769, 2941, 1895, 3399, 27665, 50613, 20747, 31903}},
+{14815, 18, 23409, {1, 1, 1, 1, 9, 7, 53, 73, 465, 725, 1537, 579, 83, 925, 15507, 13595, 16927, 205087}},
+{14816, 18, 23428, {1, 1, 3, 7, 7, 23, 31, 127, 27, 727, 1305, 3879, 817, 15995, 28607, 22695, 6367, 161587}},
+{14817, 18, 23435, {1, 3, 1, 7, 29, 23, 27, 117, 279, 917, 1105, 2061, 7719, 13633, 16501, 33739, 71939, 143115}},
+{14818, 18, 23440, {1, 3, 7, 11, 7, 27, 65, 133, 411, 441, 925, 1485, 2035, 3067, 14511, 58511, 120773, 228731}},
+{14819, 18, 23449, {1, 1, 3, 9, 21, 55, 27, 73, 175, 395, 1201, 2599, 3839, 11163, 5057, 3385, 43265, 105211}},
+{14820, 18, 23459, {1, 1, 1, 3, 7, 63, 91, 197, 417, 763, 1391, 3729, 2791, 1975, 23655, 50611, 110315, 86879}},
+{14821, 18, 23473, {1, 3, 3, 5, 31, 35, 67, 67, 89, 933, 1005, 1837, 5947, 2559, 27731, 25151, 102959, 81557}},
+{14822, 18, 23500, {1, 3, 3, 1, 3, 39, 57, 199, 87, 91, 1641, 3407, 2823, 10441, 26357, 56677, 17647, 86831}},
+{14823, 18, 23511, {1, 3, 5, 7, 15, 5, 49, 227, 395, 837, 1707, 1677, 1907, 13101, 1929, 61701, 1479, 80671}},
+{14824, 18, 23548, {1, 1, 1, 11, 17, 57, 37, 151, 61, 709, 2027, 2239, 3283, 5467, 17221, 40759, 91637, 258167}},
+{14825, 18, 23560, {1, 3, 5, 11, 27, 29, 121, 181, 503, 705, 225, 1111, 7183, 3219, 3233, 2085, 113619, 32959}},
+{14826, 18, 23563, {1, 1, 7, 5, 29, 31, 93, 113, 457, 161, 337, 2003, 1865, 13357, 19961, 51485, 62751, 111285}},
+{14827, 18, 23594, {1, 3, 1, 1, 23, 25, 65, 99, 11, 835, 661, 3291, 2655, 1135, 19957, 5029, 110483, 2499}},
+{14828, 18, 23601, {1, 1, 1, 1, 25, 21, 59, 203, 471, 697, 455, 1561, 3215, 609, 5097, 8715, 115705, 21441}},
+{14829, 18, 23625, {1, 1, 5, 13, 27, 37, 15, 175, 191, 975, 977, 401, 7053, 14291, 14621, 48989, 113033, 172569}},
+{14830, 18, 23640, {1, 3, 1, 1, 19, 11, 125, 53, 307, 421, 93, 2487, 5907, 2195, 30569, 21009, 20759, 246937}},
+{14831, 18, 23650, {1, 3, 7, 3, 23, 21, 103, 115, 453, 537, 473, 1069, 3007, 15111, 3477, 5635, 46423, 68633}},
+{14832, 18, 23662, {1, 3, 3, 1, 21, 1, 49, 197, 173, 775, 1877, 1309, 729, 3555, 5981, 32539, 22765, 171077}},
+{14833, 18, 23692, {1, 1, 3, 13, 19, 5, 75, 149, 441, 665, 1567, 2433, 8173, 12639, 27479, 47221, 66203, 89017}},
+{14834, 18, 23726, {1, 1, 1, 11, 1, 55, 99, 119, 491, 621, 619, 2521, 905, 11601, 26481, 2023, 127413, 220387}},
+{14835, 18, 23738, {1, 1, 7, 11, 9, 21, 57, 93, 243, 229, 1445, 997, 1317, 2327, 14141, 45787, 82295, 72823}},
+{14836, 18, 23743, {1, 3, 7, 3, 11, 7, 115, 143, 349, 507, 1047, 2573, 2491, 13351, 19019, 4857, 62781, 261261}},
+{14837, 18, 23755, {1, 1, 3, 1, 1, 13, 45, 227, 41, 947, 693, 2853, 7459, 1485, 22087, 61195, 111771, 136389}},
+{14838, 18, 23760, {1, 1, 3, 11, 13, 53, 49, 15, 425, 29, 681, 1493, 1385, 9555, 13291, 36735, 12351, 29293}},
+{14839, 18, 23799, {1, 1, 3, 1, 5, 19, 37, 45, 69, 209, 365, 3949, 6163, 5207, 9297, 21147, 71437, 40487}},
+{14840, 18, 23848, {1, 3, 3, 13, 31, 21, 9, 177, 95, 285, 1953, 1969, 7367, 7401, 12017, 9939, 11895, 213133}},
+{14841, 18, 23859, {1, 1, 7, 1, 1, 63, 103, 141, 39, 679, 123, 2941, 4335, 199, 12237, 6599, 48641, 140063}},
+{14842, 18, 23876, {1, 3, 7, 3, 31, 17, 21, 77, 65, 979, 109, 3325, 1781, 6983, 31477, 23149, 33943, 96137}},
+{14843, 18, 23897, {1, 3, 3, 5, 21, 5, 125, 117, 427, 381, 511, 2643, 409, 4945, 3167, 45879, 1469, 56077}},
+{14844, 18, 23907, {1, 3, 1, 5, 27, 43, 83, 31, 65, 645, 1205, 1387, 723, 15359, 13517, 23601, 61717, 47079}},
+{14845, 18, 23919, {1, 3, 3, 13, 15, 37, 101, 175, 225, 513, 483, 1291, 669, 5335, 16023, 287, 51819, 239803}},
+{14846, 18, 23921, {1, 3, 3, 3, 3, 1, 75, 175, 185, 949, 673, 2239, 4355, 10687, 27093, 37409, 23193, 211819}},
+{14847, 18, 23931, {1, 1, 3, 13, 21, 3, 41, 55, 243, 501, 285, 7, 6291, 7725, 17051, 45753, 115117, 14323}},
+{14848, 18, 23933, {1, 1, 1, 5, 13, 11, 51, 175, 435, 673, 67, 1525, 323, 5739, 19977, 62317, 97511, 130883}},
+{14849, 18, 23943, {1, 3, 5, 11, 7, 11, 97, 59, 295, 409, 453, 2439, 5217, 10315, 469, 31187, 17325, 158079}},
+{14850, 18, 23957, {1, 1, 3, 5, 31, 9, 15, 63, 411, 427, 277, 2687, 5021, 1507, 22453, 35559, 122081, 121669}},
+{14851, 18, 23986, {1, 3, 5, 13, 3, 21, 69, 51, 27, 571, 1981, 2729, 5733, 1225, 26821, 43763, 57355, 169279}},
+{14852, 18, 24020, {1, 1, 1, 13, 31, 37, 33, 19, 313, 341, 1141, 1689, 4511, 789, 15317, 61263, 79371, 65157}},
+{14853, 18, 24043, {1, 3, 3, 15, 27, 41, 107, 23, 499, 339, 273, 1937, 2743, 10879, 27127, 64817, 1217, 45863}},
+{14854, 18, 24064, {1, 1, 5, 9, 19, 43, 125, 223, 473, 489, 1999, 1513, 6479, 9511, 12503, 29419, 22559, 209499}},
+{14855, 18, 24082, {1, 3, 1, 13, 25, 55, 53, 61, 303, 337, 1325, 2525, 6503, 1155, 6841, 58167, 8175, 183949}},
+{14856, 18, 24084, {1, 3, 3, 11, 3, 15, 55, 105, 497, 527, 1007, 3545, 4187, 8723, 12761, 20751, 101583, 225373}},
+{14857, 18, 24088, {1, 3, 3, 9, 19, 59, 57, 215, 313, 871, 407, 2475, 879, 15147, 31945, 23939, 104073, 217619}},
+{14858, 18, 24117, {1, 1, 3, 1, 27, 23, 3, 43, 471, 757, 1525, 3003, 2779, 6731, 12423, 59621, 72935, 192283}},
+{14859, 18, 24149, {1, 3, 1, 7, 13, 23, 13, 91, 95, 745, 639, 2627, 4595, 11735, 4143, 23573, 98647, 171201}},
+{14860, 18, 24165, {1, 1, 1, 15, 3, 61, 33, 181, 351, 777, 1365, 1691, 2465, 5289, 24567, 8059, 95301, 75855}},
+{14861, 18, 24223, {1, 3, 5, 13, 1, 57, 57, 187, 1, 601, 563, 1703, 1307, 14673, 7793, 44589, 7629, 254071}},
+{14862, 18, 24247, {1, 1, 5, 13, 29, 17, 61, 233, 371, 909, 529, 185, 127, 15773, 19529, 49271, 26749, 70869}},
+{14863, 18, 24259, {1, 1, 3, 9, 21, 41, 37, 71, 505, 969, 301, 1667, 5879, 13187, 2461, 17301, 103673, 235133}},
+{14864, 18, 24283, {1, 3, 1, 3, 9, 13, 75, 63, 313, 273, 1061, 3821, 539, 9887, 19775, 17259, 93133, 217245}},
+{14865, 18, 24296, {1, 3, 5, 5, 21, 27, 9, 11, 461, 575, 507, 577, 4559, 9995, 13953, 61023, 121941, 195419}},
+{14866, 18, 24336, {1, 3, 3, 7, 17, 17, 45, 193, 271, 571, 1337, 2107, 1923, 4791, 23773, 60923, 58085, 81219}},
+{14867, 18, 24342, {1, 3, 1, 7, 11, 7, 85, 33, 231, 307, 993, 1509, 1427, 9545, 7919, 39775, 81145, 79139}},
+{14868, 18, 24389, {1, 3, 5, 3, 9, 57, 117, 187, 57, 719, 1635, 2499, 6747, 6649, 22643, 16429, 83233, 122057}},
+{14869, 18, 24394, {1, 1, 3, 11, 7, 39, 103, 221, 167, 181, 1355, 989, 3399, 9471, 10493, 57267, 106551, 158599}},
+{14870, 18, 24414, {1, 3, 1, 15, 23, 19, 29, 11, 355, 923, 1401, 509, 3647, 5663, 2353, 53217, 70687, 145613}},
+{14871, 18, 24424, {1, 3, 3, 11, 11, 5, 21, 107, 177, 429, 119, 1029, 5931, 7543, 15455, 62797, 118095, 35387}},
+{14872, 18, 24441, {1, 3, 5, 15, 19, 53, 17, 215, 279, 497, 1157, 2235, 5541, 5899, 20711, 20843, 113821, 164231}},
+{14873, 18, 24491, {1, 1, 1, 15, 21, 33, 67, 247, 55, 573, 1863, 2703, 5267, 4071, 18235, 44659, 102379, 171529}},
+{14874, 18, 24502, {1, 3, 1, 15, 5, 59, 69, 189, 313, 243, 339, 3097, 4999, 5909, 1903, 56143, 76209, 83073}},
+{14875, 18, 24534, {1, 3, 5, 15, 11, 41, 65, 207, 95, 115, 1203, 3731, 6845, 11173, 8281, 40623, 97119, 218455}},
+{14876, 18, 24540, {1, 3, 7, 13, 29, 57, 5, 31, 255, 539, 107, 953, 3707, 9233, 20295, 17459, 2005, 56193}},
+{14877, 18, 24543, {1, 1, 1, 15, 5, 31, 83, 165, 211, 433, 1411, 2949, 4817, 1645, 1693, 9877, 118493, 142923}},
+{14878, 18, 24549, {1, 3, 1, 11, 19, 61, 35, 21, 159, 159, 1717, 3227, 3351, 8641, 20575, 13721, 114649, 129201}},
+{14879, 18, 24567, {1, 3, 1, 13, 9, 41, 17, 7, 209, 501, 445, 23, 7911, 5867, 30129, 643, 36363, 52037}},
+{14880, 18, 24583, {1, 3, 5, 11, 31, 55, 27, 81, 413, 167, 599, 2231, 7055, 4013, 26729, 63927, 12075, 208123}},
+{14881, 18, 24693, {1, 1, 7, 9, 11, 39, 99, 187, 169, 999, 609, 3647, 2497, 8969, 30919, 29145, 67699, 51601}},
+{14882, 18, 24704, {1, 3, 1, 1, 11, 11, 69, 29, 197, 979, 1135, 869, 5435, 5151, 26349, 55911, 68051, 131849}},
+{14883, 18, 24719, {1, 1, 1, 5, 27, 1, 85, 145, 439, 585, 1713, 677, 1833, 14139, 5547, 31265, 82223, 47605}},
+{14884, 18, 24749, {1, 3, 5, 9, 17, 23, 31, 199, 447, 551, 683, 2977, 7839, 8681, 15923, 61057, 89875, 52945}},
+{14885, 18, 24799, {1, 1, 3, 11, 9, 17, 29, 125, 195, 123, 1259, 2729, 3099, 2229, 9683, 13121, 105399, 111833}},
+{14886, 18, 24830, {1, 3, 1, 3, 1, 47, 93, 117, 461, 633, 1641, 933, 7927, 13569, 483, 28159, 121561, 164325}},
+{14887, 18, 24835, {1, 3, 1, 5, 21, 19, 79, 183, 395, 23, 767, 519, 4857, 10385, 12425, 26207, 114623, 37125}},
+{14888, 18, 24907, {1, 1, 5, 5, 9, 47, 67, 217, 499, 843, 1539, 301, 1485, 3157, 22375, 47199, 26215, 182785}},
+{14889, 18, 24917, {1, 1, 1, 13, 9, 37, 87, 49, 445, 681, 1097, 1049, 4093, 13167, 18447, 58243, 41797, 217929}},
+{14890, 18, 24940, {1, 1, 5, 13, 13, 49, 21, 149, 79, 113, 1217, 921, 6321, 9345, 27987, 21723, 49249, 18813}},
+{14891, 18, 24943, {1, 3, 1, 3, 15, 27, 67, 69, 131, 713, 1741, 1955, 5665, 8749, 11971, 11257, 13999, 124535}},
+{14892, 18, 24958, {1, 3, 1, 3, 3, 11, 21, 167, 441, 557, 593, 3261, 3099, 2801, 21725, 23247, 106891, 129187}},
+{14893, 18, 24962, {1, 1, 1, 11, 5, 55, 33, 71, 505, 85, 1609, 521, 5459, 12777, 13007, 255, 67537, 2877}},
+{14894, 18, 24964, {1, 1, 1, 3, 31, 47, 49, 119, 351, 797, 1407, 4089, 2381, 12409, 12849, 23489, 53631, 119387}},
+{14895, 18, 24968, {1, 3, 5, 11, 25, 11, 25, 185, 85, 849, 141, 385, 3663, 13133, 8451, 61463, 35129, 149933}},
+{14896, 18, 25015, {1, 3, 7, 9, 23, 17, 21, 197, 15, 893, 939, 707, 5491, 7249, 14009, 18973, 111545, 36809}},
+{14897, 18, 25024, {1, 3, 3, 13, 23, 15, 19, 193, 223, 627, 1529, 1963, 1003, 7199, 15361, 25233, 110281, 221761}},
+{14898, 18, 25027, {1, 3, 3, 1, 17, 51, 61, 215, 311, 919, 349, 59, 2897, 12137, 5931, 37611, 124387, 83503}},
+{14899, 18, 25033, {1, 3, 7, 9, 13, 47, 53, 139, 481, 733, 389, 1209, 3281, 593, 29103, 61521, 41445, 11015}},
+{14900, 18, 25041, {1, 1, 1, 13, 3, 31, 19, 47, 151, 883, 1707, 827, 2129, 4333, 871, 42967, 79701, 192211}},
+{14901, 18, 25047, {1, 3, 3, 11, 11, 51, 121, 241, 199, 881, 1493, 2381, 5161, 13287, 8155, 52481, 120307, 206203}},
+{14902, 18, 25057, {1, 1, 1, 13, 15, 37, 27, 151, 17, 851, 1343, 1447, 43, 10267, 18267, 21347, 129277, 83987}},
+{14903, 18, 25082, {1, 1, 3, 3, 13, 17, 53, 217, 253, 853, 1461, 1953, 617, 4209, 9925, 377, 42789, 150415}},
+{14904, 18, 25093, {1, 3, 7, 11, 13, 23, 83, 235, 39, 701, 1091, 25, 1807, 15431, 2169, 5339, 123679, 117053}},
+{14905, 18, 25105, {1, 3, 7, 13, 3, 29, 43, 149, 33, 873, 1177, 1961, 7943, 11317, 30725, 55765, 50929, 12335}},
+{14906, 18, 25112, {1, 1, 3, 5, 25, 1, 91, 121, 295, 25, 1743, 2125, 2643, 11175, 15089, 44979, 28355, 543}},
+{14907, 18, 25117, {1, 1, 1, 13, 27, 27, 43, 195, 377, 821, 437, 3445, 2673, 15221, 15101, 25143, 22347, 218549}},
+{14908, 18, 25131, {1, 1, 3, 7, 9, 51, 121, 231, 91, 913, 1325, 167, 8067, 8119, 9307, 33551, 58069, 170567}},
+{14909, 18, 25139, {1, 3, 7, 7, 15, 7, 85, 51, 11, 353, 1117, 2479, 3091, 2377, 23589, 38537, 113047, 261285}},
+{14910, 18, 25194, {1, 1, 3, 5, 15, 33, 61, 145, 147, 815, 767, 9, 2059, 11463, 1883, 8565, 101043, 117565}},
+{14911, 18, 25204, {1, 3, 5, 3, 5, 49, 5, 33, 15, 13, 895, 3973, 7963, 3831, 26817, 10799, 111409, 90679}},
+{14912, 18, 25244, {1, 1, 5, 7, 5, 51, 35, 237, 217, 531, 719, 2711, 1937, 16071, 23233, 22799, 66023, 145739}},
+{14913, 18, 25247, {1, 3, 5, 1, 5, 63, 1, 163, 9, 697, 1379, 2989, 7113, 9821, 15941, 6495, 7825, 29715}},
+{14914, 18, 25253, {1, 3, 5, 7, 9, 41, 113, 173, 151, 963, 2019, 3531, 1133, 4287, 16917, 16929, 12345, 31201}},
+{14915, 18, 25258, {1, 3, 7, 1, 25, 9, 5, 195, 175, 297, 717, 3725, 33, 5155, 4405, 56171, 105597, 132407}},
+{14916, 18, 25275, {1, 1, 7, 7, 3, 59, 115, 95, 227, 951, 843, 619, 7791, 10981, 11773, 57651, 108391, 179561}},
+{14917, 18, 25320, {1, 3, 3, 1, 9, 3, 59, 161, 417, 413, 1933, 1027, 4575, 10427, 15643, 16049, 120089, 176607}},
+{14918, 18, 25338, {1, 3, 3, 3, 15, 1, 83, 195, 59, 859, 1669, 1063, 2069, 15875, 16459, 53741, 114521, 37641}},
+{14919, 18, 25343, {1, 1, 1, 11, 11, 45, 47, 143, 11, 239, 1329, 865, 2693, 899, 26265, 43255, 125679, 130099}},
+{14920, 18, 25351, {1, 3, 5, 3, 31, 51, 95, 127, 79, 167, 117, 3177, 5875, 14039, 20341, 47815, 118799, 211871}},
+{14921, 18, 25358, {1, 1, 1, 1, 3, 21, 65, 203, 11, 565, 537, 1307, 8189, 11423, 7745, 56117, 110959, 95361}},
+{14922, 18, 25372, {1, 1, 7, 7, 21, 63, 63, 231, 441, 127, 1943, 13, 4813, 10607, 23867, 43891, 15801, 173245}},
+{14923, 18, 25399, {1, 3, 3, 5, 25, 23, 123, 133, 129, 303, 1993, 1453, 1109, 4649, 30315, 62399, 121575, 60069}},
+{14924, 18, 25408, {1, 3, 5, 3, 29, 23, 69, 141, 137, 1017, 1915, 35, 3817, 6249, 22427, 7281, 88473, 230167}},
+{14925, 18, 25432, {1, 3, 7, 7, 19, 37, 93, 217, 287, 731, 583, 3377, 2879, 4873, 5549, 52949, 127285, 211173}},
+{14926, 18, 25442, {1, 1, 5, 7, 23, 41, 49, 145, 277, 571, 1225, 455, 2133, 1229, 25421, 20179, 70919, 242825}},
+{14927, 18, 25462, {1, 3, 5, 5, 29, 3, 1, 89, 413, 901, 1343, 3963, 6969, 14649, 18331, 4573, 82077, 100693}},
+{14928, 18, 25465, {1, 1, 1, 13, 31, 53, 107, 95, 151, 539, 1593, 3763, 1007, 8959, 25235, 16461, 121819, 106143}},
+{14929, 18, 25468, {1, 1, 1, 3, 11, 15, 5, 157, 347, 81, 2013, 2025, 6541, 12287, 1315, 23285, 23539, 75027}},
+{14930, 18, 25482, {1, 1, 5, 7, 17, 11, 65, 157, 93, 607, 1445, 4089, 3139, 4699, 1225, 58935, 93673, 146467}},
+{14931, 18, 25489, {1, 3, 3, 13, 29, 59, 69, 141, 257, 463, 93, 649, 8179, 15205, 6943, 45317, 31269, 70825}},
+{14932, 18, 25490, {1, 3, 5, 9, 23, 39, 113, 61, 315, 463, 1739, 149, 6007, 2789, 12021, 969, 18551, 153669}},
+{14933, 18, 25505, {1, 1, 3, 15, 19, 9, 23, 211, 265, 877, 325, 2635, 8131, 4957, 24371, 60975, 3887, 198927}},
+{14934, 18, 25511, {1, 1, 3, 11, 29, 31, 5, 105, 157, 573, 2009, 1701, 1549, 1641, 17429, 13587, 48421, 8675}},
+{14935, 18, 25512, {1, 1, 5, 13, 3, 13, 17, 55, 101, 369, 705, 3635, 5195, 10439, 12881, 21565, 1671, 75489}},
+{14936, 18, 25552, {1, 3, 3, 1, 1, 23, 85, 189, 347, 205, 5, 3465, 3269, 3347, 10163, 26921, 86555, 9387}},
+{14937, 18, 25555, {1, 3, 7, 15, 27, 21, 79, 151, 279, 627, 1093, 1929, 5549, 12141, 5245, 55747, 65939, 193759}},
+{14938, 18, 25595, {1, 1, 1, 5, 5, 23, 57, 235, 143, 129, 795, 35, 4375, 12577, 871, 20879, 82811, 52279}},
+{14939, 18, 25636, {1, 3, 1, 5, 11, 1, 125, 99, 89, 629, 857, 2631, 393, 15075, 27473, 42695, 61505, 239651}},
+{14940, 18, 25672, {1, 1, 5, 1, 9, 11, 55, 203, 453, 677, 259, 1979, 4101, 16067, 26783, 17907, 75349, 62797}},
+{14941, 18, 25685, {1, 3, 7, 5, 5, 19, 85, 165, 341, 405, 1779, 87, 889, 265, 9851, 36175, 69697, 123769}},
+{14942, 18, 25696, {1, 3, 7, 1, 7, 49, 93, 57, 85, 597, 183, 3253, 6301, 9307, 8753, 38133, 58743, 19621}},
+{14943, 18, 25720, {1, 1, 3, 9, 1, 15, 125, 215, 391, 141, 87, 37, 4333, 5033, 30549, 64281, 18577, 156093}},
+{14944, 18, 25730, {1, 3, 3, 15, 17, 25, 29, 81, 339, 865, 1619, 773, 901, 8163, 22275, 57159, 119951, 137451}},
+{14945, 18, 25735, {1, 3, 5, 15, 7, 57, 113, 221, 13, 49, 1653, 3695, 4423, 4383, 28669, 64175, 130355, 202543}},
+{14946, 18, 25753, {1, 1, 3, 9, 29, 21, 19, 119, 409, 717, 1853, 3981, 4489, 3985, 31205, 10423, 13223, 131973}},
+{14947, 18, 25756, {1, 1, 3, 15, 29, 7, 1, 85, 133, 345, 317, 2363, 7803, 4975, 19441, 10497, 42059, 131531}},
+{14948, 18, 25769, {1, 1, 7, 13, 3, 53, 49, 27, 487, 901, 801, 335, 6317, 14205, 26655, 52747, 102659, 231359}},
+{14949, 18, 25821, {1, 3, 3, 3, 13, 33, 113, 107, 407, 499, 903, 3059, 1343, 11859, 6315, 23071, 73627, 44239}},
+{14950, 18, 25825, {1, 3, 5, 15, 1, 53, 59, 247, 213, 981, 443, 3, 615, 12067, 3881, 61759, 101219, 110407}},
+{14951, 18, 25840, {1, 3, 5, 13, 7, 31, 87, 161, 61, 1023, 147, 2075, 7245, 9025, 7229, 60935, 104481, 169561}},
+{14952, 18, 25860, {1, 3, 1, 15, 25, 17, 53, 107, 311, 621, 1493, 2443, 4635, 12163, 12543, 43031, 90843, 139645}},
+{14953, 18, 25869, {1, 3, 5, 11, 7, 49, 91, 165, 91, 329, 493, 3533, 7429, 7047, 14767, 31641, 62005, 77267}},
+{14954, 18, 25872, {1, 1, 3, 9, 31, 21, 19, 167, 185, 199, 1989, 1093, 4213, 4769, 21659, 19685, 122123, 215233}},
+{14955, 18, 25956, {1, 3, 3, 7, 27, 23, 99, 205, 365, 689, 1281, 419, 4207, 5355, 20245, 25029, 123029, 61499}},
+{14956, 18, 25973, {1, 3, 3, 7, 19, 15, 29, 185, 165, 203, 1859, 2895, 6361, 6331, 13641, 42577, 33757, 41305}},
+{14957, 18, 25994, {1, 3, 5, 11, 21, 43, 15, 11, 425, 125, 1597, 1109, 3335, 7009, 20799, 41261, 127813, 181261}},
+{14958, 18, 26002, {1, 1, 5, 5, 27, 35, 35, 159, 111, 1011, 1487, 813, 4985, 2555, 23741, 44675, 97159, 250477}},
+{14959, 18, 26020, {1, 3, 3, 7, 17, 41, 81, 187, 367, 767, 1345, 205, 5797, 9129, 21973, 39911, 130131, 96891}},
+{14960, 18, 26023, {1, 3, 5, 1, 1, 47, 57, 177, 127, 791, 1427, 1895, 5995, 12569, 32711, 58599, 55641, 80405}},
+{14961, 18, 26041, {1, 3, 3, 1, 23, 13, 115, 81, 511, 677, 775, 3143, 4963, 7093, 15963, 59893, 22609, 137601}},
+{14962, 18, 26044, {1, 1, 5, 9, 17, 17, 115, 127, 397, 139, 1171, 207, 3485, 15869, 465, 26267, 29957, 205459}},
+{14963, 18, 26069, {1, 3, 7, 3, 9, 29, 23, 189, 447, 481, 753, 2415, 2669, 6007, 15201, 7317, 18861, 173759}},
+{14964, 18, 26097, {1, 3, 5, 7, 13, 43, 13, 163, 363, 683, 1869, 1237, 2523, 3661, 13887, 5593, 91513, 220177}},
+{14965, 18, 26113, {1, 1, 1, 11, 7, 11, 43, 39, 319, 793, 375, 3159, 7621, 8965, 25743, 351, 31873, 18115}},
+{14966, 18, 26138, {1, 1, 5, 5, 11, 57, 79, 147, 55, 553, 417, 1365, 3979, 9789, 22677, 58645, 104549, 9019}},
+{14967, 18, 26167, {1, 1, 3, 11, 17, 37, 127, 5, 165, 867, 79, 2259, 197, 4789, 28109, 46721, 3431, 118939}},
+{14968, 18, 26216, {1, 1, 5, 13, 19, 45, 113, 11, 125, 351, 1753, 3201, 1697, 2567, 9717, 22247, 84309, 248583}},
+{14969, 18, 26230, {1, 1, 5, 9, 5, 37, 65, 47, 261, 855, 1573, 2267, 7977, 13029, 32527, 59805, 103591, 180041}},
+{14970, 18, 26243, {1, 3, 3, 9, 31, 5, 115, 159, 111, 899, 1907, 2671, 1575, 7021, 10281, 34905, 641, 63549}},
+{14971, 18, 26245, {1, 3, 5, 1, 17, 61, 45, 9, 375, 761, 117, 1767, 4657, 12217, 12067, 42807, 118587, 72715}},
+{14972, 18, 26263, {1, 1, 1, 13, 3, 3, 93, 3, 351, 97, 119, 1743, 81, 12761, 22529, 47191, 111315, 256501}},
+{14973, 18, 26264, {1, 1, 5, 7, 29, 23, 41, 9, 231, 567, 1565, 3539, 7241, 11535, 7375, 10391, 127045, 9371}},
+{14974, 18, 26269, {1, 1, 1, 15, 23, 47, 39, 57, 73, 809, 513, 3233, 8071, 8595, 13817, 821, 89091, 107173}},
+{14975, 18, 26311, {1, 1, 1, 13, 13, 43, 75, 239, 487, 175, 1561, 3925, 3743, 14247, 15713, 55005, 116135, 199827}},
+{14976, 18, 26346, {1, 1, 3, 7, 13, 15, 67, 147, 77, 241, 1763, 651, 1107, 4943, 15651, 23259, 45931, 34717}},
+{14977, 18, 26354, {1, 1, 3, 5, 15, 15, 67, 153, 163, 179, 1567, 685, 3245, 2205, 8373, 56567, 32091, 23313}},
+{14978, 18, 26365, {1, 1, 7, 9, 1, 27, 79, 209, 263, 517, 635, 3, 103, 2173, 22659, 11319, 103757, 144449}},
+{14979, 18, 26368, {1, 1, 1, 5, 11, 63, 21, 89, 443, 775, 327, 1559, 1421, 2309, 18597, 46385, 16547, 186813}},
+{14980, 18, 26398, {1, 1, 7, 9, 27, 37, 43, 7, 305, 117, 1103, 1801, 3349, 12225, 28215, 8857, 118677, 88909}},
+{14981, 18, 26401, {1, 3, 3, 7, 15, 59, 21, 19, 371, 81, 755, 1565, 4823, 16363, 20301, 33571, 74423, 177205}},
+{14982, 18, 26426, {1, 1, 3, 9, 15, 33, 23, 31, 171, 713, 271, 2437, 3609, 4271, 24355, 46283, 121767, 188501}},
+{14983, 18, 26436, {1, 1, 1, 1, 21, 3, 3, 241, 339, 211, 443, 1577, 343, 2625, 1077, 29933, 106401, 51439}},
+{14984, 18, 26443, {1, 3, 5, 15, 13, 31, 11, 167, 15, 101, 373, 2095, 3017, 1347, 15029, 6579, 21233, 87589}},
+{14985, 18, 26448, {1, 3, 1, 3, 15, 1, 61, 239, 13, 867, 1621, 2275, 5757, 8275, 7923, 44469, 113513, 84927}},
+{14986, 18, 26458, {1, 1, 1, 13, 23, 27, 101, 25, 459, 517, 127, 1131, 669, 13209, 23671, 3379, 66091, 72919}},
+{14987, 18, 26464, {1, 3, 5, 7, 29, 53, 25, 185, 101, 707, 281, 183, 2823, 7241, 3127, 48093, 20195, 208349}},
+{14988, 18, 26476, {1, 3, 3, 15, 31, 11, 3, 165, 453, 609, 1053, 3937, 1989, 13887, 13415, 8005, 103537, 17853}},
+{14989, 18, 26503, {1, 1, 3, 7, 3, 41, 13, 67, 227, 265, 767, 391, 1835, 8827, 13131, 42605, 117089, 12475}},
+{14990, 18, 26504, {1, 1, 7, 3, 15, 31, 45, 157, 261, 207, 1109, 1587, 5389, 13239, 31697, 35969, 79839, 209633}},
+{14991, 18, 26515, {1, 1, 5, 9, 31, 3, 35, 187, 5, 945, 633, 2645, 171, 2221, 18369, 41765, 82373, 8007}},
+{14992, 18, 26531, {1, 1, 7, 7, 3, 57, 73, 103, 245, 811, 1637, 101, 6335, 9911, 663, 21779, 31681, 119141}},
+{14993, 18, 26548, {1, 1, 5, 13, 27, 25, 5, 203, 183, 251, 1803, 665, 6295, 965, 5269, 379, 78455, 7097}},
+{14994, 18, 26570, {1, 1, 5, 3, 19, 55, 45, 161, 481, 737, 1903, 1093, 3313, 4427, 7959, 6231, 94769, 123827}},
+{14995, 18, 26589, {1, 1, 7, 11, 29, 41, 77, 165, 49, 875, 137, 2003, 8093, 1941, 25979, 10765, 99241, 71275}},
+{14996, 18, 26594, {1, 3, 5, 3, 23, 1, 89, 163, 293, 701, 29, 2543, 4487, 14873, 28123, 48643, 31633, 74179}},
+{14997, 18, 26608, {1, 1, 7, 1, 13, 33, 33, 173, 111, 959, 205, 1633, 3127, 3963, 6455, 41809, 60655, 247121}},
+{14998, 18, 26623, {1, 3, 5, 13, 1, 49, 87, 217, 381, 125, 823, 837, 3967, 8157, 11097, 35721, 93591, 3939}},
+{14999, 18, 26678, {1, 3, 7, 1, 7, 27, 29, 21, 295, 127, 823, 2409, 1873, 2417, 27961, 39211, 14785, 71557}},
+{15000, 18, 26690, {1, 3, 1, 5, 31, 59, 43, 121, 217, 417, 2029, 3983, 5629, 10447, 1073, 57515, 58849, 178927}},
+{15001, 18, 26709, {1, 3, 3, 11, 5, 59, 45, 39, 269, 483, 757, 3245, 4383, 11127, 26535, 17395, 60953, 259333}},
+{15002, 18, 26725, {1, 1, 1, 5, 5, 49, 81, 241, 371, 353, 1293, 3375, 6725, 11891, 5973, 13901, 37999, 17751}},
+{15003, 18, 26744, {1, 3, 3, 7, 31, 21, 45, 107, 33, 911, 1869, 2643, 2655, 3979, 5509, 33065, 128463, 246937}},
+{15004, 18, 26763, {1, 1, 1, 1, 31, 33, 99, 29, 485, 11, 1423, 1775, 2045, 741, 30691, 53957, 13891, 57303}},
+{15005, 18, 26765, {1, 1, 7, 13, 7, 37, 117, 121, 51, 743, 887, 1769, 1049, 12859, 1663, 27763, 90969, 38935}},
+{15006, 18, 26768, {1, 3, 5, 7, 3, 41, 121, 89, 461, 979, 457, 2973, 8109, 13819, 30237, 54671, 66967, 135233}},
+{15007, 18, 26784, {1, 1, 7, 13, 13, 47, 51, 121, 295, 847, 681, 1163, 8123, 14179, 26561, 54057, 74043, 146155}},
+{15008, 18, 26802, {1, 3, 3, 11, 21, 15, 9, 85, 445, 11, 1525, 3165, 5929, 12481, 10769, 31885, 51487, 248933}},
+{15009, 18, 26814, {1, 3, 1, 9, 25, 41, 59, 139, 293, 1021, 2043, 967, 3949, 7309, 6545, 62761, 37761, 22395}},
+{15010, 18, 26856, {1, 3, 7, 15, 25, 45, 29, 75, 283, 845, 687, 3285, 7263, 10237, 5343, 58635, 85137, 2387}},
+{15011, 18, 26861, {1, 1, 3, 15, 29, 33, 111, 175, 251, 181, 709, 1373, 1661, 1155, 30479, 57823, 28809, 74117}},
+{15012, 18, 26862, {1, 3, 3, 5, 11, 37, 55, 155, 439, 173, 1861, 1713, 1675, 12119, 12531, 50995, 124657, 58321}},
+{15013, 18, 26894, {1, 1, 5, 13, 1, 23, 27, 141, 3, 985, 1439, 781, 7381, 2223, 26673, 46607, 54953, 24547}},
+{15014, 18, 26908, {1, 1, 5, 7, 5, 3, 41, 115, 503, 731, 633, 3631, 3455, 15937, 22639, 41163, 65243, 233749}},
+{15015, 18, 26915, {1, 3, 1, 1, 5, 57, 89, 35, 53, 653, 1763, 1247, 6999, 1811, 28191, 52327, 129421, 191093}},
+{15016, 18, 26929, {1, 3, 3, 9, 3, 27, 107, 13, 475, 409, 1623, 483, 3127, 12841, 4777, 36157, 24967, 89795}},
+{15017, 18, 26930, {1, 1, 3, 5, 7, 29, 15, 225, 257, 923, 251, 21, 4559, 3571, 9351, 1739, 37393, 170789}},
+{15018, 18, 26939, {1, 3, 7, 5, 11, 7, 107, 237, 343, 665, 767, 2293, 4781, 4811, 11227, 25045, 3951, 44307}},
+{15019, 18, 26941, {1, 3, 7, 7, 13, 31, 47, 9, 121, 441, 1011, 2015, 8053, 355, 13441, 23213, 60675, 259761}},
+{15020, 18, 26987, {1, 1, 5, 9, 21, 61, 85, 141, 271, 577, 17, 243, 3049, 2479, 28947, 53351, 67379, 211133}},
+{15021, 18, 27023, {1, 1, 1, 15, 23, 1, 119, 141, 311, 543, 1463, 3633, 8111, 9439, 4147, 64913, 28261, 197217}},
+{15022, 18, 27066, {1, 3, 1, 15, 15, 33, 125, 231, 225, 797, 605, 259, 3673, 10423, 7541, 26289, 61681, 136463}},
+{15023, 18, 27079, {1, 3, 1, 13, 23, 15, 15, 151, 289, 657, 1883, 2923, 6861, 1411, 17159, 9353, 79463, 135813}},
+{15024, 18, 27086, {1, 3, 7, 11, 5, 59, 101, 167, 291, 63, 753, 1105, 8173, 2389, 22097, 7207, 110377, 15797}},
+{15025, 18, 27091, {1, 3, 7, 15, 7, 9, 7, 135, 303, 675, 1803, 2827, 1711, 9543, 16567, 24075, 17065, 22193}},
+{15026, 18, 27113, {1, 3, 5, 7, 17, 7, 125, 57, 423, 733, 1813, 4031, 713, 10687, 27315, 37599, 78807, 103429}},
+{15027, 18, 27157, {1, 1, 5, 15, 21, 11, 87, 21, 415, 571, 1169, 2561, 7071, 12499, 195, 20111, 116757, 157731}},
+{15028, 18, 27174, {1, 3, 3, 15, 7, 33, 11, 241, 23, 189, 599, 2891, 2829, 13327, 21777, 57733, 38583, 162161}},
+{15029, 18, 27188, {1, 1, 1, 15, 3, 49, 7, 143, 291, 301, 1439, 793, 3447, 1167, 2815, 24875, 117437, 112561}},
+{15030, 18, 27191, {1, 3, 5, 13, 29, 11, 51, 255, 365, 741, 1919, 2091, 2865, 12721, 4329, 37281, 128703, 739}},
+{15031, 18, 27197, {1, 1, 1, 13, 19, 31, 39, 141, 81, 133, 297, 3837, 7537, 16043, 11755, 10289, 74399, 95371}},
+{15032, 18, 27206, {1, 1, 7, 5, 21, 35, 125, 109, 241, 217, 1219, 2617, 1925, 9573, 19305, 44689, 89365, 248869}},
+{15033, 18, 27210, {1, 3, 5, 5, 13, 33, 43, 221, 325, 267, 837, 809, 6025, 9847, 9267, 13465, 45937, 204339}},
+{15034, 18, 27245, {1, 3, 1, 3, 25, 53, 85, 249, 105, 619, 917, 1213, 5365, 6197, 22929, 27529, 71011, 141651}},
+{15035, 18, 27254, {1, 1, 5, 1, 29, 9, 27, 161, 269, 775, 1043, 303, 4503, 5059, 479, 17237, 51383, 152495}},
+{15036, 18, 27383, {1, 3, 1, 5, 19, 5, 127, 139, 1, 461, 943, 593, 7457, 3357, 1909, 64633, 91811, 92703}},
+{15037, 18, 27387, {1, 1, 5, 7, 1, 21, 83, 29, 123, 83, 1085, 2727, 651, 15801, 20561, 34821, 17671, 162227}},
+{15038, 18, 27416, {1, 3, 7, 1, 19, 59, 33, 195, 81, 69, 51, 1473, 3873, 4247, 3587, 4293, 30831, 245345}},
+{15039, 18, 27422, {1, 3, 1, 3, 23, 27, 19, 115, 275, 293, 705, 131, 1001, 8881, 30165, 25149, 38679, 175167}},
+{15040, 18, 27472, {1, 1, 3, 15, 11, 11, 79, 55, 323, 217, 859, 897, 6567, 12529, 3161, 13009, 100787, 3501}},
+{15041, 18, 27478, {1, 3, 1, 15, 17, 63, 51, 71, 55, 207, 1095, 2527, 611, 9281, 7375, 14553, 16021, 88537}},
+{15042, 18, 27548, {1, 1, 7, 9, 11, 23, 95, 25, 327, 873, 575, 3583, 6587, 137, 23737, 59341, 83281, 93541}},
+{15043, 18, 27579, {1, 1, 5, 7, 15, 37, 89, 105, 471, 757, 103, 3747, 3565, 4957, 23537, 16193, 84843, 256757}},
+{15044, 18, 27582, {1, 3, 5, 1, 15, 17, 119, 231, 387, 715, 797, 3807, 4985, 8335, 4885, 45541, 69597, 238599}},
+{15045, 18, 27589, {1, 1, 3, 1, 7, 21, 87, 205, 39, 503, 433, 3643, 4719, 2051, 10049, 28997, 75981, 253647}},
+{15046, 18, 27593, {1, 3, 1, 13, 9, 21, 103, 63, 27, 267, 185, 3507, 3009, 5183, 2261, 40249, 33733, 70493}},
+{15047, 18, 27613, {1, 1, 3, 13, 7, 7, 79, 13, 141, 327, 1035, 1699, 6273, 5621, 13877, 57607, 50207, 184643}},
+{15048, 18, 27649, {1, 1, 3, 1, 9, 19, 75, 99, 115, 469, 1025, 1999, 1985, 9975, 11069, 59113, 80877, 124153}},
+{15049, 18, 27717, {1, 3, 5, 7, 19, 27, 47, 3, 313, 575, 107, 991, 2575, 11001, 12323, 21443, 126245, 219649}},
+{15050, 18, 27729, {1, 1, 1, 5, 19, 33, 13, 1, 357, 225, 1355, 1827, 7127, 6387, 19299, 24935, 26847, 251433}},
+{15051, 18, 27751, {1, 1, 1, 5, 3, 3, 113, 19, 425, 209, 159, 347, 1349, 6771, 13125, 8393, 21435, 186369}},
+{15052, 18, 27757, {1, 1, 5, 11, 5, 39, 95, 3, 193, 741, 1755, 3361, 1927, 12909, 5413, 29111, 123429, 109191}},
+{15053, 18, 27766, {1, 1, 1, 13, 31, 23, 43, 163, 421, 719, 457, 3149, 7741, 1465, 15719, 42831, 99051, 164675}},
+{15054, 18, 27791, {1, 1, 1, 7, 15, 1, 29, 15, 9, 577, 269, 31, 4361, 5081, 32185, 54869, 115105, 151233}},
+{15055, 18, 27794, {1, 1, 1, 11, 19, 3, 67, 3, 377, 487, 1287, 3463, 6523, 15237, 3171, 38673, 7359, 29739}},
+{15056, 18, 27854, {1, 3, 5, 11, 9, 13, 47, 191, 97, 641, 807, 1085, 1537, 2855, 24615, 32383, 66425, 53713}},
+{15057, 18, 27856, {1, 1, 5, 7, 19, 25, 93, 1, 21, 853, 813, 2535, 4291, 9051, 3385, 507, 73889, 85397}},
+{15058, 18, 27866, {1, 1, 3, 13, 7, 15, 103, 199, 83, 585, 1859, 2089, 839, 8923, 14615, 3399, 7703, 229937}},
+{15059, 18, 27875, {1, 1, 3, 3, 11, 23, 125, 135, 475, 613, 327, 339, 3081, 13221, 4889, 41233, 36547, 195357}},
+{15060, 18, 27902, {1, 3, 7, 7, 19, 23, 85, 217, 501, 447, 1873, 2175, 6753, 2825, 5171, 47561, 13321, 59583}},
+{15061, 18, 27916, {1, 1, 5, 13, 23, 59, 109, 195, 487, 785, 21, 1595, 5641, 10103, 8115, 60647, 78425, 237379}},
+{15062, 18, 27924, {1, 1, 3, 15, 21, 17, 85, 51, 369, 475, 1021, 1129, 7233, 6593, 12467, 55399, 128157, 80539}},
+{15063, 18, 27933, {1, 3, 3, 9, 31, 27, 69, 145, 489, 251, 1997, 1157, 2027, 16109, 4085, 24859, 63561, 79591}},
+{15064, 18, 27940, {1, 3, 3, 5, 29, 49, 41, 185, 405, 471, 431, 3539, 6593, 1185, 24383, 17009, 111215, 79839}},
+{15065, 18, 27947, {1, 1, 7, 3, 3, 15, 97, 157, 301, 227, 717, 3291, 2471, 11515, 30657, 30745, 72147, 98653}},
+{15066, 18, 27969, {1, 3, 5, 1, 23, 21, 67, 223, 185, 385, 137, 2897, 2423, 6119, 28471, 52269, 95725, 9105}},
+{15067, 18, 27981, {1, 3, 3, 11, 19, 1, 111, 131, 293, 495, 1043, 631, 1375, 15347, 22029, 29163, 120025, 81631}},
+{15068, 18, 27996, {1, 1, 7, 5, 17, 55, 47, 183, 367, 81, 555, 2857, 4787, 5605, 32053, 11815, 81771, 234993}},
+{15069, 18, 28005, {1, 3, 7, 15, 15, 49, 45, 221, 49, 299, 887, 3991, 2097, 10819, 23297, 1823, 11319, 205273}},
+{15070, 18, 28030, {1, 1, 1, 1, 1, 15, 91, 253, 213, 849, 501, 1073, 5503, 1379, 28887, 51811, 109763, 226149}},
+{15071, 18, 28064, {1, 1, 1, 7, 27, 39, 17, 29, 359, 655, 1695, 1781, 1203, 1125, 8983, 3477, 13925, 218399}},
+{15072, 18, 28102, {1, 3, 7, 13, 1, 25, 33, 185, 87, 19, 151, 371, 1221, 4859, 20103, 11435, 104263, 218515}},
+{15073, 18, 28108, {1, 1, 3, 5, 17, 43, 29, 149, 207, 39, 1539, 2933, 6825, 12391, 18163, 24543, 35305, 196295}},
+{15074, 18, 28120, {1, 3, 7, 9, 21, 61, 69, 231, 401, 95, 1757, 839, 3395, 7573, 6583, 34621, 119303, 20767}},
+{15075, 18, 28125, {1, 1, 7, 1, 25, 53, 63, 105, 241, 591, 23, 3219, 2387, 13945, 3047, 30939, 63243, 60941}},
+{15076, 18, 28130, {1, 1, 5, 7, 25, 47, 7, 227, 57, 279, 81, 4017, 3117, 6229, 20029, 30031, 25049, 102291}},
+{15077, 18, 28142, {1, 3, 3, 1, 21, 15, 69, 57, 311, 9, 853, 3377, 2949, 4781, 15419, 54741, 11603, 136821}},
+{15078, 18, 28149, {1, 3, 3, 13, 13, 5, 103, 253, 27, 449, 821, 3241, 41, 6643, 15217, 61691, 58463, 46117}},
+{15079, 18, 28165, {1, 1, 7, 7, 27, 51, 1, 239, 71, 955, 145, 1059, 5645, 7025, 4839, 11459, 3051, 235989}},
+{15080, 18, 28169, {1, 1, 5, 15, 15, 13, 33, 21, 209, 681, 1163, 3109, 1441, 6895, 20829, 48769, 35373, 195171}},
+{15081, 18, 28177, {1, 1, 7, 3, 11, 7, 25, 27, 463, 77, 1293, 1977, 4931, 8089, 11079, 14793, 123049, 32259}},
+{15082, 18, 28211, {1, 3, 1, 15, 11, 49, 7, 103, 79, 773, 235, 1653, 6477, 8835, 26627, 61101, 40633, 98155}},
+{15083, 18, 28213, {1, 3, 5, 7, 3, 53, 77, 197, 49, 57, 1533, 3485, 6603, 1131, 9073, 37023, 85293, 170883}},
+{15084, 18, 28220, {1, 3, 7, 15, 23, 5, 125, 75, 413, 521, 1897, 1099, 35, 2013, 687, 51511, 21359, 19995}},
+{15085, 18, 28261, {1, 3, 1, 11, 19, 13, 91, 181, 39, 613, 1917, 3149, 669, 9927, 20967, 38313, 13537, 181873}},
+{15086, 18, 28271, {1, 3, 5, 7, 5, 23, 25, 145, 189, 679, 483, 2689, 2855, 9631, 8863, 34841, 83311, 211507}},
+{15087, 18, 28299, {1, 3, 5, 15, 15, 15, 87, 53, 309, 807, 1405, 259, 3181, 12187, 31529, 8861, 70557, 247787}},
+{15088, 18, 28326, {1, 1, 7, 13, 7, 15, 1, 205, 91, 325, 1371, 531, 4917, 10291, 30827, 32491, 34497, 250301}},
+{15089, 18, 28330, {1, 3, 1, 11, 29, 17, 97, 37, 259, 1021, 1705, 4001, 4385, 7047, 14593, 63443, 3283, 18195}},
+{15090, 18, 28350, {1, 1, 7, 9, 9, 55, 11, 113, 351, 513, 197, 873, 1595, 11331, 27711, 419, 73097, 144357}},
+{15091, 18, 28355, {1, 3, 7, 15, 29, 31, 37, 15, 233, 573, 1457, 293, 5437, 15909, 3087, 24535, 6507, 173555}},
+{15092, 18, 28367, {1, 1, 1, 7, 7, 47, 81, 241, 257, 389, 233, 3275, 919, 14911, 14473, 58457, 78195, 121421}},
+{15093, 18, 28376, {1, 3, 7, 13, 1, 63, 9, 233, 231, 771, 1851, 3829, 7089, 4573, 13297, 58963, 2065, 8365}},
+{15094, 18, 28379, {1, 1, 5, 1, 31, 45, 45, 209, 77, 977, 159, 1521, 969, 10115, 32387, 52821, 124209, 51841}},
+{15095, 18, 28381, {1, 3, 5, 5, 13, 27, 53, 171, 91, 743, 217, 3805, 7721, 15127, 20679, 57459, 53649, 16381}},
+{15096, 18, 28447, {1, 3, 1, 15, 23, 43, 105, 169, 143, 759, 463, 1237, 3311, 2919, 16675, 53049, 12403, 153651}},
+{15097, 18, 28465, {1, 3, 3, 11, 5, 27, 1, 135, 17, 683, 679, 2591, 2929, 12417, 18379, 61903, 81991, 25231}},
+{15098, 18, 28471, {1, 1, 1, 5, 13, 59, 73, 119, 369, 445, 553, 243, 7523, 1105, 20349, 8417, 87535, 148857}},
+{15099, 18, 28472, {1, 3, 7, 15, 29, 3, 49, 49, 7, 753, 1597, 1427, 7485, 9119, 17427, 24961, 114897, 62841}},
+{15100, 18, 28478, {1, 1, 7, 7, 17, 35, 49, 225, 267, 801, 1359, 2131, 6093, 3859, 11305, 6287, 106459, 31093}},
+{15101, 18, 28480, {1, 1, 5, 3, 1, 45, 19, 89, 145, 23, 1071, 3053, 3463, 6781, 8635, 1961, 54403, 183401}},
+{15102, 18, 28489, {1, 3, 1, 13, 17, 35, 105, 155, 145, 597, 1169, 3731, 725, 2185, 23365, 31849, 113717, 185413}},
+{15103, 18, 28514, {1, 3, 3, 5, 3, 5, 13, 119, 39, 383, 1595, 63, 7003, 6465, 19847, 37213, 42921, 254479}},
+{15104, 18, 28525, {1, 3, 3, 1, 3, 33, 43, 255, 227, 151, 1911, 2657, 6529, 3855, 24411, 8485, 30385, 193265}},
+{15105, 18, 28537, {1, 1, 7, 7, 21, 53, 101, 37, 193, 107, 1095, 369, 6423, 3491, 1219, 53385, 31041, 122587}},
+{15106, 18, 28550, {1, 1, 7, 3, 13, 39, 101, 109, 113, 201, 619, 2489, 4545, 5017, 25519, 44281, 128605, 128595}},
+{15107, 18, 28559, {1, 1, 3, 13, 25, 7, 99, 141, 465, 625, 667, 1633, 6719, 16195, 365, 34355, 65025, 128025}},
+{15108, 18, 28595, {1, 1, 1, 7, 15, 51, 43, 159, 223, 493, 411, 65, 5753, 10219, 21885, 33267, 116643, 76777}},
+{15109, 18, 28601, {1, 3, 5, 13, 25, 39, 97, 31, 245, 367, 685, 103, 4093, 10449, 3849, 52659, 63355, 262059}},
+{15110, 18, 28629, {1, 3, 3, 1, 9, 49, 25, 157, 107, 821, 265, 2939, 6365, 7539, 17935, 50147, 88907, 214317}},
+{15111, 18, 28657, {1, 1, 1, 13, 17, 5, 55, 217, 137, 915, 121, 3187, 3111, 7145, 30477, 20023, 71969, 179417}},
+{15112, 18, 28667, {1, 1, 1, 5, 7, 15, 47, 71, 197, 725, 523, 2207, 5729, 741, 8595, 39125, 25431, 101093}},
+{15113, 18, 28711, {1, 3, 1, 7, 19, 37, 117, 235, 353, 459, 207, 953, 4955, 14979, 22897, 53911, 7783, 203667}},
+{15114, 18, 28718, {1, 1, 5, 13, 9, 17, 21, 95, 37, 751, 1463, 2491, 791, 1569, 32055, 61415, 113885, 259285}},
+{15115, 18, 28730, {1, 1, 3, 11, 1, 23, 5, 73, 61, 719, 215, 469, 3267, 12003, 16535, 46913, 58321, 2407}},
+{15116, 18, 28732, {1, 1, 5, 11, 5, 9, 81, 1, 275, 877, 791, 1591, 2109, 9983, 29085, 15069, 44757, 17887}},
+{15117, 18, 28777, {1, 3, 7, 11, 23, 47, 121, 53, 55, 677, 1239, 2591, 579, 11321, 14231, 53701, 71947, 56793}},
+{15118, 18, 28801, {1, 1, 5, 1, 7, 31, 39, 205, 231, 843, 159, 2301, 7765, 3317, 8935, 60647, 110545, 142543}},
+{15119, 18, 28822, {1, 3, 3, 11, 25, 39, 9, 131, 145, 373, 41, 1687, 417, 9427, 8657, 18315, 18505, 144055}},
+{15120, 18, 28855, {1, 3, 7, 3, 1, 51, 61, 223, 409, 607, 1281, 1767, 4719, 10741, 21537, 17307, 5473, 76127}},
+{15121, 18, 28859, {1, 1, 1, 1, 1, 43, 35, 157, 183, 835, 1141, 3235, 1383, 11381, 4503, 20435, 73125, 196955}},
+{15122, 18, 28869, {1, 1, 5, 7, 13, 47, 9, 191, 349, 587, 1887, 3667, 619, 9443, 28781, 7759, 6023, 81595}},
+{15123, 18, 28893, {1, 3, 5, 9, 31, 27, 77, 47, 375, 229, 989, 1241, 4937, 5881, 18797, 21743, 49947, 246165}},
+{15124, 18, 28904, {1, 1, 5, 1, 29, 23, 43, 237, 293, 391, 243, 3471, 5205, 9951, 29329, 19873, 114325, 19239}},
+{15125, 18, 28922, {1, 3, 3, 5, 19, 49, 23, 149, 419, 23, 21, 515, 3321, 3157, 28559, 8521, 11119, 192881}},
+{15126, 18, 28930, {1, 3, 1, 9, 29, 17, 15, 13, 171, 57, 1849, 3815, 7361, 7723, 23657, 60883, 54953, 159861}},
+{15127, 18, 28949, {1, 1, 3, 5, 13, 57, 35, 227, 143, 725, 2023, 2583, 2277, 4721, 4395, 61479, 112487, 211861}},
+{15128, 18, 28972, {1, 1, 5, 7, 7, 25, 83, 95, 281, 931, 415, 1661, 1543, 5313, 13317, 21203, 23965, 60891}},
+{15129, 18, 29002, {1, 3, 3, 1, 25, 51, 65, 147, 7, 521, 235, 2165, 6219, 14247, 30621, 43245, 8133, 49481}},
+{15130, 18, 29009, {1, 1, 5, 11, 13, 27, 39, 51, 213, 811, 151, 1157, 7821, 6481, 32097, 12319, 52005, 33291}},
+{15131, 18, 29061, {1, 1, 1, 13, 19, 15, 39, 205, 481, 253, 1643, 2969, 3181, 13995, 29877, 1307, 101721, 119111}},
+{15132, 18, 29068, {1, 1, 1, 11, 5, 63, 57, 53, 187, 315, 1521, 847, 5955, 3179, 21459, 25937, 83215, 181599}},
+{15133, 18, 29107, {1, 1, 7, 13, 17, 35, 113, 73, 105, 497, 1183, 3397, 4443, 14697, 29201, 40737, 40943, 3529}},
+{15134, 18, 29119, {1, 3, 5, 5, 3, 53, 101, 125, 173, 137, 333, 381, 1143, 1165, 789, 50013, 23595, 50235}},
+{15135, 18, 29142, {1, 1, 3, 1, 23, 3, 21, 143, 475, 337, 1693, 2341, 6509, 4167, 21031, 13887, 83191, 85187}},
+{15136, 18, 29146, {1, 1, 3, 1, 29, 59, 39, 217, 77, 943, 1531, 383, 6535, 2593, 8601, 61865, 26629, 57313}},
+{15137, 18, 29152, {1, 3, 5, 15, 17, 15, 19, 31, 273, 507, 1193, 2501, 4677, 13355, 5287, 1155, 102959, 185219}},
+{15138, 18, 29200, {1, 1, 1, 9, 3, 3, 5, 111, 159, 913, 331, 303, 3673, 12227, 5245, 63749, 107123, 26315}},
+{15139, 18, 29206, {1, 3, 5, 11, 13, 13, 115, 237, 481, 793, 1783, 1107, 4811, 3965, 29571, 63237, 15013, 176925}},
+{15140, 18, 29245, {1, 1, 7, 1, 13, 57, 85, 15, 19, 889, 1637, 1721, 6299, 6659, 5541, 24365, 38363, 67749}},
+{15141, 18, 29254, {1, 1, 3, 1, 9, 39, 15, 183, 133, 821, 1361, 2617, 7197, 8251, 12599, 60549, 42947, 72519}},
+{15142, 18, 29258, {1, 3, 1, 5, 19, 17, 69, 189, 309, 33, 2003, 569, 6189, 7845, 22351, 14623, 35287, 160511}},
+{15143, 18, 29260, {1, 1, 7, 13, 25, 3, 1, 203, 163, 661, 513, 3513, 741, 16259, 29817, 6059, 23823, 51869}},
+{15144, 18, 29268, {1, 3, 3, 1, 9, 43, 59, 77, 465, 223, 2007, 2187, 1499, 9373, 10535, 22207, 111689, 108485}},
+{15145, 18, 29281, {1, 1, 5, 15, 1, 21, 87, 163, 177, 751, 115, 3981, 4257, 5345, 31211, 44075, 16983, 69783}},
+{15146, 18, 29306, {1, 1, 1, 3, 29, 31, 7, 41, 181, 979, 1661, 1403, 2577, 983, 545, 6205, 20183, 44735}},
+{15147, 18, 29317, {1, 3, 3, 15, 5, 1, 85, 243, 59, 161, 1053, 803, 1813, 13583, 2559, 62761, 105337, 83209}},
+{15148, 18, 29324, {1, 3, 3, 3, 5, 21, 101, 61, 379, 369, 1865, 3289, 2643, 951, 26493, 17915, 8185, 42387}},
+{15149, 18, 29342, {1, 3, 5, 15, 15, 13, 119, 103, 141, 735, 1317, 3345, 2885, 4145, 30719, 965, 10819, 90295}},
+{15150, 18, 29375, {1, 3, 7, 13, 15, 11, 19, 163, 495, 369, 1285, 609, 1559, 9965, 31123, 55101, 76743, 104435}},
+{15151, 18, 29384, {1, 1, 5, 1, 25, 5, 5, 139, 441, 447, 353, 1369, 959, 14593, 30991, 20651, 126945, 2219}},
+{15152, 18, 29389, {1, 3, 5, 9, 21, 9, 113, 83, 115, 15, 161, 1559, 3095, 1447, 10253, 51481, 114541, 248375}},
+{15153, 18, 29411, {1, 3, 3, 1, 31, 61, 111, 69, 495, 195, 1153, 2605, 5061, 15509, 8253, 41909, 126033, 51173}},
+{15154, 18, 29413, {1, 1, 7, 15, 15, 41, 121, 75, 471, 539, 341, 441, 5357, 11509, 32525, 65477, 101251, 164835}},
+{15155, 18, 29446, {1, 1, 5, 7, 3, 63, 13, 123, 285, 499, 1023, 3533, 483, 13747, 26515, 52381, 9073, 256319}},
+{15156, 18, 29457, {1, 3, 1, 13, 29, 41, 75, 43, 229, 557, 1775, 1933, 5567, 11439, 22045, 10571, 96761, 98559}},
+{15157, 18, 29458, {1, 1, 3, 11, 19, 39, 3, 93, 435, 433, 2005, 1561, 385, 15865, 19763, 44105, 48107, 163063}},
+{15158, 18, 29483, {1, 1, 7, 5, 29, 37, 53, 19, 335, 325, 133, 2055, 3029, 14573, 30395, 38599, 97637, 203443}},
+{15159, 18, 29488, {1, 1, 7, 15, 29, 51, 7, 145, 21, 955, 1013, 579, 4971, 4849, 11691, 23725, 71079, 102641}},
+{15160, 18, 29494, {1, 1, 7, 3, 9, 49, 79, 187, 237, 823, 1951, 2947, 3633, 9119, 14393, 52969, 44703, 222389}},
+{15161, 18, 29506, {1, 3, 5, 11, 13, 9, 13, 245, 499, 661, 1899, 1313, 6907, 12259, 4577, 38547, 79687, 17555}},
+{15162, 18, 29553, {1, 3, 3, 1, 5, 59, 123, 197, 293, 247, 687, 695, 7493, 3115, 28535, 44335, 31905, 81607}},
+{15163, 18, 29569, {1, 3, 1, 3, 19, 5, 45, 101, 457, 395, 565, 3155, 8081, 4863, 1199, 32133, 73087, 27025}},
+{15164, 18, 29587, {1, 3, 7, 1, 31, 35, 111, 95, 379, 663, 731, 1813, 4551, 13105, 18275, 19729, 121971, 139959}},
+{15165, 18, 29590, {1, 1, 7, 3, 23, 47, 11, 117, 323, 943, 183, 2169, 4625, 12931, 1305, 23345, 119521, 67911}},
+{15166, 18, 29600, {1, 1, 1, 13, 19, 45, 37, 77, 301, 741, 747, 241, 5865, 11141, 7961, 10609, 97833, 256555}},
+{15167, 18, 29612, {1, 1, 1, 11, 27, 21, 119, 103, 277, 761, 201, 2063, 1043, 13303, 6535, 15553, 57695, 124187}},
+{15168, 18, 29665, {1, 3, 7, 3, 1, 11, 79, 143, 345, 237, 1421, 193, 1889, 2515, 11729, 559, 35227, 9393}},
+{15169, 18, 29722, {1, 3, 1, 1, 27, 27, 117, 159, 183, 871, 47, 989, 999, 303, 30833, 8229, 116301, 199439}},
+{15170, 18, 29745, {1, 1, 1, 1, 31, 27, 41, 83, 435, 409, 999, 2275, 4489, 1985, 21455, 23275, 125039, 192979}},
+{15171, 18, 29746, {1, 3, 7, 3, 19, 49, 27, 185, 9, 385, 191, 735, 3439, 16307, 21181, 58749, 128393, 140383}},
+{15172, 18, 29752, {1, 3, 7, 3, 15, 5, 65, 89, 11, 915, 673, 947, 3847, 6833, 10095, 34261, 101645, 42131}},
+{15173, 18, 29775, {1, 3, 5, 11, 11, 25, 79, 225, 495, 951, 1033, 5, 699, 9621, 1791, 48221, 59275, 49875}},
+{15174, 18, 29778, {1, 3, 7, 13, 29, 59, 105, 101, 233, 901, 863, 413, 2087, 16209, 445, 27463, 61465, 121795}},
+{15175, 18, 29800, {1, 1, 1, 11, 5, 19, 11, 51, 503, 313, 195, 3, 7249, 4919, 11931, 15569, 118297, 115989}},
+{15176, 18, 29829, {1, 3, 3, 13, 13, 61, 63, 57, 429, 487, 2033, 847, 7539, 1469, 3197, 1307, 124557, 211999}},
+{15177, 18, 29830, {1, 3, 7, 13, 25, 27, 39, 103, 165, 39, 1587, 3103, 1745, 12593, 10779, 37105, 29059, 256739}},
+{15178, 18, 29877, {1, 3, 3, 9, 25, 51, 105, 109, 99, 267, 623, 1351, 3837, 793, 28609, 52199, 15621, 77873}},
+{15179, 18, 29881, {1, 1, 3, 7, 29, 61, 45, 237, 431, 791, 91, 1259, 8071, 11103, 27257, 10153, 18639, 248949}},
+{15180, 18, 29884, {1, 1, 1, 9, 15, 47, 113, 189, 291, 837, 1317, 2263, 7183, 6669, 17241, 35275, 9087, 241577}},
+{15181, 18, 29895, {1, 1, 3, 1, 15, 59, 85, 21, 69, 569, 1473, 2735, 713, 3817, 14677, 26897, 75291, 251255}},
+{15182, 18, 29899, {1, 1, 1, 7, 17, 21, 105, 77, 367, 905, 513, 1807, 5571, 14627, 10349, 47821, 34395, 51143}},
+{15183, 18, 29916, {1, 3, 7, 13, 27, 19, 123, 145, 371, 857, 1699, 2231, 373, 781, 28713, 21441, 64059, 10689}},
+{15184, 18, 29923, {1, 1, 1, 7, 19, 57, 81, 223, 87, 315, 1253, 421, 1371, 1547, 1411, 6809, 23889, 213385}},
+{15185, 18, 29935, {1, 3, 1, 5, 23, 57, 89, 15, 227, 965, 1247, 3861, 7723, 15621, 7151, 53961, 47167, 73679}},
+{15186, 18, 29955, {1, 3, 7, 15, 31, 21, 9, 79, 87, 561, 1001, 3395, 2095, 15381, 30725, 48111, 68031, 121687}},
+{15187, 18, 29962, {1, 3, 1, 9, 15, 29, 83, 87, 377, 331, 2035, 93, 2319, 3637, 4809, 40091, 93141, 39881}},
+{15188, 18, 29969, {1, 3, 3, 11, 21, 39, 27, 159, 161, 439, 1417, 595, 4873, 15703, 32743, 56603, 35881, 160727}},
+{15189, 18, 29997, {1, 1, 3, 5, 21, 37, 55, 159, 497, 425, 469, 1185, 5015, 7045, 7179, 65325, 97167, 75723}},
+{15190, 18, 30032, {1, 3, 1, 7, 31, 21, 125, 223, 479, 765, 1115, 33, 2765, 12781, 22923, 36051, 103749, 33703}},
+{15191, 18, 30041, {1, 1, 7, 1, 9, 3, 29, 125, 337, 973, 253, 3179, 3269, 8801, 19369, 20693, 17331, 190295}},
+{15192, 18, 30048, {1, 1, 3, 3, 13, 5, 115, 31, 481, 45, 855, 81, 3663, 10443, 13853, 29847, 99471, 249943}},
+{15193, 18, 30060, {1, 1, 3, 7, 3, 1, 47, 31, 169, 625, 201, 2257, 4617, 1633, 26681, 53793, 78257, 8955}},
+{15194, 18, 30063, {1, 1, 5, 1, 23, 3, 95, 89, 429, 559, 119, 2619, 1235, 7609, 21905, 45495, 19461, 189091}},
+{15195, 18, 30105, {1, 3, 5, 5, 11, 33, 123, 45, 89, 899, 1607, 3717, 6745, 15199, 22955, 15891, 50411, 148201}},
+{15196, 18, 30122, {1, 3, 5, 9, 19, 23, 87, 21, 39, 117, 603, 823, 3015, 14853, 4341, 49029, 97183, 218713}},
+{15197, 18, 30141, {1, 1, 3, 7, 11, 55, 31, 255, 399, 861, 745, 1013, 4583, 15871, 32453, 25357, 90645, 100835}},
+{15198, 18, 30142, {1, 1, 1, 11, 13, 27, 57, 233, 45, 339, 305, 3689, 5273, 11801, 29109, 44139, 83171, 250559}},
+{15199, 18, 30153, {1, 3, 7, 13, 19, 1, 29, 113, 207, 313, 1465, 3563, 2535, 3307, 14921, 1923, 31429, 59815}},
+{15200, 18, 30171, {1, 3, 1, 5, 29, 25, 59, 95, 177, 795, 353, 3973, 8029, 1687, 5045, 16157, 30361, 218479}},
+{15201, 18, 30192, {1, 3, 5, 3, 5, 27, 109, 239, 121, 347, 93, 1645, 3293, 13181, 23793, 42935, 98659, 85385}},
+{15202, 18, 30197, {1, 1, 7, 9, 9, 37, 127, 211, 77, 557, 177, 2465, 7895, 5523, 26665, 23463, 71715, 126673}},
+{15203, 18, 30223, {1, 3, 7, 1, 27, 55, 125, 85, 47, 739, 1513, 3763, 5335, 3135, 11913, 22405, 90785, 88845}},
+{15204, 18, 30235, {1, 3, 3, 9, 29, 21, 123, 211, 491, 83, 697, 929, 3507, 7139, 30569, 16365, 122657, 77523}},
+{15205, 18, 30241, {1, 3, 5, 5, 27, 21, 41, 129, 67, 503, 877, 1893, 6055, 12709, 24613, 43831, 124035, 62631}},
+{15206, 18, 30256, {1, 3, 3, 1, 21, 15, 59, 185, 405, 487, 627, 3737, 345, 14751, 2947, 15815, 55047, 207137}},
+{15207, 18, 30291, {1, 1, 1, 9, 15, 29, 19, 155, 101, 405, 597, 329, 2977, 4333, 5465, 43863, 6009, 229481}},
+{15208, 18, 30293, {1, 1, 1, 11, 7, 27, 93, 207, 43, 599, 1899, 3979, 4219, 10199, 2901, 34261, 19435, 58317}},
+{15209, 18, 30300, {1, 1, 7, 15, 9, 47, 33, 209, 235, 655, 253, 3507, 3355, 1685, 7045, 58907, 41791, 175835}},
+{15210, 18, 30331, {1, 3, 3, 11, 11, 43, 21, 255, 45, 831, 1051, 1271, 7945, 9793, 11125, 17709, 118267, 169981}},
+{15211, 18, 30349, {1, 3, 7, 13, 27, 37, 45, 221, 243, 37, 1493, 2773, 6655, 7451, 22609, 56559, 12063, 221143}},
+{15212, 18, 30361, {1, 3, 1, 1, 9, 15, 97, 61, 241, 825, 735, 3953, 5331, 16373, 19403, 28933, 31881, 111545}},
+{15213, 18, 30367, {1, 1, 1, 15, 29, 1, 127, 111, 329, 741, 1589, 1653, 5949, 8703, 27617, 65285, 122167, 11895}},
+{15214, 18, 30392, {1, 1, 3, 3, 17, 31, 91, 197, 421, 865, 1901, 897, 6917, 15943, 12823, 15325, 17011, 110783}},
+{15215, 18, 30405, {1, 1, 3, 15, 21, 57, 29, 179, 503, 929, 1513, 205, 6083, 4015, 32517, 26921, 54229, 147789}},
+{15216, 18, 30410, {1, 1, 7, 15, 27, 21, 95, 59, 193, 97, 1235, 819, 4435, 371, 627, 24673, 1775, 261041}},
+{15217, 18, 30415, {1, 1, 7, 15, 3, 37, 99, 85, 505, 1011, 19, 1241, 5299, 15661, 27323, 44625, 12683, 225687}},
+{15218, 18, 30439, {1, 1, 7, 3, 25, 37, 111, 121, 217, 659, 365, 2627, 5499, 12911, 951, 54317, 51927, 235327}},
+{15219, 18, 30446, {1, 1, 3, 9, 29, 31, 99, 195, 427, 735, 1817, 3675, 4269, 1579, 12593, 39285, 74909, 230613}},
+{15220, 18, 30501, {1, 3, 1, 13, 7, 21, 37, 101, 111, 931, 1581, 465, 4753, 15607, 14515, 29769, 107711, 32703}},
+{15221, 18, 30526, {1, 1, 7, 15, 25, 57, 117, 119, 309, 345, 491, 3647, 2933, 5409, 15431, 43731, 25537, 17269}},
+{15222, 18, 30531, {1, 1, 5, 3, 15, 9, 83, 221, 501, 675, 1441, 129, 213, 5587, 22361, 16739, 118845, 192835}},
+{15223, 18, 30537, {1, 3, 7, 13, 1, 31, 75, 23, 13, 447, 687, 2711, 7577, 8275, 5051, 61835, 22159, 56477}},
+{15224, 18, 30546, {1, 1, 3, 1, 23, 19, 111, 45, 395, 841, 1665, 21, 7435, 12457, 11065, 20007, 48785, 15115}},
+{15225, 18, 30568, {1, 3, 7, 7, 21, 3, 117, 35, 117, 433, 561, 3045, 2169, 3255, 18015, 41093, 99699, 3479}},
+{15226, 18, 30581, {1, 1, 3, 7, 9, 59, 65, 143, 315, 63, 29, 3817, 1259, 7119, 20847, 44407, 80015, 37851}},
+{15227, 18, 30588, {1, 3, 7, 13, 13, 33, 85, 75, 39, 163, 1759, 1197, 5971, 8815, 8745, 45625, 121873, 246197}},
+{15228, 18, 30598, {1, 1, 1, 13, 31, 41, 61, 7, 145, 113, 943, 3757, 2141, 3523, 22351, 14143, 107683, 105579}},
+{15229, 18, 30607, {1, 1, 5, 5, 23, 27, 75, 77, 25, 901, 1295, 3091, 981, 10109, 12649, 15123, 102433, 145557}},
+{15230, 18, 30609, {1, 1, 7, 5, 9, 11, 19, 229, 301, 835, 1577, 3365, 425, 2271, 15647, 11685, 57315, 131043}},
+{15231, 18, 30616, {1, 3, 1, 13, 31, 3, 113, 7, 473, 395, 1979, 61, 4205, 2031, 28007, 34789, 54463, 94741}},
+{15232, 18, 30626, {1, 1, 3, 5, 7, 13, 35, 151, 461, 621, 185, 2645, 907, 9151, 25953, 26363, 105531, 235555}},
+{15233, 18, 30628, {1, 3, 3, 13, 21, 5, 43, 183, 149, 607, 509, 777, 4089, 16365, 32201, 60431, 58773, 92719}},
+{15234, 18, 30638, {1, 3, 3, 11, 25, 53, 103, 203, 269, 1017, 77, 3537, 4839, 15991, 29223, 57397, 122735, 67299}},
+{15235, 18, 30658, {1, 3, 3, 1, 29, 45, 85, 171, 307, 455, 1399, 2367, 5991, 5751, 27957, 36649, 9251, 38581}},
+{15236, 18, 30663, {1, 1, 5, 13, 29, 15, 127, 1, 175, 921, 671, 2469, 3137, 3679, 32521, 5321, 92505, 45901}},
+{15237, 18, 30675, {1, 3, 3, 11, 23, 23, 113, 255, 443, 609, 1085, 133, 5369, 885, 17043, 20961, 36137, 260457}},
+{15238, 18, 30698, {1, 3, 3, 9, 13, 55, 117, 19, 111, 323, 275, 495, 6679, 2217, 12015, 3053, 32745, 189413}},
+{15239, 18, 30708, {1, 3, 5, 13, 31, 43, 37, 225, 67, 755, 1427, 3967, 6497, 9987, 28145, 50583, 59457, 213217}},
+{15240, 18, 30712, {1, 3, 1, 15, 1, 5, 121, 249, 293, 695, 1697, 313, 61, 4037, 11757, 53739, 5693, 106225}},
+{15241, 18, 30727, {1, 1, 7, 1, 23, 9, 111, 211, 303, 147, 1291, 3807, 1969, 4115, 7473, 50077, 60745, 41605}},
+{15242, 18, 30736, {1, 3, 3, 15, 21, 51, 63, 171, 197, 403, 1327, 1851, 6991, 9069, 19221, 45765, 55489, 34853}},
+{15243, 18, 30748, {1, 1, 5, 3, 5, 53, 87, 241, 255, 309, 1319, 3727, 3189, 10887, 13401, 32371, 24479, 170571}},
+{15244, 18, 30758, {1, 1, 7, 11, 5, 5, 59, 177, 317, 835, 527, 165, 2137, 9597, 30181, 1779, 75407, 185827}},
+{15245, 18, 30775, {1, 3, 3, 7, 25, 15, 15, 183, 235, 955, 27, 2223, 5587, 11301, 17653, 56697, 70787, 198347}},
+{15246, 18, 30793, {1, 3, 5, 5, 11, 63, 123, 41, 169, 975, 1709, 2965, 7491, 4183, 15217, 41343, 36139, 9649}},
+{15247, 18, 30802, {1, 1, 3, 7, 5, 37, 87, 247, 379, 603, 781, 463, 8063, 13681, 32005, 43485, 107401, 42303}},
+{15248, 18, 30820, {1, 3, 5, 9, 19, 53, 61, 219, 217, 361, 769, 1687, 5643, 3145, 12885, 40303, 86377, 255051}},
+{15249, 18, 30823, {1, 1, 7, 11, 15, 49, 127, 99, 127, 515, 647, 1725, 1605, 2357, 2069, 31803, 14179, 180367}},
+{15250, 18, 30827, {1, 3, 5, 15, 9, 7, 41, 3, 49, 485, 1471, 207, 6477, 4463, 12255, 53481, 110785, 909}},
+{15251, 18, 30848, {1, 1, 5, 9, 23, 51, 107, 227, 205, 987, 1525, 2739, 6761, 12343, 32311, 12523, 93351, 29663}},
+{15252, 18, 30893, {1, 3, 5, 11, 21, 19, 53, 169, 197, 21, 825, 4029, 6733, 8943, 13475, 60677, 31001, 242291}},
+{15253, 18, 30906, {1, 3, 7, 13, 9, 27, 87, 37, 265, 877, 735, 2249, 4801, 2365, 16923, 40451, 29693, 222483}},
+{15254, 18, 30950, {1, 1, 3, 9, 31, 61, 71, 103, 215, 421, 193, 3451, 6181, 4271, 30875, 59573, 80773, 100369}},
+{15255, 18, 30956, {1, 1, 3, 13, 17, 55, 73, 191, 233, 821, 961, 1637, 2393, 3453, 25959, 5069, 114585, 186001}},
+{15256, 18, 30996, {1, 1, 7, 5, 15, 27, 39, 23, 69, 811, 709, 2349, 6011, 803, 12497, 7387, 62023, 247875}},
+{15257, 18, 31015, {1, 1, 5, 13, 29, 55, 51, 41, 121, 599, 1633, 3813, 1913, 3803, 26097, 53799, 30997, 261965}},
+{15258, 18, 31016, {1, 1, 1, 11, 31, 25, 19, 195, 87, 657, 1005, 3853, 61, 6585, 24665, 38283, 5495, 257201}},
+{15259, 18, 31034, {1, 1, 1, 11, 23, 43, 91, 121, 49, 491, 1443, 1873, 7689, 15957, 30463, 64079, 100003, 325}},
+{15260, 18, 31099, {1, 1, 7, 1, 25, 51, 27, 105, 119, 233, 513, 3403, 2647, 2847, 12687, 15619, 71225, 243759}},
+{15261, 18, 31123, {1, 1, 7, 3, 17, 49, 19, 123, 307, 463, 1619, 1853, 7019, 2605, 17351, 7971, 20675, 235929}},
+{15262, 18, 31145, {1, 1, 5, 3, 17, 29, 71, 215, 365, 955, 1631, 3549, 1379, 13881, 25409, 55703, 29863, 135401}},
+{15263, 18, 31166, {1, 3, 7, 15, 3, 27, 107, 149, 65, 681, 505, 3957, 6697, 11203, 9321, 63323, 98587, 199241}},
+{15264, 18, 31168, {1, 1, 1, 13, 27, 41, 59, 223, 431, 339, 1805, 899, 639, 6559, 13233, 4773, 37415, 110477}},
+{15265, 18, 31174, {1, 3, 7, 9, 1, 59, 79, 161, 311, 905, 1755, 3915, 6259, 8955, 14187, 11331, 86185, 209805}},
+{15266, 18, 31216, {1, 1, 7, 9, 5, 27, 75, 93, 285, 89, 891, 3341, 1157, 11219, 8883, 8093, 68949, 189643}},
+{15267, 18, 31219, {1, 3, 1, 5, 1, 43, 97, 71, 67, 605, 739, 1641, 4415, 4487, 13437, 12755, 121595, 55761}},
+{15268, 18, 31238, {1, 1, 1, 3, 1, 13, 61, 77, 297, 507, 1527, 3585, 4515, 13913, 7679, 28461, 61807, 196517}},
+{15269, 18, 31256, {1, 1, 1, 3, 21, 23, 101, 135, 59, 485, 1601, 3713, 7409, 349, 16543, 18897, 97253, 149055}},
+{15270, 18, 31304, {1, 1, 1, 13, 5, 37, 15, 37, 109, 1005, 363, 1925, 2701, 13169, 17027, 58453, 27667, 234027}},
+{15271, 18, 31315, {1, 1, 7, 1, 1, 41, 67, 231, 143, 951, 2023, 3465, 1717, 645, 17353, 9037, 129127, 199467}},
+{15272, 18, 31324, {1, 1, 1, 11, 27, 29, 65, 139, 425, 947, 141, 2601, 7339, 4451, 25065, 62691, 62355, 91819}},
+{15273, 18, 31364, {1, 3, 7, 15, 29, 29, 93, 25, 139, 267, 1319, 3839, 7295, 11855, 17775, 30199, 44127, 150875}},
+{15274, 18, 31379, {1, 3, 5, 1, 3, 55, 23, 191, 199, 583, 1167, 1357, 6477, 11827, 15581, 56541, 16603, 120139}},
+{15275, 18, 31382, {1, 1, 1, 3, 5, 47, 103, 211, 443, 491, 1043, 4001, 121, 1637, 5685, 42675, 13009, 22979}},
+{15276, 18, 31412, {1, 1, 1, 9, 21, 7, 77, 17, 303, 955, 51, 2389, 3573, 8817, 28053, 40269, 35457, 211023}},
+{15277, 18, 31451, {1, 3, 5, 15, 3, 39, 17, 75, 223, 37, 1231, 2127, 3575, 9085, 10715, 41871, 103703, 154181}},
+{15278, 18, 31487, {1, 3, 3, 15, 25, 31, 31, 223, 473, 267, 1519, 3205, 7029, 10753, 24757, 28187, 117921, 26783}},
+{15279, 18, 31509, {1, 3, 7, 1, 5, 21, 105, 191, 55, 115, 1813, 3701, 1673, 4199, 2441, 19737, 46913, 208725}},
+{15280, 18, 31510, {1, 1, 5, 5, 19, 63, 89, 141, 143, 783, 545, 883, 2979, 9219, 24983, 41793, 88441, 207095}},
+{15281, 18, 31520, {1, 1, 1, 9, 21, 21, 93, 161, 93, 733, 417, 3133, 8155, 12415, 16343, 11727, 82877, 94469}},
+{15282, 18, 31535, {1, 1, 5, 15, 5, 39, 33, 203, 213, 731, 1849, 1675, 6029, 2743, 1529, 16345, 13955, 54929}},
+{15283, 18, 31564, {1, 1, 7, 7, 23, 47, 121, 211, 271, 737, 1015, 1021, 5641, 12659, 27545, 52363, 104761, 150143}},
+{15284, 18, 31585, {1, 3, 1, 11, 11, 51, 79, 141, 255, 1007, 481, 3221, 7741, 6861, 24943, 63091, 46741, 33359}},
+{15285, 18, 31586, {1, 1, 3, 3, 27, 47, 85, 27, 423, 811, 75, 3911, 1951, 10821, 7487, 18971, 83355, 197479}},
+{15286, 18, 31600, {1, 1, 5, 5, 1, 63, 125, 251, 457, 795, 557, 217, 2335, 5659, 18375, 52183, 9789, 31417}},
+{15287, 18, 31643, {1, 3, 3, 3, 19, 61, 41, 129, 345, 361, 187, 3881, 43, 7197, 7673, 25011, 115155, 16375}},
+{15288, 18, 31646, {1, 3, 3, 7, 13, 7, 55, 91, 153, 341, 2003, 2013, 6891, 2411, 14825, 39555, 50267, 61405}},
+{15289, 18, 31649, {1, 3, 5, 7, 13, 57, 21, 91, 331, 615, 1297, 2881, 2011, 1907, 16489, 43061, 75731, 76675}},
+{15290, 18, 31650, {1, 1, 5, 5, 25, 15, 77, 175, 101, 885, 835, 529, 2787, 547, 20191, 50457, 58557, 61807}},
+{15291, 18, 31674, {1, 3, 7, 1, 13, 47, 101, 117, 179, 245, 861, 611, 4377, 5257, 12807, 26667, 19889, 112485}},
+{15292, 18, 31679, {1, 3, 7, 1, 27, 3, 23, 109, 197, 187, 963, 1827, 5741, 11921, 6359, 3989, 108939, 5761}},
+{15293, 18, 31684, {1, 1, 7, 5, 27, 7, 119, 159, 53, 969, 557, 597, 7821, 7121, 17341, 11233, 10811, 23969}},
+{15294, 18, 31688, {1, 1, 3, 13, 23, 55, 75, 131, 339, 917, 317, 2645, 5973, 9939, 26375, 29261, 80883, 229897}},
+{15295, 18, 31706, {1, 1, 5, 13, 3, 63, 41, 191, 315, 191, 649, 2119, 317, 14699, 4097, 19557, 97015, 124557}},
+{15296, 18, 31735, {1, 3, 7, 15, 13, 29, 29, 43, 47, 37, 729, 185, 4477, 15091, 13991, 18701, 56785, 218823}},
+{15297, 18, 31754, {1, 3, 7, 15, 31, 39, 17, 133, 469, 509, 995, 1683, 391, 1775, 15431, 63489, 7405, 122125}},
+{15298, 18, 31761, {1, 3, 7, 5, 15, 63, 5, 235, 193, 411, 1493, 3967, 3279, 6421, 13359, 20949, 68097, 69469}},
+{15299, 18, 31774, {1, 3, 3, 13, 7, 37, 7, 207, 399, 553, 1629, 1903, 329, 7577, 5813, 17151, 40889, 174811}},
+{15300, 18, 31807, {1, 3, 1, 13, 7, 39, 119, 109, 323, 61, 749, 1377, 911, 8195, 19753, 6265, 60783, 182339}},
+{15301, 18, 31812, {1, 1, 5, 11, 3, 21, 89, 61, 243, 273, 1317, 3443, 117, 6205, 13907, 12903, 95485, 103355}},
+{15302, 18, 31821, {1, 3, 7, 13, 19, 27, 45, 251, 405, 289, 121, 1501, 2599, 8111, 5163, 17437, 75095, 165847}},
+{15303, 18, 31855, {1, 3, 3, 5, 23, 13, 29, 145, 333, 573, 1939, 2133, 5797, 5263, 18835, 11945, 42161, 103123}},
+{15304, 18, 31919, {1, 3, 5, 13, 9, 31, 45, 17, 181, 111, 219, 3451, 1591, 5823, 20307, 41207, 77047, 173401}},
+{15305, 18, 31934, {1, 3, 1, 9, 19, 63, 73, 111, 377, 875, 1749, 2887, 7035, 14209, 1805, 20527, 93839, 225185}},
+{15306, 18, 31956, {1, 3, 1, 9, 15, 45, 97, 235, 11, 803, 899, 427, 3353, 7363, 26687, 1307, 5451, 176233}},
+{15307, 18, 31965, {1, 3, 7, 5, 7, 51, 59, 53, 3, 263, 159, 1005, 6079, 7237, 17419, 56653, 61091, 182209}},
+{15308, 18, 31975, {1, 1, 3, 15, 19, 47, 17, 185, 167, 219, 233, 2921, 5755, 1277, 27281, 33671, 3191, 169477}},
+{15309, 18, 31981, {1, 3, 7, 1, 25, 27, 99, 81, 57, 969, 821, 2397, 2947, 5913, 15247, 47651, 449, 183295}},
+{15310, 18, 31999, {1, 3, 1, 15, 3, 63, 83, 75, 41, 959, 1005, 153, 97, 15381, 6901, 55141, 90215, 161321}},
+{15311, 18, 32014, {1, 3, 1, 9, 1, 1, 29, 191, 43, 241, 607, 667, 1189, 4389, 31335, 14133, 104049, 100925}},
+{15312, 18, 32022, {1, 1, 3, 1, 1, 61, 109, 23, 325, 27, 1601, 3957, 7181, 8375, 9823, 50533, 114895, 73825}},
+{15313, 18, 32049, {1, 1, 7, 7, 1, 25, 51, 19, 383, 955, 1717, 2953, 5431, 7883, 14451, 18619, 9601, 153151}},
+{15314, 18, 32055, {1, 3, 1, 5, 1, 1, 35, 3, 141, 37, 1531, 1855, 7905, 6509, 6223, 45911, 54267, 172275}},
+{15315, 18, 32082, {1, 1, 3, 15, 23, 39, 109, 145, 215, 147, 1191, 2425, 301, 5543, 997, 31071, 101697, 169677}},
+{15316, 18, 32087, {1, 1, 3, 5, 17, 23, 41, 191, 367, 967, 1625, 3669, 769, 7599, 111, 4399, 64121, 232275}},
+{15317, 18, 32100, {1, 3, 5, 1, 25, 61, 47, 247, 413, 605, 399, 1233, 2789, 9775, 7111, 42853, 2305, 87423}},
+{15318, 18, 32104, {1, 3, 7, 3, 1, 25, 73, 247, 221, 235, 169, 889, 5635, 4325, 27015, 39549, 107545, 80885}},
+{15319, 18, 32109, {1, 1, 7, 11, 15, 55, 61, 103, 179, 157, 481, 3089, 4539, 375, 25425, 14995, 60119, 31031}},
+{15320, 18, 32138, {1, 3, 3, 1, 31, 17, 87, 123, 27, 309, 1693, 3871, 7319, 15615, 20113, 18239, 86407, 172381}},
+{15321, 18, 32140, {1, 1, 1, 13, 17, 31, 83, 149, 451, 305, 847, 223, 5705, 9697, 4967, 34273, 4041, 252891}},
+{15322, 18, 32148, {1, 3, 3, 15, 7, 27, 105, 207, 443, 825, 701, 1159, 5267, 14085, 28295, 41757, 47799, 14835}},
+{15323, 18, 32161, {1, 3, 7, 3, 1, 31, 77, 219, 139, 497, 1575, 905, 4341, 4611, 27861, 59871, 45525, 21735}},
+{15324, 18, 32162, {1, 3, 3, 3, 7, 17, 65, 183, 231, 955, 1111, 1899, 1677, 13685, 29395, 10449, 62505, 125643}},
+{15325, 18, 32174, {1, 3, 5, 7, 27, 57, 81, 165, 279, 989, 1569, 573, 7593, 10067, 1343, 12039, 117175, 225125}},
+{15326, 18, 32196, {1, 3, 3, 15, 19, 37, 47, 175, 87, 153, 1137, 1985, 2473, 14767, 19587, 41751, 98937, 66667}},
+{15327, 18, 32220, {1, 3, 5, 3, 19, 51, 25, 155, 37, 597, 719, 1039, 165, 1871, 15677, 59891, 29899, 231979}},
+{15328, 18, 32223, {1, 3, 5, 13, 15, 39, 17, 21, 73, 695, 1813, 2463, 3549, 3081, 14037, 13077, 40417, 258995}},
+{15329, 18, 32267, {1, 1, 5, 9, 29, 5, 105, 75, 97, 937, 1767, 975, 637, 9419, 30673, 33537, 979, 45381}},
+{15330, 18, 32272, {1, 1, 5, 9, 3, 31, 91, 193, 171, 163, 925, 3519, 3621, 4943, 14093, 22881, 18459, 110155}},
+{15331, 18, 32308, {1, 1, 3, 7, 29, 1, 39, 107, 359, 805, 91, 2911, 4741, 3099, 16967, 45849, 95255, 63225}},
+{15332, 18, 32315, {1, 1, 5, 13, 25, 41, 49, 145, 345, 823, 1571, 341, 6323, 9679, 14855, 19965, 108367, 99833}},
+{15333, 18, 32317, {1, 3, 5, 3, 27, 35, 87, 83, 373, 425, 281, 1313, 5153, 6301, 2745, 12677, 34603, 181835}},
+{15334, 18, 32347, {1, 1, 7, 7, 13, 17, 83, 101, 141, 789, 1403, 2777, 2749, 1551, 9009, 9909, 48443, 176679}},
+{15335, 18, 32360, {1, 3, 5, 9, 7, 25, 125, 109, 155, 357, 1111, 3057, 771, 11253, 25811, 60333, 68505, 146987}},
+{15336, 18, 32394, {1, 3, 7, 7, 29, 19, 69, 115, 411, 793, 51, 715, 3035, 11577, 14237, 23963, 13915, 196771}},
+{15337, 18, 32411, {1, 1, 3, 3, 27, 37, 61, 163, 131, 749, 37, 1333, 47, 2519, 25473, 40851, 55861, 113961}},
+{15338, 18, 32420, {1, 3, 5, 1, 3, 49, 19, 251, 125, 387, 1887, 3571, 1465, 4831, 3859, 43357, 20859, 225835}},
+{15339, 18, 32423, {1, 3, 5, 9, 27, 53, 53, 143, 383, 781, 819, 2921, 3499, 11551, 18761, 14453, 58209, 181763}},
+{15340, 18, 32455, {1, 3, 7, 9, 17, 17, 79, 61, 145, 413, 541, 895, 2077, 6957, 28681, 44821, 30609, 131705}},
+{15341, 18, 32456, {1, 1, 3, 15, 1, 57, 17, 125, 11, 43, 1079, 1023, 5391, 67, 31701, 5737, 429, 75411}},
+{15342, 18, 32510, {1, 1, 7, 7, 21, 45, 65, 127, 447, 793, 161, 333, 637, 7403, 12861, 30173, 125121, 254687}},
+{15343, 18, 32517, {1, 1, 3, 9, 27, 53, 85, 223, 297, 455, 919, 2371, 7049, 7167, 18075, 22815, 10265, 14765}},
+{15344, 18, 32541, {1, 1, 3, 7, 1, 53, 91, 181, 471, 101, 771, 4043, 3039, 1215, 19289, 15941, 55187, 147355}},
+{15345, 18, 32552, {1, 3, 1, 1, 13, 19, 13, 47, 159, 965, 1383, 297, 4299, 7181, 1271, 17057, 114847, 180883}},
+{15346, 18, 32555, {1, 3, 1, 15, 29, 55, 113, 243, 215, 665, 641, 1975, 5907, 2617, 17077, 43697, 61101, 70007}},
+{15347, 18, 32580, {1, 3, 1, 11, 5, 55, 109, 145, 307, 663, 1327, 1247, 8033, 15425, 18539, 57027, 72161, 181655}},
+{15348, 18, 32598, {1, 3, 5, 9, 25, 17, 3, 57, 7, 449, 1049, 3423, 5769, 12713, 29849, 1017, 92579, 131255}},
+{15349, 18, 32654, {1, 1, 7, 13, 25, 13, 55, 217, 461, 595, 931, 1883, 2645, 9625, 20467, 45825, 72027, 163767}},
+{15350, 18, 32662, {1, 3, 5, 15, 29, 49, 23, 47, 45, 645, 973, 3837, 621, 7373, 3585, 16083, 93823, 184593}},
+{15351, 18, 32665, {1, 3, 7, 11, 27, 19, 59, 125, 447, 33, 541, 1067, 6983, 3779, 27275, 34269, 106937, 65085}},
+{15352, 18, 32678, {1, 3, 1, 9, 23, 23, 51, 43, 475, 861, 1759, 2559, 3059, 1175, 31555, 27671, 117653, 162735}},
+{15353, 18, 32682, {1, 1, 7, 13, 7, 61, 33, 49, 23, 737, 949, 1785, 2921, 873, 26631, 61941, 14467, 76225}},
+{15354, 18, 32687, {1, 3, 7, 5, 31, 11, 49, 149, 7, 85, 1929, 1001, 4185, 221, 23719, 52265, 52973, 67967}},
+{15355, 18, 32692, {1, 3, 1, 13, 17, 31, 35, 191, 65, 527, 51, 1093, 3673, 11167, 29985, 59739, 43567, 109817}},
+{15356, 18, 32710, {1, 1, 1, 11, 23, 39, 95, 121, 501, 355, 1043, 993, 7533, 15763, 18399, 31601, 49373, 243209}},
+{15357, 18, 32791, {1, 1, 3, 3, 15, 37, 57, 183, 27, 981, 153, 1481, 549, 7847, 2689, 57401, 46359, 175401}},
+{15358, 18, 32792, {1, 3, 5, 9, 31, 19, 83, 79, 413, 597, 1957, 3027, 4751, 1437, 11255, 39513, 56927, 166841}},
+{15359, 18, 32813, {1, 3, 7, 5, 27, 61, 69, 65, 143, 321, 1129, 2521, 4467, 4369, 11727, 35643, 80155, 184241}},
+{15360, 18, 32826, {1, 3, 7, 1, 25, 27, 107, 219, 481, 457, 2027, 1057, 6409, 5641, 19711, 11009, 44295, 28171}},
+{15361, 18, 32831, {1, 3, 3, 9, 3, 17, 85, 5, 341, 107, 2037, 93, 741, 5279, 20093, 28637, 80823, 210279}},
+{15362, 18, 32836, {1, 1, 7, 15, 5, 9, 33, 167, 451, 463, 1951, 2395, 3821, 2915, 15195, 34517, 113545, 22173}},
+{15363, 18, 32843, {1, 1, 3, 1, 23, 55, 113, 159, 139, 795, 69, 2021, 6769, 10807, 18605, 54161, 39501, 233797}},
+{15364, 18, 32854, {1, 1, 7, 11, 17, 53, 103, 131, 385, 909, 629, 3127, 6117, 11457, 31115, 8255, 33227, 170877}},
+{15365, 18, 32893, {1, 1, 3, 9, 23, 19, 99, 221, 141, 731, 311, 2617, 2763, 375, 26763, 56473, 6613, 60519}},
+{15366, 18, 32897, {1, 3, 1, 9, 7, 29, 15, 105, 243, 159, 1755, 3999, 5861, 12009, 30111, 48269, 70427, 187173}},
+{15367, 18, 32912, {1, 1, 3, 13, 1, 35, 39, 121, 409, 571, 1835, 1535, 4671, 12671, 4503, 4783, 48009, 216837}},
+{15368, 18, 32951, {1, 1, 1, 9, 25, 61, 87, 109, 489, 107, 1741, 859, 237, 7161, 27117, 58587, 55445, 155763}},
+{15369, 18, 32963, {1, 1, 7, 15, 9, 21, 61, 159, 301, 863, 1823, 11, 419, 6717, 28199, 24129, 58419, 22147}},
+{15370, 18, 32970, {1, 3, 1, 5, 9, 7, 13, 205, 185, 759, 777, 2877, 5991, 14555, 18793, 51485, 6373, 232105}},
+{15371, 18, 32975, {1, 1, 3, 5, 7, 25, 51, 79, 227, 447, 867, 2709, 2677, 15249, 22957, 45577, 39011, 16839}},
+{15372, 18, 33028, {1, 1, 1, 3, 5, 51, 69, 135, 395, 339, 685, 3657, 3789, 16345, 2911, 51737, 97471, 126605}},
+{15373, 18, 33052, {1, 3, 7, 15, 15, 5, 85, 153, 507, 347, 1457, 527, 1055, 7773, 4161, 10487, 92373, 256535}},
+{15374, 18, 33061, {1, 3, 3, 3, 1, 9, 25, 1, 155, 321, 1739, 555, 7719, 10501, 19075, 12529, 75975, 229905}},
+{15375, 18, 33083, {1, 1, 1, 3, 29, 31, 89, 23, 283, 875, 1653, 855, 7613, 15277, 23845, 47443, 287, 217441}},
+{15376, 18, 33103, {1, 3, 3, 1, 25, 7, 75, 119, 493, 131, 231, 3063, 7171, 5437, 16385, 50347, 87427, 53603}},
+{15377, 18, 33117, {1, 3, 7, 7, 27, 55, 103, 223, 219, 103, 733, 1233, 1931, 2119, 19333, 59839, 100421, 256811}},
+{15378, 18, 33139, {1, 3, 7, 15, 23, 63, 77, 151, 285, 701, 1403, 1267, 6975, 11421, 24943, 51647, 75651, 191675}},
+{15379, 18, 33151, {1, 1, 5, 7, 25, 23, 25, 7, 503, 759, 997, 1711, 1439, 12483, 30117, 55205, 8813, 221589}},
+{15380, 18, 33162, {1, 3, 7, 5, 21, 3, 117, 65, 461, 851, 915, 575, 3061, 1055, 11999, 8375, 128677, 98005}},
+{15381, 18, 33209, {1, 3, 7, 7, 19, 13, 123, 23, 41, 293, 79, 1435, 1175, 7399, 14907, 4671, 88029, 220627}},
+{15382, 18, 33210, {1, 3, 3, 13, 11, 17, 65, 21, 143, 257, 1001, 2423, 5659, 11681, 23605, 40649, 49797, 55497}},
+{15383, 18, 33223, {1, 3, 5, 5, 29, 15, 125, 83, 139, 381, 1435, 2129, 1699, 10725, 531, 767, 112477, 134223}},
+{15384, 18, 33227, {1, 3, 7, 9, 9, 23, 35, 1, 127, 143, 707, 1475, 4705, 8921, 14919, 50909, 64425, 33381}},
+{15385, 18, 33241, {1, 1, 1, 15, 11, 63, 87, 101, 243, 833, 707, 4095, 201, 4877, 10219, 39019, 129779, 229857}},
+{15386, 18, 33263, {1, 1, 1, 11, 5, 9, 35, 177, 303, 545, 917, 1037, 1789, 12147, 29095, 27391, 112833, 104713}},
+{15387, 18, 33341, {1, 1, 1, 5, 27, 23, 111, 219, 439, 445, 967, 3527, 6203, 1829, 19657, 48965, 85213, 58719}},
+{15388, 18, 33344, {1, 3, 7, 11, 15, 7, 95, 113, 317, 225, 1229, 3033, 5777, 4075, 24093, 3539, 19333, 212757}},
+{15389, 18, 33356, {1, 3, 7, 7, 1, 35, 35, 67, 459, 769, 1675, 3509, 7393, 10433, 12003, 7385, 4425, 188989}},
+{15390, 18, 33390, {1, 1, 7, 9, 5, 45, 35, 27, 443, 301, 533, 2803, 99, 17, 20749, 58353, 93067, 118763}},
+{15391, 18, 33398, {1, 1, 3, 3, 13, 51, 61, 181, 81, 859, 1461, 3455, 2277, 13769, 1251, 4313, 119973, 30693}},
+{15392, 18, 33423, {1, 1, 3, 7, 15, 29, 23, 207, 239, 65, 1889, 151, 7793, 2657, 13673, 29033, 74477, 215027}},
+{15393, 18, 33428, {1, 1, 5, 1, 19, 35, 19, 71, 187, 783, 543, 505, 347, 3191, 1087, 49735, 54109, 27979}},
+{15394, 18, 33444, {1, 3, 3, 3, 3, 61, 67, 59, 207, 957, 1709, 1567, 7973, 5921, 29841, 8311, 81165, 91965}},
+{15395, 18, 33454, {1, 1, 1, 7, 23, 47, 109, 189, 447, 861, 1615, 3283, 3059, 749, 28729, 8713, 38743, 211019}},
+{15396, 18, 33479, {1, 3, 5, 1, 17, 51, 127, 181, 355, 515, 603, 465, 1825, 9281, 31971, 42793, 22467, 175777}},
+{15397, 18, 33510, {1, 3, 1, 5, 3, 29, 111, 91, 99, 15, 535, 3047, 1083, 7181, 28003, 60719, 71825, 12293}},
+{15398, 18, 33514, {1, 3, 5, 7, 1, 43, 83, 117, 221, 353, 139, 647, 6017, 4655, 31823, 22097, 118537, 71803}},
+{15399, 18, 33528, {1, 1, 3, 3, 27, 11, 35, 169, 215, 883, 1195, 2983, 4651, 15893, 24051, 313, 103947, 5227}},
+{15400, 18, 33548, {1, 3, 5, 13, 3, 51, 33, 159, 499, 763, 845, 1541, 3837, 9397, 855, 4187, 112167, 243817}},
+{15401, 18, 33566, {1, 1, 7, 9, 1, 15, 19, 239, 227, 561, 1685, 2841, 53, 9753, 15105, 34277, 128859, 100085}},
+{15402, 18, 33570, {1, 3, 5, 13, 15, 7, 57, 9, 415, 1005, 583, 1347, 4349, 3603, 9125, 15019, 77735, 237011}},
+{15403, 18, 33593, {1, 1, 1, 13, 27, 21, 105, 17, 235, 605, 1417, 2053, 3233, 11617, 28651, 43161, 71663, 98373}},
+{15404, 18, 33599, {1, 3, 5, 13, 29, 17, 123, 105, 477, 359, 613, 1699, 2581, 3007, 8507, 14391, 95487, 633}},
+{15405, 18, 33619, {1, 1, 7, 7, 13, 55, 107, 211, 71, 339, 1169, 2629, 165, 16207, 25523, 7101, 47553, 261131}},
+{15406, 18, 33635, {1, 3, 5, 15, 11, 7, 45, 207, 39, 41, 781, 3347, 2529, 4475, 9665, 31499, 119837, 128755}},
+{15407, 18, 33659, {1, 3, 1, 15, 23, 59, 59, 17, 89, 823, 59, 3991, 305, 14893, 1411, 8015, 92193, 66935}},
+{15408, 18, 33680, {1, 1, 7, 15, 19, 29, 11, 207, 429, 851, 1661, 2903, 4413, 447, 29447, 39243, 70435, 160451}},
+{15409, 18, 33699, {1, 1, 3, 13, 17, 5, 93, 89, 455, 67, 33, 65, 7957, 14383, 28525, 56983, 71899, 4881}},
+{15410, 18, 33713, {1, 3, 3, 5, 11, 7, 47, 233, 433, 791, 47, 2561, 6539, 1151, 2083, 12309, 62353, 69507}},
+{15411, 18, 33758, {1, 3, 5, 11, 15, 55, 101, 251, 41, 39, 383, 3481, 1817, 3447, 6205, 38169, 98267, 157091}},
+{15412, 18, 33771, {1, 3, 5, 7, 9, 47, 113, 55, 421, 703, 849, 2251, 129, 9257, 28097, 33475, 98933, 32041}},
+{15413, 18, 33779, {1, 3, 3, 11, 9, 59, 1, 211, 277, 969, 977, 3079, 4707, 3341, 17679, 9469, 52859, 125883}},
+{15414, 18, 33800, {1, 1, 7, 13, 29, 19, 49, 149, 259, 573, 1137, 2571, 2661, 12865, 24993, 10721, 96921, 85931}},
+{15415, 18, 33829, {1, 3, 1, 9, 15, 27, 91, 127, 305, 159, 523, 2539, 1969, 4325, 595, 37077, 79919, 26889}},
+{15416, 18, 33836, {1, 3, 1, 11, 1, 5, 65, 75, 317, 909, 1601, 2713, 6891, 4927, 28427, 5791, 82285, 35209}},
+{15417, 18, 33844, {1, 3, 7, 7, 9, 5, 111, 167, 477, 437, 1133, 2715, 6189, 5051, 4765, 26267, 99819, 70419}},
+{15418, 18, 33856, {1, 1, 3, 9, 27, 57, 23, 233, 423, 191, 1159, 1539, 6397, 16041, 8803, 19787, 114447, 17029}},
+{15419, 18, 33859, {1, 1, 5, 1, 11, 3, 111, 125, 287, 487, 1663, 1953, 3771, 2011, 18167, 47471, 94041, 87569}},
+{15420, 18, 33873, {1, 3, 1, 11, 5, 9, 75, 153, 37, 803, 971, 1667, 4631, 9183, 20179, 6905, 80949, 54443}},
+{15421, 18, 33874, {1, 1, 1, 5, 13, 29, 91, 201, 49, 739, 1569, 2725, 257, 5505, 5289, 40731, 27843, 16565}},
+{15422, 18, 33929, {1, 1, 7, 13, 27, 41, 81, 199, 99, 43, 1331, 3237, 6493, 3839, 19329, 44371, 19715, 60553}},
+{15423, 18, 33944, {1, 1, 5, 7, 29, 41, 67, 163, 467, 93, 1977, 2625, 6967, 6655, 19835, 39517, 10259, 200487}},
+{15424, 18, 33965, {1, 1, 3, 15, 23, 35, 31, 171, 175, 883, 593, 245, 6209, 7381, 5555, 54507, 66159, 40771}},
+{15425, 18, 33978, {1, 3, 3, 11, 3, 63, 75, 177, 239, 77, 1543, 875, 7951, 7571, 961, 9909, 101781, 160399}},
+{15426, 18, 33986, {1, 3, 1, 3, 3, 37, 71, 231, 373, 443, 835, 1321, 2107, 2929, 7527, 47969, 15329, 94537}},
+{15427, 18, 34006, {1, 3, 3, 15, 7, 5, 127, 121, 159, 25, 399, 3009, 4401, 9649, 4311, 18045, 22557, 135177}},
+{15428, 18, 34025, {1, 1, 1, 3, 29, 57, 75, 73, 261, 493, 1417, 1351, 3407, 8553, 4893, 10325, 123149, 161435}},
+{15429, 18, 34106, {1, 3, 3, 11, 15, 5, 87, 115, 337, 213, 949, 1925, 5057, 5831, 6837, 51167, 25291, 182197}},
+{15430, 18, 34126, {1, 3, 1, 11, 25, 49, 27, 101, 403, 989, 1129, 3933, 1147, 13091, 11965, 38075, 68251, 103293}},
+{15431, 18, 34171, {1, 1, 7, 5, 7, 49, 1, 189, 275, 63, 149, 3255, 1175, 7811, 24845, 20755, 99391, 140673}},
+{15432, 18, 34189, {1, 3, 1, 13, 17, 35, 37, 37, 415, 125, 643, 443, 6215, 299, 31237, 45687, 78535, 102123}},
+{15433, 18, 34204, {1, 3, 5, 3, 27, 41, 85, 215, 47, 21, 725, 1967, 2317, 121, 7827, 48229, 82027, 60271}},
+{15434, 18, 34260, {1, 3, 5, 1, 1, 55, 37, 183, 117, 421, 383, 3883, 5519, 6161, 6823, 18423, 77747, 215969}},
+{15435, 18, 34270, {1, 3, 5, 13, 31, 3, 117, 59, 375, 797, 1129, 1283, 3245, 12775, 30353, 3837, 130273, 228899}},
+{15436, 18, 34280, {1, 3, 5, 1, 7, 33, 17, 153, 179, 255, 537, 2911, 1223, 367, 18131, 25903, 33509, 220031}},
+{15437, 18, 34298, {1, 3, 7, 5, 5, 7, 103, 233, 309, 947, 1835, 3509, 4267, 15619, 5895, 30707, 81841, 191899}},
+{15438, 18, 34313, {1, 1, 5, 11, 3, 15, 91, 83, 319, 765, 895, 2565, 6833, 1719, 2971, 37483, 21709, 23193}},
+{15439, 18, 34321, {1, 1, 3, 11, 31, 57, 83, 233, 439, 161, 1503, 749, 6347, 15379, 2317, 24671, 93399, 239585}},
+{15440, 18, 34333, {1, 1, 3, 9, 29, 45, 19, 107, 295, 153, 189, 2521, 5465, 7321, 6143, 229, 100553, 258911}},
+{15441, 18, 34370, {1, 3, 7, 11, 31, 27, 95, 21, 249, 981, 1725, 1481, 1025, 9301, 11809, 53109, 29007, 127683}},
+{15442, 18, 34376, {1, 3, 1, 3, 1, 23, 97, 137, 5, 471, 1887, 1035, 2681, 5143, 3145, 1517, 88107, 245245}},
+{15443, 18, 34387, {1, 1, 1, 1, 15, 11, 13, 9, 405, 607, 403, 1693, 4363, 9365, 6425, 48121, 78969, 87341}},
+{15444, 18, 34389, {1, 1, 7, 15, 3, 17, 7, 51, 111, 1023, 9, 465, 1909, 16283, 4763, 50939, 119029, 198257}},
+{15445, 18, 34417, {1, 3, 3, 1, 31, 11, 113, 13, 499, 433, 1941, 991, 5439, 3123, 24591, 16171, 55099, 206015}},
+{15446, 18, 34429, {1, 3, 5, 15, 25, 49, 125, 101, 251, 619, 1895, 4063, 3065, 14965, 20081, 11233, 58253, 69633}},
+{15447, 18, 34440, {1, 1, 1, 5, 21, 35, 29, 241, 359, 553, 1001, 1865, 5183, 5233, 16371, 55277, 102091, 143275}},
+{15448, 18, 34443, {1, 1, 1, 3, 29, 37, 3, 191, 239, 961, 2031, 1337, 1169, 5229, 22861, 38257, 55027, 153703}},
+{15449, 18, 34451, {1, 3, 5, 7, 7, 35, 49, 139, 509, 381, 1267, 2641, 747, 16239, 23133, 32111, 70471, 128427}},
+{15450, 18, 34470, {1, 1, 1, 9, 23, 25, 117, 125, 369, 891, 103, 2215, 3571, 1291, 9001, 35671, 67119, 198847}},
+{15451, 18, 34484, {1, 1, 5, 9, 17, 19, 27, 7, 207, 55, 1099, 2117, 7511, 14999, 7761, 32215, 103401, 68599}},
+{15452, 18, 34493, {1, 1, 7, 9, 1, 59, 41, 91, 9, 225, 457, 3241, 4713, 2923, 11973, 2867, 130583, 202007}},
+{15453, 18, 34496, {1, 3, 1, 9, 31, 47, 63, 49, 457, 757, 885, 937, 2973, 12147, 2607, 52907, 126047, 83275}},
+{15454, 18, 34514, {1, 3, 5, 11, 17, 1, 79, 123, 505, 203, 1779, 71, 4357, 2285, 31625, 15225, 86519, 2021}},
+{15455, 18, 34526, {1, 3, 1, 11, 21, 17, 41, 169, 125, 995, 351, 1235, 25, 7463, 2099, 18917, 71355, 26983}},
+{15456, 18, 34535, {1, 1, 7, 1, 21, 23, 41, 5, 415, 405, 1235, 1245, 151, 11283, 25293, 45147, 12597, 39501}},
+{15457, 18, 34585, {1, 1, 1, 5, 29, 29, 15, 165, 259, 179, 1479, 3535, 779, 6583, 885, 34331, 71193, 154417}},
+{15458, 18, 34591, {1, 1, 1, 5, 3, 1, 13, 181, 507, 339, 333, 4059, 7963, 15649, 15507, 16913, 34741, 202039}},
+{15459, 18, 34592, {1, 3, 7, 1, 1, 9, 17, 119, 77, 583, 259, 883, 4011, 4275, 9599, 58663, 73237, 202783}},
+{15460, 18, 34602, {1, 1, 5, 11, 23, 27, 19, 171, 373, 779, 661, 1701, 3363, 13095, 897, 51233, 1319, 41093}},
+{15461, 18, 34607, {1, 3, 3, 3, 29, 21, 105, 29, 429, 657, 1735, 1279, 809, 14963, 9735, 23251, 44879, 159371}},
+{15462, 18, 34644, {1, 1, 5, 11, 17, 27, 117, 65, 193, 539, 1095, 439, 1687, 11277, 513, 30611, 88885, 69145}},
+{15463, 18, 34657, {1, 3, 1, 7, 11, 1, 27, 41, 63, 501, 917, 2397, 6839, 10835, 26437, 56169, 46631, 64095}},
+{15464, 18, 34675, {1, 1, 7, 15, 29, 5, 17, 217, 333, 389, 403, 3167, 3599, 12055, 30669, 44821, 109811, 237393}},
+{15465, 18, 34681, {1, 3, 5, 13, 1, 39, 51, 233, 159, 135, 763, 2499, 7741, 13099, 8639, 8043, 39827, 5989}},
+{15466, 18, 34693, {1, 1, 7, 3, 1, 61, 41, 37, 37, 67, 867, 2631, 6265, 5551, 161, 56643, 126087, 126829}},
+{15467, 18, 34706, {1, 1, 7, 1, 21, 39, 101, 225, 489, 123, 661, 2489, 1865, 6809, 21663, 59405, 45579, 51257}},
+{15468, 18, 34745, {1, 3, 7, 9, 27, 53, 11, 97, 369, 389, 1933, 3321, 543, 12331, 11571, 10685, 49049, 244027}},
+{15469, 18, 34759, {1, 3, 5, 3, 7, 15, 21, 165, 181, 877, 1161, 1815, 2097, 449, 32411, 22843, 12467, 55397}},
+{15470, 18, 34765, {1, 3, 1, 3, 11, 45, 23, 193, 287, 137, 333, 1831, 457, 583, 23081, 4525, 4781, 249509}},
+{15471, 18, 34774, {1, 3, 5, 5, 15, 13, 27, 199, 267, 297, 923, 3861, 4949, 7945, 25291, 45407, 47529, 127287}},
+{15472, 18, 34780, {1, 1, 5, 7, 19, 29, 113, 51, 503, 487, 699, 2097, 2957, 6519, 19487, 46873, 38871, 89997}},
+{15473, 18, 34794, {1, 1, 5, 13, 17, 31, 57, 127, 335, 223, 1545, 3749, 1539, 3293, 21159, 13019, 48343, 190895}},
+{15474, 18, 34807, {1, 1, 7, 9, 25, 19, 75, 41, 511, 269, 819, 3313, 6805, 15051, 4349, 1809, 34841, 190641}},
+{15475, 18, 34808, {1, 3, 5, 9, 27, 7, 91, 187, 123, 519, 477, 2719, 211, 1225, 22689, 37043, 66291, 205441}},
+{15476, 18, 34835, {1, 1, 5, 13, 5, 41, 95, 49, 187, 239, 1213, 2363, 8075, 12423, 6361, 42471, 70047, 188063}},
+{15477, 18, 34842, {1, 3, 7, 3, 27, 23, 21, 217, 65, 143, 1171, 1441, 1603, 2235, 20923, 32611, 111903, 132771}},
+{15478, 18, 34865, {1, 1, 7, 9, 3, 29, 33, 203, 497, 179, 1253, 2083, 7407, 12551, 8371, 62167, 93875, 193017}},
+{15479, 18, 34907, {1, 1, 1, 13, 7, 61, 43, 107, 417, 757, 1701, 3187, 5489, 11359, 20469, 20249, 93581, 207969}},
+{15480, 18, 34928, {1, 1, 7, 3, 31, 51, 51, 183, 483, 885, 1627, 3605, 6687, 1271, 27013, 40409, 103807, 189805}},
+{15481, 18, 34949, {1, 1, 3, 1, 21, 21, 107, 185, 267, 981, 147, 1873, 1085, 15829, 10315, 21673, 7713, 120087}},
+{15482, 18, 34961, {1, 1, 5, 3, 7, 27, 73, 131, 287, 657, 1351, 547, 3655, 2433, 6753, 2465, 110299, 194587}},
+{15483, 18, 34964, {1, 1, 7, 7, 17, 55, 29, 223, 411, 775, 745, 3515, 4573, 4289, 7411, 55999, 22021, 110567}},
+{15484, 18, 34987, {1, 3, 1, 3, 29, 55, 7, 183, 507, 773, 1299, 3653, 7693, 3773, 29549, 4171, 123039, 137495}},
+{15485, 18, 34990, {1, 1, 1, 7, 5, 25, 53, 85, 41, 837, 587, 2997, 7281, 6821, 15609, 47855, 49017, 108557}},
+{15486, 18, 35019, {1, 1, 5, 5, 1, 17, 109, 231, 295, 825, 1909, 683, 2197, 1895, 8641, 37917, 36347, 38683}},
+{15487, 18, 35069, {1, 3, 7, 3, 23, 39, 91, 121, 223, 505, 127, 3439, 7779, 12917, 17351, 33063, 84019, 40077}},
+{15488, 18, 35077, {1, 3, 3, 1, 19, 1, 125, 99, 143, 549, 709, 3605, 2377, 761, 14369, 52191, 80811, 214877}},
+{15489, 18, 35090, {1, 1, 7, 9, 13, 57, 39, 91, 505, 299, 1241, 1697, 5821, 5327, 22439, 42321, 120941, 40009}},
+{15490, 18, 35152, {1, 1, 3, 13, 15, 59, 15, 129, 265, 841, 1255, 1915, 4645, 5991, 26801, 7839, 66961, 59045}},
+{15491, 18, 35173, {1, 3, 7, 15, 17, 57, 61, 173, 391, 1001, 1815, 2565, 1445, 13237, 2273, 61683, 62327, 180255}},
+{15492, 18, 35174, {1, 1, 3, 3, 23, 29, 115, 185, 333, 103, 1807, 3271, 4803, 9743, 3031, 25263, 30761, 1899}},
+{15493, 18, 35202, {1, 1, 1, 7, 1, 13, 63, 113, 467, 17, 1803, 3141, 7069, 8895, 25823, 40347, 11211, 88769}},
+{15494, 18, 35214, {1, 3, 5, 1, 3, 3, 29, 101, 315, 915, 341, 287, 4167, 7579, 19797, 18287, 19079, 52805}},
+{15495, 18, 35219, {1, 3, 7, 15, 31, 61, 27, 153, 387, 273, 343, 881, 2273, 6621, 19391, 41735, 123899, 117851}},
+{15496, 18, 35226, {1, 1, 7, 11, 5, 49, 83, 223, 87, 341, 1023, 2785, 3635, 2651, 5179, 25907, 115249, 74001}},
+{15497, 18, 35235, {1, 3, 3, 7, 31, 37, 123, 79, 365, 455, 639, 691, 2659, 12215, 26785, 48785, 120175, 155501}},
+{15498, 18, 35255, {1, 3, 3, 11, 19, 49, 81, 97, 429, 317, 257, 663, 5009, 2855, 22721, 51553, 32511, 188977}},
+{15499, 18, 35310, {1, 1, 7, 11, 5, 37, 1, 123, 477, 747, 839, 3975, 6347, 489, 31387, 56037, 62935, 177587}},
+{15500, 18, 35318, {1, 1, 1, 1, 29, 7, 119, 233, 255, 25, 127, 1377, 991, 12151, 31259, 64863, 34733, 86101}},
+{15501, 18, 35321, {1, 3, 7, 5, 19, 57, 67, 1, 81, 719, 891, 2485, 3817, 1055, 437, 9779, 23823, 173219}},
+{15502, 18, 35333, {1, 1, 1, 5, 1, 63, 87, 163, 135, 809, 637, 1233, 5245, 481, 11011, 23477, 114963, 96051}},
+{15503, 18, 35337, {1, 1, 7, 5, 25, 39, 57, 129, 311, 525, 1555, 179, 639, 4949, 8809, 31215, 95975, 79407}},
+{15504, 18, 35346, {1, 3, 1, 1, 15, 59, 77, 87, 479, 889, 1619, 331, 4781, 10597, 935, 28105, 83861, 134273}},
+{15505, 18, 35373, {1, 3, 5, 15, 21, 55, 61, 105, 373, 185, 1579, 3487, 2621, 8993, 6443, 31709, 57329, 128165}},
+{15506, 18, 35414, {1, 3, 3, 3, 7, 21, 117, 159, 177, 927, 1873, 1865, 3219, 1693, 1173, 34365, 107053, 113949}},
+{15507, 18, 35478, {1, 3, 7, 1, 17, 37, 35, 101, 305, 141, 1681, 1949, 47, 11351, 989, 13887, 127429, 13059}},
+{15508, 18, 35497, {1, 1, 3, 7, 13, 41, 125, 115, 65, 621, 1401, 631, 5875, 8589, 17185, 22757, 83625, 92907}},
+{15509, 18, 35503, {1, 3, 1, 5, 25, 37, 73, 39, 495, 645, 265, 2685, 5875, 5919, 23223, 44593, 26207, 49921}},
+{15510, 18, 35512, {1, 3, 1, 13, 25, 31, 39, 15, 179, 791, 1817, 3617, 2139, 1827, 21215, 21767, 15009, 239443}},
+{15511, 18, 35515, {1, 1, 3, 7, 17, 9, 33, 121, 235, 535, 1537, 3307, 2881, 4351, 4721, 34131, 129619, 137993}},
+{15512, 18, 35526, {1, 1, 3, 1, 3, 51, 79, 213, 205, 323, 1749, 2563, 2013, 6519, 18923, 25937, 74445, 252283}},
+{15513, 18, 35577, {1, 3, 5, 11, 3, 53, 17, 195, 305, 543, 1937, 2997, 4593, 7801, 15307, 46359, 39365, 59537}},
+{15514, 18, 35585, {1, 1, 1, 13, 31, 53, 111, 163, 139, 163, 999, 83, 5125, 10047, 11143, 51407, 13627, 3621}},
+{15515, 18, 35592, {1, 1, 3, 9, 5, 1, 125, 95, 281, 939, 913, 1441, 1209, 12983, 27759, 22393, 75985, 178997}},
+{15516, 18, 35615, {1, 3, 5, 3, 5, 27, 91, 41, 51, 447, 491, 3405, 497, 2873, 17865, 30651, 104197, 71751}},
+{15517, 18, 35616, {1, 3, 7, 1, 29, 61, 73, 31, 423, 933, 1327, 809, 1461, 269, 15121, 18649, 36095, 139429}},
+{15518, 18, 35622, {1, 1, 7, 7, 19, 49, 51, 173, 297, 411, 1255, 1093, 2821, 6743, 1927, 27563, 68459, 261411}},
+{15519, 18, 35634, {1, 3, 5, 1, 5, 33, 27, 119, 103, 615, 149, 2299, 6801, 15615, 7361, 31045, 87719, 9557}},
+{15520, 18, 35657, {1, 1, 3, 9, 17, 23, 89, 35, 151, 385, 319, 2065, 1897, 1987, 15159, 34855, 5395, 110751}},
+{15521, 18, 35672, {1, 3, 1, 13, 7, 47, 19, 185, 207, 787, 1179, 1073, 1463, 6277, 6129, 25031, 91969, 123235}},
+{15522, 18, 35708, {1, 1, 7, 3, 19, 63, 97, 1, 381, 71, 1169, 339, 6585, 3629, 31357, 59451, 102735, 253667}},
+{15523, 18, 35772, {1, 3, 3, 13, 9, 27, 69, 17, 509, 599, 1247, 2267, 3309, 1905, 17995, 41263, 5947, 51607}},
+{15524, 18, 35790, {1, 3, 1, 9, 31, 45, 69, 243, 171, 555, 61, 1135, 1993, 8615, 18363, 19545, 64015, 81391}},
+{15525, 18, 35804, {1, 1, 1, 1, 19, 49, 31, 65, 53, 123, 271, 3007, 4509, 9465, 3855, 12673, 19457, 14677}},
+{15526, 18, 35811, {1, 3, 5, 13, 29, 53, 91, 145, 115, 53, 839, 1911, 2887, 6053, 18437, 42273, 63093, 70937}},
+{15527, 18, 35814, {1, 1, 5, 5, 27, 13, 87, 175, 485, 699, 463, 811, 4991, 15303, 23007, 10021, 59125, 39997}},
+{15528, 18, 35837, {1, 1, 5, 5, 27, 21, 89, 61, 109, 555, 953, 2811, 3015, 3249, 16085, 64413, 84605, 177333}},
+{15529, 18, 35846, {1, 1, 7, 3, 1, 29, 83, 143, 67, 577, 971, 2339, 6521, 6341, 27141, 37149, 99813, 37579}},
+{15530, 18, 35873, {1, 3, 3, 7, 23, 29, 117, 5, 287, 559, 667, 2349, 7481, 679, 9633, 40857, 89841, 98125}},
+{15531, 18, 35883, {1, 1, 1, 3, 31, 31, 83, 117, 213, 213, 23, 3803, 5967, 7759, 19521, 13229, 62231, 150687}},
+{15532, 18, 35918, {1, 3, 7, 9, 1, 15, 37, 191, 19, 107, 1723, 3517, 3477, 3777, 4359, 45815, 58661, 33217}},
+{15533, 18, 35920, {1, 1, 5, 1, 17, 3, 3, 255, 501, 1021, 1731, 481, 6145, 3475, 3417, 11847, 92203, 75109}},
+{15534, 18, 35925, {1, 1, 5, 1, 1, 61, 89, 107, 503, 627, 931, 1355, 2067, 12487, 20665, 61543, 15501, 103843}},
+{15535, 18, 35926, {1, 1, 5, 9, 25, 17, 7, 255, 251, 939, 851, 2241, 939, 15331, 29357, 2485, 80791, 152601}},
+{15536, 18, 35945, {1, 1, 5, 3, 13, 25, 35, 113, 83, 765, 1317, 1409, 369, 2215, 5659, 3581, 13925, 108673}},
+{15537, 18, 35956, {1, 1, 1, 1, 13, 13, 83, 27, 5, 563, 723, 2733, 3155, 6567, 24595, 45569, 37587, 144401}},
+{15538, 18, 36003, {1, 1, 1, 9, 31, 51, 73, 105, 299, 857, 669, 963, 4115, 14939, 11669, 46215, 92707, 149249}},
+{15539, 18, 36023, {1, 1, 3, 5, 7, 41, 105, 213, 3, 999, 93, 1497, 6783, 1559, 20047, 40761, 88219, 64769}},
+{15540, 18, 36024, {1, 3, 1, 5, 13, 17, 79, 29, 453, 75, 1095, 623, 7401, 4225, 30467, 60795, 130045, 154767}},
+{15541, 18, 36059, {1, 1, 5, 3, 31, 59, 33, 129, 505, 277, 1623, 3531, 6841, 12903, 7231, 5801, 92405, 260195}},
+{15542, 18, 36061, {1, 1, 3, 5, 27, 23, 63, 219, 225, 547, 1163, 1899, 4191, 9725, 30077, 30157, 73395, 38195}},
+{15543, 18, 36072, {1, 1, 1, 11, 17, 27, 63, 127, 95, 205, 1753, 2023, 6803, 4355, 28169, 16691, 25105, 8969}},
+{15544, 18, 36075, {1, 1, 5, 3, 23, 23, 89, 115, 231, 647, 513, 3161, 3175, 5061, 5797, 35387, 109827, 19511}},
+{15545, 18, 36103, {1, 3, 5, 5, 11, 9, 39, 251, 367, 253, 2031, 3909, 1057, 12545, 25397, 51571, 91229, 83721}},
+{15546, 18, 36110, {1, 3, 5, 7, 5, 35, 57, 153, 111, 789, 177, 2237, 1333, 13185, 993, 22099, 62113, 211815}},
+{15547, 18, 36131, {1, 1, 5, 15, 19, 37, 123, 221, 375, 605, 791, 1663, 7537, 7193, 20149, 58077, 113129, 185493}},
+{15548, 18, 36151, {1, 1, 1, 1, 1, 53, 117, 227, 441, 851, 1171, 4031, 2313, 2847, 25533, 31767, 18197, 153101}},
+{15549, 18, 36160, {1, 1, 3, 3, 13, 9, 65, 225, 71, 763, 1507, 3795, 4321, 399, 12515, 4527, 89193, 236161}},
+{15550, 18, 36199, {1, 1, 3, 11, 21, 63, 73, 125, 369, 309, 953, 3525, 3925, 13609, 26061, 21739, 112867, 112985}},
+{15551, 18, 36223, {1, 1, 7, 1, 27, 25, 3, 129, 321, 193, 1871, 233, 837, 11163, 14861, 42721, 72849, 206739}},
+{15552, 18, 36227, {1, 3, 7, 3, 5, 51, 43, 177, 167, 11, 1297, 1805, 515, 6485, 8253, 271, 47435, 252291}},
+{15553, 18, 36234, {1, 3, 3, 3, 19, 47, 47, 47, 299, 101, 1535, 3593, 4669, 10367, 19219, 16579, 85269, 36115}},
+{15554, 18, 36236, {1, 1, 7, 15, 7, 51, 53, 181, 379, 267, 985, 3401, 2189, 10197, 14183, 413, 76797, 24751}},
+{15555, 18, 36284, {1, 1, 5, 7, 13, 27, 65, 119, 235, 131, 1921, 3411, 1511, 11221, 30315, 11799, 127563, 203533}},
+{15556, 18, 36319, {1, 3, 1, 3, 13, 55, 101, 189, 483, 261, 467, 645, 417, 6203, 9221, 19671, 102331, 259335}},
+{15557, 18, 36332, {1, 1, 5, 15, 19, 7, 81, 1, 371, 119, 1433, 1211, 303, 14393, 27107, 45295, 109211, 224661}},
+{15558, 18, 36343, {1, 3, 7, 9, 19, 53, 31, 55, 103, 351, 1511, 377, 981, 6709, 19553, 53579, 55043, 170489}},
+{15559, 18, 36373, {1, 3, 3, 15, 31, 49, 1, 251, 187, 73, 119, 3041, 5455, 5355, 22245, 7735, 14661, 258447}},
+{15560, 18, 36401, {1, 3, 7, 11, 13, 1, 61, 97, 179, 975, 1653, 3301, 4303, 2271, 30171, 63287, 51271, 21909}},
+{15561, 18, 36413, {1, 1, 5, 11, 21, 45, 101, 131, 121, 881, 1205, 1849, 4337, 5687, 31967, 22559, 98017, 202557}},
+{15562, 18, 36433, {1, 3, 3, 7, 1, 49, 11, 35, 141, 309, 651, 3319, 4313, 3675, 27699, 49429, 109805, 167089}},
+{15563, 18, 36459, {1, 1, 3, 13, 13, 15, 61, 251, 335, 365, 677, 2183, 6291, 8857, 15231, 551, 63149, 76729}},
+{15564, 18, 36480, {1, 3, 3, 13, 1, 59, 85, 127, 409, 1007, 1947, 3495, 6227, 11447, 14329, 3769, 109619, 59063}},
+{15565, 18, 36485, {1, 3, 5, 11, 11, 59, 67, 209, 491, 757, 1137, 1977, 3155, 9339, 11219, 20303, 66417, 187911}},
+{15566, 18, 36510, {1, 1, 5, 9, 27, 51, 87, 249, 327, 867, 29, 3811, 4769, 12353, 24803, 35747, 84101, 210975}},
+{15567, 18, 36513, {1, 3, 7, 7, 23, 37, 23, 55, 237, 543, 779, 1305, 1535, 13333, 1403, 10903, 113135, 195799}},
+{15568, 18, 36523, {1, 1, 3, 11, 1, 1, 3, 153, 401, 35, 981, 79, 4227, 9203, 8179, 29325, 104809, 140613}},
+{15569, 18, 36528, {1, 3, 5, 9, 13, 39, 101, 181, 507, 307, 1411, 1443, 6855, 8747, 22709, 37869, 102303, 577}},
+{15570, 18, 36537, {1, 3, 5, 1, 25, 41, 3, 239, 195, 1, 1277, 2085, 4253, 14683, 24171, 56733, 82795, 213291}},
+{15571, 18, 36558, {1, 1, 3, 5, 25, 55, 31, 55, 215, 149, 1813, 3775, 779, 6137, 10561, 41671, 96883, 177435}},
+{15572, 18, 36563, {1, 1, 5, 11, 15, 5, 1, 237, 131, 13, 229, 3203, 2431, 1829, 31983, 59535, 31381, 175455}},
+{15573, 18, 36576, {1, 3, 3, 7, 5, 19, 61, 253, 223, 609, 1395, 2495, 5501, 6571, 12989, 889, 49435, 200251}},
+{15574, 18, 36608, {1, 1, 7, 13, 25, 49, 33, 157, 457, 259, 1935, 2249, 7419, 12685, 30509, 32187, 108839, 178963}},
+{15575, 18, 36611, {1, 3, 3, 15, 19, 27, 91, 133, 369, 931, 359, 759, 2647, 13643, 14877, 14031, 115367, 201745}},
+{15576, 18, 36617, {1, 1, 5, 3, 9, 23, 87, 27, 203, 995, 1759, 999, 949, 2733, 29053, 46581, 129003, 42585}},
+{15577, 18, 36653, {1, 1, 3, 1, 1, 21, 63, 243, 257, 741, 681, 2471, 2455, 15145, 31739, 8751, 15963, 165405}},
+{15578, 18, 36716, {1, 3, 3, 1, 25, 21, 69, 213, 219, 9, 199, 487, 4103, 141, 18177, 58797, 60415, 6313}},
+{15579, 18, 36721, {1, 3, 1, 5, 23, 43, 61, 121, 123, 89, 283, 1313, 2707, 10199, 7699, 17437, 130995, 140327}},
+{15580, 18, 36733, {1, 3, 5, 13, 31, 41, 111, 39, 403, 5, 1125, 2867, 3143, 7051, 9891, 43349, 20751, 88465}},
+{15581, 18, 36761, {1, 1, 3, 1, 19, 53, 83, 207, 285, 789, 1515, 3455, 4057, 15777, 27879, 46971, 122661, 143407}},
+{15582, 18, 36783, {1, 3, 3, 11, 25, 21, 127, 191, 313, 357, 1625, 1323, 1151, 12509, 22275, 23517, 12221, 258709}},
+{15583, 18, 36786, {1, 1, 5, 7, 1, 47, 1, 107, 387, 965, 1319, 2911, 2121, 8595, 9, 21587, 81187, 2803}},
+{15584, 18, 36795, {1, 3, 3, 5, 19, 55, 37, 213, 23, 767, 1493, 635, 4289, 2503, 16835, 47851, 77335, 60565}},
+{15585, 18, 36800, {1, 1, 1, 7, 23, 9, 101, 145, 457, 691, 1895, 2145, 7527, 7687, 20781, 10957, 24859, 79137}},
+{15586, 18, 36810, {1, 3, 7, 15, 9, 9, 15, 195, 493, 859, 687, 1445, 429, 8599, 24591, 40709, 118361, 148163}},
+{15587, 18, 36812, {1, 1, 1, 3, 7, 51, 45, 143, 339, 475, 1177, 2829, 785, 10141, 4923, 29135, 22603, 119973}},
+{15588, 18, 36817, {1, 3, 5, 15, 25, 37, 1, 13, 351, 127, 143, 2637, 1215, 14577, 12465, 10575, 67997, 21877}},
+{15589, 18, 36818, {1, 3, 7, 3, 27, 19, 59, 241, 327, 307, 731, 3471, 6123, 13607, 8793, 14825, 110681, 83259}},
+{15590, 18, 36851, {1, 1, 1, 11, 25, 5, 59, 85, 335, 189, 499, 1305, 5801, 7259, 2397, 14045, 55585, 258579}},
+{15591, 18, 36853, {1, 1, 3, 5, 21, 49, 49, 63, 261, 657, 1453, 55, 1325, 15513, 14891, 60689, 15381, 252641}},
+{15592, 18, 36868, {1, 1, 7, 15, 25, 3, 85, 33, 495, 867, 903, 1813, 2871, 365, 17399, 45695, 102851, 225873}},
+{15593, 18, 36889, {1, 1, 1, 13, 13, 63, 29, 35, 325, 893, 1313, 133, 8169, 7791, 9271, 36759, 92275, 169717}},
+{15594, 18, 36890, {1, 1, 7, 3, 21, 45, 7, 151, 387, 891, 1921, 1701, 307, 5323, 16321, 51229, 79369, 21513}},
+{15595, 18, 36896, {1, 1, 1, 11, 7, 27, 17, 75, 161, 649, 337, 1731, 2905, 4589, 17387, 10455, 70673, 228373}},
+{15596, 18, 36905, {1, 1, 3, 15, 17, 35, 45, 131, 469, 629, 1771, 1965, 5065, 6249, 29041, 52791, 55619, 154531}},
+{15597, 18, 36919, {1, 1, 7, 3, 25, 53, 85, 233, 161, 163, 1155, 3159, 1551, 13099, 25647, 26777, 91647, 162755}},
+{15598, 18, 36938, {1, 1, 3, 9, 17, 11, 39, 63, 503, 927, 1621, 3425, 4835, 7083, 16449, 47913, 127905, 165567}},
+{15599, 18, 36946, {1, 1, 7, 1, 29, 9, 1, 111, 285, 1009, 1427, 3071, 205, 12269, 31337, 14501, 10923, 14277}},
+{15600, 18, 36951, {1, 1, 5, 5, 1, 3, 51, 205, 477, 661, 1555, 2113, 6487, 4755, 13633, 16391, 35775, 52623}},
+{15601, 18, 36952, {1, 3, 3, 3, 27, 23, 109, 49, 71, 19, 733, 1361, 4369, 14527, 20443, 10507, 120183, 246115}},
+{15602, 18, 36964, {1, 3, 3, 5, 7, 47, 51, 197, 97, 471, 1631, 3317, 5857, 9405, 30359, 7741, 45079, 175929}},
+{15603, 18, 36968, {1, 1, 3, 3, 13, 63, 39, 173, 511, 525, 1687, 1735, 6877, 7383, 27971, 26503, 6189, 232251}},
+{15604, 18, 36979, {1, 1, 5, 3, 5, 31, 101, 99, 51, 987, 1627, 3899, 6321, 9441, 4983, 64001, 30923, 199495}},
+{15605, 18, 36981, {1, 3, 1, 1, 11, 39, 119, 123, 33, 1017, 1477, 283, 4939, 453, 16445, 25599, 106857, 257811}},
+{15606, 18, 37021, {1, 3, 1, 11, 13, 1, 3, 101, 275, 75, 1795, 1449, 2503, 11765, 19299, 14237, 157, 244825}},
+{15607, 18, 37026, {1, 3, 7, 15, 23, 1, 85, 65, 55, 103, 1523, 1443, 1021, 5733, 3297, 10889, 22487, 82503}},
+{15608, 18, 37075, {1, 1, 7, 3, 17, 59, 109, 113, 17, 173, 1709, 273, 5327, 3243, 10751, 58361, 42303, 78391}},
+{15609, 18, 37077, {1, 1, 5, 15, 25, 11, 101, 133, 193, 131, 1671, 3045, 7111, 14331, 15665, 56407, 31561, 154555}},
+{15610, 18, 37108, {1, 3, 3, 5, 15, 41, 105, 65, 81, 293, 389, 2653, 1883, 14741, 23553, 33349, 39665, 154233}},
+{15611, 18, 37112, {1, 1, 5, 15, 31, 19, 121, 41, 261, 511, 1679, 957, 1647, 12647, 12285, 30291, 122483, 187911}},
+{15612, 18, 37150, {1, 3, 1, 5, 27, 25, 17, 45, 303, 947, 1123, 2729, 281, 12389, 27987, 42667, 16089, 17129}},
+{15613, 18, 37154, {1, 3, 7, 15, 13, 17, 25, 223, 125, 837, 159, 253, 2599, 11381, 639, 32545, 50633, 139025}},
+{15614, 18, 37156, {1, 3, 1, 13, 23, 43, 25, 83, 507, 47, 99, 697, 4453, 2139, 17151, 50709, 37099, 212957}},
+{15615, 18, 37163, {1, 1, 7, 7, 29, 7, 63, 141, 475, 853, 1073, 143, 6979, 5663, 29691, 59489, 89689, 223047}},
+{15616, 18, 37178, {1, 1, 1, 1, 13, 27, 101, 61, 27, 735, 207, 2065, 5811, 5461, 21493, 15481, 103727, 80017}},
+{15617, 18, 37183, {1, 3, 1, 11, 9, 9, 35, 251, 147, 841, 1891, 1909, 5053, 5103, 11751, 16209, 110475, 114875}},
+{15618, 18, 37185, {1, 3, 3, 11, 13, 55, 117, 205, 71, 159, 1797, 989, 2221, 16087, 18287, 8355, 96403, 146613}},
+{15619, 18, 37191, {1, 1, 5, 5, 29, 25, 73, 63, 299, 839, 1225, 3583, 5641, 1341, 29431, 7035, 99107, 13493}},
+{15620, 18, 37198, {1, 1, 3, 5, 27, 53, 9, 51, 79, 701, 667, 1469, 4455, 13761, 18607, 39429, 7687, 201115}},
+{15621, 18, 37203, {1, 3, 7, 11, 23, 35, 101, 129, 491, 369, 565, 2557, 2529, 1003, 16003, 33873, 52155, 861}},
+{15622, 18, 37225, {1, 1, 1, 15, 27, 63, 1, 55, 331, 853, 899, 1027, 7389, 8935, 12559, 27315, 101753, 255331}},
+{15623, 18, 37243, {1, 3, 3, 15, 5, 41, 93, 39, 473, 887, 1667, 847, 7619, 8407, 6539, 31989, 63807, 21861}},
+{15624, 18, 37252, {1, 1, 5, 11, 27, 57, 73, 249, 331, 653, 21, 2937, 4403, 16195, 18785, 30375, 22939, 235291}},
+{15625, 18, 37262, {1, 1, 7, 1, 7, 41, 59, 161, 295, 503, 595, 3021, 455, 3991, 8617, 65361, 107239, 83205}},
+{15626, 18, 37264, {1, 3, 3, 15, 17, 41, 61, 229, 273, 687, 657, 1969, 2817, 2367, 29183, 41199, 24123, 184081}},
+{15627, 18, 37276, {1, 3, 7, 5, 25, 63, 43, 65, 443, 423, 549, 2031, 3353, 7041, 6563, 18819, 46047, 239823}},
+{15628, 18, 37327, {1, 3, 3, 3, 3, 17, 13, 115, 377, 623, 1959, 127, 5125, 13209, 24731, 23151, 21303, 7213}},
+{15629, 18, 37355, {1, 1, 7, 1, 21, 11, 21, 41, 491, 37, 1759, 2771, 1301, 12995, 17621, 30907, 75511, 82321}},
+{15630, 18, 37403, {1, 3, 3, 13, 13, 23, 77, 211, 215, 711, 427, 2213, 8041, 1595, 26105, 39051, 105407, 242141}},
+{15631, 18, 37415, {1, 3, 3, 9, 13, 35, 117, 207, 75, 395, 723, 3321, 6643, 2429, 10043, 10585, 3529, 64067}},
+{15632, 18, 37422, {1, 1, 1, 7, 3, 1, 83, 93, 311, 157, 891, 1717, 7669, 16067, 11775, 27693, 11757, 94471}},
+{15633, 18, 37448, {1, 3, 3, 5, 17, 63, 23, 177, 289, 921, 315, 3083, 5903, 8697, 22425, 37845, 31171, 49237}},
+{15634, 18, 37451, {1, 1, 7, 9, 21, 63, 29, 227, 427, 271, 525, 2071, 7103, 8389, 29185, 51601, 110737, 16949}},
+{15635, 18, 37478, {1, 3, 3, 3, 3, 49, 25, 173, 79, 343, 509, 1939, 6389, 15501, 20135, 54365, 69931, 135269}},
+{15636, 18, 37484, {1, 1, 3, 3, 21, 23, 41, 71, 169, 947, 1027, 2345, 3397, 12181, 15409, 31725, 41223, 58837}},
+{15637, 18, 37525, {1, 3, 7, 1, 19, 23, 57, 201, 27, 449, 1479, 921, 4703, 10949, 14369, 27929, 45399, 46055}},
+{15638, 18, 37553, {1, 1, 3, 9, 13, 17, 125, 17, 393, 295, 497, 3089, 6589, 4003, 8687, 48145, 2683, 175521}},
+{15639, 18, 37640, {1, 3, 3, 15, 15, 13, 3, 31, 51, 101, 973, 101, 3709, 13437, 51, 14293, 21561, 136497}},
+{15640, 18, 37645, {1, 1, 5, 11, 17, 27, 51, 45, 77, 539, 225, 2029, 533, 153, 26085, 33611, 28153, 75671}},
+{15641, 18, 37658, {1, 1, 1, 15, 3, 59, 59, 123, 475, 225, 1613, 3121, 2865, 4647, 14553, 35449, 121657, 37457}},
+{15642, 18, 37667, {1, 1, 5, 1, 27, 33, 121, 225, 57, 619, 1293, 3813, 2121, 3525, 21995, 47253, 33095, 257451}},
+{15643, 18, 37708, {1, 3, 1, 11, 11, 43, 115, 233, 335, 185, 989, 3567, 4135, 2357, 20559, 43325, 43015, 51695}},
+{15644, 18, 37723, {1, 1, 5, 9, 11, 49, 45, 187, 93, 967, 1609, 2511, 1549, 4045, 21309, 16341, 13495, 214827}},
+{15645, 18, 37732, {1, 1, 1, 13, 21, 23, 81, 7, 259, 483, 1059, 773, 5297, 10123, 9857, 61187, 47355, 76307}},
+{15646, 18, 37747, {1, 3, 7, 9, 29, 51, 113, 255, 223, 853, 1173, 1019, 1587, 9629, 22373, 32731, 125179, 193271}},
+{15647, 18, 37753, {1, 1, 5, 11, 3, 55, 25, 145, 347, 451, 1447, 3399, 5873, 11579, 11107, 64707, 10161, 142003}},
+{15648, 18, 37772, {1, 1, 1, 7, 15, 49, 109, 93, 267, 919, 177, 2247, 8129, 8039, 15629, 63767, 98153, 143255}},
+{15649, 18, 37789, {1, 1, 5, 3, 3, 27, 47, 151, 231, 35, 155, 2745, 7349, 6543, 14117, 19549, 54927, 10819}},
+{15650, 18, 37817, {1, 3, 7, 15, 31, 29, 17, 203, 249, 169, 1071, 3069, 6269, 3455, 27177, 33761, 111003, 4527}},
+{15651, 18, 37826, {1, 3, 1, 5, 31, 15, 65, 189, 3, 917, 857, 1221, 3553, 2883, 3631, 32971, 68057, 109081}},
+{15652, 18, 37831, {1, 3, 1, 9, 3, 55, 127, 57, 125, 463, 199, 317, 3373, 967, 5569, 55997, 17167, 33585}},
+{15653, 18, 37845, {1, 3, 5, 1, 9, 57, 15, 89, 335, 119, 1445, 1931, 4177, 2495, 27507, 8209, 60003, 29657}},
+{15654, 18, 37855, {1, 3, 5, 7, 15, 43, 83, 117, 283, 131, 653, 57, 6789, 7633, 30525, 64131, 101981, 122017}},
+{15655, 18, 37859, {1, 3, 7, 11, 3, 17, 115, 217, 391, 825, 1633, 885, 7787, 5595, 12235, 30233, 53587, 62985}},
+{15656, 18, 37866, {1, 1, 5, 3, 5, 13, 99, 1, 75, 329, 1247, 107, 2337, 4201, 6217, 12273, 41585, 46563}},
+{15657, 18, 37880, {1, 3, 1, 15, 25, 53, 33, 125, 311, 955, 161, 3631, 581, 11915, 4223, 63207, 16517, 201665}},
+{15658, 18, 37885, {1, 1, 5, 1, 27, 23, 93, 211, 483, 691, 949, 1825, 391, 12111, 13639, 61009, 88503, 104823}},
+{15659, 18, 37897, {1, 3, 1, 13, 3, 9, 51, 133, 259, 977, 697, 661, 7661, 3987, 8327, 50155, 112235, 236135}},
+{15660, 18, 37906, {1, 1, 3, 13, 7, 39, 121, 37, 151, 973, 1275, 2699, 3345, 7167, 19245, 55535, 12305, 33567}},
+{15661, 18, 37948, {1, 1, 1, 1, 27, 5, 91, 63, 409, 579, 459, 2335, 4721, 3305, 11293, 15405, 74513, 157863}},
+{15662, 18, 37954, {1, 1, 5, 1, 21, 45, 55, 111, 475, 381, 659, 1131, 3575, 5165, 27221, 46757, 53587, 90741}},
+{15663, 18, 37978, {1, 1, 5, 15, 11, 31, 121, 209, 69, 389, 779, 2833, 4519, 1801, 4363, 24723, 105849, 54475}},
+{15664, 18, 37980, {1, 1, 3, 9, 7, 19, 11, 75, 275, 77, 1997, 1661, 6139, 13165, 30653, 49469, 67053, 3811}},
+{15665, 18, 37990, {1, 1, 3, 9, 5, 11, 5, 151, 395, 715, 1381, 3011, 5939, 1805, 8063, 62877, 99749, 112951}},
+{15666, 18, 38001, {1, 1, 5, 13, 19, 15, 113, 47, 455, 173, 1897, 701, 6093, 2089, 3977, 20599, 60947, 23671}},
+{15667, 18, 38020, {1, 1, 1, 13, 23, 19, 13, 117, 275, 313, 1683, 2975, 179, 3949, 4361, 60211, 91999, 211219}},
+{15668, 18, 38029, {1, 3, 5, 15, 13, 53, 83, 161, 491, 1001, 1773, 1227, 1965, 14479, 17677, 24399, 86431, 203303}},
+{15669, 18, 38047, {1, 1, 7, 15, 5, 51, 103, 131, 351, 747, 1227, 2859, 6693, 10615, 29485, 6619, 106239, 148739}},
+{15670, 18, 38063, {1, 3, 5, 1, 9, 43, 91, 173, 223, 393, 1181, 3785, 6589, 1299, 10217, 20891, 64125, 63409}},
+{15671, 18, 38077, {1, 1, 5, 7, 11, 23, 45, 57, 397, 771, 511, 1849, 343, 14139, 26271, 56241, 52581, 163187}},
+{15672, 18, 38110, {1, 3, 7, 5, 15, 59, 89, 151, 255, 247, 291, 219, 995, 10821, 1445, 35581, 88767, 16871}},
+{15673, 18, 38116, {1, 1, 7, 11, 7, 25, 3, 175, 253, 193, 1641, 1669, 7095, 11871, 10801, 42567, 120663, 109347}},
+{15674, 18, 38119, {1, 3, 5, 7, 31, 41, 119, 39, 149, 653, 153, 2783, 1377, 5223, 17915, 3127, 41869, 193477}},
+{15675, 18, 38176, {1, 3, 3, 13, 23, 19, 47, 85, 487, 103, 237, 2363, 4451, 5077, 23749, 17011, 73561, 169165}},
+{15676, 18, 38186, {1, 1, 3, 9, 21, 25, 77, 235, 53, 681, 1463, 2093, 1525, 12797, 5469, 54277, 15587, 68395}},
+{15677, 18, 38194, {1, 1, 1, 15, 23, 63, 63, 225, 239, 143, 1073, 199, 3231, 1371, 11215, 5999, 100705, 174681}},
+{15678, 18, 38218, {1, 1, 1, 3, 17, 25, 69, 179, 445, 695, 281, 379, 8115, 9443, 13221, 50669, 37369, 62151}},
+{15679, 18, 38241, {1, 3, 3, 9, 11, 29, 21, 89, 441, 353, 401, 1139, 5003, 8087, 24457, 50237, 110993, 117233}},
+{15680, 18, 38247, {1, 3, 3, 1, 13, 45, 31, 249, 295, 149, 591, 2071, 3611, 931, 16261, 8239, 82767, 195665}},
+{15681, 18, 38261, {1, 3, 3, 9, 19, 47, 69, 177, 493, 231, 431, 1359, 6867, 7641, 15661, 25285, 65477, 212643}},
+{15682, 18, 38268, {1, 3, 3, 13, 19, 63, 83, 153, 367, 407, 547, 661, 7743, 5473, 2993, 62937, 33811, 101313}},
+{15683, 18, 38277, {1, 3, 5, 3, 29, 17, 19, 203, 79, 279, 1333, 1851, 51, 9793, 12955, 17383, 73437, 121743}},
+{15684, 18, 38287, {1, 1, 1, 11, 11, 43, 31, 187, 463, 827, 1511, 225, 845, 8963, 1553, 61269, 122033, 245633}},
+{15685, 18, 38295, {1, 1, 3, 3, 31, 23, 9, 241, 377, 317, 655, 2197, 2461, 13239, 15649, 7879, 55085, 129855}},
+{15686, 18, 38299, {1, 3, 5, 7, 9, 37, 1, 191, 185, 145, 1567, 3423, 1127, 1991, 10741, 38407, 22915, 222845}},
+{15687, 18, 38301, {1, 1, 5, 3, 27, 31, 11, 227, 307, 973, 745, 1079, 7479, 10065, 31389, 19195, 114775, 246615}},
+{15688, 18, 38305, {1, 3, 1, 11, 29, 27, 11, 83, 205, 399, 1489, 739, 715, 7955, 16473, 21127, 62379, 260399}},
+{15689, 18, 38312, {1, 3, 3, 3, 25, 25, 123, 163, 399, 841, 963, 2089, 4949, 13085, 19831, 15345, 60377, 164235}},
+{15690, 18, 38315, {1, 1, 1, 9, 3, 21, 101, 105, 397, 23, 1505, 3201, 547, 295, 23247, 18823, 115243, 151073}},
+{15691, 18, 38317, {1, 3, 7, 1, 31, 27, 111, 23, 205, 709, 1625, 3921, 6225, 11039, 29549, 51239, 119003, 133663}},
+{15692, 18, 38343, {1, 3, 3, 11, 21, 49, 111, 195, 25, 833, 1991, 563, 7031, 15429, 5707, 12351, 32221, 16599}},
+{15693, 18, 38344, {1, 1, 5, 7, 5, 7, 39, 171, 39, 921, 385, 2343, 625, 15355, 4923, 36597, 56901, 148377}},
+{15694, 18, 38350, {1, 1, 3, 15, 7, 43, 89, 217, 67, 271, 853, 147, 6767, 3183, 341, 40769, 116767, 22351}},
+{15695, 18, 38358, {1, 3, 5, 7, 7, 3, 105, 27, 183, 59, 953, 4027, 1277, 10323, 29437, 56085, 32677, 198067}},
+{15696, 18, 38364, {1, 1, 1, 15, 23, 29, 51, 209, 13, 177, 1103, 1723, 2877, 9199, 25601, 15537, 8599, 230819}},
+{15697, 18, 38371, {1, 1, 7, 1, 29, 39, 41, 217, 467, 423, 431, 2707, 2017, 11865, 11989, 12045, 71349, 6311}},
+{15698, 18, 38373, {1, 1, 1, 13, 15, 25, 3, 55, 403, 833, 1843, 1159, 1703, 2221, 15379, 65027, 18327, 108881}},
+{15699, 18, 38377, {1, 3, 7, 13, 3, 27, 13, 227, 215, 873, 1073, 1117, 7941, 13607, 7571, 6957, 44991, 239761}},
+{15700, 18, 38392, {1, 3, 7, 11, 23, 1, 95, 235, 283, 977, 1443, 161, 5937, 4351, 30835, 35569, 57509, 1835}},
+{15701, 18, 38407, {1, 3, 3, 13, 11, 1, 85, 75, 261, 543, 9, 899, 5821, 5465, 9771, 53707, 101003, 219215}},
+{15702, 18, 38408, {1, 3, 1, 7, 21, 49, 35, 19, 35, 759, 1467, 1423, 6355, 8415, 563, 24157, 121029, 87309}},
+{15703, 18, 38421, {1, 1, 7, 1, 9, 13, 65, 85, 209, 583, 387, 1743, 2665, 12021, 7525, 27665, 45885, 135039}},
+{15704, 18, 38438, {1, 1, 7, 11, 29, 41, 91, 17, 291, 211, 1801, 493, 899, 14491, 1741, 28971, 35205, 131417}},
+{15705, 18, 38442, {1, 1, 5, 13, 23, 55, 119, 165, 61, 653, 1375, 3575, 5081, 7767, 19963, 61583, 107149, 240639}},
+{15706, 18, 38464, {1, 3, 5, 15, 25, 3, 51, 27, 127, 259, 55, 2221, 3951, 6243, 15825, 42881, 37009, 254401}},
+{15707, 18, 38473, {1, 3, 5, 11, 25, 63, 13, 105, 111, 677, 1545, 2399, 4419, 10853, 7213, 17183, 103411, 67459}},
+{15708, 18, 38484, {1, 1, 1, 11, 11, 31, 73, 125, 155, 545, 1857, 2749, 6389, 4083, 16239, 23651, 68881, 43455}},
+{15709, 18, 38491, {1, 3, 7, 7, 21, 3, 117, 237, 431, 17, 687, 2613, 7483, 3253, 30511, 53833, 33077, 157055}},
+{15710, 18, 38510, {1, 1, 1, 1, 1, 57, 65, 97, 415, 477, 1003, 1415, 1493, 12993, 30965, 24809, 1467, 213021}},
+{15711, 18, 38518, {1, 1, 3, 7, 25, 33, 45, 25, 511, 733, 1077, 2483, 5899, 14295, 11631, 50609, 128989, 45177}},
+{15712, 18, 38531, {1, 1, 3, 3, 25, 17, 115, 31, 115, 191, 293, 3991, 3039, 6751, 16217, 16517, 21121, 193641}},
+{15713, 18, 38537, {1, 3, 3, 13, 25, 23, 7, 51, 363, 641, 333, 2533, 605, 1105, 12941, 4195, 129571, 13253}},
+{15714, 18, 38538, {1, 3, 1, 11, 17, 21, 7, 205, 293, 159, 9, 441, 3287, 10247, 2115, 54099, 128109, 8137}},
+{15715, 18, 38567, {1, 1, 7, 5, 21, 17, 43, 87, 117, 737, 149, 3175, 343, 8509, 12147, 22041, 80037, 23277}},
+{15716, 18, 38594, {1, 3, 3, 1, 3, 7, 101, 245, 11, 1003, 175, 2323, 7807, 15611, 5161, 10277, 37009, 83231}},
+{15717, 18, 38647, {1, 3, 1, 5, 13, 17, 113, 75, 315, 237, 77, 587, 5409, 2053, 22551, 15205, 82545, 18531}},
+{15718, 18, 38651, {1, 3, 5, 11, 9, 57, 61, 117, 281, 111, 369, 2411, 1691, 3391, 5379, 8237, 87329, 4253}},
+{15719, 18, 38654, {1, 3, 3, 3, 19, 25, 101, 1, 495, 25, 1317, 2333, 6183, 12215, 27879, 56403, 37169, 71635}},
+{15720, 18, 38686, {1, 1, 3, 5, 17, 63, 49, 127, 171, 405, 1763, 3697, 405, 2233, 4137, 28787, 108319, 53133}},
+{15721, 18, 38702, {1, 1, 5, 7, 23, 43, 87, 189, 97, 239, 1459, 2115, 7517, 7799, 28957, 37105, 71835, 199195}},
+{15722, 18, 38751, {1, 3, 1, 3, 25, 25, 23, 61, 369, 717, 1711, 1103, 7535, 9871, 25, 26849, 55955, 113389}},
+{15723, 18, 38821, {1, 1, 1, 11, 25, 57, 33, 175, 127, 541, 1031, 2847, 2069, 4033, 25593, 10615, 50097, 122955}},
+{15724, 18, 38825, {1, 3, 3, 13, 11, 27, 97, 171, 245, 33, 213, 4069, 753, 3535, 11727, 34941, 100543, 220789}},
+{15725, 18, 38853, {1, 3, 3, 9, 3, 17, 13, 237, 477, 507, 1751, 3191, 3385, 13977, 23355, 57355, 64341, 37683}},
+{15726, 18, 38863, {1, 1, 7, 13, 13, 43, 7, 153, 209, 7, 63, 585, 1715, 13313, 25355, 46759, 71893, 29755}},
+{15727, 18, 38882, {1, 3, 3, 3, 11, 23, 11, 147, 135, 1011, 1105, 3931, 3861, 13589, 32183, 30727, 37685, 67123}},
+{15728, 18, 38884, {1, 3, 7, 1, 11, 13, 25, 229, 147, 843, 329, 3337, 7559, 13193, 3011, 31549, 102461, 46195}},
+{15729, 18, 38932, {1, 1, 5, 11, 5, 47, 127, 89, 53, 663, 261, 541, 7743, 13037, 9013, 23079, 81225, 239875}},
+{15730, 18, 38941, {1, 1, 7, 3, 5, 39, 15, 177, 357, 357, 1959, 1721, 6703, 11829, 1195, 42113, 88699, 244347}},
+{15731, 18, 38952, {1, 1, 5, 15, 25, 19, 7, 3, 225, 773, 1535, 99, 6555, 4105, 19137, 56155, 109141, 161015}},
+{15732, 18, 38960, {1, 1, 5, 15, 5, 59, 41, 53, 203, 459, 1063, 3015, 5397, 1559, 20835, 57773, 67687, 206189}},
+{15733, 18, 38980, {1, 3, 1, 11, 17, 25, 61, 221, 37, 809, 1461, 1961, 7697, 1777, 23179, 54761, 7787, 177737}},
+{15734, 18, 38995, {1, 3, 7, 15, 27, 21, 49, 107, 353, 677, 461, 239, 5871, 1059, 3011, 32397, 13149, 103973}},
+{15735, 18, 39004, {1, 1, 5, 3, 11, 53, 61, 239, 479, 913, 479, 3435, 4979, 7931, 16841, 60077, 26667, 212601}},
+{15736, 18, 39013, {1, 1, 3, 5, 3, 19, 43, 143, 353, 507, 871, 2547, 7321, 6163, 9425, 62911, 86153, 239011}},
+{15737, 18, 39017, {1, 1, 1, 3, 15, 7, 115, 43, 69, 299, 1235, 1511, 3111, 7465, 769, 46981, 127707, 195839}},
+{15738, 18, 39026, {1, 1, 1, 5, 23, 27, 19, 21, 273, 291, 953, 3577, 3147, 3863, 18625, 53505, 33699, 123305}},
+{15739, 18, 39056, {1, 3, 5, 9, 3, 11, 89, 27, 447, 119, 493, 2605, 8175, 8837, 27555, 2319, 99101, 79121}},
+{15740, 18, 39121, {1, 1, 7, 11, 1, 11, 77, 129, 97, 261, 1241, 3117, 1627, 5397, 6495, 52339, 52711, 206237}},
+{15741, 18, 39124, {1, 3, 7, 9, 27, 57, 77, 147, 35, 845, 1417, 1615, 6097, 12559, 10765, 19027, 91693, 204339}},
+{15742, 18, 39133, {1, 1, 3, 5, 25, 47, 17, 145, 7, 969, 1981, 733, 4303, 7785, 4241, 39733, 82569, 78061}},
+{15743, 18, 39157, {1, 1, 5, 1, 5, 47, 45, 111, 405, 943, 1911, 1613, 3817, 10483, 17729, 7201, 88033, 261701}},
+{15744, 18, 39181, {1, 3, 3, 13, 9, 3, 87, 39, 277, 769, 57, 2503, 7803, 11041, 20945, 19623, 32617, 110027}},
+{15745, 18, 39187, {1, 1, 3, 3, 27, 57, 1, 103, 427, 935, 1617, 665, 837, 8001, 13543, 44771, 64033, 65239}},
+{15746, 18, 39212, {1, 1, 5, 3, 13, 21, 31, 59, 225, 945, 1825, 1511, 3273, 3171, 30347, 21993, 40203, 143297}},
+{15747, 18, 39223, {1, 3, 5, 7, 11, 3, 3, 217, 167, 885, 975, 3249, 7909, 13621, 18697, 61021, 31497, 198033}},
+{15748, 18, 39250, {1, 3, 5, 9, 11, 5, 87, 33, 117, 471, 267, 529, 5879, 13969, 5731, 52613, 106411, 74341}},
+{15749, 18, 39265, {1, 1, 7, 11, 5, 31, 25, 55, 135, 779, 717, 1953, 7929, 11011, 6133, 14099, 106975, 178337}},
+{15750, 18, 39320, {1, 3, 1, 1, 29, 17, 125, 7, 445, 299, 1897, 3235, 8189, 14339, 14725, 63185, 126751, 88747}},
+{15751, 18, 39330, {1, 1, 5, 3, 1, 11, 65, 161, 243, 605, 1945, 3141, 6443, 9703, 13331, 2239, 6315, 247595}},
+{15752, 18, 39335, {1, 3, 1, 7, 15, 23, 83, 215, 331, 631, 453, 879, 4109, 4897, 16535, 55749, 90799, 147287}},
+{15753, 18, 39353, {1, 3, 5, 13, 25, 1, 109, 205, 49, 471, 1735, 973, 1279, 9917, 18225, 44921, 98519, 211541}},
+{15754, 18, 39371, {1, 1, 5, 11, 29, 41, 113, 187, 75, 479, 1633, 841, 6259, 8919, 27751, 25179, 115369, 166567}},
+{15755, 18, 39385, {1, 3, 5, 11, 17, 31, 107, 41, 435, 647, 811, 2937, 5819, 3483, 3835, 57033, 53543, 61973}},
+{15756, 18, 39421, {1, 3, 3, 11, 15, 45, 33, 103, 505, 67, 463, 1275, 2449, 15261, 22867, 25215, 38793, 189309}},
+{15757, 18, 39432, {1, 1, 1, 5, 19, 45, 35, 173, 365, 39, 1599, 3623, 2231, 12141, 19437, 27053, 15869, 104719}},
+{15758, 18, 39443, {1, 3, 7, 7, 9, 17, 87, 151, 249, 81, 1109, 1951, 7475, 1699, 17847, 64149, 50285, 242793}},
+{15759, 18, 39450, {1, 3, 5, 13, 15, 51, 35, 105, 479, 763, 1945, 2349, 2987, 621, 283, 20411, 65799, 86517}},
+{15760, 18, 39455, {1, 3, 3, 1, 19, 31, 49, 229, 249, 689, 737, 4027, 5405, 15211, 26785, 39143, 93163, 190421}},
+{15761, 18, 39468, {1, 3, 7, 5, 1, 21, 63, 97, 347, 73, 745, 3455, 2347, 3821, 31385, 6545, 91803, 72895}},
+{15762, 18, 39473, {1, 1, 1, 15, 23, 11, 107, 47, 183, 235, 1985, 3277, 933, 8491, 14423, 24293, 6783, 162199}},
+{15763, 18, 39488, {1, 3, 3, 9, 17, 3, 123, 59, 277, 773, 1617, 2979, 1555, 9753, 10947, 24745, 89043, 45185}},
+{15764, 18, 39497, {1, 3, 7, 3, 25, 17, 79, 43, 311, 415, 1045, 1289, 7451, 11413, 11319, 37177, 101327, 147453}},
+{15765, 18, 39521, {1, 3, 7, 7, 17, 45, 49, 33, 313, 613, 1773, 773, 161, 13579, 1207, 5681, 120597, 178639}},
+{15766, 18, 39531, {1, 3, 5, 5, 17, 43, 65, 243, 287, 223, 253, 687, 887, 14887, 1077, 53337, 62381, 43531}},
+{15767, 18, 39542, {1, 3, 5, 1, 21, 3, 39, 149, 497, 939, 1537, 437, 5345, 10321, 25151, 48785, 49879, 90945}},
+{15768, 18, 39585, {1, 1, 7, 11, 1, 61, 113, 63, 285, 615, 343, 2897, 1939, 7911, 16387, 10781, 92769, 27995}},
+{15769, 18, 39605, {1, 1, 3, 3, 19, 29, 85, 227, 355, 857, 883, 1853, 5065, 13795, 5749, 59107, 57947, 35775}},
+{15770, 18, 39658, {1, 3, 5, 9, 23, 37, 119, 161, 23, 511, 81, 973, 4769, 10821, 32607, 61731, 64907, 99055}},
+{15771, 18, 39677, {1, 3, 1, 3, 11, 17, 109, 241, 349, 887, 1651, 3865, 2045, 15893, 4597, 11557, 53313, 48489}},
+{15772, 18, 39703, {1, 1, 5, 9, 31, 43, 49, 193, 171, 477, 363, 735, 1379, 8977, 9759, 56477, 99495, 170433}},
+{15773, 18, 39726, {1, 1, 3, 7, 25, 25, 77, 31, 21, 1001, 1527, 1725, 6479, 8927, 11249, 63969, 86291, 74391}},
+{15774, 18, 39731, {1, 3, 5, 13, 1, 43, 27, 7, 507, 569, 251, 2199, 3895, 7845, 13641, 1655, 112949, 119493}},
+{15775, 18, 39745, {1, 3, 7, 15, 7, 1, 123, 27, 121, 261, 201, 1469, 4229, 2933, 25157, 1919, 127937, 21607}},
+{15776, 18, 39776, {1, 1, 3, 9, 29, 59, 47, 81, 293, 191, 401, 849, 4355, 1643, 23533, 8469, 389, 97891}},
+{15777, 18, 39796, {1, 3, 5, 5, 9, 55, 37, 175, 203, 179, 901, 3473, 1489, 1009, 24623, 54895, 8711, 190271}},
+{15778, 18, 39809, {1, 1, 7, 1, 13, 39, 49, 105, 385, 189, 1079, 2799, 5901, 2511, 23199, 58925, 111727, 131193}},
+{15779, 18, 39833, {1, 1, 1, 7, 31, 63, 37, 181, 493, 745, 1131, 223, 8055, 9507, 26667, 22163, 26495, 200945}},
+{15780, 18, 39850, {1, 3, 7, 1, 25, 15, 127, 71, 445, 935, 1439, 1167, 3751, 799, 27253, 46209, 33413, 38553}},
+{15781, 18, 39869, {1, 3, 3, 11, 29, 35, 125, 77, 129, 851, 731, 3259, 4651, 4137, 20921, 19779, 119261, 141507}},
+{15782, 18, 39882, {1, 3, 1, 9, 11, 13, 31, 211, 87, 377, 547, 113, 1071, 7167, 28377, 52943, 50669, 156915}},
+{15783, 18, 39906, {1, 1, 3, 7, 29, 55, 89, 215, 425, 513, 175, 1145, 6995, 1929, 14253, 20563, 118543, 104403}},
+{15784, 18, 39918, {1, 1, 1, 5, 23, 25, 1, 23, 175, 571, 1597, 3801, 1411, 1783, 13045, 37499, 86831, 139101}},
+{15785, 18, 39929, {1, 3, 3, 13, 15, 19, 35, 139, 483, 17, 1555, 3431, 3417, 13695, 15985, 65243, 96659, 76027}},
+{15786, 18, 39947, {1, 3, 7, 9, 23, 7, 17, 89, 33, 353, 1999, 2561, 331, 15661, 25757, 63389, 112913, 131757}},
+{15787, 18, 39985, {1, 3, 1, 11, 27, 59, 37, 75, 121, 429, 1833, 3243, 2029, 2601, 5013, 29433, 123565, 234803}},
+{15788, 18, 39986, {1, 3, 1, 7, 31, 13, 33, 25, 459, 803, 267, 1573, 5579, 4575, 8125, 7491, 72681, 239409}},
+{15789, 18, 40023, {1, 1, 3, 7, 31, 43, 93, 191, 237, 75, 1809, 3257, 4131, 1983, 29153, 23205, 38393, 197859}},
+{15790, 18, 40024, {1, 3, 5, 5, 17, 47, 17, 153, 499, 529, 1515, 1587, 2951, 12431, 12787, 13245, 54117, 82663}},
+{15791, 18, 40039, {1, 1, 1, 13, 7, 23, 23, 7, 441, 991, 641, 2713, 151, 1863, 6065, 47381, 60493, 136325}},
+{15792, 18, 40053, {1, 3, 3, 11, 11, 15, 31, 137, 285, 439, 835, 3033, 6083, 7883, 3405, 35803, 65059, 150143}},
+{15793, 18, 40079, {1, 1, 7, 3, 19, 47, 61, 163, 313, 813, 1315, 2995, 2805, 14397, 6589, 62123, 46229, 206697}},
+{15794, 18, 40084, {1, 3, 5, 5, 27, 51, 25, 99, 241, 571, 1411, 1191, 7095, 8639, 29195, 53733, 53219, 42851}},
+{15795, 18, 40087, {1, 3, 1, 5, 11, 29, 1, 49, 61, 149, 1931, 29, 7163, 3717, 525, 42375, 71451, 8345}},
+{15796, 18, 40094, {1, 3, 3, 3, 13, 19, 97, 249, 265, 509, 1347, 3081, 6535, 7941, 31565, 59897, 91909, 171789}},
+{15797, 18, 40100, {1, 3, 3, 1, 25, 17, 75, 169, 251, 607, 73, 549, 1397, 10661, 1743, 9615, 41327, 243207}},
+{15798, 18, 40112, {1, 3, 1, 11, 7, 7, 15, 181, 385, 883, 651, 2939, 5457, 15309, 9807, 22221, 72893, 146331}},
+{15799, 18, 40129, {1, 3, 3, 5, 7, 7, 53, 75, 139, 459, 1861, 917, 4101, 10379, 18555, 12633, 70023, 254761}},
+{15800, 18, 40132, {1, 3, 3, 1, 17, 51, 5, 109, 471, 3, 1555, 3731, 6711, 9791, 63, 61931, 75269, 138697}},
+{15801, 18, 40142, {1, 1, 7, 15, 11, 1, 53, 141, 423, 567, 1937, 849, 5657, 7437, 32657, 16253, 115219, 106027}},
+{15802, 18, 40154, {1, 3, 5, 1, 17, 29, 65, 213, 443, 541, 697, 3859, 1463, 16081, 23299, 7645, 19475, 77857}},
+{15803, 18, 40177, {1, 1, 7, 3, 21, 43, 99, 101, 329, 755, 1123, 1277, 1381, 7017, 21763, 28243, 109995, 178377}},
+{15804, 18, 40178, {1, 3, 5, 7, 9, 31, 103, 123, 43, 895, 1925, 3383, 3539, 13669, 873, 57361, 45281, 256517}},
+{15805, 18, 40202, {1, 1, 1, 13, 1, 37, 115, 55, 415, 703, 1217, 939, 1145, 4015, 7233, 44799, 79711, 164725}},
+{15806, 18, 40219, {1, 1, 7, 1, 29, 17, 101, 15, 205, 281, 1059, 301, 753, 11953, 10533, 31881, 67741, 12683}},
+{15807, 18, 40303, {1, 1, 7, 13, 9, 23, 31, 237, 181, 813, 1765, 2237, 4897, 9955, 2139, 13113, 123423, 227629}},
+{15808, 18, 40305, {1, 1, 7, 15, 27, 57, 37, 75, 405, 185, 1671, 2245, 7151, 10531, 13161, 15695, 107547, 47689}},
+{15809, 18, 40311, {1, 1, 5, 15, 17, 53, 75, 251, 277, 1001, 179, 589, 1401, 4937, 11601, 47113, 36677, 39263}},
+{15810, 18, 40336, {1, 3, 5, 15, 23, 47, 53, 81, 115, 547, 1363, 2457, 4407, 10861, 25649, 64013, 44747, 97949}},
+{15811, 18, 40342, {1, 1, 3, 1, 25, 29, 121, 43, 205, 591, 211, 1899, 5835, 739, 19627, 60387, 127369, 11255}},
+{15812, 18, 40358, {1, 1, 3, 15, 31, 11, 93, 227, 501, 731, 1355, 3963, 347, 83, 12595, 56431, 80049, 42103}},
+{15813, 18, 40381, {1, 3, 1, 11, 13, 17, 51, 165, 311, 67, 1873, 1493, 3815, 13209, 11637, 5809, 94219, 118077}},
+{15814, 18, 40417, {1, 1, 7, 15, 19, 17, 13, 73, 365, 413, 1215, 2265, 2173, 8725, 4725, 1373, 76733, 95379}},
+{15815, 18, 40438, {1, 3, 1, 7, 7, 61, 13, 145, 205, 113, 1579, 3851, 7515, 10659, 28665, 5277, 65925, 10141}},
+{15816, 18, 40463, {1, 3, 7, 1, 9, 63, 11, 83, 197, 797, 1065, 1521, 1751, 7423, 7473, 4371, 29533, 225167}},
+{15817, 18, 40471, {1, 3, 7, 7, 3, 63, 71, 177, 53, 279, 1837, 2609, 7819, 7285, 11059, 65247, 102869, 24429}},
+{15818, 18, 40472, {1, 3, 3, 13, 9, 21, 123, 125, 367, 85, 85, 1009, 1009, 7779, 3375, 30999, 5035, 215107}},
+{15819, 18, 40488, {1, 3, 3, 9, 31, 53, 5, 43, 483, 483, 1359, 2605, 377, 4243, 13291, 50211, 118603, 259865}},
+{15820, 18, 40491, {1, 1, 1, 5, 19, 37, 109, 139, 373, 79, 1951, 3379, 5679, 6445, 29127, 56229, 97369, 232561}},
+{15821, 18, 40525, {1, 1, 3, 5, 19, 37, 61, 225, 321, 573, 1831, 971, 6507, 10005, 6837, 16433, 70913, 170873}},
+{15822, 18, 40526, {1, 1, 5, 11, 31, 17, 21, 29, 329, 679, 869, 389, 5121, 1819, 3539, 43793, 31617, 204983}},
+{15823, 18, 40550, {1, 1, 7, 7, 21, 11, 83, 97, 297, 275, 1559, 1899, 4957, 11463, 25647, 21095, 70121, 113395}},
+{15824, 18, 40553, {1, 3, 5, 11, 19, 57, 39, 37, 441, 715, 383, 4083, 1937, 12263, 6989, 36159, 118135, 238475}},
+{15825, 18, 40562, {1, 1, 1, 3, 9, 53, 85, 201, 357, 807, 865, 1621, 1993, 7623, 3165, 1005, 93343, 227765}},
+{15826, 18, 40568, {1, 1, 7, 7, 21, 29, 123, 175, 319, 621, 303, 117, 5589, 12511, 26053, 41603, 78439, 71819}},
+{15827, 18, 40580, {1, 1, 7, 15, 31, 47, 75, 225, 295, 67, 1349, 1749, 1363, 8763, 9153, 4059, 72015, 3155}},
+{15828, 18, 40608, {1, 3, 5, 13, 19, 23, 79, 25, 319, 475, 1517, 2757, 4009, 12663, 535, 51617, 55695, 64399}},
+{15829, 18, 40613, {1, 3, 7, 13, 19, 39, 61, 235, 369, 951, 111, 2169, 353, 15371, 8611, 42477, 130981, 97419}},
+{15830, 18, 40652, {1, 1, 3, 13, 27, 31, 115, 201, 3, 291, 793, 237, 3593, 2307, 12745, 54603, 96451, 80853}},
+{15831, 18, 40703, {1, 3, 3, 11, 11, 35, 43, 1, 35, 415, 1307, 2303, 5407, 6883, 29023, 31271, 119721, 90599}},
+{15832, 18, 40712, {1, 1, 5, 9, 21, 23, 3, 1, 333, 463, 1277, 1165, 6521, 4887, 16029, 32537, 43681, 21633}},
+{15833, 18, 40720, {1, 1, 1, 13, 1, 35, 45, 57, 293, 435, 1113, 2477, 6641, 14083, 28489, 26189, 44695, 220481}},
+{15834, 18, 40723, {1, 3, 5, 5, 5, 31, 75, 149, 309, 921, 941, 1063, 7041, 12651, 29533, 46955, 88133, 89989}},
+{15835, 18, 40746, {1, 1, 3, 5, 15, 23, 127, 143, 193, 739, 281, 991, 3731, 16243, 25483, 24979, 102317, 186657}},
+{15836, 18, 40759, {1, 1, 3, 13, 3, 63, 23, 69, 181, 163, 1733, 893, 5513, 1525, 31483, 15033, 108021, 167875}},
+{15837, 18, 40765, {1, 1, 5, 15, 15, 51, 79, 59, 55, 243, 565, 159, 7925, 8393, 20059, 35011, 53779, 166241}},
+{15838, 18, 40771, {1, 1, 3, 5, 11, 57, 85, 175, 495, 999, 1577, 2377, 715, 2473, 16979, 5949, 87691, 195607}},
+{15839, 18, 40778, {1, 1, 1, 13, 17, 21, 53, 73, 187, 63, 335, 3251, 4439, 5701, 13469, 23567, 70125, 68931}},
+{15840, 18, 40788, {1, 1, 1, 13, 23, 11, 55, 75, 37, 845, 745, 2193, 7113, 5657, 29449, 41153, 115547, 87261}},
+{15841, 18, 40804, {1, 3, 3, 9, 21, 39, 47, 145, 301, 883, 625, 2479, 1089, 3393, 23265, 49577, 81027, 186485}},
+{15842, 18, 40835, {1, 1, 3, 7, 3, 11, 37, 117, 79, 905, 493, 265, 1819, 12179, 12361, 27457, 14459, 231837}},
+{15843, 18, 40841, {1, 3, 5, 11, 19, 45, 99, 5, 455, 497, 1851, 2349, 5213, 3671, 5871, 43187, 59011, 211167}},
+{15844, 18, 40907, {1, 3, 7, 5, 23, 61, 63, 97, 413, 575, 1073, 2587, 573, 1805, 32307, 58463, 84927, 15065}},
+{15845, 18, 40934, {1, 3, 1, 13, 23, 9, 39, 1, 53, 383, 1277, 3599, 7719, 16175, 4443, 53143, 24345, 111899}},
+{15846, 18, 40955, {1, 1, 7, 1, 19, 37, 103, 245, 253, 5, 1367, 3127, 4689, 5089, 30697, 45513, 111291, 26599}},
+{15847, 18, 40986, {1, 3, 3, 7, 31, 31, 107, 163, 1, 855, 163, 875, 7481, 5325, 30107, 19377, 3167, 5613}},
+{15848, 18, 41007, {1, 1, 5, 13, 21, 17, 115, 203, 233, 333, 441, 3185, 3197, 3397, 8515, 61879, 11163, 233277}},
+{15849, 18, 41016, {1, 3, 5, 3, 17, 53, 93, 233, 465, 573, 1075, 1905, 1141, 4965, 13469, 24901, 23653, 225233}},
+{15850, 18, 41034, {1, 3, 7, 11, 11, 1, 95, 47, 85, 65, 9, 2413, 7347, 2127, 305, 4673, 79281, 188081}},
+{15851, 18, 41041, {1, 1, 7, 5, 9, 5, 27, 23, 393, 201, 467, 3677, 2641, 4671, 24627, 18927, 45137, 74167}},
+{15852, 18, 41063, {1, 3, 5, 11, 11, 9, 19, 247, 423, 693, 1885, 1129, 7459, 8411, 2573, 54111, 98919, 160075}},
+{15853, 18, 41084, {1, 3, 3, 3, 1, 3, 67, 131, 317, 915, 151, 3609, 4083, 6395, 12877, 44017, 28877, 244165}},
+{15854, 18, 41093, {1, 3, 1, 3, 1, 33, 29, 23, 19, 323, 873, 115, 2439, 4699, 5449, 51637, 68889, 105197}},
+{15855, 18, 41097, {1, 1, 7, 1, 19, 55, 37, 241, 53, 695, 729, 1565, 19, 12875, 26993, 18511, 35615, 169281}},
+{15856, 18, 41111, {1, 3, 3, 1, 1, 7, 121, 49, 345, 883, 1001, 657, 2647, 15387, 30633, 18107, 13745, 217735}},
+{15857, 18, 41118, {1, 3, 5, 15, 11, 45, 73, 77, 307, 373, 1723, 335, 473, 5735, 11747, 39257, 87199, 47663}},
+{15858, 18, 41121, {1, 1, 7, 7, 27, 21, 121, 169, 427, 605, 1593, 3147, 1001, 3773, 31505, 22823, 21543, 82931}},
+{15859, 18, 41141, {1, 1, 1, 9, 11, 59, 91, 165, 249, 859, 483, 3133, 5729, 12675, 7761, 6475, 116823, 224187}},
+{15860, 18, 41160, {1, 1, 3, 3, 27, 31, 51, 1, 429, 517, 1439, 3959, 2343, 6709, 5287, 24039, 52409, 20749}},
+{15861, 18, 41207, {1, 3, 7, 7, 11, 31, 83, 111, 391, 729, 721, 1675, 5679, 14637, 22065, 49903, 113759, 40881}},
+{15862, 18, 41214, {1, 3, 7, 1, 25, 15, 91, 59, 87, 313, 155, 1439, 2419, 2099, 22709, 10289, 40655, 17351}},
+{15863, 18, 41255, {1, 3, 5, 1, 15, 5, 11, 21, 261, 227, 1563, 1177, 4731, 3487, 1607, 46599, 105599, 193425}},
+{15864, 18, 41284, {1, 1, 5, 5, 5, 45, 77, 181, 431, 27, 1985, 881, 2555, 7589, 16199, 31041, 66683, 52499}},
+{15865, 18, 41287, {1, 1, 1, 15, 5, 29, 111, 209, 335, 747, 93, 3551, 5951, 14995, 18451, 33329, 9117, 167455}},
+{15866, 18, 41308, {1, 3, 1, 7, 25, 9, 113, 123, 387, 87, 267, 2251, 3509, 10829, 32733, 48025, 58267, 143553}},
+{15867, 18, 41330, {1, 3, 5, 15, 17, 17, 65, 107, 175, 427, 733, 797, 3837, 12773, 27865, 29481, 4557, 196163}},
+{15868, 18, 41336, {1, 3, 1, 3, 1, 53, 93, 175, 509, 351, 1093, 1039, 6931, 2691, 14957, 44395, 84383, 58915}},
+{15869, 18, 41437, {1, 1, 1, 11, 1, 43, 61, 123, 377, 813, 1335, 1597, 147, 13663, 30781, 47635, 24111, 64307}},
+{15870, 18, 41444, {1, 1, 3, 11, 25, 27, 15, 215, 125, 679, 1491, 3203, 5403, 4531, 11839, 44227, 49239, 110439}},
+{15871, 18, 41456, {1, 1, 3, 13, 9, 35, 71, 127, 127, 629, 1363, 585, 6713, 10637, 6803, 20963, 47157, 157781}},
+{15872, 18, 41481, {1, 1, 3, 11, 13, 21, 117, 241, 365, 175, 1397, 1279, 4117, 5427, 24007, 50711, 465, 225003}},
+{15873, 18, 41489, {1, 1, 1, 9, 13, 63, 49, 189, 113, 61, 353, 2221, 7541, 4075, 5283, 5505, 51035, 35191}},
+{15874, 18, 41499, {1, 1, 7, 9, 11, 37, 123, 63, 331, 691, 1299, 1661, 3769, 7827, 32127, 32149, 7271, 150363}},
+{15875, 18, 41555, {1, 1, 1, 5, 25, 5, 127, 195, 413, 657, 479, 879, 6743, 8959, 791, 22425, 77119, 180721}},
+{15876, 18, 41561, {1, 1, 7, 3, 13, 57, 123, 125, 135, 69, 455, 3363, 1783, 1557, 20401, 26707, 130345, 195881}},
+{15877, 18, 41562, {1, 3, 3, 7, 27, 19, 125, 71, 201, 1017, 1285, 3955, 5255, 14375, 18163, 28537, 76157, 247193}},
+{15878, 18, 41571, {1, 1, 3, 1, 27, 33, 123, 137, 189, 655, 1891, 2419, 5195, 97, 32565, 38581, 62715, 164697}},
+{15879, 18, 41592, {1, 1, 1, 15, 9, 47, 23, 147, 197, 503, 1803, 2953, 2961, 13787, 10545, 35465, 53997, 198655}},
+{15880, 18, 41631, {1, 3, 1, 9, 9, 43, 65, 237, 119, 621, 1517, 3479, 4165, 12797, 14731, 53131, 105501, 112845}},
+{15881, 18, 41661, {1, 3, 3, 15, 3, 23, 47, 163, 469, 363, 1813, 3107, 6167, 8987, 26829, 33099, 6821, 203017}},
+{15882, 18, 41682, {1, 1, 1, 9, 1, 11, 85, 11, 251, 907, 395, 3935, 3403, 229, 16825, 48337, 103647, 91425}},
+{15883, 18, 41710, {1, 3, 1, 5, 17, 57, 21, 181, 31, 27, 235, 4041, 4927, 8319, 29765, 61603, 19081, 75879}},
+{15884, 18, 41724, {1, 1, 5, 15, 11, 3, 7, 225, 247, 221, 251, 1979, 1151, 10829, 26491, 39705, 41587, 99063}},
+{15885, 18, 41727, {1, 3, 5, 5, 19, 23, 57, 127, 467, 409, 43, 829, 3883, 10767, 24351, 31365, 115943, 209231}},
+{15886, 18, 41730, {1, 1, 7, 15, 3, 51, 17, 251, 219, 33, 1511, 2027, 4995, 12277, 7639, 59895, 85267, 87735}},
+{15887, 18, 41744, {1, 3, 7, 3, 7, 29, 93, 57, 427, 235, 1591, 3475, 1159, 2387, 851, 43307, 87081, 151543}},
+{15888, 18, 41769, {1, 3, 7, 7, 1, 9, 21, 167, 73, 439, 2035, 2091, 4563, 4819, 5591, 57123, 78739, 63235}},
+{15889, 18, 41795, {1, 1, 3, 13, 19, 35, 63, 17, 425, 277, 1669, 931, 597, 5621, 22367, 1155, 109099, 169965}},
+{15890, 18, 41798, {1, 3, 7, 5, 11, 11, 41, 71, 35, 183, 555, 2631, 5199, 16381, 16319, 1851, 121551, 141711}},
+{15891, 18, 41804, {1, 3, 5, 5, 21, 17, 3, 95, 47, 1011, 1757, 3295, 1111, 16043, 6377, 16257, 37941, 206637}},
+{15892, 18, 41826, {1, 3, 1, 5, 25, 19, 19, 69, 395, 589, 1311, 1075, 5763, 12475, 3633, 40647, 54487, 97459}},
+{15893, 18, 41852, {1, 3, 5, 7, 13, 23, 83, 91, 419, 415, 685, 1685, 2893, 12953, 30641, 43565, 11851, 187837}},
+{15894, 18, 41868, {1, 1, 5, 11, 27, 1, 61, 155, 279, 737, 215, 2909, 969, 57, 17979, 34537, 41861, 243717}},
+{15895, 18, 41910, {1, 1, 5, 1, 17, 61, 57, 199, 127, 569, 1109, 3057, 7301, 16097, 17579, 25753, 82653, 237273}},
+{15896, 18, 41914, {1, 1, 7, 15, 17, 45, 19, 53, 153, 785, 51, 291, 5261, 1317, 21163, 44393, 108131, 254373}},
+{15897, 18, 41942, {1, 1, 3, 11, 5, 19, 61, 125, 127, 961, 2019, 1725, 855, 677, 20853, 38845, 3239, 95697}},
+{15898, 18, 41969, {1, 1, 3, 15, 3, 3, 117, 17, 61, 201, 241, 1759, 4465, 3985, 6985, 47703, 58657, 52633}},
+{15899, 18, 41975, {1, 3, 3, 11, 31, 39, 107, 171, 19, 825, 1309, 807, 7787, 10761, 20215, 9287, 21553, 179599}},
+{15900, 18, 41976, {1, 3, 7, 9, 5, 7, 121, 15, 3, 199, 97, 3177, 5461, 15713, 27609, 54349, 24963, 186279}},
+{15901, 18, 41994, {1, 3, 1, 15, 11, 9, 123, 187, 363, 5, 837, 451, 1601, 6597, 10857, 46893, 83729, 20409}},
+{15902, 18, 42002, {1, 3, 1, 9, 1, 53, 71, 191, 217, 165, 1709, 1827, 1977, 10073, 11373, 35311, 26637, 134519}},
+{15903, 18, 42037, {1, 3, 5, 11, 31, 55, 101, 189, 277, 347, 629, 223, 785, 5739, 25505, 55601, 55017, 212837}},
+{15904, 18, 42056, {1, 1, 5, 11, 3, 13, 45, 235, 65, 459, 621, 587, 7105, 6181, 13193, 5683, 42935, 198585}},
+{15905, 18, 42079, {1, 1, 3, 1, 3, 17, 27, 109, 261, 979, 903, 1499, 4799, 11759, 10591, 65429, 74587, 16629}},
+{15906, 18, 42085, {1, 1, 5, 1, 13, 63, 29, 11, 441, 151, 611, 4073, 3933, 6793, 28845, 39223, 120823, 49397}},
+{15907, 18, 42089, {1, 3, 3, 5, 21, 13, 23, 53, 357, 197, 1327, 1773, 2961, 11509, 16585, 10201, 28451, 45109}},
+{15908, 18, 42123, {1, 3, 5, 7, 19, 17, 97, 63, 295, 111, 85, 2981, 6719, 9193, 15197, 12117, 2553, 59909}},
+{15909, 18, 42128, {1, 1, 5, 5, 15, 3, 9, 85, 333, 379, 1409, 1445, 4173, 3953, 833, 48089, 120249, 122703}},
+{15910, 18, 42140, {1, 3, 7, 7, 29, 13, 57, 19, 141, 979, 1991, 4011, 8125, 3915, 15753, 1371, 113771, 117273}},
+{15911, 18, 42149, {1, 3, 3, 13, 21, 53, 115, 187, 279, 29, 1355, 1843, 253, 3531, 8193, 54731, 6213, 123467}},
+{15912, 18, 42156, {1, 3, 3, 1, 25, 29, 109, 19, 37, 385, 901, 3737, 6247, 9941, 13185, 2895, 88819, 53029}},
+{15913, 18, 42186, {1, 1, 1, 1, 3, 31, 89, 157, 483, 657, 1833, 2975, 3187, 631, 28685, 7277, 4915, 115955}},
+{15914, 18, 42191, {1, 3, 3, 1, 25, 41, 13, 99, 385, 303, 297, 419, 7919, 12411, 757, 9227, 47867, 120175}},
+{15915, 18, 42205, {1, 3, 5, 11, 23, 15, 21, 157, 177, 301, 789, 2791, 5769, 7809, 2369, 26123, 116465, 22595}},
+{15916, 18, 42221, {1, 1, 5, 9, 17, 63, 45, 239, 465, 811, 1157, 1443, 8137, 12587, 26209, 62057, 59299, 167171}},
+{15917, 18, 42222, {1, 3, 3, 7, 3, 45, 41, 17, 341, 461, 571, 541, 989, 4069, 17531, 46729, 107915, 47871}},
+{15918, 18, 42230, {1, 1, 7, 1, 1, 23, 45, 213, 125, 799, 5, 3443, 2535, 12983, 2133, 63411, 93027, 89831}},
+{15919, 18, 42233, {1, 1, 1, 15, 7, 31, 49, 181, 213, 923, 281, 2059, 861, 6951, 25659, 32209, 66423, 225885}},
+{15920, 18, 42241, {1, 3, 3, 7, 9, 39, 107, 197, 383, 179, 27, 1395, 6397, 16139, 32049, 33567, 43977, 203939}},
+{15921, 18, 42247, {1, 1, 3, 5, 13, 37, 13, 31, 339, 527, 641, 181, 1413, 8145, 341, 57605, 108031, 109311}},
+{15922, 18, 42248, {1, 1, 1, 1, 21, 35, 87, 15, 279, 967, 1003, 813, 5075, 10595, 5609, 33901, 86443, 150007}},
+{15923, 18, 42254, {1, 3, 1, 5, 27, 9, 75, 199, 377, 889, 545, 1987, 6277, 361, 12563, 35699, 27105, 187995}},
+{15924, 18, 42259, {1, 3, 7, 1, 11, 3, 41, 215, 273, 61, 821, 1207, 2809, 8731, 26409, 50323, 22355, 16521}},
+{15925, 18, 42268, {1, 1, 7, 5, 29, 13, 99, 133, 15, 673, 215, 445, 4051, 2187, 9395, 62491, 58685, 224707}},
+{15926, 18, 42295, {1, 3, 3, 13, 21, 59, 17, 1, 271, 613, 939, 1881, 2379, 16325, 3275, 63707, 59961, 106937}},
+{15927, 18, 42304, {1, 3, 3, 1, 23, 53, 51, 181, 391, 375, 767, 239, 373, 4593, 25211, 37173, 70409, 252345}},
+{15928, 18, 42322, {1, 3, 3, 11, 15, 17, 37, 145, 41, 107, 151, 1351, 3457, 14727, 755, 36321, 99397, 73359}},
+{15929, 18, 42334, {1, 3, 5, 7, 25, 31, 39, 185, 341, 721, 1799, 1803, 5985, 10587, 11605, 9937, 23905, 56485}},
+{15930, 18, 42355, {1, 3, 1, 3, 19, 35, 25, 71, 109, 209, 1675, 4043, 2053, 6285, 25317, 50171, 68293, 124385}},
+{15931, 18, 42361, {1, 1, 1, 1, 21, 11, 63, 137, 361, 157, 1985, 2161, 7239, 1795, 10459, 38511, 36817, 253347}},
+{15932, 18, 42373, {1, 1, 1, 5, 31, 3, 13, 83, 185, 175, 567, 295, 459, 11453, 3765, 9841, 30333, 201377}},
+{15933, 18, 42374, {1, 1, 3, 13, 5, 57, 99, 125, 371, 903, 2001, 285, 2005, 8475, 31617, 58265, 641, 115507}},
+{15934, 18, 42398, {1, 3, 5, 9, 11, 17, 123, 67, 77, 803, 815, 3173, 4795, 11917, 1187, 32389, 102289, 248359}},
+{15935, 18, 42411, {1, 1, 5, 5, 27, 19, 59, 145, 361, 821, 33, 1465, 7643, 11101, 145, 21705, 55105, 181245}},
+{15936, 18, 42443, {1, 3, 7, 5, 15, 55, 127, 133, 157, 989, 1211, 3573, 4021, 2967, 2941, 38657, 97681, 114505}},
+{15937, 18, 42446, {1, 1, 7, 7, 23, 17, 39, 209, 117, 195, 931, 5, 7509, 9187, 6011, 10297, 13727, 258007}},
+{15938, 18, 42463, {1, 3, 1, 13, 3, 17, 105, 69, 9, 163, 1615, 241, 5207, 13173, 28521, 51417, 130645, 106787}},
+{15939, 18, 42479, {1, 1, 7, 13, 15, 3, 5, 187, 5, 239, 1799, 3083, 7801, 12781, 24817, 59341, 73867, 175273}},
+{15940, 18, 42482, {1, 1, 3, 11, 11, 1, 89, 17, 497, 217, 1565, 2933, 6449, 7687, 6561, 57903, 92751, 261371}},
+{15941, 18, 42484, {1, 1, 1, 1, 15, 39, 47, 249, 39, 765, 249, 2785, 4401, 16033, 11463, 127, 120109, 83133}},
+{15942, 18, 42498, {1, 1, 3, 3, 19, 59, 47, 153, 505, 1009, 413, 1177, 5999, 6841, 12013, 40295, 115641, 189241}},
+{15943, 18, 42534, {1, 3, 3, 11, 17, 51, 45, 101, 459, 971, 1133, 3467, 4945, 12445, 1267, 41783, 66825, 130167}},
+{15944, 18, 42537, {1, 3, 1, 7, 17, 45, 77, 211, 387, 23, 1903, 2309, 2681, 6897, 6959, 30981, 113537, 207415}},
+{15945, 18, 42557, {1, 1, 3, 1, 19, 9, 103, 89, 461, 881, 71, 2019, 6475, 13563, 18835, 2375, 34807, 1373}},
+{15946, 18, 42570, {1, 1, 7, 11, 3, 31, 125, 121, 43, 737, 1995, 3043, 811, 8883, 8169, 22131, 29295, 194963}},
+{15947, 18, 42599, {1, 3, 7, 11, 7, 45, 125, 149, 427, 187, 1361, 2405, 2815, 8877, 15255, 36867, 95517, 261969}},
+{15948, 18, 42600, {1, 1, 7, 11, 9, 29, 89, 175, 467, 997, 937, 3869, 7843, 12629, 8701, 60717, 30443, 193427}},
+{15949, 18, 42633, {1, 1, 5, 7, 3, 3, 57, 199, 315, 477, 189, 2029, 2059, 3473, 27411, 30419, 26465, 187807}},
+{15950, 18, 42639, {1, 3, 1, 15, 3, 3, 11, 55, 233, 603, 1749, 1737, 5709, 4559, 13427, 39137, 44885, 61611}},
+{15951, 18, 42672, {1, 1, 7, 1, 25, 15, 61, 199, 107, 737, 909, 3229, 1799, 5129, 27655, 45937, 919, 36161}},
+{15952, 18, 42681, {1, 1, 3, 5, 31, 27, 99, 247, 425, 689, 1335, 1661, 625, 15817, 22601, 33293, 113927, 261931}},
+{15953, 18, 42687, {1, 1, 1, 9, 5, 57, 117, 121, 465, 859, 335, 879, 665, 12787, 21313, 46387, 16437, 53769}},
+{15954, 18, 42704, {1, 1, 3, 1, 11, 11, 75, 145, 307, 621, 833, 235, 3907, 11331, 6633, 51905, 72581, 129613}},
+{15955, 18, 42713, {1, 1, 3, 13, 17, 13, 81, 125, 377, 499, 1597, 3437, 4323, 789, 23825, 46609, 105997, 159709}},
+{15956, 18, 42714, {1, 3, 3, 9, 5, 29, 113, 51, 23, 957, 1981, 3205, 2549, 9771, 2555, 44289, 103893, 170241}},
+{15957, 18, 42716, {1, 1, 5, 15, 13, 17, 101, 67, 71, 7, 185, 3775, 5399, 5213, 13095, 26045, 59467, 95547}},
+{15958, 18, 42726, {1, 1, 5, 5, 31, 11, 77, 169, 3, 1007, 1853, 2245, 509, 13489, 2807, 55227, 67541, 242835}},
+{15959, 18, 42730, {1, 3, 7, 15, 11, 63, 39, 97, 1, 219, 1827, 2343, 6009, 4909, 4327, 21853, 46079, 87719}},
+{15960, 18, 42737, {1, 3, 1, 9, 17, 51, 119, 93, 179, 607, 1051, 2381, 619, 11215, 10839, 44771, 20555, 12721}},
+{15961, 18, 42752, {1, 3, 3, 5, 21, 47, 35, 133, 61, 937, 1561, 1655, 6527, 5085, 4141, 60811, 59971, 6309}},
+{15962, 18, 42757, {1, 3, 1, 7, 5, 63, 7, 235, 489, 675, 945, 943, 7107, 6005, 32695, 27655, 113219, 132963}},
+{15963, 18, 42772, {1, 1, 1, 7, 7, 5, 81, 237, 365, 1, 811, 3075, 1771, 5223, 7337, 24601, 68383, 156975}},
+{15964, 18, 42809, {1, 3, 1, 15, 5, 35, 39, 91, 301, 387, 805, 3537, 737, 7453, 4655, 16349, 108261, 123697}},
+{15965, 18, 42853, {1, 3, 5, 3, 9, 59, 95, 187, 155, 183, 589, 2107, 967, 1095, 4875, 46131, 100699, 212797}},
+{15966, 18, 42857, {1, 3, 1, 7, 27, 29, 77, 133, 397, 445, 933, 1483, 5027, 12569, 22163, 58989, 16657, 195347}},
+{15967, 18, 42902, {1, 3, 5, 15, 21, 51, 97, 135, 165, 311, 525, 171, 4785, 7947, 14649, 40837, 58875, 222303}},
+{15968, 18, 42912, {1, 3, 3, 5, 23, 47, 41, 23, 321, 709, 1555, 1139, 3775, 11617, 13001, 18235, 51803, 197863}},
+{15969, 18, 42930, {1, 3, 5, 3, 3, 41, 91, 157, 29, 1005, 945, 3471, 2563, 8493, 24961, 44759, 103079, 50841}},
+{15970, 18, 42936, {1, 1, 5, 11, 23, 19, 91, 115, 165, 291, 1653, 1061, 1067, 6171, 18441, 26067, 3569, 117329}},
+{15971, 18, 42956, {1, 3, 7, 15, 17, 19, 89, 23, 103, 389, 623, 1071, 203, 9545, 21259, 36155, 55395, 141741}},
+{15972, 18, 42959, {1, 3, 5, 11, 27, 43, 31, 193, 55, 489, 353, 1615, 7461, 13977, 31901, 64051, 82667, 258825}},
+{15973, 18, 42978, {1, 1, 3, 7, 5, 39, 7, 245, 241, 843, 1545, 3499, 8117, 15057, 14153, 2665, 107401, 66059}},
+{15974, 18, 43001, {1, 3, 5, 11, 9, 11, 41, 171, 255, 153, 1973, 759, 51, 15601, 327, 25889, 110861, 20555}},
+{15975, 18, 43011, {1, 3, 5, 7, 5, 15, 41, 77, 87, 143, 1141, 3975, 2675, 7131, 5549, 52397, 42073, 27585}},
+{15976, 18, 43047, {1, 1, 3, 7, 29, 5, 79, 243, 359, 817, 1053, 3509, 3347, 6207, 5147, 31063, 116851, 132627}},
+{15977, 18, 43059, {1, 3, 7, 3, 27, 51, 39, 7, 95, 239, 263, 3497, 867, 1869, 16773, 46947, 59193, 37523}},
+{15978, 18, 43094, {1, 3, 1, 1, 25, 31, 113, 127, 187, 77, 675, 3307, 999, 12255, 26441, 30933, 122761, 116783}},
+{15979, 18, 43124, {1, 1, 5, 7, 7, 11, 87, 59, 437, 485, 685, 3159, 7259, 16271, 24899, 17919, 130271, 52953}},
+{15980, 18, 43218, {1, 1, 3, 11, 7, 13, 61, 157, 149, 1001, 285, 3631, 1923, 16013, 19507, 64447, 8073, 261171}},
+{15981, 18, 43220, {1, 3, 7, 9, 7, 13, 45, 7, 225, 671, 287, 1059, 5223, 2077, 7551, 58385, 92955, 162725}},
+{15982, 18, 43240, {1, 1, 5, 11, 11, 21, 17, 145, 97, 633, 475, 2639, 2069, 9663, 23633, 50949, 109941, 119865}},
+{15983, 18, 43258, {1, 1, 5, 13, 9, 49, 127, 171, 199, 413, 1315, 645, 305, 12123, 9559, 38319, 99945, 103313}},
+{15984, 18, 43263, {1, 3, 5, 3, 19, 21, 119, 17, 301, 611, 1785, 2081, 2245, 8761, 4755, 9507, 23133, 144575}},
+{15985, 18, 43265, {1, 3, 7, 11, 17, 25, 101, 59, 397, 249, 687, 715, 1151, 15941, 20525, 5171, 24073, 46257}},
+{15986, 18, 43290, {1, 1, 3, 15, 11, 45, 9, 201, 421, 867, 389, 3615, 5965, 10561, 18309, 17143, 52771, 230743}},
+{15987, 18, 43346, {1, 1, 3, 5, 9, 1, 109, 233, 431, 849, 421, 475, 1331, 9903, 20649, 34759, 118611, 38541}},
+{15988, 18, 43364, {1, 3, 5, 15, 9, 55, 113, 217, 83, 409, 1449, 2325, 4825, 11311, 14565, 65075, 124399, 3591}},
+{15989, 18, 43373, {1, 3, 3, 9, 27, 13, 101, 181, 255, 313, 693, 951, 1153, 13941, 14097, 8325, 4589, 102883}},
+{15990, 18, 43401, {1, 3, 7, 3, 3, 1, 43, 65, 321, 623, 1389, 57, 3461, 9965, 6743, 34843, 91673, 249573}},
+{15991, 18, 43416, {1, 3, 5, 5, 11, 29, 101, 79, 275, 685, 569, 59, 6921, 16065, 30625, 53339, 32283, 93401}},
+{15992, 18, 43443, {1, 3, 1, 11, 29, 33, 103, 145, 431, 289, 1845, 1915, 23, 699, 5475, 18413, 127185, 162637}},
+{15993, 18, 43458, {1, 3, 1, 11, 27, 23, 71, 63, 45, 579, 1187, 1189, 1781, 5595, 9043, 10155, 33321, 36487}},
+{15994, 18, 43497, {1, 3, 3, 15, 17, 19, 85, 233, 293, 833, 1711, 857, 7573, 393, 23141, 58713, 21399, 228381}},
+{15995, 18, 43506, {1, 3, 3, 15, 3, 35, 33, 35, 403, 123, 575, 3509, 6303, 13203, 17997, 15649, 64331, 124101}},
+{15996, 18, 43545, {1, 1, 3, 9, 23, 25, 39, 53, 119, 879, 573, 3225, 5069, 15489, 21887, 11773, 37783, 169523}},
+{15997, 18, 43558, {1, 3, 5, 5, 5, 25, 29, 189, 145, 863, 661, 3939, 1059, 11993, 1487, 3157, 118287, 69835}},
+{15998, 18, 43576, {1, 3, 7, 3, 15, 9, 85, 107, 17, 965, 1097, 2087, 1947, 14649, 4099, 50941, 64511, 209153}},
+{15999, 18, 43579, {1, 3, 5, 15, 19, 21, 127, 71, 429, 97, 1989, 835, 743, 11973, 14635, 45371, 114657, 208085}},
+{16000, 18, 43624, {1, 3, 5, 7, 23, 61, 99, 133, 235, 237, 435, 2681, 331, 7859, 20859, 3573, 102901, 775}},
+{16001, 18, 43630, {1, 3, 3, 9, 7, 57, 29, 15, 53, 569, 871, 1703, 2573, 10791, 719, 3487, 105709, 89573}},
+{16002, 18, 43637, {1, 1, 1, 9, 7, 21, 21, 207, 459, 621, 737, 635, 5101, 4343, 4961, 32067, 64017, 73675}},
+{16003, 18, 43654, {1, 1, 3, 9, 25, 27, 77, 69, 251, 327, 921, 3759, 1715, 14537, 21399, 10937, 9085, 241329}},
+{16004, 18, 43660, {1, 1, 5, 1, 23, 13, 63, 117, 81, 427, 1063, 1987, 2433, 14837, 13473, 28623, 44799, 202223}},
+{16005, 18, 43696, {1, 3, 1, 11, 17, 55, 89, 89, 455, 255, 1009, 1891, 2197, 9045, 23543, 48783, 22871, 58613}},
+{16006, 18, 43706, {1, 3, 7, 15, 25, 5, 11, 71, 399, 23, 239, 93, 6681, 11311, 23403, 58131, 59549, 38917}},
+{16007, 18, 43725, {1, 1, 1, 1, 19, 63, 73, 31, 69, 145, 921, 2475, 3505, 4797, 23805, 28621, 101153, 98895}},
+{16008, 18, 43733, {1, 3, 3, 3, 9, 1, 113, 111, 275, 851, 519, 1607, 635, 13287, 6191, 24545, 112039, 114383}},
+{16009, 18, 43753, {1, 3, 7, 9, 13, 13, 107, 97, 37, 133, 21, 1059, 4201, 6777, 2843, 43503, 23761, 13247}},
+{16010, 18, 43756, {1, 1, 7, 9, 25, 23, 101, 135, 471, 901, 539, 4083, 1765, 15553, 5879, 10787, 67543, 104543}},
+{16011, 18, 43761, {1, 3, 3, 13, 25, 63, 1, 49, 287, 357, 1701, 3689, 3895, 16313, 22619, 20203, 8195, 93127}},
+{16012, 18, 43768, {1, 1, 1, 11, 15, 37, 75, 43, 311, 443, 1639, 549, 4707, 3099, 677, 59115, 11709, 71013}},
+{16013, 18, 43812, {1, 1, 5, 11, 17, 43, 23, 21, 421, 613, 199, 1029, 5255, 271, 12911, 63431, 108889, 253379}},
+{16014, 18, 43822, {1, 3, 7, 11, 27, 45, 9, 89, 65, 25, 1183, 3497, 8123, 2389, 215, 16819, 63777, 163423}},
+{16015, 18, 43841, {1, 1, 5, 5, 29, 43, 65, 201, 391, 861, 1133, 3985, 983, 13039, 15545, 13695, 91467, 963}},
+{16016, 18, 43861, {1, 3, 7, 3, 9, 55, 73, 205, 287, 765, 941, 353, 7379, 2511, 555, 64399, 77605, 121959}},
+{16017, 18, 43868, {1, 3, 1, 11, 25, 15, 109, 35, 351, 675, 1219, 3791, 233, 15133, 30733, 24477, 86077, 85857}},
+{16018, 18, 43877, {1, 1, 1, 7, 13, 33, 63, 45, 503, 525, 781, 517, 2187, 1587, 17297, 26147, 35421, 61269}},
+{16019, 18, 43878, {1, 3, 1, 9, 9, 35, 69, 79, 447, 675, 803, 2793, 5793, 4433, 29227, 5437, 103347, 37713}},
+{16020, 18, 43908, {1, 3, 1, 9, 27, 31, 65, 167, 327, 231, 1959, 657, 3141, 8659, 11055, 23923, 73597, 187139}},
+{16021, 18, 43917, {1, 1, 5, 9, 29, 5, 37, 3, 281, 693, 133, 2139, 5867, 12073, 23669, 11427, 80627, 249003}},
+{16022, 18, 43936, {1, 1, 1, 13, 9, 35, 89, 203, 381, 281, 535, 1061, 7417, 13373, 12149, 37943, 113133, 110797}},
+{16023, 18, 43954, {1, 1, 7, 5, 7, 17, 71, 65, 385, 851, 1357, 3435, 4441, 6999, 27065, 32753, 129531, 52447}},
+{16024, 18, 43963, {1, 3, 7, 1, 3, 21, 25, 113, 361, 219, 1345, 2193, 5711, 3331, 14343, 23075, 39955, 71223}},
+{16025, 18, 43977, {1, 1, 7, 9, 15, 9, 101, 183, 59, 861, 931, 3385, 6517, 12067, 7753, 37997, 128361, 4591}},
+{16026, 18, 44008, {1, 3, 5, 3, 23, 5, 37, 217, 203, 749, 993, 2537, 2425, 13949, 17235, 15461, 21275, 141815}},
+{16027, 18, 44013, {1, 3, 5, 1, 19, 59, 63, 241, 211, 285, 2033, 1111, 2859, 14801, 9491, 14557, 12973, 223089}},
+{16028, 18, 44026, {1, 1, 1, 11, 15, 41, 57, 59, 233, 897, 1193, 381, 2237, 5309, 19237, 57607, 97941, 116573}},
+{16029, 18, 44028, {1, 1, 3, 9, 15, 17, 75, 15, 385, 129, 495, 887, 4933, 15113, 7449, 56213, 15841, 248029}},
+{16030, 18, 44045, {1, 3, 1, 1, 29, 37, 19, 221, 47, 185, 1105, 3297, 5235, 6917, 12041, 10815, 54747, 132329}},
+{16031, 18, 44046, {1, 3, 1, 5, 3, 17, 33, 35, 395, 491, 1157, 2563, 6257, 1025, 18295, 5293, 77851, 140157}},
+{16032, 18, 44053, {1, 3, 1, 13, 7, 31, 95, 21, 347, 409, 1485, 925, 327, 11497, 7305, 6503, 111175, 70989}},
+{16033, 18, 44091, {1, 3, 3, 1, 11, 41, 127, 93, 367, 649, 1585, 3379, 7269, 5537, 26077, 28541, 55379, 22989}},
+{16034, 18, 44101, {1, 1, 1, 5, 27, 11, 35, 49, 7, 113, 1477, 3615, 7567, 505, 13915, 51023, 50783, 45031}},
+{16035, 18, 44129, {1, 1, 7, 5, 25, 1, 35, 59, 269, 427, 791, 3179, 1423, 9801, 17717, 23631, 97947, 126861}},
+{16036, 18, 44139, {1, 3, 5, 7, 1, 51, 77, 97, 19, 287, 303, 791, 307, 4939, 13615, 61225, 98127, 114693}},
+{16037, 18, 44172, {1, 3, 3, 15, 5, 5, 93, 119, 429, 977, 1763, 3727, 1761, 3597, 16489, 71, 44103, 257929}},
+{16038, 18, 44203, {1, 1, 5, 1, 15, 29, 79, 33, 335, 381, 1233, 47, 6741, 4953, 29689, 11223, 129185, 182487}},
+{16039, 18, 44211, {1, 1, 1, 11, 29, 27, 27, 189, 507, 523, 1949, 2567, 4105, 1227, 16631, 34187, 28521, 265}},
+{16040, 18, 44240, {1, 3, 3, 7, 3, 7, 39, 155, 315, 439, 1953, 1227, 6135, 16291, 453, 50929, 67507, 166981}},
+{16041, 18, 44259, {1, 3, 1, 5, 7, 55, 121, 119, 87, 869, 1049, 575, 3675, 13505, 15661, 43899, 106877, 141691}},
+{16042, 18, 44305, {1, 3, 1, 11, 23, 9, 117, 243, 329, 767, 335, 2951, 2887, 13441, 27579, 15437, 31699, 165177}},
+{16043, 18, 44383, {1, 3, 7, 11, 5, 49, 47, 125, 431, 511, 299, 3215, 3287, 7029, 9737, 28317, 34355, 232365}},
+{16044, 18, 44384, {1, 3, 7, 3, 17, 9, 29, 255, 509, 393, 1583, 1979, 6735, 941, 4393, 35741, 82019, 109633}},
+{16045, 18, 44389, {1, 1, 5, 1, 13, 31, 95, 133, 117, 257, 993, 1513, 4669, 12239, 7841, 751, 79567, 23289}},
+{16046, 18, 44390, {1, 1, 7, 9, 25, 33, 127, 181, 61, 333, 1087, 1661, 2715, 2569, 30041, 4937, 36053, 3435}},
+{16047, 18, 44432, {1, 3, 1, 13, 15, 27, 123, 73, 377, 85, 435, 3435, 2079, 9271, 28685, 30089, 38799, 210247}},
+{16048, 18, 44435, {1, 1, 5, 3, 5, 17, 93, 181, 313, 837, 1115, 3099, 3603, 3483, 23185, 9933, 53127, 123245}},
+{16049, 18, 44468, {1, 1, 1, 13, 3, 57, 11, 67, 41, 273, 1005, 2313, 505, 6593, 27287, 47359, 104597, 45475}},
+{16050, 18, 44472, {1, 1, 1, 5, 13, 41, 97, 251, 317, 483, 163, 1493, 6629, 11995, 31293, 4715, 98569, 178419}},
+{16051, 18, 44483, {1, 3, 5, 5, 21, 7, 69, 169, 223, 953, 1573, 1137, 8075, 7733, 23031, 14589, 6453, 228883}},
+{16052, 18, 44497, {1, 1, 7, 9, 27, 37, 3, 183, 41, 99, 111, 1713, 1291, 8263, 6373, 39549, 3099, 156793}},
+{16053, 18, 44550, {1, 1, 3, 1, 23, 43, 15, 27, 223, 173, 1601, 2159, 3595, 15143, 31065, 35799, 77339, 141397}},
+{16054, 18, 44577, {1, 1, 5, 13, 9, 35, 27, 93, 23, 999, 593, 563, 5333, 8825, 27277, 46381, 3171, 6311}},
+{16055, 18, 44584, {1, 3, 7, 15, 25, 17, 7, 237, 379, 649, 1879, 2643, 5951, 4227, 4937, 24549, 43577, 116327}},
+{16056, 18, 44601, {1, 1, 3, 9, 29, 35, 101, 105, 19, 151, 1135, 897, 2427, 15779, 31851, 29183, 44471, 187817}},
+{16057, 18, 44674, {1, 3, 7, 11, 9, 55, 19, 115, 395, 559, 1883, 409, 2459, 201, 18975, 339, 108251, 19429}},
+{16058, 18, 44683, {1, 3, 1, 13, 1, 11, 67, 45, 407, 169, 1401, 381, 3913, 6491, 28133, 63857, 52095, 115749}},
+{16059, 18, 44688, {1, 1, 1, 11, 21, 45, 65, 253, 511, 51, 893, 3533, 2101, 4779, 23941, 22449, 82457, 44447}},
+{16060, 18, 44694, {1, 1, 7, 11, 19, 33, 101, 241, 493, 111, 1967, 469, 6575, 10445, 733, 56467, 27403, 25863}},
+{16061, 18, 44703, {1, 3, 1, 1, 5, 49, 21, 79, 53, 621, 43, 1183, 1385, 9129, 21727, 35559, 35269, 211383}},
+{16062, 18, 44713, {1, 1, 1, 13, 23, 43, 53, 145, 149, 611, 745, 899, 7095, 3243, 1993, 35807, 110783, 246199}},
+{16063, 18, 44721, {1, 1, 7, 9, 25, 37, 71, 233, 407, 1, 1749, 759, 7689, 15573, 7351, 33505, 22631, 49125}},
+{16064, 18, 44722, {1, 3, 1, 13, 31, 49, 105, 13, 257, 843, 1171, 2819, 621, 12567, 24339, 6689, 127413, 249671}},
+{16065, 18, 44733, {1, 1, 5, 11, 5, 1, 93, 21, 317, 789, 571, 2493, 7255, 6459, 14737, 13989, 47003, 246561}},
+{16066, 18, 44746, {1, 3, 5, 7, 9, 11, 69, 143, 175, 581, 825, 2219, 1165, 9061, 6073, 57169, 18135, 94943}},
+{16067, 18, 44748, {1, 1, 5, 7, 7, 55, 121, 107, 395, 939, 1291, 2497, 3757, 1361, 31823, 19375, 22551, 224653}},
+{16068, 18, 44760, {1, 1, 7, 15, 15, 1, 47, 225, 223, 589, 1539, 173, 6257, 5461, 11197, 9801, 80687, 84279}},
+{16069, 18, 44765, {1, 3, 7, 11, 23, 47, 83, 119, 367, 895, 431, 1949, 565, 1397, 24911, 29661, 67861, 74621}},
+{16070, 18, 44766, {1, 3, 3, 9, 17, 29, 15, 65, 157, 255, 303, 1467, 3279, 8873, 31279, 431, 8497, 7209}},
+{16071, 18, 44775, {1, 1, 5, 13, 9, 39, 85, 133, 427, 897, 1665, 2109, 2865, 15573, 27729, 59905, 2241, 83099}},
+{16072, 18, 44794, {1, 3, 1, 13, 1, 45, 65, 65, 249, 79, 1515, 503, 953, 9859, 13307, 27419, 102209, 107529}},
+{16073, 18, 44822, {1, 3, 7, 9, 17, 13, 79, 93, 231, 5, 1811, 557, 1837, 8077, 8109, 3497, 79985, 134375}},
+{16074, 18, 44841, {1, 1, 5, 9, 15, 3, 23, 27, 491, 9, 1657, 3877, 3783, 12645, 2599, 10673, 40035, 197681}},
+{16075, 18, 44859, {1, 1, 5, 3, 5, 13, 121, 145, 291, 621, 1731, 145, 2033, 341, 3667, 4139, 52035, 115865}},
+{16076, 18, 44894, {1, 3, 5, 5, 3, 29, 115, 227, 339, 23, 1659, 2367, 1079, 10757, 30709, 41473, 55847, 228761}},
+{16077, 18, 44900, {1, 3, 5, 7, 7, 61, 103, 57, 197, 31, 237, 2507, 5247, 10529, 13823, 47845, 129031, 47029}},
+{16078, 18, 44904, {1, 3, 7, 5, 3, 17, 91, 31, 277, 977, 1905, 3991, 3657, 12197, 14535, 43263, 109629, 31665}},
+{16079, 18, 44946, {1, 1, 5, 15, 29, 43, 121, 113, 159, 929, 669, 2067, 4999, 6847, 12369, 61795, 98525, 78051}},
+{16080, 18, 44967, {1, 1, 3, 7, 25, 61, 65, 79, 373, 683, 113, 1495, 5447, 15507, 16731, 53959, 62905, 252173}},
+{16081, 18, 44994, {1, 3, 1, 11, 1, 15, 101, 55, 477, 357, 333, 3243, 3325, 5885, 11385, 685, 90575, 23015}},
+{16082, 18, 44999, {1, 3, 1, 7, 15, 13, 91, 141, 209, 865, 2035, 2791, 367, 9953, 29547, 36731, 13649, 192911}},
+{16083, 18, 45013, {1, 1, 5, 15, 9, 59, 37, 131, 3, 299, 897, 119, 7515, 5271, 2207, 18187, 62613, 210345}},
+{16084, 18, 45017, {1, 3, 1, 7, 29, 53, 95, 185, 327, 473, 1525, 3751, 915, 5883, 4137, 46343, 104917, 182895}},
+{16085, 18, 45020, {1, 1, 7, 3, 31, 57, 53, 169, 215, 607, 541, 1081, 5265, 2509, 28379, 41767, 19435, 143693}},
+{16086, 18, 45027, {1, 1, 7, 7, 31, 57, 19, 203, 467, 57, 1305, 1513, 6069, 15595, 31717, 44687, 65335, 159315}},
+{16087, 18, 45029, {1, 1, 1, 1, 13, 1, 41, 39, 489, 465, 1645, 2847, 6193, 11025, 11297, 55945, 92085, 243061}},
+{16088, 18, 45066, {1, 3, 3, 13, 15, 47, 87, 77, 321, 903, 181, 2093, 1673, 5375, 17969, 48467, 83441, 120867}},
+{16089, 18, 45074, {1, 3, 3, 13, 13, 17, 65, 181, 283, 471, 745, 1091, 7255, 5987, 29423, 27579, 96201, 218157}},
+{16090, 18, 45080, {1, 1, 1, 7, 13, 5, 101, 131, 309, 401, 99, 2353, 55, 2377, 6059, 64777, 33401, 225605}},
+{16091, 18, 45090, {1, 3, 1, 15, 9, 35, 37, 197, 65, 593, 411, 2233, 1485, 9599, 9581, 31935, 115145, 76867}},
+{16092, 18, 45101, {1, 3, 7, 9, 3, 41, 103, 237, 453, 335, 1831, 3947, 7573, 3859, 12495, 60617, 20715, 163119}},
+{16093, 18, 45110, {1, 3, 5, 7, 9, 9, 25, 79, 421, 267, 585, 1093, 2237, 8881, 7311, 39417, 110901, 8969}},
+{16094, 18, 45113, {1, 3, 3, 15, 1, 29, 75, 159, 89, 965, 457, 1645, 1485, 729, 30547, 2275, 79633, 126089}},
+{16095, 18, 45134, {1, 3, 7, 7, 19, 47, 55, 115, 287, 477, 719, 3311, 2455, 12033, 13811, 34011, 45153, 126991}},
+{16096, 18, 45136, {1, 3, 7, 5, 9, 33, 27, 215, 7, 113, 1027, 415, 1057, 13011, 1547, 7955, 21347, 79427}},
+{16097, 18, 45148, {1, 3, 1, 11, 1, 41, 27, 29, 255, 763, 219, 897, 915, 453, 9417, 22845, 31655, 228869}},
+{16098, 18, 45158, {1, 1, 7, 13, 7, 49, 105, 111, 53, 219, 171, 841, 5027, 5311, 28171, 58719, 32241, 170921}},
+{16099, 18, 45176, {1, 3, 5, 7, 21, 53, 11, 169, 45, 429, 1727, 1953, 8119, 14955, 19997, 62665, 31345, 135715}},
+{16100, 18, 45181, {1, 1, 5, 13, 17, 13, 125, 247, 411, 663, 1725, 2515, 7995, 8963, 5797, 32871, 66603, 137997}},
+{16101, 18, 45185, {1, 1, 5, 5, 23, 37, 15, 63, 35, 817, 463, 1413, 1203, 8031, 4169, 45755, 93511, 134751}},
+{16102, 18, 45188, {1, 1, 1, 1, 31, 17, 15, 125, 199, 57, 1499, 1567, 6113, 6503, 515, 57841, 49885, 213881}},
+{16103, 18, 45203, {1, 1, 7, 7, 15, 1, 67, 213, 197, 471, 577, 27, 1533, 13009, 31861, 62435, 113139, 77057}},
+{16104, 18, 45209, {1, 3, 7, 1, 29, 21, 99, 173, 137, 19, 1727, 1157, 5215, 4367, 28803, 26031, 120195, 60111}},
+{16105, 18, 45231, {1, 1, 5, 9, 25, 55, 27, 45, 231, 693, 765, 429, 2897, 6045, 19705, 61903, 5385, 172967}},
+{16106, 18, 45234, {1, 3, 1, 5, 9, 17, 35, 151, 91, 41, 89, 3751, 27, 5721, 26117, 6105, 31609, 79569}},
+{16107, 18, 45239, {1, 3, 5, 11, 15, 3, 25, 73, 383, 765, 729, 51, 4245, 6215, 9435, 45223, 68071, 68453}},
+{16108, 18, 45246, {1, 1, 7, 5, 31, 61, 19, 153, 331, 233, 11, 3047, 3939, 11959, 897, 4437, 2941, 174493}},
+{16109, 18, 45260, {1, 1, 7, 11, 27, 11, 83, 33, 7, 761, 805, 2327, 2997, 12269, 18707, 10615, 114357, 54951}},
+{16110, 18, 45284, {1, 3, 5, 9, 3, 45, 65, 193, 347, 771, 663, 2901, 6467, 14109, 5169, 38021, 39605, 216877}},
+{16111, 18, 45301, {1, 1, 7, 1, 1, 13, 109, 179, 499, 325, 1763, 1923, 7429, 259, 20589, 48473, 49605, 124709}},
+{16112, 18, 45333, {1, 3, 1, 3, 5, 27, 25, 127, 313, 541, 589, 751, 5959, 5801, 32467, 40597, 75625, 24827}},
+{16113, 18, 45350, {1, 1, 1, 3, 13, 35, 71, 223, 281, 767, 447, 1253, 2227, 7305, 23125, 62847, 16783, 76145}},
+{16114, 18, 45354, {1, 1, 5, 5, 11, 1, 95, 215, 351, 915, 1471, 143, 4011, 3373, 19019, 31797, 85891, 33871}},
+{16115, 18, 45446, {1, 1, 3, 9, 15, 39, 125, 29, 85, 625, 1155, 753, 6679, 14239, 14597, 32715, 97313, 162291}},
+{16116, 18, 45458, {1, 1, 1, 7, 13, 47, 127, 69, 199, 145, 123, 3207, 7673, 9991, 27501, 29189, 93027, 136881}},
+{16117, 18, 45518, {1, 3, 1, 15, 9, 21, 121, 23, 457, 315, 437, 1919, 5531, 13817, 8883, 4421, 19487, 88591}},
+{16118, 18, 45566, {1, 3, 1, 9, 15, 49, 101, 27, 11, 283, 1277, 971, 7697, 5915, 12709, 38251, 88165, 261609}},
+{16119, 18, 45569, {1, 1, 3, 9, 17, 19, 53, 131, 327, 917, 603, 2451, 3597, 14731, 9223, 29719, 113507, 69875}},
+{16120, 18, 45575, {1, 1, 5, 7, 1, 3, 77, 71, 149, 901, 283, 1599, 1053, 16305, 9937, 20907, 4133, 29623}},
+{16121, 18, 45576, {1, 1, 3, 9, 25, 63, 101, 255, 397, 233, 1111, 1583, 3431, 5245, 30209, 33201, 63859, 16551}},
+{16122, 18, 45587, {1, 1, 7, 5, 19, 25, 9, 137, 105, 363, 867, 811, 5829, 12595, 18867, 61021, 19425, 99399}},
+{16123, 18, 45615, {1, 1, 3, 7, 11, 1, 119, 95, 367, 239, 1677, 67, 283, 5701, 3635, 26917, 112895, 224049}},
+{16124, 18, 45661, {1, 3, 5, 11, 13, 33, 11, 191, 305, 551, 159, 1953, 4231, 811, 8711, 41291, 110917, 176177}},
+{16125, 18, 45798, {1, 3, 5, 9, 15, 3, 27, 29, 77, 881, 849, 1113, 7151, 3433, 11199, 38409, 98173, 21373}},
+{16126, 18, 45829, {1, 1, 5, 13, 25, 57, 81, 169, 215, 379, 1707, 493, 1071, 4869, 19149, 24585, 61803, 149305}},
+{16127, 18, 45847, {1, 1, 5, 11, 13, 11, 9, 45, 207, 347, 1203, 185, 3919, 3119, 27879, 50793, 18499, 109239}},
+{16128, 18, 45858, {1, 1, 1, 5, 3, 23, 123, 175, 445, 439, 215, 1883, 6857, 14837, 29411, 33633, 96241, 68361}},
+{16129, 18, 45864, {1, 1, 5, 7, 31, 53, 19, 41, 477, 203, 1133, 1471, 5067, 3875, 30655, 9207, 24835, 22019}},
+{16130, 18, 45899, {1, 3, 1, 11, 19, 9, 91, 217, 135, 169, 489, 727, 5471, 2125, 20867, 19689, 78859, 222433}},
+{16131, 18, 45904, {1, 1, 1, 13, 5, 37, 37, 39, 397, 527, 789, 1447, 7123, 6099, 16849, 48895, 95543, 56135}},
+{16132, 18, 45919, {1, 3, 7, 7, 15, 31, 81, 165, 31, 867, 1879, 1161, 3651, 5167, 12855, 60195, 85611, 191791}},
+{16133, 18, 45974, {1, 1, 1, 9, 31, 35, 19, 123, 281, 445, 63, 2683, 7073, 1489, 9791, 40125, 43723, 103765}},
+{16134, 18, 45987, {1, 3, 3, 9, 23, 31, 113, 241, 149, 463, 1047, 3737, 8105, 16295, 4565, 8095, 16617, 87455}},
+{16135, 18, 45989, {1, 3, 5, 15, 1, 47, 29, 77, 27, 1013, 1091, 3657, 835, 563, 7139, 58839, 92697, 114523}},
+{16136, 18, 46008, {1, 3, 1, 1, 5, 49, 87, 251, 473, 583, 2033, 809, 5341, 15835, 691, 57133, 75751, 127717}},
+{16137, 18, 46036, {1, 3, 1, 11, 23, 51, 95, 167, 73, 739, 573, 1113, 7585, 5457, 25767, 5583, 29583, 48263}},
+{16138, 18, 46039, {1, 1, 3, 5, 9, 59, 1, 235, 17, 973, 1987, 3629, 1739, 6419, 29943, 44963, 63943, 18571}},
+{16139, 18, 46043, {1, 3, 7, 11, 9, 37, 25, 253, 307, 411, 891, 1977, 6979, 11287, 12619, 50327, 25831, 135673}},
+{16140, 18, 46045, {1, 1, 5, 15, 23, 27, 83, 157, 253, 559, 1989, 2431, 4821, 6617, 4295, 16143, 249, 109855}},
+{16141, 18, 46079, {1, 1, 3, 9, 31, 59, 117, 139, 379, 703, 49, 3013, 6383, 4019, 7289, 4567, 34931, 224967}},
+{16142, 18, 46084, {1, 1, 1, 3, 3, 33, 49, 127, 177, 417, 723, 3259, 1547, 3297, 19733, 59465, 122179, 13209}},
+{16143, 18, 46091, {1, 3, 3, 1, 3, 61, 23, 177, 77, 579, 1739, 2707, 5319, 13291, 10223, 45395, 62797, 124675}},
+{16144, 18, 46105, {1, 1, 3, 15, 25, 47, 79, 111, 245, 853, 1103, 3741, 5783, 2075, 26371, 28801, 117831, 111735}},
+{16145, 18, 46117, {1, 1, 5, 11, 3, 47, 43, 61, 75, 963, 1507, 3491, 6031, 14171, 32557, 23779, 44815, 168409}},
+{16146, 18, 46141, {1, 3, 3, 7, 21, 39, 61, 109, 13, 833, 373, 4021, 4035, 7987, 18957, 10423, 82823, 8763}},
+{16147, 18, 46147, {1, 1, 7, 3, 3, 33, 113, 77, 447, 127, 213, 1605, 3873, 12345, 7847, 63903, 80665, 6647}},
+{16148, 18, 46162, {1, 3, 1, 5, 25, 11, 49, 233, 377, 791, 43, 195, 393, 1403, 27567, 29673, 11327, 190513}},
+{16149, 18, 46184, {1, 3, 1, 15, 21, 3, 21, 169, 221, 495, 1045, 3715, 4923, 2437, 23203, 59905, 70285, 258455}},
+{16150, 18, 46197, {1, 1, 7, 13, 29, 33, 91, 153, 31, 359, 25, 3947, 1699, 4081, 20907, 24953, 64977, 88115}},
+{16151, 18, 46207, {1, 1, 5, 11, 17, 7, 17, 129, 91, 835, 139, 3823, 1827, 6787, 27367, 26801, 61513, 189677}},
+{16152, 18, 46214, {1, 3, 3, 9, 23, 21, 97, 103, 481, 859, 413, 893, 4021, 8111, 23703, 18791, 102735, 82735}},
+{16153, 18, 46218, {1, 1, 1, 7, 11, 53, 61, 3, 347, 633, 191, 3605, 41, 12605, 14381, 60403, 126223, 186157}},
+{16154, 18, 46237, {1, 3, 5, 1, 11, 33, 61, 235, 245, 623, 2019, 3289, 5761, 15557, 1685, 2173, 104825, 245139}},
+{16155, 18, 46247, {1, 1, 3, 7, 19, 55, 75, 219, 11, 75, 1765, 1833, 263, 6605, 26297, 24969, 17721, 109495}},
+{16156, 18, 46251, {1, 1, 7, 5, 7, 33, 23, 109, 207, 137, 385, 3233, 6765, 3517, 31389, 57049, 25645, 176257}},
+{16157, 18, 46327, {1, 1, 5, 5, 27, 63, 65, 23, 93, 721, 1665, 3805, 3611, 7543, 21119, 38565, 99921, 72773}},
+{16158, 18, 46333, {1, 1, 1, 13, 13, 19, 23, 5, 425, 727, 1469, 1261, 6597, 725, 27129, 36953, 25781, 191581}},
+{16159, 18, 46342, {1, 3, 3, 1, 3, 29, 25, 109, 237, 135, 409, 2239, 5033, 11007, 31861, 55171, 76313, 216271}},
+{16160, 18, 46366, {1, 3, 7, 13, 31, 33, 11, 31, 179, 67, 755, 2513, 37, 12863, 24053, 12315, 45009, 166643}},
+{16161, 18, 46376, {1, 1, 5, 13, 13, 37, 19, 223, 409, 387, 139, 3283, 243, 15573, 24173, 63271, 91561, 168665}},
+{16162, 18, 46384, {1, 3, 5, 7, 17, 25, 63, 231, 23, 965, 1873, 1021, 7927, 11127, 19553, 9883, 83009, 258991}},
+{16163, 18, 46404, {1, 3, 1, 7, 17, 21, 71, 65, 165, 845, 1739, 2395, 5959, 14803, 17333, 59003, 36477, 202511}},
+{16164, 18, 46478, {1, 3, 5, 13, 15, 57, 59, 205, 507, 41, 703, 195, 4373, 4023, 13399, 62061, 43645, 204899}},
+{16165, 18, 46511, {1, 3, 5, 11, 13, 13, 43, 19, 497, 599, 1345, 2001, 407, 2731, 16283, 55161, 130887, 189201}},
+{16166, 18, 46540, {1, 1, 7, 5, 13, 3, 105, 83, 235, 363, 869, 1715, 4031, 3419, 15149, 10627, 47787, 226107}},
+{16167, 18, 46638, {1, 3, 3, 3, 9, 49, 99, 161, 413, 739, 195, 2815, 1157, 9069, 15591, 4509, 30765, 184013}},
+{16168, 18, 46700, {1, 3, 7, 5, 25, 63, 23, 91, 507, 647, 1249, 2035, 4341, 8811, 8345, 49463, 69023, 195775}},
+{16169, 18, 46706, {1, 3, 5, 5, 5, 21, 117, 1, 321, 495, 251, 1961, 8043, 6593, 11017, 6167, 56607, 144009}},
+{16170, 18, 46745, {1, 1, 3, 3, 15, 63, 41, 177, 403, 375, 1771, 3, 7481, 4887, 799, 59283, 106319, 32155}},
+{16171, 18, 46757, {1, 1, 1, 7, 19, 57, 97, 91, 489, 561, 335, 3809, 3167, 8879, 1789, 22329, 58851, 84461}},
+{16172, 18, 46772, {1, 3, 3, 11, 3, 23, 79, 25, 187, 497, 1343, 543, 4495, 14599, 29365, 14795, 26341, 26923}},
+{16173, 18, 46776, {1, 3, 1, 13, 21, 35, 9, 227, 423, 761, 439, 3099, 5167, 12955, 12877, 5591, 123511, 74227}},
+{16174, 18, 46790, {1, 1, 3, 7, 1, 49, 115, 95, 481, 659, 183, 2337, 39, 235, 30869, 10223, 59673, 65293}},
+{16175, 18, 46794, {1, 1, 1, 13, 11, 29, 113, 37, 153, 993, 1195, 1695, 4741, 13671, 29097, 65023, 78281, 156235}},
+{16176, 18, 46804, {1, 3, 5, 11, 19, 17, 47, 243, 273, 679, 393, 4059, 705, 12473, 1867, 13783, 86821, 240545}},
+{16177, 18, 46820, {1, 3, 1, 11, 23, 35, 15, 31, 275, 261, 427, 909, 7925, 4737, 22825, 34859, 28593, 20071}},
+{16178, 18, 46849, {1, 3, 1, 1, 13, 1, 115, 115, 103, 63, 1023, 815, 7007, 6063, 13329, 28051, 29807, 109861}},
+{16179, 18, 46870, {1, 1, 1, 11, 19, 57, 49, 169, 33, 59, 579, 2409, 89, 9655, 18091, 57771, 34509, 175991}},
+{16180, 18, 46876, {1, 1, 5, 9, 27, 19, 41, 217, 313, 359, 1745, 3887, 589, 3103, 10087, 30615, 56793, 102515}},
+{16181, 18, 46903, {1, 3, 7, 11, 25, 43, 101, 245, 67, 1003, 1379, 2141, 8025, 15231, 20705, 45513, 82251, 147295}},
+{16182, 18, 46904, {1, 3, 5, 5, 5, 47, 19, 33, 107, 773, 627, 4077, 5829, 6483, 25791, 35079, 103073, 201657}},
+{16183, 18, 46907, {1, 1, 5, 15, 1, 37, 115, 15, 61, 987, 1029, 2125, 5357, 10233, 14907, 12077, 92143, 207301}},
+{16184, 18, 46932, {1, 1, 7, 7, 3, 15, 95, 3, 393, 535, 819, 743, 3613, 11459, 2269, 17083, 65547, 74813}},
+{16185, 18, 46955, {1, 1, 7, 5, 11, 27, 117, 65, 55, 87, 105, 3219, 1587, 383, 25349, 54561, 11935, 101203}},
+{16186, 18, 46963, {1, 1, 5, 15, 23, 53, 37, 149, 191, 963, 1407, 4091, 1647, 9537, 30247, 23501, 123745, 76301}},
+{16187, 18, 46991, {1, 3, 1, 1, 21, 31, 11, 107, 55, 823, 805, 141, 7177, 15883, 3307, 52245, 115171, 260589}},
+{16188, 18, 47029, {1, 3, 7, 13, 25, 15, 5, 221, 347, 83, 51, 1227, 4591, 851, 10173, 37777, 82441, 175219}},
+{16189, 18, 47036, {1, 1, 7, 15, 17, 41, 121, 215, 111, 999, 367, 1961, 3207, 10145, 10395, 24381, 95937, 12693}},
+{16190, 18, 47054, {1, 1, 1, 11, 23, 27, 117, 255, 87, 519, 599, 3471, 3983, 2797, 13477, 56479, 27321, 101585}},
+{16191, 18, 47099, {1, 1, 5, 9, 1, 3, 35, 15, 457, 209, 141, 1295, 1631, 9745, 30247, 44865, 78113, 13207}},
+{16192, 18, 47106, {1, 3, 3, 1, 27, 63, 29, 31, 277, 173, 1321, 3847, 4127, 8713, 10507, 8697, 97025, 105995}},
+{16193, 18, 47132, {1, 1, 5, 13, 13, 47, 33, 69, 113, 369, 539, 4075, 1013, 9733, 9291, 33377, 130567, 238331}},
+{16194, 18, 47145, {1, 3, 7, 13, 15, 15, 125, 219, 205, 763, 1233, 1911, 7733, 7623, 27305, 6067, 16169, 238805}},
+{16195, 18, 47151, {1, 3, 1, 9, 23, 17, 35, 175, 157, 627, 1045, 1791, 1675, 11699, 2151, 28293, 14529, 30523}},
+{16196, 18, 47156, {1, 1, 5, 9, 5, 1, 23, 151, 295, 949, 371, 3317, 2557, 5815, 9699, 48379, 104561, 103747}},
+{16197, 18, 47171, {1, 3, 5, 5, 11, 57, 125, 247, 29, 257, 979, 2437, 4391, 8229, 11231, 30145, 111165, 92347}},
+{16198, 18, 47188, {1, 1, 3, 3, 27, 17, 71, 71, 357, 367, 1213, 2549, 6049, 15299, 2891, 21839, 109889, 34643}},
+{16199, 18, 47201, {1, 1, 1, 11, 7, 21, 41, 77, 249, 567, 1947, 2989, 875, 12975, 23599, 49313, 67213, 98415}},
+{16200, 18, 47219, {1, 1, 7, 7, 27, 51, 103, 221, 295, 247, 1579, 2435, 67, 3087, 9421, 59573, 111143, 42363}},
+{16201, 18, 47226, {1, 1, 1, 13, 27, 27, 75, 33, 81, 841, 1295, 2823, 997, 16329, 6117, 43361, 63727, 113347}},
+{16202, 18, 47241, {1, 1, 1, 3, 19, 7, 43, 93, 397, 293, 803, 3021, 3915, 1417, 22255, 38529, 53737, 133705}},
+{16203, 18, 47252, {1, 3, 3, 13, 1, 33, 1, 235, 255, 345, 1621, 315, 2685, 6451, 7133, 239, 103075, 175033}},
+{16204, 18, 47261, {1, 3, 1, 11, 29, 47, 61, 115, 395, 633, 1913, 2983, 4581, 3729, 22511, 16479, 80607, 232859}},
+{16205, 18, 47295, {1, 3, 7, 7, 27, 25, 29, 121, 511, 533, 1791, 3349, 4915, 8213, 13913, 6595, 2353, 207495}},
+{16206, 18, 47297, {1, 3, 7, 5, 21, 25, 77, 189, 473, 1015, 1455, 1923, 3281, 15163, 2329, 58529, 55369, 195007}},
+{16207, 18, 47333, {1, 3, 1, 1, 25, 37, 117, 41, 207, 413, 143, 1707, 7463, 15399, 3013, 4141, 37669, 70953}},
+{16208, 18, 47337, {1, 3, 5, 3, 31, 61, 41, 157, 141, 387, 1705, 1661, 3607, 6905, 3305, 63235, 7977, 253707}},
+{16209, 18, 47360, {1, 1, 5, 11, 29, 15, 61, 127, 417, 795, 171, 415, 7935, 4553, 29979, 21153, 108811, 219959}},
+{16210, 18, 47377, {1, 1, 5, 11, 17, 61, 3, 9, 297, 53, 933, 341, 507, 2683, 15313, 24113, 78617, 191127}},
+{16211, 18, 47378, {1, 1, 7, 15, 5, 57, 65, 187, 15, 541, 1843, 731, 7331, 2479, 26259, 32685, 125259, 108693}},
+{16212, 18, 47384, {1, 1, 7, 7, 11, 15, 33, 183, 225, 609, 1755, 3531, 2767, 6267, 30823, 36797, 59699, 136769}},
+{16213, 18, 47389, {1, 3, 5, 13, 15, 19, 77, 239, 307, 691, 1165, 1327, 7901, 9299, 7777, 39151, 96261, 79791}},
+{16214, 18, 47417, {1, 1, 3, 5, 29, 31, 85, 109, 381, 243, 955, 193, 3461, 5163, 18607, 51143, 74457, 84685}},
+{16215, 18, 47420, {1, 1, 5, 9, 11, 23, 77, 247, 149, 759, 1153, 1781, 4107, 16315, 15513, 48545, 55607, 163947}},
+{16216, 18, 47426, {1, 3, 3, 5, 21, 27, 57, 61, 75, 943, 97, 1507, 4091, 671, 23023, 49095, 61649, 222401}},
+{16217, 18, 47443, {1, 1, 3, 13, 1, 3, 15, 105, 285, 255, 577, 1347, 2917, 10257, 21607, 63041, 79823, 6447}},
+{16218, 18, 47504, {1, 1, 3, 1, 17, 25, 109, 47, 445, 225, 1729, 2835, 4569, 8755, 21847, 25839, 43503, 173599}},
+{16219, 18, 47507, {1, 1, 5, 15, 19, 1, 121, 119, 33, 77, 1147, 359, 5747, 2785, 15567, 5409, 125979, 199183}},
+{16220, 18, 47510, {1, 3, 1, 9, 17, 45, 85, 83, 427, 223, 531, 1681, 2343, 14959, 27297, 54607, 70889, 45529}},
+{16221, 18, 47526, {1, 1, 5, 11, 31, 61, 109, 195, 505, 197, 159, 2799, 4517, 11549, 10297, 17415, 58277, 206577}},
+{16222, 18, 47550, {1, 1, 3, 5, 17, 43, 107, 207, 453, 161, 1775, 1287, 5775, 12417, 14201, 48187, 75073, 121099}},
+{16223, 18, 47552, {1, 1, 5, 7, 31, 27, 67, 251, 127, 443, 263, 895, 8081, 14053, 32023, 54743, 14723, 221285}},
+{16224, 18, 47557, {1, 3, 3, 13, 27, 45, 51, 47, 243, 15, 1283, 2291, 3613, 14733, 8777, 3959, 36769, 104789}},
+{16225, 18, 47564, {1, 3, 5, 1, 5, 31, 1, 139, 411, 79, 959, 1431, 2329, 3595, 19231, 55747, 18923, 223709}},
+{16226, 18, 47591, {1, 3, 1, 1, 7, 9, 69, 201, 305, 411, 459, 3201, 2525, 6977, 16249, 17777, 114321, 243831}},
+{16227, 18, 47610, {1, 3, 3, 5, 13, 7, 3, 27, 201, 279, 1253, 1725, 1481, 8885, 1233, 40699, 7267, 189095}},
+{16228, 18, 47621, {1, 3, 5, 5, 31, 61, 53, 231, 93, 597, 2027, 2179, 4517, 565, 27807, 5447, 130341, 10411}},
+{16229, 18, 47639, {1, 1, 7, 1, 9, 17, 63, 245, 405, 23, 1647, 285, 6625, 8935, 959, 29095, 657, 185511}},
+{16230, 18, 47646, {1, 1, 7, 7, 5, 15, 49, 69, 479, 585, 437, 1097, 5933, 1709, 26169, 36895, 16981, 147033}},
+{16231, 18, 47676, {1, 3, 7, 13, 29, 19, 89, 249, 195, 687, 379, 1291, 4791, 9039, 6381, 12965, 99995, 105107}},
+{16232, 18, 47682, {1, 1, 5, 7, 13, 49, 101, 217, 205, 635, 577, 3301, 911, 1793, 22285, 20163, 22593, 45701}},
+{16233, 18, 47732, {1, 3, 7, 9, 3, 21, 55, 123, 205, 309, 59, 3739, 1625, 839, 26733, 27443, 6699, 244287}},
+{16234, 18, 47741, {1, 1, 1, 11, 29, 3, 33, 57, 481, 691, 1401, 3595, 5435, 571, 6945, 10911, 94721, 89751}},
+{16235, 18, 47751, {1, 1, 3, 5, 21, 19, 23, 169, 263, 137, 771, 1995, 2211, 6287, 18691, 14219, 65647, 89885}},
+{16236, 18, 47757, {1, 1, 3, 7, 7, 53, 9, 155, 327, 325, 301, 3703, 1069, 15573, 14873, 15665, 71617, 5079}},
+{16237, 18, 47786, {1, 3, 1, 3, 27, 15, 1, 203, 465, 629, 71, 1093, 2071, 7743, 22441, 42997, 35249, 113329}},
+{16238, 18, 47803, {1, 3, 5, 3, 21, 35, 107, 73, 247, 575, 719, 3215, 3181, 5861, 25169, 6503, 12347, 196371}},
+{16239, 18, 47828, {1, 3, 1, 3, 7, 29, 117, 115, 221, 345, 165, 1367, 1491, 15791, 12647, 34679, 1043, 219311}},
+{16240, 18, 47848, {1, 3, 5, 7, 19, 47, 65, 65, 101, 323, 1209, 3185, 3803, 1077, 18933, 17081, 7475, 165133}},
+{16241, 18, 47853, {1, 1, 7, 1, 25, 9, 61, 245, 175, 201, 1837, 2119, 943, 14043, 14343, 46299, 81151, 5587}},
+{16242, 18, 47856, {1, 1, 1, 1, 31, 27, 49, 89, 387, 975, 1203, 2995, 2969, 1465, 925, 39611, 38101, 126043}},
+{16243, 18, 47862, {1, 3, 7, 13, 21, 17, 45, 139, 359, 11, 335, 79, 6629, 6137, 7879, 62735, 99493, 138943}},
+{16244, 18, 47874, {1, 3, 5, 5, 9, 23, 91, 195, 89, 195, 1931, 3855, 387, 3491, 29643, 59939, 32347, 171539}},
+{16245, 18, 47883, {1, 3, 3, 15, 21, 55, 5, 13, 139, 125, 1731, 3131, 1927, 16051, 8351, 18625, 32465, 255813}},
+{16246, 18, 47916, {1, 3, 7, 11, 21, 45, 53, 225, 33, 733, 115, 639, 4801, 5529, 11041, 3557, 83521, 37525}},
+{16247, 18, 47934, {1, 3, 7, 15, 3, 37, 111, 127, 463, 565, 543, 2593, 2203, 5719, 11667, 63735, 16481, 155613}},
+{16248, 18, 47951, {1, 1, 3, 13, 31, 1, 17, 53, 479, 629, 1517, 89, 3377, 4831, 9213, 55029, 69547, 52363}},
+{16249, 18, 47979, {1, 1, 7, 1, 5, 47, 115, 73, 59, 407, 1227, 2955, 5249, 7921, 4713, 28699, 41455, 1161}},
+{16250, 18, 48010, {1, 1, 7, 7, 5, 7, 39, 7, 97, 867, 247, 639, 3125, 14961, 19737, 52589, 59821, 96095}},
+{16251, 18, 48027, {1, 1, 7, 5, 11, 51, 63, 245, 385, 1003, 189, 4039, 6137, 3621, 13241, 55753, 14855, 50221}},
+{16252, 18, 48046, {1, 3, 5, 3, 9, 61, 83, 209, 301, 917, 259, 187, 6253, 1579, 28285, 16571, 100945, 158067}},
+{16253, 18, 48060, {1, 3, 5, 11, 5, 47, 123, 173, 253, 183, 1823, 459, 4719, 13639, 8455, 12217, 88779, 134863}},
+{16254, 18, 48065, {1, 1, 1, 5, 1, 45, 43, 163, 371, 427, 1791, 1073, 1615, 14473, 15895, 4971, 105269, 109201}},
+{16255, 18, 48075, {1, 3, 1, 15, 11, 9, 99, 99, 25, 21, 1499, 83, 6967, 12923, 13623, 27423, 4707, 477}},
+{16256, 18, 48096, {1, 1, 3, 5, 15, 49, 45, 27, 51, 391, 1849, 347, 6841, 2831, 4425, 40701, 61135, 116945}},
+{16257, 18, 48119, {1, 1, 3, 7, 21, 23, 15, 223, 403, 395, 1997, 3247, 6345, 11739, 6511, 44323, 86667, 213287}},
+{16258, 18, 48173, {1, 3, 7, 11, 31, 21, 75, 129, 427, 777, 1787, 4031, 1493, 2279, 10681, 36675, 25527, 123533}},
+{16259, 18, 48176, {1, 3, 5, 15, 9, 5, 117, 147, 259, 265, 1817, 583, 5341, 12115, 2369, 4023, 123479, 218877}},
+{16260, 18, 48186, {1, 1, 1, 15, 5, 21, 87, 57, 487, 529, 1129, 2989, 39, 5995, 28779, 35813, 97425, 5227}},
+{16261, 18, 48213, {1, 1, 7, 3, 7, 1, 41, 231, 195, 205, 1663, 3149, 4439, 8241, 3085, 43965, 58833, 216779}},
+{16262, 18, 48223, {1, 1, 3, 1, 23, 45, 65, 3, 55, 653, 131, 2425, 5653, 9105, 16921, 55221, 29241, 220927}},
+{16263, 18, 48224, {1, 3, 1, 3, 5, 47, 107, 49, 175, 957, 1287, 1299, 5215, 4141, 31697, 9371, 43339, 133933}},
+{16264, 18, 48229, {1, 3, 1, 7, 13, 55, 33, 163, 361, 793, 101, 2159, 3457, 12893, 11627, 27115, 95201, 2945}},
+{16265, 18, 48241, {1, 1, 7, 15, 11, 39, 79, 113, 385, 41, 1715, 3887, 1347, 8141, 6121, 18653, 50867, 55745}},
+{16266, 18, 48281, {1, 1, 7, 13, 3, 5, 23, 59, 223, 665, 1823, 2989, 1069, 15161, 8917, 5539, 47437, 240933}},
+{16267, 18, 48284, {1, 3, 7, 13, 13, 19, 73, 25, 413, 211, 439, 339, 1159, 16063, 9589, 33451, 28789, 118883}},
+{16268, 18, 48291, {1, 1, 5, 11, 13, 61, 81, 63, 197, 569, 961, 253, 2065, 8969, 24045, 52811, 26929, 111329}},
+{16269, 18, 48308, {1, 3, 7, 5, 19, 23, 27, 163, 37, 103, 1737, 175, 1853, 597, 14147, 46159, 26385, 69427}},
+{16270, 18, 48340, {1, 3, 7, 9, 27, 43, 45, 209, 61, 115, 645, 1149, 1473, 10557, 8541, 51703, 29207, 92059}},
+{16271, 18, 48344, {1, 1, 5, 5, 25, 53, 123, 243, 493, 403, 485, 1505, 6879, 1921, 13569, 28271, 24407, 73057}},
+{16272, 18, 48368, {1, 1, 3, 11, 15, 31, 99, 29, 503, 819, 55, 773, 2993, 15341, 7625, 12835, 28555, 200609}},
+{16273, 18, 48400, {1, 1, 7, 9, 21, 49, 47, 207, 13, 571, 57, 1727, 7441, 1703, 4253, 64851, 113, 180273}},
+{16274, 18, 48406, {1, 3, 3, 9, 23, 1, 1, 53, 195, 569, 925, 1969, 3031, 14371, 17673, 39163, 11819, 117573}},
+{16275, 18, 48409, {1, 1, 1, 11, 5, 3, 103, 133, 447, 1015, 1049, 3283, 7507, 233, 13721, 50721, 75511, 227561}},
+{16276, 18, 48421, {1, 3, 1, 1, 17, 59, 79, 105, 503, 173, 1575, 1563, 5807, 12841, 7983, 28209, 27527, 229919}},
+{16277, 18, 48448, {1, 1, 3, 9, 3, 41, 125, 213, 361, 939, 161, 2235, 2575, 13519, 7957, 21527, 40693, 51055}},
+{16278, 18, 48453, {1, 3, 7, 11, 11, 7, 117, 21, 7, 745, 1109, 3393, 953, 5163, 19909, 49121, 85061, 209555}},
+{16279, 18, 48457, {1, 1, 7, 5, 27, 59, 127, 199, 119, 461, 653, 497, 5867, 767, 16373, 21201, 87589, 171491}},
+{16280, 18, 48478, {1, 1, 7, 11, 7, 21, 121, 97, 17, 827, 1191, 113, 6527, 14977, 32567, 15191, 104541, 140359}},
+{16281, 18, 48493, {1, 1, 7, 13, 19, 29, 127, 207, 233, 511, 43, 3177, 7963, 5559, 24185, 13373, 37853, 150537}},
+{16282, 18, 48527, {1, 3, 3, 9, 15, 17, 119, 201, 443, 51, 17, 605, 4191, 5251, 28903, 4861, 92571, 143499}},
+{16283, 18, 48583, {1, 1, 5, 11, 21, 45, 111, 245, 115, 705, 1267, 3013, 7907, 14973, 30499, 44117, 118229, 136571}},
+{16284, 18, 48597, {1, 3, 7, 7, 31, 35, 69, 143, 269, 27, 1365, 775, 6067, 11477, 28475, 54573, 92827, 226459}},
+{16285, 18, 48641, {1, 1, 5, 1, 1, 29, 41, 189, 423, 245, 1031, 1667, 3465, 1491, 26787, 53851, 26189, 215443}},
+{16286, 18, 48668, {1, 3, 3, 5, 23, 29, 97, 141, 135, 249, 767, 3627, 7867, 9311, 25411, 38325, 118643, 128453}},
+{16287, 18, 48671, {1, 3, 7, 13, 3, 25, 61, 121, 285, 401, 1099, 2327, 5509, 16127, 2363, 52395, 114233, 216013}},
+{16288, 18, 48682, {1, 1, 1, 13, 7, 37, 83, 151, 447, 605, 289, 2941, 6273, 5945, 7493, 29805, 34935, 101177}},
+{16289, 18, 48709, {1, 1, 7, 13, 31, 51, 125, 9, 321, 293, 489, 4023, 2425, 7645, 2927, 20973, 111223, 71255}},
+{16290, 18, 48719, {1, 1, 7, 3, 27, 9, 59, 143, 307, 543, 1995, 111, 5807, 4641, 3581, 2421, 64213, 187567}},
+{16291, 18, 48731, {1, 3, 3, 9, 23, 33, 47, 81, 441, 995, 213, 3501, 1003, 9885, 24101, 58767, 49507, 30525}},
+{16292, 18, 48780, {1, 3, 1, 3, 19, 51, 117, 53, 49, 167, 1799, 1421, 2473, 3183, 14421, 58621, 130703, 48095}},
+{16293, 18, 48791, {1, 1, 7, 7, 5, 25, 33, 237, 447, 377, 517, 2047, 4357, 2747, 16491, 23935, 21655, 144151}},
+{16294, 18, 48797, {1, 1, 7, 7, 17, 5, 57, 67, 89, 897, 1163, 3517, 1651, 6745, 23449, 2853, 43829, 50707}},
+{16295, 18, 48807, {1, 1, 1, 13, 5, 45, 87, 139, 339, 1021, 649, 2957, 7887, 11957, 11235, 11063, 77329, 93121}},
+{16296, 18, 48811, {1, 1, 1, 7, 11, 35, 73, 241, 11, 287, 551, 207, 4701, 2031, 27191, 44337, 35577, 226387}},
+{16297, 18, 48814, {1, 3, 5, 11, 19, 3, 41, 211, 29, 913, 1455, 2525, 3935, 5581, 8043, 12033, 97479, 73521}},
+{16298, 18, 48821, {1, 3, 5, 7, 15, 49, 53, 185, 229, 161, 121, 3407, 903, 7257, 19535, 42197, 3983, 222077}},
+{16299, 18, 48836, {1, 1, 5, 7, 17, 33, 61, 121, 343, 111, 151, 1147, 3743, 2423, 24151, 42307, 50711, 140317}},
+{16300, 18, 48846, {1, 3, 3, 7, 27, 1, 119, 209, 243, 185, 1253, 2307, 7659, 7839, 9697, 16799, 5189, 130005}},
+{16301, 18, 48848, {1, 3, 3, 1, 27, 21, 115, 175, 157, 735, 1233, 1133, 1763, 1125, 4667, 42569, 125185, 218417}},
+{16302, 18, 48854, {1, 3, 5, 9, 5, 37, 97, 165, 87, 447, 1491, 3141, 597, 10651, 9727, 65163, 2469, 141859}},
+{16303, 18, 48874, {1, 1, 5, 13, 11, 53, 111, 123, 423, 413, 1519, 3715, 6623, 15415, 24085, 20925, 1529, 85183}},
+{16304, 18, 48908, {1, 3, 7, 1, 31, 45, 93, 45, 363, 779, 443, 3687, 6051, 11683, 31733, 57251, 55087, 240877}},
+{16305, 18, 48929, {1, 1, 1, 15, 1, 17, 53, 237, 131, 673, 1919, 1531, 7455, 5043, 1709, 23375, 75657, 194393}},
+{16306, 18, 48941, {1, 3, 5, 9, 21, 3, 101, 141, 387, 887, 1329, 2627, 2865, 2685, 20273, 18901, 43805, 181049}},
+{16307, 18, 48954, {1, 3, 5, 5, 7, 49, 55, 243, 311, 653, 959, 3157, 4891, 8777, 14381, 28105, 119323, 181129}},
+{16308, 18, 48961, {1, 1, 1, 9, 17, 33, 97, 123, 71, 5, 793, 2829, 4385, 8577, 9927, 26213, 53287, 203555}},
+{16309, 18, 48962, {1, 1, 1, 9, 15, 61, 51, 31, 195, 1003, 1915, 2349, 5319, 13411, 15265, 36321, 76157, 200437}},
+{16310, 18, 48985, {1, 3, 1, 13, 19, 41, 11, 227, 447, 395, 1885, 2953, 3537, 3855, 21611, 14547, 106573, 233205}},
+{16311, 18, 49001, {1, 3, 1, 11, 1, 1, 7, 61, 69, 631, 1687, 1131, 6901, 5801, 14431, 17807, 35777, 253941}},
+{16312, 18, 49007, {1, 3, 5, 9, 15, 47, 71, 145, 419, 401, 1781, 2031, 3157, 14483, 2393, 4061, 122053, 81701}},
+{16313, 18, 49015, {1, 3, 7, 13, 23, 21, 67, 147, 137, 277, 259, 3119, 4785, 5349, 3193, 21805, 108265, 231111}},
+{16314, 18, 49035, {1, 1, 3, 9, 23, 63, 77, 153, 75, 643, 1341, 3607, 6001, 3387, 17485, 17893, 124699, 99515}},
+{16315, 18, 49062, {1, 1, 7, 11, 9, 51, 79, 255, 255, 723, 1797, 2805, 2505, 3437, 4835, 30731, 73741, 8051}},
+{16316, 18, 49066, {1, 1, 5, 7, 5, 19, 73, 75, 19, 889, 1443, 2263, 5773, 9997, 329, 46679, 82313, 130897}},
+{16317, 18, 49085, {1, 3, 3, 9, 7, 53, 69, 11, 287, 861, 1367, 1433, 2693, 16255, 6785, 24705, 77463, 231247}},
+{16318, 18, 49091, {1, 1, 3, 7, 21, 15, 115, 131, 169, 447, 1731, 2873, 119, 643, 31719, 22193, 17959, 150567}},
+{16319, 18, 49094, {1, 3, 3, 9, 23, 21, 7, 39, 185, 837, 379, 3687, 3751, 14801, 15231, 7239, 77521, 80135}},
+{16320, 18, 49127, {1, 1, 1, 1, 7, 33, 93, 247, 487, 873, 1951, 3273, 551, 3735, 29477, 62387, 30361, 145613}},
+{16321, 18, 49134, {1, 1, 3, 7, 5, 47, 17, 31, 93, 517, 1175, 1033, 7421, 75, 541, 1967, 13059, 104751}},
+{16322, 18, 49183, {1, 3, 5, 3, 19, 23, 123, 115, 99, 747, 655, 2885, 2991, 7497, 5989, 33419, 54363, 224947}},
+{16323, 18, 49221, {1, 3, 3, 1, 15, 9, 51, 3, 307, 879, 1065, 1835, 2267, 11299, 21995, 2997, 102207, 39}},
+{16324, 18, 49231, {1, 3, 5, 3, 9, 19, 19, 79, 499, 121, 951, 1151, 379, 5299, 13727, 49061, 32605, 208683}},
+{16325, 18, 49250, {1, 3, 7, 7, 23, 41, 71, 23, 493, 969, 271, 3729, 6199, 14693, 17625, 52509, 121257, 151175}},
+{16326, 18, 49252, {1, 1, 7, 15, 9, 51, 61, 9, 147, 527, 803, 3255, 723, 3241, 23961, 17497, 122569, 50863}},
+{16327, 18, 49270, {1, 3, 5, 1, 19, 19, 31, 31, 95, 667, 377, 1193, 6759, 8583, 29801, 7989, 113899, 43481}},
+{16328, 18, 49297, {1, 3, 7, 5, 17, 47, 1, 7, 305, 489, 1035, 1335, 5901, 9635, 10433, 4235, 108577, 52661}},
+{16329, 18, 49313, {1, 1, 7, 3, 15, 7, 105, 189, 429, 287, 679, 111, 2087, 8479, 3053, 21763, 65655, 16207}},
+{16330, 18, 49340, {1, 3, 5, 13, 19, 41, 45, 115, 311, 653, 1301, 3797, 6183, 7203, 9829, 13263, 71649, 255611}},
+{16331, 18, 49365, {1, 3, 1, 9, 21, 33, 19, 233, 83, 423, 1701, 347, 3999, 11885, 19699, 61931, 63895, 59615}},
+{16332, 18, 49379, {1, 1, 7, 7, 15, 19, 61, 43, 183, 223, 1135, 3099, 3137, 16181, 31019, 20151, 30169, 13125}},
+{16333, 18, 49386, {1, 1, 1, 11, 9, 11, 3, 157, 495, 207, 603, 1919, 3565, 7639, 4281, 49179, 2465, 224033}},
+{16334, 18, 49391, {1, 3, 1, 13, 13, 19, 127, 81, 475, 659, 1053, 3153, 5223, 12567, 30945, 47109, 98253, 41571}},
+{16335, 18, 49417, {1, 1, 5, 11, 19, 1, 9, 67, 501, 149, 1695, 1265, 6467, 5285, 29865, 46777, 97581, 209395}},
+{16336, 18, 49438, {1, 1, 1, 11, 21, 23, 123, 103, 419, 787, 111, 3327, 673, 3425, 8097, 2411, 107353, 121379}},
+{16337, 18, 49444, {1, 1, 3, 3, 17, 7, 87, 35, 501, 973, 351, 751, 4813, 12245, 3053, 38633, 44995, 37151}},
+{16338, 18, 49453, {1, 3, 5, 15, 7, 57, 99, 53, 3, 355, 153, 3897, 6923, 2075, 10821, 41819, 75665, 21237}},
+{16339, 18, 49454, {1, 3, 5, 9, 3, 29, 85, 115, 191, 977, 1067, 1539, 5287, 3589, 18017, 35571, 41633, 148565}},
+{16340, 18, 49480, {1, 1, 3, 9, 9, 57, 1, 63, 333, 107, 1173, 3377, 3599, 277, 20643, 19295, 91169, 168891}},
+{16341, 18, 49485, {1, 1, 5, 13, 21, 7, 55, 15, 79, 995, 1553, 949, 6357, 8137, 9539, 861, 95635, 63021}},
+{16342, 18, 49498, {1, 1, 5, 13, 31, 59, 11, 55, 159, 449, 307, 2725, 2305, 8259, 13823, 51225, 44775, 54253}},
+{16343, 18, 49513, {1, 3, 3, 15, 19, 61, 105, 19, 211, 693, 835, 3607, 3703, 14007, 24597, 47109, 49855, 166115}},
+{16344, 18, 49527, {1, 3, 1, 9, 27, 33, 81, 229, 445, 171, 247, 2019, 5227, 8759, 30155, 1851, 26909, 47145}},
+{16345, 18, 49531, {1, 1, 3, 5, 23, 1, 57, 49, 177, 451, 1283, 3859, 4719, 13507, 29439, 9155, 129585, 94713}},
+{16346, 18, 49564, {1, 3, 3, 5, 1, 9, 37, 23, 423, 611, 113, 119, 4307, 11747, 93, 51213, 5479, 172061}},
+{16347, 18, 49588, {1, 3, 3, 15, 5, 35, 9, 43, 423, 877, 1563, 3411, 4233, 6961, 22421, 7347, 39553, 199745}},
+{16348, 18, 49609, {1, 3, 1, 9, 15, 35, 85, 57, 151, 323, 1627, 27, 3603, 11475, 6561, 6091, 72099, 185321}},
+{16349, 18, 49617, {1, 1, 3, 15, 17, 21, 3, 119, 455, 147, 1077, 3955, 1355, 3083, 28217, 50745, 114445, 46563}},
+{16350, 18, 49645, {1, 1, 5, 3, 13, 11, 35, 185, 357, 447, 649, 139, 2847, 12011, 7753, 671, 113693, 236281}},
+{16351, 18, 49646, {1, 3, 5, 1, 19, 27, 117, 195, 67, 259, 1073, 81, 5527, 6829, 26675, 60029, 8159, 13553}},
+{16352, 18, 49654, {1, 3, 3, 7, 27, 63, 115, 191, 431, 191, 1547, 2261, 6527, 13459, 12773, 37485, 114847, 61709}},
+{16353, 18, 49697, {1, 1, 3, 1, 29, 63, 47, 77, 415, 191, 325, 2487, 7457, 13721, 1573, 15037, 31941, 226651}},
+{16354, 18, 49718, {1, 1, 5, 11, 29, 59, 49, 209, 195, 901, 691, 3167, 7471, 11609, 30135, 22067, 71395, 248151}},
+{16355, 18, 49741, {1, 3, 7, 11, 7, 43, 55, 69, 289, 735, 1479, 139, 1395, 6463, 19827, 52151, 18963, 103367}},
+{16356, 18, 49754, {1, 3, 5, 5, 27, 45, 77, 79, 89, 79, 913, 1437, 3337, 8861, 5477, 46195, 105869, 242599}},
+{16357, 18, 49756, {1, 3, 5, 3, 3, 27, 103, 207, 233, 995, 1173, 1143, 3517, 3207, 8373, 45145, 79687, 150107}},
+{16358, 18, 49833, {1, 3, 7, 3, 7, 37, 1, 137, 45, 479, 861, 3863, 4249, 3075, 23639, 12531, 118473, 255805}},
+{16359, 18, 49834, {1, 1, 1, 9, 7, 23, 125, 57, 347, 215, 1749, 3029, 97, 14715, 16213, 29291, 104725, 92043}},
+{16360, 18, 49879, {1, 3, 3, 15, 31, 39, 111, 97, 369, 675, 1471, 3889, 6437, 1499, 13325, 46141, 121087, 202493}},
+{16361, 18, 49942, {1, 1, 1, 15, 15, 21, 3, 167, 251, 793, 1291, 427, 6407, 15521, 15441, 20071, 54513, 200485}},
+{16362, 18, 49946, {1, 1, 7, 11, 27, 47, 123, 195, 241, 385, 609, 2323, 1221, 815, 279, 28553, 17663, 180977}},
+{16363, 18, 49982, {1, 1, 3, 15, 23, 53, 21, 19, 329, 903, 561, 1539, 2829, 13037, 29867, 27825, 84005, 14853}},
+{16364, 18, 49994, {1, 1, 5, 1, 21, 27, 103, 99, 31, 829, 515, 3949, 3635, 935, 2127, 56659, 123477, 47003}},
+{16365, 18, 50001, {1, 3, 1, 11, 17, 63, 51, 15, 319, 539, 55, 2561, 1109, 16115, 23387, 20051, 120867, 4019}},
+{16366, 18, 50023, {1, 3, 3, 7, 31, 11, 45, 251, 209, 21, 553, 887, 393, 15183, 14735, 13163, 123681, 15013}},
+{16367, 18, 50047, {1, 3, 1, 7, 21, 41, 105, 39, 213, 477, 985, 2375, 937, 7099, 8867, 36519, 60503, 143225}},
+{16368, 18, 50120, {1, 3, 1, 1, 19, 55, 73, 171, 379, 271, 791, 2477, 5381, 1703, 3805, 37227, 55553, 34549}},
+{16369, 18, 50133, {1, 1, 5, 5, 29, 51, 127, 111, 209, 663, 975, 2293, 8155, 11263, 7891, 15463, 74889, 227403}},
+{16370, 18, 50137, {1, 3, 5, 1, 15, 1, 115, 221, 23, 247, 1597, 87, 7513, 3329, 14491, 8961, 78147, 89499}},
+{16371, 18, 50140, {1, 3, 5, 15, 25, 23, 99, 85, 189, 487, 1559, 427, 6179, 5291, 27279, 65507, 77347, 177073}},
+{16372, 18, 50156, {1, 3, 7, 1, 23, 35, 7, 89, 455, 659, 2039, 3115, 4057, 139, 1269, 62319, 13629, 201571}},
+{16373, 18, 50199, {1, 1, 1, 5, 9, 47, 55, 171, 213, 813, 135, 1545, 1421, 4055, 26697, 18889, 57653, 201369}},
+{16374, 18, 50205, {1, 3, 1, 11, 9, 45, 5, 69, 261, 907, 1229, 1371, 1867, 1771, 17309, 41759, 119129, 43521}},
+{16375, 18, 50215, {1, 1, 7, 5, 11, 27, 9, 237, 405, 53, 1359, 3665, 169, 3547, 23331, 14353, 106627, 219711}},
+{16376, 18, 50216, {1, 3, 3, 5, 17, 23, 9, 41, 81, 601, 1447, 3225, 6721, 161, 16109, 54331, 111273, 81061}},
+{16377, 18, 50224, {1, 1, 5, 7, 7, 37, 71, 13, 505, 671, 425, 2771, 1131, 1259, 13715, 45779, 114839, 217499}},
+{16378, 18, 50229, {1, 1, 1, 5, 9, 51, 85, 223, 117, 403, 1117, 723, 2465, 11947, 7495, 62991, 17825, 169147}},
+{16379, 18, 50233, {1, 1, 3, 13, 5, 57, 47, 35, 313, 901, 365, 1265, 137, 6335, 31419, 38497, 93285, 177187}},
+{16380, 18, 50251, {1, 3, 5, 5, 7, 9, 21, 109, 47, 557, 1449, 3459, 5175, 5135, 727, 55425, 60593, 86571}},
+{16381, 18, 50281, {1, 3, 7, 5, 1, 17, 119, 239, 347, 75, 1345, 2765, 1491, 16297, 25233, 60401, 85433, 59287}},
+{16382, 18, 50326, {1, 1, 5, 5, 19, 57, 41, 53, 161, 475, 1791, 3617, 1651, 15227, 30357, 63547, 69937, 246473}},
+{16383, 18, 50332, {1, 3, 7, 11, 11, 43, 79, 79, 195, 437, 39, 1259, 6041, 14989, 6615, 58747, 43583, 246979}},
+{16384, 18, 50348, {1, 1, 7, 9, 11, 13, 49, 133, 365, 931, 1089, 713, 5997, 8759, 5789, 61329, 22639, 149845}},
+{16385, 18, 50359, {1, 3, 7, 13, 9, 3, 11, 253, 339, 883, 1933, 443, 4265, 14165, 15845, 12625, 1453, 70961}},
+{16386, 18, 50374, {1, 1, 7, 13, 21, 35, 113, 83, 473, 719, 1601, 1727, 3715, 631, 28075, 17725, 11393, 116883}},
+{16387, 18, 50404, {1, 3, 7, 7, 7, 13, 117, 83, 365, 529, 1297, 3903, 2633, 9617, 15819, 38137, 49065, 189445}},
+{16388, 18, 50443, {1, 1, 1, 7, 11, 41, 107, 33, 381, 395, 1993, 2819, 3301, 7543, 6787, 27437, 113681, 132403}},
+{16389, 18, 50488, {1, 1, 1, 1, 3, 59, 91, 235, 67, 987, 1587, 1119, 5851, 13201, 1125, 49709, 381, 183295}},
+{16390, 18, 50493, {1, 3, 5, 9, 3, 33, 45, 187, 455, 151, 823, 565, 5725, 1927, 25387, 61785, 130271, 134083}},
+{16391, 18, 50505, {1, 1, 7, 5, 15, 25, 63, 231, 133, 401, 307, 2961, 4249, 2639, 10207, 8349, 8203, 72783}},
+{16392, 18, 50511, {1, 1, 5, 13, 19, 27, 43, 153, 165, 815, 1385, 3041, 853, 7683, 1035, 13255, 69779, 128765}},
+{16393, 18, 50525, {1, 1, 1, 3, 31, 61, 97, 15, 327, 717, 841, 643, 4781, 11609, 14181, 14625, 75369, 251015}},
+{16394, 18, 50542, {1, 1, 5, 11, 17, 33, 9, 45, 111, 91, 1923, 967, 5649, 13647, 30497, 2925, 18395, 255089}},
+{16395, 18, 50550, {1, 3, 3, 1, 3, 55, 33, 29, 101, 211, 1731, 2351, 7389, 14935, 29703, 60031, 122305, 174323}},
+{16396, 18, 50560, {1, 1, 1, 3, 13, 23, 79, 117, 367, 267, 143, 1537, 3159, 2303, 9653, 12029, 2841, 226971}},
+{16397, 18, 50570, {1, 1, 1, 13, 19, 57, 103, 159, 315, 895, 1879, 2153, 1901, 7635, 14145, 56495, 6203, 151203}},
+{16398, 18, 50587, {1, 3, 3, 11, 31, 11, 75, 5, 419, 963, 1809, 3751, 7291, 12697, 2841, 17965, 91707, 80361}},
+{16399, 18, 50593, {1, 1, 7, 7, 5, 23, 29, 199, 413, 501, 19, 697, 6523, 3997, 4945, 59817, 127613, 220399}},
+{16400, 18, 50611, {1, 1, 7, 5, 1, 17, 51, 9, 183, 689, 325, 2391, 2095, 1907, 10325, 51045, 20097, 33719}},
+{16401, 18, 50649, {1, 3, 5, 11, 3, 33, 45, 221, 325, 7, 253, 1323, 4959, 14067, 10035, 39463, 123171, 194581}},
+{16402, 18, 50656, {1, 1, 3, 3, 15, 45, 25, 57, 357, 907, 1249, 3279, 2631, 9209, 7857, 58233, 29049, 173859}},
+{16403, 18, 50685, {1, 3, 3, 9, 29, 39, 105, 55, 295, 583, 825, 1777, 2403, 9489, 9079, 24855, 18155, 252733}},
+{16404, 18, 50686, {1, 1, 5, 15, 5, 63, 77, 215, 287, 743, 1937, 2103, 2673, 15487, 27855, 46683, 120215, 89721}},
+{16405, 18, 50692, {1, 3, 3, 5, 27, 1, 45, 19, 309, 679, 1405, 415, 6107, 13567, 5803, 61941, 130285, 51847}},
+{16406, 18, 50702, {1, 3, 1, 15, 23, 49, 47, 113, 401, 825, 1299, 2711, 6509, 12225, 16147, 20615, 121305, 121937}},
+{16407, 18, 50704, {1, 3, 5, 5, 31, 41, 31, 57, 385, 919, 593, 1371, 6773, 12099, 23767, 17663, 128321, 188921}},
+{16408, 18, 50709, {1, 1, 3, 15, 5, 41, 17, 7, 479, 143, 549, 1827, 8107, 14775, 28817, 12297, 119893, 191297}},
+{16409, 18, 50720, {1, 3, 7, 5, 29, 61, 27, 123, 269, 223, 121, 1745, 3513, 1989, 9759, 8129, 78933, 40085}},
+{16410, 18, 50726, {1, 1, 5, 13, 23, 49, 125, 225, 479, 123, 41, 2359, 4443, 4729, 31717, 3139, 3869, 118803}},
+{16411, 18, 50729, {1, 3, 3, 3, 15, 7, 7, 87, 415, 95, 1799, 2009, 4711, 15635, 21997, 47201, 16815, 99815}},
+{16412, 18, 50737, {1, 3, 3, 1, 31, 57, 73, 31, 423, 363, 1469, 2411, 6449, 15275, 14189, 51079, 130201, 130181}},
+{16413, 18, 50758, {1, 1, 5, 3, 3, 31, 107, 11, 355, 647, 1463, 3019, 3263, 13727, 10461, 26577, 4439, 132737}},
+{16414, 18, 50772, {1, 1, 1, 7, 13, 55, 31, 227, 71, 563, 1467, 3733, 725, 3443, 19279, 4111, 35749, 62275}},
+{16415, 18, 50849, {1, 3, 3, 15, 9, 17, 61, 95, 43, 583, 1381, 1285, 2655, 9213, 27551, 16237, 29569, 216879}},
+{16416, 18, 50850, {1, 1, 1, 3, 29, 3, 87, 193, 53, 599, 1581, 907, 4381, 8697, 27299, 40259, 122653, 43559}},
+{16417, 18, 50881, {1, 3, 5, 3, 15, 49, 21, 27, 35, 353, 1281, 3253, 7339, 9333, 25253, 35035, 30379, 87387}},
+{16418, 18, 50901, {1, 1, 1, 15, 7, 27, 69, 41, 45, 729, 1005, 3495, 1445, 7421, 27443, 29609, 70105, 93883}},
+{16419, 18, 50906, {1, 1, 7, 7, 1, 41, 15, 149, 107, 121, 639, 3703, 3397, 1727, 14165, 2845, 78531, 175767}},
+{16420, 18, 50915, {1, 3, 7, 15, 27, 17, 121, 175, 399, 551, 1889, 2283, 4343, 3633, 653, 3267, 101901, 162157}},
+{16421, 18, 50961, {1, 3, 3, 15, 23, 41, 97, 251, 435, 955, 69, 509, 8001, 11783, 7397, 7587, 127089, 15391}},
+{16422, 18, 50992, {1, 3, 5, 5, 25, 25, 63, 25, 203, 655, 2039, 2545, 5405, 1377, 30543, 65531, 122825, 6853}},
+{16423, 18, 50997, {1, 1, 7, 9, 9, 43, 73, 195, 465, 497, 1085, 3821, 7115, 7513, 21913, 32499, 96467, 181905}},
+{16424, 18, 51001, {1, 1, 3, 7, 29, 29, 63, 131, 409, 423, 687, 2549, 7367, 6867, 2685, 29137, 61845, 194409}},
+{16425, 18, 51004, {1, 3, 7, 7, 3, 23, 47, 31, 121, 629, 1771, 2387, 861, 2269, 29565, 19599, 18051, 121531}},
+{16426, 18, 51033, {1, 1, 1, 3, 21, 13, 109, 105, 163, 433, 521, 3467, 6225, 3705, 30605, 3265, 119313, 2535}},
+{16427, 18, 51045, {1, 3, 5, 3, 25, 25, 89, 177, 415, 67, 361, 3317, 6411, 4857, 23249, 41959, 59931, 35797}},
+{16428, 18, 51052, {1, 3, 7, 15, 5, 37, 37, 65, 71, 13, 1621, 2217, 3723, 2113, 23755, 46521, 48091, 44307}},
+{16429, 18, 51064, {1, 1, 5, 13, 5, 5, 63, 75, 61, 443, 1663, 3239, 7717, 2623, 5723, 42673, 8519, 58773}},
+{16430, 18, 51085, {1, 1, 3, 1, 29, 13, 35, 61, 391, 517, 1007, 17, 2519, 7121, 20095, 33449, 21397, 103787}},
+{16431, 18, 51127, {1, 1, 5, 1, 9, 45, 49, 151, 39, 347, 1821, 2687, 1551, 12117, 29429, 40963, 77795, 20941}},
+{16432, 18, 51139, {1, 1, 5, 3, 13, 49, 107, 105, 201, 601, 1335, 2389, 6837, 11123, 22985, 62705, 59057, 128333}},
+{16433, 18, 51153, {1, 3, 3, 13, 5, 3, 21, 103, 481, 621, 2037, 2963, 425, 4685, 27475, 24363, 116419, 171743}},
+{16434, 18, 51181, {1, 3, 3, 5, 27, 27, 5, 91, 245, 421, 795, 1869, 6455, 4463, 23467, 24039, 69681, 262127}},
+{16435, 18, 51182, {1, 3, 1, 11, 11, 5, 31, 253, 469, 593, 877, 2041, 4615, 1541, 11823, 58525, 128689, 95985}},
+{16436, 18, 51194, {1, 3, 5, 13, 31, 35, 115, 73, 97, 213, 1499, 1371, 4239, 7897, 3987, 4833, 115043, 222743}},
+{16437, 18, 51196, {1, 3, 3, 5, 31, 15, 17, 233, 137, 521, 1721, 1913, 1881, 13457, 10733, 61527, 19825, 192601}},
+{16438, 18, 51200, {1, 3, 1, 3, 11, 21, 81, 77, 377, 915, 321, 3925, 867, 5491, 4707, 37307, 52141, 29155}},
+{16439, 18, 51239, {1, 1, 5, 1, 13, 51, 97, 161, 295, 159, 1717, 3817, 4687, 1907, 2655, 60577, 73867, 161851}},
+{16440, 18, 51240, {1, 1, 3, 13, 21, 31, 33, 145, 375, 377, 1429, 1981, 4851, 9047, 2685, 49037, 67399, 124243}},
+{16441, 18, 51254, {1, 1, 7, 13, 1, 55, 65, 147, 471, 277, 1585, 3949, 1885, 1635, 15687, 46367, 120931, 192097}},
+{16442, 18, 51260, {1, 1, 7, 9, 13, 27, 33, 41, 377, 863, 1297, 181, 2685, 11285, 3961, 63201, 59757, 70231}},
+{16443, 18, 51342, {1, 1, 3, 15, 29, 3, 79, 25, 147, 683, 1563, 805, 5891, 3355, 20113, 48261, 38195, 14589}},
+{16444, 18, 51370, {1, 1, 7, 11, 9, 15, 21, 33, 47, 923, 1291, 4001, 203, 305, 21575, 41915, 74769, 114921}},
+{16445, 18, 51372, {1, 3, 7, 11, 15, 1, 75, 173, 473, 493, 291, 811, 931, 10731, 9855, 57891, 81575, 250565}},
+{16446, 18, 51377, {1, 3, 3, 3, 31, 31, 71, 141, 389, 661, 71, 3245, 6827, 9219, 26607, 50511, 94783, 130785}},
+{16447, 18, 51398, {1, 1, 7, 3, 9, 15, 67, 141, 293, 779, 3, 3311, 7063, 13709, 29715, 55227, 11043, 150343}},
+{16448, 18, 51402, {1, 3, 3, 3, 21, 9, 45, 111, 207, 715, 345, 1345, 3079, 3851, 23709, 33919, 108213, 25353}},
+{16449, 18, 51407, {1, 3, 5, 13, 7, 3, 35, 95, 397, 397, 1159, 2759, 5233, 16237, 12469, 29543, 39133, 64429}},
+{16450, 18, 51410, {1, 1, 5, 13, 19, 35, 9, 7, 153, 843, 2025, 1379, 3361, 15889, 7411, 26399, 106295, 19851}},
+{16451, 18, 51412, {1, 3, 1, 1, 21, 15, 71, 143, 279, 431, 487, 967, 4445, 11969, 16671, 48891, 59605, 230607}},
+{16452, 18, 51419, {1, 3, 5, 1, 25, 63, 23, 143, 221, 805, 377, 1441, 1971, 1985, 10055, 35991, 115873, 223455}},
+{16453, 18, 51428, {1, 3, 1, 7, 21, 57, 1, 185, 117, 75, 1623, 3805, 2385, 10245, 29009, 59149, 130219, 114763}},
+{16454, 18, 51431, {1, 3, 1, 13, 19, 13, 105, 241, 47, 597, 1725, 2579, 3785, 1667, 12427, 62623, 60883, 189977}},
+{16455, 18, 51460, {1, 3, 5, 13, 1, 55, 59, 133, 263, 415, 1013, 139, 3037, 13661, 15303, 27279, 84095, 184807}},
+{16456, 18, 51475, {1, 3, 1, 11, 7, 45, 3, 179, 315, 639, 875, 3299, 5221, 8463, 17507, 59673, 73865, 98867}},
+{16457, 18, 51477, {1, 3, 7, 7, 3, 3, 53, 233, 219, 519, 585, 3029, 3623, 9559, 2251, 43735, 121513, 208007}},
+{16458, 18, 51478, {1, 3, 1, 3, 17, 47, 47, 145, 445, 541, 163, 2653, 165, 7213, 3311, 57335, 43967, 191841}},
+{16459, 18, 51482, {1, 3, 5, 5, 7, 47, 39, 119, 13, 727, 887, 3743, 3807, 15267, 3977, 52833, 14851, 61851}},
+{16460, 18, 51511, {1, 1, 3, 5, 9, 9, 107, 119, 501, 723, 1965, 3093, 6947, 1783, 11287, 24243, 14005, 106677}},
+{16461, 18, 51518, {1, 3, 3, 11, 11, 29, 85, 243, 359, 195, 221, 1767, 6969, 15275, 20853, 26921, 40903, 29849}},
+{16462, 18, 51568, {1, 3, 1, 5, 31, 3, 11, 247, 371, 339, 1263, 119, 791, 7425, 18879, 11333, 34359, 178929}},
+{16463, 18, 51607, {1, 1, 3, 7, 23, 15, 121, 203, 441, 499, 779, 1971, 339, 8737, 6859, 32417, 97073, 256143}},
+{16464, 18, 51618, {1, 1, 5, 11, 3, 23, 25, 51, 407, 677, 97, 281, 427, 3671, 7939, 54485, 3967, 210199}},
+{16465, 18, 51630, {1, 1, 5, 9, 5, 45, 23, 171, 255, 967, 313, 3881, 6039, 10545, 3591, 51985, 37145, 99291}},
+{16466, 18, 51655, {1, 1, 5, 7, 3, 13, 55, 147, 83, 369, 1707, 1919, 491, 11507, 29559, 29169, 65897, 80587}},
+{16467, 18, 51673, {1, 1, 3, 13, 31, 41, 41, 237, 245, 109, 969, 1797, 8169, 6351, 3657, 9655, 109201, 245117}},
+{16468, 18, 51683, {1, 3, 7, 5, 17, 23, 17, 219, 473, 1, 865, 1949, 7589, 10107, 3035, 19903, 79579, 138695}},
+{16469, 18, 51709, {1, 3, 1, 15, 13, 57, 109, 117, 277, 773, 31, 3807, 7615, 2453, 22655, 51513, 108367, 248473}},
+{16470, 18, 51716, {1, 1, 7, 11, 17, 59, 27, 167, 63, 931, 13, 3721, 1789, 7621, 31093, 27541, 37283, 35193}},
+{16471, 18, 51774, {1, 3, 3, 11, 13, 9, 7, 85, 45, 151, 1865, 4049, 4433, 9517, 231, 30733, 93701, 126585}},
+{16472, 18, 51829, {1, 3, 1, 13, 21, 33, 19, 87, 77, 425, 351, 1163, 7453, 12567, 24615, 35563, 127643, 28625}},
+{16473, 18, 51830, {1, 1, 3, 11, 7, 35, 27, 47, 465, 595, 985, 573, 2541, 7841, 14749, 43761, 26699, 135895}},
+{16474, 18, 51839, {1, 1, 1, 7, 25, 51, 93, 237, 355, 575, 1, 443, 5697, 1997, 28801, 11621, 62531, 88449}},
+{16475, 18, 51849, {1, 1, 1, 9, 23, 35, 23, 91, 161, 601, 1401, 2187, 6283, 10711, 21277, 47771, 12589, 176625}},
+{16476, 18, 51869, {1, 3, 3, 5, 13, 23, 33, 65, 213, 835, 539, 2487, 273, 6113, 18327, 52493, 17571, 160909}},
+{16477, 18, 51886, {1, 3, 1, 5, 25, 9, 117, 201, 457, 331, 1455, 439, 4891, 5515, 21701, 9343, 29085, 120299}},
+{16478, 18, 51905, {1, 1, 1, 5, 29, 7, 43, 125, 155, 43, 1949, 2901, 7293, 13683, 18289, 16873, 27899, 168631}},
+{16479, 18, 51906, {1, 1, 7, 3, 29, 33, 53, 137, 301, 27, 1101, 837, 5843, 13167, 6073, 49083, 120031, 45065}},
+{16480, 18, 51915, {1, 3, 5, 1, 31, 47, 127, 185, 279, 603, 1699, 1693, 3263, 9055, 3525, 46065, 79305, 19949}},
+{16481, 18, 51948, {1, 3, 7, 9, 17, 47, 25, 191, 369, 877, 1477, 3041, 5123, 1393, 5061, 1755, 61051, 55299}},
+{16482, 18, 51988, {1, 1, 5, 13, 13, 7, 89, 141, 251, 321, 1515, 2677, 5103, 12901, 29875, 165, 15073, 47795}},
+{16483, 18, 51998, {1, 3, 1, 7, 1, 37, 55, 173, 191, 981, 685, 4003, 6319, 3037, 30637, 11955, 81015, 89239}},
+{16484, 18, 52004, {1, 3, 5, 5, 1, 5, 55, 251, 229, 153, 425, 2793, 6779, 15797, 10087, 7573, 121789, 115479}},
+{16485, 18, 52026, {1, 3, 7, 13, 23, 39, 23, 21, 55, 543, 1539, 3055, 7825, 2865, 8967, 56719, 117219, 142137}},
+{16486, 18, 52036, {1, 1, 5, 13, 1, 29, 81, 11, 509, 61, 1681, 1911, 829, 10583, 7105, 42047, 128579, 48891}},
+{16487, 18, 52082, {1, 1, 3, 13, 7, 27, 81, 89, 129, 239, 309, 1353, 5265, 12255, 29391, 1659, 114857, 43551}},
+{16488, 18, 52127, {1, 1, 7, 13, 23, 15, 9, 93, 35, 839, 549, 1793, 4693, 13295, 10603, 18179, 33141, 239555}},
+{16489, 18, 52145, {1, 3, 1, 7, 17, 5, 11, 193, 143, 579, 1199, 1239, 4503, 15855, 23345, 34789, 59427, 235319}},
+{16490, 18, 52157, {1, 3, 5, 3, 25, 63, 11, 203, 415, 135, 261, 1843, 3409, 4605, 15213, 28537, 75787, 100007}},
+{16491, 18, 52165, {1, 1, 1, 5, 3, 37, 29, 157, 213, 235, 959, 1087, 2843, 10265, 28233, 14281, 25867, 204031}},
+{16492, 18, 52193, {1, 3, 3, 7, 19, 49, 55, 111, 253, 823, 533, 941, 2509, 5595, 9267, 28457, 84301, 165385}},
+{16493, 18, 52211, {1, 3, 5, 9, 5, 59, 13, 85, 339, 889, 597, 3517, 7001, 5525, 25451, 13855, 19033, 182677}},
+{16494, 18, 52213, {1, 3, 1, 15, 23, 29, 31, 105, 353, 825, 1977, 2013, 131, 1969, 427, 16465, 90817, 257931}},
+{16495, 18, 52218, {1, 3, 1, 3, 29, 9, 109, 243, 321, 15, 1479, 787, 4667, 13925, 7347, 7977, 105585, 143959}},
+{16496, 18, 52220, {1, 1, 7, 15, 5, 45, 11, 95, 215, 719, 827, 77, 7263, 5705, 26971, 26845, 82127, 2849}},
+{16497, 18, 52238, {1, 1, 7, 9, 5, 43, 103, 133, 203, 127, 2021, 3609, 6971, 13447, 27089, 62287, 104391, 147901}},
+{16498, 18, 52240, {1, 3, 1, 3, 3, 41, 61, 101, 381, 985, 1795, 2465, 2899, 13517, 23953, 38831, 43569, 128643}},
+{16499, 18, 52243, {1, 3, 5, 5, 9, 49, 13, 7, 215, 85, 1203, 647, 6627, 1861, 17901, 40203, 13007, 84975}},
+{16500, 18, 52250, {1, 3, 5, 15, 31, 13, 55, 89, 397, 641, 1599, 3379, 3401, 4173, 5757, 42945, 59269, 106891}},
+{16501, 18, 52279, {1, 1, 5, 13, 25, 17, 45, 27, 151, 725, 819, 581, 3675, 3983, 9499, 47511, 128039, 56825}},
+{16502, 18, 52285, {1, 1, 5, 1, 7, 11, 65, 63, 301, 927, 409, 3729, 7227, 12849, 17855, 36527, 2907, 66819}},
+{16503, 18, 52306, {1, 3, 3, 3, 29, 35, 39, 1, 349, 429, 805, 3639, 3909, 4211, 10393, 36223, 72543, 136375}},
+{16504, 18, 52370, {1, 1, 1, 9, 23, 27, 25, 213, 195, 455, 883, 3357, 7277, 9061, 14103, 6005, 35031, 72703}},
+{16505, 18, 52432, {1, 1, 3, 3, 11, 17, 19, 181, 25, 775, 897, 3809, 2031, 13017, 7505, 37469, 107335, 174309}},
+{16506, 18, 52457, {1, 1, 7, 13, 7, 1, 57, 27, 159, 465, 533, 3409, 3863, 14001, 8011, 25873, 14971, 67243}},
+{16507, 18, 52466, {1, 1, 3, 11, 19, 5, 11, 19, 75, 489, 1879, 1539, 6563, 4729, 15605, 35203, 47993, 110139}},
+{16508, 18, 52514, {1, 3, 5, 9, 23, 17, 67, 89, 379, 849, 1667, 955, 1537, 11781, 9791, 46959, 79481, 237335}},
+{16509, 18, 52557, {1, 1, 7, 9, 3, 31, 127, 145, 29, 35, 463, 4009, 4427, 16215, 12093, 50085, 51259, 45091}},
+{16510, 18, 52560, {1, 1, 5, 9, 25, 3, 1, 131, 221, 951, 117, 3227, 797, 7617, 13243, 50139, 26737, 105875}},
+{16511, 18, 52585, {1, 1, 5, 3, 11, 5, 7, 155, 211, 865, 27, 3943, 7923, 9973, 23233, 37399, 89951, 106555}},
+{16512, 18, 52586, {1, 1, 3, 13, 21, 61, 77, 121, 227, 527, 1641, 3535, 3801, 7221, 6423, 9179, 114935, 33373}},
+{16513, 18, 52603, {1, 3, 7, 5, 31, 7, 123, 159, 367, 369, 1905, 1689, 6773, 675, 30289, 54149, 71469, 232835}},
+{16514, 18, 52650, {1, 1, 1, 13, 9, 23, 83, 237, 251, 941, 781, 1489, 6037, 6001, 15909, 50527, 60143, 238499}},
+{16515, 18, 52672, {1, 3, 1, 11, 5, 7, 103, 43, 413, 247, 535, 2107, 1801, 16381, 32529, 2355, 39143, 71281}},
+{16516, 18, 52681, {1, 1, 7, 5, 5, 31, 19, 11, 191, 643, 923, 1661, 2215, 11817, 23937, 62907, 128301, 21459}},
+{16517, 18, 52692, {1, 3, 7, 15, 1, 51, 123, 61, 99, 751, 1819, 1191, 3865, 8765, 7131, 33965, 55697, 87059}},
+{16518, 18, 52735, {1, 1, 5, 13, 5, 57, 41, 103, 135, 207, 517, 3995, 2537, 15705, 9123, 26193, 30653, 190549}},
+{16519, 18, 52760, {1, 1, 3, 1, 23, 5, 109, 209, 407, 143, 943, 2325, 8087, 559, 23675, 31815, 43805, 67497}},
+{16520, 18, 52772, {1, 1, 5, 9, 25, 33, 13, 21, 93, 357, 1551, 739, 5595, 16285, 30761, 54075, 75505, 177333}},
+{16521, 18, 52781, {1, 3, 5, 11, 17, 59, 31, 249, 95, 561, 1849, 4061, 5577, 2607, 30083, 59033, 56697, 89761}},
+{16522, 18, 52793, {1, 1, 3, 13, 27, 57, 9, 17, 323, 813, 1197, 2775, 3443, 9523, 24509, 12129, 89697, 169043}},
+{16523, 18, 52796, {1, 3, 5, 13, 17, 51, 91, 1, 105, 345, 829, 1365, 2755, 7197, 26655, 1303, 52223, 133893}},
+{16524, 18, 52807, {1, 1, 7, 1, 31, 3, 51, 21, 327, 851, 153, 3329, 3393, 8489, 5879, 25035, 124403, 172657}},
+{16525, 18, 52821, {1, 1, 1, 5, 3, 21, 61, 29, 99, 343, 621, 3163, 3763, 9347, 7691, 34667, 24555, 125819}},
+{16526, 18, 52849, {1, 1, 1, 1, 3, 17, 83, 191, 83, 315, 1091, 589, 5081, 4611, 15521, 25791, 9103, 13741}},
+{16527, 18, 52866, {1, 3, 5, 3, 7, 53, 9, 227, 399, 857, 673, 3027, 5045, 5573, 7467, 4813, 99659, 142845}},
+{16528, 18, 52868, {1, 1, 5, 11, 23, 37, 71, 151, 279, 879, 601, 2391, 7091, 12669, 10203, 11747, 9613, 248261}},
+{16529, 18, 52872, {1, 1, 3, 3, 29, 25, 33, 25, 1, 683, 1475, 457, 3641, 14219, 20105, 21449, 6903, 43819}},
+{16530, 18, 52875, {1, 1, 7, 7, 5, 1, 73, 79, 357, 971, 699, 1105, 1683, 1687, 32677, 62467, 47671, 88149}},
+{16531, 18, 52886, {1, 3, 1, 15, 23, 13, 93, 75, 307, 81, 1607, 1333, 6969, 7747, 27135, 58941, 26355, 5565}},
+{16532, 18, 52890, {1, 1, 7, 3, 27, 35, 85, 195, 421, 999, 1721, 2029, 283, 13995, 21649, 7519, 73357, 193171}},
+{16533, 18, 52896, {1, 3, 7, 15, 17, 63, 21, 187, 475, 671, 1681, 2731, 8169, 3327, 19789, 53295, 43219, 6949}},
+{16534, 18, 52925, {1, 1, 7, 13, 9, 33, 47, 115, 295, 123, 1293, 1627, 4261, 4503, 15925, 16521, 81759, 247089}},
+{16535, 18, 52931, {1, 3, 1, 13, 11, 15, 83, 129, 409, 465, 873, 1333, 7939, 973, 2753, 33727, 128975, 43333}},
+{16536, 18, 52937, {1, 3, 3, 3, 27, 59, 1, 137, 145, 29, 1189, 2615, 3249, 11197, 17165, 32313, 14065, 44199}},
+{16537, 18, 52938, {1, 3, 3, 11, 17, 49, 107, 111, 45, 963, 1129, 1775, 7671, 1495, 14531, 49743, 63321, 159841}},
+{16538, 18, 52952, {1, 1, 5, 9, 5, 11, 79, 99, 155, 347, 1777, 3793, 1765, 2319, 3135, 30237, 100845, 52689}},
+{16539, 18, 52979, {1, 3, 7, 13, 21, 57, 71, 207, 149, 161, 265, 991, 6967, 8905, 21581, 13921, 79201, 95667}},
+{16540, 18, 53013, {1, 3, 5, 15, 13, 53, 95, 81, 443, 161, 1071, 2749, 6637, 837, 15015, 62397, 33295, 112005}},
+{16541, 18, 53023, {1, 3, 1, 1, 31, 25, 37, 111, 79, 293, 249, 1523, 1509, 1993, 17167, 62939, 118281, 62699}},
+{16542, 18, 53027, {1, 3, 7, 7, 5, 33, 61, 179, 265, 405, 287, 1899, 437, 1609, 19617, 41093, 36341, 176593}},
+{16543, 18, 53033, {1, 1, 5, 3, 9, 33, 97, 45, 23, 807, 1575, 627, 7465, 4805, 11191, 35439, 69433, 47275}},
+{16544, 18, 53039, {1, 1, 1, 5, 1, 51, 51, 247, 453, 449, 1487, 141, 2501, 8039, 14749, 63733, 91963, 232951}},
+{16545, 18, 53041, {1, 3, 3, 13, 15, 7, 81, 211, 445, 15, 899, 835, 5163, 3403, 7367, 29963, 80413, 87209}},
+{16546, 18, 53048, {1, 3, 1, 11, 25, 43, 113, 139, 381, 391, 485, 1503, 4195, 10109, 13771, 35865, 50909, 224887}},
+{16547, 18, 53073, {1, 1, 7, 9, 9, 51, 21, 85, 137, 765, 951, 2453, 227, 9177, 1457, 47937, 84203, 118987}},
+{16548, 18, 53095, {1, 3, 5, 9, 1, 1, 21, 41, 133, 317, 519, 2249, 3453, 2957, 2029, 54737, 42515, 176017}},
+{16549, 18, 53099, {1, 3, 1, 7, 9, 27, 79, 193, 209, 281, 267, 1267, 7013, 13667, 13331, 32863, 5289, 15077}},
+{16550, 18, 53120, {1, 1, 5, 11, 29, 3, 3, 177, 75, 485, 1735, 3955, 4349, 7893, 13075, 58735, 8629, 78143}},
+{16551, 18, 53154, {1, 1, 7, 13, 3, 15, 15, 77, 7, 843, 1561, 461, 6817, 4363, 7861, 45697, 115663, 93789}},
+{16552, 18, 53168, {1, 1, 1, 7, 5, 35, 83, 213, 229, 383, 747, 337, 2589, 683, 18575, 42415, 74889, 227331}},
+{16553, 18, 53192, {1, 3, 5, 3, 17, 35, 57, 213, 247, 273, 689, 1889, 5667, 357, 4267, 11611, 20621, 159039}},
+{16554, 18, 53205, {1, 3, 3, 15, 7, 55, 25, 83, 293, 939, 1169, 2507, 3939, 7537, 2959, 40231, 124511, 181091}},
+{16555, 18, 53206, {1, 1, 5, 9, 31, 51, 67, 149, 509, 695, 449, 2761, 6597, 4741, 4205, 49177, 45599, 167807}},
+{16556, 18, 53234, {1, 1, 7, 15, 3, 7, 113, 71, 279, 885, 251, 2831, 855, 6673, 6511, 63861, 41109, 177119}},
+{16557, 18, 53246, {1, 1, 5, 3, 7, 23, 125, 11, 217, 1023, 549, 529, 3891, 10595, 13751, 37729, 113469, 110549}},
+{16558, 18, 53253, {1, 1, 3, 15, 21, 9, 13, 63, 93, 635, 659, 2837, 6303, 10083, 10107, 27859, 33891, 181229}},
+{16559, 18, 53263, {1, 1, 7, 3, 3, 43, 5, 149, 353, 353, 565, 2441, 7113, 6493, 30355, 17887, 110787, 187199}},
+{16560, 18, 53275, {1, 1, 3, 7, 19, 43, 99, 63, 169, 743, 185, 3817, 6677, 5549, 1609, 24701, 98669, 233701}},
+{16561, 18, 53313, {1, 1, 1, 1, 21, 49, 73, 169, 223, 551, 553, 917, 4705, 14951, 14031, 19753, 96205, 131755}},
+{16562, 18, 53331, {1, 1, 3, 3, 17, 49, 51, 249, 293, 921, 435, 2915, 3125, 3487, 11417, 35043, 29543, 35933}},
+{16563, 18, 53349, {1, 1, 3, 9, 23, 43, 73, 151, 379, 911, 671, 151, 955, 11885, 28795, 23967, 117135, 137985}},
+{16564, 18, 53367, {1, 1, 3, 7, 29, 3, 51, 231, 59, 227, 443, 3533, 7785, 12535, 25725, 7451, 9391, 239281}},
+{16565, 18, 53383, {1, 3, 3, 9, 17, 37, 91, 195, 5, 843, 313, 1417, 1207, 3225, 15949, 34023, 1275, 221057}},
+{16566, 18, 53392, {1, 1, 3, 15, 3, 51, 111, 135, 63, 495, 1967, 2151, 197, 10913, 20705, 1021, 68431, 67119}},
+{16567, 18, 53404, {1, 1, 5, 3, 7, 29, 87, 219, 273, 267, 1317, 797, 6723, 947, 29867, 32571, 12337, 234715}},
+{16568, 18, 53407, {1, 3, 5, 15, 1, 9, 91, 63, 97, 107, 451, 4025, 233, 7803, 17031, 7669, 49417, 256611}},
+{16569, 18, 53411, {1, 1, 7, 3, 17, 17, 45, 197, 227, 133, 799, 411, 6739, 8037, 19553, 53009, 25201, 107625}},
+{16570, 18, 53417, {1, 3, 5, 7, 3, 39, 25, 95, 197, 127, 45, 173, 3305, 6575, 19633, 54919, 35373, 59509}},
+{16571, 18, 53425, {1, 3, 3, 3, 9, 1, 107, 211, 217, 715, 311, 3641, 8055, 1, 9017, 29329, 128467, 46911}},
+{16572, 18, 53443, {1, 1, 1, 7, 1, 13, 13, 79, 259, 533, 1761, 449, 3363, 3061, 26227, 50407, 122951, 261425}},
+{16573, 18, 53469, {1, 3, 5, 5, 29, 19, 41, 7, 25, 203, 587, 3321, 655, 15877, 10423, 41481, 70325, 165527}},
+{16574, 18, 53480, {1, 3, 5, 9, 11, 45, 91, 253, 7, 137, 795, 2379, 4527, 1677, 5081, 6523, 97245, 3691}},
+{16575, 18, 53508, {1, 3, 7, 9, 25, 43, 125, 243, 391, 785, 651, 3245, 7979, 14689, 15443, 40501, 5519, 96551}},
+{16576, 18, 53535, {1, 1, 1, 3, 25, 53, 45, 159, 47, 701, 1655, 2019, 2355, 11213, 12403, 42291, 44925, 72689}},
+{16577, 18, 53536, {1, 1, 1, 5, 21, 19, 77, 31, 3, 161, 149, 3759, 6331, 12311, 7021, 1117, 12459, 134821}},
+{16578, 18, 53542, {1, 1, 3, 9, 9, 59, 23, 255, 437, 625, 719, 3727, 7157, 1889, 31523, 59127, 114143, 174179}},
+{16579, 18, 53563, {1, 1, 1, 15, 23, 7, 47, 137, 77, 519, 1681, 1159, 6121, 14789, 21343, 43101, 44709, 179863}},
+{16580, 18, 53577, {1, 3, 1, 3, 17, 27, 103, 11, 327, 735, 1949, 3719, 811, 2267, 13187, 29747, 98433, 242021}},
+{16581, 18, 53591, {1, 1, 7, 15, 15, 63, 25, 203, 109, 585, 409, 4093, 6669, 2381, 30721, 58975, 17235, 257959}},
+{16582, 18, 53607, {1, 3, 3, 5, 5, 19, 27, 69, 69, 193, 693, 1169, 6321, 3425, 9285, 28019, 128343, 185165}},
+{16583, 18, 53626, {1, 1, 3, 9, 7, 51, 113, 93, 81, 385, 1811, 2601, 2065, 1029, 24515, 7199, 26425, 174283}},
+{16584, 18, 53628, {1, 1, 1, 5, 29, 55, 93, 219, 281, 887, 891, 2763, 6083, 9627, 18559, 21329, 73887, 83699}},
+{16585, 18, 53638, {1, 1, 1, 3, 21, 31, 49, 173, 15, 177, 1001, 3453, 5623, 14107, 8837, 10163, 26817, 41947}},
+{16586, 18, 53675, {1, 1, 3, 5, 27, 63, 117, 49, 405, 281, 981, 2363, 1525, 9685, 29089, 16739, 66509, 125823}},
+{16587, 18, 53685, {1, 3, 7, 13, 27, 29, 57, 189, 345, 135, 753, 463, 731, 4823, 14335, 33299, 105229, 54705}},
+{16588, 18, 53692, {1, 3, 1, 1, 9, 43, 51, 25, 371, 261, 1409, 3493, 2811, 12915, 16075, 62159, 125945, 108453}},
+{16589, 18, 53703, {1, 3, 7, 15, 13, 33, 47, 53, 263, 669, 1383, 3059, 4043, 4777, 14679, 2077, 11019, 5803}},
+{16590, 18, 53722, {1, 1, 3, 11, 21, 7, 39, 71, 215, 79, 1849, 1261, 45, 1273, 27591, 4653, 25119, 30445}},
+{16591, 18, 53738, {1, 3, 5, 9, 21, 3, 17, 207, 417, 777, 37, 3349, 2761, 4469, 3457, 15593, 87251, 38601}},
+{16592, 18, 53748, {1, 1, 7, 13, 29, 29, 101, 103, 487, 87, 1129, 2497, 5501, 4813, 8623, 25077, 50487, 94053}},
+{16593, 18, 53752, {1, 3, 3, 11, 7, 23, 95, 245, 127, 55, 431, 2707, 4955, 15871, 29589, 60023, 1921, 227623}},
+{16594, 18, 53764, {1, 1, 3, 11, 17, 61, 103, 59, 477, 99, 1203, 157, 203, 557, 22921, 47363, 12853, 144067}},
+{16595, 18, 53781, {1, 3, 1, 13, 15, 23, 51, 109, 499, 841, 1779, 2515, 2519, 4945, 20061, 12395, 9223, 157901}},
+{16596, 18, 53788, {1, 3, 7, 9, 9, 15, 57, 223, 223, 463, 427, 2145, 1219, 12639, 28361, 46019, 128101, 198479}},
+{16597, 18, 53791, {1, 3, 7, 7, 1, 1, 99, 101, 135, 169, 1885, 3979, 3051, 13649, 26607, 45067, 4503, 74087}},
+{16598, 18, 53816, {1, 3, 7, 5, 17, 63, 27, 45, 447, 759, 1099, 3407, 489, 2719, 31577, 10355, 126835, 203439}},
+{16599, 18, 53824, {1, 1, 5, 1, 21, 19, 1, 239, 433, 531, 1181, 2021, 423, 3235, 8457, 44459, 117401, 63545}},
+{16600, 18, 53830, {1, 3, 7, 13, 21, 39, 25, 65, 405, 785, 137, 2899, 3255, 11165, 7827, 46425, 89063, 102787}},
+{16601, 18, 53839, {1, 1, 1, 11, 25, 3, 39, 61, 395, 35, 2001, 3201, 2233, 9625, 26489, 54167, 88495, 127441}},
+{16602, 18, 53844, {1, 1, 7, 7, 3, 27, 11, 49, 117, 711, 1881, 1457, 6759, 10517, 12733, 47435, 103111, 237237}},
+{16603, 18, 53875, {1, 1, 5, 5, 1, 61, 121, 155, 223, 733, 1349, 2825, 2093, 4481, 21389, 40227, 20453, 116907}},
+{16604, 18, 53921, {1, 3, 7, 7, 5, 11, 85, 131, 345, 723, 853, 3679, 7859, 11923, 16619, 63169, 127261, 155665}},
+{16605, 18, 53922, {1, 1, 5, 1, 3, 51, 93, 225, 197, 893, 555, 2611, 6225, 7819, 31655, 12235, 24919, 31451}},
+{16606, 18, 53927, {1, 1, 3, 3, 11, 23, 95, 205, 85, 705, 545, 155, 5533, 14837, 8341, 42473, 96891, 70695}},
+{16607, 18, 53948, {1, 3, 3, 5, 17, 31, 99, 187, 219, 275, 685, 2933, 4535, 13495, 20351, 60667, 95211, 129233}},
+{16608, 18, 53956, {1, 1, 1, 11, 9, 11, 123, 231, 127, 199, 733, 2495, 2601, 10565, 3155, 45251, 128319, 187457}},
+{16609, 18, 53990, {1, 3, 1, 9, 3, 33, 41, 109, 279, 851, 1115, 3773, 2383, 1885, 6993, 59693, 69863, 88081}},
+{16610, 18, 53994, {1, 1, 7, 13, 3, 27, 27, 203, 337, 965, 959, 1125, 2897, 8653, 15827, 51187, 12121, 4665}},
+{16611, 18, 54001, {1, 3, 1, 9, 19, 7, 23, 113, 257, 671, 571, 1061, 4353, 217, 13603, 27961, 68431, 147187}},
+{16612, 18, 54016, {1, 3, 5, 9, 25, 61, 7, 139, 237, 859, 761, 2005, 5981, 153, 6553, 53005, 72653, 33571}},
+{16613, 18, 54019, {1, 3, 5, 5, 9, 35, 63, 149, 427, 65, 635, 1955, 1845, 13781, 9761, 36147, 91479, 141305}},
+{16614, 18, 54070, {1, 1, 3, 5, 13, 39, 53, 113, 481, 933, 239, 3713, 7453, 12363, 14763, 46955, 108545, 74349}},
+{16615, 18, 54074, {1, 3, 1, 7, 13, 41, 57, 225, 213, 617, 1947, 2855, 4885, 8553, 20259, 57125, 59369, 178553}},
+{16616, 18, 54088, {1, 3, 5, 15, 31, 31, 19, 87, 461, 403, 1193, 2123, 4991, 14551, 17153, 14171, 17157, 194879}},
+{16617, 18, 54102, {1, 1, 5, 11, 5, 27, 119, 65, 111, 455, 1949, 3441, 6951, 6819, 12839, 6913, 57695, 145925}},
+{16618, 18, 54111, {1, 1, 1, 15, 19, 41, 55, 45, 33, 559, 589, 3773, 745, 8515, 32389, 47797, 145, 105503}},
+{16619, 18, 54130, {1, 1, 3, 15, 13, 53, 35, 223, 247, 893, 149, 553, 829, 5129, 26417, 15769, 95411, 6595}},
+{16620, 18, 54152, {1, 1, 5, 3, 3, 59, 35, 187, 387, 3, 847, 3579, 7869, 481, 23955, 22191, 21041, 230449}},
+{16621, 18, 54170, {1, 1, 3, 15, 23, 11, 97, 199, 11, 647, 803, 2391, 5791, 2223, 22187, 49675, 87775, 196871}},
+{16622, 18, 54172, {1, 3, 7, 5, 25, 63, 107, 227, 133, 337, 1767, 2459, 2987, 10463, 25001, 17047, 79901, 222877}},
+{16623, 18, 54211, {1, 3, 1, 13, 25, 5, 47, 109, 473, 389, 1743, 3951, 4231, 827, 4189, 29903, 106909, 152835}},
+{16624, 18, 54218, {1, 1, 5, 3, 7, 61, 121, 189, 303, 21, 957, 545, 7893, 3217, 25847, 29371, 100569, 132393}},
+{16625, 18, 54228, {1, 1, 1, 15, 29, 17, 59, 37, 449, 149, 845, 555, 7603, 11911, 18477, 23279, 107167, 160339}},
+{16626, 18, 54251, {1, 1, 7, 5, 13, 27, 43, 167, 443, 445, 2011, 2179, 2785, 13663, 21957, 2455, 18217, 19303}},
+{16627, 18, 54253, {1, 1, 1, 5, 19, 45, 71, 39, 21, 791, 1467, 855, 3101, 8267, 15529, 919, 105313, 75627}},
+{16628, 18, 54268, {1, 3, 1, 11, 31, 25, 57, 177, 211, 327, 679, 771, 7725, 6123, 23931, 48223, 9063, 133319}},
+{16629, 18, 54271, {1, 3, 5, 3, 1, 11, 19, 153, 177, 563, 1919, 117, 5583, 1519, 16623, 10871, 15511, 66113}},
+{16630, 18, 54274, {1, 1, 7, 7, 9, 45, 63, 253, 415, 347, 81, 2991, 2691, 2383, 15573, 33783, 12445, 224107}},
+{16631, 18, 54288, {1, 3, 5, 5, 7, 17, 99, 231, 439, 1009, 623, 833, 685, 6419, 30313, 56197, 73239, 260007}},
+{16632, 18, 54314, {1, 1, 5, 5, 5, 51, 97, 239, 267, 629, 1211, 2175, 5681, 3107, 11381, 57047, 120175, 131285}},
+{16633, 18, 54319, {1, 1, 7, 7, 29, 11, 21, 49, 481, 279, 1795, 1295, 453, 15985, 19941, 51853, 15115, 107271}},
+{16634, 18, 54321, {1, 1, 5, 1, 23, 61, 33, 21, 409, 57, 903, 557, 1673, 2759, 23705, 4109, 58865, 233081}},
+{16635, 18, 54324, {1, 1, 1, 5, 11, 37, 79, 15, 213, 485, 1477, 3925, 3205, 9267, 22043, 54197, 57101, 66185}},
+{16636, 18, 54341, {1, 1, 7, 13, 31, 27, 95, 141, 131, 43, 2039, 2257, 17, 14427, 5699, 22263, 86851, 226283}},
+{16637, 18, 54353, {1, 3, 5, 5, 11, 5, 5, 217, 363, 163, 1241, 3683, 1409, 1731, 20973, 63849, 35041, 94859}},
+{16638, 18, 54366, {1, 1, 7, 1, 25, 61, 67, 239, 369, 319, 1157, 2435, 2147, 12057, 4451, 3005, 31787, 199653}},
+{16639, 18, 54370, {1, 3, 5, 1, 11, 57, 1, 163, 433, 11, 1299, 1711, 1601, 4677, 16481, 25175, 63893, 41853}},
+{16640, 18, 54420, {1, 1, 3, 1, 29, 49, 91, 15, 313, 533, 115, 4005, 3157, 10615, 27915, 52613, 64447, 93091}},
+{16641, 18, 54423, {1, 3, 7, 3, 7, 17, 103, 67, 237, 595, 1571, 3421, 3971, 11123, 145, 52087, 59273, 21417}},
+{16642, 18, 54434, {1, 3, 5, 11, 31, 37, 105, 205, 377, 243, 841, 3153, 6847, 14171, 19947, 61561, 35, 261753}},
+{16643, 18, 54440, {1, 3, 5, 9, 29, 21, 103, 219, 107, 427, 1841, 2015, 2919, 5721, 8631, 48841, 33281, 35835}},
+{16644, 18, 54454, {1, 1, 3, 5, 25, 27, 67, 65, 305, 677, 1975, 1049, 7277, 15279, 30181, 48941, 119087, 130265}},
+{16645, 18, 54495, {1, 1, 3, 9, 29, 27, 109, 167, 351, 463, 663, 3155, 919, 10627, 30163, 62233, 32927, 210775}},
+{16646, 18, 54501, {1, 3, 5, 5, 19, 9, 17, 93, 33, 999, 1537, 3045, 3735, 4625, 31363, 46075, 80985, 108331}},
+{16647, 18, 54526, {1, 3, 7, 7, 11, 63, 83, 157, 205, 505, 657, 1901, 1405, 8349, 16473, 29397, 130379, 167963}},
+{16648, 18, 54639, {1, 3, 1, 15, 25, 49, 65, 189, 461, 923, 1839, 2597, 2471, 14103, 2915, 48429, 74387, 243465}},
+{16649, 18, 54653, {1, 3, 7, 11, 31, 47, 109, 21, 205, 343, 1999, 315, 8119, 15937, 8761, 55257, 99983, 131641}},
+{16650, 18, 54667, {1, 1, 3, 11, 3, 23, 73, 125, 17, 967, 1811, 1413, 4783, 8303, 25301, 26859, 90583, 140721}},
+{16651, 18, 54678, {1, 1, 5, 5, 25, 41, 49, 127, 391, 381, 1575, 1697, 5205, 12805, 24365, 20275, 58819, 167845}},
+{16652, 18, 54700, {1, 1, 7, 11, 17, 53, 51, 35, 383, 931, 359, 2863, 119, 6683, 26247, 14281, 49205, 256869}},
+{16653, 18, 54717, {1, 1, 7, 9, 23, 5, 69, 97, 407, 15, 579, 2905, 47, 6227, 23997, 42459, 26569, 225467}},
+{16654, 18, 54780, {1, 3, 3, 11, 7, 3, 125, 87, 347, 79, 1571, 1513, 285, 12101, 1731, 27887, 42009, 173243}},
+{16655, 18, 54801, {1, 3, 7, 13, 3, 5, 99, 29, 77, 873, 1111, 1451, 5493, 10669, 22597, 54437, 55521, 101617}},
+{16656, 18, 54813, {1, 3, 1, 3, 3, 17, 41, 215, 207, 71, 683, 1979, 4849, 2437, 5717, 28999, 55005, 233929}},
+{16657, 18, 54814, {1, 1, 1, 1, 23, 21, 105, 223, 5, 235, 1533, 3715, 2689, 13937, 12125, 63879, 111537, 39817}},
+{16658, 18, 54850, {1, 3, 3, 15, 25, 47, 71, 229, 21, 563, 1851, 2423, 131, 4431, 31567, 8883, 1311, 227893}},
+{16659, 18, 54883, {1, 3, 5, 11, 7, 23, 19, 59, 397, 315, 1149, 3595, 5973, 11027, 5233, 55237, 102777, 137421}},
+{16660, 18, 54907, {1, 1, 7, 9, 17, 61, 45, 235, 387, 171, 1079, 3119, 6933, 3591, 751, 35495, 49969, 204611}},
+{16661, 18, 54919, {1, 1, 7, 7, 21, 7, 105, 79, 81, 245, 1229, 409, 5159, 9815, 6713, 4687, 120541, 246133}},
+{16662, 18, 54931, {1, 3, 7, 13, 23, 31, 85, 97, 481, 497, 581, 1179, 243, 1767, 11855, 11599, 3141, 104741}},
+{16663, 18, 54933, {1, 3, 7, 3, 3, 45, 15, 29, 413, 631, 273, 1007, 2979, 11307, 24535, 9305, 83591, 77121}},
+{16664, 18, 54991, {1, 3, 7, 15, 21, 55, 11, 169, 417, 631, 141, 1489, 3371, 16073, 11215, 15479, 125341, 131731}},
+{16665, 18, 55003, {1, 1, 7, 5, 13, 33, 7, 121, 295, 191, 497, 2233, 997, 13833, 14503, 38357, 79007, 53985}},
+{16666, 18, 55009, {1, 3, 3, 3, 29, 63, 97, 27, 449, 643, 317, 1989, 1481, 2873, 21247, 35989, 61295, 101829}},
+{16667, 18, 55030, {1, 3, 1, 7, 13, 49, 27, 227, 21, 983, 179, 2761, 2859, 2851, 26447, 33295, 126963, 41441}},
+{16668, 18, 55034, {1, 1, 5, 13, 27, 1, 61, 115, 185, 867, 2017, 2257, 5035, 7855, 25849, 48189, 28287, 133261}},
+{16669, 18, 55039, {1, 1, 7, 13, 27, 17, 13, 205, 379, 717, 247, 3341, 2841, 10845, 26979, 5589, 1935, 48371}},
+{16670, 18, 55048, {1, 3, 1, 11, 9, 51, 25, 185, 65, 643, 1867, 3825, 3395, 8883, 29239, 20019, 19071, 3377}},
+{16671, 18, 55059, {1, 1, 1, 1, 11, 57, 61, 113, 419, 249, 153, 2883, 87, 7919, 11941, 46725, 38701, 73715}},
+{16672, 18, 55061, {1, 3, 3, 11, 3, 15, 19, 87, 27, 839, 463, 1757, 3137, 10821, 2857, 58101, 91983, 137045}},
+{16673, 18, 55068, {1, 3, 3, 1, 25, 25, 15, 93, 359, 5, 53, 647, 6245, 1957, 4651, 14697, 12193, 231303}},
+{16674, 18, 55077, {1, 1, 5, 9, 31, 49, 69, 223, 133, 595, 777, 1281, 727, 6671, 21453, 14193, 51769, 258301}},
+{16675, 18, 55122, {1, 3, 5, 11, 29, 37, 75, 17, 229, 121, 313, 2873, 5233, 13231, 7589, 40075, 42101, 137697}},
+{16676, 18, 55149, {1, 1, 7, 1, 31, 9, 15, 63, 149, 5, 1785, 21, 2619, 15071, 3243, 58023, 20697, 205181}},
+{16677, 18, 55157, {1, 3, 7, 7, 25, 61, 59, 157, 251, 303, 1905, 2389, 1681, 319, 14155, 49089, 45381, 124447}},
+{16678, 18, 55158, {1, 3, 5, 5, 25, 27, 41, 125, 105, 867, 365, 117, 7215, 2887, 28499, 9597, 105999, 150189}},
+{16679, 18, 55178, {1, 1, 5, 13, 5, 33, 47, 221, 207, 641, 525, 3215, 5293, 16343, 16169, 44393, 26305, 194411}},
+{16680, 18, 55222, {1, 3, 5, 13, 29, 17, 31, 77, 511, 465, 1141, 597, 5111, 6629, 14557, 13057, 11643, 250925}},
+{16681, 18, 55234, {1, 1, 7, 11, 1, 5, 65, 139, 471, 265, 1145, 965, 47, 10971, 15615, 62031, 58523, 175593}},
+{16682, 18, 55236, {1, 1, 5, 1, 23, 61, 57, 139, 377, 843, 79, 2873, 1823, 7551, 26741, 63031, 124879, 115295}},
+{16683, 18, 55251, {1, 1, 5, 13, 9, 19, 1, 61, 331, 1015, 1035, 1691, 4057, 6071, 24929, 39569, 95695, 39307}},
+{16684, 18, 55269, {1, 3, 3, 5, 23, 17, 13, 65, 381, 893, 1879, 3735, 1547, 6735, 30251, 11471, 102997, 126429}},
+{16685, 18, 55270, {1, 1, 5, 13, 1, 43, 15, 1, 155, 221, 1463, 3793, 6467, 7221, 28027, 55357, 69397, 87565}},
+{16686, 18, 55284, {1, 1, 7, 3, 17, 9, 71, 75, 77, 639, 1251, 701, 473, 12337, 1893, 6349, 10837, 27797}},
+{16687, 18, 55309, {1, 3, 5, 11, 11, 11, 125, 23, 161, 937, 707, 2487, 695, 8495, 16219, 33671, 109463, 248305}},
+{16688, 18, 55322, {1, 1, 1, 11, 5, 49, 15, 47, 393, 407, 39, 1867, 7727, 12701, 7805, 119, 77401, 186421}},
+{16689, 18, 55334, {1, 1, 5, 5, 19, 21, 77, 187, 387, 51, 1497, 1225, 3101, 791, 529, 4321, 118435, 112889}},
+{16690, 18, 55340, {1, 3, 1, 13, 27, 17, 11, 63, 201, 909, 1549, 3243, 1803, 9461, 20985, 24637, 100993, 200473}},
+{16691, 18, 55348, {1, 3, 7, 13, 11, 35, 97, 213, 415, 467, 2013, 2159, 7017, 7895, 18235, 50659, 113169, 141887}},
+{16692, 18, 55377, {1, 1, 3, 7, 13, 21, 119, 109, 471, 323, 277, 1685, 2399, 14777, 2643, 5879, 113043, 45223}},
+{16693, 18, 55430, {1, 3, 1, 13, 19, 5, 1, 75, 499, 297, 1897, 591, 3223, 12939, 30593, 4053, 122207, 215171}},
+{16694, 18, 55433, {1, 3, 3, 9, 21, 11, 29, 205, 13, 381, 569, 599, 7089, 8145, 18531, 34477, 101057, 64269}},
+{16695, 18, 55441, {1, 1, 5, 15, 1, 19, 37, 131, 325, 441, 3, 4001, 6937, 9207, 27543, 30321, 37083, 241019}},
+{16696, 18, 55470, {1, 3, 7, 13, 7, 15, 9, 159, 97, 905, 557, 1913, 7325, 4057, 19461, 14277, 36873, 25619}},
+{16697, 18, 55535, {1, 3, 5, 7, 3, 51, 99, 9, 185, 227, 2041, 331, 3925, 12481, 17485, 37137, 3753, 125269}},
+{16698, 18, 55561, {1, 1, 7, 11, 31, 49, 89, 37, 49, 863, 833, 3263, 351, 6277, 23055, 49727, 25005, 161585}},
+{16699, 18, 55567, {1, 3, 5, 1, 9, 35, 89, 101, 117, 365, 1015, 1159, 4623, 4541, 6831, 28091, 10647, 221415}},
+{16700, 18, 55597, {1, 1, 5, 5, 13, 47, 125, 209, 199, 885, 927, 1411, 795, 8835, 28589, 48753, 27191, 53455}},
+{16701, 18, 55630, {1, 1, 5, 9, 7, 19, 3, 87, 157, 121, 1433, 1463, 3241, 5969, 203, 36723, 14779, 63949}},
+{16702, 18, 55648, {1, 1, 3, 9, 1, 47, 71, 113, 405, 561, 1149, 3599, 4173, 6819, 5493, 45987, 41521, 221503}},
+{16703, 18, 55653, {1, 3, 3, 1, 3, 55, 101, 103, 161, 549, 457, 2529, 2043, 8843, 5677, 7449, 45185, 178289}},
+{16704, 18, 55657, {1, 1, 1, 3, 31, 25, 1, 161, 7, 503, 641, 2221, 749, 1521, 6151, 19245, 55913, 80141}},
+{16705, 18, 55665, {1, 1, 1, 9, 3, 45, 73, 217, 249, 929, 163, 2139, 3921, 11223, 11161, 52697, 89633, 14243}},
+{16706, 18, 55678, {1, 1, 7, 15, 17, 41, 5, 119, 211, 53, 985, 2679, 679, 9349, 25577, 26947, 35141, 93999}},
+{16707, 18, 55684, {1, 3, 1, 15, 17, 43, 51, 15, 363, 615, 889, 195, 6279, 15477, 31545, 50941, 119711, 66535}},
+{16708, 18, 55691, {1, 1, 1, 13, 7, 11, 17, 127, 131, 759, 739, 161, 5937, 13611, 31757, 10681, 101357, 82873}},
+{16709, 18, 55693, {1, 3, 5, 7, 21, 63, 75, 33, 233, 981, 589, 3409, 3523, 1871, 8919, 38513, 32825, 56935}},
+{16710, 18, 55702, {1, 3, 5, 3, 9, 9, 85, 221, 203, 727, 1035, 1069, 2409, 2687, 235, 23395, 64163, 193235}},
+{16711, 18, 55708, {1, 3, 3, 7, 1, 35, 119, 175, 203, 819, 207, 2283, 4175, 3581, 11647, 43073, 104573, 86607}},
+{16712, 18, 55715, {1, 3, 3, 15, 11, 63, 59, 153, 279, 779, 261, 3317, 7671, 11727, 19381, 33227, 79331, 187227}},
+{16713, 18, 55739, {1, 1, 3, 1, 7, 1, 115, 15, 235, 9, 1877, 1911, 1089, 9939, 9537, 39563, 95327, 70323}},
+{16714, 18, 55761, {1, 1, 5, 7, 25, 61, 63, 145, 425, 617, 1813, 3255, 6797, 16019, 18849, 44191, 69877, 179933}},
+{16715, 18, 55767, {1, 1, 3, 13, 17, 45, 69, 247, 27, 367, 871, 1185, 895, 7991, 8145, 22869, 97609, 14673}},
+{16716, 18, 55768, {1, 3, 3, 11, 19, 41, 99, 213, 159, 803, 121, 1197, 2849, 15191, 15603, 52445, 105077, 128231}},
+{16717, 18, 55774, {1, 3, 1, 11, 21, 61, 117, 167, 437, 447, 419, 1673, 755, 15331, 29819, 16099, 130773, 177547}},
+{16718, 18, 55787, {1, 3, 7, 7, 1, 15, 79, 109, 351, 71, 985, 89, 7517, 4175, 30533, 52125, 100863, 186477}},
+{16719, 18, 55811, {1, 1, 3, 1, 15, 1, 103, 65, 511, 241, 1279, 3233, 7141, 255, 10925, 28271, 56151, 252121}},
+{16720, 18, 55835, {1, 1, 1, 13, 17, 49, 59, 93, 19, 343, 979, 865, 3447, 4595, 3067, 26807, 98915, 126237}},
+{16721, 18, 55894, {1, 3, 3, 5, 17, 5, 91, 199, 191, 775, 233, 919, 277, 3485, 9231, 37025, 23493, 186745}},
+{16722, 18, 55897, {1, 3, 1, 1, 11, 5, 103, 187, 85, 47, 1111, 883, 6155, 15315, 9041, 58275, 75037, 7773}},
+{16723, 18, 55904, {1, 3, 1, 3, 19, 5, 7, 211, 481, 713, 383, 1203, 6089, 15817, 31577, 7283, 25457, 101455}},
+{16724, 18, 55931, {1, 3, 5, 7, 21, 9, 59, 127, 375, 477, 721, 3931, 7089, 9079, 5015, 62019, 113747, 36055}},
+{16725, 18, 55950, {1, 3, 7, 13, 3, 17, 47, 177, 103, 535, 1787, 509, 5253, 2857, 13421, 19875, 37397, 251353}},
+{16726, 18, 55961, {1, 1, 5, 7, 19, 31, 41, 93, 301, 45, 251, 2691, 4657, 2627, 17321, 24627, 80221, 117191}},
+{16727, 18, 55973, {1, 3, 5, 7, 5, 31, 27, 3, 463, 549, 1669, 499, 815, 4091, 7049, 60957, 102849, 235617}},
+{16728, 18, 56078, {1, 3, 5, 1, 21, 31, 57, 201, 503, 977, 893, 3927, 1605, 8265, 5137, 51009, 89375, 237909}},
+{16729, 18, 56099, {1, 3, 3, 1, 27, 5, 11, 81, 445, 229, 5, 543, 3397, 12961, 31911, 36945, 59485, 305}},
+{16730, 18, 56105, {1, 1, 5, 13, 31, 63, 39, 171, 243, 39, 1147, 459, 7215, 14603, 20625, 47369, 121495, 237741}},
+{16731, 18, 56119, {1, 3, 3, 13, 15, 63, 39, 23, 305, 685, 1885, 571, 2657, 16031, 24759, 10639, 25619, 246137}},
+{16732, 18, 56133, {1, 1, 1, 5, 19, 33, 5, 187, 167, 725, 1405, 511, 701, 13283, 3513, 16495, 8755, 221751}},
+{16733, 18, 56168, {1, 1, 7, 11, 3, 27, 27, 237, 495, 637, 479, 3247, 3825, 2567, 12853, 52881, 34807, 161483}},
+{16734, 18, 56191, {1, 3, 3, 9, 23, 43, 101, 175, 19, 443, 787, 1053, 4113, 12777, 4615, 53115, 2873, 117383}},
+{16735, 18, 56202, {1, 3, 1, 13, 3, 23, 33, 93, 145, 937, 957, 2463, 827, 383, 16749, 61567, 10029, 188159}},
+{16736, 18, 56209, {1, 1, 7, 15, 21, 23, 3, 71, 323, 995, 645, 1189, 1029, 519, 3479, 13587, 95641, 215337}},
+{16737, 18, 56215, {1, 3, 7, 11, 9, 17, 101, 59, 421, 417, 797, 3089, 773, 15959, 18127, 13681, 104667, 217433}},
+{16738, 18, 56232, {1, 3, 5, 7, 31, 21, 9, 7, 377, 589, 1497, 939, 5389, 10997, 22291, 19639, 72187, 66193}},
+{16739, 18, 56240, {1, 1, 1, 13, 19, 1, 127, 185, 251, 167, 1289, 2715, 5885, 12715, 18261, 36861, 102721, 246917}},
+{16740, 18, 56260, {1, 1, 7, 1, 23, 41, 19, 151, 125, 465, 813, 1711, 7933, 13561, 29737, 59207, 62533, 124149}},
+{16741, 18, 56270, {1, 3, 5, 9, 7, 13, 17, 119, 425, 877, 1207, 2211, 2943, 13921, 28251, 44143, 112149, 152341}},
+{16742, 18, 56278, {1, 3, 5, 9, 15, 21, 87, 83, 77, 731, 91, 3091, 5687, 9647, 2037, 39031, 106583, 66533}},
+{16743, 18, 56281, {1, 1, 7, 9, 31, 49, 7, 119, 147, 599, 1191, 297, 1597, 10723, 16893, 47387, 106995, 165409}},
+{16744, 18, 56288, {1, 3, 3, 3, 3, 63, 11, 193, 241, 63, 1671, 2139, 5689, 13967, 9239, 7535, 34237, 140283}},
+{16745, 18, 56303, {1, 3, 5, 13, 9, 23, 65, 247, 473, 825, 109, 1897, 245, 10517, 8147, 25989, 96447, 118689}},
+{16746, 18, 56308, {1, 1, 3, 5, 27, 35, 65, 23, 159, 729, 189, 2661, 4245, 14377, 21043, 15551, 2717, 146949}},
+{16747, 18, 56312, {1, 1, 3, 13, 23, 5, 35, 63, 293, 347, 883, 149, 5145, 10821, 5813, 24183, 94711, 64787}},
+{16748, 18, 56320, {1, 1, 5, 3, 27, 3, 127, 141, 237, 535, 1509, 2755, 5843, 2379, 19413, 52345, 100247, 42571}},
+{16749, 18, 56326, {1, 3, 3, 9, 1, 55, 61, 105, 29, 1021, 1215, 2157, 7453, 4643, 26793, 33553, 2959, 51485}},
+{16750, 18, 56392, {1, 1, 3, 7, 31, 51, 59, 49, 321, 207, 415, 2115, 219, 5045, 31133, 17961, 130779, 28255}},
+{16751, 18, 56395, {1, 3, 7, 15, 9, 29, 31, 185, 111, 959, 7, 827, 7891, 5449, 22221, 49933, 2091, 194683}},
+{16752, 18, 56403, {1, 3, 7, 1, 11, 59, 75, 255, 387, 913, 423, 2915, 5079, 6363, 5175, 57977, 5559, 13257}},
+{16753, 18, 56419, {1, 1, 7, 1, 21, 3, 21, 13, 157, 3, 715, 3525, 7769, 5333, 25345, 53473, 44323, 203167}},
+{16754, 18, 56428, {1, 1, 7, 11, 31, 25, 55, 5, 169, 695, 1599, 2357, 1427, 14469, 15223, 34275, 42605, 23005}},
+{16755, 18, 56450, {1, 1, 1, 15, 19, 51, 117, 135, 297, 831, 329, 3793, 4673, 3795, 24185, 52971, 30423, 68771}},
+{16756, 18, 56452, {1, 1, 7, 5, 19, 33, 79, 77, 315, 29, 307, 1709, 3489, 14515, 12477, 58939, 53753, 165031}},
+{16757, 18, 56485, {1, 1, 7, 1, 27, 57, 119, 207, 355, 279, 1371, 3917, 2821, 5285, 12673, 28973, 54957, 94001}},
+{16758, 18, 56486, {1, 3, 7, 3, 19, 57, 53, 199, 485, 805, 301, 1337, 5993, 2187, 30573, 12045, 101205, 129841}},
+{16759, 18, 56492, {1, 1, 3, 9, 15, 45, 71, 119, 445, 759, 1361, 1299, 2927, 2343, 22085, 53733, 21241, 1553}},
+{16760, 18, 56498, {1, 3, 5, 3, 27, 11, 1, 239, 497, 343, 1989, 1463, 2473, 5191, 6271, 14129, 124453, 96817}},
+{16761, 18, 56510, {1, 3, 5, 7, 27, 19, 123, 27, 483, 557, 1545, 1871, 1297, 587, 1067, 51259, 119231, 173659}},
+{16762, 18, 56512, {1, 3, 1, 1, 27, 45, 41, 113, 453, 553, 2019, 2039, 1709, 13017, 5497, 34459, 60295, 229405}},
+{16763, 18, 56524, {1, 3, 1, 11, 1, 57, 51, 125, 261, 915, 1673, 25, 529, 653, 17247, 64225, 98991, 248143}},
+{16764, 18, 56530, {1, 3, 5, 15, 25, 27, 31, 1, 463, 249, 113, 1955, 2223, 5463, 12281, 20843, 26495, 256759}},
+{16765, 18, 56545, {1, 1, 3, 11, 27, 33, 57, 205, 89, 435, 1983, 1165, 3843, 127, 30179, 63971, 10211, 105403}},
+{16766, 18, 56551, {1, 3, 3, 5, 21, 49, 35, 161, 273, 205, 41, 1881, 2013, 12549, 24859, 55711, 98235, 237281}},
+{16767, 18, 56565, {1, 3, 3, 1, 15, 35, 95, 1, 221, 675, 385, 2257, 2531, 2129, 12895, 11565, 125977, 51973}},
+{16768, 18, 56580, {1, 1, 1, 15, 19, 61, 35, 55, 9, 721, 499, 2577, 3001, 14861, 22293, 56195, 72855, 166703}},
+{16769, 18, 56587, {1, 1, 1, 7, 5, 25, 59, 175, 81, 989, 935, 2579, 8183, 1109, 4645, 53753, 115795, 105091}},
+{16770, 18, 56589, {1, 3, 3, 13, 7, 55, 7, 113, 197, 763, 1747, 3291, 1109, 4391, 18257, 28563, 97413, 5847}},
+{16771, 18, 56592, {1, 1, 1, 7, 23, 55, 91, 83, 479, 305, 843, 2055, 3405, 15243, 31551, 5275, 8651, 66915}},
+{16772, 18, 56611, {1, 3, 7, 9, 3, 19, 83, 229, 235, 903, 1495, 1033, 2729, 14927, 11847, 22979, 13905, 84413}},
+{16773, 18, 56623, {1, 3, 3, 13, 27, 37, 83, 193, 475, 439, 745, 757, 7359, 6683, 5839, 50765, 6933, 117411}},
+{16774, 18, 56635, {1, 3, 5, 11, 31, 25, 33, 77, 113, 815, 123, 2721, 2133, 8995, 15237, 54565, 5155, 51235}},
+{16775, 18, 56646, {1, 3, 3, 7, 15, 31, 73, 91, 379, 39, 913, 53, 41, 1059, 25883, 11769, 63015, 48125}},
+{16776, 18, 56660, {1, 1, 5, 5, 5, 13, 81, 169, 71, 529, 1429, 2101, 4069, 5509, 30283, 40625, 103673, 183243}},
+{16777, 18, 56680, {1, 3, 3, 5, 23, 39, 39, 237, 445, 567, 343, 2521, 2287, 1851, 2315, 59979, 5015, 243349}},
+{16778, 18, 56686, {1, 1, 7, 1, 1, 51, 89, 229, 187, 207, 245, 3521, 2987, 4347, 6997, 62565, 54397, 140473}},
+{16779, 18, 56716, {1, 3, 1, 5, 7, 59, 45, 161, 457, 655, 1591, 215, 2213, 15101, 14791, 40397, 95811, 126291}},
+{16780, 18, 56749, {1, 1, 3, 1, 5, 23, 7, 199, 143, 561, 1669, 17, 8109, 11003, 4535, 8593, 112021, 223153}},
+{16781, 18, 56790, {1, 3, 5, 9, 3, 37, 111, 15, 235, 697, 385, 2197, 909, 1247, 26199, 50661, 100643, 122577}},
+{16782, 18, 56809, {1, 3, 5, 11, 23, 53, 95, 75, 463, 137, 1511, 3373, 3071, 547, 22399, 51891, 9123, 240925}},
+{16783, 18, 56869, {1, 3, 7, 3, 21, 35, 69, 197, 371, 15, 185, 3539, 29, 15071, 17069, 34669, 37023, 189385}},
+{16784, 18, 56884, {1, 1, 1, 15, 5, 21, 7, 5, 201, 881, 841, 827, 503, 3545, 17771, 64481, 65105, 209947}},
+{16785, 18, 56887, {1, 1, 1, 5, 3, 31, 83, 201, 455, 169, 1797, 1769, 1999, 8629, 14313, 16851, 64955, 180631}},
+{16786, 18, 56893, {1, 1, 5, 5, 1, 35, 49, 61, 499, 619, 1509, 3015, 237, 8979, 3471, 11513, 80193, 24135}},
+{16787, 18, 56906, {1, 3, 3, 9, 25, 29, 111, 19, 339, 739, 1751, 2671, 5399, 5965, 3943, 45577, 70605, 203117}},
+{16788, 18, 56932, {1, 3, 3, 7, 3, 9, 15, 147, 177, 545, 161, 2211, 4653, 15891, 15939, 19153, 77827, 245787}},
+{16789, 18, 56959, {1, 1, 1, 1, 25, 47, 37, 159, 273, 825, 1037, 2047, 7149, 5517, 699, 49687, 110115, 159475}},
+{16790, 18, 56965, {1, 3, 1, 7, 7, 55, 77, 231, 197, 381, 2013, 2421, 7551, 9955, 21031, 11365, 48271, 190147}},
+{16791, 18, 56983, {1, 1, 5, 9, 25, 1, 81, 145, 215, 427, 905, 2307, 6149, 12777, 131, 57091, 106137, 24625}},
+{16792, 18, 57018, {1, 3, 1, 13, 13, 63, 103, 245, 275, 745, 841, 2993, 2083, 8903, 4499, 55979, 22323, 244447}},
+{16793, 18, 57023, {1, 1, 5, 5, 15, 11, 59, 181, 191, 219, 599, 59, 1079, 4445, 16537, 31127, 103257, 233855}},
+{16794, 18, 57025, {1, 3, 7, 9, 9, 37, 109, 41, 145, 1001, 609, 551, 6843, 13791, 15103, 27851, 7693, 145207}},
+{16795, 18, 57032, {1, 3, 1, 9, 3, 35, 63, 219, 49, 567, 1537, 1327, 6487, 16039, 26019, 13851, 116929, 175121}},
+{16796, 18, 57040, {1, 3, 7, 15, 17, 31, 27, 91, 241, 229, 485, 2601, 3859, 12609, 19847, 31939, 50815, 235529}},
+{16797, 18, 57046, {1, 1, 5, 15, 27, 31, 3, 47, 69, 427, 95, 1445, 1223, 2953, 32343, 6841, 67851, 79561}},
+{16798, 18, 57071, {1, 3, 5, 13, 13, 37, 19, 127, 259, 139, 1597, 651, 4845, 6413, 18205, 56005, 32107, 140783}},
+{16799, 18, 57091, {1, 1, 7, 5, 15, 23, 81, 195, 127, 113, 499, 733, 5907, 12107, 18105, 28113, 16111, 152327}},
+{16800, 18, 57094, {1, 1, 5, 15, 9, 49, 109, 181, 187, 591, 1625, 3641, 313, 1225, 11725, 9047, 30351, 124301}},
+{16801, 18, 57108, {1, 3, 1, 1, 9, 45, 103, 219, 155, 805, 1775, 759, 1687, 11415, 21623, 37831, 18995, 21667}},
+{16802, 18, 57122, {1, 3, 3, 5, 25, 13, 11, 37, 489, 935, 373, 811, 5045, 3615, 2111, 22909, 117155, 69483}},
+{16803, 18, 57127, {1, 3, 3, 5, 9, 45, 71, 87, 265, 93, 161, 2983, 1023, 3633, 5965, 9499, 35653, 219257}},
+{16804, 18, 57168, {1, 1, 5, 13, 21, 27, 101, 231, 85, 469, 1023, 3735, 5093, 253, 22585, 61975, 81041, 4175}},
+{16805, 18, 57183, {1, 3, 1, 7, 5, 41, 105, 153, 391, 5, 1917, 331, 7679, 14359, 13177, 40755, 78669, 133527}},
+{16806, 18, 57184, {1, 3, 3, 15, 21, 61, 87, 63, 227, 195, 1095, 1629, 7787, 5887, 20855, 30203, 61973, 30627}},
+{16807, 18, 57193, {1, 3, 1, 15, 31, 41, 125, 223, 201, 717, 1309, 595, 5333, 10585, 32525, 8597, 92637, 111073}},
+{16808, 18, 57202, {1, 3, 5, 3, 21, 29, 39, 105, 275, 515, 503, 79, 6715, 14203, 14035, 20871, 122417, 243167}},
+{16809, 18, 57235, {1, 3, 7, 5, 29, 41, 3, 89, 165, 879, 773, 3989, 3945, 4771, 2809, 59105, 37177, 193887}},
+{16810, 18, 57237, {1, 3, 3, 3, 27, 1, 91, 191, 135, 257, 527, 2971, 7117, 6013, 8735, 52363, 110617, 96959}},
+{16811, 18, 57251, {1, 3, 7, 9, 3, 63, 67, 67, 231, 23, 1539, 771, 1485, 4331, 19231, 50539, 15081, 75945}},
+{16812, 18, 57289, {1, 3, 3, 11, 29, 11, 77, 67, 497, 861, 21, 2939, 2463, 14435, 27399, 19733, 118207, 60909}},
+{16813, 18, 57349, {1, 1, 5, 5, 1, 11, 117, 55, 485, 877, 1213, 2231, 2613, 14027, 18491, 45431, 113303, 28457}},
+{16814, 18, 57359, {1, 3, 7, 1, 13, 49, 77, 59, 455, 251, 1033, 3451, 7641, 389, 3987, 62361, 90125, 94569}},
+{16815, 18, 57374, {1, 1, 7, 15, 3, 5, 45, 173, 343, 445, 1871, 2505, 1385, 2641, 21299, 35139, 61781, 101195}},
+{16816, 18, 57377, {1, 3, 1, 9, 25, 27, 89, 123, 473, 901, 1513, 2585, 5641, 13123, 22653, 32985, 15763, 9161}},
+{16817, 18, 57387, {1, 3, 3, 9, 29, 41, 5, 127, 489, 715, 1981, 3953, 3557, 10081, 31913, 52191, 118727, 4443}},
+{16818, 18, 57415, {1, 1, 5, 1, 19, 57, 125, 33, 253, 297, 265, 2249, 6859, 14971, 3519, 24783, 127491, 210441}},
+{16819, 18, 57440, {1, 1, 7, 7, 31, 1, 47, 175, 305, 933, 679, 317, 7511, 13219, 9509, 61183, 58907, 72905}},
+{16820, 18, 57446, {1, 1, 1, 7, 13, 49, 75, 85, 341, 911, 1217, 3631, 1849, 9715, 23193, 947, 106647, 180455}},
+{16821, 18, 57450, {1, 1, 7, 7, 1, 49, 91, 195, 329, 771, 607, 1707, 2723, 291, 21393, 6549, 31645, 151431}},
+{16822, 18, 57469, {1, 3, 7, 5, 17, 57, 7, 231, 247, 217, 1729, 3231, 7515, 15341, 18681, 21733, 28723, 228187}},
+{16823, 18, 57491, {1, 1, 5, 9, 5, 19, 121, 251, 43, 951, 957, 173, 4863, 5027, 6781, 29421, 4877, 47749}},
+{16824, 18, 57503, {1, 3, 7, 7, 11, 33, 107, 233, 329, 589, 869, 913, 7687, 13223, 27577, 24379, 13037, 214713}},
+{16825, 18, 57507, {1, 3, 7, 13, 1, 13, 121, 103, 387, 193, 543, 3085, 4323, 9885, 24499, 34985, 45763, 13107}},
+{16826, 18, 57542, {1, 1, 3, 15, 25, 63, 85, 41, 457, 779, 1199, 2235, 309, 2549, 3341, 36265, 17873, 32361}},
+{16827, 18, 57569, {1, 3, 3, 3, 15, 31, 11, 57, 499, 415, 1625, 1195, 6863, 6073, 25083, 57705, 76203, 130993}},
+{16828, 18, 57599, {1, 3, 5, 5, 21, 13, 43, 161, 255, 31, 1901, 3325, 3209, 9809, 8227, 9005, 57263, 95095}},
+{16829, 18, 57601, {1, 1, 3, 15, 13, 33, 5, 123, 291, 579, 1747, 3319, 7351, 1679, 11365, 26909, 74445, 139017}},
+{16830, 18, 57607, {1, 1, 3, 13, 17, 39, 1, 253, 487, 935, 1711, 1397, 503, 7817, 28509, 20665, 78551, 204319}},
+{16831, 18, 57608, {1, 1, 3, 1, 5, 39, 123, 105, 305, 77, 63, 3285, 7463, 11199, 647, 37757, 91083, 108325}},
+{16832, 18, 57625, {1, 1, 7, 5, 9, 49, 121, 155, 389, 119, 1327, 3583, 7715, 2705, 20047, 19151, 101455, 205263}},
+{16833, 18, 57644, {1, 1, 5, 7, 31, 23, 13, 109, 103, 41, 433, 3609, 4973, 11481, 8381, 4725, 113633, 134651}},
+{16834, 18, 57662, {1, 3, 7, 7, 25, 25, 107, 189, 89, 625, 187, 2185, 713, 10107, 11139, 63681, 97005, 79329}},
+{16835, 18, 57664, {1, 3, 1, 11, 3, 41, 43, 161, 337, 955, 1035, 451, 5989, 3593, 18087, 22667, 110213, 128545}},
+{16836, 18, 57674, {1, 1, 5, 1, 25, 31, 95, 113, 205, 565, 557, 3885, 7163, 10703, 27159, 11395, 117459, 52439}},
+{16837, 18, 57698, {1, 1, 1, 5, 27, 31, 39, 61, 323, 983, 1361, 2387, 5401, 8287, 17855, 49783, 65327, 202861}},
+{16838, 18, 57700, {1, 3, 5, 3, 31, 39, 105, 113, 183, 311, 667, 945, 3677, 14623, 27907, 16673, 77899, 182863}},
+{16839, 18, 57709, {1, 1, 5, 3, 17, 27, 99, 93, 81, 805, 1799, 2855, 6859, 3917, 26177, 22307, 59213, 210123}},
+{16840, 18, 57724, {1, 3, 5, 1, 19, 37, 51, 65, 495, 229, 229, 1283, 2967, 5329, 24339, 58739, 23145, 7033}},
+{16841, 18, 57728, {1, 3, 3, 15, 11, 51, 121, 41, 75, 845, 1771, 3625, 6137, 3463, 11767, 45181, 70907, 42771}},
+{16842, 18, 57740, {1, 3, 7, 9, 15, 25, 55, 219, 265, 655, 167, 1247, 5409, 5623, 21045, 12333, 25799, 218601}},
+{16843, 18, 57745, {1, 3, 3, 13, 31, 39, 77, 155, 471, 969, 755, 2745, 3057, 3621, 32423, 48687, 9409, 90997}},
+{16844, 18, 57751, {1, 1, 3, 15, 27, 1, 77, 231, 147, 235, 2027, 4045, 7431, 14655, 6361, 43155, 9839, 161713}},
+{16845, 18, 57774, {1, 3, 7, 5, 25, 19, 25, 75, 415, 931, 457, 3691, 687, 4849, 15469, 42871, 37949, 74163}},
+{16846, 18, 57782, {1, 3, 5, 9, 17, 19, 29, 117, 387, 1021, 1159, 2467, 2585, 2563, 9155, 44763, 93319, 6321}},
+{16847, 18, 57796, {1, 3, 5, 7, 25, 33, 127, 175, 143, 705, 539, 2563, 945, 11369, 19971, 19019, 116195, 84121}},
+{16848, 18, 57803, {1, 3, 7, 7, 5, 55, 29, 1, 419, 715, 1275, 2983, 7853, 12245, 32109, 27371, 123547, 82723}},
+{16849, 18, 57823, {1, 1, 1, 13, 3, 29, 31, 213, 195, 609, 1465, 1711, 6747, 13309, 1131, 3151, 48779, 91571}},
+{16850, 18, 57863, {1, 1, 5, 3, 17, 7, 103, 7, 217, 87, 1641, 833, 4551, 14205, 15119, 6711, 111273, 200545}},
+{16851, 18, 57894, {1, 3, 1, 5, 3, 39, 99, 15, 433, 895, 165, 4049, 3183, 4385, 24695, 40009, 67151, 156643}},
+{16852, 18, 57925, {1, 1, 7, 3, 29, 9, 15, 27, 109, 1019, 327, 2837, 5297, 12455, 2355, 37703, 122995, 177871}},
+{16853, 18, 57971, {1, 1, 5, 15, 29, 5, 121, 117, 31, 155, 1027, 1105, 8057, 8677, 9523, 3019, 98801, 15539}},
+{16854, 18, 58013, {1, 3, 7, 3, 1, 1, 37, 67, 471, 317, 1571, 2801, 7383, 4339, 8095, 45685, 95885, 39577}},
+{16855, 18, 58020, {1, 3, 7, 13, 17, 13, 91, 79, 49, 321, 1235, 311, 129, 6537, 6643, 25813, 48251, 138823}},
+{16856, 18, 58032, {1, 1, 5, 3, 21, 19, 67, 61, 153, 611, 1819, 3755, 5959, 3419, 6117, 1159, 68925, 146199}},
+{16857, 18, 58038, {1, 1, 7, 9, 23, 3, 7, 13, 429, 463, 653, 3461, 6337, 4511, 18097, 44837, 99845, 37101}},
+{16858, 18, 58061, {1, 3, 5, 13, 9, 5, 123, 199, 83, 409, 1391, 1567, 7327, 8173, 30971, 18241, 7755, 185375}},
+{16859, 18, 58069, {1, 3, 1, 7, 19, 51, 51, 23, 85, 923, 1969, 2329, 7343, 12489, 16135, 64783, 117063, 141071}},
+{16860, 18, 58080, {1, 3, 1, 3, 23, 29, 5, 77, 207, 351, 367, 2097, 2639, 9255, 21971, 64167, 98069, 81153}},
+{16861, 18, 58089, {1, 1, 7, 15, 27, 1, 83, 255, 47, 935, 567, 3573, 3629, 5833, 483, 1001, 9337, 119847}},
+{16862, 18, 58107, {1, 3, 7, 11, 31, 53, 25, 35, 463, 51, 401, 3279, 7709, 11265, 17905, 40423, 26277, 43355}},
+{16863, 18, 58121, {1, 1, 7, 5, 9, 15, 73, 217, 239, 405, 1651, 2131, 6791, 11241, 21717, 7393, 77251, 28131}},
+{16864, 18, 58130, {1, 3, 5, 3, 13, 43, 115, 159, 215, 811, 1349, 2941, 2073, 1821, 6891, 17285, 72027, 137849}},
+{16865, 18, 58146, {1, 3, 3, 3, 15, 11, 29, 53, 307, 409, 1069, 3713, 3205, 6185, 2565, 14973, 46149, 162527}},
+{16866, 18, 58190, {1, 1, 3, 15, 21, 39, 61, 209, 211, 123, 697, 2285, 859, 2501, 5847, 56449, 106575, 261069}},
+{16867, 18, 58195, {1, 3, 3, 5, 25, 21, 39, 131, 189, 747, 1499, 1865, 3369, 9161, 12543, 63155, 70083, 69441}},
+{16868, 18, 58202, {1, 3, 1, 15, 31, 43, 127, 57, 169, 109, 979, 1399, 3065, 5865, 16891, 56003, 14319, 94109}},
+{16869, 18, 58237, {1, 1, 1, 13, 23, 57, 13, 239, 139, 41, 1959, 429, 209, 543, 21297, 15343, 16521, 52305}},
+{16870, 18, 58253, {1, 1, 7, 1, 17, 1, 115, 139, 93, 123, 867, 3257, 8135, 12089, 1503, 33287, 79283, 151419}},
+{16871, 18, 58299, {1, 3, 7, 7, 27, 17, 15, 253, 89, 959, 597, 2193, 3505, 13865, 2179, 58711, 114615, 15227}},
+{16872, 18, 58302, {1, 3, 7, 5, 1, 5, 105, 241, 361, 229, 1069, 3815, 1409, 4909, 31785, 46555, 123523, 53259}},
+{16873, 18, 58327, {1, 1, 5, 5, 15, 49, 13, 195, 467, 285, 1405, 3011, 2069, 8331, 13953, 31107, 46581, 154615}},
+{16874, 18, 58328, {1, 3, 5, 7, 21, 23, 17, 17, 345, 369, 1521, 3755, 2165, 15387, 2851, 11115, 60483, 236049}},
+{16875, 18, 58364, {1, 3, 3, 1, 5, 41, 53, 239, 127, 237, 609, 927, 3787, 5059, 1865, 52991, 56229, 102093}},
+{16876, 18, 58367, {1, 1, 7, 5, 23, 7, 15, 199, 325, 695, 1525, 3435, 3997, 11577, 22985, 57713, 94309, 218433}},
+{16877, 18, 58375, {1, 3, 3, 5, 25, 25, 61, 99, 237, 447, 1905, 783, 5239, 11415, 16833, 27815, 115539, 161111}},
+{16878, 18, 58394, {1, 1, 5, 9, 31, 49, 55, 199, 159, 751, 849, 1045, 5485, 8883, 8549, 11735, 35983, 161067}},
+{16879, 18, 58405, {1, 1, 5, 9, 23, 51, 79, 171, 87, 493, 1911, 3867, 3435, 493, 16639, 64085, 97797, 244959}},
+{16880, 18, 58417, {1, 1, 5, 11, 29, 33, 15, 107, 283, 545, 1995, 995, 7181, 3581, 8621, 42391, 117997, 397}},
+{16881, 18, 58424, {1, 3, 7, 13, 31, 25, 91, 75, 123, 451, 1023, 375, 4505, 13235, 8913, 34389, 77385, 168659}},
+{16882, 18, 58430, {1, 1, 3, 3, 3, 3, 85, 143, 173, 709, 1313, 593, 6931, 14609, 13803, 30305, 109089, 11473}},
+{16883, 18, 58452, {1, 3, 7, 5, 25, 45, 25, 223, 407, 597, 83, 2543, 3823, 13959, 9089, 28325, 29237, 57147}},
+{16884, 18, 58466, {1, 1, 1, 3, 25, 53, 57, 255, 231, 361, 109, 113, 6091, 13043, 28399, 29111, 57987, 137709}},
+{16885, 18, 58468, {1, 1, 1, 5, 11, 25, 53, 141, 275, 237, 1427, 1691, 6043, 8951, 10683, 17477, 117645, 89007}},
+{16886, 18, 58495, {1, 3, 3, 13, 7, 23, 73, 213, 285, 667, 1765, 1545, 1401, 12483, 6349, 47205, 25791, 16749}},
+{16887, 18, 58501, {1, 1, 1, 15, 31, 45, 105, 249, 385, 607, 723, 745, 7037, 15735, 3637, 29013, 127315, 165507}},
+{16888, 18, 58544, {1, 1, 7, 5, 21, 63, 95, 247, 161, 839, 939, 931, 4277, 7363, 8289, 55183, 122413, 152997}},
+{16889, 18, 58571, {1, 3, 7, 11, 15, 59, 91, 5, 209, 31, 1581, 979, 6289, 11443, 26641, 20183, 106907, 128647}},
+{16890, 18, 58609, {1, 1, 3, 15, 21, 33, 117, 89, 457, 405, 1971, 2211, 4379, 16189, 7933, 39351, 79813, 56373}},
+{16891, 18, 58610, {1, 3, 3, 9, 5, 9, 93, 75, 55, 271, 321, 3143, 3893, 2601, 26169, 35179, 43063, 156635}},
+{16892, 18, 58616, {1, 3, 3, 11, 29, 37, 95, 249, 221, 965, 423, 1637, 4663, 14839, 16757, 4261, 128453, 165593}},
+{16893, 18, 58619, {1, 3, 3, 7, 1, 55, 31, 235, 447, 839, 721, 1125, 6503, 4019, 23351, 37057, 96103, 143805}},
+{16894, 18, 58641, {1, 3, 7, 5, 31, 39, 7, 157, 469, 719, 1613, 395, 8133, 9753, 17323, 13849, 45409, 7601}},
+{16895, 18, 58642, {1, 3, 7, 7, 31, 37, 89, 215, 453, 659, 605, 3325, 987, 4611, 29667, 23229, 4201, 229675}},
+{16896, 18, 58648, {1, 1, 5, 5, 3, 3, 21, 249, 377, 343, 1751, 891, 5275, 14853, 32703, 51001, 6759, 162991}},
+{16897, 18, 58660, {1, 3, 1, 13, 11, 21, 55, 17, 495, 481, 1817, 919, 2495, 16367, 3343, 16997, 83437, 127791}},
+{16898, 18, 58675, {1, 3, 1, 1, 5, 57, 65, 223, 33, 491, 1953, 1521, 4903, 5007, 14583, 17321, 82231, 206299}},
+{16899, 18, 58678, {1, 3, 7, 11, 21, 45, 55, 141, 185, 379, 851, 885, 3385, 10311, 701, 2983, 71045, 171525}},
+{16900, 18, 58690, {1, 3, 7, 3, 29, 1, 53, 139, 7, 985, 291, 3949, 1163, 14637, 363, 59679, 121571, 121081}},
+{16901, 18, 58735, {1, 3, 7, 1, 31, 1, 111, 19, 421, 917, 1529, 1361, 4461, 12457, 9791, 19985, 77283, 117059}},
+{16902, 18, 58760, {1, 3, 1, 5, 7, 55, 93, 243, 477, 193, 1983, 489, 3735, 1391, 24035, 36395, 49101, 175861}},
+{16903, 18, 58766, {1, 1, 1, 11, 3, 25, 69, 167, 351, 193, 1299, 617, 7455, 2545, 18359, 9951, 119513, 128139}},
+{16904, 18, 58799, {1, 3, 3, 7, 5, 23, 101, 47, 385, 591, 345, 3501, 531, 3277, 28945, 18695, 58587, 87221}},
+{16905, 18, 58825, {1, 1, 3, 3, 29, 47, 5, 91, 365, 1, 2015, 323, 1601, 10615, 28975, 60263, 4813, 143351}},
+{16906, 18, 58836, {1, 3, 1, 7, 25, 43, 65, 211, 91, 759, 985, 3675, 5701, 4373, 27781, 51949, 40667, 102665}},
+{16907, 18, 58855, {1, 3, 3, 5, 3, 43, 91, 33, 247, 593, 849, 1955, 7769, 2307, 2877, 26037, 28907, 211021}},
+{16908, 18, 58864, {1, 3, 5, 15, 29, 29, 85, 97, 99, 979, 2033, 1415, 2955, 15733, 5567, 6241, 100195, 89077}},
+{16909, 18, 58910, {1, 3, 7, 13, 13, 19, 121, 211, 381, 73, 1131, 1881, 1693, 7873, 27557, 201, 24997, 202471}},
+{16910, 18, 58937, {1, 3, 1, 15, 15, 33, 11, 99, 479, 271, 1873, 1117, 3559, 6605, 15995, 44805, 12465, 71933}},
+{16911, 18, 58943, {1, 3, 5, 3, 19, 61, 15, 55, 423, 431, 1321, 3345, 1633, 4587, 24909, 54985, 31831, 181083}},
+{16912, 18, 58952, {1, 1, 3, 5, 29, 43, 49, 205, 415, 907, 1651, 57, 3043, 10763, 16255, 9567, 59453, 135637}},
+{16913, 18, 58965, {1, 3, 3, 1, 17, 11, 29, 33, 293, 203, 1687, 1565, 6131, 5435, 29023, 28425, 102151, 251913}},
+{16914, 18, 58988, {1, 1, 5, 7, 9, 9, 43, 191, 269, 681, 607, 3045, 2799, 14919, 8083, 57781, 19345, 49365}},
+{16915, 18, 58994, {1, 1, 5, 13, 11, 53, 67, 127, 117, 395, 575, 1651, 2601, 15019, 21413, 34433, 66847, 84159}},
+{16916, 18, 58999, {1, 3, 5, 5, 15, 59, 33, 41, 301, 699, 1479, 2285, 1813, 2459, 4775, 53213, 26039, 223155}},
+{16917, 18, 59006, {1, 3, 1, 15, 17, 57, 5, 211, 357, 175, 945, 3625, 3943, 12871, 26805, 29305, 8839, 107837}},
+{16918, 18, 59029, {1, 3, 5, 15, 21, 41, 105, 229, 265, 777, 2047, 767, 2901, 8873, 7631, 18545, 86697, 252965}},
+{16919, 18, 59033, {1, 1, 5, 11, 31, 63, 115, 119, 271, 921, 1221, 3341, 6083, 4293, 28581, 57323, 33889, 112577}},
+{16920, 18, 59069, {1, 1, 5, 5, 31, 21, 119, 93, 287, 139, 451, 2535, 3925, 10671, 21279, 55071, 76127, 248203}},
+{16921, 18, 59096, {1, 3, 7, 11, 19, 61, 61, 53, 203, 181, 963, 3581, 519, 14679, 7717, 31981, 128709, 197269}},
+{16922, 18, 59106, {1, 1, 1, 13, 25, 23, 89, 95, 221, 803, 1433, 3617, 3217, 2033, 7859, 14279, 107239, 5139}},
+{16923, 18, 59123, {1, 3, 7, 3, 29, 41, 87, 21, 71, 959, 1149, 2961, 7471, 11665, 16037, 5791, 110155, 35365}},
+{16924, 18, 59130, {1, 1, 1, 11, 21, 49, 101, 45, 311, 529, 1301, 1377, 983, 3937, 6967, 8413, 33511, 9617}},
+{16925, 18, 59152, {1, 3, 3, 5, 15, 41, 107, 49, 409, 537, 289, 3351, 5307, 16221, 907, 39847, 61579, 161487}},
+{16926, 18, 59162, {1, 1, 3, 11, 5, 49, 71, 107, 431, 469, 453, 1367, 7811, 10485, 3861, 62797, 82025, 253785}},
+{16927, 18, 59180, {1, 1, 3, 3, 27, 19, 89, 13, 445, 915, 1259, 1423, 3987, 3661, 18183, 18521, 18831, 191447}},
+{16928, 18, 59183, {1, 1, 7, 5, 13, 15, 9, 89, 129, 949, 1733, 245, 6815, 8477, 1273, 34737, 33027, 191415}},
+{16929, 18, 59195, {1, 1, 7, 15, 25, 63, 83, 195, 319, 987, 1395, 3559, 6287, 5139, 25967, 48711, 58467, 110983}},
+{16930, 18, 59205, {1, 1, 3, 9, 5, 3, 35, 171, 15, 883, 915, 2451, 871, 11741, 32715, 33475, 81711, 259157}},
+{16931, 18, 59210, {1, 1, 7, 13, 23, 63, 33, 11, 117, 351, 1701, 671, 6753, 5, 9477, 54701, 65507, 242621}},
+{16932, 18, 59217, {1, 3, 7, 11, 21, 37, 127, 143, 369, 819, 1369, 93, 7009, 3773, 30153, 30181, 120783, 137857}},
+{16933, 18, 59218, {1, 3, 3, 7, 27, 61, 15, 141, 67, 815, 1449, 1129, 4703, 3811, 3067, 61697, 8881, 110957}},
+{16934, 18, 59236, {1, 1, 7, 13, 31, 21, 59, 75, 335, 851, 503, 251, 4869, 11789, 30871, 14641, 19319, 156843}},
+{16935, 18, 59267, {1, 3, 5, 5, 9, 41, 11, 67, 231, 945, 37, 2925, 5723, 9053, 13477, 59735, 75181, 60335}},
+{16936, 18, 59298, {1, 1, 5, 1, 13, 39, 81, 43, 363, 611, 1661, 3833, 7387, 10531, 21319, 55579, 102705, 103009}},
+{16937, 18, 59318, {1, 3, 1, 7, 23, 25, 67, 179, 327, 401, 1693, 1453, 4773, 6363, 27169, 49747, 29055, 49145}},
+{16938, 18, 59321, {1, 3, 5, 7, 13, 47, 5, 175, 369, 921, 507, 113, 6069, 10919, 11099, 19795, 95819, 52419}},
+{16939, 18, 59327, {1, 1, 1, 5, 5, 53, 93, 47, 75, 837, 109, 3691, 6961, 10715, 14269, 63791, 1941, 136899}},
+{16940, 18, 59354, {1, 1, 1, 3, 1, 63, 57, 117, 157, 327, 879, 2411, 3987, 15393, 8503, 29829, 77795, 121307}},
+{16941, 18, 59363, {1, 3, 5, 1, 25, 5, 47, 45, 433, 121, 607, 1233, 6433, 3031, 16369, 58589, 79357, 151353}},
+{16942, 18, 59377, {1, 1, 1, 1, 9, 15, 77, 163, 225, 445, 1479, 1267, 2571, 2661, 21489, 5433, 123969, 191967}},
+{16943, 18, 59389, {1, 1, 7, 1, 9, 49, 17, 19, 449, 113, 1289, 2335, 3309, 2595, 17819, 18481, 86605, 125911}},
+{16944, 18, 59403, {1, 1, 5, 11, 11, 23, 65, 147, 257, 625, 1901, 913, 5711, 8159, 16237, 25133, 100059, 11395}},
+{16945, 18, 59420, {1, 3, 7, 13, 5, 33, 89, 189, 171, 185, 751, 2915, 5025, 15981, 14853, 12229, 52829, 59953}},
+{16946, 18, 59444, {1, 3, 1, 13, 3, 37, 15, 87, 463, 655, 1927, 2705, 1885, 14801, 3491, 52835, 81761, 90273}},
+{16947, 18, 59471, {1, 1, 7, 3, 5, 15, 29, 255, 199, 225, 647, 3215, 6795, 3821, 31763, 31059, 65495, 89981}},
+{16948, 18, 59476, {1, 1, 7, 7, 9, 25, 11, 85, 111, 283, 507, 2077, 2993, 5415, 31785, 16495, 82361, 122105}},
+{16949, 18, 59483, {1, 1, 3, 11, 27, 21, 127, 175, 397, 419, 1115, 2285, 223, 3881, 4187, 53759, 115035, 181647}},
+{16950, 18, 59502, {1, 3, 7, 11, 27, 31, 29, 233, 137, 827, 1009, 3879, 7595, 12989, 27655, 8517, 28083, 214985}},
+{16951, 18, 59509, {1, 3, 5, 9, 25, 23, 85, 191, 475, 445, 621, 1341, 4045, 4299, 24933, 32765, 20219, 86949}},
+{16952, 18, 59538, {1, 3, 1, 5, 25, 35, 121, 33, 199, 405, 163, 3487, 1087, 743, 21989, 47273, 49221, 124831}},
+{16953, 18, 59556, {1, 1, 5, 1, 7, 3, 91, 15, 335, 351, 1311, 777, 4303, 7203, 19465, 9135, 32251, 69805}},
+{16954, 18, 59571, {1, 3, 3, 7, 23, 55, 73, 77, 189, 801, 1877, 1901, 2675, 1015, 3041, 35925, 125903, 126227}},
+{16955, 18, 59592, {1, 3, 3, 1, 1, 23, 105, 75, 435, 743, 651, 1045, 579, 13637, 14821, 62683, 95229, 156475}},
+{16956, 18, 59610, {1, 3, 3, 5, 1, 53, 89, 239, 439, 195, 189, 731, 1805, 15123, 23315, 47737, 29167, 112081}},
+{16957, 18, 59654, {1, 1, 5, 7, 31, 11, 119, 191, 155, 61, 247, 915, 5813, 995, 20093, 23379, 118969, 65001}},
+{16958, 18, 59677, {1, 3, 7, 3, 1, 61, 45, 85, 295, 269, 539, 1787, 6639, 11093, 11303, 18509, 77637, 200743}},
+{16959, 18, 59699, {1, 3, 1, 1, 13, 17, 75, 51, 199, 151, 1529, 1443, 4983, 6723, 6071, 34711, 39159, 5441}},
+{16960, 18, 59716, {1, 3, 3, 3, 31, 15, 91, 125, 261, 683, 1769, 1697, 2761, 11373, 13607, 24933, 19079, 55497}},
+{16961, 18, 59719, {1, 1, 1, 15, 21, 49, 117, 99, 29, 969, 463, 3869, 1251, 8815, 16443, 46861, 82839, 233325}},
+{16962, 18, 59737, {1, 3, 5, 3, 27, 39, 89, 225, 161, 63, 61, 2875, 4037, 10413, 5067, 27893, 78825, 250207}},
+{16963, 18, 59747, {1, 1, 1, 9, 13, 49, 93, 11, 23, 25, 2003, 57, 3065, 11241, 13935, 2969, 44235, 39287}},
+{16964, 18, 59789, {1, 3, 3, 9, 21, 5, 55, 247, 193, 523, 575, 1235, 3277, 5253, 5293, 7919, 7573, 168809}},
+{16965, 18, 59807, {1, 3, 1, 13, 29, 39, 43, 21, 511, 205, 303, 703, 3861, 2467, 3909, 31597, 51081, 9863}},
+{16966, 18, 59811, {1, 3, 7, 1, 25, 55, 11, 131, 5, 49, 371, 1683, 1907, 5661, 1015, 15171, 101477, 11221}},
+{16967, 18, 59818, {1, 3, 5, 5, 9, 15, 93, 245, 357, 703, 701, 3675, 4527, 9225, 16137, 55433, 81887, 99153}},
+{16968, 18, 59825, {1, 1, 3, 3, 11, 1, 39, 251, 291, 599, 643, 231, 4031, 7055, 99, 14039, 81811, 184251}},
+{16969, 18, 59826, {1, 3, 5, 13, 29, 55, 11, 117, 325, 401, 2013, 3235, 995, 9255, 2741, 8211, 71451, 180619}},
+{16970, 18, 59832, {1, 1, 1, 5, 31, 41, 41, 175, 247, 3, 739, 1391, 3311, 5975, 16921, 4291, 75065, 161745}},
+{16971, 18, 59858, {1, 1, 7, 13, 23, 19, 13, 149, 203, 351, 2033, 1867, 3871, 14437, 3793, 17399, 99577, 171605}},
+{16972, 18, 59860, {1, 1, 5, 11, 7, 9, 1, 195, 261, 977, 315, 3771, 1179, 16281, 20747, 56309, 108609, 209205}},
+{16973, 18, 59873, {1, 3, 3, 5, 19, 15, 123, 153, 325, 601, 393, 753, 93, 4803, 24343, 42645, 128209, 45773}},
+{16974, 18, 59876, {1, 3, 1, 13, 3, 29, 97, 95, 115, 539, 155, 2789, 1277, 13127, 20383, 52807, 97295, 54589}},
+{16975, 18, 59907, {1, 1, 1, 3, 25, 59, 27, 149, 365, 317, 773, 3379, 5931, 14637, 19881, 37283, 118027, 21557}},
+{16976, 18, 59928, {1, 3, 5, 3, 25, 11, 101, 221, 199, 689, 515, 2255, 6107, 6259, 2853, 19039, 117089, 107181}},
+{16977, 18, 59933, {1, 3, 5, 7, 29, 63, 19, 113, 249, 147, 737, 3959, 209, 7001, 24263, 20443, 99923, 145709}},
+{16978, 18, 59938, {1, 1, 5, 9, 25, 37, 69, 41, 87, 369, 1913, 2255, 7581, 5301, 25751, 24981, 1183, 171969}},
+{16979, 18, 59940, {1, 3, 3, 1, 9, 25, 55, 5, 267, 295, 43, 819, 4569, 7065, 31527, 57811, 48721, 107707}},
+{16980, 18, 59958, {1, 1, 7, 9, 19, 19, 1, 199, 371, 1003, 597, 2097, 4071, 6185, 879, 13545, 30033, 120313}},
+{16981, 18, 59984, {1, 1, 1, 7, 9, 11, 51, 155, 309, 493, 899, 3121, 2085, 10541, 21979, 4725, 70381, 69643}},
+{16982, 18, 60020, {1, 1, 1, 1, 13, 45, 123, 119, 459, 295, 1005, 4093, 393, 11063, 27235, 28209, 1671, 215619}},
+{16983, 18, 60024, {1, 1, 7, 13, 19, 25, 125, 255, 509, 529, 1577, 3221, 4051, 7697, 2065, 42597, 86295, 131719}},
+{16984, 18, 60033, {1, 3, 3, 9, 19, 13, 21, 199, 97, 949, 1297, 379, 1801, 13247, 22563, 49517, 22757, 87371}},
+{16985, 18, 60034, {1, 3, 3, 1, 17, 63, 109, 175, 301, 565, 1181, 465, 3457, 7175, 21225, 33149, 122169, 148043}},
+{16986, 18, 60063, {1, 1, 1, 1, 5, 7, 21, 251, 53, 369, 955, 583, 4703, 9729, 15853, 55701, 29317, 27}},
+{16987, 18, 60070, {1, 3, 3, 1, 31, 3, 53, 57, 231, 441, 109, 149, 8107, 2303, 29729, 42279, 46909, 209877}},
+{16988, 18, 60087, {1, 1, 1, 11, 23, 57, 63, 189, 259, 657, 1653, 1155, 2885, 3317, 22559, 3145, 19151, 172507}},
+{16989, 18, 60091, {1, 3, 7, 5, 31, 63, 103, 147, 287, 685, 1197, 99, 4907, 12335, 12001, 20303, 75503, 231259}},
+{16990, 18, 60105, {1, 3, 3, 13, 15, 33, 63, 11, 99, 299, 97, 2669, 3635, 9969, 1525, 36555, 85215, 86915}},
+{16991, 18, 60126, {1, 3, 7, 5, 25, 47, 25, 61, 227, 939, 1719, 245, 2389, 14663, 30671, 22667, 38873, 245509}},
+{16992, 18, 60132, {1, 1, 3, 5, 25, 15, 105, 203, 57, 961, 1941, 1241, 3163, 6203, 19631, 10383, 19235, 57569}},
+{16993, 18, 60154, {1, 1, 3, 9, 1, 35, 41, 3, 449, 87, 641, 269, 1529, 14559, 16571, 4863, 21625, 921}},
+{16994, 18, 60174, {1, 1, 7, 11, 25, 53, 85, 209, 181, 417, 1657, 2117, 4581, 7069, 15533, 64475, 82381, 146943}},
+{16995, 18, 60181, {1, 3, 1, 7, 17, 53, 5, 199, 347, 887, 1041, 595, 1843, 10931, 30559, 42849, 73723, 220473}},
+{16996, 18, 60198, {1, 3, 7, 7, 21, 53, 105, 21, 141, 575, 1965, 2187, 7293, 13675, 2471, 1259, 42485, 62911}},
+{16997, 18, 60212, {1, 1, 3, 9, 5, 27, 21, 101, 101, 71, 1215, 3235, 2451, 14835, 27817, 30079, 124301, 253691}},
+{16998, 18, 60247, {1, 1, 7, 1, 11, 37, 105, 127, 115, 157, 279, 2425, 2139, 131, 22717, 40803, 74867, 86021}},
+{16999, 18, 60254, {1, 1, 1, 7, 11, 59, 95, 61, 255, 523, 501, 2895, 7531, 8151, 18393, 42069, 120809, 236537}},
+{17000, 18, 60275, {1, 1, 1, 7, 17, 23, 31, 59, 377, 187, 873, 1565, 3459, 2975, 11633, 13247, 13095, 193803}},
+{17001, 18, 60284, {1, 3, 7, 1, 25, 3, 85, 5, 485, 451, 1385, 1663, 4825, 14019, 29437, 33717, 105343, 161335}},
+{17002, 18, 60317, {1, 1, 1, 3, 27, 43, 71, 167, 425, 579, 1739, 3557, 7403, 2023, 6533, 61177, 119273, 85229}},
+{17003, 18, 60318, {1, 1, 7, 3, 31, 37, 19, 213, 373, 505, 97, 3669, 7005, 2205, 26519, 61999, 18395, 25967}},
+{17004, 18, 60346, {1, 3, 3, 7, 29, 17, 9, 137, 265, 875, 887, 3029, 3295, 11619, 8357, 46241, 23543, 43191}},
+{17005, 18, 60360, {1, 1, 5, 1, 25, 43, 33, 133, 65, 7, 1581, 3577, 5997, 6129, 30649, 18923, 56459, 227869}},
+{17006, 18, 60380, {1, 1, 5, 13, 27, 45, 27, 111, 429, 565, 1449, 1475, 6613, 4469, 16083, 42349, 66843, 214875}},
+{17007, 18, 60389, {1, 3, 1, 1, 21, 21, 107, 7, 15, 675, 233, 4021, 1097, 1393, 6445, 3323, 102435, 249355}},
+{17008, 18, 60393, {1, 1, 5, 15, 17, 51, 99, 249, 437, 667, 1921, 2371, 3813, 10543, 19, 39079, 116825, 242821}},
+{17009, 18, 60401, {1, 1, 1, 1, 7, 15, 27, 29, 161, 37, 1847, 287, 4379, 1399, 24547, 60361, 68131, 232883}},
+{17010, 18, 60407, {1, 1, 3, 9, 17, 21, 41, 169, 61, 771, 241, 1435, 4151, 1789, 12195, 27239, 62371, 165145}},
+{17011, 18, 60408, {1, 3, 5, 15, 31, 19, 127, 181, 463, 183, 749, 253, 2403, 1363, 3965, 7953, 124025, 226691}},
+{17012, 18, 60462, {1, 1, 3, 7, 17, 57, 85, 89, 17, 33, 819, 2191, 1525, 15651, 23483, 26027, 86379, 40191}},
+{17013, 18, 60484, {1, 1, 5, 1, 9, 45, 65, 65, 359, 5, 531, 2581, 6313, 13219, 6005, 36215, 16275, 208253}},
+{17014, 18, 60505, {1, 3, 1, 1, 23, 15, 51, 43, 85, 461, 773, 219, 2681, 3377, 9797, 54469, 112871, 231533}},
+{17015, 18, 60521, {1, 3, 7, 7, 15, 9, 97, 115, 301, 493, 1085, 2021, 2305, 15003, 11381, 9339, 63015, 179115}},
+{17016, 18, 60527, {1, 3, 5, 3, 3, 61, 111, 103, 283, 7, 143, 353, 7815, 7901, 25795, 7577, 92991, 228315}},
+{17017, 18, 60532, {1, 1, 7, 13, 29, 3, 53, 105, 83, 531, 497, 729, 1375, 7063, 18655, 35219, 9671, 102913}},
+{17018, 18, 60545, {1, 1, 5, 15, 11, 7, 65, 31, 15, 921, 743, 1469, 5669, 5437, 20019, 28123, 5717, 6181}},
+{17019, 18, 60546, {1, 3, 3, 15, 19, 1, 3, 183, 315, 595, 1033, 3259, 7815, 8281, 32103, 8699, 59149, 56657}},
+{17020, 18, 60555, {1, 1, 1, 7, 9, 1, 87, 81, 267, 637, 1617, 2113, 487, 23, 11213, 29211, 92715, 177767}},
+{17021, 18, 60563, {1, 3, 5, 13, 29, 37, 31, 55, 343, 759, 813, 2945, 7189, 4821, 30661, 38373, 2793, 98683}},
+{17022, 18, 60586, {1, 3, 5, 7, 9, 43, 113, 145, 103, 303, 1065, 3781, 3527, 9449, 17355, 38301, 74859, 30735}},
+{17023, 18, 60626, {1, 1, 1, 1, 3, 53, 53, 27, 119, 701, 1777, 3959, 5911, 8473, 24997, 17557, 11593, 201381}},
+{17024, 18, 60637, {1, 3, 3, 9, 3, 3, 107, 115, 423, 531, 735, 931, 8053, 4661, 1919, 29551, 62515, 210255}},
+{17025, 18, 60665, {1, 1, 3, 9, 21, 21, 117, 67, 301, 49, 2025, 781, 7951, 15719, 27287, 34551, 115241, 243981}},
+{17026, 18, 60673, {1, 1, 7, 9, 9, 25, 87, 229, 375, 353, 445, 3169, 1865, 7305, 11175, 47081, 28609, 107301}},
+{17027, 18, 60685, {1, 3, 3, 11, 7, 31, 19, 177, 17, 535, 1353, 2587, 7723, 8039, 13607, 5017, 104937, 207761}},
+{17028, 18, 60703, {1, 1, 5, 3, 11, 27, 29, 193, 235, 435, 1451, 3487, 5749, 4825, 9487, 53933, 92061, 223305}},
+{17029, 18, 60734, {1, 3, 3, 3, 5, 5, 99, 237, 91, 945, 1373, 3303, 3079, 5345, 6843, 34131, 62851, 259561}},
+{17030, 18, 60742, {1, 1, 3, 7, 7, 25, 11, 27, 329, 37, 307, 771, 659, 13045, 25767, 18887, 54407, 251313}},
+{17031, 18, 60790, {1, 1, 1, 11, 29, 59, 37, 121, 281, 55, 495, 159, 3925, 4447, 14825, 24831, 103147, 211951}},
+{17032, 18, 60830, {1, 3, 3, 7, 23, 31, 59, 67, 303, 383, 1179, 2347, 4001, 14797, 14579, 55365, 112239, 65309}},
+{17033, 18, 60848, {1, 3, 3, 9, 15, 17, 61, 123, 339, 319, 765, 1517, 1269, 69, 9065, 32347, 21377, 38449}},
+{17034, 18, 60857, {1, 3, 5, 3, 7, 35, 71, 63, 251, 457, 351, 385, 4041, 11489, 14511, 11875, 45307, 205041}},
+{17035, 18, 60871, {1, 1, 1, 7, 1, 25, 115, 195, 41, 1001, 835, 767, 7991, 7475, 22397, 36899, 77255, 194827}},
+{17036, 18, 60875, {1, 3, 3, 11, 7, 49, 45, 13, 373, 167, 741, 2569, 3781, 1131, 2909, 40387, 77877, 201859}},
+{17037, 18, 60913, {1, 3, 5, 3, 17, 11, 123, 137, 65, 835, 1385, 1157, 7387, 12301, 5759, 13137, 30595, 50923}},
+{17038, 18, 60923, {1, 1, 5, 7, 1, 55, 57, 97, 377, 223, 115, 2515, 2565, 14965, 10485, 23957, 108239, 160707}},
+{17039, 18, 60972, {1, 3, 1, 9, 15, 17, 81, 65, 387, 275, 997, 1485, 4129, 999, 4915, 55867, 103799, 191829}},
+{17040, 18, 60989, {1, 1, 1, 5, 15, 5, 35, 167, 249, 419, 267, 503, 469, 3163, 19939, 65501, 88573, 11621}},
+{17041, 18, 61001, {1, 3, 3, 13, 7, 9, 101, 125, 371, 97, 1855, 1755, 4103, 12283, 18655, 5965, 17743, 254779}},
+{17042, 18, 61002, {1, 1, 3, 7, 13, 15, 119, 227, 451, 863, 1005, 491, 6515, 717, 12783, 14161, 106249, 185297}},
+{17043, 18, 61019, {1, 1, 7, 13, 17, 23, 95, 143, 133, 219, 897, 2291, 7469, 923, 22323, 60583, 2457, 197231}},
+{17044, 18, 61022, {1, 1, 1, 11, 3, 25, 115, 187, 319, 999, 867, 1725, 6969, 239, 2527, 55283, 91099, 252153}},
+{17045, 18, 61059, {1, 1, 7, 9, 3, 37, 107, 25, 425, 95, 631, 2831, 1265, 11509, 18865, 39791, 22281, 220517}},
+{17046, 18, 61065, {1, 3, 5, 1, 1, 47, 121, 173, 489, 241, 3, 3707, 7081, 5341, 23143, 7321, 30605, 191665}},
+{17047, 18, 61066, {1, 1, 7, 7, 7, 27, 23, 43, 145, 11, 1155, 691, 6993, 9509, 5991, 40705, 58215, 202915}},
+{17048, 18, 61071, {1, 3, 5, 1, 31, 1, 7, 189, 379, 431, 417, 3843, 3885, 3263, 16333, 58123, 68307, 33795}},
+{17049, 18, 61076, {1, 1, 5, 5, 19, 27, 19, 217, 509, 535, 287, 1637, 4829, 2665, 15393, 35185, 125335, 10909}},
+{17050, 18, 61141, {1, 3, 5, 7, 25, 13, 67, 243, 255, 1021, 1203, 821, 7811, 149, 26731, 12913, 18171, 101385}},
+{17051, 18, 61148, {1, 1, 1, 3, 25, 61, 59, 207, 449, 789, 1831, 1731, 513, 10099, 291, 1963, 100233, 21847}},
+{17052, 18, 61167, {1, 1, 7, 1, 27, 19, 45, 81, 479, 31, 707, 2669, 3589, 15411, 12089, 38235, 60897, 135451}},
+{17053, 18, 61190, {1, 3, 5, 15, 11, 3, 113, 169, 171, 21, 1291, 2031, 2023, 5783, 6137, 54637, 50247, 233753}},
+{17054, 18, 61218, {1, 1, 5, 1, 11, 13, 73, 97, 269, 801, 1015, 1329, 1779, 15225, 24251, 35191, 8619, 130993}},
+{17055, 18, 61247, {1, 1, 7, 9, 9, 19, 35, 255, 505, 513, 547, 405, 3065, 4965, 30877, 50091, 81319, 29273}},
+{17056, 18, 61256, {1, 1, 1, 9, 7, 61, 45, 75, 343, 911, 1683, 453, 1225, 10939, 19901, 63685, 123507, 252027}},
+{17057, 18, 61289, {1, 1, 5, 11, 21, 55, 37, 161, 143, 463, 1937, 3349, 2953, 14827, 7893, 26581, 128459, 72325}},
+{17058, 18, 61292, {1, 3, 5, 9, 31, 57, 115, 77, 225, 859, 621, 731, 5677, 759, 20773, 52285, 65555, 4303}},
+{17059, 18, 61307, {1, 1, 3, 15, 23, 15, 49, 171, 137, 449, 855, 565, 5579, 5957, 13643, 8979, 90327, 116349}},
+{17060, 18, 61319, {1, 1, 3, 5, 9, 13, 27, 43, 391, 595, 731, 101, 7121, 13555, 29181, 38273, 42309, 175297}},
+{17061, 18, 61353, {1, 1, 3, 11, 3, 59, 17, 143, 251, 47, 1391, 1297, 23, 15871, 13153, 44081, 65423, 54875}},
+{17062, 18, 61362, {1, 3, 7, 11, 25, 43, 3, 163, 273, 277, 755, 2743, 5909, 10841, 31331, 64131, 13945, 91557}},
+{17063, 18, 61379, {1, 3, 1, 13, 31, 35, 5, 165, 417, 623, 1083, 1221, 1051, 8917, 6725, 11385, 76315, 119837}},
+{17064, 18, 61382, {1, 1, 5, 3, 21, 53, 47, 247, 471, 877, 709, 2425, 3, 1963, 24331, 52151, 98859, 119033}},
+{17065, 18, 61433, {1, 1, 7, 3, 29, 29, 43, 59, 503, 891, 763, 2927, 1613, 9091, 10393, 36003, 61147, 3437}},
+{17066, 18, 61434, {1, 1, 5, 15, 27, 59, 73, 163, 425, 855, 349, 3451, 5779, 10523, 9103, 46477, 129873, 39091}},
+{17067, 18, 61454, {1, 3, 7, 15, 25, 45, 77, 171, 467, 1017, 1553, 1877, 5507, 3909, 12157, 60441, 98261, 37781}},
+{17068, 18, 61461, {1, 1, 7, 13, 13, 39, 99, 51, 197, 327, 1101, 2679, 8025, 11853, 7763, 62537, 96999, 88673}},
+{17069, 18, 61475, {1, 3, 1, 11, 5, 61, 29, 219, 471, 387, 319, 433, 5383, 3933, 27603, 61171, 104711, 233295}},
+{17070, 18, 61481, {1, 3, 5, 11, 15, 23, 91, 119, 207, 717, 1333, 783, 437, 13073, 10923, 27049, 87233, 174899}},
+{17071, 18, 61534, {1, 1, 1, 1, 13, 19, 109, 139, 183, 299, 1023, 3265, 5153, 6307, 27879, 55311, 95201, 19481}},
+{17072, 18, 61547, {1, 1, 5, 11, 13, 61, 81, 115, 53, 483, 693, 3527, 5033, 8527, 31345, 46155, 12403, 126815}},
+{17073, 18, 61564, {1, 3, 7, 3, 27, 7, 73, 227, 269, 683, 719, 763, 5417, 9523, 13625, 6945, 116225, 223093}},
+{17074, 18, 61568, {1, 3, 5, 9, 21, 51, 111, 157, 451, 247, 1375, 1631, 2783, 3371, 22713, 34153, 41949, 141351}},
+{17075, 18, 61588, {1, 1, 5, 1, 21, 19, 45, 69, 41, 453, 523, 3163, 7351, 4467, 18865, 35371, 129577, 78039}},
+{17076, 18, 61604, {1, 3, 5, 1, 29, 33, 13, 19, 341, 321, 117, 1187, 7021, 5785, 5553, 58055, 113557, 46957}},
+{17077, 18, 61626, {1, 1, 5, 5, 13, 59, 47, 59, 69, 125, 1491, 2813, 5005, 5973, 3145, 27579, 7763, 129949}},
+{17078, 18, 61645, {1, 1, 7, 11, 11, 7, 117, 235, 407, 749, 1925, 1735, 4499, 13027, 19355, 1981, 105657, 242853}},
+{17079, 18, 61646, {1, 1, 7, 1, 15, 19, 5, 247, 203, 707, 809, 2085, 5801, 9947, 569, 9883, 109861, 156751}},
+{17080, 18, 61654, {1, 3, 5, 3, 13, 59, 67, 181, 261, 873, 1589, 2249, 7213, 14625, 28403, 41101, 73439, 46873}},
+{17081, 18, 61663, {1, 1, 5, 7, 3, 63, 79, 115, 123, 485, 1373, 3781, 4315, 4627, 29003, 64101, 67521, 184053}},
+{17082, 18, 61669, {1, 1, 3, 9, 11, 57, 93, 243, 505, 189, 449, 643, 5267, 7447, 32265, 44095, 63015, 36905}},
+{17083, 18, 61702, {1, 3, 7, 13, 25, 59, 31, 93, 401, 41, 183, 759, 2473, 8705, 8211, 13543, 59749, 235217}},
+{17084, 18, 61705, {1, 1, 5, 5, 29, 3, 65, 133, 325, 239, 649, 3225, 4095, 11691, 4479, 15419, 100551, 261981}},
+{17085, 18, 61714, {1, 3, 7, 1, 17, 11, 63, 97, 431, 161, 1437, 3679, 1643, 10583, 20731, 45919, 94093, 147067}},
+{17086, 18, 61739, {1, 1, 7, 1, 25, 13, 63, 155, 221, 345, 189, 1199, 5465, 14767, 26263, 54093, 23697, 71231}},
+{17087, 18, 61744, {1, 1, 7, 3, 3, 19, 23, 75, 381, 339, 1989, 1137, 6449, 1437, 32279, 17195, 117423, 259311}},
+{17088, 18, 61749, {1, 3, 5, 3, 27, 45, 117, 113, 129, 585, 2019, 807, 5573, 7407, 9957, 8741, 52333, 115607}},
+{17089, 18, 61776, {1, 1, 3, 7, 9, 5, 77, 9, 417, 725, 429, 1657, 5445, 1901, 28745, 26807, 111743, 169739}},
+{17090, 18, 61786, {1, 3, 1, 5, 7, 63, 51, 183, 117, 383, 435, 755, 7849, 5997, 32697, 5789, 5189, 80645}},
+{17091, 18, 61822, {1, 1, 3, 15, 5, 47, 105, 175, 41, 275, 1441, 3183, 3651, 9561, 5749, 20431, 45969, 59473}},
+{17092, 18, 61826, {1, 1, 1, 11, 13, 35, 19, 129, 125, 35, 339, 3099, 5337, 15605, 10213, 1171, 61869, 216681}},
+{17093, 18, 61862, {1, 3, 7, 1, 7, 25, 23, 9, 431, 73, 1803, 3969, 7853, 12845, 8075, 14553, 124825, 50561}},
+{17094, 18, 61865, {1, 1, 1, 7, 29, 21, 79, 247, 313, 143, 59, 2689, 5643, 827, 26597, 56423, 107903, 180809}},
+{17095, 18, 61868, {1, 3, 7, 1, 3, 3, 25, 39, 269, 529, 67, 3703, 2163, 12417, 6307, 29883, 40303, 171831}},
+{17096, 18, 61879, {1, 3, 7, 13, 1, 19, 71, 245, 267, 105, 749, 1203, 7953, 1881, 9273, 4629, 71793, 195393}},
+{17097, 18, 61885, {1, 1, 1, 15, 3, 49, 53, 145, 47, 959, 1107, 1361, 4517, 16055, 32119, 58433, 110123, 81487}},
+{17098, 18, 61900, {1, 3, 1, 1, 5, 3, 99, 93, 257, 659, 19, 3789, 203, 6183, 11571, 54845, 80591, 243303}},
+{17099, 18, 61905, {1, 3, 7, 1, 1, 7, 27, 11, 255, 261, 769, 2877, 6013, 8431, 25669, 43591, 122501, 208947}},
+{17100, 18, 61906, {1, 1, 7, 7, 3, 25, 117, 19, 15, 843, 401, 613, 801, 10579, 129, 12249, 107465, 95953}},
+{17101, 18, 61962, {1, 1, 3, 5, 1, 35, 95, 93, 243, 937, 1543, 3443, 175, 2199, 12521, 2521, 87225, 38631}},
+{17102, 18, 61967, {1, 3, 7, 13, 21, 29, 81, 139, 247, 937, 1835, 3887, 6917, 15709, 20947, 3341, 125521, 247195}},
+{17103, 18, 61972, {1, 1, 5, 11, 31, 19, 111, 215, 191, 347, 1215, 1757, 6751, 3099, 755, 43753, 2813, 159123}},
+{17104, 18, 61976, {1, 3, 3, 3, 31, 5, 35, 87, 293, 581, 1501, 3255, 7041, 5233, 2053, 63403, 37943, 12115}},
+{17105, 18, 62027, {1, 1, 7, 15, 11, 31, 5, 123, 225, 703, 733, 635, 2193, 3059, 30933, 43149, 79409, 106995}},
+{17106, 18, 62048, {1, 3, 1, 7, 11, 21, 45, 135, 99, 883, 85, 3861, 6617, 7169, 29887, 329, 42487, 129001}},
+{17107, 18, 62051, {1, 1, 1, 3, 11, 53, 31, 245, 141, 667, 1615, 3311, 1475, 12785, 3509, 47153, 105747, 141275}},
+{17108, 18, 62066, {1, 1, 3, 15, 7, 15, 55, 13, 465, 707, 1299, 1393, 399, 9229, 4897, 50313, 1275, 131811}},
+{17109, 18, 62081, {1, 1, 3, 15, 5, 57, 43, 19, 335, 929, 459, 327, 5715, 7173, 27643, 535, 46221, 144619}},
+{17110, 18, 62108, {1, 3, 5, 1, 9, 1, 63, 187, 71, 899, 969, 1349, 1553, 15593, 22783, 211, 41643, 163981}},
+{17111, 18, 62178, {1, 1, 1, 13, 3, 63, 35, 37, 311, 253, 1393, 629, 5299, 14837, 15053, 28041, 81541, 149037}},
+{17112, 18, 62189, {1, 3, 3, 11, 13, 45, 17, 165, 497, 751, 635, 2939, 6891, 14877, 32763, 20671, 106845, 258033}},
+{17113, 18, 62224, {1, 1, 3, 11, 21, 7, 3, 247, 243, 219, 1651, 929, 2737, 9507, 31819, 61389, 14593, 137207}},
+{17114, 18, 62229, {1, 1, 7, 5, 15, 33, 31, 29, 467, 75, 523, 1067, 7313, 11715, 26581, 47037, 106385, 199859}},
+{17115, 18, 62282, {1, 3, 1, 7, 19, 59, 35, 35, 3, 899, 799, 1379, 5113, 7653, 17977, 42197, 52397, 179705}},
+{17116, 18, 62318, {1, 1, 7, 5, 13, 13, 67, 157, 181, 633, 21, 3107, 6301, 7523, 23981, 9079, 88875, 195869}},
+{17117, 18, 62320, {1, 3, 7, 9, 7, 9, 115, 49, 293, 691, 1729, 4087, 6353, 963, 12433, 22135, 96383, 127745}},
+{17118, 18, 62329, {1, 3, 7, 7, 21, 5, 43, 247, 89, 275, 1219, 311, 5677, 7161, 13853, 38613, 84935, 223563}},
+{17119, 18, 62341, {1, 3, 1, 5, 29, 61, 17, 235, 127, 979, 973, 1463, 371, 5567, 6949, 34165, 3075, 169347}},
+{17120, 18, 62353, {1, 3, 3, 15, 25, 51, 43, 73, 7, 123, 1761, 1461, 5291, 14271, 19335, 45379, 123469, 190439}},
+{17121, 18, 62359, {1, 3, 3, 13, 19, 57, 25, 161, 351, 703, 819, 753, 3101, 9043, 19179, 22665, 118533, 45817}},
+{17122, 18, 62382, {1, 3, 5, 15, 3, 33, 15, 63, 251, 87, 611, 1187, 2639, 6001, 16135, 27505, 71077, 34101}},
+{17123, 18, 62389, {1, 1, 5, 3, 31, 5, 13, 239, 119, 803, 1881, 3479, 1933, 6421, 21411, 62923, 76851, 211029}},
+{17124, 18, 62396, {1, 3, 1, 11, 13, 59, 13, 77, 87, 343, 1733, 3493, 5937, 15733, 7763, 12839, 68639, 70965}},
+{17125, 18, 62425, {1, 1, 1, 3, 5, 19, 73, 109, 197, 1007, 1369, 623, 3249, 9263, 12463, 37105, 40599, 115323}},
+{17126, 18, 62455, {1, 1, 7, 1, 21, 23, 27, 221, 117, 27, 1811, 837, 7355, 8083, 12657, 34137, 102025, 6511}},
+{17127, 18, 62484, {1, 3, 7, 13, 13, 29, 7, 103, 511, 449, 1443, 775, 3503, 1057, 8809, 48583, 27649, 206219}},
+{17128, 18, 62494, {1, 1, 7, 1, 15, 37, 53, 205, 393, 691, 989, 3493, 7813, 12371, 18125, 62569, 57075, 100625}},
+{17129, 18, 62507, {1, 3, 5, 7, 11, 11, 55, 7, 487, 861, 1589, 1003, 607, 10031, 22481, 41905, 67791, 168167}},
+{17130, 18, 62512, {1, 3, 1, 9, 21, 31, 25, 187, 315, 379, 961, 2721, 3395, 12321, 21693, 56977, 73197, 160023}},
+{17131, 18, 62550, {1, 3, 3, 7, 9, 25, 103, 1, 13, 1021, 1777, 1015, 2269, 2131, 191, 2561, 74755, 27131}},
+{17132, 18, 62577, {1, 1, 3, 13, 21, 29, 97, 153, 499, 207, 719, 585, 8155, 2873, 22073, 45933, 92875, 19205}},
+{17133, 18, 62590, {1, 3, 7, 15, 13, 31, 43, 223, 405, 839, 1241, 2219, 6911, 9469, 24477, 63157, 95503, 128431}},
+{17134, 18, 62599, {1, 3, 5, 15, 5, 11, 79, 129, 235, 171, 289, 1791, 6061, 9107, 13859, 55923, 30197, 111025}},
+{17135, 18, 62617, {1, 1, 7, 11, 13, 23, 51, 139, 219, 467, 1923, 2847, 1977, 1503, 1939, 55579, 65357, 50047}},
+{17136, 18, 62679, {1, 3, 7, 11, 27, 25, 91, 95, 73, 189, 1537, 273, 725, 1215, 15255, 18847, 67419, 162153}},
+{17137, 18, 62702, {1, 3, 3, 11, 3, 63, 49, 131, 219, 285, 819, 2801, 2645, 2943, 15055, 15659, 130641, 82913}},
+{17138, 18, 62745, {1, 1, 3, 7, 17, 19, 37, 59, 391, 1009, 1569, 2569, 2519, 33, 18827, 23277, 94797, 103673}},
+{17139, 18, 62772, {1, 3, 5, 9, 27, 57, 69, 185, 49, 829, 29, 1247, 6129, 14935, 8005, 48343, 55789, 170099}},
+{17140, 18, 62794, {1, 3, 3, 7, 19, 55, 77, 231, 79, 787, 1597, 2701, 4999, 4247, 31849, 7797, 118993, 77871}},
+{17141, 18, 62835, {1, 1, 7, 13, 5, 45, 105, 137, 239, 923, 593, 3227, 3603, 15463, 15533, 55285, 95295, 141951}},
+{17142, 18, 62842, {1, 3, 1, 5, 29, 3, 113, 241, 255, 181, 1933, 2579, 1865, 11083, 8023, 34271, 78603, 240781}},
+{17143, 18, 62847, {1, 1, 3, 7, 17, 21, 123, 75, 305, 485, 9, 3037, 677, 8001, 16803, 25851, 121773, 77729}},
+{17144, 18, 62857, {1, 3, 1, 5, 23, 7, 39, 25, 381, 1003, 361, 995, 1751, 9599, 6399, 9627, 19303, 249899}},
+{17145, 18, 62894, {1, 3, 5, 5, 13, 39, 65, 145, 351, 135, 981, 3657, 4711, 13649, 17253, 46443, 99187, 176683}},
+{17146, 18, 62911, {1, 3, 1, 9, 9, 41, 79, 237, 445, 507, 1947, 2905, 8161, 715, 24499, 62397, 26393, 197221}},
+{17147, 18, 62928, {1, 3, 5, 3, 23, 9, 107, 121, 59, 265, 177, 3495, 391, 4537, 32099, 45217, 128285, 259285}},
+{17148, 18, 62954, {1, 3, 3, 15, 5, 61, 87, 209, 139, 461, 485, 3261, 7425, 6193, 22221, 22145, 93989, 101459}},
+{17149, 18, 62964, {1, 3, 1, 1, 15, 51, 29, 145, 385, 695, 375, 3743, 1387, 15385, 7995, 22993, 64115, 239897}},
+{17150, 18, 62977, {1, 1, 5, 15, 9, 11, 73, 219, 293, 941, 477, 3935, 2717, 9559, 20537, 6935, 39711, 13623}},
+{17151, 18, 62984, {1, 3, 3, 11, 3, 23, 127, 21, 61, 59, 1685, 507, 3883, 6587, 6355, 65407, 54311, 228555}},
+{17152, 18, 63007, {1, 3, 1, 1, 25, 47, 51, 111, 77, 871, 1045, 4017, 7683, 7729, 24155, 3481, 31749, 245155}},
+{17153, 18, 63017, {1, 3, 5, 1, 25, 29, 119, 131, 475, 763, 1639, 1937, 7387, 2307, 24081, 34797, 91785, 52055}},
+{17154, 18, 63058, {1, 1, 5, 1, 29, 19, 119, 111, 119, 751, 1079, 1911, 4085, 8909, 4351, 30037, 37691, 57175}},
+{17155, 18, 63067, {1, 1, 7, 7, 27, 33, 71, 189, 105, 821, 1543, 2939, 3829, 6485, 22235, 7097, 76987, 207121}},
+{17156, 18, 63085, {1, 1, 3, 3, 7, 7, 65, 121, 355, 405, 1019, 1779, 7301, 10609, 25927, 16501, 37287, 133383}},
+{17157, 18, 63150, {1, 1, 3, 11, 31, 57, 109, 197, 165, 711, 271, 653, 5835, 14905, 26065, 52287, 106215, 225075}},
+{17158, 18, 63170, {1, 1, 3, 3, 1, 41, 5, 169, 15, 49, 1311, 2715, 579, 1693, 28001, 17935, 18585, 123531}},
+{17159, 18, 63184, {1, 1, 7, 7, 1, 49, 59, 75, 173, 361, 1947, 2707, 1835, 12025, 24051, 24359, 121841, 215797}},
+{17160, 18, 63210, {1, 1, 5, 13, 7, 49, 15, 181, 409, 1005, 383, 3449, 2987, 13051, 7097, 34571, 55495, 65251}},
+{17161, 18, 63215, {1, 1, 3, 11, 5, 9, 67, 41, 9, 79, 401, 379, 4107, 5231, 519, 47877, 17273, 137479}},
+{17162, 18, 63217, {1, 1, 3, 13, 25, 7, 9, 165, 103, 37, 1369, 933, 1119, 1025, 19767, 25765, 55487, 249709}},
+{17163, 18, 63229, {1, 3, 5, 5, 19, 53, 105, 135, 245, 957, 185, 2901, 1741, 10429, 747, 23365, 49363, 84095}},
+{17164, 18, 63237, {1, 1, 1, 15, 29, 17, 107, 193, 17, 447, 1261, 1935, 5749, 2303, 23287, 59883, 28655, 188055}},
+{17165, 18, 63259, {1, 1, 5, 9, 13, 27, 99, 253, 299, 481, 89, 3041, 1549, 15417, 30495, 2063, 53649, 219883}},
+{17166, 18, 63265, {1, 3, 3, 15, 19, 19, 7, 149, 67, 349, 789, 129, 2783, 2887, 28631, 26001, 62407, 151767}},
+{17167, 18, 63271, {1, 3, 3, 13, 7, 29, 65, 25, 93, 627, 301, 721, 7249, 13295, 19995, 33715, 36441, 157625}},
+{17168, 18, 63286, {1, 1, 1, 3, 29, 63, 85, 27, 507, 543, 1887, 3169, 4239, 4455, 22047, 15369, 48913, 192071}},
+{17169, 18, 63298, {1, 3, 7, 5, 9, 33, 125, 41, 7, 723, 1091, 3311, 8173, 3861, 31507, 42669, 68853, 60043}},
+{17170, 18, 63343, {1, 3, 1, 13, 13, 7, 121, 41, 181, 913, 371, 163, 7061, 8779, 18345, 41915, 1785, 107113}},
+{17171, 18, 63355, {1, 1, 1, 9, 13, 41, 23, 35, 157, 247, 1243, 1101, 5193, 4027, 29917, 44099, 46211, 162059}},
+{17172, 18, 63361, {1, 3, 1, 5, 15, 51, 3, 241, 131, 741, 1885, 2397, 5673, 9097, 9319, 15381, 55655, 207569}},
+{17173, 18, 63362, {1, 1, 3, 15, 25, 15, 69, 55, 435, 727, 1007, 375, 7871, 10437, 11011, 36711, 11269, 105159}},
+{17174, 18, 63379, {1, 3, 3, 13, 17, 1, 101, 189, 295, 185, 1715, 2609, 6767, 11751, 11469, 3951, 80743, 114439}},
+{17175, 18, 63397, {1, 3, 1, 7, 21, 41, 93, 39, 433, 917, 279, 161, 267, 10201, 26583, 30363, 110187, 46501}},
+{17176, 18, 63415, {1, 1, 7, 7, 13, 15, 89, 167, 365, 925, 107, 3537, 6815, 15251, 23149, 61821, 66569, 135353}},
+{17177, 18, 63421, {1, 1, 1, 3, 13, 59, 21, 255, 111, 603, 547, 465, 3001, 16055, 26389, 64301, 112751, 219279}},
+{17178, 18, 63463, {1, 1, 1, 15, 17, 3, 21, 49, 327, 349, 489, 957, 807, 11685, 23975, 34729, 100773, 223551}},
+{17179, 18, 63491, {1, 3, 5, 15, 19, 59, 63, 71, 233, 767, 1789, 3609, 5911, 3405, 7519, 3611, 92015, 126669}},
+{17180, 18, 63527, {1, 1, 1, 11, 7, 31, 79, 57, 115, 763, 1643, 3329, 7209, 1385, 15565, 64353, 60637, 59445}},
+{17181, 18, 63545, {1, 1, 3, 1, 13, 3, 47, 89, 507, 523, 1, 1391, 6973, 7267, 32527, 52631, 20775, 234503}},
+{17182, 18, 63553, {1, 3, 1, 9, 23, 23, 95, 57, 295, 857, 213, 1211, 3503, 3043, 24843, 16149, 118719, 171585}},
+{17183, 18, 63560, {1, 3, 1, 5, 1, 13, 63, 167, 305, 711, 759, 2521, 5051, 9125, 22917, 24647, 100777, 261137}},
+{17184, 18, 63563, {1, 1, 5, 9, 25, 19, 5, 225, 511, 543, 685, 733, 7249, 10447, 11115, 25927, 104327, 92861}},
+{17185, 18, 63566, {1, 3, 1, 7, 15, 7, 15, 83, 379, 461, 943, 317, 7735, 12655, 7549, 6371, 20901, 170331}},
+{17186, 18, 63589, {1, 1, 1, 13, 7, 17, 41, 51, 47, 15, 477, 1203, 819, 1615, 13805, 40147, 3967, 192647}},
+{17187, 18, 63599, {1, 3, 7, 11, 9, 11, 111, 75, 171, 833, 1503, 2325, 7279, 2687, 16499, 11547, 99409, 186429}},
+{17188, 18, 63601, {1, 1, 5, 3, 13, 21, 75, 17, 447, 647, 1309, 2297, 7911, 12093, 16237, 50831, 96123, 134479}},
+{17189, 18, 63608, {1, 1, 5, 15, 19, 29, 35, 255, 291, 437, 85, 2143, 3281, 3629, 29339, 28169, 46561, 236595}},
+{17190, 18, 63620, {1, 3, 7, 1, 31, 57, 125, 109, 317, 461, 681, 1379, 6387, 14971, 8451, 17655, 87619, 51721}},
+{17191, 18, 63654, {1, 3, 7, 1, 23, 33, 45, 149, 43, 465, 997, 601, 693, 6273, 12867, 25885, 81353, 60437}},
+{17192, 18, 63703, {1, 1, 7, 7, 31, 25, 113, 205, 481, 141, 1757, 587, 2981, 7637, 3869, 4151, 69541, 68587}},
+{17193, 18, 63719, {1, 1, 7, 13, 17, 31, 69, 247, 137, 79, 1221, 1693, 3747, 10711, 1671, 31587, 12139, 248585}},
+{17194, 18, 63758, {1, 1, 1, 3, 1, 61, 39, 139, 37, 79, 125, 1145, 7505, 10129, 29209, 52045, 99159, 195553}},
+{17195, 18, 63769, {1, 1, 5, 3, 13, 41, 13, 11, 167, 953, 1961, 3557, 871, 1687, 28479, 10621, 27533, 243519}},
+{17196, 18, 63782, {1, 1, 7, 7, 1, 35, 107, 227, 375, 225, 483, 1239, 7591, 8549, 7351, 62001, 70245, 102795}},
+{17197, 18, 63803, {1, 1, 1, 9, 29, 35, 15, 3, 337, 1017, 1065, 2107, 2457, 9455, 7069, 55081, 57887, 149679}},
+{17198, 18, 63811, {1, 1, 7, 1, 1, 1, 13, 63, 287, 895, 593, 1253, 4717, 10313, 10275, 22143, 59149, 38865}},
+{17199, 18, 63851, {1, 1, 3, 15, 27, 39, 73, 11, 509, 391, 1901, 503, 5523, 6777, 30849, 41301, 35067, 68443}},
+{17200, 18, 63854, {1, 3, 3, 15, 17, 57, 39, 229, 273, 917, 577, 3627, 3285, 4495, 28581, 34011, 38537, 194999}},
+{17201, 18, 63872, {1, 1, 7, 3, 17, 51, 91, 203, 161, 757, 581, 1625, 477, 8839, 16515, 43101, 121497, 23603}},
+{17202, 18, 63878, {1, 3, 3, 5, 19, 29, 55, 127, 283, 999, 1227, 1937, 4471, 11305, 8813, 40509, 78521, 175573}},
+{17203, 18, 63895, {1, 3, 3, 3, 5, 29, 33, 249, 25, 213, 1315, 393, 6967, 12751, 7485, 39561, 14801, 191921}},
+{17204, 18, 63917, {1, 3, 7, 9, 23, 15, 93, 69, 23, 239, 1993, 3375, 539, 14141, 10123, 33561, 127565, 181527}},
+{17205, 18, 63930, {1, 3, 3, 15, 13, 15, 65, 241, 83, 351, 1943, 1305, 7181, 11803, 31907, 63623, 5439, 150661}},
+{17206, 18, 63935, {1, 3, 7, 11, 13, 17, 17, 37, 409, 577, 973, 797, 1761, 5333, 13803, 22991, 29743, 53051}},
+{17207, 18, 63955, {1, 3, 5, 5, 27, 25, 91, 225, 411, 23, 877, 2487, 8061, 12337, 11471, 8857, 10791, 112699}},
+{17208, 18, 63964, {1, 1, 5, 3, 15, 1, 87, 249, 205, 1011, 2045, 1879, 4137, 5877, 12709, 5231, 74283, 124315}},
+{17209, 18, 63967, {1, 1, 7, 7, 31, 37, 117, 71, 139, 391, 1085, 4033, 3087, 3063, 19991, 8787, 96899, 17279}},
+{17210, 18, 63980, {1, 1, 7, 15, 19, 47, 45, 181, 303, 151, 337, 2557, 6131, 3161, 13097, 52777, 77783, 259817}},
+{17211, 18, 63985, {1, 1, 3, 3, 1, 55, 115, 227, 83, 591, 967, 4067, 3441, 243, 13443, 4043, 129365, 161459}},
+{17212, 18, 63992, {1, 1, 3, 15, 5, 23, 71, 31, 271, 585, 931, 909, 3375, 15063, 12111, 35811, 124047, 68225}},
+{17213, 18, 64021, {1, 1, 5, 11, 1, 59, 19, 193, 323, 489, 837, 3709, 1807, 11617, 30931, 33561, 2805, 100979}},
+{17214, 18, 64026, {1, 3, 5, 7, 27, 7, 71, 67, 167, 521, 1237, 2911, 3531, 2885, 4669, 25703, 87647, 36381}},
+{17215, 18, 64044, {1, 3, 3, 13, 13, 21, 97, 225, 477, 1023, 2029, 877, 3849, 4675, 17665, 19257, 9697, 168577}},
+{17216, 18, 64055, {1, 1, 7, 15, 25, 31, 19, 255, 45, 539, 1831, 2655, 7471, 12011, 12455, 3681, 123881, 234471}},
+{17217, 18, 64056, {1, 1, 3, 9, 17, 39, 105, 73, 271, 555, 987, 873, 5371, 12381, 13469, 54961, 125701, 194063}},
+{17218, 18, 64061, {1, 1, 5, 5, 7, 27, 15, 195, 121, 175, 991, 955, 5007, 11423, 1539, 21381, 79891, 162149}},
+{17219, 18, 64067, {1, 3, 1, 7, 25, 23, 69, 69, 177, 545, 481, 3503, 3721, 1077, 8763, 6919, 64743, 172311}},
+{17220, 18, 64081, {1, 1, 3, 15, 31, 5, 33, 45, 81, 795, 435, 399, 4591, 3741, 26493, 14791, 59529, 89989}},
+{17221, 18, 64100, {1, 1, 7, 13, 21, 29, 95, 75, 213, 59, 1635, 479, 441, 14667, 16389, 9139, 30955, 169895}},
+{17222, 18, 64109, {1, 3, 3, 3, 17, 61, 103, 85, 233, 287, 447, 2687, 4755, 9489, 1669, 10405, 58489, 170429}},
+{17223, 18, 64112, {1, 1, 5, 5, 13, 9, 63, 129, 321, 531, 393, 3353, 5309, 16375, 20473, 12595, 52239, 183647}},
+{17224, 18, 64118, {1, 1, 3, 7, 7, 31, 101, 253, 119, 325, 351, 2321, 1899, 14073, 8985, 13609, 32043, 33225}},
+{17225, 18, 64124, {1, 1, 3, 13, 7, 25, 73, 191, 399, 591, 819, 2859, 6053, 815, 30417, 5709, 18277, 121991}},
+{17226, 18, 64145, {1, 3, 3, 1, 7, 47, 7, 81, 451, 463, 699, 1857, 8169, 15649, 22693, 28673, 9717, 227583}},
+{17227, 18, 64151, {1, 3, 3, 3, 31, 45, 123, 205, 23, 901, 1003, 1149, 7481, 6925, 23845, 18573, 97047, 248957}},
+{17228, 18, 64203, {1, 1, 3, 3, 21, 9, 53, 241, 125, 583, 1055, 3981, 8113, 12477, 8455, 6289, 112253, 17321}},
+{17229, 18, 64208, {1, 1, 7, 3, 19, 5, 51, 111, 443, 283, 117, 2127, 4273, 2335, 20373, 2885, 57439, 56839}},
+{17230, 18, 64236, {1, 1, 5, 15, 7, 5, 65, 163, 27, 691, 1667, 69, 2459, 7477, 21349, 52417, 42299, 75965}},
+{17231, 18, 64254, {1, 1, 1, 13, 13, 19, 87, 223, 475, 205, 1113, 887, 2213, 5533, 15875, 36173, 53933, 200173}},
+{17232, 18, 64261, {1, 3, 3, 13, 23, 17, 93, 37, 391, 127, 873, 1445, 3007, 10863, 21245, 55025, 99275, 255329}},
+{17233, 18, 64280, {1, 3, 1, 15, 1, 47, 57, 5, 207, 825, 161, 539, 6151, 12829, 14121, 51217, 25547, 234303}},
+{17234, 18, 64296, {1, 1, 5, 1, 21, 63, 15, 83, 19, 817, 591, 3131, 889, 12451, 14363, 27295, 83877, 124701}},
+{17235, 18, 64313, {1, 1, 7, 7, 11, 21, 87, 85, 13, 555, 163, 9, 5973, 14749, 19585, 57287, 43421, 66301}},
+{17236, 18, 64314, {1, 3, 5, 5, 7, 33, 19, 7, 9, 819, 533, 2105, 4275, 10611, 30517, 35863, 84687, 245157}},
+{17237, 18, 64316, {1, 3, 5, 13, 3, 55, 111, 157, 235, 405, 39, 2191, 905, 3099, 245, 37371, 365, 257385}},
+{17238, 18, 64348, {1, 3, 3, 13, 29, 39, 125, 235, 213, 879, 497, 1659, 6689, 12165, 18621, 14657, 37079, 167867}},
+{17239, 18, 64352, {1, 1, 5, 15, 5, 5, 27, 197, 77, 477, 1115, 3369, 2253, 5757, 20855, 4473, 112501, 76881}},
+{17240, 18, 64355, {1, 3, 3, 13, 13, 61, 37, 97, 229, 743, 1381, 3979, 307, 319, 16765, 56295, 109303, 21361}},
+{17241, 18, 64361, {1, 1, 7, 11, 19, 7, 63, 145, 129, 899, 93, 1851, 7901, 8767, 15553, 13913, 4897, 129483}},
+{17242, 18, 64388, {1, 3, 5, 11, 7, 23, 19, 5, 465, 365, 883, 3563, 4395, 2759, 4273, 623, 75047, 249519}},
+{17243, 18, 64398, {1, 3, 1, 5, 29, 43, 75, 7, 509, 373, 359, 2041, 5957, 1251, 32431, 37803, 120915, 45137}},
+{17244, 18, 64403, {1, 3, 1, 5, 21, 9, 43, 1, 337, 743, 1359, 1629, 5117, 2499, 16129, 22831, 38795, 32137}},
+{17245, 18, 64419, {1, 3, 3, 7, 23, 57, 9, 31, 351, 559, 1729, 1461, 3037, 12685, 8899, 14859, 108851, 170195}},
+{17246, 18, 64421, {1, 1, 1, 15, 23, 57, 39, 23, 283, 487, 1055, 1265, 6781, 7955, 195, 37745, 66115, 56413}},
+{17247, 18, 64428, {1, 1, 3, 7, 27, 35, 57, 17, 137, 17, 905, 4033, 5775, 5305, 22975, 17547, 106297, 146287}},
+{17248, 18, 64453, {1, 1, 1, 3, 5, 39, 73, 151, 469, 523, 119, 539, 2817, 7783, 22957, 59937, 21331, 172437}},
+{17249, 18, 64463, {1, 1, 3, 13, 21, 1, 23, 109, 113, 257, 817, 1671, 6729, 1571, 15009, 48539, 94025, 160379}},
+{17250, 18, 64475, {1, 1, 1, 1, 31, 23, 83, 107, 225, 715, 949, 69, 2163, 4777, 7715, 25901, 82935, 81455}},
+{17251, 18, 64511, {1, 3, 5, 13, 29, 11, 61, 169, 241, 973, 315, 3991, 1389, 3293, 31123, 59419, 7359, 170929}},
+{17252, 18, 64537, {1, 1, 7, 3, 21, 15, 111, 41, 329, 513, 1175, 4037, 2747, 11465, 17253, 54055, 29409, 230925}},
+{17253, 18, 64576, {1, 3, 5, 15, 31, 17, 105, 45, 61, 339, 1387, 1021, 4499, 13671, 25521, 52081, 49153, 31587}},
+{17254, 18, 64579, {1, 3, 3, 3, 29, 17, 51, 103, 429, 849, 1759, 1267, 6255, 4631, 32643, 44977, 40875, 239457}},
+{17255, 18, 64581, {1, 1, 7, 15, 3, 11, 123, 157, 73, 151, 777, 3855, 1913, 969, 11821, 16889, 63503, 197305}},
+{17256, 18, 64606, {1, 3, 1, 5, 13, 49, 61, 209, 105, 523, 851, 3667, 7525, 5537, 12851, 42867, 50535, 131403}},
+{17257, 18, 64615, {1, 3, 1, 7, 13, 19, 107, 71, 479, 895, 405, 89, 1345, 5543, 12709, 6093, 97581, 20483}},
+{17258, 18, 64649, {1, 3, 3, 11, 3, 47, 117, 175, 175, 321, 1257, 365, 1193, 12813, 2713, 26941, 43605, 223323}},
+{17259, 18, 64655, {1, 1, 7, 1, 19, 35, 45, 143, 395, 255, 1599, 575, 2637, 1287, 27673, 48329, 57975, 44173}},
+{17260, 18, 64664, {1, 3, 5, 1, 1, 19, 107, 233, 465, 661, 91, 4007, 6409, 3399, 8175, 54171, 111417, 124955}},
+{17261, 18, 64667, {1, 1, 5, 13, 9, 27, 121, 225, 55, 761, 779, 3015, 6333, 10779, 26531, 57103, 33463, 90219}},
+{17262, 18, 64712, {1, 3, 1, 9, 17, 3, 85, 147, 111, 133, 869, 1833, 2401, 5811, 24415, 27095, 65529, 164121}},
+{17263, 18, 64715, {1, 1, 5, 13, 11, 37, 13, 83, 391, 909, 2013, 1327, 6697, 1711, 29265, 10607, 20127, 57873}},
+{17264, 18, 64718, {1, 3, 1, 11, 17, 17, 33, 101, 383, 837, 1769, 1711, 3735, 14777, 27101, 56853, 110643, 101917}},
+{17265, 18, 64741, {1, 3, 5, 13, 25, 7, 37, 99, 473, 211, 1469, 1827, 6307, 8835, 15853, 22027, 43095, 15817}},
+{17266, 18, 64766, {1, 3, 1, 5, 19, 13, 61, 193, 57, 359, 1277, 749, 5499, 11239, 20681, 48477, 7225, 259259}},
+{17267, 18, 64780, {1, 1, 1, 7, 27, 17, 79, 213, 307, 761, 429, 1519, 7483, 6007, 11251, 13263, 24851, 7919}},
+{17268, 18, 64788, {1, 1, 3, 5, 9, 37, 101, 149, 405, 413, 1213, 157, 3811, 4485, 13099, 32697, 75677, 127815}},
+{17269, 18, 64791, {1, 3, 3, 7, 29, 29, 13, 113, 45, 885, 1471, 3433, 2289, 4375, 815, 16741, 20933, 9763}},
+{17270, 18, 64795, {1, 3, 5, 15, 5, 3, 7, 37, 347, 41, 1977, 395, 6363, 3591, 21457, 31455, 60547, 108153}},
+{17271, 18, 64798, {1, 3, 5, 7, 19, 9, 113, 1, 241, 439, 731, 1591, 3347, 1295, 6635, 25267, 13239, 214669}},
+{17272, 18, 64816, {1, 1, 3, 5, 7, 7, 69, 77, 281, 851, 1533, 1, 7351, 3429, 29237, 54597, 11171, 66613}},
+{17273, 18, 64819, {1, 1, 7, 15, 29, 7, 59, 9, 105, 129, 1397, 3841, 3945, 4755, 19877, 11109, 17497, 225473}},
+{17274, 18, 64822, {1, 3, 7, 7, 15, 61, 3, 207, 97, 229, 1251, 101, 3157, 5729, 15579, 14849, 119119, 91891}},
+{17275, 18, 64833, {1, 3, 3, 9, 27, 15, 85, 221, 231, 577, 1787, 3489, 2393, 7593, 13175, 25561, 108505, 97267}},
+{17276, 18, 64836, {1, 3, 7, 13, 23, 3, 7, 85, 307, 899, 371, 3539, 3467, 7955, 9539, 53583, 125587, 30969}},
+{17277, 18, 64876, {1, 1, 5, 7, 7, 31, 115, 245, 375, 803, 1121, 3775, 3565, 15283, 25981, 24681, 34469, 172003}},
+{17278, 18, 64891, {1, 1, 5, 1, 31, 5, 5, 161, 153, 235, 1703, 2163, 1089, 16233, 6183, 25167, 102925, 36673}},
+{17279, 18, 64907, {1, 3, 3, 5, 1, 57, 59, 5, 87, 497, 151, 1731, 2727, 4583, 28165, 63053, 76003, 29259}},
+{17280, 18, 64943, {1, 1, 5, 7, 5, 21, 79, 111, 347, 879, 827, 3947, 4421, 9589, 23971, 11681, 104555, 226535}},
+{17281, 18, 64965, {1, 1, 5, 1, 17, 35, 105, 159, 391, 495, 1709, 3731, 261, 2359, 1413, 37105, 8979, 189381}},
+{17282, 18, 64977, {1, 3, 3, 1, 11, 23, 21, 213, 261, 755, 1503, 2369, 1765, 14531, 2605, 15609, 48691, 113059}},
+{17283, 18, 64999, {1, 3, 5, 1, 1, 55, 87, 197, 89, 391, 1157, 3523, 385, 5871, 13681, 29097, 101903, 184553}},
+{17284, 18, 65034, {1, 3, 7, 5, 17, 51, 87, 191, 495, 761, 1943, 1845, 2963, 13133, 22439, 20101, 96759, 215215}},
+{17285, 18, 65036, {1, 3, 5, 11, 23, 9, 53, 41, 229, 233, 2025, 2835, 2359, 4755, 3015, 48267, 20721, 61001}},
+{17286, 18, 65089, {1, 1, 7, 9, 27, 35, 45, 201, 137, 291, 151, 733, 6199, 3127, 3073, 14491, 95051, 12469}},
+{17287, 18, 65107, {1, 1, 1, 9, 7, 49, 73, 233, 239, 881, 1991, 695, 5947, 9377, 12027, 41137, 80217, 122961}},
+{17288, 18, 65110, {1, 1, 5, 11, 3, 15, 85, 203, 305, 945, 1007, 1831, 3999, 373, 21141, 63829, 91779, 122495}},
+{17289, 18, 65120, {1, 1, 1, 11, 23, 51, 127, 215, 441, 467, 229, 3071, 2731, 8813, 30155, 60289, 54531, 196187}},
+{17290, 18, 65132, {1, 3, 5, 15, 29, 31, 11, 129, 443, 649, 773, 3035, 7915, 13831, 31979, 5577, 42869, 153591}},
+{17291, 18, 65143, {1, 1, 3, 11, 21, 37, 23, 79, 153, 7, 1801, 441, 8189, 7235, 6311, 965, 71993, 81755}},
+{17292, 18, 65150, {1, 3, 5, 5, 23, 13, 93, 39, 247, 367, 811, 1381, 6809, 16219, 8755, 41923, 79873, 105781}},
+{17293, 18, 65177, {1, 3, 5, 9, 19, 43, 21, 229, 251, 187, 1047, 2295, 5529, 2965, 1507, 16185, 121183, 30551}},
+{17294, 18, 65201, {1, 3, 7, 9, 19, 11, 33, 213, 39, 811, 231, 1527, 6093, 1507, 3541, 37585, 78785, 215419}},
+{17295, 18, 65214, {1, 3, 7, 7, 11, 13, 109, 119, 175, 311, 719, 3127, 6351, 1909, 5441, 5411, 58751, 80875}},
+{17296, 18, 65234, {1, 1, 1, 7, 17, 35, 57, 139, 289, 137, 1919, 2131, 6145, 3953, 24887, 64737, 4677, 23833}},
+{17297, 18, 65240, {1, 1, 3, 13, 1, 21, 83, 243, 27, 69, 501, 3925, 3339, 13313, 27021, 38319, 76441, 146397}},
+{17298, 18, 65243, {1, 3, 7, 9, 15, 17, 97, 117, 505, 673, 1333, 3891, 7775, 6323, 12967, 17387, 19501, 68347}},
+{17299, 18, 65259, {1, 1, 1, 5, 27, 55, 43, 47, 399, 147, 1539, 2663, 5555, 11993, 8759, 33783, 8361, 78633}},
+{17300, 18, 65276, {1, 1, 1, 15, 1, 17, 21, 85, 129, 117, 339, 1319, 1119, 6869, 12913, 56873, 30795, 76849}},
+{17301, 18, 65287, {1, 1, 5, 5, 11, 1, 11, 175, 355, 737, 1367, 3089, 5993, 4377, 10325, 3817, 61735, 187689}},
+{17302, 18, 65306, {1, 3, 5, 5, 21, 41, 85, 219, 425, 611, 1219, 1849, 349, 925, 26185, 31591, 23855, 35549}},
+{17303, 18, 65311, {1, 1, 3, 5, 21, 3, 77, 25, 265, 949, 1979, 1561, 4243, 12437, 5215, 23445, 33295, 130385}},
+{17304, 18, 65321, {1, 1, 3, 1, 13, 7, 3, 81, 143, 735, 31, 1781, 1537, 10789, 11923, 61589, 75761, 178837}},
+{17305, 18, 65350, {1, 1, 7, 7, 11, 47, 55, 37, 39, 533, 1773, 3121, 183, 7193, 19403, 45757, 20457, 158437}},
+{17306, 18, 65364, {1, 1, 5, 5, 3, 15, 53, 41, 139, 529, 601, 2967, 4683, 3869, 13449, 30155, 85833, 190053}},
+{17307, 18, 65451, {1, 1, 5, 1, 11, 39, 85, 131, 349, 175, 267, 779, 923, 5905, 32727, 22055, 63087, 247607}},
+{17308, 18, 65488, {1, 3, 5, 7, 7, 59, 11, 49, 465, 617, 557, 251, 1303, 10369, 29207, 13457, 113591, 43717}},
+{17309, 18, 65510, {1, 3, 5, 3, 27, 39, 21, 157, 39, 891, 1833, 2887, 7395, 7965, 21771, 42675, 71705, 177323}},
+{17310, 18, 65528, {1, 3, 7, 7, 21, 51, 53, 83, 433, 889, 1033, 1701, 6285, 14335, 1683, 3637, 110241, 110355}},
+{17311, 18, 65533, {1, 1, 7, 7, 11, 23, 35, 63, 71, 867, 79, 2551, 1837, 773, 21093, 60433, 67305, 70731}},
+{17312, 18, 65553, {1, 3, 5, 11, 9, 25, 67, 23, 137, 75, 707, 2229, 6237, 9871, 29063, 30433, 112897, 68037}},
+{17313, 18, 65563, {1, 3, 7, 13, 1, 45, 119, 149, 487, 667, 1177, 2927, 1875, 11963, 20771, 1177, 2331, 244039}},
+{17314, 18, 65579, {1, 3, 3, 7, 19, 61, 89, 163, 91, 409, 1109, 1947, 1017, 12385, 13487, 45645, 64175, 184221}},
+{17315, 18, 65621, {1, 1, 1, 15, 13, 47, 21, 203, 341, 845, 443, 1891, 2591, 2721, 7515, 52161, 70359, 173139}},
+{17316, 18, 65625, {1, 3, 3, 11, 5, 3, 119, 179, 509, 33, 1909, 2531, 6713, 12447, 30157, 61019, 45857, 165557}},
+{17317, 18, 65635, {1, 3, 7, 5, 3, 47, 79, 55, 321, 71, 1917, 4053, 6603, 3079, 28133, 15611, 99161, 118279}},
+{17318, 18, 65644, {1, 1, 1, 7, 19, 13, 3, 31, 213, 705, 435, 2381, 991, 4719, 24473, 8907, 122013, 228081}},
+{17319, 18, 65690, {1, 1, 7, 11, 27, 15, 5, 123, 169, 197, 361, 3803, 2001, 14547, 22967, 27575, 118325, 130651}},
+{17320, 18, 65696, {1, 3, 3, 5, 29, 43, 77, 15, 463, 753, 695, 3489, 2023, 9913, 13029, 26621, 129393, 209439}},
+{17321, 18, 65705, {1, 1, 5, 15, 1, 39, 55, 129, 247, 729, 1537, 2529, 3981, 13153, 1505, 12743, 104173, 218423}},
+{17322, 18, 65716, {1, 3, 7, 3, 21, 3, 49, 173, 445, 821, 3, 2671, 1865, 1377, 7589, 65485, 96485, 80193}},
+{17323, 18, 65725, {1, 3, 3, 11, 7, 21, 99, 143, 333, 869, 1469, 1579, 1749, 2203, 18773, 47377, 103211, 238357}},
+{17324, 18, 65733, {1, 3, 5, 11, 11, 19, 25, 253, 229, 755, 101, 269, 6703, 5603, 23201, 57163, 28431, 159653}},
+{17325, 18, 65740, {1, 3, 5, 3, 3, 15, 45, 225, 325, 997, 1061, 883, 3885, 7633, 461, 44411, 52129, 84535}},
+{17326, 18, 65758, {1, 1, 7, 1, 27, 29, 51, 23, 473, 443, 117, 3021, 55, 7413, 7911, 3063, 47533, 234941}},
+{17327, 18, 65786, {1, 3, 3, 15, 19, 43, 37, 95, 249, 805, 603, 865, 2115, 6999, 9739, 59029, 12181, 211159}},
+{17328, 18, 65806, {1, 3, 7, 3, 3, 61, 105, 113, 11, 169, 1007, 689, 2553, 14561, 17473, 38249, 41225, 80021}},
+{17329, 18, 65834, {1, 3, 7, 11, 5, 47, 69, 49, 457, 931, 435, 1423, 411, 15163, 3171, 29143, 101153, 240869}},
+{17330, 18, 65844, {1, 3, 7, 1, 17, 1, 13, 45, 155, 551, 1783, 3583, 2767, 2761, 18019, 61635, 104527, 123817}},
+{17331, 18, 65866, {1, 1, 5, 11, 9, 43, 101, 205, 233, 689, 1247, 2903, 3117, 12261, 11827, 50403, 103727, 35533}},
+{17332, 18, 65895, {1, 1, 5, 13, 23, 37, 121, 195, 133, 265, 1517, 823, 5933, 13917, 6363, 8533, 58443, 178549}},
+{17333, 18, 65902, {1, 1, 7, 9, 29, 1, 3, 195, 221, 877, 71, 473, 1173, 15285, 6057, 60005, 92401, 65357}},
+{17334, 18, 65953, {1, 3, 7, 1, 5, 25, 15, 207, 455, 447, 1125, 3731, 1289, 867, 22111, 38893, 70779, 88277}},
+{17335, 18, 65954, {1, 1, 1, 13, 31, 19, 15, 179, 183, 351, 1197, 1929, 3569, 12251, 17641, 4097, 24141, 186857}},
+{17336, 18, 65983, {1, 1, 1, 9, 19, 9, 125, 23, 431, 225, 943, 479, 2615, 443, 30977, 10889, 17107, 116819}},
+{17337, 18, 65985, {1, 3, 1, 9, 9, 13, 85, 123, 85, 857, 125, 3149, 1105, 3687, 2313, 38749, 52131, 259511}},
+{17338, 18, 66003, {1, 3, 5, 7, 27, 33, 57, 105, 511, 871, 1089, 2311, 3291, 2245, 3365, 30211, 62549, 56207}},
+{17339, 18, 66010, {1, 1, 7, 11, 1, 19, 75, 37, 139, 173, 391, 317, 2575, 11887, 4289, 32275, 43487, 487}},
+{17340, 18, 66025, {1, 1, 7, 1, 11, 3, 9, 217, 343, 35, 59, 93, 1343, 5043, 14869, 63717, 40983, 235373}},
+{17341, 18, 66050, {1, 1, 3, 5, 15, 13, 93, 247, 417, 179, 307, 3299, 4383, 5491, 21271, 37155, 32289, 75737}},
+{17342, 18, 66074, {1, 3, 3, 9, 3, 39, 63, 243, 305, 729, 9, 3317, 3301, 13165, 20437, 36505, 32977, 2761}},
+{17343, 18, 66076, {1, 3, 7, 5, 3, 37, 61, 109, 351, 641, 1699, 2517, 2637, 4995, 27365, 56971, 53609, 14373}},
+{17344, 18, 66097, {1, 3, 1, 15, 31, 53, 127, 123, 219, 1003, 1425, 1201, 5303, 10369, 21481, 26987, 42541, 37855}},
+{17345, 18, 66132, {1, 3, 3, 13, 9, 29, 35, 111, 395, 791, 1619, 2647, 713, 15955, 19145, 33883, 65215, 166267}},
+{17346, 18, 66158, {1, 1, 7, 11, 17, 5, 45, 249, 421, 273, 411, 2885, 7027, 11933, 24847, 36969, 124701, 214931}},
+{17347, 18, 66175, {1, 1, 3, 1, 27, 41, 125, 83, 327, 643, 223, 151, 6709, 15949, 125, 13275, 90405, 15759}},
+{17348, 18, 66185, {1, 1, 5, 15, 19, 45, 55, 109, 497, 1011, 1363, 1937, 3697, 7475, 10533, 65325, 29681, 76275}},
+{17349, 18, 66199, {1, 1, 1, 3, 23, 17, 59, 209, 229, 151, 1199, 279, 191, 8993, 25939, 13885, 113477, 166961}},
+{17350, 18, 66206, {1, 3, 5, 1, 19, 61, 27, 129, 103, 721, 1451, 2803, 5879, 3523, 15443, 4047, 95927, 50339}},
+{17351, 18, 66222, {1, 1, 1, 11, 27, 9, 53, 47, 331, 185, 1337, 3429, 807, 3341, 14871, 11035, 50651, 243843}},
+{17352, 18, 66227, {1, 3, 5, 11, 7, 57, 125, 15, 271, 811, 1873, 3093, 7841, 5761, 19955, 571, 123319, 149465}},
+{17353, 18, 66241, {1, 3, 1, 3, 31, 61, 71, 47, 477, 273, 167, 1069, 3513, 1463, 2667, 22097, 60367, 246045}},
+{17354, 18, 66272, {1, 1, 1, 11, 1, 55, 35, 233, 37, 659, 1517, 411, 2981, 10339, 21857, 33701, 44393, 6861}},
+{17355, 18, 66324, {1, 1, 5, 7, 11, 43, 109, 205, 103, 315, 1925, 2109, 6307, 7915, 19793, 61167, 27963, 251913}},
+{17356, 18, 66424, {1, 1, 5, 11, 5, 63, 107, 219, 53, 251, 1053, 2035, 77, 15885, 22011, 3945, 91, 204899}},
+{17357, 18, 66460, {1, 3, 7, 13, 21, 45, 51, 53, 99, 831, 1421, 3171, 4241, 14105, 26161, 45071, 2813, 54339}},
+{17358, 18, 66464, {1, 3, 5, 1, 3, 61, 43, 141, 355, 699, 11, 2203, 8055, 14815, 24597, 65201, 32689, 70167}},
+{17359, 18, 66481, {1, 3, 1, 5, 11, 27, 109, 239, 199, 23, 375, 1477, 3197, 4401, 29901, 46623, 79593, 133143}},
+{17360, 18, 66482, {1, 1, 1, 3, 23, 9, 63, 103, 41, 177, 1365, 1971, 5937, 13055, 27713, 13535, 47371, 57841}},
+{17361, 18, 66523, {1, 1, 5, 5, 19, 15, 5, 21, 307, 65, 215, 3801, 4149, 6565, 10249, 63541, 30867, 12129}},
+{17362, 18, 66526, {1, 3, 3, 9, 11, 1, 107, 99, 235, 331, 1479, 1365, 2557, 9545, 25767, 12461, 6471, 184643}},
+{17363, 18, 66532, {1, 3, 3, 5, 17, 13, 103, 223, 95, 955, 1479, 1825, 705, 5311, 28531, 22787, 118899, 181829}},
+{17364, 18, 66539, {1, 3, 7, 1, 5, 59, 65, 11, 251, 419, 659, 2559, 5445, 4221, 5871, 51845, 33925, 167037}},
+{17365, 18, 66541, {1, 3, 5, 13, 15, 45, 35, 181, 325, 293, 1897, 3321, 6081, 9919, 27641, 9407, 35263, 231009}},
+{17366, 18, 66573, {1, 3, 3, 3, 3, 35, 85, 33, 293, 777, 1945, 3771, 6967, 12353, 2737, 12501, 127359, 163591}},
+{17367, 18, 66582, {1, 3, 7, 9, 13, 7, 119, 107, 309, 811, 1113, 2465, 4867, 4295, 565, 59159, 94587, 119761}},
+{17368, 18, 66591, {1, 3, 3, 1, 1, 31, 61, 49, 461, 635, 233, 175, 6237, 10463, 17847, 54925, 115675, 260575}},
+{17369, 18, 66615, {1, 3, 5, 15, 25, 17, 61, 155, 235, 483, 1771, 2903, 3163, 2525, 17153, 54701, 49521, 11911}},
+{17370, 18, 66622, {1, 3, 3, 5, 1, 35, 51, 23, 187, 107, 177, 1381, 165, 6149, 10841, 3619, 107811, 188811}},
+{17371, 18, 66629, {1, 1, 5, 9, 7, 35, 5, 233, 43, 913, 939, 2195, 1369, 5355, 7941, 26075, 66813, 227623}},
+{17372, 18, 66641, {1, 3, 7, 11, 5, 43, 97, 211, 427, 875, 1179, 3631, 7989, 2419, 17209, 15789, 128209, 224117}},
+{17373, 18, 66712, {1, 1, 1, 7, 17, 7, 109, 255, 111, 883, 371, 3481, 6031, 14665, 5905, 28735, 113003, 327}},
+{17374, 18, 66724, {1, 3, 5, 3, 5, 61, 7, 155, 87, 861, 39, 3163, 179, 15493, 16403, 18755, 116157, 233185}},
+{17375, 18, 66731, {1, 3, 5, 5, 23, 45, 67, 205, 395, 417, 1235, 669, 5097, 6823, 31483, 61395, 36073, 24183}},
+{17376, 18, 66745, {1, 1, 3, 1, 11, 35, 123, 171, 125, 759, 197, 907, 2273, 3623, 31861, 60071, 91857, 158011}},
+{17377, 18, 66759, {1, 3, 7, 11, 19, 19, 25, 25, 167, 429, 1565, 3179, 5453, 15731, 30727, 32111, 63685, 113309}},
+{17378, 18, 66808, {1, 3, 7, 9, 15, 33, 67, 225, 495, 19, 1881, 1357, 4311, 9547, 18717, 20749, 8819, 209979}},
+{17379, 18, 66814, {1, 3, 5, 3, 13, 47, 107, 153, 461, 815, 1521, 2361, 7721, 10631, 2799, 62321, 59755, 170803}},
+{17380, 18, 66821, {1, 3, 7, 5, 25, 61, 5, 235, 71, 349, 1555, 3419, 1159, 2027, 17391, 29849, 47145, 122057}},
+{17381, 18, 66831, {1, 1, 5, 11, 19, 19, 101, 45, 333, 553, 1431, 4077, 2629, 15997, 19793, 65521, 124287, 174675}},
+{17382, 18, 66834, {1, 3, 7, 11, 25, 39, 103, 219, 375, 27, 227, 1061, 445, 14803, 18883, 49191, 33303, 114467}},
+{17383, 18, 66879, {1, 1, 5, 7, 3, 13, 117, 29, 387, 891, 371, 2199, 7023, 13671, 26291, 61563, 2733, 16093}},
+{17384, 18, 66884, {1, 3, 5, 11, 29, 5, 17, 249, 149, 777, 1817, 319, 19, 12321, 15241, 29069, 58381, 157467}},
+{17385, 18, 66899, {1, 3, 7, 9, 29, 17, 81, 141, 201, 383, 429, 3675, 69, 8155, 22821, 60707, 127015, 248279}},
+{17386, 18, 66901, {1, 3, 7, 9, 25, 5, 11, 27, 423, 987, 99, 3599, 4849, 4513, 32119, 34301, 6327, 249457}},
+{17387, 18, 66924, {1, 3, 3, 7, 13, 25, 71, 227, 307, 985, 665, 3097, 6713, 3823, 6357, 58199, 84057, 28055}},
+{17388, 18, 66929, {1, 3, 5, 7, 19, 21, 93, 45, 159, 527, 493, 59, 1111, 1415, 1949, 28525, 50343, 11039}},
+{17389, 18, 66942, {1, 3, 5, 13, 17, 35, 79, 229, 449, 533, 235, 3445, 8153, 15473, 12975, 53909, 24589, 237049}},
+{17390, 18, 66985, {1, 1, 7, 5, 3, 53, 93, 33, 339, 423, 497, 2691, 6125, 3931, 25357, 27509, 92509, 227209}},
+{17391, 18, 66986, {1, 1, 7, 3, 13, 49, 111, 179, 449, 279, 827, 1481, 2477, 6867, 18079, 6261, 30885, 205675}},
+{17392, 18, 66994, {1, 3, 7, 7, 11, 9, 13, 105, 367, 639, 1307, 1617, 4759, 8387, 8909, 13715, 56599, 113259}},
+{17393, 18, 67066, {1, 1, 3, 3, 15, 17, 103, 125, 205, 67, 999, 3965, 907, 13235, 15275, 58457, 66889, 227279}},
+{17394, 18, 67075, {1, 3, 3, 3, 11, 35, 99, 81, 421, 75, 1757, 2413, 5655, 1227, 4019, 14503, 20719, 224807}},
+{17395, 18, 67099, {1, 1, 7, 11, 17, 17, 109, 203, 331, 813, 987, 2925, 1601, 13617, 29, 8235, 95129, 117987}},
+{17396, 18, 67130, {1, 3, 7, 5, 5, 33, 105, 191, 183, 899, 1949, 2923, 2473, 3435, 8097, 35615, 10109, 62563}},
+{17397, 18, 67173, {1, 1, 7, 13, 5, 25, 21, 159, 487, 415, 1507, 2161, 649, 14425, 2605, 8357, 92441, 87323}},
+{17398, 18, 67183, {1, 3, 7, 15, 3, 23, 87, 209, 407, 765, 975, 3859, 675, 6351, 18703, 44919, 57155, 134961}},
+{17399, 18, 67186, {1, 3, 5, 15, 7, 59, 77, 37, 235, 565, 1707, 3531, 6733, 2223, 12621, 59523, 83547, 172355}},
+{17400, 18, 67197, {1, 3, 7, 5, 23, 15, 57, 217, 151, 333, 1033, 2549, 303, 1455, 5329, 20187, 55415, 166093}},
+{17401, 18, 67201, {1, 3, 1, 13, 21, 27, 1, 85, 335, 201, 135, 2603, 291, 10573, 28411, 1059, 129871, 98303}},
+{17402, 18, 67208, {1, 1, 3, 5, 23, 61, 123, 169, 503, 629, 711, 2795, 2291, 13273, 32703, 63377, 72809, 214927}},
+{17403, 18, 67221, {1, 3, 5, 13, 31, 11, 115, 133, 443, 709, 263, 3739, 2777, 11545, 19137, 61285, 64065, 214477}},
+{17404, 18, 67238, {1, 3, 1, 11, 29, 25, 3, 5, 385, 613, 1277, 1445, 1643, 15137, 28041, 47713, 122051, 62915}},
+{17405, 18, 67252, {1, 3, 5, 11, 3, 11, 1, 137, 457, 577, 783, 1745, 5, 5817, 26569, 50751, 14075, 246219}},
+{17406, 18, 67256, {1, 1, 1, 9, 7, 9, 105, 27, 167, 939, 799, 2773, 6427, 15579, 1975, 10695, 111429, 227105}},
+{17407, 18, 67270, {1, 3, 1, 11, 23, 23, 73, 103, 103, 61, 1743, 3061, 8127, 15893, 21223, 43549, 103659, 89129}},
+{17408, 18, 67288, {1, 1, 7, 13, 5, 43, 59, 235, 139, 961, 839, 3843, 1317, 4903, 21043, 15479, 115065, 112531}},
+{17409, 18, 67318, {1, 3, 1, 3, 19, 15, 57, 145, 193, 321, 1919, 385, 125, 15517, 14243, 62845, 38995, 120045}},
+{17410, 18, 67329, {1, 3, 3, 7, 17, 61, 77, 75, 267, 203, 1911, 2599, 1797, 761, 28101, 58603, 107755, 158689}},
+{17411, 18, 67349, {1, 1, 5, 11, 15, 21, 71, 227, 377, 361, 2013, 129, 6271, 1421, 6009, 52261, 113389, 74915}},
+{17412, 18, 67369, {1, 1, 5, 7, 3, 39, 27, 49, 97, 885, 651, 1633, 3445, 3415, 20167, 26667, 52997, 221391}},
+{17413, 18, 67392, {1, 1, 7, 9, 7, 59, 95, 127, 479, 871, 845, 2951, 673, 6385, 10057, 2605, 78529, 230771}},
+{17414, 18, 67435, {1, 3, 5, 7, 31, 15, 53, 125, 223, 711, 875, 429, 7237, 4005, 2153, 26865, 63205, 144125}},
+{17415, 18, 67473, {1, 1, 7, 9, 1, 57, 19, 189, 67, 423, 1937, 37, 4925, 15503, 25969, 20419, 59921, 58119}},
+{17416, 18, 67496, {1, 1, 7, 7, 31, 51, 99, 189, 21, 1011, 1551, 3529, 7617, 15805, 11365, 43123, 84785, 203703}},
+{17417, 18, 67507, {1, 1, 3, 15, 3, 63, 9, 67, 399, 151, 253, 1839, 1365, 16295, 13145, 29211, 48681, 177643}},
+{17418, 18, 67514, {1, 1, 1, 5, 13, 37, 1, 21, 435, 483, 939, 535, 1505, 10879, 7027, 5599, 63261, 158573}},
+{17419, 18, 67536, {1, 1, 7, 15, 13, 39, 113, 209, 213, 1017, 1197, 285, 4221, 6831, 13383, 2265, 34313, 160879}},
+{17420, 18, 67555, {1, 3, 7, 15, 25, 23, 95, 217, 141, 681, 451, 1275, 4957, 10197, 21375, 50905, 11087, 96135}},
+{17421, 18, 67598, {1, 3, 1, 11, 17, 35, 87, 15, 57, 777, 1429, 615, 681, 8437, 23981, 51781, 112169, 198471}},
+{17422, 18, 67615, {1, 3, 1, 5, 21, 37, 113, 105, 123, 327, 549, 1641, 7697, 2127, 5709, 8351, 56787, 260157}},
+{17423, 18, 67625, {1, 3, 7, 15, 19, 17, 51, 15, 367, 89, 1635, 353, 4855, 1551, 7197, 27403, 11259, 176029}},
+{17424, 18, 67645, {1, 3, 1, 1, 27, 9, 3, 35, 213, 31, 885, 797, 7077, 15641, 22509, 35193, 112411, 157335}},
+{17425, 18, 67651, {1, 1, 5, 1, 5, 9, 101, 149, 169, 581, 1927, 197, 5935, 6361, 3915, 15541, 69575, 102451}},
+{17426, 18, 67663, {1, 3, 3, 13, 23, 63, 45, 205, 271, 17, 707, 937, 2547, 12019, 8559, 26163, 58117, 138625}},
+{17427, 18, 67672, {1, 1, 3, 1, 19, 63, 125, 175, 253, 629, 1121, 3701, 7755, 61, 13037, 39417, 6179, 261923}},
+{17428, 18, 67682, {1, 1, 5, 1, 25, 63, 27, 245, 371, 657, 157, 3821, 3279, 8977, 9065, 35611, 27325, 205737}},
+{17429, 18, 67699, {1, 3, 7, 15, 7, 57, 19, 191, 1, 927, 1379, 2579, 4335, 7163, 4877, 51435, 17309, 100173}},
+{17430, 18, 67718, {1, 1, 1, 5, 21, 59, 107, 195, 317, 691, 541, 69, 7235, 2175, 25191, 23913, 126369, 9263}},
+{17431, 18, 67780, {1, 3, 5, 15, 17, 7, 67, 27, 263, 855, 1065, 973, 6705, 10729, 8719, 32741, 59207, 249107}},
+{17432, 18, 67795, {1, 3, 1, 1, 21, 23, 115, 119, 351, 207, 1691, 1105, 7479, 3877, 24439, 29017, 34171, 133797}},
+{17433, 18, 67804, {1, 3, 3, 3, 11, 23, 39, 165, 99, 1023, 309, 3933, 4235, 3891, 27237, 30887, 34363, 175017}},
+{17434, 18, 67818, {1, 3, 1, 5, 17, 33, 79, 105, 253, 515, 823, 1783, 1523, 2095, 10355, 8929, 51001, 112815}},
+{17435, 18, 67832, {1, 3, 7, 15, 11, 27, 123, 161, 279, 541, 1343, 1009, 6015, 8565, 27031, 233, 2153, 179243}},
+{17436, 18, 67941, {1, 1, 7, 7, 1, 53, 1, 33, 75, 57, 723, 3855, 3301, 14941, 6637, 25181, 103441, 208339}},
+{17437, 18, 67984, {1, 3, 7, 13, 3, 23, 11, 75, 55, 19, 1181, 3451, 4901, 2621, 18323, 42395, 95701, 237753}},
+{17438, 18, 68044, {1, 1, 1, 5, 1, 1, 123, 203, 367, 71, 1897, 295, 6719, 2647, 7135, 34511, 79853, 58351}},
+{17439, 18, 68059, {1, 3, 3, 7, 7, 63, 87, 91, 223, 265, 927, 3843, 1703, 11633, 8077, 26425, 46573, 181201}},
+{17440, 18, 68062, {1, 3, 3, 3, 1, 51, 3, 99, 37, 251, 1739, 2813, 3955, 8745, 4425, 42419, 124177, 173997}},
+{17441, 18, 68065, {1, 3, 5, 15, 9, 19, 11, 207, 123, 287, 1703, 2155, 2729, 4541, 4925, 4735, 77159, 97911}},
+{17442, 18, 68071, {1, 3, 3, 15, 23, 31, 35, 33, 507, 315, 1071, 3001, 7569, 11749, 3183, 6989, 68637, 177803}},
+{17443, 18, 68072, {1, 3, 5, 1, 31, 1, 113, 39, 295, 263, 1113, 619, 5523, 15385, 24115, 24233, 91943, 129299}},
+{17444, 18, 68085, {1, 1, 5, 11, 9, 57, 89, 49, 67, 601, 1277, 2275, 6349, 4141, 28397, 47061, 28143, 126291}},
+{17445, 18, 68090, {1, 3, 7, 15, 11, 63, 123, 187, 305, 1009, 1509, 2569, 2235, 8233, 27351, 53437, 34353, 105799}},
+{17446, 18, 68101, {1, 1, 3, 1, 13, 9, 11, 169, 427, 171, 1031, 633, 4275, 1173, 11233, 57997, 107753, 257337}},
+{17447, 18, 68102, {1, 3, 5, 5, 3, 39, 49, 233, 309, 999, 1275, 85, 1663, 16275, 9145, 18439, 59055, 249657}},
+{17448, 18, 68106, {1, 1, 3, 7, 11, 55, 73, 75, 115, 397, 945, 3657, 6847, 7341, 21305, 30119, 65675, 169281}},
+{17449, 18, 68164, {1, 1, 7, 7, 3, 5, 31, 179, 183, 479, 329, 217, 1077, 6893, 23425, 21903, 34293, 184819}},
+{17450, 18, 68191, {1, 1, 3, 3, 7, 63, 97, 255, 289, 917, 1881, 3829, 2433, 3473, 11045, 37739, 73349, 171899}},
+{17451, 18, 68192, {1, 3, 5, 5, 27, 23, 61, 151, 353, 667, 1889, 2323, 3261, 15999, 24225, 35265, 97301, 75743}},
+{17452, 18, 68195, {1, 3, 7, 1, 19, 41, 81, 61, 461, 275, 131, 2665, 5615, 1719, 21047, 42025, 97725, 196587}},
+{17453, 18, 68209, {1, 1, 7, 11, 3, 5, 47, 107, 397, 237, 1795, 3049, 5317, 14147, 15299, 50469, 83855, 75685}},
+{17454, 18, 68245, {1, 1, 7, 7, 19, 31, 39, 153, 225, 591, 1547, 3755, 3219, 15823, 4015, 30977, 63999, 198023}},
+{17455, 18, 68246, {1, 3, 1, 1, 17, 57, 91, 3, 425, 465, 735, 719, 2955, 3003, 6669, 14335, 32137, 82265}},
+{17456, 18, 68274, {1, 3, 1, 9, 13, 25, 93, 187, 119, 735, 447, 3387, 5111, 6525, 28241, 37643, 99023, 58551}},
+{17457, 18, 68293, {1, 1, 7, 1, 23, 15, 105, 89, 109, 743, 2007, 3131, 4839, 3285, 14681, 47097, 69531, 104647}},
+{17458, 18, 68294, {1, 1, 5, 7, 27, 33, 85, 109, 165, 569, 511, 3223, 2201, 2869, 30457, 42585, 125187, 83115}},
+{17459, 18, 68322, {1, 1, 7, 13, 1, 39, 55, 69, 279, 757, 425, 1317, 2403, 10711, 3341, 33491, 5607, 214161}},
+{17460, 18, 68353, {1, 3, 3, 9, 23, 57, 109, 9, 473, 323, 1371, 657, 5039, 1947, 12787, 29099, 81887, 44039}},
+{17461, 18, 68359, {1, 3, 1, 9, 21, 49, 39, 71, 493, 611, 1465, 3965, 7509, 5315, 4095, 21865, 123533, 148467}},
+{17462, 18, 68377, {1, 1, 7, 5, 15, 45, 67, 109, 143, 423, 205, 849, 1291, 245, 26275, 62873, 69177, 173705}},
+{17463, 18, 68401, {1, 3, 7, 13, 3, 13, 103, 45, 171, 919, 903, 2171, 5025, 14855, 895, 36937, 37643, 30311}},
+{17464, 18, 68422, {1, 3, 1, 5, 31, 35, 67, 111, 201, 183, 375, 905, 5705, 8839, 31551, 22525, 53013, 34189}},
+{17465, 18, 68434, {1, 1, 3, 7, 25, 11, 85, 231, 285, 957, 1731, 1267, 8179, 14195, 18405, 8489, 32503, 86257}},
+{17466, 18, 68443, {1, 3, 7, 5, 29, 7, 73, 15, 501, 909, 1325, 793, 4479, 12137, 30871, 36243, 109781, 7235}},
+{17467, 18, 68445, {1, 1, 3, 15, 13, 13, 75, 221, 497, 921, 1939, 2791, 5277, 6257, 11129, 109, 27549, 44901}},
+{17468, 18, 68476, {1, 1, 7, 3, 21, 9, 35, 113, 101, 15, 545, 2429, 5869, 11379, 14427, 28605, 108313, 220523}},
+{17469, 18, 68492, {1, 3, 5, 5, 21, 31, 79, 101, 11, 687, 609, 3741, 1259, 1529, 10185, 49863, 86529, 5147}},
+{17470, 18, 68504, {1, 3, 1, 5, 5, 49, 105, 213, 435, 201, 511, 525, 5219, 9503, 32023, 25407, 2493, 51165}},
+{17471, 18, 68525, {1, 1, 5, 9, 9, 61, 67, 107, 351, 519, 1373, 1261, 1069, 4325, 9579, 37117, 71759, 17601}},
+{17472, 18, 68540, {1, 1, 7, 7, 27, 63, 63, 229, 239, 291, 1813, 3831, 8091, 2553, 18445, 60707, 88855, 224325}},
+{17473, 18, 68543, {1, 1, 5, 7, 15, 23, 109, 7, 409, 447, 185, 3535, 4643, 13431, 11107, 48771, 95843, 155889}},
+{17474, 18, 68555, {1, 3, 3, 11, 9, 47, 13, 31, 83, 837, 1661, 2283, 299, 13161, 25305, 6079, 107237, 58477}},
+{17475, 18, 68563, {1, 3, 7, 15, 3, 31, 21, 245, 105, 141, 703, 71, 1887, 9345, 15719, 37737, 58431, 195997}},
+{17476, 18, 68576, {1, 1, 1, 13, 25, 21, 23, 67, 349, 581, 1585, 809, 3955, 4621, 25989, 25633, 107229, 193271}},
+{17477, 18, 68581, {1, 1, 5, 3, 15, 57, 111, 147, 243, 575, 851, 3461, 5171, 4203, 21855, 59579, 90509, 16897}},
+{17478, 18, 68617, {1, 1, 5, 13, 5, 45, 83, 59, 253, 261, 1277, 3179, 6397, 4277, 6629, 10979, 55759, 3033}},
+{17479, 18, 68631, {1, 1, 1, 9, 25, 1, 127, 159, 273, 357, 1343, 3209, 649, 6631, 1365, 40813, 98955, 181679}},
+{17480, 18, 68656, {1, 3, 1, 11, 1, 9, 67, 5, 41, 661, 863, 3769, 2737, 7261, 26829, 43093, 113025, 127975}},
+{17481, 18, 68666, {1, 1, 3, 3, 7, 5, 77, 207, 125, 625, 437, 1059, 2635, 1099, 25567, 63759, 97575, 231313}},
+{17482, 18, 68714, {1, 3, 7, 5, 21, 41, 11, 177, 489, 405, 1831, 1373, 6267, 11275, 23613, 55565, 120353, 98771}},
+{17483, 18, 68743, {1, 1, 3, 11, 15, 55, 103, 185, 493, 755, 1235, 3143, 4355, 4887, 11245, 60103, 4023, 184729}},
+{17484, 18, 68761, {1, 3, 1, 1, 23, 5, 103, 117, 269, 101, 2013, 1781, 6445, 8753, 15041, 13993, 28753, 47133}},
+{17485, 18, 68764, {1, 3, 7, 5, 9, 23, 1, 203, 19, 535, 1445, 1713, 5503, 11555, 6195, 35797, 55663, 10187}},
+{17486, 18, 68767, {1, 3, 5, 1, 15, 3, 125, 225, 447, 269, 1663, 1823, 4309, 12243, 16689, 3889, 41111, 123355}},
+{17487, 18, 68768, {1, 1, 1, 5, 21, 33, 83, 147, 243, 101, 1085, 121, 4939, 6081, 22621, 52995, 103047, 82531}},
+{17488, 18, 68786, {1, 3, 5, 3, 21, 3, 5, 81, 431, 191, 1973, 3675, 6691, 8687, 31619, 51669, 95541, 110447}},
+{17489, 18, 68788, {1, 1, 1, 15, 1, 11, 83, 145, 75, 133, 967, 2837, 5111, 6099, 9119, 53661, 128647, 40557}},
+{17490, 18, 68848, {1, 1, 1, 7, 3, 57, 101, 231, 255, 117, 1903, 2133, 3867, 11299, 647, 58853, 22153, 135959}},
+{17491, 18, 68851, {1, 3, 5, 5, 9, 19, 89, 229, 313, 421, 201, 953, 2487, 6283, 1305, 33421, 20933, 164841}},
+{17492, 18, 68914, {1, 1, 3, 3, 1, 45, 93, 165, 343, 577, 1329, 3019, 2727, 14397, 7123, 63347, 45525, 35133}},
+{17493, 18, 68946, {1, 3, 5, 5, 19, 1, 33, 55, 49, 1003, 1567, 2539, 7461, 14641, 7655, 37499, 65525, 84961}},
+{17494, 18, 68952, {1, 3, 5, 5, 29, 3, 77, 39, 251, 791, 215, 3779, 1589, 3577, 22299, 24133, 105449, 257157}},
+{17495, 18, 68973, {1, 3, 1, 5, 7, 23, 109, 209, 35, 571, 1047, 3453, 3657, 11713, 19379, 57101, 29943, 60909}},
+{17496, 18, 69001, {1, 1, 7, 11, 17, 63, 15, 175, 333, 831, 1447, 1991, 3339, 2519, 30127, 51481, 71935, 144995}},
+{17497, 18, 69016, {1, 3, 1, 11, 13, 51, 17, 67, 43, 209, 789, 1285, 5655, 5841, 10203, 32053, 15721, 211725}},
+{17498, 18, 69035, {1, 1, 5, 7, 31, 49, 69, 255, 325, 819, 1769, 1961, 7403, 1241, 2241, 40425, 14839, 178969}},
+{17499, 18, 69037, {1, 1, 3, 9, 1, 5, 9, 35, 167, 865, 337, 1079, 6195, 10139, 19215, 57607, 122437, 197147}},
+{17500, 18, 69049, {1, 1, 1, 15, 23, 7, 47, 155, 345, 547, 333, 3747, 961, 1397, 17067, 33385, 48253, 138611}},
+{17501, 18, 69052, {1, 1, 7, 9, 29, 27, 81, 183, 153, 171, 1125, 1929, 1047, 12463, 1543, 42981, 126163, 203259}},
+{17502, 18, 69058, {1, 1, 5, 3, 1, 41, 123, 213, 7, 179, 1, 3527, 1437, 3545, 2025, 5325, 27097, 187823}},
+{17503, 18, 69063, {1, 1, 7, 1, 19, 5, 111, 251, 431, 91, 1437, 1155, 335, 9587, 18287, 23937, 123331, 3939}},
+{17504, 18, 69075, {1, 1, 1, 9, 13, 59, 75, 219, 225, 313, 525, 2003, 7829, 7063, 22123, 4263, 95491, 9375}},
+{17505, 18, 69112, {1, 3, 1, 1, 27, 29, 71, 189, 169, 301, 165, 2967, 5147, 7127, 2191, 34259, 66605, 149603}},
+{17506, 18, 69117, {1, 3, 5, 13, 29, 57, 105, 31, 495, 311, 1161, 2109, 1471, 1275, 12761, 58379, 46365, 229935}},
+{17507, 18, 69124, {1, 1, 7, 3, 7, 49, 125, 189, 309, 399, 1361, 3969, 2177, 8171, 26623, 41855, 2809, 5825}},
+{17508, 18, 69127, {1, 3, 5, 7, 17, 21, 77, 101, 37, 661, 1743, 2243, 823, 12431, 26931, 7163, 108093, 191305}},
+{17509, 18, 69134, {1, 1, 7, 5, 27, 55, 109, 119, 13, 727, 421, 3469, 1137, 6125, 5107, 52733, 102891, 147425}},
+{17510, 18, 69139, {1, 1, 3, 5, 17, 45, 17, 211, 137, 21, 689, 1487, 233, 9845, 6499, 52617, 73081, 198137}},
+{17511, 18, 69161, {1, 3, 7, 1, 25, 27, 67, 7, 161, 633, 729, 807, 7371, 7301, 29499, 45939, 110565, 219491}},
+{17512, 18, 69196, {1, 3, 3, 13, 17, 7, 55, 211, 103, 981, 1809, 1913, 5705, 14011, 7405, 13893, 92053, 17997}},
+{17513, 18, 69224, {1, 1, 1, 1, 15, 9, 75, 37, 5, 443, 157, 2749, 5587, 16087, 14953, 26793, 21229, 226879}},
+{17514, 18, 69238, {1, 3, 3, 3, 9, 13, 113, 7, 255, 647, 235, 1713, 525, 8579, 20873, 49565, 43869, 145823}},
+{17515, 18, 69301, {1, 1, 5, 15, 9, 1, 119, 189, 73, 321, 1045, 467, 1565, 14381, 22683, 7939, 44337, 231901}},
+{17516, 18, 69316, {1, 1, 3, 13, 21, 61, 35, 105, 425, 395, 381, 1205, 3631, 8099, 23723, 29435, 94683, 180367}},
+{17517, 18, 69325, {1, 3, 3, 13, 19, 15, 59, 111, 355, 165, 857, 3131, 5037, 2527, 17533, 53563, 621, 89837}},
+{17518, 18, 69334, {1, 3, 3, 11, 11, 41, 3, 75, 179, 325, 897, 3141, 75, 1735, 493, 1123, 126763, 68645}},
+{17519, 18, 69347, {1, 3, 5, 7, 19, 61, 9, 99, 101, 583, 1967, 621, 1869, 10693, 2025, 62797, 85727, 212309}},
+{17520, 18, 69359, {1, 3, 1, 13, 23, 47, 15, 29, 199, 889, 423, 3995, 1655, 10753, 25301, 55551, 94829, 205833}},
+{17521, 18, 69381, {1, 1, 1, 1, 21, 1, 91, 237, 195, 721, 881, 1155, 4109, 10367, 1873, 6851, 13295, 182363}},
+{17522, 18, 69388, {1, 1, 5, 15, 19, 35, 37, 197, 137, 255, 93, 681, 949, 15183, 24785, 39357, 65547, 149013}},
+{17523, 18, 69393, {1, 3, 3, 3, 27, 27, 95, 239, 171, 513, 655, 1629, 4577, 3005, 1681, 2581, 59995, 83981}},
+{17524, 18, 69409, {1, 3, 3, 7, 29, 33, 111, 85, 437, 297, 1563, 2411, 6171, 2043, 17625, 59093, 995, 211599}},
+{17525, 18, 69422, {1, 3, 1, 13, 19, 35, 33, 9, 57, 153, 819, 2017, 5879, 13559, 23135, 25981, 41091, 50975}},
+{17526, 18, 69453, {1, 3, 5, 11, 23, 53, 11, 123, 119, 57, 1775, 3457, 7939, 4999, 10771, 23571, 30099, 17361}},
+{17527, 18, 69459, {1, 1, 7, 11, 27, 13, 7, 215, 7, 1009, 1967, 1845, 6679, 13781, 21797, 18755, 47131, 245907}},
+{17528, 18, 69481, {1, 1, 1, 3, 19, 47, 35, 13, 287, 349, 439, 3125, 2387, 12483, 3833, 29399, 27037, 30235}},
+{17529, 18, 69487, {1, 3, 1, 15, 17, 41, 15, 21, 499, 87, 1899, 2835, 1919, 925, 4525, 12935, 25021, 106657}},
+{17530, 18, 69490, {1, 1, 1, 13, 17, 59, 73, 75, 443, 199, 1871, 3447, 4517, 8395, 16661, 30655, 17871, 231337}},
+{17531, 18, 69495, {1, 1, 7, 1, 1, 53, 17, 49, 259, 77, 917, 631, 6061, 12291, 17715, 49761, 70699, 68313}},
+{17532, 18, 69501, {1, 1, 3, 9, 13, 27, 67, 149, 229, 347, 1397, 3457, 6047, 13117, 11, 18121, 70323, 36441}},
+{17533, 18, 69511, {1, 3, 5, 7, 27, 13, 69, 177, 451, 87, 647, 3797, 5433, 3137, 20213, 9809, 126877, 55243}},
+{17534, 18, 69512, {1, 3, 7, 13, 21, 57, 73, 157, 173, 631, 1527, 337, 5605, 8041, 2181, 19567, 19829, 63353}},
+{17535, 18, 69532, {1, 3, 3, 7, 11, 5, 111, 161, 247, 553, 435, 3883, 5639, 10889, 8953, 58297, 15197, 99711}},
+{17536, 18, 69542, {1, 1, 7, 13, 11, 29, 71, 251, 387, 1003, 1275, 763, 67, 10597, 5995, 53677, 4683, 2157}},
+{17537, 18, 69560, {1, 1, 3, 9, 23, 27, 93, 209, 325, 517, 297, 3215, 4359, 395, 10377, 36967, 69803, 190037}},
+{17538, 18, 69565, {1, 1, 1, 3, 27, 61, 21, 229, 469, 3, 387, 523, 4753, 2267, 9879, 32113, 60837, 76205}},
+{17539, 18, 69571, {1, 3, 1, 7, 31, 31, 67, 15, 161, 699, 713, 2973, 2007, 693, 21823, 57549, 28989, 157879}},
+{17540, 18, 69611, {1, 3, 1, 1, 3, 63, 111, 61, 311, 685, 1029, 345, 6763, 16217, 14505, 9777, 3513, 160985}},
+{17541, 18, 69633, {1, 1, 1, 11, 5, 25, 13, 79, 337, 3, 1997, 3489, 7621, 12115, 9221, 7953, 19067, 52697}},
+{17542, 18, 69640, {1, 1, 1, 3, 19, 3, 85, 127, 475, 391, 293, 2249, 1211, 1185, 17133, 6753, 65517, 98157}},
+{17543, 18, 69667, {1, 1, 5, 9, 11, 31, 57, 107, 315, 983, 1117, 2189, 4813, 9925, 26635, 30589, 32989, 44195}},
+{17544, 18, 69669, {1, 1, 7, 7, 21, 1, 1, 221, 421, 199, 539, 3981, 4627, 15655, 12621, 20427, 11619, 187185}},
+{17545, 18, 69679, {1, 1, 7, 5, 13, 19, 49, 31, 55, 35, 1847, 3173, 475, 15245, 30907, 50075, 130837, 87283}},
+{17546, 18, 69688, {1, 1, 7, 15, 13, 47, 13, 17, 169, 185, 1411, 1689, 2339, 2159, 10591, 52283, 26785, 255707}},
+{17547, 18, 69699, {1, 3, 5, 7, 3, 29, 7, 83, 329, 747, 1755, 1067, 2565, 2437, 12309, 15043, 97589, 69409}},
+{17548, 18, 69756, {1, 3, 3, 9, 19, 49, 9, 231, 427, 131, 485, 1637, 1129, 14723, 19071, 47997, 74613, 171539}},
+{17549, 18, 69759, {1, 1, 1, 1, 5, 17, 105, 39, 313, 407, 1321, 3013, 8035, 4395, 15917, 21105, 53599, 21341}},
+{17550, 18, 69770, {1, 3, 1, 15, 7, 35, 5, 153, 485, 1019, 713, 1891, 5023, 13885, 15911, 48215, 81719, 228189}},
+{17551, 18, 69772, {1, 1, 3, 3, 19, 3, 103, 55, 221, 847, 27, 1653, 4887, 3617, 30235, 42353, 67007, 21443}},
+{17552, 18, 69826, {1, 1, 7, 15, 15, 39, 65, 189, 251, 411, 1953, 1187, 141, 14919, 7763, 50879, 2569, 63467}},
+{17553, 18, 69840, {1, 1, 7, 1, 15, 3, 37, 133, 11, 745, 697, 3755, 1233, 2009, 25597, 40661, 40743, 198117}},
+{17554, 18, 69846, {1, 1, 7, 15, 5, 17, 13, 253, 197, 491, 1499, 2141, 6803, 13833, 27297, 385, 54341, 64305}},
+{17555, 18, 69868, {1, 3, 5, 7, 3, 11, 19, 193, 441, 575, 1649, 1821, 2621, 15803, 7343, 37361, 16467, 60629}},
+{17556, 18, 69885, {1, 3, 3, 11, 11, 29, 109, 1, 83, 475, 1913, 1975, 1289, 5221, 24221, 7479, 26683, 203435}},
+{17557, 18, 69946, {1, 1, 3, 13, 3, 35, 119, 131, 323, 413, 147, 4009, 3167, 11161, 30523, 65223, 109859, 239317}},
+{17558, 18, 69966, {1, 3, 1, 11, 25, 17, 103, 165, 437, 163, 1141, 105, 3655, 8105, 20859, 50727, 27915, 19309}},
+{17559, 18, 69973, {1, 3, 3, 11, 9, 59, 17, 135, 131, 781, 675, 2865, 7287, 11431, 3717, 56691, 54971, 83433}},
+{17560, 18, 69977, {1, 1, 1, 11, 3, 1, 59, 35, 299, 927, 1761, 823, 287, 13271, 30321, 32895, 45961, 23151}},
+{17561, 18, 69980, {1, 3, 3, 7, 11, 3, 11, 115, 241, 497, 1359, 1789, 6677, 2683, 21145, 58185, 46131, 17591}},
+{17562, 18, 69984, {1, 3, 1, 3, 17, 5, 65, 169, 247, 1001, 1183, 1801, 759, 2797, 28721, 7549, 112463, 127451}},
+{17563, 18, 69994, {1, 1, 1, 11, 1, 49, 5, 227, 333, 793, 759, 2845, 6261, 6325, 6581, 35853, 39737, 21457}},
+{17564, 18, 70024, {1, 1, 1, 3, 7, 17, 81, 105, 453, 207, 1113, 301, 4933, 14715, 18815, 29165, 85251, 209171}},
+{17565, 18, 70044, {1, 3, 1, 13, 3, 25, 7, 109, 249, 649, 1009, 937, 659, 14605, 13325, 26003, 45507, 166837}},
+{17566, 18, 70053, {1, 3, 7, 11, 19, 57, 55, 213, 261, 325, 761, 3167, 6823, 15039, 13329, 30195, 52103, 27877}},
+{17567, 18, 70086, {1, 3, 3, 11, 31, 45, 3, 185, 225, 143, 651, 327, 4263, 6005, 31577, 57779, 90485, 48393}},
+{17568, 18, 70113, {1, 1, 3, 13, 9, 21, 97, 63, 285, 531, 1275, 175, 693, 3735, 15137, 62193, 80533, 196545}},
+{17569, 18, 70120, {1, 1, 1, 11, 5, 25, 101, 111, 101, 17, 1999, 3709, 19, 5087, 20151, 4781, 88417, 186293}},
+{17570, 18, 70131, {1, 1, 5, 7, 31, 37, 39, 85, 451, 189, 1521, 619, 5021, 2601, 32447, 43513, 8317, 170611}},
+{17571, 18, 70150, {1, 1, 7, 1, 25, 45, 33, 111, 443, 719, 1869, 3619, 5751, 2649, 27823, 55465, 113203, 23875}},
+{17572, 18, 70178, {1, 3, 5, 15, 19, 47, 49, 241, 75, 395, 307, 1001, 137, 7029, 21661, 39159, 94129, 106693}},
+{17573, 18, 70198, {1, 3, 7, 1, 7, 35, 85, 27, 285, 975, 565, 2119, 5861, 9229, 15877, 25017, 10551, 155357}},
+{17574, 18, 70227, {1, 3, 3, 5, 29, 41, 17, 159, 211, 571, 907, 1745, 6541, 11643, 4441, 54599, 83359, 57227}},
+{17575, 18, 70285, {1, 3, 7, 5, 19, 11, 37, 191, 75, 443, 1833, 1715, 6949, 2477, 31161, 15647, 84305, 82887}},
+{17576, 18, 70288, {1, 1, 3, 9, 29, 35, 87, 11, 147, 443, 1659, 2457, 1615, 16135, 10729, 31583, 111583, 52607}},
+{17577, 18, 70291, {1, 3, 7, 1, 7, 47, 55, 133, 53, 23, 225, 2689, 3075, 12435, 8337, 37065, 58631, 247415}},
+{17578, 18, 70309, {1, 3, 3, 9, 23, 39, 5, 17, 353, 443, 627, 1609, 5277, 3899, 31111, 5935, 25445, 161043}},
+{17579, 18, 70334, {1, 3, 3, 11, 31, 11, 97, 99, 37, 169, 1361, 689, 5481, 5935, 11957, 36761, 105641, 250905}},
+{17580, 18, 70339, {1, 1, 7, 15, 31, 33, 3, 201, 125, 649, 315, 497, 7715, 2331, 9081, 16073, 88459, 70475}},
+{17581, 18, 70381, {1, 1, 7, 13, 25, 25, 39, 193, 185, 253, 495, 1143, 3745, 3459, 10935, 22029, 70213, 245827}},
+{17582, 18, 70413, {1, 3, 3, 11, 1, 47, 93, 27, 117, 755, 1837, 4045, 4839, 3413, 21395, 41905, 6505, 158029}},
+{17583, 18, 70414, {1, 3, 5, 5, 3, 41, 23, 207, 3, 409, 1635, 3511, 899, 747, 10623, 44933, 62439, 75577}},
+{17584, 18, 70481, {1, 3, 7, 15, 1, 15, 113, 175, 43, 513, 515, 1295, 1903, 9961, 20995, 57319, 40649, 22799}},
+{17585, 18, 70488, {1, 1, 5, 9, 7, 25, 99, 167, 117, 547, 777, 3819, 4409, 13465, 3963, 53355, 67895, 58007}},
+{17586, 18, 70493, {1, 1, 5, 9, 25, 9, 11, 113, 455, 563, 143, 1507, 4055, 6805, 25027, 37645, 475, 193193}},
+{17587, 18, 70515, {1, 1, 1, 11, 15, 27, 123, 199, 229, 27, 1285, 4013, 6541, 11203, 23705, 56821, 59665, 151109}},
+{17588, 18, 70540, {1, 1, 3, 1, 31, 19, 27, 129, 235, 407, 865, 2723, 5387, 7727, 2309, 45787, 118107, 199907}},
+{17589, 18, 70543, {1, 1, 5, 15, 17, 1, 21, 167, 165, 203, 745, 825, 7993, 15191, 13731, 13417, 543, 201511}},
+{17590, 18, 70558, {1, 3, 1, 1, 29, 49, 45, 81, 321, 755, 1319, 633, 4889, 7809, 6305, 58233, 20213, 144915}},
+{17591, 18, 70568, {1, 1, 3, 13, 1, 31, 73, 173, 111, 961, 1995, 3827, 879, 5567, 31103, 13227, 126611, 204507}},
+{17592, 18, 70582, {1, 1, 3, 7, 21, 3, 75, 137, 125, 981, 1991, 1167, 1249, 3821, 19503, 52855, 122329, 68717}},
+{17593, 18, 70593, {1, 1, 1, 13, 17, 17, 69, 167, 327, 635, 427, 2125, 7499, 9715, 24097, 39361, 64301, 63411}},
+{17594, 18, 70596, {1, 1, 1, 1, 31, 57, 55, 31, 289, 251, 823, 2301, 5965, 3381, 479, 39545, 93051, 68683}},
+{17595, 18, 70613, {1, 1, 3, 3, 15, 27, 117, 37, 29, 851, 1891, 3507, 6279, 323, 11451, 57961, 41487, 188359}},
+{17596, 18, 70620, {1, 1, 5, 1, 25, 55, 125, 207, 129, 849, 589, 1381, 3395, 645, 1157, 29285, 105423, 104429}},
+{17597, 18, 70647, {1, 1, 7, 7, 9, 47, 41, 103, 473, 395, 883, 1087, 2827, 9685, 6313, 15461, 39803, 254865}},
+{17598, 18, 70666, {1, 1, 7, 3, 17, 55, 71, 119, 159, 185, 1415, 3033, 3045, 1403, 18349, 2727, 123995, 45953}},
+{17599, 18, 70710, {1, 1, 3, 15, 17, 11, 19, 25, 483, 29, 1329, 1779, 2885, 6655, 28327, 42255, 87555, 211051}},
+{17600, 18, 70719, {1, 3, 5, 11, 29, 19, 43, 141, 157, 87, 1091, 3505, 3139, 11919, 12123, 31581, 116229, 167875}},
+{17601, 18, 70721, {1, 3, 1, 5, 25, 55, 113, 219, 491, 607, 1641, 3833, 3153, 1881, 16027, 39923, 38551, 204819}},
+{17602, 18, 70722, {1, 1, 5, 3, 7, 9, 73, 181, 305, 211, 1699, 983, 3051, 11643, 12445, 44827, 74613, 199699}},
+{17603, 18, 70742, {1, 1, 3, 5, 23, 21, 115, 49, 311, 205, 963, 1357, 4013, 8357, 7065, 47757, 7937, 249935}},
+{17604, 18, 70757, {1, 1, 1, 9, 23, 61, 21, 165, 9, 829, 457, 3975, 5831, 10901, 15871, 36769, 45899, 162083}},
+{17605, 18, 70764, {1, 1, 3, 3, 25, 41, 91, 45, 37, 939, 299, 3815, 6433, 3121, 10585, 62125, 51333, 171615}},
+{17606, 18, 70781, {1, 1, 5, 11, 1, 1, 39, 45, 141, 803, 1493, 1151, 6243, 8683, 30223, 53661, 7949, 197291}},
+{17607, 18, 70795, {1, 1, 3, 1, 17, 35, 29, 253, 395, 933, 1015, 3431, 139, 9095, 30745, 39747, 58837, 28517}},
+{17608, 18, 70803, {1, 1, 5, 3, 21, 17, 105, 21, 249, 387, 1985, 951, 6323, 8221, 24601, 57367, 18751, 240661}},
+{17609, 18, 70809, {1, 1, 7, 9, 5, 21, 23, 149, 243, 501, 935, 855, 1821, 15885, 2239, 39091, 93615, 31411}},
+{17610, 18, 70821, {1, 1, 1, 3, 23, 11, 43, 5, 65, 193, 1723, 3253, 7533, 12987, 571, 56073, 125061, 97117}},
+{17611, 18, 70846, {1, 1, 1, 13, 13, 21, 113, 79, 115, 867, 777, 2199, 501, 2913, 18697, 14959, 18369, 41631}},
+{17612, 18, 70882, {1, 1, 7, 13, 13, 53, 101, 165, 447, 995, 587, 201, 1701, 6429, 8647, 59265, 27321, 110841}},
+{17613, 18, 70887, {1, 3, 1, 3, 25, 35, 67, 95, 173, 877, 1133, 3027, 2321, 12517, 4313, 24469, 40313, 253095}},
+{17614, 18, 70940, {1, 1, 1, 9, 17, 33, 103, 141, 259, 963, 1975, 2979, 5017, 15689, 30659, 55145, 73737, 43539}},
+{17615, 18, 70961, {1, 3, 1, 15, 7, 7, 7, 1, 267, 415, 1591, 17, 2451, 13415, 6993, 16631, 90019, 237161}},
+{17616, 18, 70996, {1, 1, 7, 11, 11, 37, 107, 143, 263, 49, 1391, 3269, 6139, 1413, 26557, 16369, 86789, 89151}},
+{17617, 18, 71012, {1, 1, 7, 13, 27, 41, 3, 169, 453, 547, 157, 3219, 4711, 9805, 10657, 8121, 40229, 247825}},
+{17618, 18, 71046, {1, 3, 3, 3, 25, 25, 109, 253, 67, 901, 259, 1159, 6161, 6763, 19669, 42775, 74089, 69821}},
+{17619, 18, 71057, {1, 3, 7, 15, 11, 25, 91, 137, 247, 851, 511, 1847, 1179, 411, 9545, 31275, 46201, 169677}},
+{17620, 18, 71060, {1, 1, 5, 3, 3, 61, 19, 167, 491, 765, 1997, 3267, 883, 15439, 27581, 24865, 128245, 130055}},
+{17621, 18, 71063, {1, 1, 3, 9, 17, 61, 7, 109, 325, 347, 1109, 889, 2995, 4763, 21551, 60137, 91833, 126989}},
+{17622, 18, 71079, {1, 3, 3, 7, 5, 17, 61, 107, 209, 577, 885, 2611, 1471, 7549, 16199, 12319, 48865, 242229}},
+{17623, 18, 71080, {1, 3, 5, 1, 5, 49, 85, 177, 213, 583, 857, 179, 1805, 4297, 5835, 61923, 22741, 261983}},
+{17624, 18, 71111, {1, 3, 1, 13, 1, 1, 83, 227, 457, 375, 567, 1563, 2085, 8153, 12563, 44561, 115487, 188351}},
+{17625, 18, 71118, {1, 3, 1, 9, 15, 39, 127, 135, 181, 967, 1495, 3187, 7463, 9651, 26261, 57435, 42069, 48549}},
+{17626, 18, 71129, {1, 3, 1, 7, 5, 31, 111, 19, 19, 855, 273, 2089, 6001, 2799, 26013, 6625, 75623, 150185}},
+{17627, 18, 71136, {1, 1, 7, 1, 31, 19, 15, 159, 35, 791, 1005, 3947, 7031, 41, 28807, 45299, 37761, 101191}},
+{17628, 18, 71142, {1, 3, 5, 3, 15, 7, 7, 67, 329, 367, 843, 2309, 3023, 5369, 21561, 18881, 14395, 193369}},
+{17629, 18, 71145, {1, 3, 3, 11, 21, 53, 3, 251, 87, 131, 563, 847, 8049, 1639, 30103, 30461, 108427, 125197}},
+{17630, 18, 71151, {1, 1, 1, 5, 21, 45, 79, 229, 29, 133, 1873, 261, 4221, 3091, 25569, 11219, 70693, 227025}},
+{17631, 18, 71163, {1, 3, 1, 5, 17, 9, 75, 101, 155, 311, 789, 821, 7361, 3791, 18511, 57607, 97647, 42107}},
+{17632, 18, 71218, {1, 3, 1, 11, 21, 39, 33, 179, 7, 775, 55, 3779, 6163, 3575, 27535, 32363, 9169, 57133}},
+{17633, 18, 71223, {1, 3, 7, 3, 19, 33, 19, 11, 173, 175, 219, 3585, 1115, 15693, 23481, 45669, 94149, 19531}},
+{17634, 18, 71232, {1, 1, 5, 11, 11, 49, 29, 217, 229, 757, 1031, 3833, 4235, 13535, 8765, 20707, 52851, 9037}},
+{17635, 18, 71237, {1, 3, 1, 13, 25, 61, 65, 111, 95, 533, 1235, 2947, 3239, 9513, 11395, 9321, 117535, 228289}},
+{17636, 18, 71272, {1, 1, 1, 3, 19, 33, 13, 233, 331, 811, 1931, 1109, 7705, 3129, 19757, 44325, 97903, 165311}},
+{17637, 18, 71323, {1, 1, 3, 15, 13, 55, 57, 81, 257, 613, 1305, 653, 6059, 4935, 15707, 4717, 1859, 109265}},
+{17638, 18, 71339, {1, 1, 7, 15, 15, 19, 19, 91, 213, 311, 1651, 2215, 6985, 2989, 11961, 28647, 111163, 217187}},
+{17639, 18, 71341, {1, 3, 3, 5, 15, 31, 45, 193, 119, 11, 511, 3155, 5989, 813, 32655, 41531, 121007, 24733}},
+{17640, 18, 71349, {1, 3, 7, 1, 19, 63, 61, 11, 225, 677, 1323, 1655, 7607, 15691, 27083, 56743, 116167, 250413}},
+{17641, 18, 71368, {1, 1, 1, 15, 7, 25, 27, 213, 171, 1011, 1483, 119, 6849, 12527, 20601, 35701, 68377, 245669}},
+{17642, 18, 71379, {1, 3, 7, 5, 27, 5, 7, 117, 127, 871, 631, 3395, 1501, 4839, 1857, 45769, 107597, 90385}},
+{17643, 18, 71395, {1, 1, 3, 13, 1, 15, 49, 69, 479, 919, 881, 3069, 5609, 12795, 30225, 14411, 122847, 75569}},
+{17644, 18, 71407, {1, 1, 5, 9, 1, 15, 91, 207, 235, 667, 321, 2047, 841, 16049, 12499, 8799, 8245, 42199}},
+{17645, 18, 71421, {1, 3, 7, 15, 11, 19, 99, 163, 331, 953, 791, 3443, 3215, 8025, 1999, 43685, 72595, 153185}},
+{17646, 18, 71430, {1, 3, 1, 13, 25, 23, 17, 133, 59, 233, 151, 1971, 3611, 3951, 16979, 991, 73325, 158475}},
+{17647, 18, 71436, {1, 3, 5, 11, 1, 53, 123, 81, 285, 457, 1183, 489, 939, 3069, 15845, 24799, 81301, 105187}},
+{17648, 18, 71454, {1, 3, 5, 1, 11, 5, 61, 151, 5, 813, 1347, 1107, 4915, 4035, 18709, 20909, 60569, 55007}},
+{17649, 18, 71467, {1, 3, 3, 7, 27, 41, 79, 193, 471, 415, 937, 2561, 1669, 9213, 21145, 44917, 64763, 33195}},
+{17650, 18, 71472, {1, 3, 7, 13, 31, 5, 71, 237, 419, 957, 1741, 2829, 5879, 8143, 8717, 48995, 114465, 110295}},
+{17651, 18, 71478, {1, 1, 7, 3, 7, 23, 83, 161, 381, 313, 383, 2813, 333, 4647, 18321, 10437, 111645, 55509}},
+{17652, 18, 71481, {1, 1, 5, 9, 23, 1, 83, 121, 245, 37, 1097, 1437, 3891, 2727, 30775, 27649, 95571, 216245}},
+{17653, 18, 71501, {1, 1, 5, 7, 1, 43, 59, 253, 329, 421, 791, 3945, 2599, 2243, 11121, 37761, 27223, 176867}},
+{17654, 18, 71519, {1, 3, 5, 5, 25, 59, 85, 155, 367, 291, 1025, 1415, 7871, 14191, 23249, 32233, 93253, 177869}},
+{17655, 18, 71530, {1, 1, 1, 9, 21, 41, 111, 241, 177, 999, 779, 2827, 1683, 6405, 16133, 26523, 102567, 190313}},
+{17656, 18, 71550, {1, 3, 3, 15, 13, 59, 69, 239, 231, 511, 1675, 147, 4041, 3723, 29191, 24913, 15601, 198141}},
+{17657, 18, 71573, {1, 3, 3, 9, 17, 29, 1, 107, 243, 509, 1949, 205, 1693, 6339, 31591, 61527, 128043, 222497}},
+{17658, 18, 71593, {1, 3, 7, 3, 21, 7, 87, 57, 9, 209, 1831, 2189, 5523, 8509, 23687, 46221, 87469, 146815}},
+{17659, 18, 71608, {1, 3, 7, 9, 5, 45, 51, 207, 401, 681, 469, 1951, 793, 16379, 32143, 55457, 91787, 178569}},
+{17660, 18, 71619, {1, 3, 3, 9, 19, 15, 121, 143, 243, 795, 1839, 2411, 7175, 11535, 31995, 4157, 20111, 92653}},
+{17661, 18, 71622, {1, 3, 1, 1, 1, 5, 47, 107, 455, 429, 1411, 2375, 2823, 14657, 16297, 21893, 115257, 50343}},
+{17662, 18, 71636, {1, 3, 5, 9, 19, 63, 55, 197, 281, 797, 1539, 2601, 4497, 1631, 26583, 23819, 104553, 27285}},
+{17663, 18, 71650, {1, 1, 3, 9, 23, 41, 123, 37, 327, 789, 1711, 1299, 6735, 7243, 30635, 21251, 56081, 65623}},
+{17664, 18, 71655, {1, 3, 7, 15, 25, 49, 89, 231, 133, 1003, 351, 765, 7115, 16239, 1141, 44063, 31519, 233719}},
+{17665, 18, 71685, {1, 3, 7, 3, 13, 37, 93, 83, 59, 539, 1185, 525, 705, 993, 1113, 1871, 60817, 254075}},
+{17666, 18, 71703, {1, 3, 7, 11, 25, 33, 23, 21, 141, 451, 25, 1321, 5139, 8947, 10305, 30175, 43123, 113049}},
+{17667, 18, 71714, {1, 3, 5, 5, 17, 1, 125, 211, 143, 637, 1175, 1149, 6775, 11091, 12503, 5537, 35379, 30045}},
+{17668, 18, 71748, {1, 1, 1, 15, 17, 31, 123, 33, 279, 831, 1247, 2305, 1033, 3201, 231, 23173, 34453, 66617}},
+{17669, 18, 71758, {1, 3, 3, 1, 3, 1, 23, 115, 421, 553, 273, 4091, 5965, 7521, 18393, 31229, 78533, 243921}},
+{17670, 18, 71766, {1, 1, 7, 15, 15, 29, 73, 165, 391, 215, 1801, 45, 7451, 6969, 27897, 36599, 103647, 145165}},
+{17671, 18, 71772, {1, 3, 3, 13, 5, 7, 67, 81, 477, 301, 1397, 921, 3777, 12431, 14753, 50555, 24497, 52995}},
+{17672, 18, 71785, {1, 1, 5, 5, 27, 21, 91, 155, 405, 347, 1135, 3701, 2471, 577, 3927, 52605, 1725, 25803}},
+{17673, 18, 71794, {1, 3, 1, 3, 15, 57, 117, 175, 437, 13, 1821, 649, 899, 1295, 2753, 2183, 47923, 163407}},
+{17674, 18, 71796, {1, 3, 5, 9, 23, 15, 103, 179, 233, 787, 715, 3751, 3321, 2069, 8299, 43417, 96549, 180737}},
+{17675, 18, 71803, {1, 3, 7, 9, 1, 41, 81, 205, 141, 707, 397, 763, 4797, 8843, 3311, 37425, 43873, 131491}},
+{17676, 18, 71809, {1, 1, 5, 3, 9, 29, 123, 163, 15, 871, 159, 2615, 6987, 471, 25653, 11295, 94481, 195409}},
+{17677, 18, 71858, {1, 3, 7, 3, 13, 7, 9, 59, 59, 381, 2027, 2639, 59, 7977, 14505, 34327, 99113, 157439}},
+{17678, 18, 71863, {1, 1, 5, 9, 27, 13, 87, 85, 443, 531, 1069, 3479, 6547, 13943, 13711, 11007, 37395, 190293}},
+{17679, 18, 71878, {1, 3, 7, 9, 19, 47, 95, 229, 395, 979, 359, 1799, 7389, 14377, 19371, 56785, 6699, 215433}},
+{17680, 18, 71895, {1, 1, 1, 5, 21, 15, 59, 17, 281, 585, 293, 3029, 2539, 16089, 19, 34757, 115811, 235565}},
+{17681, 18, 71899, {1, 1, 7, 11, 27, 19, 55, 217, 475, 119, 1291, 1761, 6879, 4355, 30019, 17573, 14987, 204623}},
+{17682, 18, 71906, {1, 1, 7, 11, 29, 47, 5, 201, 165, 845, 385, 2903, 7735, 10855, 14171, 17881, 45001, 100725}},
+{17683, 18, 71908, {1, 1, 5, 5, 31, 57, 99, 35, 315, 363, 1135, 897, 1041, 729, 26987, 15299, 29563, 67293}},
+{17684, 18, 71917, {1, 1, 5, 7, 27, 13, 99, 81, 491, 887, 1309, 3343, 7241, 1289, 12021, 52533, 101799, 238721}},
+{17685, 18, 71952, {1, 1, 1, 11, 27, 49, 79, 235, 49, 215, 2003, 2771, 5943, 1183, 31931, 33885, 56971, 52665}},
+{17686, 18, 71957, {1, 1, 1, 13, 13, 1, 123, 1, 191, 747, 859, 2287, 5113, 3715, 2217, 61483, 195, 237163}},
+{17687, 18, 71961, {1, 3, 7, 15, 13, 13, 17, 207, 141, 821, 231, 1373, 5355, 6503, 2403, 18183, 83717, 170047}},
+{17688, 18, 71973, {1, 3, 1, 3, 13, 11, 41, 51, 443, 201, 1349, 2331, 1009, 16169, 5247, 50315, 15589, 150497}},
+{17689, 18, 71980, {1, 3, 5, 13, 29, 21, 93, 55, 27, 17, 1615, 3473, 3641, 10999, 31955, 4699, 23585, 141243}},
+{17690, 18, 71997, {1, 3, 3, 11, 11, 27, 125, 139, 53, 637, 241, 2651, 4999, 5923, 16203, 13645, 95965, 94459}},
+{17691, 18, 72017, {1, 3, 7, 3, 9, 53, 87, 171, 489, 691, 303, 3599, 6093, 841, 3527, 12953, 22907, 69823}},
+{17692, 18, 72060, {1, 1, 5, 13, 31, 11, 33, 207, 437, 683, 703, 1757, 1443, 14269, 12677, 20877, 46791, 176135}},
+{17693, 18, 72091, {1, 1, 7, 1, 13, 53, 123, 199, 173, 585, 1099, 3653, 2253, 13741, 15675, 38755, 74545, 139053}},
+{17694, 18, 72097, {1, 3, 3, 3, 17, 11, 1, 161, 383, 409, 605, 889, 827, 263, 9677, 42857, 127691, 99621}},
+{17695, 18, 72166, {1, 3, 5, 9, 21, 21, 11, 151, 199, 695, 493, 569, 881, 10533, 11255, 61997, 124921, 211139}},
+{17696, 18, 72172, {1, 3, 5, 5, 9, 47, 109, 7, 195, 287, 97, 3691, 6929, 6985, 3063, 16185, 6313, 228147}},
+{17697, 18, 72183, {1, 3, 1, 3, 3, 9, 107, 243, 391, 893, 1207, 2229, 5295, 723, 14753, 10921, 104147, 214941}},
+{17698, 18, 72203, {1, 3, 1, 9, 5, 63, 63, 247, 413, 805, 285, 4001, 6735, 3531, 25949, 44845, 66959, 194429}},
+{17699, 18, 72205, {1, 1, 3, 1, 15, 15, 43, 69, 419, 739, 1739, 1091, 1043, 3217, 1139, 44749, 74131, 165145}},
+{17700, 18, 72213, {1, 1, 3, 9, 17, 53, 119, 25, 427, 791, 1873, 481, 6793, 4767, 30449, 18079, 52105, 260371}},
+{17701, 18, 72214, {1, 1, 3, 15, 15, 41, 15, 53, 395, 571, 1727, 3081, 4531, 4215, 22359, 18165, 91843, 157273}},
+{17702, 18, 72230, {1, 3, 3, 9, 19, 15, 55, 185, 321, 285, 695, 1067, 2551, 1401, 20023, 22671, 21365, 89053}},
+{17703, 18, 72239, {1, 1, 7, 15, 23, 57, 71, 141, 57, 479, 543, 3783, 3635, 14011, 23603, 40877, 21837, 81079}},
+{17704, 18, 72248, {1, 3, 7, 11, 31, 5, 83, 177, 105, 981, 331, 2901, 1781, 8407, 30199, 19287, 116219, 78471}},
+{17705, 18, 72251, {1, 1, 1, 9, 7, 13, 61, 21, 299, 15, 1045, 475, 7141, 4827, 5921, 17323, 42909, 203623}},
+{17706, 18, 72280, {1, 3, 7, 1, 17, 59, 99, 221, 77, 37, 1263, 2137, 1567, 12473, 20029, 9231, 32739, 17021}},
+{17707, 18, 72313, {1, 1, 1, 5, 23, 61, 39, 13, 97, 191, 1479, 19, 1913, 3185, 32393, 59067, 5483, 158895}},
+{17708, 18, 72338, {1, 1, 1, 7, 5, 51, 81, 223, 435, 939, 781, 1153, 6409, 6369, 30559, 19007, 50121, 26525}},
+{17709, 18, 72340, {1, 3, 3, 5, 29, 1, 57, 127, 153, 897, 161, 683, 295, 11207, 245, 1819, 3061, 242609}},
+{17710, 18, 72343, {1, 1, 1, 7, 5, 19, 105, 57, 263, 433, 1339, 1479, 6671, 9917, 26299, 4573, 68725, 195}},
+{17711, 18, 72368, {1, 3, 5, 15, 1, 19, 45, 95, 155, 117, 367, 2051, 1053, 8847, 6399, 23641, 95355, 98415}},
+{17712, 18, 72371, {1, 3, 3, 15, 3, 1, 5, 115, 349, 747, 1865, 1669, 659, 7097, 7871, 3685, 11013, 59837}},
+{17713, 18, 72426, {1, 3, 3, 5, 9, 47, 51, 131, 327, 903, 975, 2481, 3509, 12481, 4049, 38053, 4629, 254415}},
+{17714, 18, 72439, {1, 3, 5, 9, 31, 47, 1, 29, 37, 683, 1363, 2527, 4019, 4965, 14077, 14191, 101, 1945}},
+{17715, 18, 72446, {1, 1, 7, 1, 9, 35, 41, 187, 509, 33, 385, 3907, 1461, 6827, 6931, 44723, 109495, 184641}},
+{17716, 18, 72494, {1, 3, 5, 9, 5, 49, 21, 171, 353, 927, 409, 913, 5199, 11747, 8777, 19891, 63189, 118839}},
+{17717, 18, 72519, {1, 3, 3, 1, 27, 49, 43, 157, 75, 469, 787, 3957, 4147, 13919, 17489, 57103, 62091, 135589}},
+{17718, 18, 72573, {1, 1, 3, 11, 7, 45, 29, 177, 185, 185, 1537, 127, 121, 817, 31269, 1677, 20245, 3835}},
+{17719, 18, 72577, {1, 1, 5, 3, 21, 9, 67, 79, 391, 971, 1711, 2607, 5705, 12863, 12415, 41255, 26447, 1643}},
+{17720, 18, 72578, {1, 1, 5, 5, 9, 63, 67, 245, 31, 225, 309, 1753, 1507, 817, 4275, 51843, 22331, 196875}},
+{17721, 18, 72614, {1, 3, 1, 13, 15, 39, 3, 245, 147, 485, 241, 2507, 1859, 7299, 15037, 41139, 82757, 224031}},
+{17722, 18, 72628, {1, 3, 3, 15, 7, 51, 9, 103, 37, 643, 25, 2067, 7619, 11991, 12885, 46809, 109107, 22393}},
+{17723, 18, 72640, {1, 1, 1, 9, 1, 55, 119, 85, 115, 827, 187, 2241, 2553, 577, 12115, 2391, 69705, 232101}},
+{17724, 18, 72676, {1, 1, 5, 7, 13, 61, 125, 129, 475, 703, 1723, 3233, 5713, 1941, 21375, 42119, 75199, 73163}},
+{17725, 18, 72708, {1, 1, 5, 5, 5, 21, 73, 155, 493, 81, 1627, 827, 5925, 7391, 1587, 39425, 11807, 64385}},
+{17726, 18, 72717, {1, 3, 1, 15, 27, 35, 111, 183, 283, 335, 1387, 669, 6041, 11637, 26255, 21113, 121183, 219703}},
+{17727, 18, 72766, {1, 3, 5, 15, 15, 23, 119, 91, 197, 809, 975, 3275, 6171, 11769, 8385, 5461, 4561, 29159}},
+{17728, 18, 72786, {1, 1, 5, 9, 29, 9, 107, 233, 417, 1005, 799, 1437, 2679, 15643, 32341, 54055, 27861, 115483}},
+{17729, 18, 72788, {1, 1, 5, 7, 27, 19, 95, 153, 175, 407, 215, 303, 8165, 14791, 2099, 61797, 129411, 10461}},
+{17730, 18, 72795, {1, 1, 1, 13, 25, 51, 11, 77, 97, 495, 971, 449, 2833, 7121, 24105, 34527, 123135, 129305}},
+{17731, 18, 72797, {1, 1, 7, 11, 23, 9, 111, 101, 169, 233, 267, 953, 6379, 15887, 22921, 33665, 95195, 159707}},
+{17732, 18, 72798, {1, 1, 5, 15, 21, 3, 21, 57, 173, 513, 2027, 1235, 5031, 5375, 2717, 23361, 71817, 232101}},
+{17733, 18, 72808, {1, 3, 3, 11, 7, 25, 43, 65, 19, 135, 1611, 85, 7673, 6459, 27813, 55557, 100989, 25205}},
+{17734, 18, 72826, {1, 3, 7, 1, 15, 37, 55, 141, 239, 205, 647, 3715, 1617, 13507, 9847, 64681, 108711, 231329}},
+{17735, 18, 72835, {1, 3, 5, 9, 21, 27, 79, 153, 335, 299, 493, 887, 1457, 16011, 13795, 50205, 43319, 130963}},
+{17736, 18, 72837, {1, 1, 3, 1, 23, 59, 121, 83, 463, 151, 323, 2977, 4769, 6011, 20135, 59541, 23179, 203487}},
+{17737, 18, 72865, {1, 1, 5, 7, 9, 17, 63, 149, 59, 281, 763, 619, 2551, 8179, 2963, 61283, 107727, 119817}},
+{17738, 18, 72871, {1, 3, 7, 3, 15, 39, 11, 145, 141, 965, 505, 2625, 4335, 7619, 11007, 43321, 33199, 212661}},
+{17739, 18, 72872, {1, 3, 5, 9, 9, 61, 27, 223, 5, 941, 513, 1437, 481, 9651, 6567, 57945, 52547, 21283}},
+{17740, 18, 72898, {1, 3, 1, 1, 25, 1, 87, 25, 121, 757, 529, 3857, 1321, 13479, 5357, 49341, 5797, 235895}},
+{17741, 18, 72907, {1, 3, 5, 1, 21, 35, 37, 215, 509, 165, 1423, 3067, 4779, 4693, 12523, 48099, 69283, 255111}},
+{17742, 18, 72909, {1, 1, 3, 1, 31, 15, 45, 127, 339, 331, 1249, 1075, 6169, 2941, 30471, 46789, 118039, 224651}},
+{17743, 18, 72917, {1, 1, 5, 13, 21, 37, 39, 61, 191, 17, 177, 3719, 2177, 11039, 20047, 14489, 20475, 171235}},
+{17744, 18, 72934, {1, 1, 3, 9, 19, 11, 65, 111, 121, 901, 99, 1861, 3687, 765, 24861, 46315, 63433, 171679}},
+{17745, 18, 72987, {1, 3, 1, 7, 1, 51, 87, 199, 241, 909, 353, 2471, 7163, 9547, 16351, 41129, 12217, 194099}},
+{17746, 18, 73000, {1, 1, 7, 7, 17, 17, 127, 67, 51, 217, 1189, 19, 2099, 10281, 9071, 21185, 122821, 110211}},
+{17747, 18, 73005, {1, 3, 3, 7, 15, 3, 53, 45, 77, 665, 701, 3175, 6151, 2639, 19819, 1063, 25079, 203343}},
+{17748, 18, 73014, {1, 1, 5, 11, 11, 5, 103, 11, 481, 999, 713, 499, 5069, 921, 20619, 25623, 69601, 82941}},
+{17749, 18, 73023, {1, 3, 5, 9, 15, 61, 67, 79, 371, 993, 475, 617, 1611, 12513, 14907, 55313, 39207, 112653}},
+{17750, 18, 73025, {1, 1, 5, 15, 17, 45, 91, 187, 175, 465, 907, 3371, 3743, 15657, 30511, 58191, 105683, 216759}},
+{17751, 18, 73074, {1, 1, 5, 9, 23, 1, 17, 79, 73, 717, 1785, 677, 7377, 4511, 21927, 34341, 47119, 193977}},
+{17752, 18, 73076, {1, 3, 7, 13, 21, 1, 59, 179, 121, 641, 175, 563, 961, 10549, 15779, 49875, 8109, 1039}},
+{17753, 18, 73113, {1, 1, 5, 7, 17, 9, 37, 171, 335, 135, 1403, 2541, 3845, 15311, 1905, 40853, 11013, 255669}},
+{17754, 18, 73116, {1, 1, 7, 1, 5, 23, 113, 111, 337, 755, 2037, 3067, 2821, 10549, 28467, 22615, 71585, 61871}},
+{17755, 18, 73140, {1, 1, 3, 9, 7, 3, 49, 229, 111, 871, 1711, 1793, 3089, 12571, 30883, 44773, 80827, 151709}},
+{17756, 18, 73149, {1, 1, 5, 1, 13, 41, 3, 253, 399, 881, 1107, 4081, 1849, 115, 31557, 2515, 126751, 195663}},
+{17757, 18, 73186, {1, 1, 3, 1, 13, 31, 113, 85, 57, 549, 1653, 2927, 5433, 11879, 22709, 41675, 13395, 46931}},
+{17758, 18, 73188, {1, 1, 3, 9, 21, 1, 109, 65, 377, 63, 861, 1031, 2709, 7265, 9861, 64109, 34577, 9743}},
+{17759, 18, 73191, {1, 1, 7, 7, 17, 31, 5, 177, 253, 387, 1271, 2805, 2211, 1813, 11649, 3217, 123793, 197753}},
+{17760, 18, 73205, {1, 1, 3, 9, 15, 63, 89, 59, 455, 783, 1181, 7, 2309, 15961, 11231, 37389, 101221, 119331}},
+{17761, 18, 73215, {1, 3, 3, 13, 7, 3, 15, 251, 431, 951, 639, 1585, 1247, 15927, 9695, 37469, 34945, 219723}},
+{17762, 18, 73216, {1, 1, 5, 3, 21, 29, 83, 151, 383, 227, 215, 2329, 1297, 13709, 15653, 3119, 111319, 222877}},
+{17763, 18, 73239, {1, 3, 1, 13, 1, 43, 127, 125, 243, 955, 583, 3497, 6605, 3821, 4657, 10599, 90927, 82725}},
+{17764, 18, 73294, {1, 1, 1, 1, 15, 51, 61, 167, 489, 603, 873, 907, 575, 6957, 24409, 63587, 50205, 159291}},
+{17765, 18, 73311, {1, 3, 3, 1, 19, 23, 7, 23, 239, 961, 1001, 1541, 2211, 4637, 19931, 39153, 102769, 242005}},
+{17766, 18, 73330, {1, 1, 1, 15, 19, 31, 73, 121, 119, 199, 979, 4061, 3903, 12055, 27957, 15999, 5709, 210329}},
+{17767, 18, 73366, {1, 1, 7, 13, 25, 35, 21, 25, 241, 937, 13, 947, 943, 3727, 15321, 46665, 99437, 233919}},
+{17768, 18, 73379, {1, 1, 1, 9, 3, 51, 127, 113, 105, 335, 685, 2173, 4329, 7569, 5617, 32407, 21649, 30609}},
+{17769, 18, 73386, {1, 3, 7, 9, 9, 13, 69, 191, 95, 727, 1649, 1201, 2093, 10053, 29381, 6207, 70755, 118505}},
+{17770, 18, 73391, {1, 1, 1, 11, 21, 57, 77, 139, 271, 21, 1747, 2337, 7761, 7753, 6847, 5219, 87033, 229105}},
+{17771, 18, 73418, {1, 3, 3, 1, 5, 51, 15, 235, 87, 567, 391, 3039, 2253, 11177, 11899, 25305, 14815, 51051}},
+{17772, 18, 73438, {1, 3, 5, 7, 27, 51, 69, 93, 261, 947, 31, 2751, 6685, 3655, 24125, 22161, 108421, 230865}},
+{17773, 18, 73476, {1, 1, 3, 3, 27, 17, 35, 97, 285, 855, 1767, 2545, 825, 11519, 11231, 50951, 32883, 78573}},
+{17774, 18, 73503, {1, 3, 7, 13, 1, 57, 99, 193, 371, 839, 1319, 2295, 5897, 7893, 14339, 64217, 16951, 234953}},
+{17775, 18, 73509, {1, 3, 1, 3, 11, 37, 13, 21, 299, 379, 63, 1209, 7879, 5001, 10181, 40173, 1753, 104821}},
+{17776, 18, 73534, {1, 3, 5, 9, 23, 51, 75, 103, 249, 533, 621, 15, 1883, 2109, 20859, 4635, 120615, 135515}},
+{17777, 18, 73545, {1, 1, 3, 3, 21, 45, 113, 57, 495, 457, 685, 3625, 243, 14831, 12351, 63001, 118191, 153875}},
+{17778, 18, 73548, {1, 3, 5, 5, 21, 15, 65, 251, 183, 241, 1513, 2711, 4527, 12675, 26747, 5181, 4237, 246479}},
+{17779, 18, 73563, {1, 1, 5, 3, 27, 29, 91, 93, 345, 893, 195, 3109, 2611, 12657, 10401, 15063, 95807, 244587}},
+{17780, 18, 73575, {1, 3, 5, 13, 19, 49, 85, 155, 159, 939, 1139, 1569, 1129, 8641, 18391, 55201, 108491, 77863}},
+{17781, 18, 73582, {1, 3, 5, 9, 25, 53, 75, 77, 85, 903, 1399, 2379, 2219, 14725, 21877, 24271, 40955, 61849}},
+{17782, 18, 73603, {1, 1, 5, 9, 13, 49, 53, 177, 163, 331, 533, 1469, 1397, 8187, 12379, 10185, 125541, 260271}},
+{17783, 18, 73609, {1, 1, 7, 9, 19, 31, 81, 89, 281, 397, 1917, 145, 2723, 15019, 18841, 13887, 11859, 171749}},
+{17784, 18, 73610, {1, 3, 7, 13, 25, 17, 87, 189, 29, 283, 913, 3855, 5707, 15881, 12787, 42357, 84579, 78531}},
+{17785, 18, 73645, {1, 1, 5, 15, 15, 31, 37, 249, 445, 119, 431, 4069, 5699, 10119, 31661, 9555, 6869, 1145}},
+{17786, 18, 73646, {1, 3, 7, 1, 31, 29, 57, 177, 341, 411, 1019, 1889, 383, 1461, 26695, 61777, 18367, 137233}},
+{17787, 18, 73678, {1, 3, 5, 1, 7, 53, 29, 53, 387, 675, 435, 461, 6247, 7519, 14003, 9037, 116599, 54471}},
+{17788, 18, 73685, {1, 3, 3, 7, 17, 59, 91, 77, 169, 591, 95, 113, 6135, 10479, 17153, 52953, 16183, 90775}},
+{17789, 18, 73708, {1, 3, 3, 15, 11, 11, 117, 141, 493, 163, 65, 1305, 7477, 7383, 22651, 64271, 80983, 154845}},
+{17790, 18, 73747, {1, 1, 1, 3, 9, 15, 83, 11, 113, 77, 1115, 1417, 511, 6825, 21013, 37241, 104695, 31335}},
+{17791, 18, 73765, {1, 1, 7, 3, 13, 33, 115, 121, 245, 673, 1991, 2157, 479, 9843, 5963, 4637, 8925, 27751}},
+{17792, 18, 73797, {1, 3, 3, 7, 19, 11, 67, 125, 339, 27, 1545, 2319, 5977, 11603, 23219, 48273, 119265, 20151}},
+{17793, 18, 73810, {1, 1, 5, 7, 27, 29, 31, 227, 279, 405, 1133, 689, 1133, 8957, 29629, 48849, 109995, 259749}},
+{17794, 18, 73819, {1, 3, 5, 7, 7, 61, 95, 243, 91, 741, 1591, 3169, 2287, 11015, 15601, 43043, 65319, 50671}},
+{17795, 18, 73825, {1, 1, 5, 5, 13, 47, 31, 95, 425, 715, 1603, 3485, 673, 12869, 32561, 42329, 112809, 181971}},
+{17796, 18, 73845, {1, 3, 3, 3, 17, 51, 109, 45, 397, 457, 1379, 3845, 4215, 14185, 16597, 27711, 74283, 98151}},
+{17797, 18, 73855, {1, 1, 1, 15, 7, 25, 13, 49, 441, 513, 1769, 707, 6037, 9689, 18915, 35647, 110823, 196633}},
+{17798, 18, 73866, {1, 1, 1, 1, 23, 53, 93, 61, 277, 125, 55, 2453, 3331, 14037, 10809, 33205, 43785, 248743}},
+{17799, 18, 73890, {1, 1, 3, 7, 23, 15, 93, 77, 333, 801, 1969, 31, 51, 5239, 24241, 5077, 113503, 132211}},
+{17800, 18, 73919, {1, 3, 3, 1, 7, 55, 53, 5, 311, 657, 1507, 3413, 565, 15745, 6129, 40285, 91811, 90527}},
+{17801, 18, 73922, {1, 3, 3, 13, 19, 23, 45, 25, 509, 313, 915, 2199, 5549, 8469, 32735, 37877, 11607, 37993}},
+{17802, 18, 73936, {1, 1, 5, 11, 25, 33, 55, 31, 311, 851, 159, 2103, 2641, 8957, 9375, 37179, 33667, 100513}},
+{17803, 18, 73939, {1, 3, 1, 1, 7, 7, 17, 75, 217, 171, 359, 1169, 4105, 929, 6427, 56349, 77985, 41941}},
+{17804, 18, 73964, {1, 1, 1, 15, 5, 51, 73, 63, 259, 351, 1797, 1001, 5025, 11203, 30221, 54345, 11331, 158415}},
+{17805, 18, 73976, {1, 3, 1, 5, 3, 21, 13, 3, 63, 779, 871, 2517, 6345, 4103, 16321, 30211, 120815, 83751}},
+{17806, 18, 73984, {1, 1, 3, 13, 11, 7, 41, 255, 215, 37, 279, 2485, 6511, 12855, 22857, 55695, 122717, 238151}},
+{17807, 18, 73990, {1, 3, 3, 3, 1, 55, 27, 193, 509, 677, 1861, 573, 5341, 5285, 6909, 51781, 91203, 139791}},
+{17808, 18, 74013, {1, 3, 7, 11, 5, 63, 87, 215, 305, 235, 1049, 1339, 5301, 9639, 29861, 58415, 68303, 76907}},
+{17809, 18, 74014, {1, 1, 5, 11, 13, 13, 67, 139, 19, 577, 165, 3067, 8023, 10905, 3159, 41289, 118231, 119673}},
+{17810, 18, 74020, {1, 1, 3, 1, 15, 5, 69, 119, 363, 703, 461, 2293, 3801, 14217, 10709, 9553, 100651, 186115}},
+{17811, 18, 74035, {1, 3, 7, 15, 19, 21, 59, 237, 227, 193, 827, 619, 3447, 13815, 3467, 38911, 41403, 99627}},
+{17812, 18, 74038, {1, 1, 3, 3, 27, 23, 41, 199, 161, 555, 1629, 3187, 1355, 5947, 1157, 25877, 110989, 231285}},
+{17813, 18, 74069, {1, 1, 3, 15, 3, 43, 103, 29, 179, 223, 375, 2877, 1917, 9367, 15337, 15381, 62833, 139003}},
+{17814, 18, 74119, {1, 3, 3, 11, 23, 33, 107, 189, 511, 209, 1519, 2809, 6185, 5921, 20939, 63879, 113687, 79149}},
+{17815, 18, 74123, {1, 3, 5, 15, 1, 63, 101, 227, 419, 803, 59, 2261, 6905, 10679, 5393, 54447, 58521, 59855}},
+{17816, 18, 74126, {1, 1, 7, 13, 13, 21, 121, 123, 181, 371, 1485, 3191, 2627, 6197, 11169, 44927, 34739, 10687}},
+{17817, 18, 74153, {1, 1, 3, 3, 25, 47, 13, 115, 187, 967, 1439, 1021, 4413, 3343, 31463, 3729, 13511, 162125}},
+{17818, 18, 74179, {1, 3, 3, 15, 15, 59, 29, 129, 469, 171, 2045, 2859, 1097, 11199, 12147, 37465, 14179, 197923}},
+{17819, 18, 74200, {1, 1, 7, 5, 13, 35, 41, 167, 207, 123, 1077, 3145, 2803, 15729, 767, 7321, 84375, 190855}},
+{17820, 18, 74210, {1, 3, 5, 11, 3, 5, 65, 3, 111, 725, 143, 2945, 4755, 3407, 31801, 15329, 70311, 119197}},
+{17821, 18, 74216, {1, 1, 5, 3, 17, 19, 61, 73, 261, 663, 821, 3389, 3883, 9961, 17727, 33113, 98371, 247097}},
+{17822, 18, 74250, {1, 3, 1, 9, 29, 17, 43, 43, 481, 1015, 1249, 607, 3495, 13259, 29001, 23083, 51487, 81723}},
+{17823, 18, 74263, {1, 3, 1, 3, 25, 57, 5, 33, 313, 21, 1731, 3417, 7033, 6609, 31631, 63231, 61107, 10941}},
+{17824, 18, 74264, {1, 3, 3, 11, 29, 29, 117, 131, 417, 789, 1545, 1677, 3213, 13869, 5319, 41387, 13895, 252387}},
+{17825, 18, 74279, {1, 3, 3, 13, 25, 47, 55, 213, 83, 345, 1453, 159, 1521, 14777, 24177, 7631, 81259, 135411}},
+{17826, 18, 74285, {1, 1, 3, 15, 11, 63, 49, 69, 273, 843, 1661, 1157, 1285, 12751, 5, 54909, 114375, 6395}},
+{17827, 18, 74294, {1, 3, 1, 11, 25, 1, 83, 55, 161, 125, 1547, 401, 7639, 4289, 7075, 9971, 33825, 135071}},
+{17828, 18, 74298, {1, 3, 7, 9, 17, 5, 79, 131, 373, 1023, 573, 2219, 1789, 5789, 5347, 26455, 58661, 206417}},
+{17829, 18, 74303, {1, 1, 7, 5, 1, 43, 83, 107, 125, 289, 793, 1731, 5167, 8943, 28397, 26877, 53781, 95899}},
+{17830, 18, 74306, {1, 3, 3, 13, 21, 53, 123, 103, 385, 753, 1917, 2075, 4385, 5757, 9221, 35797, 86743, 69069}},
+{17831, 18, 74366, {1, 3, 3, 3, 5, 19, 119, 221, 457, 907, 359, 3493, 2331, 5685, 11133, 29293, 27051, 213927}},
+{17832, 18, 74369, {1, 1, 3, 11, 11, 31, 29, 129, 429, 601, 1217, 3653, 5935, 14823, 21161, 33423, 98391, 214703}},
+{17833, 18, 74403, {1, 1, 3, 15, 31, 49, 109, 139, 349, 13, 205, 2483, 8083, 8391, 4789, 30355, 12165, 195263}},
+{17834, 18, 74406, {1, 1, 1, 9, 19, 63, 15, 167, 45, 185, 811, 529, 6811, 13441, 27195, 59047, 106675, 167125}},
+{17835, 18, 74442, {1, 1, 7, 1, 19, 19, 39, 1, 349, 467, 551, 4081, 4743, 11627, 607, 22005, 60893, 49101}},
+{17836, 18, 74450, {1, 3, 7, 9, 9, 25, 105, 119, 113, 825, 1429, 2019, 5209, 8491, 6017, 47783, 88455, 119083}},
+{17837, 18, 74452, {1, 3, 3, 13, 21, 39, 107, 119, 321, 251, 563, 311, 4441, 6491, 3157, 65479, 107349, 211621}},
+{17838, 18, 74459, {1, 1, 7, 13, 9, 3, 17, 117, 327, 459, 489, 7, 6883, 10047, 31935, 28069, 37903, 188281}},
+{17839, 18, 74461, {1, 1, 7, 1, 15, 53, 47, 127, 483, 595, 811, 1143, 4543, 10043, 30349, 24409, 91947, 240165}},
+{17840, 18, 74477, {1, 1, 1, 13, 25, 43, 109, 161, 147, 1009, 1071, 1533, 2781, 13439, 20507, 41387, 26943, 84675}},
+{17841, 18, 74478, {1, 3, 5, 13, 19, 21, 23, 167, 135, 257, 587, 2691, 5877, 3047, 11745, 24895, 114799, 48003}},
+{17842, 18, 74489, {1, 3, 1, 1, 9, 57, 33, 51, 137, 109, 137, 195, 1233, 11139, 16833, 27545, 35877, 126627}},
+{17843, 18, 74504, {1, 1, 1, 15, 5, 37, 7, 19, 363, 411, 1193, 767, 6209, 9115, 14699, 55515, 46023, 90693}},
+{17844, 18, 74528, {1, 3, 5, 3, 19, 55, 85, 117, 391, 757, 861, 3537, 6507, 6993, 19589, 6843, 33557, 64683}},
+{17845, 18, 74533, {1, 1, 7, 5, 5, 61, 99, 9, 311, 595, 807, 429, 63, 12359, 28289, 709, 129911, 143745}},
+{17846, 18, 74538, {1, 1, 1, 7, 17, 9, 9, 117, 19, 985, 657, 2803, 2699, 829, 31069, 13277, 106769, 109231}},
+{17847, 18, 74551, {1, 1, 5, 13, 25, 19, 63, 217, 419, 221, 1921, 215, 2631, 4659, 29855, 46549, 62257, 260113}},
+{17848, 18, 74580, {1, 3, 3, 9, 13, 45, 63, 129, 147, 489, 879, 3025, 6777, 1119, 20963, 30553, 20863, 169837}},
+{17849, 18, 74589, {1, 3, 5, 9, 25, 61, 79, 51, 495, 583, 1519, 1501, 123, 13871, 32239, 957, 31921, 255561}},
+{17850, 18, 74590, {1, 3, 7, 3, 31, 61, 89, 65, 305, 429, 785, 3871, 7711, 2745, 24131, 43055, 51167, 87743}},
+{17851, 18, 74593, {1, 3, 1, 11, 19, 23, 89, 117, 185, 121, 109, 1327, 6553, 14367, 16069, 28657, 81751, 10185}},
+{17852, 18, 74608, {1, 3, 5, 5, 17, 33, 115, 61, 101, 367, 1465, 3899, 6601, 4483, 2447, 49575, 129987, 11703}},
+{17853, 18, 74611, {1, 1, 3, 13, 13, 59, 79, 83, 253, 171, 53, 2467, 5005, 1045, 943, 62419, 98563, 78935}},
+{17854, 18, 74617, {1, 1, 7, 15, 31, 17, 77, 73, 249, 247, 119, 1655, 7079, 14593, 105, 55767, 130401, 74189}},
+{17855, 18, 74623, {1, 3, 5, 11, 19, 29, 79, 251, 75, 949, 527, 2779, 5839, 11451, 24125, 45991, 127437, 86541}},
+{17856, 18, 74648, {1, 1, 5, 7, 1, 29, 127, 27, 477, 807, 829, 1569, 205, 13319, 16149, 26003, 38985, 188587}},
+{17857, 18, 74704, {1, 1, 1, 3, 19, 29, 39, 71, 17, 51, 1169, 467, 7505, 1867, 4469, 32161, 43031, 31675}},
+{17858, 18, 74735, {1, 1, 1, 15, 27, 45, 67, 107, 127, 469, 1955, 1933, 2379, 8513, 32071, 35043, 126537, 23303}},
+{17859, 18, 74737, {1, 3, 7, 9, 23, 41, 23, 197, 97, 213, 17, 1751, 5467, 6179, 29291, 33397, 42131, 151093}},
+{17860, 18, 74738, {1, 3, 7, 15, 27, 3, 39, 87, 365, 77, 487, 293, 6405, 2239, 30455, 44723, 12399, 100013}},
+{17861, 18, 74779, {1, 3, 5, 9, 29, 21, 55, 183, 343, 263, 1643, 2027, 2255, 6259, 18277, 64661, 39391, 255839}},
+{17862, 18, 74781, {1, 1, 7, 11, 21, 55, 11, 139, 261, 11, 1721, 3779, 85, 8203, 12089, 50579, 128341, 119043}},
+{17863, 18, 74809, {1, 3, 5, 13, 27, 53, 109, 1, 313, 661, 431, 1543, 1571, 7337, 18857, 49951, 7881, 228161}},
+{17864, 18, 74812, {1, 1, 7, 5, 5, 31, 27, 149, 239, 199, 1011, 1979, 5297, 14609, 26971, 65531, 64215, 115109}},
+{17865, 18, 74827, {1, 1, 5, 13, 15, 11, 63, 225, 165, 405, 1367, 2291, 5171, 12419, 19561, 37719, 621, 137607}},
+{17866, 18, 74868, {1, 3, 1, 15, 25, 1, 125, 243, 97, 455, 1977, 3333, 801, 1343, 993, 18453, 19285, 71547}},
+{17867, 18, 74871, {1, 1, 5, 11, 9, 51, 109, 135, 73, 147, 649, 4071, 7425, 3093, 26417, 51139, 1523, 142225}},
+{17868, 18, 74905, {1, 3, 7, 11, 1, 39, 109, 119, 337, 715, 1087, 4005, 1393, 6397, 31135, 38935, 106255, 60723}},
+{17869, 18, 74930, {1, 1, 1, 9, 9, 11, 45, 11, 171, 671, 965, 109, 2261, 13775, 8539, 63669, 10507, 249113}},
+{17870, 18, 74962, {1, 3, 1, 15, 21, 33, 127, 173, 419, 31, 299, 857, 4915, 11331, 29385, 47375, 111891, 14505}},
+{17871, 18, 74990, {1, 3, 5, 13, 7, 43, 85, 183, 377, 275, 803, 1755, 8005, 15327, 31043, 18851, 122581, 229731}},
+{17872, 18, 74995, {1, 3, 5, 1, 27, 9, 41, 73, 283, 475, 671, 747, 1419, 15209, 25465, 60061, 91417, 103203}},
+{17873, 18, 75007, {1, 3, 1, 15, 15, 43, 13, 45, 217, 519, 363, 3265, 6213, 13045, 3709, 22119, 79733, 224195}},
+{17874, 18, 75012, {1, 3, 1, 15, 15, 59, 95, 71, 171, 769, 1395, 2673, 4523, 749, 13411, 60431, 124651, 11475}},
+{17875, 18, 75030, {1, 1, 7, 3, 1, 35, 13, 239, 101, 355, 1201, 3665, 5403, 11413, 11983, 52469, 63621, 155819}},
+{17876, 18, 75033, {1, 1, 1, 7, 31, 59, 87, 25, 511, 483, 569, 3337, 4027, 8347, 3031, 24351, 57963, 79425}},
+{17877, 18, 75039, {1, 3, 1, 3, 11, 17, 29, 249, 61, 923, 585, 2107, 2727, 8589, 22809, 3, 17937, 163267}},
+{17878, 18, 75055, {1, 3, 5, 11, 27, 3, 73, 187, 19, 975, 257, 2361, 935, 9071, 29991, 13619, 92169, 101031}},
+{17879, 18, 75078, {1, 1, 5, 13, 17, 53, 105, 157, 343, 673, 237, 3231, 7311, 1593, 18521, 57889, 79805, 97847}},
+{17880, 18, 75120, {1, 3, 1, 3, 31, 55, 63, 167, 489, 167, 121, 3333, 2475, 1545, 13291, 921, 101757, 62147}},
+{17881, 18, 75130, {1, 3, 3, 15, 13, 17, 9, 209, 339, 567, 2011, 1737, 1455, 9289, 6105, 49733, 74237, 93195}},
+{17882, 18, 75159, {1, 1, 7, 11, 3, 13, 77, 115, 305, 327, 1005, 3381, 4269, 4835, 27221, 16301, 75173, 244603}},
+{17883, 18, 75163, {1, 3, 5, 7, 7, 31, 47, 75, 499, 41, 281, 167, 3525, 8649, 23623, 4987, 2057, 204083}},
+{17884, 18, 75170, {1, 3, 3, 5, 9, 5, 35, 53, 269, 437, 1035, 1675, 4567, 13291, 19787, 28937, 108915, 62545}},
+{17885, 18, 75193, {1, 3, 1, 5, 15, 59, 57, 181, 321, 1, 791, 2149, 591, 6691, 8759, 62861, 10815, 257331}},
+{17886, 18, 75228, {1, 1, 7, 1, 21, 25, 93, 39, 429, 455, 669, 1725, 7087, 11805, 22405, 13083, 88411, 225967}},
+{17887, 18, 75244, {1, 1, 5, 15, 5, 45, 15, 1, 55, 281, 2027, 97, 2639, 57, 23717, 21669, 92181, 32731}},
+{17888, 18, 75249, {1, 3, 7, 3, 7, 3, 67, 201, 445, 577, 1011, 793, 7763, 10823, 30309, 41565, 37263, 218909}},
+{17889, 18, 75328, {1, 1, 7, 3, 17, 53, 51, 119, 399, 903, 1785, 1053, 4315, 2967, 17579, 64185, 55005, 12969}},
+{17890, 18, 75357, {1, 3, 3, 13, 21, 63, 13, 1, 427, 39, 71, 1811, 1237, 1623, 11401, 14371, 44355, 93089}},
+{17891, 18, 75373, {1, 1, 5, 1, 17, 39, 39, 105, 187, 691, 251, 3957, 931, 12149, 18299, 48819, 23061, 49179}},
+{17892, 18, 75392, {1, 1, 5, 11, 31, 3, 23, 211, 101, 763, 237, 3635, 417, 4935, 14997, 3859, 22343, 153541}},
+{17893, 18, 75428, {1, 3, 7, 5, 21, 37, 59, 137, 13, 179, 527, 895, 3451, 1743, 3149, 10665, 119427, 259343}},
+{17894, 18, 75438, {1, 3, 5, 3, 7, 37, 103, 173, 453, 327, 131, 2453, 7795, 12585, 13947, 59161, 41845, 29527}},
+{17895, 18, 75469, {1, 3, 3, 1, 17, 49, 57, 251, 295, 279, 1545, 3963, 589, 9211, 32371, 14963, 116927, 197321}},
+{17896, 18, 75487, {1, 1, 3, 7, 17, 59, 37, 115, 315, 591, 481, 767, 4611, 14741, 6949, 19507, 6567, 143371}},
+{17897, 18, 75494, {1, 1, 5, 3, 19, 53, 121, 229, 355, 909, 339, 1645, 2747, 7045, 9085, 5799, 50997, 17981}},
+{17898, 18, 75515, {1, 3, 3, 9, 3, 1, 109, 7, 15, 177, 789, 3911, 6427, 8453, 22583, 12039, 124587, 123887}},
+{17899, 18, 75526, {1, 1, 5, 1, 7, 23, 15, 193, 109, 685, 1147, 3921, 2329, 15153, 25045, 28389, 34759, 256611}},
+{17900, 18, 75532, {1, 1, 3, 3, 23, 27, 55, 43, 485, 541, 1617, 3761, 1051, 7525, 19941, 52699, 35421, 162939}},
+{17901, 18, 75543, {1, 3, 7, 1, 25, 9, 113, 251, 477, 1005, 9, 3321, 5817, 965, 18523, 29407, 53353, 205575}},
+{17902, 18, 75549, {1, 1, 7, 11, 9, 31, 111, 175, 227, 33, 1745, 1141, 1547, 2113, 8785, 40273, 100301, 190749}},
+{17903, 18, 75559, {1, 1, 5, 11, 19, 49, 45, 197, 457, 223, 91, 2769, 6331, 1161, 6609, 61905, 42257, 152117}},
+{17904, 18, 75563, {1, 1, 7, 11, 1, 17, 37, 153, 431, 933, 269, 1529, 1297, 15567, 149, 41701, 59867, 93631}},
+{17905, 18, 75568, {1, 1, 5, 9, 25, 33, 83, 127, 305, 667, 343, 185, 3527, 13079, 10567, 35753, 72191, 214091}},
+{17906, 18, 75598, {1, 3, 7, 1, 1, 7, 75, 241, 185, 81, 2043, 3081, 3563, 385, 3055, 59421, 27081, 32521}},
+{17907, 18, 75612, {1, 1, 3, 5, 31, 1, 101, 21, 69, 979, 917, 695, 5601, 12251, 15031, 18715, 116985, 53071}},
+{17908, 18, 75622, {1, 1, 3, 9, 23, 57, 91, 127, 327, 979, 721, 3855, 1131, 997, 32227, 33843, 128299, 15239}},
+{17909, 18, 75640, {1, 3, 7, 13, 23, 1, 87, 105, 259, 939, 1935, 1983, 6619, 1611, 31901, 14745, 96641, 211945}},
+{17910, 18, 75683, {1, 1, 3, 5, 25, 17, 39, 95, 137, 971, 377, 2493, 981, 329, 25845, 44513, 100561, 57985}},
+{17911, 18, 75689, {1, 1, 3, 9, 27, 37, 69, 103, 167, 131, 487, 2935, 7099, 15375, 4825, 12209, 117165, 84909}},
+{17912, 18, 75690, {1, 3, 1, 15, 27, 19, 115, 239, 247, 243, 83, 1535, 8095, 3953, 25721, 62983, 89045, 16783}},
+{17913, 18, 75692, {1, 1, 5, 1, 19, 13, 125, 39, 439, 411, 171, 155, 5117, 15137, 19851, 251, 37921, 97209}},
+{17914, 18, 75752, {1, 1, 1, 5, 13, 41, 17, 97, 215, 323, 1333, 775, 1155, 15269, 19943, 48489, 71741, 202501}},
+{17915, 18, 75766, {1, 3, 5, 3, 1, 31, 55, 125, 69, 437, 1649, 2791, 8027, 15509, 31575, 8491, 106953, 155215}},
+{17916, 18, 75769, {1, 3, 3, 13, 19, 45, 39, 63, 227, 67, 2021, 1243, 6525, 7211, 6275, 39719, 74513, 6713}},
+{17917, 18, 75791, {1, 1, 5, 11, 13, 45, 15, 101, 171, 613, 1561, 2939, 3849, 2917, 29765, 2027, 53617, 59939}},
+{17918, 18, 75794, {1, 1, 5, 9, 27, 21, 119, 19, 441, 759, 703, 2985, 3007, 2087, 5207, 64403, 20273, 66181}},
+{17919, 18, 75806, {1, 1, 7, 13, 21, 3, 49, 3, 485, 883, 1863, 1925, 877, 10009, 24191, 58639, 107755, 106539}},
+{17920, 18, 75809, {1, 1, 1, 5, 27, 37, 23, 185, 281, 533, 437, 555, 8151, 6489, 22343, 4573, 91577, 167919}},
+{17921, 18, 75819, {1, 1, 7, 15, 3, 61, 103, 221, 223, 703, 133, 2923, 1027, 14643, 26413, 16523, 107223, 97185}},
+{17922, 18, 75834, {1, 3, 1, 11, 13, 15, 1, 203, 363, 675, 511, 3225, 1163, 741, 16063, 8097, 95905, 148465}},
+{17923, 18, 75895, {1, 3, 1, 7, 11, 11, 11, 243, 371, 129, 209, 3533, 1279, 12181, 31973, 29165, 122089, 115117}},
+{17924, 18, 75908, {1, 3, 1, 5, 25, 17, 31, 45, 215, 809, 1443, 3245, 1005, 2903, 20783, 23041, 96577, 192063}},
+{17925, 18, 75951, {1, 3, 3, 3, 19, 17, 101, 219, 91, 805, 189, 761, 4771, 11629, 7285, 21631, 21691, 47421}},
+{17926, 18, 75960, {1, 3, 7, 1, 31, 11, 71, 149, 303, 793, 35, 3109, 2769, 11593, 31839, 2053, 4541, 202997}},
+{17927, 18, 75965, {1, 1, 1, 3, 11, 19, 113, 249, 141, 659, 1117, 2145, 2617, 1075, 25347, 12913, 27457, 222095}},
+{17928, 18, 75974, {1, 3, 1, 3, 5, 23, 41, 57, 193, 815, 1293, 1109, 7597, 999, 10773, 41065, 18555, 35617}},
+{17929, 18, 75978, {1, 1, 3, 1, 31, 11, 127, 99, 163, 293, 299, 3415, 3761, 8781, 5327, 47631, 56411, 242787}},
+{17930, 18, 75998, {1, 3, 7, 13, 3, 41, 23, 169, 419, 725, 1419, 2643, 5265, 77, 24077, 18639, 78665, 205303}},
+{17931, 18, 76001, {1, 1, 5, 1, 31, 39, 39, 205, 413, 393, 1713, 309, 707, 4153, 10461, 16053, 26963, 253993}},
+{17932, 18, 76007, {1, 3, 7, 5, 23, 37, 125, 87, 199, 631, 1935, 551, 7047, 4585, 21257, 42345, 39365, 249393}},
+{17933, 18, 76016, {1, 3, 5, 13, 17, 55, 29, 209, 151, 465, 155, 363, 3097, 4093, 9869, 23297, 33973, 115543}},
+{17934, 18, 76091, {1, 1, 1, 13, 23, 59, 83, 71, 145, 717, 127, 1299, 1701, 10885, 5343, 40793, 87819, 66621}},
+{17935, 18, 76119, {1, 3, 3, 9, 19, 37, 23, 11, 269, 603, 871, 851, 837, 15303, 7595, 56481, 57819, 185065}},
+{17936, 18, 76135, {1, 3, 1, 1, 3, 15, 11, 249, 413, 723, 1403, 3233, 2747, 10335, 7127, 63285, 29237, 191953}},
+{17937, 18, 76170, {1, 3, 1, 1, 11, 31, 67, 139, 51, 413, 521, 969, 171, 5943, 31613, 16477, 85771, 202139}},
+{17938, 18, 76189, {1, 3, 7, 5, 5, 21, 109, 25, 463, 873, 493, 2673, 6409, 11199, 17195, 40623, 76821, 72509}},
+{17939, 18, 76214, {1, 1, 7, 7, 11, 1, 95, 43, 243, 67, 1289, 3219, 2255, 4957, 17561, 40499, 48537, 108809}},
+{17940, 18, 76225, {1, 1, 7, 15, 3, 39, 45, 75, 43, 821, 533, 4043, 1503, 83, 26937, 56327, 114149, 156845}},
+{17941, 18, 76235, {1, 3, 1, 1, 31, 21, 59, 1, 77, 147, 137, 1827, 4123, 2791, 27859, 57921, 40569, 134753}},
+{17942, 18, 76259, {1, 1, 5, 13, 31, 41, 111, 11, 181, 963, 459, 2771, 6123, 4035, 1627, 2047, 109537, 33653}},
+{17943, 18, 76261, {1, 3, 5, 7, 31, 57, 17, 21, 5, 761, 1833, 1279, 1239, 10089, 22531, 32547, 82699, 28389}},
+{17944, 18, 76262, {1, 3, 5, 13, 11, 39, 11, 61, 299, 753, 1067, 1347, 5189, 12859, 681, 46309, 31873, 90333}},
+{17945, 18, 76266, {1, 3, 1, 5, 13, 27, 119, 205, 377, 457, 817, 3017, 279, 1859, 30241, 52089, 61445, 176203}},
+{17946, 18, 76286, {1, 1, 3, 5, 11, 35, 17, 163, 27, 1001, 417, 2899, 1959, 5513, 1441, 19743, 67147, 236591}},
+{17947, 18, 76289, {1, 3, 5, 13, 15, 39, 53, 179, 447, 675, 933, 1261, 4415, 9845, 28459, 33497, 107375, 156855}},
+{17948, 18, 76310, {1, 3, 3, 13, 27, 31, 11, 191, 413, 1011, 2035, 3965, 2071, 5429, 16247, 7439, 15079, 225041}},
+{17949, 18, 76319, {1, 3, 3, 11, 7, 23, 87, 215, 241, 687, 1351, 2399, 4677, 12967, 22957, 10443, 116701, 155477}},
+{17950, 18, 76364, {1, 3, 7, 5, 25, 55, 5, 197, 359, 879, 619, 1969, 1513, 12743, 10953, 28343, 63685, 39115}},
+{17951, 18, 76375, {1, 1, 3, 1, 19, 15, 63, 7, 305, 343, 1333, 3845, 377, 14031, 28383, 4271, 60063, 11827}},
+{17952, 18, 76392, {1, 3, 5, 15, 25, 21, 115, 101, 171, 735, 787, 3143, 593, 8793, 4121, 15471, 53491, 20617}},
+{17953, 18, 76422, {1, 1, 5, 15, 15, 51, 103, 17, 433, 611, 1351, 1729, 6147, 11623, 3, 6319, 6133, 19029}},
+{17954, 18, 76450, {1, 3, 1, 13, 29, 15, 115, 97, 505, 985, 745, 745, 1459, 7193, 1247, 58901, 114255, 212849}},
+{17955, 18, 76496, {1, 1, 7, 1, 1, 53, 99, 35, 377, 723, 1751, 2625, 5113, 13295, 20133, 26831, 41657, 51717}},
+{17956, 18, 76521, {1, 3, 5, 15, 15, 39, 17, 227, 351, 435, 49, 203, 6959, 11673, 15755, 29733, 51445, 64619}},
+{17957, 18, 76522, {1, 1, 1, 3, 25, 51, 57, 137, 415, 49, 355, 2149, 7607, 10781, 30363, 43889, 55543, 36637}},
+{17958, 18, 76527, {1, 1, 7, 5, 5, 15, 73, 189, 153, 949, 527, 587, 513, 12891, 16765, 41477, 75569, 80747}},
+{17959, 18, 76536, {1, 1, 5, 5, 9, 5, 3, 225, 115, 125, 821, 3551, 4833, 927, 24331, 63669, 26549, 220159}},
+{17960, 18, 76541, {1, 1, 3, 9, 21, 7, 9, 183, 391, 783, 493, 2785, 3879, 8311, 9935, 60629, 119329, 5791}},
+{17961, 18, 76553, {1, 1, 5, 15, 15, 41, 61, 97, 33, 29, 199, 3335, 1531, 6107, 757, 33797, 3001, 224507}},
+{17962, 18, 76568, {1, 1, 3, 9, 13, 39, 25, 247, 407, 1, 1129, 1453, 7091, 5557, 8657, 33961, 100763, 25099}},
+{17963, 18, 76574, {1, 3, 3, 13, 31, 21, 69, 73, 431, 827, 861, 235, 2369, 4283, 27183, 29095, 99957, 97577}},
+{17964, 18, 76584, {1, 1, 7, 13, 1, 25, 21, 173, 365, 921, 21, 3527, 2481, 8795, 25621, 41755, 127249, 221385}},
+{17965, 18, 76604, {1, 1, 1, 5, 25, 25, 65, 203, 305, 373, 527, 4033, 3483, 9403, 28669, 32083, 52273, 77037}},
+{17966, 18, 76607, {1, 3, 1, 15, 9, 23, 19, 7, 29, 83, 1163, 1147, 5315, 2381, 21203, 33915, 109511, 40669}},
+{17967, 18, 76609, {1, 3, 7, 15, 23, 19, 69, 127, 113, 937, 935, 1067, 2431, 7677, 21327, 44095, 82799, 5715}},
+{17968, 18, 76669, {1, 1, 5, 5, 7, 37, 107, 223, 433, 515, 393, 1721, 1977, 6383, 18835, 54841, 103263, 196997}},
+{17969, 18, 76683, {1, 1, 1, 3, 1, 11, 85, 173, 259, 685, 595, 1635, 6979, 4483, 8097, 42249, 56259, 105925}},
+{17970, 18, 76745, {1, 1, 7, 7, 1, 23, 11, 253, 187, 665, 313, 3745, 2423, 15835, 32085, 48643, 75625, 47511}},
+{17971, 18, 76753, {1, 1, 3, 5, 1, 59, 127, 83, 501, 387, 977, 3515, 7921, 12329, 14757, 20287, 49699, 91237}},
+{17972, 18, 76754, {1, 3, 5, 11, 31, 45, 51, 109, 319, 621, 1013, 3519, 4023, 12099, 28829, 26691, 83131, 261497}},
+{17973, 18, 76756, {1, 1, 3, 3, 5, 35, 51, 253, 253, 569, 1017, 2299, 8159, 13783, 22123, 55213, 111527, 110699}},
+{17974, 18, 76760, {1, 3, 7, 3, 9, 5, 59, 129, 41, 845, 723, 1607, 3047, 14323, 19277, 39447, 12465, 45925}},
+{17975, 18, 76782, {1, 1, 3, 1, 17, 35, 51, 79, 115, 361, 739, 2037, 6167, 14699, 28187, 65271, 67285, 48489}},
+{17976, 18, 76821, {1, 3, 1, 11, 1, 29, 95, 181, 419, 235, 745, 621, 3889, 2933, 743, 23801, 32057, 54103}},
+{17977, 18, 76828, {1, 3, 1, 11, 17, 47, 43, 55, 7, 695, 1653, 3983, 961, 3037, 8669, 10039, 86571, 6981}},
+{17978, 18, 76849, {1, 1, 5, 15, 13, 19, 67, 141, 291, 511, 1913, 397, 7423, 6541, 21845, 49821, 126047, 218587}},
+{17979, 18, 76850, {1, 1, 5, 3, 11, 13, 103, 213, 189, 115, 1495, 2695, 2127, 11979, 13609, 46615, 64775, 206417}},
+{17980, 18, 76870, {1, 3, 1, 5, 5, 9, 57, 207, 253, 251, 1155, 1319, 6699, 6613, 21757, 49703, 124879, 89987}},
+{17981, 18, 76874, {1, 3, 5, 7, 23, 25, 35, 81, 165, 789, 771, 415, 5557, 8431, 12043, 44359, 9447, 229481}},
+{17982, 18, 76898, {1, 1, 1, 13, 17, 21, 63, 251, 387, 767, 85, 3901, 3227, 10329, 5049, 56173, 58065, 78595}},
+{17983, 18, 76903, {1, 3, 1, 15, 23, 5, 45, 7, 123, 389, 1041, 1223, 5865, 5365, 2915, 24861, 106893, 170769}},
+{17984, 18, 76910, {1, 3, 7, 15, 27, 61, 27, 59, 309, 103, 279, 1829, 1501, 11277, 4461, 34817, 60973, 99805}},
+{17985, 18, 76921, {1, 1, 3, 9, 1, 25, 57, 85, 411, 699, 911, 1643, 2687, 13539, 10187, 21597, 18883, 212975}},
+{17986, 18, 76968, {1, 1, 3, 7, 5, 7, 81, 209, 225, 321, 1867, 2189, 6315, 5393, 8859, 47471, 41677, 222455}},
+{17987, 18, 77013, {1, 1, 5, 11, 27, 33, 119, 159, 273, 659, 883, 3773, 6519, 15449, 17219, 23923, 33749, 225489}},
+{17988, 18, 77027, {1, 1, 7, 13, 29, 39, 1, 161, 165, 531, 1019, 2369, 2093, 4341, 24945, 28537, 49467, 258065}},
+{17989, 18, 77042, {1, 3, 3, 3, 15, 59, 23, 143, 377, 943, 1329, 977, 7025, 2167, 17973, 65087, 115757, 75959}},
+{17990, 18, 77059, {1, 1, 1, 15, 17, 55, 33, 167, 43, 719, 51, 3873, 3317, 10763, 639, 58195, 20023, 100725}},
+{17991, 18, 77062, {1, 1, 7, 5, 17, 23, 71, 249, 23, 929, 467, 3073, 3355, 1343, 18755, 12247, 49737, 184103}},
+{17992, 18, 77074, {1, 3, 3, 15, 1, 9, 17, 193, 157, 265, 983, 1825, 4805, 2131, 22117, 32937, 57, 261867}},
+{17993, 18, 77076, {1, 3, 5, 9, 5, 1, 101, 141, 511, 489, 73, 1789, 1303, 2633, 709, 11891, 44897, 191229}},
+{17994, 18, 77110, {1, 1, 7, 15, 1, 27, 121, 7, 129, 421, 725, 1421, 3883, 13335, 7247, 8393, 85029, 127691}},
+{17995, 18, 77113, {1, 1, 3, 9, 19, 53, 121, 115, 85, 909, 1535, 3261, 7063, 16381, 1719, 19847, 19041, 215433}},
+{17996, 18, 77131, {1, 1, 7, 3, 17, 45, 91, 187, 181, 829, 609, 931, 5727, 3971, 14567, 15871, 9825, 184165}},
+{17997, 18, 77157, {1, 1, 1, 3, 5, 29, 7, 249, 361, 815, 1101, 1485, 6879, 5379, 7179, 27467, 101427, 196089}},
+{17998, 18, 77158, {1, 1, 5, 7, 23, 11, 27, 175, 237, 747, 1911, 3107, 961, 6649, 29887, 11003, 27561, 233841}},
+{17999, 18, 77216, {1, 1, 1, 5, 11, 5, 125, 227, 303, 315, 1879, 817, 7445, 1447, 9333, 54825, 118865, 216397}},
+{18000, 18, 77246, {1, 1, 3, 13, 17, 33, 27, 95, 245, 25, 1741, 2633, 1869, 14111, 24507, 61287, 46397, 220803}},
+{18001, 18, 77258, {1, 1, 7, 7, 25, 5, 41, 101, 171, 333, 497, 3417, 4921, 4553, 25487, 51529, 72873, 43525}},
+{18002, 18, 77281, {1, 1, 7, 7, 9, 19, 25, 161, 235, 929, 1663, 3237, 323, 3889, 31423, 2345, 63113, 212659}},
+{18003, 18, 77284, {1, 1, 5, 13, 29, 59, 39, 25, 393, 519, 429, 1461, 5867, 113, 28091, 36813, 47827, 163407}},
+{18004, 18, 77294, {1, 3, 5, 13, 15, 49, 85, 161, 83, 389, 765, 3349, 4659, 11007, 24749, 51121, 93511, 229885}},
+{18005, 18, 77302, {1, 3, 5, 11, 5, 27, 107, 233, 221, 425, 941, 1181, 5403, 4373, 32625, 41991, 2019, 245967}},
+{18006, 18, 77306, {1, 3, 5, 9, 9, 53, 97, 27, 221, 731, 1301, 3517, 4407, 11369, 4251, 31121, 4813, 42029}},
+{18007, 18, 77315, {1, 1, 1, 9, 17, 59, 107, 247, 231, 123, 1177, 3299, 6163, 4855, 14547, 63171, 45201, 27711}},
+{18008, 18, 77352, {1, 3, 7, 3, 25, 31, 63, 37, 123, 457, 1531, 3723, 4807, 14665, 17973, 42547, 5417, 170323}},
+{18009, 18, 77360, {1, 3, 7, 3, 17, 19, 57, 7, 359, 741, 385, 3127, 855, 10803, 30093, 24501, 53629, 40447}},
+{18010, 18, 77365, {1, 3, 7, 15, 11, 45, 49, 125, 445, 795, 113, 2425, 7085, 7337, 16297, 26447, 94369, 12371}},
+{18011, 18, 77370, {1, 3, 7, 9, 29, 59, 35, 191, 123, 619, 415, 1081, 2469, 4125, 25587, 7853, 119781, 9447}},
+{18012, 18, 77378, {1, 3, 1, 15, 13, 13, 111, 89, 381, 757, 389, 253, 6929, 33, 8263, 17385, 122129, 146679}},
+{18013, 18, 77380, {1, 1, 3, 3, 15, 35, 101, 95, 479, 577, 1645, 3781, 7533, 4665, 6561, 49897, 72413, 151383}},
+{18014, 18, 77407, {1, 1, 1, 1, 7, 49, 23, 223, 189, 763, 227, 2805, 8093, 389, 11525, 30915, 91341, 210231}},
+{18015, 18, 77408, {1, 1, 7, 3, 19, 23, 3, 137, 79, 569, 1833, 2091, 4235, 10739, 22855, 33845, 120141, 220267}},
+{18016, 18, 77414, {1, 3, 7, 3, 11, 43, 85, 63, 419, 681, 365, 3017, 3603, 6413, 13515, 16003, 107949, 241261}},
+{18017, 18, 77444, {1, 1, 5, 13, 3, 35, 41, 193, 189, 999, 1395, 2431, 2227, 7245, 23929, 16137, 14591, 54999}},
+{18018, 18, 77454, {1, 1, 7, 15, 23, 51, 47, 77, 31, 25, 589, 611, 371, 13329, 5873, 2133, 40351, 145293}},
+{18019, 18, 77481, {1, 1, 7, 15, 17, 19, 53, 155, 309, 573, 1059, 3557, 2445, 12205, 4497, 32061, 130293, 73859}},
+{18020, 18, 77482, {1, 1, 7, 13, 3, 25, 71, 157, 237, 185, 1035, 1759, 1331, 13533, 25635, 811, 54391, 91109}},
+{18021, 18, 77531, {1, 1, 1, 11, 5, 21, 99, 31, 259, 413, 2033, 2187, 755, 4591, 28641, 64031, 88499, 160789}},
+{18022, 18, 77544, {1, 3, 7, 13, 29, 33, 13, 157, 97, 981, 329, 81, 6351, 4171, 10925, 22733, 72521, 105477}},
+{18023, 18, 77552, {1, 3, 7, 9, 11, 31, 97, 35, 337, 309, 847, 3429, 2697, 3141, 19481, 43679, 11129, 205757}},
+{18024, 18, 77569, {1, 3, 1, 7, 27, 45, 123, 193, 439, 639, 633, 1375, 7307, 1599, 23379, 56811, 100877, 228687}},
+{18025, 18, 77579, {1, 3, 7, 1, 29, 43, 103, 131, 103, 933, 143, 2431, 2221, 4565, 20841, 58611, 49163, 13673}},
+{18026, 18, 77610, {1, 3, 5, 13, 25, 17, 121, 17, 455, 941, 1577, 509, 5401, 797, 29573, 38373, 50527, 17951}},
+{18027, 18, 77612, {1, 1, 1, 13, 25, 21, 77, 253, 199, 871, 935, 3919, 1687, 6653, 20345, 56969, 77989, 244767}},
+{18028, 18, 77623, {1, 1, 3, 1, 17, 5, 5, 191, 279, 33, 579, 651, 969, 6091, 11659, 1643, 17935, 85145}},
+{18029, 18, 77649, {1, 3, 3, 9, 29, 1, 103, 39, 83, 295, 1237, 207, 4837, 7899, 27879, 23195, 29549, 206885}},
+{18030, 18, 77650, {1, 3, 5, 1, 9, 55, 115, 37, 225, 447, 943, 1133, 6203, 949, 9973, 4309, 43969, 166795}},
+{18031, 18, 77661, {1, 1, 7, 7, 17, 43, 75, 251, 35, 489, 1011, 355, 4113, 2377, 13775, 34935, 84905, 252973}},
+{18032, 18, 77675, {1, 3, 3, 3, 11, 45, 3, 1, 135, 499, 81, 3265, 6657, 3875, 27565, 60931, 13117, 87931}},
+{18033, 18, 77686, {1, 1, 3, 1, 9, 1, 77, 69, 137, 241, 1613, 2607, 3307, 171, 13551, 54529, 45937, 180411}},
+{18034, 18, 77742, {1, 1, 1, 1, 19, 29, 77, 255, 95, 461, 567, 1103, 2753, 10627, 19479, 43411, 128565, 29869}},
+{18035, 18, 77791, {1, 1, 3, 5, 5, 63, 123, 159, 165, 733, 1107, 1711, 5039, 9221, 15541, 5527, 27629, 206505}},
+{18036, 18, 77792, {1, 3, 1, 3, 7, 45, 73, 63, 413, 693, 433, 2281, 3981, 7719, 31473, 56939, 70391, 67467}},
+{18037, 18, 77807, {1, 1, 1, 11, 19, 33, 113, 151, 427, 603, 1653, 2451, 5367, 12171, 14373, 33175, 62013, 209273}},
+{18038, 18, 77815, {1, 3, 5, 5, 17, 37, 109, 5, 187, 293, 617, 2663, 7381, 14217, 23561, 48999, 108717, 248289}},
+{18039, 18, 77842, {1, 1, 5, 1, 9, 27, 35, 127, 355, 479, 281, 2081, 7303, 259, 8893, 59141, 20927, 61611}},
+{18040, 18, 77847, {1, 3, 3, 15, 31, 33, 71, 209, 315, 363, 593, 1035, 8029, 12501, 2859, 54745, 39391, 153259}},
+{18041, 18, 77899, {1, 3, 3, 11, 21, 39, 35, 173, 171, 15, 987, 3737, 7415, 1827, 973, 6831, 108643, 241333}},
+{18042, 18, 77901, {1, 3, 7, 9, 17, 37, 127, 243, 153, 195, 113, 309, 5301, 13619, 7927, 35385, 9501, 99241}},
+{18043, 18, 77904, {1, 3, 5, 13, 23, 9, 81, 235, 139, 635, 443, 2235, 2613, 2389, 18431, 8409, 2885, 254811}},
+{18044, 18, 77914, {1, 3, 7, 9, 1, 5, 15, 109, 141, 173, 1059, 1961, 7945, 10381, 17337, 19591, 42173, 119831}},
+{18045, 18, 77925, {1, 3, 1, 13, 19, 7, 111, 111, 345, 327, 1147, 2293, 49, 16213, 25309, 60537, 50421, 108467}},
+{18046, 18, 77950, {1, 1, 5, 1, 3, 23, 63, 219, 69, 879, 1397, 3857, 1859, 1939, 4851, 26549, 86019, 7927}},
+{18047, 18, 77959, {1, 3, 1, 13, 23, 61, 25, 31, 301, 189, 1031, 2817, 829, 8777, 26869, 54405, 43535, 234687}},
+{18048, 18, 77994, {1, 1, 1, 9, 11, 31, 13, 139, 77, 567, 949, 3415, 6955, 14973, 9565, 37911, 18395, 94167}},
+{18049, 18, 78004, {1, 3, 5, 13, 17, 17, 21, 213, 171, 993, 1001, 979, 5085, 3909, 11797, 48669, 73541, 48979}},
+{18050, 18, 78043, {1, 1, 7, 9, 7, 37, 35, 107, 347, 239, 585, 2883, 3235, 1053, 14871, 25799, 4861, 56335}},
+{18051, 18, 78052, {1, 1, 3, 5, 19, 7, 91, 139, 325, 921, 863, 209, 845, 15943, 8281, 55103, 110193, 216091}},
+{18052, 18, 78061, {1, 3, 1, 13, 31, 33, 65, 155, 177, 103, 1991, 343, 6299, 3587, 30215, 64335, 114301, 220403}},
+{18053, 18, 78064, {1, 3, 5, 3, 31, 37, 121, 157, 443, 349, 1097, 3683, 503, 14061, 14685, 29755, 61543, 232983}},
+{18054, 18, 78084, {1, 3, 3, 11, 17, 59, 29, 161, 381, 791, 1647, 1077, 6369, 1095, 17279, 43141, 65003, 144609}},
+{18055, 18, 78094, {1, 1, 5, 1, 1, 15, 67, 77, 3, 585, 1909, 1485, 3003, 591, 4711, 10279, 75901, 226417}},
+{18056, 18, 78099, {1, 3, 7, 5, 1, 5, 5, 193, 469, 631, 1065, 607, 2751, 8163, 13633, 40563, 1417, 118169}},
+{18057, 18, 78129, {1, 1, 7, 9, 25, 25, 109, 27, 157, 495, 225, 1385, 4315, 995, 10591, 1629, 129939, 56765}},
+{18058, 18, 78142, {1, 3, 1, 7, 9, 23, 61, 63, 35, 145, 1537, 1029, 4225, 1467, 10519, 32861, 519, 53983}},
+{18059, 18, 78149, {1, 3, 3, 11, 7, 59, 25, 199, 403, 967, 1089, 1121, 1063, 6701, 16827, 55479, 72983, 36873}},
+{18060, 18, 78153, {1, 1, 1, 13, 9, 27, 19, 23, 395, 229, 1837, 1231, 1737, 10475, 16743, 42369, 130331, 47255}},
+{18061, 18, 78171, {1, 1, 5, 7, 29, 15, 95, 155, 339, 65, 751, 2399, 5615, 2987, 16769, 57381, 113021, 41417}},
+{18062, 18, 78173, {1, 3, 1, 9, 15, 17, 1, 111, 197, 7, 417, 3999, 7261, 5939, 16773, 29275, 105559, 84685}},
+{18063, 18, 78174, {1, 3, 3, 13, 19, 31, 103, 1, 37, 269, 1257, 1397, 4293, 3019, 6503, 7727, 93943, 237313}},
+{18064, 18, 78195, {1, 1, 3, 9, 13, 37, 67, 129, 43, 669, 1331, 1787, 8185, 323, 18749, 13737, 86123, 154131}},
+{18065, 18, 78201, {1, 3, 1, 11, 3, 51, 13, 35, 197, 867, 559, 1381, 1057, 13293, 20603, 18633, 50503, 169685}},
+{18066, 18, 78202, {1, 3, 1, 11, 9, 35, 7, 51, 499, 885, 353, 4095, 6491, 5917, 15053, 18363, 99593, 213089}},
+{18067, 18, 78241, {1, 1, 3, 9, 19, 23, 107, 147, 339, 331, 1349, 2855, 3721, 13317, 26457, 783, 93949, 196051}},
+{18068, 18, 78247, {1, 1, 5, 1, 9, 61, 89, 217, 315, 385, 1729, 2641, 5753, 6269, 547, 33737, 20103, 31533}},
+{18069, 18, 78274, {1, 3, 5, 13, 13, 61, 3, 191, 57, 683, 1227, 1255, 3651, 10687, 9049, 6529, 60783, 28639}},
+{18070, 18, 78276, {1, 1, 7, 11, 25, 41, 79, 19, 383, 363, 1731, 1597, 1651, 15037, 22191, 51883, 41927, 82419}},
+{18071, 18, 78303, {1, 3, 5, 9, 15, 61, 39, 149, 49, 633, 709, 1743, 621, 14659, 3309, 64129, 91897, 74235}},
+{18072, 18, 78307, {1, 3, 7, 15, 5, 59, 7, 197, 111, 885, 1737, 855, 2807, 3817, 13759, 29989, 45105, 171689}},
+{18073, 18, 78328, {1, 1, 3, 9, 21, 25, 55, 67, 483, 437, 303, 703, 6993, 1971, 4565, 56117, 6105, 254517}},
+{18074, 18, 78344, {1, 3, 3, 13, 15, 13, 19, 3, 487, 751, 1185, 2985, 1619, 7139, 26087, 21105, 9049, 236153}},
+{18075, 18, 78362, {1, 1, 5, 7, 15, 55, 51, 231, 85, 953, 713, 659, 2021, 4271, 15961, 26873, 31141, 76635}},
+{18076, 18, 78367, {1, 3, 5, 1, 11, 39, 3, 223, 367, 903, 799, 415, 7247, 9539, 14479, 37195, 59951, 181935}},
+{18077, 18, 78368, {1, 1, 5, 3, 13, 47, 17, 159, 439, 859, 1067, 3111, 5277, 13973, 21999, 28381, 115685, 231483}},
+{18078, 18, 78409, {1, 1, 7, 15, 17, 21, 69, 131, 193, 479, 1075, 3271, 2057, 1295, 31235, 35027, 94145, 65419}},
+{18079, 18, 78412, {1, 3, 3, 5, 5, 21, 5, 81, 113, 259, 837, 831, 5985, 6717, 12041, 40355, 50957, 111185}},
+{18080, 18, 78417, {1, 1, 1, 9, 15, 47, 103, 195, 465, 739, 1415, 225, 3121, 12623, 7539, 17555, 36703, 217641}},
+{18081, 18, 78430, {1, 3, 1, 3, 31, 17, 91, 153, 221, 217, 525, 981, 281, 9869, 9713, 10669, 12049, 97615}},
+{18082, 18, 78433, {1, 1, 5, 7, 29, 1, 1, 199, 415, 843, 301, 941, 4589, 13301, 5833, 41311, 74019, 78537}},
+{18083, 18, 78440, {1, 1, 5, 11, 13, 5, 41, 127, 213, 917, 1297, 2281, 3193, 3877, 9517, 40685, 14657, 185139}},
+{18084, 18, 78451, {1, 1, 1, 7, 21, 45, 87, 33, 425, 487, 643, 271, 7087, 5979, 14795, 27575, 34541, 173251}},
+{18085, 18, 78453, {1, 3, 7, 5, 21, 11, 7, 169, 325, 905, 973, 2853, 7929, 8801, 1005, 60641, 45973, 81859}},
+{18086, 18, 78458, {1, 3, 3, 1, 1, 35, 39, 81, 93, 463, 697, 2309, 7769, 5169, 17595, 41447, 28837, 52613}},
+{18087, 18, 78467, {1, 1, 7, 1, 1, 23, 37, 17, 137, 873, 1657, 681, 503, 7887, 24463, 32453, 112727, 133347}},
+{18088, 18, 78479, {1, 1, 5, 9, 19, 35, 37, 85, 11, 245, 11, 3, 6475, 5953, 247, 49447, 32813, 243841}},
+{18089, 18, 78507, {1, 3, 5, 3, 19, 53, 37, 45, 431, 259, 1831, 1443, 2237, 7651, 20701, 22857, 50041, 119667}},
+{18090, 18, 78518, {1, 1, 7, 1, 5, 37, 113, 69, 389, 369, 1251, 1989, 7613, 10669, 4233, 33379, 72465, 256861}},
+{18091, 18, 78535, {1, 1, 7, 5, 27, 55, 17, 75, 373, 325, 1981, 1743, 7341, 319, 28169, 3587, 66057, 169723}},
+{18092, 18, 78542, {1, 3, 3, 15, 27, 31, 47, 91, 367, 245, 2045, 979, 2169, 10935, 29523, 64871, 119447, 92131}},
+{18093, 18, 78549, {1, 3, 7, 15, 9, 11, 93, 61, 249, 107, 1883, 2547, 375, 4195, 6451, 14533, 62529, 93557}},
+{18094, 18, 78554, {1, 1, 1, 3, 29, 61, 65, 155, 301, 1017, 131, 1567, 3649, 3447, 27943, 52111, 9133, 88147}},
+{18095, 18, 78556, {1, 1, 1, 1, 21, 59, 107, 151, 265, 707, 767, 2325, 8095, 14027, 15355, 15465, 83143, 116199}},
+{18096, 18, 78583, {1, 3, 1, 15, 23, 51, 31, 25, 439, 357, 1563, 1091, 2135, 1327, 18427, 60965, 29215, 157351}},
+{18097, 18, 78590, {1, 3, 3, 13, 29, 37, 25, 215, 149, 487, 703, 1787, 3641, 8301, 8795, 13845, 95245, 169793}},
+{18098, 18, 78615, {1, 3, 3, 11, 27, 3, 49, 87, 69, 687, 1181, 3405, 589, 12901, 14199, 48607, 74027, 181379}},
+{18099, 18, 78635, {1, 3, 5, 13, 9, 15, 33, 229, 135, 769, 1005, 2435, 4831, 5493, 16745, 64379, 20253, 52661}},
+{18100, 18, 78649, {1, 1, 1, 13, 9, 61, 33, 127, 339, 15, 945, 219, 4291, 6995, 29127, 61853, 40741, 170541}},
+{18101, 18, 78684, {1, 3, 3, 15, 9, 33, 75, 39, 327, 133, 733, 1125, 2747, 15031, 24575, 65013, 41997, 158679}},
+{18102, 18, 78691, {1, 1, 3, 9, 3, 9, 63, 83, 493, 175, 249, 1977, 8177, 4067, 2131, 12467, 86185, 73417}},
+{18103, 18, 78705, {1, 1, 3, 13, 29, 55, 91, 109, 73, 913, 1343, 2147, 105, 8763, 7613, 55749, 4339, 61253}},
+{18104, 18, 78724, {1, 1, 5, 5, 17, 19, 45, 57, 345, 835, 341, 1365, 5187, 7485, 22685, 32321, 67279, 141119}},
+{18105, 18, 78755, {1, 1, 3, 11, 9, 47, 11, 231, 241, 681, 255, 3663, 5547, 997, 2445, 64413, 55349, 61785}},
+{18106, 18, 78770, {1, 3, 5, 5, 23, 29, 23, 249, 149, 1011, 173, 271, 485, 1239, 81, 59277, 96669, 210859}},
+{18107, 18, 78772, {1, 3, 3, 1, 17, 9, 41, 39, 309, 131, 1431, 1497, 1669, 14191, 22795, 48951, 101731, 70847}},
+{18108, 18, 78818, {1, 1, 3, 15, 1, 11, 37, 79, 23, 1023, 585, 127, 7817, 15009, 3897, 44601, 83039, 240457}},
+{18109, 18, 78837, {1, 3, 5, 9, 21, 33, 55, 31, 193, 745, 1741, 3637, 7265, 8969, 11797, 33239, 29123, 126077}},
+{18110, 18, 78844, {1, 3, 3, 13, 31, 5, 87, 215, 271, 573, 1423, 2611, 947, 14669, 23785, 60579, 127099, 55877}},
+{18111, 18, 78849, {1, 3, 1, 13, 5, 53, 103, 85, 237, 457, 739, 1201, 133, 8589, 13471, 6707, 42257, 141989}},
+{18112, 18, 78909, {1, 1, 1, 5, 23, 3, 65, 159, 445, 823, 341, 1723, 6263, 9421, 16023, 19145, 52337, 229397}},
+{18113, 18, 78915, {1, 3, 5, 3, 15, 3, 15, 251, 407, 137, 951, 1319, 1035, 7713, 29579, 19591, 77841, 84949}},
+{18114, 18, 78941, {1, 1, 7, 15, 19, 25, 63, 141, 511, 11, 1027, 1209, 6627, 8127, 14879, 12965, 109973, 144501}},
+{18115, 18, 78958, {1, 1, 1, 3, 11, 57, 65, 169, 453, 197, 1249, 2933, 3743, 1971, 19373, 32109, 73265, 46185}},
+{18116, 18, 78975, {1, 1, 3, 1, 3, 1, 21, 47, 471, 565, 1795, 1771, 3187, 7189, 18627, 22993, 112319, 158693}},
+{18117, 18, 78979, {1, 1, 5, 7, 5, 25, 127, 113, 31, 609, 1273, 2799, 5713, 16091, 22239, 43617, 126003, 218991}},
+{18118, 18, 78986, {1, 3, 3, 7, 19, 59, 19, 185, 483, 431, 335, 565, 819, 2555, 18653, 36573, 50085, 31007}},
+{18119, 18, 79029, {1, 1, 3, 13, 17, 61, 5, 219, 297, 755, 2005, 391, 4927, 1517, 11341, 9527, 51739, 182599}},
+{18120, 18, 79030, {1, 3, 7, 9, 9, 3, 39, 211, 475, 717, 189, 819, 529, 469, 28559, 7321, 60213, 79505}},
+{18121, 18, 79044, {1, 3, 1, 9, 17, 39, 53, 65, 247, 145, 9, 1669, 7221, 8359, 11021, 29775, 24693, 208655}},
+{18122, 18, 79048, {1, 1, 5, 13, 7, 7, 31, 135, 375, 439, 1419, 3579, 4313, 14057, 31505, 55249, 5345, 69537}},
+{18123, 18, 79056, {1, 3, 5, 9, 21, 3, 125, 223, 9, 73, 1693, 281, 3941, 10377, 29365, 19807, 73973, 169113}},
+{18124, 18, 79095, {1, 3, 7, 15, 29, 41, 119, 75, 241, 79, 1969, 1091, 6241, 10685, 11579, 3791, 124443, 5051}},
+{18125, 18, 79099, {1, 3, 7, 15, 23, 53, 13, 255, 205, 547, 255, 1589, 7261, 15735, 14521, 29679, 109373, 236433}},
+{18126, 18, 79121, {1, 3, 7, 3, 17, 37, 71, 163, 95, 265, 1, 3239, 1779, 9047, 31387, 32291, 86741, 55317}},
+{18127, 18, 79150, {1, 3, 1, 9, 31, 55, 117, 247, 317, 673, 749, 1155, 7743, 6427, 25273, 49701, 62345, 20913}},
+{18128, 18, 79196, {1, 3, 3, 7, 27, 55, 35, 111, 69, 799, 213, 3011, 4359, 14763, 7387, 13281, 58397, 38415}},
+{18129, 18, 79199, {1, 1, 5, 9, 5, 61, 49, 219, 419, 297, 1019, 2181, 6069, 12957, 24637, 23317, 6389, 240893}},
+{18130, 18, 79220, {1, 1, 5, 15, 13, 57, 59, 43, 373, 647, 1407, 3955, 5583, 15229, 20935, 38007, 65971, 95987}},
+{18131, 18, 79229, {1, 1, 7, 7, 23, 17, 77, 91, 449, 75, 1059, 3337, 2041, 261, 25077, 28161, 44537, 189443}},
+{18132, 18, 79263, {1, 1, 7, 11, 9, 7, 117, 225, 457, 941, 161, 1825, 1101, 193, 32619, 37245, 102633, 86707}},
+{18133, 18, 79264, {1, 1, 1, 7, 13, 43, 33, 137, 275, 691, 1387, 1265, 759, 1457, 4877, 41813, 4159, 234397}},
+{18134, 18, 79296, {1, 3, 3, 1, 9, 23, 71, 39, 205, 175, 953, 2965, 3283, 6025, 5905, 34691, 120987, 71841}},
+{18135, 18, 79302, {1, 3, 1, 13, 31, 63, 49, 73, 299, 169, 1265, 2205, 1299, 10045, 6919, 26067, 56909, 42549}},
+{18136, 18, 79354, {1, 3, 3, 1, 31, 41, 75, 219, 457, 407, 5, 1901, 6823, 531, 3155, 64375, 38523, 68217}},
+{18137, 18, 79387, {1, 1, 7, 9, 7, 35, 123, 193, 145, 1021, 757, 3775, 2313, 11885, 11649, 61071, 129363, 120467}},
+{18138, 18, 79399, {1, 3, 7, 3, 29, 21, 127, 93, 415, 641, 453, 923, 7713, 9569, 5961, 25969, 31095, 93317}},
+{18139, 18, 79435, {1, 3, 3, 1, 5, 15, 21, 235, 211, 663, 385, 2429, 319, 11571, 17539, 42975, 43179, 100105}},
+{18140, 18, 79525, {1, 3, 7, 7, 25, 57, 51, 215, 393, 167, 1569, 3235, 5555, 3391, 2389, 36485, 21919, 164479}},
+{18141, 18, 79540, {1, 3, 3, 3, 29, 21, 81, 59, 239, 671, 605, 583, 2341, 2321, 28593, 19035, 10209, 36433}},
+{18142, 18, 79552, {1, 3, 3, 11, 31, 33, 1, 147, 111, 523, 427, 3545, 111, 8009, 29101, 34549, 122745, 82117}},
+{18143, 18, 79562, {1, 3, 5, 15, 19, 37, 97, 141, 387, 523, 467, 1657, 4161, 5505, 18091, 39597, 124423, 74827}},
+{18144, 18, 79576, {1, 1, 1, 11, 21, 63, 61, 13, 169, 851, 1863, 3307, 7189, 10791, 22619, 24431, 127781, 14717}},
+{18145, 18, 79579, {1, 1, 3, 13, 27, 41, 69, 127, 497, 565, 1489, 277, 2551, 15409, 9885, 187, 101319, 194121}},
+{18146, 18, 79605, {1, 1, 7, 7, 17, 45, 1, 139, 347, 503, 1189, 1459, 6117, 14319, 22153, 2915, 91991, 246679}},
+{18147, 18, 79618, {1, 3, 3, 3, 9, 41, 25, 199, 327, 295, 945, 2765, 563, 11605, 24267, 37729, 80057, 169479}},
+{18148, 18, 79648, {1, 1, 7, 3, 23, 19, 13, 219, 235, 837, 1015, 2071, 2727, 3989, 32539, 26713, 112391, 163943}},
+{18149, 18, 79654, {1, 3, 3, 9, 21, 27, 17, 187, 315, 753, 817, 3053, 5961, 973, 23973, 37621, 105637, 247711}},
+{18150, 18, 79666, {1, 1, 7, 1, 11, 15, 45, 25, 421, 213, 663, 3829, 469, 15889, 28773, 14323, 107705, 111729}},
+{18151, 18, 79686, {1, 1, 1, 7, 7, 7, 51, 189, 457, 95, 1903, 639, 1933, 7409, 22327, 18959, 42679, 158987}},
+{18152, 18, 79697, {1, 1, 5, 9, 13, 13, 49, 159, 387, 365, 1799, 2399, 6375, 14965, 32495, 5383, 73479, 5653}},
+{18153, 18, 79700, {1, 1, 3, 1, 29, 23, 81, 73, 183, 563, 435, 133, 5731, 6663, 21219, 60007, 101215, 68775}},
+{18154, 18, 79723, {1, 1, 7, 11, 31, 47, 43, 159, 221, 745, 1317, 2405, 4563, 4073, 27675, 14225, 114231, 222553}},
+{18155, 18, 79749, {1, 1, 1, 5, 11, 63, 105, 99, 413, 81, 771, 547, 1633, 8097, 30431, 31417, 101379, 163575}},
+{18156, 18, 79750, {1, 1, 3, 9, 23, 29, 123, 149, 241, 267, 1925, 467, 7743, 4473, 12223, 10521, 86265, 89949}},
+{18157, 18, 79764, {1, 3, 5, 1, 31, 29, 111, 67, 311, 851, 1919, 2563, 3725, 4035, 7241, 13859, 105207, 200599}},
+{18158, 18, 79771, {1, 3, 7, 3, 19, 53, 113, 107, 133, 243, 2021, 2669, 4633, 14393, 24827, 1233, 81471, 20105}},
+{18159, 18, 79774, {1, 1, 1, 5, 3, 23, 43, 149, 157, 875, 1175, 963, 6189, 7343, 13913, 41375, 112857, 236047}},
+{18160, 18, 79780, {1, 3, 5, 15, 11, 31, 43, 225, 469, 229, 703, 3033, 2341, 10309, 12057, 13325, 109019, 130789}},
+{18161, 18, 79789, {1, 1, 1, 7, 27, 47, 45, 49, 371, 971, 1121, 2179, 1267, 9499, 10771, 28781, 77059, 90765}},
+{18162, 18, 79798, {1, 1, 7, 1, 17, 27, 59, 169, 269, 217, 983, 1365, 1985, 12287, 5385, 46407, 24827, 155761}},
+{18163, 18, 79821, {1, 1, 7, 11, 9, 5, 19, 205, 159, 937, 763, 3823, 3625, 14209, 32031, 58879, 118449, 50723}},
+{18164, 18, 79850, {1, 1, 5, 3, 25, 55, 27, 35, 125, 999, 1541, 3883, 539, 5691, 18071, 63199, 112089, 194825}},
+{18165, 18, 79864, {1, 3, 3, 1, 27, 43, 57, 225, 173, 673, 1339, 3433, 5743, 1375, 32429, 35071, 98035, 229973}},
+{18166, 18, 79898, {1, 3, 3, 9, 3, 51, 5, 203, 439, 41, 529, 863, 6735, 13211, 7075, 55637, 24481, 46673}},
+{18167, 18, 79904, {1, 1, 5, 11, 15, 23, 93, 7, 181, 843, 777, 1299, 1941, 7147, 26253, 10967, 5387, 84611}},
+{18168, 18, 79934, {1, 3, 1, 7, 9, 57, 127, 155, 257, 423, 1421, 261, 4477, 11169, 22997, 12371, 8705, 135883}},
+{18169, 18, 79936, {1, 3, 1, 9, 17, 9, 15, 209, 427, 889, 1939, 3623, 2587, 4037, 32233, 40391, 32529, 63851}},
+{18170, 18, 79942, {1, 3, 3, 13, 3, 19, 49, 155, 213, 239, 817, 1787, 2999, 9955, 20155, 44711, 41367, 59623}},
+{18171, 18, 79945, {1, 3, 7, 5, 5, 39, 103, 181, 405, 85, 1997, 3639, 1259, 10737, 189, 44377, 23589, 89371}},
+{18172, 18, 79963, {1, 3, 5, 11, 15, 13, 57, 81, 203, 773, 1571, 3235, 6625, 13803, 2091, 64265, 131013, 189705}},
+{18173, 18, 79987, {1, 1, 1, 13, 15, 3, 113, 159, 149, 55, 355, 2345, 5043, 4067, 23277, 32647, 43755, 5445}},
+{18174, 18, 80057, {1, 3, 3, 9, 31, 7, 67, 177, 423, 269, 1731, 3957, 4383, 13483, 14653, 8243, 57689, 37375}},
+{18175, 18, 80077, {1, 1, 3, 5, 25, 5, 77, 199, 161, 859, 497, 1679, 6809, 4877, 1107, 16443, 15505, 138155}},
+{18176, 18, 80078, {1, 3, 5, 1, 11, 57, 7, 49, 145, 569, 571, 2679, 7531, 14517, 12425, 6285, 116961, 116397}},
+{18177, 18, 80080, {1, 1, 7, 11, 1, 37, 65, 43, 151, 419, 801, 3231, 5321, 10725, 12885, 62771, 16507, 179009}},
+{18178, 18, 80102, {1, 1, 5, 11, 29, 55, 89, 81, 325, 47, 1037, 3235, 2017, 10875, 8919, 25115, 118035, 178227}},
+{18179, 18, 80106, {1, 3, 1, 7, 1, 43, 101, 25, 449, 617, 381, 3437, 6655, 1291, 18693, 53939, 99143, 195695}},
+{18180, 18, 80111, {1, 3, 1, 5, 23, 7, 47, 159, 295, 939, 173, 3087, 1497, 6353, 13893, 13465, 118973, 193737}},
+{18181, 18, 80152, {1, 1, 3, 9, 3, 41, 65, 79, 449, 345, 2039, 1193, 5915, 13689, 1257, 23273, 48515, 256793}},
+{18182, 18, 80155, {1, 3, 5, 11, 11, 55, 13, 117, 343, 899, 1853, 373, 6885, 12863, 1209, 34433, 48215, 218187}},
+{18183, 18, 80173, {1, 3, 7, 7, 3, 45, 103, 145, 55, 507, 743, 4027, 2075, 15707, 4473, 50077, 64551, 204305}},
+{18184, 18, 80186, {1, 1, 3, 5, 31, 45, 123, 233, 363, 1003, 411, 1459, 6455, 985, 29451, 17625, 44153, 137097}},
+{18185, 18, 80203, {1, 3, 3, 1, 27, 11, 53, 251, 41, 43, 495, 107, 6145, 8785, 28997, 7181, 92903, 105785}},
+{18186, 18, 80223, {1, 1, 3, 11, 13, 5, 117, 141, 463, 639, 1857, 2873, 3627, 6081, 18207, 29451, 80909, 73557}},
+{18187, 18, 80233, {1, 1, 1, 3, 29, 51, 15, 81, 85, 487, 307, 2481, 2769, 14901, 9407, 58321, 52813, 230393}},
+{18188, 18, 80258, {1, 3, 3, 11, 31, 7, 107, 43, 205, 811, 1121, 2757, 2447, 6843, 21347, 9143, 41003, 80507}},
+{18189, 18, 80281, {1, 1, 1, 1, 29, 19, 13, 203, 47, 689, 2003, 1477, 7857, 5031, 21781, 5745, 3649, 160389}},
+{18190, 18, 80318, {1, 3, 3, 7, 21, 21, 65, 3, 351, 157, 167, 3425, 2395, 9165, 26143, 57221, 127171, 54461}},
+{18191, 18, 80326, {1, 3, 1, 15, 13, 13, 65, 53, 305, 719, 181, 709, 5485, 13385, 30287, 52669, 82647, 83851}},
+{18192, 18, 80330, {1, 1, 3, 11, 11, 23, 31, 109, 205, 123, 509, 3831, 7771, 7341, 31613, 28035, 38061, 49375}},
+{18193, 18, 80337, {1, 3, 3, 3, 15, 33, 47, 159, 321, 589, 393, 3253, 3743, 6161, 445, 33129, 8181, 27793}},
+{18194, 18, 80344, {1, 1, 1, 13, 9, 57, 111, 253, 203, 539, 673, 855, 1937, 2699, 25795, 6889, 13531, 63561}},
+{18195, 18, 80365, {1, 1, 1, 13, 31, 45, 13, 101, 113, 903, 1699, 2423, 7967, 7957, 20303, 64395, 124447, 33947}},
+{18196, 18, 80383, {1, 3, 5, 11, 17, 39, 59, 181, 421, 535, 1445, 3927, 5433, 12885, 12497, 47231, 39819, 46371}},
+{18197, 18, 80389, {1, 3, 5, 7, 27, 3, 75, 49, 461, 781, 433, 1767, 6903, 11907, 2063, 55199, 82823, 229405}},
+{18198, 18, 80413, {1, 3, 3, 15, 17, 61, 17, 23, 247, 683, 33, 4027, 341, 8069, 2529, 9757, 95653, 12927}},
+{18199, 18, 80441, {1, 3, 3, 11, 17, 7, 29, 205, 353, 917, 219, 3509, 7803, 5939, 25111, 45357, 9259, 1549}},
+{18200, 18, 80449, {1, 3, 3, 15, 21, 7, 23, 25, 459, 291, 31, 2091, 1177, 9311, 12231, 16617, 33575, 252643}},
+{18201, 18, 80461, {1, 3, 5, 5, 3, 51, 113, 123, 453, 503, 1575, 2785, 5011, 1789, 819, 30857, 12955, 172421}},
+{18202, 18, 80467, {1, 1, 5, 3, 15, 15, 125, 65, 113, 281, 53, 3417, 5279, 6351, 25931, 54835, 124077, 204241}},
+{18203, 18, 80476, {1, 1, 3, 9, 29, 31, 19, 179, 275, 933, 711, 3351, 6221, 1711, 9375, 11645, 118911, 249395}},
+{18204, 18, 80507, {1, 3, 7, 13, 23, 59, 43, 61, 85, 267, 691, 3949, 2135, 3203, 21455, 61895, 71157, 136739}},
+{18205, 18, 80516, {1, 1, 7, 5, 19, 27, 69, 141, 9, 633, 95, 3789, 7823, 12635, 27661, 30285, 129469, 67163}},
+{18206, 18, 80519, {1, 3, 3, 9, 11, 25, 103, 47, 425, 809, 1279, 411, 219, 6703, 24145, 17303, 56835, 84879}},
+{18207, 18, 80568, {1, 1, 5, 13, 29, 41, 47, 133, 197, 615, 169, 2157, 1795, 4945, 31693, 57763, 39369, 83353}},
+{18208, 18, 80571, {1, 3, 1, 3, 27, 23, 23, 213, 387, 239, 977, 221, 383, 11005, 7221, 8795, 100963, 163777}},
+{18209, 18, 80579, {1, 1, 1, 1, 31, 29, 87, 93, 239, 399, 801, 3143, 6973, 16331, 16865, 1823, 1127, 41983}},
+{18210, 18, 80586, {1, 1, 3, 13, 7, 39, 25, 251, 277, 417, 119, 3033, 6785, 9783, 1641, 60169, 25047, 182263}},
+{18211, 18, 80599, {1, 1, 5, 5, 7, 35, 17, 47, 295, 861, 1671, 1971, 4583, 3925, 31013, 50039, 125191, 143019}},
+{18212, 18, 80610, {1, 1, 5, 1, 3, 57, 11, 23, 273, 209, 617, 1499, 665, 1193, 7539, 1625, 48065, 82843}},
+{18213, 18, 80629, {1, 1, 3, 15, 15, 17, 39, 145, 193, 503, 1305, 2071, 93, 11529, 14267, 14779, 49327, 51347}},
+{18214, 18, 80642, {1, 3, 5, 3, 7, 39, 63, 171, 263, 493, 383, 3209, 4277, 6259, 1345, 48013, 110571, 127865}},
+{18215, 18, 80690, {1, 3, 1, 7, 15, 29, 93, 75, 37, 235, 1095, 153, 745, 9785, 28831, 58899, 67091, 34743}},
+{18216, 18, 80713, {1, 3, 7, 9, 27, 23, 67, 85, 491, 447, 1899, 709, 555, 13979, 12529, 38383, 16091, 117301}},
+{18217, 18, 80716, {1, 1, 5, 3, 9, 55, 109, 173, 29, 19, 1265, 2391, 7761, 1953, 5643, 24079, 14187, 127017}},
+{18218, 18, 80737, {1, 3, 7, 13, 21, 57, 105, 145, 73, 421, 403, 5, 3523, 7005, 1109, 63357, 111671, 191857}},
+{18219, 18, 80743, {1, 1, 7, 13, 5, 27, 21, 5, 199, 515, 917, 365, 2775, 12453, 26989, 60593, 98977, 161759}},
+{18220, 18, 80750, {1, 3, 1, 13, 15, 37, 71, 65, 27, 533, 1311, 2981, 1945, 7183, 5337, 20659, 67355, 185633}},
+{18221, 18, 80786, {1, 1, 5, 7, 21, 39, 21, 195, 443, 979, 1033, 1823, 3045, 3023, 31783, 61803, 1023, 119291}},
+{18222, 18, 80811, {1, 1, 3, 11, 5, 15, 107, 155, 465, 249, 1845, 357, 2769, 3313, 12335, 16615, 20809, 103469}},
+{18223, 18, 80834, {1, 1, 3, 9, 13, 21, 11, 227, 173, 949, 1255, 3257, 601, 10865, 12779, 9173, 87255, 12867}},
+{18224, 18, 80839, {1, 3, 3, 15, 3, 41, 97, 141, 385, 23, 1253, 2905, 1523, 7647, 7069, 61143, 101245, 59747}},
+{18225, 18, 80840, {1, 3, 1, 3, 7, 35, 117, 93, 357, 741, 1673, 3295, 6809, 547, 22949, 42151, 91241, 16189}},
+{18226, 18, 80846, {1, 3, 5, 9, 25, 31, 27, 221, 55, 595, 1513, 3963, 3143, 1189, 19843, 6361, 19575, 231765}},
+{18227, 18, 80848, {1, 1, 5, 1, 3, 35, 91, 217, 385, 717, 57, 1471, 3529, 859, 15259, 4411, 54491, 79841}},
+{18228, 18, 80876, {1, 1, 5, 9, 29, 47, 111, 89, 469, 975, 513, 1339, 1747, 8839, 30375, 46217, 128191, 95831}},
+{18229, 18, 80911, {1, 1, 5, 13, 9, 45, 3, 221, 223, 461, 1353, 3953, 5505, 3139, 3407, 12953, 74487, 209401}},
+{18230, 18, 80947, {1, 1, 7, 7, 7, 43, 33, 143, 427, 183, 573, 2881, 7355, 10693, 12841, 14267, 61847, 47689}},
+{18231, 18, 81001, {1, 1, 3, 5, 23, 45, 53, 173, 347, 715, 173, 3385, 429, 8143, 2831, 57883, 77245, 37613}},
+{18232, 18, 81031, {1, 1, 1, 13, 21, 47, 33, 157, 171, 47, 1981, 2003, 7401, 7687, 10553, 38083, 111901, 30251}},
+{18233, 18, 81045, {1, 1, 5, 9, 23, 35, 121, 251, 7, 835, 1561, 1605, 7023, 15645, 14313, 6361, 107973, 211667}},
+{18234, 18, 81056, {1, 3, 1, 13, 25, 39, 81, 31, 145, 483, 1587, 3457, 5293, 927, 3529, 22457, 69689, 190371}},
+{18235, 18, 81073, {1, 1, 1, 3, 25, 61, 87, 111, 441, 829, 313, 2271, 205, 10187, 3003, 47237, 99899, 200553}},
+{18236, 18, 81083, {1, 1, 7, 13, 31, 51, 9, 243, 219, 139, 1703, 2001, 959, 11265, 27897, 9081, 4473, 107737}},
+{18237, 18, 81145, {1, 3, 5, 1, 25, 37, 61, 131, 487, 35, 1293, 833, 3847, 11315, 11811, 2763, 2199, 81127}},
+{18238, 18, 81168, {1, 3, 7, 7, 31, 33, 87, 111, 429, 809, 173, 1093, 7719, 14307, 5735, 61019, 21223, 26361}},
+{18239, 18, 81177, {1, 1, 3, 11, 17, 33, 31, 17, 49, 885, 1279, 2243, 3693, 61, 30909, 35807, 14027, 159225}},
+{18240, 18, 81207, {1, 3, 7, 11, 9, 35, 61, 75, 171, 117, 1285, 935, 7271, 3509, 14119, 31065, 58181, 136623}},
+{18241, 18, 81208, {1, 1, 3, 15, 3, 43, 93, 221, 239, 783, 37, 4007, 3637, 10461, 18425, 59629, 93781, 252689}},
+{18242, 18, 81226, {1, 3, 5, 7, 5, 61, 19, 107, 123, 417, 1655, 2307, 8177, 13617, 17195, 31597, 66241, 107199}},
+{18243, 18, 81245, {1, 3, 7, 7, 5, 5, 25, 69, 383, 217, 993, 2719, 3425, 8395, 1125, 10763, 80111, 70421}},
+{18244, 18, 81269, {1, 1, 3, 9, 29, 45, 123, 45, 89, 1015, 1703, 4049, 4969, 3801, 23657, 41031, 66415, 34063}},
+{18245, 18, 81285, {1, 1, 3, 3, 7, 53, 125, 63, 67, 335, 1937, 1793, 4641, 7115, 10951, 45503, 54723, 177433}},
+{18246, 18, 81289, {1, 3, 5, 1, 21, 55, 83, 199, 509, 331, 695, 2133, 1881, 14369, 21687, 2343, 85895, 99255}},
+{18247, 18, 81292, {1, 1, 5, 9, 11, 5, 111, 97, 433, 851, 1537, 411, 6629, 5185, 30749, 50017, 46177, 213347}},
+{18248, 18, 81298, {1, 3, 3, 1, 7, 21, 95, 229, 311, 605, 1277, 2435, 5053, 3051, 15447, 35479, 2835, 204149}},
+{18249, 18, 81310, {1, 3, 5, 9, 31, 27, 79, 201, 329, 735, 1933, 27, 6201, 9375, 24801, 34045, 16227, 61013}},
+{18250, 18, 81346, {1, 1, 5, 5, 31, 7, 73, 197, 455, 835, 1845, 2733, 3371, 513, 10495, 43659, 4621, 68969}},
+{18251, 18, 81348, {1, 1, 1, 15, 21, 55, 15, 83, 419, 471, 1427, 919, 7125, 7635, 25579, 19493, 37381, 191563}},
+{18252, 18, 81355, {1, 1, 7, 3, 15, 35, 25, 73, 295, 507, 719, 3307, 4253, 945, 21005, 24903, 80287, 48885}},
+{18253, 18, 81388, {1, 3, 7, 15, 27, 13, 71, 79, 189, 491, 1185, 3007, 4285, 13005, 18973, 33759, 15327, 45595}},
+{18254, 18, 81396, {1, 3, 3, 9, 9, 33, 115, 103, 31, 949, 1817, 2865, 1215, 9611, 16019, 7925, 72945, 208301}},
+{18255, 18, 81415, {1, 1, 1, 5, 19, 35, 89, 181, 409, 641, 1277, 2201, 2825, 5707, 13463, 34741, 39303, 217803}},
+{18256, 18, 81460, {1, 1, 3, 11, 13, 31, 65, 191, 11, 179, 509, 2513, 3861, 13323, 11817, 24901, 53815, 44343}},
+{18257, 18, 81482, {1, 3, 1, 5, 5, 57, 97, 25, 83, 177, 1963, 2367, 6703, 13361, 8749, 45533, 87883, 2977}},
+{18258, 18, 81518, {1, 3, 5, 3, 15, 41, 113, 145, 39, 509, 81, 1387, 2881, 1441, 75, 28409, 61417, 79393}},
+{18259, 18, 81523, {1, 3, 3, 3, 17, 1, 41, 19, 173, 133, 2033, 3637, 7415, 1841, 19497, 42643, 122885, 195301}},
+{18260, 18, 81529, {1, 3, 3, 9, 15, 37, 11, 87, 291, 881, 1471, 2469, 6877, 6813, 8273, 1455, 30957, 181887}},
+{18261, 18, 81545, {1, 3, 5, 9, 25, 41, 7, 71, 451, 831, 495, 3991, 4173, 4307, 31249, 7253, 57141, 35495}},
+{18262, 18, 81570, {1, 1, 7, 9, 15, 39, 29, 193, 327, 837, 991, 3503, 1175, 14965, 18151, 22479, 51127, 159019}},
+{18263, 18, 81576, {1, 3, 1, 9, 23, 41, 89, 211, 179, 507, 1005, 613, 8083, 15655, 1927, 23401, 51025, 21589}},
+{18264, 18, 81604, {1, 1, 5, 15, 5, 63, 105, 229, 239, 399, 591, 2233, 391, 2871, 29829, 49961, 62045, 190437}},
+{18265, 18, 81613, {1, 3, 5, 9, 7, 23, 85, 219, 163, 37, 1881, 589, 4239, 12845, 19993, 57267, 29519, 207597}},
+{18266, 18, 81631, {1, 3, 7, 15, 19, 19, 115, 141, 41, 405, 657, 2517, 4231, 10247, 21383, 11479, 52955, 121545}},
+{18267, 18, 81656, {1, 3, 1, 7, 23, 33, 65, 229, 287, 739, 1265, 1105, 487, 3801, 5211, 44731, 5359, 103685}},
+{18268, 18, 81679, {1, 3, 1, 13, 23, 29, 101, 153, 395, 335, 899, 303, 2073, 15767, 1303, 15539, 12889, 35517}},
+{18269, 18, 81684, {1, 1, 5, 11, 5, 63, 41, 53, 99, 339, 563, 2921, 4959, 13941, 13655, 10115, 56867, 42919}},
+{18270, 18, 81698, {1, 3, 5, 5, 5, 35, 127, 225, 497, 27, 139, 3269, 3929, 3369, 22697, 19421, 2921, 171927}},
+{18271, 18, 81736, {1, 1, 1, 15, 15, 21, 35, 251, 67, 447, 1045, 1173, 2951, 6589, 27261, 36597, 98721, 7205}},
+{18272, 18, 81747, {1, 3, 3, 9, 11, 63, 83, 19, 163, 381, 87, 1211, 3007, 4971, 27105, 2341, 21389, 32995}},
+{18273, 18, 81765, {1, 1, 3, 3, 21, 19, 63, 65, 505, 987, 1821, 2419, 3195, 2573, 1481, 35279, 45135, 597}},
+{18274, 18, 81775, {1, 3, 1, 15, 29, 5, 77, 65, 121, 223, 2009, 593, 7929, 10353, 22301, 25137, 40289, 95847}},
+{18275, 18, 81805, {1, 1, 3, 1, 17, 49, 9, 167, 69, 729, 1189, 1191, 1, 12603, 8281, 45193, 1427, 15887}},
+{18276, 18, 81842, {1, 1, 3, 7, 17, 5, 11, 217, 505, 317, 505, 1201, 8025, 13255, 12591, 16207, 32387, 242425}},
+{18277, 18, 81859, {1, 3, 7, 9, 25, 9, 97, 23, 91, 765, 653, 2689, 2787, 11719, 8455, 24665, 26907, 78525}},
+{18278, 18, 81865, {1, 3, 3, 15, 27, 19, 79, 157, 117, 715, 1921, 2453, 499, 13593, 14173, 1993, 110087, 151427}},
+{18279, 18, 81866, {1, 3, 1, 13, 5, 43, 59, 21, 451, 863, 533, 1723, 2059, 1611, 10403, 36479, 36999, 109553}},
+{18280, 18, 81892, {1, 3, 7, 7, 29, 63, 51, 5, 475, 549, 123, 1949, 5279, 8581, 20053, 52287, 125223, 152299}},
+{18281, 18, 81902, {1, 3, 1, 1, 7, 19, 1, 215, 273, 157, 1557, 425, 7549, 12337, 1735, 30917, 116487, 177335}},
+{18282, 18, 81933, {1, 1, 1, 1, 7, 47, 61, 191, 73, 551, 1435, 2283, 3191, 8545, 11875, 41389, 17607, 26869}},
+{18283, 18, 81934, {1, 1, 7, 9, 13, 61, 109, 121, 365, 223, 1729, 3311, 7249, 10765, 12419, 4235, 64127, 132257}},
+{18284, 18, 81942, {1, 1, 3, 13, 17, 25, 65, 49, 417, 311, 141, 1127, 53, 945, 28277, 33347, 96399, 166049}},
+{18285, 18, 81969, {1, 3, 7, 9, 5, 21, 93, 203, 467, 805, 115, 1757, 4535, 8687, 10423, 8065, 2955, 20403}},
+{18286, 18, 81981, {1, 3, 3, 15, 7, 63, 103, 137, 227, 111, 735, 2139, 4293, 5347, 4131, 63405, 42599, 173299}},
+{18287, 18, 81999, {1, 3, 7, 7, 17, 53, 127, 251, 57, 625, 843, 3045, 1319, 10085, 18591, 36115, 104193, 183891}},
+{18288, 18, 82004, {1, 3, 7, 1, 31, 57, 107, 253, 207, 739, 1703, 1377, 3807, 10289, 22969, 13087, 2805, 261279}},
+{18289, 18, 82008, {1, 1, 5, 5, 5, 59, 59, 63, 77, 663, 1109, 2159, 3725, 12355, 4805, 22433, 81851, 9419}},
+{18290, 18, 82032, {1, 1, 7, 15, 1, 1, 101, 101, 295, 311, 447, 3931, 933, 15713, 8919, 7185, 38577, 254203}},
+{18291, 18, 82035, {1, 1, 5, 15, 7, 35, 35, 141, 283, 665, 1685, 3875, 495, 1655, 8269, 23493, 1523, 248783}},
+{18292, 18, 82060, {1, 1, 5, 9, 27, 35, 25, 57, 285, 469, 1491, 1479, 3705, 11357, 5319, 11575, 116207, 215961}},
+{18293, 18, 82063, {1, 3, 5, 11, 7, 41, 67, 161, 73, 777, 247, 823, 6677, 1631, 3431, 2821, 25291, 17633}},
+{18294, 18, 82071, {1, 1, 3, 9, 19, 17, 45, 181, 139, 85, 857, 1231, 7167, 2951, 26847, 39113, 51705, 104617}},
+{18295, 18, 82081, {1, 3, 5, 1, 5, 55, 101, 209, 1, 47, 1059, 2175, 1549, 8007, 11267, 21863, 125567, 102775}},
+{18296, 18, 82082, {1, 3, 3, 15, 15, 21, 79, 85, 427, 963, 1335, 2129, 6831, 6613, 13319, 15781, 3781, 222547}},
+{18297, 18, 82105, {1, 3, 3, 13, 19, 63, 25, 123, 1, 215, 139, 1345, 5035, 3107, 14381, 6239, 18481, 202581}},
+{18298, 18, 82106, {1, 1, 5, 1, 11, 11, 11, 53, 109, 533, 1113, 177, 609, 15391, 22735, 62229, 103591, 89143}},
+{18299, 18, 82120, {1, 1, 5, 15, 3, 21, 115, 223, 167, 441, 277, 2971, 933, 2841, 26893, 48513, 74553, 250413}},
+{18300, 18, 82125, {1, 1, 1, 7, 19, 17, 43, 181, 483, 897, 819, 1657, 5539, 8847, 23483, 57605, 104703, 242559}},
+{18301, 18, 82156, {1, 3, 5, 11, 3, 63, 3, 129, 45, 981, 45, 845, 1481, 14735, 30451, 16937, 13789, 27107}},
+{18302, 18, 82176, {1, 3, 3, 15, 25, 11, 33, 49, 155, 947, 521, 3417, 3299, 1123, 9517, 32127, 117795, 223167}},
+{18303, 18, 82203, {1, 3, 5, 15, 3, 35, 27, 37, 287, 541, 727, 2779, 7033, 5189, 21579, 36895, 109645, 123353}},
+{18304, 18, 82210, {1, 3, 7, 9, 15, 53, 123, 125, 405, 841, 119, 63, 853, 8693, 1537, 25509, 49345, 54301}},
+{18305, 18, 82241, {1, 3, 7, 9, 11, 63, 65, 145, 283, 529, 1553, 883, 3319, 8601, 29379, 26991, 127343, 98701}},
+{18306, 18, 82287, {1, 1, 1, 7, 23, 59, 11, 89, 407, 869, 445, 659, 3029, 5465, 5063, 36775, 69089, 205367}},
+{18307, 18, 82323, {1, 3, 7, 5, 19, 35, 99, 49, 257, 287, 1113, 2825, 2797, 7283, 31757, 47015, 106987, 82589}},
+{18308, 18, 82330, {1, 3, 7, 11, 15, 37, 41, 101, 493, 725, 1091, 503, 2611, 13025, 11071, 39311, 5193, 92127}},
+{18309, 18, 82366, {1, 1, 3, 7, 9, 59, 69, 113, 381, 341, 1495, 3169, 5099, 69, 7911, 9721, 84609, 254171}},
+{18310, 18, 82378, {1, 3, 5, 7, 21, 19, 75, 71, 7, 617, 1185, 2787, 4147, 16045, 18859, 52347, 66551, 161563}},
+{18311, 18, 82395, {1, 3, 5, 3, 27, 39, 17, 205, 425, 3, 1443, 1947, 7645, 10125, 24577, 45373, 38015, 30407}},
+{18312, 18, 82398, {1, 3, 3, 11, 1, 57, 105, 251, 65, 389, 1993, 3933, 3093, 1425, 9483, 5953, 13147, 234121}},
+{18313, 18, 82401, {1, 3, 3, 3, 1, 27, 105, 45, 435, 393, 609, 291, 545, 4905, 22621, 62115, 78955, 84355}},
+{18314, 18, 82404, {1, 3, 7, 9, 1, 15, 91, 183, 301, 223, 1183, 1877, 2141, 5549, 371, 44147, 6771, 136777}},
+{18315, 18, 82419, {1, 1, 5, 15, 5, 49, 127, 161, 121, 979, 1247, 3681, 3805, 3363, 11643, 25735, 21193, 111657}},
+{18316, 18, 82421, {1, 3, 5, 15, 15, 33, 47, 91, 137, 323, 1577, 3723, 3609, 11533, 4415, 26467, 120947, 200919}},
+{18317, 18, 82428, {1, 3, 3, 3, 3, 33, 121, 161, 453, 205, 1815, 65, 5893, 4669, 14377, 10905, 9559, 56359}},
+{18318, 18, 82442, {1, 1, 1, 7, 1, 55, 21, 143, 411, 65, 1009, 2989, 133, 7059, 30981, 15417, 2651, 110345}},
+{18319, 18, 82452, {1, 1, 3, 7, 19, 25, 91, 241, 193, 903, 661, 665, 7681, 14111, 29197, 51299, 109519, 155827}},
+{18320, 18, 82455, {1, 1, 1, 15, 25, 3, 79, 57, 417, 73, 705, 7, 4415, 7699, 28185, 53005, 88547, 7281}},
+{18321, 18, 82466, {1, 1, 7, 13, 27, 21, 35, 197, 65, 171, 1773, 393, 3759, 8335, 5987, 20611, 91373, 80715}},
+{18322, 18, 82510, {1, 3, 7, 3, 17, 51, 85, 229, 131, 733, 281, 3157, 1283, 10751, 20203, 49955, 23861, 128517}},
+{18323, 18, 82524, {1, 1, 5, 15, 3, 27, 35, 87, 391, 509, 1627, 769, 701, 4933, 24597, 9695, 111441, 198493}},
+{18324, 18, 82545, {1, 1, 1, 15, 3, 31, 73, 235, 341, 263, 883, 2369, 4887, 4659, 9493, 6763, 130625, 15031}},
+{18325, 18, 82555, {1, 3, 1, 15, 1, 11, 63, 79, 389, 355, 619, 1361, 313, 1199, 555, 42213, 81089, 170863}},
+{18326, 18, 82581, {1, 3, 1, 15, 21, 27, 1, 179, 19, 241, 1655, 1803, 5413, 5353, 65, 31211, 3501, 27205}},
+{18327, 18, 82588, {1, 3, 3, 9, 9, 19, 63, 191, 217, 271, 1453, 2777, 2915, 13291, 31391, 37489, 86435, 22857}},
+{18328, 18, 82591, {1, 3, 5, 9, 13, 41, 85, 11, 333, 479, 363, 2591, 697, 8587, 3647, 5741, 21627, 244573}},
+{18329, 18, 82636, {1, 1, 3, 1, 5, 61, 83, 229, 193, 977, 677, 2585, 3273, 12035, 2621, 12943, 49293, 37985}},
+{18330, 18, 82658, {1, 1, 5, 7, 27, 9, 69, 189, 489, 747, 519, 719, 1493, 13337, 14933, 44359, 11471, 57245}},
+{18331, 18, 82675, {1, 3, 5, 1, 5, 17, 75, 89, 417, 367, 57, 1641, 1573, 1819, 31237, 5213, 78821, 149853}},
+{18332, 18, 82678, {1, 1, 7, 3, 7, 17, 121, 91, 211, 101, 1145, 3753, 2997, 67, 10755, 11261, 122489, 61679}},
+{18333, 18, 82716, {1, 3, 7, 7, 15, 17, 73, 133, 429, 285, 201, 1917, 5677, 1793, 21653, 49729, 68965, 5347}},
+{18334, 18, 82725, {1, 3, 3, 13, 23, 17, 49, 249, 71, 169, 619, 843, 2163, 585, 23309, 39509, 68087, 232233}},
+{18335, 18, 82743, {1, 1, 7, 15, 23, 15, 19, 227, 89, 719, 1247, 2521, 1509, 7553, 12225, 12865, 100107, 261847}},
+{18336, 18, 82744, {1, 1, 5, 3, 23, 17, 117, 5, 401, 57, 1945, 1081, 1269, 5921, 31815, 42341, 112099, 130047}},
+{18337, 18, 82762, {1, 1, 1, 1, 9, 5, 87, 203, 211, 1009, 403, 1617, 3969, 2541, 7261, 6989, 16579, 206159}},
+{18338, 18, 82770, {1, 3, 7, 9, 5, 13, 93, 191, 79, 631, 1019, 3639, 7137, 13859, 19603, 63263, 82947, 181023}},
+{18339, 18, 82809, {1, 1, 5, 11, 25, 17, 85, 51, 61, 311, 517, 2001, 6325, 6831, 10835, 20101, 115241, 15815}},
+{18340, 18, 82846, {1, 3, 7, 13, 29, 19, 33, 115, 473, 477, 471, 773, 4097, 11697, 30781, 20843, 27089, 181927}},
+{18341, 18, 82855, {1, 3, 5, 5, 21, 27, 3, 239, 45, 335, 505, 149, 3005, 3511, 18037, 31291, 6145, 2913}},
+{18342, 18, 82882, {1, 1, 3, 1, 25, 49, 21, 225, 27, 395, 415, 1813, 5727, 7211, 9887, 63533, 99185, 119269}},
+{18343, 18, 82899, {1, 3, 3, 5, 15, 53, 127, 195, 81, 895, 587, 561, 5951, 9901, 18117, 37855, 19393, 259031}},
+{18344, 18, 82905, {1, 1, 7, 13, 9, 49, 109, 127, 53, 735, 391, 1523, 3759, 10363, 11299, 3203, 89121, 122643}},
+{18345, 18, 82950, {1, 1, 5, 3, 13, 3, 21, 247, 259, 557, 977, 1465, 6889, 3879, 4627, 1439, 122809, 248941}},
+{18346, 18, 82953, {1, 3, 7, 15, 7, 19, 113, 251, 245, 63, 267, 1873, 6601, 16253, 24643, 7433, 130051, 233047}},
+{18347, 18, 82967, {1, 1, 3, 9, 29, 39, 47, 31, 493, 817, 1697, 2139, 1059, 11365, 31653, 56477, 119191, 45509}},
+{18348, 18, 82971, {1, 1, 1, 15, 9, 29, 99, 61, 109, 341, 1009, 1551, 897, 13075, 10603, 25153, 65911, 228213}},
+{18349, 18, 82987, {1, 3, 7, 7, 29, 47, 57, 85, 263, 767, 1633, 2473, 199, 49, 22287, 33345, 118877, 248435}},
+{18350, 18, 83007, {1, 3, 1, 9, 5, 45, 5, 179, 9, 129, 1231, 4075, 7497, 2159, 18101, 31039, 95213, 171913}},
+{18351, 18, 83009, {1, 1, 1, 13, 23, 1, 89, 63, 21, 983, 481, 773, 5957, 4823, 4483, 50405, 42979, 243567}},
+{18352, 18, 83012, {1, 1, 5, 13, 15, 21, 65, 133, 347, 511, 1887, 743, 7825, 1681, 4857, 49247, 21277, 212995}},
+{18353, 18, 83030, {1, 3, 7, 9, 7, 51, 3, 233, 287, 727, 815, 3609, 397, 5721, 16473, 7549, 100455, 136233}},
+{18354, 18, 83045, {1, 3, 1, 1, 31, 51, 59, 37, 79, 623, 1219, 2655, 4619, 11967, 11377, 28985, 16069, 188773}},
+{18355, 18, 83050, {1, 3, 3, 13, 13, 59, 93, 159, 197, 339, 1633, 1601, 255, 1631, 4989, 12019, 23921, 261273}},
+{18356, 18, 83052, {1, 1, 3, 13, 27, 25, 55, 43, 147, 981, 65, 725, 5753, 115, 26125, 25501, 89099, 233419}},
+{18357, 18, 83070, {1, 3, 7, 5, 25, 3, 95, 135, 191, 417, 929, 3855, 5829, 3827, 13979, 65367, 63683, 85911}},
+{18358, 18, 83076, {1, 3, 5, 1, 7, 63, 45, 187, 355, 735, 1325, 1461, 3869, 2127, 18231, 45891, 24027, 202997}},
+{18359, 18, 83086, {1, 3, 7, 13, 19, 47, 89, 229, 253, 659, 355, 3323, 4081, 8243, 32553, 46579, 46431, 53291}},
+{18360, 18, 83128, {1, 1, 5, 11, 3, 61, 33, 65, 239, 779, 665, 1337, 6427, 12787, 1495, 27105, 71455, 89715}},
+{18361, 18, 83141, {1, 3, 1, 11, 31, 33, 115, 69, 511, 187, 99, 1055, 1065, 9531, 29897, 23897, 80581, 166957}},
+{18362, 18, 83153, {1, 1, 7, 13, 19, 1, 13, 241, 89, 761, 425, 3865, 961, 14999, 24175, 19103, 39095, 38899}},
+{18363, 18, 83156, {1, 3, 7, 7, 11, 17, 25, 217, 113, 615, 1455, 1409, 5679, 2321, 28687, 8089, 74031, 230559}},
+{18364, 18, 83194, {1, 3, 7, 1, 25, 15, 77, 111, 405, 523, 961, 647, 3857, 14355, 27063, 48829, 87913, 254965}},
+{18365, 18, 83225, {1, 1, 3, 3, 5, 13, 67, 155, 393, 943, 1875, 1209, 3765, 8627, 15123, 43405, 78473, 146127}},
+{18366, 18, 83261, {1, 1, 3, 7, 29, 43, 23, 33, 35, 883, 1859, 1559, 4163, 13277, 16971, 15289, 60305, 56743}},
+{18367, 18, 83264, {1, 1, 1, 5, 19, 55, 37, 53, 123, 35, 1477, 1035, 4683, 259, 20079, 37041, 48081, 198685}},
+{18368, 18, 83322, {1, 1, 3, 3, 1, 19, 27, 129, 427, 685, 959, 2501, 2761, 9495, 23649, 18789, 54521, 219547}},
+{18369, 18, 83382, {1, 1, 7, 1, 31, 11, 65, 171, 229, 11, 1825, 1641, 2731, 11085, 2567, 30831, 20365, 242731}},
+{18370, 18, 83391, {1, 1, 1, 13, 13, 5, 21, 175, 265, 271, 133, 407, 3415, 5943, 15385, 12817, 106159, 41859}},
+{18371, 18, 83399, {1, 3, 7, 1, 11, 45, 105, 229, 395, 877, 1495, 2113, 1733, 10117, 1125, 9989, 109637, 124517}},
+{18372, 18, 83406, {1, 1, 7, 3, 27, 43, 57, 77, 63, 907, 1137, 3333, 189, 15285, 13895, 23773, 73523, 47811}},
+{18373, 18, 83427, {1, 3, 3, 11, 17, 19, 81, 197, 73, 897, 515, 3801, 5105, 6987, 10125, 7239, 32339, 124411}},
+{18374, 18, 83439, {1, 3, 1, 9, 11, 15, 99, 109, 307, 133, 249, 1463, 5479, 8565, 19489, 13773, 11443, 149799}},
+{18375, 18, 83444, {1, 3, 7, 7, 19, 53, 61, 75, 83, 545, 1449, 683, 5845, 8325, 18111, 35941, 51843, 97907}},
+{18376, 18, 83453, {1, 1, 1, 3, 31, 23, 37, 187, 207, 51, 439, 3095, 2217, 6393, 9117, 2779, 47331, 118275}},
+{18377, 18, 83457, {1, 1, 3, 9, 23, 17, 41, 37, 59, 281, 319, 1333, 6207, 2265, 4445, 50831, 115893, 120491}},
+{18378, 18, 83475, {1, 3, 1, 13, 27, 23, 25, 23, 187, 51, 1257, 379, 921, 3801, 24537, 59547, 34191, 184625}},
+{18379, 18, 83484, {1, 1, 5, 3, 23, 21, 23, 159, 163, 537, 1589, 2797, 8007, 6767, 31331, 20741, 119969, 174135}},
+{18380, 18, 83488, {1, 3, 1, 1, 13, 35, 73, 147, 491, 317, 69, 1069, 5413, 13973, 19741, 44717, 63263, 77145}},
+{18381, 18, 83493, {1, 3, 1, 15, 31, 41, 23, 79, 55, 863, 129, 2229, 3395, 1621, 6273, 44521, 100047, 42337}},
+{18382, 18, 83512, {1, 3, 7, 3, 7, 5, 79, 1, 191, 227, 1039, 2909, 1085, 3173, 29311, 13861, 124785, 212453}},
+{18383, 18, 83525, {1, 3, 1, 5, 13, 9, 99, 213, 61, 201, 889, 1171, 3981, 2091, 31679, 26643, 5611, 154339}},
+{18384, 18, 83535, {1, 3, 3, 7, 27, 49, 53, 77, 285, 441, 1669, 2157, 223, 1899, 2725, 36547, 39273, 206653}},
+{18385, 18, 83560, {1, 3, 3, 9, 29, 5, 91, 1, 13, 409, 1275, 891, 6557, 5157, 6481, 57381, 87683, 117277}},
+{18386, 18, 83617, {1, 3, 3, 1, 11, 7, 13, 69, 9, 1015, 907, 2685, 6665, 16307, 24567, 13191, 9567, 55073}},
+{18387, 18, 83664, {1, 3, 1, 5, 19, 15, 65, 13, 503, 427, 1947, 1869, 5857, 823, 20533, 25337, 83551, 128505}},
+{18388, 18, 83676, {1, 1, 5, 11, 25, 53, 83, 175, 445, 5, 841, 2773, 4381, 2829, 1927, 63689, 63643, 246629}},
+{18389, 18, 83757, {1, 3, 1, 11, 27, 63, 43, 95, 453, 235, 673, 117, 6617, 7589, 5767, 16465, 36961, 39395}},
+{18390, 18, 83770, {1, 1, 3, 13, 3, 27, 119, 87, 209, 167, 721, 1499, 1955, 9151, 11649, 29009, 25249, 26125}},
+{18391, 18, 83775, {1, 1, 5, 1, 9, 59, 47, 57, 81, 243, 485, 559, 7311, 15119, 9827, 47219, 5941, 16909}},
+{18392, 18, 83835, {1, 3, 7, 11, 29, 13, 97, 63, 289, 653, 1811, 835, 801, 13103, 9333, 7785, 111587, 10021}},
+{18393, 18, 83838, {1, 3, 3, 1, 27, 61, 73, 165, 279, 239, 865, 517, 7763, 1917, 9839, 20725, 50721, 171351}},
+{18394, 18, 83848, {1, 3, 7, 1, 27, 29, 43, 137, 353, 927, 889, 2511, 709, 3309, 967, 18119, 48099, 98139}},
+{18395, 18, 83856, {1, 3, 1, 1, 17, 5, 79, 23, 367, 231, 605, 3809, 7557, 14283, 18417, 15775, 107421, 9587}},
+{18396, 18, 83878, {1, 1, 1, 7, 25, 9, 93, 41, 165, 509, 661, 2165, 3595, 2555, 11399, 2403, 76179, 176003}},
+{18397, 18, 83884, {1, 3, 3, 7, 27, 19, 55, 213, 83, 601, 377, 2381, 6831, 5609, 31321, 26897, 105321, 144705}},
+{18398, 18, 83896, {1, 3, 7, 7, 21, 11, 45, 55, 379, 133, 653, 3593, 7481, 15789, 12723, 9697, 20073, 58211}},
+{18399, 18, 83902, {1, 3, 5, 1, 1, 57, 89, 159, 461, 719, 1251, 3899, 1063, 10753, 6509, 28391, 129377, 195279}},
+{18400, 18, 83922, {1, 3, 7, 7, 5, 39, 59, 81, 27, 169, 1541, 2213, 3631, 11601, 13153, 43221, 14587, 29719}},
+{18401, 18, 83977, {1, 1, 1, 1, 3, 29, 103, 125, 35, 455, 255, 3855, 567, 12013, 13285, 44753, 117415, 226285}},
+{18402, 18, 83985, {1, 1, 5, 1, 21, 41, 59, 69, 83, 813, 1041, 2559, 1947, 7343, 5291, 39281, 56141, 54487}},
+{18403, 18, 83988, {1, 1, 7, 15, 25, 17, 83, 115, 321, 659, 1625, 3253, 281, 6673, 26301, 45647, 92151, 150707}},
+{18404, 18, 84034, {1, 1, 5, 15, 9, 19, 83, 167, 325, 869, 501, 483, 2155, 14697, 12755, 54687, 100637, 6791}},
+{18405, 18, 84046, {1, 1, 7, 3, 3, 47, 91, 79, 347, 215, 847, 2957, 5881, 5371, 20099, 45603, 29349, 175357}},
+{18406, 18, 84058, {1, 3, 1, 3, 13, 43, 101, 235, 505, 289, 691, 673, 5579, 8721, 9639, 18569, 44797, 250887}},
+{18407, 18, 84069, {1, 1, 3, 11, 23, 27, 85, 223, 365, 767, 577, 2781, 4179, 12963, 25235, 51021, 84989, 149521}},
+{18408, 18, 84107, {1, 1, 1, 1, 9, 51, 13, 129, 393, 725, 1301, 1391, 4693, 4979, 16801, 21361, 122157, 56675}},
+{18409, 18, 84155, {1, 3, 5, 11, 7, 21, 97, 97, 17, 915, 255, 155, 3961, 7999, 7493, 52683, 49377, 131663}},
+{18410, 18, 84157, {1, 3, 5, 15, 31, 23, 41, 187, 89, 933, 309, 2519, 6595, 13785, 14339, 44393, 64439, 142105}},
+{18411, 18, 84160, {1, 1, 1, 11, 13, 57, 29, 249, 467, 863, 77, 3185, 6221, 13109, 32397, 13859, 27331, 35295}},
+{18412, 18, 84165, {1, 3, 3, 3, 23, 31, 29, 189, 405, 855, 1597, 3167, 4171, 13801, 12297, 38019, 130141, 135517}},
+{18413, 18, 84187, {1, 1, 5, 7, 13, 37, 87, 41, 503, 281, 103, 1997, 3603, 4185, 25331, 55123, 74263, 248695}},
+{18414, 18, 84214, {1, 3, 1, 15, 13, 57, 67, 135, 429, 489, 829, 2069, 7657, 15713, 3907, 5819, 114005, 187859}},
+{18415, 18, 84226, {1, 1, 3, 1, 23, 43, 93, 63, 5, 435, 1649, 1429, 2923, 9035, 28667, 13991, 74491, 236225}},
+{18416, 18, 84235, {1, 3, 3, 7, 19, 29, 37, 143, 443, 955, 1431, 3193, 6023, 2421, 28955, 29171, 126785, 124709}},
+{18417, 18, 84240, {1, 3, 7, 7, 23, 45, 59, 101, 25, 711, 1685, 851, 3101, 12273, 10775, 57633, 52739, 244681}},
+{18418, 18, 84255, {1, 1, 1, 5, 3, 13, 97, 143, 367, 139, 1535, 873, 8005, 2795, 11103, 3837, 125833, 194903}},
+{18419, 18, 84273, {1, 3, 5, 7, 23, 61, 61, 203, 443, 543, 573, 2835, 941, 12315, 18453, 34367, 94359, 132437}},
+{18420, 18, 84291, {1, 1, 7, 5, 11, 21, 87, 27, 495, 67, 1267, 2029, 5041, 4133, 18821, 50249, 52397, 101431}},
+{18421, 18, 84311, {1, 3, 3, 3, 13, 51, 89, 183, 61, 919, 1841, 373, 7091, 9413, 1227, 44515, 72869, 198769}},
+{18422, 18, 84317, {1, 3, 3, 11, 13, 63, 13, 253, 203, 571, 91, 3477, 123, 15353, 7803, 62729, 14337, 252725}},
+{18423, 18, 84328, {1, 1, 7, 1, 11, 57, 45, 251, 351, 895, 1813, 3857, 7545, 9739, 32029, 24915, 46261, 8149}},
+{18424, 18, 84346, {1, 3, 1, 15, 25, 41, 71, 47, 265, 567, 307, 4079, 1943, 10407, 2999, 6605, 97621, 194711}},
+{18425, 18, 84357, {1, 1, 3, 5, 17, 29, 97, 249, 449, 761, 1727, 1533, 7417, 16167, 421, 39075, 1029, 180923}},
+{18426, 18, 84361, {1, 1, 1, 3, 11, 27, 67, 227, 131, 453, 951, 3897, 515, 4513, 17361, 50049, 4533, 35953}},
+{18427, 18, 84372, {1, 1, 1, 13, 7, 53, 25, 163, 453, 195, 1115, 1019, 3799, 7489, 12419, 15141, 112001, 106459}},
+{18428, 18, 84388, {1, 1, 3, 9, 27, 15, 63, 109, 293, 867, 645, 1821, 2867, 9653, 32617, 39617, 125589, 249169}},
+{18429, 18, 84415, {1, 1, 7, 5, 19, 17, 15, 105, 65, 143, 961, 493, 7301, 11299, 4549, 49873, 82447, 107}},
+{18430, 18, 84438, {1, 1, 7, 1, 31, 21, 19, 61, 255, 815, 421, 3097, 4993, 9709, 11529, 53839, 32653, 137861}},
+{18431, 18, 84444, {1, 3, 1, 9, 5, 5, 59, 179, 115, 101, 407, 1143, 309, 843, 31143, 60639, 126659, 111695}},
+{18432, 18, 84447, {1, 3, 7, 13, 7, 47, 65, 127, 159, 817, 1029, 2983, 5443, 11087, 10595, 47143, 128353, 195189}},
+{18433, 18, 84451, {1, 3, 7, 1, 27, 21, 61, 235, 433, 929, 581, 1925, 8185, 6037, 28859, 16843, 43499, 217091}},
+{18434, 18, 84465, {1, 3, 7, 11, 1, 11, 81, 187, 227, 967, 25, 2285, 1251, 10743, 2321, 29029, 89739, 188023}},
+{18435, 18, 84471, {1, 3, 5, 11, 21, 25, 57, 201, 89, 965, 1593, 2879, 2469, 13675, 28789, 11407, 13109, 52749}},
+{18436, 18, 84496, {1, 3, 3, 3, 19, 25, 87, 3, 127, 881, 645, 207, 1129, 4235, 1533, 52503, 128733, 238679}},
+{18437, 18, 84554, {1, 3, 3, 1, 5, 5, 63, 181, 493, 457, 1529, 1795, 219, 10807, 26713, 49673, 47167, 103595}},
+{18438, 18, 84561, {1, 1, 3, 3, 1, 31, 65, 79, 473, 257, 1477, 387, 2843, 4031, 8459, 44849, 115157, 8417}},
+{18439, 18, 84571, {1, 3, 3, 5, 15, 1, 105, 67, 343, 333, 1961, 649, 5105, 11387, 27437, 35471, 26295, 220309}},
+{18440, 18, 84580, {1, 3, 7, 15, 1, 7, 23, 113, 67, 1019, 1793, 3237, 7223, 5691, 6279, 50231, 49393, 84393}},
+{18441, 18, 84598, {1, 1, 1, 7, 9, 29, 125, 249, 89, 813, 561, 871, 1957, 1095, 18563, 5257, 39563, 225651}},
+{18442, 18, 84611, {1, 1, 1, 15, 17, 11, 51, 191, 217, 617, 793, 3633, 4673, 15463, 10621, 47221, 51611, 155937}},
+{18443, 18, 84620, {1, 3, 7, 15, 13, 7, 63, 57, 45, 1005, 685, 2913, 3597, 9933, 14819, 26015, 80023, 60547}},
+{18444, 18, 84625, {1, 1, 5, 5, 31, 43, 69, 63, 425, 439, 143, 933, 675, 11301, 31779, 53445, 25143, 213213}},
+{18445, 18, 84632, {1, 1, 1, 5, 21, 9, 91, 89, 483, 153, 389, 7, 633, 15527, 21833, 45171, 88331, 150935}},
+{18446, 18, 84648, {1, 3, 5, 5, 11, 31, 49, 139, 295, 289, 1623, 3359, 7551, 11285, 25083, 27699, 91869, 237571}},
+{18447, 18, 84659, {1, 1, 1, 9, 9, 25, 55, 71, 51, 603, 1901, 2729, 6803, 11135, 5427, 37285, 69141, 262073}},
+{18448, 18, 84662, {1, 1, 3, 11, 3, 7, 81, 89, 49, 303, 755, 223, 603, 12525, 26037, 47867, 118871, 238677}},
+{18449, 18, 84683, {1, 3, 3, 11, 1, 53, 55, 15, 341, 151, 245, 1979, 3523, 15151, 25075, 21425, 48689, 125391}},
+{18450, 18, 84697, {1, 3, 3, 7, 15, 21, 73, 247, 215, 339, 1995, 633, 2557, 5625, 28443, 16413, 34615, 260591}},
+{18451, 18, 84698, {1, 3, 5, 1, 1, 59, 21, 247, 403, 15, 1129, 2263, 3361, 10675, 30417, 31285, 69913, 124329}},
+{18452, 18, 84709, {1, 1, 5, 1, 17, 3, 103, 107, 333, 191, 345, 3219, 3845, 5953, 26403, 51115, 71623, 52293}},
+{18453, 18, 84722, {1, 1, 7, 5, 29, 13, 59, 65, 185, 91, 717, 3179, 1237, 1187, 25485, 40119, 6069, 23567}},
+{18454, 18, 84753, {1, 1, 1, 5, 17, 57, 27, 39, 269, 627, 1239, 135, 623, 483, 19229, 51939, 114387, 146431}},
+{18455, 18, 84775, {1, 3, 7, 9, 21, 41, 119, 129, 177, 149, 1527, 3639, 4489, 11635, 23007, 59863, 85199, 87795}},
+{18456, 18, 84789, {1, 3, 5, 9, 17, 25, 57, 237, 129, 855, 199, 1929, 2793, 4277, 4509, 46301, 32905, 102015}},
+{18457, 18, 84885, {1, 1, 7, 1, 15, 23, 3, 131, 475, 347, 1301, 241, 153, 2801, 29271, 1337, 107613, 154105}},
+{18458, 18, 84890, {1, 1, 1, 13, 5, 19, 43, 47, 381, 709, 637, 2565, 7503, 10027, 16873, 23511, 101785, 47987}},
+{18459, 18, 84899, {1, 1, 5, 13, 31, 15, 125, 97, 361, 819, 121, 2723, 3395, 6943, 5279, 55977, 103559, 134177}},
+{18460, 18, 84926, {1, 1, 7, 13, 17, 27, 105, 11, 327, 203, 1355, 1437, 959, 10113, 7405, 43511, 114073, 199463}},
+{18461, 18, 84946, {1, 1, 7, 5, 29, 19, 7, 151, 107, 739, 1021, 1287, 6881, 2741, 3407, 13847, 75669, 116015}},
+{18462, 18, 84958, {1, 1, 1, 5, 5, 17, 99, 67, 179, 319, 149, 4069, 7811, 3055, 24669, 21635, 68057, 72059}},
+{18463, 18, 84976, {1, 3, 1, 11, 3, 3, 103, 45, 431, 159, 1693, 1069, 3403, 6121, 12695, 16565, 29787, 199327}},
+{18464, 18, 84979, {1, 1, 5, 5, 5, 35, 97, 9, 7, 703, 1533, 847, 7693, 16041, 13127, 26829, 68801, 205219}},
+{18465, 18, 85003, {1, 1, 5, 9, 25, 59, 3, 63, 305, 71, 1429, 1567, 2377, 12611, 9267, 62381, 32373, 187735}},
+{18466, 18, 85014, {1, 1, 3, 15, 5, 31, 21, 113, 329, 573, 1975, 1615, 947, 987, 4655, 46803, 100251, 89729}},
+{18467, 18, 85017, {1, 1, 5, 9, 15, 63, 83, 5, 71, 191, 1127, 3529, 7325, 1169, 4255, 6715, 42765, 73231}},
+{18468, 18, 85024, {1, 3, 3, 9, 11, 1, 1, 23, 97, 967, 1465, 1305, 2073, 3143, 31333, 1409, 95321, 182333}},
+{18469, 18, 85029, {1, 3, 5, 13, 21, 53, 47, 105, 75, 721, 239, 3619, 2581, 2063, 21227, 25579, 23729, 20067}},
+{18470, 18, 85036, {1, 3, 5, 13, 1, 55, 55, 115, 391, 539, 869, 3347, 189, 11087, 11533, 18747, 25387, 19205}},
+{18471, 18, 85042, {1, 3, 1, 15, 25, 57, 81, 27, 379, 635, 1697, 2805, 8071, 11407, 14843, 17593, 20819, 42891}},
+{18472, 18, 85054, {1, 3, 5, 11, 1, 59, 51, 187, 11, 211, 1425, 3829, 3193, 15743, 16479, 4205, 108205, 205367}},
+{18473, 18, 85056, {1, 1, 1, 5, 7, 7, 59, 85, 63, 509, 897, 2473, 7345, 111, 4431, 55273, 114037, 232541}},
+{18474, 18, 85061, {1, 1, 5, 9, 29, 7, 25, 41, 401, 843, 115, 163, 6835, 13943, 5223, 31033, 10813, 250471}},
+{18475, 18, 85066, {1, 1, 5, 11, 27, 45, 43, 233, 195, 151, 11, 1539, 4775, 15743, 15507, 26939, 30353, 162929}},
+{18476, 18, 85073, {1, 3, 1, 7, 7, 39, 1, 87, 85, 1019, 1711, 2707, 735, 5093, 8231, 25069, 102861, 45751}},
+{18477, 18, 85096, {1, 3, 7, 1, 19, 49, 55, 249, 255, 809, 1799, 3475, 7697, 5003, 12437, 52313, 96355, 138537}},
+{18478, 18, 85101, {1, 1, 3, 5, 5, 43, 25, 95, 349, 775, 213, 3643, 1355, 7745, 9553, 53367, 123655, 195365}},
+{18479, 18, 85109, {1, 1, 1, 1, 19, 53, 39, 105, 449, 447, 147, 2293, 7817, 1503, 31985, 37193, 51039, 209083}},
+{18480, 18, 85114, {1, 3, 3, 15, 27, 15, 59, 51, 411, 543, 421, 3595, 2091, 7171, 23595, 33509, 37283, 105719}},
+{18481, 18, 85119, {1, 3, 1, 11, 5, 37, 5, 203, 171, 853, 1875, 2735, 4003, 15163, 26193, 36149, 31389, 256631}},
+{18482, 18, 85123, {1, 3, 5, 1, 21, 1, 127, 41, 185, 929, 1757, 2711, 2947, 9709, 18401, 45037, 1371, 242397}},
+{18483, 18, 85149, {1, 1, 1, 1, 13, 43, 51, 187, 487, 759, 1579, 959, 2499, 4781, 27179, 6839, 43869, 36163}},
+{18484, 18, 85185, {1, 3, 1, 15, 5, 3, 101, 25, 181, 107, 1105, 879, 5341, 12215, 21615, 9619, 129591, 108393}},
+{18485, 18, 85228, {1, 1, 7, 1, 11, 39, 55, 101, 43, 935, 1703, 1269, 6751, 13723, 7463, 10055, 112971, 72789}},
+{18486, 18, 85236, {1, 3, 5, 13, 7, 3, 81, 41, 55, 375, 663, 801, 5051, 14583, 30793, 63897, 127255, 174179}},
+{18487, 18, 85281, {1, 3, 1, 7, 19, 31, 53, 29, 313, 57, 1411, 103, 6863, 10673, 4341, 5587, 106059, 222309}},
+{18488, 18, 85282, {1, 3, 7, 3, 1, 33, 89, 199, 91, 557, 715, 2715, 4753, 5987, 30355, 13819, 57443, 112179}},
+{18489, 18, 85293, {1, 3, 5, 7, 13, 27, 55, 11, 495, 29, 1273, 1727, 3397, 2739, 22907, 46203, 16687, 47385}},
+{18490, 18, 85302, {1, 3, 5, 9, 13, 23, 23, 107, 353, 429, 359, 2667, 6137, 7213, 7977, 35903, 118507, 209243}},
+{18491, 18, 85319, {1, 3, 1, 13, 9, 7, 37, 135, 377, 753, 1819, 113, 7379, 2795, 10373, 7131, 17845, 246101}},
+{18492, 18, 85353, {1, 1, 3, 11, 11, 45, 53, 209, 49, 385, 1573, 1129, 2939, 10949, 413, 59193, 15399, 169355}},
+{18493, 18, 85354, {1, 1, 5, 15, 29, 29, 89, 139, 403, 11, 1335, 2601, 3631, 15317, 1707, 3517, 1939, 121997}},
+{18494, 18, 85356, {1, 3, 1, 7, 17, 3, 113, 97, 435, 911, 1743, 1649, 4829, 9995, 2873, 17527, 46931, 86199}},
+{18495, 18, 85389, {1, 1, 7, 1, 13, 19, 83, 51, 49, 671, 1651, 3443, 2279, 5677, 8859, 41945, 110607, 200469}},
+{18496, 18, 85418, {1, 1, 5, 13, 19, 63, 19, 73, 205, 571, 507, 1781, 1489, 5909, 10351, 64607, 67023, 49441}},
+{18497, 18, 85446, {1, 1, 3, 5, 13, 35, 107, 63, 489, 69, 1541, 3761, 17, 9317, 20323, 35401, 61451, 116115}},
+{18498, 18, 85450, {1, 3, 1, 5, 31, 35, 39, 119, 237, 533, 107, 3235, 4929, 15839, 9309, 50131, 110945, 24739}},
+{18499, 18, 85463, {1, 3, 1, 5, 3, 25, 73, 145, 391, 481, 1927, 3071, 4347, 13415, 26723, 51629, 3003, 54575}},
+{18500, 18, 85497, {1, 3, 3, 11, 29, 63, 63, 183, 11, 269, 153, 3379, 5603, 14279, 28579, 4653, 98179, 125693}},
+{18501, 18, 85534, {1, 1, 5, 15, 1, 51, 101, 69, 177, 233, 213, 2389, 4963, 3391, 13419, 41283, 25667, 187239}},
+{18502, 18, 85543, {1, 1, 1, 11, 13, 29, 95, 231, 481, 283, 1323, 521, 4689, 5311, 21949, 31851, 115845, 50433}},
+{18503, 18, 85549, {1, 3, 7, 15, 11, 31, 67, 207, 57, 439, 1561, 2167, 673, 6467, 8189, 31783, 5051, 64097}},
+{18504, 18, 85562, {1, 1, 7, 9, 17, 57, 77, 85, 119, 149, 211, 2727, 4921, 8701, 23121, 36355, 9179, 68003}},
+{18505, 18, 85587, {1, 1, 5, 15, 1, 15, 123, 205, 79, 299, 71, 3413, 7635, 5699, 32393, 10253, 86205, 216015}},
+{18506, 18, 85590, {1, 1, 5, 11, 23, 39, 105, 187, 487, 247, 333, 2423, 5643, 8111, 23549, 50153, 122859, 100361}},
+{18507, 18, 85599, {1, 1, 1, 9, 11, 33, 65, 125, 67, 743, 1331, 1563, 6333, 11375, 15873, 18137, 52765, 224889}},
+{18508, 18, 85630, {1, 3, 5, 9, 15, 17, 81, 165, 3, 609, 635, 2093, 6635, 8647, 25883, 18907, 73333, 80835}},
+{18509, 18, 85660, {1, 1, 1, 11, 1, 1, 25, 115, 205, 941, 1917, 1295, 3659, 821, 11355, 1435, 40289, 115627}},
+{18510, 18, 85669, {1, 3, 1, 9, 13, 23, 35, 105, 441, 777, 1255, 3315, 1157, 8719, 9939, 38931, 120723, 123201}},
+{18511, 18, 85693, {1, 1, 5, 3, 1, 21, 95, 143, 23, 233, 73, 1223, 5619, 8583, 21417, 61971, 74565, 116249}},
+{18512, 18, 85711, {1, 1, 7, 7, 23, 35, 21, 201, 441, 623, 419, 2375, 1189, 15681, 29469, 29437, 124525, 241899}},
+{18513, 18, 85716, {1, 1, 3, 1, 11, 7, 23, 171, 435, 467, 1811, 63, 3705, 9395, 579, 58305, 86165, 67805}},
+{18514, 18, 85773, {1, 3, 1, 3, 13, 11, 107, 243, 163, 79, 815, 1149, 2247, 12411, 30287, 56915, 26939, 85883}},
+{18515, 18, 85801, {1, 3, 3, 1, 5, 23, 105, 63, 35, 57, 1815, 3325, 3727, 3623, 7203, 8301, 28073, 190053}},
+{18516, 18, 85815, {1, 3, 1, 11, 23, 33, 121, 55, 287, 139, 491, 907, 4237, 17, 20055, 63729, 7517, 151597}},
+{18517, 18, 85839, {1, 3, 5, 5, 21, 1, 37, 19, 159, 1013, 27, 2627, 851, 14021, 31311, 5871, 77613, 125311}},
+{18518, 18, 85842, {1, 3, 3, 1, 27, 3, 51, 133, 459, 581, 383, 1351, 6149, 15611, 2631, 20797, 65955, 113665}},
+{18519, 18, 85864, {1, 3, 1, 11, 23, 61, 75, 217, 283, 405, 767, 1151, 7501, 5553, 113, 48331, 49379, 191473}},
+{18520, 18, 85867, {1, 3, 5, 5, 15, 3, 19, 27, 497, 519, 1611, 709, 405, 13329, 27861, 14981, 47197, 173979}},
+{18521, 18, 85903, {1, 1, 7, 7, 25, 19, 99, 219, 349, 713, 1421, 3427, 153, 13319, 22415, 48617, 119637, 20835}},
+{18522, 18, 85917, {1, 1, 1, 3, 13, 37, 43, 9, 317, 961, 1255, 2975, 2775, 12283, 29941, 57495, 77413, 256695}},
+{18523, 18, 85921, {1, 1, 7, 5, 29, 37, 91, 199, 397, 739, 877, 251, 847, 2951, 19497, 57285, 76891, 258711}},
+{18524, 18, 85928, {1, 1, 7, 15, 21, 55, 107, 115, 481, 845, 2015, 481, 3823, 14071, 4037, 39687, 62867, 170891}},
+{18525, 18, 85934, {1, 3, 3, 1, 17, 51, 81, 195, 189, 455, 1343, 1493, 351, 361, 20289, 37423, 7747, 245861}},
+{18526, 18, 85974, {1, 1, 5, 15, 9, 41, 71, 155, 197, 563, 1271, 2227, 2557, 6657, 13565, 8467, 96135, 5903}},
+{18527, 18, 85994, {1, 1, 5, 13, 29, 33, 115, 131, 283, 435, 1327, 1113, 4729, 14125, 23743, 40121, 119955, 237453}},
+{18528, 18, 85999, {1, 1, 1, 1, 13, 21, 109, 91, 105, 749, 1695, 1123, 4349, 9855, 31565, 64001, 7919, 83591}},
+{18529, 18, 86004, {1, 3, 1, 1, 13, 19, 89, 83, 13, 609, 731, 2655, 1123, 13415, 5645, 10003, 69381, 187621}},
+{18530, 18, 86008, {1, 3, 1, 15, 3, 37, 1, 139, 11, 917, 1191, 1381, 6035, 13851, 4565, 5427, 117703, 109965}},
+{18531, 18, 86046, {1, 1, 5, 3, 17, 37, 15, 115, 19, 65, 1807, 3879, 2709, 9819, 11457, 53705, 14821, 156079}},
+{18532, 18, 86067, {1, 1, 7, 13, 17, 29, 105, 77, 127, 457, 1287, 1533, 6879, 4001, 4083, 29523, 81175, 226409}},
+{18533, 18, 86084, {1, 3, 1, 5, 5, 59, 21, 253, 459, 733, 409, 3359, 1913, 8893, 16113, 61063, 6511, 22441}},
+{18534, 18, 86087, {1, 3, 5, 11, 7, 1, 121, 217, 63, 83, 173, 1869, 7931, 655, 21053, 20703, 116853, 131785}},
+{18535, 18, 86093, {1, 1, 7, 7, 5, 13, 41, 57, 1, 17, 649, 233, 2867, 5577, 30553, 7635, 45305, 47979}},
+{18536, 18, 86121, {1, 1, 7, 1, 1, 29, 61, 241, 107, 891, 49, 3433, 5045, 143, 22473, 29243, 82625, 184163}},
+{18537, 18, 86122, {1, 3, 1, 11, 11, 21, 119, 43, 117, 429, 1569, 637, 67, 9475, 31779, 2237, 122037, 245361}},
+{18538, 18, 86127, {1, 1, 7, 1, 31, 61, 9, 179, 467, 153, 1913, 2839, 6255, 12715, 28229, 20189, 3617, 213539}},
+{18539, 18, 86151, {1, 1, 7, 13, 25, 61, 9, 109, 331, 577, 21, 1017, 6521, 5991, 26573, 56881, 58455, 169407}},
+{18540, 18, 86166, {1, 1, 7, 9, 31, 57, 51, 41, 327, 859, 1295, 1577, 1071, 3277, 11685, 62129, 34111, 174639}},
+{18541, 18, 86179, {1, 3, 5, 1, 7, 63, 35, 165, 43, 943, 1545, 3717, 1471, 11579, 29637, 22913, 8867, 12837}},
+{18542, 18, 86188, {1, 1, 3, 1, 23, 7, 19, 151, 359, 347, 1085, 3923, 1039, 5149, 6047, 49811, 33099, 247983}},
+{18543, 18, 86193, {1, 1, 1, 5, 29, 23, 73, 189, 59, 865, 1499, 1953, 1261, 1071, 26761, 26145, 129427, 223219}},
+{18544, 18, 86206, {1, 3, 1, 9, 1, 29, 107, 173, 387, 703, 193, 1965, 6233, 10997, 32697, 31005, 15415, 94345}},
+{18545, 18, 86214, {1, 1, 3, 9, 31, 35, 7, 15, 317, 79, 2045, 1455, 1559, 15087, 287, 46665, 37225, 149017}},
+{18546, 18, 86226, {1, 1, 5, 13, 17, 27, 11, 107, 47, 803, 1487, 3049, 1171, 6237, 9157, 10037, 122349, 236877}},
+{18547, 18, 86242, {1, 1, 7, 9, 21, 35, 53, 139, 165, 73, 1405, 2941, 3553, 11945, 2493, 5743, 63749, 140535}},
+{18548, 18, 86256, {1, 3, 7, 11, 7, 57, 41, 187, 483, 499, 687, 117, 4951, 14709, 17025, 23027, 94863, 228465}},
+{18549, 18, 86259, {1, 3, 7, 7, 27, 29, 85, 117, 201, 637, 823, 1135, 7595, 3323, 23579, 40759, 25087, 995}},
+{18550, 18, 86298, {1, 3, 1, 9, 31, 53, 101, 29, 381, 101, 1939, 1973, 8191, 8155, 13881, 32309, 92907, 239525}},
+{18551, 18, 86300, {1, 1, 5, 7, 3, 35, 15, 207, 1, 47, 325, 559, 3377, 3909, 31225, 28367, 63891, 19129}},
+{18552, 18, 86307, {1, 1, 1, 5, 31, 61, 117, 211, 127, 969, 73, 1295, 7167, 14881, 9965, 28143, 28161, 131867}},
+{18553, 18, 86310, {1, 3, 7, 5, 5, 57, 37, 207, 201, 79, 1151, 3685, 2071, 1751, 5481, 51447, 103437, 154895}},
+{18554, 18, 86319, {1, 3, 5, 13, 9, 5, 57, 27, 131, 211, 1481, 2237, 4227, 6927, 18625, 49773, 55399, 15209}},
+{18555, 18, 86321, {1, 3, 1, 7, 23, 29, 3, 179, 479, 787, 463, 2041, 2581, 6281, 1657, 51433, 93807, 160047}},
+{18556, 18, 86328, {1, 1, 3, 13, 25, 35, 33, 231, 385, 479, 335, 3837, 5517, 13603, 15623, 46737, 42507, 208355}},
+{18557, 18, 86356, {1, 1, 7, 9, 3, 25, 51, 125, 213, 175, 1575, 1755, 1843, 14361, 13155, 22445, 55435, 62793}},
+{18558, 18, 86360, {1, 1, 1, 7, 25, 3, 21, 7, 309, 547, 19, 471, 2679, 16185, 12149, 41437, 47625, 75113}},
+{18559, 18, 86375, {1, 1, 5, 1, 9, 23, 81, 95, 123, 143, 1111, 9, 3501, 11897, 26499, 10009, 48073, 182529}},
+{18560, 18, 86399, {1, 3, 1, 1, 1, 17, 15, 157, 129, 1005, 543, 3917, 3493, 6537, 26997, 33217, 7987, 251635}},
+{18561, 18, 86400, {1, 3, 1, 13, 11, 41, 9, 19, 173, 751, 491, 1645, 5205, 9907, 28503, 61137, 79727, 200851}},
+{18562, 18, 86403, {1, 1, 1, 1, 3, 5, 105, 203, 97, 903, 1507, 2719, 5275, 1023, 29595, 42507, 39893, 151495}},
+{18563, 18, 86430, {1, 1, 1, 11, 31, 53, 51, 65, 145, 671, 489, 109, 803, 8541, 4439, 33893, 98495, 114955}},
+{18564, 18, 86446, {1, 1, 7, 11, 27, 63, 117, 235, 497, 841, 1461, 3757, 1077, 6997, 9611, 47453, 20197, 176939}},
+{18565, 18, 86460, {1, 3, 3, 3, 31, 17, 85, 145, 377, 225, 1033, 3017, 735, 5811, 25503, 25457, 124623, 51713}},
+{18566, 18, 86465, {1, 3, 3, 13, 19, 33, 127, 57, 321, 687, 1651, 3321, 5051, 8511, 19609, 49927, 30499, 102613}},
+{18567, 18, 86486, {1, 1, 5, 13, 7, 17, 17, 147, 381, 137, 1007, 2607, 1071, 8921, 13955, 47223, 130359, 246265}},
+{18568, 18, 86502, {1, 3, 7, 9, 13, 35, 71, 129, 57, 233, 357, 3181, 2841, 3707, 24947, 57777, 115133, 6049}},
+{18569, 18, 86563, {1, 3, 7, 15, 23, 1, 107, 225, 57, 633, 1515, 1631, 4303, 4221, 8281, 59139, 45023, 70219}},
+{18570, 18, 86595, {1, 1, 7, 5, 9, 9, 93, 131, 41, 245, 1261, 459, 4811, 10987, 10421, 63839, 34067, 196353}},
+{18571, 18, 86635, {1, 3, 3, 13, 17, 3, 87, 255, 167, 701, 821, 1965, 1415, 4101, 549, 6347, 92421, 47193}},
+{18572, 18, 86649, {1, 3, 7, 11, 23, 17, 51, 81, 71, 345, 971, 917, 1057, 3627, 20361, 13491, 12855, 234215}},
+{18573, 18, 86661, {1, 1, 1, 13, 17, 9, 25, 155, 463, 851, 243, 3887, 2445, 7459, 19915, 21813, 86969, 85891}},
+{18574, 18, 86674, {1, 1, 7, 1, 9, 15, 57, 201, 193, 169, 351, 1355, 1089, 4705, 15153, 51359, 49907, 66007}},
+{18575, 18, 86689, {1, 3, 1, 9, 19, 13, 69, 83, 39, 667, 1549, 1503, 7167, 8657, 17269, 59357, 80091, 194007}},
+{18576, 18, 86721, {1, 3, 5, 5, 17, 37, 125, 117, 355, 685, 637, 3159, 4783, 3159, 14953, 12731, 126759, 89149}},
+{18577, 18, 86734, {1, 3, 3, 9, 15, 53, 7, 41, 473, 857, 511, 3741, 6837, 6167, 26351, 9885, 104819, 48221}},
+{18578, 18, 86741, {1, 3, 7, 15, 21, 21, 21, 101, 465, 223, 13, 1773, 2763, 8621, 23591, 12633, 82143, 134899}},
+{18579, 18, 86742, {1, 3, 1, 1, 29, 25, 67, 19, 349, 503, 655, 3567, 97, 6967, 18253, 42755, 33041, 250279}},
+{18580, 18, 86784, {1, 1, 7, 9, 17, 1, 7, 165, 255, 613, 579, 127, 7567, 13181, 6255, 1785, 21527, 113815}},
+{18581, 18, 86799, {1, 3, 1, 5, 27, 33, 61, 235, 37, 135, 1515, 3611, 1825, 9627, 18805, 37065, 126107, 23223}},
+{18582, 18, 86808, {1, 3, 7, 5, 23, 11, 29, 121, 129, 311, 429, 1653, 5789, 7693, 18775, 18189, 97203, 213501}},
+{18583, 18, 86837, {1, 3, 7, 3, 29, 61, 87, 197, 43, 509, 5, 3275, 345, 7885, 4381, 22059, 1395, 40125}},
+{18584, 18, 86869, {1, 3, 5, 1, 1, 59, 69, 125, 297, 983, 641, 2665, 7045, 8591, 16581, 58657, 119189, 256579}},
+{18585, 18, 86900, {1, 3, 7, 7, 7, 53, 65, 181, 149, 987, 1377, 4045, 971, 9827, 17727, 59357, 90975, 27395}},
+{18586, 18, 86949, {1, 1, 7, 7, 1, 51, 109, 165, 361, 515, 739, 3709, 6431, 113, 21401, 41743, 53071, 134205}},
+{18587, 18, 86993, {1, 3, 1, 13, 5, 51, 107, 99, 135, 163, 1705, 1683, 6221, 1377, 2211, 13379, 22801, 208753}},
+{18588, 18, 86999, {1, 3, 5, 11, 11, 39, 49, 45, 503, 549, 821, 4077, 885, 13721, 29673, 28435, 6235, 212071}},
+{18589, 18, 87030, {1, 3, 3, 11, 15, 25, 17, 67, 125, 7, 1163, 973, 5325, 12707, 12763, 9481, 21363, 195897}},
+{18590, 18, 87041, {1, 1, 7, 9, 17, 19, 15, 13, 107, 919, 461, 343, 1101, 8195, 29293, 61643, 64995, 230469}},
+{18591, 18, 87044, {1, 3, 5, 1, 9, 25, 39, 65, 27, 461, 669, 2841, 7973, 11565, 9531, 52235, 6741, 215513}},
+{18592, 18, 87084, {1, 3, 3, 1, 7, 57, 101, 199, 37, 79, 2033, 1723, 6877, 2733, 26445, 62625, 21671, 238431}},
+{18593, 18, 87116, {1, 1, 1, 9, 27, 31, 125, 199, 331, 611, 523, 407, 747, 9499, 4685, 17805, 43717, 253233}},
+{18594, 18, 87138, {1, 1, 3, 7, 29, 7, 7, 153, 339, 337, 701, 2639, 6311, 6375, 26023, 27693, 59733, 260405}},
+{18595, 18, 87162, {1, 1, 7, 7, 15, 27, 23, 49, 181, 433, 485, 2915, 6021, 9095, 15951, 47257, 104513, 208089}},
+{18596, 18, 87188, {1, 1, 5, 7, 19, 19, 125, 153, 109, 829, 1967, 2567, 7157, 6001, 10151, 55323, 92405, 82549}},
+{18597, 18, 87211, {1, 1, 3, 11, 13, 17, 85, 215, 265, 875, 311, 3773, 8059, 2115, 19259, 63999, 77411, 220267}},
+{18598, 18, 87234, {1, 3, 1, 15, 15, 35, 81, 213, 411, 435, 105, 1487, 1991, 14539, 8175, 2115, 47259, 45893}},
+{18599, 18, 87245, {1, 3, 1, 11, 9, 47, 27, 115, 449, 521, 321, 2463, 1355, 5785, 11269, 45337, 29049, 91675}},
+{18600, 18, 87246, {1, 3, 1, 13, 21, 53, 49, 83, 373, 519, 757, 1241, 577, 14443, 449, 44773, 116673, 155209}},
+{18601, 18, 87260, {1, 3, 3, 1, 29, 63, 97, 145, 371, 585, 1809, 3997, 249, 283, 28369, 27325, 61673, 12637}},
+{18602, 18, 87270, {1, 3, 5, 9, 11, 55, 77, 89, 285, 297, 861, 2791, 3245, 15093, 32489, 40477, 97603, 35347}},
+{18603, 18, 87284, {1, 1, 1, 3, 27, 33, 115, 209, 169, 893, 393, 1457, 6069, 12511, 20423, 11385, 86711, 197555}},
+{18604, 18, 87293, {1, 3, 5, 15, 21, 25, 87, 159, 477, 177, 991, 495, 29, 9347, 9721, 4071, 30145, 214155}},
+{18605, 18, 87296, {1, 1, 5, 3, 11, 45, 53, 251, 177, 651, 549, 3377, 3247, 8761, 20339, 27743, 103387, 159591}},
+{18606, 18, 87299, {1, 3, 7, 11, 17, 27, 43, 179, 507, 553, 261, 3939, 6133, 6347, 12987, 46071, 42551, 99225}},
+{18607, 18, 87305, {1, 3, 3, 11, 3, 33, 85, 51, 277, 117, 1295, 2435, 1467, 13787, 2209, 52673, 53515, 157625}},
+{18608, 18, 87308, {1, 3, 3, 3, 9, 15, 121, 229, 227, 795, 541, 3727, 4333, 2251, 27833, 43567, 82505, 230427}},
+{18609, 18, 87313, {1, 1, 5, 13, 29, 19, 119, 63, 207, 945, 761, 2601, 1391, 8939, 11683, 52433, 63301, 82501}},
+{18610, 18, 87323, {1, 3, 7, 1, 3, 57, 127, 115, 209, 31, 1631, 347, 3937, 4015, 13313, 49507, 15103, 237071}},
+{18611, 18, 87332, {1, 3, 1, 13, 3, 25, 85, 151, 115, 385, 303, 2453, 2417, 8051, 1447, 59517, 3711, 160345}},
+{18612, 18, 87361, {1, 3, 1, 13, 1, 23, 49, 75, 117, 295, 1737, 2091, 6229, 3157, 32737, 13751, 101667, 96261}},
+{18613, 18, 87376, {1, 3, 3, 5, 27, 19, 103, 201, 65, 757, 1847, 239, 2185, 15139, 8883, 17737, 9207, 147663}},
+{18614, 18, 87392, {1, 3, 1, 9, 3, 39, 51, 1, 419, 929, 1049, 2891, 2585, 2759, 27587, 55711, 15461, 46851}},
+{18615, 18, 87419, {1, 1, 5, 3, 23, 23, 23, 101, 249, 997, 1889, 2293, 5693, 939, 29619, 2775, 49293, 168895}},
+{18616, 18, 87432, {1, 3, 1, 15, 9, 63, 17, 97, 385, 517, 1737, 713, 157, 2597, 20889, 35209, 47525, 14389}},
+{18617, 18, 87435, {1, 3, 1, 1, 7, 27, 9, 147, 349, 493, 341, 2699, 7743, 4283, 24691, 11881, 78619, 153899}},
+{18618, 18, 87445, {1, 3, 1, 9, 15, 25, 103, 177, 485, 355, 1319, 767, 6675, 3425, 7187, 53767, 92023, 151523}},
+{18619, 18, 87466, {1, 1, 3, 3, 15, 35, 25, 177, 295, 5, 661, 3651, 2597, 16229, 1343, 54941, 72047, 169155}},
+{18620, 18, 87491, {1, 1, 1, 1, 19, 29, 63, 229, 79, 551, 1401, 2851, 6935, 12485, 9243, 21671, 54209, 105347}},
+{18621, 18, 87503, {1, 1, 3, 1, 13, 33, 53, 125, 261, 623, 65, 3863, 1899, 2453, 16483, 48655, 50771, 248555}},
+{18622, 18, 87558, {1, 3, 5, 7, 25, 15, 107, 149, 485, 247, 1977, 3125, 4663, 4925, 15749, 39429, 52315, 30545}},
+{18623, 18, 87570, {1, 1, 7, 13, 23, 13, 127, 111, 9, 17, 1887, 1341, 3017, 14333, 6003, 35113, 14935, 17593}},
+{18624, 18, 87581, {1, 1, 1, 15, 23, 17, 111, 43, 71, 549, 1369, 1711, 3903, 13605, 14573, 18973, 28157, 128421}},
+{18625, 18, 87603, {1, 1, 7, 15, 27, 23, 5, 99, 87, 865, 1979, 3287, 3977, 14989, 17439, 14593, 92711, 211259}},
+{18626, 18, 87615, {1, 3, 3, 15, 5, 19, 3, 231, 127, 863, 1537, 369, 7915, 10281, 13925, 12931, 3905, 178609}},
+{18627, 18, 87623, {1, 1, 3, 15, 13, 5, 17, 217, 383, 251, 1701, 3379, 8157, 4991, 8563, 24611, 66081, 205775}},
+{18628, 18, 87635, {1, 3, 7, 11, 9, 25, 73, 131, 217, 601, 843, 807, 4509, 16209, 29581, 50869, 56595, 14283}},
+{18629, 18, 87647, {1, 3, 5, 9, 5, 59, 57, 153, 359, 775, 859, 1897, 6415, 7389, 10851, 64247, 21627, 145017}},
+{18630, 18, 87651, {1, 3, 7, 1, 27, 11, 117, 179, 175, 343, 687, 2775, 3655, 11655, 2641, 355, 83447, 237799}},
+{18631, 18, 87657, {1, 1, 7, 11, 17, 59, 91, 21, 403, 797, 1839, 525, 3279, 6575, 30083, 12503, 83057, 109465}},
+{18632, 18, 87665, {1, 3, 7, 1, 25, 27, 41, 223, 169, 679, 699, 3287, 6305, 6459, 23145, 45519, 127487, 183563}},
+{18633, 18, 87694, {1, 3, 3, 1, 9, 45, 105, 57, 185, 97, 899, 3113, 7081, 7057, 14559, 53537, 105623, 155399}},
+{18634, 18, 87701, {1, 3, 7, 5, 17, 35, 89, 13, 87, 587, 451, 4079, 1005, 4311, 15861, 49977, 59653, 12107}},
+{18635, 18, 87705, {1, 3, 7, 3, 19, 55, 43, 77, 317, 369, 71, 937, 1905, 5005, 17715, 4005, 55445, 25159}},
+{18636, 18, 87722, {1, 1, 7, 15, 15, 51, 87, 37, 59, 755, 763, 455, 711, 13399, 30999, 61269, 66037, 202793}},
+{18637, 18, 87739, {1, 1, 3, 5, 11, 57, 111, 135, 325, 553, 273, 1533, 3431, 6427, 24771, 42143, 56711, 220873}},
+{18638, 18, 87750, {1, 1, 1, 13, 3, 49, 53, 81, 491, 177, 1543, 1847, 7907, 7817, 15417, 9897, 101597, 160195}},
+{18639, 18, 87790, {1, 3, 1, 15, 19, 15, 91, 123, 365, 113, 129, 3371, 5789, 13553, 6887, 62317, 84269, 44777}},
+{18640, 18, 87795, {1, 3, 7, 13, 15, 63, 43, 175, 449, 437, 597, 1371, 5101, 13797, 28025, 15809, 7645, 21169}},
+{18641, 18, 87797, {1, 1, 7, 13, 23, 63, 105, 69, 219, 153, 1539, 1537, 6899, 9363, 27459, 34551, 62563, 236679}},
+{18642, 18, 87816, {1, 3, 7, 3, 9, 33, 3, 101, 135, 571, 127, 3881, 7017, 13403, 13817, 55167, 8645, 471}},
+{18643, 18, 87884, {1, 3, 3, 13, 7, 53, 29, 89, 473, 135, 639, 3137, 93, 965, 4867, 58265, 114963, 175295}},
+{18644, 18, 87917, {1, 3, 1, 1, 9, 11, 45, 123, 129, 441, 1601, 39, 4657, 3701, 29581, 16045, 57173, 75195}},
+{18645, 18, 87930, {1, 1, 3, 11, 7, 21, 9, 73, 25, 891, 1625, 3019, 223, 14351, 30621, 3075, 79051, 178127}},
+{18646, 18, 87942, {1, 1, 7, 3, 7, 43, 69, 209, 9, 857, 1539, 2629, 5277, 14583, 16443, 28275, 54143, 206479}},
+{18647, 18, 87953, {1, 3, 5, 9, 27, 15, 109, 237, 323, 103, 837, 597, 3609, 6249, 795, 37191, 20997, 142079}},
+{18648, 18, 87954, {1, 1, 3, 1, 27, 33, 123, 191, 55, 531, 1707, 2633, 6717, 9645, 21377, 51593, 9017, 178185}},
+{18649, 18, 87984, {1, 1, 5, 15, 3, 3, 67, 225, 229, 161, 2039, 1499, 873, 8803, 29901, 58809, 35625, 207797}},
+{18650, 18, 87989, {1, 3, 3, 7, 3, 47, 99, 237, 221, 31, 1043, 1081, 837, 1617, 17323, 43879, 55615, 238537}},
+{18651, 18, 88008, {1, 3, 7, 1, 17, 37, 45, 211, 245, 657, 221, 1067, 1683, 16127, 585, 9067, 25935, 162469}},
+{18652, 18, 88016, {1, 1, 5, 9, 23, 27, 5, 237, 137, 227, 129, 279, 4171, 5963, 349, 12387, 40701, 177255}},
+{18653, 18, 88038, {1, 3, 7, 15, 17, 11, 95, 69, 49, 901, 509, 2541, 3001, 15501, 24235, 39863, 95381, 260793}},
+{18654, 18, 88042, {1, 3, 3, 3, 29, 3, 125, 3, 423, 609, 1401, 2337, 1093, 11419, 29735, 9033, 115977, 210201}},
+{18655, 18, 88044, {1, 1, 1, 9, 11, 21, 71, 33, 399, 1005, 1691, 1501, 2585, 7361, 21527, 7535, 87091, 192319}},
+{18656, 18, 88049, {1, 1, 1, 11, 5, 49, 65, 115, 239, 255, 381, 2803, 3447, 5775, 18243, 16545, 108901, 81355}},
+{18657, 18, 88083, {1, 3, 7, 15, 31, 5, 81, 213, 281, 903, 189, 1807, 3551, 4423, 3591, 27449, 71659, 255357}},
+{18658, 18, 88119, {1, 1, 1, 15, 11, 1, 25, 213, 259, 215, 435, 3531, 4889, 9509, 21391, 21589, 89871, 85895}},
+{18659, 18, 88134, {1, 3, 3, 9, 29, 29, 37, 127, 419, 631, 1793, 1547, 1463, 13265, 17233, 24627, 3687, 174179}},
+{18660, 18, 88138, {1, 1, 1, 7, 27, 61, 105, 135, 439, 161, 721, 2779, 6731, 14575, 4565, 25869, 38981, 191683}},
+{18661, 18, 88143, {1, 1, 7, 13, 21, 41, 43, 5, 313, 407, 505, 231, 5023, 8971, 15825, 38461, 38797, 136027}},
+{18662, 18, 88191, {1, 3, 7, 3, 7, 59, 11, 255, 327, 843, 1179, 889, 4505, 10891, 7901, 14485, 72297, 255985}},
+{18663, 18, 88216, {1, 1, 5, 3, 9, 37, 89, 59, 413, 51, 515, 4009, 6501, 8443, 14381, 60917, 43567, 234431}},
+{18664, 18, 88231, {1, 1, 3, 9, 9, 57, 65, 205, 367, 935, 1975, 2561, 225, 12529, 4721, 56659, 87901, 219641}},
+{18665, 18, 88232, {1, 3, 7, 15, 23, 55, 61, 15, 89, 267, 1245, 2703, 7471, 10499, 19, 19357, 72413, 199289}},
+{18666, 18, 88297, {1, 1, 1, 13, 1, 29, 65, 11, 353, 509, 1831, 2181, 5265, 14761, 913, 17109, 113613, 37143}},
+{18667, 18, 88300, {1, 1, 7, 5, 17, 37, 97, 249, 169, 223, 475, 2091, 3101, 8541, 325, 42359, 16121, 151739}},
+{18668, 18, 88308, {1, 1, 3, 13, 1, 45, 13, 209, 395, 215, 15, 2287, 5365, 9887, 29799, 51957, 97483, 109467}},
+{18669, 18, 88317, {1, 3, 7, 1, 9, 35, 91, 51, 387, 833, 783, 2483, 3743, 6155, 5881, 3047, 86191, 151867}},
+{18670, 18, 88344, {1, 1, 1, 7, 15, 25, 13, 3, 119, 333, 761, 3459, 2555, 15737, 12945, 15225, 45487, 78235}},
+{18671, 18, 88350, {1, 3, 1, 3, 13, 55, 111, 45, 121, 593, 633, 2705, 1653, 13275, 13533, 3559, 100573, 124363}},
+{18672, 18, 88371, {1, 1, 3, 1, 29, 49, 65, 69, 133, 667, 653, 2559, 6335, 8019, 9251, 5415, 90125, 197413}},
+{18673, 18, 88469, {1, 1, 1, 7, 23, 53, 99, 149, 39, 453, 129, 185, 1143, 12799, 23339, 41293, 94023, 105581}},
+{18674, 18, 88483, {1, 3, 3, 13, 5, 3, 5, 215, 425, 455, 421, 3815, 5983, 3851, 19569, 17363, 6411, 60037}},
+{18675, 18, 88485, {1, 3, 7, 1, 29, 7, 63, 207, 299, 17, 1915, 2041, 8129, 661, 32481, 55475, 72027, 239683}},
+{18676, 18, 88518, {1, 1, 5, 13, 29, 11, 39, 177, 177, 479, 1291, 3931, 4353, 327, 7827, 9529, 6967, 6469}},
+{18677, 18, 88586, {1, 1, 5, 3, 25, 39, 121, 15, 7, 715, 583, 3997, 1373, 7747, 1777, 7269, 105333, 201511}},
+{18678, 18, 88605, {1, 3, 3, 9, 11, 7, 81, 109, 129, 359, 1281, 1163, 4895, 10303, 17801, 43461, 120271, 173027}},
+{18679, 18, 88621, {1, 3, 5, 1, 23, 59, 123, 75, 505, 925, 637, 1713, 995, 14031, 13711, 62569, 90553, 242345}},
+{18680, 18, 88651, {1, 3, 3, 15, 19, 11, 39, 203, 229, 619, 735, 1367, 4963, 5263, 30229, 17847, 9623, 3277}},
+{18681, 18, 88656, {1, 1, 7, 13, 5, 27, 23, 223, 377, 335, 1821, 2481, 4111, 10373, 18423, 7237, 75225, 223433}},
+{18682, 18, 88665, {1, 3, 7, 1, 21, 19, 71, 107, 19, 703, 945, 3831, 1099, 6267, 17489, 27665, 8861, 127499}},
+{18683, 18, 88668, {1, 3, 5, 1, 19, 49, 117, 181, 245, 939, 1279, 3127, 4427, 3061, 23399, 64805, 43077, 100789}},
+{18684, 18, 88712, {1, 1, 3, 3, 31, 55, 53, 205, 97, 645, 215, 2617, 7419, 7159, 27373, 62341, 58121, 248677}},
+{18685, 18, 88717, {1, 1, 7, 5, 15, 41, 99, 75, 201, 187, 197, 3773, 3097, 6803, 5307, 31375, 26743, 142723}},
+{18686, 18, 88751, {1, 3, 5, 11, 23, 61, 127, 15, 89, 245, 1345, 1305, 5937, 15917, 23867, 50319, 91921, 248663}},
+{18687, 18, 88754, {1, 1, 3, 9, 27, 7, 1, 75, 181, 155, 1947, 577, 2975, 8855, 5295, 43403, 112497, 100679}},
+{18688, 18, 88756, {1, 1, 1, 11, 29, 61, 35, 241, 207, 73, 1747, 1797, 3665, 14275, 25359, 28685, 79367, 81819}},
+{18689, 18, 88785, {1, 3, 5, 9, 11, 1, 37, 79, 431, 157, 1979, 159, 3087, 1731, 26141, 31411, 56457, 94293}},
+{18690, 18, 88801, {1, 3, 7, 1, 17, 35, 107, 243, 279, 79, 227, 1275, 761, 11485, 22181, 16415, 68801, 4577}},
+{18691, 18, 88807, {1, 3, 1, 9, 21, 43, 115, 131, 129, 123, 1677, 1875, 7355, 15927, 845, 24101, 48985, 39703}},
+{18692, 18, 88826, {1, 1, 7, 3, 17, 25, 105, 189, 317, 109, 1629, 3103, 615, 1047, 621, 62743, 43631, 9811}},
+{18693, 18, 88848, {1, 3, 1, 3, 3, 45, 49, 73, 383, 761, 685, 3211, 3855, 16307, 30469, 1393, 52535, 165503}},
+{18694, 18, 88854, {1, 3, 5, 15, 1, 41, 89, 105, 213, 33, 1477, 711, 4823, 503, 12533, 56781, 42825, 223399}},
+{18695, 18, 88864, {1, 3, 5, 9, 17, 45, 63, 113, 359, 927, 1467, 2811, 4275, 5193, 6023, 32689, 87747, 234697}},
+{18696, 18, 88879, {1, 1, 3, 1, 21, 49, 73, 157, 97, 915, 1689, 3289, 7515, 10759, 32253, 63175, 66175, 125813}},
+{18697, 18, 88939, {1, 1, 1, 5, 19, 1, 127, 229, 453, 617, 511, 1515, 3815, 3125, 26851, 31635, 35389, 237483}},
+{18698, 18, 88947, {1, 1, 1, 13, 27, 61, 75, 23, 289, 133, 975, 3217, 3777, 12095, 15235, 33845, 125503, 88417}},
+{18699, 18, 88987, {1, 1, 3, 13, 27, 49, 29, 115, 221, 995, 1305, 2717, 2243, 13391, 20841, 863, 63195, 46829}},
+{18700, 18, 88990, {1, 3, 1, 11, 31, 49, 43, 163, 503, 123, 657, 1285, 3695, 8401, 17087, 48289, 3947, 41495}},
+{18701, 18, 88996, {1, 3, 7, 9, 21, 17, 125, 75, 395, 979, 781, 2501, 6511, 4619, 28943, 18295, 87547, 196289}},
+{18702, 18, 89008, {1, 3, 3, 5, 3, 39, 107, 199, 7, 331, 77, 511, 5787, 3155, 29605, 44633, 51041, 89141}},
+{18703, 18, 89011, {1, 1, 3, 7, 11, 37, 79, 69, 181, 623, 299, 2321, 4371, 7449, 3137, 25753, 116673, 30441}},
+{18704, 18, 89043, {1, 1, 5, 9, 11, 13, 49, 207, 179, 671, 1469, 1005, 6887, 12203, 9365, 62455, 36283, 42053}},
+{18705, 18, 89045, {1, 3, 1, 1, 7, 31, 115, 79, 435, 101, 1525, 3695, 3229, 11401, 23959, 62055, 37725, 219753}},
+{18706, 18, 89050, {1, 3, 3, 7, 25, 49, 123, 161, 275, 291, 255, 2247, 4271, 10771, 2449, 26343, 61169, 30691}},
+{18707, 18, 89097, {1, 1, 7, 1, 15, 3, 11, 15, 125, 1021, 1817, 417, 2721, 13985, 19039, 451, 32559, 199407}},
+{18708, 18, 89100, {1, 1, 5, 15, 11, 25, 23, 101, 427, 431, 1353, 1957, 3529, 513, 11937, 14469, 89539, 242015}},
+{18709, 18, 89106, {1, 1, 5, 13, 27, 5, 107, 29, 469, 3, 1427, 1949, 7007, 16339, 3375, 63545, 100739, 229487}},
+{18710, 18, 89134, {1, 3, 5, 13, 15, 17, 59, 213, 417, 557, 11, 811, 5041, 4133, 25735, 46807, 65669, 148081}},
+{18711, 18, 89178, {1, 1, 5, 13, 9, 47, 35, 173, 277, 805, 1249, 3707, 1079, 2833, 29383, 58995, 21005, 181567}},
+{18712, 18, 89189, {1, 3, 5, 1, 5, 25, 125, 45, 157, 291, 1329, 3317, 2311, 9919, 31001, 65127, 19451, 117621}},
+{18713, 18, 89202, {1, 1, 5, 9, 31, 21, 9, 193, 23, 879, 699, 1135, 7151, 8635, 20711, 45207, 67047, 4397}},
+{18714, 18, 89211, {1, 3, 1, 11, 11, 49, 119, 129, 409, 491, 463, 833, 3661, 607, 25961, 6061, 12747, 160337}},
+{18715, 18, 89224, {1, 3, 1, 15, 31, 35, 93, 95, 239, 695, 1113, 2371, 2625, 10371, 10781, 46209, 67051, 109923}},
+{18716, 18, 89241, {1, 3, 5, 9, 5, 61, 25, 19, 99, 159, 55, 43, 3679, 1023, 17951, 44841, 101653, 195955}},
+{18717, 18, 89251, {1, 1, 3, 11, 19, 45, 99, 47, 407, 115, 353, 3537, 7147, 5837, 27309, 44539, 30227, 93183}},
+{18718, 18, 89254, {1, 1, 7, 15, 13, 59, 83, 215, 79, 865, 269, 2999, 2415, 10631, 23655, 51583, 46105, 43965}},
+{18719, 18, 89258, {1, 3, 7, 5, 17, 1, 7, 119, 501, 25, 1097, 3639, 7017, 381, 4793, 37263, 60431, 77323}},
+{18720, 18, 89295, {1, 3, 7, 13, 1, 37, 99, 103, 459, 853, 5, 3093, 6167, 14497, 7003, 36979, 71919, 64823}},
+{18721, 18, 89328, {1, 3, 7, 5, 23, 7, 37, 255, 297, 115, 113, 579, 4561, 5245, 11173, 28645, 23989, 240777}},
+{18722, 18, 89357, {1, 3, 5, 9, 29, 47, 43, 145, 481, 251, 737, 2531, 2425, 529, 3953, 13229, 35933, 187855}},
+{18723, 18, 89403, {1, 3, 1, 15, 15, 15, 29, 73, 405, 91, 1399, 3599, 1517, 11075, 11265, 22817, 26619, 1183}},
+{18724, 18, 89420, {1, 1, 5, 15, 21, 47, 93, 33, 47, 527, 877, 3453, 3867, 4007, 32503, 11789, 68333, 187419}},
+{18725, 18, 89426, {1, 1, 3, 13, 5, 3, 99, 21, 17, 779, 541, 3919, 1339, 13507, 28965, 61145, 50421, 192319}},
+{18726, 18, 89465, {1, 1, 3, 7, 31, 63, 17, 9, 331, 681, 515, 1067, 351, 2471, 31271, 36015, 72911, 32383}},
+{18727, 18, 89471, {1, 1, 3, 7, 1, 55, 97, 211, 409, 499, 1207, 2405, 2291, 1373, 1263, 65303, 38655, 159965}},
+{18728, 18, 89475, {1, 1, 1, 5, 23, 11, 21, 23, 35, 19, 1699, 2325, 6117, 14971, 32327, 31369, 28061, 112819}},
+{18729, 18, 89547, {1, 3, 3, 13, 29, 63, 19, 201, 173, 395, 1437, 369, 7045, 14347, 5393, 11311, 28415, 161019}},
+{18730, 18, 89549, {1, 3, 1, 5, 31, 15, 101, 13, 97, 865, 1063, 2129, 811, 3337, 7585, 54803, 122099, 149531}},
+{18731, 18, 89558, {1, 3, 3, 13, 19, 5, 47, 13, 497, 683, 1197, 3509, 4375, 3353, 31847, 283, 95281, 7975}},
+{18732, 18, 89564, {1, 1, 7, 5, 25, 19, 59, 105, 167, 775, 581, 2679, 3003, 9345, 20209, 31487, 25357, 226341}},
+{18733, 18, 89611, {1, 1, 5, 5, 31, 61, 13, 77, 189, 141, 1157, 609, 7245, 15303, 32743, 50229, 67391, 173977}},
+{18734, 18, 89616, {1, 3, 7, 13, 17, 11, 49, 135, 475, 303, 1373, 1437, 6119, 1729, 21347, 31643, 86523, 41223}},
+{18735, 18, 89626, {1, 3, 7, 13, 3, 19, 103, 53, 209, 281, 77, 2009, 7911, 8549, 17655, 33165, 9685, 2289}},
+{18736, 18, 89650, {1, 3, 3, 9, 5, 31, 71, 113, 93, 255, 165, 3465, 6769, 13047, 20701, 33669, 22537, 175209}},
+{18737, 18, 89691, {1, 3, 1, 1, 15, 59, 89, 227, 275, 451, 869, 1865, 1327, 3895, 5459, 47997, 34287, 95343}},
+{18738, 18, 89718, {1, 3, 7, 13, 27, 1, 25, 99, 475, 421, 693, 1955, 4017, 16037, 29915, 52415, 99913, 59151}},
+{18739, 18, 89764, {1, 3, 5, 1, 9, 61, 107, 149, 465, 1003, 891, 2387, 407, 5851, 6287, 56401, 109693, 72035}},
+{18740, 18, 89776, {1, 1, 1, 11, 25, 53, 101, 125, 35, 949, 1019, 3087, 2785, 11271, 25623, 57313, 115683, 101923}},
+{18741, 18, 89785, {1, 3, 5, 13, 19, 13, 97, 147, 149, 483, 1727, 1771, 2089, 8661, 28223, 30437, 42565, 13261}},
+{18742, 18, 89813, {1, 3, 3, 11, 17, 9, 13, 13, 419, 531, 1617, 1459, 411, 9953, 25581, 30305, 120721, 81113}},
+{18743, 18, 89817, {1, 3, 3, 9, 9, 9, 83, 35, 367, 981, 911, 1915, 4937, 16187, 20441, 30433, 107605, 119939}},
+{18744, 18, 89861, {1, 3, 7, 11, 11, 47, 31, 7, 141, 905, 1753, 3069, 47, 7347, 10517, 19515, 126827, 68669}},
+{18745, 18, 89876, {1, 3, 3, 9, 17, 33, 121, 159, 265, 389, 261, 2479, 7705, 6453, 31963, 14123, 100201, 77235}},
+{18746, 18, 89889, {1, 1, 5, 5, 13, 63, 3, 1, 107, 383, 633, 2183, 1437, 14525, 29315, 3277, 2153, 204061}},
+{18747, 18, 89904, {1, 3, 3, 3, 17, 9, 47, 173, 17, 413, 451, 1127, 1807, 5265, 32543, 8215, 123601, 138777}},
+{18748, 18, 89939, {1, 3, 1, 1, 7, 57, 93, 29, 101, 955, 1445, 4017, 2853, 3551, 22173, 40355, 34687, 133063}},
+{18749, 18, 89948, {1, 1, 5, 11, 19, 15, 95, 177, 49, 971, 15, 2293, 2627, 7841, 2103, 64331, 60481, 182431}},
+{18750, 18, 89952, {1, 3, 1, 15, 25, 57, 47, 85, 485, 11, 1669, 995, 6939, 4125, 19513, 62397, 62645, 82213}},
+{18751, 18, 89964, {1, 1, 1, 11, 1, 37, 101, 157, 17, 261, 997, 817, 2195, 4141, 10505, 60685, 98165, 167391}},
+{18752, 18, 89969, {1, 1, 1, 1, 31, 9, 103, 97, 161, 13, 1043, 307, 7321, 671, 12417, 58661, 23031, 207833}},
+{18753, 18, 89979, {1, 1, 7, 9, 15, 49, 69, 117, 93, 95, 507, 393, 6169, 2111, 27179, 47217, 93699, 67315}},
+{18754, 18, 90009, {1, 3, 7, 1, 23, 41, 115, 125, 343, 615, 397, 1199, 3041, 11019, 1071, 51069, 75757, 245765}},
+{18755, 18, 90022, {1, 1, 1, 13, 7, 15, 111, 239, 29, 419, 203, 2395, 3995, 13, 32341, 17471, 53259, 3317}},
+{18756, 18, 90031, {1, 3, 1, 11, 29, 27, 15, 217, 17, 163, 1847, 3549, 4911, 4539, 4927, 57157, 44893, 41669}},
+{18757, 18, 90043, {1, 1, 7, 7, 25, 15, 101, 149, 433, 717, 1827, 3837, 4565, 14521, 28857, 27775, 117429, 136131}},
+{18758, 18, 90045, {1, 1, 1, 3, 25, 35, 85, 3, 381, 253, 375, 3967, 3101, 12727, 31739, 48885, 35821, 92229}},
+{18759, 18, 90068, {1, 3, 3, 7, 29, 5, 51, 157, 67, 467, 1957, 3453, 1353, 4839, 25379, 42731, 109385, 52479}},
+{18760, 18, 90071, {1, 3, 7, 13, 3, 55, 61, 73, 257, 313, 89, 2557, 7467, 2223, 2951, 49265, 126605, 72007}},
+{18761, 18, 90082, {1, 3, 7, 5, 5, 11, 83, 3, 347, 63, 479, 529, 5059, 7029, 20523, 58387, 44891, 168921}},
+{18762, 18, 90087, {1, 3, 1, 11, 3, 51, 99, 5, 161, 279, 1509, 3659, 3107, 13925, 5117, 46153, 48731, 69767}},
+{18763, 18, 90117, {1, 1, 5, 5, 3, 53, 49, 243, 383, 401, 1205, 975, 3305, 12769, 25533, 28733, 115161, 160885}},
+{18764, 18, 90127, {1, 1, 1, 7, 15, 5, 43, 143, 493, 527, 1625, 2115, 3929, 12425, 16127, 25045, 55973, 202359}},
+{18765, 18, 90163, {1, 3, 7, 7, 11, 9, 69, 79, 417, 941, 473, 1655, 5763, 9889, 22443, 12153, 103489, 74737}},
+{18766, 18, 90166, {1, 1, 7, 9, 27, 31, 97, 253, 199, 99, 1955, 1481, 2509, 11923, 6337, 15899, 122515, 244721}},
+{18767, 18, 90177, {1, 1, 5, 13, 29, 15, 35, 177, 261, 613, 1279, 2837, 2945, 4501, 22865, 36893, 51979, 245569}},
+{18768, 18, 90211, {1, 1, 5, 9, 21, 5, 85, 5, 303, 165, 681, 3965, 2575, 1493, 10367, 55845, 92139, 92539}},
+{18769, 18, 90218, {1, 3, 5, 1, 23, 49, 49, 161, 481, 181, 1991, 1845, 4541, 14187, 10893, 64931, 79943, 57907}},
+{18770, 18, 90225, {1, 3, 1, 5, 11, 27, 19, 193, 371, 463, 1573, 271, 1127, 15091, 9967, 40337, 104163, 159339}},
+{18771, 18, 90231, {1, 3, 1, 3, 13, 3, 57, 149, 465, 789, 1155, 2223, 2007, 13987, 19057, 40447, 5217, 86191}},
+{18772, 18, 90235, {1, 3, 5, 5, 9, 45, 27, 155, 95, 171, 489, 2539, 843, 16125, 7047, 58541, 84641, 212013}},
+{18773, 18, 90289, {1, 3, 5, 13, 13, 53, 101, 159, 7, 481, 143, 3869, 6629, 3527, 1555, 6019, 155, 230157}},
+{18774, 18, 90344, {1, 3, 1, 1, 19, 59, 59, 129, 107, 887, 1595, 93, 6577, 3947, 14409, 31081, 68595, 226741}},
+{18775, 18, 90347, {1, 3, 3, 11, 13, 49, 81, 253, 363, 875, 489, 2181, 3487, 1615, 31157, 32949, 44809, 119421}},
+{18776, 18, 90379, {1, 1, 3, 1, 3, 19, 71, 93, 397, 521, 2015, 3829, 3013, 3941, 29437, 1959, 70283, 254361}},
+{18777, 18, 90387, {1, 3, 1, 3, 27, 11, 95, 39, 299, 521, 389, 3451, 3047, 8637, 22537, 11279, 67407, 101511}},
+{18778, 18, 90418, {1, 3, 1, 1, 27, 43, 123, 237, 315, 503, 1059, 2185, 3963, 1593, 19157, 13909, 58025, 91649}},
+{18779, 18, 90435, {1, 1, 7, 1, 5, 19, 79, 109, 459, 541, 521, 89, 389, 13499, 9769, 1429, 117357, 153261}},
+{18780, 18, 90444, {1, 1, 5, 3, 9, 29, 21, 97, 219, 915, 2013, 1955, 1015, 549, 9777, 5005, 110953, 16915}},
+{18781, 18, 90472, {1, 1, 1, 9, 29, 11, 103, 167, 465, 515, 843, 151, 769, 12033, 9451, 14949, 110075, 113947}},
+{18782, 18, 90478, {1, 3, 5, 1, 21, 1, 105, 49, 35, 737, 231, 2761, 1519, 9997, 601, 20883, 42575, 98081}},
+{18783, 18, 90485, {1, 1, 1, 5, 13, 63, 47, 171, 187, 407, 643, 1423, 6325, 10079, 23781, 36353, 20655, 10231}},
+{18784, 18, 90486, {1, 1, 7, 13, 13, 13, 91, 31, 19, 305, 505, 1937, 2683, 10791, 7719, 54797, 9405, 195819}},
+{18785, 18, 90513, {1, 1, 1, 7, 17, 9, 21, 211, 85, 851, 211, 1533, 4035, 11, 26873, 16755, 77809, 44603}},
+{18786, 18, 90514, {1, 1, 3, 1, 29, 47, 31, 141, 9, 881, 1229, 1261, 3747, 4603, 22177, 48937, 21435, 157029}},
+{18787, 18, 90532, {1, 1, 1, 9, 11, 35, 109, 187, 319, 863, 1339, 2193, 4147, 3721, 7243, 18295, 92461, 88875}},
+{18788, 18, 90567, {1, 1, 1, 1, 25, 41, 79, 191, 47, 819, 2013, 3133, 2763, 9231, 10343, 49693, 26753, 97465}},
+{18789, 18, 90595, {1, 3, 1, 3, 17, 25, 63, 139, 179, 113, 1681, 1997, 4561, 14453, 30721, 7053, 22937, 183303}},
+{18790, 18, 90597, {1, 1, 7, 3, 29, 11, 41, 157, 427, 887, 295, 443, 5593, 8633, 9757, 37595, 121655, 135739}},
+{18791, 18, 90621, {1, 3, 1, 7, 29, 5, 23, 231, 85, 67, 103, 1395, 7821, 9551, 17019, 1825, 69963, 254583}},
+{18792, 18, 90631, {1, 1, 7, 9, 7, 23, 7, 205, 17, 111, 1219, 3101, 7485, 11579, 11791, 10203, 119835, 175985}},
+{18793, 18, 90668, {1, 3, 3, 13, 3, 57, 101, 255, 331, 911, 491, 3929, 2519, 2185, 21107, 24599, 92831, 75001}},
+{18794, 18, 90706, {1, 3, 7, 1, 23, 53, 69, 229, 295, 881, 905, 3727, 3885, 7967, 2061, 53595, 16033, 36443}},
+{18795, 18, 90708, {1, 1, 7, 15, 21, 1, 127, 115, 191, 53, 929, 1093, 5447, 1665, 4409, 22611, 38157, 139201}},
+{18796, 18, 90715, {1, 3, 3, 13, 29, 31, 113, 215, 365, 41, 1977, 2839, 4147, 8321, 1361, 45717, 80505, 176631}},
+{18797, 18, 90724, {1, 3, 5, 3, 3, 57, 25, 81, 41, 229, 669, 3371, 7505, 1197, 14921, 34365, 67571, 27355}},
+{18798, 18, 90769, {1, 3, 7, 9, 17, 35, 7, 169, 13, 163, 2007, 3697, 5635, 8003, 26105, 62917, 19349, 47029}},
+{18799, 18, 90791, {1, 1, 5, 5, 29, 27, 89, 137, 69, 189, 871, 3139, 6383, 14955, 15349, 60447, 122291, 26541}},
+{18800, 18, 90792, {1, 1, 7, 13, 27, 49, 115, 111, 441, 865, 1397, 161, 755, 14461, 8601, 45533, 105309, 149799}},
+{18801, 18, 90805, {1, 1, 7, 3, 9, 29, 91, 5, 239, 605, 491, 1705, 4099, 9111, 19821, 56903, 62815, 40615}},
+{18802, 18, 90810, {1, 1, 7, 15, 5, 45, 71, 225, 211, 539, 1881, 1201, 5675, 6061, 12121, 13289, 30455, 33131}},
+{18803, 18, 90820, {1, 1, 5, 15, 5, 59, 35, 121, 185, 143, 165, 2999, 7907, 5035, 8337, 11951, 66403, 219997}},
+{18804, 18, 90844, {1, 1, 5, 9, 3, 7, 27, 129, 245, 93, 715, 1249, 1717, 13381, 31255, 23153, 22227, 8077}},
+{18805, 18, 90907, {1, 3, 5, 11, 19, 49, 21, 163, 157, 615, 1475, 2453, 6315, 12325, 26565, 58399, 49385, 252127}},
+{18806, 18, 90925, {1, 3, 7, 11, 23, 3, 35, 61, 409, 795, 1447, 3461, 535, 6533, 25757, 31783, 9509, 217589}},
+{18807, 18, 90926, {1, 1, 5, 15, 9, 21, 67, 65, 399, 515, 777, 3183, 1155, 16071, 7339, 59985, 56659, 200701}},
+{18808, 18, 90934, {1, 3, 3, 1, 15, 33, 119, 145, 71, 517, 1775, 163, 5307, 1549, 31071, 56289, 128395, 230381}},
+{18809, 18, 90946, {1, 3, 1, 7, 7, 47, 97, 187, 193, 887, 515, 1301, 4841, 12069, 413, 41503, 36421, 45909}},
+{18810, 18, 90981, {1, 1, 5, 3, 17, 21, 53, 227, 137, 865, 715, 3601, 5027, 2983, 24113, 23349, 106391, 188193}},
+{18811, 18, 90999, {1, 3, 7, 15, 29, 37, 91, 235, 351, 15, 425, 681, 187, 1517, 30079, 41347, 49691, 66369}},
+{18812, 18, 91003, {1, 1, 5, 5, 15, 25, 93, 245, 397, 517, 1635, 2475, 5543, 9597, 27721, 21475, 79571, 259011}},
+{18813, 18, 91019, {1, 1, 1, 5, 21, 29, 5, 161, 37, 409, 1661, 3371, 5663, 4317, 9951, 23605, 7393, 90593}},
+{18814, 18, 91022, {1, 1, 3, 15, 21, 51, 79, 159, 209, 891, 1391, 2895, 5003, 6601, 17983, 42359, 104497, 162181}},
+{18815, 18, 91050, {1, 3, 7, 11, 23, 51, 99, 145, 21, 345, 1389, 1035, 5939, 8293, 22765, 23331, 7789, 115149}},
+{18816, 18, 91055, {1, 1, 5, 11, 27, 61, 115, 123, 317, 607, 463, 779, 5121, 3861, 18761, 39407, 125837, 244163}},
+{18817, 18, 91064, {1, 1, 7, 3, 15, 9, 33, 1, 437, 621, 31, 147, 8157, 3451, 18223, 61187, 125297, 211225}},
+{18818, 18, 91078, {1, 3, 1, 11, 27, 55, 21, 251, 5, 57, 1889, 71, 3745, 499, 9043, 62683, 21945, 138615}},
+{18819, 18, 91117, {1, 1, 3, 13, 25, 9, 1, 31, 277, 373, 507, 301, 2341, 1741, 11997, 47661, 44121, 183151}},
+{18820, 18, 91120, {1, 3, 3, 5, 15, 51, 5, 233, 475, 397, 1833, 1267, 7025, 2593, 15425, 47053, 16205, 208007}},
+{18821, 18, 91129, {1, 3, 3, 9, 31, 51, 123, 219, 493, 789, 659, 985, 7283, 11545, 15383, 25173, 130423, 196619}},
+{18822, 18, 91140, {1, 1, 1, 15, 9, 17, 37, 145, 297, 933, 1019, 1699, 2149, 12391, 17003, 42157, 126283, 252231}},
+{18823, 18, 91157, {1, 3, 5, 9, 17, 1, 91, 69, 335, 857, 925, 3855, 2225, 6909, 19101, 12191, 92117, 229077}},
+{18824, 18, 91161, {1, 3, 5, 13, 5, 21, 67, 17, 307, 879, 1563, 3169, 745, 6799, 27237, 39621, 1413, 146295}},
+{18825, 18, 91240, {1, 3, 7, 13, 17, 59, 23, 253, 415, 761, 451, 2773, 3523, 10985, 29853, 7275, 79521, 133447}},
+{18826, 18, 91260, {1, 1, 1, 1, 15, 43, 89, 19, 85, 837, 1335, 1641, 105, 5429, 8317, 45555, 104447, 102313}},
+{18827, 18, 91270, {1, 3, 3, 5, 17, 21, 67, 235, 367, 265, 1069, 835, 5457, 177, 26987, 39477, 6895, 123283}},
+{18828, 18, 91287, {1, 1, 5, 15, 19, 61, 5, 15, 487, 291, 661, 825, 1569, 8795, 13035, 57077, 112847, 160267}},
+{18829, 18, 91321, {1, 1, 7, 9, 27, 21, 91, 133, 361, 7, 447, 3035, 3523, 13167, 15927, 35555, 35713, 91291}},
+{18830, 18, 91336, {1, 3, 7, 11, 17, 23, 77, 255, 437, 897, 1185, 1633, 6451, 13081, 29097, 61335, 39671, 177835}},
+{18831, 18, 91341, {1, 1, 7, 5, 31, 49, 81, 221, 167, 241, 1895, 1813, 1493, 2475, 379, 5685, 116341, 121823}},
+{18832, 18, 91378, {1, 3, 5, 9, 25, 11, 117, 253, 337, 381, 743, 69, 1641, 3649, 26335, 59683, 28729, 83449}},
+{18833, 18, 91398, {1, 3, 1, 7, 15, 17, 59, 9, 129, 233, 1905, 1371, 6521, 8953, 26173, 9707, 70817, 260035}},
+{18834, 18, 91437, {1, 3, 1, 5, 19, 53, 23, 255, 305, 835, 1387, 2947, 3013, 9117, 27571, 47123, 49881, 47229}},
+{18835, 18, 91440, {1, 1, 3, 5, 23, 37, 123, 193, 365, 49, 1211, 3083, 8133, 14205, 11361, 55945, 23225, 159109}},
+{18836, 18, 91475, {1, 1, 7, 11, 5, 49, 43, 165, 97, 581, 617, 3045, 6187, 8399, 24045, 46713, 28389, 156811}},
+{18837, 18, 91494, {1, 3, 1, 5, 29, 17, 75, 231, 59, 143, 2041, 2319, 2289, 11805, 4039, 29895, 91305, 179091}},
+{18838, 18, 91500, {1, 1, 7, 7, 29, 5, 13, 43, 409, 81, 751, 2157, 2543, 13317, 28275, 60871, 119833, 36743}},
+{18839, 18, 91511, {1, 1, 5, 13, 5, 5, 21, 101, 497, 993, 157, 647, 3587, 1495, 20233, 30889, 112579, 172009}},
+{18840, 18, 91567, {1, 1, 7, 13, 7, 19, 101, 217, 305, 897, 1305, 1693, 6881, 2415, 17373, 56327, 53971, 19021}},
+{18841, 18, 91572, {1, 1, 7, 15, 31, 61, 93, 99, 459, 999, 239, 969, 2427, 12295, 23699, 4839, 73707, 110365}},
+{18842, 18, 91601, {1, 3, 5, 9, 15, 59, 29, 35, 15, 331, 93, 529, 2651, 5675, 3039, 25967, 2907, 222053}},
+{18843, 18, 91617, {1, 3, 3, 1, 1, 17, 59, 81, 495, 917, 1907, 3, 1989, 14339, 21311, 60909, 39393, 54115}},
+{18844, 18, 91653, {1, 3, 1, 9, 1, 37, 31, 201, 251, 117, 1753, 2453, 5007, 6935, 1165, 49231, 51495, 200219}},
+{18845, 18, 91678, {1, 1, 3, 3, 15, 47, 17, 175, 77, 363, 1455, 1417, 1357, 2295, 31165, 53337, 97891, 145621}},
+{18846, 18, 91705, {1, 3, 3, 3, 27, 31, 41, 179, 47, 629, 5, 2543, 6817, 8953, 7151, 20715, 52363, 251037}},
+{18847, 18, 91723, {1, 3, 1, 1, 21, 11, 103, 87, 285, 189, 1911, 2979, 7563, 13405, 2309, 25695, 106277, 179493}},
+{18848, 18, 91725, {1, 1, 1, 5, 7, 19, 1, 233, 261, 825, 1071, 3529, 5617, 11207, 24559, 47461, 79753, 41009}},
+{18849, 18, 91733, {1, 1, 3, 1, 15, 35, 65, 157, 381, 509, 1455, 3117, 31, 2251, 29729, 33687, 74999, 214765}},
+{18850, 18, 91761, {1, 1, 7, 11, 31, 43, 11, 147, 509, 891, 1929, 357, 3905, 16251, 30169, 27787, 124003, 142587}},
+{18851, 18, 91768, {1, 1, 7, 11, 3, 31, 93, 161, 311, 377, 1119, 2177, 4339, 3889, 24299, 35167, 87583, 145611}},
+{18852, 18, 91790, {1, 1, 5, 9, 23, 9, 73, 85, 233, 919, 1319, 13, 3353, 1029, 31251, 17731, 86759, 11705}},
+{18853, 18, 91804, {1, 1, 1, 7, 27, 23, 67, 235, 207, 161, 697, 2433, 833, 5305, 32695, 29327, 25285, 51289}},
+{18854, 18, 91807, {1, 3, 3, 3, 31, 55, 107, 211, 61, 993, 1443, 463, 5029, 5401, 8821, 29721, 113939, 194839}},
+{18855, 18, 91808, {1, 1, 1, 11, 11, 33, 39, 167, 17, 863, 363, 3967, 2277, 4053, 15403, 31887, 98565, 217953}},
+{18856, 18, 91818, {1, 1, 7, 1, 21, 47, 97, 147, 155, 327, 1417, 3531, 7649, 8975, 21221, 57631, 72611, 97745}},
+{18857, 18, 91840, {1, 3, 3, 1, 1, 63, 19, 91, 105, 991, 819, 673, 7845, 14947, 1633, 40517, 91525, 151041}},
+{18858, 18, 91849, {1, 1, 7, 11, 25, 43, 57, 141, 65, 415, 1045, 3947, 7099, 11653, 29321, 51591, 2591, 44803}},
+{18859, 18, 91869, {1, 3, 1, 9, 15, 19, 105, 37, 485, 3, 213, 1217, 951, 5637, 1589, 25501, 95073, 124683}},
+{18860, 18, 91873, {1, 1, 5, 7, 13, 19, 55, 143, 507, 575, 715, 1633, 5201, 10493, 26041, 18407, 8097, 152313}},
+{18861, 18, 91876, {1, 1, 3, 5, 9, 51, 5, 171, 143, 877, 1571, 2997, 4209, 13423, 9389, 23015, 6665, 254799}},
+{18862, 18, 91888, {1, 3, 5, 15, 31, 43, 87, 79, 89, 463, 1075, 1257, 1631, 13225, 13529, 53267, 73651, 89125}},
+{18863, 18, 91891, {1, 3, 7, 13, 23, 17, 93, 113, 45, 225, 1939, 3301, 6031, 9749, 16577, 12857, 68437, 169861}},
+{18864, 18, 91897, {1, 3, 3, 15, 31, 11, 91, 127, 227, 813, 105, 901, 6861, 10627, 18425, 2553, 102503, 83167}},
+{18865, 18, 91911, {1, 3, 3, 13, 17, 63, 83, 163, 451, 659, 1995, 2283, 6297, 8097, 20935, 6017, 4977, 5045}},
+{18866, 18, 91965, {1, 1, 5, 13, 27, 47, 103, 129, 259, 975, 391, 2343, 6639, 1385, 30187, 35401, 74321, 24751}},
+{18867, 18, 91971, {1, 3, 1, 13, 1, 57, 37, 65, 57, 413, 63, 3819, 5915, 3925, 20777, 48539, 3019, 54965}},
+{18868, 18, 91988, {1, 1, 7, 3, 7, 13, 91, 33, 143, 489, 657, 3127, 707, 10841, 11307, 37855, 92697, 119189}},
+{18869, 18, 91992, {1, 1, 3, 11, 25, 47, 11, 57, 463, 693, 55, 501, 3765, 15443, 12917, 61677, 97145, 213637}},
+{18870, 18, 92004, {1, 3, 1, 1, 13, 49, 13, 225, 101, 475, 627, 1447, 7587, 11335, 3599, 20795, 72915, 174663}},
+{18871, 18, 92021, {1, 3, 7, 5, 31, 15, 115, 255, 329, 365, 959, 3399, 4695, 14537, 1447, 17391, 88557, 130213}},
+{18872, 18, 92035, {1, 1, 1, 9, 25, 47, 29, 173, 29, 149, 291, 691, 7621, 7607, 20769, 7149, 27323, 57689}},
+{18873, 18, 92068, {1, 3, 5, 15, 3, 61, 119, 247, 25, 495, 1297, 1119, 8011, 16077, 21567, 30559, 88455, 68763}},
+{18874, 18, 92098, {1, 1, 7, 1, 11, 47, 109, 115, 313, 517, 1951, 3319, 337, 11793, 22345, 33457, 47383, 213893}},
+{18875, 18, 92104, {1, 1, 5, 11, 11, 53, 103, 237, 383, 927, 421, 4085, 3327, 169, 9941, 24753, 65437, 108173}},
+{18876, 18, 92121, {1, 1, 5, 11, 17, 59, 107, 53, 479, 143, 825, 2667, 5219, 6143, 11573, 33637, 124981, 98195}},
+{18877, 18, 92127, {1, 3, 3, 13, 3, 17, 61, 129, 475, 585, 1611, 1791, 7817, 4099, 20437, 51411, 130173, 220085}},
+{18878, 18, 92151, {1, 3, 3, 3, 27, 25, 33, 255, 361, 967, 1415, 3213, 3341, 15875, 32359, 53267, 27665, 178301}},
+{18879, 18, 92162, {1, 1, 5, 3, 13, 9, 91, 187, 173, 525, 1675, 2217, 4093, 2009, 16917, 18485, 104849, 163233}},
+{18880, 18, 92186, {1, 1, 1, 11, 3, 17, 125, 157, 9, 429, 1573, 2257, 7943, 9893, 5611, 64619, 4509, 200181}},
+{18881, 18, 92191, {1, 3, 1, 1, 3, 9, 83, 53, 315, 85, 1093, 2621, 663, 12369, 317, 6089, 16479, 225071}},
+{18882, 18, 92192, {1, 3, 3, 1, 25, 47, 57, 45, 219, 45, 945, 3989, 4889, 8989, 381, 52483, 57029, 253899}},
+{18883, 18, 92207, {1, 3, 3, 5, 3, 61, 75, 189, 53, 489, 553, 2381, 7485, 9941, 29733, 2611, 74119, 203647}},
+{18884, 18, 92260, {1, 3, 1, 11, 27, 63, 53, 61, 59, 613, 465, 867, 1985, 7605, 14301, 53847, 68547, 14717}},
+{18885, 18, 92282, {1, 3, 5, 11, 5, 41, 51, 11, 59, 761, 59, 267, 7273, 3061, 11223, 48825, 117869, 158551}},
+{18886, 18, 92288, {1, 3, 7, 1, 31, 47, 111, 43, 435, 997, 135, 3369, 6439, 5637, 13629, 13221, 90607, 86359}},
+{18887, 18, 92297, {1, 1, 1, 11, 23, 51, 109, 223, 495, 765, 1557, 3545, 305, 4949, 23931, 45115, 12121, 14487}},
+{18888, 18, 92303, {1, 3, 5, 9, 5, 25, 41, 249, 27, 375, 1339, 3647, 3529, 2077, 21091, 45523, 67191, 1257}},
+{18889, 18, 92315, {1, 1, 3, 7, 13, 15, 63, 45, 187, 761, 1245, 3381, 1817, 2491, 16469, 64417, 87333, 143103}},
+{18890, 18, 92322, {1, 1, 3, 13, 11, 33, 87, 11, 279, 689, 1047, 3935, 5359, 11309, 19735, 33259, 12347, 183653}},
+{18891, 18, 92327, {1, 1, 5, 7, 5, 49, 109, 221, 455, 167, 785, 1859, 4337, 14937, 209, 23435, 22923, 172985}},
+{18892, 18, 92341, {1, 3, 7, 9, 13, 7, 127, 117, 147, 741, 531, 2627, 2565, 11083, 30577, 42471, 77065, 120983}},
+{18893, 18, 92389, {1, 1, 7, 1, 5, 61, 115, 203, 15, 305, 1005, 2085, 2597, 4371, 11661, 33219, 53657, 40325}},
+{18894, 18, 92390, {1, 3, 7, 13, 13, 15, 69, 167, 369, 747, 1115, 1493, 4881, 2693, 32281, 27089, 56821, 121693}},
+{18895, 18, 92422, {1, 3, 5, 3, 19, 51, 101, 29, 411, 509, 847, 1033, 4135, 15561, 7045, 60757, 48479, 247295}},
+{18896, 18, 92439, {1, 1, 5, 3, 27, 47, 103, 123, 413, 71, 689, 2113, 4347, 1983, 25727, 20095, 3271, 133081}},
+{18897, 18, 92452, {1, 1, 3, 3, 5, 39, 87, 27, 505, 631, 689, 2591, 1955, 3205, 12681, 10821, 13343, 101505}},
+{18898, 18, 92470, {1, 3, 7, 9, 31, 23, 103, 223, 499, 721, 13, 1399, 7369, 3945, 27727, 7923, 60265, 197793}},
+{18899, 18, 92473, {1, 3, 3, 5, 27, 7, 119, 23, 371, 495, 1583, 3913, 5139, 12151, 17477, 10907, 121775, 13369}},
+{18900, 18, 92493, {1, 3, 7, 1, 19, 53, 91, 235, 161, 97, 37, 1115, 5909, 1943, 8137, 1541, 16253, 252151}},
+{18901, 18, 92508, {1, 3, 7, 5, 3, 1, 107, 241, 187, 253, 1225, 2827, 4191, 2749, 25629, 47465, 19969, 45035}},
+{18902, 18, 92517, {1, 3, 1, 5, 1, 29, 47, 233, 175, 313, 793, 2089, 6235, 6595, 27599, 20505, 63379, 8729}},
+{18903, 18, 92529, {1, 3, 7, 11, 15, 9, 87, 113, 389, 1, 1057, 3307, 3455, 1847, 1497, 28115, 92897, 2383}},
+{18904, 18, 92551, {1, 3, 7, 13, 19, 59, 45, 59, 49, 273, 1619, 1975, 5949, 9951, 7685, 52559, 42377, 29855}},
+{18905, 18, 92557, {1, 1, 3, 9, 19, 7, 119, 35, 85, 37, 269, 3443, 8015, 8061, 6001, 19123, 70643, 115513}},
+{18906, 18, 92596, {1, 1, 3, 15, 3, 19, 83, 171, 259, 207, 1495, 513, 5455, 4071, 27471, 15773, 66301, 228743}},
+{18907, 18, 92611, {1, 3, 7, 9, 3, 27, 93, 3, 471, 13, 677, 4067, 1941, 15345, 26629, 29419, 121593, 108669}},
+{18908, 18, 92613, {1, 3, 7, 15, 29, 43, 97, 41, 15, 181, 1969, 1901, 7237, 3879, 19337, 17659, 17957, 164667}},
+{18909, 18, 92642, {1, 3, 1, 1, 25, 33, 7, 41, 387, 469, 795, 781, 113, 4161, 29687, 32225, 73905, 137879}},
+{18910, 18, 92666, {1, 1, 3, 13, 9, 59, 89, 23, 393, 111, 1957, 719, 6179, 16183, 31331, 48015, 32147, 31691}},
+{18911, 18, 92684, {1, 3, 7, 5, 9, 45, 73, 219, 181, 51, 717, 1813, 2581, 1395, 17595, 23689, 89709, 201451}},
+{18912, 18, 92723, {1, 3, 7, 3, 1, 21, 15, 35, 131, 515, 803, 1429, 3855, 349, 11795, 26787, 6109, 117745}},
+{18913, 18, 92732, {1, 3, 3, 9, 7, 11, 57, 15, 491, 371, 1787, 85, 577, 11455, 27419, 20687, 2493, 209993}},
+{18914, 18, 92738, {1, 3, 7, 15, 5, 5, 87, 197, 93, 643, 247, 31, 357, 7377, 10509, 29883, 42747, 248861}},
+{18915, 18, 92783, {1, 3, 3, 3, 29, 33, 47, 253, 485, 25, 2003, 2953, 1629, 11549, 5697, 1135, 117761, 96411}},
+{18916, 18, 92808, {1, 3, 5, 1, 29, 5, 27, 187, 235, 423, 41, 1855, 4359, 15627, 28409, 49331, 37735, 68823}},
+{18917, 18, 92816, {1, 1, 5, 5, 21, 61, 67, 85, 41, 671, 1617, 3867, 7913, 1693, 18487, 1831, 100971, 168191}},
+{18918, 18, 92835, {1, 1, 7, 3, 1, 61, 111, 87, 55, 229, 217, 2801, 563, 13617, 9641, 22247, 16039, 113541}},
+{18919, 18, 92847, {1, 3, 5, 7, 5, 29, 67, 99, 91, 561, 1203, 643, 2607, 13421, 29695, 31925, 82985, 69031}},
+{18920, 18, 92879, {1, 1, 1, 1, 27, 7, 63, 107, 269, 163, 1711, 587, 5657, 15077, 24709, 10235, 95483, 94799}},
+{18921, 18, 92881, {1, 3, 3, 5, 29, 5, 127, 137, 67, 609, 1657, 1131, 959, 15773, 17295, 58575, 96525, 80529}},
+{18922, 18, 92884, {1, 3, 7, 7, 25, 15, 89, 93, 145, 695, 367, 2853, 3073, 4867, 26823, 31467, 94769, 9145}},
+{18923, 18, 92932, {1, 1, 7, 15, 15, 5, 1, 225, 57, 381, 1295, 2525, 1493, 2401, 91, 19809, 32803, 195289}},
+{18924, 18, 92935, {1, 3, 3, 7, 29, 51, 29, 63, 249, 107, 1689, 3703, 7227, 6967, 27861, 39167, 20043, 218827}},
+{18925, 18, 92960, {1, 1, 3, 13, 17, 1, 77, 143, 167, 255, 1709, 2089, 7465, 4805, 16185, 15167, 20493, 240855}},
+{18926, 18, 92990, {1, 1, 5, 1, 11, 43, 107, 175, 93, 955, 615, 2923, 3637, 7451, 18847, 53467, 12463, 127249}},
+{18927, 18, 93010, {1, 1, 3, 13, 31, 1, 61, 113, 479, 777, 1805, 3625, 6299, 12221, 29599, 60175, 31165, 122815}},
+{18928, 18, 93025, {1, 3, 3, 11, 11, 29, 89, 129, 195, 337, 1843, 2769, 1747, 7137, 9901, 18459, 25215, 70609}},
+{18929, 18, 93046, {1, 1, 3, 7, 17, 35, 55, 81, 413, 25, 1505, 2185, 3121, 11435, 17885, 12543, 36767, 64039}},
+{18930, 18, 93085, {1, 3, 1, 13, 25, 9, 83, 25, 5, 49, 1975, 3967, 4135, 13213, 26479, 63913, 14921, 96193}},
+{18931, 18, 93089, {1, 3, 7, 5, 17, 15, 101, 47, 245, 821, 1275, 3343, 5471, 5045, 31741, 3319, 8141, 95501}},
+{18932, 18, 93096, {1, 3, 1, 13, 1, 5, 105, 39, 175, 439, 1625, 249, 4859, 12449, 30529, 45669, 49071, 214037}},
+{18933, 18, 93145, {1, 1, 7, 7, 17, 21, 83, 123, 261, 559, 1967, 2933, 4417, 8331, 10119, 21793, 128729, 187247}},
+{18934, 18, 93155, {1, 1, 7, 9, 15, 43, 77, 231, 241, 419, 503, 3335, 927, 2567, 31259, 52453, 114441, 257449}},
+{18935, 18, 93169, {1, 3, 3, 1, 9, 29, 21, 89, 311, 185, 519, 271, 3595, 8951, 6105, 64593, 38209, 120491}},
+{18936, 18, 93179, {1, 1, 7, 9, 1, 57, 65, 5, 275, 615, 801, 2839, 2851, 15609, 28731, 31223, 87725, 437}},
+{18937, 18, 93184, {1, 3, 3, 5, 29, 3, 67, 53, 17, 499, 263, 651, 7963, 5371, 11593, 34761, 57427, 84979}},
+{18938, 18, 93204, {1, 3, 7, 11, 15, 9, 33, 165, 313, 659, 909, 969, 2309, 2197, 27263, 35273, 52887, 236107}},
+{18939, 18, 93211, {1, 1, 7, 1, 13, 17, 29, 3, 329, 573, 619, 1013, 6947, 7031, 30773, 41129, 116481, 184233}},
+{18940, 18, 93213, {1, 1, 5, 9, 13, 5, 87, 235, 63, 759, 1143, 1861, 3783, 2735, 26191, 64387, 3651, 119447}},
+{18941, 18, 93227, {1, 1, 3, 7, 15, 41, 117, 135, 273, 655, 251, 1859, 4363, 14725, 29385, 6269, 91505, 82679}},
+{18942, 18, 93285, {1, 3, 7, 3, 13, 21, 21, 9, 121, 899, 199, 1973, 7437, 9771, 26647, 30909, 118573, 152913}},
+{18943, 18, 93292, {1, 3, 3, 9, 31, 43, 5, 249, 109, 183, 161, 1185, 4025, 10331, 20983, 28549, 122687, 183429}},
+{18944, 18, 93320, {1, 3, 7, 7, 11, 45, 111, 99, 487, 971, 597, 1555, 273, 10403, 25289, 45483, 35845, 35791}},
+{18945, 18, 93356, {1, 1, 1, 7, 11, 49, 125, 229, 279, 289, 1945, 3575, 5683, 15659, 31123, 12517, 79303, 255797}},
+{18946, 18, 93371, {1, 3, 1, 15, 9, 23, 61, 53, 383, 855, 1743, 407, 4401, 7507, 26307, 56205, 110943, 184183}},
+{18947, 18, 93374, {1, 3, 5, 13, 23, 29, 101, 243, 417, 925, 1267, 257, 5893, 4335, 6309, 43519, 126035, 99205}},
+{18948, 18, 93385, {1, 3, 1, 5, 5, 35, 83, 25, 31, 455, 1799, 2919, 7037, 11829, 12239, 12969, 108469, 89513}},
+{18949, 18, 93403, {1, 3, 5, 9, 17, 29, 61, 217, 183, 131, 425, 4025, 7141, 5445, 21497, 10603, 53423, 5701}},
+{18950, 18, 93406, {1, 1, 1, 15, 27, 35, 9, 139, 261, 43, 587, 3835, 4627, 11689, 15739, 6031, 73547, 134271}},
+{18951, 18, 93427, {1, 1, 3, 3, 25, 15, 7, 225, 29, 785, 2047, 2219, 6083, 7973, 17053, 56167, 83915, 87597}},
+{18952, 18, 93451, {1, 3, 7, 15, 13, 43, 85, 121, 421, 867, 1895, 2437, 6003, 5269, 8625, 26877, 100023, 110229}},
+{18953, 18, 93454, {1, 3, 3, 3, 25, 49, 121, 1, 125, 353, 1811, 1575, 3925, 13897, 26087, 24977, 105995, 242817}},
+{18954, 18, 93472, {1, 1, 1, 9, 31, 55, 71, 241, 439, 927, 955, 109, 7779, 2397, 18797, 34177, 1255, 178671}},
+{18955, 18, 93482, {1, 1, 7, 7, 5, 15, 99, 225, 49, 407, 1711, 4027, 4845, 9209, 20983, 33969, 14205, 9351}},
+{18956, 18, 93507, {1, 3, 5, 1, 9, 13, 113, 143, 97, 189, 929, 1163, 2261, 9761, 30011, 32911, 117043, 169493}},
+{18957, 18, 93537, {1, 1, 3, 5, 9, 35, 95, 77, 5, 95, 1745, 2013, 7009, 5427, 18969, 2771, 5099, 52939}},
+{18958, 18, 93562, {1, 3, 7, 9, 13, 19, 31, 189, 367, 569, 95, 1665, 6231, 2169, 22589, 8427, 116097, 41077}},
+{18959, 18, 93564, {1, 3, 7, 3, 31, 61, 45, 233, 327, 541, 87, 3449, 2767, 12237, 17747, 53827, 80389, 121489}},
+{18960, 18, 93608, {1, 3, 7, 15, 31, 1, 49, 73, 157, 131, 553, 3417, 5283, 4737, 31675, 63213, 43689, 261869}},
+{18961, 18, 93636, {1, 3, 7, 1, 3, 5, 113, 43, 343, 39, 135, 1555, 7955, 9851, 30983, 21955, 34871, 147649}},
+{18962, 18, 93640, {1, 3, 5, 3, 5, 27, 15, 179, 141, 983, 265, 2651, 5907, 10501, 6275, 29629, 115965, 125745}},
+{18963, 18, 93653, {1, 3, 7, 13, 1, 1, 81, 105, 309, 457, 1817, 3435, 4615, 1181, 27835, 26075, 63447, 44701}},
+{18964, 18, 93654, {1, 1, 5, 5, 25, 19, 85, 103, 409, 323, 2001, 3719, 3403, 1301, 19615, 47829, 109905, 65777}},
+{18965, 18, 93664, {1, 3, 5, 3, 21, 15, 47, 75, 467, 273, 1885, 3929, 1877, 5209, 6881, 34431, 35663, 100205}},
+{18966, 18, 93676, {1, 1, 5, 3, 3, 9, 47, 143, 471, 653, 1011, 2263, 3673, 11921, 31207, 50365, 27177, 214377}},
+{18967, 18, 93721, {1, 3, 1, 15, 3, 43, 81, 253, 495, 139, 679, 2207, 4603, 5269, 27133, 46461, 120783, 185595}},
+{18968, 18, 93740, {1, 1, 7, 3, 13, 3, 109, 197, 477, 101, 859, 1035, 777, 10153, 15581, 22715, 17493, 120851}},
+{18969, 18, 93743, {1, 3, 1, 3, 23, 5, 121, 67, 265, 935, 741, 3311, 541, 1093, 1639, 5941, 5587, 150345}},
+{18970, 18, 93745, {1, 3, 1, 5, 3, 13, 65, 173, 493, 303, 359, 3813, 6007, 1105, 12185, 10431, 17117, 164899}},
+{18971, 18, 93751, {1, 3, 3, 1, 25, 33, 71, 181, 149, 7, 333, 1981, 2981, 14683, 10997, 63373, 22605, 119681}},
+{18972, 18, 93770, {1, 1, 1, 15, 29, 35, 89, 21, 281, 175, 587, 3117, 7221, 8239, 26399, 49133, 65895, 142175}},
+{18973, 18, 93796, {1, 3, 7, 15, 9, 9, 35, 161, 65, 749, 421, 3575, 6307, 2029, 11423, 63901, 102049, 26333}},
+{18974, 18, 93820, {1, 3, 1, 13, 1, 45, 97, 41, 231, 245, 271, 1497, 3119, 6225, 21665, 12113, 67315, 62779}},
+{18975, 18, 93824, {1, 1, 1, 7, 3, 29, 119, 193, 179, 353, 1015, 2803, 6869, 7653, 22309, 53421, 86969, 115549}},
+{18976, 18, 93833, {1, 3, 3, 5, 17, 37, 49, 129, 195, 537, 1237, 2775, 6683, 699, 19181, 61125, 27483, 175645}},
+{18977, 18, 93841, {1, 3, 7, 3, 7, 49, 107, 41, 285, 335, 1415, 4015, 1301, 6525, 32429, 9337, 87923, 176751}},
+{18978, 18, 93847, {1, 1, 5, 9, 21, 43, 91, 25, 225, 311, 417, 303, 2629, 3609, 29987, 28647, 104173, 52383}},
+{18979, 18, 93848, {1, 3, 5, 9, 13, 47, 75, 143, 109, 173, 503, 3843, 1767, 9433, 10009, 5653, 87339, 212975}},
+{18980, 18, 93854, {1, 3, 1, 13, 13, 55, 123, 95, 499, 245, 1875, 3661, 7661, 6927, 21003, 51729, 88089, 89063}},
+{18981, 18, 93882, {1, 1, 3, 1, 31, 7, 93, 35, 169, 191, 1079, 2137, 4401, 1563, 20021, 9101, 66881, 231589}},
+{18982, 18, 93943, {1, 3, 1, 15, 21, 41, 75, 231, 459, 701, 1715, 2581, 4445, 5877, 4765, 1037, 15827, 189529}},
+{18983, 18, 93958, {1, 3, 5, 13, 17, 23, 41, 133, 143, 297, 1335, 3907, 7745, 5139, 9397, 5765, 5347, 243091}},
+{18984, 18, 93972, {1, 1, 5, 13, 7, 15, 31, 183, 315, 153, 785, 2723, 97, 14361, 10509, 17717, 46615, 133289}},
+{18985, 18, 93975, {1, 3, 7, 9, 13, 3, 75, 103, 445, 409, 603, 201, 1873, 9277, 23953, 6881, 64327, 196771}},
+{18986, 18, 94003, {1, 1, 7, 13, 15, 21, 73, 183, 419, 997, 857, 1373, 3855, 417, 10175, 5253, 66509, 15731}},
+{18987, 18, 94009, {1, 3, 3, 9, 19, 7, 15, 119, 497, 25, 1165, 105, 2605, 15097, 28241, 2269, 519, 235655}},
+{18988, 18, 94020, {1, 3, 3, 9, 27, 9, 103, 205, 97, 317, 1621, 971, 931, 9099, 24583, 12695, 122399, 78021}},
+{18989, 18, 94072, {1, 1, 3, 5, 27, 45, 41, 239, 87, 603, 317, 3507, 7677, 9141, 26721, 40225, 80515, 205263}},
+{18990, 18, 94081, {1, 1, 3, 1, 25, 3, 63, 165, 41, 783, 291, 1997, 3769, 1881, 30613, 18821, 86175, 38837}},
+{18991, 18, 94093, {1, 1, 3, 5, 17, 19, 95, 17, 357, 587, 689, 3127, 6999, 6703, 23923, 55945, 97629, 210177}},
+{18992, 18, 94102, {1, 1, 3, 15, 21, 55, 63, 229, 397, 1007, 779, 2105, 681, 10659, 26679, 681, 115901, 83627}},
+{18993, 18, 94122, {1, 1, 7, 11, 25, 9, 47, 133, 109, 17, 697, 749, 5529, 9289, 29675, 2631, 15247, 13913}},
+{18994, 18, 94135, {1, 1, 7, 7, 3, 55, 29, 13, 467, 889, 675, 1187, 3301, 13721, 13783, 44559, 78177, 114219}},
+{18995, 18, 94136, {1, 3, 5, 13, 15, 11, 77, 71, 313, 427, 1385, 2007, 4003, 1529, 4797, 12289, 24897, 129513}},
+{18996, 18, 94150, {1, 1, 3, 11, 9, 47, 103, 253, 345, 659, 1109, 3493, 2515, 5669, 30551, 25077, 97393, 252689}},
+{18997, 18, 94184, {1, 3, 7, 9, 25, 19, 69, 161, 365, 51, 1365, 1045, 4319, 10035, 15529, 23251, 44359, 62163}},
+{18998, 18, 94187, {1, 3, 1, 7, 3, 25, 119, 33, 19, 561, 659, 2741, 6177, 899, 30911, 9627, 83003, 12939}},
+{18999, 18, 94258, {1, 3, 7, 1, 13, 37, 19, 161, 427, 621, 1045, 1963, 6067, 4439, 32507, 32775, 5201, 144645}},
+{19000, 18, 94264, {1, 1, 5, 7, 31, 17, 89, 239, 317, 109, 1827, 1395, 1587, 14813, 29911, 63545, 22939, 235383}},
+{19001, 18, 94272, {1, 1, 7, 15, 1, 17, 41, 123, 405, 539, 1063, 1443, 4611, 1847, 24107, 29365, 85859, 218601}},
+{19002, 18, 94278, {1, 1, 5, 13, 21, 27, 101, 223, 245, 705, 1579, 679, 5461, 8955, 15031, 7731, 31219, 165033}},
+{19003, 18, 94281, {1, 1, 7, 11, 19, 29, 13, 223, 179, 481, 761, 1543, 3195, 10695, 17147, 37577, 130901, 44699}},
+{19004, 18, 94317, {1, 1, 7, 3, 19, 53, 49, 1, 393, 583, 1183, 2817, 1293, 12949, 15491, 44467, 86261, 220439}},
+{19005, 18, 94348, {1, 3, 7, 15, 15, 47, 7, 125, 467, 511, 1207, 3787, 5575, 5359, 3859, 29933, 104627, 243073}},
+{19006, 18, 94376, {1, 1, 1, 13, 27, 25, 17, 243, 477, 457, 1835, 2859, 1023, 10107, 26829, 49853, 114569, 250471}},
+{19007, 18, 94382, {1, 3, 1, 15, 11, 43, 15, 235, 431, 671, 1935, 1143, 4121, 15403, 19313, 15919, 111961, 50455}},
+{19008, 18, 94387, {1, 3, 3, 3, 11, 45, 107, 143, 353, 671, 1259, 1599, 6075, 10645, 9131, 28133, 58679, 29883}},
+{19009, 18, 94389, {1, 3, 5, 15, 15, 43, 29, 171, 303, 71, 1751, 411, 7615, 12063, 26829, 31469, 34335, 3163}},
+{19010, 18, 94393, {1, 1, 7, 7, 25, 63, 25, 25, 27, 671, 505, 1235, 1985, 2593, 30031, 3251, 94729, 248911}},
+{19011, 18, 94402, {1, 1, 3, 1, 19, 15, 125, 133, 133, 209, 1749, 2091, 6325, 1275, 5675, 2249, 22631, 56293}},
+{19012, 18, 94421, {1, 1, 5, 1, 19, 27, 25, 99, 211, 739, 565, 3903, 7701, 7547, 12303, 5421, 24663, 22807}},
+{19013, 18, 94422, {1, 3, 5, 13, 5, 45, 99, 67, 21, 269, 851, 3333, 4555, 12483, 14645, 44757, 99047, 198521}},
+{19014, 18, 94431, {1, 1, 5, 13, 19, 1, 123, 87, 109, 799, 591, 2997, 1005, 16369, 10329, 34541, 100935, 200397}},
+{19015, 18, 94473, {1, 3, 5, 1, 13, 51, 93, 23, 19, 23, 965, 171, 6865, 3561, 23255, 44295, 87405, 222269}},
+{19016, 18, 94487, {1, 1, 3, 5, 1, 53, 25, 129, 123, 737, 271, 61, 113, 8481, 27075, 58633, 21499, 156689}},
+{19017, 18, 94504, {1, 3, 3, 11, 3, 43, 11, 123, 243, 1015, 1389, 3663, 1725, 6933, 5315, 7137, 127705, 56607}},
+{19018, 18, 94510, {1, 1, 5, 13, 7, 23, 43, 103, 503, 173, 267, 1509, 3311, 9553, 28851, 15771, 28741, 236427}},
+{19019, 18, 94522, {1, 1, 5, 15, 27, 43, 119, 3, 13, 107, 317, 3725, 6669, 4945, 30485, 10155, 96893, 154081}},
+{19020, 18, 94532, {1, 3, 7, 5, 11, 21, 61, 99, 155, 45, 569, 1325, 673, 15803, 12047, 55431, 9515, 106969}},
+{19021, 18, 94572, {1, 1, 7, 11, 27, 49, 121, 145, 105, 223, 1471, 1163, 3889, 4213, 21195, 45649, 14663, 82799}},
+{19022, 18, 94589, {1, 1, 3, 3, 31, 21, 17, 85, 31, 695, 1591, 2465, 907, 11621, 29681, 13131, 77187, 175913}},
+{19023, 18, 94599, {1, 3, 5, 5, 21, 49, 77, 229, 359, 825, 1851, 1223, 3351, 5349, 30971, 20797, 26975, 94425}},
+{19024, 18, 94603, {1, 1, 3, 1, 3, 63, 23, 219, 503, 47, 1675, 1641, 5257, 8035, 29793, 30093, 44897, 235691}},
+{19025, 18, 94647, {1, 1, 7, 9, 27, 37, 109, 33, 511, 203, 1195, 3281, 407, 15237, 28485, 21379, 106325, 231755}},
+{19026, 18, 94665, {1, 3, 1, 3, 9, 45, 19, 31, 255, 799, 909, 767, 421, 3301, 18557, 15043, 48505, 36763}},
+{19027, 18, 94695, {1, 3, 7, 13, 1, 45, 59, 233, 319, 265, 517, 1571, 4593, 12813, 30729, 19517, 70345, 142411}},
+{19028, 18, 94716, {1, 1, 1, 13, 17, 15, 79, 93, 265, 381, 285, 253, 919, 3715, 30555, 38801, 30439, 51511}},
+{19029, 18, 94738, {1, 1, 7, 15, 25, 39, 71, 57, 145, 487, 1655, 2589, 7655, 8413, 24537, 36761, 36427, 88929}},
+{19030, 18, 94740, {1, 1, 3, 3, 29, 41, 61, 191, 97, 849, 911, 3269, 5425, 13997, 7749, 537, 113705, 179765}},
+{19031, 18, 94778, {1, 1, 5, 9, 13, 55, 33, 221, 27, 521, 13, 2847, 6035, 8397, 6579, 29353, 101953, 88983}},
+{19032, 18, 94803, {1, 3, 3, 13, 31, 47, 97, 177, 373, 353, 159, 249, 4741, 7427, 8353, 38617, 13857, 122081}},
+{19033, 18, 94810, {1, 3, 5, 15, 13, 21, 1, 239, 369, 253, 1009, 1927, 5111, 2219, 28167, 32013, 51487, 210521}},
+{19034, 18, 94815, {1, 3, 5, 9, 17, 21, 37, 105, 405, 39, 321, 1515, 3759, 15469, 13643, 60157, 72127, 233505}},
+{19035, 18, 94821, {1, 3, 7, 5, 1, 3, 3, 125, 283, 757, 829, 2303, 3715, 6027, 17795, 37359, 54721, 5891}},
+{19036, 18, 94862, {1, 3, 7, 15, 27, 63, 117, 101, 341, 965, 1543, 51, 3397, 14051, 9889, 64647, 111169, 249477}},
+{19037, 18, 94886, {1, 1, 5, 13, 5, 29, 51, 61, 233, 685, 751, 163, 2319, 14691, 29881, 39029, 57093, 240147}},
+{19038, 18, 94900, {1, 3, 5, 3, 9, 21, 107, 147, 263, 471, 621, 3485, 197, 13271, 24689, 64341, 110163, 142711}},
+{19039, 18, 94924, {1, 3, 1, 7, 1, 23, 17, 31, 131, 631, 795, 3751, 5337, 9151, 2873, 31113, 65303, 244969}},
+{19040, 18, 94952, {1, 1, 5, 11, 3, 51, 93, 155, 389, 859, 1181, 2711, 1375, 6119, 229, 47767, 115521, 114129}},
+{19041, 18, 94963, {1, 3, 3, 15, 5, 7, 29, 187, 259, 911, 1537, 1885, 6139, 4549, 21655, 58771, 1003, 124609}},
+{19042, 18, 94970, {1, 1, 3, 15, 25, 45, 97, 217, 331, 305, 1105, 3465, 3651, 10171, 31601, 6947, 4545, 232627}},
+{19043, 18, 94980, {1, 1, 5, 5, 9, 53, 109, 201, 473, 201, 1113, 973, 1825, 13089, 1207, 9947, 92515, 216199}},
+{19044, 18, 94992, {1, 3, 7, 3, 1, 49, 25, 109, 249, 489, 1663, 3493, 4615, 13899, 27851, 60711, 14351, 41787}},
+{19045, 18, 95017, {1, 3, 3, 7, 3, 15, 29, 53, 61, 669, 371, 2187, 6769, 4623, 25785, 12997, 52263, 28387}},
+{19046, 18, 95028, {1, 1, 1, 3, 9, 31, 69, 3, 441, 219, 285, 183, 1971, 10903, 8271, 19389, 61913, 203537}},
+{19047, 18, 95031, {1, 1, 5, 3, 9, 63, 117, 131, 53, 525, 1349, 2701, 1317, 6047, 1661, 51785, 93199, 158645}},
+{19048, 18, 95035, {1, 3, 5, 3, 21, 61, 11, 91, 317, 635, 61, 1919, 2139, 12817, 6587, 63201, 52659, 8971}},
+{19049, 18, 95040, {1, 3, 1, 9, 11, 47, 49, 35, 115, 711, 511, 835, 3787, 837, 15737, 7467, 53263, 132047}},
+{19050, 18, 95058, {1, 1, 5, 3, 27, 47, 121, 211, 65, 363, 1067, 3813, 6353, 13701, 23943, 7573, 112721, 219587}},
+{19051, 18, 95079, {1, 1, 3, 7, 21, 39, 15, 199, 113, 517, 1429, 1399, 6007, 1389, 16425, 17709, 1231, 51803}},
+{19052, 18, 95122, {1, 3, 5, 11, 5, 37, 35, 97, 215, 281, 517, 1777, 4171, 10161, 18369, 23233, 83005, 75519}},
+{19053, 18, 95149, {1, 3, 7, 9, 3, 9, 69, 111, 135, 351, 971, 3551, 3739, 3571, 22861, 62669, 83723, 10707}},
+{19054, 18, 95150, {1, 3, 3, 5, 31, 35, 103, 205, 321, 553, 409, 363, 4085, 7735, 5513, 64249, 127883, 147839}},
+{19055, 18, 95167, {1, 1, 7, 3, 23, 35, 85, 231, 251, 237, 421, 757, 7081, 11247, 24941, 22649, 51111, 157383}},
+{19056, 18, 95175, {1, 3, 7, 5, 23, 35, 7, 101, 491, 529, 1437, 489, 5057, 12955, 27543, 60903, 104151, 42545}},
+{19057, 18, 95205, {1, 1, 3, 15, 23, 53, 85, 89, 247, 269, 1555, 3789, 467, 11145, 11751, 44343, 120117, 9975}},
+{19058, 18, 95229, {1, 1, 5, 3, 29, 49, 123, 179, 311, 45, 1839, 2725, 7307, 5525, 32075, 7979, 107751, 133677}},
+{19059, 18, 95321, {1, 1, 5, 3, 31, 21, 65, 229, 31, 597, 755, 2653, 2699, 2075, 11693, 28953, 55811, 13653}},
+{19060, 18, 95345, {1, 1, 1, 7, 25, 51, 119, 21, 245, 493, 407, 2997, 4255, 15487, 26359, 24153, 42955, 142191}},
+{19061, 18, 95364, {1, 1, 5, 3, 27, 61, 13, 209, 13, 401, 399, 2909, 3623, 8057, 21301, 32273, 112127, 210221}},
+{19062, 18, 95379, {1, 3, 5, 13, 3, 19, 121, 19, 57, 583, 947, 3591, 5283, 10831, 20429, 54097, 7559, 112465}},
+{19063, 18, 95386, {1, 3, 5, 1, 21, 1, 125, 245, 217, 165, 1319, 2119, 4641, 9481, 4147, 7079, 119015, 128401}},
+{19064, 18, 95395, {1, 1, 5, 3, 3, 31, 25, 63, 17, 191, 497, 819, 1515, 11215, 24961, 7679, 125801, 239521}},
+{19065, 18, 95416, {1, 1, 5, 1, 3, 25, 27, 43, 37, 863, 739, 2585, 773, 799, 17649, 21171, 123541, 164777}},
+{19066, 18, 95419, {1, 3, 5, 7, 7, 25, 15, 251, 305, 159, 1941, 3655, 2881, 15123, 10911, 35541, 62221, 175845}},
+{19067, 18, 95433, {1, 1, 1, 9, 19, 5, 103, 1, 417, 951, 139, 2413, 2983, 15471, 9495, 41349, 110175, 29501}},
+{19068, 18, 95464, {1, 1, 1, 5, 29, 53, 95, 173, 211, 803, 1599, 4093, 5559, 15855, 12271, 12583, 102221, 203453}},
+{19069, 18, 95490, {1, 3, 5, 5, 19, 43, 31, 175, 493, 289, 1865, 2925, 3833, 11327, 23337, 62669, 99485, 230583}},
+{19070, 18, 95496, {1, 3, 3, 11, 11, 25, 95, 215, 501, 421, 725, 1571, 2133, 2761, 8649, 45359, 88851, 55057}},
+{19071, 18, 95504, {1, 1, 7, 7, 21, 45, 69, 63, 399, 929, 1431, 3397, 3613, 14595, 10417, 62913, 106283, 120869}},
+{19072, 18, 95513, {1, 3, 7, 15, 13, 45, 11, 177, 125, 611, 1115, 2441, 2689, 12517, 8989, 34991, 23789, 51543}},
+{19073, 18, 95523, {1, 1, 3, 1, 3, 15, 5, 125, 511, 137, 1919, 2953, 5267, 3543, 5485, 7463, 130407, 255945}},
+{19074, 18, 95525, {1, 1, 3, 7, 7, 21, 95, 97, 51, 91, 813, 2819, 2839, 12041, 26197, 20143, 51403, 171337}},
+{19075, 18, 95558, {1, 1, 1, 1, 7, 27, 15, 125, 441, 387, 1869, 2157, 5863, 581, 893, 58827, 104063, 93735}},
+{19076, 18, 95572, {1, 3, 3, 7, 27, 9, 79, 97, 465, 207, 931, 2809, 2225, 13749, 18819, 30605, 9829, 130743}},
+{19077, 18, 95591, {1, 3, 5, 13, 31, 41, 19, 147, 293, 725, 297, 397, 1343, 12669, 15339, 58599, 12113, 149835}},
+{19078, 18, 95609, {1, 3, 3, 13, 27, 13, 121, 253, 349, 229, 915, 1673, 3819, 77, 20691, 53823, 78265, 138743}},
+{19079, 18, 95619, {1, 1, 5, 5, 29, 41, 65, 235, 123, 871, 1809, 3013, 3531, 1551, 8441, 23481, 58729, 117639}},
+{19080, 18, 95625, {1, 1, 7, 5, 23, 55, 89, 81, 201, 313, 1307, 2427, 2025, 8543, 26631, 58655, 122095, 247579}},
+{19081, 18, 95633, {1, 3, 1, 5, 3, 63, 89, 219, 449, 9, 1771, 2915, 5925, 13773, 26119, 61309, 65107, 33001}},
+{19082, 18, 95649, {1, 3, 7, 1, 27, 11, 25, 221, 139, 665, 1543, 2157, 7617, 9135, 567, 64985, 88749, 54223}},
+{19083, 18, 95652, {1, 1, 3, 9, 13, 41, 7, 99, 483, 115, 1499, 3343, 7207, 1805, 16031, 63707, 8555, 90959}},
+{19084, 18, 95655, {1, 3, 1, 9, 15, 53, 41, 239, 295, 47, 1645, 1095, 5163, 7739, 26635, 28245, 9315, 100629}},
+{19085, 18, 95696, {1, 3, 1, 5, 1, 19, 69, 5, 171, 669, 673, 633, 6895, 7571, 11539, 25133, 99235, 7991}},
+{19086, 18, 95721, {1, 3, 5, 11, 21, 37, 63, 77, 281, 307, 1711, 2671, 1315, 14683, 28757, 22751, 56477, 190805}},
+{19087, 18, 95766, {1, 3, 3, 5, 15, 1, 5, 21, 199, 161, 655, 1263, 3315, 16051, 2409, 773, 9075, 121265}},
+{19088, 18, 95772, {1, 3, 3, 3, 7, 23, 71, 195, 11, 263, 1845, 165, 3489, 447, 11315, 23861, 110949, 78909}},
+{19089, 18, 95775, {1, 1, 7, 5, 1, 53, 37, 9, 439, 135, 909, 457, 6993, 11401, 14065, 30795, 56149, 168013}},
+{19090, 18, 95794, {1, 1, 1, 15, 23, 37, 13, 87, 113, 251, 233, 725, 7757, 14399, 3023, 54277, 87879, 54053}},
+{19091, 18, 95796, {1, 3, 5, 11, 11, 57, 109, 171, 171, 17, 343, 2749, 6525, 9735, 11715, 23783, 54439, 82819}},
+{19092, 18, 95818, {1, 1, 1, 15, 3, 47, 73, 237, 399, 301, 947, 2055, 1909, 14105, 26893, 47805, 25, 172957}},
+{19093, 18, 95820, {1, 1, 7, 7, 11, 27, 93, 167, 117, 637, 351, 319, 4605, 12897, 31001, 39655, 53551, 246113}},
+{19094, 18, 95832, {1, 3, 5, 15, 3, 37, 25, 9, 421, 519, 257, 3251, 1649, 4069, 999, 59367, 112383, 32095}},
+{19095, 18, 95842, {1, 3, 7, 7, 25, 57, 11, 37, 271, 545, 1213, 1927, 6471, 5145, 22995, 51051, 126981, 260457}},
+{19096, 18, 95851, {1, 3, 5, 11, 1, 61, 77, 201, 395, 199, 477, 103, 4069, 7003, 26371, 49145, 103839, 195661}},
+{19097, 18, 95854, {1, 3, 3, 9, 13, 41, 25, 125, 161, 371, 179, 351, 7169, 7179, 21627, 57793, 104679, 158583}},
+{19098, 18, 95859, {1, 3, 7, 11, 5, 7, 111, 163, 201, 783, 189, 273, 2751, 13917, 28501, 18261, 12755, 15521}},
+{19099, 18, 95868, {1, 1, 5, 7, 3, 37, 121, 209, 503, 299, 1301, 3703, 2321, 99, 14953, 28087, 85059, 256911}},
+{19100, 18, 95881, {1, 3, 3, 13, 3, 29, 95, 249, 383, 971, 1291, 13, 1587, 3447, 26477, 15837, 111141, 73899}},
+{19101, 18, 95895, {1, 1, 7, 1, 17, 57, 31, 1, 219, 329, 19, 3841, 1829, 5179, 14945, 6625, 3783, 200583}},
+{19102, 18, 95943, {1, 3, 1, 3, 1, 31, 23, 17, 209, 383, 297, 3065, 4323, 7847, 30189, 56541, 57535, 24853}},
+{19103, 18, 95949, {1, 1, 3, 11, 31, 35, 125, 141, 251, 79, 161, 775, 2455, 6959, 26433, 39145, 26563, 665}},
+{19104, 18, 95978, {1, 1, 7, 1, 11, 9, 9, 211, 231, 723, 1337, 1713, 3779, 2001, 23451, 27107, 64297, 254943}},
+{19105, 18, 95980, {1, 3, 7, 15, 21, 55, 19, 159, 449, 837, 1259, 1851, 5061, 355, 21531, 63479, 114657, 139265}},
+{19106, 18, 96010, {1, 1, 1, 3, 11, 55, 103, 179, 363, 567, 421, 981, 7221, 2077, 19339, 1155, 67019, 218231}},
+{19107, 18, 96020, {1, 1, 7, 11, 3, 43, 55, 161, 347, 995, 1555, 3251, 1605, 13313, 4499, 19361, 60145, 71593}},
+{19108, 18, 96024, {1, 1, 5, 3, 9, 15, 119, 213, 455, 241, 857, 683, 1247, 13085, 23919, 20365, 16303, 73263}},
+{19109, 18, 96063, {1, 1, 3, 13, 25, 17, 45, 193, 375, 289, 1381, 3629, 3015, 15883, 20633, 7431, 108787, 233297}},
+{19110, 18, 96108, {1, 1, 1, 15, 21, 57, 105, 91, 233, 961, 1623, 3849, 711, 3857, 32657, 5935, 85113, 38287}},
+{19111, 18, 96125, {1, 3, 3, 3, 15, 31, 97, 217, 335, 385, 1661, 3927, 6849, 137, 28871, 56485, 32777, 260033}},
+{19112, 18, 96154, {1, 1, 3, 13, 5, 61, 19, 255, 123, 481, 1865, 1815, 3047, 173, 25363, 1277, 6453, 174405}},
+{19113, 18, 96172, {1, 3, 7, 13, 27, 9, 19, 21, 433, 857, 1931, 2927, 629, 7733, 13503, 48263, 67517, 26495}},
+{19114, 18, 96189, {1, 1, 1, 3, 5, 43, 61, 239, 81, 585, 187, 1123, 3319, 8699, 20925, 40815, 76575, 169383}},
+{19115, 18, 96204, {1, 3, 3, 3, 9, 49, 71, 225, 95, 365, 645, 237, 7829, 5727, 17031, 58971, 71415, 232423}},
+{19116, 18, 96219, {1, 3, 5, 9, 25, 49, 113, 47, 105, 609, 1557, 2099, 2129, 8663, 24811, 25505, 38153, 185821}},
+{19117, 18, 96256, {1, 3, 5, 13, 23, 55, 107, 17, 309, 807, 635, 1007, 6207, 3363, 7607, 25013, 4141, 171509}},
+{19118, 18, 96261, {1, 1, 1, 13, 27, 35, 31, 89, 109, 879, 1845, 3999, 5415, 8777, 9605, 29703, 28149, 36469}},
+{19119, 18, 96289, {1, 3, 1, 3, 13, 3, 51, 31, 479, 549, 1245, 2033, 961, 13893, 21829, 32791, 109497, 187425}},
+{19120, 18, 96292, {1, 1, 5, 3, 19, 5, 25, 187, 173, 869, 201, 3851, 7369, 6229, 16577, 45623, 19859, 209855}},
+{19121, 18, 96296, {1, 1, 7, 9, 1, 9, 53, 47, 289, 557, 999, 141, 3789, 3087, 30217, 24221, 81431, 157507}},
+{19122, 18, 96324, {1, 1, 3, 9, 1, 25, 11, 73, 155, 155, 621, 4047, 6759, 5641, 28147, 8523, 69439, 92613}},
+{19123, 18, 96345, {1, 3, 1, 5, 25, 23, 41, 79, 71, 793, 1381, 307, 7863, 16289, 28783, 5299, 128481, 222799}},
+{19124, 18, 96346, {1, 1, 7, 1, 17, 33, 117, 111, 15, 249, 1397, 1349, 4883, 6009, 3179, 33509, 56355, 31937}},
+{19125, 18, 96358, {1, 3, 5, 13, 29, 15, 41, 185, 91, 501, 571, 2889, 6901, 3875, 3737, 23657, 101587, 261181}},
+{19126, 18, 96386, {1, 1, 7, 9, 21, 49, 33, 143, 19, 203, 75, 1353, 585, 7719, 11311, 48989, 10803, 51743}},
+{19127, 18, 96412, {1, 1, 7, 13, 23, 31, 103, 209, 375, 817, 1461, 3657, 7931, 15893, 15065, 28721, 54299, 71147}},
+{19128, 18, 96428, {1, 3, 7, 7, 7, 25, 37, 173, 355, 499, 247, 459, 7701, 2219, 11703, 20631, 128857, 125367}},
+{19129, 18, 96445, {1, 1, 3, 5, 25, 61, 43, 135, 451, 667, 547, 443, 5071, 12671, 26975, 20131, 101545, 115281}},
+{19130, 18, 96446, {1, 3, 3, 5, 9, 19, 75, 133, 211, 585, 1283, 3397, 3181, 65, 20213, 47725, 101883, 194749}},
+{19131, 18, 96448, {1, 1, 1, 1, 19, 13, 75, 135, 111, 641, 765, 1631, 4711, 241, 15125, 38233, 95535, 177965}},
+{19132, 18, 96458, {1, 1, 7, 13, 31, 1, 91, 61, 299, 35, 1327, 3903, 6193, 5589, 6331, 6321, 105741, 89639}},
+{19133, 18, 96475, {1, 3, 3, 15, 1, 55, 11, 39, 171, 713, 973, 1827, 3487, 13057, 30775, 16881, 124989, 208193}},
+{19134, 18, 96482, {1, 3, 7, 1, 21, 29, 19, 75, 397, 755, 1601, 2907, 6861, 10377, 23127, 2443, 86545, 3841}},
+{19135, 18, 96494, {1, 3, 1, 11, 25, 33, 53, 195, 343, 425, 1523, 3051, 3115, 3205, 3457, 20521, 39187, 33307}},
+{19136, 18, 96502, {1, 3, 5, 1, 25, 23, 47, 5, 133, 511, 1549, 2691, 7861, 4987, 2877, 38693, 37491, 22481}},
+{19137, 18, 96508, {1, 1, 5, 15, 5, 55, 125, 231, 11, 451, 1443, 3865, 4115, 2379, 13675, 29953, 85721, 114859}},
+{19138, 18, 96511, {1, 3, 1, 15, 19, 37, 29, 75, 483, 785, 1933, 2435, 1811, 2787, 32653, 23159, 80993, 26867}},
+{19139, 18, 96516, {1, 1, 1, 15, 7, 27, 53, 99, 11, 693, 1085, 743, 939, 6461, 6391, 45913, 94037, 217039}},
+{19140, 18, 96520, {1, 3, 3, 9, 19, 37, 93, 77, 363, 125, 1675, 347, 5599, 7771, 23549, 39945, 106931, 127959}},
+{19141, 18, 96547, {1, 3, 1, 5, 27, 47, 107, 85, 31, 621, 1529, 2349, 7055, 889, 4663, 1705, 40011, 214775}},
+{19142, 18, 96556, {1, 3, 1, 5, 11, 47, 35, 13, 139, 783, 1009, 845, 4139, 14713, 24191, 17597, 124923, 219657}},
+{19143, 18, 96561, {1, 1, 7, 3, 3, 25, 63, 207, 361, 587, 763, 3027, 6523, 6783, 11203, 57313, 115397, 149921}},
+{19144, 18, 96568, {1, 1, 7, 1, 21, 55, 109, 183, 487, 869, 195, 83, 3675, 13103, 12383, 63519, 48379, 256443}},
+{19145, 18, 96581, {1, 3, 7, 13, 9, 21, 29, 163, 105, 871, 747, 2459, 7383, 439, 5223, 1655, 1469, 50345}},
+{19146, 18, 96582, {1, 3, 1, 1, 15, 63, 37, 159, 385, 795, 1369, 1973, 6119, 6027, 23913, 52475, 80827, 198261}},
+{19147, 18, 96679, {1, 3, 3, 11, 15, 5, 121, 231, 43, 907, 1621, 3895, 5075, 10865, 3123, 49657, 69827, 215813}},
+{19148, 18, 96683, {1, 3, 1, 15, 7, 41, 75, 105, 87, 899, 629, 1699, 5861, 9279, 30107, 37443, 7555, 64461}},
+{19149, 18, 96717, {1, 3, 1, 7, 9, 15, 119, 127, 121, 621, 1117, 1659, 605, 13705, 31181, 40063, 17257, 77645}},
+{19150, 18, 96754, {1, 1, 5, 5, 3, 37, 95, 237, 379, 375, 903, 257, 4425, 14191, 9185, 57133, 82067, 73521}},
+{19151, 18, 96769, {1, 1, 7, 15, 1, 43, 63, 45, 121, 669, 1775, 179, 7385, 3557, 17261, 379, 24759, 214831}},
+{19152, 18, 96799, {1, 1, 3, 9, 31, 5, 43, 153, 451, 573, 1623, 2831, 4483, 7219, 27657, 47111, 58165, 145799}},
+{19153, 18, 96805, {1, 1, 3, 11, 3, 11, 111, 83, 329, 807, 779, 1223, 6095, 7269, 22425, 19343, 11937, 10173}},
+{19154, 18, 96809, {1, 1, 1, 13, 27, 15, 7, 111, 37, 663, 51, 3759, 6321, 8253, 737, 59501, 109595, 177827}},
+{19155, 18, 96823, {1, 1, 3, 3, 29, 39, 79, 115, 307, 765, 331, 377, 1873, 14491, 11065, 11865, 76717, 29101}},
+{19156, 18, 96829, {1, 3, 7, 3, 21, 45, 97, 213, 309, 3, 483, 3933, 1043, 8519, 22517, 34675, 78819, 172479}},
+{19157, 18, 96832, {1, 3, 5, 3, 31, 51, 27, 137, 405, 427, 815, 43, 6551, 10971, 28589, 53077, 36639, 167661}},
+{19158, 18, 96850, {1, 3, 1, 3, 29, 5, 111, 19, 343, 21, 557, 4067, 1525, 12793, 11513, 48869, 78035, 171531}},
+{19159, 18, 96856, {1, 1, 5, 7, 25, 47, 53, 245, 135, 137, 1697, 2057, 3147, 15903, 26979, 2157, 43967, 207661}},
+{19160, 18, 96906, {1, 1, 5, 3, 25, 11, 15, 59, 511, 307, 757, 3275, 1299, 10373, 11943, 54169, 32417, 21645}},
+{19161, 18, 96962, {1, 3, 3, 11, 15, 15, 5, 137, 237, 741, 1613, 3565, 7359, 6181, 25953, 18137, 59759, 186693}},
+{19162, 18, 96974, {1, 3, 5, 3, 19, 13, 99, 167, 45, 71, 1683, 3635, 7603, 14879, 23903, 14795, 58395, 11853}},
+{19163, 18, 96979, {1, 3, 1, 7, 15, 45, 111, 111, 175, 567, 1031, 2255, 3895, 11861, 20195, 15461, 88411, 225713}},
+{19164, 18, 96997, {1, 1, 7, 3, 5, 5, 85, 65, 231, 643, 1591, 219, 2929, 4845, 29327, 14769, 46629, 131367}},
+{19165, 18, 96998, {1, 1, 5, 9, 29, 21, 47, 87, 113, 469, 1647, 2461, 3663, 5865, 6647, 41345, 39539, 220301}},
+{19166, 18, 97002, {1, 1, 5, 11, 9, 55, 5, 147, 141, 181, 283, 1695, 6537, 11095, 10385, 36013, 111653, 182273}},
+{19167, 18, 97054, {1, 1, 3, 5, 17, 45, 103, 253, 407, 151, 1585, 1585, 6661, 14579, 5723, 37641, 56813, 258819}},
+{19168, 18, 97064, {1, 3, 3, 3, 5, 63, 85, 201, 87, 419, 1993, 737, 5859, 6049, 17393, 9453, 65915, 1731}},
+{19169, 18, 97067, {1, 1, 3, 3, 3, 27, 97, 135, 137, 731, 1559, 3409, 5973, 15981, 19833, 8419, 33273, 44155}},
+{19170, 18, 97110, {1, 3, 3, 9, 31, 55, 109, 191, 119, 59, 645, 1047, 7767, 8379, 13781, 52289, 31605, 186667}},
+{19171, 18, 97116, {1, 3, 1, 15, 9, 1, 23, 31, 23, 311, 1879, 1939, 5509, 14573, 10501, 38867, 39131, 231151}},
+{19172, 18, 97137, {1, 3, 7, 1, 31, 33, 33, 19, 475, 723, 795, 1793, 6639, 14349, 16639, 31473, 110411, 95703}},
+{19173, 18, 97138, {1, 1, 5, 9, 11, 3, 39, 119, 455, 839, 513, 2423, 2219, 6059, 6125, 60995, 117701, 204057}},
+{19174, 18, 97143, {1, 1, 1, 9, 5, 23, 87, 33, 59, 241, 1427, 3867, 1091, 14683, 21651, 7091, 38011, 63809}},
+{19175, 18, 97183, {1, 1, 7, 15, 15, 23, 75, 227, 415, 1015, 2033, 1311, 6659, 5093, 14799, 65331, 96989, 170395}},
+{19176, 18, 97187, {1, 3, 5, 15, 25, 61, 33, 179, 503, 875, 1853, 257, 6727, 9117, 16777, 29585, 110901, 231617}},
+{19177, 18, 97190, {1, 1, 1, 15, 13, 53, 73, 151, 315, 887, 669, 3959, 5279, 1461, 15497, 40107, 9595, 252059}},
+{19178, 18, 97202, {1, 3, 7, 13, 17, 45, 43, 61, 99, 555, 981, 3255, 6385, 8723, 24451, 45243, 68617, 171911}},
+{19179, 18, 97219, {1, 3, 3, 11, 1, 29, 97, 219, 341, 597, 503, 773, 3777, 5431, 4581, 37169, 57269, 186377}},
+{19180, 18, 97239, {1, 3, 1, 11, 15, 49, 119, 189, 279, 821, 1541, 1343, 4379, 5833, 26537, 29769, 121125, 202553}},
+{19181, 18, 97245, {1, 3, 5, 9, 19, 23, 5, 197, 323, 101, 1155, 7, 5933, 3111, 19595, 36807, 40147, 153}},
+{19182, 18, 97246, {1, 1, 5, 11, 17, 9, 83, 51, 185, 415, 367, 1431, 7803, 8253, 16283, 54545, 99733, 57777}},
+{19183, 18, 97249, {1, 1, 5, 7, 5, 31, 41, 13, 33, 531, 1381, 781, 1699, 6321, 18125, 34567, 113253, 104181}},
+{19184, 18, 97264, {1, 3, 1, 5, 1, 59, 37, 239, 343, 395, 121, 2181, 2485, 13825, 19127, 22689, 103023, 198213}},
+{19185, 18, 97267, {1, 3, 1, 15, 29, 17, 11, 27, 413, 273, 1805, 2845, 8147, 10301, 5423, 29859, 85243, 190379}},
+{19186, 18, 97269, {1, 3, 1, 15, 7, 61, 29, 135, 273, 951, 725, 1345, 4231, 13651, 31291, 6081, 85735, 96023}},
+{19187, 18, 97274, {1, 1, 3, 11, 15, 29, 81, 129, 245, 295, 527, 3905, 4323, 5447, 21253, 51177, 105105, 48323}},
+{19188, 18, 97282, {1, 1, 3, 13, 13, 45, 71, 43, 383, 95, 1689, 639, 4631, 15113, 28053, 49247, 128303, 183999}},
+{19189, 18, 97287, {1, 1, 1, 3, 19, 31, 93, 35, 369, 765, 1201, 1625, 7683, 8719, 13843, 42723, 62323, 49431}},
+{19190, 18, 97294, {1, 3, 3, 11, 5, 39, 49, 217, 109, 63, 1753, 2489, 6017, 403, 16657, 59577, 80255, 66071}},
+{19191, 18, 97299, {1, 3, 5, 5, 11, 1, 79, 37, 261, 537, 1845, 3567, 3233, 16249, 9795, 2471, 69661, 118231}},
+{19192, 18, 97306, {1, 3, 3, 1, 19, 61, 35, 253, 31, 19, 161, 2597, 5733, 8231, 26569, 38613, 121945, 137391}},
+{19193, 18, 97347, {1, 3, 7, 3, 15, 25, 125, 231, 187, 797, 1237, 1767, 1557, 1095, 13613, 43325, 33801, 127881}},
+{19194, 18, 97361, {1, 1, 1, 9, 23, 63, 75, 107, 311, 493, 471, 2985, 1861, 4285, 27125, 14961, 122567, 152033}},
+{19195, 18, 97371, {1, 3, 5, 7, 9, 7, 43, 117, 203, 727, 101, 3831, 3201, 2327, 4675, 12085, 25131, 211835}},
+{19196, 18, 97435, {1, 1, 7, 11, 17, 1, 5, 87, 291, 1023, 1345, 3879, 7739, 9201, 19573, 20037, 128711, 187263}},
+{19197, 18, 97466, {1, 1, 3, 13, 25, 39, 71, 251, 365, 617, 1539, 2121, 3803, 8003, 23393, 56991, 56143, 223453}},
+{19198, 18, 97473, {1, 3, 5, 13, 25, 61, 71, 139, 319, 399, 903, 3063, 3667, 275, 13297, 25285, 120417, 169613}},
+{19199, 18, 97474, {1, 3, 1, 9, 9, 41, 59, 213, 195, 705, 313, 2313, 4993, 323, 24049, 30527, 27287, 80489}},
+{19200, 18, 97559, {1, 1, 5, 1, 29, 57, 107, 161, 217, 295, 721, 3857, 1935, 14981, 12243, 38541, 51177, 248889}},
+{19201, 18, 97565, {1, 1, 1, 15, 5, 25, 95, 137, 11, 215, 971, 1573, 4341, 4725, 8201, 33147, 87687, 187405}},
+{19202, 18, 97587, {1, 3, 3, 9, 9, 13, 31, 3, 175, 309, 145, 2265, 4863, 7199, 23881, 15445, 123753, 126653}},
+{19203, 18, 97611, {1, 1, 7, 3, 7, 43, 51, 191, 21, 639, 939, 691, 7823, 10529, 7757, 9291, 115045, 51539}},
+{19204, 18, 97622, {1, 1, 7, 13, 7, 45, 91, 173, 73, 779, 1647, 2059, 1373, 16027, 4611, 45787, 699, 78905}},
+{19205, 18, 97625, {1, 1, 5, 15, 5, 23, 123, 45, 265, 1009, 235, 1343, 5779, 209, 23263, 63163, 26079, 240905}},
+{19206, 18, 97632, {1, 1, 1, 11, 19, 31, 75, 105, 71, 21, 1361, 2125, 6949, 2111, 10333, 61881, 112811, 85723}},
+{19207, 18, 97635, {1, 3, 5, 7, 27, 17, 95, 35, 503, 181, 1885, 1097, 6019, 13745, 15009, 26343, 117727, 93017}},
+{19208, 18, 97652, {1, 1, 3, 11, 27, 41, 109, 23, 365, 283, 1509, 3269, 5969, 14567, 27715, 429, 65813, 169391}},
+{19209, 18, 97672, {1, 1, 5, 9, 11, 1, 23, 143, 401, 61, 993, 3029, 1901, 12947, 10439, 48661, 113863, 9353}},
+{19210, 18, 97678, {1, 3, 7, 3, 15, 27, 123, 51, 403, 569, 75, 3837, 8167, 10875, 29861, 44133, 52385, 185515}},
+{19211, 18, 97683, {1, 3, 3, 15, 15, 45, 3, 77, 439, 265, 103, 3715, 7889, 9241, 26511, 19063, 108239, 237233}},
+{19212, 18, 97695, {1, 1, 5, 13, 7, 47, 7, 185, 155, 833, 1895, 1103, 6761, 4307, 19551, 2371, 41079, 207663}},
+{19213, 18, 97705, {1, 1, 3, 7, 1, 49, 79, 127, 149, 383, 919, 3787, 6703, 8823, 15551, 28397, 11497, 144227}},
+{19214, 18, 97713, {1, 1, 7, 15, 7, 5, 9, 161, 425, 275, 1943, 3003, 3615, 1417, 587, 20949, 9651, 101257}},
+{19215, 18, 97719, {1, 3, 5, 11, 31, 11, 113, 201, 113, 889, 867, 3537, 7173, 3403, 4713, 29709, 50127, 55893}},
+{19216, 18, 97757, {1, 3, 7, 11, 11, 17, 123, 97, 3, 1009, 1567, 3261, 8053, 4639, 24493, 64085, 73975, 123965}},
+{19217, 18, 97761, {1, 1, 7, 1, 31, 7, 111, 137, 427, 615, 865, 2243, 3603, 5943, 1639, 22213, 81977, 77283}},
+{19218, 18, 97762, {1, 1, 5, 11, 25, 63, 5, 19, 67, 469, 621, 2831, 1635, 11859, 23143, 29189, 43955, 87475}},
+{19219, 18, 97771, {1, 3, 7, 15, 7, 61, 125, 207, 401, 567, 1943, 2645, 641, 15427, 24467, 41767, 122591, 48905}},
+{19220, 18, 97795, {1, 3, 3, 5, 1, 61, 65, 169, 329, 489, 435, 1719, 491, 6189, 18383, 34973, 90611, 180991}},
+{19221, 18, 97809, {1, 3, 7, 9, 25, 43, 115, 11, 289, 193, 263, 3885, 4881, 15669, 19757, 20073, 119873, 67069}},
+{19222, 18, 97826, {1, 1, 7, 11, 3, 45, 93, 115, 233, 891, 1541, 2557, 2115, 2237, 4253, 30445, 32983, 86185}},
+{19223, 18, 97845, {1, 3, 7, 3, 29, 23, 105, 51, 157, 505, 773, 2403, 1237, 5193, 32725, 53331, 66377, 25745}},
+{19224, 18, 97877, {1, 3, 5, 11, 31, 5, 111, 251, 287, 225, 913, 97, 3429, 15111, 10637, 18843, 102589, 229667}},
+{19225, 18, 97882, {1, 3, 7, 13, 21, 43, 27, 11, 265, 991, 1645, 1967, 2675, 3083, 2957, 65275, 7757, 201953}},
+{19226, 18, 97891, {1, 3, 7, 7, 23, 59, 37, 105, 113, 961, 1585, 855, 6037, 8461, 24057, 46861, 42421, 21061}},
+{19227, 18, 97903, {1, 1, 5, 1, 7, 45, 37, 147, 225, 793, 737, 753, 565, 5347, 15393, 42611, 39253, 246455}},
+{19228, 18, 97961, {1, 3, 3, 5, 29, 59, 125, 69, 283, 677, 1615, 3341, 219, 10753, 445, 43343, 117035, 137907}},
+{19229, 18, 97970, {1, 1, 5, 1, 19, 41, 93, 137, 481, 93, 703, 1211, 4051, 5591, 5913, 32831, 62027, 60519}},
+{19230, 18, 97975, {1, 1, 7, 13, 17, 63, 65, 147, 361, 83, 1383, 1761, 579, 9493, 2611, 6951, 12197, 81857}},
+{19231, 18, 97996, {1, 3, 3, 15, 11, 3, 25, 7, 221, 211, 1745, 1173, 5479, 12063, 5667, 43443, 4865, 193345}},
+{19232, 18, 98001, {1, 1, 5, 11, 31, 11, 71, 61, 57, 851, 1089, 1395, 4525, 1223, 27681, 14355, 23125, 257233}},
+{19233, 18, 98014, {1, 3, 1, 11, 25, 59, 17, 193, 229, 1005, 387, 3993, 2457, 4185, 18421, 1315, 125155, 142277}},
+{19234, 18, 98023, {1, 1, 5, 11, 13, 55, 123, 191, 5, 1023, 705, 3481, 367, 12961, 11917, 12131, 99109, 105093}},
+{19235, 18, 98035, {1, 1, 3, 11, 13, 29, 57, 57, 467, 19, 1409, 971, 3041, 13487, 24737, 3377, 97883, 248893}},
+{19236, 18, 98052, {1, 3, 7, 3, 3, 37, 109, 77, 201, 469, 39, 1747, 2027, 14781, 18821, 34647, 123865, 195097}},
+{19237, 18, 98059, {1, 3, 3, 5, 29, 27, 97, 217, 249, 141, 431, 1621, 539, 8945, 3443, 48227, 27867, 205355}},
+{19238, 18, 98061, {1, 1, 3, 13, 7, 57, 65, 167, 103, 511, 239, 325, 1793, 2811, 14223, 40999, 12589, 149759}},
+{19239, 18, 98086, {1, 3, 5, 11, 3, 1, 61, 87, 283, 29, 507, 3473, 2685, 13829, 32337, 8413, 12201, 152309}},
+{19240, 18, 98098, {1, 3, 5, 15, 1, 23, 103, 173, 423, 915, 1519, 1859, 7341, 8689, 17141, 53769, 81189, 144305}},
+{19241, 18, 98117, {1, 1, 1, 5, 31, 41, 89, 117, 329, 245, 381, 3357, 1053, 15079, 3569, 27665, 65645, 259279}},
+{19242, 18, 98118, {1, 1, 7, 5, 3, 55, 91, 35, 463, 15, 1195, 533, 6013, 10755, 1919, 61169, 81285, 82757}},
+{19243, 18, 98132, {1, 3, 5, 11, 3, 29, 85, 169, 163, 733, 939, 3401, 3709, 3307, 17329, 56873, 10721, 174235}},
+{19244, 18, 98135, {1, 1, 5, 1, 11, 45, 75, 247, 435, 21, 1985, 2261, 7013, 4935, 2457, 41077, 53121, 143269}},
+{19245, 18, 98145, {1, 3, 3, 13, 17, 59, 43, 149, 27, 1, 367, 957, 5607, 2591, 22161, 10095, 73769, 52455}},
+{19246, 18, 98160, {1, 1, 3, 13, 15, 15, 121, 83, 469, 819, 1973, 3595, 2313, 1621, 3105, 42971, 7243, 98727}},
+{19247, 18, 98194, {1, 1, 5, 7, 21, 53, 123, 9, 119, 437, 1567, 431, 3647, 10967, 22037, 8523, 81279, 126473}},
+{19248, 18, 98205, {1, 1, 5, 13, 5, 23, 125, 119, 195, 555, 341, 2037, 313, 6323, 27201, 8377, 122793, 197781}},
+{19249, 18, 98210, {1, 3, 3, 5, 17, 25, 67, 237, 349, 443, 1529, 3541, 3105, 10105, 13409, 20165, 64597, 244513}},
+{19250, 18, 98224, {1, 1, 5, 1, 11, 43, 77, 245, 359, 625, 1171, 597, 3, 591, 2457, 20275, 75995, 204685}},
+{19251, 18, 98227, {1, 3, 1, 11, 5, 13, 99, 107, 285, 617, 1687, 2959, 4439, 771, 3103, 62363, 89437, 172221}},
+{19252, 18, 98254, {1, 3, 1, 11, 1, 63, 43, 85, 23, 95, 501, 1223, 669, 16101, 1071, 53175, 102101, 419}},
+{19253, 18, 98271, {1, 3, 1, 5, 19, 23, 63, 105, 289, 419, 885, 441, 5107, 4213, 8683, 1847, 113301, 240821}},
+{19254, 18, 98272, {1, 1, 1, 9, 9, 9, 111, 63, 53, 531, 517, 3463, 8171, 2645, 13883, 52213, 40707, 24637}},
+{19255, 18, 98302, {1, 3, 1, 5, 15, 43, 71, 215, 117, 685, 1819, 1105, 5805, 8875, 31093, 31077, 93807, 65631}},
+{19256, 18, 98320, {1, 1, 7, 7, 17, 15, 31, 87, 13, 615, 2003, 3461, 7585, 1947, 6693, 26141, 95059, 52229}},
+{19257, 18, 98346, {1, 1, 3, 5, 5, 55, 7, 41, 473, 541, 545, 2901, 763, 12731, 24715, 43301, 7981, 123961}},
+{19258, 18, 98356, {1, 3, 1, 11, 13, 29, 65, 47, 511, 931, 1681, 3813, 995, 4261, 32243, 21327, 33749, 52607}},
+{19259, 18, 98360, {1, 1, 3, 1, 27, 51, 19, 119, 71, 989, 485, 1483, 4115, 11743, 5513, 32447, 62599, 163185}},
+{19260, 18, 98366, {1, 3, 7, 13, 7, 5, 127, 67, 221, 773, 1641, 3763, 2061, 2025, 29813, 64385, 109219, 70149}},
+{19261, 18, 98478, {1, 1, 5, 15, 9, 29, 105, 245, 333, 11, 803, 1877, 6735, 3797, 1913, 63837, 23649, 234721}},
+{19262, 18, 98483, {1, 3, 7, 13, 11, 21, 113, 175, 385, 885, 1259, 983, 7715, 11889, 12515, 35723, 9897, 63415}},
+{19263, 18, 98486, {1, 1, 5, 9, 31, 63, 53, 51, 375, 133, 2021, 3173, 3861, 9885, 4117, 37505, 73687, 16411}},
+{19264, 18, 98497, {1, 3, 7, 7, 11, 13, 99, 235, 285, 159, 489, 917, 3033, 7711, 6545, 52893, 28549, 68791}},
+{19265, 18, 98528, {1, 1, 5, 11, 31, 15, 89, 157, 105, 347, 455, 3391, 5341, 16035, 11819, 57679, 48057, 147673}},
+{19266, 18, 98537, {1, 3, 1, 5, 21, 5, 1, 41, 213, 677, 1745, 2591, 6237, 14265, 5963, 30017, 47293, 199411}},
+{19267, 18, 98551, {1, 3, 1, 15, 19, 9, 65, 103, 489, 977, 579, 2571, 2827, 12971, 24445, 17963, 68829, 89781}},
+{19268, 18, 98557, {1, 3, 5, 7, 3, 45, 9, 223, 137, 749, 919, 2695, 7569, 6735, 16649, 55899, 91531, 10709}},
+{19269, 18, 98572, {1, 1, 5, 11, 25, 51, 81, 243, 473, 85, 1189, 2317, 785, 9307, 25555, 36623, 66881, 150945}},
+{19270, 18, 98575, {1, 1, 3, 7, 9, 17, 99, 57, 333, 891, 71, 2359, 2067, 13265, 30077, 17935, 47343, 22673}},
+{19271, 18, 98600, {1, 1, 5, 7, 13, 17, 77, 109, 427, 667, 1367, 2383, 7505, 11239, 14229, 35431, 35473, 62447}},
+{19272, 18, 98628, {1, 1, 1, 15, 27, 5, 51, 221, 471, 877, 449, 3961, 4197, 15713, 2955, 58985, 31431, 241539}},
+{19273, 18, 98635, {1, 1, 7, 1, 13, 61, 55, 199, 87, 679, 723, 271, 1061, 8043, 13163, 8079, 81501, 60467}},
+{19274, 18, 98645, {1, 1, 3, 3, 11, 1, 85, 65, 445, 731, 2017, 3113, 8085, 7133, 14789, 2435, 38459, 234997}},
+{19275, 18, 98652, {1, 3, 3, 9, 23, 31, 49, 137, 349, 651, 1975, 3429, 7137, 7841, 28297, 58209, 36493, 259097}},
+{19276, 18, 98655, {1, 1, 7, 15, 23, 11, 87, 133, 245, 445, 151, 4075, 141, 15395, 16649, 36925, 98421, 217265}},
+{19277, 18, 98665, {1, 3, 3, 5, 25, 53, 57, 177, 481, 177, 671, 1249, 2663, 12855, 24537, 31867, 110323, 164113}},
+{19278, 18, 98710, {1, 3, 5, 7, 23, 25, 19, 91, 447, 1023, 373, 3863, 4399, 12973, 7475, 37485, 8567, 53271}},
+{19279, 18, 98719, {1, 1, 5, 7, 31, 33, 31, 75, 223, 299, 1549, 1863, 353, 4339, 8891, 10365, 3399, 185807}},
+{19280, 18, 98720, {1, 1, 7, 9, 31, 53, 23, 203, 319, 915, 1923, 205, 3119, 7243, 25251, 12907, 101921, 102695}},
+{19281, 18, 98786, {1, 1, 7, 9, 15, 1, 123, 173, 123, 215, 263, 3003, 5881, 1117, 15195, 47457, 66663, 224177}},
+{19282, 18, 98792, {1, 1, 7, 13, 11, 25, 61, 121, 173, 115, 1897, 2145, 7783, 9673, 3321, 1707, 61475, 53875}},
+{19283, 18, 98806, {1, 3, 7, 3, 31, 21, 27, 99, 421, 225, 1565, 2351, 2275, 10583, 7877, 43505, 27629, 140919}},
+{19284, 18, 98816, {1, 3, 5, 5, 11, 45, 71, 105, 487, 867, 361, 3995, 2039, 1495, 27481, 4753, 20657, 67077}},
+{19285, 18, 98836, {1, 1, 5, 1, 19, 33, 1, 77, 377, 353, 719, 1463, 7053, 7409, 32165, 15557, 117673, 69887}},
+{19286, 18, 98859, {1, 1, 5, 7, 25, 5, 15, 231, 23, 213, 1627, 1801, 7793, 651, 9903, 51745, 111611, 39679}},
+{19287, 18, 98864, {1, 3, 3, 5, 23, 43, 37, 199, 437, 19, 1853, 2119, 461, 12641, 15865, 39941, 122545, 213443}},
+{19288, 18, 98879, {1, 3, 3, 11, 31, 45, 19, 227, 507, 909, 1501, 2021, 905, 1763, 1897, 3735, 81475, 30005}},
+{19289, 18, 98905, {1, 1, 5, 5, 29, 9, 55, 25, 23, 59, 593, 2197, 6029, 8235, 8397, 27521, 96221, 168837}},
+{19290, 18, 98917, {1, 3, 1, 15, 5, 33, 75, 121, 433, 557, 1011, 3785, 2545, 953, 17295, 14407, 94871, 60445}},
+{19291, 18, 98929, {1, 3, 3, 7, 7, 53, 29, 75, 171, 587, 1701, 3815, 2761, 4403, 39, 17291, 34897, 187257}},
+{19292, 18, 98969, {1, 3, 1, 15, 17, 57, 11, 95, 335, 13, 265, 1161, 7945, 6419, 26723, 31907, 89995, 82265}},
+{19293, 18, 98975, {1, 1, 7, 5, 9, 59, 27, 153, 37, 165, 823, 3525, 621, 4777, 3485, 9109, 116567, 34691}},
+{19294, 18, 98976, {1, 1, 5, 13, 23, 27, 11, 63, 35, 39, 995, 2101, 2611, 14139, 2683, 63787, 19813, 97497}},
+{19295, 18, 98981, {1, 3, 7, 15, 31, 15, 3, 163, 167, 53, 71, 1881, 4213, 3485, 21525, 705, 122345, 203549}},
+{19296, 18, 98999, {1, 3, 5, 5, 21, 33, 85, 133, 21, 505, 1639, 3989, 771, 7171, 21953, 34503, 31247, 247459}},
+{19297, 18, 99020, {1, 1, 7, 7, 31, 1, 27, 39, 469, 243, 679, 4091, 7137, 8505, 13329, 34139, 69485, 259795}},
+{19298, 18, 99026, {1, 3, 5, 5, 31, 43, 31, 161, 413, 657, 1407, 1417, 7349, 3301, 7691, 49355, 22929, 68043}},
+{19299, 18, 99054, {1, 1, 7, 11, 15, 61, 73, 217, 163, 503, 193, 3795, 41, 16251, 1187, 65363, 113211, 100337}},
+{19300, 18, 99083, {1, 3, 1, 11, 9, 15, 109, 187, 109, 865, 845, 1579, 321, 1269, 20613, 5693, 58421, 254959}},
+{19301, 18, 99093, {1, 3, 1, 13, 11, 3, 19, 135, 93, 779, 1383, 219, 2737, 377, 1125, 35663, 130815, 103797}},
+{19302, 18, 99103, {1, 1, 5, 11, 25, 25, 71, 249, 201, 679, 1677, 1817, 7619, 10327, 14821, 47847, 33629, 250979}},
+{19303, 18, 99131, {1, 1, 7, 15, 23, 19, 69, 39, 25, 843, 99, 3499, 2457, 11681, 30009, 17609, 46653, 162427}},
+{19304, 18, 99156, {1, 3, 3, 7, 23, 25, 77, 135, 61, 501, 1381, 3977, 1957, 11255, 16053, 30297, 58835, 97589}},
+{19305, 18, 99159, {1, 3, 5, 3, 9, 31, 9, 55, 421, 109, 1823, 1921, 7349, 2661, 4503, 36691, 48843, 182631}},
+{19306, 18, 99165, {1, 1, 1, 11, 7, 23, 107, 125, 393, 105, 1407, 3461, 4539, 6121, 7881, 32407, 83749, 98831}},
+{19307, 18, 99170, {1, 3, 3, 13, 5, 59, 5, 3, 185, 959, 241, 819, 1443, 1789, 12771, 26703, 25399, 182583}},
+{19308, 18, 99189, {1, 1, 1, 3, 3, 47, 7, 45, 93, 373, 175, 87, 649, 12903, 5029, 1945, 111967, 140889}},
+{19309, 18, 99223, {1, 3, 1, 11, 9, 47, 25, 191, 215, 845, 1557, 9, 3451, 5837, 11763, 29127, 113115, 99039}},
+{19310, 18, 99227, {1, 1, 1, 5, 23, 53, 45, 1, 361, 751, 807, 1765, 685, 2109, 28437, 60489, 65739, 234511}},
+{19311, 18, 99271, {1, 3, 3, 7, 15, 57, 71, 61, 195, 123, 1745, 3249, 351, 14309, 2017, 15653, 110803, 45937}},
+{19312, 18, 99277, {1, 3, 7, 9, 25, 11, 25, 29, 467, 313, 1927, 2423, 7311, 14299, 8145, 8123, 115103, 213881}},
+{19313, 18, 99278, {1, 1, 3, 15, 1, 35, 111, 99, 507, 417, 1433, 129, 5565, 13365, 18853, 8607, 109739, 120623}},
+{19314, 18, 99313, {1, 1, 1, 7, 13, 31, 93, 3, 327, 67, 1101, 1965, 5939, 6505, 3117, 3021, 33707, 79353}},
+{19315, 18, 99314, {1, 1, 3, 7, 15, 21, 23, 117, 367, 137, 287, 903, 4685, 13943, 26779, 24607, 70853, 99743}},
+{19316, 18, 99345, {1, 1, 7, 11, 25, 43, 67, 181, 459, 737, 1567, 3491, 5085, 6487, 23115, 62341, 102943, 77301}},
+{19317, 18, 99361, {1, 1, 3, 15, 7, 35, 81, 199, 455, 851, 835, 3421, 4675, 15173, 9205, 7305, 109849, 15183}},
+{19318, 18, 99367, {1, 3, 5, 11, 9, 55, 3, 53, 235, 271, 1265, 3681, 3627, 3485, 11591, 53097, 85949, 158173}},
+{19319, 18, 99386, {1, 3, 7, 3, 15, 27, 57, 183, 487, 9, 1797, 2973, 3687, 12987, 9133, 14595, 52067, 131217}},
+{19320, 18, 99394, {1, 1, 5, 3, 7, 25, 19, 215, 291, 325, 813, 577, 4249, 10373, 17233, 29557, 72979, 70721}},
+{19321, 18, 99417, {1, 3, 1, 7, 25, 1, 107, 167, 367, 303, 883, 993, 4189, 6557, 13697, 15251, 77065, 116127}},
+{19322, 18, 99418, {1, 3, 5, 11, 13, 59, 9, 121, 489, 593, 1503, 601, 5263, 13837, 20991, 35761, 45867, 155905}},
+{19323, 18, 99453, {1, 1, 3, 3, 19, 47, 127, 115, 267, 261, 969, 961, 5919, 10085, 29363, 4935, 100485, 75561}},
+{19324, 18, 99454, {1, 3, 1, 15, 11, 53, 39, 187, 53, 11, 1951, 913, 965, 2565, 5457, 3237, 24923, 245681}},
+{19325, 18, 99477, {1, 1, 7, 3, 15, 5, 25, 45, 17, 45, 1317, 1853, 6627, 15879, 29935, 24749, 118149, 35359}},
+{19326, 18, 99518, {1, 1, 7, 1, 21, 45, 67, 71, 25, 743, 925, 3441, 3013, 1613, 6321, 12491, 119931, 164701}},
+{19327, 18, 99544, {1, 1, 7, 1, 13, 15, 35, 187, 91, 995, 401, 2443, 4183, 10823, 20589, 27413, 117095, 20359}},
+{19328, 18, 99559, {1, 3, 3, 7, 15, 51, 55, 167, 409, 859, 719, 3223, 2457, 16013, 13639, 4027, 79339, 225113}},
+{19329, 18, 99592, {1, 3, 1, 9, 3, 29, 105, 193, 279, 27, 1093, 2199, 6983, 619, 10163, 40365, 71015, 102191}},
+{19330, 18, 99597, {1, 1, 3, 9, 29, 5, 33, 247, 27, 299, 2017, 379, 6199, 15047, 18329, 3493, 47679, 76703}},
+{19331, 18, 99603, {1, 3, 5, 5, 9, 19, 51, 129, 157, 831, 1373, 653, 7489, 13125, 1815, 10915, 88679, 50269}},
+{19332, 18, 99621, {1, 3, 3, 9, 9, 49, 79, 11, 181, 679, 1697, 3707, 205, 13305, 6293, 56653, 42619, 116257}},
+{19333, 18, 99646, {1, 1, 5, 9, 23, 41, 17, 135, 145, 715, 257, 1561, 6941, 2411, 31459, 25055, 35807, 51579}},
+{19334, 18, 99693, {1, 1, 1, 7, 11, 13, 49, 155, 403, 569, 751, 2959, 425, 13949, 22047, 49829, 71925, 101647}},
+{19335, 18, 99722, {1, 1, 3, 15, 15, 15, 17, 213, 113, 395, 1999, 2039, 3623, 13255, 24435, 54487, 78773, 202637}},
+{19336, 18, 99760, {1, 3, 7, 9, 5, 21, 61, 165, 97, 349, 1131, 2677, 333, 13129, 2137, 22909, 95795, 143081}},
+{19337, 18, 99780, {1, 1, 1, 5, 31, 41, 109, 179, 295, 475, 639, 3929, 1841, 7545, 19411, 52573, 10173, 236769}},
+{19338, 18, 99789, {1, 1, 1, 5, 27, 51, 9, 217, 393, 671, 931, 433, 7303, 16295, 6727, 5703, 88241, 132665}},
+{19339, 18, 99804, {1, 1, 7, 13, 21, 33, 19, 241, 497, 519, 1413, 489, 4975, 1345, 24925, 40383, 110815, 136217}},
+{19340, 18, 99823, {1, 3, 1, 9, 7, 51, 79, 15, 15, 601, 997, 3713, 7829, 903, 12393, 60059, 42057, 175141}},
+{19341, 18, 99826, {1, 1, 5, 15, 9, 63, 107, 63, 495, 591, 207, 779, 8069, 3013, 23839, 3075, 127481, 193885}},
+{19342, 18, 99832, {1, 1, 1, 7, 13, 17, 121, 171, 99, 59, 1043, 1109, 1337, 1179, 27635, 34063, 12945, 1431}},
+{19343, 18, 99842, {1, 3, 1, 3, 5, 47, 101, 205, 157, 595, 263, 3887, 7015, 4693, 15211, 25381, 128803, 227233}},
+{19344, 18, 99851, {1, 1, 3, 11, 17, 33, 1, 19, 153, 603, 119, 2305, 4041, 4011, 19849, 761, 52807, 129811}},
+{19345, 18, 99862, {1, 3, 7, 15, 21, 7, 13, 225, 497, 459, 389, 911, 6349, 5059, 6363, 41915, 90687, 214501}},
+{19346, 18, 99871, {1, 3, 1, 15, 1, 39, 31, 83, 147, 629, 185, 1913, 3217, 959, 651, 65267, 108613, 20391}},
+{19347, 18, 99899, {1, 3, 1, 7, 9, 11, 29, 201, 245, 815, 1869, 2597, 5693, 15669, 23293, 30885, 4029, 225737}},
+{19348, 18, 99940, {1, 3, 5, 11, 7, 29, 119, 207, 499, 23, 1563, 3645, 3839, 2509, 24043, 64231, 22509, 221835}},
+{19349, 18, 99983, {1, 3, 3, 7, 11, 49, 13, 201, 353, 217, 831, 2803, 1521, 12989, 25339, 41035, 2125, 165271}},
+{19350, 18, 99985, {1, 1, 5, 11, 1, 45, 93, 29, 55, 1007, 1919, 241, 5931, 9211, 17291, 39849, 25453, 96077}},
+{19351, 18, 100025, {1, 3, 1, 1, 29, 43, 11, 105, 331, 693, 1363, 291, 8191, 7813, 14135, 38287, 15469, 256913}},
+{19352, 18, 100043, {1, 3, 5, 11, 19, 21, 23, 117, 253, 111, 733, 3785, 5835, 423, 30251, 27283, 79561, 162095}},
+{19353, 18, 100070, {1, 3, 3, 1, 9, 19, 83, 13, 37, 725, 1597, 1117, 8067, 8085, 1315, 41813, 8973, 175525}},
+{19354, 18, 100076, {1, 1, 5, 3, 13, 39, 3, 213, 335, 907, 1143, 1729, 601, 11255, 24351, 41045, 11335, 186221}},
+{19355, 18, 100084, {1, 3, 3, 9, 17, 11, 29, 33, 303, 815, 1607, 2403, 8095, 4213, 16697, 64733, 24439, 93081}},
+{19356, 18, 100096, {1, 1, 1, 3, 13, 37, 35, 181, 243, 645, 1915, 3521, 569, 3005, 7271, 32755, 64575, 119813}},
+{19357, 18, 100105, {1, 1, 5, 13, 25, 59, 77, 121, 459, 755, 385, 1893, 1227, 9957, 5069, 40063, 27261, 4703}},
+{19358, 18, 100108, {1, 3, 1, 3, 29, 41, 95, 255, 219, 21, 317, 3021, 2615, 5101, 19413, 25795, 6521, 157749}},
+{19359, 18, 100123, {1, 3, 3, 5, 7, 33, 7, 205, 415, 23, 1431, 117, 1605, 9541, 11825, 49195, 86341, 99673}},
+{19360, 18, 100132, {1, 3, 3, 5, 17, 37, 33, 209, 49, 161, 321, 3697, 6483, 12859, 895, 675, 1899, 260289}},
+{19361, 18, 100141, {1, 1, 3, 15, 1, 27, 83, 125, 309, 553, 505, 2209, 4931, 2593, 28253, 12879, 74971, 9047}},
+{19362, 18, 100181, {1, 3, 7, 3, 15, 3, 105, 19, 41, 119, 149, 3847, 6593, 875, 23777, 4547, 57717, 139387}},
+{19363, 18, 100191, {1, 1, 1, 3, 9, 43, 25, 15, 67, 609, 951, 273, 8095, 621, 24819, 17233, 53423, 192757}},
+{19364, 18, 100202, {1, 3, 5, 3, 9, 49, 107, 215, 245, 217, 545, 2285, 2075, 401, 26599, 32967, 130457, 203755}},
+{19365, 18, 100216, {1, 1, 5, 1, 7, 31, 87, 181, 135, 155, 9, 1431, 307, 13367, 31147, 10327, 2817, 63327}},
+{19366, 18, 100246, {1, 3, 3, 3, 29, 17, 55, 201, 33, 275, 2005, 3037, 3439, 1513, 7563, 46491, 103319, 5279}},
+{19367, 18, 100256, {1, 3, 7, 11, 31, 63, 105, 169, 257, 225, 711, 2041, 1519, 11801, 18543, 35173, 92125, 72729}},
+{19368, 18, 100271, {1, 1, 3, 3, 11, 13, 127, 231, 229, 809, 303, 1167, 47, 4281, 2373, 10455, 74685, 131775}},
+{19369, 18, 100285, {1, 1, 5, 15, 1, 5, 97, 139, 189, 39, 37, 3513, 2119, 1453, 11477, 45477, 75613, 169915}},
+{19370, 18, 100294, {1, 3, 5, 1, 15, 27, 31, 87, 311, 785, 489, 1331, 5259, 6963, 26441, 41675, 107187, 60723}},
+{19371, 18, 100305, {1, 1, 3, 5, 13, 9, 33, 3, 273, 357, 841, 1421, 5993, 12449, 6821, 4283, 9437, 215035}},
+{19372, 18, 100321, {1, 3, 3, 1, 15, 43, 101, 35, 23, 743, 29, 3953, 3095, 14355, 25977, 12513, 54565, 20199}},
+{19373, 18, 100331, {1, 3, 3, 1, 11, 53, 99, 95, 63, 503, 1361, 3231, 2445, 5073, 4667, 33033, 4575, 139475}},
+{19374, 18, 100334, {1, 3, 3, 5, 19, 57, 15, 115, 125, 1017, 1913, 907, 2461, 3229, 16591, 6591, 26385, 228661}},
+{19375, 18, 100345, {1, 3, 1, 11, 27, 19, 7, 121, 245, 997, 1743, 2571, 1333, 9603, 27811, 42081, 44365, 94943}},
+{19376, 18, 100346, {1, 3, 1, 1, 13, 5, 127, 217, 63, 137, 989, 1441, 1133, 8273, 18091, 22243, 122931, 28867}},
+{19377, 18, 100369, {1, 1, 7, 15, 23, 39, 57, 83, 321, 817, 819, 223, 4803, 6935, 2027, 20373, 119683, 29781}},
+{19378, 18, 100372, {1, 1, 7, 7, 9, 1, 55, 211, 455, 283, 1647, 471, 4351, 14119, 6945, 63117, 109687, 200165}},
+{19379, 18, 100382, {1, 1, 7, 7, 29, 45, 113, 253, 135, 375, 1091, 959, 1423, 1241, 31689, 33751, 73459, 91769}},
+{19380, 18, 100403, {1, 3, 5, 11, 23, 63, 55, 181, 453, 267, 995, 1309, 2847, 3791, 21683, 59809, 81891, 132635}},
+{19381, 18, 100451, {1, 1, 1, 13, 17, 37, 87, 17, 61, 689, 1895, 3877, 4717, 6447, 22329, 1619, 30069, 190887}},
+{19382, 18, 100488, {1, 3, 1, 7, 27, 61, 17, 51, 99, 909, 85, 951, 107, 1923, 35, 63389, 90273, 152643}},
+{19383, 18, 100499, {1, 1, 1, 1, 15, 39, 77, 255, 191, 613, 655, 1881, 267, 3927, 18025, 13825, 15381, 169193}},
+{19384, 18, 100501, {1, 3, 3, 1, 31, 17, 73, 69, 231, 221, 501, 3755, 1671, 2049, 22493, 16353, 1775, 181783}},
+{19385, 18, 100511, {1, 1, 7, 5, 31, 45, 125, 189, 287, 487, 1911, 3133, 3257, 8967, 21295, 1247, 72297, 68269}},
+{19386, 18, 100536, {1, 3, 3, 1, 7, 9, 123, 147, 7, 381, 1597, 1289, 7831, 14493, 21145, 15487, 70353, 147891}},
+{19387, 18, 100629, {1, 1, 5, 9, 15, 17, 43, 87, 101, 425, 1819, 163, 6741, 8255, 2591, 17719, 112871, 110793}},
+{19388, 18, 100652, {1, 1, 3, 9, 3, 27, 7, 41, 43, 743, 131, 705, 2607, 9963, 26367, 41191, 126347, 164291}},
+{19389, 18, 100655, {1, 3, 3, 15, 7, 17, 97, 153, 283, 461, 1723, 2421, 4973, 16369, 30633, 62299, 119425, 3591}},
+{19390, 18, 100669, {1, 1, 1, 13, 7, 33, 95, 255, 429, 693, 849, 3783, 5985, 8551, 23227, 1015, 109023, 42493}},
+{19391, 18, 100687, {1, 3, 1, 7, 3, 43, 53, 137, 413, 265, 2033, 1347, 335, 529, 24751, 16443, 122195, 158951}},
+{19392, 18, 100692, {1, 1, 5, 9, 27, 21, 83, 185, 325, 557, 1247, 2739, 6925, 5459, 26027, 62217, 61113, 197743}},
+{19393, 18, 100696, {1, 1, 3, 13, 9, 57, 79, 133, 137, 851, 863, 1605, 7839, 11809, 29941, 20473, 6687, 164479}},
+{19394, 18, 100701, {1, 1, 3, 9, 9, 51, 123, 29, 139, 43, 1329, 2701, 3413, 3875, 19673, 62369, 10529, 226525}},
+{19395, 18, 100706, {1, 3, 1, 5, 25, 47, 7, 201, 119, 623, 9, 25, 1713, 10817, 8201, 5847, 77477, 237883}},
+{19396, 18, 100711, {1, 1, 5, 13, 15, 53, 39, 93, 235, 619, 1695, 2389, 2571, 2389, 4619, 45769, 17245, 69973}},
+{19397, 18, 100726, {1, 1, 7, 1, 31, 9, 75, 143, 1, 67, 809, 1037, 2801, 16129, 22443, 26021, 119683, 14681}},
+{19398, 18, 100754, {1, 3, 1, 9, 23, 49, 69, 71, 139, 953, 1053, 3059, 1061, 5881, 26207, 15907, 79389, 95341}},
+{19399, 18, 100759, {1, 3, 5, 1, 19, 39, 69, 183, 95, 289, 847, 393, 1649, 1275, 21187, 34715, 67553, 123239}},
+{19400, 18, 100790, {1, 1, 1, 5, 21, 39, 119, 193, 347, 87, 731, 3327, 6089, 13781, 20389, 52303, 11869, 48975}},
+{19401, 18, 100838, {1, 3, 5, 1, 19, 17, 93, 33, 215, 457, 687, 1325, 1997, 2655, 21195, 54997, 36877, 57991}},
+{19402, 18, 100878, {1, 1, 1, 3, 17, 45, 91, 45, 231, 611, 413, 2321, 7181, 13765, 7791, 6973, 24497, 231795}},
+{19403, 18, 100880, {1, 3, 3, 15, 7, 29, 103, 31, 295, 637, 1775, 2293, 8001, 4175, 1257, 16881, 93695, 180591}},
+{19404, 18, 100885, {1, 1, 1, 13, 31, 7, 47, 51, 267, 231, 463, 939, 7977, 8593, 15329, 36871, 50449, 222341}},
+{19405, 18, 100886, {1, 3, 7, 3, 27, 31, 57, 135, 507, 177, 1455, 1963, 4473, 6449, 727, 49853, 65275, 237531}},
+{19406, 18, 100943, {1, 3, 7, 11, 31, 21, 111, 231, 269, 27, 719, 3275, 2489, 3689, 3425, 23763, 39413, 64565}},
+{19407, 18, 100948, {1, 1, 1, 11, 23, 27, 31, 153, 201, 985, 1553, 3061, 7663, 4079, 13549, 48765, 64169, 68223}},
+{19408, 18, 100957, {1, 1, 7, 15, 11, 53, 125, 23, 73, 799, 591, 665, 127, 3941, 11251, 12649, 2657, 230923}},
+{19409, 18, 100962, {1, 1, 7, 15, 29, 43, 95, 81, 337, 367, 779, 1237, 7627, 997, 3355, 1245, 70477, 159097}},
+{19410, 18, 100968, {1, 3, 1, 13, 19, 31, 11, 91, 179, 425, 1395, 1439, 2723, 401, 26779, 36723, 115743, 179653}},
+{19411, 18, 100981, {1, 1, 3, 1, 29, 35, 11, 217, 301, 421, 765, 1949, 5475, 2247, 3953, 27091, 16895, 194821}},
+{19412, 18, 100986, {1, 1, 5, 9, 11, 21, 95, 135, 127, 65, 609, 3893, 7143, 13231, 29199, 36205, 38711, 159599}},
+{19413, 18, 101001, {1, 3, 5, 13, 25, 25, 101, 221, 495, 993, 961, 2575, 907, 5277, 18415, 1797, 22043, 129889}},
+{19414, 18, 101012, {1, 1, 1, 15, 21, 21, 99, 3, 175, 735, 659, 543, 7573, 15549, 14067, 60009, 65785, 112927}},
+{19415, 18, 101015, {1, 3, 7, 7, 3, 39, 61, 203, 143, 581, 487, 2097, 3943, 6869, 14435, 46431, 101781, 233067}},
+{19416, 18, 101019, {1, 1, 3, 1, 13, 27, 21, 147, 295, 89, 1845, 1017, 4621, 10029, 3517, 25371, 104531, 225179}},
+{19417, 18, 101037, {1, 1, 3, 11, 25, 51, 45, 179, 299, 487, 2039, 85, 4643, 8211, 12051, 64819, 93481, 159511}},
+{19418, 18, 101063, {1, 1, 5, 3, 21, 7, 73, 193, 415, 7, 125, 2487, 7369, 2043, 7633, 19265, 65337, 57399}},
+{19419, 18, 101105, {1, 1, 5, 3, 3, 53, 51, 169, 313, 973, 1549, 243, 3155, 13827, 24971, 61393, 15147, 187397}},
+{19420, 18, 101144, {1, 3, 3, 3, 29, 33, 91, 41, 367, 77, 1259, 1703, 2105, 14473, 17763, 29809, 47777, 205553}},
+{19421, 18, 101147, {1, 3, 7, 3, 23, 61, 59, 235, 51, 41, 417, 691, 2953, 15577, 32283, 2793, 109557, 64729}},
+{19422, 18, 101154, {1, 1, 5, 9, 13, 17, 93, 201, 151, 323, 1481, 3645, 3039, 5131, 503, 42055, 114939, 198755}},
+{19423, 18, 101163, {1, 3, 5, 1, 21, 53, 75, 29, 283, 541, 499, 309, 1923, 995, 21479, 56183, 103743, 152113}},
+{19424, 18, 101166, {1, 3, 1, 3, 21, 51, 67, 97, 481, 509, 805, 213, 5157, 13573, 16187, 8199, 28025, 208445}},
+{19425, 18, 101173, {1, 1, 7, 7, 15, 25, 107, 127, 355, 249, 707, 1287, 6831, 5317, 15613, 12837, 48091, 27611}},
+{19426, 18, 101174, {1, 3, 3, 7, 31, 53, 127, 239, 17, 709, 979, 4023, 7149, 4239, 20015, 44365, 113245, 75873}},
+{19427, 18, 101219, {1, 3, 5, 11, 27, 37, 49, 123, 137, 967, 1857, 3961, 7429, 8355, 30733, 64587, 73903, 188581}},
+{19428, 18, 101240, {1, 3, 3, 7, 19, 51, 69, 121, 345, 637, 1987, 335, 7071, 13849, 22369, 46895, 20761, 148227}},
+{19429, 18, 101250, {1, 1, 3, 11, 9, 1, 93, 151, 487, 889, 919, 2429, 5425, 15303, 12583, 57627, 42683, 98265}},
+{19430, 18, 101259, {1, 3, 5, 3, 1, 29, 87, 189, 285, 805, 933, 1381, 2789, 107, 14215, 33171, 110573, 250983}},
+{19431, 18, 101273, {1, 3, 1, 1, 27, 43, 63, 115, 317, 401, 885, 1029, 7003, 10041, 15299, 42251, 58675, 177545}},
+{19432, 18, 101274, {1, 3, 5, 7, 11, 33, 119, 5, 185, 777, 1795, 1585, 3543, 1801, 17681, 1041, 44513, 105435}},
+{19433, 18, 101285, {1, 3, 1, 9, 19, 33, 15, 253, 299, 925, 241, 1333, 615, 12501, 499, 44449, 16595, 70357}},
+{19434, 18, 101300, {1, 1, 3, 13, 13, 31, 17, 123, 215, 805, 1177, 3683, 27, 11881, 7645, 25575, 63057, 89547}},
+{19435, 18, 101309, {1, 1, 5, 5, 17, 1, 57, 183, 267, 825, 1987, 329, 5603, 1295, 425, 61871, 27859, 157109}},
+{19436, 18, 101310, {1, 3, 3, 11, 19, 45, 37, 79, 191, 17, 17, 3379, 7941, 3159, 20351, 26341, 34687, 116281}},
+{19437, 18, 101321, {1, 1, 3, 7, 11, 7, 61, 199, 459, 993, 1729, 3751, 1067, 14965, 14669, 40281, 12579, 154601}},
+{19438, 18, 101324, {1, 3, 3, 13, 19, 53, 17, 39, 137, 219, 1645, 2899, 505, 10057, 22891, 32317, 81201, 126291}},
+{19439, 18, 101363, {1, 3, 5, 7, 21, 53, 65, 125, 69, 781, 761, 1683, 5817, 11859, 11543, 62853, 57149, 212261}},
+{19440, 18, 101366, {1, 3, 5, 9, 13, 25, 81, 119, 439, 25, 239, 2867, 421, 12631, 22705, 31039, 96105, 79023}},
+{19441, 18, 101377, {1, 3, 5, 3, 19, 9, 51, 135, 437, 393, 1711, 1205, 5195, 10927, 28583, 7513, 110227, 139295}},
+{19442, 18, 101380, {1, 3, 7, 9, 31, 15, 5, 143, 49, 13, 1143, 2325, 5437, 14289, 31555, 58777, 102675, 64559}},
+{19443, 18, 101389, {1, 1, 7, 3, 3, 21, 65, 127, 341, 109, 167, 1835, 6687, 1695, 15631, 47047, 127543, 51413}},
+{19444, 18, 101407, {1, 1, 3, 1, 31, 49, 103, 147, 59, 701, 1251, 3391, 1935, 5371, 28585, 50023, 73839, 118205}},
+{19445, 18, 101411, {1, 3, 3, 1, 5, 49, 91, 23, 91, 663, 1369, 1437, 2657, 11369, 29857, 53875, 127045, 242323}},
+{19446, 18, 101432, {1, 3, 1, 3, 23, 33, 7, 105, 353, 863, 1211, 1175, 1347, 12913, 11973, 55255, 27145, 175539}},
+{19447, 18, 101476, {1, 1, 1, 13, 9, 29, 71, 71, 509, 571, 2005, 3125, 2731, 6829, 26863, 16459, 113195, 80247}},
+{19448, 18, 101488, {1, 3, 5, 1, 7, 11, 45, 177, 281, 695, 1197, 2035, 2137, 11833, 12417, 5805, 77211, 45553}},
+{19449, 18, 101494, {1, 1, 7, 7, 27, 59, 91, 183, 267, 373, 677, 2431, 903, 4229, 31997, 19843, 125089, 242871}},
+{19450, 18, 101514, {1, 3, 3, 13, 23, 23, 53, 101, 225, 247, 2013, 853, 279, 2161, 30045, 28255, 130907, 57157}},
+{19451, 18, 101534, {1, 3, 5, 13, 5, 11, 63, 137, 219, 661, 773, 1991, 4081, 5963, 25207, 50461, 85293, 159441}},
+{19452, 18, 101537, {1, 3, 1, 15, 5, 59, 43, 87, 429, 77, 73, 1275, 2619, 16133, 20009, 26089, 38129, 157267}},
+{19453, 18, 101543, {1, 1, 5, 15, 9, 59, 37, 127, 127, 733, 1703, 1331, 4293, 3555, 22739, 49513, 34533, 143225}},
+{19454, 18, 101547, {1, 1, 7, 7, 11, 51, 121, 59, 505, 147, 1855, 1661, 5539, 3421, 28863, 14811, 39811, 228927}},
+{19455, 18, 101584, {1, 1, 5, 5, 1, 31, 57, 167, 107, 753, 1835, 2491, 3311, 8639, 8743, 17279, 77071, 8673}},
+{19456, 18, 101589, {1, 1, 3, 3, 15, 39, 1, 223, 395, 603, 1095, 435, 1225, 4045, 21721, 40767, 48971, 1583}},
+{19457, 18, 101590, {1, 1, 3, 13, 9, 17, 47, 175, 229, 827, 769, 2901, 137, 9931, 11115, 25337, 105811, 68413}},
+{19458, 18, 101629, {1, 1, 1, 5, 29, 55, 43, 39, 319, 919, 749, 931, 1973, 13147, 913, 48353, 40955, 189783}},
+{19459, 18, 101678, {1, 3, 5, 5, 13, 33, 81, 213, 79, 781, 1069, 3117, 5859, 9061, 30963, 17307, 6281, 208707}},
+{19460, 18, 101683, {1, 1, 5, 13, 27, 63, 41, 91, 123, 763, 1115, 3193, 4571, 4573, 8235, 24291, 40911, 225985}},
+{19461, 18, 101700, {1, 1, 1, 7, 13, 5, 77, 215, 67, 183, 1447, 1571, 213, 3481, 28349, 22451, 44951, 240257}},
+{19462, 18, 101712, {1, 3, 7, 7, 3, 21, 39, 233, 263, 19, 489, 1511, 2313, 1799, 25173, 17913, 70593, 2969}},
+{19463, 18, 101748, {1, 3, 7, 15, 3, 1, 93, 101, 393, 911, 1055, 953, 1279, 11947, 11963, 53443, 29105, 226057}},
+{19464, 18, 101757, {1, 1, 3, 7, 7, 53, 119, 39, 439, 629, 1845, 3411, 3633, 16345, 27501, 59565, 39581, 85373}},
+{19465, 18, 101762, {1, 1, 5, 7, 19, 39, 19, 191, 509, 239, 359, 645, 8107, 13721, 21289, 20763, 67727, 45957}},
+{19466, 18, 101771, {1, 1, 1, 13, 5, 13, 113, 41, 135, 351, 311, 1099, 2391, 16165, 15805, 54737, 102645, 224417}},
+{19467, 18, 101785, {1, 3, 3, 9, 17, 47, 95, 249, 45, 749, 313, 317, 2413, 15861, 27221, 35537, 6407, 50111}},
+{19468, 18, 101795, {1, 1, 7, 5, 29, 57, 81, 7, 233, 393, 307, 1089, 1367, 12275, 11861, 29119, 27271, 36351}},
+{19469, 18, 101822, {1, 3, 5, 15, 9, 15, 23, 241, 233, 305, 1025, 2035, 4897, 10321, 17345, 42873, 109045, 129533}},
+{19470, 18, 101851, {1, 3, 5, 9, 21, 33, 111, 81, 311, 829, 1851, 1437, 5935, 7847, 15493, 28531, 74879, 40567}},
+{19471, 18, 101863, {1, 3, 7, 7, 13, 21, 43, 119, 507, 701, 1385, 745, 799, 1567, 13271, 40267, 130843, 59951}},
+{19472, 18, 101894, {1, 3, 3, 1, 19, 43, 45, 119, 87, 263, 1475, 3897, 2811, 2711, 4949, 48043, 125237, 230897}},
+{19473, 18, 101903, {1, 1, 7, 1, 1, 53, 17, 71, 313, 373, 5, 2359, 1643, 9867, 18365, 5011, 40675, 105371}},
+{19474, 18, 101924, {1, 3, 7, 11, 23, 49, 123, 255, 33, 241, 473, 959, 1859, 6109, 5433, 27625, 46839, 90727}},
+{19475, 18, 101939, {1, 1, 1, 3, 31, 43, 33, 129, 159, 445, 1831, 1005, 587, 2091, 5749, 33271, 50909, 65057}},
+{19476, 18, 101980, {1, 1, 7, 13, 3, 21, 17, 125, 357, 97, 1255, 669, 1583, 7433, 32287, 61795, 5915, 211593}},
+{19477, 18, 101993, {1, 1, 7, 7, 31, 19, 71, 211, 213, 731, 1491, 3315, 3633, 14953, 21369, 4977, 33533, 12115}},
+{19478, 18, 101994, {1, 3, 1, 1, 31, 1, 87, 253, 211, 57, 1431, 2613, 4075, 14463, 11287, 38671, 100129, 4241}},
+{19479, 18, 101996, {1, 1, 1, 5, 21, 13, 27, 29, 31, 285, 179, 3861, 5319, 15683, 2579, 15663, 63357, 81849}},
+{19480, 18, 102007, {1, 1, 3, 7, 23, 29, 29, 79, 263, 865, 1237, 3871, 2097, 5337, 2387, 59277, 28831, 57957}},
+{19481, 18, 102044, {1, 3, 7, 15, 15, 31, 83, 195, 87, 691, 71, 1025, 3145, 675, 14619, 22399, 88885, 222969}},
+{19482, 18, 102086, {1, 1, 5, 7, 19, 3, 121, 105, 383, 675, 777, 2073, 643, 14439, 19467, 13159, 115421, 250561}},
+{19483, 18, 102097, {1, 3, 5, 9, 13, 41, 119, 23, 355, 765, 579, 849, 3313, 2443, 29521, 42965, 102559, 227707}},
+{19484, 18, 102113, {1, 3, 3, 7, 23, 55, 115, 83, 331, 873, 797, 621, 1197, 15299, 26307, 34287, 120459, 260603}},
+{19485, 18, 102123, {1, 1, 3, 5, 7, 11, 113, 119, 65, 691, 1169, 2291, 7283, 1391, 10737, 3801, 40649, 191009}},
+{19486, 18, 102155, {1, 1, 7, 9, 3, 23, 95, 109, 457, 277, 871, 3013, 2833, 4131, 21081, 43635, 19875, 162173}},
+{19487, 18, 102157, {1, 1, 3, 15, 25, 7, 45, 109, 195, 935, 1487, 1603, 1663, 15595, 10687, 4073, 34863, 45851}},
+{19488, 18, 102169, {1, 1, 1, 5, 21, 19, 37, 141, 377, 553, 1225, 2485, 1235, 13179, 2587, 43659, 1405, 52023}},
+{19489, 18, 102181, {1, 3, 1, 9, 5, 27, 1, 219, 397, 555, 533, 941, 2755, 1295, 16157, 30733, 54279, 168455}},
+{19490, 18, 102182, {1, 3, 3, 1, 27, 41, 93, 177, 119, 581, 167, 3943, 5765, 15455, 555, 17419, 33117, 160599}},
+{19491, 18, 102185, {1, 1, 3, 7, 15, 25, 29, 177, 503, 529, 229, 2535, 1493, 805, 30983, 26309, 123453, 118441}},
+{19492, 18, 102199, {1, 1, 7, 15, 13, 33, 83, 151, 183, 433, 823, 4003, 1991, 6563, 18743, 61835, 56535, 191193}},
+{19493, 18, 102208, {1, 1, 1, 13, 9, 31, 91, 63, 455, 67, 243, 1573, 3507, 9491, 4677, 13835, 121603, 241781}},
+{19494, 18, 102213, {1, 1, 5, 5, 29, 13, 45, 29, 289, 909, 1923, 3371, 3675, 13119, 24599, 58511, 109467, 126865}},
+{19495, 18, 102226, {1, 1, 5, 9, 21, 41, 41, 179, 25, 463, 949, 819, 397, 12329, 3461, 34773, 61337, 23579}},
+{19496, 18, 102290, {1, 3, 3, 11, 1, 25, 17, 165, 77, 455, 1983, 143, 2763, 8165, 14849, 1601, 30093, 54599}},
+{19497, 18, 102296, {1, 1, 7, 3, 7, 1, 117, 117, 53, 611, 1405, 3357, 1717, 8157, 247, 17501, 30201, 192485}},
+{19498, 18, 102306, {1, 1, 1, 5, 23, 47, 95, 173, 133, 603, 1627, 4039, 5599, 10575, 30275, 60287, 3313, 77551}},
+{19499, 18, 102317, {1, 1, 1, 9, 31, 49, 87, 169, 221, 561, 1045, 365, 1955, 9905, 13057, 33717, 91203, 57513}},
+{19500, 18, 102337, {1, 3, 3, 1, 19, 25, 113, 231, 415, 717, 1767, 755, 4825, 7541, 10121, 9351, 72093, 255877}},
+{19501, 18, 102344, {1, 3, 1, 7, 1, 35, 3, 231, 345, 375, 809, 2753, 849, 13915, 16127, 7575, 45259, 28917}},
+{19502, 18, 102350, {1, 3, 3, 11, 23, 43, 13, 37, 305, 765, 517, 333, 473, 14949, 11939, 35171, 63963, 181825}},
+{19503, 18, 102378, {1, 3, 3, 3, 5, 43, 35, 89, 293, 913, 1325, 2097, 603, 14365, 4005, 38935, 23837, 34271}},
+{19504, 18, 102383, {1, 1, 3, 15, 1, 47, 67, 199, 167, 909, 1167, 1513, 7087, 5017, 23469, 2621, 24961, 226679}},
+{19505, 18, 102391, {1, 3, 7, 15, 23, 37, 111, 217, 33, 423, 457, 1767, 4821, 10233, 27045, 33397, 85351, 156751}},
+{19506, 18, 102400, {1, 3, 3, 7, 31, 25, 67, 65, 291, 169, 1505, 1707, 4833, 11541, 1189, 62959, 59831, 48729}},
+{19507, 18, 102409, {1, 1, 5, 7, 27, 27, 15, 23, 189, 819, 709, 3591, 2781, 14807, 20303, 27795, 88349, 210251}},
+{19508, 18, 102427, {1, 3, 7, 15, 1, 19, 49, 103, 219, 85, 1281, 3981, 7229, 10427, 11689, 1547, 90747, 12283}},
+{19509, 18, 102434, {1, 1, 1, 13, 31, 49, 81, 121, 287, 851, 333, 353, 7373, 10165, 1157, 11713, 89445, 210709}},
+{19510, 18, 102453, {1, 3, 7, 5, 31, 35, 3, 229, 443, 973, 1971, 1861, 5695, 6725, 6405, 45927, 115313, 228667}},
+{19511, 18, 102472, {1, 3, 3, 11, 29, 17, 105, 203, 69, 945, 1239, 3213, 6005, 10095, 31233, 37421, 62911, 91371}},
+{19512, 18, 102502, {1, 1, 7, 1, 21, 59, 7, 43, 391, 299, 1225, 283, 3351, 11495, 25071, 16619, 65127, 114033}},
+{19513, 18, 102525, {1, 1, 3, 9, 17, 11, 71, 73, 377, 437, 311, 1083, 6941, 1039, 1047, 55647, 21239, 209201}},
+{19514, 18, 102547, {1, 3, 7, 5, 29, 51, 113, 163, 215, 511, 615, 2427, 2747, 14389, 1005, 27015, 31809, 30603}},
+{19515, 18, 102554, {1, 1, 1, 3, 9, 61, 9, 201, 259, 411, 175, 1003, 401, 13695, 13103, 3075, 43695, 177139}},
+{19516, 18, 102560, {1, 1, 5, 3, 17, 47, 125, 173, 277, 17, 619, 2295, 3091, 5615, 4529, 54065, 81875, 97279}},
+{19517, 18, 102578, {1, 3, 3, 9, 3, 61, 97, 151, 287, 671, 1439, 1129, 6343, 8161, 24593, 40371, 109705, 106279}},
+{19518, 18, 102580, {1, 3, 3, 1, 5, 61, 21, 31, 41, 855, 1541, 3351, 575, 3195, 17155, 46913, 1797, 146401}},
+{19519, 18, 102597, {1, 1, 7, 13, 11, 43, 27, 97, 479, 117, 1873, 3103, 1947, 9273, 29171, 35719, 10601, 209629}},
+{19520, 18, 102616, {1, 3, 1, 9, 21, 47, 53, 129, 85, 505, 165, 3437, 5687, 10289, 6615, 46719, 50731, 25271}},
+{19521, 18, 102625, {1, 1, 3, 1, 1, 33, 37, 239, 45, 565, 1907, 3831, 2177, 10967, 12689, 49395, 36289, 247507}},
+{19522, 18, 102632, {1, 1, 5, 1, 19, 57, 75, 245, 59, 967, 1319, 3971, 5267, 11713, 15417, 60503, 63431, 157267}},
+{19523, 18, 102663, {1, 1, 5, 7, 7, 15, 99, 87, 331, 261, 1973, 219, 3063, 4071, 19273, 48637, 128089, 55511}},
+{19524, 18, 102669, {1, 3, 5, 13, 23, 43, 7, 171, 173, 1023, 1145, 3551, 5127, 6365, 18013, 1613, 51997, 107265}},
+{19525, 18, 102681, {1, 3, 5, 3, 7, 7, 23, 195, 251, 387, 1889, 3645, 4221, 6025, 27291, 24831, 123749, 231403}},
+{19526, 18, 102694, {1, 3, 1, 1, 29, 49, 107, 215, 93, 211, 1349, 1925, 7149, 1015, 27465, 34139, 126149, 121349}},
+{19527, 18, 102706, {1, 1, 5, 5, 19, 15, 121, 189, 167, 801, 483, 1955, 8031, 4749, 26665, 64791, 18671, 123221}},
+{19528, 18, 102715, {1, 3, 3, 15, 23, 57, 15, 249, 197, 103, 2021, 1897, 5975, 12821, 6441, 62719, 81415, 232417}},
+{19529, 18, 102723, {1, 1, 3, 9, 17, 45, 111, 225, 103, 121, 1259, 2849, 2235, 2041, 13261, 7929, 76325, 38677}},
+{19530, 18, 102730, {1, 1, 3, 9, 25, 17, 63, 63, 369, 387, 31, 1423, 5699, 12519, 27407, 53193, 963, 123473}},
+{19531, 18, 102743, {1, 3, 3, 13, 3, 59, 59, 3, 367, 357, 1391, 1519, 2619, 2291, 1349, 28275, 21655, 8763}},
+{19532, 18, 102856, {1, 1, 7, 1, 31, 51, 121, 49, 157, 509, 1513, 3247, 3439, 8691, 20729, 17585, 49013, 228695}},
+{19533, 18, 102870, {1, 1, 5, 9, 11, 29, 103, 49, 209, 35, 673, 1409, 2483, 4561, 12435, 46139, 31019, 50929}},
+{19534, 18, 102898, {1, 1, 3, 9, 11, 45, 77, 143, 277, 769, 1151, 3705, 7901, 3735, 31155, 46135, 84061, 254357}},
+{19535, 18, 102926, {1, 3, 3, 3, 5, 51, 95, 7, 155, 121, 1899, 2261, 2915, 6637, 6557, 20535, 20937, 257275}},
+{19536, 18, 102931, {1, 1, 7, 9, 13, 49, 125, 135, 7, 535, 1171, 3501, 1701, 5791, 10121, 9845, 21645, 56451}},
+{19537, 18, 102938, {1, 1, 7, 5, 9, 1, 115, 27, 229, 813, 133, 753, 1959, 13121, 30425, 31059, 114619, 132257}},
+{19538, 18, 102947, {1, 1, 5, 3, 23, 25, 41, 165, 21, 551, 1751, 3563, 731, 15811, 14777, 22327, 82853, 116699}},
+{19539, 18, 102968, {1, 3, 1, 9, 3, 25, 95, 211, 457, 25, 349, 921, 213, 5721, 26725, 19541, 102473, 200845}},
+{19540, 18, 102976, {1, 3, 1, 13, 5, 1, 31, 49, 493, 785, 61, 2603, 5997, 12545, 9793, 32521, 99859, 256105}},
+{19541, 18, 102993, {1, 3, 3, 7, 31, 19, 31, 121, 507, 79, 685, 197, 4027, 12909, 30533, 38427, 38993, 14581}},
+{19542, 18, 103005, {1, 3, 7, 13, 13, 23, 63, 15, 223, 25, 1957, 2527, 6061, 11753, 4835, 34553, 45579, 205805}},
+{19543, 18, 103019, {1, 3, 3, 3, 5, 39, 55, 123, 275, 185, 749, 3227, 8137, 12959, 7243, 20613, 46247, 106127}},
+{19544, 18, 103022, {1, 1, 7, 13, 1, 21, 49, 145, 237, 291, 1721, 2981, 267, 1255, 21817, 39553, 21937, 115307}},
+{19545, 18, 103057, {1, 1, 1, 15, 5, 63, 3, 201, 117, 991, 1049, 1975, 5117, 5799, 28211, 37907, 46799, 240847}},
+{19546, 18, 103080, {1, 3, 3, 5, 25, 15, 29, 111, 201, 857, 319, 2695, 4251, 4303, 28495, 12481, 31979, 107503}},
+{19547, 18, 103100, {1, 1, 3, 11, 3, 27, 81, 55, 489, 983, 293, 3181, 4593, 4759, 18437, 51185, 47701, 75469}},
+{19548, 18, 103106, {1, 3, 1, 3, 11, 25, 113, 243, 365, 299, 1717, 561, 5173, 5983, 7453, 33563, 98519, 162451}},
+{19549, 18, 103126, {1, 3, 1, 5, 1, 21, 3, 87, 267, 483, 1397, 791, 4807, 4649, 13713, 19861, 110471, 51443}},
+{19550, 18, 103173, {1, 3, 7, 5, 31, 9, 13, 251, 351, 609, 841, 3267, 4201, 8771, 6673, 44867, 105221, 189399}},
+{19551, 18, 103202, {1, 1, 3, 1, 13, 43, 47, 153, 331, 1013, 705, 1867, 563, 6361, 7407, 46243, 30521, 213831}},
+{19552, 18, 103207, {1, 3, 3, 7, 29, 41, 3, 179, 319, 877, 905, 3803, 2775, 9729, 5673, 9521, 117887, 37605}},
+{19553, 18, 103219, {1, 1, 5, 5, 11, 49, 111, 195, 467, 931, 849, 2785, 7829, 2291, 29031, 52019, 86493, 213971}},
+{19554, 18, 103226, {1, 1, 3, 11, 13, 11, 81, 81, 419, 621, 181, 1203, 7305, 7857, 16885, 2531, 53127, 35553}},
+{19555, 18, 103228, {1, 1, 5, 1, 19, 35, 75, 131, 159, 211, 319, 2805, 6497, 14759, 28997, 62347, 4013, 233821}},
+{19556, 18, 103248, {1, 3, 3, 15, 1, 55, 107, 105, 35, 369, 1259, 665, 6717, 2555, 7149, 10373, 33153, 105915}},
+{19557, 18, 103274, {1, 3, 7, 5, 31, 13, 27, 207, 359, 355, 2047, 1777, 5555, 12659, 30547, 3655, 86189, 961}},
+{19558, 18, 103288, {1, 3, 7, 9, 9, 55, 7, 117, 57, 115, 745, 501, 2341, 3899, 8229, 10625, 66905, 187959}},
+{19559, 18, 103291, {1, 3, 3, 13, 25, 43, 87, 197, 303, 405, 1459, 3385, 4109, 8325, 24747, 18405, 48845, 96673}},
+{19560, 18, 103293, {1, 3, 5, 3, 21, 37, 109, 9, 183, 585, 1287, 3851, 4939, 1057, 19489, 42603, 32447, 117957}},
+{19561, 18, 103324, {1, 1, 5, 13, 3, 47, 109, 115, 73, 733, 1189, 3773, 7471, 10339, 5093, 50253, 122665, 254381}},
+{19562, 18, 103358, {1, 1, 5, 5, 21, 33, 113, 187, 51, 245, 241, 3887, 4075, 11945, 20883, 18817, 43567, 851}},
+{19563, 18, 103372, {1, 3, 7, 3, 1, 29, 87, 101, 29, 93, 643, 2659, 1753, 4797, 17477, 16087, 43453, 110383}},
+{19564, 18, 103375, {1, 1, 7, 13, 17, 51, 75, 91, 445, 171, 1369, 499, 3753, 14035, 4445, 21437, 86205, 231163}},
+{19565, 18, 103390, {1, 1, 7, 13, 17, 41, 67, 49, 225, 659, 1181, 1751, 5211, 6847, 20339, 34271, 60273, 52315}},
+{19566, 18, 103414, {1, 1, 5, 5, 5, 17, 87, 223, 25, 773, 53, 2447, 6805, 6547, 4429, 46809, 51171, 66457}},
+{19567, 18, 103432, {1, 1, 5, 3, 29, 49, 11, 205, 279, 821, 725, 2425, 443, 211, 6347, 59845, 90763, 237911}},
+{19568, 18, 103446, {1, 1, 3, 9, 31, 7, 49, 1, 229, 755, 517, 809, 2955, 3571, 2385, 33097, 19659, 55397}},
+{19569, 18, 103455, {1, 3, 5, 3, 5, 21, 67, 227, 359, 401, 1697, 2131, 4585, 2661, 3659, 22621, 51639, 245877}},
+{19570, 18, 103471, {1, 1, 7, 5, 11, 7, 57, 133, 9, 917, 427, 2777, 6009, 11393, 29473, 59311, 77095, 176215}},
+{19571, 18, 103474, {1, 1, 7, 5, 13, 29, 101, 15, 293, 7, 797, 437, 3739, 3369, 16917, 19047, 17773, 219541}},
+{19572, 18, 103476, {1, 3, 1, 9, 13, 51, 15, 19, 209, 991, 413, 787, 3797, 14029, 23699, 8591, 40429, 56115}},
+{19573, 18, 103515, {1, 3, 7, 3, 31, 9, 77, 33, 487, 155, 1903, 3023, 8163, 385, 4703, 57511, 102083, 85785}},
+{19574, 18, 103527, {1, 1, 5, 11, 17, 59, 115, 73, 89, 723, 1523, 2671, 1755, 3463, 19861, 31573, 126405, 90215}},
+{19575, 18, 103542, {1, 3, 3, 13, 17, 27, 123, 37, 71, 173, 203, 1245, 7905, 8955, 22589, 56705, 120473, 90129}},
+{19576, 18, 103562, {1, 3, 3, 1, 17, 63, 55, 225, 259, 531, 1493, 2639, 1319, 10865, 17993, 11205, 13253, 111261}},
+{19577, 18, 103569, {1, 1, 1, 11, 25, 17, 41, 45, 385, 1009, 1573, 1797, 527, 543, 14743, 35789, 63871, 112183}},
+{19578, 18, 103572, {1, 1, 7, 15, 15, 57, 109, 127, 143, 955, 1091, 2585, 3429, 11763, 5849, 53805, 116865, 68895}},
+{19579, 18, 103581, {1, 1, 7, 15, 9, 11, 1, 9, 491, 765, 1835, 3825, 5043, 13091, 4123, 19621, 17687, 241015}},
+{19580, 18, 103609, {1, 3, 5, 7, 25, 51, 117, 193, 91, 451, 1871, 3819, 1881, 8065, 25809, 36257, 107955, 37109}},
+{19581, 18, 103612, {1, 3, 1, 15, 5, 5, 101, 7, 59, 859, 977, 2673, 2825, 3291, 26283, 23467, 28383, 257775}},
+{19582, 18, 103618, {1, 3, 3, 15, 17, 43, 87, 191, 85, 829, 653, 327, 1773, 10101, 2707, 18341, 61435, 242215}},
+{19583, 18, 103637, {1, 3, 7, 13, 27, 43, 127, 253, 403, 81, 505, 2841, 1509, 4951, 23791, 18099, 46747, 192717}},
+{19584, 18, 103644, {1, 1, 1, 9, 31, 15, 127, 29, 171, 999, 1919, 4059, 2781, 2475, 8997, 15459, 37003, 217141}},
+{19585, 18, 103653, {1, 3, 3, 1, 31, 41, 67, 31, 171, 719, 789, 645, 3925, 11117, 1241, 63221, 1087, 59789}},
+{19586, 18, 103663, {1, 1, 1, 9, 17, 41, 107, 13, 405, 879, 1955, 3309, 1281, 10601, 13883, 43987, 111691, 130555}},
+{19587, 18, 103671, {1, 3, 7, 9, 21, 17, 127, 243, 51, 689, 1945, 3769, 7121, 7703, 16825, 34893, 32167, 20167}},
+{19588, 18, 103678, {1, 1, 1, 5, 7, 7, 61, 149, 75, 289, 717, 1951, 5917, 13375, 15683, 27507, 10897, 199009}},
+{19589, 18, 103695, {1, 3, 7, 9, 25, 61, 43, 167, 45, 299, 5, 125, 3289, 13685, 10843, 25535, 98383, 143401}},
+{19590, 18, 103698, {1, 1, 3, 15, 21, 27, 37, 45, 233, 179, 611, 3025, 7887, 9421, 16791, 17147, 49013, 33249}},
+{19591, 18, 103720, {1, 3, 7, 15, 19, 43, 43, 9, 255, 295, 649, 811, 1303, 1989, 5401, 53891, 42679, 66879}},
+{19592, 18, 103723, {1, 1, 7, 7, 25, 31, 89, 199, 455, 733, 295, 1157, 4375, 7341, 7823, 6025, 56311, 257579}},
+{19593, 18, 103738, {1, 1, 7, 3, 1, 51, 15, 29, 35, 917, 1839, 741, 1089, 8615, 4967, 34047, 32981, 200693}},
+{19594, 18, 103743, {1, 3, 3, 11, 21, 13, 71, 53, 315, 801, 1015, 3829, 2297, 6649, 28501, 18173, 83121, 107195}},
+{19595, 18, 103745, {1, 1, 7, 7, 1, 5, 127, 103, 435, 707, 7, 1045, 187, 10927, 32395, 24999, 58463, 94069}},
+{19596, 18, 103757, {1, 1, 7, 9, 11, 25, 73, 57, 231, 455, 1033, 2899, 2861, 8811, 21671, 16115, 97807, 221791}},
+{19597, 18, 103810, {1, 3, 5, 11, 11, 19, 105, 37, 181, 1, 1231, 2275, 4789, 13071, 24843, 25901, 123711, 145609}},
+{19598, 18, 103822, {1, 3, 7, 13, 7, 7, 21, 215, 393, 43, 1713, 2921, 1959, 14417, 17109, 55793, 36285, 81731}},
+{19599, 18, 103855, {1, 1, 5, 15, 29, 15, 5, 115, 15, 795, 1535, 2473, 3663, 10123, 20721, 32739, 21141, 217731}},
+{19600, 18, 103887, {1, 1, 3, 1, 15, 13, 21, 49, 293, 689, 985, 3949, 3329, 7167, 16925, 15069, 47345, 192749}},
+{19601, 18, 103905, {1, 3, 3, 7, 5, 27, 85, 11, 337, 651, 777, 1775, 5279, 15229, 21473, 36561, 85293, 27893}},
+{19602, 18, 103915, {1, 3, 7, 1, 15, 29, 7, 199, 71, 893, 1587, 1831, 3891, 3299, 14323, 23165, 28199, 84055}},
+{19603, 18, 103925, {1, 1, 1, 7, 9, 27, 15, 75, 497, 127, 433, 1781, 3711, 12659, 3765, 40827, 112425, 36281}},
+{19604, 18, 103929, {1, 1, 5, 1, 31, 59, 9, 91, 301, 217, 2013, 2015, 265, 3795, 14609, 13389, 5451, 260169}},
+{19605, 18, 103945, {1, 1, 1, 15, 19, 43, 85, 37, 33, 687, 1253, 2615, 4027, 3741, 13971, 21261, 106261, 204233}},
+{19606, 18, 103954, {1, 1, 7, 9, 31, 45, 105, 111, 207, 433, 633, 3949, 8057, 5049, 23657, 12227, 86251, 218077}},
+{19607, 18, 103969, {1, 3, 5, 11, 13, 33, 1, 67, 117, 595, 1835, 287, 2509, 14841, 1525, 15761, 61319, 182531}},
+{19608, 18, 104011, {1, 1, 3, 9, 7, 43, 105, 85, 17, 349, 1769, 3945, 31, 4907, 9373, 22447, 70905, 29189}},
+{19609, 18, 104055, {1, 1, 5, 5, 9, 19, 93, 179, 95, 255, 1807, 2717, 4757, 15025, 19479, 63499, 42441, 236519}},
+{19610, 18, 104111, {1, 1, 1, 1, 21, 35, 1, 101, 343, 1023, 1311, 347, 301, 8419, 23367, 31543, 51661, 148277}},
+{19611, 18, 104116, {1, 1, 7, 11, 23, 37, 113, 207, 147, 743, 1905, 1683, 3733, 5659, 22491, 62129, 111671, 227019}},
+{19612, 18, 104125, {1, 1, 3, 13, 27, 5, 21, 207, 445, 319, 1355, 2541, 2853, 583, 1261, 64477, 18337, 91611}},
+{19613, 18, 104145, {1, 3, 5, 3, 1, 31, 51, 55, 487, 735, 1599, 523, 5323, 10855, 28717, 62103, 18671, 143885}},
+{19614, 18, 104162, {1, 3, 1, 1, 15, 5, 79, 107, 173, 747, 1213, 1151, 875, 12759, 27115, 16403, 31349, 208909}},
+{19615, 18, 104176, {1, 3, 5, 9, 13, 57, 35, 121, 135, 237, 1707, 3655, 8109, 3623, 5119, 27645, 49401, 46453}},
+{19616, 18, 104193, {1, 3, 7, 11, 27, 3, 103, 231, 43, 515, 1279, 499, 1355, 2605, 11587, 33641, 81661, 29441}},
+{19617, 18, 104199, {1, 3, 5, 7, 13, 27, 55, 191, 81, 185, 527, 519, 4555, 3349, 24533, 60635, 40009, 230761}},
+{19618, 18, 104224, {1, 1, 5, 3, 13, 35, 75, 211, 67, 305, 705, 543, 3819, 16265, 9867, 64309, 35047, 24873}},
+{19619, 18, 104236, {1, 3, 1, 1, 11, 37, 75, 3, 145, 327, 1243, 3291, 7127, 5009, 7757, 59567, 90459, 98035}},
+{19620, 18, 104247, {1, 3, 5, 9, 9, 5, 71, 29, 243, 41, 447, 2597, 1243, 12899, 19681, 30523, 90799, 142279}},
+{19621, 18, 104254, {1, 3, 3, 3, 15, 21, 25, 101, 451, 651, 143, 3899, 3377, 4855, 23843, 25047, 87951, 239229}},
+{19622, 18, 104289, {1, 1, 1, 1, 23, 29, 25, 31, 227, 43, 399, 723, 693, 12379, 11343, 46123, 105435, 224997}},
+{19623, 18, 104325, {1, 1, 7, 3, 21, 47, 77, 57, 397, 689, 267, 813, 1279, 1727, 7451, 34025, 90273, 111663}},
+{19624, 18, 104332, {1, 1, 5, 3, 25, 61, 7, 137, 271, 723, 495, 2575, 3695, 4947, 31973, 47835, 107003, 221839}},
+{19625, 18, 104335, {1, 3, 1, 7, 5, 25, 21, 95, 323, 3, 613, 1721, 2551, 8803, 6803, 52765, 34543, 110945}},
+{19626, 18, 104353, {1, 3, 5, 9, 27, 23, 123, 193, 63, 161, 1395, 679, 161, 13719, 29321, 19243, 51947, 229547}},
+{19627, 18, 104363, {1, 3, 5, 15, 15, 37, 127, 103, 439, 513, 989, 1393, 3761, 9109, 20649, 18171, 69939, 117447}},
+{19628, 18, 104371, {1, 1, 7, 9, 7, 57, 87, 159, 195, 821, 57, 2469, 7693, 6759, 32595, 41109, 94785, 53381}},
+{19629, 18, 104373, {1, 3, 3, 7, 17, 63, 41, 7, 437, 469, 1453, 3741, 7591, 5563, 11819, 23861, 129777, 119731}},
+{19630, 18, 104406, {1, 1, 3, 3, 27, 55, 21, 145, 243, 991, 687, 909, 2105, 4485, 9095, 3677, 53819, 183027}},
+{19631, 18, 104412, {1, 1, 1, 15, 13, 61, 27, 81, 95, 37, 1439, 973, 7613, 5749, 16811, 26801, 105745, 8847}},
+{19632, 18, 104440, {1, 3, 1, 9, 15, 17, 111, 61, 27, 373, 89, 2729, 6397, 4899, 11297, 4403, 30657, 207379}},
+{19633, 18, 104459, {1, 3, 5, 15, 19, 9, 19, 19, 497, 667, 105, 601, 6715, 6355, 4231, 19241, 101771, 105651}},
+{19634, 18, 104461, {1, 1, 3, 9, 11, 11, 115, 109, 177, 753, 997, 2119, 5969, 13377, 13285, 25373, 105023, 158393}},
+{19635, 18, 104469, {1, 3, 5, 15, 27, 23, 19, 117, 129, 457, 1973, 2171, 8071, 2093, 13407, 9295, 82967, 184753}},
+{19636, 18, 104479, {1, 1, 7, 5, 1, 45, 9, 25, 307, 629, 1169, 2859, 3987, 11411, 13609, 44993, 26019, 107003}},
+{19637, 18, 104483, {1, 1, 1, 13, 29, 15, 13, 163, 203, 885, 281, 1605, 8001, 899, 4081, 65467, 61283, 198963}},
+{19638, 18, 104490, {1, 1, 3, 5, 27, 9, 89, 193, 375, 633, 1807, 2069, 3467, 3167, 23751, 39115, 90093, 190365}},
+{19639, 18, 104500, {1, 3, 3, 5, 1, 1, 19, 161, 21, 745, 493, 2227, 7993, 3337, 27041, 4817, 58963, 237015}},
+{19640, 18, 104536, {1, 3, 5, 15, 15, 45, 51, 145, 299, 787, 1059, 2407, 1143, 775, 17473, 22235, 18241, 103897}},
+{19641, 18, 104560, {1, 1, 1, 9, 11, 35, 75, 195, 281, 935, 113, 3009, 4797, 7221, 12475, 18563, 10315, 255541}},
+{19642, 18, 104569, {1, 1, 5, 7, 25, 9, 121, 179, 303, 511, 2041, 1485, 529, 13843, 29013, 28139, 63237, 21259}},
+{19643, 18, 104588, {1, 3, 7, 11, 9, 21, 61, 177, 63, 179, 679, 17, 4069, 8929, 14499, 53913, 27925, 48449}},
+{19644, 18, 104591, {1, 3, 5, 3, 9, 27, 111, 247, 253, 175, 1591, 3583, 3351, 9039, 597, 23859, 126585, 157367}},
+{19645, 18, 104621, {1, 1, 7, 9, 1, 9, 29, 1, 273, 89, 767, 1873, 39, 10487, 29857, 23577, 67457, 44571}},
+{19646, 18, 104661, {1, 1, 7, 5, 5, 23, 13, 181, 283, 333, 21, 1409, 5937, 8981, 7445, 61267, 21729, 32677}},
+{19647, 18, 104675, {1, 3, 1, 15, 31, 5, 45, 253, 179, 91, 341, 359, 4269, 7567, 23699, 30589, 42909, 126171}},
+{19648, 18, 104684, {1, 3, 7, 7, 23, 45, 15, 93, 115, 873, 49, 845, 827, 14357, 20163, 41565, 37105, 120331}},
+{19649, 18, 104713, {1, 1, 7, 7, 15, 25, 55, 175, 11, 457, 1537, 1937, 807, 11399, 27751, 16935, 75231, 204039}},
+{19650, 18, 104747, {1, 3, 7, 13, 1, 37, 67, 145, 471, 1013, 1273, 4093, 4449, 4433, 29063, 205, 93249, 140383}},
+{19651, 18, 104750, {1, 3, 1, 13, 1, 57, 85, 223, 349, 125, 863, 2179, 7813, 8817, 1767, 19169, 41367, 65883}},
+{19652, 18, 104757, {1, 3, 3, 15, 21, 39, 3, 31, 67, 505, 271, 505, 5495, 4183, 3631, 4567, 48061, 149565}},
+{19653, 18, 104775, {1, 1, 7, 11, 13, 39, 109, 201, 287, 1013, 1505, 3105, 3845, 1963, 4361, 61753, 29145, 146235}},
+{19654, 18, 104782, {1, 3, 5, 3, 29, 39, 71, 99, 501, 53, 835, 3295, 5335, 1017, 25913, 63637, 115353, 210509}},
+{19655, 18, 104803, {1, 3, 1, 13, 9, 53, 33, 177, 419, 63, 793, 1329, 2261, 11633, 18805, 49771, 47533, 74949}},
+{19656, 18, 104820, {1, 3, 7, 11, 7, 49, 123, 237, 195, 17, 1919, 1911, 4135, 11829, 26307, 34905, 114361, 228655}},
+{19657, 18, 104824, {1, 3, 5, 3, 5, 57, 65, 161, 195, 857, 1187, 2303, 1975, 2555, 26065, 17963, 57403, 136193}},
+{19658, 18, 104829, {1, 1, 3, 11, 1, 5, 105, 217, 229, 769, 1393, 2419, 7751, 14293, 9407, 4569, 30663, 89345}},
+{19659, 18, 104830, {1, 3, 3, 7, 23, 15, 15, 189, 67, 863, 485, 2435, 5145, 10537, 16485, 50369, 118245, 253201}},
+{19660, 18, 104836, {1, 1, 1, 5, 27, 27, 47, 129, 383, 227, 115, 3027, 1575, 15765, 10207, 4885, 125707, 184703}},
+{19661, 18, 104851, {1, 3, 5, 5, 17, 9, 45, 55, 151, 751, 415, 2139, 8071, 2309, 27641, 29743, 47183, 21437}},
+{19662, 18, 104882, {1, 3, 3, 7, 9, 47, 51, 31, 261, 237, 1695, 1065, 4503, 7167, 25791, 39659, 90145, 130481}},
+{19663, 18, 104920, {1, 1, 3, 3, 21, 27, 53, 249, 407, 779, 1315, 1005, 6953, 14959, 2265, 61645, 118623, 254067}},
+{19664, 18, 104941, {1, 3, 1, 9, 13, 25, 33, 225, 467, 325, 1513, 1237, 1569, 8749, 1587, 4699, 19893, 163597}},
+{19665, 18, 104963, {1, 3, 5, 5, 29, 29, 1, 55, 437, 575, 149, 791, 4243, 4405, 22963, 64125, 21631, 25819}},
+{19666, 18, 104989, {1, 3, 5, 3, 25, 9, 19, 27, 419, 139, 2035, 2065, 1925, 11499, 20053, 13161, 15115, 120891}},
+{19667, 18, 104999, {1, 1, 5, 9, 7, 9, 113, 3, 195, 555, 863, 595, 6569, 9819, 14727, 38285, 13737, 130903}},
+{19668, 18, 105006, {1, 1, 3, 7, 19, 17, 35, 107, 489, 285, 247, 3103, 2919, 11163, 2811, 62081, 42989, 24495}},
+{19669, 18, 105040, {1, 3, 1, 15, 17, 5, 123, 221, 117, 689, 1567, 3803, 5801, 14121, 23263, 8851, 41559, 226271}},
+{19670, 18, 105066, {1, 1, 1, 15, 21, 39, 87, 135, 485, 59, 1899, 2483, 2599, 8783, 6129, 55407, 7291, 217117}},
+{19671, 18, 105089, {1, 1, 3, 11, 27, 53, 45, 241, 51, 829, 121, 3047, 6785, 15127, 13923, 47913, 9087, 112005}},
+{19672, 18, 105120, {1, 1, 1, 13, 5, 9, 45, 37, 235, 497, 871, 1471, 2895, 247, 9085, 39611, 63445, 218391}},
+{19673, 18, 105125, {1, 1, 5, 3, 5, 29, 23, 155, 339, 293, 535, 1569, 2625, 2867, 4639, 53049, 88721, 96903}},
+{19674, 18, 105137, {1, 1, 3, 15, 5, 25, 17, 45, 47, 683, 949, 1381, 5929, 9539, 3345, 59883, 19071, 200411}},
+{19675, 18, 105179, {1, 1, 1, 11, 11, 5, 71, 15, 469, 749, 1763, 541, 7109, 11731, 8463, 35145, 121795, 219441}},
+{19676, 18, 105215, {1, 3, 7, 11, 5, 17, 63, 159, 69, 993, 1519, 1531, 6913, 3901, 22131, 42909, 41299, 261813}},
+{19677, 18, 105244, {1, 1, 3, 5, 21, 27, 27, 197, 339, 275, 2011, 2263, 855, 1939, 21561, 30577, 6515, 124417}},
+{19678, 18, 105258, {1, 3, 5, 15, 25, 35, 91, 31, 269, 857, 327, 3643, 3211, 14401, 18399, 9007, 12897, 25555}},
+{19679, 18, 105263, {1, 1, 7, 15, 19, 47, 127, 157, 407, 867, 943, 1509, 3113, 49, 32131, 46975, 130013, 66457}},
+{19680, 18, 105280, {1, 3, 3, 13, 31, 45, 59, 135, 67, 825, 157, 2441, 2851, 2355, 28115, 14075, 106317, 145945}},
+{19681, 18, 105286, {1, 1, 1, 15, 27, 27, 5, 211, 85, 749, 671, 1341, 6865, 10027, 14419, 20159, 126647, 147893}},
+{19682, 18, 105380, {1, 1, 1, 7, 25, 49, 115, 231, 65, 161, 1409, 573, 2859, 639, 12567, 58459, 73781, 136893}},
+{19683, 18, 105397, {1, 1, 1, 7, 11, 57, 97, 141, 327, 975, 1799, 3051, 365, 9331, 14583, 16723, 113153, 224127}},
+{19684, 18, 105409, {1, 3, 1, 13, 13, 17, 105, 109, 151, 41, 1903, 1685, 2285, 5697, 16559, 34133, 106045, 203217}},
+{19685, 18, 105427, {1, 1, 1, 3, 29, 61, 43, 255, 269, 277, 1847, 3781, 7991, 131, 9833, 34305, 10763, 41869}},
+{19686, 18, 105452, {1, 1, 7, 3, 11, 1, 85, 89, 247, 99, 419, 2041, 3729, 10301, 5291, 36033, 31749, 261871}},
+{19687, 18, 105469, {1, 3, 7, 9, 27, 27, 41, 3, 303, 893, 697, 1631, 5015, 4233, 22827, 3913, 22245, 121193}},
+{19688, 18, 105472, {1, 3, 3, 13, 19, 11, 15, 239, 419, 123, 1213, 185, 4465, 4909, 25421, 18363, 72537, 167939}},
+{19689, 18, 105477, {1, 1, 3, 5, 13, 49, 57, 197, 19, 877, 1465, 2933, 5909, 7147, 1039, 37035, 91209, 126013}},
+{19690, 18, 105490, {1, 1, 3, 5, 23, 7, 63, 179, 59, 47, 1501, 1863, 2949, 13959, 28131, 29705, 107975, 155251}},
+{19691, 18, 105505, {1, 1, 1, 5, 25, 51, 77, 169, 327, 585, 1531, 3367, 3075, 6313, 26725, 453, 68635, 173787}},
+{19692, 18, 105529, {1, 3, 7, 9, 5, 15, 43, 45, 311, 367, 297, 2249, 7507, 4785, 22685, 37279, 121683, 141453}},
+{19693, 18, 105530, {1, 3, 7, 15, 17, 33, 43, 251, 281, 345, 1659, 3729, 7629, 6179, 26107, 64255, 88003, 2545}},
+{19694, 18, 105604, {1, 3, 7, 9, 17, 13, 71, 49, 341, 495, 1975, 173, 5773, 3821, 6615, 50917, 53781, 75557}},
+{19695, 18, 105614, {1, 1, 5, 13, 17, 21, 121, 35, 195, 367, 1191, 1331, 6423, 8425, 7705, 59117, 44575, 225431}},
+{19696, 18, 105622, {1, 1, 1, 5, 25, 39, 89, 65, 449, 491, 211, 2949, 4493, 23, 22571, 4801, 50525, 222563}},
+{19697, 18, 105625, {1, 1, 7, 5, 7, 21, 15, 171, 443, 225, 577, 1841, 8139, 15071, 6095, 60185, 71957, 244753}},
+{19698, 18, 105652, {1, 1, 5, 9, 31, 33, 21, 195, 415, 1003, 441, 627, 2339, 8245, 11187, 55933, 59045, 177455}},
+{19699, 18, 105687, {1, 1, 3, 9, 31, 29, 7, 15, 31, 577, 1435, 1317, 2923, 3807, 29693, 45857, 61787, 213565}},
+{19700, 18, 105693, {1, 3, 7, 15, 17, 51, 65, 87, 295, 811, 753, 1113, 7695, 275, 28331, 46363, 53247, 166993}},
+{19701, 18, 105707, {1, 1, 5, 11, 15, 31, 31, 47, 273, 383, 1831, 3821, 1337, 13257, 415, 35453, 15293, 173095}},
+{19702, 18, 105721, {1, 3, 1, 13, 19, 21, 63, 199, 159, 475, 1257, 3119, 7083, 2861, 21099, 16873, 83583, 186289}},
+{19703, 18, 105730, {1, 1, 7, 13, 15, 23, 11, 103, 387, 899, 261, 2863, 3681, 5683, 5587, 64655, 7411, 148633}},
+{19704, 18, 105736, {1, 3, 1, 13, 1, 45, 5, 173, 379, 287, 1451, 2253, 3811, 10963, 20285, 59681, 81285, 48523}},
+{19705, 18, 105753, {1, 1, 5, 9, 27, 17, 57, 25, 499, 289, 1083, 3057, 793, 5251, 10519, 36647, 67751, 237487}},
+{19706, 18, 105759, {1, 1, 3, 1, 17, 13, 23, 73, 1, 951, 111, 3769, 3611, 4827, 10081, 55919, 21411, 127303}},
+{19707, 18, 105760, {1, 3, 1, 1, 29, 35, 93, 139, 179, 217, 1839, 1907, 4365, 1813, 31985, 28927, 39319, 233413}},
+{19708, 18, 105802, {1, 1, 1, 7, 7, 47, 37, 127, 449, 473, 311, 3833, 3263, 4163, 15985, 50159, 82685, 73273}},
+{19709, 18, 105822, {1, 1, 1, 3, 3, 5, 69, 95, 101, 115, 1575, 63, 1897, 13733, 22149, 8793, 82983, 192553}},
+{19710, 18, 105832, {1, 3, 1, 5, 3, 57, 121, 13, 291, 975, 505, 3105, 6929, 12737, 25869, 29173, 16757, 17733}},
+{19711, 18, 105865, {1, 1, 3, 13, 13, 23, 51, 51, 239, 795, 877, 1547, 6533, 11497, 14309, 32941, 128109, 187313}},
+{19712, 18, 105873, {1, 1, 3, 5, 19, 37, 57, 223, 509, 379, 1235, 1881, 4133, 13219, 5479, 36781, 56155, 231001}},
+{19713, 18, 105874, {1, 1, 1, 5, 25, 45, 111, 183, 37, 875, 1487, 3771, 5593, 6835, 10921, 40697, 114455, 259491}},
+{19714, 18, 105880, {1, 1, 3, 11, 13, 5, 43, 47, 7, 435, 1543, 3835, 1631, 8889, 23567, 24705, 26687, 14261}},
+{19715, 18, 105899, {1, 3, 3, 11, 1, 13, 51, 171, 433, 1011, 679, 1307, 1683, 7379, 7163, 29727, 40209, 259973}},
+{19716, 18, 105902, {1, 3, 1, 5, 25, 33, 111, 11, 303, 815, 1883, 263, 7907, 12637, 19203, 64151, 55739, 240509}},
+{19717, 18, 105909, {1, 3, 5, 7, 23, 51, 3, 183, 425, 47, 231, 807, 1891, 10943, 17873, 20209, 60871, 30269}},
+{19718, 18, 105919, {1, 1, 1, 1, 1, 23, 11, 183, 351, 5, 37, 3883, 1291, 15933, 11379, 53057, 61389, 240547}},
+{19719, 18, 105922, {1, 3, 1, 5, 7, 53, 97, 29, 239, 805, 1929, 1001, 5103, 11, 24695, 7825, 109755, 254717}},
+{19720, 18, 105946, {1, 3, 3, 11, 15, 37, 115, 117, 391, 313, 1761, 3627, 3931, 10277, 1767, 25401, 123827, 60463}},
+{19721, 18, 105975, {1, 1, 7, 9, 9, 61, 23, 65, 473, 579, 1979, 415, 629, 3613, 27409, 46909, 3281, 3883}},
+{19722, 18, 105992, {1, 3, 3, 13, 25, 17, 71, 247, 297, 451, 153, 1949, 2727, 6427, 19815, 54013, 129363, 248237}},
+{19723, 18, 106005, {1, 1, 7, 7, 29, 9, 57, 171, 159, 287, 693, 1365, 4665, 5255, 15013, 21225, 125409, 5893}},
+{19724, 18, 106057, {1, 3, 3, 1, 9, 43, 13, 139, 359, 267, 115, 2025, 693, 4789, 10353, 60459, 30835, 56575}},
+{19725, 18, 106081, {1, 1, 1, 7, 23, 35, 35, 77, 245, 705, 75, 2841, 1683, 6109, 19661, 49021, 25019, 7297}},
+{19726, 18, 106093, {1, 3, 1, 5, 1, 19, 49, 53, 19, 435, 1471, 409, 7051, 7057, 3621, 42925, 59551, 70941}},
+{19727, 18, 106117, {1, 3, 7, 5, 21, 27, 39, 221, 389, 255, 537, 597, 7729, 10473, 6657, 13261, 11303, 112409}},
+{19728, 18, 106127, {1, 3, 7, 13, 29, 29, 81, 107, 329, 25, 537, 561, 2247, 10371, 30031, 20537, 28437, 113319}},
+{19729, 18, 106135, {1, 1, 5, 9, 9, 7, 89, 155, 337, 829, 755, 3259, 3563, 11849, 31179, 43297, 79601, 187545}},
+{19730, 18, 106141, {1, 3, 3, 5, 11, 63, 101, 159, 357, 627, 587, 3233, 405, 4083, 5953, 44541, 110723, 240573}},
+{19731, 18, 106189, {1, 1, 3, 15, 5, 39, 87, 231, 455, 195, 1603, 315, 3869, 6375, 745, 28349, 56469, 119033}},
+{19732, 18, 106190, {1, 1, 7, 1, 11, 7, 79, 47, 391, 585, 1299, 3237, 7345, 15959, 4293, 43285, 111737, 215923}},
+{19733, 18, 106197, {1, 1, 3, 15, 21, 53, 113, 73, 265, 589, 299, 289, 3983, 1653, 17407, 15287, 53199, 44221}},
+{19734, 18, 106214, {1, 3, 1, 3, 1, 13, 31, 41, 509, 523, 401, 2647, 2731, 5699, 15649, 51737, 81249, 230865}},
+{19735, 18, 106237, {1, 3, 5, 3, 15, 53, 91, 209, 249, 243, 1119, 2531, 319, 9259, 26555, 59579, 28767, 235073}},
+{19736, 18, 106245, {1, 1, 1, 13, 29, 25, 57, 3, 413, 945, 841, 1151, 7167, 2545, 7283, 3947, 109375, 148677}},
+{19737, 18, 106257, {1, 3, 3, 7, 29, 27, 81, 141, 21, 771, 577, 897, 73, 13081, 30035, 49213, 90627, 7483}},
+{19738, 18, 106300, {1, 3, 1, 13, 23, 11, 19, 159, 183, 789, 683, 2071, 7107, 3025, 27333, 9571, 69621, 48529}},
+{19739, 18, 106335, {1, 3, 1, 9, 5, 43, 7, 123, 341, 75, 1709, 135, 7929, 14563, 6849, 32783, 91971, 223789}},
+{19740, 18, 106351, {1, 1, 7, 3, 19, 13, 45, 229, 7, 559, 1895, 2649, 7593, 1063, 17715, 45019, 29743, 37819}},
+{19741, 18, 106370, {1, 1, 5, 3, 11, 25, 11, 169, 249, 415, 249, 209, 2223, 5947, 23381, 12109, 37697, 131729}},
+{19742, 18, 106375, {1, 1, 1, 7, 19, 47, 125, 117, 235, 825, 801, 921, 2363, 1261, 20529, 65445, 55315, 173561}},
+{19743, 18, 106376, {1, 1, 1, 1, 5, 39, 31, 11, 239, 333, 727, 3991, 1453, 2201, 18129, 3513, 112057, 109673}},
+{19744, 18, 106384, {1, 1, 7, 5, 21, 59, 37, 255, 261, 1, 1401, 1101, 1233, 3813, 22809, 39389, 66263, 191623}},
+{19745, 18, 106403, {1, 3, 1, 7, 5, 51, 73, 85, 319, 671, 1149, 1631, 6021, 10711, 3813, 36485, 106147, 202021}},
+{19746, 18, 106405, {1, 3, 3, 13, 7, 63, 59, 253, 337, 453, 61, 209, 2809, 10429, 28069, 55971, 57985, 244779}},
+{19747, 18, 106406, {1, 1, 1, 9, 27, 59, 45, 101, 427, 713, 1667, 2965, 6161, 1235, 8793, 2387, 66031, 85151}},
+{19748, 18, 106429, {1, 1, 3, 1, 5, 25, 101, 7, 449, 149, 823, 725, 6803, 11949, 13009, 14785, 45633, 241957}},
+{19749, 18, 106447, {1, 3, 7, 15, 29, 45, 103, 151, 159, 23, 1353, 3541, 5909, 4173, 31391, 16179, 38289, 206603}},
+{19750, 18, 106466, {1, 1, 7, 7, 23, 3, 97, 29, 141, 383, 379, 3189, 4399, 4545, 30797, 55827, 126223, 97049}},
+{19751, 18, 106495, {1, 3, 3, 7, 25, 35, 61, 15, 349, 929, 65, 3697, 7637, 12239, 29051, 36001, 114513, 151069}},
+{19752, 18, 106532, {1, 3, 3, 11, 19, 1, 23, 245, 9, 689, 1251, 1043, 2393, 15817, 31561, 21059, 3435, 228091}},
+{19753, 18, 106542, {1, 3, 7, 3, 23, 17, 121, 147, 427, 47, 905, 3877, 2301, 15709, 13599, 48895, 108955, 53219}},
+{19754, 18, 106547, {1, 3, 7, 3, 25, 31, 53, 143, 1, 841, 1691, 749, 6713, 5373, 23487, 25749, 13911, 240923}},
+{19755, 18, 106564, {1, 3, 5, 3, 7, 39, 101, 83, 159, 187, 583, 721, 7745, 1119, 61, 27319, 35157, 241729}},
+{19756, 18, 106576, {1, 1, 5, 11, 27, 21, 79, 199, 179, 463, 987, 3909, 1741, 503, 12339, 15323, 4063, 180337}},
+{19757, 18, 106586, {1, 3, 7, 11, 23, 43, 7, 115, 489, 215, 209, 3213, 4057, 13221, 27061, 52037, 34921, 36385}},
+{19758, 18, 106592, {1, 1, 7, 1, 15, 13, 113, 55, 207, 839, 1939, 4095, 5629, 7647, 12753, 59739, 60779, 196589}},
+{19759, 18, 106597, {1, 1, 1, 5, 5, 13, 113, 243, 297, 513, 1615, 1513, 1247, 4025, 20901, 44775, 86987, 75437}},
+{19760, 18, 106610, {1, 1, 3, 7, 7, 35, 77, 115, 223, 929, 1683, 949, 2191, 15533, 29471, 24103, 102475, 173027}},
+{19761, 18, 106612, {1, 3, 1, 11, 23, 37, 7, 179, 287, 267, 319, 3147, 1481, 12297, 28185, 51423, 7505, 236225}},
+{19762, 18, 106635, {1, 1, 3, 5, 27, 5, 71, 95, 289, 121, 939, 3543, 365, 4903, 10091, 3903, 111155, 83517}},
+{19763, 18, 106640, {1, 1, 7, 9, 29, 3, 87, 245, 313, 973, 1181, 3389, 3697, 13237, 13703, 31557, 17269, 17329}},
+{19764, 18, 106673, {1, 1, 5, 11, 5, 41, 117, 51, 239, 907, 809, 741, 5327, 3403, 11825, 46981, 93485, 38053}},
+{19765, 18, 106691, {1, 1, 7, 1, 25, 41, 5, 169, 11, 599, 1451, 2189, 7255, 8441, 11169, 58313, 4387, 69}},
+{19766, 18, 106724, {1, 3, 1, 13, 5, 21, 75, 229, 153, 355, 1511, 175, 4793, 12111, 25321, 39983, 84205, 195003}},
+{19767, 18, 106731, {1, 1, 7, 1, 17, 61, 67, 181, 69, 149, 921, 1107, 6319, 431, 29481, 12507, 13109, 29527}},
+{19768, 18, 106741, {1, 1, 5, 5, 27, 47, 69, 119, 469, 193, 513, 1573, 7421, 2723, 20997, 59585, 49645, 261259}},
+{19769, 18, 106748, {1, 1, 3, 9, 27, 41, 41, 3, 181, 803, 1281, 2937, 6745, 5629, 8403, 18987, 98411, 128321}},
+{19770, 18, 106765, {1, 3, 3, 9, 5, 29, 55, 223, 309, 841, 1049, 1163, 3497, 8935, 8529, 51367, 90693, 77463}},
+{19771, 18, 106789, {1, 3, 5, 3, 3, 59, 23, 31, 309, 907, 107, 3471, 4365, 14463, 24093, 35435, 24587, 151163}},
+{19772, 18, 106822, {1, 3, 3, 1, 11, 37, 99, 95, 485, 601, 1797, 891, 5645, 8927, 22085, 5185, 18495, 260455}},
+{19773, 18, 106856, {1, 3, 7, 15, 31, 61, 5, 177, 159, 287, 311, 1377, 1419, 4387, 25297, 22505, 100937, 223785}},
+{19774, 18, 106861, {1, 3, 3, 3, 27, 31, 45, 171, 95, 507, 1475, 4013, 2781, 133, 6857, 3367, 103455, 69559}},
+{19775, 18, 106870, {1, 3, 3, 7, 9, 51, 47, 247, 213, 665, 1929, 2799, 5513, 9183, 20197, 14831, 75277, 187565}},
+{19776, 18, 106883, {1, 3, 1, 9, 13, 11, 15, 253, 145, 31, 847, 1579, 5513, 9, 3327, 46049, 16709, 56353}},
+{19777, 18, 106895, {1, 3, 3, 3, 9, 17, 59, 131, 3, 621, 1209, 3415, 2999, 127, 629, 7925, 6109, 59743}},
+{19778, 18, 106928, {1, 1, 5, 15, 29, 35, 87, 197, 495, 671, 51, 293, 3943, 7969, 4739, 10161, 119943, 97217}},
+{19779, 18, 106938, {1, 1, 1, 9, 25, 57, 61, 197, 139, 899, 783, 3835, 3407, 16301, 19033, 33359, 56309, 16237}},
+{19780, 18, 106979, {1, 1, 5, 11, 25, 47, 95, 121, 197, 511, 227, 2281, 5805, 10581, 14885, 19685, 28075, 25431}},
+{19781, 18, 106985, {1, 1, 3, 9, 1, 43, 59, 105, 319, 45, 1567, 905, 7641, 2199, 3979, 13717, 22829, 44777}},
+{19782, 18, 107005, {1, 3, 7, 1, 19, 49, 105, 53, 227, 293, 989, 697, 2553, 4561, 14851, 8999, 74815, 207475}},
+{19783, 18, 107012, {1, 1, 5, 11, 23, 3, 85, 29, 419, 847, 1385, 3857, 641, 14951, 25629, 18019, 2497, 24723}},
+{19784, 18, 107019, {1, 3, 5, 15, 5, 11, 51, 225, 179, 695, 787, 663, 7051, 3595, 4987, 53315, 88693, 7915}},
+{19785, 18, 107045, {1, 3, 1, 13, 17, 51, 51, 247, 431, 555, 603, 3301, 443, 629, 26509, 32047, 54433, 208297}},
+{19786, 18, 107052, {1, 3, 7, 7, 13, 41, 95, 105, 135, 443, 377, 1259, 3301, 6945, 11677, 33869, 107799, 186567}},
+{19787, 18, 107082, {1, 1, 5, 7, 31, 17, 85, 129, 409, 781, 983, 25, 6877, 83, 12625, 31919, 41989, 55195}},
+{19788, 18, 107089, {1, 1, 3, 3, 7, 45, 37, 45, 237, 967, 1371, 657, 7983, 3121, 32707, 25757, 49987, 92683}},
+{19789, 18, 107118, {1, 3, 1, 1, 19, 57, 63, 25, 355, 893, 2017, 1671, 7343, 4451, 28243, 22157, 103901, 178017}},
+{19790, 18, 107163, {1, 3, 7, 13, 17, 59, 81, 99, 329, 117, 1395, 2565, 5725, 2371, 343, 4713, 35077, 49793}},
+{19791, 18, 107202, {1, 3, 7, 15, 31, 19, 87, 243, 411, 339, 1063, 117, 1827, 1583, 12571, 23153, 3363, 81695}},
+{19792, 18, 107238, {1, 3, 7, 1, 3, 49, 95, 133, 295, 433, 1885, 843, 6679, 13673, 32277, 59085, 46957, 217037}},
+{19793, 18, 107242, {1, 1, 3, 9, 23, 53, 45, 183, 79, 55, 1267, 283, 3249, 4101, 8107, 54473, 126141, 127235}},
+{19794, 18, 107244, {1, 3, 5, 7, 19, 57, 113, 205, 37, 817, 929, 3643, 2231, 15725, 1733, 7877, 116741, 254529}},
+{19795, 18, 107264, {1, 3, 1, 9, 9, 7, 75, 45, 83, 203, 1401, 445, 1043, 239, 30865, 32189, 91081, 180681}},
+{19796, 18, 107273, {1, 1, 7, 7, 1, 3, 61, 255, 483, 599, 897, 1601, 5189, 13279, 4981, 37235, 117505, 66625}},
+{19797, 18, 107291, {1, 1, 3, 13, 29, 43, 65, 73, 213, 307, 959, 2735, 5155, 16063, 15745, 6225, 50159, 182445}},
+{19798, 18, 107293, {1, 1, 3, 9, 31, 61, 73, 185, 457, 687, 1887, 4041, 3455, 4739, 16399, 40929, 32631, 179031}},
+{19799, 18, 107312, {1, 3, 3, 15, 5, 45, 1, 241, 187, 23, 63, 2497, 7759, 9175, 11003, 40579, 45769, 107133}},
+{19800, 18, 107318, {1, 3, 3, 7, 5, 63, 7, 67, 31, 917, 1825, 2037, 2527, 9767, 2665, 18573, 14289, 21583}},
+{19801, 18, 107335, {1, 1, 5, 15, 15, 25, 51, 127, 261, 925, 1651, 769, 7779, 7327, 7239, 20437, 9947, 144697}},
+{19802, 18, 107349, {1, 1, 5, 1, 5, 13, 99, 7, 269, 135, 345, 1851, 7963, 457, 24573, 32529, 127359, 157755}},
+{19803, 18, 107350, {1, 3, 5, 15, 21, 17, 31, 115, 321, 351, 117, 1301, 2455, 3363, 14213, 62903, 75273, 261119}},
+{19804, 18, 107363, {1, 3, 7, 1, 1, 9, 53, 209, 319, 489, 827, 1365, 4709, 7419, 28213, 56095, 9611, 234877}},
+{19805, 18, 107390, {1, 1, 5, 5, 1, 7, 49, 15, 377, 309, 1701, 1775, 5571, 12437, 27521, 54753, 68977, 138549}},
+{19806, 18, 107405, {1, 1, 3, 11, 9, 29, 67, 21, 411, 647, 983, 1075, 2387, 13355, 1781, 56129, 87235, 260133}},
+{19807, 18, 107408, {1, 3, 1, 11, 5, 57, 71, 159, 345, 853, 745, 3733, 1607, 7265, 20097, 18911, 101141, 70495}},
+{19808, 18, 107427, {1, 1, 3, 9, 1, 43, 127, 127, 471, 465, 1777, 1879, 4655, 12925, 24935, 58445, 78303, 200463}},
+{19809, 18, 107433, {1, 1, 1, 15, 5, 33, 63, 17, 401, 831, 1559, 3547, 7869, 13901, 18185, 9399, 65859, 185315}},
+{19810, 18, 107444, {1, 3, 7, 1, 25, 21, 17, 175, 401, 833, 847, 3593, 1283, 14745, 11827, 1987, 89299, 187369}},
+{19811, 18, 107514, {1, 1, 7, 13, 29, 31, 45, 219, 177, 369, 1313, 3015, 5859, 1829, 8793, 49109, 97581, 233179}},
+{19812, 18, 107522, {1, 3, 3, 15, 17, 31, 61, 215, 231, 495, 1307, 3067, 3187, 8813, 22505, 14055, 30773, 177955}},
+{19813, 18, 107545, {1, 3, 7, 15, 9, 61, 57, 105, 89, 267, 233, 905, 3727, 1841, 31875, 32499, 27003, 208491}},
+{19814, 18, 107582, {1, 3, 1, 11, 31, 9, 63, 55, 213, 209, 1625, 2635, 4335, 15201, 6127, 11097, 37991, 62813}},
+{19815, 18, 107590, {1, 1, 1, 5, 13, 49, 127, 249, 339, 525, 1943, 2935, 3255, 5199, 6869, 6325, 731, 51085}},
+{19816, 18, 107593, {1, 1, 5, 7, 7, 29, 59, 187, 463, 409, 1321, 377, 7361, 8303, 20385, 39649, 81379, 235555}},
+{19817, 18, 107599, {1, 1, 5, 13, 15, 45, 99, 57, 217, 535, 1747, 4081, 4781, 1005, 25197, 23853, 90587, 189579}},
+{19818, 18, 107604, {1, 1, 7, 7, 23, 31, 1, 151, 339, 447, 523, 2609, 5917, 6965, 25815, 62797, 104083, 245917}},
+{19819, 18, 107608, {1, 3, 5, 3, 7, 37, 79, 253, 423, 511, 1477, 3121, 5557, 1413, 31075, 22249, 117639, 243543}},
+{19820, 18, 107627, {1, 1, 3, 7, 5, 31, 93, 117, 135, 235, 745, 3287, 4451, 2487, 15179, 62229, 18247, 150277}},
+{19821, 18, 107638, {1, 1, 7, 15, 31, 57, 125, 219, 433, 629, 1809, 2499, 6083, 7631, 31495, 63183, 28533, 120579}},
+{19822, 18, 107666, {1, 1, 1, 13, 31, 47, 77, 73, 343, 867, 1055, 1121, 3035, 15693, 6971, 50231, 16527, 190795}},
+{19823, 18, 107678, {1, 3, 7, 7, 11, 1, 5, 215, 87, 885, 1429, 1277, 3831, 9341, 22011, 34585, 56167, 65301}},
+{19824, 18, 107701, {1, 3, 1, 15, 13, 53, 91, 59, 277, 819, 453, 3191, 757, 4729, 20605, 4283, 110745, 233655}},
+{19825, 18, 107720, {1, 3, 3, 5, 17, 47, 69, 117, 113, 775, 935, 1879, 2239, 5877, 18337, 50895, 44891, 2759}},
+{19826, 18, 107723, {1, 3, 5, 1, 27, 31, 77, 65, 355, 405, 825, 2419, 3337, 10179, 27665, 35459, 13721, 154227}},
+{19827, 18, 107725, {1, 3, 3, 7, 23, 61, 9, 241, 239, 85, 485, 2659, 5371, 16175, 28691, 49109, 124433, 167033}},
+{19828, 18, 107731, {1, 3, 3, 3, 11, 57, 37, 155, 443, 249, 1913, 1347, 6569, 5357, 4231, 58273, 50707, 57097}},
+{19829, 18, 107737, {1, 1, 3, 3, 1, 7, 87, 115, 259, 807, 45, 2997, 63, 16313, 12507, 39925, 17699, 24411}},
+{19830, 18, 107767, {1, 3, 3, 1, 19, 59, 97, 209, 247, 395, 21, 1803, 2547, 11607, 15703, 58099, 111907, 196101}},
+{19831, 18, 107779, {1, 1, 7, 13, 27, 61, 73, 183, 493, 953, 445, 567, 7373, 15275, 30081, 539, 89365, 3455}},
+{19832, 18, 107788, {1, 3, 1, 3, 25, 35, 3, 105, 243, 781, 1937, 2781, 7849, 2159, 2221, 58005, 89313, 182183}},
+{19833, 18, 107799, {1, 1, 7, 15, 21, 7, 67, 163, 179, 453, 581, 2245, 3915, 8985, 16809, 35113, 93605, 79009}},
+{19834, 18, 107819, {1, 1, 7, 5, 29, 57, 13, 75, 387, 511, 331, 1119, 307, 6145, 3841, 49987, 67335, 120419}},
+{19835, 18, 107833, {1, 3, 1, 5, 13, 21, 119, 207, 453, 943, 137, 2245, 7771, 5737, 9541, 29209, 106867, 110513}},
+{19836, 18, 107881, {1, 3, 7, 13, 7, 3, 99, 129, 245, 687, 883, 1321, 1131, 6661, 7437, 1345, 128247, 167877}},
+{19837, 18, 107901, {1, 1, 3, 11, 7, 57, 59, 3, 217, 549, 85, 2607, 215, 2249, 3963, 42931, 33747, 226265}},
+{19838, 18, 107911, {1, 1, 5, 5, 29, 23, 115, 215, 103, 427, 1689, 831, 3293, 14055, 3735, 49521, 17703, 182887}},
+{19839, 18, 107930, {1, 1, 1, 15, 5, 43, 27, 181, 217, 955, 225, 2731, 7347, 14123, 26169, 4371, 26907, 15017}},
+{19840, 18, 107936, {1, 1, 7, 7, 31, 55, 63, 223, 61, 63, 431, 2779, 3169, 14323, 2945, 63913, 85407, 76511}},
+{19841, 18, 107980, {1, 1, 3, 11, 5, 27, 113, 75, 313, 697, 13, 1853, 7467, 5701, 16749, 17939, 13475, 39807}},
+{19842, 18, 108004, {1, 1, 7, 5, 13, 53, 55, 115, 125, 341, 321, 3291, 2675, 13659, 16819, 45397, 42917, 104361}},
+{19843, 18, 108008, {1, 3, 3, 15, 27, 47, 19, 213, 441, 605, 593, 2287, 4847, 10505, 22185, 36157, 10881, 87799}},
+{19844, 18, 108016, {1, 1, 1, 11, 15, 39, 109, 3, 469, 371, 1743, 2789, 199, 8703, 7407, 3353, 103417, 73319}},
+{19845, 18, 108066, {1, 3, 7, 5, 25, 61, 77, 111, 263, 399, 1579, 3447, 6205, 5945, 28099, 39183, 77003, 115001}},
+{19846, 18, 108071, {1, 1, 1, 3, 1, 7, 57, 193, 379, 923, 151, 2227, 7285, 2371, 24567, 34037, 80655, 125499}},
+{19847, 18, 108107, {1, 3, 5, 7, 13, 15, 5, 193, 55, 319, 1851, 2439, 8071, 5329, 3155, 64669, 18547, 238997}},
+{19848, 18, 108110, {1, 3, 3, 11, 7, 23, 1, 203, 333, 951, 153, 1249, 5093, 407, 361, 14175, 45149, 186291}},
+{19849, 18, 108124, {1, 3, 1, 11, 13, 19, 89, 229, 139, 981, 455, 907, 5109, 8513, 23823, 54933, 69985, 227679}},
+{19850, 18, 108145, {1, 3, 5, 13, 23, 47, 65, 123, 115, 759, 375, 1283, 729, 11045, 22015, 18287, 112603, 75911}},
+{19851, 18, 108148, {1, 1, 3, 1, 5, 43, 91, 123, 219, 409, 517, 3999, 1409, 5949, 15727, 62705, 73573, 198447}},
+{19852, 18, 108158, {1, 3, 3, 3, 5, 23, 95, 51, 275, 455, 1831, 2427, 3779, 10209, 30839, 23393, 25681, 8715}},
+{19853, 18, 108164, {1, 3, 5, 3, 9, 5, 61, 97, 497, 397, 695, 517, 3313, 4911, 1961, 45805, 99135, 216657}},
+{19854, 18, 108197, {1, 1, 1, 7, 13, 41, 19, 31, 103, 1005, 73, 1855, 405, 12395, 19979, 17663, 105183, 28493}},
+{19855, 18, 108198, {1, 3, 1, 11, 27, 27, 69, 149, 1, 225, 1809, 1367, 3663, 6545, 8475, 40837, 64459, 66705}},
+{19856, 18, 108219, {1, 3, 3, 1, 29, 21, 113, 149, 215, 443, 1069, 3437, 1793, 13573, 28285, 33707, 29127, 40715}},
+{19857, 18, 108222, {1, 3, 3, 5, 21, 9, 53, 181, 455, 283, 245, 3999, 875, 9799, 10963, 31603, 34907, 64977}},
+{19858, 18, 108224, {1, 3, 1, 11, 31, 51, 29, 103, 61, 529, 777, 1097, 445, 9169, 6305, 4513, 60189, 164103}},
+{19859, 18, 108227, {1, 1, 1, 3, 21, 5, 87, 11, 461, 637, 1283, 1471, 1429, 2401, 12163, 29401, 30089, 41745}},
+{19860, 18, 108290, {1, 1, 3, 3, 17, 43, 13, 153, 73, 419, 747, 279, 7195, 4383, 26345, 28365, 97753, 208989}},
+{19861, 18, 108302, {1, 3, 7, 1, 17, 55, 103, 151, 327, 575, 1923, 1533, 4699, 2171, 15447, 64047, 59007, 54523}},
+{19862, 18, 108329, {1, 3, 7, 7, 3, 51, 79, 39, 403, 599, 161, 2465, 4911, 10327, 23599, 3267, 44177, 184231}},
+{19863, 18, 108335, {1, 3, 3, 15, 5, 19, 57, 83, 507, 927, 665, 3471, 5037, 2051, 22923, 36813, 97393, 102715}},
+{19864, 18, 108338, {1, 3, 3, 13, 11, 19, 91, 179, 113, 295, 855, 2071, 3265, 4089, 8627, 7461, 23855, 53675}},
+{19865, 18, 108362, {1, 1, 3, 5, 21, 41, 11, 227, 87, 417, 209, 2013, 4849, 5291, 22073, 40235, 71283, 140785}},
+{19866, 18, 108398, {1, 3, 3, 5, 29, 57, 95, 65, 177, 177, 1973, 563, 5249, 337, 7611, 45099, 15443, 46583}},
+{19867, 18, 108405, {1, 1, 7, 3, 3, 5, 107, 75, 31, 293, 821, 1837, 2363, 13621, 8793, 29841, 127201, 131707}},
+{19868, 18, 108409, {1, 1, 1, 5, 1, 45, 69, 61, 157, 999, 183, 3431, 3487, 9461, 17545, 26973, 115527, 58419}},
+{19869, 18, 108431, {1, 1, 7, 7, 27, 5, 125, 153, 191, 745, 125, 2807, 5043, 10657, 24487, 19517, 31735, 42421}},
+{19870, 18, 108449, {1, 1, 7, 9, 25, 37, 73, 255, 141, 229, 1723, 1331, 6089, 13109, 30683, 2335, 111517, 105411}},
+{19871, 18, 108474, {1, 1, 5, 7, 3, 61, 79, 203, 423, 669, 1757, 1725, 4239, 7013, 28591, 61853, 81103, 39813}},
+{19872, 18, 108488, {1, 1, 3, 7, 21, 27, 23, 119, 441, 113, 1019, 285, 53, 8643, 31689, 2629, 126573, 60835}},
+{19873, 18, 108530, {1, 1, 5, 11, 29, 49, 23, 55, 441, 809, 1177, 1371, 5945, 6461, 11537, 12287, 85637, 232065}},
+{19874, 18, 108545, {1, 3, 1, 15, 5, 13, 19, 209, 105, 897, 565, 3209, 487, 9837, 22169, 26317, 39907, 185193}},
+{19875, 18, 108551, {1, 1, 1, 5, 23, 45, 49, 55, 501, 213, 1217, 3159, 733, 5889, 5475, 4953, 37317, 100369}},
+{19876, 18, 108558, {1, 1, 5, 1, 19, 5, 57, 137, 361, 605, 1077, 2015, 5511, 4667, 18457, 45979, 120253, 203397}},
+{19877, 18, 108585, {1, 1, 7, 9, 19, 19, 11, 187, 5, 647, 275, 1265, 7587, 16183, 369, 31885, 58347, 36829}},
+{19878, 18, 108613, {1, 3, 5, 3, 31, 31, 7, 105, 359, 839, 641, 3215, 4807, 13397, 885, 52867, 57125, 180607}},
+{19879, 18, 108638, {1, 1, 7, 9, 19, 45, 43, 211, 429, 757, 1637, 1569, 935, 8899, 24823, 18599, 111373, 190979}},
+{19880, 18, 108642, {1, 1, 7, 7, 13, 47, 3, 241, 467, 209, 323, 3467, 4397, 15395, 15373, 14499, 92443, 65931}},
+{19881, 18, 108653, {1, 3, 3, 5, 5, 9, 67, 115, 45, 279, 1753, 1575, 8127, 9651, 5169, 25643, 29671, 214383}},
+{19882, 18, 108671, {1, 3, 7, 7, 29, 7, 37, 205, 495, 445, 1771, 1439, 3577, 10423, 10865, 26851, 15251, 63373}},
+{19883, 18, 108675, {1, 3, 1, 9, 29, 13, 45, 61, 153, 193, 1407, 1075, 4023, 2367, 1147, 51277, 52975, 123061}},
+{19884, 18, 108684, {1, 3, 3, 3, 31, 25, 113, 173, 345, 565, 145, 3437, 7051, 12557, 27919, 41733, 76717, 192645}},
+{19885, 18, 108687, {1, 3, 3, 7, 3, 55, 35, 219, 55, 467, 635, 3833, 3753, 1099, 15301, 53121, 120807, 70481}},
+{19886, 18, 108696, {1, 3, 7, 7, 13, 1, 121, 191, 71, 193, 1891, 2303, 1401, 9143, 31297, 38979, 43093, 138941}},
+{19887, 18, 108786, {1, 3, 7, 5, 17, 51, 83, 201, 231, 423, 511, 1301, 6075, 475, 2603, 49327, 78565, 220827}},
+{19888, 18, 108792, {1, 3, 1, 7, 5, 61, 23, 11, 9, 711, 251, 1383, 613, 6213, 8921, 27267, 66009, 28575}},
+{19889, 18, 108795, {1, 3, 1, 3, 13, 13, 61, 211, 353, 883, 343, 1089, 2041, 7781, 25285, 9053, 76801, 153009}},
+{19890, 18, 108818, {1, 3, 7, 5, 17, 61, 67, 69, 361, 937, 949, 1483, 2825, 3753, 16533, 17277, 16539, 140521}},
+{19891, 18, 108830, {1, 3, 5, 9, 7, 19, 31, 239, 357, 561, 1583, 3059, 2023, 2213, 11283, 18603, 83487, 162415}},
+{19892, 18, 108836, {1, 1, 3, 15, 15, 59, 9, 43, 353, 203, 765, 1907, 2733, 3747, 30617, 32671, 119005, 72131}},
+{19893, 18, 108839, {1, 3, 1, 7, 17, 61, 55, 113, 439, 75, 703, 2741, 1059, 4561, 15923, 17153, 32563, 79681}},
+{19894, 18, 108851, {1, 1, 1, 15, 11, 57, 91, 245, 187, 185, 1859, 1209, 3247, 10863, 22421, 47287, 26831, 200935}},
+{19895, 18, 108875, {1, 1, 3, 13, 11, 39, 61, 211, 51, 197, 861, 2965, 4691, 9955, 2289, 28795, 61537, 235359}},
+{19896, 18, 108883, {1, 1, 7, 1, 31, 37, 121, 107, 79, 521, 371, 983, 6189, 4515, 25691, 26933, 123189, 70033}},
+{19897, 18, 108895, {1, 3, 3, 15, 19, 33, 31, 237, 35, 877, 1013, 3445, 573, 1145, 27781, 26327, 117451, 142339}},
+{19898, 18, 108908, {1, 3, 3, 15, 15, 9, 17, 185, 151, 499, 493, 1331, 1587, 12657, 22577, 7957, 126253, 57971}},
+{19899, 18, 108953, {1, 3, 7, 15, 3, 29, 43, 105, 423, 601, 793, 1011, 6657, 7287, 18561, 46993, 72945, 233051}},
+{19900, 18, 108956, {1, 1, 7, 5, 15, 17, 125, 141, 75, 877, 281, 2011, 4217, 9785, 7587, 42863, 35585, 212795}},
+{19901, 18, 108963, {1, 1, 3, 3, 3, 37, 67, 129, 433, 233, 115, 687, 6253, 12805, 10935, 49963, 91675, 241951}},
+{19902, 18, 108989, {1, 3, 1, 5, 3, 41, 3, 233, 317, 959, 1407, 1251, 743, 4165, 15561, 41165, 22393, 111633}},
+{19903, 18, 109001, {1, 3, 3, 15, 17, 15, 53, 245, 109, 413, 1149, 35, 2931, 11635, 27091, 63659, 33973, 16867}},
+{19904, 18, 109009, {1, 3, 7, 13, 3, 43, 83, 201, 367, 275, 235, 1795, 4041, 13539, 22345, 31451, 83985, 3527}},
+{19905, 18, 109052, {1, 3, 3, 9, 31, 47, 63, 117, 195, 497, 453, 1183, 3857, 14075, 28057, 13205, 54331, 54641}},
+{19906, 18, 109083, {1, 1, 7, 11, 11, 39, 37, 183, 213, 537, 1371, 901, 5255, 11791, 18993, 58785, 114113, 229815}},
+{19907, 18, 109090, {1, 3, 5, 5, 13, 45, 77, 165, 329, 439, 2011, 1845, 4577, 12457, 16959, 45943, 37715, 169775}},
+{19908, 18, 109104, {1, 1, 3, 11, 5, 7, 21, 245, 365, 371, 1291, 2569, 1791, 6003, 18619, 18661, 98551, 89645}},
+{19909, 18, 109121, {1, 3, 1, 7, 3, 51, 49, 245, 151, 919, 489, 3967, 3157, 7159, 17207, 19749, 94455, 112403}},
+{19910, 18, 109128, {1, 3, 7, 5, 9, 15, 17, 201, 273, 669, 1571, 3915, 1859, 2569, 28855, 27225, 116711, 148377}},
+{19911, 18, 109141, {1, 3, 7, 3, 19, 45, 115, 71, 201, 85, 1349, 3897, 4941, 10839, 14781, 36487, 107037, 109185}},
+{19912, 18, 109146, {1, 3, 5, 13, 11, 11, 35, 19, 213, 41, 45, 4075, 3163, 12937, 17487, 28911, 21289, 198489}},
+{19913, 18, 109155, {1, 1, 1, 11, 7, 35, 67, 23, 451, 235, 717, 181, 6697, 9359, 24561, 36187, 125179, 35119}},
+{19914, 18, 109162, {1, 1, 7, 15, 7, 47, 55, 125, 465, 251, 211, 3137, 4101, 1341, 2287, 22149, 45089, 94173}},
+{19915, 18, 109209, {1, 3, 1, 15, 19, 7, 15, 207, 7, 759, 869, 2337, 6805, 8287, 13447, 9963, 7177, 173505}},
+{19916, 18, 109216, {1, 3, 7, 13, 15, 3, 65, 143, 291, 511, 939, 669, 4095, 1931, 26015, 18253, 102461, 93837}},
+{19917, 18, 109243, {1, 3, 1, 5, 23, 3, 19, 121, 489, 583, 1425, 627, 4229, 5343, 3759, 17845, 105369, 132239}},
+{19918, 18, 109265, {1, 3, 3, 9, 29, 9, 17, 153, 111, 879, 1225, 979, 2687, 10477, 10105, 18091, 37825, 28077}},
+{19919, 18, 109282, {1, 1, 7, 9, 3, 51, 75, 101, 197, 551, 89, 1441, 607, 14025, 30411, 26887, 3435, 32977}},
+{19920, 18, 109306, {1, 1, 7, 3, 25, 29, 95, 123, 197, 767, 1513, 721, 4149, 10873, 32247, 4469, 42297, 49651}},
+{19921, 18, 109316, {1, 3, 5, 15, 11, 3, 77, 161, 309, 923, 513, 161, 6447, 9811, 9209, 21413, 8611, 237557}},
+{19922, 18, 109334, {1, 3, 1, 3, 23, 11, 61, 107, 317, 771, 1469, 3367, 6607, 11495, 12271, 59989, 52483, 194761}},
+{19923, 18, 109359, {1, 3, 7, 7, 23, 1, 37, 47, 185, 863, 1153, 3517, 6165, 3921, 19311, 37339, 112477, 204915}},
+{19924, 18, 109373, {1, 3, 7, 7, 15, 61, 9, 113, 175, 305, 1759, 2933, 2139, 3591, 15303, 54479, 126511, 255205}},
+{19925, 18, 109386, {1, 1, 1, 3, 29, 43, 19, 183, 121, 577, 1329, 1737, 4373, 5577, 24023, 40103, 22333, 123423}},
+{19926, 18, 109394, {1, 3, 5, 1, 29, 1, 5, 177, 271, 431, 139, 705, 4319, 9301, 15887, 13253, 13275, 233317}},
+{19927, 18, 109403, {1, 1, 3, 7, 21, 3, 13, 51, 459, 359, 1721, 193, 4887, 7805, 20615, 28813, 82427, 57853}},
+{19928, 18, 109409, {1, 3, 3, 13, 3, 29, 43, 95, 339, 993, 979, 2323, 7505, 10203, 9475, 16513, 21651, 104871}},
+{19929, 18, 109412, {1, 1, 3, 15, 11, 5, 97, 127, 397, 25, 507, 1839, 2313, 13399, 899, 25713, 94363, 178287}},
+{19930, 18, 109427, {1, 1, 5, 5, 9, 53, 95, 171, 107, 129, 1041, 3583, 5479, 943, 21435, 36481, 85519, 169651}},
+{19931, 18, 109439, {1, 1, 1, 1, 1, 11, 17, 249, 277, 805, 1827, 2705, 3015, 9033, 25019, 38593, 59235, 21145}},
+{19932, 18, 109464, {1, 1, 7, 3, 7, 59, 107, 213, 109, 213, 555, 3463, 953, 3173, 18947, 2863, 27889, 32493}},
+{19933, 18, 109467, {1, 3, 5, 15, 21, 11, 99, 131, 287, 513, 1393, 3327, 7347, 4343, 8805, 29571, 97151, 97313}},
+{19934, 18, 109476, {1, 3, 5, 3, 17, 53, 23, 21, 227, 291, 111, 1951, 6593, 16325, 31725, 31997, 116907, 181027}},
+{19935, 18, 109488, {1, 1, 5, 3, 15, 57, 93, 153, 345, 257, 169, 795, 3907, 5669, 25447, 28775, 1489, 216417}},
+{19936, 18, 109497, {1, 1, 1, 5, 19, 19, 113, 55, 431, 685, 1839, 711, 4909, 10211, 25765, 37, 72657, 79769}},
+{19937, 18, 109523, {1, 3, 5, 7, 19, 17, 93, 145, 99, 799, 1615, 1583, 7705, 1069, 30259, 37951, 78965, 16203}},
+{19938, 18, 109551, {1, 3, 7, 13, 23, 61, 119, 49, 413, 1021, 415, 465, 7395, 31, 16415, 1009, 9843, 86531}},
+{19939, 18, 109556, {1, 1, 3, 15, 17, 21, 83, 69, 411, 1, 269, 1391, 295, 13649, 21649, 62453, 11457, 215375}},
+{19940, 18, 109566, {1, 3, 3, 7, 25, 53, 95, 99, 447, 323, 27, 1595, 3771, 16099, 31523, 14405, 66999, 65733}},
+{19941, 18, 109598, {1, 1, 3, 11, 25, 29, 19, 95, 101, 661, 537, 641, 1455, 16151, 29087, 54009, 89395, 2223}},
+{19942, 18, 109628, {1, 1, 1, 11, 11, 33, 91, 227, 449, 661, 1621, 1743, 2859, 9797, 32397, 41767, 116325, 6839}},
+{19943, 18, 109643, {1, 3, 3, 7, 31, 41, 15, 139, 53, 789, 25, 67, 1131, 5987, 14091, 37259, 70313, 6633}},
+{19944, 18, 109663, {1, 3, 7, 13, 21, 29, 71, 245, 497, 493, 207, 3221, 3695, 3045, 1497, 29235, 65113, 82015}},
+{19945, 18, 109674, {1, 1, 7, 5, 29, 29, 87, 197, 123, 323, 773, 157, 2925, 9235, 31625, 58187, 121457, 25561}},
+{19946, 18, 109688, {1, 1, 1, 9, 3, 15, 99, 55, 133, 757, 1405, 997, 5201, 8971, 6095, 33309, 35587, 254545}},
+{19947, 18, 109691, {1, 3, 5, 9, 19, 57, 85, 45, 429, 823, 1369, 933, 1971, 13753, 11351, 45805, 16527, 129907}},
+{19948, 18, 109704, {1, 3, 3, 15, 23, 15, 35, 89, 477, 875, 1087, 2837, 1093, 617, 18687, 53269, 63447, 226393}},
+{19949, 18, 109715, {1, 1, 7, 9, 27, 37, 23, 107, 265, 485, 1975, 3159, 4065, 10089, 26975, 45067, 4241, 49051}},
+{19950, 18, 109717, {1, 3, 3, 1, 29, 53, 89, 129, 149, 717, 749, 1481, 7829, 15887, 23185, 30667, 11749, 188963}},
+{19951, 18, 109746, {1, 3, 5, 9, 13, 47, 119, 135, 407, 99, 1773, 2307, 7885, 4013, 25723, 53519, 37487, 205671}},
+{19952, 18, 109789, {1, 1, 5, 1, 11, 27, 121, 213, 147, 669, 799, 485, 4275, 15909, 30583, 45925, 90365, 226901}},
+{19953, 18, 109794, {1, 1, 3, 5, 1, 19, 81, 109, 217, 949, 1637, 3413, 5957, 7293, 17337, 63857, 103815, 80805}},
+{19954, 18, 109868, {1, 3, 7, 3, 9, 43, 119, 251, 345, 3, 203, 829, 3391, 2575, 6859, 50849, 22221, 227581}},
+{19955, 18, 109886, {1, 1, 7, 15, 13, 43, 7, 23, 101, 89, 1747, 1231, 1883, 13363, 10981, 59179, 59555, 242021}},
+{19956, 18, 109888, {1, 1, 5, 5, 23, 15, 93, 183, 231, 891, 1745, 2665, 1689, 8515, 11717, 35643, 113067, 233757}},
+{19957, 18, 109903, {1, 3, 7, 11, 29, 21, 13, 59, 103, 105, 483, 863, 2711, 7917, 29279, 53931, 7011, 60075}},
+{19958, 18, 109908, {1, 1, 3, 15, 5, 37, 101, 163, 31, 575, 2029, 1625, 4545, 12579, 15175, 32667, 59497, 63653}},
+{19959, 18, 109912, {1, 3, 5, 7, 23, 37, 61, 101, 273, 49, 1943, 3381, 491, 4079, 20341, 26463, 122261, 77965}},
+{19960, 18, 109927, {1, 1, 3, 15, 9, 51, 53, 89, 175, 487, 1583, 1797, 4353, 1339, 19613, 26913, 78955, 166523}},
+{19961, 18, 109936, {1, 3, 3, 9, 27, 57, 25, 207, 233, 675, 661, 2629, 6971, 8723, 31199, 47215, 36931, 28347}},
+{19962, 18, 109979, {1, 3, 1, 3, 31, 15, 123, 17, 211, 883, 1861, 2747, 8075, 5373, 23521, 46217, 86629, 171777}},
+{19963, 18, 110005, {1, 3, 5, 9, 11, 43, 45, 171, 465, 835, 603, 2121, 409, 1643, 20327, 63211, 129479, 223113}},
+{19964, 18, 110010, {1, 1, 5, 7, 13, 57, 83, 233, 307, 489, 941, 1723, 6149, 5557, 2053, 17377, 31597, 176051}},
+{19965, 18, 110017, {1, 1, 7, 3, 11, 11, 85, 163, 169, 989, 1289, 2749, 7681, 4679, 645, 36589, 85907, 194713}},
+{19966, 18, 110041, {1, 1, 1, 7, 3, 57, 39, 149, 463, 947, 481, 1163, 7171, 8539, 28991, 61235, 74487, 107051}},
+{19967, 18, 110042, {1, 1, 3, 7, 9, 57, 89, 101, 231, 163, 1355, 1393, 5823, 7565, 26285, 13523, 130329, 26099}},
+{19968, 18, 110047, {1, 1, 7, 15, 13, 59, 111, 35, 265, 927, 125, 1881, 5397, 757, 23845, 9677, 76077, 163361}},
+{19969, 18, 110048, {1, 1, 7, 9, 1, 63, 61, 157, 389, 143, 1445, 881, 3609, 9955, 11159, 59677, 45831, 138345}},
+{19970, 18, 110053, {1, 3, 5, 7, 5, 45, 65, 23, 257, 589, 905, 3651, 743, 117, 30307, 7415, 103331, 252889}},
+{19971, 18, 110054, {1, 1, 7, 13, 3, 57, 113, 91, 217, 967, 481, 989, 4795, 3549, 23717, 60793, 80281, 19977}},
+{19972, 18, 110057, {1, 3, 3, 1, 15, 37, 113, 245, 239, 575, 197, 2803, 7743, 13447, 3601, 56981, 76381, 13321}},
+{19973, 18, 110091, {1, 3, 1, 11, 27, 33, 99, 151, 43, 835, 1951, 1957, 2983, 6781, 9319, 2119, 40533, 118325}},
+{19974, 18, 110093, {1, 3, 3, 7, 27, 19, 23, 243, 347, 477, 1661, 1891, 2439, 2485, 31743, 1427, 20317, 90803}},
+{19975, 18, 110112, {1, 3, 1, 1, 3, 59, 71, 129, 21, 3, 449, 629, 3657, 4045, 8305, 40461, 60927, 38529}},
+{19976, 18, 110127, {1, 3, 3, 7, 9, 11, 85, 185, 369, 451, 887, 3709, 6931, 111, 1379, 8741, 58777, 188045}},
+{19977, 18, 110178, {1, 3, 7, 11, 23, 13, 77, 141, 99, 543, 725, 2439, 6825, 1361, 2785, 5345, 5941, 234751}},
+{19978, 18, 110183, {1, 1, 5, 5, 17, 55, 69, 9, 431, 585, 1049, 165, 1705, 14907, 8655, 12485, 22783, 91195}},
+{19979, 18, 110184, {1, 1, 7, 11, 29, 41, 91, 137, 17, 785, 1151, 2033, 7031, 15077, 2241, 21453, 117947, 128891}},
+{19980, 18, 110195, {1, 1, 1, 11, 17, 53, 113, 195, 409, 275, 1757, 245, 6263, 14785, 29159, 43827, 65027, 248403}},
+{19981, 18, 110307, {1, 3, 3, 3, 5, 15, 23, 41, 261, 891, 1021, 1999, 4883, 9233, 10385, 21953, 50711, 4247}},
+{19982, 18, 110334, {1, 1, 1, 13, 23, 47, 33, 77, 317, 251, 617, 2265, 7549, 327, 2317, 41209, 41063, 120863}},
+{19983, 18, 110336, {1, 1, 7, 11, 15, 17, 25, 105, 253, 713, 1147, 415, 5777, 2215, 4207, 33857, 17001, 260533}},
+{19984, 18, 110354, {1, 1, 1, 11, 31, 45, 3, 25, 329, 45, 1563, 121, 1413, 16229, 32485, 54477, 101025, 64847}},
+{19985, 18, 110356, {1, 3, 5, 1, 15, 59, 113, 203, 481, 545, 371, 1357, 5549, 3043, 397, 61483, 59779, 58159}},
+{19986, 18, 110390, {1, 3, 3, 3, 25, 39, 29, 193, 379, 293, 1173, 3389, 4231, 11519, 6681, 28813, 63609, 13029}},
+{19987, 18, 110419, {1, 3, 1, 1, 27, 57, 37, 249, 441, 905, 463, 3543, 7203, 10075, 5373, 46103, 6685, 146943}},
+{19988, 18, 110452, {1, 3, 5, 7, 31, 51, 21, 139, 209, 219, 1663, 837, 3351, 6291, 735, 8715, 33751, 199485}},
+{19989, 18, 110461, {1, 3, 5, 11, 19, 57, 41, 163, 287, 327, 243, 2891, 1095, 3959, 5067, 2867, 16207, 213089}},
+{19990, 18, 110465, {1, 1, 5, 11, 21, 59, 97, 239, 309, 371, 797, 453, 2595, 4277, 3771, 5665, 10075, 56101}},
+{19991, 18, 110466, {1, 1, 3, 15, 17, 29, 103, 33, 449, 525, 961, 3551, 3611, 14057, 15971, 26981, 35169, 130213}},
+{19992, 18, 110468, {1, 1, 3, 1, 5, 13, 39, 211, 387, 797, 1051, 3287, 3737, 12953, 3387, 35107, 78809, 162907}},
+{19993, 18, 110486, {1, 1, 7, 9, 7, 63, 127, 115, 173, 981, 623, 737, 7625, 12245, 4195, 61873, 104301, 250333}},
+{19994, 18, 110511, {1, 1, 1, 5, 19, 5, 123, 43, 209, 741, 747, 1057, 2683, 15359, 24121, 38413, 5823, 62213}},
+{19995, 18, 110531, {1, 1, 7, 1, 23, 13, 63, 165, 309, 323, 247, 3827, 5451, 4823, 23925, 56957, 69765, 259923}},
+{19996, 18, 110561, {1, 1, 5, 1, 5, 49, 51, 65, 31, 257, 1363, 3031, 5765, 3645, 16383, 6347, 30429, 130557}},
+{19997, 18, 110573, {1, 3, 5, 13, 9, 63, 31, 3, 317, 379, 1345, 2161, 7787, 2055, 21507, 20347, 97021, 183377}},
+{19998, 18, 110593, {1, 3, 5, 11, 15, 59, 13, 139, 415, 821, 639, 1249, 6349, 15861, 21377, 22813, 42839, 76595}},
+{19999, 18, 110611, {1, 1, 7, 9, 23, 11, 25, 115, 393, 153, 1269, 871, 1323, 1891, 11619, 3103, 79813, 39811}},
+{20000, 18, 110614, {1, 3, 1, 15, 27, 37, 63, 253, 1, 855, 1651, 3111, 6693, 1825, 22549, 64189, 18347, 253425}},
+{20001, 18, 110651, {1, 3, 1, 11, 23, 27, 119, 59, 421, 343, 831, 2679, 5899, 12087, 15953, 18601, 109551, 33895}},
+{20002, 18, 110661, {1, 3, 1, 13, 29, 3, 91, 227, 301, 491, 1045, 2105, 5189, 13717, 1095, 6039, 16229, 215687}},
+{20003, 18, 110665, {1, 1, 7, 3, 11, 53, 85, 25, 23, 293, 841, 3569, 5335, 8949, 28665, 15139, 100807, 155587}},
+{20004, 18, 110701, {1, 1, 1, 9, 31, 1, 77, 149, 181, 5, 915, 1155, 4717, 2837, 17545, 3235, 26811, 124901}},
+{20005, 18, 110730, {1, 1, 3, 5, 25, 27, 47, 215, 425, 195, 1575, 3961, 3521, 4197, 9565, 32523, 125091, 165543}},
+{20006, 18, 110735, {1, 3, 7, 3, 17, 57, 7, 137, 507, 303, 1123, 1511, 2465, 4277, 19959, 31951, 83157, 62843}},
+{20007, 18, 110738, {1, 3, 3, 1, 27, 43, 79, 191, 265, 167, 665, 4017, 6613, 1175, 5427, 47139, 91517, 32071}},
+{20008, 18, 110759, {1, 1, 1, 11, 29, 63, 9, 39, 303, 1021, 415, 2157, 5227, 13557, 4931, 12541, 74101, 13189}},
+{20009, 18, 110763, {1, 1, 3, 9, 15, 41, 45, 163, 301, 315, 1433, 1449, 3589, 15783, 16069, 16155, 10527, 69335}},
+{20010, 18, 110768, {1, 3, 1, 1, 1, 5, 75, 169, 215, 115, 939, 1285, 43, 1941, 27847, 5245, 51211, 244817}},
+{20011, 18, 110774, {1, 1, 1, 15, 7, 33, 31, 23, 397, 537, 1415, 329, 6705, 15015, 18883, 62895, 21435, 233075}},
+{20012, 18, 110783, {1, 3, 3, 5, 11, 49, 73, 147, 183, 317, 11, 1997, 1045, 6015, 29159, 55195, 105711, 134727}},
+{20013, 18, 110785, {1, 3, 3, 9, 21, 41, 5, 213, 421, 539, 1269, 1929, 3701, 2165, 14997, 21933, 58167, 239719}},
+{20014, 18, 110809, {1, 3, 1, 5, 23, 63, 37, 27, 21, 547, 1499, 1621, 141, 5309, 32257, 47241, 123617, 243853}},
+{20015, 18, 110812, {1, 1, 1, 13, 31, 45, 47, 91, 165, 1007, 1295, 4035, 1461, 10423, 7747, 7329, 114599, 169375}},
+{20016, 18, 110840, {1, 1, 5, 3, 21, 9, 75, 61, 35, 745, 31, 4085, 3645, 16239, 14979, 15725, 108859, 56745}},
+{20017, 18, 110853, {1, 1, 5, 15, 11, 31, 13, 229, 417, 147, 1993, 4043, 7757, 13507, 15297, 56119, 2223, 142275}},
+{20018, 18, 110905, {1, 3, 5, 13, 3, 57, 45, 109, 135, 829, 159, 769, 865, 2583, 15755, 44343, 84561, 98621}},
+{20019, 18, 110933, {1, 1, 7, 11, 17, 11, 115, 45, 371, 411, 863, 2139, 3897, 13981, 16771, 4587, 25195, 66077}},
+{20020, 18, 110961, {1, 3, 7, 15, 17, 47, 51, 133, 133, 475, 1363, 3325, 4287, 4837, 22077, 60225, 3097, 246805}},
+{20021, 18, 110962, {1, 3, 5, 9, 29, 51, 127, 125, 353, 519, 129, 1409, 1497, 3167, 14163, 24921, 81343, 129835}},
+{20022, 18, 110974, {1, 3, 5, 5, 19, 39, 95, 109, 229, 1015, 367, 2373, 709, 6169, 4089, 13533, 22399, 118977}},
+{20023, 18, 110987, {1, 1, 5, 5, 17, 21, 91, 131, 309, 739, 1373, 3723, 6659, 1119, 27521, 55589, 34967, 70831}},
+{20024, 18, 110989, {1, 3, 1, 11, 5, 7, 85, 215, 425, 947, 589, 375, 5943, 13399, 18307, 27007, 18919, 200617}},
+{20025, 18, 111007, {1, 1, 3, 15, 11, 37, 111, 179, 259, 517, 1679, 225, 3493, 15025, 21751, 40687, 73001, 214477}},
+{20026, 18, 111011, {1, 1, 7, 15, 17, 41, 109, 129, 427, 847, 1965, 3269, 5871, 12331, 26899, 49791, 103471, 213789}},
+{20027, 18, 111043, {1, 3, 3, 3, 9, 41, 25, 115, 95, 737, 717, 1545, 841, 14923, 7409, 45365, 100139, 77787}},
+{20028, 18, 111070, {1, 1, 3, 15, 11, 3, 63, 23, 425, 433, 537, 1599, 2691, 11271, 1695, 40579, 53507, 73033}},
+{20029, 18, 111088, {1, 3, 7, 13, 9, 21, 85, 31, 337, 583, 1883, 3877, 7197, 7715, 21525, 53273, 11263, 41907}},
+{20030, 18, 111127, {1, 3, 7, 1, 7, 53, 61, 45, 299, 885, 1391, 3109, 6851, 6079, 18857, 44537, 95713, 146125}},
+{20031, 18, 111140, {1, 1, 1, 3, 21, 49, 95, 105, 419, 315, 365, 3035, 4169, 5723, 26921, 62809, 27019, 243965}},
+{20032, 18, 111149, {1, 1, 3, 5, 11, 39, 71, 89, 249, 11, 1395, 105, 6637, 4577, 22979, 32405, 93163, 58785}},
+{20033, 18, 111229, {1, 1, 1, 1, 27, 25, 125, 85, 495, 697, 1793, 301, 7665, 12671, 25359, 38803, 58723, 189837}},
+{20034, 18, 111230, {1, 3, 5, 11, 17, 11, 61, 211, 19, 901, 1701, 223, 2195, 15571, 3529, 34699, 94607, 196519}},
+{20035, 18, 111243, {1, 3, 7, 11, 15, 1, 111, 1, 381, 145, 293, 3639, 6931, 13195, 19985, 58491, 53067, 184411}},
+{20036, 18, 111267, {1, 3, 1, 15, 31, 39, 39, 101, 17, 431, 1151, 2465, 727, 12709, 5377, 5857, 49707, 76439}},
+{20037, 18, 111287, {1, 3, 3, 5, 7, 1, 3, 39, 357, 339, 415, 567, 7245, 13943, 7495, 54133, 119705, 160615}},
+{20038, 18, 111313, {1, 3, 5, 15, 9, 17, 13, 253, 337, 673, 1745, 2613, 4635, 14025, 11159, 50001, 40753, 172983}},
+{20039, 18, 111356, {1, 3, 7, 11, 3, 15, 19, 107, 393, 1015, 1441, 181, 5721, 9987, 15557, 37263, 90053, 205685}},
+{20040, 18, 111368, {1, 1, 5, 1, 9, 3, 69, 123, 245, 111, 283, 1581, 259, 275, 813, 12213, 19639, 7335}},
+{20041, 18, 111409, {1, 3, 7, 7, 1, 55, 101, 63, 259, 705, 653, 3821, 2081, 6447, 25471, 15523, 38827, 68055}},
+{20042, 18, 111419, {1, 1, 5, 7, 27, 9, 97, 149, 445, 341, 167, 3695, 375, 853, 8143, 36027, 62729, 197357}},
+{20043, 18, 111430, {1, 3, 7, 1, 1, 37, 97, 103, 493, 319, 1287, 3787, 4079, 13049, 14305, 6665, 4631, 96225}},
+{20044, 18, 111433, {1, 1, 5, 7, 1, 5, 127, 143, 251, 725, 1759, 2381, 181, 15741, 9395, 64441, 44347, 221697}},
+{20045, 18, 111442, {1, 3, 1, 3, 25, 47, 29, 167, 397, 827, 1255, 3271, 6307, 13915, 3131, 19123, 88619, 62847}},
+{20046, 18, 111467, {1, 3, 5, 1, 29, 11, 59, 203, 245, 553, 617, 1287, 205, 2291, 3613, 39933, 116981, 43595}},
+{20047, 18, 111491, {1, 1, 3, 9, 27, 33, 35, 77, 437, 1003, 119, 253, 6643, 113, 10587, 41073, 55371, 233307}},
+{20048, 18, 111503, {1, 3, 7, 1, 29, 63, 1, 231, 373, 995, 1063, 1385, 273, 14115, 6899, 62991, 112003, 80527}},
+{20049, 18, 111527, {1, 3, 3, 1, 31, 21, 55, 115, 393, 685, 245, 1587, 5617, 267, 19639, 15169, 14073, 173091}},
+{20050, 18, 111531, {1, 3, 1, 11, 29, 45, 53, 21, 433, 979, 1067, 2999, 6279, 4739, 30835, 61653, 112893, 75839}},
+{20051, 18, 111541, {1, 1, 5, 11, 23, 25, 15, 107, 325, 981, 1057, 1181, 4465, 16291, 1523, 64497, 129437, 45067}},
+{20052, 18, 111546, {1, 1, 1, 5, 1, 21, 79, 135, 419, 997, 1967, 747, 2097, 15397, 4415, 15807, 79583, 259561}},
+{20053, 18, 111548, {1, 3, 1, 7, 5, 49, 105, 109, 243, 371, 13, 2297, 2845, 12569, 13165, 13551, 75471, 168579}},
+{20054, 18, 111577, {1, 1, 1, 1, 9, 33, 7, 233, 43, 773, 1121, 3763, 4047, 15039, 8165, 25407, 82561, 215045}},
+{20055, 18, 111625, {1, 3, 7, 1, 17, 41, 105, 129, 333, 687, 1357, 1197, 1271, 3835, 15823, 36777, 94311, 192321}},
+{20056, 18, 111636, {1, 1, 5, 15, 13, 31, 93, 249, 81, 167, 1681, 1587, 179, 5755, 27741, 29437, 100407, 63287}},
+{20057, 18, 111650, {1, 3, 3, 13, 11, 39, 85, 23, 37, 183, 547, 1255, 1167, 15961, 23281, 59989, 99393, 34983}},
+{20058, 18, 111655, {1, 3, 7, 5, 13, 33, 17, 243, 321, 845, 447, 1997, 4639, 11175, 24651, 18281, 82677, 244543}},
+{20059, 18, 111662, {1, 3, 5, 13, 3, 63, 75, 35, 493, 207, 1707, 1401, 3687, 11353, 5461, 23433, 71259, 93483}},
+{20060, 18, 111673, {1, 1, 3, 1, 19, 61, 81, 133, 115, 957, 669, 647, 347, 8739, 18451, 39641, 118677, 136601}},
+{20061, 18, 111699, {1, 1, 7, 13, 3, 13, 119, 187, 111, 181, 1865, 1613, 201, 3633, 17805, 46553, 8899, 100407}},
+{20062, 18, 111727, {1, 3, 3, 9, 19, 33, 35, 215, 235, 893, 877, 3099, 7597, 13521, 22473, 65435, 3205, 44897}},
+{20063, 18, 111729, {1, 3, 3, 11, 27, 3, 101, 201, 215, 373, 859, 1435, 2637, 6795, 21157, 3333, 27797, 199427}},
+{20064, 18, 111741, {1, 1, 7, 13, 31, 33, 85, 205, 273, 565, 2033, 3451, 7581, 16223, 1383, 16297, 1263, 49065}},
+{20065, 18, 111757, {1, 1, 1, 13, 11, 29, 65, 71, 395, 179, 1193, 3859, 3075, 10133, 6463, 34617, 20173, 203471}},
+{20066, 18, 111781, {1, 1, 7, 3, 7, 29, 11, 115, 465, 695, 1759, 3137, 6337, 977, 43, 62501, 13297, 59319}},
+{20067, 18, 111791, {1, 3, 5, 9, 31, 59, 11, 107, 109, 797, 177, 2891, 2535, 4305, 19255, 9591, 84417, 87381}},
+{20068, 18, 111826, {1, 3, 3, 3, 1, 9, 45, 219, 73, 573, 1477, 3699, 8145, 835, 7123, 37167, 53411, 45397}},
+{20069, 18, 111838, {1, 3, 5, 15, 15, 41, 37, 63, 233, 971, 1497, 1223, 3909, 11721, 9217, 41055, 9779, 199339}},
+{20070, 18, 111854, {1, 3, 3, 7, 17, 61, 91, 237, 313, 841, 7, 3283, 4049, 10403, 22157, 4889, 31903, 188043}},
+{20071, 18, 111861, {1, 3, 7, 1, 25, 3, 59, 87, 191, 725, 1615, 4057, 3037, 14597, 17371, 42221, 73919, 58009}},
+{20072, 18, 111866, {1, 3, 5, 11, 27, 7, 45, 231, 315, 727, 843, 2191, 7909, 53, 23309, 55189, 96193, 174017}},
+{20073, 18, 111868, {1, 3, 5, 11, 27, 51, 127, 187, 209, 883, 429, 137, 4585, 15195, 16527, 32571, 30905, 8137}},
+{20074, 18, 111897, {1, 1, 1, 11, 15, 55, 13, 161, 183, 671, 659, 3669, 4461, 13691, 17119, 26877, 52041, 110103}},
+{20075, 18, 111903, {1, 3, 5, 9, 5, 45, 29, 19, 415, 931, 683, 2987, 3839, 4529, 3091, 54457, 115537, 102671}},
+{20076, 18, 111904, {1, 1, 7, 13, 23, 31, 61, 17, 327, 951, 1333, 713, 4309, 1955, 22797, 27007, 106673, 47177}},
+{20077, 18, 111959, {1, 3, 3, 9, 31, 49, 19, 115, 413, 257, 1799, 3641, 2075, 15613, 14293, 16123, 45131, 209389}},
+{20078, 18, 111975, {1, 1, 7, 15, 1, 15, 27, 63, 463, 825, 1081, 991, 2641, 5999, 8551, 41119, 80251, 189263}},
+{20079, 18, 112018, {1, 1, 5, 9, 7, 55, 125, 97, 245, 997, 457, 1087, 1297, 3433, 14887, 24117, 30689, 184809}},
+{20080, 18, 112023, {1, 3, 1, 9, 23, 59, 81, 233, 341, 943, 1335, 2819, 2625, 4957, 14925, 7917, 107383, 204493}},
+{20081, 18, 112033, {1, 3, 5, 5, 5, 25, 79, 29, 191, 541, 1295, 269, 613, 5201, 28639, 52839, 52865, 75181}},
+{20082, 18, 112036, {1, 3, 3, 7, 19, 45, 35, 201, 391, 317, 1323, 2733, 3407, 10273, 32689, 52153, 108751, 242493}},
+{20083, 18, 112043, {1, 3, 1, 7, 15, 27, 45, 21, 383, 483, 1857, 3443, 2263, 11471, 3697, 63929, 116399, 229733}},
+{20084, 18, 112095, {1, 1, 3, 9, 13, 27, 19, 37, 181, 811, 1833, 177, 7689, 10073, 20229, 31397, 65415, 68461}},
+{20085, 18, 112113, {1, 1, 1, 15, 19, 53, 65, 209, 433, 783, 1647, 4075, 3155, 733, 25603, 39033, 43109, 151257}},
+{20086, 18, 112136, {1, 3, 3, 5, 9, 37, 61, 75, 497, 825, 1785, 3709, 1731, 889, 19325, 57453, 39095, 190855}},
+{20087, 18, 112153, {1, 3, 3, 13, 3, 53, 21, 39, 483, 833, 1191, 2829, 1323, 1877, 17257, 36077, 47997, 25349}},
+{20088, 18, 112165, {1, 1, 7, 9, 29, 25, 7, 91, 87, 723, 777, 1865, 7763, 10995, 15953, 36111, 21313, 214417}},
+{20089, 18, 112166, {1, 3, 5, 3, 17, 15, 85, 133, 245, 317, 879, 3237, 7049, 6501, 13359, 34063, 124703, 118289}},
+{20090, 18, 112177, {1, 1, 1, 7, 11, 25, 111, 143, 369, 593, 237, 2787, 1015, 13059, 23275, 38453, 90809, 25803}},
+{20091, 18, 112189, {1, 1, 7, 5, 13, 21, 39, 235, 381, 381, 949, 773, 1123, 9911, 18115, 47657, 47849, 197633}},
+{20092, 18, 112226, {1, 1, 3, 13, 15, 57, 47, 203, 483, 341, 137, 1283, 2847, 5051, 22593, 60915, 45123, 258733}},
+{20093, 18, 112237, {1, 1, 3, 5, 29, 7, 23, 127, 493, 543, 747, 3547, 4433, 5847, 28999, 18079, 81205, 231557}},
+{20094, 18, 112240, {1, 1, 3, 15, 9, 63, 17, 197, 75, 387, 1679, 2631, 1033, 2757, 18365, 11957, 98915, 24223}},
+{20095, 18, 112255, {1, 1, 3, 9, 27, 55, 67, 97, 345, 995, 1151, 1747, 4889, 13847, 13237, 9035, 13461, 10377}},
+{20096, 18, 112265, {1, 1, 5, 9, 27, 13, 7, 77, 399, 191, 137, 2801, 6379, 15969, 1727, 27503, 97385, 147625}},
+{20097, 18, 112280, {1, 3, 1, 7, 5, 9, 103, 163, 489, 615, 1359, 2635, 3115, 13795, 18853, 65225, 26545, 212065}},
+{20098, 18, 112292, {1, 3, 7, 3, 13, 25, 125, 133, 359, 423, 751, 4045, 1209, 7521, 6653, 39171, 125083, 229399}},
+{20099, 18, 112307, {1, 3, 1, 9, 15, 21, 121, 223, 283, 313, 1807, 3829, 5279, 10609, 20113, 7851, 23731, 245327}},
+{20100, 18, 112316, {1, 1, 1, 11, 15, 13, 63, 253, 311, 369, 1549, 2803, 2029, 14967, 14217, 1387, 104669, 63375}},
+{20101, 18, 112342, {1, 1, 3, 3, 31, 49, 59, 189, 249, 779, 275, 3761, 3465, 2205, 11543, 16973, 126249, 104769}},
+{20102, 18, 112345, {1, 3, 1, 5, 11, 39, 59, 33, 121, 151, 467, 1011, 1379, 13955, 20117, 52537, 51049, 50663}},
+{20103, 18, 112351, {1, 1, 1, 7, 5, 41, 121, 29, 357, 33, 849, 2441, 2127, 1337, 21147, 63869, 80215, 31211}},
+{20104, 18, 112361, {1, 3, 3, 3, 25, 41, 17, 101, 173, 915, 463, 2391, 1671, 8789, 13357, 42127, 17599, 61087}},
+{20105, 18, 112364, {1, 1, 3, 9, 29, 23, 47, 211, 435, 223, 1421, 2463, 4543, 8569, 30209, 46621, 14367, 13263}},
+{20106, 18, 112372, {1, 3, 7, 7, 5, 9, 75, 209, 299, 81, 1705, 2335, 6703, 6309, 5859, 57889, 43219, 7667}},
+{20107, 18, 112382, {1, 3, 3, 3, 19, 31, 107, 87, 413, 111, 215, 2711, 7053, 5223, 25241, 26675, 16067, 122719}},
+{20108, 18, 112389, {1, 1, 1, 15, 21, 3, 15, 13, 281, 63, 725, 2025, 4813, 14177, 18577, 875, 118623, 192005}},
+{20109, 18, 112408, {1, 3, 5, 9, 17, 21, 85, 173, 59, 153, 763, 3899, 1985, 2071, 10439, 44911, 60915, 122419}},
+{20110, 18, 112417, {1, 3, 7, 13, 11, 63, 59, 95, 53, 927, 555, 1897, 5195, 13469, 16973, 3463, 125173, 256021}},
+{20111, 18, 112423, {1, 1, 3, 7, 9, 63, 33, 193, 61, 445, 1247, 1379, 4701, 5311, 30709, 16795, 69871, 161113}},
+{20112, 18, 112476, {1, 3, 1, 3, 21, 25, 125, 111, 109, 75, 455, 861, 6483, 4501, 19095, 45601, 78415, 30995}},
+{20113, 18, 112480, {1, 1, 3, 5, 1, 25, 15, 25, 223, 961, 537, 1453, 4951, 5085, 19801, 9863, 108819, 7319}},
+{20114, 18, 112483, {1, 3, 1, 5, 29, 21, 79, 113, 177, 691, 219, 3159, 3493, 25, 30655, 46257, 23707, 243377}},
+{20115, 18, 112513, {1, 1, 3, 3, 27, 21, 11, 95, 43, 161, 2029, 4091, 6695, 7179, 9955, 45195, 32017, 128605}},
+{20116, 18, 112538, {1, 1, 7, 5, 19, 37, 47, 83, 169, 143, 773, 2127, 347, 1887, 2861, 8155, 21437, 175641}},
+{20117, 18, 112543, {1, 3, 1, 1, 27, 63, 119, 57, 77, 931, 629, 1807, 4469, 2315, 3767, 19207, 114581, 125135}},
+{20118, 18, 112574, {1, 1, 5, 11, 13, 51, 51, 239, 333, 369, 1035, 3017, 103, 1809, 14579, 34425, 123915, 258397}},
+{20119, 18, 112599, {1, 1, 1, 3, 3, 19, 63, 237, 141, 929, 943, 2597, 3983, 1043, 24269, 12325, 39013, 216689}},
+{20120, 18, 112605, {1, 1, 3, 7, 9, 61, 73, 31, 287, 303, 1415, 3453, 2667, 8625, 14347, 51953, 9181, 251937}},
+{20121, 18, 112667, {1, 1, 7, 1, 15, 41, 1, 197, 87, 311, 1147, 3799, 2585, 14027, 491, 54203, 124861, 227637}},
+{20122, 18, 112688, {1, 3, 7, 3, 15, 35, 97, 89, 65, 493, 1897, 3345, 3807, 5911, 12461, 21393, 116975, 212801}},
+{20123, 18, 112735, {1, 1, 7, 11, 29, 47, 61, 171, 399, 929, 93, 2815, 4933, 9209, 15053, 21911, 117217, 52539}},
+{20124, 18, 112746, {1, 3, 1, 1, 19, 25, 11, 41, 73, 317, 215, 923, 5153, 8025, 18703, 11513, 107981, 2027}},
+{20125, 18, 112810, {1, 1, 5, 7, 27, 33, 47, 99, 171, 259, 2017, 2055, 909, 4185, 26689, 23155, 109857, 213957}},
+{20126, 18, 112817, {1, 3, 7, 3, 31, 17, 39, 203, 255, 345, 1461, 1561, 4349, 6451, 14763, 32993, 74475, 140557}},
+{20127, 18, 112827, {1, 1, 5, 3, 21, 57, 75, 201, 371, 529, 1471, 243, 3751, 581, 18405, 40933, 106311, 745}},
+{20128, 18, 112835, {1, 1, 3, 13, 7, 53, 125, 15, 55, 267, 1865, 3297, 4331, 2913, 21675, 58911, 28419, 105585}},
+{20129, 18, 112892, {1, 3, 5, 13, 7, 13, 37, 37, 207, 127, 785, 1129, 8123, 7655, 16003, 18907, 48883, 2001}},
+{20130, 18, 112898, {1, 1, 5, 3, 11, 3, 127, 149, 503, 1019, 887, 3429, 7775, 7113, 19571, 34461, 38889, 66981}},
+{20131, 18, 112915, {1, 3, 7, 7, 1, 55, 87, 217, 465, 485, 411, 2955, 4899, 1741, 7051, 42885, 1837, 68175}},
+{20132, 18, 112918, {1, 1, 7, 1, 7, 39, 25, 1, 185, 523, 273, 2409, 1867, 3101, 29823, 4509, 81621, 11815}},
+{20133, 18, 112937, {1, 1, 1, 11, 13, 11, 89, 237, 355, 347, 91, 1791, 5745, 4181, 29207, 39495, 5275, 199395}},
+{20134, 18, 112940, {1, 1, 7, 3, 17, 37, 109, 169, 191, 295, 1001, 2631, 1981, 11821, 8315, 40675, 1293, 220247}},
+{20135, 18, 112958, {1, 3, 1, 7, 31, 25, 5, 55, 1, 795, 1663, 3177, 6821, 2073, 25789, 23691, 25015, 75203}},
+{20136, 18, 113013, {1, 3, 5, 9, 19, 9, 97, 129, 351, 735, 1897, 3555, 1731, 5413, 32051, 12869, 111973, 100157}},
+{20137, 18, 113014, {1, 3, 3, 15, 27, 1, 3, 167, 7, 851, 805, 713, 6389, 1455, 32371, 7617, 107157, 131299}},
+{20138, 18, 113027, {1, 3, 1, 13, 31, 29, 91, 123, 387, 939, 223, 3583, 2889, 5307, 16561, 6055, 4437, 123229}},
+{20139, 18, 113048, {1, 3, 5, 11, 27, 17, 5, 145, 369, 449, 1677, 1039, 3553, 3057, 11667, 51879, 20519, 41573}},
+{20140, 18, 113051, {1, 3, 1, 9, 9, 1, 91, 33, 379, 35, 691, 375, 5937, 15019, 16177, 53457, 52015, 232257}},
+{20141, 18, 113053, {1, 1, 3, 11, 23, 17, 75, 217, 377, 571, 1725, 2719, 3911, 12277, 27799, 55573, 21981, 112529}},
+{20142, 18, 113102, {1, 3, 1, 11, 9, 37, 81, 95, 501, 615, 327, 3751, 7333, 15407, 7785, 29113, 116335, 221853}},
+{20143, 18, 113104, {1, 1, 1, 3, 17, 1, 125, 157, 461, 845, 93, 107, 4429, 2271, 14445, 32919, 81175, 244557}},
+{20144, 18, 113114, {1, 3, 3, 1, 27, 23, 33, 15, 29, 361, 409, 981, 7819, 10259, 21971, 23317, 66641, 54591}},
+{20145, 18, 113130, {1, 3, 7, 13, 31, 63, 11, 167, 511, 81, 1165, 3973, 4275, 3315, 10227, 34973, 58505, 2333}},
+{20146, 18, 113159, {1, 3, 1, 9, 3, 49, 111, 101, 41, 775, 449, 1349, 4411, 8691, 535, 60137, 3269, 204895}},
+{20147, 18, 113180, {1, 3, 7, 15, 7, 43, 39, 147, 309, 185, 733, 1473, 5467, 6183, 17971, 56805, 111931, 163515}},
+{20148, 18, 113189, {1, 3, 1, 3, 21, 31, 17, 129, 317, 587, 801, 2517, 2569, 765, 20869, 16461, 34425, 101123}},
+{20149, 18, 113211, {1, 3, 1, 7, 13, 63, 117, 31, 25, 741, 365, 687, 6195, 2093, 14679, 16861, 123381, 25263}},
+{20150, 18, 113245, {1, 1, 1, 3, 13, 59, 65, 131, 41, 39, 1659, 1491, 225, 10277, 12445, 4161, 92119, 146705}},
+{20151, 18, 113261, {1, 3, 5, 1, 31, 11, 21, 203, 345, 473, 1643, 1377, 555, 11675, 15383, 30855, 41249, 231059}},
+{20152, 18, 113273, {1, 1, 7, 15, 3, 23, 33, 133, 433, 407, 1217, 3345, 7455, 11489, 21463, 41621, 95755, 86971}},
+{20153, 18, 113292, {1, 1, 1, 3, 13, 47, 45, 181, 489, 89, 427, 1915, 3993, 10133, 20437, 31811, 48421, 150009}},
+{20154, 18, 113314, {1, 3, 1, 9, 9, 25, 89, 195, 503, 755, 59, 1869, 6645, 13841, 22973, 17761, 46759, 68717}},
+{20155, 18, 113319, {1, 3, 1, 1, 19, 21, 119, 123, 481, 289, 1009, 3769, 3909, 1123, 17875, 17383, 71533, 45455}},
+{20156, 18, 113323, {1, 1, 1, 3, 31, 33, 127, 43, 467, 749, 377, 3025, 511, 13335, 23987, 63627, 50211, 197253}},
+{20157, 18, 113326, {1, 1, 5, 13, 29, 7, 101, 43, 299, 769, 1637, 3731, 1945, 9933, 22263, 1523, 127557, 116867}},
+{20158, 18, 113337, {1, 1, 3, 11, 1, 59, 25, 45, 275, 535, 1349, 3625, 8125, 727, 1215, 15487, 86229, 124817}},
+{20159, 18, 113338, {1, 3, 3, 13, 3, 11, 25, 237, 213, 331, 395, 1775, 1225, 6859, 16577, 39105, 118081, 74727}},
+{20160, 18, 113355, {1, 1, 1, 9, 5, 27, 117, 75, 479, 757, 1299, 2273, 3221, 5297, 249, 60327, 48739, 107023}},
+{20161, 18, 113365, {1, 1, 5, 9, 27, 9, 123, 49, 63, 763, 121, 3955, 2069, 5999, 25973, 64661, 6321, 1179}},
+{20162, 18, 113376, {1, 3, 7, 11, 9, 51, 65, 93, 51, 51, 829, 3239, 7431, 3489, 7691, 38777, 28151, 96635}},
+{20163, 18, 113408, {1, 3, 3, 13, 15, 51, 13, 203, 49, 73, 363, 2173, 7771, 11527, 27683, 39333, 2083, 178623}},
+{20164, 18, 113462, {1, 1, 5, 5, 15, 27, 27, 127, 503, 955, 427, 3061, 6213, 917, 889, 12601, 72445, 105383}},
+{20165, 18, 113476, {1, 3, 5, 3, 27, 43, 105, 187, 309, 747, 1843, 723, 539, 8829, 19171, 46009, 26129, 173145}},
+{20166, 18, 113503, {1, 3, 7, 7, 9, 51, 121, 139, 107, 453, 1103, 2957, 633, 1435, 27275, 53231, 51393, 16847}},
+{20167, 18, 113550, {1, 3, 7, 5, 25, 31, 71, 191, 169, 69, 1477, 1413, 7659, 11737, 12365, 25067, 21787, 16225}},
+{20168, 18, 113578, {1, 1, 7, 1, 9, 33, 37, 123, 391, 341, 829, 1543, 7323, 14695, 16431, 20009, 95821, 182791}},
+{20169, 18, 113580, {1, 3, 1, 5, 9, 59, 109, 39, 301, 977, 1963, 177, 8107, 16193, 5691, 14157, 71605, 250839}},
+{20170, 18, 113634, {1, 3, 5, 9, 29, 33, 33, 153, 7, 217, 201, 563, 6577, 9605, 16671, 63949, 97937, 234309}},
+{20171, 18, 113653, {1, 3, 7, 3, 25, 11, 81, 89, 275, 801, 477, 1921, 2279, 1651, 13333, 9127, 99693, 83141}},
+{20172, 18, 113677, {1, 3, 7, 5, 23, 51, 23, 51, 447, 689, 387, 1845, 6033, 2037, 20139, 33165, 56111, 243353}},
+{20173, 18, 113713, {1, 3, 5, 7, 5, 7, 105, 121, 439, 471, 721, 85, 1627, 3735, 29611, 15537, 36131, 30225}},
+{20174, 18, 113751, {1, 1, 5, 5, 7, 29, 31, 209, 183, 217, 467, 1287, 6145, 14737, 16249, 8857, 101405, 103355}},
+{20175, 18, 113771, {1, 3, 3, 5, 19, 1, 43, 15, 239, 63, 617, 2189, 3841, 1223, 12217, 4121, 88047, 14069}},
+{20176, 18, 113781, {1, 3, 7, 1, 9, 49, 11, 65, 297, 943, 1739, 3797, 6169, 2057, 5031, 2149, 21439, 141039}},
+{20177, 18, 113797, {1, 1, 1, 7, 15, 59, 35, 203, 347, 529, 1741, 1003, 6143, 4979, 15495, 48447, 2139, 187025}},
+{20178, 18, 113846, {1, 1, 7, 13, 15, 17, 77, 225, 461, 691, 1067, 1133, 6555, 511, 25845, 39835, 11755, 142743}},
+{20179, 18, 113849, {1, 3, 3, 11, 27, 25, 49, 51, 335, 1, 381, 2703, 7023, 14739, 19335, 39625, 82255, 76277}},
+{20180, 18, 113855, {1, 3, 3, 7, 19, 3, 35, 95, 203, 991, 515, 2245, 6085, 4129, 9581, 38309, 114203, 136021}},
+{20181, 18, 113878, {1, 1, 7, 7, 21, 61, 31, 57, 459, 119, 523, 1293, 3647, 735, 28849, 15581, 123943, 210069}},
+{20182, 18, 113884, {1, 1, 7, 3, 9, 55, 103, 23, 401, 109, 23, 4083, 6179, 12817, 2787, 43337, 53647, 241507}},
+{20183, 18, 113926, {1, 1, 5, 7, 9, 51, 37, 133, 97, 933, 1509, 2229, 1769, 12901, 15439, 25687, 128823, 72451}},
+{20184, 18, 113938, {1, 3, 1, 13, 17, 19, 7, 109, 299, 799, 621, 3393, 3645, 283, 29889, 63215, 97805, 45795}},
+{20185, 18, 113956, {1, 3, 1, 15, 21, 7, 65, 237, 221, 433, 1611, 2591, 3639, 3231, 6025, 53465, 88091, 17657}},
+{20186, 18, 113980, {1, 1, 7, 9, 27, 13, 11, 185, 381, 43, 961, 2743, 2691, 10531, 3713, 61757, 124011, 209323}},
+{20187, 18, 113986, {1, 3, 5, 1, 13, 7, 109, 65, 359, 577, 2001, 3085, 3519, 8577, 19299, 40145, 37159, 82421}},
+{20188, 18, 113991, {1, 1, 3, 11, 7, 5, 21, 215, 391, 317, 879, 1835, 611, 7189, 3887, 45383, 41025, 175701}},
+{20189, 18, 114005, {1, 1, 1, 1, 5, 17, 69, 115, 481, 477, 2017, 583, 8033, 11349, 16625, 213, 88033, 31707}},
+{20190, 18, 114022, {1, 1, 7, 15, 19, 55, 121, 35, 1, 71, 1011, 3247, 4133, 1681, 29943, 30149, 96797, 177707}},
+{20191, 18, 114036, {1, 3, 5, 13, 11, 45, 83, 153, 455, 223, 787, 2025, 5271, 229, 17549, 5775, 75311, 134523}},
+{20192, 18, 114046, {1, 3, 5, 7, 21, 43, 3, 253, 395, 651, 1111, 1685, 539, 6555, 25761, 39477, 15823, 261825}},
+{20193, 18, 114050, {1, 3, 7, 15, 27, 35, 43, 191, 269, 247, 883, 887, 1505, 7433, 6239, 5421, 49583, 17765}},
+{20194, 18, 114061, {1, 1, 5, 15, 7, 19, 113, 177, 63, 119, 517, 3987, 971, 12071, 13107, 28913, 85675, 204921}},
+{20195, 18, 114067, {1, 3, 7, 15, 31, 47, 21, 129, 31, 505, 661, 855, 6135, 13063, 27971, 63801, 27469, 75373}},
+{20196, 18, 114117, {1, 1, 7, 5, 13, 23, 111, 85, 279, 969, 483, 831, 483, 9065, 10997, 59031, 5083, 150939}},
+{20197, 18, 114142, {1, 3, 5, 7, 17, 55, 11, 223, 189, 209, 139, 577, 5443, 913, 19085, 53113, 8427, 11251}},
+{20198, 18, 114158, {1, 1, 1, 7, 23, 61, 95, 213, 443, 803, 1545, 3625, 2195, 2649, 10913, 14339, 23001, 16735}},
+{20199, 18, 114165, {1, 3, 3, 3, 13, 45, 15, 225, 419, 445, 527, 635, 2279, 5097, 25267, 199, 66187, 156717}},
+{20200, 18, 114200, {1, 1, 1, 7, 23, 17, 113, 245, 99, 159, 919, 2961, 1731, 6241, 12749, 8925, 44153, 243249}},
+{20201, 18, 114219, {1, 3, 1, 3, 29, 57, 43, 245, 389, 233, 135, 45, 3771, 14061, 10173, 51939, 128985, 81605}},
+{20202, 18, 114254, {1, 1, 1, 15, 1, 19, 25, 111, 91, 193, 1185, 3679, 7155, 7077, 13743, 35631, 128975, 196979}},
+{20203, 18, 114265, {1, 3, 3, 13, 31, 57, 25, 53, 149, 331, 643, 915, 1607, 14429, 29803, 23459, 72915, 39253}},
+{20204, 18, 114272, {1, 3, 3, 9, 23, 45, 9, 29, 383, 277, 981, 1647, 5217, 4449, 26759, 63849, 98081, 37565}},
+{20205, 18, 114312, {1, 1, 1, 15, 3, 23, 9, 121, 231, 27, 1961, 2389, 1689, 7041, 8069, 37973, 74601, 15553}},
+{20206, 18, 114318, {1, 1, 5, 15, 15, 29, 11, 177, 355, 47, 1821, 393, 3383, 10439, 6357, 41119, 60323, 206253}},
+{20207, 18, 114348, {1, 1, 1, 1, 21, 29, 87, 149, 157, 979, 1867, 729, 1949, 4409, 27495, 6841, 89033, 214957}},
+{20208, 18, 114377, {1, 1, 3, 3, 9, 7, 115, 129, 141, 157, 881, 109, 5537, 303, 32549, 1953, 9903, 82401}},
+{20209, 18, 114383, {1, 1, 5, 15, 9, 19, 93, 53, 319, 913, 1341, 705, 4639, 16189, 11375, 39155, 81393, 115843}},
+{20210, 18, 114386, {1, 1, 5, 7, 31, 21, 3, 47, 437, 799, 359, 3291, 3917, 12983, 19283, 23769, 34033, 226041}},
+{20211, 18, 114431, {1, 3, 7, 7, 27, 13, 65, 31, 181, 511, 1373, 3871, 1537, 6015, 12103, 42187, 121043, 95715}},
+{20212, 18, 114448, {1, 1, 5, 11, 1, 55, 91, 11, 105, 137, 1787, 81, 5163, 5793, 17403, 59433, 113439, 65751}},
+{20213, 18, 114479, {1, 1, 3, 13, 21, 57, 87, 157, 379, 5, 285, 3217, 4557, 3359, 28953, 63397, 110537, 230571}},
+{20214, 18, 114487, {1, 3, 7, 7, 7, 27, 25, 109, 125, 337, 719, 561, 5903, 12913, 6987, 17157, 50655, 195109}},
+{20215, 18, 114513, {1, 3, 3, 15, 3, 11, 97, 93, 441, 19, 1435, 515, 6129, 5177, 28075, 53495, 107817, 78399}},
+{20216, 18, 114542, {1, 3, 1, 9, 13, 7, 89, 171, 165, 479, 223, 4001, 691, 4033, 13577, 33363, 63447, 46609}},
+{20217, 18, 114572, {1, 3, 7, 1, 15, 47, 103, 45, 209, 639, 1465, 2795, 6025, 7981, 29491, 47743, 12861, 222445}},
+{20218, 18, 114584, {1, 3, 3, 3, 1, 25, 121, 91, 253, 969, 1259, 1409, 1329, 15995, 17733, 24081, 101747, 120619}},
+{20219, 18, 114600, {1, 3, 7, 11, 11, 5, 7, 241, 469, 411, 1733, 1385, 7005, 10977, 23369, 10675, 90341, 93077}},
+{20220, 18, 114605, {1, 3, 3, 13, 17, 35, 107, 189, 437, 801, 1761, 3133, 3847, 14079, 22465, 45957, 38449, 54273}},
+{20221, 18, 114623, {1, 1, 7, 9, 9, 47, 55, 107, 491, 281, 777, 2187, 6179, 6607, 2151, 9093, 42873, 104677}},
+{20222, 18, 114628, {1, 1, 5, 3, 25, 3, 37, 55, 339, 619, 1227, 3859, 5593, 9639, 31199, 48155, 80779, 6497}},
+{20223, 18, 114640, {1, 1, 7, 1, 21, 49, 105, 45, 119, 635, 163, 3821, 3689, 11395, 19265, 14289, 89259, 167433}},
+{20224, 18, 114650, {1, 3, 3, 15, 29, 23, 11, 255, 425, 443, 1659, 3965, 4791, 10223, 11113, 48751, 7987, 166605}},
+{20225, 18, 114668, {1, 1, 7, 3, 7, 1, 113, 153, 233, 803, 539, 297, 4847, 11203, 29393, 54319, 94373, 173471}},
+{20226, 18, 114671, {1, 3, 3, 5, 27, 57, 23, 147, 423, 617, 103, 3369, 4825, 13613, 23635, 61977, 5331, 115243}},
+{20227, 18, 114674, {1, 3, 3, 9, 11, 47, 41, 27, 345, 657, 1873, 365, 1685, 11181, 31977, 60489, 98741, 215357}},
+{20228, 18, 114700, {1, 3, 1, 11, 19, 33, 39, 223, 151, 921, 309, 3413, 6735, 11971, 25583, 6927, 54821, 125203}},
+{20229, 18, 114731, {1, 1, 5, 1, 27, 31, 61, 247, 207, 895, 1453, 3613, 7097, 6537, 29407, 9903, 39937, 98285}},
+{20230, 18, 114748, {1, 3, 1, 5, 7, 11, 119, 7, 323, 27, 1069, 2033, 7387, 3381, 19007, 49039, 39453, 115411}},
+{20231, 18, 114759, {1, 1, 7, 3, 9, 15, 51, 139, 353, 857, 1829, 3955, 7669, 3961, 22805, 39879, 26677, 66865}},
+{20232, 18, 114766, {1, 3, 5, 7, 1, 11, 59, 95, 181, 645, 829, 3119, 3607, 5973, 12381, 41577, 79443, 226945}},
+{20233, 18, 114768, {1, 3, 3, 5, 3, 13, 91, 119, 103, 889, 703, 3005, 541, 7529, 12613, 14267, 70445, 217543}},
+{20234, 18, 114784, {1, 1, 5, 7, 17, 41, 5, 225, 85, 759, 1071, 2055, 1655, 14811, 25635, 50803, 58545, 105687}},
+{20235, 18, 114808, {1, 3, 5, 13, 3, 7, 77, 209, 139, 717, 985, 1085, 831, 11011, 27313, 46423, 29435, 207359}},
+{20236, 18, 114813, {1, 3, 1, 7, 27, 45, 39, 75, 311, 937, 1593, 1357, 4815, 1997, 1045, 48681, 49301, 155607}},
+{20237, 18, 114829, {1, 3, 5, 11, 21, 9, 111, 39, 447, 241, 1613, 1799, 4817, 1861, 1263, 63641, 92081, 252051}},
+{20238, 18, 114830, {1, 1, 1, 13, 31, 13, 39, 29, 349, 25, 1227, 2457, 3831, 7965, 16903, 25825, 62381, 101765}},
+{20239, 18, 114842, {1, 1, 3, 7, 15, 17, 5, 29, 83, 607, 931, 261, 1087, 16247, 10129, 7813, 5445, 167723}},
+{20240, 18, 114875, {1, 3, 5, 9, 15, 31, 69, 191, 139, 467, 1681, 1951, 7813, 4295, 18191, 11411, 15601, 13025}},
+{20241, 18, 114898, {1, 1, 1, 11, 29, 53, 97, 205, 281, 917, 1009, 913, 1003, 16085, 30339, 55753, 53099, 30697}},
+{20242, 18, 114903, {1, 1, 3, 15, 25, 35, 7, 227, 63, 251, 845, 843, 7117, 6021, 26917, 43611, 108643, 215471}},
+{20243, 18, 114913, {1, 1, 3, 11, 19, 29, 75, 5, 131, 37, 1185, 2387, 8161, 1621, 19887, 20525, 33067, 30869}},
+{20244, 18, 114928, {1, 1, 3, 3, 7, 37, 75, 159, 313, 17, 479, 2477, 7779, 309, 26095, 35693, 92561, 143151}},
+{20245, 18, 114937, {1, 1, 5, 9, 5, 29, 65, 223, 331, 1013, 37, 1813, 1379, 9277, 14681, 61687, 24763, 124669}},
+{20246, 18, 114958, {1, 3, 1, 1, 17, 47, 7, 219, 11, 13, 1517, 2583, 7483, 5399, 6883, 51387, 17901, 108659}},
+{20247, 18, 114963, {1, 3, 7, 11, 9, 63, 81, 91, 411, 535, 255, 3683, 5285, 1787, 27205, 43651, 15647, 230651}},
+{20248, 18, 115000, {1, 3, 1, 11, 7, 47, 35, 255, 341, 379, 421, 753, 7821, 13271, 13021, 463, 48457, 132521}},
+{20249, 18, 115018, {1, 1, 5, 7, 21, 23, 53, 229, 393, 509, 1641, 2245, 6941, 10447, 3231, 5451, 18883, 47401}},
+{20250, 18, 115023, {1, 3, 1, 7, 13, 61, 71, 49, 147, 625, 299, 3843, 4851, 3483, 27005, 23871, 18855, 124893}},
+{20251, 18, 115028, {1, 3, 1, 7, 31, 13, 127, 177, 259, 179, 531, 1775, 5481, 13157, 23821, 31773, 93941, 237697}},
+{20252, 18, 115042, {1, 1, 7, 1, 23, 21, 111, 219, 401, 455, 1603, 2077, 1537, 2063, 17821, 52087, 20707, 29535}},
+{20253, 18, 115084, {1, 1, 3, 11, 17, 17, 13, 79, 49, 353, 1691, 361, 2805, 7121, 27013, 50631, 108235, 70513}},
+{20254, 18, 115096, {1, 1, 5, 3, 15, 25, 103, 73, 377, 253, 1303, 501, 555, 15789, 16647, 9019, 60581, 157337}},
+{20255, 18, 115105, {1, 3, 5, 9, 23, 45, 3, 251, 25, 559, 429, 1091, 5657, 15387, 5113, 64533, 131049, 127587}},
+{20256, 18, 115117, {1, 1, 3, 15, 1, 53, 71, 141, 413, 849, 737, 3045, 7119, 8049, 18295, 31447, 70735, 117457}},
+{20257, 18, 115149, {1, 1, 1, 11, 17, 11, 69, 155, 211, 249, 1869, 1575, 6859, 7045, 7015, 20135, 84157, 232621}},
+{20258, 18, 115155, {1, 3, 7, 5, 19, 55, 15, 163, 457, 371, 1665, 1935, 601, 3629, 21975, 1191, 45133, 111649}},
+{20259, 18, 115198, {1, 3, 7, 11, 23, 33, 5, 253, 355, 379, 933, 1781, 3989, 6191, 19081, 7651, 74671, 258799}},
+{20260, 18, 115221, {1, 1, 3, 3, 23, 3, 63, 123, 273, 861, 369, 2409, 1505, 9059, 10727, 189, 122911, 44037}},
+{20261, 18, 115222, {1, 1, 7, 13, 13, 23, 19, 87, 191, 397, 2027, 1689, 1143, 10919, 27073, 15013, 118429, 119165}},
+{20262, 18, 115225, {1, 1, 5, 9, 15, 13, 29, 81, 409, 955, 1827, 1341, 3473, 16005, 29041, 57527, 7329, 167093}},
+{20263, 18, 115276, {1, 1, 5, 3, 11, 31, 47, 13, 171, 995, 961, 3885, 3259, 2745, 12405, 49281, 2901, 207591}},
+{20264, 18, 115294, {1, 3, 5, 13, 31, 3, 1, 215, 465, 279, 1697, 2449, 3829, 2053, 9877, 52911, 126077, 210515}},
+{20265, 18, 115297, {1, 1, 3, 7, 11, 27, 55, 115, 249, 353, 407, 2567, 8105, 7747, 18111, 3383, 101875, 2185}},
+{20266, 18, 115321, {1, 1, 3, 9, 25, 5, 35, 137, 405, 667, 1671, 2965, 5975, 4999, 18421, 43623, 64621, 129797}},
+{20267, 18, 115348, {1, 3, 7, 13, 3, 17, 33, 191, 463, 787, 1795, 3037, 1679, 63, 12389, 3983, 22385, 84235}},
+{20268, 18, 115364, {1, 1, 5, 9, 11, 25, 85, 215, 355, 553, 317, 1637, 3461, 15943, 2619, 14545, 125507, 18659}},
+{20269, 18, 115376, {1, 1, 7, 5, 3, 41, 105, 179, 125, 557, 1345, 3631, 481, 10621, 11213, 40223, 46581, 113137}},
+{20270, 18, 115385, {1, 3, 3, 15, 1, 63, 95, 213, 89, 21, 1249, 3063, 413, 4307, 26723, 10225, 115143, 144817}},
+{20271, 18, 115386, {1, 3, 5, 15, 9, 43, 41, 117, 419, 143, 1651, 377, 4775, 8761, 23793, 8719, 76499, 208119}},
+{20272, 18, 115400, {1, 3, 3, 1, 21, 29, 47, 117, 23, 333, 1153, 1067, 5859, 9375, 29997, 58991, 55895, 204933}},
+{20273, 18, 115414, {1, 1, 3, 11, 11, 21, 115, 85, 223, 281, 701, 1331, 1341, 1149, 5993, 10885, 77353, 113553}},
+{20274, 18, 115465, {1, 1, 5, 1, 25, 1, 1, 153, 449, 231, 593, 3061, 4157, 6661, 21735, 11361, 57751, 129569}},
+{20275, 18, 115485, {1, 1, 3, 7, 27, 63, 81, 251, 125, 197, 1525, 1637, 4643, 4743, 17127, 51217, 95781, 973}},
+{20276, 18, 115492, {1, 1, 3, 7, 11, 51, 13, 139, 83, 341, 543, 3061, 7777, 6705, 9609, 28933, 24669, 225275}},
+{20277, 18, 115501, {1, 3, 1, 9, 25, 39, 99, 139, 5, 725, 1759, 1577, 1751, 3197, 3169, 39051, 1743, 108813}},
+{20278, 18, 115519, {1, 1, 7, 5, 31, 15, 115, 229, 499, 291, 501, 3119, 2293, 14137, 625, 16379, 111057, 101643}},
+{20279, 18, 115527, {1, 3, 7, 15, 31, 1, 51, 73, 455, 51, 1983, 3687, 6049, 3495, 26247, 6567, 28479, 158909}},
+{20280, 18, 115531, {1, 3, 5, 5, 9, 11, 77, 181, 165, 773, 1611, 3945, 6787, 3827, 28597, 53269, 34003, 237291}},
+{20281, 18, 115567, {1, 1, 5, 3, 31, 57, 15, 9, 163, 363, 1021, 2193, 8175, 3851, 26059, 63915, 114293, 163637}},
+{20282, 18, 115572, {1, 1, 3, 7, 27, 49, 35, 121, 469, 833, 879, 1601, 6991, 13271, 8085, 45343, 5189, 109413}},
+{20283, 18, 115631, {1, 3, 1, 15, 7, 11, 111, 153, 129, 769, 565, 2693, 333, 7343, 28535, 56937, 85641, 19871}},
+{20284, 18, 115648, {1, 1, 5, 13, 7, 49, 121, 223, 55, 33, 19, 2291, 1847, 10173, 23337, 23431, 18181, 155663}},
+{20285, 18, 115660, {1, 3, 1, 11, 25, 9, 3, 255, 425, 861, 1025, 3719, 6995, 14687, 31083, 60609, 115375, 17813}},
+{20286, 18, 115672, {1, 1, 5, 13, 1, 55, 109, 239, 13, 939, 1077, 669, 1643, 10949, 25399, 55055, 125829, 253077}},
+{20287, 18, 115681, {1, 1, 5, 3, 15, 51, 13, 133, 257, 387, 2017, 2223, 1479, 9377, 12867, 9833, 32323, 6255}},
+{20288, 18, 115688, {1, 3, 1, 9, 1, 53, 121, 163, 349, 491, 1867, 3403, 6859, 459, 1483, 23893, 66851, 150843}},
+{20289, 18, 115694, {1, 1, 1, 1, 1, 33, 51, 33, 177, 633, 449, 2705, 663, 3701, 8331, 43895, 87223, 48587}},
+{20290, 18, 115699, {1, 3, 5, 7, 23, 7, 99, 43, 217, 31, 749, 2831, 1557, 3295, 6797, 45229, 46831, 62183}},
+{20291, 18, 115719, {1, 1, 7, 7, 1, 45, 35, 51, 415, 693, 479, 1017, 6703, 241, 30887, 8953, 26901, 2951}},
+{20292, 18, 115726, {1, 3, 3, 7, 29, 3, 25, 217, 67, 769, 653, 3983, 5513, 15481, 21399, 17525, 81747, 109843}},
+{20293, 18, 115733, {1, 3, 5, 5, 29, 17, 97, 187, 157, 189, 1531, 1123, 4291, 14831, 15493, 62753, 53563, 153679}},
+{20294, 18, 115796, {1, 3, 7, 13, 15, 63, 47, 5, 351, 275, 1177, 3947, 6755, 1319, 17053, 14267, 98215, 228795}},
+{20295, 18, 115879, {1, 3, 7, 5, 19, 45, 43, 223, 213, 903, 539, 267, 83, 6951, 2979, 56929, 58405, 198373}},
+{20296, 18, 115880, {1, 1, 5, 11, 21, 37, 109, 103, 29, 49, 17, 3987, 5679, 2559, 17391, 46157, 38743, 82245}},
+{20297, 18, 115888, {1, 1, 3, 7, 7, 35, 57, 187, 113, 361, 721, 1821, 6473, 10233, 22549, 37725, 8445, 220669}},
+{20298, 18, 115908, {1, 3, 3, 9, 21, 41, 73, 29, 163, 701, 1277, 3869, 1529, 4889, 10091, 65507, 53829, 191347}},
+{20299, 18, 115925, {1, 1, 5, 15, 5, 21, 39, 39, 341, 271, 1543, 3161, 3935, 8319, 24921, 19575, 95009, 256221}},
+{20300, 18, 115942, {1, 1, 1, 3, 11, 33, 63, 189, 21, 773, 1261, 3947, 183, 6769, 31337, 22179, 57255, 8323}},
+{20301, 18, 115978, {1, 1, 3, 15, 29, 59, 103, 251, 107, 499, 915, 387, 3127, 5597, 3345, 15657, 979, 91685}},
+{20302, 18, 115986, {1, 3, 3, 11, 13, 27, 9, 137, 177, 75, 567, 1511, 7355, 3087, 15309, 51733, 87329, 217125}},
+{20303, 18, 116014, {1, 1, 1, 15, 9, 43, 113, 177, 507, 379, 765, 75, 6895, 7523, 24611, 7315, 49653, 59263}},
+{20304, 18, 116019, {1, 3, 1, 5, 29, 23, 59, 215, 267, 161, 1957, 341, 4081, 9635, 3345, 12323, 128751, 144577}},
+{20305, 18, 116031, {1, 3, 3, 13, 17, 55, 59, 73, 65, 697, 1209, 3345, 5629, 4545, 23043, 37649, 55015, 10263}},
+{20306, 18, 116048, {1, 1, 7, 1, 21, 3, 7, 19, 445, 417, 1677, 799, 1241, 15463, 19815, 52845, 81309, 256713}},
+{20307, 18, 116069, {1, 1, 3, 13, 13, 57, 17, 199, 3, 377, 1799, 2713, 3937, 12511, 7439, 33605, 56697, 168195}},
+{20308, 18, 116091, {1, 3, 1, 7, 21, 53, 115, 97, 389, 83, 961, 813, 1499, 3411, 22377, 33323, 118405, 115947}},
+{20309, 18, 116103, {1, 3, 7, 11, 23, 43, 85, 249, 151, 893, 833, 901, 7731, 13467, 14721, 38613, 104033, 136097}},
+{20310, 18, 116107, {1, 3, 1, 11, 23, 23, 119, 129, 175, 159, 1031, 2379, 2753, 6755, 10979, 18225, 52375, 257003}},
+{20311, 18, 116145, {1, 3, 1, 13, 1, 9, 61, 255, 433, 621, 1469, 705, 5841, 7421, 23873, 30487, 55823, 119705}},
+{20312, 18, 116152, {1, 3, 1, 15, 19, 31, 29, 163, 87, 793, 885, 2495, 4609, 2757, 5333, 52937, 79187, 228777}},
+{20313, 18, 116247, {1, 1, 1, 3, 17, 43, 69, 241, 143, 173, 327, 2747, 5617, 16347, 16155, 47775, 25917, 163663}},
+{20314, 18, 116289, {1, 1, 1, 1, 19, 19, 15, 27, 25, 139, 691, 4019, 3055, 10301, 11281, 10957, 59117, 178149}},
+{20315, 18, 116316, {1, 1, 1, 3, 15, 15, 37, 89, 103, 7, 527, 2823, 7205, 6831, 25179, 22249, 103323, 31251}},
+{20316, 18, 116344, {1, 1, 3, 3, 7, 49, 7, 241, 37, 11, 577, 1987, 1935, 14787, 16411, 36305, 65185, 221253}},
+{20317, 18, 116354, {1, 1, 1, 5, 31, 51, 123, 169, 441, 13, 721, 2359, 5687, 2641, 16339, 8441, 55967, 98775}},
+{20318, 18, 116368, {1, 1, 7, 5, 21, 23, 91, 229, 23, 105, 339, 2371, 7803, 14913, 12651, 40573, 117399, 134865}},
+{20319, 18, 116377, {1, 3, 1, 15, 19, 27, 127, 77, 469, 343, 451, 2251, 6705, 7765, 8623, 10367, 100379, 140899}},
+{20320, 18, 116383, {1, 3, 1, 5, 1, 11, 93, 231, 33, 133, 1545, 1015, 7577, 8871, 29975, 12141, 130833, 103123}},
+{20321, 18, 116387, {1, 3, 3, 5, 7, 25, 95, 93, 293, 543, 1785, 2097, 6045, 4225, 607, 443, 72055, 32269}},
+{20322, 18, 116408, {1, 1, 1, 1, 5, 55, 47, 105, 189, 359, 1589, 765, 2303, 11963, 25565, 40669, 98977, 242089}},
+{20323, 18, 116428, {1, 1, 1, 15, 13, 45, 121, 235, 125, 181, 1891, 3265, 2097, 3207, 31647, 13407, 22515, 15155}},
+{20324, 18, 116445, {1, 1, 5, 15, 13, 11, 81, 233, 307, 505, 221, 813, 6483, 741, 9819, 19405, 74235, 144761}},
+{20325, 18, 116476, {1, 3, 5, 7, 9, 25, 31, 209, 337, 473, 1831, 2711, 5551, 13531, 28747, 1875, 6401, 159995}},
+{20326, 18, 116482, {1, 1, 7, 7, 29, 3, 127, 207, 387, 849, 1449, 2741, 2105, 885, 18115, 5433, 122119, 16969}},
+{20327, 18, 116488, {1, 3, 7, 9, 25, 17, 43, 209, 41, 927, 409, 1567, 1609, 12487, 16305, 41365, 10991, 172127}},
+{20328, 18, 116493, {1, 1, 3, 7, 27, 29, 63, 127, 81, 283, 1459, 143, 5993, 14027, 8055, 28065, 128389, 255307}},
+{20329, 18, 116502, {1, 3, 7, 11, 13, 41, 63, 223, 215, 901, 1853, 2881, 5149, 7439, 4519, 33279, 127765, 139431}},
+{20330, 18, 116518, {1, 3, 7, 7, 15, 61, 61, 173, 221, 711, 191, 3863, 2695, 9663, 6277, 8791, 128019, 256755}},
+{20331, 18, 116524, {1, 3, 1, 9, 29, 45, 83, 43, 297, 605, 1887, 2421, 2307, 5199, 17275, 39225, 127215, 253687}},
+{20332, 18, 116527, {1, 1, 5, 3, 21, 23, 121, 125, 497, 945, 1367, 2757, 3481, 8607, 32447, 62373, 32171, 226621}},
+{20333, 18, 116549, {1, 3, 1, 5, 7, 1, 71, 255, 465, 951, 129, 1989, 6053, 3737, 6511, 54519, 16947, 124491}},
+{20334, 18, 116561, {1, 3, 5, 1, 9, 21, 127, 49, 85, 615, 1897, 1715, 7923, 10309, 16919, 24131, 18015, 140195}},
+{20335, 18, 116562, {1, 1, 1, 1, 5, 27, 3, 205, 29, 319, 485, 3941, 7829, 789, 4207, 39939, 67761, 152459}},
+{20336, 18, 116568, {1, 3, 7, 11, 9, 41, 1, 129, 511, 831, 1007, 2011, 6211, 9179, 20877, 62121, 21879, 23661}},
+{20337, 18, 116577, {1, 1, 7, 1, 19, 53, 75, 123, 181, 735, 925, 1065, 3317, 3201, 27473, 19379, 78223, 45725}},
+{20338, 18, 116590, {1, 1, 5, 9, 9, 61, 3, 193, 441, 815, 583, 3235, 247, 14091, 19877, 33505, 3477, 20111}},
+{20339, 18, 116602, {1, 1, 5, 13, 29, 53, 55, 165, 359, 889, 1833, 1543, 7913, 307, 22853, 37839, 15569, 140127}},
+{20340, 18, 116607, {1, 1, 1, 15, 21, 53, 63, 195, 299, 1019, 1371, 1311, 5401, 8015, 30335, 56281, 61011, 59279}},
+{20341, 18, 116611, {1, 1, 3, 13, 3, 57, 45, 239, 445, 419, 581, 3971, 4621, 9327, 27255, 53069, 126415, 250313}},
+{20342, 18, 116626, {1, 3, 1, 9, 5, 63, 21, 25, 447, 961, 1857, 3123, 3029, 9743, 26069, 38251, 58475, 108737}},
+{20343, 18, 116637, {1, 3, 1, 15, 13, 59, 5, 21, 171, 107, 1631, 2407, 6695, 8079, 2805, 50995, 53173, 104757}},
+{20344, 18, 116647, {1, 3, 7, 7, 1, 55, 103, 67, 369, 533, 515, 2363, 5147, 11633, 20435, 24591, 68155, 140029}},
+{20345, 18, 116665, {1, 3, 7, 13, 19, 51, 13, 149, 159, 915, 1029, 2825, 5259, 5139, 31325, 42825, 119923, 227811}},
+{20346, 18, 116674, {1, 3, 3, 3, 23, 17, 121, 25, 403, 333, 491, 2869, 881, 12997, 5101, 48351, 90831, 143009}},
+{20347, 18, 116700, {1, 1, 3, 15, 23, 63, 93, 43, 107, 393, 419, 3509, 1543, 10295, 11019, 8389, 73753, 42681}},
+{20348, 18, 116714, {1, 1, 7, 1, 29, 49, 41, 189, 303, 955, 1241, 1623, 2269, 3413, 6261, 2155, 90945, 95117}},
+{20349, 18, 116719, {1, 1, 3, 15, 31, 13, 103, 241, 189, 283, 1303, 1693, 1587, 16313, 205, 43421, 121799, 200151}},
+{20350, 18, 116744, {1, 3, 5, 1, 29, 27, 105, 83, 345, 411, 1197, 3489, 5891, 1137, 7311, 681, 127991, 69533}},
+{20351, 18, 116764, {1, 3, 5, 15, 31, 11, 105, 221, 57, 39, 145, 3233, 1431, 16271, 21225, 47989, 72583, 191327}},
+{20352, 18, 116774, {1, 3, 7, 9, 25, 47, 109, 61, 257, 949, 981, 1383, 8003, 4661, 19555, 20191, 114641, 84817}},
+{20353, 18, 116778, {1, 1, 5, 9, 17, 9, 19, 209, 73, 573, 1039, 2741, 1495, 1615, 6299, 20507, 84729, 166977}},
+{20354, 18, 116798, {1, 3, 5, 13, 27, 51, 39, 203, 437, 725, 1479, 3071, 621, 15563, 28473, 58403, 25943, 116683}},
+{20355, 18, 116803, {1, 1, 3, 9, 5, 29, 63, 61, 329, 305, 523, 2243, 6689, 11773, 19319, 57783, 24265, 218153}},
+{20356, 18, 116806, {1, 3, 7, 5, 17, 27, 115, 9, 243, 613, 679, 1915, 7265, 2989, 13663, 15115, 50779, 235761}},
+{20357, 18, 116827, {1, 1, 5, 5, 13, 35, 111, 151, 255, 569, 1209, 3277, 4503, 3797, 22601, 19523, 126339, 141289}},
+{20358, 18, 116839, {1, 1, 3, 9, 15, 51, 85, 125, 233, 1011, 231, 2949, 1091, 8605, 14855, 62401, 14143, 212557}},
+{20359, 18, 116863, {1, 3, 5, 11, 29, 53, 83, 31, 201, 219, 1083, 967, 6913, 10325, 1971, 55841, 7733, 208883}},
+{20360, 18, 116873, {1, 3, 3, 1, 23, 33, 51, 103, 265, 285, 1363, 2813, 3327, 7921, 13537, 31483, 43405, 189641}},
+{20361, 18, 116882, {1, 1, 7, 15, 27, 3, 5, 87, 117, 437, 1251, 189, 3271, 15579, 25025, 23203, 39421, 133581}},
+{20362, 18, 116887, {1, 1, 5, 1, 9, 3, 91, 45, 71, 557, 2019, 2355, 5539, 2843, 13025, 61017, 3475, 179891}},
+{20363, 18, 116915, {1, 1, 7, 5, 17, 11, 127, 241, 9, 971, 1699, 2719, 1947, 109, 19817, 13949, 120247, 60775}},
+{20364, 18, 116939, {1, 1, 5, 9, 9, 39, 117, 221, 197, 767, 1691, 4075, 3665, 1271, 16119, 64129, 2681, 105325}},
+{20365, 18, 116944, {1, 3, 3, 11, 31, 51, 5, 23, 419, 715, 1985, 4095, 7255, 10491, 25575, 6177, 35917, 178345}},
+{20366, 18, 116953, {1, 3, 5, 7, 15, 23, 99, 203, 461, 509, 1501, 1965, 1105, 1341, 21713, 21901, 129905, 67937}},
+{20367, 18, 116965, {1, 3, 3, 15, 25, 5, 55, 167, 477, 125, 163, 2379, 2433, 12975, 26259, 55825, 19913, 202873}},
+{20368, 18, 117002, {1, 3, 3, 7, 15, 15, 67, 227, 413, 905, 1609, 2083, 4011, 10477, 22809, 61873, 96423, 119253}},
+{20369, 18, 117007, {1, 3, 1, 11, 13, 17, 37, 147, 355, 445, 619, 3181, 5939, 6953, 15859, 37979, 24723, 133037}},
+{20370, 18, 117015, {1, 1, 5, 15, 5, 25, 89, 3, 279, 569, 343, 2453, 5739, 2901, 6709, 43957, 75791, 20791}},
+{20371, 18, 117032, {1, 1, 3, 5, 13, 39, 53, 203, 75, 945, 635, 349, 2339, 2549, 23827, 7903, 128005, 14949}},
+{20372, 18, 117035, {1, 1, 7, 3, 7, 59, 59, 77, 143, 99, 1313, 3957, 3807, 15731, 20919, 60829, 105967, 226767}},
+{20373, 18, 117052, {1, 1, 3, 7, 17, 49, 27, 245, 129, 583, 1055, 741, 5607, 689, 20075, 54837, 113257, 222677}},
+{20374, 18, 117087, {1, 1, 7, 13, 17, 5, 19, 141, 205, 749, 1769, 2981, 5787, 4511, 135, 19475, 113735, 116859}},
+{20375, 18, 117139, {1, 3, 7, 1, 9, 33, 111, 139, 77, 117, 363, 1171, 2587, 1539, 30791, 10697, 6879, 104827}},
+{20376, 18, 117157, {1, 3, 3, 5, 27, 47, 49, 215, 65, 435, 1601, 231, 2047, 10405, 28409, 17013, 103909, 232051}},
+{20377, 18, 117193, {1, 3, 3, 3, 13, 19, 3, 159, 293, 675, 247, 2829, 6703, 6085, 1935, 18209, 15709, 186669}},
+{20378, 18, 117211, {1, 3, 3, 5, 21, 55, 17, 237, 121, 603, 953, 947, 6973, 15979, 11029, 12381, 12807, 131603}},
+{20379, 18, 117214, {1, 3, 5, 3, 3, 41, 121, 203, 283, 349, 1841, 115, 6567, 2131, 883, 50515, 78381, 168189}},
+{20380, 18, 117220, {1, 3, 7, 15, 5, 55, 85, 13, 77, 443, 1711, 1043, 1265, 3701, 5121, 41435, 40637, 69125}},
+{20381, 18, 117238, {1, 1, 5, 15, 15, 33, 67, 235, 3, 95, 1685, 731, 2187, 11857, 7197, 62113, 12565, 127455}},
+{20382, 18, 117248, {1, 3, 7, 7, 11, 45, 125, 231, 263, 611, 221, 195, 6347, 14029, 7823, 52295, 78879, 211441}},
+{20383, 18, 117275, {1, 3, 7, 15, 9, 63, 75, 189, 187, 449, 27, 3647, 4705, 13037, 3773, 36441, 35445, 181793}},
+{20384, 18, 117293, {1, 1, 5, 3, 31, 19, 123, 39, 297, 1017, 1191, 2227, 6085, 5117, 16569, 64743, 29329, 157279}},
+{20385, 18, 117301, {1, 1, 5, 5, 15, 47, 111, 61, 435, 657, 141, 3445, 6921, 7759, 30141, 37631, 85969, 227563}},
+{20386, 18, 117319, {1, 3, 1, 13, 27, 39, 15, 167, 151, 185, 1513, 211, 951, 12705, 25703, 29289, 120993, 156741}},
+{20387, 18, 117338, {1, 3, 7, 7, 7, 39, 19, 221, 351, 951, 1231, 1915, 3043, 189, 18977, 50149, 56583, 122147}},
+{20388, 18, 117347, {1, 1, 5, 15, 29, 37, 77, 207, 291, 851, 131, 1041, 1657, 4393, 5023, 12745, 32253, 204431}},
+{20389, 18, 117361, {1, 1, 7, 15, 11, 59, 85, 255, 67, 23, 1321, 2153, 7043, 417, 15719, 59937, 37619, 109331}},
+{20390, 18, 117380, {1, 3, 7, 15, 25, 37, 43, 15, 385, 735, 1741, 3655, 4215, 1097, 19519, 44313, 99851, 204717}},
+{20391, 18, 117389, {1, 1, 3, 7, 15, 17, 17, 105, 399, 49, 105, 159, 465, 11991, 29797, 23907, 129609, 179013}},
+{20392, 18, 117398, {1, 1, 7, 13, 9, 17, 87, 51, 391, 695, 545, 3061, 4499, 2059, 10095, 13847, 68519, 60611}},
+{20393, 18, 117435, {1, 3, 3, 1, 31, 7, 11, 233, 231, 189, 1599, 1589, 401, 8759, 17273, 43613, 48709, 253521}},
+{20394, 18, 117458, {1, 1, 1, 11, 5, 9, 27, 77, 491, 951, 579, 1635, 3241, 14497, 27149, 45001, 56769, 160731}},
+{20395, 18, 117476, {1, 3, 7, 15, 29, 11, 125, 101, 19, 971, 107, 1525, 3939, 7633, 16355, 24727, 19475, 157571}},
+{20396, 18, 117498, {1, 1, 1, 9, 25, 7, 35, 187, 321, 483, 1919, 1911, 7869, 12903, 26977, 49419, 24973, 214731}},
+{20397, 18, 117500, {1, 1, 5, 3, 23, 1, 11, 143, 315, 1015, 1367, 1555, 1041, 6655, 10481, 49275, 49575, 101061}},
+{20398, 18, 117529, {1, 3, 5, 15, 15, 59, 13, 117, 217, 975, 1821, 3829, 1545, 921, 20875, 43305, 18793, 158651}},
+{20399, 18, 117554, {1, 3, 3, 11, 23, 23, 91, 7, 29, 613, 1093, 3881, 3301, 3751, 16137, 48277, 119813, 177341}},
+{20400, 18, 117556, {1, 3, 3, 15, 7, 37, 115, 19, 147, 585, 1877, 2395, 3343, 9567, 16199, 13969, 89731, 124835}},
+{20401, 18, 117565, {1, 1, 5, 7, 29, 3, 59, 141, 375, 527, 1219, 409, 7155, 2823, 32497, 23103, 73187, 53089}},
+{20402, 18, 117580, {1, 1, 5, 3, 13, 27, 111, 63, 189, 813, 643, 19, 3461, 13891, 26651, 52395, 74729, 148397}},
+{20403, 18, 117585, {1, 3, 5, 1, 27, 61, 97, 227, 123, 829, 1559, 2523, 7737, 6047, 213, 23613, 61571, 7093}},
+{20404, 18, 117592, {1, 1, 1, 11, 17, 1, 73, 203, 391, 937, 321, 3431, 7163, 3547, 29467, 65271, 69775, 226405}},
+{20405, 18, 117597, {1, 1, 5, 15, 25, 7, 75, 199, 511, 731, 1547, 2127, 1609, 5623, 26771, 29935, 76671, 178683}},
+{20406, 18, 117616, {1, 3, 5, 15, 25, 49, 99, 23, 281, 81, 507, 1499, 5235, 9945, 14099, 5993, 319, 178581}},
+{20407, 18, 117637, {1, 3, 7, 9, 5, 13, 105, 7, 135, 827, 927, 3463, 839, 7047, 19863, 63859, 13951, 221795}},
+{20408, 18, 117644, {1, 1, 1, 13, 7, 21, 59, 9, 467, 299, 1035, 1395, 7413, 7313, 24769, 44043, 50679, 72867}},
+{20409, 18, 117659, {1, 1, 7, 1, 31, 33, 95, 155, 429, 413, 493, 2025, 2069, 551, 507, 13515, 3507, 93873}},
+{20410, 18, 117703, {1, 1, 3, 5, 3, 33, 109, 1, 299, 727, 495, 2981, 3795, 11467, 27173, 4171, 6859, 129961}},
+{20411, 18, 117704, {1, 1, 7, 9, 23, 41, 113, 103, 161, 303, 1565, 2637, 7113, 11635, 13707, 3559, 21007, 250107}},
+{20412, 18, 117727, {1, 1, 5, 13, 1, 49, 11, 87, 31, 77, 1847, 1137, 3031, 1943, 28755, 32197, 96043, 152447}},
+{20413, 18, 117738, {1, 1, 3, 7, 3, 3, 123, 65, 175, 809, 681, 2135, 5279, 7119, 4573, 19287, 90235, 183391}},
+{20414, 18, 117770, {1, 3, 1, 13, 7, 5, 25, 151, 437, 155, 1841, 219, 5641, 12097, 6153, 11, 60315, 169293}},
+{20415, 18, 117796, {1, 1, 7, 5, 21, 29, 23, 83, 35, 651, 1507, 635, 3867, 12133, 25523, 55341, 105741, 240349}},
+{20416, 18, 117799, {1, 1, 1, 15, 9, 29, 27, 151, 463, 747, 547, 577, 1263, 15235, 6695, 60849, 72231, 175671}},
+{20417, 18, 117820, {1, 3, 5, 11, 11, 43, 81, 37, 505, 509, 1325, 3295, 839, 5855, 19795, 1403, 15711, 219481}},
+{20418, 18, 117832, {1, 3, 3, 15, 25, 61, 121, 37, 201, 133, 537, 1345, 4213, 13023, 18795, 8949, 84431, 105521}},
+{20419, 18, 117840, {1, 3, 7, 11, 13, 51, 87, 245, 357, 7, 699, 2003, 5963, 1399, 69, 19083, 114585, 232313}},
+{20420, 18, 117843, {1, 1, 1, 13, 9, 29, 65, 123, 37, 885, 227, 2795, 1037, 10905, 21217, 4081, 77643, 254245}},
+{20421, 18, 117865, {1, 3, 1, 3, 25, 23, 71, 189, 253, 785, 1337, 1275, 3285, 1067, 8607, 3883, 119099, 116637}},
+{20422, 18, 117868, {1, 1, 1, 15, 19, 43, 17, 89, 257, 175, 1943, 207, 597, 9279, 405, 33209, 65221, 39557}},
+{20423, 18, 117874, {1, 1, 7, 5, 7, 47, 127, 11, 197, 871, 23, 1951, 6829, 7831, 5223, 56287, 115649, 114283}},
+{20424, 18, 117886, {1, 3, 1, 3, 1, 35, 81, 189, 19, 117, 1683, 469, 8117, 5449, 22871, 5505, 125111, 128717}},
+{20425, 18, 117962, {1, 3, 7, 5, 7, 31, 105, 57, 387, 691, 1293, 3103, 2329, 16247, 18357, 55453, 112633, 225641}},
+{20426, 18, 117967, {1, 3, 1, 3, 13, 3, 65, 25, 47, 413, 521, 3507, 1793, 14431, 22341, 39813, 46399, 204501}},
+{20427, 18, 117995, {1, 3, 1, 1, 31, 37, 21, 45, 261, 665, 1243, 1937, 5001, 3789, 26473, 20153, 107131, 75523}},
+{20428, 18, 118000, {1, 3, 5, 15, 27, 61, 109, 139, 19, 583, 353, 445, 53, 67, 20753, 57827, 116527, 55109}},
+{20429, 18, 118017, {1, 1, 3, 3, 1, 37, 113, 21, 305, 967, 1703, 2095, 1059, 2843, 22381, 24871, 24765, 52425}},
+{20430, 18, 118037, {1, 3, 7, 11, 27, 59, 111, 111, 283, 79, 1227, 3631, 4169, 5671, 7769, 56553, 75503, 206259}},
+{20431, 18, 118038, {1, 1, 5, 11, 11, 1, 127, 13, 17, 255, 1383, 2879, 6785, 289, 7061, 53067, 11539, 131405}},
+{20432, 18, 118051, {1, 1, 5, 15, 29, 27, 67, 15, 247, 689, 579, 3237, 5279, 13847, 20305, 60237, 115841, 144855}},
+{20433, 18, 118057, {1, 1, 5, 1, 9, 25, 75, 11, 83, 1015, 281, 1617, 7449, 10673, 7033, 38839, 113703, 233101}},
+{20434, 18, 118072, {1, 3, 3, 3, 23, 41, 81, 109, 199, 969, 935, 1793, 6921, 4013, 9625, 48149, 54395, 1193}},
+{20435, 18, 118080, {1, 3, 5, 7, 19, 63, 25, 201, 63, 799, 765, 533, 1417, 3199, 7773, 44247, 112207, 11783}},
+{20436, 18, 118098, {1, 3, 1, 11, 7, 25, 87, 159, 491, 749, 1157, 667, 2951, 12019, 22259, 36933, 124159, 176041}},
+{20437, 18, 118107, {1, 1, 5, 15, 21, 19, 113, 175, 129, 385, 2025, 2685, 1925, 8547, 4835, 15953, 128023, 236341}},
+{20438, 18, 118109, {1, 1, 1, 9, 13, 47, 25, 81, 389, 249, 1857, 1061, 4439, 3717, 16299, 23247, 95275, 222701}},
+{20439, 18, 118114, {1, 3, 3, 1, 3, 61, 61, 117, 159, 689, 43, 113, 4203, 7699, 27607, 37195, 63415, 90481}},
+{20440, 18, 118123, {1, 3, 1, 5, 11, 49, 73, 13, 307, 655, 645, 2765, 6079, 12687, 22417, 44713, 5247, 40265}},
+{20441, 18, 118150, {1, 1, 7, 13, 5, 55, 57, 237, 317, 101, 481, 2515, 707, 6385, 9421, 50557, 92395, 193737}},
+{20442, 18, 118159, {1, 3, 5, 1, 27, 35, 65, 107, 63, 57, 1699, 4077, 4279, 8547, 15137, 11533, 117641, 64925}},
+{20443, 18, 118164, {1, 1, 5, 1, 13, 7, 7, 141, 305, 191, 2033, 2677, 6025, 12927, 4057, 12047, 60253, 90803}},
+{20444, 18, 118173, {1, 1, 7, 3, 1, 9, 63, 233, 185, 97, 913, 187, 4321, 8951, 27669, 27035, 30029, 218725}},
+{20445, 18, 118201, {1, 1, 7, 1, 11, 59, 41, 195, 335, 551, 491, 3079, 7777, 4003, 24543, 17165, 103261, 167505}},
+{20446, 18, 118212, {1, 1, 3, 3, 9, 59, 37, 185, 289, 845, 1083, 63, 7439, 4677, 29245, 40813, 16295, 45499}},
+{20447, 18, 118246, {1, 3, 5, 1, 1, 37, 89, 5, 277, 493, 155, 1641, 5395, 11389, 26247, 2833, 103803, 74447}},
+{20448, 18, 118257, {1, 1, 3, 1, 29, 55, 83, 211, 377, 583, 1075, 2679, 7157, 11719, 1653, 5977, 52263, 45531}},
+{20449, 18, 118303, {1, 1, 5, 15, 1, 31, 89, 7, 239, 821, 887, 1319, 225, 14555, 5443, 44717, 99803, 241577}},
+{20450, 18, 118310, {1, 3, 5, 11, 7, 23, 81, 161, 67, 1011, 177, 2837, 7767, 14385, 29415, 9377, 7407, 128403}},
+{20451, 18, 118313, {1, 1, 7, 11, 3, 13, 13, 237, 199, 601, 481, 3809, 6591, 8497, 25361, 22547, 28317, 22961}},
+{20452, 18, 118324, {1, 3, 1, 1, 31, 29, 105, 161, 483, 391, 321, 1087, 4149, 8803, 22291, 24611, 114447, 33645}},
+{20453, 18, 118334, {1, 3, 1, 11, 1, 47, 41, 45, 287, 503, 169, 2265, 1835, 6609, 25245, 7069, 61137, 160653}},
+{20454, 18, 118336, {1, 1, 7, 13, 11, 39, 29, 39, 489, 205, 741, 2871, 377, 10679, 11689, 50947, 85309, 95697}},
+{20455, 18, 118339, {1, 3, 7, 7, 23, 19, 103, 15, 79, 425, 369, 2009, 4417, 11031, 2113, 36969, 73241, 120903}},
+{20456, 18, 118353, {1, 3, 1, 7, 27, 9, 43, 33, 123, 895, 223, 1045, 2701, 3339, 12099, 24449, 52973, 175671}},
+{20457, 18, 118354, {1, 3, 5, 5, 3, 1, 13, 117, 429, 167, 1361, 2299, 7565, 1153, 9259, 29209, 25747, 71005}},
+{20458, 18, 118390, {1, 3, 1, 15, 7, 7, 13, 209, 73, 523, 1549, 2545, 5583, 10209, 27205, 41243, 14217, 208993}},
+{20459, 18, 118396, {1, 3, 5, 5, 3, 29, 99, 255, 479, 297, 1319, 2171, 7321, 14425, 15869, 44449, 10917, 171165}},
+{20460, 18, 118436, {1, 3, 3, 11, 13, 49, 29, 95, 79, 987, 161, 859, 6503, 8839, 14131, 30249, 16183, 40257}},
+{20461, 18, 118453, {1, 3, 3, 11, 27, 7, 27, 33, 255, 847, 789, 3897, 2599, 16107, 22379, 1853, 102713, 197547}},
+{20462, 18, 118466, {1, 1, 3, 9, 29, 11, 107, 227, 35, 183, 639, 1585, 313, 1451, 19789, 13855, 94277, 85569}},
+{20463, 18, 118492, {1, 3, 7, 7, 25, 33, 101, 49, 137, 457, 2027, 3317, 1961, 6097, 739, 12875, 69503, 95453}},
+{20464, 18, 118506, {1, 3, 3, 11, 29, 13, 127, 3, 31, 319, 1341, 927, 5067, 13891, 31265, 41381, 49341, 160343}},
+{20465, 18, 118525, {1, 1, 3, 15, 31, 21, 93, 155, 471, 707, 1395, 2995, 867, 10353, 8137, 44267, 24823, 6113}},
+{20466, 18, 118557, {1, 3, 1, 7, 7, 33, 83, 79, 349, 687, 1045, 1183, 4441, 15199, 1953, 36395, 84691, 134939}},
+{20467, 18, 118561, {1, 1, 3, 15, 13, 21, 41, 105, 189, 439, 1171, 4005, 7641, 1597, 24317, 58749, 35539, 220647}},
+{20468, 18, 118586, {1, 1, 3, 15, 13, 39, 49, 5, 461, 613, 1633, 1951, 7959, 5733, 10061, 18829, 49505, 90033}},
+{20469, 18, 118606, {1, 3, 5, 5, 29, 25, 19, 227, 379, 525, 687, 2629, 7729, 4791, 5911, 14481, 49063, 216669}},
+{20470, 18, 118627, {1, 3, 7, 7, 7, 63, 93, 227, 79, 165, 1971, 1695, 4485, 6009, 8769, 12861, 83653, 27667}},
+{20471, 18, 118641, {1, 1, 5, 5, 25, 11, 23, 89, 363, 491, 459, 4063, 3787, 9375, 28011, 44757, 56441, 116609}},
+{20472, 18, 118654, {1, 3, 5, 9, 7, 53, 43, 149, 435, 35, 135, 1759, 3197, 7749, 12731, 28295, 25901, 125847}},
+{20473, 18, 118687, {1, 1, 3, 5, 15, 15, 1, 215, 307, 711, 1971, 2795, 677, 11921, 10303, 37997, 6653, 51295}},
+{20474, 18, 118688, {1, 1, 5, 15, 1, 59, 75, 195, 51, 215, 1303, 3023, 8023, 10951, 13015, 23513, 37029, 23581}},
+{20475, 18, 118735, {1, 1, 1, 3, 27, 3, 77, 165, 97, 499, 937, 1129, 6649, 11305, 27763, 32849, 78251, 210407}},
+{20476, 18, 118737, {1, 3, 3, 3, 9, 21, 19, 197, 339, 53, 1875, 1057, 3485, 14645, 13417, 39307, 81437, 45857}},
+{20477, 18, 118750, {1, 1, 1, 5, 19, 5, 95, 205, 399, 699, 819, 1927, 7913, 8109, 1223, 28595, 397, 81051}},
+{20478, 18, 118773, {1, 3, 7, 13, 23, 11, 37, 167, 189, 813, 1199, 3545, 655, 13239, 10469, 33895, 119025, 185361}},
+{20479, 18, 118778, {1, 1, 5, 11, 9, 13, 41, 37, 443, 269, 1199, 1347, 7081, 11273, 14389, 64083, 117901, 51903}},
+{20480, 18, 118786, {1, 1, 3, 13, 5, 17, 117, 151, 155, 637, 731, 1839, 855, 9749, 19529, 18101, 20341, 21941}},
+{20481, 18, 118809, {1, 1, 1, 11, 15, 17, 35, 9, 91, 907, 667, 853, 1455, 10097, 31277, 749, 47089, 219517}},
+{20482, 18, 118833, {1, 3, 7, 1, 27, 31, 9, 145, 309, 811, 5, 2645, 7851, 1953, 21427, 18805, 108755, 77215}},
+{20483, 18, 118853, {1, 1, 7, 3, 21, 7, 25, 233, 145, 1015, 43, 2205, 4735, 13257, 24001, 50469, 42567, 253745}},
+{20484, 18, 118854, {1, 3, 1, 15, 3, 53, 51, 45, 397, 379, 641, 895, 7569, 15783, 23923, 6147, 121395, 261853}},
+{20485, 18, 118863, {1, 1, 1, 1, 23, 47, 35, 125, 289, 65, 1875, 2309, 519, 5435, 5271, 25319, 14557, 19389}},
+{20486, 18, 118881, {1, 3, 5, 7, 27, 43, 15, 61, 357, 791, 1781, 3671, 3911, 1325, 5607, 44107, 67873, 119849}},
+{20487, 18, 118896, {1, 3, 1, 5, 25, 37, 105, 51, 491, 407, 475, 1763, 1425, 14883, 31435, 48979, 120667, 131089}},
+{20488, 18, 118917, {1, 3, 5, 13, 1, 51, 109, 161, 215, 871, 185, 2389, 7977, 6705, 14045, 45569, 44557, 114795}},
+{20489, 18, 118921, {1, 3, 7, 11, 17, 21, 111, 183, 343, 593, 447, 3995, 759, 3709, 32655, 30141, 127225, 120899}},
+{20490, 18, 118939, {1, 1, 5, 3, 17, 3, 69, 25, 113, 897, 1933, 2717, 2003, 5847, 2541, 62415, 50975, 97903}},
+{20491, 18, 118948, {1, 1, 1, 1, 9, 35, 107, 81, 257, 57, 1719, 4049, 1237, 10659, 4689, 20887, 90791, 251911}},
+{20492, 18, 118960, {1, 1, 7, 11, 1, 49, 83, 213, 169, 169, 825, 2983, 5833, 2413, 32165, 47459, 129021, 156217}},
+{20493, 18, 118970, {1, 1, 5, 13, 15, 39, 61, 93, 407, 553, 839, 4035, 6609, 6327, 945, 49625, 127867, 240161}},
+{20494, 18, 118983, {1, 1, 1, 15, 23, 47, 21, 235, 81, 431, 1819, 1141, 7973, 4623, 4539, 23201, 83111, 230857}},
+{20495, 18, 119025, {1, 3, 3, 15, 9, 15, 15, 173, 29, 803, 1453, 2621, 8095, 6639, 6607, 21471, 44785, 122271}},
+{20496, 18, 119026, {1, 3, 3, 7, 21, 5, 127, 203, 43, 581, 1925, 165, 4615, 9141, 18563, 54413, 71559, 172791}},
+{20497, 18, 119064, {1, 3, 3, 3, 27, 31, 55, 3, 381, 971, 1087, 2659, 139, 10935, 9189, 3445, 15071, 218873}},
+{20498, 18, 119069, {1, 3, 1, 3, 1, 57, 47, 71, 85, 335, 207, 225, 2931, 14721, 21431, 17199, 745, 177403}},
+{20499, 18, 119079, {1, 3, 1, 7, 7, 17, 21, 57, 345, 29, 1147, 1179, 7371, 14725, 27445, 62061, 16483, 112489}},
+{20500, 18, 119085, {1, 3, 7, 15, 23, 11, 91, 1, 1, 117, 1665, 3899, 5683, 14497, 25633, 6233, 104029, 22155}},
+{20501, 18, 119115, {1, 3, 5, 9, 1, 27, 15, 187, 37, 329, 585, 729, 5651, 15715, 4339, 1899, 90611, 195643}},
+{20502, 18, 119165, {1, 1, 3, 11, 1, 45, 95, 103, 13, 83, 319, 2295, 6333, 13469, 19237, 55985, 129725, 141699}},
+{20503, 18, 119166, {1, 1, 5, 11, 7, 41, 97, 159, 511, 617, 1545, 3023, 7919, 8437, 8345, 16701, 69053, 105047}},
+{20504, 18, 119193, {1, 3, 3, 11, 29, 35, 23, 95, 277, 931, 857, 3887, 4597, 10841, 12947, 18009, 61499, 242827}},
+{20505, 18, 119194, {1, 1, 3, 3, 7, 63, 35, 161, 125, 637, 149, 1045, 3297, 16213, 1543, 8073, 80373, 61507}},
+{20506, 18, 119199, {1, 1, 7, 5, 31, 43, 113, 189, 181, 659, 1971, 3309, 4237, 4279, 31563, 29429, 17443, 154385}},
+{20507, 18, 119215, {1, 1, 1, 13, 19, 43, 99, 91, 47, 477, 153, 3295, 6281, 779, 17169, 343, 1723, 171133}},
+{20508, 18, 119218, {1, 1, 1, 15, 9, 35, 123, 45, 417, 631, 1415, 1835, 3063, 897, 18947, 62477, 12759, 97831}},
+{20509, 18, 119241, {1, 1, 3, 13, 31, 1, 31, 139, 411, 605, 1829, 303, 3891, 15807, 7335, 44833, 87427, 62183}},
+{20510, 18, 119277, {1, 1, 3, 13, 29, 55, 97, 107, 241, 981, 1281, 3295, 6825, 15865, 4221, 24695, 54203, 252069}},
+{20511, 18, 119301, {1, 3, 7, 13, 1, 3, 33, 165, 483, 813, 127, 1717, 8077, 3521, 23465, 41705, 2769, 173233}},
+{20512, 18, 119306, {1, 3, 1, 11, 11, 51, 39, 125, 375, 825, 1775, 2923, 4903, 4779, 907, 47787, 22293, 169631}},
+{20513, 18, 119335, {1, 3, 5, 5, 13, 27, 43, 229, 267, 153, 567, 3403, 2103, 6203, 29629, 29715, 116735, 122515}},
+{20514, 18, 119344, {1, 3, 5, 13, 3, 3, 15, 5, 345, 343, 691, 3703, 361, 2019, 9309, 26909, 22897, 103555}},
+{20515, 18, 119364, {1, 3, 1, 11, 9, 25, 123, 235, 131, 469, 1749, 3681, 3841, 10157, 15183, 61413, 42207, 170359}},
+{20516, 18, 119373, {1, 1, 7, 3, 13, 9, 7, 191, 239, 417, 817, 1381, 1179, 2719, 21025, 17429, 50295, 196485}},
+{20517, 18, 119382, {1, 1, 7, 9, 9, 31, 123, 229, 381, 569, 513, 1617, 6141, 9717, 31769, 30159, 113697, 254237}},
+{20518, 18, 119410, {1, 1, 1, 15, 31, 43, 37, 17, 283, 905, 297, 1317, 1883, 11313, 5653, 55655, 121029, 149831}},
+{20519, 18, 119425, {1, 1, 1, 7, 7, 47, 83, 101, 497, 465, 1133, 3877, 5371, 3355, 17161, 50185, 120837, 255103}},
+{20520, 18, 119459, {1, 1, 3, 5, 5, 19, 3, 251, 433, 303, 1193, 1263, 2139, 473, 10725, 57725, 111411, 133687}},
+{20521, 18, 119473, {1, 1, 1, 7, 3, 1, 99, 115, 481, 395, 115, 1699, 953, 2807, 7227, 52781, 2855, 161159}},
+{20522, 18, 119486, {1, 1, 5, 9, 25, 25, 85, 3, 451, 847, 837, 3669, 4717, 3661, 29111, 43735, 49445, 100379}},
+{20523, 18, 119500, {1, 1, 7, 9, 19, 61, 67, 123, 195, 483, 1741, 2719, 7809, 5035, 30689, 21325, 56191, 46127}},
+{20524, 18, 119508, {1, 1, 3, 11, 15, 39, 101, 27, 103, 807, 1557, 1647, 1285, 16169, 20203, 57153, 60749, 71361}},
+{20525, 18, 119511, {1, 3, 3, 3, 19, 1, 93, 31, 105, 925, 689, 3061, 7451, 12667, 27179, 36295, 61011, 90321}},
+{20526, 18, 119517, {1, 3, 7, 15, 19, 35, 47, 241, 261, 935, 1033, 751, 6519, 6911, 13519, 2539, 40285, 81535}},
+{20527, 18, 119528, {1, 1, 7, 13, 17, 31, 71, 135, 167, 5, 673, 2909, 4377, 3453, 31289, 38081, 21993, 192933}},
+{20528, 18, 119533, {1, 1, 5, 15, 23, 49, 85, 127, 13, 849, 1661, 2099, 3479, 3613, 21723, 58147, 56321, 203171}},
+{20529, 18, 119539, {1, 1, 7, 15, 23, 63, 3, 207, 445, 573, 1419, 1161, 2237, 1251, 23387, 65259, 81447, 74555}},
+{20530, 18, 119542, {1, 3, 5, 3, 25, 61, 37, 25, 287, 969, 37, 1615, 7923, 4457, 27611, 8519, 113957, 237427}},
+{20531, 18, 119546, {1, 3, 5, 11, 11, 25, 117, 169, 149, 701, 139, 2835, 6029, 9067, 841, 51707, 9287, 115825}},
+{20532, 18, 119566, {1, 1, 1, 13, 31, 5, 9, 5, 313, 1023, 551, 3635, 6765, 13379, 29135, 39737, 80913, 256355}},
+{20533, 18, 119587, {1, 3, 1, 13, 9, 23, 105, 117, 181, 211, 755, 555, 2763, 13965, 14743, 63725, 16377, 203435}},
+{20534, 18, 119590, {1, 3, 1, 15, 11, 45, 111, 147, 471, 321, 381, 2921, 6423, 629, 25117, 51213, 126941, 181931}},
+{20535, 18, 119607, {1, 1, 1, 11, 1, 49, 127, 105, 315, 1, 859, 1223, 5967, 2521, 14491, 58399, 45155, 192567}},
+{20536, 18, 119614, {1, 1, 3, 9, 19, 21, 73, 93, 95, 307, 293, 3243, 4765, 2253, 16775, 29861, 3785, 90357}},
+{20537, 18, 119625, {1, 1, 3, 7, 3, 53, 33, 167, 165, 509, 1133, 169, 6951, 7715, 26317, 5249, 86235, 39649}},
+{20538, 18, 119633, {1, 1, 5, 5, 3, 47, 105, 89, 201, 1003, 877, 635, 2225, 6391, 21247, 5707, 1233, 87055}},
+{20539, 18, 119634, {1, 1, 1, 1, 9, 39, 61, 201, 435, 843, 1245, 533, 1757, 1117, 19687, 54817, 32495, 228865}},
+{20540, 18, 119643, {1, 3, 1, 1, 3, 61, 63, 117, 143, 217, 435, 1977, 2647, 7631, 12969, 50211, 26483, 256329}},
+{20541, 18, 119683, {1, 3, 3, 9, 21, 25, 113, 243, 457, 143, 833, 1505, 3071, 1845, 17867, 58205, 103819, 185215}},
+{20542, 18, 119704, {1, 1, 5, 7, 23, 51, 11, 117, 195, 535, 685, 31, 3037, 9719, 22811, 42959, 21021, 126297}},
+{20543, 18, 119710, {1, 3, 3, 1, 1, 17, 107, 245, 257, 547, 887, 45, 5243, 2439, 22191, 19503, 2143, 75187}},
+{20544, 18, 119734, {1, 3, 7, 9, 11, 27, 123, 197, 353, 151, 1115, 403, 1105, 7425, 7463, 42065, 116187, 154537}},
+{20545, 18, 119752, {1, 3, 5, 15, 23, 5, 49, 177, 223, 615, 1255, 2081, 321, 8733, 19549, 53027, 275, 62739}},
+{20546, 18, 119760, {1, 3, 7, 1, 17, 61, 3, 233, 249, 763, 369, 555, 1621, 7221, 22575, 13295, 99793, 233635}},
+{20547, 18, 119826, {1, 1, 3, 1, 27, 41, 125, 113, 47, 583, 543, 453, 1213, 14187, 1645, 35761, 110051, 197081}},
+{20548, 18, 119922, {1, 1, 7, 9, 29, 43, 105, 125, 489, 135, 153, 2279, 4079, 6731, 12055, 60181, 82563, 173991}},
+{20549, 18, 119931, {1, 3, 7, 3, 29, 1, 67, 151, 127, 625, 113, 2127, 6723, 12359, 28609, 60605, 20375, 120129}},
+{20550, 18, 119977, {1, 1, 5, 7, 9, 13, 27, 171, 129, 199, 303, 4045, 2047, 8887, 22233, 57571, 40545, 36479}},
+{20551, 18, 120015, {1, 3, 1, 7, 1, 5, 127, 203, 213, 691, 1155, 27, 5409, 13519, 6747, 42371, 37089, 145855}},
+{20552, 18, 120020, {1, 3, 3, 9, 3, 33, 119, 25, 337, 715, 1093, 987, 7157, 14975, 28595, 19021, 1243, 148707}},
+{20553, 18, 120083, {1, 3, 1, 13, 3, 41, 81, 151, 23, 787, 181, 2357, 5077, 1997, 6451, 25505, 44875, 198341}},
+{20554, 18, 120086, {1, 1, 7, 3, 5, 15, 9, 169, 337, 487, 1325, 1505, 465, 2339, 20747, 8269, 96875, 108985}},
+{20555, 18, 120101, {1, 3, 1, 7, 23, 7, 113, 181, 25, 989, 1649, 1, 823, 6793, 18729, 3599, 97951, 239609}},
+{20556, 18, 120105, {1, 3, 7, 7, 3, 63, 63, 207, 419, 355, 1133, 2979, 2071, 11699, 32565, 61347, 106475, 16893}},
+{20557, 18, 120155, {1, 1, 7, 5, 7, 3, 119, 133, 189, 341, 1571, 1559, 4309, 16203, 22459, 21019, 80375, 3453}},
+{20558, 18, 120188, {1, 1, 3, 11, 21, 21, 45, 69, 485, 21, 727, 703, 5209, 14745, 3437, 54603, 104357, 151207}},
+{20559, 18, 120195, {1, 3, 7, 5, 25, 17, 13, 147, 329, 93, 121, 315, 2779, 6921, 425, 50441, 1133, 252291}},
+{20560, 18, 120216, {1, 1, 3, 5, 5, 51, 15, 135, 323, 841, 409, 1067, 3243, 4207, 6833, 59329, 90545, 116661}},
+{20561, 18, 120228, {1, 1, 3, 15, 25, 7, 43, 147, 153, 947, 79, 1897, 4519, 14441, 27181, 38517, 71673, 158597}},
+{20562, 18, 120238, {1, 3, 3, 3, 3, 47, 109, 111, 273, 271, 741, 3999, 649, 7367, 14933, 11785, 92709, 133815}},
+{20563, 18, 120255, {1, 1, 3, 13, 5, 41, 55, 15, 409, 355, 1255, 3043, 7503, 3523, 4261, 48927, 119901, 149411}},
+{20564, 18, 120317, {1, 1, 5, 1, 11, 57, 3, 149, 409, 287, 909, 3541, 4243, 4485, 3611, 63213, 102575, 49863}},
+{20565, 18, 120327, {1, 1, 3, 7, 15, 55, 119, 185, 511, 301, 237, 3701, 3195, 1323, 27511, 44635, 45363, 117683}},
+{20566, 18, 120369, {1, 3, 3, 11, 3, 61, 125, 15, 235, 819, 467, 1097, 1055, 16343, 8329, 37807, 38663, 145625}},
+{20567, 18, 120382, {1, 1, 7, 1, 25, 49, 117, 163, 413, 509, 63, 1313, 5113, 6505, 25475, 12059, 88021, 168037}},
+{20568, 18, 120404, {1, 3, 3, 9, 9, 37, 15, 185, 359, 231, 1483, 2999, 773, 10375, 27103, 39899, 100187, 54485}},
+{20569, 18, 120414, {1, 3, 3, 1, 13, 63, 111, 79, 133, 425, 1491, 3735, 533, 13417, 5161, 11455, 16907, 132267}},
+{20570, 18, 120432, {1, 3, 1, 15, 15, 47, 57, 157, 453, 681, 1811, 1685, 4329, 131, 22763, 1017, 66637, 1673}},
+{20571, 18, 120435, {1, 3, 7, 3, 31, 5, 105, 101, 431, 983, 1333, 845, 7369, 15041, 6527, 8617, 61911, 137513}},
+{20572, 18, 120454, {1, 3, 7, 15, 3, 45, 57, 23, 393, 495, 769, 215, 3611, 12907, 20637, 52997, 88345, 37961}},
+{20573, 18, 120463, {1, 3, 5, 7, 31, 3, 85, 249, 353, 559, 1803, 959, 4625, 9413, 22339, 6071, 124765, 43973}},
+{20574, 18, 120471, {1, 3, 1, 9, 31, 15, 109, 197, 179, 293, 457, 709, 627, 7743, 1997, 59625, 36919, 252849}},
+{20575, 18, 120505, {1, 1, 7, 11, 17, 21, 89, 11, 431, 617, 1029, 2649, 1725, 2723, 18367, 46103, 108063, 221855}},
+{20576, 18, 120528, {1, 3, 7, 1, 29, 7, 81, 187, 353, 807, 965, 3655, 3255, 9139, 28619, 32127, 107901, 139099}},
+{20577, 18, 120588, {1, 1, 5, 3, 17, 9, 39, 59, 431, 829, 525, 1885, 2387, 13381, 5271, 29739, 80413, 240595}},
+{20578, 18, 120616, {1, 3, 1, 5, 1, 5, 25, 9, 193, 971, 681, 2921, 3271, 3891, 20123, 37477, 33141, 82481}},
+{20579, 18, 120630, {1, 1, 3, 5, 1, 63, 77, 93, 63, 399, 1945, 387, 5457, 7339, 13279, 34119, 129903, 12621}},
+{20580, 18, 120644, {1, 3, 3, 11, 17, 11, 117, 189, 473, 23, 13, 1261, 2153, 12181, 21075, 33179, 43355, 168293}},
+{20581, 18, 120672, {1, 3, 5, 11, 21, 13, 73, 227, 211, 939, 885, 2091, 1123, 14809, 15705, 56675, 58087, 1451}},
+{20582, 18, 120677, {1, 3, 7, 1, 15, 15, 101, 235, 287, 675, 1741, 3885, 6211, 14817, 10235, 29289, 60401, 27639}},
+{20583, 18, 120718, {1, 3, 5, 13, 13, 7, 117, 31, 143, 505, 1823, 2841, 2133, 7305, 14093, 14229, 85179, 136793}},
+{20584, 18, 120725, {1, 1, 3, 15, 27, 15, 67, 237, 315, 793, 207, 3781, 5201, 13191, 9601, 44041, 116097, 178543}},
+{20585, 18, 120730, {1, 3, 1, 9, 9, 47, 53, 225, 109, 831, 1757, 349, 6353, 15417, 16395, 36295, 10901, 122349}},
+{20586, 18, 120756, {1, 1, 1, 1, 1, 17, 109, 13, 123, 537, 1859, 3717, 4441, 4271, 29017, 13601, 18533, 216695}},
+{20587, 18, 120759, {1, 3, 3, 13, 31, 23, 45, 233, 29, 295, 761, 757, 777, 3499, 26715, 24153, 113777, 256337}},
+{20588, 18, 120765, {1, 3, 5, 7, 23, 57, 37, 179, 511, 897, 2031, 1285, 3957, 15085, 19993, 28819, 39959, 187445}},
+{20589, 18, 120795, {1, 3, 1, 15, 25, 41, 121, 227, 433, 859, 357, 3107, 3241, 879, 10763, 59473, 73145, 258493}},
+{20590, 18, 120821, {1, 3, 3, 5, 13, 9, 85, 117, 347, 161, 995, 549, 5443, 9057, 28931, 57549, 27523, 54717}},
+{20591, 18, 120850, {1, 1, 5, 13, 13, 33, 97, 37, 55, 367, 403, 2361, 5717, 4433, 26921, 14227, 69445, 100337}},
+{20592, 18, 120868, {1, 3, 5, 7, 1, 41, 89, 165, 163, 1, 685, 3577, 1079, 1057, 125, 35853, 8387, 113035}},
+{20593, 18, 120880, {1, 3, 3, 13, 3, 59, 119, 51, 325, 205, 821, 1417, 2097, 13725, 31785, 53803, 15737, 2013}},
+{20594, 18, 120885, {1, 3, 7, 7, 1, 45, 95, 221, 249, 65, 1479, 2163, 5761, 15321, 8013, 25771, 110897, 214127}},
+{20595, 18, 120892, {1, 3, 3, 5, 25, 11, 27, 29, 95, 955, 1989, 3775, 609, 7073, 4571, 38857, 92205, 156209}},
+{20596, 18, 120897, {1, 3, 1, 13, 29, 57, 97, 47, 499, 641, 587, 2125, 2257, 13911, 13993, 1715, 46233, 181279}},
+{20597, 18, 120912, {1, 1, 7, 13, 7, 55, 69, 235, 379, 269, 1969, 2733, 3677, 1707, 26999, 64041, 98111, 138691}},
+{20598, 18, 120934, {1, 1, 3, 5, 27, 63, 65, 251, 413, 903, 1307, 2941, 5649, 11271, 1935, 49389, 37995, 218197}},
+{20599, 18, 120991, {1, 3, 3, 13, 7, 1, 45, 225, 13, 169, 581, 1657, 117, 10251, 23435, 40379, 127085, 88185}},
+{20600, 18, 121004, {1, 1, 7, 5, 21, 63, 69, 37, 459, 115, 1403, 1939, 6437, 13149, 3597, 50115, 129075, 260613}},
+{20601, 18, 121021, {1, 1, 3, 5, 29, 57, 15, 223, 131, 907, 1561, 1103, 4355, 2763, 6359, 55401, 1751, 53143}},
+{20602, 18, 121022, {1, 1, 7, 11, 15, 5, 17, 159, 505, 407, 1873, 2501, 2203, 12559, 5123, 53281, 29307, 16215}},
+{20603, 18, 121036, {1, 1, 1, 15, 9, 41, 77, 145, 325, 529, 1939, 3835, 3109, 12215, 18323, 2551, 89793, 94745}},
+{20604, 18, 121041, {1, 3, 1, 9, 21, 5, 7, 57, 99, 1005, 1211, 4063, 6851, 7653, 29283, 15463, 121289, 187055}},
+{20605, 18, 121069, {1, 1, 3, 3, 13, 11, 17, 125, 173, 283, 1419, 2533, 6875, 16031, 26633, 51027, 27343, 74257}},
+{20606, 18, 121078, {1, 1, 3, 11, 29, 49, 87, 19, 367, 941, 983, 1041, 8099, 8735, 30123, 62665, 87051, 98745}},
+{20607, 18, 121126, {1, 1, 1, 15, 25, 57, 97, 177, 467, 181, 923, 3833, 5405, 14335, 23495, 48323, 70331, 136825}},
+{20608, 18, 121135, {1, 1, 1, 13, 21, 17, 29, 237, 305, 117, 1077, 2999, 1879, 6875, 19321, 10999, 130513, 160883}},
+{20609, 18, 121138, {1, 3, 7, 15, 19, 47, 89, 153, 287, 7, 1429, 1507, 2853, 4197, 11195, 33891, 59063, 189601}},
+{20610, 18, 121162, {1, 1, 3, 15, 31, 5, 113, 71, 13, 925, 147, 451, 5701, 13671, 13943, 13799, 59627, 115715}},
+{20611, 18, 121176, {1, 1, 1, 5, 13, 25, 51, 11, 409, 393, 1479, 2583, 3101, 303, 17609, 10653, 69107, 150459}},
+{20612, 18, 121186, {1, 1, 5, 7, 21, 27, 107, 77, 61, 467, 1723, 1247, 287, 1039, 25347, 18111, 24837, 42903}},
+{20613, 18, 121209, {1, 3, 5, 5, 1, 29, 57, 177, 311, 9, 819, 3235, 3887, 9679, 11849, 31755, 68467, 135587}},
+{20614, 18, 121212, {1, 1, 5, 5, 29, 15, 13, 69, 163, 709, 1405, 3835, 777, 7567, 10153, 5043, 129465, 59113}},
+{20615, 18, 121221, {1, 1, 1, 13, 3, 47, 97, 101, 179, 53, 1919, 17, 3597, 11769, 17971, 39257, 76167, 255653}},
+{20616, 18, 121225, {1, 1, 7, 5, 1, 45, 121, 223, 299, 271, 1857, 1955, 5509, 1245, 9519, 60547, 78497, 191251}},
+{20617, 18, 121228, {1, 1, 1, 11, 5, 57, 87, 113, 59, 547, 1591, 1905, 475, 4687, 27591, 43807, 9617, 70769}},
+{20618, 18, 121239, {1, 1, 7, 1, 1, 35, 35, 11, 107, 401, 827, 2271, 2131, 12751, 25771, 51311, 46897, 198655}},
+{20619, 18, 121245, {1, 3, 3, 3, 15, 29, 91, 147, 9, 611, 1739, 3211, 3883, 14205, 24073, 37445, 54451, 208123}},
+{20620, 18, 121264, {1, 3, 7, 1, 25, 53, 33, 161, 365, 651, 1263, 1623, 1767, 3789, 18013, 52133, 60119, 100859}},
+{20621, 18, 121270, {1, 3, 5, 9, 15, 9, 97, 67, 379, 981, 1323, 1095, 3701, 3257, 13647, 12511, 53375, 156689}},
+{20622, 18, 121299, {1, 1, 3, 5, 9, 23, 97, 239, 171, 501, 1549, 1029, 8019, 5023, 9439, 14223, 54433, 152855}},
+{20623, 18, 121306, {1, 1, 7, 13, 17, 35, 111, 169, 81, 599, 1673, 3461, 7905, 7925, 16311, 20327, 57109, 158719}},
+{20624, 18, 121315, {1, 1, 3, 15, 7, 33, 23, 33, 273, 987, 1489, 363, 4017, 8919, 28839, 10143, 114179, 218155}},
+{20625, 18, 121317, {1, 3, 5, 13, 29, 5, 61, 133, 65, 933, 509, 551, 7365, 3703, 15003, 27849, 64211, 140383}},
+{20626, 18, 121321, {1, 1, 1, 13, 7, 25, 49, 1, 269, 601, 251, 33, 2443, 13725, 5805, 63347, 109489, 111491}},
+{20627, 18, 121324, {1, 1, 7, 9, 31, 23, 117, 71, 371, 733, 605, 4019, 4577, 3887, 31061, 24939, 57905, 148331}},
+{20628, 18, 121330, {1, 3, 5, 1, 3, 35, 35, 227, 355, 27, 1673, 2173, 5001, 14613, 6343, 40775, 72349, 101287}},
+{20629, 18, 121339, {1, 1, 7, 15, 29, 3, 43, 77, 43, 51, 1495, 2577, 2093, 7515, 20151, 44533, 32223, 6355}},
+{20630, 18, 121346, {1, 1, 5, 5, 11, 47, 91, 221, 35, 969, 343, 3287, 857, 4851, 12599, 939, 53615, 262125}},
+{20631, 18, 121370, {1, 1, 5, 7, 29, 11, 67, 155, 317, 629, 211, 583, 1061, 13243, 13999, 45405, 18187, 99021}},
+{20632, 18, 121372, {1, 3, 7, 13, 3, 39, 5, 207, 175, 515, 1181, 739, 379, 9919, 12079, 18903, 62475, 239383}},
+{20633, 18, 121393, {1, 1, 1, 15, 25, 15, 113, 215, 281, 861, 1055, 2577, 5545, 12365, 16097, 35775, 8331, 119353}},
+{20634, 18, 121396, {1, 1, 1, 1, 25, 55, 111, 185, 485, 361, 155, 4077, 5517, 16057, 19069, 40129, 38959, 211233}},
+{20635, 18, 121414, {1, 1, 3, 3, 13, 1, 93, 129, 243, 813, 115, 177, 53, 8251, 32351, 63847, 54537, 25527}},
+{20636, 18, 121442, {1, 3, 5, 11, 25, 47, 113, 69, 285, 451, 2011, 81, 6535, 3409, 8647, 56575, 975, 149571}},
+{20637, 18, 121475, {1, 1, 7, 7, 19, 1, 75, 123, 413, 697, 41, 3179, 4075, 15967, 2477, 17549, 54193, 258657}},
+{20638, 18, 121499, {1, 1, 5, 5, 11, 23, 19, 253, 303, 255, 901, 875, 1517, 6953, 25189, 26763, 28843, 167705}},
+{20639, 18, 121512, {1, 3, 7, 7, 17, 45, 31, 79, 279, 965, 1869, 1201, 1627, 14035, 11651, 45021, 76171, 49137}},
+{20640, 18, 121518, {1, 3, 1, 15, 9, 55, 83, 59, 437, 915, 1667, 89, 2797, 1841, 29261, 23497, 55785, 102265}},
+{20641, 18, 121588, {1, 1, 5, 5, 3, 59, 17, 131, 199, 541, 1647, 2175, 4449, 6081, 10609, 39467, 72945, 32423}},
+{20642, 18, 121597, {1, 3, 1, 7, 5, 7, 85, 11, 255, 397, 87, 1661, 6523, 5699, 29407, 28015, 50783, 246625}},
+{20643, 18, 121612, {1, 3, 3, 13, 5, 61, 123, 147, 295, 37, 301, 2549, 7615, 5725, 32477, 18121, 69353, 242579}},
+{20644, 18, 121629, {1, 3, 5, 7, 9, 45, 83, 211, 475, 281, 743, 3955, 7811, 6043, 30547, 5315, 53345, 25775}},
+{20645, 18, 121630, {1, 3, 3, 5, 7, 63, 125, 43, 131, 353, 345, 1689, 5483, 5467, 13445, 13041, 68381, 134567}},
+{20646, 18, 121634, {1, 3, 5, 11, 31, 9, 123, 53, 237, 911, 349, 3737, 1867, 7375, 3031, 4191, 8697, 182255}},
+{20647, 18, 121680, {1, 1, 3, 3, 11, 11, 89, 251, 69, 93, 1241, 1719, 2227, 1793, 21683, 58099, 110831, 24835}},
+{20648, 18, 121725, {1, 1, 5, 9, 3, 57, 3, 17, 11, 217, 923, 3623, 727, 1837, 21203, 63007, 33691, 216259}},
+{20649, 18, 121798, {1, 3, 3, 9, 21, 25, 83, 115, 325, 921, 811, 303, 3555, 10669, 5837, 45585, 61923, 159061}},
+{20650, 18, 121815, {1, 3, 3, 15, 17, 29, 77, 75, 509, 363, 199, 317, 7375, 11971, 15679, 17135, 101925, 103375}},
+{20651, 18, 121822, {1, 3, 5, 5, 29, 45, 85, 151, 73, 329, 911, 3055, 2381, 4717, 5133, 58987, 59885, 226689}},
+{20652, 18, 121837, {1, 3, 5, 1, 11, 59, 17, 83, 385, 867, 215, 2275, 7247, 10613, 6493, 63843, 74483, 134271}},
+{20653, 18, 121840, {1, 1, 7, 13, 29, 25, 77, 61, 281, 439, 353, 2213, 697, 14741, 1597, 7515, 7703, 149123}},
+{20654, 18, 121869, {1, 3, 7, 7, 7, 53, 77, 21, 483, 793, 969, 123, 3581, 12489, 22943, 54573, 25785, 178419}},
+{20655, 18, 121878, {1, 3, 5, 3, 17, 59, 75, 55, 125, 569, 1625, 77, 4593, 8493, 5259, 54537, 100479, 107509}},
+{20656, 18, 121897, {1, 1, 1, 15, 5, 7, 11, 169, 349, 133, 1113, 2877, 6109, 16275, 9755, 1385, 55005, 36095}},
+{20657, 18, 121920, {1, 1, 7, 7, 21, 25, 41, 161, 11, 321, 343, 705, 4601, 12867, 21997, 25283, 78467, 159089}},
+{20658, 18, 121929, {1, 3, 7, 1, 15, 3, 71, 227, 427, 883, 1021, 1405, 7791, 12669, 9159, 30931, 105993, 40917}},
+{20659, 18, 121944, {1, 1, 5, 5, 25, 41, 93, 57, 125, 915, 701, 2589, 7147, 15369, 28307, 54635, 13253, 97177}},
+{20660, 18, 121999, {1, 3, 1, 13, 11, 63, 103, 241, 317, 927, 965, 3179, 5213, 13849, 11509, 52665, 1637, 235647}},
+{20661, 18, 122008, {1, 3, 5, 3, 31, 31, 111, 9, 339, 1017, 1715, 101, 6849, 14329, 31607, 40741, 73067, 119001}},
+{20662, 18, 122056, {1, 3, 1, 13, 3, 55, 53, 15, 185, 717, 1447, 3029, 4899, 14217, 19949, 32817, 24829, 206829}},
+{20663, 18, 122062, {1, 3, 7, 9, 21, 11, 33, 213, 5, 769, 1807, 2179, 63, 5167, 23235, 25495, 113299, 129419}},
+{20664, 18, 122067, {1, 3, 7, 11, 11, 33, 23, 125, 21, 609, 595, 1329, 6175, 15837, 3889, 57797, 81453, 211413}},
+{20665, 18, 122083, {1, 1, 5, 11, 31, 7, 13, 73, 143, 559, 1541, 275, 3349, 2987, 21797, 32921, 125395, 247667}},
+{20666, 18, 122095, {1, 1, 3, 11, 19, 1, 23, 167, 337, 75, 1597, 3591, 2705, 7323, 5957, 7317, 58945, 44625}},
+{20667, 18, 122110, {1, 1, 5, 11, 27, 19, 63, 231, 353, 645, 531, 3861, 1681, 6901, 16217, 20639, 70077, 220233}},
+{20668, 18, 122118, {1, 1, 5, 15, 31, 41, 19, 253, 147, 365, 509, 1199, 6699, 14633, 1339, 48203, 58707, 83315}},
+{20669, 18, 122127, {1, 1, 5, 7, 19, 47, 47, 17, 267, 139, 549, 803, 4625, 6851, 32141, 12891, 43785, 211361}},
+{20670, 18, 122189, {1, 3, 1, 13, 19, 35, 13, 45, 167, 627, 1449, 3041, 5043, 9279, 15889, 41675, 25769, 13835}},
+{20671, 18, 122207, {1, 3, 7, 7, 19, 47, 13, 117, 403, 79, 1623, 3741, 3255, 2301, 25, 2311, 5237, 150879}},
+{20672, 18, 122226, {1, 1, 1, 15, 29, 43, 75, 21, 237, 809, 129, 2637, 181, 15921, 30709, 61281, 82405, 232885}},
+{20673, 18, 122253, {1, 1, 3, 15, 15, 15, 55, 217, 243, 579, 945, 3993, 1875, 2425, 25045, 36729, 42935, 213703}},
+{20674, 18, 122301, {1, 3, 3, 1, 5, 59, 115, 71, 483, 327, 701, 2893, 1815, 4611, 3843, 5893, 126479, 167807}},
+{20675, 18, 122324, {1, 3, 1, 7, 17, 59, 115, 191, 3, 615, 215, 2121, 5085, 15233, 16661, 6215, 31061, 192847}},
+{20676, 18, 122337, {1, 3, 1, 1, 21, 25, 41, 195, 151, 905, 1587, 439, 3317, 2275, 4743, 33505, 1185, 254873}},
+{20677, 18, 122362, {1, 1, 3, 9, 11, 49, 37, 117, 419, 1007, 789, 1323, 345, 2047, 20697, 57063, 69167, 219393}},
+{20678, 18, 122368, {1, 3, 1, 1, 25, 49, 81, 79, 117, 1015, 1777, 2427, 527, 10139, 16261, 42587, 33933, 19749}},
+{20679, 18, 122371, {1, 1, 5, 15, 31, 43, 19, 17, 97, 591, 891, 177, 7835, 3979, 15473, 2173, 65555, 182773}},
+{20680, 18, 122378, {1, 1, 3, 15, 13, 53, 31, 179, 247, 635, 683, 423, 2981, 14401, 26385, 10935, 68497, 181703}},
+{20681, 18, 122404, {1, 3, 3, 9, 25, 55, 43, 29, 487, 969, 989, 3561, 6425, 11619, 5773, 56515, 17461, 151239}},
+{20682, 18, 122443, {1, 1, 5, 13, 3, 31, 73, 51, 213, 215, 297, 783, 697, 14197, 7277, 60697, 985, 189995}},
+{20683, 18, 122451, {1, 3, 3, 5, 9, 47, 69, 27, 15, 407, 1029, 2541, 183, 4413, 5143, 33903, 49509, 49007}},
+{20684, 18, 122457, {1, 1, 1, 3, 5, 3, 9, 165, 215, 577, 1657, 363, 737, 5483, 5955, 34533, 45861, 104645}},
+{20685, 18, 122458, {1, 1, 5, 7, 31, 27, 37, 215, 125, 915, 1297, 3095, 1529, 12737, 25675, 29355, 83939, 106765}},
+{20686, 18, 122479, {1, 1, 3, 3, 1, 49, 29, 115, 395, 647, 147, 3905, 1025, 8873, 10587, 25471, 72089, 171467}},
+{20687, 18, 122484, {1, 3, 7, 1, 21, 55, 57, 233, 487, 883, 439, 929, 1405, 13709, 2389, 20205, 17579, 9129}},
+{20688, 18, 122521, {1, 3, 5, 5, 23, 51, 55, 45, 307, 855, 933, 1443, 4757, 8719, 28401, 35189, 105329, 9211}},
+{20689, 18, 122540, {1, 3, 7, 11, 29, 17, 17, 147, 221, 997, 1433, 59, 8027, 231, 30335, 2153, 21393, 116661}},
+{20690, 18, 122545, {1, 1, 7, 3, 5, 43, 47, 155, 357, 915, 1923, 3315, 4107, 9785, 4847, 57683, 87569, 179583}},
+{20691, 18, 122552, {1, 1, 7, 7, 27, 5, 37, 95, 265, 113, 143, 3755, 5793, 5601, 16621, 54777, 15989, 158933}},
+{20692, 18, 122560, {1, 3, 1, 1, 13, 31, 113, 255, 367, 559, 1777, 4065, 8061, 15785, 10345, 54833, 95277, 159347}},
+{20693, 18, 122575, {1, 1, 1, 15, 3, 43, 85, 251, 193, 19, 1685, 271, 1779, 11901, 18983, 65361, 128217, 248051}},
+{20694, 18, 122578, {1, 3, 5, 7, 29, 21, 5, 47, 263, 913, 83, 3233, 113, 8341, 14473, 37405, 2363, 155931}},
+{20695, 18, 122605, {1, 1, 7, 15, 7, 25, 41, 39, 315, 323, 827, 1277, 1211, 4465, 21161, 36865, 6689, 139147}},
+{20696, 18, 122661, {1, 1, 1, 9, 11, 45, 81, 235, 31, 247, 77, 1877, 7119, 16007, 2225, 65, 85537, 99251}},
+{20697, 18, 122673, {1, 1, 3, 11, 19, 5, 49, 179, 345, 961, 349, 2099, 2317, 12771, 27169, 59389, 116071, 68333}},
+{20698, 18, 122722, {1, 3, 3, 5, 15, 53, 47, 177, 103, 941, 87, 2813, 7729, 8003, 7717, 40095, 74569, 106617}},
+{20699, 18, 122728, {1, 1, 7, 7, 31, 23, 105, 205, 325, 855, 1529, 3601, 7151, 15827, 16241, 18221, 55771, 139225}},
+{20700, 18, 122739, {1, 3, 5, 13, 13, 5, 95, 167, 25, 779, 1147, 221, 5055, 10943, 28077, 15131, 89501, 137407}},
+{20701, 18, 122751, {1, 3, 7, 13, 31, 3, 105, 163, 41, 823, 1493, 2985, 5589, 3543, 24683, 34469, 40595, 200875}},
+{20702, 18, 122762, {1, 3, 5, 3, 27, 35, 105, 163, 477, 667, 45, 319, 3201, 11535, 19349, 55253, 60275, 209597}},
+{20703, 18, 122769, {1, 3, 1, 11, 5, 13, 25, 225, 169, 925, 1617, 537, 891, 5583, 7181, 39953, 97537, 104019}},
+{20704, 18, 122772, {1, 3, 5, 9, 13, 1, 69, 147, 465, 259, 1219, 2407, 4015, 4883, 4333, 40441, 31289, 52989}},
+{20705, 18, 122782, {1, 3, 5, 5, 17, 29, 105, 233, 307, 807, 1535, 251, 135, 925, 6865, 59739, 112757, 208275}},
+{20706, 18, 122798, {1, 1, 1, 7, 9, 21, 49, 247, 33, 127, 1277, 1745, 139, 12165, 23517, 50235, 101003, 109031}},
+{20707, 18, 122810, {1, 3, 5, 9, 19, 7, 9, 139, 511, 901, 551, 2717, 6091, 3213, 819, 51381, 108333, 119681}},
+{20708, 18, 122812, {1, 1, 1, 3, 19, 17, 73, 19, 313, 589, 1965, 1745, 921, 4237, 12527, 10735, 110139, 171513}},
+{20709, 18, 122818, {1, 1, 5, 15, 25, 29, 15, 217, 87, 793, 419, 915, 1359, 10507, 25343, 62977, 100913, 110041}},
+{20710, 18, 122829, {1, 3, 7, 15, 15, 15, 91, 243, 441, 437, 1759, 2659, 2319, 7783, 16857, 19051, 15463, 253115}},
+{20711, 18, 122851, {1, 1, 5, 13, 15, 5, 7, 165, 355, 559, 217, 235, 3565, 12047, 2387, 62285, 73363, 238551}},
+{20712, 18, 122857, {1, 3, 7, 11, 5, 5, 69, 205, 179, 815, 335, 979, 2129, 6221, 31987, 13623, 23103, 24373}},
+{20713, 18, 122868, {1, 1, 7, 11, 31, 51, 55, 93, 195, 219, 825, 2919, 4495, 5927, 11813, 16415, 121595, 188613}},
+{20714, 18, 122893, {1, 1, 3, 1, 3, 11, 73, 45, 141, 219, 337, 2569, 6549, 3699, 2417, 2945, 19389, 82561}},
+{20715, 18, 122894, {1, 3, 1, 13, 5, 47, 47, 81, 11, 57, 1965, 2173, 3209, 10617, 19887, 5571, 61403, 37401}},
+{20716, 18, 122902, {1, 3, 3, 7, 3, 5, 99, 253, 287, 655, 813, 3365, 2387, 8951, 1561, 37637, 97625, 148699}},
+{20717, 18, 122921, {1, 1, 3, 5, 9, 31, 49, 7, 55, 607, 1489, 3229, 5871, 1271, 22751, 32309, 16125, 93409}},
+{20718, 18, 122959, {1, 3, 1, 5, 19, 35, 29, 233, 407, 297, 1465, 3089, 7535, 7221, 24469, 42653, 65719, 196771}},
+{20719, 18, 122984, {1, 1, 7, 13, 17, 19, 37, 45, 211, 545, 963, 79, 13, 8319, 8045, 24975, 122749, 25845}},
+{20720, 18, 123001, {1, 3, 5, 3, 23, 23, 53, 101, 363, 49, 1351, 3419, 1603, 10795, 5289, 63695, 113911, 228301}},
+{20721, 18, 123038, {1, 3, 7, 9, 15, 59, 125, 59, 11, 397, 693, 397, 3829, 14349, 13973, 54739, 22093, 216009}},
+{20722, 18, 123076, {1, 1, 1, 13, 5, 63, 21, 23, 421, 35, 589, 803, 6193, 11375, 9501, 34441, 68421, 120109}},
+{20723, 18, 123100, {1, 3, 3, 7, 23, 25, 79, 203, 177, 173, 175, 809, 4331, 6953, 4999, 34345, 94481, 88683}},
+{20724, 18, 123107, {1, 3, 3, 3, 1, 51, 109, 195, 83, 747, 63, 325, 927, 1757, 32055, 37185, 22697, 41509}},
+{20725, 18, 123122, {1, 3, 5, 13, 1, 63, 45, 73, 121, 445, 1935, 3373, 563, 7503, 17941, 60313, 42219, 220917}},
+{20726, 18, 123139, {1, 3, 5, 13, 27, 31, 7, 83, 109, 387, 447, 1691, 1301, 7449, 8075, 30713, 87207, 84855}},
+{20727, 18, 123175, {1, 3, 1, 5, 25, 51, 83, 11, 261, 977, 1415, 2973, 1789, 12641, 16279, 4225, 44237, 173561}},
+{20728, 18, 123190, {1, 1, 5, 15, 17, 47, 105, 199, 83, 705, 1215, 2759, 7509, 10407, 4005, 4575, 65961, 209933}},
+{20729, 18, 123201, {1, 3, 1, 13, 27, 3, 5, 199, 405, 515, 291, 3399, 1497, 14755, 30229, 35075, 111585, 16633}},
+{20730, 18, 123219, {1, 1, 1, 13, 17, 53, 93, 161, 447, 903, 947, 1871, 3597, 10575, 18389, 48551, 65229, 32591}},
+{20731, 18, 123232, {1, 3, 5, 11, 9, 7, 53, 155, 299, 523, 1653, 3517, 2725, 9485, 27099, 47895, 30169, 260463}},
+{20732, 18, 123255, {1, 1, 3, 13, 11, 45, 31, 183, 445, 21, 313, 2597, 195, 16053, 7323, 52951, 25919, 9323}},
+{20733, 18, 123285, {1, 1, 1, 15, 1, 35, 15, 115, 53, 561, 1141, 3261, 83, 2547, 8925, 43455, 112755, 94157}},
+{20734, 18, 123328, {1, 1, 3, 5, 27, 25, 81, 51, 209, 87, 379, 3167, 4953, 13885, 20159, 103, 115363, 123585}},
+{20735, 18, 123385, {1, 3, 5, 1, 25, 29, 107, 225, 77, 435, 2009, 4069, 3703, 8855, 14101, 61683, 16993, 110823}},
+{20736, 18, 123397, {1, 3, 7, 3, 31, 25, 51, 117, 397, 271, 89, 3571, 2357, 4923, 16303, 2357, 107775, 73809}},
+{20737, 18, 123404, {1, 1, 3, 1, 29, 21, 33, 67, 363, 753, 915, 3715, 2013, 8439, 5779, 267, 32687, 104283}},
+{20738, 18, 123419, {1, 3, 1, 11, 11, 7, 31, 43, 339, 917, 2005, 759, 4285, 1933, 4341, 19111, 130651, 122853}},
+{20739, 18, 123435, {1, 1, 5, 1, 17, 63, 85, 63, 387, 127, 1313, 619, 6525, 9003, 10915, 64507, 13175, 45219}},
+{20740, 18, 123437, {1, 3, 7, 9, 25, 15, 43, 13, 411, 391, 571, 527, 8175, 10849, 20093, 2987, 29869, 77207}},
+{20741, 18, 123443, {1, 1, 5, 3, 29, 53, 105, 57, 91, 977, 1103, 2977, 5617, 7203, 26717, 28463, 55909, 59943}},
+{20742, 18, 123500, {1, 3, 1, 7, 1, 47, 111, 215, 189, 377, 11, 871, 2267, 5705, 8165, 38895, 71025, 10921}},
+{20743, 18, 123506, {1, 1, 7, 9, 29, 55, 1, 103, 505, 697, 317, 3209, 3643, 13689, 8499, 14671, 67937, 100467}},
+{20744, 18, 123511, {1, 3, 1, 5, 25, 15, 99, 199, 117, 957, 1421, 1719, 5185, 15247, 28615, 2657, 46867, 190135}},
+{20745, 18, 123512, {1, 1, 7, 9, 27, 55, 81, 47, 15, 497, 537, 857, 2905, 1909, 3341, 32625, 123189, 21875}},
+{20746, 18, 123518, {1, 3, 1, 3, 19, 51, 97, 143, 305, 1021, 543, 829, 7593, 8101, 6337, 4869, 19177, 38981}},
+{20747, 18, 123522, {1, 3, 3, 15, 9, 37, 51, 193, 295, 731, 809, 4065, 3377, 15303, 12505, 11327, 76191, 139899}},
+{20748, 18, 123545, {1, 1, 5, 1, 3, 19, 5, 223, 379, 7, 755, 1127, 505, 9429, 27409, 50817, 97599, 179019}},
+{20749, 18, 123572, {1, 3, 5, 3, 5, 11, 83, 119, 3, 311, 405, 2401, 1821, 1381, 4567, 44079, 61903, 183583}},
+{20750, 18, 123587, {1, 3, 7, 9, 7, 11, 107, 95, 271, 537, 335, 3079, 6695, 1163, 32055, 44985, 29075, 94235}},
+{20751, 18, 123594, {1, 3, 7, 7, 7, 57, 59, 85, 199, 563, 1835, 351, 7675, 2601, 3717, 57975, 92529, 101511}},
+{20752, 18, 123607, {1, 1, 1, 5, 17, 5, 97, 43, 101, 141, 1511, 199, 7157, 3169, 24815, 55653, 104195, 37951}},
+{20753, 18, 123608, {1, 1, 1, 11, 23, 29, 41, 47, 447, 583, 773, 859, 1657, 8707, 16709, 53477, 42037, 186809}},
+{20754, 18, 123630, {1, 1, 1, 13, 13, 5, 85, 9, 213, 511, 1003, 811, 2271, 14715, 21423, 48127, 50613, 214031}},
+{20755, 18, 123635, {1, 1, 3, 5, 7, 31, 87, 101, 297, 853, 1599, 1521, 4965, 9655, 23543, 62277, 11231, 49931}},
+{20756, 18, 123659, {1, 1, 7, 7, 19, 31, 9, 165, 207, 919, 739, 3849, 2121, 867, 3233, 40867, 75721, 5327}},
+{20757, 18, 123692, {1, 3, 7, 1, 17, 3, 27, 13, 431, 283, 465, 1427, 1937, 15601, 21793, 9315, 54285, 196453}},
+{20758, 18, 123695, {1, 1, 7, 3, 17, 39, 65, 137, 511, 19, 1357, 3373, 5227, 2485, 1151, 25061, 117507, 119219}},
+{20759, 18, 123700, {1, 3, 3, 9, 9, 23, 13, 235, 505, 625, 115, 3859, 6943, 14719, 6363, 14957, 28241, 187989}},
+{20760, 18, 123730, {1, 3, 7, 13, 11, 31, 23, 39, 463, 441, 1145, 417, 4177, 1655, 26491, 16895, 26263, 198157}},
+{20761, 18, 123748, {1, 3, 3, 7, 25, 55, 121, 157, 131, 537, 1891, 2367, 1717, 2331, 20251, 8679, 62657, 121957}},
+{20762, 18, 123751, {1, 1, 1, 11, 7, 43, 59, 101, 333, 961, 569, 1603, 3009, 6539, 9627, 5759, 44401, 127613}},
+{20763, 18, 123770, {1, 3, 3, 3, 1, 27, 15, 135, 235, 215, 627, 2427, 2647, 3201, 22873, 64445, 32635, 16587}},
+{20764, 18, 123793, {1, 3, 7, 7, 5, 49, 63, 103, 467, 897, 117, 1149, 6045, 5003, 5005, 6183, 90815, 190909}},
+{20765, 18, 123800, {1, 1, 3, 3, 31, 43, 45, 227, 363, 409, 1097, 3155, 1519, 14461, 29377, 19577, 52595, 94041}},
+{20766, 18, 123803, {1, 3, 1, 1, 3, 25, 83, 243, 57, 243, 389, 1427, 5197, 13125, 18571, 17845, 74961, 125569}},
+{20767, 18, 123851, {1, 3, 5, 5, 1, 39, 11, 175, 97, 1001, 143, 3653, 5887, 5845, 5691, 5433, 62629, 176261}},
+{20768, 18, 123859, {1, 1, 1, 13, 11, 41, 41, 155, 17, 823, 1507, 733, 5663, 13657, 24133, 9971, 27179, 108075}},
+{20769, 18, 123866, {1, 1, 7, 9, 19, 9, 103, 29, 427, 363, 931, 3959, 1629, 5127, 14807, 61937, 127175, 237233}},
+{20770, 18, 123868, {1, 1, 1, 5, 29, 53, 51, 229, 123, 1001, 697, 411, 4669, 5051, 18447, 55437, 129269, 72613}},
+{20771, 18, 123877, {1, 3, 7, 3, 19, 53, 111, 131, 255, 547, 653, 2839, 1447, 14397, 5707, 23773, 127897, 135177}},
+{20772, 18, 123884, {1, 3, 3, 5, 21, 37, 53, 219, 359, 341, 489, 2477, 3383, 6931, 7753, 2619, 114267, 63271}},
+{20773, 18, 123909, {1, 1, 3, 15, 15, 15, 95, 171, 301, 563, 603, 593, 4037, 7305, 10849, 11753, 103087, 74887}},
+{20774, 18, 123910, {1, 1, 5, 3, 11, 51, 105, 35, 155, 643, 569, 1697, 1679, 7547, 19289, 7065, 57359, 142855}},
+{20775, 18, 123919, {1, 1, 7, 15, 23, 55, 17, 67, 375, 559, 355, 165, 93, 973, 22831, 48027, 98435, 59945}},
+{20776, 18, 123927, {1, 3, 7, 3, 5, 43, 9, 253, 111, 819, 45, 3461, 4821, 14735, 14469, 29793, 30681, 26359}},
+{20777, 18, 123937, {1, 3, 3, 5, 15, 1, 39, 233, 63, 287, 131, 3453, 427, 4929, 30085, 18583, 50119, 262101}},
+{20778, 18, 123950, {1, 3, 7, 9, 31, 7, 127, 157, 287, 57, 1091, 1989, 5045, 13071, 27705, 58125, 85317, 66649}},
+{20779, 18, 123957, {1, 1, 1, 15, 17, 29, 25, 223, 311, 489, 1901, 3197, 1813, 10097, 31915, 54871, 32289, 227001}},
+{20780, 18, 123979, {1, 3, 7, 5, 31, 35, 69, 87, 131, 963, 1125, 1109, 8037, 3257, 27655, 50999, 3715, 57851}},
+{20781, 18, 123996, {1, 1, 5, 5, 27, 7, 119, 29, 425, 721, 541, 3069, 3349, 13623, 12293, 51395, 14033, 61545}},
+{20782, 18, 124040, {1, 3, 7, 3, 17, 49, 103, 115, 387, 729, 1389, 2257, 3273, 3375, 23143, 2835, 28071, 79533}},
+{20783, 18, 124054, {1, 1, 3, 7, 9, 19, 55, 159, 261, 467, 17, 2595, 3947, 7045, 193, 23629, 89067, 81197}},
+{20784, 18, 124063, {1, 1, 1, 15, 13, 39, 103, 195, 251, 769, 1003, 2707, 3263, 8451, 8007, 53789, 112653, 258717}},
+{20785, 18, 124067, {1, 3, 5, 1, 3, 21, 29, 217, 125, 779, 1597, 513, 2677, 3979, 31903, 64813, 69963, 92887}},
+{20786, 18, 124088, {1, 1, 3, 11, 11, 59, 81, 237, 447, 703, 41, 3369, 3547, 14935, 31693, 52005, 74149, 131039}},
+{20787, 18, 124101, {1, 1, 3, 1, 23, 1, 33, 93, 275, 847, 921, 2745, 533, 8975, 30529, 46809, 98975, 75541}},
+{20788, 18, 124154, {1, 1, 7, 7, 15, 1, 3, 213, 71, 1009, 1951, 3015, 713, 9365, 21949, 60983, 117633, 225387}},
+{20789, 18, 124162, {1, 1, 1, 11, 31, 27, 59, 179, 231, 635, 1555, 2765, 31, 15065, 22719, 59251, 84733, 96769}},
+{20790, 18, 124167, {1, 3, 7, 3, 19, 5, 35, 207, 317, 735, 943, 3987, 4021, 11229, 13015, 713, 125167, 55887}},
+{20791, 18, 124176, {1, 1, 3, 1, 27, 49, 81, 17, 253, 633, 43, 2953, 3151, 8429, 30625, 28551, 126683, 175087}},
+{20792, 18, 124195, {1, 3, 3, 3, 9, 53, 111, 245, 57, 557, 945, 2957, 7669, 12537, 17291, 9713, 87727, 44739}},
+{20793, 18, 124230, {1, 3, 1, 1, 5, 39, 77, 127, 87, 687, 1485, 1555, 2567, 13551, 17075, 24003, 47627, 129813}},
+{20794, 18, 124267, {1, 3, 5, 9, 25, 35, 87, 233, 439, 563, 1719, 419, 4459, 4285, 25157, 943, 111543, 232107}},
+{20795, 18, 124346, {1, 3, 5, 11, 1, 13, 97, 153, 459, 551, 73, 2087, 3985, 4661, 15603, 22211, 123163, 187233}},
+{20796, 18, 124389, {1, 1, 7, 13, 17, 59, 5, 219, 353, 441, 387, 441, 3009, 485, 20081, 38023, 50659, 159243}},
+{20797, 18, 124418, {1, 3, 1, 7, 21, 31, 117, 49, 227, 677, 417, 1153, 1611, 1669, 25161, 52223, 15109, 114759}},
+{20798, 18, 124420, {1, 1, 7, 9, 19, 13, 111, 7, 1, 701, 731, 2075, 685, 15679, 19149, 44315, 41719, 243975}},
+{20799, 18, 124454, {1, 3, 3, 7, 15, 63, 59, 105, 327, 39, 1497, 2407, 2865, 7065, 9957, 20031, 45359, 73657}},
+{20800, 18, 124490, {1, 3, 1, 13, 7, 3, 55, 221, 443, 953, 15, 2455, 4681, 16247, 18179, 44731, 41323, 172621}},
+{20801, 18, 124503, {1, 1, 3, 9, 1, 27, 65, 167, 115, 137, 819, 2129, 3393, 5901, 11735, 62753, 14941, 21425}},
+{20802, 18, 124519, {1, 3, 7, 11, 7, 9, 41, 175, 237, 481, 59, 265, 2135, 9419, 3937, 55959, 48343, 172549}},
+{20803, 18, 124533, {1, 1, 1, 13, 23, 33, 105, 87, 461, 297, 1345, 3715, 7715, 16369, 19017, 15141, 10873, 109641}},
+{20804, 18, 124544, {1, 3, 5, 1, 11, 1, 13, 41, 447, 511, 447, 2295, 2401, 14171, 16269, 50453, 40361, 205857}},
+{20805, 18, 124589, {1, 1, 3, 3, 27, 7, 35, 193, 113, 341, 335, 2113, 343, 4575, 20863, 40383, 86787, 142603}},
+{20806, 18, 124616, {1, 1, 7, 11, 17, 25, 51, 89, 341, 237, 1233, 1505, 7401, 6887, 26897, 20127, 51077, 107559}},
+{20807, 18, 124630, {1, 1, 1, 15, 9, 59, 29, 115, 339, 785, 201, 947, 1501, 6883, 169, 44059, 17527, 197623}},
+{20808, 18, 124636, {1, 3, 7, 3, 17, 59, 15, 5, 379, 347, 821, 4047, 3565, 13689, 23275, 27901, 121401, 43077}},
+{20809, 18, 124645, {1, 1, 1, 7, 15, 11, 35, 29, 59, 99, 181, 3035, 3239, 1553, 32319, 64195, 115247, 149211}},
+{20810, 18, 124652, {1, 1, 5, 3, 31, 49, 87, 177, 231, 167, 373, 1125, 5919, 4805, 31983, 42873, 30169, 91853}},
+{20811, 18, 124663, {1, 1, 5, 15, 7, 63, 37, 15, 459, 449, 1835, 1769, 2527, 2577, 4251, 62459, 76699, 81721}},
+{20812, 18, 124667, {1, 1, 1, 3, 21, 15, 19, 183, 423, 827, 341, 2101, 3797, 7103, 30845, 24511, 115337, 117019}},
+{20813, 18, 124690, {1, 3, 5, 5, 19, 1, 97, 13, 491, 51, 445, 1987, 7481, 2613, 23141, 36603, 26917, 177397}},
+{20814, 18, 124755, {1, 1, 1, 5, 15, 43, 21, 167, 259, 989, 1937, 1519, 2201, 13973, 18031, 31583, 57557, 252737}},
+{20815, 18, 124757, {1, 3, 3, 7, 31, 11, 89, 53, 279, 83, 1247, 1221, 5499, 1199, 361, 22269, 88633, 134975}},
+{20816, 18, 124819, {1, 1, 3, 5, 9, 5, 113, 41, 143, 655, 1147, 2043, 4229, 10523, 1453, 1735, 76259, 30607}},
+{20817, 18, 124862, {1, 1, 1, 11, 5, 7, 9, 155, 221, 619, 813, 3111, 6039, 10789, 10905, 33285, 62841, 229217}},
+{20818, 18, 124864, {1, 3, 5, 9, 19, 19, 123, 65, 419, 597, 87, 3843, 4857, 15903, 23655, 13023, 8389, 230803}},
+{20819, 18, 124874, {1, 3, 3, 15, 9, 19, 51, 223, 197, 759, 139, 59, 6547, 1043, 5077, 55267, 23681, 17099}},
+{20820, 18, 124882, {1, 1, 3, 3, 15, 43, 63, 85, 227, 961, 1043, 1069, 6557, 7499, 31639, 4345, 26991, 132783}},
+{20821, 18, 124903, {1, 3, 1, 1, 25, 33, 59, 219, 435, 105, 1001, 323, 2729, 12517, 16607, 57533, 101167, 53829}},
+{20822, 18, 124915, {1, 3, 7, 7, 9, 55, 3, 247, 303, 453, 861, 817, 705, 14337, 15965, 28867, 126763, 204005}},
+{20823, 18, 124938, {1, 1, 3, 7, 1, 39, 15, 39, 359, 313, 1753, 2835, 387, 16223, 10945, 19481, 19995, 29989}},
+{20824, 18, 124945, {1, 1, 1, 5, 3, 31, 103, 123, 493, 1023, 119, 2175, 2273, 11637, 21605, 23349, 100759, 41227}},
+{20825, 18, 124973, {1, 3, 7, 13, 5, 13, 17, 7, 341, 945, 621, 1421, 3893, 5825, 26777, 35497, 13791, 25415}},
+{20826, 18, 124986, {1, 1, 5, 1, 19, 27, 39, 7, 177, 749, 1217, 2133, 6913, 13489, 23713, 1085, 31529, 179741}},
+{20827, 18, 124991, {1, 3, 3, 3, 15, 21, 5, 145, 281, 131, 1347, 19, 4917, 8655, 2515, 36927, 56551, 202039}},
+{20828, 18, 125011, {1, 1, 3, 7, 27, 31, 33, 255, 511, 195, 1493, 2221, 2157, 9303, 3957, 14163, 70435, 215763}},
+{20829, 18, 125014, {1, 3, 3, 15, 31, 41, 33, 37, 239, 865, 375, 2217, 809, 11961, 29393, 52145, 76223, 202623}},
+{20830, 18, 125082, {1, 3, 5, 11, 5, 57, 73, 193, 341, 843, 1817, 231, 65, 5941, 29693, 31751, 57081, 180977}},
+{20831, 18, 125105, {1, 3, 1, 9, 29, 57, 85, 107, 343, 891, 465, 2413, 1965, 7303, 7461, 25857, 110517, 16995}},
+{20832, 18, 125163, {1, 1, 7, 15, 7, 49, 121, 211, 253, 511, 1385, 1205, 33, 7713, 20059, 47353, 3267, 215759}},
+{20833, 18, 125165, {1, 1, 3, 9, 15, 63, 45, 155, 415, 589, 651, 3707, 5429, 4497, 13733, 21231, 18953, 28671}},
+{20834, 18, 125205, {1, 1, 5, 15, 7, 57, 31, 109, 427, 921, 629, 3439, 7615, 4535, 1507, 58931, 49597, 214397}},
+{20835, 18, 125219, {1, 3, 3, 5, 21, 35, 9, 241, 67, 767, 659, 1639, 7797, 5209, 14851, 55311, 108549, 175937}},
+{20836, 18, 125239, {1, 1, 7, 15, 21, 61, 13, 47, 267, 269, 1169, 257, 2481, 8345, 1061, 28119, 127197, 95379}},
+{20837, 18, 125240, {1, 1, 3, 7, 21, 35, 121, 223, 145, 665, 1389, 2105, 5499, 1377, 32417, 39027, 5335, 248315}},
+{20838, 18, 125257, {1, 3, 3, 9, 13, 33, 57, 225, 123, 703, 1049, 709, 7347, 11317, 12339, 23247, 62157, 85931}},
+{20839, 18, 125284, {1, 3, 3, 3, 5, 3, 105, 115, 13, 675, 757, 987, 6429, 13017, 21347, 38829, 82153, 220677}},
+{20840, 18, 125302, {1, 3, 1, 13, 5, 51, 75, 205, 7, 561, 207, 1133, 3303, 1889, 17093, 5933, 48109, 244387}},
+{20841, 18, 125327, {1, 3, 3, 7, 11, 11, 71, 243, 235, 941, 1875, 2387, 1139, 16275, 4537, 18791, 67927, 156759}},
+{20842, 18, 125336, {1, 3, 5, 5, 11, 35, 29, 5, 351, 223, 847, 1539, 4903, 7619, 24907, 37071, 57899, 32981}},
+{20843, 18, 125355, {1, 3, 1, 7, 23, 7, 119, 17, 123, 845, 1423, 2995, 3595, 13287, 31217, 33939, 6891, 156477}},
+{20844, 18, 125363, {1, 1, 1, 9, 11, 55, 121, 85, 175, 757, 1093, 513, 1117, 14049, 22377, 4623, 38511, 51391}},
+{20845, 18, 125365, {1, 1, 7, 1, 17, 1, 7, 185, 173, 841, 61, 2735, 6679, 7617, 17309, 58047, 11791, 228635}},
+{20846, 18, 125372, {1, 1, 5, 5, 1, 1, 61, 57, 37, 857, 531, 2655, 1907, 4245, 3047, 50489, 93447, 116637}},
+{20847, 18, 125378, {1, 3, 5, 7, 27, 47, 121, 95, 73, 63, 539, 137, 1765, 4659, 31141, 24495, 109541, 16421}},
+{20848, 18, 125383, {1, 3, 7, 13, 13, 25, 47, 45, 97, 243, 1509, 3539, 4791, 5627, 31981, 57663, 65359, 32183}},
+{20849, 18, 125387, {1, 1, 1, 7, 15, 57, 117, 249, 183, 849, 557, 833, 5751, 8035, 3371, 11389, 125581, 248799}},
+{20850, 18, 125390, {1, 3, 1, 15, 13, 31, 59, 243, 17, 473, 289, 1527, 649, 2807, 6183, 6173, 74381, 261673}},
+{20851, 18, 125414, {1, 1, 7, 7, 19, 17, 95, 81, 191, 487, 2023, 307, 3261, 13885, 9285, 30831, 114009, 26483}},
+{20852, 18, 125435, {1, 1, 3, 11, 17, 21, 85, 193, 477, 267, 393, 39, 5793, 8621, 25379, 9721, 13947, 44235}},
+{20853, 18, 125466, {1, 1, 7, 5, 27, 33, 93, 9, 471, 751, 1279, 695, 2625, 7061, 29577, 5403, 80705, 77895}},
+{20854, 18, 125481, {1, 1, 3, 11, 7, 25, 125, 9, 233, 935, 1897, 3685, 595, 15499, 43, 29251, 18029, 250231}},
+{20855, 18, 125522, {1, 1, 5, 1, 9, 55, 125, 179, 287, 371, 233, 149, 5639, 5737, 25251, 103, 117015, 35579}},
+{20856, 18, 125531, {1, 1, 5, 9, 17, 33, 69, 15, 209, 521, 1083, 2469, 679, 9307, 31539, 63889, 48825, 126327}},
+{20857, 18, 125544, {1, 3, 5, 15, 15, 41, 105, 121, 21, 935, 721, 445, 6759, 4227, 15227, 54933, 69589, 2689}},
+{20858, 18, 125564, {1, 1, 7, 15, 1, 15, 111, 141, 279, 1013, 825, 1069, 3793, 12929, 153, 11463, 87759, 179987}},
+{20859, 18, 125588, {1, 1, 1, 9, 15, 59, 109, 103, 223, 695, 1979, 1241, 2559, 8627, 10559, 53319, 94311, 245193}},
+{20860, 18, 125602, {1, 1, 5, 3, 1, 41, 51, 129, 297, 15, 637, 2489, 343, 13549, 7707, 36757, 55703, 161043}},
+{20861, 18, 125613, {1, 3, 5, 1, 13, 35, 119, 219, 319, 733, 789, 1343, 8035, 15049, 981, 14477, 13717, 177481}},
+{20862, 18, 125621, {1, 1, 1, 11, 5, 17, 3, 43, 129, 705, 1701, 3635, 1201, 12283, 27443, 54257, 102281, 211859}},
+{20863, 18, 125648, {1, 3, 1, 13, 7, 63, 9, 45, 283, 41, 801, 131, 2797, 13329, 19011, 21055, 122965, 7961}},
+{20864, 18, 125651, {1, 3, 3, 5, 9, 27, 99, 129, 499, 523, 1939, 3661, 455, 12601, 11723, 3727, 32671, 78251}},
+{20865, 18, 125681, {1, 3, 7, 5, 9, 57, 63, 47, 49, 745, 945, 2927, 6659, 1023, 9991, 55379, 105295, 259901}},
+{20866, 18, 125719, {1, 1, 3, 3, 3, 47, 15, 237, 193, 409, 1165, 3581, 719, 3049, 14679, 31559, 7825, 96083}},
+{20867, 18, 125773, {1, 1, 7, 11, 9, 55, 29, 123, 163, 415, 2013, 97, 1471, 1409, 28867, 50405, 99417, 57113}},
+{20868, 18, 125774, {1, 1, 7, 15, 5, 17, 57, 123, 25, 119, 1699, 1289, 3139, 7177, 13465, 33583, 34517, 182669}},
+{20869, 18, 125779, {1, 1, 3, 1, 15, 45, 79, 7, 461, 223, 691, 3071, 6233, 14997, 4083, 65391, 60571, 82929}},
+{20870, 18, 125786, {1, 3, 5, 1, 25, 39, 89, 105, 497, 685, 1921, 133, 4849, 8467, 609, 62183, 123787, 223025}},
+{20871, 18, 125792, {1, 1, 1, 13, 3, 57, 117, 241, 501, 107, 1253, 3097, 603, 10645, 3395, 13997, 112527, 208263}},
+{20872, 18, 125822, {1, 1, 7, 9, 7, 31, 25, 97, 205, 785, 517, 549, 6841, 7097, 9635, 17151, 57135, 105469}},
+{20873, 18, 125828, {1, 3, 7, 1, 25, 35, 43, 75, 179, 1023, 1921, 1529, 2791, 6747, 9135, 61801, 46729, 26821}},
+{20874, 18, 125831, {1, 1, 3, 1, 31, 49, 107, 219, 285, 501, 1503, 3103, 5257, 14561, 31493, 7753, 34375, 260357}},
+{20875, 18, 125837, {1, 3, 7, 13, 15, 7, 75, 57, 329, 67, 1541, 2445, 3069, 6723, 10189, 22913, 110781, 243765}},
+{20876, 18, 125880, {1, 1, 5, 3, 5, 45, 47, 39, 493, 787, 1019, 3933, 535, 1763, 139, 45967, 123167, 115019}},
+{20877, 18, 125891, {1, 3, 1, 3, 23, 59, 93, 139, 349, 973, 1401, 2109, 701, 461, 19199, 21733, 80009, 37239}},
+{20878, 18, 125922, {1, 1, 3, 5, 3, 39, 117, 77, 257, 117, 1991, 3371, 509, 3963, 14579, 62459, 52281, 99209}},
+{20879, 18, 125928, {1, 3, 1, 15, 29, 47, 73, 157, 429, 497, 39, 123, 4851, 12871, 4567, 29453, 90777, 188683}},
+{20880, 18, 125931, {1, 3, 3, 1, 17, 25, 5, 247, 61, 81, 1555, 2167, 6003, 15911, 16023, 7841, 50731, 229163}},
+{20881, 18, 125941, {1, 1, 5, 9, 9, 39, 89, 37, 105, 133, 333, 2863, 7249, 2355, 9407, 28145, 25923, 68827}},
+{20882, 18, 125948, {1, 3, 7, 13, 15, 55, 11, 93, 197, 447, 1793, 1793, 4639, 1869, 1711, 1439, 15899, 106931}},
+{20883, 18, 125960, {1, 1, 5, 13, 23, 11, 67, 155, 511, 363, 1073, 2249, 719, 11167, 7953, 21699, 55735, 47353}},
+{20884, 18, 125973, {1, 1, 3, 3, 21, 59, 123, 227, 65, 695, 1769, 4057, 7071, 1827, 13639, 45711, 84019, 96897}},
+{20885, 18, 126014, {1, 3, 1, 11, 25, 51, 57, 139, 147, 589, 1565, 511, 3629, 7329, 9565, 62893, 85789, 112047}},
+{20886, 18, 126016, {1, 3, 5, 5, 23, 11, 93, 75, 25, 947, 1489, 4081, 3395, 4655, 27853, 41299, 89447, 100971}},
+{20887, 18, 126036, {1, 3, 5, 11, 25, 63, 93, 227, 411, 49, 403, 437, 1739, 8453, 31693, 51439, 89729, 113405}},
+{20888, 18, 126043, {1, 3, 7, 9, 29, 13, 51, 155, 403, 627, 173, 2111, 833, 11453, 17673, 7121, 52943, 114835}},
+{20889, 18, 126062, {1, 1, 5, 13, 11, 11, 105, 101, 309, 577, 1003, 3667, 3489, 11807, 6119, 13773, 89879, 12391}},
+{20890, 18, 126076, {1, 3, 7, 9, 17, 11, 111, 239, 225, 723, 933, 3353, 2003, 5273, 207, 38539, 82539, 209781}},
+{20891, 18, 126116, {1, 1, 7, 13, 15, 53, 69, 105, 155, 445, 353, 617, 5625, 13439, 29223, 60439, 119635, 49643}},
+{20892, 18, 126125, {1, 1, 3, 11, 13, 25, 107, 27, 109, 313, 1721, 2647, 1861, 10631, 17131, 31365, 65319, 102905}},
+{20893, 18, 126145, {1, 1, 1, 7, 21, 29, 39, 167, 341, 115, 1523, 2209, 95, 4399, 3881, 38875, 107691, 132471}},
+{20894, 18, 126152, {1, 1, 1, 13, 15, 61, 125, 23, 301, 407, 1497, 3731, 7013, 5405, 31233, 51701, 45619, 107407}},
+{20895, 18, 126175, {1, 3, 5, 5, 31, 27, 77, 21, 339, 1013, 371, 19, 5733, 2177, 15547, 27595, 6805, 172695}},
+{20896, 18, 126188, {1, 3, 5, 11, 5, 15, 71, 23, 441, 169, 1715, 437, 1791, 293, 13441, 11225, 119119, 223035}},
+{20897, 18, 126199, {1, 3, 1, 5, 11, 15, 95, 127, 433, 789, 899, 2591, 2339, 8237, 20765, 32897, 51511, 58437}},
+{20898, 18, 126205, {1, 3, 5, 9, 11, 57, 103, 5, 401, 51, 1813, 923, 1983, 1853, 21913, 3051, 56309, 19423}},
+{20899, 18, 126213, {1, 1, 3, 15, 3, 3, 41, 5, 231, 35, 391, 185, 7585, 1005, 20311, 11193, 18275, 114131}},
+{20900, 18, 126220, {1, 1, 3, 9, 13, 13, 115, 203, 223, 575, 459, 1839, 3949, 16027, 23137, 13723, 19195, 249337}},
+{20901, 18, 126286, {1, 1, 1, 9, 21, 51, 39, 245, 187, 609, 319, 2927, 3625, 10789, 31291, 45557, 45935, 132447}},
+{20902, 18, 126294, {1, 3, 3, 9, 25, 37, 47, 55, 219, 409, 1927, 553, 3953, 6209, 11807, 11133, 48047, 132437}},
+{20903, 18, 126300, {1, 3, 1, 13, 23, 31, 109, 167, 281, 179, 233, 1603, 7391, 9091, 27021, 31213, 13093, 86017}},
+{20904, 18, 126322, {1, 3, 1, 13, 13, 15, 7, 29, 409, 59, 505, 1307, 6247, 6055, 5531, 59727, 58069, 84049}},
+{20905, 18, 126324, {1, 1, 5, 7, 19, 7, 103, 245, 133, 609, 1087, 2365, 3341, 1689, 18841, 19625, 47413, 63445}},
+{20906, 18, 126343, {1, 1, 7, 3, 11, 27, 79, 75, 97, 355, 493, 2035, 3413, 11835, 9157, 51173, 1, 71797}},
+{20907, 18, 126344, {1, 1, 5, 5, 29, 1, 43, 135, 473, 329, 1197, 1693, 3823, 7723, 24771, 22349, 94383, 41461}},
+{20908, 18, 126430, {1, 3, 3, 15, 25, 9, 79, 213, 317, 615, 541, 441, 505, 13665, 3691, 17825, 49303, 91783}},
+{20909, 18, 126433, {1, 3, 1, 11, 27, 33, 65, 31, 469, 799, 1251, 3357, 5239, 5651, 13317, 28553, 64225, 9805}},
+{20910, 18, 126448, {1, 1, 7, 13, 9, 49, 77, 43, 363, 719, 1943, 1285, 1587, 1047, 29419, 24025, 89901, 229095}},
+{20911, 18, 126451, {1, 1, 1, 15, 19, 57, 33, 243, 111, 183, 497, 603, 923, 1957, 6493, 11833, 7331, 229975}},
+{20912, 18, 126457, {1, 3, 1, 1, 13, 43, 31, 25, 169, 303, 69, 723, 1745, 1025, 14301, 2523, 111887, 179519}},
+{20913, 18, 126458, {1, 3, 1, 5, 31, 55, 11, 103, 391, 881, 1885, 3923, 7507, 377, 29331, 32167, 56915, 44211}},
+{20914, 18, 126463, {1, 1, 7, 1, 27, 55, 33, 141, 393, 73, 701, 3173, 973, 15553, 10219, 51441, 55201, 131055}},
+{20915, 18, 126470, {1, 1, 3, 9, 1, 31, 115, 85, 173, 227, 163, 157, 5569, 8291, 27163, 7581, 8699, 104523}},
+{20916, 18, 126484, {1, 1, 1, 5, 5, 19, 11, 55, 217, 571, 1001, 945, 6237, 1993, 11809, 63893, 60081, 102997}},
+{20917, 18, 126518, {1, 3, 3, 15, 15, 7, 51, 161, 147, 263, 1701, 1079, 3027, 11779, 24885, 16127, 68985, 162975}},
+{20918, 18, 126521, {1, 3, 1, 9, 25, 1, 47, 107, 149, 997, 1779, 2905, 4951, 10345, 31059, 63831, 117219, 251935}},
+{20919, 18, 126547, {1, 3, 3, 9, 5, 23, 83, 95, 399, 343, 1597, 1733, 5959, 9685, 4721, 59109, 113633, 80365}},
+{20920, 18, 126556, {1, 1, 7, 11, 31, 43, 71, 133, 305, 529, 645, 3095, 6273, 4019, 14433, 41609, 64093, 79051}},
+{20921, 18, 126583, {1, 3, 5, 11, 1, 63, 123, 25, 245, 583, 1013, 3275, 2997, 13021, 27515, 16233, 113093, 249101}},
+{20922, 18, 126584, {1, 1, 1, 9, 3, 59, 113, 155, 125, 423, 259, 1559, 3745, 9105, 27673, 36601, 36117, 47953}},
+{20923, 18, 126633, {1, 3, 3, 7, 19, 41, 55, 87, 53, 801, 661, 329, 3391, 7581, 25487, 25751, 120171, 35953}},
+{20924, 18, 126673, {1, 1, 7, 15, 31, 57, 49, 179, 147, 139, 957, 289, 4321, 8747, 53, 46003, 40219, 96855}},
+{20925, 18, 126680, {1, 1, 7, 9, 29, 49, 71, 101, 389, 793, 1355, 3263, 6331, 4869, 28479, 8335, 74653, 8519}},
+{20926, 18, 126686, {1, 1, 1, 13, 1, 19, 31, 161, 261, 679, 1115, 985, 2855, 4395, 15087, 18593, 98535, 52537}},
+{20927, 18, 126689, {1, 1, 3, 11, 15, 51, 79, 7, 75, 75, 753, 2637, 7193, 7961, 21411, 24273, 7543, 6277}},
+{20928, 18, 126702, {1, 3, 1, 5, 5, 51, 67, 191, 201, 777, 587, 1439, 1027, 3759, 31141, 42159, 58475, 7355}},
+{20929, 18, 126710, {1, 3, 5, 3, 15, 37, 11, 251, 53, 799, 739, 2225, 6985, 9183, 12341, 29963, 44101, 23889}},
+{20930, 18, 126722, {1, 1, 3, 3, 5, 33, 81, 223, 89, 531, 301, 305, 2401, 4015, 18607, 65041, 82447, 228487}},
+{20931, 18, 126787, {1, 3, 1, 7, 15, 29, 71, 247, 445, 1005, 1229, 3897, 899, 11175, 6349, 29145, 103153, 90275}},
+{20932, 18, 126789, {1, 3, 3, 7, 15, 7, 75, 13, 417, 719, 121, 1345, 3737, 4119, 15259, 33579, 57727, 111517}},
+{20933, 18, 126794, {1, 3, 7, 3, 31, 11, 49, 61, 405, 741, 1607, 1561, 4655, 9775, 14349, 27431, 91791, 228607}},
+{20934, 18, 126801, {1, 3, 5, 13, 17, 27, 93, 153, 99, 683, 219, 3783, 6963, 1633, 6621, 8133, 5111, 57333}},
+{20935, 18, 126857, {1, 3, 3, 3, 25, 29, 75, 155, 159, 25, 637, 3053, 4737, 5831, 9651, 45331, 100407, 188607}},
+{20936, 18, 126891, {1, 3, 1, 9, 21, 55, 123, 27, 509, 227, 1569, 1379, 7137, 11749, 14257, 38349, 459, 54873}},
+{20937, 18, 126896, {1, 1, 7, 15, 29, 35, 81, 79, 237, 155, 1551, 343, 5127, 3233, 3691, 59917, 7367, 181979}},
+{20938, 18, 126902, {1, 3, 1, 15, 1, 57, 111, 121, 375, 635, 1529, 635, 2337, 6553, 22067, 36047, 80099, 116411}},
+{20939, 18, 126911, {1, 1, 3, 3, 29, 27, 19, 3, 69, 197, 1829, 1907, 5901, 12651, 3295, 7805, 57871, 47571}},
+{20940, 18, 126919, {1, 1, 1, 13, 21, 5, 115, 51, 203, 991, 1731, 1101, 1607, 14323, 12233, 48047, 33969, 147621}},
+{20941, 18, 126943, {1, 3, 3, 1, 25, 55, 41, 31, 101, 551, 1519, 1915, 6961, 13919, 15339, 13141, 107625, 9247}},
+{20942, 18, 126947, {1, 1, 7, 11, 17, 25, 87, 175, 341, 445, 1813, 2995, 3217, 6015, 1637, 65243, 72743, 248715}},
+{20943, 18, 126949, {1, 1, 5, 13, 11, 1, 61, 139, 233, 167, 1363, 1991, 7999, 16289, 25595, 8915, 32205, 169963}},
+{20944, 18, 126953, {1, 1, 1, 13, 31, 33, 67, 57, 121, 477, 755, 2035, 3683, 16205, 5511, 25615, 5169, 128843}},
+{20945, 18, 126971, {1, 3, 5, 15, 31, 1, 89, 29, 493, 379, 1627, 491, 2503, 8105, 30275, 27379, 43905, 46397}},
+{20946, 18, 126976, {1, 1, 7, 9, 31, 41, 127, 121, 61, 561, 223, 3231, 7321, 3683, 15455, 8019, 116739, 96557}},
+{20947, 18, 126982, {1, 1, 5, 9, 19, 41, 25, 65, 111, 535, 611, 1631, 4251, 107, 19787, 40749, 65701, 48749}},
+{20948, 18, 127009, {1, 3, 3, 11, 27, 49, 75, 93, 15, 937, 1517, 1577, 7485, 8713, 15979, 13799, 103057, 144799}},
+{20949, 18, 127021, {1, 1, 7, 7, 7, 29, 3, 63, 177, 781, 2001, 315, 6703, 8055, 19081, 33641, 44279, 87597}},
+{20950, 18, 127027, {1, 1, 7, 11, 29, 53, 83, 223, 275, 951, 1883, 2447, 1815, 9313, 9247, 17185, 8143, 135247}},
+{20951, 18, 127039, {1, 1, 5, 13, 21, 47, 87, 55, 169, 95, 777, 2787, 7227, 11373, 16707, 28237, 30789, 64589}},
+{20952, 18, 127041, {1, 1, 1, 11, 15, 41, 1, 55, 337, 493, 1379, 2505, 6831, 10955, 1875, 21821, 54101, 9379}},
+{20953, 18, 127044, {1, 3, 5, 15, 27, 9, 121, 49, 439, 781, 1457, 1341, 7433, 5879, 13039, 24001, 64059, 157077}},
+{20954, 18, 127059, {1, 1, 1, 9, 19, 55, 89, 37, 255, 345, 215, 4067, 8151, 14253, 12121, 3637, 29185, 60643}},
+{20955, 18, 127071, {1, 3, 1, 7, 31, 39, 71, 29, 71, 83, 1249, 871, 8037, 1001, 25245, 26651, 34509, 123607}},
+{20956, 18, 127075, {1, 1, 3, 11, 13, 21, 15, 171, 255, 373, 429, 2179, 4431, 16087, 17949, 16307, 129877, 186495}},
+{20957, 18, 127126, {1, 3, 3, 9, 17, 45, 75, 175, 3, 403, 215, 1781, 7875, 14113, 6967, 65263, 125885, 232983}},
+{20958, 18, 127129, {1, 1, 7, 9, 21, 57, 73, 105, 163, 583, 587, 2743, 2199, 5187, 5571, 56399, 797, 192405}},
+{20959, 18, 127145, {1, 1, 1, 3, 29, 27, 71, 145, 11, 455, 1505, 2789, 4083, 12345, 14785, 4981, 95121, 134977}},
+{20960, 18, 127154, {1, 1, 1, 1, 1, 27, 1, 145, 473, 483, 83, 3009, 7241, 13633, 15071, 30767, 128103, 94727}},
+{20961, 18, 127165, {1, 3, 5, 15, 17, 51, 71, 21, 237, 65, 901, 3365, 7831, 3027, 8751, 14435, 79445, 172587}},
+{20962, 18, 127171, {1, 1, 5, 1, 9, 49, 49, 31, 395, 339, 343, 1813, 2607, 9347, 11239, 6761, 127623, 43459}},
+{20963, 18, 127197, {1, 1, 1, 1, 13, 23, 71, 131, 225, 229, 117, 889, 8145, 5953, 10679, 38687, 80029, 63689}},
+{20964, 18, 127198, {1, 1, 5, 1, 29, 1, 87, 181, 441, 353, 257, 335, 203, 10897, 24085, 26967, 62573, 170285}},
+{20965, 18, 127207, {1, 1, 7, 3, 3, 39, 47, 135, 353, 977, 89, 259, 6411, 5511, 10697, 57623, 27367, 108451}},
+{20966, 18, 127226, {1, 3, 3, 11, 9, 57, 95, 211, 237, 281, 1703, 2107, 2179, 3411, 32621, 5387, 29971, 102889}},
+{20967, 18, 127240, {1, 1, 1, 13, 27, 49, 47, 49, 413, 985, 649, 1245, 807, 13637, 21741, 32565, 80135, 127971}},
+{20968, 18, 127254, {1, 3, 7, 13, 3, 19, 57, 97, 493, 597, 135, 1689, 5011, 4579, 6093, 28341, 37279, 142197}},
+{20969, 18, 127269, {1, 3, 1, 15, 15, 31, 3, 89, 327, 107, 827, 1111, 261, 6211, 4359, 38553, 43297, 75057}},
+{20970, 18, 127305, {1, 1, 1, 9, 19, 19, 53, 195, 141, 297, 141, 3859, 4173, 12243, 31399, 6353, 110505, 172219}},
+{20971, 18, 127323, {1, 3, 3, 9, 31, 51, 59, 53, 55, 723, 1575, 3399, 8057, 12317, 8393, 1719, 96987, 228955}},
+{20972, 18, 127342, {1, 1, 7, 11, 19, 59, 41, 9, 217, 267, 629, 2977, 4515, 463, 31773, 61765, 78827, 51331}},
+{20973, 18, 127347, {1, 3, 3, 13, 9, 55, 51, 177, 183, 431, 555, 3573, 7977, 3067, 21111, 12971, 78283, 260721}},
+{20974, 18, 127363, {1, 1, 1, 11, 27, 5, 89, 69, 435, 199, 221, 1017, 7703, 7469, 7755, 46319, 37941, 55285}},
+{20975, 18, 127394, {1, 1, 7, 13, 19, 55, 53, 207, 367, 177, 1483, 2857, 3753, 5493, 13349, 14033, 7933, 93457}},
+{20976, 18, 127426, {1, 1, 7, 3, 27, 35, 19, 223, 341, 137, 1195, 1263, 5937, 13517, 55, 6391, 106173, 176503}},
+{20977, 18, 127432, {1, 3, 7, 11, 23, 25, 37, 103, 351, 945, 1205, 2543, 3875, 155, 27777, 36647, 47979, 25113}},
+{20978, 18, 127440, {1, 1, 3, 15, 25, 59, 79, 39, 17, 553, 1119, 3353, 2619, 3851, 5945, 47501, 17369, 89355}},
+{20979, 18, 127462, {1, 1, 1, 13, 9, 55, 13, 173, 207, 925, 1855, 1871, 7851, 1361, 20117, 51677, 77703, 51309}},
+{20980, 18, 127468, {1, 3, 1, 1, 31, 57, 3, 25, 329, 927, 1683, 1447, 6853, 103, 9549, 21393, 415, 122749}},
+{20981, 18, 127473, {1, 1, 5, 5, 31, 61, 31, 213, 85, 531, 931, 999, 1189, 5189, 15127, 47799, 70769, 81901}},
+{20982, 18, 127486, {1, 1, 3, 1, 5, 59, 89, 53, 105, 761, 313, 3013, 4093, 9595, 4287, 51505, 20095, 232933}},
+{20983, 18, 127502, {1, 1, 7, 7, 23, 9, 41, 29, 399, 395, 759, 2541, 2373, 15365, 12083, 49579, 34401, 168121}},
+{20984, 18, 127510, {1, 1, 3, 1, 7, 23, 37, 183, 205, 377, 1081, 1081, 7767, 363, 14571, 16265, 18267, 102155}},
+{20985, 18, 127523, {1, 3, 3, 15, 19, 11, 59, 59, 465, 437, 965, 3707, 3505, 14785, 23605, 12505, 130607, 40693}},
+{20986, 18, 127543, {1, 1, 3, 13, 5, 15, 91, 33, 235, 215, 1997, 2035, 7407, 3203, 27143, 14007, 96411, 593}},
+{20987, 18, 127567, {1, 3, 7, 1, 19, 51, 1, 69, 489, 629, 1731, 393, 6807, 10521, 23971, 45649, 105183, 207351}},
+{20988, 18, 127570, {1, 3, 5, 3, 5, 41, 89, 141, 469, 177, 109, 2439, 7155, 2083, 31993, 13933, 100557, 137255}},
+{20989, 18, 127585, {1, 1, 7, 15, 21, 45, 41, 197, 365, 177, 61, 811, 2535, 5219, 3689, 53129, 42063, 60759}},
+{20990, 18, 127588, {1, 3, 5, 1, 23, 7, 19, 193, 253, 793, 539, 3747, 2611, 16211, 17199, 14875, 95377, 6999}},
+{20991, 18, 127619, {1, 1, 3, 5, 9, 5, 9, 129, 217, 473, 151, 3053, 6981, 8075, 32121, 31995, 41271, 208927}},
+{20992, 18, 127621, {1, 1, 5, 9, 9, 9, 89, 139, 381, 937, 1937, 1879, 8191, 2237, 25629, 51471, 87639, 173697}},
+{20993, 18, 127626, {1, 1, 5, 9, 17, 35, 81, 223, 161, 315, 139, 2597, 2599, 16191, 2567, 54947, 8603, 121589}},
+{20994, 18, 127628, {1, 1, 5, 5, 9, 7, 33, 49, 49, 723, 1013, 1055, 4025, 1471, 30081, 17475, 127931, 63723}},
+{20995, 18, 127640, {1, 3, 7, 7, 9, 49, 107, 17, 335, 119, 1959, 3613, 8129, 11033, 12197, 23803, 112595, 131655}},
+{20996, 18, 127662, {1, 3, 5, 11, 3, 45, 91, 17, 181, 1005, 985, 3045, 853, 8181, 5517, 48515, 16225, 237151}},
+{20997, 18, 127684, {1, 1, 3, 1, 3, 63, 35, 135, 61, 383, 1233, 675, 151, 2157, 18711, 37113, 40353, 61783}},
+{20998, 18, 127687, {1, 3, 5, 5, 29, 3, 105, 11, 351, 761, 165, 911, 6903, 10111, 1779, 24601, 3177, 110301}},
+{20999, 18, 127693, {1, 1, 3, 15, 25, 19, 73, 237, 263, 161, 731, 3853, 7705, 14497, 30799, 32979, 100729, 21761}},
+{21000, 18, 127696, {1, 1, 3, 5, 27, 9, 3, 149, 207, 715, 1435, 2563, 2451, 7951, 26313, 55115, 99423, 231639}},
+{21001, 18, 127708, {1, 1, 5, 15, 11, 51, 13, 47, 311, 969, 2013, 357, 4847, 1831, 2235, 22779, 32375, 40893}},
+{21002, 18, 127711, {1, 1, 3, 9, 21, 45, 11, 99, 275, 849, 443, 1257, 7855, 9121, 6549, 20289, 101337, 13869}},
+{21003, 18, 127722, {1, 1, 1, 15, 25, 27, 15, 111, 215, 437, 1923, 1985, 4603, 15469, 6667, 17941, 50433, 152759}},
+{21004, 18, 127732, {1, 3, 7, 15, 7, 37, 119, 53, 337, 853, 1785, 3507, 3743, 14303, 22757, 5149, 1539, 227051}},
+{21005, 18, 127747, {1, 1, 3, 13, 11, 23, 55, 19, 495, 531, 1021, 3831, 5993, 15819, 2121, 52773, 19775, 94643}},
+{21006, 18, 127767, {1, 1, 3, 3, 23, 55, 55, 69, 457, 755, 1187, 3993, 613, 12691, 1779, 21251, 2293, 236725}},
+{21007, 18, 127771, {1, 1, 5, 9, 23, 27, 61, 125, 113, 99, 503, 699, 6873, 13141, 10649, 65209, 21773, 162749}},
+{21008, 18, 127790, {1, 1, 1, 11, 15, 27, 111, 227, 493, 361, 1071, 607, 1409, 9281, 24515, 26739, 82421, 30463}},
+{21009, 18, 127816, {1, 3, 5, 1, 11, 57, 23, 239, 265, 675, 441, 4031, 5163, 15729, 2741, 26037, 32533, 140645}},
+{21010, 18, 127824, {1, 3, 3, 7, 3, 45, 105, 135, 493, 579, 1707, 2933, 1135, 11891, 3171, 45401, 24993, 175681}},
+{21011, 18, 127833, {1, 1, 1, 11, 11, 3, 67, 213, 483, 9, 1053, 213, 3205, 8487, 16093, 7305, 122591, 31811}},
+{21012, 18, 127869, {1, 1, 5, 13, 19, 31, 13, 65, 29, 929, 343, 463, 1885, 13467, 14997, 22737, 42869, 128239}},
+{21013, 18, 127910, {1, 3, 3, 13, 9, 47, 125, 33, 475, 285, 1901, 2525, 305, 11587, 27309, 30037, 70681, 180425}},
+{21014, 18, 127928, {1, 3, 5, 15, 9, 37, 45, 149, 19, 135, 555, 4037, 5173, 12473, 983, 40923, 28561, 185941}},
+{21015, 18, 127933, {1, 3, 3, 9, 23, 35, 35, 151, 113, 885, 1553, 2233, 351, 4071, 28127, 26109, 12299, 163973}},
+{21016, 18, 127963, {1, 3, 3, 11, 17, 55, 125, 87, 315, 917, 383, 2397, 1573, 9255, 10499, 16051, 99487, 139415}},
+{21017, 18, 127975, {1, 1, 3, 1, 29, 21, 101, 153, 5, 705, 1965, 1447, 8163, 13547, 25929, 28569, 57897, 173229}},
+{21018, 18, 128016, {1, 1, 7, 15, 3, 37, 113, 213, 495, 935, 529, 2299, 6901, 1765, 4255, 14579, 14175, 112333}},
+{21019, 18, 128031, {1, 3, 3, 9, 11, 53, 89, 27, 461, 235, 1525, 3533, 3061, 4351, 12847, 21649, 10843, 60901}},
+{21020, 18, 128059, {1, 1, 5, 1, 17, 11, 17, 157, 387, 887, 2017, 3641, 923, 12659, 19691, 18657, 3127, 218819}},
+{21021, 18, 128074, {1, 3, 1, 9, 5, 3, 49, 215, 379, 765, 1375, 345, 2285, 8197, 9531, 6725, 22475, 203883}},
+{21022, 18, 128107, {1, 1, 3, 9, 19, 41, 13, 233, 97, 755, 249, 2011, 5815, 6317, 4121, 63637, 43353, 154753}},
+{21023, 18, 128122, {1, 3, 7, 15, 31, 25, 93, 197, 455, 979, 1805, 2619, 803, 5705, 1679, 29317, 66477, 159187}},
+{21024, 18, 128157, {1, 1, 1, 13, 11, 25, 61, 233, 339, 171, 559, 427, 3239, 8889, 3711, 19743, 18099, 49201}},
+{21025, 18, 128161, {1, 3, 7, 13, 19, 5, 9, 183, 355, 137, 1767, 1113, 1149, 5791, 4099, 37911, 75945, 115397}},
+{21026, 18, 128200, {1, 1, 3, 13, 27, 25, 121, 3, 337, 195, 1841, 2009, 4181, 3197, 20275, 42493, 7495, 24407}},
+{21027, 18, 128213, {1, 1, 1, 15, 3, 43, 39, 25, 57, 829, 565, 1977, 4027, 11053, 13961, 13965, 4207, 1663}},
+{21028, 18, 128229, {1, 3, 5, 9, 11, 7, 107, 205, 479, 961, 1549, 1701, 6305, 15419, 23331, 46443, 55171, 235109}},
+{21029, 18, 128233, {1, 3, 5, 5, 19, 3, 39, 211, 429, 363, 765, 283, 2469, 1947, 10481, 1969, 95545, 187671}},
+{21030, 18, 128241, {1, 1, 1, 1, 11, 55, 47, 121, 251, 63, 767, 3673, 3233, 14865, 25713, 48443, 79139, 225021}},
+{21031, 18, 128259, {1, 1, 3, 11, 25, 35, 57, 103, 385, 155, 173, 4023, 489, 1733, 14423, 61843, 24793, 9871}},
+{21032, 18, 128295, {1, 3, 1, 15, 9, 29, 99, 187, 471, 877, 1321, 2489, 7439, 4259, 32703, 1459, 42093, 261097}},
+{21033, 18, 128299, {1, 1, 3, 11, 9, 25, 113, 251, 337, 405, 847, 2451, 5649, 3449, 11703, 18271, 108005, 208789}},
+{21034, 18, 128313, {1, 3, 3, 7, 13, 53, 61, 251, 461, 461, 1557, 1215, 6731, 13349, 21003, 11573, 66751, 79733}},
+{21035, 18, 128345, {1, 1, 5, 1, 23, 49, 101, 175, 251, 577, 1667, 2561, 6545, 16305, 18457, 65067, 35843, 123445}},
+{21036, 18, 128362, {1, 1, 5, 3, 7, 9, 61, 107, 395, 137, 559, 2315, 2559, 11929, 4843, 41661, 61361, 146163}},
+{21037, 18, 128375, {1, 3, 1, 5, 1, 3, 43, 251, 329, 289, 323, 2201, 4129, 4963, 27477, 18743, 46551, 93061}},
+{21038, 18, 128376, {1, 1, 7, 3, 17, 63, 21, 159, 447, 377, 69, 2517, 8181, 6043, 3039, 7747, 72465, 41027}},
+{21039, 18, 128406, {1, 1, 1, 1, 13, 3, 45, 93, 391, 509, 867, 1561, 5017, 11851, 24891, 22531, 18993, 129421}},
+{21040, 18, 128410, {1, 3, 3, 11, 15, 1, 127, 9, 161, 321, 2003, 239, 1379, 11903, 13503, 26529, 57725, 214797}},
+{21041, 18, 128416, {1, 1, 1, 13, 31, 11, 17, 25, 1, 645, 675, 735, 2083, 1919, 18977, 4995, 91559, 230463}},
+{21042, 18, 128443, {1, 3, 1, 13, 17, 21, 107, 167, 135, 797, 715, 3275, 5437, 4253, 11671, 14867, 36041, 71751}},
+{21043, 18, 128451, {1, 3, 5, 5, 11, 49, 93, 231, 431, 567, 1605, 3281, 7049, 2947, 863, 39593, 117167, 167301}},
+{21044, 18, 128465, {1, 1, 1, 1, 5, 13, 61, 91, 127, 189, 1879, 3921, 4303, 4831, 6765, 31005, 107627, 80693}},
+{21045, 18, 128466, {1, 3, 1, 3, 1, 49, 61, 9, 467, 891, 105, 317, 137, 12789, 12367, 57455, 39777, 88047}},
+{21046, 18, 128484, {1, 1, 3, 13, 23, 63, 37, 103, 23, 223, 647, 2523, 3211, 14551, 22663, 48237, 54777, 180297}},
+{21047, 18, 128499, {1, 3, 3, 7, 29, 51, 85, 179, 441, 431, 535, 2975, 8083, 8619, 30229, 31421, 54063, 163601}},
+{21048, 18, 128502, {1, 3, 1, 1, 27, 39, 125, 171, 57, 729, 511, 957, 7541, 2347, 1669, 32323, 108531, 69943}},
+{21049, 18, 128524, {1, 3, 3, 7, 1, 33, 89, 245, 95, 21, 699, 1441, 2659, 501, 32323, 39145, 82311, 155479}},
+{21050, 18, 128536, {1, 1, 3, 11, 29, 13, 87, 251, 329, 667, 325, 2411, 7959, 8069, 20817, 42445, 121675, 113421}},
+{21051, 18, 128541, {1, 1, 1, 7, 9, 57, 109, 237, 325, 535, 89, 1285, 5649, 13673, 29375, 51553, 81723, 11003}},
+{21052, 18, 128542, {1, 3, 1, 1, 13, 5, 31, 109, 157, 817, 1303, 725, 1841, 5503, 2255, 34637, 93603, 82825}},
+{21053, 18, 128592, {1, 3, 7, 7, 5, 33, 39, 233, 217, 157, 357, 2727, 3565, 1539, 5317, 23967, 30375, 260381}},
+{21054, 18, 128598, {1, 1, 5, 3, 23, 51, 45, 181, 353, 519, 949, 3043, 1517, 3387, 15081, 5997, 31523, 80007}},
+{21055, 18, 128623, {1, 1, 3, 5, 23, 21, 83, 51, 275, 629, 1433, 1821, 3761, 2367, 32089, 13813, 99629, 64603}},
+{21056, 18, 128632, {1, 1, 5, 15, 11, 49, 69, 197, 193, 459, 1915, 787, 3631, 5219, 11109, 12311, 56625, 117439}},
+{21057, 18, 128671, {1, 3, 3, 3, 31, 29, 57, 27, 43, 231, 777, 2139, 2609, 12273, 23777, 4151, 51749, 110013}},
+{21058, 18, 128713, {1, 1, 5, 13, 9, 63, 83, 69, 225, 913, 99, 1167, 5279, 14163, 3979, 55151, 84387, 234583}},
+{21059, 18, 128724, {1, 1, 7, 5, 9, 57, 87, 23, 335, 403, 1843, 725, 5187, 4137, 24299, 44807, 98523, 217815}},
+{21060, 18, 128731, {1, 3, 3, 3, 3, 23, 115, 229, 193, 655, 1205, 3159, 1935, 113, 20943, 32917, 69633, 2133}},
+{21061, 18, 128761, {1, 3, 3, 1, 17, 5, 59, 139, 75, 185, 1951, 3689, 4997, 2761, 8673, 41783, 75075, 101063}},
+{21062, 18, 128767, {1, 3, 1, 13, 1, 51, 63, 127, 67, 743, 1049, 2055, 4249, 131, 8153, 50237, 28135, 76059}},
+{21063, 18, 128782, {1, 3, 7, 13, 5, 39, 83, 63, 429, 573, 1915, 3801, 2223, 1585, 16997, 45571, 23311, 108099}},
+{21064, 18, 128793, {1, 3, 1, 3, 15, 49, 19, 65, 433, 401, 1901, 3653, 2399, 15171, 9695, 30257, 104877, 181221}},
+{21065, 18, 128805, {1, 3, 1, 1, 25, 37, 89, 7, 81, 343, 949, 3535, 1681, 10089, 23513, 3897, 127083, 214005}},
+{21066, 18, 128820, {1, 3, 7, 13, 1, 1, 123, 89, 433, 541, 1579, 931, 3459, 11095, 20729, 13117, 59323, 90309}},
+{21067, 18, 128830, {1, 1, 7, 1, 19, 9, 31, 211, 271, 25, 1053, 2249, 6549, 12785, 16947, 55633, 70155, 253741}},
+{21068, 18, 128842, {1, 3, 5, 9, 7, 49, 11, 251, 101, 795, 1015, 2037, 1239, 10151, 22179, 749, 2373, 224517}},
+{21069, 18, 128852, {1, 3, 7, 15, 21, 19, 15, 59, 439, 621, 1081, 3041, 1587, 3077, 2319, 51135, 110513, 222551}},
+{21070, 18, 128859, {1, 1, 5, 5, 9, 61, 49, 97, 361, 647, 351, 1977, 3023, 10213, 6889, 8753, 72203, 37521}},
+{21071, 18, 128866, {1, 3, 3, 1, 7, 29, 51, 117, 259, 81, 1263, 1829, 6541, 5699, 30367, 61325, 78795, 3491}},
+{21072, 18, 128875, {1, 1, 1, 5, 5, 23, 19, 255, 267, 251, 239, 3561, 6771, 10647, 4129, 40285, 11041, 27023}},
+{21073, 18, 128892, {1, 1, 7, 5, 29, 17, 121, 91, 427, 51, 243, 1617, 5389, 3633, 14105, 5329, 109507, 93719}},
+{21074, 18, 128896, {1, 3, 7, 5, 7, 59, 107, 89, 181, 719, 1029, 585, 2415, 9175, 11605, 9271, 12105, 42503}},
+{21075, 18, 128914, {1, 3, 5, 15, 27, 15, 83, 223, 489, 901, 1823, 1515, 6295, 12509, 27179, 181, 29813, 66163}},
+{21076, 18, 128935, {1, 1, 7, 15, 5, 9, 79, 29, 201, 391, 609, 935, 4025, 201, 8333, 24557, 33739, 257979}},
+{21077, 18, 128964, {1, 3, 3, 9, 9, 19, 55, 211, 347, 943, 559, 467, 1363, 10249, 7109, 41293, 28035, 205889}},
+{21078, 18, 128973, {1, 1, 5, 3, 21, 25, 25, 163, 95, 119, 789, 1679, 3845, 1427, 25531, 13375, 121029, 194845}},
+{21079, 18, 129001, {1, 1, 5, 3, 31, 21, 83, 27, 17, 59, 885, 3889, 4795, 4383, 28739, 55129, 10387, 176437}},
+{21080, 18, 129007, {1, 3, 1, 5, 31, 39, 37, 79, 433, 313, 1155, 3025, 6141, 10695, 27819, 28227, 32161, 250515}},
+{21081, 18, 129012, {1, 1, 5, 9, 27, 41, 3, 129, 235, 621, 1171, 3305, 6309, 5323, 15049, 16301, 13817, 238521}},
+{21082, 18, 129021, {1, 3, 7, 7, 27, 31, 63, 143, 183, 625, 1627, 3093, 6597, 14089, 30197, 60411, 66221, 221691}},
+{21083, 18, 129026, {1, 3, 7, 13, 21, 15, 59, 67, 441, 113, 1229, 1587, 5889, 6691, 10641, 11865, 89791, 82867}},
+{21084, 18, 129055, {1, 1, 7, 9, 13, 21, 53, 145, 235, 877, 2005, 1005, 7137, 6091, 19611, 25959, 124019, 216269}},
+{21085, 18, 129071, {1, 3, 7, 9, 17, 63, 5, 245, 397, 351, 1613, 4079, 7235, 4397, 18951, 11609, 71593, 148615}},
+{21086, 18, 129093, {1, 3, 3, 11, 5, 59, 65, 221, 237, 527, 861, 397, 249, 15273, 8415, 61185, 59419, 98115}},
+{21087, 18, 129105, {1, 1, 3, 5, 5, 59, 17, 247, 3, 765, 835, 1131, 3985, 9021, 18067, 28525, 86513, 250227}},
+{21088, 18, 129124, {1, 3, 7, 15, 25, 47, 119, 143, 143, 283, 1791, 59, 8171, 12577, 17079, 9809, 100299, 63977}},
+{21089, 18, 129148, {1, 3, 5, 13, 1, 47, 93, 159, 199, 863, 1279, 77, 4719, 3623, 30713, 39271, 126299, 130297}},
+{21090, 18, 129151, {1, 1, 5, 3, 23, 11, 119, 187, 57, 373, 747, 1507, 5165, 12929, 903, 49041, 70215, 117113}},
+{21091, 18, 129155, {1, 1, 5, 1, 3, 59, 23, 77, 151, 77, 627, 2865, 7055, 10469, 12095, 20481, 13429, 47573}},
+{21092, 18, 129161, {1, 3, 1, 13, 27, 13, 115, 233, 343, 407, 1321, 4011, 5589, 15369, 23495, 4435, 75421, 229325}},
+{21093, 18, 129200, {1, 3, 3, 3, 5, 51, 89, 53, 275, 279, 203, 2829, 4415, 4735, 25417, 17633, 99445, 183945}},
+{21094, 18, 129224, {1, 3, 3, 15, 7, 9, 91, 63, 143, 945, 453, 4001, 3943, 7285, 9359, 27507, 8571, 31827}},
+{21095, 18, 129230, {1, 3, 3, 11, 15, 49, 103, 25, 273, 791, 145, 2203, 4721, 7709, 25085, 33937, 98693, 97445}},
+{21096, 18, 129237, {1, 1, 5, 15, 9, 13, 87, 27, 331, 137, 1031, 585, 7841, 12213, 32259, 46953, 17813, 203379}},
+{21097, 18, 129298, {1, 3, 1, 5, 29, 53, 121, 179, 21, 311, 991, 2145, 6577, 12889, 8763, 46629, 128093, 105033}},
+{21098, 18, 129300, {1, 3, 1, 9, 7, 29, 57, 137, 333, 109, 615, 749, 2665, 13087, 13989, 41857, 102937, 125183}},
+{21099, 18, 129316, {1, 1, 5, 5, 3, 23, 107, 5, 319, 503, 1209, 47, 349, 11681, 28521, 44707, 112887, 232275}},
+{21100, 18, 129345, {1, 3, 3, 13, 13, 51, 13, 5, 293, 15, 555, 135, 2565, 13325, 30411, 14837, 65591, 249205}},
+{21101, 18, 129351, {1, 3, 5, 13, 17, 3, 73, 255, 447, 699, 503, 3655, 7735, 12163, 6167, 15027, 103831, 146395}},
+{21102, 18, 129352, {1, 3, 1, 13, 5, 9, 27, 45, 397, 463, 1739, 3193, 6731, 7533, 11217, 22359, 82603, 231613}},
+{21103, 18, 129363, {1, 1, 3, 15, 5, 43, 73, 191, 53, 187, 1905, 745, 1571, 9013, 8515, 59527, 104671, 227063}},
+{21104, 18, 129393, {1, 1, 3, 1, 5, 47, 57, 179, 433, 979, 147, 1701, 4019, 6855, 24487, 65495, 69919, 6659}},
+{21105, 18, 129410, {1, 3, 3, 1, 17, 17, 13, 75, 163, 781, 421, 1573, 2519, 9243, 20693, 60909, 65661, 208125}},
+{21106, 18, 129415, {1, 3, 5, 7, 27, 57, 39, 79, 157, 415, 729, 3651, 3581, 9443, 6409, 45993, 99051, 140977}},
+{21107, 18, 129449, {1, 3, 3, 13, 1, 7, 109, 77, 423, 185, 97, 3719, 2355, 10593, 2421, 37339, 24961, 24305}},
+{21108, 18, 129477, {1, 3, 5, 13, 17, 7, 125, 43, 453, 43, 643, 3757, 3721, 16083, 20871, 26451, 95201, 29153}},
+{21109, 18, 129501, {1, 1, 7, 3, 13, 49, 99, 253, 59, 21, 445, 3677, 6683, 2165, 32367, 55249, 5991, 155033}},
+{21110, 18, 129518, {1, 1, 3, 9, 21, 9, 15, 219, 175, 631, 665, 2455, 4701, 10639, 13907, 26937, 58867, 259861}},
+{21111, 18, 129520, {1, 3, 5, 5, 23, 5, 39, 233, 27, 811, 1435, 625, 4703, 3699, 20763, 50047, 123875, 10129}},
+{21112, 18, 129545, {1, 1, 7, 5, 23, 1, 49, 223, 309, 691, 953, 575, 5279, 10515, 11519, 35387, 48417, 134001}},
+{21113, 18, 129563, {1, 1, 7, 11, 3, 15, 125, 109, 39, 713, 1823, 1613, 4347, 6839, 29511, 26865, 102077, 31425}},
+{21114, 18, 129594, {1, 1, 1, 7, 31, 43, 13, 221, 115, 993, 1155, 1641, 1063, 2065, 18909, 45769, 65331, 188455}},
+{21115, 18, 129608, {1, 1, 7, 13, 21, 9, 59, 7, 79, 217, 2009, 667, 7685, 14761, 20149, 44133, 41037, 78369}},
+{21116, 18, 129616, {1, 3, 1, 9, 23, 57, 1, 193, 77, 681, 1135, 3657, 8149, 3559, 25011, 55027, 121903, 240157}},
+{21117, 18, 129652, {1, 3, 3, 5, 31, 41, 59, 5, 159, 627, 1569, 23, 2311, 2239, 20811, 54931, 130949, 193071}},
+{21118, 18, 129659, {1, 1, 1, 1, 27, 45, 43, 1, 381, 801, 451, 1361, 1611, 5379, 27819, 8949, 4953, 222335}},
+{21119, 18, 129680, {1, 1, 7, 7, 7, 11, 101, 17, 197, 561, 297, 159, 7443, 7273, 819, 23487, 24927, 151781}},
+{21120, 18, 129692, {1, 3, 1, 3, 15, 43, 119, 193, 205, 835, 7, 689, 8045, 11167, 19521, 65075, 87265, 53669}},
+{21121, 18, 129738, {1, 3, 7, 7, 9, 51, 43, 209, 239, 415, 995, 4037, 1219, 2683, 30459, 36161, 111157, 184551}},
+{21122, 18, 129764, {1, 3, 7, 11, 27, 3, 81, 43, 407, 463, 231, 3545, 2691, 5235, 22053, 37233, 98757, 149111}},
+{21123, 18, 129782, {1, 3, 1, 5, 17, 25, 47, 185, 487, 403, 1063, 1445, 4457, 15443, 11693, 54823, 131001, 9813}},
+{21124, 18, 129793, {1, 3, 5, 3, 5, 35, 127, 253, 173, 491, 133, 3575, 1981, 12735, 26021, 61615, 74615, 159829}},
+{21125, 18, 129820, {1, 1, 5, 9, 13, 37, 67, 155, 317, 389, 603, 4061, 3527, 9315, 32331, 43145, 82511, 240133}},
+{21126, 18, 129824, {1, 1, 5, 1, 21, 41, 89, 3, 61, 627, 1301, 2073, 447, 8139, 2509, 52075, 50687, 240239}},
+{21127, 18, 129829, {1, 3, 7, 13, 25, 61, 117, 107, 175, 7, 1173, 561, 5777, 10525, 20713, 34987, 48005, 214361}},
+{21128, 18, 129848, {1, 3, 7, 15, 25, 31, 127, 147, 177, 881, 95, 2115, 4765, 10485, 9253, 721, 193, 222459}},
+{21129, 18, 129854, {1, 3, 5, 3, 3, 13, 47, 77, 441, 1001, 215, 2365, 3603, 405, 11401, 14523, 65755, 258229}},
+{21130, 18, 129861, {1, 1, 3, 9, 19, 29, 71, 153, 77, 613, 1815, 2033, 1821, 15497, 18805, 28851, 88247, 143115}},
+{21131, 18, 129879, {1, 3, 1, 11, 21, 19, 37, 35, 427, 887, 1977, 1961, 3619, 10739, 30115, 55937, 102045, 110929}},
+{21132, 18, 129886, {1, 3, 3, 13, 21, 27, 49, 15, 405, 629, 2015, 867, 2121, 13789, 19225, 22343, 105629, 123113}},
+{21133, 18, 129907, {1, 1, 1, 1, 17, 19, 55, 207, 507, 1001, 1753, 315, 2799, 8643, 1519, 4057, 16599, 222223}},
+{21134, 18, 129949, {1, 1, 5, 7, 21, 37, 63, 53, 103, 261, 595, 389, 6041, 11127, 23625, 61683, 80953, 255891}},
+{21135, 18, 129953, {1, 1, 1, 5, 25, 21, 81, 233, 79, 57, 1311, 3965, 7747, 687, 32149, 397, 4551, 37657}},
+{21136, 18, 129980, {1, 1, 1, 5, 9, 19, 87, 67, 325, 157, 317, 591, 1401, 8275, 20413, 39529, 75349, 183679}},
+{21137, 18, 129998, {1, 3, 3, 15, 9, 3, 83, 205, 195, 599, 829, 3109, 3705, 13991, 8781, 41555, 31689, 86933}},
+{21138, 18, 130031, {1, 3, 5, 1, 3, 9, 37, 235, 271, 883, 561, 1473, 7693, 177, 14113, 19507, 75221, 67517}},
+{21139, 18, 130043, {1, 1, 1, 9, 7, 29, 87, 189, 239, 429, 537, 1657, 6373, 2449, 17621, 19649, 77235, 102775}},
+{21140, 18, 130057, {1, 1, 7, 7, 1, 43, 69, 207, 241, 561, 1809, 3119, 4657, 15797, 18751, 52169, 105005, 172657}},
+{21141, 18, 130065, {1, 1, 7, 5, 5, 59, 67, 231, 27, 435, 1073, 2689, 229, 733, 1579, 52289, 110285, 76721}},
+{21142, 18, 130087, {1, 3, 5, 9, 31, 19, 87, 41, 489, 705, 1363, 963, 5865, 8237, 10295, 43169, 81561, 177209}},
+{21143, 18, 130091, {1, 3, 3, 1, 25, 39, 63, 255, 403, 625, 1601, 71, 6609, 4165, 21987, 31269, 25473, 17063}},
+{21144, 18, 130096, {1, 3, 3, 11, 19, 13, 101, 245, 17, 687, 1037, 3345, 7257, 13081, 5131, 29003, 72319, 223505}},
+{21145, 18, 130101, {1, 3, 3, 3, 11, 49, 107, 29, 463, 465, 977, 4007, 2121, 4821, 1465, 53725, 36783, 247057}},
+{21146, 18, 130111, {1, 1, 1, 3, 1, 43, 71, 49, 261, 965, 1041, 3951, 3791, 2503, 26009, 52039, 4639, 141281}},
+{21147, 18, 130126, {1, 1, 3, 5, 29, 45, 79, 33, 119, 491, 1403, 1637, 853, 5609, 29853, 16435, 117877, 58443}},
+{21148, 18, 130137, {1, 1, 3, 5, 13, 17, 109, 187, 201, 705, 235, 1485, 7673, 6335, 3341, 20451, 64697, 129519}},
+{21149, 18, 130138, {1, 1, 7, 13, 11, 41, 95, 81, 135, 783, 1293, 2095, 3599, 10175, 3205, 56915, 131, 19281}},
+{21150, 18, 130149, {1, 3, 5, 9, 13, 19, 53, 223, 283, 733, 1915, 3029, 2779, 8133, 28163, 37263, 91245, 1927}},
+{21151, 18, 130177, {1, 3, 3, 3, 1, 55, 41, 123, 209, 195, 1423, 2467, 3809, 11169, 23593, 8703, 40975, 175651}},
+{21152, 18, 130180, {1, 3, 7, 9, 31, 57, 31, 115, 415, 445, 557, 3971, 1565, 15223, 7799, 10463, 117387, 225127}},
+{21153, 18, 130214, {1, 3, 5, 11, 31, 19, 3, 63, 315, 501, 903, 1925, 3393, 16149, 11013, 15483, 70765, 279}},
+{21154, 18, 130228, {1, 3, 3, 9, 29, 21, 13, 227, 263, 815, 1259, 2549, 955, 9237, 16083, 38891, 31145, 731}},
+{21155, 18, 130240, {1, 3, 3, 5, 27, 23, 33, 189, 107, 655, 889, 1549, 7315, 13341, 12721, 59339, 54503, 91679}},
+{21156, 18, 130267, {1, 3, 7, 5, 15, 9, 1, 255, 451, 91, 1279, 2359, 5913, 5215, 23161, 29327, 45275, 206709}},
+{21157, 18, 130280, {1, 3, 3, 9, 9, 41, 75, 91, 87, 695, 335, 3375, 7307, 14095, 5359, 7815, 9339, 46387}},
+{21158, 18, 130294, {1, 1, 3, 15, 5, 47, 69, 231, 423, 255, 1335, 3395, 2799, 8955, 31445, 59849, 104955, 240587}},
+{21159, 18, 130306, {1, 3, 5, 7, 7, 9, 21, 209, 321, 5, 653, 2199, 3657, 6397, 20229, 32349, 54543, 47971}},
+{21160, 18, 130325, {1, 3, 7, 11, 31, 21, 85, 49, 197, 865, 53, 609, 1867, 14503, 12671, 61703, 39245, 8493}},
+{21161, 18, 130398, {1, 3, 1, 13, 27, 31, 119, 247, 209, 65, 1729, 1563, 1597, 1617, 26597, 50139, 108667, 77035}},
+{21162, 18, 130402, {1, 1, 5, 13, 3, 49, 53, 219, 71, 1013, 1239, 3725, 117, 9273, 8277, 32619, 45933, 71509}},
+{21163, 18, 130421, {1, 3, 7, 13, 1, 3, 119, 153, 79, 555, 429, 1221, 3725, 6073, 1295, 7187, 117709, 258911}},
+{21164, 18, 130438, {1, 3, 3, 13, 1, 13, 105, 185, 81, 989, 563, 3761, 6725, 4699, 10539, 50247, 95307, 211927}},
+{21165, 18, 130441, {1, 3, 7, 3, 21, 11, 45, 81, 495, 391, 1437, 3495, 3789, 13701, 9479, 42505, 22561, 135019}},
+{21166, 18, 130475, {1, 3, 3, 11, 7, 61, 65, 211, 269, 997, 385, 3843, 4905, 2939, 28551, 19515, 25177, 68137}},
+{21167, 18, 130486, {1, 1, 3, 3, 3, 47, 73, 127, 15, 977, 209, 1791, 4711, 6733, 29093, 36311, 13665, 240603}},
+{21168, 18, 130503, {1, 3, 5, 5, 19, 39, 29, 211, 463, 755, 1723, 397, 213, 14009, 22701, 7131, 35587, 183885}},
+{21169, 18, 130551, {1, 3, 5, 9, 11, 29, 7, 25, 381, 631, 1343, 2255, 2535, 3239, 7287, 14161, 69295, 85245}},
+{21170, 18, 130574, {1, 1, 5, 5, 17, 47, 19, 217, 289, 411, 1855, 323, 4109, 2601, 5835, 61909, 99333, 99959}},
+{21171, 18, 130602, {1, 1, 3, 11, 1, 51, 121, 207, 403, 993, 1171, 3451, 3389, 957, 22125, 9333, 110775, 54125}},
+{21172, 18, 130612, {1, 3, 5, 15, 9, 51, 13, 251, 203, 861, 321, 2017, 6933, 10785, 20089, 65213, 105451, 117319}},
+{21173, 18, 130621, {1, 3, 3, 15, 19, 63, 89, 217, 269, 723, 57, 1923, 4267, 4895, 2191, 21605, 62401, 11063}},
+{21174, 18, 130633, {1, 3, 1, 3, 21, 47, 103, 75, 167, 989, 1401, 575, 3717, 10373, 21321, 5487, 36063, 140411}},
+{21175, 18, 130684, {1, 1, 7, 15, 19, 29, 121, 197, 429, 773, 901, 1875, 291, 11395, 31459, 55041, 49263, 185143}},
+{21176, 18, 130688, {1, 3, 3, 1, 19, 17, 19, 21, 41, 885, 1665, 547, 5887, 6205, 3317, 59399, 125559, 82721}},
+{21177, 18, 130698, {1, 3, 1, 9, 15, 39, 81, 9, 279, 33, 1287, 3035, 5759, 10647, 3933, 20953, 3137, 30693}},
+{21178, 18, 130700, {1, 3, 5, 13, 3, 33, 33, 169, 233, 83, 467, 3719, 5617, 6165, 15631, 56059, 95541, 245233}},
+{21179, 18, 130712, {1, 3, 5, 13, 5, 21, 81, 9, 413, 247, 1307, 3363, 3383, 11525, 1259, 8735, 36507, 98359}},
+{21180, 18, 130739, {1, 1, 1, 13, 17, 49, 105, 131, 385, 309, 1295, 565, 8031, 15391, 31263, 52657, 102721, 212195}},
+{21181, 18, 130748, {1, 3, 1, 7, 13, 41, 21, 103, 237, 649, 55, 1565, 6327, 8743, 15457, 29975, 34165, 80839}},
+{21182, 18, 130774, {1, 3, 5, 11, 15, 31, 121, 219, 375, 159, 731, 59, 3205, 15039, 10023, 46209, 34619, 110253}},
+{21183, 18, 130783, {1, 3, 3, 11, 31, 19, 79, 185, 363, 635, 463, 987, 2681, 6405, 30077, 21173, 14213, 58095}},
+{21184, 18, 130802, {1, 1, 5, 13, 23, 37, 57, 111, 293, 553, 269, 3393, 345, 1983, 1097, 47217, 22281, 212607}},
+{21185, 18, 130811, {1, 3, 5, 7, 7, 33, 65, 61, 185, 411, 187, 641, 6437, 4625, 17547, 38941, 81119, 48651}},
+{21186, 18, 130836, {1, 1, 7, 3, 19, 25, 39, 243, 139, 465, 691, 713, 7879, 14539, 31669, 35871, 130681, 255929}},
+{21187, 18, 130840, {1, 3, 1, 1, 3, 43, 87, 13, 179, 835, 719, 1189, 7207, 5863, 6077, 20669, 35469, 211155}},
+{21188, 18, 130856, {1, 3, 7, 13, 25, 59, 97, 129, 151, 985, 739, 1919, 7729, 14057, 21721, 17603, 82797, 181319}},
+{21189, 18, 130864, {1, 1, 7, 7, 5, 3, 21, 141, 379, 257, 207, 597, 4051, 7563, 25481, 59427, 45449, 61159}},
+{21190, 18, 130873, {1, 3, 3, 9, 11, 25, 5, 29, 131, 603, 637, 189, 4033, 13099, 15219, 4447, 73501, 135795}},
+{21191, 18, 130918, {1, 3, 1, 9, 1, 49, 57, 227, 141, 543, 1499, 3525, 3127, 11191, 4071, 47003, 7431, 155137}},
+{21192, 18, 130927, {1, 3, 1, 11, 27, 31, 15, 31, 113, 135, 1251, 245, 6965, 14263, 5679, 55201, 121453, 132503}},
+{21193, 18, 130929, {1, 1, 5, 15, 7, 23, 67, 163, 57, 513, 1809, 1343, 6165, 199, 31169, 30803, 86705, 71103}},
+{21194, 18, 130958, {1, 1, 3, 1, 15, 9, 75, 143, 273, 797, 819, 4037, 2305, 4841, 15697, 41191, 38187, 174131}},
+{21195, 18, 130966, {1, 3, 7, 7, 3, 55, 65, 135, 423, 185, 299, 2221, 7987, 4223, 28183, 32273, 95941, 260297}},
+{21196, 18, 130970, {1, 1, 7, 7, 7, 11, 67, 109, 507, 673, 1555, 2537, 7553, 4659, 3945, 20839, 32539, 43053}},
+{21197, 18, 130976, {1, 1, 7, 15, 1, 47, 61, 73, 211, 397, 1785, 4063, 6461, 13725, 11299, 17565, 80063, 118271}},
+{21198, 18, 131006, {1, 1, 7, 5, 29, 27, 97, 105, 379, 153, 915, 2795, 4933, 6729, 21207, 9995, 70241, 85641}},
+{21199, 18, 131008, {1, 3, 5, 5, 23, 13, 41, 67, 127, 649, 1351, 3597, 7077, 4989, 14649, 17401, 70883, 239841}},
+{21200, 18, 131020, {1, 1, 5, 1, 19, 1, 83, 3, 425, 873, 1943, 3935, 4257, 14587, 11829, 55217, 21963, 39683}},
+{21201, 18, 131059, {1, 1, 7, 11, 15, 7, 37, 239, 337, 245, 1557, 3681, 7357, 9639, 27367, 26869, 114603, 86317}}
+};
diff --git a/intern/cycles/scene/stats.cpp b/intern/cycles/scene/stats.cpp
new file mode 100644
index 00000000000..e2b00d16593
--- /dev/null
+++ b/intern/cycles/scene/stats.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/stats.h"
+#include "scene/object.h"
+#include "util/algorithm.h"
+#include "util/foreach.h"
+#include "util/string.h"
+
+CCL_NAMESPACE_BEGIN
+
+static int kIndentNumSpaces = 2;
+
+/* Named size entry. */
+
+namespace {
+
+bool namedSizeEntryComparator(const NamedSizeEntry &a, const NamedSizeEntry &b)
+{
+ /* We sort in descending order. */
+ return a.size > b.size;
+}
+
+bool namedTimeEntryComparator(const NamedTimeEntry &a, const NamedTimeEntry &b)
+{
+ /* We sort in descending order. */
+ return a.time > b.time;
+}
+
+bool namedTimeSampleEntryComparator(const NamedNestedSampleStats &a,
+ const NamedNestedSampleStats &b)
+{
+ return a.sum_samples > b.sum_samples;
+}
+
+bool namedSampleCountPairComparator(const NamedSampleCountPair &a, const NamedSampleCountPair &b)
+{
+ return a.samples > b.samples;
+}
+
+} // namespace
+
+NamedSizeEntry::NamedSizeEntry() : name(""), size(0)
+{
+}
+
+NamedSizeEntry::NamedSizeEntry(const string &name, size_t size) : name(name), size(size)
+{
+}
+
+NamedTimeEntry::NamedTimeEntry() : name(""), time(0)
+{
+}
+
+NamedTimeEntry::NamedTimeEntry(const string &name, double time) : name(name), time(time)
+{
+}
+
+/* Named size statistics. */
+
+NamedSizeStats::NamedSizeStats() : total_size(0)
+{
+}
+
+void NamedSizeStats::add_entry(const NamedSizeEntry &entry)
+{
+ total_size += entry.size;
+ entries.push_back(entry);
+}
+
+string NamedSizeStats::full_report(int indent_level)
+{
+ const string indent(indent_level * kIndentNumSpaces, ' ');
+ const string double_indent = indent + indent;
+ string result = "";
+ result += string_printf("%sTotal memory: %s (%s)\n",
+ indent.c_str(),
+ string_human_readable_size(total_size).c_str(),
+ string_human_readable_number(total_size).c_str());
+ sort(entries.begin(), entries.end(), namedSizeEntryComparator);
+ foreach (const NamedSizeEntry &entry, entries) {
+ result += string_printf("%s%-32s %s (%s)\n",
+ double_indent.c_str(),
+ entry.name.c_str(),
+ string_human_readable_size(entry.size).c_str(),
+ string_human_readable_number(entry.size).c_str());
+ }
+ return result;
+}
+
+string NamedTimeStats::full_report(int indent_level)
+{
+ const string indent(indent_level * kIndentNumSpaces, ' ');
+ const string double_indent = indent + indent;
+ string result = "";
+ result += string_printf("%sTotal time: %fs\n", indent.c_str(), total_time);
+ sort(entries.begin(), entries.end(), namedTimeEntryComparator);
+ foreach (const NamedTimeEntry &entry, entries) {
+ result += string_printf(
+ "%s%-40s %fs\n", double_indent.c_str(), entry.name.c_str(), entry.time);
+ }
+ return result;
+}
+
+/* Named time sample statistics. */
+
+NamedNestedSampleStats::NamedNestedSampleStats() : name(""), self_samples(0), sum_samples(0)
+{
+}
+
+NamedNestedSampleStats::NamedNestedSampleStats(const string &name, uint64_t samples)
+ : name(name), self_samples(samples), sum_samples(samples)
+{
+}
+
+NamedNestedSampleStats &NamedNestedSampleStats::add_entry(const string &name_, uint64_t samples_)
+{
+ entries.push_back(NamedNestedSampleStats(name_, samples_));
+ return entries[entries.size() - 1];
+}
+
+void NamedNestedSampleStats::update_sum()
+{
+ sum_samples = self_samples;
+ foreach (NamedNestedSampleStats &entry, entries) {
+ entry.update_sum();
+ sum_samples += entry.sum_samples;
+ }
+}
+
+string NamedNestedSampleStats::full_report(int indent_level, uint64_t total_samples)
+{
+ update_sum();
+
+ if (total_samples == 0) {
+ total_samples = sum_samples;
+ }
+
+ const string indent(indent_level * kIndentNumSpaces, ' ');
+
+ const double sum_percent = 100 * ((double)sum_samples) / total_samples;
+ const double sum_seconds = sum_samples * 0.001;
+ const double self_percent = 100 * ((double)self_samples) / total_samples;
+ const double self_seconds = self_samples * 0.001;
+ string info = string_printf("%-32s: Total %3.2f%% (%.2fs), Self %3.2f%% (%.2fs)\n",
+ name.c_str(),
+ sum_percent,
+ sum_seconds,
+ self_percent,
+ self_seconds);
+ string result = indent + info;
+
+ sort(entries.begin(), entries.end(), namedTimeSampleEntryComparator);
+ foreach (NamedNestedSampleStats &entry, entries) {
+ result += entry.full_report(indent_level + 1, total_samples);
+ }
+ return result;
+}
+
+/* Named sample count pairs. */
+
+NamedSampleCountPair::NamedSampleCountPair(const ustring &name, uint64_t samples, uint64_t hits)
+ : name(name), samples(samples), hits(hits)
+{
+}
+
+NamedSampleCountStats::NamedSampleCountStats()
+{
+}
+
+void NamedSampleCountStats::add(const ustring &name, uint64_t samples, uint64_t hits)
+{
+ entry_map::iterator entry = entries.find(name);
+ if (entry != entries.end()) {
+ entry->second.samples += samples;
+ entry->second.hits += hits;
+ return;
+ }
+ entries.emplace(name, NamedSampleCountPair(name, samples, hits));
+}
+
+string NamedSampleCountStats::full_report(int indent_level)
+{
+ const string indent(indent_level * kIndentNumSpaces, ' ');
+
+ vector<NamedSampleCountPair> sorted_entries;
+ sorted_entries.reserve(entries.size());
+
+ uint64_t total_hits = 0, total_samples = 0;
+ foreach (entry_map::const_reference entry, entries) {
+ const NamedSampleCountPair &pair = entry.second;
+
+ total_hits += pair.hits;
+ total_samples += pair.samples;
+
+ sorted_entries.push_back(pair);
+ }
+ const double avg_samples_per_hit = ((double)total_samples) / total_hits;
+
+ sort(sorted_entries.begin(), sorted_entries.end(), namedSampleCountPairComparator);
+
+ string result = "";
+ foreach (const NamedSampleCountPair &entry, sorted_entries) {
+ const double seconds = entry.samples * 0.001;
+ const double relative = ((double)entry.samples) / (entry.hits * avg_samples_per_hit);
+
+ result += indent +
+ string_printf(
+ "%-32s: %.2fs (Relative cost: %.2f)\n", entry.name.c_str(), seconds, relative);
+ }
+ return result;
+}
+
+/* Mesh statistics. */
+
+MeshStats::MeshStats()
+{
+}
+
+string MeshStats::full_report(int indent_level)
+{
+ const string indent(indent_level * kIndentNumSpaces, ' ');
+ string result = "";
+ result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1);
+ return result;
+}
+
+/* Image statistics. */
+
+ImageStats::ImageStats()
+{
+}
+
+string ImageStats::full_report(int indent_level)
+{
+ const string indent(indent_level * kIndentNumSpaces, ' ');
+ string result = "";
+ result += indent + "Textures:\n" + textures.full_report(indent_level + 1);
+ return result;
+}
+
+/* Overall statistics. */
+
+RenderStats::RenderStats()
+{
+ has_profiling = false;
+}
+
+void RenderStats::collect_profiling(Scene *scene, Profiler &prof)
+{
+ has_profiling = true;
+
+ kernel = NamedNestedSampleStats("Total render time", prof.get_event(PROFILING_UNKNOWN));
+ kernel.add_entry("Ray setup", prof.get_event(PROFILING_RAY_SETUP));
+ kernel.add_entry("Intersect Closest", prof.get_event(PROFILING_INTERSECT_CLOSEST));
+ kernel.add_entry("Intersect Shadow", prof.get_event(PROFILING_INTERSECT_SHADOW));
+ kernel.add_entry("Intersect Subsurface", prof.get_event(PROFILING_INTERSECT_SUBSURFACE));
+ kernel.add_entry("Intersect Volume Stack", prof.get_event(PROFILING_INTERSECT_VOLUME_STACK));
+
+ NamedNestedSampleStats &surface = kernel.add_entry("Shade Surface", 0);
+ surface.add_entry("Setup", prof.get_event(PROFILING_SHADE_SURFACE_SETUP));
+ surface.add_entry("Shader Evaluation", prof.get_event(PROFILING_SHADE_SURFACE_EVAL));
+ surface.add_entry("Render Passes", prof.get_event(PROFILING_SHADE_SURFACE_PASSES));
+ surface.add_entry("Direct Light", prof.get_event(PROFILING_SHADE_SURFACE_DIRECT_LIGHT));
+ surface.add_entry("Indirect Light", prof.get_event(PROFILING_SHADE_SURFACE_INDIRECT_LIGHT));
+ surface.add_entry("Ambient Occlusion", prof.get_event(PROFILING_SHADE_SURFACE_AO));
+
+ NamedNestedSampleStats &volume = kernel.add_entry("Shade Volume", 0);
+ volume.add_entry("Setup", prof.get_event(PROFILING_SHADE_VOLUME_SETUP));
+ volume.add_entry("Integrate", prof.get_event(PROFILING_SHADE_VOLUME_INTEGRATE));
+ volume.add_entry("Direct Light", prof.get_event(PROFILING_SHADE_VOLUME_DIRECT_LIGHT));
+ volume.add_entry("Indirect Light", prof.get_event(PROFILING_SHADE_VOLUME_INDIRECT_LIGHT));
+
+ NamedNestedSampleStats &shadow = kernel.add_entry("Shade Shadow", 0);
+ shadow.add_entry("Setup", prof.get_event(PROFILING_SHADE_SHADOW_SETUP));
+ shadow.add_entry("Surface", prof.get_event(PROFILING_SHADE_SHADOW_SURFACE));
+ shadow.add_entry("Volume", prof.get_event(PROFILING_SHADE_SHADOW_VOLUME));
+
+ NamedNestedSampleStats &light = kernel.add_entry("Shade Light", 0);
+ light.add_entry("Setup", prof.get_event(PROFILING_SHADE_LIGHT_SETUP));
+ light.add_entry("Shader Evaluation", prof.get_event(PROFILING_SHADE_LIGHT_EVAL));
+
+ shaders.entries.clear();
+ foreach (Shader *shader, scene->shaders) {
+ uint64_t samples, hits;
+ if (prof.get_shader(shader->id, samples, hits)) {
+ shaders.add(shader->name, samples, hits);
+ }
+ }
+
+ objects.entries.clear();
+ foreach (Object *object, scene->objects) {
+ uint64_t samples, hits;
+ if (prof.get_object(object->get_device_index(), samples, hits)) {
+ objects.add(object->name, samples, hits);
+ }
+ }
+}
+
+string RenderStats::full_report()
+{
+ string result = "";
+ result += "Mesh statistics:\n" + mesh.full_report(1);
+ result += "Image statistics:\n" + image.full_report(1);
+ if (has_profiling) {
+ result += "Kernel statistics:\n" + kernel.full_report(1);
+ result += "Shader statistics:\n" + shaders.full_report(1);
+ result += "Object statistics:\n" + objects.full_report(1);
+ }
+ else {
+ result += "Profiling information not available (only works with CPU rendering)";
+ }
+ return result;
+}
+
+NamedTimeStats::NamedTimeStats() : total_time(0.0)
+{
+}
+
+string UpdateTimeStats::full_report(int indent_level)
+{
+ return times.full_report(indent_level + 1);
+}
+
+SceneUpdateStats::SceneUpdateStats()
+{
+}
+
+string SceneUpdateStats::full_report()
+{
+ string result = "";
+ result += "Scene:\n" + scene.full_report(1);
+ result += "Geometry:\n" + geometry.full_report(1);
+ result += "Light:\n" + light.full_report(1);
+ result += "Object:\n" + object.full_report(1);
+ result += "Image:\n" + image.full_report(1);
+ result += "Background:\n" + background.full_report(1);
+ result += "Bake:\n" + bake.full_report(1);
+ result += "Camera:\n" + camera.full_report(1);
+ result += "Film:\n" + film.full_report(1);
+ result += "Integrator:\n" + integrator.full_report(1);
+ result += "OSL:\n" + osl.full_report(1);
+ result += "Particles:\n" + particles.full_report(1);
+ result += "SVM:\n" + svm.full_report(1);
+ result += "Tables:\n" + tables.full_report(1);
+ result += "Procedurals:\n" + procedurals.full_report(1);
+ return result;
+}
+
+void SceneUpdateStats::clear()
+{
+ geometry.times.clear();
+ image.times.clear();
+ light.times.clear();
+ object.times.clear();
+ background.times.clear();
+ bake.times.clear();
+ camera.times.clear();
+ film.times.clear();
+ integrator.times.clear();
+ osl.times.clear();
+ particles.times.clear();
+ scene.times.clear();
+ svm.times.clear();
+ tables.times.clear();
+ procedurals.times.clear();
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/stats.h b/intern/cycles/scene/stats.h
new file mode 100644
index 00000000000..d9095acc4c9
--- /dev/null
+++ b/intern/cycles/scene/stats.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RENDER_STATS_H__
+#define __RENDER_STATS_H__
+
+#include "scene/scene.h"
+
+#include "util/stats.h"
+#include "util/string.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Named statistics entry, which corresponds to a size. There is no real
+ * semantic around the units of size, it just should be the same for all
+ * entries.
+ *
+ * This is a generic entry for all size-related statistics, which helps
+ * avoiding duplicating code for things like sorting.
+ */
+class NamedSizeEntry {
+ public:
+ NamedSizeEntry();
+ NamedSizeEntry(const string &name, size_t size);
+
+ string name;
+ size_t size;
+};
+
+class NamedTimeEntry {
+ public:
+ NamedTimeEntry();
+ NamedTimeEntry(const string &name, double time);
+
+ string name;
+ double time;
+};
+
+/* Container of named size entries. Used, for example, to store per-mesh memory
+ * usage statistics. But also keeps track of overall memory usage of the
+ * container.
+ */
+class NamedSizeStats {
+ public:
+ NamedSizeStats();
+
+ /* Add entry to the statistics. */
+ void add_entry(const NamedSizeEntry &entry);
+
+ /* Generate full human-readable report. */
+ string full_report(int indent_level = 0);
+
+ /* Total size of all entries. */
+ size_t total_size;
+
+ /* NOTE: Is fine to read directly, but for adding use add_entry(), which
+ * makes sure all accumulating values are properly updated.
+ */
+ vector<NamedSizeEntry> entries;
+};
+
+class NamedTimeStats {
+ public:
+ NamedTimeStats();
+
+ /* Add entry to the statistics. */
+ void add_entry(const NamedTimeEntry &entry)
+ {
+ total_time += entry.time;
+ entries.push_back(entry);
+ }
+
+ /* Generate full human-readable report. */
+ string full_report(int indent_level = 0);
+
+ /* Total time of all entries. */
+ double total_time;
+
+ /* NOTE: Is fine to read directly, but for adding use add_entry(), which
+ * makes sure all accumulating values are properly updated.
+ */
+ vector<NamedTimeEntry> entries;
+
+ void clear()
+ {
+ total_time = 0.0;
+ entries.clear();
+ }
+};
+
+class NamedNestedSampleStats {
+ public:
+ NamedNestedSampleStats();
+ NamedNestedSampleStats(const string &name, uint64_t samples);
+
+ NamedNestedSampleStats &add_entry(const string &name, uint64_t samples);
+
+ /* Updates sum_samples recursively. */
+ void update_sum();
+
+ string full_report(int indent_level = 0, uint64_t total_samples = 0);
+
+ string name;
+
+ /* self_samples contains only the samples that this specific event got,
+ * while sum_samples also includes the samples of all sub-entries. */
+ uint64_t self_samples, sum_samples;
+
+ vector<NamedNestedSampleStats> entries;
+};
+
+/* Named entry containing both a time-sample count for objects of a type and a
+ * total count of processed items.
+ * This allows to estimate the time spent per item. */
+class NamedSampleCountPair {
+ public:
+ NamedSampleCountPair(const ustring &name, uint64_t samples, uint64_t hits);
+
+ ustring name;
+ uint64_t samples;
+ uint64_t hits;
+};
+
+/* Contains statistics about pairs of samples and counts as described above. */
+class NamedSampleCountStats {
+ public:
+ NamedSampleCountStats();
+
+ string full_report(int indent_level = 0);
+ void add(const ustring &name, uint64_t samples, uint64_t hits);
+
+ typedef unordered_map<ustring, NamedSampleCountPair, ustringHash> entry_map;
+ entry_map entries;
+};
+
+/* Statistics about mesh in the render database. */
+class MeshStats {
+ public:
+ MeshStats();
+
+ /* Generate full human-readable report. */
+ string full_report(int indent_level = 0);
+
+ /* Input geometry statistics, this is what is coming as an input to render
+ * from. say, Blender. This does not include runtime or engine specific
+ * memory like BVH.
+ */
+ NamedSizeStats geometry;
+};
+
+/* Statistics about images held in memory. */
+class ImageStats {
+ public:
+ ImageStats();
+
+ /* Generate full human-readable report. */
+ string full_report(int indent_level = 0);
+
+ NamedSizeStats textures;
+};
+
+/* Render process statistics. */
+class RenderStats {
+ public:
+ RenderStats();
+
+ /* Return full report as string. */
+ string full_report();
+
+ /* Collect kernel sampling information from Stats. */
+ void collect_profiling(Scene *scene, Profiler &prof);
+
+ bool has_profiling;
+
+ MeshStats mesh;
+ ImageStats image;
+ NamedNestedSampleStats kernel;
+ NamedSampleCountStats shaders;
+ NamedSampleCountStats objects;
+};
+
+class UpdateTimeStats {
+ public:
+ /* Generate full human-readable report. */
+ string full_report(int indent_level = 0);
+
+ NamedTimeStats times;
+};
+
+class SceneUpdateStats {
+ public:
+ SceneUpdateStats();
+
+ UpdateTimeStats geometry;
+ UpdateTimeStats image;
+ UpdateTimeStats light;
+ UpdateTimeStats object;
+ UpdateTimeStats background;
+ UpdateTimeStats bake;
+ UpdateTimeStats camera;
+ UpdateTimeStats film;
+ UpdateTimeStats integrator;
+ UpdateTimeStats osl;
+ UpdateTimeStats particles;
+ UpdateTimeStats scene;
+ UpdateTimeStats svm;
+ UpdateTimeStats tables;
+ UpdateTimeStats procedurals;
+
+ string full_report();
+
+ void clear();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __RENDER_STATS_H__ */
diff --git a/intern/cycles/scene/svm.cpp b/intern/cycles/scene/svm.cpp
new file mode 100644
index 00000000000..6da0df302ad
--- /dev/null
+++ b/intern/cycles/scene/svm.cpp
@@ -0,0 +1,984 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device/device.h"
+
+#include "scene/background.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+#include "scene/stats.h"
+#include "scene/svm.h"
+
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/progress.h"
+#include "util/task.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Shader Manager */
+
+SVMShaderManager::SVMShaderManager()
+{
+}
+
+SVMShaderManager::~SVMShaderManager()
+{
+}
+
+void SVMShaderManager::reset(Scene * /*scene*/)
+{
+}
+
+void SVMShaderManager::device_update_shader(Scene *scene,
+ Shader *shader,
+ Progress *progress,
+ array<int4> *svm_nodes)
+{
+ if (progress->get_cancel()) {
+ return;
+ }
+ assert(shader->graph);
+
+ svm_nodes->push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
+
+ SVMCompiler::Summary summary;
+ SVMCompiler compiler(scene);
+ compiler.background = (shader == scene->background->get_shader(scene));
+ compiler.compile(shader, *svm_nodes, 0, &summary);
+
+ VLOG(2) << "Compilation summary:\n"
+ << "Shader name: " << shader->name << "\n"
+ << summary.full_report();
+}
+
+void SVMShaderManager::device_update_specific(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
+{
+ if (!need_update())
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->svm.times.add_entry({"device_update", time});
+ }
+ });
+
+ const int num_shaders = scene->shaders.size();
+
+ VLOG(1) << "Total " << num_shaders << " shaders.";
+
+ double start_time = time_dt();
+
+ /* test if we need to update */
+ device_free(device, dscene, scene);
+
+ /* Build all shaders. */
+ TaskPool task_pool;
+ vector<array<int4>> shader_svm_nodes(num_shaders);
+ for (int i = 0; i < num_shaders; i++) {
+ task_pool.push(function_bind(&SVMShaderManager::device_update_shader,
+ this,
+ scene,
+ scene->shaders[i],
+ &progress,
+ &shader_svm_nodes[i]));
+ }
+ task_pool.wait_work();
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ /* The global node list contains a jump table (one node per shader)
+ * followed by the nodes of all shaders. */
+ int svm_nodes_size = num_shaders;
+ for (int i = 0; i < num_shaders; i++) {
+ /* Since we're not copying the local jump node, the size ends up being one node lower. */
+ svm_nodes_size += shader_svm_nodes[i].size() - 1;
+ }
+
+ int4 *svm_nodes = dscene->svm_nodes.alloc(svm_nodes_size);
+
+ int node_offset = num_shaders;
+ for (int i = 0; i < num_shaders; i++) {
+ Shader *shader = scene->shaders[i];
+
+ shader->clear_modified();
+ if (shader->get_use_mis() && shader->has_surface_emission) {
+ scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
+ }
+
+ /* Update the global jump table.
+ * Each compiled shader starts with a jump node that has offsets local
+ * to the shader, so copy those and add the offset into the global node list. */
+ int4 &global_jump_node = svm_nodes[shader->id];
+ int4 &local_jump_node = shader_svm_nodes[i][0];
+
+ global_jump_node.x = NODE_SHADER_JUMP;
+ global_jump_node.y = local_jump_node.y - 1 + node_offset;
+ global_jump_node.z = local_jump_node.z - 1 + node_offset;
+ global_jump_node.w = local_jump_node.w - 1 + node_offset;
+
+ node_offset += shader_svm_nodes[i].size() - 1;
+ }
+
+ /* Copy the nodes of each shader into the correct location. */
+ svm_nodes += num_shaders;
+ for (int i = 0; i < num_shaders; i++) {
+ int shader_size = shader_svm_nodes[i].size() - 1;
+
+ memcpy(svm_nodes, &shader_svm_nodes[i][1], sizeof(int4) * shader_size);
+ svm_nodes += shader_size;
+ }
+
+ if (progress.get_cancel()) {
+ return;
+ }
+
+ dscene->svm_nodes.copy_to_device();
+
+ device_update_common(device, dscene, scene, progress);
+
+ update_flags = UPDATE_NONE;
+
+ VLOG(1) << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
+ << " seconds.";
+}
+
+void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
+{
+ device_free_common(device, dscene, scene);
+
+ dscene->svm_nodes.free();
+}
+
+/* Graph Compiler */
+
+SVMCompiler::SVMCompiler(Scene *scene) : scene(scene)
+{
+ max_stack_use = 0;
+ current_type = SHADER_TYPE_SURFACE;
+ current_shader = NULL;
+ current_graph = NULL;
+ background = false;
+ mix_weight_offset = SVM_STACK_INVALID;
+ compile_failed = false;
+}
+
+int SVMCompiler::stack_size(SocketType::Type type)
+{
+ int size = 0;
+
+ switch (type) {
+ case SocketType::FLOAT:
+ case SocketType::INT:
+ size = 1;
+ break;
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::NORMAL:
+ case SocketType::POINT:
+ size = 3;
+ break;
+ case SocketType::CLOSURE:
+ size = 0;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ return size;
+}
+
+int SVMCompiler::stack_find_offset(int size)
+{
+ int offset = -1;
+
+ /* find free space in stack & mark as used */
+ for (int i = 0, num_unused = 0; i < SVM_STACK_SIZE; i++) {
+ if (active_stack.users[i])
+ num_unused = 0;
+ else
+ num_unused++;
+
+ if (num_unused == size) {
+ offset = i + 1 - size;
+ max_stack_use = max(i + 1, max_stack_use);
+
+ while (i >= offset)
+ active_stack.users[i--] = 1;
+
+ return offset;
+ }
+ }
+
+ if (!compile_failed) {
+ compile_failed = true;
+ fprintf(stderr,
+ "Cycles: out of SVM stack space, shader \"%s\" too big.\n",
+ current_shader->name.c_str());
+ }
+
+ return 0;
+}
+
+int SVMCompiler::stack_find_offset(SocketType::Type type)
+{
+ return stack_find_offset(stack_size(type));
+}
+
+void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset)
+{
+ int size = stack_size(type);
+
+ for (int i = 0; i < size; i++)
+ active_stack.users[offset + i]--;
+}
+
+int SVMCompiler::stack_assign(ShaderInput *input)
+{
+ /* stack offset assign? */
+ if (input->stack_offset == SVM_STACK_INVALID) {
+ if (input->link) {
+ /* linked to output -> use output offset */
+ assert(input->link->stack_offset != SVM_STACK_INVALID);
+ input->stack_offset = input->link->stack_offset;
+ }
+ else {
+ Node *node = input->parent;
+
+ /* not linked to output -> add nodes to load default value */
+ input->stack_offset = stack_find_offset(input->type());
+
+ if (input->type() == SocketType::FLOAT) {
+ add_node(NODE_VALUE_F,
+ __float_as_int(node->get_float(input->socket_type)),
+ input->stack_offset);
+ }
+ else if (input->type() == SocketType::INT) {
+ add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset);
+ }
+ else if (input->type() == SocketType::VECTOR || input->type() == SocketType::NORMAL ||
+ input->type() == SocketType::POINT || input->type() == SocketType::COLOR) {
+
+ add_node(NODE_VALUE_V, input->stack_offset);
+ add_node(NODE_VALUE_V, node->get_float3(input->socket_type));
+ }
+ else /* should not get called for closure */
+ assert(0);
+ }
+ }
+
+ return input->stack_offset;
+}
+
+int SVMCompiler::stack_assign(ShaderOutput *output)
+{
+ /* if no stack offset assigned yet, find one */
+ if (output->stack_offset == SVM_STACK_INVALID)
+ output->stack_offset = stack_find_offset(output->type());
+
+ return output->stack_offset;
+}
+
+int SVMCompiler::stack_assign_if_linked(ShaderInput *input)
+{
+ if (input->link || input->constant_folded_in)
+ return stack_assign(input);
+
+ return SVM_STACK_INVALID;
+}
+
+int SVMCompiler::stack_assign_if_linked(ShaderOutput *output)
+{
+ if (!output->links.empty())
+ return stack_assign(output);
+
+ return SVM_STACK_INVALID;
+}
+
+void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output)
+{
+ if (output->stack_offset == SVM_STACK_INVALID) {
+ assert(input->link);
+ assert(stack_size(output->type()) == stack_size(input->link->type()));
+
+ output->stack_offset = input->link->stack_offset;
+
+ int size = stack_size(output->type());
+
+ for (int i = 0; i < size; i++)
+ active_stack.users[output->stack_offset + i]++;
+ }
+}
+
+void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet &done)
+{
+ /* optimization we should add:
+ * find and lower user counts for outputs for which all inputs are done.
+ * this is done before the node is compiled, under the assumption that the
+ * node will first load all inputs from the stack and then writes its
+ * outputs. this used to work, but was disabled because it gave trouble
+ * with inputs getting stack positions assigned */
+
+ foreach (ShaderInput *input, node->inputs) {
+ ShaderOutput *output = input->link;
+
+ if (output && output->stack_offset != SVM_STACK_INVALID) {
+ bool all_done = true;
+
+ /* optimization we should add: verify if in->parent is actually used */
+ foreach (ShaderInput *in, output->links)
+ if (in->parent != node && done.find(in->parent) == done.end())
+ all_done = false;
+
+ if (all_done) {
+ stack_clear_offset(output->type(), output->stack_offset);
+ output->stack_offset = SVM_STACK_INVALID;
+
+ foreach (ShaderInput *in, output->links)
+ in->stack_offset = SVM_STACK_INVALID;
+ }
+ }
+ }
+}
+
+void SVMCompiler::stack_clear_temporary(ShaderNode *node)
+{
+ foreach (ShaderInput *input, node->inputs) {
+ if (!input->link && input->stack_offset != SVM_STACK_INVALID) {
+ stack_clear_offset(input->type(), input->stack_offset);
+ input->stack_offset = SVM_STACK_INVALID;
+ }
+ }
+}
+
+uint SVMCompiler::encode_uchar4(uint x, uint y, uint z, uint w)
+{
+ assert(x <= 255);
+ assert(y <= 255);
+ assert(z <= 255);
+ assert(w <= 255);
+
+ return (x) | (y << 8) | (z << 16) | (w << 24);
+}
+
+void SVMCompiler::add_node(int a, int b, int c, int d)
+{
+ current_svm_nodes.push_back_slow(make_int4(a, b, c, d));
+}
+
+void SVMCompiler::add_node(ShaderNodeType type, int a, int b, int c)
+{
+ current_svm_nodes.push_back_slow(make_int4(type, a, b, c));
+}
+
+void SVMCompiler::add_node(ShaderNodeType type, const float3 &f)
+{
+ current_svm_nodes.push_back_slow(
+ make_int4(type, __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z)));
+}
+
+void SVMCompiler::add_node(const float4 &f)
+{
+ current_svm_nodes.push_back_slow(make_int4(
+ __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), __float_as_int(f.w)));
+}
+
+uint SVMCompiler::attribute(ustring name)
+{
+ return scene->shader_manager->get_attribute_id(name);
+}
+
+uint SVMCompiler::attribute(AttributeStandard std)
+{
+ return scene->shader_manager->get_attribute_id(std);
+}
+
+uint SVMCompiler::attribute_standard(ustring name)
+{
+ AttributeStandard std = Attribute::name_standard(name.c_str());
+ return (std) ? attribute(std) : attribute(name);
+}
+
+void SVMCompiler::find_dependencies(ShaderNodeSet &dependencies,
+ const ShaderNodeSet &done,
+ ShaderInput *input,
+ ShaderNode *skip_node)
+{
+ ShaderNode *node = (input->link) ? input->link->parent : NULL;
+ if (node != NULL && done.find(node) == done.end() && node != skip_node &&
+ dependencies.find(node) == dependencies.end()) {
+ foreach (ShaderInput *in, node->inputs) {
+ find_dependencies(dependencies, done, in, skip_node);
+ }
+ dependencies.insert(node);
+ }
+}
+
+void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet &done)
+{
+ node->compile(*this);
+ stack_clear_users(node, done);
+ stack_clear_temporary(node);
+
+ if (current_type == SHADER_TYPE_SURFACE) {
+ if (node->has_spatial_varying())
+ current_shader->has_surface_spatial_varying = true;
+ if (node->get_feature() & KERNEL_FEATURE_NODE_RAYTRACE)
+ current_shader->has_surface_raytrace = true;
+ }
+ else if (current_type == SHADER_TYPE_VOLUME) {
+ if (node->has_spatial_varying())
+ current_shader->has_volume_spatial_varying = true;
+ if (node->has_attribute_dependency())
+ current_shader->has_volume_attribute_dependency = true;
+ }
+
+ if (node->has_integrator_dependency()) {
+ current_shader->has_integrator_dependency = true;
+ }
+}
+
+void SVMCompiler::generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state)
+{
+ ShaderNodeSet &done = state->nodes_done;
+ vector<bool> &done_flag = state->nodes_done_flag;
+
+ bool nodes_done;
+ do {
+ nodes_done = true;
+
+ foreach (ShaderNode *node, nodes) {
+ if (!done_flag[node->id]) {
+ bool inputs_done = true;
+
+ foreach (ShaderInput *input, node->inputs) {
+ if (input->link && !done_flag[input->link->parent->id]) {
+ inputs_done = false;
+ }
+ }
+ if (inputs_done) {
+ generate_node(node, done);
+ done.insert(node);
+ done_flag[node->id] = true;
+ }
+ else {
+ nodes_done = false;
+ }
+ }
+ }
+ } while (!nodes_done);
+}
+
+void SVMCompiler::generate_closure_node(ShaderNode *node, CompilerState *state)
+{
+ /* Skip generating closure that are not supported or needed for a particular
+ * type of shader. For example a BSDF in a volume shader. */
+ const int node_feature = node->get_feature();
+ if ((state->node_feature_mask & node_feature) != node_feature) {
+ return;
+ }
+
+ /* execute dependencies for closure */
+ foreach (ShaderInput *in, node->inputs) {
+ if (in->link != NULL) {
+ ShaderNodeSet dependencies;
+ find_dependencies(dependencies, state->nodes_done, in);
+ generate_svm_nodes(dependencies, state);
+ }
+ }
+
+ /* closure mix weight */
+ const char *weight_name = (current_type == SHADER_TYPE_VOLUME) ? "VolumeMixWeight" :
+ "SurfaceMixWeight";
+ ShaderInput *weight_in = node->input(weight_name);
+
+ if (weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f))
+ mix_weight_offset = stack_assign(weight_in);
+ else
+ mix_weight_offset = SVM_STACK_INVALID;
+
+ /* compile closure itself */
+ generate_node(node, state->nodes_done);
+
+ mix_weight_offset = SVM_STACK_INVALID;
+
+ if (current_type == SHADER_TYPE_SURFACE) {
+ if (node->has_surface_emission())
+ current_shader->has_surface_emission = true;
+ if (node->has_surface_transparent())
+ current_shader->has_surface_transparent = true;
+ if (node->has_surface_bssrdf()) {
+ current_shader->has_surface_bssrdf = true;
+ if (node->has_bssrdf_bump())
+ current_shader->has_bssrdf_bump = true;
+ }
+ if (node->has_bump()) {
+ current_shader->has_bump = true;
+ }
+ }
+}
+
+void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
+ ShaderNode *node,
+ CompilerState *state,
+ const ShaderNodeSet &shared)
+{
+ if (shared.find(node) != shared.end()) {
+ generate_multi_closure(root_node, node, state);
+ }
+ else {
+ foreach (ShaderInput *in, node->inputs) {
+ if (in->type() == SocketType::CLOSURE && in->link)
+ generated_shared_closure_nodes(root_node, in->link->parent, state, shared);
+ }
+ }
+}
+
+void SVMCompiler::find_aov_nodes_and_dependencies(ShaderNodeSet &aov_nodes,
+ ShaderGraph *graph,
+ CompilerState *state)
+{
+ foreach (ShaderNode *node, graph->nodes) {
+ if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
+ OutputAOVNode *aov_node = static_cast<OutputAOVNode *>(node);
+ if (aov_node->offset >= 0) {
+ aov_nodes.insert(aov_node);
+ foreach (ShaderInput *in, node->inputs) {
+ if (in->link != NULL) {
+ find_dependencies(aov_nodes, state->nodes_done, in);
+ }
+ }
+ }
+ }
+ }
+}
+
+void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
+ ShaderNode *node,
+ CompilerState *state)
+{
+ /* only generate once */
+ if (state->closure_done.find(node) != state->closure_done.end())
+ return;
+
+ state->closure_done.insert(node);
+
+ if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) {
+ /* weighting is already taken care of in ShaderGraph::transform_multi_closure */
+ ShaderInput *cl1in = node->input("Closure1");
+ ShaderInput *cl2in = node->input("Closure2");
+ ShaderInput *facin = node->input("Fac");
+
+ /* skip empty mix/add closure nodes */
+ if (!cl1in->link && !cl2in->link)
+ return;
+
+ if (facin && facin->link) {
+ /* mix closure: generate instructions to compute mix weight */
+ ShaderNodeSet dependencies;
+ find_dependencies(dependencies, state->nodes_done, facin);
+ generate_svm_nodes(dependencies, state);
+
+ /* execute shared dependencies. this is needed to allow skipping
+ * of zero weight closures and their dependencies later, so we
+ * ensure that they only skip dependencies that are unique to them */
+ ShaderNodeSet cl1deps, cl2deps, shareddeps;
+
+ find_dependencies(cl1deps, state->nodes_done, cl1in);
+ find_dependencies(cl2deps, state->nodes_done, cl2in);
+
+ ShaderNodeIDComparator node_id_comp;
+ set_intersection(cl1deps.begin(),
+ cl1deps.end(),
+ cl2deps.begin(),
+ cl2deps.end(),
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
+
+ /* it's possible some nodes are not shared between this mix node
+ * inputs, but still needed to be always executed, this mainly
+ * happens when a node of current subbranch is used by a parent
+ * node or so */
+ if (root_node != node) {
+ foreach (ShaderInput *in, root_node->inputs) {
+ ShaderNodeSet rootdeps;
+ find_dependencies(rootdeps, state->nodes_done, in, node);
+ set_intersection(rootdeps.begin(),
+ rootdeps.end(),
+ cl1deps.begin(),
+ cl1deps.end(),
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
+ set_intersection(rootdeps.begin(),
+ rootdeps.end(),
+ cl2deps.begin(),
+ cl2deps.end(),
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
+ }
+ }
+
+ /* For dependencies AOV nodes, prevent them from being categorized
+ * as exclusive deps of one or the other closure, since the need to
+ * execute them for AOV writing is not dependent on the closure
+ * weights. */
+ if (state->aov_nodes.size()) {
+ set_intersection(state->aov_nodes.begin(),
+ state->aov_nodes.end(),
+ cl1deps.begin(),
+ cl1deps.end(),
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
+ set_intersection(state->aov_nodes.begin(),
+ state->aov_nodes.end(),
+ cl2deps.begin(),
+ cl2deps.end(),
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
+ }
+
+ if (!shareddeps.empty()) {
+ if (cl1in->link) {
+ generated_shared_closure_nodes(root_node, cl1in->link->parent, state, shareddeps);
+ }
+ if (cl2in->link) {
+ generated_shared_closure_nodes(root_node, cl2in->link->parent, state, shareddeps);
+ }
+
+ generate_svm_nodes(shareddeps, state);
+ }
+
+ /* generate instructions for input closure 1 */
+ if (cl1in->link) {
+ /* Add instruction to skip closure and its dependencies if mix
+ * weight is zero.
+ */
+ current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ONE, 0, stack_assign(facin), 0));
+ int node_jump_skip_index = current_svm_nodes.size() - 1;
+
+ generate_multi_closure(root_node, cl1in->link->parent, state);
+
+ /* Fill in jump instruction location to be after closure. */
+ current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() -
+ node_jump_skip_index - 1;
+ }
+
+ /* generate instructions for input closure 2 */
+ if (cl2in->link) {
+ /* Add instruction to skip closure and its dependencies if mix
+ * weight is zero.
+ */
+ current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ZERO, 0, stack_assign(facin), 0));
+ int node_jump_skip_index = current_svm_nodes.size() - 1;
+
+ generate_multi_closure(root_node, cl2in->link->parent, state);
+
+ /* Fill in jump instruction location to be after closure. */
+ current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() -
+ node_jump_skip_index - 1;
+ }
+
+ /* unassign */
+ facin->stack_offset = SVM_STACK_INVALID;
+ }
+ else {
+ /* execute closures and their dependencies, no runtime checks
+ * to skip closures here because was already optimized due to
+ * fixed weight or add closure that always needs both */
+ if (cl1in->link)
+ generate_multi_closure(root_node, cl1in->link->parent, state);
+ if (cl2in->link)
+ generate_multi_closure(root_node, cl2in->link->parent, state);
+ }
+ }
+ else {
+ generate_closure_node(node, state);
+ }
+
+ state->nodes_done.insert(node);
+ state->nodes_done_flag[node->id] = true;
+}
+
+void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
+{
+ /* Converting a shader graph into svm_nodes that can be executed
+ * sequentially on the virtual machine is fairly simple. We can keep
+ * looping over nodes and each time all the inputs of a node are
+ * ready, we add svm_nodes for it that read the inputs from the
+ * stack and write outputs back to the stack.
+ *
+ * With the SVM, we always sample only a single closure. We can think
+ * of all closures nodes as a binary tree with mix closures as inner
+ * nodes and other closures as leafs. The SVM will traverse that tree,
+ * each time deciding to go left or right depending on the mix weights,
+ * until a closure is found.
+ *
+ * We only execute nodes that are needed for the mix weights and chosen
+ * closure.
+ */
+
+ current_type = type;
+ current_graph = graph;
+
+ /* get input in output node */
+ ShaderNode *output = graph->output();
+ ShaderInput *clin = NULL;
+
+ switch (type) {
+ case SHADER_TYPE_SURFACE:
+ clin = output->input("Surface");
+ break;
+ case SHADER_TYPE_VOLUME:
+ clin = output->input("Volume");
+ break;
+ case SHADER_TYPE_DISPLACEMENT:
+ clin = output->input("Displacement");
+ break;
+ case SHADER_TYPE_BUMP:
+ clin = output->input("Normal");
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ /* clear all compiler state */
+ memset((void *)&active_stack, 0, sizeof(active_stack));
+ current_svm_nodes.clear();
+
+ foreach (ShaderNode *node, graph->nodes) {
+ foreach (ShaderInput *input, node->inputs)
+ input->stack_offset = SVM_STACK_INVALID;
+ foreach (ShaderOutput *output, node->outputs)
+ output->stack_offset = SVM_STACK_INVALID;
+ }
+
+ /* for the bump shader we need add a node to store the shader state */
+ bool need_bump_state = (type == SHADER_TYPE_BUMP) &&
+ (shader->get_displacement_method() == DISPLACE_BOTH);
+ int bump_state_offset = SVM_STACK_INVALID;
+ if (need_bump_state) {
+ bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE);
+ add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset);
+ }
+
+ if (shader->reference_count()) {
+ CompilerState state(graph);
+ if (clin->link) {
+ bool generate = false;
+
+ switch (type) {
+ case SHADER_TYPE_SURFACE: /* generate surface shader */
+ generate = true;
+ shader->has_surface = true;
+ state.node_feature_mask = KERNEL_FEATURE_NODE_MASK_SURFACE;
+ break;
+ case SHADER_TYPE_VOLUME: /* generate volume shader */
+ generate = true;
+ shader->has_volume = true;
+ state.node_feature_mask = KERNEL_FEATURE_NODE_MASK_VOLUME;
+ break;
+ case SHADER_TYPE_DISPLACEMENT: /* generate displacement shader */
+ generate = true;
+ shader->has_displacement = true;
+ state.node_feature_mask = KERNEL_FEATURE_NODE_MASK_DISPLACEMENT;
+ break;
+ case SHADER_TYPE_BUMP: /* generate bump shader */
+ generate = true;
+ state.node_feature_mask = KERNEL_FEATURE_NODE_MASK_BUMP;
+ break;
+ default:
+ break;
+ }
+
+ if (generate) {
+ if (type == SHADER_TYPE_SURFACE) {
+ find_aov_nodes_and_dependencies(state.aov_nodes, graph, &state);
+ }
+ generate_multi_closure(clin->link->parent, clin->link->parent, &state);
+ }
+ }
+
+ /* compile output node */
+ output->compile(*this);
+
+ if (!state.aov_nodes.empty()) {
+ /* AOV passes are only written if the object is directly visible, so
+ * there is no point in evaluating all the nodes generated only for the
+ * AOV outputs if that's not the case. Therefore, we insert
+ * NODE_AOV_START into the shader before the AOV-only nodes are
+ * generated which tells the kernel that it can stop evaluation
+ * early if AOVs will not be written. */
+ add_node(NODE_AOV_START, 0, 0, 0);
+ generate_svm_nodes(state.aov_nodes, &state);
+ }
+ }
+
+ /* add node to restore state after bump shader has finished */
+ if (need_bump_state) {
+ add_node(NODE_LEAVE_BUMP_EVAL, bump_state_offset);
+ }
+
+ /* if compile failed, generate empty shader */
+ if (compile_failed) {
+ current_svm_nodes.clear();
+ compile_failed = false;
+ }
+
+ /* for bump shaders we fall thru to the surface shader, but if this is any other kind of shader
+ * it ends here */
+ if (type != SHADER_TYPE_BUMP) {
+ add_node(NODE_END, 0, 0, 0);
+ }
+}
+
+void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary)
+{
+ /* copy graph for shader with bump mapping */
+ ShaderNode *output = shader->graph->output();
+ int start_num_svm_nodes = svm_nodes.size();
+
+ const double time_start = time_dt();
+
+ bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) &&
+ output->input("Surface")->link && output->input("Displacement")->link;
+
+ /* finalize */
+ {
+ scoped_timer timer((summary != NULL) ? &summary->time_finalize : NULL);
+ shader->graph->finalize(scene,
+ has_bump,
+ shader->has_integrator_dependency,
+ shader->get_displacement_method() == DISPLACE_BOTH);
+ }
+
+ current_shader = shader;
+
+ shader->has_surface = false;
+ shader->has_surface_emission = false;
+ shader->has_surface_transparent = false;
+ shader->has_surface_raytrace = false;
+ shader->has_surface_bssrdf = false;
+ shader->has_bump = has_bump;
+ shader->has_bssrdf_bump = has_bump;
+ shader->has_volume = false;
+ shader->has_displacement = false;
+ shader->has_surface_spatial_varying = false;
+ shader->has_volume_spatial_varying = false;
+ shader->has_volume_attribute_dependency = false;
+ shader->has_integrator_dependency = false;
+
+ /* generate bump shader */
+ if (has_bump) {
+ scoped_timer timer((summary != NULL) ? &summary->time_generate_bump : NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_BUMP);
+ svm_nodes[index].y = svm_nodes.size();
+ svm_nodes.append(current_svm_nodes);
+ }
+
+ /* generate surface shader */
+ {
+ scoped_timer timer((summary != NULL) ? &summary->time_generate_surface : NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
+ /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this
+ * one if it exists */
+ if (!has_bump) {
+ svm_nodes[index].y = svm_nodes.size();
+ }
+ svm_nodes.append(current_svm_nodes);
+ }
+
+ /* generate volume shader */
+ {
+ scoped_timer timer((summary != NULL) ? &summary->time_generate_volume : NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
+ svm_nodes[index].z = svm_nodes.size();
+ svm_nodes.append(current_svm_nodes);
+ }
+
+ /* generate displacement shader */
+ {
+ scoped_timer timer((summary != NULL) ? &summary->time_generate_displacement : NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
+ svm_nodes[index].w = svm_nodes.size();
+ svm_nodes.append(current_svm_nodes);
+ }
+
+ /* Fill in summary information. */
+ if (summary != NULL) {
+ summary->time_total = time_dt() - time_start;
+ summary->peak_stack_usage = max_stack_use;
+ summary->num_svm_nodes = svm_nodes.size() - start_num_svm_nodes;
+ }
+}
+
+/* Compiler summary implementation. */
+
+SVMCompiler::Summary::Summary()
+ : num_svm_nodes(0),
+ peak_stack_usage(0),
+ time_finalize(0.0),
+ time_generate_surface(0.0),
+ time_generate_bump(0.0),
+ time_generate_volume(0.0),
+ time_generate_displacement(0.0),
+ time_total(0.0)
+{
+}
+
+string SVMCompiler::Summary::full_report() const
+{
+ string report = "";
+ report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes);
+ report += string_printf("Peak stack usage: %d\n", peak_stack_usage);
+
+ report += string_printf("Time (in seconds):\n");
+ report += string_printf("Finalize: %f\n", time_finalize);
+ report += string_printf(" Surface: %f\n", time_generate_surface);
+ report += string_printf(" Bump: %f\n", time_generate_bump);
+ report += string_printf(" Volume: %f\n", time_generate_volume);
+ report += string_printf(" Displacement: %f\n", time_generate_displacement);
+ report += string_printf("Generate: %f\n",
+ time_generate_surface + time_generate_bump + time_generate_volume +
+ time_generate_displacement);
+ report += string_printf("Total: %f\n", time_total);
+
+ return report;
+}
+
+/* Global state of the compiler. */
+
+SVMCompiler::CompilerState::CompilerState(ShaderGraph *graph)
+{
+ int max_id = 0;
+ foreach (ShaderNode *node, graph->nodes) {
+ max_id = max(node->id, max_id);
+ }
+ nodes_done_flag.resize(max_id + 1, false);
+ node_feature_mask = 0;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/svm.h b/intern/cycles/scene/svm.h
new file mode 100644
index 00000000000..edfd71040e4
--- /dev/null
+++ b/intern/cycles/scene/svm.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SVM_H__
+#define __SVM_H__
+
+#include "scene/attribute.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+
+#include "util/array.h"
+#include "util/set.h"
+#include "util/string.h"
+#include "util/thread.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class ImageManager;
+class Scene;
+class ShaderGraph;
+class ShaderInput;
+class ShaderNode;
+class ShaderOutput;
+
+/* Shader Manager */
+
+class SVMShaderManager : public ShaderManager {
+ public:
+ SVMShaderManager();
+ ~SVMShaderManager();
+
+ void reset(Scene *scene) override;
+
+ void device_update_specific(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress) override;
+ void device_free(Device *device, DeviceScene *dscene, Scene *scene) override;
+
+ protected:
+ void device_update_shader(Scene *scene,
+ Shader *shader,
+ Progress *progress,
+ array<int4> *svm_nodes);
+};
+
+/* Graph Compiler */
+
+class SVMCompiler {
+ public:
+ struct Summary {
+ Summary();
+
+ /* Number of SVM nodes shader was compiled into. */
+ int num_svm_nodes;
+
+ /* Peak stack usage during shader evaluation. */
+ int peak_stack_usage;
+
+ /* Time spent on surface graph finalization. */
+ double time_finalize;
+
+ /* Time spent on generating SVM nodes for surface shader. */
+ double time_generate_surface;
+
+ /* Time spent on generating SVM nodes for bump shader. */
+ double time_generate_bump;
+
+ /* Time spent on generating SVM nodes for volume shader. */
+ double time_generate_volume;
+
+ /* Time spent on generating SVM nodes for displacement shader. */
+ double time_generate_displacement;
+
+ /* Total time spent on all routines. */
+ double time_total;
+
+ /* A full multi-line description of the state of the compiler after compilation. */
+ string full_report() const;
+ };
+
+ SVMCompiler(Scene *scene);
+ void compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary = NULL);
+
+ int stack_assign(ShaderOutput *output);
+ int stack_assign(ShaderInput *input);
+ int stack_assign_if_linked(ShaderInput *input);
+ int stack_assign_if_linked(ShaderOutput *output);
+ int stack_find_offset(int size);
+ int stack_find_offset(SocketType::Type type);
+ void stack_clear_offset(SocketType::Type type, int offset);
+ void stack_link(ShaderInput *input, ShaderOutput *output);
+
+ void add_node(ShaderNodeType type, int a = 0, int b = 0, int c = 0);
+ void add_node(int a = 0, int b = 0, int c = 0, int d = 0);
+ void add_node(ShaderNodeType type, const float3 &f);
+ void add_node(const float4 &f);
+ uint attribute(ustring name);
+ uint attribute(AttributeStandard std);
+ uint attribute_standard(ustring name);
+ uint encode_uchar4(uint x, uint y = 0, uint z = 0, uint w = 0);
+ uint closure_mix_weight_offset()
+ {
+ return mix_weight_offset;
+ }
+
+ ShaderType output_type()
+ {
+ return current_type;
+ }
+
+ Scene *scene;
+ ShaderGraph *current_graph;
+ bool background;
+
+ protected:
+ /* stack */
+ struct Stack {
+ Stack()
+ {
+ memset(users, 0, sizeof(users));
+ }
+ Stack(const Stack &other)
+ {
+ memcpy(users, other.users, sizeof(users));
+ }
+ Stack &operator=(const Stack &other)
+ {
+ memcpy(users, other.users, sizeof(users));
+ return *this;
+ }
+
+ bool empty()
+ {
+ for (int i = 0; i < SVM_STACK_SIZE; i++)
+ if (users[i])
+ return false;
+
+ return true;
+ }
+
+ void print()
+ {
+ printf("stack <");
+
+ for (int i = 0; i < SVM_STACK_SIZE; i++)
+ printf((users[i]) ? "*" : " ");
+
+ printf(">\n");
+ }
+
+ int users[SVM_STACK_SIZE];
+ };
+
+ /* Global state of the compiler accessible from the compilation routines. */
+ struct CompilerState {
+ explicit CompilerState(ShaderGraph *graph);
+
+ /* ** Global state, used by various compilation steps. ** */
+
+ /* Set of nodes which were already compiled. */
+ ShaderNodeSet nodes_done;
+
+ /* Set of closures which were already compiled. */
+ ShaderNodeSet closure_done;
+
+ /* Set of nodes used for writing AOVs. */
+ ShaderNodeSet aov_nodes;
+
+ /* ** SVM nodes generation state ** */
+
+ /* Flag whether the node with corresponding ID was already compiled or
+ * not. Array element with index i corresponds to a node with such if.
+ *
+ * TODO(sergey): This is actually a copy of nodes_done just in another
+ * notation. We can de-duplicate this storage actually after switching
+ * all areas to use this flags array.
+ */
+ vector<bool> nodes_done_flag;
+
+ /* Node features that can be compiled. */
+ uint node_feature_mask;
+ };
+
+ void stack_clear_temporary(ShaderNode *node);
+ int stack_size(SocketType::Type type);
+ void stack_clear_users(ShaderNode *node, ShaderNodeSet &done);
+
+ /* single closure */
+ void find_dependencies(ShaderNodeSet &dependencies,
+ const ShaderNodeSet &done,
+ ShaderInput *input,
+ ShaderNode *skip_node = NULL);
+ void find_aov_nodes_and_dependencies(ShaderNodeSet &aov_nodes,
+ ShaderGraph *graph,
+ CompilerState *state);
+ void generate_node(ShaderNode *node, ShaderNodeSet &done);
+ void generate_aov_node(ShaderNode *node, CompilerState *state);
+ void generate_closure_node(ShaderNode *node, CompilerState *state);
+ void generated_shared_closure_nodes(ShaderNode *root_node,
+ ShaderNode *node,
+ CompilerState *state,
+ const ShaderNodeSet &shared);
+ void generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state);
+
+ /* multi closure */
+ void generate_multi_closure(ShaderNode *root_node, ShaderNode *node, CompilerState *state);
+
+ /* compile */
+ void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
+
+ array<int4> current_svm_nodes;
+ ShaderType current_type;
+ Shader *current_shader;
+ Stack active_stack;
+ int max_stack_use;
+ uint mix_weight_offset;
+ bool compile_failed;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __SVM_H__ */
diff --git a/intern/cycles/scene/tables.cpp b/intern/cycles/scene/tables.cpp
new file mode 100644
index 00000000000..3544fea67d6
--- /dev/null
+++ b/intern/cycles/scene/tables.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/tables.h"
+#include "device/device.h"
+#include "scene/scene.h"
+#include "scene/stats.h"
+
+#include "util/log.h"
+#include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Lookup Tables */
+
+LookupTables::LookupTables()
+{
+ need_update_ = true;
+}
+
+LookupTables::~LookupTables()
+{
+ assert(lookup_tables.size() == 0);
+}
+
+void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene)
+{
+ if (!need_update())
+ return;
+
+ scoped_callback_timer timer([scene](double time) {
+ if (scene->update_stats) {
+ scene->update_stats->tables.times.add_entry({"device_update", time});
+ }
+ });
+
+ VLOG(1) << "Total " << lookup_tables.size() << " lookup tables.";
+
+ if (lookup_tables.size() > 0)
+ dscene->lookup_table.copy_to_device();
+
+ need_update_ = false;
+}
+
+void LookupTables::device_free(Device *, DeviceScene *dscene)
+{
+ dscene->lookup_table.free();
+}
+
+bool LookupTables::need_update() const
+{
+ return need_update_;
+}
+
+static size_t round_up_to_multiple(size_t size, size_t chunk)
+{
+ return ((size + chunk - 1) / chunk) * chunk;
+}
+
+size_t LookupTables::add_table(DeviceScene *dscene, vector<float> &data)
+{
+ assert(data.size() > 0);
+
+ need_update_ = true;
+
+ Table new_table;
+ new_table.offset = 0;
+ new_table.size = round_up_to_multiple(data.size(), TABLE_CHUNK_SIZE);
+
+ /* find space to put lookup table */
+ list<Table>::iterator table;
+
+ for (table = lookup_tables.begin(); table != lookup_tables.end(); table++) {
+ if (new_table.offset + new_table.size <= table->offset) {
+ lookup_tables.insert(table, new_table);
+ break;
+ }
+ else
+ new_table.offset = table->offset + table->size;
+ }
+
+ if (table == lookup_tables.end()) {
+ /* add at the end */
+ lookup_tables.push_back(new_table);
+ dscene->lookup_table.resize(new_table.offset + new_table.size);
+ }
+
+ /* copy table data and return offset */
+ float *dtable = dscene->lookup_table.data();
+ memcpy(dtable + new_table.offset, &data[0], sizeof(float) * data.size());
+
+ return new_table.offset;
+}
+
+void LookupTables::remove_table(size_t *offset)
+{
+ if (*offset == TABLE_OFFSET_INVALID) {
+ /* The table isn't even allocated, so just return here. */
+ return;
+ }
+
+ need_update_ = true;
+
+ list<Table>::iterator table;
+
+ for (table = lookup_tables.begin(); table != lookup_tables.end(); table++) {
+ if (table->offset == *offset) {
+ lookup_tables.erase(table);
+ *offset = TABLE_OFFSET_INVALID;
+ return;
+ }
+ }
+
+ assert(table != lookup_tables.end());
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/tables.h b/intern/cycles/scene/tables.h
new file mode 100644
index 00000000000..3e52544d1fb
--- /dev/null
+++ b/intern/cycles/scene/tables.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TABLES_H__
+#define __TABLES_H__
+
+#include "util/list.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Scene;
+
+enum { TABLE_CHUNK_SIZE = 256 };
+enum { TABLE_OFFSET_INVALID = -1 };
+
+class LookupTables {
+ bool need_update_;
+
+ public:
+ struct Table {
+ size_t offset;
+ size_t size;
+ };
+
+ list<Table> lookup_tables;
+
+ LookupTables();
+ ~LookupTables();
+
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene);
+ void device_free(Device *device, DeviceScene *dscene);
+
+ bool need_update() const;
+
+ size_t add_table(DeviceScene *dscene, vector<float> &data);
+ void remove_table(size_t *offset);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __TABLES_H__ */
diff --git a/intern/cycles/scene/volume.cpp b/intern/cycles/scene/volume.cpp
new file mode 100644
index 00000000000..509d0ecedf7
--- /dev/null
+++ b/intern/cycles/scene/volume.cpp
@@ -0,0 +1,635 @@
+/*
+ * Copyright 2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/volume.h"
+#include "scene/attribute.h"
+#include "scene/image_vdb.h"
+#include "scene/scene.h"
+
+#ifdef WITH_OPENVDB
+# include <openvdb/tools/Dense.h>
+# include <openvdb/tools/GridTransformer.h>
+# include <openvdb/tools/Morphology.h>
+#endif
+
+#include "util/foreach.h"
+#include "util/hash.h"
+#include "util/log.h"
+#include "util/openvdb.h"
+#include "util/progress.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+NODE_DEFINE(Volume)
+{
+ NodeType *type = NodeType::add("volume", create, NodeType::NONE, Mesh::get_node_type());
+
+ SOCKET_FLOAT(clipping, "Clipping", 0.001f);
+ SOCKET_FLOAT(step_size, "Step Size", 0.0f);
+ SOCKET_BOOLEAN(object_space, "Object Space", false);
+
+ return type;
+}
+
+Volume::Volume() : Mesh(get_node_type(), Geometry::VOLUME)
+{
+ clipping = 0.001f;
+ step_size = 0.0f;
+ object_space = false;
+}
+
+void Volume::clear(bool preserve_shaders)
+{
+ Mesh::clear(preserve_shaders, true);
+}
+
+struct QuadData {
+ int v0, v1, v2, v3;
+
+ float3 normal;
+};
+
+enum {
+ QUAD_X_MIN = 0,
+ QUAD_X_MAX = 1,
+ QUAD_Y_MIN = 2,
+ QUAD_Y_MAX = 3,
+ QUAD_Z_MIN = 4,
+ QUAD_Z_MAX = 5,
+};
+
+#ifdef WITH_OPENVDB
+const int quads_indices[6][4] = {
+ /* QUAD_X_MIN */
+ {4, 0, 3, 7},
+ /* QUAD_X_MAX */
+ {1, 5, 6, 2},
+ /* QUAD_Y_MIN */
+ {4, 5, 1, 0},
+ /* QUAD_Y_MAX */
+ {3, 2, 6, 7},
+ /* QUAD_Z_MIN */
+ {0, 1, 2, 3},
+ /* QUAD_Z_MAX */
+ {5, 4, 7, 6},
+};
+
+const float3 quads_normals[6] = {
+ /* QUAD_X_MIN */
+ make_float3(-1.0f, 0.0f, 0.0f),
+ /* QUAD_X_MAX */
+ make_float3(1.0f, 0.0f, 0.0f),
+ /* QUAD_Y_MIN */
+ make_float3(0.0f, -1.0f, 0.0f),
+ /* QUAD_Y_MAX */
+ make_float3(0.0f, 1.0f, 0.0f),
+ /* QUAD_Z_MIN */
+ make_float3(0.0f, 0.0f, -1.0f),
+ /* QUAD_Z_MAX */
+ make_float3(0.0f, 0.0f, 1.0f),
+};
+
+static int add_vertex(int3 v,
+ vector<int3> &vertices,
+ int3 res,
+ unordered_map<size_t, int> &used_verts)
+{
+ size_t vert_key = v.x + v.y * (res.x + 1) + v.z * (res.x + 1) * (res.y + 1);
+ unordered_map<size_t, int>::iterator it = used_verts.find(vert_key);
+
+ if (it != used_verts.end()) {
+ return it->second;
+ }
+
+ int vertex_offset = vertices.size();
+ used_verts[vert_key] = vertex_offset;
+ vertices.push_back(v);
+ return vertex_offset;
+}
+
+static void create_quad(int3 corners[8],
+ vector<int3> &vertices,
+ vector<QuadData> &quads,
+ int3 res,
+ unordered_map<size_t, int> &used_verts,
+ int face_index)
+{
+ QuadData quad;
+ quad.v0 = add_vertex(corners[quads_indices[face_index][0]], vertices, res, used_verts);
+ quad.v1 = add_vertex(corners[quads_indices[face_index][1]], vertices, res, used_verts);
+ quad.v2 = add_vertex(corners[quads_indices[face_index][2]], vertices, res, used_verts);
+ quad.v3 = add_vertex(corners[quads_indices[face_index][3]], vertices, res, used_verts);
+ quad.normal = quads_normals[face_index];
+
+ quads.push_back(quad);
+}
+#endif
+
+/* Create a mesh from a volume.
+ *
+ * The way the algorithm works is as follows:
+ *
+ * - The topologies of input OpenVDB grids are merged into a temporary grid.
+ * - Voxels of the temporary grid are dilated to account for the padding necessary for volume
+ * sampling.
+ * - Quads are created on the boundary between active and inactive leaf nodes of the temporary
+ * grid.
+ */
+class VolumeMeshBuilder {
+ public:
+#ifdef WITH_OPENVDB
+ /* use a MaskGrid to store the topology to save memory */
+ openvdb::MaskGrid::Ptr topology_grid;
+ openvdb::CoordBBox bbox;
+#endif
+ bool first_grid;
+
+ VolumeMeshBuilder();
+
+#ifdef WITH_OPENVDB
+ void add_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping);
+#endif
+
+ void add_padding(int pad_size);
+
+ void create_mesh(vector<float3> &vertices,
+ vector<int> &indices,
+ vector<float3> &face_normals,
+ const float face_overlap_avoidance);
+
+ void generate_vertices_and_quads(vector<int3> &vertices_is, vector<QuadData> &quads);
+
+ void convert_object_space(const vector<int3> &vertices,
+ vector<float3> &out_vertices,
+ const float face_overlap_avoidance);
+
+ void convert_quads_to_tris(const vector<QuadData> &quads,
+ vector<int> &tris,
+ vector<float3> &face_normals);
+
+ bool empty_grid() const;
+
+#ifdef WITH_OPENVDB
+ template<typename GridType>
+ void merge_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping)
+ {
+ typename GridType::ConstPtr typed_grid = openvdb::gridConstPtrCast<GridType>(grid);
+
+ if (do_clipping) {
+ using ValueType = typename GridType::ValueType;
+ typename GridType::Ptr copy = typed_grid->deepCopy();
+ typename GridType::ValueOnIter iter = copy->beginValueOn();
+
+ for (; iter; ++iter) {
+ if (iter.getValue() < ValueType(volume_clipping)) {
+ iter.setValueOff();
+ }
+ }
+
+ typed_grid = copy;
+ }
+
+ topology_grid->topologyUnion(*typed_grid);
+ }
+#endif
+};
+
+VolumeMeshBuilder::VolumeMeshBuilder()
+{
+ first_grid = true;
+}
+
+#ifdef WITH_OPENVDB
+void VolumeMeshBuilder::add_grid(openvdb::GridBase::ConstPtr grid,
+ bool do_clipping,
+ float volume_clipping)
+{
+ /* set the transform of our grid from the first one */
+ if (first_grid) {
+ topology_grid = openvdb::MaskGrid::create();
+ topology_grid->setTransform(grid->transform().copy());
+ first_grid = false;
+ }
+ /* if the transforms do not match, we need to resample one of the grids so that
+ * its index space registers with that of the other, here we resample our mask
+ * grid so memory usage is kept low */
+ else if (topology_grid->transform() != grid->transform()) {
+ openvdb::MaskGrid::Ptr temp_grid = topology_grid->copyWithNewTree();
+ temp_grid->setTransform(grid->transform().copy());
+ openvdb::tools::resampleToMatch<openvdb::tools::BoxSampler>(*topology_grid, *temp_grid);
+ topology_grid = temp_grid;
+ topology_grid->setTransform(grid->transform().copy());
+ }
+
+ if (grid->isType<openvdb::FloatGrid>()) {
+ merge_grid<openvdb::FloatGrid>(grid, do_clipping, volume_clipping);
+ }
+ else if (grid->isType<openvdb::Vec3fGrid>()) {
+ merge_grid<openvdb::Vec3fGrid>(grid, do_clipping, volume_clipping);
+ }
+ else if (grid->isType<openvdb::Vec4fGrid>()) {
+ merge_grid<openvdb::Vec4fGrid>(grid, do_clipping, volume_clipping);
+ }
+ else if (grid->isType<openvdb::BoolGrid>()) {
+ merge_grid<openvdb::BoolGrid>(grid, do_clipping, volume_clipping);
+ }
+ else if (grid->isType<openvdb::DoubleGrid>()) {
+ merge_grid<openvdb::DoubleGrid>(grid, do_clipping, volume_clipping);
+ }
+ else if (grid->isType<openvdb::Int32Grid>()) {
+ merge_grid<openvdb::Int32Grid>(grid, do_clipping, volume_clipping);
+ }
+ else if (grid->isType<openvdb::Int64Grid>()) {
+ merge_grid<openvdb::Int64Grid>(grid, do_clipping, volume_clipping);
+ }
+ else if (grid->isType<openvdb::Vec3IGrid>()) {
+ merge_grid<openvdb::Vec3IGrid>(grid, do_clipping, volume_clipping);
+ }
+ else if (grid->isType<openvdb::Vec3dGrid>()) {
+ merge_grid<openvdb::Vec3dGrid>(grid, do_clipping, volume_clipping);
+ }
+ else if (grid->isType<openvdb::MaskGrid>()) {
+ topology_grid->topologyUnion(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid));
+ }
+}
+#endif
+
+void VolumeMeshBuilder::add_padding(int pad_size)
+{
+#ifdef WITH_OPENVDB
+ openvdb::tools::dilateVoxels(topology_grid->tree(), pad_size);
+#else
+ (void)pad_size;
+#endif
+}
+
+void VolumeMeshBuilder::create_mesh(vector<float3> &vertices,
+ vector<int> &indices,
+ vector<float3> &face_normals,
+ const float face_overlap_avoidance)
+{
+#ifdef WITH_OPENVDB
+ /* We create vertices in index space (is), and only convert them to object
+ * space when done. */
+ vector<int3> vertices_is;
+ vector<QuadData> quads;
+
+ /* make sure we only have leaf nodes in the tree, as tiles are not handled by
+ * this algorithm */
+ topology_grid->tree().voxelizeActiveTiles();
+
+ generate_vertices_and_quads(vertices_is, quads);
+
+ convert_object_space(vertices_is, vertices, face_overlap_avoidance);
+
+ convert_quads_to_tris(quads, indices, face_normals);
+#else
+ (void)vertices;
+ (void)indices;
+ (void)face_normals;
+ (void)face_overlap_avoidance;
+#endif
+}
+
+void VolumeMeshBuilder::generate_vertices_and_quads(vector<ccl::int3> &vertices_is,
+ vector<QuadData> &quads)
+{
+#ifdef WITH_OPENVDB
+ const openvdb::MaskGrid::TreeType &tree = topology_grid->tree();
+ tree.evalLeafBoundingBox(bbox);
+
+ const int3 resolution = make_int3(bbox.dim().x(), bbox.dim().y(), bbox.dim().z());
+
+ unordered_map<size_t, int> used_verts;
+
+ for (auto iter = tree.cbeginLeaf(); iter; ++iter) {
+ openvdb::CoordBBox leaf_bbox = iter->getNodeBoundingBox();
+ /* +1 to convert from exclusive to include bounds. */
+ leaf_bbox.max() = leaf_bbox.max().offsetBy(1);
+
+ int3 min = make_int3(leaf_bbox.min().x(), leaf_bbox.min().y(), leaf_bbox.min().z());
+ int3 max = make_int3(leaf_bbox.max().x(), leaf_bbox.max().y(), leaf_bbox.max().z());
+
+ int3 corners[8] = {
+ make_int3(min[0], min[1], min[2]),
+ make_int3(max[0], min[1], min[2]),
+ make_int3(max[0], max[1], min[2]),
+ make_int3(min[0], max[1], min[2]),
+ make_int3(min[0], min[1], max[2]),
+ make_int3(max[0], min[1], max[2]),
+ make_int3(max[0], max[1], max[2]),
+ make_int3(min[0], max[1], max[2]),
+ };
+
+ /* Only create a quad if on the border between an active and an inactive leaf.
+ *
+ * We verify that a leaf exists by probing a coordinate that is at its center,
+ * to do so we compute the center of the current leaf and offset this coordinate
+ * by the size of a leaf in each direction.
+ */
+ static const int LEAF_DIM = openvdb::MaskGrid::TreeType::LeafNodeType::DIM;
+ auto center = leaf_bbox.min() + openvdb::Coord(LEAF_DIM / 2);
+
+ if (!tree.probeLeaf(openvdb::Coord(center.x() - LEAF_DIM, center.y(), center.z()))) {
+ create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_X_MIN);
+ }
+
+ if (!tree.probeLeaf(openvdb::Coord(center.x() + LEAF_DIM, center.y(), center.z()))) {
+ create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_X_MAX);
+ }
+
+ if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y() - LEAF_DIM, center.z()))) {
+ create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Y_MIN);
+ }
+
+ if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y() + LEAF_DIM, center.z()))) {
+ create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Y_MAX);
+ }
+
+ if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y(), center.z() - LEAF_DIM))) {
+ create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Z_MIN);
+ }
+
+ if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y(), center.z() + LEAF_DIM))) {
+ create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Z_MAX);
+ }
+ }
+#else
+ (void)vertices_is;
+ (void)quads;
+#endif
+}
+
+void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
+ vector<float3> &out_vertices,
+ const float face_overlap_avoidance)
+{
+#ifdef WITH_OPENVDB
+ /* compute the offset for the face overlap avoidance */
+ bbox = topology_grid->evalActiveVoxelBoundingBox();
+ openvdb::Coord dim = bbox.dim();
+
+ float3 cell_size = make_float3(1.0f / dim.x(), 1.0f / dim.y(), 1.0f / dim.z());
+ float3 point_offset = cell_size * face_overlap_avoidance;
+
+ out_vertices.reserve(vertices.size());
+
+ for (size_t i = 0; i < vertices.size(); ++i) {
+ openvdb::math::Vec3d p = topology_grid->indexToWorld(
+ openvdb::math::Vec3d(vertices[i].x, vertices[i].y, vertices[i].z));
+ float3 vertex = make_float3((float)p.x(), (float)p.y(), (float)p.z());
+ out_vertices.push_back(vertex + point_offset);
+ }
+#else
+ (void)vertices;
+ (void)out_vertices;
+ (void)face_overlap_avoidance;
+#endif
+}
+
+void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads,
+ vector<int> &tris,
+ vector<float3> &face_normals)
+{
+ int index_offset = 0;
+ tris.resize(quads.size() * 6);
+ face_normals.reserve(quads.size() * 2);
+
+ for (size_t i = 0; i < quads.size(); ++i) {
+ tris[index_offset++] = quads[i].v0;
+ tris[index_offset++] = quads[i].v2;
+ tris[index_offset++] = quads[i].v1;
+
+ face_normals.push_back(quads[i].normal);
+
+ tris[index_offset++] = quads[i].v0;
+ tris[index_offset++] = quads[i].v3;
+ tris[index_offset++] = quads[i].v2;
+
+ face_normals.push_back(quads[i].normal);
+ }
+}
+
+bool VolumeMeshBuilder::empty_grid() const
+{
+#ifdef WITH_OPENVDB
+ return !topology_grid || topology_grid->tree().leafCount() == 0;
+#else
+ return true;
+#endif
+}
+
+#ifdef WITH_OPENVDB
+template<typename GridType>
+static openvdb::GridBase::ConstPtr openvdb_grid_from_device_texture(device_texture *image_memory,
+ float volume_clipping,
+ Transform transform_3d)
+{
+ using ValueType = typename GridType::ValueType;
+
+ openvdb::CoordBBox dense_bbox(0,
+ 0,
+ 0,
+ image_memory->data_width - 1,
+ image_memory->data_height - 1,
+ image_memory->data_depth - 1);
+
+ typename GridType::Ptr sparse = GridType::create(ValueType(0.0f));
+ if (dense_bbox.empty()) {
+ return sparse;
+ }
+
+ openvdb::tools::Dense<ValueType, openvdb::tools::MemoryLayout::LayoutXYZ> dense(
+ dense_bbox, static_cast<ValueType *>(image_memory->host_pointer));
+
+ openvdb::tools::copyFromDense(dense, *sparse, ValueType(volume_clipping));
+
+ /* #copyFromDense will remove any leaf node that contains constant data and replace it with a
+ * tile, however, we need to preserve the leaves in order to generate the mesh, so re-voxelize
+ * the leaves that were pruned. This should not affect areas that were skipped due to the
+ * volume_clipping parameter. */
+ sparse->tree().voxelizeActiveTiles();
+
+ /* Compute index to world matrix. */
+ float3 voxel_size = make_float3(1.0f / image_memory->data_width,
+ 1.0f / image_memory->data_height,
+ 1.0f / image_memory->data_depth);
+
+ transform_3d = transform_inverse(transform_3d);
+
+ openvdb::Mat4R index_to_world_mat((double)(voxel_size.x * transform_3d[0][0]),
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ (double)(voxel_size.y * transform_3d[1][1]),
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ (double)(voxel_size.z * transform_3d[2][2]),
+ 0.0,
+ (double)transform_3d[0][3],
+ (double)transform_3d[1][3],
+ (double)transform_3d[2][3],
+ 1.0);
+
+ openvdb::math::Transform::Ptr index_to_world_tfm =
+ openvdb::math::Transform::createLinearTransform(index_to_world_mat);
+
+ sparse->setTransform(index_to_world_tfm);
+
+ return sparse;
+}
+#endif
+
+/* ************************************************************************** */
+
+void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
+{
+ string msg = string_printf("Computing Volume Mesh %s", volume->name.c_str());
+ progress.set_status("Updating Mesh", msg);
+
+ /* Find shader and compute padding based on volume shader interpolation settings. */
+ Shader *volume_shader = NULL;
+ int pad_size = 0;
+
+ foreach (Node *node, volume->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+
+ if (!shader->has_volume) {
+ continue;
+ }
+
+ volume_shader = shader;
+
+ if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_LINEAR) {
+ pad_size = max(1, pad_size);
+ }
+ else if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC) {
+ pad_size = max(2, pad_size);
+ }
+
+ break;
+ }
+
+ /* Clear existing volume mesh, done here in case we early out due to
+ * empty grid or missing volume shader.
+ * Also keep the shaders to avoid infinite loops when synchronizing, as this will tag the shaders
+ * as having changed. */
+ volume->clear(true);
+ volume->need_update_rebuild = true;
+
+ if (!volume_shader) {
+ return;
+ }
+
+ /* Create volume mesh builder. */
+ VolumeMeshBuilder builder;
+
+#ifdef WITH_OPENVDB
+ foreach (Attribute &attr, volume->attributes.attributes) {
+ if (attr.element != ATTR_ELEMENT_VOXEL) {
+ continue;
+ }
+
+ bool do_clipping = false;
+
+ ImageHandle &handle = attr.data_voxel();
+
+ /* Try building from OpenVDB grid directly. */
+ VDBImageLoader *vdb_loader = handle.vdb_loader();
+ openvdb::GridBase::ConstPtr grid;
+ if (vdb_loader) {
+ grid = vdb_loader->get_grid();
+
+ /* If building from an OpenVDB grid, we need to manually clip the values. */
+ do_clipping = true;
+ }
+
+ /* Else fall back to creating an OpenVDB grid from the dense volume data. */
+ if (!grid) {
+ device_texture *image_memory = handle.image_memory();
+
+ if (image_memory->data_elements == 1) {
+ grid = openvdb_grid_from_device_texture<openvdb::FloatGrid>(
+ image_memory, volume->get_clipping(), handle.metadata().transform_3d);
+ }
+ else if (image_memory->data_elements == 3) {
+ grid = openvdb_grid_from_device_texture<openvdb::Vec3fGrid>(
+ image_memory, volume->get_clipping(), handle.metadata().transform_3d);
+ }
+ else if (image_memory->data_elements == 4) {
+ grid = openvdb_grid_from_device_texture<openvdb::Vec4fGrid>(
+ image_memory, volume->get_clipping(), handle.metadata().transform_3d);
+ }
+ }
+
+ if (grid) {
+ builder.add_grid(grid, do_clipping, volume->get_clipping());
+ }
+ }
+#endif
+
+ /* If nothing to build, early out. */
+ if (builder.empty_grid()) {
+ return;
+ }
+
+ builder.add_padding(pad_size);
+
+ /* Slightly offset vertex coordinates to avoid overlapping faces with other
+ * volumes or meshes. The proper solution would be to improve intersection in
+ * the kernel to support robust handling of multiple overlapping faces or use
+ * an all-hit intersection similar to shadows. */
+ const float face_overlap_avoidance = 0.1f *
+ hash_uint_to_float(hash_string(volume->name.c_str()));
+
+ /* Create mesh. */
+ vector<float3> vertices;
+ vector<int> indices;
+ vector<float3> face_normals;
+ builder.create_mesh(vertices, indices, face_normals, face_overlap_avoidance);
+
+ volume->reserve_mesh(vertices.size(), indices.size() / 3);
+ volume->used_shaders.clear();
+ volume->used_shaders.push_back_slow(volume_shader);
+
+ for (size_t i = 0; i < vertices.size(); ++i) {
+ volume->add_vertex(vertices[i]);
+ }
+
+ for (size_t i = 0; i < indices.size(); i += 3) {
+ volume->add_triangle(indices[i], indices[i + 1], indices[i + 2], 0, false);
+ }
+
+ Attribute *attr_fN = volume->attributes.add(ATTR_STD_FACE_NORMAL);
+ float3 *fN = attr_fN->data_float3();
+
+ for (size_t i = 0; i < face_normals.size(); ++i) {
+ fN[i] = face_normals[i];
+ }
+
+ /* Print stats. */
+ VLOG(1) << "Memory usage volume mesh: "
+ << ((vertices.size() + face_normals.size()) * sizeof(float3) +
+ indices.size() * sizeof(int)) /
+ (1024.0 * 1024.0)
+ << "Mb.";
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/volume.h b/intern/cycles/scene/volume.h
new file mode 100644
index 00000000000..eae48f78b8c
--- /dev/null
+++ b/intern/cycles/scene/volume.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "graph/node.h"
+
+#include "scene/mesh.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Volume : public Mesh {
+ public:
+ NODE_DECLARE
+
+ Volume();
+
+ NODE_SOCKET_API(float, clipping)
+ NODE_SOCKET_API(float, step_size)
+ NODE_SOCKET_API(bool, object_space)
+
+ virtual void clear(bool preserve_shaders = false) override;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/session/CMakeLists.txt b/intern/cycles/session/CMakeLists.txt
new file mode 100644
index 00000000000..f441def128e
--- /dev/null
+++ b/intern/cycles/session/CMakeLists.txt
@@ -0,0 +1,48 @@
+# Copyright 2011-2021 Blender Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(INC
+ ..
+)
+
+set(SRC
+ buffers.cpp
+ denoising.cpp
+ merge.cpp
+ session.cpp
+ tile.cpp
+)
+
+set(SRC_HEADERS
+ buffers.h
+ display_driver.h
+ denoising.h
+ merge.h
+ output_driver.h
+ session.h
+ tile.h
+)
+
+set(LIB
+ cycles_device
+ cycles_integrator
+ cycles_util
+)
+
+include_directories(${INC})
+include_directories(SYSTEM ${INC_SYS})
+
+add_definitions(${GL_DEFINITIONS})
+
+cycles_add_library(cycles_session "${LIB}" ${SRC} ${SRC_HEADERS})
diff --git a/intern/cycles/session/buffers.cpp b/intern/cycles/session/buffers.cpp
new file mode 100644
index 00000000000..5c9e097e5b1
--- /dev/null
+++ b/intern/cycles/session/buffers.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include "device/device.h"
+#include "session/buffers.h"
+
+#include "util/foreach.h"
+#include "util/hash.h"
+#include "util/math.h"
+#include "util/time.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* --------------------------------------------------------------------
+ * Convert part information to an index of `BufferParams::pass_offset_`.
+ */
+
+static int pass_type_mode_to_index(PassType pass_type, PassMode mode)
+{
+ int index = static_cast<int>(pass_type) * 2;
+
+ if (mode == PassMode::DENOISED) {
+ ++index;
+ }
+
+ return index;
+}
+
+static int pass_to_index(const BufferPass &pass)
+{
+ return pass_type_mode_to_index(pass.type, pass.mode);
+}
+
+/* --------------------------------------------------------------------
+ * Buffer pass.
+ */
+
+NODE_DEFINE(BufferPass)
+{
+ NodeType *type = NodeType::add("buffer_pass", create);
+
+ const NodeEnum *pass_type_enum = Pass::get_type_enum();
+ const NodeEnum *pass_mode_enum = Pass::get_mode_enum();
+
+ SOCKET_ENUM(type, "Type", *pass_type_enum, PASS_COMBINED);
+ SOCKET_ENUM(mode, "Mode", *pass_mode_enum, static_cast<int>(PassMode::DENOISED));
+ SOCKET_STRING(name, "Name", ustring());
+ SOCKET_BOOLEAN(include_albedo, "Include Albedo", false);
+
+ SOCKET_INT(offset, "Offset", -1);
+
+ return type;
+}
+
+BufferPass::BufferPass() : Node(get_node_type())
+{
+}
+
+BufferPass::BufferPass(const Pass *scene_pass)
+ : Node(get_node_type()),
+ type(scene_pass->get_type()),
+ mode(scene_pass->get_mode()),
+ name(scene_pass->get_name()),
+ include_albedo(scene_pass->get_include_albedo())
+{
+}
+
+PassInfo BufferPass::get_info() const
+{
+ return Pass::get_info(type, include_albedo);
+}
+
+/* --------------------------------------------------------------------
+ * Buffer Params.
+ */
+
+NODE_DEFINE(BufferParams)
+{
+ NodeType *type = NodeType::add("buffer_params", create);
+
+ SOCKET_INT(width, "Width", 0);
+ SOCKET_INT(height, "Height", 0);
+
+ SOCKET_INT(window_x, "Window X", 0);
+ SOCKET_INT(window_y, "Window Y", 0);
+ SOCKET_INT(window_width, "Window Width", 0);
+ SOCKET_INT(window_height, "Window Height", 0);
+
+ SOCKET_INT(full_x, "Full X", 0);
+ SOCKET_INT(full_y, "Full Y", 0);
+ SOCKET_INT(full_width, "Full Width", 0);
+ SOCKET_INT(full_height, "Full Height", 0);
+
+ SOCKET_STRING(layer, "Layer", ustring());
+ SOCKET_STRING(view, "View", ustring());
+ SOCKET_INT(samples, "Samples", 0);
+ SOCKET_FLOAT(exposure, "Exposure", 1.0f);
+ SOCKET_BOOLEAN(use_approximate_shadow_catcher, "Use Approximate Shadow Catcher", false);
+ SOCKET_BOOLEAN(use_transparent_background, "Transparent Background", false);
+
+ /* Notes:
+ * - Skip passes since they do not follow typical container socket definition.
+ * Might look into covering those as a socket in the future.
+ *
+ * - Skip offset, stride, and pass stride since those can be delivered from the passes and
+ * rest of the sockets. */
+
+ return type;
+}
+
+BufferParams::BufferParams() : Node(get_node_type())
+{
+ reset_pass_offset();
+}
+
+void BufferParams::update_passes()
+{
+ update_offset_stride();
+ reset_pass_offset();
+
+ pass_stride = 0;
+ for (const BufferPass &pass : passes) {
+ if (pass.offset != PASS_UNUSED) {
+ const int index = pass_to_index(pass);
+ if (pass_offset_[index] == PASS_UNUSED) {
+ pass_offset_[index] = pass_stride;
+ }
+
+ pass_stride += pass.get_info().num_components;
+ }
+ }
+}
+
+void BufferParams::update_passes(const vector<Pass *> &scene_passes)
+{
+ passes.clear();
+
+ pass_stride = 0;
+ for (const Pass *scene_pass : scene_passes) {
+ BufferPass buffer_pass(scene_pass);
+
+ if (scene_pass->is_written()) {
+ buffer_pass.offset = pass_stride;
+ pass_stride += scene_pass->get_info().num_components;
+ }
+ else {
+ buffer_pass.offset = PASS_UNUSED;
+ }
+
+ passes.emplace_back(std::move(buffer_pass));
+ }
+
+ update_passes();
+}
+
+void BufferParams::reset_pass_offset()
+{
+ for (int i = 0; i < kNumPassOffsets; ++i) {
+ pass_offset_[i] = PASS_UNUSED;
+ }
+}
+
+int BufferParams::get_pass_offset(PassType pass_type, PassMode mode) const
+{
+ if (pass_type == PASS_NONE || pass_type == PASS_UNUSED) {
+ return PASS_UNUSED;
+ }
+
+ const int index = pass_type_mode_to_index(pass_type, mode);
+ return pass_offset_[index];
+}
+
+const BufferPass *BufferParams::find_pass(string_view name) const
+{
+ for (const BufferPass &pass : passes) {
+ if (pass.name == name) {
+ return &pass;
+ }
+ }
+
+ return nullptr;
+}
+
+const BufferPass *BufferParams::find_pass(PassType type, PassMode mode) const
+{
+ for (const BufferPass &pass : passes) {
+ if (pass.type == type && pass.mode == mode) {
+ return &pass;
+ }
+ }
+
+ return nullptr;
+}
+
+const BufferPass *BufferParams::get_actual_display_pass(PassType type, PassMode mode) const
+{
+ const BufferPass *pass = find_pass(type, mode);
+ return get_actual_display_pass(pass);
+}
+
+const BufferPass *BufferParams::get_actual_display_pass(const BufferPass *pass) const
+{
+ if (!pass) {
+ return nullptr;
+ }
+
+ if (pass->type == PASS_COMBINED) {
+ const BufferPass *shadow_catcher_matte_pass = find_pass(PASS_SHADOW_CATCHER_MATTE, pass->mode);
+ if (shadow_catcher_matte_pass) {
+ pass = shadow_catcher_matte_pass;
+ }
+ }
+
+ return pass;
+}
+
+void BufferParams::update_offset_stride()
+{
+ offset = -(full_x + full_y * width);
+ stride = width;
+}
+
+bool BufferParams::modified(const BufferParams &other) const
+{
+ if (width != other.width || height != other.height) {
+ return true;
+ }
+
+ if (full_x != other.full_x || full_y != other.full_y || full_width != other.full_width ||
+ full_height != other.full_height) {
+ return true;
+ }
+
+ if (window_x != other.window_x || window_y != other.window_y ||
+ window_width != other.window_width || window_height != other.window_height) {
+ return true;
+ }
+
+ if (offset != other.offset || stride != other.stride || pass_stride != other.pass_stride) {
+ return true;
+ }
+
+ if (layer != other.layer || view != other.view) {
+ return true;
+ }
+
+ if (exposure != other.exposure ||
+ use_approximate_shadow_catcher != other.use_approximate_shadow_catcher ||
+ use_transparent_background != other.use_transparent_background) {
+ return true;
+ }
+
+ return !(passes == other.passes);
+}
+
+/* --------------------------------------------------------------------
+ * Render Buffers.
+ */
+
+RenderBuffers::RenderBuffers(Device *device) : buffer(device, "RenderBuffers", MEM_READ_WRITE)
+{
+}
+
+RenderBuffers::~RenderBuffers()
+{
+ buffer.free();
+}
+
+void RenderBuffers::reset(const BufferParams &params_)
+{
+ DCHECK(params_.pass_stride != -1);
+
+ params = params_;
+
+ /* re-allocate buffer */
+ buffer.alloc(params.width * params.pass_stride, params.height);
+}
+
+void RenderBuffers::zero()
+{
+ buffer.zero_to_device();
+}
+
+bool RenderBuffers::copy_from_device()
+{
+ DCHECK(params.pass_stride != -1);
+
+ if (!buffer.device_pointer)
+ return false;
+
+ buffer.copy_from_device(0, params.width * params.pass_stride, params.height);
+
+ return true;
+}
+
+void RenderBuffers::copy_to_device()
+{
+ buffer.copy_to_device();
+}
+
+void render_buffers_host_copy_denoised(RenderBuffers *dst,
+ const BufferParams &dst_params,
+ const RenderBuffers *src,
+ const BufferParams &src_params,
+ const size_t src_offset)
+{
+ DCHECK_EQ(dst_params.width, src_params.width);
+ /* TODO(sergey): More sanity checks to avoid buffer overrun. */
+
+ /* Create a map of pass offsets to be copied.
+ * Assume offsets are different to allow copying passes between buffers with different set of
+ * passes. */
+
+ struct {
+ int dst_offset;
+ int src_offset;
+ } pass_offsets[PASS_NUM];
+
+ int num_passes = 0;
+
+ for (int i = 0; i < PASS_NUM; ++i) {
+ const PassType pass_type = static_cast<PassType>(i);
+
+ const int dst_pass_offset = dst_params.get_pass_offset(pass_type, PassMode::DENOISED);
+ if (dst_pass_offset == PASS_UNUSED) {
+ continue;
+ }
+
+ const int src_pass_offset = src_params.get_pass_offset(pass_type, PassMode::DENOISED);
+ if (src_pass_offset == PASS_UNUSED) {
+ continue;
+ }
+
+ pass_offsets[num_passes].dst_offset = dst_pass_offset;
+ pass_offsets[num_passes].src_offset = src_pass_offset;
+ ++num_passes;
+ }
+
+ /* Copy passes. */
+ /* TODO(sergey): Make it more reusable, allowing implement copy of noisy passes. */
+
+ const int64_t dst_width = dst_params.width;
+ const int64_t dst_height = dst_params.height;
+ const int64_t dst_pass_stride = dst_params.pass_stride;
+ const int64_t dst_num_pixels = dst_width * dst_height;
+
+ const int64_t src_pass_stride = src_params.pass_stride;
+ const int64_t src_offset_in_floats = src_offset * src_pass_stride;
+
+ const float *src_pixel = src->buffer.data() + src_offset_in_floats;
+ float *dst_pixel = dst->buffer.data();
+
+ for (int i = 0; i < dst_num_pixels;
+ ++i, src_pixel += src_pass_stride, dst_pixel += dst_pass_stride) {
+ for (int pass_offset_idx = 0; pass_offset_idx < num_passes; ++pass_offset_idx) {
+ const int dst_pass_offset = pass_offsets[pass_offset_idx].dst_offset;
+ const int src_pass_offset = pass_offsets[pass_offset_idx].src_offset;
+
+ /* TODO(sergey): Support non-RGBA passes. */
+ dst_pixel[dst_pass_offset + 0] = src_pixel[src_pass_offset + 0];
+ dst_pixel[dst_pass_offset + 1] = src_pixel[src_pass_offset + 1];
+ dst_pixel[dst_pass_offset + 2] = src_pixel[src_pass_offset + 2];
+ dst_pixel[dst_pass_offset + 3] = src_pixel[src_pass_offset + 3];
+ }
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/session/buffers.h b/intern/cycles/session/buffers.h
new file mode 100644
index 00000000000..67022bb5b6b
--- /dev/null
+++ b/intern/cycles/session/buffers.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BUFFERS_H__
+#define __BUFFERS_H__
+
+#include "device/memory.h"
+#include "graph/node.h"
+#include "scene/pass.h"
+
+#include "kernel/types.h"
+
+#include "util/half.h"
+#include "util/string.h"
+#include "util/thread.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+struct DeviceDrawParams;
+struct float4;
+
+/* NOTE: Is not a real scene node. Using Node API for ease of (de)serialization. */
+class BufferPass : public Node {
+ public:
+ NODE_DECLARE
+
+ PassType type = PASS_NONE;
+ PassMode mode = PassMode::NOISY;
+ ustring name;
+ bool include_albedo = false;
+
+ int offset = -1;
+
+ BufferPass();
+ explicit BufferPass(const Pass *scene_pass);
+
+ BufferPass(BufferPass &&other) noexcept = default;
+ BufferPass(const BufferPass &other) = default;
+
+ BufferPass &operator=(BufferPass &&other) = default;
+ BufferPass &operator=(const BufferPass &other) = default;
+
+ ~BufferPass() = default;
+
+ PassInfo get_info() const;
+
+ inline bool operator==(const BufferPass &other) const
+ {
+ return type == other.type && mode == other.mode && name == other.name &&
+ include_albedo == other.include_albedo && offset == other.offset;
+ }
+ inline bool operator!=(const BufferPass &other) const
+ {
+ return !(*this == other);
+ }
+};
+
+/* Buffer Parameters
+ * Size of render buffer and how it fits in the full image (border render). */
+
+/* NOTE: Is not a real scene node. Using Node API for ease of (de)serialization. */
+class BufferParams : public Node {
+ public:
+ NODE_DECLARE
+
+ /* Width/height of the physical buffer. */
+ int width = 0;
+ int height = 0;
+
+ /* Windows defines which part of the buffers is visible. The part outside of the window is
+ * considered an "overscan".
+ *
+ * Window X and Y are relative to the position of the buffer in the full buffer. */
+ int window_x = 0;
+ int window_y = 0;
+ int window_width = 0;
+ int window_height = 0;
+
+ /* Offset into and width/height of the full buffer. */
+ int full_x = 0;
+ int full_y = 0;
+ int full_width = 0;
+ int full_height = 0;
+
+ /* Runtime fields, only valid after `update_passes()` or `update_offset_stride()`. */
+ int offset = -1, stride = -1;
+
+ /* Runtime fields, only valid after `update_passes()`. */
+ int pass_stride = -1;
+
+ /* Properties which are used for accessing buffer pixels outside of scene graph. */
+ vector<BufferPass> passes;
+ ustring layer;
+ ustring view;
+ int samples = 0;
+ float exposure = 1.0f;
+ bool use_approximate_shadow_catcher = false;
+ bool use_transparent_background = false;
+
+ BufferParams();
+
+ BufferParams(BufferParams &&other) noexcept = default;
+ BufferParams(const BufferParams &other) = default;
+
+ BufferParams &operator=(BufferParams &&other) = default;
+ BufferParams &operator=(const BufferParams &other) = default;
+
+ ~BufferParams() = default;
+
+ /* Pre-calculate all fields which depends on the passes.
+ *
+ * When the scene passes are given, the buffer passes will be created from them and stored in
+ * this params, and then params are updated for those passes.
+ * The `update_passes()` without parameters updates offsets and strides which are stored outside
+ * of the passes. */
+ void update_passes();
+ void update_passes(const vector<Pass *> &scene_passes);
+
+ /* Returns PASS_UNUSED if there is no such pass in the buffer. */
+ int get_pass_offset(PassType type, PassMode mode = PassMode::NOISY) const;
+
+ /* Returns nullptr if pass with given name does not exist. */
+ const BufferPass *find_pass(string_view name) const;
+ const BufferPass *find_pass(PassType type, PassMode mode = PassMode::NOISY) const;
+
+ /* Get display pass from its name.
+ * Will do special logic to replace combined pass with shadow catcher matte. */
+ const BufferPass *get_actual_display_pass(PassType type, PassMode mode = PassMode::NOISY) const;
+ const BufferPass *get_actual_display_pass(const BufferPass *pass) const;
+
+ void update_offset_stride();
+
+ bool modified(const BufferParams &other) const;
+
+ protected:
+ void reset_pass_offset();
+
+ /* Multiplied by 2 to be able to store noisy and denoised pass types. */
+ static constexpr int kNumPassOffsets = PASS_NUM * 2;
+
+ /* Indexed by an index derived from pass type and mode, indicates offset of the corresponding
+ * pass in the buffer.
+ * If there are multiple passes with same type and mode contains lowest offset of all of them. */
+ int pass_offset_[kNumPassOffsets];
+};
+
+/* Render Buffers */
+
+class RenderBuffers {
+ public:
+ /* buffer parameters */
+ BufferParams params;
+
+ /* float buffer */
+ device_vector<float> buffer;
+
+ explicit RenderBuffers(Device *device);
+ ~RenderBuffers();
+
+ void reset(const BufferParams &params);
+ void zero();
+
+ bool copy_from_device();
+ void copy_to_device();
+};
+
+/* Copy denoised passes form source to destination.
+ *
+ * Buffer parameters are provided explicitly, allowing to copy pixels between render buffers which
+ * content corresponds to a render result at a non-unit resolution divider.
+ *
+ * `src_offset` allows to offset source pixel index which is used when a fraction of the source
+ * buffer is to be copied.
+ *
+ * Copy happens of the number of pixels in the destination. */
+void render_buffers_host_copy_denoised(RenderBuffers *dst,
+ const BufferParams &dst_params,
+ const RenderBuffers *src,
+ const BufferParams &src_params,
+ const size_t src_offset = 0);
+
+CCL_NAMESPACE_END
+
+#endif /* __BUFFERS_H__ */
diff --git a/intern/cycles/session/denoising.cpp b/intern/cycles/session/denoising.cpp
new file mode 100644
index 00000000000..21df068092a
--- /dev/null
+++ b/intern/cycles/session/denoising.cpp
@@ -0,0 +1,934 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "session/denoising.h"
+
+#if 0
+
+# include "kernel/filter/filter_defines.h"
+
+# include "util/util_foreach.h"
+# include "util/util_map.h"
+# include "util/util_system.h"
+# include "util/util_task.h"
+# include "util/util_time.h"
+
+# include <OpenImageIO/filesystem.h>
+
+CCL_NAMESPACE_BEGIN
+
+/* Utility Functions */
+
+static void print_progress(int num, int total, int frame, int num_frames)
+{
+ const char *label = "Denoise Frame ";
+ int cols = system_console_width();
+
+ cols -= strlen(label);
+
+ int len = 1;
+ for (int x = total; x > 9; x /= 10) {
+ len++;
+ }
+
+ int bars = cols - 2 * len - 6;
+
+ printf("\r%s", label);
+
+ if (num_frames > 1) {
+ int frame_len = 1;
+ for (int x = num_frames - 1; x > 9; x /= 10) {
+ frame_len++;
+ }
+ bars -= frame_len + 2;
+ printf("%*d ", frame_len, frame);
+ }
+
+ int v = int(float(num) * bars / total);
+ printf("[");
+ for (int i = 0; i < v; i++) {
+ printf("=");
+ }
+ if (v < bars) {
+ printf(">");
+ }
+ for (int i = v + 1; i < bars; i++) {
+ printf(" ");
+ }
+ printf(string_printf("] %%%dd / %d", len, total).c_str(), num);
+ fflush(stdout);
+}
+
+/* Splits in at its last dot, setting suffix to the part after the dot and in to the part before
+ * it. Returns whether a dot was found. */
+static bool split_last_dot(string &in, string &suffix)
+{
+ size_t pos = in.rfind(".");
+ if (pos == string::npos) {
+ return false;
+ }
+ suffix = in.substr(pos + 1);
+ in = in.substr(0, pos);
+ return true;
+}
+
+/* Separate channel names as generated by Blender.
+ * If views is true:
+ * Inputs are expected in the form RenderLayer.Pass.View.Channel, sets renderlayer to
+ * "RenderLayer.View" Otherwise: Inputs are expected in the form RenderLayer.Pass.Channel */
+static bool parse_channel_name(
+ string name, string &renderlayer, string &pass, string &channel, bool multiview_channels)
+{
+ if (!split_last_dot(name, channel)) {
+ return false;
+ }
+ string view;
+ if (multiview_channels && !split_last_dot(name, view)) {
+ return false;
+ }
+ if (!split_last_dot(name, pass)) {
+ return false;
+ }
+ renderlayer = name;
+
+ if (multiview_channels) {
+ renderlayer += "." + view;
+ }
+
+ return true;
+}
+
+/* Channel Mapping */
+
+struct ChannelMapping {
+ int channel;
+ string name;
+};
+
+static void fill_mapping(vector<ChannelMapping> &map, int pos, string name, string channels)
+{
+ for (const char *chan = channels.c_str(); *chan; chan++) {
+ map.push_back({pos++, name + "." + *chan});
+ }
+}
+
+static const int INPUT_NUM_CHANNELS = 15;
+static const int INPUT_DENOISING_DEPTH = 0;
+static const int INPUT_DENOISING_NORMAL = 1;
+static const int INPUT_DENOISING_SHADOWING = 4;
+static const int INPUT_DENOISING_ALBEDO = 5;
+static const int INPUT_NOISY_IMAGE = 8;
+static const int INPUT_DENOISING_VARIANCE = 11;
+static const int INPUT_DENOISING_INTENSITY = 14;
+static vector<ChannelMapping> input_channels()
+{
+ vector<ChannelMapping> map;
+ fill_mapping(map, INPUT_DENOISING_DEPTH, "Denoising Depth", "Z");
+ fill_mapping(map, INPUT_DENOISING_NORMAL, "Denoising Normal", "XYZ");
+ fill_mapping(map, INPUT_DENOISING_SHADOWING, "Denoising Shadowing", "X");
+ fill_mapping(map, INPUT_DENOISING_ALBEDO, "Denoising Albedo", "RGB");
+ fill_mapping(map, INPUT_NOISY_IMAGE, "Noisy Image", "RGB");
+ fill_mapping(map, INPUT_DENOISING_VARIANCE, "Denoising Variance", "RGB");
+ fill_mapping(map, INPUT_DENOISING_INTENSITY, "Denoising Intensity", "X");
+ return map;
+}
+
+static const int OUTPUT_NUM_CHANNELS = 3;
+static vector<ChannelMapping> output_channels()
+{
+ vector<ChannelMapping> map;
+ fill_mapping(map, 0, "Combined", "RGB");
+ return map;
+}
+
+/* Renderlayer Handling */
+
+bool DenoiseImageLayer::detect_denoising_channels()
+{
+ /* Map device input to image channels. */
+ input_to_image_channel.clear();
+ input_to_image_channel.resize(INPUT_NUM_CHANNELS, -1);
+
+ foreach (const ChannelMapping &mapping, input_channels()) {
+ vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name);
+ if (i == channels.end()) {
+ return false;
+ }
+
+ size_t input_channel = mapping.channel;
+ size_t layer_channel = i - channels.begin();
+ input_to_image_channel[input_channel] = layer_to_image_channel[layer_channel];
+ }
+
+ /* Map device output to image channels. */
+ output_to_image_channel.clear();
+ output_to_image_channel.resize(OUTPUT_NUM_CHANNELS, -1);
+
+ foreach (const ChannelMapping &mapping, output_channels()) {
+ vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name);
+ if (i == channels.end()) {
+ return false;
+ }
+
+ size_t output_channel = mapping.channel;
+ size_t layer_channel = i - channels.begin();
+ output_to_image_channel[output_channel] = layer_to_image_channel[layer_channel];
+ }
+
+ /* Check that all buffer channels are correctly set. */
+ for (int i = 0; i < INPUT_NUM_CHANNELS; i++) {
+ assert(input_to_image_channel[i] >= 0);
+ }
+ for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
+ assert(output_to_image_channel[i] >= 0);
+ }
+
+ return true;
+}
+
+bool DenoiseImageLayer::match_channels(int neighbor,
+ const std::vector<string> &channelnames,
+ const std::vector<string> &neighbor_channelnames)
+{
+ neighbor_input_to_image_channel.resize(neighbor + 1);
+ vector<int> &mapping = neighbor_input_to_image_channel[neighbor];
+
+ assert(mapping.size() == 0);
+ mapping.resize(input_to_image_channel.size(), -1);
+
+ for (int i = 0; i < input_to_image_channel.size(); i++) {
+ const string &channel = channelnames[input_to_image_channel[i]];
+ std::vector<string>::const_iterator frame_channel = find(
+ neighbor_channelnames.begin(), neighbor_channelnames.end(), channel);
+
+ if (frame_channel == neighbor_channelnames.end()) {
+ return false;
+ }
+
+ mapping[i] = frame_channel - neighbor_channelnames.begin();
+ }
+
+ return true;
+}
+
+/* Denoise Task */
+
+DenoiseTask::DenoiseTask(Device *device,
+ DenoiserPipeline *denoiser,
+ int frame,
+ const vector<int> &neighbor_frames)
+ : denoiser(denoiser),
+ device(device),
+ frame(frame),
+ neighbor_frames(neighbor_frames),
+ current_layer(0),
+ input_pixels(device, "filter input buffer", MEM_READ_ONLY),
+ num_tiles(0)
+{
+ image.samples = denoiser->samples_override;
+}
+
+DenoiseTask::~DenoiseTask()
+{
+ free();
+}
+
+/* Device callbacks */
+
+bool DenoiseTask::acquire_tile(Device *device, Device *tile_device, RenderTile &tile)
+{
+ thread_scoped_lock tile_lock(tiles_mutex);
+
+ if (tiles.empty()) {
+ return false;
+ }
+
+ tile = tiles.front();
+ tiles.pop_front();
+
+ device->map_tile(tile_device, tile);
+
+ print_progress(num_tiles - tiles.size(), num_tiles, frame, denoiser->num_frames);
+
+ return true;
+}
+
+/* Mapping tiles is required for regular rendering since each tile has its separate memory
+ * which may be allocated on a different device.
+ * For standalone denoising, there is a single memory that is present on all devices, so the only
+ * thing that needs to be done here is to specify the surrounding tile geometry.
+ *
+ * However, since there is only one large memory, the denoised result has to be written to
+ * a different buffer to avoid having to copy an entire horizontal slice of the image. */
+void DenoiseTask::map_neighboring_tiles(RenderTileNeighbors &neighbors, Device *tile_device)
+{
+ RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
+ RenderTile &target_tile = neighbors.target;
+
+ /* Fill tile information. */
+ for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
+ if (i == RenderTileNeighbors::CENTER) {
+ continue;
+ }
+
+ RenderTile &tile = neighbors.tiles[i];
+ int dx = (i % 3) - 1;
+ int dy = (i / 3) - 1;
+ tile.x = clamp(center_tile.x + dx * denoiser->tile_size.x, 0, image.width);
+ tile.w = clamp(center_tile.x + (dx + 1) * denoiser->tile_size.x, 0, image.width) - tile.x;
+ tile.y = clamp(center_tile.y + dy * denoiser->tile_size.y, 0, image.height);
+ tile.h = clamp(center_tile.y + (dy + 1) * denoiser->tile_size.y, 0, image.height) - tile.y;
+
+ tile.buffer = center_tile.buffer;
+ tile.offset = center_tile.offset;
+ tile.stride = image.width;
+ }
+
+ /* Allocate output buffer. */
+ device_vector<float> *output_mem = new device_vector<float>(
+ tile_device, "denoising_output", MEM_READ_WRITE);
+ output_mem->alloc(OUTPUT_NUM_CHANNELS * center_tile.w * center_tile.h);
+
+ /* Fill output buffer with noisy image, assumed by kernel_filter_finalize
+ * when skipping denoising of some pixels. */
+ float *result = output_mem->data();
+ float *in = &image.pixels[image.num_channels * (center_tile.y * image.width + center_tile.x)];
+
+ const DenoiseImageLayer &layer = image.layers[current_layer];
+ const int *input_to_image_channel = layer.input_to_image_channel.data();
+
+ for (int y = 0; y < center_tile.h; y++) {
+ for (int x = 0; x < center_tile.w; x++, result += OUTPUT_NUM_CHANNELS) {
+ for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
+ result[i] = in[image.num_channels * x + input_to_image_channel[INPUT_NOISY_IMAGE + i]];
+ }
+ }
+ in += image.num_channels * image.width;
+ }
+
+ output_mem->copy_to_device();
+
+ /* Fill output tile info. */
+ target_tile = center_tile;
+ target_tile.buffer = output_mem->device_pointer;
+ target_tile.stride = target_tile.w;
+ target_tile.offset -= target_tile.x + target_tile.y * target_tile.stride;
+
+ thread_scoped_lock output_lock(output_mutex);
+ assert(output_pixels.count(center_tile.tile_index) == 0);
+ output_pixels[target_tile.tile_index] = output_mem;
+}
+
+void DenoiseTask::unmap_neighboring_tiles(RenderTileNeighbors &neighbors)
+{
+ RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
+ RenderTile &target_tile = neighbors.target;
+
+ thread_scoped_lock output_lock(output_mutex);
+ assert(output_pixels.count(center_tile.tile_index) == 1);
+ device_vector<float> *output_mem = output_pixels[target_tile.tile_index];
+ output_pixels.erase(center_tile.tile_index);
+ output_lock.unlock();
+
+ /* Copy denoised pixels from device. */
+ output_mem->copy_from_device(0, OUTPUT_NUM_CHANNELS * target_tile.w, target_tile.h);
+
+ float *result = output_mem->data();
+ float *out = &image.pixels[image.num_channels * (target_tile.y * image.width + target_tile.x)];
+
+ const DenoiseImageLayer &layer = image.layers[current_layer];
+ const int *output_to_image_channel = layer.output_to_image_channel.data();
+
+ for (int y = 0; y < target_tile.h; y++) {
+ for (int x = 0; x < target_tile.w; x++, result += OUTPUT_NUM_CHANNELS) {
+ for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
+ out[image.num_channels * x + output_to_image_channel[i]] = result[i];
+ }
+ }
+ out += image.num_channels * image.width;
+ }
+
+ /* Free device buffer. */
+ output_mem->free();
+ delete output_mem;
+}
+
+void DenoiseTask::release_tile()
+{
+}
+
+bool DenoiseTask::get_cancel()
+{
+ return false;
+}
+
+void DenoiseTask::create_task(DeviceTask &task)
+{
+ /* Callback functions. */
+ task.acquire_tile = function_bind(&DenoiseTask::acquire_tile, this, device, _1, _2);
+ task.map_neighbor_tiles = function_bind(&DenoiseTask::map_neighboring_tiles, this, _1, _2);
+ task.unmap_neighbor_tiles = function_bind(&DenoiseTask::unmap_neighboring_tiles, this, _1);
+ task.release_tile = function_bind(&DenoiseTask::release_tile, this);
+ task.get_cancel = function_bind(&DenoiseTask::get_cancel, this);
+
+ /* Denoising parameters. */
+ task.denoising = denoiser->params;
+ task.denoising.type = DENOISER_NLM;
+ task.denoising.use = true;
+ task.denoising_from_render = false;
+
+ task.denoising_frames.resize(neighbor_frames.size());
+ for (int i = 0; i < neighbor_frames.size(); i++) {
+ task.denoising_frames[i] = neighbor_frames[i] - frame;
+ }
+
+ /* Buffer parameters. */
+ task.pass_stride = INPUT_NUM_CHANNELS;
+ task.target_pass_stride = OUTPUT_NUM_CHANNELS;
+ task.pass_denoising_data = 0;
+ task.pass_denoising_clean = -1;
+ task.frame_stride = image.width * image.height * INPUT_NUM_CHANNELS;
+
+ /* Create tiles. */
+ thread_scoped_lock tile_lock(tiles_mutex);
+ thread_scoped_lock output_lock(output_mutex);
+
+ tiles.clear();
+ assert(output_pixels.empty());
+ output_pixels.clear();
+
+ int tiles_x = divide_up(image.width, denoiser->tile_size.x);
+ int tiles_y = divide_up(image.height, denoiser->tile_size.y);
+
+ for (int ty = 0; ty < tiles_y; ty++) {
+ for (int tx = 0; tx < tiles_x; tx++) {
+ RenderTile tile;
+ tile.x = tx * denoiser->tile_size.x;
+ tile.y = ty * denoiser->tile_size.y;
+ tile.w = min(image.width - tile.x, denoiser->tile_size.x);
+ tile.h = min(image.height - tile.y, denoiser->tile_size.y);
+ tile.start_sample = 0;
+ tile.num_samples = image.layers[current_layer].samples;
+ tile.sample = 0;
+ tile.offset = 0;
+ tile.stride = image.width;
+ tile.tile_index = ty * tiles_x + tx;
+ tile.task = RenderTile::DENOISE;
+ tile.buffers = NULL;
+ tile.buffer = input_pixels.device_pointer;
+ tiles.push_back(tile);
+ }
+ }
+
+ num_tiles = tiles.size();
+}
+
+/* Denoiser Operations */
+
+bool DenoiseTask::load_input_pixels(int layer)
+{
+ int w = image.width;
+ int h = image.height;
+ int num_pixels = image.width * image.height;
+ int frame_stride = num_pixels * INPUT_NUM_CHANNELS;
+
+ /* Load center image */
+ DenoiseImageLayer &image_layer = image.layers[layer];
+
+ float *buffer_data = input_pixels.data();
+ image.read_pixels(image_layer, buffer_data);
+ buffer_data += frame_stride;
+
+ /* Load neighbor images */
+ for (int i = 0; i < image.in_neighbors.size(); i++) {
+ if (!image.read_neighbor_pixels(i, image_layer, buffer_data)) {
+ error = "Failed to read neighbor frame pixels";
+ return false;
+ }
+ buffer_data += frame_stride;
+ }
+
+ /* Preprocess */
+ buffer_data = input_pixels.data();
+ for (int neighbor = 0; neighbor < image.in_neighbors.size() + 1; neighbor++) {
+ /* Clamp */
+ if (denoiser->params.clamp_input) {
+ for (int i = 0; i < num_pixels * INPUT_NUM_CHANNELS; i++) {
+ buffer_data[i] = clamp(buffer_data[i], -1e8f, 1e8f);
+ }
+ }
+
+ /* Box blur */
+ int r = 5 * denoiser->params.radius;
+ float *data = buffer_data + 14;
+ array<float> temp(num_pixels);
+
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int n = 0;
+ float sum = 0.0f;
+ for (int dx = max(x - r, 0); dx < min(x + r + 1, w); dx++, n++) {
+ sum += data[INPUT_NUM_CHANNELS * (y * w + dx)];
+ }
+ temp[y * w + x] = sum / n;
+ }
+ }
+
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int n = 0;
+ float sum = 0.0f;
+
+ for (int dy = max(y - r, 0); dy < min(y + r + 1, h); dy++, n++) {
+ sum += temp[dy * w + x];
+ }
+
+ data[INPUT_NUM_CHANNELS * (y * w + x)] = sum / n;
+ }
+ }
+
+ /* Highlight compression */
+ data = buffer_data + 8;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int idx = INPUT_NUM_CHANNELS * (y * w + x);
+ float3 color = make_float3(data[idx], data[idx + 1], data[idx + 2]);
+ color = color_highlight_compress(color, NULL);
+ data[idx] = color.x;
+ data[idx + 1] = color.y;
+ data[idx + 2] = color.z;
+ }
+ }
+
+ buffer_data += frame_stride;
+ }
+
+ /* Copy to device */
+ input_pixels.copy_to_device();
+
+ return true;
+}
+
+/* Task stages */
+
+bool DenoiseTask::load()
+{
+ string center_filepath = denoiser->input[frame];
+ if (!image.load(center_filepath, error)) {
+ return false;
+ }
+
+ if (!image.load_neighbors(denoiser->input, neighbor_frames, error)) {
+ return false;
+ }
+
+ if (image.layers.empty()) {
+ error = "No image layers found to denoise in " + center_filepath;
+ return false;
+ }
+
+ /* Allocate device buffer. */
+ int num_frames = image.in_neighbors.size() + 1;
+ input_pixels.alloc(image.width * INPUT_NUM_CHANNELS, image.height * num_frames);
+ input_pixels.zero_to_device();
+
+ /* Read pixels for first layer. */
+ current_layer = 0;
+ if (!load_input_pixels(current_layer)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool DenoiseTask::exec()
+{
+ for (current_layer = 0; current_layer < image.layers.size(); current_layer++) {
+ /* Read pixels for secondary layers, first was already loaded. */
+ if (current_layer > 0) {
+ if (!load_input_pixels(current_layer)) {
+ return false;
+ }
+ }
+
+ /* Run task on device. */
+ DeviceTask task(DeviceTask::RENDER);
+ create_task(task);
+ device->task_add(task);
+ device->task_wait();
+
+ printf("\n");
+ }
+
+ return true;
+}
+
+bool DenoiseTask::save()
+{
+ bool ok = image.save_output(denoiser->output[frame], error);
+ free();
+ return ok;
+}
+
+void DenoiseTask::free()
+{
+ image.free();
+ input_pixels.free();
+ assert(output_pixels.empty());
+}
+
+/* Denoise Image Storage */
+
+DenoiseImage::DenoiseImage()
+{
+ width = 0;
+ height = 0;
+ num_channels = 0;
+ samples = 0;
+}
+
+DenoiseImage::~DenoiseImage()
+{
+ free();
+}
+
+void DenoiseImage::close_input()
+{
+ in_neighbors.clear();
+}
+
+void DenoiseImage::free()
+{
+ close_input();
+ pixels.clear();
+}
+
+bool DenoiseImage::parse_channels(const ImageSpec &in_spec, string &error)
+{
+ const std::vector<string> &channels = in_spec.channelnames;
+ const ParamValue *multiview = in_spec.find_attribute("multiView");
+ const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING &&
+ multiview->type().arraylen >= 2);
+
+ layers.clear();
+
+ /* Loop over all the channels in the file, parse their name and sort them
+ * by RenderLayer.
+ * Channels that can't be parsed are directly passed through to the output. */
+ map<string, DenoiseImageLayer> file_layers;
+ for (int i = 0; i < channels.size(); i++) {
+ string layer, pass, channel;
+ if (parse_channel_name(channels[i], layer, pass, channel, multiview_channels)) {
+ file_layers[layer].channels.push_back(pass + "." + channel);
+ file_layers[layer].layer_to_image_channel.push_back(i);
+ }
+ }
+
+ /* Loop over all detected RenderLayers, check whether they contain a full set of input channels.
+ * Any channels that won't be processed internally are also passed through. */
+ for (map<string, DenoiseImageLayer>::iterator i = file_layers.begin(); i != file_layers.end();
+ ++i) {
+ const string &name = i->first;
+ DenoiseImageLayer &layer = i->second;
+
+ /* Check for full pass set. */
+ if (!layer.detect_denoising_channels()) {
+ continue;
+ }
+
+ layer.name = name;
+ layer.samples = samples;
+
+ /* If the sample value isn't set yet, check if there is a layer-specific one in the input file.
+ */
+ if (layer.samples < 1) {
+ string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", "");
+ if (sample_string != "") {
+ if (!sscanf(sample_string.c_str(), "%d", &layer.samples)) {
+ error = "Failed to parse samples metadata: " + sample_string;
+ return false;
+ }
+ }
+ }
+
+ if (layer.samples < 1) {
+ error = string_printf(
+ "No sample number specified in the file for layer %s or on the command line",
+ name.c_str());
+ return false;
+ }
+
+ layers.push_back(layer);
+ }
+
+ return true;
+}
+
+void DenoiseImage::read_pixels(const DenoiseImageLayer &layer, float *input_pixels)
+{
+ /* Pixels from center file have already been loaded into pixels.
+ * We copy a subset into the device input buffer with channels reshuffled. */
+ const int *input_to_image_channel = layer.input_to_image_channel.data();
+
+ for (int i = 0; i < width * height; i++) {
+ for (int j = 0; j < INPUT_NUM_CHANNELS; j++) {
+ int image_channel = input_to_image_channel[j];
+ input_pixels[i * INPUT_NUM_CHANNELS + j] =
+ pixels[((size_t)i) * num_channels + image_channel];
+ }
+ }
+}
+
+bool DenoiseImage::read_neighbor_pixels(int neighbor,
+ const DenoiseImageLayer &layer,
+ float *input_pixels)
+{
+ /* Load pixels from neighboring frames, and copy them into device buffer
+ * with channels reshuffled. */
+ size_t num_pixels = (size_t)width * (size_t)height;
+ array<float> neighbor_pixels(num_pixels * num_channels);
+ if (!in_neighbors[neighbor]->read_image(TypeDesc::FLOAT, neighbor_pixels.data())) {
+ return false;
+ }
+
+ const int *input_to_image_channel = layer.neighbor_input_to_image_channel[neighbor].data();
+
+ for (int i = 0; i < width * height; i++) {
+ for (int j = 0; j < INPUT_NUM_CHANNELS; j++) {
+ int image_channel = input_to_image_channel[j];
+ input_pixels[i * INPUT_NUM_CHANNELS + j] =
+ neighbor_pixels[((size_t)i) * num_channels + image_channel];
+ }
+ }
+
+ return true;
+}
+
+bool DenoiseImage::load(const string &in_filepath, string &error)
+{
+ if (!Filesystem::is_regular(in_filepath)) {
+ error = "Couldn't find file: " + in_filepath;
+ return false;
+ }
+
+ unique_ptr<ImageInput> in(ImageInput::open(in_filepath));
+ if (!in) {
+ error = "Couldn't open file: " + in_filepath;
+ return false;
+ }
+
+ in_spec = in->spec();
+ width = in_spec.width;
+ height = in_spec.height;
+ num_channels = in_spec.nchannels;
+
+ if (!parse_channels(in_spec, error)) {
+ return false;
+ }
+
+ if (layers.size() == 0) {
+ error = "Could not find a render layer containing denoising info";
+ return false;
+ }
+
+ size_t num_pixels = (size_t)width * (size_t)height;
+ pixels.resize(num_pixels * num_channels);
+
+ /* Read all channels into buffer. Reading all channels at once is faster
+ * than individually due to interleaved EXR channel storage. */
+ if (!in->read_image(TypeDesc::FLOAT, pixels.data())) {
+ error = "Failed to read image: " + in_filepath;
+ return false;
+ }
+
+ return true;
+}
+
+bool DenoiseImage::load_neighbors(const vector<string> &filepaths,
+ const vector<int> &frames,
+ string &error)
+{
+ if (frames.size() > DENOISE_MAX_FRAMES - 1) {
+ error = string_printf("Maximum number of neighbors (%d) exceeded\n", DENOISE_MAX_FRAMES - 1);
+ return false;
+ }
+
+ for (int neighbor = 0; neighbor < frames.size(); neighbor++) {
+ int frame = frames[neighbor];
+ const string &filepath = filepaths[frame];
+
+ if (!Filesystem::is_regular(filepath)) {
+ error = "Couldn't find neighbor frame: " + filepath;
+ return false;
+ }
+
+ unique_ptr<ImageInput> in_neighbor(ImageInput::open(filepath));
+ if (!in_neighbor) {
+ error = "Couldn't open neighbor frame: " + filepath;
+ return false;
+ }
+
+ const ImageSpec &neighbor_spec = in_neighbor->spec();
+ if (neighbor_spec.width != width || neighbor_spec.height != height) {
+ error = "Neighbor frame has different dimensions: " + filepath;
+ return false;
+ }
+
+ foreach (DenoiseImageLayer &layer, layers) {
+ if (!layer.match_channels(neighbor, in_spec.channelnames, neighbor_spec.channelnames)) {
+ error = "Neighbor frame misses denoising data passes: " + filepath;
+ return false;
+ }
+ }
+
+ in_neighbors.push_back(std::move(in_neighbor));
+ }
+
+ return true;
+}
+
+bool DenoiseImage::save_output(const string &out_filepath, string &error)
+{
+ /* Save image with identical dimensions, channels and metadata. */
+ ImageSpec out_spec = in_spec;
+
+ /* Ensure that the output frame contains sample information even if the input didn't. */
+ for (int i = 0; i < layers.size(); i++) {
+ string name = "cycles." + layers[i].name + ".samples";
+ if (!out_spec.find_attribute(name, TypeDesc::STRING)) {
+ out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", layers[i].samples));
+ }
+ }
+
+ /* We don't need input anymore at this point, and will possibly
+ * overwrite the same file. */
+ close_input();
+
+ /* Write to temporary file path, so we denoise images in place and don't
+ * risk destroying files when something goes wrong in file saving. */
+ string extension = OIIO::Filesystem::extension(out_filepath);
+ string unique_name = ".denoise-tmp-" + OIIO::Filesystem::unique_path();
+ string tmp_filepath = out_filepath + unique_name + extension;
+ unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath));
+
+ if (!out) {
+ error = "Failed to open temporary file " + tmp_filepath + " for writing";
+ return false;
+ }
+
+ /* Open temporary file and write image buffers. */
+ if (!out->open(tmp_filepath, out_spec)) {
+ error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror();
+ return false;
+ }
+
+ bool ok = true;
+ if (!out->write_image(TypeDesc::FLOAT, pixels.data())) {
+ error = "Failed to write to file " + tmp_filepath + ": " + out->geterror();
+ ok = false;
+ }
+
+ if (!out->close()) {
+ error = "Failed to save to file " + tmp_filepath + ": " + out->geterror();
+ ok = false;
+ }
+
+ out.reset();
+
+ /* Copy temporary file to output filepath. */
+ string rename_error;
+ if (ok && !OIIO::Filesystem::rename(tmp_filepath, out_filepath, rename_error)) {
+ error = "Failed to move denoised image to " + out_filepath + ": " + rename_error;
+ ok = false;
+ }
+
+ if (!ok) {
+ OIIO::Filesystem::remove(tmp_filepath);
+ }
+
+ return ok;
+}
+
+/* File pattern handling and outer loop over frames */
+
+DenoiserPipeline::DenoiserPipeline(DeviceInfo &device_info)
+{
+ samples_override = 0;
+ tile_size = make_int2(64, 64);
+
+ num_frames = 0;
+
+ /* Initialize task scheduler. */
+ TaskScheduler::init();
+
+ /* Initialize device. */
+ device = Device::create(device_info, stats, profiler, true);
+
+ device->load_kernels(KERNEL_FEATURE_DENOISING);
+}
+
+DenoiserPipeline::~DenoiserPipeline()
+{
+ delete device;
+ TaskScheduler::exit();
+}
+
+bool DenoiserPipeline::run()
+{
+ assert(input.size() == output.size());
+
+ num_frames = output.size();
+
+ for (int frame = 0; frame < num_frames; frame++) {
+ /* Skip empty output paths. */
+ if (output[frame].empty()) {
+ continue;
+ }
+
+ /* Determine neighbor frame numbers that should be used for filtering. */
+ vector<int> neighbor_frames;
+ for (int f = frame - params.neighbor_frames; f <= frame + params.neighbor_frames; f++) {
+ if (f >= 0 && f < num_frames && f != frame) {
+ neighbor_frames.push_back(f);
+ }
+ }
+
+ /* Execute task. */
+ DenoiseTask task(device, this, frame, neighbor_frames);
+ if (!task.load()) {
+ error = task.error;
+ return false;
+ }
+
+ if (!task.exec()) {
+ error = task.error;
+ return false;
+ }
+
+ if (!task.save()) {
+ error = task.error;
+ return false;
+ }
+
+ task.free();
+ }
+
+ return true;
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/render/denoising.h b/intern/cycles/session/denoising.h
index 097cc570d06..097cc570d06 100644
--- a/intern/cycles/render/denoising.h
+++ b/intern/cycles/session/denoising.h
diff --git a/intern/cycles/session/display_driver.h b/intern/cycles/session/display_driver.h
new file mode 100644
index 00000000000..77f89326fd0
--- /dev/null
+++ b/intern/cycles/session/display_driver.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "util/half.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Display driver for efficient interactive display of renders.
+ *
+ * Host applications implement this interface for viewport rendering. For best performance, we
+ * recommend:
+ * - Allocating a texture on the GPU to be interactively updated
+ * - Using the graphics interop mechanism to avoid CPU-GPU copying overhead
+ * - Using a dedicated or thread-safe graphics API context for updates, to avoid
+ * blocking the host application.
+ */
+class DisplayDriver {
+ public:
+ DisplayDriver() = default;
+ virtual ~DisplayDriver() = default;
+
+ /* Render buffer parameters. */
+ struct Params {
+ public:
+ /* Render resolution, ignoring progressive resolution changes.
+ * The texture buffer should be allocated with this size. */
+ int2 size = make_int2(0, 0);
+
+ /* For border rendering, the full resolution of the render, and the offset within that larger
+ * render. */
+ int2 full_size = make_int2(0, 0);
+ int2 full_offset = make_int2(0, 0);
+
+ bool modified(const Params &other) const
+ {
+ return !(full_offset == other.full_offset && full_size == other.full_size &&
+ size == other.size);
+ }
+ };
+
+ /* Update the render from the rendering thread.
+ *
+ * Cycles periodically updates the render to be displayed. For multithreaded updates with
+ * potentially multiple rendering devices, it will call these methods as follows.
+ *
+ * if (driver.update_begin(params, width, height)) {
+ * parallel_for_each(rendering_device) {
+ * buffer = driver.map_texture_buffer();
+ * if (buffer) {
+ * fill(buffer);
+ * driver.unmap_texture_buffer();
+ * }
+ * }
+ * driver.update_end();
+ * }
+ *
+ * The parameters may dynamically change due to camera changes in the scene, and resources should
+ * be re-allocated accordingly.
+ *
+ * The width and height passed to update_begin() are the effective render resolution taking into
+ * account progressive resolution changes, which may be equal to or smaller than the params.size.
+ * For efficiency, changes in this resolution should be handled without re-allocating resources,
+ * but rather by using a subset of the full resolution buffer. */
+ virtual bool update_begin(const Params &params, int width, int height) = 0;
+ virtual void update_end() = 0;
+
+ virtual half4 *map_texture_buffer() = 0;
+ virtual void unmap_texture_buffer() = 0;
+
+ /* Optionally return a handle to a native graphics API texture buffer. If supported,
+ * the rendering device may write directly to this buffer instead of calling
+ * map_texture_buffer() and unmap_texture_buffer(). */
+ class GraphicsInterop {
+ public:
+ /* Dimensions of the buffer, in pixels. */
+ int buffer_width = 0;
+ int buffer_height = 0;
+
+ /* OpenGL pixel buffer object. */
+ int opengl_pbo_id = 0;
+
+ /* Clear the entire buffer before doing partial write to it. */
+ bool need_clear = false;
+ };
+
+ virtual GraphicsInterop graphics_interop_get()
+ {
+ return GraphicsInterop();
+ }
+
+ /* (De)activate graphics context required for editing or deleting the graphics interop
+ * object.
+ *
+ * For example, destruction of the CUDA object associated with an OpenGL requires the
+ * OpenGL context to be active. */
+ virtual void graphics_interop_activate(){};
+ virtual void graphics_interop_deactivate(){};
+
+ /* Clear the display buffer by filling it with zeros. */
+ virtual void clear() = 0;
+
+ /* Draw the render using the native graphics API.
+ *
+ * Note that this may be called in parallel to updates. The implementation is responsible for
+ * mutex locking or other mechanisms to avoid conflicts.
+ *
+ * The parameters may have changed since the last update. The implementation is responsible for
+ * deciding to skip or adjust render display for such changes.
+ *
+ * Host application drawing the render buffer should use Session.draw(), which will
+ * call this method. */
+ virtual void draw(const Params &params) = 0;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/session/merge.cpp b/intern/cycles/session/merge.cpp
new file mode 100644
index 00000000000..5890c15f48c
--- /dev/null
+++ b/intern/cycles/session/merge.cpp
@@ -0,0 +1,516 @@
+/*
+ * Copyright 2011-2019 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "session/merge.h"
+
+#include "util/array.h"
+#include "util/map.h"
+#include "util/system.h"
+#include "util/time.h"
+#include "util/unique_ptr.h"
+
+#include <OpenImageIO/filesystem.h>
+#include <OpenImageIO/imageio.h>
+
+OIIO_NAMESPACE_USING
+
+CCL_NAMESPACE_BEGIN
+
+/* Merge Image Layer */
+
+enum MergeChannelOp {
+ MERGE_CHANNEL_NOP,
+ MERGE_CHANNEL_COPY,
+ MERGE_CHANNEL_SUM,
+ MERGE_CHANNEL_AVERAGE
+};
+
+struct MergeImagePass {
+ /* Full channel name. */
+ string channel_name;
+ /* Channel format in the file. */
+ TypeDesc format;
+ /* Type of operation to perform when merging. */
+ MergeChannelOp op;
+ /* Offset of layer channels in input image. */
+ int offset;
+ /* Offset of layer channels in merged image. */
+ int merge_offset;
+};
+
+struct MergeImageLayer {
+ /* Layer name. */
+ string name;
+ /* Passes. */
+ vector<MergeImagePass> passes;
+ /* Sample amount that was used for rendering this layer. */
+ int samples;
+};
+
+/* Merge Image */
+
+struct MergeImage {
+ /* OIIO file handle. */
+ unique_ptr<ImageInput> in;
+ /* Image file path. */
+ string filepath;
+ /* Render layers. */
+ vector<MergeImageLayer> layers;
+};
+
+/* Channel Parsing */
+
+static MergeChannelOp parse_channel_operation(const string &pass_name)
+{
+ if (pass_name == "Depth" || pass_name == "IndexMA" || pass_name == "IndexOB" ||
+ string_startswith(pass_name, "Crypto")) {
+ return MERGE_CHANNEL_COPY;
+ }
+ else if (string_startswith(pass_name, "Debug BVH") ||
+ string_startswith(pass_name, "Debug Ray") ||
+ string_startswith(pass_name, "Debug Render Time")) {
+ return MERGE_CHANNEL_SUM;
+ }
+ else {
+ return MERGE_CHANNEL_AVERAGE;
+ }
+}
+
+/* Splits in at its last dot, setting suffix to the part after the dot and
+ * into the part before it. Returns whether a dot was found. */
+static bool split_last_dot(string &in, string &suffix)
+{
+ size_t pos = in.rfind(".");
+ if (pos == string::npos) {
+ return false;
+ }
+ suffix = in.substr(pos + 1);
+ in = in.substr(0, pos);
+ return true;
+}
+
+/* Separate channel names as generated by Blender.
+ * Multiview format: RenderLayer.Pass.View.Channel
+ * Otherwise: RenderLayer.Pass.Channel */
+static bool parse_channel_name(
+ string name, string &renderlayer, string &pass, string &channel, bool multiview_channels)
+{
+ if (!split_last_dot(name, channel)) {
+ return false;
+ }
+ string view;
+ if (multiview_channels && !split_last_dot(name, view)) {
+ return false;
+ }
+ if (!split_last_dot(name, pass)) {
+ return false;
+ }
+ renderlayer = name;
+
+ if (multiview_channels) {
+ renderlayer += "." + view;
+ }
+
+ return true;
+}
+
+static bool parse_channels(const ImageSpec &in_spec,
+ vector<MergeImageLayer> &layers,
+ string &error)
+{
+ const ParamValue *multiview = in_spec.find_attribute("multiView");
+ const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING &&
+ multiview->type().arraylen >= 2);
+
+ layers.clear();
+
+ /* Loop over all the channels in the file, parse their name and sort them
+ * by RenderLayer.
+ * Channels that can't be parsed are directly passed through to the output. */
+ map<string, MergeImageLayer> file_layers;
+ for (int i = 0; i < in_spec.nchannels; i++) {
+ MergeImagePass pass;
+ pass.channel_name = in_spec.channelnames[i];
+ pass.format = (in_spec.channelformats.size() > 0) ? in_spec.channelformats[i] : in_spec.format;
+ pass.offset = i;
+ pass.merge_offset = i;
+
+ string layername, passname, channelname;
+ if (parse_channel_name(
+ pass.channel_name, layername, passname, channelname, multiview_channels)) {
+ /* Channel part of a render layer. */
+ pass.op = parse_channel_operation(passname);
+ }
+ else {
+ /* Other channels are added in unnamed layer. */
+ layername = "";
+ pass.op = parse_channel_operation(pass.channel_name);
+ }
+
+ file_layers[layername].passes.push_back(pass);
+ }
+
+ /* Loop over all detected render-layers, check whether they contain a full set of input channels.
+ * Any channels that won't be processed internally are also passed through. */
+ for (auto &i : file_layers) {
+ const string &name = i.first;
+ MergeImageLayer &layer = i.second;
+
+ layer.name = name;
+ layer.samples = 0;
+
+ /* Determine number of samples from metadata. */
+ if (layer.name == "") {
+ layer.samples = 1;
+ }
+ else if (layer.samples < 1) {
+ string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", "");
+ if (sample_string != "") {
+ if (!sscanf(sample_string.c_str(), "%d", &layer.samples)) {
+ error = "Failed to parse samples metadata: " + sample_string;
+ return false;
+ }
+ }
+ }
+
+ if (layer.samples < 1) {
+ error = string_printf(
+ "No sample number specified in the file for layer %s or on the command line",
+ name.c_str());
+ return false;
+ }
+
+ layers.push_back(layer);
+ }
+
+ return true;
+}
+
+static bool open_images(const vector<string> &filepaths, vector<MergeImage> &images, string &error)
+{
+ for (const string &filepath : filepaths) {
+ unique_ptr<ImageInput> in(ImageInput::open(filepath));
+ if (!in) {
+ error = "Couldn't open file: " + filepath;
+ return false;
+ }
+
+ MergeImage image;
+ image.in = std::move(in);
+ image.filepath = filepath;
+ if (!parse_channels(image.in->spec(), image.layers, error)) {
+ return false;
+ }
+
+ if (image.layers.size() == 0) {
+ error = "Could not find a render layer for merging";
+ return false;
+ }
+
+ if (image.in->spec().deep) {
+ error = "Merging deep images not supported.";
+ return false;
+ }
+
+ if (images.size() > 0) {
+ const ImageSpec &base_spec = images[0].in->spec();
+ const ImageSpec &spec = image.in->spec();
+
+ if (base_spec.width != spec.width || base_spec.height != spec.height ||
+ base_spec.depth != spec.depth || base_spec.format != spec.format ||
+ base_spec.deep != spec.deep) {
+ error = "Images do not have matching size and data layout.";
+ return false;
+ }
+ }
+
+ images.push_back(std::move(image));
+ }
+
+ return true;
+}
+
+static void merge_render_time(ImageSpec &spec,
+ const vector<MergeImage> &images,
+ const string &name,
+ const bool average)
+{
+ double time = 0.0;
+
+ for (const MergeImage &image : images) {
+ string time_str = image.in->spec().get_string_attribute(name, "");
+ time += time_human_readable_to_seconds(time_str);
+ }
+
+ if (average) {
+ time /= images.size();
+ }
+
+ spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time));
+}
+
+static void merge_layer_render_time(ImageSpec &spec,
+ const vector<MergeImage> &images,
+ const string &layer_name,
+ const string &time_name,
+ const bool average)
+{
+ string name = "cycles." + layer_name + "." + time_name;
+ double time = 0.0;
+
+ for (const MergeImage &image : images) {
+ string time_str = image.in->spec().get_string_attribute(name, "");
+ time += time_human_readable_to_seconds(time_str);
+ }
+
+ if (average) {
+ time /= images.size();
+ }
+
+ spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time));
+}
+
+static void merge_channels_metadata(vector<MergeImage> &images,
+ ImageSpec &out_spec,
+ vector<int> &channel_total_samples)
+{
+ /* Based on first image. */
+ out_spec = images[0].in->spec();
+
+ /* Merge channels and compute offsets. */
+ out_spec.nchannels = 0;
+ out_spec.channelformats.clear();
+ out_spec.channelnames.clear();
+
+ for (MergeImage &image : images) {
+ for (MergeImageLayer &layer : image.layers) {
+ for (MergeImagePass &pass : layer.passes) {
+ /* Test if matching channel already exists in merged image. */
+ bool found = false;
+
+ for (size_t i = 0; i < out_spec.nchannels; i++) {
+ if (pass.channel_name == out_spec.channelnames[i]) {
+ pass.merge_offset = i;
+ channel_total_samples[i] += layer.samples;
+ /* First image wins for channels that can't be averaged or summed. */
+ if (pass.op == MERGE_CHANNEL_COPY) {
+ pass.op = MERGE_CHANNEL_NOP;
+ }
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* Add new channel. */
+ pass.merge_offset = out_spec.nchannels;
+ channel_total_samples.push_back(layer.samples);
+
+ out_spec.channelnames.push_back(pass.channel_name);
+ out_spec.channelformats.push_back(pass.format);
+ out_spec.nchannels++;
+ }
+ }
+ }
+ }
+
+ /* Merge metadata. */
+ merge_render_time(out_spec, images, "RenderTime", false);
+
+ map<string, int> layer_num_samples;
+ for (MergeImage &image : images) {
+ for (MergeImageLayer &layer : image.layers) {
+ if (layer.name != "") {
+ layer_num_samples[layer.name] += layer.samples;
+ }
+ }
+ }
+
+ for (const auto &i : layer_num_samples) {
+ string name = "cycles." + i.first + ".samples";
+ out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", i.second));
+
+ merge_layer_render_time(out_spec, images, i.first, "total_time", false);
+ merge_layer_render_time(out_spec, images, i.first, "render_time", false);
+ merge_layer_render_time(out_spec, images, i.first, "synchronization_time", true);
+ }
+}
+
+static void alloc_pixels(const ImageSpec &spec, array<float> &pixels)
+{
+ const size_t width = spec.width;
+ const size_t height = spec.height;
+ const size_t num_channels = spec.nchannels;
+
+ const size_t num_pixels = (size_t)width * (size_t)height;
+ pixels.resize(num_pixels * num_channels);
+}
+
+static bool merge_pixels(const vector<MergeImage> &images,
+ const ImageSpec &out_spec,
+ const vector<int> &channel_total_samples,
+ array<float> &out_pixels,
+ string &error)
+{
+ alloc_pixels(out_spec, out_pixels);
+ memset(out_pixels.data(), 0, out_pixels.size() * sizeof(float));
+
+ for (const MergeImage &image : images) {
+ /* Read all channels into buffer. Reading all channels at once is
+ * faster than individually due to interleaved EXR channel storage. */
+ array<float> pixels;
+ alloc_pixels(image.in->spec(), pixels);
+
+ if (!image.in->read_image(TypeDesc::FLOAT, pixels.data())) {
+ error = "Failed to read image: " + image.filepath;
+ return false;
+ }
+
+ for (size_t li = 0; li < image.layers.size(); li++) {
+ const MergeImageLayer &layer = image.layers[li];
+
+ const size_t stride = image.in->spec().nchannels;
+ const size_t out_stride = out_spec.nchannels;
+ const size_t num_pixels = pixels.size();
+
+ for (const MergeImagePass &pass : layer.passes) {
+ size_t offset = pass.offset;
+ size_t out_offset = pass.merge_offset;
+
+ switch (pass.op) {
+ case MERGE_CHANNEL_NOP:
+ break;
+ case MERGE_CHANNEL_COPY:
+ for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
+ out_pixels[out_offset] = pixels[offset];
+ }
+ break;
+ case MERGE_CHANNEL_SUM:
+ for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
+ out_pixels[out_offset] += pixels[offset];
+ }
+ break;
+ case MERGE_CHANNEL_AVERAGE:
+ /* Weights based on sample metadata. Per channel since not
+ * all files are guaranteed to have the same channels. */
+ const int total_samples = channel_total_samples[out_offset];
+ const float t = (float)layer.samples / (float)total_samples;
+
+ for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
+ out_pixels[out_offset] += t * pixels[offset];
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool save_output(const string &filepath,
+ const ImageSpec &spec,
+ const array<float> &pixels,
+ string &error)
+{
+ /* Write to temporary file path, so we merge images in place and don't
+ * risk destroying files when something goes wrong in file saving. */
+ string extension = OIIO::Filesystem::extension(filepath);
+ string unique_name = ".merge-tmp-" + OIIO::Filesystem::unique_path();
+ string tmp_filepath = filepath + unique_name + extension;
+ unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath));
+
+ if (!out) {
+ error = "Failed to open temporary file " + tmp_filepath + " for writing";
+ return false;
+ }
+
+ /* Open temporary file and write image buffers. */
+ if (!out->open(tmp_filepath, spec)) {
+ error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror();
+ return false;
+ }
+
+ bool ok = true;
+ if (!out->write_image(TypeDesc::FLOAT, pixels.data())) {
+ error = "Failed to write to file " + tmp_filepath + ": " + out->geterror();
+ ok = false;
+ }
+
+ if (!out->close()) {
+ error = "Failed to save to file " + tmp_filepath + ": " + out->geterror();
+ ok = false;
+ }
+
+ out.reset();
+
+ /* Copy temporary file to output filepath. */
+ string rename_error;
+ if (ok && !OIIO::Filesystem::rename(tmp_filepath, filepath, rename_error)) {
+ error = "Failed to move merged image to " + filepath + ": " + rename_error;
+ ok = false;
+ }
+
+ if (!ok) {
+ OIIO::Filesystem::remove(tmp_filepath);
+ }
+
+ return ok;
+}
+
+/* Image Merger */
+
+ImageMerger::ImageMerger()
+{
+}
+
+bool ImageMerger::run()
+{
+ if (input.empty()) {
+ error = "No input file paths specified.";
+ return false;
+ }
+ if (output.empty()) {
+ error = "No output file path specified.";
+ return false;
+ }
+
+ /* Open images and verify they have matching layout. */
+ vector<MergeImage> images;
+ if (!open_images(input, images, error)) {
+ return false;
+ }
+
+ /* Merge metadata and setup channels and offsets. */
+ ImageSpec out_spec;
+ vector<int> channel_total_samples;
+ merge_channels_metadata(images, out_spec, channel_total_samples);
+
+ /* Merge pixels. */
+ array<float> out_pixels;
+ if (!merge_pixels(images, out_spec, channel_total_samples, out_pixels, error)) {
+ return false;
+ }
+
+ /* We don't need input anymore at this point, and will possibly
+ * overwrite the same file. */
+ images.clear();
+
+ /* Save output file. */
+ return save_output(output, out_spec, out_pixels, error);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/session/merge.h b/intern/cycles/session/merge.h
new file mode 100644
index 00000000000..be03a69b27a
--- /dev/null
+++ b/intern/cycles/session/merge.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011-2019 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MERGE_H__
+#define __MERGE_H__
+
+#include "util/string.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Merge OpenEXR multilayer renders. */
+
+class ImageMerger {
+ public:
+ ImageMerger();
+ bool run();
+
+ /* Error message after running, in case of failure. */
+ string error;
+
+ /* List of image filepaths to merge. */
+ vector<string> input;
+ /* Output filepath. */
+ string output;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __MERGE_H__ */
diff --git a/intern/cycles/session/output_driver.h b/intern/cycles/session/output_driver.h
new file mode 100644
index 00000000000..95e15ed875b
--- /dev/null
+++ b/intern/cycles/session/output_driver.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "util/math.h"
+#include "util/string.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Output driver for reading render buffers.
+ *
+ * Host applications implement this interface for outputting render buffers for offline rendering.
+ * Drivers can be used to copy the buffers into the host application or write them directly to
+ * disk. This interface may also be used for interactive display, however the DisplayDriver is more
+ * efficient for that purpose.
+ */
+class OutputDriver {
+ public:
+ OutputDriver() = default;
+ virtual ~OutputDriver() = default;
+
+ class Tile {
+ public:
+ Tile(const int2 offset,
+ const int2 size,
+ const int2 full_size,
+ const string_view layer,
+ const string_view view)
+ : offset(offset), size(size), full_size(full_size), layer(layer), view(view)
+ {
+ }
+ virtual ~Tile() = default;
+
+ const int2 offset;
+ const int2 size;
+ const int2 full_size;
+ const string layer;
+ const string view;
+
+ virtual bool get_pass_pixels(const string_view pass_name,
+ const int num_channels,
+ float *pixels) const = 0;
+ virtual bool set_pass_pixels(const string_view pass_name,
+ const int num_channels,
+ const float *pixels) const = 0;
+ };
+
+ /* Write tile once it has finished rendering. */
+ virtual void write_render_tile(const Tile &tile) = 0;
+
+ /* Update tile while rendering is in progress. Return true if any update
+ * was performed. */
+ virtual bool update_render_tile(const Tile & /* tile */)
+ {
+ return false;
+ }
+
+ /* For baking, read render pass PASS_BAKE_PRIMITIVE and PASS_BAKE_DIFFERENTIAL
+ * to determine which shading points to use for baking at each pixel. Return
+ * true if any data was read. */
+ virtual bool read_render_tile(const Tile & /* tile */)
+ {
+ return false;
+ }
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/session/session.cpp b/intern/cycles/session/session.cpp
new file mode 100644
index 00000000000..b228939689c
--- /dev/null
+++ b/intern/cycles/session/session.cpp
@@ -0,0 +1,624 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits.h>
+#include <string.h>
+
+#include "device/cpu/device.h"
+#include "device/device.h"
+#include "integrator/pass_accessor_cpu.h"
+#include "integrator/path_trace.h"
+#include "scene/background.h"
+#include "scene/bake.h"
+#include "scene/camera.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "scene/shader_graph.h"
+#include "session/buffers.h"
+#include "session/display_driver.h"
+#include "session/output_driver.h"
+#include "session/session.h"
+
+#include "util/foreach.h"
+#include "util/function.h"
+#include "util/log.h"
+#include "util/math.h"
+#include "util/task.h"
+#include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+Session::Session(const SessionParams &params_, const SceneParams &scene_params)
+ : params(params_), render_scheduler_(tile_manager_, params)
+{
+ TaskScheduler::init(params.threads);
+
+ session_thread_ = nullptr;
+
+ delayed_reset_.do_reset = false;
+
+ pause_ = false;
+ cancel_ = false;
+ new_work_added_ = false;
+
+ device = Device::create(params.device, stats, profiler);
+
+ scene = new Scene(scene_params, device);
+
+ /* Configure path tracer. */
+ path_trace_ = make_unique<PathTrace>(
+ device, scene->film, &scene->dscene, render_scheduler_, tile_manager_);
+ path_trace_->set_progress(&progress);
+ path_trace_->progress_update_cb = [&]() { update_status_time(); };
+
+ tile_manager_.full_buffer_written_cb = [&](string_view filename) {
+ if (!full_buffer_written_cb) {
+ return;
+ }
+ full_buffer_written_cb(filename);
+ };
+}
+
+Session::~Session()
+{
+ cancel();
+
+ /* Make sure path tracer is destroyed before the device. This is needed because destruction might
+ * need to access device for device memory free. */
+ /* TODO(sergey): Convert device to be unique_ptr, and rely on C++ to destruct objects in the
+ * pre-defined order. */
+ path_trace_.reset();
+
+ delete scene;
+ delete device;
+
+ TaskScheduler::exit();
+}
+
+void Session::start()
+{
+ if (!session_thread_) {
+ session_thread_ = new thread(function_bind(&Session::run, this));
+ }
+}
+
+void Session::cancel(bool quick)
+{
+ if (quick && path_trace_) {
+ path_trace_->cancel();
+ }
+
+ if (session_thread_) {
+ /* wait for session thread to end */
+ progress.set_cancel("Exiting");
+
+ {
+ thread_scoped_lock pause_lock(pause_mutex_);
+ pause_ = false;
+ cancel_ = true;
+ }
+ pause_cond_.notify_all();
+
+ wait();
+ }
+}
+
+bool Session::ready_to_reset()
+{
+ return path_trace_->ready_to_reset();
+}
+
+void Session::run_main_render_loop()
+{
+ path_trace_->clear_display();
+
+ while (true) {
+ RenderWork render_work = run_update_for_next_iteration();
+
+ if (!render_work) {
+ if (VLOG_IS_ON(2)) {
+ double total_time, render_time;
+ progress.get_time(total_time, render_time);
+ VLOG(2) << "Rendering in main loop is done in " << render_time << " seconds.";
+ VLOG(2) << path_trace_->full_report();
+ }
+
+ if (params.background) {
+ /* if no work left and in background mode, we can stop immediately. */
+ progress.set_status("Finished");
+ break;
+ }
+ }
+
+ const bool did_cancel = progress.get_cancel();
+ if (did_cancel) {
+ render_scheduler_.render_work_reschedule_on_cancel(render_work);
+ if (!render_work) {
+ break;
+ }
+ }
+ else if (run_wait_for_work(render_work)) {
+ continue;
+ }
+
+ /* Stop rendering if error happened during scene update or other step of preparing scene
+ * for render. */
+ if (device->have_error()) {
+ progress.set_error(device->error_message());
+ break;
+ }
+
+ {
+ /* buffers mutex is locked entirely while rendering each
+ * sample, and released/reacquired on each iteration to allow
+ * reset and draw in between */
+ thread_scoped_lock buffers_lock(buffers_mutex_);
+
+ /* update status and timing */
+ update_status_time();
+
+ /* render */
+ path_trace_->render(render_work);
+
+ /* update status and timing */
+ update_status_time();
+
+ /* Stop rendering if error happened during path tracing. */
+ if (device->have_error()) {
+ progress.set_error(device->error_message());
+ break;
+ }
+ }
+
+ progress.set_update();
+
+ if (did_cancel) {
+ break;
+ }
+ }
+}
+
+void Session::run()
+{
+ if (params.use_profiling && (params.device.type == DEVICE_CPU)) {
+ profiler.start();
+ }
+
+ /* session thread loop */
+ progress.set_status("Waiting for render to start");
+
+ /* run */
+ if (!progress.get_cancel()) {
+ /* reset number of rendered samples */
+ progress.reset_sample();
+
+ run_main_render_loop();
+ }
+
+ profiler.stop();
+
+ /* progress update */
+ if (progress.get_cancel())
+ progress.set_status(progress.get_cancel_message());
+ else
+ progress.set_update();
+}
+
+RenderWork Session::run_update_for_next_iteration()
+{
+ RenderWork render_work;
+
+ thread_scoped_lock scene_lock(scene->mutex);
+ thread_scoped_lock reset_lock(delayed_reset_.mutex);
+
+ bool have_tiles = true;
+ bool switched_to_new_tile = false;
+
+ const bool did_reset = delayed_reset_.do_reset;
+ if (delayed_reset_.do_reset) {
+ thread_scoped_lock buffers_lock(buffers_mutex_);
+ do_delayed_reset();
+
+ /* After reset make sure the tile manager is at the first big tile. */
+ have_tiles = tile_manager_.next();
+ switched_to_new_tile = true;
+ }
+
+ /* Update number of samples in the integrator.
+ * Ideally this would need to happen once in `Session::set_samples()`, but the issue there is
+ * the initial configuration when Session is created where the `set_samples()` is not used.
+ *
+ * NOTE: Unless reset was requested only allow increasing number of samples. */
+ if (did_reset || scene->integrator->get_aa_samples() < params.samples) {
+ scene->integrator->set_aa_samples(params.samples);
+ }
+
+ /* Update denoiser settings. */
+ {
+ const DenoiseParams denoise_params = scene->integrator->get_denoise_params();
+ path_trace_->set_denoiser_params(denoise_params);
+ }
+
+ /* Update adaptive sampling. */
+ {
+ const AdaptiveSampling adaptive_sampling = scene->integrator->get_adaptive_sampling();
+ path_trace_->set_adaptive_sampling(adaptive_sampling);
+ }
+
+ render_scheduler_.set_num_samples(params.samples);
+ render_scheduler_.set_time_limit(params.time_limit);
+
+ while (have_tiles) {
+ render_work = render_scheduler_.get_render_work();
+ if (render_work) {
+ break;
+ }
+
+ progress.add_finished_tile(false);
+
+ have_tiles = tile_manager_.next();
+ if (have_tiles) {
+ render_scheduler_.reset_for_next_tile();
+ switched_to_new_tile = true;
+ }
+ }
+
+ if (render_work) {
+ scoped_timer update_timer;
+
+ if (switched_to_new_tile) {
+ BufferParams tile_params = buffer_params_;
+
+ const Tile &tile = tile_manager_.get_current_tile();
+
+ tile_params.width = tile.width;
+ tile_params.height = tile.height;
+
+ tile_params.window_x = tile.window_x;
+ tile_params.window_y = tile.window_y;
+ tile_params.window_width = tile.window_width;
+ tile_params.window_height = tile.window_height;
+
+ tile_params.full_x = tile.x + buffer_params_.full_x;
+ tile_params.full_y = tile.y + buffer_params_.full_y;
+ tile_params.full_width = buffer_params_.full_width;
+ tile_params.full_height = buffer_params_.full_height;
+
+ tile_params.update_offset_stride();
+
+ path_trace_->reset(buffer_params_, tile_params);
+ }
+
+ const int resolution = render_work.resolution_divider;
+ const int width = max(1, buffer_params_.full_width / resolution);
+ const int height = max(1, buffer_params_.full_height / resolution);
+
+ if (update_scene(width, height)) {
+ profiler.reset(scene->shaders.size(), scene->objects.size());
+ }
+ progress.add_skip_time(update_timer, params.background);
+ }
+
+ return render_work;
+}
+
+bool Session::run_wait_for_work(const RenderWork &render_work)
+{
+ /* In an offline rendering there is no pause, and no tiles will mean the job is fully done. */
+ if (params.background) {
+ return false;
+ }
+
+ thread_scoped_lock pause_lock(pause_mutex_);
+
+ if (!pause_ && render_work) {
+ /* Rendering is not paused and there is work to be done. No need to wait for anything. */
+ return false;
+ }
+
+ const bool no_work = !render_work;
+ update_status_time(pause_, no_work);
+
+ /* Only leave the loop when rendering is not paused. But even if the current render is un-paused
+ * but there is nothing to render keep waiting until new work is added. */
+ while (!cancel_) {
+ scoped_timer pause_timer;
+
+ if (!pause_ && (render_work || new_work_added_ || delayed_reset_.do_reset)) {
+ break;
+ }
+
+ /* Wait for either pause state changed, or extra samples added to render. */
+ pause_cond_.wait(pause_lock);
+
+ if (pause_) {
+ progress.add_skip_time(pause_timer, params.background);
+ }
+
+ update_status_time(pause_, no_work);
+ progress.set_update();
+ }
+
+ new_work_added_ = false;
+
+ return no_work;
+}
+
+void Session::draw()
+{
+ path_trace_->draw();
+}
+
+int2 Session::get_effective_tile_size() const
+{
+ /* No support yet for baking with tiles. */
+ if (!params.use_auto_tile || scene->bake_manager->get_baking()) {
+ return make_int2(buffer_params_.width, buffer_params_.height);
+ }
+
+ /* TODO(sergey): Take available memory into account, and if there is enough memory do not tile
+ * and prefer optimal performance. */
+ const int tile_size = tile_manager_.compute_render_tile_size(params.tile_size);
+ return make_int2(tile_size, tile_size);
+}
+
+void Session::do_delayed_reset()
+{
+ if (!delayed_reset_.do_reset) {
+ return;
+ }
+ delayed_reset_.do_reset = false;
+
+ params = delayed_reset_.session_params;
+ buffer_params_ = delayed_reset_.buffer_params;
+
+ /* Store parameters used for buffers access outside of scene graph. */
+ buffer_params_.samples = params.samples;
+ buffer_params_.exposure = scene->film->get_exposure();
+ buffer_params_.use_approximate_shadow_catcher =
+ scene->film->get_use_approximate_shadow_catcher();
+ buffer_params_.use_transparent_background = scene->background->get_transparent();
+
+ /* Tile and work scheduling. */
+ tile_manager_.reset_scheduling(buffer_params_, get_effective_tile_size());
+ render_scheduler_.reset(buffer_params_, params.samples);
+
+ /* Passes. */
+ /* When multiple tiles are used SAMPLE_COUNT pass is used to keep track of possible partial
+ * tile results. It is safe to use generic update function here which checks for changes since
+ * changes in tile settings re-creates session, which ensures film is fully updated on tile
+ * changes. */
+ scene->film->update_passes(scene, tile_manager_.has_multiple_tiles());
+
+ /* Update for new state of scene and passes. */
+ buffer_params_.update_passes(scene->passes);
+ tile_manager_.update(buffer_params_, scene);
+
+ /* Progress. */
+ progress.reset_sample();
+ progress.set_total_pixel_samples(static_cast<uint64_t>(buffer_params_.width) *
+ buffer_params_.height * params.samples);
+
+ if (!params.background) {
+ progress.set_start_time();
+ }
+ progress.set_render_start_time();
+}
+
+void Session::reset(const SessionParams &session_params, const BufferParams &buffer_params)
+{
+ {
+ thread_scoped_lock reset_lock(delayed_reset_.mutex);
+ thread_scoped_lock pause_lock(pause_mutex_);
+
+ delayed_reset_.do_reset = true;
+ delayed_reset_.session_params = session_params;
+ delayed_reset_.buffer_params = buffer_params;
+
+ path_trace_->cancel();
+ }
+
+ pause_cond_.notify_all();
+}
+
+void Session::set_samples(int samples)
+{
+ if (samples == params.samples) {
+ return;
+ }
+
+ params.samples = samples;
+
+ {
+ thread_scoped_lock pause_lock(pause_mutex_);
+ new_work_added_ = true;
+ }
+
+ pause_cond_.notify_all();
+}
+
+void Session::set_time_limit(double time_limit)
+{
+ if (time_limit == params.time_limit) {
+ return;
+ }
+
+ params.time_limit = time_limit;
+
+ {
+ thread_scoped_lock pause_lock(pause_mutex_);
+ new_work_added_ = true;
+ }
+
+ pause_cond_.notify_all();
+}
+
+void Session::set_pause(bool pause)
+{
+ bool notify = false;
+
+ {
+ thread_scoped_lock pause_lock(pause_mutex_);
+
+ if (pause != pause_) {
+ pause_ = pause;
+ notify = true;
+ }
+ }
+
+ if (session_thread_) {
+ if (notify) {
+ pause_cond_.notify_all();
+ }
+ }
+ else if (pause_) {
+ update_status_time(pause_);
+ }
+}
+
+void Session::set_output_driver(unique_ptr<OutputDriver> driver)
+{
+ path_trace_->set_output_driver(move(driver));
+}
+
+void Session::set_display_driver(unique_ptr<DisplayDriver> driver)
+{
+ path_trace_->set_display_driver(move(driver));
+}
+
+double Session::get_estimated_remaining_time() const
+{
+ const float completed = progress.get_progress();
+ if (completed == 0.0f) {
+ return 0.0;
+ }
+
+ double total_time, render_time;
+ progress.get_time(total_time, render_time);
+ double remaining = (1.0 - (double)completed) * (render_time / (double)completed);
+
+ const double time_limit = render_scheduler_.get_time_limit();
+ if (time_limit != 0.0) {
+ remaining = min(remaining, max(time_limit - render_time, 0.0));
+ }
+
+ return remaining;
+}
+
+void Session::wait()
+{
+ if (session_thread_) {
+ session_thread_->join();
+ delete session_thread_;
+ }
+
+ session_thread_ = nullptr;
+}
+
+bool Session::update_scene(int width, int height)
+{
+ /* Update camera if dimensions changed for progressive render. the camera
+ * knows nothing about progressive or cropped rendering, it just gets the
+ * image dimensions passed in. */
+ Camera *cam = scene->camera;
+ cam->set_screen_size(width, height);
+
+ const bool scene_update_result = scene->update(progress);
+
+ path_trace_->load_kernels();
+ path_trace_->alloc_work_memory();
+
+ return scene_update_result;
+}
+
+static string status_append(const string &status, const string &suffix)
+{
+ string prefix = status;
+ if (!prefix.empty()) {
+ prefix += ", ";
+ }
+ return prefix + suffix;
+}
+
+void Session::update_status_time(bool show_pause, bool show_done)
+{
+ string status, substatus;
+
+ const int current_tile = progress.get_rendered_tiles();
+ const int num_tiles = tile_manager_.get_num_tiles();
+
+ const int current_sample = progress.get_current_sample();
+ const int num_samples = render_scheduler_.get_num_samples();
+
+ /* TIle. */
+ if (tile_manager_.has_multiple_tiles()) {
+ substatus = status_append(substatus,
+ string_printf("Rendered %d/%d Tiles", current_tile, num_tiles));
+ }
+
+ /* Sample. */
+ if (num_samples == Integrator::MAX_SAMPLES) {
+ substatus = status_append(substatus, string_printf("Sample %d", current_sample));
+ }
+ else {
+ substatus = status_append(substatus,
+ string_printf("Sample %d/%d", current_sample, num_samples));
+ }
+
+ /* TODO(sergey): Denoising status from the path trace. */
+
+ if (show_pause) {
+ status = "Rendering Paused";
+ }
+ else if (show_done) {
+ status = "Rendering Done";
+ progress.set_end_time(); /* Save end time so that further calls to get_time are accurate. */
+ }
+ else {
+ status = substatus;
+ substatus.clear();
+ }
+
+ progress.set_status(status, substatus);
+}
+
+void Session::device_free()
+{
+ scene->device_free();
+ path_trace_->device_free();
+}
+
+void Session::collect_statistics(RenderStats *render_stats)
+{
+ scene->collect_statistics(render_stats);
+ if (params.use_profiling && (params.device.type == DEVICE_CPU)) {
+ render_stats->collect_profiling(scene, profiler);
+ }
+}
+
+/* --------------------------------------------------------------------
+ * Full-frame on-disk storage.
+ */
+
+void Session::process_full_buffer_from_disk(string_view filename)
+{
+ path_trace_->process_full_buffer_from_disk(filename);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/session/session.h b/intern/cycles/session/session.h
new file mode 100644
index 00000000000..1ec0c6e9bb1
--- /dev/null
+++ b/intern/cycles/session/session.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SESSION_H__
+#define __SESSION_H__
+
+#include "device/device.h"
+#include "integrator/render_scheduler.h"
+#include "scene/shader.h"
+#include "scene/stats.h"
+#include "session/buffers.h"
+#include "session/tile.h"
+
+#include "util/progress.h"
+#include "util/stats.h"
+#include "util/thread.h"
+#include "util/unique_ptr.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BufferParams;
+class Device;
+class DeviceScene;
+class DisplayDriver;
+class OutputDriver;
+class PathTrace;
+class Progress;
+class RenderBuffers;
+class Scene;
+class SceneParams;
+
+/* Session Parameters */
+
+class SessionParams {
+ public:
+ DeviceInfo device;
+
+ bool headless;
+ bool background;
+
+ bool experimental;
+ int samples;
+ int pixel_size;
+ int threads;
+
+ /* Limit in seconds for how long path tracing is allowed to happen.
+ * Zero means no limit is applied. */
+ double time_limit;
+
+ bool use_profiling;
+
+ bool use_auto_tile;
+ int tile_size;
+
+ ShadingSystem shadingsystem;
+
+ SessionParams()
+ {
+ headless = false;
+ background = false;
+
+ experimental = false;
+ samples = 1024;
+ pixel_size = 1;
+ threads = 0;
+ time_limit = 0.0;
+
+ use_profiling = false;
+
+ use_auto_tile = true;
+ tile_size = 2048;
+
+ shadingsystem = SHADINGSYSTEM_SVM;
+ }
+
+ bool modified(const SessionParams &params) const
+ {
+ /* Modified means we have to recreate the session, any parameter changes
+ * that can be handled by an existing Session are omitted. */
+ return !(device == params.device && headless == params.headless &&
+ background == params.background && experimental == params.experimental &&
+ pixel_size == params.pixel_size && threads == params.threads &&
+ use_profiling == params.use_profiling && shadingsystem == params.shadingsystem &&
+ use_auto_tile == params.use_auto_tile && tile_size == params.tile_size);
+ }
+};
+
+/* Session
+ *
+ * This is the class that contains the session thread, running the render
+ * control loop and dispatching tasks. */
+
+class Session {
+ public:
+ Device *device;
+ Scene *scene;
+ Progress progress;
+ SessionParams params;
+ Stats stats;
+ Profiler profiler;
+
+ /* Callback is invoked by tile manager whenever on-dist tiles storage file is closed after
+ * writing. Allows an engine integration to keep track of those files without worry about
+ * transferring the information when it needs to re-create session during rendering. */
+ function<void(string_view)> full_buffer_written_cb;
+
+ explicit Session(const SessionParams &params, const SceneParams &scene_params);
+ ~Session();
+
+ void start();
+
+ /* When quick cancel is requested path tracing is cancels as soon as possible, without waiting
+ * for the buffer to be uniformly sampled. */
+ void cancel(bool quick = false);
+
+ void draw();
+ void wait();
+
+ bool ready_to_reset();
+ void reset(const SessionParams &session_params, const BufferParams &buffer_params);
+
+ void set_pause(bool pause);
+
+ void set_samples(int samples);
+ void set_time_limit(double time_limit);
+
+ void set_output_driver(unique_ptr<OutputDriver> driver);
+ void set_display_driver(unique_ptr<DisplayDriver> driver);
+
+ double get_estimated_remaining_time() const;
+
+ void device_free();
+
+ /* Returns the rendering progress or 0 if no progress can be determined
+ * (for example, when rendering with unlimited samples). */
+ float get_progress();
+
+ void collect_statistics(RenderStats *stats);
+
+ /* --------------------------------------------------------------------
+ * Full-frame on-disk storage.
+ */
+
+ /* Read given full-frame file from disk, perform needed processing and write it to the software
+ * via the write callback. */
+ void process_full_buffer_from_disk(string_view filename);
+
+ protected:
+ struct DelayedReset {
+ thread_mutex mutex;
+ bool do_reset;
+ SessionParams session_params;
+ BufferParams buffer_params;
+ } delayed_reset_;
+
+ void run();
+
+ /* Update for the new iteration of the main loop in run implementation (run_cpu and run_gpu).
+ *
+ * Will take care of the following things:
+ * - Delayed reset
+ * - Scene update
+ * - Tile manager advance
+ * - Render scheduler work request
+ *
+ * The updates are done in a proper order with proper locking around them, which guarantees
+ * that the device side of scene and render buffers are always in a consistent state.
+ *
+ * Returns render work which is to be rendered next. */
+ RenderWork run_update_for_next_iteration();
+
+ /* Wait for rendering to be unpaused, or for new tiles for render to arrive.
+ * Returns true if new main render loop iteration is required after this function call.
+ *
+ * The `render_work` is the work which was scheduled by the render scheduler right before
+ * checking the pause. */
+ bool run_wait_for_work(const RenderWork &render_work);
+
+ void run_main_render_loop();
+
+ bool update_scene(int width, int height);
+
+ void update_status_time(bool show_pause = false, bool show_done = false);
+
+ void do_delayed_reset();
+
+ int2 get_effective_tile_size() const;
+
+ thread *session_thread_;
+
+ bool pause_ = false;
+ bool cancel_ = false;
+ bool new_work_added_ = false;
+
+ thread_condition_variable pause_cond_;
+ thread_mutex pause_mutex_;
+ thread_mutex tile_mutex_;
+ thread_mutex buffers_mutex_;
+
+ TileManager tile_manager_;
+ BufferParams buffer_params_;
+
+ /* Render scheduler is used to get work to be rendered with the current big tile. */
+ RenderScheduler render_scheduler_;
+
+ /* Path tracer object.
+ *
+ * Is a single full-frame path tracer for interactive viewport rendering.
+ * A path tracer for the current big-tile for an offline rendering. */
+ unique_ptr<PathTrace> path_trace_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __SESSION_H__ */
diff --git a/intern/cycles/session/tile.cpp b/intern/cycles/session/tile.cpp
new file mode 100644
index 00000000000..56bc519378f
--- /dev/null
+++ b/intern/cycles/session/tile.cpp
@@ -0,0 +1,635 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "session/tile.h"
+
+#include <atomic>
+
+#include "graph/node.h"
+#include "scene/background.h"
+#include "scene/film.h"
+#include "scene/integrator.h"
+#include "scene/scene.h"
+#include "util/algorithm.h"
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/path.h"
+#include "util/string.h"
+#include "util/system.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* --------------------------------------------------------------------
+ * Internal functions.
+ */
+
+static const char *ATTR_PASSES_COUNT = "cycles.passes.count";
+static const char *ATTR_PASS_SOCKET_PREFIX_FORMAT = "cycles.passes.%d.";
+static const char *ATTR_BUFFER_SOCKET_PREFIX = "cycles.buffer.";
+static const char *ATTR_DENOISE_SOCKET_PREFIX = "cycles.denoise.";
+
+/* Global counter of ToleManager object instances. */
+static std::atomic<uint64_t> g_instance_index = 0;
+
+/* Construct names of EXR channels which will ensure order of all channels to match exact offsets
+ * in render buffers corresponding to the given passes.
+ *
+ * Returns `std` datatypes so that it can be assigned directly to the OIIO's `ImageSpec`. */
+static std::vector<std::string> exr_channel_names_for_passes(const BufferParams &buffer_params)
+{
+ static const char *component_suffixes[] = {"R", "G", "B", "A"};
+
+ int pass_index = 0;
+ int num_channels = 0;
+ std::vector<std::string> channel_names;
+ for (const BufferPass &pass : buffer_params.passes) {
+ if (pass.offset == PASS_UNUSED) {
+ continue;
+ }
+
+ const PassInfo pass_info = pass.get_info();
+ num_channels += pass_info.num_components;
+
+ /* EXR canonically expects first part of channel names to be sorted alphabetically, which is
+ * not guaranteed to be the case with passes names. Assign a prefix based on the pass index
+ * with a fixed width to ensure ordering. This makes it possible to dump existing render
+ * buffers memory to disk and read it back without doing extra mapping. */
+ const string prefix = string_printf("%08d", pass_index);
+
+ const string channel_name_prefix = prefix + string(pass.name) + ".";
+
+ for (int i = 0; i < pass_info.num_components; ++i) {
+ channel_names.push_back(channel_name_prefix + component_suffixes[i]);
+ }
+
+ ++pass_index;
+ }
+
+ return channel_names;
+}
+
+inline string node_socket_attribute_name(const SocketType &socket, const string &attr_name_prefix)
+{
+ return attr_name_prefix + string(socket.name);
+}
+
+template<typename ValidateValueFunc, typename GetValueFunc>
+static bool node_socket_generic_to_image_spec_atttributes(
+ ImageSpec *image_spec,
+ const Node *node,
+ const SocketType &socket,
+ const string &attr_name_prefix,
+ const ValidateValueFunc &validate_value_func,
+ const GetValueFunc &get_value_func)
+{
+ if (!validate_value_func(node, socket)) {
+ return false;
+ }
+
+ image_spec->attribute(node_socket_attribute_name(socket, attr_name_prefix),
+ get_value_func(node, socket));
+
+ return true;
+}
+
+static bool node_socket_to_image_spec_atttributes(ImageSpec *image_spec,
+ const Node *node,
+ const SocketType &socket,
+ const string &attr_name_prefix)
+{
+ const string attr_name = node_socket_attribute_name(socket, attr_name_prefix);
+
+ switch (socket.type) {
+ case SocketType::ENUM: {
+ const ustring value = node->get_string(socket);
+
+ /* Validate that the node is consistent with the node type definition. */
+ const NodeEnum &enum_values = *socket.enum_values;
+ if (!enum_values.exists(value)) {
+ LOG(DFATAL) << "Node enum contains invalid value " << value;
+ return false;
+ }
+
+ image_spec->attribute(attr_name, value);
+
+ return true;
+ }
+
+ case SocketType::STRING:
+ image_spec->attribute(attr_name, node->get_string(socket));
+ return true;
+
+ case SocketType::INT:
+ image_spec->attribute(attr_name, node->get_int(socket));
+ return true;
+
+ case SocketType::FLOAT:
+ image_spec->attribute(attr_name, node->get_float(socket));
+ return true;
+
+ case SocketType::BOOLEAN:
+ image_spec->attribute(attr_name, node->get_bool(socket));
+ return true;
+
+ default:
+ LOG(DFATAL) << "Unhandled socket type " << socket.type << ", should never happen.";
+ return false;
+ }
+}
+
+static bool node_socket_from_image_spec_atttributes(Node *node,
+ const SocketType &socket,
+ const ImageSpec &image_spec,
+ const string &attr_name_prefix)
+{
+ const string attr_name = node_socket_attribute_name(socket, attr_name_prefix);
+
+ switch (socket.type) {
+ case SocketType::ENUM: {
+ /* TODO(sergey): Avoid construction of `ustring` by using `string_view` in the Node API. */
+ const ustring value(image_spec.get_string_attribute(attr_name, ""));
+
+ /* Validate that the node is consistent with the node type definition. */
+ const NodeEnum &enum_values = *socket.enum_values;
+ if (!enum_values.exists(value)) {
+ LOG(ERROR) << "Invalid enumerator value " << value;
+ return false;
+ }
+
+ node->set(socket, enum_values[value]);
+
+ return true;
+ }
+
+ case SocketType::STRING:
+ /* TODO(sergey): Avoid construction of `ustring` by using `string_view` in the Node API. */
+ node->set(socket, ustring(image_spec.get_string_attribute(attr_name, "")));
+ return true;
+
+ case SocketType::INT:
+ node->set(socket, image_spec.get_int_attribute(attr_name, 0));
+ return true;
+
+ case SocketType::FLOAT:
+ node->set(socket, image_spec.get_float_attribute(attr_name, 0));
+ return true;
+
+ case SocketType::BOOLEAN:
+ node->set(socket, static_cast<bool>(image_spec.get_int_attribute(attr_name, 0)));
+ return true;
+
+ default:
+ LOG(DFATAL) << "Unhandled socket type " << socket.type << ", should never happen.";
+ return false;
+ }
+}
+
+static bool node_to_image_spec_atttributes(ImageSpec *image_spec,
+ const Node *node,
+ const string &attr_name_prefix)
+{
+ for (const SocketType &socket : node->type->inputs) {
+ if (!node_socket_to_image_spec_atttributes(image_spec, node, socket, attr_name_prefix)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool node_from_image_spec_atttributes(Node *node,
+ const ImageSpec &image_spec,
+ const string &attr_name_prefix)
+{
+ for (const SocketType &socket : node->type->inputs) {
+ if (!node_socket_from_image_spec_atttributes(node, socket, image_spec, attr_name_prefix)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool buffer_params_to_image_spec_atttributes(ImageSpec *image_spec,
+ const BufferParams &buffer_params)
+{
+ if (!node_to_image_spec_atttributes(image_spec, &buffer_params, ATTR_BUFFER_SOCKET_PREFIX)) {
+ return false;
+ }
+
+ /* Passes storage is not covered by the node socket. so "expand" the loop manually. */
+
+ const int num_passes = buffer_params.passes.size();
+ image_spec->attribute(ATTR_PASSES_COUNT, num_passes);
+
+ for (int pass_index = 0; pass_index < num_passes; ++pass_index) {
+ const string attr_name_prefix = string_printf(ATTR_PASS_SOCKET_PREFIX_FORMAT, pass_index);
+
+ const BufferPass *pass = &buffer_params.passes[pass_index];
+ if (!node_to_image_spec_atttributes(image_spec, pass, attr_name_prefix)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool buffer_params_from_image_spec_atttributes(BufferParams *buffer_params,
+ const ImageSpec &image_spec)
+{
+ if (!node_from_image_spec_atttributes(buffer_params, image_spec, ATTR_BUFFER_SOCKET_PREFIX)) {
+ return false;
+ }
+
+ /* Passes storage is not covered by the node socket. so "expand" the loop manually. */
+
+ const int num_passes = image_spec.get_int_attribute(ATTR_PASSES_COUNT, 0);
+ if (num_passes == 0) {
+ LOG(ERROR) << "Missing passes count attribute.";
+ return false;
+ }
+
+ for (int pass_index = 0; pass_index < num_passes; ++pass_index) {
+ const string attr_name_prefix = string_printf(ATTR_PASS_SOCKET_PREFIX_FORMAT, pass_index);
+
+ BufferPass pass;
+
+ if (!node_from_image_spec_atttributes(&pass, image_spec, attr_name_prefix)) {
+ return false;
+ }
+
+ buffer_params->passes.emplace_back(std::move(pass));
+ }
+
+ buffer_params->update_passes();
+
+ return true;
+}
+
+/* Configure image specification for the given buffer parameters and passes.
+ *
+ * Image channels will be strictly ordered to match content of corresponding buffer, and the
+ * metadata will be set so that the render buffers and passes can be reconstructed from it.
+ *
+ * If the tile size different from (0, 0) the image specification will be configured to use the
+ * given tile size for tiled IO. */
+static bool configure_image_spec_from_buffer(ImageSpec *image_spec,
+ const BufferParams &buffer_params,
+ const int2 tile_size = make_int2(0, 0))
+{
+ const std::vector<std::string> channel_names = exr_channel_names_for_passes(buffer_params);
+ const int num_channels = channel_names.size();
+
+ *image_spec = ImageSpec(
+ buffer_params.width, buffer_params.height, num_channels, TypeDesc::FLOAT);
+
+ image_spec->channelnames = move(channel_names);
+
+ if (!buffer_params_to_image_spec_atttributes(image_spec, buffer_params)) {
+ return false;
+ }
+
+ if (tile_size.x != 0 || tile_size.y != 0) {
+ DCHECK_GT(tile_size.x, 0);
+ DCHECK_GT(tile_size.y, 0);
+
+ image_spec->tile_width = min(TileManager::IMAGE_TILE_SIZE, tile_size.x);
+ image_spec->tile_height = min(TileManager::IMAGE_TILE_SIZE, tile_size.y);
+ }
+
+ return true;
+}
+
+/* --------------------------------------------------------------------
+ * Tile Manager.
+ */
+
+TileManager::TileManager()
+{
+ /* Use process ID to separate different processes.
+ * To ensure uniqueness from within a process use combination of object address and instance
+ * index. This solves problem of possible object re-allocation at the same time, and solves
+ * possible conflict when the counter overflows while there are still active instances of the
+ * class. */
+ const int tile_manager_id = g_instance_index.fetch_add(1, std::memory_order_relaxed);
+ tile_file_unique_part_ = to_string(system_self_process_id()) + "-" +
+ to_string(reinterpret_cast<uintptr_t>(this)) + "-" +
+ to_string(tile_manager_id);
+}
+
+TileManager::~TileManager()
+{
+}
+
+int TileManager::compute_render_tile_size(const int suggested_tile_size) const
+{
+ /* Must be a multiple of IMAGE_TILE_SIZE so that we can write render tiles into the image file
+ * aligned on image tile boundaries. We can't set IMAGE_TILE_SIZE equal to the render tile size
+ * because too big tile size leads to integer overflow inside OpenEXR. */
+ return (suggested_tile_size <= IMAGE_TILE_SIZE) ? suggested_tile_size :
+ align_up(suggested_tile_size, IMAGE_TILE_SIZE);
+}
+
+void TileManager::reset_scheduling(const BufferParams &params, int2 tile_size)
+{
+ VLOG(3) << "Using tile size of " << tile_size;
+
+ close_tile_output();
+
+ tile_size_ = tile_size;
+
+ tile_state_.num_tiles_x = divide_up(params.width, tile_size_.x);
+ tile_state_.num_tiles_y = divide_up(params.height, tile_size_.y);
+ tile_state_.num_tiles = tile_state_.num_tiles_x * tile_state_.num_tiles_y;
+
+ tile_state_.next_tile_index = 0;
+
+ tile_state_.current_tile = Tile();
+}
+
+void TileManager::update(const BufferParams &params, const Scene *scene)
+{
+ DCHECK_NE(params.pass_stride, -1);
+
+ buffer_params_ = params;
+
+ if (has_multiple_tiles()) {
+ /* TODO(sergey): Proper Error handling, so that if configuration has failed we don't attempt to
+ * write to a partially configured file. */
+ configure_image_spec_from_buffer(&write_state_.image_spec, buffer_params_, tile_size_);
+
+ const DenoiseParams denoise_params = scene->integrator->get_denoise_params();
+ const AdaptiveSampling adaptive_sampling = scene->integrator->get_adaptive_sampling();
+
+ node_to_image_spec_atttributes(
+ &write_state_.image_spec, &denoise_params, ATTR_DENOISE_SOCKET_PREFIX);
+
+ if (adaptive_sampling.use) {
+ overscan_ = 4;
+ }
+ else {
+ overscan_ = 0;
+ }
+ }
+ else {
+ write_state_.image_spec = ImageSpec();
+ overscan_ = 0;
+ }
+}
+
+bool TileManager::done()
+{
+ return tile_state_.next_tile_index == tile_state_.num_tiles;
+}
+
+bool TileManager::next()
+{
+ if (done()) {
+ return false;
+ }
+
+ tile_state_.current_tile = get_tile_for_index(tile_state_.next_tile_index);
+
+ ++tile_state_.next_tile_index;
+
+ return true;
+}
+
+Tile TileManager::get_tile_for_index(int index) const
+{
+ /* TODO(sergey): Consider using hilbert spiral, or. maybe, even configurable. Not sure this
+ * brings a lot of value since this is only applicable to BIG tiles. */
+
+ const int tile_index_y = index / tile_state_.num_tiles_x;
+ const int tile_index_x = index - tile_index_y * tile_state_.num_tiles_x;
+
+ const int tile_window_x = tile_index_x * tile_size_.x;
+ const int tile_window_y = tile_index_y * tile_size_.y;
+
+ Tile tile;
+
+ tile.x = max(0, tile_window_x - overscan_);
+ tile.y = max(0, tile_window_y - overscan_);
+
+ tile.window_x = tile_window_x - tile.x;
+ tile.window_y = tile_window_y - tile.y;
+ tile.window_width = min(tile_size_.x, buffer_params_.width - tile_window_x);
+ tile.window_height = min(tile_size_.y, buffer_params_.height - tile_window_y);
+
+ tile.width = min(buffer_params_.width - tile.x, tile.window_x + tile.window_width + overscan_);
+ tile.height = min(buffer_params_.height - tile.y,
+ tile.window_y + tile.window_height + overscan_);
+
+ return tile;
+}
+
+const Tile &TileManager::get_current_tile() const
+{
+ return tile_state_.current_tile;
+}
+
+const int2 TileManager::get_size() const
+{
+ return make_int2(buffer_params_.width, buffer_params_.height);
+}
+
+bool TileManager::open_tile_output()
+{
+ write_state_.filename = path_temp_get("cycles-tile-buffer-" + tile_file_unique_part_ + "-" +
+ to_string(write_state_.tile_file_index) + ".exr");
+
+ write_state_.tile_out = ImageOutput::create(write_state_.filename);
+ if (!write_state_.tile_out) {
+ LOG(ERROR) << "Error creating image output for " << write_state_.filename;
+ return false;
+ }
+
+ if (!write_state_.tile_out->supports("tiles")) {
+ LOG(ERROR) << "Progress tile file format does not support tiling.";
+ return false;
+ }
+
+ if (!write_state_.tile_out->open(write_state_.filename, write_state_.image_spec)) {
+ LOG(ERROR) << "Error opening tile file: " << write_state_.tile_out->geterror();
+ write_state_.tile_out = nullptr;
+ return false;
+ }
+
+ write_state_.num_tiles_written = 0;
+
+ VLOG(3) << "Opened tile file " << write_state_.filename;
+
+ return true;
+}
+
+bool TileManager::close_tile_output()
+{
+ if (!write_state_.tile_out) {
+ return true;
+ }
+
+ const bool success = write_state_.tile_out->close();
+ write_state_.tile_out = nullptr;
+
+ if (!success) {
+ LOG(ERROR) << "Error closing tile file.";
+ return false;
+ }
+
+ VLOG(3) << "Tile output is closed.";
+
+ return true;
+}
+
+bool TileManager::write_tile(const RenderBuffers &tile_buffers)
+{
+ if (!write_state_.tile_out) {
+ if (!open_tile_output()) {
+ return false;
+ }
+ }
+
+ DCHECK_EQ(tile_buffers.params.pass_stride, buffer_params_.pass_stride);
+
+ vector<float> pixel_storage;
+
+ const BufferParams &tile_params = tile_buffers.params;
+
+ const int tile_x = tile_params.full_x - buffer_params_.full_x + tile_params.window_x;
+ const int tile_y = tile_params.full_y - buffer_params_.full_y + tile_params.window_y;
+
+ const int64_t pass_stride = tile_params.pass_stride;
+ const int64_t tile_row_stride = tile_params.width * pass_stride;
+
+ const int64_t xstride = pass_stride * sizeof(float);
+ const int64_t ystride = xstride * tile_params.width;
+ const int64_t zstride = ystride * tile_params.height;
+
+ const float *pixels = tile_buffers.buffer.data() + tile_params.window_x * pass_stride +
+ tile_params.window_y * tile_row_stride;
+
+ VLOG(3) << "Write tile at " << tile_x << ", " << tile_y;
+
+ /* The image tile sizes in the OpenEXR file are different from the size of our big tiles. The
+ * write_tiles() method expects a contiguous image region that will be split into tiles
+ * internally. OpenEXR expects the size of this region to be a multiple of the tile size,
+ * however OpenImageIO automatically adds the required padding.
+ *
+ * The only thing we have to ensure is that the tile_x and tile_y are a multiple of the
+ * image tile size, which happens in compute_render_tile_size. */
+ if (!write_state_.tile_out->write_tiles(tile_x,
+ tile_x + tile_params.window_width,
+ tile_y,
+ tile_y + tile_params.window_height,
+ 0,
+ 1,
+ TypeDesc::FLOAT,
+ pixels,
+ xstride,
+ ystride,
+ zstride)) {
+ LOG(ERROR) << "Error writing tile " << write_state_.tile_out->geterror();
+ return false;
+ }
+
+ ++write_state_.num_tiles_written;
+
+ return true;
+}
+
+void TileManager::finish_write_tiles()
+{
+ if (!write_state_.tile_out) {
+ /* None of the tiles were written hence the file was not created.
+ * Avoid creation of fully empty file since it is redundant. */
+ return;
+ }
+
+ /* EXR expects all tiles to present in file. So explicitly write missing tiles as all-zero. */
+ if (write_state_.num_tiles_written < tile_state_.num_tiles) {
+ vector<float> pixel_storage(tile_size_.x * tile_size_.y * buffer_params_.pass_stride);
+
+ for (int tile_index = write_state_.num_tiles_written; tile_index < tile_state_.num_tiles;
+ ++tile_index) {
+ const Tile tile = get_tile_for_index(tile_index);
+
+ const int tile_x = tile.x + tile.window_x;
+ const int tile_y = tile.y + tile.window_y;
+
+ VLOG(3) << "Write dummy tile at " << tile_x << ", " << tile_y;
+
+ write_state_.tile_out->write_tiles(tile_x,
+ tile_x + tile.window_width,
+ tile_y,
+ tile_y + tile.window_height,
+ 0,
+ 1,
+ TypeDesc::FLOAT,
+ pixel_storage.data());
+ }
+ }
+
+ close_tile_output();
+
+ if (full_buffer_written_cb) {
+ full_buffer_written_cb(write_state_.filename);
+ }
+
+ /* Advance the counter upon explicit finish of the file.
+ * Makes it possible to re-use tile manager for another scene, and avoids unnecessary increments
+ * of the tile-file-within-session index. */
+ ++write_state_.tile_file_index;
+
+ write_state_.filename = "";
+}
+
+bool TileManager::read_full_buffer_from_disk(const string_view filename,
+ RenderBuffers *buffers,
+ DenoiseParams *denoise_params)
+{
+ unique_ptr<ImageInput> in(ImageInput::open(filename));
+ if (!in) {
+ LOG(ERROR) << "Error opening tile file " << filename;
+ return false;
+ }
+
+ const ImageSpec &image_spec = in->spec();
+
+ BufferParams buffer_params;
+ if (!buffer_params_from_image_spec_atttributes(&buffer_params, image_spec)) {
+ return false;
+ }
+ buffers->reset(buffer_params);
+
+ if (!node_from_image_spec_atttributes(denoise_params, image_spec, ATTR_DENOISE_SOCKET_PREFIX)) {
+ return false;
+ }
+
+ if (!in->read_image(TypeDesc::FLOAT, buffers->buffer.data())) {
+ LOG(ERROR) << "Error reading pixels from the tile file " << in->geterror();
+ return false;
+ }
+
+ if (!in->close()) {
+ LOG(ERROR) << "Error closing tile file " << in->geterror();
+ return false;
+ }
+
+ return true;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/session/tile.h b/intern/cycles/session/tile.h
new file mode 100644
index 00000000000..eace148eb0a
--- /dev/null
+++ b/intern/cycles/session/tile.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "session/buffers.h"
+#include "util/image.h"
+#include "util/string.h"
+#include "util/unique_ptr.h"
+
+CCL_NAMESPACE_BEGIN
+
+class DenoiseParams;
+class Scene;
+
+/* --------------------------------------------------------------------
+ * Tile.
+ */
+
+class Tile {
+ public:
+ int x = 0, y = 0;
+ int width = 0, height = 0;
+
+ int window_x = 0, window_y = 0;
+ int window_width = 0, window_height = 0;
+
+ Tile()
+ {
+ }
+};
+
+/* --------------------------------------------------------------------
+ * Tile Manager.
+ */
+
+class TileManager {
+ public:
+ /* This callback is invoked by whenever on-dist tiles storage file is closed after writing. */
+ function<void(string_view)> full_buffer_written_cb;
+
+ TileManager();
+ ~TileManager();
+
+ TileManager(const TileManager &other) = delete;
+ TileManager(TileManager &&other) noexcept = delete;
+ TileManager &operator=(const TileManager &other) = delete;
+ TileManager &operator=(TileManager &&other) = delete;
+
+ /* Reset current progress and start new rendering of the full-frame parameters in tiles of the
+ * given size.
+ * Only touches scheduling-related state of the tile manager. */
+ /* TODO(sergey): Consider using tile area instead of exact size to help dealing with extreme
+ * cases of stretched renders. */
+ void reset_scheduling(const BufferParams &params, int2 tile_size);
+
+ /* Update for the known buffer passes and scene parameters.
+ * Will store all parameters needed for buffers access outside of the scene graph. */
+ void update(const BufferParams &params, const Scene *scene);
+
+ inline int get_num_tiles() const
+ {
+ return tile_state_.num_tiles;
+ }
+
+ inline bool has_multiple_tiles() const
+ {
+ return tile_state_.num_tiles > 1;
+ }
+
+ inline int get_tile_overscan() const
+ {
+ return overscan_;
+ }
+
+ bool next();
+ bool done();
+
+ const Tile &get_current_tile() const;
+ const int2 get_size() const;
+
+ /* Write render buffer of a tile to a file on disk.
+ *
+ * Opens file for write when first tile is written.
+ *
+ * Returns true on success. */
+ bool write_tile(const RenderBuffers &tile_buffers);
+
+ /* Inform the tile manager that no more tiles will be written to disk.
+ * The file will be considered final, all handles to it will be closed. */
+ void finish_write_tiles();
+
+ /* Check whether any tile has been written to disk. */
+ inline bool has_written_tiles() const
+ {
+ return write_state_.num_tiles_written != 0;
+ }
+
+ /* Read full frame render buffer from tiles file on disk.
+ *
+ * Returns true on success. */
+ bool read_full_buffer_from_disk(string_view filename,
+ RenderBuffers *buffers,
+ DenoiseParams *denoise_params);
+
+ /* Compute valid tile size compatible with image saving. */
+ int compute_render_tile_size(const int suggested_tile_size) const;
+
+ /* Tile size in the image file. */
+ static const int IMAGE_TILE_SIZE = 128;
+
+ protected:
+ /* Get tile configuration for its index.
+ * The tile index must be within [0, state_.tile_state_). */
+ Tile get_tile_for_index(int index) const;
+
+ bool open_tile_output();
+ bool close_tile_output();
+
+ /* Part of an on-disk tile file name which avoids conflicts between several Cycles instances or
+ * several sessions. */
+ string tile_file_unique_part_;
+
+ int2 tile_size_ = make_int2(0, 0);
+
+ /* Number of extra pixels around the actual tile to render. */
+ int overscan_ = 0;
+
+ BufferParams buffer_params_;
+
+ /* Tile scheduling state. */
+ struct {
+ int num_tiles_x = 0;
+ int num_tiles_y = 0;
+ int num_tiles = 0;
+
+ int next_tile_index;
+
+ Tile current_tile;
+ } tile_state_;
+
+ /* State of tiles writing to a file on disk. */
+ struct {
+ /* Index of a tile file used during the current session.
+ * This number is used for the file name construction, making it possible to render several
+ * scenes throughout duration of the session and keep all results available for later read
+ * access. */
+ int tile_file_index = 0;
+
+ string filename;
+
+ /* Specification of the tile image which corresponds to the buffer parameters.
+ * Contains channels configured according to the passes configuration in the path traces.
+ *
+ * Output images are saved using this specification, input images are expected to have matched
+ * specification. */
+ ImageSpec image_spec;
+
+ /* Output handle for the tile file.
+ *
+ * This file can not be closed until all tiles has been provided, so the handle is stored in
+ * the state and is created whenever writing is requested. */
+ unique_ptr<ImageOutput> tile_out;
+
+ int num_tiles_written = 0;
+ } write_state_;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/CMakeLists.txt b/intern/cycles/subd/CMakeLists.txt
index c697ddb9891..4bf5503dc4b 100644
--- a/intern/cycles/subd/CMakeLists.txt
+++ b/intern/cycles/subd/CMakeLists.txt
@@ -21,18 +21,18 @@ set(INC_SYS
)
set(SRC
- subd_dice.cpp
- subd_patch.cpp
- subd_split.cpp
- subd_patch_table.cpp
+ dice.cpp
+ patch.cpp
+ split.cpp
+ patch_table.cpp
)
set(SRC_HEADERS
- subd_dice.h
- subd_patch.h
- subd_patch_table.h
- subd_split.h
- subd_subpatch.h
+ dice.h
+ patch.h
+ patch_table.h
+ split.h
+ subpatch.h
)
set(LIB
diff --git a/intern/cycles/subd/dice.cpp b/intern/cycles/subd/dice.cpp
new file mode 100644
index 00000000000..461fa0bcd9c
--- /dev/null
+++ b/intern/cycles/subd/dice.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/camera.h"
+#include "scene/mesh.h"
+
+#include "subd/dice.h"
+#include "subd/patch.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* EdgeDice Base */
+
+EdgeDice::EdgeDice(const SubdParams &params_) : params(params_)
+{
+ mesh_P = NULL;
+ mesh_N = NULL;
+ vert_offset = 0;
+
+ params.mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
+
+ if (params.ptex) {
+ params.mesh->attributes.add(ATTR_STD_PTEX_UV);
+ params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID);
+ }
+}
+
+void EdgeDice::reserve(int num_verts, int num_triangles)
+{
+ Mesh *mesh = params.mesh;
+
+ vert_offset = mesh->get_verts().size();
+ tri_offset = mesh->num_triangles();
+
+ mesh->resize_mesh(mesh->get_verts().size() + num_verts, mesh->num_triangles());
+ mesh->reserve_mesh(mesh->get_verts().size() + num_verts, mesh->num_triangles() + num_triangles);
+
+ Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
+
+ mesh_P = mesh->verts.data() + vert_offset;
+ mesh_N = attr_vN->data_float3() + vert_offset;
+
+ params.mesh->num_subd_verts += num_verts;
+}
+
+void EdgeDice::set_vert(Patch *patch, int index, float2 uv)
+{
+ float3 P, N;
+
+ patch->eval(&P, NULL, NULL, &N, uv.x, uv.y);
+
+ assert(index < params.mesh->verts.size());
+
+ mesh_P[index] = P;
+ mesh_N[index] = N;
+ params.mesh->vert_patch_uv[index + vert_offset] = make_float2(uv.x, uv.y);
+}
+
+void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2)
+{
+ Mesh *mesh = params.mesh;
+
+ mesh->add_triangle(v0 + vert_offset, v1 + vert_offset, v2 + vert_offset, patch->shader, true);
+ params.mesh->triangle_patch[params.mesh->num_triangles() - 1] = patch->patch_index;
+
+ tri_offset++;
+}
+
+void EdgeDice::stitch_triangles(Subpatch &sub, int edge)
+{
+ int Mu = max(sub.edge_u0.T, sub.edge_u1.T);
+ int Mv = max(sub.edge_v0.T, sub.edge_v1.T);
+ Mu = max(Mu, 2);
+ Mv = max(Mv, 2);
+
+ int outer_T = sub.edges[edge].T;
+ int inner_T = ((edge % 2) == 0) ? Mv - 2 : Mu - 2;
+
+ if (inner_T < 0 || outer_T < 0)
+ return; // XXX avoid crashes for Mu or Mv == 1, missing polygons
+
+ /* stitch together two arrays of verts with triangles. at each step,
+ * we compare using the next verts on both sides, to find the split
+ * direction with the smallest diagonal, and use that in order to keep
+ * the triangle shape reasonable. */
+ for (size_t i = 0, j = 0; i < inner_T || j < outer_T;) {
+ int v0, v1, v2;
+
+ v0 = sub.get_vert_along_grid_edge(edge, i);
+ v1 = sub.get_vert_along_edge(edge, j);
+
+ if (j == outer_T) {
+ v2 = sub.get_vert_along_grid_edge(edge, ++i);
+ }
+ else if (i == inner_T) {
+ v2 = sub.get_vert_along_edge(edge, ++j);
+ }
+ else {
+ /* length of diagonals */
+ float len1 = len_squared(mesh_P[sub.get_vert_along_grid_edge(edge, i)] -
+ mesh_P[sub.get_vert_along_edge(edge, j + 1)]);
+ float len2 = len_squared(mesh_P[sub.get_vert_along_edge(edge, j)] -
+ mesh_P[sub.get_vert_along_grid_edge(edge, i + 1)]);
+
+ /* use smallest diagonal */
+ if (len1 < len2)
+ v2 = sub.get_vert_along_edge(edge, ++j);
+ else
+ v2 = sub.get_vert_along_grid_edge(edge, ++i);
+ }
+
+ add_triangle(sub.patch, v1, v0, v2);
+ }
+}
+
+/* QuadDice */
+
+QuadDice::QuadDice(const SubdParams &params_) : EdgeDice(params_)
+{
+}
+
+float2 QuadDice::map_uv(Subpatch &sub, float u, float v)
+{
+ /* map UV from subpatch to patch parametric coordinates */
+ float2 d0 = interp(sub.c00, sub.c01, v);
+ float2 d1 = interp(sub.c10, sub.c11, v);
+ return interp(d0, d1, u);
+}
+
+float3 QuadDice::eval_projected(Subpatch &sub, float u, float v)
+{
+ float2 uv = map_uv(sub, u, v);
+ float3 P;
+
+ sub.patch->eval(&P, NULL, NULL, NULL, uv.x, uv.y);
+ if (params.camera)
+ P = transform_perspective(&params.camera->worldtoraster, P);
+
+ return P;
+}
+
+void QuadDice::set_vert(Subpatch &sub, int index, float u, float v)
+{
+ EdgeDice::set_vert(sub.patch, index, map_uv(sub, u, v));
+}
+
+void QuadDice::set_side(Subpatch &sub, int edge)
+{
+ int t = sub.edges[edge].T;
+
+ /* set verts on the edge of the patch */
+ for (int i = 0; i < t; i++) {
+ float f = i / (float)t;
+
+ float u, v;
+ switch (edge) {
+ case 0:
+ u = 0;
+ v = f;
+ break;
+ case 1:
+ u = f;
+ v = 1;
+ break;
+ case 2:
+ u = 1;
+ v = 1.0f - f;
+ break;
+ case 3:
+ default:
+ u = 1.0f - f;
+ v = 0;
+ break;
+ }
+
+ set_vert(sub, sub.get_vert_along_edge(edge, i), u, v);
+ }
+}
+
+float QuadDice::quad_area(const float3 &a, const float3 &b, const float3 &c, const float3 &d)
+{
+ return triangle_area(a, b, d) + triangle_area(a, d, c);
+}
+
+float QuadDice::scale_factor(Subpatch &sub, int Mu, int Mv)
+{
+ /* estimate area as 4x largest of 4 quads */
+ float3 P[3][3];
+
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ P[i][j] = eval_projected(sub, i * 0.5f, j * 0.5f);
+
+ float A1 = quad_area(P[0][0], P[1][0], P[0][1], P[1][1]);
+ float A2 = quad_area(P[1][0], P[2][0], P[1][1], P[2][1]);
+ float A3 = quad_area(P[0][1], P[1][1], P[0][2], P[1][2]);
+ float A4 = quad_area(P[1][1], P[2][1], P[1][2], P[2][2]);
+ float Apatch = max(A1, max(A2, max(A3, A4))) * 4.0f;
+
+ /* solve for scaling factor */
+ float Atri = params.dicing_rate * params.dicing_rate * 0.5f;
+ float Ntris = Apatch / Atri;
+
+ // XXX does the -sqrt solution matter
+ // XXX max(D, 0.0) is highly suspicious, need to test cases
+ // where D goes negative
+ float N = 0.5f * (Ntris - (sub.edge_u0.T + sub.edge_u1.T + sub.edge_v0.T + sub.edge_v1.T));
+ float D = 4.0f * N * Mu * Mv + (Mu + Mv) * (Mu + Mv);
+ float S = (Mu + Mv + sqrtf(max(D, 0.0f))) / (2 * Mu * Mv);
+
+ return S;
+}
+
+void QuadDice::add_grid(Subpatch &sub, int Mu, int Mv, int offset)
+{
+ /* create inner grid */
+ float du = 1.0f / (float)Mu;
+ float dv = 1.0f / (float)Mv;
+
+ for (int j = 1; j < Mv; j++) {
+ for (int i = 1; i < Mu; i++) {
+ float u = i * du;
+ float v = j * dv;
+
+ set_vert(sub, offset + (i - 1) + (j - 1) * (Mu - 1), u, v);
+
+ if (i < Mu - 1 && j < Mv - 1) {
+ int i1 = offset + (i - 1) + (j - 1) * (Mu - 1);
+ int i2 = offset + i + (j - 1) * (Mu - 1);
+ int i3 = offset + i + j * (Mu - 1);
+ int i4 = offset + (i - 1) + j * (Mu - 1);
+
+ add_triangle(sub.patch, i1, i2, i3);
+ add_triangle(sub.patch, i1, i3, i4);
+ }
+ }
+ }
+}
+
+void QuadDice::dice(Subpatch &sub)
+{
+ /* compute inner grid size with scale factor */
+ int Mu = max(sub.edge_u0.T, sub.edge_u1.T);
+ int Mv = max(sub.edge_v0.T, sub.edge_v1.T);
+
+#if 0 /* Doesn't work very well, especially at grazing angles. */
+ float S = scale_factor(sub, ef, Mu, Mv);
+#else
+ float S = 1.0f;
+#endif
+
+ Mu = max((int)ceilf(S * Mu), 2); // XXX handle 0 & 1?
+ Mv = max((int)ceilf(S * Mv), 2); // XXX handle 0 & 1?
+
+ /* inner grid */
+ add_grid(sub, Mu, Mv, sub.inner_grid_vert_offset);
+
+ /* sides */
+ set_side(sub, 0);
+ set_side(sub, 1);
+ set_side(sub, 2);
+ set_side(sub, 3);
+
+ stitch_triangles(sub, 0);
+ stitch_triangles(sub, 1);
+ stitch_triangles(sub, 2);
+ stitch_triangles(sub, 3);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/dice.h b/intern/cycles/subd/dice.h
new file mode 100644
index 00000000000..7510aae775c
--- /dev/null
+++ b/intern/cycles/subd/dice.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SUBD_DICE_H__
+#define __SUBD_DICE_H__
+
+/* DX11 like EdgeDice implementation, with different tessellation factors for
+ * each edge for watertight tessellation, with subpatch remapping to work with
+ * DiagSplit. For more algorithm details, see the DiagSplit paper or the
+ * ARB_tessellation_shader OpenGL extension, Section 2.X.2. */
+
+#include "util/types.h"
+#include "util/vector.h"
+
+#include "subd/subpatch.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Camera;
+class Mesh;
+class Patch;
+
+struct SubdParams {
+ Mesh *mesh;
+ bool ptex;
+
+ int test_steps;
+ int split_threshold;
+ float dicing_rate;
+ int max_level;
+ Camera *camera;
+ Transform objecttoworld;
+
+ SubdParams(Mesh *mesh_, bool ptex_ = false)
+ {
+ mesh = mesh_;
+ ptex = ptex_;
+
+ test_steps = 3;
+ split_threshold = 1;
+ dicing_rate = 1.0f;
+ max_level = 12;
+ camera = NULL;
+ }
+};
+
+/* EdgeDice Base */
+
+class EdgeDice {
+ public:
+ SubdParams params;
+ float3 *mesh_P;
+ float3 *mesh_N;
+ size_t vert_offset;
+ size_t tri_offset;
+
+ explicit EdgeDice(const SubdParams &params);
+
+ void reserve(int num_verts, int num_triangles);
+
+ void set_vert(Patch *patch, int index, float2 uv);
+ void add_triangle(Patch *patch, int v0, int v1, int v2);
+
+ void stitch_triangles(Subpatch &sub, int edge);
+};
+
+/* Quad EdgeDice */
+
+class QuadDice : public EdgeDice {
+ public:
+ explicit QuadDice(const SubdParams &params);
+
+ float3 eval_projected(Subpatch &sub, float u, float v);
+
+ float2 map_uv(Subpatch &sub, float u, float v);
+ void set_vert(Subpatch &sub, int index, float u, float v);
+
+ void add_grid(Subpatch &sub, int Mu, int Mv, int offset);
+
+ void set_side(Subpatch &sub, int edge);
+
+ float quad_area(const float3 &a, const float3 &b, const float3 &c, const float3 &d);
+ float scale_factor(Subpatch &sub, int Mu, int Mv);
+
+ void dice(Subpatch &sub);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __SUBD_DICE_H__ */
diff --git a/intern/cycles/subd/patch.cpp b/intern/cycles/subd/patch.cpp
new file mode 100644
index 00000000000..4d73f334c1b
--- /dev/null
+++ b/intern/cycles/subd/patch.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Parts adapted from code in the public domain in NVidia Mesh Tools. */
+
+#include "scene/mesh.h"
+
+#include "subd/patch.h"
+
+#include "util/math.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* De Casteljau Evaluation */
+
+static void decasteljau_cubic(float3 *P, float3 *dt, float t, const float3 cp[4])
+{
+ float3 d0 = cp[0] + t * (cp[1] - cp[0]);
+ float3 d1 = cp[1] + t * (cp[2] - cp[1]);
+ float3 d2 = cp[2] + t * (cp[3] - cp[2]);
+
+ d0 += t * (d1 - d0);
+ d1 += t * (d2 - d1);
+
+ *P = d0 + t * (d1 - d0);
+ if (dt)
+ *dt = d1 - d0;
+}
+
+static void decasteljau_bicubic(
+ float3 *P, float3 *du, float3 *dv, const float3 cp[16], float u, float v)
+{
+ float3 ucp[4], utn[4];
+
+ /* interpolate over u */
+ decasteljau_cubic(ucp + 0, utn + 0, u, cp);
+ decasteljau_cubic(ucp + 1, utn + 1, u, cp + 4);
+ decasteljau_cubic(ucp + 2, utn + 2, u, cp + 8);
+ decasteljau_cubic(ucp + 3, utn + 3, u, cp + 12);
+
+ /* interpolate over v */
+ decasteljau_cubic(P, dv, v, ucp);
+ if (du)
+ decasteljau_cubic(du, NULL, v, utn);
+}
+
+/* Linear Quad Patch */
+
+void LinearQuadPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
+{
+ float3 d0 = interp(hull[0], hull[1], u);
+ float3 d1 = interp(hull[2], hull[3], u);
+
+ *P = interp(d0, d1, v);
+
+ if (dPdu && dPdv) {
+ *dPdu = interp(hull[1] - hull[0], hull[3] - hull[2], v);
+ *dPdv = interp(hull[2] - hull[0], hull[3] - hull[1], u);
+ }
+
+ if (N) {
+ *N = normalize(
+ interp(interp(normals[0], normals[1], u), interp(normals[2], normals[3], u), v));
+ }
+}
+
+BoundBox LinearQuadPatch::bound()
+{
+ BoundBox bbox = BoundBox::empty;
+
+ for (int i = 0; i < 4; i++)
+ bbox.grow(hull[i]);
+
+ return bbox;
+}
+
+/* Bicubic Patch */
+
+void BicubicPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
+{
+ if (N) {
+ float3 dPdu_, dPdv_;
+ decasteljau_bicubic(P, &dPdu_, &dPdv_, hull, u, v);
+
+ if (dPdu && dPdv) {
+ *dPdu = dPdu_;
+ *dPdv = dPdv_;
+ }
+
+ *N = normalize(cross(dPdu_, dPdv_));
+ }
+ else {
+ decasteljau_bicubic(P, dPdu, dPdv, hull, u, v);
+ }
+}
+
+BoundBox BicubicPatch::bound()
+{
+ BoundBox bbox = BoundBox::empty;
+
+ for (int i = 0; i < 16; i++)
+ bbox.grow(hull[i]);
+
+ return bbox;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/patch.h b/intern/cycles/subd/patch.h
new file mode 100644
index 00000000000..ad4dc1bd8e9
--- /dev/null
+++ b/intern/cycles/subd/patch.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SUBD_PATCH_H__
+#define __SUBD_PATCH_H__
+
+#include "util/boundbox.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Patch {
+ public:
+ Patch() : patch_index(0), shader(0), from_ngon(false)
+ {
+ }
+
+ virtual ~Patch() = default;
+
+ virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) = 0;
+
+ int patch_index;
+ int shader;
+ bool from_ngon;
+};
+
+/* Linear Quad Patch */
+
+class LinearQuadPatch : public Patch {
+ public:
+ float3 hull[4];
+ float3 normals[4];
+
+ void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
+ BoundBox bound();
+};
+
+/* Bicubic Patch */
+
+class BicubicPatch : public Patch {
+ public:
+ float3 hull[16];
+
+ void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
+ BoundBox bound();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __SUBD_PATCH_H__ */
diff --git a/intern/cycles/subd/patch_table.cpp b/intern/cycles/subd/patch_table.cpp
new file mode 100644
index 00000000000..d215dfaa1dd
--- /dev/null
+++ b/intern/cycles/subd/patch_table.cpp
@@ -0,0 +1,295 @@
+/*
+ * Based on code from OpenSubdiv released under this license:
+ *
+ * Copyright 2014 DreamWorks Animation LLC.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "Apache License")
+ * with the following modification; you may not use this file except in
+ * compliance with the Apache License and the following modification to it:
+ * Section 6. Trademarks. is deleted and replaced with:
+ *
+ * 6. Trademarks. This License does not grant permission to use the trade
+ * names, trademarks, service marks, or product names of the Licensor
+ * and its affiliates, except as required to comply with Section 4(c) of
+ * the License and to reproduce the content of the NOTICE file.
+ *
+ * You may obtain a copy of the Apache License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Apache License with the above modification is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the Apache License for the specific
+ * language governing permissions and limitations under the Apache License.
+ */
+
+#include "subd/patch_table.h"
+#include "kernel/types.h"
+
+#include "util/math.h"
+
+#ifdef WITH_OPENSUBDIV
+# include <opensubdiv/far/patchTable.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_OPENSUBDIV
+
+using namespace OpenSubdiv;
+
+/* functions for building patch maps */
+
+struct PatchMapQuadNode {
+ /* sets all the children to point to the patch of index */
+ void set_child(int index)
+ {
+ for (int i = 0; i < 4; i++) {
+ children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF;
+ }
+ }
+
+ /* sets the child in quadrant to point to the node or patch of the given index */
+ void set_child(unsigned char quadrant, int index, bool is_leaf = true)
+ {
+ assert(quadrant < 4);
+ children[quadrant] = index | PATCH_MAP_NODE_IS_SET | (is_leaf ? PATCH_MAP_NODE_IS_LEAF : 0);
+ }
+
+ uint children[4];
+};
+
+template<class T> static int resolve_quadrant(T &median, T &u, T &v)
+{
+ int quadrant = -1;
+
+ if (u < median) {
+ if (v < median) {
+ quadrant = 0;
+ }
+ else {
+ quadrant = 1;
+ v -= median;
+ }
+ }
+ else {
+ if (v < median) {
+ quadrant = 3;
+ }
+ else {
+ quadrant = 2;
+ v -= median;
+ }
+ u -= median;
+ }
+
+ return quadrant;
+}
+
+static void build_patch_map(PackedPatchTable &table,
+ OpenSubdiv::Far::PatchTable *patch_table,
+ int offset)
+{
+ int num_faces = 0;
+
+ for (int array = 0; array < table.num_arrays; array++) {
+ Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
+
+ for (int j = 0; j < patch_table->GetNumPatches(array); j++) {
+ num_faces = max(num_faces, (int)params[j].GetFaceId());
+ }
+ }
+ num_faces++;
+
+ vector<PatchMapQuadNode> quadtree;
+ quadtree.reserve(num_faces + table.num_patches);
+ quadtree.resize(num_faces);
+
+ /* adjust offsets to make indices relative to the table */
+ int handle_index = -(table.num_patches * PATCH_HANDLE_SIZE);
+ offset += table.total_size();
+
+ /* populate the quadtree from the FarPatchArrays sub-patches */
+ for (int array = 0; array < table.num_arrays; array++) {
+ Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
+
+ for (int i = 0; i < patch_table->GetNumPatches(array);
+ i++, handle_index += PATCH_HANDLE_SIZE) {
+ const Far::PatchParam &param = params[i];
+ unsigned short depth = param.GetDepth();
+
+ PatchMapQuadNode *node = &quadtree[params[i].GetFaceId()];
+
+ if (depth == (param.NonQuadRoot() ? 1 : 0)) {
+ /* special case : regular BSpline face w/ no sub-patches */
+ node->set_child(handle_index + offset);
+ continue;
+ }
+
+ int u = param.GetU();
+ int v = param.GetV();
+ int pdepth = param.NonQuadRoot() ? depth - 2 : depth - 1;
+ int half = 1 << pdepth;
+
+ for (int j = 0; j < depth; j++) {
+ int delta = half >> 1;
+
+ int quadrant = resolve_quadrant(half, u, v);
+ assert(quadrant >= 0);
+
+ half = delta;
+
+ if (j == pdepth) {
+ /* we have reached the depth of the sub-patch : add a leaf */
+ assert(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET));
+ node->set_child(quadrant, handle_index + offset, true);
+ break;
+ }
+ else {
+ /* travel down the child node of the corresponding quadrant */
+ if (!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET)) {
+ /* create a new branch in the quadrant */
+ quadtree.push_back(PatchMapQuadNode());
+
+ int idx = (int)quadtree.size() - 1;
+ node->set_child(quadrant, idx * 4 + offset, false);
+
+ node = &quadtree[idx];
+ }
+ else {
+ /* travel down an existing branch */
+ uint idx = node->children[quadrant] & PATCH_MAP_NODE_INDEX_MASK;
+ node = &(quadtree[(idx - offset) / 4]);
+ }
+ }
+ }
+ }
+ }
+
+ /* copy into table */
+ assert(table.table.size() == table.total_size());
+ uint map_offset = table.total_size();
+
+ table.num_nodes = quadtree.size() * 4;
+ table.table.resize(table.total_size());
+
+ uint *data = &table.table[map_offset];
+
+ for (int i = 0; i < quadtree.size(); i++) {
+ for (int j = 0; j < 4; j++) {
+ assert(quadtree[i].children[j] & PATCH_MAP_NODE_IS_SET);
+ *(data++) = quadtree[i].children[j];
+ }
+ }
+}
+
+#endif
+
+/* packed patch table functions */
+
+size_t PackedPatchTable::total_size()
+{
+ return num_arrays * PATCH_ARRAY_SIZE + num_indices +
+ num_patches * (PATCH_PARAM_SIZE + PATCH_HANDLE_SIZE) + num_nodes * PATCH_NODE_SIZE;
+}
+
+void PackedPatchTable::pack(Far::PatchTable *patch_table, int offset)
+{
+ num_arrays = 0;
+ num_patches = 0;
+ num_indices = 0;
+ num_nodes = 0;
+
+#ifdef WITH_OPENSUBDIV
+ num_arrays = patch_table->GetNumPatchArrays();
+
+ for (int i = 0; i < num_arrays; i++) {
+ int patches = patch_table->GetNumPatches(i);
+ int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
+
+ num_patches += patches;
+ num_indices += patches * num_control;
+ }
+
+ table.resize(total_size());
+ uint *data = table.data();
+
+ uint *array = data;
+ uint *index = array + num_arrays * PATCH_ARRAY_SIZE;
+ uint *param = index + num_indices;
+ uint *handle = param + num_patches * PATCH_PARAM_SIZE;
+
+ uint current_param = 0;
+
+ for (int i = 0; i < num_arrays; i++) {
+ *(array++) = patch_table->GetPatchArrayDescriptor(i).GetType();
+ *(array++) = patch_table->GetNumPatches(i);
+ *(array++) = (index - data) + offset;
+ *(array++) = (param - data) + offset;
+
+ Far::ConstIndexArray indices = patch_table->GetPatchArrayVertices(i);
+
+ for (int j = 0; j < indices.size(); j++) {
+ *(index++) = indices[j];
+ }
+
+ const Far::PatchParamTable &param_table = patch_table->GetPatchParamTable();
+
+ int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
+ int patches = patch_table->GetNumPatches(i);
+
+ for (int j = 0; j < patches; j++, current_param++) {
+ *(param++) = param_table[current_param].field0;
+ *(param++) = param_table[current_param].field1;
+
+ *(handle++) = (array - data) - PATCH_ARRAY_SIZE + offset;
+ *(handle++) = (param - data) - PATCH_PARAM_SIZE + offset;
+ *(handle++) = j * num_control;
+ }
+ }
+
+ build_patch_map(*this, patch_table, offset);
+#else
+ (void)patch_table;
+ (void)offset;
+#endif
+}
+
+void PackedPatchTable::copy_adjusting_offsets(uint *dest, int doffset)
+{
+ uint *src = table.data();
+
+ /* arrays */
+ for (int i = 0; i < num_arrays; i++) {
+ *(dest++) = *(src++);
+ *(dest++) = *(src++);
+ *(dest++) = *(src++) + doffset;
+ *(dest++) = *(src++) + doffset;
+ }
+
+ /* indices */
+ for (int i = 0; i < num_indices; i++) {
+ *(dest++) = *(src++);
+ }
+
+ /* params */
+ for (int i = 0; i < num_patches; i++) {
+ *(dest++) = *(src++);
+ *(dest++) = *(src++);
+ }
+
+ /* handles */
+ for (int i = 0; i < num_patches; i++) {
+ *(dest++) = *(src++) + doffset;
+ *(dest++) = *(src++) + doffset;
+ *(dest++) = *(src++);
+ }
+
+ /* nodes */
+ for (int i = 0; i < num_nodes; i++) {
+ *(dest++) = *(src++) + doffset;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/patch_table.h b/intern/cycles/subd/patch_table.h
new file mode 100644
index 00000000000..b5fd5923f31
--- /dev/null
+++ b/intern/cycles/subd/patch_table.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SUBD_PATCH_TABLE_H__
+#define __SUBD_PATCH_TABLE_H__
+
+#include "util/array.h"
+#include "util/types.h"
+
+#ifdef WITH_OPENSUBDIV
+# ifdef _MSC_VER
+# include "iso646.h"
+# endif
+
+# include <opensubdiv/far/patchTable.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_OPENSUBDIV
+using namespace OpenSubdiv;
+#else
+/* forward declare for when OpenSubdiv is unavailable */
+namespace Far {
+struct PatchTable;
+}
+#endif
+
+#define PATCH_ARRAY_SIZE 4
+#define PATCH_PARAM_SIZE 2
+#define PATCH_HANDLE_SIZE 3
+#define PATCH_NODE_SIZE 1
+
+struct PackedPatchTable {
+ array<uint> table;
+
+ size_t num_arrays;
+ size_t num_indices;
+ size_t num_patches;
+ size_t num_nodes;
+
+ /* calculated size from num_* members */
+ size_t total_size();
+
+ void pack(Far::PatchTable *patch_table, int offset = 0);
+ void copy_adjusting_offsets(uint *dest, int doffset);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __SUBD_PATCH_TABLE_H__ */
diff --git a/intern/cycles/subd/split.cpp b/intern/cycles/subd/split.cpp
new file mode 100644
index 00000000000..2b29f3a5a78
--- /dev/null
+++ b/intern/cycles/subd/split.cpp
@@ -0,0 +1,748 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scene/camera.h"
+#include "scene/mesh.h"
+
+#include "subd/dice.h"
+#include "subd/patch.h"
+#include "subd/split.h"
+
+#include "util/algorithm.h"
+#include "util/foreach.h"
+#include "util/hash.h"
+#include "util/math.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* DiagSplit */
+
+#define DSPLIT_NON_UNIFORM -1
+#define STITCH_NGON_CENTER_VERT_INDEX_OFFSET 0x60000000
+#define STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG (0x60000000 - 1)
+
+DiagSplit::DiagSplit(const SubdParams &params_) : params(params_)
+{
+}
+
+float3 DiagSplit::to_world(Patch *patch, float2 uv)
+{
+ float3 P;
+
+ patch->eval(&P, NULL, NULL, NULL, uv.x, uv.y);
+ if (params.camera)
+ P = transform_point(&params.objecttoworld, P);
+
+ return P;
+}
+
+static void order_float2(float2 &a, float2 &b)
+{
+ if (b.x < a.x || b.y < a.y) {
+ swap(a, b);
+ }
+}
+
+int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend, bool recursive_resolve)
+{
+ order_float2(Pstart, Pend); /* May not be necessary, but better to be safe. */
+
+ float Lsum = 0.0f;
+ float Lmax = 0.0f;
+
+ float3 Plast = to_world(patch, Pstart);
+
+ for (int i = 1; i < params.test_steps; i++) {
+ float t = i / (float)(params.test_steps - 1);
+
+ float3 P = to_world(patch, Pstart + t * (Pend - Pstart));
+
+ float L;
+
+ if (!params.camera) {
+ L = len(P - Plast);
+ }
+ else {
+ Camera *cam = params.camera;
+
+ float pixel_width = cam->world_to_raster_size((P + Plast) * 0.5f);
+ L = len(P - Plast) / pixel_width;
+ }
+
+ Lsum += L;
+ Lmax = max(L, Lmax);
+
+ Plast = P;
+ }
+
+ int tmin = (int)ceilf(Lsum / params.dicing_rate);
+ int tmax = (int)ceilf((params.test_steps - 1) * Lmax /
+ params.dicing_rate); // XXX paper says N instead of N-1, seems wrong?
+ int res = max(tmax, 1);
+
+ if (tmax - tmin > params.split_threshold) {
+ if (!recursive_resolve) {
+ res = DSPLIT_NON_UNIFORM;
+ }
+ else {
+ float2 P = (Pstart + Pend) * 0.5f;
+ res = T(patch, Pstart, P, true) + T(patch, P, Pend, true);
+ }
+ }
+
+ limit_edge_factor(res, patch, Pstart, Pend);
+ return res;
+}
+
+void DiagSplit::partition_edge(
+ Patch *patch, float2 *P, int *t0, int *t1, float2 Pstart, float2 Pend, int t)
+{
+ if (t == DSPLIT_NON_UNIFORM) {
+ *P = (Pstart + Pend) * 0.5f;
+ *t0 = T(patch, Pstart, *P);
+ *t1 = T(patch, *P, Pend);
+ }
+ else {
+ assert(t >= 2); /* Need at least two segments to partition into. */
+
+ int I = (int)floorf((float)t * 0.5f);
+ *P = interp(Pstart, Pend, I / (float)t);
+ *t0 = I;
+ *t1 = t - I;
+ }
+}
+
+void DiagSplit::limit_edge_factor(int &T, Patch *patch, float2 Pstart, float2 Pend)
+{
+ int max_t = 1 << params.max_level;
+ int max_t_for_edge = int(max_t * len(Pstart - Pend));
+
+ if (patch->from_ngon) {
+ max_t_for_edge >>= 1; /* Initial split of ngon causes edges to extend half the distance. */
+ }
+
+ T = (max_t_for_edge <= 1) ? 1 : min(T, max_t_for_edge);
+
+ assert(T >= 1 || T == DSPLIT_NON_UNIFORM);
+}
+
+void DiagSplit::resolve_edge_factors(Subpatch &sub)
+{
+ /* Resolve DSPLIT_NON_UNIFORM to actual T value if splitting is no longer possible. */
+ if (sub.edge_u0.T == 1 && sub.edge_u1.T == DSPLIT_NON_UNIFORM) {
+ sub.edge_u1.T = T(sub.patch, sub.c01, sub.c11, true);
+ }
+ if (sub.edge_u1.T == 1 && sub.edge_u0.T == DSPLIT_NON_UNIFORM) {
+ sub.edge_u0.T = T(sub.patch, sub.c00, sub.c10, true);
+ }
+ if (sub.edge_v0.T == 1 && sub.edge_v1.T == DSPLIT_NON_UNIFORM) {
+ sub.edge_v1.T = T(sub.patch, sub.c11, sub.c10, true);
+ }
+ if (sub.edge_v1.T == 1 && sub.edge_v0.T == DSPLIT_NON_UNIFORM) {
+ sub.edge_v0.T = T(sub.patch, sub.c01, sub.c00, true);
+ }
+}
+
+void DiagSplit::split(Subpatch &sub, int depth)
+{
+ if (depth > 32) {
+ /* We should never get here, but just in case end recursion safely. */
+ assert(!"diagsplit recursion limit reached");
+
+ sub.edge_u0.T = 1;
+ sub.edge_u1.T = 1;
+ sub.edge_v0.T = 1;
+ sub.edge_v1.T = 1;
+
+ subpatches.push_back(sub);
+ return;
+ }
+
+ bool split_u = (sub.edge_u0.T == DSPLIT_NON_UNIFORM || sub.edge_u1.T == DSPLIT_NON_UNIFORM);
+ bool split_v = (sub.edge_v0.T == DSPLIT_NON_UNIFORM || sub.edge_v1.T == DSPLIT_NON_UNIFORM);
+
+ /* Split subpatches such that the ratio of T for opposite edges doesn't
+ * exceed 1.5, this reduces over tessellation for some patches
+ */
+ /* clang-format off */
+ if (min(sub.edge_u0.T, sub.edge_u1.T) > 8 && /* Must be uniform and preferably greater than 8 to split. */
+ min(sub.edge_v0.T, sub.edge_v1.T) >= 2 && /* Must be uniform and at least 2 to split. */
+ max(sub.edge_u0.T, sub.edge_u1.T) / min(sub.edge_u0.T, sub.edge_u1.T) > 1.5f)
+ {
+ split_v = true;
+ }
+ if (min(sub.edge_v0.T, sub.edge_v1.T) > 8 &&
+ min(sub.edge_u0.T, sub.edge_u1.T) >= 2 &&
+ max(sub.edge_v0.T, sub.edge_v1.T) / min(sub.edge_v0.T, sub.edge_v1.T) > 1.5f)
+ {
+ split_u = true;
+ }
+ /* clang-format on */
+
+ /* Alternate axis. */
+ if (split_u && split_v) {
+ split_u = depth % 2;
+ }
+
+ if (!split_u && !split_v) {
+ /* Add the unsplit subpatch. */
+ subpatches.push_back(sub);
+ Subpatch &subpatch = subpatches[subpatches.size() - 1];
+
+ /* Update T values and offsets. */
+ for (int i = 0; i < 4; i++) {
+ Subpatch::edge_t &edge = subpatch.edges[i];
+
+ edge.offset = edge.edge->T;
+ edge.edge->T += edge.T;
+ }
+ }
+ else {
+ /* Copy into new subpatches. */
+ Subpatch sub_a = sub;
+ Subpatch sub_b = sub;
+
+ /* Pointers to various subpatch elements. */
+ Subpatch::edge_t *sub_across_0, *sub_across_1;
+ Subpatch::edge_t *sub_a_across_0, *sub_a_across_1;
+ Subpatch::edge_t *sub_b_across_0, *sub_b_across_1;
+
+ Subpatch::edge_t *sub_a_split, *sub_b_split;
+
+ float2 *Pa, *Pb, *Pc, *Pd;
+
+ /* Set pointers based on split axis. */
+ if (split_u) {
+ sub_across_0 = &sub.edge_u0;
+ sub_across_1 = &sub.edge_u1;
+ sub_a_across_0 = &sub_a.edge_u0;
+ sub_a_across_1 = &sub_a.edge_u1;
+ sub_b_across_0 = &sub_b.edge_u0;
+ sub_b_across_1 = &sub_b.edge_u1;
+
+ sub_a_split = &sub_a.edge_v1;
+ sub_b_split = &sub_b.edge_v0;
+
+ Pa = &sub_a.c11;
+ Pb = &sub_a.c10;
+ Pc = &sub_b.c01;
+ Pd = &sub_b.c00;
+ }
+ else {
+ sub_across_0 = &sub.edge_v0;
+ sub_across_1 = &sub.edge_v1;
+ sub_a_across_0 = &sub_a.edge_v0;
+ sub_a_across_1 = &sub_a.edge_v1;
+ sub_b_across_0 = &sub_b.edge_v0;
+ sub_b_across_1 = &sub_b.edge_v1;
+
+ sub_a_split = &sub_a.edge_u0;
+ sub_b_split = &sub_b.edge_u1;
+
+ Pa = &sub_a.c10;
+ Pb = &sub_a.c00;
+ Pc = &sub_b.c11;
+ Pd = &sub_b.c01;
+ }
+
+ /* Partition edges */
+ float2 P0, P1;
+
+ partition_edge(
+ sub.patch, &P0, &sub_a_across_0->T, &sub_b_across_0->T, *Pd, *Pb, sub_across_0->T);
+ partition_edge(
+ sub.patch, &P1, &sub_a_across_1->T, &sub_b_across_1->T, *Pc, *Pa, sub_across_1->T);
+
+ /* Split */
+ *Pa = P1;
+ *Pb = P0;
+
+ *Pc = P1;
+ *Pd = P0;
+
+ int tsplit = T(sub.patch, P0, P1);
+
+ if (depth == -2 && tsplit == 1) {
+ tsplit = 2; /* Ensure we can always split at depth -1. */
+ }
+
+ sub_a_split->T = tsplit;
+ sub_b_split->T = tsplit;
+
+ resolve_edge_factors(sub_a);
+ resolve_edge_factors(sub_b);
+
+ /* Create new edge */
+ Edge &edge = *alloc_edge();
+
+ sub_a_split->edge = &edge;
+ sub_b_split->edge = &edge;
+
+ sub_a_split->offset = 0;
+ sub_b_split->offset = 0;
+
+ sub_a_split->indices_decrease_along_edge = false;
+ sub_b_split->indices_decrease_along_edge = true;
+
+ sub_a_split->sub_edges_created_in_reverse_order = !split_u;
+ sub_b_split->sub_edges_created_in_reverse_order = !split_u;
+
+ edge.top_indices_decrease = sub_across_1->sub_edges_created_in_reverse_order;
+ edge.bottom_indices_decrease = sub_across_0->sub_edges_created_in_reverse_order;
+
+ /* Recurse */
+ edge.T = 0;
+ split(sub_a, depth + 1);
+
+ int edge_t = edge.T;
+ (void)edge_t;
+
+ edge.top_offset = sub_across_1->edge->T;
+ edge.bottom_offset = sub_across_0->edge->T;
+
+ edge.T = 0; /* We calculate T twice along each edge. :/ */
+ split(sub_b, depth + 1);
+
+ assert(edge.T == edge_t); /* If this fails we will crash at some later point! */
+
+ edge.top = sub_across_1->edge;
+ edge.bottom = sub_across_0->edge;
+ }
+}
+
+int DiagSplit::alloc_verts(int n)
+{
+ int a = num_alloced_verts;
+ num_alloced_verts += n;
+ return a;
+}
+
+Edge *DiagSplit::alloc_edge()
+{
+ edges.emplace_back();
+ return &edges.back();
+}
+
+void DiagSplit::split_patches(Patch *patches, size_t patches_byte_stride)
+{
+ int patch_index = 0;
+
+ for (int f = 0; f < params.mesh->get_num_subd_faces(); f++) {
+ Mesh::SubdFace face = params.mesh->get_subd_face(f);
+
+ Patch *patch = (Patch *)(((char *)patches) + patch_index * patches_byte_stride);
+
+ if (face.is_quad()) {
+ patch_index++;
+
+ split_quad(face, patch);
+ }
+ else {
+ patch_index += face.num_corners;
+
+ split_ngon(face, patch, patches_byte_stride);
+ }
+ }
+
+ params.mesh->vert_to_stitching_key_map.clear();
+ params.mesh->vert_stitching_map.clear();
+
+ post_split();
+}
+
+static Edge *create_edge_from_corner(DiagSplit *split,
+ const Mesh *mesh,
+ const Mesh::SubdFace &face,
+ int corner,
+ bool &reversed,
+ int v0,
+ int v1)
+{
+ int a = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 0, face.num_corners)];
+ int b = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 1, face.num_corners)];
+
+ reversed = !(b < a);
+
+ if (b < a) {
+ swap(a, b);
+ swap(v0, v1);
+ }
+
+ Edge *edge = split->alloc_edge();
+
+ edge->is_stitch_edge = true;
+ edge->stitch_start_vert_index = a;
+ edge->stitch_end_vert_index = b;
+
+ edge->start_vert_index = v0;
+ edge->end_vert_index = v1;
+
+ edge->stitch_edge_key = {a, b};
+
+ return edge;
+}
+
+void DiagSplit::split_quad(const Mesh::SubdFace &face, Patch *patch)
+{
+ Subpatch subpatch(patch);
+
+ int v = alloc_verts(4);
+
+ bool v0_reversed, u1_reversed, v1_reversed, u0_reversed;
+ subpatch.edge_v0.edge = create_edge_from_corner(
+ this, params.mesh, face, 3, v0_reversed, v + 3, v + 0);
+ subpatch.edge_u1.edge = create_edge_from_corner(
+ this, params.mesh, face, 2, u1_reversed, v + 2, v + 3);
+ subpatch.edge_v1.edge = create_edge_from_corner(
+ this, params.mesh, face, 1, v1_reversed, v + 1, v + 2);
+ subpatch.edge_u0.edge = create_edge_from_corner(
+ this, params.mesh, face, 0, u0_reversed, v + 0, v + 1);
+
+ subpatch.edge_v0.sub_edges_created_in_reverse_order = !v0_reversed;
+ subpatch.edge_u1.sub_edges_created_in_reverse_order = u1_reversed;
+ subpatch.edge_v1.sub_edges_created_in_reverse_order = v1_reversed;
+ subpatch.edge_u0.sub_edges_created_in_reverse_order = !u0_reversed;
+
+ subpatch.edge_v0.indices_decrease_along_edge = v0_reversed;
+ subpatch.edge_u1.indices_decrease_along_edge = u1_reversed;
+ subpatch.edge_v1.indices_decrease_along_edge = v1_reversed;
+ subpatch.edge_u0.indices_decrease_along_edge = u0_reversed;
+
+ /* Forces a split in both axis for quads, needed to match split of ngons into quads. */
+ subpatch.edge_u0.T = DSPLIT_NON_UNIFORM;
+ subpatch.edge_u1.T = DSPLIT_NON_UNIFORM;
+ subpatch.edge_v0.T = DSPLIT_NON_UNIFORM;
+ subpatch.edge_v1.T = DSPLIT_NON_UNIFORM;
+
+ split(subpatch, -2);
+}
+
+static Edge *create_split_edge_from_corner(DiagSplit *split,
+ const Mesh *mesh,
+ const Mesh::SubdFace &face,
+ int corner,
+ int side,
+ bool &reversed,
+ int v0,
+ int v1,
+ int vc)
+{
+ Edge *edge = split->alloc_edge();
+
+ int a = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 0, face.num_corners)];
+ int b = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 1, face.num_corners)];
+
+ if (b < a) {
+ edge->stitch_edge_key = {b, a};
+ }
+ else {
+ edge->stitch_edge_key = {a, b};
+ }
+
+ reversed = !(b < a);
+
+ if (side == 0) {
+ a = vc;
+ }
+ else {
+ b = vc;
+ }
+
+ if (!reversed) {
+ swap(a, b);
+ swap(v0, v1);
+ }
+
+ edge->is_stitch_edge = true;
+ edge->stitch_start_vert_index = a;
+ edge->stitch_end_vert_index = b;
+
+ edge->start_vert_index = v0;
+ edge->end_vert_index = v1;
+
+ return edge;
+}
+
+void DiagSplit::split_ngon(const Mesh::SubdFace &face, Patch *patches, size_t patches_byte_stride)
+{
+ Edge *prev_edge_u0 = nullptr;
+ Edge *first_edge_v0 = nullptr;
+
+ for (int corner = 0; corner < face.num_corners; corner++) {
+ Patch *patch = (Patch *)(((char *)patches) + corner * patches_byte_stride);
+
+ Subpatch subpatch(patch);
+
+ int v = alloc_verts(4);
+
+ /* Setup edges. */
+ Edge *edge_u1 = alloc_edge();
+ Edge *edge_v1 = alloc_edge();
+
+ edge_v1->is_stitch_edge = true;
+ edge_u1->is_stitch_edge = true;
+
+ edge_u1->stitch_start_vert_index = -(face.start_corner + mod(corner + 0, face.num_corners)) -
+ 1;
+ edge_u1->stitch_end_vert_index = STITCH_NGON_CENTER_VERT_INDEX_OFFSET + face.ptex_offset;
+
+ edge_u1->start_vert_index = v + 3;
+ edge_u1->end_vert_index = v + 2;
+
+ edge_u1->stitch_edge_key = {edge_u1->stitch_start_vert_index, edge_u1->stitch_end_vert_index};
+
+ edge_v1->stitch_start_vert_index = -(face.start_corner + mod(corner + 1, face.num_corners)) -
+ 1;
+ edge_v1->stitch_end_vert_index = STITCH_NGON_CENTER_VERT_INDEX_OFFSET + face.ptex_offset;
+
+ edge_v1->start_vert_index = v + 1;
+ edge_v1->end_vert_index = v + 2;
+
+ edge_v1->stitch_edge_key = {edge_v1->stitch_start_vert_index, edge_v1->stitch_end_vert_index};
+
+ bool v0_reversed, u0_reversed;
+
+ subpatch.edge_v0.edge = create_split_edge_from_corner(this,
+ params.mesh,
+ face,
+ corner - 1,
+ 0,
+ v0_reversed,
+ v + 3,
+ v + 0,
+ STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG);
+
+ subpatch.edge_u1.edge = edge_u1;
+ subpatch.edge_v1.edge = edge_v1;
+
+ subpatch.edge_u0.edge = create_split_edge_from_corner(this,
+ params.mesh,
+ face,
+ corner + 0,
+ 1,
+ u0_reversed,
+ v + 0,
+ v + 1,
+ STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG);
+
+ subpatch.edge_v0.sub_edges_created_in_reverse_order = !v0_reversed;
+ subpatch.edge_u1.sub_edges_created_in_reverse_order = false;
+ subpatch.edge_v1.sub_edges_created_in_reverse_order = true;
+ subpatch.edge_u0.sub_edges_created_in_reverse_order = !u0_reversed;
+
+ subpatch.edge_v0.indices_decrease_along_edge = v0_reversed;
+ subpatch.edge_u1.indices_decrease_along_edge = false;
+ subpatch.edge_v1.indices_decrease_along_edge = true;
+ subpatch.edge_u0.indices_decrease_along_edge = u0_reversed;
+
+ /* Perform split. */
+ {
+ subpatch.edge_u0.T = T(subpatch.patch, subpatch.c00, subpatch.c10);
+ subpatch.edge_u1.T = T(subpatch.patch, subpatch.c01, subpatch.c11);
+ subpatch.edge_v0.T = T(subpatch.patch, subpatch.c00, subpatch.c01);
+ subpatch.edge_v1.T = T(subpatch.patch, subpatch.c10, subpatch.c11);
+
+ resolve_edge_factors(subpatch);
+
+ split(subpatch, 0);
+ }
+
+ /* Update offsets after T is known from split. */
+ edge_u1->top = subpatch.edge_v0.edge;
+ edge_u1->stitch_top_offset = edge_u1->top->T * (v0_reversed ? -1 : 1);
+ edge_v1->top = subpatch.edge_u0.edge;
+ edge_v1->stitch_top_offset = edge_v1->top->T * (!u0_reversed ? -1 : 1);
+
+ if (corner == 0) {
+ first_edge_v0 = subpatch.edge_v0.edge;
+ }
+
+ if (prev_edge_u0) {
+ if (v0_reversed) {
+ subpatch.edge_v0.edge->stitch_offset = prev_edge_u0->T;
+ }
+ else {
+ prev_edge_u0->stitch_offset = subpatch.edge_v0.edge->T;
+ }
+
+ int T = subpatch.edge_v0.edge->T + prev_edge_u0->T;
+ subpatch.edge_v0.edge->stitch_edge_T = T;
+ prev_edge_u0->stitch_edge_T = T;
+ }
+
+ if (corner == face.num_corners - 1) {
+ if (v0_reversed) {
+ subpatch.edge_u0.edge->stitch_offset = first_edge_v0->T;
+ }
+ else {
+ first_edge_v0->stitch_offset = subpatch.edge_u0.edge->T;
+ }
+
+ int T = first_edge_v0->T + subpatch.edge_u0.edge->T;
+ first_edge_v0->stitch_edge_T = T;
+ subpatch.edge_u0.edge->stitch_edge_T = T;
+ }
+
+ prev_edge_u0 = subpatch.edge_u0.edge;
+ }
+}
+
+void DiagSplit::post_split()
+{
+ int num_stitch_verts = 0;
+
+ /* All patches are now split, and all T values known. */
+
+ foreach (Edge &edge, edges) {
+ if (edge.second_vert_index < 0) {
+ edge.second_vert_index = alloc_verts(edge.T - 1);
+ }
+
+ if (edge.is_stitch_edge) {
+ num_stitch_verts = max(num_stitch_verts,
+ max(edge.stitch_start_vert_index, edge.stitch_end_vert_index));
+ }
+ }
+
+ num_stitch_verts += 1;
+
+ /* Map of edge key to edge stitching vert offset. */
+ struct pair_hasher {
+ size_t operator()(const pair<int, int> &k) const
+ {
+ return hash_uint2(k.first, k.second);
+ }
+ };
+ typedef unordered_map<pair<int, int>, int, pair_hasher> edge_stitch_verts_map_t;
+ edge_stitch_verts_map_t edge_stitch_verts_map;
+
+ foreach (Edge &edge, edges) {
+ if (edge.is_stitch_edge) {
+ if (edge.stitch_edge_T == 0) {
+ edge.stitch_edge_T = edge.T;
+ }
+
+ if (edge_stitch_verts_map.find(edge.stitch_edge_key) == edge_stitch_verts_map.end()) {
+ edge_stitch_verts_map[edge.stitch_edge_key] = num_stitch_verts;
+ num_stitch_verts += edge.stitch_edge_T - 1;
+ }
+ }
+ }
+
+ /* Set start and end indices for edges generated from a split. */
+ foreach (Edge &edge, edges) {
+ if (edge.start_vert_index < 0) {
+ /* Fix up offsets. */
+ if (edge.top_indices_decrease) {
+ edge.top_offset = edge.top->T - edge.top_offset;
+ }
+
+ edge.start_vert_index = edge.top->get_vert_along_edge(edge.top_offset);
+ }
+
+ if (edge.end_vert_index < 0) {
+ if (edge.bottom_indices_decrease) {
+ edge.bottom_offset = edge.bottom->T - edge.bottom_offset;
+ }
+
+ edge.end_vert_index = edge.bottom->get_vert_along_edge(edge.bottom_offset);
+ }
+ }
+
+ int vert_offset = params.mesh->verts.size();
+
+ /* Add verts to stitching map. */
+ foreach (const Edge &edge, edges) {
+ if (edge.is_stitch_edge) {
+ int second_stitch_vert_index = edge_stitch_verts_map[edge.stitch_edge_key];
+
+ for (int i = 0; i <= edge.T; i++) {
+ /* Get proper stitching key. */
+ int key;
+
+ if (i == 0) {
+ key = edge.stitch_start_vert_index;
+ }
+ else if (i == edge.T) {
+ key = edge.stitch_end_vert_index;
+ }
+ else {
+ key = second_stitch_vert_index + i - 1 + edge.stitch_offset;
+ }
+
+ if (key == STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG) {
+ if (i == 0) {
+ key = second_stitch_vert_index - 1 + edge.stitch_offset;
+ }
+ else if (i == edge.T) {
+ key = second_stitch_vert_index - 1 + edge.T;
+ }
+ }
+ else if (key < 0 && edge.top) { /* ngon spoke edge */
+ int s = edge_stitch_verts_map[edge.top->stitch_edge_key];
+ if (edge.stitch_top_offset >= 0) {
+ key = s - 1 + edge.stitch_top_offset;
+ }
+ else {
+ key = s - 1 + edge.top->stitch_edge_T + edge.stitch_top_offset;
+ }
+ }
+
+ /* Get real vert index. */
+ int vert = edge.get_vert_along_edge(i) + vert_offset;
+
+ /* Add to map */
+ if (params.mesh->vert_to_stitching_key_map.find(vert) ==
+ params.mesh->vert_to_stitching_key_map.end()) {
+ params.mesh->vert_to_stitching_key_map[vert] = key;
+ params.mesh->vert_stitching_map.insert({key, vert});
+ }
+ }
+ }
+ }
+
+ /* Dice; TODO(mai): Move this out of split. */
+ QuadDice dice(params);
+
+ int num_verts = num_alloced_verts;
+ int num_triangles = 0;
+
+ for (size_t i = 0; i < subpatches.size(); i++) {
+ subpatches[i].inner_grid_vert_offset = num_verts;
+ num_verts += subpatches[i].calc_num_inner_verts();
+ num_triangles += subpatches[i].calc_num_triangles();
+ }
+
+ dice.reserve(num_verts, num_triangles);
+
+ for (size_t i = 0; i < subpatches.size(); i++) {
+ Subpatch &sub = subpatches[i];
+
+ sub.edge_u0.T = max(sub.edge_u0.T, 1);
+ sub.edge_u1.T = max(sub.edge_u1.T, 1);
+ sub.edge_v0.T = max(sub.edge_v0.T, 1);
+ sub.edge_v1.T = max(sub.edge_v1.T, 1);
+
+ dice.dice(sub);
+ }
+
+ /* Cleanup */
+ subpatches.clear();
+ edges.clear();
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/split.h b/intern/cycles/subd/split.h
new file mode 100644
index 00000000000..e876f34c419
--- /dev/null
+++ b/intern/cycles/subd/split.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SUBD_SPLIT_H__
+#define __SUBD_SPLIT_H__
+
+/* DiagSplit: Parallel, Crack-free, Adaptive Tessellation for Micropolygon Rendering
+ * Splits up patches and determines edge tessellation factors for dicing. Patch
+ * evaluation at arbitrary points is required for this to work. See the paper
+ * for more details. */
+
+#include "subd/dice.h"
+#include "subd/subpatch.h"
+
+#include "util/deque.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+#include <deque>
+
+CCL_NAMESPACE_BEGIN
+
+class Mesh;
+class Patch;
+
+class DiagSplit {
+ SubdParams params;
+
+ vector<Subpatch> subpatches;
+ /* `deque` is used so that element pointers remain valid when size is changed. */
+ deque<Edge> edges;
+
+ float3 to_world(Patch *patch, float2 uv);
+ int T(Patch *patch, float2 Pstart, float2 Pend, bool recursive_resolve = false);
+
+ void limit_edge_factor(int &T, Patch *patch, float2 Pstart, float2 Pend);
+ void resolve_edge_factors(Subpatch &sub);
+
+ void partition_edge(
+ Patch *patch, float2 *P, int *t0, int *t1, float2 Pstart, float2 Pend, int t);
+
+ void split(Subpatch &sub, int depth = 0);
+
+ int num_alloced_verts = 0;
+ int alloc_verts(int n); /* Returns start index of new verts. */
+
+ public:
+ Edge *alloc_edge();
+
+ explicit DiagSplit(const SubdParams &params);
+
+ void split_patches(Patch *patches, size_t patches_byte_stride);
+
+ void split_quad(const Mesh::SubdFace &face, Patch *patch);
+ void split_ngon(const Mesh::SubdFace &face, Patch *patches, size_t patches_byte_stride);
+
+ void post_split();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __SUBD_SPLIT_H__ */
diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp
deleted file mode 100644
index 4efdb98aa0f..00000000000
--- a/intern/cycles/subd/subd_dice.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/camera.h"
-#include "render/mesh.h"
-
-#include "subd/subd_dice.h"
-#include "subd/subd_patch.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* EdgeDice Base */
-
-EdgeDice::EdgeDice(const SubdParams &params_) : params(params_)
-{
- mesh_P = NULL;
- mesh_N = NULL;
- vert_offset = 0;
-
- params.mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
-
- if (params.ptex) {
- params.mesh->attributes.add(ATTR_STD_PTEX_UV);
- params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID);
- }
-}
-
-void EdgeDice::reserve(int num_verts, int num_triangles)
-{
- Mesh *mesh = params.mesh;
-
- vert_offset = mesh->get_verts().size();
- tri_offset = mesh->num_triangles();
-
- mesh->resize_mesh(mesh->get_verts().size() + num_verts, mesh->num_triangles());
- mesh->reserve_mesh(mesh->get_verts().size() + num_verts, mesh->num_triangles() + num_triangles);
-
- Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
-
- mesh_P = mesh->verts.data() + vert_offset;
- mesh_N = attr_vN->data_float3() + vert_offset;
-
- params.mesh->num_subd_verts += num_verts;
-}
-
-void EdgeDice::set_vert(Patch *patch, int index, float2 uv)
-{
- float3 P, N;
-
- patch->eval(&P, NULL, NULL, &N, uv.x, uv.y);
-
- assert(index < params.mesh->verts.size());
-
- mesh_P[index] = P;
- mesh_N[index] = N;
- params.mesh->vert_patch_uv[index + vert_offset] = make_float2(uv.x, uv.y);
-}
-
-void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2)
-{
- Mesh *mesh = params.mesh;
-
- mesh->add_triangle(v0 + vert_offset, v1 + vert_offset, v2 + vert_offset, patch->shader, true);
- params.mesh->triangle_patch[params.mesh->num_triangles() - 1] = patch->patch_index;
-
- tri_offset++;
-}
-
-void EdgeDice::stitch_triangles(Subpatch &sub, int edge)
-{
- int Mu = max(sub.edge_u0.T, sub.edge_u1.T);
- int Mv = max(sub.edge_v0.T, sub.edge_v1.T);
- Mu = max(Mu, 2);
- Mv = max(Mv, 2);
-
- int outer_T = sub.edges[edge].T;
- int inner_T = ((edge % 2) == 0) ? Mv - 2 : Mu - 2;
-
- if (inner_T < 0 || outer_T < 0)
- return; // XXX avoid crashes for Mu or Mv == 1, missing polygons
-
- /* stitch together two arrays of verts with triangles. at each step,
- * we compare using the next verts on both sides, to find the split
- * direction with the smallest diagonal, and use that in order to keep
- * the triangle shape reasonable. */
- for (size_t i = 0, j = 0; i < inner_T || j < outer_T;) {
- int v0, v1, v2;
-
- v0 = sub.get_vert_along_grid_edge(edge, i);
- v1 = sub.get_vert_along_edge(edge, j);
-
- if (j == outer_T) {
- v2 = sub.get_vert_along_grid_edge(edge, ++i);
- }
- else if (i == inner_T) {
- v2 = sub.get_vert_along_edge(edge, ++j);
- }
- else {
- /* length of diagonals */
- float len1 = len_squared(mesh_P[sub.get_vert_along_grid_edge(edge, i)] -
- mesh_P[sub.get_vert_along_edge(edge, j + 1)]);
- float len2 = len_squared(mesh_P[sub.get_vert_along_edge(edge, j)] -
- mesh_P[sub.get_vert_along_grid_edge(edge, i + 1)]);
-
- /* use smallest diagonal */
- if (len1 < len2)
- v2 = sub.get_vert_along_edge(edge, ++j);
- else
- v2 = sub.get_vert_along_grid_edge(edge, ++i);
- }
-
- add_triangle(sub.patch, v1, v0, v2);
- }
-}
-
-/* QuadDice */
-
-QuadDice::QuadDice(const SubdParams &params_) : EdgeDice(params_)
-{
-}
-
-float2 QuadDice::map_uv(Subpatch &sub, float u, float v)
-{
- /* map UV from subpatch to patch parametric coordinates */
- float2 d0 = interp(sub.c00, sub.c01, v);
- float2 d1 = interp(sub.c10, sub.c11, v);
- return interp(d0, d1, u);
-}
-
-float3 QuadDice::eval_projected(Subpatch &sub, float u, float v)
-{
- float2 uv = map_uv(sub, u, v);
- float3 P;
-
- sub.patch->eval(&P, NULL, NULL, NULL, uv.x, uv.y);
- if (params.camera)
- P = transform_perspective(&params.camera->worldtoraster, P);
-
- return P;
-}
-
-void QuadDice::set_vert(Subpatch &sub, int index, float u, float v)
-{
- EdgeDice::set_vert(sub.patch, index, map_uv(sub, u, v));
-}
-
-void QuadDice::set_side(Subpatch &sub, int edge)
-{
- int t = sub.edges[edge].T;
-
- /* set verts on the edge of the patch */
- for (int i = 0; i < t; i++) {
- float f = i / (float)t;
-
- float u, v;
- switch (edge) {
- case 0:
- u = 0;
- v = f;
- break;
- case 1:
- u = f;
- v = 1;
- break;
- case 2:
- u = 1;
- v = 1.0f - f;
- break;
- case 3:
- default:
- u = 1.0f - f;
- v = 0;
- break;
- }
-
- set_vert(sub, sub.get_vert_along_edge(edge, i), u, v);
- }
-}
-
-float QuadDice::quad_area(const float3 &a, const float3 &b, const float3 &c, const float3 &d)
-{
- return triangle_area(a, b, d) + triangle_area(a, d, c);
-}
-
-float QuadDice::scale_factor(Subpatch &sub, int Mu, int Mv)
-{
- /* estimate area as 4x largest of 4 quads */
- float3 P[3][3];
-
- for (int i = 0; i < 3; i++)
- for (int j = 0; j < 3; j++)
- P[i][j] = eval_projected(sub, i * 0.5f, j * 0.5f);
-
- float A1 = quad_area(P[0][0], P[1][0], P[0][1], P[1][1]);
- float A2 = quad_area(P[1][0], P[2][0], P[1][1], P[2][1]);
- float A3 = quad_area(P[0][1], P[1][1], P[0][2], P[1][2]);
- float A4 = quad_area(P[1][1], P[2][1], P[1][2], P[2][2]);
- float Apatch = max(A1, max(A2, max(A3, A4))) * 4.0f;
-
- /* solve for scaling factor */
- float Atri = params.dicing_rate * params.dicing_rate * 0.5f;
- float Ntris = Apatch / Atri;
-
- // XXX does the -sqrt solution matter
- // XXX max(D, 0.0) is highly suspicious, need to test cases
- // where D goes negative
- float N = 0.5f * (Ntris - (sub.edge_u0.T + sub.edge_u1.T + sub.edge_v0.T + sub.edge_v1.T));
- float D = 4.0f * N * Mu * Mv + (Mu + Mv) * (Mu + Mv);
- float S = (Mu + Mv + sqrtf(max(D, 0.0f))) / (2 * Mu * Mv);
-
- return S;
-}
-
-void QuadDice::add_grid(Subpatch &sub, int Mu, int Mv, int offset)
-{
- /* create inner grid */
- float du = 1.0f / (float)Mu;
- float dv = 1.0f / (float)Mv;
-
- for (int j = 1; j < Mv; j++) {
- for (int i = 1; i < Mu; i++) {
- float u = i * du;
- float v = j * dv;
-
- set_vert(sub, offset + (i - 1) + (j - 1) * (Mu - 1), u, v);
-
- if (i < Mu - 1 && j < Mv - 1) {
- int i1 = offset + (i - 1) + (j - 1) * (Mu - 1);
- int i2 = offset + i + (j - 1) * (Mu - 1);
- int i3 = offset + i + j * (Mu - 1);
- int i4 = offset + (i - 1) + j * (Mu - 1);
-
- add_triangle(sub.patch, i1, i2, i3);
- add_triangle(sub.patch, i1, i3, i4);
- }
- }
- }
-}
-
-void QuadDice::dice(Subpatch &sub)
-{
- /* compute inner grid size with scale factor */
- int Mu = max(sub.edge_u0.T, sub.edge_u1.T);
- int Mv = max(sub.edge_v0.T, sub.edge_v1.T);
-
-#if 0 /* Doesn't work very well, especially at grazing angles. */
- float S = scale_factor(sub, ef, Mu, Mv);
-#else
- float S = 1.0f;
-#endif
-
- Mu = max((int)ceilf(S * Mu), 2); // XXX handle 0 & 1?
- Mv = max((int)ceilf(S * Mv), 2); // XXX handle 0 & 1?
-
- /* inner grid */
- add_grid(sub, Mu, Mv, sub.inner_grid_vert_offset);
-
- /* sides */
- set_side(sub, 0);
- set_side(sub, 1);
- set_side(sub, 2);
- set_side(sub, 3);
-
- stitch_triangles(sub, 0);
- stitch_triangles(sub, 1);
- stitch_triangles(sub, 2);
- stitch_triangles(sub, 3);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h
deleted file mode 100644
index ee63403d40c..00000000000
--- a/intern/cycles/subd/subd_dice.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SUBD_DICE_H__
-#define __SUBD_DICE_H__
-
-/* DX11 like EdgeDice implementation, with different tessellation factors for
- * each edge for watertight tessellation, with subpatch remapping to work with
- * DiagSplit. For more algorithm details, see the DiagSplit paper or the
- * ARB_tessellation_shader OpenGL extension, Section 2.X.2. */
-
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-#include "subd/subd_subpatch.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Camera;
-class Mesh;
-class Patch;
-
-struct SubdParams {
- Mesh *mesh;
- bool ptex;
-
- int test_steps;
- int split_threshold;
- float dicing_rate;
- int max_level;
- Camera *camera;
- Transform objecttoworld;
-
- SubdParams(Mesh *mesh_, bool ptex_ = false)
- {
- mesh = mesh_;
- ptex = ptex_;
-
- test_steps = 3;
- split_threshold = 1;
- dicing_rate = 1.0f;
- max_level = 12;
- camera = NULL;
- }
-};
-
-/* EdgeDice Base */
-
-class EdgeDice {
- public:
- SubdParams params;
- float3 *mesh_P;
- float3 *mesh_N;
- size_t vert_offset;
- size_t tri_offset;
-
- explicit EdgeDice(const SubdParams &params);
-
- void reserve(int num_verts, int num_triangles);
-
- void set_vert(Patch *patch, int index, float2 uv);
- void add_triangle(Patch *patch, int v0, int v1, int v2);
-
- void stitch_triangles(Subpatch &sub, int edge);
-};
-
-/* Quad EdgeDice */
-
-class QuadDice : public EdgeDice {
- public:
- explicit QuadDice(const SubdParams &params);
-
- float3 eval_projected(Subpatch &sub, float u, float v);
-
- float2 map_uv(Subpatch &sub, float u, float v);
- void set_vert(Subpatch &sub, int index, float u, float v);
-
- void add_grid(Subpatch &sub, int Mu, int Mv, int offset);
-
- void set_side(Subpatch &sub, int edge);
-
- float quad_area(const float3 &a, const float3 &b, const float3 &c, const float3 &d);
- float scale_factor(Subpatch &sub, int Mu, int Mv);
-
- void dice(Subpatch &sub);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __SUBD_DICE_H__ */
diff --git a/intern/cycles/subd/subd_patch.cpp b/intern/cycles/subd/subd_patch.cpp
deleted file mode 100644
index a975b7b6342..00000000000
--- a/intern/cycles/subd/subd_patch.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Parts adapted from code in the public domain in NVidia Mesh Tools. */
-
-#include "render/mesh.h"
-
-#include "subd/subd_patch.h"
-
-#include "util/util_math.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* De Casteljau Evaluation */
-
-static void decasteljau_cubic(float3 *P, float3 *dt, float t, const float3 cp[4])
-{
- float3 d0 = cp[0] + t * (cp[1] - cp[0]);
- float3 d1 = cp[1] + t * (cp[2] - cp[1]);
- float3 d2 = cp[2] + t * (cp[3] - cp[2]);
-
- d0 += t * (d1 - d0);
- d1 += t * (d2 - d1);
-
- *P = d0 + t * (d1 - d0);
- if (dt)
- *dt = d1 - d0;
-}
-
-static void decasteljau_bicubic(
- float3 *P, float3 *du, float3 *dv, const float3 cp[16], float u, float v)
-{
- float3 ucp[4], utn[4];
-
- /* interpolate over u */
- decasteljau_cubic(ucp + 0, utn + 0, u, cp);
- decasteljau_cubic(ucp + 1, utn + 1, u, cp + 4);
- decasteljau_cubic(ucp + 2, utn + 2, u, cp + 8);
- decasteljau_cubic(ucp + 3, utn + 3, u, cp + 12);
-
- /* interpolate over v */
- decasteljau_cubic(P, dv, v, ucp);
- if (du)
- decasteljau_cubic(du, NULL, v, utn);
-}
-
-/* Linear Quad Patch */
-
-void LinearQuadPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
-{
- float3 d0 = interp(hull[0], hull[1], u);
- float3 d1 = interp(hull[2], hull[3], u);
-
- *P = interp(d0, d1, v);
-
- if (dPdu && dPdv) {
- *dPdu = interp(hull[1] - hull[0], hull[3] - hull[2], v);
- *dPdv = interp(hull[2] - hull[0], hull[3] - hull[1], u);
- }
-
- if (N) {
- *N = normalize(
- interp(interp(normals[0], normals[1], u), interp(normals[2], normals[3], u), v));
- }
-}
-
-BoundBox LinearQuadPatch::bound()
-{
- BoundBox bbox = BoundBox::empty;
-
- for (int i = 0; i < 4; i++)
- bbox.grow(hull[i]);
-
- return bbox;
-}
-
-/* Bicubic Patch */
-
-void BicubicPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
-{
- if (N) {
- float3 dPdu_, dPdv_;
- decasteljau_bicubic(P, &dPdu_, &dPdv_, hull, u, v);
-
- if (dPdu && dPdv) {
- *dPdu = dPdu_;
- *dPdv = dPdv_;
- }
-
- *N = normalize(cross(dPdu_, dPdv_));
- }
- else {
- decasteljau_bicubic(P, dPdu, dPdv, hull, u, v);
- }
-}
-
-BoundBox BicubicPatch::bound()
-{
- BoundBox bbox = BoundBox::empty;
-
- for (int i = 0; i < 16; i++)
- bbox.grow(hull[i]);
-
- return bbox;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/subd_patch.h b/intern/cycles/subd/subd_patch.h
deleted file mode 100644
index 8fe423bc94d..00000000000
--- a/intern/cycles/subd/subd_patch.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SUBD_PATCH_H__
-#define __SUBD_PATCH_H__
-
-#include "util/util_boundbox.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Patch {
- public:
- Patch() : patch_index(0), shader(0), from_ngon(false)
- {
- }
-
- virtual ~Patch() = default;
-
- virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) = 0;
-
- int patch_index;
- int shader;
- bool from_ngon;
-};
-
-/* Linear Quad Patch */
-
-class LinearQuadPatch : public Patch {
- public:
- float3 hull[4];
- float3 normals[4];
-
- void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
- BoundBox bound();
-};
-
-/* Bicubic Patch */
-
-class BicubicPatch : public Patch {
- public:
- float3 hull[16];
-
- void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
- BoundBox bound();
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __SUBD_PATCH_H__ */
diff --git a/intern/cycles/subd/subd_patch_table.cpp b/intern/cycles/subd/subd_patch_table.cpp
deleted file mode 100644
index 4e873375725..00000000000
--- a/intern/cycles/subd/subd_patch_table.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Based on code from OpenSubdiv released under this license:
- *
- * Copyright 2014 DreamWorks Animation LLC.
- *
- * Licensed under the Apache License, Version 2.0 (the "Apache License")
- * with the following modification; you may not use this file except in
- * compliance with the Apache License and the following modification to it:
- * Section 6. Trademarks. is deleted and replaced with:
- *
- * 6. Trademarks. This License does not grant permission to use the trade
- * names, trademarks, service marks, or product names of the Licensor
- * and its affiliates, except as required to comply with Section 4(c) of
- * the License and to reproduce the content of the NOTICE file.
- *
- * You may obtain a copy of the Apache License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the Apache License with the above modification is
- * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the Apache License for the specific
- * language governing permissions and limitations under the Apache License.
- */
-
-#include "subd/subd_patch_table.h"
-#include "kernel/kernel_types.h"
-
-#include "util/util_math.h"
-
-#ifdef WITH_OPENSUBDIV
-# include <opensubdiv/far/patchTable.h>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef WITH_OPENSUBDIV
-
-using namespace OpenSubdiv;
-
-/* functions for building patch maps */
-
-struct PatchMapQuadNode {
- /* sets all the children to point to the patch of index */
- void set_child(int index)
- {
- for (int i = 0; i < 4; i++) {
- children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF;
- }
- }
-
- /* sets the child in quadrant to point to the node or patch of the given index */
- void set_child(unsigned char quadrant, int index, bool is_leaf = true)
- {
- assert(quadrant < 4);
- children[quadrant] = index | PATCH_MAP_NODE_IS_SET | (is_leaf ? PATCH_MAP_NODE_IS_LEAF : 0);
- }
-
- uint children[4];
-};
-
-template<class T> static int resolve_quadrant(T &median, T &u, T &v)
-{
- int quadrant = -1;
-
- if (u < median) {
- if (v < median) {
- quadrant = 0;
- }
- else {
- quadrant = 1;
- v -= median;
- }
- }
- else {
- if (v < median) {
- quadrant = 3;
- }
- else {
- quadrant = 2;
- v -= median;
- }
- u -= median;
- }
-
- return quadrant;
-}
-
-static void build_patch_map(PackedPatchTable &table,
- OpenSubdiv::Far::PatchTable *patch_table,
- int offset)
-{
- int num_faces = 0;
-
- for (int array = 0; array < table.num_arrays; array++) {
- Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
-
- for (int j = 0; j < patch_table->GetNumPatches(array); j++) {
- num_faces = max(num_faces, (int)params[j].GetFaceId());
- }
- }
- num_faces++;
-
- vector<PatchMapQuadNode> quadtree;
- quadtree.reserve(num_faces + table.num_patches);
- quadtree.resize(num_faces);
-
- /* adjust offsets to make indices relative to the table */
- int handle_index = -(table.num_patches * PATCH_HANDLE_SIZE);
- offset += table.total_size();
-
- /* populate the quadtree from the FarPatchArrays sub-patches */
- for (int array = 0; array < table.num_arrays; array++) {
- Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
-
- for (int i = 0; i < patch_table->GetNumPatches(array);
- i++, handle_index += PATCH_HANDLE_SIZE) {
- const Far::PatchParam &param = params[i];
- unsigned short depth = param.GetDepth();
-
- PatchMapQuadNode *node = &quadtree[params[i].GetFaceId()];
-
- if (depth == (param.NonQuadRoot() ? 1 : 0)) {
- /* special case : regular BSpline face w/ no sub-patches */
- node->set_child(handle_index + offset);
- continue;
- }
-
- int u = param.GetU();
- int v = param.GetV();
- int pdepth = param.NonQuadRoot() ? depth - 2 : depth - 1;
- int half = 1 << pdepth;
-
- for (int j = 0; j < depth; j++) {
- int delta = half >> 1;
-
- int quadrant = resolve_quadrant(half, u, v);
- assert(quadrant >= 0);
-
- half = delta;
-
- if (j == pdepth) {
- /* we have reached the depth of the sub-patch : add a leaf */
- assert(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET));
- node->set_child(quadrant, handle_index + offset, true);
- break;
- }
- else {
- /* travel down the child node of the corresponding quadrant */
- if (!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET)) {
- /* create a new branch in the quadrant */
- quadtree.push_back(PatchMapQuadNode());
-
- int idx = (int)quadtree.size() - 1;
- node->set_child(quadrant, idx * 4 + offset, false);
-
- node = &quadtree[idx];
- }
- else {
- /* travel down an existing branch */
- uint idx = node->children[quadrant] & PATCH_MAP_NODE_INDEX_MASK;
- node = &(quadtree[(idx - offset) / 4]);
- }
- }
- }
- }
- }
-
- /* copy into table */
- assert(table.table.size() == table.total_size());
- uint map_offset = table.total_size();
-
- table.num_nodes = quadtree.size() * 4;
- table.table.resize(table.total_size());
-
- uint *data = &table.table[map_offset];
-
- for (int i = 0; i < quadtree.size(); i++) {
- for (int j = 0; j < 4; j++) {
- assert(quadtree[i].children[j] & PATCH_MAP_NODE_IS_SET);
- *(data++) = quadtree[i].children[j];
- }
- }
-}
-
-#endif
-
-/* packed patch table functions */
-
-size_t PackedPatchTable::total_size()
-{
- return num_arrays * PATCH_ARRAY_SIZE + num_indices +
- num_patches * (PATCH_PARAM_SIZE + PATCH_HANDLE_SIZE) + num_nodes * PATCH_NODE_SIZE;
-}
-
-void PackedPatchTable::pack(Far::PatchTable *patch_table, int offset)
-{
- num_arrays = 0;
- num_patches = 0;
- num_indices = 0;
- num_nodes = 0;
-
-#ifdef WITH_OPENSUBDIV
- num_arrays = patch_table->GetNumPatchArrays();
-
- for (int i = 0; i < num_arrays; i++) {
- int patches = patch_table->GetNumPatches(i);
- int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
-
- num_patches += patches;
- num_indices += patches * num_control;
- }
-
- table.resize(total_size());
- uint *data = table.data();
-
- uint *array = data;
- uint *index = array + num_arrays * PATCH_ARRAY_SIZE;
- uint *param = index + num_indices;
- uint *handle = param + num_patches * PATCH_PARAM_SIZE;
-
- uint current_param = 0;
-
- for (int i = 0; i < num_arrays; i++) {
- *(array++) = patch_table->GetPatchArrayDescriptor(i).GetType();
- *(array++) = patch_table->GetNumPatches(i);
- *(array++) = (index - data) + offset;
- *(array++) = (param - data) + offset;
-
- Far::ConstIndexArray indices = patch_table->GetPatchArrayVertices(i);
-
- for (int j = 0; j < indices.size(); j++) {
- *(index++) = indices[j];
- }
-
- const Far::PatchParamTable &param_table = patch_table->GetPatchParamTable();
-
- int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
- int patches = patch_table->GetNumPatches(i);
-
- for (int j = 0; j < patches; j++, current_param++) {
- *(param++) = param_table[current_param].field0;
- *(param++) = param_table[current_param].field1;
-
- *(handle++) = (array - data) - PATCH_ARRAY_SIZE + offset;
- *(handle++) = (param - data) - PATCH_PARAM_SIZE + offset;
- *(handle++) = j * num_control;
- }
- }
-
- build_patch_map(*this, patch_table, offset);
-#else
- (void)patch_table;
- (void)offset;
-#endif
-}
-
-void PackedPatchTable::copy_adjusting_offsets(uint *dest, int doffset)
-{
- uint *src = table.data();
-
- /* arrays */
- for (int i = 0; i < num_arrays; i++) {
- *(dest++) = *(src++);
- *(dest++) = *(src++);
- *(dest++) = *(src++) + doffset;
- *(dest++) = *(src++) + doffset;
- }
-
- /* indices */
- for (int i = 0; i < num_indices; i++) {
- *(dest++) = *(src++);
- }
-
- /* params */
- for (int i = 0; i < num_patches; i++) {
- *(dest++) = *(src++);
- *(dest++) = *(src++);
- }
-
- /* handles */
- for (int i = 0; i < num_patches; i++) {
- *(dest++) = *(src++) + doffset;
- *(dest++) = *(src++) + doffset;
- *(dest++) = *(src++);
- }
-
- /* nodes */
- for (int i = 0; i < num_nodes; i++) {
- *(dest++) = *(src++) + doffset;
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/subd_patch_table.h b/intern/cycles/subd/subd_patch_table.h
deleted file mode 100644
index 118d410f8f0..00000000000
--- a/intern/cycles/subd/subd_patch_table.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SUBD_PATCH_TABLE_H__
-#define __SUBD_PATCH_TABLE_H__
-
-#include "util/util_array.h"
-#include "util/util_types.h"
-
-#ifdef WITH_OPENSUBDIV
-# ifdef _MSC_VER
-# include "iso646.h"
-# endif
-
-# include <opensubdiv/far/patchTable.h>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef WITH_OPENSUBDIV
-using namespace OpenSubdiv;
-#else
-/* forward declare for when OpenSubdiv is unavailable */
-namespace Far {
-struct PatchTable;
-}
-#endif
-
-#define PATCH_ARRAY_SIZE 4
-#define PATCH_PARAM_SIZE 2
-#define PATCH_HANDLE_SIZE 3
-#define PATCH_NODE_SIZE 1
-
-struct PackedPatchTable {
- array<uint> table;
-
- size_t num_arrays;
- size_t num_indices;
- size_t num_patches;
- size_t num_nodes;
-
- /* calculated size from num_* members */
- size_t total_size();
-
- void pack(Far::PatchTable *patch_table, int offset = 0);
- void copy_adjusting_offsets(uint *dest, int doffset);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __SUBD_PATCH_TABLE_H__ */
diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp
deleted file mode 100644
index 4d648eb1f77..00000000000
--- a/intern/cycles/subd/subd_split.cpp
+++ /dev/null
@@ -1,748 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "render/camera.h"
-#include "render/mesh.h"
-
-#include "subd/subd_dice.h"
-#include "subd/subd_patch.h"
-#include "subd/subd_split.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_foreach.h"
-#include "util/util_hash.h"
-#include "util/util_math.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* DiagSplit */
-
-#define DSPLIT_NON_UNIFORM -1
-#define STITCH_NGON_CENTER_VERT_INDEX_OFFSET 0x60000000
-#define STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG (0x60000000 - 1)
-
-DiagSplit::DiagSplit(const SubdParams &params_) : params(params_)
-{
-}
-
-float3 DiagSplit::to_world(Patch *patch, float2 uv)
-{
- float3 P;
-
- patch->eval(&P, NULL, NULL, NULL, uv.x, uv.y);
- if (params.camera)
- P = transform_point(&params.objecttoworld, P);
-
- return P;
-}
-
-static void order_float2(float2 &a, float2 &b)
-{
- if (b.x < a.x || b.y < a.y) {
- swap(a, b);
- }
-}
-
-int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend, bool recursive_resolve)
-{
- order_float2(Pstart, Pend); /* May not be necessary, but better to be safe. */
-
- float Lsum = 0.0f;
- float Lmax = 0.0f;
-
- float3 Plast = to_world(patch, Pstart);
-
- for (int i = 1; i < params.test_steps; i++) {
- float t = i / (float)(params.test_steps - 1);
-
- float3 P = to_world(patch, Pstart + t * (Pend - Pstart));
-
- float L;
-
- if (!params.camera) {
- L = len(P - Plast);
- }
- else {
- Camera *cam = params.camera;
-
- float pixel_width = cam->world_to_raster_size((P + Plast) * 0.5f);
- L = len(P - Plast) / pixel_width;
- }
-
- Lsum += L;
- Lmax = max(L, Lmax);
-
- Plast = P;
- }
-
- int tmin = (int)ceilf(Lsum / params.dicing_rate);
- int tmax = (int)ceilf((params.test_steps - 1) * Lmax /
- params.dicing_rate); // XXX paper says N instead of N-1, seems wrong?
- int res = max(tmax, 1);
-
- if (tmax - tmin > params.split_threshold) {
- if (!recursive_resolve) {
- res = DSPLIT_NON_UNIFORM;
- }
- else {
- float2 P = (Pstart + Pend) * 0.5f;
- res = T(patch, Pstart, P, true) + T(patch, P, Pend, true);
- }
- }
-
- limit_edge_factor(res, patch, Pstart, Pend);
- return res;
-}
-
-void DiagSplit::partition_edge(
- Patch *patch, float2 *P, int *t0, int *t1, float2 Pstart, float2 Pend, int t)
-{
- if (t == DSPLIT_NON_UNIFORM) {
- *P = (Pstart + Pend) * 0.5f;
- *t0 = T(patch, Pstart, *P);
- *t1 = T(patch, *P, Pend);
- }
- else {
- assert(t >= 2); /* Need at least two segments to partition into. */
-
- int I = (int)floorf((float)t * 0.5f);
- *P = interp(Pstart, Pend, I / (float)t);
- *t0 = I;
- *t1 = t - I;
- }
-}
-
-void DiagSplit::limit_edge_factor(int &T, Patch *patch, float2 Pstart, float2 Pend)
-{
- int max_t = 1 << params.max_level;
- int max_t_for_edge = int(max_t * len(Pstart - Pend));
-
- if (patch->from_ngon) {
- max_t_for_edge >>= 1; /* Initial split of ngon causes edges to extend half the distance. */
- }
-
- T = (max_t_for_edge <= 1) ? 1 : min(T, max_t_for_edge);
-
- assert(T >= 1 || T == DSPLIT_NON_UNIFORM);
-}
-
-void DiagSplit::resolve_edge_factors(Subpatch &sub)
-{
- /* Resolve DSPLIT_NON_UNIFORM to actual T value if splitting is no longer possible. */
- if (sub.edge_u0.T == 1 && sub.edge_u1.T == DSPLIT_NON_UNIFORM) {
- sub.edge_u1.T = T(sub.patch, sub.c01, sub.c11, true);
- }
- if (sub.edge_u1.T == 1 && sub.edge_u0.T == DSPLIT_NON_UNIFORM) {
- sub.edge_u0.T = T(sub.patch, sub.c00, sub.c10, true);
- }
- if (sub.edge_v0.T == 1 && sub.edge_v1.T == DSPLIT_NON_UNIFORM) {
- sub.edge_v1.T = T(sub.patch, sub.c11, sub.c10, true);
- }
- if (sub.edge_v1.T == 1 && sub.edge_v0.T == DSPLIT_NON_UNIFORM) {
- sub.edge_v0.T = T(sub.patch, sub.c01, sub.c00, true);
- }
-}
-
-void DiagSplit::split(Subpatch &sub, int depth)
-{
- if (depth > 32) {
- /* We should never get here, but just in case end recursion safely. */
- assert(!"diagsplit recursion limit reached");
-
- sub.edge_u0.T = 1;
- sub.edge_u1.T = 1;
- sub.edge_v0.T = 1;
- sub.edge_v1.T = 1;
-
- subpatches.push_back(sub);
- return;
- }
-
- bool split_u = (sub.edge_u0.T == DSPLIT_NON_UNIFORM || sub.edge_u1.T == DSPLIT_NON_UNIFORM);
- bool split_v = (sub.edge_v0.T == DSPLIT_NON_UNIFORM || sub.edge_v1.T == DSPLIT_NON_UNIFORM);
-
- /* Split subpatches such that the ratio of T for opposite edges doesn't
- * exceed 1.5, this reduces over tessellation for some patches
- */
- /* clang-format off */
- if (min(sub.edge_u0.T, sub.edge_u1.T) > 8 && /* Must be uniform and preferably greater than 8 to split. */
- min(sub.edge_v0.T, sub.edge_v1.T) >= 2 && /* Must be uniform and at least 2 to split. */
- max(sub.edge_u0.T, sub.edge_u1.T) / min(sub.edge_u0.T, sub.edge_u1.T) > 1.5f)
- {
- split_v = true;
- }
- if (min(sub.edge_v0.T, sub.edge_v1.T) > 8 &&
- min(sub.edge_u0.T, sub.edge_u1.T) >= 2 &&
- max(sub.edge_v0.T, sub.edge_v1.T) / min(sub.edge_v0.T, sub.edge_v1.T) > 1.5f)
- {
- split_u = true;
- }
- /* clang-format on */
-
- /* Alternate axis. */
- if (split_u && split_v) {
- split_u = depth % 2;
- }
-
- if (!split_u && !split_v) {
- /* Add the unsplit subpatch. */
- subpatches.push_back(sub);
- Subpatch &subpatch = subpatches[subpatches.size() - 1];
-
- /* Update T values and offsets. */
- for (int i = 0; i < 4; i++) {
- Subpatch::edge_t &edge = subpatch.edges[i];
-
- edge.offset = edge.edge->T;
- edge.edge->T += edge.T;
- }
- }
- else {
- /* Copy into new subpatches. */
- Subpatch sub_a = sub;
- Subpatch sub_b = sub;
-
- /* Pointers to various subpatch elements. */
- Subpatch::edge_t *sub_across_0, *sub_across_1;
- Subpatch::edge_t *sub_a_across_0, *sub_a_across_1;
- Subpatch::edge_t *sub_b_across_0, *sub_b_across_1;
-
- Subpatch::edge_t *sub_a_split, *sub_b_split;
-
- float2 *Pa, *Pb, *Pc, *Pd;
-
- /* Set pointers based on split axis. */
- if (split_u) {
- sub_across_0 = &sub.edge_u0;
- sub_across_1 = &sub.edge_u1;
- sub_a_across_0 = &sub_a.edge_u0;
- sub_a_across_1 = &sub_a.edge_u1;
- sub_b_across_0 = &sub_b.edge_u0;
- sub_b_across_1 = &sub_b.edge_u1;
-
- sub_a_split = &sub_a.edge_v1;
- sub_b_split = &sub_b.edge_v0;
-
- Pa = &sub_a.c11;
- Pb = &sub_a.c10;
- Pc = &sub_b.c01;
- Pd = &sub_b.c00;
- }
- else {
- sub_across_0 = &sub.edge_v0;
- sub_across_1 = &sub.edge_v1;
- sub_a_across_0 = &sub_a.edge_v0;
- sub_a_across_1 = &sub_a.edge_v1;
- sub_b_across_0 = &sub_b.edge_v0;
- sub_b_across_1 = &sub_b.edge_v1;
-
- sub_a_split = &sub_a.edge_u0;
- sub_b_split = &sub_b.edge_u1;
-
- Pa = &sub_a.c10;
- Pb = &sub_a.c00;
- Pc = &sub_b.c11;
- Pd = &sub_b.c01;
- }
-
- /* Partition edges */
- float2 P0, P1;
-
- partition_edge(
- sub.patch, &P0, &sub_a_across_0->T, &sub_b_across_0->T, *Pd, *Pb, sub_across_0->T);
- partition_edge(
- sub.patch, &P1, &sub_a_across_1->T, &sub_b_across_1->T, *Pc, *Pa, sub_across_1->T);
-
- /* Split */
- *Pa = P1;
- *Pb = P0;
-
- *Pc = P1;
- *Pd = P0;
-
- int tsplit = T(sub.patch, P0, P1);
-
- if (depth == -2 && tsplit == 1) {
- tsplit = 2; /* Ensure we can always split at depth -1. */
- }
-
- sub_a_split->T = tsplit;
- sub_b_split->T = tsplit;
-
- resolve_edge_factors(sub_a);
- resolve_edge_factors(sub_b);
-
- /* Create new edge */
- Edge &edge = *alloc_edge();
-
- sub_a_split->edge = &edge;
- sub_b_split->edge = &edge;
-
- sub_a_split->offset = 0;
- sub_b_split->offset = 0;
-
- sub_a_split->indices_decrease_along_edge = false;
- sub_b_split->indices_decrease_along_edge = true;
-
- sub_a_split->sub_edges_created_in_reverse_order = !split_u;
- sub_b_split->sub_edges_created_in_reverse_order = !split_u;
-
- edge.top_indices_decrease = sub_across_1->sub_edges_created_in_reverse_order;
- edge.bottom_indices_decrease = sub_across_0->sub_edges_created_in_reverse_order;
-
- /* Recurse */
- edge.T = 0;
- split(sub_a, depth + 1);
-
- int edge_t = edge.T;
- (void)edge_t;
-
- edge.top_offset = sub_across_1->edge->T;
- edge.bottom_offset = sub_across_0->edge->T;
-
- edge.T = 0; /* We calculate T twice along each edge. :/ */
- split(sub_b, depth + 1);
-
- assert(edge.T == edge_t); /* If this fails we will crash at some later point! */
-
- edge.top = sub_across_1->edge;
- edge.bottom = sub_across_0->edge;
- }
-}
-
-int DiagSplit::alloc_verts(int n)
-{
- int a = num_alloced_verts;
- num_alloced_verts += n;
- return a;
-}
-
-Edge *DiagSplit::alloc_edge()
-{
- edges.emplace_back();
- return &edges.back();
-}
-
-void DiagSplit::split_patches(Patch *patches, size_t patches_byte_stride)
-{
- int patch_index = 0;
-
- for (int f = 0; f < params.mesh->get_num_subd_faces(); f++) {
- Mesh::SubdFace face = params.mesh->get_subd_face(f);
-
- Patch *patch = (Patch *)(((char *)patches) + patch_index * patches_byte_stride);
-
- if (face.is_quad()) {
- patch_index++;
-
- split_quad(face, patch);
- }
- else {
- patch_index += face.num_corners;
-
- split_ngon(face, patch, patches_byte_stride);
- }
- }
-
- params.mesh->vert_to_stitching_key_map.clear();
- params.mesh->vert_stitching_map.clear();
-
- post_split();
-}
-
-static Edge *create_edge_from_corner(DiagSplit *split,
- const Mesh *mesh,
- const Mesh::SubdFace &face,
- int corner,
- bool &reversed,
- int v0,
- int v1)
-{
- int a = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 0, face.num_corners)];
- int b = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 1, face.num_corners)];
-
- reversed = !(b < a);
-
- if (b < a) {
- swap(a, b);
- swap(v0, v1);
- }
-
- Edge *edge = split->alloc_edge();
-
- edge->is_stitch_edge = true;
- edge->stitch_start_vert_index = a;
- edge->stitch_end_vert_index = b;
-
- edge->start_vert_index = v0;
- edge->end_vert_index = v1;
-
- edge->stitch_edge_key = {a, b};
-
- return edge;
-}
-
-void DiagSplit::split_quad(const Mesh::SubdFace &face, Patch *patch)
-{
- Subpatch subpatch(patch);
-
- int v = alloc_verts(4);
-
- bool v0_reversed, u1_reversed, v1_reversed, u0_reversed;
- subpatch.edge_v0.edge = create_edge_from_corner(
- this, params.mesh, face, 3, v0_reversed, v + 3, v + 0);
- subpatch.edge_u1.edge = create_edge_from_corner(
- this, params.mesh, face, 2, u1_reversed, v + 2, v + 3);
- subpatch.edge_v1.edge = create_edge_from_corner(
- this, params.mesh, face, 1, v1_reversed, v + 1, v + 2);
- subpatch.edge_u0.edge = create_edge_from_corner(
- this, params.mesh, face, 0, u0_reversed, v + 0, v + 1);
-
- subpatch.edge_v0.sub_edges_created_in_reverse_order = !v0_reversed;
- subpatch.edge_u1.sub_edges_created_in_reverse_order = u1_reversed;
- subpatch.edge_v1.sub_edges_created_in_reverse_order = v1_reversed;
- subpatch.edge_u0.sub_edges_created_in_reverse_order = !u0_reversed;
-
- subpatch.edge_v0.indices_decrease_along_edge = v0_reversed;
- subpatch.edge_u1.indices_decrease_along_edge = u1_reversed;
- subpatch.edge_v1.indices_decrease_along_edge = v1_reversed;
- subpatch.edge_u0.indices_decrease_along_edge = u0_reversed;
-
- /* Forces a split in both axis for quads, needed to match split of ngons into quads. */
- subpatch.edge_u0.T = DSPLIT_NON_UNIFORM;
- subpatch.edge_u1.T = DSPLIT_NON_UNIFORM;
- subpatch.edge_v0.T = DSPLIT_NON_UNIFORM;
- subpatch.edge_v1.T = DSPLIT_NON_UNIFORM;
-
- split(subpatch, -2);
-}
-
-static Edge *create_split_edge_from_corner(DiagSplit *split,
- const Mesh *mesh,
- const Mesh::SubdFace &face,
- int corner,
- int side,
- bool &reversed,
- int v0,
- int v1,
- int vc)
-{
- Edge *edge = split->alloc_edge();
-
- int a = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 0, face.num_corners)];
- int b = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 1, face.num_corners)];
-
- if (b < a) {
- edge->stitch_edge_key = {b, a};
- }
- else {
- edge->stitch_edge_key = {a, b};
- }
-
- reversed = !(b < a);
-
- if (side == 0) {
- a = vc;
- }
- else {
- b = vc;
- }
-
- if (!reversed) {
- swap(a, b);
- swap(v0, v1);
- }
-
- edge->is_stitch_edge = true;
- edge->stitch_start_vert_index = a;
- edge->stitch_end_vert_index = b;
-
- edge->start_vert_index = v0;
- edge->end_vert_index = v1;
-
- return edge;
-}
-
-void DiagSplit::split_ngon(const Mesh::SubdFace &face, Patch *patches, size_t patches_byte_stride)
-{
- Edge *prev_edge_u0 = nullptr;
- Edge *first_edge_v0 = nullptr;
-
- for (int corner = 0; corner < face.num_corners; corner++) {
- Patch *patch = (Patch *)(((char *)patches) + corner * patches_byte_stride);
-
- Subpatch subpatch(patch);
-
- int v = alloc_verts(4);
-
- /* Setup edges. */
- Edge *edge_u1 = alloc_edge();
- Edge *edge_v1 = alloc_edge();
-
- edge_v1->is_stitch_edge = true;
- edge_u1->is_stitch_edge = true;
-
- edge_u1->stitch_start_vert_index = -(face.start_corner + mod(corner + 0, face.num_corners)) -
- 1;
- edge_u1->stitch_end_vert_index = STITCH_NGON_CENTER_VERT_INDEX_OFFSET + face.ptex_offset;
-
- edge_u1->start_vert_index = v + 3;
- edge_u1->end_vert_index = v + 2;
-
- edge_u1->stitch_edge_key = {edge_u1->stitch_start_vert_index, edge_u1->stitch_end_vert_index};
-
- edge_v1->stitch_start_vert_index = -(face.start_corner + mod(corner + 1, face.num_corners)) -
- 1;
- edge_v1->stitch_end_vert_index = STITCH_NGON_CENTER_VERT_INDEX_OFFSET + face.ptex_offset;
-
- edge_v1->start_vert_index = v + 1;
- edge_v1->end_vert_index = v + 2;
-
- edge_v1->stitch_edge_key = {edge_v1->stitch_start_vert_index, edge_v1->stitch_end_vert_index};
-
- bool v0_reversed, u0_reversed;
-
- subpatch.edge_v0.edge = create_split_edge_from_corner(this,
- params.mesh,
- face,
- corner - 1,
- 0,
- v0_reversed,
- v + 3,
- v + 0,
- STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG);
-
- subpatch.edge_u1.edge = edge_u1;
- subpatch.edge_v1.edge = edge_v1;
-
- subpatch.edge_u0.edge = create_split_edge_from_corner(this,
- params.mesh,
- face,
- corner + 0,
- 1,
- u0_reversed,
- v + 0,
- v + 1,
- STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG);
-
- subpatch.edge_v0.sub_edges_created_in_reverse_order = !v0_reversed;
- subpatch.edge_u1.sub_edges_created_in_reverse_order = false;
- subpatch.edge_v1.sub_edges_created_in_reverse_order = true;
- subpatch.edge_u0.sub_edges_created_in_reverse_order = !u0_reversed;
-
- subpatch.edge_v0.indices_decrease_along_edge = v0_reversed;
- subpatch.edge_u1.indices_decrease_along_edge = false;
- subpatch.edge_v1.indices_decrease_along_edge = true;
- subpatch.edge_u0.indices_decrease_along_edge = u0_reversed;
-
- /* Perform split. */
- {
- subpatch.edge_u0.T = T(subpatch.patch, subpatch.c00, subpatch.c10);
- subpatch.edge_u1.T = T(subpatch.patch, subpatch.c01, subpatch.c11);
- subpatch.edge_v0.T = T(subpatch.patch, subpatch.c00, subpatch.c01);
- subpatch.edge_v1.T = T(subpatch.patch, subpatch.c10, subpatch.c11);
-
- resolve_edge_factors(subpatch);
-
- split(subpatch, 0);
- }
-
- /* Update offsets after T is known from split. */
- edge_u1->top = subpatch.edge_v0.edge;
- edge_u1->stitch_top_offset = edge_u1->top->T * (v0_reversed ? -1 : 1);
- edge_v1->top = subpatch.edge_u0.edge;
- edge_v1->stitch_top_offset = edge_v1->top->T * (!u0_reversed ? -1 : 1);
-
- if (corner == 0) {
- first_edge_v0 = subpatch.edge_v0.edge;
- }
-
- if (prev_edge_u0) {
- if (v0_reversed) {
- subpatch.edge_v0.edge->stitch_offset = prev_edge_u0->T;
- }
- else {
- prev_edge_u0->stitch_offset = subpatch.edge_v0.edge->T;
- }
-
- int T = subpatch.edge_v0.edge->T + prev_edge_u0->T;
- subpatch.edge_v0.edge->stitch_edge_T = T;
- prev_edge_u0->stitch_edge_T = T;
- }
-
- if (corner == face.num_corners - 1) {
- if (v0_reversed) {
- subpatch.edge_u0.edge->stitch_offset = first_edge_v0->T;
- }
- else {
- first_edge_v0->stitch_offset = subpatch.edge_u0.edge->T;
- }
-
- int T = first_edge_v0->T + subpatch.edge_u0.edge->T;
- first_edge_v0->stitch_edge_T = T;
- subpatch.edge_u0.edge->stitch_edge_T = T;
- }
-
- prev_edge_u0 = subpatch.edge_u0.edge;
- }
-}
-
-void DiagSplit::post_split()
-{
- int num_stitch_verts = 0;
-
- /* All patches are now split, and all T values known. */
-
- foreach (Edge &edge, edges) {
- if (edge.second_vert_index < 0) {
- edge.second_vert_index = alloc_verts(edge.T - 1);
- }
-
- if (edge.is_stitch_edge) {
- num_stitch_verts = max(num_stitch_verts,
- max(edge.stitch_start_vert_index, edge.stitch_end_vert_index));
- }
- }
-
- num_stitch_verts += 1;
-
- /* Map of edge key to edge stitching vert offset. */
- struct pair_hasher {
- size_t operator()(const pair<int, int> &k) const
- {
- return hash_uint2(k.first, k.second);
- }
- };
- typedef unordered_map<pair<int, int>, int, pair_hasher> edge_stitch_verts_map_t;
- edge_stitch_verts_map_t edge_stitch_verts_map;
-
- foreach (Edge &edge, edges) {
- if (edge.is_stitch_edge) {
- if (edge.stitch_edge_T == 0) {
- edge.stitch_edge_T = edge.T;
- }
-
- if (edge_stitch_verts_map.find(edge.stitch_edge_key) == edge_stitch_verts_map.end()) {
- edge_stitch_verts_map[edge.stitch_edge_key] = num_stitch_verts;
- num_stitch_verts += edge.stitch_edge_T - 1;
- }
- }
- }
-
- /* Set start and end indices for edges generated from a split. */
- foreach (Edge &edge, edges) {
- if (edge.start_vert_index < 0) {
- /* Fix up offsets. */
- if (edge.top_indices_decrease) {
- edge.top_offset = edge.top->T - edge.top_offset;
- }
-
- edge.start_vert_index = edge.top->get_vert_along_edge(edge.top_offset);
- }
-
- if (edge.end_vert_index < 0) {
- if (edge.bottom_indices_decrease) {
- edge.bottom_offset = edge.bottom->T - edge.bottom_offset;
- }
-
- edge.end_vert_index = edge.bottom->get_vert_along_edge(edge.bottom_offset);
- }
- }
-
- int vert_offset = params.mesh->verts.size();
-
- /* Add verts to stitching map. */
- foreach (const Edge &edge, edges) {
- if (edge.is_stitch_edge) {
- int second_stitch_vert_index = edge_stitch_verts_map[edge.stitch_edge_key];
-
- for (int i = 0; i <= edge.T; i++) {
- /* Get proper stitching key. */
- int key;
-
- if (i == 0) {
- key = edge.stitch_start_vert_index;
- }
- else if (i == edge.T) {
- key = edge.stitch_end_vert_index;
- }
- else {
- key = second_stitch_vert_index + i - 1 + edge.stitch_offset;
- }
-
- if (key == STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG) {
- if (i == 0) {
- key = second_stitch_vert_index - 1 + edge.stitch_offset;
- }
- else if (i == edge.T) {
- key = second_stitch_vert_index - 1 + edge.T;
- }
- }
- else if (key < 0 && edge.top) { /* ngon spoke edge */
- int s = edge_stitch_verts_map[edge.top->stitch_edge_key];
- if (edge.stitch_top_offset >= 0) {
- key = s - 1 + edge.stitch_top_offset;
- }
- else {
- key = s - 1 + edge.top->stitch_edge_T + edge.stitch_top_offset;
- }
- }
-
- /* Get real vert index. */
- int vert = edge.get_vert_along_edge(i) + vert_offset;
-
- /* Add to map */
- if (params.mesh->vert_to_stitching_key_map.find(vert) ==
- params.mesh->vert_to_stitching_key_map.end()) {
- params.mesh->vert_to_stitching_key_map[vert] = key;
- params.mesh->vert_stitching_map.insert({key, vert});
- }
- }
- }
- }
-
- /* Dice; TODO(mai): Move this out of split. */
- QuadDice dice(params);
-
- int num_verts = num_alloced_verts;
- int num_triangles = 0;
-
- for (size_t i = 0; i < subpatches.size(); i++) {
- subpatches[i].inner_grid_vert_offset = num_verts;
- num_verts += subpatches[i].calc_num_inner_verts();
- num_triangles += subpatches[i].calc_num_triangles();
- }
-
- dice.reserve(num_verts, num_triangles);
-
- for (size_t i = 0; i < subpatches.size(); i++) {
- Subpatch &sub = subpatches[i];
-
- sub.edge_u0.T = max(sub.edge_u0.T, 1);
- sub.edge_u1.T = max(sub.edge_u1.T, 1);
- sub.edge_v0.T = max(sub.edge_v0.T, 1);
- sub.edge_v1.T = max(sub.edge_v1.T, 1);
-
- dice.dice(sub);
- }
-
- /* Cleanup */
- subpatches.clear();
- edges.clear();
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/subd_split.h b/intern/cycles/subd/subd_split.h
deleted file mode 100644
index 7416b2fbbf8..00000000000
--- a/intern/cycles/subd/subd_split.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SUBD_SPLIT_H__
-#define __SUBD_SPLIT_H__
-
-/* DiagSplit: Parallel, Crack-free, Adaptive Tessellation for Micropolygon Rendering
- * Splits up patches and determines edge tessellation factors for dicing. Patch
- * evaluation at arbitrary points is required for this to work. See the paper
- * for more details. */
-
-#include "subd/subd_dice.h"
-#include "subd/subd_subpatch.h"
-
-#include "util/util_deque.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-#include <deque>
-
-CCL_NAMESPACE_BEGIN
-
-class Mesh;
-class Patch;
-
-class DiagSplit {
- SubdParams params;
-
- vector<Subpatch> subpatches;
- /* `deque` is used so that element pointers remain valid when size is changed. */
- deque<Edge> edges;
-
- float3 to_world(Patch *patch, float2 uv);
- int T(Patch *patch, float2 Pstart, float2 Pend, bool recursive_resolve = false);
-
- void limit_edge_factor(int &T, Patch *patch, float2 Pstart, float2 Pend);
- void resolve_edge_factors(Subpatch &sub);
-
- void partition_edge(
- Patch *patch, float2 *P, int *t0, int *t1, float2 Pstart, float2 Pend, int t);
-
- void split(Subpatch &sub, int depth = 0);
-
- int num_alloced_verts = 0;
- int alloc_verts(int n); /* Returns start index of new verts. */
-
- public:
- Edge *alloc_edge();
-
- explicit DiagSplit(const SubdParams &params);
-
- void split_patches(Patch *patches, size_t patches_byte_stride);
-
- void split_quad(const Mesh::SubdFace &face, Patch *patch);
- void split_ngon(const Mesh::SubdFace &face, Patch *patches, size_t patches_byte_stride);
-
- void post_split();
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __SUBD_SPLIT_H__ */
diff --git a/intern/cycles/subd/subd_subpatch.h b/intern/cycles/subd/subd_subpatch.h
deleted file mode 100644
index cdaa310916a..00000000000
--- a/intern/cycles/subd/subd_subpatch.h
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SUBD_SUBPATCH_H__
-#define __SUBD_SUBPATCH_H__
-
-#include "util/util_map.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Subpatch */
-
-class Subpatch {
- public:
- class Patch *patch; /* Patch this is a subpatch of. */
- int inner_grid_vert_offset;
-
- struct edge_t {
- int T;
- int offset; /* Offset along main edge, interpretation depends on the two flags below. */
-
- bool indices_decrease_along_edge;
- bool sub_edges_created_in_reverse_order;
-
- struct Edge *edge;
-
- int get_vert_along_edge(int n) const;
- };
-
- /*
- * eu1
- * c01 --------- c11
- * | |
- * ev0 | | ev1
- * | |
- * c00 --------- c10
- * eu0
- */
-
- union {
- float2 corners[4]; /* UV within patch, clockwise starting from uv (0, 0) towards (0, 1) etc. */
- struct {
- float2 c00, c01, c11, c10;
- };
- };
-
- union {
- edge_t
- edges[4]; /* Edges of this subpatch, each edge starts at the corner of the same index. */
- struct {
- edge_t edge_v0, edge_u1, edge_v1, edge_u0;
- };
- };
-
- explicit Subpatch(Patch *patch = nullptr)
- : patch(patch),
- c00(zero_float2()),
- c01(make_float2(0.0f, 1.0f)),
- c11(one_float2()),
- c10(make_float2(1.0f, 0.0f))
- {
- }
-
- Subpatch(Patch *patch, float2 c00, float2 c01, float2 c11, float2 c10)
- : patch(patch), c00(c00), c01(c01), c11(c11), c10(c10)
- {
- }
-
- int calc_num_inner_verts() const
- {
- int Mu = max(edge_u0.T, edge_u1.T);
- int Mv = max(edge_v0.T, edge_v1.T);
- Mu = max(Mu, 2);
- Mv = max(Mv, 2);
- return (Mu - 1) * (Mv - 1);
- }
-
- int calc_num_triangles() const
- {
- int Mu = max(edge_u0.T, edge_u1.T);
- int Mv = max(edge_v0.T, edge_v1.T);
- Mu = max(Mu, 2);
- Mv = max(Mv, 2);
-
- int inner_triangles = (Mu - 2) * (Mv - 2) * 2;
- int edge_triangles = edge_u0.T + edge_u1.T + edge_v0.T + edge_v1.T + (Mu - 2) * 2 +
- (Mv - 2) * 2;
-
- return inner_triangles + edge_triangles;
- }
-
- int get_vert_along_edge(int e, int n) const;
-
- int get_vert_along_grid_edge(int edge, int n) const
- {
- int Mu = max(edge_u0.T, edge_u1.T);
- int Mv = max(edge_v0.T, edge_v1.T);
- Mu = max(Mu, 2);
- Mv = max(Mv, 2);
-
- switch (edge) {
- case 0:
- return inner_grid_vert_offset + n * (Mu - 1);
- case 1:
- return inner_grid_vert_offset + (Mu - 1) * (Mv - 2) + n;
- case 2:
- return inner_grid_vert_offset + ((Mu - 1) * (Mv - 1) - 1) - n * (Mu - 1);
- case 3:
- return inner_grid_vert_offset + (Mu - 2) - n;
- }
-
- return -1;
- }
-};
-
-struct Edge {
- /* Number of segments the edge will be diced into, see DiagSplit paper. */
- int T;
-
- /* top is edge adjacent to start, bottom is adjacent to end. */
- Edge *top, *bottom;
-
- int top_offset, bottom_offset;
- bool top_indices_decrease, bottom_indices_decrease;
-
- int start_vert_index;
- int end_vert_index;
-
- /* Index of the second vert from this edges corner along the edge towards the next corner. */
- int second_vert_index;
-
- /* Vertices on edge are to be stitched. */
- bool is_stitch_edge;
-
- /* Key to match this edge with others to be stitched with.
- * The ints in the pair are ordered stitching indices */
- pair<int, int> stitch_edge_key;
-
- /* Full T along edge (may be larger than T for edges split from ngon edges) */
- int stitch_edge_T;
- int stitch_offset;
- int stitch_top_offset;
- int stitch_start_vert_index;
- int stitch_end_vert_index;
-
- Edge()
- : T(0),
- top(nullptr),
- bottom(nullptr),
- top_offset(-1),
- bottom_offset(-1),
- top_indices_decrease(false),
- bottom_indices_decrease(false),
- start_vert_index(-1),
- end_vert_index(-1),
- second_vert_index(-1),
- is_stitch_edge(false),
- stitch_edge_T(0),
- stitch_offset(0)
- {
- }
-
- int get_vert_along_edge(int n) const
- {
- assert(n >= 0 && n <= T);
-
- if (n == 0) {
- return start_vert_index;
- }
- else if (n == T) {
- return end_vert_index;
- }
-
- return second_vert_index + n - 1;
- }
-};
-
-inline int Subpatch::edge_t::get_vert_along_edge(int n) const
-{
- assert(n >= 0 && n <= T);
-
- if (!indices_decrease_along_edge && !sub_edges_created_in_reverse_order) {
- n = offset + n;
- }
- else if (!indices_decrease_along_edge && sub_edges_created_in_reverse_order) {
- n = edge->T - offset - T + n;
- }
- else if (indices_decrease_along_edge && !sub_edges_created_in_reverse_order) {
- n = offset + T - n;
- }
- else if (indices_decrease_along_edge && sub_edges_created_in_reverse_order) {
- n = edge->T - offset - n;
- }
-
- return edge->get_vert_along_edge(n);
-}
-
-inline int Subpatch::get_vert_along_edge(int edge, int n) const
-{
- return edges[edge].get_vert_along_edge(n);
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __SUBD_SUBPATCH_H__ */
diff --git a/intern/cycles/subd/subpatch.h b/intern/cycles/subd/subpatch.h
new file mode 100644
index 00000000000..0ba8ed88aa8
--- /dev/null
+++ b/intern/cycles/subd/subpatch.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SUBD_SUBPATCH_H__
+#define __SUBD_SUBPATCH_H__
+
+#include "util/map.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Subpatch */
+
+class Subpatch {
+ public:
+ class Patch *patch; /* Patch this is a subpatch of. */
+ int inner_grid_vert_offset;
+
+ struct edge_t {
+ int T;
+ int offset; /* Offset along main edge, interpretation depends on the two flags below. */
+
+ bool indices_decrease_along_edge;
+ bool sub_edges_created_in_reverse_order;
+
+ struct Edge *edge;
+
+ int get_vert_along_edge(int n) const;
+ };
+
+ /*
+ * eu1
+ * c01 --------- c11
+ * | |
+ * ev0 | | ev1
+ * | |
+ * c00 --------- c10
+ * eu0
+ */
+
+ union {
+ float2 corners[4]; /* UV within patch, clockwise starting from uv (0, 0) towards (0, 1) etc. */
+ struct {
+ float2 c00, c01, c11, c10;
+ };
+ };
+
+ union {
+ edge_t
+ edges[4]; /* Edges of this subpatch, each edge starts at the corner of the same index. */
+ struct {
+ edge_t edge_v0, edge_u1, edge_v1, edge_u0;
+ };
+ };
+
+ explicit Subpatch(Patch *patch = nullptr)
+ : patch(patch),
+ c00(zero_float2()),
+ c01(make_float2(0.0f, 1.0f)),
+ c11(one_float2()),
+ c10(make_float2(1.0f, 0.0f))
+ {
+ }
+
+ Subpatch(Patch *patch, float2 c00, float2 c01, float2 c11, float2 c10)
+ : patch(patch), c00(c00), c01(c01), c11(c11), c10(c10)
+ {
+ }
+
+ int calc_num_inner_verts() const
+ {
+ int Mu = max(edge_u0.T, edge_u1.T);
+ int Mv = max(edge_v0.T, edge_v1.T);
+ Mu = max(Mu, 2);
+ Mv = max(Mv, 2);
+ return (Mu - 1) * (Mv - 1);
+ }
+
+ int calc_num_triangles() const
+ {
+ int Mu = max(edge_u0.T, edge_u1.T);
+ int Mv = max(edge_v0.T, edge_v1.T);
+ Mu = max(Mu, 2);
+ Mv = max(Mv, 2);
+
+ int inner_triangles = (Mu - 2) * (Mv - 2) * 2;
+ int edge_triangles = edge_u0.T + edge_u1.T + edge_v0.T + edge_v1.T + (Mu - 2) * 2 +
+ (Mv - 2) * 2;
+
+ return inner_triangles + edge_triangles;
+ }
+
+ int get_vert_along_edge(int e, int n) const;
+
+ int get_vert_along_grid_edge(int edge, int n) const
+ {
+ int Mu = max(edge_u0.T, edge_u1.T);
+ int Mv = max(edge_v0.T, edge_v1.T);
+ Mu = max(Mu, 2);
+ Mv = max(Mv, 2);
+
+ switch (edge) {
+ case 0:
+ return inner_grid_vert_offset + n * (Mu - 1);
+ case 1:
+ return inner_grid_vert_offset + (Mu - 1) * (Mv - 2) + n;
+ case 2:
+ return inner_grid_vert_offset + ((Mu - 1) * (Mv - 1) - 1) - n * (Mu - 1);
+ case 3:
+ return inner_grid_vert_offset + (Mu - 2) - n;
+ }
+
+ return -1;
+ }
+};
+
+struct Edge {
+ /* Number of segments the edge will be diced into, see DiagSplit paper. */
+ int T;
+
+ /* top is edge adjacent to start, bottom is adjacent to end. */
+ Edge *top, *bottom;
+
+ int top_offset, bottom_offset;
+ bool top_indices_decrease, bottom_indices_decrease;
+
+ int start_vert_index;
+ int end_vert_index;
+
+ /* Index of the second vert from this edges corner along the edge towards the next corner. */
+ int second_vert_index;
+
+ /* Vertices on edge are to be stitched. */
+ bool is_stitch_edge;
+
+ /* Key to match this edge with others to be stitched with.
+ * The ints in the pair are ordered stitching indices */
+ pair<int, int> stitch_edge_key;
+
+ /* Full T along edge (may be larger than T for edges split from ngon edges) */
+ int stitch_edge_T;
+ int stitch_offset;
+ int stitch_top_offset;
+ int stitch_start_vert_index;
+ int stitch_end_vert_index;
+
+ Edge()
+ : T(0),
+ top(nullptr),
+ bottom(nullptr),
+ top_offset(-1),
+ bottom_offset(-1),
+ top_indices_decrease(false),
+ bottom_indices_decrease(false),
+ start_vert_index(-1),
+ end_vert_index(-1),
+ second_vert_index(-1),
+ is_stitch_edge(false),
+ stitch_edge_T(0),
+ stitch_offset(0)
+ {
+ }
+
+ int get_vert_along_edge(int n) const
+ {
+ assert(n >= 0 && n <= T);
+
+ if (n == 0) {
+ return start_vert_index;
+ }
+ else if (n == T) {
+ return end_vert_index;
+ }
+
+ return second_vert_index + n - 1;
+ }
+};
+
+inline int Subpatch::edge_t::get_vert_along_edge(int n) const
+{
+ assert(n >= 0 && n <= T);
+
+ if (!indices_decrease_along_edge && !sub_edges_created_in_reverse_order) {
+ n = offset + n;
+ }
+ else if (!indices_decrease_along_edge && sub_edges_created_in_reverse_order) {
+ n = edge->T - offset - T + n;
+ }
+ else if (indices_decrease_along_edge && !sub_edges_created_in_reverse_order) {
+ n = offset + T - n;
+ }
+ else if (indices_decrease_along_edge && sub_edges_created_in_reverse_order) {
+ n = edge->T - offset - n;
+ }
+
+ return edge->get_vert_along_edge(n);
+}
+
+inline int Subpatch::get_vert_along_edge(int edge, int n) const
+{
+ return edges[edge].get_vert_along_edge(n);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __SUBD_SUBPATCH_H__ */
diff --git a/intern/cycles/test/CMakeLists.txt b/intern/cycles/test/CMakeLists.txt
index 0f6b435813f..86a830b2b65 100644
--- a/intern/cycles/test/CMakeLists.txt
+++ b/intern/cycles/test/CMakeLists.txt
@@ -20,23 +20,18 @@ if(WITH_GTESTS)
endif()
set(INC
- .
..
- ../device
- ../graph
- ../kernel
- ../render
- ../util
)
set(ALL_CYCLES_LIBRARIES
- cycles_device
cycles_kernel
cycles_integrator
- cycles_render
+ cycles_scene
+ cycles_session
cycles_bvh
cycles_graph
cycles_subd
+ cycles_device
cycles_util
extern_clew
${CYCLES_GL_LIBRARIES}
diff --git a/intern/cycles/test/integrator_adaptive_sampling_test.cpp b/intern/cycles/test/integrator_adaptive_sampling_test.cpp
index 3ed6a23125d..30688605e44 100644
--- a/intern/cycles/test/integrator_adaptive_sampling_test.cpp
+++ b/intern/cycles/test/integrator_adaptive_sampling_test.cpp
@@ -17,7 +17,7 @@
#include "testing/testing.h"
#include "integrator/adaptive_sampling.h"
-#include "util/util_vector.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/test/integrator_tile_test.cpp b/intern/cycles/test/integrator_tile_test.cpp
index 5bb57b48c3c..8bb0856d6a9 100644
--- a/intern/cycles/test/integrator_tile_test.cpp
+++ b/intern/cycles/test/integrator_tile_test.cpp
@@ -17,30 +17,33 @@
#include "testing/testing.h"
#include "integrator/tile.h"
-#include "util/util_math.h"
+#include "util/math.h"
CCL_NAMESPACE_BEGIN
TEST(tile_calculate_best_size, Basic)
{
/* Make sure CPU-like case is handled properly. */
- EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 1, 1), TileSize(1, 1, 1));
- EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 100, 1), TileSize(1, 1, 1));
+ EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 1, 1, 1.0f), TileSize(1, 1, 1));
+ EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 100, 1, 1.0f), TileSize(1, 1, 1));
/* Enough path states to fit an entire image with all samples. */
- EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 1, 1920 * 1080),
+ EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 1, 1920 * 1080, 1.0f),
TileSize(1920, 1080, 1));
- EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 100, 1920 * 1080 * 100),
+ EXPECT_EQ(tile_calculate_best_size(make_int2(1920, 1080), 100, 1920 * 1080 * 100, 1.0f),
TileSize(1920, 1080, 100));
}
TEST(tile_calculate_best_size, Extreme)
{
- EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 262144, 131072), TileSize(1, 1, 512));
- EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 1048576, 131072), TileSize(1, 1, 1024));
- EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 10485760, 131072), TileSize(1, 1, 4096));
+ EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 262144, 131072, 1.0f),
+ TileSize(1, 1, 512));
+ EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 1048576, 131072, 1.0f),
+ TileSize(1, 1, 1024));
+ EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 10485760, 131072, 1.0f),
+ TileSize(1, 1, 4096));
- EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 8192 * 8192 * 2, 1024),
+ EXPECT_EQ(tile_calculate_best_size(make_int2(32, 32), 8192 * 8192 * 2, 1024, 1.0f),
TileSize(1, 1, 1024));
}
diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp
index 19c211fe5f7..4207b437a41 100644
--- a/intern/cycles/test/render_graph_finalize_test.cpp
+++ b/intern/cycles/test/render_graph_finalize_test.cpp
@@ -19,15 +19,15 @@
#include "device/device.h"
-#include "render/graph.h"
-#include "render/nodes.h"
-#include "render/scene.h"
-
-#include "util/util_array.h"
-#include "util/util_logging.h"
-#include "util/util_stats.h"
-#include "util/util_string.h"
-#include "util/util_vector.h"
+#include "scene/scene.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+
+#include "util/array.h"
+#include "util/log.h"
+#include "util/stats.h"
+#include "util/string.h"
+#include "util/vector.h"
using testing::_;
using testing::AnyNumber;
diff --git a/intern/cycles/test/util_aligned_malloc_test.cpp b/intern/cycles/test/util_aligned_malloc_test.cpp
index 8829c422a0f..2748db520eb 100644
--- a/intern/cycles/test/util_aligned_malloc_test.cpp
+++ b/intern/cycles/test/util_aligned_malloc_test.cpp
@@ -16,7 +16,7 @@
#include "testing/testing.h"
-#include "util/util_aligned_malloc.h"
+#include "util/aligned_malloc.h"
#define CHECK_ALIGNMENT(ptr, align) EXPECT_EQ((size_t)ptr % align, 0)
diff --git a/intern/cycles/test/util_avxf_test.h b/intern/cycles/test/util_avxf_test.h
index 64825200c9e..b178a0450d0 100644
--- a/intern/cycles/test/util_avxf_test.h
+++ b/intern/cycles/test/util_avxf_test.h
@@ -15,8 +15,8 @@
*/
#include "testing/testing.h"
-#include "util/util_system.h"
-#include "util/util_types.h"
+#include "util/system.h"
+#include "util/types.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/test/util_math_test.cpp b/intern/cycles/test/util_math_test.cpp
index b6ce3ef0cf3..adbedf7adbe 100644
--- a/intern/cycles/test/util_math_test.cpp
+++ b/intern/cycles/test/util_math_test.cpp
@@ -16,7 +16,7 @@
#include "testing/testing.h"
-#include "util/util_math.h"
+#include "util/math.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/test/util_path_test.cpp b/intern/cycles/test/util_path_test.cpp
index 76d48dc241d..7afdd1150a4 100644
--- a/intern/cycles/test/util_path_test.cpp
+++ b/intern/cycles/test/util_path_test.cpp
@@ -16,7 +16,7 @@
#include "testing/testing.h"
-#include "util/util_path.h"
+#include "util/path.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/test/util_string_test.cpp b/intern/cycles/test/util_string_test.cpp
index c9022d1b132..f558dda9e47 100644
--- a/intern/cycles/test/util_string_test.cpp
+++ b/intern/cycles/test/util_string_test.cpp
@@ -16,7 +16,7 @@
#include "testing/testing.h"
-#include "util/util_string.h"
+#include "util/string.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/test/util_task_test.cpp b/intern/cycles/test/util_task_test.cpp
index a8b4dfc3a37..17cfe4ff9b2 100644
--- a/intern/cycles/test/util_task_test.cpp
+++ b/intern/cycles/test/util_task_test.cpp
@@ -16,7 +16,7 @@
#include "testing/testing.h"
-#include "util/util_task.h"
+#include "util/task.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/test/util_time_test.cpp b/intern/cycles/test/util_time_test.cpp
index ab5ead2c7b1..97a0134df67 100644
--- a/intern/cycles/test/util_time_test.cpp
+++ b/intern/cycles/test/util_time_test.cpp
@@ -16,7 +16,7 @@
#include "testing/testing.h"
-#include "util/util_time.h"
+#include "util/time.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/test/util_transform_test.cpp b/intern/cycles/test/util_transform_test.cpp
index a5267df9fb7..11dd71ea0c2 100644
--- a/intern/cycles/test/util_transform_test.cpp
+++ b/intern/cycles/test/util_transform_test.cpp
@@ -16,8 +16,8 @@
#include "testing/testing.h"
-#include "util/util_transform.h"
-#include "util/util_vector.h"
+#include "util/transform.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index 18e14913884..b68646a44d5 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -22,23 +22,23 @@ set(INC_SYS
)
set(SRC
- util_aligned_malloc.cpp
- util_debug.cpp
- util_ies.cpp
- util_logging.cpp
- util_math_cdf.cpp
- util_md5.cpp
- util_murmurhash.cpp
- util_path.cpp
- util_profiling.cpp
- util_string.cpp
- util_simd.cpp
- util_system.cpp
- util_task.cpp
- util_thread.cpp
- util_time.cpp
- util_transform.cpp
- util_windows.cpp
+ aligned_malloc.cpp
+ debug.cpp
+ ies.cpp
+ log.cpp
+ math_cdf.cpp
+ md5.cpp
+ murmurhash.cpp
+ path.cpp
+ profiling.cpp
+ string.cpp
+ simd.cpp
+ system.cpp
+ task.cpp
+ thread.cpp
+ time.cpp
+ transform.cpp
+ windows.cpp
)
set(LIB
@@ -48,7 +48,7 @@ set(LIB
if(WITH_CYCLES_STANDALONE)
if(WITH_CYCLES_STANDALONE_GUI)
list(APPEND SRC
- util_view.cpp
+ view.cpp
)
endif()
endif()
@@ -64,108 +64,108 @@ else()
endif()
set(SRC_HEADERS
- util_algorithm.h
- util_aligned_malloc.h
- util_args.h
- util_array.h
- util_atomic.h
- util_boundbox.h
- util_debug.h
- util_defines.h
- util_deque.h
- util_disjoint_set.h
- util_guarded_allocator.cpp
- util_foreach.h
- util_function.h
- util_guarded_allocator.h
- util_half.h
- util_hash.h
- util_ies.h
- util_image.h
- util_image_impl.h
- util_list.h
- util_logging.h
- util_map.h
- util_math.h
- util_math_cdf.h
- util_math_fast.h
- util_math_intersect.h
- util_math_float2.h
- util_math_float3.h
- util_math_float4.h
- util_math_int2.h
- util_math_int3.h
- util_math_int4.h
- util_math_matrix.h
- util_md5.h
- util_murmurhash.h
- util_openimagedenoise.h
- util_opengl.h
- util_openvdb.h
- util_optimization.h
- util_param.h
- util_path.h
- util_profiling.h
- util_progress.h
- util_projection.h
- util_queue.h
- util_rect.h
- util_set.h
- util_simd.h
- util_avxf.h
- util_avxb.h
- util_avxi.h
- util_semaphore.h
- util_sseb.h
- util_ssef.h
- util_ssei.h
- util_stack_allocator.h
- util_static_assert.h
- util_stats.h
- util_string.h
- util_system.h
- util_task.h
- util_tbb.h
- util_texture.h
- util_thread.h
- util_time.h
- util_transform.h
- util_types.h
- util_types_float2.h
- util_types_float2_impl.h
- util_types_float3.h
- util_types_float3_impl.h
- util_types_float4.h
- util_types_float4_impl.h
- util_types_float8.h
- util_types_float8_impl.h
- util_types_int2.h
- util_types_int2_impl.h
- util_types_int3.h
- util_types_int3_impl.h
- util_types_int4.h
- util_types_int4_impl.h
- util_types_uchar2.h
- util_types_uchar2_impl.h
- util_types_uchar3.h
- util_types_uchar3_impl.h
- util_types_uchar4.h
- util_types_uchar4_impl.h
- util_types_uint2.h
- util_types_uint2_impl.h
- util_types_uint3.h
- util_types_uint3_impl.h
- util_types_uint4.h
- util_types_uint4_impl.h
- util_types_ushort4.h
- util_types_vector3.h
- util_types_vector3_impl.h
- util_unique_ptr.h
- util_vector.h
- util_version.h
- util_view.h
- util_windows.h
- util_xml.h
+ algorithm.h
+ aligned_malloc.h
+ args.h
+ array.h
+ atomic.h
+ boundbox.h
+ debug.h
+ defines.h
+ deque.h
+ disjoint_set.h
+ guarded_allocator.cpp
+ foreach.h
+ function.h
+ guarded_allocator.h
+ half.h
+ hash.h
+ ies.h
+ image.h
+ image_impl.h
+ list.h
+ log.h
+ map.h
+ math.h
+ math_cdf.h
+ math_fast.h
+ math_intersect.h
+ math_float2.h
+ math_float3.h
+ math_float4.h
+ math_int2.h
+ math_int3.h
+ math_int4.h
+ math_matrix.h
+ md5.h
+ murmurhash.h
+ openimagedenoise.h
+ opengl.h
+ openvdb.h
+ optimization.h
+ param.h
+ path.h
+ profiling.h
+ progress.h
+ projection.h
+ queue.h
+ rect.h
+ set.h
+ simd.h
+ avxf.h
+ avxb.h
+ avxi.h
+ semaphore.h
+ sseb.h
+ ssef.h
+ ssei.h
+ stack_allocator.h
+ static_assert.h
+ stats.h
+ string.h
+ system.h
+ task.h
+ tbb.h
+ texture.h
+ thread.h
+ time.h
+ transform.h
+ types.h
+ types_float2.h
+ types_float2_impl.h
+ types_float3.h
+ types_float3_impl.h
+ types_float4.h
+ types_float4_impl.h
+ types_float8.h
+ types_float8_impl.h
+ types_int2.h
+ types_int2_impl.h
+ types_int3.h
+ types_int3_impl.h
+ types_int4.h
+ types_int4_impl.h
+ types_uchar2.h
+ types_uchar2_impl.h
+ types_uchar3.h
+ types_uchar3_impl.h
+ types_uchar4.h
+ types_uchar4_impl.h
+ types_uint2.h
+ types_uint2_impl.h
+ types_uint3.h
+ types_uint3_impl.h
+ types_uint4.h
+ types_uint4_impl.h
+ types_ushort4.h
+ types_vector3.h
+ types_vector3_impl.h
+ unique_ptr.h
+ vector.h
+ version.h
+ view.h
+ windows.h
+ xml.h
)
include_directories(${INC})
diff --git a/intern/cycles/util/util_algorithm.h b/intern/cycles/util/algorithm.h
index 63abd4e92a3..63abd4e92a3 100644
--- a/intern/cycles/util/util_algorithm.h
+++ b/intern/cycles/util/algorithm.h
diff --git a/intern/cycles/util/aligned_malloc.cpp b/intern/cycles/util/aligned_malloc.cpp
new file mode 100644
index 00000000000..2b05559b55f
--- /dev/null
+++ b/intern/cycles/util/aligned_malloc.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/aligned_malloc.h"
+#include "util/guarded_allocator.h"
+
+#include <cassert>
+
+/* Adopted from Libmv. */
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
+/* Needed for memalign on Linux and _aligned_alloc on Windows. */
+# ifdef FREE_WINDOWS
+/* Make sure _aligned_malloc is included. */
+# ifdef __MSVCRT_VERSION__
+# undef __MSVCRT_VERSION__
+# endif
+# define __MSVCRT_VERSION__ 0x0700
+# endif /* FREE_WINDOWS */
+# include <malloc.h>
+#else
+/* Apple's malloc is 16-byte aligned, and does not have malloc.h, so include
+ * stdilb instead.
+ */
+# include <cstdlib>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+void *util_aligned_malloc(size_t size, int alignment)
+{
+#ifdef WITH_BLENDER_GUARDEDALLOC
+ return MEM_mallocN_aligned(size, alignment, "Cycles Aligned Alloc");
+#elif defined(_WIN32)
+ return _aligned_malloc(size, alignment);
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+ void *result;
+ if (posix_memalign(&result, alignment, size)) {
+ /* Non-zero means allocation error
+ * either no allocation or bad alignment value.
+ */
+ return NULL;
+ }
+ return result;
+#else /* This is for Linux. */
+ return memalign(alignment, size);
+#endif
+}
+
+void util_aligned_free(void *ptr)
+{
+#if defined(WITH_BLENDER_GUARDEDALLOC)
+ if (ptr != NULL) {
+ MEM_freeN(ptr);
+ }
+#elif defined(_WIN32)
+ _aligned_free(ptr);
+#else
+ free(ptr);
+#endif
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/aligned_malloc.h b/intern/cycles/util/aligned_malloc.h
new file mode 100644
index 00000000000..66c2ac1c593
--- /dev/null
+++ b/intern/cycles/util/aligned_malloc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_ALIGNED_MALLOC_H__
+#define __UTIL_ALIGNED_MALLOC_H__
+
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Minimum alignment needed by all CPU native data types (SSE, AVX). */
+#define MIN_ALIGNMENT_CPU_DATA_TYPES 16
+
+/* Allocate block of size bytes at least aligned to a given value. */
+void *util_aligned_malloc(size_t size, int alignment);
+
+/* Free memory allocated by util_aligned_malloc. */
+void util_aligned_free(void *ptr);
+
+/* Aligned new operator. */
+template<typename T, typename... Args> T *util_aligned_new(Args... args)
+{
+ void *mem = util_aligned_malloc(sizeof(T), alignof(T));
+ return new (mem) T(args...);
+}
+
+template<typename T> void util_aligned_delete(T *t)
+{
+ if (t) {
+ t->~T();
+ util_aligned_free(t);
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_ALIGNED_MALLOC_H__ */
diff --git a/intern/cycles/util/util_args.h b/intern/cycles/util/args.h
index be6f2c2b9f1..be6f2c2b9f1 100644
--- a/intern/cycles/util/util_args.h
+++ b/intern/cycles/util/args.h
diff --git a/intern/cycles/util/array.h b/intern/cycles/util/array.h
new file mode 100644
index 00000000000..4c905b09138
--- /dev/null
+++ b/intern/cycles/util/array.h
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_ARRAY_H__
+#define __UTIL_ARRAY_H__
+
+#include <cassert>
+#include <cstring>
+
+#include "util/aligned_malloc.h"
+#include "util/guarded_allocator.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Simplified version of vector, serving multiple purposes:
+ * - somewhat faster in that it does not clear memory on resize/alloc,
+ * this was actually showing up in profiles quite significantly. it
+ * also does not run any constructors/destructors
+ * - if this is used, we are not tempted to use inefficient operations
+ * - aligned allocation for CPU native data types */
+
+template<typename T, size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES> class array {
+ public:
+ array() : data_(NULL), datasize_(0), capacity_(0)
+ {
+ }
+
+ explicit array(size_t newsize)
+ {
+ if (newsize == 0) {
+ data_ = NULL;
+ datasize_ = 0;
+ capacity_ = 0;
+ }
+ else {
+ data_ = mem_allocate(newsize);
+ datasize_ = newsize;
+ capacity_ = datasize_;
+ }
+ }
+
+ array(const array &from)
+ {
+ if (from.datasize_ == 0) {
+ data_ = NULL;
+ datasize_ = 0;
+ capacity_ = 0;
+ }
+ else {
+ data_ = mem_allocate(from.datasize_);
+ if (from.datasize_ > 0) {
+ memcpy(data_, from.data_, from.datasize_ * sizeof(T));
+ }
+ datasize_ = from.datasize_;
+ capacity_ = datasize_;
+ }
+ }
+
+ array &operator=(const array &from)
+ {
+ if (this != &from) {
+ resize(from.size());
+ if (datasize_ > 0) {
+ memcpy((void *)data_, from.data_, datasize_ * sizeof(T));
+ }
+ }
+
+ return *this;
+ }
+
+ array &operator=(const vector<T> &from)
+ {
+ resize(from.size());
+
+ if (from.size() > 0 && datasize_ > 0) {
+ memcpy(data_, &from[0], datasize_ * sizeof(T));
+ }
+
+ return *this;
+ }
+
+ ~array()
+ {
+ mem_free(data_, capacity_);
+ }
+
+ bool operator==(const array<T> &other) const
+ {
+ if (datasize_ != other.datasize_) {
+ return false;
+ }
+ if (datasize_ == 0) {
+ return true;
+ }
+
+ return memcmp(data_, other.data_, datasize_ * sizeof(T)) == 0;
+ }
+
+ bool operator!=(const array<T> &other) const
+ {
+ return !(*this == other);
+ }
+
+ void steal_data(array &from)
+ {
+ if (this != &from) {
+ clear();
+
+ data_ = from.data_;
+ datasize_ = from.datasize_;
+ capacity_ = from.capacity_;
+
+ from.data_ = NULL;
+ from.datasize_ = 0;
+ from.capacity_ = 0;
+ }
+ }
+
+ void set_data(T *ptr_, size_t datasize)
+ {
+ clear();
+ data_ = ptr_;
+ datasize_ = datasize;
+ capacity_ = datasize;
+ }
+
+ T *steal_pointer()
+ {
+ T *ptr = data_;
+ data_ = NULL;
+ clear();
+ return ptr;
+ }
+
+ T *resize(size_t newsize)
+ {
+ if (newsize == 0) {
+ clear();
+ }
+ else if (newsize != datasize_) {
+ if (newsize > capacity_) {
+ T *newdata = mem_allocate(newsize);
+ if (newdata == NULL) {
+ /* Allocation failed, likely out of memory. */
+ clear();
+ return NULL;
+ }
+ else if (data_ != NULL) {
+ memcpy(
+ (void *)newdata, data_, ((datasize_ < newsize) ? datasize_ : newsize) * sizeof(T));
+ mem_free(data_, capacity_);
+ }
+ data_ = newdata;
+ capacity_ = newsize;
+ }
+ datasize_ = newsize;
+ }
+ return data_;
+ }
+
+ T *resize(size_t newsize, const T &value)
+ {
+ size_t oldsize = size();
+ resize(newsize);
+
+ for (size_t i = oldsize; i < size(); i++) {
+ data_[i] = value;
+ }
+
+ return data_;
+ }
+
+ void clear()
+ {
+ if (data_ != NULL) {
+ mem_free(data_, capacity_);
+ data_ = NULL;
+ }
+ datasize_ = 0;
+ capacity_ = 0;
+ }
+
+ size_t empty() const
+ {
+ return datasize_ == 0;
+ }
+
+ size_t size() const
+ {
+ return datasize_;
+ }
+
+ T *data()
+ {
+ return data_;
+ }
+
+ const T *data() const
+ {
+ return data_;
+ }
+
+ T &operator[](size_t i) const
+ {
+ assert(i < datasize_);
+ return data_[i];
+ }
+
+ T *begin()
+ {
+ return data_;
+ }
+
+ const T *begin() const
+ {
+ return data_;
+ }
+
+ T *end()
+ {
+ return data_ + datasize_;
+ }
+
+ const T *end() const
+ {
+ return data_ + datasize_;
+ }
+
+ void reserve(size_t newcapacity)
+ {
+ if (newcapacity > capacity_) {
+ T *newdata = mem_allocate(newcapacity);
+ if (data_ != NULL) {
+ memcpy(newdata, data_, ((datasize_ < newcapacity) ? datasize_ : newcapacity) * sizeof(T));
+ mem_free(data_, capacity_);
+ }
+ data_ = newdata;
+ capacity_ = newcapacity;
+ }
+ }
+
+ size_t capacity() const
+ {
+ return capacity_;
+ }
+
+ // do not use this method unless you are sure the code is not performance critical
+ void push_back_slow(const T &t)
+ {
+ if (capacity_ == datasize_) {
+ reserve(datasize_ == 0 ? 1 : (size_t)((datasize_ + 1) * 1.2));
+ }
+
+ data_[datasize_++] = t;
+ }
+
+ void push_back_reserved(const T &t)
+ {
+ assert(datasize_ < capacity_);
+ push_back_slow(t);
+ }
+
+ void append(const array<T> &from)
+ {
+ if (from.size()) {
+ size_t old_size = size();
+ resize(old_size + from.size());
+ memcpy(data_ + old_size, from.data(), sizeof(T) * from.size());
+ }
+ }
+
+ protected:
+ inline T *mem_allocate(size_t N)
+ {
+ if (N == 0) {
+ return NULL;
+ }
+ T *mem = (T *)util_aligned_malloc(sizeof(T) * N, alignment);
+ if (mem != NULL) {
+ util_guarded_mem_alloc(sizeof(T) * N);
+ }
+ else {
+ throw std::bad_alloc();
+ }
+ return mem;
+ }
+
+ inline void mem_free(T *mem, size_t N)
+ {
+ if (mem != NULL) {
+ util_guarded_mem_free(sizeof(T) * N);
+ util_aligned_free(mem);
+ }
+ }
+
+ T *data_;
+ size_t datasize_;
+ size_t capacity_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_ARRAY_H__ */
diff --git a/intern/cycles/util/util_atomic.h b/intern/cycles/util/atomic.h
index faba411c769..faba411c769 100644
--- a/intern/cycles/util/util_atomic.h
+++ b/intern/cycles/util/atomic.h
diff --git a/intern/cycles/util/util_avxb.h b/intern/cycles/util/avxb.h
index 15215d04ca3..15215d04ca3 100644
--- a/intern/cycles/util/util_avxb.h
+++ b/intern/cycles/util/avxb.h
diff --git a/intern/cycles/util/util_avxf.h b/intern/cycles/util/avxf.h
index 1fb3ded422f..1fb3ded422f 100644
--- a/intern/cycles/util/util_avxf.h
+++ b/intern/cycles/util/avxf.h
diff --git a/intern/cycles/util/util_avxi.h b/intern/cycles/util/avxi.h
index 0ae4bf271c8..0ae4bf271c8 100644
--- a/intern/cycles/util/util_avxi.h
+++ b/intern/cycles/util/avxi.h
diff --git a/intern/cycles/util/boundbox.h b/intern/cycles/util/boundbox.h
new file mode 100644
index 00000000000..ed81e4cf8c3
--- /dev/null
+++ b/intern/cycles/util/boundbox.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_BOUNDBOX_H__
+#define __UTIL_BOUNDBOX_H__
+
+#include <float.h>
+#include <math.h>
+
+#include "util/math.h"
+#include "util/string.h"
+#include "util/transform.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* 3D BoundBox */
+
+class BoundBox {
+ public:
+ float3 min, max;
+
+ __forceinline BoundBox()
+ {
+ }
+
+ __forceinline BoundBox(const float3 &pt) : min(pt), max(pt)
+ {
+ }
+
+ __forceinline BoundBox(const float3 &min_, const float3 &max_) : min(min_), max(max_)
+ {
+ }
+
+ enum empty_t { empty = 0 };
+
+ __forceinline BoundBox(empty_t)
+ : min(make_float3(FLT_MAX, FLT_MAX, FLT_MAX)), max(make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX))
+ {
+ }
+
+ __forceinline void grow(const float3 &pt)
+ {
+ /* the order of arguments to min is such that if pt is nan, it will not
+ * influence the resulting bounding box */
+ min = ccl::min(pt, min);
+ max = ccl::max(pt, max);
+ }
+
+ __forceinline void grow(const float3 &pt, float border)
+ {
+ float3 shift = make_float3(border, border, border);
+ min = ccl::min(pt - shift, min);
+ max = ccl::max(pt + shift, max);
+ }
+
+ __forceinline void grow(const BoundBox &bbox)
+ {
+ grow(bbox.min);
+ grow(bbox.max);
+ }
+
+ __forceinline void grow_safe(const float3 &pt)
+ {
+ /* the order of arguments to min is such that if pt is nan, it will not
+ * influence the resulting bounding box */
+ if (isfinite(pt.x) && isfinite(pt.y) && isfinite(pt.z)) {
+ min = ccl::min(pt, min);
+ max = ccl::max(pt, max);
+ }
+ }
+
+ __forceinline void grow_safe(const float3 &pt, float border)
+ {
+ if (isfinite(pt.x) && isfinite(pt.y) && isfinite(pt.z) && isfinite(border)) {
+ float3 shift = make_float3(border, border, border);
+ min = ccl::min(pt - shift, min);
+ max = ccl::max(pt + shift, max);
+ }
+ }
+
+ __forceinline void grow_safe(const BoundBox &bbox)
+ {
+ grow_safe(bbox.min);
+ grow_safe(bbox.max);
+ }
+
+ __forceinline void intersect(const BoundBox &bbox)
+ {
+ min = ccl::max(min, bbox.min);
+ max = ccl::min(max, bbox.max);
+ }
+
+ /* todo: avoid using this */
+ __forceinline float safe_area() const
+ {
+ if (!((min.x <= max.x) && (min.y <= max.y) && (min.z <= max.z)))
+ return 0.0f;
+
+ return area();
+ }
+
+ __forceinline float area() const
+ {
+ return half_area() * 2.0f;
+ }
+
+ __forceinline float half_area() const
+ {
+ float3 d = max - min;
+ return (d.x * d.z + d.y * d.z + d.x * d.y);
+ }
+
+ __forceinline float3 center() const
+ {
+ return 0.5f * (min + max);
+ }
+
+ __forceinline float3 center2() const
+ {
+ return min + max;
+ }
+
+ __forceinline float3 size() const
+ {
+ return max - min;
+ }
+
+ __forceinline bool valid() const
+ {
+ return (min.x <= max.x) && (min.y <= max.y) && (min.z <= max.z) &&
+ (isfinite(min.x) && isfinite(min.y) && isfinite(min.z)) &&
+ (isfinite(max.x) && isfinite(max.y) && isfinite(max.z));
+ }
+
+ BoundBox transformed(const Transform *tfm) const
+ {
+ BoundBox result = BoundBox::empty;
+
+ for (int i = 0; i < 8; i++) {
+ float3 p;
+
+ p.x = (i & 1) ? min.x : max.x;
+ p.y = (i & 2) ? min.y : max.y;
+ p.z = (i & 4) ? min.z : max.z;
+
+ result.grow(transform_point(tfm, p));
+ }
+
+ return result;
+ }
+
+ __forceinline bool intersects(const BoundBox &other)
+ {
+ float3 center_diff = center() - other.center(), total_size = (size() + other.size()) * 0.5f;
+ return fabsf(center_diff.x) <= total_size.x && fabsf(center_diff.y) <= total_size.y &&
+ fabsf(center_diff.z) <= total_size.z;
+ }
+};
+
+__forceinline BoundBox merge(const BoundBox &bbox, const float3 &pt)
+{
+ return BoundBox(min(bbox.min, pt), max(bbox.max, pt));
+}
+
+__forceinline BoundBox merge(const BoundBox &a, const BoundBox &b)
+{
+ return BoundBox(min(a.min, b.min), max(a.max, b.max));
+}
+
+__forceinline BoundBox merge(const BoundBox &a,
+ const BoundBox &b,
+ const BoundBox &c,
+ const BoundBox &d)
+{
+ return merge(merge(a, b), merge(c, d));
+}
+
+__forceinline BoundBox intersect(const BoundBox &a, const BoundBox &b)
+{
+ return BoundBox(max(a.min, b.min), min(a.max, b.max));
+}
+
+__forceinline BoundBox intersect(const BoundBox &a, const BoundBox &b, const BoundBox &c)
+{
+ return intersect(a, intersect(b, c));
+}
+
+/* 2D BoundBox */
+
+class BoundBox2D {
+ public:
+ float left;
+ float right;
+ float bottom;
+ float top;
+
+ BoundBox2D() : left(0.0f), right(1.0f), bottom(0.0f), top(1.0f)
+ {
+ }
+
+ bool operator==(const BoundBox2D &other) const
+ {
+ return (left == other.left && right == other.right && bottom == other.bottom &&
+ top == other.top);
+ }
+
+ float width()
+ {
+ return right - left;
+ }
+
+ float height()
+ {
+ return top - bottom;
+ }
+
+ BoundBox2D operator*(float f) const
+ {
+ BoundBox2D result;
+
+ result.left = left * f;
+ result.right = right * f;
+ result.bottom = bottom * f;
+ result.top = top * f;
+
+ return result;
+ }
+
+ BoundBox2D subset(const BoundBox2D &other) const
+ {
+ BoundBox2D subset;
+
+ subset.left = left + other.left * (right - left);
+ subset.right = left + other.right * (right - left);
+ subset.bottom = bottom + other.bottom * (top - bottom);
+ subset.top = bottom + other.top * (top - bottom);
+
+ return subset;
+ }
+
+ BoundBox2D make_relative_to(const BoundBox2D &other) const
+ {
+ BoundBox2D result;
+
+ result.left = ((left - other.left) / (other.right - other.left));
+ result.right = ((right - other.left) / (other.right - other.left));
+ result.bottom = ((bottom - other.bottom) / (other.top - other.bottom));
+ result.top = ((top - other.bottom) / (other.top - other.bottom));
+
+ return result;
+ }
+
+ BoundBox2D clamp(float mn = 0.0f, float mx = 1.0f)
+ {
+ BoundBox2D result;
+
+ result.left = ccl::clamp(left, mn, mx);
+ result.right = ccl::clamp(right, mn, mx);
+ result.bottom = ccl::clamp(bottom, mn, mx);
+ result.top = ccl::clamp(top, mn, mx);
+
+ return result;
+ }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_BOUNDBOX_H__ */
diff --git a/intern/cycles/util/color.h b/intern/cycles/util/color.h
new file mode 100644
index 00000000000..e2a5c5b9c4a
--- /dev/null
+++ b/intern/cycles/util/color.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_COLOR_H__
+#define __UTIL_COLOR_H__
+
+#include "util/math.h"
+#include "util/types.h"
+
+#if !defined(__KERNEL_GPU__) && defined(__KERNEL_SSE2__)
+# include "util/simd.h"
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device uchar float_to_byte(float val)
+{
+ return ((val <= 0.0f) ? 0 :
+ ((val > (1.0f - 0.5f / 255.0f)) ? 255 : (uchar)((255.0f * val) + 0.5f)));
+}
+
+ccl_device uchar4 color_float_to_byte(float3 c)
+{
+ uchar r, g, b;
+
+ r = float_to_byte(c.x);
+ g = float_to_byte(c.y);
+ b = float_to_byte(c.z);
+
+ return make_uchar4(r, g, b, 0);
+}
+
+ccl_device uchar4 color_float4_to_uchar4(float4 c)
+{
+ uchar r, g, b, a;
+
+ r = float_to_byte(c.x);
+ g = float_to_byte(c.y);
+ b = float_to_byte(c.z);
+ a = float_to_byte(c.w);
+
+ return make_uchar4(r, g, b, a);
+}
+
+ccl_device_inline float3 color_byte_to_float(uchar4 c)
+{
+ return make_float3(c.x * (1.0f / 255.0f), c.y * (1.0f / 255.0f), c.z * (1.0f / 255.0f));
+}
+
+ccl_device_inline float4 color_uchar4_to_float4(uchar4 c)
+{
+ return make_float4(
+ c.x * (1.0f / 255.0f), c.y * (1.0f / 255.0f), c.z * (1.0f / 255.0f), c.w * (1.0f / 255.0f));
+}
+
+ccl_device float color_srgb_to_linear(float c)
+{
+ if (c < 0.04045f)
+ return (c < 0.0f) ? 0.0f : c * (1.0f / 12.92f);
+ else
+ return powf((c + 0.055f) * (1.0f / 1.055f), 2.4f);
+}
+
+ccl_device float color_linear_to_srgb(float c)
+{
+ if (c < 0.0031308f)
+ return (c < 0.0f) ? 0.0f : c * 12.92f;
+ else
+ return 1.055f * powf(c, 1.0f / 2.4f) - 0.055f;
+}
+
+ccl_device float3 rgb_to_hsv(float3 rgb)
+{
+ float cmax, cmin, h, s, v, cdelta;
+ float3 c;
+
+ cmax = fmaxf(rgb.x, fmaxf(rgb.y, rgb.z));
+ cmin = min(rgb.x, min(rgb.y, rgb.z));
+ cdelta = cmax - cmin;
+
+ v = cmax;
+
+ if (cmax != 0.0f) {
+ s = cdelta / cmax;
+ }
+ else {
+ s = 0.0f;
+ h = 0.0f;
+ }
+
+ if (s != 0.0f) {
+ float3 cmax3 = make_float3(cmax, cmax, cmax);
+ c = (cmax3 - rgb) / cdelta;
+
+ if (rgb.x == cmax)
+ h = c.z - c.y;
+ else if (rgb.y == cmax)
+ h = 2.0f + c.x - c.z;
+ else
+ h = 4.0f + c.y - c.x;
+
+ h /= 6.0f;
+
+ if (h < 0.0f)
+ h += 1.0f;
+ }
+ else {
+ h = 0.0f;
+ }
+
+ return make_float3(h, s, v);
+}
+
+ccl_device float3 hsv_to_rgb(float3 hsv)
+{
+ float i, f, p, q, t, h, s, v;
+ float3 rgb;
+
+ h = hsv.x;
+ s = hsv.y;
+ v = hsv.z;
+
+ if (s != 0.0f) {
+ if (h == 1.0f)
+ h = 0.0f;
+
+ h *= 6.0f;
+ i = floorf(h);
+ f = h - i;
+ rgb = make_float3(f, f, f);
+ p = v * (1.0f - s);
+ q = v * (1.0f - (s * f));
+ t = v * (1.0f - (s * (1.0f - f)));
+
+ if (i == 0.0f)
+ rgb = make_float3(v, t, p);
+ else if (i == 1.0f)
+ rgb = make_float3(q, v, p);
+ else if (i == 2.0f)
+ rgb = make_float3(p, v, t);
+ else if (i == 3.0f)
+ rgb = make_float3(p, q, v);
+ else if (i == 4.0f)
+ rgb = make_float3(t, p, v);
+ else
+ rgb = make_float3(v, p, q);
+ }
+ else {
+ rgb = make_float3(v, v, v);
+ }
+
+ return rgb;
+}
+
+ccl_device float3 xyY_to_xyz(float x, float y, float Y)
+{
+ float X, Z;
+
+ if (y != 0.0f)
+ X = (x / y) * Y;
+ else
+ X = 0.0f;
+
+ if (y != 0.0f && Y != 0.0f)
+ Z = (1.0f - x - y) / y * Y;
+ else
+ Z = 0.0f;
+
+ return make_float3(X, Y, Z);
+}
+
+#ifdef __KERNEL_SSE2__
+/*
+ * Calculate initial guess for arg^exp based on float representation
+ * This method gives a constant bias,
+ * which can be easily compensated by multiplication with bias_coeff.
+ * Gives better results for exponents near 1 (e. g. 4/5).
+ * exp = exponent, encoded as uint32_t
+ * e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent), encoded as uint32_t
+ */
+template<unsigned exp, unsigned e2coeff> ccl_device_inline ssef fastpow(const ssef &arg)
+{
+ ssef ret;
+ ret = arg * cast(ssei(e2coeff));
+ ret = ssef(cast(ret));
+ ret = ret * cast(ssei(exp));
+ ret = cast(ssei(ret));
+ return ret;
+}
+
+/* Improve x ^ 1.0f/5.0f solution with Newton-Raphson method */
+ccl_device_inline ssef improve_5throot_solution(const ssef &old_result, const ssef &x)
+{
+ ssef approx2 = old_result * old_result;
+ ssef approx4 = approx2 * approx2;
+ ssef t = x / approx4;
+ ssef summ = madd(ssef(4.0f), old_result, t);
+ return summ * ssef(1.0f / 5.0f);
+}
+
+/* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */
+ccl_device_inline ssef fastpow24(const ssef &arg)
+{
+ /* max, avg and |avg| errors were calculated in gcc without FMA instructions
+ * The final precision should be better than powf in glibc */
+
+ /* Calculate x^4/5, coefficient 0.994 was constructed manually to minimize avg error */
+ /* 0x3F4CCCCD = 4/5 */
+ /* 0x4F55A7FB = 2^(127/(4/5) - 127) * 0.994^(1/(4/5)) */
+ ssef x = fastpow<0x3F4CCCCD, 0x4F55A7FB>(arg); // error max = 0.17 avg = 0.0018 |avg| = 0.05
+ ssef arg2 = arg * arg;
+ ssef arg4 = arg2 * arg2;
+
+ /* error max = 0.018 avg = 0.0031 |avg| = 0.0031 */
+ x = improve_5throot_solution(x, arg4);
+ /* error max = 0.00021 avg = 1.6e-05 |avg| = 1.6e-05 */
+ x = improve_5throot_solution(x, arg4);
+ /* error max = 6.1e-07 avg = 5.2e-08 |avg| = 1.1e-07 */
+ x = improve_5throot_solution(x, arg4);
+
+ return x * (x * x);
+}
+
+ccl_device ssef color_srgb_to_linear(const ssef &c)
+{
+ sseb cmp = c < ssef(0.04045f);
+ ssef lt = max(c * ssef(1.0f / 12.92f), ssef(0.0f));
+ ssef gtebase = (c + ssef(0.055f)) * ssef(1.0f / 1.055f); /* fma */
+ ssef gte = fastpow24(gtebase);
+ return select(cmp, lt, gte);
+}
+#endif /* __KERNEL_SSE2__ */
+
+ccl_device float3 color_srgb_to_linear_v3(float3 c)
+{
+ return make_float3(
+ color_srgb_to_linear(c.x), color_srgb_to_linear(c.y), color_srgb_to_linear(c.z));
+}
+
+ccl_device float3 color_linear_to_srgb_v3(float3 c)
+{
+ return make_float3(
+ color_linear_to_srgb(c.x), color_linear_to_srgb(c.y), color_linear_to_srgb(c.z));
+}
+
+ccl_device float4 color_linear_to_srgb_v4(float4 c)
+{
+ return make_float4(
+ color_linear_to_srgb(c.x), color_linear_to_srgb(c.y), color_linear_to_srgb(c.z), c.w);
+}
+
+ccl_device float4 color_srgb_to_linear_v4(float4 c)
+{
+#ifdef __KERNEL_SSE2__
+ ssef r_ssef;
+ float4 &r = (float4 &)r_ssef;
+ r = c;
+ r_ssef = color_srgb_to_linear(r_ssef);
+ r.w = c.w;
+ return r;
+#else
+ return make_float4(
+ color_srgb_to_linear(c.x), color_srgb_to_linear(c.y), color_srgb_to_linear(c.z), c.w);
+#endif
+}
+
+ccl_device float3 color_highlight_compress(float3 color, ccl_private float3 *variance)
+{
+ color += one_float3();
+ if (variance) {
+ *variance *= sqr3(one_float3() / color);
+ }
+ return log3(color);
+}
+
+ccl_device float3 color_highlight_uncompress(float3 color)
+{
+ return exp3(color) - one_float3();
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_COLOR_H__ */
diff --git a/intern/cycles/util/debug.cpp b/intern/cycles/util/debug.cpp
new file mode 100644
index 00000000000..b49df3d42bc
--- /dev/null
+++ b/intern/cycles/util/debug.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/debug.h"
+
+#include <stdlib.h>
+
+#include "bvh/params.h"
+
+#include "util/log.h"
+#include "util/string.h"
+
+CCL_NAMESPACE_BEGIN
+
+DebugFlags::CPU::CPU()
+ : avx2(true), avx(true), sse41(true), sse3(true), sse2(true), bvh_layout(BVH_LAYOUT_AUTO)
+{
+ reset();
+}
+
+void DebugFlags::CPU::reset()
+{
+#define STRINGIFY(x) #x
+#define CHECK_CPU_FLAGS(flag, env) \
+ do { \
+ flag = (getenv(env) == NULL); \
+ if (!flag) { \
+ VLOG(1) << "Disabling " << STRINGIFY(flag) << " instruction set."; \
+ } \
+ } while (0)
+
+ CHECK_CPU_FLAGS(avx2, "CYCLES_CPU_NO_AVX2");
+ CHECK_CPU_FLAGS(avx, "CYCLES_CPU_NO_AVX");
+ CHECK_CPU_FLAGS(sse41, "CYCLES_CPU_NO_SSE41");
+ CHECK_CPU_FLAGS(sse3, "CYCLES_CPU_NO_SSE3");
+ CHECK_CPU_FLAGS(sse2, "CYCLES_CPU_NO_SSE2");
+
+#undef STRINGIFY
+#undef CHECK_CPU_FLAGS
+
+ bvh_layout = BVH_LAYOUT_AUTO;
+}
+
+DebugFlags::CUDA::CUDA() : adaptive_compile(false)
+{
+ reset();
+}
+
+DebugFlags::HIP::HIP() : adaptive_compile(false)
+{
+ reset();
+}
+
+void DebugFlags::CUDA::reset()
+{
+ if (getenv("CYCLES_CUDA_ADAPTIVE_COMPILE") != NULL)
+ adaptive_compile = true;
+}
+
+void DebugFlags::HIP::reset()
+{
+ if (getenv("CYCLES_HIP_ADAPTIVE_COMPILE") != NULL)
+ adaptive_compile = true;
+}
+
+DebugFlags::OptiX::OptiX()
+{
+ reset();
+}
+
+void DebugFlags::OptiX::reset()
+{
+ use_debug = false;
+}
+
+DebugFlags::DebugFlags() : viewport_static_bvh(false), running_inside_blender(false)
+{
+ /* Nothing for now. */
+}
+
+void DebugFlags::reset()
+{
+ viewport_static_bvh = false;
+ cpu.reset();
+ cuda.reset();
+ optix.reset();
+}
+
+std::ostream &operator<<(std::ostream &os, DebugFlagsConstRef debug_flags)
+{
+ os << "CPU flags:\n"
+ << " AVX2 : " << string_from_bool(debug_flags.cpu.avx2) << "\n"
+ << " AVX : " << string_from_bool(debug_flags.cpu.avx) << "\n"
+ << " SSE4.1 : " << string_from_bool(debug_flags.cpu.sse41) << "\n"
+ << " SSE3 : " << string_from_bool(debug_flags.cpu.sse3) << "\n"
+ << " SSE2 : " << string_from_bool(debug_flags.cpu.sse2) << "\n"
+ << " BVH layout : " << bvh_layout_name(debug_flags.cpu.bvh_layout) << "\n";
+
+ os << "CUDA flags:\n"
+ << " Adaptive Compile : " << string_from_bool(debug_flags.cuda.adaptive_compile) << "\n";
+
+ os << "OptiX flags:\n"
+ << " Debug : " << string_from_bool(debug_flags.optix.use_debug) << "\n";
+
+ os << "HIP flags:\n"
+ << " HIP streams : " << string_from_bool(debug_flags.hip.adaptive_compile) << "\n";
+
+ return os;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/debug.h b/intern/cycles/util/debug.h
new file mode 100644
index 00000000000..58b2b047261
--- /dev/null
+++ b/intern/cycles/util/debug.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_DEBUG_H__
+#define __UTIL_DEBUG_H__
+
+#include <cassert>
+#include <iostream>
+
+#include "bvh/params.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Global storage for all sort of flags used to fine-tune behavior of particular
+ * areas for the development purposes, without officially exposing settings to
+ * the interface.
+ */
+class DebugFlags {
+ public:
+ /* Use static BVH in viewport, to match final render exactly. */
+ bool viewport_static_bvh;
+
+ bool running_inside_blender;
+
+ /* Descriptor of CPU feature-set to be used. */
+ struct CPU {
+ CPU();
+
+ /* Reset flags to their defaults. */
+ void reset();
+
+ /* Flags describing which instructions sets are allowed for use. */
+ bool avx2;
+ bool avx;
+ bool sse41;
+ bool sse3;
+ bool sse2;
+
+ /* Check functions to see whether instructions up to the given one
+ * are allowed for use.
+ */
+ bool has_avx2()
+ {
+ return has_avx() && avx2;
+ }
+ bool has_avx()
+ {
+ return has_sse41() && avx;
+ }
+ bool has_sse41()
+ {
+ return has_sse3() && sse41;
+ }
+ bool has_sse3()
+ {
+ return has_sse2() && sse3;
+ }
+ bool has_sse2()
+ {
+ return sse2;
+ }
+
+ /* Requested BVH layout.
+ *
+ * By default the fastest will be used. For debugging the BVH used by other
+ * CPUs and GPUs can be selected here instead.
+ */
+ BVHLayout bvh_layout;
+ };
+
+ /* Descriptor of CUDA feature-set to be used. */
+ struct CUDA {
+ CUDA();
+
+ /* Reset flags to their defaults. */
+ void reset();
+
+ /* Whether adaptive feature based runtime compile is enabled or not.
+ * Requires the CUDA Toolkit and only works on Linux at the moment. */
+ bool adaptive_compile;
+ };
+
+ /* Descriptor of HIP feature-set to be used. */
+ struct HIP {
+ HIP();
+
+ /* Reset flags to their defaults. */
+ void reset();
+
+ /* Whether adaptive feature based runtime compile is enabled or not.*/
+ bool adaptive_compile;
+ };
+
+ /* Descriptor of OptiX feature-set to be used. */
+ struct OptiX {
+ OptiX();
+
+ /* Reset flags to their defaults. */
+ void reset();
+
+ /* Load OptiX module with debug capabilities. Will lower logging verbosity level, enable
+ * validations, and lower optimization level. */
+ bool use_debug;
+ };
+
+ /* Get instance of debug flags registry. */
+ static DebugFlags &get()
+ {
+ static DebugFlags instance;
+ return instance;
+ }
+
+ /* Reset flags to their defaults. */
+ void reset();
+
+ /* Requested CPU flags. */
+ CPU cpu;
+
+ /* Requested CUDA flags. */
+ CUDA cuda;
+
+ /* Requested OptiX flags. */
+ OptiX optix;
+
+ /* Requested HIP flags. */
+ HIP hip;
+
+ private:
+ DebugFlags();
+
+#if (__cplusplus > 199711L)
+ public:
+ explicit DebugFlags(DebugFlags const & /*other*/) = delete;
+ void operator=(DebugFlags const & /*other*/) = delete;
+#else
+ private:
+ explicit DebugFlags(DebugFlags const & /*other*/);
+ void operator=(DebugFlags const & /*other*/);
+#endif
+};
+
+typedef DebugFlags &DebugFlagsRef;
+typedef const DebugFlags &DebugFlagsConstRef;
+
+inline DebugFlags &DebugFlags()
+{
+ return DebugFlags::get();
+}
+
+std::ostream &operator<<(std::ostream &os, DebugFlagsConstRef debug_flags);
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_DEBUG_H__ */
diff --git a/intern/cycles/util/defines.h b/intern/cycles/util/defines.h
new file mode 100644
index 00000000000..a778bef52b2
--- /dev/null
+++ b/intern/cycles/util/defines.h
@@ -0,0 +1,151 @@
+
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* clang-format off */
+
+/* #define __forceinline triggers a bug in some clang-format versions, disable
+ * format for entire file to keep results consistent. */
+
+#ifndef __UTIL_DEFINES_H__
+#define __UTIL_DEFINES_H__
+
+/* Bitness */
+
+#if defined(__ppc64__) || defined(__PPC64__) || defined(__x86_64__) || defined(__ia64__) || \
+ defined(_M_X64) || defined(__aarch64__)
+# define __KERNEL_64_BIT__
+#endif
+
+/* Qualifiers for kernel code shared by CPU and GPU */
+
+#ifndef __KERNEL_GPU__
+
+/* Leave inlining decisions to compiler for these, the inline keyword here
+ * is not about performance but including function definitions in headers. */
+# define ccl_device static inline
+# define ccl_device_noinline static inline
+# define ccl_device_noinline_cpu ccl_device_noinline
+
+/* Forced inlining. */
+# if defined(_WIN32) && !defined(FREE_WINDOWS)
+# define ccl_device_inline static __forceinline
+# define ccl_device_forceinline static __forceinline
+# define ccl_align(...) __declspec(align(__VA_ARGS__))
+# ifdef __KERNEL_64_BIT__
+# define ccl_try_align(...) __declspec(align(__VA_ARGS__))
+# else /* __KERNEL_64_BIT__ */
+# undef __KERNEL_WITH_SSE_ALIGN__
+/* No support for function arguments (error C2719). */
+# define ccl_try_align(...)
+# endif /* __KERNEL_64_BIT__ */
+# define ccl_may_alias
+# define ccl_always_inline __forceinline
+# define ccl_never_inline __declspec(noinline)
+# else /* _WIN32 && !FREE_WINDOWS */
+# define ccl_device_inline static inline __attribute__((always_inline))
+# define ccl_device_forceinline static inline __attribute__((always_inline))
+# define ccl_align(...) __attribute__((aligned(__VA_ARGS__)))
+# ifndef FREE_WINDOWS64
+# define __forceinline inline __attribute__((always_inline))
+# endif
+# define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__)))
+# define ccl_may_alias __attribute__((__may_alias__))
+# define ccl_always_inline __attribute__((always_inline))
+# define ccl_never_inline __attribute__((noinline))
+# endif /* _WIN32 && !FREE_WINDOWS */
+
+/* Address spaces for GPU. */
+# define ccl_global
+# define ccl_static_constant static const
+# define ccl_constant const
+# define ccl_private
+
+# define ccl_restrict __restrict
+# define ccl_optional_struct_init
+# define ccl_loop_no_unroll
+# define ccl_attr_maybe_unused [[maybe_unused]]
+# define __KERNEL_WITH_SSE_ALIGN__
+
+/* Use to suppress '-Wimplicit-fallthrough' (in place of 'break'). */
+# ifndef ATTR_FALLTHROUGH
+# if defined(__GNUC__) && (__GNUC__ >= 7) /* gcc7.0+ only */
+# define ATTR_FALLTHROUGH __attribute__((fallthrough))
+# else
+# define ATTR_FALLTHROUGH ((void)0)
+# endif
+# endif
+#endif /* __KERNEL_GPU__ */
+
+/* macros */
+
+/* hints for branch prediction, only use in code that runs a _lot_ */
+#if defined(__GNUC__) && defined(__KERNEL_CPU__)
+# define LIKELY(x) __builtin_expect(!!(x), 1)
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+# define LIKELY(x) (x)
+# define UNLIKELY(x) (x)
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+# if defined(__cplusplus)
+/* Some magic to be sure we don't have reference in the type. */
+template<typename T> static inline T decltype_helper(T x)
+{
+ return x;
+}
+# define TYPEOF(x) decltype(decltype_helper(x))
+# else
+# define TYPEOF(x) typeof(x)
+# endif
+#endif
+
+/* Causes warning:
+ * incompatible types when assigning to type 'Foo' from type 'Bar'
+ * ... the compiler optimizes away the temp var */
+#ifdef __GNUC__
+# define CHECK_TYPE(var, type) \
+ { \
+ TYPEOF(var) * __tmp; \
+ __tmp = (type *)NULL; \
+ (void)__tmp; \
+ } \
+ (void)0
+
+# define CHECK_TYPE_PAIR(var_a, var_b) \
+ { \
+ TYPEOF(var_a) * __tmp; \
+ __tmp = (typeof(var_b) *)NULL; \
+ (void)__tmp; \
+ } \
+ (void)0
+#else
+# define CHECK_TYPE(var, type)
+# define CHECK_TYPE_PAIR(var_a, var_b)
+#endif
+
+/* can be used in simple macros */
+#define CHECK_TYPE_INLINE(val, type) ((void)(((type)0) != (val)))
+
+#ifndef __KERNEL_GPU__
+# include <cassert>
+# define util_assert(statement) assert(statement)
+#else
+# define util_assert(statement)
+#endif
+
+#endif /* __UTIL_DEFINES_H__ */
diff --git a/intern/cycles/util/util_deque.h b/intern/cycles/util/deque.h
index ccac961aa7d..ccac961aa7d 100644
--- a/intern/cycles/util/util_deque.h
+++ b/intern/cycles/util/deque.h
diff --git a/intern/cycles/util/disjoint_set.h b/intern/cycles/util/disjoint_set.h
new file mode 100644
index 00000000000..5226423d7cd
--- /dev/null
+++ b/intern/cycles/util/disjoint_set.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_DISJOINT_SET_H__
+#define __UTIL_DISJOINT_SET_H__
+
+#include "util/array.h"
+#include <utility>
+
+CCL_NAMESPACE_BEGIN
+
+class DisjointSet {
+ private:
+ array<size_t> parents;
+ array<size_t> ranks;
+
+ public:
+ DisjointSet(size_t size) : parents(size), ranks(size)
+ {
+ for (size_t i = 0; i < size; i++) {
+ parents[i] = i;
+ ranks[i] = 0;
+ }
+ }
+
+ size_t find(size_t x)
+ {
+ size_t root = x;
+ while (parents[root] != root) {
+ root = parents[root];
+ }
+ while (parents[x] != root) {
+ size_t parent = parents[x];
+ parents[x] = root;
+ x = parent;
+ }
+ return root;
+ }
+
+ void join(size_t x, size_t y)
+ {
+ size_t x_root = find(x);
+ size_t y_root = find(y);
+
+ if (x_root == y_root) {
+ return;
+ }
+
+ if (ranks[x_root] < ranks[y_root]) {
+ std::swap(x_root, y_root);
+ }
+ parents[y_root] = x_root;
+
+ if (ranks[x_root] == ranks[y_root]) {
+ ranks[x_root]++;
+ }
+ }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_DISJOINT_SET_H__ */
diff --git a/intern/cycles/util/util_foreach.h b/intern/cycles/util/foreach.h
index d907974be91..d907974be91 100644
--- a/intern/cycles/util/util_foreach.h
+++ b/intern/cycles/util/foreach.h
diff --git a/intern/cycles/util/util_function.h b/intern/cycles/util/function.h
index f3cc00329ad..f3cc00329ad 100644
--- a/intern/cycles/util/util_function.h
+++ b/intern/cycles/util/function.h
diff --git a/intern/cycles/util/guarded_allocator.cpp b/intern/cycles/util/guarded_allocator.cpp
new file mode 100644
index 00000000000..4063b301331
--- /dev/null
+++ b/intern/cycles/util/guarded_allocator.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/guarded_allocator.h"
+#include "util/stats.h"
+
+CCL_NAMESPACE_BEGIN
+
+static Stats global_stats(Stats::static_init);
+
+/* Internal API. */
+
+void util_guarded_mem_alloc(size_t n)
+{
+ global_stats.mem_alloc(n);
+}
+
+void util_guarded_mem_free(size_t n)
+{
+ global_stats.mem_free(n);
+}
+
+/* Public API. */
+
+size_t util_guarded_get_mem_used()
+{
+ return global_stats.mem_used;
+}
+
+size_t util_guarded_get_mem_peak()
+{
+ return global_stats.mem_peak;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_guarded_allocator.h b/intern/cycles/util/guarded_allocator.h
index f78cc5f5da9..f78cc5f5da9 100644
--- a/intern/cycles/util/util_guarded_allocator.h
+++ b/intern/cycles/util/guarded_allocator.h
diff --git a/intern/cycles/util/half.h b/intern/cycles/util/half.h
new file mode 100644
index 00000000000..016975e3c25
--- /dev/null
+++ b/intern/cycles/util/half.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_HALF_H__
+#define __UTIL_HALF_H__
+
+#include "util/math.h"
+#include "util/types.h"
+
+#if !defined(__KERNEL_GPU__) && defined(__KERNEL_SSE2__)
+# include "util/simd.h"
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* Half Floats */
+
+/* CUDA has its own half data type, no need to define then */
+#if !defined(__KERNEL_CUDA__) && !defined(__KERNEL_HIP__)
+/* Implementing this as a class rather than a typedef so that the compiler can tell it apart from
+ * unsigned shorts. */
+class half {
+ public:
+ half() : v(0)
+ {
+ }
+ half(const unsigned short &i) : v(i)
+ {
+ }
+ operator unsigned short()
+ {
+ return v;
+ }
+ half &operator=(const unsigned short &i)
+ {
+ v = i;
+ return *this;
+ }
+
+ private:
+ unsigned short v;
+};
+#endif
+
+struct half4 {
+ half x, y, z, w;
+};
+
+/* Conversion to/from half float for image textures
+ *
+ * Simplified float to half for fast sampling on processor without a native
+ * instruction, and eliminating any NaN and inf values. */
+
+ccl_device_inline half float_to_half_image(float f)
+{
+#if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
+ return __float2half(f);
+#else
+ const uint u = __float_as_uint(f);
+ /* Sign bit, shifted to its position. */
+ uint sign_bit = u & 0x80000000;
+ sign_bit >>= 16;
+ /* Exponent. */
+ uint exponent_bits = u & 0x7f800000;
+ /* Non-sign bits. */
+ uint value_bits = u & 0x7fffffff;
+ value_bits >>= 13; /* Align mantissa on MSB. */
+ value_bits -= 0x1c000; /* Adjust bias. */
+ /* Flush-to-zero. */
+ value_bits = (exponent_bits < 0x38800000) ? 0 : value_bits;
+ /* Clamp-to-max. */
+ value_bits = (exponent_bits > 0x47000000) ? 0x7bff : value_bits;
+ /* Denormals-as-zero. */
+ value_bits = (exponent_bits == 0 ? 0 : value_bits);
+ /* Re-insert sign bit and return. */
+ return (value_bits | sign_bit);
+#endif
+}
+
+ccl_device_inline float half_to_float_image(half h)
+{
+#if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
+ return __half2float(h);
+#else
+ const int x = ((h & 0x8000) << 16) | (((h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13);
+ return __int_as_float(x);
+#endif
+}
+
+ccl_device_inline float4 half4_to_float4_image(const half4 h)
+{
+ /* Unable to use because it gives different results half_to_float_image, can we
+ * modify float_to_half_image so the conversion results are identical? */
+#if 0 /* defined(__KERNEL_AVX2__) */
+ /* CPU: AVX. */
+ __m128i x = _mm_castpd_si128(_mm_load_sd((const double *)&h));
+ return float4(_mm_cvtph_ps(x));
+#endif
+
+ const float4 f = make_float4(half_to_float_image(h.x),
+ half_to_float_image(h.y),
+ half_to_float_image(h.z),
+ half_to_float_image(h.w));
+ return f;
+}
+
+/* Conversion to half float texture for display.
+ *
+ * Simplified float to half for fast display texture conversion on processors
+ * without a native instruction. Assumes no negative, no NaN, no inf, and sets
+ * denormal to 0. */
+
+ccl_device_inline half float_to_half_display(const float f)
+{
+#if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
+ return __float2half(f);
+#else
+ const int x = __float_as_int((f > 0.0f) ? ((f < 65504.0f) ? f : 65504.0f) : 0.0f);
+ const int absolute = x & 0x7FFFFFFF;
+ const int Z = absolute + 0xC8000000;
+ const int result = (absolute < 0x38800000) ? 0 : Z;
+ const int rshift = (result >> 13);
+ return (rshift & 0x7FFF);
+#endif
+}
+
+ccl_device_inline half4 float4_to_half4_display(const float4 f)
+{
+#ifdef __KERNEL_SSE2__
+ /* CPU: SSE and AVX. */
+ ssef x = min(max(load4f(f), 0.0f), 65504.0f);
+# ifdef __KERNEL_AVX2__
+ ssei rpack = _mm_cvtps_ph(x, 0);
+# else
+ ssei absolute = cast(x) & 0x7FFFFFFF;
+ ssei Z = absolute + 0xC8000000;
+ ssei result = andnot(absolute < 0x38800000, Z);
+ ssei rshift = (result >> 13) & 0x7FFF;
+ ssei rpack = _mm_packs_epi32(rshift, rshift);
+# endif
+ half4 h;
+ _mm_storel_pi((__m64 *)&h, _mm_castsi128_ps(rpack));
+ return h;
+#else
+ /* GPU and scalar fallback. */
+ const half4 h = {float_to_half_display(f.x),
+ float_to_half_display(f.y),
+ float_to_half_display(f.z),
+ float_to_half_display(f.w)};
+ return h;
+#endif
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_HALF_H__ */
diff --git a/intern/cycles/util/hash.h b/intern/cycles/util/hash.h
new file mode 100644
index 00000000000..013a0f90a27
--- /dev/null
+++ b/intern/cycles/util/hash.h
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_HASH_H__
+#define __UTIL_HASH_H__
+
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* ***** Jenkins Lookup3 Hash Functions ***** */
+
+/* Source: http://burtleburtle.net/bob/c/lookup3.c */
+
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+
+#define mix(a, b, c) \
+ { \
+ a -= c; \
+ a ^= rot(c, 4); \
+ c += b; \
+ b -= a; \
+ b ^= rot(a, 6); \
+ a += c; \
+ c -= b; \
+ c ^= rot(b, 8); \
+ b += a; \
+ a -= c; \
+ a ^= rot(c, 16); \
+ c += b; \
+ b -= a; \
+ b ^= rot(a, 19); \
+ a += c; \
+ c -= b; \
+ c ^= rot(b, 4); \
+ b += a; \
+ } \
+ ((void)0)
+
+#define final(a, b, c) \
+ { \
+ c ^= b; \
+ c -= rot(b, 14); \
+ a ^= c; \
+ a -= rot(c, 11); \
+ b ^= a; \
+ b -= rot(a, 25); \
+ c ^= b; \
+ c -= rot(b, 16); \
+ a ^= c; \
+ a -= rot(c, 4); \
+ b ^= a; \
+ b -= rot(a, 14); \
+ c ^= b; \
+ c -= rot(b, 24); \
+ } \
+ ((void)0)
+
+ccl_device_inline uint hash_uint(uint kx)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeef + (1 << 2) + 13;
+
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline uint hash_uint2(uint kx, uint ky)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeef + (2 << 2) + 13;
+
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline uint hash_uint3(uint kx, uint ky, uint kz)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeef + (3 << 2) + 13;
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline uint hash_uint4(uint kx, uint ky, uint kz, uint kw)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeef + (4 << 2) + 13;
+
+ a += kx;
+ b += ky;
+ c += kz;
+ mix(a, b, c);
+
+ a += kw;
+ final(a, b, c);
+
+ return c;
+}
+
+#undef rot
+#undef final
+#undef mix
+
+/* Hashing uint or uint[234] into a float in the range [0, 1]. */
+
+ccl_device_inline float hash_uint_to_float(uint kx)
+{
+ return (float)hash_uint(kx) / (float)0xFFFFFFFFu;
+}
+
+ccl_device_inline float hash_uint2_to_float(uint kx, uint ky)
+{
+ return (float)hash_uint2(kx, ky) / (float)0xFFFFFFFFu;
+}
+
+ccl_device_inline float hash_uint3_to_float(uint kx, uint ky, uint kz)
+{
+ return (float)hash_uint3(kx, ky, kz) / (float)0xFFFFFFFFu;
+}
+
+ccl_device_inline float hash_uint4_to_float(uint kx, uint ky, uint kz, uint kw)
+{
+ return (float)hash_uint4(kx, ky, kz, kw) / (float)0xFFFFFFFFu;
+}
+
+/* Hashing float or float[234] into a float in the range [0, 1]. */
+
+ccl_device_inline float hash_float_to_float(float k)
+{
+ return hash_uint_to_float(__float_as_uint(k));
+}
+
+ccl_device_inline float hash_float2_to_float(float2 k)
+{
+ return hash_uint2_to_float(__float_as_uint(k.x), __float_as_uint(k.y));
+}
+
+ccl_device_inline float hash_float3_to_float(float3 k)
+{
+ return hash_uint3_to_float(__float_as_uint(k.x), __float_as_uint(k.y), __float_as_uint(k.z));
+}
+
+ccl_device_inline float hash_float4_to_float(float4 k)
+{
+ return hash_uint4_to_float(
+ __float_as_uint(k.x), __float_as_uint(k.y), __float_as_uint(k.z), __float_as_uint(k.w));
+}
+
+/* Hashing float[234] into float[234] of components in the range [0, 1]. */
+
+ccl_device_inline float2 hash_float2_to_float2(float2 k)
+{
+ return make_float2(hash_float2_to_float(k), hash_float3_to_float(make_float3(k.x, k.y, 1.0)));
+}
+
+ccl_device_inline float3 hash_float3_to_float3(float3 k)
+{
+ return make_float3(hash_float3_to_float(k),
+ hash_float4_to_float(make_float4(k.x, k.y, k.z, 1.0)),
+ hash_float4_to_float(make_float4(k.x, k.y, k.z, 2.0)));
+}
+
+ccl_device_inline float4 hash_float4_to_float4(float4 k)
+{
+ return make_float4(hash_float4_to_float(k),
+ hash_float4_to_float(make_float4(k.w, k.x, k.y, k.z)),
+ hash_float4_to_float(make_float4(k.z, k.w, k.x, k.y)),
+ hash_float4_to_float(make_float4(k.y, k.z, k.w, k.x)));
+}
+
+/* Hashing float or float[234] into float3 of components in range [0, 1]. */
+
+ccl_device_inline float3 hash_float_to_float3(float k)
+{
+ return make_float3(hash_float_to_float(k),
+ hash_float2_to_float(make_float2(k, 1.0)),
+ hash_float2_to_float(make_float2(k, 2.0)));
+}
+
+ccl_device_inline float3 hash_float2_to_float3(float2 k)
+{
+ return make_float3(hash_float2_to_float(k),
+ hash_float3_to_float(make_float3(k.x, k.y, 1.0)),
+ hash_float3_to_float(make_float3(k.x, k.y, 2.0)));
+}
+
+ccl_device_inline float3 hash_float4_to_float3(float4 k)
+{
+ return make_float3(hash_float4_to_float(k),
+ hash_float4_to_float(make_float4(k.z, k.x, k.w, k.y)),
+ hash_float4_to_float(make_float4(k.w, k.z, k.y, k.x)));
+}
+
+/* SSE Versions Of Jenkins Lookup3 Hash Functions */
+
+#ifdef __KERNEL_SSE2__
+# define rot(x, k) (((x) << (k)) | (srl(x, 32 - (k))))
+
+# define mix(a, b, c) \
+ { \
+ a -= c; \
+ a ^= rot(c, 4); \
+ c += b; \
+ b -= a; \
+ b ^= rot(a, 6); \
+ a += c; \
+ c -= b; \
+ c ^= rot(b, 8); \
+ b += a; \
+ a -= c; \
+ a ^= rot(c, 16); \
+ c += b; \
+ b -= a; \
+ b ^= rot(a, 19); \
+ a += c; \
+ c -= b; \
+ c ^= rot(b, 4); \
+ b += a; \
+ }
+
+# define final(a, b, c) \
+ { \
+ c ^= b; \
+ c -= rot(b, 14); \
+ a ^= c; \
+ a -= rot(c, 11); \
+ b ^= a; \
+ b -= rot(a, 25); \
+ c ^= b; \
+ c -= rot(b, 16); \
+ a ^= c; \
+ a -= rot(c, 4); \
+ b ^= a; \
+ b -= rot(a, 14); \
+ c ^= b; \
+ c -= rot(b, 24); \
+ }
+
+ccl_device_inline ssei hash_ssei(ssei kx)
+{
+ ssei a, b, c;
+ a = b = c = ssei(0xdeadbeef + (1 << 2) + 13);
+
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline ssei hash_ssei2(ssei kx, ssei ky)
+{
+ ssei a, b, c;
+ a = b = c = ssei(0xdeadbeef + (2 << 2) + 13);
+
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline ssei hash_ssei3(ssei kx, ssei ky, ssei kz)
+{
+ ssei a, b, c;
+ a = b = c = ssei(0xdeadbeef + (3 << 2) + 13);
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline ssei hash_ssei4(ssei kx, ssei ky, ssei kz, ssei kw)
+{
+ ssei a, b, c;
+ a = b = c = ssei(0xdeadbeef + (4 << 2) + 13);
+
+ a += kx;
+ b += ky;
+ c += kz;
+ mix(a, b, c);
+
+ a += kw;
+ final(a, b, c);
+
+ return c;
+}
+
+# if defined(__KERNEL_AVX__)
+ccl_device_inline avxi hash_avxi(avxi kx)
+{
+ avxi a, b, c;
+ a = b = c = avxi(0xdeadbeef + (1 << 2) + 13);
+
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline avxi hash_avxi2(avxi kx, avxi ky)
+{
+ avxi a, b, c;
+ a = b = c = avxi(0xdeadbeef + (2 << 2) + 13);
+
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline avxi hash_avxi3(avxi kx, avxi ky, avxi kz)
+{
+ avxi a, b, c;
+ a = b = c = avxi(0xdeadbeef + (3 << 2) + 13);
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline avxi hash_avxi4(avxi kx, avxi ky, avxi kz, avxi kw)
+{
+ avxi a, b, c;
+ a = b = c = avxi(0xdeadbeef + (4 << 2) + 13);
+
+ a += kx;
+ b += ky;
+ c += kz;
+ mix(a, b, c);
+
+ a += kw;
+ final(a, b, c);
+
+ return c;
+}
+# endif
+
+# undef rot
+# undef final
+# undef mix
+
+#endif
+
+#ifndef __KERNEL_GPU__
+static inline uint hash_string(const char *str)
+{
+ uint i = 0, c;
+
+ while ((c = *str++))
+ i = i * 37 + c;
+
+ return i;
+}
+#endif
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_HASH_H__ */
diff --git a/intern/cycles/util/ies.cpp b/intern/cycles/util/ies.cpp
new file mode 100644
index 00000000000..5e879478df5
--- /dev/null
+++ b/intern/cycles/util/ies.cpp
@@ -0,0 +1,411 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+
+#include "util/foreach.h"
+#include "util/ies.h"
+#include "util/math.h"
+#include "util/string.h"
+
+CCL_NAMESPACE_BEGIN
+
+// NOTE: For some reason gcc-7.2 does not instantiate this versio of allocator
+// gere (used in IESTextParser). Works fine for gcc-6, gcc-7.3 and gcc-8.
+//
+// TODO(sergey): Get to the root of this issue, or confirm this i a compiler
+// issue.
+template class GuardedAllocator<char>;
+
+bool IESFile::load(const string &ies)
+{
+ clear();
+ if (!parse(ies) || !process()) {
+ clear();
+ return false;
+ }
+ return true;
+}
+
+void IESFile::clear()
+{
+ intensity.clear();
+ v_angles.clear();
+ h_angles.clear();
+}
+
+int IESFile::packed_size()
+{
+ if (v_angles.size() && h_angles.size() > 0) {
+ return 2 + h_angles.size() + v_angles.size() + h_angles.size() * v_angles.size();
+ }
+ return 0;
+}
+
+void IESFile::pack(float *data)
+{
+ if (v_angles.size() && h_angles.size()) {
+ *(data++) = __int_as_float(h_angles.size());
+ *(data++) = __int_as_float(v_angles.size());
+
+ memcpy(data, &h_angles[0], h_angles.size() * sizeof(float));
+ data += h_angles.size();
+ memcpy(data, &v_angles[0], v_angles.size() * sizeof(float));
+ data += v_angles.size();
+
+ for (int h = 0; h < intensity.size(); h++) {
+ memcpy(data, &intensity[h][0], v_angles.size() * sizeof(float));
+ data += v_angles.size();
+ }
+ }
+}
+
+class IESTextParser {
+ public:
+ vector<char> text;
+ char *data;
+
+ IESTextParser(const string &str) : text(str.begin(), str.end())
+ {
+ std::replace(text.begin(), text.end(), ',', ' ');
+ data = strstr(&text[0], "\nTILT=");
+ }
+
+ bool eof()
+ {
+ return (data == NULL) || (data[0] == '\0');
+ }
+
+ double get_double()
+ {
+ if (eof()) {
+ return 0.0;
+ }
+ char *old_data = data;
+ double val = strtod(data, &data);
+ if (data == old_data) {
+ data = NULL;
+ return 0.0;
+ }
+ return val;
+ }
+
+ long get_long()
+ {
+ if (eof()) {
+ return 0;
+ }
+ char *old_data = data;
+ long val = strtol(data, &data, 10);
+ if (data == old_data) {
+ data = NULL;
+ return 0;
+ }
+ return val;
+ }
+};
+
+bool IESFile::parse(const string &ies)
+{
+ if (ies.empty()) {
+ return false;
+ }
+
+ IESTextParser parser(ies);
+ if (parser.eof()) {
+ return false;
+ }
+
+ /* Handle the tilt data block. */
+ if (strncmp(parser.data, "\nTILT=INCLUDE", 13) == 0) {
+ parser.data += 13;
+ parser.get_double(); /* Lamp to Luminaire geometry */
+ int num_tilt = parser.get_long(); /* Amount of tilt angles and factors */
+ /* Skip over angles and factors. */
+ for (int i = 0; i < 2 * num_tilt; i++) {
+ parser.get_double();
+ }
+ }
+ else {
+ /* Skip to next line. */
+ parser.data = strstr(parser.data + 1, "\n");
+ }
+
+ if (parser.eof()) {
+ return false;
+ }
+ parser.data++;
+
+ parser.get_long(); /* Number of lamps */
+ parser.get_double(); /* Lumens per lamp */
+ double factor = parser.get_double(); /* Candela multiplier */
+ int v_angles_num = parser.get_long(); /* Number of vertical angles */
+ int h_angles_num = parser.get_long(); /* Number of horizontal angles */
+ type = (IESType)parser.get_long(); /* Photometric type */
+
+ /* TODO(lukas): Test whether the current type B processing can also deal with type A files.
+ * In theory the only difference should be orientation which we ignore anyways, but with IES you
+ * never know...
+ */
+ if (type != TYPE_B && type != TYPE_C) {
+ return false;
+ }
+
+ parser.get_long(); /* Unit of the geometry data */
+ parser.get_double(); /* Width */
+ parser.get_double(); /* Length */
+ parser.get_double(); /* Height */
+ factor *= parser.get_double(); /* Ballast factor */
+ factor *= parser.get_double(); /* Ballast-Lamp Photometric factor */
+ parser.get_double(); /* Input Watts */
+
+ /* Intensity values in IES files are specified in candela (lumen/sr), a photometric quantity.
+ * Cycles expects radiometric quantities, though, which requires a conversion.
+ * However, the Luminous efficacy (ratio of lumens per Watt) depends on the spectral distribution
+ * of the light source since lumens take human perception into account.
+ * Since this spectral distribution is not known from the IES file, a typical one must be
+ * assumed. The D65 standard illuminant has a Luminous efficacy of 177.83, which is used here to
+ * convert to Watt/sr. A more advanced approach would be to add a Blackbody Temperature input to
+ * the node and numerically integrate the Luminous efficacy from the resulting spectral
+ * distribution. Also, the Watt/sr value must be multiplied by 4*pi to get the Watt value that
+ * Cycles expects for lamp strength. Therefore, the conversion here uses 4*pi/177.83 as a Candela
+ * to Watt factor.
+ */
+ factor *= 0.0706650768394;
+
+ v_angles.reserve(v_angles_num);
+ for (int i = 0; i < v_angles_num; i++) {
+ v_angles.push_back((float)parser.get_double());
+ }
+
+ h_angles.reserve(h_angles_num);
+ for (int i = 0; i < h_angles_num; i++) {
+ h_angles.push_back((float)parser.get_double());
+ }
+
+ intensity.resize(h_angles_num);
+ for (int i = 0; i < h_angles_num; i++) {
+ intensity[i].reserve(v_angles_num);
+ for (int j = 0; j < v_angles_num; j++) {
+ intensity[i].push_back((float)(factor * parser.get_double()));
+ }
+ }
+
+ return !parser.eof();
+}
+
+bool IESFile::process_type_b()
+{
+ vector<vector<float>> newintensity;
+ newintensity.resize(v_angles.size());
+ for (int i = 0; i < v_angles.size(); i++) {
+ newintensity[i].reserve(h_angles.size());
+ for (int j = 0; j < h_angles.size(); j++) {
+ newintensity[i].push_back(intensity[j][i]);
+ }
+ }
+ intensity.swap(newintensity);
+ h_angles.swap(v_angles);
+
+ float h_first = h_angles[0], h_last = h_angles[h_angles.size() - 1];
+ if (h_last != 90.0f) {
+ return false;
+ }
+
+ if (h_first == 0.0f) {
+ /* The range in the file corresponds to 90°-180°, we need to mirror that to get the
+ * full 180° range. */
+ vector<float> new_h_angles;
+ vector<vector<float>> new_intensity;
+ int hnum = h_angles.size();
+ new_h_angles.reserve(2 * hnum - 1);
+ new_intensity.reserve(2 * hnum - 1);
+ for (int i = hnum - 1; i > 0; i--) {
+ new_h_angles.push_back(90.0f - h_angles[i]);
+ new_intensity.push_back(intensity[i]);
+ }
+ for (int i = 0; i < hnum; i++) {
+ new_h_angles.push_back(90.0f + h_angles[i]);
+ new_intensity.push_back(intensity[i]);
+ }
+ h_angles.swap(new_h_angles);
+ intensity.swap(new_intensity);
+ }
+ else if (h_first == -90.0f) {
+ /* We have full 180° coverage, so just shift to match the angle range convention. */
+ for (int i = 0; i < h_angles.size(); i++) {
+ h_angles[i] += 90.0f;
+ }
+ }
+ /* To get correct results with the cubic interpolation in the kernel, the horizontal range
+ * has to cover all 360°. Therefore, we copy the 0° entry to 360° to ensure full coverage
+ * and seamless interpolation. */
+ h_angles.push_back(360.0f);
+ intensity.push_back(intensity[0]);
+
+ float v_first = v_angles[0], v_last = v_angles[v_angles.size() - 1];
+ if (v_last != 90.0f) {
+ return false;
+ }
+
+ if (v_first == 0.0f) {
+ /* The range in the file corresponds to 90°-180°, we need to mirror that to get the
+ * full 180° range. */
+ vector<float> new_v_angles;
+ int hnum = h_angles.size();
+ int vnum = v_angles.size();
+ new_v_angles.reserve(2 * vnum - 1);
+ for (int i = vnum - 1; i > 0; i--) {
+ new_v_angles.push_back(90.0f - v_angles[i]);
+ }
+ for (int i = 0; i < vnum; i++) {
+ new_v_angles.push_back(90.0f + v_angles[i]);
+ }
+ for (int i = 0; i < hnum; i++) {
+ vector<float> new_intensity;
+ new_intensity.reserve(2 * vnum - 1);
+ for (int j = vnum - 2; j >= 0; j--) {
+ new_intensity.push_back(intensity[i][j]);
+ }
+ new_intensity.insert(new_intensity.end(), intensity[i].begin(), intensity[i].end());
+ intensity[i].swap(new_intensity);
+ }
+ v_angles.swap(new_v_angles);
+ }
+ else if (v_first == -90.0f) {
+ /* We have full 180° coverage, so just shift to match the angle range convention. */
+ for (int i = 0; i < v_angles.size(); i++) {
+ v_angles[i] += 90.0f;
+ }
+ }
+
+ return true;
+}
+
+bool IESFile::process_type_c()
+{
+ if (h_angles[0] == 90.0f) {
+ /* Some files are stored from 90° to 270°, so we just rotate them to the regular 0°-180° range
+ * here. */
+ for (int i = 0; i < h_angles.size(); i++) {
+ h_angles[i] -= 90.0f;
+ }
+ }
+
+ if (h_angles[0] != 0.0f) {
+ return false;
+ }
+
+ if (h_angles.size() == 1) {
+ h_angles.push_back(360.0f);
+ intensity.push_back(intensity[0]);
+ }
+
+ if (h_angles[h_angles.size() - 1] == 90.0f) {
+ /* Only one quadrant is defined, so we need to mirror twice (from one to two, then to four).
+ * Since the two->four mirroring step might also be required if we get an input of two
+ * quadrants, we only do the first mirror here and later do the second mirror in either case.
+ */
+ int hnum = h_angles.size();
+ for (int i = hnum - 2; i >= 0; i--) {
+ h_angles.push_back(180.0f - h_angles[i]);
+ intensity.push_back(intensity[i]);
+ }
+ }
+
+ if (h_angles[h_angles.size() - 1] == 180.0f) {
+ /* Mirror half to the full range. */
+ int hnum = h_angles.size();
+ for (int i = hnum - 2; i >= 0; i--) {
+ h_angles.push_back(360.0f - h_angles[i]);
+ intensity.push_back(intensity[i]);
+ }
+ }
+
+ /* Some files skip the 360° entry (contrary to standard) because it's supposed to be identical to
+ * the 0° entry. If the file has a discernible order in its spacing, just fix this. */
+ if (h_angles[h_angles.size() - 1] != 360.0f) {
+ int hnum = h_angles.size();
+ float last_step = h_angles[hnum - 1] - h_angles[hnum - 2];
+ float first_step = h_angles[1] - h_angles[0];
+ float difference = 360.0f - h_angles[hnum - 1];
+ if (last_step == difference || first_step == difference) {
+ h_angles.push_back(360.0f);
+ intensity.push_back(intensity[0]);
+ }
+ else {
+ return false;
+ }
+ }
+
+ float v_first = v_angles[0], v_last = v_angles[v_angles.size() - 1];
+ if (v_first == 90.0f) {
+ if (v_last == 180.0f) {
+ /* Flip to ensure that vertical angles always start at 0°. */
+ for (int i = 0; i < v_angles.size(); i++) {
+ v_angles[i] = 180.0f - v_angles[i];
+ }
+ }
+ else {
+ return false;
+ }
+ }
+ else if (v_first != 0.0f) {
+ return false;
+ }
+
+ return true;
+}
+
+bool IESFile::process()
+{
+ if (h_angles.size() == 0 || v_angles.size() == 0) {
+ return false;
+ }
+
+ if (type == TYPE_B) {
+ if (!process_type_b()) {
+ return false;
+ }
+ }
+ else {
+ assert(type == TYPE_C);
+ if (!process_type_c()) {
+ return false;
+ }
+ }
+
+ assert(v_angles[0] == 0.0f);
+ assert(h_angles[0] == 0.0f);
+ assert(h_angles[h_angles.size() - 1] == 360.0f);
+
+ /* Convert from deg to rad. */
+ for (int i = 0; i < v_angles.size(); i++) {
+ v_angles[i] *= M_PI_F / 180.f;
+ }
+ for (int i = 0; i < h_angles.size(); i++) {
+ h_angles[i] *= M_PI_F / 180.f;
+ }
+
+ return true;
+}
+
+IESFile::~IESFile()
+{
+ clear();
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/ies.h b/intern/cycles/util/ies.h
new file mode 100644
index 00000000000..7be072dd5f5
--- /dev/null
+++ b/intern/cycles/util/ies.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_IES_H__
+#define __UTIL_IES_H__
+
+#include "util/string.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class IESFile {
+ public:
+ IESFile()
+ {
+ }
+ ~IESFile();
+
+ int packed_size();
+ void pack(float *data);
+
+ bool load(const string &ies);
+ void clear();
+
+ protected:
+ bool parse(const string &ies);
+ bool process();
+ bool process_type_b();
+ bool process_type_c();
+
+ /* The brightness distribution is stored in spherical coordinates.
+ * The horizontal angles correspond to theta in the regular notation
+ * and always span the full range from 0° to 360°.
+ * The vertical angles correspond to phi and always start at 0°. */
+ vector<float> v_angles, h_angles;
+ /* The actual values are stored here, with every entry storing the values
+ * of one horizontal segment. */
+ vector<vector<float>> intensity;
+
+ /* Types of angle representation in IES files. Currently, only B and C are supported. */
+ enum IESType { TYPE_A = 3, TYPE_B = 2, TYPE_C = 1 } type;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_IES_H__ */
diff --git a/intern/cycles/util/image.h b/intern/cycles/util/image.h
new file mode 100644
index 00000000000..69fc3a50c1d
--- /dev/null
+++ b/intern/cycles/util/image.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_IMAGE_H__
+# define __UTIL_IMAGE_H__
+
+/* OpenImageIO is used for all image file reading and writing. */
+
+# include <OpenImageIO/imageio.h>
+
+# include "util/half.h"
+# include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+OIIO_NAMESPACE_USING
+
+template<typename T>
+void util_image_resize_pixels(const vector<T> &input_pixels,
+ const size_t input_width,
+ const size_t input_height,
+ const size_t input_depth,
+ const size_t components,
+ vector<T> *output_pixels,
+ size_t *output_width,
+ size_t *output_height,
+ size_t *output_depth);
+
+/* Cast input pixel from unknown storage to float. */
+template<typename T> inline float util_image_cast_to_float(T value);
+
+template<> inline float util_image_cast_to_float(float value)
+{
+ return value;
+}
+template<> inline float util_image_cast_to_float(uchar value)
+{
+ return (float)value / 255.0f;
+}
+template<> inline float util_image_cast_to_float(uint16_t value)
+{
+ return (float)value / 65535.0f;
+}
+template<> inline float util_image_cast_to_float(half value)
+{
+ return half_to_float_image(value);
+}
+
+/* Cast float value to output pixel type. */
+template<typename T> inline T util_image_cast_from_float(float value);
+
+template<> inline float util_image_cast_from_float(float value)
+{
+ return value;
+}
+template<> inline uchar util_image_cast_from_float(float value)
+{
+ if (value < 0.0f) {
+ return 0;
+ }
+ else if (value > (1.0f - 0.5f / 255.0f)) {
+ return 255;
+ }
+ return (uchar)((255.0f * value) + 0.5f);
+}
+template<> inline uint16_t util_image_cast_from_float(float value)
+{
+ if (value < 0.0f) {
+ return 0;
+ }
+ else if (value > (1.0f - 0.5f / 65535.0f)) {
+ return 65535;
+ }
+ return (uint16_t)((65535.0f * value) + 0.5f);
+}
+template<> inline half util_image_cast_from_float(float value)
+{
+ return float_to_half_image(value);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_IMAGE_H__ */
+
+#include "util/image_impl.h"
diff --git a/intern/cycles/util/image_impl.h b/intern/cycles/util/image_impl.h
new file mode 100644
index 00000000000..3d8eed80775
--- /dev/null
+++ b/intern/cycles/util/image_impl.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_IMAGE_IMPL_H__
+#define __UTIL_IMAGE_IMPL_H__
+
+#include "util/algorithm.h"
+#include "util/half.h"
+#include "util/image.h"
+
+CCL_NAMESPACE_BEGIN
+
+namespace {
+
+template<typename T>
+const T *util_image_read(const vector<T> &pixels,
+ const size_t width,
+ const size_t height,
+ const size_t /*depth*/,
+ const size_t components,
+ const size_t x,
+ const size_t y,
+ const size_t z)
+{
+ const size_t index = ((size_t)z * (width * height) + (size_t)y * width + (size_t)x) * components;
+ return &pixels[index];
+}
+
+template<typename T>
+void util_image_downscale_sample(const vector<T> &pixels,
+ const size_t width,
+ const size_t height,
+ const size_t depth,
+ const size_t components,
+ const size_t kernel_size,
+ const float x,
+ const float y,
+ const float z,
+ T *result)
+{
+ assert(components <= 4);
+ const size_t ix = (size_t)x, iy = (size_t)y, iz = (size_t)z;
+ /* TODO(sergey): Support something smarter than box filer. */
+ float accum[4] = {0};
+ size_t count = 0;
+ for (size_t dz = 0; dz < kernel_size; ++dz) {
+ for (size_t dy = 0; dy < kernel_size; ++dy) {
+ for (size_t dx = 0; dx < kernel_size; ++dx) {
+ const size_t nx = ix + dx, ny = iy + dy, nz = iz + dz;
+ if (nx >= width || ny >= height || nz >= depth) {
+ continue;
+ }
+ const T *pixel = util_image_read(pixels, width, height, depth, components, nx, ny, nz);
+ for (size_t k = 0; k < components; ++k) {
+ accum[k] += util_image_cast_to_float(pixel[k]);
+ }
+ ++count;
+ }
+ }
+ }
+ if (count != 0) {
+ const float inv_count = 1.0f / (float)count;
+ for (size_t k = 0; k < components; ++k) {
+ result[k] = util_image_cast_from_float<T>(accum[k] * inv_count);
+ }
+ }
+ else {
+ for (size_t k = 0; k < components; ++k) {
+ result[k] = T(0.0f);
+ }
+ }
+}
+
+template<typename T>
+void util_image_downscale_pixels(const vector<T> &input_pixels,
+ const size_t input_width,
+ const size_t input_height,
+ const size_t input_depth,
+ const size_t components,
+ const float inv_scale_factor,
+ const size_t output_width,
+ const size_t output_height,
+ const size_t output_depth,
+ vector<T> *output_pixels)
+{
+ const size_t kernel_size = (size_t)(inv_scale_factor + 0.5f);
+ for (size_t z = 0; z < output_depth; ++z) {
+ for (size_t y = 0; y < output_height; ++y) {
+ for (size_t x = 0; x < output_width; ++x) {
+ const float input_x = (float)x * inv_scale_factor, input_y = (float)y * inv_scale_factor,
+ input_z = (float)z * inv_scale_factor;
+ const size_t output_index = (z * output_width * output_height + y * output_width + x) *
+ components;
+ util_image_downscale_sample(input_pixels,
+ input_width,
+ input_height,
+ input_depth,
+ components,
+ kernel_size,
+ input_x,
+ input_y,
+ input_z,
+ &output_pixels->at(output_index));
+ }
+ }
+ }
+}
+
+} /* namespace */
+
+template<typename T>
+void util_image_resize_pixels(const vector<T> &input_pixels,
+ const size_t input_width,
+ const size_t input_height,
+ const size_t input_depth,
+ const size_t components,
+ const float scale_factor,
+ vector<T> *output_pixels,
+ size_t *output_width,
+ size_t *output_height,
+ size_t *output_depth)
+{
+ /* Early output for case when no scaling is applied. */
+ if (scale_factor == 1.0f) {
+ *output_width = input_width;
+ *output_height = input_height;
+ *output_depth = input_depth;
+ *output_pixels = input_pixels;
+ return;
+ }
+ /* First of all, we calculate output image dimensions.
+ * We clamp them to be 1 pixel at least so we do not generate degenerate
+ * image.
+ */
+ *output_width = max((size_t)((float)input_width * scale_factor), (size_t)1);
+ *output_height = max((size_t)((float)input_height * scale_factor), (size_t)1);
+ *output_depth = max((size_t)((float)input_depth * scale_factor), (size_t)1);
+ /* Prepare pixel storage for the result. */
+ const size_t num_output_pixels = ((*output_width) * (*output_height) * (*output_depth)) *
+ components;
+ output_pixels->resize(num_output_pixels);
+ if (scale_factor < 1.0f) {
+ const float inv_scale_factor = 1.0f / scale_factor;
+ util_image_downscale_pixels(input_pixels,
+ input_width,
+ input_height,
+ input_depth,
+ components,
+ inv_scale_factor,
+ *output_width,
+ *output_height,
+ *output_depth,
+ output_pixels);
+ }
+ else {
+ /* TODO(sergey): Needs implementation. */
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_IMAGE_IMPL_H__ */
diff --git a/intern/cycles/util/util_list.h b/intern/cycles/util/list.h
index f555b001186..f555b001186 100644
--- a/intern/cycles/util/util_list.h
+++ b/intern/cycles/util/list.h
diff --git a/intern/cycles/util/log.cpp b/intern/cycles/util/log.cpp
new file mode 100644
index 00000000000..68a5a3f576f
--- /dev/null
+++ b/intern/cycles/util/log.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2011-2014 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/log.h"
+
+#include "util/math.h"
+#include "util/string.h"
+
+#include <stdio.h>
+#ifdef _MSC_VER
+# define snprintf _snprintf
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_CYCLES_LOGGING
+static bool is_verbosity_set()
+{
+ using CYCLES_GFLAGS_NAMESPACE::GetCommandLineOption;
+
+ std::string verbosity;
+ if (!GetCommandLineOption("v", &verbosity)) {
+ return false;
+ }
+ return verbosity != "0";
+}
+#endif
+
+void util_logging_init(const char *argv0)
+{
+#ifdef WITH_CYCLES_LOGGING
+ using CYCLES_GFLAGS_NAMESPACE::SetCommandLineOption;
+
+ google::InitGoogleLogging(argv0);
+ SetCommandLineOption("logtostderr", "1");
+ if (!is_verbosity_set()) {
+ SetCommandLineOption("v", "0");
+ }
+ SetCommandLineOption("stderrthreshold", "0");
+ SetCommandLineOption("minloglevel", "0");
+#else
+ (void)argv0;
+#endif
+}
+
+void util_logging_start()
+{
+#ifdef WITH_CYCLES_LOGGING
+ using CYCLES_GFLAGS_NAMESPACE::SetCommandLineOption;
+ SetCommandLineOption("logtostderr", "1");
+ if (!is_verbosity_set()) {
+ SetCommandLineOption("v", "2");
+ }
+ SetCommandLineOption("stderrthreshold", "0");
+ SetCommandLineOption("minloglevel", "0");
+#endif
+}
+
+void util_logging_verbosity_set(int verbosity)
+{
+#ifdef WITH_CYCLES_LOGGING
+ using CYCLES_GFLAGS_NAMESPACE::SetCommandLineOption;
+ char val[10];
+ snprintf(val, sizeof(val), "%d", verbosity);
+ SetCommandLineOption("v", val);
+#else
+ (void)verbosity;
+#endif
+}
+
+std::ostream &operator<<(std::ostream &os, const int2 &value)
+{
+ os << "(" << value.x << ", " << value.y << ")";
+ return os;
+}
+
+std::ostream &operator<<(std::ostream &os, const float3 &value)
+{
+ os << "(" << value.x << ", " << value.y << ", " << value.z << ")";
+ return os;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_logging.h b/intern/cycles/util/log.h
index 35c2d436d09..35c2d436d09 100644
--- a/intern/cycles/util/util_logging.h
+++ b/intern/cycles/util/log.h
diff --git a/intern/cycles/util/util_map.h b/intern/cycles/util/map.h
index f1b2522362f..f1b2522362f 100644
--- a/intern/cycles/util/util_map.h
+++ b/intern/cycles/util/map.h
diff --git a/intern/cycles/util/math.h b/intern/cycles/util/math.h
new file mode 100644
index 00000000000..e4c7df6e44a
--- /dev/null
+++ b/intern/cycles/util/math.h
@@ -0,0 +1,875 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_MATH_H__
+#define __UTIL_MATH_H__
+
+/* Math
+ *
+ * Basic math functions on scalar and vector types. This header is used by
+ * both the kernel code when compiled as C++, and other C++ non-kernel code. */
+
+#ifndef __KERNEL_GPU__
+# include <cmath>
+#endif
+
+#ifdef __HIP__
+# include <hip/hip_vector_types.h>
+#endif
+
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Float Pi variations */
+
+/* Division */
+#ifndef M_PI_F
+# define M_PI_F (3.1415926535897932f) /* pi */
+#endif
+#ifndef M_PI_2_F
+# define M_PI_2_F (1.5707963267948966f) /* pi/2 */
+#endif
+#ifndef M_PI_4_F
+# define M_PI_4_F (0.7853981633974830f) /* pi/4 */
+#endif
+#ifndef M_1_PI_F
+# define M_1_PI_F (0.3183098861837067f) /* 1/pi */
+#endif
+#ifndef M_2_PI_F
+# define M_2_PI_F (0.6366197723675813f) /* 2/pi */
+#endif
+#ifndef M_1_2PI_F
+# define M_1_2PI_F (0.1591549430918953f) /* 1/(2*pi) */
+#endif
+#ifndef M_SQRT_PI_8_F
+# define M_SQRT_PI_8_F (0.6266570686577501f) /* sqrt(pi/8) */
+#endif
+#ifndef M_LN_2PI_F
+# define M_LN_2PI_F (1.8378770664093454f) /* ln(2*pi) */
+#endif
+
+/* Multiplication */
+#ifndef M_2PI_F
+# define M_2PI_F (6.2831853071795864f) /* 2*pi */
+#endif
+#ifndef M_4PI_F
+# define M_4PI_F (12.566370614359172f) /* 4*pi */
+#endif
+
+/* Float sqrt variations */
+#ifndef M_SQRT2_F
+# define M_SQRT2_F (1.4142135623730950f) /* sqrt(2) */
+#endif
+#ifndef M_LN2_F
+# define M_LN2_F (0.6931471805599453f) /* ln(2) */
+#endif
+#ifndef M_LN10_F
+# define M_LN10_F (2.3025850929940457f) /* ln(10) */
+#endif
+
+/* Scalar */
+
+#ifndef __HIP__
+# ifdef _WIN32
+ccl_device_inline float fmaxf(float a, float b)
+{
+ return (a > b) ? a : b;
+}
+
+ccl_device_inline float fminf(float a, float b)
+{
+ return (a < b) ? a : b;
+}
+
+# endif /* _WIN32 */
+#endif /* __HIP__ */
+
+#ifndef __KERNEL_GPU__
+using std::isfinite;
+using std::isnan;
+using std::sqrt;
+
+ccl_device_inline int abs(int x)
+{
+ return (x > 0) ? x : -x;
+}
+
+ccl_device_inline int max(int a, int b)
+{
+ return (a > b) ? a : b;
+}
+
+ccl_device_inline int min(int a, int b)
+{
+ return (a < b) ? a : b;
+}
+
+ccl_device_inline uint min(uint a, uint b)
+{
+ return (a < b) ? a : b;
+}
+
+ccl_device_inline float max(float a, float b)
+{
+ return (a > b) ? a : b;
+}
+
+ccl_device_inline float min(float a, float b)
+{
+ return (a < b) ? a : b;
+}
+
+ccl_device_inline double max(double a, double b)
+{
+ return (a > b) ? a : b;
+}
+
+ccl_device_inline double min(double a, double b)
+{
+ return (a < b) ? a : b;
+}
+
+/* These 2 guys are templated for usage with registers data.
+ *
+ * NOTE: Since this is CPU-only functions it is ok to use references here.
+ * But for other devices we'll need to be careful about this.
+ */
+
+template<typename T> ccl_device_inline T min4(const T &a, const T &b, const T &c, const T &d)
+{
+ return min(min(a, b), min(c, d));
+}
+
+template<typename T> ccl_device_inline T max4(const T &a, const T &b, const T &c, const T &d)
+{
+ return max(max(a, b), max(c, d));
+}
+#endif /* __KERNEL_GPU__ */
+
+ccl_device_inline float min4(float a, float b, float c, float d)
+{
+ return min(min(a, b), min(c, d));
+}
+
+ccl_device_inline float max4(float a, float b, float c, float d)
+{
+ return max(max(a, b), max(c, d));
+}
+
+/* Int/Float conversion */
+
+ccl_device_inline int as_int(uint i)
+{
+ union {
+ uint ui;
+ int i;
+ } u;
+ u.ui = i;
+ return u.i;
+}
+
+ccl_device_inline uint as_uint(int i)
+{
+ union {
+ uint ui;
+ int i;
+ } u;
+ u.i = i;
+ return u.ui;
+}
+
+ccl_device_inline uint as_uint(float f)
+{
+ union {
+ uint i;
+ float f;
+ } u;
+ u.f = f;
+ return u.i;
+}
+
+#ifndef __HIP__
+ccl_device_inline int __float_as_int(float f)
+{
+ union {
+ int i;
+ float f;
+ } u;
+ u.f = f;
+ return u.i;
+}
+
+ccl_device_inline float __int_as_float(int i)
+{
+ union {
+ int i;
+ float f;
+ } u;
+ u.i = i;
+ return u.f;
+}
+
+ccl_device_inline uint __float_as_uint(float f)
+{
+ union {
+ uint i;
+ float f;
+ } u;
+ u.f = f;
+ return u.i;
+}
+
+ccl_device_inline float __uint_as_float(uint i)
+{
+ union {
+ uint i;
+ float f;
+ } u;
+ u.i = i;
+ return u.f;
+}
+#endif
+
+ccl_device_inline int4 __float4_as_int4(float4 f)
+{
+#ifdef __KERNEL_SSE__
+ return int4(_mm_castps_si128(f.m128));
+#else
+ return make_int4(
+ __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), __float_as_int(f.w));
+#endif
+}
+
+ccl_device_inline float4 __int4_as_float4(int4 i)
+{
+#ifdef __KERNEL_SSE__
+ return float4(_mm_castsi128_ps(i.m128));
+#else
+ return make_float4(
+ __int_as_float(i.x), __int_as_float(i.y), __int_as_float(i.z), __int_as_float(i.w));
+#endif
+}
+
+template<typename T> ccl_device_inline uint pointer_pack_to_uint_0(T *ptr)
+{
+ return ((uint64_t)ptr) & 0xFFFFFFFF;
+}
+
+template<typename T> ccl_device_inline uint pointer_pack_to_uint_1(T *ptr)
+{
+ return (((uint64_t)ptr) >> 32) & 0xFFFFFFFF;
+}
+
+template<typename T> ccl_device_inline T *pointer_unpack_from_uint(const uint a, const uint b)
+{
+ return (T *)(((uint64_t)b << 32) | a);
+}
+
+ccl_device_inline uint uint16_pack_to_uint(const uint a, const uint b)
+{
+ return (a << 16) | b;
+}
+
+ccl_device_inline uint uint16_unpack_from_uint_0(const uint i)
+{
+ return i >> 16;
+}
+
+ccl_device_inline uint uint16_unpack_from_uint_1(const uint i)
+{
+ return i & 0xFFFF;
+}
+
+/* Versions of functions which are safe for fast math. */
+ccl_device_inline bool isnan_safe(float f)
+{
+ unsigned int x = __float_as_uint(f);
+ return (x << 1) > 0xff000000u;
+}
+
+ccl_device_inline bool isfinite_safe(float f)
+{
+ /* By IEEE 754 rule, 2*Inf equals Inf */
+ unsigned int x = __float_as_uint(f);
+ return (f == f) && (x == 0 || x == (1u << 31) || (f != 2.0f * f)) && !((x << 1) > 0xff000000u);
+}
+
+ccl_device_inline float ensure_finite(float v)
+{
+ return isfinite_safe(v) ? v : 0.0f;
+}
+
+ccl_device_inline int clamp(int a, int mn, int mx)
+{
+ return min(max(a, mn), mx);
+}
+
+ccl_device_inline float clamp(float a, float mn, float mx)
+{
+ return min(max(a, mn), mx);
+}
+
+ccl_device_inline float mix(float a, float b, float t)
+{
+ return a + t * (b - a);
+}
+
+ccl_device_inline float smoothstep(float edge0, float edge1, float x)
+{
+ float result;
+ if (x < edge0)
+ result = 0.0f;
+ else if (x >= edge1)
+ result = 1.0f;
+ else {
+ float t = (x - edge0) / (edge1 - edge0);
+ result = (3.0f - 2.0f * t) * (t * t);
+ }
+ return result;
+}
+
+#ifndef __KERNEL_CUDA__
+ccl_device_inline float saturatef(float a)
+{
+ return clamp(a, 0.0f, 1.0f);
+}
+#else
+ccl_device_inline float saturatef(float a)
+{
+ return __saturatef(a);
+}
+#endif /* __KERNEL_CUDA__ */
+
+ccl_device_inline int float_to_int(float f)
+{
+ return (int)f;
+}
+
+ccl_device_inline int floor_to_int(float f)
+{
+ return float_to_int(floorf(f));
+}
+
+ccl_device_inline int quick_floor_to_int(float x)
+{
+ return float_to_int(x) - ((x < 0) ? 1 : 0);
+}
+
+ccl_device_inline float floorfrac(float x, ccl_private int *i)
+{
+ *i = quick_floor_to_int(x);
+ return x - *i;
+}
+
+ccl_device_inline int ceil_to_int(float f)
+{
+ return float_to_int(ceilf(f));
+}
+
+ccl_device_inline float fractf(float x)
+{
+ return x - floorf(x);
+}
+
+/* Adapted from godot-engine math_funcs.h. */
+ccl_device_inline float wrapf(float value, float max, float min)
+{
+ float range = max - min;
+ return (range != 0.0f) ? value - (range * floorf((value - min) / range)) : min;
+}
+
+ccl_device_inline float pingpongf(float a, float b)
+{
+ return (b != 0.0f) ? fabsf(fractf((a - b) / (b * 2.0f)) * b * 2.0f - b) : 0.0f;
+}
+
+ccl_device_inline float smoothminf(float a, float b, float k)
+{
+ if (k != 0.0f) {
+ float h = fmaxf(k - fabsf(a - b), 0.0f) / k;
+ return fminf(a, b) - h * h * h * k * (1.0f / 6.0f);
+ }
+ else {
+ return fminf(a, b);
+ }
+}
+
+ccl_device_inline float signf(float f)
+{
+ return (f < 0.0f) ? -1.0f : 1.0f;
+}
+
+ccl_device_inline float nonzerof(float f, float eps)
+{
+ if (fabsf(f) < eps)
+ return signf(f) * eps;
+ else
+ return f;
+}
+
+/* `signum` function testing for zero. Matches GLSL and OSL functions. */
+ccl_device_inline float compatible_signf(float f)
+{
+ if (f == 0.0f) {
+ return 0.0f;
+ }
+ else {
+ return signf(f);
+ }
+}
+
+ccl_device_inline float smoothstepf(float f)
+{
+ float ff = f * f;
+ return (3.0f * ff - 2.0f * ff * f);
+}
+
+ccl_device_inline int mod(int x, int m)
+{
+ return (x % m + m) % m;
+}
+
+ccl_device_inline float3 float2_to_float3(const float2 a)
+{
+ return make_float3(a.x, a.y, 0.0f);
+}
+
+ccl_device_inline float3 float4_to_float3(const float4 a)
+{
+ return make_float3(a.x, a.y, a.z);
+}
+
+ccl_device_inline float4 float3_to_float4(const float3 a)
+{
+ return make_float4(a.x, a.y, a.z, 1.0f);
+}
+
+ccl_device_inline float inverse_lerp(float a, float b, float x)
+{
+ return (x - a) / (b - a);
+}
+
+/* Cubic interpolation between b and c, a and d are the previous and next point. */
+ccl_device_inline float cubic_interp(float a, float b, float c, float d, float x)
+{
+ return 0.5f *
+ (((d + 3.0f * (b - c) - a) * x + (2.0f * a - 5.0f * b + 4.0f * c - d)) * x +
+ (c - a)) *
+ x +
+ b;
+}
+
+CCL_NAMESPACE_END
+
+#include "util/math_int2.h"
+#include "util/math_int3.h"
+#include "util/math_int4.h"
+
+#include "util/math_float2.h"
+#include "util/math_float3.h"
+#include "util/math_float4.h"
+
+#include "util/rect.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Interpolation */
+
+template<class A, class B> A lerp(const A &a, const A &b, const B &t)
+{
+ return (A)(a * ((B)1 - t) + b * t);
+}
+
+/* Triangle */
+
+ccl_device_inline float triangle_area(ccl_private const float3 &v1,
+ ccl_private const float3 &v2,
+ ccl_private const float3 &v3)
+{
+ return len(cross(v3 - v2, v1 - v2)) * 0.5f;
+}
+
+/* Orthonormal vectors */
+
+ccl_device_inline void make_orthonormals(const float3 N,
+ ccl_private float3 *a,
+ ccl_private float3 *b)
+{
+#if 0
+ if (fabsf(N.y) >= 0.999f) {
+ *a = make_float3(1, 0, 0);
+ *b = make_float3(0, 0, 1);
+ return;
+ }
+ if (fabsf(N.z) >= 0.999f) {
+ *a = make_float3(1, 0, 0);
+ *b = make_float3(0, 1, 0);
+ return;
+ }
+#endif
+
+ if (N.x != N.y || N.x != N.z)
+ *a = make_float3(N.z - N.y, N.x - N.z, N.y - N.x); //(1,1,1)x N
+ else
+ *a = make_float3(N.z - N.y, N.x + N.z, -N.y - N.x); //(-1,1,1)x N
+
+ *a = normalize(*a);
+ *b = cross(N, *a);
+}
+
+/* Color division */
+
+ccl_device_inline float3 safe_invert_color(float3 a)
+{
+ float x, y, z;
+
+ x = (a.x != 0.0f) ? 1.0f / a.x : 0.0f;
+ y = (a.y != 0.0f) ? 1.0f / a.y : 0.0f;
+ z = (a.z != 0.0f) ? 1.0f / a.z : 0.0f;
+
+ return make_float3(x, y, z);
+}
+
+ccl_device_inline float3 safe_divide_color(float3 a, float3 b)
+{
+ float x, y, z;
+
+ x = (b.x != 0.0f) ? a.x / b.x : 0.0f;
+ y = (b.y != 0.0f) ? a.y / b.y : 0.0f;
+ z = (b.z != 0.0f) ? a.z / b.z : 0.0f;
+
+ return make_float3(x, y, z);
+}
+
+ccl_device_inline float3 safe_divide_even_color(float3 a, float3 b)
+{
+ float x, y, z;
+
+ x = (b.x != 0.0f) ? a.x / b.x : 0.0f;
+ y = (b.y != 0.0f) ? a.y / b.y : 0.0f;
+ z = (b.z != 0.0f) ? a.z / b.z : 0.0f;
+
+ /* try to get gray even if b is zero */
+ if (b.x == 0.0f) {
+ if (b.y == 0.0f) {
+ x = z;
+ y = z;
+ }
+ else if (b.z == 0.0f) {
+ x = y;
+ z = y;
+ }
+ else
+ x = 0.5f * (y + z);
+ }
+ else if (b.y == 0.0f) {
+ if (b.z == 0.0f) {
+ y = x;
+ z = x;
+ }
+ else
+ y = 0.5f * (x + z);
+ }
+ else if (b.z == 0.0f) {
+ z = 0.5f * (x + y);
+ }
+
+ return make_float3(x, y, z);
+}
+
+/* Rotation of point around axis and angle */
+
+ccl_device_inline float3 rotate_around_axis(float3 p, float3 axis, float angle)
+{
+ float costheta = cosf(angle);
+ float sintheta = sinf(angle);
+ float3 r;
+
+ r.x = ((costheta + (1 - costheta) * axis.x * axis.x) * p.x) +
+ (((1 - costheta) * axis.x * axis.y - axis.z * sintheta) * p.y) +
+ (((1 - costheta) * axis.x * axis.z + axis.y * sintheta) * p.z);
+
+ r.y = (((1 - costheta) * axis.x * axis.y + axis.z * sintheta) * p.x) +
+ ((costheta + (1 - costheta) * axis.y * axis.y) * p.y) +
+ (((1 - costheta) * axis.y * axis.z - axis.x * sintheta) * p.z);
+
+ r.z = (((1 - costheta) * axis.x * axis.z - axis.y * sintheta) * p.x) +
+ (((1 - costheta) * axis.y * axis.z + axis.x * sintheta) * p.y) +
+ ((costheta + (1 - costheta) * axis.z * axis.z) * p.z);
+
+ return r;
+}
+
+/* NaN-safe math ops */
+
+ccl_device_inline float safe_sqrtf(float f)
+{
+ return sqrtf(max(f, 0.0f));
+}
+
+ccl_device_inline float inversesqrtf(float f)
+{
+ return (f > 0.0f) ? 1.0f / sqrtf(f) : 0.0f;
+}
+
+ccl_device float safe_asinf(float a)
+{
+ return asinf(clamp(a, -1.0f, 1.0f));
+}
+
+ccl_device float safe_acosf(float a)
+{
+ return acosf(clamp(a, -1.0f, 1.0f));
+}
+
+ccl_device float compatible_powf(float x, float y)
+{
+#ifdef __KERNEL_GPU__
+ if (y == 0.0f) /* x^0 -> 1, including 0^0 */
+ return 1.0f;
+
+ /* GPU pow doesn't accept negative x, do manual checks here */
+ if (x < 0.0f) {
+ if (fmodf(-y, 2.0f) == 0.0f)
+ return powf(-x, y);
+ else
+ return -powf(-x, y);
+ }
+ else if (x == 0.0f)
+ return 0.0f;
+#endif
+ return powf(x, y);
+}
+
+ccl_device float safe_powf(float a, float b)
+{
+ if (UNLIKELY(a < 0.0f && b != float_to_int(b)))
+ return 0.0f;
+
+ return compatible_powf(a, b);
+}
+
+ccl_device float safe_divide(float a, float b)
+{
+ return (b != 0.0f) ? a / b : 0.0f;
+}
+
+ccl_device float safe_logf(float a, float b)
+{
+ if (UNLIKELY(a <= 0.0f || b <= 0.0f))
+ return 0.0f;
+
+ return safe_divide(logf(a), logf(b));
+}
+
+ccl_device float safe_modulo(float a, float b)
+{
+ return (b != 0.0f) ? fmodf(a, b) : 0.0f;
+}
+
+ccl_device_inline float sqr(float a)
+{
+ return a * a;
+}
+
+ccl_device_inline float pow20(float a)
+{
+ return sqr(sqr(sqr(sqr(a)) * a));
+}
+
+ccl_device_inline float pow22(float a)
+{
+ return sqr(a * sqr(sqr(sqr(a)) * a));
+}
+
+ccl_device_inline float beta(float x, float y)
+{
+ return expf(lgammaf(x) + lgammaf(y) - lgammaf(x + y));
+}
+
+ccl_device_inline float xor_signmask(float x, int y)
+{
+ return __int_as_float(__float_as_int(x) ^ y);
+}
+
+ccl_device float bits_to_01(uint bits)
+{
+ return bits * (1.0f / (float)0xFFFFFFFF);
+}
+
+ccl_device_inline uint count_leading_zeros(uint x)
+{
+#if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) || defined(__KERNEL_HIP__)
+ return __clz(x);
+#else
+ assert(x != 0);
+# ifdef _MSC_VER
+ unsigned long leading_zero = 0;
+ _BitScanReverse(&leading_zero, x);
+ return (31 - leading_zero);
+# else
+ return __builtin_clz(x);
+# endif
+#endif
+}
+
+ccl_device_inline uint count_trailing_zeros(uint x)
+{
+#if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) || defined(__KERNEL_HIP__)
+ return (__ffs(x) - 1);
+#else
+ assert(x != 0);
+# ifdef _MSC_VER
+ unsigned long ctz = 0;
+ _BitScanForward(&ctz, x);
+ return ctz;
+# else
+ return __builtin_ctz(x);
+# endif
+#endif
+}
+
+ccl_device_inline uint find_first_set(uint x)
+{
+#if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) || defined(__KERNEL_HIP__)
+ return __ffs(x);
+#else
+# ifdef _MSC_VER
+ return (x != 0) ? (32 - count_leading_zeros(x & (-x))) : 0;
+# else
+ return __builtin_ffs(x);
+# endif
+#endif
+}
+
+/* projections */
+ccl_device_inline float2 map_to_tube(const float3 co)
+{
+ float len, u, v;
+ len = sqrtf(co.x * co.x + co.y * co.y);
+ if (len > 0.0f) {
+ u = (1.0f - (atan2f(co.x / len, co.y / len) / M_PI_F)) * 0.5f;
+ v = (co.z + 1.0f) * 0.5f;
+ }
+ else {
+ u = v = 0.0f;
+ }
+ return make_float2(u, v);
+}
+
+ccl_device_inline float2 map_to_sphere(const float3 co)
+{
+ float l = len(co);
+ float u, v;
+ if (l > 0.0f) {
+ if (UNLIKELY(co.x == 0.0f && co.y == 0.0f)) {
+ u = 0.0f; /* Otherwise domain error. */
+ }
+ else {
+ u = (1.0f - atan2f(co.x, co.y) / M_PI_F) / 2.0f;
+ }
+ v = 1.0f - safe_acosf(co.z / l) / M_PI_F;
+ }
+ else {
+ u = v = 0.0f;
+ }
+ return make_float2(u, v);
+}
+
+/* Compares two floats.
+ * Returns true if their absolute difference is smaller than abs_diff (for numbers near zero)
+ * or their relative difference is less than ulp_diff ULPs.
+ * Based on
+ * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+ */
+
+ccl_device_inline float compare_floats(float a, float b, float abs_diff, int ulp_diff)
+{
+ if (fabsf(a - b) < abs_diff) {
+ return true;
+ }
+
+ if ((a < 0.0f) != (b < 0.0f)) {
+ return false;
+ }
+
+ return (abs(__float_as_int(a) - __float_as_int(b)) < ulp_diff);
+}
+
+/* Calculate the angle between the two vectors a and b.
+ * The usual approach `acos(dot(a, b))` has severe precision issues for small angles,
+ * which are avoided by this method.
+ * Based on "Mangled Angles" from https://people.eecs.berkeley.edu/~wkahan/Mindless.pdf
+ */
+ccl_device_inline float precise_angle(float3 a, float3 b)
+{
+ return 2.0f * atan2f(len(a - b), len(a + b));
+}
+
+/* Return value which is greater than the given one and is a power of two. */
+ccl_device_inline uint next_power_of_two(uint x)
+{
+ return x == 0 ? 1 : 1 << (32 - count_leading_zeros(x));
+}
+
+/* Return value which is lower than the given one and is a power of two. */
+ccl_device_inline uint prev_power_of_two(uint x)
+{
+ return x < 2 ? x : 1 << (31 - count_leading_zeros(x - 1));
+}
+
+#ifndef __has_builtin
+# define __has_builtin(v) 0
+#endif
+
+/* Reverses the bits of a 32 bit integer. */
+ccl_device_inline uint32_t reverse_integer_bits(uint32_t x)
+{
+ /* Use a native instruction if it exists. */
+#if defined(__arm__) || defined(__aarch64__)
+ __asm__("rbit %w0, %w1" : "=r"(x) : "r"(x));
+ return x;
+#elif defined(__KERNEL_CUDA__)
+ return __brev(x);
+#elif __has_builtin(__builtin_bitreverse32)
+ return __builtin_bitreverse32(x);
+#else
+ /* Flip pairwise. */
+ x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1);
+ /* Flip pairs. */
+ x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2);
+ /* Flip nibbles. */
+ x = ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4);
+ /* Flip bytes. CPUs have an instruction for that, pretty fast one. */
+# ifdef _MSC_VER
+ return _byteswap_ulong(x);
+# elif defined(__INTEL_COMPILER)
+ return (uint32_t)_bswap((int)x);
+# else
+ /* Assuming gcc or clang. */
+ return __builtin_bswap32(x);
+# endif
+#endif
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MATH_H__ */
diff --git a/intern/cycles/util/math_cdf.cpp b/intern/cycles/util/math_cdf.cpp
new file mode 100644
index 00000000000..02c6646f824
--- /dev/null
+++ b/intern/cycles/util/math_cdf.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/math_cdf.h"
+
+#include "util/algorithm.h"
+#include "util/math.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Invert pre-calculated CDF function. */
+void util_cdf_invert(const int resolution,
+ const float from,
+ const float to,
+ const vector<float> &cdf,
+ const bool make_symmetric,
+ vector<float> &inv_cdf)
+{
+ const float inv_resolution = 1.0f / (float)resolution;
+ const float range = to - from;
+ inv_cdf.resize(resolution);
+ if (make_symmetric) {
+ const int half_size = (resolution - 1) / 2;
+ for (int i = 0; i <= half_size; i++) {
+ float x = i / (float)half_size;
+ int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin();
+ float t;
+ if (index < cdf.size() - 1) {
+ t = (x - cdf[index]) / (cdf[index + 1] - cdf[index]);
+ }
+ else {
+ t = 0.0f;
+ index = cdf.size() - 1;
+ }
+ float y = ((index + t) / (resolution - 1)) * (2.0f * range);
+ inv_cdf[half_size + i] = 0.5f * (1.0f + y);
+ inv_cdf[half_size - i] = 0.5f * (1.0f - y);
+ }
+ }
+ else {
+ for (int i = 0; i < resolution; i++) {
+ float x = from + range * (float)i * inv_resolution;
+ int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin();
+ float t;
+ if (index < cdf.size() - 1) {
+ t = (x - cdf[index]) / (cdf[index + 1] - cdf[index]);
+ }
+ else {
+ t = 0.0f;
+ index = resolution;
+ }
+ inv_cdf[i] = (index + t) * inv_resolution;
+ }
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/math_cdf.h b/intern/cycles/util/math_cdf.h
new file mode 100644
index 00000000000..4c57dac4bbe
--- /dev/null
+++ b/intern/cycles/util/math_cdf.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_MATH_CDF_H__
+#define __UTIL_MATH_CDF_H__
+
+#include "util/algorithm.h"
+#include "util/math.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Evaluate CDF of a given functor with given range and resolution. */
+template<typename Functor>
+void util_cdf_evaluate(
+ const int resolution, const float from, const float to, Functor functor, vector<float> &cdf)
+{
+ const int cdf_count = resolution + 1;
+ const float range = to - from;
+ cdf.resize(cdf_count);
+ cdf[0] = 0.0f;
+ /* Actual CDF evaluation. */
+ for (int i = 0; i < resolution; ++i) {
+ float x = from + range * (float)i / (resolution - 1);
+ float y = functor(x);
+ cdf[i + 1] = cdf[i] + fabsf(y);
+ }
+ /* Normalize the CDF. */
+ for (int i = 0; i <= resolution; i++) {
+ cdf[i] /= cdf[resolution];
+ }
+}
+
+/* Invert pre-calculated CDF function. */
+void util_cdf_invert(const int resolution,
+ const float from,
+ const float to,
+ const vector<float> &cdf,
+ const bool make_symmetric,
+ vector<float> &inv_cdf);
+
+/* Evaluate inverted CDF of a given functor with given range and resolution. */
+template<typename Functor>
+void util_cdf_inverted(const int resolution,
+ const float from,
+ const float to,
+ Functor functor,
+ const bool make_symmetric,
+ vector<float> &inv_cdf)
+{
+ vector<float> cdf;
+ /* There is no much smartness going around lower resolution for the CDF table,
+ * this just to match the old code from pixel filter so it all stays exactly
+ * the same and no regression tests are failed.
+ */
+ util_cdf_evaluate(resolution - 1, from, to, functor, cdf);
+ util_cdf_invert(resolution, from, to, cdf, make_symmetric, inv_cdf);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MATH_H_CDF__ */
diff --git a/intern/cycles/util/util_math_fast.h b/intern/cycles/util/math_fast.h
index cc924f36a71..cc924f36a71 100644
--- a/intern/cycles/util/util_math_fast.h
+++ b/intern/cycles/util/math_fast.h
diff --git a/intern/cycles/util/math_float2.h b/intern/cycles/util/math_float2.h
new file mode 100644
index 00000000000..87141d5bc37
--- /dev/null
+++ b/intern/cycles/util/math_float2.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_MATH_FLOAT2_H__
+#define __UTIL_MATH_FLOAT2_H__
+
+#ifndef __UTIL_MATH_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/*******************************************************************************
+ * Declaration.
+ */
+
+ccl_device_inline float2 operator-(const float2 &a);
+ccl_device_inline float2 operator*(const float2 &a, const float2 &b);
+ccl_device_inline float2 operator*(const float2 &a, float f);
+ccl_device_inline float2 operator*(float f, const float2 &a);
+ccl_device_inline float2 operator/(float f, const float2 &a);
+ccl_device_inline float2 operator/(const float2 &a, float f);
+ccl_device_inline float2 operator/(const float2 &a, const float2 &b);
+ccl_device_inline float2 operator+(const float2 &a, const float f);
+ccl_device_inline float2 operator+(const float2 &a, const float2 &b);
+ccl_device_inline float2 operator-(const float2 &a, const float f);
+ccl_device_inline float2 operator-(const float2 &a, const float2 &b);
+ccl_device_inline float2 operator+=(float2 &a, const float2 &b);
+ccl_device_inline float2 operator*=(float2 &a, const float2 &b);
+ccl_device_inline float2 operator*=(float2 &a, float f);
+ccl_device_inline float2 operator/=(float2 &a, const float2 &b);
+ccl_device_inline float2 operator/=(float2 &a, float f);
+
+ccl_device_inline bool operator==(const float2 &a, const float2 &b);
+ccl_device_inline bool operator!=(const float2 &a, const float2 &b);
+
+ccl_device_inline bool is_zero(const float2 &a);
+ccl_device_inline float average(const float2 &a);
+ccl_device_inline float distance(const float2 &a, const float2 &b);
+ccl_device_inline float dot(const float2 &a, const float2 &b);
+ccl_device_inline float cross(const float2 &a, const float2 &b);
+ccl_device_inline float len(const float2 &a);
+ccl_device_inline float2 normalize(const float2 &a);
+ccl_device_inline float2 normalize_len(const float2 &a, float *t);
+ccl_device_inline float2 safe_normalize(const float2 &a);
+ccl_device_inline float2 min(const float2 &a, const float2 &b);
+ccl_device_inline float2 max(const float2 &a, const float2 &b);
+ccl_device_inline float2 clamp(const float2 &a, const float2 &mn, const float2 &mx);
+ccl_device_inline float2 fabs(const float2 &a);
+ccl_device_inline float2 as_float2(const float4 &a);
+ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t);
+ccl_device_inline float2 floor(const float2 &a);
+
+ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b);
+
+/*******************************************************************************
+ * Definition.
+ */
+
+ccl_device_inline float2 zero_float2()
+{
+ return make_float2(0.0f, 0.0f);
+}
+
+ccl_device_inline float2 one_float2()
+{
+ return make_float2(1.0f, 1.0f);
+}
+
+ccl_device_inline float2 operator-(const float2 &a)
+{
+ return make_float2(-a.x, -a.y);
+}
+
+ccl_device_inline float2 operator*(const float2 &a, const float2 &b)
+{
+ return make_float2(a.x * b.x, a.y * b.y);
+}
+
+ccl_device_inline float2 operator*(const float2 &a, float f)
+{
+ return make_float2(a.x * f, a.y * f);
+}
+
+ccl_device_inline float2 operator*(float f, const float2 &a)
+{
+ return make_float2(a.x * f, a.y * f);
+}
+
+ccl_device_inline float2 operator/(float f, const float2 &a)
+{
+ return make_float2(f / a.x, f / a.y);
+}
+
+ccl_device_inline float2 operator/(const float2 &a, float f)
+{
+ float invf = 1.0f / f;
+ return make_float2(a.x * invf, a.y * invf);
+}
+
+ccl_device_inline float2 operator/(const float2 &a, const float2 &b)
+{
+ return make_float2(a.x / b.x, a.y / b.y);
+}
+
+ccl_device_inline float2 operator+(const float2 &a, const float f)
+{
+ return a + make_float2(f, f);
+}
+
+ccl_device_inline float2 operator+(const float2 &a, const float2 &b)
+{
+ return make_float2(a.x + b.x, a.y + b.y);
+}
+
+ccl_device_inline float2 operator-(const float2 &a, const float f)
+{
+ return a - make_float2(f, f);
+}
+
+ccl_device_inline float2 operator-(const float2 &a, const float2 &b)
+{
+ return make_float2(a.x - b.x, a.y - b.y);
+}
+
+ccl_device_inline float2 operator+=(float2 &a, const float2 &b)
+{
+ return a = a + b;
+}
+
+ccl_device_inline float2 operator*=(float2 &a, const float2 &b)
+{
+ return a = a * b;
+}
+
+ccl_device_inline float2 operator*=(float2 &a, float f)
+{
+ return a = a * f;
+}
+
+ccl_device_inline float2 operator/=(float2 &a, const float2 &b)
+{
+ return a = a / b;
+}
+
+ccl_device_inline float2 operator/=(float2 &a, float f)
+{
+ float invf = 1.0f / f;
+ return a = a * invf;
+}
+
+ccl_device_inline bool operator==(const float2 &a, const float2 &b)
+{
+ return (a.x == b.x && a.y == b.y);
+}
+
+ccl_device_inline bool operator!=(const float2 &a, const float2 &b)
+{
+ return !(a == b);
+}
+
+ccl_device_inline bool is_zero(const float2 &a)
+{
+ return (a.x == 0.0f && a.y == 0.0f);
+}
+
+ccl_device_inline float average(const float2 &a)
+{
+ return (a.x + a.y) * (1.0f / 2.0f);
+}
+
+ccl_device_inline float distance(const float2 &a, const float2 &b)
+{
+ return len(a - b);
+}
+
+ccl_device_inline float dot(const float2 &a, const float2 &b)
+{
+ return a.x * b.x + a.y * b.y;
+}
+
+ccl_device_inline float cross(const float2 &a, const float2 &b)
+{
+ return (a.x * b.y - a.y * b.x);
+}
+
+ccl_device_inline float len(const float2 &a)
+{
+ return sqrtf(dot(a, a));
+}
+
+ccl_device_inline float2 normalize(const float2 &a)
+{
+ return a / len(a);
+}
+
+ccl_device_inline float2 normalize_len(const float2 &a, ccl_private float *t)
+{
+ *t = len(a);
+ return a / (*t);
+}
+
+ccl_device_inline float2 safe_normalize(const float2 &a)
+{
+ float t = len(a);
+ return (t != 0.0f) ? a / t : a;
+}
+
+ccl_device_inline float2 min(const float2 &a, const float2 &b)
+{
+ return make_float2(min(a.x, b.x), min(a.y, b.y));
+}
+
+ccl_device_inline float2 max(const float2 &a, const float2 &b)
+{
+ return make_float2(max(a.x, b.x), max(a.y, b.y));
+}
+
+ccl_device_inline float2 clamp(const float2 &a, const float2 &mn, const float2 &mx)
+{
+ return min(max(a, mn), mx);
+}
+
+ccl_device_inline float2 fabs(const float2 &a)
+{
+ return make_float2(fabsf(a.x), fabsf(a.y));
+}
+
+ccl_device_inline float2 as_float2(const float4 &a)
+{
+ return make_float2(a.x, a.y);
+}
+
+ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t)
+{
+ return a + t * (b - a);
+}
+
+ccl_device_inline float2 mix(const float2 &a, const float2 &b, float t)
+{
+ return a + t * (b - a);
+}
+
+ccl_device_inline float2 floor(const float2 &a)
+{
+ return make_float2(floorf(a.x), floorf(a.y));
+}
+
+ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b)
+{
+ return (b != 0.0f) ? a / b : zero_float2();
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MATH_FLOAT2_H__ */
diff --git a/intern/cycles/util/math_float3.h b/intern/cycles/util/math_float3.h
new file mode 100644
index 00000000000..81550c5d03c
--- /dev/null
+++ b/intern/cycles/util/math_float3.h
@@ -0,0 +1,530 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_MATH_FLOAT3_H__
+#define __UTIL_MATH_FLOAT3_H__
+
+#ifndef __UTIL_MATH_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/*******************************************************************************
+ * Declaration.
+ */
+
+ccl_device_inline float3 operator-(const float3 &a);
+ccl_device_inline float3 operator*(const float3 &a, const float3 &b);
+ccl_device_inline float3 operator*(const float3 &a, const float f);
+ccl_device_inline float3 operator*(const float f, const float3 &a);
+ccl_device_inline float3 operator/(const float f, const float3 &a);
+ccl_device_inline float3 operator/(const float3 &a, const float f);
+ccl_device_inline float3 operator/(const float3 &a, const float3 &b);
+ccl_device_inline float3 operator+(const float3 &a, const float f);
+ccl_device_inline float3 operator+(const float3 &a, const float3 &b);
+ccl_device_inline float3 operator-(const float3 &a, const float f);
+ccl_device_inline float3 operator-(const float3 &a, const float3 &b);
+ccl_device_inline float3 operator+=(float3 &a, const float3 &b);
+ccl_device_inline float3 operator-=(float3 &a, const float3 &b);
+ccl_device_inline float3 operator*=(float3 &a, const float3 &b);
+ccl_device_inline float3 operator*=(float3 &a, float f);
+ccl_device_inline float3 operator/=(float3 &a, const float3 &b);
+ccl_device_inline float3 operator/=(float3 &a, float f);
+
+ccl_device_inline bool operator==(const float3 &a, const float3 &b);
+ccl_device_inline bool operator!=(const float3 &a, const float3 &b);
+
+ccl_device_inline float distance(const float3 &a, const float3 &b);
+ccl_device_inline float dot(const float3 &a, const float3 &b);
+ccl_device_inline float dot_xy(const float3 &a, const float3 &b);
+ccl_device_inline float3 cross(const float3 &a, const float3 &b);
+ccl_device_inline float3 normalize(const float3 &a);
+ccl_device_inline float3 min(const float3 &a, const float3 &b);
+ccl_device_inline float3 max(const float3 &a, const float3 &b);
+ccl_device_inline float3 clamp(const float3 &a, const float3 &mn, const float3 &mx);
+ccl_device_inline float3 fabs(const float3 &a);
+ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t);
+ccl_device_inline float3 rcp(const float3 &a);
+ccl_device_inline float3 sqrt(const float3 &a);
+ccl_device_inline float3 floor(const float3 &a);
+ccl_device_inline float3 ceil(const float3 &a);
+
+ccl_device_inline float min3(float3 a);
+ccl_device_inline float max3(float3 a);
+ccl_device_inline float len(const float3 a);
+ccl_device_inline float len_squared(const float3 a);
+
+ccl_device_inline float3 reflect(const float3 incident, const float3 normal);
+ccl_device_inline float3 project(const float3 v, const float3 v_proj);
+
+ccl_device_inline float3 saturate3(float3 a);
+ccl_device_inline float3 safe_normalize(const float3 a);
+ccl_device_inline float3 normalize_len(const float3 a, float *t);
+ccl_device_inline float3 safe_normalize_len(const float3 a, float *t);
+ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b);
+ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b);
+ccl_device_inline float3 interp(float3 a, float3 b, float t);
+ccl_device_inline float3 sqr3(float3 a);
+
+ccl_device_inline bool is_zero(const float3 a);
+ccl_device_inline float reduce_add(const float3 a);
+ccl_device_inline float average(const float3 a);
+ccl_device_inline bool isequal_float3(const float3 a, const float3 b);
+
+/*******************************************************************************
+ * Definition.
+ */
+
+ccl_device_inline float3 zero_float3()
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_setzero_ps());
+#else
+ return make_float3(0.0f, 0.0f, 0.0f);
+#endif
+}
+
+ccl_device_inline float3 one_float3()
+{
+ return make_float3(1.0f, 1.0f, 1.0f);
+}
+
+ccl_device_inline float3 operator-(const float3 &a)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_xor_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000))));
+#else
+ return make_float3(-a.x, -a.y, -a.z);
+#endif
+}
+
+ccl_device_inline float3 operator*(const float3 &a, const float3 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_mul_ps(a.m128, b.m128));
+#else
+ return make_float3(a.x * b.x, a.y * b.y, a.z * b.z);
+#endif
+}
+
+ccl_device_inline float3 operator*(const float3 &a, const float f)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_mul_ps(a.m128, _mm_set1_ps(f)));
+#else
+ return make_float3(a.x * f, a.y * f, a.z * f);
+#endif
+}
+
+ccl_device_inline float3 operator*(const float f, const float3 &a)
+{
+#if defined(__KERNEL_SSE__)
+ return float3(_mm_mul_ps(_mm_set1_ps(f), a.m128));
+#else
+ return make_float3(a.x * f, a.y * f, a.z * f);
+#endif
+}
+
+ccl_device_inline float3 operator/(const float f, const float3 &a)
+{
+#if defined(__KERNEL_SSE__)
+ return float3(_mm_div_ps(_mm_set1_ps(f), a.m128));
+#else
+ return make_float3(f / a.x, f / a.y, f / a.z);
+#endif
+}
+
+ccl_device_inline float3 operator/(const float3 &a, const float f)
+{
+ float invf = 1.0f / f;
+ return a * invf;
+}
+
+ccl_device_inline float3 operator/(const float3 &a, const float3 &b)
+{
+#if defined(__KERNEL_SSE__)
+ return float3(_mm_div_ps(a.m128, b.m128));
+#else
+ return make_float3(a.x / b.x, a.y / b.y, a.z / b.z);
+#endif
+}
+
+ccl_device_inline float3 operator+(const float3 &a, const float f)
+{
+ return a + make_float3(f, f, f);
+}
+
+ccl_device_inline float3 operator+(const float3 &a, const float3 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_add_ps(a.m128, b.m128));
+#else
+ return make_float3(a.x + b.x, a.y + b.y, a.z + b.z);
+#endif
+}
+
+ccl_device_inline float3 operator-(const float3 &a, const float f)
+{
+ return a - make_float3(f, f, f);
+}
+
+ccl_device_inline float3 operator-(const float3 &a, const float3 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_sub_ps(a.m128, b.m128));
+#else
+ return make_float3(a.x - b.x, a.y - b.y, a.z - b.z);
+#endif
+}
+
+ccl_device_inline float3 operator+=(float3 &a, const float3 &b)
+{
+ return a = a + b;
+}
+
+ccl_device_inline float3 operator-=(float3 &a, const float3 &b)
+{
+ return a = a - b;
+}
+
+ccl_device_inline float3 operator*=(float3 &a, const float3 &b)
+{
+ return a = a * b;
+}
+
+ccl_device_inline float3 operator*=(float3 &a, float f)
+{
+ return a = a * f;
+}
+
+ccl_device_inline float3 operator/=(float3 &a, const float3 &b)
+{
+ return a = a / b;
+}
+
+ccl_device_inline float3 operator/=(float3 &a, float f)
+{
+ float invf = 1.0f / f;
+ return a = a * invf;
+}
+
+ccl_device_inline bool operator==(const float3 &a, const float3 &b)
+{
+#ifdef __KERNEL_SSE__
+ return (_mm_movemask_ps(_mm_cmpeq_ps(a.m128, b.m128)) & 7) == 7;
+#else
+ return (a.x == b.x && a.y == b.y && a.z == b.z);
+#endif
+}
+
+ccl_device_inline bool operator!=(const float3 &a, const float3 &b)
+{
+ return !(a == b);
+}
+
+ccl_device_inline float distance(const float3 &a, const float3 &b)
+{
+ return len(a - b);
+}
+
+ccl_device_inline float dot(const float3 &a, const float3 &b)
+{
+#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
+ return _mm_cvtss_f32(_mm_dp_ps(a, b, 0x7F));
+#else
+ return a.x * b.x + a.y * b.y + a.z * b.z;
+#endif
+}
+
+ccl_device_inline float dot_xy(const float3 &a, const float3 &b)
+{
+#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
+ return _mm_cvtss_f32(_mm_hadd_ps(_mm_mul_ps(a, b), b));
+#else
+ return a.x * b.x + a.y * b.y;
+#endif
+}
+
+ccl_device_inline float3 cross(const float3 &a, const float3 &b)
+{
+ float3 r = make_float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
+ return r;
+}
+
+ccl_device_inline float3 normalize(const float3 &a)
+{
+#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
+ __m128 norm = _mm_sqrt_ps(_mm_dp_ps(a.m128, a.m128, 0x7F));
+ return float3(_mm_div_ps(a.m128, norm));
+#else
+ return a / len(a);
+#endif
+}
+
+ccl_device_inline float3 min(const float3 &a, const float3 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_min_ps(a.m128, b.m128));
+#else
+ return make_float3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
+#endif
+}
+
+ccl_device_inline float3 max(const float3 &a, const float3 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_max_ps(a.m128, b.m128));
+#else
+ return make_float3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
+#endif
+}
+
+ccl_device_inline float3 clamp(const float3 &a, const float3 &mn, const float3 &mx)
+{
+ return min(max(a, mn), mx);
+}
+
+ccl_device_inline float3 fabs(const float3 &a)
+{
+#ifdef __KERNEL_SSE__
+# ifdef __KERNEL_NEON__
+ return float3(vabsq_f32(a.m128));
+# else
+ __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
+ return float3(_mm_and_ps(a.m128, mask));
+# endif
+#else
+ return make_float3(fabsf(a.x), fabsf(a.y), fabsf(a.z));
+#endif
+}
+
+ccl_device_inline float3 sqrt(const float3 &a)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_sqrt_ps(a));
+#else
+ return make_float3(sqrtf(a.x), sqrtf(a.y), sqrtf(a.z));
+#endif
+}
+
+ccl_device_inline float3 floor(const float3 &a)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_floor_ps(a));
+#else
+ return make_float3(floorf(a.x), floorf(a.y), floorf(a.z));
+#endif
+}
+
+ccl_device_inline float3 ceil(const float3 &a)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_ceil_ps(a));
+#else
+ return make_float3(ceilf(a.x), ceilf(a.y), ceilf(a.z));
+#endif
+}
+
+ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t)
+{
+ return a + t * (b - a);
+}
+
+ccl_device_inline float3 rcp(const float3 &a)
+{
+#ifdef __KERNEL_SSE__
+ /* Don't use _mm_rcp_ps due to poor precision. */
+ return float3(_mm_div_ps(_mm_set_ps1(1.0f), a.m128));
+#else
+ return make_float3(1.0f / a.x, 1.0f / a.y, 1.0f / a.z);
+#endif
+}
+
+ccl_device_inline float min3(float3 a)
+{
+ return min(min(a.x, a.y), a.z);
+}
+
+ccl_device_inline float max3(float3 a)
+{
+ return max(max(a.x, a.y), a.z);
+}
+
+ccl_device_inline float len(const float3 a)
+{
+#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
+ return _mm_cvtss_f32(_mm_sqrt_ss(_mm_dp_ps(a.m128, a.m128, 0x7F)));
+#else
+ return sqrtf(dot(a, a));
+#endif
+}
+
+ccl_device_inline float len_squared(const float3 a)
+{
+ return dot(a, a);
+}
+
+ccl_device_inline float3 reflect(const float3 incident, const float3 normal)
+{
+ float3 unit_normal = normalize(normal);
+ return incident - 2.0f * unit_normal * dot(incident, unit_normal);
+}
+
+ccl_device_inline float3 refract(const float3 incident, const float3 normal, const float eta)
+{
+ float k = 1.0f - eta * eta * (1.0f - dot(normal, incident) * dot(normal, incident));
+ if (k < 0.0f)
+ return zero_float3();
+ else
+ return eta * incident - (eta * dot(normal, incident) + sqrt(k)) * normal;
+}
+
+ccl_device_inline float3 faceforward(const float3 vector,
+ const float3 incident,
+ const float3 reference)
+{
+ return (dot(reference, incident) < 0.0f) ? vector : -vector;
+}
+
+ccl_device_inline float3 project(const float3 v, const float3 v_proj)
+{
+ float len_squared = dot(v_proj, v_proj);
+ return (len_squared != 0.0f) ? (dot(v, v_proj) / len_squared) * v_proj : zero_float3();
+}
+
+ccl_device_inline float3 saturate3(float3 a)
+{
+ return make_float3(saturatef(a.x), saturatef(a.y), saturatef(a.z));
+}
+
+ccl_device_inline float3 normalize_len(const float3 a, ccl_private float *t)
+{
+ *t = len(a);
+ float x = 1.0f / *t;
+ return a * x;
+}
+
+ccl_device_inline float3 safe_normalize(const float3 a)
+{
+ float t = len(a);
+ return (t != 0.0f) ? a * (1.0f / t) : a;
+}
+
+ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t)
+{
+ *t = len(a);
+ return (*t != 0.0f) ? a / (*t) : a;
+}
+
+ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b)
+{
+ return make_float3((b.x != 0.0f) ? a.x / b.x : 0.0f,
+ (b.y != 0.0f) ? a.y / b.y : 0.0f,
+ (b.z != 0.0f) ? a.z / b.z : 0.0f);
+}
+
+ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b)
+{
+ return (b != 0.0f) ? a / b : zero_float3();
+}
+
+ccl_device_inline float3 interp(float3 a, float3 b, float t)
+{
+ return a + t * (b - a);
+}
+
+ccl_device_inline float3 sqr3(float3 a)
+{
+ return a * a;
+}
+
+ccl_device_inline bool is_zero(const float3 a)
+{
+#ifdef __KERNEL_SSE__
+ return a == make_float3(0.0f);
+#else
+ return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f);
+#endif
+}
+
+ccl_device_inline float reduce_add(const float3 a)
+{
+#if defined(__KERNEL_SSE__) && defined(__KERNEL_NEON__)
+ __m128 t = a.m128;
+ t[3] = 0.0f;
+ return vaddvq_f32(t);
+#else
+ return (a.x + a.y + a.z);
+#endif
+}
+
+ccl_device_inline float average(const float3 a)
+{
+ return reduce_add(a) * (1.0f / 3.0f);
+}
+
+ccl_device_inline bool isequal_float3(const float3 a, const float3 b)
+{
+ return a == b;
+}
+
+ccl_device_inline float3 pow3(float3 v, float e)
+{
+ return make_float3(powf(v.x, e), powf(v.y, e), powf(v.z, e));
+}
+
+ccl_device_inline float3 exp3(float3 v)
+{
+ return make_float3(expf(v.x), expf(v.y), expf(v.z));
+}
+
+ccl_device_inline float3 log3(float3 v)
+{
+ return make_float3(logf(v.x), logf(v.y), logf(v.z));
+}
+
+ccl_device_inline int3 quick_floor_to_int3(const float3 a)
+{
+#ifdef __KERNEL_SSE__
+ int3 b = int3(_mm_cvttps_epi32(a.m128));
+ int3 isneg = int3(_mm_castps_si128(_mm_cmplt_ps(a.m128, _mm_set_ps1(0.0f))));
+ /* Unsaturated add 0xffffffff is the same as subtract -1. */
+ return b + isneg;
+#else
+ return make_int3(quick_floor_to_int(a.x), quick_floor_to_int(a.y), quick_floor_to_int(a.z));
+#endif
+}
+
+ccl_device_inline bool isfinite3_safe(float3 v)
+{
+ return isfinite_safe(v.x) && isfinite_safe(v.y) && isfinite_safe(v.z);
+}
+
+ccl_device_inline float3 ensure_finite3(float3 v)
+{
+ if (!isfinite_safe(v.x))
+ v.x = 0.0f;
+ if (!isfinite_safe(v.y))
+ v.y = 0.0f;
+ if (!isfinite_safe(v.z))
+ v.z = 0.0f;
+ return v;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MATH_FLOAT3_H__ */
diff --git a/intern/cycles/util/math_float4.h b/intern/cycles/util/math_float4.h
new file mode 100644
index 00000000000..c76959ee7ff
--- /dev/null
+++ b/intern/cycles/util/math_float4.h
@@ -0,0 +1,536 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_MATH_FLOAT4_H__
+#define __UTIL_MATH_FLOAT4_H__
+
+#ifndef __UTIL_MATH_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/*******************************************************************************
+ * Declaration.
+ */
+
+ccl_device_inline float4 operator-(const float4 &a);
+ccl_device_inline float4 operator*(const float4 &a, const float4 &b);
+ccl_device_inline float4 operator*(const float4 &a, float f);
+ccl_device_inline float4 operator*(float f, const float4 &a);
+ccl_device_inline float4 operator/(const float4 &a, float f);
+ccl_device_inline float4 operator/(const float4 &a, const float4 &b);
+ccl_device_inline float4 operator+(const float4 &a, const float f);
+ccl_device_inline float4 operator+(const float4 &a, const float4 &b);
+ccl_device_inline float4 operator-(const float4 &a, const float f);
+ccl_device_inline float4 operator-(const float4 &a, const float4 &b);
+ccl_device_inline float4 operator+=(float4 &a, const float4 &b);
+ccl_device_inline float4 operator*=(float4 &a, const float4 &b);
+ccl_device_inline float4 operator*=(float4 &a, float f);
+ccl_device_inline float4 operator/=(float4 &a, float f);
+
+ccl_device_inline int4 operator<(const float4 &a, const float4 &b);
+ccl_device_inline int4 operator>=(const float4 &a, const float4 &b);
+ccl_device_inline int4 operator<=(const float4 &a, const float4 &b);
+ccl_device_inline bool operator==(const float4 &a, const float4 &b);
+
+ccl_device_inline float distance(const float4 &a, const float4 &b);
+ccl_device_inline float dot(const float4 &a, const float4 &b);
+ccl_device_inline float len_squared(const float4 &a);
+ccl_device_inline float4 rcp(const float4 &a);
+ccl_device_inline float4 sqrt(const float4 &a);
+ccl_device_inline float4 sqr(const float4 &a);
+ccl_device_inline float4 cross(const float4 &a, const float4 &b);
+ccl_device_inline bool is_zero(const float4 &a);
+ccl_device_inline float average(const float4 &a);
+ccl_device_inline float len(const float4 &a);
+ccl_device_inline float4 normalize(const float4 &a);
+ccl_device_inline float4 safe_normalize(const float4 &a);
+ccl_device_inline float4 min(const float4 &a, const float4 &b);
+ccl_device_inline float4 max(const float4 &a, const float4 &b);
+ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx);
+ccl_device_inline float4 fabs(const float4 &a);
+ccl_device_inline float4 floor(const float4 &a);
+ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t);
+
+ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b);
+
+#ifdef __KERNEL_SSE__
+template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
+__forceinline const float4 shuffle(const float4 &b);
+template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
+__forceinline const float4 shuffle(const float4 &a, const float4 &b);
+
+template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &b);
+
+template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &a, const float4 &b);
+template<> __forceinline const float4 shuffle<2, 3, 2, 3>(const float4 &a, const float4 &b);
+
+# ifdef __KERNEL_SSE3__
+template<> __forceinline const float4 shuffle<0, 0, 2, 2>(const float4 &b);
+template<> __forceinline const float4 shuffle<1, 1, 3, 3>(const float4 &b);
+# endif
+#endif /* __KERNEL_SSE__ */
+
+#ifndef __KERNEL_GPU__
+ccl_device_inline float4 select(const int4 &mask, const float4 &a, const float4 &b);
+ccl_device_inline float4 reduce_min(const float4 &a);
+ccl_device_inline float4 reduce_max(const float4 &a);
+ccl_device_inline float4 reduce_add(const float4 &a);
+#endif /* !__KERNEL_GPU__ */
+
+/*******************************************************************************
+ * Definition.
+ */
+
+ccl_device_inline float4 zero_float4()
+{
+#ifdef __KERNEL_SSE__
+ return float4(_mm_setzero_ps());
+#else
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+#endif
+}
+
+ccl_device_inline float4 one_float4()
+{
+ return make_float4(1.0f, 1.0f, 1.0f, 1.0f);
+}
+
+ccl_device_inline float4 operator-(const float4 &a)
+{
+#ifdef __KERNEL_SSE__
+ __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+ return float4(_mm_xor_ps(a.m128, mask));
+#else
+ return make_float4(-a.x, -a.y, -a.z, -a.w);
+#endif
+}
+
+ccl_device_inline float4 operator*(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float4(_mm_mul_ps(a.m128, b.m128));
+#else
+ return make_float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
+#endif
+}
+
+ccl_device_inline float4 operator*(const float4 &a, float f)
+{
+#if defined(__KERNEL_SSE__)
+ return a * make_float4(f);
+#else
+ return make_float4(a.x * f, a.y * f, a.z * f, a.w * f);
+#endif
+}
+
+ccl_device_inline float4 operator*(float f, const float4 &a)
+{
+ return a * f;
+}
+
+ccl_device_inline float4 operator/(const float4 &a, float f)
+{
+ return a * (1.0f / f);
+}
+
+ccl_device_inline float4 operator/(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float4(_mm_div_ps(a.m128, b.m128));
+#else
+ return make_float4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
+#endif
+}
+
+ccl_device_inline float4 operator+(const float4 &a, const float f)
+{
+ return a + make_float4(f, f, f, f);
+}
+
+ccl_device_inline float4 operator+(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float4(_mm_add_ps(a.m128, b.m128));
+#else
+ return make_float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
+#endif
+}
+
+ccl_device_inline float4 operator-(const float4 &a, const float f)
+{
+ return a - make_float4(f, f, f, f);
+}
+
+ccl_device_inline float4 operator-(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float4(_mm_sub_ps(a.m128, b.m128));
+#else
+ return make_float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
+#endif
+}
+
+ccl_device_inline float4 operator+=(float4 &a, const float4 &b)
+{
+ return a = a + b;
+}
+
+ccl_device_inline float4 operator-=(float4 &a, const float4 &b)
+{
+ return a = a - b;
+}
+
+ccl_device_inline float4 operator*=(float4 &a, const float4 &b)
+{
+ return a = a * b;
+}
+
+ccl_device_inline float4 operator*=(float4 &a, float f)
+{
+ return a = a * f;
+}
+
+ccl_device_inline float4 operator/=(float4 &a, float f)
+{
+ return a = a / f;
+}
+
+ccl_device_inline int4 operator<(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return int4(_mm_castps_si128(_mm_cmplt_ps(a.m128, b.m128)));
+#else
+ return make_int4(a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w);
+#endif
+}
+
+ccl_device_inline int4 operator>=(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return int4(_mm_castps_si128(_mm_cmpge_ps(a.m128, b.m128)));
+#else
+ return make_int4(a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w);
+#endif
+}
+
+ccl_device_inline int4 operator<=(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return int4(_mm_castps_si128(_mm_cmple_ps(a.m128, b.m128)));
+#else
+ return make_int4(a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w);
+#endif
+}
+
+ccl_device_inline bool operator==(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return (_mm_movemask_ps(_mm_cmpeq_ps(a.m128, b.m128)) & 15) == 15;
+#else
+ return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
+#endif
+}
+
+ccl_device_inline float distance(const float4 &a, const float4 &b)
+{
+ return len(a - b);
+}
+
+ccl_device_inline float dot(const float4 &a, const float4 &b)
+{
+#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
+# if defined(__KERNEL_NEON__)
+ __m128 t = vmulq_f32(a, b);
+ return vaddvq_f32(t);
+# else
+ return _mm_cvtss_f32(_mm_dp_ps(a, b, 0xFF));
+# endif
+#else
+ return (a.x * b.x + a.y * b.y) + (a.z * b.z + a.w * b.w);
+#endif
+}
+
+ccl_device_inline float len_squared(const float4 &a)
+{
+ return dot(a, a);
+}
+
+ccl_device_inline float4 rcp(const float4 &a)
+{
+#ifdef __KERNEL_SSE__
+ /* Don't use _mm_rcp_ps due to poor precision. */
+ return float4(_mm_div_ps(_mm_set_ps1(1.0f), a.m128));
+#else
+ return make_float4(1.0f / a.x, 1.0f / a.y, 1.0f / a.z, 1.0f / a.w);
+#endif
+}
+
+ccl_device_inline float4 sqrt(const float4 &a)
+{
+#ifdef __KERNEL_SSE__
+ return float4(_mm_sqrt_ps(a.m128));
+#else
+ return make_float4(sqrtf(a.x), sqrtf(a.y), sqrtf(a.z), sqrtf(a.w));
+#endif
+}
+
+ccl_device_inline float4 sqr(const float4 &a)
+{
+ return a * a;
+}
+
+ccl_device_inline float4 cross(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return (shuffle<1, 2, 0, 0>(a) * shuffle<2, 0, 1, 0>(b)) -
+ (shuffle<2, 0, 1, 0>(a) * shuffle<1, 2, 0, 0>(b));
+#else
+ return make_float4(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x, 0.0f);
+#endif
+}
+
+ccl_device_inline bool is_zero(const float4 &a)
+{
+#ifdef __KERNEL_SSE__
+ return a == make_float4(0.0f);
+#else
+ return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f && a.w == 0.0f);
+#endif
+}
+
+ccl_device_inline float4 reduce_add(const float4 &a)
+{
+#if defined(__KERNEL_SSE__)
+# if defined(__KERNEL_NEON__)
+ return float4(vdupq_n_f32(vaddvq_f32(a)));
+# elif defined(__KERNEL_SSE3__)
+ float4 h(_mm_hadd_ps(a.m128, a.m128));
+ return float4(_mm_hadd_ps(h.m128, h.m128));
+# else
+ float4 h(shuffle<1, 0, 3, 2>(a) + a);
+ return shuffle<2, 3, 0, 1>(h) + h;
+# endif
+#else
+ float sum = (a.x + a.y) + (a.z + a.w);
+ return make_float4(sum, sum, sum, sum);
+#endif
+}
+
+ccl_device_inline float average(const float4 &a)
+{
+ return reduce_add(a).x * 0.25f;
+}
+
+ccl_device_inline float len(const float4 &a)
+{
+ return sqrtf(dot(a, a));
+}
+
+ccl_device_inline float4 normalize(const float4 &a)
+{
+ return a / len(a);
+}
+
+ccl_device_inline float4 safe_normalize(const float4 &a)
+{
+ float t = len(a);
+ return (t != 0.0f) ? a / t : a;
+}
+
+ccl_device_inline float4 min(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float4(_mm_min_ps(a.m128, b.m128));
+#else
+ return make_float4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w));
+#endif
+}
+
+ccl_device_inline float4 max(const float4 &a, const float4 &b)
+{
+#ifdef __KERNEL_SSE__
+ return float4(_mm_max_ps(a.m128, b.m128));
+#else
+ return make_float4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w));
+#endif
+}
+
+ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx)
+{
+ return min(max(a, mn), mx);
+}
+
+ccl_device_inline float4 fabs(const float4 &a)
+{
+#if defined(__KERNEL_SSE__)
+# if defined(__KERNEL_NEON__)
+ return float4(vabsq_f32(a));
+# else
+ return float4(_mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))));
+# endif
+#else
+ return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w));
+#endif
+}
+
+ccl_device_inline float4 floor(const float4 &a)
+{
+#ifdef __KERNEL_SSE__
+ return float4(_mm_floor_ps(a));
+#else
+ return make_float4(floorf(a.x), floorf(a.y), floorf(a.z), floorf(a.w));
+#endif
+}
+
+ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t)
+{
+ return a + t * (b - a);
+}
+
+#ifdef __KERNEL_SSE__
+template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
+__forceinline const float4 shuffle(const float4 &b)
+{
+# if defined(__KERNEL_NEON__)
+ return float4(shuffle_neon<__m128, index_0, index_1, index_2, index_3>(b.m128));
+# else
+ return float4(_mm_castsi128_ps(
+ _mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(index_3, index_2, index_1, index_0))));
+# endif
+}
+
+template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
+__forceinline const float4 shuffle(const float4 &a, const float4 &b)
+{
+# if defined(__KERNEL_NEON__)
+ return float4(shuffle_neon<__m128, index_0, index_1, index_2, index_3>(a.m128, b.m128));
+# else
+ return float4(_mm_shuffle_ps(a.m128, b.m128, _MM_SHUFFLE(index_3, index_2, index_1, index_0)));
+# endif
+}
+
+template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &b)
+{
+ return float4(_mm_castpd_ps(_mm_movedup_pd(_mm_castps_pd(b))));
+}
+
+template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &a, const float4 &b)
+{
+ return float4(_mm_movelh_ps(a.m128, b.m128));
+}
+
+template<> __forceinline const float4 shuffle<2, 3, 2, 3>(const float4 &a, const float4 &b)
+{
+ return float4(_mm_movehl_ps(b.m128, a.m128));
+}
+
+# ifdef __KERNEL_SSE3__
+template<> __forceinline const float4 shuffle<0, 0, 2, 2>(const float4 &b)
+{
+ return float4(_mm_moveldup_ps(b));
+}
+
+template<> __forceinline const float4 shuffle<1, 1, 3, 3>(const float4 &b)
+{
+ return float4(_mm_movehdup_ps(b));
+}
+# endif /* __KERNEL_SSE3__ */
+#endif /* __KERNEL_SSE__ */
+
+#ifndef __KERNEL_GPU__
+ccl_device_inline float4 select(const int4 &mask, const float4 &a, const float4 &b)
+{
+# ifdef __KERNEL_SSE__
+ return float4(_mm_blendv_ps(b.m128, a.m128, _mm_castsi128_ps(mask.m128)));
+# else
+ return make_float4(
+ (mask.x) ? a.x : b.x, (mask.y) ? a.y : b.y, (mask.z) ? a.z : b.z, (mask.w) ? a.w : b.w);
+# endif
+}
+
+ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
+{
+ /* Replace elements of x with zero where mask isn't set. */
+ return select(mask, a, make_float4(0.0f));
+}
+
+ccl_device_inline float4 reduce_min(const float4 &a)
+{
+# if defined(__KERNEL_SSE__)
+# if defined(__KERNEL_NEON__)
+ return float4(vdupq_n_f32(vminvq_f32(a)));
+# else
+ float4 h = min(shuffle<1, 0, 3, 2>(a), a);
+ return min(shuffle<2, 3, 0, 1>(h), h);
+# endif
+# else
+ return make_float4(min(min(a.x, a.y), min(a.z, a.w)));
+# endif
+}
+
+ccl_device_inline float4 reduce_max(const float4 &a)
+{
+# if defined(__KERNEL_SSE__)
+# if defined(__KERNEL_NEON__)
+ return float4(vdupq_n_f32(vmaxvq_f32(a)));
+# else
+ float4 h = max(shuffle<1, 0, 3, 2>(a), a);
+ return max(shuffle<2, 3, 0, 1>(h), h);
+# endif
+# else
+ return make_float4(max(max(a.x, a.y), max(a.z, a.w)));
+# endif
+}
+
+ccl_device_inline float4 load_float4(ccl_private const float *v)
+{
+# ifdef __KERNEL_SSE__
+ return float4(_mm_loadu_ps(v));
+# else
+ return make_float4(v[0], v[1], v[2], v[3]);
+# endif
+}
+
+#endif /* !__KERNEL_GPU__ */
+
+ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b)
+{
+ return (b != 0.0f) ? a / b : zero_float4();
+}
+
+ccl_device_inline bool isfinite4_safe(float4 v)
+{
+ return isfinite_safe(v.x) && isfinite_safe(v.y) && isfinite_safe(v.z) && isfinite_safe(v.w);
+}
+
+ccl_device_inline float4 ensure_finite4(float4 v)
+{
+ if (!isfinite_safe(v.x))
+ v.x = 0.0f;
+ if (!isfinite_safe(v.y))
+ v.y = 0.0f;
+ if (!isfinite_safe(v.z))
+ v.z = 0.0f;
+ if (!isfinite_safe(v.w))
+ v.w = 0.0f;
+ return v;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MATH_FLOAT4_H__ */
diff --git a/intern/cycles/util/math_int2.h b/intern/cycles/util/math_int2.h
new file mode 100644
index 00000000000..5b04be92152
--- /dev/null
+++ b/intern/cycles/util/math_int2.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_MATH_INT2_H__
+#define __UTIL_MATH_INT2_H__
+
+#ifndef __UTIL_MATH_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/*******************************************************************************
+ * Declaration.
+ */
+
+ccl_device_inline bool operator==(const int2 a, const int2 b);
+ccl_device_inline int2 operator+(const int2 &a, const int2 &b);
+ccl_device_inline int2 operator+=(int2 &a, const int2 &b);
+ccl_device_inline int2 operator-(const int2 &a, const int2 &b);
+ccl_device_inline int2 operator*(const int2 &a, const int2 &b);
+ccl_device_inline int2 operator/(const int2 &a, const int2 &b);
+
+/*******************************************************************************
+ * Definition.
+ */
+
+ccl_device_inline bool operator==(const int2 a, const int2 b)
+{
+ return (a.x == b.x && a.y == b.y);
+}
+
+ccl_device_inline int2 operator+(const int2 &a, const int2 &b)
+{
+ return make_int2(a.x + b.x, a.y + b.y);
+}
+
+ccl_device_inline int2 operator+=(int2 &a, const int2 &b)
+{
+ return a = a + b;
+}
+
+ccl_device_inline int2 operator-(const int2 &a, const int2 &b)
+{
+ return make_int2(a.x - b.x, a.y - b.y);
+}
+
+ccl_device_inline int2 operator*(const int2 &a, const int2 &b)
+{
+ return make_int2(a.x * b.x, a.y * b.y);
+}
+
+ccl_device_inline int2 operator/(const int2 &a, const int2 &b)
+{
+ return make_int2(a.x / b.x, a.y / b.y);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MATH_INT2_H__ */
diff --git a/intern/cycles/util/math_int3.h b/intern/cycles/util/math_int3.h
new file mode 100644
index 00000000000..128f2cb53b8
--- /dev/null
+++ b/intern/cycles/util/math_int3.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_MATH_INT3_H__
+#define __UTIL_MATH_INT3_H__
+
+#ifndef __UTIL_MATH_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/*******************************************************************************
+ * Declaration.
+ */
+
+ccl_device_inline int3 min(int3 a, int3 b);
+ccl_device_inline int3 max(int3 a, int3 b);
+ccl_device_inline int3 clamp(const int3 &a, int mn, int mx);
+ccl_device_inline int3 clamp(const int3 &a, int3 &mn, int mx);
+
+/*******************************************************************************
+ * Definition.
+ */
+
+ccl_device_inline int3 min(int3 a, int3 b)
+{
+#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__)
+ return int3(_mm_min_epi32(a.m128, b.m128));
+#else
+ return make_int3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
+#endif
+}
+
+ccl_device_inline int3 max(int3 a, int3 b)
+{
+#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__)
+ return int3(_mm_max_epi32(a.m128, b.m128));
+#else
+ return make_int3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
+#endif
+}
+
+ccl_device_inline int3 clamp(const int3 &a, int mn, int mx)
+{
+#ifdef __KERNEL_SSE__
+ return min(max(a, make_int3(mn)), make_int3(mx));
+#else
+ return make_int3(clamp(a.x, mn, mx), clamp(a.y, mn, mx), clamp(a.z, mn, mx));
+#endif
+}
+
+ccl_device_inline int3 clamp(const int3 &a, int3 &mn, int mx)
+{
+#ifdef __KERNEL_SSE__
+ return min(max(a, mn), make_int3(mx));
+#else
+ return make_int3(clamp(a.x, mn.x, mx), clamp(a.y, mn.y, mx), clamp(a.z, mn.z, mx));
+#endif
+}
+
+ccl_device_inline bool operator==(const int3 &a, const int3 &b)
+{
+ return a.x == b.x && a.y == b.y && a.z == b.z;
+}
+
+ccl_device_inline bool operator!=(const int3 &a, const int3 &b)
+{
+ return !(a == b);
+}
+
+ccl_device_inline bool operator<(const int3 &a, const int3 &b)
+{
+ return a.x < b.x && a.y < b.y && a.z < b.z;
+}
+
+ccl_device_inline int3 operator+(const int3 &a, const int3 &b)
+{
+#ifdef __KERNEL_SSE__
+ return int3(_mm_add_epi32(a.m128, b.m128));
+#else
+ return make_int3(a.x + b.x, a.y + b.y, a.z + b.z);
+#endif
+}
+
+ccl_device_inline int3 operator-(const int3 &a, const int3 &b)
+{
+#ifdef __KERNEL_SSE__
+ return int3(_mm_sub_epi32(a.m128, b.m128));
+#else
+ return make_int3(a.x - b.x, a.y - b.y, a.z - b.z);
+#endif
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MATH_INT3_H__ */
diff --git a/intern/cycles/util/math_int4.h b/intern/cycles/util/math_int4.h
new file mode 100644
index 00000000000..9e3f001efc2
--- /dev/null
+++ b/intern/cycles/util/math_int4.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_MATH_INT4_H__
+#define __UTIL_MATH_INT4_H__
+
+#ifndef __UTIL_MATH_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/*******************************************************************************
+ * Declaration.
+ */
+
+#ifndef __KERNEL_GPU__
+ccl_device_inline int4 operator+(const int4 &a, const int4 &b);
+ccl_device_inline int4 operator+=(int4 &a, const int4 &b);
+ccl_device_inline int4 operator>>(const int4 &a, int i);
+ccl_device_inline int4 operator<<(const int4 &a, int i);
+ccl_device_inline int4 operator<(const int4 &a, const int4 &b);
+ccl_device_inline int4 operator>=(const int4 &a, const int4 &b);
+ccl_device_inline int4 operator&(const int4 &a, const int4 &b);
+ccl_device_inline int4 min(int4 a, int4 b);
+ccl_device_inline int4 max(int4 a, int4 b);
+ccl_device_inline int4 clamp(const int4 &a, const int4 &mn, const int4 &mx);
+ccl_device_inline int4 select(const int4 &mask, const int4 &a, const int4 &b);
+#endif /* __KERNEL_GPU__ */
+
+/*******************************************************************************
+ * Definition.
+ */
+
+#ifndef __KERNEL_GPU__
+ccl_device_inline int4 operator+(const int4 &a, const int4 &b)
+{
+# ifdef __KERNEL_SSE__
+ return int4(_mm_add_epi32(a.m128, b.m128));
+# else
+ return make_int4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
+# endif
+}
+
+ccl_device_inline int4 operator+=(int4 &a, const int4 &b)
+{
+ return a = a + b;
+}
+
+ccl_device_inline int4 operator>>(const int4 &a, int i)
+{
+# ifdef __KERNEL_SSE__
+ return int4(_mm_srai_epi32(a.m128, i));
+# else
+ return make_int4(a.x >> i, a.y >> i, a.z >> i, a.w >> i);
+# endif
+}
+
+ccl_device_inline int4 operator<<(const int4 &a, int i)
+{
+# ifdef __KERNEL_SSE__
+ return int4(_mm_slli_epi32(a.m128, i));
+# else
+ return make_int4(a.x << i, a.y << i, a.z << i, a.w << i);
+# endif
+}
+
+ccl_device_inline int4 operator<(const int4 &a, const int4 &b)
+{
+# ifdef __KERNEL_SSE__
+ return int4(_mm_cmplt_epi32(a.m128, b.m128));
+# else
+ return make_int4(a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w);
+# endif
+}
+
+ccl_device_inline int4 operator>=(const int4 &a, const int4 &b)
+{
+# ifdef __KERNEL_SSE__
+ return int4(_mm_xor_si128(_mm_set1_epi32(0xffffffff), _mm_cmplt_epi32(a.m128, b.m128)));
+# else
+ return make_int4(a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w);
+# endif
+}
+
+ccl_device_inline int4 operator&(const int4 &a, const int4 &b)
+{
+# ifdef __KERNEL_SSE__
+ return int4(_mm_and_si128(a.m128, b.m128));
+# else
+ return make_int4(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);
+# endif
+}
+
+ccl_device_inline int4 min(int4 a, int4 b)
+{
+# if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__)
+ return int4(_mm_min_epi32(a.m128, b.m128));
+# else
+ return make_int4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w));
+# endif
+}
+
+ccl_device_inline int4 max(int4 a, int4 b)
+{
+# if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__)
+ return int4(_mm_max_epi32(a.m128, b.m128));
+# else
+ return make_int4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w));
+# endif
+}
+
+ccl_device_inline int4 clamp(const int4 &a, const int4 &mn, const int4 &mx)
+{
+ return min(max(a, mn), mx);
+}
+
+ccl_device_inline int4 select(const int4 &mask, const int4 &a, const int4 &b)
+{
+# ifdef __KERNEL_SSE__
+ const __m128 m = _mm_cvtepi32_ps(mask);
+ /* TODO(sergey): avoid cvt. */
+ return int4(_mm_castps_si128(
+ _mm_or_ps(_mm_and_ps(m, _mm_castsi128_ps(a)), _mm_andnot_ps(m, _mm_castsi128_ps(b)))));
+# else
+ return make_int4(
+ (mask.x) ? a.x : b.x, (mask.y) ? a.y : b.y, (mask.z) ? a.z : b.z, (mask.w) ? a.w : b.w);
+# endif
+}
+
+ccl_device_inline int4 load_int4(const int *v)
+{
+# ifdef __KERNEL_SSE__
+ return int4(_mm_loadu_si128((__m128i *)v));
+# else
+ return make_int4(v[0], v[1], v[2], v[3]);
+# endif
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MATH_INT4_H__ */
diff --git a/intern/cycles/util/util_math_intersect.h b/intern/cycles/util/math_intersect.h
index 0c431a36afb..0c431a36afb 100644
--- a/intern/cycles/util/util_math_intersect.h
+++ b/intern/cycles/util/math_intersect.h
diff --git a/intern/cycles/util/util_math_matrix.h b/intern/cycles/util/math_matrix.h
index bff7ddb4cee..bff7ddb4cee 100644
--- a/intern/cycles/util/util_math_matrix.h
+++ b/intern/cycles/util/math_matrix.h
diff --git a/intern/cycles/util/md5.cpp b/intern/cycles/util/md5.cpp
new file mode 100644
index 00000000000..47e489b1aed
--- /dev/null
+++ b/intern/cycles/util/md5.cpp
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * L. Peter Deutsch
+ * ghost@aladdin.com
+ */
+
+/* Minor modifications done to remove some code and change style. */
+
+#include "util/md5.h"
+#include "util/path.h"
+
+#include <stdio.h>
+#include <string.h>
+
+CCL_NAMESPACE_BEGIN
+
+#define T_MASK ((uint32_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+void MD5Hash::process(const uint8_t *data /*[64]*/)
+{
+ uint32_t a = abcd[0], b = abcd[1], c = abcd[2], d = abcd[3];
+ uint32_t t;
+ /* Define storage for little-endian or both types of CPUs. */
+ uint32_t xbuf[16];
+ const uint32_t *X;
+
+ {
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const uint8_t *)&w)) /* dynamic little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const uint8_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const uint32_t *)data;
+ }
+ else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+ else { /* dynamic big-endian */
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const uint8_t *xp = data;
+ int i;
+
+ X = xbuf; /* (dynamic only) */
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ * a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + F(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ * a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + G(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ * a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + H(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ * a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + I(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ * of the four registers by the value it had before this block
+ * was started.) */
+ abcd[0] += a;
+ abcd[1] += b;
+ abcd[2] += c;
+ abcd[3] += d;
+}
+
+MD5Hash::MD5Hash()
+{
+ count[0] = count[1] = 0;
+ abcd[0] = 0x67452301;
+ abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ abcd[3] = 0x10325476;
+}
+
+MD5Hash::~MD5Hash()
+{
+}
+
+void MD5Hash::append(const uint8_t *data, int nbytes)
+{
+ const uint8_t *p = data;
+ int left = nbytes;
+ int offset = (count[0] >> 3) & 63;
+ uint32_t nbits = (uint32_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ count[1] += nbytes >> 29;
+ count[0] += nbits;
+ if (count[0] < nbits)
+ count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ process(buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ process(p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(buf, p, left);
+}
+
+void MD5Hash::append(const string &str)
+{
+ if (str.size()) {
+ append((const uint8_t *)str.c_str(), str.size());
+ }
+}
+
+bool MD5Hash::append_file(const string &filepath)
+{
+ FILE *f = path_fopen(filepath, "rb");
+
+ if (!f) {
+ fprintf(stderr, "MD5: failed to open file %s\n", filepath.c_str());
+ return false;
+ }
+
+ const size_t buffer_size = 1024;
+ uint8_t buffer[buffer_size];
+ size_t n;
+
+ do {
+ n = fread(buffer, 1, buffer_size, f);
+ append(buffer, n);
+ } while (n == buffer_size);
+
+ bool success = (ferror(f) == 0);
+
+ fclose(f);
+
+ return success;
+}
+
+void MD5Hash::finish(uint8_t digest[16])
+{
+ static const uint8_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ uint8_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (uint8_t)(count[i >> 2] >> ((i & 3) << 3));
+
+ /* Pad to 56 bytes mod 64. */
+ append(pad, ((55 - (count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ append(data, 8);
+
+ for (i = 0; i < 16; ++i)
+ digest[i] = (uint8_t)(abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+string MD5Hash::get_hex()
+{
+ uint8_t digest[16];
+ char buf[16 * 2 + 1];
+
+ finish(digest);
+
+ for (int i = 0; i < 16; i++)
+ sprintf(buf + i * 2, "%02X", (unsigned int)digest[i]);
+ buf[sizeof(buf) - 1] = '\0';
+
+ return string(buf);
+}
+
+string util_md5_string(const string &str)
+{
+ MD5Hash md5;
+ md5.append((uint8_t *)str.c_str(), str.size());
+ return md5.get_hex();
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/md5.h b/intern/cycles/util/md5.h
new file mode 100644
index 00000000000..cc7cbef6a49
--- /dev/null
+++ b/intern/cycles/util/md5.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * L. Peter Deutsch
+ * ghost@aladdin.com
+ */
+
+/* MD5
+ *
+ * Simply MD5 hash computation, used by disk cache. Adapted from external
+ * code, with minor code modifications done to remove some unused code and
+ * change code style. */
+
+#ifndef __UTIL_MD5_H__
+#define __UTIL_MD5_H__
+
+#include "util/string.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class MD5Hash {
+ public:
+ MD5Hash();
+ ~MD5Hash();
+
+ void append(const uint8_t *data, int size);
+ void append(const string &str);
+ bool append_file(const string &filepath);
+ string get_hex();
+
+ protected:
+ void process(const uint8_t *data);
+ void finish(uint8_t digest[16]);
+
+ uint32_t count[2]; /* message length in bits, LSW first. */
+ uint32_t abcd[4]; /* digest buffer */
+ uint8_t buf[64]; /* accumulate block */
+};
+
+string util_md5_string(const string &str);
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MD5_H__ */
diff --git a/intern/cycles/util/murmurhash.cpp b/intern/cycles/util/murmurhash.cpp
new file mode 100644
index 00000000000..9ba0a282cc2
--- /dev/null
+++ b/intern/cycles/util/murmurhash.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This is taken from alShaders/Cryptomatte/MurmurHash3.h:
+ *
+ * MurmurHash3 was written by Austin Appleby, and is placed in the public
+ * domain. The author hereby disclaims copyright to this source code.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "util/algorithm.h"
+#include "util/murmurhash.h"
+
+#if defined(_MSC_VER)
+# define ROTL32(x, y) _rotl(x, y)
+# define ROTL64(x, y) _rotl64(x, y)
+# define BIG_CONSTANT(x) (x)
+#else
+ccl_device_inline uint32_t rotl32(uint32_t x, int8_t r)
+{
+ return (x << r) | (x >> (32 - r));
+}
+# define ROTL32(x, y) rotl32(x, y)
+# define BIG_CONSTANT(x) (x##LLU)
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* Block read - if your platform needs to do endian-swapping or can only
+ * handle aligned reads, do the conversion here. */
+ccl_device_inline uint32_t mm_hash_getblock32(const uint32_t *p, int i)
+{
+ return p[i];
+}
+
+/* Finalization mix - force all bits of a hash block to avalanche */
+ccl_device_inline uint32_t mm_hash_fmix32(uint32_t h)
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+ return h;
+}
+
+uint32_t util_murmur_hash3(const void *key, int len, uint32_t seed)
+{
+ const uint8_t *data = (const uint8_t *)key;
+ const int nblocks = len / 4;
+
+ uint32_t h1 = seed;
+
+ const uint32_t c1 = 0xcc9e2d51;
+ const uint32_t c2 = 0x1b873593;
+
+ const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
+
+ for (int i = -nblocks; i; i++) {
+ uint32_t k1 = mm_hash_getblock32(blocks, i);
+
+ k1 *= c1;
+ k1 = ROTL32(k1, 15);
+ k1 *= c2;
+
+ h1 ^= k1;
+ h1 = ROTL32(h1, 13);
+ h1 = h1 * 5 + 0xe6546b64;
+ }
+
+ const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
+
+ uint32_t k1 = 0;
+
+ switch (len & 3) {
+ case 3:
+ k1 ^= tail[2] << 16;
+ ATTR_FALLTHROUGH;
+ case 2:
+ k1 ^= tail[1] << 8;
+ ATTR_FALLTHROUGH;
+ case 1:
+ k1 ^= tail[0];
+ k1 *= c1;
+ k1 = ROTL32(k1, 15);
+ k1 *= c2;
+ h1 ^= k1;
+ }
+
+ h1 ^= len;
+ h1 = mm_hash_fmix32(h1);
+ return h1;
+}
+
+/* This is taken from the cryptomatte specification 1.0 */
+float util_hash_to_float(uint32_t hash)
+{
+ uint32_t mantissa = hash & ((1 << 23) - 1);
+ uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
+ exponent = max(exponent, (uint32_t)1);
+ exponent = min(exponent, (uint32_t)254);
+ exponent = exponent << 23;
+ uint32_t sign = (hash >> 31);
+ sign = sign << 31;
+ uint32_t float_bits = sign | exponent | mantissa;
+ float f;
+ memcpy(&f, &float_bits, sizeof(uint32_t));
+ return f;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/murmurhash.h b/intern/cycles/util/murmurhash.h
new file mode 100644
index 00000000000..7c303db6ffa
--- /dev/null
+++ b/intern/cycles/util/murmurhash.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_MURMURHASH_H__
+#define __UTIL_MURMURHASH_H__
+
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+uint32_t util_murmur_hash3(const void *key, int len, uint32_t seed);
+float util_hash_to_float(uint32_t hash);
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MURMURHASH_H__ */
diff --git a/intern/cycles/util/util_opengl.h b/intern/cycles/util/opengl.h
index 7a8d5eec1f9..7a8d5eec1f9 100644
--- a/intern/cycles/util/util_opengl.h
+++ b/intern/cycles/util/opengl.h
diff --git a/intern/cycles/util/openimagedenoise.h b/intern/cycles/util/openimagedenoise.h
new file mode 100644
index 00000000000..cc7b14ae18f
--- /dev/null
+++ b/intern/cycles/util/openimagedenoise.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_OPENIMAGEDENOISE_H__
+#define __UTIL_OPENIMAGEDENOISE_H__
+
+#ifdef WITH_OPENIMAGEDENOISE
+# include <OpenImageDenoise/oidn.hpp>
+#endif
+
+#include "util/system.h"
+
+CCL_NAMESPACE_BEGIN
+
+static inline bool openimagedenoise_supported()
+{
+#ifdef WITH_OPENIMAGEDENOISE
+# ifdef __APPLE__
+ /* Always supported through Accelerate framework BNNS. */
+ return true;
+# else
+ return system_cpu_support_sse41();
+# endif
+#else
+ return false;
+#endif
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_OPENIMAGEDENOISE_H__ */
diff --git a/intern/cycles/util/util_openvdb.h b/intern/cycles/util/openvdb.h
index ae5326e3199..ae5326e3199 100644
--- a/intern/cycles/util/util_openvdb.h
+++ b/intern/cycles/util/openvdb.h
diff --git a/intern/cycles/util/util_optimization.h b/intern/cycles/util/optimization.h
index 7ecd3893cf4..7ecd3893cf4 100644
--- a/intern/cycles/util/util_optimization.h
+++ b/intern/cycles/util/optimization.h
diff --git a/intern/cycles/util/util_param.h b/intern/cycles/util/param.h
index 3f8e2d6d700..3f8e2d6d700 100644
--- a/intern/cycles/util/util_param.h
+++ b/intern/cycles/util/param.h
diff --git a/intern/cycles/util/path.cpp b/intern/cycles/util/path.cpp
new file mode 100644
index 00000000000..5704c4ef8ef
--- /dev/null
+++ b/intern/cycles/util/path.cpp
@@ -0,0 +1,781 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/path.h"
+#include "util/md5.h"
+#include "util/string.h"
+
+#include <OpenImageIO/filesystem.h>
+#include <OpenImageIO/strutil.h>
+#include <OpenImageIO/sysutil.h>
+
+OIIO_NAMESPACE_USING
+
+#include <stdio.h>
+
+#include <sys/stat.h>
+
+#if defined(_WIN32)
+# define DIR_SEP '\\'
+# define DIR_SEP_ALT '/'
+# include <direct.h>
+#else
+# define DIR_SEP '/'
+# include <dirent.h>
+# include <pwd.h>
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_SHLWAPI_H
+# include <shlwapi.h>
+#endif
+
+#include "util/map.h"
+#include "util/windows.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef _WIN32
+# if defined(_MSC_VER) || defined(__MINGW64__)
+typedef struct _stat64 path_stat_t;
+# elif defined(__MINGW32__)
+typedef struct _stati64 path_stat_t;
+# else
+typedef struct _stat path_stat_t;
+# endif
+# ifndef S_ISDIR
+# define S_ISDIR(x) (((x)&_S_IFDIR) == _S_IFDIR)
+# endif
+#else
+typedef struct stat path_stat_t;
+#endif
+
+static string cached_path = "";
+static string cached_user_path = "";
+static string cached_temp_path = "";
+static string cached_xdg_cache_path = "";
+
+namespace {
+
+#ifdef _WIN32
+class directory_iterator {
+ public:
+ class path_info {
+ public:
+ path_info(const string &path, const WIN32_FIND_DATAW &find_data)
+ : path_(path), find_data_(find_data)
+ {
+ }
+
+ string path()
+ {
+ return path_join(path_, string_from_wstring(find_data_.cFileName));
+ }
+
+ protected:
+ const string &path_;
+ const WIN32_FIND_DATAW &find_data_;
+ };
+
+ directory_iterator() : path_info_("", find_data_), h_find_(INVALID_HANDLE_VALUE)
+ {
+ }
+
+ explicit directory_iterator(const string &path) : path_(path), path_info_(path, find_data_)
+ {
+ string wildcard = path;
+ if (wildcard[wildcard.size() - 1] != DIR_SEP) {
+ wildcard += DIR_SEP;
+ }
+ wildcard += "*";
+ h_find_ = FindFirstFileW(string_to_wstring(wildcard).c_str(), &find_data_);
+ if (h_find_ != INVALID_HANDLE_VALUE) {
+ skip_dots();
+ }
+ }
+
+ ~directory_iterator()
+ {
+ if (h_find_ != INVALID_HANDLE_VALUE) {
+ FindClose(h_find_);
+ }
+ }
+
+ directory_iterator &operator++()
+ {
+ step();
+ return *this;
+ }
+
+ path_info *operator->()
+ {
+ return &path_info_;
+ }
+
+ bool operator!=(const directory_iterator &other)
+ {
+ return h_find_ != other.h_find_;
+ }
+
+ protected:
+ bool step()
+ {
+ if (do_step()) {
+ return skip_dots();
+ }
+ return false;
+ }
+
+ bool do_step()
+ {
+ if (h_find_ != INVALID_HANDLE_VALUE) {
+ bool result = FindNextFileW(h_find_, &find_data_) == TRUE;
+ if (!result) {
+ FindClose(h_find_);
+ h_find_ = INVALID_HANDLE_VALUE;
+ }
+ return result;
+ }
+ return false;
+ }
+
+ bool skip_dots()
+ {
+ while (wcscmp(find_data_.cFileName, L".") == 0 || wcscmp(find_data_.cFileName, L"..") == 0) {
+ if (!do_step()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ string path_;
+ path_info path_info_;
+ WIN32_FIND_DATAW find_data_;
+ HANDLE h_find_;
+};
+#else /* _WIN32 */
+
+class directory_iterator {
+ public:
+ class path_info {
+ public:
+ explicit path_info(const string &path) : path_(path), entry_(NULL)
+ {
+ }
+
+ string path()
+ {
+ return path_join(path_, entry_->d_name);
+ }
+
+ void current_entry_set(const struct dirent *entry)
+ {
+ entry_ = entry;
+ }
+
+ protected:
+ const string &path_;
+ const struct dirent *entry_;
+ };
+
+ directory_iterator() : path_info_(""), name_list_(NULL), num_entries_(-1), cur_entry_(-1)
+ {
+ }
+
+ explicit directory_iterator(const string &path) : path_(path), path_info_(path_), cur_entry_(0)
+ {
+ num_entries_ = scandir(path.c_str(), &name_list_, NULL, alphasort);
+ if (num_entries_ < 0) {
+ perror("scandir");
+ }
+ else {
+ skip_dots();
+ }
+ }
+
+ ~directory_iterator()
+ {
+ destroy_name_list();
+ }
+
+ directory_iterator &operator++()
+ {
+ step();
+ return *this;
+ }
+
+ path_info *operator->()
+ {
+ path_info_.current_entry_set(name_list_[cur_entry_]);
+ return &path_info_;
+ }
+
+ bool operator!=(const directory_iterator &other)
+ {
+ return name_list_ != other.name_list_;
+ }
+
+ protected:
+ bool step()
+ {
+ if (do_step()) {
+ return skip_dots();
+ }
+ return false;
+ }
+
+ bool do_step()
+ {
+ ++cur_entry_;
+ if (cur_entry_ >= num_entries_) {
+ destroy_name_list();
+ return false;
+ }
+ return true;
+ }
+
+ /* Skip . and .. folders. */
+ bool skip_dots()
+ {
+ while (strcmp(name_list_[cur_entry_]->d_name, ".") == 0 ||
+ strcmp(name_list_[cur_entry_]->d_name, "..") == 0) {
+ if (!step()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void destroy_name_list()
+ {
+ if (name_list_ == NULL) {
+ return;
+ }
+ for (int i = 0; i < num_entries_; ++i) {
+ free(name_list_[i]);
+ }
+ free(name_list_);
+ name_list_ = NULL;
+ }
+
+ string path_;
+ path_info path_info_;
+ struct dirent **name_list_;
+ int num_entries_, cur_entry_;
+};
+
+#endif /* _WIN32 */
+
+size_t find_last_slash(const string &path)
+{
+ for (size_t i = 0; i < path.size(); ++i) {
+ size_t index = path.size() - 1 - i;
+#ifdef _WIN32
+ if (path[index] == DIR_SEP || path[index] == DIR_SEP_ALT)
+#else
+ if (path[index] == DIR_SEP)
+#endif
+ {
+ return index;
+ }
+ }
+ return string::npos;
+}
+
+} /* namespace */
+
+static char *path_specials(const string &sub)
+{
+ static bool env_init = false;
+ static char *env_shader_path;
+ static char *env_source_path;
+ if (!env_init) {
+ env_shader_path = getenv("CYCLES_SHADER_PATH");
+ /* NOTE: It is KERNEL in env variable for compatibility reasons. */
+ env_source_path = getenv("CYCLES_KERNEL_PATH");
+ env_init = true;
+ }
+ if (env_shader_path != NULL && sub == "shader") {
+ return env_shader_path;
+ }
+ else if (env_shader_path != NULL && sub == "source") {
+ return env_source_path;
+ }
+ return NULL;
+}
+
+#if defined(__linux__) || defined(__APPLE__)
+static string path_xdg_cache_get()
+{
+ const char *home = getenv("XDG_CACHE_HOME");
+ if (home) {
+ return string(home);
+ }
+ else {
+ home = getenv("HOME");
+ if (home == NULL) {
+ home = getpwuid(getuid())->pw_dir;
+ }
+ return path_join(string(home), ".cache");
+ }
+}
+#endif
+
+void path_init(const string &path, const string &user_path, const string &temp_path)
+{
+ cached_path = path;
+ cached_user_path = user_path;
+ cached_temp_path = temp_path;
+
+#ifdef _MSC_VER
+ // workaround for https://svn.boost.org/trac/boost/ticket/6320
+ // indirectly init boost codec here since it's not thread safe, and can
+ // cause crashes when it happens in multithreaded image load
+ OIIO::Filesystem::exists(path);
+#endif
+}
+
+string path_get(const string &sub)
+{
+ char *special = path_specials(sub);
+ if (special != NULL)
+ return special;
+
+ if (cached_path == "")
+ cached_path = path_dirname(Sysutil::this_program_path());
+
+ return path_join(cached_path, sub);
+}
+
+string path_user_get(const string &sub)
+{
+ if (cached_user_path == "")
+ cached_user_path = path_dirname(Sysutil::this_program_path());
+
+ return path_join(cached_user_path, sub);
+}
+
+string path_cache_get(const string &sub)
+{
+#if defined(__linux__) || defined(__APPLE__)
+ if (cached_xdg_cache_path == "") {
+ cached_xdg_cache_path = path_xdg_cache_get();
+ }
+ string result = path_join(cached_xdg_cache_path, "cycles");
+ return path_join(result, sub);
+#else
+ /* TODO(sergey): What that should be on Windows? */
+ return path_user_get(path_join("cache", sub));
+#endif
+}
+
+string path_temp_get(const string &sub)
+{
+ if (cached_temp_path == "") {
+ cached_temp_path = Filesystem::temp_directory_path();
+ }
+
+ return path_join(cached_temp_path, sub);
+}
+
+#if defined(__linux__) || defined(__APPLE__)
+string path_xdg_home_get(const string &sub = "");
+#endif
+
+string path_filename(const string &path)
+{
+ size_t index = find_last_slash(path);
+ if (index != string::npos) {
+ /* Corner cases to match boost behavior. */
+#ifndef _WIN32
+ if (index == 0 && path.size() == 1) {
+ return path;
+ }
+#endif
+ if (index == path.size() - 1) {
+#ifdef _WIN32
+ if (index == 2) {
+ return string(1, DIR_SEP);
+ }
+#endif
+ return ".";
+ }
+ return path.substr(index + 1, path.size() - index - 1);
+ }
+ return path;
+}
+
+string path_dirname(const string &path)
+{
+ size_t index = find_last_slash(path);
+ if (index != string::npos) {
+#ifndef _WIN32
+ if (index == 0 && path.size() > 1) {
+ return string(1, DIR_SEP);
+ }
+#endif
+ return path.substr(0, index);
+ }
+ return "";
+}
+
+string path_join(const string &dir, const string &file)
+{
+ if (dir.size() == 0) {
+ return file;
+ }
+ if (file.size() == 0) {
+ return dir;
+ }
+ string result = dir;
+#ifndef _WIN32
+ if (result[result.size() - 1] != DIR_SEP && file[0] != DIR_SEP)
+#else
+ if (result[result.size() - 1] != DIR_SEP && result[result.size() - 1] != DIR_SEP_ALT &&
+ file[0] != DIR_SEP && file[0] != DIR_SEP_ALT)
+#endif
+ {
+ result += DIR_SEP;
+ }
+ result += file;
+ return result;
+}
+
+string path_escape(const string &path)
+{
+ string result = path;
+ string_replace(result, " ", "\\ ");
+ return result;
+}
+
+bool path_is_relative(const string &path)
+{
+#ifdef _WIN32
+# ifdef HAVE_SHLWAPI_H
+ return PathIsRelative(path.c_str());
+# else /* HAVE_SHLWAPI_H */
+ if (path.size() >= 3) {
+ return !(((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) &&
+ path[1] == ':' && path[2] == DIR_SEP);
+ }
+ return true;
+# endif /* HAVE_SHLWAPI_H */
+#else /* _WIN32 */
+ if (path.size() == 0) {
+ return 1;
+ }
+ return path[0] != DIR_SEP;
+#endif /* _WIN32 */
+}
+
+#ifdef _WIN32
+/* Add a slash if the UNC path points to a share. */
+static string path_unc_add_slash_to_share(const string &path)
+{
+ size_t slash_after_server = path.find(DIR_SEP, 2);
+ if (slash_after_server != string::npos) {
+ size_t slash_after_share = path.find(DIR_SEP, slash_after_server + 1);
+ if (slash_after_share == string::npos) {
+ return path + DIR_SEP;
+ }
+ }
+ return path;
+}
+
+/* Convert:
+ * \\?\UNC\server\share\folder\... to \\server\share\folder\...
+ * \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
+ */
+static string path_unc_to_short(const string &path)
+{
+ size_t len = path.size();
+ if ((len > 3) && (path[0] == DIR_SEP) && (path[1] == DIR_SEP) && (path[2] == '?') &&
+ ((path[3] == DIR_SEP) || (path[3] == DIR_SEP_ALT))) {
+ if ((len > 5) && (path[5] == ':')) {
+ return path.substr(4, len - 4);
+ }
+ else if ((len > 7) && (path.substr(4, 3) == "UNC") &&
+ ((path[7] == DIR_SEP) || (path[7] == DIR_SEP_ALT))) {
+ return "\\\\" + path.substr(8, len - 8);
+ }
+ }
+ return path;
+}
+
+static string path_cleanup_unc(const string &path)
+{
+ string result = path_unc_to_short(path);
+ if (path.size() > 2) {
+ /* It's possible path is now a non-UNC. */
+ if (result[0] == DIR_SEP && result[1] == DIR_SEP) {
+ return path_unc_add_slash_to_share(result);
+ }
+ }
+ return result;
+}
+
+/* Make path compatible for stat() functions. */
+static string path_make_compatible(const string &path)
+{
+ string result = path;
+ /* In Windows stat() doesn't recognize dir ending on a slash. */
+ if (result.size() > 3 && result[result.size() - 1] == DIR_SEP) {
+ result.resize(result.size() - 1);
+ }
+ /* Clean up UNC path. */
+ if ((path.size() >= 3) && (path[0] == DIR_SEP) && (path[1] == DIR_SEP)) {
+ result = path_cleanup_unc(result);
+ }
+ /* Make sure volume-only path ends up wit ha directory separator. */
+ if (result.size() == 2 && result[1] == ':') {
+ result += DIR_SEP;
+ }
+ return result;
+}
+
+static int path_wstat(const wstring &path_wc, path_stat_t *st)
+{
+# if defined(_MSC_VER) || defined(__MINGW64__)
+ return _wstat64(path_wc.c_str(), st);
+# elif defined(__MINGW32__)
+ return _wstati64(path_wc.c_str(), st);
+# else
+ return _wstat(path_wc.c_str(), st);
+# endif
+}
+
+static int path_stat(const string &path, path_stat_t *st)
+{
+ wstring path_wc = string_to_wstring(path);
+ return path_wstat(path_wc, st);
+}
+#else /* _WIN32 */
+static int path_stat(const string &path, path_stat_t *st)
+{
+ return stat(path.c_str(), st);
+}
+#endif /* _WIN32 */
+
+size_t path_file_size(const string &path)
+{
+ path_stat_t st;
+ if (path_stat(path, &st) != 0) {
+ return -1;
+ }
+ return st.st_size;
+}
+
+bool path_exists(const string &path)
+{
+#ifdef _WIN32
+ string fixed_path = path_make_compatible(path);
+ wstring path_wc = string_to_wstring(fixed_path);
+ path_stat_t st;
+ if (path_wstat(path_wc, &st) != 0) {
+ return false;
+ }
+ return st.st_mode != 0;
+#else /* _WIN32 */
+ struct stat st;
+ if (stat(path.c_str(), &st) != 0) {
+ return 0;
+ }
+ return st.st_mode != 0;
+#endif /* _WIN32 */
+}
+
+bool path_is_directory(const string &path)
+{
+ path_stat_t st;
+ if (path_stat(path, &st) != 0) {
+ return false;
+ }
+ return S_ISDIR(st.st_mode);
+}
+
+static void path_files_md5_hash_recursive(MD5Hash &hash, const string &dir)
+{
+ if (path_exists(dir)) {
+ directory_iterator it(dir), it_end;
+
+ for (; it != it_end; ++it) {
+ if (path_is_directory(it->path())) {
+ path_files_md5_hash_recursive(hash, it->path());
+ }
+ else {
+ string filepath = it->path();
+
+ hash.append((const uint8_t *)filepath.c_str(), filepath.size());
+ hash.append_file(filepath);
+ }
+ }
+ }
+}
+
+string path_files_md5_hash(const string &dir)
+{
+ /* computes md5 hash of all files in the directory */
+ MD5Hash hash;
+
+ path_files_md5_hash_recursive(hash, dir);
+
+ return hash.get_hex();
+}
+
+static bool create_directories_recursivey(const string &path)
+{
+ if (path_is_directory(path)) {
+ /* Directory already exists, nothing to do. */
+ return true;
+ }
+ if (path_exists(path)) {
+ /* File exists and it's not a directory. */
+ return false;
+ }
+
+ string parent = path_dirname(path);
+ if (parent.size() > 0 && parent != path) {
+ if (!create_directories_recursivey(parent)) {
+ return false;
+ }
+ }
+
+#ifdef _WIN32
+ wstring path_wc = string_to_wstring(path);
+ return _wmkdir(path_wc.c_str()) == 0;
+#else
+ return mkdir(path.c_str(), 0777) == 0;
+#endif
+}
+
+void path_create_directories(const string &filepath)
+{
+ string path = path_dirname(filepath);
+ create_directories_recursivey(path);
+}
+
+bool path_write_binary(const string &path, const vector<uint8_t> &binary)
+{
+ path_create_directories(path);
+
+ /* write binary file from memory */
+ FILE *f = path_fopen(path, "wb");
+
+ if (!f)
+ return false;
+
+ if (binary.size() > 0)
+ fwrite(&binary[0], sizeof(uint8_t), binary.size(), f);
+
+ fclose(f);
+
+ return true;
+}
+
+bool path_write_text(const string &path, string &text)
+{
+ vector<uint8_t> binary(text.length(), 0);
+ std::copy(text.begin(), text.end(), binary.begin());
+
+ return path_write_binary(path, binary);
+}
+
+bool path_read_binary(const string &path, vector<uint8_t> &binary)
+{
+ /* read binary file into memory */
+ FILE *f = path_fopen(path, "rb");
+
+ if (!f) {
+ binary.resize(0);
+ return false;
+ }
+
+ binary.resize(path_file_size(path));
+
+ if (binary.size() == 0) {
+ fclose(f);
+ return false;
+ }
+
+ if (fread(&binary[0], sizeof(uint8_t), binary.size(), f) != binary.size()) {
+ fclose(f);
+ return false;
+ }
+
+ fclose(f);
+
+ return true;
+}
+
+bool path_read_text(const string &path, string &text)
+{
+ vector<uint8_t> binary;
+
+ if (!path_exists(path) || !path_read_binary(path, binary))
+ return false;
+
+ const char *str = (const char *)&binary[0];
+ size_t size = binary.size();
+ text = string(str, size);
+
+ return true;
+}
+
+uint64_t path_modified_time(const string &path)
+{
+ path_stat_t st;
+ if (path_stat(path, &st) != 0) {
+ return 0;
+ }
+ return st.st_mtime;
+}
+
+bool path_remove(const string &path)
+{
+ return remove(path.c_str()) == 0;
+}
+
+FILE *path_fopen(const string &path, const string &mode)
+{
+#ifdef _WIN32
+ wstring path_wc = string_to_wstring(path);
+ wstring mode_wc = string_to_wstring(mode);
+ return _wfopen(path_wc.c_str(), mode_wc.c_str());
+#else
+ return fopen(path.c_str(), mode.c_str());
+#endif
+}
+
+void path_cache_clear_except(const string &name, const set<string> &except)
+{
+ string dir = path_user_get("cache");
+
+ if (path_exists(dir)) {
+ directory_iterator it(dir), it_end;
+
+ for (; it != it_end; ++it) {
+ string filename = path_filename(it->path());
+
+ if (string_startswith(filename, name.c_str()))
+ if (except.find(filename) == except.end())
+ path_remove(it->path());
+ }
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/path.h b/intern/cycles/util/path.h
new file mode 100644
index 00000000000..a1394555302
--- /dev/null
+++ b/intern/cycles/util/path.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_PATH_H__
+#define __UTIL_PATH_H__
+
+/* Utility functions to get paths to files distributed with the program. For
+ * the standalone apps, paths are relative to the executable, for dynamically
+ * linked libraries, the path to the library may be set with path_init, which
+ * then makes all paths relative to that. */
+
+#include <stdio.h>
+
+#include "util/set.h"
+#include "util/string.h"
+#include "util/types.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* program paths */
+void path_init(const string &path = "", const string &user_path = "", const string &tmp_path = "");
+string path_get(const string &sub = "");
+string path_user_get(const string &sub = "");
+string path_temp_get(const string &sub = "");
+string path_cache_get(const string &sub = "");
+
+/* path string manipulation */
+string path_filename(const string &path);
+string path_dirname(const string &path);
+string path_join(const string &dir, const string &file);
+string path_escape(const string &path);
+bool path_is_relative(const string &path);
+
+/* file info */
+size_t path_file_size(const string &path);
+bool path_exists(const string &path);
+bool path_is_directory(const string &path);
+string path_files_md5_hash(const string &dir);
+uint64_t path_modified_time(const string &path);
+
+/* directory utility */
+void path_create_directories(const string &path);
+
+/* file read/write utilities */
+FILE *path_fopen(const string &path, const string &mode);
+
+bool path_write_binary(const string &path, const vector<uint8_t> &binary);
+bool path_write_text(const string &path, string &text);
+bool path_read_binary(const string &path, vector<uint8_t> &binary);
+bool path_read_text(const string &path, string &text);
+
+/* File manipulation. */
+bool path_remove(const string &path);
+
+/* cache utility */
+void path_cache_clear_except(const string &name, const set<string> &except);
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/util/profiling.cpp b/intern/cycles/util/profiling.cpp
new file mode 100644
index 00000000000..55b35b7320f
--- /dev/null
+++ b/intern/cycles/util/profiling.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/profiling.h"
+#include "util/algorithm.h"
+#include "util/foreach.h"
+#include "util/set.h"
+
+CCL_NAMESPACE_BEGIN
+
+Profiler::Profiler() : do_stop_worker(true), worker(NULL)
+{
+}
+
+Profiler::~Profiler()
+{
+ assert(worker == NULL);
+}
+
+void Profiler::run()
+{
+ uint64_t updates = 0;
+ auto start_time = std::chrono::system_clock::now();
+ while (!do_stop_worker) {
+ thread_scoped_lock lock(mutex);
+ foreach (ProfilingState *state, states) {
+ uint32_t cur_event = state->event;
+ int32_t cur_shader = state->shader;
+ int32_t cur_object = state->object;
+
+ /* The state reads/writes should be atomic, but just to be sure
+ * check the values for validity anyways. */
+ if (cur_event < PROFILING_NUM_EVENTS) {
+ event_samples[cur_event]++;
+ }
+
+ if (cur_shader >= 0 && cur_shader < shader_samples.size()) {
+ shader_samples[cur_shader]++;
+ }
+
+ if (cur_object >= 0 && cur_object < object_samples.size()) {
+ object_samples[cur_object]++;
+ }
+ }
+ lock.unlock();
+
+ /* Relative waits always overshoot a bit, so just waiting 1ms every
+ * time would cause the sampling to drift over time.
+ * By keeping track of the absolute time, the wait times correct themselves -
+ * if one wait overshoots a lot, the next one will be shorter to compensate. */
+ updates++;
+ std::this_thread::sleep_until(start_time + updates * std::chrono::milliseconds(1));
+ }
+}
+
+void Profiler::reset(int num_shaders, int num_objects)
+{
+ bool running = (worker != NULL);
+ if (running) {
+ stop();
+ }
+
+ /* Resize and clear the accumulation vectors. */
+ shader_hits.assign(num_shaders, 0);
+ object_hits.assign(num_objects, 0);
+
+ event_samples.assign(PROFILING_NUM_EVENTS, 0);
+ shader_samples.assign(num_shaders, 0);
+ object_samples.assign(num_objects, 0);
+
+ if (running) {
+ start();
+ }
+}
+
+void Profiler::start()
+{
+ assert(worker == NULL);
+ do_stop_worker = false;
+ worker = new thread(function_bind(&Profiler::run, this));
+}
+
+void Profiler::stop()
+{
+ if (worker != NULL) {
+ do_stop_worker = true;
+
+ worker->join();
+ delete worker;
+ worker = NULL;
+ }
+}
+
+void Profiler::add_state(ProfilingState *state)
+{
+ thread_scoped_lock lock(mutex);
+
+ /* Add the ProfilingState from the list of sampled states. */
+ assert(std::find(states.begin(), states.end(), state) == states.end());
+ states.push_back(state);
+
+ /* Resize thread-local hit counters. */
+ state->shader_hits.assign(shader_hits.size(), 0);
+ state->object_hits.assign(object_hits.size(), 0);
+
+ /* Initialize the state. */
+ state->event = PROFILING_UNKNOWN;
+ state->shader = -1;
+ state->object = -1;
+ state->active = true;
+}
+
+void Profiler::remove_state(ProfilingState *state)
+{
+ thread_scoped_lock lock(mutex);
+
+ /* Remove the ProfilingState from the list of sampled states. */
+ states.erase(std::remove(states.begin(), states.end(), state), states.end());
+ state->active = false;
+
+ /* Merge thread-local hit counters. */
+ assert(shader_hits.size() == state->shader_hits.size());
+ for (int i = 0; i < shader_hits.size(); i++) {
+ shader_hits[i] += state->shader_hits[i];
+ }
+
+ assert(object_hits.size() == state->object_hits.size());
+ for (int i = 0; i < object_hits.size(); i++) {
+ object_hits[i] += state->object_hits[i];
+ }
+}
+
+uint64_t Profiler::get_event(ProfilingEvent event)
+{
+ assert(worker == NULL);
+ return event_samples[event];
+}
+
+bool Profiler::get_shader(int shader, uint64_t &samples, uint64_t &hits)
+{
+ assert(worker == NULL);
+ if (shader_samples[shader] == 0) {
+ return false;
+ }
+ samples = shader_samples[shader];
+ hits = shader_hits[shader];
+ return true;
+}
+
+bool Profiler::get_object(int object, uint64_t &samples, uint64_t &hits)
+{
+ assert(worker == NULL);
+ if (object_samples[object] == 0) {
+ return false;
+ }
+ samples = object_samples[object];
+ hits = object_hits[object];
+ return true;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/profiling.h b/intern/cycles/util/profiling.h
new file mode 100644
index 00000000000..b30aac90879
--- /dev/null
+++ b/intern/cycles/util/profiling.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_PROFILING_H__
+#define __UTIL_PROFILING_H__
+
+#include <atomic>
+
+#include "util/map.h"
+#include "util/thread.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+enum ProfilingEvent : uint32_t {
+ PROFILING_UNKNOWN,
+ PROFILING_RAY_SETUP,
+
+ PROFILING_INTERSECT_CLOSEST,
+ PROFILING_INTERSECT_SUBSURFACE,
+ PROFILING_INTERSECT_SHADOW,
+ PROFILING_INTERSECT_VOLUME_STACK,
+
+ PROFILING_SHADE_SURFACE_SETUP,
+ PROFILING_SHADE_SURFACE_EVAL,
+ PROFILING_SHADE_SURFACE_DIRECT_LIGHT,
+ PROFILING_SHADE_SURFACE_INDIRECT_LIGHT,
+ PROFILING_SHADE_SURFACE_AO,
+ PROFILING_SHADE_SURFACE_PASSES,
+
+ PROFILING_SHADE_VOLUME_SETUP,
+ PROFILING_SHADE_VOLUME_INTEGRATE,
+ PROFILING_SHADE_VOLUME_DIRECT_LIGHT,
+ PROFILING_SHADE_VOLUME_INDIRECT_LIGHT,
+
+ PROFILING_SHADE_SHADOW_SETUP,
+ PROFILING_SHADE_SHADOW_SURFACE,
+ PROFILING_SHADE_SHADOW_VOLUME,
+
+ PROFILING_SHADE_LIGHT_SETUP,
+ PROFILING_SHADE_LIGHT_EVAL,
+
+ PROFILING_NUM_EVENTS,
+};
+
+/* Contains the current execution state of a worker thread.
+ * These values are constantly updated by the worker.
+ * Periodically the profiler thread will wake up, read them
+ * and update its internal counters based on it.
+ *
+ * Atomics aren't needed here since we're only doing direct
+ * writes and reads to (4-byte-aligned) uint32_t, which is
+ * guaranteed to be atomic on x86 since the 486.
+ * Memory ordering is not guaranteed but does not matter.
+ *
+ * And even on other architectures, the extremely rare corner
+ * case of reading an intermediate state could at worst result
+ * in a single incorrect sample. */
+struct ProfilingState {
+ volatile uint32_t event = PROFILING_UNKNOWN;
+ volatile int32_t shader = -1;
+ volatile int32_t object = -1;
+ volatile bool active = false;
+
+ vector<uint64_t> shader_hits;
+ vector<uint64_t> object_hits;
+};
+
+class Profiler {
+ public:
+ Profiler();
+ ~Profiler();
+
+ void reset(int num_shaders, int num_objects);
+
+ void start();
+ void stop();
+
+ void add_state(ProfilingState *state);
+ void remove_state(ProfilingState *state);
+
+ uint64_t get_event(ProfilingEvent event);
+ bool get_shader(int shader, uint64_t &samples, uint64_t &hits);
+ bool get_object(int object, uint64_t &samples, uint64_t &hits);
+
+ protected:
+ void run();
+
+ /* Tracks how often the worker was in each ProfilingEvent while sampling,
+ * so multiplying the values by the sample frequency (currently 1ms)
+ * gives the approximate time spent in each state. */
+ vector<uint64_t> event_samples;
+ vector<uint64_t> shader_samples;
+ vector<uint64_t> object_samples;
+
+ /* Tracks the total amounts every object/shader was hit.
+ * Used to evaluate relative cost, written by the render thread.
+ * Indexed by the shader and object IDs that the kernel also uses
+ * to index __object_flag and __shaders. */
+ vector<uint64_t> shader_hits;
+ vector<uint64_t> object_hits;
+
+ volatile bool do_stop_worker;
+ thread *worker;
+
+ thread_mutex mutex;
+ vector<ProfilingState *> states;
+};
+
+class ProfilingHelper {
+ public:
+ ProfilingHelper(ProfilingState *state, ProfilingEvent event) : state(state)
+ {
+ previous_event = state->event;
+ state->event = event;
+ }
+
+ ~ProfilingHelper()
+ {
+ state->event = previous_event;
+ }
+
+ inline void set_event(ProfilingEvent event)
+ {
+ state->event = event;
+ }
+
+ protected:
+ ProfilingState *state;
+ uint32_t previous_event;
+};
+
+class ProfilingWithShaderHelper : public ProfilingHelper {
+ public:
+ ProfilingWithShaderHelper(ProfilingState *state, ProfilingEvent event)
+ : ProfilingHelper(state, event)
+ {
+ }
+
+ ~ProfilingWithShaderHelper()
+ {
+ state->object = -1;
+ state->shader = -1;
+ }
+
+ inline void set_shader(int object, int shader)
+ {
+ if (state->active) {
+ state->shader = shader;
+ state->object = object;
+
+ if (shader >= 0) {
+ assert(shader < state->shader_hits.size());
+ state->shader_hits[shader]++;
+ }
+
+ if (object >= 0) {
+ assert(object < state->object_hits.size());
+ state->object_hits[object]++;
+ }
+ }
+ }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_PROFILING_H__ */
diff --git a/intern/cycles/util/progress.h b/intern/cycles/util/progress.h
new file mode 100644
index 00000000000..4b0ff08aa7e
--- /dev/null
+++ b/intern/cycles/util/progress.h
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_PROGRESS_H__
+#define __UTIL_PROGRESS_H__
+
+/* Progress
+ *
+ * Simple class to communicate progress status messages, timing information,
+ * update notifications from a job running in another thread. All methods
+ * except for the constructor/destructor are thread safe. */
+
+#include "util/function.h"
+#include "util/string.h"
+#include "util/thread.h"
+#include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Progress {
+ public:
+ Progress()
+ {
+ pixel_samples = 0;
+ total_pixel_samples = 0;
+ current_tile_sample = 0;
+ rendered_tiles = 0;
+ denoised_tiles = 0;
+ start_time = time_dt();
+ render_start_time = time_dt();
+ end_time = 0.0;
+ status = "Initializing";
+ substatus = "";
+ sync_status = "";
+ sync_substatus = "";
+ update_cb = function_null;
+ cancel = false;
+ cancel_message = "";
+ error = false;
+ error_message = "";
+ cancel_cb = function_null;
+ }
+
+ Progress(Progress &progress)
+ {
+ *this = progress;
+ }
+
+ Progress &operator=(Progress &progress)
+ {
+ thread_scoped_lock lock(progress.progress_mutex);
+
+ progress.get_status(status, substatus);
+
+ pixel_samples = progress.pixel_samples;
+ total_pixel_samples = progress.total_pixel_samples;
+ current_tile_sample = progress.get_current_sample();
+
+ return *this;
+ }
+
+ void reset()
+ {
+ pixel_samples = 0;
+ total_pixel_samples = 0;
+ current_tile_sample = 0;
+ rendered_tiles = 0;
+ denoised_tiles = 0;
+ start_time = time_dt();
+ render_start_time = time_dt();
+ end_time = 0.0;
+ status = "Initializing";
+ substatus = "";
+ sync_status = "";
+ sync_substatus = "";
+ cancel = false;
+ cancel_message = "";
+ error = false;
+ error_message = "";
+ }
+
+ /* cancel */
+ void set_cancel(const string &cancel_message_)
+ {
+ thread_scoped_lock lock(progress_mutex);
+ cancel_message = cancel_message_;
+ cancel = true;
+ }
+
+ bool get_cancel() const
+ {
+ if (!cancel && cancel_cb)
+ cancel_cb();
+
+ return cancel;
+ }
+
+ string get_cancel_message() const
+ {
+ thread_scoped_lock lock(progress_mutex);
+ return cancel_message;
+ }
+
+ void set_cancel_callback(function<void()> function)
+ {
+ cancel_cb = function;
+ }
+
+ /* error */
+ void set_error(const string &error_message_)
+ {
+ thread_scoped_lock lock(progress_mutex);
+ error_message = error_message_;
+ error = true;
+ /* If error happens we also stop rendering. */
+ cancel_message = error_message_;
+ cancel = true;
+ }
+
+ bool get_error() const
+ {
+ return error;
+ }
+
+ string get_error_message() const
+ {
+ thread_scoped_lock lock(progress_mutex);
+ return error_message;
+ }
+
+ /* tile and timing information */
+
+ void set_start_time()
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ start_time = time_dt();
+ end_time = 0.0;
+ }
+
+ void set_render_start_time()
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ render_start_time = time_dt();
+ }
+
+ void add_skip_time(const scoped_timer &start_timer, bool only_render)
+ {
+ double skip_time = time_dt() - start_timer.get_start();
+
+ render_start_time += skip_time;
+ if (!only_render) {
+ start_time += skip_time;
+ }
+ }
+
+ void get_time(double &total_time_, double &render_time_) const
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ double time = (end_time > 0) ? end_time : time_dt();
+
+ total_time_ = time - start_time;
+ render_time_ = time - render_start_time;
+ }
+
+ void set_end_time()
+ {
+ end_time = time_dt();
+ }
+
+ void reset_sample()
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ pixel_samples = 0;
+ current_tile_sample = 0;
+ rendered_tiles = 0;
+ denoised_tiles = 0;
+ }
+
+ void set_total_pixel_samples(uint64_t total_pixel_samples_)
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ total_pixel_samples = total_pixel_samples_;
+ }
+
+ float get_progress() const
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ if (total_pixel_samples > 0) {
+ return ((float)pixel_samples) / total_pixel_samples;
+ }
+ return 0.0f;
+ }
+
+ void add_samples(uint64_t pixel_samples_, int tile_sample)
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ pixel_samples += pixel_samples_;
+ current_tile_sample = tile_sample;
+ }
+
+ void add_samples_update(uint64_t pixel_samples_, int tile_sample)
+ {
+ add_samples(pixel_samples_, tile_sample);
+ set_update();
+ }
+
+ void add_finished_tile(bool denoised)
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ if (denoised) {
+ denoised_tiles++;
+ }
+ else {
+ rendered_tiles++;
+ }
+ }
+
+ int get_current_sample() const
+ {
+ thread_scoped_lock lock(progress_mutex);
+ /* Note that the value here always belongs to the last tile that updated,
+ * so it's only useful if there is only one active tile. */
+ return current_tile_sample;
+ }
+
+ int get_rendered_tiles() const
+ {
+ thread_scoped_lock lock(progress_mutex);
+ return rendered_tiles;
+ }
+
+ int get_denoised_tiles() const
+ {
+ thread_scoped_lock lock(progress_mutex);
+ return denoised_tiles;
+ }
+
+ /* status messages */
+
+ void set_status(const string &status_, const string &substatus_ = "")
+ {
+ {
+ thread_scoped_lock lock(progress_mutex);
+ status = status_;
+ substatus = substatus_;
+ }
+
+ set_update();
+ }
+
+ void set_substatus(const string &substatus_)
+ {
+ {
+ thread_scoped_lock lock(progress_mutex);
+ substatus = substatus_;
+ }
+
+ set_update();
+ }
+
+ void set_sync_status(const string &status_, const string &substatus_ = "")
+ {
+ {
+ thread_scoped_lock lock(progress_mutex);
+ sync_status = status_;
+ sync_substatus = substatus_;
+ }
+
+ set_update();
+ }
+
+ void set_sync_substatus(const string &substatus_)
+ {
+ {
+ thread_scoped_lock lock(progress_mutex);
+ sync_substatus = substatus_;
+ }
+
+ set_update();
+ }
+
+ void get_status(string &status_, string &substatus_) const
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ if (sync_status != "") {
+ status_ = sync_status;
+ substatus_ = sync_substatus;
+ }
+ else {
+ status_ = status;
+ substatus_ = substatus;
+ }
+ }
+
+ /* callback */
+
+ void set_update()
+ {
+ if (update_cb) {
+ thread_scoped_lock lock(update_mutex);
+ update_cb();
+ }
+ }
+
+ void set_update_callback(function<void()> function)
+ {
+ update_cb = function;
+ }
+
+ protected:
+ mutable thread_mutex progress_mutex;
+ mutable thread_mutex update_mutex;
+ function<void()> update_cb;
+ function<void()> cancel_cb;
+
+ /* pixel_samples counts how many samples have been rendered over all pixel, not just per pixel.
+ * This makes the progress estimate more accurate when tiles with different sizes are used.
+ *
+ * total_pixel_samples is the total amount of pixel samples that will be rendered. */
+ uint64_t pixel_samples, total_pixel_samples;
+ /* Stores the current sample count of the last tile that called the update function.
+ * It's used to display the sample count if only one tile is active. */
+ int current_tile_sample;
+ /* Stores the number of tiles that's already finished.
+ * Used to determine whether all but the last tile are finished rendering,
+ * in which case the current_tile_sample is displayed. */
+ int rendered_tiles, denoised_tiles;
+
+ double start_time, render_start_time;
+ /* End time written when render is done, so it doesn't keep increasing on redraws. */
+ double end_time;
+
+ string status;
+ string substatus;
+
+ string sync_status;
+ string sync_substatus;
+
+ volatile bool cancel;
+ string cancel_message;
+
+ volatile bool error;
+ string error_message;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_PROGRESS_H__ */
diff --git a/intern/cycles/util/projection.h b/intern/cycles/util/projection.h
new file mode 100644
index 00000000000..8d822a3777d
--- /dev/null
+++ b/intern/cycles/util/projection.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_PROJECTION_H__
+#define __UTIL_PROJECTION_H__
+
+#include "util/transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* 4x4 projection matrix, perspective or orthographic. */
+
+typedef struct ProjectionTransform {
+ float4 x, y, z, w; /* rows */
+
+#ifndef __KERNEL_GPU__
+ ProjectionTransform()
+ {
+ }
+
+ explicit ProjectionTransform(const Transform &tfm)
+ : x(tfm.x), y(tfm.y), z(tfm.z), w(make_float4(0.0f, 0.0f, 0.0f, 1.0f))
+ {
+ }
+#endif
+} ProjectionTransform;
+
+typedef struct PerspectiveMotionTransform {
+ ProjectionTransform pre;
+ ProjectionTransform post;
+} PerspectiveMotionTransform;
+
+/* Functions */
+
+ccl_device_inline float3 transform_perspective(ccl_private const ProjectionTransform *t,
+ const float3 a)
+{
+ float4 b = make_float4(a.x, a.y, a.z, 1.0f);
+ float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
+ float w = dot(t->w, b);
+
+ return (w != 0.0f) ? c / w : zero_float3();
+}
+
+ccl_device_inline float3 transform_perspective_direction(ccl_private const ProjectionTransform *t,
+ const float3 a)
+{
+ float3 c = make_float3(a.x * t->x.x + a.y * t->x.y + a.z * t->x.z,
+ a.x * t->y.x + a.y * t->y.y + a.z * t->y.z,
+ a.x * t->z.x + a.y * t->z.y + a.z * t->z.z);
+
+ return c;
+}
+
+#ifndef __KERNEL_GPU__
+
+ccl_device_inline Transform projection_to_transform(const ProjectionTransform &a)
+{
+ Transform tfm = {a.x, a.y, a.z};
+ return tfm;
+}
+
+ccl_device_inline ProjectionTransform projection_transpose(const ProjectionTransform &a)
+{
+ ProjectionTransform t;
+
+ t.x.x = a.x.x;
+ t.x.y = a.y.x;
+ t.x.z = a.z.x;
+ t.x.w = a.w.x;
+ t.y.x = a.x.y;
+ t.y.y = a.y.y;
+ t.y.z = a.z.y;
+ t.y.w = a.w.y;
+ t.z.x = a.x.z;
+ t.z.y = a.y.z;
+ t.z.z = a.z.z;
+ t.z.w = a.w.z;
+ t.w.x = a.x.w;
+ t.w.y = a.y.w;
+ t.w.z = a.z.w;
+ t.w.w = a.w.w;
+
+ return t;
+}
+
+ProjectionTransform projection_inverse(const ProjectionTransform &a);
+
+ccl_device_inline ProjectionTransform make_projection(float a,
+ float b,
+ float c,
+ float d,
+ float e,
+ float f,
+ float g,
+ float h,
+ float i,
+ float j,
+ float k,
+ float l,
+ float m,
+ float n,
+ float o,
+ float p)
+{
+ ProjectionTransform t;
+
+ t.x.x = a;
+ t.x.y = b;
+ t.x.z = c;
+ t.x.w = d;
+ t.y.x = e;
+ t.y.y = f;
+ t.y.z = g;
+ t.y.w = h;
+ t.z.x = i;
+ t.z.y = j;
+ t.z.z = k;
+ t.z.w = l;
+ t.w.x = m;
+ t.w.y = n;
+ t.w.z = o;
+ t.w.w = p;
+
+ return t;
+}
+ccl_device_inline ProjectionTransform projection_identity()
+{
+ return make_projection(1.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f);
+}
+
+ccl_device_inline ProjectionTransform operator*(const ProjectionTransform &a,
+ const ProjectionTransform &b)
+{
+ ProjectionTransform c = projection_transpose(b);
+ ProjectionTransform t;
+
+ t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
+ t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
+ t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
+ t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
+
+ return t;
+}
+
+ccl_device_inline ProjectionTransform operator*(const ProjectionTransform &a, const Transform &b)
+{
+ return a * ProjectionTransform(b);
+}
+
+ccl_device_inline ProjectionTransform operator*(const Transform &a, const ProjectionTransform &b)
+{
+ return ProjectionTransform(a) * b;
+}
+
+ccl_device_inline void print_projection(const char *label, const ProjectionTransform &t)
+{
+ print_float4(label, t.x);
+ print_float4(label, t.y);
+ print_float4(label, t.z);
+ print_float4(label, t.w);
+ printf("\n");
+}
+
+ccl_device_inline ProjectionTransform projection_perspective(float fov, float n, float f)
+{
+ ProjectionTransform persp = make_projection(
+ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, f / (f - n), -f * n / (f - n), 0, 0, 1, 0);
+
+ float inv_angle = 1.0f / tanf(0.5f * fov);
+
+ Transform scale = transform_scale(inv_angle, inv_angle, 1);
+
+ return scale * persp;
+}
+
+ccl_device_inline ProjectionTransform projection_orthographic(float znear, float zfar)
+{
+ Transform t = transform_scale(1.0f, 1.0f, 1.0f / (zfar - znear)) *
+ transform_translate(0.0f, 0.0f, -znear);
+
+ return ProjectionTransform(t);
+}
+
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_PROJECTION_H__ */
diff --git a/intern/cycles/util/util_queue.h b/intern/cycles/util/queue.h
index 622f4fe3e47..622f4fe3e47 100644
--- a/intern/cycles/util/util_queue.h
+++ b/intern/cycles/util/queue.h
diff --git a/intern/cycles/util/rect.h b/intern/cycles/util/rect.h
new file mode 100644
index 00000000000..79d64b917b7
--- /dev/null
+++ b/intern/cycles/util/rect.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_RECT_H__
+#define __UTIL_RECT_H__
+
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Rectangles are represented as a int4 containing the coordinates of the lower-left and
+ * upper-right corners in the order (x0, y0, x1, y1). */
+
+ccl_device_inline int4 rect_from_shape(int x0, int y0, int w, int h)
+{
+ return make_int4(x0, y0, x0 + w, y0 + h);
+}
+
+ccl_device_inline int4 rect_expand(int4 rect, int d)
+{
+ return make_int4(rect.x - d, rect.y - d, rect.z + d, rect.w + d);
+}
+
+/* Returns the intersection of two rects. */
+ccl_device_inline int4 rect_clip(int4 a, int4 b)
+{
+ return make_int4(max(a.x, b.x), max(a.y, b.y), min(a.z, b.z), min(a.w, b.w));
+}
+
+ccl_device_inline bool rect_is_valid(int4 rect)
+{
+ return (rect.z > rect.x) && (rect.w > rect.y);
+}
+
+/* Returns the local row-major index of the pixel inside the rect. */
+ccl_device_inline int coord_to_local_index(int4 rect, int x, int y)
+{
+ int w = rect.z - rect.x;
+ return (y - rect.y) * w + (x - rect.x);
+}
+
+/* Finds the coordinates of a pixel given by its row-major index in the rect,
+ * and returns whether the pixel is inside it. */
+ccl_device_inline bool local_index_to_coord(int4 rect,
+ int idx,
+ ccl_private int *x,
+ ccl_private int *y)
+{
+ int w = rect.z - rect.x;
+ *x = (idx % w) + rect.x;
+ *y = (idx / w) + rect.y;
+ return (*y < rect.w);
+}
+
+ccl_device_inline int rect_size(int4 rect)
+{
+ return (rect.z - rect.x) * (rect.w - rect.y);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_RECT_H__ */
diff --git a/intern/cycles/util/semaphore.h b/intern/cycles/util/semaphore.h
new file mode 100644
index 00000000000..8da8a232ba2
--- /dev/null
+++ b/intern/cycles/util/semaphore.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_SEMAPHORE_H__
+#define __UTIL_SEMAPHORE_H__
+
+#include "util/thread.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Counting Semaphore
+ *
+ * To restrict concurrent access to a resource to a specified number
+ * of threads. Similar to std::counting_semaphore from C++20. */
+
+class thread_counting_semaphore {
+ public:
+ explicit thread_counting_semaphore(const int count) : count(count)
+ {
+ }
+
+ thread_counting_semaphore(const thread_counting_semaphore &) = delete;
+
+ void acquire()
+ {
+ thread_scoped_lock lock(mutex);
+ while (count == 0) {
+ condition.wait(lock);
+ }
+ count--;
+ }
+
+ void release()
+ {
+ thread_scoped_lock lock(mutex);
+ count++;
+ condition.notify_one();
+ }
+
+ protected:
+ thread_mutex mutex;
+ thread_condition_variable condition;
+ int count;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_SEMAPHORE_H__ */
diff --git a/intern/cycles/util/util_set.h b/intern/cycles/util/set.h
index 298e1f7729a..298e1f7729a 100644
--- a/intern/cycles/util/util_set.h
+++ b/intern/cycles/util/set.h
diff --git a/intern/cycles/util/simd.cpp b/intern/cycles/util/simd.cpp
new file mode 100644
index 00000000000..089444bb6cc
--- /dev/null
+++ b/intern/cycles/util/simd.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011-2013 Intel Corporation
+ * Modifications Copyright 2014, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if (defined(WITH_KERNEL_SSE2)) || (defined(WITH_KERNEL_NATIVE) && defined(__SSE2__))
+
+# define __KERNEL_SSE2__
+# include "util/simd.h"
+
+CCL_NAMESPACE_BEGIN
+
+const __m128 _mm_lookupmask_ps[16] = {_mm_castsi128_ps(_mm_set_epi32(0, 0, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(0, 0, 0, -1)),
+ _mm_castsi128_ps(_mm_set_epi32(0, 0, -1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(0, 0, -1, -1)),
+ _mm_castsi128_ps(_mm_set_epi32(0, -1, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(0, -1, 0, -1)),
+ _mm_castsi128_ps(_mm_set_epi32(0, -1, -1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(0, -1, -1, -1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0, 0, -1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0, -1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0, -1, -1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, -1, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, -1, 0, -1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, -1, -1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, -1, -1, -1))};
+
+CCL_NAMESPACE_END
+
+#endif // WITH_KERNEL_SSE2
diff --git a/intern/cycles/util/simd.h b/intern/cycles/util/simd.h
new file mode 100644
index 00000000000..cc4950891d0
--- /dev/null
+++ b/intern/cycles/util/simd.h
@@ -0,0 +1,572 @@
+/*
+ * Copyright 2011-2013 Intel Corporation
+ * Modifications Copyright 2014, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0(the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_SIMD_TYPES_H__
+#define __UTIL_SIMD_TYPES_H__
+
+#include <limits>
+#include <stdint.h>
+
+#include "util/defines.h"
+
+/* SSE Intrinsics includes
+ *
+ * We assume __KERNEL_SSEX__ flags to have been defined at this point.
+ *
+ * MinGW64 has conflicting declarations for these SSE headers in <windows.h>.
+ * Since we can't avoid including <windows.h>, better only include that */
+#if defined(FREE_WINDOWS64)
+# include "util/windows.h"
+#elif defined(_MSC_VER)
+# include <intrin.h>
+#elif (defined(__x86_64__) || defined(__i386__))
+# include <x86intrin.h>
+#elif defined(__KERNEL_NEON__)
+# define SSE2NEON_PRECISE_MINMAX 1
+# include <sse2neon.h>
+#endif
+
+/* Floating Point Control, for Embree. */
+#if defined(__x86_64__) || defined(_M_X64)
+# define SIMD_SET_FLUSH_TO_ZERO \
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); \
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
+#else
+# define SIMD_SET_FLUSH_TO_ZERO
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* Data structures used by SSE classes. */
+#ifdef __KERNEL_SSE2__
+
+extern const __m128 _mm_lookupmask_ps[16];
+
+static struct TrueTy {
+ __forceinline operator bool() const
+ {
+ return true;
+ }
+} True ccl_attr_maybe_unused;
+
+static struct FalseTy {
+ __forceinline operator bool() const
+ {
+ return false;
+ }
+} False ccl_attr_maybe_unused;
+
+static struct ZeroTy {
+ __forceinline operator float() const
+ {
+ return 0;
+ }
+ __forceinline operator int() const
+ {
+ return 0;
+ }
+} zero ccl_attr_maybe_unused;
+
+static struct OneTy {
+ __forceinline operator float() const
+ {
+ return 1;
+ }
+ __forceinline operator int() const
+ {
+ return 1;
+ }
+} one ccl_attr_maybe_unused;
+
+static struct NegInfTy {
+ __forceinline operator float() const
+ {
+ return -std::numeric_limits<float>::infinity();
+ }
+ __forceinline operator int() const
+ {
+ return std::numeric_limits<int>::min();
+ }
+} neg_inf ccl_attr_maybe_unused;
+
+static struct PosInfTy {
+ __forceinline operator float() const
+ {
+ return std::numeric_limits<float>::infinity();
+ }
+ __forceinline operator int() const
+ {
+ return std::numeric_limits<int>::max();
+ }
+} inf ccl_attr_maybe_unused, pos_inf ccl_attr_maybe_unused;
+
+static struct StepTy {
+} step ccl_attr_maybe_unused;
+
+#endif
+
+/* Utilities used by Neon */
+#if defined(__KERNEL_NEON__)
+template<class type, int i0, int i1, int i2, int i3> type shuffle_neon(const type &a)
+{
+ if (i0 == i1 && i0 == i2 && i0 == i3) {
+ return type(vdupq_laneq_s32(int32x4_t(a), i0));
+ }
+ static const uint8_t tbl[16] = {(i0 * 4) + 0,
+ (i0 * 4) + 1,
+ (i0 * 4) + 2,
+ (i0 * 4) + 3,
+ (i1 * 4) + 0,
+ (i1 * 4) + 1,
+ (i1 * 4) + 2,
+ (i1 * 4) + 3,
+ (i2 * 4) + 0,
+ (i2 * 4) + 1,
+ (i2 * 4) + 2,
+ (i2 * 4) + 3,
+ (i3 * 4) + 0,
+ (i3 * 4) + 1,
+ (i3 * 4) + 2,
+ (i3 * 4) + 3};
+
+ return type(vqtbl1q_s8(int8x16_t(a), *(uint8x16_t *)tbl));
+}
+
+template<class type, int i0, int i1, int i2, int i3>
+type shuffle_neon(const type &a, const type &b)
+{
+ if (&a == &b) {
+ static const uint8_t tbl[16] = {(i0 * 4) + 0,
+ (i0 * 4) + 1,
+ (i0 * 4) + 2,
+ (i0 * 4) + 3,
+ (i1 * 4) + 0,
+ (i1 * 4) + 1,
+ (i1 * 4) + 2,
+ (i1 * 4) + 3,
+ (i2 * 4) + 0,
+ (i2 * 4) + 1,
+ (i2 * 4) + 2,
+ (i2 * 4) + 3,
+ (i3 * 4) + 0,
+ (i3 * 4) + 1,
+ (i3 * 4) + 2,
+ (i3 * 4) + 3};
+
+ return type(vqtbl1q_s8(int8x16_t(b), *(uint8x16_t *)tbl));
+ }
+ else {
+
+ static const uint8_t tbl[16] = {(i0 * 4) + 0,
+ (i0 * 4) + 1,
+ (i0 * 4) + 2,
+ (i0 * 4) + 3,
+ (i1 * 4) + 0,
+ (i1 * 4) + 1,
+ (i1 * 4) + 2,
+ (i1 * 4) + 3,
+ (i2 * 4) + 0 + 16,
+ (i2 * 4) + 1 + 16,
+ (i2 * 4) + 2 + 16,
+ (i2 * 4) + 3 + 16,
+ (i3 * 4) + 0 + 16,
+ (i3 * 4) + 1 + 16,
+ (i3 * 4) + 2 + 16,
+ (i3 * 4) + 3 + 16};
+
+ return type(vqtbl2q_s8((int8x16x2_t){int8x16_t(a), int8x16_t(b)}, *(uint8x16_t *)tbl));
+ }
+}
+#endif /* __KERNEL_NEON */
+
+/* Intrinsics Functions
+ *
+ * For fast bit operations. */
+
+#if defined(__BMI__) && defined(__GNUC__)
+# ifndef _tzcnt_u32
+# define _tzcnt_u32 __tzcnt_u32
+# endif
+# ifndef _tzcnt_u64
+# define _tzcnt_u64 __tzcnt_u64
+# endif
+#endif
+
+#if defined(__LZCNT__)
+# define _lzcnt_u32 __lzcnt32
+# define _lzcnt_u64 __lzcnt64
+#endif
+
+#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__clang__)
+/* Intrinsic functions on Windows. */
+__forceinline uint32_t __bsf(uint32_t v)
+{
+# if defined(__KERNEL_AVX2__)
+ return _tzcnt_u32(v);
+# else
+ unsigned long r = 0;
+ _BitScanForward(&r, v);
+ return r;
+# endif
+}
+
+__forceinline uint32_t __bsr(uint32_t v)
+{
+ unsigned long r = 0;
+ _BitScanReverse(&r, v);
+ return r;
+}
+
+__forceinline uint32_t __btc(uint32_t v, uint32_t i)
+{
+ long r = v;
+ _bittestandcomplement(&r, i);
+ return r;
+}
+
+__forceinline uint32_t bitscan(uint32_t v)
+{
+# if defined(__KERNEL_AVX2__)
+ return _tzcnt_u32(v);
+# else
+ return __bsf(v);
+# endif
+}
+
+# if defined(__KERNEL_64_BIT__)
+
+__forceinline uint64_t __bsf(uint64_t v)
+{
+# if defined(__KERNEL_AVX2__)
+ return _tzcnt_u64(v);
+# else
+ unsigned long r = 0;
+ _BitScanForward64(&r, v);
+ return r;
+# endif
+}
+
+__forceinline uint64_t __bsr(uint64_t v)
+{
+ unsigned long r = 0;
+ _BitScanReverse64(&r, v);
+ return r;
+}
+
+__forceinline uint64_t __btc(uint64_t v, uint64_t i)
+{
+ uint64_t r = v;
+ _bittestandcomplement64((__int64 *)&r, i);
+ return r;
+}
+
+__forceinline uint64_t bitscan(uint64_t v)
+{
+# if defined(__KERNEL_AVX2__)
+# if defined(__KERNEL_64_BIT__)
+ return _tzcnt_u64(v);
+# else
+ return _tzcnt_u32(v);
+# endif
+# else
+ return __bsf(v);
+# endif
+}
+
+# endif /* __KERNEL_64_BIT__ */
+
+#elif (defined(__x86_64__) || defined(__i386__)) && defined(__KERNEL_SSE2__)
+/* Intrinsic functions with x86 SSE. */
+
+__forceinline uint32_t __bsf(const uint32_t v)
+{
+ uint32_t r = 0;
+ asm("bsf %1,%0" : "=r"(r) : "r"(v));
+ return r;
+}
+
+__forceinline uint32_t __bsr(const uint32_t v)
+{
+ uint32_t r = 0;
+ asm("bsr %1,%0" : "=r"(r) : "r"(v));
+ return r;
+}
+
+__forceinline uint32_t __btc(const uint32_t v, uint32_t i)
+{
+ uint32_t r = 0;
+ asm("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags");
+ return r;
+}
+
+# if (defined(__KERNEL_64_BIT__) || defined(__APPLE__)) && \
+ !(defined(__ILP32__) && defined(__x86_64__))
+__forceinline uint64_t __bsf(const uint64_t v)
+{
+ uint64_t r = 0;
+ asm("bsf %1,%0" : "=r"(r) : "r"(v));
+ return r;
+}
+# endif
+
+__forceinline uint64_t __bsr(const uint64_t v)
+{
+ uint64_t r = 0;
+ asm("bsr %1,%0" : "=r"(r) : "r"(v));
+ return r;
+}
+
+__forceinline uint64_t __btc(const uint64_t v, const uint64_t i)
+{
+ uint64_t r = 0;
+ asm("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags");
+ return r;
+}
+
+__forceinline uint32_t bitscan(uint32_t v)
+{
+# if defined(__KERNEL_AVX2__)
+ return _tzcnt_u32(v);
+# else
+ return __bsf(v);
+# endif
+}
+
+# if (defined(__KERNEL_64_BIT__) || defined(__APPLE__)) && \
+ !(defined(__ILP32__) && defined(__x86_64__))
+__forceinline uint64_t bitscan(uint64_t v)
+{
+# if defined(__KERNEL_AVX2__)
+# if defined(__KERNEL_64_BIT__)
+ return _tzcnt_u64(v);
+# else
+ return _tzcnt_u32(v);
+# endif
+# else
+ return __bsf(v);
+# endif
+}
+# endif
+
+#else
+/* Intrinsic functions fallback for arbitrary processor. */
+__forceinline uint32_t __bsf(const uint32_t x)
+{
+ for (int i = 0; i < 32; i++) {
+ if (x & (1U << i))
+ return i;
+ }
+ return 32;
+}
+
+__forceinline uint32_t __bsr(const uint32_t x)
+{
+ for (int i = 0; i < 32; i++) {
+ if (x & (1U << (31 - i)))
+ return (31 - i);
+ }
+ return 32;
+}
+
+__forceinline uint32_t __btc(const uint32_t x, const uint32_t bit)
+{
+ uint32_t mask = 1U << bit;
+ return x & (~mask);
+}
+
+__forceinline uint32_t __bsf(const uint64_t x)
+{
+ for (int i = 0; i < 64; i++) {
+ if (x & (1UL << i))
+ return i;
+ }
+ return 64;
+}
+
+__forceinline uint32_t __bsr(const uint64_t x)
+{
+ for (int i = 0; i < 64; i++) {
+ if (x & (1UL << (63 - i)))
+ return (63 - i);
+ }
+ return 64;
+}
+
+__forceinline uint64_t __btc(const uint64_t x, const uint32_t bit)
+{
+ uint64_t mask = 1UL << bit;
+ return x & (~mask);
+}
+
+__forceinline uint32_t bitscan(uint32_t value)
+{
+ assert(value != 0);
+ uint32_t bit = 0;
+ while ((value & (1 << bit)) == 0) {
+ ++bit;
+ }
+ return bit;
+}
+
+__forceinline uint64_t bitscan(uint64_t value)
+{
+ assert(value != 0);
+ uint64_t bit = 0;
+ while ((value & (1 << bit)) == 0) {
+ ++bit;
+ }
+ return bit;
+}
+
+#endif /* Intrinsics */
+
+/* SSE compatibility.
+ *
+ * Various utilities to smooth over differences between SSE versions and
+ * implementations. */
+#ifdef __KERNEL_SSE2__
+
+/* Test __KERNEL_SSE41__ for MSVC which does not define __SSE4_1__, and test
+ * __SSE4_1__ to avoid OpenImageIO conflicts with our emulation macros on other
+ * platforms when compiling code outside the kernel. */
+# if !(defined(__KERNEL_SSE41__) || defined(__SSE4_1__) || defined(__SSE4_2__))
+
+/* Emulation of SSE4 functions with SSE2 */
+
+# define _MM_FROUND_TO_NEAREST_INT 0x00
+# define _MM_FROUND_TO_NEG_INF 0x01
+# define _MM_FROUND_TO_POS_INF 0x02
+# define _MM_FROUND_TO_ZERO 0x03
+# define _MM_FROUND_CUR_DIRECTION 0x04
+
+# undef _mm_blendv_ps
+# define _mm_blendv_ps _mm_blendv_ps_emu
+__forceinline __m128 _mm_blendv_ps_emu(__m128 value, __m128 input, __m128 mask)
+{
+ __m128i isignmask = _mm_set1_epi32(0x80000000);
+ __m128 signmask = _mm_castsi128_ps(isignmask);
+ __m128i iandsign = _mm_castps_si128(_mm_and_ps(mask, signmask));
+ __m128i icmpmask = _mm_cmpeq_epi32(iandsign, isignmask);
+ __m128 cmpmask = _mm_castsi128_ps(icmpmask);
+ return _mm_or_ps(_mm_and_ps(cmpmask, input), _mm_andnot_ps(cmpmask, value));
+}
+
+# undef _mm_blend_ps
+# define _mm_blend_ps _mm_blend_ps_emu
+__forceinline __m128 _mm_blend_ps_emu(__m128 value, __m128 input, const int mask)
+{
+ assert(mask < 0x10);
+ return _mm_blendv_ps(value, input, _mm_lookupmask_ps[mask]);
+}
+
+# undef _mm_blendv_epi8
+# define _mm_blendv_epi8 _mm_blendv_epi8_emu
+__forceinline __m128i _mm_blendv_epi8_emu(__m128i value, __m128i input, __m128i mask)
+{
+ return _mm_or_si128(_mm_and_si128(mask, input), _mm_andnot_si128(mask, value));
+}
+
+# undef _mm_min_epi32
+# define _mm_min_epi32 _mm_min_epi32_emu
+__forceinline __m128i _mm_min_epi32_emu(__m128i value, __m128i input)
+{
+ return _mm_blendv_epi8(input, value, _mm_cmplt_epi32(value, input));
+}
+
+# undef _mm_max_epi32
+# define _mm_max_epi32 _mm_max_epi32_emu
+__forceinline __m128i _mm_max_epi32_emu(__m128i value, __m128i input)
+{
+ return _mm_blendv_epi8(value, input, _mm_cmplt_epi32(value, input));
+}
+
+# ifndef __KERNEL_NEON__
+# undef _mm_extract_epi32
+# define _mm_extract_epi32 _mm_extract_epi32_emu
+__forceinline int _mm_extract_epi32_emu(__m128i input, const int index)
+{
+ switch (index) {
+ case 0:
+ return _mm_cvtsi128_si32(input);
+ case 1:
+ return _mm_cvtsi128_si32(_mm_shuffle_epi32(input, _MM_SHUFFLE(1, 1, 1, 1)));
+ case 2:
+ return _mm_cvtsi128_si32(_mm_shuffle_epi32(input, _MM_SHUFFLE(2, 2, 2, 2)));
+ case 3:
+ return _mm_cvtsi128_si32(_mm_shuffle_epi32(input, _MM_SHUFFLE(3, 3, 3, 3)));
+ default:
+ assert(false);
+ return 0;
+ }
+}
+# endif
+
+# undef _mm_insert_epi32
+# define _mm_insert_epi32 _mm_insert_epi32_emu
+__forceinline __m128i _mm_insert_epi32_emu(__m128i value, int input, const int index)
+{
+ assert(index >= 0 && index < 4);
+ ((int *)&value)[index] = input;
+ return value;
+}
+
+# undef _mm_insert_ps
+# define _mm_insert_ps _mm_insert_ps_emu
+__forceinline __m128 _mm_insert_ps_emu(__m128 value, __m128 input, const int index)
+{
+ assert(index < 0x100);
+ ((float *)&value)[(index >> 4) & 0x3] = ((float *)&input)[index >> 6];
+ return _mm_andnot_ps(_mm_lookupmask_ps[index & 0xf], value);
+}
+
+# undef _mm_round_ps
+# define _mm_round_ps _mm_round_ps_emu
+__forceinline __m128 _mm_round_ps_emu(__m128 value, const int flags)
+{
+ switch (flags) {
+ case _MM_FROUND_TO_NEAREST_INT:
+ return _mm_cvtepi32_ps(_mm_cvtps_epi32(value));
+ case _MM_FROUND_TO_NEG_INF:
+ return _mm_cvtepi32_ps(_mm_cvtps_epi32(_mm_add_ps(value, _mm_set1_ps(-0.5f))));
+ case _MM_FROUND_TO_POS_INF:
+ return _mm_cvtepi32_ps(_mm_cvtps_epi32(_mm_add_ps(value, _mm_set1_ps(0.5f))));
+ case _MM_FROUND_TO_ZERO:
+ return _mm_cvtepi32_ps(_mm_cvttps_epi32(value));
+ }
+ return value;
+}
+
+# endif /* !(defined(__KERNEL_SSE41__) || defined(__SSE4_1__) || defined(__SSE4_2__)) */
+
+/* Older GCC versions do not have _mm256_cvtss_f32 yet, so define it ourselves.
+ * _mm256_castps256_ps128 generates no instructions so this is just as efficient. */
+# if defined(__KERNEL_AVX__) || defined(__KERNEL_AVX2__)
+# undef _mm256_cvtss_f32
+# define _mm256_cvtss_f32(a) (_mm_cvtss_f32(_mm256_castps256_ps128(a)))
+# endif
+
+#endif /* __KERNEL_SSE2__ */
+
+/* quiet unused define warnings */
+#if defined(__KERNEL_SSE2__) || defined(__KERNEL_SSE3__) || defined(__KERNEL_SSSE3__) || \
+ defined(__KERNEL_SSE41__) || defined(__KERNEL_AVX__) || defined(__KERNEL_AVX2__)
+/* do nothing */
+#endif
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_SIMD_TYPES_H__ */
diff --git a/intern/cycles/util/util_sseb.h b/intern/cycles/util/sseb.h
index 6afce4f8909..6afce4f8909 100644
--- a/intern/cycles/util/util_sseb.h
+++ b/intern/cycles/util/sseb.h
diff --git a/intern/cycles/util/ssef.h b/intern/cycles/util/ssef.h
new file mode 100644
index 00000000000..ea5e78b54d2
--- /dev/null
+++ b/intern/cycles/util/ssef.h
@@ -0,0 +1,1104 @@
+/*
+ * Copyright 2011-2013 Intel Corporation
+ * Modifications Copyright 2014, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0(the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_SSEF_H__
+#define __UTIL_SSEF_H__
+
+#include "util/ssei.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __KERNEL_SSE2__
+
+struct sseb;
+struct ssef;
+
+/*! 4-wide SSE float type. */
+struct ssef {
+ typedef sseb Mask; // mask type
+ typedef ssei Int; // int type
+ typedef ssef Float; // float type
+
+ enum { size = 4 }; // number of SIMD elements
+ union {
+ __m128 m128;
+ float f[4];
+ int i[4];
+ }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline ssef()
+ {
+ }
+ __forceinline ssef(const ssef &other)
+ {
+ m128 = other.m128;
+ }
+ __forceinline ssef &operator=(const ssef &other)
+ {
+ m128 = other.m128;
+ return *this;
+ }
+
+ __forceinline ssef(const __m128 a) : m128(a)
+ {
+ }
+ __forceinline operator const __m128 &() const
+ {
+ return m128;
+ }
+ __forceinline operator __m128 &()
+ {
+ return m128;
+ }
+
+ __forceinline ssef(float a) : m128(_mm_set1_ps(a))
+ {
+ }
+ __forceinline ssef(float a, float b, float c, float d) : m128(_mm_setr_ps(a, b, c, d))
+ {
+ }
+
+ __forceinline explicit ssef(const __m128i a) : m128(_mm_cvtepi32_ps(a))
+ {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+# if defined(__KERNEL_AVX__)
+ static __forceinline ssef broadcast(const void *const a)
+ {
+ return _mm_broadcast_ss((float *)a);
+ }
+# else
+ static __forceinline ssef broadcast(const void *const a)
+ {
+ return _mm_set1_ps(*(float *)a);
+ }
+# endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float &operator[](const size_t i) const
+ {
+ assert(i < 4);
+ return f[i];
+ }
+ __forceinline float &operator[](const size_t i)
+ {
+ assert(i < 4);
+ return f[i];
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unary Operators
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline const ssef cast(const __m128i &a)
+{
+ return _mm_castsi128_ps(a);
+}
+__forceinline const ssef operator+(const ssef &a)
+{
+ return a;
+}
+__forceinline const ssef operator-(const ssef &a)
+{
+ return _mm_xor_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000)));
+}
+__forceinline const ssef abs(const ssef &a)
+{
+ return _mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)));
+}
+# if defined(__KERNEL_SSE41__)
+__forceinline const ssef sign(const ssef &a)
+{
+ return _mm_blendv_ps(ssef(1.0f), -ssef(1.0f), _mm_cmplt_ps(a, ssef(0.0f)));
+}
+# endif
+__forceinline const ssef signmsk(const ssef &a)
+{
+ return _mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000)));
+}
+
+__forceinline const ssef rcp(const ssef &a)
+{
+ const ssef r = _mm_rcp_ps(a.m128);
+ return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
+}
+__forceinline const ssef sqr(const ssef &a)
+{
+ return _mm_mul_ps(a, a);
+}
+__forceinline const ssef mm_sqrt(const ssef &a)
+{
+ return _mm_sqrt_ps(a.m128);
+}
+__forceinline const ssef rsqrt(const ssef &a)
+{
+ const ssef r = _mm_rsqrt_ps(a.m128);
+ return _mm_add_ps(
+ _mm_mul_ps(_mm_set_ps(1.5f, 1.5f, 1.5f, 1.5f), r),
+ _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set_ps(-0.5f, -0.5f, -0.5f, -0.5f)), r),
+ _mm_mul_ps(r, r)));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Binary Operators
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline const ssef operator+(const ssef &a, const ssef &b)
+{
+ return _mm_add_ps(a.m128, b.m128);
+}
+__forceinline const ssef operator+(const ssef &a, const float &b)
+{
+ return a + ssef(b);
+}
+__forceinline const ssef operator+(const float &a, const ssef &b)
+{
+ return ssef(a) + b;
+}
+
+__forceinline const ssef operator-(const ssef &a, const ssef &b)
+{
+ return _mm_sub_ps(a.m128, b.m128);
+}
+__forceinline const ssef operator-(const ssef &a, const float &b)
+{
+ return a - ssef(b);
+}
+__forceinline const ssef operator-(const float &a, const ssef &b)
+{
+ return ssef(a) - b;
+}
+
+__forceinline const ssef operator*(const ssef &a, const ssef &b)
+{
+ return _mm_mul_ps(a.m128, b.m128);
+}
+__forceinline const ssef operator*(const ssef &a, const float &b)
+{
+ return a * ssef(b);
+}
+__forceinline const ssef operator*(const float &a, const ssef &b)
+{
+ return ssef(a) * b;
+}
+
+__forceinline const ssef operator/(const ssef &a, const ssef &b)
+{
+ return _mm_div_ps(a.m128, b.m128);
+}
+__forceinline const ssef operator/(const ssef &a, const float &b)
+{
+ return a / ssef(b);
+}
+__forceinline const ssef operator/(const float &a, const ssef &b)
+{
+ return ssef(a) / b;
+}
+
+__forceinline const ssef operator^(const ssef &a, const ssef &b)
+{
+ return _mm_xor_ps(a.m128, b.m128);
+}
+__forceinline const ssef operator^(const ssef &a, const ssei &b)
+{
+ return _mm_xor_ps(a.m128, _mm_castsi128_ps(b.m128));
+}
+
+__forceinline const ssef operator&(const ssef &a, const ssef &b)
+{
+ return _mm_and_ps(a.m128, b.m128);
+}
+__forceinline const ssef operator&(const ssef &a, const ssei &b)
+{
+ return _mm_and_ps(a.m128, _mm_castsi128_ps(b.m128));
+}
+
+__forceinline const ssef operator|(const ssef &a, const ssef &b)
+{
+ return _mm_or_ps(a.m128, b.m128);
+}
+__forceinline const ssef operator|(const ssef &a, const ssei &b)
+{
+ return _mm_or_ps(a.m128, _mm_castsi128_ps(b.m128));
+}
+
+__forceinline const ssef andnot(const ssef &a, const ssef &b)
+{
+ return _mm_andnot_ps(a.m128, b.m128);
+}
+
+__forceinline const ssef min(const ssef &a, const ssef &b)
+{
+ return _mm_min_ps(a.m128, b.m128);
+}
+__forceinline const ssef min(const ssef &a, const float &b)
+{
+ return _mm_min_ps(a.m128, ssef(b));
+}
+__forceinline const ssef min(const float &a, const ssef &b)
+{
+ return _mm_min_ps(ssef(a), b.m128);
+}
+
+__forceinline const ssef max(const ssef &a, const ssef &b)
+{
+ return _mm_max_ps(a.m128, b.m128);
+}
+__forceinline const ssef max(const ssef &a, const float &b)
+{
+ return _mm_max_ps(a.m128, ssef(b));
+}
+__forceinline const ssef max(const float &a, const ssef &b)
+{
+ return _mm_max_ps(ssef(a), b.m128);
+}
+
+# if defined(__KERNEL_SSE41__)
+__forceinline ssef mini(const ssef &a, const ssef &b)
+{
+ const ssei ai = _mm_castps_si128(a);
+ const ssei bi = _mm_castps_si128(b);
+ const ssei ci = _mm_min_epi32(ai, bi);
+ return _mm_castsi128_ps(ci);
+}
+# endif
+
+# if defined(__KERNEL_SSE41__)
+__forceinline ssef maxi(const ssef &a, const ssef &b)
+{
+ const ssei ai = _mm_castps_si128(a);
+ const ssei bi = _mm_castps_si128(b);
+ const ssei ci = _mm_max_epi32(ai, bi);
+ return _mm_castsi128_ps(ci);
+}
+# endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Ternary Operators
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline const ssef madd(const ssef &a, const ssef &b, const ssef &c)
+{
+# if defined(__KERNEL_NEON__)
+ return vfmaq_f32(c, a, b);
+# elif defined(__KERNEL_AVX2__)
+ return _mm_fmadd_ps(a, b, c);
+# else
+ return a * b + c;
+# endif
+}
+__forceinline const ssef msub(const ssef &a, const ssef &b, const ssef &c)
+{
+# if defined(__KERNEL_NEON__)
+ return vfmaq_f32(vnegq_f32(c), a, b);
+# elif defined(__KERNEL_AVX2__)
+ return _mm_fmsub_ps(a, b, c);
+# else
+ return a * b - c;
+# endif
+}
+__forceinline const ssef nmadd(const ssef &a, const ssef &b, const ssef &c)
+{
+# if defined(__KERNEL_NEON__)
+ return vfmsq_f32(c, a, b);
+# elif defined(__KERNEL_AVX2__)
+ return _mm_fnmadd_ps(a, b, c);
+# else
+ return c - a * b;
+# endif
+}
+__forceinline const ssef nmsub(const ssef &a, const ssef &b, const ssef &c)
+{
+# if defined(__KERNEL_NEON__)
+ return vfmsq_f32(vnegq_f32(c), a, b);
+# elif defined(__KERNEL_AVX2__)
+ return _mm_fnmsub_ps(a, b, c);
+# else
+ return -a * b - c;
+# endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Assignment Operators
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline ssef &operator+=(ssef &a, const ssef &b)
+{
+ return a = a + b;
+}
+__forceinline ssef &operator+=(ssef &a, const float &b)
+{
+ return a = a + b;
+}
+
+__forceinline ssef &operator-=(ssef &a, const ssef &b)
+{
+ return a = a - b;
+}
+__forceinline ssef &operator-=(ssef &a, const float &b)
+{
+ return a = a - b;
+}
+
+__forceinline ssef &operator*=(ssef &a, const ssef &b)
+{
+ return a = a * b;
+}
+__forceinline ssef &operator*=(ssef &a, const float &b)
+{
+ return a = a * b;
+}
+
+__forceinline ssef &operator/=(ssef &a, const ssef &b)
+{
+ return a = a / b;
+}
+__forceinline ssef &operator/=(ssef &a, const float &b)
+{
+ return a = a / b;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Comparison Operators + Select
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline const sseb operator==(const ssef &a, const ssef &b)
+{
+ return _mm_cmpeq_ps(a.m128, b.m128);
+}
+__forceinline const sseb operator==(const ssef &a, const float &b)
+{
+ return a == ssef(b);
+}
+__forceinline const sseb operator==(const float &a, const ssef &b)
+{
+ return ssef(a) == b;
+}
+
+__forceinline const sseb operator!=(const ssef &a, const ssef &b)
+{
+ return _mm_cmpneq_ps(a.m128, b.m128);
+}
+__forceinline const sseb operator!=(const ssef &a, const float &b)
+{
+ return a != ssef(b);
+}
+__forceinline const sseb operator!=(const float &a, const ssef &b)
+{
+ return ssef(a) != b;
+}
+
+__forceinline const sseb operator<(const ssef &a, const ssef &b)
+{
+ return _mm_cmplt_ps(a.m128, b.m128);
+}
+__forceinline const sseb operator<(const ssef &a, const float &b)
+{
+ return a < ssef(b);
+}
+__forceinline const sseb operator<(const float &a, const ssef &b)
+{
+ return ssef(a) < b;
+}
+
+__forceinline const sseb operator>=(const ssef &a, const ssef &b)
+{
+ return _mm_cmpnlt_ps(a.m128, b.m128);
+}
+__forceinline const sseb operator>=(const ssef &a, const float &b)
+{
+ return a >= ssef(b);
+}
+__forceinline const sseb operator>=(const float &a, const ssef &b)
+{
+ return ssef(a) >= b;
+}
+
+__forceinline const sseb operator>(const ssef &a, const ssef &b)
+{
+ return _mm_cmpnle_ps(a.m128, b.m128);
+}
+__forceinline const sseb operator>(const ssef &a, const float &b)
+{
+ return a > ssef(b);
+}
+__forceinline const sseb operator>(const float &a, const ssef &b)
+{
+ return ssef(a) > b;
+}
+
+__forceinline const sseb operator<=(const ssef &a, const ssef &b)
+{
+ return _mm_cmple_ps(a.m128, b.m128);
+}
+__forceinline const sseb operator<=(const ssef &a, const float &b)
+{
+ return a <= ssef(b);
+}
+__forceinline const sseb operator<=(const float &a, const ssef &b)
+{
+ return ssef(a) <= b;
+}
+
+__forceinline const ssef select(const sseb &m, const ssef &t, const ssef &f)
+{
+# ifdef __KERNEL_SSE41__
+ return _mm_blendv_ps(f, t, m);
+# else
+ return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
+# endif
+}
+
+__forceinline const ssef select(const ssef &m, const ssef &t, const ssef &f)
+{
+# ifdef __KERNEL_SSE41__
+ return _mm_blendv_ps(f, t, m);
+# else
+ return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
+# endif
+}
+
+__forceinline const ssef select(const int mask, const ssef &t, const ssef &f)
+{
+# if defined(__KERNEL_SSE41__) && \
+ ((!defined(__clang__) && !defined(_MSC_VER)) || defined(__INTEL_COMPILER))
+ return _mm_blend_ps(f, t, mask);
+# else
+ return select(sseb(mask), t, f);
+# endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Rounding Functions
+////////////////////////////////////////////////////////////////////////////////
+
+# if defined(__KERNEL_SSE41__)
+__forceinline const ssef round_even(const ssef &a)
+{
+# ifdef __KERNEL_NEON__
+ return vrndnq_f32(a);
+# else
+ return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT);
+# endif
+}
+__forceinline const ssef round_down(const ssef &a)
+{
+# ifdef __KERNEL_NEON__
+ return vrndmq_f32(a);
+# else
+ return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF);
+# endif
+}
+__forceinline const ssef round_up(const ssef &a)
+{
+# ifdef __KERNEL_NEON__
+ return vrndpq_f32(a);
+# else
+ return _mm_round_ps(a, _MM_FROUND_TO_POS_INF);
+# endif
+}
+__forceinline const ssef round_zero(const ssef &a)
+{
+# ifdef __KERNEL_NEON__
+ return vrndq_f32(a);
+# else
+ return _mm_round_ps(a, _MM_FROUND_TO_ZERO);
+# endif
+}
+__forceinline const ssef floor(const ssef &a)
+{
+# ifdef __KERNEL_NEON__
+ return vrndnq_f32(a);
+# else
+ return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF);
+# endif
+}
+__forceinline const ssef ceil(const ssef &a)
+{
+# ifdef __KERNEL_NEON__
+ return vrndpq_f32(a);
+# else
+ return _mm_round_ps(a, _MM_FROUND_TO_POS_INF);
+# endif
+}
+# endif
+
+__forceinline ssei truncatei(const ssef &a)
+{
+ return _mm_cvttps_epi32(a.m128);
+}
+
+/* This is about 25% faster than straightforward floor to integer conversion
+ * due to better pipelining.
+ *
+ * Unsaturated add 0xffffffff (a < 0) is the same as subtract -1.
+ */
+__forceinline ssei floori(const ssef &a)
+{
+ return truncatei(a) + cast((a < 0.0f).m128);
+}
+
+__forceinline ssef floorfrac(const ssef &x, ssei *i)
+{
+ *i = floori(x);
+ return x - ssef(*i);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Common Functions
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline ssef mix(const ssef &a, const ssef &b, const ssef &t)
+{
+ return madd(t, b, (ssef(1.0f) - t) * a);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Movement/Shifting/Shuffling Functions
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline ssef unpacklo(const ssef &a, const ssef &b)
+{
+ return _mm_unpacklo_ps(a.m128, b.m128);
+}
+__forceinline ssef unpackhi(const ssef &a, const ssef &b)
+{
+ return _mm_unpackhi_ps(a.m128, b.m128);
+}
+
+template<size_t i0, size_t i1, size_t i2, size_t i3>
+__forceinline const ssef shuffle(const ssef &b)
+{
+# ifdef __KERNEL_NEON__
+ return shuffle_neon<float32x4_t, i0, i1, i2, i3>(b.m128);
+# else
+ return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+# endif
+}
+
+template<> __forceinline const ssef shuffle<0, 1, 0, 1>(const ssef &a)
+{
+ return _mm_movelh_ps(a, a);
+}
+
+template<> __forceinline const ssef shuffle<2, 3, 2, 3>(const ssef &a)
+{
+ return _mm_movehl_ps(a, a);
+}
+
+template<size_t i0, size_t i1, size_t i2, size_t i3>
+__forceinline const ssef shuffle(const ssef &a, const ssef &b)
+{
+# ifdef __KERNEL_NEON__
+ return shuffle_neon<float32x4_t, i0, i1, i2, i3>(a, b);
+# else
+ return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
+# endif
+}
+
+template<size_t i0> __forceinline const ssef shuffle(const ssef &a, const ssef &b)
+{
+# ifdef __KERNEL_NEON__
+ return shuffle_neon<float32x4_t, i0, i0, i0, i0>(a, b);
+# else
+ return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i0, i0, i0, i0));
+# endif
+}
+
+# ifndef __KERNEL_NEON__
+template<> __forceinline const ssef shuffle<0, 1, 0, 1>(const ssef &a, const ssef &b)
+{
+ return _mm_movelh_ps(a, b);
+}
+
+template<> __forceinline const ssef shuffle<2, 3, 2, 3>(const ssef &a, const ssef &b)
+{
+ return _mm_movehl_ps(b, a);
+}
+# endif
+
+# if defined(__KERNEL_SSSE3__)
+__forceinline const ssef shuffle8(const ssef &a, const ssei &shuf)
+{
+ return _mm_castsi128_ps(_mm_shuffle_epi8(_mm_castps_si128(a), shuf));
+}
+# endif
+
+# if defined(__KERNEL_SSE3__)
+template<> __forceinline const ssef shuffle<0, 0, 2, 2>(const ssef &b)
+{
+ return _mm_moveldup_ps(b);
+}
+template<> __forceinline const ssef shuffle<1, 1, 3, 3>(const ssef &b)
+{
+ return _mm_movehdup_ps(b);
+}
+# endif
+
+template<size_t i0> __forceinline const ssef shuffle(const ssef &b)
+{
+ return shuffle<i0, i0, i0, i0>(b);
+}
+
+# if defined(__KERNEL_AVX__)
+__forceinline const ssef shuffle(const ssef &a, const ssei &shuf)
+{
+ return _mm_permutevar_ps(a, shuf);
+}
+# endif
+
+template<size_t i> __forceinline float extract(const ssef &a)
+{
+ return _mm_cvtss_f32(shuffle<i, i, i, i>(a));
+}
+template<> __forceinline float extract<0>(const ssef &a)
+{
+ return _mm_cvtss_f32(a);
+}
+
+# if defined(__KERNEL_SSE41__)
+template<size_t dst, size_t src, size_t clr>
+__forceinline const ssef insert(const ssef &a, const ssef &b)
+{
+# ifdef __KERNEL_NEON__
+ ssef res = a;
+ if (clr)
+ res[dst] = 0;
+ else
+ res[dst] = b[src];
+ return res;
+# else
+ return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr);
+# endif
+}
+template<size_t dst, size_t src> __forceinline const ssef insert(const ssef &a, const ssef &b)
+{
+ return insert<dst, src, 0>(a, b);
+}
+template<size_t dst> __forceinline const ssef insert(const ssef &a, const float b)
+{
+ return insert<dst, 0>(a, _mm_set_ss(b));
+}
+# else
+template<size_t dst> __forceinline const ssef insert(const ssef &a, const float b)
+{
+ ssef c = a;
+ c[dst] = b;
+ return c;
+}
+# endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Transpose
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline void transpose(const ssef &r0,
+ const ssef &r1,
+ const ssef &r2,
+ const ssef &r3,
+ ssef &c0,
+ ssef &c1,
+ ssef &c2,
+ ssef &c3)
+{
+ ssef l02 = unpacklo(r0, r2);
+ ssef h02 = unpackhi(r0, r2);
+ ssef l13 = unpacklo(r1, r3);
+ ssef h13 = unpackhi(r1, r3);
+ c0 = unpacklo(l02, l13);
+ c1 = unpackhi(l02, l13);
+ c2 = unpacklo(h02, h13);
+ c3 = unpackhi(h02, h13);
+}
+
+__forceinline void transpose(
+ const ssef &r0, const ssef &r1, const ssef &r2, const ssef &r3, ssef &c0, ssef &c1, ssef &c2)
+{
+ ssef l02 = unpacklo(r0, r2);
+ ssef h02 = unpackhi(r0, r2);
+ ssef l13 = unpacklo(r1, r3);
+ ssef h13 = unpackhi(r1, r3);
+ c0 = unpacklo(l02, l13);
+ c1 = unpackhi(l02, l13);
+ c2 = unpacklo(h02, h13);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Reductions
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline const ssef vreduce_min(const ssef &v)
+{
+# ifdef __KERNEL_NEON__
+ return vdupq_n_f32(vminvq_f32(v));
+# else
+ ssef h = min(shuffle<1, 0, 3, 2>(v), v);
+ return min(shuffle<2, 3, 0, 1>(h), h);
+# endif
+}
+__forceinline const ssef vreduce_max(const ssef &v)
+{
+# ifdef __KERNEL_NEON__
+ return vdupq_n_f32(vmaxvq_f32(v));
+# else
+ ssef h = max(shuffle<1, 0, 3, 2>(v), v);
+ return max(shuffle<2, 3, 0, 1>(h), h);
+# endif
+}
+__forceinline const ssef vreduce_add(const ssef &v)
+{
+# ifdef __KERNEL_NEON__
+ return vdupq_n_f32(vaddvq_f32(v));
+# else
+ ssef h = shuffle<1, 0, 3, 2>(v) + v;
+ return shuffle<2, 3, 0, 1>(h) + h;
+# endif
+}
+
+__forceinline float reduce_min(const ssef &v)
+{
+# ifdef __KERNEL_NEON__
+ return vminvq_f32(v);
+# else
+ return _mm_cvtss_f32(vreduce_min(v));
+# endif
+}
+__forceinline float reduce_max(const ssef &v)
+{
+# ifdef __KERNEL_NEON__
+ return vmaxvq_f32(v);
+# else
+ return _mm_cvtss_f32(vreduce_max(v));
+# endif
+}
+__forceinline float reduce_add(const ssef &v)
+{
+# ifdef __KERNEL_NEON__
+ return vaddvq_f32(v);
+# else
+ return _mm_cvtss_f32(vreduce_add(v));
+# endif
+}
+
+__forceinline uint32_t select_min(const ssef &v)
+{
+ return __bsf(movemask(v == vreduce_min(v)));
+}
+__forceinline uint32_t select_max(const ssef &v)
+{
+ return __bsf(movemask(v == vreduce_max(v)));
+}
+
+__forceinline uint32_t select_min(const sseb &valid, const ssef &v)
+{
+ const ssef a = select(valid, v, ssef(pos_inf));
+ return __bsf(movemask(valid & (a == vreduce_min(a))));
+}
+__forceinline uint32_t select_max(const sseb &valid, const ssef &v)
+{
+ const ssef a = select(valid, v, ssef(neg_inf));
+ return __bsf(movemask(valid & (a == vreduce_max(a))));
+}
+
+__forceinline uint32_t movemask(const ssef &a)
+{
+ return _mm_movemask_ps(a);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Memory load and store operations
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline ssef load4f(const float4 &a)
+{
+# ifdef __KERNEL_WITH_SSE_ALIGN__
+ return _mm_load_ps(&a.x);
+# else
+ return _mm_loadu_ps(&a.x);
+# endif
+}
+
+__forceinline ssef load4f(const float3 &a)
+{
+# ifdef __KERNEL_WITH_SSE_ALIGN__
+ return _mm_load_ps(&a.x);
+# else
+ return _mm_loadu_ps(&a.x);
+# endif
+}
+
+__forceinline ssef load4f(const void *const a)
+{
+ return _mm_load_ps((float *)a);
+}
+
+__forceinline ssef load1f_first(const float a)
+{
+ return _mm_set_ss(a);
+}
+
+__forceinline void store4f(void *ptr, const ssef &v)
+{
+ _mm_store_ps((float *)ptr, v);
+}
+
+__forceinline ssef loadu4f(const void *const a)
+{
+ return _mm_loadu_ps((float *)a);
+}
+
+__forceinline void storeu4f(void *ptr, const ssef &v)
+{
+ _mm_storeu_ps((float *)ptr, v);
+}
+
+__forceinline void store4f(const sseb &mask, void *ptr, const ssef &f)
+{
+# if defined(__KERNEL_AVX__)
+ _mm_maskstore_ps((float *)ptr, (__m128i)mask, f);
+# else
+ *(ssef *)ptr = select(mask, f, *(ssef *)ptr);
+# endif
+}
+
+__forceinline ssef load4f_nt(void *ptr)
+{
+# if defined(__KERNEL_SSE41__)
+ return _mm_castsi128_ps(_mm_stream_load_si128((__m128i *)ptr));
+# else
+ return _mm_load_ps((float *)ptr);
+# endif
+}
+
+__forceinline void store4f_nt(void *ptr, const ssef &v)
+{
+# if defined(__KERNEL_SSE41__)
+ _mm_stream_ps((float *)ptr, v);
+# else
+ _mm_store_ps((float *)ptr, v);
+# endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Euclidian Space Operators
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline float dot(const ssef &a, const ssef &b)
+{
+ return reduce_add(a * b);
+}
+
+/* calculate shuffled cross product, useful when order of components does not matter */
+__forceinline ssef cross_zxy(const ssef &a, const ssef &b)
+{
+ const ssef a0 = a;
+ const ssef b0 = shuffle<1, 2, 0, 3>(b);
+ const ssef a1 = shuffle<1, 2, 0, 3>(a);
+ const ssef b1 = b;
+ return msub(a0, b0, a1 * b1);
+}
+
+__forceinline ssef cross(const ssef &a, const ssef &b)
+{
+ return shuffle<1, 2, 0, 3>(cross_zxy(a, b));
+}
+
+ccl_device_inline const ssef dot3_splat(const ssef &a, const ssef &b)
+{
+# ifdef __KERNEL_SSE41__
+ return _mm_dp_ps(a.m128, b.m128, 0x7f);
+# else
+ ssef t = a * b;
+ return ssef(((float *)&t)[0] + ((float *)&t)[1] + ((float *)&t)[2]);
+# endif
+}
+
+/* squared length taking only specified axes into account */
+template<size_t X, size_t Y, size_t Z, size_t W> ccl_device_inline float len_squared(const ssef &a)
+{
+# ifndef __KERNEL_SSE41__
+ float4 &t = (float4 &)a;
+ return (X ? t.x * t.x : 0.0f) + (Y ? t.y * t.y : 0.0f) + (Z ? t.z * t.z : 0.0f) +
+ (W ? t.w * t.w : 0.0f);
+# else
+ return extract<0>(
+ ssef(_mm_dp_ps(a.m128, a.m128, (X << 4) | (Y << 5) | (Z << 6) | (W << 7) | 0xf)));
+# endif
+}
+
+ccl_device_inline float dot3(const ssef &a, const ssef &b)
+{
+# ifdef __KERNEL_SSE41__
+ return extract<0>(ssef(_mm_dp_ps(a.m128, b.m128, 0x7f)));
+# else
+ ssef t = a * b;
+ return ((float *)&t)[0] + ((float *)&t)[1] + ((float *)&t)[2];
+# endif
+}
+
+ccl_device_inline const ssef len3_squared_splat(const ssef &a)
+{
+ return dot3_splat(a, a);
+}
+
+ccl_device_inline float len3_squared(const ssef &a)
+{
+ return dot3(a, a);
+}
+
+ccl_device_inline float len3(const ssef &a)
+{
+ return extract<0>(mm_sqrt(dot3_splat(a, a)));
+}
+
+/* SSE shuffle utility functions */
+
+# ifdef __KERNEL_SSSE3__
+
+/* faster version for SSSE3 */
+typedef ssei shuffle_swap_t;
+
+ccl_device_inline shuffle_swap_t shuffle_swap_identity()
+{
+ return _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
+}
+
+ccl_device_inline shuffle_swap_t shuffle_swap_swap()
+{
+ return _mm_set_epi8(7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8);
+}
+
+ccl_device_inline const ssef shuffle_swap(const ssef &a, const shuffle_swap_t &shuf)
+{
+ return cast(_mm_shuffle_epi8(cast(a), shuf));
+}
+
+# else
+
+/* somewhat slower version for SSE2 */
+typedef int shuffle_swap_t;
+
+ccl_device_inline shuffle_swap_t shuffle_swap_identity()
+{
+ return 0;
+}
+
+ccl_device_inline shuffle_swap_t shuffle_swap_swap()
+{
+ return 1;
+}
+
+ccl_device_inline const ssef shuffle_swap(const ssef &a, shuffle_swap_t shuf)
+{
+ /* shuffle value must be a constant, so we need to branch */
+ if (shuf)
+ return shuffle<1, 0, 3, 2>(a);
+ else
+ return shuffle<3, 2, 1, 0>(a);
+}
+
+# endif
+
+# if defined(__KERNEL_SSE41__) && !defined(__KERNEL_NEON__)
+
+ccl_device_inline void gen_idirsplat_swap(const ssef &pn,
+ const shuffle_swap_t &shuf_identity,
+ const shuffle_swap_t &shuf_swap,
+ const float3 &idir,
+ ssef idirsplat[3],
+ shuffle_swap_t shufflexyz[3])
+{
+ const __m128 idirsplat_raw[] = {_mm_set_ps1(idir.x), _mm_set_ps1(idir.y), _mm_set_ps1(idir.z)};
+ idirsplat[0] = _mm_xor_ps(idirsplat_raw[0], pn);
+ idirsplat[1] = _mm_xor_ps(idirsplat_raw[1], pn);
+ idirsplat[2] = _mm_xor_ps(idirsplat_raw[2], pn);
+
+ const ssef signmask = cast(ssei(0x80000000));
+ const ssef shuf_identity_f = cast(shuf_identity);
+ const ssef shuf_swap_f = cast(shuf_swap);
+
+ shufflexyz[0] = _mm_castps_si128(
+ _mm_blendv_ps(shuf_identity_f, shuf_swap_f, _mm_and_ps(idirsplat_raw[0], signmask)));
+ shufflexyz[1] = _mm_castps_si128(
+ _mm_blendv_ps(shuf_identity_f, shuf_swap_f, _mm_and_ps(idirsplat_raw[1], signmask)));
+ shufflexyz[2] = _mm_castps_si128(
+ _mm_blendv_ps(shuf_identity_f, shuf_swap_f, _mm_and_ps(idirsplat_raw[2], signmask)));
+}
+
+# else
+
+ccl_device_inline void gen_idirsplat_swap(const ssef &pn,
+ const shuffle_swap_t &shuf_identity,
+ const shuffle_swap_t &shuf_swap,
+ const float3 &idir,
+ ssef idirsplat[3],
+ shuffle_swap_t shufflexyz[3])
+{
+ idirsplat[0] = ssef(idir.x) ^ pn;
+ idirsplat[1] = ssef(idir.y) ^ pn;
+ idirsplat[2] = ssef(idir.z) ^ pn;
+
+ shufflexyz[0] = (idir.x >= 0) ? shuf_identity : shuf_swap;
+ shufflexyz[1] = (idir.y >= 0) ? shuf_identity : shuf_swap;
+ shufflexyz[2] = (idir.z >= 0) ? shuf_identity : shuf_swap;
+}
+
+# endif
+
+ccl_device_inline const ssef uint32_to_float(const ssei &in)
+{
+ ssei a = _mm_srli_epi32(in, 16);
+ ssei b = _mm_and_si128(in, _mm_set1_epi32(0x0000ffff));
+ ssei c = _mm_or_si128(a, _mm_set1_epi32(0x53000000));
+ ssef d = _mm_cvtepi32_ps(b);
+ ssef e = _mm_sub_ps(_mm_castsi128_ps(c), _mm_castsi128_ps(_mm_set1_epi32(0x53000000)));
+ return _mm_add_ps(e, d);
+}
+
+template<size_t S1, size_t S2, size_t S3, size_t S4>
+ccl_device_inline const ssef set_sign_bit(const ssef &a)
+{
+ return cast(cast(a) ^ ssei(S1 << 31, S2 << 31, S3 << 31, S4 << 31));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Debug Functions
+////////////////////////////////////////////////////////////////////////////////
+
+ccl_device_inline void print_ssef(const char *label, const ssef &a)
+{
+ printf(
+ "%s: %.8f %.8f %.8f %.8f\n", label, (double)a[0], (double)a[1], (double)a[2], (double)a[3]);
+}
+
+#endif
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/util/util_ssei.h b/intern/cycles/util/ssei.h
index 94412fb77e7..94412fb77e7 100644
--- a/intern/cycles/util/util_ssei.h
+++ b/intern/cycles/util/ssei.h
diff --git a/intern/cycles/util/util_stack_allocator.h b/intern/cycles/util/stack_allocator.h
index ef31c0fe5e2..ef31c0fe5e2 100644
--- a/intern/cycles/util/util_stack_allocator.h
+++ b/intern/cycles/util/stack_allocator.h
diff --git a/intern/cycles/util/util_static_assert.h b/intern/cycles/util/static_assert.h
index 7df52d462b7..7df52d462b7 100644
--- a/intern/cycles/util/util_static_assert.h
+++ b/intern/cycles/util/static_assert.h
diff --git a/intern/cycles/util/stats.h b/intern/cycles/util/stats.h
new file mode 100644
index 00000000000..590973f1cbc
--- /dev/null
+++ b/intern/cycles/util/stats.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_STATS_H__
+#define __UTIL_STATS_H__
+
+#include "util/atomic.h"
+#include "util/profiling.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Stats {
+ public:
+ enum static_init_t { static_init = 0 };
+
+ Stats() : mem_used(0), mem_peak(0)
+ {
+ }
+ explicit Stats(static_init_t)
+ {
+ }
+
+ void mem_alloc(size_t size)
+ {
+ atomic_add_and_fetch_z(&mem_used, size);
+ atomic_fetch_and_update_max_z(&mem_peak, mem_used);
+ }
+
+ void mem_free(size_t size)
+ {
+ assert(mem_used >= size);
+ atomic_sub_and_fetch_z(&mem_used, size);
+ }
+
+ size_t mem_used;
+ size_t mem_peak;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_STATS_H__ */
diff --git a/intern/cycles/util/string.cpp b/intern/cycles/util/string.cpp
new file mode 100644
index 00000000000..b98272f7759
--- /dev/null
+++ b/intern/cycles/util/string.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <algorithm>
+#include <cctype>
+
+#include "util/foreach.h"
+#include "util/string.h"
+#include "util/windows.h"
+
+#ifdef _WIN32
+# ifndef vsnprintf
+# define vsnprintf _vsnprintf
+# endif
+#endif /* _WIN32 */
+
+CCL_NAMESPACE_BEGIN
+
+string string_printf(const char *format, ...)
+{
+ vector<char> str(128, 0);
+
+ while (1) {
+ va_list args;
+ int result;
+
+ va_start(args, format);
+ result = vsnprintf(&str[0], str.size(), format, args);
+ va_end(args);
+
+ if (result == -1) {
+ /* not enough space or formatting error */
+ if (str.size() > 65536) {
+ assert(0);
+ return string("");
+ }
+
+ str.resize(str.size() * 2, 0);
+ continue;
+ }
+ else if (result >= (int)str.size()) {
+ /* not enough space */
+ str.resize(result + 1, 0);
+ continue;
+ }
+
+ return string(&str[0]);
+ }
+}
+
+bool string_iequals(const string &a, const string &b)
+{
+ if (a.size() == b.size()) {
+ for (size_t i = 0; i < a.size(); i++)
+ if (toupper(a[i]) != toupper(b[i]))
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+void string_split(vector<string> &tokens,
+ const string &str,
+ const string &separators,
+ bool skip_empty_tokens)
+{
+ size_t token_start = 0, token_length = 0;
+ for (size_t i = 0; i < str.size(); ++i) {
+ const char ch = str[i];
+ if (separators.find(ch) == string::npos) {
+ /* Current character is not a separator,
+ * append it to token by increasing token length.
+ */
+ ++token_length;
+ }
+ else {
+ /* Current character is a separator,
+ * append current token to the list.
+ */
+ if (!skip_empty_tokens || token_length > 0) {
+ string token = str.substr(token_start, token_length);
+ tokens.push_back(token);
+ }
+ token_start = i + 1;
+ token_length = 0;
+ }
+ }
+ /* Append token from the tail of the string if exists. */
+ if (token_length) {
+ string token = str.substr(token_start, token_length);
+ tokens.push_back(token);
+ }
+}
+
+bool string_startswith(const string_view s, const string_view start)
+{
+ const size_t len = start.size();
+
+ if (len > s.size()) {
+ return false;
+ }
+
+ return strncmp(s.c_str(), start.data(), len) == 0;
+}
+
+bool string_endswith(const string_view s, const string_view end)
+{
+ const size_t len = end.size();
+
+ if (len > s.size()) {
+ return false;
+ }
+
+ return strncmp(s.c_str() + s.size() - len, end.data(), len) == 0;
+}
+
+string string_strip(const string &s)
+{
+ string result = s;
+ result.erase(0, result.find_first_not_of(' '));
+ result.erase(result.find_last_not_of(' ') + 1);
+ return result;
+}
+
+void string_replace(string &haystack, const string &needle, const string &other)
+{
+ size_t i = 0, index;
+ while ((index = haystack.find(needle, i)) != string::npos) {
+ haystack.replace(index, needle.size(), other);
+ i = index + other.size();
+ }
+}
+
+string string_remove_trademark(const string &s)
+{
+ string result = s;
+
+ /* Special case, so we don't leave sequential spaces behind. */
+ /* TODO(sergey): Consider using regex perhaps? */
+ string_replace(result, " (TM)", "");
+ string_replace(result, " (R)", "");
+
+ string_replace(result, "(TM)", "");
+ string_replace(result, "(R)", "");
+
+ return string_strip(result);
+}
+
+string string_from_bool(bool var)
+{
+ if (var)
+ return "True";
+ else
+ return "False";
+}
+
+string to_string(const char *str)
+{
+ return string(str);
+}
+
+string string_to_lower(const string &s)
+{
+ string r = s;
+ std::transform(r.begin(), r.end(), r.begin(), [](char c) { return std::tolower(c); });
+ return r;
+}
+
+/* Wide char strings helpers for Windows. */
+
+#ifdef _WIN32
+
+wstring string_to_wstring(const string &str)
+{
+ const int length_wc = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
+ wstring str_wc(length_wc, 0);
+ MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &str_wc[0], length_wc);
+ return str_wc;
+}
+
+string string_from_wstring(const wstring &str)
+{
+ int length_mb = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.size(), NULL, 0, NULL, NULL);
+ string str_mb(length_mb, 0);
+ WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.size(), &str_mb[0], length_mb, NULL, NULL);
+ return str_mb;
+}
+
+string string_to_ansi(const string &str)
+{
+ const int length_wc = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
+ wstring str_wc(length_wc, 0);
+ MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &str_wc[0], length_wc);
+
+ int length_mb = WideCharToMultiByte(
+ CP_ACP, 0, str_wc.c_str(), str_wc.size(), NULL, 0, NULL, NULL);
+
+ string str_mb(length_mb, 0);
+ WideCharToMultiByte(CP_ACP, 0, str_wc.c_str(), str_wc.size(), &str_mb[0], length_mb, NULL, NULL);
+
+ return str_mb;
+}
+
+#endif /* _WIN32 */
+
+string string_human_readable_size(size_t size)
+{
+ static const char suffixes[] = "BKMGTPEZY";
+
+ const char *suffix = suffixes;
+ size_t r = 0;
+
+ while (size >= 1024) {
+ r = size % 1024;
+ size /= 1024;
+ suffix++;
+ }
+
+ if (*suffix != 'B')
+ return string_printf("%.2f%c", double(size * 1024 + r) / 1024.0, *suffix);
+ else
+ return string_printf("%zu", size);
+}
+
+string string_human_readable_number(size_t num)
+{
+ if (num == 0) {
+ return "0";
+ }
+
+ /* Add thousands separators. */
+ char buf[32];
+
+ char *p = buf + 31;
+ *p = '\0';
+
+ int i = -1;
+ while (num) {
+ if (++i && i % 3 == 0)
+ *(--p) = ',';
+
+ *(--p) = '0' + (num % 10);
+
+ num /= 10;
+ }
+
+ return p;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/string.h b/intern/cycles/util/string.h
new file mode 100644
index 00000000000..cc20a6df120
--- /dev/null
+++ b/intern/cycles/util/string.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sstream>
+#include <string.h>
+#include <string>
+
+/* Use string view implementation from OIIO.
+ * Ideally, need to switch to `std::string_view`, but this first requires getting rid of using
+ * namespace OIIO as it causes symbol collision. */
+#include <OpenImageIO/string_view.h>
+
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+using std::istringstream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::to_string;
+
+using OIIO::string_view;
+
+#ifdef __GNUC__
+# define PRINTF_ATTRIBUTE __attribute__((format(printf, 1, 2)))
+#else
+# define PRINTF_ATTRIBUTE
+#endif
+
+string string_printf(const char *format, ...) PRINTF_ATTRIBUTE;
+
+bool string_iequals(const string &a, const string &b);
+void string_split(vector<string> &tokens,
+ const string &str,
+ const string &separators = "\t ",
+ bool skip_empty_tokens = true);
+void string_replace(string &haystack, const string &needle, const string &other);
+bool string_startswith(string_view s, string_view start);
+bool string_endswith(string_view s, string_view end);
+string string_strip(const string &s);
+string string_remove_trademark(const string &s);
+string string_from_bool(const bool var);
+string to_string(const char *str);
+string string_to_lower(const string &s);
+
+/* Wide char strings are only used on Windows to deal with non-ASCII
+ * characters in file names and such. No reason to use such strings
+ * for something else at this moment.
+ *
+ * Please note that strings are expected to be in UTF-8 codepage, and
+ * if ANSI is needed then explicit conversion required.
+ */
+#ifdef _WIN32
+using std::wstring;
+wstring string_to_wstring(const string &path);
+string string_from_wstring(const wstring &path);
+string string_to_ansi(const string &str);
+#endif
+
+/* Make a string from a size in bytes in human readable form. */
+string string_human_readable_size(size_t size);
+/* Make a string from a unit-less quantity in human readable form. */
+string string_human_readable_number(size_t num);
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/system.cpp b/intern/cycles/util/system.cpp
new file mode 100644
index 00000000000..f12e15e756f
--- /dev/null
+++ b/intern/cycles/util/system.cpp
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/system.h"
+
+#include "util/log.h"
+#include "util/string.h"
+#include "util/types.h"
+
+#include <numaapi.h>
+
+#include <OpenImageIO/sysutil.h>
+OIIO_NAMESPACE_USING
+
+#ifdef _WIN32
+# if (!defined(FREE_WINDOWS))
+# include <intrin.h>
+# endif
+# include "util/windows.h"
+#elif defined(__APPLE__)
+# include <sys/ioctl.h>
+# include <sys/sysctl.h>
+# include <sys/types.h>
+#else
+# include <sys/ioctl.h>
+# include <unistd.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+bool system_cpu_ensure_initialized()
+{
+ static bool is_initialized = false;
+ static bool result = false;
+ if (is_initialized) {
+ return result;
+ }
+ is_initialized = true;
+ const NUMAAPI_Result numa_result = numaAPI_Initialize();
+ result = (numa_result == NUMAAPI_SUCCESS);
+ return result;
+}
+
+/* Fallback solution, which doesn't use NUMA/CPU groups. */
+static int system_cpu_thread_count_fallback()
+{
+#ifdef _WIN32
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ return info.dwNumberOfProcessors;
+#elif defined(__APPLE__)
+ int count;
+ size_t len = sizeof(count);
+ int mib[2] = {CTL_HW, HW_NCPU};
+ sysctl(mib, 2, &count, &len, NULL, 0);
+ return count;
+#else
+ return sysconf(_SC_NPROCESSORS_ONLN);
+#endif
+}
+
+int system_cpu_thread_count()
+{
+ const int num_nodes = system_cpu_num_numa_nodes();
+ int num_threads = 0;
+ for (int node = 0; node < num_nodes; ++node) {
+ if (!system_cpu_is_numa_node_available(node)) {
+ continue;
+ }
+ num_threads += system_cpu_num_numa_node_processors(node);
+ }
+ return num_threads;
+}
+
+int system_cpu_num_numa_nodes()
+{
+ if (!system_cpu_ensure_initialized()) {
+ /* Fallback to a single node with all the threads. */
+ return 1;
+ }
+ return numaAPI_GetNumNodes();
+}
+
+bool system_cpu_is_numa_node_available(int node)
+{
+ if (!system_cpu_ensure_initialized()) {
+ return true;
+ }
+ return numaAPI_IsNodeAvailable(node);
+}
+
+int system_cpu_num_numa_node_processors(int node)
+{
+ if (!system_cpu_ensure_initialized()) {
+ return system_cpu_thread_count_fallback();
+ }
+ return numaAPI_GetNumNodeProcessors(node);
+}
+
+bool system_cpu_run_thread_on_node(int node)
+{
+ if (!system_cpu_ensure_initialized()) {
+ return true;
+ }
+ return numaAPI_RunThreadOnNode(node);
+}
+
+int system_console_width()
+{
+ int columns = 0;
+
+#ifdef _WIN32
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
+ columns = csbi.dwSize.X;
+ }
+#else
+ struct winsize w;
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
+ columns = w.ws_col;
+ }
+#endif
+
+ return (columns > 0) ? columns : 80;
+}
+
+int system_cpu_num_active_group_processors()
+{
+ if (!system_cpu_ensure_initialized()) {
+ return system_cpu_thread_count_fallback();
+ }
+ return numaAPI_GetNumCurrentNodesProcessors();
+}
+
+/* Equivalent of Windows __cpuid for x86 processors on other platforms. */
+#if (!defined(_WIN32) || defined(FREE_WINDOWS)) && (defined(__x86_64__) || defined(__i386__))
+static void __cpuid(int data[4], int selector)
+{
+# if defined(__x86_64__)
+ asm("cpuid" : "=a"(data[0]), "=b"(data[1]), "=c"(data[2]), "=d"(data[3]) : "a"(selector));
+# elif defined(__i386__)
+ asm("pushl %%ebx \n\t"
+ "cpuid \n\t"
+ "movl %%ebx, %1 \n\t"
+ "popl %%ebx \n\t"
+ : "=a"(data[0]), "=r"(data[1]), "=c"(data[2]), "=d"(data[3])
+ : "a"(selector)
+ : "ebx");
+# else
+ data[0] = data[1] = data[2] = data[3] = 0;
+# endif
+}
+#endif
+
+string system_cpu_brand_string()
+{
+#if defined(__APPLE__)
+ /* Get from system on macOS. */
+ char modelname[512] = "";
+ size_t bufferlen = 512;
+ if (sysctlbyname("machdep.cpu.brand_string", &modelname, &bufferlen, NULL, 0) == 0) {
+ return modelname;
+ }
+#elif defined(WIN32) || defined(__x86_64__) || defined(__i386__)
+ /* Get from intrinsics on Windows and x86. */
+ char buf[49] = {0};
+ int result[4] = {0};
+
+ __cpuid(result, 0x80000000);
+
+ if (result[0] != 0 && result[0] >= (int)0x80000004) {
+ __cpuid((int *)(buf + 0), 0x80000002);
+ __cpuid((int *)(buf + 16), 0x80000003);
+ __cpuid((int *)(buf + 32), 0x80000004);
+
+ string brand = buf;
+
+ /* Make it a bit more presentable. */
+ brand = string_remove_trademark(brand);
+
+ return brand;
+ }
+#else
+ /* Get from /proc/cpuinfo on Unix systems. */
+ FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (cpuinfo != nullptr) {
+ char cpuinfo_buf[513] = "";
+ fread(cpuinfo_buf, sizeof(cpuinfo_buf) - 1, 1, cpuinfo);
+ fclose(cpuinfo);
+
+ char *modelname = strstr(cpuinfo_buf, "model name");
+ if (modelname != nullptr) {
+ modelname = strchr(modelname, ':');
+ if (modelname != nullptr) {
+ modelname += 2;
+ char *modelname_end = strchr(modelname, '\n');
+ if (modelname_end != nullptr) {
+ *modelname_end = '\0';
+ return modelname;
+ }
+ }
+ }
+ }
+#endif
+ return "Unknown CPU";
+}
+
+int system_cpu_bits()
+{
+ return (sizeof(void *) * 8);
+}
+
+#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
+
+struct CPUCapabilities {
+ bool x64;
+ bool mmx;
+ bool sse;
+ bool sse2;
+ bool sse3;
+ bool ssse3;
+ bool sse41;
+ bool sse42;
+ bool sse4a;
+ bool avx;
+ bool f16c;
+ bool avx2;
+ bool xop;
+ bool fma3;
+ bool fma4;
+ bool bmi1;
+ bool bmi2;
+};
+
+static CPUCapabilities &system_cpu_capabilities()
+{
+ static CPUCapabilities caps;
+ static bool caps_init = false;
+
+ if (!caps_init) {
+ int result[4], num;
+
+ memset(&caps, 0, sizeof(caps));
+
+ __cpuid(result, 0);
+ num = result[0];
+
+ if (num >= 1) {
+ __cpuid(result, 0x00000001);
+ caps.mmx = (result[3] & ((int)1 << 23)) != 0;
+ caps.sse = (result[3] & ((int)1 << 25)) != 0;
+ caps.sse2 = (result[3] & ((int)1 << 26)) != 0;
+ caps.sse3 = (result[2] & ((int)1 << 0)) != 0;
+
+ caps.ssse3 = (result[2] & ((int)1 << 9)) != 0;
+ caps.sse41 = (result[2] & ((int)1 << 19)) != 0;
+ caps.sse42 = (result[2] & ((int)1 << 20)) != 0;
+
+ caps.fma3 = (result[2] & ((int)1 << 12)) != 0;
+ caps.avx = false;
+ bool os_uses_xsave_xrestore = (result[2] & ((int)1 << 27)) != 0;
+ bool cpu_avx_support = (result[2] & ((int)1 << 28)) != 0;
+
+ if (os_uses_xsave_xrestore && cpu_avx_support) {
+ // Check if the OS will save the YMM registers
+ uint32_t xcr_feature_mask;
+# if defined(__GNUC__)
+ int edx; /* not used */
+ /* actual opcode for xgetbv */
+ __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(xcr_feature_mask), "=d"(edx) : "c"(0));
+# elif defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)
+ /* Minimum VS2010 SP1 compiler is required. */
+ xcr_feature_mask = (uint32_t)_xgetbv(_XCR_XFEATURE_ENABLED_MASK);
+# else
+ xcr_feature_mask = 0;
+# endif
+ caps.avx = (xcr_feature_mask & 0x6) == 0x6;
+ }
+
+ caps.f16c = (result[2] & ((int)1 << 29)) != 0;
+
+ __cpuid(result, 0x00000007);
+ caps.bmi1 = (result[1] & ((int)1 << 3)) != 0;
+ caps.bmi2 = (result[1] & ((int)1 << 8)) != 0;
+ caps.avx2 = (result[1] & ((int)1 << 5)) != 0;
+ }
+
+ caps_init = true;
+ }
+
+ return caps;
+}
+
+bool system_cpu_support_sse2()
+{
+ CPUCapabilities &caps = system_cpu_capabilities();
+ return caps.sse && caps.sse2;
+}
+
+bool system_cpu_support_sse3()
+{
+ CPUCapabilities &caps = system_cpu_capabilities();
+ return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3;
+}
+
+bool system_cpu_support_sse41()
+{
+ CPUCapabilities &caps = system_cpu_capabilities();
+ return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41;
+}
+
+bool system_cpu_support_avx()
+{
+ CPUCapabilities &caps = system_cpu_capabilities();
+ return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx;
+}
+
+bool system_cpu_support_avx2()
+{
+ CPUCapabilities &caps = system_cpu_capabilities();
+ return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx && caps.f16c &&
+ caps.avx2 && caps.fma3 && caps.bmi1 && caps.bmi2;
+}
+#else
+
+bool system_cpu_support_sse2()
+{
+ return false;
+}
+
+bool system_cpu_support_sse3()
+{
+ return false;
+}
+
+bool system_cpu_support_sse41()
+{
+ return false;
+}
+
+bool system_cpu_support_avx()
+{
+ return false;
+}
+bool system_cpu_support_avx2()
+{
+ return false;
+}
+
+#endif
+
+bool system_call_self(const vector<string> &args)
+{
+ /* Escape program and arguments in case they contain spaces. */
+ string cmd = "\"" + Sysutil::this_program_path() + "\"";
+
+ for (int i = 0; i < args.size(); i++) {
+ cmd += " \"" + args[i] + "\"";
+ }
+
+#ifdef _WIN32
+ /* Use cmd /S to avoid issues with spaces in arguments. */
+ cmd = "cmd /S /C \"" + cmd + " > nul \"";
+#else
+ /* Quiet output. */
+ cmd += " > /dev/null";
+#endif
+
+ return (system(cmd.c_str()) == 0);
+}
+
+size_t system_physical_ram()
+{
+#ifdef _WIN32
+ MEMORYSTATUSEX ram;
+ ram.dwLength = sizeof(ram);
+ GlobalMemoryStatusEx(&ram);
+ return ram.ullTotalPhys;
+#elif defined(__APPLE__)
+ uint64_t ram = 0;
+ size_t len = sizeof(ram);
+ if (sysctlbyname("hw.memsize", &ram, &len, NULL, 0) == 0) {
+ return ram;
+ }
+ return 0;
+#else
+ size_t ps = sysconf(_SC_PAGESIZE);
+ size_t pn = sysconf(_SC_PHYS_PAGES);
+ return ps * pn;
+#endif
+}
+
+uint64_t system_self_process_id()
+{
+#ifdef _WIN32
+ return GetCurrentProcessId();
+#else
+ return getpid();
+#endif
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/system.h b/intern/cycles/util/system.h
new file mode 100644
index 00000000000..425c7255cbe
--- /dev/null
+++ b/intern/cycles/util/system.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_SYSTEM_H__
+#define __UTIL_SYSTEM_H__
+
+#include "util/string.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Make sure CPU groups / NUMA API is initialized. */
+bool system_cpu_ensure_initialized();
+
+/* Get total number of threads in all NUMA nodes / CPU groups. */
+int system_cpu_thread_count();
+
+/* Get width in characters of the current console output. */
+int system_console_width();
+
+/* Get number of available nodes.
+ *
+ * This is in fact an index of last node plus one and it's not guaranteed
+ * that all nodes up to this one are available. */
+int system_cpu_num_numa_nodes();
+
+/* Returns truth if the given node is available for compute. */
+bool system_cpu_is_numa_node_available(int node);
+
+/* Get number of available processors on a given node. */
+int system_cpu_num_numa_node_processors(int node);
+
+/* Runs the current thread and its children on a specific node.
+ *
+ * Returns truth if affinity has successfully changed. */
+bool system_cpu_run_thread_on_node(int node);
+
+/* Number of processors within the current CPU group (or within active thread
+ * thread affinity). */
+int system_cpu_num_active_group_processors();
+
+string system_cpu_brand_string();
+int system_cpu_bits();
+bool system_cpu_support_sse2();
+bool system_cpu_support_sse3();
+bool system_cpu_support_sse41();
+bool system_cpu_support_avx();
+bool system_cpu_support_avx2();
+
+size_t system_physical_ram();
+
+/* Start a new process of the current application with the given arguments. */
+bool system_call_self(const vector<string> &args);
+
+/* Get identifier of the currently running process. */
+uint64_t system_self_process_id();
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_SYSTEM_H__ */
diff --git a/intern/cycles/util/task.cpp b/intern/cycles/util/task.cpp
new file mode 100644
index 00000000000..ce61bf8d6c4
--- /dev/null
+++ b/intern/cycles/util/task.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/task.h"
+#include "util/foreach.h"
+#include "util/log.h"
+#include "util/system.h"
+#include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Task Pool */
+
+TaskPool::TaskPool() : start_time(time_dt()), num_tasks_pushed(0)
+{
+}
+
+TaskPool::~TaskPool()
+{
+ cancel();
+}
+
+void TaskPool::push(TaskRunFunction &&task)
+{
+ tbb_group.run(std::move(task));
+ num_tasks_pushed++;
+}
+
+void TaskPool::wait_work(Summary *stats)
+{
+ tbb_group.wait();
+
+ if (stats != NULL) {
+ stats->time_total = time_dt() - start_time;
+ stats->num_tasks_handled = num_tasks_pushed;
+ }
+
+ num_tasks_pushed = 0;
+}
+
+void TaskPool::cancel()
+{
+ if (num_tasks_pushed > 0) {
+ tbb_group.cancel();
+ tbb_group.wait();
+ num_tasks_pushed = 0;
+ }
+}
+
+bool TaskPool::canceled()
+{
+ return tbb::is_current_task_group_canceling();
+}
+
+/* Task Scheduler */
+
+thread_mutex TaskScheduler::mutex;
+int TaskScheduler::users = 0;
+int TaskScheduler::active_num_threads = 0;
+tbb::global_control *TaskScheduler::global_control = nullptr;
+
+void TaskScheduler::init(int num_threads)
+{
+ thread_scoped_lock lock(mutex);
+ /* Multiple cycles instances can use this task scheduler, sharing the same
+ * threads, so we keep track of the number of users. */
+ ++users;
+ if (users != 1) {
+ return;
+ }
+ if (num_threads > 0) {
+ /* Automatic number of threads. */
+ VLOG(1) << "Overriding number of TBB threads to " << num_threads << ".";
+ global_control = new tbb::global_control(tbb::global_control::max_allowed_parallelism,
+ num_threads);
+ active_num_threads = num_threads;
+ }
+ else {
+ active_num_threads = system_cpu_thread_count();
+ }
+}
+
+void TaskScheduler::exit()
+{
+ thread_scoped_lock lock(mutex);
+ users--;
+ if (users == 0) {
+ delete global_control;
+ global_control = nullptr;
+ active_num_threads = 0;
+ }
+}
+
+void TaskScheduler::free_memory()
+{
+ assert(users == 0);
+}
+
+int TaskScheduler::num_threads()
+{
+ return active_num_threads;
+}
+
+/* Dedicated Task Pool */
+
+DedicatedTaskPool::DedicatedTaskPool()
+{
+ do_cancel = false;
+ do_exit = false;
+ num = 0;
+
+ worker_thread = new thread(function_bind(&DedicatedTaskPool::thread_run, this));
+}
+
+DedicatedTaskPool::~DedicatedTaskPool()
+{
+ wait();
+
+ do_exit = true;
+ queue_cond.notify_all();
+
+ worker_thread->join();
+ delete worker_thread;
+}
+
+void DedicatedTaskPool::push(TaskRunFunction &&task, bool front)
+{
+ num_increase();
+
+ /* add task to queue */
+ queue_mutex.lock();
+ if (front)
+ queue.emplace_front(std::move(task));
+ else
+ queue.emplace_back(std::move(task));
+
+ queue_cond.notify_one();
+ queue_mutex.unlock();
+}
+
+void DedicatedTaskPool::wait()
+{
+ thread_scoped_lock num_lock(num_mutex);
+
+ while (num)
+ num_cond.wait(num_lock);
+}
+
+void DedicatedTaskPool::cancel()
+{
+ do_cancel = true;
+
+ clear();
+ wait();
+
+ do_cancel = false;
+}
+
+bool DedicatedTaskPool::canceled()
+{
+ return do_cancel;
+}
+
+void DedicatedTaskPool::num_decrease(int done)
+{
+ thread_scoped_lock num_lock(num_mutex);
+ num -= done;
+
+ assert(num >= 0);
+ if (num == 0)
+ num_cond.notify_all();
+}
+
+void DedicatedTaskPool::num_increase()
+{
+ thread_scoped_lock num_lock(num_mutex);
+ num++;
+ num_cond.notify_all();
+}
+
+bool DedicatedTaskPool::thread_wait_pop(TaskRunFunction &task)
+{
+ thread_scoped_lock queue_lock(queue_mutex);
+
+ while (queue.empty() && !do_exit)
+ queue_cond.wait(queue_lock);
+
+ if (queue.empty()) {
+ assert(do_exit);
+ return false;
+ }
+
+ task = queue.front();
+ queue.pop_front();
+
+ return true;
+}
+
+void DedicatedTaskPool::thread_run()
+{
+ TaskRunFunction task;
+
+ /* keep popping off tasks */
+ while (thread_wait_pop(task)) {
+ /* run task */
+ task();
+
+ /* delete task */
+ task = nullptr;
+
+ /* notify task was done */
+ num_decrease(1);
+ }
+}
+
+void DedicatedTaskPool::clear()
+{
+ thread_scoped_lock queue_lock(queue_mutex);
+
+ /* erase all tasks from the queue */
+ int done = queue.size();
+ queue.clear();
+
+ queue_lock.unlock();
+
+ /* notify done */
+ num_decrease(done);
+}
+
+string TaskPool::Summary::full_report() const
+{
+ string report = "";
+ report += string_printf("Total time: %f\n", time_total);
+ report += string_printf("Tasks handled: %d\n", num_tasks_handled);
+ return report;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/task.h b/intern/cycles/util/task.h
new file mode 100644
index 00000000000..1a8f512b83a
--- /dev/null
+++ b/intern/cycles/util/task.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TASK_H__
+#define __UTIL_TASK_H__
+
+#include "util/list.h"
+#include "util/string.h"
+#include "util/tbb.h"
+#include "util/thread.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class TaskPool;
+class TaskScheduler;
+
+typedef function<void(void)> TaskRunFunction;
+
+/* Task Pool
+ *
+ * Pool of tasks that will be executed by the central TaskScheduler. For each
+ * pool, we can wait for all tasks to be done, or cancel them before they are
+ * done.
+ *
+ * TaskRunFunction may be created with std::bind or lambda expressions. */
+
+class TaskPool {
+ public:
+ struct Summary {
+ /* Time spent to handle all tasks. */
+ double time_total;
+
+ /* Number of all tasks handled by this pool. */
+ int num_tasks_handled;
+
+ /* A full multi-line description of the state of the pool after
+ * all work is done.
+ */
+ string full_report() const;
+ };
+
+ TaskPool();
+ ~TaskPool();
+
+ void push(TaskRunFunction &&task);
+
+ void wait_work(Summary *stats = NULL); /* work and wait until all tasks are done */
+ void cancel(); /* cancel all tasks and wait until they are no longer executing */
+
+ static bool canceled(); /* For worker threads, test if current task pool canceled. */
+
+ protected:
+ tbb::task_group tbb_group;
+
+ /* ** Statistics ** */
+
+ /* Time stamp of first task pushed. */
+ double start_time;
+
+ /* Number of all tasks pushed to the pool. Cleared after wait_work() and cancel(). */
+ int num_tasks_pushed;
+};
+
+/* Task Scheduler
+ *
+ * Central scheduler that holds running threads ready to execute tasks. A single
+ * queue holds the task from all pools. */
+
+class TaskScheduler {
+ public:
+ static void init(int num_threads = 0);
+ static void exit();
+ static void free_memory();
+
+ /* Approximate number of threads that will work on task, which may be lower
+ * or higher than the actual number of threads. Use as little as possible and
+ * leave splitting up tasks to the scheduler. */
+ static int num_threads();
+
+ protected:
+ static thread_mutex mutex;
+ static int users;
+ static int active_num_threads;
+
+#ifdef WITH_TBB_GLOBAL_CONTROL
+ static tbb::global_control *global_control;
+#endif
+};
+
+/* Dedicated Task Pool
+ *
+ * Like a TaskPool, but will launch one dedicated thread to execute all tasks.
+ *
+ * The run callback that actually executes the task may be created like this:
+ * function_bind(&MyClass::task_execute, this, _1, _2) */
+
+class DedicatedTaskPool {
+ public:
+ DedicatedTaskPool();
+ ~DedicatedTaskPool();
+
+ void push(TaskRunFunction &&run, bool front = false);
+
+ void wait(); /* wait until all tasks are done */
+ void cancel(); /* cancel all tasks, keep worker thread running */
+
+ bool canceled(); /* for worker thread, test if canceled */
+
+ protected:
+ void num_decrease(int done);
+ void num_increase();
+
+ void thread_run();
+ bool thread_wait_pop(TaskRunFunction &task);
+
+ void clear();
+
+ thread_mutex num_mutex;
+ thread_condition_variable num_cond;
+
+ list<TaskRunFunction> queue;
+ thread_mutex queue_mutex;
+ thread_condition_variable queue_cond;
+
+ int num;
+ bool do_cancel;
+ bool do_exit;
+
+ thread *worker_thread;
+};
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/util/tbb.h b/intern/cycles/util/tbb.h
new file mode 100644
index 00000000000..6fc3b8daad3
--- /dev/null
+++ b/intern/cycles/util/tbb.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2011-2020 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TBB_H__
+#define __UTIL_TBB_H__
+
+/* TBB includes <windows.h>, do it ourselves first so we are sure
+ * WIN32_LEAN_AND_MEAN and similar are defined beforehand. */
+#include "util/windows.h"
+
+#include <tbb/enumerable_thread_specific.h>
+#include <tbb/parallel_for.h>
+#include <tbb/parallel_for_each.h>
+#include <tbb/task_arena.h>
+#include <tbb/task_group.h>
+
+#if TBB_INTERFACE_VERSION_MAJOR >= 10
+# define WITH_TBB_GLOBAL_CONTROL
+# include <tbb/global_control.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+using tbb::blocked_range;
+using tbb::enumerable_thread_specific;
+using tbb::parallel_for;
+
+static inline void parallel_for_cancel()
+{
+#if TBB_INTERFACE_VERSION_MAJOR >= 12
+ tbb::task_group_context *ctx = tbb::task::current_context();
+ if (ctx) {
+ ctx->cancel_group_execution();
+ }
+#else
+ tbb::task::self().cancel_group_execution();
+#endif
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TBB_H__ */
diff --git a/intern/cycles/util/texture.h b/intern/cycles/util/texture.h
new file mode 100644
index 00000000000..5e37b79e340
--- /dev/null
+++ b/intern/cycles/util/texture.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TEXTURE_H__
+#define __UTIL_TEXTURE_H__
+
+#include "util/transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Color to use when textures are not found. */
+#define TEX_IMAGE_MISSING_R 1
+#define TEX_IMAGE_MISSING_G 0
+#define TEX_IMAGE_MISSING_B 1
+#define TEX_IMAGE_MISSING_A 1
+
+/* Interpolation types for textures
+ * cuda also use texture space to store other objects */
+typedef enum InterpolationType {
+ INTERPOLATION_NONE = -1,
+ INTERPOLATION_LINEAR = 0,
+ INTERPOLATION_CLOSEST = 1,
+ INTERPOLATION_CUBIC = 2,
+ INTERPOLATION_SMART = 3,
+
+ INTERPOLATION_NUM_TYPES,
+} InterpolationType;
+
+typedef enum ImageDataType {
+ IMAGE_DATA_TYPE_FLOAT4 = 0,
+ IMAGE_DATA_TYPE_BYTE4 = 1,
+ IMAGE_DATA_TYPE_HALF4 = 2,
+ IMAGE_DATA_TYPE_FLOAT = 3,
+ IMAGE_DATA_TYPE_BYTE = 4,
+ IMAGE_DATA_TYPE_HALF = 5,
+ IMAGE_DATA_TYPE_USHORT4 = 6,
+ IMAGE_DATA_TYPE_USHORT = 7,
+ IMAGE_DATA_TYPE_NANOVDB_FLOAT = 8,
+ IMAGE_DATA_TYPE_NANOVDB_FLOAT3 = 9,
+
+ IMAGE_DATA_NUM_TYPES
+} ImageDataType;
+
+/* Alpha types
+ * How to treat alpha in images. */
+typedef enum ImageAlphaType {
+ IMAGE_ALPHA_UNASSOCIATED = 0,
+ IMAGE_ALPHA_ASSOCIATED = 1,
+ IMAGE_ALPHA_CHANNEL_PACKED = 2,
+ IMAGE_ALPHA_IGNORE = 3,
+ IMAGE_ALPHA_AUTO = 4,
+
+ IMAGE_ALPHA_NUM_TYPES,
+} ImageAlphaType;
+
+/* Extension types for textures.
+ *
+ * Defines how the image is extrapolated past its original bounds. */
+typedef enum ExtensionType {
+ /* Cause the image to repeat horizontally and vertically. */
+ EXTENSION_REPEAT = 0,
+ /* Extend by repeating edge pixels of the image. */
+ EXTENSION_EXTEND = 1,
+ /* Clip to image size and set exterior pixels as transparent. */
+ EXTENSION_CLIP = 2,
+
+ EXTENSION_NUM_TYPES,
+} ExtensionType;
+
+typedef struct TextureInfo {
+ /* Pointer, offset or texture depending on device. */
+ uint64_t data;
+ /* Data Type */
+ uint data_type;
+ /* Interpolation and extension type. */
+ uint interpolation, extension;
+ /* Dimensions. */
+ uint width, height, depth;
+ /* Transform for 3D textures. */
+ uint use_transform_3d;
+ Transform transform_3d;
+} TextureInfo;
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TEXTURE_H__ */
diff --git a/intern/cycles/util/thread.cpp b/intern/cycles/util/thread.cpp
new file mode 100644
index 00000000000..24a0600425d
--- /dev/null
+++ b/intern/cycles/util/thread.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/thread.h"
+
+#include "util/system.h"
+#include "util/windows.h"
+
+CCL_NAMESPACE_BEGIN
+
+thread::thread(function<void()> run_cb, int node) : run_cb_(run_cb), joined_(false), node_(node)
+{
+#ifdef __APPLE__
+ /* Set the stack size to 2MB to match Linux. The default 512KB on macOS is
+ * too small for Embree, and consistent stack size also makes things more
+ * predictable in general. */
+ pthread_attr_t attribute;
+ pthread_attr_init(&attribute);
+ pthread_attr_setstacksize(&attribute, 1024 * 1024 * 2);
+ pthread_create(&pthread_id, &attribute, run, (void *)this);
+#else
+ std_thread = std::thread(&thread::run, this);
+#endif
+}
+
+thread::~thread()
+{
+ if (!joined_) {
+ join();
+ }
+}
+
+void *thread::run(void *arg)
+{
+ thread *self = (thread *)(arg);
+ if (self->node_ != -1) {
+ system_cpu_run_thread_on_node(self->node_);
+ }
+ self->run_cb_();
+ return NULL;
+}
+
+bool thread::join()
+{
+ joined_ = true;
+#ifdef __APPLE__
+ return pthread_join(pthread_id, NULL) == 0;
+#else
+ try {
+ std_thread.join();
+ return true;
+ }
+ catch (const std::system_error &) {
+ return false;
+ }
+#endif
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/thread.h b/intern/cycles/util/thread.h
new file mode 100644
index 00000000000..09686e4b23f
--- /dev/null
+++ b/intern/cycles/util/thread.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_THREAD_H__
+#define __UTIL_THREAD_H__
+
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#ifdef _WIN32
+# include "util/windows.h"
+#else
+# include <pthread.h>
+#endif
+
+/* NOTE: Use tbb/spin_mutex.h instead of util_tbb.h because some of the TBB
+ * functionality requires RTTI, which is disabled for OSL kernel. */
+#include <tbb/spin_mutex.h>
+
+#include "util/function.h"
+
+CCL_NAMESPACE_BEGIN
+
+typedef std::mutex thread_mutex;
+typedef std::unique_lock<std::mutex> thread_scoped_lock;
+typedef std::condition_variable thread_condition_variable;
+
+/* Own thread implementation similar to std::thread, so we can set a
+ * custom stack size on macOS. */
+
+class thread {
+ public:
+ /* NOTE: Node index of -1 means that affinity will be inherited from the
+ * parent thread and no override on top of that will happen. */
+ thread(function<void()> run_cb, int node = -1);
+ ~thread();
+
+ static void *run(void *arg);
+ bool join();
+
+ protected:
+ function<void()> run_cb_;
+#ifdef __APPLE__
+ pthread_t pthread_id;
+#else
+ std::thread std_thread;
+#endif
+ bool joined_;
+ int node_;
+};
+
+using thread_spin_lock = tbb::spin_mutex;
+
+class thread_scoped_spin_lock {
+ public:
+ explicit thread_scoped_spin_lock(thread_spin_lock &lock) : lock_(lock)
+ {
+ lock_.lock();
+ }
+
+ ~thread_scoped_spin_lock()
+ {
+ lock_.unlock();
+ }
+
+ /* TODO(sergey): Implement manual control over lock/unlock. */
+
+ protected:
+ thread_spin_lock &lock_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_THREAD_H__ */
diff --git a/intern/cycles/util/time.cpp b/intern/cycles/util/time.cpp
new file mode 100644
index 00000000000..62d14b063be
--- /dev/null
+++ b/intern/cycles/util/time.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/time.h"
+
+#include <stdlib.h>
+
+#if !defined(_WIN32)
+# include <sys/time.h>
+# include <unistd.h>
+#endif
+
+#include "util/math.h"
+#include "util/string.h"
+#include "util/windows.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef _WIN32
+double time_dt()
+{
+ __int64 frequency, counter;
+
+ QueryPerformanceFrequency((LARGE_INTEGER *)&frequency);
+ QueryPerformanceCounter((LARGE_INTEGER *)&counter);
+
+ return (double)counter / (double)frequency;
+}
+
+void time_sleep(double t)
+{
+ Sleep((int)(t * 1000));
+}
+#else
+double time_dt()
+{
+ struct timeval now;
+ gettimeofday(&now, NULL);
+
+ return now.tv_sec + now.tv_usec * 1e-6;
+}
+
+/* sleep t seconds */
+void time_sleep(double t)
+{
+ /* get whole seconds */
+ int s = (int)t;
+
+ if (s >= 1) {
+ sleep(s);
+
+ /* adjust parameter to remove whole seconds */
+ t -= s;
+ }
+
+ /* get microseconds */
+ int us = (int)(t * 1e6);
+ if (us > 0)
+ usleep(us);
+}
+#endif
+
+/* Time in format "hours:minutes:seconds.hundreds" */
+
+string time_human_readable_from_seconds(const double seconds)
+{
+ const int h = (((int)seconds) / (60 * 60));
+ const int m = (((int)seconds) / 60) % 60;
+ const int s = (((int)seconds) % 60);
+ const int r = (((int)(seconds * 100)) % 100);
+
+ if (h > 0) {
+ return string_printf("%.2d:%.2d:%.2d.%.2d", h, m, s, r);
+ }
+ else {
+ return string_printf("%.2d:%.2d.%.2d", m, s, r);
+ }
+}
+
+double time_human_readable_to_seconds(const string &time_string)
+{
+ /* Those are multiplies of a corresponding token surrounded by : in the
+ * time string, which denotes how to convert value to seconds.
+ * Effectively: seconds, minutes, hours, days in seconds. */
+ const int multipliers[] = {1, 60, 60 * 60, 24 * 60 * 60};
+ const int num_multiplies = sizeof(multipliers) / sizeof(*multipliers);
+ if (time_string.empty()) {
+ return 0.0;
+ }
+ double result = 0.0;
+ /* Split fractions of a second from the encoded time. */
+ vector<string> fraction_tokens;
+ string_split(fraction_tokens, time_string, ".", false);
+ const int num_fraction_tokens = fraction_tokens.size();
+ if (num_fraction_tokens == 0) {
+ /* Time string is malformed. */
+ return 0.0;
+ }
+ else if (fraction_tokens.size() == 1) {
+ /* There is no fraction of a second specified, the rest of the code
+ * handles this normally. */
+ }
+ else if (fraction_tokens.size() == 2) {
+ result = atof(fraction_tokens[1].c_str());
+ result *= pow(0.1, fraction_tokens[1].length());
+ }
+ else {
+ /* This is not a valid string, the result can not be reliable. */
+ return 0.0;
+ }
+ /* Split hours, minutes and seconds.
+ * Hours part is optional. */
+ vector<string> tokens;
+ string_split(tokens, fraction_tokens[0], ":", false);
+ const int num_tokens = tokens.size();
+ if (num_tokens > num_multiplies) {
+ /* Can not reliably represent the value. */
+ return 0.0;
+ }
+ for (int i = 0; i < num_tokens; ++i) {
+ result += atoi(tokens[num_tokens - i - 1].c_str()) * multipliers[i];
+ }
+ return result;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/time.h b/intern/cycles/util/time.h
new file mode 100644
index 00000000000..380921664e8
--- /dev/null
+++ b/intern/cycles/util/time.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TIME_H__
+#define __UTIL_TIME_H__
+
+#include "util/function.h"
+#include "util/string.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Give current time in seconds in double precision, with good accuracy. */
+
+double time_dt();
+
+/* Sleep for the specified number of seconds. */
+
+void time_sleep(double t);
+
+/* Scoped timer. */
+
+class scoped_timer {
+ public:
+ explicit scoped_timer(double *value = NULL) : value_(value)
+ {
+ time_start_ = time_dt();
+ }
+
+ ~scoped_timer()
+ {
+ if (value_ != NULL) {
+ *value_ = get_time();
+ }
+ }
+
+ double get_start() const
+ {
+ return time_start_;
+ }
+
+ double get_time() const
+ {
+ return time_dt() - time_start_;
+ }
+
+ protected:
+ double *value_;
+ double time_start_;
+};
+
+class scoped_callback_timer {
+ public:
+ using callback_type = function<void(double)>;
+
+ explicit scoped_callback_timer(callback_type cb) : cb(cb)
+ {
+ }
+
+ ~scoped_callback_timer()
+ {
+ if (cb) {
+ cb(timer.get_time());
+ }
+ }
+
+ protected:
+ scoped_timer timer;
+ callback_type cb;
+};
+
+/* Make human readable string from time, compatible with Blender metadata. */
+
+string time_human_readable_from_seconds(const double seconds);
+double time_human_readable_to_seconds(const string &str);
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/util/transform.cpp b/intern/cycles/util/transform.cpp
new file mode 100644
index 00000000000..bd990cb0f79
--- /dev/null
+++ b/intern/cycles/util/transform.cpp
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Adapted from code with license:
+ *
+ * Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+ * Digital Ltd. LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Industrial Light & Magic nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "util/transform.h"
+#include "util/projection.h"
+
+#include "util/boundbox.h"
+#include "util/math.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Transform Inverse */
+
+static bool transform_matrix4_gj_inverse(float R[][4], float M[][4])
+{
+ /* forward elimination */
+ for (int i = 0; i < 4; i++) {
+ int pivot = i;
+ float pivotsize = M[i][i];
+
+ if (pivotsize < 0)
+ pivotsize = -pivotsize;
+
+ for (int j = i + 1; j < 4; j++) {
+ float tmp = M[j][i];
+
+ if (tmp < 0)
+ tmp = -tmp;
+
+ if (tmp > pivotsize) {
+ pivot = j;
+ pivotsize = tmp;
+ }
+ }
+
+ if (UNLIKELY(pivotsize == 0.0f))
+ return false;
+
+ if (pivot != i) {
+ for (int j = 0; j < 4; j++) {
+ float tmp;
+
+ tmp = M[i][j];
+ M[i][j] = M[pivot][j];
+ M[pivot][j] = tmp;
+
+ tmp = R[i][j];
+ R[i][j] = R[pivot][j];
+ R[pivot][j] = tmp;
+ }
+ }
+
+ for (int j = i + 1; j < 4; j++) {
+ float f = M[j][i] / M[i][i];
+
+ for (int k = 0; k < 4; k++) {
+ M[j][k] -= f * M[i][k];
+ R[j][k] -= f * R[i][k];
+ }
+ }
+ }
+
+ /* backward substitution */
+ for (int i = 3; i >= 0; --i) {
+ float f;
+
+ if (UNLIKELY((f = M[i][i]) == 0.0f))
+ return false;
+
+ for (int j = 0; j < 4; j++) {
+ M[i][j] /= f;
+ R[i][j] /= f;
+ }
+
+ for (int j = 0; j < i; j++) {
+ f = M[j][i];
+
+ for (int k = 0; k < 4; k++) {
+ M[j][k] -= f * M[i][k];
+ R[j][k] -= f * R[i][k];
+ }
+ }
+ }
+
+ return true;
+}
+
+ProjectionTransform projection_inverse(const ProjectionTransform &tfm)
+{
+ ProjectionTransform tfmR = projection_identity();
+ float M[4][4], R[4][4];
+
+ memcpy(R, &tfmR, sizeof(R));
+ memcpy(M, &tfm, sizeof(M));
+
+ if (UNLIKELY(!transform_matrix4_gj_inverse(R, M))) {
+ /* matrix is degenerate (e.g. 0 scale on some axis), ideally we should
+ * never be in this situation, but try to invert it anyway with tweak */
+ M[0][0] += 1e-8f;
+ M[1][1] += 1e-8f;
+ M[2][2] += 1e-8f;
+
+ if (UNLIKELY(!transform_matrix4_gj_inverse(R, M))) {
+ return projection_identity();
+ }
+ }
+
+ memcpy(&tfmR, R, sizeof(R));
+
+ return tfmR;
+}
+
+Transform transform_inverse(const Transform &tfm)
+{
+ ProjectionTransform projection(tfm);
+ return projection_to_transform(projection_inverse(projection));
+}
+
+Transform transform_transposed_inverse(const Transform &tfm)
+{
+ ProjectionTransform projection(tfm);
+ ProjectionTransform iprojection = projection_inverse(projection);
+ return projection_to_transform(projection_transpose(iprojection));
+}
+
+/* Motion Transform */
+
+float4 transform_to_quat(const Transform &tfm)
+{
+ double trace = (double)(tfm[0][0] + tfm[1][1] + tfm[2][2]);
+ float4 qt;
+
+ if (trace > 0.0) {
+ double s = sqrt(trace + 1.0);
+
+ qt.w = (float)(s / 2.0);
+ s = 0.5 / s;
+
+ qt.x = (float)((double)(tfm[2][1] - tfm[1][2]) * s);
+ qt.y = (float)((double)(tfm[0][2] - tfm[2][0]) * s);
+ qt.z = (float)((double)(tfm[1][0] - tfm[0][1]) * s);
+ }
+ else {
+ int i = 0;
+
+ if (tfm[1][1] > tfm[i][i])
+ i = 1;
+ if (tfm[2][2] > tfm[i][i])
+ i = 2;
+
+ int j = (i + 1) % 3;
+ int k = (j + 1) % 3;
+
+ double s = sqrt((double)(tfm[i][i] - (tfm[j][j] + tfm[k][k])) + 1.0);
+
+ double q[3];
+ q[i] = s * 0.5;
+ if (s != 0.0)
+ s = 0.5 / s;
+
+ double w = (double)(tfm[k][j] - tfm[j][k]) * s;
+ q[j] = (double)(tfm[j][i] + tfm[i][j]) * s;
+ q[k] = (double)(tfm[k][i] + tfm[i][k]) * s;
+
+ qt.x = (float)q[0];
+ qt.y = (float)q[1];
+ qt.z = (float)q[2];
+ qt.w = (float)w;
+ }
+
+ return qt;
+}
+
+static void transform_decompose(DecomposedTransform *decomp, const Transform *tfm)
+{
+ /* extract translation */
+ decomp->y = make_float4(tfm->x.w, tfm->y.w, tfm->z.w, 0.0f);
+
+ /* extract rotation */
+ Transform M = *tfm;
+ M.x.w = 0.0f;
+ M.y.w = 0.0f;
+ M.z.w = 0.0f;
+
+#if 0
+ Transform R = M;
+ float norm;
+ int iteration = 0;
+
+ do {
+ Transform Rnext;
+ Transform Rit = transform_transposed_inverse(R);
+
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 4; j++)
+ Rnext[i][j] = 0.5f * (R[i][j] + Rit[i][j]);
+
+ norm = 0.0f;
+ for (int i = 0; i < 3; i++) {
+ norm = max(norm,
+ fabsf(R[i][0] - Rnext[i][0]) + fabsf(R[i][1] - Rnext[i][1]) +
+ fabsf(R[i][2] - Rnext[i][2]));
+ }
+
+ R = Rnext;
+ iteration++;
+ } while (iteration < 100 && norm > 1e-4f);
+
+ if (transform_negative_scale(R))
+ R = R * transform_scale(-1.0f, -1.0f, -1.0f);
+
+ decomp->x = transform_to_quat(R);
+
+ /* extract scale and pack it */
+ Transform scale = transform_inverse(R) * M;
+ decomp->y.w = scale.x.x;
+ decomp->z = make_float4(scale.x.y, scale.x.z, scale.y.x, scale.y.y);
+ decomp->w = make_float4(scale.y.z, scale.z.x, scale.z.y, scale.z.z);
+#else
+ float3 colx = transform_get_column(&M, 0);
+ float3 coly = transform_get_column(&M, 1);
+ float3 colz = transform_get_column(&M, 2);
+
+ /* extract scale and shear first */
+ float3 scale, shear;
+ scale.x = len(colx);
+ colx = safe_divide_float3_float(colx, scale.x);
+ shear.z = dot(colx, coly);
+ coly -= shear.z * colx;
+ scale.y = len(coly);
+ coly = safe_divide_float3_float(coly, scale.y);
+ shear.y = dot(colx, colz);
+ colz -= shear.y * colx;
+ shear.x = dot(coly, colz);
+ colz -= shear.x * coly;
+ scale.z = len(colz);
+ colz = safe_divide_float3_float(colz, scale.z);
+
+ transform_set_column(&M, 0, colx);
+ transform_set_column(&M, 1, coly);
+ transform_set_column(&M, 2, colz);
+
+ if (transform_negative_scale(M)) {
+ scale *= -1.0f;
+ M = M * transform_scale(-1.0f, -1.0f, -1.0f);
+ }
+
+ decomp->x = transform_to_quat(M);
+
+ decomp->y.w = scale.x;
+ decomp->z = make_float4(shear.z, shear.y, 0.0f, scale.y);
+ decomp->w = make_float4(shear.x, 0.0f, 0.0f, scale.z);
+#endif
+}
+
+void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size)
+{
+ /* Decompose and correct rotation. */
+ for (size_t i = 0; i < size; i++) {
+ transform_decompose(decomp + i, motion + i);
+
+ if (i > 0) {
+ /* Ensure rotation around shortest angle, negated quaternions are the same
+ * but this means we don't have to do the check in quat_interpolate */
+ if (dot(decomp[i - 1].x, decomp[i].x) < 0.0f)
+ decomp[i].x = -decomp[i].x;
+ }
+ }
+
+ /* Copy rotation to decomposed transform where scale is degenerate. This avoids weird object
+ * rotation interpolation when the scale goes to 0 for a time step.
+ *
+ * Note that this is very simple and naive implementation, which only deals with degenerated
+ * scale happening only on one frame. It is possible to improve it further by interpolating
+ * rotation into s degenerated range using rotation from time-steps from adjacent non-degenerated
+ * time steps. */
+ for (size_t i = 0; i < size; i++) {
+ const float3 scale = make_float3(decomp[i].y.w, decomp[i].z.w, decomp[i].w.w);
+ if (!is_zero(scale)) {
+ continue;
+ }
+
+ if (i > 0) {
+ decomp[i].x = decomp[i - 1].x;
+ }
+ else if (i < size - 1) {
+ decomp[i].x = decomp[i + 1].x;
+ }
+ }
+}
+
+Transform transform_from_viewplane(BoundBox2D &viewplane)
+{
+ return transform_scale(1.0f / (viewplane.right - viewplane.left),
+ 1.0f / (viewplane.top - viewplane.bottom),
+ 1.0f) *
+ transform_translate(-viewplane.left, -viewplane.bottom, 0.0f);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/transform.h b/intern/cycles/util/transform.h
new file mode 100644
index 00000000000..7bfe747fcfb
--- /dev/null
+++ b/intern/cycles/util/transform.h
@@ -0,0 +1,512 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TRANSFORM_H__
+#define __UTIL_TRANSFORM_H__
+
+#ifndef __KERNEL_GPU__
+# include <string.h>
+#endif
+
+#include "util/math.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Affine transformation, stored as 4x3 matrix. */
+
+typedef struct Transform {
+ float4 x, y, z;
+
+#ifndef __KERNEL_GPU__
+ float4 operator[](int i) const
+ {
+ return *(&x + i);
+ }
+ float4 &operator[](int i)
+ {
+ return *(&x + i);
+ }
+#endif
+} Transform;
+
+/* Transform decomposed in rotation/translation/scale. we use the same data
+ * structure as Transform, and tightly pack decomposition into it. first the
+ * rotation (4), then translation (3), then 3x3 scale matrix (9). */
+
+typedef struct DecomposedTransform {
+ float4 x, y, z, w;
+} DecomposedTransform;
+
+/* Functions */
+
+ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
+{
+ /* TODO(sergey): Disabled for now, causes crashes in certain cases. */
+#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
+ ssef x, y, z, w, aa;
+ aa = a.m128;
+
+ x = _mm_loadu_ps(&t->x.x);
+ y = _mm_loadu_ps(&t->y.x);
+ z = _mm_loadu_ps(&t->z.x);
+ w = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
+
+ _MM_TRANSPOSE4_PS(x, y, z, w);
+
+ ssef tmp = shuffle<0>(aa) * x;
+ tmp = madd(shuffle<1>(aa), y, tmp);
+ tmp = madd(shuffle<2>(aa), z, tmp);
+ tmp += w;
+
+ return float3(tmp.m128);
+#else
+ float3 c = make_float3(a.x * t->x.x + a.y * t->x.y + a.z * t->x.z + t->x.w,
+ a.x * t->y.x + a.y * t->y.y + a.z * t->y.z + t->y.w,
+ a.x * t->z.x + a.y * t->z.y + a.z * t->z.z + t->z.w);
+
+ return c;
+#endif
+}
+
+ccl_device_inline float3 transform_direction(ccl_private const Transform *t, const float3 a)
+{
+#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
+ ssef x, y, z, w, aa;
+ aa = a.m128;
+ x = _mm_loadu_ps(&t->x.x);
+ y = _mm_loadu_ps(&t->y.x);
+ z = _mm_loadu_ps(&t->z.x);
+ w = _mm_setzero_ps();
+
+ _MM_TRANSPOSE4_PS(x, y, z, w);
+
+ ssef tmp = shuffle<0>(aa) * x;
+ tmp = madd(shuffle<1>(aa), y, tmp);
+ tmp = madd(shuffle<2>(aa), z, tmp);
+
+ return float3(tmp.m128);
+#else
+ float3 c = make_float3(a.x * t->x.x + a.y * t->x.y + a.z * t->x.z,
+ a.x * t->y.x + a.y * t->y.y + a.z * t->y.z,
+ a.x * t->z.x + a.y * t->z.y + a.z * t->z.z);
+
+ return c;
+#endif
+}
+
+ccl_device_inline float3 transform_direction_transposed(ccl_private const Transform *t,
+ const float3 a)
+{
+ float3 x = make_float3(t->x.x, t->y.x, t->z.x);
+ float3 y = make_float3(t->x.y, t->y.y, t->z.y);
+ float3 z = make_float3(t->x.z, t->y.z, t->z.z);
+
+ return make_float3(dot(x, a), dot(y, a), dot(z, a));
+}
+
+ccl_device_inline Transform make_transform(float a,
+ float b,
+ float c,
+ float d,
+ float e,
+ float f,
+ float g,
+ float h,
+ float i,
+ float j,
+ float k,
+ float l)
+{
+ Transform t;
+
+ t.x.x = a;
+ t.x.y = b;
+ t.x.z = c;
+ t.x.w = d;
+ t.y.x = e;
+ t.y.y = f;
+ t.y.z = g;
+ t.y.w = h;
+ t.z.x = i;
+ t.z.y = j;
+ t.z.z = k;
+ t.z.w = l;
+
+ return t;
+}
+
+ccl_device_inline Transform euler_to_transform(const float3 euler)
+{
+ float cx = cosf(euler.x);
+ float cy = cosf(euler.y);
+ float cz = cosf(euler.z);
+ float sx = sinf(euler.x);
+ float sy = sinf(euler.y);
+ float sz = sinf(euler.z);
+
+ Transform t;
+ t.x.x = cy * cz;
+ t.y.x = cy * sz;
+ t.z.x = -sy;
+
+ t.x.y = sy * sx * cz - cx * sz;
+ t.y.y = sy * sx * sz + cx * cz;
+ t.z.y = cy * sx;
+
+ t.x.z = sy * cx * cz + sx * sz;
+ t.y.z = sy * cx * sz - sx * cz;
+ t.z.z = cy * cx;
+
+ t.x.w = t.y.w = t.z.w = 0.0f;
+ return t;
+}
+
+/* Constructs a coordinate frame from a normalized normal. */
+ccl_device_inline Transform make_transform_frame(float3 N)
+{
+ const float3 dx0 = cross(make_float3(1.0f, 0.0f, 0.0f), N);
+ const float3 dx1 = cross(make_float3(0.0f, 1.0f, 0.0f), N);
+ const float3 dx = normalize((dot(dx0, dx0) > dot(dx1, dx1)) ? dx0 : dx1);
+ const float3 dy = normalize(cross(N, dx));
+ return make_transform(dx.x, dx.y, dx.z, 0.0f, dy.x, dy.y, dy.z, 0.0f, N.x, N.y, N.z, 0.0f);
+}
+
+#ifndef __KERNEL_GPU__
+
+ccl_device_inline Transform transform_zero()
+{
+ Transform zero = {zero_float4(), zero_float4(), zero_float4()};
+ return zero;
+}
+
+ccl_device_inline Transform operator*(const Transform a, const Transform b)
+{
+ float4 c_x = make_float4(b.x.x, b.y.x, b.z.x, 0.0f);
+ float4 c_y = make_float4(b.x.y, b.y.y, b.z.y, 0.0f);
+ float4 c_z = make_float4(b.x.z, b.y.z, b.z.z, 0.0f);
+ float4 c_w = make_float4(b.x.w, b.y.w, b.z.w, 1.0f);
+
+ Transform t;
+ t.x = make_float4(dot(a.x, c_x), dot(a.x, c_y), dot(a.x, c_z), dot(a.x, c_w));
+ t.y = make_float4(dot(a.y, c_x), dot(a.y, c_y), dot(a.y, c_z), dot(a.y, c_w));
+ t.z = make_float4(dot(a.z, c_x), dot(a.z, c_y), dot(a.z, c_z), dot(a.z, c_w));
+
+ return t;
+}
+
+ccl_device_inline void print_transform(const char *label, const Transform &t)
+{
+ print_float4(label, t.x);
+ print_float4(label, t.y);
+ print_float4(label, t.z);
+ printf("\n");
+}
+
+ccl_device_inline Transform transform_translate(float3 t)
+{
+ return make_transform(1, 0, 0, t.x, 0, 1, 0, t.y, 0, 0, 1, t.z);
+}
+
+ccl_device_inline Transform transform_translate(float x, float y, float z)
+{
+ return transform_translate(make_float3(x, y, z));
+}
+
+ccl_device_inline Transform transform_scale(float3 s)
+{
+ return make_transform(s.x, 0, 0, 0, 0, s.y, 0, 0, 0, 0, s.z, 0);
+}
+
+ccl_device_inline Transform transform_scale(float x, float y, float z)
+{
+ return transform_scale(make_float3(x, y, z));
+}
+
+ccl_device_inline Transform transform_rotate(float angle, float3 axis)
+{
+ float s = sinf(angle);
+ float c = cosf(angle);
+ float t = 1.0f - c;
+
+ axis = normalize(axis);
+
+ return make_transform(axis.x * axis.x * t + c,
+ axis.x * axis.y * t - s * axis.z,
+ axis.x * axis.z * t + s * axis.y,
+ 0.0f,
+
+ axis.y * axis.x * t + s * axis.z,
+ axis.y * axis.y * t + c,
+ axis.y * axis.z * t - s * axis.x,
+ 0.0f,
+
+ axis.z * axis.x * t - s * axis.y,
+ axis.z * axis.y * t + s * axis.x,
+ axis.z * axis.z * t + c,
+ 0.0f);
+}
+
+/* Euler is assumed to be in XYZ order. */
+ccl_device_inline Transform transform_euler(float3 euler)
+{
+ return transform_rotate(euler.z, make_float3(0.0f, 0.0f, 1.0f)) *
+ transform_rotate(euler.y, make_float3(0.0f, 1.0f, 0.0f)) *
+ transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f));
+}
+
+ccl_device_inline Transform transform_identity()
+{
+ return transform_scale(1.0f, 1.0f, 1.0f);
+}
+
+ccl_device_inline bool operator==(const Transform &A, const Transform &B)
+{
+ return memcmp(&A, &B, sizeof(Transform)) == 0;
+}
+
+ccl_device_inline bool operator!=(const Transform &A, const Transform &B)
+{
+ return !(A == B);
+}
+
+ccl_device_inline float3 transform_get_column(const Transform *t, int column)
+{
+ return make_float3(t->x[column], t->y[column], t->z[column]);
+}
+
+ccl_device_inline void transform_set_column(Transform *t, int column, float3 value)
+{
+ t->x[column] = value.x;
+ t->y[column] = value.y;
+ t->z[column] = value.z;
+}
+
+Transform transform_inverse(const Transform &a);
+Transform transform_transposed_inverse(const Transform &a);
+
+ccl_device_inline bool transform_uniform_scale(const Transform &tfm, float &scale)
+{
+ /* the epsilon here is quite arbitrary, but this function is only used for
+ * surface area and bump, where we expect it to not be so sensitive */
+ float eps = 1e-6f;
+
+ float sx = len_squared(float4_to_float3(tfm.x));
+ float sy = len_squared(float4_to_float3(tfm.y));
+ float sz = len_squared(float4_to_float3(tfm.z));
+ float stx = len_squared(transform_get_column(&tfm, 0));
+ float sty = len_squared(transform_get_column(&tfm, 1));
+ float stz = len_squared(transform_get_column(&tfm, 2));
+
+ if (fabsf(sx - sy) < eps && fabsf(sx - sz) < eps && fabsf(sx - stx) < eps &&
+ fabsf(sx - sty) < eps && fabsf(sx - stz) < eps) {
+ scale = sx;
+ return true;
+ }
+
+ return false;
+}
+
+ccl_device_inline bool transform_negative_scale(const Transform &tfm)
+{
+ float3 c0 = transform_get_column(&tfm, 0);
+ float3 c1 = transform_get_column(&tfm, 1);
+ float3 c2 = transform_get_column(&tfm, 2);
+
+ return (dot(cross(c0, c1), c2) < 0.0f);
+}
+
+ccl_device_inline Transform transform_clear_scale(const Transform &tfm)
+{
+ Transform ntfm = tfm;
+
+ transform_set_column(&ntfm, 0, normalize(transform_get_column(&ntfm, 0)));
+ transform_set_column(&ntfm, 1, normalize(transform_get_column(&ntfm, 1)));
+ transform_set_column(&ntfm, 2, normalize(transform_get_column(&ntfm, 2)));
+
+ return ntfm;
+}
+
+ccl_device_inline Transform transform_empty()
+{
+ return make_transform(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+}
+
+#endif
+
+/* Motion Transform */
+
+ccl_device_inline float4 quat_interpolate(float4 q1, float4 q2, float t)
+{
+ /* Optix is using lerp to interpolate motion transformations. */
+#ifdef __KERNEL_OPTIX__
+ return normalize((1.0f - t) * q1 + t * q2);
+#else /* __KERNEL_OPTIX__ */
+ /* note: this does not ensure rotation around shortest angle, q1 and q2
+ * are assumed to be matched already in transform_motion_decompose */
+ float costheta = dot(q1, q2);
+
+ /* possible optimization: it might be possible to precompute theta/qperp */
+
+ if (costheta > 0.9995f) {
+ /* linear interpolation in degenerate case */
+ return normalize((1.0f - t) * q1 + t * q2);
+ }
+ else {
+ /* slerp */
+ float theta = acosf(clamp(costheta, -1.0f, 1.0f));
+ float4 qperp = normalize(q2 - q1 * costheta);
+ float thetap = theta * t;
+ return q1 * cosf(thetap) + qperp * sinf(thetap);
+ }
+#endif /* __KERNEL_OPTIX__ */
+}
+
+ccl_device_inline Transform transform_quick_inverse(Transform M)
+{
+ /* possible optimization: can we avoid doing this altogether and construct
+ * the inverse matrix directly from negated translation, transposed rotation,
+ * scale can be inverted but what about shearing? */
+ Transform R;
+ float det = M.x.x * (M.z.z * M.y.y - M.z.y * M.y.z) - M.y.x * (M.z.z * M.x.y - M.z.y * M.x.z) +
+ M.z.x * (M.y.z * M.x.y - M.y.y * M.x.z);
+ if (det == 0.0f) {
+ M.x.x += 1e-8f;
+ M.y.y += 1e-8f;
+ M.z.z += 1e-8f;
+ det = M.x.x * (M.z.z * M.y.y - M.z.y * M.y.z) - M.y.x * (M.z.z * M.x.y - M.z.y * M.x.z) +
+ M.z.x * (M.y.z * M.x.y - M.y.y * M.x.z);
+ }
+ det = (det != 0.0f) ? 1.0f / det : 0.0f;
+
+ float3 Rx = det * make_float3(M.z.z * M.y.y - M.z.y * M.y.z,
+ M.z.y * M.x.z - M.z.z * M.x.y,
+ M.y.z * M.x.y - M.y.y * M.x.z);
+ float3 Ry = det * make_float3(M.z.x * M.y.z - M.z.z * M.y.x,
+ M.z.z * M.x.x - M.z.x * M.x.z,
+ M.y.x * M.x.z - M.y.z * M.x.x);
+ float3 Rz = det * make_float3(M.z.y * M.y.x - M.z.x * M.y.y,
+ M.z.x * M.x.y - M.z.y * M.x.x,
+ M.y.y * M.x.x - M.y.x * M.x.y);
+ float3 T = -make_float3(M.x.w, M.y.w, M.z.w);
+
+ R.x = make_float4(Rx.x, Rx.y, Rx.z, dot(Rx, T));
+ R.y = make_float4(Ry.x, Ry.y, Ry.z, dot(Ry, T));
+ R.z = make_float4(Rz.x, Rz.y, Rz.z, dot(Rz, T));
+
+ return R;
+}
+
+ccl_device_inline void transform_compose(ccl_private Transform *tfm,
+ ccl_private const DecomposedTransform *decomp)
+{
+ /* rotation */
+ float q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc;
+
+ q0 = M_SQRT2_F * decomp->x.w;
+ q1 = M_SQRT2_F * decomp->x.x;
+ q2 = M_SQRT2_F * decomp->x.y;
+ q3 = M_SQRT2_F * decomp->x.z;
+
+ qda = q0 * q1;
+ qdb = q0 * q2;
+ qdc = q0 * q3;
+ qaa = q1 * q1;
+ qab = q1 * q2;
+ qac = q1 * q3;
+ qbb = q2 * q2;
+ qbc = q2 * q3;
+ qcc = q3 * q3;
+
+ float3 rotation_x = make_float3(1.0f - qbb - qcc, -qdc + qab, qdb + qac);
+ float3 rotation_y = make_float3(qdc + qab, 1.0f - qaa - qcc, -qda + qbc);
+ float3 rotation_z = make_float3(-qdb + qac, qda + qbc, 1.0f - qaa - qbb);
+
+ /* scale */
+ float3 scale_x = make_float3(decomp->y.w, decomp->z.z, decomp->w.y);
+ float3 scale_y = make_float3(decomp->z.x, decomp->z.w, decomp->w.z);
+ float3 scale_z = make_float3(decomp->z.y, decomp->w.x, decomp->w.w);
+
+ /* compose with translation */
+ tfm->x = make_float4(
+ dot(rotation_x, scale_x), dot(rotation_x, scale_y), dot(rotation_x, scale_z), decomp->y.x);
+ tfm->y = make_float4(
+ dot(rotation_y, scale_x), dot(rotation_y, scale_y), dot(rotation_y, scale_z), decomp->y.y);
+ tfm->z = make_float4(
+ dot(rotation_z, scale_x), dot(rotation_z, scale_y), dot(rotation_z, scale_z), decomp->y.z);
+}
+
+/* Interpolate from array of decomposed transforms. */
+ccl_device void transform_motion_array_interpolate(Transform *tfm,
+ const DecomposedTransform *motion,
+ uint numsteps,
+ float time)
+{
+ /* Figure out which steps we need to interpolate. */
+ int maxstep = numsteps - 1;
+ int step = min((int)(time * maxstep), maxstep - 1);
+ float t = time * maxstep - step;
+
+ const DecomposedTransform *a = motion + step;
+ const DecomposedTransform *b = motion + step + 1;
+
+ /* Interpolate rotation, translation and scale. */
+ DecomposedTransform decomp;
+ decomp.x = quat_interpolate(a->x, b->x, t);
+ decomp.y = (1.0f - t) * a->y + t * b->y;
+ decomp.z = (1.0f - t) * a->z + t * b->z;
+ decomp.w = (1.0f - t) * a->w + t * b->w;
+
+ /* Compose rotation, translation, scale into matrix. */
+ transform_compose(tfm, &decomp);
+}
+
+ccl_device_inline bool transform_isfinite_safe(ccl_private Transform *tfm)
+{
+ return isfinite4_safe(tfm->x) && isfinite4_safe(tfm->y) && isfinite4_safe(tfm->z);
+}
+
+ccl_device_inline bool transform_decomposed_isfinite_safe(ccl_private DecomposedTransform *decomp)
+{
+ return isfinite4_safe(decomp->x) && isfinite4_safe(decomp->y) && isfinite4_safe(decomp->z) &&
+ isfinite4_safe(decomp->w);
+}
+
+#ifndef __KERNEL_GPU__
+
+class BoundBox2D;
+
+ccl_device_inline bool operator==(const DecomposedTransform &A, const DecomposedTransform &B)
+{
+ return memcmp(&A, &B, sizeof(DecomposedTransform)) == 0;
+}
+
+float4 transform_to_quat(const Transform &tfm);
+void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size);
+Transform transform_from_viewplane(BoundBox2D &viewplane);
+
+#endif
+
+/* TODO: This can be removed when we know if no devices will require explicit
+ * address space qualifiers for this case. */
+
+#define transform_point_auto transform_point
+#define transform_direction_auto transform_direction
+#define transform_direction_transposed_auto transform_direction_transposed
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TRANSFORM_H__ */
diff --git a/intern/cycles/util/types.h b/intern/cycles/util/types.h
new file mode 100644
index 00000000000..697dc2b44ea
--- /dev/null
+++ b/intern/cycles/util/types.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_H__
+#define __UTIL_TYPES_H__
+
+#include <stdlib.h>
+
+/* Standard Integer Types */
+
+#if !defined(__KERNEL_GPU__)
+# include <stdint.h>
+#endif
+
+#include "util/defines.h"
+
+#ifndef __KERNEL_GPU__
+# include "util/optimization.h"
+# include "util/simd.h"
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* Types
+ *
+ * Define simpler unsigned type names, and integer with defined number of bits.
+ * Also vector types, named to be compatible with OpenCL builtin types, while
+ * working for CUDA and C++ too. */
+
+/* Shorter Unsigned Names */
+
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+
+/* Fixed Bits Types */
+
+#ifndef __KERNEL_GPU__
+/* Generic Memory Pointer */
+
+typedef uint64_t device_ptr;
+#endif /* __KERNEL_GPU__ */
+
+ccl_device_inline size_t align_up(size_t offset, size_t alignment)
+{
+ return (offset + alignment - 1) & ~(alignment - 1);
+}
+
+ccl_device_inline size_t divide_up(size_t x, size_t y)
+{
+ return (x + y - 1) / y;
+}
+
+ccl_device_inline size_t round_up(size_t x, size_t multiple)
+{
+ return ((x + multiple - 1) / multiple) * multiple;
+}
+
+ccl_device_inline size_t round_down(size_t x, size_t multiple)
+{
+ return (x / multiple) * multiple;
+}
+
+ccl_device_inline bool is_power_of_two(size_t x)
+{
+ return (x & (x - 1)) == 0;
+}
+
+CCL_NAMESPACE_END
+
+/* Vectorized types declaration. */
+#include "util/types_uchar2.h"
+#include "util/types_uchar3.h"
+#include "util/types_uchar4.h"
+
+#include "util/types_int2.h"
+#include "util/types_int3.h"
+#include "util/types_int4.h"
+
+#include "util/types_uint2.h"
+#include "util/types_uint3.h"
+#include "util/types_uint4.h"
+
+#include "util/types_ushort4.h"
+
+#include "util/types_float2.h"
+#include "util/types_float3.h"
+#include "util/types_float4.h"
+#include "util/types_float8.h"
+
+#include "util/types_vector3.h"
+
+/* Vectorized types implementation. */
+#include "util/types_uchar2_impl.h"
+#include "util/types_uchar3_impl.h"
+#include "util/types_uchar4_impl.h"
+
+#include "util/types_int2_impl.h"
+#include "util/types_int3_impl.h"
+#include "util/types_int4_impl.h"
+
+#include "util/types_uint2_impl.h"
+#include "util/types_uint3_impl.h"
+#include "util/types_uint4_impl.h"
+
+#include "util/types_float2_impl.h"
+#include "util/types_float3_impl.h"
+#include "util/types_float4_impl.h"
+#include "util/types_float8_impl.h"
+
+#include "util/types_vector3_impl.h"
+
+/* SSE types. */
+#ifndef __KERNEL_GPU__
+# include "util/sseb.h"
+# include "util/ssef.h"
+# include "util/ssei.h"
+# if defined(__KERNEL_AVX__) || defined(__KERNEL_AVX2__)
+# include "util/avxb.h"
+# include "util/avxf.h"
+# include "util/avxi.h"
+# endif
+#endif
+
+#endif /* __UTIL_TYPES_H__ */
diff --git a/intern/cycles/util/types_float2.h b/intern/cycles/util/types_float2.h
new file mode 100644
index 00000000000..e71204bef5b
--- /dev/null
+++ b/intern/cycles/util/types_float2.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_FLOAT2_H__
+#define __UTIL_TYPES_FLOAT2_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct float2 {
+ float x, y;
+
+ __forceinline float operator[](int i) const;
+ __forceinline float &operator[](int i);
+};
+
+ccl_device_inline float2 make_float2(float x, float y);
+ccl_device_inline void print_float2(const char *label, const float2 &a);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_FLOAT2_H__ */
diff --git a/intern/cycles/util/types_float2_impl.h b/intern/cycles/util/types_float2_impl.h
new file mode 100644
index 00000000000..c02c13f8c47
--- /dev/null
+++ b/intern/cycles/util/types_float2_impl.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_FLOAT2_IMPL_H__
+#define __UTIL_TYPES_FLOAT2_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+#ifndef __KERNEL_GPU__
+# include <cstdio>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+__forceinline float float2::operator[](int i) const
+{
+ util_assert(i >= 0);
+ util_assert(i < 2);
+ return *(&x + i);
+}
+
+__forceinline float &float2::operator[](int i)
+{
+ util_assert(i >= 0);
+ util_assert(i < 2);
+ return *(&x + i);
+}
+
+ccl_device_inline float2 make_float2(float x, float y)
+{
+ float2 a = {x, y};
+ return a;
+}
+
+ccl_device_inline void print_float2(const char *label, const float2 &a)
+{
+ printf("%s: %.8f %.8f\n", label, (double)a.x, (double)a.y);
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_FLOAT2_IMPL_H__ */
diff --git a/intern/cycles/util/types_float3.h b/intern/cycles/util/types_float3.h
new file mode 100644
index 00000000000..f990367e7b8
--- /dev/null
+++ b/intern/cycles/util/types_float3.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_FLOAT3_H__
+#define __UTIL_TYPES_FLOAT3_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct ccl_try_align(16) float3
+{
+# ifdef __KERNEL_SSE__
+ union {
+ __m128 m128;
+ struct {
+ float x, y, z, w;
+ };
+ };
+
+ __forceinline float3();
+ __forceinline float3(const float3 &a);
+ __forceinline explicit float3(const __m128 &a);
+
+ __forceinline operator const __m128 &() const;
+ __forceinline operator __m128 &();
+
+ __forceinline float3 &operator=(const float3 &a);
+# else /* __KERNEL_SSE__ */
+ float x, y, z, w;
+# endif /* __KERNEL_SSE__ */
+
+ __forceinline float operator[](int i) const;
+ __forceinline float &operator[](int i);
+};
+
+ccl_device_inline float3 make_float3(float f);
+ccl_device_inline float3 make_float3(float x, float y, float z);
+ccl_device_inline void print_float3(const char *label, const float3 &a);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_FLOAT3_H__ */
diff --git a/intern/cycles/util/types_float3_impl.h b/intern/cycles/util/types_float3_impl.h
new file mode 100644
index 00000000000..76a9067acc7
--- /dev/null
+++ b/intern/cycles/util/types_float3_impl.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_FLOAT3_IMPL_H__
+#define __UTIL_TYPES_FLOAT3_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+#ifndef __KERNEL_GPU__
+# include <cstdio>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+# ifdef __KERNEL_SSE__
+__forceinline float3::float3()
+{
+}
+
+__forceinline float3::float3(const float3 &a) : m128(a.m128)
+{
+}
+
+__forceinline float3::float3(const __m128 &a) : m128(a)
+{
+}
+
+__forceinline float3::operator const __m128 &() const
+{
+ return m128;
+}
+
+__forceinline float3::operator __m128 &()
+{
+ return m128;
+}
+
+__forceinline float3 &float3::operator=(const float3 &a)
+{
+ m128 = a.m128;
+ return *this;
+}
+# endif /* __KERNEL_SSE__ */
+
+__forceinline float float3::operator[](int i) const
+{
+ util_assert(i >= 0);
+ util_assert(i < 3);
+ return *(&x + i);
+}
+
+__forceinline float &float3::operator[](int i)
+{
+ util_assert(i >= 0);
+ util_assert(i < 3);
+ return *(&x + i);
+}
+
+ccl_device_inline float3 make_float3(float f)
+{
+# ifdef __KERNEL_SSE__
+ float3 a(_mm_set1_ps(f));
+# else
+ float3 a = {f, f, f, f};
+# endif
+ return a;
+}
+
+ccl_device_inline float3 make_float3(float x, float y, float z)
+{
+# ifdef __KERNEL_SSE__
+ float3 a(_mm_set_ps(0.0f, z, y, x));
+# else
+ float3 a = {x, y, z, 0.0f};
+# endif
+ return a;
+}
+
+ccl_device_inline void print_float3(const char *label, const float3 &a)
+{
+ printf("%s: %.8f %.8f %.8f\n", label, (double)a.x, (double)a.y, (double)a.z);
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_FLOAT3_IMPL_H__ */
diff --git a/intern/cycles/util/types_float4.h b/intern/cycles/util/types_float4.h
new file mode 100644
index 00000000000..8d4e07e7e4d
--- /dev/null
+++ b/intern/cycles/util/types_float4.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_FLOAT4_H__
+#define __UTIL_TYPES_FLOAT4_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct int4;
+
+struct ccl_try_align(16) float4
+{
+# ifdef __KERNEL_SSE__
+ union {
+ __m128 m128;
+ struct {
+ float x, y, z, w;
+ };
+ };
+
+ __forceinline float4();
+ __forceinline explicit float4(const __m128 &a);
+
+ __forceinline operator const __m128 &() const;
+ __forceinline operator __m128 &();
+
+ __forceinline float4 &operator=(const float4 &a);
+
+# else /* __KERNEL_SSE__ */
+ float x, y, z, w;
+# endif /* __KERNEL_SSE__ */
+
+ __forceinline float operator[](int i) const;
+ __forceinline float &operator[](int i);
+};
+
+ccl_device_inline float4 make_float4(float f);
+ccl_device_inline float4 make_float4(float x, float y, float z, float w);
+ccl_device_inline float4 make_float4(const int4 &i);
+ccl_device_inline void print_float4(const char *label, const float4 &a);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_FLOAT4_H__ */
diff --git a/intern/cycles/util/types_float4_impl.h b/intern/cycles/util/types_float4_impl.h
new file mode 100644
index 00000000000..d75715332e5
--- /dev/null
+++ b/intern/cycles/util/types_float4_impl.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_FLOAT4_IMPL_H__
+#define __UTIL_TYPES_FLOAT4_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+#ifndef __KERNEL_GPU__
+# include <cstdio>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+# ifdef __KERNEL_SSE__
+__forceinline float4::float4()
+{
+}
+
+__forceinline float4::float4(const __m128 &a) : m128(a)
+{
+}
+
+__forceinline float4::operator const __m128 &() const
+{
+ return m128;
+}
+
+__forceinline float4::operator __m128 &()
+{
+ return m128;
+}
+
+__forceinline float4 &float4::operator=(const float4 &a)
+{
+ m128 = a.m128;
+ return *this;
+}
+# endif /* __KERNEL_SSE__ */
+
+__forceinline float float4::operator[](int i) const
+{
+ util_assert(i >= 0);
+ util_assert(i < 4);
+ return *(&x + i);
+}
+
+__forceinline float &float4::operator[](int i)
+{
+ util_assert(i >= 0);
+ util_assert(i < 4);
+ return *(&x + i);
+}
+
+ccl_device_inline float4 make_float4(float f)
+{
+# ifdef __KERNEL_SSE__
+ float4 a(_mm_set1_ps(f));
+# else
+ float4 a = {f, f, f, f};
+# endif
+ return a;
+}
+
+ccl_device_inline float4 make_float4(float x, float y, float z, float w)
+{
+# ifdef __KERNEL_SSE__
+ float4 a(_mm_set_ps(w, z, y, x));
+# else
+ float4 a = {x, y, z, w};
+# endif
+ return a;
+}
+
+ccl_device_inline float4 make_float4(const int4 &i)
+{
+# ifdef __KERNEL_SSE__
+ float4 a(_mm_cvtepi32_ps(i.m128));
+# else
+ float4 a = {(float)i.x, (float)i.y, (float)i.z, (float)i.w};
+# endif
+ return a;
+}
+
+ccl_device_inline void print_float4(const char *label, const float4 &a)
+{
+ printf("%s: %.8f %.8f %.8f %.8f\n", label, (double)a.x, (double)a.y, (double)a.z, (double)a.w);
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_FLOAT4_IMPL_H__ */
diff --git a/intern/cycles/util/types_float8.h b/intern/cycles/util/types_float8.h
new file mode 100644
index 00000000000..cf1f66b7622
--- /dev/null
+++ b/intern/cycles/util/types_float8.h
@@ -0,0 +1,74 @@
+/*
+ * Original code Copyright 2017, Intel Corporation
+ * Modifications Copyright 2018, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __UTIL_TYPES_FLOAT8_H__
+#define __UTIL_TYPES_FLOAT8_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+
+struct ccl_try_align(32) float8
+{
+# ifdef __KERNEL_AVX2__
+ union {
+ __m256 m256;
+ struct {
+ float a, b, c, d, e, f, g, h;
+ };
+ };
+
+ __forceinline float8();
+ __forceinline float8(const float8 &a);
+ __forceinline explicit float8(const __m256 &a);
+
+ __forceinline operator const __m256 &() const;
+ __forceinline operator __m256 &();
+
+ __forceinline float8 &operator=(const float8 &a);
+
+# else /* __KERNEL_AVX2__ */
+ float a, b, c, d, e, f, g, h;
+# endif /* __KERNEL_AVX2__ */
+
+ __forceinline float operator[](int i) const;
+ __forceinline float &operator[](int i);
+};
+
+ccl_device_inline float8 make_float8(float f);
+ccl_device_inline float8
+make_float8(float a, float b, float c, float d, float e, float f, float g, float h);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_FLOAT8_H__ */
diff --git a/intern/cycles/util/types_float8_impl.h b/intern/cycles/util/types_float8_impl.h
new file mode 100644
index 00000000000..a795666adc7
--- /dev/null
+++ b/intern/cycles/util/types_float8_impl.h
@@ -0,0 +1,112 @@
+/*
+ * Original code Copyright 2017, Intel Corporation
+ * Modifications Copyright 2018, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __UTIL_TYPES_FLOAT8_IMPL_H__
+#define __UTIL_TYPES_FLOAT8_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+#ifndef __KERNEL_GPU__
+# include <cstdio>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+# ifdef __KERNEL_AVX2__
+__forceinline float8::float8()
+{
+}
+
+__forceinline float8::float8(const float8 &f) : m256(f.m256)
+{
+}
+
+__forceinline float8::float8(const __m256 &f) : m256(f)
+{
+}
+
+__forceinline float8::operator const __m256 &() const
+{
+ return m256;
+}
+
+__forceinline float8::operator __m256 &()
+{
+ return m256;
+}
+
+__forceinline float8 &float8::operator=(const float8 &f)
+{
+ m256 = f.m256;
+ return *this;
+}
+# endif /* __KERNEL_AVX2__ */
+
+__forceinline float float8::operator[](int i) const
+{
+ util_assert(i >= 0);
+ util_assert(i < 8);
+ return *(&a + i);
+}
+
+__forceinline float &float8::operator[](int i)
+{
+ util_assert(i >= 0);
+ util_assert(i < 8);
+ return *(&a + i);
+}
+
+ccl_device_inline float8 make_float8(float f)
+{
+# ifdef __KERNEL_AVX2__
+ float8 r(_mm256_set1_ps(f));
+# else
+ float8 r = {f, f, f, f, f, f, f, f};
+# endif
+ return r;
+}
+
+ccl_device_inline float8
+make_float8(float a, float b, float c, float d, float e, float f, float g, float h)
+{
+# ifdef __KERNEL_AVX2__
+ float8 r(_mm256_set_ps(a, b, c, d, e, f, g, h));
+# else
+ float8 r = {a, b, c, d, e, f, g, h};
+# endif
+ return r;
+}
+
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_FLOAT8_IMPL_H__ */
diff --git a/intern/cycles/util/types_int2.h b/intern/cycles/util/types_int2.h
new file mode 100644
index 00000000000..75970577d77
--- /dev/null
+++ b/intern/cycles/util/types_int2.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_INT2_H__
+#define __UTIL_TYPES_INT2_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct int2 {
+ int x, y;
+
+ __forceinline int operator[](int i) const;
+ __forceinline int &operator[](int i);
+};
+
+ccl_device_inline int2 make_int2(int x, int y);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_INT2_H__ */
diff --git a/intern/cycles/util/types_int2_impl.h b/intern/cycles/util/types_int2_impl.h
new file mode 100644
index 00000000000..efa63cdfd2a
--- /dev/null
+++ b/intern/cycles/util/types_int2_impl.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_INT2_IMPL_H__
+#define __UTIL_TYPES_INT2_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+int int2::operator[](int i) const
+{
+ util_assert(i >= 0);
+ util_assert(i < 2);
+ return *(&x + i);
+}
+
+int &int2::operator[](int i)
+{
+ util_assert(i >= 0);
+ util_assert(i < 2);
+ return *(&x + i);
+}
+
+ccl_device_inline int2 make_int2(int x, int y)
+{
+ int2 a = {x, y};
+ return a;
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_INT2_IMPL_H__ */
diff --git a/intern/cycles/util/types_int3.h b/intern/cycles/util/types_int3.h
new file mode 100644
index 00000000000..071a886136e
--- /dev/null
+++ b/intern/cycles/util/types_int3.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_INT3_H__
+#define __UTIL_TYPES_INT3_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct ccl_try_align(16) int3
+{
+# ifdef __KERNEL_SSE__
+ union {
+ __m128i m128;
+ struct {
+ int x, y, z, w;
+ };
+ };
+
+ __forceinline int3();
+ __forceinline int3(const int3 &a);
+ __forceinline explicit int3(const __m128i &a);
+
+ __forceinline operator const __m128i &() const;
+ __forceinline operator __m128i &();
+
+ __forceinline int3 &operator=(const int3 &a);
+# else /* __KERNEL_SSE__ */
+ int x, y, z, w;
+# endif /* __KERNEL_SSE__ */
+
+ __forceinline int operator[](int i) const;
+ __forceinline int &operator[](int i);
+};
+
+ccl_device_inline int3 make_int3(int i);
+ccl_device_inline int3 make_int3(int x, int y, int z);
+ccl_device_inline void print_int3(const char *label, const int3 &a);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_INT3_H__ */
diff --git a/intern/cycles/util/types_int3_impl.h b/intern/cycles/util/types_int3_impl.h
new file mode 100644
index 00000000000..c91c64b804e
--- /dev/null
+++ b/intern/cycles/util/types_int3_impl.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_INT3_IMPL_H__
+#define __UTIL_TYPES_INT3_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+#ifndef __KERNEL_GPU__
+# include <cstdio>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+# ifdef __KERNEL_SSE__
+__forceinline int3::int3()
+{
+}
+
+__forceinline int3::int3(const __m128i &a) : m128(a)
+{
+}
+
+__forceinline int3::int3(const int3 &a) : m128(a.m128)
+{
+}
+
+__forceinline int3::operator const __m128i &() const
+{
+ return m128;
+}
+
+__forceinline int3::operator __m128i &()
+{
+ return m128;
+}
+
+__forceinline int3 &int3::operator=(const int3 &a)
+{
+ m128 = a.m128;
+ return *this;
+}
+# endif /* __KERNEL_SSE__ */
+
+__forceinline int int3::operator[](int i) const
+{
+ util_assert(i >= 0);
+ util_assert(i < 3);
+ return *(&x + i);
+}
+
+__forceinline int &int3::operator[](int i)
+{
+ util_assert(i >= 0);
+ util_assert(i < 3);
+ return *(&x + i);
+}
+
+ccl_device_inline int3 make_int3(int i)
+{
+# ifdef __KERNEL_SSE__
+ int3 a(_mm_set1_epi32(i));
+# else
+ int3 a = {i, i, i, i};
+# endif
+ return a;
+}
+
+ccl_device_inline int3 make_int3(int x, int y, int z)
+{
+# ifdef __KERNEL_SSE__
+ int3 a(_mm_set_epi32(0, z, y, x));
+# else
+ int3 a = {x, y, z, 0};
+# endif
+
+ return a;
+}
+
+ccl_device_inline void print_int3(const char *label, const int3 &a)
+{
+ printf("%s: %d %d %d\n", label, a.x, a.y, a.z);
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_INT3_IMPL_H__ */
diff --git a/intern/cycles/util/types_int4.h b/intern/cycles/util/types_int4.h
new file mode 100644
index 00000000000..cb497d70035
--- /dev/null
+++ b/intern/cycles/util/types_int4.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_INT4_H__
+#define __UTIL_TYPES_INT4_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+
+struct float3;
+struct float4;
+
+struct ccl_try_align(16) int4
+{
+# ifdef __KERNEL_SSE__
+ union {
+ __m128i m128;
+ struct {
+ int x, y, z, w;
+ };
+ };
+
+ __forceinline int4();
+ __forceinline int4(const int4 &a);
+ __forceinline explicit int4(const __m128i &a);
+
+ __forceinline operator const __m128i &() const;
+ __forceinline operator __m128i &();
+
+ __forceinline int4 &operator=(const int4 &a);
+# else /* __KERNEL_SSE__ */
+ int x, y, z, w;
+# endif /* __KERNEL_SSE__ */
+
+ __forceinline int operator[](int i) const;
+ __forceinline int &operator[](int i);
+};
+
+ccl_device_inline int4 make_int4(int i);
+ccl_device_inline int4 make_int4(int x, int y, int z, int w);
+ccl_device_inline int4 make_int4(const float3 &f);
+ccl_device_inline int4 make_int4(const float4 &f);
+ccl_device_inline void print_int4(const char *label, const int4 &a);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_INT4_H__ */
diff --git a/intern/cycles/util/types_int4_impl.h b/intern/cycles/util/types_int4_impl.h
new file mode 100644
index 00000000000..258b42c029e
--- /dev/null
+++ b/intern/cycles/util/types_int4_impl.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_INT4_IMPL_H__
+#define __UTIL_TYPES_INT4_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+#ifndef __KERNEL_GPU__
+# include <cstdio>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+# ifdef __KERNEL_SSE__
+__forceinline int4::int4()
+{
+}
+
+__forceinline int4::int4(const int4 &a) : m128(a.m128)
+{
+}
+
+__forceinline int4::int4(const __m128i &a) : m128(a)
+{
+}
+
+__forceinline int4::operator const __m128i &() const
+{
+ return m128;
+}
+
+__forceinline int4::operator __m128i &()
+{
+ return m128;
+}
+
+__forceinline int4 &int4::operator=(const int4 &a)
+{
+ m128 = a.m128;
+ return *this;
+}
+# endif /* __KERNEL_SSE__ */
+
+__forceinline int int4::operator[](int i) const
+{
+ util_assert(i >= 0);
+ util_assert(i < 4);
+ return *(&x + i);
+}
+
+__forceinline int &int4::operator[](int i)
+{
+ util_assert(i >= 0);
+ util_assert(i < 4);
+ return *(&x + i);
+}
+
+ccl_device_inline int4 make_int4(int i)
+{
+# ifdef __KERNEL_SSE__
+ int4 a(_mm_set1_epi32(i));
+# else
+ int4 a = {i, i, i, i};
+# endif
+ return a;
+}
+
+ccl_device_inline int4 make_int4(int x, int y, int z, int w)
+{
+# ifdef __KERNEL_SSE__
+ int4 a(_mm_set_epi32(w, z, y, x));
+# else
+ int4 a = {x, y, z, w};
+# endif
+ return a;
+}
+
+ccl_device_inline int4 make_int4(const float3 &f)
+{
+# ifdef __KERNEL_SSE__
+ int4 a(_mm_cvtps_epi32(f.m128));
+# else
+ int4 a = {(int)f.x, (int)f.y, (int)f.z, (int)f.w};
+# endif
+ return a;
+}
+
+ccl_device_inline int4 make_int4(const float4 &f)
+{
+# ifdef __KERNEL_SSE__
+ int4 a(_mm_cvtps_epi32(f.m128));
+# else
+ int4 a = {(int)f.x, (int)f.y, (int)f.z, (int)f.w};
+# endif
+ return a;
+}
+
+ccl_device_inline void print_int4(const char *label, const int4 &a)
+{
+ printf("%s: %d %d %d %d\n", label, a.x, a.y, a.z, a.w);
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_INT4_IMPL_H__ */
diff --git a/intern/cycles/util/types_uchar2.h b/intern/cycles/util/types_uchar2.h
new file mode 100644
index 00000000000..0dc1d46bf29
--- /dev/null
+++ b/intern/cycles/util/types_uchar2.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UCHAR2_H__
+#define __UTIL_TYPES_UCHAR2_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct uchar2 {
+ uchar x, y;
+
+ __forceinline uchar operator[](int i) const;
+ __forceinline uchar &operator[](int i);
+};
+
+ccl_device_inline uchar2 make_uchar2(uchar x, uchar y);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UCHAR2_H__ */
diff --git a/intern/cycles/util/types_uchar2_impl.h b/intern/cycles/util/types_uchar2_impl.h
new file mode 100644
index 00000000000..234a71a2247
--- /dev/null
+++ b/intern/cycles/util/types_uchar2_impl.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UCHAR2_IMPL_H__
+#define __UTIL_TYPES_UCHAR2_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+uchar uchar2::operator[](int i) const
+{
+ util_assert(i >= 0);
+ util_assert(i < 2);
+ return *(&x + i);
+}
+
+uchar &uchar2::operator[](int i)
+{
+ util_assert(i >= 0);
+ util_assert(i < 2);
+ return *(&x + i);
+}
+
+ccl_device_inline uchar2 make_uchar2(uchar x, uchar y)
+{
+ uchar2 a = {x, y};
+ return a;
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UCHAR2_IMPL_H__ */
diff --git a/intern/cycles/util/types_uchar3.h b/intern/cycles/util/types_uchar3.h
new file mode 100644
index 00000000000..d3913afb3a2
--- /dev/null
+++ b/intern/cycles/util/types_uchar3.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UCHAR3_H__
+#define __UTIL_TYPES_UCHAR3_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct uchar3 {
+ uchar x, y, z;
+
+ __forceinline uchar operator[](int i) const;
+ __forceinline uchar &operator[](int i);
+};
+
+ccl_device_inline uchar3 make_uchar3(uchar x, uchar y, uchar z);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UCHAR3_H__ */
diff --git a/intern/cycles/util/types_uchar3_impl.h b/intern/cycles/util/types_uchar3_impl.h
new file mode 100644
index 00000000000..90f510e3b28
--- /dev/null
+++ b/intern/cycles/util/types_uchar3_impl.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UCHAR3_IMPL_H__
+#define __UTIL_TYPES_UCHAR3_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+uchar uchar3::operator[](int i) const
+{
+ util_assert(i >= 0);
+ util_assert(i < 3);
+ return *(&x + i);
+}
+
+uchar &uchar3::operator[](int i)
+{
+ util_assert(i >= 0);
+ util_assert(i < 3);
+ return *(&x + i);
+}
+
+ccl_device_inline uchar3 make_uchar3(uchar x, uchar y, uchar z)
+{
+ uchar3 a = {x, y, z};
+ return a;
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UCHAR3_IMPL_H__ */
diff --git a/intern/cycles/util/types_uchar4.h b/intern/cycles/util/types_uchar4.h
new file mode 100644
index 00000000000..bfe1c06acd8
--- /dev/null
+++ b/intern/cycles/util/types_uchar4.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UCHAR4_H__
+#define __UTIL_TYPES_UCHAR4_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct uchar4 {
+ uchar x, y, z, w;
+
+ __forceinline uchar operator[](int i) const;
+ __forceinline uchar &operator[](int i);
+};
+
+ccl_device_inline uchar4 make_uchar4(uchar x, uchar y, uchar z, uchar w);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UCHAR4_H__ */
diff --git a/intern/cycles/util/types_uchar4_impl.h b/intern/cycles/util/types_uchar4_impl.h
new file mode 100644
index 00000000000..d15c74bed03
--- /dev/null
+++ b/intern/cycles/util/types_uchar4_impl.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UCHAR4_IMPL_H__
+#define __UTIL_TYPES_UCHAR4_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+uchar uchar4::operator[](int i) const
+{
+ util_assert(i >= 0);
+ util_assert(i < 4);
+ return *(&x + i);
+}
+
+uchar &uchar4::operator[](int i)
+{
+ util_assert(i >= 0);
+ util_assert(i < 4);
+ return *(&x + i);
+}
+
+ccl_device_inline uchar4 make_uchar4(uchar x, uchar y, uchar z, uchar w)
+{
+ uchar4 a = {x, y, z, w};
+ return a;
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UCHAR4_IMPL_H__ */
diff --git a/intern/cycles/util/types_uint2.h b/intern/cycles/util/types_uint2.h
new file mode 100644
index 00000000000..7419977040b
--- /dev/null
+++ b/intern/cycles/util/types_uint2.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UINT2_H__
+#define __UTIL_TYPES_UINT2_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct uint2 {
+ uint x, y;
+
+ __forceinline uint operator[](uint i) const;
+ __forceinline uint &operator[](uint i);
+};
+
+ccl_device_inline uint2 make_uint2(uint x, uint y);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UINT2_H__ */
diff --git a/intern/cycles/util/types_uint2_impl.h b/intern/cycles/util/types_uint2_impl.h
new file mode 100644
index 00000000000..8427f9694b5
--- /dev/null
+++ b/intern/cycles/util/types_uint2_impl.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UINT2_IMPL_H__
+#define __UTIL_TYPES_UINT2_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+__forceinline uint uint2::operator[](uint i) const
+{
+ util_assert(i < 2);
+ return *(&x + i);
+}
+
+__forceinline uint &uint2::operator[](uint i)
+{
+ util_assert(i < 2);
+ return *(&x + i);
+}
+
+ccl_device_inline uint2 make_uint2(uint x, uint y)
+{
+ uint2 a = {x, y};
+ return a;
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UINT2_IMPL_H__ */
diff --git a/intern/cycles/util/types_uint3.h b/intern/cycles/util/types_uint3.h
new file mode 100644
index 00000000000..1e97e7f2d36
--- /dev/null
+++ b/intern/cycles/util/types_uint3.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UINT3_H__
+#define __UTIL_TYPES_UINT3_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct uint3 {
+ uint x, y, z;
+
+ __forceinline uint operator[](uint i) const;
+ __forceinline uint &operator[](uint i);
+};
+
+ccl_device_inline uint3 make_uint3(uint x, uint y, uint z);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UINT3_H__ */
diff --git a/intern/cycles/util/types_uint3_impl.h b/intern/cycles/util/types_uint3_impl.h
new file mode 100644
index 00000000000..ba83cffe9a8
--- /dev/null
+++ b/intern/cycles/util/types_uint3_impl.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UINT3_IMPL_H__
+#define __UTIL_TYPES_UINT3_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+__forceinline uint uint3::operator[](uint i) const
+{
+ util_assert(i < 3);
+ return *(&x + i);
+}
+
+__forceinline uint &uint3::operator[](uint i)
+{
+ util_assert(i < 3);
+ return *(&x + i);
+}
+
+ccl_device_inline uint3 make_uint3(uint x, uint y, uint z)
+{
+ uint3 a = {x, y, z};
+ return a;
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UINT3_IMPL_H__ */
diff --git a/intern/cycles/util/types_uint4.h b/intern/cycles/util/types_uint4.h
new file mode 100644
index 00000000000..b135877b890
--- /dev/null
+++ b/intern/cycles/util/types_uint4.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UINT4_H__
+#define __UTIL_TYPES_UINT4_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+struct uint4 {
+ uint x, y, z, w;
+
+ __forceinline uint operator[](uint i) const;
+ __forceinline uint &operator[](uint i);
+};
+
+ccl_device_inline uint4 make_uint4(uint x, uint y, uint z, uint w);
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UINT4_H__ */
diff --git a/intern/cycles/util/types_uint4_impl.h b/intern/cycles/util/types_uint4_impl.h
new file mode 100644
index 00000000000..b860fbfc49a
--- /dev/null
+++ b/intern/cycles/util/types_uint4_impl.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_UINT4_IMPL_H__
+#define __UTIL_TYPES_UINT4_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+__forceinline uint uint4::operator[](uint i) const
+{
+ util_assert(i < 3);
+ return *(&x + i);
+}
+
+__forceinline uint &uint4::operator[](uint i)
+{
+ util_assert(i < 3);
+ return *(&x + i);
+}
+
+ccl_device_inline uint4 make_uint4(uint x, uint y, uint z, uint w)
+{
+ uint4 a = {x, y, z, w};
+ return a;
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_UINT4_IMPL_H__ */
diff --git a/intern/cycles/util/types_ushort4.h b/intern/cycles/util/types_ushort4.h
new file mode 100644
index 00000000000..8d080bcc1b9
--- /dev/null
+++ b/intern/cycles/util/types_ushort4.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_USHORT4_H__
+#define __UTIL_TYPES_USHORT4_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+
+struct ushort4 {
+ uint16_t x, y, z, w;
+};
+
+#endif
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_USHORT4_H__ */
diff --git a/intern/cycles/util/types_vector3.h b/intern/cycles/util/types_vector3.h
new file mode 100644
index 00000000000..d46a0266855
--- /dev/null
+++ b/intern/cycles/util/types_vector3.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_VECTOR3_H__
+#define __UTIL_TYPES_VECTOR3_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+template<typename T> class vector3 {
+ public:
+ T x, y, z;
+
+ __forceinline vector3();
+ __forceinline vector3(const T &a);
+ __forceinline vector3(const T &x, const T &y, const T &z);
+};
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_VECTOR3_H__ */
diff --git a/intern/cycles/util/types_vector3_impl.h b/intern/cycles/util/types_vector3_impl.h
new file mode 100644
index 00000000000..ff6dcd85b12
--- /dev/null
+++ b/intern/cycles/util/types_vector3_impl.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011-2017 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TYPES_VECTOR3_IMPL_H__
+#define __UTIL_TYPES_VECTOR3_IMPL_H__
+
+#ifndef __UTIL_TYPES_H__
+# error "Do not include this file directly, include util/types.h instead."
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifndef __KERNEL_GPU__
+template<typename T> ccl_always_inline vector3<T>::vector3()
+{
+}
+
+template<typename T> ccl_always_inline vector3<T>::vector3(const T &a) : x(a), y(a), z(a)
+{
+}
+
+template<typename T>
+ccl_always_inline vector3<T>::vector3(const T &x, const T &y, const T &z) : x(x), y(y), z(z)
+{
+}
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TYPES_VECTOR3_IMPL_H__ */
diff --git a/intern/cycles/util/util_unique_ptr.h b/intern/cycles/util/unique_ptr.h
index 3181eafd43d..3181eafd43d 100644
--- a/intern/cycles/util/util_unique_ptr.h
+++ b/intern/cycles/util/unique_ptr.h
diff --git a/intern/cycles/util/util_aligned_malloc.cpp b/intern/cycles/util/util_aligned_malloc.cpp
deleted file mode 100644
index 9b729cd4fc4..00000000000
--- a/intern/cycles/util/util_aligned_malloc.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2011-2015 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_aligned_malloc.h"
-#include "util/util_guarded_allocator.h"
-
-#include <cassert>
-
-/* Adopted from Libmv. */
-
-#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
-/* Needed for memalign on Linux and _aligned_alloc on Windows. */
-# ifdef FREE_WINDOWS
-/* Make sure _aligned_malloc is included. */
-# ifdef __MSVCRT_VERSION__
-# undef __MSVCRT_VERSION__
-# endif
-# define __MSVCRT_VERSION__ 0x0700
-# endif /* FREE_WINDOWS */
-# include <malloc.h>
-#else
-/* Apple's malloc is 16-byte aligned, and does not have malloc.h, so include
- * stdilb instead.
- */
-# include <cstdlib>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-void *util_aligned_malloc(size_t size, int alignment)
-{
-#ifdef WITH_BLENDER_GUARDEDALLOC
- return MEM_mallocN_aligned(size, alignment, "Cycles Aligned Alloc");
-#elif defined(_WIN32)
- return _aligned_malloc(size, alignment);
-#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
- void *result;
- if (posix_memalign(&result, alignment, size)) {
- /* Non-zero means allocation error
- * either no allocation or bad alignment value.
- */
- return NULL;
- }
- return result;
-#else /* This is for Linux. */
- return memalign(alignment, size);
-#endif
-}
-
-void util_aligned_free(void *ptr)
-{
-#if defined(WITH_BLENDER_GUARDEDALLOC)
- if (ptr != NULL) {
- MEM_freeN(ptr);
- }
-#elif defined(_WIN32)
- _aligned_free(ptr);
-#else
- free(ptr);
-#endif
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_aligned_malloc.h b/intern/cycles/util/util_aligned_malloc.h
deleted file mode 100644
index df7d93c056d..00000000000
--- a/intern/cycles/util/util_aligned_malloc.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011-2015 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_ALIGNED_MALLOC_H__
-#define __UTIL_ALIGNED_MALLOC_H__
-
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Minimum alignment needed by all CPU native data types (SSE, AVX). */
-#define MIN_ALIGNMENT_CPU_DATA_TYPES 16
-
-/* Allocate block of size bytes at least aligned to a given value. */
-void *util_aligned_malloc(size_t size, int alignment);
-
-/* Free memory allocated by util_aligned_malloc. */
-void util_aligned_free(void *ptr);
-
-/* Aligned new operator. */
-template<typename T, typename... Args> T *util_aligned_new(Args... args)
-{
- void *mem = util_aligned_malloc(sizeof(T), alignof(T));
- return new (mem) T(args...);
-}
-
-template<typename T> void util_aligned_delete(T *t)
-{
- if (t) {
- t->~T();
- util_aligned_free(t);
- }
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_ALIGNED_MALLOC_H__ */
diff --git a/intern/cycles/util/util_array.h b/intern/cycles/util/util_array.h
deleted file mode 100644
index 73f7d6cf7f8..00000000000
--- a/intern/cycles/util/util_array.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_ARRAY_H__
-#define __UTIL_ARRAY_H__
-
-#include <cassert>
-#include <cstring>
-
-#include "util/util_aligned_malloc.h"
-#include "util/util_guarded_allocator.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Simplified version of vector, serving multiple purposes:
- * - somewhat faster in that it does not clear memory on resize/alloc,
- * this was actually showing up in profiles quite significantly. it
- * also does not run any constructors/destructors
- * - if this is used, we are not tempted to use inefficient operations
- * - aligned allocation for CPU native data types */
-
-template<typename T, size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES> class array {
- public:
- array() : data_(NULL), datasize_(0), capacity_(0)
- {
- }
-
- explicit array(size_t newsize)
- {
- if (newsize == 0) {
- data_ = NULL;
- datasize_ = 0;
- capacity_ = 0;
- }
- else {
- data_ = mem_allocate(newsize);
- datasize_ = newsize;
- capacity_ = datasize_;
- }
- }
-
- array(const array &from)
- {
- if (from.datasize_ == 0) {
- data_ = NULL;
- datasize_ = 0;
- capacity_ = 0;
- }
- else {
- data_ = mem_allocate(from.datasize_);
- if (from.datasize_ > 0) {
- memcpy(data_, from.data_, from.datasize_ * sizeof(T));
- }
- datasize_ = from.datasize_;
- capacity_ = datasize_;
- }
- }
-
- array &operator=(const array &from)
- {
- if (this != &from) {
- resize(from.size());
- if (datasize_ > 0) {
- memcpy((void *)data_, from.data_, datasize_ * sizeof(T));
- }
- }
-
- return *this;
- }
-
- array &operator=(const vector<T> &from)
- {
- resize(from.size());
-
- if (from.size() > 0 && datasize_ > 0) {
- memcpy(data_, &from[0], datasize_ * sizeof(T));
- }
-
- return *this;
- }
-
- ~array()
- {
- mem_free(data_, capacity_);
- }
-
- bool operator==(const array<T> &other) const
- {
- if (datasize_ != other.datasize_) {
- return false;
- }
- if (datasize_ == 0) {
- return true;
- }
-
- return memcmp(data_, other.data_, datasize_ * sizeof(T)) == 0;
- }
-
- bool operator!=(const array<T> &other) const
- {
- return !(*this == other);
- }
-
- void steal_data(array &from)
- {
- if (this != &from) {
- clear();
-
- data_ = from.data_;
- datasize_ = from.datasize_;
- capacity_ = from.capacity_;
-
- from.data_ = NULL;
- from.datasize_ = 0;
- from.capacity_ = 0;
- }
- }
-
- void set_data(T *ptr_, size_t datasize)
- {
- clear();
- data_ = ptr_;
- datasize_ = datasize;
- capacity_ = datasize;
- }
-
- T *steal_pointer()
- {
- T *ptr = data_;
- data_ = NULL;
- clear();
- return ptr;
- }
-
- T *resize(size_t newsize)
- {
- if (newsize == 0) {
- clear();
- }
- else if (newsize != datasize_) {
- if (newsize > capacity_) {
- T *newdata = mem_allocate(newsize);
- if (newdata == NULL) {
- /* Allocation failed, likely out of memory. */
- clear();
- return NULL;
- }
- else if (data_ != NULL) {
- memcpy(
- (void *)newdata, data_, ((datasize_ < newsize) ? datasize_ : newsize) * sizeof(T));
- mem_free(data_, capacity_);
- }
- data_ = newdata;
- capacity_ = newsize;
- }
- datasize_ = newsize;
- }
- return data_;
- }
-
- T *resize(size_t newsize, const T &value)
- {
- size_t oldsize = size();
- resize(newsize);
-
- for (size_t i = oldsize; i < size(); i++) {
- data_[i] = value;
- }
-
- return data_;
- }
-
- void clear()
- {
- if (data_ != NULL) {
- mem_free(data_, capacity_);
- data_ = NULL;
- }
- datasize_ = 0;
- capacity_ = 0;
- }
-
- size_t empty() const
- {
- return datasize_ == 0;
- }
-
- size_t size() const
- {
- return datasize_;
- }
-
- T *data()
- {
- return data_;
- }
-
- const T *data() const
- {
- return data_;
- }
-
- T &operator[](size_t i) const
- {
- assert(i < datasize_);
- return data_[i];
- }
-
- T *begin()
- {
- return data_;
- }
-
- const T *begin() const
- {
- return data_;
- }
-
- T *end()
- {
- return data_ + datasize_;
- }
-
- const T *end() const
- {
- return data_ + datasize_;
- }
-
- void reserve(size_t newcapacity)
- {
- if (newcapacity > capacity_) {
- T *newdata = mem_allocate(newcapacity);
- if (data_ != NULL) {
- memcpy(newdata, data_, ((datasize_ < newcapacity) ? datasize_ : newcapacity) * sizeof(T));
- mem_free(data_, capacity_);
- }
- data_ = newdata;
- capacity_ = newcapacity;
- }
- }
-
- size_t capacity() const
- {
- return capacity_;
- }
-
- // do not use this method unless you are sure the code is not performance critical
- void push_back_slow(const T &t)
- {
- if (capacity_ == datasize_) {
- reserve(datasize_ == 0 ? 1 : (size_t)((datasize_ + 1) * 1.2));
- }
-
- data_[datasize_++] = t;
- }
-
- void push_back_reserved(const T &t)
- {
- assert(datasize_ < capacity_);
- push_back_slow(t);
- }
-
- void append(const array<T> &from)
- {
- if (from.size()) {
- size_t old_size = size();
- resize(old_size + from.size());
- memcpy(data_ + old_size, from.data(), sizeof(T) * from.size());
- }
- }
-
- protected:
- inline T *mem_allocate(size_t N)
- {
- if (N == 0) {
- return NULL;
- }
- T *mem = (T *)util_aligned_malloc(sizeof(T) * N, alignment);
- if (mem != NULL) {
- util_guarded_mem_alloc(sizeof(T) * N);
- }
- else {
- throw std::bad_alloc();
- }
- return mem;
- }
-
- inline void mem_free(T *mem, size_t N)
- {
- if (mem != NULL) {
- util_guarded_mem_free(sizeof(T) * N);
- util_aligned_free(mem);
- }
- }
-
- T *data_;
- size_t datasize_;
- size_t capacity_;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_ARRAY_H__ */
diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h
deleted file mode 100644
index 7fab7bd5a15..00000000000
--- a/intern/cycles/util/util_boundbox.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_BOUNDBOX_H__
-#define __UTIL_BOUNDBOX_H__
-
-#include <float.h>
-#include <math.h>
-
-#include "util/util_math.h"
-#include "util/util_string.h"
-#include "util/util_transform.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* 3D BoundBox */
-
-class BoundBox {
- public:
- float3 min, max;
-
- __forceinline BoundBox()
- {
- }
-
- __forceinline BoundBox(const float3 &pt) : min(pt), max(pt)
- {
- }
-
- __forceinline BoundBox(const float3 &min_, const float3 &max_) : min(min_), max(max_)
- {
- }
-
- enum empty_t { empty = 0 };
-
- __forceinline BoundBox(empty_t)
- : min(make_float3(FLT_MAX, FLT_MAX, FLT_MAX)), max(make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX))
- {
- }
-
- __forceinline void grow(const float3 &pt)
- {
- /* the order of arguments to min is such that if pt is nan, it will not
- * influence the resulting bounding box */
- min = ccl::min(pt, min);
- max = ccl::max(pt, max);
- }
-
- __forceinline void grow(const float3 &pt, float border)
- {
- float3 shift = make_float3(border, border, border);
- min = ccl::min(pt - shift, min);
- max = ccl::max(pt + shift, max);
- }
-
- __forceinline void grow(const BoundBox &bbox)
- {
- grow(bbox.min);
- grow(bbox.max);
- }
-
- __forceinline void grow_safe(const float3 &pt)
- {
- /* the order of arguments to min is such that if pt is nan, it will not
- * influence the resulting bounding box */
- if (isfinite(pt.x) && isfinite(pt.y) && isfinite(pt.z)) {
- min = ccl::min(pt, min);
- max = ccl::max(pt, max);
- }
- }
-
- __forceinline void grow_safe(const float3 &pt, float border)
- {
- if (isfinite(pt.x) && isfinite(pt.y) && isfinite(pt.z) && isfinite(border)) {
- float3 shift = make_float3(border, border, border);
- min = ccl::min(pt - shift, min);
- max = ccl::max(pt + shift, max);
- }
- }
-
- __forceinline void grow_safe(const BoundBox &bbox)
- {
- grow_safe(bbox.min);
- grow_safe(bbox.max);
- }
-
- __forceinline void intersect(const BoundBox &bbox)
- {
- min = ccl::max(min, bbox.min);
- max = ccl::min(max, bbox.max);
- }
-
- /* todo: avoid using this */
- __forceinline float safe_area() const
- {
- if (!((min.x <= max.x) && (min.y <= max.y) && (min.z <= max.z)))
- return 0.0f;
-
- return area();
- }
-
- __forceinline float area() const
- {
- return half_area() * 2.0f;
- }
-
- __forceinline float half_area() const
- {
- float3 d = max - min;
- return (d.x * d.z + d.y * d.z + d.x * d.y);
- }
-
- __forceinline float3 center() const
- {
- return 0.5f * (min + max);
- }
-
- __forceinline float3 center2() const
- {
- return min + max;
- }
-
- __forceinline float3 size() const
- {
- return max - min;
- }
-
- __forceinline bool valid() const
- {
- return (min.x <= max.x) && (min.y <= max.y) && (min.z <= max.z) &&
- (isfinite(min.x) && isfinite(min.y) && isfinite(min.z)) &&
- (isfinite(max.x) && isfinite(max.y) && isfinite(max.z));
- }
-
- BoundBox transformed(const Transform *tfm) const
- {
- BoundBox result = BoundBox::empty;
-
- for (int i = 0; i < 8; i++) {
- float3 p;
-
- p.x = (i & 1) ? min.x : max.x;
- p.y = (i & 2) ? min.y : max.y;
- p.z = (i & 4) ? min.z : max.z;
-
- result.grow(transform_point(tfm, p));
- }
-
- return result;
- }
-
- __forceinline bool intersects(const BoundBox &other)
- {
- float3 center_diff = center() - other.center(), total_size = (size() + other.size()) * 0.5f;
- return fabsf(center_diff.x) <= total_size.x && fabsf(center_diff.y) <= total_size.y &&
- fabsf(center_diff.z) <= total_size.z;
- }
-};
-
-__forceinline BoundBox merge(const BoundBox &bbox, const float3 &pt)
-{
- return BoundBox(min(bbox.min, pt), max(bbox.max, pt));
-}
-
-__forceinline BoundBox merge(const BoundBox &a, const BoundBox &b)
-{
- return BoundBox(min(a.min, b.min), max(a.max, b.max));
-}
-
-__forceinline BoundBox merge(const BoundBox &a,
- const BoundBox &b,
- const BoundBox &c,
- const BoundBox &d)
-{
- return merge(merge(a, b), merge(c, d));
-}
-
-__forceinline BoundBox intersect(const BoundBox &a, const BoundBox &b)
-{
- return BoundBox(max(a.min, b.min), min(a.max, b.max));
-}
-
-__forceinline BoundBox intersect(const BoundBox &a, const BoundBox &b, const BoundBox &c)
-{
- return intersect(a, intersect(b, c));
-}
-
-/* 2D BoundBox */
-
-class BoundBox2D {
- public:
- float left;
- float right;
- float bottom;
- float top;
-
- BoundBox2D() : left(0.0f), right(1.0f), bottom(0.0f), top(1.0f)
- {
- }
-
- bool operator==(const BoundBox2D &other) const
- {
- return (left == other.left && right == other.right && bottom == other.bottom &&
- top == other.top);
- }
-
- float width()
- {
- return right - left;
- }
-
- float height()
- {
- return top - bottom;
- }
-
- BoundBox2D operator*(float f) const
- {
- BoundBox2D result;
-
- result.left = left * f;
- result.right = right * f;
- result.bottom = bottom * f;
- result.top = top * f;
-
- return result;
- }
-
- BoundBox2D subset(const BoundBox2D &other) const
- {
- BoundBox2D subset;
-
- subset.left = left + other.left * (right - left);
- subset.right = left + other.right * (right - left);
- subset.bottom = bottom + other.bottom * (top - bottom);
- subset.top = bottom + other.top * (top - bottom);
-
- return subset;
- }
-
- BoundBox2D make_relative_to(const BoundBox2D &other) const
- {
- BoundBox2D result;
-
- result.left = ((left - other.left) / (other.right - other.left));
- result.right = ((right - other.left) / (other.right - other.left));
- result.bottom = ((bottom - other.bottom) / (other.top - other.bottom));
- result.top = ((top - other.bottom) / (other.top - other.bottom));
-
- return result;
- }
-
- BoundBox2D clamp(float mn = 0.0f, float mx = 1.0f)
- {
- BoundBox2D result;
-
- result.left = ccl::clamp(left, mn, mx);
- result.right = ccl::clamp(right, mn, mx);
- result.bottom = ccl::clamp(bottom, mn, mx);
- result.top = ccl::clamp(top, mn, mx);
-
- return result;
- }
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_BOUNDBOX_H__ */
diff --git a/intern/cycles/util/util_color.h b/intern/cycles/util/util_color.h
deleted file mode 100644
index 361c36d9061..00000000000
--- a/intern/cycles/util/util_color.h
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_COLOR_H__
-#define __UTIL_COLOR_H__
-
-#include "util/util_math.h"
-#include "util/util_types.h"
-
-#if !defined(__KERNEL_GPU__) && defined(__KERNEL_SSE2__)
-# include "util/util_simd.h"
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device uchar float_to_byte(float val)
-{
- return ((val <= 0.0f) ? 0 :
- ((val > (1.0f - 0.5f / 255.0f)) ? 255 : (uchar)((255.0f * val) + 0.5f)));
-}
-
-ccl_device uchar4 color_float_to_byte(float3 c)
-{
- uchar r, g, b;
-
- r = float_to_byte(c.x);
- g = float_to_byte(c.y);
- b = float_to_byte(c.z);
-
- return make_uchar4(r, g, b, 0);
-}
-
-ccl_device uchar4 color_float4_to_uchar4(float4 c)
-{
- uchar r, g, b, a;
-
- r = float_to_byte(c.x);
- g = float_to_byte(c.y);
- b = float_to_byte(c.z);
- a = float_to_byte(c.w);
-
- return make_uchar4(r, g, b, a);
-}
-
-ccl_device_inline float3 color_byte_to_float(uchar4 c)
-{
- return make_float3(c.x * (1.0f / 255.0f), c.y * (1.0f / 255.0f), c.z * (1.0f / 255.0f));
-}
-
-ccl_device_inline float4 color_uchar4_to_float4(uchar4 c)
-{
- return make_float4(
- c.x * (1.0f / 255.0f), c.y * (1.0f / 255.0f), c.z * (1.0f / 255.0f), c.w * (1.0f / 255.0f));
-}
-
-ccl_device float color_srgb_to_linear(float c)
-{
- if (c < 0.04045f)
- return (c < 0.0f) ? 0.0f : c * (1.0f / 12.92f);
- else
- return powf((c + 0.055f) * (1.0f / 1.055f), 2.4f);
-}
-
-ccl_device float color_linear_to_srgb(float c)
-{
- if (c < 0.0031308f)
- return (c < 0.0f) ? 0.0f : c * 12.92f;
- else
- return 1.055f * powf(c, 1.0f / 2.4f) - 0.055f;
-}
-
-ccl_device float3 rgb_to_hsv(float3 rgb)
-{
- float cmax, cmin, h, s, v, cdelta;
- float3 c;
-
- cmax = fmaxf(rgb.x, fmaxf(rgb.y, rgb.z));
- cmin = min(rgb.x, min(rgb.y, rgb.z));
- cdelta = cmax - cmin;
-
- v = cmax;
-
- if (cmax != 0.0f) {
- s = cdelta / cmax;
- }
- else {
- s = 0.0f;
- h = 0.0f;
- }
-
- if (s != 0.0f) {
- float3 cmax3 = make_float3(cmax, cmax, cmax);
- c = (cmax3 - rgb) / cdelta;
-
- if (rgb.x == cmax)
- h = c.z - c.y;
- else if (rgb.y == cmax)
- h = 2.0f + c.x - c.z;
- else
- h = 4.0f + c.y - c.x;
-
- h /= 6.0f;
-
- if (h < 0.0f)
- h += 1.0f;
- }
- else {
- h = 0.0f;
- }
-
- return make_float3(h, s, v);
-}
-
-ccl_device float3 hsv_to_rgb(float3 hsv)
-{
- float i, f, p, q, t, h, s, v;
- float3 rgb;
-
- h = hsv.x;
- s = hsv.y;
- v = hsv.z;
-
- if (s != 0.0f) {
- if (h == 1.0f)
- h = 0.0f;
-
- h *= 6.0f;
- i = floorf(h);
- f = h - i;
- rgb = make_float3(f, f, f);
- p = v * (1.0f - s);
- q = v * (1.0f - (s * f));
- t = v * (1.0f - (s * (1.0f - f)));
-
- if (i == 0.0f)
- rgb = make_float3(v, t, p);
- else if (i == 1.0f)
- rgb = make_float3(q, v, p);
- else if (i == 2.0f)
- rgb = make_float3(p, v, t);
- else if (i == 3.0f)
- rgb = make_float3(p, q, v);
- else if (i == 4.0f)
- rgb = make_float3(t, p, v);
- else
- rgb = make_float3(v, p, q);
- }
- else {
- rgb = make_float3(v, v, v);
- }
-
- return rgb;
-}
-
-ccl_device float3 xyY_to_xyz(float x, float y, float Y)
-{
- float X, Z;
-
- if (y != 0.0f)
- X = (x / y) * Y;
- else
- X = 0.0f;
-
- if (y != 0.0f && Y != 0.0f)
- Z = (1.0f - x - y) / y * Y;
- else
- Z = 0.0f;
-
- return make_float3(X, Y, Z);
-}
-
-#ifdef __KERNEL_SSE2__
-/*
- * Calculate initial guess for arg^exp based on float representation
- * This method gives a constant bias,
- * which can be easily compensated by multiplication with bias_coeff.
- * Gives better results for exponents near 1 (e. g. 4/5).
- * exp = exponent, encoded as uint32_t
- * e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent), encoded as uint32_t
- */
-template<unsigned exp, unsigned e2coeff> ccl_device_inline ssef fastpow(const ssef &arg)
-{
- ssef ret;
- ret = arg * cast(ssei(e2coeff));
- ret = ssef(cast(ret));
- ret = ret * cast(ssei(exp));
- ret = cast(ssei(ret));
- return ret;
-}
-
-/* Improve x ^ 1.0f/5.0f solution with Newton-Raphson method */
-ccl_device_inline ssef improve_5throot_solution(const ssef &old_result, const ssef &x)
-{
- ssef approx2 = old_result * old_result;
- ssef approx4 = approx2 * approx2;
- ssef t = x / approx4;
- ssef summ = madd(ssef(4.0f), old_result, t);
- return summ * ssef(1.0f / 5.0f);
-}
-
-/* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */
-ccl_device_inline ssef fastpow24(const ssef &arg)
-{
- /* max, avg and |avg| errors were calculated in gcc without FMA instructions
- * The final precision should be better than powf in glibc */
-
- /* Calculate x^4/5, coefficient 0.994 was constructed manually to minimize avg error */
- /* 0x3F4CCCCD = 4/5 */
- /* 0x4F55A7FB = 2^(127/(4/5) - 127) * 0.994^(1/(4/5)) */
- ssef x = fastpow<0x3F4CCCCD, 0x4F55A7FB>(arg); // error max = 0.17 avg = 0.0018 |avg| = 0.05
- ssef arg2 = arg * arg;
- ssef arg4 = arg2 * arg2;
-
- /* error max = 0.018 avg = 0.0031 |avg| = 0.0031 */
- x = improve_5throot_solution(x, arg4);
- /* error max = 0.00021 avg = 1.6e-05 |avg| = 1.6e-05 */
- x = improve_5throot_solution(x, arg4);
- /* error max = 6.1e-07 avg = 5.2e-08 |avg| = 1.1e-07 */
- x = improve_5throot_solution(x, arg4);
-
- return x * (x * x);
-}
-
-ccl_device ssef color_srgb_to_linear(const ssef &c)
-{
- sseb cmp = c < ssef(0.04045f);
- ssef lt = max(c * ssef(1.0f / 12.92f), ssef(0.0f));
- ssef gtebase = (c + ssef(0.055f)) * ssef(1.0f / 1.055f); /* fma */
- ssef gte = fastpow24(gtebase);
- return select(cmp, lt, gte);
-}
-#endif /* __KERNEL_SSE2__ */
-
-ccl_device float3 color_srgb_to_linear_v3(float3 c)
-{
- return make_float3(
- color_srgb_to_linear(c.x), color_srgb_to_linear(c.y), color_srgb_to_linear(c.z));
-}
-
-ccl_device float3 color_linear_to_srgb_v3(float3 c)
-{
- return make_float3(
- color_linear_to_srgb(c.x), color_linear_to_srgb(c.y), color_linear_to_srgb(c.z));
-}
-
-ccl_device float4 color_linear_to_srgb_v4(float4 c)
-{
- return make_float4(
- color_linear_to_srgb(c.x), color_linear_to_srgb(c.y), color_linear_to_srgb(c.z), c.w);
-}
-
-ccl_device float4 color_srgb_to_linear_v4(float4 c)
-{
-#ifdef __KERNEL_SSE2__
- ssef r_ssef;
- float4 &r = (float4 &)r_ssef;
- r = c;
- r_ssef = color_srgb_to_linear(r_ssef);
- r.w = c.w;
- return r;
-#else
- return make_float4(
- color_srgb_to_linear(c.x), color_srgb_to_linear(c.y), color_srgb_to_linear(c.z), c.w);
-#endif
-}
-
-ccl_device float3 color_highlight_compress(float3 color, ccl_private float3 *variance)
-{
- color += one_float3();
- if (variance) {
- *variance *= sqr3(one_float3() / color);
- }
- return log3(color);
-}
-
-ccl_device float3 color_highlight_uncompress(float3 color)
-{
- return exp3(color) - one_float3();
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_COLOR_H__ */
diff --git a/intern/cycles/util/util_debug.cpp b/intern/cycles/util/util_debug.cpp
deleted file mode 100644
index 2245668d02f..00000000000
--- a/intern/cycles/util/util_debug.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_debug.h"
-
-#include <stdlib.h>
-
-#include "bvh/bvh_params.h"
-
-#include "util/util_logging.h"
-#include "util/util_string.h"
-
-CCL_NAMESPACE_BEGIN
-
-DebugFlags::CPU::CPU()
- : avx2(true), avx(true), sse41(true), sse3(true), sse2(true), bvh_layout(BVH_LAYOUT_AUTO)
-{
- reset();
-}
-
-void DebugFlags::CPU::reset()
-{
-#define STRINGIFY(x) #x
-#define CHECK_CPU_FLAGS(flag, env) \
- do { \
- flag = (getenv(env) == NULL); \
- if (!flag) { \
- VLOG(1) << "Disabling " << STRINGIFY(flag) << " instruction set."; \
- } \
- } while (0)
-
- CHECK_CPU_FLAGS(avx2, "CYCLES_CPU_NO_AVX2");
- CHECK_CPU_FLAGS(avx, "CYCLES_CPU_NO_AVX");
- CHECK_CPU_FLAGS(sse41, "CYCLES_CPU_NO_SSE41");
- CHECK_CPU_FLAGS(sse3, "CYCLES_CPU_NO_SSE3");
- CHECK_CPU_FLAGS(sse2, "CYCLES_CPU_NO_SSE2");
-
-#undef STRINGIFY
-#undef CHECK_CPU_FLAGS
-
- bvh_layout = BVH_LAYOUT_AUTO;
-}
-
-DebugFlags::CUDA::CUDA() : adaptive_compile(false)
-{
- reset();
-}
-
-DebugFlags::HIP::HIP() : adaptive_compile(false)
-{
- reset();
-}
-
-void DebugFlags::CUDA::reset()
-{
- if (getenv("CYCLES_CUDA_ADAPTIVE_COMPILE") != NULL)
- adaptive_compile = true;
-}
-
-void DebugFlags::HIP::reset()
-{
- if (getenv("CYCLES_HIP_ADAPTIVE_COMPILE") != NULL)
- adaptive_compile = true;
-}
-
-DebugFlags::OptiX::OptiX()
-{
- reset();
-}
-
-void DebugFlags::OptiX::reset()
-{
- use_debug = false;
-}
-
-DebugFlags::DebugFlags() : viewport_static_bvh(false), running_inside_blender(false)
-{
- /* Nothing for now. */
-}
-
-void DebugFlags::reset()
-{
- viewport_static_bvh = false;
- cpu.reset();
- cuda.reset();
- optix.reset();
-}
-
-std::ostream &operator<<(std::ostream &os, DebugFlagsConstRef debug_flags)
-{
- os << "CPU flags:\n"
- << " AVX2 : " << string_from_bool(debug_flags.cpu.avx2) << "\n"
- << " AVX : " << string_from_bool(debug_flags.cpu.avx) << "\n"
- << " SSE4.1 : " << string_from_bool(debug_flags.cpu.sse41) << "\n"
- << " SSE3 : " << string_from_bool(debug_flags.cpu.sse3) << "\n"
- << " SSE2 : " << string_from_bool(debug_flags.cpu.sse2) << "\n"
- << " BVH layout : " << bvh_layout_name(debug_flags.cpu.bvh_layout) << "\n";
-
- os << "CUDA flags:\n"
- << " Adaptive Compile : " << string_from_bool(debug_flags.cuda.adaptive_compile) << "\n";
-
- os << "OptiX flags:\n"
- << " Debug : " << string_from_bool(debug_flags.optix.use_debug) << "\n";
-
- os << "HIP flags:\n"
- << " HIP streams : " << string_from_bool(debug_flags.hip.adaptive_compile) << "\n";
-
- return os;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_debug.h b/intern/cycles/util/util_debug.h
deleted file mode 100644
index 81677201790..00000000000
--- a/intern/cycles/util/util_debug.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_DEBUG_H__
-#define __UTIL_DEBUG_H__
-
-#include <cassert>
-#include <iostream>
-
-#include "bvh/bvh_params.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Global storage for all sort of flags used to fine-tune behavior of particular
- * areas for the development purposes, without officially exposing settings to
- * the interface.
- */
-class DebugFlags {
- public:
- /* Use static BVH in viewport, to match final render exactly. */
- bool viewport_static_bvh;
-
- bool running_inside_blender;
-
- /* Descriptor of CPU feature-set to be used. */
- struct CPU {
- CPU();
-
- /* Reset flags to their defaults. */
- void reset();
-
- /* Flags describing which instructions sets are allowed for use. */
- bool avx2;
- bool avx;
- bool sse41;
- bool sse3;
- bool sse2;
-
- /* Check functions to see whether instructions up to the given one
- * are allowed for use.
- */
- bool has_avx2()
- {
- return has_avx() && avx2;
- }
- bool has_avx()
- {
- return has_sse41() && avx;
- }
- bool has_sse41()
- {
- return has_sse3() && sse41;
- }
- bool has_sse3()
- {
- return has_sse2() && sse3;
- }
- bool has_sse2()
- {
- return sse2;
- }
-
- /* Requested BVH layout.
- *
- * By default the fastest will be used. For debugging the BVH used by other
- * CPUs and GPUs can be selected here instead.
- */
- BVHLayout bvh_layout;
- };
-
- /* Descriptor of CUDA feature-set to be used. */
- struct CUDA {
- CUDA();
-
- /* Reset flags to their defaults. */
- void reset();
-
- /* Whether adaptive feature based runtime compile is enabled or not.
- * Requires the CUDA Toolkit and only works on Linux at the moment. */
- bool adaptive_compile;
- };
-
- /* Descriptor of HIP feature-set to be used. */
- struct HIP {
- HIP();
-
- /* Reset flags to their defaults. */
- void reset();
-
- /* Whether adaptive feature based runtime compile is enabled or not.*/
- bool adaptive_compile;
- };
-
- /* Descriptor of OptiX feature-set to be used. */
- struct OptiX {
- OptiX();
-
- /* Reset flags to their defaults. */
- void reset();
-
- /* Load OptiX module with debug capabilities. Will lower logging verbosity level, enable
- * validations, and lower optimization level. */
- bool use_debug;
- };
-
- /* Get instance of debug flags registry. */
- static DebugFlags &get()
- {
- static DebugFlags instance;
- return instance;
- }
-
- /* Reset flags to their defaults. */
- void reset();
-
- /* Requested CPU flags. */
- CPU cpu;
-
- /* Requested CUDA flags. */
- CUDA cuda;
-
- /* Requested OptiX flags. */
- OptiX optix;
-
- /* Requested HIP flags. */
- HIP hip;
-
- private:
- DebugFlags();
-
-#if (__cplusplus > 199711L)
- public:
- explicit DebugFlags(DebugFlags const & /*other*/) = delete;
- void operator=(DebugFlags const & /*other*/) = delete;
-#else
- private:
- explicit DebugFlags(DebugFlags const & /*other*/);
- void operator=(DebugFlags const & /*other*/);
-#endif
-};
-
-typedef DebugFlags &DebugFlagsRef;
-typedef const DebugFlags &DebugFlagsConstRef;
-
-inline DebugFlags &DebugFlags()
-{
- return DebugFlags::get();
-}
-
-std::ostream &operator<<(std::ostream &os, DebugFlagsConstRef debug_flags);
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_DEBUG_H__ */
diff --git a/intern/cycles/util/util_defines.h b/intern/cycles/util/util_defines.h
deleted file mode 100644
index 9b1698d461a..00000000000
--- a/intern/cycles/util/util_defines.h
+++ /dev/null
@@ -1,146 +0,0 @@
-
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* clang-format off */
-
-/* #define __forceinline triggers a bug in some clang-format versions, disable
- * format for entire file to keep results consistent. */
-
-#ifndef __UTIL_DEFINES_H__
-#define __UTIL_DEFINES_H__
-
-/* Bitness */
-
-#if defined(__ppc64__) || defined(__PPC64__) || defined(__x86_64__) || defined(__ia64__) || \
- defined(_M_X64) || defined(__aarch64__)
-# define __KERNEL_64_BIT__
-#endif
-
-/* Qualifiers for kernel code shared by CPU and GPU */
-
-#ifndef __KERNEL_GPU__
-# define ccl_device static inline
-# define ccl_device_noinline static
-# define ccl_device_noinline_cpu ccl_device_noinline
-# define ccl_global
-# define ccl_static_constant static const
-# define ccl_constant const
-# define ccl_local
-# define ccl_local_param
-# define ccl_private
-# define ccl_restrict __restrict
-# define ccl_optional_struct_init
-# define ccl_loop_no_unroll
-# define ccl_attr_maybe_unused [[maybe_unused]]
-# define __KERNEL_WITH_SSE_ALIGN__
-
-# if defined(_WIN32) && !defined(FREE_WINDOWS)
-# define ccl_device_inline static __forceinline
-# define ccl_device_forceinline static __forceinline
-# define ccl_align(...) __declspec(align(__VA_ARGS__))
-# ifdef __KERNEL_64_BIT__
-# define ccl_try_align(...) __declspec(align(__VA_ARGS__))
-# else /* __KERNEL_64_BIT__ */
-# undef __KERNEL_WITH_SSE_ALIGN__
-/* No support for function arguments (error C2719). */
-# define ccl_try_align(...)
-# endif /* __KERNEL_64_BIT__ */
-# define ccl_may_alias
-# define ccl_always_inline __forceinline
-# define ccl_never_inline __declspec(noinline)
-# else /* _WIN32 && !FREE_WINDOWS */
-# define ccl_device_inline static inline __attribute__((always_inline))
-# define ccl_device_forceinline static inline __attribute__((always_inline))
-# define ccl_align(...) __attribute__((aligned(__VA_ARGS__)))
-# ifndef FREE_WINDOWS64
-# define __forceinline inline __attribute__((always_inline))
-# endif
-# define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__)))
-# define ccl_may_alias __attribute__((__may_alias__))
-# define ccl_always_inline __attribute__((always_inline))
-# define ccl_never_inline __attribute__((noinline))
-# endif /* _WIN32 && !FREE_WINDOWS */
-
-/* Use to suppress '-Wimplicit-fallthrough' (in place of 'break'). */
-# ifndef ATTR_FALLTHROUGH
-# if defined(__GNUC__) && (__GNUC__ >= 7) /* gcc7.0+ only */
-# define ATTR_FALLTHROUGH __attribute__((fallthrough))
-# else
-# define ATTR_FALLTHROUGH ((void)0)
-# endif
-# endif
-#endif /* __KERNEL_GPU__ */
-
-/* macros */
-
-/* hints for branch prediction, only use in code that runs a _lot_ */
-#if defined(__GNUC__) && defined(__KERNEL_CPU__)
-# define LIKELY(x) __builtin_expect(!!(x), 1)
-# define UNLIKELY(x) __builtin_expect(!!(x), 0)
-#else
-# define LIKELY(x) (x)
-# define UNLIKELY(x) (x)
-#endif
-
-#if defined(__GNUC__) || defined(__clang__)
-# if defined(__cplusplus)
-/* Some magic to be sure we don't have reference in the type. */
-template<typename T> static inline T decltype_helper(T x)
-{
- return x;
-}
-# define TYPEOF(x) decltype(decltype_helper(x))
-# else
-# define TYPEOF(x) typeof(x)
-# endif
-#endif
-
-/* Causes warning:
- * incompatible types when assigning to type 'Foo' from type 'Bar'
- * ... the compiler optimizes away the temp var */
-#ifdef __GNUC__
-# define CHECK_TYPE(var, type) \
- { \
- TYPEOF(var) * __tmp; \
- __tmp = (type *)NULL; \
- (void)__tmp; \
- } \
- (void)0
-
-# define CHECK_TYPE_PAIR(var_a, var_b) \
- { \
- TYPEOF(var_a) * __tmp; \
- __tmp = (typeof(var_b) *)NULL; \
- (void)__tmp; \
- } \
- (void)0
-#else
-# define CHECK_TYPE(var, type)
-# define CHECK_TYPE_PAIR(var_a, var_b)
-#endif
-
-/* can be used in simple macros */
-#define CHECK_TYPE_INLINE(val, type) ((void)(((type)0) != (val)))
-
-#ifndef __KERNEL_GPU__
-# include <cassert>
-# define util_assert(statement) assert(statement)
-#else
-# define util_assert(statement)
-#endif
-
-#endif /* __UTIL_DEFINES_H__ */
diff --git a/intern/cycles/util/util_disjoint_set.h b/intern/cycles/util/util_disjoint_set.h
deleted file mode 100644
index 946632371d2..00000000000
--- a/intern/cycles/util/util_disjoint_set.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_DISJOINT_SET_H__
-#define __UTIL_DISJOINT_SET_H__
-
-#include "util_array.h"
-#include <utility>
-
-CCL_NAMESPACE_BEGIN
-
-class DisjointSet {
- private:
- array<size_t> parents;
- array<size_t> ranks;
-
- public:
- DisjointSet(size_t size) : parents(size), ranks(size)
- {
- for (size_t i = 0; i < size; i++) {
- parents[i] = i;
- ranks[i] = 0;
- }
- }
-
- size_t find(size_t x)
- {
- size_t root = x;
- while (parents[root] != root) {
- root = parents[root];
- }
- while (parents[x] != root) {
- size_t parent = parents[x];
- parents[x] = root;
- x = parent;
- }
- return root;
- }
-
- void join(size_t x, size_t y)
- {
- size_t x_root = find(x);
- size_t y_root = find(y);
-
- if (x_root == y_root) {
- return;
- }
-
- if (ranks[x_root] < ranks[y_root]) {
- std::swap(x_root, y_root);
- }
- parents[y_root] = x_root;
-
- if (ranks[x_root] == ranks[y_root]) {
- ranks[x_root]++;
- }
- }
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_DISJOINT_SET_H__ */
diff --git a/intern/cycles/util/util_guarded_allocator.cpp b/intern/cycles/util/util_guarded_allocator.cpp
deleted file mode 100644
index 1cb466a1ffa..00000000000
--- a/intern/cycles/util/util_guarded_allocator.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2011-2015 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_guarded_allocator.h"
-#include "util/util_stats.h"
-
-CCL_NAMESPACE_BEGIN
-
-static Stats global_stats(Stats::static_init);
-
-/* Internal API. */
-
-void util_guarded_mem_alloc(size_t n)
-{
- global_stats.mem_alloc(n);
-}
-
-void util_guarded_mem_free(size_t n)
-{
- global_stats.mem_free(n);
-}
-
-/* Public API. */
-
-size_t util_guarded_get_mem_used()
-{
- return global_stats.mem_used;
-}
-
-size_t util_guarded_get_mem_peak()
-{
- return global_stats.mem_peak;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_half.h b/intern/cycles/util/util_half.h
deleted file mode 100644
index 0db5acd319a..00000000000
--- a/intern/cycles/util/util_half.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_HALF_H__
-#define __UTIL_HALF_H__
-
-#include "util/util_math.h"
-#include "util/util_types.h"
-
-#if !defined(__KERNEL_GPU__) && defined(__KERNEL_SSE2__)
-# include "util/util_simd.h"
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/* Half Floats */
-
-/* CUDA has its own half data type, no need to define then */
-#if !defined(__KERNEL_CUDA__) && !defined(__KERNEL_HIP__)
-/* Implementing this as a class rather than a typedef so that the compiler can tell it apart from
- * unsigned shorts. */
-class half {
- public:
- half() : v(0)
- {
- }
- half(const unsigned short &i) : v(i)
- {
- }
- operator unsigned short()
- {
- return v;
- }
- half &operator=(const unsigned short &i)
- {
- v = i;
- return *this;
- }
-
- private:
- unsigned short v;
-};
-#endif
-
-struct half4 {
- half x, y, z, w;
-};
-
-/* Conversion to/from half float for image textures
- *
- * Simplified float to half for fast sampling on processor without a native
- * instruction, and eliminating any NaN and inf values. */
-
-ccl_device_inline half float_to_half_image(float f)
-{
-#if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
- return __float2half(f);
-#else
- const uint u = __float_as_uint(f);
- /* Sign bit, shifted to its position. */
- uint sign_bit = u & 0x80000000;
- sign_bit >>= 16;
- /* Exponent. */
- uint exponent_bits = u & 0x7f800000;
- /* Non-sign bits. */
- uint value_bits = u & 0x7fffffff;
- value_bits >>= 13; /* Align mantissa on MSB. */
- value_bits -= 0x1c000; /* Adjust bias. */
- /* Flush-to-zero. */
- value_bits = (exponent_bits < 0x38800000) ? 0 : value_bits;
- /* Clamp-to-max. */
- value_bits = (exponent_bits > 0x47000000) ? 0x7bff : value_bits;
- /* Denormals-as-zero. */
- value_bits = (exponent_bits == 0 ? 0 : value_bits);
- /* Re-insert sign bit and return. */
- return (value_bits | sign_bit);
-#endif
-}
-
-ccl_device_inline float half_to_float_image(half h)
-{
-#if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
- return __half2float(h);
-#else
- const int x = ((h & 0x8000) << 16) | (((h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13);
- return __int_as_float(x);
-#endif
-}
-
-ccl_device_inline float4 half4_to_float4_image(const half4 h)
-{
- /* Unable to use because it gives different results half_to_float_image, can we
- * modify float_to_half_image so the conversion results are identical? */
-#if 0 /* defined(__KERNEL_AVX2__) */
- /* CPU: AVX. */
- __m128i x = _mm_castpd_si128(_mm_load_sd((const double *)&h));
- return float4(_mm_cvtph_ps(x));
-#endif
-
- const float4 f = make_float4(half_to_float_image(h.x),
- half_to_float_image(h.y),
- half_to_float_image(h.z),
- half_to_float_image(h.w));
- return f;
-}
-
-/* Conversion to half float texture for display.
- *
- * Simplified float to half for fast display texture conversion on processors
- * without a native instruction. Assumes no negative, no NaN, no inf, and sets
- * denormal to 0. */
-
-ccl_device_inline half float_to_half_display(const float f)
-{
-#if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
- return __float2half(f);
-#else
- const int x = __float_as_int((f > 0.0f) ? ((f < 65504.0f) ? f : 65504.0f) : 0.0f);
- const int absolute = x & 0x7FFFFFFF;
- const int Z = absolute + 0xC8000000;
- const int result = (absolute < 0x38800000) ? 0 : Z;
- const int rshift = (result >> 13);
- return (rshift & 0x7FFF);
-#endif
-}
-
-ccl_device_inline half4 float4_to_half4_display(const float4 f)
-{
-#ifdef __KERNEL_SSE2__
- /* CPU: SSE and AVX. */
- ssef x = min(max(load4f(f), 0.0f), 65504.0f);
-# ifdef __KERNEL_AVX2__
- ssei rpack = _mm_cvtps_ph(x, 0);
-# else
- ssei absolute = cast(x) & 0x7FFFFFFF;
- ssei Z = absolute + 0xC8000000;
- ssei result = andnot(absolute < 0x38800000, Z);
- ssei rshift = (result >> 13) & 0x7FFF;
- ssei rpack = _mm_packs_epi32(rshift, rshift);
-# endif
- half4 h;
- _mm_storel_pi((__m64 *)&h, _mm_castsi128_ps(rpack));
- return h;
-#else
- /* GPU and scalar fallback. */
- const half4 h = {float_to_half_display(f.x),
- float_to_half_display(f.y),
- float_to_half_display(f.z),
- float_to_half_display(f.w)};
- return h;
-#endif
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_HALF_H__ */
diff --git a/intern/cycles/util/util_hash.h b/intern/cycles/util/util_hash.h
deleted file mode 100644
index 0021eec169b..00000000000
--- a/intern/cycles/util/util_hash.h
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_HASH_H__
-#define __UTIL_HASH_H__
-
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* ***** Jenkins Lookup3 Hash Functions ***** */
-
-/* Source: http://burtleburtle.net/bob/c/lookup3.c */
-
-#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
-
-#define mix(a, b, c) \
- { \
- a -= c; \
- a ^= rot(c, 4); \
- c += b; \
- b -= a; \
- b ^= rot(a, 6); \
- a += c; \
- c -= b; \
- c ^= rot(b, 8); \
- b += a; \
- a -= c; \
- a ^= rot(c, 16); \
- c += b; \
- b -= a; \
- b ^= rot(a, 19); \
- a += c; \
- c -= b; \
- c ^= rot(b, 4); \
- b += a; \
- } \
- ((void)0)
-
-#define final(a, b, c) \
- { \
- c ^= b; \
- c -= rot(b, 14); \
- a ^= c; \
- a -= rot(c, 11); \
- b ^= a; \
- b -= rot(a, 25); \
- c ^= b; \
- c -= rot(b, 16); \
- a ^= c; \
- a -= rot(c, 4); \
- b ^= a; \
- b -= rot(a, 14); \
- c ^= b; \
- c -= rot(b, 24); \
- } \
- ((void)0)
-
-ccl_device_inline uint hash_uint(uint kx)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeef + (1 << 2) + 13;
-
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-ccl_device_inline uint hash_uint2(uint kx, uint ky)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeef + (2 << 2) + 13;
-
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-ccl_device_inline uint hash_uint3(uint kx, uint ky, uint kz)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeef + (3 << 2) + 13;
-
- c += kz;
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-ccl_device_inline uint hash_uint4(uint kx, uint ky, uint kz, uint kw)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeef + (4 << 2) + 13;
-
- a += kx;
- b += ky;
- c += kz;
- mix(a, b, c);
-
- a += kw;
- final(a, b, c);
-
- return c;
-}
-
-#undef rot
-#undef final
-#undef mix
-
-/* Hashing uint or uint[234] into a float in the range [0, 1]. */
-
-ccl_device_inline float hash_uint_to_float(uint kx)
-{
- return (float)hash_uint(kx) / (float)0xFFFFFFFFu;
-}
-
-ccl_device_inline float hash_uint2_to_float(uint kx, uint ky)
-{
- return (float)hash_uint2(kx, ky) / (float)0xFFFFFFFFu;
-}
-
-ccl_device_inline float hash_uint3_to_float(uint kx, uint ky, uint kz)
-{
- return (float)hash_uint3(kx, ky, kz) / (float)0xFFFFFFFFu;
-}
-
-ccl_device_inline float hash_uint4_to_float(uint kx, uint ky, uint kz, uint kw)
-{
- return (float)hash_uint4(kx, ky, kz, kw) / (float)0xFFFFFFFFu;
-}
-
-/* Hashing float or float[234] into a float in the range [0, 1]. */
-
-ccl_device_inline float hash_float_to_float(float k)
-{
- return hash_uint_to_float(__float_as_uint(k));
-}
-
-ccl_device_inline float hash_float2_to_float(float2 k)
-{
- return hash_uint2_to_float(__float_as_uint(k.x), __float_as_uint(k.y));
-}
-
-ccl_device_inline float hash_float3_to_float(float3 k)
-{
- return hash_uint3_to_float(__float_as_uint(k.x), __float_as_uint(k.y), __float_as_uint(k.z));
-}
-
-ccl_device_inline float hash_float4_to_float(float4 k)
-{
- return hash_uint4_to_float(
- __float_as_uint(k.x), __float_as_uint(k.y), __float_as_uint(k.z), __float_as_uint(k.w));
-}
-
-/* Hashing float[234] into float[234] of components in the range [0, 1]. */
-
-ccl_device_inline float2 hash_float2_to_float2(float2 k)
-{
- return make_float2(hash_float2_to_float(k), hash_float3_to_float(make_float3(k.x, k.y, 1.0)));
-}
-
-ccl_device_inline float3 hash_float3_to_float3(float3 k)
-{
- return make_float3(hash_float3_to_float(k),
- hash_float4_to_float(make_float4(k.x, k.y, k.z, 1.0)),
- hash_float4_to_float(make_float4(k.x, k.y, k.z, 2.0)));
-}
-
-ccl_device_inline float4 hash_float4_to_float4(float4 k)
-{
- return make_float4(hash_float4_to_float(k),
- hash_float4_to_float(make_float4(k.w, k.x, k.y, k.z)),
- hash_float4_to_float(make_float4(k.z, k.w, k.x, k.y)),
- hash_float4_to_float(make_float4(k.y, k.z, k.w, k.x)));
-}
-
-/* Hashing float or float[234] into float3 of components in range [0, 1]. */
-
-ccl_device_inline float3 hash_float_to_float3(float k)
-{
- return make_float3(hash_float_to_float(k),
- hash_float2_to_float(make_float2(k, 1.0)),
- hash_float2_to_float(make_float2(k, 2.0)));
-}
-
-ccl_device_inline float3 hash_float2_to_float3(float2 k)
-{
- return make_float3(hash_float2_to_float(k),
- hash_float3_to_float(make_float3(k.x, k.y, 1.0)),
- hash_float3_to_float(make_float3(k.x, k.y, 2.0)));
-}
-
-ccl_device_inline float3 hash_float4_to_float3(float4 k)
-{
- return make_float3(hash_float4_to_float(k),
- hash_float4_to_float(make_float4(k.z, k.x, k.w, k.y)),
- hash_float4_to_float(make_float4(k.w, k.z, k.y, k.x)));
-}
-
-/* SSE Versions Of Jenkins Lookup3 Hash Functions */
-
-#ifdef __KERNEL_SSE2__
-# define rot(x, k) (((x) << (k)) | (srl(x, 32 - (k))))
-
-# define mix(a, b, c) \
- { \
- a -= c; \
- a ^= rot(c, 4); \
- c += b; \
- b -= a; \
- b ^= rot(a, 6); \
- a += c; \
- c -= b; \
- c ^= rot(b, 8); \
- b += a; \
- a -= c; \
- a ^= rot(c, 16); \
- c += b; \
- b -= a; \
- b ^= rot(a, 19); \
- a += c; \
- c -= b; \
- c ^= rot(b, 4); \
- b += a; \
- }
-
-# define final(a, b, c) \
- { \
- c ^= b; \
- c -= rot(b, 14); \
- a ^= c; \
- a -= rot(c, 11); \
- b ^= a; \
- b -= rot(a, 25); \
- c ^= b; \
- c -= rot(b, 16); \
- a ^= c; \
- a -= rot(c, 4); \
- b ^= a; \
- b -= rot(a, 14); \
- c ^= b; \
- c -= rot(b, 24); \
- }
-
-ccl_device_inline ssei hash_ssei(ssei kx)
-{
- ssei a, b, c;
- a = b = c = ssei(0xdeadbeef + (1 << 2) + 13);
-
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-ccl_device_inline ssei hash_ssei2(ssei kx, ssei ky)
-{
- ssei a, b, c;
- a = b = c = ssei(0xdeadbeef + (2 << 2) + 13);
-
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-ccl_device_inline ssei hash_ssei3(ssei kx, ssei ky, ssei kz)
-{
- ssei a, b, c;
- a = b = c = ssei(0xdeadbeef + (3 << 2) + 13);
-
- c += kz;
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-ccl_device_inline ssei hash_ssei4(ssei kx, ssei ky, ssei kz, ssei kw)
-{
- ssei a, b, c;
- a = b = c = ssei(0xdeadbeef + (4 << 2) + 13);
-
- a += kx;
- b += ky;
- c += kz;
- mix(a, b, c);
-
- a += kw;
- final(a, b, c);
-
- return c;
-}
-
-# if defined(__KERNEL_AVX__)
-ccl_device_inline avxi hash_avxi(avxi kx)
-{
- avxi a, b, c;
- a = b = c = avxi(0xdeadbeef + (1 << 2) + 13);
-
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-ccl_device_inline avxi hash_avxi2(avxi kx, avxi ky)
-{
- avxi a, b, c;
- a = b = c = avxi(0xdeadbeef + (2 << 2) + 13);
-
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-ccl_device_inline avxi hash_avxi3(avxi kx, avxi ky, avxi kz)
-{
- avxi a, b, c;
- a = b = c = avxi(0xdeadbeef + (3 << 2) + 13);
-
- c += kz;
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-ccl_device_inline avxi hash_avxi4(avxi kx, avxi ky, avxi kz, avxi kw)
-{
- avxi a, b, c;
- a = b = c = avxi(0xdeadbeef + (4 << 2) + 13);
-
- a += kx;
- b += ky;
- c += kz;
- mix(a, b, c);
-
- a += kw;
- final(a, b, c);
-
- return c;
-}
-# endif
-
-# undef rot
-# undef final
-# undef mix
-
-#endif
-
-#ifndef __KERNEL_GPU__
-static inline uint hash_string(const char *str)
-{
- uint i = 0, c;
-
- while ((c = *str++))
- i = i * 37 + c;
-
- return i;
-}
-#endif
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_HASH_H__ */
diff --git a/intern/cycles/util/util_ies.cpp b/intern/cycles/util/util_ies.cpp
deleted file mode 100644
index 62d3d42186d..00000000000
--- a/intern/cycles/util/util_ies.cpp
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-
-#include "util/util_foreach.h"
-#include "util/util_ies.h"
-#include "util/util_math.h"
-#include "util/util_string.h"
-
-CCL_NAMESPACE_BEGIN
-
-// NOTE: For some reason gcc-7.2 does not instantiate this versio of allocator
-// gere (used in IESTextParser). Works fine for gcc-6, gcc-7.3 and gcc-8.
-//
-// TODO(sergey): Get to the root of this issue, or confirm this i a compiler
-// issue.
-template class GuardedAllocator<char>;
-
-bool IESFile::load(const string &ies)
-{
- clear();
- if (!parse(ies) || !process()) {
- clear();
- return false;
- }
- return true;
-}
-
-void IESFile::clear()
-{
- intensity.clear();
- v_angles.clear();
- h_angles.clear();
-}
-
-int IESFile::packed_size()
-{
- if (v_angles.size() && h_angles.size() > 0) {
- return 2 + h_angles.size() + v_angles.size() + h_angles.size() * v_angles.size();
- }
- return 0;
-}
-
-void IESFile::pack(float *data)
-{
- if (v_angles.size() && h_angles.size()) {
- *(data++) = __int_as_float(h_angles.size());
- *(data++) = __int_as_float(v_angles.size());
-
- memcpy(data, &h_angles[0], h_angles.size() * sizeof(float));
- data += h_angles.size();
- memcpy(data, &v_angles[0], v_angles.size() * sizeof(float));
- data += v_angles.size();
-
- for (int h = 0; h < intensity.size(); h++) {
- memcpy(data, &intensity[h][0], v_angles.size() * sizeof(float));
- data += v_angles.size();
- }
- }
-}
-
-class IESTextParser {
- public:
- vector<char> text;
- char *data;
-
- IESTextParser(const string &str) : text(str.begin(), str.end())
- {
- std::replace(text.begin(), text.end(), ',', ' ');
- data = strstr(&text[0], "\nTILT=");
- }
-
- bool eof()
- {
- return (data == NULL) || (data[0] == '\0');
- }
-
- double get_double()
- {
- if (eof()) {
- return 0.0;
- }
- char *old_data = data;
- double val = strtod(data, &data);
- if (data == old_data) {
- data = NULL;
- return 0.0;
- }
- return val;
- }
-
- long get_long()
- {
- if (eof()) {
- return 0;
- }
- char *old_data = data;
- long val = strtol(data, &data, 10);
- if (data == old_data) {
- data = NULL;
- return 0;
- }
- return val;
- }
-};
-
-bool IESFile::parse(const string &ies)
-{
- if (ies.empty()) {
- return false;
- }
-
- IESTextParser parser(ies);
- if (parser.eof()) {
- return false;
- }
-
- /* Handle the tilt data block. */
- if (strncmp(parser.data, "\nTILT=INCLUDE", 13) == 0) {
- parser.data += 13;
- parser.get_double(); /* Lamp to Luminaire geometry */
- int num_tilt = parser.get_long(); /* Amount of tilt angles and factors */
- /* Skip over angles and factors. */
- for (int i = 0; i < 2 * num_tilt; i++) {
- parser.get_double();
- }
- }
- else {
- /* Skip to next line. */
- parser.data = strstr(parser.data + 1, "\n");
- }
-
- if (parser.eof()) {
- return false;
- }
- parser.data++;
-
- parser.get_long(); /* Number of lamps */
- parser.get_double(); /* Lumens per lamp */
- double factor = parser.get_double(); /* Candela multiplier */
- int v_angles_num = parser.get_long(); /* Number of vertical angles */
- int h_angles_num = parser.get_long(); /* Number of horizontal angles */
- type = (IESType)parser.get_long(); /* Photometric type */
-
- /* TODO(lukas): Test whether the current type B processing can also deal with type A files.
- * In theory the only difference should be orientation which we ignore anyways, but with IES you
- * never know...
- */
- if (type != TYPE_B && type != TYPE_C) {
- return false;
- }
-
- parser.get_long(); /* Unit of the geometry data */
- parser.get_double(); /* Width */
- parser.get_double(); /* Length */
- parser.get_double(); /* Height */
- factor *= parser.get_double(); /* Ballast factor */
- factor *= parser.get_double(); /* Ballast-Lamp Photometric factor */
- parser.get_double(); /* Input Watts */
-
- /* Intensity values in IES files are specified in candela (lumen/sr), a photometric quantity.
- * Cycles expects radiometric quantities, though, which requires a conversion.
- * However, the Luminous efficacy (ratio of lumens per Watt) depends on the spectral distribution
- * of the light source since lumens take human perception into account.
- * Since this spectral distribution is not known from the IES file, a typical one must be
- * assumed. The D65 standard illuminant has a Luminous efficacy of 177.83, which is used here to
- * convert to Watt/sr. A more advanced approach would be to add a Blackbody Temperature input to
- * the node and numerically integrate the Luminous efficacy from the resulting spectral
- * distribution. Also, the Watt/sr value must be multiplied by 4*pi to get the Watt value that
- * Cycles expects for lamp strength. Therefore, the conversion here uses 4*pi/177.83 as a Candela
- * to Watt factor.
- */
- factor *= 0.0706650768394;
-
- v_angles.reserve(v_angles_num);
- for (int i = 0; i < v_angles_num; i++) {
- v_angles.push_back((float)parser.get_double());
- }
-
- h_angles.reserve(h_angles_num);
- for (int i = 0; i < h_angles_num; i++) {
- h_angles.push_back((float)parser.get_double());
- }
-
- intensity.resize(h_angles_num);
- for (int i = 0; i < h_angles_num; i++) {
- intensity[i].reserve(v_angles_num);
- for (int j = 0; j < v_angles_num; j++) {
- intensity[i].push_back((float)(factor * parser.get_double()));
- }
- }
-
- return !parser.eof();
-}
-
-bool IESFile::process_type_b()
-{
- vector<vector<float>> newintensity;
- newintensity.resize(v_angles.size());
- for (int i = 0; i < v_angles.size(); i++) {
- newintensity[i].reserve(h_angles.size());
- for (int j = 0; j < h_angles.size(); j++) {
- newintensity[i].push_back(intensity[j][i]);
- }
- }
- intensity.swap(newintensity);
- h_angles.swap(v_angles);
-
- float h_first = h_angles[0], h_last = h_angles[h_angles.size() - 1];
- if (h_last != 90.0f) {
- return false;
- }
-
- if (h_first == 0.0f) {
- /* The range in the file corresponds to 90°-180°, we need to mirror that to get the
- * full 180° range. */
- vector<float> new_h_angles;
- vector<vector<float>> new_intensity;
- int hnum = h_angles.size();
- new_h_angles.reserve(2 * hnum - 1);
- new_intensity.reserve(2 * hnum - 1);
- for (int i = hnum - 1; i > 0; i--) {
- new_h_angles.push_back(90.0f - h_angles[i]);
- new_intensity.push_back(intensity[i]);
- }
- for (int i = 0; i < hnum; i++) {
- new_h_angles.push_back(90.0f + h_angles[i]);
- new_intensity.push_back(intensity[i]);
- }
- h_angles.swap(new_h_angles);
- intensity.swap(new_intensity);
- }
- else if (h_first == -90.0f) {
- /* We have full 180° coverage, so just shift to match the angle range convention. */
- for (int i = 0; i < h_angles.size(); i++) {
- h_angles[i] += 90.0f;
- }
- }
- /* To get correct results with the cubic interpolation in the kernel, the horizontal range
- * has to cover all 360°. Therefore, we copy the 0° entry to 360° to ensure full coverage
- * and seamless interpolation. */
- h_angles.push_back(360.0f);
- intensity.push_back(intensity[0]);
-
- float v_first = v_angles[0], v_last = v_angles[v_angles.size() - 1];
- if (v_last != 90.0f) {
- return false;
- }
-
- if (v_first == 0.0f) {
- /* The range in the file corresponds to 90°-180°, we need to mirror that to get the
- * full 180° range. */
- vector<float> new_v_angles;
- int hnum = h_angles.size();
- int vnum = v_angles.size();
- new_v_angles.reserve(2 * vnum - 1);
- for (int i = vnum - 1; i > 0; i--) {
- new_v_angles.push_back(90.0f - v_angles[i]);
- }
- for (int i = 0; i < vnum; i++) {
- new_v_angles.push_back(90.0f + v_angles[i]);
- }
- for (int i = 0; i < hnum; i++) {
- vector<float> new_intensity;
- new_intensity.reserve(2 * vnum - 1);
- for (int j = vnum - 2; j >= 0; j--) {
- new_intensity.push_back(intensity[i][j]);
- }
- new_intensity.insert(new_intensity.end(), intensity[i].begin(), intensity[i].end());
- intensity[i].swap(new_intensity);
- }
- v_angles.swap(new_v_angles);
- }
- else if (v_first == -90.0f) {
- /* We have full 180° coverage, so just shift to match the angle range convention. */
- for (int i = 0; i < v_angles.size(); i++) {
- v_angles[i] += 90.0f;
- }
- }
-
- return true;
-}
-
-bool IESFile::process_type_c()
-{
- if (h_angles[0] == 90.0f) {
- /* Some files are stored from 90° to 270°, so we just rotate them to the regular 0°-180° range
- * here. */
- for (int i = 0; i < h_angles.size(); i++) {
- h_angles[i] -= 90.0f;
- }
- }
-
- if (h_angles[0] != 0.0f) {
- return false;
- }
-
- if (h_angles.size() == 1) {
- h_angles.push_back(360.0f);
- intensity.push_back(intensity[0]);
- }
-
- if (h_angles[h_angles.size() - 1] == 90.0f) {
- /* Only one quadrant is defined, so we need to mirror twice (from one to two, then to four).
- * Since the two->four mirroring step might also be required if we get an input of two
- * quadrants, we only do the first mirror here and later do the second mirror in either case.
- */
- int hnum = h_angles.size();
- for (int i = hnum - 2; i >= 0; i--) {
- h_angles.push_back(180.0f - h_angles[i]);
- intensity.push_back(intensity[i]);
- }
- }
-
- if (h_angles[h_angles.size() - 1] == 180.0f) {
- /* Mirror half to the full range. */
- int hnum = h_angles.size();
- for (int i = hnum - 2; i >= 0; i--) {
- h_angles.push_back(360.0f - h_angles[i]);
- intensity.push_back(intensity[i]);
- }
- }
-
- /* Some files skip the 360° entry (contrary to standard) because it's supposed to be identical to
- * the 0° entry. If the file has a discernible order in its spacing, just fix this. */
- if (h_angles[h_angles.size() - 1] != 360.0f) {
- int hnum = h_angles.size();
- float last_step = h_angles[hnum - 1] - h_angles[hnum - 2];
- float first_step = h_angles[1] - h_angles[0];
- float difference = 360.0f - h_angles[hnum - 1];
- if (last_step == difference || first_step == difference) {
- h_angles.push_back(360.0f);
- intensity.push_back(intensity[0]);
- }
- else {
- return false;
- }
- }
-
- float v_first = v_angles[0], v_last = v_angles[v_angles.size() - 1];
- if (v_first == 90.0f) {
- if (v_last == 180.0f) {
- /* Flip to ensure that vertical angles always start at 0°. */
- for (int i = 0; i < v_angles.size(); i++) {
- v_angles[i] = 180.0f - v_angles[i];
- }
- }
- else {
- return false;
- }
- }
- else if (v_first != 0.0f) {
- return false;
- }
-
- return true;
-}
-
-bool IESFile::process()
-{
- if (h_angles.size() == 0 || v_angles.size() == 0) {
- return false;
- }
-
- if (type == TYPE_B) {
- if (!process_type_b()) {
- return false;
- }
- }
- else {
- assert(type == TYPE_C);
- if (!process_type_c()) {
- return false;
- }
- }
-
- assert(v_angles[0] == 0.0f);
- assert(h_angles[0] == 0.0f);
- assert(h_angles[h_angles.size() - 1] == 360.0f);
-
- /* Convert from deg to rad. */
- for (int i = 0; i < v_angles.size(); i++) {
- v_angles[i] *= M_PI_F / 180.f;
- }
- for (int i = 0; i < h_angles.size(); i++) {
- h_angles[i] *= M_PI_F / 180.f;
- }
-
- return true;
-}
-
-IESFile::~IESFile()
-{
- clear();
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_ies.h b/intern/cycles/util/util_ies.h
deleted file mode 100644
index 95473103614..00000000000
--- a/intern/cycles/util/util_ies.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_IES_H__
-#define __UTIL_IES_H__
-
-#include "util/util_string.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class IESFile {
- public:
- IESFile()
- {
- }
- ~IESFile();
-
- int packed_size();
- void pack(float *data);
-
- bool load(const string &ies);
- void clear();
-
- protected:
- bool parse(const string &ies);
- bool process();
- bool process_type_b();
- bool process_type_c();
-
- /* The brightness distribution is stored in spherical coordinates.
- * The horizontal angles correspond to theta in the regular notation
- * and always span the full range from 0° to 360°.
- * The vertical angles correspond to phi and always start at 0°. */
- vector<float> v_angles, h_angles;
- /* The actual values are stored here, with every entry storing the values
- * of one horizontal segment. */
- vector<vector<float>> intensity;
-
- /* Types of angle representation in IES files. Currently, only B and C are supported. */
- enum IESType { TYPE_A = 3, TYPE_B = 2, TYPE_C = 1 } type;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_IES_H__ */
diff --git a/intern/cycles/util/util_image.h b/intern/cycles/util/util_image.h
deleted file mode 100644
index b082b971613..00000000000
--- a/intern/cycles/util/util_image.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_IMAGE_H__
-# define __UTIL_IMAGE_H__
-
-/* OpenImageIO is used for all image file reading and writing. */
-
-# include <OpenImageIO/imageio.h>
-
-# include "util/util_half.h"
-# include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-OIIO_NAMESPACE_USING
-
-template<typename T>
-void util_image_resize_pixels(const vector<T> &input_pixels,
- const size_t input_width,
- const size_t input_height,
- const size_t input_depth,
- const size_t components,
- vector<T> *output_pixels,
- size_t *output_width,
- size_t *output_height,
- size_t *output_depth);
-
-/* Cast input pixel from unknown storage to float. */
-template<typename T> inline float util_image_cast_to_float(T value);
-
-template<> inline float util_image_cast_to_float(float value)
-{
- return value;
-}
-template<> inline float util_image_cast_to_float(uchar value)
-{
- return (float)value / 255.0f;
-}
-template<> inline float util_image_cast_to_float(uint16_t value)
-{
- return (float)value / 65535.0f;
-}
-template<> inline float util_image_cast_to_float(half value)
-{
- return half_to_float_image(value);
-}
-
-/* Cast float value to output pixel type. */
-template<typename T> inline T util_image_cast_from_float(float value);
-
-template<> inline float util_image_cast_from_float(float value)
-{
- return value;
-}
-template<> inline uchar util_image_cast_from_float(float value)
-{
- if (value < 0.0f) {
- return 0;
- }
- else if (value > (1.0f - 0.5f / 255.0f)) {
- return 255;
- }
- return (uchar)((255.0f * value) + 0.5f);
-}
-template<> inline uint16_t util_image_cast_from_float(float value)
-{
- if (value < 0.0f) {
- return 0;
- }
- else if (value > (1.0f - 0.5f / 65535.0f)) {
- return 65535;
- }
- return (uint16_t)((65535.0f * value) + 0.5f);
-}
-template<> inline half util_image_cast_from_float(float value)
-{
- return float_to_half_image(value);
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_IMAGE_H__ */
-
-#include "util/util_image_impl.h"
diff --git a/intern/cycles/util/util_image_impl.h b/intern/cycles/util/util_image_impl.h
deleted file mode 100644
index 3eb30d070ea..00000000000
--- a/intern/cycles/util/util_image_impl.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_IMAGE_IMPL_H__
-#define __UTIL_IMAGE_IMPL_H__
-
-#include "util/util_algorithm.h"
-#include "util/util_half.h"
-#include "util/util_image.h"
-
-CCL_NAMESPACE_BEGIN
-
-namespace {
-
-template<typename T>
-const T *util_image_read(const vector<T> &pixels,
- const size_t width,
- const size_t height,
- const size_t /*depth*/,
- const size_t components,
- const size_t x,
- const size_t y,
- const size_t z)
-{
- const size_t index = ((size_t)z * (width * height) + (size_t)y * width + (size_t)x) * components;
- return &pixels[index];
-}
-
-template<typename T>
-void util_image_downscale_sample(const vector<T> &pixels,
- const size_t width,
- const size_t height,
- const size_t depth,
- const size_t components,
- const size_t kernel_size,
- const float x,
- const float y,
- const float z,
- T *result)
-{
- assert(components <= 4);
- const size_t ix = (size_t)x, iy = (size_t)y, iz = (size_t)z;
- /* TODO(sergey): Support something smarter than box filer. */
- float accum[4] = {0};
- size_t count = 0;
- for (size_t dz = 0; dz < kernel_size; ++dz) {
- for (size_t dy = 0; dy < kernel_size; ++dy) {
- for (size_t dx = 0; dx < kernel_size; ++dx) {
- const size_t nx = ix + dx, ny = iy + dy, nz = iz + dz;
- if (nx >= width || ny >= height || nz >= depth) {
- continue;
- }
- const T *pixel = util_image_read(pixels, width, height, depth, components, nx, ny, nz);
- for (size_t k = 0; k < components; ++k) {
- accum[k] += util_image_cast_to_float(pixel[k]);
- }
- ++count;
- }
- }
- }
- if (count != 0) {
- const float inv_count = 1.0f / (float)count;
- for (size_t k = 0; k < components; ++k) {
- result[k] = util_image_cast_from_float<T>(accum[k] * inv_count);
- }
- }
- else {
- for (size_t k = 0; k < components; ++k) {
- result[k] = T(0.0f);
- }
- }
-}
-
-template<typename T>
-void util_image_downscale_pixels(const vector<T> &input_pixels,
- const size_t input_width,
- const size_t input_height,
- const size_t input_depth,
- const size_t components,
- const float inv_scale_factor,
- const size_t output_width,
- const size_t output_height,
- const size_t output_depth,
- vector<T> *output_pixels)
-{
- const size_t kernel_size = (size_t)(inv_scale_factor + 0.5f);
- for (size_t z = 0; z < output_depth; ++z) {
- for (size_t y = 0; y < output_height; ++y) {
- for (size_t x = 0; x < output_width; ++x) {
- const float input_x = (float)x * inv_scale_factor, input_y = (float)y * inv_scale_factor,
- input_z = (float)z * inv_scale_factor;
- const size_t output_index = (z * output_width * output_height + y * output_width + x) *
- components;
- util_image_downscale_sample(input_pixels,
- input_width,
- input_height,
- input_depth,
- components,
- kernel_size,
- input_x,
- input_y,
- input_z,
- &output_pixels->at(output_index));
- }
- }
- }
-}
-
-} /* namespace */
-
-template<typename T>
-void util_image_resize_pixels(const vector<T> &input_pixels,
- const size_t input_width,
- const size_t input_height,
- const size_t input_depth,
- const size_t components,
- const float scale_factor,
- vector<T> *output_pixels,
- size_t *output_width,
- size_t *output_height,
- size_t *output_depth)
-{
- /* Early output for case when no scaling is applied. */
- if (scale_factor == 1.0f) {
- *output_width = input_width;
- *output_height = input_height;
- *output_depth = input_depth;
- *output_pixels = input_pixels;
- return;
- }
- /* First of all, we calculate output image dimensions.
- * We clamp them to be 1 pixel at least so we do not generate degenerate
- * image.
- */
- *output_width = max((size_t)((float)input_width * scale_factor), (size_t)1);
- *output_height = max((size_t)((float)input_height * scale_factor), (size_t)1);
- *output_depth = max((size_t)((float)input_depth * scale_factor), (size_t)1);
- /* Prepare pixel storage for the result. */
- const size_t num_output_pixels = ((*output_width) * (*output_height) * (*output_depth)) *
- components;
- output_pixels->resize(num_output_pixels);
- if (scale_factor < 1.0f) {
- const float inv_scale_factor = 1.0f / scale_factor;
- util_image_downscale_pixels(input_pixels,
- input_width,
- input_height,
- input_depth,
- components,
- inv_scale_factor,
- *output_width,
- *output_height,
- *output_depth,
- output_pixels);
- }
- else {
- /* TODO(sergey): Needs implementation. */
- }
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_IMAGE_IMPL_H__ */
diff --git a/intern/cycles/util/util_logging.cpp b/intern/cycles/util/util_logging.cpp
deleted file mode 100644
index 8272728a7a0..00000000000
--- a/intern/cycles/util/util_logging.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2011-2014 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_logging.h"
-
-#include "util/util_math.h"
-#include "util/util_string.h"
-
-#include <stdio.h>
-#ifdef _MSC_VER
-# define snprintf _snprintf
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef WITH_CYCLES_LOGGING
-static bool is_verbosity_set()
-{
- using CYCLES_GFLAGS_NAMESPACE::GetCommandLineOption;
-
- std::string verbosity;
- if (!GetCommandLineOption("v", &verbosity)) {
- return false;
- }
- return verbosity != "0";
-}
-#endif
-
-void util_logging_init(const char *argv0)
-{
-#ifdef WITH_CYCLES_LOGGING
- using CYCLES_GFLAGS_NAMESPACE::SetCommandLineOption;
-
- google::InitGoogleLogging(argv0);
- SetCommandLineOption("logtostderr", "1");
- if (!is_verbosity_set()) {
- SetCommandLineOption("v", "0");
- }
- SetCommandLineOption("stderrthreshold", "0");
- SetCommandLineOption("minloglevel", "0");
-#else
- (void)argv0;
-#endif
-}
-
-void util_logging_start()
-{
-#ifdef WITH_CYCLES_LOGGING
- using CYCLES_GFLAGS_NAMESPACE::SetCommandLineOption;
- SetCommandLineOption("logtostderr", "1");
- if (!is_verbosity_set()) {
- SetCommandLineOption("v", "2");
- }
- SetCommandLineOption("stderrthreshold", "0");
- SetCommandLineOption("minloglevel", "0");
-#endif
-}
-
-void util_logging_verbosity_set(int verbosity)
-{
-#ifdef WITH_CYCLES_LOGGING
- using CYCLES_GFLAGS_NAMESPACE::SetCommandLineOption;
- char val[10];
- snprintf(val, sizeof(val), "%d", verbosity);
- SetCommandLineOption("v", val);
-#else
- (void)verbosity;
-#endif
-}
-
-std::ostream &operator<<(std::ostream &os, const int2 &value)
-{
- os << "(" << value.x << ", " << value.y << ")";
- return os;
-}
-
-std::ostream &operator<<(std::ostream &os, const float3 &value)
-{
- os << "(" << value.x << ", " << value.y << ", " << value.z << ")";
- return os;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
deleted file mode 100644
index 535b6881d3f..00000000000
--- a/intern/cycles/util/util_math.h
+++ /dev/null
@@ -1,870 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_MATH_H__
-#define __UTIL_MATH_H__
-
-/* Math
- *
- * Basic math functions on scalar and vector types. This header is used by
- * both the kernel code when compiled as C++, and other C++ non-kernel code. */
-
-#ifndef __KERNEL_GPU__
-# include <cmath>
-#endif
-
-#ifdef __HIP__
-# include <hip/hip_vector_types.h>
-#endif
-
-#include <float.h>
-#include <math.h>
-#include <stdio.h>
-
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Float Pi variations */
-
-/* Division */
-#ifndef M_PI_F
-# define M_PI_F (3.1415926535897932f) /* pi */
-#endif
-#ifndef M_PI_2_F
-# define M_PI_2_F (1.5707963267948966f) /* pi/2 */
-#endif
-#ifndef M_PI_4_F
-# define M_PI_4_F (0.7853981633974830f) /* pi/4 */
-#endif
-#ifndef M_1_PI_F
-# define M_1_PI_F (0.3183098861837067f) /* 1/pi */
-#endif
-#ifndef M_2_PI_F
-# define M_2_PI_F (0.6366197723675813f) /* 2/pi */
-#endif
-#ifndef M_1_2PI_F
-# define M_1_2PI_F (0.1591549430918953f) /* 1/(2*pi) */
-#endif
-#ifndef M_SQRT_PI_8_F
-# define M_SQRT_PI_8_F (0.6266570686577501f) /* sqrt(pi/8) */
-#endif
-#ifndef M_LN_2PI_F
-# define M_LN_2PI_F (1.8378770664093454f) /* ln(2*pi) */
-#endif
-
-/* Multiplication */
-#ifndef M_2PI_F
-# define M_2PI_F (6.2831853071795864f) /* 2*pi */
-#endif
-#ifndef M_4PI_F
-# define M_4PI_F (12.566370614359172f) /* 4*pi */
-#endif
-
-/* Float sqrt variations */
-#ifndef M_SQRT2_F
-# define M_SQRT2_F (1.4142135623730950f) /* sqrt(2) */
-#endif
-#ifndef M_LN2_F
-# define M_LN2_F (0.6931471805599453f) /* ln(2) */
-#endif
-#ifndef M_LN10_F
-# define M_LN10_F (2.3025850929940457f) /* ln(10) */
-#endif
-
-/* Scalar */
-
-#ifndef __HIP__
-# ifdef _WIN32
-ccl_device_inline float fmaxf(float a, float b)
-{
- return (a > b) ? a : b;
-}
-
-ccl_device_inline float fminf(float a, float b)
-{
- return (a < b) ? a : b;
-}
-
-# endif /* _WIN32 */
-#endif /* __HIP__ */
-
-#ifndef __KERNEL_GPU__
-using std::isfinite;
-using std::isnan;
-using std::sqrt;
-
-ccl_device_inline int abs(int x)
-{
- return (x > 0) ? x : -x;
-}
-
-ccl_device_inline int max(int a, int b)
-{
- return (a > b) ? a : b;
-}
-
-ccl_device_inline int min(int a, int b)
-{
- return (a < b) ? a : b;
-}
-
-ccl_device_inline uint min(uint a, uint b)
-{
- return (a < b) ? a : b;
-}
-
-ccl_device_inline float max(float a, float b)
-{
- return (a > b) ? a : b;
-}
-
-ccl_device_inline float min(float a, float b)
-{
- return (a < b) ? a : b;
-}
-
-ccl_device_inline double max(double a, double b)
-{
- return (a > b) ? a : b;
-}
-
-ccl_device_inline double min(double a, double b)
-{
- return (a < b) ? a : b;
-}
-
-/* These 2 guys are templated for usage with registers data.
- *
- * NOTE: Since this is CPU-only functions it is ok to use references here.
- * But for other devices we'll need to be careful about this.
- */
-
-template<typename T> ccl_device_inline T min4(const T &a, const T &b, const T &c, const T &d)
-{
- return min(min(a, b), min(c, d));
-}
-
-template<typename T> ccl_device_inline T max4(const T &a, const T &b, const T &c, const T &d)
-{
- return max(max(a, b), max(c, d));
-}
-#endif /* __KERNEL_GPU__ */
-
-ccl_device_inline float min4(float a, float b, float c, float d)
-{
- return min(min(a, b), min(c, d));
-}
-
-ccl_device_inline float max4(float a, float b, float c, float d)
-{
- return max(max(a, b), max(c, d));
-}
-
-/* Int/Float conversion */
-
-ccl_device_inline int as_int(uint i)
-{
- union {
- uint ui;
- int i;
- } u;
- u.ui = i;
- return u.i;
-}
-
-ccl_device_inline uint as_uint(int i)
-{
- union {
- uint ui;
- int i;
- } u;
- u.i = i;
- return u.ui;
-}
-
-ccl_device_inline uint as_uint(float f)
-{
- union {
- uint i;
- float f;
- } u;
- u.f = f;
- return u.i;
-}
-
-#ifndef __HIP__
-ccl_device_inline int __float_as_int(float f)
-{
- union {
- int i;
- float f;
- } u;
- u.f = f;
- return u.i;
-}
-
-ccl_device_inline float __int_as_float(int i)
-{
- union {
- int i;
- float f;
- } u;
- u.i = i;
- return u.f;
-}
-
-ccl_device_inline uint __float_as_uint(float f)
-{
- union {
- uint i;
- float f;
- } u;
- u.f = f;
- return u.i;
-}
-
-ccl_device_inline float __uint_as_float(uint i)
-{
- union {
- uint i;
- float f;
- } u;
- u.i = i;
- return u.f;
-}
-#endif
-
-ccl_device_inline int4 __float4_as_int4(float4 f)
-{
-#ifdef __KERNEL_SSE__
- return int4(_mm_castps_si128(f.m128));
-#else
- return make_int4(
- __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), __float_as_int(f.w));
-#endif
-}
-
-ccl_device_inline float4 __int4_as_float4(int4 i)
-{
-#ifdef __KERNEL_SSE__
- return float4(_mm_castsi128_ps(i.m128));
-#else
- return make_float4(
- __int_as_float(i.x), __int_as_float(i.y), __int_as_float(i.z), __int_as_float(i.w));
-#endif
-}
-
-template<typename T> ccl_device_inline uint pointer_pack_to_uint_0(T *ptr)
-{
- return ((uint64_t)ptr) & 0xFFFFFFFF;
-}
-
-template<typename T> ccl_device_inline uint pointer_pack_to_uint_1(T *ptr)
-{
- return (((uint64_t)ptr) >> 32) & 0xFFFFFFFF;
-}
-
-template<typename T> ccl_device_inline T *pointer_unpack_from_uint(const uint a, const uint b)
-{
- return (T *)(((uint64_t)b << 32) | a);
-}
-
-ccl_device_inline uint uint16_pack_to_uint(const uint a, const uint b)
-{
- return (a << 16) | b;
-}
-
-ccl_device_inline uint uint16_unpack_from_uint_0(const uint i)
-{
- return i >> 16;
-}
-
-ccl_device_inline uint uint16_unpack_from_uint_1(const uint i)
-{
- return i & 0xFFFF;
-}
-
-/* Versions of functions which are safe for fast math. */
-ccl_device_inline bool isnan_safe(float f)
-{
- unsigned int x = __float_as_uint(f);
- return (x << 1) > 0xff000000u;
-}
-
-ccl_device_inline bool isfinite_safe(float f)
-{
- /* By IEEE 754 rule, 2*Inf equals Inf */
- unsigned int x = __float_as_uint(f);
- return (f == f) && (x == 0 || x == (1u << 31) || (f != 2.0f * f)) && !((x << 1) > 0xff000000u);
-}
-
-ccl_device_inline float ensure_finite(float v)
-{
- return isfinite_safe(v) ? v : 0.0f;
-}
-
-ccl_device_inline int clamp(int a, int mn, int mx)
-{
- return min(max(a, mn), mx);
-}
-
-ccl_device_inline float clamp(float a, float mn, float mx)
-{
- return min(max(a, mn), mx);
-}
-
-ccl_device_inline float mix(float a, float b, float t)
-{
- return a + t * (b - a);
-}
-
-ccl_device_inline float smoothstep(float edge0, float edge1, float x)
-{
- float result;
- if (x < edge0)
- result = 0.0f;
- else if (x >= edge1)
- result = 1.0f;
- else {
- float t = (x - edge0) / (edge1 - edge0);
- result = (3.0f - 2.0f * t) * (t * t);
- }
- return result;
-}
-
-#ifndef __KERNEL_CUDA__
-ccl_device_inline float saturate(float a)
-{
- return clamp(a, 0.0f, 1.0f);
-}
-#endif /* __KERNEL_CUDA__ */
-
-ccl_device_inline int float_to_int(float f)
-{
- return (int)f;
-}
-
-ccl_device_inline int floor_to_int(float f)
-{
- return float_to_int(floorf(f));
-}
-
-ccl_device_inline int quick_floor_to_int(float x)
-{
- return float_to_int(x) - ((x < 0) ? 1 : 0);
-}
-
-ccl_device_inline float floorfrac(float x, ccl_private int *i)
-{
- *i = quick_floor_to_int(x);
- return x - *i;
-}
-
-ccl_device_inline int ceil_to_int(float f)
-{
- return float_to_int(ceilf(f));
-}
-
-ccl_device_inline float fractf(float x)
-{
- return x - floorf(x);
-}
-
-/* Adapted from godot-engine math_funcs.h. */
-ccl_device_inline float wrapf(float value, float max, float min)
-{
- float range = max - min;
- return (range != 0.0f) ? value - (range * floorf((value - min) / range)) : min;
-}
-
-ccl_device_inline float pingpongf(float a, float b)
-{
- return (b != 0.0f) ? fabsf(fractf((a - b) / (b * 2.0f)) * b * 2.0f - b) : 0.0f;
-}
-
-ccl_device_inline float smoothminf(float a, float b, float k)
-{
- if (k != 0.0f) {
- float h = fmaxf(k - fabsf(a - b), 0.0f) / k;
- return fminf(a, b) - h * h * h * k * (1.0f / 6.0f);
- }
- else {
- return fminf(a, b);
- }
-}
-
-ccl_device_inline float signf(float f)
-{
- return (f < 0.0f) ? -1.0f : 1.0f;
-}
-
-ccl_device_inline float nonzerof(float f, float eps)
-{
- if (fabsf(f) < eps)
- return signf(f) * eps;
- else
- return f;
-}
-
-/* `signum` function testing for zero. Matches GLSL and OSL functions. */
-ccl_device_inline float compatible_signf(float f)
-{
- if (f == 0.0f) {
- return 0.0f;
- }
- else {
- return signf(f);
- }
-}
-
-ccl_device_inline float smoothstepf(float f)
-{
- float ff = f * f;
- return (3.0f * ff - 2.0f * ff * f);
-}
-
-ccl_device_inline int mod(int x, int m)
-{
- return (x % m + m) % m;
-}
-
-ccl_device_inline float3 float2_to_float3(const float2 a)
-{
- return make_float3(a.x, a.y, 0.0f);
-}
-
-ccl_device_inline float3 float4_to_float3(const float4 a)
-{
- return make_float3(a.x, a.y, a.z);
-}
-
-ccl_device_inline float4 float3_to_float4(const float3 a)
-{
- return make_float4(a.x, a.y, a.z, 1.0f);
-}
-
-ccl_device_inline float inverse_lerp(float a, float b, float x)
-{
- return (x - a) / (b - a);
-}
-
-/* Cubic interpolation between b and c, a and d are the previous and next point. */
-ccl_device_inline float cubic_interp(float a, float b, float c, float d, float x)
-{
- return 0.5f *
- (((d + 3.0f * (b - c) - a) * x + (2.0f * a - 5.0f * b + 4.0f * c - d)) * x +
- (c - a)) *
- x +
- b;
-}
-
-CCL_NAMESPACE_END
-
-#include "util/util_math_int2.h"
-#include "util/util_math_int3.h"
-#include "util/util_math_int4.h"
-
-#include "util/util_math_float2.h"
-#include "util/util_math_float3.h"
-#include "util/util_math_float4.h"
-
-#include "util/util_rect.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Interpolation */
-
-template<class A, class B> A lerp(const A &a, const A &b, const B &t)
-{
- return (A)(a * ((B)1 - t) + b * t);
-}
-
-/* Triangle */
-
-ccl_device_inline float triangle_area(ccl_private const float3 &v1,
- ccl_private const float3 &v2,
- ccl_private const float3 &v3)
-{
- return len(cross(v3 - v2, v1 - v2)) * 0.5f;
-}
-
-/* Orthonormal vectors */
-
-ccl_device_inline void make_orthonormals(const float3 N,
- ccl_private float3 *a,
- ccl_private float3 *b)
-{
-#if 0
- if (fabsf(N.y) >= 0.999f) {
- *a = make_float3(1, 0, 0);
- *b = make_float3(0, 0, 1);
- return;
- }
- if (fabsf(N.z) >= 0.999f) {
- *a = make_float3(1, 0, 0);
- *b = make_float3(0, 1, 0);
- return;
- }
-#endif
-
- if (N.x != N.y || N.x != N.z)
- *a = make_float3(N.z - N.y, N.x - N.z, N.y - N.x); //(1,1,1)x N
- else
- *a = make_float3(N.z - N.y, N.x + N.z, -N.y - N.x); //(-1,1,1)x N
-
- *a = normalize(*a);
- *b = cross(N, *a);
-}
-
-/* Color division */
-
-ccl_device_inline float3 safe_invert_color(float3 a)
-{
- float x, y, z;
-
- x = (a.x != 0.0f) ? 1.0f / a.x : 0.0f;
- y = (a.y != 0.0f) ? 1.0f / a.y : 0.0f;
- z = (a.z != 0.0f) ? 1.0f / a.z : 0.0f;
-
- return make_float3(x, y, z);
-}
-
-ccl_device_inline float3 safe_divide_color(float3 a, float3 b)
-{
- float x, y, z;
-
- x = (b.x != 0.0f) ? a.x / b.x : 0.0f;
- y = (b.y != 0.0f) ? a.y / b.y : 0.0f;
- z = (b.z != 0.0f) ? a.z / b.z : 0.0f;
-
- return make_float3(x, y, z);
-}
-
-ccl_device_inline float3 safe_divide_even_color(float3 a, float3 b)
-{
- float x, y, z;
-
- x = (b.x != 0.0f) ? a.x / b.x : 0.0f;
- y = (b.y != 0.0f) ? a.y / b.y : 0.0f;
- z = (b.z != 0.0f) ? a.z / b.z : 0.0f;
-
- /* try to get gray even if b is zero */
- if (b.x == 0.0f) {
- if (b.y == 0.0f) {
- x = z;
- y = z;
- }
- else if (b.z == 0.0f) {
- x = y;
- z = y;
- }
- else
- x = 0.5f * (y + z);
- }
- else if (b.y == 0.0f) {
- if (b.z == 0.0f) {
- y = x;
- z = x;
- }
- else
- y = 0.5f * (x + z);
- }
- else if (b.z == 0.0f) {
- z = 0.5f * (x + y);
- }
-
- return make_float3(x, y, z);
-}
-
-/* Rotation of point around axis and angle */
-
-ccl_device_inline float3 rotate_around_axis(float3 p, float3 axis, float angle)
-{
- float costheta = cosf(angle);
- float sintheta = sinf(angle);
- float3 r;
-
- r.x = ((costheta + (1 - costheta) * axis.x * axis.x) * p.x) +
- (((1 - costheta) * axis.x * axis.y - axis.z * sintheta) * p.y) +
- (((1 - costheta) * axis.x * axis.z + axis.y * sintheta) * p.z);
-
- r.y = (((1 - costheta) * axis.x * axis.y + axis.z * sintheta) * p.x) +
- ((costheta + (1 - costheta) * axis.y * axis.y) * p.y) +
- (((1 - costheta) * axis.y * axis.z - axis.x * sintheta) * p.z);
-
- r.z = (((1 - costheta) * axis.x * axis.z - axis.y * sintheta) * p.x) +
- (((1 - costheta) * axis.y * axis.z + axis.x * sintheta) * p.y) +
- ((costheta + (1 - costheta) * axis.z * axis.z) * p.z);
-
- return r;
-}
-
-/* NaN-safe math ops */
-
-ccl_device_inline float safe_sqrtf(float f)
-{
- return sqrtf(max(f, 0.0f));
-}
-
-ccl_device_inline float inversesqrtf(float f)
-{
- return (f > 0.0f) ? 1.0f / sqrtf(f) : 0.0f;
-}
-
-ccl_device float safe_asinf(float a)
-{
- return asinf(clamp(a, -1.0f, 1.0f));
-}
-
-ccl_device float safe_acosf(float a)
-{
- return acosf(clamp(a, -1.0f, 1.0f));
-}
-
-ccl_device float compatible_powf(float x, float y)
-{
-#ifdef __KERNEL_GPU__
- if (y == 0.0f) /* x^0 -> 1, including 0^0 */
- return 1.0f;
-
- /* GPU pow doesn't accept negative x, do manual checks here */
- if (x < 0.0f) {
- if (fmodf(-y, 2.0f) == 0.0f)
- return powf(-x, y);
- else
- return -powf(-x, y);
- }
- else if (x == 0.0f)
- return 0.0f;
-#endif
- return powf(x, y);
-}
-
-ccl_device float safe_powf(float a, float b)
-{
- if (UNLIKELY(a < 0.0f && b != float_to_int(b)))
- return 0.0f;
-
- return compatible_powf(a, b);
-}
-
-ccl_device float safe_divide(float a, float b)
-{
- return (b != 0.0f) ? a / b : 0.0f;
-}
-
-ccl_device float safe_logf(float a, float b)
-{
- if (UNLIKELY(a <= 0.0f || b <= 0.0f))
- return 0.0f;
-
- return safe_divide(logf(a), logf(b));
-}
-
-ccl_device float safe_modulo(float a, float b)
-{
- return (b != 0.0f) ? fmodf(a, b) : 0.0f;
-}
-
-ccl_device_inline float sqr(float a)
-{
- return a * a;
-}
-
-ccl_device_inline float pow20(float a)
-{
- return sqr(sqr(sqr(sqr(a)) * a));
-}
-
-ccl_device_inline float pow22(float a)
-{
- return sqr(a * sqr(sqr(sqr(a)) * a));
-}
-
-ccl_device_inline float beta(float x, float y)
-{
- return expf(lgammaf(x) + lgammaf(y) - lgammaf(x + y));
-}
-
-ccl_device_inline float xor_signmask(float x, int y)
-{
- return __int_as_float(__float_as_int(x) ^ y);
-}
-
-ccl_device float bits_to_01(uint bits)
-{
- return bits * (1.0f / (float)0xFFFFFFFF);
-}
-
-ccl_device_inline uint count_leading_zeros(uint x)
-{
-#if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) || defined(__KERNEL_HIP__)
- return __clz(x);
-#else
- assert(x != 0);
-# ifdef _MSC_VER
- unsigned long leading_zero = 0;
- _BitScanReverse(&leading_zero, x);
- return (31 - leading_zero);
-# else
- return __builtin_clz(x);
-# endif
-#endif
-}
-
-ccl_device_inline uint count_trailing_zeros(uint x)
-{
-#if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) || defined(__KERNEL_HIP__)
- return (__ffs(x) - 1);
-#else
- assert(x != 0);
-# ifdef _MSC_VER
- unsigned long ctz = 0;
- _BitScanForward(&ctz, x);
- return ctz;
-# else
- return __builtin_ctz(x);
-# endif
-#endif
-}
-
-ccl_device_inline uint find_first_set(uint x)
-{
-#if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) || defined(__KERNEL_HIP__)
- return __ffs(x);
-#else
-# ifdef _MSC_VER
- return (x != 0) ? (32 - count_leading_zeros(x & (-x))) : 0;
-# else
- return __builtin_ffs(x);
-# endif
-#endif
-}
-
-/* projections */
-ccl_device_inline float2 map_to_tube(const float3 co)
-{
- float len, u, v;
- len = sqrtf(co.x * co.x + co.y * co.y);
- if (len > 0.0f) {
- u = (1.0f - (atan2f(co.x / len, co.y / len) / M_PI_F)) * 0.5f;
- v = (co.z + 1.0f) * 0.5f;
- }
- else {
- u = v = 0.0f;
- }
- return make_float2(u, v);
-}
-
-ccl_device_inline float2 map_to_sphere(const float3 co)
-{
- float l = len(co);
- float u, v;
- if (l > 0.0f) {
- if (UNLIKELY(co.x == 0.0f && co.y == 0.0f)) {
- u = 0.0f; /* Otherwise domain error. */
- }
- else {
- u = (1.0f - atan2f(co.x, co.y) / M_PI_F) / 2.0f;
- }
- v = 1.0f - safe_acosf(co.z / l) / M_PI_F;
- }
- else {
- u = v = 0.0f;
- }
- return make_float2(u, v);
-}
-
-/* Compares two floats.
- * Returns true if their absolute difference is smaller than abs_diff (for numbers near zero)
- * or their relative difference is less than ulp_diff ULPs.
- * Based on
- * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
- */
-
-ccl_device_inline float compare_floats(float a, float b, float abs_diff, int ulp_diff)
-{
- if (fabsf(a - b) < abs_diff) {
- return true;
- }
-
- if ((a < 0.0f) != (b < 0.0f)) {
- return false;
- }
-
- return (abs(__float_as_int(a) - __float_as_int(b)) < ulp_diff);
-}
-
-/* Calculate the angle between the two vectors a and b.
- * The usual approach `acos(dot(a, b))` has severe precision issues for small angles,
- * which are avoided by this method.
- * Based on "Mangled Angles" from https://people.eecs.berkeley.edu/~wkahan/Mindless.pdf
- */
-ccl_device_inline float precise_angle(float3 a, float3 b)
-{
- return 2.0f * atan2f(len(a - b), len(a + b));
-}
-
-/* Return value which is greater than the given one and is a power of two. */
-ccl_device_inline uint next_power_of_two(uint x)
-{
- return x == 0 ? 1 : 1 << (32 - count_leading_zeros(x));
-}
-
-/* Return value which is lower than the given one and is a power of two. */
-ccl_device_inline uint prev_power_of_two(uint x)
-{
- return x < 2 ? x : 1 << (31 - count_leading_zeros(x - 1));
-}
-
-#ifndef __has_builtin
-# define __has_builtin(v) 0
-#endif
-
-/* Reverses the bits of a 32 bit integer. */
-ccl_device_inline uint32_t reverse_integer_bits(uint32_t x)
-{
- /* Use a native instruction if it exists. */
-#if defined(__arm__) || defined(__aarch64__)
- __asm__("rbit %w0, %w1" : "=r"(x) : "r"(x));
- return x;
-#elif defined(__KERNEL_CUDA__)
- return __brev(x);
-#elif __has_builtin(__builtin_bitreverse32)
- return __builtin_bitreverse32(x);
-#else
- /* Flip pairwise. */
- x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1);
- /* Flip pairs. */
- x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2);
- /* Flip nibbles. */
- x = ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4);
- /* Flip bytes. CPUs have an instruction for that, pretty fast one. */
-# ifdef _MSC_VER
- return _byteswap_ulong(x);
-# elif defined(__INTEL_COMPILER)
- return (uint32_t)_bswap((int)x);
-# else
- /* Assuming gcc or clang. */
- return __builtin_bswap32(x);
-# endif
-#endif
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MATH_H__ */
diff --git a/intern/cycles/util/util_math_cdf.cpp b/intern/cycles/util/util_math_cdf.cpp
deleted file mode 100644
index a58bab188ef..00000000000
--- a/intern/cycles/util/util_math_cdf.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2011-2015 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_math_cdf.h"
-
-#include "util/util_algorithm.h"
-#include "util/util_math.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Invert pre-calculated CDF function. */
-void util_cdf_invert(const int resolution,
- const float from,
- const float to,
- const vector<float> &cdf,
- const bool make_symmetric,
- vector<float> &inv_cdf)
-{
- const float inv_resolution = 1.0f / (float)resolution;
- const float range = to - from;
- inv_cdf.resize(resolution);
- if (make_symmetric) {
- const int half_size = (resolution - 1) / 2;
- for (int i = 0; i <= half_size; i++) {
- float x = i / (float)half_size;
- int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin();
- float t;
- if (index < cdf.size() - 1) {
- t = (x - cdf[index]) / (cdf[index + 1] - cdf[index]);
- }
- else {
- t = 0.0f;
- index = cdf.size() - 1;
- }
- float y = ((index + t) / (resolution - 1)) * (2.0f * range);
- inv_cdf[half_size + i] = 0.5f * (1.0f + y);
- inv_cdf[half_size - i] = 0.5f * (1.0f - y);
- }
- }
- else {
- for (int i = 0; i < resolution; i++) {
- float x = from + range * (float)i * inv_resolution;
- int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin();
- float t;
- if (index < cdf.size() - 1) {
- t = (x - cdf[index]) / (cdf[index + 1] - cdf[index]);
- }
- else {
- t = 0.0f;
- index = resolution;
- }
- inv_cdf[i] = (index + t) * inv_resolution;
- }
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_math_cdf.h b/intern/cycles/util/util_math_cdf.h
deleted file mode 100644
index 43995204263..00000000000
--- a/intern/cycles/util/util_math_cdf.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2011-2015 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_MATH_CDF_H__
-#define __UTIL_MATH_CDF_H__
-
-#include "util/util_algorithm.h"
-#include "util/util_math.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Evaluate CDF of a given functor with given range and resolution. */
-template<typename Functor>
-void util_cdf_evaluate(
- const int resolution, const float from, const float to, Functor functor, vector<float> &cdf)
-{
- const int cdf_count = resolution + 1;
- const float range = to - from;
- cdf.resize(cdf_count);
- cdf[0] = 0.0f;
- /* Actual CDF evaluation. */
- for (int i = 0; i < resolution; ++i) {
- float x = from + range * (float)i / (resolution - 1);
- float y = functor(x);
- cdf[i + 1] = cdf[i] + fabsf(y);
- }
- /* Normalize the CDF. */
- for (int i = 0; i <= resolution; i++) {
- cdf[i] /= cdf[resolution];
- }
-}
-
-/* Invert pre-calculated CDF function. */
-void util_cdf_invert(const int resolution,
- const float from,
- const float to,
- const vector<float> &cdf,
- const bool make_symmetric,
- vector<float> &inv_cdf);
-
-/* Evaluate inverted CDF of a given functor with given range and resolution. */
-template<typename Functor>
-void util_cdf_inverted(const int resolution,
- const float from,
- const float to,
- Functor functor,
- const bool make_symmetric,
- vector<float> &inv_cdf)
-{
- vector<float> cdf;
- /* There is no much smartness going around lower resolution for the CDF table,
- * this just to match the old code from pixel filter so it all stays exactly
- * the same and no regression tests are failed.
- */
- util_cdf_evaluate(resolution - 1, from, to, functor, cdf);
- util_cdf_invert(resolution, from, to, cdf, make_symmetric, inv_cdf);
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MATH_H_CDF__ */
diff --git a/intern/cycles/util/util_math_float2.h b/intern/cycles/util/util_math_float2.h
deleted file mode 100644
index 25eda840214..00000000000
--- a/intern/cycles/util/util_math_float2.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_MATH_FLOAT2_H__
-#define __UTIL_MATH_FLOAT2_H__
-
-#ifndef __UTIL_MATH_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/*******************************************************************************
- * Declaration.
- */
-
-ccl_device_inline float2 operator-(const float2 &a);
-ccl_device_inline float2 operator*(const float2 &a, const float2 &b);
-ccl_device_inline float2 operator*(const float2 &a, float f);
-ccl_device_inline float2 operator*(float f, const float2 &a);
-ccl_device_inline float2 operator/(float f, const float2 &a);
-ccl_device_inline float2 operator/(const float2 &a, float f);
-ccl_device_inline float2 operator/(const float2 &a, const float2 &b);
-ccl_device_inline float2 operator+(const float2 &a, const float f);
-ccl_device_inline float2 operator+(const float2 &a, const float2 &b);
-ccl_device_inline float2 operator-(const float2 &a, const float f);
-ccl_device_inline float2 operator-(const float2 &a, const float2 &b);
-ccl_device_inline float2 operator+=(float2 &a, const float2 &b);
-ccl_device_inline float2 operator*=(float2 &a, const float2 &b);
-ccl_device_inline float2 operator*=(float2 &a, float f);
-ccl_device_inline float2 operator/=(float2 &a, const float2 &b);
-ccl_device_inline float2 operator/=(float2 &a, float f);
-
-ccl_device_inline bool operator==(const float2 &a, const float2 &b);
-ccl_device_inline bool operator!=(const float2 &a, const float2 &b);
-
-ccl_device_inline bool is_zero(const float2 &a);
-ccl_device_inline float average(const float2 &a);
-ccl_device_inline float distance(const float2 &a, const float2 &b);
-ccl_device_inline float dot(const float2 &a, const float2 &b);
-ccl_device_inline float cross(const float2 &a, const float2 &b);
-ccl_device_inline float len(const float2 &a);
-ccl_device_inline float2 normalize(const float2 &a);
-ccl_device_inline float2 normalize_len(const float2 &a, float *t);
-ccl_device_inline float2 safe_normalize(const float2 &a);
-ccl_device_inline float2 min(const float2 &a, const float2 &b);
-ccl_device_inline float2 max(const float2 &a, const float2 &b);
-ccl_device_inline float2 clamp(const float2 &a, const float2 &mn, const float2 &mx);
-ccl_device_inline float2 fabs(const float2 &a);
-ccl_device_inline float2 as_float2(const float4 &a);
-ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t);
-ccl_device_inline float2 floor(const float2 &a);
-
-ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b);
-
-/*******************************************************************************
- * Definition.
- */
-
-ccl_device_inline float2 zero_float2()
-{
- return make_float2(0.0f, 0.0f);
-}
-
-ccl_device_inline float2 one_float2()
-{
- return make_float2(1.0f, 1.0f);
-}
-
-ccl_device_inline float2 operator-(const float2 &a)
-{
- return make_float2(-a.x, -a.y);
-}
-
-ccl_device_inline float2 operator*(const float2 &a, const float2 &b)
-{
- return make_float2(a.x * b.x, a.y * b.y);
-}
-
-ccl_device_inline float2 operator*(const float2 &a, float f)
-{
- return make_float2(a.x * f, a.y * f);
-}
-
-ccl_device_inline float2 operator*(float f, const float2 &a)
-{
- return make_float2(a.x * f, a.y * f);
-}
-
-ccl_device_inline float2 operator/(float f, const float2 &a)
-{
- return make_float2(f / a.x, f / a.y);
-}
-
-ccl_device_inline float2 operator/(const float2 &a, float f)
-{
- float invf = 1.0f / f;
- return make_float2(a.x * invf, a.y * invf);
-}
-
-ccl_device_inline float2 operator/(const float2 &a, const float2 &b)
-{
- return make_float2(a.x / b.x, a.y / b.y);
-}
-
-ccl_device_inline float2 operator+(const float2 &a, const float f)
-{
- return a + make_float2(f, f);
-}
-
-ccl_device_inline float2 operator+(const float2 &a, const float2 &b)
-{
- return make_float2(a.x + b.x, a.y + b.y);
-}
-
-ccl_device_inline float2 operator-(const float2 &a, const float f)
-{
- return a - make_float2(f, f);
-}
-
-ccl_device_inline float2 operator-(const float2 &a, const float2 &b)
-{
- return make_float2(a.x - b.x, a.y - b.y);
-}
-
-ccl_device_inline float2 operator+=(float2 &a, const float2 &b)
-{
- return a = a + b;
-}
-
-ccl_device_inline float2 operator*=(float2 &a, const float2 &b)
-{
- return a = a * b;
-}
-
-ccl_device_inline float2 operator*=(float2 &a, float f)
-{
- return a = a * f;
-}
-
-ccl_device_inline float2 operator/=(float2 &a, const float2 &b)
-{
- return a = a / b;
-}
-
-ccl_device_inline float2 operator/=(float2 &a, float f)
-{
- float invf = 1.0f / f;
- return a = a * invf;
-}
-
-ccl_device_inline bool operator==(const float2 &a, const float2 &b)
-{
- return (a.x == b.x && a.y == b.y);
-}
-
-ccl_device_inline bool operator!=(const float2 &a, const float2 &b)
-{
- return !(a == b);
-}
-
-ccl_device_inline bool is_zero(const float2 &a)
-{
- return (a.x == 0.0f && a.y == 0.0f);
-}
-
-ccl_device_inline float average(const float2 &a)
-{
- return (a.x + a.y) * (1.0f / 2.0f);
-}
-
-ccl_device_inline float distance(const float2 &a, const float2 &b)
-{
- return len(a - b);
-}
-
-ccl_device_inline float dot(const float2 &a, const float2 &b)
-{
- return a.x * b.x + a.y * b.y;
-}
-
-ccl_device_inline float cross(const float2 &a, const float2 &b)
-{
- return (a.x * b.y - a.y * b.x);
-}
-
-ccl_device_inline float len(const float2 &a)
-{
- return sqrtf(dot(a, a));
-}
-
-ccl_device_inline float2 normalize(const float2 &a)
-{
- return a / len(a);
-}
-
-ccl_device_inline float2 normalize_len(const float2 &a, ccl_private float *t)
-{
- *t = len(a);
- return a / (*t);
-}
-
-ccl_device_inline float2 safe_normalize(const float2 &a)
-{
- float t = len(a);
- return (t != 0.0f) ? a / t : a;
-}
-
-ccl_device_inline float2 min(const float2 &a, const float2 &b)
-{
- return make_float2(min(a.x, b.x), min(a.y, b.y));
-}
-
-ccl_device_inline float2 max(const float2 &a, const float2 &b)
-{
- return make_float2(max(a.x, b.x), max(a.y, b.y));
-}
-
-ccl_device_inline float2 clamp(const float2 &a, const float2 &mn, const float2 &mx)
-{
- return min(max(a, mn), mx);
-}
-
-ccl_device_inline float2 fabs(const float2 &a)
-{
- return make_float2(fabsf(a.x), fabsf(a.y));
-}
-
-ccl_device_inline float2 as_float2(const float4 &a)
-{
- return make_float2(a.x, a.y);
-}
-
-ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t)
-{
- return a + t * (b - a);
-}
-
-ccl_device_inline float2 mix(const float2 &a, const float2 &b, float t)
-{
- return a + t * (b - a);
-}
-
-ccl_device_inline float2 floor(const float2 &a)
-{
- return make_float2(floorf(a.x), floorf(a.y));
-}
-
-ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b)
-{
- return (b != 0.0f) ? a / b : zero_float2();
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MATH_FLOAT2_H__ */
diff --git a/intern/cycles/util/util_math_float3.h b/intern/cycles/util/util_math_float3.h
deleted file mode 100644
index c3230a8068c..00000000000
--- a/intern/cycles/util/util_math_float3.h
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_MATH_FLOAT3_H__
-#define __UTIL_MATH_FLOAT3_H__
-
-#ifndef __UTIL_MATH_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/*******************************************************************************
- * Declaration.
- */
-
-ccl_device_inline float3 operator-(const float3 &a);
-ccl_device_inline float3 operator*(const float3 &a, const float3 &b);
-ccl_device_inline float3 operator*(const float3 &a, const float f);
-ccl_device_inline float3 operator*(const float f, const float3 &a);
-ccl_device_inline float3 operator/(const float f, const float3 &a);
-ccl_device_inline float3 operator/(const float3 &a, const float f);
-ccl_device_inline float3 operator/(const float3 &a, const float3 &b);
-ccl_device_inline float3 operator+(const float3 &a, const float f);
-ccl_device_inline float3 operator+(const float3 &a, const float3 &b);
-ccl_device_inline float3 operator-(const float3 &a, const float f);
-ccl_device_inline float3 operator-(const float3 &a, const float3 &b);
-ccl_device_inline float3 operator+=(float3 &a, const float3 &b);
-ccl_device_inline float3 operator-=(float3 &a, const float3 &b);
-ccl_device_inline float3 operator*=(float3 &a, const float3 &b);
-ccl_device_inline float3 operator*=(float3 &a, float f);
-ccl_device_inline float3 operator/=(float3 &a, const float3 &b);
-ccl_device_inline float3 operator/=(float3 &a, float f);
-
-ccl_device_inline bool operator==(const float3 &a, const float3 &b);
-ccl_device_inline bool operator!=(const float3 &a, const float3 &b);
-
-ccl_device_inline float distance(const float3 &a, const float3 &b);
-ccl_device_inline float dot(const float3 &a, const float3 &b);
-ccl_device_inline float dot_xy(const float3 &a, const float3 &b);
-ccl_device_inline float3 cross(const float3 &a, const float3 &b);
-ccl_device_inline float3 normalize(const float3 &a);
-ccl_device_inline float3 min(const float3 &a, const float3 &b);
-ccl_device_inline float3 max(const float3 &a, const float3 &b);
-ccl_device_inline float3 clamp(const float3 &a, const float3 &mn, const float3 &mx);
-ccl_device_inline float3 fabs(const float3 &a);
-ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t);
-ccl_device_inline float3 rcp(const float3 &a);
-ccl_device_inline float3 sqrt(const float3 &a);
-ccl_device_inline float3 floor(const float3 &a);
-ccl_device_inline float3 ceil(const float3 &a);
-
-ccl_device_inline float min3(float3 a);
-ccl_device_inline float max3(float3 a);
-ccl_device_inline float len(const float3 a);
-ccl_device_inline float len_squared(const float3 a);
-
-ccl_device_inline float3 reflect(const float3 incident, const float3 normal);
-ccl_device_inline float3 project(const float3 v, const float3 v_proj);
-
-ccl_device_inline float3 saturate3(float3 a);
-ccl_device_inline float3 safe_normalize(const float3 a);
-ccl_device_inline float3 normalize_len(const float3 a, float *t);
-ccl_device_inline float3 safe_normalize_len(const float3 a, float *t);
-ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b);
-ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b);
-ccl_device_inline float3 interp(float3 a, float3 b, float t);
-ccl_device_inline float3 sqr3(float3 a);
-
-ccl_device_inline bool is_zero(const float3 a);
-ccl_device_inline float reduce_add(const float3 a);
-ccl_device_inline float average(const float3 a);
-ccl_device_inline bool isequal_float3(const float3 a, const float3 b);
-
-/*******************************************************************************
- * Definition.
- */
-
-ccl_device_inline float3 zero_float3()
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_setzero_ps());
-#else
- return make_float3(0.0f, 0.0f, 0.0f);
-#endif
-}
-
-ccl_device_inline float3 one_float3()
-{
- return make_float3(1.0f, 1.0f, 1.0f);
-}
-
-ccl_device_inline float3 operator-(const float3 &a)
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_xor_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000))));
-#else
- return make_float3(-a.x, -a.y, -a.z);
-#endif
-}
-
-ccl_device_inline float3 operator*(const float3 &a, const float3 &b)
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_mul_ps(a.m128, b.m128));
-#else
- return make_float3(a.x * b.x, a.y * b.y, a.z * b.z);
-#endif
-}
-
-ccl_device_inline float3 operator*(const float3 &a, const float f)
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_mul_ps(a.m128, _mm_set1_ps(f)));
-#else
- return make_float3(a.x * f, a.y * f, a.z * f);
-#endif
-}
-
-ccl_device_inline float3 operator*(const float f, const float3 &a)
-{
-#if defined(__KERNEL_SSE__)
- return float3(_mm_mul_ps(_mm_set1_ps(f), a.m128));
-#else
- return make_float3(a.x * f, a.y * f, a.z * f);
-#endif
-}
-
-ccl_device_inline float3 operator/(const float f, const float3 &a)
-{
-#if defined(__KERNEL_SSE__)
- return float3(_mm_div_ps(_mm_set1_ps(f), a.m128));
-#else
- return make_float3(f / a.x, f / a.y, f / a.z);
-#endif
-}
-
-ccl_device_inline float3 operator/(const float3 &a, const float f)
-{
- float invf = 1.0f / f;
- return a * invf;
-}
-
-ccl_device_inline float3 operator/(const float3 &a, const float3 &b)
-{
-#if defined(__KERNEL_SSE__)
- return float3(_mm_div_ps(a.m128, b.m128));
-#else
- return make_float3(a.x / b.x, a.y / b.y, a.z / b.z);
-#endif
-}
-
-ccl_device_inline float3 operator+(const float3 &a, const float f)
-{
- return a + make_float3(f, f, f);
-}
-
-ccl_device_inline float3 operator+(const float3 &a, const float3 &b)
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_add_ps(a.m128, b.m128));
-#else
- return make_float3(a.x + b.x, a.y + b.y, a.z + b.z);
-#endif
-}
-
-ccl_device_inline float3 operator-(const float3 &a, const float f)
-{
- return a - make_float3(f, f, f);
-}
-
-ccl_device_inline float3 operator-(const float3 &a, const float3 &b)
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_sub_ps(a.m128, b.m128));
-#else
- return make_float3(a.x - b.x, a.y - b.y, a.z - b.z);
-#endif
-}
-
-ccl_device_inline float3 operator+=(float3 &a, const float3 &b)
-{
- return a = a + b;
-}
-
-ccl_device_inline float3 operator-=(float3 &a, const float3 &b)
-{
- return a = a - b;
-}
-
-ccl_device_inline float3 operator*=(float3 &a, const float3 &b)
-{
- return a = a * b;
-}
-
-ccl_device_inline float3 operator*=(float3 &a, float f)
-{
- return a = a * f;
-}
-
-ccl_device_inline float3 operator/=(float3 &a, const float3 &b)
-{
- return a = a / b;
-}
-
-ccl_device_inline float3 operator/=(float3 &a, float f)
-{
- float invf = 1.0f / f;
- return a = a * invf;
-}
-
-ccl_device_inline bool operator==(const float3 &a, const float3 &b)
-{
-#ifdef __KERNEL_SSE__
- return (_mm_movemask_ps(_mm_cmpeq_ps(a.m128, b.m128)) & 7) == 7;
-#else
- return (a.x == b.x && a.y == b.y && a.z == b.z);
-#endif
-}
-
-ccl_device_inline bool operator!=(const float3 &a, const float3 &b)
-{
- return !(a == b);
-}
-
-ccl_device_inline float distance(const float3 &a, const float3 &b)
-{
- return len(a - b);
-}
-
-ccl_device_inline float dot(const float3 &a, const float3 &b)
-{
-#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
- return _mm_cvtss_f32(_mm_dp_ps(a, b, 0x7F));
-#else
- return a.x * b.x + a.y * b.y + a.z * b.z;
-#endif
-}
-
-ccl_device_inline float dot_xy(const float3 &a, const float3 &b)
-{
-#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
- return _mm_cvtss_f32(_mm_hadd_ps(_mm_mul_ps(a, b), b));
-#else
- return a.x * b.x + a.y * b.y;
-#endif
-}
-
-ccl_device_inline float3 cross(const float3 &a, const float3 &b)
-{
- float3 r = make_float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
- return r;
-}
-
-ccl_device_inline float3 normalize(const float3 &a)
-{
-#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
- __m128 norm = _mm_sqrt_ps(_mm_dp_ps(a.m128, a.m128, 0x7F));
- return float3(_mm_div_ps(a.m128, norm));
-#else
- return a / len(a);
-#endif
-}
-
-ccl_device_inline float3 min(const float3 &a, const float3 &b)
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_min_ps(a.m128, b.m128));
-#else
- return make_float3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
-#endif
-}
-
-ccl_device_inline float3 max(const float3 &a, const float3 &b)
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_max_ps(a.m128, b.m128));
-#else
- return make_float3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
-#endif
-}
-
-ccl_device_inline float3 clamp(const float3 &a, const float3 &mn, const float3 &mx)
-{
- return min(max(a, mn), mx);
-}
-
-ccl_device_inline float3 fabs(const float3 &a)
-{
-#ifdef __KERNEL_SSE__
-# ifdef __KERNEL_NEON__
- return float3(vabsq_f32(a.m128));
-# else
- __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
- return float3(_mm_and_ps(a.m128, mask));
-# endif
-#else
- return make_float3(fabsf(a.x), fabsf(a.y), fabsf(a.z));
-#endif
-}
-
-ccl_device_inline float3 sqrt(const float3 &a)
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_sqrt_ps(a));
-#else
- return make_float3(sqrtf(a.x), sqrtf(a.y), sqrtf(a.z));
-#endif
-}
-
-ccl_device_inline float3 floor(const float3 &a)
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_floor_ps(a));
-#else
- return make_float3(floorf(a.x), floorf(a.y), floorf(a.z));
-#endif
-}
-
-ccl_device_inline float3 ceil(const float3 &a)
-{
-#ifdef __KERNEL_SSE__
- return float3(_mm_ceil_ps(a));
-#else
- return make_float3(ceilf(a.x), ceilf(a.y), ceilf(a.z));
-#endif
-}
-
-ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t)
-{
- return a + t * (b - a);
-}
-
-ccl_device_inline float3 rcp(const float3 &a)
-{
-#ifdef __KERNEL_SSE__
- /* Don't use _mm_rcp_ps due to poor precision. */
- return float3(_mm_div_ps(_mm_set_ps1(1.0f), a.m128));
-#else
- return make_float3(1.0f / a.x, 1.0f / a.y, 1.0f / a.z);
-#endif
-}
-
-ccl_device_inline float min3(float3 a)
-{
- return min(min(a.x, a.y), a.z);
-}
-
-ccl_device_inline float max3(float3 a)
-{
- return max(max(a.x, a.y), a.z);
-}
-
-ccl_device_inline float len(const float3 a)
-{
-#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
- return _mm_cvtss_f32(_mm_sqrt_ss(_mm_dp_ps(a.m128, a.m128, 0x7F)));
-#else
- return sqrtf(dot(a, a));
-#endif
-}
-
-ccl_device_inline float len_squared(const float3 a)
-{
- return dot(a, a);
-}
-
-ccl_device_inline float3 reflect(const float3 incident, const float3 normal)
-{
- float3 unit_normal = normalize(normal);
- return incident - 2.0f * unit_normal * dot(incident, unit_normal);
-}
-
-ccl_device_inline float3 refract(const float3 incident, const float3 normal, const float eta)
-{
- float k = 1.0f - eta * eta * (1.0f - dot(normal, incident) * dot(normal, incident));
- if (k < 0.0f)
- return zero_float3();
- else
- return eta * incident - (eta * dot(normal, incident) + sqrt(k)) * normal;
-}
-
-ccl_device_inline float3 faceforward(const float3 vector,
- const float3 incident,
- const float3 reference)
-{
- return (dot(reference, incident) < 0.0f) ? vector : -vector;
-}
-
-ccl_device_inline float3 project(const float3 v, const float3 v_proj)
-{
- float len_squared = dot(v_proj, v_proj);
- return (len_squared != 0.0f) ? (dot(v, v_proj) / len_squared) * v_proj : zero_float3();
-}
-
-ccl_device_inline float3 saturate3(float3 a)
-{
- return make_float3(saturate(a.x), saturate(a.y), saturate(a.z));
-}
-
-ccl_device_inline float3 normalize_len(const float3 a, ccl_private float *t)
-{
- *t = len(a);
- float x = 1.0f / *t;
- return a * x;
-}
-
-ccl_device_inline float3 safe_normalize(const float3 a)
-{
- float t = len(a);
- return (t != 0.0f) ? a * (1.0f / t) : a;
-}
-
-ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t)
-{
- *t = len(a);
- return (*t != 0.0f) ? a / (*t) : a;
-}
-
-ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b)
-{
- return make_float3((b.x != 0.0f) ? a.x / b.x : 0.0f,
- (b.y != 0.0f) ? a.y / b.y : 0.0f,
- (b.z != 0.0f) ? a.z / b.z : 0.0f);
-}
-
-ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b)
-{
- return (b != 0.0f) ? a / b : zero_float3();
-}
-
-ccl_device_inline float3 interp(float3 a, float3 b, float t)
-{
- return a + t * (b - a);
-}
-
-ccl_device_inline float3 sqr3(float3 a)
-{
- return a * a;
-}
-
-ccl_device_inline bool is_zero(const float3 a)
-{
-#ifdef __KERNEL_SSE__
- return a == make_float3(0.0f);
-#else
- return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f);
-#endif
-}
-
-ccl_device_inline float reduce_add(const float3 a)
-{
-#if defined(__KERNEL_SSE__) && defined(__KERNEL_NEON__)
- __m128 t = a.m128;
- t[3] = 0.0f;
- return vaddvq_f32(t);
-#else
- return (a.x + a.y + a.z);
-#endif
-}
-
-ccl_device_inline float average(const float3 a)
-{
- return reduce_add(a) * (1.0f / 3.0f);
-}
-
-ccl_device_inline bool isequal_float3(const float3 a, const float3 b)
-{
- return a == b;
-}
-
-ccl_device_inline float3 pow3(float3 v, float e)
-{
- return make_float3(powf(v.x, e), powf(v.y, e), powf(v.z, e));
-}
-
-ccl_device_inline float3 exp3(float3 v)
-{
- return make_float3(expf(v.x), expf(v.y), expf(v.z));
-}
-
-ccl_device_inline float3 log3(float3 v)
-{
- return make_float3(logf(v.x), logf(v.y), logf(v.z));
-}
-
-ccl_device_inline int3 quick_floor_to_int3(const float3 a)
-{
-#ifdef __KERNEL_SSE__
- int3 b = int3(_mm_cvttps_epi32(a.m128));
- int3 isneg = int3(_mm_castps_si128(_mm_cmplt_ps(a.m128, _mm_set_ps1(0.0f))));
- /* Unsaturated add 0xffffffff is the same as subtract -1. */
- return b + isneg;
-#else
- return make_int3(quick_floor_to_int(a.x), quick_floor_to_int(a.y), quick_floor_to_int(a.z));
-#endif
-}
-
-ccl_device_inline bool isfinite3_safe(float3 v)
-{
- return isfinite_safe(v.x) && isfinite_safe(v.y) && isfinite_safe(v.z);
-}
-
-ccl_device_inline float3 ensure_finite3(float3 v)
-{
- if (!isfinite_safe(v.x))
- v.x = 0.0f;
- if (!isfinite_safe(v.y))
- v.y = 0.0f;
- if (!isfinite_safe(v.z))
- v.z = 0.0f;
- return v;
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MATH_FLOAT3_H__ */
diff --git a/intern/cycles/util/util_math_float4.h b/intern/cycles/util/util_math_float4.h
deleted file mode 100644
index f30a78cfc69..00000000000
--- a/intern/cycles/util/util_math_float4.h
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_MATH_FLOAT4_H__
-#define __UTIL_MATH_FLOAT4_H__
-
-#ifndef __UTIL_MATH_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/*******************************************************************************
- * Declaration.
- */
-
-ccl_device_inline float4 operator-(const float4 &a);
-ccl_device_inline float4 operator*(const float4 &a, const float4 &b);
-ccl_device_inline float4 operator*(const float4 &a, float f);
-ccl_device_inline float4 operator*(float f, const float4 &a);
-ccl_device_inline float4 operator/(const float4 &a, float f);
-ccl_device_inline float4 operator/(const float4 &a, const float4 &b);
-ccl_device_inline float4 operator+(const float4 &a, const float f);
-ccl_device_inline float4 operator+(const float4 &a, const float4 &b);
-ccl_device_inline float4 operator-(const float4 &a, const float f);
-ccl_device_inline float4 operator-(const float4 &a, const float4 &b);
-ccl_device_inline float4 operator+=(float4 &a, const float4 &b);
-ccl_device_inline float4 operator*=(float4 &a, const float4 &b);
-ccl_device_inline float4 operator*=(float4 &a, float f);
-ccl_device_inline float4 operator/=(float4 &a, float f);
-
-ccl_device_inline int4 operator<(const float4 &a, const float4 &b);
-ccl_device_inline int4 operator>=(const float4 &a, const float4 &b);
-ccl_device_inline int4 operator<=(const float4 &a, const float4 &b);
-ccl_device_inline bool operator==(const float4 &a, const float4 &b);
-
-ccl_device_inline float distance(const float4 &a, const float4 &b);
-ccl_device_inline float dot(const float4 &a, const float4 &b);
-ccl_device_inline float len_squared(const float4 &a);
-ccl_device_inline float4 rcp(const float4 &a);
-ccl_device_inline float4 sqrt(const float4 &a);
-ccl_device_inline float4 sqr(const float4 &a);
-ccl_device_inline float4 cross(const float4 &a, const float4 &b);
-ccl_device_inline bool is_zero(const float4 &a);
-ccl_device_inline float average(const float4 &a);
-ccl_device_inline float len(const float4 &a);
-ccl_device_inline float4 normalize(const float4 &a);
-ccl_device_inline float4 safe_normalize(const float4 &a);
-ccl_device_inline float4 min(const float4 &a, const float4 &b);
-ccl_device_inline float4 max(const float4 &a, const float4 &b);
-ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx);
-ccl_device_inline float4 fabs(const float4 &a);
-ccl_device_inline float4 floor(const float4 &a);
-ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t);
-
-ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b);
-
-#ifdef __KERNEL_SSE__
-template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
-__forceinline const float4 shuffle(const float4 &b);
-template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
-__forceinline const float4 shuffle(const float4 &a, const float4 &b);
-
-template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &b);
-
-template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &a, const float4 &b);
-template<> __forceinline const float4 shuffle<2, 3, 2, 3>(const float4 &a, const float4 &b);
-
-# ifdef __KERNEL_SSE3__
-template<> __forceinline const float4 shuffle<0, 0, 2, 2>(const float4 &b);
-template<> __forceinline const float4 shuffle<1, 1, 3, 3>(const float4 &b);
-# endif
-#endif /* __KERNEL_SSE__ */
-
-#ifndef __KERNEL_GPU__
-ccl_device_inline float4 select(const int4 &mask, const float4 &a, const float4 &b);
-ccl_device_inline float4 reduce_min(const float4 &a);
-ccl_device_inline float4 reduce_max(const float4 &a);
-ccl_device_inline float4 reduce_add(const float4 &a);
-#endif /* !__KERNEL_GPU__ */
-
-/*******************************************************************************
- * Definition.
- */
-
-ccl_device_inline float4 zero_float4()
-{
-#ifdef __KERNEL_SSE__
- return float4(_mm_setzero_ps());
-#else
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-#endif
-}
-
-ccl_device_inline float4 one_float4()
-{
- return make_float4(1.0f, 1.0f, 1.0f, 1.0f);
-}
-
-ccl_device_inline float4 operator-(const float4 &a)
-{
-#ifdef __KERNEL_SSE__
- __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
- return float4(_mm_xor_ps(a.m128, mask));
-#else
- return make_float4(-a.x, -a.y, -a.z, -a.w);
-#endif
-}
-
-ccl_device_inline float4 operator*(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return float4(_mm_mul_ps(a.m128, b.m128));
-#else
- return make_float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
-#endif
-}
-
-ccl_device_inline float4 operator*(const float4 &a, float f)
-{
-#if defined(__KERNEL_SSE__)
- return a * make_float4(f);
-#else
- return make_float4(a.x * f, a.y * f, a.z * f, a.w * f);
-#endif
-}
-
-ccl_device_inline float4 operator*(float f, const float4 &a)
-{
- return a * f;
-}
-
-ccl_device_inline float4 operator/(const float4 &a, float f)
-{
- return a * (1.0f / f);
-}
-
-ccl_device_inline float4 operator/(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return float4(_mm_div_ps(a.m128, b.m128));
-#else
- return make_float4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
-#endif
-}
-
-ccl_device_inline float4 operator+(const float4 &a, const float f)
-{
- return a + make_float4(f, f, f, f);
-}
-
-ccl_device_inline float4 operator+(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return float4(_mm_add_ps(a.m128, b.m128));
-#else
- return make_float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
-#endif
-}
-
-ccl_device_inline float4 operator-(const float4 &a, const float f)
-{
- return a - make_float4(f, f, f, f);
-}
-
-ccl_device_inline float4 operator-(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return float4(_mm_sub_ps(a.m128, b.m128));
-#else
- return make_float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
-#endif
-}
-
-ccl_device_inline float4 operator+=(float4 &a, const float4 &b)
-{
- return a = a + b;
-}
-
-ccl_device_inline float4 operator-=(float4 &a, const float4 &b)
-{
- return a = a - b;
-}
-
-ccl_device_inline float4 operator*=(float4 &a, const float4 &b)
-{
- return a = a * b;
-}
-
-ccl_device_inline float4 operator*=(float4 &a, float f)
-{
- return a = a * f;
-}
-
-ccl_device_inline float4 operator/=(float4 &a, float f)
-{
- return a = a / f;
-}
-
-ccl_device_inline int4 operator<(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return int4(_mm_castps_si128(_mm_cmplt_ps(a.m128, b.m128)));
-#else
- return make_int4(a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w);
-#endif
-}
-
-ccl_device_inline int4 operator>=(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return int4(_mm_castps_si128(_mm_cmpge_ps(a.m128, b.m128)));
-#else
- return make_int4(a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w);
-#endif
-}
-
-ccl_device_inline int4 operator<=(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return int4(_mm_castps_si128(_mm_cmple_ps(a.m128, b.m128)));
-#else
- return make_int4(a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w);
-#endif
-}
-
-ccl_device_inline bool operator==(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return (_mm_movemask_ps(_mm_cmpeq_ps(a.m128, b.m128)) & 15) == 15;
-#else
- return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
-#endif
-}
-
-ccl_device_inline float distance(const float4 &a, const float4 &b)
-{
- return len(a - b);
-}
-
-ccl_device_inline float dot(const float4 &a, const float4 &b)
-{
-#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
-# if defined(__KERNEL_NEON__)
- __m128 t = vmulq_f32(a, b);
- return vaddvq_f32(t);
-# else
- return _mm_cvtss_f32(_mm_dp_ps(a, b, 0xFF));
-# endif
-#else
- return (a.x * b.x + a.y * b.y) + (a.z * b.z + a.w * b.w);
-#endif
-}
-
-ccl_device_inline float len_squared(const float4 &a)
-{
- return dot(a, a);
-}
-
-ccl_device_inline float4 rcp(const float4 &a)
-{
-#ifdef __KERNEL_SSE__
- /* Don't use _mm_rcp_ps due to poor precision. */
- return float4(_mm_div_ps(_mm_set_ps1(1.0f), a.m128));
-#else
- return make_float4(1.0f / a.x, 1.0f / a.y, 1.0f / a.z, 1.0f / a.w);
-#endif
-}
-
-ccl_device_inline float4 sqrt(const float4 &a)
-{
-#ifdef __KERNEL_SSE__
- return float4(_mm_sqrt_ps(a.m128));
-#else
- return make_float4(sqrtf(a.x), sqrtf(a.y), sqrtf(a.z), sqrtf(a.w));
-#endif
-}
-
-ccl_device_inline float4 sqr(const float4 &a)
-{
- return a * a;
-}
-
-ccl_device_inline float4 cross(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return (shuffle<1, 2, 0, 0>(a) * shuffle<2, 0, 1, 0>(b)) -
- (shuffle<2, 0, 1, 0>(a) * shuffle<1, 2, 0, 0>(b));
-#else
- return make_float4(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x, 0.0f);
-#endif
-}
-
-ccl_device_inline bool is_zero(const float4 &a)
-{
-#ifdef __KERNEL_SSE__
- return a == make_float4(0.0f);
-#else
- return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f && a.w == 0.0f);
-#endif
-}
-
-ccl_device_inline float4 reduce_add(const float4 &a)
-{
-#if defined(__KERNEL_SSE__)
-# if defined(__KERNEL_NEON__)
- return float4(vdupq_n_f32(vaddvq_f32(a)));
-# elif defined(__KERNEL_SSE3__)
- float4 h(_mm_hadd_ps(a.m128, a.m128));
- return float4(_mm_hadd_ps(h.m128, h.m128));
-# else
- float4 h(shuffle<1, 0, 3, 2>(a) + a);
- return shuffle<2, 3, 0, 1>(h) + h;
-# endif
-#else
- float sum = (a.x + a.y) + (a.z + a.w);
- return make_float4(sum, sum, sum, sum);
-#endif
-}
-
-ccl_device_inline float average(const float4 &a)
-{
- return reduce_add(a).x * 0.25f;
-}
-
-ccl_device_inline float len(const float4 &a)
-{
- return sqrtf(dot(a, a));
-}
-
-ccl_device_inline float4 normalize(const float4 &a)
-{
- return a / len(a);
-}
-
-ccl_device_inline float4 safe_normalize(const float4 &a)
-{
- float t = len(a);
- return (t != 0.0f) ? a / t : a;
-}
-
-ccl_device_inline float4 min(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return float4(_mm_min_ps(a.m128, b.m128));
-#else
- return make_float4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w));
-#endif
-}
-
-ccl_device_inline float4 max(const float4 &a, const float4 &b)
-{
-#ifdef __KERNEL_SSE__
- return float4(_mm_max_ps(a.m128, b.m128));
-#else
- return make_float4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w));
-#endif
-}
-
-ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx)
-{
- return min(max(a, mn), mx);
-}
-
-ccl_device_inline float4 fabs(const float4 &a)
-{
-#if defined(__KERNEL_SSE__)
-# if defined(__KERNEL_NEON__)
- return float4(vabsq_f32(a));
-# else
- return float4(_mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))));
-# endif
-#else
- return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w));
-#endif
-}
-
-ccl_device_inline float4 floor(const float4 &a)
-{
-#ifdef __KERNEL_SSE__
- return float4(_mm_floor_ps(a));
-#else
- return make_float4(floorf(a.x), floorf(a.y), floorf(a.z), floorf(a.w));
-#endif
-}
-
-ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t)
-{
- return a + t * (b - a);
-}
-
-#ifdef __KERNEL_SSE__
-template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
-__forceinline const float4 shuffle(const float4 &b)
-{
-# if defined(__KERNEL_NEON__)
- return float4(shuffle_neon<__m128, index_0, index_1, index_2, index_3>(b.m128));
-# else
- return float4(_mm_castsi128_ps(
- _mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(index_3, index_2, index_1, index_0))));
-# endif
-}
-
-template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
-__forceinline const float4 shuffle(const float4 &a, const float4 &b)
-{
-# if defined(__KERNEL_NEON__)
- return float4(shuffle_neon<__m128, index_0, index_1, index_2, index_3>(a.m128, b.m128));
-# else
- return float4(_mm_shuffle_ps(a.m128, b.m128, _MM_SHUFFLE(index_3, index_2, index_1, index_0)));
-# endif
-}
-
-template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &b)
-{
- return float4(_mm_castpd_ps(_mm_movedup_pd(_mm_castps_pd(b))));
-}
-
-template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &a, const float4 &b)
-{
- return float4(_mm_movelh_ps(a.m128, b.m128));
-}
-
-template<> __forceinline const float4 shuffle<2, 3, 2, 3>(const float4 &a, const float4 &b)
-{
- return float4(_mm_movehl_ps(b.m128, a.m128));
-}
-
-# ifdef __KERNEL_SSE3__
-template<> __forceinline const float4 shuffle<0, 0, 2, 2>(const float4 &b)
-{
- return float4(_mm_moveldup_ps(b));
-}
-
-template<> __forceinline const float4 shuffle<1, 1, 3, 3>(const float4 &b)
-{
- return float4(_mm_movehdup_ps(b));
-}
-# endif /* __KERNEL_SSE3__ */
-#endif /* __KERNEL_SSE__ */
-
-#ifndef __KERNEL_GPU__
-ccl_device_inline float4 select(const int4 &mask, const float4 &a, const float4 &b)
-{
-# ifdef __KERNEL_SSE__
- return float4(_mm_blendv_ps(b.m128, a.m128, _mm_castsi128_ps(mask.m128)));
-# else
- return make_float4(
- (mask.x) ? a.x : b.x, (mask.y) ? a.y : b.y, (mask.z) ? a.z : b.z, (mask.w) ? a.w : b.w);
-# endif
-}
-
-ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
-{
- /* Replace elements of x with zero where mask isn't set. */
- return select(mask, a, make_float4(0.0f));
-}
-
-ccl_device_inline float4 reduce_min(const float4 &a)
-{
-# if defined(__KERNEL_SSE__)
-# if defined(__KERNEL_NEON__)
- return float4(vdupq_n_f32(vminvq_f32(a)));
-# else
- float4 h = min(shuffle<1, 0, 3, 2>(a), a);
- return min(shuffle<2, 3, 0, 1>(h), h);
-# endif
-# else
- return make_float4(min(min(a.x, a.y), min(a.z, a.w)));
-# endif
-}
-
-ccl_device_inline float4 reduce_max(const float4 &a)
-{
-# if defined(__KERNEL_SSE__)
-# if defined(__KERNEL_NEON__)
- return float4(vdupq_n_f32(vmaxvq_f32(a)));
-# else
- float4 h = max(shuffle<1, 0, 3, 2>(a), a);
- return max(shuffle<2, 3, 0, 1>(h), h);
-# endif
-# else
- return make_float4(max(max(a.x, a.y), max(a.z, a.w)));
-# endif
-}
-
-ccl_device_inline float4 load_float4(ccl_private const float *v)
-{
-# ifdef __KERNEL_SSE__
- return float4(_mm_loadu_ps(v));
-# else
- return make_float4(v[0], v[1], v[2], v[3]);
-# endif
-}
-
-#endif /* !__KERNEL_GPU__ */
-
-ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b)
-{
- return (b != 0.0f) ? a / b : zero_float4();
-}
-
-ccl_device_inline bool isfinite4_safe(float4 v)
-{
- return isfinite_safe(v.x) && isfinite_safe(v.y) && isfinite_safe(v.z) && isfinite_safe(v.w);
-}
-
-ccl_device_inline float4 ensure_finite4(float4 v)
-{
- if (!isfinite_safe(v.x))
- v.x = 0.0f;
- if (!isfinite_safe(v.y))
- v.y = 0.0f;
- if (!isfinite_safe(v.z))
- v.z = 0.0f;
- if (!isfinite_safe(v.w))
- v.w = 0.0f;
- return v;
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MATH_FLOAT4_H__ */
diff --git a/intern/cycles/util/util_math_int2.h b/intern/cycles/util/util_math_int2.h
deleted file mode 100644
index 5782b878801..00000000000
--- a/intern/cycles/util/util_math_int2.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_MATH_INT2_H__
-#define __UTIL_MATH_INT2_H__
-
-#ifndef __UTIL_MATH_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/*******************************************************************************
- * Declaration.
- */
-
-ccl_device_inline bool operator==(const int2 a, const int2 b);
-ccl_device_inline int2 operator+(const int2 &a, const int2 &b);
-ccl_device_inline int2 operator+=(int2 &a, const int2 &b);
-ccl_device_inline int2 operator-(const int2 &a, const int2 &b);
-ccl_device_inline int2 operator*(const int2 &a, const int2 &b);
-ccl_device_inline int2 operator/(const int2 &a, const int2 &b);
-
-/*******************************************************************************
- * Definition.
- */
-
-ccl_device_inline bool operator==(const int2 a, const int2 b)
-{
- return (a.x == b.x && a.y == b.y);
-}
-
-ccl_device_inline int2 operator+(const int2 &a, const int2 &b)
-{
- return make_int2(a.x + b.x, a.y + b.y);
-}
-
-ccl_device_inline int2 operator+=(int2 &a, const int2 &b)
-{
- return a = a + b;
-}
-
-ccl_device_inline int2 operator-(const int2 &a, const int2 &b)
-{
- return make_int2(a.x - b.x, a.y - b.y);
-}
-
-ccl_device_inline int2 operator*(const int2 &a, const int2 &b)
-{
- return make_int2(a.x * b.x, a.y * b.y);
-}
-
-ccl_device_inline int2 operator/(const int2 &a, const int2 &b)
-{
- return make_int2(a.x / b.x, a.y / b.y);
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MATH_INT2_H__ */
diff --git a/intern/cycles/util/util_math_int3.h b/intern/cycles/util/util_math_int3.h
deleted file mode 100644
index e0dfae7c015..00000000000
--- a/intern/cycles/util/util_math_int3.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_MATH_INT3_H__
-#define __UTIL_MATH_INT3_H__
-
-#ifndef __UTIL_MATH_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/*******************************************************************************
- * Declaration.
- */
-
-ccl_device_inline int3 min(int3 a, int3 b);
-ccl_device_inline int3 max(int3 a, int3 b);
-ccl_device_inline int3 clamp(const int3 &a, int mn, int mx);
-ccl_device_inline int3 clamp(const int3 &a, int3 &mn, int mx);
-
-/*******************************************************************************
- * Definition.
- */
-
-ccl_device_inline int3 min(int3 a, int3 b)
-{
-#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__)
- return int3(_mm_min_epi32(a.m128, b.m128));
-#else
- return make_int3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
-#endif
-}
-
-ccl_device_inline int3 max(int3 a, int3 b)
-{
-#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__)
- return int3(_mm_max_epi32(a.m128, b.m128));
-#else
- return make_int3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
-#endif
-}
-
-ccl_device_inline int3 clamp(const int3 &a, int mn, int mx)
-{
-#ifdef __KERNEL_SSE__
- return min(max(a, make_int3(mn)), make_int3(mx));
-#else
- return make_int3(clamp(a.x, mn, mx), clamp(a.y, mn, mx), clamp(a.z, mn, mx));
-#endif
-}
-
-ccl_device_inline int3 clamp(const int3 &a, int3 &mn, int mx)
-{
-#ifdef __KERNEL_SSE__
- return min(max(a, mn), make_int3(mx));
-#else
- return make_int3(clamp(a.x, mn.x, mx), clamp(a.y, mn.y, mx), clamp(a.z, mn.z, mx));
-#endif
-}
-
-ccl_device_inline bool operator==(const int3 &a, const int3 &b)
-{
- return a.x == b.x && a.y == b.y && a.z == b.z;
-}
-
-ccl_device_inline bool operator!=(const int3 &a, const int3 &b)
-{
- return !(a == b);
-}
-
-ccl_device_inline bool operator<(const int3 &a, const int3 &b)
-{
- return a.x < b.x && a.y < b.y && a.z < b.z;
-}
-
-ccl_device_inline int3 operator+(const int3 &a, const int3 &b)
-{
-#ifdef __KERNEL_SSE__
- return int3(_mm_add_epi32(a.m128, b.m128));
-#else
- return make_int3(a.x + b.x, a.y + b.y, a.z + b.z);
-#endif
-}
-
-ccl_device_inline int3 operator-(const int3 &a, const int3 &b)
-{
-#ifdef __KERNEL_SSE__
- return int3(_mm_sub_epi32(a.m128, b.m128));
-#else
- return make_int3(a.x - b.x, a.y - b.y, a.z - b.z);
-#endif
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MATH_INT3_H__ */
diff --git a/intern/cycles/util/util_math_int4.h b/intern/cycles/util/util_math_int4.h
deleted file mode 100644
index 186cc58489b..00000000000
--- a/intern/cycles/util/util_math_int4.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_MATH_INT4_H__
-#define __UTIL_MATH_INT4_H__
-
-#ifndef __UTIL_MATH_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/*******************************************************************************
- * Declaration.
- */
-
-#ifndef __KERNEL_GPU__
-ccl_device_inline int4 operator+(const int4 &a, const int4 &b);
-ccl_device_inline int4 operator+=(int4 &a, const int4 &b);
-ccl_device_inline int4 operator>>(const int4 &a, int i);
-ccl_device_inline int4 operator<<(const int4 &a, int i);
-ccl_device_inline int4 operator<(const int4 &a, const int4 &b);
-ccl_device_inline int4 operator>=(const int4 &a, const int4 &b);
-ccl_device_inline int4 operator&(const int4 &a, const int4 &b);
-ccl_device_inline int4 min(int4 a, int4 b);
-ccl_device_inline int4 max(int4 a, int4 b);
-ccl_device_inline int4 clamp(const int4 &a, const int4 &mn, const int4 &mx);
-ccl_device_inline int4 select(const int4 &mask, const int4 &a, const int4 &b);
-#endif /* __KERNEL_GPU__ */
-
-/*******************************************************************************
- * Definition.
- */
-
-#ifndef __KERNEL_GPU__
-ccl_device_inline int4 operator+(const int4 &a, const int4 &b)
-{
-# ifdef __KERNEL_SSE__
- return int4(_mm_add_epi32(a.m128, b.m128));
-# else
- return make_int4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
-# endif
-}
-
-ccl_device_inline int4 operator+=(int4 &a, const int4 &b)
-{
- return a = a + b;
-}
-
-ccl_device_inline int4 operator>>(const int4 &a, int i)
-{
-# ifdef __KERNEL_SSE__
- return int4(_mm_srai_epi32(a.m128, i));
-# else
- return make_int4(a.x >> i, a.y >> i, a.z >> i, a.w >> i);
-# endif
-}
-
-ccl_device_inline int4 operator<<(const int4 &a, int i)
-{
-# ifdef __KERNEL_SSE__
- return int4(_mm_slli_epi32(a.m128, i));
-# else
- return make_int4(a.x << i, a.y << i, a.z << i, a.w << i);
-# endif
-}
-
-ccl_device_inline int4 operator<(const int4 &a, const int4 &b)
-{
-# ifdef __KERNEL_SSE__
- return int4(_mm_cmplt_epi32(a.m128, b.m128));
-# else
- return make_int4(a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w);
-# endif
-}
-
-ccl_device_inline int4 operator>=(const int4 &a, const int4 &b)
-{
-# ifdef __KERNEL_SSE__
- return int4(_mm_xor_si128(_mm_set1_epi32(0xffffffff), _mm_cmplt_epi32(a.m128, b.m128)));
-# else
- return make_int4(a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w);
-# endif
-}
-
-ccl_device_inline int4 operator&(const int4 &a, const int4 &b)
-{
-# ifdef __KERNEL_SSE__
- return int4(_mm_and_si128(a.m128, b.m128));
-# else
- return make_int4(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);
-# endif
-}
-
-ccl_device_inline int4 min(int4 a, int4 b)
-{
-# if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__)
- return int4(_mm_min_epi32(a.m128, b.m128));
-# else
- return make_int4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w));
-# endif
-}
-
-ccl_device_inline int4 max(int4 a, int4 b)
-{
-# if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__)
- return int4(_mm_max_epi32(a.m128, b.m128));
-# else
- return make_int4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w));
-# endif
-}
-
-ccl_device_inline int4 clamp(const int4 &a, const int4 &mn, const int4 &mx)
-{
- return min(max(a, mn), mx);
-}
-
-ccl_device_inline int4 select(const int4 &mask, const int4 &a, const int4 &b)
-{
-# ifdef __KERNEL_SSE__
- const __m128 m = _mm_cvtepi32_ps(mask);
- /* TODO(sergey): avoid cvt. */
- return int4(_mm_castps_si128(
- _mm_or_ps(_mm_and_ps(m, _mm_castsi128_ps(a)), _mm_andnot_ps(m, _mm_castsi128_ps(b)))));
-# else
- return make_int4(
- (mask.x) ? a.x : b.x, (mask.y) ? a.y : b.y, (mask.z) ? a.z : b.z, (mask.w) ? a.w : b.w);
-# endif
-}
-
-ccl_device_inline int4 load_int4(const int *v)
-{
-# ifdef __KERNEL_SSE__
- return int4(_mm_loadu_si128((__m128i *)v));
-# else
- return make_int4(v[0], v[1], v[2], v[3]);
-# endif
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MATH_INT4_H__ */
diff --git a/intern/cycles/util/util_md5.cpp b/intern/cycles/util/util_md5.cpp
deleted file mode 100644
index 0df521c2b58..00000000000
--- a/intern/cycles/util/util_md5.cpp
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- *
- * L. Peter Deutsch
- * ghost@aladdin.com
- */
-
-/* Minor modifications done to remove some code and change style. */
-
-#include "util_md5.h"
-#include "util_path.h"
-
-#include <stdio.h>
-#include <string.h>
-
-CCL_NAMESPACE_BEGIN
-
-#define T_MASK ((uint32_t)~0)
-#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
-#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
-#define T3 0x242070db
-#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
-#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
-#define T6 0x4787c62a
-#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
-#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
-#define T9 0x698098d8
-#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
-#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
-#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
-#define T13 0x6b901122
-#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
-#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
-#define T16 0x49b40821
-#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
-#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
-#define T19 0x265e5a51
-#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
-#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
-#define T22 0x02441453
-#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
-#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
-#define T25 0x21e1cde6
-#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
-#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
-#define T28 0x455a14ed
-#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
-#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
-#define T31 0x676f02d9
-#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
-#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
-#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
-#define T35 0x6d9d6122
-#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
-#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
-#define T38 0x4bdecfa9
-#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
-#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
-#define T41 0x289b7ec6
-#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
-#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
-#define T44 0x04881d05
-#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
-#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
-#define T47 0x1fa27cf8
-#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
-#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
-#define T50 0x432aff97
-#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
-#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
-#define T53 0x655b59c3
-#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
-#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
-#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
-#define T57 0x6fa87e4f
-#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
-#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
-#define T60 0x4e0811a1
-#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
-#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
-#define T63 0x2ad7d2bb
-#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
-
-void MD5Hash::process(const uint8_t *data /*[64]*/)
-{
- uint32_t a = abcd[0], b = abcd[1], c = abcd[2], d = abcd[3];
- uint32_t t;
- /* Define storage for little-endian or both types of CPUs. */
- uint32_t xbuf[16];
- const uint32_t *X;
-
- {
- /*
- * Determine dynamically whether this is a big-endian or
- * little-endian machine, since we can use a more efficient
- * algorithm on the latter.
- */
- static const int w = 1;
-
- if (*((const uint8_t *)&w)) /* dynamic little-endian */
- {
- /*
- * On little-endian machines, we can process properly aligned
- * data without copying it.
- */
- if (!((data - (const uint8_t *)0) & 3)) {
- /* data are properly aligned */
- X = (const uint32_t *)data;
- }
- else {
- /* not aligned */
- memcpy(xbuf, data, 64);
- X = xbuf;
- }
- }
- else { /* dynamic big-endian */
- /*
- * On big-endian machines, we must arrange the bytes in the
- * right order.
- */
- const uint8_t *xp = data;
- int i;
-
- X = xbuf; /* (dynamic only) */
- for (i = 0; i < 16; ++i, xp += 4)
- xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
- }
- }
-
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-
- /* Round 1. */
- /* Let [abcd k s i] denote the operation
- * a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
-#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
-#define SET(a, b, c, d, k, s, Ti) \
- t = a + F(b, c, d) + X[k] + Ti; \
- a = ROTATE_LEFT(t, s) + b
- /* Do the following 16 operations. */
- SET(a, b, c, d, 0, 7, T1);
- SET(d, a, b, c, 1, 12, T2);
- SET(c, d, a, b, 2, 17, T3);
- SET(b, c, d, a, 3, 22, T4);
- SET(a, b, c, d, 4, 7, T5);
- SET(d, a, b, c, 5, 12, T6);
- SET(c, d, a, b, 6, 17, T7);
- SET(b, c, d, a, 7, 22, T8);
- SET(a, b, c, d, 8, 7, T9);
- SET(d, a, b, c, 9, 12, T10);
- SET(c, d, a, b, 10, 17, T11);
- SET(b, c, d, a, 11, 22, T12);
- SET(a, b, c, d, 12, 7, T13);
- SET(d, a, b, c, 13, 12, T14);
- SET(c, d, a, b, 14, 17, T15);
- SET(b, c, d, a, 15, 22, T16);
-#undef SET
-
- /* Round 2. */
- /* Let [abcd k s i] denote the operation
- * a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
-#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
-#define SET(a, b, c, d, k, s, Ti) \
- t = a + G(b, c, d) + X[k] + Ti; \
- a = ROTATE_LEFT(t, s) + b
- /* Do the following 16 operations. */
- SET(a, b, c, d, 1, 5, T17);
- SET(d, a, b, c, 6, 9, T18);
- SET(c, d, a, b, 11, 14, T19);
- SET(b, c, d, a, 0, 20, T20);
- SET(a, b, c, d, 5, 5, T21);
- SET(d, a, b, c, 10, 9, T22);
- SET(c, d, a, b, 15, 14, T23);
- SET(b, c, d, a, 4, 20, T24);
- SET(a, b, c, d, 9, 5, T25);
- SET(d, a, b, c, 14, 9, T26);
- SET(c, d, a, b, 3, 14, T27);
- SET(b, c, d, a, 8, 20, T28);
- SET(a, b, c, d, 13, 5, T29);
- SET(d, a, b, c, 2, 9, T30);
- SET(c, d, a, b, 7, 14, T31);
- SET(b, c, d, a, 12, 20, T32);
-#undef SET
-
- /* Round 3. */
- /* Let [abcd k s t] denote the operation
- * a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define SET(a, b, c, d, k, s, Ti) \
- t = a + H(b, c, d) + X[k] + Ti; \
- a = ROTATE_LEFT(t, s) + b
- /* Do the following 16 operations. */
- SET(a, b, c, d, 5, 4, T33);
- SET(d, a, b, c, 8, 11, T34);
- SET(c, d, a, b, 11, 16, T35);
- SET(b, c, d, a, 14, 23, T36);
- SET(a, b, c, d, 1, 4, T37);
- SET(d, a, b, c, 4, 11, T38);
- SET(c, d, a, b, 7, 16, T39);
- SET(b, c, d, a, 10, 23, T40);
- SET(a, b, c, d, 13, 4, T41);
- SET(d, a, b, c, 0, 11, T42);
- SET(c, d, a, b, 3, 16, T43);
- SET(b, c, d, a, 6, 23, T44);
- SET(a, b, c, d, 9, 4, T45);
- SET(d, a, b, c, 12, 11, T46);
- SET(c, d, a, b, 15, 16, T47);
- SET(b, c, d, a, 2, 23, T48);
-#undef SET
-
- /* Round 4. */
- /* Let [abcd k s t] denote the operation
- * a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))
-#define SET(a, b, c, d, k, s, Ti) \
- t = a + I(b, c, d) + X[k] + Ti; \
- a = ROTATE_LEFT(t, s) + b
- /* Do the following 16 operations. */
- SET(a, b, c, d, 0, 6, T49);
- SET(d, a, b, c, 7, 10, T50);
- SET(c, d, a, b, 14, 15, T51);
- SET(b, c, d, a, 5, 21, T52);
- SET(a, b, c, d, 12, 6, T53);
- SET(d, a, b, c, 3, 10, T54);
- SET(c, d, a, b, 10, 15, T55);
- SET(b, c, d, a, 1, 21, T56);
- SET(a, b, c, d, 8, 6, T57);
- SET(d, a, b, c, 15, 10, T58);
- SET(c, d, a, b, 6, 15, T59);
- SET(b, c, d, a, 13, 21, T60);
- SET(a, b, c, d, 4, 6, T61);
- SET(d, a, b, c, 11, 10, T62);
- SET(c, d, a, b, 2, 15, T63);
- SET(b, c, d, a, 9, 21, T64);
-#undef SET
-
- /* Then perform the following additions. (That is increment each
- * of the four registers by the value it had before this block
- * was started.) */
- abcd[0] += a;
- abcd[1] += b;
- abcd[2] += c;
- abcd[3] += d;
-}
-
-MD5Hash::MD5Hash()
-{
- count[0] = count[1] = 0;
- abcd[0] = 0x67452301;
- abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
- abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
- abcd[3] = 0x10325476;
-}
-
-MD5Hash::~MD5Hash()
-{
-}
-
-void MD5Hash::append(const uint8_t *data, int nbytes)
-{
- const uint8_t *p = data;
- int left = nbytes;
- int offset = (count[0] >> 3) & 63;
- uint32_t nbits = (uint32_t)(nbytes << 3);
-
- if (nbytes <= 0)
- return;
-
- /* Update the message length. */
- count[1] += nbytes >> 29;
- count[0] += nbits;
- if (count[0] < nbits)
- count[1]++;
-
- /* Process an initial partial block. */
- if (offset) {
- int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
-
- memcpy(buf + offset, p, copy);
- if (offset + copy < 64)
- return;
- p += copy;
- left -= copy;
- process(buf);
- }
-
- /* Process full blocks. */
- for (; left >= 64; p += 64, left -= 64)
- process(p);
-
- /* Process a final partial block. */
- if (left)
- memcpy(buf, p, left);
-}
-
-void MD5Hash::append(const string &str)
-{
- if (str.size()) {
- append((const uint8_t *)str.c_str(), str.size());
- }
-}
-
-bool MD5Hash::append_file(const string &filepath)
-{
- FILE *f = path_fopen(filepath, "rb");
-
- if (!f) {
- fprintf(stderr, "MD5: failed to open file %s\n", filepath.c_str());
- return false;
- }
-
- const size_t buffer_size = 1024;
- uint8_t buffer[buffer_size];
- size_t n;
-
- do {
- n = fread(buffer, 1, buffer_size, f);
- append(buffer, n);
- } while (n == buffer_size);
-
- bool success = (ferror(f) == 0);
-
- fclose(f);
-
- return success;
-}
-
-void MD5Hash::finish(uint8_t digest[16])
-{
- static const uint8_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
- uint8_t data[8];
- int i;
-
- /* Save the length before padding. */
- for (i = 0; i < 8; ++i)
- data[i] = (uint8_t)(count[i >> 2] >> ((i & 3) << 3));
-
- /* Pad to 56 bytes mod 64. */
- append(pad, ((55 - (count[0] >> 3)) & 63) + 1);
- /* Append the length. */
- append(data, 8);
-
- for (i = 0; i < 16; ++i)
- digest[i] = (uint8_t)(abcd[i >> 2] >> ((i & 3) << 3));
-}
-
-string MD5Hash::get_hex()
-{
- uint8_t digest[16];
- char buf[16 * 2 + 1];
-
- finish(digest);
-
- for (int i = 0; i < 16; i++)
- sprintf(buf + i * 2, "%02X", (unsigned int)digest[i]);
- buf[sizeof(buf) - 1] = '\0';
-
- return string(buf);
-}
-
-string util_md5_string(const string &str)
-{
- MD5Hash md5;
- md5.append((uint8_t *)str.c_str(), str.size());
- return md5.get_hex();
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_md5.h b/intern/cycles/util/util_md5.h
deleted file mode 100644
index 3102a0f4bad..00000000000
--- a/intern/cycles/util/util_md5.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- *
- * L. Peter Deutsch
- * ghost@aladdin.com
- */
-
-/* MD5
- *
- * Simply MD5 hash computation, used by disk cache. Adapted from external
- * code, with minor code modifications done to remove some unused code and
- * change code style. */
-
-#ifndef __UTIL_MD5_H__
-#define __UTIL_MD5_H__
-
-#include "util/util_string.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class MD5Hash {
- public:
- MD5Hash();
- ~MD5Hash();
-
- void append(const uint8_t *data, int size);
- void append(const string &str);
- bool append_file(const string &filepath);
- string get_hex();
-
- protected:
- void process(const uint8_t *data);
- void finish(uint8_t digest[16]);
-
- uint32_t count[2]; /* message length in bits, LSW first. */
- uint32_t abcd[4]; /* digest buffer */
- uint8_t buf[64]; /* accumulate block */
-};
-
-string util_md5_string(const string &str);
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MD5_H__ */
diff --git a/intern/cycles/util/util_murmurhash.cpp b/intern/cycles/util/util_murmurhash.cpp
deleted file mode 100644
index 5d728769fe9..00000000000
--- a/intern/cycles/util/util_murmurhash.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* This is taken from alShaders/Cryptomatte/MurmurHash3.h:
- *
- * MurmurHash3 was written by Austin Appleby, and is placed in the public
- * domain. The author hereby disclaims copyright to this source code.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "util/util_algorithm.h"
-#include "util/util_murmurhash.h"
-
-#if defined(_MSC_VER)
-# define ROTL32(x, y) _rotl(x, y)
-# define ROTL64(x, y) _rotl64(x, y)
-# define BIG_CONSTANT(x) (x)
-#else
-ccl_device_inline uint32_t rotl32(uint32_t x, int8_t r)
-{
- return (x << r) | (x >> (32 - r));
-}
-# define ROTL32(x, y) rotl32(x, y)
-# define BIG_CONSTANT(x) (x##LLU)
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/* Block read - if your platform needs to do endian-swapping or can only
- * handle aligned reads, do the conversion here. */
-ccl_device_inline uint32_t mm_hash_getblock32(const uint32_t *p, int i)
-{
- return p[i];
-}
-
-/* Finalization mix - force all bits of a hash block to avalanche */
-ccl_device_inline uint32_t mm_hash_fmix32(uint32_t h)
-{
- h ^= h >> 16;
- h *= 0x85ebca6b;
- h ^= h >> 13;
- h *= 0xc2b2ae35;
- h ^= h >> 16;
- return h;
-}
-
-uint32_t util_murmur_hash3(const void *key, int len, uint32_t seed)
-{
- const uint8_t *data = (const uint8_t *)key;
- const int nblocks = len / 4;
-
- uint32_t h1 = seed;
-
- const uint32_t c1 = 0xcc9e2d51;
- const uint32_t c2 = 0x1b873593;
-
- const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
-
- for (int i = -nblocks; i; i++) {
- uint32_t k1 = mm_hash_getblock32(blocks, i);
-
- k1 *= c1;
- k1 = ROTL32(k1, 15);
- k1 *= c2;
-
- h1 ^= k1;
- h1 = ROTL32(h1, 13);
- h1 = h1 * 5 + 0xe6546b64;
- }
-
- const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
-
- uint32_t k1 = 0;
-
- switch (len & 3) {
- case 3:
- k1 ^= tail[2] << 16;
- ATTR_FALLTHROUGH;
- case 2:
- k1 ^= tail[1] << 8;
- ATTR_FALLTHROUGH;
- case 1:
- k1 ^= tail[0];
- k1 *= c1;
- k1 = ROTL32(k1, 15);
- k1 *= c2;
- h1 ^= k1;
- }
-
- h1 ^= len;
- h1 = mm_hash_fmix32(h1);
- return h1;
-}
-
-/* This is taken from the cryptomatte specification 1.0 */
-float util_hash_to_float(uint32_t hash)
-{
- uint32_t mantissa = hash & ((1 << 23) - 1);
- uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
- exponent = max(exponent, (uint32_t)1);
- exponent = min(exponent, (uint32_t)254);
- exponent = exponent << 23;
- uint32_t sign = (hash >> 31);
- sign = sign << 31;
- uint32_t float_bits = sign | exponent | mantissa;
- float f;
- memcpy(&f, &float_bits, sizeof(uint32_t));
- return f;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_murmurhash.h b/intern/cycles/util/util_murmurhash.h
deleted file mode 100644
index 2ec87efd87a..00000000000
--- a/intern/cycles/util/util_murmurhash.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_MURMURHASH_H__
-#define __UTIL_MURMURHASH_H__
-
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-uint32_t util_murmur_hash3(const void *key, int len, uint32_t seed);
-float util_hash_to_float(uint32_t hash);
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MURMURHASH_H__ */
diff --git a/intern/cycles/util/util_openimagedenoise.h b/intern/cycles/util/util_openimagedenoise.h
deleted file mode 100644
index 898c634141e..00000000000
--- a/intern/cycles/util/util_openimagedenoise.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_OPENIMAGEDENOISE_H__
-#define __UTIL_OPENIMAGEDENOISE_H__
-
-#ifdef WITH_OPENIMAGEDENOISE
-# include <OpenImageDenoise/oidn.hpp>
-#endif
-
-#include "util_system.h"
-
-CCL_NAMESPACE_BEGIN
-
-static inline bool openimagedenoise_supported()
-{
-#ifdef WITH_OPENIMAGEDENOISE
-# ifdef __APPLE__
- /* Always supported through Accelerate framework BNNS. */
- return true;
-# else
- return system_cpu_support_sse41();
-# endif
-#else
- return false;
-#endif
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_OPENIMAGEDENOISE_H__ */
diff --git a/intern/cycles/util/util_path.cpp b/intern/cycles/util/util_path.cpp
deleted file mode 100644
index c78f4615013..00000000000
--- a/intern/cycles/util/util_path.cpp
+++ /dev/null
@@ -1,781 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_path.h"
-#include "util/util_md5.h"
-#include "util/util_string.h"
-
-#include <OpenImageIO/filesystem.h>
-#include <OpenImageIO/strutil.h>
-#include <OpenImageIO/sysutil.h>
-
-OIIO_NAMESPACE_USING
-
-#include <stdio.h>
-
-#include <sys/stat.h>
-
-#if defined(_WIN32)
-# define DIR_SEP '\\'
-# define DIR_SEP_ALT '/'
-# include <direct.h>
-#else
-# define DIR_SEP '/'
-# include <dirent.h>
-# include <pwd.h>
-# include <sys/types.h>
-# include <unistd.h>
-#endif
-
-#ifdef HAVE_SHLWAPI_H
-# include <shlwapi.h>
-#endif
-
-#include "util/util_map.h"
-#include "util/util_windows.h"
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef _WIN32
-# if defined(_MSC_VER) || defined(__MINGW64__)
-typedef struct _stat64 path_stat_t;
-# elif defined(__MINGW32__)
-typedef struct _stati64 path_stat_t;
-# else
-typedef struct _stat path_stat_t;
-# endif
-# ifndef S_ISDIR
-# define S_ISDIR(x) (((x)&_S_IFDIR) == _S_IFDIR)
-# endif
-#else
-typedef struct stat path_stat_t;
-#endif
-
-static string cached_path = "";
-static string cached_user_path = "";
-static string cached_temp_path = "";
-static string cached_xdg_cache_path = "";
-
-namespace {
-
-#ifdef _WIN32
-class directory_iterator {
- public:
- class path_info {
- public:
- path_info(const string &path, const WIN32_FIND_DATAW &find_data)
- : path_(path), find_data_(find_data)
- {
- }
-
- string path()
- {
- return path_join(path_, string_from_wstring(find_data_.cFileName));
- }
-
- protected:
- const string &path_;
- const WIN32_FIND_DATAW &find_data_;
- };
-
- directory_iterator() : path_info_("", find_data_), h_find_(INVALID_HANDLE_VALUE)
- {
- }
-
- explicit directory_iterator(const string &path) : path_(path), path_info_(path, find_data_)
- {
- string wildcard = path;
- if (wildcard[wildcard.size() - 1] != DIR_SEP) {
- wildcard += DIR_SEP;
- }
- wildcard += "*";
- h_find_ = FindFirstFileW(string_to_wstring(wildcard).c_str(), &find_data_);
- if (h_find_ != INVALID_HANDLE_VALUE) {
- skip_dots();
- }
- }
-
- ~directory_iterator()
- {
- if (h_find_ != INVALID_HANDLE_VALUE) {
- FindClose(h_find_);
- }
- }
-
- directory_iterator &operator++()
- {
- step();
- return *this;
- }
-
- path_info *operator->()
- {
- return &path_info_;
- }
-
- bool operator!=(const directory_iterator &other)
- {
- return h_find_ != other.h_find_;
- }
-
- protected:
- bool step()
- {
- if (do_step()) {
- return skip_dots();
- }
- return false;
- }
-
- bool do_step()
- {
- if (h_find_ != INVALID_HANDLE_VALUE) {
- bool result = FindNextFileW(h_find_, &find_data_) == TRUE;
- if (!result) {
- FindClose(h_find_);
- h_find_ = INVALID_HANDLE_VALUE;
- }
- return result;
- }
- return false;
- }
-
- bool skip_dots()
- {
- while (wcscmp(find_data_.cFileName, L".") == 0 || wcscmp(find_data_.cFileName, L"..") == 0) {
- if (!do_step()) {
- return false;
- }
- }
- return true;
- }
-
- string path_;
- path_info path_info_;
- WIN32_FIND_DATAW find_data_;
- HANDLE h_find_;
-};
-#else /* _WIN32 */
-
-class directory_iterator {
- public:
- class path_info {
- public:
- explicit path_info(const string &path) : path_(path), entry_(NULL)
- {
- }
-
- string path()
- {
- return path_join(path_, entry_->d_name);
- }
-
- void current_entry_set(const struct dirent *entry)
- {
- entry_ = entry;
- }
-
- protected:
- const string &path_;
- const struct dirent *entry_;
- };
-
- directory_iterator() : path_info_(""), name_list_(NULL), num_entries_(-1), cur_entry_(-1)
- {
- }
-
- explicit directory_iterator(const string &path) : path_(path), path_info_(path_), cur_entry_(0)
- {
- num_entries_ = scandir(path.c_str(), &name_list_, NULL, alphasort);
- if (num_entries_ < 0) {
- perror("scandir");
- }
- else {
- skip_dots();
- }
- }
-
- ~directory_iterator()
- {
- destroy_name_list();
- }
-
- directory_iterator &operator++()
- {
- step();
- return *this;
- }
-
- path_info *operator->()
- {
- path_info_.current_entry_set(name_list_[cur_entry_]);
- return &path_info_;
- }
-
- bool operator!=(const directory_iterator &other)
- {
- return name_list_ != other.name_list_;
- }
-
- protected:
- bool step()
- {
- if (do_step()) {
- return skip_dots();
- }
- return false;
- }
-
- bool do_step()
- {
- ++cur_entry_;
- if (cur_entry_ >= num_entries_) {
- destroy_name_list();
- return false;
- }
- return true;
- }
-
- /* Skip . and .. folders. */
- bool skip_dots()
- {
- while (strcmp(name_list_[cur_entry_]->d_name, ".") == 0 ||
- strcmp(name_list_[cur_entry_]->d_name, "..") == 0) {
- if (!step()) {
- return false;
- }
- }
- return true;
- }
-
- void destroy_name_list()
- {
- if (name_list_ == NULL) {
- return;
- }
- for (int i = 0; i < num_entries_; ++i) {
- free(name_list_[i]);
- }
- free(name_list_);
- name_list_ = NULL;
- }
-
- string path_;
- path_info path_info_;
- struct dirent **name_list_;
- int num_entries_, cur_entry_;
-};
-
-#endif /* _WIN32 */
-
-size_t find_last_slash(const string &path)
-{
- for (size_t i = 0; i < path.size(); ++i) {
- size_t index = path.size() - 1 - i;
-#ifdef _WIN32
- if (path[index] == DIR_SEP || path[index] == DIR_SEP_ALT)
-#else
- if (path[index] == DIR_SEP)
-#endif
- {
- return index;
- }
- }
- return string::npos;
-}
-
-} /* namespace */
-
-static char *path_specials(const string &sub)
-{
- static bool env_init = false;
- static char *env_shader_path;
- static char *env_source_path;
- if (!env_init) {
- env_shader_path = getenv("CYCLES_SHADER_PATH");
- /* NOTE: It is KERNEL in env variable for compatibility reasons. */
- env_source_path = getenv("CYCLES_KERNEL_PATH");
- env_init = true;
- }
- if (env_shader_path != NULL && sub == "shader") {
- return env_shader_path;
- }
- else if (env_shader_path != NULL && sub == "source") {
- return env_source_path;
- }
- return NULL;
-}
-
-#if defined(__linux__) || defined(__APPLE__)
-static string path_xdg_cache_get()
-{
- const char *home = getenv("XDG_CACHE_HOME");
- if (home) {
- return string(home);
- }
- else {
- home = getenv("HOME");
- if (home == NULL) {
- home = getpwuid(getuid())->pw_dir;
- }
- return path_join(string(home), ".cache");
- }
-}
-#endif
-
-void path_init(const string &path, const string &user_path, const string &temp_path)
-{
- cached_path = path;
- cached_user_path = user_path;
- cached_temp_path = temp_path;
-
-#ifdef _MSC_VER
- // workaround for https://svn.boost.org/trac/boost/ticket/6320
- // indirectly init boost codec here since it's not thread safe, and can
- // cause crashes when it happens in multithreaded image load
- OIIO::Filesystem::exists(path);
-#endif
-}
-
-string path_get(const string &sub)
-{
- char *special = path_specials(sub);
- if (special != NULL)
- return special;
-
- if (cached_path == "")
- cached_path = path_dirname(Sysutil::this_program_path());
-
- return path_join(cached_path, sub);
-}
-
-string path_user_get(const string &sub)
-{
- if (cached_user_path == "")
- cached_user_path = path_dirname(Sysutil::this_program_path());
-
- return path_join(cached_user_path, sub);
-}
-
-string path_cache_get(const string &sub)
-{
-#if defined(__linux__) || defined(__APPLE__)
- if (cached_xdg_cache_path == "") {
- cached_xdg_cache_path = path_xdg_cache_get();
- }
- string result = path_join(cached_xdg_cache_path, "cycles");
- return path_join(result, sub);
-#else
- /* TODO(sergey): What that should be on Windows? */
- return path_user_get(path_join("cache", sub));
-#endif
-}
-
-string path_temp_get(const string &sub)
-{
- if (cached_temp_path == "") {
- cached_temp_path = Filesystem::temp_directory_path();
- }
-
- return path_join(cached_temp_path, sub);
-}
-
-#if defined(__linux__) || defined(__APPLE__)
-string path_xdg_home_get(const string &sub = "");
-#endif
-
-string path_filename(const string &path)
-{
- size_t index = find_last_slash(path);
- if (index != string::npos) {
- /* Corner cases to match boost behavior. */
-#ifndef _WIN32
- if (index == 0 && path.size() == 1) {
- return path;
- }
-#endif
- if (index == path.size() - 1) {
-#ifdef _WIN32
- if (index == 2) {
- return string(1, DIR_SEP);
- }
-#endif
- return ".";
- }
- return path.substr(index + 1, path.size() - index - 1);
- }
- return path;
-}
-
-string path_dirname(const string &path)
-{
- size_t index = find_last_slash(path);
- if (index != string::npos) {
-#ifndef _WIN32
- if (index == 0 && path.size() > 1) {
- return string(1, DIR_SEP);
- }
-#endif
- return path.substr(0, index);
- }
- return "";
-}
-
-string path_join(const string &dir, const string &file)
-{
- if (dir.size() == 0) {
- return file;
- }
- if (file.size() == 0) {
- return dir;
- }
- string result = dir;
-#ifndef _WIN32
- if (result[result.size() - 1] != DIR_SEP && file[0] != DIR_SEP)
-#else
- if (result[result.size() - 1] != DIR_SEP && result[result.size() - 1] != DIR_SEP_ALT &&
- file[0] != DIR_SEP && file[0] != DIR_SEP_ALT)
-#endif
- {
- result += DIR_SEP;
- }
- result += file;
- return result;
-}
-
-string path_escape(const string &path)
-{
- string result = path;
- string_replace(result, " ", "\\ ");
- return result;
-}
-
-bool path_is_relative(const string &path)
-{
-#ifdef _WIN32
-# ifdef HAVE_SHLWAPI_H
- return PathIsRelative(path.c_str());
-# else /* HAVE_SHLWAPI_H */
- if (path.size() >= 3) {
- return !(((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) &&
- path[1] == ':' && path[2] == DIR_SEP);
- }
- return true;
-# endif /* HAVE_SHLWAPI_H */
-#else /* _WIN32 */
- if (path.size() == 0) {
- return 1;
- }
- return path[0] != DIR_SEP;
-#endif /* _WIN32 */
-}
-
-#ifdef _WIN32
-/* Add a slash if the UNC path points to a share. */
-static string path_unc_add_slash_to_share(const string &path)
-{
- size_t slash_after_server = path.find(DIR_SEP, 2);
- if (slash_after_server != string::npos) {
- size_t slash_after_share = path.find(DIR_SEP, slash_after_server + 1);
- if (slash_after_share == string::npos) {
- return path + DIR_SEP;
- }
- }
- return path;
-}
-
-/* Convert:
- * \\?\UNC\server\share\folder\... to \\server\share\folder\...
- * \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
- */
-static string path_unc_to_short(const string &path)
-{
- size_t len = path.size();
- if ((len > 3) && (path[0] == DIR_SEP) && (path[1] == DIR_SEP) && (path[2] == '?') &&
- ((path[3] == DIR_SEP) || (path[3] == DIR_SEP_ALT))) {
- if ((len > 5) && (path[5] == ':')) {
- return path.substr(4, len - 4);
- }
- else if ((len > 7) && (path.substr(4, 3) == "UNC") &&
- ((path[7] == DIR_SEP) || (path[7] == DIR_SEP_ALT))) {
- return "\\\\" + path.substr(8, len - 8);
- }
- }
- return path;
-}
-
-static string path_cleanup_unc(const string &path)
-{
- string result = path_unc_to_short(path);
- if (path.size() > 2) {
- /* It's possible path is now a non-UNC. */
- if (result[0] == DIR_SEP && result[1] == DIR_SEP) {
- return path_unc_add_slash_to_share(result);
- }
- }
- return result;
-}
-
-/* Make path compatible for stat() functions. */
-static string path_make_compatible(const string &path)
-{
- string result = path;
- /* In Windows stat() doesn't recognize dir ending on a slash. */
- if (result.size() > 3 && result[result.size() - 1] == DIR_SEP) {
- result.resize(result.size() - 1);
- }
- /* Clean up UNC path. */
- if ((path.size() >= 3) && (path[0] == DIR_SEP) && (path[1] == DIR_SEP)) {
- result = path_cleanup_unc(result);
- }
- /* Make sure volume-only path ends up wit ha directory separator. */
- if (result.size() == 2 && result[1] == ':') {
- result += DIR_SEP;
- }
- return result;
-}
-
-static int path_wstat(const wstring &path_wc, path_stat_t *st)
-{
-# if defined(_MSC_VER) || defined(__MINGW64__)
- return _wstat64(path_wc.c_str(), st);
-# elif defined(__MINGW32__)
- return _wstati64(path_wc.c_str(), st);
-# else
- return _wstat(path_wc.c_str(), st);
-# endif
-}
-
-static int path_stat(const string &path, path_stat_t *st)
-{
- wstring path_wc = string_to_wstring(path);
- return path_wstat(path_wc, st);
-}
-#else /* _WIN32 */
-static int path_stat(const string &path, path_stat_t *st)
-{
- return stat(path.c_str(), st);
-}
-#endif /* _WIN32 */
-
-size_t path_file_size(const string &path)
-{
- path_stat_t st;
- if (path_stat(path, &st) != 0) {
- return -1;
- }
- return st.st_size;
-}
-
-bool path_exists(const string &path)
-{
-#ifdef _WIN32
- string fixed_path = path_make_compatible(path);
- wstring path_wc = string_to_wstring(fixed_path);
- path_stat_t st;
- if (path_wstat(path_wc, &st) != 0) {
- return false;
- }
- return st.st_mode != 0;
-#else /* _WIN32 */
- struct stat st;
- if (stat(path.c_str(), &st) != 0) {
- return 0;
- }
- return st.st_mode != 0;
-#endif /* _WIN32 */
-}
-
-bool path_is_directory(const string &path)
-{
- path_stat_t st;
- if (path_stat(path, &st) != 0) {
- return false;
- }
- return S_ISDIR(st.st_mode);
-}
-
-static void path_files_md5_hash_recursive(MD5Hash &hash, const string &dir)
-{
- if (path_exists(dir)) {
- directory_iterator it(dir), it_end;
-
- for (; it != it_end; ++it) {
- if (path_is_directory(it->path())) {
- path_files_md5_hash_recursive(hash, it->path());
- }
- else {
- string filepath = it->path();
-
- hash.append((const uint8_t *)filepath.c_str(), filepath.size());
- hash.append_file(filepath);
- }
- }
- }
-}
-
-string path_files_md5_hash(const string &dir)
-{
- /* computes md5 hash of all files in the directory */
- MD5Hash hash;
-
- path_files_md5_hash_recursive(hash, dir);
-
- return hash.get_hex();
-}
-
-static bool create_directories_recursivey(const string &path)
-{
- if (path_is_directory(path)) {
- /* Directory already exists, nothing to do. */
- return true;
- }
- if (path_exists(path)) {
- /* File exists and it's not a directory. */
- return false;
- }
-
- string parent = path_dirname(path);
- if (parent.size() > 0 && parent != path) {
- if (!create_directories_recursivey(parent)) {
- return false;
- }
- }
-
-#ifdef _WIN32
- wstring path_wc = string_to_wstring(path);
- return _wmkdir(path_wc.c_str()) == 0;
-#else
- return mkdir(path.c_str(), 0777) == 0;
-#endif
-}
-
-void path_create_directories(const string &filepath)
-{
- string path = path_dirname(filepath);
- create_directories_recursivey(path);
-}
-
-bool path_write_binary(const string &path, const vector<uint8_t> &binary)
-{
- path_create_directories(path);
-
- /* write binary file from memory */
- FILE *f = path_fopen(path, "wb");
-
- if (!f)
- return false;
-
- if (binary.size() > 0)
- fwrite(&binary[0], sizeof(uint8_t), binary.size(), f);
-
- fclose(f);
-
- return true;
-}
-
-bool path_write_text(const string &path, string &text)
-{
- vector<uint8_t> binary(text.length(), 0);
- std::copy(text.begin(), text.end(), binary.begin());
-
- return path_write_binary(path, binary);
-}
-
-bool path_read_binary(const string &path, vector<uint8_t> &binary)
-{
- /* read binary file into memory */
- FILE *f = path_fopen(path, "rb");
-
- if (!f) {
- binary.resize(0);
- return false;
- }
-
- binary.resize(path_file_size(path));
-
- if (binary.size() == 0) {
- fclose(f);
- return false;
- }
-
- if (fread(&binary[0], sizeof(uint8_t), binary.size(), f) != binary.size()) {
- fclose(f);
- return false;
- }
-
- fclose(f);
-
- return true;
-}
-
-bool path_read_text(const string &path, string &text)
-{
- vector<uint8_t> binary;
-
- if (!path_exists(path) || !path_read_binary(path, binary))
- return false;
-
- const char *str = (const char *)&binary[0];
- size_t size = binary.size();
- text = string(str, size);
-
- return true;
-}
-
-uint64_t path_modified_time(const string &path)
-{
- path_stat_t st;
- if (path_stat(path, &st) != 0) {
- return 0;
- }
- return st.st_mtime;
-}
-
-bool path_remove(const string &path)
-{
- return remove(path.c_str()) == 0;
-}
-
-FILE *path_fopen(const string &path, const string &mode)
-{
-#ifdef _WIN32
- wstring path_wc = string_to_wstring(path);
- wstring mode_wc = string_to_wstring(mode);
- return _wfopen(path_wc.c_str(), mode_wc.c_str());
-#else
- return fopen(path.c_str(), mode.c_str());
-#endif
-}
-
-void path_cache_clear_except(const string &name, const set<string> &except)
-{
- string dir = path_user_get("cache");
-
- if (path_exists(dir)) {
- directory_iterator it(dir), it_end;
-
- for (; it != it_end; ++it) {
- string filename = path_filename(it->path());
-
- if (string_startswith(filename, name.c_str()))
- if (except.find(filename) == except.end())
- path_remove(it->path());
- }
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_path.h b/intern/cycles/util/util_path.h
deleted file mode 100644
index f899bc2e01c..00000000000
--- a/intern/cycles/util/util_path.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_PATH_H__
-#define __UTIL_PATH_H__
-
-/* Utility functions to get paths to files distributed with the program. For
- * the standalone apps, paths are relative to the executable, for dynamically
- * linked libraries, the path to the library may be set with path_init, which
- * then makes all paths relative to that. */
-
-#include <stdio.h>
-
-#include "util/util_set.h"
-#include "util/util_string.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* program paths */
-void path_init(const string &path = "", const string &user_path = "", const string &tmp_path = "");
-string path_get(const string &sub = "");
-string path_user_get(const string &sub = "");
-string path_temp_get(const string &sub = "");
-string path_cache_get(const string &sub = "");
-
-/* path string manipulation */
-string path_filename(const string &path);
-string path_dirname(const string &path);
-string path_join(const string &dir, const string &file);
-string path_escape(const string &path);
-bool path_is_relative(const string &path);
-
-/* file info */
-size_t path_file_size(const string &path);
-bool path_exists(const string &path);
-bool path_is_directory(const string &path);
-string path_files_md5_hash(const string &dir);
-uint64_t path_modified_time(const string &path);
-
-/* directory utility */
-void path_create_directories(const string &path);
-
-/* file read/write utilities */
-FILE *path_fopen(const string &path, const string &mode);
-
-bool path_write_binary(const string &path, const vector<uint8_t> &binary);
-bool path_write_text(const string &path, string &text);
-bool path_read_binary(const string &path, vector<uint8_t> &binary);
-bool path_read_text(const string &path, string &text);
-
-/* File manipulation. */
-bool path_remove(const string &path);
-
-/* cache utility */
-void path_cache_clear_except(const string &name, const set<string> &except);
-
-CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/util/util_profiling.cpp b/intern/cycles/util/util_profiling.cpp
deleted file mode 100644
index 5343f076e22..00000000000
--- a/intern/cycles/util/util_profiling.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_profiling.h"
-#include "util/util_algorithm.h"
-#include "util/util_foreach.h"
-#include "util/util_set.h"
-
-CCL_NAMESPACE_BEGIN
-
-Profiler::Profiler() : do_stop_worker(true), worker(NULL)
-{
-}
-
-Profiler::~Profiler()
-{
- assert(worker == NULL);
-}
-
-void Profiler::run()
-{
- uint64_t updates = 0;
- auto start_time = std::chrono::system_clock::now();
- while (!do_stop_worker) {
- thread_scoped_lock lock(mutex);
- foreach (ProfilingState *state, states) {
- uint32_t cur_event = state->event;
- int32_t cur_shader = state->shader;
- int32_t cur_object = state->object;
-
- /* The state reads/writes should be atomic, but just to be sure
- * check the values for validity anyways. */
- if (cur_event < PROFILING_NUM_EVENTS) {
- event_samples[cur_event]++;
- }
-
- if (cur_shader >= 0 && cur_shader < shader_samples.size()) {
- shader_samples[cur_shader]++;
- }
-
- if (cur_object >= 0 && cur_object < object_samples.size()) {
- object_samples[cur_object]++;
- }
- }
- lock.unlock();
-
- /* Relative waits always overshoot a bit, so just waiting 1ms every
- * time would cause the sampling to drift over time.
- * By keeping track of the absolute time, the wait times correct themselves -
- * if one wait overshoots a lot, the next one will be shorter to compensate. */
- updates++;
- std::this_thread::sleep_until(start_time + updates * std::chrono::milliseconds(1));
- }
-}
-
-void Profiler::reset(int num_shaders, int num_objects)
-{
- bool running = (worker != NULL);
- if (running) {
- stop();
- }
-
- /* Resize and clear the accumulation vectors. */
- shader_hits.assign(num_shaders, 0);
- object_hits.assign(num_objects, 0);
-
- event_samples.assign(PROFILING_NUM_EVENTS, 0);
- shader_samples.assign(num_shaders, 0);
- object_samples.assign(num_objects, 0);
-
- if (running) {
- start();
- }
-}
-
-void Profiler::start()
-{
- assert(worker == NULL);
- do_stop_worker = false;
- worker = new thread(function_bind(&Profiler::run, this));
-}
-
-void Profiler::stop()
-{
- if (worker != NULL) {
- do_stop_worker = true;
-
- worker->join();
- delete worker;
- worker = NULL;
- }
-}
-
-void Profiler::add_state(ProfilingState *state)
-{
- thread_scoped_lock lock(mutex);
-
- /* Add the ProfilingState from the list of sampled states. */
- assert(std::find(states.begin(), states.end(), state) == states.end());
- states.push_back(state);
-
- /* Resize thread-local hit counters. */
- state->shader_hits.assign(shader_hits.size(), 0);
- state->object_hits.assign(object_hits.size(), 0);
-
- /* Initialize the state. */
- state->event = PROFILING_UNKNOWN;
- state->shader = -1;
- state->object = -1;
- state->active = true;
-}
-
-void Profiler::remove_state(ProfilingState *state)
-{
- thread_scoped_lock lock(mutex);
-
- /* Remove the ProfilingState from the list of sampled states. */
- states.erase(std::remove(states.begin(), states.end(), state), states.end());
- state->active = false;
-
- /* Merge thread-local hit counters. */
- assert(shader_hits.size() == state->shader_hits.size());
- for (int i = 0; i < shader_hits.size(); i++) {
- shader_hits[i] += state->shader_hits[i];
- }
-
- assert(object_hits.size() == state->object_hits.size());
- for (int i = 0; i < object_hits.size(); i++) {
- object_hits[i] += state->object_hits[i];
- }
-}
-
-uint64_t Profiler::get_event(ProfilingEvent event)
-{
- assert(worker == NULL);
- return event_samples[event];
-}
-
-bool Profiler::get_shader(int shader, uint64_t &samples, uint64_t &hits)
-{
- assert(worker == NULL);
- if (shader_samples[shader] == 0) {
- return false;
- }
- samples = shader_samples[shader];
- hits = shader_hits[shader];
- return true;
-}
-
-bool Profiler::get_object(int object, uint64_t &samples, uint64_t &hits)
-{
- assert(worker == NULL);
- if (object_samples[object] == 0) {
- return false;
- }
- samples = object_samples[object];
- hits = object_hits[object];
- return true;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_profiling.h b/intern/cycles/util/util_profiling.h
deleted file mode 100644
index 96bb682c50e..00000000000
--- a/intern/cycles/util/util_profiling.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_PROFILING_H__
-#define __UTIL_PROFILING_H__
-
-#include <atomic>
-
-#include "util/util_map.h"
-#include "util/util_thread.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-enum ProfilingEvent : uint32_t {
- PROFILING_UNKNOWN,
- PROFILING_RAY_SETUP,
-
- PROFILING_INTERSECT_CLOSEST,
- PROFILING_INTERSECT_SUBSURFACE,
- PROFILING_INTERSECT_SHADOW,
- PROFILING_INTERSECT_VOLUME_STACK,
-
- PROFILING_SHADE_SURFACE_SETUP,
- PROFILING_SHADE_SURFACE_EVAL,
- PROFILING_SHADE_SURFACE_DIRECT_LIGHT,
- PROFILING_SHADE_SURFACE_INDIRECT_LIGHT,
- PROFILING_SHADE_SURFACE_AO,
- PROFILING_SHADE_SURFACE_PASSES,
-
- PROFILING_SHADE_VOLUME_SETUP,
- PROFILING_SHADE_VOLUME_INTEGRATE,
- PROFILING_SHADE_VOLUME_DIRECT_LIGHT,
- PROFILING_SHADE_VOLUME_INDIRECT_LIGHT,
-
- PROFILING_SHADE_SHADOW_SETUP,
- PROFILING_SHADE_SHADOW_SURFACE,
- PROFILING_SHADE_SHADOW_VOLUME,
-
- PROFILING_SHADE_LIGHT_SETUP,
- PROFILING_SHADE_LIGHT_EVAL,
-
- PROFILING_NUM_EVENTS,
-};
-
-/* Contains the current execution state of a worker thread.
- * These values are constantly updated by the worker.
- * Periodically the profiler thread will wake up, read them
- * and update its internal counters based on it.
- *
- * Atomics aren't needed here since we're only doing direct
- * writes and reads to (4-byte-aligned) uint32_t, which is
- * guaranteed to be atomic on x86 since the 486.
- * Memory ordering is not guaranteed but does not matter.
- *
- * And even on other architectures, the extremely rare corner
- * case of reading an intermediate state could at worst result
- * in a single incorrect sample. */
-struct ProfilingState {
- volatile uint32_t event = PROFILING_UNKNOWN;
- volatile int32_t shader = -1;
- volatile int32_t object = -1;
- volatile bool active = false;
-
- vector<uint64_t> shader_hits;
- vector<uint64_t> object_hits;
-};
-
-class Profiler {
- public:
- Profiler();
- ~Profiler();
-
- void reset(int num_shaders, int num_objects);
-
- void start();
- void stop();
-
- void add_state(ProfilingState *state);
- void remove_state(ProfilingState *state);
-
- uint64_t get_event(ProfilingEvent event);
- bool get_shader(int shader, uint64_t &samples, uint64_t &hits);
- bool get_object(int object, uint64_t &samples, uint64_t &hits);
-
- protected:
- void run();
-
- /* Tracks how often the worker was in each ProfilingEvent while sampling,
- * so multiplying the values by the sample frequency (currently 1ms)
- * gives the approximate time spent in each state. */
- vector<uint64_t> event_samples;
- vector<uint64_t> shader_samples;
- vector<uint64_t> object_samples;
-
- /* Tracks the total amounts every object/shader was hit.
- * Used to evaluate relative cost, written by the render thread.
- * Indexed by the shader and object IDs that the kernel also uses
- * to index __object_flag and __shaders. */
- vector<uint64_t> shader_hits;
- vector<uint64_t> object_hits;
-
- volatile bool do_stop_worker;
- thread *worker;
-
- thread_mutex mutex;
- vector<ProfilingState *> states;
-};
-
-class ProfilingHelper {
- public:
- ProfilingHelper(ProfilingState *state, ProfilingEvent event) : state(state)
- {
- previous_event = state->event;
- state->event = event;
- }
-
- ~ProfilingHelper()
- {
- state->event = previous_event;
- }
-
- inline void set_event(ProfilingEvent event)
- {
- state->event = event;
- }
-
- protected:
- ProfilingState *state;
- uint32_t previous_event;
-};
-
-class ProfilingWithShaderHelper : public ProfilingHelper {
- public:
- ProfilingWithShaderHelper(ProfilingState *state, ProfilingEvent event)
- : ProfilingHelper(state, event)
- {
- }
-
- ~ProfilingWithShaderHelper()
- {
- state->object = -1;
- state->shader = -1;
- }
-
- inline void set_shader(int object, int shader)
- {
- if (state->active) {
- state->shader = shader;
- state->object = object;
-
- if (shader >= 0) {
- assert(shader < state->shader_hits.size());
- state->shader_hits[shader]++;
- }
-
- if (object >= 0) {
- assert(object < state->object_hits.size());
- state->object_hits[object]++;
- }
- }
- }
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_PROFILING_H__ */
diff --git a/intern/cycles/util/util_progress.h b/intern/cycles/util/util_progress.h
deleted file mode 100644
index 176ee11e1e9..00000000000
--- a/intern/cycles/util/util_progress.h
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_PROGRESS_H__
-#define __UTIL_PROGRESS_H__
-
-/* Progress
- *
- * Simple class to communicate progress status messages, timing information,
- * update notifications from a job running in another thread. All methods
- * except for the constructor/destructor are thread safe. */
-
-#include "util/util_function.h"
-#include "util/util_string.h"
-#include "util/util_thread.h"
-#include "util/util_time.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Progress {
- public:
- Progress()
- {
- pixel_samples = 0;
- total_pixel_samples = 0;
- current_tile_sample = 0;
- rendered_tiles = 0;
- denoised_tiles = 0;
- start_time = time_dt();
- render_start_time = time_dt();
- end_time = 0.0;
- status = "Initializing";
- substatus = "";
- sync_status = "";
- sync_substatus = "";
- update_cb = function_null;
- cancel = false;
- cancel_message = "";
- error = false;
- error_message = "";
- cancel_cb = function_null;
- }
-
- Progress(Progress &progress)
- {
- *this = progress;
- }
-
- Progress &operator=(Progress &progress)
- {
- thread_scoped_lock lock(progress.progress_mutex);
-
- progress.get_status(status, substatus);
-
- pixel_samples = progress.pixel_samples;
- total_pixel_samples = progress.total_pixel_samples;
- current_tile_sample = progress.get_current_sample();
-
- return *this;
- }
-
- void reset()
- {
- pixel_samples = 0;
- total_pixel_samples = 0;
- current_tile_sample = 0;
- rendered_tiles = 0;
- denoised_tiles = 0;
- start_time = time_dt();
- render_start_time = time_dt();
- end_time = 0.0;
- status = "Initializing";
- substatus = "";
- sync_status = "";
- sync_substatus = "";
- cancel = false;
- cancel_message = "";
- error = false;
- error_message = "";
- }
-
- /* cancel */
- void set_cancel(const string &cancel_message_)
- {
- thread_scoped_lock lock(progress_mutex);
- cancel_message = cancel_message_;
- cancel = true;
- }
-
- bool get_cancel() const
- {
- if (!cancel && cancel_cb)
- cancel_cb();
-
- return cancel;
- }
-
- string get_cancel_message() const
- {
- thread_scoped_lock lock(progress_mutex);
- return cancel_message;
- }
-
- void set_cancel_callback(function<void()> function)
- {
- cancel_cb = function;
- }
-
- /* error */
- void set_error(const string &error_message_)
- {
- thread_scoped_lock lock(progress_mutex);
- error_message = error_message_;
- error = true;
- /* If error happens we also stop rendering. */
- cancel_message = error_message_;
- cancel = true;
- }
-
- bool get_error() const
- {
- return error;
- }
-
- string get_error_message() const
- {
- thread_scoped_lock lock(progress_mutex);
- return error_message;
- }
-
- /* tile and timing information */
-
- void set_start_time()
- {
- thread_scoped_lock lock(progress_mutex);
-
- start_time = time_dt();
- end_time = 0.0;
- }
-
- void set_render_start_time()
- {
- thread_scoped_lock lock(progress_mutex);
-
- render_start_time = time_dt();
- }
-
- void add_skip_time(const scoped_timer &start_timer, bool only_render)
- {
- double skip_time = time_dt() - start_timer.get_start();
-
- render_start_time += skip_time;
- if (!only_render) {
- start_time += skip_time;
- }
- }
-
- void get_time(double &total_time_, double &render_time_) const
- {
- thread_scoped_lock lock(progress_mutex);
-
- double time = (end_time > 0) ? end_time : time_dt();
-
- total_time_ = time - start_time;
- render_time_ = time - render_start_time;
- }
-
- void set_end_time()
- {
- end_time = time_dt();
- }
-
- void reset_sample()
- {
- thread_scoped_lock lock(progress_mutex);
-
- pixel_samples = 0;
- current_tile_sample = 0;
- rendered_tiles = 0;
- denoised_tiles = 0;
- }
-
- void set_total_pixel_samples(uint64_t total_pixel_samples_)
- {
- thread_scoped_lock lock(progress_mutex);
-
- total_pixel_samples = total_pixel_samples_;
- }
-
- float get_progress() const
- {
- thread_scoped_lock lock(progress_mutex);
-
- if (total_pixel_samples > 0) {
- return ((float)pixel_samples) / total_pixel_samples;
- }
- return 0.0f;
- }
-
- void add_samples(uint64_t pixel_samples_, int tile_sample)
- {
- thread_scoped_lock lock(progress_mutex);
-
- pixel_samples += pixel_samples_;
- current_tile_sample = tile_sample;
- }
-
- void add_samples_update(uint64_t pixel_samples_, int tile_sample)
- {
- add_samples(pixel_samples_, tile_sample);
- set_update();
- }
-
- void add_finished_tile(bool denoised)
- {
- thread_scoped_lock lock(progress_mutex);
-
- if (denoised) {
- denoised_tiles++;
- }
- else {
- rendered_tiles++;
- }
- }
-
- int get_current_sample() const
- {
- thread_scoped_lock lock(progress_mutex);
- /* Note that the value here always belongs to the last tile that updated,
- * so it's only useful if there is only one active tile. */
- return current_tile_sample;
- }
-
- int get_rendered_tiles() const
- {
- thread_scoped_lock lock(progress_mutex);
- return rendered_tiles;
- }
-
- int get_denoised_tiles() const
- {
- thread_scoped_lock lock(progress_mutex);
- return denoised_tiles;
- }
-
- /* status messages */
-
- void set_status(const string &status_, const string &substatus_ = "")
- {
- {
- thread_scoped_lock lock(progress_mutex);
- status = status_;
- substatus = substatus_;
- }
-
- set_update();
- }
-
- void set_substatus(const string &substatus_)
- {
- {
- thread_scoped_lock lock(progress_mutex);
- substatus = substatus_;
- }
-
- set_update();
- }
-
- void set_sync_status(const string &status_, const string &substatus_ = "")
- {
- {
- thread_scoped_lock lock(progress_mutex);
- sync_status = status_;
- sync_substatus = substatus_;
- }
-
- set_update();
- }
-
- void set_sync_substatus(const string &substatus_)
- {
- {
- thread_scoped_lock lock(progress_mutex);
- sync_substatus = substatus_;
- }
-
- set_update();
- }
-
- void get_status(string &status_, string &substatus_) const
- {
- thread_scoped_lock lock(progress_mutex);
-
- if (sync_status != "") {
- status_ = sync_status;
- substatus_ = sync_substatus;
- }
- else {
- status_ = status;
- substatus_ = substatus;
- }
- }
-
- /* callback */
-
- void set_update()
- {
- if (update_cb) {
- thread_scoped_lock lock(update_mutex);
- update_cb();
- }
- }
-
- void set_update_callback(function<void()> function)
- {
- update_cb = function;
- }
-
- protected:
- mutable thread_mutex progress_mutex;
- mutable thread_mutex update_mutex;
- function<void()> update_cb;
- function<void()> cancel_cb;
-
- /* pixel_samples counts how many samples have been rendered over all pixel, not just per pixel.
- * This makes the progress estimate more accurate when tiles with different sizes are used.
- *
- * total_pixel_samples is the total amount of pixel samples that will be rendered. */
- uint64_t pixel_samples, total_pixel_samples;
- /* Stores the current sample count of the last tile that called the update function.
- * It's used to display the sample count if only one tile is active. */
- int current_tile_sample;
- /* Stores the number of tiles that's already finished.
- * Used to determine whether all but the last tile are finished rendering,
- * in which case the current_tile_sample is displayed. */
- int rendered_tiles, denoised_tiles;
-
- double start_time, render_start_time;
- /* End time written when render is done, so it doesn't keep increasing on redraws. */
- double end_time;
-
- string status;
- string substatus;
-
- string sync_status;
- string sync_substatus;
-
- volatile bool cancel;
- string cancel_message;
-
- volatile bool error;
- string error_message;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_PROGRESS_H__ */
diff --git a/intern/cycles/util/util_projection.h b/intern/cycles/util/util_projection.h
deleted file mode 100644
index 04b4574d75b..00000000000
--- a/intern/cycles/util/util_projection.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_PROJECTION_H__
-#define __UTIL_PROJECTION_H__
-
-#include "util/util_transform.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* 4x4 projection matrix, perspective or orthographic. */
-
-typedef struct ProjectionTransform {
- float4 x, y, z, w; /* rows */
-
-#ifndef __KERNEL_GPU__
- ProjectionTransform()
- {
- }
-
- explicit ProjectionTransform(const Transform &tfm)
- : x(tfm.x), y(tfm.y), z(tfm.z), w(make_float4(0.0f, 0.0f, 0.0f, 1.0f))
- {
- }
-#endif
-} ProjectionTransform;
-
-typedef struct PerspectiveMotionTransform {
- ProjectionTransform pre;
- ProjectionTransform post;
-} PerspectiveMotionTransform;
-
-/* Functions */
-
-ccl_device_inline float3 transform_perspective(ccl_private const ProjectionTransform *t,
- const float3 a)
-{
- float4 b = make_float4(a.x, a.y, a.z, 1.0f);
- float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
- float w = dot(t->w, b);
-
- return (w != 0.0f) ? c / w : zero_float3();
-}
-
-ccl_device_inline float3 transform_perspective_direction(ccl_private const ProjectionTransform *t,
- const float3 a)
-{
- float3 c = make_float3(a.x * t->x.x + a.y * t->x.y + a.z * t->x.z,
- a.x * t->y.x + a.y * t->y.y + a.z * t->y.z,
- a.x * t->z.x + a.y * t->z.y + a.z * t->z.z);
-
- return c;
-}
-
-#ifndef __KERNEL_GPU__
-
-ccl_device_inline Transform projection_to_transform(const ProjectionTransform &a)
-{
- Transform tfm = {a.x, a.y, a.z};
- return tfm;
-}
-
-ccl_device_inline ProjectionTransform projection_transpose(const ProjectionTransform &a)
-{
- ProjectionTransform t;
-
- t.x.x = a.x.x;
- t.x.y = a.y.x;
- t.x.z = a.z.x;
- t.x.w = a.w.x;
- t.y.x = a.x.y;
- t.y.y = a.y.y;
- t.y.z = a.z.y;
- t.y.w = a.w.y;
- t.z.x = a.x.z;
- t.z.y = a.y.z;
- t.z.z = a.z.z;
- t.z.w = a.w.z;
- t.w.x = a.x.w;
- t.w.y = a.y.w;
- t.w.z = a.z.w;
- t.w.w = a.w.w;
-
- return t;
-}
-
-ProjectionTransform projection_inverse(const ProjectionTransform &a);
-
-ccl_device_inline ProjectionTransform make_projection(float a,
- float b,
- float c,
- float d,
- float e,
- float f,
- float g,
- float h,
- float i,
- float j,
- float k,
- float l,
- float m,
- float n,
- float o,
- float p)
-{
- ProjectionTransform t;
-
- t.x.x = a;
- t.x.y = b;
- t.x.z = c;
- t.x.w = d;
- t.y.x = e;
- t.y.y = f;
- t.y.z = g;
- t.y.w = h;
- t.z.x = i;
- t.z.y = j;
- t.z.z = k;
- t.z.w = l;
- t.w.x = m;
- t.w.y = n;
- t.w.z = o;
- t.w.w = p;
-
- return t;
-}
-ccl_device_inline ProjectionTransform projection_identity()
-{
- return make_projection(1.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f);
-}
-
-ccl_device_inline ProjectionTransform operator*(const ProjectionTransform &a,
- const ProjectionTransform &b)
-{
- ProjectionTransform c = projection_transpose(b);
- ProjectionTransform t;
-
- t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
- t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
- t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
- t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
-
- return t;
-}
-
-ccl_device_inline ProjectionTransform operator*(const ProjectionTransform &a, const Transform &b)
-{
- return a * ProjectionTransform(b);
-}
-
-ccl_device_inline ProjectionTransform operator*(const Transform &a, const ProjectionTransform &b)
-{
- return ProjectionTransform(a) * b;
-}
-
-ccl_device_inline void print_projection(const char *label, const ProjectionTransform &t)
-{
- print_float4(label, t.x);
- print_float4(label, t.y);
- print_float4(label, t.z);
- print_float4(label, t.w);
- printf("\n");
-}
-
-ccl_device_inline ProjectionTransform projection_perspective(float fov, float n, float f)
-{
- ProjectionTransform persp = make_projection(
- 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, f / (f - n), -f * n / (f - n), 0, 0, 1, 0);
-
- float inv_angle = 1.0f / tanf(0.5f * fov);
-
- Transform scale = transform_scale(inv_angle, inv_angle, 1);
-
- return scale * persp;
-}
-
-ccl_device_inline ProjectionTransform projection_orthographic(float znear, float zfar)
-{
- Transform t = transform_scale(1.0f, 1.0f, 1.0f / (zfar - znear)) *
- transform_translate(0.0f, 0.0f, -znear);
-
- return ProjectionTransform(t);
-}
-
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_PROJECTION_H__ */
diff --git a/intern/cycles/util/util_rect.h b/intern/cycles/util/util_rect.h
deleted file mode 100644
index 32df9327cbd..00000000000
--- a/intern/cycles/util/util_rect.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_RECT_H__
-#define __UTIL_RECT_H__
-
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Rectangles are represented as a int4 containing the coordinates of the lower-left and
- * upper-right corners in the order (x0, y0, x1, y1). */
-
-ccl_device_inline int4 rect_from_shape(int x0, int y0, int w, int h)
-{
- return make_int4(x0, y0, x0 + w, y0 + h);
-}
-
-ccl_device_inline int4 rect_expand(int4 rect, int d)
-{
- return make_int4(rect.x - d, rect.y - d, rect.z + d, rect.w + d);
-}
-
-/* Returns the intersection of two rects. */
-ccl_device_inline int4 rect_clip(int4 a, int4 b)
-{
- return make_int4(max(a.x, b.x), max(a.y, b.y), min(a.z, b.z), min(a.w, b.w));
-}
-
-ccl_device_inline bool rect_is_valid(int4 rect)
-{
- return (rect.z > rect.x) && (rect.w > rect.y);
-}
-
-/* Returns the local row-major index of the pixel inside the rect. */
-ccl_device_inline int coord_to_local_index(int4 rect, int x, int y)
-{
- int w = rect.z - rect.x;
- return (y - rect.y) * w + (x - rect.x);
-}
-
-/* Finds the coordinates of a pixel given by its row-major index in the rect,
- * and returns whether the pixel is inside it. */
-ccl_device_inline bool local_index_to_coord(int4 rect,
- int idx,
- ccl_private int *x,
- ccl_private int *y)
-{
- int w = rect.z - rect.x;
- *x = (idx % w) + rect.x;
- *y = (idx / w) + rect.y;
- return (*y < rect.w);
-}
-
-ccl_device_inline int rect_size(int4 rect)
-{
- return (rect.z - rect.x) * (rect.w - rect.y);
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_RECT_H__ */
diff --git a/intern/cycles/util/util_semaphore.h b/intern/cycles/util/util_semaphore.h
deleted file mode 100644
index d995b0732b8..00000000000
--- a/intern/cycles/util/util_semaphore.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_SEMAPHORE_H__
-#define __UTIL_SEMAPHORE_H__
-
-#include "util/util_thread.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Counting Semaphore
- *
- * To restrict concurrent access to a resource to a specified number
- * of threads. Similar to std::counting_semaphore from C++20. */
-
-class thread_counting_semaphore {
- public:
- explicit thread_counting_semaphore(const int count) : count(count)
- {
- }
-
- thread_counting_semaphore(const thread_counting_semaphore &) = delete;
-
- void acquire()
- {
- thread_scoped_lock lock(mutex);
- while (count == 0) {
- condition.wait(lock);
- }
- count--;
- }
-
- void release()
- {
- thread_scoped_lock lock(mutex);
- count++;
- condition.notify_one();
- }
-
- protected:
- thread_mutex mutex;
- thread_condition_variable condition;
- int count;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_SEMAPHORE_H__ */
diff --git a/intern/cycles/util/util_simd.cpp b/intern/cycles/util/util_simd.cpp
deleted file mode 100644
index 861dcf1fe36..00000000000
--- a/intern/cycles/util/util_simd.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2011-2013 Intel Corporation
- * Modifications Copyright 2014, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#if (defined(WITH_KERNEL_SSE2)) || (defined(WITH_KERNEL_NATIVE) && defined(__SSE2__))
-
-# define __KERNEL_SSE2__
-# include "util/util_simd.h"
-
-CCL_NAMESPACE_BEGIN
-
-const __m128 _mm_lookupmask_ps[16] = {_mm_castsi128_ps(_mm_set_epi32(0, 0, 0, 0)),
- _mm_castsi128_ps(_mm_set_epi32(0, 0, 0, -1)),
- _mm_castsi128_ps(_mm_set_epi32(0, 0, -1, 0)),
- _mm_castsi128_ps(_mm_set_epi32(0, 0, -1, -1)),
- _mm_castsi128_ps(_mm_set_epi32(0, -1, 0, 0)),
- _mm_castsi128_ps(_mm_set_epi32(0, -1, 0, -1)),
- _mm_castsi128_ps(_mm_set_epi32(0, -1, -1, 0)),
- _mm_castsi128_ps(_mm_set_epi32(0, -1, -1, -1)),
- _mm_castsi128_ps(_mm_set_epi32(-1, 0, 0, 0)),
- _mm_castsi128_ps(_mm_set_epi32(-1, 0, 0, -1)),
- _mm_castsi128_ps(_mm_set_epi32(-1, 0, -1, 0)),
- _mm_castsi128_ps(_mm_set_epi32(-1, 0, -1, -1)),
- _mm_castsi128_ps(_mm_set_epi32(-1, -1, 0, 0)),
- _mm_castsi128_ps(_mm_set_epi32(-1, -1, 0, -1)),
- _mm_castsi128_ps(_mm_set_epi32(-1, -1, -1, 0)),
- _mm_castsi128_ps(_mm_set_epi32(-1, -1, -1, -1))};
-
-CCL_NAMESPACE_END
-
-#endif // WITH_KERNEL_SSE2
diff --git a/intern/cycles/util/util_simd.h b/intern/cycles/util/util_simd.h
deleted file mode 100644
index b4a153c329f..00000000000
--- a/intern/cycles/util/util_simd.h
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * Copyright 2011-2013 Intel Corporation
- * Modifications Copyright 2014, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0(the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_SIMD_TYPES_H__
-#define __UTIL_SIMD_TYPES_H__
-
-#include <limits>
-#include <stdint.h>
-
-#include "util/util_defines.h"
-
-/* SSE Intrinsics includes
- *
- * We assume __KERNEL_SSEX__ flags to have been defined at this point.
- *
- * MinGW64 has conflicting declarations for these SSE headers in <windows.h>.
- * Since we can't avoid including <windows.h>, better only include that */
-#if defined(FREE_WINDOWS64)
-# include "util/util_windows.h"
-#elif defined(_MSC_VER)
-# include <intrin.h>
-#elif (defined(__x86_64__) || defined(__i386__))
-# include <x86intrin.h>
-#elif defined(__KERNEL_NEON__)
-# define SSE2NEON_PRECISE_MINMAX 1
-# include <sse2neon.h>
-#endif
-
-/* Floating Point Control, for Embree. */
-#if defined(__x86_64__) || defined(_M_X64)
-# define SIMD_SET_FLUSH_TO_ZERO \
- _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); \
- _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
-#else
-# define SIMD_SET_FLUSH_TO_ZERO
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/* Data structures used by SSE classes. */
-#ifdef __KERNEL_SSE2__
-
-extern const __m128 _mm_lookupmask_ps[16];
-
-static struct TrueTy {
- __forceinline operator bool() const
- {
- return true;
- }
-} True ccl_attr_maybe_unused;
-
-static struct FalseTy {
- __forceinline operator bool() const
- {
- return false;
- }
-} False ccl_attr_maybe_unused;
-
-static struct ZeroTy {
- __forceinline operator float() const
- {
- return 0;
- }
- __forceinline operator int() const
- {
- return 0;
- }
-} zero ccl_attr_maybe_unused;
-
-static struct OneTy {
- __forceinline operator float() const
- {
- return 1;
- }
- __forceinline operator int() const
- {
- return 1;
- }
-} one ccl_attr_maybe_unused;
-
-static struct NegInfTy {
- __forceinline operator float() const
- {
- return -std::numeric_limits<float>::infinity();
- }
- __forceinline operator int() const
- {
- return std::numeric_limits<int>::min();
- }
-} neg_inf ccl_attr_maybe_unused;
-
-static struct PosInfTy {
- __forceinline operator float() const
- {
- return std::numeric_limits<float>::infinity();
- }
- __forceinline operator int() const
- {
- return std::numeric_limits<int>::max();
- }
-} inf ccl_attr_maybe_unused, pos_inf ccl_attr_maybe_unused;
-
-static struct StepTy {
-} step ccl_attr_maybe_unused;
-
-#endif
-
-/* Utilities used by Neon */
-#if defined(__KERNEL_NEON__)
-template<class type, int i0, int i1, int i2, int i3> type shuffle_neon(const type &a)
-{
- if (i0 == i1 && i0 == i2 && i0 == i3) {
- return type(vdupq_laneq_s32(int32x4_t(a), i0));
- }
- static const uint8_t tbl[16] = {(i0 * 4) + 0,
- (i0 * 4) + 1,
- (i0 * 4) + 2,
- (i0 * 4) + 3,
- (i1 * 4) + 0,
- (i1 * 4) + 1,
- (i1 * 4) + 2,
- (i1 * 4) + 3,
- (i2 * 4) + 0,
- (i2 * 4) + 1,
- (i2 * 4) + 2,
- (i2 * 4) + 3,
- (i3 * 4) + 0,
- (i3 * 4) + 1,
- (i3 * 4) + 2,
- (i3 * 4) + 3};
-
- return type(vqtbl1q_s8(int8x16_t(a), *(uint8x16_t *)tbl));
-}
-
-template<class type, int i0, int i1, int i2, int i3>
-type shuffle_neon(const type &a, const type &b)
-{
- if (&a == &b) {
- static const uint8_t tbl[16] = {(i0 * 4) + 0,
- (i0 * 4) + 1,
- (i0 * 4) + 2,
- (i0 * 4) + 3,
- (i1 * 4) + 0,
- (i1 * 4) + 1,
- (i1 * 4) + 2,
- (i1 * 4) + 3,
- (i2 * 4) + 0,
- (i2 * 4) + 1,
- (i2 * 4) + 2,
- (i2 * 4) + 3,
- (i3 * 4) + 0,
- (i3 * 4) + 1,
- (i3 * 4) + 2,
- (i3 * 4) + 3};
-
- return type(vqtbl1q_s8(int8x16_t(b), *(uint8x16_t *)tbl));
- }
- else {
-
- static const uint8_t tbl[16] = {(i0 * 4) + 0,
- (i0 * 4) + 1,
- (i0 * 4) + 2,
- (i0 * 4) + 3,
- (i1 * 4) + 0,
- (i1 * 4) + 1,
- (i1 * 4) + 2,
- (i1 * 4) + 3,
- (i2 * 4) + 0 + 16,
- (i2 * 4) + 1 + 16,
- (i2 * 4) + 2 + 16,
- (i2 * 4) + 3 + 16,
- (i3 * 4) + 0 + 16,
- (i3 * 4) + 1 + 16,
- (i3 * 4) + 2 + 16,
- (i3 * 4) + 3 + 16};
-
- return type(vqtbl2q_s8((int8x16x2_t){int8x16_t(a), int8x16_t(b)}, *(uint8x16_t *)tbl));
- }
-}
-#endif /* __KERNEL_NEON */
-
-/* Intrinsics Functions
- *
- * For fast bit operations. */
-
-#if defined(__BMI__) && defined(__GNUC__)
-# ifndef _tzcnt_u32
-# define _tzcnt_u32 __tzcnt_u32
-# endif
-# ifndef _tzcnt_u64
-# define _tzcnt_u64 __tzcnt_u64
-# endif
-#endif
-
-#if defined(__LZCNT__)
-# define _lzcnt_u32 __lzcnt32
-# define _lzcnt_u64 __lzcnt64
-#endif
-
-#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__clang__)
-/* Intrinsic functions on Windows. */
-__forceinline uint32_t __bsf(uint32_t v)
-{
-# if defined(__KERNEL_AVX2__)
- return _tzcnt_u32(v);
-# else
- unsigned long r = 0;
- _BitScanForward(&r, v);
- return r;
-# endif
-}
-
-__forceinline uint32_t __bsr(uint32_t v)
-{
- unsigned long r = 0;
- _BitScanReverse(&r, v);
- return r;
-}
-
-__forceinline uint32_t __btc(uint32_t v, uint32_t i)
-{
- long r = v;
- _bittestandcomplement(&r, i);
- return r;
-}
-
-__forceinline uint32_t bitscan(uint32_t v)
-{
-# if defined(__KERNEL_AVX2__)
- return _tzcnt_u32(v);
-# else
- return __bsf(v);
-# endif
-}
-
-# if defined(__KERNEL_64_BIT__)
-
-__forceinline uint64_t __bsf(uint64_t v)
-{
-# if defined(__KERNEL_AVX2__)
- return _tzcnt_u64(v);
-# else
- unsigned long r = 0;
- _BitScanForward64(&r, v);
- return r;
-# endif
-}
-
-__forceinline uint64_t __bsr(uint64_t v)
-{
- unsigned long r = 0;
- _BitScanReverse64(&r, v);
- return r;
-}
-
-__forceinline uint64_t __btc(uint64_t v, uint64_t i)
-{
- uint64_t r = v;
- _bittestandcomplement64((__int64 *)&r, i);
- return r;
-}
-
-__forceinline uint64_t bitscan(uint64_t v)
-{
-# if defined(__KERNEL_AVX2__)
-# if defined(__KERNEL_64_BIT__)
- return _tzcnt_u64(v);
-# else
- return _tzcnt_u32(v);
-# endif
-# else
- return __bsf(v);
-# endif
-}
-
-# endif /* __KERNEL_64_BIT__ */
-
-#elif (defined(__x86_64__) || defined(__i386__)) && defined(__KERNEL_SSE2__)
-/* Intrinsic functions with x86 SSE. */
-
-__forceinline uint32_t __bsf(const uint32_t v)
-{
- uint32_t r = 0;
- asm("bsf %1,%0" : "=r"(r) : "r"(v));
- return r;
-}
-
-__forceinline uint32_t __bsr(const uint32_t v)
-{
- uint32_t r = 0;
- asm("bsr %1,%0" : "=r"(r) : "r"(v));
- return r;
-}
-
-__forceinline uint32_t __btc(const uint32_t v, uint32_t i)
-{
- uint32_t r = 0;
- asm("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags");
- return r;
-}
-
-# if (defined(__KERNEL_64_BIT__) || defined(__APPLE__)) && \
- !(defined(__ILP32__) && defined(__x86_64__))
-__forceinline uint64_t __bsf(const uint64_t v)
-{
- uint64_t r = 0;
- asm("bsf %1,%0" : "=r"(r) : "r"(v));
- return r;
-}
-# endif
-
-__forceinline uint64_t __bsr(const uint64_t v)
-{
- uint64_t r = 0;
- asm("bsr %1,%0" : "=r"(r) : "r"(v));
- return r;
-}
-
-__forceinline uint64_t __btc(const uint64_t v, const uint64_t i)
-{
- uint64_t r = 0;
- asm("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags");
- return r;
-}
-
-__forceinline uint32_t bitscan(uint32_t v)
-{
-# if defined(__KERNEL_AVX2__)
- return _tzcnt_u32(v);
-# else
- return __bsf(v);
-# endif
-}
-
-# if (defined(__KERNEL_64_BIT__) || defined(__APPLE__)) && \
- !(defined(__ILP32__) && defined(__x86_64__))
-__forceinline uint64_t bitscan(uint64_t v)
-{
-# if defined(__KERNEL_AVX2__)
-# if defined(__KERNEL_64_BIT__)
- return _tzcnt_u64(v);
-# else
- return _tzcnt_u32(v);
-# endif
-# else
- return __bsf(v);
-# endif
-}
-# endif
-
-#else
-/* Intrinsic functions fallback for arbitrary processor. */
-__forceinline uint32_t __bsf(const uint32_t x)
-{
- for (int i = 0; i < 32; i++) {
- if (x & (1U << i))
- return i;
- }
- return 32;
-}
-
-__forceinline uint32_t __bsr(const uint32_t x)
-{
- for (int i = 0; i < 32; i++) {
- if (x & (1U << (31 - i)))
- return (31 - i);
- }
- return 32;
-}
-
-__forceinline uint32_t __btc(const uint32_t x, const uint32_t bit)
-{
- uint32_t mask = 1U << bit;
- return x & (~mask);
-}
-
-__forceinline uint32_t __bsf(const uint64_t x)
-{
- for (int i = 0; i < 64; i++) {
- if (x & (1UL << i))
- return i;
- }
- return 64;
-}
-
-__forceinline uint32_t __bsr(const uint64_t x)
-{
- for (int i = 0; i < 64; i++) {
- if (x & (1UL << (63 - i)))
- return (63 - i);
- }
- return 64;
-}
-
-__forceinline uint64_t __btc(const uint64_t x, const uint32_t bit)
-{
- uint64_t mask = 1UL << bit;
- return x & (~mask);
-}
-
-__forceinline uint32_t bitscan(uint32_t value)
-{
- assert(value != 0);
- uint32_t bit = 0;
- while ((value & (1 << bit)) == 0) {
- ++bit;
- }
- return bit;
-}
-
-__forceinline uint64_t bitscan(uint64_t value)
-{
- assert(value != 0);
- uint64_t bit = 0;
- while ((value & (1 << bit)) == 0) {
- ++bit;
- }
- return bit;
-}
-
-#endif /* Intrinsics */
-
-/* SSE compatibility.
- *
- * Various utilities to smooth over differences between SSE versions and
- * implementations. */
-#ifdef __KERNEL_SSE2__
-
-/* Test __KERNEL_SSE41__ for MSVC which does not define __SSE4_1__, and test
- * __SSE4_1__ to avoid OpenImageIO conflicts with our emulation macros on other
- * platforms when compiling code outside the kernel. */
-# if !(defined(__KERNEL_SSE41__) || defined(__SSE4_1__) || defined(__SSE4_2__))
-
-/* Emulation of SSE4 functions with SSE2 */
-
-# define _MM_FROUND_TO_NEAREST_INT 0x00
-# define _MM_FROUND_TO_NEG_INF 0x01
-# define _MM_FROUND_TO_POS_INF 0x02
-# define _MM_FROUND_TO_ZERO 0x03
-# define _MM_FROUND_CUR_DIRECTION 0x04
-
-# undef _mm_blendv_ps
-# define _mm_blendv_ps _mm_blendv_ps_emu
-__forceinline __m128 _mm_blendv_ps_emu(__m128 value, __m128 input, __m128 mask)
-{
- __m128i isignmask = _mm_set1_epi32(0x80000000);
- __m128 signmask = _mm_castsi128_ps(isignmask);
- __m128i iandsign = _mm_castps_si128(_mm_and_ps(mask, signmask));
- __m128i icmpmask = _mm_cmpeq_epi32(iandsign, isignmask);
- __m128 cmpmask = _mm_castsi128_ps(icmpmask);
- return _mm_or_ps(_mm_and_ps(cmpmask, input), _mm_andnot_ps(cmpmask, value));
-}
-
-# undef _mm_blend_ps
-# define _mm_blend_ps _mm_blend_ps_emu
-__forceinline __m128 _mm_blend_ps_emu(__m128 value, __m128 input, const int mask)
-{
- assert(mask < 0x10);
- return _mm_blendv_ps(value, input, _mm_lookupmask_ps[mask]);
-}
-
-# undef _mm_blendv_epi8
-# define _mm_blendv_epi8 _mm_blendv_epi8_emu
-__forceinline __m128i _mm_blendv_epi8_emu(__m128i value, __m128i input, __m128i mask)
-{
- return _mm_or_si128(_mm_and_si128(mask, input), _mm_andnot_si128(mask, value));
-}
-
-# undef _mm_min_epi32
-# define _mm_min_epi32 _mm_min_epi32_emu
-__forceinline __m128i _mm_min_epi32_emu(__m128i value, __m128i input)
-{
- return _mm_blendv_epi8(input, value, _mm_cmplt_epi32(value, input));
-}
-
-# undef _mm_max_epi32
-# define _mm_max_epi32 _mm_max_epi32_emu
-__forceinline __m128i _mm_max_epi32_emu(__m128i value, __m128i input)
-{
- return _mm_blendv_epi8(value, input, _mm_cmplt_epi32(value, input));
-}
-
-# ifndef __KERNEL_NEON__
-# undef _mm_extract_epi32
-# define _mm_extract_epi32 _mm_extract_epi32_emu
-__forceinline int _mm_extract_epi32_emu(__m128i input, const int index)
-{
- switch (index) {
- case 0:
- return _mm_cvtsi128_si32(input);
- case 1:
- return _mm_cvtsi128_si32(_mm_shuffle_epi32(input, _MM_SHUFFLE(1, 1, 1, 1)));
- case 2:
- return _mm_cvtsi128_si32(_mm_shuffle_epi32(input, _MM_SHUFFLE(2, 2, 2, 2)));
- case 3:
- return _mm_cvtsi128_si32(_mm_shuffle_epi32(input, _MM_SHUFFLE(3, 3, 3, 3)));
- default:
- assert(false);
- return 0;
- }
-}
-# endif
-
-# undef _mm_insert_epi32
-# define _mm_insert_epi32 _mm_insert_epi32_emu
-__forceinline __m128i _mm_insert_epi32_emu(__m128i value, int input, const int index)
-{
- assert(index >= 0 && index < 4);
- ((int *)&value)[index] = input;
- return value;
-}
-
-# undef _mm_insert_ps
-# define _mm_insert_ps _mm_insert_ps_emu
-__forceinline __m128 _mm_insert_ps_emu(__m128 value, __m128 input, const int index)
-{
- assert(index < 0x100);
- ((float *)&value)[(index >> 4) & 0x3] = ((float *)&input)[index >> 6];
- return _mm_andnot_ps(_mm_lookupmask_ps[index & 0xf], value);
-}
-
-# undef _mm_round_ps
-# define _mm_round_ps _mm_round_ps_emu
-__forceinline __m128 _mm_round_ps_emu(__m128 value, const int flags)
-{
- switch (flags) {
- case _MM_FROUND_TO_NEAREST_INT:
- return _mm_cvtepi32_ps(_mm_cvtps_epi32(value));
- case _MM_FROUND_TO_NEG_INF:
- return _mm_cvtepi32_ps(_mm_cvtps_epi32(_mm_add_ps(value, _mm_set1_ps(-0.5f))));
- case _MM_FROUND_TO_POS_INF:
- return _mm_cvtepi32_ps(_mm_cvtps_epi32(_mm_add_ps(value, _mm_set1_ps(0.5f))));
- case _MM_FROUND_TO_ZERO:
- return _mm_cvtepi32_ps(_mm_cvttps_epi32(value));
- }
- return value;
-}
-
-# endif /* !(defined(__KERNEL_SSE41__) || defined(__SSE4_1__) || defined(__SSE4_2__)) */
-
-/* Older GCC versions do not have _mm256_cvtss_f32 yet, so define it ourselves.
- * _mm256_castps256_ps128 generates no instructions so this is just as efficient. */
-# if defined(__KERNEL_AVX__) || defined(__KERNEL_AVX2__)
-# undef _mm256_cvtss_f32
-# define _mm256_cvtss_f32(a) (_mm_cvtss_f32(_mm256_castps256_ps128(a)))
-# endif
-
-#endif /* __KERNEL_SSE2__ */
-
-/* quiet unused define warnings */
-#if defined(__KERNEL_SSE2__) || defined(__KERNEL_SSE3__) || defined(__KERNEL_SSSE3__) || \
- defined(__KERNEL_SSE41__) || defined(__KERNEL_AVX__) || defined(__KERNEL_AVX2__)
-/* do nothing */
-#endif
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_SIMD_TYPES_H__ */
diff --git a/intern/cycles/util/util_ssef.h b/intern/cycles/util/util_ssef.h
deleted file mode 100644
index 0c81ed87553..00000000000
--- a/intern/cycles/util/util_ssef.h
+++ /dev/null
@@ -1,1104 +0,0 @@
-/*
- * Copyright 2011-2013 Intel Corporation
- * Modifications Copyright 2014, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0(the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_SSEF_H__
-#define __UTIL_SSEF_H__
-
-#include "util_ssei.h"
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef __KERNEL_SSE2__
-
-struct sseb;
-struct ssef;
-
-/*! 4-wide SSE float type. */
-struct ssef {
- typedef sseb Mask; // mask type
- typedef ssei Int; // int type
- typedef ssef Float; // float type
-
- enum { size = 4 }; // number of SIMD elements
- union {
- __m128 m128;
- float f[4];
- int i[4];
- }; // data
-
- ////////////////////////////////////////////////////////////////////////////////
- /// Constructors, Assignment & Cast Operators
- ////////////////////////////////////////////////////////////////////////////////
-
- __forceinline ssef()
- {
- }
- __forceinline ssef(const ssef &other)
- {
- m128 = other.m128;
- }
- __forceinline ssef &operator=(const ssef &other)
- {
- m128 = other.m128;
- return *this;
- }
-
- __forceinline ssef(const __m128 a) : m128(a)
- {
- }
- __forceinline operator const __m128 &() const
- {
- return m128;
- }
- __forceinline operator __m128 &()
- {
- return m128;
- }
-
- __forceinline ssef(float a) : m128(_mm_set1_ps(a))
- {
- }
- __forceinline ssef(float a, float b, float c, float d) : m128(_mm_setr_ps(a, b, c, d))
- {
- }
-
- __forceinline explicit ssef(const __m128i a) : m128(_mm_cvtepi32_ps(a))
- {
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- /// Loads and Stores
- ////////////////////////////////////////////////////////////////////////////////
-
-# if defined(__KERNEL_AVX__)
- static __forceinline ssef broadcast(const void *const a)
- {
- return _mm_broadcast_ss((float *)a);
- }
-# else
- static __forceinline ssef broadcast(const void *const a)
- {
- return _mm_set1_ps(*(float *)a);
- }
-# endif
-
- ////////////////////////////////////////////////////////////////////////////////
- /// Array Access
- ////////////////////////////////////////////////////////////////////////////////
-
- __forceinline const float &operator[](const size_t i) const
- {
- assert(i < 4);
- return f[i];
- }
- __forceinline float &operator[](const size_t i)
- {
- assert(i < 4);
- return f[i];
- }
-};
-
-////////////////////////////////////////////////////////////////////////////////
-/// Unary Operators
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline const ssef cast(const __m128i &a)
-{
- return _mm_castsi128_ps(a);
-}
-__forceinline const ssef operator+(const ssef &a)
-{
- return a;
-}
-__forceinline const ssef operator-(const ssef &a)
-{
- return _mm_xor_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000)));
-}
-__forceinline const ssef abs(const ssef &a)
-{
- return _mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)));
-}
-# if defined(__KERNEL_SSE41__)
-__forceinline const ssef sign(const ssef &a)
-{
- return _mm_blendv_ps(ssef(1.0f), -ssef(1.0f), _mm_cmplt_ps(a, ssef(0.0f)));
-}
-# endif
-__forceinline const ssef signmsk(const ssef &a)
-{
- return _mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000)));
-}
-
-__forceinline const ssef rcp(const ssef &a)
-{
- const ssef r = _mm_rcp_ps(a.m128);
- return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
-}
-__forceinline const ssef sqr(const ssef &a)
-{
- return _mm_mul_ps(a, a);
-}
-__forceinline const ssef mm_sqrt(const ssef &a)
-{
- return _mm_sqrt_ps(a.m128);
-}
-__forceinline const ssef rsqrt(const ssef &a)
-{
- const ssef r = _mm_rsqrt_ps(a.m128);
- return _mm_add_ps(
- _mm_mul_ps(_mm_set_ps(1.5f, 1.5f, 1.5f, 1.5f), r),
- _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set_ps(-0.5f, -0.5f, -0.5f, -0.5f)), r),
- _mm_mul_ps(r, r)));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Binary Operators
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline const ssef operator+(const ssef &a, const ssef &b)
-{
- return _mm_add_ps(a.m128, b.m128);
-}
-__forceinline const ssef operator+(const ssef &a, const float &b)
-{
- return a + ssef(b);
-}
-__forceinline const ssef operator+(const float &a, const ssef &b)
-{
- return ssef(a) + b;
-}
-
-__forceinline const ssef operator-(const ssef &a, const ssef &b)
-{
- return _mm_sub_ps(a.m128, b.m128);
-}
-__forceinline const ssef operator-(const ssef &a, const float &b)
-{
- return a - ssef(b);
-}
-__forceinline const ssef operator-(const float &a, const ssef &b)
-{
- return ssef(a) - b;
-}
-
-__forceinline const ssef operator*(const ssef &a, const ssef &b)
-{
- return _mm_mul_ps(a.m128, b.m128);
-}
-__forceinline const ssef operator*(const ssef &a, const float &b)
-{
- return a * ssef(b);
-}
-__forceinline const ssef operator*(const float &a, const ssef &b)
-{
- return ssef(a) * b;
-}
-
-__forceinline const ssef operator/(const ssef &a, const ssef &b)
-{
- return _mm_div_ps(a.m128, b.m128);
-}
-__forceinline const ssef operator/(const ssef &a, const float &b)
-{
- return a / ssef(b);
-}
-__forceinline const ssef operator/(const float &a, const ssef &b)
-{
- return ssef(a) / b;
-}
-
-__forceinline const ssef operator^(const ssef &a, const ssef &b)
-{
- return _mm_xor_ps(a.m128, b.m128);
-}
-__forceinline const ssef operator^(const ssef &a, const ssei &b)
-{
- return _mm_xor_ps(a.m128, _mm_castsi128_ps(b.m128));
-}
-
-__forceinline const ssef operator&(const ssef &a, const ssef &b)
-{
- return _mm_and_ps(a.m128, b.m128);
-}
-__forceinline const ssef operator&(const ssef &a, const ssei &b)
-{
- return _mm_and_ps(a.m128, _mm_castsi128_ps(b.m128));
-}
-
-__forceinline const ssef operator|(const ssef &a, const ssef &b)
-{
- return _mm_or_ps(a.m128, b.m128);
-}
-__forceinline const ssef operator|(const ssef &a, const ssei &b)
-{
- return _mm_or_ps(a.m128, _mm_castsi128_ps(b.m128));
-}
-
-__forceinline const ssef andnot(const ssef &a, const ssef &b)
-{
- return _mm_andnot_ps(a.m128, b.m128);
-}
-
-__forceinline const ssef min(const ssef &a, const ssef &b)
-{
- return _mm_min_ps(a.m128, b.m128);
-}
-__forceinline const ssef min(const ssef &a, const float &b)
-{
- return _mm_min_ps(a.m128, ssef(b));
-}
-__forceinline const ssef min(const float &a, const ssef &b)
-{
- return _mm_min_ps(ssef(a), b.m128);
-}
-
-__forceinline const ssef max(const ssef &a, const ssef &b)
-{
- return _mm_max_ps(a.m128, b.m128);
-}
-__forceinline const ssef max(const ssef &a, const float &b)
-{
- return _mm_max_ps(a.m128, ssef(b));
-}
-__forceinline const ssef max(const float &a, const ssef &b)
-{
- return _mm_max_ps(ssef(a), b.m128);
-}
-
-# if defined(__KERNEL_SSE41__)
-__forceinline ssef mini(const ssef &a, const ssef &b)
-{
- const ssei ai = _mm_castps_si128(a);
- const ssei bi = _mm_castps_si128(b);
- const ssei ci = _mm_min_epi32(ai, bi);
- return _mm_castsi128_ps(ci);
-}
-# endif
-
-# if defined(__KERNEL_SSE41__)
-__forceinline ssef maxi(const ssef &a, const ssef &b)
-{
- const ssei ai = _mm_castps_si128(a);
- const ssei bi = _mm_castps_si128(b);
- const ssei ci = _mm_max_epi32(ai, bi);
- return _mm_castsi128_ps(ci);
-}
-# endif
-
-////////////////////////////////////////////////////////////////////////////////
-/// Ternary Operators
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline const ssef madd(const ssef &a, const ssef &b, const ssef &c)
-{
-# if defined(__KERNEL_NEON__)
- return vfmaq_f32(c, a, b);
-# elif defined(__KERNEL_AVX2__)
- return _mm_fmadd_ps(a, b, c);
-# else
- return a * b + c;
-# endif
-}
-__forceinline const ssef msub(const ssef &a, const ssef &b, const ssef &c)
-{
-# if defined(__KERNEL_NEON__)
- return vfmaq_f32(vnegq_f32(c), a, b);
-# elif defined(__KERNEL_AVX2__)
- return _mm_fmsub_ps(a, b, c);
-# else
- return a * b - c;
-# endif
-}
-__forceinline const ssef nmadd(const ssef &a, const ssef &b, const ssef &c)
-{
-# if defined(__KERNEL_NEON__)
- return vfmsq_f32(c, a, b);
-# elif defined(__KERNEL_AVX2__)
- return _mm_fnmadd_ps(a, b, c);
-# else
- return c - a * b;
-# endif
-}
-__forceinline const ssef nmsub(const ssef &a, const ssef &b, const ssef &c)
-{
-# if defined(__KERNEL_NEON__)
- return vfmsq_f32(vnegq_f32(c), a, b);
-# elif defined(__KERNEL_AVX2__)
- return _mm_fnmsub_ps(a, b, c);
-# else
- return -a * b - c;
-# endif
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Assignment Operators
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline ssef &operator+=(ssef &a, const ssef &b)
-{
- return a = a + b;
-}
-__forceinline ssef &operator+=(ssef &a, const float &b)
-{
- return a = a + b;
-}
-
-__forceinline ssef &operator-=(ssef &a, const ssef &b)
-{
- return a = a - b;
-}
-__forceinline ssef &operator-=(ssef &a, const float &b)
-{
- return a = a - b;
-}
-
-__forceinline ssef &operator*=(ssef &a, const ssef &b)
-{
- return a = a * b;
-}
-__forceinline ssef &operator*=(ssef &a, const float &b)
-{
- return a = a * b;
-}
-
-__forceinline ssef &operator/=(ssef &a, const ssef &b)
-{
- return a = a / b;
-}
-__forceinline ssef &operator/=(ssef &a, const float &b)
-{
- return a = a / b;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Comparison Operators + Select
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline const sseb operator==(const ssef &a, const ssef &b)
-{
- return _mm_cmpeq_ps(a.m128, b.m128);
-}
-__forceinline const sseb operator==(const ssef &a, const float &b)
-{
- return a == ssef(b);
-}
-__forceinline const sseb operator==(const float &a, const ssef &b)
-{
- return ssef(a) == b;
-}
-
-__forceinline const sseb operator!=(const ssef &a, const ssef &b)
-{
- return _mm_cmpneq_ps(a.m128, b.m128);
-}
-__forceinline const sseb operator!=(const ssef &a, const float &b)
-{
- return a != ssef(b);
-}
-__forceinline const sseb operator!=(const float &a, const ssef &b)
-{
- return ssef(a) != b;
-}
-
-__forceinline const sseb operator<(const ssef &a, const ssef &b)
-{
- return _mm_cmplt_ps(a.m128, b.m128);
-}
-__forceinline const sseb operator<(const ssef &a, const float &b)
-{
- return a < ssef(b);
-}
-__forceinline const sseb operator<(const float &a, const ssef &b)
-{
- return ssef(a) < b;
-}
-
-__forceinline const sseb operator>=(const ssef &a, const ssef &b)
-{
- return _mm_cmpnlt_ps(a.m128, b.m128);
-}
-__forceinline const sseb operator>=(const ssef &a, const float &b)
-{
- return a >= ssef(b);
-}
-__forceinline const sseb operator>=(const float &a, const ssef &b)
-{
- return ssef(a) >= b;
-}
-
-__forceinline const sseb operator>(const ssef &a, const ssef &b)
-{
- return _mm_cmpnle_ps(a.m128, b.m128);
-}
-__forceinline const sseb operator>(const ssef &a, const float &b)
-{
- return a > ssef(b);
-}
-__forceinline const sseb operator>(const float &a, const ssef &b)
-{
- return ssef(a) > b;
-}
-
-__forceinline const sseb operator<=(const ssef &a, const ssef &b)
-{
- return _mm_cmple_ps(a.m128, b.m128);
-}
-__forceinline const sseb operator<=(const ssef &a, const float &b)
-{
- return a <= ssef(b);
-}
-__forceinline const sseb operator<=(const float &a, const ssef &b)
-{
- return ssef(a) <= b;
-}
-
-__forceinline const ssef select(const sseb &m, const ssef &t, const ssef &f)
-{
-# ifdef __KERNEL_SSE41__
- return _mm_blendv_ps(f, t, m);
-# else
- return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
-# endif
-}
-
-__forceinline const ssef select(const ssef &m, const ssef &t, const ssef &f)
-{
-# ifdef __KERNEL_SSE41__
- return _mm_blendv_ps(f, t, m);
-# else
- return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
-# endif
-}
-
-__forceinline const ssef select(const int mask, const ssef &t, const ssef &f)
-{
-# if defined(__KERNEL_SSE41__) && \
- ((!defined(__clang__) && !defined(_MSC_VER)) || defined(__INTEL_COMPILER))
- return _mm_blend_ps(f, t, mask);
-# else
- return select(sseb(mask), t, f);
-# endif
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Rounding Functions
-////////////////////////////////////////////////////////////////////////////////
-
-# if defined(__KERNEL_SSE41__)
-__forceinline const ssef round_even(const ssef &a)
-{
-# ifdef __KERNEL_NEON__
- return vrndnq_f32(a);
-# else
- return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT);
-# endif
-}
-__forceinline const ssef round_down(const ssef &a)
-{
-# ifdef __KERNEL_NEON__
- return vrndmq_f32(a);
-# else
- return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF);
-# endif
-}
-__forceinline const ssef round_up(const ssef &a)
-{
-# ifdef __KERNEL_NEON__
- return vrndpq_f32(a);
-# else
- return _mm_round_ps(a, _MM_FROUND_TO_POS_INF);
-# endif
-}
-__forceinline const ssef round_zero(const ssef &a)
-{
-# ifdef __KERNEL_NEON__
- return vrndq_f32(a);
-# else
- return _mm_round_ps(a, _MM_FROUND_TO_ZERO);
-# endif
-}
-__forceinline const ssef floor(const ssef &a)
-{
-# ifdef __KERNEL_NEON__
- return vrndnq_f32(a);
-# else
- return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF);
-# endif
-}
-__forceinline const ssef ceil(const ssef &a)
-{
-# ifdef __KERNEL_NEON__
- return vrndpq_f32(a);
-# else
- return _mm_round_ps(a, _MM_FROUND_TO_POS_INF);
-# endif
-}
-# endif
-
-__forceinline ssei truncatei(const ssef &a)
-{
- return _mm_cvttps_epi32(a.m128);
-}
-
-/* This is about 25% faster than straightforward floor to integer conversion
- * due to better pipelining.
- *
- * Unsaturated add 0xffffffff (a < 0) is the same as subtract -1.
- */
-__forceinline ssei floori(const ssef &a)
-{
- return truncatei(a) + cast((a < 0.0f).m128);
-}
-
-__forceinline ssef floorfrac(const ssef &x, ssei *i)
-{
- *i = floori(x);
- return x - ssef(*i);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Common Functions
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline ssef mix(const ssef &a, const ssef &b, const ssef &t)
-{
- return madd(t, b, (ssef(1.0f) - t) * a);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Movement/Shifting/Shuffling Functions
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline ssef unpacklo(const ssef &a, const ssef &b)
-{
- return _mm_unpacklo_ps(a.m128, b.m128);
-}
-__forceinline ssef unpackhi(const ssef &a, const ssef &b)
-{
- return _mm_unpackhi_ps(a.m128, b.m128);
-}
-
-template<size_t i0, size_t i1, size_t i2, size_t i3>
-__forceinline const ssef shuffle(const ssef &b)
-{
-# ifdef __KERNEL_NEON__
- return shuffle_neon<float32x4_t, i0, i1, i2, i3>(b.m128);
-# else
- return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(i3, i2, i1, i0)));
-# endif
-}
-
-template<> __forceinline const ssef shuffle<0, 1, 0, 1>(const ssef &a)
-{
- return _mm_movelh_ps(a, a);
-}
-
-template<> __forceinline const ssef shuffle<2, 3, 2, 3>(const ssef &a)
-{
- return _mm_movehl_ps(a, a);
-}
-
-template<size_t i0, size_t i1, size_t i2, size_t i3>
-__forceinline const ssef shuffle(const ssef &a, const ssef &b)
-{
-# ifdef __KERNEL_NEON__
- return shuffle_neon<float32x4_t, i0, i1, i2, i3>(a, b);
-# else
- return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
-# endif
-}
-
-template<size_t i0> __forceinline const ssef shuffle(const ssef &a, const ssef &b)
-{
-# ifdef __KERNEL_NEON__
- return shuffle_neon<float32x4_t, i0, i0, i0, i0>(a, b);
-# else
- return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i0, i0, i0, i0));
-# endif
-}
-
-# ifndef __KERNEL_NEON__
-template<> __forceinline const ssef shuffle<0, 1, 0, 1>(const ssef &a, const ssef &b)
-{
- return _mm_movelh_ps(a, b);
-}
-
-template<> __forceinline const ssef shuffle<2, 3, 2, 3>(const ssef &a, const ssef &b)
-{
- return _mm_movehl_ps(b, a);
-}
-# endif
-
-# if defined(__KERNEL_SSSE3__)
-__forceinline const ssef shuffle8(const ssef &a, const ssei &shuf)
-{
- return _mm_castsi128_ps(_mm_shuffle_epi8(_mm_castps_si128(a), shuf));
-}
-# endif
-
-# if defined(__KERNEL_SSE3__)
-template<> __forceinline const ssef shuffle<0, 0, 2, 2>(const ssef &b)
-{
- return _mm_moveldup_ps(b);
-}
-template<> __forceinline const ssef shuffle<1, 1, 3, 3>(const ssef &b)
-{
- return _mm_movehdup_ps(b);
-}
-# endif
-
-template<size_t i0> __forceinline const ssef shuffle(const ssef &b)
-{
- return shuffle<i0, i0, i0, i0>(b);
-}
-
-# if defined(__KERNEL_AVX__)
-__forceinline const ssef shuffle(const ssef &a, const ssei &shuf)
-{
- return _mm_permutevar_ps(a, shuf);
-}
-# endif
-
-template<size_t i> __forceinline float extract(const ssef &a)
-{
- return _mm_cvtss_f32(shuffle<i, i, i, i>(a));
-}
-template<> __forceinline float extract<0>(const ssef &a)
-{
- return _mm_cvtss_f32(a);
-}
-
-# if defined(__KERNEL_SSE41__)
-template<size_t dst, size_t src, size_t clr>
-__forceinline const ssef insert(const ssef &a, const ssef &b)
-{
-# ifdef __KERNEL_NEON__
- ssef res = a;
- if (clr)
- res[dst] = 0;
- else
- res[dst] = b[src];
- return res;
-# else
- return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr);
-# endif
-}
-template<size_t dst, size_t src> __forceinline const ssef insert(const ssef &a, const ssef &b)
-{
- return insert<dst, src, 0>(a, b);
-}
-template<size_t dst> __forceinline const ssef insert(const ssef &a, const float b)
-{
- return insert<dst, 0>(a, _mm_set_ss(b));
-}
-# else
-template<size_t dst> __forceinline const ssef insert(const ssef &a, const float b)
-{
- ssef c = a;
- c[dst] = b;
- return c;
-}
-# endif
-
-////////////////////////////////////////////////////////////////////////////////
-/// Transpose
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline void transpose(const ssef &r0,
- const ssef &r1,
- const ssef &r2,
- const ssef &r3,
- ssef &c0,
- ssef &c1,
- ssef &c2,
- ssef &c3)
-{
- ssef l02 = unpacklo(r0, r2);
- ssef h02 = unpackhi(r0, r2);
- ssef l13 = unpacklo(r1, r3);
- ssef h13 = unpackhi(r1, r3);
- c0 = unpacklo(l02, l13);
- c1 = unpackhi(l02, l13);
- c2 = unpacklo(h02, h13);
- c3 = unpackhi(h02, h13);
-}
-
-__forceinline void transpose(
- const ssef &r0, const ssef &r1, const ssef &r2, const ssef &r3, ssef &c0, ssef &c1, ssef &c2)
-{
- ssef l02 = unpacklo(r0, r2);
- ssef h02 = unpackhi(r0, r2);
- ssef l13 = unpacklo(r1, r3);
- ssef h13 = unpackhi(r1, r3);
- c0 = unpacklo(l02, l13);
- c1 = unpackhi(l02, l13);
- c2 = unpacklo(h02, h13);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Reductions
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline const ssef vreduce_min(const ssef &v)
-{
-# ifdef __KERNEL_NEON__
- return vdupq_n_f32(vminvq_f32(v));
-# else
- ssef h = min(shuffle<1, 0, 3, 2>(v), v);
- return min(shuffle<2, 3, 0, 1>(h), h);
-# endif
-}
-__forceinline const ssef vreduce_max(const ssef &v)
-{
-# ifdef __KERNEL_NEON__
- return vdupq_n_f32(vmaxvq_f32(v));
-# else
- ssef h = max(shuffle<1, 0, 3, 2>(v), v);
- return max(shuffle<2, 3, 0, 1>(h), h);
-# endif
-}
-__forceinline const ssef vreduce_add(const ssef &v)
-{
-# ifdef __KERNEL_NEON__
- return vdupq_n_f32(vaddvq_f32(v));
-# else
- ssef h = shuffle<1, 0, 3, 2>(v) + v;
- return shuffle<2, 3, 0, 1>(h) + h;
-# endif
-}
-
-__forceinline float reduce_min(const ssef &v)
-{
-# ifdef __KERNEL_NEON__
- return vminvq_f32(v);
-# else
- return _mm_cvtss_f32(vreduce_min(v));
-# endif
-}
-__forceinline float reduce_max(const ssef &v)
-{
-# ifdef __KERNEL_NEON__
- return vmaxvq_f32(v);
-# else
- return _mm_cvtss_f32(vreduce_max(v));
-# endif
-}
-__forceinline float reduce_add(const ssef &v)
-{
-# ifdef __KERNEL_NEON__
- return vaddvq_f32(v);
-# else
- return _mm_cvtss_f32(vreduce_add(v));
-# endif
-}
-
-__forceinline uint32_t select_min(const ssef &v)
-{
- return __bsf(movemask(v == vreduce_min(v)));
-}
-__forceinline uint32_t select_max(const ssef &v)
-{
- return __bsf(movemask(v == vreduce_max(v)));
-}
-
-__forceinline uint32_t select_min(const sseb &valid, const ssef &v)
-{
- const ssef a = select(valid, v, ssef(pos_inf));
- return __bsf(movemask(valid & (a == vreduce_min(a))));
-}
-__forceinline uint32_t select_max(const sseb &valid, const ssef &v)
-{
- const ssef a = select(valid, v, ssef(neg_inf));
- return __bsf(movemask(valid & (a == vreduce_max(a))));
-}
-
-__forceinline uint32_t movemask(const ssef &a)
-{
- return _mm_movemask_ps(a);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Memory load and store operations
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline ssef load4f(const float4 &a)
-{
-# ifdef __KERNEL_WITH_SSE_ALIGN__
- return _mm_load_ps(&a.x);
-# else
- return _mm_loadu_ps(&a.x);
-# endif
-}
-
-__forceinline ssef load4f(const float3 &a)
-{
-# ifdef __KERNEL_WITH_SSE_ALIGN__
- return _mm_load_ps(&a.x);
-# else
- return _mm_loadu_ps(&a.x);
-# endif
-}
-
-__forceinline ssef load4f(const void *const a)
-{
- return _mm_load_ps((float *)a);
-}
-
-__forceinline ssef load1f_first(const float a)
-{
- return _mm_set_ss(a);
-}
-
-__forceinline void store4f(void *ptr, const ssef &v)
-{
- _mm_store_ps((float *)ptr, v);
-}
-
-__forceinline ssef loadu4f(const void *const a)
-{
- return _mm_loadu_ps((float *)a);
-}
-
-__forceinline void storeu4f(void *ptr, const ssef &v)
-{
- _mm_storeu_ps((float *)ptr, v);
-}
-
-__forceinline void store4f(const sseb &mask, void *ptr, const ssef &f)
-{
-# if defined(__KERNEL_AVX__)
- _mm_maskstore_ps((float *)ptr, (__m128i)mask, f);
-# else
- *(ssef *)ptr = select(mask, f, *(ssef *)ptr);
-# endif
-}
-
-__forceinline ssef load4f_nt(void *ptr)
-{
-# if defined(__KERNEL_SSE41__)
- return _mm_castsi128_ps(_mm_stream_load_si128((__m128i *)ptr));
-# else
- return _mm_load_ps((float *)ptr);
-# endif
-}
-
-__forceinline void store4f_nt(void *ptr, const ssef &v)
-{
-# if defined(__KERNEL_SSE41__)
- _mm_stream_ps((float *)ptr, v);
-# else
- _mm_store_ps((float *)ptr, v);
-# endif
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Euclidian Space Operators
-////////////////////////////////////////////////////////////////////////////////
-
-__forceinline float dot(const ssef &a, const ssef &b)
-{
- return reduce_add(a * b);
-}
-
-/* calculate shuffled cross product, useful when order of components does not matter */
-__forceinline ssef cross_zxy(const ssef &a, const ssef &b)
-{
- const ssef a0 = a;
- const ssef b0 = shuffle<1, 2, 0, 3>(b);
- const ssef a1 = shuffle<1, 2, 0, 3>(a);
- const ssef b1 = b;
- return msub(a0, b0, a1 * b1);
-}
-
-__forceinline ssef cross(const ssef &a, const ssef &b)
-{
- return shuffle<1, 2, 0, 3>(cross_zxy(a, b));
-}
-
-ccl_device_inline const ssef dot3_splat(const ssef &a, const ssef &b)
-{
-# ifdef __KERNEL_SSE41__
- return _mm_dp_ps(a.m128, b.m128, 0x7f);
-# else
- ssef t = a * b;
- return ssef(((float *)&t)[0] + ((float *)&t)[1] + ((float *)&t)[2]);
-# endif
-}
-
-/* squared length taking only specified axes into account */
-template<size_t X, size_t Y, size_t Z, size_t W> ccl_device_inline float len_squared(const ssef &a)
-{
-# ifndef __KERNEL_SSE41__
- float4 &t = (float4 &)a;
- return (X ? t.x * t.x : 0.0f) + (Y ? t.y * t.y : 0.0f) + (Z ? t.z * t.z : 0.0f) +
- (W ? t.w * t.w : 0.0f);
-# else
- return extract<0>(
- ssef(_mm_dp_ps(a.m128, a.m128, (X << 4) | (Y << 5) | (Z << 6) | (W << 7) | 0xf)));
-# endif
-}
-
-ccl_device_inline float dot3(const ssef &a, const ssef &b)
-{
-# ifdef __KERNEL_SSE41__
- return extract<0>(ssef(_mm_dp_ps(a.m128, b.m128, 0x7f)));
-# else
- ssef t = a * b;
- return ((float *)&t)[0] + ((float *)&t)[1] + ((float *)&t)[2];
-# endif
-}
-
-ccl_device_inline const ssef len3_squared_splat(const ssef &a)
-{
- return dot3_splat(a, a);
-}
-
-ccl_device_inline float len3_squared(const ssef &a)
-{
- return dot3(a, a);
-}
-
-ccl_device_inline float len3(const ssef &a)
-{
- return extract<0>(mm_sqrt(dot3_splat(a, a)));
-}
-
-/* SSE shuffle utility functions */
-
-# ifdef __KERNEL_SSSE3__
-
-/* faster version for SSSE3 */
-typedef ssei shuffle_swap_t;
-
-ccl_device_inline shuffle_swap_t shuffle_swap_identity()
-{
- return _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
-}
-
-ccl_device_inline shuffle_swap_t shuffle_swap_swap()
-{
- return _mm_set_epi8(7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8);
-}
-
-ccl_device_inline const ssef shuffle_swap(const ssef &a, const shuffle_swap_t &shuf)
-{
- return cast(_mm_shuffle_epi8(cast(a), shuf));
-}
-
-# else
-
-/* somewhat slower version for SSE2 */
-typedef int shuffle_swap_t;
-
-ccl_device_inline shuffle_swap_t shuffle_swap_identity()
-{
- return 0;
-}
-
-ccl_device_inline shuffle_swap_t shuffle_swap_swap()
-{
- return 1;
-}
-
-ccl_device_inline const ssef shuffle_swap(const ssef &a, shuffle_swap_t shuf)
-{
- /* shuffle value must be a constant, so we need to branch */
- if (shuf)
- return shuffle<1, 0, 3, 2>(a);
- else
- return shuffle<3, 2, 1, 0>(a);
-}
-
-# endif
-
-# if defined(__KERNEL_SSE41__) && !defined(__KERNEL_NEON__)
-
-ccl_device_inline void gen_idirsplat_swap(const ssef &pn,
- const shuffle_swap_t &shuf_identity,
- const shuffle_swap_t &shuf_swap,
- const float3 &idir,
- ssef idirsplat[3],
- shuffle_swap_t shufflexyz[3])
-{
- const __m128 idirsplat_raw[] = {_mm_set_ps1(idir.x), _mm_set_ps1(idir.y), _mm_set_ps1(idir.z)};
- idirsplat[0] = _mm_xor_ps(idirsplat_raw[0], pn);
- idirsplat[1] = _mm_xor_ps(idirsplat_raw[1], pn);
- idirsplat[2] = _mm_xor_ps(idirsplat_raw[2], pn);
-
- const ssef signmask = cast(ssei(0x80000000));
- const ssef shuf_identity_f = cast(shuf_identity);
- const ssef shuf_swap_f = cast(shuf_swap);
-
- shufflexyz[0] = _mm_castps_si128(
- _mm_blendv_ps(shuf_identity_f, shuf_swap_f, _mm_and_ps(idirsplat_raw[0], signmask)));
- shufflexyz[1] = _mm_castps_si128(
- _mm_blendv_ps(shuf_identity_f, shuf_swap_f, _mm_and_ps(idirsplat_raw[1], signmask)));
- shufflexyz[2] = _mm_castps_si128(
- _mm_blendv_ps(shuf_identity_f, shuf_swap_f, _mm_and_ps(idirsplat_raw[2], signmask)));
-}
-
-# else
-
-ccl_device_inline void gen_idirsplat_swap(const ssef &pn,
- const shuffle_swap_t &shuf_identity,
- const shuffle_swap_t &shuf_swap,
- const float3 &idir,
- ssef idirsplat[3],
- shuffle_swap_t shufflexyz[3])
-{
- idirsplat[0] = ssef(idir.x) ^ pn;
- idirsplat[1] = ssef(idir.y) ^ pn;
- idirsplat[2] = ssef(idir.z) ^ pn;
-
- shufflexyz[0] = (idir.x >= 0) ? shuf_identity : shuf_swap;
- shufflexyz[1] = (idir.y >= 0) ? shuf_identity : shuf_swap;
- shufflexyz[2] = (idir.z >= 0) ? shuf_identity : shuf_swap;
-}
-
-# endif
-
-ccl_device_inline const ssef uint32_to_float(const ssei &in)
-{
- ssei a = _mm_srli_epi32(in, 16);
- ssei b = _mm_and_si128(in, _mm_set1_epi32(0x0000ffff));
- ssei c = _mm_or_si128(a, _mm_set1_epi32(0x53000000));
- ssef d = _mm_cvtepi32_ps(b);
- ssef e = _mm_sub_ps(_mm_castsi128_ps(c), _mm_castsi128_ps(_mm_set1_epi32(0x53000000)));
- return _mm_add_ps(e, d);
-}
-
-template<size_t S1, size_t S2, size_t S3, size_t S4>
-ccl_device_inline const ssef set_sign_bit(const ssef &a)
-{
- return cast(cast(a) ^ ssei(S1 << 31, S2 << 31, S3 << 31, S4 << 31));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Debug Functions
-////////////////////////////////////////////////////////////////////////////////
-
-ccl_device_inline void print_ssef(const char *label, const ssef &a)
-{
- printf(
- "%s: %.8f %.8f %.8f %.8f\n", label, (double)a[0], (double)a[1], (double)a[2], (double)a[3]);
-}
-
-#endif
-
-CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/util/util_stats.h b/intern/cycles/util/util_stats.h
deleted file mode 100644
index 15cf836de3c..00000000000
--- a/intern/cycles/util/util_stats.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_STATS_H__
-#define __UTIL_STATS_H__
-
-#include "util/util_atomic.h"
-#include "util/util_profiling.h"
-
-CCL_NAMESPACE_BEGIN
-
-class Stats {
- public:
- enum static_init_t { static_init = 0 };
-
- Stats() : mem_used(0), mem_peak(0)
- {
- }
- explicit Stats(static_init_t)
- {
- }
-
- void mem_alloc(size_t size)
- {
- atomic_add_and_fetch_z(&mem_used, size);
- atomic_fetch_and_update_max_z(&mem_peak, mem_used);
- }
-
- void mem_free(size_t size)
- {
- assert(mem_used >= size);
- atomic_sub_and_fetch_z(&mem_used, size);
- }
-
- size_t mem_used;
- size_t mem_peak;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_STATS_H__ */
diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp
deleted file mode 100644
index 0fc9cb4ae77..00000000000
--- a/intern/cycles/util/util_string.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdarg.h>
-#include <stdio.h>
-
-#include <algorithm>
-#include <cctype>
-
-#include "util/util_foreach.h"
-#include "util/util_string.h"
-#include "util/util_windows.h"
-
-#ifdef _WIN32
-# ifndef vsnprintf
-# define vsnprintf _vsnprintf
-# endif
-#endif /* _WIN32 */
-
-CCL_NAMESPACE_BEGIN
-
-string string_printf(const char *format, ...)
-{
- vector<char> str(128, 0);
-
- while (1) {
- va_list args;
- int result;
-
- va_start(args, format);
- result = vsnprintf(&str[0], str.size(), format, args);
- va_end(args);
-
- if (result == -1) {
- /* not enough space or formatting error */
- if (str.size() > 65536) {
- assert(0);
- return string("");
- }
-
- str.resize(str.size() * 2, 0);
- continue;
- }
- else if (result >= (int)str.size()) {
- /* not enough space */
- str.resize(result + 1, 0);
- continue;
- }
-
- return string(&str[0]);
- }
-}
-
-bool string_iequals(const string &a, const string &b)
-{
- if (a.size() == b.size()) {
- for (size_t i = 0; i < a.size(); i++)
- if (toupper(a[i]) != toupper(b[i]))
- return false;
-
- return true;
- }
-
- return false;
-}
-
-void string_split(vector<string> &tokens,
- const string &str,
- const string &separators,
- bool skip_empty_tokens)
-{
- size_t token_start = 0, token_length = 0;
- for (size_t i = 0; i < str.size(); ++i) {
- const char ch = str[i];
- if (separators.find(ch) == string::npos) {
- /* Current character is not a separator,
- * append it to token by increasing token length.
- */
- ++token_length;
- }
- else {
- /* Current character is a separator,
- * append current token to the list.
- */
- if (!skip_empty_tokens || token_length > 0) {
- string token = str.substr(token_start, token_length);
- tokens.push_back(token);
- }
- token_start = i + 1;
- token_length = 0;
- }
- }
- /* Append token from the tail of the string if exists. */
- if (token_length) {
- string token = str.substr(token_start, token_length);
- tokens.push_back(token);
- }
-}
-
-bool string_startswith(const string_view s, const string_view start)
-{
- const size_t len = start.size();
-
- if (len > s.size()) {
- return false;
- }
-
- return strncmp(s.c_str(), start.data(), len) == 0;
-}
-
-bool string_endswith(const string_view s, const string_view end)
-{
- const size_t len = end.size();
-
- if (len > s.size()) {
- return false;
- }
-
- return strncmp(s.c_str() + s.size() - len, end.data(), len) == 0;
-}
-
-string string_strip(const string &s)
-{
- string result = s;
- result.erase(0, result.find_first_not_of(' '));
- result.erase(result.find_last_not_of(' ') + 1);
- return result;
-}
-
-void string_replace(string &haystack, const string &needle, const string &other)
-{
- size_t i = 0, index;
- while ((index = haystack.find(needle, i)) != string::npos) {
- haystack.replace(index, needle.size(), other);
- i = index + other.size();
- }
-}
-
-string string_remove_trademark(const string &s)
-{
- string result = s;
-
- /* Special case, so we don't leave sequential spaces behind. */
- /* TODO(sergey): Consider using regex perhaps? */
- string_replace(result, " (TM)", "");
- string_replace(result, " (R)", "");
-
- string_replace(result, "(TM)", "");
- string_replace(result, "(R)", "");
-
- return string_strip(result);
-}
-
-string string_from_bool(bool var)
-{
- if (var)
- return "True";
- else
- return "False";
-}
-
-string to_string(const char *str)
-{
- return string(str);
-}
-
-string string_to_lower(const string &s)
-{
- string r = s;
- std::transform(r.begin(), r.end(), r.begin(), [](char c) { return std::tolower(c); });
- return r;
-}
-
-/* Wide char strings helpers for Windows. */
-
-#ifdef _WIN32
-
-wstring string_to_wstring(const string &str)
-{
- const int length_wc = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
- wstring str_wc(length_wc, 0);
- MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &str_wc[0], length_wc);
- return str_wc;
-}
-
-string string_from_wstring(const wstring &str)
-{
- int length_mb = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.size(), NULL, 0, NULL, NULL);
- string str_mb(length_mb, 0);
- WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.size(), &str_mb[0], length_mb, NULL, NULL);
- return str_mb;
-}
-
-string string_to_ansi(const string &str)
-{
- const int length_wc = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
- wstring str_wc(length_wc, 0);
- MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &str_wc[0], length_wc);
-
- int length_mb = WideCharToMultiByte(
- CP_ACP, 0, str_wc.c_str(), str_wc.size(), NULL, 0, NULL, NULL);
-
- string str_mb(length_mb, 0);
- WideCharToMultiByte(CP_ACP, 0, str_wc.c_str(), str_wc.size(), &str_mb[0], length_mb, NULL, NULL);
-
- return str_mb;
-}
-
-#endif /* _WIN32 */
-
-string string_human_readable_size(size_t size)
-{
- static const char suffixes[] = "BKMGTPEZY";
-
- const char *suffix = suffixes;
- size_t r = 0;
-
- while (size >= 1024) {
- r = size % 1024;
- size /= 1024;
- suffix++;
- }
-
- if (*suffix != 'B')
- return string_printf("%.2f%c", double(size * 1024 + r) / 1024.0, *suffix);
- else
- return string_printf("%zu", size);
-}
-
-string string_human_readable_number(size_t num)
-{
- if (num == 0) {
- return "0";
- }
-
- /* Add thousands separators. */
- char buf[32];
-
- char *p = buf + 31;
- *p = '\0';
-
- int i = -1;
- while (num) {
- if (++i && i % 3 == 0)
- *(--p) = ',';
-
- *(--p) = '0' + (num % 10);
-
- num /= 10;
- }
-
- return p;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h
deleted file mode 100644
index 55462cfd8b8..00000000000
--- a/intern/cycles/util/util_string.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_STRING_H__
-#define __UTIL_STRING_H__
-
-#include <sstream>
-#include <string.h>
-#include <string>
-
-/* Use string view implementation from OIIO.
- * Ideally, need to switch to `std::string_view`, but this first requires getting rid of using
- * namespace OIIO as it causes symbol collision. */
-#include <OpenImageIO/string_view.h>
-
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-using std::istringstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::to_string;
-
-using OIIO::string_view;
-
-#ifdef __GNUC__
-# define PRINTF_ATTRIBUTE __attribute__((format(printf, 1, 2)))
-#else
-# define PRINTF_ATTRIBUTE
-#endif
-
-string string_printf(const char *format, ...) PRINTF_ATTRIBUTE;
-
-bool string_iequals(const string &a, const string &b);
-void string_split(vector<string> &tokens,
- const string &str,
- const string &separators = "\t ",
- bool skip_empty_tokens = true);
-void string_replace(string &haystack, const string &needle, const string &other);
-bool string_startswith(string_view s, string_view start);
-bool string_endswith(string_view s, string_view end);
-string string_strip(const string &s);
-string string_remove_trademark(const string &s);
-string string_from_bool(const bool var);
-string to_string(const char *str);
-string string_to_lower(const string &s);
-
-/* Wide char strings are only used on Windows to deal with non-ASCII
- * characters in file names and such. No reason to use such strings
- * for something else at this moment.
- *
- * Please note that strings are expected to be in UTF-8 codepage, and
- * if ANSI is needed then explicit conversion required.
- */
-#ifdef _WIN32
-using std::wstring;
-wstring string_to_wstring(const string &path);
-string string_from_wstring(const wstring &path);
-string string_to_ansi(const string &str);
-#endif
-
-/* Make a string from a size in bytes in human readable form. */
-string string_human_readable_size(size_t size);
-/* Make a string from a unit-less quantity in human readable form. */
-string string_human_readable_number(size_t num);
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_STRING_H__ */
diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp
deleted file mode 100644
index be8c2fb505a..00000000000
--- a/intern/cycles/util/util_system.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_system.h"
-
-#include "util/util_logging.h"
-#include "util/util_string.h"
-#include "util/util_types.h"
-
-#include <numaapi.h>
-
-#include <OpenImageIO/sysutil.h>
-OIIO_NAMESPACE_USING
-
-#ifdef _WIN32
-# if (!defined(FREE_WINDOWS))
-# include <intrin.h>
-# endif
-# include "util_windows.h"
-#elif defined(__APPLE__)
-# include <sys/ioctl.h>
-# include <sys/sysctl.h>
-# include <sys/types.h>
-#else
-# include <sys/ioctl.h>
-# include <unistd.h>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-bool system_cpu_ensure_initialized()
-{
- static bool is_initialized = false;
- static bool result = false;
- if (is_initialized) {
- return result;
- }
- is_initialized = true;
- const NUMAAPI_Result numa_result = numaAPI_Initialize();
- result = (numa_result == NUMAAPI_SUCCESS);
- return result;
-}
-
-/* Fallback solution, which doesn't use NUMA/CPU groups. */
-static int system_cpu_thread_count_fallback()
-{
-#ifdef _WIN32
- SYSTEM_INFO info;
- GetSystemInfo(&info);
- return info.dwNumberOfProcessors;
-#elif defined(__APPLE__)
- int count;
- size_t len = sizeof(count);
- int mib[2] = {CTL_HW, HW_NCPU};
- sysctl(mib, 2, &count, &len, NULL, 0);
- return count;
-#else
- return sysconf(_SC_NPROCESSORS_ONLN);
-#endif
-}
-
-int system_cpu_thread_count()
-{
- const int num_nodes = system_cpu_num_numa_nodes();
- int num_threads = 0;
- for (int node = 0; node < num_nodes; ++node) {
- if (!system_cpu_is_numa_node_available(node)) {
- continue;
- }
- num_threads += system_cpu_num_numa_node_processors(node);
- }
- return num_threads;
-}
-
-int system_cpu_num_numa_nodes()
-{
- if (!system_cpu_ensure_initialized()) {
- /* Fallback to a single node with all the threads. */
- return 1;
- }
- return numaAPI_GetNumNodes();
-}
-
-bool system_cpu_is_numa_node_available(int node)
-{
- if (!system_cpu_ensure_initialized()) {
- return true;
- }
- return numaAPI_IsNodeAvailable(node);
-}
-
-int system_cpu_num_numa_node_processors(int node)
-{
- if (!system_cpu_ensure_initialized()) {
- return system_cpu_thread_count_fallback();
- }
- return numaAPI_GetNumNodeProcessors(node);
-}
-
-bool system_cpu_run_thread_on_node(int node)
-{
- if (!system_cpu_ensure_initialized()) {
- return true;
- }
- return numaAPI_RunThreadOnNode(node);
-}
-
-int system_console_width()
-{
- int columns = 0;
-
-#ifdef _WIN32
- CONSOLE_SCREEN_BUFFER_INFO csbi;
- if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
- columns = csbi.dwSize.X;
- }
-#else
- struct winsize w;
- if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
- columns = w.ws_col;
- }
-#endif
-
- return (columns > 0) ? columns : 80;
-}
-
-int system_cpu_num_active_group_processors()
-{
- if (!system_cpu_ensure_initialized()) {
- return system_cpu_thread_count_fallback();
- }
- return numaAPI_GetNumCurrentNodesProcessors();
-}
-
-/* Equivalent of Windows __cpuid for x86 processors on other platforms. */
-#if (!defined(_WIN32) || defined(FREE_WINDOWS)) && (defined(__x86_64__) || defined(__i386__))
-static void __cpuid(int data[4], int selector)
-{
-# if defined(__x86_64__)
- asm("cpuid" : "=a"(data[0]), "=b"(data[1]), "=c"(data[2]), "=d"(data[3]) : "a"(selector));
-# elif defined(__i386__)
- asm("pushl %%ebx \n\t"
- "cpuid \n\t"
- "movl %%ebx, %1 \n\t"
- "popl %%ebx \n\t"
- : "=a"(data[0]), "=r"(data[1]), "=c"(data[2]), "=d"(data[3])
- : "a"(selector)
- : "ebx");
-# else
- data[0] = data[1] = data[2] = data[3] = 0;
-# endif
-}
-#endif
-
-string system_cpu_brand_string()
-{
-#if defined(__APPLE__)
- /* Get from system on macOS. */
- char modelname[512] = "";
- size_t bufferlen = 512;
- if (sysctlbyname("machdep.cpu.brand_string", &modelname, &bufferlen, NULL, 0) == 0) {
- return modelname;
- }
-#elif defined(WIN32) || defined(__x86_64__) || defined(__i386__)
- /* Get from intrinsics on Windows and x86. */
- char buf[49] = {0};
- int result[4] = {0};
-
- __cpuid(result, 0x80000000);
-
- if (result[0] != 0 && result[0] >= (int)0x80000004) {
- __cpuid((int *)(buf + 0), 0x80000002);
- __cpuid((int *)(buf + 16), 0x80000003);
- __cpuid((int *)(buf + 32), 0x80000004);
-
- string brand = buf;
-
- /* Make it a bit more presentable. */
- brand = string_remove_trademark(brand);
-
- return brand;
- }
-#else
- /* Get from /proc/cpuinfo on Unix systems. */
- FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
- if (cpuinfo != nullptr) {
- char cpuinfo_buf[513] = "";
- fread(cpuinfo_buf, sizeof(cpuinfo_buf) - 1, 1, cpuinfo);
- fclose(cpuinfo);
-
- char *modelname = strstr(cpuinfo_buf, "model name");
- if (modelname != nullptr) {
- modelname = strchr(modelname, ':');
- if (modelname != nullptr) {
- modelname += 2;
- char *modelname_end = strchr(modelname, '\n');
- if (modelname_end != nullptr) {
- *modelname_end = '\0';
- return modelname;
- }
- }
- }
- }
-#endif
- return "Unknown CPU";
-}
-
-int system_cpu_bits()
-{
- return (sizeof(void *) * 8);
-}
-
-#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
-
-struct CPUCapabilities {
- bool x64;
- bool mmx;
- bool sse;
- bool sse2;
- bool sse3;
- bool ssse3;
- bool sse41;
- bool sse42;
- bool sse4a;
- bool avx;
- bool f16c;
- bool avx2;
- bool xop;
- bool fma3;
- bool fma4;
- bool bmi1;
- bool bmi2;
-};
-
-static CPUCapabilities &system_cpu_capabilities()
-{
- static CPUCapabilities caps;
- static bool caps_init = false;
-
- if (!caps_init) {
- int result[4], num;
-
- memset(&caps, 0, sizeof(caps));
-
- __cpuid(result, 0);
- num = result[0];
-
- if (num >= 1) {
- __cpuid(result, 0x00000001);
- caps.mmx = (result[3] & ((int)1 << 23)) != 0;
- caps.sse = (result[3] & ((int)1 << 25)) != 0;
- caps.sse2 = (result[3] & ((int)1 << 26)) != 0;
- caps.sse3 = (result[2] & ((int)1 << 0)) != 0;
-
- caps.ssse3 = (result[2] & ((int)1 << 9)) != 0;
- caps.sse41 = (result[2] & ((int)1 << 19)) != 0;
- caps.sse42 = (result[2] & ((int)1 << 20)) != 0;
-
- caps.fma3 = (result[2] & ((int)1 << 12)) != 0;
- caps.avx = false;
- bool os_uses_xsave_xrestore = (result[2] & ((int)1 << 27)) != 0;
- bool cpu_avx_support = (result[2] & ((int)1 << 28)) != 0;
-
- if (os_uses_xsave_xrestore && cpu_avx_support) {
- // Check if the OS will save the YMM registers
- uint32_t xcr_feature_mask;
-# if defined(__GNUC__)
- int edx; /* not used */
- /* actual opcode for xgetbv */
- __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(xcr_feature_mask), "=d"(edx) : "c"(0));
-# elif defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)
- /* Minimum VS2010 SP1 compiler is required. */
- xcr_feature_mask = (uint32_t)_xgetbv(_XCR_XFEATURE_ENABLED_MASK);
-# else
- xcr_feature_mask = 0;
-# endif
- caps.avx = (xcr_feature_mask & 0x6) == 0x6;
- }
-
- caps.f16c = (result[2] & ((int)1 << 29)) != 0;
-
- __cpuid(result, 0x00000007);
- caps.bmi1 = (result[1] & ((int)1 << 3)) != 0;
- caps.bmi2 = (result[1] & ((int)1 << 8)) != 0;
- caps.avx2 = (result[1] & ((int)1 << 5)) != 0;
- }
-
- caps_init = true;
- }
-
- return caps;
-}
-
-bool system_cpu_support_sse2()
-{
- CPUCapabilities &caps = system_cpu_capabilities();
- return caps.sse && caps.sse2;
-}
-
-bool system_cpu_support_sse3()
-{
- CPUCapabilities &caps = system_cpu_capabilities();
- return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3;
-}
-
-bool system_cpu_support_sse41()
-{
- CPUCapabilities &caps = system_cpu_capabilities();
- return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41;
-}
-
-bool system_cpu_support_avx()
-{
- CPUCapabilities &caps = system_cpu_capabilities();
- return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx;
-}
-
-bool system_cpu_support_avx2()
-{
- CPUCapabilities &caps = system_cpu_capabilities();
- return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx && caps.f16c &&
- caps.avx2 && caps.fma3 && caps.bmi1 && caps.bmi2;
-}
-#else
-
-bool system_cpu_support_sse2()
-{
- return false;
-}
-
-bool system_cpu_support_sse3()
-{
- return false;
-}
-
-bool system_cpu_support_sse41()
-{
- return false;
-}
-
-bool system_cpu_support_avx()
-{
- return false;
-}
-bool system_cpu_support_avx2()
-{
- return false;
-}
-
-#endif
-
-bool system_call_self(const vector<string> &args)
-{
- /* Escape program and arguments in case they contain spaces. */
- string cmd = "\"" + Sysutil::this_program_path() + "\"";
-
- for (int i = 0; i < args.size(); i++) {
- cmd += " \"" + args[i] + "\"";
- }
-
-#ifdef _WIN32
- /* Use cmd /S to avoid issues with spaces in arguments. */
- cmd = "cmd /S /C \"" + cmd + " > nul \"";
-#else
- /* Quiet output. */
- cmd += " > /dev/null";
-#endif
-
- return (system(cmd.c_str()) == 0);
-}
-
-size_t system_physical_ram()
-{
-#ifdef _WIN32
- MEMORYSTATUSEX ram;
- ram.dwLength = sizeof(ram);
- GlobalMemoryStatusEx(&ram);
- return ram.ullTotalPhys;
-#elif defined(__APPLE__)
- uint64_t ram = 0;
- size_t len = sizeof(ram);
- if (sysctlbyname("hw.memsize", &ram, &len, NULL, 0) == 0) {
- return ram;
- }
- return 0;
-#else
- size_t ps = sysconf(_SC_PAGESIZE);
- size_t pn = sysconf(_SC_PHYS_PAGES);
- return ps * pn;
-#endif
-}
-
-uint64_t system_self_process_id()
-{
-#ifdef _WIN32
- return GetCurrentProcessId();
-#else
- return getpid();
-#endif
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_system.h b/intern/cycles/util/util_system.h
deleted file mode 100644
index a1797e6ca44..00000000000
--- a/intern/cycles/util/util_system.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_SYSTEM_H__
-#define __UTIL_SYSTEM_H__
-
-#include "util/util_string.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Make sure CPU groups / NUMA API is initialized. */
-bool system_cpu_ensure_initialized();
-
-/* Get total number of threads in all NUMA nodes / CPU groups. */
-int system_cpu_thread_count();
-
-/* Get width in characters of the current console output. */
-int system_console_width();
-
-/* Get number of available nodes.
- *
- * This is in fact an index of last node plus one and it's not guaranteed
- * that all nodes up to this one are available. */
-int system_cpu_num_numa_nodes();
-
-/* Returns truth if the given node is available for compute. */
-bool system_cpu_is_numa_node_available(int node);
-
-/* Get number of available processors on a given node. */
-int system_cpu_num_numa_node_processors(int node);
-
-/* Runs the current thread and its children on a specific node.
- *
- * Returns truth if affinity has successfully changed. */
-bool system_cpu_run_thread_on_node(int node);
-
-/* Number of processors within the current CPU group (or within active thread
- * thread affinity). */
-int system_cpu_num_active_group_processors();
-
-string system_cpu_brand_string();
-int system_cpu_bits();
-bool system_cpu_support_sse2();
-bool system_cpu_support_sse3();
-bool system_cpu_support_sse41();
-bool system_cpu_support_avx();
-bool system_cpu_support_avx2();
-
-size_t system_physical_ram();
-
-/* Start a new process of the current application with the given arguments. */
-bool system_call_self(const vector<string> &args);
-
-/* Get identifier of the currently running process. */
-uint64_t system_self_process_id();
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_SYSTEM_H__ */
diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp
deleted file mode 100644
index 949ba0a7b4d..00000000000
--- a/intern/cycles/util/util_task.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_task.h"
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_system.h"
-#include "util/util_time.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Task Pool */
-
-TaskPool::TaskPool() : start_time(time_dt()), num_tasks_pushed(0)
-{
-}
-
-TaskPool::~TaskPool()
-{
- cancel();
-}
-
-void TaskPool::push(TaskRunFunction &&task)
-{
- tbb_group.run(std::move(task));
- num_tasks_pushed++;
-}
-
-void TaskPool::wait_work(Summary *stats)
-{
- tbb_group.wait();
-
- if (stats != NULL) {
- stats->time_total = time_dt() - start_time;
- stats->num_tasks_handled = num_tasks_pushed;
- }
-
- num_tasks_pushed = 0;
-}
-
-void TaskPool::cancel()
-{
- if (num_tasks_pushed > 0) {
- tbb_group.cancel();
- tbb_group.wait();
- num_tasks_pushed = 0;
- }
-}
-
-bool TaskPool::canceled()
-{
- return tbb::is_current_task_group_canceling();
-}
-
-/* Task Scheduler */
-
-thread_mutex TaskScheduler::mutex;
-int TaskScheduler::users = 0;
-int TaskScheduler::active_num_threads = 0;
-tbb::global_control *TaskScheduler::global_control = nullptr;
-
-void TaskScheduler::init(int num_threads)
-{
- thread_scoped_lock lock(mutex);
- /* Multiple cycles instances can use this task scheduler, sharing the same
- * threads, so we keep track of the number of users. */
- ++users;
- if (users != 1) {
- return;
- }
- if (num_threads > 0) {
- /* Automatic number of threads. */
- VLOG(1) << "Overriding number of TBB threads to " << num_threads << ".";
- global_control = new tbb::global_control(tbb::global_control::max_allowed_parallelism,
- num_threads);
- active_num_threads = num_threads;
- }
- else {
- active_num_threads = system_cpu_thread_count();
- }
-}
-
-void TaskScheduler::exit()
-{
- thread_scoped_lock lock(mutex);
- users--;
- if (users == 0) {
- delete global_control;
- global_control = nullptr;
- active_num_threads = 0;
- }
-}
-
-void TaskScheduler::free_memory()
-{
- assert(users == 0);
-}
-
-int TaskScheduler::num_threads()
-{
- return active_num_threads;
-}
-
-/* Dedicated Task Pool */
-
-DedicatedTaskPool::DedicatedTaskPool()
-{
- do_cancel = false;
- do_exit = false;
- num = 0;
-
- worker_thread = new thread(function_bind(&DedicatedTaskPool::thread_run, this));
-}
-
-DedicatedTaskPool::~DedicatedTaskPool()
-{
- wait();
-
- do_exit = true;
- queue_cond.notify_all();
-
- worker_thread->join();
- delete worker_thread;
-}
-
-void DedicatedTaskPool::push(TaskRunFunction &&task, bool front)
-{
- num_increase();
-
- /* add task to queue */
- queue_mutex.lock();
- if (front)
- queue.emplace_front(std::move(task));
- else
- queue.emplace_back(std::move(task));
-
- queue_cond.notify_one();
- queue_mutex.unlock();
-}
-
-void DedicatedTaskPool::wait()
-{
- thread_scoped_lock num_lock(num_mutex);
-
- while (num)
- num_cond.wait(num_lock);
-}
-
-void DedicatedTaskPool::cancel()
-{
- do_cancel = true;
-
- clear();
- wait();
-
- do_cancel = false;
-}
-
-bool DedicatedTaskPool::canceled()
-{
- return do_cancel;
-}
-
-void DedicatedTaskPool::num_decrease(int done)
-{
- thread_scoped_lock num_lock(num_mutex);
- num -= done;
-
- assert(num >= 0);
- if (num == 0)
- num_cond.notify_all();
-}
-
-void DedicatedTaskPool::num_increase()
-{
- thread_scoped_lock num_lock(num_mutex);
- num++;
- num_cond.notify_all();
-}
-
-bool DedicatedTaskPool::thread_wait_pop(TaskRunFunction &task)
-{
- thread_scoped_lock queue_lock(queue_mutex);
-
- while (queue.empty() && !do_exit)
- queue_cond.wait(queue_lock);
-
- if (queue.empty()) {
- assert(do_exit);
- return false;
- }
-
- task = queue.front();
- queue.pop_front();
-
- return true;
-}
-
-void DedicatedTaskPool::thread_run()
-{
- TaskRunFunction task;
-
- /* keep popping off tasks */
- while (thread_wait_pop(task)) {
- /* run task */
- task();
-
- /* delete task */
- task = nullptr;
-
- /* notify task was done */
- num_decrease(1);
- }
-}
-
-void DedicatedTaskPool::clear()
-{
- thread_scoped_lock queue_lock(queue_mutex);
-
- /* erase all tasks from the queue */
- int done = queue.size();
- queue.clear();
-
- queue_lock.unlock();
-
- /* notify done */
- num_decrease(done);
-}
-
-string TaskPool::Summary::full_report() const
-{
- string report = "";
- report += string_printf("Total time: %f\n", time_total);
- report += string_printf("Tasks handled: %d\n", num_tasks_handled);
- return report;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_task.h b/intern/cycles/util/util_task.h
deleted file mode 100644
index ec45dfa8040..00000000000
--- a/intern/cycles/util/util_task.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TASK_H__
-#define __UTIL_TASK_H__
-
-#include "util/util_list.h"
-#include "util/util_string.h"
-#include "util/util_tbb.h"
-#include "util/util_thread.h"
-#include "util/util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class TaskPool;
-class TaskScheduler;
-
-typedef function<void(void)> TaskRunFunction;
-
-/* Task Pool
- *
- * Pool of tasks that will be executed by the central TaskScheduler. For each
- * pool, we can wait for all tasks to be done, or cancel them before they are
- * done.
- *
- * TaskRunFunction may be created with std::bind or lambda expressions. */
-
-class TaskPool {
- public:
- struct Summary {
- /* Time spent to handle all tasks. */
- double time_total;
-
- /* Number of all tasks handled by this pool. */
- int num_tasks_handled;
-
- /* A full multi-line description of the state of the pool after
- * all work is done.
- */
- string full_report() const;
- };
-
- TaskPool();
- ~TaskPool();
-
- void push(TaskRunFunction &&task);
-
- void wait_work(Summary *stats = NULL); /* work and wait until all tasks are done */
- void cancel(); /* cancel all tasks and wait until they are no longer executing */
-
- static bool canceled(); /* For worker threads, test if current task pool canceled. */
-
- protected:
- tbb::task_group tbb_group;
-
- /* ** Statistics ** */
-
- /* Time stamp of first task pushed. */
- double start_time;
-
- /* Number of all tasks pushed to the pool. Cleared after wait_work() and cancel(). */
- int num_tasks_pushed;
-};
-
-/* Task Scheduler
- *
- * Central scheduler that holds running threads ready to execute tasks. A single
- * queue holds the task from all pools. */
-
-class TaskScheduler {
- public:
- static void init(int num_threads = 0);
- static void exit();
- static void free_memory();
-
- /* Approximate number of threads that will work on task, which may be lower
- * or higher than the actual number of threads. Use as little as possible and
- * leave splitting up tasks to the scheduler. */
- static int num_threads();
-
- protected:
- static thread_mutex mutex;
- static int users;
- static int active_num_threads;
-
-#ifdef WITH_TBB_GLOBAL_CONTROL
- static tbb::global_control *global_control;
-#endif
-};
-
-/* Dedicated Task Pool
- *
- * Like a TaskPool, but will launch one dedicated thread to execute all tasks.
- *
- * The run callback that actually executes the task may be created like this:
- * function_bind(&MyClass::task_execute, this, _1, _2) */
-
-class DedicatedTaskPool {
- public:
- DedicatedTaskPool();
- ~DedicatedTaskPool();
-
- void push(TaskRunFunction &&run, bool front = false);
-
- void wait(); /* wait until all tasks are done */
- void cancel(); /* cancel all tasks, keep worker thread running */
-
- bool canceled(); /* for worker thread, test if canceled */
-
- protected:
- void num_decrease(int done);
- void num_increase();
-
- void thread_run();
- bool thread_wait_pop(TaskRunFunction &task);
-
- void clear();
-
- thread_mutex num_mutex;
- thread_condition_variable num_cond;
-
- list<TaskRunFunction> queue;
- thread_mutex queue_mutex;
- thread_condition_variable queue_cond;
-
- int num;
- bool do_cancel;
- bool do_exit;
-
- thread *worker_thread;
-};
-
-CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/util/util_tbb.h b/intern/cycles/util/util_tbb.h
deleted file mode 100644
index 8f84377ac8c..00000000000
--- a/intern/cycles/util/util_tbb.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2011-2020 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TBB_H__
-#define __UTIL_TBB_H__
-
-/* TBB includes <windows.h>, do it ourselves first so we are sure
- * WIN32_LEAN_AND_MEAN and similar are defined beforehand. */
-#include "util_windows.h"
-
-#include <tbb/enumerable_thread_specific.h>
-#include <tbb/parallel_for.h>
-#include <tbb/parallel_for_each.h>
-#include <tbb/task_arena.h>
-#include <tbb/task_group.h>
-
-#if TBB_INTERFACE_VERSION_MAJOR >= 10
-# define WITH_TBB_GLOBAL_CONTROL
-# include <tbb/global_control.h>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-using tbb::blocked_range;
-using tbb::enumerable_thread_specific;
-using tbb::parallel_for;
-
-static inline void parallel_for_cancel()
-{
-#if TBB_INTERFACE_VERSION_MAJOR >= 12
- tbb::task_group_context *ctx = tbb::task::current_context();
- if (ctx) {
- ctx->cancel_group_execution();
- }
-#else
- tbb::task::self().cancel_group_execution();
-#endif
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TBB_H__ */
diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h
deleted file mode 100644
index 4de66bf5f46..00000000000
--- a/intern/cycles/util/util_texture.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TEXTURE_H__
-#define __UTIL_TEXTURE_H__
-
-#include "util_transform.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Color to use when textures are not found. */
-#define TEX_IMAGE_MISSING_R 1
-#define TEX_IMAGE_MISSING_G 0
-#define TEX_IMAGE_MISSING_B 1
-#define TEX_IMAGE_MISSING_A 1
-
-/* Interpolation types for textures
- * cuda also use texture space to store other objects */
-typedef enum InterpolationType {
- INTERPOLATION_NONE = -1,
- INTERPOLATION_LINEAR = 0,
- INTERPOLATION_CLOSEST = 1,
- INTERPOLATION_CUBIC = 2,
- INTERPOLATION_SMART = 3,
-
- INTERPOLATION_NUM_TYPES,
-} InterpolationType;
-
-typedef enum ImageDataType {
- IMAGE_DATA_TYPE_FLOAT4 = 0,
- IMAGE_DATA_TYPE_BYTE4 = 1,
- IMAGE_DATA_TYPE_HALF4 = 2,
- IMAGE_DATA_TYPE_FLOAT = 3,
- IMAGE_DATA_TYPE_BYTE = 4,
- IMAGE_DATA_TYPE_HALF = 5,
- IMAGE_DATA_TYPE_USHORT4 = 6,
- IMAGE_DATA_TYPE_USHORT = 7,
- IMAGE_DATA_TYPE_NANOVDB_FLOAT = 8,
- IMAGE_DATA_TYPE_NANOVDB_FLOAT3 = 9,
-
- IMAGE_DATA_NUM_TYPES
-} ImageDataType;
-
-/* Alpha types
- * How to treat alpha in images. */
-typedef enum ImageAlphaType {
- IMAGE_ALPHA_UNASSOCIATED = 0,
- IMAGE_ALPHA_ASSOCIATED = 1,
- IMAGE_ALPHA_CHANNEL_PACKED = 2,
- IMAGE_ALPHA_IGNORE = 3,
- IMAGE_ALPHA_AUTO = 4,
-
- IMAGE_ALPHA_NUM_TYPES,
-} ImageAlphaType;
-
-/* Extension types for textures.
- *
- * Defines how the image is extrapolated past its original bounds. */
-typedef enum ExtensionType {
- /* Cause the image to repeat horizontally and vertically. */
- EXTENSION_REPEAT = 0,
- /* Extend by repeating edge pixels of the image. */
- EXTENSION_EXTEND = 1,
- /* Clip to image size and set exterior pixels as transparent. */
- EXTENSION_CLIP = 2,
-
- EXTENSION_NUM_TYPES,
-} ExtensionType;
-
-typedef struct TextureInfo {
- /* Pointer, offset or texture depending on device. */
- uint64_t data;
- /* Data Type */
- uint data_type;
- /* Interpolation and extension type. */
- uint interpolation, extension;
- /* Dimensions. */
- uint width, height, depth;
- /* Transform for 3D textures. */
- uint use_transform_3d;
- Transform transform_3d;
-} TextureInfo;
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TEXTURE_H__ */
diff --git a/intern/cycles/util/util_thread.cpp b/intern/cycles/util/util_thread.cpp
deleted file mode 100644
index cccde5ae7d5..00000000000
--- a/intern/cycles/util/util_thread.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2011-2016 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_thread.h"
-
-#include "util/util_system.h"
-#include "util/util_windows.h"
-
-CCL_NAMESPACE_BEGIN
-
-thread::thread(function<void()> run_cb, int node) : run_cb_(run_cb), joined_(false), node_(node)
-{
-#ifdef __APPLE__
- /* Set the stack size to 2MB to match Linux. The default 512KB on macOS is
- * too small for Embree, and consistent stack size also makes things more
- * predictable in general. */
- pthread_attr_t attribute;
- pthread_attr_init(&attribute);
- pthread_attr_setstacksize(&attribute, 1024 * 1024 * 2);
- pthread_create(&pthread_id, &attribute, run, (void *)this);
-#else
- std_thread = std::thread(&thread::run, this);
-#endif
-}
-
-thread::~thread()
-{
- if (!joined_) {
- join();
- }
-}
-
-void *thread::run(void *arg)
-{
- thread *self = (thread *)(arg);
- if (self->node_ != -1) {
- system_cpu_run_thread_on_node(self->node_);
- }
- self->run_cb_();
- return NULL;
-}
-
-bool thread::join()
-{
- joined_ = true;
-#ifdef __APPLE__
- return pthread_join(pthread_id, NULL) == 0;
-#else
- try {
- std_thread.join();
- return true;
- }
- catch (const std::system_error &) {
- return false;
- }
-#endif
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h
deleted file mode 100644
index 29f9becbefe..00000000000
--- a/intern/cycles/util/util_thread.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_THREAD_H__
-#define __UTIL_THREAD_H__
-
-#include <condition_variable>
-#include <functional>
-#include <mutex>
-#include <queue>
-#include <thread>
-
-#ifdef _WIN32
-# include "util_windows.h"
-#else
-# include <pthread.h>
-#endif
-
-/* NOTE: Use tbb/spin_mutex.h instead of util_tbb.h because some of the TBB
- * functionality requires RTTI, which is disabled for OSL kernel. */
-#include <tbb/spin_mutex.h>
-
-#include "util/util_function.h"
-
-CCL_NAMESPACE_BEGIN
-
-typedef std::mutex thread_mutex;
-typedef std::unique_lock<std::mutex> thread_scoped_lock;
-typedef std::condition_variable thread_condition_variable;
-
-/* Own thread implementation similar to std::thread, so we can set a
- * custom stack size on macOS. */
-
-class thread {
- public:
- /* NOTE: Node index of -1 means that affinity will be inherited from the
- * parent thread and no override on top of that will happen. */
- thread(function<void()> run_cb, int node = -1);
- ~thread();
-
- static void *run(void *arg);
- bool join();
-
- protected:
- function<void()> run_cb_;
-#ifdef __APPLE__
- pthread_t pthread_id;
-#else
- std::thread std_thread;
-#endif
- bool joined_;
- int node_;
-};
-
-using thread_spin_lock = tbb::spin_mutex;
-
-class thread_scoped_spin_lock {
- public:
- explicit thread_scoped_spin_lock(thread_spin_lock &lock) : lock_(lock)
- {
- lock_.lock();
- }
-
- ~thread_scoped_spin_lock()
- {
- lock_.unlock();
- }
-
- /* TODO(sergey): Implement manual control over lock/unlock. */
-
- protected:
- thread_spin_lock &lock_;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_THREAD_H__ */
diff --git a/intern/cycles/util/util_time.cpp b/intern/cycles/util/util_time.cpp
deleted file mode 100644
index 1641395d07e..00000000000
--- a/intern/cycles/util/util_time.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/util_time.h"
-
-#include <stdlib.h>
-
-#if !defined(_WIN32)
-# include <sys/time.h>
-# include <unistd.h>
-#endif
-
-#include "util/util_math.h"
-#include "util/util_string.h"
-#include "util/util_windows.h"
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef _WIN32
-double time_dt()
-{
- __int64 frequency, counter;
-
- QueryPerformanceFrequency((LARGE_INTEGER *)&frequency);
- QueryPerformanceCounter((LARGE_INTEGER *)&counter);
-
- return (double)counter / (double)frequency;
-}
-
-void time_sleep(double t)
-{
- Sleep((int)(t * 1000));
-}
-#else
-double time_dt()
-{
- struct timeval now;
- gettimeofday(&now, NULL);
-
- return now.tv_sec + now.tv_usec * 1e-6;
-}
-
-/* sleep t seconds */
-void time_sleep(double t)
-{
- /* get whole seconds */
- int s = (int)t;
-
- if (s >= 1) {
- sleep(s);
-
- /* adjust parameter to remove whole seconds */
- t -= s;
- }
-
- /* get microseconds */
- int us = (int)(t * 1e6);
- if (us > 0)
- usleep(us);
-}
-#endif
-
-/* Time in format "hours:minutes:seconds.hundreds" */
-
-string time_human_readable_from_seconds(const double seconds)
-{
- const int h = (((int)seconds) / (60 * 60));
- const int m = (((int)seconds) / 60) % 60;
- const int s = (((int)seconds) % 60);
- const int r = (((int)(seconds * 100)) % 100);
-
- if (h > 0) {
- return string_printf("%.2d:%.2d:%.2d.%.2d", h, m, s, r);
- }
- else {
- return string_printf("%.2d:%.2d.%.2d", m, s, r);
- }
-}
-
-double time_human_readable_to_seconds(const string &time_string)
-{
- /* Those are multiplies of a corresponding token surrounded by : in the
- * time string, which denotes how to convert value to seconds.
- * Effectively: seconds, minutes, hours, days in seconds. */
- const int multipliers[] = {1, 60, 60 * 60, 24 * 60 * 60};
- const int num_multiplies = sizeof(multipliers) / sizeof(*multipliers);
- if (time_string.empty()) {
- return 0.0;
- }
- double result = 0.0;
- /* Split fractions of a second from the encoded time. */
- vector<string> fraction_tokens;
- string_split(fraction_tokens, time_string, ".", false);
- const int num_fraction_tokens = fraction_tokens.size();
- if (num_fraction_tokens == 0) {
- /* Time string is malformed. */
- return 0.0;
- }
- else if (fraction_tokens.size() == 1) {
- /* There is no fraction of a second specified, the rest of the code
- * handles this normally. */
- }
- else if (fraction_tokens.size() == 2) {
- result = atof(fraction_tokens[1].c_str());
- result *= pow(0.1, fraction_tokens[1].length());
- }
- else {
- /* This is not a valid string, the result can not be reliable. */
- return 0.0;
- }
- /* Split hours, minutes and seconds.
- * Hours part is optional. */
- vector<string> tokens;
- string_split(tokens, fraction_tokens[0], ":", false);
- const int num_tokens = tokens.size();
- if (num_tokens > num_multiplies) {
- /* Can not reliably represent the value. */
- return 0.0;
- }
- for (int i = 0; i < num_tokens; ++i) {
- result += atoi(tokens[num_tokens - i - 1].c_str()) * multipliers[i];
- }
- return result;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_time.h b/intern/cycles/util/util_time.h
deleted file mode 100644
index a82d400a0d7..00000000000
--- a/intern/cycles/util/util_time.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TIME_H__
-#define __UTIL_TIME_H__
-
-#include "util/util_function.h"
-#include "util/util_string.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Give current time in seconds in double precision, with good accuracy. */
-
-double time_dt();
-
-/* Sleep for the specified number of seconds. */
-
-void time_sleep(double t);
-
-/* Scoped timer. */
-
-class scoped_timer {
- public:
- explicit scoped_timer(double *value = NULL) : value_(value)
- {
- time_start_ = time_dt();
- }
-
- ~scoped_timer()
- {
- if (value_ != NULL) {
- *value_ = get_time();
- }
- }
-
- double get_start() const
- {
- return time_start_;
- }
-
- double get_time() const
- {
- return time_dt() - time_start_;
- }
-
- protected:
- double *value_;
- double time_start_;
-};
-
-class scoped_callback_timer {
- public:
- using callback_type = function<void(double)>;
-
- explicit scoped_callback_timer(callback_type cb) : cb(cb)
- {
- }
-
- ~scoped_callback_timer()
- {
- if (cb) {
- cb(timer.get_time());
- }
- }
-
- protected:
- scoped_timer timer;
- callback_type cb;
-};
-
-/* Make human readable string from time, compatible with Blender metadata. */
-
-string time_human_readable_from_seconds(const double seconds);
-double time_human_readable_to_seconds(const string &str);
-
-CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/util/util_transform.cpp b/intern/cycles/util/util_transform.cpp
deleted file mode 100644
index e8233b7fe6d..00000000000
--- a/intern/cycles/util/util_transform.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Adapted from code with license:
- *
- * Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
- * Digital Ltd. LLC. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Industrial Light & Magic nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "util/util_transform.h"
-#include "util/util_projection.h"
-
-#include "util/util_boundbox.h"
-#include "util/util_math.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Transform Inverse */
-
-static bool transform_matrix4_gj_inverse(float R[][4], float M[][4])
-{
- /* forward elimination */
- for (int i = 0; i < 4; i++) {
- int pivot = i;
- float pivotsize = M[i][i];
-
- if (pivotsize < 0)
- pivotsize = -pivotsize;
-
- for (int j = i + 1; j < 4; j++) {
- float tmp = M[j][i];
-
- if (tmp < 0)
- tmp = -tmp;
-
- if (tmp > pivotsize) {
- pivot = j;
- pivotsize = tmp;
- }
- }
-
- if (UNLIKELY(pivotsize == 0.0f))
- return false;
-
- if (pivot != i) {
- for (int j = 0; j < 4; j++) {
- float tmp;
-
- tmp = M[i][j];
- M[i][j] = M[pivot][j];
- M[pivot][j] = tmp;
-
- tmp = R[i][j];
- R[i][j] = R[pivot][j];
- R[pivot][j] = tmp;
- }
- }
-
- for (int j = i + 1; j < 4; j++) {
- float f = M[j][i] / M[i][i];
-
- for (int k = 0; k < 4; k++) {
- M[j][k] -= f * M[i][k];
- R[j][k] -= f * R[i][k];
- }
- }
- }
-
- /* backward substitution */
- for (int i = 3; i >= 0; --i) {
- float f;
-
- if (UNLIKELY((f = M[i][i]) == 0.0f))
- return false;
-
- for (int j = 0; j < 4; j++) {
- M[i][j] /= f;
- R[i][j] /= f;
- }
-
- for (int j = 0; j < i; j++) {
- f = M[j][i];
-
- for (int k = 0; k < 4; k++) {
- M[j][k] -= f * M[i][k];
- R[j][k] -= f * R[i][k];
- }
- }
- }
-
- return true;
-}
-
-ProjectionTransform projection_inverse(const ProjectionTransform &tfm)
-{
- ProjectionTransform tfmR = projection_identity();
- float M[4][4], R[4][4];
-
- memcpy(R, &tfmR, sizeof(R));
- memcpy(M, &tfm, sizeof(M));
-
- if (UNLIKELY(!transform_matrix4_gj_inverse(R, M))) {
- /* matrix is degenerate (e.g. 0 scale on some axis), ideally we should
- * never be in this situation, but try to invert it anyway with tweak */
- M[0][0] += 1e-8f;
- M[1][1] += 1e-8f;
- M[2][2] += 1e-8f;
-
- if (UNLIKELY(!transform_matrix4_gj_inverse(R, M))) {
- return projection_identity();
- }
- }
-
- memcpy(&tfmR, R, sizeof(R));
-
- return tfmR;
-}
-
-Transform transform_inverse(const Transform &tfm)
-{
- ProjectionTransform projection(tfm);
- return projection_to_transform(projection_inverse(projection));
-}
-
-Transform transform_transposed_inverse(const Transform &tfm)
-{
- ProjectionTransform projection(tfm);
- ProjectionTransform iprojection = projection_inverse(projection);
- return projection_to_transform(projection_transpose(iprojection));
-}
-
-/* Motion Transform */
-
-float4 transform_to_quat(const Transform &tfm)
-{
- double trace = (double)(tfm[0][0] + tfm[1][1] + tfm[2][2]);
- float4 qt;
-
- if (trace > 0.0) {
- double s = sqrt(trace + 1.0);
-
- qt.w = (float)(s / 2.0);
- s = 0.5 / s;
-
- qt.x = (float)((double)(tfm[2][1] - tfm[1][2]) * s);
- qt.y = (float)((double)(tfm[0][2] - tfm[2][0]) * s);
- qt.z = (float)((double)(tfm[1][0] - tfm[0][1]) * s);
- }
- else {
- int i = 0;
-
- if (tfm[1][1] > tfm[i][i])
- i = 1;
- if (tfm[2][2] > tfm[i][i])
- i = 2;
-
- int j = (i + 1) % 3;
- int k = (j + 1) % 3;
-
- double s = sqrt((double)(tfm[i][i] - (tfm[j][j] + tfm[k][k])) + 1.0);
-
- double q[3];
- q[i] = s * 0.5;
- if (s != 0.0)
- s = 0.5 / s;
-
- double w = (double)(tfm[k][j] - tfm[j][k]) * s;
- q[j] = (double)(tfm[j][i] + tfm[i][j]) * s;
- q[k] = (double)(tfm[k][i] + tfm[i][k]) * s;
-
- qt.x = (float)q[0];
- qt.y = (float)q[1];
- qt.z = (float)q[2];
- qt.w = (float)w;
- }
-
- return qt;
-}
-
-static void transform_decompose(DecomposedTransform *decomp, const Transform *tfm)
-{
- /* extract translation */
- decomp->y = make_float4(tfm->x.w, tfm->y.w, tfm->z.w, 0.0f);
-
- /* extract rotation */
- Transform M = *tfm;
- M.x.w = 0.0f;
- M.y.w = 0.0f;
- M.z.w = 0.0f;
-
-#if 0
- Transform R = M;
- float norm;
- int iteration = 0;
-
- do {
- Transform Rnext;
- Transform Rit = transform_transposed_inverse(R);
-
- for (int i = 0; i < 3; i++)
- for (int j = 0; j < 4; j++)
- Rnext[i][j] = 0.5f * (R[i][j] + Rit[i][j]);
-
- norm = 0.0f;
- for (int i = 0; i < 3; i++) {
- norm = max(norm,
- fabsf(R[i][0] - Rnext[i][0]) + fabsf(R[i][1] - Rnext[i][1]) +
- fabsf(R[i][2] - Rnext[i][2]));
- }
-
- R = Rnext;
- iteration++;
- } while (iteration < 100 && norm > 1e-4f);
-
- if (transform_negative_scale(R))
- R = R * transform_scale(-1.0f, -1.0f, -1.0f);
-
- decomp->x = transform_to_quat(R);
-
- /* extract scale and pack it */
- Transform scale = transform_inverse(R) * M;
- decomp->y.w = scale.x.x;
- decomp->z = make_float4(scale.x.y, scale.x.z, scale.y.x, scale.y.y);
- decomp->w = make_float4(scale.y.z, scale.z.x, scale.z.y, scale.z.z);
-#else
- float3 colx = transform_get_column(&M, 0);
- float3 coly = transform_get_column(&M, 1);
- float3 colz = transform_get_column(&M, 2);
-
- /* extract scale and shear first */
- float3 scale, shear;
- scale.x = len(colx);
- colx = safe_divide_float3_float(colx, scale.x);
- shear.z = dot(colx, coly);
- coly -= shear.z * colx;
- scale.y = len(coly);
- coly = safe_divide_float3_float(coly, scale.y);
- shear.y = dot(colx, colz);
- colz -= shear.y * colx;
- shear.x = dot(coly, colz);
- colz -= shear.x * coly;
- scale.z = len(colz);
- colz = safe_divide_float3_float(colz, scale.z);
-
- transform_set_column(&M, 0, colx);
- transform_set_column(&M, 1, coly);
- transform_set_column(&M, 2, colz);
-
- if (transform_negative_scale(M)) {
- scale *= -1.0f;
- M = M * transform_scale(-1.0f, -1.0f, -1.0f);
- }
-
- decomp->x = transform_to_quat(M);
-
- decomp->y.w = scale.x;
- decomp->z = make_float4(shear.z, shear.y, 0.0f, scale.y);
- decomp->w = make_float4(shear.x, 0.0f, 0.0f, scale.z);
-#endif
-}
-
-void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size)
-{
- /* Decompose and correct rotation. */
- for (size_t i = 0; i < size; i++) {
- transform_decompose(decomp + i, motion + i);
-
- if (i > 0) {
- /* Ensure rotation around shortest angle, negated quaternions are the same
- * but this means we don't have to do the check in quat_interpolate */
- if (dot(decomp[i - 1].x, decomp[i].x) < 0.0f)
- decomp[i].x = -decomp[i].x;
- }
- }
-
- /* Copy rotation to decomposed transform where scale is degenerate. This avoids weird object
- * rotation interpolation when the scale goes to 0 for a time step.
- *
- * Note that this is very simple and naive implementation, which only deals with degenerated
- * scale happening only on one frame. It is possible to improve it further by interpolating
- * rotation into s degenerated range using rotation from time-steps from adjacent non-degenerated
- * time steps. */
- for (size_t i = 0; i < size; i++) {
- const float3 scale = make_float3(decomp[i].y.w, decomp[i].z.w, decomp[i].w.w);
- if (!is_zero(scale)) {
- continue;
- }
-
- if (i > 0) {
- decomp[i].x = decomp[i - 1].x;
- }
- else if (i < size - 1) {
- decomp[i].x = decomp[i + 1].x;
- }
- }
-}
-
-Transform transform_from_viewplane(BoundBox2D &viewplane)
-{
- return transform_scale(1.0f / (viewplane.right - viewplane.left),
- 1.0f / (viewplane.top - viewplane.bottom),
- 1.0f) *
- transform_translate(-viewplane.left, -viewplane.bottom, 0.0f);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h
deleted file mode 100644
index fc04f9aab46..00000000000
--- a/intern/cycles/util/util_transform.h
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TRANSFORM_H__
-#define __UTIL_TRANSFORM_H__
-
-#ifndef __KERNEL_GPU__
-# include <string.h>
-#endif
-
-#include "util/util_math.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Affine transformation, stored as 4x3 matrix. */
-
-typedef struct Transform {
- float4 x, y, z;
-
-#ifndef __KERNEL_GPU__
- float4 operator[](int i) const
- {
- return *(&x + i);
- }
- float4 &operator[](int i)
- {
- return *(&x + i);
- }
-#endif
-} Transform;
-
-/* Transform decomposed in rotation/translation/scale. we use the same data
- * structure as Transform, and tightly pack decomposition into it. first the
- * rotation (4), then translation (3), then 3x3 scale matrix (9). */
-
-typedef struct DecomposedTransform {
- float4 x, y, z, w;
-} DecomposedTransform;
-
-/* Functions */
-
-ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
-{
- /* TODO(sergey): Disabled for now, causes crashes in certain cases. */
-#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
- ssef x, y, z, w, aa;
- aa = a.m128;
-
- x = _mm_loadu_ps(&t->x.x);
- y = _mm_loadu_ps(&t->y.x);
- z = _mm_loadu_ps(&t->z.x);
- w = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
-
- _MM_TRANSPOSE4_PS(x, y, z, w);
-
- ssef tmp = shuffle<0>(aa) * x;
- tmp = madd(shuffle<1>(aa), y, tmp);
- tmp = madd(shuffle<2>(aa), z, tmp);
- tmp += w;
-
- return float3(tmp.m128);
-#else
- float3 c = make_float3(a.x * t->x.x + a.y * t->x.y + a.z * t->x.z + t->x.w,
- a.x * t->y.x + a.y * t->y.y + a.z * t->y.z + t->y.w,
- a.x * t->z.x + a.y * t->z.y + a.z * t->z.z + t->z.w);
-
- return c;
-#endif
-}
-
-ccl_device_inline float3 transform_direction(ccl_private const Transform *t, const float3 a)
-{
-#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
- ssef x, y, z, w, aa;
- aa = a.m128;
- x = _mm_loadu_ps(&t->x.x);
- y = _mm_loadu_ps(&t->y.x);
- z = _mm_loadu_ps(&t->z.x);
- w = _mm_setzero_ps();
-
- _MM_TRANSPOSE4_PS(x, y, z, w);
-
- ssef tmp = shuffle<0>(aa) * x;
- tmp = madd(shuffle<1>(aa), y, tmp);
- tmp = madd(shuffle<2>(aa), z, tmp);
-
- return float3(tmp.m128);
-#else
- float3 c = make_float3(a.x * t->x.x + a.y * t->x.y + a.z * t->x.z,
- a.x * t->y.x + a.y * t->y.y + a.z * t->y.z,
- a.x * t->z.x + a.y * t->z.y + a.z * t->z.z);
-
- return c;
-#endif
-}
-
-ccl_device_inline float3 transform_direction_transposed(ccl_private const Transform *t,
- const float3 a)
-{
- float3 x = make_float3(t->x.x, t->y.x, t->z.x);
- float3 y = make_float3(t->x.y, t->y.y, t->z.y);
- float3 z = make_float3(t->x.z, t->y.z, t->z.z);
-
- return make_float3(dot(x, a), dot(y, a), dot(z, a));
-}
-
-ccl_device_inline Transform make_transform(float a,
- float b,
- float c,
- float d,
- float e,
- float f,
- float g,
- float h,
- float i,
- float j,
- float k,
- float l)
-{
- Transform t;
-
- t.x.x = a;
- t.x.y = b;
- t.x.z = c;
- t.x.w = d;
- t.y.x = e;
- t.y.y = f;
- t.y.z = g;
- t.y.w = h;
- t.z.x = i;
- t.z.y = j;
- t.z.z = k;
- t.z.w = l;
-
- return t;
-}
-
-ccl_device_inline Transform euler_to_transform(const float3 euler)
-{
- float cx = cosf(euler.x);
- float cy = cosf(euler.y);
- float cz = cosf(euler.z);
- float sx = sinf(euler.x);
- float sy = sinf(euler.y);
- float sz = sinf(euler.z);
-
- Transform t;
- t.x.x = cy * cz;
- t.y.x = cy * sz;
- t.z.x = -sy;
-
- t.x.y = sy * sx * cz - cx * sz;
- t.y.y = sy * sx * sz + cx * cz;
- t.z.y = cy * sx;
-
- t.x.z = sy * cx * cz + sx * sz;
- t.y.z = sy * cx * sz - sx * cz;
- t.z.z = cy * cx;
-
- t.x.w = t.y.w = t.z.w = 0.0f;
- return t;
-}
-
-/* Constructs a coordinate frame from a normalized normal. */
-ccl_device_inline Transform make_transform_frame(float3 N)
-{
- const float3 dx0 = cross(make_float3(1.0f, 0.0f, 0.0f), N);
- const float3 dx1 = cross(make_float3(0.0f, 1.0f, 0.0f), N);
- const float3 dx = normalize((dot(dx0, dx0) > dot(dx1, dx1)) ? dx0 : dx1);
- const float3 dy = normalize(cross(N, dx));
- return make_transform(dx.x, dx.y, dx.z, 0.0f, dy.x, dy.y, dy.z, 0.0f, N.x, N.y, N.z, 0.0f);
-}
-
-#ifndef __KERNEL_GPU__
-
-ccl_device_inline Transform transform_zero()
-{
- Transform zero = {zero_float4(), zero_float4(), zero_float4()};
- return zero;
-}
-
-ccl_device_inline Transform operator*(const Transform a, const Transform b)
-{
- float4 c_x = make_float4(b.x.x, b.y.x, b.z.x, 0.0f);
- float4 c_y = make_float4(b.x.y, b.y.y, b.z.y, 0.0f);
- float4 c_z = make_float4(b.x.z, b.y.z, b.z.z, 0.0f);
- float4 c_w = make_float4(b.x.w, b.y.w, b.z.w, 1.0f);
-
- Transform t;
- t.x = make_float4(dot(a.x, c_x), dot(a.x, c_y), dot(a.x, c_z), dot(a.x, c_w));
- t.y = make_float4(dot(a.y, c_x), dot(a.y, c_y), dot(a.y, c_z), dot(a.y, c_w));
- t.z = make_float4(dot(a.z, c_x), dot(a.z, c_y), dot(a.z, c_z), dot(a.z, c_w));
-
- return t;
-}
-
-ccl_device_inline void print_transform(const char *label, const Transform &t)
-{
- print_float4(label, t.x);
- print_float4(label, t.y);
- print_float4(label, t.z);
- printf("\n");
-}
-
-ccl_device_inline Transform transform_translate(float3 t)
-{
- return make_transform(1, 0, 0, t.x, 0, 1, 0, t.y, 0, 0, 1, t.z);
-}
-
-ccl_device_inline Transform transform_translate(float x, float y, float z)
-{
- return transform_translate(make_float3(x, y, z));
-}
-
-ccl_device_inline Transform transform_scale(float3 s)
-{
- return make_transform(s.x, 0, 0, 0, 0, s.y, 0, 0, 0, 0, s.z, 0);
-}
-
-ccl_device_inline Transform transform_scale(float x, float y, float z)
-{
- return transform_scale(make_float3(x, y, z));
-}
-
-ccl_device_inline Transform transform_rotate(float angle, float3 axis)
-{
- float s = sinf(angle);
- float c = cosf(angle);
- float t = 1.0f - c;
-
- axis = normalize(axis);
-
- return make_transform(axis.x * axis.x * t + c,
- axis.x * axis.y * t - s * axis.z,
- axis.x * axis.z * t + s * axis.y,
- 0.0f,
-
- axis.y * axis.x * t + s * axis.z,
- axis.y * axis.y * t + c,
- axis.y * axis.z * t - s * axis.x,
- 0.0f,
-
- axis.z * axis.x * t - s * axis.y,
- axis.z * axis.y * t + s * axis.x,
- axis.z * axis.z * t + c,
- 0.0f);
-}
-
-/* Euler is assumed to be in XYZ order. */
-ccl_device_inline Transform transform_euler(float3 euler)
-{
- return transform_rotate(euler.z, make_float3(0.0f, 0.0f, 1.0f)) *
- transform_rotate(euler.y, make_float3(0.0f, 1.0f, 0.0f)) *
- transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f));
-}
-
-ccl_device_inline Transform transform_identity()
-{
- return transform_scale(1.0f, 1.0f, 1.0f);
-}
-
-ccl_device_inline bool operator==(const Transform &A, const Transform &B)
-{
- return memcmp(&A, &B, sizeof(Transform)) == 0;
-}
-
-ccl_device_inline bool operator!=(const Transform &A, const Transform &B)
-{
- return !(A == B);
-}
-
-ccl_device_inline float3 transform_get_column(const Transform *t, int column)
-{
- return make_float3(t->x[column], t->y[column], t->z[column]);
-}
-
-ccl_device_inline void transform_set_column(Transform *t, int column, float3 value)
-{
- t->x[column] = value.x;
- t->y[column] = value.y;
- t->z[column] = value.z;
-}
-
-Transform transform_inverse(const Transform &a);
-Transform transform_transposed_inverse(const Transform &a);
-
-ccl_device_inline bool transform_uniform_scale(const Transform &tfm, float &scale)
-{
- /* the epsilon here is quite arbitrary, but this function is only used for
- * surface area and bump, where we expect it to not be so sensitive */
- float eps = 1e-6f;
-
- float sx = len_squared(float4_to_float3(tfm.x));
- float sy = len_squared(float4_to_float3(tfm.y));
- float sz = len_squared(float4_to_float3(tfm.z));
- float stx = len_squared(transform_get_column(&tfm, 0));
- float sty = len_squared(transform_get_column(&tfm, 1));
- float stz = len_squared(transform_get_column(&tfm, 2));
-
- if (fabsf(sx - sy) < eps && fabsf(sx - sz) < eps && fabsf(sx - stx) < eps &&
- fabsf(sx - sty) < eps && fabsf(sx - stz) < eps) {
- scale = sx;
- return true;
- }
-
- return false;
-}
-
-ccl_device_inline bool transform_negative_scale(const Transform &tfm)
-{
- float3 c0 = transform_get_column(&tfm, 0);
- float3 c1 = transform_get_column(&tfm, 1);
- float3 c2 = transform_get_column(&tfm, 2);
-
- return (dot(cross(c0, c1), c2) < 0.0f);
-}
-
-ccl_device_inline Transform transform_clear_scale(const Transform &tfm)
-{
- Transform ntfm = tfm;
-
- transform_set_column(&ntfm, 0, normalize(transform_get_column(&ntfm, 0)));
- transform_set_column(&ntfm, 1, normalize(transform_get_column(&ntfm, 1)));
- transform_set_column(&ntfm, 2, normalize(transform_get_column(&ntfm, 2)));
-
- return ntfm;
-}
-
-ccl_device_inline Transform transform_empty()
-{
- return make_transform(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
-}
-
-#endif
-
-/* Motion Transform */
-
-ccl_device_inline float4 quat_interpolate(float4 q1, float4 q2, float t)
-{
- /* Optix is using lerp to interpolate motion transformations. */
-#ifdef __KERNEL_OPTIX__
- return normalize((1.0f - t) * q1 + t * q2);
-#else /* __KERNEL_OPTIX__ */
- /* note: this does not ensure rotation around shortest angle, q1 and q2
- * are assumed to be matched already in transform_motion_decompose */
- float costheta = dot(q1, q2);
-
- /* possible optimization: it might be possible to precompute theta/qperp */
-
- if (costheta > 0.9995f) {
- /* linear interpolation in degenerate case */
- return normalize((1.0f - t) * q1 + t * q2);
- }
- else {
- /* slerp */
- float theta = acosf(clamp(costheta, -1.0f, 1.0f));
- float4 qperp = normalize(q2 - q1 * costheta);
- float thetap = theta * t;
- return q1 * cosf(thetap) + qperp * sinf(thetap);
- }
-#endif /* __KERNEL_OPTIX__ */
-}
-
-ccl_device_inline Transform transform_quick_inverse(Transform M)
-{
- /* possible optimization: can we avoid doing this altogether and construct
- * the inverse matrix directly from negated translation, transposed rotation,
- * scale can be inverted but what about shearing? */
- Transform R;
- float det = M.x.x * (M.z.z * M.y.y - M.z.y * M.y.z) - M.y.x * (M.z.z * M.x.y - M.z.y * M.x.z) +
- M.z.x * (M.y.z * M.x.y - M.y.y * M.x.z);
- if (det == 0.0f) {
- M.x.x += 1e-8f;
- M.y.y += 1e-8f;
- M.z.z += 1e-8f;
- det = M.x.x * (M.z.z * M.y.y - M.z.y * M.y.z) - M.y.x * (M.z.z * M.x.y - M.z.y * M.x.z) +
- M.z.x * (M.y.z * M.x.y - M.y.y * M.x.z);
- }
- det = (det != 0.0f) ? 1.0f / det : 0.0f;
-
- float3 Rx = det * make_float3(M.z.z * M.y.y - M.z.y * M.y.z,
- M.z.y * M.x.z - M.z.z * M.x.y,
- M.y.z * M.x.y - M.y.y * M.x.z);
- float3 Ry = det * make_float3(M.z.x * M.y.z - M.z.z * M.y.x,
- M.z.z * M.x.x - M.z.x * M.x.z,
- M.y.x * M.x.z - M.y.z * M.x.x);
- float3 Rz = det * make_float3(M.z.y * M.y.x - M.z.x * M.y.y,
- M.z.x * M.x.y - M.z.y * M.x.x,
- M.y.y * M.x.x - M.y.x * M.x.y);
- float3 T = -make_float3(M.x.w, M.y.w, M.z.w);
-
- R.x = make_float4(Rx.x, Rx.y, Rx.z, dot(Rx, T));
- R.y = make_float4(Ry.x, Ry.y, Ry.z, dot(Ry, T));
- R.z = make_float4(Rz.x, Rz.y, Rz.z, dot(Rz, T));
-
- return R;
-}
-
-ccl_device_inline void transform_compose(ccl_private Transform *tfm,
- ccl_private const DecomposedTransform *decomp)
-{
- /* rotation */
- float q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc;
-
- q0 = M_SQRT2_F * decomp->x.w;
- q1 = M_SQRT2_F * decomp->x.x;
- q2 = M_SQRT2_F * decomp->x.y;
- q3 = M_SQRT2_F * decomp->x.z;
-
- qda = q0 * q1;
- qdb = q0 * q2;
- qdc = q0 * q3;
- qaa = q1 * q1;
- qab = q1 * q2;
- qac = q1 * q3;
- qbb = q2 * q2;
- qbc = q2 * q3;
- qcc = q3 * q3;
-
- float3 rotation_x = make_float3(1.0f - qbb - qcc, -qdc + qab, qdb + qac);
- float3 rotation_y = make_float3(qdc + qab, 1.0f - qaa - qcc, -qda + qbc);
- float3 rotation_z = make_float3(-qdb + qac, qda + qbc, 1.0f - qaa - qbb);
-
- /* scale */
- float3 scale_x = make_float3(decomp->y.w, decomp->z.z, decomp->w.y);
- float3 scale_y = make_float3(decomp->z.x, decomp->z.w, decomp->w.z);
- float3 scale_z = make_float3(decomp->z.y, decomp->w.x, decomp->w.w);
-
- /* compose with translation */
- tfm->x = make_float4(
- dot(rotation_x, scale_x), dot(rotation_x, scale_y), dot(rotation_x, scale_z), decomp->y.x);
- tfm->y = make_float4(
- dot(rotation_y, scale_x), dot(rotation_y, scale_y), dot(rotation_y, scale_z), decomp->y.y);
- tfm->z = make_float4(
- dot(rotation_z, scale_x), dot(rotation_z, scale_y), dot(rotation_z, scale_z), decomp->y.z);
-}
-
-/* Interpolate from array of decomposed transforms. */
-ccl_device void transform_motion_array_interpolate(Transform *tfm,
- const DecomposedTransform *motion,
- uint numsteps,
- float time)
-{
- /* Figure out which steps we need to interpolate. */
- int maxstep = numsteps - 1;
- int step = min((int)(time * maxstep), maxstep - 1);
- float t = time * maxstep - step;
-
- const DecomposedTransform *a = motion + step;
- const DecomposedTransform *b = motion + step + 1;
-
- /* Interpolate rotation, translation and scale. */
- DecomposedTransform decomp;
- decomp.x = quat_interpolate(a->x, b->x, t);
- decomp.y = (1.0f - t) * a->y + t * b->y;
- decomp.z = (1.0f - t) * a->z + t * b->z;
- decomp.w = (1.0f - t) * a->w + t * b->w;
-
- /* Compose rotation, translation, scale into matrix. */
- transform_compose(tfm, &decomp);
-}
-
-ccl_device_inline bool transform_isfinite_safe(ccl_private Transform *tfm)
-{
- return isfinite4_safe(tfm->x) && isfinite4_safe(tfm->y) && isfinite4_safe(tfm->z);
-}
-
-ccl_device_inline bool transform_decomposed_isfinite_safe(ccl_private DecomposedTransform *decomp)
-{
- return isfinite4_safe(decomp->x) && isfinite4_safe(decomp->y) && isfinite4_safe(decomp->z) &&
- isfinite4_safe(decomp->w);
-}
-
-#ifndef __KERNEL_GPU__
-
-class BoundBox2D;
-
-ccl_device_inline bool operator==(const DecomposedTransform &A, const DecomposedTransform &B)
-{
- return memcmp(&A, &B, sizeof(DecomposedTransform)) == 0;
-}
-
-float4 transform_to_quat(const Transform &tfm);
-void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size);
-Transform transform_from_viewplane(BoundBox2D &viewplane);
-
-#endif
-
-/* TODO: This can be removed when we know if no devices will require explicit
- * address space qualifiers for this case. */
-
-#define transform_point_auto transform_point
-#define transform_direction_auto transform_direction
-#define transform_direction_transposed_auto transform_direction_transposed
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TRANSFORM_H__ */
diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h
deleted file mode 100644
index 442c32b3a3d..00000000000
--- a/intern/cycles/util/util_types.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_H__
-#define __UTIL_TYPES_H__
-
-#include <stdlib.h>
-
-/* Standard Integer Types */
-
-#if !defined(__KERNEL_GPU__)
-# include <stdint.h>
-#endif
-
-#include "util/util_defines.h"
-
-#ifndef __KERNEL_GPU__
-# include "util/util_optimization.h"
-# include "util/util_simd.h"
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/* Types
- *
- * Define simpler unsigned type names, and integer with defined number of bits.
- * Also vector types, named to be compatible with OpenCL builtin types, while
- * working for CUDA and C++ too. */
-
-/* Shorter Unsigned Names */
-
-typedef unsigned char uchar;
-typedef unsigned int uint;
-typedef unsigned short ushort;
-
-/* Fixed Bits Types */
-
-#ifndef __KERNEL_GPU__
-/* Generic Memory Pointer */
-
-typedef uint64_t device_ptr;
-#endif /* __KERNEL_GPU__ */
-
-ccl_device_inline size_t align_up(size_t offset, size_t alignment)
-{
- return (offset + alignment - 1) & ~(alignment - 1);
-}
-
-ccl_device_inline size_t divide_up(size_t x, size_t y)
-{
- return (x + y - 1) / y;
-}
-
-ccl_device_inline size_t round_up(size_t x, size_t multiple)
-{
- return ((x + multiple - 1) / multiple) * multiple;
-}
-
-ccl_device_inline size_t round_down(size_t x, size_t multiple)
-{
- return (x / multiple) * multiple;
-}
-
-ccl_device_inline bool is_power_of_two(size_t x)
-{
- return (x & (x - 1)) == 0;
-}
-
-CCL_NAMESPACE_END
-
-/* Vectorized types declaration. */
-#include "util/util_types_uchar2.h"
-#include "util/util_types_uchar3.h"
-#include "util/util_types_uchar4.h"
-
-#include "util/util_types_int2.h"
-#include "util/util_types_int3.h"
-#include "util/util_types_int4.h"
-
-#include "util/util_types_uint2.h"
-#include "util/util_types_uint3.h"
-#include "util/util_types_uint4.h"
-
-#include "util/util_types_ushort4.h"
-
-#include "util/util_types_float2.h"
-#include "util/util_types_float3.h"
-#include "util/util_types_float4.h"
-#include "util/util_types_float8.h"
-
-#include "util/util_types_vector3.h"
-
-/* Vectorized types implementation. */
-#include "util/util_types_uchar2_impl.h"
-#include "util/util_types_uchar3_impl.h"
-#include "util/util_types_uchar4_impl.h"
-
-#include "util/util_types_int2_impl.h"
-#include "util/util_types_int3_impl.h"
-#include "util/util_types_int4_impl.h"
-
-#include "util/util_types_uint2_impl.h"
-#include "util/util_types_uint3_impl.h"
-#include "util/util_types_uint4_impl.h"
-
-#include "util/util_types_float2_impl.h"
-#include "util/util_types_float3_impl.h"
-#include "util/util_types_float4_impl.h"
-#include "util/util_types_float8_impl.h"
-
-#include "util/util_types_vector3_impl.h"
-
-/* SSE types. */
-#ifndef __KERNEL_GPU__
-# include "util/util_sseb.h"
-# include "util/util_ssef.h"
-# include "util/util_ssei.h"
-# if defined(__KERNEL_AVX__) || defined(__KERNEL_AVX2__)
-# include "util/util_avxb.h"
-# include "util/util_avxf.h"
-# include "util/util_avxi.h"
-# endif
-#endif
-
-#endif /* __UTIL_TYPES_H__ */
diff --git a/intern/cycles/util/util_types_float2.h b/intern/cycles/util/util_types_float2.h
deleted file mode 100644
index 3760bf579b6..00000000000
--- a/intern/cycles/util/util_types_float2.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_FLOAT2_H__
-#define __UTIL_TYPES_FLOAT2_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct float2 {
- float x, y;
-
- __forceinline float operator[](int i) const;
- __forceinline float &operator[](int i);
-};
-
-ccl_device_inline float2 make_float2(float x, float y);
-ccl_device_inline void print_float2(const char *label, const float2 &a);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT2_H__ */
diff --git a/intern/cycles/util/util_types_float2_impl.h b/intern/cycles/util/util_types_float2_impl.h
deleted file mode 100644
index 7810d2a8781..00000000000
--- a/intern/cycles/util/util_types_float2_impl.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_FLOAT2_IMPL_H__
-#define __UTIL_TYPES_FLOAT2_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-__forceinline float float2::operator[](int i) const
-{
- util_assert(i >= 0);
- util_assert(i < 2);
- return *(&x + i);
-}
-
-__forceinline float &float2::operator[](int i)
-{
- util_assert(i >= 0);
- util_assert(i < 2);
- return *(&x + i);
-}
-
-ccl_device_inline float2 make_float2(float x, float y)
-{
- float2 a = {x, y};
- return a;
-}
-
-ccl_device_inline void print_float2(const char *label, const float2 &a)
-{
- printf("%s: %.8f %.8f\n", label, (double)a.x, (double)a.y);
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT2_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_float3.h b/intern/cycles/util/util_types_float3.h
deleted file mode 100644
index 694a600bf5c..00000000000
--- a/intern/cycles/util/util_types_float3.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_FLOAT3_H__
-#define __UTIL_TYPES_FLOAT3_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct ccl_try_align(16) float3
-{
-# ifdef __KERNEL_SSE__
- union {
- __m128 m128;
- struct {
- float x, y, z, w;
- };
- };
-
- __forceinline float3();
- __forceinline float3(const float3 &a);
- __forceinline explicit float3(const __m128 &a);
-
- __forceinline operator const __m128 &() const;
- __forceinline operator __m128 &();
-
- __forceinline float3 &operator=(const float3 &a);
-# else /* __KERNEL_SSE__ */
- float x, y, z, w;
-# endif /* __KERNEL_SSE__ */
-
- __forceinline float operator[](int i) const;
- __forceinline float &operator[](int i);
-};
-
-ccl_device_inline float3 make_float3(float f);
-ccl_device_inline float3 make_float3(float x, float y, float z);
-ccl_device_inline void print_float3(const char *label, const float3 &a);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT3_H__ */
diff --git a/intern/cycles/util/util_types_float3_impl.h b/intern/cycles/util/util_types_float3_impl.h
deleted file mode 100644
index ab25fb4c975..00000000000
--- a/intern/cycles/util/util_types_float3_impl.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_FLOAT3_IMPL_H__
-#define __UTIL_TYPES_FLOAT3_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-# ifdef __KERNEL_SSE__
-__forceinline float3::float3()
-{
-}
-
-__forceinline float3::float3(const float3 &a) : m128(a.m128)
-{
-}
-
-__forceinline float3::float3(const __m128 &a) : m128(a)
-{
-}
-
-__forceinline float3::operator const __m128 &() const
-{
- return m128;
-}
-
-__forceinline float3::operator __m128 &()
-{
- return m128;
-}
-
-__forceinline float3 &float3::operator=(const float3 &a)
-{
- m128 = a.m128;
- return *this;
-}
-# endif /* __KERNEL_SSE__ */
-
-__forceinline float float3::operator[](int i) const
-{
- util_assert(i >= 0);
- util_assert(i < 3);
- return *(&x + i);
-}
-
-__forceinline float &float3::operator[](int i)
-{
- util_assert(i >= 0);
- util_assert(i < 3);
- return *(&x + i);
-}
-
-ccl_device_inline float3 make_float3(float f)
-{
-# ifdef __KERNEL_SSE__
- float3 a(_mm_set1_ps(f));
-# else
- float3 a = {f, f, f, f};
-# endif
- return a;
-}
-
-ccl_device_inline float3 make_float3(float x, float y, float z)
-{
-# ifdef __KERNEL_SSE__
- float3 a(_mm_set_ps(0.0f, z, y, x));
-# else
- float3 a = {x, y, z, 0.0f};
-# endif
- return a;
-}
-
-ccl_device_inline void print_float3(const char *label, const float3 &a)
-{
- printf("%s: %.8f %.8f %.8f\n", label, (double)a.x, (double)a.y, (double)a.z);
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT3_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_float4.h b/intern/cycles/util/util_types_float4.h
deleted file mode 100644
index c29e6e15bc3..00000000000
--- a/intern/cycles/util/util_types_float4.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_FLOAT4_H__
-#define __UTIL_TYPES_FLOAT4_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct int4;
-
-struct ccl_try_align(16) float4
-{
-# ifdef __KERNEL_SSE__
- union {
- __m128 m128;
- struct {
- float x, y, z, w;
- };
- };
-
- __forceinline float4();
- __forceinline explicit float4(const __m128 &a);
-
- __forceinline operator const __m128 &() const;
- __forceinline operator __m128 &();
-
- __forceinline float4 &operator=(const float4 &a);
-
-# else /* __KERNEL_SSE__ */
- float x, y, z, w;
-# endif /* __KERNEL_SSE__ */
-
- __forceinline float operator[](int i) const;
- __forceinline float &operator[](int i);
-};
-
-ccl_device_inline float4 make_float4(float f);
-ccl_device_inline float4 make_float4(float x, float y, float z, float w);
-ccl_device_inline float4 make_float4(const int4 &i);
-ccl_device_inline void print_float4(const char *label, const float4 &a);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT4_H__ */
diff --git a/intern/cycles/util/util_types_float4_impl.h b/intern/cycles/util/util_types_float4_impl.h
deleted file mode 100644
index 05a1feee5b2..00000000000
--- a/intern/cycles/util/util_types_float4_impl.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_FLOAT4_IMPL_H__
-#define __UTIL_TYPES_FLOAT4_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-# ifdef __KERNEL_SSE__
-__forceinline float4::float4()
-{
-}
-
-__forceinline float4::float4(const __m128 &a) : m128(a)
-{
-}
-
-__forceinline float4::operator const __m128 &() const
-{
- return m128;
-}
-
-__forceinline float4::operator __m128 &()
-{
- return m128;
-}
-
-__forceinline float4 &float4::operator=(const float4 &a)
-{
- m128 = a.m128;
- return *this;
-}
-# endif /* __KERNEL_SSE__ */
-
-__forceinline float float4::operator[](int i) const
-{
- util_assert(i >= 0);
- util_assert(i < 4);
- return *(&x + i);
-}
-
-__forceinline float &float4::operator[](int i)
-{
- util_assert(i >= 0);
- util_assert(i < 4);
- return *(&x + i);
-}
-
-ccl_device_inline float4 make_float4(float f)
-{
-# ifdef __KERNEL_SSE__
- float4 a(_mm_set1_ps(f));
-# else
- float4 a = {f, f, f, f};
-# endif
- return a;
-}
-
-ccl_device_inline float4 make_float4(float x, float y, float z, float w)
-{
-# ifdef __KERNEL_SSE__
- float4 a(_mm_set_ps(w, z, y, x));
-# else
- float4 a = {x, y, z, w};
-# endif
- return a;
-}
-
-ccl_device_inline float4 make_float4(const int4 &i)
-{
-# ifdef __KERNEL_SSE__
- float4 a(_mm_cvtepi32_ps(i.m128));
-# else
- float4 a = {(float)i.x, (float)i.y, (float)i.z, (float)i.w};
-# endif
- return a;
-}
-
-ccl_device_inline void print_float4(const char *label, const float4 &a)
-{
- printf("%s: %.8f %.8f %.8f %.8f\n", label, (double)a.x, (double)a.y, (double)a.z, (double)a.w);
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT4_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_float8.h b/intern/cycles/util/util_types_float8.h
deleted file mode 100644
index 27da120a4ba..00000000000
--- a/intern/cycles/util/util_types_float8.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Original code Copyright 2017, Intel Corporation
- * Modifications Copyright 2018, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Intel Corporation nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __UTIL_TYPES_FLOAT8_H__
-#define __UTIL_TYPES_FLOAT8_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-
-struct ccl_try_align(32) float8
-{
-# ifdef __KERNEL_AVX2__
- union {
- __m256 m256;
- struct {
- float a, b, c, d, e, f, g, h;
- };
- };
-
- __forceinline float8();
- __forceinline float8(const float8 &a);
- __forceinline explicit float8(const __m256 &a);
-
- __forceinline operator const __m256 &() const;
- __forceinline operator __m256 &();
-
- __forceinline float8 &operator=(const float8 &a);
-
-# else /* __KERNEL_AVX2__ */
- float a, b, c, d, e, f, g, h;
-# endif /* __KERNEL_AVX2__ */
-
- __forceinline float operator[](int i) const;
- __forceinline float &operator[](int i);
-};
-
-ccl_device_inline float8 make_float8(float f);
-ccl_device_inline float8
-make_float8(float a, float b, float c, float d, float e, float f, float g, float h);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT8_H__ */
diff --git a/intern/cycles/util/util_types_float8_impl.h b/intern/cycles/util/util_types_float8_impl.h
deleted file mode 100644
index 4e4ea28c6a4..00000000000
--- a/intern/cycles/util/util_types_float8_impl.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Original code Copyright 2017, Intel Corporation
- * Modifications Copyright 2018, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Intel Corporation nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __UTIL_TYPES_FLOAT8_IMPL_H__
-#define __UTIL_TYPES_FLOAT8_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-# ifdef __KERNEL_AVX2__
-__forceinline float8::float8()
-{
-}
-
-__forceinline float8::float8(const float8 &f) : m256(f.m256)
-{
-}
-
-__forceinline float8::float8(const __m256 &f) : m256(f)
-{
-}
-
-__forceinline float8::operator const __m256 &() const
-{
- return m256;
-}
-
-__forceinline float8::operator __m256 &()
-{
- return m256;
-}
-
-__forceinline float8 &float8::operator=(const float8 &f)
-{
- m256 = f.m256;
- return *this;
-}
-# endif /* __KERNEL_AVX2__ */
-
-__forceinline float float8::operator[](int i) const
-{
- util_assert(i >= 0);
- util_assert(i < 8);
- return *(&a + i);
-}
-
-__forceinline float &float8::operator[](int i)
-{
- util_assert(i >= 0);
- util_assert(i < 8);
- return *(&a + i);
-}
-
-ccl_device_inline float8 make_float8(float f)
-{
-# ifdef __KERNEL_AVX2__
- float8 r(_mm256_set1_ps(f));
-# else
- float8 r = {f, f, f, f, f, f, f, f};
-# endif
- return r;
-}
-
-ccl_device_inline float8
-make_float8(float a, float b, float c, float d, float e, float f, float g, float h)
-{
-# ifdef __KERNEL_AVX2__
- float8 r(_mm256_set_ps(a, b, c, d, e, f, g, h));
-# else
- float8 r = {a, b, c, d, e, f, g, h};
-# endif
- return r;
-}
-
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT8_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_int2.h b/intern/cycles/util/util_types_int2.h
deleted file mode 100644
index 8811e5ec7c2..00000000000
--- a/intern/cycles/util/util_types_int2.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_INT2_H__
-#define __UTIL_TYPES_INT2_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct int2 {
- int x, y;
-
- __forceinline int operator[](int i) const;
- __forceinline int &operator[](int i);
-};
-
-ccl_device_inline int2 make_int2(int x, int y);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT2_H__ */
diff --git a/intern/cycles/util/util_types_int2_impl.h b/intern/cycles/util/util_types_int2_impl.h
deleted file mode 100644
index ce95d4f14e5..00000000000
--- a/intern/cycles/util/util_types_int2_impl.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_INT2_IMPL_H__
-#define __UTIL_TYPES_INT2_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-int int2::operator[](int i) const
-{
- util_assert(i >= 0);
- util_assert(i < 2);
- return *(&x + i);
-}
-
-int &int2::operator[](int i)
-{
- util_assert(i >= 0);
- util_assert(i < 2);
- return *(&x + i);
-}
-
-ccl_device_inline int2 make_int2(int x, int y)
-{
- int2 a = {x, y};
- return a;
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT2_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_int3.h b/intern/cycles/util/util_types_int3.h
deleted file mode 100644
index 09edc09dff3..00000000000
--- a/intern/cycles/util/util_types_int3.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_INT3_H__
-#define __UTIL_TYPES_INT3_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct ccl_try_align(16) int3
-{
-# ifdef __KERNEL_SSE__
- union {
- __m128i m128;
- struct {
- int x, y, z, w;
- };
- };
-
- __forceinline int3();
- __forceinline int3(const int3 &a);
- __forceinline explicit int3(const __m128i &a);
-
- __forceinline operator const __m128i &() const;
- __forceinline operator __m128i &();
-
- __forceinline int3 &operator=(const int3 &a);
-# else /* __KERNEL_SSE__ */
- int x, y, z, w;
-# endif /* __KERNEL_SSE__ */
-
- __forceinline int operator[](int i) const;
- __forceinline int &operator[](int i);
-};
-
-ccl_device_inline int3 make_int3(int i);
-ccl_device_inline int3 make_int3(int x, int y, int z);
-ccl_device_inline void print_int3(const char *label, const int3 &a);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT3_H__ */
diff --git a/intern/cycles/util/util_types_int3_impl.h b/intern/cycles/util/util_types_int3_impl.h
deleted file mode 100644
index 080c892640b..00000000000
--- a/intern/cycles/util/util_types_int3_impl.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_INT3_IMPL_H__
-#define __UTIL_TYPES_INT3_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-# ifdef __KERNEL_SSE__
-__forceinline int3::int3()
-{
-}
-
-__forceinline int3::int3(const __m128i &a) : m128(a)
-{
-}
-
-__forceinline int3::int3(const int3 &a) : m128(a.m128)
-{
-}
-
-__forceinline int3::operator const __m128i &() const
-{
- return m128;
-}
-
-__forceinline int3::operator __m128i &()
-{
- return m128;
-}
-
-__forceinline int3 &int3::operator=(const int3 &a)
-{
- m128 = a.m128;
- return *this;
-}
-# endif /* __KERNEL_SSE__ */
-
-__forceinline int int3::operator[](int i) const
-{
- util_assert(i >= 0);
- util_assert(i < 3);
- return *(&x + i);
-}
-
-__forceinline int &int3::operator[](int i)
-{
- util_assert(i >= 0);
- util_assert(i < 3);
- return *(&x + i);
-}
-
-ccl_device_inline int3 make_int3(int i)
-{
-# ifdef __KERNEL_SSE__
- int3 a(_mm_set1_epi32(i));
-# else
- int3 a = {i, i, i, i};
-# endif
- return a;
-}
-
-ccl_device_inline int3 make_int3(int x, int y, int z)
-{
-# ifdef __KERNEL_SSE__
- int3 a(_mm_set_epi32(0, z, y, x));
-# else
- int3 a = {x, y, z, 0};
-# endif
-
- return a;
-}
-
-ccl_device_inline void print_int3(const char *label, const int3 &a)
-{
- printf("%s: %d %d %d\n", label, a.x, a.y, a.z);
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT3_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_int4.h b/intern/cycles/util/util_types_int4.h
deleted file mode 100644
index 5c7917cf5d6..00000000000
--- a/intern/cycles/util/util_types_int4.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_INT4_H__
-#define __UTIL_TYPES_INT4_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-
-struct float3;
-struct float4;
-
-struct ccl_try_align(16) int4
-{
-# ifdef __KERNEL_SSE__
- union {
- __m128i m128;
- struct {
- int x, y, z, w;
- };
- };
-
- __forceinline int4();
- __forceinline int4(const int4 &a);
- __forceinline explicit int4(const __m128i &a);
-
- __forceinline operator const __m128i &() const;
- __forceinline operator __m128i &();
-
- __forceinline int4 &operator=(const int4 &a);
-# else /* __KERNEL_SSE__ */
- int x, y, z, w;
-# endif /* __KERNEL_SSE__ */
-
- __forceinline int operator[](int i) const;
- __forceinline int &operator[](int i);
-};
-
-ccl_device_inline int4 make_int4(int i);
-ccl_device_inline int4 make_int4(int x, int y, int z, int w);
-ccl_device_inline int4 make_int4(const float3 &f);
-ccl_device_inline int4 make_int4(const float4 &f);
-ccl_device_inline void print_int4(const char *label, const int4 &a);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT4_H__ */
diff --git a/intern/cycles/util/util_types_int4_impl.h b/intern/cycles/util/util_types_int4_impl.h
deleted file mode 100644
index c6f6ff23a17..00000000000
--- a/intern/cycles/util/util_types_int4_impl.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_INT4_IMPL_H__
-#define __UTIL_TYPES_INT4_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-# ifdef __KERNEL_SSE__
-__forceinline int4::int4()
-{
-}
-
-__forceinline int4::int4(const int4 &a) : m128(a.m128)
-{
-}
-
-__forceinline int4::int4(const __m128i &a) : m128(a)
-{
-}
-
-__forceinline int4::operator const __m128i &() const
-{
- return m128;
-}
-
-__forceinline int4::operator __m128i &()
-{
- return m128;
-}
-
-__forceinline int4 &int4::operator=(const int4 &a)
-{
- m128 = a.m128;
- return *this;
-}
-# endif /* __KERNEL_SSE__ */
-
-__forceinline int int4::operator[](int i) const
-{
- util_assert(i >= 0);
- util_assert(i < 4);
- return *(&x + i);
-}
-
-__forceinline int &int4::operator[](int i)
-{
- util_assert(i >= 0);
- util_assert(i < 4);
- return *(&x + i);
-}
-
-ccl_device_inline int4 make_int4(int i)
-{
-# ifdef __KERNEL_SSE__
- int4 a(_mm_set1_epi32(i));
-# else
- int4 a = {i, i, i, i};
-# endif
- return a;
-}
-
-ccl_device_inline int4 make_int4(int x, int y, int z, int w)
-{
-# ifdef __KERNEL_SSE__
- int4 a(_mm_set_epi32(w, z, y, x));
-# else
- int4 a = {x, y, z, w};
-# endif
- return a;
-}
-
-ccl_device_inline int4 make_int4(const float3 &f)
-{
-# ifdef __KERNEL_SSE__
- int4 a(_mm_cvtps_epi32(f.m128));
-# else
- int4 a = {(int)f.x, (int)f.y, (int)f.z, (int)f.w};
-# endif
- return a;
-}
-
-ccl_device_inline int4 make_int4(const float4 &f)
-{
-# ifdef __KERNEL_SSE__
- int4 a(_mm_cvtps_epi32(f.m128));
-# else
- int4 a = {(int)f.x, (int)f.y, (int)f.z, (int)f.w};
-# endif
- return a;
-}
-
-ccl_device_inline void print_int4(const char *label, const int4 &a)
-{
- printf("%s: %d %d %d %d\n", label, a.x, a.y, a.z, a.w);
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT4_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_uchar2.h b/intern/cycles/util/util_types_uchar2.h
deleted file mode 100644
index 8cc486e3e48..00000000000
--- a/intern/cycles/util/util_types_uchar2.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UCHAR2_H__
-#define __UTIL_TYPES_UCHAR2_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct uchar2 {
- uchar x, y;
-
- __forceinline uchar operator[](int i) const;
- __forceinline uchar &operator[](int i);
-};
-
-ccl_device_inline uchar2 make_uchar2(uchar x, uchar y);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UCHAR2_H__ */
diff --git a/intern/cycles/util/util_types_uchar2_impl.h b/intern/cycles/util/util_types_uchar2_impl.h
deleted file mode 100644
index 16968c32dd9..00000000000
--- a/intern/cycles/util/util_types_uchar2_impl.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UCHAR2_IMPL_H__
-#define __UTIL_TYPES_UCHAR2_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-uchar uchar2::operator[](int i) const
-{
- util_assert(i >= 0);
- util_assert(i < 2);
- return *(&x + i);
-}
-
-uchar &uchar2::operator[](int i)
-{
- util_assert(i >= 0);
- util_assert(i < 2);
- return *(&x + i);
-}
-
-ccl_device_inline uchar2 make_uchar2(uchar x, uchar y)
-{
- uchar2 a = {x, y};
- return a;
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UCHAR2_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_uchar3.h b/intern/cycles/util/util_types_uchar3.h
deleted file mode 100644
index 5838c437c70..00000000000
--- a/intern/cycles/util/util_types_uchar3.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UCHAR3_H__
-#define __UTIL_TYPES_UCHAR3_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct uchar3 {
- uchar x, y, z;
-
- __forceinline uchar operator[](int i) const;
- __forceinline uchar &operator[](int i);
-};
-
-ccl_device_inline uchar3 make_uchar3(uchar x, uchar y, uchar z);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UCHAR3_H__ */
diff --git a/intern/cycles/util/util_types_uchar3_impl.h b/intern/cycles/util/util_types_uchar3_impl.h
deleted file mode 100644
index aa31b725731..00000000000
--- a/intern/cycles/util/util_types_uchar3_impl.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UCHAR3_IMPL_H__
-#define __UTIL_TYPES_UCHAR3_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-uchar uchar3::operator[](int i) const
-{
- util_assert(i >= 0);
- util_assert(i < 3);
- return *(&x + i);
-}
-
-uchar &uchar3::operator[](int i)
-{
- util_assert(i >= 0);
- util_assert(i < 3);
- return *(&x + i);
-}
-
-ccl_device_inline uchar3 make_uchar3(uchar x, uchar y, uchar z)
-{
- uchar3 a = {x, y, z};
- return a;
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UCHAR3_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_uchar4.h b/intern/cycles/util/util_types_uchar4.h
deleted file mode 100644
index 22b6a1ac705..00000000000
--- a/intern/cycles/util/util_types_uchar4.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UCHAR4_H__
-#define __UTIL_TYPES_UCHAR4_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct uchar4 {
- uchar x, y, z, w;
-
- __forceinline uchar operator[](int i) const;
- __forceinline uchar &operator[](int i);
-};
-
-ccl_device_inline uchar4 make_uchar4(uchar x, uchar y, uchar z, uchar w);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UCHAR4_H__ */
diff --git a/intern/cycles/util/util_types_uchar4_impl.h b/intern/cycles/util/util_types_uchar4_impl.h
deleted file mode 100644
index 79879f176a6..00000000000
--- a/intern/cycles/util/util_types_uchar4_impl.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UCHAR4_IMPL_H__
-#define __UTIL_TYPES_UCHAR4_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-uchar uchar4::operator[](int i) const
-{
- util_assert(i >= 0);
- util_assert(i < 4);
- return *(&x + i);
-}
-
-uchar &uchar4::operator[](int i)
-{
- util_assert(i >= 0);
- util_assert(i < 4);
- return *(&x + i);
-}
-
-ccl_device_inline uchar4 make_uchar4(uchar x, uchar y, uchar z, uchar w)
-{
- uchar4 a = {x, y, z, w};
- return a;
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UCHAR4_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_uint2.h b/intern/cycles/util/util_types_uint2.h
deleted file mode 100644
index abcb8ee5346..00000000000
--- a/intern/cycles/util/util_types_uint2.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UINT2_H__
-#define __UTIL_TYPES_UINT2_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct uint2 {
- uint x, y;
-
- __forceinline uint operator[](uint i) const;
- __forceinline uint &operator[](uint i);
-};
-
-ccl_device_inline uint2 make_uint2(uint x, uint y);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT2_H__ */
diff --git a/intern/cycles/util/util_types_uint2_impl.h b/intern/cycles/util/util_types_uint2_impl.h
deleted file mode 100644
index db62bd99b89..00000000000
--- a/intern/cycles/util/util_types_uint2_impl.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UINT2_IMPL_H__
-#define __UTIL_TYPES_UINT2_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-__forceinline uint uint2::operator[](uint i) const
-{
- util_assert(i < 2);
- return *(&x + i);
-}
-
-__forceinline uint &uint2::operator[](uint i)
-{
- util_assert(i < 2);
- return *(&x + i);
-}
-
-ccl_device_inline uint2 make_uint2(uint x, uint y)
-{
- uint2 a = {x, y};
- return a;
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT2_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_uint3.h b/intern/cycles/util/util_types_uint3.h
deleted file mode 100644
index 436d870b621..00000000000
--- a/intern/cycles/util/util_types_uint3.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UINT3_H__
-#define __UTIL_TYPES_UINT3_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct uint3 {
- uint x, y, z;
-
- __forceinline uint operator[](uint i) const;
- __forceinline uint &operator[](uint i);
-};
-
-ccl_device_inline uint3 make_uint3(uint x, uint y, uint z);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT3_H__ */
diff --git a/intern/cycles/util/util_types_uint3_impl.h b/intern/cycles/util/util_types_uint3_impl.h
deleted file mode 100644
index d188fa06e2a..00000000000
--- a/intern/cycles/util/util_types_uint3_impl.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UINT3_IMPL_H__
-#define __UTIL_TYPES_UINT3_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-__forceinline uint uint3::operator[](uint i) const
-{
- util_assert(i < 3);
- return *(&x + i);
-}
-
-__forceinline uint &uint3::operator[](uint i)
-{
- util_assert(i < 3);
- return *(&x + i);
-}
-
-ccl_device_inline uint3 make_uint3(uint x, uint y, uint z)
-{
- uint3 a = {x, y, z};
- return a;
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT3_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_uint4.h b/intern/cycles/util/util_types_uint4.h
deleted file mode 100644
index 57f2859fedf..00000000000
--- a/intern/cycles/util/util_types_uint4.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UINT4_H__
-#define __UTIL_TYPES_UINT4_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-struct uint4 {
- uint x, y, z, w;
-
- __forceinline uint operator[](uint i) const;
- __forceinline uint &operator[](uint i);
-};
-
-ccl_device_inline uint4 make_uint4(uint x, uint y, uint z, uint w);
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT4_H__ */
diff --git a/intern/cycles/util/util_types_uint4_impl.h b/intern/cycles/util/util_types_uint4_impl.h
deleted file mode 100644
index bac8d23030d..00000000000
--- a/intern/cycles/util/util_types_uint4_impl.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_UINT4_IMPL_H__
-#define __UTIL_TYPES_UINT4_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-__forceinline uint uint4::operator[](uint i) const
-{
- util_assert(i < 3);
- return *(&x + i);
-}
-
-__forceinline uint &uint4::operator[](uint i)
-{
- util_assert(i < 3);
- return *(&x + i);
-}
-
-ccl_device_inline uint4 make_uint4(uint x, uint y, uint z, uint w)
-{
- uint4 a = {x, y, z, w};
- return a;
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT4_IMPL_H__ */
diff --git a/intern/cycles/util/util_types_ushort4.h b/intern/cycles/util/util_types_ushort4.h
deleted file mode 100644
index 476ceec622c..00000000000
--- a/intern/cycles/util/util_types_ushort4.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_USHORT4_H__
-#define __UTIL_TYPES_USHORT4_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-
-struct ushort4 {
- uint16_t x, y, z, w;
-};
-
-#endif
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_USHORT4_H__ */
diff --git a/intern/cycles/util/util_types_vector3.h b/intern/cycles/util/util_types_vector3.h
deleted file mode 100644
index 728c7ca62a1..00000000000
--- a/intern/cycles/util/util_types_vector3.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_VECTOR3_H__
-#define __UTIL_TYPES_VECTOR3_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-template<typename T> class vector3 {
- public:
- T x, y, z;
-
- __forceinline vector3();
- __forceinline vector3(const T &a);
- __forceinline vector3(const T &x, const T &y, const T &z);
-};
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_VECTOR3_H__ */
diff --git a/intern/cycles/util/util_types_vector3_impl.h b/intern/cycles/util/util_types_vector3_impl.h
deleted file mode 100644
index 33ba53e20b2..00000000000
--- a/intern/cycles/util/util_types_vector3_impl.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2011-2017 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_TYPES_VECTOR3_IMPL_H__
-#define __UTIL_TYPES_VECTOR3_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util_types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-template<typename T> ccl_always_inline vector3<T>::vector3()
-{
-}
-
-template<typename T> ccl_always_inline vector3<T>::vector3(const T &a) : x(a), y(a), z(a)
-{
-}
-
-template<typename T>
-ccl_always_inline vector3<T>::vector3(const T &x, const T &y, const T &z) : x(x), y(y), z(z)
-{
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_VECTOR3_IMPL_H__ */
diff --git a/intern/cycles/util/util_vector.h b/intern/cycles/util/util_vector.h
deleted file mode 100644
index 87cd4de8438..00000000000
--- a/intern/cycles/util/util_vector.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_VECTOR_H__
-#define __UTIL_VECTOR_H__
-
-#include <cassert>
-#include <cstring>
-#include <vector>
-
-#include "util/util_aligned_malloc.h"
-#include "util/util_guarded_allocator.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Own subclass-ed version of std::vector. Subclass is needed because:
- *
- * - Use own allocator which keeps track of used/peak memory.
- * - Have method to ensure capacity is re-set to 0.
- */
-template<typename value_type, typename allocator_type = GuardedAllocator<value_type>>
-class vector : public std::vector<value_type, allocator_type> {
- public:
- typedef std::vector<value_type, allocator_type> BaseClass;
-
- /* Inherit all constructors from base class. */
- using BaseClass::vector;
-
- /* Try as hard as possible to use zero memory. */
- void free_memory()
- {
- vector<value_type, allocator_type> empty;
- BaseClass::swap(empty);
- }
-
- /* Some external API might demand working with std::vector. */
- operator std::vector<value_type>()
- {
- return std::vector<value_type>(this->begin(), this->end());
- }
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_VECTOR_H__ */
diff --git a/intern/cycles/util/util_view.cpp b/intern/cycles/util/util_view.cpp
deleted file mode 100644
index 9d9ff451b3b..00000000000
--- a/intern/cycles/util/util_view.cpp
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "util/util_opengl.h"
-#include "util/util_string.h"
-#include "util/util_time.h"
-#include "util/util_version.h"
-#include "util/util_view.h"
-
-#ifdef __APPLE__
-# include <GLUT/glut.h>
-#else
-# include <GL/glut.h>
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-/* structs */
-
-struct View {
- ViewInitFunc initf;
- ViewExitFunc exitf;
- ViewResizeFunc resize;
- ViewDisplayFunc display;
- ViewKeyboardFunc keyboard;
- ViewMotionFunc motion;
-
- bool first_display;
- bool redraw;
-
- int mouseX, mouseY;
- int mouseBut0, mouseBut2;
-
- int width, height;
-} V;
-
-/* public */
-
-static void view_display_text(int x, int y, const char *text)
-{
- const char *c;
-
- glRasterPos3f(x, y, 0);
-
- for (c = text; *c != '\0'; c++)
- glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, *c);
-}
-
-void view_display_info(const char *info)
-{
- const int height = 20;
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4f(0.1f, 0.1f, 0.1f, 0.8f);
- glRectf(0.0f, V.height - height, V.width, V.height);
- glDisable(GL_BLEND);
-
- glColor3f(0.5f, 0.5f, 0.5f);
-
- view_display_text(10, 7 + V.height - height, info);
-
- glColor3f(1.0f, 1.0f, 1.0f);
-}
-
-void view_display_help()
-{
- const int w = (int)((float)V.width / 1.15f);
- const int h = (int)((float)V.height / 1.15f);
-
- const int x1 = (V.width - w) / 2;
- const int x2 = x1 + w;
-
- const int y1 = (V.height - h) / 2;
- const int y2 = y1 + h;
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4f(0.5f, 0.5f, 0.5f, 0.8f);
- glRectf(x1, y1, x2, y2);
- glDisable(GL_BLEND);
-
- glColor3f(0.8f, 0.8f, 0.8f);
-
- string info = string("Cycles Renderer ") + CYCLES_VERSION_STRING;
-
- view_display_text(x1 + 20, y2 - 20, info.c_str());
- view_display_text(x1 + 20, y2 - 40, "(C) 2011-2016 Blender Foundation");
- view_display_text(x1 + 20, y2 - 80, "Controls:");
- view_display_text(x1 + 20, y2 - 100, "h: Info/Help");
- view_display_text(x1 + 20, y2 - 120, "r: Reset");
- view_display_text(x1 + 20, y2 - 140, "p: Pause");
- view_display_text(x1 + 20, y2 - 160, "esc: Cancel");
- view_display_text(x1 + 20, y2 - 180, "q: Quit program");
-
- view_display_text(x1 + 20, y2 - 210, "i: Interactive mode");
- view_display_text(x1 + 20, y2 - 230, "Left mouse: Move camera");
- view_display_text(x1 + 20, y2 - 250, "Right mouse: Rotate camera");
- view_display_text(x1 + 20, y2 - 270, "W/A/S/D: Move camera");
- view_display_text(x1 + 20, y2 - 290, "0/1/2/3: Set max bounces");
-
- glColor3f(1.0f, 1.0f, 1.0f);
-}
-
-static void view_display()
-{
- if (V.first_display) {
- if (V.initf)
- V.initf();
- if (V.exitf)
- atexit(V.exitf);
-
- V.first_display = false;
- }
-
- glClearColor(0.05f, 0.05f, 0.05f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0, V.width, 0, V.height, -1, 1);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- glRasterPos3f(0, 0, 0);
-
- if (V.display)
- V.display();
-
- glutSwapBuffers();
-}
-
-static void view_reshape(int width, int height)
-{
- if (width <= 0 || height <= 0)
- return;
-
- V.width = width;
- V.height = height;
-
- glViewport(0, 0, width, height);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- if (V.resize)
- V.resize(width, height);
-}
-
-static void view_keyboard(unsigned char key, int x, int y)
-{
- if (V.keyboard)
- V.keyboard(key);
-
- if (key == 'm')
- printf("mouse %d %d\n", x, y);
- if (key == 'q') {
- if (V.exitf)
- V.exitf();
- exit(0);
- }
-}
-
-static void view_mouse(int button, int state, int x, int y)
-{
- if (button == 0) {
- if (state == GLUT_DOWN) {
- V.mouseX = x;
- V.mouseY = y;
- V.mouseBut0 = 1;
- }
- else if (state == GLUT_UP) {
- V.mouseBut0 = 0;
- }
- }
- else if (button == 2) {
- if (state == GLUT_DOWN) {
- V.mouseX = x;
- V.mouseY = y;
- V.mouseBut2 = 1;
- }
- else if (state == GLUT_UP) {
- V.mouseBut2 = 0;
- }
- }
-}
-
-static void view_motion(int x, int y)
-{
- const int but = V.mouseBut0 ? 0 : 2;
- const int distX = x - V.mouseX;
- const int distY = y - V.mouseY;
-
- if (V.motion)
- V.motion(distX, distY, but);
-
- V.mouseX = x;
- V.mouseY = y;
-}
-
-static void view_idle()
-{
- if (V.redraw) {
- V.redraw = false;
- glutPostRedisplay();
- }
-
- time_sleep(0.1);
-}
-
-void view_main_loop(const char *title,
- int width,
- int height,
- ViewInitFunc initf,
- ViewExitFunc exitf,
- ViewResizeFunc resize,
- ViewDisplayFunc display,
- ViewKeyboardFunc keyboard,
- ViewMotionFunc motion)
-{
- const char *name = "app";
- char *argv = (char *)name;
- int argc = 1;
-
- memset(&V, 0, sizeof(V));
- V.width = width;
- V.height = height;
- V.first_display = true;
- V.redraw = false;
- V.initf = initf;
- V.exitf = exitf;
- V.resize = resize;
- V.display = display;
- V.keyboard = keyboard;
- V.motion = motion;
-
- glutInit(&argc, &argv);
- glutInitWindowSize(width, height);
- glutInitWindowPosition(0, 0);
- glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
- glutCreateWindow(title);
-
- glewInit();
-
- view_reshape(width, height);
-
- glutDisplayFunc(view_display);
- glutIdleFunc(view_idle);
- glutReshapeFunc(view_reshape);
- glutKeyboardFunc(view_keyboard);
- glutMouseFunc(view_mouse);
- glutMotionFunc(view_motion);
-
- glutMainLoop();
-}
-
-void view_redraw()
-{
- V.redraw = true;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_windows.cpp b/intern/cycles/util/util_windows.cpp
deleted file mode 100644
index 807a5adc84a..00000000000
--- a/intern/cycles/util/util_windows.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2019-2019 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifdef _WIN32
-# include <windows.h>
-#endif
-
-#include "util_windows.h"
-
-CCL_NAMESPACE_BEGIN
-
-bool system_windows_version_at_least(int major, int build)
-{
-#ifdef _WIN32
- HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
- if (hMod == 0) {
- return false;
- }
-
- typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
- RtlGetVersionPtr rtl_get_version = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
- if (rtl_get_version == NULL) {
- return false;
- }
-
- RTL_OSVERSIONINFOW rovi = {0};
- rovi.dwOSVersionInfoSize = sizeof(rovi);
- if (rtl_get_version(&rovi) != 0) {
- return false;
- }
-
- return (rovi.dwMajorVersion > major ||
- (rovi.dwMajorVersion == major && rovi.dwBuildNumber >= build));
-#else
- (void)major;
- (void)build;
- return false;
-#endif
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/vector.h b/intern/cycles/util/vector.h
new file mode 100644
index 00000000000..db35f198dc1
--- /dev/null
+++ b/intern/cycles/util/vector.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_VECTOR_H__
+#define __UTIL_VECTOR_H__
+
+#include <cassert>
+#include <cstring>
+#include <vector>
+
+#include "util/aligned_malloc.h"
+#include "util/guarded_allocator.h"
+#include "util/types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Own subclass-ed version of std::vector. Subclass is needed because:
+ *
+ * - Use own allocator which keeps track of used/peak memory.
+ * - Have method to ensure capacity is re-set to 0.
+ */
+template<typename value_type, typename allocator_type = GuardedAllocator<value_type>>
+class vector : public std::vector<value_type, allocator_type> {
+ public:
+ typedef std::vector<value_type, allocator_type> BaseClass;
+
+ /* Inherit all constructors from base class. */
+ using BaseClass::vector;
+
+ /* Try as hard as possible to use zero memory. */
+ void free_memory()
+ {
+ vector<value_type, allocator_type> empty;
+ BaseClass::swap(empty);
+ }
+
+ /* Some external API might demand working with std::vector. */
+ operator std::vector<value_type>()
+ {
+ return std::vector<value_type>(this->begin(), this->end());
+ }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_VECTOR_H__ */
diff --git a/intern/cycles/util/util_version.h b/intern/cycles/util/version.h
index 8bce5ff85aa..8bce5ff85aa 100644
--- a/intern/cycles/util/util_version.h
+++ b/intern/cycles/util/version.h
diff --git a/intern/cycles/util/view.cpp b/intern/cycles/util/view.cpp
new file mode 100644
index 00000000000..1c70cea1a8b
--- /dev/null
+++ b/intern/cycles/util/view.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util/opengl.h"
+#include "util/string.h"
+#include "util/time.h"
+#include "util/version.h"
+#include "util/view.h"
+
+#ifdef __APPLE__
+# include <GLUT/glut.h>
+#else
+# include <GL/glut.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* structs */
+
+struct View {
+ ViewInitFunc initf;
+ ViewExitFunc exitf;
+ ViewResizeFunc resize;
+ ViewDisplayFunc display;
+ ViewKeyboardFunc keyboard;
+ ViewMotionFunc motion;
+
+ bool first_display;
+ bool redraw;
+
+ int mouseX, mouseY;
+ int mouseBut0, mouseBut2;
+
+ int width, height;
+} V;
+
+/* public */
+
+static void view_display_text(int x, int y, const char *text)
+{
+ const char *c;
+
+ glRasterPos3f(x, y, 0);
+
+ for (c = text; *c != '\0'; c++)
+ glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, *c);
+}
+
+void view_display_info(const char *info)
+{
+ const int height = 20;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4f(0.1f, 0.1f, 0.1f, 0.8f);
+ glRectf(0.0f, V.height - height, V.width, V.height);
+ glDisable(GL_BLEND);
+
+ glColor3f(0.5f, 0.5f, 0.5f);
+
+ view_display_text(10, 7 + V.height - height, info);
+
+ glColor3f(1.0f, 1.0f, 1.0f);
+}
+
+void view_display_help()
+{
+ const int w = (int)((float)V.width / 1.15f);
+ const int h = (int)((float)V.height / 1.15f);
+
+ const int x1 = (V.width - w) / 2;
+ const int x2 = x1 + w;
+
+ const int y1 = (V.height - h) / 2;
+ const int y2 = y1 + h;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4f(0.5f, 0.5f, 0.5f, 0.8f);
+ glRectf(x1, y1, x2, y2);
+ glDisable(GL_BLEND);
+
+ glColor3f(0.8f, 0.8f, 0.8f);
+
+ string info = string("Cycles Renderer ") + CYCLES_VERSION_STRING;
+
+ view_display_text(x1 + 20, y2 - 20, info.c_str());
+ view_display_text(x1 + 20, y2 - 40, "(C) 2011-2016 Blender Foundation");
+ view_display_text(x1 + 20, y2 - 80, "Controls:");
+ view_display_text(x1 + 20, y2 - 100, "h: Info/Help");
+ view_display_text(x1 + 20, y2 - 120, "r: Reset");
+ view_display_text(x1 + 20, y2 - 140, "p: Pause");
+ view_display_text(x1 + 20, y2 - 160, "esc: Cancel");
+ view_display_text(x1 + 20, y2 - 180, "q: Quit program");
+
+ view_display_text(x1 + 20, y2 - 210, "i: Interactive mode");
+ view_display_text(x1 + 20, y2 - 230, "Left mouse: Move camera");
+ view_display_text(x1 + 20, y2 - 250, "Right mouse: Rotate camera");
+ view_display_text(x1 + 20, y2 - 270, "W/A/S/D: Move camera");
+ view_display_text(x1 + 20, y2 - 290, "0/1/2/3: Set max bounces");
+
+ glColor3f(1.0f, 1.0f, 1.0f);
+}
+
+static void view_display()
+{
+ if (V.first_display) {
+ if (V.initf)
+ V.initf();
+ if (V.exitf)
+ atexit(V.exitf);
+
+ V.first_display = false;
+ }
+
+ glClearColor(0.05f, 0.05f, 0.05f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, V.width, 0, V.height, -1, 1);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glRasterPos3f(0, 0, 0);
+
+ if (V.display)
+ V.display();
+
+ glutSwapBuffers();
+}
+
+static void view_reshape(int width, int height)
+{
+ if (width <= 0 || height <= 0)
+ return;
+
+ V.width = width;
+ V.height = height;
+
+ glViewport(0, 0, width, height);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ if (V.resize)
+ V.resize(width, height);
+}
+
+static void view_keyboard(unsigned char key, int x, int y)
+{
+ if (V.keyboard)
+ V.keyboard(key);
+
+ if (key == 'm')
+ printf("mouse %d %d\n", x, y);
+ if (key == 'q') {
+ if (V.exitf)
+ V.exitf();
+ exit(0);
+ }
+}
+
+static void view_mouse(int button, int state, int x, int y)
+{
+ if (button == 0) {
+ if (state == GLUT_DOWN) {
+ V.mouseX = x;
+ V.mouseY = y;
+ V.mouseBut0 = 1;
+ }
+ else if (state == GLUT_UP) {
+ V.mouseBut0 = 0;
+ }
+ }
+ else if (button == 2) {
+ if (state == GLUT_DOWN) {
+ V.mouseX = x;
+ V.mouseY = y;
+ V.mouseBut2 = 1;
+ }
+ else if (state == GLUT_UP) {
+ V.mouseBut2 = 0;
+ }
+ }
+}
+
+static void view_motion(int x, int y)
+{
+ const int but = V.mouseBut0 ? 0 : 2;
+ const int distX = x - V.mouseX;
+ const int distY = y - V.mouseY;
+
+ if (V.motion)
+ V.motion(distX, distY, but);
+
+ V.mouseX = x;
+ V.mouseY = y;
+}
+
+static void view_idle()
+{
+ if (V.redraw) {
+ V.redraw = false;
+ glutPostRedisplay();
+ }
+
+ time_sleep(0.1);
+}
+
+void view_main_loop(const char *title,
+ int width,
+ int height,
+ ViewInitFunc initf,
+ ViewExitFunc exitf,
+ ViewResizeFunc resize,
+ ViewDisplayFunc display,
+ ViewKeyboardFunc keyboard,
+ ViewMotionFunc motion)
+{
+ const char *name = "app";
+ char *argv = (char *)name;
+ int argc = 1;
+
+ memset(&V, 0, sizeof(V));
+ V.width = width;
+ V.height = height;
+ V.first_display = true;
+ V.redraw = false;
+ V.initf = initf;
+ V.exitf = exitf;
+ V.resize = resize;
+ V.display = display;
+ V.keyboard = keyboard;
+ V.motion = motion;
+
+ glutInit(&argc, &argv);
+ glutInitWindowSize(width, height);
+ glutInitWindowPosition(0, 0);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ glutCreateWindow(title);
+
+ glewInit();
+
+ view_reshape(width, height);
+
+ glutDisplayFunc(view_display);
+ glutIdleFunc(view_idle);
+ glutReshapeFunc(view_reshape);
+ glutKeyboardFunc(view_keyboard);
+ glutMouseFunc(view_mouse);
+ glutMotionFunc(view_motion);
+
+ glutMainLoop();
+}
+
+void view_redraw()
+{
+ V.redraw = true;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_view.h b/intern/cycles/util/view.h
index ad5c53ee5d5..ad5c53ee5d5 100644
--- a/intern/cycles/util/util_view.h
+++ b/intern/cycles/util/view.h
diff --git a/intern/cycles/util/windows.cpp b/intern/cycles/util/windows.cpp
new file mode 100644
index 00000000000..96944d07390
--- /dev/null
+++ b/intern/cycles/util/windows.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019-2019 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef _WIN32
+# include <windows.h>
+#endif
+
+#include "util/windows.h"
+
+CCL_NAMESPACE_BEGIN
+
+bool system_windows_version_at_least(int major, int build)
+{
+#ifdef _WIN32
+ HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
+ if (hMod == 0) {
+ return false;
+ }
+
+ typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
+ RtlGetVersionPtr rtl_get_version = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
+ if (rtl_get_version == NULL) {
+ return false;
+ }
+
+ RTL_OSVERSIONINFOW rovi = {0};
+ rovi.dwOSVersionInfoSize = sizeof(rovi);
+ if (rtl_get_version(&rovi) != 0) {
+ return false;
+ }
+
+ return (rovi.dwMajorVersion > major ||
+ (rovi.dwMajorVersion == major && rovi.dwBuildNumber >= build));
+#else
+ (void)major;
+ (void)build;
+ return false;
+#endif
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_windows.h b/intern/cycles/util/windows.h
index 9cbf91a23a7..9cbf91a23a7 100644
--- a/intern/cycles/util/util_windows.h
+++ b/intern/cycles/util/windows.h
diff --git a/intern/cycles/util/util_xml.h b/intern/cycles/util/xml.h
index 6f06f17937b..6f06f17937b 100644
--- a/intern/cycles/util/util_xml.h
+++ b/intern/cycles/util/xml.h
diff --git a/intern/ghost/intern/GHOST_XrSession.cpp b/intern/ghost/intern/GHOST_XrSession.cpp
index 808f3a26be7..64aa2f515c4 100644
--- a/intern/ghost/intern/GHOST_XrSession.cpp
+++ b/intern/ghost/intern/GHOST_XrSession.cpp
@@ -127,7 +127,9 @@ void GHOST_XrSession::initSystem()
/** \name State Management
* \{ */
-static void create_reference_spaces(OpenXRSessionData &oxr, const GHOST_XrPose &base_pose)
+static void create_reference_spaces(OpenXRSessionData &oxr,
+ const GHOST_XrPose &base_pose,
+ bool isDebugMode)
{
XrReferenceSpaceCreateInfo create_info = {XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
create_info.poseInReferenceSpace.orientation.w = 1.0f;
@@ -163,10 +165,11 @@ static void create_reference_spaces(OpenXRSessionData &oxr, const GHOST_XrPose &
* since runtimes are not required to support the stage reference space. If the runtime
* doesn't support it then just fall back to the local space. */
if (result == XR_ERROR_REFERENCE_SPACE_UNSUPPORTED) {
- printf(
- "Warning: XR runtime does not support stage reference space, falling back to local "
- "reference space.\n");
-
+ if (isDebugMode) {
+ printf(
+ "Warning: XR runtime does not support stage reference space, falling back to local "
+ "reference space.\n");
+ }
create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
CHECK_XR(xrCreateReferenceSpace(oxr.session, &create_info, &oxr.reference_space),
"Failed to create local reference space.");
@@ -182,11 +185,12 @@ static void create_reference_spaces(OpenXRSessionData &oxr, const GHOST_XrPose &
CHECK_XR(xrGetReferenceSpaceBoundsRect(oxr.session, XR_REFERENCE_SPACE_TYPE_STAGE, &extents),
"Failed to get stage reference space bounds.");
if (extents.width == 0.0f || extents.height == 0.0f) {
- printf(
- "Warning: Invalid stage reference space bounds, falling back to local reference space. "
- "To use the stage reference space, please define a tracking space via the XR "
- "runtime.\n");
-
+ if (isDebugMode) {
+ printf(
+ "Warning: Invalid stage reference space bounds, falling back to local reference "
+ "space. To use the stage reference space, please define a tracking space via the XR "
+ "runtime.\n");
+ }
/* Fallback to local space. */
if (oxr.reference_space != XR_NULL_HANDLE) {
CHECK_XR(xrDestroySpace(oxr.reference_space), "Failed to destroy stage reference space.");
@@ -255,7 +259,7 @@ void GHOST_XrSession::start(const GHOST_XrSessionBeginInfo *begin_info)
"detailed error information to the command line.");
prepareDrawing();
- create_reference_spaces(*m_oxr, begin_info->base_pose);
+ create_reference_spaces(*m_oxr, begin_info->base_pose, m_context->isDebugMode());
/* Create and bind actions here. */
m_context->getCustomFuncs().session_create_fn();
diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp
index 73433fe7c5e..ede9377b38f 100644
--- a/intern/locale/boost_locale_wrapper.cpp
+++ b/intern/locale/boost_locale_wrapper.cpp
@@ -117,6 +117,13 @@ void bl_locale_set(const char *locale)
#undef LOCALE_INFO
}
+ // Extra catch on `std::runtime_error` is needed for macOS/Clang as it seems that exceptions
+ // like `boost::locale::conv::conversion_error` (which inherit from `std::runtime_error`) are
+ // not caught by their ancestor `std::exception`. See
+ // https://developer.blender.org/T88877#1177108 .
+ catch (std::runtime_error const &e) {
+ std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n";
+ }
catch (std::exception const &e) {
std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n";
}
diff --git a/intern/locale/osx_user_locale.mm b/intern/locale/osx_user_locale.mm
index e2f65d39df9..ce694b5fc1e 100644
--- a/intern/locale/osx_user_locale.mm
+++ b/intern/locale/osx_user_locale.mm
@@ -14,7 +14,17 @@ const char *osx_user_locale()
CFLocaleRef myCFLocale = CFLocaleCopyCurrent();
NSLocale *myNSLocale = (NSLocale *)myCFLocale;
[myNSLocale autorelease];
- NSString *nsIdentifier = [myNSLocale localeIdentifier];
+
+ // This produces gettext-invalid locale in recent macOS versions (11.4),
+ // like `ko-Kore_KR` instead of `ko_KR`. See T88877.
+ // NSString *nsIdentifier = [myNSLocale localeIdentifier];
+
+ const NSString *nsIdentifier = [myNSLocale languageCode];
+ const NSString *const nsIdentifier_country = [myNSLocale countryCode];
+ if ([nsIdentifier length] != 0 && [nsIdentifier_country length] != 0) {
+ nsIdentifier = [NSString stringWithFormat:@"%@_%@", nsIdentifier, nsIdentifier_country];
+ }
+
user_locale = ::strdup([nsIdentifier UTF8String]);
[pool drain];
diff --git a/make.bat b/make.bat
index e94f7637512..d55b2cfd1b3 100644
--- a/make.bat
+++ b/make.bat
@@ -56,6 +56,11 @@ if "%BUILD_VS_YEAR%" == "" (
)
)
+if "%SVN_FIX%" == "1" (
+ call "%BLENDER_DIR%\build_files\windows\svn_fix.cmd"
+ goto EOF
+)
+
if "%BUILD_UPDATE%" == "1" (
call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd"
if errorlevel 1 goto EOF
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 80d9e7ee122c626cbbcd1da554683bce79f8d3d
+Subproject 8ee2942570f08d10484bb2328d0d1b0aaaa0367
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index ad93f87e962..f33ecea0eed 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -22,181 +22,163 @@ const bTheme U_theme_default = {
.name = "Default",
.tui = {
.wcol_regular = {
- .outline = RGBA(0x373737ff),
- .inner = RGBA(0x585858ff),
- .inner_sel = RGBA(0x5680c2e6),
- .item = RGBA(0x3e3e3eff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x545454ff),
+ .inner_sel = RGBA(0x4772b3ff),
+ .item = RGBA(0xffffff80),
.text = RGBA(0xd9d9d9ff),
.text_sel = RGBA(0xffffffff),
- .shadedown = -5,
.roundness = 0.2f,
},
.wcol_tool = {
- .outline = RGBA(0x373737ff),
- .inner = RGBA(0x585858ff),
- .inner_sel = RGBA(0x5680c2ff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x545454ff),
+ .inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0xffffffff),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
- .shadedown = -5,
.roundness = 0.2f,
},
.wcol_toolbar_item = {
- .outline = RGBA(0x373737ff),
- .inner = RGBA(0x313131ff),
- .inner_sel = RGBA(0x5680c2ff),
- .item = RGBA(0xe6e6e6cc),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x282828ff),
+ .inner_sel = RGBA(0x4772b3ff),
+ .item = RGBA(0xffffff80),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
.roundness = 0.2f,
},
.wcol_text = {
- .outline = RGBA(0x444444ff),
- .inner = RGBA(0x1f1f1fff),
- .inner_sel = RGBA(0x505050ff),
- .item = RGBA(0x191919ff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x1d1d1dff),
+ .inner_sel = RGBA(0x181818ff),
+ .item = RGBA(0x4772b3ff),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
- .shaded = 1,
- .shadetop = -3,
.roundness = 0.2f,
},
.wcol_radio = {
- .outline = RGBA(0x373737ff),
- .inner = RGBA(0x595959ff),
- .inner_sel = RGBA(0x5680c2e6),
- .item = RGBA(0xffffffff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x282828ff),
+ .inner_sel = RGBA(0x4772b3ff),
+ .item = RGBA(0x252525ff),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
- .shadetop = 5,
- .shadedown = -5,
.roundness = 0.2f,
},
.wcol_option = {
- .outline = RGBA(0x373737ff),
- .inner = RGBA(0x666666ff),
- .inner_sel = RGBA(0x5680c2e6),
- .item = RGBA(0xffffffff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x282828ff),
+ .inner_sel = RGBA(0x71aaffff),
+ .item = RGBA(0x111111ff),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
- .shadedown = -15,
.roundness = 0.2f,
},
.wcol_toggle = {
- .outline = RGBA(0x373737ff),
- .inner = RGBA(0x595959ff),
- .inner_sel = RGBA(0x5680c2e6),
- .item = RGBA(0x191919ff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x282828ff),
+ .inner_sel = RGBA(0x4772b3ff),
+ .item = RGBA(0x252525ff),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
.roundness = 0.2f,
},
.wcol_num = {
- .outline = RGBA(0x444444ff),
- .inner = RGBA(0x595959ff),
- .inner_sel = RGBA(0x505050ff),
- .item = RGBA(0x191919ff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x545454ff),
+ .inner_sel = RGBA(0x222222ff),
+ .item = RGBA(0x4772b3ff),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
.roundness = 0.2f,
},
.wcol_numslider = {
- .outline = RGBA(0x444444ff),
- .inner = RGBA(0x595959ff),
- .inner_sel = RGBA(0x505050ff),
- .item = RGBA(0x5680c2e6),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x545454ff),
+ .inner_sel = RGBA(0x222222ff),
+ .item = RGBA(0x4772b3ff),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
- .shaded = 1,
- .shadetop = -4,
.roundness = 0.2f,
},
.wcol_tab = {
- .outline = RGBA(0x202020ff),
- .inner = RGBA(0x2b2b2bff),
- .inner_sel = RGBA(0x424242ff),
- .item = RGBA(0x2d2d2dff),
+ .outline = RGBA(0x1d1d1dff),
+ .inner = RGBA(0x1d1d1dff),
+ .inner_sel = RGBA(0x303030ff),
+ .item = RGBA(0x1d1d1dff),
.text = RGBA(0x989898ff),
.text_sel = RGBA(0xffffffff),
.roundness = 0.2f,
},
.wcol_menu = {
- .outline = RGBA(0x444444ff),
- .inner = RGBA(0x2c2c2cff),
- .inner_sel = RGBA(0x696e76ff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x282828ff),
+ .inner_sel = RGBA(0x4772b3b3),
.item = RGBA(0xd9d9d9ff),
- .text = RGBA(0xd9d9d9ff),
+ .text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
- .shadetop = 10,
- .shadedown = -10,
.roundness = 0.2f,
},
.wcol_pulldown = {
- .outline = RGBA(0x4d4d4dff),
- .inner = RGBA(0x2e2e2ecc),
- .inner_sel = RGBA(0x5680c2e6),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x22222266),
+ .inner_sel = RGBA(0x4772b3b3),
.item = RGBA(0x727272ff),
.text = RGBA(0xd9d9d9ff),
.text_sel = RGBA(0xffffffff),
- .shadetop = 25,
- .shadedown = -20,
.roundness = 0.2f,
},
.wcol_menu_back = {
- .outline = RGBA(0x19191aff),
- .inner = RGBA(0x1f1f1fef),
- .inner_sel = RGBA(0x585858ff),
- .item = RGBA(0x727272ff),
- .text = RGBA(0xa5a5a5ff),
+ .outline = RGBA(0x242424ff),
+ .inner = RGBA(0x181818ff),
+ .inner_sel = RGBA(0x4772b3ff),
+ .item = RGBA(0xd9d9d9ff),
+ .text = RGBA(0x999999ff),
.text_sel = RGBA(0xffffffff),
- .shadetop = 25,
- .shadedown = -20,
.roundness = 0.2f,
},
.wcol_menu_item = {
- .inner_sel = RGBA(0x5680c2e6),
+ .outline = RGBA(0x3d3d3d00),
+ .inner = RGBA(0x18181800),
+ .inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0xffffff8f),
- .text = RGBA(0xe6e6e6ff),
+ .text = RGBA(0xddddddff),
.text_sel = RGBA(0xffffffff),
- .shadetop = 38,
.roundness = 0.2f,
},
.wcol_tooltip = {
.outline = RGBA(0x19191aff),
- .inner = RGBA(0x19191aef),
- .inner_sel = RGBA(0x19191aef),
- .item = RGBA(0x19191aef),
- .text = RGBA(0xe6e6e6ff),
+ .inner = RGBA(0x181818ff),
+ .inner_sel = RGBA(0x181818ff),
+ .item = RGBA(0x181818ff),
+ .text = RGBA(0xccccccff),
.text_sel = RGBA(0xffffffff),
- .shadetop = 25,
- .shadedown = -20,
.roundness = 0.2f,
},
.wcol_box = {
- .outline = RGBA(0x444444ff),
- .inner = RGBA(0x00000033),
- .inner_sel = RGBA(0x696e76ff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x1d1d1d80),
+ .inner_sel = RGBA(0x545454ff),
.item = RGBA(0x191919ff),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
.roundness = 0.2f,
},
.wcol_scroll = {
- .outline = RGBA(0x424242ff),
- .inner = RGBA(0x67676700),
- .inner_sel = RGBA(0xb3b3b3ff),
- .item = RGBA(0x676767ff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x22222200),
+ .inner_sel = RGBA(0xffffffff),
+ .item = RGBA(0x545454ff),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
- .shadetop = 5,
- .shadedown = -5,
.roundness = 0.5f,
},
.wcol_progress = {
- .outline = RGBA(0x585858ff),
- .inner = RGBA(0x2c2c2cff),
- .inner_sel = RGBA(0x5680c2ff),
- .item = RGBA(0x5680c2ff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x222222ff),
+ .inner_sel = RGBA(0x4772b3ff),
+ .item = RGBA(0x4772b3ff),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
.roundness = 0.2f,
@@ -204,21 +186,19 @@ const bTheme U_theme_default = {
.wcol_list_item = {
.outline = RGBA(0x2d2d2dff),
.inner = RGBA(0x2d2d2d00),
- .inner_sel = RGBA(0x696e76ff),
+ .inner_sel = RGBA(0x484a4fff),
.item = RGBA(0xb3b3b3ff),
- .text = RGBA(0xe6e6e6ff),
+ .text = RGBA(0xccccccff),
.text_sel = RGBA(0xffffffff),
.roundness = 0.2f,
},
.wcol_pie_menu = {
- .outline = RGBA(0x333333ff),
- .inner = RGBA(0x212121ef),
- .inner_sel = RGBA(0x5680c2e6),
- .item = RGBA(0x585858ff),
+ .outline = RGBA(0x3d3d3dff),
+ .inner = RGBA(0x181818ff),
+ .inner_sel = RGBA(0x5680c2ff),
+ .item = RGBA(0x4772b3ff),
.text = RGBA(0xd9d9d9ff),
.text_sel = RGBA(0xffffffff),
- .shadetop = 10,
- .shadedown = -10,
.roundness = 0.2f,
},
.wcol_state = {
@@ -235,15 +215,15 @@ const bTheme U_theme_default = {
.blend = 0.5f,
},
.widget_emboss = RGBA(0x00000026),
- .menu_shadow_fac = 0.3f,
- .menu_shadow_width = 4,
- .editor_outline = RGBA(0x1f1f1fff),
+ .menu_shadow_fac = 0.4f,
+ .menu_shadow_width = 2,
+ .editor_outline = RGBA(0x161616ff),
.transparent_checker_primary = RGBA(0x333333ff),
.transparent_checker_secondary = RGBA(0x262626ff),
.transparent_checker_size = 8,
.icon_alpha = 1.0f,
.icon_saturation = 0.5f,
- .widget_text_cursor = RGBA(0x3399e6ff),
+ .widget_text_cursor = RGBA(0x71a8ffff),
.xaxis = RGBA(0xff3352ff),
.yaxis = RGBA(0x8bdc00ff),
.zaxis = RGBA(0x2890ffff),
@@ -253,65 +233,70 @@ const bTheme U_theme_default = {
.gizmo_view_align = RGBA(0xffffffff),
.gizmo_a = RGBA(0x4da84dff),
.gizmo_b = RGBA(0xa33535ff),
- .icon_scene = RGBA(0xe6e6e6ff),
- .icon_collection = RGBA(0xf4f4f4ff),
- .icon_object = RGBA(0xee9e5dff),
+ .icon_scene = RGBA(0xccccccff),
+ .icon_collection = RGBA(0xffffffff),
+ .icon_object = RGBA(0xe19658ff),
.icon_object_data = RGBA(0x00d4a3ff),
- .icon_modifier = RGBA(0x84b8ffff),
- .icon_shading = RGBA(0xea7581ff),
- .icon_folder = RGBA(0xe3c16eff),
+ .icon_modifier = RGBA(0x74a2ffff),
+ .icon_shading = RGBA(0xcc6670ff),
+ .icon_folder = RGBA(0xccad63ff),
.panel_roundness = 0.4f,
},
.space_properties = {
- .back = RGBA(0x42424200),
- .title = RGBA(0xd4d4d4ff),
+ .back = RGBA(0x30303000),
+ .title = RGBA(0xe6e6e6ff),
.text = RGBA(0xe6e6e6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
- .button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
+ .button_title = RGBA(0xccccccff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
- .navigation_bar = RGBA(0x232323ff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x1d1d1dff),
.panelcolors = {
- .header = RGBA(0x424242ff),
- .back = RGBA(0x383838ff),
- .sub_back = RGBA(0x00000024),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
+ .active = RGBA(0x4772b3ff),
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
- .match = RGBA(0x5680c2ff),
- .active = RGBA(0x5680c2ff),
+ .match = RGBA(0x4772b3ff),
},
.space_view3d = {
- .back = RGBA(0x393939ff),
+ .back = RGBA(0x3d3d3dff),
+ .back_grad = RGBA(0x30303000),
+ .background_type = 2,
.title = RGBA(0xeeeeeeff),
.text = RGBA(0xe6e6e6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x42424200),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x35353500),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242e6),
- .back = RGBA(0x333333f0),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
- .grid = RGBA(0x6666664d),
+ .grid = RGBA(0x54545480),
.wire = RGBA(0x000000ff),
.wire_edit = RGBA(0x000000ff),
.select = RGBA(0xed5700ff),
@@ -347,7 +332,7 @@ const bTheme U_theme_default = {
.bone_pose = RGBA(0x50c8ff50),
.bone_pose_active = RGBA(0x8cffff50),
.bone_locked_weight = RGBA(0xff000080),
- .cframe = RGBA(0x60c040ff),
+ .cframe = RGBA(0x4772b3ff),
.time_keyframe = RGBA(0xddd700ff),
.time_gp_keyframe = RGBA(0xb5e61dff),
.freestyle_edge_mark = RGBA(0x7fff7fff),
@@ -371,7 +356,7 @@ const bTheme U_theme_default = {
.obcenter_dia = 6,
.facedot_size = 3,
.editmesh_active = RGBA(0xffffff33),
- .clipping_border_3d = RGBA(0x313131ff),
+ .clipping_border_3d = RGBA(0x3f3f3fff),
.bundle_solid = RGBA(0xc8c8c8ff),
.camera_path = RGBA(0x000000ff),
.gp_vertex_size = 3,
@@ -386,66 +371,69 @@ const bTheme U_theme_default = {
.title = RGBA(0xffffffff),
.text = RGBA(0xe6e6e6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x2e2e2eff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x4b4b4bff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
- .execution_buts = RGBA(0x444444ff),
+ .navigation_bar = RGBA(0x303030ff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x4b4b4bff),
- .back = RGBA(0x404040ff),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
- .hilite = RGBA(0x4f76b3ff),
+ .hilite = RGBA(0x4772b3ff),
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
- .row_alternate = RGBA(0xffffff07),
+ .row_alternate = RGBA(0xffffff04),
},
.space_graph = {
- .back = RGBA(0x42424200),
+ .back = RGBA(0x30303000),
.title = RGBA(0xffffffff),
.text = RGBA(0xa6a6a6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x2e2e2eff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
- .list = RGBA(0x282828ff),
+ .list = RGBA(0x1d1d1dff),
.list_title = RGBA(0xffffffff),
.list_text = RGBA(0xb8b8b8ff),
- .list_text_hi = RGBA(0xffaf29ff),
+ .list_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
.shade1 = RGBA(0x96969600),
- .shade2 = RGBA(0x33333364),
- .grid = RGBA(0x2a2a2aff),
- .group = RGBA(0x16330fff),
- .group_active = RGBA(0x368024ff),
+ .shade2 = RGBA(0x12121264),
+ .grid = RGBA(0x1a1a1aff),
+ .group = RGBA(0x1a332dff),
+ .group_active = RGBA(0x216d5bff),
.vertex = RGBA(0x000000ff),
.vertex_select = RGBA(0xff8500ff),
.vertex_active = RGBA(0xffffffff),
- .cframe = RGBA(0x5680c2ff),
- .time_scrub_background = RGBA(0x292929e6),
- .time_marker_line = RGBA(0x00000060),
- .time_marker_line_selected = RGBA(0xffffff60),
+ .cframe = RGBA(0x4772b3ff),
+ .time_scrub_background = RGBA(0x161616ff),
+ .time_marker_line = RGBA(0xffffff4d),
+ .time_marker_line_selected = RGBA(0xffffffb3),
.lastsel_point = RGBA(0xffffffff),
.handle_auto = RGBA(0x909000ff),
.handle_vect = RGBA(0x409030ff),
@@ -455,8 +443,8 @@ const bTheme U_theme_default = {
.handle_sel_vect = RGBA(0x40c030ff),
.handle_sel_align = RGBA(0xf090a0ff),
.handle_sel_auto_clamped = RGBA(0xf0af90ff),
- .ds_channel = RGBA(0x0f2c4dff),
- .ds_subchannel = RGBA(0x143e66ff),
+ .ds_channel = RGBA(0x194e80ff),
+ .ds_subchannel = RGBA(0x0f2c4dff),
.vertex_size = 6,
.outline_width = 1,
.facedot_size = 4,
@@ -465,25 +453,27 @@ const bTheme U_theme_default = {
.anim_preview_range = RGBA(0xa14d0066),
},
.space_info = {
- .back = RGBA(0x28282800),
+ .back = RGBA(0x1d1d1d00),
.title = RGBA(0xffffffff),
.text = RGBA(0xc3c3c3ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x454545ff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
.vertex_size = 3,
.outline_width = 1,
@@ -498,56 +488,58 @@ const bTheme U_theme_default = {
.info_info_text = RGBA(0xffffffff),
.info_debug = RGBA(0x6b3293ff),
.info_debug_text = RGBA(0xffffffff),
- .info_property = RGBA(0x329364ff),
+ .info_property = RGBA(0x236666ff),
.info_property_text = RGBA(0xffffffff),
- .info_operator = RGBA(0x329364ff),
+ .info_operator = RGBA(0x235266ff),
.info_operator_text = RGBA(0xffffffff),
},
.space_action = {
- .back = RGBA(0x42424200),
+ .back = RGBA(0x30303000),
.title = RGBA(0xeeeeeeff),
.text = RGBA(0xa6a6a6ff),
- .text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .text_hi = RGBA(0x143e66ff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x282828ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x22222200),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
- .list = RGBA(0x282828ff),
+ .list = RGBA(0x1d1d1dff),
.list_title = RGBA(0xffffffff),
.list_text = RGBA(0xb8b8b8ff),
- .list_text_hi = RGBA(0xffaf29ff),
+ .list_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
.shade1 = RGBA(0xc0c0c000),
- .shade2 = RGBA(0x333333ff),
+ .shade2 = RGBA(0x1d1d1d99),
.hilite = RGBA(0x60c04044),
- .grid = RGBA(0x2a2a2aff),
- .group = RGBA(0x16330f37),
- .group_active = RGBA(0x36802455),
- .strip = RGBA(0x1a151580),
- .strip_select = RGBA(0xff8c00cc),
- .cframe = RGBA(0x5680c2ff),
- .time_scrub_background = RGBA(0x292929e6),
- .time_marker_line = RGBA(0x00000060),
- .time_marker_line_selected = RGBA(0xffffff60),
- .ds_channel = RGBA(0x0f2c4d24),
- .ds_subchannel = RGBA(0x143e6624),
+ .grid = RGBA(0x161616ff),
+ .group = RGBA(0x1a332d37),
+ .group_active = RGBA(0x216d5b67),
+ .strip = RGBA(0xffffff1f),
+ .strip_select = RGBA(0xff8c0099),
+ .cframe = RGBA(0x4772b3ff),
+ .time_scrub_background = RGBA(0x1d1d1dff),
+ .time_marker_line = RGBA(0xffffff4d),
+ .time_marker_line_selected = RGBA(0xffffffb3),
+ .ds_channel = RGBA(0x194e8080),
+ .ds_subchannel = RGBA(0x0f2c4d80),
.ds_ipoline = RGBA(0x94e575cc),
- .keytype_keyframe = RGBA(0xe8e8e8ff),
+ .keytype_keyframe = RGBA(0xbfbfbfff),
.keytype_extreme = RGBA(0xe8b3ccff),
.keytype_breakdown = RGBA(0xb3dbe8ff),
.keytype_jitter = RGBA(0x94e575ff),
- .keytype_movehold = RGBA(0x5c5656ff),
+ .keytype_movehold = RGBA(0x808080ff),
.keytype_keyframe_select = RGBA(0xffbe33ff),
.keytype_extreme_select = RGBA(0xf28080ff),
.keytype_breakdown_select = RGBA(0x54bfedff),
@@ -560,43 +552,45 @@ const bTheme U_theme_default = {
.facedot_size = 4,
.keyframe_scale_fac = 1.0f,
.handle_vertex_size = 4,
- .anim_active = RGBA(0x4d250066),
+ .anim_active = RGBA(0x4d272766),
.anim_preview_range = RGBA(0xa14d0066),
},
.space_nla = {
- .back = RGBA(0x42424200),
+ .back = RGBA(0x30303000),
.title = RGBA(0xffffffff),
.text = RGBA(0xa6a6a6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
- .list = RGBA(0x282828ff),
+ .list = RGBA(0x1d1d1dff),
.list_title = RGBA(0xffffffff),
- .list_text = RGBA(0xb8b8b8ff),
- .list_text_hi = RGBA(0xffaf29ff),
+ .list_text = RGBA(0xe5e5e5ff),
+ .list_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
.shade1 = RGBA(0x96969600),
.grid = RGBA(0x2a2a2aff),
- .strip = RGBA(0x0c0a0a80),
+ .strip = RGBA(0x0d0d0d80),
.strip_select = RGBA(0xff8c00ff),
- .cframe = RGBA(0x5680c2ff),
- .time_scrub_background = RGBA(0x292929e6),
- .time_marker_line = RGBA(0x00000060),
- .time_marker_line_selected = RGBA(0xffffff60),
- .ds_channel = RGBA(0x5a85b2ff),
+ .cframe = RGBA(0x4772b3ff),
+ .time_scrub_background = RGBA(0x161616ff),
+ .time_marker_line = RGBA(0xffffff4d),
+ .time_marker_line_selected = RGBA(0xffffffb3),
+ .ds_channel = RGBA(0x0f2c4dff),
.ds_subchannel = RGBA(0x7d98b3ff),
.keyborder = RGBA(0x000000ff),
.keyborder_select = RGBA(0x000000ff),
@@ -604,12 +598,12 @@ const bTheme U_theme_default = {
.outline_width = 1,
.facedot_size = 4,
.handle_vertex_size = 4,
- .anim_active = RGBA(0xcc701a66),
- .anim_non_active = RGBA(0x9987614d),
+ .anim_active = RGBA(0x99541366),
+ .anim_non_active = RGBA(0x4d3b174d),
.anim_preview_range = RGBA(0xa14d0066),
.nla_tweaking = RGBA(0x4df31a4d),
.nla_tweakdupli = RGBA(0xd90000ff),
- .nla_track = RGBA(0x424242ff),
+ .nla_track = RGBA(0x303030ff),
.nla_transition = RGBA(0x1c2630ff),
.nla_transition_sel = RGBA(0x2e75dbff),
.nla_meta = RGBA(0x332642ff),
@@ -618,34 +612,36 @@ const bTheme U_theme_default = {
.nla_sound_sel = RGBA(0x1f7a7aff),
},
.space_sequencer = {
- .back = RGBA(0x42424200),
+ .back = RGBA(0x30303000),
.title = RGBA(0xeeeeeeff),
.text = RGBA(0xa6a6a6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
.shade1 = RGBA(0xa0a0a000),
- .grid = RGBA(0x212121ff),
+ .grid = RGBA(0x181818ff),
.vertex_select = RGBA(0xff8500ff),
.bone_pose = RGBA(0x50c8ff50),
- .cframe = RGBA(0x5680c2ff),
- .time_scrub_background = RGBA(0x292929e6),
- .time_marker_line = RGBA(0x00000060),
- .time_marker_line_selected = RGBA(0xffffff60),
+ .cframe = RGBA(0x4772b3ff),
+ .time_scrub_background = RGBA(0x121212ff),
+ .time_marker_line = RGBA(0xffffff4d),
+ .time_marker_line_selected = RGBA(0xffffffb3),
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
@@ -653,8 +649,8 @@ const bTheme U_theme_default = {
.movieclip = RGBA(0x8f4c4cff),
.mask = RGBA(0x666666ff),
.image = RGBA(0x8f744bff),
- .scene = RGBA(0x828f50ff),
- .audio = RGBA(0x4c8f8fff),
+ .scene = RGBA(0x808033ff),
+ .audio = RGBA(0x448080ff),
.effect = RGBA(0x514a73ff),
.transition = RGBA(0x8f4571ff),
.meta = RGBA(0x5b4d91ff),
@@ -664,39 +660,41 @@ const bTheme U_theme_default = {
.selected_strip = RGBA(0xff8f0dff),
.gp_vertex_size = 3,
.gp_vertex_select = RGBA(0xff8500ff),
+ .row_alternate = RGBA(0xffffff05),
.anim_preview_range = RGBA(0xa14d0066),
.metadatatext = RGBA(0xffffffff),
- .row_alternate = RGBA(0xffffff0d),
},
.space_image = {
- .back = RGBA(0x44444400),
+ .back = RGBA(0x30303000),
.title = RGBA(0xeeeeeeff),
.text = RGBA(0xe6e6e6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x35353500),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
- .grid = RGBA(0x505050ff),
+ .grid = RGBA(0x303030ff),
.wire_edit = RGBA(0xc0c0c0ff),
.vertex_select = RGBA(0xff8500ff),
.edge_select = RGBA(0xff8500ff),
.face = RGBA(0xffffff0a),
.face_select = RGBA(0xff85003c),
.face_dot = RGBA(0xff8500ff),
- .cframe = RGBA(0x60c040ff),
+ .cframe = RGBA(0x4772b3ff),
.freestyle_face_mark = RGBA(0x7fff7f33),
.handle_auto = RGBA(0x909000ff),
.handle_align = RGBA(0x803060ff),
@@ -723,182 +721,190 @@ const bTheme U_theme_default = {
.metadatatext = RGBA(0xffffffff),
},
.space_text = {
- .back = RGBA(0x30303000),
+ .back = RGBA(0x23232300),
.title = RGBA(0xeeeeeeff),
.text = RGBA(0xe6e6e6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x42424200),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x42424200),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
- .shade2 = RGBA(0x5680c2e6),
+ .shade2 = RGBA(0x2d4366e6),
.hilite = RGBA(0xff0000ff),
- .grid = RGBA(0x202020ff),
+ .grid = RGBA(0x1d1d1dff),
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
- .syntaxl = RGBA(0xf6e162ff),
+ .syntaxl = RGBA(0xe6d573ff),
.syntaxs = RGBA(0xff734dff),
- .syntaxb = RGBA(0xff1961ff),
- .syntaxn = RGBA(0x50dbffff),
- .syntaxv = RGBA(0x95d600ff),
+ .syntaxb = RGBA(0xe62e67ff),
+ .syntaxn = RGBA(0x48c5e6ff),
+ .syntaxv = RGBA(0x689d06ff),
.syntaxc = RGBA(0x939393ff),
- .syntaxd = RGBA(0xad80ffff),
+ .syntaxd = RGBA(0x9c73e6ff),
.syntaxr = RGBA(0xc4753bff),
- .line_numbers = RGBA(0xd0d0d0ff),
+ .line_numbers = RGBA(0x777777ff),
},
.space_outliner = {
.back = RGBA(0x28282800),
.title = RGBA(0xffffffff),
.text = RGBA(0xc3c3c3ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x454545ff),
+ .header = RGBA(0x282828b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
- .active = RGBA(0x3b5689ff),
+ .active = RGBA(0x334d80ff),
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
.match = RGBA(0x337f334c),
- .selected_highlight = RGBA(0x223a5bff),
+ .selected_highlight = RGBA(0x1d314dff),
.selected_object = RGBA(0xe96a00ff),
.active_object = RGBA(0xffaf29ff),
.edited_object = RGBA(0x00806266),
- .row_alternate = RGBA(0xffffff07),
+ .row_alternate = RGBA(0xffffff04),
},
.space_node = {
- .back = RGBA(0x23232300),
+ .back = RGBA(0x1d1d1d00),
.title = RGBA(0xeeeeeeff),
.text = RGBA(0xe6e6e6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .header = RGBA(0x1d1d1db3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x42424200),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
- .list = RGBA(0x282828ff),
+ .list = RGBA(0x303030ff),
.list_title = RGBA(0xffffffff),
.list_text = RGBA(0xccccccff),
.list_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
- .shade2 = RGBA(0x7f707064),
- .grid = RGBA(0x23232300),
- .wire = RGBA(0x232323ff),
+ .shade2 = RGBA(0x7f7f7f64),
+ .grid = RGBA(0x28282800),
+ .wire = RGBA(0x1a1a1aff),
.select = RGBA(0xed5700ff),
.active = RGBA(0xffffffff),
- .edge_select = RGBA(0xffffffff),
- .console_output = RGBA(0x1a1a1aff),
+ .edge_select = RGBA(0xffffffb3),
+ .console_output = RGBA(0x000000ff),
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
.noodle_curving = 4,
- .grid_levels = 2,
+ .grid_levels = 7,
.dash_alpha = 0.5f,
- .syntaxl = RGBA(0x565656ff),
- .syntaxs = RGBA(0x975b5bff),
- .syntaxb = RGBA(0xccb83dff),
- .syntaxn = RGBA(0xe64555ff),
- .syntaxv = RGBA(0x66c4ffff),
- .syntaxc = RGBA(0x426628b9),
- .syntaxd = RGBA(0x749797ff),
- .syntaxr = RGBA(0x808080ff),
- .nodeclass_output = RGBA(0xb33641ff),
- .nodeclass_filter = RGBA(0x584d80ff),
- .nodeclass_vector = RGBA(0x9b80ffff),
- .nodeclass_texture = RGBA(0xe68745ff),
- .nodeclass_shader = RGBA(0x63c763ff),
+ .syntaxl = RGBA(0x303030ff),
+ .syntaxs = RGBA(0x973c3cff),
+ .syntaxb = RGBA(0xcccc00ff),
+ .syntaxn = RGBA(0xff3371ff),
+ .syntaxv = RGBA(0x12adffff),
+ .syntaxc = RGBA(0x3b660aff),
+ .syntaxd = RGBA(0x4c9797ff),
+ .syntaxr = RGBA(0x8d8d8dff),
+ .nodeclass_output = RGBA(0x4d0017ff),
+ .nodeclass_filter = RGBA(0x551a80ff),
+ .nodeclass_vector = RGBA(0x4d4dffff),
+ .nodeclass_texture = RGBA(0xe66800ff),
+ .nodeclass_shader = RGBA(0x24b524ff),
.nodeclass_script = RGBA(0x084d4dff),
.nodeclass_pattern = RGBA(0x6c696fff),
.nodeclass_layout = RGBA(0x6c696fff),
- .nodeclass_geometry = RGBA(0x00d7a4ff),
- .nodeclass_attribute = RGBA(0x3f5980ff),
- .movie = RGBA(0x1a1a1a7d),
+ .nodeclass_geometry = RGBA(0x00d6a3ff),
+ .nodeclass_attribute = RGBA(0x001566ff),
+ .movie = RGBA(0x0f0f0fcc),
.gp_vertex_size = 3,
.gp_vertex = RGBA(0x97979700),
.gp_vertex_select = RGBA(0xff8500ff),
},
.space_preferences = {
- .back = RGBA(0x42424200),
+ .back = RGBA(0x30303000),
.title = RGBA(0xeeeeeeff),
.text = RGBA(0xe6e6e6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x1d1d1dff),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
- .navigation_bar = RGBA(0x4b4b4bff),
- .execution_buts = RGBA(0x4b4b4bff),
+ .navigation_bar = RGBA(0x303030ff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x42424200),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
},
.space_console = {
- .back = RGBA(0x30303000),
+ .back = RGBA(0x1d1d1d00),
.title = RGBA(0xeeeeeeff),
.text = RGBA(0xe6e6e6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
.console_output = RGBA(0x71a8ffff),
.console_input = RGBA(0xf2f2f2ff),
@@ -911,46 +917,51 @@ const bTheme U_theme_default = {
.facedot_size = 4,
},
.space_clip = {
- .back = RGBA(0x42424200),
+ .back = RGBA(0x30303000),
.title = RGBA(0xeeeeeeff),
.text = RGBA(0xa6a6a6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
- .list = RGBA(0x282828ff),
- .list_text = RGBA(0x000000ff),
+ .list = RGBA(0x303030ff),
+ .list_title = RGBA(0xffffff00),
+ .list_text = RGBA(0xb8b8b8ff),
.list_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
- .grid = RGBA(0x424242ff),
- .strip = RGBA(0x0c0a0a80),
+ .grid = RGBA(0x181818ff),
+ .strip = RGBA(0xffffff80),
.strip_select = RGBA(0xff8c00ff),
- .cframe = RGBA(0x5680c2ff),
- .time_scrub_background = RGBA(0x292929e6),
- .time_marker_line = RGBA(0x00000060),
- .time_marker_line_selected = RGBA(0xffffff60),
+ .cframe = RGBA(0x4772b3ff),
+ .time_scrub_background = RGBA(0x181818ff),
+ .time_marker_line = RGBA(0xffffff4d),
+ .time_marker_line_selected = RGBA(0xffffffb3),
.handle_auto = RGBA(0x909000ff),
.handle_align = RGBA(0x803060ff),
+ .handle_auto_clamped = RGBA(0x99403000),
.handle_sel_auto = RGBA(0xf0ff40ff),
.handle_sel_align = RGBA(0xf090a0ff),
+ .handle_sel_auto_clamped = RGBA(0xf0af9000),
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
- .handle_vertex_select = RGBA(0xffff00ff),
+ .handle_vertex_select = RGBA(0xff8500ff),
.handle_vertex_size = 5,
- .marker = RGBA(0x7f7f00ff),
+ .marker = RGBA(0x808000ff),
.act_marker = RGBA(0xffffffff),
.sel_marker = RGBA(0xffff00ff),
.dis_marker = RGBA(0x7f0000ff),
@@ -963,25 +974,27 @@ const bTheme U_theme_default = {
.metadatatext = RGBA(0xffffffff),
},
.space_topbar = {
- .back = RGBA(0x42424200),
+ .back = RGBA(0x18181800),
.title = RGBA(0xffffffff),
.text = RGBA(0xe6e6e6ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x232323ff),
+ .header = RGBA(0x181818b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
.vertex_size = 3,
.outline_width = 1,
@@ -989,23 +1002,26 @@ const bTheme U_theme_default = {
.gp_vertex_size = 3,
},
.space_statusbar = {
- .back = RGBA(0x2e2e2e00),
+ .back = RGBA(0x30303000),
.title = RGBA(0xffffffff),
.text = RGBA(0x838383ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x303030ff),
- .header_text = RGBA(0xaaaaaaff),
+ .header = RGBA(0x181818b3),
+ .header_text = RGBA(0x888888ff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x353535ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
+ .button_text = RGBA(0xcccccc00),
.button_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
.vertex_size = 3,
.outline_width = 1,
@@ -1017,22 +1033,29 @@ const bTheme U_theme_default = {
.title = RGBA(0xffffffff),
.text = RGBA(0xc3c3c3ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x454545ff),
+ .header = RGBA(0x303030b3),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
- .tab_active = RGBA(0x4b4b4bff),
- .tab_inactive = RGBA(0x2b2b2bff),
- .tab_back = RGBA(0x232323ff),
- .tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
.button_title = RGBA(0xffffffff),
- .button_text = RGBA(0xe5e5e5ff),
+ .button_text = RGBA(0xccccccff),
.button_text_hi = RGBA(0xffffffff),
+ .list = RGBA(0x303030ff),
+ .list_title = RGBA(0xc3c3c3ff),
+ .list_text = RGBA(0xc3c3c3ff),
+ .list_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x1d1d1dff),
+ .execution_buts = RGBA(0x303030ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
- .sub_back = RGBA(0x0000003e),
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
},
+ .hilite = RGBA(0x80808080),
.active = RGBA(0x3b5689ff),
.vertex_size = 3,
.outline_width = 1,
@@ -1042,12 +1065,7 @@ const bTheme U_theme_default = {
.selected_object = RGBA(0xe96a00ff),
.active_object = RGBA(0xffaf29ff),
.edited_object = RGBA(0x00806266),
- .row_alternate = RGBA(0xffffff07),
- .list = RGBA(0x424242ff),
- .list_title = RGBA(0xc3c3c3ff),
- .list_text = RGBA(0xc3c3c3ff),
- .list_text_hi = RGBA(0xffffff),
- .hilite = RGBA(0x80808080),
+ .row_alternate = RGBA(0xffffff04),
},
.tarm = {
{
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject e68c0118c13c3575e6096ad2dc7fb4434eadf38
+Subproject f2a08d80ccd3c13af304525778df3905f95bd44
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 42da56aa73726710107031787af5eea18679798
+Subproject 16467648282500cc229c271f62201ef897f2c2c
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index 2cc806be10d..fce59a26c38 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -28,7 +28,7 @@ ARRAY_TYPES = (list, tuple, IDPropertyArray, Vector, bpy_prop_array)
# Maximum length of an array property for which a multi-line
# edit field will be displayed in the Custom Properties panel.
-MAX_DISPLAY_ROWS = 4
+MAX_DISPLAY_ROWS = 8
def rna_idprop_quote_path(prop):
@@ -134,18 +134,7 @@ def rna_idprop_ui_create(
def draw(layout, context, context_member, property_type, *, use_edit=True):
-
- def assign_props(prop, value, key):
- prop.data_path = context_member
- prop.property_name = key
-
- try:
- prop.value = str(value)
- except:
- pass
-
rna_item, context_member = rna_idprop_context_value(context, context_member, property_type)
-
# poll should really get this...
if not rna_item:
return
@@ -164,17 +153,15 @@ def draw(layout, context, context_member, property_type, *, use_edit=True):
# TODO: Allow/support adding new custom props to overrides.
if use_edit and not is_lib_override:
row = layout.row()
- props = row.operator("wm.properties_add", text="Add")
+ props = row.operator("wm.properties_add", text="New", icon='ADD')
props.data_path = context_member
del row
+ layout.separator()
show_developer_ui = context.preferences.view.show_developer_ui
rna_properties = {prop.identifier for prop in rna_item.bl_rna.properties if prop.is_runtime} if items else None
- layout.use_property_split = True
- layout.use_property_decorate = False # No animation.
-
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
+ layout.use_property_decorate = False
for key, value in items:
is_rna = (key in rna_properties)
@@ -188,57 +175,50 @@ def draw(layout, context, context_member, property_type, *, use_edit=True):
if to_dict:
value = to_dict()
- val_draw = str(value)
elif to_list:
value = to_list()
- val_draw = str(value)
- else:
- val_draw = value
- row = layout.row(align=True)
- box = row.box()
+ split = layout.split(factor=0.4, align=True)
+ label_row = split.row()
+ label_row.alignment = 'RIGHT'
+ label_row.label(text=key, translate=False)
- if use_edit:
- split = box.split(factor=0.75)
- row = split.row()
- else:
- split = box.split(factor=1.00)
- row = split.row()
+ value_row = split.row(align=True)
+ value_column = value_row.column(align=True)
- row.alignment = 'RIGHT'
+ is_long_array = to_list and len(value) >= MAX_DISPLAY_ROWS
- row.label(text=key, translate=False)
+ if is_rna:
+ value_column.prop(rna_item, key, text="")
+ elif to_dict or is_long_array:
+ props = value_column.operator("wm.properties_edit_value", text="Edit Value")
+ props.data_path = context_member
+ props.property_name = key
+ else:
+ value_column.prop(rna_item, '["%s"]' % escape_identifier(key), text="")
- # Explicit exception for arrays.
- show_array_ui = to_list and not is_rna and 0 < len(value) <= MAX_DISPLAY_ROWS
+ operator_row = value_row.row()
- if show_array_ui and isinstance(value[0], (int, float)):
- row.prop(rna_item, '["%s"]' % escape_identifier(key), text="")
- elif to_dict or to_list:
- row.label(text=val_draw, translate=False)
- else:
- if is_rna:
- row.prop(rna_item, key, text="")
- else:
- row.prop(rna_item, '["%s"]' % escape_identifier(key), text="")
+ # Do not allow editing of overridden properties (we cannot use a poll function
+ # of the operators here since they's have no access to the specific property).
+ operator_row.enabled = not(is_lib_override and key in rna_item.id_data.override_library.reference)
if use_edit:
- row = split.row(align=True)
- # Do not allow editing of overridden properties (we cannot use a poll function
- # of the operators here since they's have no access to the specific property).
- row.enabled = not(is_lib_override and key in rna_item.id_data.override_library.reference)
if is_rna:
- row.label(text="API Defined")
+ operator_row.label(text="API Defined")
elif is_lib_override:
- row.label(text="Library Override")
+ operator_row.active = False
+ operator_row.label(text="", icon='DECORATE_LIBRARY_OVERRIDE')
else:
- props = row.operator("wm.properties_edit", text="Edit")
- assign_props(props, val_draw, key)
- props = row.operator("wm.properties_remove", text="", icon='REMOVE')
- assign_props(props, val_draw, key)
-
- del flow
-
+ props = operator_row.operator("wm.properties_edit", text="", icon='PREFERENCES', emboss=False)
+ props.data_path = context_member
+ props.property_name = key
+ props = operator_row.operator("wm.properties_remove", text="", icon='X', emboss=False)
+ props.data_path = context_member
+ props.property_name = key
+ else:
+ # Add some spacing, so the right side of the buttons line up with layouts with decorators.
+ operator_row.label(text="", icon='BLANK1')
class PropertyPanel:
"""
diff --git a/release/scripts/presets/interface_theme/Blender_Light.xml b/release/scripts/presets/interface_theme/Blender_Light.xml
index 8074371c450..e3ac77b008d 100644
--- a/release/scripts/presets/interface_theme/Blender_Light.xml
+++ b/release/scripts/presets/interface_theme/Blender_Light.xml
@@ -434,7 +434,7 @@
button="#99999900"
button_title="#1a1a1a"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#b3b3b3"
@@ -509,7 +509,7 @@
button="#999999e6"
button_title="#1a1a1a"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#6697e6"
@@ -555,7 +555,7 @@
button="#999999e6"
button_title="#1a1a1a"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#999999e6"
tab_active="#6697e6"
@@ -613,7 +613,7 @@
button="#7272727f"
button_title="#000000"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#6697e6"
@@ -688,7 +688,7 @@
button="#7272727f"
button_title="#000000"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#6697e6"
@@ -773,7 +773,7 @@
button="#99999900"
button_title="#1a1a1a"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#b3b3b3"
@@ -833,7 +833,7 @@
button="#99999900"
button_title="#1a1a1a"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#b3b3b3"
@@ -870,7 +870,7 @@
button="#7272727f"
button_title="#000000"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#656565ff"
execution_buts="#00000000"
tab_active="#6697e6"
@@ -917,7 +917,7 @@
button="#7272727f"
button_title="#000000"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#6697e6"
@@ -939,7 +939,7 @@
</text_editor>
<node_editor>
<ThemeNodeEditor
- grid="#353535"
+ grid="#1B1B1B"
node_selected="#f15800"
node_active="#f15800"
wire="#191919"
@@ -955,7 +955,7 @@
matte_node="#977474"
distor_node="#749797"
noodle_curving="4"
- grid_levels="2"
+ grid_levels="7"
dash_alpha="0.5"
input_node="#cb3d4a"
output_node="#cb3d4a"
@@ -981,7 +981,7 @@
button="#99999900"
button_title="#1a1a1a"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#b3b3b3"
@@ -1032,7 +1032,7 @@
button="#7272727f"
button_title="#000000"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#6697e6"
@@ -1081,7 +1081,7 @@
button="#7272727f"
button_title="#000000"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#6697e6"
@@ -1115,7 +1115,7 @@
button="#7272727f"
button_title="#000000"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#b3b3b3ff"
execution_buts="#b3b3b3ff"
tab_active="#6697e6"
@@ -1156,7 +1156,7 @@
button="#7272727f"
button_title="#000000"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#6697e6"
@@ -1221,7 +1221,7 @@
button="#7272727f"
button_title="#000000"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#6697e6"
@@ -1263,8 +1263,8 @@
header_text_hi="#ffffff"
button="#2f303599"
button_title="#ffffff"
- button_text="#ffffff"
- button_text_hi="#ffffff"
+ button_text="#000000"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#446499"
@@ -1298,7 +1298,7 @@
button="#2f303500"
button_title="#ffffff"
button_text="#ffffff"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#00000000"
tab_active="#446499"
@@ -1334,7 +1334,7 @@
button="#999999e6"
button_title="#1a1a1a"
button_text="#000000"
- button_text_hi="#ffffff"
+ button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#999999e6"
tab_active="#6697e6"
diff --git a/release/scripts/presets/keyconfig/Blender.py b/release/scripts/presets/keyconfig/Blender.py
index 1852e150589..35c920b3f40 100644
--- a/release/scripts/presets/keyconfig/Blender.py
+++ b/release/scripts/presets/keyconfig/Blender.py
@@ -56,7 +56,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
update=update_fn,
)
tool_key_mode: EnumProperty(
- name="Tool Keys:",
+ name="Tool Keys",
description=(
"The method of keys to activate tools such as move, rotate & scale (G, R, S)"
),
@@ -242,13 +242,13 @@ class Prefs(bpy.types.KeyConfigPreferences):
# General settings.
col = layout.column()
- col.row().prop(self, "select_mouse", text="Select with Mouse Button:", expand=True)
- col.row().prop(self, "spacebar_action", text="Spacebar Action:", expand=True)
+ col.row().prop(self, "select_mouse", text="Select with Mouse Button", expand=True)
+ col.row().prop(self, "spacebar_action", text="Spacebar Action", expand=True)
if is_select_left:
- col.row().prop(self, "gizmo_action", text="Activate Gizmo Event:", expand=True)
+ col.row().prop(self, "gizmo_action", text="Activate Gizmo Event", expand=True)
else:
- col.row().prop(self, "rmb_action", text="Right Mouse Select Action:", expand=True)
+ col.row().prop(self, "rmb_action", text="Right Mouse Select Action", expand=True)
col.row().prop(self, "tool_key_mode", expand=True)
@@ -271,9 +271,9 @@ class Prefs(bpy.types.KeyConfigPreferences):
# 3DView settings.
col = layout.column()
col.label(text="3D View")
- col.row().prop(self, "v3d_tilde_action", text="Grave Accent / Tilde Action:", expand=True)
- col.row().prop(self, "v3d_mmb_action", text="Middle Mouse Action:", expand=True)
- col.row().prop(self, "v3d_alt_mmb_drag_action", text="Alt Middle Mouse Drag Action:", expand=True)
+ col.row().prop(self, "v3d_tilde_action", text="Grave Accent / Tilde Action", expand=True)
+ col.row().prop(self, "v3d_mmb_action", text="Middle Mouse Action", expand=True)
+ col.row().prop(self, "v3d_alt_mmb_drag_action", text="Alt Middle Mouse Drag Action", expand=True)
# Checkboxes sub-layout.
col = layout.column()
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index e70fe63677a..9f921bd2b70 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -208,7 +208,6 @@ class Params:
# ------------------------------------------------------------------------------
# Constants
-
# Physical layout.
NUMBERS_1 = ('ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE', 'ZERO')
# Numeric order.
@@ -846,8 +845,156 @@ def km_user_interface(_params):
# ------------------------------------------------------------------------------
-# Editors
+# Shared Between Editors (Mask, Time-Line)
+def km_mask_editing(params):
+ items = []
+ keymap = (
+ "Mask Editing",
+ {"space_type": 'EMPTY', "region_type": 'WINDOW'},
+ {"items": items},
+ )
+
+ if params.select_mouse == 'RIGHTMOUSE':
+ # mask.slide_point performs mostly the same function, so for the left
+ # click select keymap it's fine to have the context menu instead.
+ items.extend([
+ ("mask.select", {"type": 'RIGHTMOUSE', "value": 'PRESS'},
+ {"properties": [("deselect_all", not params.legacy)]}),
+ ("transform.translate", {"type": 'EVT_TWEAK_R', "value": 'ANY'}, None),
+ ])
+
+ items.extend([
+ ("mask.new", {"type": 'N', "value": 'PRESS', "alt": True}, None),
+ op_menu("MASK_MT_add", {"type": 'A', "value": 'PRESS', "shift": True}),
+ *_template_items_proportional_editing(
+ params, connected=False, toggle_data_path='tool_settings.use_proportional_edit_mask'),
+ ("mask.add_vertex_slide", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
+ ("mask.add_feather_vertex_slide", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
+ ("mask.delete", {"type": 'X', "value": 'PRESS'}, None),
+ ("mask.delete", {"type": 'DEL', "value": 'PRESS'}, None),
+ ("mask.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True},
+ {"properties": [("toggle", True)]}),
+ *_template_items_select_actions(params, "mask.select_all"),
+ ("mask.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
+ ("mask.select_linked_pick", {"type": 'L', "value": 'PRESS'},
+ {"properties": [("deselect", False)]}),
+ ("mask.select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True},
+ {"properties": [("deselect", True)]}),
+ ("mask.select_box", {"type": 'B', "value": 'PRESS'}, None),
+ ("mask.select_circle", {"type": 'C', "value": 'PRESS'}, None),
+ ("mask.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True},
+ {"properties": [("mode", 'ADD')]}),
+ ("mask.select_lasso", {"type": params.action_tweak, "value": 'ANY', "shift": True, "ctrl": True, "alt": True},
+ {"properties": [("mode", 'SUB')]}),
+ ("mask.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
+ ("mask.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
+ *_template_items_hide_reveal_actions("mask.hide_view_set", "mask.hide_view_clear"),
+ ("clip.select", {"type": params.select_mouse, "value": 'PRESS', "ctrl": True}, None),
+ ("mask.cyclic_toggle", {"type": 'C', "value": 'PRESS', "alt": True}, None),
+ ("mask.slide_point", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
+ ("mask.slide_spline_curvature", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
+ ("mask.handle_type_set", {"type": 'V', "value": 'PRESS'}, None),
+ ("mask.normals_make_consistent",
+ {"type": 'N', "value": 'PRESS', "ctrl" if params.legacy else "shift": True}, None),
+ ("mask.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None),
+ ("mask.parent_clear", {"type": 'P', "value": 'PRESS', "alt": True}, None),
+ ("mask.shape_key_insert", {"type": 'I', "value": 'PRESS'}, None),
+ ("mask.shape_key_clear", {"type": 'I', "value": 'PRESS', "alt": True}, None),
+ ("mask.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ ("mask.copy_splines", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
+ ("mask.paste_splines", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
+ ("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
+ ("transform.translate", {"type": params.select_tweak, "value": 'ANY'}, None),
+ ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
+ ("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
+ ("transform.tosphere", {"type": 'S', "value": 'PRESS', "shift": True, "alt": True}, None),
+ ("transform.shear", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
+ ("transform.transform", {"type": 'S', "value": 'PRESS', "alt": True},
+ {"properties": [("mode", 'MASK_SHRINKFATTEN')]}),
+ ])
+
+ # 3D cursor
+ if params.cursor_tweak_event:
+ items.extend([
+ ("uv.cursor_set", params.cursor_set_event, None),
+ ("transform.translate", params.cursor_tweak_event,
+ {"properties": [("release_confirm", True), ("cursor_transform", True)]}),
+ ])
+ else:
+ items.extend([
+ ("uv.cursor_set", params.cursor_set_event, None),
+ ])
+
+ return keymap
+
+
+def km_markers(params):
+ items = []
+ keymap = (
+ "Markers",
+ {"space_type": 'EMPTY', "region_type": 'WINDOW'},
+ {"items": items},
+ )
+
+ items.extend([
+ ("marker.add", {"type": 'M', "value": 'PRESS'}, None),
+ ("marker.move", {"type": params.select_tweak, "value": 'ANY'},
+ {"properties": [("tweak", True)]}),
+ ("marker.duplicate", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ ("marker.select", {"type": params.select_mouse, "value": 'PRESS'}, None),
+ ("marker.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True},
+ {"properties": [("extend", True)]}),
+ ("marker.select", {"type": params.select_mouse, "value": 'PRESS', "ctrl": True},
+ {"properties": [("camera", True)]}),
+ ("marker.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True, "ctrl": True},
+ {"properties": [("extend", True), ("camera", True)]}),
+ ("marker.select_box", {"type": params.select_tweak, "value": 'ANY'},
+ {"properties": [("tweak", True)]}),
+ ("marker.select_box", {"type": 'B', "value": 'PRESS'}, None),
+ *_template_items_select_actions(params, "marker.select_all"),
+ ("marker.delete", {"type": 'X', "value": 'PRESS'}, None),
+ ("marker.delete", {"type": 'DEL', "value": 'PRESS'}, None),
+ ("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
+ ("marker.move", {"type": 'G', "value": 'PRESS'}, None),
+ ("marker.camera_bind", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
+ ])
+
+ return keymap
+
+
+def km_time_scrub(_params):
+ items = []
+ keymap = (
+ "Time Scrub",
+ {"space_type": 'EMPTY', "region_type": 'WINDOW'},
+ {"items": items},
+ )
+
+ items.extend([
+ ("anim.change_frame", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
+ ])
+
+ return keymap
+
+
+def km_time_scrub_clip(_params):
+ items = []
+ keymap = (
+ "Clip Time Scrub",
+ {"space_type": 'CLIP_EDITOR', "region_type": 'PREVIEW'},
+ {"items": items},
+ )
+
+ items.extend([
+ ("clip.change_frame", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
+ ])
+
+ return keymap
+
+
+# ------------------------------------------------------------------------------
+# Editor (Property Editor)
def km_property_editor(_params):
items = []
@@ -894,6 +1041,9 @@ def km_property_editor(_params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (Outliner)
+
def km_outliner(params):
items = []
keymap = (
@@ -983,6 +1133,9 @@ def km_outliner(params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (UV Editor)
+
def km_uv_editor(params):
items = []
keymap = (
@@ -1114,6 +1267,9 @@ def km_uv_editor(params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (3D View)
+
# 3D View: all regions.
def km_view3d_generic(_params):
items = []
@@ -1478,151 +1634,8 @@ def km_view3d(params):
return keymap
-def km_mask_editing(params):
- items = []
- keymap = (
- "Mask Editing",
- {"space_type": 'EMPTY', "region_type": 'WINDOW'},
- {"items": items},
- )
-
- if params.select_mouse == 'RIGHTMOUSE':
- # mask.slide_point performs mostly the same function, so for the left
- # click select keymap it's fine to have the context menu instead.
- items.extend([
- ("mask.select", {"type": 'RIGHTMOUSE', "value": 'PRESS'},
- {"properties": [("deselect_all", not params.legacy)]}),
- ("transform.translate", {"type": 'EVT_TWEAK_R', "value": 'ANY'}, None),
- ])
-
- items.extend([
- ("mask.new", {"type": 'N', "value": 'PRESS', "alt": True}, None),
- op_menu("MASK_MT_add", {"type": 'A', "value": 'PRESS', "shift": True}),
- *_template_items_proportional_editing(
- params, connected=False, toggle_data_path='tool_settings.use_proportional_edit_mask'),
- ("mask.add_vertex_slide", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
- ("mask.add_feather_vertex_slide", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
- ("mask.delete", {"type": 'X', "value": 'PRESS'}, None),
- ("mask.delete", {"type": 'DEL', "value": 'PRESS'}, None),
- ("mask.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True},
- {"properties": [("toggle", True)]}),
- *_template_items_select_actions(params, "mask.select_all"),
- ("mask.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
- ("mask.select_linked_pick", {"type": 'L', "value": 'PRESS'},
- {"properties": [("deselect", False)]}),
- ("mask.select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True},
- {"properties": [("deselect", True)]}),
- ("mask.select_box", {"type": 'B', "value": 'PRESS'}, None),
- ("mask.select_circle", {"type": 'C', "value": 'PRESS'}, None),
- ("mask.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True},
- {"properties": [("mode", 'ADD')]}),
- ("mask.select_lasso", {"type": params.action_tweak, "value": 'ANY', "shift": True, "ctrl": True, "alt": True},
- {"properties": [("mode", 'SUB')]}),
- ("mask.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
- ("mask.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
- *_template_items_hide_reveal_actions("mask.hide_view_set", "mask.hide_view_clear"),
- ("clip.select", {"type": params.select_mouse, "value": 'PRESS', "ctrl": True}, None),
- ("mask.cyclic_toggle", {"type": 'C', "value": 'PRESS', "alt": True}, None),
- ("mask.slide_point", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
- ("mask.slide_spline_curvature", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
- ("mask.handle_type_set", {"type": 'V', "value": 'PRESS'}, None),
- ("mask.normals_make_consistent",
- {"type": 'N', "value": 'PRESS', "ctrl" if params.legacy else "shift": True}, None),
- ("mask.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None),
- ("mask.parent_clear", {"type": 'P', "value": 'PRESS', "alt": True}, None),
- ("mask.shape_key_insert", {"type": 'I', "value": 'PRESS'}, None),
- ("mask.shape_key_clear", {"type": 'I', "value": 'PRESS', "alt": True}, None),
- ("mask.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
- ("mask.copy_splines", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
- ("mask.paste_splines", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
- ("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
- ("transform.translate", {"type": params.select_tweak, "value": 'ANY'}, None),
- ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
- ("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
- ("transform.tosphere", {"type": 'S', "value": 'PRESS', "shift": True, "alt": True}, None),
- ("transform.shear", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
- ("transform.transform", {"type": 'S', "value": 'PRESS', "alt": True},
- {"properties": [("mode", 'MASK_SHRINKFATTEN')]}),
- ])
-
- # 3D cursor
- if params.cursor_tweak_event:
- items.extend([
- ("uv.cursor_set", params.cursor_set_event, None),
- ("transform.translate", params.cursor_tweak_event,
- {"properties": [("release_confirm", True), ("cursor_transform", True)]}),
- ])
- else:
- items.extend([
- ("uv.cursor_set", params.cursor_set_event, None),
- ])
-
- return keymap
-
-
-def km_markers(params):
- items = []
- keymap = (
- "Markers",
- {"space_type": 'EMPTY', "region_type": 'WINDOW'},
- {"items": items},
- )
-
- items.extend([
- ("marker.add", {"type": 'M', "value": 'PRESS'}, None),
- ("marker.move", {"type": params.select_tweak, "value": 'ANY'},
- {"properties": [("tweak", True)]}),
- ("marker.duplicate", {"type": 'D', "value": 'PRESS', "shift": True}, None),
- ("marker.select", {"type": params.select_mouse, "value": 'PRESS'}, None),
- ("marker.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True},
- {"properties": [("extend", True)]}),
- ("marker.select", {"type": params.select_mouse, "value": 'PRESS', "ctrl": True},
- {"properties": [("camera", True)]}),
- ("marker.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True, "ctrl": True},
- {"properties": [("extend", True), ("camera", True)]}),
- ("marker.select_box", {"type": params.select_tweak, "value": 'ANY'},
- {"properties": [("tweak", True)]}),
- ("marker.select_box", {"type": 'B', "value": 'PRESS'}, None),
- *_template_items_select_actions(params, "marker.select_all"),
- ("marker.delete", {"type": 'X', "value": 'PRESS'}, None),
- ("marker.delete", {"type": 'DEL', "value": 'PRESS'}, None),
- ("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
- ("marker.move", {"type": 'G', "value": 'PRESS'}, None),
- ("marker.camera_bind", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
- ])
-
- return keymap
-
-
-def km_time_scrub(_params):
- items = []
- keymap = (
- "Time Scrub",
- {"space_type": 'EMPTY', "region_type": 'WINDOW'},
- {"items": items},
- )
-
- items.extend([
- ("anim.change_frame", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
- ])
-
- return keymap
-
-
-def km_time_scrub_clip(_params):
- items = []
- keymap = (
- "Clip Time Scrub",
- {"space_type": 'CLIP_EDITOR', "region_type": 'PREVIEW'},
- {"items": items},
- )
-
- items.extend([
- ("clip.change_frame", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
- ])
-
- return keymap
-
+# ------------------------------------------------------------------------------
+# Editor (Graph Editor)
def km_graph_editor_generic(_params):
items = []
@@ -1637,7 +1650,7 @@ def km_graph_editor_generic(_params):
sidebar_key={"type": 'N', "value": 'PRESS'},
),
("graph.extrapolation_type", {"type": 'E', "value": 'PRESS', "shift": True}, None),
- ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
+ ("anim.channels_select_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
*_template_items_hide_reveal_actions("graph.hide", "graph.reveal"),
("wm.context_set_enum", {"type": 'TAB', "value": 'PRESS', "ctrl": True},
{"properties": [("data_path", 'area.type'), ("value", 'DOPESHEET_EDITOR')]}),
@@ -1777,6 +1790,9 @@ def km_graph_editor(params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (Image)
+
def km_image_generic(params):
items = []
keymap = (
@@ -1899,6 +1915,9 @@ def km_image(params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (Node)
+
def km_node_generic(_params):
items = []
keymap = (
@@ -2072,6 +2091,9 @@ def km_node_editor(params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (Info)
+
def km_info(params):
items = []
keymap = (
@@ -2098,6 +2120,9 @@ def km_info(params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (File Browser)
+
def km_file_browser(params):
items = []
keymap = (
@@ -2115,7 +2140,9 @@ def km_file_browser(params):
("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "alt": True}, None),
("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, None),
("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, None),
+ # The two refresh operators have polls excluding each other (so only one is available depending on context).
("file.refresh", {"type": 'R', "value": 'PRESS'}, None),
+ ("file.asset_library_refresh", {"type": 'R', "value": 'PRESS'}, None),
("file.parent", {"type": 'P', "value": 'PRESS'}, None),
("file.previous", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None),
@@ -2165,7 +2192,7 @@ def km_file_browser_main(params):
if not params.use_file_single_click:
items.extend([
("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
- {"properties": [("open", True), ("deselect_all", not params.legacy)]}),
+ {"properties": [("open", True), ("deselect_all", not params.legacy)]}),
])
items.extend([
@@ -2248,6 +2275,9 @@ def km_file_browser_buttons(_params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (Dope Sheet)
+
def km_dopesheet_generic(_params):
items = []
keymap = (
@@ -2359,7 +2389,7 @@ def km_dopesheet(params):
("action.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
("action.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None),
("anim.channels_editable_toggle", {"type": 'TAB', "value": 'PRESS'}, None),
- ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
+ ("anim.channels_select_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
("transform.transform", {"type": 'G', "value": 'PRESS'},
{"properties": [("mode", 'TIME_TRANSLATE')]}),
("transform.transform", {"type": params.select_tweak, "value": 'ANY'},
@@ -2382,6 +2412,9 @@ def km_dopesheet(params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (NLA)
+
def km_nla_generic(_params):
items = []
keymap = (
@@ -2400,7 +2433,7 @@ def km_nla_generic(_params):
{"properties": [("isolate_action", True)]}),
("nla.tweakmode_exit", {"type": 'TAB', "value": 'PRESS', "shift": True},
{"properties": [("isolate_action", True)]}),
- ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
+ ("anim.channels_select_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
])
return keymap
@@ -2511,6 +2544,9 @@ def km_nla_editor(params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (Text)
+
def km_text_generic(_params):
items = []
keymap = (
@@ -2672,6 +2708,9 @@ def km_text(params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (Sequencer)
+
def km_sequencercommon(params):
items = []
keymap = (
@@ -2831,7 +2870,10 @@ def km_sequencerpreview(params):
value=params.select_mouse_value_fallback,
legacy=params.legacy,
),
+ *_template_items_select_actions(params, "sequencer.select_all"),
+ ("sequencer.select_box", {"type": 'B', "value": 'PRESS'}, None),
+ # View.
("sequencer.view_all_preview", {"type": 'HOME', "value": 'PRESS'}, None),
("sequencer.view_all_preview", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None),
("sequencer.view_ghost_border", {"type": 'O', "value": 'PRESS'}, None),
@@ -2849,6 +2891,8 @@ def km_sequencerpreview(params):
{"properties": [("ratio", 0.25)]}),
("sequencer.view_zoom_ratio", {"type": 'NUMPAD_8', "value": 'PRESS'},
{"properties": [("ratio", 0.125)]}),
+
+ # Edit.
("transform.translate", {"type": params.select_tweak, "value": 'ANY'}, None),
op_tool_optional(
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
@@ -2865,6 +2909,10 @@ def km_sequencerpreview(params):
{"properties": [("property", 'SCALE')]}),
("sequencer.strip_transform_clear", {"type": 'R', "alt": True, "value": 'PRESS'},
{"properties": [("property", 'ROTATION')]}),
+
+ ("sequencer.delete", {"type": 'X', "value": 'PRESS'}, None),
+ ("sequencer.delete", {"type": 'DEL', "value": 'PRESS'}, None),
+
*_template_items_context_menu("SEQUENCER_MT_preview_context_menu", params.context_menu_event),
])
@@ -2893,6 +2941,9 @@ def km_sequencerpreview(params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (Console)
+
def km_console(_params):
items = []
keymap = (
@@ -2958,6 +3009,9 @@ def km_console(_params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (Clip)
+
def km_clip(_params):
items = []
keymap = (
@@ -3187,6 +3241,9 @@ def km_clip_dopesheet_editor(_params):
return keymap
+# ------------------------------------------------------------------------------
+# Editor (Spreadsheet)
+
def km_spreadsheet_generic(_params):
items = []
keymap = (
@@ -3208,7 +3265,6 @@ def km_spreadsheet_generic(_params):
# ------------------------------------------------------------------------------
# Animation
-
def km_frames(params):
items = []
keymap = (
@@ -3328,7 +3384,7 @@ def km_animation_channels(params):
("anim.channel_select_keys", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "shift": True},
{"properties": [("extend", True)]}),
# Find (setting the name filter).
- ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
+ ("anim.channels_select_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
# Selection.
*_template_items_select_actions(params, "anim.channels_select_all"),
("anim.channels_select_box", {"type": 'B', "value": 'PRESS'}, None),
@@ -3372,8 +3428,7 @@ def km_animation_channels(params):
# ------------------------------------------------------------------------------
-# Modes
-
+# Object Modes
def km_grease_pencil(params):
items = []
@@ -4607,17 +4662,6 @@ def _template_view3d_select(*, type, value, legacy):
)]
-def _template_view3d_select_for_fallback(params, fallback):
- if (not fallback) and params.use_fallback_tool_rmb:
- # Needed so we have immediate select+tweak when the default select tool is active.
- return _template_view3d_select(
- type=params.select_mouse,
- value=params.select_mouse_value,
- legacy=params.legacy,
- )
- return []
-
-
def _template_view3d_gpencil_select(*, type, value, legacy, use_select_mouse=True):
return [
*([] if not use_select_mouse else [
@@ -4633,17 +4677,6 @@ def _template_view3d_gpencil_select(*, type, value, legacy, use_select_mouse=Tru
]
-def _template_view3d_gpencil_select_for_fallback(params, fallback):
- if (not fallback) and params.use_fallback_tool_rmb:
- # Needed so we have immediate select+tweak when the default select tool is active.
- return _template_view3d_gpencil_select(
- type=params.select_mouse,
- value=params.select_mouse_value,
- legacy=params.legacy,
- )
- return []
-
-
def _template_uv_select(*, type, value, legacy):
return [
("uv.select", {"type": type, "value": value},
@@ -4653,17 +4686,6 @@ def _template_uv_select(*, type, value, legacy):
]
-def _template_uv_select_for_fallback(params, fallback):
- if (not fallback) and params.use_fallback_tool_rmb:
- # Needed so we have immediate select+tweak when the default select tool is active.
- return _template_uv_select(
- type=params.select_mouse,
- value=params.select_mouse_value,
- legacy=params.legacy,
- )
- return []
-
-
def _template_sequencer_generic_select(*, type, value, legacy):
return [(
"sequencer.select",
@@ -4686,7 +4708,7 @@ def _template_sequencer_preview_select(*, type, value, legacy):
(("center",), ("ctrl",)),
# TODO:
# (("enumerate",), ("alt",)),
- (("toggle", "center"), ("shift", "ctrl")),
+ (("toggle", "center"), ("shift", "ctrl")),
# (("center", "enumerate"), ("ctrl", "alt")),
# (("toggle", "enumerate"), ("shift", "alt")),
# (("toggle", "center", "enumerate"), ("shift", "ctrl", "alt")),
@@ -4709,17 +4731,6 @@ def _template_sequencer_timeline_select(*, type, value, legacy):
)]
-def _template_sequencer_select_for_fallback(params, fallback):
- if (not fallback) and params.use_fallback_tool_rmb:
- # Needed so we have immediate select+tweak when the default select tool is active.
- return _template_sequencer_generic_select(
- type=params.select_mouse,
- value=params.select_mouse_value,
- legacy=params.legacy,
- )
- return []
-
-
def km_image_paint(params):
items = []
keymap = (
@@ -5486,7 +5497,6 @@ def km_object_non_modal(params):
# ------------------------------------------------------------------------------
# Modal Maps and Gizmos
-
def km_eyedropper_modal_map(_params):
items = []
keymap = (
@@ -6160,11 +6170,10 @@ def km_popup_toolbar(_params):
# ------------------------------------------------------------------------------
-# Tool System Keymaps
+# Tool System (Generic)
#
# Named are auto-generated based on the tool name and it's toolbar.
-
def km_generic_tool_annotate(params):
return (
"Generic Tool: Annotate",
@@ -6227,6 +6236,9 @@ def km_image_editor_tool_generic_sample(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (UV Editor)
+
def km_image_editor_tool_uv_cursor(params):
return (
"Image Editor Tool: Uv, Cursor",
@@ -6261,7 +6273,6 @@ def km_image_editor_tool_uv_select_box(params, *, fallback):
"uv.select_box",
# Don't use `tool_maybe_tweak_event`, see comment for this slot.
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
- *_template_uv_select_for_fallback(params, fallback),
]},
)
@@ -6289,7 +6300,6 @@ def km_image_editor_tool_uv_select_lasso(params, *, fallback):
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions_simple(
"uv.select_lasso",
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
- *_template_uv_select_for_fallback(params, fallback),
]},
)
@@ -6357,6 +6367,9 @@ def km_image_editor_tool_uv_scale(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (Node Editor)
+
def km_node_editor_tool_select(params, *, fallback):
return (
_fallback_id("Node Tool: Tweak", fallback),
@@ -6377,7 +6390,8 @@ def km_node_editor_tool_select_box(params, *, fallback):
{"items": [
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions_simple(
"node.select_box",
- type=params.tool_maybe_tweak, value=params.tool_maybe_tweak_value,
+ # Don't use `tool_maybe_tweak_event`, see comment for this slot.
+ **(params.select_tweak_event if fallback else params.tool_tweak_event),
properties=[("tweak", True)],
)),
]},
@@ -6390,7 +6404,7 @@ def km_node_editor_tool_select_lasso(params, *, fallback):
{"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'},
{"items": [
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions_simple(
- "node.select_lasso", type=params.tool_mouse, value='PRESS',
+ "node.select_lasso", **(params.select_tweak_event if fallback else params.tool_tweak_event),
properties=[("tweak", True)]))
]},
)
@@ -6402,7 +6416,11 @@ def km_node_editor_tool_select_circle(params, *, fallback):
{"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'},
{"items": [
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions_simple(
- "node.select_circle", type=params.tool_mouse, value='PRESS',
+ "node.select_circle",
+ # Why circle select should be used on tweak?
+ # So that RMB or Shift-RMB is still able to set an element as active.
+ type=params.select_tweak if fallback else params.tool_mouse,
+ value='ANY' if fallback else 'PRESS',
properties=[("wait_for_input", False)])),
]},
)
@@ -6418,6 +6436,9 @@ def km_node_editor_tool_links_cut(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Generic)
+
def km_3d_view_tool_cursor(params):
return (
"3D View Tool: Cursor",
@@ -6453,7 +6474,6 @@ def km_3d_view_tool_select_box(params, *, fallback):
"view3d.select_box",
# Don't use `tool_maybe_tweak_event`, see comment for this slot.
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
- *_template_view3d_select_for_fallback(params, fallback),
]},
)
@@ -6470,7 +6490,6 @@ def km_3d_view_tool_select_circle(params, *, fallback):
type=params.select_tweak if fallback else params.tool_mouse,
value='ANY' if fallback else 'PRESS',
properties=[("wait_for_input", False)])),
- # No selection fallback since this operates on press.
]},
)
@@ -6483,7 +6502,6 @@ def km_3d_view_tool_select_lasso(params, *, fallback):
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions(
"view3d.select_lasso",
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
- *_template_view3d_select_for_fallback(params, fallback),
]}
)
@@ -6564,6 +6582,9 @@ def km_3d_view_tool_measure(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Pose Mode)
+
def km_3d_view_tool_pose_breakdowner(params):
return (
"3D View Tool: Pose, Breakdowner",
@@ -6594,6 +6615,9 @@ def km_3d_view_tool_pose_relax(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Edit Armature)
+
def km_3d_view_tool_edit_armature_roll(params):
return (
"3D View Tool: Edit Armature, Roll",
@@ -6649,6 +6673,9 @@ def km_3d_view_tool_edit_armature_extrude_to_cursor(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Object Mode)
+
def km_3d_view_tool_interactive_add(params):
return (
"3D View Tool: Object, Add Primitive",
@@ -6665,6 +6692,9 @@ def km_3d_view_tool_interactive_add(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Edit Mesh)
+
def km_3d_view_tool_edit_mesh_extrude_region(params):
return (
"3D View Tool: Edit Mesh, Extrude Region",
@@ -6931,6 +6961,9 @@ def km_3d_view_tool_edit_mesh_rip_edge(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Edit Curve)
+
def km_3d_view_tool_edit_curve_draw(params):
return (
"3D View Tool: Edit Curve, Draw",
@@ -6998,6 +7031,9 @@ def km_3d_view_tool_edit_curve_extrude_to_cursor(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Sculpt)
+
def km_3d_view_tool_sculpt_box_hide(params):
return (
"3D View Tool: Sculpt, Box Hide",
@@ -7153,6 +7189,9 @@ def km_3d_view_tool_sculpt_face_set_edit(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Weight Paint)
+
def km_3d_view_tool_paint_weight_sample_weight(params):
return (
"3D View Tool: Paint Weight, Sample Weight",
@@ -7183,6 +7222,9 @@ def km_3d_view_tool_paint_weight_gradient(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Grease Pencil, Paint)
+
def km_3d_view_tool_paint_gpencil_line(params):
return (
"3D View Tool: Paint Gpencil, Line",
@@ -7317,6 +7359,9 @@ def km_3d_view_tool_paint_gpencil_interpolate(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Grease Pencil, Edit)
+
def km_3d_view_tool_edit_gpencil_select(params, *, fallback):
return (
_fallback_id("3D View Tool: Edit Gpencil, Tweak", fallback),
@@ -7339,7 +7384,6 @@ def km_3d_view_tool_edit_gpencil_select_box(params, *, fallback):
"gpencil.select_box",
# Don't use `tool_maybe_tweak_event`, see comment for this slot.
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
- *_template_view3d_gpencil_select_for_fallback(params, fallback),
]},
)
@@ -7356,7 +7400,6 @@ def km_3d_view_tool_edit_gpencil_select_circle(params, *, fallback):
type=params.select_tweak if fallback else params.tool_mouse,
value='ANY' if fallback else 'PRESS',
properties=[("wait_for_input", False)])),
- # No selection fallback since this operates on press.
]},
)
@@ -7369,7 +7412,6 @@ def km_3d_view_tool_edit_gpencil_select_lasso(params, *, fallback):
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions(
"gpencil.select_lasso",
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
- *_template_view3d_gpencil_select_for_fallback(params, fallback),
]}
)
@@ -7455,6 +7497,9 @@ def km_3d_view_tool_edit_gpencil_interpolate(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (3D View, Grease Pencil, Sculpt)
+
def km_3d_view_tool_sculpt_gpencil_select(params):
return (
"3D View Tool: Sculpt Gpencil, Tweak",
@@ -7490,24 +7535,26 @@ def km_3d_view_tool_sculpt_gpencil_select_lasso(params):
)
-def km_sequencer_editor_tool_select(params, *, fallback):
+# ------------------------------------------------------------------------------
+# Tool System (Sequencer, Generic)
+
+def km_sequencer_editor_tool_generic_select(params, *, fallback):
return (
_fallback_id("Sequencer Tool: Tweak", fallback),
{"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
{"items": [
- *([] if fallback else
- _template_items_tool_select(params, "sequencer.select", "sequencer.cursor_set", extend="toggle")
- ),
- *([] if (not params.use_fallback_tool_rmb) else _template_sequencer_generic_select(
- type=params.select_mouse, value=params.select_mouse_value, legacy=params.legacy)),
+ *([] if fallback else _template_items_tool_select(
+ params, "sequencer.select", "sequencer.cursor_set", extend="toggle")),
+ *([] if (not params.use_fallback_tool_rmb) else _template_sequencer_preview_select(
+ type=params.select_mouse, value=params.select_mouse_value_fallback, legacy=params.legacy)),
# Ignored for preview.
*_template_items_change_frame(params),
]},
)
-def km_sequencer_editor_tool_select_box(params, *, fallback):
+def km_sequencer_editor_tool_generic_select_box(params, *, fallback):
return (
_fallback_id("Sequencer Tool: Select Box", fallback),
{"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
@@ -7517,7 +7564,6 @@ def km_sequencer_editor_tool_select_box(params, *, fallback):
"sequencer.select_box",
**(params.select_tweak_event if fallback else params.tool_tweak_event),
properties=[("tweak", params.select_mouse == 'LEFTMOUSE')])),
- *_template_sequencer_select_for_fallback(params, fallback),
# RMB select can already set the frame, match the tweak tool.
# Ignored for preview.
@@ -7527,17 +7573,7 @@ def km_sequencer_editor_tool_select_box(params, *, fallback):
)
-def km_sequencer_editor_tool_generic_sample(params):
- return (
- "Sequencer Tool: Sample",
- {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
- {"items": [
- ("sequencer.sample", {"type": params.tool_mouse, "value": 'PRESS'}, None),
- ]},
- )
-
-
-def km_sequencer_editor_tool_cursor(params):
+def km_sequencer_editor_tool_generic_cursor(params):
return (
"Sequencer Tool: Cursor",
{"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
@@ -7550,6 +7586,9 @@ def km_sequencer_editor_tool_cursor(params):
)
+# ------------------------------------------------------------------------------
+# Tool System (Sequencer, Timeline)
+
def km_sequencer_editor_tool_blade(_params):
return (
"Sequencer Tool: Blade",
@@ -7566,6 +7605,19 @@ def km_sequencer_editor_tool_blade(_params):
)
+# ------------------------------------------------------------------------------
+# Tool System (Sequencer, Preview)
+
+def km_sequencer_editor_tool_sample(params):
+ return (
+ "Sequencer Tool: Sample",
+ {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
+ {"items": [
+ ("sequencer.sample", {"type": params.tool_mouse, "value": 'PRESS'}, None),
+ ]},
+ )
+
+
def km_sequencer_editor_tool_move(params):
return (
"Sequencer Tool: Move",
@@ -7848,14 +7900,14 @@ def generate_keymaps(params=None):
km_3d_view_tool_sculpt_gpencil_select_box(params),
km_3d_view_tool_sculpt_gpencil_select_circle(params),
km_3d_view_tool_sculpt_gpencil_select_lasso(params),
- *(km_sequencer_editor_tool_select(params, fallback=fallback) for fallback in (False, True)),
- *(km_sequencer_editor_tool_select_box(params, fallback=fallback) for fallback in (False, True)),
+ *(km_sequencer_editor_tool_generic_select(params, fallback=fallback) for fallback in (False, True)),
+ *(km_sequencer_editor_tool_generic_select_box(params, fallback=fallback) for fallback in (False, True)),
+ km_sequencer_editor_tool_generic_cursor(params),
km_sequencer_editor_tool_blade(params),
- km_sequencer_editor_tool_generic_sample(params),
- km_sequencer_editor_tool_cursor(params),
- km_sequencer_editor_tool_scale(params),
- km_sequencer_editor_tool_rotate(params),
+ km_sequencer_editor_tool_sample(params),
km_sequencer_editor_tool_move(params),
+ km_sequencer_editor_tool_rotate(params),
+ km_sequencer_editor_tool_scale(params),
]
# ------------------------------------------------------------------------------
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index 6baf0d569d6..0ae64dbc62e 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -875,7 +875,7 @@ def km_graph_editor_generic(params):
items.extend([
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
- ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
+ ("anim.channels_select_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
("graph.hide", {"type": 'H', "value": 'PRESS', "ctrl": True},
{"properties": [("unselected", False)]}),
("graph.hide", {"type": 'H', "value": 'PRESS', "shift": True},
@@ -1227,7 +1227,9 @@ def km_file_browser(params):
("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "ctrl": True}, None),
("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, None),
("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True}, None),
+ # The two refresh operators have polls excluding each other (so only one is available depending on context).
("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("file.asset_library_refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("file.previous", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None),
("wm.context_toggle", {"type": 'H', "value": 'PRESS'},
@@ -1272,7 +1274,9 @@ def km_file_browser_main(params):
items.extend([
("file.mouse_execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
+ # The two refresh operators have polls excluding each other (so only one is available depending on context).
("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("file.asset_library_refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
{"properties": [("open", False), ("deselect_all", True)]}),
@@ -1439,7 +1443,7 @@ def km_dopesheet(params):
("action.view_selected", {"type": 'F', "value": 'PRESS'}, None),
("action.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None),
("anim.channels_editable_toggle", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
- ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
+ ("anim.channels_select_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
("transform.transform", {"type": 'W', "value": 'PRESS'},
{"properties": [("mode", 'TIME_TRANSLATE')]}),
("transform.transform", {"type": 'EVT_TWEAK_L', "value": 'ANY'},
@@ -1477,7 +1481,7 @@ def km_nla_generic(params):
*_template_items_animation(),
("nla.tweakmode_enter", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
("nla.tweakmode_exit", {"type": 'ESC', "value": 'PRESS'}, None),
- ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
+ ("anim.channels_select_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
])
return keymap
@@ -2234,7 +2238,7 @@ def km_animation_channels(params):
("anim.channel_select_keys", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "shift": True},
{"properties": [("extend", True)]}),
# Find (setting the name filter).
- ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
+ ("anim.channels_select_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
# Selection.
("anim.channels_select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
("anim.channels_select_all", {"type": 'A', "value": 'PRESS', "ctrl": True, "shift": True}, {"properties": [("action", 'DESELECT')]}),
diff --git a/release/scripts/startup/bl_operators/spreadsheet.py b/release/scripts/startup/bl_operators/spreadsheet.py
index b5098d63dac..ba0c9969356 100644
--- a/release/scripts/startup/bl_operators/spreadsheet.py
+++ b/release/scripts/startup/bl_operators/spreadsheet.py
@@ -50,19 +50,6 @@ class SPREADSHEET_OT_toggle_pin(Operator):
space.is_pinned = False
space.context_path.guess()
- def find_geometry_node_editors(self, context):
- editors = []
- for window in context.window_manager.windows:
- for area in window.screen.areas:
- space = area.spaces.active
- if space.type != 'NODE_EDITOR':
- continue
- if space.edit_tree is None:
- continue
- if space.edit_tree.type == 'GEOMETRY':
- editors.append(space)
- return editors
-
classes = (
SPREADSHEET_OT_toggle_pin,
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index 67a02f6e1f4..1363bcf60e4 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -100,14 +100,6 @@ class PREFERENCES_OT_copy_prev(Operator):
version_new = ((version[0] * 100) + version[1])
version_old = ((version[0] * 100) + version[1]) - 1
- # Special case, remove when the version is > 3.0.
- if version_new == 300:
- version_new = 294
- version_old = 293
- else:
- print("TODO: remove exception!")
- # End special case.
-
# Ensure we only try to copy files from a point release.
# The check below ensures the second numbers match.
while (version_new % 100) // 10 == (version_old % 100) // 10:
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 170b9f3ae44..28bb0a58c02 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1298,6 +1298,13 @@ rna_vector_subtype_items = (
('QUATERNION', "Quaternion Rotation", "Quaternion rotation (affects NLA blending)"),
)
+
+# NOTE: needed for Python 3.10 since there are name-space issues with annotations.
+# This can be moved into the class as a static-method once Python 3.9x is dropped.
+def _wm_properties_edit_subtype_items(_self, _context):
+ return WM_OT_properties_edit.subtype_items
+
+
class WM_OT_properties_edit(Operator):
"""Change a custom property's type, or adjust how it is displayed in the interface"""
bl_idname = "wm.properties_edit"
@@ -1312,7 +1319,7 @@ class WM_OT_properties_edit(Operator):
property_name: rna_custom_property_name
property_type: EnumProperty(
name="Type",
- items=lambda self, _context: WM_OT_properties_edit.type_items,
+ items=rna_custom_property_type_items,
)
is_overridable_library: BoolProperty(
name="Is Library Overridable",
@@ -1404,7 +1411,7 @@ class WM_OT_properties_edit(Operator):
)
subtype: EnumProperty(
name="Subtype",
- items=lambda self, _context: WM_OT_properties_edit.subtype_items,
+ items=_wm_properties_edit_subtype_items,
)
# String properties.
@@ -1442,7 +1449,7 @@ class WM_OT_properties_edit(Operator):
# Convert an old property for a string, avoiding unhelpful string representations for custom list types.
@staticmethod
- def _convert_old_property_to_string(item, name):
+ def convert_custom_property_to_string(item, name):
# The IDProperty group view API currently doesn't have a "lookup" method.
for key, value in item.items():
if key == name:
@@ -1461,7 +1468,8 @@ class WM_OT_properties_edit(Operator):
# Retrieve the current type of the custom property on the RNA struct. Some properties like group properties
# can be created in the UI, but editing their meta-data isn't supported. In that case, return 'PYTHON'.
- def _get_property_type(self, item, property_name):
+ @staticmethod
+ def get_property_type(item, property_name):
from rna_prop_ui import (
rna_idprop_value_item_type,
)
@@ -1549,17 +1557,17 @@ class WM_OT_properties_edit(Operator):
return self._convert_new_value_single(item[name_old], float)
if prop_type_new == 'INT_ARRAY':
- prop_type_old = self._get_property_type(item, name_old)
+ prop_type_old = self.get_property_type(item, name_old)
if prop_type_old in {'INT', 'FLOAT', 'INT_ARRAY', 'FLOAT_ARRAY'}:
return self._convert_new_value_array(item[name_old], int, self.array_length)
if prop_type_new == 'FLOAT_ARRAY':
- prop_type_old = self._get_property_type(item, name_old)
+ prop_type_old = self.get_property_type(item, name_old)
if prop_type_old in {'INT', 'FLOAT', 'FLOAT_ARRAY', 'INT_ARRAY'}:
return self._convert_new_value_array(item[name_old], float, self.array_length)
if prop_type_new == 'STRING':
- return self._convert_old_property_to_string(item, name_old)
+ return self.convert_custom_property_to_string(item, name_old)
# If all else fails, create an empty string property. That should avoid errors later on anyway.
return ""
@@ -1672,7 +1680,7 @@ class WM_OT_properties_edit(Operator):
self.report({'ERROR'}, "Cannot edit properties from override data")
return {'CANCELLED'}
- prop_type_old = self._get_property_type(item, name_old)
+ prop_type_old = self.get_property_type(item, name_old)
prop_type_new = self.property_type
self._old_prop_name[:] = [name]
@@ -1716,14 +1724,14 @@ class WM_OT_properties_edit(Operator):
return {'CANCELLED'}
# Set operator's property type with the type of the existing property, to display the right settings.
- old_type = self._get_property_type(item, name)
+ old_type = self.get_property_type(item, name)
self.property_type = old_type
self.last_property_type = old_type
# So that the operator can do something for unsupported properties, change the property into
# a string, just for editing in the dialog. When the operator executes, it will be converted back
# into a python value. Always do this conversion, in case the Python property edit type is selected.
- self.eval_string = self._convert_old_property_to_string(item, name)
+ self.eval_string = self.convert_custom_property_to_string(item, name)
if old_type != 'PYTHON':
self._fill_old_ui_data(item, name)
@@ -1845,6 +1853,62 @@ class WM_OT_properties_edit(Operator):
layout.prop(self, "description")
+# Edit the value of a custom property with the given name on the RNA struct at the given data path.
+# For supported types, this simply acts as a convenient way to create a popup for a specific property
+# and draws the custom property value directly in the popup. For types like groups which can't be edited
+# directly with buttons, instead convert the value to a string, evaluate the changed string when executing.
+class WM_OT_properties_edit_value(Operator):
+ """Edit the value of a custom property"""
+ bl_idname = "wm.properties_edit_value"
+ bl_label = "Edit Property Value"
+ # register only because invoke_props_popup requires.
+ bl_options = {'REGISTER', 'INTERNAL'}
+
+ data_path: rna_path
+ property_name: rna_custom_property_name
+
+ # Store the value converted to a string as a fallback for otherwise unsupported types.
+ eval_string: StringProperty(
+ name="Value",
+ description="Value for custom property types that can only be edited as a Python expression"
+ )
+
+ def execute(self, context):
+ if self.eval_string:
+ rna_item = eval("context.%s" % self.data_path)
+ try:
+ new_value = eval(self.eval_string)
+ except Exception as ex:
+ self.report({'WARNING'}, "Python evaluation failed: " + str(ex))
+ return {'CANCELLED'}
+ rna_item[self.property_name] = new_value
+ return {'FINISHED'}
+
+ def invoke(self, context, _event):
+ rna_item = eval("context.%s" % self.data_path)
+
+ if WM_OT_properties_edit.get_property_type(rna_item, self.property_name) == 'PYTHON':
+ self.eval_string = WM_OT_properties_edit.convert_custom_property_to_string(rna_item,
+ self.property_name)
+ else:
+ self.eval_string = ""
+
+ wm = context.window_manager
+ return wm.invoke_props_dialog(self)
+
+ def draw(self, context):
+ from bpy.utils import escape_identifier
+
+ rna_item = eval("context.%s" % self.data_path)
+
+ layout = self.layout
+ if WM_OT_properties_edit.get_property_type(rna_item, self.property_name) == 'PYTHON':
+ layout.prop(self, "eval_string")
+ else:
+ col = layout.column(align=True)
+ col.prop(rna_item, '["%s"]' % escape_identifier(self.property_name), text="")
+
+
class WM_OT_properties_add(Operator):
"""Add your own property to the data-block"""
bl_idname = "wm.properties_add"
@@ -3056,6 +3120,7 @@ classes = (
WM_OT_properties_add,
WM_OT_properties_context_change,
WM_OT_properties_edit,
+ WM_OT_properties_edit_value,
WM_OT_properties_remove,
WM_OT_sysinfo,
WM_OT_owner_disable,
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index c31881fa194..6ca13674234 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -591,7 +591,7 @@ class GreasePencilMaterialsPanel:
if len(ob.material_slots) > 0 and ob.active_material_index >= 0:
ma = ob.material_slots[ob.active_material_index].material
- if ma is not None and ma.grease_pencil is not None:
+ if is_view3d and ma is not None and ma.grease_pencil is not None:
gpcolor = ma.grease_pencil
if gpcolor.stroke_style == 'SOLID':
row = layout.row()
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index 927a30f0ae0..05f505c518d 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -52,7 +52,9 @@ class FILEBROWSER_HT_header(Header):
icon_only=True,
)
- layout.prop(params, "filter_search", text="", icon='VIEWZOOM')
+ sub = layout.row()
+ sub.ui_units_x = 8
+ sub.prop(params, "filter_search", text="", icon='VIEWZOOM')
layout.popover(
panel="ASSETBROWSER_PT_filter",
@@ -734,6 +736,7 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
row.operator("asset.open_containing_blend_file", text="", icon='TOOL_SETTINGS')
layout.prop(asset_file_handle.asset_data, "description")
+ layout.prop(asset_file_handle.asset_data, "author")
class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel):
@@ -789,7 +792,7 @@ class ASSETBROWSER_MT_context_menu(AssetBrowserMenu, Menu):
st = context.space_data
params = st.params
- layout.operator("file.refresh", text="Refresh")
+ layout.operator("file.asset_library_refresh")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 9b96cef9de4..120b2d7c13a 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -37,6 +37,14 @@ from bl_ui.space_toolsystem_common import (
from rna_prop_ui import PropertyPanel
+def _space_view_types(st):
+ view_type = st.view_type
+ return (
+ view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'},
+ view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'},
+ )
+
+
def selected_sequences_len(context):
selected_sequences = getattr(context, "selected_sequences", None)
if selected_sequences is None:
@@ -228,15 +236,19 @@ class SEQUENCER_MT_editor_menus(Menu):
def draw(self, context):
layout = self.layout
st = context.space_data
+ has_sequencer, _has_preview = _space_view_types(st)
layout.menu("SEQUENCER_MT_view")
+ layout.menu("SEQUENCER_MT_select")
- if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
- layout.menu("SEQUENCER_MT_select")
+ if has_sequencer:
if st.show_markers:
layout.menu("SEQUENCER_MT_marker")
layout.menu("SEQUENCER_MT_add")
- layout.menu("SEQUENCER_MT_strip")
+
+ layout.menu("SEQUENCER_MT_strip")
+
+ layout.menu("SEQUENCER_MT_image")
class SEQUENCER_PT_gizmo_display(Panel):
@@ -559,8 +571,14 @@ class SEQUENCER_MT_select_linked(Menu):
class SEQUENCER_MT_select(Menu):
bl_label = "Select"
- def draw(self, _context):
+ def draw(self, context):
layout = self.layout
+ st = context.space_data
+ has_sequencer, has_preview = _space_view_types(st)
+
+ # FIXME: this doesn't work for both preview + window region.
+ if has_preview:
+ layout.operator_context = 'INVOKE_REGION_PREVIEW'
layout.operator("sequencer.select_all", text="All").action = 'SELECT'
layout.operator("sequencer.select_all", text="None").action = 'DESELECT'
@@ -569,17 +587,20 @@ class SEQUENCER_MT_select(Menu):
layout.separator()
layout.operator("sequencer.select_box", text="Box Select")
- props = layout.operator("sequencer.select_box", text="Box Select (Include Handles)")
- props.include_handles = True
+ if has_sequencer:
+ props = layout.operator("sequencer.select_box", text="Box Select (Include Handles)")
+ props.include_handles = True
layout.separator()
- layout.operator_menu_enum("sequencer.select_side_of_frame", "side", text="Side of Frame...")
- layout.menu("SEQUENCER_MT_select_handle", text="Handle")
- layout.menu("SEQUENCER_MT_select_channel", text="Channel")
- layout.menu("SEQUENCER_MT_select_linked", text="Linked")
+ if has_sequencer:
+ layout.operator_menu_enum("sequencer.select_side_of_frame", "side", text="Side of Frame...")
+ layout.menu("SEQUENCER_MT_select_handle", text="Handle")
+ layout.menu("SEQUENCER_MT_select_channel", text="Channel")
+ layout.menu("SEQUENCER_MT_select_linked", text="Linked")
+
+ layout.separator()
- layout.separator()
layout.operator_menu_enum("sequencer.select_grouped", "type", text="Grouped")
@@ -787,43 +808,43 @@ class SEQUENCER_MT_add_effect(Menu):
col.enabled = selected_sequences_len(context) != 0
-class SEQUENCER_MT_strip_image_transform(Menu):
- bl_label = "Image Transform"
-
- def draw(self, _context):
- layout = self.layout
-
- layout.operator("sequencer.strip_transform_fit", text="Scale To Fit").fit_method = 'FIT'
- layout.operator("sequencer.strip_transform_fit", text="Scale to Fill").fit_method = 'FILL'
- layout.operator("sequencer.strip_transform_fit", text="Stretch To Fill").fit_method = 'STRETCH'
- layout.separator()
-
- layout.operator("sequencer.strip_transform_clear", text="Clear Position").property = 'POSITION'
- layout.operator("sequencer.strip_transform_clear", text="Clear Scale").property = 'SCALE'
- layout.operator("sequencer.strip_transform_clear", text="Clear Rotation").property = 'ROTATION'
- layout.operator("sequencer.strip_transform_clear", text="Clear All").property = 'ALL'
-
-
class SEQUENCER_MT_strip_transform(Menu):
bl_label = "Transform"
- def draw(self, _context):
+ def draw(self, context):
layout = self.layout
+ st = context.space_data
+ has_sequencer, has_preview = _space_view_types(st)
- layout.operator("transform.seq_slide", text="Move")
- layout.operator("transform.transform", text="Move/Extend from Current Frame").mode = 'TIME_EXTEND'
- layout.operator("sequencer.slip", text="Slip Strip Contents")
+ if has_preview:
+ layout.operator_context = 'INVOKE_REGION_PREVIEW'
+ else:
+ layout.operator_context = 'INVOKE_REGION_WIN'
- layout.separator()
- layout.operator("sequencer.snap")
- layout.operator("sequencer.offset_clear")
+ # FIXME: mixed preview/sequencer views.
+ if has_preview:
+ layout.operator("transform.translate", text="Move")
+ layout.operator("transform.rotate", text="Rotate")
+ layout.operator("transform.resize", text="Scale")
+ else:
+ layout.operator("transform.seq_slide", text="Move")
+ layout.operator("transform.transform", text="Move/Extend from Current Frame").mode = 'TIME_EXTEND'
+ layout.operator("sequencer.slip", text="Slip Strip Contents")
- layout.separator()
- layout.operator_menu_enum("sequencer.swap", "side")
+ # TODO (for preview)
+ if has_sequencer:
+ layout.separator()
+ layout.operator("sequencer.snap")
+ layout.operator("sequencer.offset_clear")
- layout.separator()
- layout.operator("sequencer.gap_remove").all = False
- layout.operator("sequencer.gap_insert")
+ layout.separator()
+
+ if has_sequencer:
+ layout.operator_menu_enum("sequencer.swap", "side")
+
+ layout.separator()
+ layout.operator("sequencer.gap_remove").all = False
+ layout.operator("sequencer.gap_insert")
class SEQUENCER_MT_strip_input(Menu):
@@ -893,69 +914,129 @@ class SEQUENCER_MT_strip(Menu):
def draw(self, context):
layout = self.layout
+ st = context.space_data
+ has_sequencer, has_preview = _space_view_types(st)
- layout.operator_context = 'INVOKE_REGION_WIN'
+ # FIXME: this doesn't work for both preview + window region.
+ if has_preview:
+ layout.operator_context = 'INVOKE_REGION_PREVIEW'
+ else:
+ layout.operator_context = 'INVOKE_REGION_WIN'
- layout.separator()
layout.menu("SEQUENCER_MT_strip_transform")
- layout.menu("SEQUENCER_MT_strip_image_transform")
-
layout.separator()
- layout.operator("sequencer.split", text="Split").type = 'SOFT'
- layout.operator("sequencer.split", text="Hold Split").type = 'HARD'
- layout.separator()
- layout.operator("sequencer.copy", text="Copy")
- layout.operator("sequencer.paste", text="Paste")
- layout.operator("sequencer.duplicate_move")
+ if has_sequencer:
+
+ layout.operator("sequencer.split", text="Split").type = 'SOFT'
+ layout.operator("sequencer.split", text="Hold Split").type = 'HARD'
+ layout.separator()
+
+ if has_sequencer:
+ layout.operator("sequencer.copy", text="Copy")
+ layout.operator("sequencer.paste", text="Paste")
+ layout.operator("sequencer.duplicate_move")
+
layout.operator("sequencer.delete", text="Delete")
strip = context.active_sequence_strip
- if strip:
- strip_type = strip.type
+ if has_sequencer:
+ if strip:
+ strip_type = strip.type
- if strip_type != 'SOUND':
- layout.separator()
- layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
- layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
+ if strip_type != 'SOUND':
+ layout.separator()
+ layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
+ layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
+
+ if strip_type in {
+ 'CROSS', 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
+ 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'WIPE', 'GLOW',
+ 'TRANSFORM', 'COLOR', 'SPEED', 'MULTICAM', 'ADJUSTMENT',
+ 'GAUSSIAN_BLUR',
+ }:
+ layout.separator()
+ layout.menu("SEQUENCER_MT_strip_effect")
+ elif strip_type == 'MOVIE':
+ layout.separator()
+ layout.menu("SEQUENCER_MT_strip_movie")
+ elif strip_type == 'IMAGE':
+ layout.separator()
+ layout.operator("sequencer.rendersize")
+ layout.operator("sequencer.images_separate")
+ elif strip_type == 'TEXT':
+ layout.separator()
+ layout.menu("SEQUENCER_MT_strip_effect")
+ elif strip_type == 'META':
+ layout.separator()
+ layout.operator("sequencer.meta_make")
+ layout.operator("sequencer.meta_separate")
+ layout.operator("sequencer.meta_toggle", text="Toggle Meta")
+ if strip_type != 'META':
+ layout.separator()
+ layout.operator("sequencer.meta_make")
+ layout.operator("sequencer.meta_toggle", text="Toggle Meta")
- if strip_type in {
- 'CROSS', 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
- 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'WIPE', 'GLOW',
- 'TRANSFORM', 'COLOR', 'SPEED', 'MULTICAM', 'ADJUSTMENT',
- 'GAUSSIAN_BLUR',
- }:
- layout.separator()
- layout.menu("SEQUENCER_MT_strip_effect")
- elif strip_type == 'MOVIE':
- layout.separator()
- layout.menu("SEQUENCER_MT_strip_movie")
- elif strip_type == 'IMAGE':
- layout.separator()
- layout.operator("sequencer.rendersize")
- layout.operator("sequencer.images_separate")
- elif strip_type == 'TEXT':
- layout.separator()
- layout.menu("SEQUENCER_MT_strip_effect")
- elif strip_type == 'META':
- layout.separator()
- layout.operator("sequencer.meta_make")
- layout.operator("sequencer.meta_separate")
- layout.operator("sequencer.meta_toggle", text="Toggle Meta")
- if strip_type != 'META':
- layout.separator()
- layout.operator("sequencer.meta_make")
- layout.operator("sequencer.meta_toggle", text="Toggle Meta")
+ if has_sequencer:
+ layout.separator()
+ layout.menu("SEQUENCER_MT_color_tag_picker")
- layout.separator()
- layout.menu("SEQUENCER_MT_color_tag_picker")
+ layout.separator()
+ layout.menu("SEQUENCER_MT_strip_lock_mute")
- layout.separator()
- layout.menu("SEQUENCER_MT_strip_lock_mute")
+ layout.separator()
+ layout.menu("SEQUENCER_MT_strip_input")
- layout.separator()
- layout.menu("SEQUENCER_MT_strip_input")
+
+class SEQUENCER_MT_image(Menu):
+ bl_label = "Image"
+
+ def draw(self, context):
+ layout = self.layout
+ st = context.space_data
+
+ if st.view_type == {'PREVIEW', 'SEQUENCER_PREVIEW'}:
+ layout.menu("SEQUENCER_MT_image_transform")
+
+ layout.menu("SEQUENCER_MT_image_clear")
+ layout.menu("SEQUENCER_MT_image_apply")
+
+
+class SEQUENCER_MT_image_transform(Menu):
+ bl_label = "Transfrom"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_REGION_PREVIEW'
+
+ layout.operator("transform.translate")
+ layout.operator("transform.rotate")
+ layout.operator("transform.resize", text="Scale")
+
+
+class SEQUENCER_MT_image_clear(Menu):
+ bl_label = "Clear"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("sequencer.strip_transform_clear", text="Position").property = 'POSITION'
+ layout.operator("sequencer.strip_transform_clear", text="Scale").property = 'SCALE'
+ layout.operator("sequencer.strip_transform_clear", text="Rotation").property = 'ROTATION'
+ layout.operator("sequencer.strip_transform_clear", text="All Transforms").property = 'ALL'
+
+
+class SEQUENCER_MT_image_apply(Menu):
+ bl_label = "Apply"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("sequencer.strip_transform_fit", text="Scale To Fit").fit_method = 'FIT'
+ layout.operator("sequencer.strip_transform_fit", text="Scale to Fill").fit_method = 'FILL'
+ layout.operator("sequencer.strip_transform_fit", text="Stretch To Fill").fit_method = 'STRETCH'
class SEQUENCER_MT_context_menu(Menu):
@@ -2523,10 +2604,13 @@ classes = (
SEQUENCER_MT_strip_effect,
SEQUENCER_MT_strip_movie,
SEQUENCER_MT_strip,
- SEQUENCER_MT_strip_image_transform,
SEQUENCER_MT_strip_transform,
SEQUENCER_MT_strip_input,
SEQUENCER_MT_strip_lock_mute,
+ SEQUENCER_MT_image,
+ SEQUENCER_MT_image_transform,
+ SEQUENCER_MT_image_clear,
+ SEQUENCER_MT_image_apply,
SEQUENCER_MT_color_tag_picker,
SEQUENCER_MT_context_menu,
SEQUENCER_MT_preview_context_menu,
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 721c6bdb99c..1a448046f7a 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -2429,6 +2429,7 @@ class _defs_node_edit:
icon="ops.node.links_cut",
widget=None,
keymap="Node Tool: Links Cut",
+ options={'KEYMAP_FALLBACK'},
)
@@ -2462,6 +2463,7 @@ class _defs_sequencer_generic:
widget=None,
keymap="Sequencer Tool: Blade",
draw_settings=draw_settings,
+ options={'KEYMAP_FALLBACK'},
)
@ToolDef.from_fn
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 1c2190bb7a0..0172fa0655f 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2265,6 +2265,7 @@ class VIEW3D_MT_object(Menu):
layout.separator()
+ layout.menu("VIEW3D_MT_object_asset")
layout.menu("VIEW3D_MT_object_parent")
layout.menu("VIEW3D_MT_object_collection")
layout.menu("VIEW3D_MT_object_relations")
@@ -2758,6 +2759,16 @@ class VIEW3D_MT_object_cleanup(Menu):
layout.operator("object.material_slot_remove_unused", text="Remove Unused Material Slots")
+class VIEW3D_MT_object_asset(Menu):
+ bl_label = "Asset"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("asset.mark")
+ layout.operator("asset.clear", text="Clear Asset").set_fake_user = False
+ layout.operator("asset.clear", text="Clear Asset (Set Fake User)").set_fake_user = True
+
class VIEW3D_MT_make_single_user(Menu):
bl_label = "Make Single User"
@@ -7541,6 +7552,7 @@ classes = (
VIEW3D_MT_image_add,
VIEW3D_MT_object,
VIEW3D_MT_object_animation,
+ VIEW3D_MT_object_asset,
VIEW3D_MT_object_rigid_body,
VIEW3D_MT_object_clear,
VIEW3D_MT_object_context_menu,
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 0a34f541e5c..34f447a7108 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -87,8 +87,6 @@ def curve_node_items(context):
space = context.space_data
if not space:
return
- if not space.edit_tree:
- return
if geometry_nodes_legacy_poll(context):
yield NodeItem("GeometryNodeLegacyCurveEndpoints")
@@ -137,8 +135,6 @@ def mesh_node_items(context):
space = context.space_data
if not space:
return
- if not space.edit_tree:
- return
if geometry_nodes_legacy_poll(context):
yield NodeItem("GeometryNodeLegacyEdgeSplit", poll=geometry_nodes_legacy_poll)
@@ -157,6 +153,32 @@ def mesh_node_items(context):
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
yield NodeItem("GeometryNodeSetShadeSmooth")
+# Custom Menu for Geometry Nodes "Geometry" category
+def geometry_node_items(context):
+ if context is None:
+ return
+ space = context.space_data
+ if not space:
+ return
+
+ if geometry_nodes_legacy_poll(context):
+ yield NodeItem("GeometryNodeLegacyDeleteGeometry", poll=geometry_nodes_legacy_poll)
+ yield NodeItem("GeometryNodeLegacyRaycast", poll=geometry_nodes_legacy_poll)
+ yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+
+ yield NodeItem("GeometryNodeBoundBox")
+ yield NodeItem("GeometryNodeConvexHull")
+ yield NodeItem("GeometryNodeDeleteGeometry")
+ yield NodeItem("GeometryNodeProximity")
+ yield NodeItem("GeometryNodeJoinGeometry")
+ yield NodeItem("GeometryNodeRaycast")
+ yield NodeItem("GeometryNodeSeparateComponents")
+ yield NodeItem("GeometryNodeSeparateGeometry")
+ yield NodeItem("GeometryNodeTransform")
+ yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+ yield NodeItem("GeometryNodeSetID")
+ yield NodeItem("GeometryNodeSetPosition")
+
# Custom Menu for Geometry Node Input Nodes
def geometry_input_node_items(context):
if context is None:
@@ -164,15 +186,13 @@ def geometry_input_node_items(context):
space = context.space_data
if not space:
return
- if not space.edit_tree:
- return
if geometry_nodes_legacy_poll(context):
yield NodeItem("FunctionNodeLegacyRandomFloat")
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeCollectionInfo")
yield NodeItem("FunctionNodeInputBool")
+ yield NodeItem("GeometryNodeCollectionInfo")
yield NodeItem("FunctionNodeInputColor")
yield NodeItem("FunctionNodeInputInt")
yield NodeItem("GeometryNodeIsViewport")
@@ -182,6 +202,7 @@ def geometry_input_node_items(context):
yield NodeItem("ShaderNodeValue")
yield NodeItem("FunctionNodeInputVector")
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+ yield NodeItem("GeometryNodeInputID")
yield NodeItem("GeometryNodeInputIndex")
yield NodeItem("GeometryNodeInputNormal")
yield NodeItem("GeometryNodeInputPosition")
@@ -194,8 +215,6 @@ def geometry_material_node_items(context):
space = context.space_data
if not space:
return
- if not space.edit_tree:
- return
if geometry_nodes_legacy_poll(context):
yield NodeItem("GeometryNodeLegacyMaterialAssign")
@@ -217,8 +236,6 @@ def point_node_items(context):
space = context.space_data
if not space:
return
- if not space.edit_tree:
- return
if geometry_nodes_legacy_poll(context):
yield NodeItem("GeometryNodeLegacyAlignRotationToVector", poll=geometry_nodes_legacy_poll)
@@ -244,15 +261,16 @@ def node_group_items(context):
space = context.space_data
if not space:
return
- ntree = space.edit_tree
- if not ntree:
- return
yield NodeItemCustom(draw=group_tools_draw)
yield NodeItem("NodeGroupInput", poll=group_input_output_item_poll)
yield NodeItem("NodeGroupOutput", poll=group_input_output_item_poll)
+ ntree = space.edit_tree
+ if not ntree:
+ return
+
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
def contains_group(nodetree, group):
@@ -677,21 +695,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeCurvePrimitiveQuadrilateral"),
NodeItem("GeometryNodeCurvePrimitiveBezierSegment"),
]),
- GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=[
- NodeItem("GeometryNodeLegacyDeleteGeometry", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyRaycast", poll=geometry_nodes_legacy_poll),
-
- NodeItem("GeometryNodeRaycast"),
- NodeItem("GeometryNodeProximity"),
- NodeItem("GeometryNodeBoundBox"),
- NodeItem("GeometryNodeConvexHull"),
- NodeItem("GeometryNodeDeleteGeometry"),
- NodeItem("GeometryNodeTransform"),
- NodeItem("GeometryNodeJoinGeometry"),
- NodeItem("GeometryNodeSeparateComponents"),
- NodeItem("GeometryNodeSeparateGeometry"),
- NodeItem("GeometryNodeSetPosition"),
- ]),
+ GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=geometry_node_items),
GeometryNodeCategory("GEO_INPUT", "Input", items=geometry_input_node_items),
GeometryNodeCategory("GEO_INSTANCE", "Instances", items=[
NodeItem("GeometryNodeInstanceOnPoints"),
@@ -727,6 +731,7 @@ geometry_node_categories = [
NodeItem("FunctionNodeReplaceString"),
]),
GeometryNodeCategory("GEO_TEXTURE", "Texture", items=[
+ NodeItem("ShaderNodeTexBrick"),
NodeItem("ShaderNodeTexChecker"),
NodeItem("ShaderNodeTexGradient"),
NodeItem("ShaderNodeTexMagic"),
@@ -735,6 +740,7 @@ geometry_node_categories = [
NodeItem("ShaderNodeTexVoronoi"),
NodeItem("ShaderNodeTexWave"),
NodeItem("ShaderNodeTexWhiteNoise"),
+ NodeItem("GeometryNodeImageTexture"),
]),
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
NodeItem("ShaderNodeMapRange"),
@@ -758,6 +764,7 @@ geometry_node_categories = [
]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
NodeItem("GeometryNodeLegacyPointsToVolume", poll=geometry_nodes_legacy_poll),
+ NodeItem("GeometryNodeLegacyVolumeToMesh", poll=geometry_nodes_legacy_poll),
NodeItem("GeometryNodeVolumeToMesh"),
]),
diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt
index 4bcd27082c0..4c2e72418a0 100644
--- a/source/blender/blendthumb/CMakeLists.txt
+++ b/source/blender/blendthumb/CMakeLists.txt
@@ -56,11 +56,6 @@ if(WIN32)
target_link_libraries(BlendThumb bf_blenlib dbghelp.lib Version.lib)
set_target_properties(BlendThumb PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB:msvcrt")
- install(
- FILES $<TARGET_FILE:BlendThumb>
- COMPONENT Blender
- DESTINATION "."
- )
else()
# -----------------------------------------------------------------------------
# Build `blender-thumbnailer` executable
@@ -68,10 +63,4 @@ else()
add_executable(blender-thumbnailer ${SRC} src/blender_thumbnailer.cc)
target_link_libraries(blender-thumbnailer bf_blenlib)
target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES})
-
- install(
- FILES $<TARGET_FILE:blender-thumbnailer>
- COMPONENT Blender
- DESTINATION "."
- )
endif()
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 27478bd7f8e..90c8d6357de 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -297,44 +297,27 @@ static void blf_batch_draw_end(void)
* characters.
*/
-BLI_INLINE GlyphBLF *blf_utf8_next_fast(
- FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t str_len, size_t *i_p, uint *r_c)
+BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step(
+ FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t str_len, size_t *i_p)
{
- GlyphBLF *g;
- if ((*r_c = str[*i_p]) < GLYPH_ASCII_TABLE_SIZE) {
- g = (gc->glyph_ascii_table)[*r_c];
- if (UNLIKELY(g == NULL)) {
- g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c);
- gc->glyph_ascii_table[*r_c] = g;
- }
- (*i_p)++;
- }
- else {
- *r_c = BLI_str_utf8_as_unicode_step(str, str_len, i_p);
- g = blf_glyph_search(gc, *r_c);
- if (UNLIKELY(g == NULL)) {
- g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c);
- }
- }
- return g;
+ uint charcode = BLI_str_utf8_as_unicode_step(str, str_len, i_p);
+ /* Invalid unicode sequences return the byte value, stepping forward one.
+ * This allows `latin1` to display (which is sometimes used for file-paths). */
+ BLI_assert(charcode != BLI_UTF8_ERR);
+ return blf_glyph_ensure(font, gc, charcode);
}
-BLI_INLINE void blf_kerning_step_fast(FontBLF *font,
- const GlyphBLF *g_prev,
- const GlyphBLF *g,
- const uint c_prev,
- const uint c,
- int *pen_x_p)
+BLI_INLINE int blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
{
if (!FT_HAS_KERNING(font->face) || g_prev == NULL) {
- return;
+ return 0;
}
FT_Vector delta = {KERNING_ENTRY_UNSET};
/* Get unscaled kerning value from our cache if ASCII. */
- if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) {
- delta.x = font->kerning_cache->ascii_table[c][c_prev];
+ if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
+ delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c];
}
/* If not ASCII or not found in cache, ask FreeType for kerning. */
@@ -344,14 +327,16 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font,
}
/* If ASCII we save this value to our cache for quicker access next time. */
- if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) {
- font->kerning_cache->ascii_table[c][c_prev] = (int)delta.x;
+ if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
+ font->kerning_cache->ascii_table[g->c][g_prev->c] = (int)delta.x;
}
if (delta.x != 0) {
/* Convert unscaled design units to pixels and move pen. */
- *pen_x_p += blf_unscaled_F26Dot6_to_pixels(font, delta.x);
+ return blf_unscaled_F26Dot6_to_pixels(font, delta.x);
}
+
+ return 0;
}
/** \} */
@@ -367,7 +352,6 @@ static void blf_font_draw_ex(FontBLF *font,
struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0;
@@ -380,22 +364,18 @@ static void blf_font_draw_ex(FontBLF *font,
blf_batch_draw_begin(font);
while ((i < str_len) && str[i]) {
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x);
+ pen_x += blf_kerning(font, g_prev, g);
/* do not return this loop if clipped, we want every character tested */
- blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
+ blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y);
pen_x += g->advance_i;
g_prev = g;
- c_prev = c;
}
blf_batch_draw_end();
@@ -415,7 +395,6 @@ void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, struct
/* use fixed column width, but an utf8 character may occupy multiple columns */
int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int cwidth)
{
- unsigned int c;
GlyphBLF *g;
int col, columns = 0;
int pen_x = 0, pen_y = 0;
@@ -426,19 +405,15 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int
blf_batch_draw_begin(font);
while ((i < str_len) && str[i]) {
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
-
/* do not return this loop if clipped, we want every character tested */
- blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
+ blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y);
- col = BLI_wcwidth((char32_t)c);
+ col = BLI_wcwidth((char32_t)g->c);
if (col < 0) {
col = 1;
}
@@ -467,7 +442,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = (int)font->pos[0];
int pen_y_basis = (int)font->pos[1] + pen_y;
@@ -483,15 +457,12 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
/* another buffer specific call for color conversion */
while ((i < str_len) && str[i]) {
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x);
+ pen_x += blf_kerning(font, g_prev, g);
chx = pen_x + ((int)g->pos[0]);
chy = pen_y_basis + g->dims[1];
@@ -588,7 +559,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
pen_x += g->advance_i;
g_prev = g;
- c_prev = c;
}
if (r_info) {
@@ -617,31 +587,22 @@ void blf_font_draw_buffer(FontBLF *font,
* - #BLF_width_to_rstrlen
* \{ */
-static bool blf_font_width_to_strlen_glyph_process(FontBLF *font,
- const uint c_prev,
- const uint c,
- GlyphBLF *g_prev,
- GlyphBLF *g,
- int *pen_x,
- const int width_i)
+static bool blf_font_width_to_strlen_glyph_process(
+ FontBLF *font, GlyphBLF *g_prev, GlyphBLF *g, int *pen_x, const int width_i)
{
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- return true; /* break the calling loop. */
- }
if (UNLIKELY(g == NULL)) {
return false; /* continue the calling loop. */
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, pen_x);
-
+ *pen_x += blf_kerning(font, g_prev, g);
*pen_x += g->advance_i;
+ /* When true, break the calling loop. */
return (*pen_x >= width_i);
}
size_t blf_font_width_to_strlen(
FontBLF *font, const char *str, const size_t str_len, float width, float *r_width)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev;
int pen_x, width_new;
size_t i, i_prev;
@@ -649,11 +610,11 @@ size_t blf_font_width_to_strlen(
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
const int width_i = (int)width;
- for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < str_len) && str[i];
- i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) {
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL; (i < str_len) && str[i];
+ i_prev = i, width_new = pen_x, g_prev = g) {
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) {
+ if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width_i)) {
break;
}
}
@@ -669,7 +630,6 @@ size_t blf_font_width_to_strlen(
size_t blf_font_width_to_rstrlen(
FontBLF *font, const char *str, const size_t str_len, float width, float *r_width)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev;
int pen_x, width_new;
size_t i, i_prev, i_tmp;
@@ -685,19 +645,19 @@ size_t blf_font_width_to_rstrlen(
i_prev = (size_t)(s_prev - str);
i_tmp = i;
- g = blf_utf8_next_fast(font, gc, str, str_len, &i_tmp, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i_tmp);
for (width_new = pen_x = 0; (s != NULL);
- i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) {
+ i = i_prev, s = s_prev, g = g_prev, g_prev = NULL, width_new = pen_x) {
s_prev = BLI_str_find_prev_char_utf8(s, str);
i_prev = (size_t)(s_prev - str);
if (s_prev != NULL) {
i_tmp = i_prev;
- g_prev = blf_utf8_next_fast(font, gc, str, str_len, &i_tmp, &c_prev);
+ g_prev = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i_tmp);
BLI_assert(i_tmp == i);
}
- if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) {
+ if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width_i)) {
break;
}
}
@@ -724,7 +684,6 @@ static void blf_font_boundbox_ex(FontBLF *font,
struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0;
@@ -736,15 +695,12 @@ static void blf_font_boundbox_ex(FontBLF *font,
box->ymax = -32000.0f;
while ((i < str_len) && str[i]) {
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x);
+ pen_x += blf_kerning(font, g_prev, g);
gbox.xmin = (float)pen_x;
gbox.xmax = (float)pen_x + g->advance;
@@ -767,7 +723,6 @@ static void blf_font_boundbox_ex(FontBLF *font,
pen_x += g->advance_i;
g_prev = g;
- c_prev = c;
}
if (box->xmin > box->xmax) {
@@ -874,7 +829,7 @@ float blf_font_fixed_width(FontBLF *font)
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphBLF *g = blf_glyph_search(gc, c);
if (!g) {
- g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c);
+ g = blf_glyph_ensure(font, gc, FT_Get_Char_Index(font->face, c));
/* if we don't find the glyph. */
if (!g) {
@@ -896,7 +851,6 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0, i_curr;
@@ -909,15 +863,12 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
while ((i < str_len) && str[i]) {
i_curr = i;
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x);
+ pen_x += blf_kerning(font, g_prev, g);
gbox.xmin = pen_x;
gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]);
@@ -931,7 +882,6 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
}
g_prev = g;
- c_prev = c;
}
if (r_info) {
@@ -978,7 +928,6 @@ static void blf_font_wrap_apply(FontBLF *font,
void *userdata),
void *userdata)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0, pen_y = 0;
size_t i = 0;
@@ -999,15 +948,12 @@ static void blf_font_wrap_apply(FontBLF *font,
size_t i_curr = i;
bool do_draw = false;
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x);
+ pen_x += blf_kerning(font, g_prev, g);
/**
* Implementation Detail (utf8).
@@ -1047,14 +993,12 @@ static void blf_font_wrap_apply(FontBLF *font,
pen_x = 0;
pen_y -= gc->glyph_height_max;
g_prev = NULL;
- c_prev = BLI_UTF8_ERR;
lines += 1;
continue;
}
pen_x = pen_x_next;
g_prev = g;
- c_prev = c;
}
// printf("done! lines: %d, width, %d\n", lines, pen_x_next);
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 6cdf5fc5996..9170a1c0ac4 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -175,33 +175,8 @@ GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c)
return NULL;
}
-GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, unsigned int c)
+static bool blf_glyph_render(FontBLF *font, FT_UInt glyph_index)
{
- FT_GlyphSlot slot;
- GlyphBLF *g;
- FT_Error err;
- FT_Bitmap bitmap, tempbitmap;
- FT_BBox bbox;
- unsigned int key;
-
- g = blf_glyph_search(gc, c);
- if (g) {
- return g;
- }
-
- /* glyphs are dynamically created as needed by font rendering. this means that
- * to make font rendering thread safe we have to do locking here. note that this
- * must be a lock for the whole library and not just per font, because the font
- * renderer uses a shared buffer internally */
- BLI_spin_lock(font->ft_lib_mutex);
-
- /* search again after locking */
- g = blf_glyph_search(gc, c);
- if (g) {
- BLI_spin_unlock(font->ft_lib_mutex);
- return g;
- }
-
int load_flags;
int render_mode;
@@ -228,7 +203,10 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un
}
}
- err = FT_Load_Glyph(font->face, (FT_UInt)index, load_flags);
+ FT_Error err = FT_Load_Glyph(font->face, glyph_index, load_flags);
+ if (err != 0) {
+ return false;
+ }
/* Do not oblique a font that is designed to be italic! */
if (((font->flags & BLF_ITALIC) != 0) && !(font->face->style_flags & FT_STYLE_FLAG_ITALIC) &&
@@ -243,9 +221,8 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un
}
/* Do not embolden an already bold font! */
- if (((font->flags & BLF_BOLD) != 0) &&
- !(font->face->style_flags & FT_STYLE_FLAG_BOLD) &
- (font->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) {
+ if (((font->flags & BLF_BOLD) != 0) && !(font->face->style_flags & FT_STYLE_FLAG_BOLD) &&
+ (font->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) {
/* Strengthen the width more than the height. */
const FT_Pos extra_x = FT_MulFix(font->face->units_per_EM, font->face->size->metrics.x_scale) /
14;
@@ -263,15 +240,12 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un
}
}
- if (err) {
- BLI_spin_unlock(font->ft_lib_mutex);
- return NULL;
- }
-
/* get the glyph. */
- slot = font->face->glyph;
+ FT_GlyphSlot slot = font->face->glyph;
err = FT_Render_Glyph(slot, render_mode);
+ FT_Bitmap tempbitmap;
+
if (font->flags & BLF_MONOCHROME) {
/* Convert result from 1 bit per pixel to 8 bit per pixel */
/* Accum errors for later, fine if not interested beyond "ok vs any error" */
@@ -284,45 +258,69 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un
}
if (err || slot->format != FT_GLYPH_FORMAT_BITMAP) {
- BLI_spin_unlock(font->ft_lib_mutex);
- return NULL;
+ return false;
}
- g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_add");
- g->c = c;
- g->idx = (FT_UInt)index;
- bitmap = slot->bitmap;
- g->dims[0] = (int)bitmap.width;
- g->dims[1] = (int)bitmap.rows;
+ return true;
+}
- const int buffer_size = g->dims[0] * g->dims[1];
+GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode)
+{
+ GlyphBLF *g = (charcode < GLYPH_ASCII_TABLE_SIZE) ? (gc->glyph_ascii_table)[charcode] :
+ blf_glyph_search(gc, charcode);
+ if (g) {
+ return g;
+ }
- if (buffer_size != 0) {
- if (font->flags & BLF_MONOCHROME) {
- /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */
- for (int i = 0; i < buffer_size; i++) {
- bitmap.buffer[i] = bitmap.buffer[i] ? 255 : 0;
- }
- }
+ FT_UInt glyph_index = FT_Get_Char_Index(font->face, charcode);
- g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap");
- memcpy(g->bitmap, bitmap.buffer, (size_t)buffer_size);
+ if (!blf_glyph_render(font, glyph_index)) {
+ return NULL;
}
+ FT_GlyphSlot slot = font->face->glyph;
+
+ /* glyphs are dynamically created as needed by font rendering. this means that
+ * to make font rendering thread safe we have to do locking here. note that this
+ * must be a lock for the whole library and not just per font, because the font
+ * renderer uses a shared buffer internally */
+ BLI_spin_lock(font->ft_lib_mutex);
+
+ g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_get");
+ g->c = charcode;
+ g->idx = glyph_index;
g->advance = ((float)slot->advance.x) / 64.0f;
g->advance_i = (int)g->advance;
g->pos[0] = slot->bitmap_left;
g->pos[1] = slot->bitmap_top;
+ g->dims[0] = (int)slot->bitmap.width;
+ g->dims[1] = (int)slot->bitmap.rows;
g->pitch = slot->bitmap.pitch;
+ FT_BBox bbox;
FT_Outline_Get_CBox(&(slot->outline), &bbox);
g->box.xmin = ((float)bbox.xMin) / 64.0f;
g->box.xmax = ((float)bbox.xMax) / 64.0f;
g->box.ymin = ((float)bbox.yMin) / 64.0f;
g->box.ymax = ((float)bbox.yMax) / 64.0f;
- key = blf_hash(g->c);
+ const int buffer_size = (int)(slot->bitmap.width * slot->bitmap.rows);
+ if (buffer_size != 0) {
+ if (font->flags & BLF_MONOCHROME) {
+ /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */
+ for (int i = 0; i < buffer_size; i++) {
+ slot->bitmap.buffer[i] = slot->bitmap.buffer[i] ? 255 : 0;
+ }
+ }
+ g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap");
+ memcpy(g->bitmap, slot->bitmap.buffer, (size_t)buffer_size);
+ }
+
+ unsigned int key = blf_hash(g->c);
BLI_addhead(&(gc->bucket[key]), g);
+ if (charcode < GLYPH_ASCII_TABLE_SIZE) {
+ gc->glyph_ascii_table[charcode] = g;
+ }
BLI_spin_unlock(font->ft_lib_mutex);
@@ -419,7 +417,7 @@ static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y
blf_glyph_calc_rect(rect, g, x + (float)font->shadow_x, y + (float)font->shadow_y);
}
-void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y)
+void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y)
{
if ((!g->dims[0]) || (!g->dims[1])) {
return;
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 6fd5e8b7503..ba871ea2496 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -140,13 +140,10 @@ void blf_glyph_cache_clear(struct FontBLF *font);
void blf_glyph_cache_free(struct GlyphCacheBLF *gc);
struct GlyphBLF *blf_glyph_search(struct GlyphCacheBLF *gc, unsigned int c);
-struct GlyphBLF *blf_glyph_add(struct FontBLF *font,
- struct GlyphCacheBLF *gc,
- unsigned int index,
- unsigned int c);
+struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc, uint charcode);
void blf_glyph_free(struct GlyphBLF *g);
-void blf_glyph_render(
+void blf_glyph_draw(
struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, float x, float y);
#ifdef WIN32
diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h
index 42eea41b7a7..722d142b56c 100644
--- a/source/blender/blenkernel/BKE_asset.h
+++ b/source/blender/blenkernel/BKE_asset.h
@@ -20,6 +20,7 @@
#pragma once
+#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#include "DNA_asset_types.h"
@@ -29,11 +30,23 @@ extern "C" {
#endif
struct AssetLibraryReference;
+struct AssetMetaData;
struct BlendDataReader;
struct BlendWriter;
struct ID;
+struct IDProperty;
struct PreviewImage;
+typedef void (*PreSaveFn)(void *asset_ptr, struct AssetMetaData *asset_data);
+
+typedef struct AssetTypeInfo {
+ /**
+ * For local assets (assets in the current .blend file), a callback to execute before the file is
+ * saved.
+ */
+ PreSaveFn pre_save_fn;
+} AssetTypeInfo;
+
struct AssetMetaData *BKE_asset_metadata_create(void);
void BKE_asset_metadata_free(struct AssetMetaData **asset_data);
@@ -56,6 +69,10 @@ void BKE_asset_metadata_catalog_id_set(struct AssetMetaData *asset_data,
void BKE_asset_library_reference_init_default(struct AssetLibraryReference *library_ref);
+void BKE_asset_metadata_idprop_ensure(struct AssetMetaData *asset_data, struct IDProperty *prop);
+struct IDProperty *BKE_asset_metadata_idprop_find(const struct AssetMetaData *asset_data,
+ const char *name) ATTR_WARN_UNUSED_RESULT;
+
struct PreviewImage *BKE_asset_metadata_preview_get_from_id(const struct AssetMetaData *asset_data,
const struct ID *owner_id);
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index 4a1c29badb4..cf19eb29a0e 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -183,6 +183,8 @@ struct WriteAttributeLookup {
GVMutableArrayPtr varray;
/* Domain the attributes lives on in the geometry. */
AttributeDomain domain;
+ /* Call this after changing the attribute to invalidate caches that depend on this attribute. */
+ std::function<void()> tag_modified_fn;
/* Convenience function to check if the attribute has been found. */
operator bool() const
@@ -208,7 +210,7 @@ class OutputAttribute {
private:
GVMutableArrayPtr varray_;
- AttributeDomain domain_;
+ AttributeDomain domain_ = ATTR_DOMAIN_AUTO;
SaveFn save_;
std::unique_ptr<fn::GVMutableArray_GSpan> optional_span_varray_;
bool ignore_old_values_ = false;
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 3f8b56b2736..6fc2fa37d9f 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -31,7 +31,7 @@ extern "C" {
*/
/* Blender major and minor version. */
-#define BLENDER_VERSION 300
+#define BLENDER_VERSION 301
/* Blender patch version for bugfix releases. */
#define BLENDER_VERSION_PATCH 0
/** Blender release cycle stage: alpha/beta/rc/release. */
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 38
+#define BLENDER_FILE_SUBVERSION 0
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_curve_to_mesh.hh b/source/blender/blenkernel/BKE_curve_to_mesh.hh
index 87bec6203a9..fb077425336 100644
--- a/source/blender/blenkernel/BKE_curve_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_curve_to_mesh.hh
@@ -25,7 +25,7 @@ struct CurveEval;
namespace blender::bke {
-Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile);
+Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, bool fill_caps);
Mesh *curve_to_wire_mesh(const CurveEval &curve);
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index f57765e373b..58a89d0207a 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -318,6 +318,9 @@ struct GeometrySet {
bool include_instances,
blender::Map<blender::bke::AttributeIDRef, AttributeKind> &r_attributes) const;
+ blender::Vector<GeometryComponentType> gather_component_types(bool include_instances,
+ bool ignore_empty) const;
+
using ForeachSubGeometryCallback = blender::FunctionRef<void(GeometrySet &geometry_set)>;
void modify_geometry_sets(ForeachSubGeometryCallback callback);
@@ -621,7 +624,9 @@ class InstancesComponent : public GeometryComponent {
blender::Vector<blender::float4x4> instance_transforms_;
/**
* IDs of the instances. They are used for consistency over multiple frames for things like
- * motion blur.
+ * motion blur. Proper stable ID data that actually helps when rendering can only be generated
+ * in some situations, so this vector is allowed to be empty, in which case the index of each
+ * instance will be used for the final ID.
*/
blender::Vector<int> instance_ids_;
@@ -643,7 +648,7 @@ class InstancesComponent : public GeometryComponent {
void resize(int capacity);
int add_reference(const InstanceReference &reference);
- void add_instance(int instance_handle, const blender::float4x4 &transform, const int id = -1);
+ void add_instance(int instance_handle, const blender::float4x4 &transform);
blender::Span<InstanceReference> references() const;
void remove_unused_references();
@@ -658,6 +663,9 @@ class InstancesComponent : public GeometryComponent {
blender::MutableSpan<int> instance_ids();
blender::Span<int> instance_ids() const;
+ blender::MutableSpan<int> instance_ids_ensure();
+ void instance_ids_clear();
+
int instances_amount() const;
int references_amount() const;
@@ -736,6 +744,7 @@ class AttributeFieldInput : public fn::FieldInput {
AttributeFieldInput(std::string name, const CPPType &type)
: fn::FieldInput(type, name), name_(std::move(name))
{
+ category_ = Category::NamedAttribute;
}
template<typename T> static fn::Field<T> Create(std::string name)
@@ -764,10 +773,9 @@ class IDAttributeFieldInput : public fn::FieldInput {
public:
IDAttributeFieldInput() : fn::FieldInput(CPPType::get<int>())
{
+ category_ = Category::Generated;
}
- static fn::Field<int> Create();
-
const GVArray *get_varray_for_context(const fn::FieldContext &context,
IndexMask mask,
ResourceScope &scope) const override;
@@ -785,18 +793,25 @@ class AnonymousAttributeFieldInput : public fn::FieldInput {
* automatically.
*/
StrongAnonymousAttributeID anonymous_id_;
+ std::string producer_name_;
public:
- AnonymousAttributeFieldInput(StrongAnonymousAttributeID anonymous_id, const CPPType &type)
- : fn::FieldInput(type, anonymous_id.debug_name()), anonymous_id_(std::move(anonymous_id))
+ AnonymousAttributeFieldInput(StrongAnonymousAttributeID anonymous_id,
+ const CPPType &type,
+ std::string producer_name)
+ : fn::FieldInput(type, anonymous_id.debug_name()),
+ anonymous_id_(std::move(anonymous_id)),
+ producer_name_(producer_name)
{
+ category_ = Category::AnonymousAttribute;
}
- template<typename T> static fn::Field<T> Create(StrongAnonymousAttributeID anonymous_id)
+ template<typename T>
+ static fn::Field<T> Create(StrongAnonymousAttributeID anonymous_id, std::string producer_name)
{
const CPPType &type = CPPType::get<T>();
- auto field_input = std::make_shared<AnonymousAttributeFieldInput>(std::move(anonymous_id),
- type);
+ auto field_input = std::make_shared<AnonymousAttributeFieldInput>(
+ std::move(anonymous_id), type, std::move(producer_name));
return fn::Field<T>{field_input};
}
diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index cd656d94fce..d33c24f2c75 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -228,6 +228,11 @@ typedef struct IDTypeInfo {
* \note Currently needed for some update operation on point caches.
*/
IDTypeLibOverrideApplyPost lib_override_apply_post;
+
+ /**
+ * Callbacks for assets, based on the type of asset.
+ */
+ struct AssetTypeInfo *asset_type_info;
} IDTypeInfo;
/* ********** Declaration of each IDTypeInfo. ********** */
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index 9c49514e7b8..30c742e3af6 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -143,7 +143,8 @@ enum {
typedef struct LibraryForeachIDData LibraryForeachIDData;
-bool BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data,
+bool BKE_lib_query_foreachid_iter_stop(struct LibraryForeachIDData *data);
+void BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data,
struct ID **id_pp,
int cb_flag);
int BKE_lib_query_foreachid_process_flags_get(struct LibraryForeachIDData *data);
@@ -154,22 +155,33 @@ int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeach
#define BKE_LIB_FOREACHID_PROCESS_ID(_data, _id, _cb_flag) \
{ \
CHECK_TYPE_ANY((_id), ID *, void *); \
- if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id), (_cb_flag))) { \
+ BKE_lib_query_foreachid_process((_data), (ID **)&(_id), (_cb_flag)); \
+ if (BKE_lib_query_foreachid_iter_stop((_data))) { \
return; \
} \
} \
((void)0)
-#define BKE_LIB_FOREACHID_PROCESS(_data, _id_super, _cb_flag) \
+#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(_data, _id_super, _cb_flag) \
{ \
CHECK_TYPE(&((_id_super)->id), ID *); \
- if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \
+ BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag)); \
+ if (BKE_lib_query_foreachid_iter_stop((_data))) { \
return; \
} \
} \
((void)0)
-bool BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp);
+#define BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(_data, _func_call) \
+ { \
+ _func_call; \
+ if (BKE_lib_query_foreachid_iter_stop((_data))) { \
+ return; \
+ } \
+ } \
+ ((void)0)
+
+void BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp);
void BKE_lib_query_idpropertiesForeachIDLink_callback(struct IDProperty *id_prop, void *user_data);
/* Loop over all of the ID's this datablock links to. */
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index c70521f9593..8df6a803358 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -111,8 +111,7 @@ void BKE_libblock_relink_ex(struct Main *bmain,
void *new_idv,
const short remap_flags) ATTR_NONNULL(1, 2);
-void BKE_libblock_relink_to_newid(struct ID *id) ATTR_NONNULL();
-void BKE_libblock_relink_to_newid_new(struct Main *bmain, struct ID *id) ATTR_NONNULL();
+void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id) ATTR_NONNULL();
typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 68b1b55f47f..9ded97e0003 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -244,9 +244,9 @@ void BKE_main_library_weak_reference_remove_item(struct GHash *library_weak_refe
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id) \
{ \
- ID *_id_next = (_lb)->first; \
+ ID *_id_next = (ID *)(_lb)->first; \
for ((_id) = _id_next; (_id) != NULL; (_id) = _id_next) { \
- _id_next = (_id)->next;
+ _id_next = (ID *)(_id)->next;
#define FOREACH_MAIN_LISTBASE_ID_END \
} \
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index ef1e7249658..58fea6d462c 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1442,7 +1442,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_COLLECTION_INFO 1023
#define GEO_NODE_IS_VIEWPORT 1024
#define GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY 1025
-#define GEO_NODE_VOLUME_TO_MESH 1026
+#define GEO_NODE_LEGACY_VOLUME_TO_MESH 1026
#define GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ 1027
#define GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ 1028
#define GEO_NODE_SUBDIVIDE_MESH 1029
@@ -1547,6 +1547,10 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_RAYCAST 1128
#define GEO_NODE_CURVE_TO_POINTS 1130
#define GEO_NODE_INSTANCES_TO_POINTS 1131
+#define GEO_NODE_IMAGE_TEXTURE 1132
+#define GEO_NODE_VOLUME_TO_MESH 1133
+#define GEO_NODE_INPUT_ID 1134
+#define GEO_NODE_SET_ID 1135
/** \} */
diff --git a/source/blender/blenkernel/BKE_preferences.h b/source/blender/blenkernel/BKE_preferences.h
index bd887c1ea0d..fce2d3178aa 100644
--- a/source/blender/blenkernel/BKE_preferences.h
+++ b/source/blender/blenkernel/BKE_preferences.h
@@ -29,6 +29,9 @@ extern "C" {
struct UserDef;
struct bUserAssetLibrary;
+/** Name of the asset library added by default. */
+#define BKE_PREFS_ASSET_LIBRARY_DEFAULT_NAME DATA_("User Library")
+
struct bUserAssetLibrary *BKE_preferences_asset_library_add(struct UserDef *userdef,
const char *name,
const char *path) ATTR_NONNULL(1);
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index 97e0d8415a5..8509b730709 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -570,6 +570,8 @@ struct CurveEval {
blender::Array<int> evaluated_point_offsets() const;
blender::Array<float> accumulated_spline_lengths() const;
+ void mark_cache_invalid();
+
void assert_valid_point_attributes() const;
};
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index 5fe0d54c2cf..601e0cf26a9 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -160,6 +160,7 @@ bool BKE_volume_save(const struct Volume *volume,
#ifdef __cplusplus
# include "BLI_float3.hh"
# include "BLI_float4x4.hh"
+# include "BLI_string_ref.hh"
bool BKE_volume_min_max(const Volume *volume, blender::float3 &r_min, blender::float3 &r_max);
@@ -167,6 +168,10 @@ bool BKE_volume_min_max(const Volume *volume, blender::float3 &r_min, blender::f
# include <openvdb/openvdb.h>
# include <openvdb/points/PointDataGrid.h>
+VolumeGrid *BKE_volume_grid_add_vdb(Volume &volume,
+ blender::StringRef name,
+ openvdb::GridBase::Ptr vdb_grid);
+
bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid,
blender::float3 &r_min,
blender::float3 &r_max);
diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh
index 1f6e89636c4..9532da8c23c 100644
--- a/source/blender/blenkernel/BKE_volume_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_span.hh"
+
#include "DNA_modifier_types.h"
#ifdef WITH_OPENVDB
@@ -33,10 +35,40 @@ struct VolumeToMeshResolution {
};
#ifdef WITH_OPENVDB
+
+/**
+ * The result of converting a volume grid to mesh data, in the format used by the OpenVDB API.
+ */
+struct OpenVDBMeshData {
+ std::vector<openvdb::Vec3s> verts;
+ std::vector<openvdb::Vec3I> tris;
+ std::vector<openvdb::Vec4I> quads;
+ bool is_empty() const
+ {
+ return verts.empty();
+ }
+};
+
struct Mesh *volume_to_mesh(const openvdb::GridBase &grid,
const VolumeToMeshResolution &resolution,
const float threshold,
const float adaptivity);
+
+struct OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid,
+ const VolumeToMeshResolution &resolution,
+ const float threshold,
+ const float adaptivity);
+
+void fill_mesh_from_openvdb_data(const Span<openvdb::Vec3s> vdb_verts,
+ const Span<openvdb::Vec3I> vdb_tris,
+ const Span<openvdb::Vec4I> vdb_quads,
+ const int vert_offset,
+ const int poly_offset,
+ const int loop_offset,
+ MutableSpan<MVert> verts,
+ MutableSpan<MPoly> polys,
+ MutableSpan<MLoop> loops);
+
#endif
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 65900ec0f4b..cae72ddf68c 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -175,11 +175,11 @@ static void action_foreach_id(ID *id, LibraryForeachIDData *data)
bAction *act = (bAction *)id;
LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
- BKE_fcurve_foreach_id(fcu, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data));
}
LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) {
- BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, marker->camera, IDWALK_CB_NOP);
}
}
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 7e4ab754500..21887d514d9 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -294,11 +294,11 @@ bool BKE_animdata_id_is_animated(const struct ID *id)
void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
{
LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
- BKE_fcurve_foreach_id(fcu, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data));
}
- BKE_LIB_FOREACHID_PROCESS(data, adt->action, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, adt->tmpact, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, adt->action, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, adt->tmpact, IDWALK_CB_USER);
LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) {
LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) {
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index ce4ab8a4ba1..fb6656a4b1c 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -259,23 +259,24 @@ bool BKE_appdir_folder_caches(char *r_path, const size_t path_len)
/**
* Gets a good default directory for fonts.
*/
-bool BKE_appdir_font_folder_default(
- /* This parameter can only be `const` on non-windows platforms.
- * NOLINTNEXTLINE: readability-non-const-parameter. */
- char *dir)
+bool BKE_appdir_font_folder_default(char *dir)
{
- bool success = false;
#ifdef WIN32
wchar_t wpath[FILE_MAXDIR];
- success = SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0);
- if (success) {
+ if (SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0)) {
wcscat(wpath, L"\\");
BLI_strncpy_wchar_as_utf8(dir, wpath, FILE_MAXDIR);
+ return (BLI_exists(dir));
}
+ return false;
+#elif defined(__APPLE__)
+ const char *home = BLI_getenv("HOME");
+ BLI_snprintf(dir, FILE_MAXDIR, "%s/Library/Fonts/", home);
+ return (BLI_exists(dir));
+#else
+ BLI_strncpy(dir, "/usr/share/fonts/", FILE_MAXDIR);
+ return (BLI_exists(dir));
#endif
- /* TODO: Values for other platforms. */
- UNUSED_VARS(dir);
- return success;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index b64b050f4e7..b830c9de5f5 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -161,30 +161,36 @@ static void armature_free_data(struct ID *id)
static void armature_foreach_id_bone(Bone *bone, LibraryForeachIDData *data)
{
- IDP_foreach_property(
- bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(
+ bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data));
LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) {
- armature_foreach_id_bone(curbone, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(curbone, data));
}
}
static void armature_foreach_id_editbone(EditBone *edit_bone, LibraryForeachIDData *data)
{
- IDP_foreach_property(
- edit_bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(edit_bone->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data));
}
static void armature_foreach_id(ID *id, LibraryForeachIDData *data)
{
bArmature *arm = (bArmature *)id;
LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
- armature_foreach_id_bone(bone, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(bone, data));
}
if (arm->edbo != NULL) {
LISTBASE_FOREACH (EditBone *, edit_bone, arm->edbo) {
- armature_foreach_id_editbone(edit_bone, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_editbone(edit_bone, data));
}
}
}
diff --git a/source/blender/blenkernel/intern/armature_test.cc b/source/blender/blenkernel/intern/armature_test.cc
index 2375c606247..a6d9a1f41e9 100644
--- a/source/blender/blenkernel/intern/armature_test.cc
+++ b/source/blender/blenkernel/intern/armature_test.cc
@@ -133,7 +133,7 @@ static double test_vec_roll_to_mat3_normalized(const float input[3],
float roll_mat[3][3];
if (normalize) {
- /* The vector is renormalized to replicate the actual usage. */
+ /* The vector is re-normalized to replicate the actual usage. */
normalize_v3_v3(input_normalized, input);
}
else {
diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc
index ae9ded3c754..7bea089b9bf 100644
--- a/source/blender/blenkernel/intern/asset.cc
+++ b/source/blender/blenkernel/intern/asset.cc
@@ -53,6 +53,7 @@ void BKE_asset_metadata_free(AssetMetaData **asset_data)
if ((*asset_data)->properties) {
IDP_FreeProperty((*asset_data)->properties);
}
+ MEM_SAFE_FREE((*asset_data)->author);
MEM_SAFE_FREE((*asset_data)->description);
BLI_freelistN(&(*asset_data)->tags);
@@ -140,6 +141,25 @@ void BKE_asset_metadata_catalog_id_set(struct AssetMetaData *asset_data,
trimmed_id.copy(asset_data->catalog_simple_name, max_simple_name_length);
}
+void BKE_asset_metadata_idprop_ensure(AssetMetaData *asset_data, IDProperty *prop)
+{
+ if (!asset_data->properties) {
+ IDPropertyTemplate val = {0};
+ asset_data->properties = IDP_New(IDP_GROUP, &val, "AssetMetaData.properties");
+ }
+ /* Important: The property may already exist. For now just allow always allow a newly allocated
+ * property, and replace the existing one as a way of updating. */
+ IDP_ReplaceInGroup(asset_data->properties, prop);
+}
+
+IDProperty *BKE_asset_metadata_idprop_find(const AssetMetaData *asset_data, const char *name)
+{
+ if (!asset_data->properties) {
+ return nullptr;
+ }
+ return IDP_GetPropertyFromGroup(asset_data->properties, name);
+}
+
/* Queries -------------------------------------------- */
PreviewImage *BKE_asset_metadata_preview_get_from_id(const AssetMetaData *UNUSED(asset_data),
@@ -158,6 +178,9 @@ void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data)
IDP_BlendWrite(writer, asset_data->properties);
}
+ if (asset_data->author) {
+ BLO_write_string(writer, asset_data->author);
+ }
if (asset_data->description) {
BLO_write_string(writer, asset_data->description);
}
@@ -169,12 +192,14 @@ void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data)
void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data)
{
/* asset_data itself has been read already. */
+ asset_data->local_type_info = nullptr;
if (asset_data->properties) {
BLO_read_data_address(reader, &asset_data->properties);
IDP_BlendDataRead(reader, &asset_data->properties);
}
+ BLO_read_data_address(reader, &asset_data->author);
BLO_read_data_address(reader, &asset_data->description);
BLO_read_list(reader, &asset_data->tags);
BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags);
diff --git a/source/blender/blenkernel/intern/asset_catalog_path.cc b/source/blender/blenkernel/intern/asset_catalog_path.cc
index fec2b76e7a1..20cac76b40b 100644
--- a/source/blender/blenkernel/intern/asset_catalog_path.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_path.cc
@@ -197,6 +197,8 @@ void AssetCatalogPath::iterate_components(ComponentIteratorFn callback) const
for (const char *path_component = this->path_.data(); path_component && path_component[0];
/* Jump to one after the next slash if there is any. */
path_component = next_slash_ptr ? next_slash_ptr + 1 : nullptr) {
+ /* Note that this also treats backslashes as component separators, which
+ * helps in cleaning up backslash-separated paths. */
next_slash_ptr = BLI_path_slash_find(path_component);
const bool is_last_component = next_slash_ptr == nullptr;
diff --git a/source/blender/blenkernel/intern/asset_catalog_path_test.cc b/source/blender/blenkernel/intern/asset_catalog_path_test.cc
index be50f2fc001..f248863ce77 100644
--- a/source/blender/blenkernel/intern/asset_catalog_path_test.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_path_test.cc
@@ -193,19 +193,33 @@ TEST(AssetCatalogPathTest, is_contained_in)
TEST(AssetCatalogPathTest, cleanup)
{
- AssetCatalogPath ugly_path("/ some / родитель / ");
- AssetCatalogPath clean_path = ugly_path.cleanup();
-
- EXPECT_EQ(AssetCatalogPath("/ some / родитель / "), ugly_path)
- << "cleanup should not modify the path instance itself";
-
- EXPECT_EQ(AssetCatalogPath("some/родитель"), clean_path);
-
- AssetCatalogPath double_slashed("some//родитель");
- EXPECT_EQ(AssetCatalogPath("some/родитель"), double_slashed.cleanup());
-
- AssetCatalogPath with_colons("some/key:subkey=value/path");
- EXPECT_EQ(AssetCatalogPath("some/key-subkey=value/path"), with_colons.cleanup());
+ {
+ AssetCatalogPath ugly_path("/ some / родитель / ");
+ AssetCatalogPath clean_path = ugly_path.cleanup();
+ EXPECT_EQ(AssetCatalogPath("/ some / родитель / "), ugly_path)
+ << "cleanup should not modify the path instance itself";
+ EXPECT_EQ(AssetCatalogPath("some/родитель"), clean_path);
+ }
+ {
+ AssetCatalogPath double_slashed("some//родитель");
+ EXPECT_EQ(AssetCatalogPath("some/родитель"), double_slashed.cleanup());
+ }
+ {
+ AssetCatalogPath with_colons("some/key:subkey=value/path");
+ EXPECT_EQ(AssetCatalogPath("some/key-subkey=value/path"), with_colons.cleanup());
+ }
+ {
+ const AssetCatalogPath with_backslashes("windows\\for\\life");
+ EXPECT_EQ(AssetCatalogPath("windows/for/life"), with_backslashes.cleanup());
+ }
+ {
+ const AssetCatalogPath with_mixed("windows\\for/life");
+ EXPECT_EQ(AssetCatalogPath("windows/for/life"), with_mixed.cleanup());
+ }
+ {
+ const AssetCatalogPath with_punctuation("is!/this?/¿valid?");
+ EXPECT_EQ(AssetCatalogPath("is!/this?/¿valid?"), with_punctuation.cleanup());
+ }
}
TEST(AssetCatalogPathTest, iterate_components)
diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc
index abe6d384247..2cef34966f8 100644
--- a/source/blender/blenkernel/intern/asset_catalog_test.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_test.cc
@@ -902,8 +902,6 @@ TEST_F(AssetCatalogTest, update_catalog_path)
const AssetCatalog *renamed_cat = service.find_catalog(UUID_POSES_RUZENA);
ASSERT_NE(nullptr, renamed_cat);
ASSERT_EQ(orig_cat, renamed_cat) << "Changing the path should not reallocate the catalog.";
- EXPECT_EQ(orig_cat->simple_name, renamed_cat->simple_name)
- << "Changing the path should not change the simple name.";
EXPECT_EQ(orig_cat->catalog_id, renamed_cat->catalog_id)
<< "Changing the path should not change the catalog ID.";
@@ -932,6 +930,47 @@ TEST_F(AssetCatalogTest, update_catalog_path_simple_name)
<< "Changing the path should update the simplename of children.";
}
+TEST_F(AssetCatalogTest, update_catalog_path_add_slashes)
+{
+ AssetCatalogService service(asset_library_root_);
+ service.load_from_disk(asset_library_root_ + "/" +
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME);
+
+ const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA);
+ const AssetCatalogPath orig_path = orig_cat->path;
+
+ /* Original path is `character/Ružena/poselib`.
+ * This rename will also create a new catalog for `character/Ružena/poses`. */
+ service.update_catalog_path(UUID_POSES_RUZENA, "character/Ružena/poses/general");
+
+ EXPECT_EQ(nullptr, service.find_catalog_by_path(orig_path))
+ << "The original (pre-rename) path should not be associated with a catalog any more.";
+
+ const AssetCatalog *renamed_cat = service.find_catalog(UUID_POSES_RUZENA);
+ ASSERT_NE(nullptr, renamed_cat);
+ EXPECT_EQ(orig_cat->catalog_id, renamed_cat->catalog_id)
+ << "Changing the path should not change the catalog ID.";
+
+ EXPECT_EQ("character/Ružena/poses/general", renamed_cat->path.str())
+ << "When creating a new catalog by renaming + adding a slash, the renamed catalog should be "
+ "assigned the path passed to update_catalog_path()";
+
+ /* Test the newly created catalog. */
+ const AssetCatalog *new_cat = service.find_catalog_by_path("character/Ružena/poses");
+ ASSERT_NE(nullptr, new_cat) << "Renaming to .../X/Y should cause .../X to exist as well.";
+ EXPECT_EQ("character/Ružena/poses", new_cat->path.str());
+ EXPECT_EQ("character-Ružena-poses", new_cat->simple_name);
+ EXPECT_TRUE(new_cat->flags.has_unsaved_changes);
+
+ /* Test the children. */
+ EXPECT_EQ("character/Ružena/poses/general/hand",
+ service.find_catalog(UUID_POSES_RUZENA_HAND)->path.str())
+ << "Changing the path should update children.";
+ EXPECT_EQ("character/Ružena/poses/general/face",
+ service.find_catalog(UUID_POSES_RUZENA_FACE)->path.str())
+ << "Changing the path should update children.";
+}
+
TEST_F(AssetCatalogTest, merge_catalog_files)
{
const CatalogFilePath cdf_dir = create_temp_path();
diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc
index 80504bbdc05..e26ae05301e 100644
--- a/source/blender/blenkernel/intern/asset_library_service_test.cc
+++ b/source/blender/blenkernel/intern/asset_library_service_test.cc
@@ -23,6 +23,7 @@
#include "BLI_path_util.h"
#include "BKE_appdir.h"
+#include "BKE_callbacks.h"
#include "CLG_log.h"
@@ -40,10 +41,12 @@ class AssetLibraryServiceTest : public testing::Test {
static void SetUpTestSuite()
{
CLG_init();
+ BKE_callback_global_init();
}
static void TearDownTestSuite()
{
CLG_exit();
+ BKE_callback_global_finalize();
}
void SetUp() override
diff --git a/source/blender/blenkernel/intern/asset_library_test.cc b/source/blender/blenkernel/intern/asset_library_test.cc
index c6c949a7ec4..702008fed96 100644
--- a/source/blender/blenkernel/intern/asset_library_test.cc
+++ b/source/blender/blenkernel/intern/asset_library_test.cc
@@ -20,6 +20,7 @@
#include "BKE_appdir.h"
#include "BKE_asset_catalog.hh"
#include "BKE_asset_library.hh"
+#include "BKE_callbacks.h"
#include "asset_library_service.hh"
@@ -34,10 +35,12 @@ class AssetLibraryTest : public testing::Test {
static void SetUpTestSuite()
{
CLG_init();
+ BKE_callback_global_init();
}
static void TearDownTestSuite()
{
CLG_exit();
+ BKE_callback_global_finalize();
}
void TearDown() override
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 3386d346364..01b53baf237 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -360,7 +360,7 @@ GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read(
return as_read_attribute_(data, domain_size);
}
-GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write(
+WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
GeometryComponent &component) const
{
if (writable_ != Writable) {
@@ -397,10 +397,14 @@ GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write(
data = new_data;
}
+ std::function<void()> tag_modified_fn;
if (update_on_write_ != nullptr) {
- update_on_write_(component);
+ tag_modified_fn = [component = &component, update = update_on_write_]() {
+ update(*component);
+ };
}
- return as_write_attribute_(data, domain_size);
+
+ return {as_write_attribute_(data, domain_size), domain_, std::move(tag_modified_fn)};
}
bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const
@@ -925,7 +929,7 @@ blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_writ
const BuiltinAttributeProvider *builtin_provider =
providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
if (builtin_provider != nullptr) {
- return {builtin_provider->try_get_for_write(*this), builtin_provider->domain()};
+ return builtin_provider->try_get_for_write(*this);
}
}
for (const DynamicAttributesProvider *dynamic_provider :
@@ -1249,6 +1253,20 @@ static void save_output_attribute(OutputAttribute &output_attribute)
varray.get(i, buffer);
write_attribute.varray->set_by_relocate(i, buffer);
}
+ if (write_attribute.tag_modified_fn) {
+ write_attribute.tag_modified_fn();
+ }
+}
+
+static std::function<void(OutputAttribute &)> get_simple_output_attribute_save_method(
+ const blender::bke::WriteAttributeLookup &attribute)
+{
+ if (!attribute.tag_modified_fn) {
+ return {};
+ }
+ return [tag_modified_fn = attribute.tag_modified_fn](OutputAttribute &UNUSED(attribute)) {
+ tag_modified_fn();
+ };
}
static OutputAttribute create_output_attribute(GeometryComponent &component,
@@ -1293,14 +1311,21 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
/* Builtin attribute is on different domain. */
return {};
}
+
GVMutableArrayPtr varray = std::move(attribute.varray);
if (varray->type() == *cpp_type) {
/* Builtin attribute matches exactly. */
- return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
+ return OutputAttribute(std::move(varray),
+ domain,
+ get_simple_output_attribute_save_method(attribute),
+ ignore_old_values);
}
/* Builtin attribute is on the same domain but has a different data type. */
varray = conversions.try_convert(std::move(varray), *cpp_type);
- return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
+ return OutputAttribute(std::move(varray),
+ domain,
+ get_simple_output_attribute_save_method(attribute),
+ ignore_old_values);
}
const int domain_size = component.attribute_domain_size(domain);
@@ -1324,7 +1349,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
}
if (attribute.domain == domain && attribute.varray->type() == *cpp_type) {
/* Existing generic attribute matches exactly. */
- return OutputAttribute(std::move(attribute.varray), domain, {}, ignore_old_values);
+
+ return OutputAttribute(std::move(attribute.varray),
+ domain,
+ get_simple_output_attribute_save_method(attribute),
+ ignore_old_values);
}
/* Allocate a new array that lives next to the existing attribute. It will overwrite the existing
@@ -1385,7 +1414,7 @@ const GVArray *AttributeFieldInput::get_varray_for_context(const fn::FieldContex
std::string AttributeFieldInput::socket_inspection_name() const
{
std::stringstream ss;
- ss << TIP_("Attribute: ") << name_;
+ ss << '"' << name_ << '"' << TIP_(" attribute from geometry");
return ss.str();
}
@@ -1468,7 +1497,7 @@ const GVArray *AnonymousAttributeFieldInput::get_varray_for_context(
std::string AnonymousAttributeFieldInput::socket_inspection_name() const
{
std::stringstream ss;
- ss << TIP_("Anonymous Attribute: ") << debug_name_;
+ ss << '"' << debug_name_ << '"' << TIP_(" from ") << producer_name_;
return ss.str();
}
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index 5cedcf69953..140498bdb01 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -87,7 +87,7 @@ class BuiltinAttributeProvider {
}
virtual GVArrayPtr try_get_for_read(const GeometryComponent &component) const = 0;
- virtual GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const = 0;
+ virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component) const = 0;
virtual bool try_delete(GeometryComponent &component) const = 0;
virtual bool try_create(GeometryComponent &UNUSED(component),
const AttributeInit &UNUSED(initializer)) const = 0;
@@ -267,7 +267,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
}
GVArrayPtr try_get_for_read(const GeometryComponent &component) const final;
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final;
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final;
bool try_delete(GeometryComponent &component) const final;
bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final;
bool exists(const GeometryComponent &component) const final;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 9facb146361..dc3c2a8e55e 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -207,14 +207,15 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data)
{
Brush *brush = (Brush *)id;
- BKE_LIB_FOREACHID_PROCESS(data, brush->toggle_brush, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, brush->clone.image, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, brush->paint_curve, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->toggle_brush, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->clone.image, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->paint_curve, IDWALK_CB_USER);
if (brush->gpencil_settings) {
- BKE_LIB_FOREACHID_PROCESS(data, brush->gpencil_settings->material, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->gpencil_settings->material, IDWALK_CB_USER);
}
- BKE_texture_mtex_foreach_id(data, &brush->mtex);
- BKE_texture_mtex_foreach_id(data, &brush->mask_mtex);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_texture_mtex_foreach_id(data, &brush->mtex));
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
+ BKE_texture_mtex_foreach_id(data, &brush->mask_mtex));
}
static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_address)
diff --git a/source/blender/blenkernel/intern/callbacks.c b/source/blender/blenkernel/intern/callbacks.c
index dbc213907ac..72dd51a940d 100644
--- a/source/blender/blenkernel/intern/callbacks.c
+++ b/source/blender/blenkernel/intern/callbacks.c
@@ -30,11 +30,20 @@
static ListBase callback_slots[BKE_CB_EVT_TOT] = {{NULL}};
+static bool callbacks_initialized = false;
+
+#define ASSERT_CALLBACKS_INITIALIZED() \
+ BLI_assert_msg(callbacks_initialized, \
+ "Callbacks should be initialized with BKE_callback_global_init() before using " \
+ "the callback system.")
+
void BKE_callback_exec(struct Main *bmain,
struct PointerRNA **pointers,
const int num_pointers,
eCbEvent evt)
{
+ ASSERT_CALLBACKS_INITIALIZED();
+
/* Use mutable iteration so handlers are able to remove themselves. */
ListBase *lb = &callback_slots[evt];
LISTBASE_FOREACH_MUTABLE (bCallbackFuncStore *, funcstore, lb) {
@@ -75,18 +84,26 @@ void BKE_callback_exec_id_depsgraph(struct Main *bmain,
void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt)
{
+ ASSERT_CALLBACKS_INITIALIZED();
ListBase *lb = &callback_slots[evt];
BLI_addtail(lb, funcstore);
}
void BKE_callback_remove(bCallbackFuncStore *funcstore, eCbEvent evt)
{
- ListBase *lb = &callback_slots[evt];
-
- /* Be safe, as the callback may have already been removed by BKE_callback_global_finalize(), for
+ /* The callback may have already been removed by BKE_callback_global_finalize(), for
* example when removing callbacks in response to a BKE_blender_atexit_register callback
* function. `BKE_blender_atexit()` runs after `BKE_callback_global_finalize()`. */
- BLI_remlink_safe(lb, funcstore);
+ if (!callbacks_initialized) {
+ return;
+ }
+
+ ListBase *lb = &callback_slots[evt];
+
+ /* Be noisy about potential programming errors. */
+ BLI_assert_msg(BLI_findindex(lb, funcstore) != -1, "To-be-removed callback not found");
+
+ BLI_remlink(lb, funcstore);
if (funcstore->alloc) {
MEM_freeN(funcstore);
@@ -95,7 +112,7 @@ void BKE_callback_remove(bCallbackFuncStore *funcstore, eCbEvent evt)
void BKE_callback_global_init(void)
{
- /* do nothing */
+ callbacks_initialized = true;
}
/* call on application exit */
@@ -111,4 +128,6 @@ void BKE_callback_global_finalize(void)
BKE_callback_remove(funcstore, evt);
}
}
+
+ callbacks_initialized = false;
}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index ed1f6fcb40a..9455eed7f3f 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -103,13 +103,13 @@ static void camera_foreach_id(ID *id, LibraryForeachIDData *data)
{
Camera *camera = (Camera *)id;
- BKE_LIB_FOREACHID_PROCESS(data, camera->dof.focus_object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, camera->dof.focus_object, IDWALK_CB_NOP);
LISTBASE_FOREACH (CameraBGImage *, bgpic, &camera->bg_images) {
if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
- BKE_LIB_FOREACHID_PROCESS(data, bgpic->ima, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, bgpic->ima, IDWALK_CB_USER);
}
else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
- BKE_LIB_FOREACHID_PROCESS(data, bgpic->clip, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, bgpic->clip, IDWALK_CB_USER);
}
}
}
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 8e50b9e9534..14097ecd8a7 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -158,10 +158,11 @@ static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
Collection *collection = (Collection *)id;
LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
- BKE_LIB_FOREACHID_PROCESS(data, cob->ob, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, cob->ob, IDWALK_CB_USER);
}
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- BKE_LIB_FOREACHID_PROCESS(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
+ data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
}
LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) {
/* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
@@ -170,7 +171,7 @@ static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
(parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
IDWALK_CB_EMBEDDED :
IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);
}
}
@@ -715,7 +716,7 @@ Collection *BKE_collection_duplicate(Main *bmain,
collection_new->id.tag &= ~LIB_TAG_NEW;
/* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */
- BKE_libblock_relink_to_newid(&collection_new->id);
+ BKE_libblock_relink_to_newid(bmain, &collection_new->id);
#ifndef NDEBUG
/* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 620110f7881..aae9ac383a4 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -130,17 +130,17 @@ static void curve_free_data(ID *id)
static void curve_foreach_id(ID *id, LibraryForeachIDData *data)
{
Curve *curve = (Curve *)id;
- BKE_LIB_FOREACHID_PROCESS(data, curve->bevobj, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, curve->taperobj, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, curve->textoncurve, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, curve->key, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->bevobj, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->taperobj, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->textoncurve, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->key, IDWALK_CB_USER);
for (int i = 0; i < curve->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, curve->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->mat[i], IDWALK_CB_USER);
}
- BKE_LIB_FOREACHID_PROCESS(data, curve->vfont, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, curve->vfontb, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, curve->vfonti, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, curve->vfontbi, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->vfont, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->vfontb, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->vfonti, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->vfontbi, IDWALK_CB_USER);
}
static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_address)
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index 8eec7f5dfab..0e3da9e0789 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -160,6 +160,13 @@ blender::Array<float> CurveEval::accumulated_spline_lengths() const
return spline_lengths;
}
+void CurveEval::mark_cache_invalid()
+{
+ for (SplinePtr &spline : splines_) {
+ spline->mark_cache_invalid();
+ }
+}
+
static BezierSpline::HandleType handle_type_from_dna_bezt(const eBezTriple_Handle dna_handle_type)
{
switch (dna_handle_type) {
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 5f2f945192c..cd40d5e8a41 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -88,6 +88,7 @@ static void mark_edges_sharp(MutableSpan<MEdge> edges)
}
static void spline_extrude_to_mesh_data(const ResultInfo &info,
+ const bool fill_caps,
MutableSpan<MVert> r_verts,
MutableSpan<MEdge> r_edges,
MutableSpan<MLoop> r_loops,
@@ -180,6 +181,37 @@ static void spline_extrude_to_mesh_data(const ResultInfo &info,
}
}
+ if (fill_caps && profile.is_cyclic()) {
+ const int poly_size = info.spline_edge_len * info.profile_edge_len;
+ const int cap_loop_offset = info.loop_offset + poly_size * 4;
+ const int cap_poly_offset = info.poly_offset + poly_size;
+
+ MPoly &poly_start = r_polys[cap_poly_offset];
+ poly_start.loopstart = cap_loop_offset;
+ poly_start.totloop = info.profile_edge_len;
+ MPoly &poly_end = r_polys[cap_poly_offset + 1];
+ poly_end.loopstart = cap_loop_offset + info.profile_edge_len;
+ poly_end.totloop = info.profile_edge_len;
+
+ const int last_ring_index = info.spline_vert_len - 1;
+ const int last_ring_vert_offset = info.vert_offset + info.profile_vert_len * last_ring_index;
+ const int last_ring_edge_offset = profile_edges_start +
+ info.profile_edge_len * last_ring_index;
+
+ for (const int i : IndexRange(info.profile_edge_len)) {
+ const int i_inv = info.profile_edge_len - i - 1;
+ MLoop &loop_start = r_loops[cap_loop_offset + i];
+ loop_start.v = info.vert_offset + i_inv;
+ loop_start.e = profile_edges_start + i_inv;
+ MLoop &loop_end = r_loops[cap_loop_offset + info.profile_edge_len + i];
+ loop_end.v = last_ring_vert_offset + i;
+ loop_end.e = last_ring_edge_offset + i;
+ }
+
+ mark_edges_sharp(r_edges.slice(profile_edges_start, info.profile_edge_len));
+ mark_edges_sharp(r_edges.slice(last_ring_edge_offset, info.profile_edge_len));
+ }
+
/* Calculate the positions of each profile ring profile along the spline. */
Span<float3> positions = spline.evaluated_positions();
Span<float3> tangents = spline.evaluated_tangents();
@@ -226,14 +258,22 @@ static inline int spline_extrude_edge_size(const Spline &curve, const Spline &pr
curve.evaluated_edges_size() * profile.evaluated_points_size();
}
-static inline int spline_extrude_loop_size(const Spline &curve, const Spline &profile)
+static inline int spline_extrude_loop_size(const Spline &curve,
+ const Spline &profile,
+ const bool fill_caps)
{
- return curve.evaluated_edges_size() * profile.evaluated_edges_size() * 4;
+ const int tube = curve.evaluated_edges_size() * profile.evaluated_edges_size() * 4;
+ const int caps = (fill_caps && profile.is_cyclic()) ? profile.evaluated_edges_size() * 2 : 0;
+ return tube + caps;
}
-static inline int spline_extrude_poly_size(const Spline &curve, const Spline &profile)
+static inline int spline_extrude_poly_size(const Spline &curve,
+ const Spline &profile,
+ const bool fill_caps)
{
- return curve.evaluated_edges_size() * profile.evaluated_edges_size();
+ const int tube = curve.evaluated_edges_size() * profile.evaluated_edges_size();
+ const int caps = (fill_caps && profile.is_cyclic()) ? 2 : 0;
+ return tube + caps;
}
struct ResultOffsets {
@@ -242,7 +282,9 @@ struct ResultOffsets {
Array<int> loop;
Array<int> poly;
};
-static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles, Span<SplinePtr> curves)
+static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles,
+ Span<SplinePtr> curves,
+ const bool fill_caps)
{
const int total = profiles.size() * curves.size();
Array<int> vert(total + 1);
@@ -263,8 +305,8 @@ static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles, Span<Spl
poly[mesh_index] = poly_offset;
vert_offset += spline_extrude_vert_size(*curves[i_spline], *profiles[i_profile]);
edge_offset += spline_extrude_edge_size(*curves[i_spline], *profiles[i_profile]);
- loop_offset += spline_extrude_loop_size(*curves[i_spline], *profiles[i_profile]);
- poly_offset += spline_extrude_poly_size(*curves[i_spline], *profiles[i_profile]);
+ loop_offset += spline_extrude_loop_size(*curves[i_spline], *profiles[i_profile], fill_caps);
+ poly_offset += spline_extrude_poly_size(*curves[i_spline], *profiles[i_profile], fill_caps);
mesh_index++;
}
}
@@ -652,12 +694,12 @@ static void copy_spline_domain_attributes_to_mesh(const CurveEval &curve,
* changed anyway in a way that affects the normals. So currently this code uses the safer /
* simpler solution of deferring normal calculation to the rest of Blender.
*/
-Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile)
+Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, const bool fill_caps)
{
Span<SplinePtr> profiles = profile.splines();
Span<SplinePtr> curves = curve.splines();
- const ResultOffsets offsets = calculate_result_offsets(profiles, curves);
+ const ResultOffsets offsets = calculate_result_offsets(profiles, curves, fill_caps);
if (offsets.vert.last() == 0) {
return nullptr;
}
@@ -696,6 +738,7 @@ Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile)
};
spline_extrude_to_mesh_data(info,
+ fill_caps,
{mesh->mvert, mesh->totvert},
{mesh->medge, mesh->totedge},
{mesh->mloop, mesh->totloop},
@@ -733,7 +776,7 @@ static CurveEval get_curve_single_vert()
Mesh *curve_to_wire_mesh(const CurveEval &curve)
{
static const CurveEval vert_curve = get_curve_single_vert();
- return curve_to_mesh_sweep(curve, vert_curve);
+ return curve_to_mesh_sweep(curve, vert_curve, false);
}
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 8e9c504dcbf..bbf61c51bfb 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -203,14 +203,18 @@ void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
switch (fcm->type) {
case FMODIFIER_TYPE_PYTHON: {
FMod_Python *fcm_py = (FMod_Python *)fcm->data;
- BKE_LIB_FOREACHID_PROCESS(data, fcm_py->script, IDWALK_CB_NOP);
-
- IDP_foreach_property(fcm_py->prop,
- IDP_TYPE_FILTER_ID,
- BKE_lib_query_idpropertiesForeachIDLink_callback,
- data);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fcm_py->script, IDWALK_CB_NOP);
+
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(fcm_py->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data));
break;
}
+ default:
+ break;
}
}
}
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index f30ff2a70a7..d3c3fcc1e67 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -433,7 +433,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
return as_read_attribute_(*curve);
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
{
if (writable_ != Writable) {
return {};
@@ -442,7 +442,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
if (curve == nullptr) {
return {};
}
- return as_write_attribute_(*curve);
+ return {as_write_attribute_(*curve), domain_};
}
bool try_delete(GeometryComponent &UNUSED(component)) const final
@@ -1122,7 +1122,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
return point_data_gvarray(spans, offsets);
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const override
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override
{
CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
@@ -1133,22 +1133,30 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
return {};
}
+ std::function<void()> tag_modified_fn;
+ if (update_on_write_ != nullptr) {
+ tag_modified_fn = [curve, update = update_on_write_]() {
+ for (SplinePtr &spline : curve->splines()) {
+ update(*spline);
+ }
+ };
+ }
+
MutableSpan<SplinePtr> splines = curve->splines();
if (splines.size() == 1) {
- return std::make_unique<fn::GVMutableArray_For_GMutableSpan>(
- get_mutable_span_(*splines.first()));
+ return {std::make_unique<fn::GVMutableArray_For_GMutableSpan>(
+ get_mutable_span_(*splines.first())),
+ domain_,
+ std::move(tag_modified_fn)};
}
Array<int> offsets = curve->control_point_offsets();
Array<MutableSpan<T>> spans(splines.size());
for (const int i : splines.index_range()) {
spans[i] = get_mutable_span_(*splines[i]);
- if (update_on_write_) {
- update_on_write_(*splines[i]);
- }
}
- return point_data_gvarray(spans, offsets);
+ return {point_data_gvarray(spans, offsets), domain_, tag_modified_fn};
}
bool try_delete(GeometryComponent &component) const final
@@ -1220,7 +1228,7 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
{
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
{
CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
@@ -1233,16 +1241,19 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
return BuiltinPointAttributeProvider<float3>::try_get_for_write(component);
}
- /* Changing the positions requires recalculation of cached evaluated data in many cases.
- * This could set more specific flags in the future to avoid unnecessary recomputation. */
- for (SplinePtr &spline : curve->splines()) {
- spline->mark_cache_invalid();
- }
+ auto tag_modified_fn = [curve]() {
+ /* Changing the positions requires recalculation of cached evaluated data in many cases.
+ * This could set more specific flags in the future to avoid unnecessary recomputation. */
+ curve->mark_cache_invalid();
+ };
Array<int> offsets = curve->control_point_offsets();
- return std::make_unique<
- fn::GVMutableArray_For_EmbeddedVMutableArray<float3, VMutableArray_For_SplinePosition>>(
- offsets.last(), curve->splines(), std::move(offsets));
+ return {std::make_unique<
+ fn::GVMutableArray_For_EmbeddedVMutableArray<float3,
+ VMutableArray_For_SplinePosition>>(
+ offsets.last(), curve->splines(), std::move(offsets)),
+ domain_,
+ tag_modified_fn};
}
};
@@ -1278,7 +1289,7 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
offsets.last(), curve->splines(), std::move(offsets), is_right_);
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const override
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override
{
CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
@@ -1289,10 +1300,15 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
return {};
}
+ auto tag_modified_fn = [curve]() { curve->mark_cache_invalid(); };
+
Array<int> offsets = curve->control_point_offsets();
- return std::make_unique<
- fn::GVMutableArray_For_EmbeddedVMutableArray<float3, VMutableArray_For_BezierHandles>>(
- offsets.last(), curve->splines(), std::move(offsets), is_right_);
+ return {
+ std::make_unique<
+ fn::GVMutableArray_For_EmbeddedVMutableArray<float3, VMutableArray_For_BezierHandles>>(
+ offsets.last(), curve->splines(), std::move(offsets), is_right_),
+ domain_,
+ tag_modified_fn};
}
bool try_delete(GeometryComponent &UNUSED(component)) const final
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 4204d62e1a7..5fe77000519 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -60,7 +60,9 @@ void InstancesComponent::reserve(int min_capacity)
{
instance_reference_handles_.reserve(min_capacity);
instance_transforms_.reserve(min_capacity);
- instance_ids_.reserve(min_capacity);
+ if (!instance_ids_.is_empty()) {
+ this->instance_ids_ensure();
+ }
}
/**
@@ -73,7 +75,9 @@ void InstancesComponent::resize(int capacity)
{
instance_reference_handles_.resize(capacity);
instance_transforms_.resize(capacity);
- instance_ids_.resize(capacity);
+ if (!instance_ids_.is_empty()) {
+ this->instance_ids_ensure();
+ }
}
void InstancesComponent::clear()
@@ -85,15 +89,15 @@ void InstancesComponent::clear()
references_.clear();
}
-void InstancesComponent::add_instance(const int instance_handle,
- const float4x4 &transform,
- const int id)
+void InstancesComponent::add_instance(const int instance_handle, const float4x4 &transform)
{
BLI_assert(instance_handle >= 0);
BLI_assert(instance_handle < references_.size());
instance_reference_handles_.append(instance_handle);
instance_transforms_.append(transform);
- instance_ids_.append(id);
+ if (!instance_ids_.is_empty()) {
+ this->instance_ids_ensure();
+ }
}
blender::Span<int> InstancesComponent::instance_reference_handles() const
@@ -125,6 +129,22 @@ blender::Span<int> InstancesComponent::instance_ids() const
}
/**
+ * Make sure the ID storage size matches the number of instances. By directly resizing the
+ * component's vectors internally, it is possible to be in a situation where the IDs are not
+ * empty but they do not have the correct size; this function resolves that.
+ */
+blender::MutableSpan<int> InstancesComponent::instance_ids_ensure()
+{
+ instance_ids_.append_n_times(0, this->instances_amount() - instance_ids_.size());
+ return instance_ids_;
+}
+
+void InstancesComponent::instance_ids_clear()
+{
+ instance_ids_.clear_and_make_inline();
+}
+
+/**
* With write access to the instances component, the data in the instanced geometry sets can be
* changed. This is a function on the component rather than each reference to ensure `const`
* correctness for that reason.
@@ -327,8 +347,16 @@ static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
blender::Span<int> InstancesComponent::almost_unique_ids() const
{
std::lock_guard lock(almost_unique_ids_mutex_);
- if (almost_unique_ids_.size() != instance_ids_.size()) {
- almost_unique_ids_ = generate_unique_instance_ids(instance_ids_);
+ if (instance_ids().is_empty()) {
+ almost_unique_ids_.reinitialize(this->instances_amount());
+ for (const int i : almost_unique_ids_.index_range()) {
+ almost_unique_ids_[i] = i;
+ }
+ }
+ else {
+ if (almost_unique_ids_.size() != instance_ids_.size()) {
+ almost_unique_ids_ = generate_unique_instance_ids(instance_ids_);
+ }
}
return almost_unique_ids_;
}
@@ -370,15 +398,16 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
transforms);
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
{
InstancesComponent &instances_component = static_cast<InstancesComponent &>(component);
MutableSpan<float4x4> transforms = instances_component.instance_transforms();
- return std::make_unique<fn::GVMutableArray_For_DerivedSpan<float4x4,
- float3,
- get_transform_position,
- set_transform_position>>(
- transforms);
+ return {
+ std::make_unique<fn::GVMutableArray_For_DerivedSpan<float4x4,
+ float3,
+ get_transform_position,
+ set_transform_position>>(transforms),
+ domain_};
}
bool try_delete(GeometryComponent &UNUSED(component)) const final
@@ -398,11 +427,83 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
}
};
+class InstanceIDAttributeProvider final : public BuiltinAttributeProvider {
+ public:
+ InstanceIDAttributeProvider()
+ : BuiltinAttributeProvider(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32, Creatable, Writable, Deletable)
+ {
+ }
+
+ GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
+ {
+ const InstancesComponent &instances = static_cast<const InstancesComponent &>(component);
+ if (instances.instance_ids().is_empty()) {
+ return {};
+ }
+ return std::make_unique<fn::GVArray_For_Span<int>>(instances.instance_ids());
+ }
+
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
+ {
+ InstancesComponent &instances = static_cast<InstancesComponent &>(component);
+ if (instances.instance_ids().is_empty()) {
+ return {};
+ }
+ return {std::make_unique<fn::GVMutableArray_For_MutableSpan<int>>(instances.instance_ids()),
+ domain_};
+ }
+
+ bool try_delete(GeometryComponent &component) const final
+ {
+ InstancesComponent &instances = static_cast<InstancesComponent &>(component);
+ if (instances.instance_ids().is_empty()) {
+ return false;
+ }
+ instances.instance_ids_clear();
+ return true;
+ }
+
+ bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final
+ {
+ InstancesComponent &instances = static_cast<InstancesComponent &>(component);
+ if (instances.instances_amount() == 0) {
+ return false;
+ }
+ MutableSpan<int> ids = instances.instance_ids_ensure();
+ switch (initializer.type) {
+ case AttributeInit::Type::Default: {
+ ids.fill(0);
+ break;
+ }
+ case AttributeInit::Type::VArray: {
+ const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray;
+ varray->materialize_to_uninitialized(IndexRange(varray->size()), ids.data());
+ break;
+ }
+ case AttributeInit::Type::MoveArray: {
+ void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
+ ids.copy_from({static_cast<int *>(source_data), instances.instances_amount()});
+ MEM_freeN(source_data);
+ break;
+ }
+ }
+ return true;
+ }
+
+ bool exists(const GeometryComponent &component) const final
+ {
+ const InstancesComponent &instances = static_cast<const InstancesComponent &>(component);
+ return !instances.instance_ids().is_empty();
+ }
+};
+
static ComponentAttributeProviders create_attribute_providers_for_instances()
{
static InstancePositionAttributeProvider position;
+ static InstanceIDAttributeProvider id;
- return ComponentAttributeProviders({&position}, {});
+ return ComponentAttributeProviders({&position, &id}, {});
}
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 6091d3f3dab..c3e39c0b2cb 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -1210,7 +1210,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
+ WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final
{
return {};
}
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 4753a9e0768..cd1bafe445a 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -527,6 +527,40 @@ void GeometrySet::gather_attributes_for_propagation(
delete dummy_component;
}
+static void gather_component_types_recursive(const GeometrySet &geometry_set,
+ const bool include_instances,
+ const bool ignore_empty,
+ Vector<GeometryComponentType> &r_types)
+{
+ for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
+ if (ignore_empty) {
+ if (component->is_empty()) {
+ continue;
+ }
+ }
+ r_types.append_non_duplicates(component->type());
+ }
+ if (!include_instances) {
+ return;
+ }
+ const InstancesComponent *instances = geometry_set.get_component_for_read<InstancesComponent>();
+ if (instances == nullptr) {
+ return;
+ }
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_component_types_recursive(
+ instance_geometry_set, include_instances, ignore_empty, r_types);
+ });
+}
+
+blender::Vector<GeometryComponentType> GeometrySet::gather_component_types(
+ const bool include_instances, bool ignore_empty) const
+{
+ Vector<GeometryComponentType> types;
+ gather_component_types_recursive(*this, include_instances, ignore_empty, types);
+ return types;
+}
+
static void gather_mutable_geometry_sets(GeometrySet &geometry_set,
Vector<GeometrySet *> &r_geometry_sets)
{
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index fa0741d3a2e..bea65030c06 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -139,11 +139,11 @@ static void greasepencil_foreach_id(ID *id, LibraryForeachIDData *data)
bGPdata *gpencil = (bGPdata *)id;
/* materials */
for (int i = 0; i < gpencil->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, gpencil->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, gpencil->mat[i], IDWALK_CB_USER);
}
LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) {
- BKE_LIB_FOREACHID_PROCESS(data, gplayer->parent, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, gplayer->parent, IDWALK_CB_NOP);
}
}
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c
index cf346e9cac7..7433ee7ac29 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.c
@@ -107,7 +107,7 @@ static void hair_foreach_id(ID *id, LibraryForeachIDData *data)
{
Hair *hair = (Hair *)id;
for (int i = 0; i < hair->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, hair->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, hair->mat[i], IDWALK_CB_USER);
}
}
diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc
index 97c742b1ec1..f820b345c59 100644
--- a/source/blender/blenkernel/intern/icons.cc
+++ b/source/blender/blenkernel/intern/icons.cc
@@ -359,22 +359,30 @@ void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
PreviewImage **BKE_previewimg_id_get_p(const ID *id)
{
switch (GS(id->name)) {
+ case ID_OB: {
+ Object *ob = (Object *)id;
+ /* Currently, only object types with real geometry can be rendered as preview. */
+ if (!OB_TYPE_IS_GEOMETRY(ob->type)) {
+ return nullptr;
+ }
+ return &ob->preview;
+ }
+
#define ID_PRV_CASE(id_code, id_struct) \
case id_code: { \
return &((id_struct *)id)->preview; \
} \
((void)0)
- ID_PRV_CASE(ID_MA, Material);
- ID_PRV_CASE(ID_TE, Tex);
- ID_PRV_CASE(ID_WO, World);
- ID_PRV_CASE(ID_LA, Light);
- ID_PRV_CASE(ID_IM, Image);
- ID_PRV_CASE(ID_BR, Brush);
- ID_PRV_CASE(ID_OB, Object);
- ID_PRV_CASE(ID_GR, Collection);
- ID_PRV_CASE(ID_SCE, Scene);
- ID_PRV_CASE(ID_SCR, bScreen);
- ID_PRV_CASE(ID_AC, bAction);
+ ID_PRV_CASE(ID_MA, Material);
+ ID_PRV_CASE(ID_TE, Tex);
+ ID_PRV_CASE(ID_WO, World);
+ ID_PRV_CASE(ID_LA, Light);
+ ID_PRV_CASE(ID_IM, Image);
+ ID_PRV_CASE(ID_BR, Brush);
+ ID_PRV_CASE(ID_GR, Collection);
+ ID_PRV_CASE(ID_SCE, Scene);
+ ID_PRV_CASE(ID_SCR, bScreen);
+ ID_PRV_CASE(ID_AC, bAction);
#undef ID_PRV_CASE
default:
break;
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 5ae338aaaeb..3800cbec94b 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -211,8 +211,12 @@ static void image_foreach_cache(ID *id,
for (int eye = 0; eye < 2; eye++) {
for (int a = 0; a < TEXTARGET_COUNT; a++) {
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ GPUTexture *texture = image->gputexture[a][eye][resolution];
+ if (texture == NULL) {
+ continue;
+ }
key.offset_in_ID = offsetof(Image, gputexture[a][eye][resolution]);
- key.cache_v = image->gputexture[a][eye];
+ key.cache_v = texture;
function_callback(id, &key, (void **)&image->gputexture[a][eye][resolution], 0, user_data);
}
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 9bca8172e64..a2da59bca58 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -131,7 +131,7 @@ static void lattice_free_data(ID *id)
static void lattice_foreach_id(ID *id, LibraryForeachIDData *data)
{
Lattice *lattice = (Lattice *)id;
- BKE_LIB_FOREACHID_PROCESS(data, lattice->key, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lattice->key, IDWALK_CB_USER);
}
static void lattice_blend_write(BlendWriter *writer, ID *id, const void *id_address)
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 2ac92828cec..74750a9b61a 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -76,48 +76,52 @@ typedef struct LibraryForeachIDData {
BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
-bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag)
+/** Check whether current iteration over ID usages should be stopped or not.
+ * \return true if the iteration should be stopped, false otherwise. */
+bool BKE_lib_query_foreachid_iter_stop(LibraryForeachIDData *data)
{
- if (!(data->status & IDWALK_STOP)) {
- const int flag = data->flag;
- ID *old_id = *id_pp;
-
- /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic
- * caller code. */
- cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear);
-
- /* Update the callback flags with some extra information regarding overrides: all 'loopback',
- * 'internal', 'embedded' etc. ID pointers are never overridable. */
- if (cb_flag &
- (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
- cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE;
- }
+ return (data->status & IDWALK_STOP) != 0;
+}
- const int callback_return = data->callback(
- &(struct LibraryIDLinkCallbackData){.user_data = data->user_data,
- .bmain = data->bmain,
- .id_owner = data->owner_id,
- .id_self = data->self_id,
- .id_pointer = id_pp,
- .cb_flag = cb_flag});
- if (flag & IDWALK_READONLY) {
- BLI_assert(*(id_pp) == old_id);
- }
- if (old_id && (flag & IDWALK_RECURSE)) {
- if (BLI_gset_add((data)->ids_handled, old_id)) {
- if (!(callback_return & IDWALK_RET_STOP_RECURSION)) {
- BLI_LINKSTACK_PUSH(data->ids_todo, old_id);
- }
+void BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag)
+{
+ if (BKE_lib_query_foreachid_iter_stop(data)) {
+ return;
+ }
+
+ const int flag = data->flag;
+ ID *old_id = *id_pp;
+
+ /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic
+ * caller code. */
+ cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear);
+
+ /* Update the callback flags with some extra information regarding overrides: all 'loopback',
+ * 'internal', 'embedded' etc. ID pointers are never overridable. */
+ if (cb_flag & (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
+ cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE;
+ }
+
+ const int callback_return = data->callback(
+ &(struct LibraryIDLinkCallbackData){.user_data = data->user_data,
+ .bmain = data->bmain,
+ .id_owner = data->owner_id,
+ .id_self = data->self_id,
+ .id_pointer = id_pp,
+ .cb_flag = cb_flag});
+ if (flag & IDWALK_READONLY) {
+ BLI_assert(*(id_pp) == old_id);
+ }
+ if (old_id && (flag & IDWALK_RECURSE)) {
+ if (BLI_gset_add((data)->ids_handled, old_id)) {
+ if (!(callback_return & IDWALK_RET_STOP_RECURSION)) {
+ BLI_LINKSTACK_PUSH(data->ids_todo, old_id);
}
}
- if (callback_return & IDWALK_RET_STOP_ITER) {
- data->status |= IDWALK_STOP;
- return false;
- }
- return true;
}
-
- return false;
+ if (callback_return & IDWALK_RET_STOP_ITER) {
+ data->status |= IDWALK_STOP;
+ }
}
int BKE_lib_query_foreachid_process_flags_get(LibraryForeachIDData *data)
@@ -139,7 +143,7 @@ int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData
return cb_flag_backup;
}
-static void library_foreach_ID_link(Main *bmain,
+static bool library_foreach_ID_link(Main *bmain,
ID *id_owner,
ID *id,
LibraryIDLinkCallback callback,
@@ -158,19 +162,24 @@ void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void
BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, cb_flag);
}
-bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
+/** Process embedded ID pointers (root nodetrees, master collections, ...).
+ *
+ * Those require specific care, since they are technically sub-data of their owner, yet in some
+ * cases they still behave as regular IDs. */
+void BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
{
/* Needed e.g. for callbacks handling relationships. This call shall be absolutely read-only. */
ID *id = *id_pp;
const int flag = data->flag;
- if (!BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED)) {
- return false;
+ BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED);
+ if (BKE_lib_query_foreachid_iter_stop(data)) {
+ return;
}
BLI_assert(id == *id_pp);
if (id == NULL) {
- return true;
+ return;
}
if (flag & IDWALK_IGNORE_EMBEDDED_ID) {
@@ -186,14 +195,24 @@ bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
}
}
else {
- library_foreach_ID_link(
- data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data);
+ if (!library_foreach_ID_link(
+ data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data)) {
+ data->status |= IDWALK_STOP;
+ return;
+ }
}
+}
- return true;
+static void library_foreach_ID_data_cleanup(LibraryForeachIDData *data)
+{
+ if (data->ids_handled != NULL) {
+ BLI_gset_free(data->ids_handled, NULL);
+ BLI_LINKSTACK_FREE(data->ids_todo);
+ }
}
-static void library_foreach_ID_link(Main *bmain,
+/** \return false in case iteration over ID pointers must be stopped, true otherwise. */
+static bool library_foreach_ID_link(Main *bmain,
ID *id_owner,
ID *id,
LibraryIDLinkCallback callback,
@@ -210,6 +229,10 @@ static void library_foreach_ID_link(Main *bmain,
flag |= IDWALK_READONLY;
flag &= ~IDWALK_DO_INTERNAL_RUNTIME_POINTERS;
+ /* NOTE: This function itself should never be called recursively when IDWALK_RECURSE is set,
+ * see also comments in #BKE_library_foreach_ID_embedded.
+ * This is why we can always create this data here, and do not need to try and re-use it from
+ * `inherit_data`. */
data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
BLI_LINKSTACK_INIT(data.ids_todo);
@@ -224,10 +247,26 @@ static void library_foreach_ID_link(Main *bmain,
data.user_data = user_data;
#define CALLBACK_INVOKE_ID(check_id, cb_flag) \
- BKE_LIB_FOREACHID_PROCESS_ID(&data, check_id, cb_flag)
+ { \
+ CHECK_TYPE_ANY((check_id), ID *, void *); \
+ BKE_lib_query_foreachid_process(&data, (ID **)&(check_id), (cb_flag)); \
+ if (BKE_lib_query_foreachid_iter_stop(&data)) { \
+ library_foreach_ID_data_cleanup(&data); \
+ return false; \
+ } \
+ } \
+ ((void)0)
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
- BKE_LIB_FOREACHID_PROCESS(&data, check_id_super, cb_flag)
+ { \
+ CHECK_TYPE(&((check_id_super)->id), ID *); \
+ BKE_lib_query_foreachid_process(&data, (ID **)&(check_id_super), (cb_flag)); \
+ if (BKE_lib_query_foreachid_iter_stop(&data)) { \
+ library_foreach_ID_data_cleanup(&data); \
+ return false; \
+ } \
+ } \
+ ((void)0)
for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
data.self_id = id;
@@ -269,6 +308,10 @@ static void library_foreach_ID_link(Main *bmain,
to_id_entry = to_id_entry->next) {
BKE_lib_query_foreachid_process(
&data, to_id_entry->id_pointer.to, to_id_entry->usage_flag);
+ if (BKE_lib_query_foreachid_iter_stop(&data)) {
+ library_foreach_ID_data_cleanup(&data);
+ return false;
+ }
}
continue;
}
@@ -292,26 +335,33 @@ static void library_foreach_ID_link(Main *bmain,
IDP_TYPE_FILTER_ID,
BKE_lib_query_idpropertiesForeachIDLink_callback,
&data);
+ if (BKE_lib_query_foreachid_iter_stop(&data)) {
+ library_foreach_ID_data_cleanup(&data);
+ return false;
+ }
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
BKE_animdata_foreach_id(adt, &data);
+ if (BKE_lib_query_foreachid_iter_stop(&data)) {
+ library_foreach_ID_data_cleanup(&data);
+ return false;
+ }
}
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
if (id_type->foreach_id != NULL) {
id_type->foreach_id(id, &data);
- if (data.status & IDWALK_STOP) {
- break;
+ if (BKE_lib_query_foreachid_iter_stop(&data)) {
+ library_foreach_ID_data_cleanup(&data);
+ return false;
}
}
}
- if (data.ids_handled) {
- BLI_gset_free(data.ids_handled, NULL);
- BLI_LINKSTACK_FREE(data.ids_todo);
- }
+ library_foreach_ID_data_cleanup(&data);
+ return true;
#undef CALLBACK_INVOKE_ID
#undef CALLBACK_INVOKE
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index b5c45c0902b..248d85bcae0 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -669,56 +669,10 @@ void BKE_libblock_relink_ex(
DEG_relations_tag_update(bmain);
}
+static void libblock_relink_to_newid(Main *bmain, ID *id);
static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data)
{
const int cb_flag = cb_data->cb_flag;
- if (cb_flag & IDWALK_CB_EMBEDDED) {
- return IDWALK_RET_NOP;
- }
-
- ID **id_pointer = cb_data->id_pointer;
- ID *id = *id_pointer;
- if (id) {
- /* See: NEW_ID macro */
- if (id->newid) {
- BKE_library_update_ID_link_user(id->newid, id, cb_flag);
- id = id->newid;
- *id_pointer = id;
- }
- if (id->tag & LIB_TAG_NEW) {
- id->tag &= ~LIB_TAG_NEW;
- BKE_libblock_relink_to_newid(id);
- }
- }
- return IDWALK_RET_NOP;
-}
-
-/**
- * Similar to #libblock_relink_ex,
- * but is remapping IDs to their newid value if non-NULL, in given \a id.
- *
- * Very specific usage, not sure we'll keep it on the long run,
- * currently only used in Object/Collection duplication code...
- *
- * WARNING: This is a deprecated version of this function, should not be used by new code. See
- * #BKE_libblock_relink_to_newid_new below.
- */
-void BKE_libblock_relink_to_newid(ID *id)
-{
- if (ID_IS_LINKED(id)) {
- return;
- }
-
- BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0);
-}
-
-/* ************************
- * FIXME: Port all usages of #BKE_libblock_relink_to_newid to this
- * #BKE_libblock_relink_to_newid_new new code and remove old one.
- ************************** */
-static int id_relink_to_newid_looper_new(LibraryIDLinkCallbackData *cb_data)
-{
- const int cb_flag = cb_data->cb_flag;
if (cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
return IDWALK_RET_NOP;
}
@@ -739,12 +693,22 @@ static int id_relink_to_newid_looper_new(LibraryIDLinkCallbackData *cb_data)
}
if (id->tag & LIB_TAG_NEW) {
id->tag &= ~LIB_TAG_NEW;
- BKE_libblock_relink_to_newid_new(bmain, id);
+ libblock_relink_to_newid(bmain, id);
}
}
return IDWALK_RET_NOP;
}
+static void libblock_relink_to_newid(Main *bmain, ID *id)
+{
+ if (ID_IS_LINKED(id)) {
+ return;
+ }
+
+ id->tag &= ~LIB_TAG_NEW;
+ BKE_library_foreach_ID_link(bmain, id, id_relink_to_newid_looper, NULL, 0);
+}
+
/**
* Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
* in the dependency tree of IDs for all data-blocks tagged with `LIB_TAG_NEW`.
@@ -754,7 +718,7 @@ static int id_relink_to_newid_looper_new(LibraryIDLinkCallbackData *cb_data)
* Very specific usage, not sure we'll keep it on the long run,
* currently only used in Object/Collection duplication code...
*/
-void BKE_libblock_relink_to_newid_new(Main *bmain, ID *id)
+void BKE_libblock_relink_to_newid(Main *bmain, ID *id)
{
if (ID_IS_LINKED(id)) {
return;
@@ -762,6 +726,8 @@ void BKE_libblock_relink_to_newid_new(Main *bmain, ID *id)
/* We do not want to have those cached relationship data here. */
BLI_assert(bmain->relations == NULL);
- id->tag &= ~LIB_TAG_NEW;
- BKE_library_foreach_ID_link(bmain, id, id_relink_to_newid_looper_new, NULL, 0);
+ BKE_layer_collection_resync_forbid();
+ libblock_relink_to_newid(bmain, id);
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync_remap(bmain);
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 36958e36004..1dba353d8ce 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -57,7 +57,7 @@ static void library_free_data(ID *id)
static void library_foreach_id(ID *id, LibraryForeachIDData *data)
{
Library *lib = (Library *)id;
- BKE_LIB_FOREACHID_PROCESS(data, lib->parent, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lib->parent, IDWALK_CB_NEVER_SELF);
}
IDTypeInfo IDType_ID_LI = {
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index a6150028f46..05e8d4fe978 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -129,7 +129,8 @@ static void light_foreach_id(ID *id, LibraryForeachIDData *data)
Light *lamp = (Light *)id;
if (lamp->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree));
}
}
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 1f4abf36426..57ad6695db4 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -53,8 +53,8 @@ static void lightprobe_foreach_id(ID *id, LibraryForeachIDData *data)
{
LightProbe *probe = (LightProbe *)id;
- BKE_LIB_FOREACHID_PROCESS(data, probe->image, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, probe->visibility_grp, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, probe->image, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, probe->visibility_grp, IDWALK_CB_NOP);
}
static void lightprobe_blend_write(BlendWriter *writer, ID *id, const void *id_address)
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index f4e4dd9f1ab..3c305d1fb3f 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -155,12 +155,14 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data)
for (int i = 0; i < MAX_MTEX; i++) {
if (linestyle->mtex[i]) {
- BKE_texture_mtex_foreach_id(data, linestyle->mtex[i]);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_texture_mtex_foreach_id(data, linestyle->mtex[i]));
}
}
if (linestyle->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree));
}
LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) {
@@ -168,7 +170,7 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data)
LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)
lsm;
if (p->target) {
- BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, p->target, IDWALK_CB_NOP);
}
}
}
@@ -177,7 +179,7 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data)
LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)
lsm;
if (p->target) {
- BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, p->target, IDWALK_CB_NOP);
}
}
}
@@ -186,7 +188,7 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data)
LineStyleThicknessModifier_DistanceFromObject *p =
(LineStyleThicknessModifier_DistanceFromObject *)lsm;
if (p->target) {
- BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, p->target, IDWALK_CB_NOP);
}
}
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 6c57d3139bb..5f726defb1a 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -166,15 +166,14 @@ static void material_foreach_id(ID *id, LibraryForeachIDData *data)
{
Material *material = (Material *)id;
/* Nodetrees **are owned by IDs**, treat them as mere sub-data and not real ID! */
- if (!BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)) {
- return;
- }
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree));
if (material->texpaintslot != NULL) {
- BKE_LIB_FOREACHID_PROCESS(data, material->texpaintslot->ima, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->texpaintslot->ima, IDWALK_CB_NOP);
}
if (material->gp_style != NULL) {
- BKE_LIB_FOREACHID_PROCESS(data, material->gp_style->sima, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, material->gp_style->ima, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->gp_style->sima, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->gp_style->ima, IDWALK_CB_USER);
}
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 6c8664aefed..48d31361eac 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -112,7 +112,7 @@ static void metaball_foreach_id(ID *id, LibraryForeachIDData *data)
{
MetaBall *metaball = (MetaBall *)id;
for (int i = 0; i < metaball->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, metaball->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, metaball->mat[i], IDWALK_CB_USER);
}
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index ed3766ad6a3..7277f7ad209 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -176,10 +176,10 @@ static void mesh_free_data(ID *id)
static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
{
Mesh *mesh = (Mesh *)id;
- BKE_LIB_FOREACHID_PROCESS(data, mesh->texcomesh, IDWALK_CB_NEVER_SELF);
- BKE_LIB_FOREACHID_PROCESS(data, mesh->key, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->texcomesh, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->key, IDWALK_CB_USER);
for (int i = 0; i < mesh->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, mesh->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->mat[i], IDWALK_CB_USER);
}
}
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 7ac4c29f0ee..1c8646a4bdd 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -52,6 +52,8 @@ void BKE_mesh_runtime_reset(Mesh *mesh)
memset(&mesh->runtime, 0, sizeof(mesh->runtime));
mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
BLI_mutex_init(mesh->runtime.eval_mutex);
+ mesh->runtime.render_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime render_mutex");
+ BLI_mutex_init(mesh->runtime.render_mutex);
}
/* Clear all pointers which we don't want to be shared on copying the datablock.
@@ -71,6 +73,9 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
BLI_mutex_init(mesh->runtime.eval_mutex);
+
+ mesh->runtime.render_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime render_mutex");
+ BLI_mutex_init(mesh->runtime.render_mutex);
}
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
@@ -80,6 +85,11 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
MEM_freeN(mesh->runtime.eval_mutex);
mesh->runtime.eval_mutex = NULL;
}
+ if (mesh->runtime.render_mutex != NULL) {
+ BLI_mutex_end(mesh->runtime.render_mutex);
+ MEM_freeN(mesh->runtime.render_mutex);
+ mesh->runtime.render_mutex = NULL;
+ }
if (mesh->runtime.mesh_eval != NULL) {
mesh->runtime.mesh_eval->edit_mesh = NULL;
BKE_id_free(NULL, mesh->runtime.mesh_eval);
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 0c2ac841b87..002f370cdcb 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -132,19 +132,19 @@ static void movie_clip_foreach_id(ID *id, LibraryForeachIDData *data)
MovieClip *movie_clip = (MovieClip *)id;
MovieTracking *tracking = &movie_clip->tracking;
- BKE_LIB_FOREACHID_PROCESS(data, movie_clip->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, movie_clip->gpd, IDWALK_CB_USER);
LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
- BKE_LIB_FOREACHID_PROCESS(data, track->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, track->gpd, IDWALK_CB_USER);
}
LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
LISTBASE_FOREACH (MovieTrackingTrack *, track, &object->tracks) {
- BKE_LIB_FOREACHID_PROCESS(data, track->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, track->gpd, IDWALK_CB_USER);
}
}
LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking->plane_tracks) {
- BKE_LIB_FOREACHID_PROCESS(data, plane_track->image, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, plane_track->image, IDWALK_CB_USER);
}
}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 487e925df79..124db07298d 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -488,14 +488,14 @@ NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
*/
void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
{
- BKE_LIB_FOREACHID_PROCESS(data, strip->act, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, strip->act, IDWALK_CB_USER);
LISTBASE_FOREACH (FCurve *, fcu, &strip->fcurves) {
- BKE_fcurve_foreach_id(fcu, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data));
}
LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) {
- BKE_nla_strip_foreach_id(substrip, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_nla_strip_foreach_id(substrip, data));
}
}
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index eda57d9e984..55e8bdb2483 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -307,34 +307,36 @@ static void ntree_free_data(ID *id)
static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock)
{
- IDP_foreach_property(
- sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(
+ sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data));
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value;
- BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value;
- BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_COLLECTION: {
bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *)
sock->default_value;
- BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_TEXTURE: {
bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value;
- BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_MATERIAL: {
bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value;
- BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_FLOAT:
@@ -355,26 +357,30 @@ static void node_foreach_id(ID *id, LibraryForeachIDData *data)
{
bNodeTree *ntree = (bNodeTree *)id;
- BKE_LIB_FOREACHID_PROCESS(data, ntree->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, ntree->gpd, IDWALK_CB_USER);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
BKE_LIB_FOREACHID_PROCESS_ID(data, node->id, IDWALK_CB_USER);
- IDP_foreach_property(
- node->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(node->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data));
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- library_foreach_node_socket(data, sock);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock));
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
- library_foreach_node_socket(data, sock);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock));
}
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
- library_foreach_node_socket(data, sock);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock));
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
- library_foreach_node_socket(data, sock);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock));
}
}
@@ -4679,7 +4685,7 @@ static OutputFieldDependency find_group_output_dependencies(
while (!sockets_to_check.is_empty()) {
const InputSocketRef *input_socket = sockets_to_check.pop();
- for (const OutputSocketRef *origin_socket : input_socket->logically_linked_sockets()) {
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
const NodeRef &origin_node = origin_socket->node();
const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
@@ -4717,10 +4723,10 @@ static OutputFieldDependency find_group_output_dependencies(
static void propagate_data_requirements_from_right_to_left(
const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
{
- const Vector<const NodeRef *> sorted_nodes = tree.toposort(
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
NodeTreeRef::ToposortDirection::RightToLeft);
- for (const NodeRef *node : sorted_nodes) {
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
*node);
@@ -4829,10 +4835,10 @@ static void determine_group_input_states(
static void propagate_field_status_from_left_to_right(
const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
{
- Vector<const NodeRef *> sorted_nodes = tree.toposort(
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
NodeTreeRef::ToposortDirection::LeftToRight);
- for (const NodeRef *node : sorted_nodes) {
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
if (node->is_group_input_node()) {
continue;
}
@@ -4848,14 +4854,14 @@ static void propagate_field_status_from_left_to_right(
continue;
}
state.is_single = true;
- if (input_socket->logically_linked_sockets().is_empty()) {
+ if (input_socket->directly_linked_sockets().is_empty()) {
if (inferencing_interface.inputs[input_socket->index()] ==
InputSocketFieldType::Implicit) {
state.is_single = false;
}
}
else {
- for (const OutputSocketRef *origin_socket : input_socket->logically_linked_sockets()) {
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
if (!field_state_by_socket_id[origin_socket->id()].is_single) {
state.is_single = false;
break;
@@ -5753,6 +5759,7 @@ static void registerGeometryNodes()
register_node_type_geo_legacy_select_by_handle_type();
register_node_type_geo_legacy_select_by_material();
register_node_type_geo_legacy_subdivision_surface();
+ register_node_type_geo_legacy_volume_to_mesh();
register_node_type_geo_align_rotation_to_vector();
register_node_type_geo_attribute_capture();
@@ -5800,8 +5807,10 @@ static void registerGeometryNodes()
register_node_type_geo_delete_geometry();
register_node_type_geo_distribute_points_on_faces();
register_node_type_geo_edge_split();
+ register_node_type_geo_image_texture();
register_node_type_geo_input_curve_handles();
register_node_type_geo_input_curve_tilt();
+ register_node_type_geo_input_id();
register_node_type_geo_input_index();
register_node_type_geo_input_material_index();
register_node_type_geo_input_material();
@@ -5850,6 +5859,7 @@ static void registerGeometryNodes()
register_node_type_geo_set_curve_handles();
register_node_type_geo_set_curve_radius();
register_node_type_geo_set_curve_tilt();
+ register_node_type_geo_set_id();
register_node_type_geo_set_material_index();
register_node_type_geo_set_material();
register_node_type_geo_set_point_radius();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index e85c6b4c7c5..3b0825fb8db 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -82,6 +82,7 @@
#include "BKE_anim_visualization.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
+#include "BKE_asset.h"
#include "BKE_camera.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
@@ -388,7 +389,8 @@ static void library_foreach_modifiersForeachIDLink(void *user_data,
int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data,
@@ -397,7 +399,8 @@ static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data,
int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
static void library_foreach_shaderfxForeachIDLink(void *user_data,
@@ -406,7 +409,8 @@ static void library_foreach_shaderfxForeachIDLink(void *user_data,
int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con),
@@ -416,7 +420,8 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con),
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys),
@@ -425,7 +430,8 @@ static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(p
int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
static void object_foreach_id(ID *id, LibraryForeachIDData *data)
@@ -452,11 +458,11 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
- BKE_LIB_FOREACHID_PROCESS(data, object->parent, IDWALK_CB_NEVER_SELF);
- BKE_LIB_FOREACHID_PROCESS(data, object->track, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->parent, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->track, IDWALK_CB_NEVER_SELF);
/* object->proxy is refcounted, but not object->proxy_group... *sigh* */
- BKE_LIB_FOREACHID_PROCESS(data, object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF);
- BKE_LIB_FOREACHID_PROCESS(data, object->proxy_group, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->proxy_group, IDWALK_CB_NOP);
/* Special case!
* Since this field is set/owned by 'user' of this ID (and not ID itself),
@@ -468,22 +474,23 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
IDWALK_CB_INDIRECT_USAGE :
0,
true);
- BKE_LIB_FOREACHID_PROCESS(data, object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
+ data, object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true);
}
- BKE_LIB_FOREACHID_PROCESS(data, object->poselib, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->poselib, IDWALK_CB_USER);
for (int i = 0; i < object->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, object->mat[i], proxy_cb_flag | IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->mat[i], proxy_cb_flag | IDWALK_CB_USER);
}
/* Note that ob->gpd is deprecated, so no need to handle it here. */
- BKE_LIB_FOREACHID_PROCESS(data, object->instance_collection, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->instance_collection, IDWALK_CB_USER);
if (object->pd) {
- BKE_LIB_FOREACHID_PROCESS(data, object->pd->tex, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, object->pd->f_source, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->pd->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->pd->f_source, IDWALK_CB_NOP);
}
/* Note that ob->effect is deprecated, so no need to handle it here. */
@@ -491,34 +498,52 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override(
data, proxy_cb_flag, false);
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- IDP_foreach_property(
- pchan->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
- BKE_LIB_FOREACHID_PROCESS(data, pchan->custom, IDWALK_CB_USER);
- BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(pchan->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data));
+
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, pchan->custom, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ BKE_constraints_id_loop(
+ &pchan->constraints, library_foreach_constraintObjectLooper, data));
}
BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true);
}
if (object->rigidbody_constraint) {
- BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF);
- BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF);
- }
-
- BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data);
- BKE_gpencil_modifiers_foreach_ID_link(
- object, library_foreach_gpencil_modifiersForeachIDLink, data);
- BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data);
- BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
+ data, object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
+ data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF);
+ }
+
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data));
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ BKE_gpencil_modifiers_foreach_ID_link(
+ object, library_foreach_gpencil_modifiersForeachIDLink, data));
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data));
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data));
LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
- BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data));
}
if (object->soft) {
- BKE_LIB_FOREACHID_PROCESS(data, object->soft->collision_group, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->soft->collision_group, IDWALK_CB_NOP);
if (object->soft->effector_weights) {
- BKE_LIB_FOREACHID_PROCESS(data, object->soft->effector_weights->group, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
+ data, object->soft->effector_weights->group, IDWALK_CB_NOP);
}
}
}
@@ -1158,8 +1183,10 @@ static void object_lib_override_apply_post(ID *id_dst, ID *id_src)
for (pid_dst = pidlist_dst.first, pid_src = pidlist_src.first; pid_dst != NULL;
pid_dst = pid_dst->next, pid_src = (pid_src != NULL) ? pid_src->next : NULL) {
/* If pid's do not match, just tag info of caches in dst as dirty and continue. */
- if (pid_src == NULL || pid_dst->type != pid_src->type ||
- pid_dst->file_type != pid_src->file_type ||
+ if (pid_src == NULL) {
+ continue;
+ }
+ if (pid_dst->type != pid_src->type || pid_dst->file_type != pid_src->file_type ||
pid_dst->default_step != pid_src->default_step || pid_dst->max_step != pid_src->max_step ||
pid_dst->data_types != pid_src->data_types || pid_dst->info_types != pid_src->info_types) {
LISTBASE_FOREACH (PointCache *, point_cache_src, pid_src->ptcaches) {
@@ -1190,6 +1217,40 @@ static void object_lib_override_apply_post(ID *id_dst, ID *id_src)
BLI_freelistN(&pidlist_src);
}
+static IDProperty *object_asset_dimensions_property(Object *ob)
+{
+ float dimensions[3];
+ BKE_object_dimensions_get(ob, dimensions);
+ if (is_zero_v3(dimensions)) {
+ return NULL;
+ }
+
+ IDPropertyTemplate idprop = {0};
+ idprop.array.len = ARRAY_SIZE(dimensions);
+ idprop.array.type = IDP_FLOAT;
+
+ IDProperty *property = IDP_New(IDP_ARRAY, &idprop, "dimensions");
+ memcpy(IDP_Array(property), dimensions, sizeof(dimensions));
+
+ return property;
+}
+
+static void object_asset_pre_save(void *asset_ptr, struct AssetMetaData *asset_data)
+{
+ Object *ob = asset_ptr;
+ BLI_assert(GS(ob->id.name) == ID_OB);
+
+ /* Update dimensions hint for the asset. */
+ IDProperty *dimensions_prop = object_asset_dimensions_property(ob);
+ if (dimensions_prop) {
+ BKE_asset_metadata_idprop_ensure(asset_data, dimensions_prop);
+ }
+}
+
+AssetTypeInfo AssetType_OB = {
+ .pre_save_fn = object_asset_pre_save,
+};
+
IDTypeInfo IDType_ID_OB = {
.id_code = ID_OB,
.id_filter = FILTER_ID_OB,
@@ -1216,6 +1277,8 @@ IDTypeInfo IDType_ID_OB = {
.blend_read_undo_preserve = NULL,
.lib_override_apply_post = object_lib_override_apply_post,
+
+ .asset_type_info = &AssetType_OB,
};
void BKE_object_workob_clear(Object *workob)
@@ -2815,7 +2878,7 @@ Object *BKE_object_duplicate(Main *bmain,
if (!is_subprocess) {
/* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */
- BKE_libblock_relink_to_newid(&obn->id);
+ BKE_libblock_relink_to_newid(bmain, &obn->id);
#ifndef NDEBUG
/* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 7b2a1af7086..5b62761bd91 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -173,28 +173,29 @@ static void particle_settings_free_data(ID *id)
static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data)
{
ParticleSettings *psett = (ParticleSettings *)id;
- BKE_LIB_FOREACHID_PROCESS(data, psett->instance_collection, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, psett->instance_object, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, psett->bb_ob, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, psett->collision_group, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->instance_collection, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->instance_object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->bb_ob, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->collision_group, IDWALK_CB_NOP);
for (int i = 0; i < MAX_MTEX; i++) {
if (psett->mtex[i]) {
- BKE_texture_mtex_foreach_id(data, psett->mtex[i]);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
+ BKE_texture_mtex_foreach_id(data, psett->mtex[i]));
}
}
if (psett->effector_weights) {
- BKE_LIB_FOREACHID_PROCESS(data, psett->effector_weights->group, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->effector_weights->group, IDWALK_CB_NOP);
}
if (psett->pd) {
- BKE_LIB_FOREACHID_PROCESS(data, psett->pd->tex, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, psett->pd->f_source, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->pd->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->pd->f_source, IDWALK_CB_NOP);
}
if (psett->pd2) {
- BKE_LIB_FOREACHID_PROCESS(data, psett->pd2->tex, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, psett->pd2->f_source, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->pd2->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->pd2->f_source, IDWALK_CB_NOP);
}
if (psett->boids) {
@@ -202,18 +203,18 @@ static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data)
LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
if (rule->type == eBoidRuleType_Avoid) {
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- BKE_LIB_FOREACHID_PROCESS(data, gabr->ob, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, gabr->ob, IDWALK_CB_NOP);
}
else if (rule->type == eBoidRuleType_FollowLeader) {
BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- BKE_LIB_FOREACHID_PROCESS(data, flbr->ob, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, flbr->ob, IDWALK_CB_NOP);
}
}
}
}
LISTBASE_FOREACH (ParticleDupliWeight *, dw, &psett->instance_weights) {
- BKE_LIB_FOREACHID_PROCESS(data, dw->ob, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, dw->ob, IDWALK_CB_NOP);
}
}
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 1db14dc3dc8..15c5a809118 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -105,7 +105,7 @@ static void pointcloud_foreach_id(ID *id, LibraryForeachIDData *data)
{
PointCloud *pointcloud = (PointCloud *)id;
for (int i = 0; i < pointcloud->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, pointcloud->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, pointcloud->mat[i], IDWALK_CB_USER);
}
}
diff --git a/source/blender/blenkernel/intern/preferences.c b/source/blender/blenkernel/intern/preferences.c
index 0b8e8d7c311..79a8b591f72 100644
--- a/source/blender/blenkernel/intern/preferences.c
+++ b/source/blender/blenkernel/intern/preferences.c
@@ -120,7 +120,8 @@ void BKE_preferences_asset_library_default_add(UserDef *userdef)
return;
}
- bUserAssetLibrary *library = BKE_preferences_asset_library_add(userdef, DATA_("Default"), NULL);
+ bUserAssetLibrary *library = BKE_preferences_asset_library_add(
+ userdef, BKE_PREFS_ASSET_LIBRARY_DEFAULT_NAME, NULL);
/* Add new "Default" library under '[doc_path]/Blender/Assets'. */
BLI_path_join(
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 2cb0213a192..a827e1c32a2 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -471,7 +471,8 @@ static void scene_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSE
int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
/**
@@ -522,7 +523,10 @@ static void scene_foreach_toolsettings_id_pointer_process(
}
}
-#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS( \
+/* Special handling is needed here, as `scene_foreach_toolsettings` (and its dependency
+ * `scene_foreach_paint`) are also used by `scene_undo_preserve`, where `LibraryForeachIDData
+ * *data` is NULL. */
+#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER( \
__data, __id, __do_undo_restore, __action, __reader, __id_old, __cb_flag) \
{ \
if (__do_undo_restore) { \
@@ -530,7 +534,21 @@ static void scene_foreach_toolsettings_id_pointer_process(
(ID **)&(__id), __action, __reader, (ID **)&(__id_old), __cb_flag); \
} \
else { \
- BKE_LIB_FOREACHID_PROCESS(__data, __id, __cb_flag); \
+ BLI_assert((__data) != NULL); \
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(__data, __id, __cb_flag); \
+ } \
+ } \
+ (void)0
+
+#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( \
+ __data, __do_undo_restore, __func_call) \
+ { \
+ if (__do_undo_restore) { \
+ __func_call; \
+ } \
+ else { \
+ BLI_assert((__data) != NULL); \
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(__data, __func_call); \
} \
} \
(void)0
@@ -541,13 +559,13 @@ static void scene_foreach_paint(LibraryForeachIDData *data,
BlendLibReader *reader,
Paint *paint_old)
{
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- paint->brush,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- paint_old->brush,
- IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ paint->brush,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ paint_old->brush,
+ IDWALK_CB_USER);
for (int i = 0; i < paint_old->tool_slots_len; i++) {
/* This is a bit tricky.
* - In case we do not do `undo_restore`, `paint` and `paint_old` pointers are the same, so
@@ -559,21 +577,21 @@ static void scene_foreach_paint(LibraryForeachIDData *data,
*/
Brush *brush_tmp = NULL;
Brush **brush_p = i < paint->tool_slots_len ? &paint->tool_slots[i].brush : &brush_tmp;
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- *brush_p,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- paint_old->brush,
- IDWALK_CB_USER);
- }
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- paint->palette,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- paint_old->palette,
- IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ *brush_p,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ paint_old->brush,
+ IDWALK_CB_USER);
+ }
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ paint->palette,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ paint_old->palette,
+ IDWALK_CB_USER);
}
static void scene_foreach_toolsettings(LibraryForeachIDData *data,
@@ -582,110 +600,152 @@ static void scene_foreach_toolsettings(LibraryForeachIDData *data,
BlendLibReader *reader,
ToolSettings *toolsett_old)
{
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->particle.scene,
- do_undo_restore,
- SCENE_FOREACH_UNDO_NO_RESTORE,
- reader,
- toolsett_old->particle.scene,
- IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->particle.object,
- do_undo_restore,
- SCENE_FOREACH_UNDO_NO_RESTORE,
- reader,
- toolsett_old->particle.object,
- IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->particle.shape_object,
- do_undo_restore,
- SCENE_FOREACH_UNDO_NO_RESTORE,
- reader,
- toolsett_old->particle.shape_object,
- IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->particle.scene,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_NO_RESTORE,
+ reader,
+ toolsett_old->particle.scene,
+ IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->particle.object,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_NO_RESTORE,
+ reader,
+ toolsett_old->particle.object,
+ IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->particle.shape_object,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_NO_RESTORE,
+ reader,
+ toolsett_old->particle.shape_object,
+ IDWALK_CB_NOP);
scene_foreach_paint(
data, &toolsett->imapaint.paint, do_undo_restore, reader, &toolsett_old->imapaint.paint);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->imapaint.stencil,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- toolsett_old->imapaint.stencil,
- IDWALK_CB_USER);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->imapaint.clone,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- toolsett_old->imapaint.clone,
- IDWALK_CB_USER);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->imapaint.canvas,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- toolsett_old->imapaint.canvas,
- IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->imapaint.stencil,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ toolsett_old->imapaint.stencil,
+ IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->imapaint.clone,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ toolsett_old->imapaint.clone,
+ IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->imapaint.canvas,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ toolsett_old->imapaint.canvas,
+ IDWALK_CB_USER);
if (toolsett->vpaint) {
- scene_foreach_paint(
- data, &toolsett->vpaint->paint, do_undo_restore, reader, &toolsett_old->vpaint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->vpaint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->vpaint->paint));
}
if (toolsett->wpaint) {
- scene_foreach_paint(
- data, &toolsett->wpaint->paint, do_undo_restore, reader, &toolsett_old->wpaint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->wpaint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->wpaint->paint));
}
if (toolsett->sculpt) {
- scene_foreach_paint(
- data, &toolsett->sculpt->paint, do_undo_restore, reader, &toolsett_old->sculpt->paint);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->sculpt->gravity_object,
- do_undo_restore,
- SCENE_FOREACH_UNDO_NO_RESTORE,
- reader,
- toolsett_old->sculpt->gravity_object,
- IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->sculpt->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->sculpt->paint));
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->sculpt->gravity_object,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_NO_RESTORE,
+ reader,
+ toolsett_old->sculpt->gravity_object,
+ IDWALK_CB_NOP);
}
if (toolsett->uvsculpt) {
- scene_foreach_paint(
- data, &toolsett->uvsculpt->paint, do_undo_restore, reader, &toolsett_old->uvsculpt->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->uvsculpt->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->uvsculpt->paint));
}
if (toolsett->gp_paint) {
- scene_foreach_paint(
- data, &toolsett->gp_paint->paint, do_undo_restore, reader, &toolsett_old->gp_paint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->gp_paint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->gp_paint->paint));
}
if (toolsett->gp_vertexpaint) {
- scene_foreach_paint(data,
- &toolsett->gp_vertexpaint->paint,
- do_undo_restore,
- reader,
- &toolsett_old->gp_vertexpaint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->gp_vertexpaint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->gp_vertexpaint->paint));
}
if (toolsett->gp_sculptpaint) {
- scene_foreach_paint(data,
- &toolsett->gp_sculptpaint->paint,
- do_undo_restore,
- reader,
- &toolsett_old->gp_sculptpaint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->gp_sculptpaint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->gp_sculptpaint->paint));
}
if (toolsett->gp_weightpaint) {
- scene_foreach_paint(data,
- &toolsett->gp_weightpaint->paint,
- do_undo_restore,
- reader,
- &toolsett_old->gp_weightpaint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->gp_weightpaint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->gp_weightpaint->paint));
}
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->gp_sculpt.guide.reference_object,
- do_undo_restore,
- SCENE_FOREACH_UNDO_NO_RESTORE,
- reader,
- toolsett_old->gp_sculpt.guide.reference_object,
- IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->gp_sculpt.guide.reference_object,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_NO_RESTORE,
+ reader,
+ toolsett_old->gp_sculpt.guide.reference_object,
+ IDWALK_CB_NOP);
}
+#undef BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER
+#undef BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL
+
static void scene_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb)
{
LISTBASE_FOREACH (LayerCollection *, lc, lb) {
@@ -695,7 +755,7 @@ static void scene_foreach_layer_collection(LibraryForeachIDData *data, ListBase
(lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
IDWALK_CB_EMBEDDED :
IDWALK_CB_NOP;
- BKE_LIB_FOREACHID_PROCESS(data, lc->collection, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lc->collection, cb_flag);
scene_foreach_layer_collection(data, &lc->layer_collections);
}
}
@@ -704,32 +764,33 @@ static bool seq_foreach_member_id_cb(Sequence *seq, void *user_data)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
-#define FOREACHID_PROCESS(_data, _id_super, _cb_flag) \
+#define FOREACHID_PROCESS_IDSUPER(_data, _id_super, _cb_flag) \
{ \
CHECK_TYPE(&((_id_super)->id), ID *); \
- if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \
+ BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag)); \
+ if (!BKE_lib_query_foreachid_iter_stop((_data))) { \
return false; \
} \
} \
((void)0)
- FOREACHID_PROCESS(data, seq->scene, IDWALK_CB_NEVER_SELF);
- FOREACHID_PROCESS(data, seq->scene_camera, IDWALK_CB_NOP);
- FOREACHID_PROCESS(data, seq->clip, IDWALK_CB_USER);
- FOREACHID_PROCESS(data, seq->mask, IDWALK_CB_USER);
- FOREACHID_PROCESS(data, seq->sound, IDWALK_CB_USER);
+ FOREACHID_PROCESS_IDSUPER(data, seq->scene, IDWALK_CB_NEVER_SELF);
+ FOREACHID_PROCESS_IDSUPER(data, seq->scene_camera, IDWALK_CB_NOP);
+ FOREACHID_PROCESS_IDSUPER(data, seq->clip, IDWALK_CB_USER);
+ FOREACHID_PROCESS_IDSUPER(data, seq->mask, IDWALK_CB_USER);
+ FOREACHID_PROCESS_IDSUPER(data, seq->sound, IDWALK_CB_USER);
IDP_foreach_property(
seq->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) {
- FOREACHID_PROCESS(data, smd->mask_id, IDWALK_CB_USER);
+ FOREACHID_PROCESS_IDSUPER(data, smd->mask_id, IDWALK_CB_USER);
}
if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
TextVars *text_data = seq->effectdata;
- FOREACHID_PROCESS(data, text_data->text_font, IDWALK_CB_USER);
+ FOREACHID_PROCESS_IDSUPER(data, text_data->text_font, IDWALK_CB_USER);
}
-#undef FOREACHID_PROCESS
+#undef FOREACHID_PROCESS_IDSUPER
return true;
}
@@ -738,66 +799,77 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data)
{
Scene *scene = (Scene *)id;
- BKE_LIB_FOREACHID_PROCESS(data, scene->camera, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, scene->world, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, scene->set, IDWALK_CB_NEVER_SELF);
- BKE_LIB_FOREACHID_PROCESS(data, scene->clip, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, scene->gpd, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, scene->r.bake.cage_object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->world, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->set, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->clip, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->r.bake.cage_object, IDWALK_CB_NOP);
if (scene->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree));
}
if (scene->ed) {
- SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_member_id_cb, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_member_id_cb, data));
}
/* This pointer can be NULL during old files reading, better be safe than sorry. */
if (scene->master_collection != NULL) {
- BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection));
}
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- BKE_LIB_FOREACHID_PROCESS(data, view_layer->mat_override, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, view_layer->mat_override, IDWALK_CB_USER);
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
- BKE_LIB_FOREACHID_PROCESS(
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, base->object, IDWALK_CB_NOP | IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE);
}
- scene_foreach_layer_collection(data, &view_layer->layer_collections);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, scene_foreach_layer_collection(data, &view_layer->layer_collections));
LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) {
if (fmc->script) {
- BKE_LIB_FOREACHID_PROCESS(data, fmc->script, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fmc->script, IDWALK_CB_NOP);
}
}
LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
if (fls->group) {
- BKE_LIB_FOREACHID_PROCESS(data, fls->group, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fls->group, IDWALK_CB_USER);
}
if (fls->linestyle) {
- BKE_LIB_FOREACHID_PROCESS(data, fls->linestyle, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fls->linestyle, IDWALK_CB_USER);
}
}
}
LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
- BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP);
- IDP_foreach_property(
- marker->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, marker->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(marker->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data));
}
ToolSettings *toolsett = scene->toolsettings;
if (toolsett) {
- scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett));
}
if (scene->rigidbody_world) {
- BKE_rigidbody_world_id_loop(
- scene->rigidbody_world, scene_foreach_rigidbodyworldSceneLooper, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ BKE_rigidbody_world_id_loop(
+ scene->rigidbody_world, scene_foreach_rigidbodyworldSceneLooper, data));
}
}
@@ -1853,7 +1925,7 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
if (!is_subprocess) {
/* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */
- BKE_libblock_relink_to_newid(&sce_copy->id);
+ BKE_libblock_relink_to_newid(bmain, &sce_copy->id);
#ifndef NDEBUG
/* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 0474c2b81cb..69e926caeae 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -93,13 +93,17 @@ static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet *
{
if (ads != NULL) {
BKE_LIB_FOREACHID_PROCESS_ID(data, ads->source, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, ads->filter_grp, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, ads->filter_grp, IDWALK_CB_NOP);
}
}
+/**
+ * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
+ * `IDTypeInfo` structure).
+ */
void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area)
{
- BKE_LIB_FOREACHID_PROCESS(data, area->full, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, area->full, IDWALK_CB_NOP);
/* TODO: this should be moved to a callback in `SpaceType`, defined in each editor's own code.
* Will be for a later round of cleanup though... */
@@ -107,24 +111,21 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
switch (sl->spacetype) {
case SPACE_VIEW3D: {
View3D *v3d = (View3D *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, v3d->camera, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, v3d->ob_center, IDWALK_CB_NOP);
-
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->ob_center, IDWALK_CB_NOP);
if (v3d->localvd) {
- BKE_LIB_FOREACHID_PROCESS(data, v3d->localvd->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->localvd->camera, IDWALK_CB_NOP);
}
break;
}
case SPACE_GRAPH: {
SpaceGraph *sipo = (SpaceGraph *)sl;
-
- screen_foreach_id_dopesheet(data, sipo->ads);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
+ screen_foreach_id_dopesheet(data, sipo->ads));
break;
}
case SPACE_PROPERTIES: {
SpaceProperties *sbuts = (SpaceProperties *)sl;
-
BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP);
break;
}
@@ -132,48 +133,41 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
break;
case SPACE_ACTION: {
SpaceAction *saction = (SpaceAction *)sl;
-
screen_foreach_id_dopesheet(data, &saction->ads);
- BKE_LIB_FOREACHID_PROCESS(data, saction->action, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, saction->action, IDWALK_CB_NOP);
break;
}
case SPACE_IMAGE: {
SpaceImage *sima = (SpaceImage *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, sima->image, IDWALK_CB_USER_ONE);
- BKE_LIB_FOREACHID_PROCESS(data, sima->mask_info.mask, IDWALK_CB_USER_ONE);
- BKE_LIB_FOREACHID_PROCESS(data, sima->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->image, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->mask_info.mask, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->gpd, IDWALK_CB_USER);
break;
}
case SPACE_SEQ: {
SpaceSeq *sseq = (SpaceSeq *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, sseq->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sseq->gpd, IDWALK_CB_USER);
break;
}
case SPACE_NLA: {
SpaceNla *snla = (SpaceNla *)sl;
-
- screen_foreach_id_dopesheet(data, snla->ads);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
+ screen_foreach_id_dopesheet(data, snla->ads));
break;
}
case SPACE_TEXT: {
SpaceText *st = (SpaceText *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, st->text, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, st->text, IDWALK_CB_NOP);
break;
}
case SPACE_SCRIPT: {
SpaceScript *scpt = (SpaceScript *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, scpt->script, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scpt->script, IDWALK_CB_NOP);
break;
}
case SPACE_OUTLINER: {
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
-
BKE_LIB_FOREACHID_PROCESS_ID(data, space_outliner->search_tse.id, IDWALK_CB_NOP);
-
if (space_outliner->treestore != NULL) {
TreeStoreElem *tselem;
BLI_mempool_iter iter;
@@ -187,26 +181,24 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
}
case SPACE_NODE: {
SpaceNode *snode = (SpaceNode *)sl;
-
const bool is_private_nodetree = snode->id != NULL &&
ntreeFromID(snode->id) == snode->nodetree;
BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP);
-
- BKE_LIB_FOREACHID_PROCESS(
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE);
LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
if (path == snode->treepath.first) {
/* first nodetree in path is same as snode->nodetree */
- BKE_LIB_FOREACHID_PROCESS(data,
- path->nodetree,
- is_private_nodetree ? IDWALK_CB_EMBEDDED :
- IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data,
+ path->nodetree,
+ is_private_nodetree ? IDWALK_CB_EMBEDDED :
+ IDWALK_CB_USER_ONE);
}
else {
- BKE_LIB_FOREACHID_PROCESS(data, path->nodetree, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, path->nodetree, IDWALK_CB_USER_ONE);
}
if (path->nodetree == NULL) {
@@ -214,22 +206,20 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
}
}
- BKE_LIB_FOREACHID_PROCESS(data, snode->edittree, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, snode->edittree, IDWALK_CB_NOP);
break;
}
case SPACE_CLIP: {
SpaceClip *sclip = (SpaceClip *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, sclip->clip, IDWALK_CB_USER_ONE);
- BKE_LIB_FOREACHID_PROCESS(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->clip, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
break;
}
case SPACE_SPREADSHEET: {
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
-
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
- BKE_LIB_FOREACHID_PROCESS(
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, ((SpreadsheetContextObject *)context)->object, IDWALK_CB_NOP);
}
}
@@ -243,12 +233,13 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
static void screen_foreach_id(ID *id, LibraryForeachIDData *data)
{
- if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
- bScreen *screen = (bScreen *)id;
+ if ((BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) == 0) {
+ return;
+ }
+ bScreen *screen = (bScreen *)id;
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- BKE_screen_foreach_id_screen_area(data, area);
- }
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_screen_foreach_id_screen_area(data, area));
}
}
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 1d297b3ced9..98e7405bde6 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -103,7 +103,8 @@ static void simulation_foreach_id(ID *id, LibraryForeachIDData *data)
Simulation *simulation = (Simulation *)id;
if (simulation->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree));
}
}
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index b361f31cc30..230ff9d6da0 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -50,7 +50,7 @@ static void speaker_foreach_id(ID *id, LibraryForeachIDData *data)
{
Speaker *speaker = (Speaker *)id;
- BKE_LIB_FOREACHID_PROCESS(data, speaker->sound, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, speaker->sound, IDWALK_CB_USER);
}
static void speaker_blend_write(BlendWriter *writer, ID *id, const void *id_address)
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index 663c1951ba3..bbe4e0aab7b 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -486,6 +486,12 @@ Array<float> Spline::sample_uniform_index_factors(const int samples_size) const
prev_length = length;
}
+ /* Zero lengths or float innacuracies can cause invalid values, or simply
+ * skip some, so set the values that weren't completed in the main loop. */
+ for (const int i : IndexRange(i_sample, samples_size - i_sample)) {
+ samples[i] = float(samples_size);
+ }
+
if (!is_cyclic_) {
/* In rare cases this can prevent overflow of the stored index. */
samples.last() = lengths.size();
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index d5f7647f07a..0811e6cb675 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -142,9 +142,10 @@ static void texture_foreach_id(ID *id, LibraryForeachIDData *data)
Tex *texture = (Tex *)id;
if (texture->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree));
}
- BKE_LIB_FOREACHID_PROCESS(data, texture->ima, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, texture->ima, IDWALK_CB_USER);
}
static void texture_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -233,8 +234,8 @@ IDTypeInfo IDType_ID_TE = {
/* Utils for all IDs using those texture slots. */
void BKE_texture_mtex_foreach_id(LibraryForeachIDData *data, MTex *mtex)
{
- BKE_LIB_FOREACHID_PROCESS(data, mtex->object, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, mtex->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mtex->object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mtex->tex, IDWALK_CB_USER);
}
/* ****************** Mapping ******************* */
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 0b9ef5c537d..a72b5268e1d 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -36,6 +36,7 @@
#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
@@ -71,6 +72,7 @@ static CLG_LogRef LOG = {"bke.volume"};
using blender::float3;
using blender::float4x4;
using blender::IndexRange;
+using blender::StringRef;
#ifdef WITH_OPENVDB
# include <atomic>
@@ -556,7 +558,7 @@ static void volume_foreach_id(ID *id, LibraryForeachIDData *data)
{
Volume *volume = (Volume *)id;
for (int i = 0; i < volume->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, volume->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, volume->mat[i], IDWALK_CB_USER);
}
}
@@ -1451,6 +1453,21 @@ VolumeGrid *BKE_volume_grid_add(Volume *volume, const char *name, VolumeGridType
#endif
}
+#ifdef WITH_OPENVDB
+VolumeGrid *BKE_volume_grid_add_vdb(Volume &volume,
+ const StringRef name,
+ openvdb::GridBase::Ptr vdb_grid)
+{
+ VolumeGridVector &grids = *volume.runtime.grids;
+ BLI_assert(BKE_volume_grid_find_for_read(&volume, name.data()) == nullptr);
+ BLI_assert(BKE_volume_grid_type_openvdb(*vdb_grid) != VOLUME_GRID_UNKNOWN);
+
+ vdb_grid->setName(name);
+ grids.emplace_back(vdb_grid);
+ return &grids.back();
+}
+#endif
+
void BKE_volume_grid_remove(Volume *volume, VolumeGrid *grid)
{
#ifdef WITH_OPENVDB
diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc
index e9d6eea4614..6e465b2fdf0 100644
--- a/source/blender/blenkernel/intern/volume_to_mesh.cc
+++ b/source/blender/blenkernel/intern/volume_to_mesh.cc
@@ -121,46 +121,66 @@ struct VolumeToMeshOp {
}
};
-static Mesh *new_mesh_from_openvdb_data(Span<openvdb::Vec3s> verts,
- Span<openvdb::Vec3I> tris,
- Span<openvdb::Vec4I> quads)
+/**
+ * Convert mesh data from the format provided by OpenVDB into Blender's #Mesh data structure.
+ * This can be used to add mesh data from a grid into an existing mesh rather than merging multiple
+ * meshes later on.
+ */
+void fill_mesh_from_openvdb_data(const Span<openvdb::Vec3s> vdb_verts,
+ const Span<openvdb::Vec3I> vdb_tris,
+ const Span<openvdb::Vec4I> vdb_quads,
+ const int vert_offset,
+ const int poly_offset,
+ const int loop_offset,
+ MutableSpan<MVert> verts,
+ MutableSpan<MPoly> polys,
+ MutableSpan<MLoop> loops)
{
- const int tot_loops = 3 * tris.size() + 4 * quads.size();
- const int tot_polys = tris.size() + quads.size();
-
- Mesh *mesh = BKE_mesh_new_nomain(verts.size(), 0, 0, tot_loops, tot_polys);
-
/* Write vertices. */
- for (const int i : verts.index_range()) {
- const blender::float3 co = blender::float3(verts[i].asV());
- copy_v3_v3(mesh->mvert[i].co, co);
+ for (const int i : vdb_verts.index_range()) {
+ const blender::float3 co = blender::float3(vdb_verts[i].asV());
+ copy_v3_v3(verts[vert_offset + i].co, co);
}
/* Write triangles. */
- for (const int i : tris.index_range()) {
- mesh->mpoly[i].loopstart = 3 * i;
- mesh->mpoly[i].totloop = 3;
+ for (const int i : vdb_tris.index_range()) {
+ polys[poly_offset + i].loopstart = loop_offset + 3 * i;
+ polys[poly_offset + i].totloop = 3;
for (int j = 0; j < 3; j++) {
/* Reverse vertex order to get correct normals. */
- mesh->mloop[3 * i + j].v = tris[i][2 - j];
+ loops[loop_offset + 3 * i + j].v = vert_offset + vdb_tris[i][2 - j];
}
}
/* Write quads. */
- const int poly_offset = tris.size();
- const int loop_offset = tris.size() * 3;
- for (const int i : quads.index_range()) {
- mesh->mpoly[poly_offset + i].loopstart = loop_offset + 4 * i;
- mesh->mpoly[poly_offset + i].totloop = 4;
+ const int quad_offset = poly_offset + vdb_tris.size();
+ const int quad_loop_offset = loop_offset + vdb_tris.size() * 3;
+ for (const int i : vdb_quads.index_range()) {
+ polys[quad_offset + i].loopstart = quad_loop_offset + 4 * i;
+ polys[quad_offset + i].totloop = 4;
for (int j = 0; j < 4; j++) {
/* Reverse vertex order to get correct normals. */
- mesh->mloop[loop_offset + 4 * i + j].v = quads[i][3 - j];
+ loops[quad_loop_offset + 4 * i + j].v = vert_offset + vdb_quads[i][3 - j];
}
}
+}
- BKE_mesh_calc_edges(mesh, false, false);
- BKE_mesh_normals_tag_dirty(mesh);
- return mesh;
+/**
+ * Convert an OpenVDB volume grid to corresponding mesh data: vertex positions and quad and
+ * triangle indices.
+ */
+bke::OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid,
+ const VolumeToMeshResolution &resolution,
+ const float threshold,
+ const float adaptivity)
+{
+ const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid);
+
+ VolumeToMeshOp to_mesh_op{grid, resolution, threshold, adaptivity};
+ if (!BKE_volume_grid_type_operation(grid_type, to_mesh_op)) {
+ return {};
+ }
+ return {std::move(to_mesh_op.verts), std::move(to_mesh_op.tris), std::move(to_mesh_op.quads)};
}
Mesh *volume_to_mesh(const openvdb::GridBase &grid,
@@ -168,14 +188,27 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid,
const float threshold,
const float adaptivity)
{
- const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid);
+ const bke::OpenVDBMeshData mesh_data = volume_to_mesh_data(
+ grid, resolution, threshold, adaptivity);
+
+ const int tot_loops = 3 * mesh_data.tris.size() + 4 * mesh_data.quads.size();
+ const int tot_polys = mesh_data.tris.size() + mesh_data.quads.size();
+ Mesh *mesh = BKE_mesh_new_nomain(mesh_data.verts.size(), 0, 0, tot_loops, tot_polys);
+
+ fill_mesh_from_openvdb_data(mesh_data.verts,
+ mesh_data.tris,
+ mesh_data.quads,
+ 0,
+ 0,
+ 0,
+ {mesh->mvert, mesh->totvert},
+ {mesh->mpoly, mesh->totpoly},
+ {mesh->mloop, mesh->totloop});
- VolumeToMeshOp to_mesh_op{grid, resolution, threshold, adaptivity};
- if (!BKE_volume_grid_type_operation(grid_type, to_mesh_op)) {
- return nullptr;
- }
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_normals_tag_dirty(mesh);
- return new_mesh_from_openvdb_data(to_mesh_op.verts, to_mesh_op.tris, to_mesh_op.quads);
+ return mesh;
}
#endif /* WITH_OPENVDB */
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 3c168a6c7b2..6269cfc4349 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -82,7 +82,7 @@ static void workspace_foreach_id(ID *id, LibraryForeachIDData *data)
WorkSpace *workspace = (WorkSpace *)id;
LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
- BKE_LIB_FOREACHID_PROCESS(data, layout->screen, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, layout->screen, IDWALK_CB_USER);
}
}
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index fe03c5b817a..2f0a282a298 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -131,7 +131,8 @@ static void world_foreach_id(ID *id, LibraryForeachIDData *data)
if (world->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree));
}
}
diff --git a/source/blender/blenlib/BLI_serialize.hh b/source/blender/blenlib/BLI_serialize.hh
new file mode 100644
index 00000000000..7b8aa03b807
--- /dev/null
+++ b/source/blender/blenlib/BLI_serialize.hh
@@ -0,0 +1,329 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ *
+ * An abstraction layer for serialization formats.
+ *
+ * Allowing to read/write data to a serialization format like JSON.
+ *
+ *
+ *
+ * # Supported data types
+ *
+ * The abstraction layer has a limited set of data types it supports.
+ * There are specific classes that builds up the data structure that
+ * can be (de)serialized.
+ *
+ * - StringValue: for strings
+ * - IntValue: for integer values
+ * - DoubleValue: for double precision floating point numbers
+ * - BooleanValue: for boolean values
+ * - ArrayValue: An array of any supported value.
+ * - ObjectValue: A key value pair where keys are std::string.
+ * - NullValue: for null values.
+ *
+ * # Basic usage
+ *
+ * ## Serializing
+ *
+ * - Construct a structure that needs to be serialized using the `*Value` classes.
+ * - Construct the formatter you want to use
+ * - Invoke the formatter.serialize method passing an output stream and the value.
+ *
+ * The next example would format an integer value (42) as JSON the result will
+ * be stored inside `out`.
+ *
+ * \code{.cc}
+ * JsonFormatter json;
+ * std::stringstream out;
+ * IntValue test_value(42);
+ * json.serialize(out, test_value);
+ * \endcode
+ *
+ * ## Deserializing
+ *
+ * \code{.cc}
+ * std::stringstream is("42");
+ * JsonFormatter json;
+ * std::unique_ptr<Value> value = json.deserialize(is);
+ * \endcode
+ *
+ * # Adding a new formatter
+ *
+ * To add a new formatter a new sub-class of `Formatter` must be created and the
+ * `serialize`/`deserialize` methods should be implemented.
+ *
+ */
+
+#include <ostream>
+
+#include "BLI_map.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+namespace blender::io::serialize {
+
+/**
+ * Enumeration containing all sub-classes of Value. It is used as for type checking.
+ *
+ * \see #Value::type()
+ */
+enum class eValueType {
+ String,
+ Int,
+ Array,
+ Null,
+ Boolean,
+ Double,
+ Object,
+};
+
+class Value;
+class StringValue;
+class ObjectValue;
+template<typename T, eValueType V> class PrimitiveValue;
+using IntValue = PrimitiveValue<int64_t, eValueType::Int>;
+using DoubleValue = PrimitiveValue<double, eValueType::Double>;
+using BooleanValue = PrimitiveValue<bool, eValueType::Boolean>;
+
+template<typename Container, typename ContainerItem, eValueType V> class ContainerValue;
+/* ArrayValue stores its items as shared pointer as it shares data with a lookup table that can
+ * be created by calling `create_lookup`. */
+using ArrayValue =
+ ContainerValue<Vector<std::shared_ptr<Value>>, std::shared_ptr<Value>, eValueType::Array>;
+
+/**
+ * Class containing a (de)serializable value.
+ *
+ * To serialize from or to a specific format the Value will be used as an intermediate container
+ * holding the values. Value class is abstract. There are concrete classes to for different data
+ * types.
+ *
+ * - `StringValue`: contains a string.
+ * - `IntValue`: contains an integer.
+ * - `ArrayValue`: contains an array of elements. Elements don't need to be the same type.
+ * - `NullValue`: represents nothing (null pointer or optional).
+ * - `BooleanValue`: contains a boolean (true/false).
+ * - `DoubleValue`: contains a double precision floating point number.
+ * - `ObjectValue`: represents an object (key value pairs where keys are strings and values can be
+ * of different types.
+ *
+ */
+class Value {
+ private:
+ eValueType type_;
+
+ protected:
+ Value() = delete;
+ explicit Value(eValueType type) : type_(type)
+ {
+ }
+
+ public:
+ virtual ~Value() = default;
+ const eValueType type() const
+ {
+ return type_;
+ }
+
+ /**
+ * Casts to a StringValue.
+ * Will return nullptr when it is a different type.
+ */
+ const StringValue *as_string_value() const;
+
+ /**
+ * Casts to an IntValue.
+ * Will return nullptr when it is a different type.
+ */
+ const IntValue *as_int_value() const;
+
+ /**
+ * Casts to a DoubleValue.
+ * Will return nullptr when it is a different type.
+ */
+ const DoubleValue *as_double_value() const;
+
+ /**
+ * Casts to a BooleanValue.
+ * Will return nullptr when it is a different type.
+ */
+ const BooleanValue *as_boolean_value() const;
+
+ /**
+ * Casts to an ArrayValue.
+ * Will return nullptr when it is a different type.
+ */
+ const ArrayValue *as_array_value() const;
+
+ /**
+ * Casts to an ObjectValue.
+ * Will return nullptr when it is a different type.
+ */
+ const ObjectValue *as_object_value() const;
+};
+
+/**
+ * For generating value types that represent types that are typically known processor data types.
+ */
+template<
+ /** Wrapped c/cpp data type that is used to store the value. */
+ typename T,
+ /** Value type of the class. */
+ eValueType V>
+class PrimitiveValue : public Value {
+ private:
+ T inner_value_{};
+
+ public:
+ explicit PrimitiveValue(const T value) : Value(V), inner_value_(value)
+ {
+ }
+
+ const T value() const
+ {
+ return inner_value_;
+ }
+};
+
+class NullValue : public Value {
+ public:
+ NullValue() : Value(eValueType::Null)
+ {
+ }
+};
+
+class StringValue : public Value {
+ private:
+ std::string string_;
+
+ public:
+ StringValue(const StringRef string) : Value(eValueType::String), string_(string)
+ {
+ }
+
+ const std::string &value() const
+ {
+ return string_;
+ }
+};
+
+/**
+ * Template for arrays and objects.
+ *
+ * Both ArrayValue and ObjectValue store their values in an array.
+ */
+template<
+ /** The container type where the elements are stored in. */
+ typename Container,
+
+ /** Type of the data inside the container. */
+ typename ContainerItem,
+
+ /** ValueType representing the value (object/array). */
+ eValueType V>
+class ContainerValue : public Value {
+ public:
+ using Items = Container;
+ using Item = ContainerItem;
+
+ private:
+ Container inner_value_;
+
+ public:
+ ContainerValue() : Value(V)
+ {
+ }
+
+ const Container &elements() const
+ {
+ return inner_value_;
+ }
+
+ Container &elements()
+ {
+ return inner_value_;
+ }
+};
+
+/**
+ * Internal storage type for ObjectValue.
+ *
+ * The elements are stored as an key value pair. The value is a shared pointer so it can be shared
+ * when using `ObjectValue::create_lookup`.
+ */
+using ObjectElementType = std::pair<std::string, std::shared_ptr<Value>>;
+
+/**
+ * Object is a key-value container where the key must be a std::string.
+ * Internally it is stored in a blender::Vector to ensure the order of keys.
+ */
+class ObjectValue
+ : public ContainerValue<Vector<ObjectElementType>, ObjectElementType, eValueType::Object> {
+ public:
+ using LookupValue = std::shared_ptr<Value>;
+ using Lookup = Map<std::string, LookupValue>;
+
+ /**
+ * Return a lookup map to quickly lookup by key.
+ *
+ * The lookup is owned by the caller.
+ */
+ const Lookup create_lookup() const
+ {
+ Lookup result;
+ for (const Item &item : elements()) {
+ result.add_as(item.first, item.second);
+ }
+ return result;
+ }
+};
+
+/**
+ * Interface for any provided Formatter.
+ */
+class Formatter {
+ public:
+ virtual ~Formatter() = default;
+
+ /** Serialize the value to the given stream. */
+ virtual void serialize(std::ostream &os, const Value &value) = 0;
+
+ /** Deserialize the stream. */
+ virtual std::unique_ptr<Value> deserialize(std::istream &is) = 0;
+};
+
+/**
+ * Formatter to (de)serialize a JSON formatted stream.
+ */
+class JsonFormatter : public Formatter {
+ public:
+ /**
+ * The indentation level to use.
+ * Typically number of chars. Set to 0 to not use indentation.
+ */
+ int8_t indentation_len = 0;
+
+ public:
+ void serialize(std::ostream &os, const Value &value) override;
+ std::unique_ptr<Value> deserialize(std::istream &is) override;
+};
+
+} // namespace blender::io::serialize
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index c01052f0111..7db984aef5c 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../../intern/guardedalloc
../../../intern/numaapi/include
../../../extern/wcwidth
+ ../../../extern/json/include
)
set(INC_SYS
@@ -126,6 +127,7 @@ set(SRC
intern/scanfill.c
intern/scanfill_utils.c
intern/session_uuid.c
+ intern/serialize.cc
intern/smallhash.c
intern/sort.c
intern/sort_utils.c
@@ -282,6 +284,7 @@ set(SRC
BLI_session_uuid.h
BLI_set.hh
BLI_set_slots.hh
+ BLI_serialize.hh
BLI_simd.h
BLI_smallhash.h
BLI_sort.h
@@ -364,6 +367,10 @@ if(WITH_GMP)
endif()
if(WIN32)
+ if (WITH_BLENDER_THUMBNAILER)
+ # Needed for querying the thumbnailer .dll in winstuff.c
+ add_definitions(-DWITH_BLENDER_THUMBNAILER)
+ endif()
list(APPEND INC
../../../intern/utfconv
)
@@ -448,6 +455,7 @@ if(WITH_GTESTS)
tests/BLI_span_test.cc
tests/BLI_stack_cxx_test.cc
tests/BLI_stack_test.cc
+ tests/BLI_serialize_test.cc
tests/BLI_string_ref_test.cc
tests/BLI_string_search_test.cc
tests/BLI_string_test.cc
diff --git a/source/blender/blenlib/intern/noise.cc b/source/blender/blenlib/intern/noise.cc
index 5fa2746d07f..4259237af6e 100644
--- a/source/blender/blenlib/intern/noise.cc
+++ b/source/blender/blenlib/intern/noise.cc
@@ -1528,9 +1528,15 @@ void voronoi_f1(
targetPosition = pointPosition;
}
}
- *r_distance = minDistance;
- *r_color = hash_float_to_float3(cellPosition + targetOffset);
- *r_w = targetPosition + cellPosition;
+ if (r_distance != nullptr) {
+ *r_distance = minDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + targetOffset);
+ }
+ if (r_w != nullptr) {
+ *r_w = targetPosition + cellPosition;
+ }
}
void voronoi_smooth_f1(const float w,
@@ -1555,14 +1561,26 @@ void voronoi_smooth_f1(const float w,
0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
float correctionFactor = smoothness * h * (1.0f - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
- correctionFactor /= 1.0f + 3.0f * smoothness;
- const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
- smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
- smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ if (r_color != nullptr || r_w != nullptr) {
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ if (r_color != nullptr) {
+ const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ }
+ if (r_w != nullptr) {
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = smoothDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = smoothColor;
+ }
+ if (r_w != nullptr) {
+ *r_w = cellPosition + smoothPosition;
}
- *r_distance = smoothDistance;
- *r_color = smoothColor;
- *r_w = cellPosition + smoothPosition;
}
void voronoi_f2(
@@ -1596,9 +1614,15 @@ void voronoi_f2(
positionF2 = pointPosition;
}
}
- *r_distance = distanceF2;
- *r_color = hash_float_to_float3(cellPosition + offsetF2);
- *r_w = positionF2 + cellPosition;
+ if (r_distance != nullptr) {
+ *r_distance = distanceF2;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + offsetF2);
+ }
+ if (r_w != nullptr) {
+ *r_w = positionF2 + cellPosition;
+ }
}
void voronoi_distance_to_edge(const float w, const float randomness, float *r_distance)
@@ -1706,9 +1730,15 @@ void voronoi_f1(const float2 coord,
}
}
}
- *r_distance = minDistance;
- *r_color = hash_float_to_float3(cellPosition + targetOffset);
- *r_position = targetPosition + cellPosition;
+ if (r_distance != nullptr) {
+ *r_distance = minDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + targetOffset);
+ }
+ if (r_position != nullptr) {
+ *r_position = targetPosition + cellPosition;
+ }
}
void voronoi_smooth_f1(const float2 coord,
@@ -1737,15 +1767,28 @@ void voronoi_smooth_f1(const float2 coord,
0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
float correctionFactor = smoothness * h * (1.0f - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
- correctionFactor /= 1.0f + 3.0f * smoothness;
- const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
- smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
- smoothPosition = float2::interpolate(smoothPosition, pointPosition, h) - correctionFactor;
+ if (r_color != nullptr || r_position != nullptr) {
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ if (r_color != nullptr) {
+ const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ }
+ if (r_position != nullptr) {
+ smoothPosition = float2::interpolate(smoothPosition, pointPosition, h) -
+ correctionFactor;
+ }
+ }
}
}
- *r_distance = smoothDistance;
- *r_color = smoothColor;
- *r_position = cellPosition + smoothPosition;
+ if (r_distance != nullptr) {
+ *r_distance = smoothDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = smoothColor;
+ }
+ if (r_position != nullptr) {
+ *r_position = cellPosition + smoothPosition;
+ }
}
void voronoi_f2(const float2 coord,
@@ -1787,9 +1830,15 @@ void voronoi_f2(const float2 coord,
}
}
}
- *r_distance = distanceF2;
- *r_color = hash_float_to_float3(cellPosition + offsetF2);
- *r_position = positionF2 + cellPosition;
+ if (r_distance != nullptr) {
+ *r_distance = distanceF2;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + offsetF2);
+ }
+ if (r_position != nullptr) {
+ *r_position = positionF2 + cellPosition;
+ }
}
void voronoi_distance_to_edge(const float2 coord, const float randomness, float *r_distance)
@@ -1928,9 +1977,15 @@ void voronoi_f1(const float3 coord,
}
}
}
- *r_distance = minDistance;
- *r_color = hash_float_to_float3(cellPosition + targetOffset);
- *r_position = targetPosition + cellPosition;
+ if (r_distance != nullptr) {
+ *r_distance = minDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + targetOffset);
+ }
+ if (r_position != nullptr) {
+ *r_position = targetPosition + cellPosition;
+ }
}
void voronoi_smooth_f1(const float3 coord,
@@ -1960,16 +2015,29 @@ void voronoi_smooth_f1(const float3 coord,
0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
float correctionFactor = smoothness * h * (1.0f - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
- correctionFactor /= 1.0f + 3.0f * smoothness;
- const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
- smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
- smoothPosition = float3::interpolate(smoothPosition, pointPosition, h) - correctionFactor;
+ if (r_color != nullptr || r_position != nullptr) {
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ if (r_color != nullptr) {
+ const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ }
+ if (r_position != nullptr) {
+ smoothPosition = float3::interpolate(smoothPosition, pointPosition, h) -
+ correctionFactor;
+ }
+ }
}
}
}
- *r_distance = smoothDistance;
- *r_color = smoothColor;
- *r_position = cellPosition + smoothPosition;
+ if (r_distance != nullptr) {
+ *r_distance = smoothDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = smoothColor;
+ }
+ if (r_position != nullptr) {
+ *r_position = cellPosition + smoothPosition;
+ }
}
void voronoi_f2(const float3 coord,
@@ -2013,9 +2081,15 @@ void voronoi_f2(const float3 coord,
}
}
}
- *r_distance = distanceF2;
- *r_color = hash_float_to_float3(cellPosition + offsetF2);
- *r_position = positionF2 + cellPosition;
+ if (r_distance != nullptr) {
+ *r_distance = distanceF2;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + offsetF2);
+ }
+ if (r_position != nullptr) {
+ *r_position = positionF2 + cellPosition;
+ }
}
void voronoi_distance_to_edge(const float3 coord, const float randomness, float *r_distance)
@@ -2166,9 +2240,15 @@ void voronoi_f1(const float4 coord,
}
}
}
- *r_distance = minDistance;
- *r_color = hash_float_to_float3(cellPosition + targetOffset);
- *r_position = targetPosition + cellPosition;
+ if (r_distance != nullptr) {
+ *r_distance = minDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + targetOffset);
+ }
+ if (r_position != nullptr) {
+ *r_position = targetPosition + cellPosition;
+ }
}
void voronoi_smooth_f1(const float4 coord,
@@ -2200,18 +2280,30 @@ void voronoi_smooth_f1(const float4 coord,
0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
float correctionFactor = smoothness * h * (1.0f - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
- correctionFactor /= 1.0f + 3.0f * smoothness;
- const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
- smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
- smoothPosition = float4::interpolate(smoothPosition, pointPosition, h) -
- correctionFactor;
+ if (r_color != nullptr || r_position != nullptr) {
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ if (r_color != nullptr) {
+ const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ }
+ if (r_position != nullptr) {
+ smoothPosition = float4::interpolate(smoothPosition, pointPosition, h) -
+ correctionFactor;
+ }
+ }
}
}
}
}
- *r_distance = smoothDistance;
- *r_color = smoothColor;
- *r_position = cellPosition + smoothPosition;
+ if (r_distance != nullptr) {
+ *r_distance = smoothDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = smoothColor;
+ }
+ if (r_position != nullptr) {
+ *r_position = cellPosition + smoothPosition;
+ }
}
void voronoi_f2(const float4 coord,
@@ -2258,9 +2350,15 @@ void voronoi_f2(const float4 coord,
}
}
}
- *r_distance = distanceF2;
- *r_color = hash_float_to_float3(cellPosition + offsetF2);
- *r_position = positionF2 + cellPosition;
+ if (r_distance != nullptr) {
+ *r_distance = distanceF2;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + offsetF2);
+ }
+ if (r_position != nullptr) {
+ *r_position = positionF2 + cellPosition;
+ }
}
void voronoi_distance_to_edge(const float4 coord, const float randomness, float *r_distance)
diff --git a/source/blender/blenlib/intern/serialize.cc b/source/blender/blenlib/intern/serialize.cc
new file mode 100644
index 00000000000..52aff140e3e
--- /dev/null
+++ b/source/blender/blenlib/intern/serialize.cc
@@ -0,0 +1,216 @@
+#include "BLI_serialize.hh"
+
+#include "json.hpp"
+
+namespace blender::io::serialize {
+
+const StringValue *Value::as_string_value() const
+{
+ if (type_ != eValueType::String) {
+ return nullptr;
+ }
+ return static_cast<const StringValue *>(this);
+}
+
+const IntValue *Value::as_int_value() const
+{
+ if (type_ != eValueType::Int) {
+ return nullptr;
+ }
+ return static_cast<const IntValue *>(this);
+}
+
+const DoubleValue *Value::as_double_value() const
+{
+ if (type_ != eValueType::Double) {
+ return nullptr;
+ }
+ return static_cast<const DoubleValue *>(this);
+}
+
+const BooleanValue *Value::as_boolean_value() const
+{
+ if (type_ != eValueType::Boolean) {
+ return nullptr;
+ }
+ return static_cast<const BooleanValue *>(this);
+}
+
+const ArrayValue *Value::as_array_value() const
+{
+ if (type_ != eValueType::Array) {
+ return nullptr;
+ }
+ return static_cast<const ArrayValue *>(this);
+}
+
+const ObjectValue *Value::as_object_value() const
+{
+ if (type_ != eValueType::Object) {
+ return nullptr;
+ }
+ return static_cast<const ObjectValue *>(this);
+}
+
+static void convert_to_json(nlohmann::ordered_json &j, const Value &value);
+static void convert_to_json(nlohmann::ordered_json &j, const ArrayValue &value)
+{
+ const ArrayValue::Items &items = value.elements();
+ /* Create a json array to store the elements. If this isn't done and items is empty it would
+ * return use a null value, in stead of an empty array. */
+ j = "[]"_json;
+ for (const ArrayValue::Item &item_value : items) {
+ nlohmann::ordered_json json_item;
+ convert_to_json(json_item, *item_value);
+ j.push_back(json_item);
+ }
+}
+
+static void convert_to_json(nlohmann::ordered_json &j, const ObjectValue &value)
+{
+ const ObjectValue::Items &attributes = value.elements();
+ /* Create a json object to store the attributes. If this isn't done and attributes is empty it
+ * would return use a null value, in stead of an empty object. */
+ j = "{}"_json;
+ for (const ObjectValue::Item &attribute : attributes) {
+ nlohmann::ordered_json json_item;
+ convert_to_json(json_item, *attribute.second);
+ j[attribute.first] = json_item;
+ }
+}
+
+static void convert_to_json(nlohmann::ordered_json &j, const Value &value)
+{
+ switch (value.type()) {
+ case eValueType::String: {
+ j = value.as_string_value()->value();
+ break;
+ }
+
+ case eValueType::Int: {
+ j = value.as_int_value()->value();
+ break;
+ }
+
+ case eValueType::Array: {
+ const ArrayValue &array = *value.as_array_value();
+ convert_to_json(j, array);
+ break;
+ }
+
+ case eValueType::Object: {
+ const ObjectValue &object = *value.as_object_value();
+ convert_to_json(j, object);
+ break;
+ }
+
+ case eValueType::Null: {
+ j = nullptr;
+ break;
+ }
+
+ case eValueType::Boolean: {
+ j = value.as_boolean_value()->value();
+ break;
+ }
+
+ case eValueType::Double: {
+ j = value.as_double_value()->value();
+ }
+ }
+}
+
+static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j);
+static std::unique_ptr<ArrayValue> convert_from_json_to_array(const nlohmann::ordered_json &j)
+{
+ std::unique_ptr<ArrayValue> array = std::make_unique<ArrayValue>();
+ ArrayValue::Items &elements = array->elements();
+ for (auto element : j.items()) {
+ nlohmann::ordered_json element_json = element.value();
+ std::unique_ptr<Value> value = convert_from_json(element_json);
+ elements.append_as(value.release());
+ }
+ return array;
+}
+
+static std::unique_ptr<ObjectValue> convert_from_json_to_object(const nlohmann::ordered_json &j)
+{
+ std::unique_ptr<ObjectValue> object = std::make_unique<ObjectValue>();
+ ObjectValue::Items &elements = object->elements();
+ for (auto element : j.items()) {
+ std::string key = element.key();
+ nlohmann::ordered_json element_json = element.value();
+ std::unique_ptr<Value> value = convert_from_json(element_json);
+ elements.append_as(std::pair(key, value.release()));
+ }
+ return object;
+}
+
+static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j)
+{
+ switch (j.type()) {
+ case nlohmann::json::value_t::array: {
+ return convert_from_json_to_array(j);
+ }
+
+ case nlohmann::json::value_t::object: {
+ return convert_from_json_to_object(j);
+ }
+
+ case nlohmann::json::value_t::string: {
+ std::string value = j;
+ return std::make_unique<StringValue>(value);
+ }
+
+ case nlohmann::json::value_t::null: {
+ return std::make_unique<NullValue>();
+ }
+
+ case nlohmann::json::value_t::boolean: {
+ return std::make_unique<BooleanValue>(j);
+ }
+ case nlohmann::json::value_t::number_integer:
+ case nlohmann::json::value_t::number_unsigned: {
+ return std::make_unique<IntValue>(j);
+ }
+
+ case nlohmann::json::value_t::number_float: {
+ return std::make_unique<DoubleValue>(j);
+ }
+
+ case nlohmann::json::value_t::binary:
+ case nlohmann::json::value_t::discarded:
+ /*
+ * Binary data isn't supported.
+ * Discarded is an internal type of nlohmann.
+ *
+ * Assert in case we need to parse them.
+ */
+ BLI_assert_unreachable();
+ return std::make_unique<NullValue>();
+ }
+
+ BLI_assert_unreachable();
+ return std::make_unique<NullValue>();
+}
+
+void JsonFormatter::serialize(std::ostream &os, const Value &value)
+{
+ nlohmann::ordered_json j;
+ convert_to_json(j, value);
+ if (indentation_len) {
+ os << j.dump(indentation_len);
+ }
+ else {
+ os << j.dump();
+ }
+}
+
+std::unique_ptr<Value> JsonFormatter::deserialize(std::istream &is)
+{
+ nlohmann::ordered_json j;
+ is >> j;
+ return convert_from_json(j);
+}
+
+} // namespace blender::io::serialize
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
index d5c9c5cd5e6..3001b25bc1e 100644
--- a/source/blender/blenlib/intern/winstuff.c
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -172,12 +172,14 @@ bool BLI_windows_register_blend_extension(const bool background)
return false;
}
+# ifdef WITH_BLENDER_THUMBNAILER
BLI_windows_get_executable_dir(InstallDir);
GetSystemDirectory(SysDir, FILE_MAXDIR);
ThumbHandlerDLL = "BlendThumb.dll";
snprintf(
RegCmd, MAX_PATH * 2, "%s\\regsvr32 /s \"%s\\%s\"", SysDir, InstallDir, ThumbHandlerDLL);
system(RegCmd);
+# endif
RegCloseKey(root);
printf("success (%s)\n", usr_mode ? "user" : "system");
diff --git a/source/blender/blenlib/tests/BLI_serialize_test.cc b/source/blender/blenlib/tests/BLI_serialize_test.cc
new file mode 100644
index 00000000000..6c55a85ca1e
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_serialize_test.cc
@@ -0,0 +1,207 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_serialize.hh"
+
+/* -------------------------------------------------------------------- */
+/* tests */
+
+namespace blender::io::serialize::json::testing {
+
+TEST(serialize, string_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ StringValue test_value("Hello JSON");
+ json.serialize(out, test_value);
+ EXPECT_EQ(out.str(), "\"Hello JSON\"");
+}
+
+static void test_int_to_json(int64_t value, StringRef expected)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ IntValue test_value(value);
+ json.serialize(out, test_value);
+ EXPECT_EQ(out.str(), expected);
+}
+
+TEST(serialize, int_to_json)
+{
+ test_int_to_json(42, "42");
+ test_int_to_json(-42, "-42");
+ test_int_to_json(std::numeric_limits<int32_t>::max(), "2147483647");
+ test_int_to_json(std::numeric_limits<int32_t>::min(), "-2147483648");
+ test_int_to_json(std::numeric_limits<int64_t>::max(), "9223372036854775807");
+ test_int_to_json(std::numeric_limits<int64_t>::min(), "-9223372036854775808");
+}
+
+TEST(serialize, double_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ DoubleValue test_value(42.31);
+ json.serialize(out, test_value);
+ EXPECT_EQ(out.str(), "42.31");
+}
+
+TEST(serialize, null_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ NullValue test_value;
+ json.serialize(out, test_value);
+ EXPECT_EQ(out.str(), "null");
+}
+
+TEST(serialize, false_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ BooleanValue value(false);
+ json.serialize(out, value);
+ EXPECT_EQ(out.str(), "false");
+}
+
+TEST(serialize, true_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ BooleanValue value(true);
+ json.serialize(out, value);
+ EXPECT_EQ(out.str(), "true");
+}
+
+TEST(serialize, array_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ ArrayValue value_array;
+ ArrayValue::Items &array = value_array.elements();
+ array.append_as(new IntValue(42));
+ array.append_as(new StringValue("Hello JSON"));
+ array.append_as(new NullValue);
+ array.append_as(new BooleanValue(false));
+ array.append_as(new BooleanValue(true));
+
+ json.serialize(out, value_array);
+ EXPECT_EQ(out.str(), "[42,\"Hello JSON\",null,false,true]");
+}
+
+TEST(serialize, object_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ ObjectValue value_object;
+ ObjectValue::Items &attributes = value_object.elements();
+ attributes.append_as(std::pair(std::string("best_number"), new IntValue(42)));
+
+ json.serialize(out, value_object);
+ EXPECT_EQ(out.str(), "{\"best_number\":42}");
+}
+
+TEST(serialize, json_roundtrip_ordering)
+{
+ const std::string input =
+ "[{\"_id\":\"614ada7c476c472ecbd0ecbb\",\"index\":0,\"guid\":\"d5b81381-cef8-4327-923d-"
+ "41e57ff79326\",\"isActive\":false,\"balance\":\"$2,062.25\",\"picture\":\"http://"
+ "placehold.it/32x32\",\"age\":26,\"eyeColor\":\"brown\",\"name\":\"Geneva "
+ "Vega\",\"gender\":\"female\",\"company\":\"SLOGANAUT\",\"email\":\"genevavega@sloganaut."
+ "com\",\"phone\":\"+1 (993) 432-2805\",\"address\":\"943 Christopher Avenue, Northchase, "
+ "Alabama, 5769\",\"about\":\"Eu cillum qui eu fugiat sit nulla eu duis. Aliqua nulla aliqua "
+ "ea tempor dolor fugiat sint consectetur exercitation ipsum magna ex. Aute laborum esse "
+ "magna nostrud in cillum et mollit proident. Deserunt ex minim adipisicing incididunt "
+ "incididunt dolore velit aliqua.\\r\\n\",\"registered\":\"2014-06-02T06:29:33 "
+ "-02:00\",\"latitude\":-66.003108,\"longitude\":44.038986,\"tags\":[\"exercitation\","
+ "\"laborum\",\"velit\",\"magna\",\"officia\",\"aliqua\",\"laboris\"],\"friends\":[{\"id\":0,"
+ "\"name\":\"Daniel Stuart\"},{\"id\":1,\"name\":\"Jackson "
+ "Velez\"},{\"id\":2,\"name\":\"Browning Boyd\"}],\"greeting\":\"Hello, Geneva Vega! You "
+ "have 8 unread "
+ "messages.\",\"favoriteFruit\":\"strawberry\"},{\"_id\":\"614ada7cf28685063c6722af\","
+ "\"index\":1,\"guid\":\"e157edf3-a86d-4984-b18d-e2fe568a9915\",\"isActive\":false,"
+ "\"balance\":\"$3,550.44\",\"picture\":\"http://placehold.it/"
+ "32x32\",\"age\":40,\"eyeColor\":\"blue\",\"name\":\"Lamb "
+ "Lowe\",\"gender\":\"male\",\"company\":\"PROXSOFT\",\"email\":\"lamblowe@proxsoft.com\","
+ "\"phone\":\"+1 (999) 573-2855\",\"address\":\"632 Rockwell Place, Diaperville, "
+ "Pennsylvania, 5050\",\"about\":\"Anim dolor deserunt esse quis velit adipisicing aute "
+ "nostrud velit minim culpa aute et tempor. Dolor aliqua reprehenderit anim voluptate. "
+ "Consequat proident ut culpa reprehenderit qui. Nisi proident velit cillum voluptate. "
+ "Ullamco id sunt quis aute adipisicing cupidatat consequat "
+ "aliquip.\\r\\n\",\"registered\":\"2014-09-06T06:13:36 "
+ "-02:00\",\"latitude\":-44.550228,\"longitude\":-80.893356,\"tags\":[\"anim\",\"id\","
+ "\"irure\",\"do\",\"officia\",\"irure\",\"Lorem\"],\"friends\":[{\"id\":0,\"name\":"
+ "\"Faulkner Watkins\"},{\"id\":1,\"name\":\"Cecile Schneider\"},{\"id\":2,\"name\":\"Burt "
+ "Lester\"}],\"greeting\":\"Hello, Lamb Lowe! You have 1 unread "
+ "messages.\",\"favoriteFruit\":\"strawberry\"},{\"_id\":\"614ada7c235335fc56bc2f78\","
+ "\"index\":2,\"guid\":\"8206bad1-8274-49fd-9223-d727589f22ca\",\"isActive\":false,"
+ "\"balance\":\"$2,548.34\",\"picture\":\"http://placehold.it/"
+ "32x32\",\"age\":37,\"eyeColor\":\"blue\",\"name\":\"Sallie "
+ "Chase\",\"gender\":\"female\",\"company\":\"FLEETMIX\",\"email\":\"salliechase@fleetmix."
+ "com\",\"phone\":\"+1 (953) 453-3388\",\"address\":\"865 Irving Place, Chelsea, Utah, "
+ "9777\",\"about\":\"In magna exercitation incididunt exercitation dolor anim. Consectetur "
+ "dolore commodo elit cillum dolor reprehenderit magna minim et ex labore pariatur. Nulla "
+ "ullamco officia velit in aute proident nostrud. Duis deserunt et labore Lorem aliqua "
+ "eiusmod commodo sunt.\\r\\n\",\"registered\":\"2017-03-16T08:54:53 "
+ "-01:00\",\"latitude\":-78.481939,\"longitude\":-149.820215,\"tags\":[\"Lorem\",\"ipsum\","
+ "\"in\",\"tempor\",\"consectetur\",\"voluptate\",\"elit\"],\"friends\":[{\"id\":0,\"name\":"
+ "\"Gibson Garner\"},{\"id\":1,\"name\":\"Anna Frank\"},{\"id\":2,\"name\":\"Roberson "
+ "Daugherty\"}],\"greeting\":\"Hello, Sallie Chase! You have 7 unread "
+ "messages.\",\"favoriteFruit\":\"apple\"},{\"_id\":\"614ada7c93b63ecad5f9ba5e\",\"index\":3,"
+ "\"guid\":\"924b02fc-7c27-481a-9941-db3b9403dfe1\",\"isActive\":true,\"balance\":\"$1,633."
+ "60\",\"picture\":\"http://placehold.it/"
+ "32x32\",\"age\":29,\"eyeColor\":\"brown\",\"name\":\"Grace "
+ "Mccall\",\"gender\":\"female\",\"company\":\"PIVITOL\",\"email\":\"gracemccall@pivitol."
+ "com\",\"phone\":\"+1 (964) 541-2514\",\"address\":\"734 Schaefer Street, Topaz, Virginia, "
+ "9137\",\"about\":\"Amet officia magna fugiat ut pariatur fugiat elit culpa voluptate elit "
+ "do proident culpa minim. Commodo do minim reprehenderit ut voluptate ut velit id esse "
+ "consequat. Labore ullamco deserunt irure eiusmod cillum tempor incididunt qui adipisicing "
+ "nostrud pariatur enim aliquip. Excepteur nostrud commodo consectetur esse duis irure "
+ "qui.\\r\\n\",\"registered\":\"2015-04-24T03:55:17 "
+ "-02:00\",\"latitude\":58.801446,\"longitude\":-157.413865,\"tags\":[\"do\",\"ea\",\"eu\","
+ "\"eu\",\"qui\",\"duis\",\"sint\"],\"friends\":[{\"id\":0,\"name\":\"Carrie "
+ "Short\"},{\"id\":1,\"name\":\"Dickerson Barnes\"},{\"id\":2,\"name\":\"Rae "
+ "Rios\"}],\"greeting\":\"Hello, Grace Mccall! You have 5 unread "
+ "messages.\",\"favoriteFruit\":\"apple\"},{\"_id\":\"614ada7c9caf1353b0e22bbf\",\"index\":4,"
+ "\"guid\":\"e5981ae1-90e4-41c4-9905-161522db700b\",\"isActive\":false,\"balance\":\"$3,660."
+ "34\",\"picture\":\"http://placehold.it/"
+ "32x32\",\"age\":31,\"eyeColor\":\"blue\",\"name\":\"Herring "
+ "Powers\",\"gender\":\"male\",\"company\":\"PYRAMIA\",\"email\":\"herringpowers@pyramia."
+ "com\",\"phone\":\"+1 (981) 541-2829\",\"address\":\"409 Furman Avenue, Waterloo, South "
+ "Carolina, 380\",\"about\":\"In officia culpa aliqua culpa pariatur aliqua mollit ex. Velit "
+ "est Lorem enim magna cillum sunt elit consectetur deserunt ea est consectetur fugiat "
+ "mollit. Aute Lorem excepteur minim esse qui. Id Lorem in tempor et. Nisi aliquip laborum "
+ "magna eu aute.\\r\\n\",\"registered\":\"2018-07-05T07:28:54 "
+ "-02:00\",\"latitude\":51.497405,\"longitude\":-129.422711,\"tags\":[\"eiusmod\",\"et\","
+ "\"nostrud\",\"reprehenderit\",\"Lorem\",\"cillum\",\"nulla\"],\"friends\":[{\"id\":0,"
+ "\"name\":\"Tonia Keith\"},{\"id\":1,\"name\":\"Leanne Rice\"},{\"id\":2,\"name\":\"Craig "
+ "Gregory\"}],\"greeting\":\"Hello, Herring Powers! You have 6 unread "
+ "messages.\",\"favoriteFruit\":\"strawberry\"},{\"_id\":\"614ada7c53a3d6da77468f25\","
+ "\"index\":5,\"guid\":\"abb2eec9-c4f0-4a0d-b20a-5c8e50fe88a1\",\"isActive\":true,"
+ "\"balance\":\"$1,481.08\",\"picture\":\"http://placehold.it/"
+ "32x32\",\"age\":31,\"eyeColor\":\"green\",\"name\":\"Lela "
+ "Dillard\",\"gender\":\"female\",\"company\":\"CEMENTION\",\"email\":\"leladillard@"
+ "cemention.com\",\"phone\":\"+1 (856) 456-3657\",\"address\":\"391 Diamond Street, Madaket, "
+ "Ohio, 9337\",\"about\":\"Tempor dolor ullamco esse cillum excepteur. Excepteur aliqua non "
+ "enim anim esse amet cupidatat non. Cillum excepteur occaecat cupidatat elit labore. "
+ "Pariatur ut esse sint elit. Velit sint magna et commodo sit velit labore consectetur irure "
+ "officia proident aliquip. Aliqua dolore ipsum voluptate veniam deserunt amet irure. Cillum "
+ "consequat veniam proident Lorem in anim enim veniam ea "
+ "nulla.\\r\\n\",\"registered\":\"2017-01-11T11:07:22 "
+ "-01:00\",\"latitude\":86.349081,\"longitude\":-179.983754,\"tags\":[\"consequat\","
+ "\"labore\",\"consectetur\",\"dolor\",\"laborum\",\"eiusmod\",\"in\"],\"friends\":[{\"id\":"
+ "0,\"name\":\"Hancock Rivera\"},{\"id\":1,\"name\":\"Chasity "
+ "Oneil\"},{\"id\":2,\"name\":\"Whitaker Barr\"}],\"greeting\":\"Hello, Lela Dillard! You "
+ "have 3 unread messages.\",\"favoriteFruit\":\"strawberry\"}]";
+ std::stringstream is(input);
+
+ JsonFormatter json;
+ std::unique_ptr<Value> value = json.deserialize(is);
+ EXPECT_EQ(value->type(), eValueType::Array);
+
+ std::stringstream out;
+ json.serialize(out, *value);
+ EXPECT_EQ(out.str(), input);
+}
+
+} // namespace blender::io::serialize::json::testing
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 0b69395b4f8..600abcca818 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2211,6 +2211,9 @@ static void direct_link_id_common(
if (id->asset_data) {
BLO_read_data_address(reader, &id->asset_data);
BKE_asset_metadata_read(reader, id->asset_data);
+ /* Restore runtime asset type info. */
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
+ id->asset_data->local_type_info = id_type->asset_type_info;
}
/* Link direct data of ID properties. */
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index e6247750759..e809d580fd2 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -1717,18 +1717,8 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - #blo_do_versions_280 in this file.
- * - "versioning_userdef.c", #blo_do_versions_userdef
- * - "versioning_userdef.c", #do_versions_theme
- *
- * \note Keep this message at the bottom of the function.
- */
- {
- /* Keep this block, even when empty. */
+ /* Old forgotten versioning code. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 39)) {
/* Paint Brush. This ensure that the brush paints by default. Used during the development and
* patch review of the initial Sculpt Vertex Colors implementation (D5975) */
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
@@ -1748,6 +1738,20 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
}
}
}
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - #blo_do_versions_280 in this file.
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+ }
}
/* NOTE: This version patch is intended for versions < 2.52.2,
@@ -5066,17 +5070,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - #do_versions_after_linking_280 in this file.
- * - "versioning_userdef.c", #blo_do_versions_userdef
- * - "versioning_userdef.c", #do_versions_theme
- *
- * \note Keep this message at the bottom of the function.
- */
- {
+ /* Old forgotten versioning code. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 39)) {
/* Set the cloth wind factor to 1 for old forces. */
if (!DNA_struct_elem_find(fd->filesdna, "PartDeflect", "float", "f_wind_factor")) {
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
@@ -5096,10 +5091,22 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
/* Don't rotate light with the viewer by default, make it fixed. Shading settings can't be
- * edited and this flag should always be set. So we can always execute this. */
+ * edited and this flag should always be set. */
wm->xr.session_settings.shading.flag |= V3D_SHADING_WORLD_ORIENTATION;
}
+ }
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - #do_versions_after_linking_280 in this file.
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
/* Keep this block, even when empty. */
}
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index d2c722f8be7..def14768ec6 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1985,7 +1985,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 293, 18)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
- version_node_socket_name(ntree, GEO_NODE_VOLUME_TO_MESH, "Grid", "Density");
+ version_node_socket_name(ntree, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Grid", "Density");
}
}
FOREACH_NODETREE_END;
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 8168b917b5e..68faa4c0672 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -535,7 +535,7 @@ static void version_geometry_nodes_add_realize_instance_nodes(bNodeTree *ntree)
}
/* Also realize instances for the profile input of the curve to mesh node. */
if (node->type == GEO_NODE_CURVE_TO_MESH) {
- bNodeSocket *profile_socket = node->inputs.last;
+ bNodeSocket *profile_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
add_realize_instances_before_socket(ntree, node, profile_socket);
}
}
@@ -967,7 +967,7 @@ static bool geometry_node_is_293_legacy(const short node_type)
/* Maybe legacy: Special case for grid names? Or finish patch from level set branch to
* generate a mesh for all grids in the volume. */
- case GEO_NODE_VOLUME_TO_MESH:
+ case GEO_NODE_LEGACY_VOLUME_TO_MESH:
return false;
/* Legacy: Transferred *all* attributes before, will not transfer all built-ins now. */
@@ -1218,6 +1218,56 @@ static void do_version_bones_roll(ListBase *lb)
}
}
+static void version_geometry_nodes_set_position_node_offset(bNodeTree *ntree)
+{
+ /* Add the new Offset socket. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_SET_POSITION) {
+ continue;
+ }
+ if (BLI_listbase_count(&node->inputs) < 4) {
+ /* The offset socket didn't exist in the file yet. */
+ return;
+ }
+ bNodeSocket *old_offset_socket = BLI_findlink(&node->inputs, 3);
+ if (old_offset_socket->type == SOCK_VECTOR) {
+ /* Versioning happened already. */
+ return;
+ }
+ /* Change identifier of old socket, so that the there is no name collision. */
+ STRNCPY(old_offset_socket->identifier, "Offset_old");
+ nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_VECTOR, PROP_TRANSLATION, "Offset", "Offset");
+ }
+
+ /* Relink links that were connected to Position while Offset was enabled. */
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->tonode->type != GEO_NODE_SET_POSITION) {
+ continue;
+ }
+ if (!STREQ(link->tosock->identifier, "Position")) {
+ continue;
+ }
+ bNodeSocket *old_offset_socket = BLI_findlink(&link->tonode->inputs, 3);
+ /* This assumes that the offset is not linked to something else. That seems to be a reasonable
+ * assumption, because the node is probably only ever used in one or the other mode. */
+ const bool offset_enabled =
+ ((bNodeSocketValueBoolean *)old_offset_socket->default_value)->value;
+ if (offset_enabled) {
+ /* Relink to new offset socket. */
+ link->tosock = old_offset_socket->next;
+ }
+ }
+
+ /* Remove old Offset socket. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_SET_POSITION) {
+ continue;
+ }
+ bNodeSocket *old_offset_socket = BLI_findlink(&node->inputs, 3);
+ nodeRemoveSocket(ntree, node, old_offset_socket);
+ }
+}
+
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
@@ -2021,6 +2071,79 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 39)) {
+ LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
+ wm->xr.session_settings.base_scale = 1.0f;
+ wm->xr.session_settings.draw_flags |= (V3D_OFSDRAW_SHOW_SELECTION |
+ V3D_OFSDRAW_XR_SHOW_CONTROLLERS |
+ V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 40)) {
+ /* Update the `idnames` for renamed geometry and function nodes. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ version_node_id(ntree, FN_NODE_SLICE_STRING, "FunctionNodeSliceString");
+ version_geometry_nodes_set_position_node_offset(ntree);
+ version_node_id(ntree, GEO_NODE_LEGACY_VOLUME_TO_MESH, "GeometryNodeLegacyVolumeToMesh");
+ }
+
+ /* Add storage to viewer node. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_VIEWER) {
+ if (node->storage == NULL) {
+ NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(
+ sizeof(NodeGeometryViewer), __func__);
+ data->data_type = CD_PROP_FLOAT;
+ node->storage = data;
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(
+ ntree, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, "Geometry", "Mesh");
+ version_node_input_socket_name(ntree, GEO_NODE_POINTS_TO_VOLUME, "Geometry", "Points");
+ version_node_output_socket_name(ntree, GEO_NODE_POINTS_TO_VOLUME, "Geometry", "Volume");
+ version_node_socket_name(ntree, GEO_NODE_SUBDIVISION_SURFACE, "Geometry", "Mesh");
+ version_node_socket_name(ntree, GEO_NODE_RESAMPLE_CURVE, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SUBDIVIDE_CURVE, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SET_CURVE_RADIUS, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SET_CURVE_TILT, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SET_CURVE_HANDLES, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_TRANSLATE_INSTANCES, "Geometry", "Instances");
+ version_node_socket_name(ntree, GEO_NODE_ROTATE_INSTANCES, "Geometry", "Instances");
+ version_node_socket_name(ntree, GEO_NODE_SCALE_INSTANCES, "Geometry", "Instances");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry", "Mesh");
+ version_node_input_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry 1", "Mesh 1");
+ version_node_input_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry 2", "Mesh 2");
+ version_node_socket_name(ntree, GEO_NODE_SUBDIVIDE_MESH, "Geometry", "Mesh");
+ version_node_socket_name(ntree, GEO_NODE_TRIANGULATE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_CONE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_CUBE, "Geometry", "Mesh");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_GRID, "Geometry", "Mesh");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_LINE, "Geometry", "Mesh");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "Geometry", "Mesh");
+ version_node_socket_name(ntree, GEO_NODE_SET_POINT_RADIUS, "Geometry", "Points");
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -2030,15 +2153,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*
* \note Keep this message at the bottom of the function.
*/
-
{
- /* Update the `idnames` for renamed geometry and function nodes. */
- LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
- if (ntree->type != NTREE_GEOMETRY) {
- continue;
- }
- version_node_id(ntree, FN_NODE_SLICE_STRING, "FunctionNodeSliceString");
- }
/* Keep this block, even when empty. */
}
}
diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc
index 6c4996ba9b2..ecc944defba 100644
--- a/source/blender/blenloader/intern/versioning_common.cc
+++ b/source/blender/blenloader/intern/versioning_common.cc
@@ -87,6 +87,18 @@ ID *do_versions_rename_id(Main *bmain,
return id;
}
+static void change_node_socket_name(ListBase *sockets, const char *old_name, const char *new_name)
+{
+ LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
+ if (STREQ(socket->name, old_name)) {
+ BLI_strncpy(socket->name, new_name, sizeof(socket->name));
+ }
+ if (STREQ(socket->identifier, old_name)) {
+ BLI_strncpy(socket->identifier, new_name, sizeof(socket->name));
+ }
+ }
+}
+
void version_node_socket_name(bNodeTree *ntree,
const int node_type,
const char *old_name,
@@ -94,22 +106,32 @@ void version_node_socket_name(bNodeTree *ntree,
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == node_type) {
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (STREQ(socket->name, old_name)) {
- BLI_strncpy(socket->name, new_name, sizeof(socket->name));
- }
- if (STREQ(socket->identifier, old_name)) {
- BLI_strncpy(socket->identifier, new_name, sizeof(socket->name));
- }
- }
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
- if (STREQ(socket->name, old_name)) {
- BLI_strncpy(socket->name, new_name, sizeof(socket->name));
- }
- if (STREQ(socket->identifier, old_name)) {
- BLI_strncpy(socket->identifier, new_name, sizeof(socket->name));
- }
- }
+ change_node_socket_name(&node->inputs, old_name, new_name);
+ change_node_socket_name(&node->outputs, old_name, new_name);
+ }
+ }
+}
+
+void version_node_input_socket_name(bNodeTree *ntree,
+ const int node_type,
+ const char *old_name,
+ const char *new_name)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == node_type) {
+ change_node_socket_name(&node->inputs, old_name, new_name);
+ }
+ }
+}
+
+void version_node_output_socket_name(bNodeTree *ntree,
+ const int node_type,
+ const char *old_name,
+ const char *new_name)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == node_type) {
+ change_node_socket_name(&node->outputs, old_name, new_name);
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h
index 1826182be21..8697e8e2639 100644
--- a/source/blender/blenloader/intern/versioning_common.h
+++ b/source/blender/blenloader/intern/versioning_common.h
@@ -43,6 +43,14 @@ void version_node_socket_name(struct bNodeTree *ntree,
const int node_type,
const char *old_name,
const char *new_name);
+void version_node_input_socket_name(struct bNodeTree *ntree,
+ const int node_type,
+ const char *old_name,
+ const char *new_name);
+void version_node_output_socket_name(struct bNodeTree *ntree,
+ const int node_type,
+ const char *old_name,
+ const char *new_name);
void version_node_id(struct bNodeTree *ntree, const int node_type, const char *new_name);
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 170e6be715a..4234570af6c 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -27,9 +27,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#ifdef WITH_INTERNATIONAL
-# include "BLT_translation.h"
-#endif
+#include "BLT_translation.h"
#include "DNA_anim_types.h"
#include "DNA_collection_types.h"
@@ -60,10 +58,6 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
{
#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(userdef, ver, subver)
- if (!USER_VERSION_ATLEAST(280, 20)) {
- memcpy(btheme, &U_theme_default, sizeof(*btheme));
- }
-
#define FROM_DEFAULT_V4_UCHAR(member) copy_v4_v4_uchar(btheme->member, U_theme_default.member)
if (!USER_VERSION_ATLEAST(280, 25)) {
@@ -314,6 +308,15 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
btheme->space_node.dash_alpha = 0.5f;
}
+ if (!USER_VERSION_ATLEAST(300, 39)) {
+ FROM_DEFAULT_V4_UCHAR(space_node.grid);
+ btheme->space_node.grid_levels = 7;
+ }
+
+ if (!USER_VERSION_ATLEAST(300, 40)) {
+ memcpy(btheme, &U_theme_default, sizeof(*btheme));
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -923,6 +926,24 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->dupflag |= USER_DUP_SPEAKER;
}
+ if (!USER_VERSION_ATLEAST(300, 40)) {
+ /* Rename the default asset library from "Default" to "User Library" */
+ LISTBASE_FOREACH (bUserAssetLibrary *, asset_library, &userdef->asset_libraries) {
+ if (STREQ(asset_library->name, DATA_("Default"))) {
+ BKE_preferences_asset_library_name_set(
+ userdef, asset_library, BKE_PREFS_ASSET_LIBRARY_DEFAULT_NAME);
+ }
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(300, 40)) {
+ LISTBASE_FOREACH (uiStyle *, style, &userdef->uistyles) {
+ const int default_title_points = 11; /* UI_DEFAULT_TITLE_POINTS */
+ style->paneltitle.points = default_title_points;
+ style->grouplabel.points = default_title_points;
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index baf83234354..0baf994d978 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -61,6 +61,7 @@ set(SRC
intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
intern/mesh_extractors/extract_mesh_ibo_points.cc
intern/mesh_extractors/extract_mesh_ibo_tris.cc
+ intern/mesh_extractors/extract_mesh_vbo_attributes.cc
intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index b07e86000fd..7f9e37f58d5 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -463,9 +463,14 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
case OB_LIGHTPROBE:
OVERLAY_lightprobe_cache_populate(vedata, ob);
break;
- case OB_LATTICE:
- OVERLAY_lattice_cache_populate(vedata, ob);
+ case OB_LATTICE: {
+ /* Unlike the other types above, lattices actually have a bounding box defined, so hide the
+ * lattice wires if only the boundingbox is requested. */
+ if (ob->dt > OB_BOUNDBOX) {
+ OVERLAY_lattice_cache_populate(vedata, ob);
+ }
break;
+ }
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c
index 31c8ed9d664..4a551c4dec5 100644
--- a/source/blender/draw/engines/overlay/overlay_grid.c
+++ b/source/blender/draw/engines/overlay/overlay_grid.c
@@ -200,6 +200,15 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
shd->grid_distance = dist / 2.0f;
ED_view3d_grid_steps(scene, v3d, rv3d, shd->grid_steps);
+
+ if ((v3d->flag & (V3D_XR_SESSION_SURFACE | V3D_XR_SESSION_MIRROR)) != 0) {
+ /* The calculations for the grid parameters assume that the view matrix has no scale component,
+ * which may not be correct if the user is "shrunk" or "enlarged" by zooming in or out.
+ * Therefore, we need to compensate the values here. */
+ float viewinvscale = len_v3(
+ viewinv[0]); /* Assumption is uniform scaling (all column vectors are of same length). */
+ shd->grid_distance *= viewinvscale;
+ }
}
void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index a680cc0d6b7..ba42cdf66e7 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -24,6 +24,10 @@
struct TaskGraph;
+#include "DNA_customdata_types.h"
+
+#include "BKE_attribute.h"
+
#include "GPU_batch.h"
#include "GPU_index_buffer.h"
#include "GPU_vertex_buffer.h"
@@ -56,7 +60,6 @@ typedef struct DRW_MeshCDMask {
uint32_t uv : 8;
uint32_t tan : 8;
uint32_t vcol : 8;
- uint32_t sculpt_vcol : 8;
uint32_t orco : 1;
uint32_t tan_orco : 1;
uint32_t sculpt_overlays : 1;
@@ -64,10 +67,10 @@ typedef struct DRW_MeshCDMask {
* modifiers could remove it. (see T68857) */
uint32_t edit_uv : 1;
} DRW_MeshCDMask;
-/* Keep `DRW_MeshCDMask` struct within an `uint64_t`.
+/* Keep `DRW_MeshCDMask` struct within an `uint32_t`.
* bit-wise and atomic operations are used to compare and update the struct.
* See `mesh_cd_layers_type_*` functions. */
-BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint64_t), "DRW_MeshCDMask exceeds 64 bits")
+BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask exceeds 32 bits")
typedef enum eMRIterType {
MR_ITER_LOOPTRI = 1 << 0,
MR_ITER_POLY = 1 << 1,
@@ -76,6 +79,17 @@ typedef enum eMRIterType {
} eMRIterType;
ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT)
+typedef struct DRW_AttributeRequest {
+ CustomDataType cd_type;
+ int layer_index;
+ AttributeDomain domain;
+} DRW_AttributeRequest;
+
+typedef struct DRW_MeshAttributes {
+ DRW_AttributeRequest requests[GPU_MAX_ATTR];
+ int num_requests;
+} DRW_MeshAttributes;
+
typedef enum eMRDataType {
MR_DATA_NONE = 0,
MR_DATA_POLY_NOR = 1 << 1,
@@ -133,6 +147,7 @@ typedef struct MeshBufferList {
GPUVertBuf *edge_idx; /* extend */
GPUVertBuf *poly_idx;
GPUVertBuf *fdot_idx;
+ GPUVertBuf *attr[GPU_MAX_ATTR];
} vbo;
/* Index Buffers:
* Only need to be updated when topology changes. */
@@ -285,6 +300,8 @@ typedef struct MeshBatchCache {
DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
+ DRW_MeshAttributes attr_used, attr_needed, attr_used_over_time;
+
int lastmatch;
/* Valid only if edge_detection is up to date. */
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 06c449fe590..f3b72503907 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -650,6 +650,9 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
EXTRACT_ADD_REQUESTED(vbo, vert_idx);
EXTRACT_ADD_REQUESTED(vbo, fdot_idx);
EXTRACT_ADD_REQUESTED(vbo, skin_roots);
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ EXTRACT_ADD_REQUESTED(vbo, attr[i]);
+ }
EXTRACT_ADD_REQUESTED(ibo, tris);
if (DRW_ibo_requested(mbuflist->ibo.lines_loose)) {
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 18664498d00..12c19c671ab 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -41,6 +41,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
@@ -121,6 +122,8 @@
# define _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5) _MDEPS_ASSERT5(b, n1, n2, n3, n4); _MDEPS_ASSERT2(b, n5)
# define _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6) _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5); _MDEPS_ASSERT2(b, n6)
# define _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7) _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6); _MDEPS_ASSERT2(b, n7)
+# define _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20) _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7); _MDEPS_ASSERT8(b, n8, n9, n10, n11, n12, n13, n14); _MDEPS_ASSERT7(b, n15, n16, n17, n18, n19, n20)
+# define _MDEPS_ASSERT22(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21) _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20); _MDEPS_ASSERT2(b, n21);
# define MDEPS_ASSERT_FLAG(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_ASSERT, __VA_ARGS__)
# define MDEPS_ASSERT(batch_name, ...) MDEPS_ASSERT_FLAG(BATCH_FLAG(batch_name), __VA_ARGS__)
@@ -192,6 +195,21 @@ static const DRWBatchFlag g_buffer_deps[] = {
[BUFFER_INDEX(vbo.edge_idx)] = BATCH_FLAG(edit_selection_edges),
[BUFFER_INDEX(vbo.poly_idx)] = BATCH_FLAG(edit_selection_faces),
[BUFFER_INDEX(vbo.fdot_idx)] = BATCH_FLAG(edit_selection_fdots),
+ [BUFFER_INDEX(vbo.attr) + 0] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 1] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 2] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 3] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 4] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 5] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 6] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 7] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 8] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 9] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 10] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 11] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 12] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 13] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 14] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
[BUFFER_INDEX(ibo.tris)] = BATCH_FLAG(surface,
surface_weights,
@@ -240,12 +258,12 @@ static void mesh_batch_cache_discard_batch(MeshBatchCache *cache, const DRWBatch
/* Return true is all layers in _b_ are inside _a_. */
BLI_INLINE bool mesh_cd_layers_type_overlap(DRW_MeshCDMask a, DRW_MeshCDMask b)
{
- return (*((uint64_t *)&a) & *((uint64_t *)&b)) == *((uint64_t *)&b);
+ return (*((uint32_t *)&a) & *((uint32_t *)&b)) == *((uint32_t *)&b);
}
BLI_INLINE bool mesh_cd_layers_type_equal(DRW_MeshCDMask a, DRW_MeshCDMask b)
{
- return *((uint64_t *)&a) == *((uint64_t *)&b);
+ return *((uint32_t *)&a) == *((uint32_t *)&b);
}
BLI_INLINE void mesh_cd_layers_type_merge(DRW_MeshCDMask *a, DRW_MeshCDMask b)
@@ -253,12 +271,11 @@ BLI_INLINE void mesh_cd_layers_type_merge(DRW_MeshCDMask *a, DRW_MeshCDMask b)
uint32_t *a_p = (uint32_t *)a;
uint32_t *b_p = (uint32_t *)&b;
atomic_fetch_and_or_uint32(a_p, *b_p);
- atomic_fetch_and_or_uint32(a_p + 1, *(b_p + 1));
}
BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a)
{
- *((uint64_t *)a) = 0;
+ *((uint32_t *)a) = 0;
}
BLI_INLINE const Mesh *editmesh_final_or_this(const Mesh *me)
@@ -271,6 +288,95 @@ static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *c
cd_used->edit_uv = 1;
}
+/** \name DRW_MeshAttributes
+ *
+ * Utilities for handling requested attributes.
+ * \{ */
+
+/* Return true if the given DRW_AttributeRequest is already in the requests. */
+static bool has_request(const DRW_MeshAttributes *requests, DRW_AttributeRequest req)
+{
+ for (int i = 0; i < requests->num_requests; i++) {
+ const DRW_AttributeRequest src_req = requests->requests[i];
+ if (src_req.domain != req.domain) {
+ continue;
+ }
+ if (src_req.layer_index != req.layer_index) {
+ continue;
+ }
+ if (src_req.cd_type != req.cd_type) {
+ continue;
+ }
+ return true;
+ }
+ return false;
+}
+
+static void mesh_attrs_merge_requests(const DRW_MeshAttributes *src_requests,
+ DRW_MeshAttributes *dst_requests)
+{
+ for (int i = 0; i < src_requests->num_requests; i++) {
+ if (dst_requests->num_requests == GPU_MAX_ATTR) {
+ return;
+ }
+
+ if (has_request(dst_requests, src_requests->requests[i])) {
+ continue;
+ }
+
+ dst_requests->requests[dst_requests->num_requests] = src_requests->requests[i];
+ dst_requests->num_requests += 1;
+ }
+}
+
+static void drw_mesh_attributes_clear(DRW_MeshAttributes *attributes)
+{
+ memset(attributes, 0, sizeof(DRW_MeshAttributes));
+}
+
+static void drw_mesh_attributes_merge(DRW_MeshAttributes *dst,
+ const DRW_MeshAttributes *src,
+ ThreadMutex *mesh_render_mutex)
+{
+ BLI_mutex_lock(mesh_render_mutex);
+ mesh_attrs_merge_requests(src, dst);
+ BLI_mutex_unlock(mesh_render_mutex);
+}
+
+/* Return true if all requests in b are in a. */
+static bool drw_mesh_attributes_overlap(DRW_MeshAttributes *a, DRW_MeshAttributes *b)
+{
+ if (a->num_requests != b->num_requests) {
+ return false;
+ }
+
+ for (int i = 0; i < a->num_requests; i++) {
+ if (!has_request(a, b->requests[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void drw_mesh_attributes_add_request(DRW_MeshAttributes *attrs,
+ CustomDataType type,
+ int layer,
+ AttributeDomain domain)
+{
+ if (attrs->num_requests >= GPU_MAX_ATTR) {
+ return;
+ }
+
+ DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests];
+ req->cd_type = type;
+ req->layer_index = layer;
+ req->domain = domain;
+ attrs->num_requests += 1;
+}
+
+/** \} */
+
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
@@ -286,6 +392,36 @@ BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
return &me->ldata;
}
+BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me)
+{
+ switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_MDATA:
+ return &me->pdata;
+ break;
+ case ME_WRAPPER_TYPE_BMESH:
+ return &me->edit_mesh->bm->pdata;
+ break;
+ }
+
+ BLI_assert(0);
+ return &me->pdata;
+}
+
+BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me)
+{
+ switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_MDATA:
+ return &me->edata;
+ break;
+ case ME_WRAPPER_TYPE_BMESH:
+ return &me->edit_mesh->bm->edata;
+ break;
+ }
+
+ BLI_assert(0);
+ return &me->edata;
+}
+
BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
@@ -321,14 +457,14 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd
}
}
-static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
+static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshAttributes *attrs_used)
{
const Mesh *me_final = editmesh_final_or_this(me);
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR);
if (layer != -1) {
- cd_used->sculpt_vcol |= (1 << layer);
+ drw_mesh_attributes_add_request(attrs_used, CD_PROP_COLOR, layer, ATTR_DOMAIN_POINT);
}
}
@@ -343,13 +479,45 @@ static void mesh_cd_calc_active_mloopcol_layer(const Mesh *me, DRW_MeshCDMask *c
}
}
+static bool custom_data_match_attribute(const CustomData *custom_data,
+ const char *name,
+ int *r_layer_index,
+ int *r_type)
+{
+ const int possible_attribute_types[6] = {
+ CD_PROP_BOOL,
+ CD_PROP_INT32,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT2,
+ CD_PROP_FLOAT3,
+ CD_PROP_COLOR,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {
+ const int attr_type = possible_attribute_types[i];
+ int layer_index = CustomData_get_named_layer(custom_data, attr_type, name);
+ if (layer_index == -1) {
+ continue;
+ }
+
+ *r_layer_index = layer_index;
+ *r_type = attr_type;
+ return true;
+ }
+
+ return false;
+}
+
static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
struct GPUMaterial **gpumat_array,
- int gpumat_array_len)
+ int gpumat_array_len,
+ DRW_MeshAttributes *attributes)
{
const Mesh *me_final = editmesh_final_or_this(me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
+ const CustomData *cd_pdata = mesh_cd_pdata_get_from_mesh(me_final);
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
+ const CustomData *cd_edata = mesh_cd_edata_get_from_mesh(me_final);
/* See: DM_vertex_attributes_from_gpu for similar logic */
DRW_MeshCDMask cd_used;
@@ -363,6 +531,8 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
const char *name = gpu_attr->name;
int type = gpu_attr->type;
int layer = -1;
+ /* ATTR_DOMAIN_NUM is standard for "invalid value". */
+ AttributeDomain domain = ATTR_DOMAIN_NUM;
if (type == CD_AUTO_FROM_NAME) {
/* We need to deduct what exact layer is used.
@@ -374,13 +544,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
type = CD_MTFACE;
if (layer == -1) {
- if (U.experimental.use_sculpt_vertex_colors) {
- layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name);
- type = CD_PROP_COLOR;
- }
- }
-
- if (layer == -1) {
layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name);
type = CD_MCOL;
}
@@ -392,6 +555,27 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
}
#endif
if (layer == -1) {
+ /* Try to match a generic attribute, we use the first attribute domain with a
+ * matching name. */
+ if (custom_data_match_attribute(cd_vdata, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_POINT;
+ }
+ else if (custom_data_match_attribute(cd_ldata, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_CORNER;
+ }
+ else if (custom_data_match_attribute(cd_pdata, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_FACE;
+ }
+ else if (custom_data_match_attribute(cd_edata, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_EDGE;
+ }
+ else {
+ layer = -1;
+ domain = ATTR_DOMAIN_NUM;
+ }
+ }
+
+ if (layer == -1) {
continue;
}
}
@@ -432,31 +616,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
}
break;
}
- case CD_PROP_COLOR: {
- /* Sculpt Vertex Colors */
- bool use_mloop_cols = false;
- if (layer == -1) {
- layer = (name[0] != '\0') ?
- CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name) :
- CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR);
- /* Fallback to Vertex Color data */
- if (layer == -1) {
- layer = (name[0] != '\0') ?
- CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name) :
- CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL);
- use_mloop_cols = true;
- }
- }
- if (layer != -1) {
- if (use_mloop_cols) {
- cd_used.vcol |= (1 << layer);
- }
- else {
- cd_used.sculpt_vcol |= (1 << layer);
- }
- }
- break;
- }
case CD_MCOL: {
/* Vertex Color Data */
if (layer == -1) {
@@ -473,6 +632,17 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
cd_used.orco = 1;
break;
}
+ case CD_PROP_BOOL:
+ case CD_PROP_INT32:
+ case CD_PROP_FLOAT:
+ case CD_PROP_FLOAT2:
+ case CD_PROP_FLOAT3:
+ case CD_PROP_COLOR: {
+ if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
+ drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ }
+ break;
+ }
}
}
}
@@ -935,14 +1105,14 @@ static void texpaint_request_active_vcol(MeshBatchCache *cache, Mesh *me)
static void sculpt_request_active_vcol(MeshBatchCache *cache, Mesh *me)
{
- DRW_MeshCDMask cd_needed;
- mesh_cd_layers_type_clear(&cd_needed);
- mesh_cd_calc_active_vcol_layer(me, &cd_needed);
+ DRW_MeshAttributes attrs_needed;
+ drw_mesh_attributes_clear(&attrs_needed);
+ mesh_cd_calc_active_vcol_layer(me, &attrs_needed);
- BLI_assert(cd_needed.sculpt_vcol != 0 &&
+ BLI_assert(attrs_needed.num_requests != 0 &&
"No MPropCol layer available in Sculpt, but batches requested anyway!");
- mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
+ drw_mesh_attributes_merge(&cache->attr_needed, &attrs_needed, me->runtime.render_mutex);
}
GPUBatch *DRW_mesh_batch_cache_get_all_verts(Mesh *me)
@@ -1015,11 +1185,16 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
uint gpumat_array_len)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(me, gpumat_array, gpumat_array_len);
+ DRW_MeshAttributes attrs_needed;
+ drw_mesh_attributes_clear(&attrs_needed);
+ DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(
+ me, gpumat_array, gpumat_array_len, &attrs_needed);
BLI_assert(gpumat_array_len == cache->mat_len);
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
+ ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
+ drw_mesh_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
mesh_batch_cache_request_surface_batches(cache);
return cache->surface_per_mat;
}
@@ -1296,11 +1471,25 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
cache->lastmatch = ctime;
}
+ if (drw_mesh_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) {
+ cache->lastmatch = ctime;
+ }
+
if (ctime - cache->lastmatch > U.vbotimeout) {
mesh_batch_cache_discard_shaded_tri(cache);
}
mesh_cd_layers_type_clear(&cache->cd_used_over_time);
+ drw_mesh_attributes_clear(&cache->attr_used_over_time);
+}
+
+static void drw_add_attributes_vbo(GPUBatch *batch,
+ MeshBufferList *mbuflist,
+ DRW_MeshAttributes *attr_used)
+{
+ for (int i = 0; i < attr_used->num_requests; i++) {
+ DRW_vbo_request(batch, &mbuflist->vbo.attr[i]);
+ }
}
#ifdef DEBUG
@@ -1409,12 +1598,15 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
}
+ ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
+
/* Verify that all surface batches have needed attribute layers.
*/
/* TODO(fclem): We could be a bit smarter here and only do it per
* material. */
bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed);
- if (cd_overlap == false) {
+ bool attr_overlap = drw_mesh_attributes_overlap(&cache->attr_used, &cache->attr_needed);
+ if (cd_overlap == false || attr_overlap == false) {
FOREACH_MESH_BUFFER_CACHE (cache, mbc) {
if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv);
@@ -1430,11 +1622,14 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (cache->cd_used.sculpt_overlays != cache->cd_needed.sculpt_overlays) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.sculpt_data);
}
- if (((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) ||
- ((cache->cd_used.sculpt_vcol & cache->cd_needed.sculpt_vcol) !=
- cache->cd_needed.sculpt_vcol)) {
+ if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol);
}
+ if (!drw_mesh_attributes_overlap(&cache->attr_used, &cache->attr_needed)) {
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.attr[i]);
+ }
+ }
}
/* We can't discard batches at this point as they have been
* referenced for drawing. Just clear them in place. */
@@ -1445,9 +1640,13 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
cache->batch_ready &= ~(MBC_SURFACE);
mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed);
+ drw_mesh_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex);
}
mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed);
mesh_cd_layers_type_clear(&cache->cd_needed);
+
+ drw_mesh_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex);
+ drw_mesh_attributes_clear(&cache->attr_needed);
}
if (batch_requested & MBC_EDITUV) {
@@ -1506,7 +1705,27 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
MeshBufferList *mbuflist = &cache->final.buff;
/* Initialize batches and request VBO's & IBO's. */
- MDEPS_ASSERT(surface, ibo.tris, vbo.lnor, vbo.pos_nor, vbo.uv, vbo.vcol);
+ MDEPS_ASSERT(surface,
+ ibo.tris,
+ vbo.lnor,
+ vbo.pos_nor,
+ vbo.uv,
+ vbo.vcol,
+ vbo.attr[0],
+ vbo.attr[1],
+ vbo.attr[2],
+ vbo.attr[3],
+ vbo.attr[4],
+ vbo.attr[5],
+ vbo.attr[6],
+ vbo.attr[7],
+ vbo.attr[8],
+ vbo.attr[9],
+ vbo.attr[10],
+ vbo.attr[11],
+ vbo.attr[12],
+ vbo.attr[13],
+ vbo.attr[14]);
if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface, &mbuflist->ibo.tris);
/* Order matters. First ones override latest VBO's attributes. */
@@ -1515,9 +1734,10 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (cache->cd_used.uv != 0) {
DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.uv);
}
- if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) {
+ if (cache->cd_used.vcol != 0) {
DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.vcol);
}
+ drw_add_attributes_vbo(cache->batch.surface, mbuflist, &cache->attr_used);
}
MDEPS_ASSERT(all_verts, vbo.pos_nor);
if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) {
@@ -1580,8 +1800,28 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
/* Per Material */
- MDEPS_ASSERT_FLAG(
- SURFACE_PER_MAT_FLAG, vbo.lnor, vbo.pos_nor, vbo.uv, vbo.tan, vbo.vcol, vbo.orco);
+ MDEPS_ASSERT_FLAG(SURFACE_PER_MAT_FLAG,
+ vbo.lnor,
+ vbo.pos_nor,
+ vbo.uv,
+ vbo.tan,
+ vbo.vcol,
+ vbo.orco,
+ vbo.attr[0],
+ vbo.attr[1],
+ vbo.attr[2],
+ vbo.attr[3],
+ vbo.attr[4],
+ vbo.attr[5],
+ vbo.attr[6],
+ vbo.attr[7],
+ vbo.attr[8],
+ vbo.attr[9],
+ vbo.attr[10],
+ vbo.attr[11],
+ vbo.attr[12],
+ vbo.attr[13],
+ vbo.attr[14]);
MDEPS_ASSERT_INDEX(TRIS_PER_MAT_INDEX, SURFACE_PER_MAT_FLAG);
for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
@@ -1595,12 +1835,13 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if ((cache->cd_used.tan != 0) || (cache->cd_used.tan_orco != 0)) {
DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.tan);
}
- if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) {
+ if (cache->cd_used.vcol != 0) {
DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.vcol);
}
if (cache->cd_used.orco != 0) {
DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.orco);
}
+ drw_add_attributes_vbo(cache->surface_per_mat[i], mbuflist, &cache->attr_used);
}
}
@@ -1751,6 +1992,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
MDEPS_ASSERT_MAP(vbo.edituv_stretch_angle);
MDEPS_ASSERT_MAP(vbo.fdots_uv);
MDEPS_ASSERT_MAP(vbo.fdots_edituv_data);
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ MDEPS_ASSERT_MAP(vbo.attr[i]);
+ }
MDEPS_ASSERT_MAP(ibo.tris);
MDEPS_ASSERT_MAP(ibo.lines);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index f96bd474aec..5d3e3db866f 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -1684,10 +1684,12 @@ static void draw_frustum_bound_sphere_calc(const BoundBox *bbox,
bsphere->center[0] = farcenter[0] * z / e;
bsphere->center[1] = farcenter[1] * z / e;
bsphere->center[2] = z;
- bsphere->radius = len_v3v3(bsphere->center, farpoint);
- /* Transform to world space. */
- mul_m4_v3(viewinv, bsphere->center);
+ /* For XR, the view matrix may contain a scale factor. Then, transforming only the center
+ * into world space after calculating the radius will result in incorrect behavior. */
+ mul_m4_v3(viewinv, bsphere->center); /* Transform to world space. */
+ mul_m4_v3(viewinv, farpoint);
+ bsphere->radius = len_v3v3(bsphere->center, farpoint);
}
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
index d9f397fd8b8..d1ffef4fe92 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
@@ -328,6 +328,7 @@ extern const MeshExtract extract_poly_idx;
extern const MeshExtract extract_edge_idx;
extern const MeshExtract extract_vert_idx;
extern const MeshExtract extract_fdot_idx;
+extern const MeshExtract extract_attr[GPU_MAX_ATTR];
#ifdef __cplusplus
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
new file mode 100644
index 00000000000..9edefe32fbc
--- /dev/null
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -0,0 +1,398 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include <functional>
+
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
+#include "BLI_float4.hh"
+#include "BLI_string.h"
+
+#include "BKE_attribute.h"
+
+#include "extract_mesh.h"
+
+namespace blender::draw {
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Attributes
+ * \{ */
+
+static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, AttributeDomain domain)
+{
+ switch (domain) {
+ default: {
+ return nullptr;
+ }
+ case ATTR_DOMAIN_POINT: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ }
+ case ATTR_DOMAIN_FACE: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata;
+ }
+ }
+}
+
+/* Utility to convert from the type used in the attributes to the types for the VBO.
+ * This is mostly used to promote integers and booleans to floats, as other types (float, float2,
+ * etc.) directly map to available GPU types. Booleans are still converted as attributes are vec4
+ * in the shader.
+ */
+template<typename AttributeType, typename VBOType> struct attribute_type_converter {
+ static VBOType convert_value(AttributeType value)
+ {
+ if constexpr (std::is_same_v<AttributeType, VBOType>) {
+ return value;
+ }
+
+ /* This should only concern bools which are converted to floats. */
+ return static_cast<VBOType>(value);
+ }
+};
+
+/* Similar to the one in #extract_mesh_vcol_vbo.cc */
+struct gpuMeshCol {
+ ushort r, g, b, a;
+};
+
+template<> struct attribute_type_converter<MPropCol, gpuMeshCol> {
+ static gpuMeshCol convert_value(MPropCol value)
+ {
+ gpuMeshCol result;
+ result.r = unit_float_to_ushort_clamp(value.color[0]);
+ result.g = unit_float_to_ushort_clamp(value.color[1]);
+ result.b = unit_float_to_ushort_clamp(value.color[2]);
+ result.a = unit_float_to_ushort_clamp(value.color[3]);
+ return result;
+ }
+};
+
+/* Return the number of component for the attribute's value type, or 0 if is it unsupported. */
+static uint gpu_component_size_for_attribute_type(CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_BOOL:
+ case CD_PROP_INT32:
+ case CD_PROP_FLOAT: {
+ /* TODO(kevindietrich) : should be 1 when scalar attributes conversion is handled by us. See
+ * comment #extract_attr_init. */
+ return 3;
+ }
+ case CD_PROP_FLOAT2: {
+ return 2;
+ }
+ case CD_PROP_FLOAT3: {
+ return 3;
+ }
+ case CD_PROP_COLOR: {
+ return 4;
+ }
+ default: {
+ return 0;
+ }
+ }
+}
+
+static GPUVertFetchMode get_fetch_mode_for_type(CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_INT32: {
+ return GPU_FETCH_INT_TO_FLOAT;
+ }
+ case CD_PROP_COLOR: {
+ return GPU_FETCH_INT_TO_FLOAT_UNIT;
+ }
+ default: {
+ return GPU_FETCH_FLOAT;
+ }
+ }
+}
+
+static GPUVertCompType get_comp_type_for_type(CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_INT32: {
+ return GPU_COMP_I32;
+ }
+ case CD_PROP_COLOR: {
+ return GPU_COMP_U16;
+ }
+ default: {
+ return GPU_COMP_F32;
+ }
+ }
+}
+
+static void init_vbo_for_attribute(const MeshRenderData *mr,
+ GPUVertBuf *vbo,
+ const DRW_AttributeRequest &request)
+{
+ GPUVertCompType comp_type = get_comp_type_for_type(request.cd_type);
+ GPUVertFetchMode fetch_mode = get_fetch_mode_for_type(request.cd_type);
+ const uint comp_size = gpu_component_size_for_attribute_type(request.cd_type);
+ /* We should not be here if the attribute type is not supported. */
+ BLI_assert(comp_size != 0);
+
+ const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain);
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ const char *layer_name = CustomData_get_layer_name(
+ custom_data, request.cd_type, request.layer_index);
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+ /* Attributes use auto-name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+ GPU_vertformat_attr_add(&format, attr_name, comp_type, comp_size, fetch_mode);
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, static_cast<uint32_t>(mr->loop_len));
+}
+
+template<typename AttributeType, typename VBOType>
+static void fill_vertbuf_with_attribute(const MeshRenderData *mr,
+ VBOType *vbo_data,
+ const DRW_AttributeRequest &request)
+{
+ const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain);
+ BLI_assert(custom_data);
+ const int layer_index = request.layer_index;
+
+ const MPoly *mpoly = mr->mpoly;
+ const MLoop *mloop = mr->mloop;
+
+ const AttributeType *attr_data = static_cast<AttributeType *>(
+ CustomData_get_layer_n(custom_data, request.cd_type, layer_index));
+
+ using converter = attribute_type_converter<AttributeType, VBOType>;
+
+ switch (request.domain) {
+ default: {
+ BLI_assert(false);
+ break;
+ }
+ case ATTR_DOMAIN_POINT: {
+ for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
+ *vbo_data = converter::convert_value(attr_data[mloop->v]);
+ }
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++) {
+ *vbo_data = converter::convert_value(attr_data[ml_index]);
+ }
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
+ *vbo_data = converter::convert_value(attr_data[mloop->e]);
+ }
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
+ const MPoly &poly = mpoly[mp_index];
+ const VBOType value = converter::convert_value(attr_data[mp_index]);
+ for (int l = 0; l < poly.totloop; l++) {
+ *vbo_data++ = value;
+ }
+ }
+ break;
+ }
+ }
+}
+
+template<typename AttributeType, typename VBOType>
+static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
+ VBOType *&vbo_data,
+ const DRW_AttributeRequest &request)
+{
+ const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain);
+ BLI_assert(custom_data);
+ const int layer_index = request.layer_index;
+
+ int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
+
+ using converter = attribute_type_converter<AttributeType, VBOType>;
+
+ BMIter f_iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const AttributeType *attr_data = nullptr;
+ if (request.domain == ATTR_DOMAIN_POINT) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs));
+ }
+ else if (request.domain == ATTR_DOMAIN_CORNER) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs));
+ }
+ else if (request.domain == ATTR_DOMAIN_FACE) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(efa, cd_ofs));
+ }
+ else if (request.domain == ATTR_DOMAIN_EDGE) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs));
+ }
+ else {
+ BLI_assert(false);
+ continue;
+ }
+ *vbo_data = converter::convert_value(*attr_data);
+ vbo_data++;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+}
+
+template<typename AttributeType, typename VBOType = AttributeType>
+static void extract_attr_generic(const MeshRenderData *mr,
+ GPUVertBuf *vbo,
+ const DRW_AttributeRequest &request)
+{
+ VBOType *vbo_data = static_cast<VBOType *>(GPU_vertbuf_get_data(vbo));
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ fill_vertbuf_with_attribute_bm<AttributeType>(mr, vbo_data, request);
+ }
+ else {
+ fill_vertbuf_with_attribute<AttributeType>(mr, vbo_data, request);
+ }
+}
+
+static void extract_attr_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data),
+ int index)
+{
+ const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_AttributeRequest &request = attrs_used->requests[index];
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+
+ init_vbo_for_attribute(mr, vbo, request);
+
+ /* TODO(kevindietrich) : float3 is used for scalar attributes as the implicit conversion done by
+ * OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following the
+ * Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a similar
+ * texture as for volume attribute, so we can control the conversion ourselves. */
+ switch (request.cd_type) {
+ case CD_PROP_BOOL: {
+ extract_attr_generic<bool, float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_INT32: {
+ extract_attr_generic<int32_t, float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_FLOAT: {
+ extract_attr_generic<float, float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_FLOAT2: {
+ extract_attr_generic<float2>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ extract_attr_generic<float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_COLOR: {
+ extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request);
+ break;
+ }
+ default: {
+ BLI_assert(false);
+ }
+ }
+}
+
+/* Wrappers around extract_attr_init so we can pass the index of the attribute that we want to
+ * extract. The overall API does not allow us to pass this in a convenient way. */
+#define EXTRACT_INIT_WRAPPER(index) \
+ static void extract_attr_init##index( \
+ const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \
+ { \
+ extract_attr_init(mr, cache, buf, tls_data, index); \
+ }
+
+EXTRACT_INIT_WRAPPER(0)
+EXTRACT_INIT_WRAPPER(1)
+EXTRACT_INIT_WRAPPER(2)
+EXTRACT_INIT_WRAPPER(3)
+EXTRACT_INIT_WRAPPER(4)
+EXTRACT_INIT_WRAPPER(5)
+EXTRACT_INIT_WRAPPER(6)
+EXTRACT_INIT_WRAPPER(7)
+EXTRACT_INIT_WRAPPER(8)
+EXTRACT_INIT_WRAPPER(9)
+EXTRACT_INIT_WRAPPER(10)
+EXTRACT_INIT_WRAPPER(11)
+EXTRACT_INIT_WRAPPER(12)
+EXTRACT_INIT_WRAPPER(13)
+EXTRACT_INIT_WRAPPER(14)
+
+template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn)
+{
+ MeshExtract extractor = {nullptr};
+ extractor.init = fn;
+ extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = 0;
+ extractor.use_threading = false;
+ extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]);
+ return extractor;
+}
+
+/** \} */
+
+} // namespace blender::draw
+
+extern "C" {
+#define CREATE_EXTRACTOR_ATTR(index) \
+ blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index)
+
+const MeshExtract extract_attr[GPU_MAX_ATTR] = {
+ CREATE_EXTRACTOR_ATTR(0),
+ CREATE_EXTRACTOR_ATTR(1),
+ CREATE_EXTRACTOR_ATTR(2),
+ CREATE_EXTRACTOR_ATTR(3),
+ CREATE_EXTRACTOR_ATTR(4),
+ CREATE_EXTRACTOR_ATTR(5),
+ CREATE_EXTRACTOR_ATTR(6),
+ CREATE_EXTRACTOR_ATTR(7),
+ CREATE_EXTRACTOR_ATTR(8),
+ CREATE_EXTRACTOR_ATTR(9),
+ CREATE_EXTRACTOR_ATTR(10),
+ CREATE_EXTRACTOR_ATTR(11),
+ CREATE_EXTRACTOR_ATTR(12),
+ CREATE_EXTRACTOR_ATTR(13),
+ CREATE_EXTRACTOR_ATTR(14),
+};
+}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
index 2c7770c8e72..f8878eb2617 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
@@ -43,9 +43,7 @@ static void extract_vcol_init(const MeshRenderData *mr,
GPU_vertformat_deinterleave(&format);
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
- CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
uint32_t vcol_layers = cache->cd_used.vcol;
- uint32_t svcol_layers = cache->cd_used.sculpt_vcol;
for (int i = 0; i < MAX_MCOL; i++) {
if (vcol_layers & (1 << i)) {
@@ -64,42 +62,14 @@ static void extract_vcol_init(const MeshRenderData *mr,
}
/* Gather number of auto layers. */
- /* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */
- if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1 &&
- CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, layer_name) == -1) {
+ /* We only do `vcols` that are not overridden by `uvs`. */
+ if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
GPU_vertformat_alias_add(&format, attr_name);
}
}
}
- /* Sculpt Vertex Colors */
- if (U.experimental.use_sculpt_vertex_colors) {
- for (int i = 0; i < 8; i++) {
- if (svcol_layers & (1 << i)) {
- char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
- const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i);
- GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
-
- BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
-
- if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) {
- GPU_vertformat_alias_add(&format, "c");
- }
- if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) {
- GPU_vertformat_alias_add(&format, "ac");
- }
- /* Gather number of auto layers. */
- /* We only do `vcols` that are not overridden by `uvs`. */
- if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
- BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
- GPU_vertformat_alias_add(&format, attr_name);
- }
- }
- }
- }
-
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -108,7 +78,6 @@ static void extract_vcol_init(const MeshRenderData *mr,
};
gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
- MLoop *loops = (MLoop *)CustomData_get_layer(cd_ldata, CD_MLOOP);
for (int i = 0; i < MAX_MCOL; i++) {
if (vcol_layers & (1 << i)) {
@@ -139,35 +108,6 @@ static void extract_vcol_init(const MeshRenderData *mr,
}
}
}
-
- if (svcol_layers & (1 << i) && U.experimental.use_sculpt_vertex_colors) {
- if (mr->extract_type == MR_EXTRACT_BMESH) {
- int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i);
- BMIter f_iter;
- BMFace *efa;
- BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const MPropCol *prop_col = (const MPropCol *)BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs);
- vcol_data->r = unit_float_to_ushort_clamp(prop_col->color[0]);
- vcol_data->g = unit_float_to_ushort_clamp(prop_col->color[1]);
- vcol_data->b = unit_float_to_ushort_clamp(prop_col->color[2]);
- vcol_data->a = unit_float_to_ushort_clamp(prop_col->color[3]);
- vcol_data++;
- } while ((l_iter = l_iter->next) != l_first);
- }
- }
- else {
- MPropCol *vcol = (MPropCol *)CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i);
- for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vcol_data++) {
- vcol_data->r = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[0]);
- vcol_data->g = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[1]);
- vcol_data->b = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[2]);
- vcol_data->a = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[3]);
- }
- }
- }
}
}
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index afbd9b2c92d..69fabd004cc 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -51,6 +51,7 @@
#include "BKE_mask.h"
#include "BKE_nla.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -2522,10 +2523,10 @@ static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Find / Set Filter Operator ******************** */
+/* ****************** Select Filter Textbox Operator ******************** */
/* XXX: make this generic? */
-static bool animchannels_find_poll(bContext *C)
+static bool animchannels_select_filter_poll(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -2537,64 +2538,62 @@ static bool animchannels_find_poll(bContext *C)
return ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA);
}
-/* find_invoke() - Get initial channels */
-static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int animchannels_select_filter_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const struct wmEvent *UNUSED(event))
{
- bAnimContext ac;
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region_ctx = CTX_wm_region(C);
+ ARegion *region_channels = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS);
- /* get editor data */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return OPERATOR_CANCELLED;
+ CTX_wm_region_set(C, region_channels);
+
+ /* Show the channel region if it's hidden. This means that direct activation of the input field
+ * is impossible, as it may not exist yet. For that reason, the actual activation is deferred to
+ * the modal callback function; by the time it runs, the screen has been redrawn and the UI
+ * element is there to activate. */
+ if (region_channels->flag & RGN_FLAG_HIDDEN) {
+ ED_region_toggle_hidden(C, region_channels);
+ ED_region_tag_redraw(region_channels);
}
- /* set initial filter text, and enable filter */
- RNA_string_set(op->ptr, "query", ac.ads->searchstr);
+ WM_event_add_modal_handler(C, op);
- /* defer to popup */
- return WM_operator_props_popup(C, op, event);
+ CTX_wm_region_set(C, region_ctx);
+ return OPERATOR_RUNNING_MODAL;
}
-/* find_exec() - Called to set the value */
-static int animchannels_find_exec(bContext *C, wmOperator *op)
+static int animchannels_select_filter_modal(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(event))
{
bAnimContext ac;
-
- /* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
return OPERATOR_CANCELLED;
}
- /* update filter text */
- RNA_string_get(op->ptr, "query", ac.ads->searchstr);
-
- /* redraw */
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ ARegion *region = CTX_wm_region(C);
+ if (UI_textbutton_activate_rna(C, region, ac.ads, "filter_text")) {
+ /* Redraw to make sure it shows the cursor after activating */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
-static void ANIM_OT_channels_find(wmOperatorType *ot)
+static void ANIM_OT_channels_select_filter(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Find Channels";
- ot->idname = "ANIM_OT_channels_find";
- ot->description = "Filter the set of channels shown to only include those with matching names";
+ ot->name = "Filter Channels";
+ ot->idname = "ANIM_OT_channels_select_filter";
+ ot->description =
+ "Start entering text which filters the set of channels shown to only include those with "
+ "matching names";
/* callbacks */
- ot->invoke = animchannels_find_invoke;
- ot->exec = animchannels_find_exec;
- ot->poll = animchannels_find_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_string(ot->srna,
- "query",
- "Query",
- sizeof(((bDopeSheet *)NULL)->searchstr),
- "",
- "Text to search for in channel names");
+ ot->invoke = animchannels_select_filter_invoke;
+ ot->modal = animchannels_select_filter_modal;
+ ot->poll = animchannels_select_filter_poll;
}
/* ********************** Select All Operator *********************** */
@@ -3563,7 +3562,7 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channel_select_keys);
WM_operatortype_append(ANIM_OT_channels_rename);
- WM_operatortype_append(ANIM_OT_channels_find);
+ WM_operatortype_append(ANIM_OT_channels_select_filter);
WM_operatortype_append(ANIM_OT_channels_setting_enable);
WM_operatortype_append(ANIM_OT_channels_setting_disable);
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index bd799c00373..937385f9ffa 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -673,11 +673,7 @@ static EditBone *get_nearest_editbonepoint(
}
if (use_cycle) {
- static int last_mval[2] = {-100, -100};
- if ((len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) == 0) {
- use_cycle = false;
- }
- copy_v2_v2_int(last_mval, vc->mval);
+ use_cycle = !WM_cursor_test_motion_and_update(vc->mval);
}
const bool do_nearest = !(XRAY_ACTIVE(vc->v3d) || use_cycle);
diff --git a/source/blender/editors/asset/ED_asset_catalog.hh b/source/blender/editors/asset/ED_asset_catalog.hh
index 8b8fc4d3574..8da8fc0d6c9 100644
--- a/source/blender/editors/asset/ED_asset_catalog.hh
+++ b/source/blender/editors/asset/ED_asset_catalog.hh
@@ -37,3 +37,6 @@ void ED_asset_catalog_remove(AssetLibrary *library, const blender::bke::CatalogI
void ED_asset_catalog_rename(AssetLibrary *library,
blender::bke::CatalogID catalog_id,
blender::StringRefNull new_name);
+void ED_asset_catalog_move(AssetLibrary *library,
+ blender::bke::CatalogID src_catalog_id,
+ blender::bke::CatalogID dst_parent_catalog_id);
diff --git a/source/blender/editors/asset/ED_asset_mark_clear.h b/source/blender/editors/asset/ED_asset_mark_clear.h
index bab1d1bf8a5..8e6a8e11d69 100644
--- a/source/blender/editors/asset/ED_asset_mark_clear.h
+++ b/source/blender/editors/asset/ED_asset_mark_clear.h
@@ -26,6 +26,7 @@ extern "C" {
struct ID;
struct bContext;
+struct Main;
/**
* Mark the datablock as asset.
@@ -52,6 +53,8 @@ void ED_asset_generate_preview(const struct bContext *C, struct ID *id);
* \return whether the asset metadata was actually removed; false when the ID was not an asset. */
bool ED_asset_clear_id(struct ID *id);
+void ED_assets_pre_save(struct Main *bmain);
+
bool ED_asset_can_mark_single_from_context(const struct bContext *C);
#ifdef __cplusplus
diff --git a/source/blender/editors/asset/ED_asset_type.h b/source/blender/editors/asset/ED_asset_type.h
index 5629ae189c0..36cbb4591e9 100644
--- a/source/blender/editors/asset/ED_asset_type.h
+++ b/source/blender/editors/asset/ED_asset_type.h
@@ -29,7 +29,8 @@ extern "C" {
struct ID;
bool ED_asset_type_id_is_non_experimental(const struct ID *id);
-#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS (FILTER_ID_MA | FILTER_ID_AC | FILTER_ID_WO)
+#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS \
+ (FILTER_ID_MA | FILTER_ID_OB | FILTER_ID_AC | FILTER_ID_WO)
/**
* Check if the asset type for \a id (which doesn't need to be an asset right now) can be an asset,
@@ -51,7 +52,7 @@ int64_t ED_asset_types_supported_as_filter_flags(void);
* strings with this (not all UI code supports dynamic strings nicely).
* Should start with a consonant, so usages can prefix it with "a" (not "an").
*/
-#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING "Material, Pose Action, or World"
+#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING "Material, Object, Pose Action, or World"
#ifdef __cplusplus
}
diff --git a/source/blender/editors/asset/intern/asset_catalog.cc b/source/blender/editors/asset/intern/asset_catalog.cc
index dae960cbb0a..8e1e5be2e47 100644
--- a/source/blender/editors/asset/intern/asset_catalog.cc
+++ b/source/blender/editors/asset/intern/asset_catalog.cc
@@ -107,17 +107,44 @@ void ED_asset_catalog_rename(::AssetLibrary *library,
AssetCatalog *catalog = catalog_service->find_catalog(catalog_id);
- AssetCatalogPath new_path = catalog->path.parent();
- new_path = new_path / StringRef(new_name);
+ const AssetCatalogPath new_path = catalog->path.parent() / StringRef(new_name);
+ const AssetCatalogPath clean_new_path = new_path.cleanup();
- if (new_path == catalog->path) {
+ if (new_path == catalog->path || clean_new_path == catalog->path) {
/* Nothing changed, so don't bother renaming for nothing. */
return;
}
catalog_service->undo_push();
catalog_service->tag_has_unsaved_changes(catalog);
- catalog_service->update_catalog_path(catalog_id, new_path);
+ catalog_service->update_catalog_path(catalog_id, clean_new_path);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+}
+
+void ED_asset_catalog_move(::AssetLibrary *library,
+ const CatalogID src_catalog_id,
+ const CatalogID dst_parent_catalog_id)
+{
+ bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library);
+ if (!catalog_service) {
+ BLI_assert_unreachable();
+ return;
+ }
+
+ AssetCatalog *src_catalog = catalog_service->find_catalog(src_catalog_id);
+ AssetCatalog *dst_catalog = catalog_service->find_catalog(dst_parent_catalog_id);
+
+ const AssetCatalogPath new_path = dst_catalog->path / StringRef(src_catalog->path.name());
+ const AssetCatalogPath clean_new_path = new_path.cleanup();
+
+ if (new_path == src_catalog->path || clean_new_path == src_catalog->path) {
+ /* Nothing changed, so don't bother renaming for nothing. */
+ return;
+ }
+
+ catalog_service->undo_push();
+ catalog_service->tag_has_unsaved_changes(src_catalog);
+ catalog_service->update_catalog_path(src_catalog_id, clean_new_path);
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
}
diff --git a/source/blender/editors/asset/intern/asset_mark_clear.cc b/source/blender/editors/asset/intern/asset_mark_clear.cc
index 4be7376a1c3..eb254dcd28b 100644
--- a/source/blender/editors/asset/intern/asset_mark_clear.cc
+++ b/source/blender/editors/asset/intern/asset_mark_clear.cc
@@ -25,7 +25,9 @@
#include "BKE_asset.h"
#include "BKE_context.h"
+#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_main.h"
#include "BLO_readfile.h"
@@ -52,7 +54,9 @@ bool ED_asset_mark_id(ID *id)
id_fake_user_set(id);
+ const IDTypeInfo *id_type_info = BKE_idtype_get_info_from_id(id);
id->asset_data = BKE_asset_metadata_create();
+ id->asset_data->local_type_info = id_type_info->asset_type_info;
/* Important for asset storage to update properly! */
ED_assetlist_storage_tag_main_data_dirty();
@@ -79,6 +83,21 @@ bool ED_asset_clear_id(ID *id)
return true;
}
+void ED_assets_pre_save(struct Main *bmain)
+{
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (!id->asset_data || !id->asset_data->local_type_info) {
+ continue;
+ }
+
+ if (id->asset_data->local_type_info->pre_save_fn) {
+ id->asset_data->local_type_info->pre_save_fn(id, id->asset_data);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+}
+
bool ED_asset_can_mark_single_from_context(const bContext *C)
{
/* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index e2ae3b3893b..d2fd8ab88a4 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -427,7 +427,12 @@ static int asset_catalog_new_exec(bContext *C, wmOperator *op)
struct AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
char *parent_path = RNA_string_get_alloc(op->ptr, "parent_path", nullptr, 0, nullptr);
- ED_asset_catalog_add(asset_library, "Catalog", parent_path);
+ blender::bke::AssetCatalog *new_catalog = ED_asset_catalog_add(
+ asset_library, "Catalog", parent_path);
+
+ if (sfile) {
+ ED_fileselect_activate_asset_catalog(sfile, new_catalog->catalog_id);
+ }
MEM_freeN(parent_path);
@@ -554,7 +559,7 @@ static bool asset_catalog_redo_poll(bContext *C)
static void ASSET_OT_catalog_redo(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "redo Catalog Edits";
+ ot->name = "Redo Catalog Edits";
ot->description = "Redo the last undone edit to the asset catalogs";
ot->idname = "ASSET_OT_catalog_redo";
diff --git a/source/blender/editors/asset/intern/asset_type.cc b/source/blender/editors/asset/intern/asset_type.cc
index cdff538a712..028c0cb9ffc 100644
--- a/source/blender/editors/asset/intern/asset_type.cc
+++ b/source/blender/editors/asset/intern/asset_type.cc
@@ -30,7 +30,7 @@ bool ED_asset_type_id_is_non_experimental(const ID *id)
{
/* Remember to update #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING and
* #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS() with this! */
- return ELEM(GS(id->name), ID_MA, ID_AC, ID_WO);
+ return ELEM(GS(id->name), ID_MA, ID_OB, ID_AC, ID_WO);
}
bool ED_asset_type_is_supported(const ID *id)
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
index 07117c0153b..aed58e31798 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -220,7 +220,7 @@ static void cage3d_draw_circle_wire(const float r[3],
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", line_width * U.pixelsize);
- imm_draw_cube_wire_3d(pos, (float[3]){0}, r);
+ imm_draw_cube_wire_3d(pos, (const float[3]){0}, r);
#if 0
if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE) {
diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
index 33532bd0549..93ee6ec2d81 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -225,8 +225,10 @@ static void snap_gizmo_setup(wmGizmo *gz)
gz->flag |= WM_GIZMO_NO_TOOLTIP;
SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
snap_gizmo->snap_state = ED_view3d_cursor_snap_active();
- snap_gizmo->snap_state->draw_point = true;
- snap_gizmo->snap_state->draw_plane = false;
+ if (snap_gizmo->snap_state) {
+ snap_gizmo->snap_state->draw_point = true;
+ snap_gizmo->snap_state->draw_plane = false;
+ }
rgba_float_to_uchar(snap_gizmo->snap_state->color_point, gz->color);
}
@@ -284,7 +286,9 @@ static int snap_gizmo_invoke(bContext *UNUSED(C),
static void snap_gizmo_free(wmGizmo *gz)
{
SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- ED_view3d_cursor_snap_deactive(snap_gizmo->snap_state);
+ if (snap_gizmo->snap_state) {
+ ED_view3d_cursor_snap_deactive(snap_gizmo->snap_state);
+ }
}
static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 3beabaf2d1d..68b6e44371c 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -23,6 +23,8 @@
#pragma once
+#include "DNA_uuid_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -145,7 +147,9 @@ bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile);
struct AssetLibrary *ED_fileselect_active_asset_library_get(const struct SpaceFile *sfile);
struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile);
-/* Activate the file that corresponds to the given ID.
+void ED_fileselect_activate_asset_catalog(const struct SpaceFile *sfile, bUUID catalog_id);
+
+/* Activate and select the file that corresponds to the given ID.
* Pass deferred=true to wait for the next refresh before activating. */
void ED_fileselect_activate_by_id(struct SpaceFile *sfile,
struct ID *asset_id,
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 1d51a3e77cf..e68617f7867 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -49,7 +49,7 @@ typedef enum {
NODE_RIGHT = 8,
} NodeBorder;
-#define NODE_GRID_STEPS 5
+#define NODE_GRID_STEP_SIZE 10
#define NODE_EDGE_PAN_INSIDE_PAD 2
#define NODE_EDGE_PAN_OUTSIDE_PAD 0 /* Disable clamping for node panning, use whole screen. */
#define NODE_EDGE_PAN_SPEED_RAMP 1
@@ -64,7 +64,6 @@ void ED_node_cursor_location_set(struct SpaceNode *snode, const float value[2]);
int ED_node_tree_path_length(struct SpaceNode *snode);
void ED_node_tree_path_get(struct SpaceNode *snode, char *value);
-void ED_node_tree_path_get_fixedbuf(struct SpaceNode *snode, char *value, int max_length);
void ED_node_tree_start(struct SpaceNode *snode,
struct bNodeTree *ntree,
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 083d167c573..2a557f1abd3 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -122,6 +122,8 @@ void ED_object_xform_skip_child_container_item_ensure(struct XFormObjectSkipChil
struct Object *ob_parent_recurse,
int mode);
+void ED_object_xform_array_m4(struct Object **objects, uint objects_len, const float matrix[4][4]);
+
/* object_ops.c */
void ED_operatortypes_object(void);
void ED_operatormacros_object(void);
@@ -202,7 +204,7 @@ void ED_object_parent(struct Object *ob,
const char *substr);
char *ED_object_ot_drop_named_material_tooltip(struct bContext *C,
struct PointerRNA *properties,
- const struct wmEvent *event);
+ const int mval[2]);
/* bitflags for enter/exit editmode */
enum {
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index b90c7f27c57..08b6c02a8d0 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -317,6 +317,7 @@ bool ED_operator_regionactive(struct bContext *C);
bool ED_operator_scene(struct bContext *C);
bool ED_operator_scene_editable(struct bContext *C);
bool ED_operator_objectmode(struct bContext *C);
+bool ED_operator_objectmode_poll_msg(struct bContext *C);
bool ED_operator_view3d_active(struct bContext *C);
bool ED_operator_region_view3d_active(struct bContext *C);
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index 7002db163b6..62d1dfbf0b1 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -44,6 +44,7 @@ typedef enum {
SNAP_NOT_SELECTED = 1,
SNAP_NOT_ACTIVE = 2,
SNAP_ONLY_ACTIVE = 3,
+ SNAP_SELECTABLE = 4,
} eSnapSelect;
typedef enum {
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 67c470a005f..6d20044d8cf 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -276,12 +276,15 @@ typedef struct V3DSnapCursorState {
eV3DPlaceOrient plane_orient;
uchar color_line[4];
uchar color_point[4];
+ uchar color_box[4];
float *prevpoint;
+ float box_dimensions[3];
short snap_elem_force; /* If zero, use scene settings. */
short plane_axis;
bool use_plane_axis_auto;
bool draw_point;
bool draw_plane;
+ bool draw_box;
} V3DSnapCursorState;
void ED_view3d_cursor_snap_state_default_set(V3DSnapCursorState *state);
@@ -293,7 +296,6 @@ V3DSnapCursorData *ED_view3d_cursor_snap_data_get(V3DSnapCursorState *state,
const struct bContext *C,
const int x,
const int y);
-
struct SnapObjectContext *ED_view3d_cursor_snap_context_ensure(struct Scene *scene);
void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
const float loc_prev[3],
@@ -302,7 +304,6 @@ void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
const uchar color_line[4],
const uchar color_point[4],
const short snap_elem_type);
-void ED_view3d_cursor_snap_exit(void);
/* view3d_iterators.c */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 67d034f4ab6..725c9921d13 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -37,6 +37,7 @@ extern "C" {
struct ARegion;
struct AssetFilterSettings;
struct AssetHandle;
+struct AssetMetaData;
struct AutoComplete;
struct EnumPropertyItem;
struct FileDirEntry;
@@ -246,7 +247,7 @@ enum {
#define UI_DEFAULT_TEXT_POINTS 11
/* Larger size used for title text. */
-#define UI_DEFAULT_TITLE_POINTS 12
+#define UI_DEFAULT_TITLE_POINTS 11
#define UI_PANEL_WIDTH 340
#define UI_COMPACT_PANEL_WIDTH 160
@@ -423,10 +424,6 @@ typedef enum eButGradientType {
* Functions to draw various shapes, taking theme settings into account.
* Used for code that draws its own UI style elements. */
-void UI_draw_anti_tria(
- float x1, float y1, float x2, float y2, float x3, float y3, const float color[4]);
-void UI_draw_anti_fan(float tri_array[][2], unsigned int length, const float color[4]);
-
void UI_draw_roundbox_corner_set(int type);
void UI_draw_roundbox_aa(const struct rctf *rect, bool filled, float rad, const float color[4]);
void UI_draw_roundbox_4fv(const struct rctf *rect, bool filled, float rad, const float col[4]);
@@ -437,12 +434,6 @@ void UI_draw_roundbox_3ub_alpha(const struct rctf *rect,
unsigned char alpha);
void UI_draw_roundbox_3fv_alpha(
const struct rctf *rect, bool filled, float rad, const float col[3], float alpha);
-void UI_draw_roundbox_shade_x(const struct rctf *rect,
- bool filled,
- float rad,
- float shadetop,
- float shadedown,
- const float col[4]);
void UI_draw_roundbox_4fv_ex(const struct rctf *rect,
const float inner1[4],
const float inner2[4],
@@ -785,6 +776,7 @@ void UI_but_drag_set_id(uiBut *but, struct ID *id);
void UI_but_drag_set_asset(uiBut *but,
const struct AssetHandle *asset,
const char *path,
+ struct AssetMetaData *metadata,
int import_type, /* eFileAssetImportType */
int icon,
struct ImBuf *imb,
@@ -796,7 +788,8 @@ void UI_but_drag_set_value(uiBut *but);
void UI_but_drag_set_image(
uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free);
-bool UI_but_active_drop_name(struct bContext *C);
+uiBut *UI_but_active_drop_name_button(const struct bContext *C);
+bool UI_but_active_drop_name(const struct bContext *C);
bool UI_but_active_drop_color(struct bContext *C);
void UI_but_flag_enable(uiBut *but, int flag);
@@ -2687,7 +2680,12 @@ void UI_fontstyle_draw_simple_backdrop(const struct uiFontStyle *fs,
const float col_fg[4],
const float col_bg[4]);
-int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str);
+int UI_fontstyle_string_width(const struct uiFontStyle *fs,
+ const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+int UI_fontstyle_string_width_with_block_aspect(const struct uiFontStyle *fs,
+ const char *str,
+ const float aspect) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2);
int UI_fontstyle_height_max(const struct uiFontStyle *fs);
void UI_draw_icon_tri(float x, float y, char dir, const float[4]);
@@ -2780,12 +2778,12 @@ void UI_interface_tag_script_reload(void);
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
-bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_, const struct wmDrag *drag);
+bool UI_tree_view_item_drag_start(struct bContext *C, uiTreeViewItemHandle *item_);
+bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
+ const struct wmDrag *drag,
+ const char **r_disabled_hint);
+char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item, const struct wmDrag *drag);
bool UI_tree_view_item_drop_handle(uiTreeViewItemHandle *item_, const struct ListBase *drags);
-char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item,
- const struct bContext *C,
- const struct wmDrag *drag,
- const struct wmEvent *event);
bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle);
void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle);
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index 5edccfa8c88..b14ee6c4a59 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -23,15 +23,40 @@
#include <memory>
#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "UI_resources.h"
namespace blender::nodes::geometry_nodes_eval_log {
struct GeometryAttributeInfo;
}
struct uiBlock;
+struct StructRNA;
+struct uiSearchItems;
+
namespace blender::ui {
+
class AbstractTreeView;
+/**
+ * An item in a breadcrumb-like context. Currently this struct is very simple, but more
+ * could be added to it in the future, to support interactivity or tooltips, for example.
+ */
+struct ContextPathItem {
+ /* Text to display in the UI. */
+ std::string name;
+ /* #BIFIconID */
+ int icon;
+};
+
+void context_path_add_generic(Vector<ContextPathItem> &path,
+ StructRNA &rna_type,
+ void *ptr,
+ const BIFIconID icon_override = ICON_NONE);
+
+void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path);
+
void attribute_search_add_items(
StringRefNull str,
const bool is_output,
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index b1ec22c57a6..0d18eedeac9 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -48,6 +48,8 @@ namespace blender::ui {
class AbstractTreeView;
class AbstractTreeViewItem;
+class AbstractTreeViewItemDropController;
+class AbstractTreeViewItemDragController;
/* ---------------------------------------------------------------------- */
/** \name Tree-View Item Container
@@ -242,17 +244,7 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
* arguments for checking if the item is currently in an active state.
*/
virtual void is_active(IsActiveFn is_active_fn);
- virtual bool on_drop(const wmDrag &drag);
- virtual bool can_drop(const wmDrag &drag) const;
- /**
- * Custom text to display when dragging over a tree item. Should explain what happens when
- * dropping the data onto this item. Will only be used if #AbstractTreeViewItem::can_drop()
- * returns true, so the implementing override doesn't have to check that again.
- * The returned value must be a translated string.
- */
- virtual std::string drop_tooltip(const bContext &C,
- const wmDrag &drag,
- const wmEvent &event) const;
+
/**
* Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if
* another item is already being renamed.
@@ -282,6 +274,20 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
*/
virtual bool matches(const AbstractTreeViewItem &other) const;
+ /**
+ * If an item wants to support being dragged, it has to return a drag controller here.
+ * That is an object implementing #AbstractTreeViewItemDragController.
+ */
+ virtual std::unique_ptr<AbstractTreeViewItemDragController> create_drag_controller() const;
+ /**
+ * If an item wants to support dropping data into it, it has to return a drop controller here.
+ * That is an object implementing #AbstractTreeViewItemDropController.
+ *
+ * \note This drop controller may be requested for each event. The tree-view doesn't keep a drop
+ * controller around currently. So it can not contain persistent state.
+ */
+ virtual std::unique_ptr<AbstractTreeViewItemDropController> create_drop_controller() const;
+
void begin_renaming();
void end_renaming();
@@ -344,6 +350,62 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
/** \} */
/* ---------------------------------------------------------------------- */
+/** \name Drag 'n Drop
+ * \{ */
+
+/**
+ * Class to enable dragging a tree-item. An item can return a drop controller for itself via a
+ * custom implementation of #AbstractTreeViewItem::create_drag_controller().
+ */
+class AbstractTreeViewItemDragController {
+ public:
+ virtual ~AbstractTreeViewItemDragController() = default;
+
+ virtual int get_drag_type() const = 0;
+ virtual void *create_drag_data() const = 0;
+};
+
+/**
+ * Class to customize the drop behavior of a tree-item, plus the behavior when dragging over this
+ * item. An item can return a drop controller for itself via a custom implementation of
+ * #AbstractTreeViewItem::create_drop_controller().
+ */
+class AbstractTreeViewItemDropController {
+ protected:
+ AbstractTreeView &tree_view_;
+
+ public:
+ AbstractTreeViewItemDropController(AbstractTreeView &tree_view);
+ virtual ~AbstractTreeViewItemDropController() = default;
+
+ /**
+ * Check if the data dragged with \a drag can be dropped on the item this controller is for.
+ * \param r_disabled_hint: Return a static string to display to the user, explaining why dropping
+ * isn't possible on this item. Shouldn't be done too aggressively, e.g.
+ * don't set this if the drag-type can't be dropped here; only if it can
+ * but there's another reason it can't be dropped.
+ * Can assume this is a non-null pointer.
+ */
+ virtual bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const = 0;
+ /**
+ * Custom text to display when dragging over a tree item. Should explain what happens when
+ * dropping the data onto this item. Will only be used if #AbstractTreeViewItem::can_drop()
+ * returns true, so the implementing override doesn't have to check that again.
+ * The returned value must be a translated string.
+ */
+ virtual std::string drop_tooltip(const wmDrag &drag) const = 0;
+ /**
+ * Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this
+ * controller is for.
+ */
+ virtual bool on_drop(const wmDrag &drag) = 0;
+
+ template<class TreeViewType> inline TreeViewType &tree_view() const;
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
/** \name Predefined Tree-View Item Types
*
* Common, Basic Tree-View Item Types.
@@ -357,9 +419,10 @@ class BasicTreeViewItem : public AbstractTreeViewItem {
using ActivateFn = std::function<void(BasicTreeViewItem &new_active)>;
BIFIconID icon;
- BasicTreeViewItem(StringRef label, BIFIconID icon = ICON_NONE);
+ explicit BasicTreeViewItem(StringRef label, BIFIconID icon = ICON_NONE);
void build_row(uiLayout &row) override;
+ void add_label(uiLayout &layout, StringRefNull label_override = "");
void on_activate(ActivateFn fn);
protected:
@@ -390,4 +453,11 @@ inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
}
+template<class TreeViewType> TreeViewType &AbstractTreeViewItemDropController::tree_view() const
+{
+ static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
+ "Type must derive from and implement the AbstractTreeView interface");
+ return static_cast<TreeViewType &>(tree_view_);
+}
+
} // namespace blender::ui
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 13895879f01..122e5a7d839 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -147,6 +147,10 @@ void UI_view2d_view_restore(const struct bContext *C);
/* grid drawing */
void UI_view2d_multi_grid_draw(
const struct View2D *v2d, int colorid, float step, int level_size, int totlevels);
+void UI_view2d_dot_grid_draw(const struct View2D *v2d,
+ int grid_color_id,
+ float step,
+ int grid_levels);
void UI_view2d_draw_lines_y__values(const struct View2D *v2d);
void UI_view2d_draw_lines_x__values(const struct View2D *v2d);
@@ -311,6 +315,9 @@ typedef struct View2DEdgePanData {
/** View2d we're operating in. */
struct View2D *v2d;
+ /** Panning should only start once being in the inside rect once (e.g. adding nodes can happen
+ * outside). */
+ bool enabled;
/** Inside distance in UI units from the edge of the region within which to start panning. */
float inside_pad;
/** Outside distance in UI units from the edge of the region at which to stop panning. */
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index b2659f5ed52..84172c7efce 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
interface_anim.c
interface_button_group.c
interface_context_menu.c
+ interface_context_path.cc
interface_draw.c
interface_dropboxes.cc
interface_eyedropper.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 5068969946a..62c84ed38ff 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -6231,12 +6231,13 @@ void UI_but_drag_set_id(uiBut *but, ID *id)
void UI_but_drag_set_asset(uiBut *but,
const AssetHandle *asset,
const char *path,
+ struct AssetMetaData *metadata,
int import_type,
int icon,
struct ImBuf *imb,
float scale)
{
- wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, path, import_type);
+ wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
/* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the
* #wmDropBox.
diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc
new file mode 100644
index 00000000000..b0f8d186afa
--- /dev/null
+++ b/source/blender/editors/interface/interface_context_path.cc
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "BLI_vector.hh"
+
+#include "BKE_screen.h"
+
+#include "RNA_access.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+
+namespace blender::ui {
+
+void context_path_add_generic(Vector<ContextPathItem> &path,
+ StructRNA &rna_type,
+ void *ptr,
+ const BIFIconID icon_override)
+{
+ /* Add the null check here to make calling functions less verbose. */
+ if (!ptr) {
+ return;
+ }
+
+ PointerRNA rna_ptr;
+ RNA_pointer_create(nullptr, &rna_type, ptr, &rna_ptr);
+ char name[128];
+ RNA_struct_name_get_alloc(&rna_ptr, name, sizeof(name), nullptr);
+
+ /* Use a blank icon by default to check whether to retrieve it automatically from the type. */
+ const BIFIconID icon = icon_override == ICON_NONE ?
+ static_cast<BIFIconID>(RNA_struct_ui_icon(rna_ptr.type)) :
+ icon_override;
+
+ path.append({name, static_cast<int>(icon)});
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Breadcrumb Template
+ * \{ */
+
+void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path)
+{
+ uiLayout *row = uiLayoutRow(&layout, true);
+ uiLayoutSetAlignment(&layout, UI_LAYOUT_ALIGN_LEFT);
+
+ for (const int i : context_path.index_range()) {
+ uiLayout *sub_row = uiLayoutRow(row, true);
+ uiLayoutSetAlignment(sub_row, UI_LAYOUT_ALIGN_LEFT);
+
+ if (i > 0) {
+ uiItemL(sub_row, "", ICON_RIGHTARROW_THIN);
+ }
+ uiItemL(sub_row, context_path[i].name.c_str(), context_path[i].icon);
+ }
+}
+
+} // namespace blender::ui
+
+/** \} */ \ No newline at end of file
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 6cb0fcd499c..e45a5fc61c6 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -178,35 +178,6 @@ void UI_draw_roundbox_4fv(const rctf *rect, bool filled, float rad, const float
UI_draw_roundbox_4fv_ex(rect, (filled) ? col : NULL, NULL, 1.0f, col, U.pixelsize, rad);
}
-/* linear horizontal shade within button or in outline */
-/* view2d scrollers use it */
-void UI_draw_roundbox_shade_x(
- const rctf *rect, bool filled, float rad, float shadetop, float shadedown, const float col[4])
-{
- float inner1[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float inner2[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float outline[4];
-
- if (filled) {
- inner1[0] = min_ff(1.0f, col[0] + shadetop);
- inner1[1] = min_ff(1.0f, col[1] + shadetop);
- inner1[2] = min_ff(1.0f, col[2] + shadetop);
- inner1[3] = 1.0f;
- inner2[0] = max_ff(0.0f, col[0] + shadedown);
- inner2[1] = max_ff(0.0f, col[1] + shadedown);
- inner2[2] = max_ff(0.0f, col[2] + shadedown);
- inner2[3] = 1.0f;
- }
-
- /* TODO: non-filled box don't have gradients. Just use middle color. */
- outline[0] = clamp_f(col[0] + shadetop + shadedown, 0.0f, 1.0f);
- outline[1] = clamp_f(col[1] + shadetop + shadedown, 0.0f, 1.0f);
- outline[2] = clamp_f(col[2] + shadetop + shadedown, 0.0f, 1.0f);
- outline[3] = clamp_f(col[3] + shadetop + shadedown, 0.0f, 1.0f);
-
- UI_draw_roundbox_4fv_ex(rect, inner1, inner2, 1.0f, outline, U.pixelsize, rad);
-}
-
void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4])
{
const int ofs_y = 4 * U.pixelsize;
diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc
index 62250a34cf4..81a1354cbe7 100644
--- a/source/blender/editors/interface/interface_dropboxes.cc
+++ b/source/blender/editors/interface/interface_dropboxes.cc
@@ -22,6 +22,10 @@
#include "DNA_space_types.h"
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
#include "WM_api.h"
#include "UI_interface.h"
@@ -35,24 +39,43 @@ static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *eve
return false;
}
- return UI_tree_view_item_can_drop(hovered_tree_item, drag);
+ if (drag->free_disabled_info) {
+ MEM_SAFE_FREE(drag->disabled_info);
+ }
+
+ drag->free_disabled_info = false;
+ return UI_tree_view_item_can_drop(hovered_tree_item, drag, &drag->disabled_info);
}
static char *ui_tree_view_drop_tooltip(bContext *C,
wmDrag *drag,
- const wmEvent *event,
+ const int xy[2],
wmDropBox *UNUSED(drop))
{
const ARegion *region = CTX_wm_region(C);
- const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region,
- event->xy);
+ const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, xy);
if (!hovered_tree_item) {
return nullptr;
}
- return UI_tree_view_item_drop_tooltip(hovered_tree_item, C, drag, event);
+ return UI_tree_view_item_drop_tooltip(hovered_tree_item, drag);
}
+/* ---------------------------------------------------------------------- */
+
+static bool ui_drop_name_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
+{
+ return UI_but_active_drop_name(C) && (drag->type == WM_DRAG_ID);
+}
+
+static void ui_drop_name_copy(wmDrag *drag, wmDropBox *drop)
+{
+ const ID *id = WM_drag_get_local_ID(drag, 0);
+ RNA_string_set(drop->ptr, "string", id->name + 2);
+}
+
+/* ---------------------------------------------------------------------- */
+
void ED_dropboxes_ui()
{
ListBase *lb = WM_dropboxmap_find("User Interface", SPACE_EMPTY, 0);
@@ -63,4 +86,10 @@ void ED_dropboxes_ui()
nullptr,
nullptr,
ui_tree_view_drop_tooltip);
+ WM_dropbox_add(lb,
+ "UI_OT_drop_name",
+ ui_drop_name_poll,
+ ui_drop_name_copy,
+ WM_drag_free_imported_drag_ID,
+ nullptr);
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 52ab13e5cd0..51ebe5399b3 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -2145,6 +2145,12 @@ static bool ui_but_drag_init(bContext *C,
return false;
}
}
+ else if (but->type == UI_BTYPE_TREEROW) {
+ uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
+ if (tree_row_but->tree_item) {
+ UI_tree_view_item_drag_start(C, tree_row_but->tree_item);
+ }
+ }
else {
wmDrag *drag = WM_event_start_drag(
C,
@@ -2437,39 +2443,6 @@ static void ui_apply_but(
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Button Drop Event
- * \{ */
-
-/* only call if event type is EVT_DROP */
-static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleButtonData *data)
-{
- ListBase *drags = event->customdata; /* drop event type has listbase customdata by default */
-
- LISTBASE_FOREACH (wmDrag *, wmd, drags) {
- /* TODO: asset dropping. */
- if (wmd->type == WM_DRAG_ID) {
- /* align these types with UI_but_active_drop_name */
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
- ID *id = WM_drag_get_local_ID(wmd, 0);
-
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
-
- ui_textedit_string_set(but, data, id->name + 2);
-
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU)) {
- but->changed = true;
- ui_searchbox_update(C, data->searchbox, but, true);
- }
-
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- }
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Button Copy & Paste
* \{ */
@@ -2666,15 +2639,9 @@ static void ui_but_copy_text(uiBut *but, char *output, int output_len_max)
static void ui_but_paste_text(bContext *C, uiBut *but, uiHandleButtonData *data, char *buf_paste)
{
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
- ui_textedit_string_set(but, but->active, buf_paste);
-
- if (but->type == UI_BTYPE_SEARCH_MENU) {
- but->changed = true;
- ui_searchbox_update(C, data->searchbox, but, true);
- }
-
- button_activate_state(C, but, BUTTON_STATE_EXIT);
+ BLI_assert(but->active == data);
+ UNUSED_VARS_NDEBUG(data);
+ ui_but_set_string_interactive(C, but, buf_paste);
}
static void ui_but_copy_colorband(uiBut *but)
@@ -3018,6 +2985,24 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
/** \name Button Text Selection/Editing
* \{ */
+/**
+ * Use handling code to set a string for the button. Handles the case where the string is set for a
+ * search button while the search menu is open, so the results are updated accordingly.
+ * This is basically the same as pasting the string into the button.
+ */
+void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
+{
+ button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ ui_textedit_string_set(but, but->active, value);
+
+ if (but->type == UI_BTYPE_SEARCH_MENU && but->active) {
+ but->changed = true;
+ ui_searchbox_update(C, but->active->searchbox, but, true);
+ }
+
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+}
+
void ui_but_active_string_clear_and_exit(bContext *C, uiBut *but)
{
if (!but->active) {
@@ -4821,19 +4806,33 @@ static int ui_do_but_TREEROW(bContext *C,
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE) {
- if (event->val == KM_CLICK) {
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_BREAK;
- }
- if (event->val == KM_DBL_CLICK) {
- data->cancel = true;
+ switch (event->val) {
+ case KM_PRESS:
+ /* Extra icons have priority, don't mess with them. */
+ if (ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
+ return WM_UI_HANDLER_BREAK;
+ }
+ button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
+ return WM_UI_HANDLER_CONTINUE;
- UI_tree_view_item_begin_rename(tree_row_but->tree_item);
- ED_region_tag_redraw(CTX_wm_region(C));
- return WM_UI_HANDLER_BREAK;
+ case KM_CLICK:
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_BREAK;
+
+ case KM_DBL_CLICK:
+ data->cancel = true;
+ UI_tree_view_item_begin_rename(tree_row_but->tree_item);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return WM_UI_HANDLER_BREAK;
}
}
}
+ else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+ /* Let "default" button handling take care of the drag logic. */
+ return ui_do_but_EXIT(C, but, data, event);
+ }
return WM_UI_HANDLER_CONTINUE;
}
@@ -7929,7 +7928,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* Only hard-coded stuff here, button interactions with configurable
* keymaps are handled using operators (see #ED_keymap_ui). */
- if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) {
+ if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* handle copy and paste */
bool is_press_ctrl_but_no_shift = event->val == KM_PRESS && IS_EVENT_MOD(event, ctrl, oskey) &&
@@ -7978,11 +7977,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
return WM_UI_HANDLER_BREAK;
}
- /* handle drop */
- if (event->type == EVT_DROP) {
- ui_but_drop(C, event, but, data);
- }
-
if ((data->state == BUTTON_STATE_HIGHLIGHT) &&
ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, EVT_PADENTER, EVT_RETKEY) &&
(event->val == KM_RELEASE) &&
@@ -10648,7 +10642,8 @@ static int ui_handle_menu_event(bContext *C,
menu->menuretval = UI_RETURN_OUT;
}
}
- else if (saferct && !BLI_rctf_isect_pt(&saferct->parent, (float)event->xy[0], (float)event->xy[1])) {
+ else if (saferct && !BLI_rctf_isect_pt(
+ &saferct->parent, (float)event->xy[0], (float)event->xy[1])) {
if (block->flag & UI_BLOCK_OUT_1) {
menu->menuretval = UI_RETURN_OK;
}
@@ -10779,7 +10774,7 @@ static int ui_handle_menu_event(bContext *C,
}
#endif
- /* Don't handle double click events, rehandle as regular press/release. */
+ /* Don't handle double click events, re-handle as regular press/release. */
if (retval == WM_UI_HANDLER_CONTINUE && event->val == KM_DBL_CLICK) {
return retval;
}
@@ -11695,20 +11690,25 @@ void UI_screen_free_active_but(const bContext *C, bScreen *screen)
}
}
-/* returns true if highlighted button allows drop of names */
-/* called in region context */
-bool UI_but_active_drop_name(bContext *C)
+uiBut *UI_but_active_drop_name_button(const bContext *C)
{
ARegion *region = CTX_wm_region(C);
uiBut *but = ui_region_find_active_but(region);
if (but) {
if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
- return true;
+ return but;
}
}
- return false;
+ return NULL;
+}
+
+/* returns true if highlighted button allows drop of names */
+/* called in region context */
+bool UI_but_active_drop_name(const bContext *C)
+{
+ return UI_but_active_drop_name_button(C) != NULL;
}
bool UI_but_active_drop_color(bContext *C)
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 0826157b5e6..f766bb1465f 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -680,6 +680,7 @@ extern bool ui_but_string_eval_number(struct bContext *C,
extern int ui_but_string_get_max_length(uiBut *but);
/* Clear & exit the active button's string. */
extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but) ATTR_NONNULL();
+extern void ui_but_set_string_interactive(struct bContext *C, uiBut *but, const char *value);
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
void ui_def_but_icon(uiBut *but, const int icon, const int flag);
@@ -1031,7 +1032,6 @@ enum {
struct GPUBatch *ui_batch_roundbox_widget_get(void);
struct GPUBatch *ui_batch_roundbox_shadow_get(void);
-void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
void ui_draw_popover_back(struct ARegion *region,
struct uiStyle *style,
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index e54b261facd..25ba0e13487 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -351,12 +351,16 @@ static int ui_text_icon_width_ex(uiLayout *layout,
if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
layout->item.flag |= UI_ITEM_FIXED_SIZE;
}
- const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+
float margin = pad_factor->text;
if (icon) {
margin += pad_factor->icon;
}
- return UI_fontstyle_string_width(fstyle, name) + (unit_x * margin);
+
+ const float aspect = layout->root->block->aspect;
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ return UI_fontstyle_string_width_with_block_aspect(fstyle, name, aspect) +
+ (int)ceilf(unit_x * margin);
}
return unit_x * 10;
}
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 1a1d52b0425..c962a1107ae 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1864,6 +1864,39 @@ static void UI_OT_drop_color(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Drop Name Operator
+ * \{ */
+
+static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ uiBut *but = UI_but_active_drop_name_button(C);
+ char *str = RNA_string_get_alloc(op->ptr, "string", NULL, 0, NULL);
+
+ if (str) {
+ ui_but_set_string_interactive(C, but, str);
+ MEM_freeN(str);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_drop_name(wmOperatorType *ot)
+{
+ ot->name = "Drop Name";
+ ot->idname = "UI_OT_drop_name";
+ ot->description = "Drop name to button";
+
+ ot->poll = ED_operator_regionactive;
+ ot->invoke = drop_name_invoke;
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_string(
+ ot->srna, "string", NULL, 0, "String", "The string value to drop into the button");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name UI List Search Operator
* \{ */
@@ -2025,6 +2058,7 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_jump_to_target_button);
WM_operatortype_append(UI_OT_drop_color);
+ WM_operatortype_append(UI_OT_drop_name);
#ifdef WITH_PYTHON
WM_operatortype_append(UI_OT_editsource);
WM_operatortype_append(UI_OT_edittranslation_init);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index a22351eea7e..072362492d8 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1550,7 +1550,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
}
BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f);
- BLF_color3ubv(fontid, theme_col_text);
+ BLF_color3ubv(fontid, is_active ? theme_col_text_hi : theme_col_text);
BLF_draw(fontid, category_id_draw, category_draw_len);
GPU_blend(GPU_BLEND_NONE);
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 6b1ff92a855..92a9f14c77d 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -376,6 +376,37 @@ int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str)
return (int)BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
}
+/**
+ * Return the width of `str` with the spacing & kerning of `fs` with `aspect`
+ * (representing #uiBlock.aspect) applied.
+ *
+ * When calculating text width, the UI layout logic calculate widths without scale,
+ * only applying scale when drawing. This causes problems for fonts since kerning at
+ * smaller sizes often makes them wider than a scaled down version of the larger text.
+ * Resolve this by calculating the text at the on-screen size,
+ * returning the result scaled back to 1:1. See T92361.
+ */
+int UI_fontstyle_string_width_with_block_aspect(const uiFontStyle *fs,
+ const char *str,
+ const float aspect)
+{
+ uiFontStyle fs_buf;
+ if (aspect != 1.0f) {
+ fs_buf = *fs;
+ ui_fontscale(&fs_buf.points, aspect);
+ fs = &fs_buf;
+ }
+
+ int width = UI_fontstyle_string_width(fs, str);
+
+ if (aspect != 1.0f) {
+ /* While in most cases rounding up isn't important, it can make a difference
+ * with small fonts (3px or less), zooming out in the node-editor for e.g. */
+ width = (int)ceilf(width * aspect);
+ }
+ return width;
+}
+
int UI_fontstyle_height_max(const uiFontStyle *fs)
{
UI_fontstyle_set(fs);
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index f27b37a27de..d3ce7ebc3db 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -70,6 +70,7 @@ static void asset_view_item_but_drag_set(uiBut *but,
UI_but_drag_set_asset(but,
asset_handle,
BLI_strdup(blend_path),
+ ED_asset_handle_get_metadata(asset_handle),
FILE_ASSET_IMPORT_APPEND,
ED_asset_handle_get_preview_icon_id(asset_handle),
imbuf,
diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc
index 0157d0b66a3..85a6147432b 100644
--- a/source/blender/editors/interface/interface_template_attribute_search.cc
+++ b/source/blender/editors/interface/interface_template_attribute_search.cc
@@ -80,9 +80,10 @@ void attribute_search_add_items(StringRefNull str,
break;
}
}
- if (!contained && is_output) {
+ if (!contained) {
dummy_info.name = str;
- UI_search_item_add(seach_items, str.c_str(), &dummy_info, ICON_ADD, 0, 0);
+ UI_search_item_add(
+ seach_items, str.c_str(), &dummy_info, is_output ? ICON_ADD : ICON_NONE, 0, 0);
}
}
@@ -122,4 +123,4 @@ void attribute_search_add_items(StringRefNull str,
BLI_string_search_free(search);
}
-} // namespace blender::ui \ No newline at end of file
+} // namespace blender::ui
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index e9acc65ed37..3e9042d29a0 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -518,7 +518,7 @@ GPUBatch *ui_batch_roundbox_shadow_get(void)
/** \name Draw Triangle Arrow
* \{ */
-void UI_draw_anti_tria(
+static void draw_anti_tria(
float x1, float y1, float x2, float y2, float x3, float y3, const float color[4])
{
const float tri_arr[3][2] = {{x1, y1}, {x2, y2}, {x3, y3}};
@@ -559,66 +559,31 @@ void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
const float f7 = 0.25 * U.widget_unit;
if (dir == 'h') {
- UI_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
+ draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
}
else if (dir == 't') {
- UI_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
+ draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
}
else { /* 'v' = vertical, down. */
- UI_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
+ draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
}
}
/* triangle 'icon' inside rect */
-void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
+static void draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
{
if (dir == 'h') {
const float half = 0.5f * BLI_rctf_size_y(rect);
- UI_draw_anti_tria(
+ draw_anti_tria(
rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half, color);
}
else {
const float half = 0.5f * BLI_rctf_size_x(rect);
- UI_draw_anti_tria(
+ draw_anti_tria(
rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin, color);
}
}
-void UI_draw_anti_fan(float tri_array[][2], uint length, const float color[4])
-{
- float draw_color[4];
-
- copy_v4_v4(draw_color, color);
- draw_color[3] *= 2.0f / WIDGET_AA_JITTER;
-
- GPU_blend(GPU_BLEND_ALPHA);
-
- const uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- immUniformColor4fv(draw_color);
-
- /* for each AA step */
- for (int j = 0; j < WIDGET_AA_JITTER; j++) {
- immBegin(GPU_PRIM_TRI_FAN, length);
- immVertex2f(pos, tri_array[0][0], tri_array[0][1]);
- immVertex2f(pos, tri_array[1][0], tri_array[1][1]);
-
- /* We jitter only the middle of the fan, the extremes are pinned. */
- for (int i = 2; i < length - 1; i++) {
- immVertex2f(pos, tri_array[i][0] + jit[j][0], tri_array[i][1] + jit[j][1]);
- }
-
- immVertex2f(pos, tri_array[length - 1][0], tri_array[length - 1][1]);
- immEnd();
- }
-
- immUnbindProgram();
-
- GPU_blend(GPU_BLEND_NONE);
-}
-
static void widget_init(uiWidgetBase *wtb)
{
wtb->totvert = wtb->halfwayvert = 0;
@@ -1494,7 +1459,7 @@ static void widget_draw_submenu_tria(const uiBut *but,
GPU_blend(GPU_BLEND_ALPHA);
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
- ui_draw_anti_tria_rect(&tria_rect, 'h', col);
+ draw_anti_tria_rect(&tria_rect, 'h', col);
}
static void ui_text_clip_give_prev_off(uiBut *but, const char *str)
@@ -3721,7 +3686,7 @@ static void widget_datasetrow(
static void widget_nodesocket(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
- const int radi = 5;
+ const int radi = 0.25f * BLI_rcti_size_y(rect);
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4632,6 +4597,9 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
switch (but->type) {
case UI_BTYPE_LABEL:
wt = widget_type(UI_WTYPE_ICON_LABEL);
+ if (!(but->flag & UI_HAS_ICON)) {
+ but->drawflag |= UI_BUT_NO_TEXT_PADDING;
+ }
break;
default:
wt = widget_type(UI_WTYPE_ICON);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index ad7c6332ee9..aece2e58f1e 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -252,10 +252,11 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_HEADER_ACTIVE:
cp = ts->header;
+ const int factor = 5;
/* Lighten the header color when editor is active. */
- header_active[0] = cp[0] > 245 ? cp[0] - 10 : cp[0] + 10;
- header_active[1] = cp[1] > 245 ? cp[1] - 10 : cp[1] + 10;
- header_active[2] = cp[2] > 245 ? cp[2] - 10 : cp[2] + 10;
+ header_active[0] = cp[0] > 245 ? cp[0] - factor : cp[0] + factor;
+ header_active[1] = cp[1] > 245 ? cp[1] - factor : cp[1] + factor;
+ header_active[2] = cp[2] > 245 ? cp[2] - factor : cp[2] + factor;
header_active[3] = cp[3];
cp = header_active;
break;
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index 88aa362deb5..c08fa51d5a5 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -29,6 +29,7 @@
#include "UI_interface.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "UI_tree_view.hh"
@@ -354,22 +355,18 @@ void AbstractTreeViewItem::is_active(IsActiveFn is_active_fn)
is_active_fn_ = is_active_fn;
}
-bool AbstractTreeViewItem::on_drop(const wmDrag & /*drag*/)
+std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller()
+ const
{
- /* Do nothing by default. */
- return false;
-}
-
-bool AbstractTreeViewItem::can_drop(const wmDrag & /*drag*/) const
-{
- return false;
+ /* There's no drag controller (and hence no drag support) by default. */
+ return nullptr;
}
-std::string AbstractTreeViewItem::drop_tooltip(const bContext & /*C*/,
- const wmDrag & /*drag*/,
- const wmEvent & /*event*/) const
+std::unique_ptr<AbstractTreeViewItemDropController> AbstractTreeViewItem::create_drop_controller()
+ const
{
- return TIP_("Drop into/onto tree item");
+ /* There's no drop controller (and hence no drop support) by default. */
+ return nullptr;
}
bool AbstractTreeViewItem::can_rename() const
@@ -553,6 +550,12 @@ void AbstractTreeViewItem::change_state_delayed()
activate();
}
}
+/* ---------------------------------------------------------------------- */
+
+AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view)
+ : tree_view_(tree_view)
+{
+}
/* ---------------------------------------------------------------------- */
@@ -646,7 +649,18 @@ BasicTreeViewItem::BasicTreeViewItem(StringRef label, BIFIconID icon_) : icon(ic
void BasicTreeViewItem::build_row(uiLayout &row)
{
- uiItemL(&row, label_.c_str(), icon);
+ add_label(row);
+}
+
+void BasicTreeViewItem::add_label(uiLayout &layout, StringRefNull label_override)
+{
+ const StringRefNull label = label_override.is_empty() ? StringRefNull(label_) : label_override;
+
+ /* Some padding for labels without collapse chevron and no icon. Looks weird without. */
+ if (icon == ICON_NONE && !is_collapsible()) {
+ uiItemS_ex(&layout, 0.8f);
+ }
+ uiItemL(&layout, label.c_str(), icon);
}
void BasicTreeViewItem::on_activate()
@@ -680,19 +694,53 @@ bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a_handle,
return a.matches_including_parents(b);
}
-bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_, const wmDrag *drag)
+/**
+ * Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
+ * support dragging, i.e. it won't create a drag-controller upon request.
+ * \return True if dragging started successfully, otherwise false.
+ */
+bool UI_tree_view_item_drag_start(bContext *C, uiTreeViewItemHandle *item_)
+{
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
+ const std::unique_ptr<AbstractTreeViewItemDragController> drag_controller =
+ item.create_drag_controller();
+ if (!drag_controller) {
+ return false;
+ }
+
+ WM_event_start_drag(C,
+ ICON_NONE,
+ drag_controller->get_drag_type(),
+ drag_controller->create_drag_data(),
+ 0,
+ WM_DRAG_FREE_DATA);
+ return true;
+}
+
+bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
+ const wmDrag *drag,
+ const char **r_disabled_hint)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- return item.can_drop(*drag);
+ const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return false;
+ }
+
+ return drop_controller->can_drop(*drag, r_disabled_hint);
}
-char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_,
- const bContext *C,
- const wmDrag *drag,
- const wmEvent *event)
+char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_, const wmDrag *drag)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- return BLI_strdup(item.drop_tooltip(*C, *drag, *event).c_str());
+ const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return nullptr;
+ }
+
+ return BLI_strdup(drop_controller->drop_tooltip(*drag).c_str());
}
/**
@@ -702,10 +750,13 @@ char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_,
bool UI_tree_view_item_drop_handle(uiTreeViewItemHandle *item_, const ListBase *drags)
{
AbstractTreeViewItem &item = reinterpret_cast<AbstractTreeViewItem &>(*item_);
+ std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ const char *disabled_hint_dummy = nullptr;
LISTBASE_FOREACH (const wmDrag *, drag, drags) {
- if (item.can_drop(*drag)) {
- return item.on_drop(*drag);
+ if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
+ return drop_controller->on_drop(*drag);
}
}
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index ca96fde9810..eea6512f0f8 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -32,6 +32,7 @@
#include "DNA_userdef_types.h"
#include "BLI_array.h"
+#include "BLI_easing.h"
#include "BLI_link_utils.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -166,7 +167,7 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
scroll = view2d_scroll_mapped(v2d->scroll);
- /* scrollers are based off regionsize
+ /* Scrollers are based off region-size:
* - they can only be on one to two edges of the region they define
* - if they overlap, they must not occupy the corners (which are reserved for other widgets)
*/
@@ -1291,6 +1292,114 @@ void UI_view2d_multi_grid_draw(
immUnbindProgram();
}
+static void grid_axis_start_and_count(
+ const float step, const float min, const float max, float *r_start, int *r_count)
+{
+ *r_start = min;
+ if (*r_start < 0.0f) {
+ *r_start += -(float)fmod(min, step);
+ }
+ else {
+ *r_start += step - (float)fabs(fmod(min, step));
+ }
+
+ if (*r_start > max) {
+ *r_count = 0;
+ }
+ else {
+ *r_count = (max - *r_start) / step + 1;
+ }
+}
+
+typedef struct DotGridLevelInfo {
+ /* The factor applied to the #min_step argument. This could be easily computed in runtime,
+ * but seeing it together with the other values is helpful. */
+ float step_factor;
+ /* The normalized zoom level at which the grid level starts to fade in.
+ * At lower zoom levels, the points will not be visible and the level will be skipped. */
+ float fade_in_start_zoom;
+ /* The normalized zoom level at which the grid finishes fading in.
+ * At higher zoom levels, the points will be opaque. */
+ float fade_in_end_zoom;
+} DotGridLevelInfo;
+
+static const DotGridLevelInfo level_info[9] = {
+ {6.4f, -0.1f, 0.01f},
+ {3.2f, 0.0f, 0.025f},
+ {1.6f, 0.025f, 0.15f},
+ {0.8f, 0.05f, 0.2f},
+ {0.4f, 0.1f, 0.25f},
+ {0.2f, 0.125f, 0.3f},
+ {0.1f, 0.25f, 0.5f},
+ {0.05f, 0.7f, 0.9f},
+ {0.025f, 0.6f, 0.9f},
+};
+
+/**
+ * Draw a multi-level grid of dots, with a dynamic number of levels based on the fading.
+ *
+ * \param grid_color_id: The theme color used for the points. Faded dynamically based on zoom.
+ * \param min_step: The base size of the grid. At different zoom levels, the visible grid may have
+ * a larger step size.
+ * \param grid_levels: The maximum grid depth. Larger grid levels will subdivide the grid more.
+ */
+void UI_view2d_dot_grid_draw(const View2D *v2d,
+ const int grid_color_id,
+ const float min_step,
+ const int grid_levels)
+{
+ BLI_assert(grid_levels > 0 && grid_levels < 10);
+ const float zoom_x = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
+ const float zoom_normalized = (zoom_x - v2d->minzoom) / (v2d->maxzoom - v2d->minzoom);
+
+ GPUVertFormat *format = immVertexFormat();
+ const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ GPU_point_size(3.0f * UI_DPI_FAC);
+
+ float color[4];
+ UI_GetThemeColor3fv(grid_color_id, color);
+
+ for (int level = 0; level < grid_levels; level++) {
+ const DotGridLevelInfo *info = &level_info[level];
+ const float step = min_step * info->step_factor * U.widget_unit;
+
+ const float alpha_factor = (zoom_normalized - info->fade_in_start_zoom) /
+ (info->fade_in_end_zoom - info->fade_in_start_zoom);
+ color[3] = clamp_f(BLI_easing_cubic_ease_in_out(alpha_factor, 0.0f, 1.0f, 1.0f), 0.0f, 1.0f);
+ if (color[3] == 0.0f) {
+ break;
+ }
+
+ int count_x;
+ float start_x;
+ grid_axis_start_and_count(step, v2d->cur.xmin, v2d->cur.xmax, &start_x, &count_x);
+ int count_y;
+ float start_y;
+ grid_axis_start_and_count(step, v2d->cur.ymin, v2d->cur.ymax, &start_y, &count_y);
+ if (count_x == 0 || count_y == 0) {
+ continue;
+ }
+
+ immBegin(GPU_PRIM_POINTS, count_x * count_y);
+
+ /* Theoretically drawing on top of lower grid levels could be avoided, but it would also
+ * increase the complexity of this loop, which isn't worth the time at the moment. */
+ for (int i_y = 0; i_y < count_y; i_y++) {
+ const float y = start_y + step * i_y;
+ for (int i_x = 0; i_x < count_x; i_x++) {
+ const float x = start_x + step * i_x;
+ immAttr4fv(color_id, color);
+ immVertex2f(pos, x, y);
+ }
+ }
+
+ immEnd();
+ }
+
+ immUnbindProgram();
+}
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/interface/view2d_edge_pan.c b/source/blender/editors/interface/view2d_edge_pan.c
index a49666ebbd3..8d8b9a4fe48 100644
--- a/source/blender/editors/interface/view2d_edge_pan.c
+++ b/source/blender/editors/interface/view2d_edge_pan.c
@@ -92,6 +92,8 @@ void UI_view2d_edge_pan_init(bContext *C,
vpd->delay = delay;
vpd->zoom_influence = zoom_influence;
+ vpd->enabled = false;
+
/* Calculate translation factor, based on size of view. */
const float winx = (float)(BLI_rcti_size_x(&vpd->region->winrct) + 1);
const float winy = (float)(BLI_rcti_size_y(&vpd->region->winrct) + 1);
@@ -227,9 +229,16 @@ void UI_view2d_edge_pan_apply(bContext *C, View2DEdgePanData *vpd, const int xy[
BLI_rcti_pad(&inside_rect, -vpd->inside_pad * U.widget_unit, -vpd->inside_pad * U.widget_unit);
BLI_rcti_pad(&outside_rect, vpd->outside_pad * U.widget_unit, vpd->outside_pad * U.widget_unit);
+ /* Check if we can actually start the edge pan (e.g. adding nodes outside the view will start
+ * disabled). */
+ if (BLI_rcti_isect_pt_v(&inside_rect, xy)) {
+ /* We are inside once, can start. */
+ vpd->enabled = true;
+ }
+
int pan_dir_x = 0;
int pan_dir_y = 0;
- if ((vpd->outside_pad == 0) || BLI_rcti_isect_pt_v(&outside_rect, xy)) {
+ if (vpd->enabled && ((vpd->outside_pad == 0) || BLI_rcti_isect_pt_v(&outside_rect, xy))) {
/* Find whether the mouse is beyond X and Y edges. */
if (xy[0] > inside_rect.xmax) {
pan_dir_x = 1;
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index d073f5f2ba4..b712cfc24ed 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -184,8 +184,6 @@ typedef struct KnifeMeasureData {
float cage[3];
float mval[2];
bool is_stored;
- float corr_prev_cage[3]; /* "knife_start_cut" updates prev.cage breaking angle calculations,
- * store correct version. */
} KnifeMeasureData;
typedef struct KnifeUndoFrame {
@@ -242,6 +240,7 @@ typedef struct KnifeTool_OpData {
BLI_mempool *kverts;
BLI_mempool *kedges;
+ bool no_cuts; /* A cut has not been made yet. */
BLI_Stack *undostack;
BLI_Stack *splitstack; /* Store edge splits by #knife_split_edge. */
@@ -496,7 +495,7 @@ static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd)
const int distance_precision = 4;
/* Calculate distance and convert to string. */
- const float cut_len = len_v3v3(kcd->mdata.corr_prev_cage, kcd->curr.cage);
+ const float cut_len = len_v3v3(kcd->prev.cage, kcd->curr.cage);
UnitSettings *unit = &kcd->scene->unit;
if (unit->system == USER_UNIT_NONE) {
@@ -703,7 +702,7 @@ static void knifetool_draw_visible_angles(const KnifeTool_OpData *kcd)
else {
tempkfv = tempkfe->v2;
}
- angle = angle_v3v3v3(kcd->mdata.corr_prev_cage, kcd->curr.cage, tempkfv->cageco);
+ angle = angle_v3v3v3(kcd->prev.cage, kcd->curr.cage, tempkfv->cageco);
if (angle < min_angle) {
min_angle = angle;
kfe = tempkfe;
@@ -717,7 +716,7 @@ static void knifetool_draw_visible_angles(const KnifeTool_OpData *kcd)
ED_view3d_project_float_global(kcd->region, end, end_ss, V3D_PROJ_TEST_NOP);
knifetool_draw_angle(kcd,
- kcd->mdata.corr_prev_cage,
+ kcd->prev.cage,
kcd->curr.cage,
end,
kcd->prev.mval,
@@ -730,11 +729,11 @@ static void knifetool_draw_visible_angles(const KnifeTool_OpData *kcd)
kfe = kcd->curr.edge;
/* Check for most recent cut (if cage is part of previous cut). */
- if (!compare_v3v3(kfe->v1->cageco, kcd->mdata.corr_prev_cage, KNIFE_FLT_EPSBIG) &&
- !compare_v3v3(kfe->v2->cageco, kcd->mdata.corr_prev_cage, KNIFE_FLT_EPSBIG)) {
+ if (!compare_v3v3(kfe->v1->cageco, kcd->prev.cage, KNIFE_FLT_EPSBIG) &&
+ !compare_v3v3(kfe->v2->cageco, kcd->prev.cage, KNIFE_FLT_EPSBIG)) {
/* Determine acute angle. */
- float angle1 = angle_v3v3v3(kcd->mdata.corr_prev_cage, kcd->curr.cage, kfe->v1->cageco);
- float angle2 = angle_v3v3v3(kcd->mdata.corr_prev_cage, kcd->curr.cage, kfe->v2->cageco);
+ float angle1 = angle_v3v3v3(kcd->prev.cage, kcd->curr.cage, kfe->v1->cageco);
+ float angle2 = angle_v3v3v3(kcd->prev.cage, kcd->curr.cage, kfe->v2->cageco);
float angle;
float *end;
@@ -751,14 +750,8 @@ static void knifetool_draw_visible_angles(const KnifeTool_OpData *kcd)
float end_ss[2];
ED_view3d_project_float_global(kcd->region, end, end_ss, V3D_PROJ_TEST_NOP);
- knifetool_draw_angle(kcd,
- kcd->mdata.corr_prev_cage,
- kcd->curr.cage,
- end,
- kcd->prev.mval,
- kcd->curr.mval,
- end_ss,
- angle);
+ knifetool_draw_angle(
+ kcd, kcd->prev.cage, kcd->curr.cage, end, kcd->prev.mval, kcd->curr.mval, end_ss, angle);
}
}
@@ -852,10 +845,10 @@ static void knifetool_draw_visible_angles(const KnifeTool_OpData *kcd)
kcd, kcd->curr.cage, kcd->prev.cage, end, kcd->curr.mval, kcd->prev.mval, end_ss, angle);
}
else if (kcd->mdata.is_stored && !kcd->prev.is_space) {
- float angle = angle_v3v3v3(kcd->curr.cage, kcd->mdata.corr_prev_cage, kcd->mdata.cage);
+ float angle = angle_v3v3v3(kcd->curr.cage, kcd->prev.cage, kcd->mdata.cage);
knifetool_draw_angle(kcd,
kcd->curr.cage,
- kcd->mdata.corr_prev_cage,
+ kcd->prev.cage,
kcd->mdata.cage,
kcd->curr.mval,
kcd->prev.mval,
@@ -1468,7 +1461,10 @@ static void knife_input_ray_segment(KnifeTool_OpData *kcd,
ED_view3d_unproject_v3(kcd->vc.region, mval[0], mval[1], ofs, r_origin_ofs);
}
-static void knifetool_recast_cageco(KnifeTool_OpData *kcd, float mval[3], float r_cage[3])
+/* No longer used, but may be useful in the future. */
+static void UNUSED_FUNCTION(knifetool_recast_cageco)(KnifeTool_OpData *kcd,
+ float mval[3],
+ float r_cage[3])
{
float origin[3];
float origin_ofs[3];
@@ -2396,7 +2392,7 @@ static void knife_add_cut(KnifeTool_OpData *kcd)
}
/* Save values for angle drawing calculations. */
- copy_v3_v3(kcd->mdata.cage, kcd->mdata.corr_prev_cage);
+ copy_v3_v3(kcd->mdata.cage, kcd->prev.cage);
copy_v2_v2(kcd->mdata.mval, kcd->prev.mval);
kcd->mdata.is_stored = true;
@@ -4094,6 +4090,8 @@ static void knifetool_init(bContext *C,
knife_init_colors(&kcd->colors);
}
+ kcd->no_cuts = true;
+
kcd->axis_string[0] = ' ';
kcd->axis_string[1] = '\0';
@@ -4506,12 +4504,23 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
handled = true;
break;
case KNF_MODAL_NEW_CUT:
+ /* If no cuts have been made, exit.
+ * Preserves right click cancel workflow which most tools use,
+ * but stops accidentally deleting entire cuts with right click.
+ */
+ if (kcd->no_cuts) {
+ ED_region_tag_redraw(kcd->region);
+ knifetool_exit(op);
+ ED_workspace_status_text(C, NULL);
+ return OPERATOR_CANCELLED;
+ }
ED_region_tag_redraw(kcd->region);
knife_finish_cut(kcd);
kcd->mode = MODE_IDLE;
handled = true;
break;
case KNF_MODAL_ADD_CUT:
+ kcd->no_cuts = false;
knife_recalc_ortho(kcd);
/* Get the value of the event which triggered this one. */
@@ -4525,16 +4534,6 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
kcd->init = kcd->curr;
}
- /* Preserve correct prev.cage for angle drawing calculations. */
- if (kcd->prev.edge == NULL && kcd->prev.vert == NULL) {
- /* "knife_start_cut" moves prev.cage so needs to be recalculated. */
- /* Only occurs if prev was started on a face. */
- knifetool_recast_cageco(kcd, kcd->prev.mval, kcd->mdata.corr_prev_cage);
- }
- else {
- copy_v3_v3(kcd->mdata.corr_prev_cage, kcd->prev.cage);
- }
-
/* Freehand drawing is incompatible with cut-through. */
if (kcd->cut_through == false) {
kcd->is_drag_hold = true;
@@ -4811,7 +4810,7 @@ void MESH_OT_knife_tool(wmOperatorType *ot)
"Occlude Geometry",
"Only cut the front most geometry");
RNA_def_boolean(ot->srna, "only_selected", false, "Only Selected", "Only cut selected geometry");
- RNA_def_boolean(ot->srna, "xray", true, "X-Ray", "Show cuts through geometry");
+ RNA_def_boolean(ot->srna, "xray", true, "X-Ray", "Show cuts hidden by geometry");
RNA_def_enum(ot->srna,
"visible_measurements",
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 2fcf8fa6f8f..e0768bcff24 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -884,9 +884,8 @@ static bool unified_findnearest(ViewContext *vc,
BMFace **r_efa)
{
BMEditMesh *em = vc->em;
- static short mval_prev[2] = {-1, -1};
- /* only cycle while the mouse remains still */
- const bool use_cycle = ((mval_prev[0] == vc->mval[0]) && (mval_prev[1] == vc->mval[1]));
+
+ const bool use_cycle = !WM_cursor_test_motion_and_update(vc->mval);
const float dist_init = ED_view3d_select_dist_px();
/* since edges select lines, we give dots advantage of ~20 pix */
const float dist_margin = (dist_init / 2);
@@ -988,9 +987,6 @@ static bool unified_findnearest(ViewContext *vc,
}
}
- mval_prev[0] = vc->mval[0];
- mval_prev[1] = vc->mval[1];
-
/* Only one element type will be non-null. */
BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 114f540b614..d22ae5bc804 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1323,6 +1323,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
const bool use_in_front = RNA_boolean_get(op->ptr, "use_in_front");
const bool use_lights = RNA_boolean_get(op->ptr, "use_lights");
const int stroke_depth_order = RNA_enum_get(op->ptr, "stroke_depth_order");
+ const float stroke_depth_offset = RNA_float_get(op->ptr, "stroke_depth_offset");
ushort local_view_bits;
float loc[3], rot[3];
@@ -1454,6 +1455,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
if (stroke_depth_order == GP_DRAWMODE_3D) {
gpd->draw_mode = GP_DRAWMODE_3D;
}
+ md->stroke_depth_offset = stroke_depth_offset;
}
break;
@@ -1491,9 +1493,10 @@ static void object_add_ui(bContext *UNUSED(C), wmOperator *op)
uiItemR(layout, op->ptr, "use_lights", 0, NULL, ICON_NONE);
uiItemR(layout, op->ptr, "use_in_front", 0, NULL, ICON_NONE);
bool in_front = RNA_boolean_get(op->ptr, "use_in_front");
- uiLayout *row = uiLayoutRow(layout, false);
- uiLayoutSetActive(row, !in_front);
- uiItemR(row, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE);
+ uiLayout *col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, !in_front);
+ uiItemR(col, op->ptr, "stroke_depth_offset", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE);
}
}
@@ -1532,9 +1535,18 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", "");
RNA_def_boolean(ot->srna,
"use_in_front",
- false,
- "In Front",
+ true,
+ "Show In Front",
"Show line art grease pencil in front of everything");
+ RNA_def_float(ot->srna,
+ "stroke_depth_offset",
+ 0.05f,
+ 0.0f,
+ FLT_MAX,
+ "Stroke Offset",
+ "Stroke offset for the line art modifier",
+ 0.0f,
+ 0.5f);
RNA_def_boolean(
ot->srna, "use_lights", false, "Use Lights", "Use lights for this grease pencil object");
RNA_def_enum(
@@ -1543,7 +1555,7 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot)
rna_enum_gpencil_add_stroke_depth_order_items,
GP_DRAWMODE_3D,
"Stroke Depth Order",
- "Defines how the strokes are ordered in 3D space for objects not displayed 'In Front'");
+ "Defines how the strokes are ordered in 3D space for objects not displayed 'In Front')");
}
/** \} */
@@ -2133,7 +2145,7 @@ static void copy_object_set_idnew(bContext *C)
Main *bmain = CTX_data_main(C);
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- BKE_libblock_relink_to_newid(&ob->id);
+ BKE_libblock_relink_to_newid(bmain, &ob->id);
}
CTX_DATA_END;
@@ -2366,7 +2378,7 @@ static void make_object_duplilist_real(bContext *C,
Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob);
/* Remap new object to itself, and clear again newid pointer of orig object. */
- BKE_libblock_relink_to_newid(&ob_dst->id);
+ BKE_libblock_relink_to_newid(bmain, &ob_dst->id);
DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY);
@@ -3363,7 +3375,7 @@ Base *ED_object_add_duplicate(
ob = basen->object;
/* link own references to the newly duplicated data T26816. */
- BKE_libblock_relink_to_newid(&ob->id);
+ BKE_libblock_relink_to_newid(bmain, &ob->id);
/* DAG_relations_tag_update(bmain); */ /* caller must do */
@@ -3469,19 +3481,6 @@ void OBJECT_OT_duplicate(wmOperatorType *ot)
* Use for drag & drop.
* \{ */
-static Base *object_add_ensure_in_view_layer(Main *bmain, ViewLayer *view_layer, Object *ob)
-{
- Base *base = BKE_view_layer_base_find(view_layer, ob);
-
- if (!base) {
- LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
- BKE_collection_object_add(bmain, layer_collection->collection, ob);
- base = BKE_view_layer_base_find(view_layer, ob);
- }
-
- return base;
-}
-
static int object_add_named_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -3489,8 +3488,7 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
Base *basen;
Object *ob;
- const bool duplicate = RNA_boolean_get(op->ptr, "duplicate");
- const bool linked = duplicate && RNA_boolean_get(op->ptr, "linked");
+ const bool linked = RNA_boolean_get(op->ptr, "linked");
const eDupli_ID_Flags dupflag = (linked) ? 0 : (eDupli_ID_Flags)U.dupflag;
char name[MAX_ID_NAME - 2];
@@ -3504,41 +3502,26 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
}
/* prepare dupli */
- if (duplicate) {
- basen = object_add_duplicate_internal(
- bmain,
- scene,
- view_layer,
- ob,
- dupflag,
- /* Sub-process flag because the new-ID remapping (#BKE_libblock_relink_to_newid()) in this
- * function will only work if the object is already linked in the view layer, which is not
- * the case here. So we have to do the new-ID relinking ourselves
- * (#copy_object_set_idnew()).
- */
- LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID);
- }
- else {
- /* basen is actually not a new base in this case. */
- basen = object_add_ensure_in_view_layer(bmain, view_layer, ob);
- }
+ basen = object_add_duplicate_internal(
+ bmain,
+ scene,
+ view_layer,
+ ob,
+ dupflag,
+ /* Sub-process flag because the new-ID remapping (#BKE_libblock_relink_to_newid()) in this
+ * function will only work if the object is already linked in the view layer, which is not
+ * the case here. So we have to do the new-ID relinking ourselves
+ * (#copy_object_set_idnew()).
+ */
+ LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID);
if (basen == NULL) {
- BKE_report(op->reports,
- RPT_ERROR,
- duplicate ? "Object could not be duplicated" :
- "Object could not be linked to the view layer");
+ BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated");
return OPERATOR_CANCELLED;
}
basen->object->visibility_flag &= ~OB_HIDE_VIEWPORT;
- int mval[2];
- if (object_add_drop_xy_get(C, op, &mval)) {
- ED_object_location_from_view(C, basen->object->loc);
- ED_view3d_cursor3d_position(C, mval, false, basen->object->loc);
- }
-
/* object_add_duplicate_internal() doesn't deselect other objects, unlike object_add_common() or
* BKE_view_layer_base_deselect_all(). */
ED_object_base_deselect_all(view_layer, NULL, SEL_DESELECT);
@@ -3556,44 +3539,164 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
ED_outliner_select_sync_from_object_tag(C);
+ PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix");
+ if (RNA_property_is_set(op->ptr, prop_matrix)) {
+ Object *ob_add = basen->object;
+ RNA_property_float_get_array(op->ptr, prop_matrix, &ob_add->obmat[0][0]);
+ BKE_object_apply_mat4(ob_add, ob_add->obmat, true, true);
+
+ DEG_id_tag_update(&ob_add->id, ID_RECALC_TRANSFORM);
+ }
+ else {
+ int mval[2];
+ if (object_add_drop_xy_get(C, op, &mval)) {
+ ED_object_location_from_view(C, basen->object->loc);
+ ED_view3d_cursor3d_position(C, mval, false, basen->object->loc);
+ }
+ }
+
return OPERATOR_FINISHED;
}
void OBJECT_OT_add_named(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Named Object";
+ ot->name = "Add Object";
ot->description = "Add named object";
ot->idname = "OBJECT_OT_add_named";
/* api callbacks */
ot->invoke = object_add_drop_xy_generic_invoke;
ot->exec = object_add_named_exec;
- ot->poll = ED_operator_objectmode;
+ ot->poll = ED_operator_objectmode_poll_msg;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
-
- prop = RNA_def_boolean(
- ot->srna,
- "duplicate",
- true,
- "Duplicate",
- "Create a duplicate of the object. If not set, only ensures the object is linked into the "
- "active view layer, positions and selects/activates it (deselecting others)");
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
RNA_def_boolean(ot->srna,
"linked",
false,
"Linked",
- "Duplicate object but not object data, linking to the original data (ignored if "
- "'duplicate' is false)");
+ "Duplicate object but not object data, linking to the original data");
RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Object name to add");
+ prop = RNA_def_float_matrix(
+ ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ object_add_drop_xy_props(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Object to Mouse Operator
+ * \{ */
+
+/**
+ * Alternate behavior for dropping an asset that positions the appended object(s).
+ */
+static int object_transform_to_mouse_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob;
+
+ if (RNA_struct_property_is_set(op->ptr, "name")) {
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
+ ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
+ }
+ else {
+ ob = OBACT(view_layer);
+ }
+
+ if (ob == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Object not found");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Don't transform a linked object. There's just nothing to do here in this case, so return
+ * #OPERATOR_FINISHED. */
+ if (ID_IS_LINKED(ob)) {
+ return OPERATOR_FINISHED;
+ }
+
+ /* Ensure the locations are updated so snap reads the evaluated active location. */
+ CTX_data_ensure_evaluated_depsgraph(C);
+
+ PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix");
+ if (RNA_property_is_set(op->ptr, prop_matrix)) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_selected_objects(view_layer, NULL, &objects_len, {0});
+
+ float matrix[4][4];
+ RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]);
+
+ float mat_src_unit[4][4];
+ float mat_dst_unit[4][4];
+ float final_delta[4][4];
+
+ normalize_m4_m4(mat_src_unit, ob->obmat);
+ normalize_m4_m4(mat_dst_unit, matrix);
+ invert_m4(mat_src_unit);
+ mul_m4_m4m4(final_delta, mat_dst_unit, mat_src_unit);
+
+ ED_object_xform_array_m4(objects, objects_len, final_delta);
+
+ MEM_freeN(objects);
+ }
+ else {
+ int mval[2];
+ if (object_add_drop_xy_get(C, op, &mval)) {
+ float cursor[3];
+ ED_object_location_from_view(C, cursor);
+ ED_view3d_cursor3d_position(C, mval, false, cursor);
+
+ /* Use the active objects location since this is the ID which the user selected to drop.
+ *
+ * This transforms all selected objects, so that dropping a single object which links in
+ * other objects will have their relative transformation preserved.
+ * For example a child/parent relationship or other objects used with a boolean modifier.
+ *
+ * The caller is responsible for ensuring the selection state gives useful results.
+ * Link/append does this using #FILE_AUTOSELECT. */
+ ED_view3d_snap_selected_to_location(C, cursor, V3D_AROUND_ACTIVE);
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_transform_to_mouse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Place Object Under Mouse";
+ ot->description = "Snap selected item(s) to the mouse location";
+ ot->idname = "OBJECT_OT_transform_to_mouse";
+
+ /* api callbacks */
+ ot->invoke = object_add_drop_xy_generic_invoke;
+ ot->exec = object_transform_to_mouse_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ PropertyRNA *prop;
+ RNA_def_string(ot->srna,
+ "name",
+ NULL,
+ MAX_ID_NAME - 2,
+ "Name",
+ "Object name to place (when unset use the active object)");
+
+ prop = RNA_def_float_matrix(
+ ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
object_add_drop_xy_props(ot);
}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index ea9a2de090b..fe07ecef438 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -106,6 +106,7 @@ void OBJECT_OT_select_same_collection(struct wmOperatorType *ot);
/* object_add.c */
void OBJECT_OT_add(struct wmOperatorType *ot);
void OBJECT_OT_add_named(struct wmOperatorType *ot);
+void OBJECT_OT_transform_to_mouse(struct wmOperatorType *ot);
void OBJECT_OT_metaball_add(struct wmOperatorType *ot);
void OBJECT_OT_text_add(struct wmOperatorType *ot);
void OBJECT_OT_armature_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index b3bf2c64a91..b171da42522 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -112,6 +112,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_volume_import);
WM_operatortype_append(OBJECT_OT_add);
WM_operatortype_append(OBJECT_OT_add_named);
+ WM_operatortype_append(OBJECT_OT_transform_to_mouse);
WM_operatortype_append(OBJECT_OT_effector_add);
WM_operatortype_append(OBJECT_OT_collection_instance_add);
WM_operatortype_append(OBJECT_OT_data_instance_add);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index d81143d6081..acd3f058554 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1685,18 +1685,20 @@ static bool single_data_needs_duplication(ID *id)
return (id != NULL && (id->us > 1 || ID_IS_LINKED(id)));
}
-static void libblock_relink_collection(Collection *collection, const bool do_collection)
+static void libblock_relink_collection(Main *bmain,
+ Collection *collection,
+ const bool do_collection)
{
if (do_collection) {
- BKE_libblock_relink_to_newid(&collection->id);
+ BKE_libblock_relink_to_newid(bmain, &collection->id);
}
for (CollectionObject *cob = collection->gobject.first; cob != NULL; cob = cob->next) {
- BKE_libblock_relink_to_newid(&cob->ob->id);
+ BKE_libblock_relink_to_newid(bmain, &cob->ob->id);
}
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- libblock_relink_collection(child->collection, true);
+ libblock_relink_collection(bmain, child->collection, true);
}
}
@@ -1766,10 +1768,10 @@ static void single_object_users(
single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true);
/* Will also handle the master collection. */
- BKE_libblock_relink_to_newid(&scene->id);
+ BKE_libblock_relink_to_newid(bmain, &scene->id);
/* Collection and object pointers in collections */
- libblock_relink_collection(scene->master_collection, false);
+ libblock_relink_collection(bmain, scene->master_collection, false);
/* We also have to handle runtime things in UI. */
if (v3d) {
@@ -2589,10 +2591,10 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
char *ED_object_ot_drop_named_material_tooltip(bContext *C,
PointerRNA *properties,
- const wmEvent *event)
+ const int mval[2])
{
int mat_slot = 0;
- Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot);
+ Object *ob = ED_view3d_give_material_slot_under_cursor(C, mval, &mat_slot);
if (ob == NULL) {
return BLI_strdup("");
}
@@ -2642,8 +2644,10 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_FINISHED;
}
-/* used for dropbox */
-/* assigns to object under cursor, only first material slot */
+/**
+ * Used for drop-box.
+ * Assigns to object under cursor, only first material slot.
+ */
void OBJECT_OT_drop_named_material(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c
index 66390f6f165..c7dfe911ce7 100644
--- a/source/blender/editors/object/object_utils.c
+++ b/source/blender/editors/object/object_utils.c
@@ -36,6 +36,7 @@
#include "BKE_armature.h"
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
+#include "BKE_object.h"
#include "BKE_scene.h"
#include "DEG_depsgraph_query.h"
@@ -430,3 +431,70 @@ void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xd
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Object Array
+ *
+ * Low level object transform function, transforming objects by `matrix`.
+ * Simple alternative to full transform logic.
+ * \{ */
+
+static bool object_parent_in_set(GSet *objects_set, Object *ob)
+{
+ for (Object *parent = ob->parent; parent; parent = parent->parent) {
+ if (BLI_gset_lookup(objects_set, parent)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ED_object_xform_array_m4(Object **objects, uint objects_len, const float matrix[4][4])
+{
+ /* Filter out objects that have parents in `objects_set`. */
+ {
+ GSet *objects_set = BLI_gset_ptr_new_ex(__func__, objects_len);
+ for (uint i = 0; i < objects_len; i++) {
+ BLI_gset_add(objects_set, objects[i]);
+ }
+ for (uint i = 0; i < objects_len;) {
+ if (object_parent_in_set(objects_set, objects[i])) {
+ objects[i] = objects[--objects_len];
+ }
+ else {
+ i++;
+ }
+ }
+ BLI_gset_free(objects_set, NULL);
+ }
+
+ /* Detect translation only matrix, prevent rotation/scale channels from being touched at all. */
+ bool is_translation_only;
+ {
+ float test_m4_a[4][4], test_m4_b[4][4];
+ unit_m4(test_m4_a);
+ copy_m4_m4(test_m4_b, matrix);
+ zero_v3(test_m4_b[3]);
+ is_translation_only = equals_m4m4(test_m4_a, test_m4_b);
+ }
+
+ if (is_translation_only) {
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ add_v3_v3(ob->loc, matrix[3]);
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
+ }
+ else {
+ for (uint i = 0; i < objects_len; i++) {
+ float m4[4][4];
+ Object *ob = objects[i];
+ BKE_object_to_mat4(ob, m4);
+ mul_m4_m4m4(m4, matrix, m4);
+ BKE_object_apply_mat4(ob, m4, true, true);
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 3ac6dca3044..367d72b0ad7 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -1235,9 +1235,15 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op)
const bool use_active = RNA_boolean_get(op->ptr, "use_active");
Scene *scene = CTX_data_scene(C);
Object *ob_from = ED_object_active_context(C);
- ParticleSystem *psys_from =
- use_active ? CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data :
- NULL;
+
+ ParticleSystem *psys_from = NULL;
+ if (use_active) {
+ psys_from = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
+ if (psys_from == NULL) {
+ /* Particle System context pointer is only valid in the Properties Editor. */
+ psys_from = psys_get_current(ob_from);
+ }
+ }
int changed_tot = 0;
int fail = 0;
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index b69a563166a..80c14371c16 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1744,7 +1744,7 @@ static void ed_default_handlers(
if (flag & ED_KEYMAP_TOOL) {
if (flag & ED_KEYMAP_GIZMO) {
WM_event_add_keymap_handler_dynamic(
- &region->handlers, WM_event_get_keymap_from_toolsystem_fallback, area);
+ &region->handlers, WM_event_get_keymap_from_toolsystem_with_gizmos, area);
}
else {
WM_event_add_keymap_handler_dynamic(
@@ -1940,7 +1940,7 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
rcti window_rect;
WM_window_rect_calc(win, &window_rect);
- /* set typedefinitions */
+ /* Set type-definitions. */
area->type = BKE_spacetype_from_id(area->spacetype);
if (area->type == NULL) {
@@ -3027,7 +3027,7 @@ void ED_region_panels_layout_ex(const bContext *C,
search_filter);
}
- /* Draw "polyinstantaited" panels that don't have a 1 to 1 correspondence with their types. */
+ /* Draw "poly-instantiated" panels that don't have a 1 to 1 correspondence with their types. */
if (has_instanced_panel) {
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->type == NULL) {
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 841792d5f2d..fa0cfd16817 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -935,6 +935,10 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
}
}
}
+
+ /* Ensure test-motion values are never shared between regions. */
+ const bool use_cycle = !WM_cursor_test_motion_and_update((const int[2]){-1, -1});
+ UNUSED_VARS(use_cycle);
}
/* Cursors, for time being set always on edges,
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index e5fbcbb0b6c..66140cba9c6 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -219,6 +219,20 @@ bool ED_operator_objectmode(bContext *C)
return true;
}
+/**
+ * Same as #ED_operator_objectmode() but additionally sets a "disabled hint". That is, a message
+ * to be displayed to the user explaining why the operator can't be used in current context.
+ */
+bool ED_operator_objectmode_poll_msg(bContext *C)
+{
+ if (!ED_operator_objectmode(C)) {
+ CTX_wm_operator_poll_msg_set(C, "Only supported in object mode");
+ return false;
+ }
+
+ return true;
+}
+
static bool ed_spacetype_test(bContext *C, int type)
{
if (ED_operator_areaactive(C)) {
@@ -1283,7 +1297,7 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C,
*
* callbacks:
*
- * invoke() gets called on shift+lmb drag in action-zone
+ * invoke() gets called on Shift-LMB drag in action-zone
* exec() execute without any user interaction, based on properties
* call init(), add handler
*
@@ -2078,7 +2092,7 @@ typedef struct sAreaSplitData {
int bigger, smaller; /* constraints for moving new edge */
int delta; /* delta move edge */
int origmin, origsize; /* to calculate fac, for property storage */
- int previewmode; /* draw previewline, then split */
+ int previewmode; /* draw preview-line, then split. */
void *draw_callback; /* call `screen_draw_split_preview` */
bool do_snap;
@@ -2628,8 +2642,8 @@ static int area_max_regionsize(ScrArea *area, ARegion *scalear, AZEdge edge)
dist = BLI_rcti_size_y(&area->totrct);
}
- /* subtractwidth of regions on opposite side
- * prevents dragging regions into other opposite regions */
+ /* Subtract the width of regions on opposite side
+ * prevents dragging regions into other opposite regions. */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region == scalear) {
continue;
@@ -3082,12 +3096,12 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
float cfra = (float)(CFRA);
- /* init binarytree-list for getting keyframes */
+ /* Initialize binary-tree-list for getting keyframes. */
struct AnimKeylist *keylist = ED_keylist_create();
- /* seed up dummy dopesheet context with flags to perform necessary filtering */
+ /* Speed up dummy dope-sheet context with flags to perform necessary filtering. */
if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
- /* only selected channels are included */
+ /* Only selected channels are included. */
ads.filterflag |= ADS_FILTER_ONLYSEL;
}
@@ -4206,7 +4220,7 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Region Context Menu Operator (Header/Footer/Navbar)
+/** \name Region Context Menu Operator (Header/Footer/Navigation-Bar)
* \{ */
static void screen_area_menu_items(ScrArea *area, uiLayout *layout)
@@ -5058,6 +5072,18 @@ static int userpref_show_exec(bContext *C, wmOperator *op)
int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_DPI_FAC;
int sizey = 520 * UI_DPI_FAC;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "section");
+ if (prop && RNA_property_is_set(op->ptr, prop)) {
+ /* Set active section via RNA, so it can fail properly. */
+
+ PointerRNA pref_ptr;
+ RNA_pointer_create(NULL, &RNA_Preferences, &U, &pref_ptr);
+ PropertyRNA *active_section_prop = RNA_struct_find_property(&pref_ptr, "active_section");
+
+ RNA_property_enum_set(&pref_ptr, active_section_prop, RNA_property_enum_get(op->ptr, prop));
+ RNA_property_update(C, &pref_ptr, active_section_prop);
+ }
+
/* changes context! */
if (WM_window_open(C,
IFACE_("Blender Preferences"),
@@ -5091,14 +5117,24 @@ static int userpref_show_exec(bContext *C, wmOperator *op)
static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
- ot->name = "Show Preferences";
+ ot->name = "Open Preferences...";
ot->description = "Edit user preferences and system settings";
ot->idname = "SCREEN_OT_userpref_show";
/* api callbacks */
ot->exec = userpref_show_exec;
ot->poll = ED_operator_screenactive_nobackground; /* Not in background as this opens a window. */
+
+ prop = RNA_def_enum(ot->srna,
+ "section",
+ rna_enum_preference_section_items,
+ 0,
+ "",
+ "Section to activate in the Preferences");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 4e0dcfe8e3c..fede01a614b 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -295,7 +295,7 @@ static uint vpaint_blend(const VPaint *vp,
uint color_blend = ED_vpaint_blend_tool(blend, color_curr, color_paint, alpha_i);
- /* if no accumulate, clip color adding with colorig & orig alpha */
+ /* If no accumulate, clip color adding with `color_orig` & `color_test`. */
if (!brush_use_accumulate(vp)) {
uint color_test, a;
char *cp, *ct, *co;
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index c305a11daf4..e6b76e05e16 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -60,6 +60,7 @@ class AssetCatalogTreeView : public ui::AbstractTreeView {
SpaceFile &space_file_;
friend class AssetCatalogTreeViewItem;
+ friend class AssetCatalogDropController;
public:
AssetCatalogTreeView(::AssetLibrary *library,
@@ -86,25 +87,52 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
public:
AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog_item);
- static bool has_droppable_item(const wmDrag &drag);
- static bool drop_into_catalog(const AssetCatalogTreeView &tree_view,
- const wmDrag &drag,
- CatalogID catalog_id,
- StringRefNull simple_name = "");
-
void on_activate() override;
void build_row(uiLayout &row) override;
void build_context_menu(bContext &C, uiLayout &column) const override;
- bool can_drop(const wmDrag &drag) const override;
- std::string drop_tooltip(const bContext &C,
- const wmDrag &drag,
- const wmEvent &event) const override;
- bool on_drop(const wmDrag &drag) override;
-
bool can_rename() const override;
bool rename(StringRefNull new_name) override;
+
+ /** Add drag support for catalog items. */
+ std::unique_ptr<ui::AbstractTreeViewItemDragController> create_drag_controller() const override;
+ /** Add dropping support for catalog items. */
+ std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+};
+
+class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController {
+ AssetCatalogTreeItem &catalog_item_;
+
+ public:
+ explicit AssetCatalogDragController(AssetCatalogTreeItem &catalog_item);
+
+ int get_drag_type() const override;
+ void *create_drag_data() const override;
+};
+
+class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController {
+ AssetCatalogTreeItem &catalog_item_;
+
+ public:
+ AssetCatalogDropController(AssetCatalogTreeView &tree_view, AssetCatalogTreeItem &catalog_item);
+
+ bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
+ std::string drop_tooltip(const wmDrag &drag) const override;
+ bool on_drop(const wmDrag &drag) override;
+
+ ::AssetLibrary &get_asset_library() const;
+
+ static bool has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint);
+ static bool drop_assets_into_catalog(const AssetCatalogTreeView &tree_view,
+ const wmDrag &drag,
+ CatalogID catalog_id,
+ StringRefNull simple_name = "");
+
+ private:
+ bool drop_asset_catalog_into_catalog(const wmDrag &drag);
+ std::string drop_tooltip_asset_list(const wmDrag &drag) const;
+ std::string drop_tooltip_asset_catalog(const wmDrag &drag) const;
};
/** Only reason this isn't just `BasicTreeViewItem` is to add a '+' icon for adding a root level
@@ -118,11 +146,15 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
using BasicTreeViewItem::BasicTreeViewItem;
- bool can_drop(const wmDrag &drag) const override;
- std::string drop_tooltip(const bContext &C,
- const wmDrag &drag,
- const wmEvent &event) const override;
- bool on_drop(const wmDrag &drag) override;
+ struct DropController : public ui::AbstractTreeViewItemDropController {
+ DropController(AssetCatalogTreeView &tree_view);
+
+ bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
+ std::string drop_tooltip(const wmDrag &drag) const override;
+ bool on_drop(const wmDrag &drag) override;
+ };
+
+ std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
};
/* ---------------------------------------------------------------------- */
@@ -219,12 +251,8 @@ void AssetCatalogTreeViewItem::on_activate()
void AssetCatalogTreeViewItem::build_row(uiLayout &row)
{
- if (catalog_item_.has_unsaved_changes()) {
- uiItemL(&row, (label_ + "*").c_str(), icon);
- }
- else {
- uiItemL(&row, label_.c_str(), icon);
- }
+ const std::string label_override = catalog_item_.has_unsaved_changes() ? (label_ + "*") : label_;
+ add_label(row, label_override);
if (!is_hovered()) {
return;
@@ -275,31 +303,80 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column)
UI_menutype_draw(&C, mt, &column);
}
-bool AssetCatalogTreeViewItem::has_droppable_item(const wmDrag &drag)
+bool AssetCatalogTreeViewItem::can_rename() const
{
- const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
+ return true;
+}
- /* There needs to be at least one asset from the current file. */
- LISTBASE_FOREACH (const wmDragAssetListItem *, asset_item, asset_drags) {
- if (!asset_item->is_external) {
- return true;
- }
+bool AssetCatalogTreeViewItem::rename(StringRefNull new_name)
+{
+ /* Important to keep state. */
+ BasicTreeViewItem::rename(new_name);
+
+ const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>(
+ get_tree_view());
+ ED_asset_catalog_rename(tree_view.asset_library_, catalog_item_.get_catalog_id(), new_name);
+ return true;
+}
+
+std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewItem::
+ create_drop_controller() const
+{
+ return std::make_unique<AssetCatalogDropController>(
+ static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
+}
+
+std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem::
+ create_drag_controller() const
+{
+ return std::make_unique<AssetCatalogDragController>(catalog_item_);
+}
+
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item)
+ : ui::AbstractTreeViewItemDropController(tree_view), catalog_item_(catalog_item)
+{
+}
+
+bool AssetCatalogDropController::can_drop(const wmDrag &drag, const char **r_disabled_hint) const
+{
+ if (drag.type == WM_DRAG_ASSET_CATALOG) {
+ /* Always supported. */
+ return true;
+ }
+ if (drag.type == WM_DRAG_ASSET_LIST) {
+ return has_droppable_asset(drag, r_disabled_hint);
}
return false;
}
-bool AssetCatalogTreeViewItem::can_drop(const wmDrag &drag) const
+std::string AssetCatalogDropController::drop_tooltip(const wmDrag &drag) const
{
- if (drag.type != WM_DRAG_ASSET_LIST) {
- return false;
+ if (drag.type == WM_DRAG_ASSET_CATALOG) {
+ return drop_tooltip_asset_catalog(drag);
}
- return has_droppable_item(drag);
+ return drop_tooltip_asset_list(drag);
}
-std::string AssetCatalogTreeViewItem::drop_tooltip(const bContext & /*C*/,
- const wmDrag &drag,
- const wmEvent & /*event*/) const
+std::string AssetCatalogDropController::drop_tooltip_asset_catalog(const wmDrag &drag) const
{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+
+ const ::AssetLibrary *asset_library = tree_view<AssetCatalogTreeView>().asset_library_;
+ bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(asset_library);
+ wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
+ AssetCatalog *src_catalog = catalog_service->find_catalog(catalog_drag->drag_catalog_id);
+
+ return std::string(TIP_("Move Catalog")) + " '" + src_catalog->path.name() + "' " +
+ IFACE_("into") + " '" + catalog_item_.get_name() + "'";
+}
+
+std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &drag) const
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_LIST);
+
const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
const bool is_multiple_assets = !BLI_listbase_is_single(asset_drags);
@@ -312,11 +389,34 @@ std::string AssetCatalogTreeViewItem::drop_tooltip(const bContext & /*C*/,
")";
}
-bool AssetCatalogTreeViewItem::drop_into_catalog(const AssetCatalogTreeView &tree_view,
- const wmDrag &drag,
- CatalogID catalog_id,
- StringRefNull simple_name)
+bool AssetCatalogDropController::on_drop(const wmDrag &drag)
{
+ if (drag.type == WM_DRAG_ASSET_CATALOG) {
+ return drop_asset_catalog_into_catalog(drag);
+ }
+ return drop_assets_into_catalog(tree_view<AssetCatalogTreeView>(),
+ drag,
+ catalog_item_.get_catalog_id(),
+ catalog_item_.get_simple_name());
+}
+
+bool AssetCatalogDropController::drop_asset_catalog_into_catalog(const wmDrag &drag)
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
+ ED_asset_catalog_move(
+ &get_asset_library(), catalog_drag->drag_catalog_id, catalog_item_.get_catalog_id());
+
+ WM_main_add_notifier(NC_ASSET | ND_ASSET_CATALOGS, nullptr);
+ return true;
+}
+
+bool AssetCatalogDropController::drop_assets_into_catalog(const AssetCatalogTreeView &tree_view,
+ const wmDrag &drag,
+ CatalogID catalog_id,
+ StringRefNull simple_name)
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_LIST);
const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
if (!asset_drags) {
return false;
@@ -339,28 +439,46 @@ bool AssetCatalogTreeViewItem::drop_into_catalog(const AssetCatalogTreeView &tre
return true;
}
-bool AssetCatalogTreeViewItem::on_drop(const wmDrag &drag)
+bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag,
+ const char **r_disabled_hint)
{
- const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>(
- get_tree_view());
- return drop_into_catalog(
- tree_view, drag, catalog_item_.get_catalog_id(), catalog_item_.get_simple_name());
+ const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
+
+ *r_disabled_hint = nullptr;
+ /* There needs to be at least one asset from the current file. */
+ LISTBASE_FOREACH (const wmDragAssetListItem *, asset_item, asset_drags) {
+ if (!asset_item->is_external) {
+ return true;
+ }
+ }
+
+ *r_disabled_hint = "Only assets from this current file can be moved between catalogs";
+ return false;
}
-bool AssetCatalogTreeViewItem::can_rename() const
+::AssetLibrary &AssetCatalogDropController::get_asset_library() const
{
- return true;
+ return *tree_view<AssetCatalogTreeView>().asset_library_;
}
-bool AssetCatalogTreeViewItem::rename(StringRefNull new_name)
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeItem &catalog_item)
+ : catalog_item_(catalog_item)
{
- /* Important to keep state. */
- BasicTreeViewItem::rename(new_name);
+}
- const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>(
- get_tree_view());
- ED_asset_catalog_rename(tree_view.asset_library_, catalog_item_.get_catalog_id(), new_name);
- return true;
+int AssetCatalogDragController::get_drag_type() const
+{
+ return WM_DRAG_ASSET_CATALOG;
+}
+
+void *AssetCatalogDragController::create_drag_data() const
+{
+ wmDragAssetCatalog *drag_catalog = (wmDragAssetCatalog *)MEM_callocN(sizeof(*drag_catalog),
+ __func__);
+ drag_catalog->drag_catalog_id = catalog_item_.get_catalog_id();
+ return drag_catalog;
}
/* ---------------------------------------------------------------------- */
@@ -382,17 +500,29 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
/* ---------------------------------------------------------------------- */
-bool AssetCatalogTreeViewUnassignedItem::can_drop(const wmDrag &drag) const
+std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnassignedItem::
+ create_drop_controller() const
+{
+ return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropController>(
+ static_cast<AssetCatalogTreeView &>(get_tree_view()));
+}
+
+AssetCatalogTreeViewUnassignedItem::DropController::DropController(AssetCatalogTreeView &tree_view)
+ : ui::AbstractTreeViewItemDropController(tree_view)
+{
+}
+
+bool AssetCatalogTreeViewUnassignedItem::DropController::can_drop(
+ const wmDrag &drag, const char **r_disabled_hint) const
{
if (drag.type != WM_DRAG_ASSET_LIST) {
return false;
}
- return AssetCatalogTreeViewItem::has_droppable_item(drag);
+ return AssetCatalogDropController::has_droppable_asset(drag, r_disabled_hint);
}
-std::string AssetCatalogTreeViewUnassignedItem::drop_tooltip(const bContext & /*C*/,
- const wmDrag &drag,
- const wmEvent & /*event*/) const
+std::string AssetCatalogTreeViewUnassignedItem::DropController::drop_tooltip(
+ const wmDrag &drag) const
{
const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
const bool is_multiple_assets = !BLI_listbase_is_single(asset_drags);
@@ -401,16 +531,17 @@ std::string AssetCatalogTreeViewUnassignedItem::drop_tooltip(const bContext & /*
TIP_("Move asset out of any catalog");
}
-bool AssetCatalogTreeViewUnassignedItem::on_drop(const wmDrag &drag)
+bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(const wmDrag &drag)
{
- const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>(
- get_tree_view());
/* Assign to nil catalog ID. */
- return AssetCatalogTreeViewItem::drop_into_catalog(tree_view, drag, CatalogID{});
+ return AssetCatalogDropController::drop_assets_into_catalog(
+ tree_view<AssetCatalogTreeView>(), drag, CatalogID{});
}
} // namespace blender::ed::asset_browser
+/* ---------------------------------------------------------------------- */
+
namespace blender::ed::asset_browser {
class AssetCatalogFilterSettings {
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 24b24eb81dd..2e2f0c146d6 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -190,6 +190,7 @@ static void file_draw_icon(const SpaceFile *sfile,
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
+ file->asset_data,
asset_params->import_type,
icon,
preview_image,
@@ -242,8 +243,9 @@ static void file_draw_string(int sx,
}
/**
- * \param r_sx, r_sy: The lower right corner of the last line drawn. AKA the cursor position on
- * completion.
+ * \param r_sx, r_sy: The lower right corner of the last line drawn, plus the height of the last
+ * line. This is the cursor position on completion to allow drawing more text
+ * behind that.
*/
static void file_draw_string_multiline(int sx,
int sy,
@@ -515,6 +517,7 @@ static void file_draw_preview(const SpaceFile *sfile,
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
+ file->asset_data,
asset_params->import_type,
icon,
imb,
@@ -1064,7 +1067,9 @@ void file_draw_list(const bContext *C, ARegion *region)
layout->curr_size = params->thumbnail_size;
}
-static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion *region)
+static void file_draw_invalid_library_hint(const bContext *C,
+ const SpaceFile *sfile,
+ ARegion *region)
{
const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
@@ -1072,9 +1077,7 @@ static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion
file_path_to_ui_path(asset_params->base_params.dir, library_ui_path, sizeof(library_ui_path));
uchar text_col[4];
- uchar text_alert_col[4];
UI_GetThemeColor4ubv(TH_TEXT, text_col);
- UI_GetThemeColor4ubv(TH_REDALERT, text_alert_col);
const View2D *v2d = &region->v2d;
const int pad = sfile->layout->tile_border_x;
@@ -1085,23 +1088,42 @@ static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion
int sy = v2d->tot.ymax;
{
- const char *message = TIP_("Library not found");
- const int draw_string_str_len = strlen(message) + 2 + sizeof(library_ui_path);
- char *draw_string = alloca(draw_string_str_len);
- BLI_snprintf(draw_string, draw_string_str_len, "%s: %s", message, library_ui_path);
- file_draw_string_multiline(sx, sy, draw_string, width, line_height, text_alert_col, NULL, &sy);
+ const char *message = TIP_("Path to asset library does not exist:");
+ file_draw_string_multiline(sx, sy, message, width, line_height, text_col, NULL, &sy);
+
+ sy -= line_height;
+ file_draw_string(sx, sy, library_ui_path, width, line_height, UI_STYLE_TEXT_LEFT, text_col);
}
- /* Next line, but separate it a bit further. */
- sy -= line_height;
+ /* Separate a bit further. */
+ sy -= line_height * 2.2f;
{
UI_icon_draw(sx, sy - UI_UNIT_Y, ICON_INFO);
const char *suggestion = TIP_(
- "Set up the library or edit libraries in the Preferences, File Paths section");
+ "Asset Libraries are local directories that can contain .blend files with assets inside.\n"
+ "Manage Asset Libraries from the File Paths section in Preferences.");
file_draw_string_multiline(
- sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, NULL, NULL);
+ sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, NULL, &sy);
+
+ uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
+ uiBut *but = uiDefIconTextButO(block,
+ UI_BTYPE_BUT,
+ "SCREEN_OT_userpref_show",
+ WM_OP_INVOKE_DEFAULT,
+ ICON_PREFERENCES,
+ NULL,
+ sx + UI_UNIT_X,
+ sy - line_height - UI_UNIT_Y * 1.2f,
+ UI_UNIT_X * 8,
+ UI_UNIT_Y,
+ NULL);
+ PointerRNA *but_opptr = UI_but_operator_ptr_get(but);
+ RNA_enum_set(but_opptr, "section", USER_SECTION_FILE_PATHS);
+
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
}
}
@@ -1109,7 +1131,7 @@ static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion
* Draw a string hint if the file list is invalid.
* \return true if the list is invalid and a hint was drawn.
*/
-bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region)
+bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region)
{
FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
/* Only for asset browser. */
@@ -1122,7 +1144,7 @@ bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region)
return false;
}
- file_draw_invalid_library_hint(sfile, region);
+ file_draw_invalid_library_hint(C, sfile, region);
return true;
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index ba08777e4e2..4be5d6d8008 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -47,7 +47,7 @@ struct View2D;
void file_calc_previews(const bContext *C, ARegion *region);
void file_draw_list(const bContext *C, ARegion *region);
-bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region);
+bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region);
void file_draw_check_ex(bContext *C, struct ScrArea *area);
void file_draw_check(bContext *C);
@@ -79,6 +79,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot);
void FILE_OT_previous(struct wmOperatorType *ot);
void FILE_OT_next(struct wmOperatorType *ot);
void FILE_OT_refresh(struct wmOperatorType *ot);
+void FILE_OT_asset_library_refresh(struct wmOperatorType *ot);
void FILE_OT_filenum(struct wmOperatorType *ot);
void FILE_OT_delete(struct wmOperatorType *ot);
void FILE_OT_rename(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index f647e1d4e4f..4eb10e65867 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1950,8 +1950,36 @@ void FILE_OT_refresh(struct wmOperatorType *ot)
/* api callbacks */
ot->exec = file_refresh_exec;
- /* Operator works for file or asset browsing */
- ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
+ ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Refresh Asset Library Operator
+ * \{ */
+
+static int file_asset_library_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+
+ ED_fileselect_clear(wm, sfile);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void FILE_OT_asset_library_refresh(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Refresh Asset Library";
+ ot->description = "Reread assets and asset catalogs from the asset library on disk";
+ ot->idname = "FILE_OT_asset_library_refresh";
+
+ /* api callbacks */
+ ot->exec = file_asset_library_refresh_exec;
+ ot->poll = ED_operator_asset_browsing_active;
}
/** \} */
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index 51d0581d6a4..0e468718a04 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -247,7 +247,7 @@ static void file_panel_asset_catalog_buttons_draw(const bContext *C, Panel *pane
uiItemR(row, &params_ptr, "asset_library_ref", 0, "", ICON_NONE);
if (params->asset_library_ref.type != ASSET_LIBRARY_LOCAL) {
- uiItemO(row, "", ICON_FILE_REFRESH, "FILE_OT_refresh");
+ uiItemO(row, "", ICON_FILE_REFRESH, "FILE_OT_asset_library_refresh");
}
uiItemS(col);
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index d329a8809c7..a73fa2b9740 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -817,88 +817,85 @@ static bool is_filtered_hidden(const char *filename,
return false;
}
-static bool is_filtered_file(FileListInternEntry *file,
- const char *UNUSED(root),
- FileListFilter *filter)
+/**
+ * Apply the filter string as file path matching pattern.
+ * \return true when the file should be in the result set, false if it should be filtered out. */
+static bool is_filtered_file_relpath(const FileListInternEntry *file, const FileListFilter *filter)
{
- bool is_filtered = !is_filtered_hidden(file->relpath, filter, file);
+ if (filter->filter_search[0] == '\0') {
+ return true;
+ }
- if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
- /* We only check for types if some type are enabled in filtering. */
- if (filter->filter && (filter->flags & FLF_DO_FILTER)) {
- if (file->typeflag & FILE_TYPE_DIR) {
- if (file->typeflag &
- (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
- if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
- is_filtered = false;
- }
- }
- else {
- if (!(filter->filter & FILE_TYPE_FOLDER)) {
- is_filtered = false;
- }
+ /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
+ return fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) == 0;
+}
+
+/** \return true when the file should be in the result set, false if it should be filtered out. */
+static bool is_filtered_file_type(const FileListInternEntry *file, const FileListFilter *filter)
+{
+ if (is_filtered_hidden(file->relpath, filter, file)) {
+ return false;
+ }
+
+ if (FILENAME_IS_CURRPAR(file->relpath)) {
+ return false;
+ }
+
+ /* We only check for types if some type are enabled in filtering. */
+ if (filter->filter && (filter->flags & FLF_DO_FILTER)) {
+ if (file->typeflag & FILE_TYPE_DIR) {
+ if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
+ if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
+ return false;
}
}
else {
- if (!(file->typeflag & filter->filter)) {
- is_filtered = false;
+ if (!(filter->filter & FILE_TYPE_FOLDER)) {
+ return false;
}
}
}
- /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
- if (is_filtered && (filter->filter_search[0] != '\0')) {
- if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
- is_filtered = false;
+ else {
+ if (!(file->typeflag & filter->filter)) {
+ return false;
}
}
}
+ return true;
+}
- return is_filtered;
+/** \return true when the file should be in the result set, false if it should be filtered out. */
+static bool is_filtered_file(FileListInternEntry *file,
+ const char *UNUSED(root),
+ FileListFilter *filter)
+{
+ return is_filtered_file_type(file, filter) && is_filtered_file_relpath(file, filter);
}
-static bool is_filtered_id_file(const FileListInternEntry *file,
- const char *id_group,
- const char *name,
- const FileListFilter *filter)
+static bool is_filtered_id_file_type(const FileListInternEntry *file,
+ const char *id_group,
+ const char *name,
+ const FileListFilter *filter)
{
- bool is_filtered = !is_filtered_hidden(file->relpath, filter, file);
- if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
- /* We only check for types if some type are enabled in filtering. */
- if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
- if (file->typeflag & FILE_TYPE_DIR) {
- if (file->typeflag &
- (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
- if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
- is_filtered = false;
- }
- }
- else {
- if (!(filter->filter & FILE_TYPE_FOLDER)) {
- is_filtered = false;
- }
- }
- }
- if (is_filtered && id_group) {
- if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
- is_filtered = false;
- }
- else {
- uint64_t filter_id = groupname_to_filter_id(id_group);
- if (!(filter_id & filter->filter_id)) {
- is_filtered = false;
- }
- }
+ if (!is_filtered_file_type(file, filter)) {
+ return false;
+ }
+
+ /* We only check for types if some type are enabled in filtering. */
+ if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
+ if (id_group) {
+ if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
+ return false;
}
- }
- /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
- if (is_filtered && (filter->filter_search[0] != '\0')) {
- if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
- is_filtered = false;
+
+ uint64_t filter_id = groupname_to_filter_id(id_group);
+ if (!(filter_id & filter->filter_id)) {
+ return false;
}
}
}
- return is_filtered;
+ return true;
}
/**
@@ -921,40 +918,100 @@ static void prepare_filter_asset_library(const FileList *filelist, FileListFilte
file_ensure_updated_catalog_filter_data(filter->asset_catalog_filter, filelist->asset_library);
}
+/**
+ * Copy a string from source to `dest`, but prefix and suffix it with a single space.
+ * Assumes `dest` has at least space enough for the two spaces.
+ */
+static void tag_copy_with_spaces(char *dest, const char *source, const size_t dest_size)
+{
+ BLI_assert(dest_size > 2);
+ const size_t source_length = BLI_strncpy_rlen(dest + 1, source, dest_size - 2);
+ dest[0] = ' ';
+ dest[source_length + 1] = ' ';
+ dest[source_length + 2] = '\0';
+}
+
+/**
+ * Return whether at least one tag matches the search filter.
+ * Tags are searched as "entire words", so instead of searching for "tag" in the
+ * filter string, this function searches for " tag ". Assumes the search filter
+ * starts and ends with a space.
+ *
+ * Here the tags on the asset are written in set notation:
+ *
+ * `asset_tag_matches_filter(" some tags ", {"some", "blue"})` -> true
+ * `asset_tag_matches_filter(" some tags ", {"som", "tag"})` -> false
+ * `asset_tag_matches_filter(" some tags ", {})` -> false
+ */
+static bool asset_tag_matches_filter(const char *filter_search, const AssetMetaData *asset_data)
+{
+ LISTBASE_FOREACH (const AssetTag *, asset_tag, &asset_data->tags) {
+ char tag_name[MAX_NAME + 2]; /* sizeof(AssetTag::name) + 2 */
+ tag_copy_with_spaces(tag_name, asset_tag->name, sizeof(tag_name));
+ if (BLI_strcasestr(filter_search, tag_name) != NULL) {
+ return true;
+ }
+ }
+ return false;
+}
+
static bool is_filtered_asset(FileListInternEntry *file, FileListFilter *filter)
{
+ const AssetMetaData *asset_data = filelist_file_internal_get_asset_data(file);
+
/* Not used yet for the asset view template. */
- if (!filter->asset_catalog_filter) {
+ if (filter->asset_catalog_filter && !file_is_asset_visible_in_catalog_filter_settings(
+ filter->asset_catalog_filter, asset_data)) {
+ return false;
+ }
+
+ if (filter->filter_search[0] == '\0') {
+ /* If there is no filter text, everything matches. */
return true;
}
- const AssetMetaData *asset_data = filelist_file_internal_get_asset_data(file);
- return file_is_asset_visible_in_catalog_filter_settings(filter->asset_catalog_filter,
- asset_data);
+ /* filter->filter_search contains "*the search text*". */
+ char filter_search[66]; /* sizeof(FileListFilter::filter_search) */
+ const size_t string_length = STRNCPY_RLEN(filter_search, filter->filter_search);
+
+ /* When doing a name comparison, get rid of the leading/trailing asterisks. */
+ filter_search[string_length - 1] = '\0';
+ if (BLI_strcasestr(file->name, filter_search + 1) != NULL) {
+ return true;
+ }
+
+ /* Replace the asterisks with spaces, so that we can do matching on " sometag "; that way
+ * an artist searching for "redder" doesn't result in a match for the tag "red". */
+ filter_search[string_length - 1] = ' ';
+ filter_search[0] = ' ';
+
+ return asset_tag_matches_filter(filter_search, asset_data);
}
-static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
+static bool is_filtered_lib_type(FileListInternEntry *file,
+ const char *root,
+ FileListFilter *filter)
{
- bool is_filtered;
char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
BLI_join_dirfile(path, sizeof(path), root, file->relpath);
if (BLO_library_path_explode(path, dir, &group, &name)) {
- is_filtered = is_filtered_id_file(file, group, name, filter);
- }
- else {
- is_filtered = is_filtered_file(file, root, filter);
+ return is_filtered_id_file_type(file, group, name, filter);
}
+ return is_filtered_file_type(file, filter);
+}
- return is_filtered;
+static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
+{
+ return is_filtered_lib_type(file, root, filter) && is_filtered_file_relpath(file, filter);
}
static bool is_filtered_asset_library(FileListInternEntry *file,
const char *root,
FileListFilter *filter)
{
- return is_filtered_lib(file, root, filter) && is_filtered_asset(file, filter);
+ return is_filtered_lib_type(file, root, filter) && is_filtered_asset(file, filter);
}
static bool is_filtered_main(FileListInternEntry *file,
@@ -969,7 +1026,7 @@ static bool is_filtered_main_assets(FileListInternEntry *file,
FileListFilter *filter)
{
/* "Filtered" means *not* being filtered out... So return true if the file should be visible. */
- return is_filtered_id_file(file, file->relpath, file->name, filter) &&
+ return is_filtered_id_file_type(file, file->relpath, file->name, filter) &&
is_filtered_asset(file, filter);
}
@@ -1854,6 +1911,7 @@ static void filelist_clear_asset_library(FileList *filelist)
{
/* The AssetLibraryService owns the AssetLibrary pointer, so no need for us to free it. */
filelist->asset_library = NULL;
+ file_delete_asset_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter);
}
void filelist_clear_ex(struct FileList *filelist,
@@ -1953,7 +2011,6 @@ void filelist_free(struct FileList *filelist)
filelist->selection_state = NULL;
}
- file_delete_asset_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter);
MEM_SAFE_FREE(filelist->asset_library_ref);
memset(&filelist->filter_data, 0, sizeof(filelist->filter_data));
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 6ab7e4eeecf..ce76fd65a86 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -486,6 +486,18 @@ struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile)
return filelist_file_get_id(file);
}
+void ED_fileselect_activate_asset_catalog(const SpaceFile *sfile, const bUUID catalog_id)
+{
+ if (!ED_fileselect_is_asset_browser(sfile)) {
+ return;
+ }
+
+ FileAssetSelectParams *params = ED_fileselect_get_asset_params(sfile);
+ params->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
+ params->catalog_id = catalog_id;
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, NULL);
+}
+
static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data)
{
ID *asset_id = (ID *)custom_data;
@@ -517,14 +529,12 @@ void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool def
const FileDirEntry *file = filelist_file_ex(files, file_index, false);
if (filelist_file_get_id(file) != asset_id) {
- filelist_entry_select_set(files, file, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
continue;
}
params->active_file = file_index;
filelist_entry_select_set(files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
-
- /* Keep looping to deselect the other files. */
+ break;
}
WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, NULL);
@@ -984,6 +994,8 @@ static void file_attribute_columns_init(const FileSelectParams *params, FileLayo
void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
{
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ /* Request a slightly more compact layout for asset browsing. */
+ const bool compact = ED_fileselect_is_asset_browser(sfile);
FileLayout *layout = NULL;
View2D *v2d = &region->v2d;
int numfiles;
@@ -1003,12 +1015,13 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
layout->textheight = textheight;
if (params->display == FILE_IMGDISPLAY) {
+ const float pad_fac = compact ? 0.15f : 0.3f;
layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
- layout->tile_border_x = 0.3f * UI_UNIT_X;
- layout->tile_border_y = 0.3f * UI_UNIT_X;
- layout->prv_border_x = 0.3f * UI_UNIT_X;
- layout->prv_border_y = 0.3f * UI_UNIT_Y;
+ layout->tile_border_x = pad_fac * UI_UNIT_X;
+ layout->tile_border_y = pad_fac * UI_UNIT_X;
+ layout->prv_border_x = pad_fac * UI_UNIT_X;
+ layout->prv_border_y = pad_fac * UI_UNIT_Y;
layout->tile_w = layout->prv_w + 2 * layout->prv_border_x;
layout->tile_h = layout->prv_h + 2 * layout->prv_border_y + textheight;
layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index a875b7a2c12..b115c63a569 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -659,7 +659,7 @@ static void file_main_region_draw(const bContext *C, ARegion *region)
file_highlight_set(sfile, region, event->xy[0], event->xy[1]);
}
- if (!file_draw_hint_if_invalid(sfile, region)) {
+ if (!file_draw_hint_if_invalid(C, sfile, region)) {
file_draw_list(C, region);
}
@@ -688,6 +688,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_previous);
WM_operatortype_append(FILE_OT_next);
WM_operatortype_append(FILE_OT_refresh);
+ WM_operatortype_append(FILE_OT_asset_library_refresh);
WM_operatortype_append(FILE_OT_bookmark_add);
WM_operatortype_append(FILE_OT_bookmark_delete);
WM_operatortype_append(FILE_OT_bookmark_cleanup);
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 4694d8652f6..bf2d20cf4c9 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -323,12 +323,19 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uin
{
const float yheight = ymaxc - yminc;
- immUniformColor3f(0.7f, 0.7f, 0.7f);
-
/* draw with AA'd line */
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
+ /* Fully opaque line on selected strips. */
+ if (strip->flag & NLASTRIP_FLAG_SELECT) {
+ /* TODO: Use theme setting. */
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+ }
+ else {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ }
+
/* influence -------------------------- */
if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
FCurve *fcu = BKE_fcurve_find(&strip->fcurves, "influence", 0);
@@ -501,7 +508,7 @@ static void nla_draw_strip(SpaceNla *snla,
/* strip is in normal track */
UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */
- UI_draw_roundbox_shade_x(
+ UI_draw_roundbox_4fv(
&(const rctf){
.xmin = strip->start,
.xmax = strip->end,
@@ -509,9 +516,7 @@ static void nla_draw_strip(SpaceNla *snla,
.ymax = ymaxc,
},
true,
- 0.0,
- 0.5,
- 0.1,
+ 0.0f,
color);
/* restore current vertex format & program (roundbox trashes it) */
@@ -545,11 +550,9 @@ static void nla_draw_strip(SpaceNla *snla,
/* draw strip outline
* - color used here is to indicate active vs non-active
*/
- if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
+ if (strip->flag & (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT)) {
/* strip should appear 'sunken', so draw a light border around it */
- color[0] = 0.9f; /* FIXME: hardcoded temp-hack colors */
- color[1] = 1.0f;
- color[2] = 0.9f;
+ color[0] = color[1] = color[2] = 1.0f; /* FIXME: hardcoded temp-hack colors */
}
else {
/* strip should appear to stand out, so draw a dark border around it */
@@ -566,7 +569,7 @@ static void nla_draw_strip(SpaceNla *snla,
}
else {
/* non-muted - draw solid, rounded outline */
- UI_draw_roundbox_shade_x(
+ UI_draw_roundbox_4fv(
&(const rctf){
.xmin = strip->start,
.xmax = strip->end,
@@ -574,9 +577,7 @@ static void nla_draw_strip(SpaceNla *snla,
.ymax = ymaxc,
},
false,
- 0.0,
- 0.0,
- 0.1,
+ 0.0f,
color);
/* restore current vertex format & program (roundbox trashes it) */
@@ -661,7 +662,7 @@ static void nla_draw_strip_text(AnimData *adt,
}
/* set text color - if colors (see above) are light, draw black text, otherwise draw white */
- if (strip->flag & (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_TWEAKUSER)) {
+ if (strip->flag & (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_TWEAKUSER)) {
col[0] = col[1] = col[2] = 0;
}
else {
@@ -805,29 +806,6 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
immRectf(
pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP, v2d->cur.xmax, ymax - NLACHANNEL_SKIP);
- /* draw 'embossed' lines above and below the strip for effect */
- /* white base-lines */
- GPU_line_width(2.0f);
- immUniformColor4f(1.0f, 1.0f, 1.0f, 0.3f);
- immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmax, ymin + NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmin, ymax - NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmax, ymax - NLACHANNEL_SKIP);
- immEnd();
-
- /* black top-lines */
- GPU_line_width(1.0f);
- immUniformColor3f(0.0f, 0.0f, 0.0f);
- immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmax, ymin + NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmin, ymax - NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmax, ymax - NLACHANNEL_SKIP);
- immEnd();
-
- /* TODO: these lines but better --^ */
-
immUnbindProgram();
/* draw keyframes in the action */
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 80d3b43bf6b..600309c2c86 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -40,6 +40,7 @@ set(INC
set(SRC
drawnode.cc
node_add.cc
+ node_context_path.cc
node_draw.cc
node_edit.cc
node_geometry_attribute_search.cc
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index 8a63a1f3505..24f5decacdf 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -3619,7 +3619,39 @@ static void std_node_socket_draw(
break;
}
case SOCK_IMAGE: {
- uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
+ const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id;
+ if (node_tree->type == NTREE_GEOMETRY) {
+ if (text[0] == '\0') {
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "default_value",
+ "image.new",
+ "image.open",
+ nullptr,
+ 0,
+ ICON_NONE,
+ nullptr);
+ }
+ else {
+ /* 0.3 split ratio is inconsistent, but use it here because the "New" button is large. */
+ uiLayout *row = uiLayoutSplit(layout, 0.3f, false);
+ uiItemL(row, text, 0);
+ uiTemplateID(row,
+ C,
+ ptr,
+ "default_value",
+ "image.new",
+ "image.open",
+ nullptr,
+ 0,
+ ICON_NONE,
+ nullptr);
+ }
+ }
+ else {
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
+ }
break;
}
case SOCK_COLLECTION: {
@@ -4297,6 +4329,25 @@ void node_draw_link_bezier(const View2D *v2d,
UI_GetThemeColor4fv(th_col2, colors[2]);
}
+ /* Highlight links connected to selected nodes. */
+ const bool is_fromnode_selected = link->fromnode && link->fromnode->flag & SELECT;
+ const bool is_tonode_selected = link->tonode && link->tonode->flag & SELECT;
+ if (is_fromnode_selected || is_tonode_selected) {
+ float color_selected[4];
+ UI_GetThemeColor4fv(TH_EDGE_SELECT, color_selected);
+ const float alpha = color_selected[3];
+
+ /* Interpolate color if highlight color is not fully transparent. */
+ if (alpha != 0.0) {
+ if (is_fromnode_selected) {
+ interp_v3_v3v3(colors[1], colors[1], color_selected, alpha);
+ }
+ if (is_tonode_selected) {
+ interp_v3_v3v3(colors[2], colors[2], color_selected, alpha);
+ }
+ }
+ }
+
if (g_batch_link.enabled && !highlighted) {
/* Add link to batch. */
nodelink_batch_add_link(snode,
@@ -4370,15 +4421,6 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
else if (link->flag & NODE_LINK_MUTED) {
th_col1 = th_col2 = TH_REDALERT;
}
- else {
- /* Regular link, highlight if connected to selected node. */
- if (link->fromnode && link->fromnode->flag & SELECT) {
- th_col1 = TH_EDGE_SELECT;
- }
- if (link->tonode && link->tonode->flag & SELECT) {
- th_col2 = TH_EDGE_SELECT;
- }
- }
}
else {
/* Invalid link. */
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 7b6ca5e6e61..cb66d0dbd2b 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -758,7 +758,7 @@ static bool node_add_file_poll(bContext *C)
{
const SpaceNode *snode = CTX_wm_space_node(C);
return ED_operator_node_editable(C) &&
- ELEM(snode->nodetree->type, NTREE_SHADER, NTREE_TEXTURE, NTREE_COMPOSIT);
+ ELEM(snode->nodetree->type, NTREE_SHADER, NTREE_TEXTURE, NTREE_COMPOSIT, NTREE_GEOMETRY);
}
static int node_add_file_exec(bContext *C, wmOperator *op)
@@ -784,6 +784,9 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
case NTREE_COMPOSIT:
type = CMP_NODE_IMAGE;
break;
+ case NTREE_GEOMETRY:
+ type = GEO_NODE_IMAGE_TEXTURE;
+ break;
default:
return OPERATOR_CANCELLED;
}
@@ -797,7 +800,14 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- node->id = (ID *)ima;
+ if (type == GEO_NODE_IMAGE_TEXTURE) {
+ bNodeSocket *image_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocketValueImage *socket_value = (bNodeSocketValueImage *)image_socket->default_value;
+ socket_value->value = ima;
+ }
+ else {
+ node->id = (ID *)ima;
+ }
/* When adding new image file via drag-drop we need to load imbuf in order
* to get proper image source.
diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc
new file mode 100644
index 00000000000..a0ff7f3ce25
--- /dev/null
+++ b/source/blender/editors/space_node/node_context_path.cc
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup spnode
+ * \brief Node breadcrumbs drawing
+ */
+
+#include "BLI_vector.hh"
+
+#include "DNA_node_types.h"
+
+#include "BKE_context.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BKE_screen.h"
+
+#include "RNA_access.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_resources.h"
+
+#include "UI_interface.hh"
+
+#include "node_intern.h"
+
+struct Mesh;
+struct Curve;
+struct Light;
+struct World;
+struct Material;
+
+namespace blender::ed::space_node {
+
+static void context_path_add_object_data(Vector<ui::ContextPathItem> &path, Object &object)
+{
+ if (object.type == OB_MESH && object.data) {
+ Mesh *mesh = (Mesh *)object.data;
+ ui::context_path_add_generic(path, RNA_Mesh, mesh);
+ }
+ if (object.type == OB_LAMP && object.data) {
+ Light *light = (Light *)object.data;
+ ui::context_path_add_generic(path, RNA_Light, light);
+ }
+ if (ELEM(object.type, OB_CURVE, OB_FONT, OB_SURF) && object.data) {
+ Curve *curve = (Curve *)object.data;
+ ui::context_path_add_generic(path, RNA_Curve, curve);
+ }
+}
+
+static void context_path_add_node_tree_and_node_groups(const SpaceNode &snode,
+ Vector<ui::ContextPathItem> &path,
+ const bool skip_base = false)
+{
+ Vector<const bNodeTreePath *> tree_path = snode.treepath;
+ for (const bNodeTreePath *path_item : tree_path.as_span().drop_front(int(skip_base))) {
+ ui::context_path_add_generic(path, RNA_NodeTree, path_item->nodetree, ICON_NODETREE);
+ }
+}
+
+static void get_context_path_node_shader(const bContext &C,
+ SpaceNode &snode,
+ Vector<ui::ContextPathItem> &path)
+{
+ if (snode.flag & SNODE_PIN) {
+ if (snode.shaderfrom == SNODE_SHADER_WORLD) {
+ Scene *scene = CTX_data_scene(&C);
+ ui::context_path_add_generic(path, RNA_Scene, scene);
+ if (scene != nullptr) {
+ World *world = scene->world;
+ ui::context_path_add_generic(path, RNA_World, world);
+ }
+ /* Skip the base node tree here, because the world contains a node tree already. */
+ context_path_add_node_tree_and_node_groups(snode, path, true);
+ }
+ else {
+ context_path_add_node_tree_and_node_groups(snode, path);
+ }
+ }
+ else {
+ Object *object = CTX_data_active_object(&C);
+ if (snode.shaderfrom == SNODE_SHADER_OBJECT && object != nullptr) {
+ ui::context_path_add_generic(path, RNA_Object, object);
+ if (!(object->matbits && object->matbits[object->actcol - 1])) {
+ context_path_add_object_data(path, *object);
+ }
+ Material *material = BKE_object_material_get(object, object->actcol);
+ ui::context_path_add_generic(path, RNA_Material, material);
+ }
+ else if (snode.shaderfrom == SNODE_SHADER_WORLD) {
+ Scene *scene = CTX_data_scene(&C);
+ ui::context_path_add_generic(path, RNA_Scene, scene);
+ if (scene != nullptr) {
+ World *world = scene->world;
+ ui::context_path_add_generic(path, RNA_World, world);
+ }
+ }
+#ifdef WITH_FREESTYLE
+ else if (snode.shaderfrom == SNODE_SHADER_LINESTYLE) {
+ ViewLayer *viewlayer = CTX_data_view_layer(&C);
+ FreestyleLineStyle *linestyle = BKE_linestyle_active_from_view_layer(viewlayer);
+ ui::context_path_add_generic(path, RNA_ViewLayer, viewlayer);
+ Material *mat = BKE_object_material_get(object, object->actcol);
+ ui::context_path_add_generic(path, RNA_Material, mat);
+ }
+#endif
+ context_path_add_node_tree_and_node_groups(snode, path, true);
+ }
+}
+
+static void get_context_path_node_compositor(const bContext &C,
+ SpaceNode &snode,
+ Vector<ui::ContextPathItem> &path)
+{
+ if (snode.flag & SNODE_PIN) {
+ context_path_add_node_tree_and_node_groups(snode, path);
+ }
+ else {
+ Scene *scene = CTX_data_scene(&C);
+ ui::context_path_add_generic(path, RNA_Scene, scene);
+ context_path_add_node_tree_and_node_groups(snode, path);
+ }
+}
+
+static void get_context_path_node_geometry(const bContext &C,
+ SpaceNode &snode,
+ Vector<ui::ContextPathItem> &path)
+{
+ if (snode.flag & SNODE_PIN) {
+ context_path_add_node_tree_and_node_groups(snode, path);
+ }
+ else {
+ Object *object = CTX_data_active_object(&C);
+ ui::context_path_add_generic(path, RNA_Object, object);
+ ModifierData *modifier = BKE_object_active_modifier(object);
+ ui::context_path_add_generic(path, RNA_Modifier, modifier, ICON_MODIFIER);
+ context_path_add_node_tree_and_node_groups(snode, path);
+ }
+}
+
+Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C)
+{
+ SpaceNode *snode = CTX_wm_space_node(&C);
+ if (snode == nullptr) {
+ return {};
+ }
+
+ Vector<ui::ContextPathItem> context_path;
+
+ if (snode->edittree->type == NTREE_GEOMETRY) {
+ get_context_path_node_geometry(C, *snode, context_path);
+ }
+ else if (snode->edittree->type == NTREE_SHADER) {
+ get_context_path_node_shader(C, *snode, context_path);
+ }
+ else if (snode->edittree->type == NTREE_COMPOSIT) {
+ get_context_path_node_compositor(C, *snode, context_path);
+ }
+
+ return context_path;
+}
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 97655080192..a6496294f96 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -71,8 +71,10 @@
#include "ED_gpencil.h"
#include "ED_node.h"
+#include "ED_screen.h"
#include "ED_space_api.h"
+#include "UI_interface.hh"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -728,7 +730,7 @@ static void node_draw_mute_line(const View2D *v2d, const SpaceNode *snode, const
GPU_blend(GPU_BLEND_ALPHA);
LISTBASE_FOREACH (const bNodeLink *, link, &node->internal_links) {
- node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1);
+ node_draw_link_bezier(v2d, snode, link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE);
}
GPU_blend(GPU_BLEND_NONE);
@@ -807,12 +809,10 @@ static void node_socket_outline_color_get(const bool selected,
float r_outline_color[4])
{
if (selected) {
- UI_GetThemeColor4fv(TH_TEXT_HI, r_outline_color);
- r_outline_color[3] = 0.9f;
+ UI_GetThemeColor4fv(TH_ACTIVE, r_outline_color);
}
else {
- copy_v4_fl(r_outline_color, 0.0f);
- r_outline_color[3] = 0.6f;
+ UI_GetThemeColor4fv(TH_WIRE, r_outline_color);
}
/* Until there is a better place for per socket color,
@@ -832,11 +832,6 @@ void node_socket_color_get(
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
sock->typeinfo->draw_color(C, &ptr, node_ptr, r_color);
-
- bNode *node = (bNode *)node_ptr->data;
- if (node->flag & NODE_MUTED) {
- r_color[3] *= 0.25f;
- }
}
struct SocketTooltipData {
@@ -854,60 +849,7 @@ static void create_inspection_string_for_generic_value(const geo_log::GenericVal
const GPointer value = value_log.value();
const CPPType &type = *value.type();
- if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) {
- const CPPType &base_type = field_type->field_type();
- BUFFER_FOR_CPP_TYPE_VALUE(base_type, buffer);
- const GField &field = field_type->get_gfield(value.get());
- if (field.node().depends_on_input()) {
- if (base_type.is<int>()) {
- ss << TIP_("Integer Field");
- }
- else if (base_type.is<float>()) {
- ss << TIP_("Float Field");
- }
- else if (base_type.is<blender::float3>()) {
- ss << TIP_("Vector Field");
- }
- else if (base_type.is<bool>()) {
- ss << TIP_("Boolean Field");
- }
- else if (base_type.is<std::string>()) {
- ss << TIP_("String Field");
- }
- ss << TIP_(" based on:\n");
-
- /* Use vector set to deduplicate inputs. */
- VectorSet<std::reference_wrapper<const FieldInput>> field_inputs;
- field.node().foreach_field_input(
- [&](const FieldInput &field_input) { field_inputs.add(field_input); });
- for (const FieldInput &field_input : field_inputs) {
- ss << "\u2022 " << field_input.socket_inspection_name();
- if (field_input != field_inputs.as_span().last().get()) {
- ss << ".\n";
- }
- }
- }
- else {
- blender::fn::evaluate_constant_field(field, buffer);
- if (base_type.is<int>()) {
- ss << *(int *)buffer << TIP_(" (Integer)");
- }
- else if (base_type.is<float>()) {
- ss << *(float *)buffer << TIP_(" (Float)");
- }
- else if (base_type.is<blender::float3>()) {
- ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
- }
- else if (base_type.is<bool>()) {
- ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
- }
- else if (base_type.is<std::string>()) {
- ss << *(std::string *)buffer << TIP_(" (String)");
- }
- base_type.destruct(buffer);
- }
- }
- else if (type.is<Object *>()) {
+ if (type.is<Object *>()) {
id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB);
}
else if (type.is<Material *>()) {
@@ -924,6 +866,71 @@ static void create_inspection_string_for_generic_value(const geo_log::GenericVal
}
}
+static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &value_log,
+ std::stringstream &ss)
+{
+ const CPPType &type = value_log.type();
+ const GField &field = value_log.field();
+ const Span<std::string> input_tooltips = value_log.input_tooltips();
+
+ if (input_tooltips.is_empty()) {
+ if (field) {
+ BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
+ blender::fn::evaluate_constant_field(field, buffer);
+ if (type.is<int>()) {
+ ss << *(int *)buffer << TIP_(" (Integer)");
+ }
+ else if (type.is<float>()) {
+ ss << *(float *)buffer << TIP_(" (Float)");
+ }
+ else if (type.is<blender::float3>()) {
+ ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
+ }
+ else if (type.is<bool>()) {
+ ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
+ }
+ else if (type.is<std::string>()) {
+ ss << *(std::string *)buffer << TIP_(" (String)");
+ }
+ type.destruct(buffer);
+ }
+ else {
+ /* Constant values should always be logged. */
+ BLI_assert_unreachable();
+ ss << "Value has not been logged";
+ }
+ }
+ else {
+ if (type.is<int>()) {
+ ss << TIP_("Integer field");
+ }
+ else if (type.is<float>()) {
+ ss << TIP_("Float field");
+ }
+ else if (type.is<blender::float3>()) {
+ ss << TIP_("Vector field");
+ }
+ else if (type.is<bool>()) {
+ ss << TIP_("Boolean field");
+ }
+ else if (type.is<std::string>()) {
+ ss << TIP_("String field");
+ }
+ else if (type.is<blender::ColorGeometry4f>()) {
+ ss << TIP_("Color field");
+ }
+ ss << TIP_(" based on:\n");
+
+ for (const int i : input_tooltips.index_range()) {
+ const blender::StringRef tooltip = input_tooltips[i];
+ ss << "\u2022 " << tooltip;
+ if (i < input_tooltips.size() - 1) {
+ ss << ".\n";
+ }
+ }
+ }
+}
+
static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log,
std::stringstream &ss)
{
@@ -1015,6 +1022,10 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
create_inspection_string_for_generic_value(*generic_value_log, ss);
}
+ if (const geo_log::GFieldValueLog *gfield_value_log =
+ dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) {
+ create_inspection_string_for_gfield(*gfield_value_log, ss);
+ }
else if (const geo_log::GeometryValueLog *geo_value_log =
dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
create_inspection_string_for_geometry(*geo_value_log, ss);
@@ -1156,7 +1167,7 @@ void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[
GPU_program_point_size(true);
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_SHAPE);
- immUniform1f("outline_scale", 0.7f);
+ immUniform1f("outline_scale", 1.0f);
immUniform2f("ViewportSize", -1.0f, -1.0f);
/* Single point. */
@@ -1301,7 +1312,7 @@ void node_draw_sockets(const View2D *v2d,
GPU_blend(GPU_BLEND_ALPHA);
GPU_program_point_size(true);
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_SHAPE);
- immUniform1f("outline_scale", 0.7f);
+ immUniform1f("outline_scale", 1.0f);
immUniform2f("ViewportSize", -1.0f, -1.0f);
/* Set handle size. */
@@ -1595,24 +1606,13 @@ static void node_draw_basis(const bContext *C,
/* Shadow. */
node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
+ rctf *rct = &node->totr;
float color[4];
int color_id = node_get_colorid(node);
- if (node->flag & NODE_MUTED) {
- /* Muted nodes are semi-transparent and colorless. */
- UI_GetThemeColor3fv(TH_NODE, color);
- color[3] = 0.25f;
- }
- else {
- /* Opaque headers for regular nodes. */
- UI_GetThemeColor3fv(color_id, color);
- color[3] = 1.0f;
- }
GPU_line_width(1.0f);
- rctf *rct = &node->totr;
- UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
-
+ /* Header. */
{
const rctf rect = {
rct->xmin,
@@ -1620,7 +1620,19 @@ static void node_draw_basis(const bContext *C,
rct->ymax - NODE_DY,
rct->ymax,
};
- UI_draw_roundbox_aa(&rect, true, BASIS_RAD, color);
+
+ float color_header[4];
+
+ /* Muted nodes get a mix of the background with the node color. */
+ if (node->flag & NODE_MUTED) {
+ UI_GetThemeColorBlend4f(TH_BACK, color_id, 0.1f, color_header);
+ }
+ else {
+ UI_GetThemeColorBlend4f(TH_NODE, color_id, 0.4f, color_header);
+ }
+
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
+ UI_draw_roundbox_4fv(&rect, true, BASIS_RAD, color_header);
}
/* Show/hide icons. */
@@ -1703,31 +1715,28 @@ static void node_draw_basis(const bContext *C,
UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
}
- /* Open/close entirely. */
+ /* Collapse/expand icon. */
{
- int but_size = U.widget_unit * 0.8f;
- /* XXX button uses a custom triangle draw below, so make it invisible without icon. */
+ const int but_size = U.widget_unit * 0.8f;
UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiBut *but = uiDefBut(node->block,
- UI_BTYPE_BUT_TOGGLE,
- 0,
- "",
- rct->xmin + 0.35f * U.widget_unit,
- rct->ymax - NODE_DY / 2.2f - but_size / 2,
- but_size,
- but_size,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- "");
+
+ uiBut *but = uiDefIconBut(node->block,
+ UI_BTYPE_BUT_TOGGLE,
+ 0,
+ ICON_DOWNARROW_HLT,
+ rct->xmin + (NODE_MARGIN_X / 3),
+ rct->ymax - NODE_DY / 2.2f - but_size / 2,
+ but_size,
+ but_size,
+ nullptr,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ "");
+
UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
UI_block_emboss_set(node->block, UI_EMBOSS);
-
- UI_GetThemeColor4fv(TH_TEXT, color);
- /* Custom draw function for this button. */
- UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, rct->ymax - NODE_DY / 2.2f, 'v', color);
}
char showname[128];
@@ -1737,7 +1746,7 @@ static void node_draw_basis(const bContext *C,
UI_BTYPE_LABEL,
0,
showname,
- (int)(rct->xmin + NODE_MARGIN_X),
+ (int)(rct->xmin + NODE_MARGIN_X + 0.4f),
(int)(rct->ymax - NODE_DY),
(short)(iconofs - rct->xmin - (18.0f * U.dpi_fac)),
(short)NODE_DY,
@@ -1751,49 +1760,96 @@ static void node_draw_basis(const bContext *C,
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
+ /* Wire across the node when muted/disabled. */
+ if (node->flag & NODE_MUTED) {
+ node_draw_mute_line(v2d, snode, node);
+ }
+
/* Body. */
- if (nodeTypeUndefined(node)) {
+ const float outline_width = 1.0f;
+ {
/* Use warning color to indicate undefined types. */
- UI_GetThemeColor4fv(TH_REDALERT, color);
- }
- else if (node->flag & NODE_MUTED) {
- /* Muted nodes are semi-transparent and colorless. */
- UI_GetThemeColor4fv(TH_NODE, color);
- }
- else if (node->flag & NODE_CUSTOM_COLOR) {
- rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
- }
- else {
- UI_GetThemeColor4fv(TH_NODE, color);
- }
+ if (nodeTypeUndefined(node)) {
+ UI_GetThemeColorBlend4f(TH_REDALERT, TH_NODE, 0.4f, color);
+ }
+ /* Muted nodes get a mix of the background with the node color. */
+ else if (node->flag & NODE_MUTED) {
+ UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color);
+ }
+ else if (node->flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_NODE, color);
+ }
- if (node->flag & NODE_MUTED) {
- color[3] = 0.5f;
+ /* Draw selected nodes fully opaque. */
+ if (node->flag & SELECT) {
+ color[3] = 1.0f;
+ }
+
+ /* Draw muted nodes slightly transparent so the wires inside are visible. */
+ if (node->flag & NODE_MUTED) {
+ color[3] -= 0.2f;
+ }
+
+ const rctf rect = {
+ rct->xmin,
+ rct->xmax,
+ rct->ymin,
+ rct->ymax - (NODE_DY + outline_width),
+ };
+
+ UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
+ UI_draw_roundbox_4fv(&rect, true, BASIS_RAD, color);
}
+ /* Header underline. */
{
- UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
+ float color_underline[4];
+
+ if (node->flag & NODE_MUTED) {
+ UI_GetThemeColor4fv(TH_WIRE, color_underline);
+ }
+ else {
+ UI_GetThemeColorBlend4f(TH_BACK, color_id, 0.2f, color_underline);
+ }
+
const rctf rect = {
rct->xmin,
rct->xmax,
- rct->ymin,
+ rct->ymax - (NODE_DY + outline_width),
rct->ymax - NODE_DY,
};
- UI_draw_roundbox_aa(&rect, true, BASIS_RAD, color);
+
+ UI_draw_roundbox_corner_set(UI_CNR_NONE);
+ UI_draw_roundbox_4fv(&rect, true, 0.0f, color_underline);
}
- /* Outline active and selected emphasis. */
- if (node->flag & SELECT) {
- UI_GetThemeColorShadeAlpha4fv(
- (node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
+ /* Outline. */
+ {
+ const rctf rect = {
+ rct->xmin - outline_width,
+ rct->xmax + outline_width,
+ rct->ymin - outline_width,
+ rct->ymax + outline_width,
+ };
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(rct, false, BASIS_RAD, color);
- }
+ /* Color the outline according to active, selected, or undefined status. */
+ float color_outline[4];
- /* Disable lines. */
- if (node->flag & NODE_MUTED) {
- node_draw_mute_line(v2d, snode, node);
+ if (node->flag & SELECT) {
+ UI_GetThemeColor4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
+ }
+ else if (nodeTypeUndefined(node)) {
+ UI_GetThemeColor4fv(TH_REDALERT, color_outline);
+ }
+ else {
+ UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color_outline);
+ }
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_4fv(&rect, false, BASIS_RAD, color_outline);
}
node_draw_sockets(v2d, C, ntree, node, true, false);
@@ -1828,46 +1884,45 @@ static void node_draw_hidden(const bContext *C,
float scale;
UI_view2d_scale_get(v2d, &scale, nullptr);
+ const int color_id = node_get_colorid(node);
+
/* Shadow. */
node_draw_shadow(snode, node, hiddenrad, 1.0f);
- /* Body. */
- float color[4];
- int color_id = node_get_colorid(node);
+ /* Wire across the node when muted/disabled. */
if (node->flag & NODE_MUTED) {
- /* Muted nodes are semi-transparent and colorless. */
- UI_GetThemeColor4fv(TH_NODE, color);
- color[3] = 0.25f;
- }
- else {
- UI_GetThemeColor4fv(color_id, color);
+ node_draw_mute_line(v2d, snode, node);
}
- UI_draw_roundbox_aa(rct, true, hiddenrad, color);
-
- /* Outline active and selected emphasis. */
- if (node->flag & SELECT) {
- UI_GetThemeColorShadeAlpha4fv(
- (node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
-
- UI_draw_roundbox_aa(rct, false, hiddenrad, color);
- }
+ /* Body. */
+ float color[4];
+ {
+ if (nodeTypeUndefined(node)) {
+ /* Use warning color to indicate undefined types. */
+ UI_GetThemeColorBlend4f(TH_REDALERT, TH_NODE, 0.4f, color);
+ }
+ else if (node->flag & NODE_MUTED) {
+ /* Muted nodes get a mix of the background with the node color. */
+ UI_GetThemeColorBlendShade4fv(TH_BACK, color_id, 0.1f, 0, color);
+ }
+ else if (node->flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
+ }
+ else {
+ UI_GetThemeColorBlend4f(TH_NODE, color_id, 0.4f, color);
+ }
- /* Custom color inline. */
- if (node->flag & NODE_CUSTOM_COLOR) {
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
+ /* Draw selected nodes fully opaque. */
+ if (node->flag & SELECT) {
+ color[3] = 1.0f;
+ }
- const rctf rect = {
- rct->xmin + 1,
- rct->xmax - 1,
- rct->ymin + 1,
- rct->ymax - 1,
- };
- UI_draw_roundbox_3fv_alpha(&rect, false, hiddenrad, node->color, 1.0f);
+ /* Draw muted nodes slightly transparent so the wires inside are visible. */
+ if (node->flag & NODE_MUTED) {
+ color[3] -= 0.2f;
+ }
- GPU_line_smooth(false);
- GPU_blend(GPU_BLEND_NONE);
+ UI_draw_roundbox_4fv(rct, true, hiddenrad, color);
}
/* Title. */
@@ -1878,36 +1933,28 @@ static void node_draw_hidden(const bContext *C,
UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
}
- /* Open / collapse icon. */
+ /* Collapse/expand icon. */
{
- int but_size = U.widget_unit * 0.8f;
- /* XXX button uses a custom triangle draw below, so make it invisible without icon */
+ const int but_size = U.widget_unit * 1.0f;
UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiBut *but = uiDefBut(node->block,
- UI_BTYPE_BUT_TOGGLE,
- 0,
- "",
- rct->xmin + 0.35f * U.widget_unit,
- centy - but_size / 2,
- but_size,
- but_size,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- "");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
- UI_block_emboss_set(node->block, UI_EMBOSS);
- UI_GetThemeColor4fv(TH_TEXT, color);
- /* Custom draw function for this button. */
- UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, centy, 'h', color);
- }
+ uiBut *but = uiDefIconBut(node->block,
+ UI_BTYPE_BUT_TOGGLE,
+ 0,
+ ICON_RIGHTARROW,
+ rct->xmin + (NODE_MARGIN_X / 3),
+ centy - but_size / 2,
+ but_size,
+ but_size,
+ nullptr,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ "");
- /* Disable lines. */
- if (node->flag & NODE_MUTED) {
- node_draw_mute_line(v2d, snode, node);
+ UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
+ UI_block_emboss_set(node->block, UI_EMBOSS);
}
char showname[128];
@@ -1927,15 +1974,44 @@ static void node_draw_hidden(const bContext *C,
0,
0,
"");
+
+ /* Outline. */
+ {
+ const float outline_width = 1.0f;
+ const rctf rect = {
+ rct->xmin - outline_width,
+ rct->xmax + outline_width,
+ rct->ymin - outline_width,
+ rct->ymax + outline_width,
+ };
+
+ /* Color the outline according to active, selected, or undefined status. */
+ float color_outline[4];
+
+ if (node->flag & SELECT) {
+ UI_GetThemeColor4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
+ }
+ else if (nodeTypeUndefined(node)) {
+ UI_GetThemeColor4fv(TH_REDALERT, color_outline);
+ }
+ else {
+ UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color_outline);
+ }
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_4fv(&rect, false, hiddenrad, color_outline);
+ }
+
if (node->flag & NODE_MUTED) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
/* Scale widget thing. */
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_blend(GPU_BLEND_ALPHA);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformThemeColorShade(color_id, -10);
+ immUniformThemeColorShadeAlpha(TH_TEXT, -40, -180);
float dx = 10.0f;
immBegin(GPU_PRIM_LINES, 4);
@@ -1946,7 +2022,7 @@ static void node_draw_hidden(const bContext *C,
immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy + 4.0f);
immEnd();
- immUniformThemeColorShade(color_id, 30);
+ immUniformThemeColorShadeAlpha(TH_TEXT, 0, -180);
dx -= snode->runtime->aspect;
immBegin(GPU_PRIM_LINES, 4);
@@ -1958,6 +2034,7 @@ static void node_draw_hidden(const bContext *C,
immEnd();
immUnbindProgram();
+ GPU_blend(GPU_BLEND_NONE);
node_draw_sockets(v2d, C, ntree, node, true, false);
@@ -2142,15 +2219,34 @@ void node_draw_nodetree(const bContext *C,
}
}
-/* Draw tree path info in lower left corner. */
-static void draw_tree_path(SpaceNode *snode)
+/* Draw the breadcrumb on the bottom of the editor. */
+static void draw_tree_path(const bContext &C, ARegion &region)
{
- char info[256];
+ using namespace blender;
+
+ GPU_matrix_push_projection();
+ wmOrtho2_region_pixelspace(&region);
+
+ const rcti *rect = ED_region_visible_rect(&region);
+
+ const uiStyle *style = UI_style_get_dpi();
+ const float padding_x = 16 * UI_DPI_FAC;
+ const int x = rect->xmin + padding_x;
+ const int y = region.winy - UI_UNIT_Y * 0.6f;
+ const int width = BLI_rcti_size_x(rect) - 2 * padding_x;
- ED_node_tree_path_get_fixedbuf(snode, info, sizeof(info));
+ uiBlock *block = UI_block_begin(&C, &region, __func__, UI_EMBOSS_NONE);
+ uiLayout *layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y, width, 1, 0, style);
- UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
- BLF_draw_default(1.5f * UI_UNIT_X, 1.5f * UI_UNIT_Y, 0.0f, info, sizeof(info));
+ Vector<ui::ContextPathItem> context_path = ed::space_node::context_path_for_space_node(C);
+ ui::template_breadcrumbs(*layout, context_path);
+
+ UI_block_layout_resolve(block, nullptr, nullptr);
+ UI_block_end(&C, block);
+ UI_block_draw(&C, block);
+
+ GPU_matrix_pop_projection();
}
static void snode_setup_v2d(SpaceNode *snode, ARegion *region, const float center[2])
@@ -2227,8 +2323,6 @@ void node_draw_space(const bContext *C, ARegion *region)
snode->runtime->cursor[0] /= UI_DPI_FAC;
snode->runtime->cursor[1] /= UI_DPI_FAC;
- int grid_levels = UI_GetThemeValueType(TH_NODE_GRID_LEVELS, SPACE_NODE);
-
ED_region_draw_cb_draw(C, region, REGION_DRAW_PRE_VIEW);
/* Only set once. */
@@ -2237,6 +2331,9 @@ void node_draw_space(const bContext *C, ARegion *region)
/* Nodes. */
snode_set_context(C);
+ const int grid_levels = UI_GetThemeValueType(TH_NODE_GRID_LEVELS, SPACE_NODE);
+ UI_view2d_dot_grid_draw(v2d, TH_GRID, NODE_GRID_STEP_SIZE, grid_levels);
+
/* Draw parent node trees. */
if (snode->treepath.last) {
bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
@@ -2264,9 +2361,6 @@ void node_draw_space(const bContext *C, ARegion *region)
if (ntree) {
snode_setup_v2d(snode, region, center);
- /* Grid. */
- UI_view2d_multi_grid_draw(v2d, TH_GRID, ED_node_grid_size(), NODE_GRID_STEPS, grid_levels);
-
/* Backdrop. */
draw_nodespace_back_pix(C, region, snode, path->parent_key);
@@ -2305,8 +2399,6 @@ void node_draw_space(const bContext *C, ARegion *region)
}
}
else {
- /* Default grid. */
- UI_view2d_multi_grid_draw(v2d, TH_GRID, ED_node_grid_size(), NODE_GRID_STEPS, grid_levels);
/* Backdrop. */
draw_nodespace_back_pix(C, region, snode, NODE_INSTANCE_KEY_NONE);
@@ -2324,8 +2416,10 @@ void node_draw_space(const bContext *C, ARegion *region)
}
}
- /* Tree path info. */
- draw_tree_path(snode);
+ /* Draw context path. */
+ if (snode->edittree) {
+ draw_tree_path(*C, *region);
+ }
/* Scrollers. */
UI_view2d_scrollers_draw(v2d, nullptr);
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index f069038cc09..c0d50e753ff 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -332,7 +332,7 @@ extern const char *node_context_dir[];
#define NODE_SOCKDY (0.1f * U.widget_unit)
#define NODE_WIDTH(node) (node->width * UI_DPI_FAC)
#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC)
-#define NODE_MARGIN_X (1.10f * U.widget_unit)
+#define NODE_MARGIN_X (1.2f * U.widget_unit)
#define NODE_SOCKSIZE (0.25f * U.widget_unit)
#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit)
#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit)
@@ -341,3 +341,11 @@ extern const char *node_context_dir[];
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+# include "BLI_vector.hh"
+# include "UI_interface.hh"
+namespace blender::ed::space_node {
+Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C);
+}
+#endif \ No newline at end of file
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index df4f63af20b..0c54da65e9c 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -156,6 +156,7 @@ void ED_operatormacros_node(void)
OPTYPE_UNDO | OPTYPE_REGISTER);
mot = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(mot->ptr, "remove_on_cancel", true);
+ RNA_boolean_set(mot->ptr, "view2d_edge_pan", true);
WM_operatortype_macro_define(ot, "NODE_OT_attach");
WM_operatortype_macro_define(ot, "NODE_OT_insert_offset");
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index b69e7e98bca..76aad684b4c 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -57,8 +57,12 @@
#include "BLT_translation.h"
+#include "NOD_node_tree_ref.hh"
+
#include "node_intern.h" /* own include */
+using namespace blender::nodes::node_tree_ref_types;
+
/* -------------------------------------------------------------------- */
/** \name Relations Helpers
* \{ */
@@ -612,160 +616,282 @@ static void snode_autoconnect(Main *bmain,
/** \name Link Viewer Operator
* \{ */
-static int node_link_viewer(const bContext *C, bNode *tonode)
-{
- SpaceNode *snode = CTX_wm_space_node(C);
+namespace blender::ed::nodes::viewer_linking {
- /* context check */
- if (tonode == nullptr || BLI_listbase_is_empty(&tonode->outputs)) {
- return OPERATOR_CANCELLED;
+/* Depending on the node tree type, different socket types are supported by viewer nodes. */
+static bool socket_can_be_viewed(const OutputSocketRef &socket)
+{
+ if (nodeSocketIsHidden(socket.bsocket())) {
+ return false;
}
- if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) {
- return OPERATOR_CANCELLED;
+ if (socket.idname() == "NodeSocketVirtual") {
+ return false;
}
+ if (socket.tree().btree()->type != NTREE_GEOMETRY) {
+ return true;
+ }
+ return ELEM(socket.typeinfo()->type,
+ SOCK_GEOMETRY,
+ SOCK_FLOAT,
+ SOCK_VECTOR,
+ SOCK_INT,
+ SOCK_BOOLEAN,
+ SOCK_RGBA);
+}
- /* get viewer */
- bNode *viewer_node = nullptr;
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) {
- if (node->flag & NODE_DO_OUTPUT) {
- viewer_node = node;
- break;
- }
- }
+static CustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type)
+{
+ switch (socket_type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_VECTOR:
+ return CD_PROP_FLOAT3;
+ case SOCK_BOOLEAN:
+ return CD_PROP_BOOL;
+ case SOCK_RGBA:
+ return CD_PROP_COLOR;
+ default:
+ /* Fallback. */
+ return CD_AUTO_FROM_NAME;
}
- /* no viewer, we make one active */
- if (viewer_node == nullptr) {
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) {
- node->flag |= NODE_DO_OUTPUT;
- viewer_node = node;
- break;
+}
+
+/**
+ * Find the socket to link to in a viewer node.
+ */
+static bNodeSocket *node_link_viewer_get_socket(bNodeTree *ntree,
+ bNode *viewer_node,
+ bNodeSocket *src_socket)
+{
+ if (viewer_node->type != GEO_NODE_VIEWER) {
+ /* In viewer nodes in the compositor, only the first input should be linked to. */
+ return (bNodeSocket *)viewer_node->inputs.first;
+ }
+ /* For the geometry nodes viewer, find the socket with the correct type. */
+ LISTBASE_FOREACH (bNodeSocket *, viewer_socket, &viewer_node->inputs) {
+ if (viewer_socket->type == src_socket->type) {
+ if (viewer_socket->type == SOCK_GEOMETRY) {
+ return viewer_socket;
}
+ NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node->storage;
+ const CustomDataType data_type = socket_type_to_custom_data_type(
+ (eNodeSocketDatatype)src_socket->type);
+ BLI_assert(data_type != CD_AUTO_FROM_NAME);
+ storage->data_type = data_type;
+ nodeUpdate(ntree, viewer_node);
+ return viewer_socket;
}
}
+ return nullptr;
+}
- bNodeSocket *sock = nullptr;
- bNodeLink *link = nullptr;
+static bool is_viewer_node(const NodeRef &node)
+{
+ return ELEM(node.bnode()->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER);
+}
- /* try to find an already connected socket to cycle to the next */
- if (viewer_node) {
- link = nullptr;
+static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree)
+{
+ Vector<const NodeRef *> viewer_nodes;
+ for (const NodeRef *node : tree.nodes()) {
+ if (is_viewer_node(*node)) {
+ viewer_nodes.append(node);
+ }
+ }
+ return viewer_nodes;
+}
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
- if (link->tonode == viewer_node && link->fromnode == tonode) {
- if (link->tosock == viewer_node->inputs.first) {
- break;
- }
- }
+static bool is_viewer_socket_in_viewer(const InputSocketRef &socket)
+{
+ const NodeRef &node = socket.node();
+ BLI_assert(is_viewer_node(node));
+ if (node.typeinfo()->type == GEO_NODE_VIEWER) {
+ return true;
+ }
+ return socket.index() == 0;
+}
+
+static bool is_linked_to_viewer(const OutputSocketRef &socket, const NodeRef &viewer_node)
+{
+ for (const InputSocketRef *target_socket : socket.directly_linked_sockets()) {
+ if (&target_socket->node() != &viewer_node) {
+ continue;
+ }
+ if (!target_socket->is_available()) {
+ continue;
+ }
+ if (is_viewer_socket_in_viewer(*target_socket)) {
+ return true;
}
- if (link) {
- /* unlink existing connection */
- sock = link->fromsock;
- nodeRemLink(snode->edittree, link);
+ }
+ return false;
+}
- /* find a socket after the previously connected socket */
- if (ED_node_is_geometry(snode)) {
- /* Geometry nodes viewer only supports geometry sockets for now. */
- for (sock = sock->next; sock; sock = sock->next) {
- if (sock->type == SOCK_GEOMETRY && !nodeSocketIsHidden(sock)) {
- break;
- }
- }
- }
- else {
- for (sock = sock->next; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock)) {
- break;
- }
- }
+static int get_default_viewer_type(const bContext *C)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ return ED_node_is_compositor(snode) ? CMP_NODE_VIEWER : GEO_NODE_VIEWER;
+}
+
+static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode &viewer_node)
+{
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &btree.links) {
+ if (link->tonode == &viewer_node) {
+ if (link->tosock->flag & SOCK_UNAVAIL) {
+ nodeRemLink(&btree, link);
}
}
}
+}
- if (tonode) {
- /* Find a selected socket that overrides the socket to connect to */
- if (ED_node_is_geometry(snode)) {
- /* Geometry nodes viewer only supports geometry sockets for now. */
- LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) {
- if (sock2->type == SOCK_GEOMETRY && !nodeSocketIsHidden(sock2) && sock2->flag & SELECT) {
- sock = sock2;
- break;
- }
- }
+static const NodeRef *get_existing_viewer(const NodeTreeRef &tree)
+{
+ Vector<const NodeRef *> viewer_nodes = find_viewer_nodes(tree);
+
+ /* Check if there is already an active viewer node that should be used. */
+ for (const NodeRef *viewer_node : viewer_nodes) {
+ if (viewer_node->bnode()->flag & NODE_DO_OUTPUT) {
+ return viewer_node;
}
- else {
- LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) {
- if (!nodeSocketIsHidden(sock2) && sock2->flag & SELECT) {
- sock = sock2;
- break;
- }
- }
+ }
+
+ /* If no active but non-active viewers exist, make one active. */
+ if (!viewer_nodes.is_empty()) {
+ viewer_nodes[0]->bnode()->flag |= NODE_DO_OUTPUT;
+ return viewer_nodes[0];
+ }
+ return nullptr;
+}
+
+static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *active_viewer_node,
+ const NodeRef &node_to_view)
+{
+ /* Check if any of the output sockets is selected, which is the case when the user just clicked
+ * on the socket. */
+ for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ if (output_socket->bsocket()->flag & SELECT) {
+ return output_socket;
}
}
- /* find a socket starting from the first socket */
- if (!sock) {
- if (ED_node_is_geometry(snode)) {
- /* Geometry nodes viewer only supports geometry sockets for now. */
- for (sock = (bNodeSocket *)tonode->outputs.first; sock; sock = sock->next) {
- if (sock->type == SOCK_GEOMETRY && !nodeSocketIsHidden(sock)) {
- break;
- }
+ const OutputSocketRef *last_socket_linked_to_viewer = nullptr;
+ if (active_viewer_node != nullptr) {
+ for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ if (!socket_can_be_viewed(*output_socket)) {
+ continue;
}
- }
- else {
- for (sock = (bNodeSocket *)tonode->outputs.first; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock)) {
- break;
- }
+ if (is_linked_to_viewer(*output_socket, *active_viewer_node)) {
+ last_socket_linked_to_viewer = output_socket;
}
}
}
-
- if (sock) {
- /* add a new viewer if none exists yet */
- if (!viewer_node) {
- /* XXX location is a quick hack, just place it next to the linked socket */
- const int viewer_type = ED_node_is_compositor(snode) ? CMP_NODE_VIEWER : GEO_NODE_VIEWER;
- viewer_node = node_add_node(C, nullptr, viewer_type, sock->locx + 100, sock->locy);
- if (!viewer_node) {
- return OPERATOR_CANCELLED;
+ if (last_socket_linked_to_viewer == nullptr) {
+ /* If no output is connected to a viewer, use the first output that can be viewed. */
+ for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ if (socket_can_be_viewed(*output_socket)) {
+ return output_socket;
}
-
- link = nullptr;
}
- else {
- /* get link to viewer */
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
- if (link->tonode == viewer_node && link->tosock == viewer_node->inputs.first) {
- break;
- }
+ }
+ else {
+ /* Pick the next socket to be linked to the viewer. */
+ const int tot_outputs = node_to_view.outputs().size();
+ for (const int offset : IndexRange(1, tot_outputs - 1)) {
+ const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs;
+ const OutputSocketRef &output_socket = node_to_view.output(index);
+ if (!socket_can_be_viewed(output_socket)) {
+ continue;
+ }
+ if (is_linked_to_viewer(output_socket, *active_viewer_node)) {
+ continue;
}
+ return &output_socket;
}
+ }
+ return nullptr;
+}
- if (link == nullptr) {
- nodeAddLink(
- snode->edittree, tonode, sock, viewer_node, (bNodeSocket *)viewer_node->inputs.first);
- }
- else {
- link->fromnode = tonode;
- link->fromsock = sock;
- /* make sure the dependency sorting is updated */
- snode->edittree->update |= NTREE_UPDATE_LINKS;
+static int link_socket_to_viewer(const bContext *C,
+ bNode *viewer_bnode,
+ bNode *bnode_to_view,
+ bNodeSocket *bsocket_to_view)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *btree = snode->edittree;
+
+ if (viewer_bnode == nullptr) {
+ /* Create a new viewer node if none exists. */
+ const int viewer_type = get_default_viewer_type(C);
+ viewer_bnode = node_add_node(
+ C, nullptr, viewer_type, bsocket_to_view->locx + 100, bsocket_to_view->locy);
+ if (viewer_bnode == nullptr) {
+ return OPERATOR_CANCELLED;
}
- if (ED_node_is_geometry(snode)) {
- ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_node);
+ }
+
+ bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, viewer_bnode, bsocket_to_view);
+ if (viewer_bsocket == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bNodeLink *link_to_change = nullptr;
+ LISTBASE_FOREACH (bNodeLink *, link, &btree->links) {
+ if (link->tosock == viewer_bsocket) {
+ link_to_change = link;
+ break;
}
+ }
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_update(snode, viewer_node);
- DEG_id_tag_update(&snode->edittree->id, 0);
+ if (link_to_change == nullptr) {
+ nodeAddLink(btree, bnode_to_view, bsocket_to_view, viewer_bnode, viewer_bsocket);
+ }
+ else {
+ link_to_change->fromnode = bnode_to_view;
+ link_to_change->fromsock = bsocket_to_view;
+ btree->update |= NTREE_UPDATE_LINKS;
}
+ remove_links_to_unavailable_viewer_sockets(*btree, *viewer_bnode);
+
+ if (btree->type == NTREE_GEOMETRY) {
+ ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_bnode);
+ }
+
+ ntreeUpdateTree(CTX_data_main(C), btree);
+ snode_update(snode, viewer_bnode);
+ DEG_id_tag_update(&btree->id, 0);
+
return OPERATOR_FINISHED;
}
+static int node_link_viewer(const bContext *C, bNode *bnode_to_view)
+{
+ if (bnode_to_view == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *btree = snode->edittree;
+
+ const NodeTreeRef tree{btree};
+ const NodeRef &node_to_view = *tree.find_node(*bnode_to_view);
+ const NodeRef *active_viewer_node = get_existing_viewer(tree);
+
+ const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node,
+ node_to_view);
+ if (socket_to_view == nullptr) {
+ return OPERATOR_FINISHED;
+ }
+
+ bNodeSocket *bsocket_to_view = socket_to_view->bsocket();
+ bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr;
+ return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view);
+}
+
+} // namespace blender::ed::nodes::viewer_linking
+
static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceNode *snode = CTX_wm_space_node(C);
@@ -777,7 +903,7 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- if (node_link_viewer(C, node) == OPERATOR_CANCELLED) {
+ if (blender::ed::nodes::viewer_linking::node_link_viewer(C, node) == OPERATOR_CANCELLED) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index bd2559c4d4d..0b5d7cdda82 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -92,9 +92,6 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
snode->id = id;
snode->from = from;
- snode->overlay.flag |= SN_OVERLAY_SHOW_OVERLAYS;
- snode->overlay.flag |= SN_OVERLAY_SHOW_WIRE_COLORS;
-
ED_node_set_active_viewer_key(snode);
WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
@@ -204,27 +201,6 @@ void ED_node_tree_path_get(SpaceNode *snode, char *value)
}
}
-void ED_node_tree_path_get_fixedbuf(SpaceNode *snode, char *value, int max_length)
-{
- int size;
-
- value[0] = '\0';
- int i = 0;
- LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
- if (i == 0) {
- size = BLI_strncpy_rlen(value, path->display_name, max_length);
- }
- else {
- size = BLI_snprintf_rlen(value, max_length, "/%s", path->display_name);
- }
- max_length -= size;
- if (max_length <= 0) {
- break;
- }
- value += size;
- }
-}
-
void ED_node_set_active_viewer_key(SpaceNode *snode)
{
bNodeTreePath *path = snode->treepath.last;
@@ -259,6 +235,8 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
snode->spacetype = SPACE_NODE;
snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_OVERLAYS;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_WIRE_COLORS;
/* backdrop */
snode->zoom = 1.0f;
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index a82f516b125..a391d032d7e 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -868,7 +868,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
static char *datastack_drop_tooltip(bContext *UNUSED(C),
wmDrag *drag,
- const wmEvent *UNUSED(event),
+ const int UNUSED(xy[2]),
struct wmDropBox *UNUSED(drop))
{
StackDropData *drop_data = drag->poin;
@@ -1201,11 +1201,13 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
static char *collection_drop_tooltip(bContext *C,
wmDrag *drag,
- const wmEvent *event,
+ const int UNUSED(xy[2]),
wmDropBox *UNUSED(drop))
{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL;
CollectionDrop data;
- if (!event->shift && collection_drop_init(C, drag, event, &data)) {
+ if (event && !event->shift && collection_drop_init(C, drag, event, &data)) {
TreeElement *te = data.te;
if (!data.from || event->ctrl) {
return BLI_strdup(TIP_("Link inside Collection"));
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 75bdc5dbac6..ae2b1870884 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -197,11 +197,24 @@ static void get_element_operation_type(
static TreeElement *get_target_element(SpaceOutliner *space_outliner)
{
TreeElement *te = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
- BLI_assert(te);
return te;
}
+static bool outliner_operation_tree_element_poll(bContext *C)
+{
+ if (!ED_operator_outliner_active(C)) {
+ return false;
+ }
+ SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
+ TreeElement *te = get_target_element(space_outliner);
+ if (te == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
static void unlink_action_fn(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@@ -1426,7 +1439,7 @@ static void outliner_do_data_operation(
}
}
-static Base *outline_batch_delete_hierarchy(
+static Base *outliner_batch_delete_hierarchy(
ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base)
{
Base *child_base, *base_next;
@@ -1444,7 +1457,7 @@ static Base *outline_batch_delete_hierarchy(
/* pass */
}
if (parent) {
- base_next = outline_batch_delete_hierarchy(reports, bmain, view_layer, scene, child_base);
+ base_next = outliner_batch_delete_hierarchy(reports, bmain, view_layer, scene, child_base);
}
}
@@ -1497,7 +1510,7 @@ static void object_batch_delete_hierarchy_fn(bContext *C,
ED_object_editmode_exit(C, EM_FREEDATA);
}
- outline_batch_delete_hierarchy(reports, CTX_data_main(C), view_layer, scene, base);
+ outliner_batch_delete_hierarchy(reports, CTX_data_main(C), view_layer, scene, base);
}
}
@@ -1868,6 +1881,10 @@ static bool outliner_id_operation_item_poll(bContext *C,
PropertyRNA *UNUSED(prop),
const int enum_value)
{
+ if (!outliner_operation_tree_element_poll(C)) {
+ return false;
+ }
+
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
TreeElement *te = get_target_element(space_outliner);
TreeStoreElem *tselem = TREESTORE(te);
@@ -2254,7 +2271,7 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
/* callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = outliner_id_operation_exec;
- ot->poll = ED_operator_outliner_active;
+ ot->poll = outliner_operation_tree_element_poll;
ot->flag = 0;
@@ -2361,7 +2378,7 @@ void OUTLINER_OT_lib_operation(wmOperatorType *ot)
/* callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = outliner_lib_operation_exec;
- ot->poll = ED_operator_outliner_active;
+ ot->poll = outliner_operation_tree_element_poll;
ot->prop = RNA_def_enum(
ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", "");
@@ -2420,14 +2437,8 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
-
bAction *act;
- /* check for invalid states */
- if (space_outliner == NULL) {
- return OPERATOR_CANCELLED;
- }
-
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
@@ -2482,7 +2493,7 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_enum_search_invoke;
ot->exec = outliner_action_set_exec;
- ot->poll = ED_operator_outliner_active;
+ ot->poll = outliner_operation_tree_element_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2531,12 +2542,6 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
-
- /* check for invalid states */
- if (space_outliner == NULL) {
- return OPERATOR_CANCELLED;
- }
-
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
@@ -2722,12 +2727,6 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
-
- /* check for invalid states */
- if (space_outliner == NULL) {
- return OPERATOR_CANCELLED;
- }
-
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
@@ -2806,6 +2805,13 @@ static const EnumPropertyItem *outliner_data_op_sets_enum_item_fn(bContext *C,
return DummyRNA_DEFAULT_items;
}
+ TreeElement *te = get_target_element(space_outliner);
+ if (te == NULL) {
+ return DummyRNA_NULL_items;
+ }
+
+ TreeStoreElem *tselem = TREESTORE(te);
+
static const EnumPropertyItem optype_sel_and_hide[] = {
{OL_DOP_SELECT, "SELECT", 0, "Select", ""},
{OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
@@ -2816,9 +2822,6 @@ static const EnumPropertyItem *outliner_data_op_sets_enum_item_fn(bContext *C,
static const EnumPropertyItem optype_sel_linked[] = {
{OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, {0, NULL, 0, NULL, NULL}};
- TreeElement *te = get_target_element(space_outliner);
- TreeStoreElem *tselem = TREESTORE(te);
-
if (tselem->type == TSE_RNA_STRUCT) {
return optype_sel_linked;
}
@@ -2835,7 +2838,7 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
/* callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = outliner_data_operation_exec;
- ot->poll = ED_operator_outliner_active;
+ ot->poll = outliner_operation_tree_element_poll;
ot->flag = 0;
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 2a29125af19..8c70f4e3f7a 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1709,16 +1709,24 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbasep = SEQ_active_seqbase_get(SEQ_editing_get(scene));
SEQ_prefetch_stop(scene);
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ const bool is_preview = sequencer_view_preview_poll(C);
+ if (is_preview) {
+ SEQ_query_rendered_strips_to_tag(seqbasep, scene->r.cfra, 0);
+ }
+
+ LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (seq->flag & SELECT) {
- SEQ_edit_flag_for_removal(scene, ed->seqbasep, seq);
+ SEQ_edit_flag_for_removal(scene, seqbasep, seq);
}
}
- SEQ_edit_remove_flagged_sequences(scene, ed->seqbasep);
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(bmain);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index b4271ebd812..8a8a24f08ff 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -25,6 +25,8 @@
#include <stdlib.h>
#include <string.h>
+#include "MEM_guardedalloc.h"
+
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -414,9 +416,17 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
+ const bool is_preview = sequencer_view_preview_poll(C);
+ if (is_preview) {
+ SEQ_query_rendered_strips_to_tag(ed->seqbasep, scene->r.cfra, 0);
+ }
+
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (seq->flag & SEQ_ALLSEL) {
action = SEL_DESELECT;
break;
@@ -425,6 +435,9 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
}
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
switch (action) {
case SEL_SELECT:
seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
@@ -481,7 +494,15 @@ static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
+ const bool is_preview = sequencer_view_preview_poll(C);
+ if (is_preview) {
+ SEQ_query_rendered_strips_to_tag(ed->seqbasep, scene->r.cfra, 0);
+ }
+
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_ALLSEL;
}
@@ -635,11 +656,51 @@ static void sequencer_select_linked_handle(const bContext *C,
}
}
-/* Check if click happened on image which belongs to strip. If multiple strips are found, loop
- * through them in order. */
-static Sequence *seq_select_seq_from_preview(const bContext *C,
- const int mval[2],
- const bool center)
+/** Collect sequencer that are candidates for being selected. */
+struct SeqSelect_Link {
+ struct SeqSelect_Link *next, *prev;
+ Sequence *seq;
+ /** Only use for center selection. */
+ float center_dist_sq;
+};
+
+static int seq_sort_for_depth_select(const void *a, const void *b)
+{
+ const struct SeqSelect_Link *slink_a = a;
+ const struct SeqSelect_Link *slink_b = b;
+
+ /* Exactly overlapping strips, sort by machine (so the top-most is first). */
+ if (slink_a->seq->machine < slink_b->seq->machine) {
+ return 1;
+ }
+ if (slink_a->seq->machine > slink_b->seq->machine) {
+ return -1;
+ }
+ return 0;
+}
+
+static int seq_sort_for_center_select(const void *a, const void *b)
+{
+ const struct SeqSelect_Link *slink_a = a;
+ const struct SeqSelect_Link *slink_b = b;
+ if (slink_a->center_dist_sq > slink_b->center_dist_sq) {
+ return 1;
+ }
+ if (slink_a->center_dist_sq < slink_b->center_dist_sq) {
+ return -1;
+ }
+
+ /* Exactly overlapping strips, use depth. */
+ return seq_sort_for_depth_select(a, b);
+}
+
+/**
+ * Check if click happened on image which belongs to strip.
+ * If multiple strips are found, loop through them in order
+ * (depth (top-most first) or closest to mouse when `center` is true).
+ */
+static Sequence *seq_select_seq_from_preview(
+ const bContext *C, const int mval[2], const bool toggle, const bool extend, const bool center)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
@@ -650,70 +711,82 @@ static Sequence *seq_select_seq_from_preview(const bContext *C,
float mouseco_view[2];
UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseco_view[0], &mouseco_view[1]);
+ /* Always update the coordinates (check extended after). */
+ const bool use_cycle = (!WM_cursor_test_motion_and_update(mval) || extend || toggle);
+
SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, sseq->chanshown);
/* Allow strips this far from the closest center to be included.
* This allows cycling over center points which are near enough
* to overlapping from the users perspective. */
- const float center_threshold_cycle_px = 5.0f;
- const float center_dist_sq_eps = square_f(center_threshold_cycle_px * U.pixelsize);
+ const float center_dist_sq_max = square_f(75.0f * U.pixelsize);
const float center_scale_px[2] = {
UI_view2d_scale_get_x(v2d),
UI_view2d_scale_get_y(v2d),
};
- float center_co_best[2] = {0.0f};
-
- if (center) {
- Sequence *seq_best = NULL;
- float center_dist_sq_best = 0.0f;
-
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips) {
- float co[2];
- SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, co);
- const float center_dist_sq_test = len_squared_v2v2(co, mouseco_view);
- if ((seq_best == NULL) || (center_dist_sq_test < center_dist_sq_best)) {
- seq_best = seq;
- center_dist_sq_best = center_dist_sq_test;
- copy_v2_v2(center_co_best, co);
- }
- }
- }
+ struct SeqSelect_Link *slink_active = NULL;
+ Sequence *seq_active = SEQ_select_active_get(scene);
ListBase strips_ordered = {NULL};
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
bool isect = false;
+ float center_dist_sq_test = 0.0f;
if (center) {
/* Detect overlapping center points (scaled by the zoom level). */
float co[2];
SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, co);
- sub_v2_v2(co, center_co_best);
+ sub_v2_v2(co, mouseco_view);
mul_v2_v2(co, center_scale_px);
- isect = len_squared_v2(co) <= center_dist_sq_eps;
+ center_dist_sq_test = len_squared_v2(co);
+ isect = center_dist_sq_test <= center_dist_sq_max;
+ if (isect) {
+ /* Use an active strip penalty for "center" selection when cycle is enabled. */
+ if (use_cycle && (seq == seq_active) && (seq_active->flag & SELECT)) {
+ center_dist_sq_test = square_f(sqrtf(center_dist_sq_test) + (3.0f * U.pixelsize));
+ }
+ }
}
else {
isect = seq_point_image_isect(scene, seq, mouseco_view);
}
if (isect) {
- BLI_remlink(seqbase, seq);
- BLI_addtail(&strips_ordered, seq);
+ struct SeqSelect_Link *slink = MEM_callocN(sizeof(*slink), __func__);
+ slink->seq = seq;
+ slink->center_dist_sq = center_dist_sq_test;
+ BLI_addtail(&strips_ordered, slink);
+
+ if (seq == seq_active) {
+ slink_active = slink;
+ }
}
}
SEQ_collection_free(strips);
- SEQ_sort(&strips_ordered);
- Sequence *seq_active = SEQ_select_active_get(scene);
- Sequence *seq_select = strips_ordered.first;
- LISTBASE_FOREACH (Sequence *, seq_iter, &strips_ordered) {
- if (seq_iter == seq_active && seq_iter->next != NULL) {
- seq_select = seq_iter->next;
- break;
+ BLI_listbase_sort(&strips_ordered,
+ center ? seq_sort_for_center_select : seq_sort_for_depth_select);
+
+ struct SeqSelect_Link *slink_select = strips_ordered.first;
+ Sequence *seq_select = NULL;
+ if (slink_select != NULL) {
+ /* Only use special behavior for the active strip when it's selected. */
+ if ((center == false) && slink_active && (seq_active->flag & SELECT)) {
+ if (use_cycle) {
+ if (slink_active->next) {
+ slink_select = slink_active->next;
+ }
+ }
+ else {
+ /* Match object selection behavior: keep the current active item unless cycle is enabled.
+ * Clicking again in the same location will cycle away from the active object. */
+ slink_select = slink_active;
+ }
}
+ seq_select = slink_select->seq;
}
- BLI_movelisttolist(seqbase, &strips_ordered);
+ BLI_freelistN(&strips_ordered);
return seq_select;
}
@@ -759,7 +832,7 @@ static void sequencer_select_strip_impl(const Editing *ed,
action = 0;
}
else {
- if ((seq->flag & SELECT) == 0 || is_active) {
+ if (!((seq->flag & SELECT) && is_active)) {
action = 1;
}
else if (toggle) {
@@ -812,7 +885,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
int handle_clicked = SEQ_SIDE_NONE;
Sequence *seq = NULL;
if (region->regiontype == RGN_TYPE_PREVIEW) {
- seq = seq_select_seq_from_preview(C, mval, center);
+ seq = seq_select_seq_from_preview(C, mval, toggle, extend, center);
}
else {
seq = find_nearest_seq(scene, v2d, &handle_clicked, mval);
@@ -821,7 +894,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* NOTE: `side_of_frame` and `linked_time` functionality is designed to be shared on one keymap,
* therefore both properties can be true at the same time. */
if (seq && RNA_boolean_get(op->ptr, "linked_time")) {
- if (!extend) {
+ if (!extend && !toggle) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_strip_impl(ed, seq, handle_clicked, extend, deselect, toggle);
@@ -833,7 +906,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* Select left, right or overlapping the current frame. */
if (RNA_boolean_get(op->ptr, "side_of_frame")) {
- if (!extend) {
+ if (!extend && !toggle) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_side_of_frame(C, v2d, mval, scene);
@@ -843,7 +916,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* On Alt selection, select the strip and bordering handles. */
if (seq && RNA_boolean_get(op->ptr, "linked_handle")) {
- if (!extend) {
+ if (!extend && !toggle) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_linked_handle(C, seq, handle_clicked);
@@ -1694,11 +1767,17 @@ static const EnumPropertyItem sequencer_prop_select_grouped_types[] = {
#define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
-static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_type(ListBase *seqbasep,
+ const bool is_preview,
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
seq->flag |= SELECT;
changed = true;
@@ -1708,12 +1787,18 @@ static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel
return changed;
}
-static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_type_basic(ListBase *seqbase,
+ const bool is_preview,
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
const bool is_sound = SEQ_IS_SOUND(actseq);
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
seq->flag |= SELECT;
changed = true;
@@ -1723,12 +1808,18 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int c
return changed;
}
-static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_type_effect(ListBase *seqbase,
+ const bool is_preview,
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
const bool is_effect = SEQ_IS_EFFECT(actseq);
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) &&
(is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
seq->flag |= SELECT;
@@ -1739,7 +1830,10 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int
return changed;
}
-static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_data(ListBase *seqbase,
+ const bool is_preview,
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
const char *dir = actseq->strip ? actseq->strip->dir : NULL;
@@ -1749,7 +1843,10 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
if (SEQ_HAS_PATH(actseq) && dir) {
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip &&
STREQ(seq->strip->dir, dir)) {
seq->flag |= SELECT;
@@ -1759,7 +1856,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
else if (actseq->type == SEQ_TYPE_SCENE) {
Scene *sce = actseq->scene;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
seq->flag |= SELECT;
changed = true;
@@ -1768,7 +1865,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
else if (actseq->type == SEQ_TYPE_MOVIECLIP) {
MovieClip *clip = actseq->clip;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP &&
seq->clip == clip) {
seq->flag |= SELECT;
@@ -1778,7 +1875,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
else if (actseq->type == SEQ_TYPE_MASK) {
struct Mask *mask = actseq->mask;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
seq->flag |= SELECT;
changed = true;
@@ -1789,7 +1886,10 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
return changed;
}
-static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_effect(ListBase *seqbase,
+ const bool is_preview,
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
bool effects[SEQ_TYPE_MAX + 1];
@@ -1798,14 +1898,20 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int chann
effects[i] = false;
}
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
effects[seq->type] = true;
}
}
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
if (seq->seq1) {
seq->seq1->flag |= SELECT;
@@ -1823,11 +1929,14 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int chann
return changed;
}
-static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
+static bool select_grouped_time_overlap(ListBase *seqbase, const bool is_preview, Sequence *actseq)
{
bool changed = false;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
seq->flag |= SELECT;
changed = true;
@@ -1856,12 +1965,11 @@ static void query_lower_channel_strips(Sequence *seq_reference,
/* Select all strips within time range and with lower channel of initial selection. Then select
* effect chains of these strips. */
-static bool select_grouped_effect_link(Editing *ed,
+static bool select_grouped_effect_link(ListBase *seqbase,
+ const bool is_preview,
Sequence *UNUSED(actseq),
const int UNUSED(channel))
{
- ListBase *seqbase = SEQ_active_seqbase_get(ed);
-
/* Get collection of strips. */
SeqCollection *collection = SEQ_query_selected_strips(seqbase);
const int selected_strip_count = BLI_gset_len(collection->set);
@@ -1874,6 +1982,9 @@ static bool select_grouped_effect_link(Editing *ed,
/* Actual logic. */
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, collection) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
seq->flag |= SELECT;
}
@@ -1889,9 +2000,17 @@ static bool select_grouped_effect_link(Editing *ed,
static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
Sequence *actseq = SEQ_select_active_get(scene);
+ const bool is_preview = sequencer_view_preview_poll(C);
+ if (is_preview) {
+ SEQ_query_rendered_strips_to_tag(seqbase, scene->r.cfra, 0);
+ if (actseq && actseq->tmp_tag == false) {
+ actseq = NULL;
+ }
+ }
+
if (actseq == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active sequence!");
return OPERATOR_CANCELLED;
@@ -1904,7 +2023,7 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
bool changed = false;
if (!extend) {
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
seq->flag &= ~SELECT;
changed = true;
}
@@ -1912,25 +2031,25 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
switch (type) {
case SEQ_SELECT_GROUP_TYPE:
- changed |= select_grouped_type(ed, actseq, channel);
+ changed |= select_grouped_type(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_TYPE_BASIC:
- changed |= select_grouped_type_basic(ed, actseq, channel);
+ changed |= select_grouped_type_basic(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_TYPE_EFFECT:
- changed |= select_grouped_type_effect(ed, actseq, channel);
+ changed |= select_grouped_type_effect(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_DATA:
- changed |= select_grouped_data(ed, actseq, channel);
+ changed |= select_grouped_data(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT:
- changed |= select_grouped_effect(ed, actseq, channel);
+ changed |= select_grouped_effect(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT_LINK:
- changed |= select_grouped_effect_link(ed, actseq, channel);
+ changed |= select_grouped_effect_link(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_OVERLAP:
- changed |= select_grouped_time_overlap(ed, actseq);
+ changed |= select_grouped_time_overlap(seqbase, is_preview, actseq);
break;
default:
BLI_assert(0);
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 79593b0bbb0..2d2e7de7135 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -92,7 +92,14 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
const Editing *ed = SEQ_editing_get(scene);
- SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &box);
+ SEQ_timeline_init_boundbox(scene, &box);
+ MetaStack *ms = SEQ_meta_stack_active_get(ed);
+ /* Use meta strip range instead of scene. */
+ if (ms != NULL) {
+ box.xmin = ms->disp_range[0] - 1;
+ box.xmax = ms->disp_range[1] + 1;
+ }
+ SEQ_timeline_expand_boundbox(SEQ_active_seqbase_get(ed), &box);
UI_view2d_smooth_view(C, region, &box, smooth_viewtx);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index e903feeec1b..91fe1bc01b7 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -35,6 +35,7 @@ set(INC
set(SRC
space_spreadsheet.cc
+ spreadsheet_cache.cc
spreadsheet_column.cc
spreadsheet_context.cc
spreadsheet_data_source.cc
@@ -47,6 +48,7 @@ set(SRC
spreadsheet_row_filter.cc
spreadsheet_row_filter_ui.cc
+ spreadsheet_cache.hh
spreadsheet_cell_value.hh
spreadsheet_column.hh
spreadsheet_column_values.hh
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index a82648aeee0..73e0be76466 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -112,7 +112,7 @@ static void spreadsheet_free(SpaceLink *sl)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- MEM_SAFE_FREE(sspreadsheet->runtime);
+ delete sspreadsheet->runtime;
LISTBASE_FOREACH_MUTABLE (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
spreadsheet_row_filter_free(row_filter);
@@ -129,8 +129,7 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)area->spacedata.first;
if (sspreadsheet->runtime == nullptr) {
- sspreadsheet->runtime = (SpaceSpreadsheet_Runtime *)MEM_callocN(
- sizeof(SpaceSpreadsheet_Runtime), __func__);
+ sspreadsheet->runtime = new SpaceSpreadsheet_Runtime();
}
}
@@ -138,7 +137,7 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
{
const SpaceSpreadsheet *sspreadsheet_old = (SpaceSpreadsheet *)sl;
SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old);
- sspreadsheet_new->runtime = (SpaceSpreadsheet_Runtime *)MEM_dupallocN(sspreadsheet_old->runtime);
+ sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime(*sspreadsheet_old->runtime);
BLI_listbase_clear(&sspreadsheet_new->row_filters);
LISTBASE_FOREACH (const SpreadsheetRowFilter *, src_filter, &sspreadsheet_old->row_filters) {
@@ -294,16 +293,39 @@ static std::unique_ptr<DataSource> get_data_source(const bContext *C)
return {};
}
-static float get_column_width(const ColumnValues &values)
+static float get_default_column_width(const ColumnValues &values)
{
- if (values.default_width > 0) {
+ if (values.default_width > 0.0f) {
return values.default_width;
}
+ static const float float_width = 3;
+ switch (values.type()) {
+ case SPREADSHEET_VALUE_TYPE_BOOL:
+ return 2.0f;
+ case SPREADSHEET_VALUE_TYPE_INT32:
+ return float_width;
+ case SPREADSHEET_VALUE_TYPE_FLOAT:
+ return float_width;
+ case SPREADSHEET_VALUE_TYPE_FLOAT2:
+ return 2.0f * float_width;
+ case SPREADSHEET_VALUE_TYPE_FLOAT3:
+ return 3.0f * float_width;
+ case SPREADSHEET_VALUE_TYPE_COLOR:
+ return 4.0f * float_width;
+ case SPREADSHEET_VALUE_TYPE_INSTANCES:
+ return 8.0f;
+ }
+ return float_width;
+}
+
+static float get_column_width(const ColumnValues &values)
+{
+ float data_width = get_default_column_width(values);
const int fontid = UI_style_get()->widget.uifont_id;
BLF_size(fontid, UI_DEFAULT_TEXT_POINTS, U.dpi);
const StringRefNull name = values.name();
const float name_width = BLF_width(fontid, name.data(), name.size());
- return std::max<float>(name_width / UI_UNIT_X + 1.0f, 3.0f);
+ return std::max<float>(name_width / UI_UNIT_X + 1.0f, data_width);
}
static float get_column_width_in_pixels(const ColumnValues &values)
@@ -339,21 +361,28 @@ static void update_visible_columns(ListBase &columns, DataSource &data_source)
}
}
- data_source.foreach_default_column_ids([&](const SpreadsheetColumnID &column_id) {
- std::unique_ptr<ColumnValues> values = data_source.get_column_values(column_id);
- if (values) {
- if (used_ids.add(column_id)) {
- SpreadsheetColumnID *new_id = spreadsheet_column_id_copy(&column_id);
- SpreadsheetColumn *new_column = spreadsheet_column_new(new_id);
- BLI_addtail(&columns, new_column);
- }
- }
- });
+ data_source.foreach_default_column_ids(
+ [&](const SpreadsheetColumnID &column_id, const bool is_extra) {
+ std::unique_ptr<ColumnValues> values = data_source.get_column_values(column_id);
+ if (values) {
+ if (used_ids.add(column_id)) {
+ SpreadsheetColumnID *new_id = spreadsheet_column_id_copy(&column_id);
+ SpreadsheetColumn *new_column = spreadsheet_column_new(new_id);
+ if (is_extra) {
+ BLI_addhead(&columns, new_column);
+ }
+ else {
+ BLI_addtail(&columns, new_column);
+ }
+ }
+ }
+ });
}
static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ sspreadsheet->runtime->cache.set_all_unused();
spreadsheet_update_context_path(C);
std::unique_ptr<DataSource> data_source = get_data_source(C);
@@ -394,6 +423,9 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
ED_region_tag_redraw(footer);
ARegion *sidebar = BKE_area_find_region_type(CTX_wm_area(C), RGN_TYPE_UI);
ED_region_tag_redraw(sidebar);
+
+ /* Free all cache items that have not been used. */
+ sspreadsheet->runtime->cache.remove_all_unused();
}
static void spreadsheet_main_region_listener(const wmRegionListenerParams *params)
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cache.cc b/source/blender/editors/space_spreadsheet/spreadsheet_cache.cc
new file mode 100644
index 00000000000..2a399e018b6
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_cache.cc
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#include "spreadsheet_cache.hh"
+
+namespace blender::ed::spreadsheet {
+
+void SpreadsheetCache::add(std::unique_ptr<Key> key, std::unique_ptr<Value> value)
+{
+ key->is_used = true;
+ cache_map_.add_overwrite(*key, std::move(value));
+ keys_.append(std::move(key));
+}
+
+SpreadsheetCache::Value *SpreadsheetCache::lookup(const Key &key)
+{
+ std::unique_ptr<Value> *value = cache_map_.lookup_ptr(key);
+ if (value == nullptr) {
+ return nullptr;
+ }
+ const Key &stored_cache_key = cache_map_.lookup_key(key);
+ stored_cache_key.is_used = true;
+ return value->get();
+}
+
+SpreadsheetCache::Value &SpreadsheetCache::lookup_or_add(
+ std::unique_ptr<Key> key, FunctionRef<std::unique_ptr<Value>()> create_value)
+{
+ Value *value = this->lookup(*key);
+ if (value != nullptr) {
+ return *value;
+ }
+ std::unique_ptr<Value> new_value = create_value();
+ value = new_value.get();
+ this->add(std::move(key), std::move(new_value));
+ return *value;
+}
+
+void SpreadsheetCache::set_all_unused()
+{
+ for (std::unique_ptr<Key> &key : keys_) {
+ key->is_used = false;
+ }
+}
+
+void SpreadsheetCache::remove_all_unused()
+{
+ /* First remove the keys from the map and free the values. */
+ for (auto it = cache_map_.keys().begin(); it != cache_map_.keys().end(); ++it) {
+ const Key &key = *it;
+ if (!key.is_used) {
+ cache_map_.remove(it);
+ }
+ }
+ /* Then free the keys. */
+ for (int i = 0; i < keys_.size();) {
+ if (keys_[i]->is_used) {
+ i++;
+ }
+ else {
+ keys_.remove_and_reorder(i);
+ }
+ }
+}
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cache.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cache.hh
new file mode 100644
index 00000000000..d370bdab5c1
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_cache.hh
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <atomic>
+
+#include "BLI_function_ref.hh"
+#include "BLI_map.hh"
+#include "BLI_vector.hh"
+
+namespace blender::ed::spreadsheet {
+
+/**
+ * A generic cache for the spreadsheet. Different data sources can cache custom data using custom
+ * keys.
+ *
+ * Elements are removed from the cache when they are not used during a redraw.
+ */
+class SpreadsheetCache {
+ public:
+ class Key {
+ public:
+ virtual ~Key() = default;
+
+ mutable bool is_used = false;
+
+ virtual uint64_t hash() const = 0;
+
+ friend bool operator==(const Key &a, const Key &b)
+ {
+ return a.is_equal_to(b);
+ }
+
+ private:
+ virtual bool is_equal_to(const Key &other) const = 0;
+ };
+
+ class Value {
+ public:
+ virtual ~Value() = default;
+ };
+
+ private:
+ Vector<std::unique_ptr<Key>> keys_;
+ Map<std::reference_wrapper<const Key>, std::unique_ptr<Value>> cache_map_;
+
+ public:
+ /* Adding or looking up a key tags it as being used, so that it won't be removed. */
+ void add(std::unique_ptr<Key> key, std::unique_ptr<Value> value);
+ Value *lookup(const Key &key);
+ Value &lookup_or_add(std::unique_ptr<Key> key,
+ FunctionRef<std::unique_ptr<Value>()> create_value);
+
+ void set_all_unused();
+ void remove_all_unused();
+
+ template<typename T> T &lookup_or_add(std::unique_ptr<Key> key)
+ {
+ return dynamic_cast<T &>(
+ this->lookup_or_add(std::move(key), []() { return std::make_unique<T>(); }));
+ }
+};
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
index 68370cf6a44..877651d6530 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
@@ -97,9 +97,4 @@ std::unique_ptr<ColumnValues> column_values_from_function(const eSpreadsheetColu
return column_values;
}
-static constexpr float default_float_column_width = 3;
-static constexpr float default_float2_column_width = 2 * default_float_column_width;
-static constexpr float default_float3_column_width = 3 * default_float_column_width;
-static constexpr float default_color_column_width = 4 * default_float_column_width;
-
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
index c38e765caee..e55a7cae6a6 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
@@ -373,6 +373,21 @@ void ED_spreadsheet_context_path_set_evaluated_object(SpaceSpreadsheet *sspreads
BLI_addtail(&sspreadsheet->context_path, context);
}
+static bScreen *find_screen_to_search_for_context(wmWindow *window,
+ SpaceSpreadsheet *current_space)
+{
+ bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) {
+ /* If the spreadsheet is maximized, try to find the context in the unmaximized screen. */
+ ScrArea *main_area = (ScrArea *)screen->areabase.first;
+ SpaceLink *sl = (SpaceLink *)main_area->spacedata.first;
+ if (sl == (SpaceLink *)current_space) {
+ return main_area->full;
+ }
+ }
+ return screen;
+}
+
void ED_spreadsheet_context_path_guess(const bContext *C, SpaceSpreadsheet *sspreadsheet)
{
ED_spreadsheet_context_path_clear(sspreadsheet);
@@ -385,9 +400,12 @@ void ED_spreadsheet_context_path_guess(const bContext *C, SpaceSpreadsheet *sspr
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) {
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
- bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ bScreen *screen = find_screen_to_search_for_context(window, sspreadsheet);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
SpaceLink *sl = (SpaceLink *)area->spacedata.first;
+ if (sl == nullptr) {
+ continue;
+ }
if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
if (snode->edittree != nullptr) {
@@ -466,9 +484,12 @@ bool ED_spreadsheet_context_path_is_active(const bContext *C, SpaceSpreadsheet *
}
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
- bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ bScreen *screen = find_screen_to_search_for_context(window, sspreadsheet);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
SpaceLink *sl = (SpaceLink *)area->spacedata.first;
+ if (sl == nullptr) {
+ continue;
+ }
if (sl->spacetype != SPACE_NODE) {
continue;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
index 2ea7fb5809f..873735c81e5 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
@@ -36,8 +36,12 @@ class DataSource {
* Calls the callback with all the column ids that should be displayed as long as the user does
* not manually add or remove columns. The column id can be stack allocated. Therefore, the
* callback should not keep a reference to it (and copy it instead).
+ *
+ * The `is_extra` argument indicates that this column is special and should be drawn as the first
+ * column. (This can be made a bit more generic in the future when necessary.)
*/
- virtual void foreach_default_column_ids(FunctionRef<void(const SpreadsheetColumnID &)> fn) const
+ virtual void foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
UNUSED_VARS(fn);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index 78d9f61d8d5..c1d345d1861 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -33,18 +33,99 @@
#include "NOD_geometry_nodes_eval_log.hh"
+#include "FN_field_cpp_type.hh"
+
#include "bmesh.h"
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
+using blender::fn::GField;
namespace blender::ed::spreadsheet {
+static std::optional<eSpreadsheetColumnValueType> cpp_type_to_column_value_type(
+ const fn::CPPType &type)
+{
+ if (type.is<bool>()) {
+ return SPREADSHEET_VALUE_TYPE_BOOL;
+ }
+ if (type.is<int>()) {
+ return SPREADSHEET_VALUE_TYPE_INT32;
+ }
+ if (type.is<float>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT;
+ }
+ if (type.is<float2>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT2;
+ }
+ if (type.is<float3>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT3;
+ }
+ if (type.is<ColorGeometry4f>()) {
+ return SPREADSHEET_VALUE_TYPE_COLOR;
+ }
+ return std::nullopt;
+}
+
+void ExtraColumns::foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
+{
+ for (const auto &item : columns_.items()) {
+ SpreadsheetColumnID column_id;
+ column_id.name = (char *)item.key.c_str();
+ fn(column_id, true);
+ }
+}
+
+std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
+ const SpreadsheetColumnID &column_id) const
+{
+ const fn::GSpan *values = columns_.lookup_ptr(column_id.name);
+ if (values == nullptr) {
+ return {};
+ }
+ eSpreadsheetColumnValueType column_type = *cpp_type_to_column_value_type(values->type());
+ return column_values_from_function(column_type,
+ column_id.name,
+ values->size(),
+ [column_type, values](int index, CellValue &r_cell_value) {
+ const void *value = (*values)[index];
+ switch (column_type) {
+ case SPREADSHEET_VALUE_TYPE_BOOL:
+ r_cell_value.value_bool = *(const bool *)value;
+ break;
+ case SPREADSHEET_VALUE_TYPE_INT32:
+ r_cell_value.value_int = *(const int *)value;
+ break;
+ case SPREADSHEET_VALUE_TYPE_FLOAT:
+ r_cell_value.value_float = *(const float *)value;
+ break;
+ case SPREADSHEET_VALUE_TYPE_FLOAT2:
+ r_cell_value.value_float2 = *(const float2 *)value;
+ break;
+ case SPREADSHEET_VALUE_TYPE_FLOAT3:
+ r_cell_value.value_float3 = *(const float3 *)value;
+ break;
+ case SPREADSHEET_VALUE_TYPE_COLOR:
+ r_cell_value.value_color = *(
+ const ColorGeometry4f *)value;
+ break;
+ case SPREADSHEET_VALUE_TYPE_INSTANCES:
+ break;
+ }
+ });
+}
+
void GeometryDataSource::foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &)> fn) const
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
+ if (component_->attribute_domain_size(domain_) == 0) {
+ return;
+ }
+
+ extra_columns_.foreach_default_column_ids(fn);
component_->attribute_foreach(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
if (meta_data.domain != domain_) {
@@ -55,7 +136,7 @@ void GeometryDataSource::foreach_default_column_ids(
}
SpreadsheetColumnID column_id;
column_id.name = (char *)attribute_id.name().data();
- fn(column_id);
+ fn(column_id, false);
return true;
});
}
@@ -63,8 +144,17 @@ void GeometryDataSource::foreach_default_column_ids(
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
+ if (component_->attribute_domain_size(domain_) == 0) {
+ return {};
+ }
+
std::lock_guard lock{mutex_};
+ std::unique_ptr<ColumnValues> extra_column_values = extra_columns_.get_column_values(column_id);
+ if (extra_column_values) {
+ return extra_column_values;
+ }
+
bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
if (!attribute) {
return {};
@@ -86,14 +176,16 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
r_cell_value.value_float = value;
});
case CD_PROP_INT32:
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_INT32,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- int value;
- varray->get(index, &value);
- r_cell_value.value_int = value;
- });
+ return column_values_from_function(
+ SPREADSHEET_VALUE_TYPE_INT32,
+ column_id.name,
+ domain_size,
+ [varray](int index, CellValue &r_cell_value) {
+ int value;
+ varray->get(index, &value);
+ r_cell_value.value_int = value;
+ },
+ STREQ(column_id.name, "id") ? 5.5f : 0.0f);
case CD_PROP_BOOL:
return column_values_from_function(SPREADSHEET_VALUE_TYPE_BOOL,
column_id.name,
@@ -104,40 +196,34 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
r_cell_value.value_bool = value;
});
case CD_PROP_FLOAT2: {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT2,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float2 value;
- varray->get(index, &value);
- r_cell_value.value_float2 = value;
- },
- default_float2_column_width);
+ return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT2,
+ column_id.name,
+ domain_size,
+ [varray](int index, CellValue &r_cell_value) {
+ float2 value;
+ varray->get(index, &value);
+ r_cell_value.value_float2 = value;
+ });
}
case CD_PROP_FLOAT3: {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float3 value;
- varray->get(index, &value);
- r_cell_value.value_float3 = value;
- },
- default_float3_column_width);
+ return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
+ column_id.name,
+ domain_size,
+ [varray](int index, CellValue &r_cell_value) {
+ float3 value;
+ varray->get(index, &value);
+ r_cell_value.value_float3 = value;
+ });
}
case CD_PROP_COLOR: {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_COLOR,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- ColorGeometry4f value;
- varray->get(index, &value);
- r_cell_value.value_color = value;
- },
- default_color_column_width);
+ return column_values_from_function(SPREADSHEET_VALUE_TYPE_COLOR,
+ column_id.name,
+ domain_size,
+ [varray](int index, CellValue &r_cell_value) {
+ ColorGeometry4f value;
+ varray->get(index, &value);
+ r_cell_value.value_color = value;
+ });
}
default:
break;
@@ -293,18 +379,20 @@ void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included)
}
void InstancesDataSource::foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &)> fn) const
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
if (component_->instances_amount() == 0) {
return;
}
+ extra_columns_.foreach_default_column_ids(fn);
+
SpreadsheetColumnID column_id;
column_id.name = (char *)"Name";
- fn(column_id);
- for (const char *name : {"Position", "Rotation", "Scale", "ID"}) {
+ fn(column_id, false);
+ for (const char *name : {"Position", "Rotation", "Scale", "id"}) {
column_id.name = (char *)name;
- fn(column_id);
+ fn(column_id, false);
}
}
@@ -315,6 +403,11 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
return {};
}
+ std::unique_ptr<ColumnValues> extra_column_values = extra_columns_.get_column_values(column_id);
+ if (extra_column_values) {
+ return extra_column_values;
+ }
+
const int size = this->tot_rows();
if (STREQ(column_id.name, "Name")) {
Span<int> reference_handles = component_->instance_reference_handles();
@@ -346,7 +439,6 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
}
}
});
- values->default_width = 8.0f;
return values;
}
Span<float4x4> transforms = component_->instance_transforms();
@@ -357,38 +449,35 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
size,
[transforms](int index, CellValue &r_cell_value) {
r_cell_value.value_float3 = transforms[index].translation();
- },
- default_float3_column_width);
+ });
}
if (STREQ(column_id.name, "Rotation")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].to_euler();
- },
- default_float3_column_width);
+ return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
+ column_id.name,
+ size,
+ [transforms](int index, CellValue &r_cell_value) {
+ r_cell_value.value_float3 = transforms[index].to_euler();
+ });
}
if (STREQ(column_id.name, "Scale")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].scale();
- },
- default_float3_column_width);
+ return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
+ column_id.name,
+ size,
+ [transforms](int index, CellValue &r_cell_value) {
+ r_cell_value.value_float3 = transforms[index].scale();
+ });
}
Span<int> ids = component_->instance_ids();
- if (STREQ(column_id.name, "ID")) {
- /* Make the column a bit wider by default, since the IDs tend to be large numbers. */
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INT32,
- column_id.name,
- size,
- [ids](int index, CellValue &r_cell_value) { r_cell_value.value_int = ids[index]; },
- 5.5f);
+ if (!ids.is_empty()) {
+ if (STREQ(column_id.name, "id")) {
+ /* Make the column a bit wider by default, since the IDs tend to be large numbers. */
+ return column_values_from_function(
+ SPREADSHEET_VALUE_TYPE_INT32,
+ column_id.name,
+ size,
+ [ids](int index, CellValue &r_cell_value) { r_cell_value.value_int = ids[index]; },
+ 5.5f);
+ }
}
return {};
}
@@ -469,6 +558,36 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
return geometry_set;
}
+static void find_fields_to_evaluate(const SpaceSpreadsheet *sspreadsheet,
+ Map<std::string, GField> &r_fields)
+{
+ if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) {
+ return;
+ }
+ if (BLI_listbase_count(&sspreadsheet->context_path) <= 1) {
+ /* No viewer is currently referenced by the context path. */
+ return;
+ }
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_spreadsheet_editor_context(
+ *sspreadsheet);
+ if (node_log == nullptr) {
+ return;
+ }
+ for (const geo_log::SocketLog &socket_log : node_log->input_logs()) {
+ const geo_log::ValueLog *value_log = socket_log.value();
+ if (value_log == nullptr) {
+ continue;
+ }
+ if (const geo_log::GFieldValueLog *field_value_log =
+ dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) {
+ const GField &field = field_value_log->field();
+ if (field) {
+ r_fields.add("Viewer", std::move(field));
+ }
+ }
+ }
+}
+
static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
@@ -481,6 +600,69 @@ static GeometryComponentType get_display_component_type(const bContext *C, Objec
return GEO_COMPONENT_TYPE_MESH;
}
+class GeometryComponentCacheKey : public SpreadsheetCache::Key {
+ public:
+ /* Use the pointer to the geometry component as a key to detect when the geometry changed. */
+ const GeometryComponent *component;
+
+ GeometryComponentCacheKey(const GeometryComponent &component) : component(&component)
+ {
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash(this->component);
+ }
+
+ bool is_equal_to(const Key &other) const override
+ {
+ if (const GeometryComponentCacheKey *other_geo =
+ dynamic_cast<const GeometryComponentCacheKey *>(&other)) {
+ return this->component == other_geo->component;
+ }
+ return false;
+ }
+};
+
+class GeometryComponentCacheValue : public SpreadsheetCache::Value {
+ public:
+ /* Stores the result of fields evaluated on a geometry component. Without this, fields would have
+ * to be reevaluated on every redraw. */
+ Map<std::pair<AttributeDomain, GField>, fn::GArray<>> arrays;
+};
+
+static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
+ const GeometryComponent &component,
+ ExtraColumns &r_extra_columns)
+{
+ Map<std::string, GField> fields_to_show;
+ find_fields_to_evaluate(sspreadsheet, fields_to_show);
+
+ GeometryComponentCacheValue &cache =
+ sspreadsheet->runtime->cache.lookup_or_add<GeometryComponentCacheValue>(
+ std::make_unique<GeometryComponentCacheKey>(component));
+
+ const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
+ const int domain_size = component.attribute_domain_size(domain);
+ for (const auto &item : fields_to_show.items()) {
+ StringRef name = item.key;
+ const GField &field = item.value;
+
+ /* Use the cached evaluated array if it exists, otherwise evaluate the field now. */
+ fn::GArray<> &evaluated_array = cache.arrays.lookup_or_add_cb({domain, field}, [&]() {
+ fn::GArray<> evaluated_array(field.cpp_type(), domain_size);
+
+ bke::GeometryComponentFieldContext field_context{component, domain};
+ fn::FieldEvaluator field_evaluator{field_context, domain_size};
+ field_evaluator.add_with_destination(field, evaluated_array);
+ field_evaluator.evaluate();
+ return evaluated_array;
+ });
+
+ r_extra_columns.add(std::move(name), evaluated_array.as_span());
+ }
+}
+
std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
@@ -493,10 +675,15 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
return {};
}
+ const GeometryComponent &component = *geometry_set.get_component_for_read(component_type);
+ ExtraColumns extra_columns;
+ add_fields_as_extra_columns(sspreadsheet, component, extra_columns);
+
if (component_type == GEO_COMPONENT_TYPE_INSTANCES) {
- return std::make_unique<InstancesDataSource>(geometry_set);
+ return std::make_unique<InstancesDataSource>(geometry_set, std::move(extra_columns));
}
- return std::make_unique<GeometryDataSource>(object_eval, geometry_set, component_type, domain);
+ return std::make_unique<GeometryDataSource>(
+ object_eval, geometry_set, component_type, domain, std::move(extra_columns));
}
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
index d1b5dc6845e..6c88a94f585 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -28,12 +28,34 @@ struct bContext;
namespace blender::ed::spreadsheet {
+/**
+ * Contains additional named columns that should be displayed that are not stored on the geometry
+ * directly. This is used for displaying the evaluated fields connected to a viewer node.
+ */
+class ExtraColumns {
+ private:
+ /** Maps column names to their data. The data is actually stored in the spreadsheet cache. */
+ Map<std::string, fn::GSpan> columns_;
+
+ public:
+ void add(std::string name, fn::GSpan data)
+ {
+ columns_.add(std::move(name), data);
+ }
+
+ void foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const;
+
+ std::unique_ptr<ColumnValues> get_column_values(const SpreadsheetColumnID &column_id) const;
+};
+
class GeometryDataSource : public DataSource {
private:
Object *object_eval_;
const GeometrySet geometry_set_;
const GeometryComponent *component_;
AttributeDomain domain_;
+ ExtraColumns extra_columns_;
/* Some data is computed on the fly only when it is requested. Computing it does not change the
* logical state of this data source. Therefore, the corresponding methods are const and need to
@@ -45,11 +67,13 @@ class GeometryDataSource : public DataSource {
GeometryDataSource(Object *object_eval,
GeometrySet geometry_set,
const GeometryComponentType component_type,
- const AttributeDomain domain)
+ const AttributeDomain domain,
+ ExtraColumns extra_columns)
: object_eval_(object_eval),
geometry_set_(std::move(geometry_set)),
component_(geometry_set_.get_component_for_read(component_type)),
- domain_(domain)
+ domain_(domain),
+ extra_columns_(std::move(extra_columns))
{
}
@@ -62,7 +86,7 @@ class GeometryDataSource : public DataSource {
void apply_selection_filter(MutableSpan<bool> rows_included) const;
void foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &)> fn) const override;
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override;
std::unique_ptr<ColumnValues> get_column_values(
const SpreadsheetColumnID &column_id) const override;
@@ -73,16 +97,18 @@ class GeometryDataSource : public DataSource {
class InstancesDataSource : public DataSource {
const GeometrySet geometry_set_;
const InstancesComponent *component_;
+ ExtraColumns extra_columns_;
public:
- InstancesDataSource(GeometrySet geometry_set)
+ InstancesDataSource(GeometrySet geometry_set, ExtraColumns extra_columns)
: geometry_set_(std::move(geometry_set)),
- component_(geometry_set_.get_component_for_read<InstancesComponent>())
+ component_(geometry_set_.get_component_for_read<InstancesComponent>()),
+ extra_columns_(std::move(extra_columns))
{
}
void foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &)> fn) const override;
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override;
std::unique_ptr<ColumnValues> get_column_values(
const SpreadsheetColumnID &column_id) const override;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
index 8be5283fd63..8b050c2e69b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
@@ -17,12 +17,24 @@
#pragma once
#include "BKE_geometry_set.hh"
+#include "spreadsheet_cache.hh"
-typedef struct SpaceSpreadsheet_Runtime {
- int visible_rows;
- int tot_rows;
- int tot_columns;
-} SpaceSpreadsheet_Runtime;
+struct SpaceSpreadsheet_Runtime {
+ public:
+ int visible_rows = 0;
+ int tot_rows = 0;
+ int tot_columns = 0;
+
+ blender::ed::spreadsheet::SpreadsheetCache cache;
+
+ SpaceSpreadsheet_Runtime() = default;
+
+ /* The cache is not copied currently. */
+ SpaceSpreadsheet_Runtime(const SpaceSpreadsheet_Runtime &other)
+ : visible_rows(other.visible_rows), tot_rows(other.tot_rows), tot_columns(other.tot_columns)
+ {
+ }
+};
struct bContext;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 1a5eac53306..355899be279 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -93,7 +93,9 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
const int real_index = spreadsheet_layout_.row_indices[row_index];
const ColumnValues &column = *spreadsheet_layout_.columns[column_index].values;
CellValue cell_value;
- column.get_value(real_index, cell_value);
+ if (real_index < column.size()) {
+ column.get_value(real_index, cell_value);
+ }
if (cell_value.value_int.has_value()) {
const int value = *cell_value.value_int;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 7999018a6b6..6acf51aec6e 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -40,12 +40,14 @@
#include "BLT_translation.h"
+#include "BKE_asset.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
@@ -55,6 +57,7 @@
#include "BKE_workspace.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_render.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -82,6 +85,7 @@
#endif
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "view3d_intern.h" /* own include */
@@ -515,10 +519,74 @@ static bool view3d_drop_id_in_main_region_poll(bContext *C,
return WM_drag_is_ID_type(drag, id_type);
}
+static void view3d_ob_drop_draw_activate(struct wmDropBox *drop, wmDrag *drag)
+{
+ V3DSnapCursorState *state = drop->draw_data;
+ if (state) {
+ return;
+ }
+
+ /* Don't use the snap cursor when linking the object. Object transform isn't editable then and
+ * would be reset on reload. */
+ if (WM_drag_asset_will_import_linked(drag)) {
+ return;
+ }
+
+ state = drop->draw_data = ED_view3d_cursor_snap_active();
+ state->draw_plane = true;
+
+ float dimensions[3] = {0.0f};
+ if (drag->type == WM_DRAG_ID) {
+ Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB);
+ BKE_object_dimensions_get(ob, dimensions);
+ }
+ else {
+ struct AssetMetaData *meta_data = WM_drag_get_asset_meta_data(drag, ID_OB);
+ IDProperty *dimensions_prop = BKE_asset_metadata_idprop_find(meta_data, "dimensions");
+ if (dimensions_prop) {
+ copy_v3_v3(dimensions, IDP_Array(dimensions_prop));
+ }
+ }
+
+ if (!is_zero_v3(dimensions)) {
+ mul_v3_v3fl(state->box_dimensions, dimensions, 0.5f);
+ UI_GetThemeColor4ubv(TH_GIZMO_PRIMARY, state->color_box);
+ state->draw_box = true;
+ }
+}
+
+static void view3d_ob_drop_draw_deactivate(struct wmDropBox *drop, wmDrag *UNUSED(drag))
+{
+ V3DSnapCursorState *state = drop->draw_data;
+ if (state) {
+ ED_view3d_cursor_snap_deactive(state);
+ drop->draw_data = NULL;
+ }
+}
+
static bool view3d_ob_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
return view3d_drop_id_in_main_region_poll(C, drag, event, ID_OB);
}
+static bool view3d_ob_drop_poll_external_asset(bContext *C, wmDrag *drag, const wmEvent *event)
+{
+ if (!view3d_ob_drop_poll(C, drag, event) || (drag->type != WM_DRAG_ASSET)) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * \note the term local here refers to not being an external asset,
+ * poll will succeed for linked library objects.
+ */
+static bool view3d_ob_drop_poll_local_id(bContext *C, wmDrag *drag, const wmEvent *event)
+{
+ if (!view3d_ob_drop_poll(C, drag, event) || (drag->type != WM_DRAG_ID)) {
+ return false;
+ }
+ return true;
+}
static bool view3d_collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
@@ -532,12 +600,17 @@ static bool view3d_mat_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
static char *view3d_mat_drop_tooltip(bContext *C,
wmDrag *drag,
- const wmEvent *event,
+ const int xy[2],
struct wmDropBox *drop)
{
const char *name = WM_drag_get_item_name(drag);
+ ARegion *region = CTX_wm_region(C);
RNA_string_set(drop->ptr, "name", name);
- return ED_object_ot_drop_named_material_tooltip(C, drop->ptr, event);
+ int mval[2] = {
+ xy[0] - region->winrct.xmin,
+ xy[1] - region->winrct.ymin,
+ };
+ return ED_object_ot_drop_named_material_tooltip(C, drop->ptr, mval);
}
static bool view3d_world_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -556,7 +629,7 @@ static bool view3d_object_data_drop_poll(bContext *C, wmDrag *drag, const wmEven
static char *view3d_object_data_drop_tooltip(bContext *UNUSED(C),
wmDrag *UNUSED(drag),
- const wmEvent *UNUSED(event),
+ const int UNUSED(xy[2]),
wmDropBox *UNUSED(drop))
{
return BLI_strdup(TIP_("Create object instance from object-data"));
@@ -626,14 +699,85 @@ static bool view3d_volume_drop_poll(bContext *UNUSED(C),
return (drag->type == WM_DRAG_PATH) && (drag->icon == ICON_FILE_VOLUME);
}
-static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
+static void view3d_ob_drop_matrix_from_snap(V3DSnapCursorState *snap_state,
+ Object *ob,
+ float obmat_final[4][4])
{
- ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_OB);
+ V3DSnapCursorData *snap_data;
+ snap_data = ED_view3d_cursor_snap_data_get(snap_state, NULL, 0, 0);
+ BLI_assert(snap_state->draw_box || snap_state->draw_plane);
+ copy_m4_m3(obmat_final, snap_data->plane_omat);
+ copy_v3_v3(obmat_final[3], snap_data->loc);
+
+ float scale[3];
+ mat4_to_size(scale, ob->obmat);
+ rescale_m4(obmat_final, scale);
+
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ float offset[3];
+ BKE_boundbox_calc_center_aabb(bb, offset);
+ offset[2] = bb->vec[0][2];
+ mul_mat3_m4_v3(obmat_final, offset);
+ sub_v3_v3(obmat_final[3], offset);
+ }
+}
+
+static void view3d_ob_drop_copy_local_id(wmDrag *drag, wmDropBox *drop)
+{
+ ID *id = WM_drag_get_local_ID(drag, ID_OB);
RNA_string_set(drop->ptr, "name", id->name + 2);
/* Don't duplicate ID's which were just imported. Only do that for existing, local IDs. */
- const bool is_imported_id = drag->type == WM_DRAG_ASSET;
- RNA_boolean_set(drop->ptr, "duplicate", !is_imported_id);
+ BLI_assert(drag->type != WM_DRAG_ASSET);
+
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ float obmat_final[4][4];
+
+ view3d_ob_drop_matrix_from_snap(snap_state, (Object *)id, obmat_final);
+
+ RNA_float_set_array(drop->ptr, "matrix", &obmat_final[0][0]);
+}
+
+static void view3d_ob_drop_copy_external_asset(wmDrag *drag, wmDropBox *drop)
+{
+ /* NOTE(@campbellbarton): Selection is handled here, de-selecting objects before append,
+ * using auto-select to ensure the new objects are selected.
+ * This is done so #OBJECT_OT_transform_to_mouse (which runs after this drop handler)
+ * can use the context setup here to place the objects. */
+ BLI_assert(drag->type == WM_DRAG_ASSET);
+
+ wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0);
+ bContext *C = asset_drag->evil_C;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ BKE_view_layer_base_deselect_all(view_layer);
+
+ ID *id = WM_drag_asset_id_import(asset_drag, FILE_AUTOSELECT);
+
+ /* TODO(sergey): Only update relations for the current scene. */
+ DEG_relations_tag_update(CTX_data_main(C));
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
+
+ RNA_string_set(drop->ptr, "name", id->name + 2);
+
+ Base *base = BKE_view_layer_base_find(view_layer, (Object *)id);
+ if (base != NULL) {
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+ WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene);
+ }
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_object_tag(C);
+
+ V3DSnapCursorState *snap_state = drop->draw_data;
+ if (snap_state) {
+ float obmat_final[4][4];
+
+ view3d_ob_drop_matrix_from_snap(snap_state, (Object *)id, obmat_final);
+
+ RNA_float_set_array(drop->ptr, "matrix", &obmat_final[0][0]);
+ }
}
static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop)
@@ -698,12 +842,31 @@ static void view3d_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW);
- WM_dropbox_add(lb,
- "OBJECT_OT_add_named",
- view3d_ob_drop_poll,
- view3d_ob_drop_copy,
- WM_drag_free_imported_drag_ID,
- NULL);
+ struct wmDropBox *drop;
+ drop = WM_dropbox_add(lb,
+ "OBJECT_OT_add_named",
+ view3d_ob_drop_poll_local_id,
+ view3d_ob_drop_copy_local_id,
+ WM_drag_free_imported_drag_ID,
+ NULL);
+
+ drop->draw = WM_drag_draw_item_name_fn;
+ drop->draw_activate = view3d_ob_drop_draw_activate;
+ drop->draw_deactivate = view3d_ob_drop_draw_deactivate;
+ drop->opcontext = WM_OP_EXEC_DEFAULT; /* Not really needed. */
+
+ drop = WM_dropbox_add(lb,
+ "OBJECT_OT_transform_to_mouse",
+ view3d_ob_drop_poll_external_asset,
+ view3d_ob_drop_copy_external_asset,
+ WM_drag_free_imported_drag_ID,
+ NULL);
+
+ drop->draw = WM_drag_draw_item_name_fn;
+ drop->draw_activate = view3d_ob_drop_draw_activate;
+ drop->draw_deactivate = view3d_ob_drop_draw_deactivate;
+ drop->opcontext = WM_OP_INVOKE_DEFAULT;
+
WM_dropbox_add(lb,
"OBJECT_OT_drop_named_material",
view3d_mat_drop_poll,
@@ -1616,6 +1779,7 @@ static void space_view3d_refresh(const bContext *C, ScrArea *area)
const char *view3d_context_dir[] = {
"active_object",
+ "selected_ids",
NULL,
};
@@ -1626,8 +1790,9 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, view3d_context_dir);
+ return CTX_RESULT_OK;
}
- else if (CTX_data_equals(member, "active_object")) {
+ if (CTX_data_equals(member, "active_object")) {
/* In most cases the active object is the `view_layer->basact->object`.
* For the 3D view however it can be NULL when hidden.
*
@@ -1651,13 +1816,21 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
}
}
- return 1;
+ return CTX_RESULT_OK;
}
- else {
- return 0; /* not found */
+ if (CTX_data_equals(member, "selected_ids")) {
+ ListBase selected_objects;
+ CTX_data_selected_objects(C, &selected_objects);
+ LISTBASE_FOREACH (CollectionPointerLink *, object_ptr_link, &selected_objects) {
+ ID *selected_id = object_ptr_link->ptr.owner_id;
+ CTX_data_id_list_add(result, selected_id);
+ }
+ BLI_freelistN(&selected_objects);
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
}
- return -1; /* found but not available */
+ return CTX_RESULT_MEMBER_NOT_FOUND;
}
static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c
index 1cb650910ce..baf61befcba 100644
--- a/source/blender/editors/space_view3d/view3d_cursor_snap.c
+++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c
@@ -37,6 +37,7 @@
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
@@ -54,27 +55,25 @@
#include "WM_api.h"
-#define STATE_LEN 3
+#define STATE_INTERN_GET(state) \
+ (SnapStateIntern *)((char *)state - offsetof(SnapStateIntern, snap_state))
typedef struct SnapStateIntern {
+ struct SnapStateIntern *next, *prev;
V3DSnapCursorState snap_state;
- float prevpoint_stack[3];
- int state_active_prev;
- bool is_active;
} SnapStateIntern;
typedef struct SnapCursorDataIntern {
V3DSnapCursorState state_default;
- SnapStateIntern state_intern[STATE_LEN];
+ ListBase state_intern;
V3DSnapCursorData snap_data;
- int state_active_len;
- int state_active;
-
struct SnapObjectContext *snap_context_v3d;
const Scene *scene;
short snap_elem_hidden;
+ float prevpoint_stack[3];
+
/* Copy of the parameters of the last event state in order to detect updates. */
struct {
int x;
@@ -94,17 +93,6 @@ typedef struct SnapCursorDataIntern {
bool is_initiated;
} SnapCursorDataIntern;
-static void UNUSED_FUNCTION(v3d_cursor_snap_state_init)(V3DSnapCursorState *state)
-{
- state->prevpoint = NULL;
- state->snap_elem_force = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT);
- state->plane_axis = 2;
- rgba_uchar_args_set(state->color_point, 255, 255, 255, 255);
- rgba_uchar_args_set(state->color_line, 255, 255, 255, 128);
- state->draw_point = true;
- state->draw_plane = false;
-}
static SnapCursorDataIntern g_data_intern = {
.state_default = {.prevpoint = NULL,
.snap_elem_force = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE |
@@ -113,8 +101,9 @@ static SnapCursorDataIntern g_data_intern = {
.plane_axis = 2,
.color_point = {255, 255, 255, 255},
.color_line = {255, 255, 255, 128},
- .draw_point = true,
- .draw_plane = false}};
+ .color_box = {255, 255, 255, 128},
+ .box_dimensions = {1.0f, 1.0f, 1.0f},
+ .draw_point = true}};
/**
* Calculate a 3x3 orientation matrix from the surface under the cursor.
@@ -373,6 +362,24 @@ static void v3d_cursor_plane_draw(const RegionView3D *rv3d,
}
}
+static void cursor_box_draw(const float dimensions[3], uchar color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPU_blend(GPU_BLEND_ALPHA);
+ GPU_line_smooth(true);
+ GPU_line_width(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4ubv(color);
+ imm_draw_cube_corners_3d(pos_id, (const float[3]){0.0f, 0.0f, dimensions[2]}, dimensions, 0.15f);
+ immUnbindProgram();
+
+ GPU_line_smooth(false);
+ GPU_blend(GPU_BLEND_NONE);
+}
+
void ED_view3d_cursor_snap_draw_util(RegionView3D *rv3d,
const float loc_prev[3],
const float loc_curr[3],
@@ -601,7 +608,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
ushort snap_elements = v3d_cursor_snap_elements(state, scene);
data_intern->snap_elem_hidden = 0;
- const bool draw_plane = state->draw_plane;
+ const bool draw_plane = state->draw_plane || state->draw_box;
if (draw_plane && !(snap_elements & SCE_SNAP_MODE_FACE)) {
data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
snap_elements |= SCE_SNAP_MODE_FACE;
@@ -674,6 +681,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
}
if (draw_plane) {
+ RegionView3D *rv3d = region->regiondata;
bool orient_surface = snap_elem && (state->plane_orient == V3D_PLACE_ORIENT_SURFACE);
if (orient_surface) {
copy_m3_m4(omat, obmat);
@@ -686,7 +694,6 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
ED_transform_calc_orientation_from_type_ex(
scene, view_layer, v3d, region->regiondata, ob, ob, orient_index, pivot_point, omat);
- RegionView3D *rv3d = region->regiondata;
if (state->use_plane_axis_auto) {
mat3_align_axis_to_v3(omat, state->plane_axis, rv3d->viewinv[2]);
}
@@ -699,6 +706,9 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
orthogonalize_m3(omat, state->plane_axis);
if (orient_surface) {
+ if (dot_v3v3(rv3d->viewinv[2], face_nor) < 0.0f) {
+ negate_v3(face_nor);
+ }
v3d_cursor_poject_surface_normal(face_nor, obmat, omat);
}
}
@@ -755,16 +765,12 @@ static bool v3d_cursor_snap_pool_fn(bContext *C)
return false;
}
- ARegion *region = CTX_wm_region(C);
- if (region->regiontype != RGN_TYPE_WINDOW) {
- return false;
- }
-
ScrArea *area = CTX_wm_area(C);
if (area->spacetype != SPACE_VIEW3D) {
return false;
}
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
RegionView3D *rv3d = region->regiondata;
if (rv3d->rflag & RV3D_NAVIGATING) {
/* Don't draw the cursor while navigating. It can be distracting. */
@@ -781,7 +787,8 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
V3DSnapCursorData *snap_data = &data_intern->snap_data;
wmWindowManager *wm = CTX_wm_manager(C);
- ARegion *region = CTX_wm_region(C);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
x -= region->winrct.xmin;
y -= region->winrct.ymin;
if (v3d_cursor_eventstate_has_changed(data_intern, state, wm, x, y)) {
@@ -791,7 +798,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
v3d_cursor_snap_update(state, C, wm, depsgraph, scene, region, v3d, x, y);
}
- const bool draw_plane = state->draw_plane;
+ const bool draw_plane = state->draw_plane || state->draw_box;
if (!snap_data->snap_elem && !draw_plane) {
return;
}
@@ -802,8 +809,6 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
GPU_matrix_projection_set(rv3d->winmat);
GPU_matrix_set(rv3d->viewmat);
- GPU_blend(GPU_BLEND_ALPHA);
-
float matrix[4][4];
if (draw_plane) {
copy_m4_m3(matrix, snap_data->plane_omat);
@@ -812,7 +817,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
v3d_cursor_plane_draw(rv3d, state->plane_axis, matrix);
}
- if (snap_data->snap_elem && state->draw_point) {
+ if (snap_data->snap_elem && (state->draw_point || state->draw_box)) {
const float *prev_point = (snap_data->snap_elem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) ?
state->prevpoint :
NULL;
@@ -829,7 +834,10 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
snap_data->snap_elem);
}
- GPU_blend(GPU_BLEND_NONE);
+ if (state->draw_box) {
+ GPU_matrix_mul(matrix);
+ cursor_box_draw(state->box_dimensions, state->color_box);
+ }
/* Restore matrix. */
wmWindowViewport(CTX_wm_window(C));
@@ -839,10 +847,11 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
V3DSnapCursorState *ED_view3d_cursor_snap_state_get(void)
{
- if (!g_data_intern.state_active_len) {
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ if (BLI_listbase_is_empty(&data_intern->state_intern)) {
return &g_data_intern.state_default;
}
- return (V3DSnapCursorState *)&g_data_intern.state_intern[g_data_intern.state_active];
+ return &((SnapStateIntern *)data_intern->state_intern.last)->snap_state;
}
static void v3d_cursor_snap_activate(void)
@@ -872,20 +881,16 @@ static void v3d_cursor_snap_activate(void)
static void v3d_cursor_snap_free(void)
{
SnapCursorDataIntern *data_intern = &g_data_intern;
- if (data_intern->handle && G_MAIN->wm.first) {
- WM_paint_cursor_end(data_intern->handle);
+ if (data_intern->handle) {
+ if (G_MAIN->wm.first) {
+ WM_paint_cursor_end(data_intern->handle);
+ }
data_intern->handle = NULL;
}
if (data_intern->snap_context_v3d) {
ED_transform_snap_object_context_destroy(data_intern->snap_context_v3d);
data_intern->snap_context_v3d = NULL;
}
-
- for (SnapStateIntern *state_intern = data_intern->state_intern;
- state_intern < &data_intern->state_intern[STATE_LEN];
- state_intern++) {
- state_intern->is_active = false;
- }
}
void ED_view3d_cursor_snap_state_default_set(V3DSnapCursorState *state)
@@ -896,56 +901,41 @@ void ED_view3d_cursor_snap_state_default_set(V3DSnapCursorState *state)
V3DSnapCursorState *ED_view3d_cursor_snap_active(void)
{
SnapCursorDataIntern *data_intern = &g_data_intern;
- if (!data_intern->state_active_len) {
+ if (!data_intern->handle) {
v3d_cursor_snap_activate();
}
- data_intern->state_active_len++;
- for (int i = 0; i < STATE_LEN; i++) {
- SnapStateIntern *state_intern = &g_data_intern.state_intern[i];
- if (!state_intern->is_active) {
- state_intern->snap_state = g_data_intern.state_default;
- state_intern->is_active = true;
- state_intern->state_active_prev = data_intern->state_active;
- data_intern->state_active = i;
- return (V3DSnapCursorState *)state_intern;
- }
- }
+ SnapStateIntern *state_intern = MEM_mallocN(sizeof(*state_intern), __func__);
+ state_intern->snap_state = g_data_intern.state_default;
+ BLI_addtail(&g_data_intern.state_intern, state_intern);
- BLI_assert(false);
- data_intern->state_active_len--;
- return NULL;
+ return (V3DSnapCursorState *)&state_intern->snap_state;
}
void ED_view3d_cursor_snap_deactive(V3DSnapCursorState *state)
{
SnapCursorDataIntern *data_intern = &g_data_intern;
- if (!data_intern->state_active_len) {
- BLI_assert(false);
- return;
- }
-
- SnapStateIntern *state_intern = (SnapStateIntern *)state;
- if (!state_intern->is_active) {
+ if (BLI_listbase_is_empty(&data_intern->state_intern)) {
return;
}
- state_intern->is_active = false;
- data_intern->state_active_len--;
- if (!data_intern->state_active_len) {
+ SnapStateIntern *state_intern = STATE_INTERN_GET(state);
+ BLI_remlink(&data_intern->state_intern, state_intern);
+ MEM_freeN(state_intern);
+ if (BLI_listbase_is_empty(&data_intern->state_intern)) {
v3d_cursor_snap_free();
}
- else {
- data_intern->state_active = state_intern->state_active_prev;
- }
}
void ED_view3d_cursor_snap_prevpoint_set(V3DSnapCursorState *state, const float prev_point[3])
{
- SnapStateIntern *state_intern = (SnapStateIntern *)state;
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ if (!state) {
+ state = ED_view3d_cursor_snap_state_get();
+ }
if (prev_point) {
- copy_v3_v3(state_intern->prevpoint_stack, prev_point);
- state->prevpoint = state_intern->prevpoint_stack;
+ copy_v3_v3(data_intern->prevpoint_stack, prev_point);
+ state->prevpoint = data_intern->prevpoint_stack;
}
else {
state->prevpoint = NULL;
@@ -958,12 +948,13 @@ V3DSnapCursorData *ED_view3d_cursor_snap_data_get(V3DSnapCursorState *state,
const int y)
{
SnapCursorDataIntern *data_intern = &g_data_intern;
- if (C && data_intern->state_active_len) {
+ if (C) {
wmWindowManager *wm = CTX_wm_manager(C);
if (v3d_cursor_eventstate_has_changed(data_intern, state, wm, x, y)) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = DEG_get_input_scene(depsgraph);
- ARegion *region = CTX_wm_region(C);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
View3D *v3d = CTX_wm_view3d(C);
if (!state) {
@@ -982,8 +973,3 @@ struct SnapObjectContext *ED_view3d_cursor_snap_context_ensure(Scene *scene)
v3d_cursor_snap_context_ensure(scene);
return data_intern->snap_context_v3d;
}
-
-void ED_view3d_cursor_snap_exit(void)
-{
- v3d_cursor_snap_free();
-}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index fe347e89600..fceb6553cab 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -347,6 +347,8 @@ static void view3d_xr_mirror_setup(const wmWindowManager *wm,
(wm->xr.session_settings.draw_flags & V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS) !=
0,
V3D_XR_SHOW_CUSTOM_OVERLAYS);
+ /* Hide navigation gizmo since it gets distorted if the view matrix has a scale factor. */
+ v3d->gizmo_flag |= V3D_GIZMO_HIDE_NAVIGATE;
/* Reset overridden View3D data. */
v3d->lens = lens_old;
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index 7fe97705765..572fc8e3156 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -742,16 +742,19 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv
ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
- ipd->snap_state = ED_view3d_cursor_snap_active();
- ipd->snap_state->draw_point = true;
- ipd->snap_state->draw_plane = true;
+ V3DSnapCursorState *snap_state_new = ED_view3d_cursor_snap_active();
+ if (snap_state_new) {
+ ipd->snap_state = snap_state = snap_state_new;
+ }
+ snap_state->draw_point = true;
+ snap_state->draw_plane = true;
ipd->is_snap_found =
view3d_interactive_add_calc_snap(
C, event, ipd->co_src, ipd->matrix_orient, &ipd->use_snap, &ipd->is_snap_invert) != 0;
- ipd->snap_state->draw_plane = false;
- ED_view3d_cursor_snap_prevpoint_set(ipd->snap_state, ipd->co_src);
+ snap_state->draw_plane = false;
+ ED_view3d_cursor_snap_prevpoint_set(snap_state, ipd->co_src);
ipd->orient_axis = plane_axis;
for (int i = 0; i < 2; i++) {
@@ -1515,10 +1518,12 @@ static void preview_plane_free_fn(void *customdata)
static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_active();
- snap_state->draw_plane = true;
+ if (snap_state) {
+ snap_state->draw_plane = true;
- gzgroup->customdata = snap_state;
- gzgroup->customdata_free = preview_plane_free_fn;
+ gzgroup->customdata = snap_state;
+ gzgroup->customdata_free = preview_plane_free_fn;
+ }
}
void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt)
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 07f1f8a753c..18820039c7f 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -2047,19 +2047,16 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
bool enumerate,
bool *r_do_nearest)
{
- static int last_mval[2] = {-100, -100};
bool do_nearest = false;
View3D *v3d = vc->v3d;
/* define if we use solid nearest select or not */
if (use_cycle) {
+ /* Update the coordinates (even if the return value isn't used). */
+ const bool has_motion = WM_cursor_test_motion_and_update(mval);
if (!XRAY_ACTIVE(v3d)) {
- do_nearest = true;
- if (len_manhattan_v2v2_int(mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
- do_nearest = false;
- }
+ do_nearest = has_motion;
}
- copy_v2_v2_int(last_mval, mval);
}
else {
if (!XRAY_ACTIVE(v3d)) {
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 55ec6652495..67b61ed77d8 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -615,7 +615,7 @@ static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op)
const float *snap_target_global = scene->cursor.location;
const int pivot_point = scene->toolsettings->transform_pivot_point;
- if (snap_selected_to_location(C, snap_target_global, pivot_point, use_offset, true)) {
+ if (snap_selected_to_location(C, snap_target_global, use_offset, pivot_point, true)) {
return OPERATOR_CANCELLED;
}
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index f5da7c14a88..46a664f10fa 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -1730,7 +1730,12 @@ void ED_view3d_xr_shading_update(wmWindowManager *wm, const View3D *v3d, const S
if (v3d->runtime.flag & V3D_RUNTIME_XR_SESSION_ROOT) {
View3DShading *xr_shading = &wm->xr.session_settings.shading;
/* Flags that shouldn't be overridden by the 3D View shading. */
- const int flag_copy = V3D_SHADING_WORLD_ORIENTATION;
+ int flag_copy = 0;
+ if (v3d->shading.type !=
+ OB_SOLID) { /* Don't set V3D_SHADING_WORLD_ORIENTATION for solid shading since it results
+ in distorted lighting when the view matrix has a scale factor. */
+ flag_copy |= V3D_SHADING_WORLD_ORIENTATION;
+ }
BLI_assert(WM_xr_session_exists(&wm->xr));
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index e4c20fa0be1..466c4202dbd 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -646,10 +646,8 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = area->spacedata.first;
- Object *obedit = CTX_data_edit_object(C);
RegionView3D *rv3d = region->regiondata;
Base *base;
- Object *ob = OBACT(view_layer);
bGPdata *gpd = CTX_data_gpencil_data(C);
const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
const bool is_curve_edit = GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
@@ -660,6 +658,15 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
(params->orientation_index - 1) :
BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
+ Object *ob = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_OBACT(ob);
+ if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
+ Object *obpose = BKE_object_pose_armature_get(ob);
+ if (obpose != NULL) {
+ ob = obpose;
+ }
+ }
+
/* transform widget matrix */
unit_m4(rv3d->twmat);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index dea8a7c6f03..c779fbe4a33 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -493,6 +493,11 @@ static void iter_snap_objects(SnapObjectContext *sctx,
continue;
}
}
+ else if (snap_select == SNAP_SELECTABLE) {
+ if (!(base->flag & BASE_SELECTABLE)) {
+ continue;
+ }
+ }
Object *obj_eval = DEG_get_evaluated_object(sctx->runtime.depsgraph, base->object);
if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) {
@@ -2308,7 +2313,7 @@ static short snapMesh(SnapObjectContext *sctx,
float dist_px_sq = square_f(*dist_px);
/* Test BoundBox */
- BoundBox *bb = BKE_mesh_boundbox_get(ob_eval);
+ BoundBox *bb = BKE_object_boundbox_get(ob_eval);
if (bb &&
!snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) {
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
index 2acdf5cfd9c..7bcf6812ce9 100644
--- a/source/blender/editors/transform/transform_snap_sequencer.c
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -220,13 +220,13 @@ static void seq_snap_target_points_build(const TransInfo *t,
int content_end = max_ii(seq->startdisp, seq->start + seq->len);
/* Effects and single image strips produce incorrect content length. Skip these strips. */
if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->len == 1) {
- if (seq->anim_startofs == 0 && seq->startstill == 0) {
- content_start = seq->startdisp;
- }
- if (seq->anim_endofs == 0 && seq->endstill == 0) {
- content_end = seq->enddisp;
- }
+ content_start = seq->startdisp;
+ content_end = seq->enddisp;
}
+
+ CLAMP(content_start, seq->startdisp, seq->enddisp);
+ CLAMP(content_end, seq->startdisp, seq->enddisp);
+
snap_data->target_snap_points[i] = content_start;
snap_data->target_snap_points[i + 1] = content_end;
i += 2;
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index ed5064fdf25..5e0302130af 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -227,9 +227,19 @@ class FieldContext;
* A #FieldNode that represents an input to the entire field-tree.
*/
class FieldInput : public FieldNode {
+ public:
+ /* The order is also used for sorting in socket inspection. */
+ enum class Category {
+ NamedAttribute = 0,
+ Generated = 1,
+ AnonymousAttribute = 2,
+ Unknown,
+ };
+
protected:
const CPPType *type_;
std::string debug_name_;
+ Category category_ = Category::Unknown;
public:
FieldInput(const CPPType &type, std::string debug_name = "");
@@ -245,6 +255,7 @@ class FieldInput : public FieldNode {
virtual std::string socket_inspection_name() const;
blender::StringRef debug_name() const;
const CPPType &cpp_type() const;
+ Category category() const;
const CPPType &output_cpp_type(int output_index) const override;
void foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const override;
@@ -527,6 +538,11 @@ inline const CPPType &FieldInput::cpp_type() const
return *type_;
}
+inline FieldInput::Category FieldInput::category() const
+{
+ return category_;
+}
+
inline const CPPType &FieldInput::output_cpp_type(int output_index) const
{
BLI_assert(output_index == 0);
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index c6125b65c5e..4de5e71c910 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -477,6 +477,12 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
void evaluate_constant_field(const GField &field, void *r_value)
{
+ if (field.node().depends_on_input()) {
+ const CPPType &type = field.cpp_type();
+ type.copy_construct(type.default_value(), r_value);
+ return;
+ }
+
ResourceScope scope;
FieldContext context;
Vector<const GVArray *> varrays = evaluate_fields(scope, {field}, IndexRange(1), context);
@@ -517,6 +523,7 @@ const GVArray *FieldContext::get_varray_for_input(const FieldInput &field_input,
IndexFieldInput::IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index")
{
+ category_ = Category::Generated;
}
GVArray *IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &scope)
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 595a0c1cc5e..9ea146c77f2 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -156,7 +156,7 @@ float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr)
MDeformWeight *dw = BKE_defvert_find_index(dvert, def_nr);
weight = dw ? dw->weight : -1.0f;
if ((weight >= 0.0f) && (inverse)) {
- return -1.0f;
+ return 1.0f - weight;
}
if ((weight < 0.0f) && (!inverse)) {
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
index ba33edd6a94..33cc3094a36 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
@@ -255,7 +255,7 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
BKE_gpencil_frame_active_set(depsgraph, gpd);
bGPDframe *gpf = gpl->actframe;
if (gpf == NULL) {
- return;
+ continue;
}
apply_dash_for_frame(ob, gpl, gpd, gpf, (DashGpencilModifierData *)md);
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index c5ccf1d8229..fa31aec2b5b 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -160,12 +160,14 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
LineartCache *local_lc = gpd->runtime.lineart_cache;
if (!gpd->runtime.lineart_cache) {
- MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache);
+ MOD_lineart_compute_feature_lines(
+ depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT)));
MOD_lineart_destroy_render_data(lmd);
}
else {
if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) {
- MOD_lineart_compute_feature_lines(depsgraph, lmd, &local_lc);
+ MOD_lineart_compute_feature_lines(
+ depsgraph, lmd, &local_lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
MOD_lineart_destroy_render_data(lmd);
}
MOD_lineart_chain_clear_picked_flag(local_lc);
@@ -210,7 +212,8 @@ static void bakeModifier(Main *UNUSED(bmain),
lmd->edge_types_override = lmd->edge_types;
lmd->level_end_override = lmd->level_end;
- MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache);
+ MOD_lineart_compute_feature_lines(
+ depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT)));
MOD_lineart_destroy_render_data(lmd);
}
@@ -261,7 +264,13 @@ static void updateDepsgraph(GpencilModifierData *md,
else {
add_this_collection(ctx->scene->master_collection, ctx, mode);
}
- if (ctx->scene->camera) {
+ if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA && lmd->source_camera) {
+ DEG_add_object_relation(
+ ctx->node, lmd->source_camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
+ DEG_add_object_relation(
+ ctx->node, lmd->source_camera, DEG_OB_COMP_PARAMETERS, "Line Art Modifier");
+ }
+ else if (ctx->scene->camera) {
DEG_add_object_relation(
ctx->node, ctx->scene->camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
DEG_add_object_relation(
@@ -277,6 +286,7 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk,
walk(userData, ob, (ID **)&lmd->source_collection, IDWALK_CB_NOP);
walk(userData, ob, (ID **)&lmd->source_object, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&lmd->source_camera, IDWALK_CB_NOP);
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -382,7 +392,12 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
return;
}
- uiItemR(layout, ptr, "overscan", 0, NULL, ICON_NONE);
+ uiLayout *row = uiLayoutRowWithHeading(layout, false, IFACE_("Custom Camera"));
+ uiItemR(row, ptr, "use_custom_camera", 0, "", 0);
+ uiLayout *subrow = uiLayoutRow(row, true);
+ uiLayoutSetActive(subrow, RNA_boolean_get(ptr, "use_custom_camera"));
+ uiLayoutSetPropSep(subrow, true);
+ uiItemR(subrow, ptr, "source_camera", 0, "", ICON_OBJECT_DATA);
uiLayout *col = uiLayoutColumn(layout, true);
@@ -391,7 +406,7 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_object_instances", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_crease_on_smooth", 0, IFACE_("Crease On Smooth"), ICON_NONE);
- uiItemR(layout, ptr, "use_crease_on_sharp", 0, IFACE_("Crease On Sharp"), ICON_NONE);
+ uiItemR(col, ptr, "use_crease_on_sharp", 0, IFACE_("Crease On Sharp"), ICON_NONE);
}
static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -412,14 +427,23 @@ static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
- PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+ const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels");
+ const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
+
uiLayoutSetPropSep(layout, true);
uiLayoutSetEnabled(layout, !is_baked);
- const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels");
+ if (!show_in_front) {
+ uiItemL(layout, IFACE_("Object is not in front"), ICON_INFO);
+ }
+
+ layout = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(layout, show_in_front);
uiItemR(layout, ptr, "use_multiple_levels", 0, IFACE_("Range"), ICON_NONE);
@@ -447,11 +471,14 @@ static bool anything_showing_through(PointerRNA *ptr)
static void material_mask_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
- PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+ const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
+
uiLayoutSetEnabled(layout, !is_baked);
- uiLayoutSetActive(layout, anything_showing_through(ptr));
+ uiLayoutSetActive(layout, show_in_front && anything_showing_through(ptr));
uiItemR(layout, ptr, "use_material_mask", 0, IFACE_("Material Mask"), ICON_NONE);
}
@@ -654,6 +681,32 @@ static void bake_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_clear_all");
}
+static void composition_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ uiLayout *layout = panel->layout;
+
+ const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiItemR(layout, ptr, "overscan", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_image_boundary_trimming", 0, NULL, ICON_NONE);
+
+ if (show_in_front) {
+ uiItemL(layout, IFACE_("Object is shown in front"), ICON_ERROR);
+ }
+
+ uiLayout *col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, !show_in_front);
+
+ uiItemR(col, ptr, "stroke_depth_offset", UI_ITEM_R_SLIDER, IFACE_("Depth Offset"), ICON_NONE);
+ uiItemR(
+ col, ptr, "use_offset_towards_custom_camera", 0, IFACE_("Towards Custom Camera"), ICON_NONE);
+}
+
static void panelRegister(ARegionType *region_type)
{
PanelType *panel_type = gpencil_modifier_panel_register(
@@ -682,6 +735,8 @@ static void panelRegister(ARegionType *region_type)
gpencil_modifier_subpanel_register(
region_type, "vgroup", "Vertex Weight Transfer", NULL, vgroup_panel_draw, panel_type);
gpencil_modifier_subpanel_register(
+ region_type, "composition", "Composition", NULL, composition_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(
region_type, "bake", "Bake", NULL, bake_panel_draw, panel_type);
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
index fb75b1e99ac..2e55369ea97 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -240,10 +240,10 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "hardness", 0, NULL, ICON_NONE);
}
else {
- const bool is_normalized = RNA_boolean_get(ptr, "normalize_opacity");
+ const bool is_normalized = RNA_boolean_get(ptr, "use_normalized_opacity");
const bool is_weighted = RNA_boolean_get(ptr, "use_weight_factor");
- uiItemR(layout, ptr, "normalize_opacity", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_normalized_opacity", 0, NULL, ICON_NONE);
const char *text = (is_normalized) ? IFACE_("Strength") : IFACE_("Opacity Factor");
uiLayout *row = uiLayoutRow(layout, true);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
index cac700e15f4..233992bbd31 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -191,8 +191,8 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
- uiItemR(layout, ptr, "normalize_thickness", 0, NULL, ICON_NONE);
- if (RNA_boolean_get(ptr, "normalize_thickness")) {
+ uiItemR(layout, ptr, "use_normalized_thickness", 0, NULL, ICON_NONE);
+ if (RNA_boolean_get(ptr, "use_normalized_thickness")) {
uiItemR(layout, ptr, "thickness", 0, NULL, ICON_NONE);
}
else {
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index c00f34185dd..d8926a63307 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -182,9 +182,9 @@ typedef struct LineartEdgeChain {
typedef struct LineartEdgeChainItem {
struct LineartEdgeChainItem *next, *prev;
- /** Need z value for fading */
- float pos[3];
- /** For restoring position to 3d space */
+ /** Need z value for fading, w value for image frame clipping. */
+ float pos[4];
+ /** For restoring position to 3d space. */
float gpos[3];
float normal[3];
unsigned char line_type;
@@ -299,6 +299,7 @@ typedef struct LineartRenderBuffer {
bool use_loose_as_contour;
bool use_loose_edge_chain;
bool use_geometry_space_chain;
+ bool use_image_boundary_trimming;
bool filter_face_mark;
bool filter_face_mark_invert;
@@ -311,6 +312,7 @@ typedef struct LineartRenderBuffer {
bool cam_is_persp;
float cam_obmat[4][4];
double camera_pos[3];
+ double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */
double near_clip, far_clip;
float shift_x, shift_y;
float crease_threshold;
@@ -593,15 +595,20 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb);
void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb);
void MOD_lineart_chain_connect(LineartRenderBuffer *rb);
void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold);
+void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb);
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad);
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance);
+void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
+ float dist,
+ bool use_custom_camera);
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);
bool MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph,
struct LineartGpencilModifierData *lmd,
- LineartCache **cached_result);
+ struct LineartCache **cached_result,
+ bool enable_stroke_offset);
struct Scene;
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index 8935bdd1870..f3110cf87b6 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -126,7 +126,7 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
- copy_v2_v2(eci->pos, fbcoord);
+ copy_v4_v4(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
eci->index = index;
copy_v3_v3(eci->normal, normal);
@@ -156,7 +156,7 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb
eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
- copy_v2_v2(eci->pos, fbcoord);
+ copy_v4_v4(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
eci->index = index;
copy_v3_v3(eci->normal, normal);
@@ -177,15 +177,15 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
int last_occlusion;
unsigned char last_transparency;
/* Used when converting from double. */
- float use_fbcoord[2];
+ float use_fbcoord[4];
float use_gpos[3];
#define VERT_COORD_TO_FLOAT(a) \
- copy_v2fl_v2db(use_fbcoord, (a)->fbcoord); \
+ copy_v4fl_v4db(use_fbcoord, (a)->fbcoord); \
copy_v3fl_v3db(use_gpos, (a)->gloc);
#define POS_TO_FLOAT(lpos, gpos) \
- copy_v2fl_v2db(use_fbcoord, lpos); \
+ copy_v3fl_v3db(use_fbcoord, lpos); \
copy_v3fl_v3db(use_gpos, gpos);
LRT_ITER_ALL_LINES_BEGIN
@@ -262,6 +262,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
+ use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
lineart_chain_prepend_point(rb,
ec,
@@ -287,6 +288,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
+ use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
lineart_chain_prepend_point(rb,
ec,
@@ -340,6 +342,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
interp_v3_v3v3_db(lpos, e->v1->fbcoord, e->v2->fbcoord, es->at);
interp_v3_v3v3_db(gpos, e->v1->gloc, e->v2->gloc, global_at);
+ use_fbcoord[3] = interpf(e->v2->fbcoord[3], e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
lineart_chain_append_point(rb,
ec,
@@ -403,6 +406,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
+ use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
last_occlusion = es->prev ? es->prev->occlusion : last_occlusion;
last_transparency = es->prev ? es->prev->material_mask_bits : last_transparency;
POS_TO_FLOAT(lpos, gpos)
@@ -430,6 +434,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
+ use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
lineart_chain_append_point(rb,
ec,
@@ -926,9 +931,9 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
{
- LISTBASE_FOREACH (LineartEdgeChain *, rlc, &rb->chains) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
LineartEdgeChainItem *next_eci;
- for (LineartEdgeChainItem *eci = rlc->chain.first; eci; eci = next_eci) {
+ for (LineartEdgeChainItem *eci = ec->chain.first; eci; eci = next_eci) {
next_eci = eci->next;
LineartEdgeChainItem *eci2, *eci3, *eci4;
@@ -944,7 +949,7 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) {
/* And if p4 is on the extension of p1-p2 , we remove p3. */
if ((eci4 = eci3->next) && (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) {
- BLI_remlink(&rlc->chain, eci3);
+ BLI_remlink(&ec->chain, eci3);
next_eci = eci;
}
}
@@ -952,6 +957,116 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
}
}
+static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBuffer *rb,
+ LineartEdgeChainItem *eci_inside,
+ LineartEdgeChainItem *eci_outside)
+{
+ float isec[2];
+ float LU[2] = {-1.0f, 1.0f}, LB[2] = {-1.0f, -1.0f}, RU[2] = {1.0f, 1.0f}, RB[2] = {1.0f, -1.0f};
+ bool found = false;
+ LineartEdgeChainItem *eci2 = eci_outside, *eci1 = eci_inside;
+ if (eci2->pos[0] < -1.0f) {
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, LB, isec) > 0);
+ }
+ if (!found && eci2->pos[0] > 1.0f) {
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, RU, RB, isec) > 0);
+ }
+ if (!found && eci2->pos[1] < -1.0f) {
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LB, RB, isec) > 0);
+ }
+ if (!found && eci2->pos[1] > 1.0f) {
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, RU, isec) > 0);
+ }
+
+ if (UNLIKELY(!found)) {
+ return NULL;
+ }
+
+ float ratio = (fabs(eci2->pos[0] - eci1->pos[0]) > fabs(eci2->pos[1] - eci1->pos[1])) ?
+ ratiof(eci1->pos[0], eci2->pos[0], isec[0]) :
+ ratiof(eci1->pos[1], eci2->pos[1], isec[1]);
+ float gratio = eci1->pos[3] * ratio / (ratio * eci1->pos[3] + (1 - ratio) * eci2->pos[3]);
+
+ LineartEdgeChainItem *eci = lineart_mem_acquire(rb->chain_data_pool,
+ sizeof(LineartEdgeChainItem));
+ memcpy(eci, eci1, sizeof(LineartEdgeChainItem));
+ interp_v3_v3v3(eci->gpos, eci1->gpos, eci2->gpos, gratio);
+ interp_v3_v3v3(eci->pos, eci1->pos, eci2->pos, ratio);
+ eci->pos[3] = interpf(eci2->pos[3], eci1->pos[3], gratio);
+ eci->next = eci->prev = NULL;
+ return eci;
+}
+
+#define LRT_ECI_INSIDE(eci) \
+ ((eci)->pos[0] >= -1.0f && (eci)->pos[0] <= 1.0f && (eci)->pos[1] >= -1.0f && \
+ (eci)->pos[1] <= 1.0f)
+
+void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
+{
+ LineartEdgeChain *ec;
+ LineartEdgeChainItem *eci, *next_eci, *prev_eci, *new_eci;
+ bool is_inside, new_inside;
+ ListBase swap = {0};
+ swap.first = rb->chains.first;
+ swap.last = rb->chains.last;
+
+ rb->chains.last = rb->chains.first = NULL;
+ while ((ec = BLI_pophead(&swap)) != NULL) {
+ bool ec_added = false;
+ LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
+ is_inside = LRT_ECI_INSIDE(first_eci) ? true : false;
+ if (!is_inside) {
+ ec->picked = true;
+ }
+ for (eci = first_eci->next; eci; eci = next_eci) {
+ next_eci = eci->next;
+ prev_eci = eci->prev;
+
+ /* We only need to do something if the edge crossed from outside to the inside or from inside
+ * to the outside. */
+ if ((new_inside = LRT_ECI_INSIDE(eci)) != is_inside) {
+ if (new_inside == false) {
+ /* Stroke goes out. */
+ new_eci = lineart_chain_create_crossing_point(rb, prev_eci, eci);
+
+ LineartEdgeChain *new_ec = lineart_mem_acquire(rb->chain_data_pool,
+ sizeof(LineartEdgeChain));
+ memcpy(new_ec, ec, sizeof(LineartEdgeChain));
+ new_ec->chain.first = next_eci;
+ eci->prev = NULL;
+ prev_eci->next = NULL;
+ ec->chain.last = prev_eci;
+ BLI_addtail(&ec->chain, new_eci);
+ BLI_addtail(&rb->chains, ec);
+ ec_added = true;
+ ec = new_ec;
+
+ next_eci = eci->next;
+ is_inside = new_inside;
+ continue;
+ }
+ /* Stroke comes in. */
+ new_eci = lineart_chain_create_crossing_point(rb, eci, prev_eci);
+
+ ec->chain.first = eci;
+ eci->prev = NULL;
+
+ BLI_addhead(&ec->chain, new_eci);
+
+ ec_added = false;
+
+ next_eci = eci->next;
+ is_inside = new_inside;
+ continue;
+ }
+ }
+
+ if ((!ec_added) && is_inside) {
+ BLI_addtail(&rb->chains, ec);
+ }
+ }
+}
+
/**
* This should always be the last stage!, see the end of
* #MOD_lineart_chain_split_for_fixed_occlusion().
@@ -1008,3 +1123,45 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
}
}
}
+
+void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
+ float dist,
+ bool use_custom_camera)
+{
+ float dir[3];
+ float cam[3];
+ float view[3];
+ float view_clamp[3];
+ copy_v3fl_v3db(cam, rb->camera_pos);
+ copy_v3fl_v3db(view, rb->view_vector);
+
+ if (use_custom_camera) {
+ copy_v3fl_v3db(cam, rb->camera_pos);
+ }
+ else {
+ copy_v3fl_v3db(cam, rb->active_camera_pos);
+ }
+
+ if (rb->cam_is_persp) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
+ sub_v3_v3v3(dir, cam, eci->gpos);
+ float orig_len = len_v3(dir);
+ normalize_v3(dir);
+ mul_v3_fl(dir, MIN2(dist, orig_len - rb->near_clip));
+ add_v3_v3(eci->gpos, dir);
+ }
+ }
+ }
+ else {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
+ sub_v3_v3v3(dir, cam, eci->gpos);
+ float len_lim = dot_v3v3(view, dir) - rb->near_clip;
+ normalize_v3_v3(view_clamp, view);
+ mul_v3_fl(view_clamp, MIN2(dist, len_lim));
+ add_v3_v3(eci->gpos, view_clamp);
+ }
+ }
+ }
+}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 6660da79b40..93e9062e910 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -2998,7 +2998,7 @@ void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
}
}
-static LineartCache *lineart_init_cache()
+static LineartCache *lineart_init_cache(void)
{
LineartCache *lc = MEM_callocN(sizeof(LineartCache), "Lineart Cache");
return lc;
@@ -3016,6 +3016,8 @@ void MOD_lineart_clear_cache(struct LineartCache **lc)
static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
LineartGpencilModifierData *lmd,
+ Object *camera,
+ Object *active_camera,
LineartCache *lc)
{
LineartRenderBuffer *rb = MEM_callocN(sizeof(LineartRenderBuffer), "Line Art render buffer");
@@ -3024,10 +3026,10 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
lmd->render_buffer_ptr = rb;
lc->rb_edge_types = lmd->edge_types_override;
- if (!scene || !scene->camera || !lc) {
+ if (!scene || !camera || !lc) {
return NULL;
}
- Camera *c = scene->camera->data;
+ Camera *c = camera->data;
double clipping_offset = 0;
if (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) {
@@ -3035,8 +3037,11 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
clipping_offset = 0.0001;
}
- copy_v3db_v3fl(rb->camera_pos, scene->camera->obmat[3]);
- copy_m4_m4(rb->cam_obmat, scene->camera->obmat);
+ copy_v3db_v3fl(rb->camera_pos, camera->obmat[3]);
+ if (active_camera) {
+ copy_v3db_v3fl(rb->active_camera_pos, active_camera->obmat[3]);
+ }
+ copy_m4_m4(rb->cam_obmat, camera->obmat);
rb->cam_is_persp = (c->type == CAM_PERSP);
rb->near_clip = c->clip_start + clipping_offset;
rb->far_clip = c->clip_end - clipping_offset;
@@ -3072,6 +3077,8 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->use_loose_as_contour = (lmd->calculation_flags & LRT_LOOSE_AS_CONTOUR) != 0;
rb->use_loose_edge_chain = (lmd->calculation_flags & LRT_CHAIN_LOOSE_EDGES) != 0;
rb->use_geometry_space_chain = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0;
+ rb->use_image_boundary_trimming = (lmd->calculation_flags & LRT_USE_IMAGE_BOUNDARY_TRIMMING) !=
+ 0;
/* See lineart_edge_from_triangle() for how this option may impact performance. */
rb->allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0;
@@ -4076,11 +4083,13 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
*/
bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
LineartGpencilModifierData *lmd,
- LineartCache **cached_result)
+ LineartCache **cached_result,
+ bool enable_stroke_depth_offset)
{
LineartRenderBuffer *rb;
Scene *scene = DEG_get_evaluated_scene(depsgraph);
int intersections_only = 0; /* Not used right now, but preserve for future. */
+ Object *use_camera;
double t_start;
@@ -4090,14 +4099,24 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
BKE_scene_camera_switch_update(scene);
- if (!scene->camera) {
- return false;
+ if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA) {
+ if (!lmd->source_camera ||
+ (use_camera = DEG_get_evaluated_object(depsgraph, lmd->source_camera))->type !=
+ OB_CAMERA) {
+ return false;
+ }
+ }
+ else {
+ if (!scene->camera) {
+ return false;
+ }
+ use_camera = scene->camera;
}
LineartCache *lc = lineart_init_cache();
*cached_result = lc;
- rb = lineart_create_render_buffer(scene, lmd, lc);
+ rb = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc);
/* Triangle thread testing data size varies depending on the thread count.
* See definition of LineartTriangleThread for details. */
@@ -4117,7 +4136,7 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
/* Get view vector before loading geometries, because we detect feature lines there. */
lineart_main_get_view_vector(rb);
lineart_main_load_geometries(
- depsgraph, scene, scene->camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
+ depsgraph, scene, use_camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
if (!rb->vertex_buffer_pointers.first) {
/* No geometry loaded, return early. */
@@ -4185,10 +4204,19 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50);
}
+ if (rb->use_image_boundary_trimming) {
+ MOD_lineart_chain_clip_at_border(rb);
+ }
+
if (rb->angle_splitting_threshold > FLT_EPSILON) {
MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold);
}
+ if (enable_stroke_depth_offset && lmd->stroke_depth_offset > FLT_EPSILON) {
+ MOD_lineart_chain_offset_towards_camera(
+ rb, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
+ }
+
/* Finally transfer the result list into cache. */
memcpy(&lc->chains, &rb->chains, sizeof(ListBase));
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
index 988c90483a6..b74499daf6b 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
@@ -118,12 +118,12 @@ static bool bake_strokes(Object *ob,
}
LineartCache *local_lc = *lc;
if (!(*lc)) {
- MOD_lineart_compute_feature_lines(dg, lmd, lc);
+ MOD_lineart_compute_feature_lines(dg, lmd, lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
MOD_lineart_destroy_render_data(lmd);
}
else {
if (is_first || (!(lmd->flags & LRT_GPENCIL_USE_CACHE))) {
- MOD_lineart_compute_feature_lines(dg, lmd, &local_lc);
+ MOD_lineart_compute_feature_lines(dg, lmd, &local_lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
MOD_lineart_destroy_render_data(lmd);
}
MOD_lineart_chain_clear_picked_flag(local_lc);
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 018e192bf37..911c8cc2e42 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -32,7 +32,7 @@
#include "GPU_shader.h"
#include "GPU_vertex_buffer.h"
-#define GPU_BATCH_VBO_MAX_LEN 6
+#define GPU_BATCH_VBO_MAX_LEN 16
#define GPU_BATCH_INST_VBO_MAX_LEN 2
#define GPU_BATCH_VAO_STATIC_LEN 3
#define GPU_BATCH_VAO_DYN_ALLOC_COUNT 16
@@ -54,11 +54,11 @@ typedef enum eGPUBatchFlag {
GPU_BATCH_OWNS_INDEX = (GPU_BATCH_OWNS_INST_VBO_MAX << 1),
/** Has been initialized. At least one VBO is set. */
- GPU_BATCH_INIT = (1 << 16),
+ GPU_BATCH_INIT = (1 << 26),
/** Batch is initialized but its VBOs are still being populated. (optional) */
- GPU_BATCH_BUILDING = (1 << 16),
+ GPU_BATCH_BUILDING = (1 << 26),
/** Cached data need to be rebuild. (VAO, PSO, ...) */
- GPU_BATCH_DIRTY = (1 << 17),
+ GPU_BATCH_DIRTY = (1 << 27),
} eGPUBatchFlag;
#define GPU_BATCH_OWNS_NONE GPU_BATCH_INVALID
diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h
index 3ea809d59a7..0d3d39839b2 100644
--- a/source/blender/gpu/GPU_immediate_util.h
+++ b/source/blender/gpu/GPU_immediate_util.h
@@ -78,8 +78,12 @@ void imm_draw_box_checker_2d_ex(float x1,
int checker_size);
void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2);
-void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]);
-void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3]);
+void imm_draw_cube_fill_3d(uint pos, const float center[3], const float aspect[3]);
+void imm_draw_cube_wire_3d(uint pos, const float center[3], const float aspect[3]);
+void imm_draw_cube_corners_3d(uint pos,
+ const float center[3],
+ const float aspect[3],
+ const float factor);
void imm_draw_cylinder_fill_normal_3d(
uint pos, uint nor, float base, float top, float height, int slices, int stacks);
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index d18dc862ce7..032974db8d1 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -391,12 +391,12 @@ void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2)
imm_draw_box_checker_2d_ex(x1, y1, x2, y2, checker_primary, checker_secondary, checker_size);
}
-void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3])
+void imm_draw_cube_fill_3d(uint pos, const float center[3], const float aspect[3])
{
float coords[ARRAY_SIZE(cube_coords)][3];
for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) {
- madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect);
+ madd_v3_v3v3v3(coords[i], center, cube_coords[i], aspect);
}
immBegin(GPU_PRIM_TRIS, ARRAY_SIZE(cube_quad_index) * 3 * 2);
@@ -412,12 +412,12 @@ void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3])
immEnd();
}
-void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3])
+void imm_draw_cube_wire_3d(uint pos, const float center[3], const float aspect[3])
{
float coords[ARRAY_SIZE(cube_coords)][3];
for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) {
- madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect);
+ madd_v3_v3v3v3(coords[i], center, cube_coords[i], aspect);
}
immBegin(GPU_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 2);
@@ -428,6 +428,36 @@ void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3])
immEnd();
}
+void imm_draw_cube_corners_3d(uint pos,
+ const float center[3],
+ const float aspect[3],
+ const float factor)
+{
+ float coords[ARRAY_SIZE(cube_coords)][3];
+
+ for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) {
+ madd_v3_v3v3v3(coords[i], center, cube_coords[i], aspect);
+ }
+
+ immBegin(GPU_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 4);
+ for (int i = 0; i < ARRAY_SIZE(cube_line_index); i++) {
+ float vec[3], co[3];
+ sub_v3_v3v3(vec, coords[cube_line_index[i][1]], coords[cube_line_index[i][0]]);
+ mul_v3_fl(vec, factor);
+
+ copy_v3_v3(co, coords[cube_line_index[i][0]]);
+ immVertex3fv(pos, co);
+ add_v3_v3(co, vec);
+ immVertex3fv(pos, co);
+
+ copy_v3_v3(co, coords[cube_line_index[i][1]]);
+ immVertex3fv(pos, co);
+ sub_v3_v3(co, vec);
+ immVertex3fv(pos, co);
+ }
+ immEnd();
+}
+
/**
* Draw a cylinder. Replacement for gluCylinder.
* _warning_ : Slow, better use it only if you no other choices.
diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h
index f5bdad3e79e..bd604b90b5a 100644
--- a/source/blender/makesdna/DNA_asset_types.h
+++ b/source/blender/makesdna/DNA_asset_types.h
@@ -56,6 +56,9 @@ typedef struct AssetFilterSettings {
* more than that from the file. So pointers to other IDs or ID data are strictly forbidden.
*/
typedef struct AssetMetaData {
+ /** Runtime type, to reference event callbacks. Only valid for local assets. */
+ struct AssetTypeInfo *local_type_info;
+
/** Custom asset meta-data. Cannot store pointers to IDs (#STRUCT_NO_DATABLOCK_IDPROPERTIES)! */
struct IDProperty *properties;
@@ -72,8 +75,12 @@ typedef struct AssetMetaData {
* #catalog_id is updated. */
char catalog_simple_name[64]; /* MAX_NAME */
+ /** Optional name of the author for display in the UI. Dynamic length. */
+ char *author;
+
/** Optional description of this asset for display in the UI. Dynamic length. */
char *description;
+
/** User defined tags for this asset. The asset manager uses these for filtering, but how they
* function exactly (e.g. how they are registered to provide a list of searchable available tags)
* is up to the asset-engine. */
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index 11299ae9717..1ad884bee8f 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -319,6 +319,7 @@
.angle_splitting_threshold = DEG2RAD(60.0f), \
.chaining_image_threshold = 0.001f, \
.chain_smooth_tolerance = 0.2f,\
+ .stroke_depth_offset = 0.05,\
}
#define _DNA_DEFAULT_LengthGpencilModifierData \
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index c7a93080f7c..339714da255 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -978,6 +978,7 @@ typedef enum eLineArtGPencilModifierFlags {
LRT_GPENCIL_BINARY_WEIGHTS = (1 << 2) /* Deprecated, this is removed for lack of use case. */,
LRT_GPENCIL_IS_BAKED = (1 << 3),
LRT_GPENCIL_USE_CACHE = (1 << 4),
+ LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA = (1 << 5),
} eLineArtGPencilModifierFlags;
typedef enum eLineartGpencilMaskSwitches {
@@ -1004,6 +1005,8 @@ typedef struct LineartGpencilModifierData {
short level_start;
short level_end;
+ struct Object *source_camera;
+
struct Object *source_object;
struct Collection *source_collection;
@@ -1042,7 +1045,6 @@ typedef struct LineartGpencilModifierData {
/** Strength for smoothing jagged chains. */
float chain_smooth_tolerance;
- int _pad1;
/* CPU mode */
float chaining_image_threshold;
@@ -1053,6 +1055,9 @@ typedef struct LineartGpencilModifierData {
/* #eLineArtGPencilModifierFlags, modifier internal state. */
int flags;
+ /* Move strokes towards camera to avoid clipping while preserve depth for the viewport. */
+ float stroke_depth_offset;
+
/* Runtime data. */
/* Because we can potentially only compute features lines once per modifier stack (Use Cache), we
diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h
index bdc9bcb6980..d4440592a00 100644
--- a/source/blender/makesdna/DNA_lineart_types.h
+++ b/source/blender/makesdna/DNA_lineart_types.h
@@ -49,6 +49,8 @@ typedef enum eLineartMainFlags {
LRT_ALLOW_OVERLAP_EDGE_TYPES = (1 << 14),
LRT_USE_CREASE_ON_SMOOTH_SURFACES = (1 << 15),
LRT_USE_CREASE_ON_SHARP_EDGES = (1 << 16),
+ LRT_USE_CUSTOM_CAMERA = (1 << 17),
+ LRT_USE_IMAGE_BOUNDARY_TRIMMING = (1 << 20),
} eLineartMainFlags;
typedef enum eLineartEdgeFlag {
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 97f14b2195d..3943c063c39 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -127,6 +127,10 @@ typedef struct Mesh_Runtime {
/** Needed in case we need to lazily initialize the mesh. */
CustomData_MeshMasks cd_mask_extra;
+ /** Needed to ensure some thread-safety during render data pre-processing. */
+ void *render_mutex;
+ void *_pad3;
+
} Mesh_Runtime;
typedef struct Mesh {
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index b585cbd6306..d5d2520ddf6 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1581,6 +1581,16 @@ typedef struct NodeGeometrySeparateGeometry {
int8_t domain;
} NodeGeometrySeparateGeometry;
+typedef struct NodeGeometryImageTexture {
+ int interpolation;
+ int extension;
+} NodeGeometryImageTexture;
+
+typedef struct NodeGeometryViewer {
+ /* CustomDataType. */
+ int8_t data_type;
+} NodeGeometryViewer;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 5a88ce7c9f5..e94541fdc7f 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -501,6 +501,9 @@ enum {
/* check if the object type supports materials */
#define OB_TYPE_SUPPORT_MATERIAL(_type) \
(((_type) >= OB_MESH && (_type) <= OB_MBALL) || ((_type) >= OB_GPENCIL && (_type) <= OB_VOLUME))
+/** Does the object have some render-able geometry (unlike empties, cameras, etc.). */
+#define OB_TYPE_IS_GEOMETRY(_type) \
+ (ELEM(_type, OB_MESH, OB_SURF, OB_FONT, OB_MBALL, OB_GPENCIL, OB_HAIR, OB_POINTCLOUD, OB_VOLUME))
#define OB_TYPE_SUPPORT_VGROUP(_type) (ELEM(_type, OB_MESH, OB_LATTICE, OB_GPENCIL))
#define OB_TYPE_SUPPORT_EDITMODE(_type) \
(ELEM(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE))
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index af01bb76680..fc23d3c69a3 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -179,7 +179,9 @@ typedef struct Sequence {
/** Starting and ending points of the strip in the sequence. */
int startdisp, enddisp;
float sat;
- float mul, handsize;
+ float mul;
+ char tmp_tag;
+ char _pad[3];
short anim_preseek; /* UNUSED. */
/** Streamindex for movie or sound files with several streams. */
@@ -250,7 +252,7 @@ typedef struct Sequence {
/* Multiview */
char views_format;
- char _pad[3];
+ char _pad1[3];
struct Stereo3dFormat *stereo3d_format;
struct IDProperty *prop;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index e24d39b61eb..841edaf8724 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -138,7 +138,14 @@ typedef struct wmWindowManager {
ID id;
/** Separate active from drawable. */
- struct wmWindow *windrawable, *winactive;
+ struct wmWindow *windrawable;
+ /**
+ * \note `CTX_wm_window(C)` is usually preferred.
+ * Avoid relying on this where possible as this may become NULL during when handling
+ * events that close or replace windows (opening a file for e.g.).
+ * While this happens rarely in practice, it can cause difficult to reproduce bugs.
+ */
+ struct wmWindow *winactive;
ListBase windows;
/** Set on file read. */
diff --git a/source/blender/makesdna/DNA_xr_types.h b/source/blender/makesdna/DNA_xr_types.h
index 6f4f7e3e8ae..f7da912f299 100644
--- a/source/blender/makesdna/DNA_xr_types.h
+++ b/source/blender/makesdna/DNA_xr_types.h
@@ -32,8 +32,8 @@ typedef struct XrSessionSettings {
/** Shading settings, struct shared with 3D-View so settings are the same. */
struct View3DShading shading;
- char _pad[7];
-
+ float base_scale;
+ char _pad[3];
char base_pose_type; /* #eXRSessionBasePoseType */
/** Object to take the location and rotation as base position from. */
Object *base_pose_object;
diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c
index 979d0882dd5..5d83da170b5 100644
--- a/source/blender/makesrna/intern/rna_asset.c
+++ b/source/blender/makesrna/intern/rna_asset.c
@@ -139,6 +139,40 @@ static IDProperty **rna_AssetMetaData_idprops(PointerRNA *ptr)
return &asset_data->properties;
}
+static void rna_AssetMetaData_author_get(PointerRNA *ptr, char *value)
+{
+ AssetMetaData *asset_data = ptr->data;
+
+ if (asset_data->author) {
+ strcpy(value, asset_data->author);
+ }
+ else {
+ value[0] = '\0';
+ }
+}
+
+static int rna_AssetMetaData_author_length(PointerRNA *ptr)
+{
+ AssetMetaData *asset_data = ptr->data;
+ return asset_data->author ? strlen(asset_data->author) : 0;
+}
+
+static void rna_AssetMetaData_author_set(PointerRNA *ptr, const char *value)
+{
+ AssetMetaData *asset_data = ptr->data;
+
+ if (asset_data->author) {
+ MEM_freeN(asset_data->author);
+ }
+
+ if (value[0]) {
+ asset_data->author = BLI_strdup(value);
+ }
+ else {
+ asset_data->author = NULL;
+ }
+}
+
static void rna_AssetMetaData_description_get(PointerRNA *ptr, char *value)
{
AssetMetaData *asset_data = ptr->data;
@@ -347,6 +381,14 @@ static void rna_def_asset_data(BlenderRNA *brna)
RNA_def_struct_idprops_func(srna, "rna_AssetMetaData_idprops");
RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); /* Mandatory! */
+ prop = RNA_def_property(srna, "author", PROP_STRING, PROP_NONE);
+ RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable");
+ RNA_def_property_string_funcs(prop,
+ "rna_AssetMetaData_author_get",
+ "rna_AssetMetaData_author_length",
+ "rna_AssetMetaData_author_set");
+ RNA_def_property_ui_text(prop, "Author", "Name of the creator of the asset");
+
prop = RNA_def_property(srna, "description", PROP_STRING, PROP_NONE);
RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable");
RNA_def_property_string_funcs(prop,
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index f1831bca0fe..dbf20896463 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -323,8 +323,10 @@ static void rna_AttributeGroup_next_domain(ID *id,
int(skip)(CollectionPropertyIterator *iter, void *data))
{
do {
- CustomDataLayer *prev_layers = (CustomDataLayer *)iter->internal.array.endptr -
- iter->internal.array.length;
+ CustomDataLayer *prev_layers = (iter->internal.array.endptr == NULL) ?
+ NULL :
+ (CustomDataLayer *)iter->internal.array.endptr -
+ iter->internal.array.length;
CustomData *customdata = BKE_id_attributes_iterator_next_domain(id, prev_layers);
if (customdata == NULL) {
return;
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 631d5822c5e..c4efe5a0ea1 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -1309,7 +1309,7 @@ static void rna_def_modifier_gpencilthick(BlenderRNA *brna)
prop, "Custom Curve", "Use a custom curve to define thickness change along the strokes");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "normalize_thickness", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_normalized_thickness", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_NORMALIZE);
RNA_def_property_ui_text(prop, "Uniform Thickness", "Replace the stroke thickness");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
@@ -1865,7 +1865,7 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "normalize_opacity", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_normalized_opacity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_NORMALIZE);
RNA_def_property_ui_text(prop, "Uniform Opacity", "Replace the stroke opacity");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_opacity_update");
@@ -3073,6 +3073,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_define_lib_overridable(true);
+ prop = RNA_def_property(srna, "use_custom_camera", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_USE_CUSTOM_CAMERA);
+ RNA_def_property_ui_text(
+ prop, "Use Custom Camera", "Use custom camera instead of the active camera");
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "use_fuzzy_intersections", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_INTERSECTION_AS_CONTOUR);
RNA_def_property_ui_text(prop,
@@ -3200,6 +3206,30 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
"separate stroke for each overlapping type");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "stroke_depth_offset", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_ui_text(prop,
+ "Stroke Depth Offset",
+ "Move strokes slightly towards the camera to avoid clipping while "
+ "preserve depth for the viewport");
+ RNA_def_property_ui_range(prop, 0.0, 0.5, 0.001, 4);
+ RNA_def_property_range(prop, -0.1, FLT_MAX);
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_offset_towards_custom_camera", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
+ RNA_def_property_ui_text(prop,
+ "Offset Towards Custom Camera",
+ "Offset strokes towards selected camera instead of the active camera");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "source_camera", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(
+ prop, "Camera Object", "Use specified camera object for generating line art");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
prop = RNA_def_property(srna, "source_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, modifier_lineart_source_type);
RNA_def_property_ui_text(prop, "Source Type", "Line art stroke source type");
@@ -3375,6 +3405,14 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Crease On Sharp Edges", "Allow crease to show on sharp edges");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_image_boundary_trimming", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_USE_IMAGE_BOUNDARY_TRIMMING);
+ RNA_def_property_ui_text(
+ prop,
+ "Image Boundary Trimming",
+ "Trim all edges right at the boundary of image(including overscan region)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
RNA_define_lib_overridable(false);
}
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index f0508ee5317..6a36ef07dee 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2056,7 +2056,8 @@ static bool switch_type_supported(const EnumPropertyItem *item)
SOCK_OBJECT,
SOCK_COLLECTION,
SOCK_TEXTURE,
- SOCK_MATERIAL);
+ SOCK_MATERIAL,
+ SOCK_IMAGE);
}
static const EnumPropertyItem *rna_GeometryNodeSwitch_type_itemf(bContext *UNUSED(C),
@@ -5022,10 +5023,8 @@ static void def_fn_input_bool(StructRNA *srna)
prop = RNA_def_property(srna, "boolean", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "boolean", 1);
- RNA_def_property_ui_text(
- prop, "Boolean", "Input value used for unconnected socket");
+ RNA_def_property_ui_text(prop, "Boolean", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
}
static void def_fn_input_int(StructRNA *srna)
@@ -5037,8 +5036,7 @@ static void def_fn_input_int(StructRNA *srna)
prop = RNA_def_property(srna, "integer", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "integer");
RNA_def_property_int_default(prop, 1);
- RNA_def_property_ui_text(
- prop, "Integer", "Input value used for unconnected socket");
+ RNA_def_property_ui_text(prop, "Integer", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -5416,6 +5414,50 @@ static void def_sh_tex_image(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Node_update");
}
+static void def_geo_image_texture(StructRNA *srna)
+{
+ static const EnumPropertyItem fn_tex_prop_interpolation_items[] = {
+ {SHD_INTERP_LINEAR, "Linear", 0, "Linear", "Linear interpolation"},
+ {SHD_INTERP_CLOSEST, "Closest", 0, "Closest", "No interpolation (sample closest texel)"},
+ {SHD_INTERP_CUBIC, "Cubic", 0, "Cubic", "Cubic interpolation"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem prop_image_extension[] = {
+ {SHD_IMAGE_EXTENSION_REPEAT,
+ "REPEAT",
+ 0,
+ "Repeat",
+ "Cause the image to repeat horizontally and vertically"},
+ {SHD_IMAGE_EXTENSION_EXTEND,
+ "EXTEND",
+ 0,
+ "Extend",
+ "Extend by repeating edge pixels of the image"},
+ {SHD_IMAGE_EXTENSION_CLIP,
+ "CLIP",
+ 0,
+ "Clip",
+ "Clip to image size and set exterior pixels as transparent"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryImageTexture", "storage");
+
+ prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, fn_tex_prop_interpolation_items);
+ RNA_def_property_ui_text(prop, "Interpolation", "Method for smoothing values between pixels");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "extension", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_image_extension);
+ RNA_def_property_ui_text(
+ prop, "Extension", "How the image is extrapolated past its original bounds");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+}
+
static void def_sh_tex_gradient(StructRNA *srna)
{
static const EnumPropertyItem prop_gradient_type[] = {
@@ -10300,12 +10342,12 @@ static void def_geo_volume_to_mesh(StructRNA *srna)
{VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT,
"VOXEL_AMOUNT",
0,
- "Voxel Amount",
+ "Amount",
"Desired number of voxels along one axis"},
{VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE,
"VOXEL_SIZE",
0,
- "Voxel Size",
+ "Size",
"Desired voxel side length"},
{0, NULL, 0, NULL, NULL},
};
@@ -11035,6 +11077,20 @@ static void def_geo_separate_geometry(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_geo_viewer(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryViewer", "storage");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
+ RNA_def_property_ui_text(prop, "Data Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index c91ef25daa8..03976967e9f 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -3074,12 +3074,34 @@ static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bma
PointerRNA *ptr)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data;
- if (sspreadsheet->geometry_component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) {
- sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
- }
- if (sspreadsheet->geometry_component_type == GEO_COMPONENT_TYPE_CURVE &&
- !ELEM(sspreadsheet->attribute_domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) {
- sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
+ switch (sspreadsheet->geometry_component_type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ if (!ELEM(sspreadsheet->attribute_domain,
+ ATTR_DOMAIN_POINT,
+ ATTR_DOMAIN_EDGE,
+ ATTR_DOMAIN_FACE,
+ ATTR_DOMAIN_CORNER)) {
+ sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ if (!ELEM(sspreadsheet->attribute_domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) {
+ sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
+ }
+ break;
+ }
}
}
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index 295ecf590bb..c5569683c9c 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -122,7 +122,8 @@ void RNA_api_space_filebrowser(StructRNA *srna)
PropertyRNA *parm;
func = RNA_def_function(srna, "activate_asset_by_id", "ED_fileselect_activate_by_id");
- RNA_def_function_ui_description(func, "Activate the asset entry that represents the given ID");
+ RNA_def_function_ui_description(
+ func, "Activate and select the asset entry that represents the given ID");
parm = RNA_def_property(func, "id_to_activate", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "ID");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 37d2b711b7d..2514a604087 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2844,7 +2844,7 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "wire_select", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "edge_select");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Wire Select", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
@@ -2911,10 +2911,10 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "grid_levels", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "grid_levels");
- RNA_def_property_int_default(prop, 2);
- RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_int_default(prop, 7);
+ RNA_def_property_range(prop, 0, 9);
RNA_def_property_ui_text(
- prop, "Grid Levels", "Amount of grid lines displayed in the background");
+ prop, "Grid Levels", "Number of subdivisions for the dot grid displayed in the background");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "dash_alpha", PROP_FLOAT, PROP_FACTOR);
diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c
index 826e6d21c36..68f11d71de2 100644
--- a/source/blender/makesrna/intern/rna_world.c
+++ b/source/blender/makesrna/intern/rna_world.c
@@ -128,6 +128,7 @@ static void rna_def_lighting(BlenderRNA *brna)
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "aodist");
+ RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_text(
prop, "Distance", "Length of rays, defines how far away other faces give occlusion effect");
RNA_def_property_update(prop, 0, "rna_World_update");
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index 3705284ca66..dd4cbeac174 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -892,6 +892,71 @@ static void rna_XrSessionState_viewer_pose_rotation_get(PointerRNA *ptr, float *
# endif
}
+static void rna_XrSessionState_nav_location_get(PointerRNA *ptr, float *r_values)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_location_get(xr, r_values);
+# else
+ UNUSED_VARS(ptr);
+ zero_v3(r_values);
+# endif
+}
+
+static void rna_XrSessionState_nav_location_set(PointerRNA *ptr, const float *values)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_location_set(xr, values);
+# else
+ UNUSED_VARS(ptr, values);
+# endif
+}
+
+static void rna_XrSessionState_nav_rotation_get(PointerRNA *ptr, float *r_values)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_rotation_get(xr, r_values);
+# else
+ UNUSED_VARS(ptr);
+ unit_qt(r_values);
+# endif
+}
+
+static void rna_XrSessionState_nav_rotation_set(PointerRNA *ptr, const float *values)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_rotation_set(xr, values);
+# else
+ UNUSED_VARS(ptr, values);
+# endif
+}
+
+static float rna_XrSessionState_nav_scale_get(PointerRNA *ptr)
+{
+ float value;
+# ifdef WITH_XR_OPENXR
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_scale_get(xr, &value);
+# else
+ UNUSED_VARS(ptr);
+ value = 1.0f;
+# endif
+ return value;
+}
+
+static void rna_XrSessionState_nav_scale_set(PointerRNA *ptr, float value)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_scale_set(xr, value);
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
static void rna_XrSessionState_actionmaps_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
@@ -1615,6 +1680,13 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
"Rotation angle around the Z-Axis to apply the rotation deltas from the VR headset to");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+ prop = RNA_def_property(srna, "base_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Base Scale", "Uniform scale to apply to VR view");
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+
prop = RNA_def_property(srna, "show_floor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_SHOW_GRIDFLOOR);
RNA_def_property_ui_text(prop, "Display Grid Floor", "Show the ground plane grid");
@@ -1675,7 +1747,9 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
"rna_XrSessionSettings_use_absolute_tracking_get",
"rna_XrSessionSettings_use_absolute_tracking_set");
RNA_def_property_ui_text(
- prop, "Absolute Tracking", "Use unadjusted location/rotation as defined by the XR runtime");
+ prop,
+ "Absolute Tracking",
+ "Allow the VR tracking origin to be defined independently of the headset location");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
}
@@ -1981,6 +2055,32 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
"Viewer Pose Rotation",
"Last known rotation of the viewer pose (center between the eyes) in world space");
+ prop = RNA_def_property(srna, "navigation_location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_float_funcs(
+ prop, "rna_XrSessionState_nav_location_get", "rna_XrSessionState_nav_location_set", NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Navigation Location",
+ "Location offset to apply to base pose when determining viewer location");
+
+ prop = RNA_def_property(srna, "navigation_rotation", PROP_FLOAT, PROP_QUATERNION);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_float_funcs(
+ prop, "rna_XrSessionState_nav_rotation_get", "rna_XrSessionState_nav_rotation_set", NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Navigation Rotation",
+ "Rotation offset to apply to base pose when determining viewer rotation");
+
+ prop = RNA_def_property(srna, "navigation_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_funcs(
+ prop, "rna_XrSessionState_nav_scale_get", "rna_XrSessionState_nav_scale_set", NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Navigation Scale",
+ "Additional scale multiplier to apply to base scale when determining viewer scale");
+
prop = RNA_def_property(srna, "actionmaps", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop,
"rna_XrSessionState_actionmaps_begin",
diff --git a/source/blender/modifiers/intern/MOD_fluid.c b/source/blender/modifiers/intern/MOD_fluid.c
index a14d582063a..e087b8411f8 100644
--- a/source/blender/modifiers/intern/MOD_fluid.c
+++ b/source/blender/modifiers/intern/MOD_fluid.c
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -112,6 +113,31 @@ static void requiredDataMask(Object *UNUSED(ob),
}
}
+typedef struct FluidIsolationData {
+ Depsgraph *depsgraph;
+ Object *object;
+ Mesh *mesh;
+ FluidModifierData *fmd;
+
+ Mesh *result;
+} FluidIsolationData;
+
+#ifdef WITH_FLUID
+static void fluid_modifier_do_isolated(void *userdata)
+{
+ FluidIsolationData *isolation_data = (FluidIsolationData *)userdata;
+
+ Scene *scene = DEG_get_evaluated_scene(isolation_data->depsgraph);
+
+ Mesh *result = BKE_fluid_modifier_do(isolation_data->fmd,
+ isolation_data->depsgraph,
+ scene,
+ isolation_data->object,
+ isolation_data->mesh);
+ isolation_data->result = result ? result : isolation_data->mesh;
+}
+#endif /* WITH_FLUID */
+
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me)
{
#ifndef WITH_FLUID
@@ -119,16 +145,24 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return me;
#else
FluidModifierData *fmd = (FluidModifierData *)md;
- Mesh *result = NULL;
if (ctx->flag & MOD_APPLY_ORCO) {
return me;
}
- Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
-
- result = BKE_fluid_modifier_do(fmd, ctx->depsgraph, scene, ctx->object, me);
- return result ? result : me;
+ /* Isolate execution of Mantaflow when running from dependency graph. The reason for this is
+ * because Mantaflow uses TBB to parallel its own computation which without isolation will start
+ * stealing tasks from dependency graph. Stealing tasks from the dependency graph might cause
+ * a recursive lock when Python drivers are used (because Mantaflow is interfaced via Python as
+ * well. */
+ FluidIsolationData isolation_data;
+ isolation_data.depsgraph = ctx->depsgraph;
+ isolation_data.object = ctx->object;
+ isolation_data.mesh = me;
+ isolation_data.fmd = fmd;
+ BLI_task_isolate(fluid_modifier_do_isolated, &isolation_data);
+
+ return isolation_data.result;
#endif /* WITH_FLUID */
}
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index e6cc7663c58..c88940c00c2 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -917,6 +917,10 @@ static void store_output_value_in_geometry(GeometrySet &geometry_set,
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
store_field_on_geometry_component(component, attribute_name, domain, field);
}
+ if (geometry_set.has_instances()) {
+ InstancesComponent &component = geometry_set.get_component_for_write<InstancesComponent>();
+ store_field_on_geometry_component(component, attribute_name, domain, field);
+ }
}
/**
@@ -1424,13 +1428,18 @@ static void output_attribute_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, true);
+ bool has_output_attribute = false;
if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->outputs) {
if (socket_type_has_attribute_toggle(*socket)) {
+ has_output_attribute = true;
draw_property_for_output_socket(layout, *nmd, ptr, *socket);
}
}
}
+ if (!has_output_attribute) {
+ uiItemL(layout, IFACE_("No group output attributes connected."), ICON_INFO);
+ }
}
static void panelRegister(ARegionType *region_type)
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index 69132f6c177..a312872f5d9 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -1455,6 +1455,7 @@ class GeometryNodesEvaluator {
}
void *converted_buffer = allocator.allocate(required_type.size(), required_type.alignment());
this->convert_value(type, required_type, buffer, converted_buffer);
+ type.destruct(buffer);
return {required_type, converted_buffer};
}
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 7a728b9041b..f4ca9f51b1b 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -193,6 +193,8 @@ set(SRC
geometry/nodes/legacy/node_geo_raycast.cc
geometry/nodes/legacy/node_geo_select_by_material.cc
geometry/nodes/legacy/node_geo_subdivision_surface.cc
+ geometry/nodes/legacy/node_geo_volume_to_mesh.cc
+
geometry/nodes/node_geo_attribute_capture.cc
geometry/nodes/node_geo_attribute_remove.cc
geometry/nodes/node_geo_attribute_statistic.cc
@@ -226,11 +228,13 @@ set(SRC
geometry/nodes/node_geo_delete_geometry.cc
geometry/nodes/node_geo_distribute_points_on_faces.cc
geometry/nodes/node_geo_edge_split.cc
+ geometry/nodes/node_geo_image_texture.cc
geometry/nodes/node_geo_input_curve_handles.cc
geometry/nodes/node_geo_input_curve_tilt.cc
+ geometry/nodes/node_geo_input_id.cc
geometry/nodes/node_geo_input_index.cc
- geometry/nodes/node_geo_input_material.cc
geometry/nodes/node_geo_input_material_index.cc
+ geometry/nodes/node_geo_input_material.cc
geometry/nodes/node_geo_input_normal.cc
geometry/nodes/node_geo_input_position.cc
geometry/nodes/node_geo_input_radius.cc
@@ -269,8 +273,9 @@ set(SRC
geometry/nodes/node_geo_set_curve_handles.cc
geometry/nodes/node_geo_set_curve_radius.cc
geometry/nodes/node_geo_set_curve_tilt.cc
- geometry/nodes/node_geo_set_material.cc
+ geometry/nodes/node_geo_set_id.cc
geometry/nodes/node_geo_set_material_index.cc
+ geometry/nodes/node_geo_set_material.cc
geometry/nodes/node_geo_set_point_radius.cc
geometry/nodes/node_geo_set_position.cc
geometry/nodes/node_geo_set_shade_smooth.cc
@@ -445,6 +450,7 @@ set(SRC
NOD_shader.h
NOD_socket.h
NOD_socket_declarations.hh
+ NOD_socket_declarations_geometry.hh
NOD_static_types.h
NOD_texture.h
NOD_type_conversions.hh
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index a37dcf28757..ea3458af065 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -29,24 +29,25 @@ void register_node_tree_type_geo(void);
void register_node_type_geo_group(void);
void register_node_type_geo_custom_group(bNodeType *ntype);
-void register_node_type_geo_legacy_attribute_transfer(void);
-void register_node_type_geo_legacy_curve_set_handles(void);
void register_node_type_geo_legacy_attribute_proximity(void);
void register_node_type_geo_legacy_attribute_randomize(void);
+void register_node_type_geo_legacy_attribute_transfer(void);
+void register_node_type_geo_legacy_curve_endpoints(void);
+void register_node_type_geo_legacy_curve_reverse(void);
+void register_node_type_geo_legacy_curve_set_handles(void);
+void register_node_type_geo_legacy_curve_spline_type(void);
+void register_node_type_geo_legacy_curve_subdivide(void);
void register_node_type_geo_legacy_curve_to_points(void);
void register_node_type_geo_legacy_delete_geometry(void);
+void register_node_type_geo_legacy_edge_split(void);
void register_node_type_geo_legacy_material_assign(void);
void register_node_type_geo_legacy_mesh_to_curve(void);
void register_node_type_geo_legacy_points_to_volume(void);
-void register_node_type_geo_legacy_select_by_material(void);
-void register_node_type_geo_legacy_curve_endpoints(void);
-void register_node_type_geo_legacy_curve_spline_type(void);
-void register_node_type_geo_legacy_curve_reverse(void);
+void register_node_type_geo_legacy_raycast(void);
void register_node_type_geo_legacy_select_by_handle_type(void);
-void register_node_type_geo_legacy_curve_subdivide(void);
-void register_node_type_geo_legacy_edge_split(void);
+void register_node_type_geo_legacy_select_by_material(void);
void register_node_type_geo_legacy_subdivision_surface(void);
-void register_node_type_geo_legacy_raycast(void);
+void register_node_type_geo_legacy_volume_to_mesh(void);
void register_node_type_geo_align_rotation_to_vector(void);
void register_node_type_geo_attribute_capture(void);
@@ -94,11 +95,13 @@ void register_node_type_geo_curve_trim(void);
void register_node_type_geo_delete_geometry(void);
void register_node_type_geo_distribute_points_on_faces(void);
void register_node_type_geo_edge_split(void);
+void register_node_type_geo_image_texture(void);
void register_node_type_geo_input_curve_handles(void);
void register_node_type_geo_input_curve_tilt(void);
+void register_node_type_geo_input_id(void);
void register_node_type_geo_input_index(void);
-void register_node_type_geo_input_material(void);
void register_node_type_geo_input_material_index(void);
+void register_node_type_geo_input_material(void);
void register_node_type_geo_input_normal(void);
void register_node_type_geo_input_position(void);
void register_node_type_geo_input_radius(void);
@@ -145,8 +148,9 @@ void register_node_type_geo_separate_geometry(void);
void register_node_type_geo_set_curve_handles(void);
void register_node_type_geo_set_curve_radius(void);
void register_node_type_geo_set_curve_tilt(void);
-void register_node_type_geo_set_material(void);
+void register_node_type_geo_set_id(void);
void register_node_type_geo_set_material_index(void);
+void register_node_type_geo_set_material(void);
void register_node_type_geo_set_point_radius(void);
void register_node_type_geo_set_position(void);
void register_node_type_geo_set_shade_smooth(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 962e1c3c48f..6e1f21dbae0 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -171,10 +171,16 @@ class GeoNodeExecParams {
this->check_input_access(identifier, &CPPType::get<T>());
#endif
GMutablePointer gvalue = this->extract_input(identifier);
- return gvalue.relocate_out<T>();
+ T value = gvalue.relocate_out<T>();
+ if constexpr (std::is_same_v<T, GeometrySet>) {
+ this->check_input_geometry_set(identifier, value);
+ }
+ return value;
}
}
+ void check_input_geometry_set(StringRef identifier, const GeometrySet &geometry_set) const;
+
/**
* Get input as vector for multi input socket with the given identifier.
*
@@ -211,7 +217,11 @@ class GeoNodeExecParams {
#endif
GPointer gvalue = provider_->get_input(identifier);
BLI_assert(gvalue.is_type<T>());
- return *(const T *)gvalue.get();
+ const T &value = *(const T *)gvalue.get();
+ if constexpr (std::is_same_v<T, GeometrySet>) {
+ this->check_input_geometry_set(identifier, value);
+ }
+ return value;
}
}
@@ -335,6 +345,8 @@ class GeoNodeExecParams {
const GeometryComponent &component,
const AttributeDomain default_domain) const;
+ std::string attribute_producer_name() const;
+
private:
/* Utilities for detecting common errors at when using this class. */
void check_input_access(StringRef identifier, const CPPType *requested_type = nullptr) const;
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index 830a7d4070c..2a118057a03 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -76,6 +76,31 @@ class GenericValueLog : public ValueLog {
}
};
+class GFieldValueLog : public ValueLog {
+ private:
+ fn::GField field_;
+ const fn::CPPType &type_;
+ Vector<std::string> input_tooltips_;
+
+ public:
+ GFieldValueLog(fn::GField field, bool log_full_field);
+
+ const fn::GField &field() const
+ {
+ return field_;
+ }
+
+ Span<std::string> input_tooltips() const
+ {
+ return input_tooltips_;
+ }
+
+ const fn::CPPType &type() const
+ {
+ return type_;
+ }
+};
+
struct GeometryAttributeInfo {
std::string name;
AttributeDomain domain;
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index b6e372470c8..e04dd7f41bd 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -200,6 +200,8 @@ class NodeRef : NonCopyable, NonMovable {
PointerRNA *rna() const;
StringRefNull idname() const;
StringRefNull name() const;
+ StringRefNull label() const;
+ StringRefNull label_or_name() const;
bNodeType *typeinfo() const;
const NodeDeclaration *declaration() const;
@@ -285,7 +287,17 @@ class NodeTreeRef : NonCopyable, NonMovable {
RightToLeft,
};
- Vector<const NodeRef *> toposort(ToposortDirection direction) const;
+ struct ToposortResult {
+ Vector<const NodeRef *> sorted_nodes;
+ /**
+ * There can't be a correct topologycal sort of the nodes when there is a cycle. The nodes will
+ * still be sorted to some degree. The caller has to decide whether it can handle non-perfect
+ * sorts or not.
+ */
+ bool has_cycle = false;
+ };
+
+ ToposortResult toposort(ToposortDirection direction) const;
bNodeTree *btree() const;
StringRefNull name() const;
@@ -575,6 +587,20 @@ inline StringRefNull NodeRef::name() const
return bnode_->name;
}
+inline StringRefNull NodeRef::label() const
+{
+ return bnode_->label;
+}
+
+inline StringRefNull NodeRef::label_or_name() const
+{
+ const StringRefNull label = this->label();
+ if (!label.is_empty()) {
+ return label;
+ }
+ return this->name();
+}
+
inline bNodeType *NodeRef::typeinfo() const
{
return bnode_->typeinfo;
diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh
index d4958f433d6..f7aea212f73 100644
--- a/source/blender/nodes/NOD_socket_declarations.hh
+++ b/source/blender/nodes/NOD_socket_declarations.hh
@@ -212,14 +212,6 @@ class Image : public IDSocketDeclaration {
Image();
};
-class Geometry : public SocketDeclaration {
- public:
- using Builder = SocketDeclarationBuilder<Geometry>;
-
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
- bool matches(const bNodeSocket &socket) const override;
-};
-
/* -------------------------------------------------------------------- */
/** \name #FloatBuilder Inline Methods
* \{ */
@@ -396,9 +388,7 @@ MAKE_EXTERN_SOCKET_DECLARATION(decl::Vector)
MAKE_EXTERN_SOCKET_DECLARATION(decl::Bool)
MAKE_EXTERN_SOCKET_DECLARATION(decl::Color)
MAKE_EXTERN_SOCKET_DECLARATION(decl::String)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Geometry)
-#undef MAKE_EXTERN_SOCKET_DECLARATION
} // namespace blender::nodes
/** \} */
diff --git a/source/blender/nodes/NOD_socket_declarations_geometry.hh b/source/blender/nodes/NOD_socket_declarations_geometry.hh
new file mode 100644
index 00000000000..1531f82d67d
--- /dev/null
+++ b/source/blender/nodes/NOD_socket_declarations_geometry.hh
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BKE_geometry_set.hh"
+
+#include "NOD_socket_declarations.hh"
+
+namespace blender::nodes::decl {
+
+class GeometryBuilder;
+
+class Geometry : public SocketDeclaration {
+ private:
+ blender::Vector<GeometryComponentType> supported_types_;
+ bool only_realized_data_ = false;
+ bool only_instances_ = false;
+
+ friend GeometryBuilder;
+
+ public:
+ using Builder = GeometryBuilder;
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bool matches(const bNodeSocket &socket) const override;
+
+ Span<GeometryComponentType> supported_types() const;
+ bool only_realized_data() const;
+ bool only_instances() const;
+};
+
+class GeometryBuilder : public SocketDeclarationBuilder<Geometry> {
+ public:
+ GeometryBuilder &supported_type(GeometryComponentType supported_type);
+ GeometryBuilder &supported_type(blender::Vector<GeometryComponentType> supported_types);
+ GeometryBuilder &only_realized_data(bool value = true);
+ GeometryBuilder &only_instances(bool value = true);
+};
+
+} // namespace blender::nodes::decl
+
+namespace blender::nodes {
+MAKE_EXTERN_SOCKET_DECLARATION(decl::Geometry)
+}
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index af14538e6cc..20ad4d359f1 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -321,21 +321,18 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_POINTS_TO_VOLUME, def_geo_legacy_points_to
DefNode(GeometryNode, GEO_NODE_LEGACY_RAYCAST, def_geo_legacy_raycast, "LEGACY_RAYCAST", LegacyRaycast, "Raycast", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, 0, "LEGACY_SELECT_BY_MATERIAL", LegacySelectByMaterial, "Select by Material", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "LEGACY_SUBDIVISION_SURFACE", LegacySubdivisionSurface, "Subdivision Surface", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "LEGACY_VOLUME_TO_MESH", LegacyVolumeToMesh, "Volume to Mesh", "")
-DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "")
-DefNode(GeometryNode, GEO_NODE_MESH_BOOLEAN, def_geo_boolean, "MESH_BOOLEAN", MeshBoolean, "Mesh Boolean", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
+DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Convex Hull", "")
DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINT_SELECTION, 0, "CURVE_ENDPOINT_SELECTION", CurveEndpointSelection, "Endpoint Selection", "")
-DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "")
-DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "")
DefNode(GeometryNode, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, def_geo_curve_handle_type_selection, "CURVE_HANDLE_TYPE_SELECTION", CurveHandleTypeSelection, "Handle Type Selection", "")
DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PARAMETER, 0, "CURVE_PARAMETER", CurveParameter, "Curve Parameter", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "")
@@ -343,22 +340,21 @@ DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, 0, "CURVE_PRIMI
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_primitive_quadrilateral, "CURVE_PRIMITIVE_QUADRILATERAL", CurvePrimitiveQuadrilateral, "Quadrilateral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "")
-DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE_CURVE", ResampleCurve, "Resample Curve", "")
-DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "")
-DefNode(GeometryNode, GEO_NODE_SAMPLE_CURVE, def_geo_curve_sample, "SAMPLE_CURVE", SampleCurve, "Sample Curve", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "")
-DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_CURVE, 0, "SUBDIVIDE_CURVE", SubdivideCurve, "Subdivide Curve", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "")
-DefNode(GeometryNode, GEO_NODE_TRIM_CURVE, def_geo_curve_trim, "TRIM_CURVE", TrimCurve, "Trim Curve", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "")
-DefNode(GeometryNode, GEO_NODE_SPLIT_EDGES, 0, "SPLIT_EDGES", SplitEdges, "Split Edges", "")
+DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "")
+DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "")
+DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "")
DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", InputCurveHandlePositions, "Curve Handle Positions", "")
DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "")
DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "")
-DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
DefNode(GeometryNode, GEO_NODE_INPUT_NORMAL, 0, "INPUT_NORMAL", InputNormal, "Normal", "")
DefNode(GeometryNode, GEO_NODE_INPUT_POSITION, 0, "POSITION", InputPosition, "Position", "")
DefNode(GeometryNode, GEO_NODE_INPUT_RADIUS, 0, "INPUT_RADIUS", InputRadius, "Radius", "")
@@ -371,8 +367,8 @@ DefNode(GeometryNode, GEO_NODE_INSTANCE_ON_POINTS, 0, "INSTANCE_ON_POINTS", Inst
DefNode(GeometryNode, GEO_NODE_INSTANCES_TO_POINTS, 0, "INSTANCES_TO_POINTS", InstancesToPoints, "Instances to Points", "")
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
-DefNode(GeometryNode, GEO_NODE_REPLACE_MATERIAL, 0, "REPLACE_MATERIAL", ReplaceMaterial, "Replace Material", "")
DefNode(GeometryNode, GEO_NODE_MATERIAL_SELECTION, 0, "MATERIAL_SELECTION", MaterialSelection, "Material Selection", "")
+DefNode(GeometryNode, GEO_NODE_MESH_BOOLEAN, def_geo_boolean, "MESH_BOOLEAN", MeshBoolean, "Mesh Boolean", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Mesh Circle", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE", MeshCube, "Cube", "")
@@ -381,7 +377,6 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID", Me
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Mesh Line", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
-DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_MESH, 0, "SUBDIVIDE_MESH", SubdivideMesh, "Subdivide Mesh", "")
DefNode(GeometryNode, GEO_NODE_MESH_TO_CURVE, 0, "MESH_TO_CURVE", MeshToCurve, "Mesh to Curve", "")
DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, def_geo_mesh_to_points, "MESH_TO_POINTS", MeshToPoints, "Mesh to Points", "")
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
@@ -390,29 +385,38 @@ DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POIN
DefNode(GeometryNode, GEO_NODE_PROXIMITY, def_geo_proximity, "PROXIMITY", Proximity, "Geometry Proximity", "")
DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "")
DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, 0, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "")
+DefNode(GeometryNode, GEO_NODE_REPLACE_MATERIAL, 0, "REPLACE_MATERIAL", ReplaceMaterial, "Replace Material", "")
+DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE_CURVE", ResampleCurve, "Resample Curve", "")
+DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "")
DefNode(GeometryNode, GEO_NODE_ROTATE_INSTANCES, 0, "ROTATE_INSTANCES", RotateInstances, "Rotate Instances", "")
+DefNode(GeometryNode, GEO_NODE_SAMPLE_CURVE, def_geo_curve_sample, "SAMPLE_CURVE", SampleCurve, "Sample Curve", "")
DefNode(GeometryNode, GEO_NODE_SCALE_INSTANCES, 0, "SCALE_INSTANCES", ScaleInstances, "Scale Instances", "")
DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS", SeparateComponents, "Separate Components", "")
DefNode(GeometryNode, GEO_NODE_SEPARATE_GEOMETRY, def_geo_separate_geometry, "SEPARATE_GEOMETRY", SeparateGeometry, "Separate Geometry", "")
DefNode(GeometryNode, GEO_NODE_SET_CURVE_HANDLES, def_geo_curve_set_handle_positions, "SET_CURVE_HANDLES", SetCurveHandlePositions, "Set Handle Positions", "")
DefNode(GeometryNode, GEO_NODE_SET_CURVE_RADIUS, 0, "SET_CURVE_RADIUS", SetCurveRadius, "Set Curve Radius", "")
DefNode(GeometryNode, GEO_NODE_SET_CURVE_TILT, 0, "SET_CURVE_TILT", SetCurveTilt, "Set Curve Tilt", "")
-DefNode(GeometryNode, GEO_NODE_SET_MATERIAL, 0, "SET_MATERIAL", SetMaterial, "Set Material", "")
+DefNode(GeometryNode, GEO_NODE_SET_ID, 0, "SET_ID", SetID, "Set ID", "")
DefNode(GeometryNode, GEO_NODE_SET_MATERIAL_INDEX, 0, "SET_MATERIAL_INDEX", SetMaterialIndex, "Set Material Index", "")
+DefNode(GeometryNode, GEO_NODE_SET_MATERIAL, 0, "SET_MATERIAL", SetMaterial, "Set Material", "")
DefNode(GeometryNode, GEO_NODE_SET_POINT_RADIUS, 0, "SET_POINT_RADIUS", SetPointRadius, "Set Point Radius", "")
DefNode(GeometryNode, GEO_NODE_SET_POSITION, 0, "SET_POSITION", SetPosition, "Set Position", "")
DefNode(GeometryNode, GEO_NODE_SET_SHADE_SMOOTH, 0, "SET_SHADE_SMOOTH", SetShadeSmooth, "Set Shade Smooth", "")
DefNode(GeometryNode, GEO_NODE_SET_SPLINE_CYCLIC, 0, "SET_SPLINE_CYCLIC", SetSplineCyclic, "Set Spline Cyclic", "")
DefNode(GeometryNode, GEO_NODE_SET_SPLINE_RESOLUTION, 0, "SET_SPLINE_RESOLUTION", SetSplineResolution, "Set Spline Resolution", "")
+DefNode(GeometryNode, GEO_NODE_SPLIT_EDGES, 0, "SPLIT_EDGES", SplitEdges, "Split Edges", "")
DefNode(GeometryNode, GEO_NODE_STRING_JOIN, 0, "STRING_JOIN", StringJoin, "Join Strings", "")
DefNode(GeometryNode, GEO_NODE_STRING_TO_CURVES, def_geo_string_to_curves, "STRING_TO_CURVES", StringToCurves, "String to Curves", "")
+DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_CURVE, 0, "SUBDIVIDE_CURVE", SubdivideCurve, "Subdivide Curve", "")
+DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_MESH, 0, "SUBDIVIDE_MESH", SubdivideMesh, "Subdivide Mesh", "")
DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "")
DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "")
DefNode(GeometryNode, GEO_NODE_TRANSFER_ATTRIBUTE, def_geo_transfer_attribute, "ATTRIBUTE_TRANSFER", AttributeTransfer, "Transfer Attribute", "")
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
DefNode(GeometryNode, GEO_NODE_TRANSLATE_INSTANCES, 0, "TRANSLATE_INSTANCES", TranslateInstances, "Translate Instances", "")
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
-DefNode(GeometryNode, GEO_NODE_VIEWER, 0, "VIEWER", Viewer, "Viewer", "")
+DefNode(GeometryNode, GEO_NODE_TRIM_CURVE, def_geo_curve_trim, "TRIM_CURVE", TrimCurve, "Trim Curve", "")
+DefNode(GeometryNode, GEO_NODE_VIEWER, def_geo_viewer, "VIEWER", Viewer, "Viewer", "")
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
/* undefine macros */
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
index 3a4bf94d256..3f8a7606d94 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
@@ -29,7 +29,7 @@ namespace blender::nodes {
static void cmp_node_bokehimage_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Color>("Image");
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.cc b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
index ad4b09c69d0..028afad3cf8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
@@ -29,10 +29,10 @@ namespace blender::nodes {
static void cmp_node_brightcontrast_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Bright").min(-100.0f).max(100.0f);
- b.add_input<decl::Float>("Contrast").min(-100.0f).max(100.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Bright")).min(-100.0f).max(100.0f);
+ b.add_input<decl::Float>(N_("Contrast")).min(-100.0f).max(100.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
index 440e37fe741..ef8af5f81a6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void cmp_node_colorbalance_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
index 0682c66f1e8..095fbef826a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void cmp_node_colorcorrection_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Mask").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Mask")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc
index 170fecb251c..4247e81e9b2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_composite.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void cmp_node_composite_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({0.0f, 0.0f, 0.0f, 1.0f});
- b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_input<decl::Float>("Z").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Color>(N_("Image")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Alpha")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(1.0f);
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc
index 88d96e1ca4a..5f99bb57768 100644
--- a/source/blender/nodes/composite/nodes/node_composite_curves.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc
@@ -29,7 +29,7 @@ namespace blender::nodes {
static void cmp_node_time_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Fac");
+ b.add_output<decl::Float>(N_("Fac"));
}
} // namespace blender::nodes
@@ -90,11 +90,12 @@ namespace blender::nodes {
static void cmp_node_rgbcurves_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(-1.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Color>("Black Level").default_value({0.0f, 0.0f, 0.0f, 1.0f});
- b.add_input<decl::Color>("White Level").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(-1.0f).max(1.0f).subtype(
+ PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Black Level")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Color>(N_("White Level")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.cc b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
index fd959376afe..c1e64065f7e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_exposure.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void cmp_node_exposure_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Exposure").min(-10.0f).max(10.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Exposure")).min(-10.0f).max(10.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.cc b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
index a29a001688a..74152a27485 100644
--- a/source/blender/nodes/composite/nodes/node_composite_gamma.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
@@ -29,10 +29,13 @@ namespace blender::nodes {
static void cmp_node_gamma_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Gamma").default_value(1.0f).min(0.001f).max(10.0f).subtype(
- PROP_UNSIGNED);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Gamma"))
+ .default_value(1.0f)
+ .min(0.001f)
+ .max(10.0f)
+ .subtype(PROP_UNSIGNED);
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
index 07746918a94..21430035465 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
@@ -29,16 +29,20 @@ namespace blender::nodes {
static void cmp_node_huesatval_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Hue").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Saturation")
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Hue")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Saturation"))
.default_value(1.0f)
.min(0.0f)
.max(2.0f)
.subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Value").default_value(1.0f).min(0.0f).max(2.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Value"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(2.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
index 39014896a7b..83743bbed18 100644
--- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
@@ -27,9 +27,9 @@ namespace blender::nodes {
static void cmp_node_huecorrect_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.cc b/source/blender/nodes/composite/nodes/node_composite_idMask.cc
index de011dd6274..5121370567c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_idMask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_idMask.cc
@@ -29,8 +29,8 @@ namespace blender::nodes {
static void cmp_node_idmask_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("ID value").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_output<decl::Float>("Alpha");
+ b.add_input<decl::Float>(N_("ID value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Alpha"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.cc b/source/blender/nodes/composite/nodes/node_composite_invert.cc
index 57b7ed36ccd..dabf0452628 100644
--- a/source/blender/nodes/composite/nodes/node_composite_invert.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void cmp_node_invert_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Color");
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Color"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.cc b/source/blender/nodes/composite/nodes/node_composite_levels.cc
index aaab8dcc874..54064f24e0d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_levels.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void cmp_node_levels_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({0.0f, 0.0f, 0.0f, 1.0f});
- b.add_output<decl::Float>("Mean");
- b.add_output<decl::Float>("Std Dev");
+ b.add_input<decl::Color>(N_("Image")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Mean"));
+ b.add_output<decl::Float>(N_("Std Dev"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.cc b/source/blender/nodes/composite/nodes/node_composite_mask.cc
index 8b415bb8b63..6428fadaa5f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mask.cc
@@ -31,7 +31,7 @@ namespace blender::nodes {
static void cmp_node_mask_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Mask");
+ b.add_output<decl::Float>(N_("Mask"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
index ae91212f811..5d63a1b8002 100644
--- a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
@@ -30,12 +30,12 @@ namespace blender::nodes {
static void cmp_node_movieclip_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Color>("Image");
- b.add_output<decl::Float>("Alpha");
- b.add_output<decl::Float>("Offset X");
- b.add_output<decl::Float>("Offset Y");
- b.add_output<decl::Float>("Scale");
- b.add_output<decl::Float>("Angle");
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Alpha"));
+ b.add_output<decl::Float>(N_("Offset X"));
+ b.add_output<decl::Float>(N_("Offset Y"));
+ b.add_output<decl::Float>(N_("Scale"));
+ b.add_output<decl::Float>(N_("Angle"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
index e557854c611..49068429a8d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
@@ -29,8 +29,8 @@ namespace blender::nodes {
static void cmp_node_premulkey_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
index 332e56e26b1..abe69d6a756 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
@@ -29,7 +29,7 @@ namespace blender::nodes {
static void cmp_node_rgb_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Color>("RGBA").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_output<decl::Color>(N_("RGBA")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
index aa719a99b36..83c54069658 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
@@ -29,11 +29,11 @@ namespace blender::nodes {
static void cmp_node_sephsva_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Float>("H");
- b.add_output<decl::Float>("S");
- b.add_output<decl::Float>("V");
- b.add_output<decl::Float>("A");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("H"));
+ b.add_output<decl::Float>(N_("S"));
+ b.add_output<decl::Float>(N_("V"));
+ b.add_output<decl::Float>(N_("A"));
}
} // namespace blender::nodes
@@ -53,11 +53,11 @@ namespace blender::nodes {
static void cmp_node_combhsva_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("H").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("S").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("V").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("A").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("H")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("S")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("V")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("A")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
index b29af1359f5..049e798af0a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
@@ -28,11 +28,11 @@ namespace blender::nodes {
static void cmp_node_seprgba_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Float>("R");
- b.add_output<decl::Float>("G");
- b.add_output<decl::Float>("B");
- b.add_output<decl::Float>("A");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("R"));
+ b.add_output<decl::Float>(N_("G"));
+ b.add_output<decl::Float>(N_("B"));
+ b.add_output<decl::Float>(N_("A"));
}
} // namespace blender::nodes
@@ -53,11 +53,11 @@ namespace blender::nodes {
static void cmp_node_combrgba_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("R").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("G").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("B").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("A").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("R")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("G")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("B")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("A")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
index 526d6b4eb5b..eaf6ba5e9b2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
@@ -29,11 +29,11 @@ namespace blender::nodes {
static void cmp_node_sepycca_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Float>("Y");
- b.add_output<decl::Float>("Cb");
- b.add_output<decl::Float>("Cr");
- b.add_output<decl::Float>("A");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Y"));
+ b.add_output<decl::Float>(N_("Cb"));
+ b.add_output<decl::Float>(N_("Cr"));
+ b.add_output<decl::Float>(N_("A"));
}
} // namespace blender::nodes
@@ -60,11 +60,11 @@ namespace blender::nodes {
static void cmp_node_combycca_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Y").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("Cb").default_value(0.5f).min(0.0f).max(1.0f);
- b.add_input<decl::Float>("Cr").default_value(0.5f).min(0.0f).max(1.0f);
- b.add_input<decl::Float>("A").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Y")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Cb")).default_value(0.5f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Cr")).default_value(0.5f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("A")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
index 4619b0c97f1..bc7710122d1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
@@ -29,11 +29,11 @@ namespace blender::nodes {
static void cmp_node_sepyuva_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Float>("Y");
- b.add_output<decl::Float>("U");
- b.add_output<decl::Float>("V");
- b.add_output<decl::Float>("A");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Y"));
+ b.add_output<decl::Float>(N_("U"));
+ b.add_output<decl::Float>(N_("V"));
+ b.add_output<decl::Float>(N_("A"));
}
} // namespace blender::nodes
@@ -54,11 +54,11 @@ namespace blender::nodes {
static void cmp_node_combyuva_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Y").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("U").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("V").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("A").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Y")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("U")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("V")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("A")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
index 07a7ffcb426..f59ba76f0c5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void cmp_node_setalpha_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Alpha")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.cc b/source/blender/nodes/composite/nodes/node_composite_texture.cc
index eff008b4b41..55ae6a4185e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_texture.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc
@@ -29,14 +29,14 @@ namespace blender::nodes {
static void cmp_node_texture_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>("Offset").min(-2.0f).max(2.0f).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Scale")
+ b.add_input<decl::Vector>(N_("Offset")).min(-2.0f).max(2.0f).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Scale"))
.default_value({1.0f, 1.0f, 1.0f})
.min(-10.0f)
.max(10.0f)
.subtype(PROP_XYZ);
- b.add_output<decl::Float>("Value");
- b.add_output<decl::Color>("Color");
+ b.add_output<decl::Float>(N_("Value"));
+ b.add_output<decl::Color>(N_("Color"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
index 85fd240ce2e..33d6f98201c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
@@ -27,8 +27,8 @@ namespace blender::nodes {
static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
index cb5c9468daa..537f7e661db 100644
--- a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
@@ -27,9 +27,9 @@ namespace blender::nodes {
static void cmp_node_trackpos_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("X");
- b.add_output<decl::Float>("Y");
- b.add_output<decl::Vector>("Speed").subtype(PROP_VELOCITY);
+ b.add_output<decl::Float>(N_("X"));
+ b.add_output<decl::Float>(N_("Y"));
+ b.add_output<decl::Vector>(N_("Speed")).subtype(PROP_VELOCITY);
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
index 9e4f1329fbd..a0ab056e657 100644
--- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void cmp_node_valtorgb_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_output<decl::Color>("Image");
- b.add_output<decl::Float>("Alpha");
+ b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Alpha"));
}
} // namespace blender::nodes
@@ -60,8 +60,8 @@ namespace blender::nodes {
static void cmp_node_rgbtobw_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_output<decl::Color>("Val");
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Val"));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_value.cc b/source/blender/nodes/composite/nodes/node_composite_value.cc
index 5459801bcc7..51214d23472 100644
--- a/source/blender/nodes/composite/nodes/node_composite_value.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_value.cc
@@ -29,7 +29,7 @@ namespace blender::nodes {
static void cmp_node_value_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Value").default_value(0.5f);
+ b.add_output<decl::Float>(N_("Value")).default_value(0.5f);
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
index 7234d4d8eb2..b86ae57f664 100644
--- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
@@ -32,9 +32,9 @@ namespace blender::nodes {
static void cmp_node_viewer_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({0.0f, 0.0f, 0.0f, 1.0f});
- b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_input<decl::Float>("Z").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Color>(N_("Image")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Alpha")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(1.0f);
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
index 7f6f554ba93..d98d49c7273 100644
--- a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
@@ -23,10 +23,10 @@ namespace blender::nodes {
static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Min").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Max").default_value(1.0f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Int>("Seed").min(-10000).max(10000);
- b.add_output<decl::Float>("Value");
+ b.add_input<decl::Float>(N_("Min")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
+ b.add_output<decl::Float>(N_("Value"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
index ae41cdfca5a..4088fa24ca7 100644
--- a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
+++ b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
@@ -28,10 +28,14 @@ namespace blender::nodes {
static void fn_node_align_euler_to_vector_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER).hide_value();
- b.add_input<decl::Float>("Factor").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Vector>("Vector").default_value({0.0, 0.0, 1.0});
- b.add_output<decl::Vector>("Rotation").subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).hide_value();
+ b.add_input<decl::Float>(N_("Factor"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Vector")).default_value({0.0, 0.0, 1.0});
+ b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
}
static void fn_node_align_euler_to_vector_layout(uiLayout *layout,
diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
index 09caf12e425..b44e8d54ff1 100644
--- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void fn_node_boolean_math_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Bool>("Boolean", "Boolean");
- b.add_input<decl::Bool>("Boolean", "Boolean_001");
- b.add_output<decl::Bool>("Boolean");
+ b.add_input<decl::Bool>(N_("Boolean"), "Boolean");
+ b.add_input<decl::Bool>(N_("Boolean"), "Boolean_001");
+ b.add_output<decl::Bool>(N_("Boolean"));
};
static void fn_node_boolean_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
index bdc4a3c1e02..2e1f2aaeeef 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
@@ -31,10 +31,10 @@ namespace blender::nodes {
static void fn_node_float_compare_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("A").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("B").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Epsilon").default_value(0.001f).min(-10000.0f).max(10000.0f);
- b.add_output<decl::Bool>("Result");
+ b.add_input<decl::Float>(N_("A")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("B")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Epsilon")).default_value(0.001f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Bool>(N_("Result"));
};
static void geo_node_float_compare_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
index 5dccd26158b..e6ec925f945 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
@@ -30,8 +30,8 @@ namespace blender::nodes {
static void fn_node_float_to_int_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Float");
- b.add_output<decl::Int>("Integer");
+ b.add_input<decl::Float>(N_("Float"));
+ b.add_output<decl::Int>(N_("Integer"));
};
static void fn_node_float_to_int_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/function/nodes/node_fn_input_bool.cc b/source/blender/nodes/function/nodes/node_fn_input_bool.cc
index 58f8969f1b6..1358bf8a223 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_bool.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_bool.cc
@@ -25,7 +25,7 @@ namespace blender::nodes {
static void fn_node_input_bool_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Bool>("Boolean");
+ b.add_output<decl::Bool>(N_("Boolean"));
};
static void fn_node_input_bool_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/function/nodes/node_fn_input_color.cc b/source/blender/nodes/function/nodes/node_fn_input_color.cc
index b6079835eae..43bb654b776 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_color.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_color.cc
@@ -23,7 +23,7 @@ namespace blender::nodes {
static void fn_node_input_color_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Color>("Color");
+ b.add_output<decl::Color>(N_("Color"));
};
static void fn_node_input_color_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/function/nodes/node_fn_input_int.cc b/source/blender/nodes/function/nodes/node_fn_input_int.cc
index db52d569ac5..ddbb86e2661 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_int.cc
@@ -25,7 +25,7 @@ namespace blender::nodes {
static void fn_node_input_int_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Int>("Integer");
+ b.add_output<decl::Int>(N_("Integer"));
};
static void fn_node_input_int_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
index 11c64d3f694..c61af419e50 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
@@ -20,8 +20,8 @@ namespace blender::nodes {
static void fn_node_input_special_characters_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::String>("Line Break");
- b.add_output<decl::String>("Tab");
+ b.add_output<decl::String>(N_("Line Break"));
+ b.add_output<decl::String>(N_("Tab"));
};
class MF_SpecialCharacters : public fn::MultiFunction {
diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc
index 0982096eaea..dd2d1292601 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc
@@ -24,7 +24,7 @@ namespace blender::nodes {
static void fn_node_input_string_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_output<decl::String>("String");
+ b.add_output<decl::String>(N_("String"));
};
static void fn_node_input_string_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/function/nodes/node_fn_input_vector.cc b/source/blender/nodes/function/nodes/node_fn_input_vector.cc
index f64fd182282..1e5fd186b5a 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_vector.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc
@@ -25,7 +25,7 @@ namespace blender::nodes {
static void fn_node_input_vector_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Vector");
+ b.add_output<decl::Vector>(N_("Vector"));
};
static void fn_node_input_vector_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc
index 53ca77aab0c..d48b9f3461a 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_value.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -26,29 +26,29 @@ namespace blender::nodes {
static void fn_node_random_value_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>("Min").supports_field();
- b.add_input<decl::Vector>("Max").default_value({1.0f, 1.0f, 1.0f}).supports_field();
- b.add_input<decl::Float>("Min", "Min_001").supports_field();
- b.add_input<decl::Float>("Max", "Max_001").default_value(1.0f).supports_field();
- b.add_input<decl::Int>("Min", "Min_002").min(-100000).max(100000).supports_field();
- b.add_input<decl::Int>("Max", "Max_002")
+ b.add_input<decl::Vector>(N_("Min")).supports_field();
+ b.add_input<decl::Vector>(N_("Max")).default_value({1.0f, 1.0f, 1.0f}).supports_field();
+ b.add_input<decl::Float>(N_("Min"), "Min_001").supports_field();
+ b.add_input<decl::Float>(N_("Max"), "Max_001").default_value(1.0f).supports_field();
+ b.add_input<decl::Int>(N_("Min"), "Min_002").min(-100000).max(100000).supports_field();
+ b.add_input<decl::Int>(N_("Max"), "Max_002")
.default_value(100)
.min(-100000)
.max(100000)
.supports_field();
- b.add_input<decl::Float>("Probability")
+ b.add_input<decl::Float>(N_("Probability"))
.min(0.0f)
.max(1.0f)
.default_value(0.5f)
.subtype(PROP_FACTOR)
.supports_field();
- b.add_input<decl::Int>("ID").implicit_field();
- b.add_input<decl::Int>("Seed").default_value(0).min(-10000).max(10000).supports_field();
+ b.add_input<decl::Int>(N_("ID")).implicit_field();
+ b.add_input<decl::Int>(N_("Seed")).default_value(0).min(-10000).max(10000).supports_field();
- b.add_output<decl::Vector>("Value").dependent_field();
- b.add_output<decl::Float>("Value", "Value_001").dependent_field();
- b.add_output<decl::Int>("Value", "Value_002").dependent_field();
- b.add_output<decl::Bool>("Value", "Value_003").dependent_field();
+ b.add_output<decl::Vector>(N_("Value")).dependent_field();
+ b.add_output<decl::Float>(N_("Value"), "Value_001").dependent_field();
+ b.add_output<decl::Int>(N_("Value"), "Value_002").dependent_field();
+ b.add_output<decl::Bool>(N_("Value"), "Value_003").dependent_field();
}
static void fn_node_random_value_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/function/nodes/node_fn_replace_string.cc b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
index 1ec4979176e..881a3c68e7d 100644
--- a/source/blender/nodes/function/nodes/node_fn_replace_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
@@ -22,10 +22,11 @@ namespace blender::nodes {
static void fn_node_replace_string_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::String>("String");
- b.add_input<decl::String>("Find").description("The string to find in the input string");
- b.add_input<decl::String>("Replace").description("The string to replace each match with");
- b.add_output<decl::String>("String");
+ b.add_input<decl::String>(N_("String"));
+ b.add_input<decl::String>(N_("Find")).description(N_("The string to find in the input string"));
+ b.add_input<decl::String>(N_("Replace"))
+ .description(N_("The string to replace each match with"));
+ b.add_output<decl::String>(N_("String"));
};
static std::string replace_all(std::string str, const std::string &from, const std::string &to)
diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
index a01cc6b58dd..fc4c3d8221f 100644
--- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
+++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
@@ -29,11 +29,11 @@ namespace blender::nodes {
static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER).hide_value();
- b.add_input<decl::Vector>("Rotate By").subtype(PROP_EULER);
- b.add_input<decl::Vector>("Axis").default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
- b.add_input<decl::Float>("Angle").subtype(PROP_ANGLE);
- b.add_output<decl::Vector>("Rotation");
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).hide_value();
+ b.add_input<decl::Vector>(N_("Rotate By")).subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Axis")).default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
+ b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE);
+ b.add_output<decl::Vector>(N_("Rotation"));
};
static void fn_node_rotate_euler_update(bNodeTree *UNUSED(ntree), bNode *node)
diff --git a/source/blender/nodes/function/nodes/node_fn_slice_string.cc b/source/blender/nodes/function/nodes/node_fn_slice_string.cc
index 08e17da0d92..5cb753e8f34 100644
--- a/source/blender/nodes/function/nodes/node_fn_slice_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_slice_string.cc
@@ -22,10 +22,10 @@ namespace blender::nodes {
static void fn_node_slice_string_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::String>("String");
- b.add_input<decl::Int>("Position");
- b.add_input<decl::Int>("Length").min(0).default_value(10);
- b.add_output<decl::String>("String");
+ b.add_input<decl::String>(N_("String"));
+ b.add_input<decl::Int>(N_("Position"));
+ b.add_input<decl::Int>(N_("Length")).min(0).default_value(10);
+ b.add_output<decl::String>(N_("String"));
};
static void fn_node_slice_string_build_multi_function(NodeMultiFunctionBuilder &builder)
diff --git a/source/blender/nodes/function/nodes/node_fn_string_length.cc b/source/blender/nodes/function/nodes/node_fn_string_length.cc
index d882280b566..63429d35993 100644
--- a/source/blender/nodes/function/nodes/node_fn_string_length.cc
+++ b/source/blender/nodes/function/nodes/node_fn_string_length.cc
@@ -24,8 +24,8 @@ namespace blender::nodes {
static void fn_node_string_length_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::String>("String");
- b.add_output<decl::Int>("Length");
+ b.add_input<decl::String>(N_("String"));
+ b.add_output<decl::Int>(N_("Length"));
};
static void fn_node_string_length_build_multi_function(NodeMultiFunctionBuilder &builder)
diff --git a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
index 112726f98dc..96a56760664 100644
--- a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
@@ -21,9 +21,9 @@ namespace blender::nodes {
static void fn_node_value_to_string_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Value");
- b.add_input<decl::Int>("Decimals").min(0);
- b.add_output<decl::String>("String");
+ b.add_input<decl::Float>(N_("Value"));
+ b.add_input<decl::Int>(N_("Decimals")).min(0);
+ b.add_output<decl::String>(N_("String"));
};
static void fn_node_value_to_string_build_multi_function(NodeMultiFunctionBuilder &builder)
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index f382ff6c132..167765fa131 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -32,6 +32,7 @@
#include "NOD_geometry.h"
#include "NOD_geometry_exec.hh"
#include "NOD_socket_declarations.hh"
+#include "NOD_socket_declarations_geometry.hh"
#include "node_util.h"
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc
index d0bb906e8af..b92d4704d63 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc
@@ -26,18 +26,18 @@ namespace blender::nodes {
static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Factor");
- b.add_input<decl::Float>("Factor", "Factor_001")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Factor"));
+ b.add_input<decl::Float>(N_("Factor"), "Factor_001")
.default_value(1.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
- b.add_input<decl::String>("Vector");
- b.add_input<decl::Vector>("Vector", "Vector_001")
+ b.add_input<decl::String>(N_("Vector"));
+ b.add_input<decl::Vector>(N_("Vector"), "Vector_001")
.default_value({0.0, 0.0, 1.0})
.subtype(PROP_ANGLE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_align_rotation_to_vector_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc
index 2e931a2da98..91ff114a480 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc
@@ -24,18 +24,18 @@ namespace blender::nodes {
static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::String>("Result");
- b.add_input<decl::Vector>("Min");
- b.add_input<decl::Vector>("Max").default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Min", "Min_001");
- b.add_input<decl::Float>("Max", "Max_001").default_value(1.0f);
- b.add_input<decl::Int>("Min", "Min_002").min(-100000).max(100000);
- b.add_input<decl::Int>("Max", "Max_002").default_value(100).min(-100000).max(100000);
- b.add_input<decl::Color>("Min", "Min_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::Color>("Max", "Max_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_input<decl::Vector>(N_("Min"));
+ b.add_input<decl::Vector>(N_("Max")).default_value({1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Min"), "Min_001");
+ b.add_input<decl::Float>(N_("Max"), "Max_001").default_value(1.0f);
+ b.add_input<decl::Int>(N_("Min"), "Min_002").min(-100000).max(100000);
+ b.add_input<decl::Int>(N_("Max"), "Max_002").default_value(100).min(-100000).max(100000);
+ b.add_input<decl::Color>(N_("Min"), "Min_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_input<decl::Color>(N_("Max"), "Max_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_clamp_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc
index aa054af3acd..ab4b6aad545 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc
@@ -27,10 +27,10 @@ namespace blender::nodes {
static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_color_ramp_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc
index 569d5a824ca..d4c23380b4e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc
@@ -23,15 +23,15 @@ namespace blender::nodes {
static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("X");
- b.add_input<decl::Float>("X", "X_001");
- b.add_input<decl::String>("Y");
- b.add_input<decl::Float>("Y", "Y_001");
- b.add_input<decl::String>("Z");
- b.add_input<decl::Float>("Z", "Z_001");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("X"));
+ b.add_input<decl::Float>(N_("X"), "X_001");
+ b.add_input<decl::String>(N_("Y"));
+ b.add_input<decl::Float>(N_("Y"), "Y_001");
+ b.add_input<decl::String>(N_("Z"));
+ b.add_input<decl::Float>(N_("Z"), "Z_001");
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_combine_xyz_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc
index 0b9708dae14..e4e43a7b724 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc
@@ -25,18 +25,18 @@ namespace blender::nodes {
static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("A");
- b.add_input<decl::Float>("A", "A_001");
- b.add_input<decl::Vector>("A", "A_002");
- b.add_input<decl::Color>("A", "A_003").default_value({0.5, 0.5, 0.5, 1.0});
- b.add_input<decl::String>("B");
- b.add_input<decl::Float>("B", "B_001");
- b.add_input<decl::Vector>("B", "B_002");
- b.add_input<decl::Color>("B", "B_003").default_value({0.5, 0.5, 0.5, 1.0});
- b.add_input<decl::Float>("Threshold").default_value(0.01f).min(0.0f);
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("A"));
+ b.add_input<decl::Float>(N_("A"), "A_001");
+ b.add_input<decl::Vector>(N_("A"), "A_002");
+ b.add_input<decl::Color>(N_("A"), "A_003").default_value({0.5, 0.5, 0.5, 1.0});
+ b.add_input<decl::String>(N_("B"));
+ b.add_input<decl::Float>(N_("B"), "B_001");
+ b.add_input<decl::Vector>(N_("B"), "B_002");
+ b.add_input<decl::Color>(N_("B"), "B_003").default_value({0.5, 0.5, 0.5, 1.0});
+ b.add_input<decl::Float>(N_("Threshold")).default_value(0.01f).min(0.0f);
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_compare_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc
index a2382aa9d25..dc05fa2c125 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc
@@ -23,10 +23,10 @@ namespace blender::nodes {
static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_convert_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc
index b9621b4ae92..669ac21436f 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc
@@ -28,10 +28,10 @@ namespace blender::nodes {
static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_curve_map_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc
index 1458b6df9ba..5cb49dd83d0 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc
@@ -23,14 +23,14 @@ namespace blender::nodes {
static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute").is_attribute_name();
- b.add_input<decl::Vector>("Value", "Value");
- b.add_input<decl::Float>("Value", "Value_001");
- b.add_input<decl::Color>("Value", "Value_002");
- b.add_input<decl::Bool>("Value", "Value_003");
- b.add_input<decl::Int>("Value", "Value_004");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute")).is_attribute_name();
+ b.add_input<decl::Vector>(N_("Value"), "Value");
+ b.add_input<decl::Float>(N_("Value"), "Value_001");
+ b.add_input<decl::Color>(N_("Value"), "Value_002");
+ b.add_input<decl::Bool>(N_("Value"), "Value_003");
+ b.add_input<decl::Int>(N_("Value"), "Value_004");
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc
index 0ea3bbe1e45..978c75187fe 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc
@@ -26,21 +26,21 @@ namespace blender::nodes {
static void geo_node_attribute_map_range_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::String>("Result");
- b.add_input<decl::Float>("From Min");
- b.add_input<decl::Float>("From Max").default_value(1.0f);
- b.add_input<decl::Float>("To Min");
- b.add_input<decl::Float>("To Max").default_value(1.0f);
- b.add_input<decl::Float>("Steps").default_value(4.0f);
- b.add_input<decl::Vector>("From Min", "From Min_001");
- b.add_input<decl::Vector>("From Max", "From Max_001").default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Vector>("To Min", "To Min_001");
- b.add_input<decl::Vector>("To Max", "To Max_001").default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Vector>("Steps", "Steps_001").default_value({4.0f, 4.0f, 4.0f});
- b.add_input<decl::Bool>("Clamp");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_input<decl::Float>(N_("From Min"));
+ b.add_input<decl::Float>(N_("From Max")).default_value(1.0f);
+ b.add_input<decl::Float>(N_("To Min"));
+ b.add_input<decl::Float>(N_("To Max")).default_value(1.0f);
+ b.add_input<decl::Float>(N_("Steps")).default_value(4.0f);
+ b.add_input<decl::Vector>(N_("From Min"), "From Min_001");
+ b.add_input<decl::Vector>(N_("From Max"), "From Max_001").default_value({1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("To Min"), "To Min_001");
+ b.add_input<decl::Vector>(N_("To Max"), "To Max_001").default_value({1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Steps"), "Steps_001").default_value({4.0f, 4.0f, 4.0f});
+ b.add_input<decl::Bool>(N_("Clamp"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc
index efa09215b45..55d35f87cda 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc
@@ -29,15 +29,15 @@ namespace blender::nodes {
static void geo_node_attribute_math_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("A");
- b.add_input<decl::Float>("A", "A_001");
- b.add_input<decl::String>("B");
- b.add_input<decl::Float>("B", "B_001");
- b.add_input<decl::String>("C");
- b.add_input<decl::Float>("C", "C_001");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("A"));
+ b.add_input<decl::Float>(N_("A"), "A_001");
+ b.add_input<decl::String>(N_("B"));
+ b.add_input<decl::Float>(N_("B"), "B_001");
+ b.add_input<decl::String>(N_("C"));
+ b.add_input<decl::Float>(N_("C"), "C_001");
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static bool operation_use_input_c(const NodeMathOperation operation)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc
index 74e05cb997d..b4205bc91b7 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc
@@ -29,23 +29,23 @@ namespace blender::nodes {
static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Factor");
- b.add_input<decl::Float>("Factor", "Factor_001")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Factor"));
+ b.add_input<decl::Float>(N_("Factor"), "Factor_001")
.default_value(0.5f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
- b.add_input<decl::String>("A");
- b.add_input<decl::Float>("A", "A_001");
- b.add_input<decl::Vector>("A", "A_002");
- b.add_input<decl::Color>("A", "A_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::String>("B");
- b.add_input<decl::Float>("B", "B_001");
- b.add_input<decl::Vector>("B", "B_002");
- b.add_input<decl::Color>("B", "B_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::String>(N_("A"));
+ b.add_input<decl::Float>(N_("A"), "A_001");
+ b.add_input<decl::Vector>(N_("A"), "A_002");
+ b.add_input<decl::Color>(N_("A"), "A_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_input<decl::String>(N_("B"));
+ b.add_input<decl::Float>(N_("B"), "B_001");
+ b.add_input<decl::Vector>(N_("B"), "B_002");
+ b.add_input<decl::Color>(N_("B"), "B_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc
index 6120118f611..9e3a7984c53 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc
@@ -30,11 +30,11 @@ namespace blender::nodes {
static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Geometry>("Target");
- b.add_input<decl::String>("Distance");
- b.add_input<decl::String>("Position");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Geometry>(N_("Target"));
+ b.add_input<decl::String>(N_("Distance"));
+ b.add_input<decl::String>(N_("Position"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_proximity_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc
index 2e6ba456725..2901472d661 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc
@@ -27,16 +27,16 @@ namespace blender::nodes {
static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::Vector>("Min");
- b.add_input<decl::Vector>("Max").default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Min", "Min_001");
- b.add_input<decl::Float>("Max", "Max_001").default_value(1.0f);
- b.add_input<decl::Int>("Min", "Min_002").min(-100000).max(100000);
- b.add_input<decl::Int>("Max", "Max_002").default_value(100).min(-100000).max(100000);
- b.add_input<decl::Int>("Seed").min(-10000).max(10000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::Vector>(N_("Min"));
+ b.add_input<decl::Vector>(N_("Max")).default_value({1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Min"), "Min_001");
+ b.add_input<decl::Float>(N_("Max"), "Max_001").default_value(1.0f);
+ b.add_input<decl::Int>(N_("Min"), "Min_002").min(-100000).max(100000);
+ b.add_input<decl::Int>(N_("Max"), "Max_002").default_value(100).min(-100000).max(100000);
+ b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_legacy_attribute_random_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc
index 52f97475941..19d6ced6eb6 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc
@@ -32,11 +32,11 @@ namespace blender::nodes {
static void geo_node_attribute_sample_texture_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Texture>("Texture").hide_label();
- b.add_input<decl::String>("Mapping");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Texture>(N_("Texture")).hide_label();
+ b.add_input<decl::String>(N_("Mapping"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static AttributeDomain get_result_domain(const GeometryComponent &component,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc
index de0090406c6..809e75e73a3 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc
@@ -23,13 +23,13 @@ namespace blender::nodes {
static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Vector");
- b.add_input<decl::Vector>("Vector", "Vector_001");
- b.add_input<decl::String>("Result X");
- b.add_input<decl::String>("Result Y");
- b.add_input<decl::String>("Result Z");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Vector"));
+ b.add_input<decl::Vector>(N_("Vector"), "Vector_001");
+ b.add_input<decl::String>(N_("Result X"));
+ b.add_input<decl::String>(N_("Result Y"));
+ b.add_input<decl::String>(N_("Result Z"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_separate_xyz_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc
index d7a66dac3ad..3a9cd52661a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc
@@ -33,11 +33,11 @@ namespace blender::nodes {
static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Geometry>("Source Geometry");
- b.add_input<decl::String>("Source");
- b.add_input<decl::String>("Destination");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Geometry>(N_("Source Geometry"));
+ b.add_input<decl::String>(N_("Source"));
+ b.add_input<decl::String>(N_("Destination"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_transfer_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc
index 59903050f88..4c351846243 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc
@@ -30,17 +30,17 @@ namespace blender::nodes {
static void geo_node_attribute_vector_math_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("A");
- b.add_input<decl::Vector>("A", "A_001");
- b.add_input<decl::String>("B");
- b.add_input<decl::Vector>("B", "B_001");
- b.add_input<decl::Float>("B", "B_002");
- b.add_input<decl::String>("C");
- b.add_input<decl::Vector>("C", "C_001");
- b.add_input<decl::Float>("C", "C_002");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("A"));
+ b.add_input<decl::Vector>(N_("A"), "A_001");
+ b.add_input<decl::String>(N_("B"));
+ b.add_input<decl::Vector>(N_("B"), "B_001");
+ b.add_input<decl::Float>(N_("B"), "B_002");
+ b.add_input<decl::String>(N_("C"));
+ b.add_input<decl::Vector>(N_("C"), "C_001");
+ b.add_input<decl::Float>(N_("C"), "C_002");
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static bool operation_use_input_b(const NodeVectorMathOperation operation)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc
index 0c515fa63fb..9ab8ec25fb6 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc
@@ -25,21 +25,21 @@ namespace blender::nodes {
static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Vector");
- b.add_input<decl::Vector>("Vector", "Vector_001").min(0.0f).max(1.0f).hide_value();
- b.add_input<decl::String>("Center");
- b.add_input<decl::Vector>("Center", "Center_001").subtype(PROP_XYZ);
- b.add_input<decl::String>("Axis");
- b.add_input<decl::Vector>("Axis", "Axis_001").min(-1.0f).max(1.0f).subtype(PROP_XYZ);
- b.add_input<decl::String>("Angle");
- b.add_input<decl::Float>("Angle", "Angle_001").subtype(PROP_ANGLE);
- b.add_input<decl::String>("Rotation");
- b.add_input<decl::Vector>("Rotation", "Rotation_001").subtype(PROP_EULER);
- b.add_input<decl::Bool>("Invert");
- b.add_input<decl::String>("Result");
-
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Vector"));
+ b.add_input<decl::Vector>(N_("Vector"), "Vector_001").min(0.0f).max(1.0f).hide_value();
+ b.add_input<decl::String>(N_("Center"));
+ b.add_input<decl::Vector>(N_("Center"), "Center_001").subtype(PROP_XYZ);
+ b.add_input<decl::String>(N_("Axis"));
+ b.add_input<decl::Vector>(N_("Axis"), "Axis_001").min(-1.0f).max(1.0f).subtype(PROP_XYZ);
+ b.add_input<decl::String>(N_("Angle"));
+ b.add_input<decl::Float>(N_("Angle"), "Angle_001").subtype(PROP_ANGLE);
+ b.add_input<decl::String>(N_("Rotation"));
+ b.add_input<decl::Vector>(N_("Rotation"), "Rotation_001").subtype(PROP_EULER);
+ b.add_input<decl::Bool>(N_("Invert"));
+ b.add_input<decl::String>(N_("Result"));
+
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_attribute_vector_rotate_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc
index 85d1392aa35..8b81008ff34 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void geo_node_curve_endpoints_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_output<decl::Geometry>("Start Points");
- b.add_output<decl::Geometry>("End Points");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Geometry>(N_("Start Points"));
+ b.add_output<decl::Geometry>(N_("End Points"));
}
/**
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc
index d1c81333c30..ba76fafe3e6 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc
@@ -24,9 +24,9 @@ namespace blender::nodes {
static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc
index 0d3de7ac5f5..40d827ae141 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc
@@ -27,9 +27,9 @@ namespace blender::nodes {
static void geo_node_select_by_handle_type_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_curve_select_by_handle_type_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc
index 339029336d9..4bac9cb976e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc
@@ -25,9 +25,9 @@ namespace blender::nodes {
static void geo_node_curve_set_handles_decalre(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_set_handles_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc
index 44522e990d9..df53c96e6ca 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc
@@ -27,9 +27,9 @@ namespace blender::nodes {
static void geo_node_legacy_curve_spline_type_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_legacy_curve_spline_type_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
index 61165902028..f9b0a9d128e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
@@ -33,10 +33,10 @@ namespace blender::nodes {
static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Cuts");
- b.add_input<decl::Int>("Cuts", "Cuts_001").default_value(1).min(0).max(1000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Cuts"));
+ b.add_input<decl::Int>(N_("Cuts"), "Cuts_001").default_value(1).min(0).max(1000);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_curve_subdivide_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc
index 2936c150376..c171d485a6a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc
@@ -30,10 +30,10 @@ namespace blender::nodes {
static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Count").default_value(10).min(2).max(100000);
- b.add_input<decl::Float>("Length").default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000);
+ b.add_input<decl::Float>(N_("Length")).default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc
index 2d9b4da4c83..1d76a0532a1 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc
@@ -47,10 +47,10 @@ namespace blender::nodes {
static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Selection");
- b.add_input<decl::Bool>("Invert");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_input<decl::Bool>(N_("Invert"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc
index d7e908edf61..8f2bf05d2b4 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc
@@ -26,15 +26,15 @@ namespace blender::nodes {
static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Edge Angle").default_value(true);
- b.add_input<decl::Float>("Angle")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Edge Angle")).default_value(true);
+ b.add_input<decl::Float>(N_("Angle"))
.default_value(DEG2RADF(30.0f))
.min(0.0f)
.max(DEG2RADF(180.0f))
.subtype(PROP_ANGLE);
- b.add_input<decl::Bool>("Sharp Edges");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Bool>(N_("Sharp Edges"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_edge_split_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc
index 7d3481c1067..333a17aa4e9 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc
@@ -28,10 +28,10 @@ namespace blender::nodes {
static void geo_node_legacy_material_assign_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Material>("Material").hide_label(true);
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Material>(N_("Material")).hide_label(true);
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask, Material *material)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc
index 7a27e856cef..9167096fd3d 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc
@@ -22,9 +22,9 @@ namespace blender::nodes {
static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Mesh");
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Mesh"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc
index f30feb48734..210757f986d 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc
@@ -42,16 +42,16 @@ namespace blender::nodes {
static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Float>("Distance Min").min(0.0f).max(100000.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Density Max")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).max(100000.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Density Max"))
.default_value(1.0f)
.min(0.0f)
.max(100000.0f)
.subtype(PROP_NONE);
- b.add_input<decl::String>("Density Attribute");
- b.add_input<decl::Int>("Seed").min(-10000).max(10000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::String>(N_("Density Attribute"));
+ b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_point_distribute_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
index fb45c22ced4..ffb2a0dd7ac 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
@@ -28,12 +28,12 @@ namespace blender::nodes {
static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Object>("Object").hide_label();
- b.add_input<decl::Collection>("Collection").hide_label();
- b.add_input<decl::Geometry>("Instance Geometry");
- b.add_input<decl::Int>("Seed").min(-10000).max(10000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Object>(N_("Object")).hide_label();
+ b.add_input<decl::Collection>(N_("Collection")).hide_label();
+ b.add_input<decl::Geometry>(N_("Instance Geometry"));
+ b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -184,7 +184,7 @@ static void add_instances_from_component(InstancesComponent &instances,
instances.resize(start_len + domain_size);
MutableSpan<int> handles = instances.instance_reference_handles().slice(start_len, domain_size);
MutableSpan<float4x4> transforms = instances.instance_transforms().slice(start_len, domain_size);
- MutableSpan<int> instance_ids = instances.instance_ids().slice(start_len, domain_size);
+ MutableSpan<int> instance_ids = instances.instance_ids_ensure().slice(start_len, domain_size);
/* Skip all of the randomness handling if there is only a single possible instance
* (anything except for collection mode with "Whole Collection" turned off). */
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc
index 60c82360007..54d36dab98d 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc
@@ -25,14 +25,16 @@ namespace blender::nodes {
static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Axis");
- b.add_input<decl::Vector>("Axis", "Axis_001").default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
- b.add_input<decl::String>("Angle");
- b.add_input<decl::Float>("Angle", "Angle_001").subtype(PROP_ANGLE);
- b.add_input<decl::String>("Rotation");
- b.add_input<decl::Vector>("Rotation", "Rotation_001").subtype(PROP_EULER);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Axis"));
+ b.add_input<decl::Vector>(N_("Axis"), "Axis_001")
+ .default_value({0.0, 0.0, 1.0})
+ .subtype(PROP_XYZ);
+ b.add_input<decl::String>(N_("Angle"));
+ b.add_input<decl::Float>(N_("Angle"), "Angle_001").subtype(PROP_ANGLE);
+ b.add_input<decl::String>(N_("Rotation"));
+ b.add_input<decl::Vector>(N_("Rotation"), "Rotation_001").subtype(PROP_EULER);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc
index 99adce149e9..934442ee8a3 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc
@@ -25,13 +25,13 @@ namespace blender::nodes {
static void geo_node_point_scale_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Factor");
- b.add_input<decl::Vector>("Factor", "Factor_001")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Factor"));
+ b.add_input<decl::Vector>(N_("Factor"), "Factor_001")
.default_value({1.0f, 1.0f, 1.0f})
.subtype(PROP_XYZ);
- b.add_input<decl::Float>("Factor", "Factor_002").default_value(1.0f).min(0.0f);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Float>(N_("Factor"), "Factor_002").default_value(1.0f).min(0.0f);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_point_scale_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc
index 48b6676c1dd..accdaf78439 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc
@@ -27,10 +27,10 @@ namespace blender::nodes {
static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Mask");
- b.add_output<decl::Geometry>("Geometry 1");
- b.add_output<decl::Geometry>("Geometry 2");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Mask"));
+ b.add_output<decl::Geometry>(N_("Geometry 1"));
+ b.add_output<decl::Geometry>(N_("Geometry 2"));
}
template<typename T>
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc
index f2fce45c57b..34f7641995f 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc
@@ -23,10 +23,10 @@ namespace blender::nodes {
static void geo_node_point_translate_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Translation");
- b.add_input<decl::Vector>("Translation", "Translation_001").subtype(PROP_TRANSLATION);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Translation"));
+ b.add_input<decl::Vector>(N_("Translation"), "Translation_001").subtype(PROP_TRANSLATION);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_point_translate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc
index 68d3f232ce1..cf7f466c2a6 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc
@@ -32,13 +32,13 @@ namespace blender::nodes {
static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Float>("Density").default_value(1.0f).min(0.0f);
- b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Voxel Amount").default_value(64.0f).min(0.0f);
- b.add_input<decl::String>("Radius");
- b.add_input<decl::Float>("Radius", "Radius_001").default_value(0.5f).min(0.0f);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f);
+ b.add_input<decl::String>(N_("Radius"));
+ b.add_input<decl::Float>(N_("Radius"), "Radius_001").default_value(0.5f).min(0.0f);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_points_to_volume_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc
index 6641e622362..e6a81fc9627 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc
@@ -28,23 +28,23 @@ namespace blender::nodes {
static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Geometry>("Target Geometry");
- b.add_input<decl::String>("Ray Direction");
- b.add_input<decl::Vector>("Ray Direction", "Ray Direction_001")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Geometry>(N_("Target Geometry"));
+ b.add_input<decl::String>(N_("Ray Direction"));
+ b.add_input<decl::Vector>(N_("Ray Direction"), "Ray Direction_001")
.default_value({0.0f, 0.0f, 1.0f});
- b.add_input<decl::String>("Ray Length");
- b.add_input<decl::Float>("Ray Length", "Ray Length_001")
+ b.add_input<decl::String>(N_("Ray Length"));
+ b.add_input<decl::Float>(N_("Ray Length"), "Ray Length_001")
.default_value(100.0f)
.min(0.0f)
.subtype(PROP_DISTANCE);
- b.add_input<decl::String>("Target Attribute");
- b.add_input<decl::String>("Is Hit");
- b.add_input<decl::String>("Hit Position");
- b.add_input<decl::String>("Hit Normal");
- b.add_input<decl::String>("Hit Distance");
- b.add_input<decl::String>("Hit Attribute");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::String>(N_("Target Attribute"));
+ b.add_input<decl::String>(N_("Is Hit"));
+ b.add_input<decl::String>(N_("Hit Position"));
+ b.add_input<decl::String>(N_("Hit Normal"));
+ b.add_input<decl::String>(N_("Hit Distance"));
+ b.add_input<decl::String>(N_("Hit Attribute"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc
index eabdd2bcd5a..a8d6f33a5fd 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc
@@ -30,10 +30,10 @@ namespace blender::nodes {
static void geo_node_legacy_select_by_material_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Material>("Material").hide_label();
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Material>(N_("Material")).hide_label();
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void select_mesh_by_material(const Mesh &mesh,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc
index 101c915eb77..295cd05fd01 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc
@@ -27,10 +27,10 @@ namespace blender::nodes {
static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Level").default_value(1).min(0).max(6);
- b.add_input<decl::Bool>("Use Creases");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
+ b.add_input<decl::Bool>(N_("Use Creases"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_subdivision_surface_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc
new file mode 100644
index 00000000000..39af5bf1fd2
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+#include "DEG_depsgraph_query.h"
+#ifdef WITH_OPENVDB
+# include <openvdb/tools/GridTransformer.h>
+# include <openvdb/tools/VolumeToMesh.h>
+#endif
+
+#include "node_geometry_util.hh"
+
+#include "BKE_lib_id.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_volume.h"
+#include "BKE_volume_to_mesh.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Density"));
+ b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Threshold")).default_value(0.1f).min(0.0f);
+ b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
+}
+
+static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
+ sizeof(NodeGeometryVolumeToMesh), __func__);
+ data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
+
+ bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density");
+ bNodeSocketValueString *grid_socket_value = (bNodeSocketValueString *)grid_socket->default_value;
+ STRNCPY(grid_socket_value->value, "density");
+
+ node->storage = data;
+}
+
+static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage;
+
+ bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
+ bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
+ nodeSetSocketAvailability(voxel_amount_socket,
+ data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT);
+ nodeSetSocketAvailability(voxel_size_socket,
+ data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
+}
+
+#ifdef WITH_OPENVDB
+
+static void create_mesh_from_volume(GeometrySet &geometry_set_in,
+ GeometrySet &geometry_set_out,
+ GeoNodeExecParams &params)
+{
+ if (!geometry_set_in.has<VolumeComponent>()) {
+ return;
+ }
+
+ const NodeGeometryVolumeToMesh &storage =
+ *(const NodeGeometryVolumeToMesh *)params.node().storage;
+
+ bke::VolumeToMeshResolution resolution;
+ resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode;
+ if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT) {
+ resolution.settings.voxel_amount = params.get_input<float>("Voxel Amount");
+ if (resolution.settings.voxel_amount <= 0.0f) {
+ return;
+ }
+ }
+ else if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE) {
+ resolution.settings.voxel_size = params.get_input<float>("Voxel Size");
+ if (resolution.settings.voxel_size <= 0.0f) {
+ return;
+ }
+ }
+
+ const VolumeComponent *component = geometry_set_in.get_component_for_read<VolumeComponent>();
+ const Volume *volume = component->get_for_read();
+ if (volume == nullptr) {
+ return;
+ }
+
+ const Main *bmain = DEG_get_bmain(params.depsgraph());
+ BKE_volume_load(volume, bmain);
+
+ const std::string grid_name = params.get_input<std::string>("Density");
+ const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, grid_name.c_str());
+ if (volume_grid == nullptr) {
+ return;
+ }
+
+ float threshold = params.get_input<float>("Threshold");
+ float adaptivity = params.get_input<float>("Adaptivity");
+
+ const openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
+ Mesh *mesh = bke::volume_to_mesh(*grid, resolution, threshold, adaptivity);
+ if (mesh == nullptr) {
+ return;
+ }
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ MeshComponent &dst_component = geometry_set_out.get_component_for_write<MeshComponent>();
+ dst_component.replace(mesh);
+}
+
+#endif /* WITH_OPENVDB */
+
+static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set_out;
+
+#ifdef WITH_OPENVDB
+ create_mesh_from_volume(geometry_set_in, geometry_set_out, params);
+#else
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenVDB"));
+#endif
+
+ params.set_output("Geometry", geometry_set_out);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_legacy_volume_to_mesh()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
+ ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare;
+ node_type_storage(
+ &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
+ node_type_size(&ntype, 170, 120, 700);
+ node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init);
+ node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update);
+ ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec;
+ ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
index b7352160f89..5cc8f1476f8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -25,19 +25,19 @@ namespace blender::nodes {
static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Vector>("Value").supports_field();
- b.add_input<decl::Float>("Value", "Value_001").supports_field();
- b.add_input<decl::Color>("Value", "Value_002").supports_field();
- b.add_input<decl::Bool>("Value", "Value_003").supports_field();
- b.add_input<decl::Int>("Value", "Value_004").supports_field();
-
- b.add_output<decl::Geometry>("Geometry");
- b.add_output<decl::Vector>("Attribute").field_source();
- b.add_output<decl::Float>("Attribute", "Attribute_001").field_source();
- b.add_output<decl::Color>("Attribute", "Attribute_002").field_source();
- b.add_output<decl::Bool>("Attribute", "Attribute_003").field_source();
- b.add_output<decl::Int>("Attribute", "Attribute_004").field_source();
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Vector>(N_("Value")).supports_field();
+ b.add_input<decl::Float>(N_("Value"), "Value_001").supports_field();
+ b.add_input<decl::Color>(N_("Value"), "Value_002").supports_field();
+ b.add_input<decl::Bool>(N_("Value"), "Value_003").supports_field();
+ b.add_input<decl::Int>(N_("Value"), "Value_004").supports_field();
+
+ b.add_output<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Vector>(N_("Attribute")).field_source();
+ b.add_output<decl::Float>(N_("Attribute"), "Attribute_001").field_source();
+ b.add_output<decl::Color>(N_("Attribute"), "Attribute_002").field_source();
+ b.add_output<decl::Bool>(N_("Attribute"), "Attribute_003").field_source();
+ b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").field_source();
}
static void geo_node_attribute_capture_layout(uiLayout *layout,
@@ -144,7 +144,7 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
break;
}
- WeakAnonymousAttributeID anonymous_id{"Attribute Capture"};
+ WeakAnonymousAttributeID anonymous_id{"Attribute"};
const CPPType &type = field.cpp_type();
static const Array<GeometryComponentType> types = {
@@ -158,8 +158,8 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
}
});
- GField output_field{
- std::make_shared<bke::AnonymousAttributeFieldInput>(std::move(anonymous_id), type)};
+ GField output_field{std::make_shared<bke::AnonymousAttributeFieldInput>(
+ std::move(anonymous_id), type, params.attribute_producer_name())};
switch (data_type) {
case CD_PROP_FLOAT: {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
index f93ef6f1db3..f80b8ccc971 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
@@ -20,9 +20,9 @@ namespace blender::nodes {
static void geo_node_attribute_remove_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute").multi_input();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute")).multi_input();
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void remove_attribute(GeometryComponent &component,
@@ -59,6 +59,10 @@ static void geo_node_attribute_remove_exec(GeoNodeExecParams params)
remove_attribute(
geometry_set.get_component_for_write<CurveComponent>(), params, attribute_names);
}
+ if (geometry_set.has<InstancesComponent>()) {
+ remove_attribute(
+ geometry_set.get_component_for_write<InstancesComponent>(), params, attribute_names);
+ }
params.set_output("Geometry", geometry_set);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
index 1b7d2fe28a1..155bd8c8c28 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -28,27 +28,27 @@ namespace blender::nodes {
static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Float>("Attribute").hide_value().supports_field();
- b.add_input<decl::Vector>("Attribute", "Attribute_001").hide_value().supports_field();
-
- b.add_output<decl::Float>("Mean");
- b.add_output<decl::Float>("Median");
- b.add_output<decl::Float>("Sum");
- b.add_output<decl::Float>("Min");
- b.add_output<decl::Float>("Max");
- b.add_output<decl::Float>("Range");
- b.add_output<decl::Float>("Standard Deviation");
- b.add_output<decl::Float>("Variance");
-
- b.add_output<decl::Vector>("Mean", "Mean_001");
- b.add_output<decl::Vector>("Median", "Median_001");
- b.add_output<decl::Vector>("Sum", "Sum_001");
- b.add_output<decl::Vector>("Min", "Min_001");
- b.add_output<decl::Vector>("Max", "Max_001");
- b.add_output<decl::Vector>("Range", "Range_001");
- b.add_output<decl::Vector>("Standard Deviation", "Standard Deviation_001");
- b.add_output<decl::Vector>("Variance", "Variance_001");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Float>(N_("Attribute")).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
+
+ b.add_output<decl::Float>(N_("Mean"));
+ b.add_output<decl::Float>(N_("Median"));
+ b.add_output<decl::Float>(N_("Sum"));
+ b.add_output<decl::Float>(N_("Min"));
+ b.add_output<decl::Float>(N_("Max"));
+ b.add_output<decl::Float>(N_("Range"));
+ b.add_output<decl::Float>(N_("Standard Deviation"));
+ b.add_output<decl::Float>(N_("Variance"));
+
+ b.add_output<decl::Vector>(N_("Mean"), "Mean_001");
+ b.add_output<decl::Vector>(N_("Median"), "Median_001");
+ b.add_output<decl::Vector>(N_("Sum"), "Sum_001");
+ b.add_output<decl::Vector>(N_("Min"), "Min_001");
+ b.add_output<decl::Vector>(N_("Max"), "Max_001");
+ b.add_output<decl::Vector>(N_("Range"), "Range_001");
+ b.add_output<decl::Vector>(N_("Standard Deviation"), "Standard Deviation_001");
+ b.add_output<decl::Vector>(N_("Variance"), "Variance_001");
}
static void geo_node_attribute_statistic_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 27e18f16bad..516f07b7ad3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -27,11 +27,13 @@ namespace blender::nodes {
static void geo_node_boolean_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry 1");
- b.add_input<decl::Geometry>("Geometry 2").multi_input();
- b.add_input<decl::Bool>("Self Intersection");
- b.add_input<decl::Bool>("Hole Tolerant");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Mesh 1"))
+ .only_realized_data()
+ .supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Geometry>(N_("Mesh 2")).multi_input().supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Self Intersection"));
+ b.add_input<decl::Bool>(N_("Hole Tolerant"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geo_node_boolean_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -51,12 +53,12 @@ static void geo_node_boolean_update(bNodeTree *UNUSED(ntree), bNode *node)
case GEO_NODE_BOOLEAN_UNION:
nodeSetSocketAvailability(geometry_1_socket, false);
nodeSetSocketAvailability(geometry_2_socket, true);
- node_sock_label(geometry_2_socket, N_("Geometry"));
+ node_sock_label(geometry_2_socket, N_("Mesh"));
break;
case GEO_NODE_BOOLEAN_DIFFERENCE:
nodeSetSocketAvailability(geometry_1_socket, true);
nodeSetSocketAvailability(geometry_2_socket, true);
- node_sock_label(geometry_2_socket, N_("Geometry 2"));
+ node_sock_label(geometry_2_socket, N_("Mesh 2"));
break;
}
}
@@ -82,12 +84,7 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
GeometrySet set_a;
if (operation == GEO_NODE_BOOLEAN_DIFFERENCE) {
- set_a = params.extract_input<GeometrySet>("Geometry 1");
- if (set_a.has_instances()) {
- params.error_message_add(
- NodeWarningType::Info,
- TIP_("Instances are not supported for the first geometry input, and will not be used"));
- }
+ set_a = params.extract_input<GeometrySet>("Mesh 1");
/* Note that it technically wouldn't be necessary to realize the instances for the first
* geometry input, but the boolean code expects the first shape for the difference operation
* to be a single mesh. */
@@ -101,7 +98,7 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
/* The instance transform matrices are owned by the instance group, so we have to
* keep all of them around for use during the boolean operation. */
Vector<bke::GeometryInstanceGroup> set_groups;
- Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Geometry 2");
+ Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Mesh 2");
for (const GeometrySet &geometry_set : geometry_sets) {
bke::geometry_set_gather_instances(geometry_set, set_groups);
}
@@ -119,7 +116,7 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
Mesh *result = blender::meshintersect::direct_mesh_boolean(
meshes, transforms, float4x4::identity(), {}, use_self, hole_tolerant, operation);
- params.set_output("Geometry", GeometrySet::create_with_mesh(result));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(result));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
index e34b65e6c94..e7c9715934a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
@@ -20,10 +20,10 @@ namespace blender::nodes {
static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_output<decl::Geometry>("Bounding Box");
- b.add_output<decl::Vector>("Min");
- b.add_output<decl::Vector>("Max");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Geometry>(N_("Bounding Box"));
+ b.add_output<decl::Vector>(N_("Min"));
+ b.add_output<decl::Vector>(N_("Max"));
}
static void geo_node_bounding_box_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
index eca4e3d2d14..f068e621596 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
@@ -31,15 +31,15 @@ namespace blender::nodes {
static void geo_node_collection_info_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Collection>("Collection").hide_label();
- b.add_input<decl::Bool>("Separate Children")
+ b.add_input<decl::Collection>(N_("Collection")).hide_label();
+ b.add_input<decl::Bool>(N_("Separate Children"))
.description(
- "Output each child of the collection as a separate instance, sorted alphabetically");
- b.add_input<decl::Bool>("Reset Children")
+ N_("Output each child of the collection as a separate instance, sorted alphabetically"));
+ b.add_input<decl::Bool>(N_("Reset Children"))
.description(
- "Reset the transforms of every child instance in the output. Only used when Separate "
- "Children is enabled");
- b.add_output<decl::Geometry>("Geometry");
+ N_("Reset the transforms of every child instance in the output. Only used when Separate "
+ "Children is enabled"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_collection_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -71,6 +71,14 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set_out);
return;
}
+ const Object *self_object = params.self_object();
+ const bool is_recursive = BKE_collection_has_object_recursive_instanced(collection,
+ (Object *)self_object);
+ if (is_recursive) {
+ params.error_message_add(NodeWarningType::Error, "Collection contains current object");
+ params.set_output("Geometry", geometry_set_out);
+ return;
+ }
const bNode &bnode = params.node();
NodeGeometryCollectionInfo *node_storage = (NodeGeometryCollectionInfo *)bnode.storage;
@@ -79,8 +87,6 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
- const Object *self_object = params.self_object();
-
const bool separate_children = params.get_input<bool>("Separate Children");
if (separate_children) {
const bool reset_children = params.get_input<bool>("Reset Children");
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index 4377d32210d..3cf682e161c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -32,8 +32,8 @@ namespace blender::nodes {
static void geo_node_convex_hull_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_output<decl::Geometry>("Convex Hull");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Geometry>(N_("Convex Hull"));
}
using bke::GeometryInstanceGroup;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
index ee6cf055ecb..42d88cdb1e7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
@@ -25,19 +25,20 @@ namespace blender::nodes {
static void geo_node_curve_endpoint_selection_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Start Size")
+ b.add_input<decl::Int>(N_("Start Size"))
.min(0)
.default_value(1)
.supports_field()
- .description("The amount of points to select from the start of each spline");
- b.add_input<decl::Int>("End Size")
+ .description(N_("The amount of points to select from the start of each spline"));
+ b.add_input<decl::Int>(N_("End Size"))
.min(0)
.default_value(1)
.supports_field()
- .description("The amount of points to select from the end of each spline");
- b.add_output<decl::Bool>("Selection")
+ .description(N_("The amount of points to select from the end of each spline"));
+ b.add_output<decl::Bool>(N_("Selection"))
.field_source()
- .description("The selection from the start and end of the splines based on the input sizes");
+ .description(
+ N_("The selection from the start and end of the splines based on the input sizes"));
}
static void select_by_spline(const int start, const int end, MutableSpan<bool> r_selection)
@@ -56,8 +57,11 @@ class EndpointFieldInput final : public fn::FieldInput {
public:
EndpointFieldInput(Field<int> start_size, Field<int> end_size)
- : FieldInput(CPPType::get<bool>(), "Selection"), start_size_(start_size), end_size_(end_size)
+ : FieldInput(CPPType::get<bool>(), "Endpoint Selection node"),
+ start_size_(start_size),
+ end_size_(end_size)
{
+ category_ = Category::Generated;
}
const GVArray *get_varray_for_context(const fn::FieldContext &context,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
index 953922531c1..219effadec4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -35,8 +35,8 @@ namespace blender::nodes {
static void geo_node_curve_fill_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_output<decl::Geometry>("Mesh");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geo_node_curve_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
index 67ce5b00d6b..27d7d22b106 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -29,16 +29,16 @@ namespace blender::nodes {
static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Int>("Count").default_value(1).min(1).max(1000).supports_field();
- b.add_input<decl::Float>("Radius")
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Int>(N_("Count")).default_value(1).min(1).max(1000).supports_field();
+ b.add_input<decl::Float>(N_("Radius"))
.min(0.0f)
.max(FLT_MAX)
.subtype(PropertySubType::PROP_DISTANCE)
.default_value(0.25f)
.supports_field();
- b.add_input<decl::Bool>("Limit Radius");
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Bool>(N_("Limit Radius"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_fillet_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
index b565b1e4602..165f5da5f71 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
@@ -25,7 +25,7 @@ namespace blender::nodes {
static void geo_node_curve_handle_type_selection_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Bool>("Selection").field_source();
+ b.add_output<decl::Bool>(N_("Selection")).field_source();
}
static void geo_node_curve_handle_type_selection_layout(uiLayout *layout,
@@ -91,8 +91,9 @@ class HandleTypeFieldInput final : public fn::FieldInput {
public:
HandleTypeFieldInput(BezierSpline::HandleType type, GeometryNodeCurveHandleMode mode)
- : FieldInput(CPPType::get<bool>(), "Selection"), type_(type), mode_(mode)
+ : FieldInput(CPPType::get<bool>(), "Handle Type Selection node"), type_(type), mode_(mode)
{
+ category_ = Category::Generated;
}
const GVArray *get_varray_for_context(const fn::FieldContext &context,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
index ac7df35bb72..0d0dc0ec89c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -21,8 +21,8 @@ namespace blender::nodes {
static void geo_node_curve_length_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_output<decl::Float>("Length");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_output<decl::Float>(N_("Length"));
}
static void geo_node_curve_length_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
index 90853387ec7..4c89aba2e6d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
@@ -24,7 +24,7 @@ namespace blender::nodes {
static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Factor").field_source();
+ b.add_output<decl::Float>(N_("Factor")).field_source();
}
/**
@@ -150,8 +150,9 @@ static const GVArray *construct_curve_parameter_gvarray(const CurveEval &curve,
class CurveParameterFieldInput final : public fn::FieldInput {
public:
- CurveParameterFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Parameter")
+ CurveParameterFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Parameter node")
{
+ category_ = Category::Generated;
}
const GVArray *get_varray_for_context(const fn::FieldContext &context,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index 313473e3442..a755d47cc6a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -25,14 +25,20 @@ namespace blender::nodes {
static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Resolution").default_value(16).min(1).max(256).subtype(PROP_UNSIGNED);
- b.add_input<decl::Vector>("Start").default_value({-1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Start Handle")
+ b.add_input<decl::Int>(N_("Resolution"))
+ .default_value(16)
+ .min(1)
+ .max(256)
+ .subtype(PROP_UNSIGNED);
+ b.add_input<decl::Vector>(N_("Start"))
+ .default_value({-1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Start Handle"))
.default_value({-0.5f, 0.5f, 0.0f})
.subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("End Handle").subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("End").default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Vector>(N_("End Handle")).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("End")).default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_primitive_bezier_segment_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index 8d5f4855512..bf4f22d6578 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -25,15 +25,19 @@ namespace blender::nodes {
static void geo_node_curve_primitive_circle_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Resolution").default_value(32).min(3).max(512);
- b.add_input<decl::Vector>("Point 1")
+ b.add_input<decl::Int>(N_("Resolution")).default_value(32).min(3).max(512);
+ b.add_input<decl::Vector>(N_("Point 1"))
.default_value({-1.0f, 0.0f, 0.0f})
.subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Point 2").default_value({0.0f, 1.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Point 3").default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Float>("Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Curve");
- b.add_output<decl::Vector>("Center");
+ b.add_input<decl::Vector>(N_("Point 2"))
+ .default_value({0.0f, 1.0f, 0.0f})
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Point 3"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Curve"));
+ b.add_output<decl::Vector>(N_("Center"));
}
static void geo_node_curve_primitive_circle_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index a3d2ada612f..5b215797052 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -25,11 +25,11 @@ namespace blender::nodes {
static void geo_node_curve_primitive_line_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>("Start").subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("End").default_value({0.0f, 0.0f, 1.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Direction").default_value({0.0f, 0.0f, 1.0f});
- b.add_input<decl::Float>("Length").default_value(1.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Vector>(N_("Start")).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("End")).default_value({0.0f, 0.0f, 1.0f}).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Direction")).default_value({0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Length")).default_value(1.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_primitive_line_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
index a54fd971ac4..6041ddee02d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
@@ -21,11 +21,19 @@ namespace blender::nodes {
static void geo_node_curve_primitive_quadratic_bezier_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Resolution").default_value(16).min(3).max(256).subtype(PROP_UNSIGNED);
- b.add_input<decl::Vector>("Start").default_value({-1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Middle").default_value({0.0f, 2.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("End").default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Int>(N_("Resolution"))
+ .default_value(16)
+ .min(3)
+ .max(256)
+ .subtype(PROP_UNSIGNED);
+ b.add_input<decl::Vector>(N_("Start"))
+ .default_value({-1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Middle"))
+ .default_value({0.0f, 2.0f, 0.0f})
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("End")).default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
index 07ddaa8f61e..7260da05a8d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -23,18 +23,32 @@ namespace blender::nodes {
static void geo_node_curve_primitive_quadrilateral_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Width").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Height").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Bottom Width").default_value(4.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Top Width").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Offset").default_value(1.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Bottom Height").default_value(3.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Top Height").default_value(1.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Vector>("Point 1").default_value({-1.0f, -1.0f, 0.0f}).subtype(PROP_DISTANCE);
- b.add_input<decl::Vector>("Point 2").default_value({1.0f, -1.0f, 0.0f}).subtype(PROP_DISTANCE);
- b.add_input<decl::Vector>("Point 3").default_value({1.0f, 1.0f, 0.0f}).subtype(PROP_DISTANCE);
- b.add_input<decl::Vector>("Point 4").default_value({-1.0f, 1.0f, 0.0f}).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Float>(N_("Width")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Height")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Bottom Width"))
+ .default_value(4.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Top Width")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Offset")).default_value(1.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Bottom Height"))
+ .default_value(3.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Top Height")).default_value(1.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Vector>(N_("Point 1"))
+ .default_value({-1.0f, -1.0f, 0.0f})
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Vector>(N_("Point 2"))
+ .default_value({1.0f, -1.0f, 0.0f})
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Vector>(N_("Point 3"))
+ .default_value({1.0f, 1.0f, 0.0f})
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Vector>(N_("Point 4"))
+ .default_value({-1.0f, 1.0f, 0.0f})
+ .subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
index 7292fafc8b0..1dc9cd7f107 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -22,13 +22,17 @@ namespace blender::nodes {
static void geo_node_curve_primitive_spiral_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Resolution").default_value(32).min(1).max(1024).subtype(PROP_UNSIGNED);
- b.add_input<decl::Float>("Rotations").default_value(2.0f).min(0.0f);
- b.add_input<decl::Float>("Start Radius").default_value(1.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("End Radius").default_value(2.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Height").default_value(2.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Bool>("Reverse");
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Int>(N_("Resolution"))
+ .default_value(32)
+ .min(1)
+ .max(1024)
+ .subtype(PROP_UNSIGNED);
+ b.add_input<decl::Float>(N_("Rotations")).default_value(2.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Start Radius")).default_value(1.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("End Radius")).default_value(2.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Height")).default_value(2.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Bool>(N_("Reverse"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
index 6261146562d..b5bafce17c6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
@@ -22,11 +22,17 @@ namespace blender::nodes {
static void geo_node_curve_primitive_star_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Points").default_value(8).min(3).max(256).subtype(PROP_UNSIGNED);
- b.add_input<decl::Float>("Inner Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Outer Radius").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Twist").subtype(PROP_ANGLE);
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Int>(N_("Points")).default_value(8).min(3).max(256).subtype(PROP_UNSIGNED);
+ b.add_input<decl::Float>(N_("Inner Radius"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Outer Radius"))
+ .default_value(2.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Twist")).subtype(PROP_ANGLE);
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index 2617b2f6646..945dac5650b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -34,11 +34,14 @@ namespace blender::nodes {
static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Count").default_value(10).min(1).max(100000).supports_field();
- b.add_input<decl::Float>("Length").default_value(0.1f).min(0.001f).supports_field().subtype(
- PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Int>(N_("Count")).default_value(10).min(1).max(100000).supports_field();
+ b.add_input<decl::Float>(N_("Length"))
+ .default_value(0.1f)
+ .min(0.001f)
+ .supports_field()
+ .subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_resample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -79,7 +82,7 @@ static SplinePtr resample_spline(const Spline &src, const int count)
Spline::copy_base_settings(src, *dst);
if (src.evaluated_edges_size() < 1 || count == 1) {
- dst->add_point(src.positions().first(), src.tilts().first(), src.radii().first());
+ dst->add_point(src.positions().first(), src.radii().first(), src.tilts().first());
dst->attributes.reallocate(1);
src.attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
@@ -234,7 +237,7 @@ static void geometry_set_curve_resample(GeometrySet &geometry_set,
static void geo_node_resample_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)params.node().storage;
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
@@ -244,7 +247,7 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) {
Field<int> count = params.extract_input<Field<int>>("Count");
if (count < 1) {
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Curve", GeometrySet());
return;
}
mode_param.count.emplace(count);
@@ -257,7 +260,7 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
geometry_set.modify_geometry_sets(
[&](GeometrySet &geometry_set) { geometry_set_curve_resample(geometry_set, mode_param); });
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Curve", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index d4ccb768713..745012c1851 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -24,9 +24,9 @@ namespace blender::nodes {
static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
index 6d371c27d43..31b38c0dce7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -27,13 +27,15 @@ namespace blender::nodes {
static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Float>("Factor").min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
- b.add_input<decl::Float>("Length").min(0.0f).subtype(PROP_DISTANCE).supports_field();
-
- b.add_output<decl::Vector>("Position").dependent_field();
- b.add_output<decl::Vector>("Tangent").dependent_field();
- b.add_output<decl::Vector>("Normal").dependent_field();
+ b.add_input<decl::Geometry>(N_("Curve"))
+ .only_realized_data()
+ .supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Float>(N_("Factor")).min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
+ b.add_input<decl::Float>(N_("Length")).min(0.0f).subtype(PROP_DISTANCE).supports_field();
+
+ b.add_output<decl::Vector>(N_("Position")).dependent_field();
+ b.add_output<decl::Vector>(N_("Tangent")).dependent_field();
+ b.add_output<decl::Vector>(N_("Normal")).dependent_field();
}
static void geo_node_curve_sample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -237,12 +239,6 @@ static void geo_node_curve_sample_exec(GeoNodeExecParams params)
params.set_output("Normal", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
};
- if (geometry_set.has_instances()) {
- params.error_message_add(
- NodeWarningType::Info,
- TIP_("The node only supports realized curve data, instances are ignored"));
- }
-
const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
if (component == nullptr) {
return return_default();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
index 9e7ac60c29d..8b0a6ca840c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
@@ -25,9 +25,9 @@ namespace blender::nodes {
static void geo_node_curve_set_handles_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_set_handles_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index ec72154db13..ae4453929ac 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -27,9 +27,9 @@ namespace blender::nodes {
static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_spline_type_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index 5a79fcffd4d..b52de822c22 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -33,9 +33,9 @@ namespace blender::nodes {
static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Cuts").default_value(1).min(0).max(1000).supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Int>(N_("Cuts")).default_value(1).min(0).max(1000).supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static Array<int> get_subdivided_offsets(const Spline &spline,
@@ -328,7 +328,7 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
static void geo_node_subdivide_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<int> cuts_field = params.extract_input<Field<int>>("Cuts");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
@@ -352,7 +352,7 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params)
std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts);
geometry_set.replace_curve(output_curve.release());
});
- params.set_output("Geometry", geometry_set);
+ params.set_output("Curve", geometry_set);
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index 00451946af9..1977b465de4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -27,21 +27,29 @@ namespace blender::nodes {
static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Geometry>("Profile Curve");
- b.add_output<decl::Geometry>("Mesh");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Geometry>(N_("Profile Curve"))
+ .only_realized_data()
+ .supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Fill Caps"))
+ .description(
+ N_("If the profile spline is cyclic, fill the ends of the generated mesh with N-gons"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geometry_set_curve_to_mesh(GeometrySet &geometry_set, const GeometrySet &profile_set)
+static void geometry_set_curve_to_mesh(GeometrySet &geometry_set,
+ const GeometrySet &profile_set,
+ const bool fill_caps)
{
+ const CurveEval *curve = geometry_set.get_curve_for_read();
const CurveEval *profile_curve = profile_set.get_curve_for_read();
if (profile_curve == nullptr) {
- Mesh *mesh = bke::curve_to_wire_mesh(*geometry_set.get_curve_for_read());
+ Mesh *mesh = bke::curve_to_wire_mesh(*curve);
geometry_set.replace_mesh(mesh);
}
else {
- Mesh *mesh = bke::curve_to_mesh_sweep(*geometry_set.get_curve_for_read(), *profile_curve);
+ Mesh *mesh = bke::curve_to_mesh_sweep(*curve, *profile_curve, fill_caps);
geometry_set.replace_mesh(mesh);
}
}
@@ -50,33 +58,17 @@ static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve");
-
- if (profile_set.has_instances()) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("Instances are not supported in the profile input"));
- params.set_output("Mesh", GeometrySet());
- return;
- }
-
- if (!profile_set.has_curve() && !profile_set.is_empty()) {
- params.error_message_add(NodeWarningType::Warning,
- TIP_("No curve data available in the profile input"));
- }
+ const bool fill_caps = params.extract_input<bool>("Fill Caps");
bool has_curve = false;
curve_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (geometry_set.has_curve()) {
has_curve = true;
- geometry_set_curve_to_mesh(geometry_set, profile_set);
+ geometry_set_curve_to_mesh(geometry_set, profile_set, fill_caps);
}
geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
});
- if (!has_curve && !curve_set.is_empty()) {
- params.error_message_add(NodeWarningType::Warning,
- TIP_("No curve data available in curve input"));
- }
-
params.set_output("Mesh", std::move(curve_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index 4f4fde6c7df..38d7fb99e87 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -30,13 +30,13 @@ namespace blender::nodes {
static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Int>("Count").default_value(10).min(2).max(100000);
- b.add_input<decl::Float>("Length").default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Points");
- b.add_output<decl::Vector>("Tangent").field_source();
- b.add_output<decl::Vector>("Normal").field_source();
- b.add_output<decl::Vector>("Rotation").field_source();
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000);
+ b.add_input<decl::Float>(N_("Length")).default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Points"));
+ b.add_output<decl::Vector>(N_("Tangent")).field_source();
+ b.add_output<decl::Vector>(N_("Normal")).field_source();
+ b.add_output<decl::Vector>(N_("Rotation")).field_source();
}
static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -357,17 +357,20 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
if (attribute_outputs.tangent_id) {
params.set_output(
"Tangent",
- AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.tangent_id)));
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.tangent_id),
+ params.attribute_producer_name()));
}
if (attribute_outputs.normal_id) {
params.set_output(
"Normal",
- AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id)));
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id),
+ params.attribute_producer_name()));
}
if (attribute_outputs.rotation_id) {
params.set_output(
"Rotation",
- AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id)));
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id),
+ params.attribute_producer_name()));
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index 6b049b4d384..4e1a2910c7c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -28,21 +28,24 @@ namespace blender::nodes {
static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Float>("Start").min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
- b.add_input<decl::Float>("End")
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Float>(N_("Start")).min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
+ b.add_input<decl::Float>(N_("End"))
.min(0.0f)
.max(1.0f)
.default_value(1.0f)
.subtype(PROP_FACTOR)
.supports_field();
- b.add_input<decl::Float>("Start", "Start_001").min(0.0f).subtype(PROP_DISTANCE).supports_field();
- b.add_input<decl::Float>("End", "End_001")
+ b.add_input<decl::Float>(N_("Start"), "Start_001")
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .supports_field();
+ b.add_input<decl::Float>(N_("End"), "End_001")
.min(0.0f)
.default_value(1.0f)
.subtype(PROP_DISTANCE)
.supports_field();
- b.add_output<decl::Geometry>("Curve");
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_curve_trim_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index e293cd9b8fe..e0a3faaefb0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -50,13 +50,13 @@ namespace blender::nodes {
static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection"))
.default_value(true)
.hide_value()
.supports_field()
- .description("The parts of the geometry to be deleted");
- b.add_output<decl::Geometry>("Geometry");
+ .description(N_("The parts of the geometry to be deleted"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_delete_geometry_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
index 0d481011f00..fa439b04da0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
@@ -42,22 +42,22 @@ namespace blender::nodes {
static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Float>("Distance Min").min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Density Max").default_value(10.0f).min(0.0f);
- b.add_input<decl::Float>("Density").default_value(10.0f).supports_field();
- b.add_input<decl::Float>("Density Factor")
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Density Max")).default_value(10.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Density")).default_value(10.0f).supports_field();
+ b.add_input<decl::Float>(N_("Density Factor"))
.default_value(1.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR)
.supports_field();
- b.add_input<decl::Int>("Seed");
+ b.add_input<decl::Int>(N_("Seed"));
- b.add_output<decl::Geometry>("Points");
- b.add_output<decl::Vector>("Normal").field_source();
- b.add_output<decl::Vector>("Rotation").subtype(PROP_EULER).field_source();
+ b.add_output<decl::Geometry>(N_("Points"));
+ b.add_output<decl::Vector>(N_("Normal")).field_source();
+ b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).field_source();
}
static void geo_node_point_distribute_points_on_faces_layout(uiLayout *layout,
@@ -533,7 +533,7 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
const GeometryNodeDistributePointsOnFacesMode method =
static_cast<GeometryNodeDistributePointsOnFacesMode>(params.node().custom1);
@@ -543,10 +543,10 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par
AttributeOutputs attribute_outputs;
if (params.output_is_required("Normal")) {
- attribute_outputs.normal_id = StrongAnonymousAttributeID("normal");
+ attribute_outputs.normal_id = StrongAnonymousAttributeID("Normal");
}
if (params.output_is_required("Rotation")) {
- attribute_outputs.rotation_id = StrongAnonymousAttributeID("rotation");
+ attribute_outputs.rotation_id = StrongAnonymousAttributeID("Rotation");
}
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
@@ -562,12 +562,14 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par
if (attribute_outputs.normal_id) {
params.set_output(
"Normal",
- AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id)));
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id),
+ params.attribute_producer_name()));
}
if (attribute_outputs.rotation_id) {
params.set_output(
"Rotation",
- AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id)));
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id),
+ params.attribute_producer_name()));
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index e97fc5c2c83..f562fb29e90 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -26,9 +26,9 @@ namespace blender::nodes {
static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Mesh");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_output<decl::Geometry>("Mesh");
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
new file mode 100644
index 00000000000..e1c72fbd438
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
@@ -0,0 +1,429 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_geometry_util.hh"
+
+#include "BKE_image.h"
+
+#include "BLI_float4.hh"
+#include "BLI_threads.h"
+#include "BLI_timeit.hh"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+static void geo_node_image_texture_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Image>(N_("Image")).hide_label();
+ b.add_input<decl::Vector>(N_("Vector"))
+ .implicit_field()
+ .description(("Texture coordinates from 0 to 1"));
+ b.add_input<decl::Int>(N_("Frame")).min(0).max(MAXFRAMEF);
+ b.add_output<decl::Color>(N_("Color")).no_muted_links().dependent_field();
+ b.add_output<decl::Float>(N_("Alpha")).no_muted_links().dependent_field();
+}
+
+static void geo_node_image_texture_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "extension", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+static void geo_node_image_texture_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryImageTexture *tex = (NodeGeometryImageTexture *)MEM_callocN(
+ sizeof(NodeGeometryImageTexture), __func__);
+ node->storage = tex;
+}
+
+class ImageFieldsFunction : public fn::MultiFunction {
+ private:
+ const int interpolation_;
+ const int extension_;
+ Image &image_;
+ ImageUser image_user_;
+ void *image_lock_;
+ ImBuf *image_buffer_;
+
+ public:
+ ImageFieldsFunction(const int interpolation,
+ const int extension,
+ Image &image,
+ ImageUser image_user)
+ : interpolation_(interpolation),
+ extension_(extension),
+ image_(image),
+ image_user_(image_user)
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+
+ image_buffer_ = BKE_image_acquire_ibuf(&image_, &image_user_, &image_lock_);
+ if (image_buffer_ == nullptr) {
+ throw std::runtime_error("cannot aquire image buffer");
+ }
+
+ if (image_buffer_->rect_float == nullptr) {
+ BLI_thread_lock(LOCK_IMAGE);
+ if (!image_buffer_->rect_float) {
+ IMB_float_from_rect(image_buffer_);
+ }
+ BLI_thread_unlock(LOCK_IMAGE);
+ }
+
+ if (image_buffer_->rect_float == nullptr) {
+ BKE_image_release_ibuf(&image_, image_buffer_, image_lock_);
+ throw std::runtime_error("cannot get float buffer");
+ }
+ }
+
+ ~ImageFieldsFunction() override
+ {
+ BKE_image_release_ibuf(&image_, image_buffer_, image_lock_);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"ImageFunction"};
+ signature.single_input<float3>("Vector");
+ signature.single_output<ColorGeometry4f>("Color");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ static int wrap_periodic(int x, const int width)
+ {
+ x %= width;
+ if (x < 0) {
+ x += width;
+ }
+ return x;
+ }
+
+ static int wrap_clamp(const int x, const int width)
+ {
+ return std::clamp(x, 0, width - 1);
+ }
+
+ static float4 image_pixel_lookup(const ImBuf *ibuf, const int px, const int py)
+ {
+ if (px < 0 || py < 0 || px >= ibuf->x || py >= ibuf->y) {
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ return ((const float4 *)ibuf->rect_float)[px + py * ibuf->x];
+ }
+
+ static float frac(const float x, int *ix)
+ {
+ const int i = (int)x - ((x < 0.0f) ? 1 : 0);
+ *ix = i;
+ return x - (float)i;
+ }
+
+ static float4 image_cubic_texture_lookup(const ImBuf *ibuf,
+ const float px,
+ const float py,
+ const int extension)
+ {
+ const int width = ibuf->x;
+ const int height = ibuf->y;
+ int pix, piy, nix, niy;
+ const float tx = frac(px * (float)width - 0.5f, &pix);
+ const float ty = frac(py * (float)height - 0.5f, &piy);
+ int ppix, ppiy, nnix, nniy;
+
+ switch (extension) {
+ case SHD_IMAGE_EXTENSION_REPEAT: {
+ pix = wrap_periodic(pix, width);
+ piy = wrap_periodic(piy, height);
+ ppix = wrap_periodic(pix - 1, width);
+ ppiy = wrap_periodic(piy - 1, height);
+ nix = wrap_periodic(pix + 1, width);
+ niy = wrap_periodic(piy + 1, height);
+ nnix = wrap_periodic(pix + 2, width);
+ nniy = wrap_periodic(piy + 2, height);
+ break;
+ }
+ case SHD_IMAGE_EXTENSION_CLIP: {
+ ppix = pix - 1;
+ ppiy = piy - 1;
+ nix = pix + 1;
+ niy = piy + 1;
+ nnix = pix + 2;
+ nniy = piy + 2;
+ break;
+ }
+ case SHD_IMAGE_EXTENSION_EXTEND: {
+ ppix = wrap_clamp(pix - 1, width);
+ ppiy = wrap_clamp(piy - 1, height);
+ nix = wrap_clamp(pix + 1, width);
+ niy = wrap_clamp(piy + 1, height);
+ nnix = wrap_clamp(pix + 2, width);
+ nniy = wrap_clamp(piy + 2, height);
+ pix = wrap_clamp(pix, width);
+ piy = wrap_clamp(piy, height);
+ break;
+ }
+ default:
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+
+ const int xc[4] = {ppix, pix, nix, nnix};
+ const int yc[4] = {ppiy, piy, niy, nniy};
+ float u[4], v[4];
+
+ u[0] = (((-1.0f / 6.0f) * tx + 0.5f) * tx - 0.5f) * tx + (1.0f / 6.0f);
+ u[1] = ((0.5f * tx - 1.0f) * tx) * tx + (2.0f / 3.0f);
+ u[2] = ((-0.5f * tx + 0.5f) * tx + 0.5f) * tx + (1.0f / 6.0f);
+ u[3] = (1.0f / 6.0f) * tx * tx * tx;
+
+ v[0] = (((-1.0f / 6.0f) * ty + 0.5f) * ty - 0.5f) * ty + (1.0f / 6.0f);
+ v[1] = ((0.5f * ty - 1.0f) * ty) * ty + (2.0f / 3.0f);
+ v[2] = ((-0.5f * ty + 0.5f) * ty + 0.5f) * ty + (1.0f / 6.0f);
+ v[3] = (1.0f / 6.0f) * ty * ty * ty;
+
+ return (v[0] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[0])) +
+ u[1] * (image_pixel_lookup(ibuf, xc[1], yc[0])) +
+ u[2] * (image_pixel_lookup(ibuf, xc[2], yc[0])) +
+ u[3] * (image_pixel_lookup(ibuf, xc[3], yc[0])))) +
+ (v[1] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[1])) +
+ u[1] * (image_pixel_lookup(ibuf, xc[1], yc[1])) +
+ u[2] * (image_pixel_lookup(ibuf, xc[2], yc[1])) +
+ u[3] * (image_pixel_lookup(ibuf, xc[3], yc[1])))) +
+ (v[2] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[2])) +
+ u[1] * (image_pixel_lookup(ibuf, xc[1], yc[2])) +
+ u[2] * (image_pixel_lookup(ibuf, xc[2], yc[2])) +
+ u[3] * (image_pixel_lookup(ibuf, xc[3], yc[2])))) +
+ (v[3] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[3])) +
+ u[1] * (image_pixel_lookup(ibuf, xc[1], yc[3])) +
+ u[2] * (image_pixel_lookup(ibuf, xc[2], yc[3])) +
+ u[3] * (image_pixel_lookup(ibuf, xc[3], yc[3]))));
+ }
+
+ static float4 image_linear_texture_lookup(const ImBuf *ibuf,
+ const float px,
+ const float py,
+ const int extension)
+ {
+ const int width = ibuf->x;
+ const int height = ibuf->y;
+ int pix, piy, nix, niy;
+ const float nfx = frac(px * (float)width - 0.5f, &pix);
+ const float nfy = frac(py * (float)height - 0.5f, &piy);
+
+ switch (extension) {
+ case SHD_IMAGE_EXTENSION_CLIP: {
+ nix = pix + 1;
+ niy = piy + 1;
+ break;
+ }
+ case SHD_IMAGE_EXTENSION_EXTEND: {
+ nix = wrap_clamp(pix + 1, width);
+ niy = wrap_clamp(piy + 1, height);
+ pix = wrap_clamp(pix, width);
+ piy = wrap_clamp(piy, height);
+ break;
+ }
+ default:
+ case SHD_IMAGE_EXTENSION_REPEAT:
+ pix = wrap_periodic(pix, width);
+ piy = wrap_periodic(piy, height);
+ nix = wrap_periodic(pix + 1, width);
+ niy = wrap_periodic(piy + 1, height);
+ break;
+ }
+
+ const float ptx = 1.0f - nfx;
+ const float pty = 1.0f - nfy;
+
+ return image_pixel_lookup(ibuf, pix, piy) * ptx * pty +
+ image_pixel_lookup(ibuf, nix, piy) * nfx * pty +
+ image_pixel_lookup(ibuf, pix, niy) * ptx * nfy +
+ image_pixel_lookup(ibuf, nix, niy) * nfx * nfy;
+ }
+
+ static float4 image_closest_texture_lookup(const ImBuf *ibuf,
+ const float px,
+ const float py,
+ const int extension)
+ {
+ const int width = ibuf->x;
+ const int height = ibuf->y;
+ int ix, iy;
+ const float tx = frac(px * (float)width - 0.5f, &ix);
+ const float ty = frac(py * (float)height - 0.5f, &iy);
+
+ switch (extension) {
+ case SHD_IMAGE_EXTENSION_REPEAT: {
+ ix = wrap_periodic(ix, width);
+ iy = wrap_periodic(iy, height);
+ return image_pixel_lookup(ibuf, ix, iy);
+ }
+ case SHD_IMAGE_EXTENSION_CLIP: {
+ if (tx < 0.0f || ty < 0.0f || tx > 1.0f || ty > 1.0f) {
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ if (ix < 0 || iy < 0 || ix > width || iy > height) {
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ ATTR_FALLTHROUGH;
+ }
+ case SHD_IMAGE_EXTENSION_EXTEND: {
+ ix = wrap_clamp(ix, width);
+ iy = wrap_clamp(iy, height);
+ return image_pixel_lookup(ibuf, ix, iy);
+ }
+ default:
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &vectors = params.readonly_single_input<float3>(0, "Vector");
+ MutableSpan<ColorGeometry4f> r_color = params.uninitialized_single_output<ColorGeometry4f>(
+ 1, "Color");
+ MutableSpan<float> r_alpha = params.uninitialized_single_output_if_required<float>(2, "Alpha");
+
+ MutableSpan<float4> color_data{(float4 *)r_color.data(), r_color.size()};
+
+ /* Sample image texture. */
+ switch (interpolation_) {
+ case SHD_INTERP_LINEAR:
+ for (const int64_t i : mask) {
+ const float3 p = vectors[i];
+ color_data[i] = image_linear_texture_lookup(image_buffer_, p.x, p.y, extension_);
+ }
+ break;
+ case SHD_INTERP_CLOSEST:
+ for (const int64_t i : mask) {
+ const float3 p = vectors[i];
+ color_data[i] = image_closest_texture_lookup(image_buffer_, p.x, p.y, extension_);
+ }
+ break;
+ case SHD_INTERP_CUBIC:
+ case SHD_INTERP_SMART:
+ for (const int64_t i : mask) {
+ const float3 p = vectors[i];
+ color_data[i] = image_cubic_texture_lookup(image_buffer_, p.x, p.y, extension_);
+ }
+ break;
+ }
+
+ int alpha_mode = image_.alpha_mode;
+ if (IMB_colormanagement_space_name_is_data(image_.colorspace_settings.name)) {
+ alpha_mode = IMA_ALPHA_CHANNEL_PACKED;
+ }
+
+ switch (alpha_mode) {
+ case IMA_ALPHA_STRAIGHT: {
+ /* #ColorGeometry expects premultiplied alpha, so convert from straight to that. */
+ for (int64_t i : mask) {
+ straight_to_premul_v4(color_data[i]);
+ }
+ break;
+ }
+ case IMA_ALPHA_PREMUL: {
+ /* Alpha is premultiplied already, nothing to do. */
+ break;
+ }
+ case IMA_ALPHA_CHANNEL_PACKED: {
+ /* Color and alpha channels shouldn't interact with each other, nothing to do. */
+ break;
+ }
+ case IMA_ALPHA_IGNORE: {
+ /* The image should be treated as being opaque. */
+ for (int64_t i : mask) {
+ color_data[i].w = 1.0f;
+ }
+ break;
+ }
+ }
+
+ if (!r_alpha.is_empty()) {
+ for (int64_t i : mask) {
+ r_alpha[i] = r_color[i].a;
+ }
+ }
+ }
+};
+
+static void geo_node_image_texture_exec(GeoNodeExecParams params)
+{
+ auto return_default = [&]() {
+ params.set_output("Color", ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
+ params.set_output("Alpha", 1.0f);
+ };
+
+ Image *image = params.get_input<Image *>("Image");
+ if (image == nullptr) {
+ return return_default();
+ }
+
+ const bNode &node = params.node();
+ NodeGeometryImageTexture *data = (NodeGeometryImageTexture *)node.storage;
+
+ ImageUser image_user;
+ BKE_imageuser_default(&image_user);
+ image_user.cycl = false;
+ image_user.frames = INT_MAX;
+ image_user.sfra = 1;
+ image_user.framenr = BKE_image_is_animated(image) ? params.get_input<int>("Frame") : 0;
+
+ std::unique_ptr<ImageFieldsFunction> image_fn;
+ try {
+ image_fn = std::make_unique<ImageFieldsFunction>(
+ data->interpolation, data->extension, *image, image_user);
+ }
+ catch (const std::runtime_error &) {
+ return return_default();
+ }
+
+ Field<float3> vector_field = params.extract_input<Field<float3>>("Vector");
+
+ auto image_op = std::make_shared<FieldOperation>(
+ FieldOperation(std::move(image_fn), {std::move(vector_field)}));
+
+ params.set_output("Color", Field<ColorGeometry4f>(image_op, 0));
+ params.set_output("Alpha", Field<float>(image_op, 1));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_image_texture(void)
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE, 0);
+ ntype.declare = blender::nodes::geo_node_image_texture_declare;
+ ntype.draw_buttons = blender::nodes::geo_node_image_texture_layout;
+ node_type_init(&ntype, blender::nodes::geo_node_image_texture_init);
+ node_type_storage(
+ &ntype, "NodeGeometryImageTexture", node_free_standard_storage, node_copy_standard_storage);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ ntype.geometry_node_execute = blender::nodes::geo_node_image_texture_exec;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
index 604b181918d..b8df545d073 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
@@ -20,8 +20,8 @@ namespace blender::nodes {
static void geo_node_input_curve_handles_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Left").field_source();
- b.add_output<decl::Vector>("Right").field_source();
+ b.add_output<decl::Vector>(N_("Left")).field_source();
+ b.add_output<decl::Vector>(N_("Right")).field_source();
}
static void geo_node_input_curve_handles_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
index 5a24b7f3f07..f32db3842db 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
@@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_input_curve_tilt_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Tilt").field_source();
+ b.add_output<decl::Float>(N_("Tilt")).field_source();
}
static void geo_node_input_curve_tilt_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
new file mode 100644
index 00000000000..37d5bac0325
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_input_id_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("ID")).field_source();
+}
+
+static void geo_node_input_id_exec(GeoNodeExecParams params)
+{
+ Field<int> position_field{std::make_shared<bke::IDAttributeFieldInput>()};
+ params.set_output("ID", std::move(position_field));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_input_id()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT, 0);
+ ntype.geometry_node_execute = blender::nodes::geo_node_input_id_exec;
+ ntype.declare = blender::nodes::geo_node_input_id_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
index 7fcbaf429dd..6200ac5e7a8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
@@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_input_index_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Int>("Index").field_source();
+ b.add_output<decl::Int>(N_("Index")).field_source();
}
static void geo_node_input_index_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
index 8e805bd1359..fc41188dee5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
@@ -23,7 +23,7 @@ namespace blender::nodes {
static void geo_node_input_material_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Material>("Material");
+ b.add_output<decl::Material>(N_("Material"));
}
static void geo_node_input_material_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
index 702c83daea0..5d5d9e40032 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
@@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_input_material_index_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Int>("Material Index").field_source();
+ b.add_output<decl::Int>(N_("Material Index")).field_source();
}
static void geo_node_input_material_index_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
index 5a2495afb9e..92b89313d23 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -28,7 +28,7 @@ namespace blender::nodes {
static void geo_node_input_normal_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Normal").field_source();
+ b.add_output<decl::Vector>(N_("Normal")).field_source();
}
static GVArrayPtr mesh_face_normals(const Mesh &mesh,
@@ -241,8 +241,9 @@ static const GVArray *construct_curve_normal_gvarray(const CurveComponent &compo
class NormalFieldInput final : public fn::FieldInput {
public:
- NormalFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Normal")
+ NormalFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Normal node")
{
+ category_ = Category::Generated;
}
const GVArray *get_varray_for_context(const fn::FieldContext &context,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
index 44874259e20..a8477d4bc4f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
@@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_input_position_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Position").field_source();
+ b.add_output<decl::Vector>(N_("Position")).field_source();
}
static void geo_node_input_position_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
index 586005511ad..6d2c4c38cbe 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
@@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_input_radius_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Radius").default_value(1.0f).min(0.0f).field_source();
+ b.add_output<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).field_source();
}
static void geo_node_input_radius_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
index de520787e78..dcd14b1c054 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
@@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_input_shade_smooth_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Bool>("Smooth").field_source();
+ b.add_output<decl::Bool>(N_("Smooth")).field_source();
}
static void geo_node_input_shade_smooth_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
index 44a1bb62de8..a8ee6dd8b12 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
@@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_input_spline_cyclic_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Bool>("Cyclic").field_source();
+ b.add_output<decl::Bool>(N_("Cyclic")).field_source();
}
static void geo_node_input_spline_cyclic_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index b5f3e1b0c28..895efa6f0ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -22,7 +22,7 @@ namespace blender::nodes {
static void geo_node_input_spline_length_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Length").field_source();
+ b.add_output<decl::Float>(N_("Length")).field_source();
}
static const GVArray *construct_spline_length_gvarray(const CurveComponent &component,
@@ -57,8 +57,9 @@ static const GVArray *construct_spline_length_gvarray(const CurveComponent &comp
class SplineLengthFieldInput final : public fn::FieldInput {
public:
- SplineLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Spline Length")
+ SplineLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Spline Length node")
{
+ category_ = Category::Generated;
}
const GVArray *get_varray_for_context(const fn::FieldContext &context,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
index eab95ebc46e..75fb8a13d38 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
@@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_input_spline_resolution_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Int>("Resolution").field_source();
+ b.add_output<decl::Int>(N_("Resolution")).field_source();
}
static void geo_node_input_spline_resolution_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
index d690642373a..6b1736fe2ac 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -24,7 +24,7 @@ namespace blender::nodes {
static void geo_node_input_tangent_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Tangent").field_source();
+ b.add_output<decl::Vector>(N_("Tangent")).field_source();
}
static void calculate_bezier_tangents(const BezierSpline &spline, MutableSpan<float3> tangents)
@@ -121,8 +121,9 @@ static const GVArray *construct_curve_tangent_gvarray(const CurveComponent &comp
class TangentFieldInput final : public fn::FieldInput {
public:
- TangentFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Tangent")
+ TangentFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Tangent node")
{
+ category_ = Category::Generated;
}
const GVArray *get_varray_for_context(const fn::FieldContext &context,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
index 78399fad2c0..aff29d973d4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
@@ -28,28 +28,29 @@ namespace blender::nodes {
static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Points").description("Points to instance on");
- b.add_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
- b.add_input<decl::Geometry>("Instance").description("Geometry that is instanced on the points");
- b.add_input<decl::Bool>("Pick Instance")
+ b.add_input<decl::Geometry>(N_("Points")).description(N_("Points to instance on"));
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_input<decl::Geometry>(N_("Instance"))
+ .description(N_("Geometry that is instanced on the points"));
+ b.add_input<decl::Bool>(N_("Pick Instance"))
.supports_field()
.description("Place different instances on different points");
- b.add_input<decl::Int>("Instance Index")
+ b.add_input<decl::Int>(N_("Instance Index"))
.implicit_field()
- .description(
+ .description(N_(
"Index of the instance that used for each point. This is only used when Pick Instances "
- "is on. By default the point index is used");
- b.add_input<decl::Vector>("Rotation")
+ "is on. By default the point index is used"));
+ b.add_input<decl::Vector>(N_("Rotation"))
.subtype(PROP_EULER)
.supports_field()
- .description("Rotation of the instances");
- b.add_input<decl::Vector>("Scale")
+ .description(N_("Rotation of the instances"));
+ b.add_input<decl::Vector>(N_("Scale"))
.default_value({1.0f, 1.0f, 1.0f})
.subtype(PROP_XYZ)
.supports_field()
- .description("Scale of the instances");
+ .description(N_("Scale of the instances"));
- b.add_output<decl::Geometry>("Instances");
+ b.add_output<decl::Geometry>(N_("Instances"));
}
static void add_instances_from_component(InstancesComponent &dst_component,
@@ -77,7 +78,6 @@ static void add_instances_from_component(InstancesComponent &dst_component,
select_len);
MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len,
select_len);
- MutableSpan<int> dst_stable_ids = dst_component.instance_ids().slice(start_len, select_len);
FieldEvaluator field_evaluator{field_context, domain_size};
const VArray<bool> *pick_instance = nullptr;
@@ -86,7 +86,6 @@ static void add_instances_from_component(InstancesComponent &dst_component,
const VArray<float3> *scales = nullptr;
/* The evaluator could use the component's stable IDs as a destination directly, but only the
* selected indices should be copied. */
- GVArray_Typed<int> stable_ids = src_component.attribute_get_for_read("id", ATTR_DOMAIN_POINT, 0);
field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance);
field_evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices);
field_evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations);
@@ -119,7 +118,6 @@ static void add_instances_from_component(InstancesComponent &dst_component,
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) {
for (const int range_i : selection_range) {
const int64_t i = selection[range_i];
- dst_stable_ids[range_i] = (*stable_ids)[i];
/* Compute base transform for every instances. */
float4x4 &dst_transform = dst_transforms[range_i];
@@ -157,6 +155,17 @@ static void add_instances_from_component(InstancesComponent &dst_component,
}
});
+ GVArrayPtr id_attribute = src_component.attribute_try_get_for_read(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (id_attribute) {
+ GVArray_Typed<int> ids{*id_attribute};
+ VArray_Span<int> ids_span{ids};
+ MutableSpan<int> dst_ids = dst_component.instance_ids_ensure();
+ for (const int64_t i : selection.index_range()) {
+ dst_ids[i] = ids_span[selection[i]];
+ }
+ }
+
if (pick_instance->is_single()) {
if (pick_instance->get_internal_single()) {
if (instance.has_realized_data()) {
@@ -194,11 +203,15 @@ static void geo_node_instance_on_points_exec(GeoNodeExecParams params)
instances, *geometry_set.get_component_for_read<CurveComponent>(), instance, params);
geometry_set.remove(GEO_COMPONENT_TYPE_CURVE);
}
- /* Unused references may have been added above. Remove those now so that other nodes don't
- * process them needlessly. */
- instances.remove_unused_references();
});
+ /* Unused references may have been added above. Remove those now so that other nodes don't
+ * process them needlessly.
+ * This should eventually be moved into the loop above, but currently this is quite tricky
+ * because it might remove references that the loop still wants to iterate over. */
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ instances.remove_unused_references();
+
params.set_output("Instances", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
index 63d1f88a442..c3955426e69 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -23,15 +23,15 @@ namespace blender::nodes {
static void geo_node_instances_to_points_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Instances");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Vector>("Position").implicit_field();
- b.add_input<decl::Float>("Radius")
+ b.add_input<decl::Geometry>(N_("Instances")).only_instances();
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Float>(N_("Radius"))
.default_value(0.05f)
.min(0.0f)
.subtype(PROP_DISTANCE)
.supports_field();
- b.add_output<decl::Geometry>("Points");
+ b.add_output<decl::Geometry>(N_("Points"));
}
template<typename T>
@@ -77,13 +77,15 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
const VArray<float> &radii = evaluator.get_evaluated<float>(1);
copy_attribute_to_points(radii, selection, {pointcloud->radius, pointcloud->totpoint});
- OutputAttribute_Typed<int> id_attribute = points.attribute_try_get_for_output<int>(
- "id", ATTR_DOMAIN_POINT, 0);
- MutableSpan<int> ids = id_attribute.as_span();
- for (const int i : selection.index_range()) {
- ids[i] = instances.instance_ids()[selection[i]];
+ if (!instances.instance_ids().is_empty()) {
+ OutputAttribute_Typed<int> id_attribute = points.attribute_try_get_for_output<int>(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ MutableSpan<int> ids = id_attribute.as_span();
+ for (const int i : selection.index_range()) {
+ ids[i] = instances.instance_ids()[selection[i]];
+ }
+ id_attribute.save();
}
- id_attribute.save();
}
static void geo_node_instances_to_points_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
index f8a1c764f61..8e0e98f7bd5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
@@ -22,7 +22,7 @@ namespace blender::nodes {
static void geo_node_is_viewport_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Bool>("Is Viewport");
+ b.add_output<decl::Bool>(N_("Is Viewport"));
}
static void geo_node_is_viewport_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index b628c5cbab8..cd385f364e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -33,8 +33,8 @@ namespace blender::nodes {
static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry").multi_input();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry")).multi_input();
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent *> src_components)
@@ -270,17 +270,16 @@ static void join_components(Span<const InstancesComponent *> src_components, Geo
}
Span<float4x4> src_transforms = src_component->instance_transforms();
- Span<int> src_ids = src_component->instance_ids();
Span<int> src_reference_handles = src_component->instance_reference_handles();
for (const int i : src_transforms.index_range()) {
const int src_handle = src_reference_handles[i];
const int dst_handle = handle_map[src_handle];
const float4x4 &transform = src_transforms[i];
- const int id = src_ids[i];
- dst_component.add_instance(dst_handle, transform, id);
+ dst_component.add_instance(dst_handle, transform);
}
}
+ join_attributes(to_base_components(src_components), dst_component, {"position"});
}
static void join_components(Span<const VolumeComponent *> src_components, GeometrySet &result)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
index f3562bed6e9..e4a62bd5267 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
@@ -28,10 +28,10 @@ namespace blender::nodes {
static void geo_node_material_replace_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Material>("Old");
- b.add_input<decl::Material>("New");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Material>(N_("Old"));
+ b.add_input<decl::Material>(N_("New"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_material_replace_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
index 9d4533b9bda..06c770820ee 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -30,8 +30,8 @@ namespace blender::nodes {
static void geo_node_material_selection_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Material>("Material").hide_label(true);
- b.add_output<decl::Bool>("Selection").field_source();
+ b.add_input<decl::Material>(N_("Material")).hide_label(true);
+ b.add_output<decl::Bool>(N_("Selection")).field_source();
}
static void select_mesh_by_material(const Mesh &mesh,
@@ -59,8 +59,9 @@ class MaterialSelectionFieldInput final : public fn::FieldInput {
public:
MaterialSelectionFieldInput(Material *material)
- : fn::FieldInput(CPPType::get<bool>(), "Material Selection"), material_(material)
+ : fn::FieldInput(CPPType::get<bool>(), "Material Selection node"), material_(material)
{
+ category_ = Category::Generated;
}
const GVArray *get_varray_for_context(const fn::FieldContext &context,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index 9c477c639a2..685a8faff5c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -29,9 +29,9 @@ namespace blender::nodes {
static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Vertices").default_value(32).min(3);
- b.add_input<decl::Float>("Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Int>(N_("Vertices")).default_value(32).min(3);
+ b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geo_node_mesh_primitive_circle_layout(uiLayout *layout,
@@ -204,7 +204,7 @@ static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params)
const int verts_num = params.extract_input<int>("Vertices");
if (verts_num < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Mesh", GeometrySet());
return;
}
@@ -212,7 +212,7 @@ static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params)
BLI_assert(BKE_mesh_is_valid(mesh));
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index 93c35a1111b..206d48d40c8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -29,13 +29,16 @@ namespace blender::nodes {
static void geo_node_mesh_primitive_cone_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Vertices").default_value(32).min(3).max(512);
- b.add_input<decl::Int>("Side Segments").default_value(1).min(1).max(512);
- b.add_input<decl::Int>("Fill Segments").default_value(1).min(1).max(512);
- b.add_input<decl::Float>("Radius Top").min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Radius Bottom").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Depth").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Int>(N_("Vertices")).default_value(32).min(3).max(512);
+ b.add_input<decl::Int>(N_("Side Segments")).default_value(1).min(1).max(512);
+ b.add_input<decl::Int>(N_("Fill Segments")).default_value(1).min(1).max(512);
+ b.add_input<decl::Float>(N_("Radius Top")).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Radius Bottom"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Depth")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node)
@@ -708,14 +711,14 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
const int circle_segments = params.extract_input<int>("Vertices");
if (circle_segments < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Mesh", GeometrySet());
return;
}
const int side_segments = params.extract_input<int>("Side Segments");
if (side_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1"));
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Mesh", GeometrySet());
return;
}
@@ -723,7 +726,7 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments");
if (fill_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1"));
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Mesh", GeometrySet());
return;
}
@@ -737,7 +740,7 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
/* Transform the mesh so that the base of the cone is at the origin. */
BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
index 5a520d36296..3a211993bdc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
@@ -26,11 +26,14 @@ namespace blender::nodes {
static void geo_node_mesh_primitive_cube_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>("Size").default_value(float3(1)).min(0.0f).subtype(PROP_TRANSLATION);
- b.add_input<decl::Int>("Vertices X").default_value(2).min(2).max(1000);
- b.add_input<decl::Int>("Vertices Y").default_value(2).min(2).max(1000);
- b.add_input<decl::Int>("Vertices Z").default_value(2).min(2).max(1000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Vector>(N_("Size"))
+ .default_value(float3(1))
+ .min(0.0f)
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Int>(N_("Vertices X")).default_value(2).min(2).max(1000);
+ b.add_input<decl::Int>(N_("Vertices Y")).default_value(2).min(2).max(1000);
+ b.add_input<decl::Int>(N_("Vertices Z")).default_value(2).min(2).max(1000);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
struct CuboidConfig {
@@ -476,13 +479,13 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
const int verts_z = params.extract_input<int>("Vertices Z");
if (verts_x < 1 || verts_y < 1 || verts_z < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 1"));
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Mesh", GeometrySet());
return;
}
Mesh *mesh = create_cube_mesh(size, verts_x, verts_y, verts_z);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
index 287ea896ade..3bcf42b40b1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
@@ -29,32 +29,32 @@ namespace blender::nodes {
static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Vertices")
+ b.add_input<decl::Int>(N_("Vertices"))
.default_value(32)
.min(3)
.max(512)
- .description("The number of vertices around the circumference");
- b.add_input<decl::Int>("Side Segments")
+ .description(N_("The number of vertices around the circumference"));
+ b.add_input<decl::Int>(N_("Side Segments"))
.default_value(1)
.min(1)
.max(512)
- .description("The number of segments along the side");
- b.add_input<decl::Int>("Fill Segments")
+ .description(N_("The number of segments along the side"));
+ b.add_input<decl::Int>(N_("Fill Segments"))
.default_value(1)
.min(1)
.max(512)
- .description("The number of concentric segments of the fill");
- b.add_input<decl::Float>("Radius")
+ .description(N_("The number of concentric segments of the fill"));
+ b.add_input<decl::Float>(N_("Radius"))
.default_value(1.0f)
.min(0.0f)
.subtype(PROP_DISTANCE)
- .description("The radius of the cylinder");
- b.add_input<decl::Float>("Depth")
+ .description(N_("The radius of the cylinder"));
+ b.add_input<decl::Float>(N_("Depth"))
.default_value(2.0f)
.min(0.0f)
.subtype(PROP_DISTANCE)
- .description("The height of the cylinder on the Z axis");
- b.add_output<decl::Geometry>("Geometry");
+ .description(N_("The height of the cylinder on the Z axis"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout,
@@ -102,14 +102,14 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
const int circle_segments = params.extract_input<int>("Vertices");
if (circle_segments < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Mesh", GeometrySet());
return;
}
const int side_segments = params.extract_input<int>("Side Segments");
if (side_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1"));
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Mesh", GeometrySet());
return;
}
@@ -117,7 +117,7 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments");
if (fill_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1"));
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Mesh", GeometrySet());
return;
}
@@ -125,7 +125,7 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
Mesh *mesh = create_cylinder_or_cone_mesh(
radius, radius, depth, circle_segments, side_segments, fill_segments, fill_type);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 858ef8648f8..c4e476981c1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -29,11 +29,11 @@ namespace blender::nodes {
static void geo_node_mesh_primitive_grid_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Size X").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Size Y").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Int>("Vertices X").default_value(3).min(2).max(1000);
- b.add_input<decl::Int>("Vertices Y").default_value(3).min(2).max(1000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Float>(N_("Size X")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Size Y")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Int>(N_("Vertices X")).default_value(3).min(2).max(1000);
+ b.add_input<decl::Int>(N_("Vertices Y")).default_value(3).min(2).max(1000);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void calculate_uvs(
@@ -160,7 +160,7 @@ static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params)
const int verts_x = params.extract_input<int>("Vertices X");
const int verts_y = params.extract_input<int>("Vertices Y");
if (verts_x < 1 || verts_y < 1) {
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Mesh", GeometrySet());
return;
}
@@ -168,7 +168,7 @@ static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params)
BLI_assert(BKE_mesh_is_valid(mesh));
BKE_id_material_eval_ensure_default_slot(&mesh->id);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
index 5ea7165ac31..da3dfef3aea 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
@@ -28,9 +28,9 @@ namespace blender::nodes {
static void geo_node_mesh_primitive_ico_sphere_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Int>("Subdivisions").default_value(1).min(1).max(7);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Int>(N_("Subdivisions")).default_value(1).min(1).max(7);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius)
@@ -66,7 +66,7 @@ static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params)
const float radius = params.extract_input<float>("Radius");
Mesh *mesh = create_ico_sphere_mesh(subdivisions, radius);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index 031223b5ca6..6515afe5966 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -29,11 +29,13 @@ namespace blender::nodes {
static void geo_node_mesh_primitive_line_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Count").default_value(10).min(1).max(10000);
- b.add_input<decl::Float>("Resolution").default_value(1.0f).min(0.1f).subtype(PROP_DISTANCE);
- b.add_input<decl::Vector>("Start Location").subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Offset").default_value({0.0f, 0.0f, 1.0f}).subtype(PROP_TRANSLATION);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Int>(N_("Count")).default_value(10).min(1).max(10000);
+ b.add_input<decl::Float>(N_("Resolution")).default_value(1.0f).min(0.1f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Vector>(N_("Start Location")).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Offset"))
+ .default_value({0.0f, 0.0f, 1.0f})
+ .subtype(PROP_TRANSLATION);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geo_node_mesh_primitive_line_layout(uiLayout *layout,
@@ -154,7 +156,7 @@ static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
mesh = create_line_mesh(start, delta, count);
}
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index 6fd6cdf5747..54a762fc15d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -29,10 +29,10 @@ namespace blender::nodes {
static void geo_node_mesh_primitive_uv_shpere_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Segments").default_value(32).min(3).max(1024);
- b.add_input<decl::Int>("Rings").default_value(16).min(2).max(1024);
- b.add_input<decl::Float>("Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Int>(N_("Segments")).default_value(32).min(3).max(1024);
+ b.add_input<decl::Int>(N_("Rings")).default_value(16).min(2).max(1024);
+ b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static int sphere_vert_total(const int segments, const int rings)
@@ -291,14 +291,14 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
if (rings_num < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Rings must be at least 3"));
}
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Mesh", GeometrySet());
return;
}
const float radius = params.extract_input<float>("Radius");
Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
index d1dd5b1bf8b..d99c0c851a8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -27,9 +27,9 @@ namespace blender::nodes {
static void geo_node_mesh_subdivide_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Level").default_value(1).min(0).max(6);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int level)
@@ -74,12 +74,12 @@ static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int lev
static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
#ifndef WITH_OPENSUBDIV
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenSubdiv"));
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Mesh", std::move(geometry_set));
return;
#endif
@@ -87,14 +87,14 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 11);
if (subdiv_level == 0) {
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Mesh", std::move(geometry_set));
return;
}
geometry_set.modify_geometry_sets(
[&](GeometrySet &geometry_set) { geometry_set_mesh_subdivide(geometry_set, subdiv_level); });
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Mesh", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index 7bca9ec141b..11865c635b8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -22,9 +22,9 @@ namespace blender::nodes {
static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Mesh");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
index df0fdd8eccd..92911e89f59 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
@@ -30,15 +30,15 @@ namespace blender::nodes {
static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Mesh");
- b.add_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
- b.add_input<decl::Vector>("Position").implicit_field();
- b.add_input<decl::Float>("Radius")
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Float>(N_("Radius"))
.default_value(0.05f)
.min(0.0f)
.subtype(PROP_DISTANCE)
.supports_field();
- b.add_output<decl::Geometry>("Points");
+ b.add_output<decl::Geometry>(N_("Points"));
}
static void geo_node_mesh_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index e61709ed86a..3ba32c4b674 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -25,15 +25,15 @@ namespace blender::nodes {
static void geo_node_object_info_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Object>("Object").hide_label();
- b.add_input<decl::Bool>("As Instance")
+ b.add_input<decl::Object>(N_("Object")).hide_label();
+ b.add_input<decl::Bool>(N_("As Instance"))
.description(
- "Output the entire object as single instance. "
- "This allows instancing non-geometry object types");
- b.add_output<decl::Vector>("Location");
- b.add_output<decl::Vector>("Rotation");
- b.add_output<decl::Vector>("Scale");
- b.add_output<decl::Geometry>("Geometry");
+ N_("Output the entire object as single instance. "
+ "This allows instancing non-geometry object types"));
+ b.add_output<decl::Vector>(N_("Location"));
+ b.add_output<decl::Vector>(N_("Rotation"));
+ b.add_output<decl::Vector>(N_("Scale"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_object_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
index afd0ced6360..3e0096824d3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
@@ -27,9 +27,9 @@ namespace blender::nodes {
static void geo_node_points_to_vertices_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Points");
- b.add_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
- b.add_output<decl::Geometry>("Mesh");
+ b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
template<typename T>
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index 719523f64f0..312ea7df919 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -32,16 +32,16 @@ namespace blender::nodes {
static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Float>("Density").default_value(1.0f).min(0.0f);
- b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Voxel Amount").default_value(64.0f).min(0.0f);
- b.add_input<decl::Float>("Radius")
+ b.add_input<decl::Geometry>(N_("Points"));
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Radius"))
.default_value(0.5f)
.min(0.0f)
.subtype(PROP_DISTANCE)
.supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_output<decl::Geometry>(N_("Volume"));
}
static void geo_node_points_to_volume_layout(uiLayout *layout,
@@ -239,17 +239,17 @@ static void initialize_volume_component_from_points(GeoNodeExecParams &params,
static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
#ifdef WITH_OPENVDB
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
initialize_volume_component_from_points(params, geometry_set);
});
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Volume", std::move(geometry_set));
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenVDB"));
- params.set_output("Geometry", GeometrySet());
+ params.set_output("Volume", GeometrySet());
#endif
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
index ec4d6ceb728..c05476b982b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
@@ -31,10 +31,12 @@ namespace blender::nodes {
static void geo_node_proximity_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Target");
- b.add_input<decl::Vector>("Source Position").implicit_field();
- b.add_output<decl::Vector>("Position").dependent_field();
- b.add_output<decl::Float>("Distance").dependent_field();
+ b.add_input<decl::Geometry>(N_("Target"))
+ .only_realized_data()
+ .supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD});
+ b.add_input<decl::Vector>(N_("Source Position")).implicit_field();
+ b.add_output<decl::Vector>(N_("Position")).dependent_field();
+ b.add_output<decl::Float>(N_("Distance")).dependent_field();
}
static void geo_node_proximity_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -214,12 +216,6 @@ static void geo_node_proximity_exec(GeoNodeExecParams params)
params.set_output("Distance", fn::make_constant_field<float>(0.0f));
};
- if (geometry_set_target.has_instances()) {
- params.error_message_add(
- NodeWarningType::Info,
- TIP_("The node only supports realized mesh or point cloud data, instances are ignored"));
- }
-
if (!geometry_set_target.has_mesh() && !geometry_set_target.has_pointcloud()) {
return return_default();
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index 1e687f163e6..34946b1115c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -31,32 +31,36 @@ namespace blender::nodes {
static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Target Geometry");
-
- b.add_input<decl::Vector>("Attribute").hide_value().supports_field();
- b.add_input<decl::Float>("Attribute", "Attribute_001").hide_value().supports_field();
- b.add_input<decl::Color>("Attribute", "Attribute_002").hide_value().supports_field();
- b.add_input<decl::Bool>("Attribute", "Attribute_003").hide_value().supports_field();
- b.add_input<decl::Int>("Attribute", "Attribute_004").hide_value().supports_field();
-
- b.add_input<decl::Vector>("Source Position").implicit_field();
- b.add_input<decl::Vector>("Ray Direction").default_value({0.0f, 0.0f, 1.0f}).supports_field();
- b.add_input<decl::Float>("Ray Length")
+ b.add_input<decl::Geometry>(N_("Target Geometry"))
+ .only_realized_data()
+ .supported_type(GEO_COMPONENT_TYPE_MESH);
+
+ b.add_input<decl::Vector>(N_("Attribute")).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
+ b.add_input<decl::Color>(N_("Attribute"), "Attribute_002").hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Attribute"), "Attribute_003").hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Attribute"), "Attribute_004").hide_value().supports_field();
+
+ b.add_input<decl::Vector>(N_("Source Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Ray Direction"))
+ .default_value({0.0f, 0.0f, -1.0f})
+ .supports_field();
+ b.add_input<decl::Float>(N_("Ray Length"))
.default_value(100.0f)
.min(0.0f)
.subtype(PROP_DISTANCE)
.supports_field();
- b.add_output<decl::Bool>("Is Hit").dependent_field();
- b.add_output<decl::Vector>("Hit Position").dependent_field();
- b.add_output<decl::Vector>("Hit Normal").dependent_field();
- b.add_output<decl::Float>("Hit Distance").dependent_field();
+ b.add_output<decl::Bool>(N_("Is Hit")).dependent_field();
+ b.add_output<decl::Vector>(N_("Hit Position")).dependent_field();
+ b.add_output<decl::Vector>(N_("Hit Normal")).dependent_field();
+ b.add_output<decl::Float>(N_("Hit Distance")).dependent_field();
- b.add_output<decl::Vector>("Attribute").dependent_field({1, 2, 3, 4, 5, 6});
- b.add_output<decl::Float>("Attribute", "Attribute_001").dependent_field({1, 2, 3, 4, 5, 6});
- b.add_output<decl::Color>("Attribute", "Attribute_002").dependent_field({1, 2, 3, 4, 5, 6});
- b.add_output<decl::Bool>("Attribute", "Attribute_003").dependent_field({1, 2, 3, 4, 5, 6});
- b.add_output<decl::Int>("Attribute", "Attribute_004").dependent_field({1, 2, 3, 4, 5, 6});
+ b.add_output<decl::Vector>(N_("Attribute")).dependent_field({1, 2, 3, 4, 5, 6});
+ b.add_output<decl::Float>(N_("Attribute"), "Attribute_001").dependent_field({1, 2, 3, 4, 5, 6});
+ b.add_output<decl::Color>(N_("Attribute"), "Attribute_002").dependent_field({1, 2, 3, 4, 5, 6});
+ b.add_output<decl::Bool>(N_("Attribute"), "Attribute_003").dependent_field({1, 2, 3, 4, 5, 6});
+ b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({1, 2, 3, 4, 5, 6});
}
static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -389,26 +393,11 @@ static void geo_node_raycast_exec(GeoNodeExecParams params)
});
};
- if (target.has_instances()) {
- if (target.has_realized_data()) {
- params.error_message_add(
- NodeWarningType::Info,
- TIP_("The node only supports realized mesh data, instances are ignored"));
- }
- else {
- params.error_message_add(NodeWarningType::Error,
- TIP_("The target geometry must contain realized data"));
- return return_default();
- }
- }
-
if (target.is_empty()) {
return return_default();
}
if (!target.has_mesh()) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("The target geometry must contain a mesh"));
return return_default();
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
index 3be79d5ba3b..6c51c1f738f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
@@ -23,8 +23,8 @@ namespace blender::nodes {
static void geo_node_realize_instances_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void geo_node_realize_instances_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
index 09d92d7fa1e..abf44b1aaf8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
@@ -22,12 +22,12 @@ namespace blender::nodes {
static void geo_node_rotate_instances_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER).supports_field();
- b.add_input<decl::Vector>("Pivot Point").subtype(PROP_TRANSLATION).supports_field();
- b.add_input<decl::Bool>("Local Space").default_value(true).supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Instances")).only_instances();
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).supports_field();
+ b.add_input<decl::Vector>(N_("Pivot Point")).subtype(PROP_TRANSLATION).supports_field();
+ b.add_input<decl::Bool>(N_("Local Space")).default_value(true).supports_field();
+ b.add_output<decl::Geometry>(N_("Instances"));
};
static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
@@ -55,34 +55,55 @@ static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &inst
for (const int i_selection : range) {
const int i = selection[i_selection];
const float3 pivot = pivots[i];
+ const float3 euler = rotations[i];
float4x4 &instance_transform = instance_transforms[i];
- const float4x4 rotation_matrix = float4x4::from_loc_eul_scale(
- {0, 0, 0}, rotations[i], {1, 1, 1});
+
+ float4x4 rotation_matrix;
+ float3 used_pivot;
if (local_spaces[i]) {
- instance_transform *= float4x4::from_location(pivot);
- instance_transform *= rotation_matrix;
- instance_transform *= float4x4::from_location(-pivot);
+ /* Find rotation axis from the matrix. This should work even if the instance is skewed. */
+ const float3 rotation_axis_x = instance_transform.values[0];
+ const float3 rotation_axis_y = instance_transform.values[1];
+ const float3 rotation_axis_z = instance_transform.values[2];
+
+ /* Create rotations around the individual axis. This could be optimized to skip some axis
+ * when the angle is zero. */
+ float rotation_x[3][3], rotation_y[3][3], rotation_z[3][3];
+ axis_angle_to_mat3(rotation_x, rotation_axis_x, euler.x);
+ axis_angle_to_mat3(rotation_y, rotation_axis_y, euler.y);
+ axis_angle_to_mat3(rotation_z, rotation_axis_z, euler.z);
+
+ /* Combine the previously computed rotations into the final rotation matrix. */
+ float rotation[3][3];
+ mul_m3_series(rotation, rotation_z, rotation_y, rotation_x);
+ copy_m4_m3(rotation_matrix.values, rotation);
+
+ /* Transform the passed in pivot into the local space of the instance. */
+ used_pivot = instance_transform * pivot;
}
else {
- const float4x4 orgiginal_transform = instance_transform;
- instance_transform = float4x4::from_location(pivot);
- instance_transform *= rotation_matrix;
- instance_transform *= float4x4::from_location(-pivot);
- instance_transform *= orgiginal_transform;
+ used_pivot = pivot;
+ eul_to_mat4(rotation_matrix.values, euler);
}
+ /* Move the pivot to the origin so that we can rotate around it. */
+ sub_v3_v3(instance_transform.values[3], used_pivot);
+ /* Perform the actual rotation. */
+ mul_m4_m4_pre(instance_transform.values, rotation_matrix.values);
+ /* Undo the pivot shifting done before. */
+ add_v3_v3(instance_transform.values[3], used_pivot);
}
});
}
static void geo_node_rotate_instances_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
if (geometry_set.has_instances()) {
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
rotate_instances(params, instances);
}
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Instances", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
index 33897ef354d..ea2b458410e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
@@ -22,12 +22,15 @@ namespace blender::nodes {
static void geo_node_scale_instances_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Vector>("Scale").subtype(PROP_XYZ).default_value({1, 1, 1}).supports_field();
- b.add_input<decl::Vector>("Center").subtype(PROP_TRANSLATION).supports_field();
- b.add_input<decl::Bool>("Local Space").default_value(true).supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Instances")).only_instances();
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Scale"))
+ .subtype(PROP_XYZ)
+ .default_value({1, 1, 1})
+ .supports_field();
+ b.add_input<decl::Vector>(N_("Center")).subtype(PROP_TRANSLATION).supports_field();
+ b.add_input<decl::Bool>(N_("Local Space")).default_value(true).supports_field();
+ b.add_output<decl::Geometry>(N_("Instances"));
};
static void scale_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
@@ -74,12 +77,12 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
static void geo_node_scale_instances_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
if (geometry_set.has_instances()) {
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
scale_instances(params, instances);
}
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Instances", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
index dafd10cee2d..a16fb712b13 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
@@ -20,12 +20,12 @@ namespace blender::nodes {
static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_output<decl::Geometry>("Mesh");
- b.add_output<decl::Geometry>("Point Cloud");
- b.add_output<decl::Geometry>("Curve");
- b.add_output<decl::Geometry>("Volume");
- b.add_output<decl::Geometry>("Instances");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+ b.add_output<decl::Geometry>(N_("Point Cloud"));
+ b.add_output<decl::Geometry>(N_("Curve"));
+ b.add_output<decl::Geometry>(N_("Volume"));
+ b.add_output<decl::Geometry>(N_("Instances"));
}
static void geo_node_separate_components_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
index 970d49e0626..28e214c0ccc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -23,16 +23,16 @@ namespace blender::nodes {
static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection"))
.default_value(true)
.hide_value()
.supports_field()
- .description("The parts of the geometry that go into the first output");
- b.add_output<decl::Geometry>("Selection")
- .description("The parts of the geometry in the selection");
- b.add_output<decl::Geometry>("Inverted")
- .description("The parts of the geometry not in the selection");
+ .description(N_("The parts of the geometry that go into the first output"));
+ b.add_output<decl::Geometry>(N_("Selection"))
+ .description(N_("The parts of the geometry in the selection"));
+ b.add_output<decl::Geometry>(N_("Inverted"))
+ .description(N_("The parts of the geometry not in the selection"));
}
static void geo_node_separate_geometry_layout(uiLayout *layout,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
index d7aaaffc7c6..b64aa266330 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -25,10 +25,10 @@ namespace blender::nodes {
static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Vector>("Position").implicit_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void geo_node_set_curve_handles_layout(uiLayout *layout,
@@ -125,7 +125,7 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params)
(NodeGeometrySetCurveHandlePositions *)params.node().storage;
const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode;
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
Field<float3> position_field = params.extract_input<Field<float3>>("Position");
@@ -144,7 +144,7 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params)
params.error_message_add(NodeWarningType::Info,
TIP_("The input geometry does not contain a Bezier spline"));
}
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Curve", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
index 8fa4ff1a808..e47ce7dea30 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
@@ -20,11 +20,14 @@ namespace blender::nodes {
static void geo_node_set_curve_radius_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Float>("Radius").min(0.0f).default_value(1.0f).supports_field().subtype(
- PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Radius"))
+ .min(0.0f)
+ .default_value(1.0f)
+ .supports_field()
+ .subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void set_radius_in_component(GeometryComponent &component,
@@ -52,7 +55,7 @@ static void set_radius_in_component(GeometryComponent &component,
static void geo_node_set_curve_radius_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
Field<float> radii_field = params.extract_input<Field<float>>("Radius");
@@ -63,7 +66,7 @@ static void geo_node_set_curve_radius_exec(GeoNodeExecParams params)
}
});
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Curve", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
index 113149613ef..dde6d0bab92 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
@@ -20,10 +20,10 @@ namespace blender::nodes {
static void geo_node_set_curve_tilt_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Float>("Tilt").subtype(PROP_ANGLE).supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Tilt")).subtype(PROP_ANGLE).supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static void set_tilt_in_component(GeometryComponent &component,
@@ -51,7 +51,7 @@ static void set_tilt_in_component(GeometryComponent &component,
static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
Field<float> tilt_field = params.extract_input<Field<float>>("Tilt");
@@ -62,7 +62,7 @@ static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params)
}
});
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Curve", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
new file mode 100644
index 00000000000..77d8e786501
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_set_id_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Int>(N_("ID")).implicit_field();
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void set_id_in_component(GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<int> &id_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
+ return;
+ }
+
+ fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+
+ /* Since adding the ID attribute can change the result of the field evaluation (the random value
+ * node uses the index if the ID is unavailable), make sure that it isn't added before evaluating
+ * the field. However, as an optimization, use a faster code path when it already exists. */
+ fn::FieldEvaluator id_evaluator{field_context, &selection};
+ if (component.attribute_exists("id")) {
+ OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
+ "id", ATTR_DOMAIN_POINT);
+ id_evaluator.add_with_destination(id_field, id_attribute.varray());
+ id_evaluator.evaluate();
+ id_attribute.save();
+ }
+ else {
+ id_evaluator.add(id_field);
+ id_evaluator.evaluate();
+ const VArray<int> &result_ids = id_evaluator.get_evaluated<int>(0);
+ OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
+ "id", ATTR_DOMAIN_POINT);
+ result_ids.materialize(selection, id_attribute.as_span());
+ id_attribute.save();
+ }
+}
+
+static void geo_node_set_id_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<int> id_field = params.extract_input<Field<int>>("ID");
+
+ for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_INSTANCES,
+ GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE}) {
+ if (geometry_set.has(type)) {
+ set_id_in_component(geometry_set.get_component_for_write(type), selection_field, id_field);
+ }
+ }
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_set_id()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY, 0);
+ ntype.geometry_node_execute = blender::nodes::geo_node_set_id_exec;
+ ntype.declare = blender::nodes::geo_node_set_id_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
index 0d85af60944..040509ad6d1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
@@ -28,10 +28,10 @@ namespace blender::nodes {
static void geo_node_set_material_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Material>("Material").hide_label();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Material>(N_("Material")).hide_label();
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Material *material)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
index a25fe332916..a8bb1bd8644 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
@@ -20,10 +20,10 @@ namespace blender::nodes {
static void geo_node_set_material_index_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Int>("Material Index").supports_field().min(0);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Material Index")).supports_field().min(0);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void set_material_index_in_component(GeometryComponent &component,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
index b59c9a9e8f5..9ff299542b4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
@@ -20,11 +20,14 @@ namespace blender::nodes {
static void geo_node_set_point_radius_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Float>("Radius").default_value(0.05f).min(0.0f).supports_field().subtype(
- PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Radius"))
+ .default_value(0.05f)
+ .min(0.0f)
+ .supports_field()
+ .subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Points"));
}
static void set_radius_in_component(GeometryComponent &component,
@@ -52,7 +55,7 @@ static void set_radius_in_component(GeometryComponent &component,
static void geo_node_set_point_radius_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
Field<float> radii_field = params.extract_input<Field<float>>("Radius");
@@ -64,7 +67,7 @@ static void geo_node_set_point_radius_exec(GeoNodeExecParams params)
}
});
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Points", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index 15930508e78..4e564386a28 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -22,17 +22,17 @@ namespace blender::nodes {
static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Vector>("Position").implicit_field();
- b.add_input<decl::Bool>("Offset").default_value(false).supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Offset")).supports_field().subtype(PROP_TRANSLATION);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void set_position_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<float3> &position_field,
- const Field<bool> &offset_field)
+ const Field<float3> &offset_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
@@ -45,10 +45,6 @@ static void set_position_in_component(GeometryComponent &component,
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
- OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
- "position", ATTR_DOMAIN_POINT, {0, 0, 0});
- MutableSpan<float3> position_mutable = positions.as_span();
-
fn::FieldEvaluator position_evaluator{field_context, &selection};
position_evaluator.add(position_field);
position_evaluator.add(offset_field);
@@ -58,11 +54,14 @@ static void set_position_in_component(GeometryComponent &component,
* value or not */
const VArray<float3> &positions_input = position_evaluator.get_evaluated<float3>(0);
- const VArray<bool> &offsets_input = position_evaluator.get_evaluated<bool>(1);
+ const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1);
+
+ OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
+ "position", ATTR_DOMAIN_POINT, {0, 0, 0});
+ MutableSpan<float3> position_mutable = positions.as_span();
for (int i : selection) {
- position_mutable[i] = offsets_input[i] ? position_mutable[i] + positions_input[i] :
- positions_input[i];
+ position_mutable[i] = positions_input[i] + offsets_input[i];
}
positions.save();
}
@@ -71,7 +70,7 @@ static void geo_node_set_position_exec(GeoNodeExecParams params)
{
GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
- Field<bool> offset_field = params.extract_input<Field<bool>>("Offset");
+ Field<float3> offset_field = params.extract_input<Field<float3>>("Offset");
Field<float3> position_field = params.extract_input<Field<float3>>("Position");
for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_MESH,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
index ca77041ba7c..06e25c2ed55 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
@@ -20,10 +20,10 @@ namespace blender::nodes {
static void geo_node_set_shade_smooth_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Bool>("Shade Smooth").supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Shade Smooth")).supports_field().default_value(true);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void set_smooth_in_component(GeometryComponent &component,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
index 50e00ff3758..ec751ae1d2b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
@@ -20,10 +20,10 @@ namespace blender::nodes {
static void geo_node_set_spline_cyclic_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Bool>("Cyclic").supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Cyclic")).supports_field();
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void set_cyclic_in_component(GeometryComponent &component,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
index dccb0b1a969..ccf419975ca 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
@@ -22,10 +22,10 @@ namespace blender::nodes {
static void geo_node_set_spline_resolution_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Int>("Resolution").default_value(12).supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Resolution")).default_value(12).supports_field();
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void set_resolution_in_component(GeometryComponent &component,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
index 515f072e976..98d0aca084a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
@@ -20,9 +20,9 @@ namespace blender::nodes {
static void geo_node_string_join_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::String>("Delimiter");
- b.add_input<decl::String>("Strings").multi_input().hide_value();
- b.add_output<decl::String>("String");
+ b.add_input<decl::String>(N_("Delimiter"));
+ b.add_input<decl::String>(N_("Strings")).multi_input().hide_value();
+ b.add_output<decl::String>(N_("String"));
};
static void geo_node_string_join_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index 1cb6d43f685..95e94a22d81 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -34,18 +34,30 @@ namespace blender::nodes {
static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::String>("String");
- b.add_input<decl::Float>("Size").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Character Spacing")
+ b.add_input<decl::String>(N_("String"));
+ b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Character Spacing"))
.default_value(1.0f)
.min(0.0f)
.subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Word Spacing").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Line Spacing").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Text Box Width").default_value(0.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Text Box Height").default_value(0.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Curves");
- b.add_output<decl::String>("Remainder");
+ b.add_input<decl::Float>(N_("Word Spacing"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Line Spacing"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Text Box Width"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Text Box Height"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Curves"));
+ b.add_output<decl::String>(N_("Remainder"));
}
static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
@@ -242,13 +254,11 @@ static void add_instances_from_handles(InstancesComponent &instances,
instances.resize(positions.size());
MutableSpan<int> handles = instances.instance_reference_handles();
MutableSpan<float4x4> transforms = instances.instance_transforms();
- MutableSpan<int> instance_ids = instances.instance_ids();
threading::parallel_for(IndexRange(positions.size()), 256, [&](IndexRange range) {
for (const int i : range) {
handles[i] = char_handles.lookup(charcodes[i]);
transforms[i] = float4x4::from_location({positions[i].x, positions[i].y, 0});
- instance_ids[i] = i;
}
});
}
@@ -271,8 +281,9 @@ static void geo_node_string_to_curves_exec(GeoNodeExecParams params)
/* Convert UTF-8 encoded string to UTF-32. */
size_t len_bytes;
size_t len_chars = BLI_strlen_utf8_ex(layout.text.c_str(), &len_bytes);
- Array<char32_t> char_codes(len_chars + 1);
- BLI_str_utf8_as_utf32(char_codes.data(), layout.text.c_str(), len_chars + 1);
+ Array<char32_t> char_codes_with_null(len_chars + 1);
+ BLI_str_utf8_as_utf32(char_codes_with_null.data(), layout.text.c_str(), len_chars + 1);
+ const Span<char32_t> char_codes = char_codes_with_null.as_span().drop_back(1);
/* Create and add instances. */
GeometrySet geometry_set_out;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 410c9a8bb35..2b3430a5ed0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -31,29 +31,23 @@ namespace blender::nodes {
static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Level").default_value(1).min(0).max(6);
- b.add_input<decl::Float>("Crease")
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
+ b.add_input<decl::Float>(N_("Crease"))
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.supports_field()
.subtype(PROP_FACTOR);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geo_node_subdivision_surface_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
-#ifdef WITH_OPENSUBDIV
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "uv_smooth", 0, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "boundary_smooth", 0, nullptr, ICON_NONE);
-#else
- UNUSED_VARS(layout, ptr);
-#endif
+ uiItemR(layout, ptr, "uv_smooth", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "boundary_smooth", 0, "", ICON_NONE);
}
static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node)
@@ -67,7 +61,7 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n
static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
#ifndef WITH_OPENSUBDIV
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenSubdiv"));
@@ -82,7 +76,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
/* Only process subdivision if level is greater than 0. */
if (subdiv_level == 0) {
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Mesh", std::move(geometry_set));
return;
}
@@ -148,7 +142,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
BKE_subdiv_free(subdiv);
});
#endif
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Mesh", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index c01fcf5bb5f..7e07a552650 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -30,48 +30,57 @@ namespace blender::nodes {
static void geo_node_switch_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Bool>("Switch").default_value(false).supports_field();
- b.add_input<decl::Bool>("Switch", "Switch_001").default_value(false);
-
- b.add_input<decl::Float>("False").supports_field();
- b.add_input<decl::Float>("True").supports_field();
- b.add_input<decl::Int>("False", "False_001").min(-100000).max(100000).supports_field();
- b.add_input<decl::Int>("True", "True_001").min(-100000).max(100000).supports_field();
- b.add_input<decl::Bool>("False", "False_002").default_value(false).hide_value().supports_field();
- b.add_input<decl::Bool>("True", "True_002").default_value(true).hide_value().supports_field();
- b.add_input<decl::Vector>("False", "False_003").supports_field();
- b.add_input<decl::Vector>("True", "True_003").supports_field();
- b.add_input<decl::Color>("False", "False_004")
+ b.add_input<decl::Bool>(N_("Switch")).default_value(false).supports_field();
+ b.add_input<decl::Bool>(N_("Switch"), "Switch_001").default_value(false);
+
+ b.add_input<decl::Float>(N_("False")).supports_field();
+ b.add_input<decl::Float>(N_("True")).supports_field();
+ b.add_input<decl::Int>(N_("False"), "False_001").min(-100000).max(100000).supports_field();
+ b.add_input<decl::Int>(N_("True"), "True_001").min(-100000).max(100000).supports_field();
+ b.add_input<decl::Bool>(N_("False"), "False_002")
+ .default_value(false)
+ .hide_value()
+ .supports_field();
+ b.add_input<decl::Bool>(N_("True"), "True_002")
+ .default_value(true)
+ .hide_value()
+ .supports_field();
+ b.add_input<decl::Vector>(N_("False"), "False_003").supports_field();
+ b.add_input<decl::Vector>(N_("True"), "True_003").supports_field();
+ b.add_input<decl::Color>(N_("False"), "False_004")
.default_value({0.8f, 0.8f, 0.8f, 1.0f})
.supports_field();
- b.add_input<decl::Color>("True", "True_004")
+ b.add_input<decl::Color>(N_("True"), "True_004")
.default_value({0.8f, 0.8f, 0.8f, 1.0f})
.supports_field();
- b.add_input<decl::String>("False", "False_005").supports_field();
- b.add_input<decl::String>("True", "True_005").supports_field();
-
- b.add_input<decl::Geometry>("False", "False_006");
- b.add_input<decl::Geometry>("True", "True_006");
- b.add_input<decl::Object>("False", "False_007");
- b.add_input<decl::Object>("True", "True_007");
- b.add_input<decl::Collection>("False", "False_008");
- b.add_input<decl::Collection>("True", "True_008");
- b.add_input<decl::Texture>("False", "False_009");
- b.add_input<decl::Texture>("True", "True_009");
- b.add_input<decl::Material>("False", "False_010");
- b.add_input<decl::Material>("True", "True_010");
-
- b.add_output<decl::Float>("Output").dependent_field();
- b.add_output<decl::Int>("Output", "Output_001").dependent_field();
- b.add_output<decl::Bool>("Output", "Output_002").dependent_field();
- b.add_output<decl::Vector>("Output", "Output_003").dependent_field();
- b.add_output<decl::Color>("Output", "Output_004").dependent_field();
- b.add_output<decl::String>("Output", "Output_005").dependent_field();
- b.add_output<decl::Geometry>("Output", "Output_006");
- b.add_output<decl::Object>("Output", "Output_007");
- b.add_output<decl::Collection>("Output", "Output_008");
- b.add_output<decl::Texture>("Output", "Output_009");
- b.add_output<decl::Material>("Output", "Output_010");
+ b.add_input<decl::String>(N_("False"), "False_005").supports_field();
+ b.add_input<decl::String>(N_("True"), "True_005").supports_field();
+
+ b.add_input<decl::Geometry>(N_("False"), "False_006");
+ b.add_input<decl::Geometry>(N_("True"), "True_006");
+ b.add_input<decl::Object>(N_("False"), "False_007");
+ b.add_input<decl::Object>(N_("True"), "True_007");
+ b.add_input<decl::Collection>(N_("False"), "False_008");
+ b.add_input<decl::Collection>(N_("True"), "True_008");
+ b.add_input<decl::Texture>(N_("False"), "False_009");
+ b.add_input<decl::Texture>(N_("True"), "True_009");
+ b.add_input<decl::Material>(N_("False"), "False_010");
+ b.add_input<decl::Material>(N_("True"), "True_010");
+ b.add_input<decl::Image>(N_("False"), "False_011");
+ b.add_input<decl::Image>(N_("True"), "True_011");
+
+ b.add_output<decl::Float>(N_("Output")).dependent_field();
+ b.add_output<decl::Int>(N_("Output"), "Output_001").dependent_field();
+ b.add_output<decl::Bool>(N_("Output"), "Output_002").dependent_field();
+ b.add_output<decl::Vector>(N_("Output"), "Output_003").dependent_field();
+ b.add_output<decl::Color>(N_("Output"), "Output_004").dependent_field();
+ b.add_output<decl::String>(N_("Output"), "Output_005").dependent_field();
+ b.add_output<decl::Geometry>(N_("Output"), "Output_006");
+ b.add_output<decl::Object>(N_("Output"), "Output_007");
+ b.add_output<decl::Collection>(N_("Output"), "Output_008");
+ b.add_output<decl::Texture>(N_("Output"), "Output_009");
+ b.add_output<decl::Material>(N_("Output"), "Output_010");
+ b.add_output<decl::Image>(N_("Output"), "Output_011");
}
static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -274,6 +283,10 @@ static void geo_node_switch_exec(GeoNodeExecParams params)
switch_no_fields<Material *>(params, "_010");
break;
}
+ case SOCK_IMAGE: {
+ switch_no_fields<Image *>(params, "_011");
+ break;
+ }
default:
BLI_assert_unreachable();
break;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
index 1c287a0f1bf..a889678537f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -40,22 +40,24 @@ namespace blender::nodes {
static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Target");
-
- b.add_input<decl::Vector>("Attribute").hide_value().supports_field();
- b.add_input<decl::Float>("Attribute", "Attribute_001").hide_value().supports_field();
- b.add_input<decl::Color>("Attribute", "Attribute_002").hide_value().supports_field();
- b.add_input<decl::Bool>("Attribute", "Attribute_003").hide_value().supports_field();
- b.add_input<decl::Int>("Attribute", "Attribute_004").hide_value().supports_field();
-
- b.add_input<decl::Vector>("Source Position").implicit_field();
- b.add_input<decl::Int>("Index").implicit_field();
-
- b.add_output<decl::Vector>("Attribute").dependent_field({6, 7});
- b.add_output<decl::Float>("Attribute", "Attribute_001").dependent_field({6, 7});
- b.add_output<decl::Color>("Attribute", "Attribute_002").dependent_field({6, 7});
- b.add_output<decl::Bool>("Attribute", "Attribute_003").dependent_field({6, 7});
- b.add_output<decl::Int>("Attribute", "Attribute_004").dependent_field({6, 7});
+ b.add_input<decl::Geometry>(N_("Target"))
+ .only_realized_data()
+ .supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD});
+
+ b.add_input<decl::Vector>(N_("Attribute")).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
+ b.add_input<decl::Color>(N_("Attribute"), "Attribute_002").hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Attribute"), "Attribute_003").hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Attribute"), "Attribute_004").hide_value().supports_field();
+
+ b.add_input<decl::Vector>(N_("Source Position")).implicit_field();
+ b.add_input<decl::Int>(N_("Index")).implicit_field();
+
+ b.add_output<decl::Vector>(N_("Attribute")).dependent_field({6, 7});
+ b.add_output<decl::Float>(N_("Attribute"), "Attribute_001").dependent_field({6, 7});
+ b.add_output<decl::Color>(N_("Attribute"), "Attribute_002").dependent_field({6, 7});
+ b.add_output<decl::Bool>(N_("Attribute"), "Attribute_003").dependent_field({6, 7});
+ b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({6, 7});
}
static void geo_node_transfer_attribute_layout(uiLayout *layout,
@@ -628,13 +630,14 @@ class IndexTransferFieldInput : public FieldInput {
GField src_field,
Field<int> index_field,
const AttributeDomain domain)
- : FieldInput(src_field.cpp_type(), "Attribute Transfer Index"),
+ : FieldInput(src_field.cpp_type(), "Attribute Transfer node"),
src_geometry_(std::move(geometry)),
src_field_(std::move(src_field)),
index_field_(std::move(index_field)),
domain_(domain)
{
src_geometry_.ensure_owns_direct_data();
+ category_ = Category::Generated;
}
const GVArray *get_varray_for_context(const FieldContext &context,
@@ -746,21 +749,9 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params)
});
};
- if (geometry.has_instances()) {
- if (geometry.has_realized_data()) {
- params.error_message_add(
- NodeWarningType::Info,
- TIP_("Only realized geometry is supported, instances will not be used"));
- }
- else {
- params.error_message_add(NodeWarningType::Error,
- TIP_("Target geometry must contain realized data"));
- return return_default();
- }
- /* Since the instances are not used, there is no point in keeping
- * a reference to them while the field is passed around. */
- geometry.remove(GEO_COMPONENT_TYPE_INSTANCES);
- }
+ /* Since the instances are not used, there is no point in keeping
+ * a reference to them while the field is passed around. */
+ geometry.remove(GEO_COMPONENT_TYPE_INSTANCES);
GField output_field;
switch (mapping) {
@@ -790,8 +781,6 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params)
}
case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST: {
if (geometry.has_curve() && !geometry.has_mesh() && !geometry.has_pointcloud()) {
- params.error_message_add(NodeWarningType::Warning,
- TIP_("Curve targets are not currently supported"));
return return_default();
}
auto fn = std::make_unique<NearestTransferFunction>(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 005714a9580..2c55a255b5d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -37,11 +37,11 @@ namespace blender::nodes {
static void geo_node_transform_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Vector>("Translation").subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER);
- b.add_input<decl::Vector>("Scale").default_value({1, 1, 1}).subtype(PROP_XYZ);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static bool use_translate(const float3 rotation, const float3 scale)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
index 8fc2843fd8a..fa05d858a07 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
@@ -22,11 +22,11 @@ namespace blender::nodes {
static void geo_node_translate_instances_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_input<decl::Vector>("Translation").subtype(PROP_TRANSLATION).supports_field();
- b.add_input<decl::Bool>("Local Space").default_value(true).supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Instances")).only_instances();
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION).supports_field();
+ b.add_input<decl::Bool>(N_("Local Space")).default_value(true).supports_field();
+ b.add_output<decl::Geometry>(N_("Instances"));
};
static void translate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
@@ -62,12 +62,12 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
static void geo_node_translate_instances_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
if (geometry_set.has_instances()) {
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
translate_instances(params, instances);
}
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Instances", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 7ef0913622c..c869846e1f8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -31,9 +31,9 @@ namespace blender::nodes {
static void geo_node_triangulate_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Minimum Vertices").default_value(4).min(4).max(10000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Int>(N_("Minimum Vertices")).default_value(4).min(4).max(10000);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geo_node_triangulate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -50,7 +50,7 @@ static void geo_triangulate_init(bNodeTree *UNUSED(ntree), bNode *node)
static void geo_node_triangulate_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
const int min_vertices = std::max(params.extract_input<int>("Minimum Vertices"), 4);
GeometryNodeTriangulateQuads quad_method = static_cast<GeometryNodeTriangulateQuads>(
@@ -67,7 +67,7 @@ static void geo_node_triangulate_exec(GeoNodeExecParams params)
}
});
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Mesh", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index 3331962341f..194d1a751ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -14,13 +14,69 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_geometry_util.hh"
namespace blender::nodes {
static void geo_node_viewer_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Float>(N_("Value")).supports_field().hide_value();
+ b.add_input<decl::Vector>(N_("Value"), "Value_001").supports_field().hide_value();
+ b.add_input<decl::Color>(N_("Value"), "Value_002").supports_field().hide_value();
+ b.add_input<decl::Int>(N_("Value"), "Value_003").supports_field().hide_value();
+ b.add_input<decl::Bool>(N_("Value"), "Value_004").supports_field().hide_value();
+}
+
+static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(sizeof(NodeGeometryViewer),
+ __func__);
+ data->data_type = CD_PROP_FLOAT;
+
+ node->storage = data;
+}
+
+static void geo_node_viewer_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
+
+static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_FLOAT:
+ return SOCK_FLOAT;
+ case CD_PROP_INT32:
+ return SOCK_INT;
+ case CD_PROP_FLOAT3:
+ return SOCK_VECTOR;
+ case CD_PROP_BOOL:
+ return SOCK_BOOLEAN;
+ case CD_PROP_COLOR:
+ return SOCK_RGBA;
+ default:
+ BLI_assert_unreachable();
+ return SOCK_FLOAT;
+ }
+}
+
+static void geo_node_viewer_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeGeometryViewer &storage = *(const NodeGeometryViewer *)node->storage;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eNodeSocketDatatype socket_type = custom_data_type_to_socket_type(data_type);
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (socket->type == SOCK_GEOMETRY) {
+ continue;
+ }
+ nodeSetSocketAvailability(socket, socket->type == socket_type);
+ }
+}
+
} // namespace blender::nodes
void register_node_type_geo_viewer()
@@ -28,6 +84,11 @@ void register_node_type_geo_viewer()
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0);
+ node_type_storage(
+ &ntype, "NodeGeometryViewer", node_free_standard_storage, node_copy_standard_storage);
+ node_type_update(&ntype, blender::nodes::geo_node_viewer_update);
+ node_type_init(&ntype, blender::nodes::geo_node_viewer_init);
ntype.declare = blender::nodes::geo_node_viewer_declare;
+ ntype.draw_buttons_ex = blender::nodes::geo_node_viewer_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index 229a35e0007..416d502dc59 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -39,13 +39,12 @@ namespace blender::nodes {
static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Density");
- b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Voxel Amount").default_value(64.0f).min(0.0f);
- b.add_input<decl::Float>("Threshold").default_value(0.1f).min(0.0f);
- b.add_input<decl::Float>("Adaptivity").min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Volume")).supported_type(GEO_COMPONENT_TYPE_VOLUME);
+ b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Threshold")).default_value(0.1f).min(0.0f);
+ b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -60,11 +59,6 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
sizeof(NodeGeometryVolumeToMesh), __func__);
data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
-
- bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density");
- bNodeSocketValueString *grid_socket_value = (bNodeSocketValueString *)grid_socket->default_value;
- STRNCPY(grid_socket_value->value, "density");
-
node->storage = data;
}
@@ -82,75 +76,120 @@ static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node
#ifdef WITH_OPENVDB
-static void create_mesh_from_volume(GeometrySet &geometry_set_in,
- GeometrySet &geometry_set_out,
- GeoNodeExecParams &params)
+static bke::VolumeToMeshResolution get_resolution_param(const GeoNodeExecParams &params)
{
- if (!geometry_set_in.has<VolumeComponent>()) {
- return;
- }
-
const NodeGeometryVolumeToMesh &storage =
*(const NodeGeometryVolumeToMesh *)params.node().storage;
bke::VolumeToMeshResolution resolution;
resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode;
if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT) {
- resolution.settings.voxel_amount = params.get_input<float>("Voxel Amount");
- if (resolution.settings.voxel_amount <= 0.0f) {
- return;
- }
+ resolution.settings.voxel_amount = std::max(params.get_input<float>("Voxel Amount"), 0.0f);
}
else if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE) {
- resolution.settings.voxel_size = params.get_input<float>("Voxel Size");
- if (resolution.settings.voxel_size <= 0.0f) {
- return;
- }
+ resolution.settings.voxel_size = std::max(params.get_input<float>("Voxel Size"), 0.0f);
+ }
+
+ return resolution;
+}
+
+static Mesh *create_mesh_from_volume_grids(Span<openvdb::GridBase::ConstPtr> grids,
+ const float threshold,
+ const float adaptivity,
+ const bke::VolumeToMeshResolution &resolution)
+{
+ Array<bke::OpenVDBMeshData> mesh_data(grids.size());
+ for (const int i : grids.index_range()) {
+ mesh_data[i] = bke::volume_to_mesh_data(*grids[i], resolution, threshold, adaptivity);
+ }
+
+ int vert_offset = 0;
+ int poly_offset = 0;
+ int loop_offset = 0;
+ Array<int> vert_offsets(mesh_data.size());
+ Array<int> poly_offsets(mesh_data.size());
+ Array<int> loop_offsets(mesh_data.size());
+ for (const int i : grids.index_range()) {
+ const bke::OpenVDBMeshData &data = mesh_data[i];
+ vert_offsets[i] = vert_offset;
+ poly_offsets[i] = poly_offset;
+ loop_offsets[i] = loop_offset;
+ vert_offset += data.verts.size();
+ poly_offset += (data.tris.size() + data.quads.size());
+ loop_offset += (3 * data.tris.size() + 4 * data.quads.size());
}
- const VolumeComponent *component = geometry_set_in.get_component_for_read<VolumeComponent>();
- const Volume *volume = component->get_for_read();
+ Mesh *mesh = BKE_mesh_new_nomain(vert_offset, 0, 0, loop_offset, poly_offset);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+ MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+
+ for (const int i : grids.index_range()) {
+ const bke::OpenVDBMeshData &data = mesh_data[i];
+ bke::fill_mesh_from_openvdb_data(data.verts,
+ data.tris,
+ data.quads,
+ vert_offsets[i],
+ poly_offsets[i],
+ loop_offsets[i],
+ verts,
+ polys,
+ loops);
+ }
+
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_normals_tag_dirty(mesh);
+
+ return mesh;
+}
+
+static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParams &params)
+{
+ const Volume *volume = geometry_set.get_volume_for_read();
if (volume == nullptr) {
- return;
+ return nullptr;
}
+ const bke::VolumeToMeshResolution resolution = get_resolution_param(params);
const Main *bmain = DEG_get_bmain(params.depsgraph());
BKE_volume_load(volume, bmain);
- const std::string grid_name = params.get_input<std::string>("Density");
- const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, grid_name.c_str());
- if (volume_grid == nullptr) {
- return;
+ Vector<openvdb::GridBase::ConstPtr> grids;
+ for (const int i : IndexRange(BKE_volume_num_grids(volume))) {
+ const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, i);
+ openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
+ grids.append(std::move(grid));
}
- float threshold = params.get_input<float>("Threshold");
- float adaptivity = params.get_input<float>("Adaptivity");
-
- const openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
- Mesh *mesh = bke::volume_to_mesh(*grid, resolution, threshold, adaptivity);
- if (mesh == nullptr) {
- return;
+ if (grids.is_empty()) {
+ return nullptr;
}
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MeshComponent &dst_component = geometry_set_out.get_component_for_write<MeshComponent>();
- dst_component.replace(mesh);
+
+ return create_mesh_from_volume_grids(grids,
+ params.get_input<float>("Threshold"),
+ params.get_input<float>("Adaptivity"),
+ resolution);
}
#endif /* WITH_OPENVDB */
static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
- GeometrySet geometry_set_out;
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
#ifdef WITH_OPENVDB
- create_mesh_from_volume(geometry_set_in, geometry_set_out, params);
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ Mesh *mesh = create_mesh_from_volume(geometry_set, params);
+ geometry_set.replace_mesh(mesh);
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
+ });
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenVDB"));
#endif
- params.set_output("Geometry", geometry_set_out);
+ params.set_output("Mesh", std::move(geometry_set));
}
} // namespace blender::nodes
@@ -163,7 +202,7 @@ void register_node_type_geo_volume_to_mesh()
ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare;
node_type_storage(
&ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
- node_type_size(&ntype, 200, 120, 700);
+ node_type_size(&ntype, 170, 120, 700);
node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init);
node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update);
ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec;
diff --git a/source/blender/nodes/intern/extern_implementations.cc b/source/blender/nodes/intern/extern_implementations.cc
index 42d4b2878bc..35de319f20b 100644
--- a/source/blender/nodes/intern/extern_implementations.cc
+++ b/source/blender/nodes/intern/extern_implementations.cc
@@ -15,6 +15,7 @@
*/
#include "NOD_socket_declarations.hh"
+#include "NOD_socket_declarations_geometry.hh"
namespace blender::nodes {
#define MAKE_EXTERN_SOCKET_IMPLEMENTATION(TYPE) \
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index 852f52f38cd..ddd3c991518 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -21,9 +21,16 @@
#include "DNA_modifier_types.h"
#include "DNA_space_types.h"
+#include "FN_field_cpp_type.hh"
+
+#include "BLT_translation.h"
+
namespace blender::nodes::geometry_nodes_eval_log {
using fn::CPPType;
+using fn::FieldCPPType;
+using fn::FieldInput;
+using fn::GField;
ModifierLog::ModifierLog(GeoLogger &logger)
: input_geometry_log_(std::move(logger.input_geometry_log_)),
@@ -168,6 +175,34 @@ const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket
return this->lookup_socket_log((eNodeSocketInOut)socket.in_out, index);
}
+GFieldValueLog::GFieldValueLog(fn::GField field, bool log_full_field) : type_(field.cpp_type())
+{
+ Set<std::reference_wrapper<const FieldInput>> field_inputs_set;
+ field.node().foreach_field_input(
+ [&](const FieldInput &field_input) { field_inputs_set.add(field_input); });
+
+ Vector<std::reference_wrapper<const FieldInput>> field_inputs;
+ field_inputs.extend(field_inputs_set.begin(), field_inputs_set.end());
+
+ std::sort(
+ field_inputs.begin(), field_inputs.end(), [](const FieldInput &a, const FieldInput &b) {
+ const int index_a = (int)a.category();
+ const int index_b = (int)b.category();
+ if (index_a == index_b) {
+ return a.socket_inspection_name().size() < b.socket_inspection_name().size();
+ }
+ return index_a < index_b;
+ });
+
+ for (const FieldInput &field_input : field_inputs) {
+ input_tooltips_.append(field_input.socket_inspection_name());
+ }
+
+ if (log_full_field) {
+ field_ = std::move(field);
+ }
+}
+
GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry)
{
static std::array all_component_types = {GEO_COMPONENT_TYPE_CURVE,
@@ -175,13 +210,19 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful
GEO_COMPONENT_TYPE_MESH,
GEO_COMPONENT_TYPE_POINT_CLOUD,
GEO_COMPONENT_TYPE_VOLUME};
+
+ /* Keep track handled attribute names to make sure that we do not return the same name twice.
+ * Currently #GeometrySet::attribute_foreach does not do that. Note that this will merge
+ * attributes with the same name but different domains or data types on separate components. */
+ Set<StringRef> names;
+
geometry_set.attribute_foreach(
all_component_types,
true,
[&](const bke::AttributeIDRef &attribute_id,
const AttributeMetaData &meta_data,
const GeometryComponent &UNUSED(component)) {
- if (attribute_id.is_named()) {
+ if (attribute_id.is_named() && names.add(attribute_id.name())) {
this->attributes_.append({attribute_id.name(), meta_data.domain, meta_data.data_type});
}
});
@@ -376,6 +417,26 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value
geometry_set, log_full_geometry);
values_.append({copied_sockets, std::move(value_log)});
}
+ else if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) {
+ GField field = field_type->get_gfield(value.get());
+ bool log_full_field = false;
+ if (!field.node().depends_on_input()) {
+ /* Always log constant fields so that their value can be shown in socket inspection.
+ * In the future we can also evaluate the field here and only store the value. */
+ log_full_field = true;
+ }
+ if (!log_full_field) {
+ for (const DSocket &socket : sockets) {
+ if (main_logger_->log_full_sockets_.contains(socket)) {
+ log_full_field = true;
+ break;
+ }
+ }
+ }
+ destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>(
+ std::move(field), log_full_field);
+ values_.append({copied_sockets, std::move(value_log)});
+ }
else {
void *buffer = allocator_->allocate(type.size(), type.alignment());
type.copy_construct(value.get(), buffer);
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index a3bbca90731..c7a3e795c33 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -36,6 +36,72 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin
local_logger.log_node_warning(provider_->dnode, type, std::move(message));
}
+void GeoNodeExecParams::check_input_geometry_set(StringRef identifier,
+ const GeometrySet &geometry_set) const
+{
+ const int input_index = provider_->dnode->input_by_identifier(identifier).index();
+ const SocketDeclaration &decl = *provider_->dnode->declaration()->inputs()[input_index];
+ const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl);
+ if (geo_decl == nullptr) {
+ return;
+ }
+
+ const bool only_realized_data = geo_decl->only_realized_data();
+ const bool only_instances = geo_decl->only_instances();
+ const Span<GeometryComponentType> supported_types = geo_decl->supported_types();
+
+ if (only_realized_data) {
+ if (geometry_set.has_instances()) {
+ this->error_message_add(NodeWarningType::Info,
+ TIP_("Instances in input geometry are ignored"));
+ }
+ }
+ if (only_instances) {
+ if (geometry_set.has_realized_data()) {
+ this->error_message_add(NodeWarningType::Info,
+ TIP_("Realized data in input geometry is ignored"));
+ }
+ }
+ if (supported_types.is_empty()) {
+ /* Assume all types are supported. */
+ return;
+ }
+ const Vector<GeometryComponentType> types_in_geometry = geometry_set.gather_component_types(
+ true, true);
+ for (const GeometryComponentType type : types_in_geometry) {
+ if (type == GEO_COMPONENT_TYPE_INSTANCES) {
+ continue;
+ }
+ if (supported_types.contains(type)) {
+ continue;
+ }
+ std::string message = TIP_("Input geometry has unsupported type: ");
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ message += TIP_("Mesh");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ message += TIP_("Point Cloud");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ BLI_assert_unreachable();
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ message += TIP_("Volume");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ message += TIP_("Curve");
+ break;
+ }
+ }
+ this->error_message_add(NodeWarningType::Info, std::move(message));
+ }
+}
+
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
{
for (const InputSocketRef *socket : provider_->dnode->inputs()) {
@@ -183,6 +249,11 @@ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
return default_domain;
}
+std::string GeoNodeExecParams::attribute_producer_name() const
+{
+ return provider_->dnode->label_or_name() + TIP_(" node");
+}
+
void GeoNodeExecParams::check_input_access(StringRef identifier,
const CPPType *requested_type) const
{
diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc
index e823476f9e4..ed5691ebf7f 100644
--- a/source/blender/nodes/intern/node_socket_declarations.cc
+++ b/source/blender/nodes/intern/node_socket_declarations.cc
@@ -15,6 +15,7 @@
*/
#include "NOD_socket_declarations.hh"
+#include "NOD_socket_declarations_geometry.hh"
#include "BKE_node.h"
@@ -333,6 +334,46 @@ bool Geometry::matches(const bNodeSocket &socket) const
return true;
}
+Span<GeometryComponentType> Geometry::supported_types() const
+{
+ return supported_types_;
+}
+
+bool Geometry::only_realized_data() const
+{
+ return only_realized_data_;
+}
+
+bool Geometry::only_instances() const
+{
+ return only_instances_;
+}
+
+GeometryBuilder &GeometryBuilder::supported_type(GeometryComponentType supported_type)
+{
+ decl_->supported_types_ = {supported_type};
+ return *this;
+}
+
+GeometryBuilder &GeometryBuilder::supported_type(
+ blender::Vector<GeometryComponentType> supported_types)
+{
+ decl_->supported_types_ = std::move(supported_types);
+ return *this;
+}
+
+GeometryBuilder &GeometryBuilder::only_realized_data(bool value)
+{
+ decl_->only_realized_data_ = value;
+ return *this;
+}
+
+GeometryBuilder &GeometryBuilder::only_instances(bool value)
+{
+ decl_->only_instances_ = value;
+ return *this;
+}
+
/** \} */
} // namespace blender::nodes::decl
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 2ca797009da..5481465aef6 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -502,11 +502,15 @@ bool NodeRef::any_socket_is_directly_linked(eNodeSocketInOut in_out) const
return this->any_output_is_directly_linked();
}
-/**
- * Sort nodes topologically from left to right or right to left.
- * In the future the result if this could be cached on #NodeTreeRef.
- */
-Vector<const NodeRef *> NodeTreeRef::toposort(const ToposortDirection direction) const
+struct ToposortNodeState {
+ bool is_done = false;
+ bool is_in_stack = false;
+};
+
+static void toposort_from_start_node(const NodeTreeRef::ToposortDirection direction,
+ const NodeRef &start_node,
+ MutableSpan<ToposortNodeState> node_states,
+ NodeTreeRef::ToposortResult &result)
{
struct Item {
const NodeRef *node;
@@ -516,64 +520,97 @@ Vector<const NodeRef *> NodeTreeRef::toposort(const ToposortDirection direction)
int link_index = 0;
};
- Vector<const NodeRef *> toposort;
- toposort.reserve(nodes_by_id_.size());
- Array<bool> node_is_done_by_id(nodes_by_id_.size(), false);
- Stack<Item> nodes_to_check;
+ /* Do a depth-first search to sort nodes topologically. */
+ Stack<Item, 64> nodes_to_check;
+ nodes_to_check.push({&start_node});
+ while (!nodes_to_check.is_empty()) {
+ Item &item = nodes_to_check.peek();
+ const NodeRef &node = *item.node;
+ const Span<const SocketRef *> sockets = node.sockets(
+ direction == NodeTreeRef::ToposortDirection::LeftToRight ? SOCK_IN : SOCK_OUT);
+
+ while (true) {
+ if (item.socket_index == sockets.size()) {
+ /* All sockets have already been visited. */
+ break;
+ }
+ const SocketRef &socket = *sockets[item.socket_index];
+ const Span<const SocketRef *> linked_sockets = socket.directly_linked_sockets();
+ if (item.link_index == linked_sockets.size()) {
+ /* All links connected to this socket have already been visited. */
+ item.socket_index++;
+ item.link_index = 0;
+ continue;
+ }
+ const SocketRef &linked_socket = *linked_sockets[item.link_index];
+ const NodeRef &linked_node = linked_socket.node();
+ ToposortNodeState &linked_node_state = node_states[linked_node.id()];
+ if (linked_node_state.is_done) {
+ /* The linked node has already been visited. */
+ item.link_index++;
+ continue;
+ }
+ if (linked_node_state.is_in_stack) {
+ result.has_cycle = true;
+ }
+ else {
+ nodes_to_check.push({&linked_node});
+ linked_node_state.is_in_stack = true;
+ }
+ break;
+ }
- for (const NodeRef *start_node : nodes_by_id_) {
- if (node_is_done_by_id[start_node->id()]) {
+ /* If no other element has been pushed, the current node can be pushed to the sorted list. */
+ if (&item == &nodes_to_check.peek()) {
+ ToposortNodeState &node_state = node_states[node.id()];
+ node_state.is_done = true;
+ node_state.is_in_stack = false;
+ result.sorted_nodes.append(&node);
+ nodes_to_check.pop();
+ }
+ }
+}
+
+/**
+ * Sort nodes topologically from left to right or right to left.
+ * In the future the result if this could be cached on #NodeTreeRef.
+ */
+NodeTreeRef::ToposortResult NodeTreeRef::toposort(const ToposortDirection direction) const
+{
+ ToposortResult result;
+ result.sorted_nodes.reserve(nodes_by_id_.size());
+
+ Array<ToposortNodeState> node_states(nodes_by_id_.size());
+
+ for (const NodeRef *node : nodes_by_id_) {
+ if (node_states[node->id()].is_done) {
/* Ignore nodes that are done already. */
continue;
}
- if (start_node->any_socket_is_directly_linked(
+ if (node->any_socket_is_directly_linked(
direction == ToposortDirection::LeftToRight ? SOCK_OUT : SOCK_IN)) {
/* Ignore non-start nodes. */
continue;
}
- /* Do a depth-first search to sort nodes topologically. */
- nodes_to_check.push({start_node});
- while (!nodes_to_check.is_empty()) {
- Item &item = nodes_to_check.peek();
- const NodeRef &node = *item.node;
- const Span<const SocketRef *> sockets = node.sockets(
- direction == ToposortDirection::LeftToRight ? SOCK_IN : SOCK_OUT);
-
- while (true) {
- if (item.socket_index == sockets.size()) {
- /* All sockets have already been visited. */
- break;
- }
- const SocketRef &socket = *sockets[item.socket_index];
- const Span<const SocketRef *> linked_sockets = socket.directly_linked_sockets();
- if (item.link_index == linked_sockets.size()) {
- /* All links connected to this socket have already been visited. */
- item.socket_index++;
- item.link_index = 0;
- continue;
- }
- const SocketRef &linked_socket = *linked_sockets[item.link_index];
- const NodeRef &linked_node = linked_socket.node();
- if (node_is_done_by_id[linked_node.id()]) {
- /* The linked node has already been visited. */
- item.link_index++;
- continue;
- }
- nodes_to_check.push({&linked_node});
- break;
- }
+ toposort_from_start_node(direction, *node, node_states, result);
+ }
- /* If no other element has been pushed, the current node can be pushed to the sorted list. */
- if (&item == &nodes_to_check.peek()) {
- node_is_done_by_id[node.id()] = true;
- toposort.append(&node);
- nodes_to_check.pop();
+ /* Check if the loop above forgot some nodes because there is a cycle. */
+ if (result.sorted_nodes.size() < nodes_by_id_.size()) {
+ result.has_cycle = true;
+ for (const NodeRef *node : nodes_by_id_) {
+ if (node_states[node->id()].is_done) {
+ /* Ignore nodes that are done already. */
+ continue;
}
+ /* Start toposort at this node which is somewhere in the middle of a loop. */
+ toposort_from_start_node(direction, *node, node_states, result);
}
}
- return toposort;
+ BLI_assert(result.sorted_nodes.size() == nodes_by_id_.size());
+ return result;
}
const NodeRef *NodeTreeRef::find_node(const bNode &bnode) const
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
index e8d4239937f..57a992a4275 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
@@ -28,10 +28,10 @@ namespace blender::nodes {
static void sh_node_clamp_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Value").min(0.0f).max(1.0f).default_value(1.0f);
- b.add_input<decl::Float>("Min").default_value(0.0f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Max").default_value(1.0f).min(-10000.0f).max(10000.0f);
- b.add_output<decl::Float>("Result");
+ b.add_input<decl::Float>(N_("Value")).min(0.0f).max(1.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Float>(N_("Result"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc
index 875e6fa0c35..f8f0ee97eae 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -28,9 +28,9 @@ namespace blender::nodes {
static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Fac").min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Vector>("Vector").min(-1.0f).max(1.0f);
- b.add_output<decl::Vector>("Vector");
+ b.add_input<decl::Float>(N_("Fac")).min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Vector")).min(-1.0f).max(1.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
};
} // namespace blender::nodes
@@ -175,9 +175,9 @@ namespace blender::nodes {
static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Fac").min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Color");
+ b.add_input<decl::Float>(N_("Fac")).min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Color"));
};
} // namespace blender::nodes
@@ -352,9 +352,13 @@ namespace blender::nodes {
static void sh_node_curve_float_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Factor").min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Value").default_value(1.0f);
- b.add_output<decl::Float>("Value");
+ b.add_input<decl::Float>(N_("Factor"))
+ .min(0.0f)
+ .max(1.0f)
+ .default_value(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f);
+ b.add_output<decl::Float>(N_("Value"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
index 5ea194ddc83..c866a154e8c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -30,13 +30,13 @@ namespace blender::nodes {
static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Value").min(-10000.0f).max(10000.0f).default_value(1.0f);
- b.add_input<decl::Float>("From Min").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("From Max").min(-10000.0f).max(10000.0f).default_value(1.0f);
- b.add_input<decl::Float>("To Min").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("To Max").min(-10000.0f).max(10000.0f).default_value(1.0f);
- b.add_input<decl::Float>("Steps").min(-10000.0f).max(10000.0f).default_value(4.0f);
- b.add_output<decl::Float>("Result");
+ b.add_input<decl::Float>(N_("Value")).min(-10000.0f).max(10000.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("From Min")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("From Max")).min(-10000.0f).max(10000.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("To Min")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("To Max")).min(-10000.0f).max(10000.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("Steps")).min(-10000.0f).max(10000.0f).default_value(4.0f);
+ b.add_output<decl::Float>(N_("Result"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index 96d1be49c04..284a5f1189f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -32,10 +32,16 @@ namespace blender::nodes {
static void sh_node_math_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Value").default_value(0.5f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Value", "Value_001").default_value(0.5f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Value", "Value_002").default_value(0.5f).min(-10000.0f).max(10000.0f);
- b.add_output<decl::Float>("Value");
+ b.add_input<decl::Float>(N_("Value")).default_value(0.5f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Value"), "Value_001")
+ .default_value(0.5f)
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_input<decl::Float>(N_("Value"), "Value_002")
+ .default_value(0.5f)
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_output<decl::Float>(N_("Value"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
index d4d02e80ada..06fafff578e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
@@ -28,10 +28,10 @@ namespace blender::nodes {
static void sh_node_mix_rgb_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Fac").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Color1").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::Color>("Color2").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_output<decl::Color>("Color");
+ b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Color1")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_input<decl::Color>(N_("Color2")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_output<decl::Color>(N_("Color"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
index 24c5dcf7ba3..08a9e01786e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
@@ -28,10 +28,10 @@ namespace blender::nodes {
static void sh_node_seprgb_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Color>("Image").default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_output<decl::Float>("R");
- b.add_output<decl::Float>("G");
- b.add_output<decl::Float>("B");
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Float>(N_("R"));
+ b.add_output<decl::Float>(N_("G"));
+ b.add_output<decl::Float>(N_("B"));
};
} // namespace blender::nodes
@@ -121,10 +121,10 @@ namespace blender::nodes {
static void sh_node_combrgb_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("R").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("G").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("B").min(0.0f).max(1.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("R")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("G")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("B")).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
index 8ca8fc19521..1bbfa629462 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
@@ -28,10 +28,10 @@ namespace blender::nodes {
static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f);
- b.add_output<decl::Float>("X");
- b.add_output<decl::Float>("Y");
- b.add_output<decl::Float>("Z");
+ b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Float>(N_("X"));
+ b.add_output<decl::Float>(N_("Y"));
+ b.add_output<decl::Float>(N_("Z"));
};
} // namespace blender::nodes
@@ -105,10 +105,10 @@ namespace blender::nodes {
static void sh_node_combxyz_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("X").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Y").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Z").min(-10000.0f).max(10000.0f);
- b.add_output<decl::Vector>("Vector");
+ b.add_input<decl::Float>(N_("X")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Y")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Z")).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
index e90dae60189..b840bd75e42 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
@@ -19,39 +19,42 @@
#include "../node_shader_util.h"
+#include "BLI_float2.hh"
+#include "BLI_float4.hh"
+
namespace blender::nodes {
static void sh_node_tex_brick_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f).implicit_field();
- b.add_input<decl::Color>("Color1").default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_input<decl::Color>("Color2").default_value({0.2f, 0.2f, 0.2f, 1.0f});
- b.add_input<decl::Color>("Mortar").default_value({0.0f, 0.0f, 0.0f, 1.0f}).no_muted_links();
- b.add_input<decl::Float>("Scale")
+ b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
+ b.add_input<decl::Color>(N_("Color1")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Color2")).default_value({0.2f, 0.2f, 0.2f, 1.0f});
+ b.add_input<decl::Color>(N_("Mortar")).default_value({0.0f, 0.0f, 0.0f, 1.0f}).no_muted_links();
+ b.add_input<decl::Float>(N_("Scale"))
.min(-1000.0f)
.max(1000.0f)
.default_value(5.0f)
.no_muted_links();
- b.add_input<decl::Float>("Mortar Size")
+ b.add_input<decl::Float>(N_("Mortar Size"))
.min(0.0f)
.max(0.125f)
.default_value(0.02f)
.no_muted_links();
- b.add_input<decl::Float>("Mortar Smooth").min(0.0f).max(1.0f).no_muted_links();
- b.add_input<decl::Float>("Bias").min(-1.0f).max(1.0f).no_muted_links();
- b.add_input<decl::Float>("Brick Width")
+ b.add_input<decl::Float>(N_("Mortar Smooth")).min(0.0f).max(1.0f).no_muted_links();
+ b.add_input<decl::Float>(N_("Bias")).min(-1.0f).max(1.0f).no_muted_links();
+ b.add_input<decl::Float>(N_("Brick Width"))
.min(0.01f)
.max(100.0f)
.default_value(0.5f)
.no_muted_links();
- b.add_input<decl::Float>("Row Height")
+ b.add_input<decl::Float>(N_("Row Height"))
.min(0.01f)
.max(100.0f)
.default_value(0.25f)
.no_muted_links();
- b.add_output<decl::Color>("Color");
- b.add_output<decl::Float>("Fac");
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Fac"));
};
} // namespace blender::nodes
@@ -98,18 +101,185 @@ static int node_shader_gpu_tex_brick(GPUMaterial *mat,
GPU_constant(&squash_freq));
}
-/* node type definition */
+namespace blender::nodes {
+
+class BrickFunction : public fn::MultiFunction {
+ private:
+ const float offset_;
+ const int offset_freq_;
+ const float squash_;
+ const int squash_freq_;
+
+ public:
+ BrickFunction(const float offset,
+ const int offset_freq,
+ const float squash,
+ const int squash_freq)
+ : offset_(offset), offset_freq_(offset_freq), squash_(squash), squash_freq_(squash_freq)
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"BrickTexture"};
+ signature.single_input<float3>("Vector");
+ signature.single_input<ColorGeometry4f>("Color1");
+ signature.single_input<ColorGeometry4f>("Color2");
+ signature.single_input<ColorGeometry4f>("Mortar");
+ signature.single_input<float>("Scale");
+ signature.single_input<float>("Mortar Size");
+ signature.single_input<float>("Mortar Smooth");
+ signature.single_input<float>("Bias");
+ signature.single_input<float>("Brick Width");
+ signature.single_input<float>("Row Height");
+ signature.single_output<ColorGeometry4f>("Color");
+ signature.single_output<float>("Fac");
+ return signature.build();
+ }
+
+ /* Fast integer noise. */
+ static float brick_noise(uint n)
+ {
+ n = (n + 1013) & 0x7fffffff;
+ n = (n >> 13) ^ n;
+ const uint nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ return 0.5f * ((float)nn / 1073741824.0f);
+ }
+
+ static float smoothstepf(const float f)
+ {
+ const float ff = f * f;
+ return (3.0f * ff - 2.0f * ff * f);
+ }
+
+ static float2 brick(float3 p,
+ float mortar_size,
+ float mortar_smooth,
+ float bias,
+ float brick_width,
+ float row_height,
+ float offset_amount,
+ int offset_frequency,
+ float squash_amount,
+ int squash_frequency)
+ {
+ float offset = 0.0f;
+
+ const int rownum = (int)floorf(p.y / row_height);
+
+ if (offset_frequency && squash_frequency) {
+ brick_width *= (rownum % squash_frequency) ? 1.0f : squash_amount;
+ offset = (rownum % offset_frequency) ? 0.0f : (brick_width * offset_amount);
+ }
+
+ const int bricknum = (int)floorf((p.x + offset) / brick_width);
+
+ const float x = (p.x + offset) - brick_width * bricknum;
+ const float y = p.y - row_height * rownum;
+
+ const float tint = clamp_f(
+ brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias, 0.0f, 1.0f);
+ float min_dist = std::min(std::min(x, y), std::min(brick_width - x, row_height - y));
+
+ float mortar;
+ if (min_dist >= mortar_size) {
+ mortar = 0.0f;
+ }
+ else if (mortar_smooth == 0.0f) {
+ mortar = 1.0f;
+ }
+ else {
+ min_dist = 1.0f - min_dist / mortar_size;
+ mortar = (min_dist < mortar_smooth) ? smoothstepf(min_dist / mortar_smooth) : 1.0f;
+ }
+
+ return float2(tint, mortar);
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
+ const VArray<ColorGeometry4f> &color1_values = params.readonly_single_input<ColorGeometry4f>(
+ 1, "Color1");
+ const VArray<ColorGeometry4f> &color2_values = params.readonly_single_input<ColorGeometry4f>(
+ 2, "Color2");
+ const VArray<ColorGeometry4f> &mortar_values = params.readonly_single_input<ColorGeometry4f>(
+ 3, "Mortar");
+ const VArray<float> &scale = params.readonly_single_input<float>(4, "Scale");
+ const VArray<float> &mortar_size = params.readonly_single_input<float>(5, "Mortar Size");
+ const VArray<float> &mortar_smooth = params.readonly_single_input<float>(6, "Mortar Smooth");
+ const VArray<float> &bias = params.readonly_single_input<float>(7, "Bias");
+ const VArray<float> &brick_width = params.readonly_single_input<float>(8, "Brick Width");
+ const VArray<float> &row_height = params.readonly_single_input<float>(9, "Row Height");
+
+ MutableSpan<ColorGeometry4f> r_color =
+ params.uninitialized_single_output_if_required<ColorGeometry4f>(10, "Color");
+ MutableSpan<float> r_fac = params.uninitialized_single_output_if_required<float>(11, "Fac");
+
+ const bool store_fac = !r_fac.is_empty();
+ const bool store_color = !r_color.is_empty();
+
+ for (int64_t i : mask) {
+ const float2 f2 = brick(vector[i] * scale[i],
+ mortar_size[i],
+ mortar_smooth[i],
+ bias[i],
+ brick_width[i],
+ row_height[i],
+ offset_,
+ offset_freq_,
+ squash_,
+ squash_freq_);
+
+ float4 color_data, color1, color2, mortar;
+ copy_v4_v4(color_data, color1_values[i]);
+ copy_v4_v4(color1, color1_values[i]);
+ copy_v4_v4(color2, color2_values[i]);
+ copy_v4_v4(mortar, mortar_values[i]);
+ const float tint = f2.x;
+ const float f = f2.y;
+
+ if (f != 1.0f) {
+ const float facm = 1.0f - tint;
+ color_data = color1 * facm + color2 * tint;
+ }
+
+ if (store_color) {
+ color_data = color_data * (1.0f - f) + mortar * f;
+ copy_v4_v4(r_color[i], color_data);
+ }
+ if (store_fac) {
+ r_fac[i] = f;
+ }
+ }
+ }
+};
+
+static void sh_node_brick_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &node = builder.node();
+ NodeTexBrick *tex = (NodeTexBrick *)node.storage;
+
+ builder.construct_and_set_matching_fn<BrickFunction>(
+ tex->offset, tex->offset_freq, tex->squash, tex->squash_freq);
+}
+
+} // namespace blender::nodes
+
void register_node_type_sh_tex_brick(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE, 0);
ntype.declare = blender::nodes::sh_node_tex_brick_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_tex_brick);
node_type_storage(
&ntype, "NodeTexBrick", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_brick);
+ ntype.build_multi_function = blender::nodes::sh_node_brick_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
index 7ba468a93e0..7c1223a6a32 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
@@ -24,16 +24,16 @@ namespace blender::nodes {
static void sh_node_tex_checker_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f).implicit_field();
- b.add_input<decl::Color>("Color1").default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_input<decl::Color>("Color2").default_value({0.2f, 0.2f, 0.2f, 1.0f});
- b.add_input<decl::Float>("Scale")
+ b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
+ b.add_input<decl::Color>(N_("Color1")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Color2")).default_value({0.2f, 0.2f, 0.2f, 1.0f});
+ b.add_input<decl::Float>(N_("Scale"))
.min(-10000.0f)
.max(10000.0f)
.default_value(5.0f)
.no_muted_links();
- b.add_output<decl::Color>("Color");
- b.add_output<decl::Float>("Fac");
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Fac"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
index 4796af02361..33832c42b3c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
@@ -24,9 +24,9 @@ namespace blender::nodes {
static void sh_node_tex_gradient_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").hide_value().implicit_field();
- b.add_output<decl::Color>("Color").no_muted_links();
- b.add_output<decl::Float>("Fac").no_muted_links();
+ b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+ b.add_output<decl::Float>(N_("Fac")).no_muted_links();
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
index df1051c07b4..f20fc85cbe0 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
@@ -24,9 +24,9 @@ namespace blender::nodes {
static void sh_node_tex_image_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").implicit_field();
- b.add_output<decl::Color>("Color").no_muted_links();
- b.add_output<decl::Float>("Alpha").no_muted_links();
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+ b.add_output<decl::Float>(N_("Alpha")).no_muted_links();
};
}; // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
index b6cdcf86528..62e68d53d03 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
@@ -24,11 +24,11 @@ namespace blender::nodes {
static void sh_node_tex_magic_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").implicit_field();
- b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
- b.add_input<decl::Float>("Distortion").min(-1000.0f).max(1000.0f).default_value(1.0f);
- b.add_output<decl::Color>("Color").no_muted_links();
- b.add_output<decl::Float>("Fac").no_muted_links();
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
+ b.add_input<decl::Float>(N_("Distortion")).min(-1000.0f).max(1000.0f).default_value(1.0f);
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+ b.add_output<decl::Float>(N_("Fac")).no_muted_links();
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
index 61c26d07e2f..3bf4e24ed53 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
@@ -26,15 +26,15 @@ namespace blender::nodes {
static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").hide_value().implicit_field();
- b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f);
- b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
- b.add_input<decl::Float>("Detail").min(0.0f).max(16.0f).default_value(2.0f);
- b.add_input<decl::Float>("Dimension").min(0.0f).max(1000.0f).default_value(2.0f);
- b.add_input<decl::Float>("Lacunarity").min(0.0f).max(1000.0f).default_value(2.0f);
- b.add_input<decl::Float>("Offset").min(-1000.0f).max(1000.0f);
- b.add_input<decl::Float>("Gain").min(0.0f).max(1000.0f).default_value(1.0f);
- b.add_output<decl::Float>("Fac").no_muted_links();
+ b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
+ b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(16.0f).default_value(2.0f);
+ b.add_input<decl::Float>(N_("Dimension")).min(0.0f).max(1000.0f).default_value(2.0f);
+ b.add_input<decl::Float>(N_("Lacunarity")).min(0.0f).max(1000.0f).default_value(2.0f);
+ b.add_input<decl::Float>(N_("Offset")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Gain")).min(0.0f).max(1000.0f).default_value(1.0f);
+ b.add_output<decl::Float>(N_("Fac")).no_muted_links();
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
index 6ffc8979815..72892c32795 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
@@ -26,18 +26,18 @@ namespace blender::nodes {
static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").implicit_field();
- b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f);
- b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
- b.add_input<decl::Float>("Detail").min(0.0f).max(16.0f).default_value(2.0f);
- b.add_input<decl::Float>("Roughness")
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
+ b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(16.0f).default_value(2.0f);
+ b.add_input<decl::Float>(N_("Roughness"))
.min(0.0f)
.max(1.0f)
.default_value(0.5f)
.subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Distortion").min(-1000.0f).max(1000.0f).default_value(0.0f);
- b.add_output<decl::Float>("Fac").no_muted_links();
- b.add_output<decl::Color>("Color").no_muted_links();
+ b.add_input<decl::Float>(N_("Distortion")).min(-1000.0f).max(1000.0f).default_value(0.0f);
+ b.add_output<decl::Float>(N_("Fac")).no_muted_links();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
index 574260f3c36..422268b98c3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
@@ -26,25 +26,25 @@ namespace blender::nodes {
static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").hide_value().implicit_field();
- b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f);
- b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
- b.add_input<decl::Float>("Smoothness")
+ b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
+ b.add_input<decl::Float>(N_("Smoothness"))
.min(0.0f)
.max(1.0f)
.default_value(1.0f)
.subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Exponent").min(0.0f).max(32.0f).default_value(0.5f);
- b.add_input<decl::Float>("Randomness")
+ b.add_input<decl::Float>(N_("Exponent")).min(0.0f).max(32.0f).default_value(0.5f);
+ b.add_input<decl::Float>(N_("Randomness"))
.min(0.0f)
.max(1.0f)
.default_value(1.0f)
.subtype(PROP_FACTOR);
- b.add_output<decl::Float>("Distance").no_muted_links();
- b.add_output<decl::Color>("Color").no_muted_links();
- b.add_output<decl::Vector>("Position").no_muted_links();
- b.add_output<decl::Float>("W").no_muted_links();
- b.add_output<decl::Float>("Radius").no_muted_links();
+ b.add_output<decl::Float>(N_("Distance")).no_muted_links();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+ b.add_output<decl::Vector>(N_("Position")).no_muted_links();
+ b.add_output<decl::Float>(N_("W")).no_muted_links();
+ b.add_output<decl::Float>(N_("Radius")).no_muted_links();
};
} // namespace blender::nodes
@@ -239,16 +239,16 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
return params.readonly_single_input<float>(param_index, "Randomness");
};
auto get_r_distance = [&](int param_index) -> MutableSpan<float> {
- return params.uninitialized_single_output<float>(param_index, "Distance");
+ return params.uninitialized_single_output_if_required<float>(param_index, "Distance");
};
auto get_r_color = [&](int param_index) -> MutableSpan<ColorGeometry4f> {
- return params.uninitialized_single_output<ColorGeometry4f>(param_index, "Color");
+ return params.uninitialized_single_output_if_required<ColorGeometry4f>(param_index, "Color");
};
auto get_r_position = [&](int param_index) -> MutableSpan<float3> {
- return params.uninitialized_single_output<float3>(param_index, "Position");
+ return params.uninitialized_single_output_if_required<float3>(param_index, "Position");
};
auto get_r_w = [&](int param_index) -> MutableSpan<float> {
- return params.uninitialized_single_output<float>(param_index, "W");
+ return params.uninitialized_single_output_if_required<float>(param_index, "W");
};
int param = 0;
@@ -263,6 +263,9 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
@@ -271,12 +274,16 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
exponent[i],
rand,
SHD_VORONOI_MINKOWSKI,
- &r_distance[i],
- &col,
- &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float2::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, 0.0f);
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = float2::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
}
break;
}
@@ -288,6 +295,9 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
@@ -296,12 +306,16 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
exponent[i],
rand,
SHD_VORONOI_MINKOWSKI,
- &r_distance[i],
- &col,
- &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float2::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, 0.0f);
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = float2::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
}
break;
}
@@ -314,6 +328,9 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
@@ -324,12 +341,16 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
exponent[i],
rand,
SHD_VORONOI_MINKOWSKI,
- &r_distance[i],
- &col,
- &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float2::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, 0.0f);
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = float2::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
}
break;
}
@@ -346,6 +367,9 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
@@ -353,11 +377,15 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
exponent[i],
rand,
SHD_VORONOI_MINKOWSKI,
- &r_distance[i],
- &col,
- &r_position[i]);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ }
}
break;
}
@@ -369,6 +397,9 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
@@ -376,11 +407,15 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
exponent[i],
rand,
SHD_VORONOI_MINKOWSKI,
- &r_distance[i],
- &col,
- &r_position[i]);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ }
}
break;
}
@@ -393,6 +428,9 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
@@ -402,11 +440,15 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
exponent[i],
rand,
SHD_VORONOI_MINKOWSKI,
- &r_distance[i],
- &col,
- &r_position[i]);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ }
}
break;
}
@@ -425,16 +467,34 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
float3 col;
float4 pos;
- noise::voronoi_f1(p, exponent[i], rand, SHD_VORONOI_F1, &r_distance[i], &col, &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float4::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, pos.z);
- r_w[i] = pos.w;
+ noise::voronoi_f1(p,
+ exponent[i],
+ rand,
+ SHD_VORONOI_F1,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = float4::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
}
break;
}
@@ -448,17 +508,34 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
float3 col;
float4 pos;
- noise::voronoi_f2(
- p, exponent[i], rand, SHD_VORONOI_MINKOWSKI, &r_distance[i], &col, &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float4::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, pos.z);
- r_w[i] = pos.w;
+ noise::voronoi_f2(p,
+ exponent[i],
+ rand,
+ SHD_VORONOI_MINKOWSKI,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = float4::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
}
break;
}
@@ -473,18 +550,36 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
for (int64_t i : mask) {
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
float3 col;
float4 pos;
- noise::voronoi_smooth_f1(
- p, smth, exponent[i], rand, SHD_VORONOI_MINKOWSKI, &r_distance[i], &col, &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float4::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, pos.z);
- r_w[i] = pos.w;
+ noise::voronoi_smooth_f1(p,
+ smth,
+ exponent[i],
+ rand,
+ SHD_VORONOI_MINKOWSKI,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = float4::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
}
break;
}
@@ -572,16 +667,16 @@ class VoronoiMetricFunction : public fn::MultiFunction {
return params.readonly_single_input<float>(param_index, "Randomness");
};
auto get_r_distance = [&](int param_index) -> MutableSpan<float> {
- return params.uninitialized_single_output<float>(param_index, "Distance");
+ return params.uninitialized_single_output_if_required<float>(param_index, "Distance");
};
auto get_r_color = [&](int param_index) -> MutableSpan<ColorGeometry4f> {
- return params.uninitialized_single_output<ColorGeometry4f>(param_index, "Color");
+ return params.uninitialized_single_output_if_required<ColorGeometry4f>(param_index, "Color");
};
auto get_r_position = [&](int param_index) -> MutableSpan<float3> {
- return params.uninitialized_single_output<float3>(param_index, "Position");
+ return params.uninitialized_single_output_if_required<float3>(param_index, "Position");
};
auto get_r_w = [&](int param_index) -> MutableSpan<float> {
- return params.uninitialized_single_output<float>(param_index, "W");
+ return params.uninitialized_single_output_if_required<float>(param_index, "W");
};
int param = 0;
@@ -595,13 +690,24 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_w = !r_w.is_empty();
for (int64_t i : mask) {
const float p = w[i] * scale[i];
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
- noise::voronoi_f1(p, rand, &r_distance[i], &col, &r_w[i]);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- r_w[i] = safe_divide(r_w[i], scale[i]);
+ noise::voronoi_f1(p,
+ rand,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_w ? &r_w[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_w) {
+ r_w[i] = safe_divide(r_w[i], scale[i]);
+ }
}
break;
}
@@ -612,13 +718,24 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_w = !r_w.is_empty();
for (int64_t i : mask) {
const float p = w[i] * scale[i];
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
- noise::voronoi_f2(p, rand, &r_distance[i], &col, &r_w[i]);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- r_w[i] = safe_divide(r_w[i], scale[i]);
+ noise::voronoi_f2(p,
+ rand,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_w ? &r_w[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_w) {
+ r_w[i] = safe_divide(r_w[i], scale[i]);
+ }
}
break;
}
@@ -630,14 +747,26 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_w = !r_w.is_empty();
for (int64_t i : mask) {
const float p = w[i] * scale[i];
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
- noise::voronoi_smooth_f1(p, smth, rand, &r_distance[i], &col, &r_w[i]);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- r_w[i] = safe_divide(r_w[i], scale[i]);
+ noise::voronoi_smooth_f1(p,
+ smth,
+ rand,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_w ? &r_w[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_w) {
+ r_w[i] = safe_divide(r_w[i], scale[i]);
+ }
}
break;
}
@@ -653,6 +782,9 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
@@ -661,12 +793,16 @@ class VoronoiMetricFunction : public fn::MultiFunction {
0.0f,
rand,
metric_,
- &r_distance[i],
- &col,
- &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float2::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, 0.0f);
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = float2::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
}
break;
}
@@ -677,6 +813,9 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
@@ -685,12 +824,16 @@ class VoronoiMetricFunction : public fn::MultiFunction {
0.0f,
rand,
metric_,
- &r_distance[i],
- &col,
- &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float2::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, 0.0f);
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = float2::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
}
break;
}
@@ -702,6 +845,9 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
@@ -712,12 +858,16 @@ class VoronoiMetricFunction : public fn::MultiFunction {
0.0f,
rand,
metric_,
- &r_distance[i],
- &col,
- &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float2::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, 0.0f);
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = float2::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
}
break;
}
@@ -733,13 +883,25 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
- noise::voronoi_f1(
- vector[i] * scale[i], 0.0f, rand, metric_, &r_distance[i], &col, &r_position[i]);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ noise::voronoi_f1(vector[i] * scale[i],
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ }
}
break;
}
@@ -750,13 +912,25 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
float3 col;
- noise::voronoi_f2(
- vector[i] * scale[i], 0.0f, rand, metric_, &r_distance[i], &col, &r_position[i]);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ noise::voronoi_f2(vector[i] * scale[i],
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ }
}
break;
}
@@ -768,21 +942,31 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<float> r_distance = get_r_distance(param++);
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
- for (int64_t i : mask) {
- const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
- const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
- float3 col;
- noise::voronoi_smooth_f1(vector[i] * scale[i],
- smth,
- 0.0f,
- rand,
- metric_,
- &r_distance[i],
- &col,
- &r_position[i]);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ {
+ for (int64_t i : mask) {
+ const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ noise::voronoi_smooth_f1(vector[i] * scale[i],
+ smth,
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ }
+ }
}
+
break;
}
}
@@ -799,16 +983,34 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
float3 col;
float4 pos;
- noise::voronoi_f1(p, 0.0f, rand, metric_, &r_distance[i], &col, &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float4::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, pos.z);
- r_w[i] = pos.w;
+ noise::voronoi_f1(p,
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = float4::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
}
break;
}
@@ -821,16 +1023,34 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
for (int64_t i : mask) {
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
float3 col;
float4 pos;
- noise::voronoi_f2(p, 0.0f, rand, metric_, &r_distance[i], &col, &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float4::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, pos.z);
- r_w[i] = pos.w;
+ noise::voronoi_f2(p,
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = float4::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
}
break;
}
@@ -844,17 +1064,36 @@ class VoronoiMetricFunction : public fn::MultiFunction {
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
MutableSpan<float3> r_position = get_r_position(param++);
MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
for (int64_t i : mask) {
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
float3 col;
float4 pos;
- noise::voronoi_smooth_f1(p, smth, 0.0f, rand, metric_, &r_distance[i], &col, &pos);
- r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
- pos = float4::safe_divide(pos, scale[i]);
- r_position[i] = float3(pos.x, pos.y, pos.z);
- r_w[i] = pos.w;
+ noise::voronoi_smooth_f1(p,
+ smth,
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = float4::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
}
break;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
index 25e65e3d3f0..144aa1885bd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
@@ -26,19 +26,19 @@ namespace blender::nodes {
static void sh_node_tex_wave_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").implicit_field();
- b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
- b.add_input<decl::Float>("Distortion").min(-1000.0f).max(1000.0f).default_value(0.0f);
- b.add_input<decl::Float>("Detail").min(0.0f).max(16.0f).default_value(2.0f);
- b.add_input<decl::Float>("Detail Scale").min(-1000.0f).max(1000.0f).default_value(1.0f);
- b.add_input<decl::Float>("Detail Roughness")
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
+ b.add_input<decl::Float>(N_("Distortion")).min(-1000.0f).max(1000.0f).default_value(0.0f);
+ b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(16.0f).default_value(2.0f);
+ b.add_input<decl::Float>(N_("Detail Scale")).min(-1000.0f).max(1000.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("Detail Roughness"))
.min(0.0f)
.max(1.0f)
.default_value(0.5f)
.subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Phase Offset").min(-1000.0f).max(1000.0f).default_value(0.0f);
- b.add_output<decl::Color>("Color").no_muted_links();
- b.add_output<decl::Float>("Fac").no_muted_links();
+ b.add_input<decl::Float>(N_("Phase Offset")).min(-1000.0f).max(1000.0f).default_value(0.0f);
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+ b.add_output<decl::Float>(N_("Fac")).no_muted_links();
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
index 445b201e419..43ee9400551 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
@@ -26,10 +26,10 @@ namespace blender::nodes {
static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f).implicit_field();
- b.add_input<decl::Float>("W").min(-10000.0f).max(10000.0f);
- b.add_output<decl::Float>("Value");
- b.add_output<decl::Color>("Color");
+ b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
+ b.add_input<decl::Float>(N_("W")).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Float>(N_("Value"));
+ b.add_output<decl::Color>(N_("Color"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
index 2544ea1921c..e4f1b2c76f0 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
@@ -34,9 +34,9 @@ namespace blender::nodes {
static void sh_node_valtorgb_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Fac").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_output<decl::Color>("Color");
- b.add_output<decl::Float>("Alpha");
+ b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Alpha"));
};
} // namespace blender::nodes
@@ -192,8 +192,8 @@ namespace blender::nodes {
static void sh_node_rgbtobw_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Color").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_output<decl::Float>("Val");
+ b.add_input<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_output<decl::Float>(N_("Val"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc
index 1344ce5c5d9..b0f152d8526 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -27,7 +27,7 @@ namespace blender::nodes {
static void sh_node_value_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Value");
+ b.add_output<decl::Float>(N_("Value"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
index f49ff06cef1..ca5aeea9a7d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
@@ -30,12 +30,12 @@ namespace blender::nodes {
static void sh_node_vector_math_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Vector>("Vector", "Vector_001").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Vector>("Vector", "Vector_002").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Scale").default_value(1.0f).min(-10000.0f).max(10000.0f);
- b.add_output<decl::Vector>("Vector");
- b.add_output<decl::Float>("Value");
+ b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Vector>(N_("Vector"), "Vector_001").min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Vector>(N_("Vector"), "Vector_002").min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
+ b.add_output<decl::Float>(N_("Value"));
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
index c9b26fa5199..1ab643bc3fa 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -28,12 +28,12 @@ namespace blender::nodes {
static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").min(0.0f).max(1.0f).hide_value();
- b.add_input<decl::Vector>("Center");
- b.add_input<decl::Vector>("Axis").min(-1.0f).max(1.0f).default_value({0.0f, 0.0f, 1.0f});
- b.add_input<decl::Float>("Angle").subtype(PROP_ANGLE);
- b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER);
- b.add_output<decl::Vector>("Vector");
+ b.add_input<decl::Vector>(N_("Vector")).min(0.0f).max(1.0f).hide_value();
+ b.add_input<decl::Vector>(N_("Center"));
+ b.add_input<decl::Vector>(N_("Axis")).min(-1.0f).max(1.0f).default_value({0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE);
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
+ b.add_output<decl::Vector>(N_("Vector"));
};
} // namespace blender::nodes
diff --git a/source/blender/python/generic/bl_math_py_api.c b/source/blender/python/generic/bl_math_py_api.c
index 5e938db0c35..2211cc931da 100644
--- a/source/blender/python/generic/bl_math_py_api.c
+++ b/source/blender/python/generic/bl_math_py_api.c
@@ -99,21 +99,21 @@ static PyObject *py_bl_math_lerp(PyObject *UNUSED(self), PyObject *args)
return PyFloat_FromDouble(a * (1.0 - x) + b * x);
}
-PyDoc_STRVAR(
- py_bl_math_smoothstep_doc,
- ".. function:: smoothstep(from_value, to_value, value)\n"
- "\n"
- " Performs smooth interpolation between 0 and 1 as value changes between from and to values.\n"
- " Outside the range the function returns the same value as the nearest edge.\n"
- "\n"
- " :arg from_value: The edge value where the result is 0.\n"
- " :type from_value: float\n"
- " :arg to_value: The edge value where the result is 1.\n"
- " :type to_value: float\n"
- " :arg factor: The interpolation value.\n"
- " :type factor: float\n"
- " :return: The interpolated value in [0.0, 1.0].\n"
- " :rtype: float\n");
+PyDoc_STRVAR(py_bl_math_smoothstep_doc,
+ ".. function:: smoothstep(from_value, to_value, value)\n"
+ "\n"
+ " Performs smooth interpolation between 0 and 1 as value changes between from and "
+ "to values.\n"
+ " Outside the range the function returns the same value as the nearest edge.\n"
+ "\n"
+ " :arg from_value: The edge value where the result is 0.\n"
+ " :type from_value: float\n"
+ " :arg to_value: The edge value where the result is 1.\n"
+ " :type to_value: float\n"
+ " :arg factor: The interpolation value.\n"
+ " :type factor: float\n"
+ " :return: The interpolated value in [0.0, 1.0].\n"
+ " :rtype: float\n");
static PyObject *py_bl_math_smoothstep(PyObject *UNUSED(self), PyObject *args)
{
double a, b, x;
diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h
index d2a47a13db3..4de7c09640b 100644
--- a/source/blender/sequencer/SEQ_iterator.h
+++ b/source/blender/sequencer/SEQ_iterator.h
@@ -104,6 +104,11 @@ void SEQ_query_strip_effect_chain(struct Sequence *seq_reference,
SeqCollection *collection);
void SEQ_filter_selected_strips(SeqCollection *collection);
+/* Utilities to access these as tags. */
+int SEQ_query_rendered_strips_to_tag(ListBase *seqbase,
+ const int timeline_frame,
+ const int displayed_channel);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h
index c9024614dfd..df3c9a40409 100644
--- a/source/blender/sequencer/SEQ_time.h
+++ b/source/blender/sequencer/SEQ_time.h
@@ -32,6 +32,8 @@ struct Scene;
struct Sequence;
struct rctf;
+void SEQ_timeline_init_boundbox(const struct Scene *scene, struct rctf *rect);
+void SEQ_timeline_expand_boundbox(const struct ListBase *seqbase, struct rctf *rect);
void SEQ_timeline_boundbox(const struct Scene *scene,
const struct ListBase *seqbase,
struct rctf *rect);
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 427a8835879..b9ee23a9186 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -2451,7 +2451,6 @@ static void do_transform_effect(const SeqRenderData *context,
int total_lines,
ImBuf *out)
{
- Scene *scene = context->scene;
TransformVars *transform = (TransformVars *)seq->effectdata;
float scale_x, scale_y, translate_x, translate_y, rotate_radians;
@@ -2469,10 +2468,14 @@ static void do_transform_effect(const SeqRenderData *context,
/* Translate */
if (!transform->percent) {
- float rd_s = (scene->r.size / 100.0f);
+ /* Compensate text size for preview render size. */
+ double proxy_size_comp = context->scene->r.size / 100.0;
+ if (context->preview_render_size != SEQ_RENDER_SIZE_SCENE) {
+ proxy_size_comp = SEQ_rendersize_to_scale_factor(context->preview_render_size);
+ }
- translate_x = transform->xIni * rd_s + (x / 2.0f);
- translate_y = transform->yIni * rd_s + (y / 2.0f);
+ translate_x = transform->xIni * proxy_size_comp + (x / 2.0f);
+ translate_y = transform->yIni * proxy_size_comp + (y / 2.0f);
}
else {
translate_x = x * (transform->xIni / 100.0f) + (x / 2.0f);
diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c
index a12a5cbdc61..68f632ddb28 100644
--- a/source/blender/sequencer/intern/iterator.c
+++ b/source/blender/sequencer/intern/iterator.c
@@ -520,3 +520,29 @@ void SEQ_filter_selected_strips(SeqCollection *collection)
}
}
}
+
+static void seq_collection_to_tag(ListBase *seqbase, SeqCollection *collection)
+{
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ seq->tmp_tag = false;
+ }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ seq->tmp_tag = true;
+ }
+}
+
+/* Utilities to access these as tags. */
+int SEQ_query_rendered_strips_to_tag(ListBase *seqbase,
+ const int timeline_frame,
+ const int displayed_channel)
+{
+ SeqCollection *collection = SEQ_query_rendered_strips(
+ seqbase, timeline_frame, displayed_channel);
+
+ seq_collection_to_tag(seqbase, collection);
+
+ const int len = SEQ_collection_len(collection);
+ SEQ_collection_free(collection);
+ return len;
+}
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index 1c5f4c3ab76..92ac580f3b1 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -376,19 +376,27 @@ float SEQ_time_sequence_get_fps(Scene *scene, Sequence *seq)
}
/**
- * Define boundary rectangle of sequencer timeline and fill in rect data
+ * Initialize given rectangle with the Scene's timeline boundaries.
*
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param rect: data structure describing rectangle, that will be filled in by this function
+ * \param scene: the Scene instance whose timeline boundaries are extracted from
+ * \param rect: output parameter to be filled with timeline boundaries
*/
-void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
+void SEQ_timeline_init_boundbox(const Scene *scene, rctf *rect)
{
rect->xmin = scene->r.sfra;
rect->xmax = scene->r.efra + 1;
rect->ymin = 0.0f;
rect->ymax = 8.0f;
+}
+/**
+ * Stretch the given rectangle to include the given strips boundaries
+ *
+ * \param seqbase: ListBase in which strips are located
+ * \param rect: output parameter to be filled with strips' boundaries
+ */
+void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
+{
if (seqbase == NULL) {
return;
}
@@ -406,6 +414,19 @@ void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *re
}
}
+/**
+ * Define boundary rectangle of sequencer timeline and fill in rect data
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param rect: data structure describing rectangle, that will be filled in by this function
+ */
+void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
+{
+ SEQ_timeline_init_boundbox(scene, rect);
+ SEQ_timeline_expand_boundbox(seqbase, rect);
+}
+
static bool strip_exists_at_frame(SeqCollection *all_strips, const int timeline_frame)
{
Sequence *seq;
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 4d65726fe2b..03b2fb49085 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -202,6 +202,7 @@ if(WITH_XR_OPENXR)
xr/intern/wm_xr_action.c
xr/intern/wm_xr_actionmap.c
xr/intern/wm_xr_draw.c
+ xr/intern/wm_xr_operators.c
xr/intern/wm_xr_session.c
xr/wm_xr.h
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index eaf32c06aba..112d76a3e65 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -276,10 +276,10 @@ typedef void(wmEventHandler_KeymapDynamicFn)(wmWindowManager *wm,
struct wmEventHandler_Keymap *handler,
struct wmEventHandler_KeymapResult *km_result);
-void WM_event_get_keymap_from_toolsystem_fallback(struct wmWindowManager *wm,
- struct wmWindow *win,
- struct wmEventHandler_Keymap *handler,
- wmEventHandler_KeymapResult *km_result);
+void WM_event_get_keymap_from_toolsystem_with_gizmos(struct wmWindowManager *wm,
+ struct wmWindow *win,
+ struct wmEventHandler_Keymap *handler,
+ wmEventHandler_KeymapResult *km_result);
void WM_event_get_keymap_from_toolsystem(struct wmWindowManager *wm,
struct wmWindow *win,
struct wmEventHandler_Keymap *handler,
@@ -740,24 +740,38 @@ struct wmDropBox *WM_dropbox_add(
void (*copy)(struct wmDrag *, struct wmDropBox *),
void (*cancel)(struct Main *, struct wmDrag *, struct wmDropBox *),
WMDropboxTooltipFunc tooltip);
+void WM_drag_draw_item_name_fn(struct bContext *C,
+ struct wmWindow *win,
+ struct wmDrag *drag,
+ const int xy[2]);
+void WM_drag_draw_default_fn(struct bContext *C,
+ struct wmWindow *win,
+ struct wmDrag *drag,
+ const int xy[2]);
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid);
/* ID drag and drop */
+ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, int flag_extra);
+bool WM_drag_asset_will_import_linked(const wmDrag *drag);
void WM_drag_add_local_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent);
struct ID *WM_drag_get_local_ID(const struct wmDrag *drag, short idcode);
struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short idcode);
bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode);
wmDragAsset *WM_drag_create_asset_data(const struct AssetHandle *asset,
+ struct AssetMetaData *metadata,
const char *path,
int import_type);
struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode);
+struct AssetMetaData *WM_drag_get_asset_meta_data(const struct wmDrag *drag, int idcode);
struct ID *WM_drag_get_local_ID_or_import_from_asset(const struct wmDrag *drag, int idcode);
void WM_drag_free_imported_drag_ID(struct Main *bmain,
struct wmDrag *drag,
struct wmDropBox *drop);
+struct wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const struct wmDrag *drag);
+
void WM_drag_add_asset_list_item(wmDrag *drag,
const struct bContext *C,
const struct AssetLibraryReference *asset_library_ref,
@@ -923,6 +937,7 @@ bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
bool WM_event_is_last_mousemove(const struct wmEvent *event);
bool WM_event_is_mouse_drag(const struct wmEvent *event);
bool WM_event_is_mouse_drag_or_press(const wmEvent *event);
+bool WM_cursor_test_motion_and_update(const int mval[2]) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
int WM_event_drag_threshold(const struct wmEvent *event);
bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]);
@@ -1017,6 +1032,13 @@ bool WM_xr_session_state_controller_aim_location_get(const wmXrData *xr,
bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr,
unsigned int subaction_idx,
float r_rotation[4]);
+bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3]);
+void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3]);
+bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4]);
+void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4]);
+bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale);
+void WM_xr_session_state_nav_scale_set(wmXrData *xr, float scale);
+void WM_xr_session_state_navigation_reset(struct wmXrSessionState *state);
struct ARegionType *WM_xr_surface_controller_region_type_get(void);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index f4595869baf..9f427a90353 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -119,6 +119,7 @@ struct wmWindowManager;
#include "BLI_compiler_attrs.h"
#include "DNA_listBase.h"
+#include "DNA_uuid_types.h"
#include "DNA_vec_types.h"
#include "DNA_xr_types.h"
#include "RNA_types.h"
@@ -967,6 +968,7 @@ typedef void (*wmPaintCursorDraw)(struct bContext *C, int, int, void *customdata
#define WM_DRAG_VALUE 6
#define WM_DRAG_COLOR 7
#define WM_DRAG_DATASTACK 8
+#define WM_DRAG_ASSET_CATALOG 9
typedef enum wmDragFlags {
WM_DRAG_NOP = 0,
@@ -989,6 +991,7 @@ typedef struct wmDragAsset {
/* Always freed. */
const char *path;
int id_type;
+ struct AssetMetaData *metadata;
int import_type; /* eFileAssetImportType */
/* FIXME: This is temporary evil solution to get scene/view-layer/etc in the copy callback of the
@@ -999,6 +1002,10 @@ typedef struct wmDragAsset {
struct bContext *evil_C;
} wmDragAsset;
+typedef struct wmDragAssetCatalog {
+ bUUID drag_catalog_id;
+} wmDragAssetCatalog;
+
/**
* For some specific cases we support dragging multiple assets (#WM_DRAG_ASSET_LIST). There is no
* proper support for dragging multiple items in the `wmDrag`/`wmDrop` API yet, so this is really
@@ -1020,7 +1027,7 @@ typedef struct wmDragAssetListItem {
typedef char *(*WMDropboxTooltipFunc)(struct bContext *,
struct wmDrag *,
- const struct wmEvent *event,
+ const int xy[2],
struct wmDropBox *drop);
typedef struct wmDrag {
@@ -1038,8 +1045,16 @@ typedef struct wmDrag {
float scale;
int sx, sy;
- /** If filled, draws operator tooltip/operator name. */
- char tooltip[200];
+ /** Informs which dropbox is activated with the drag item.
+ * When this value changes, the #draw_activate and #draw_deactivate dropbox callbacks are
+ * triggered.
+ */
+ struct wmDropBox *active_dropbox;
+ /* Text to show when the operator poll fails. Typically the message the
+ * operator set with CTX_wm_operator_poll_msg_set(). */
+ const char *disabled_info;
+ bool free_disabled_info;
+
unsigned int flags;
/** List of wmDragIDs, all are guaranteed to have the same ID type. */
@@ -1067,6 +1082,18 @@ typedef struct wmDropBox {
*/
void (*cancel)(struct Main *, struct wmDrag *, struct wmDropBox *);
+ /** Override the default drawing function. */
+ void (*draw)(struct bContext *, struct wmWindow *, struct wmDrag *, const int *);
+
+ /** Called when pool returns true the first time. */
+ void (*draw_activate)(struct wmDropBox *, struct wmDrag *drag);
+
+ /** Called when pool returns false the first time or when the drag event ends. */
+ void (*draw_deactivate)(struct wmDropBox *, struct wmDrag *drag);
+
+ /** Custom data for drawing. */
+ void *draw_data;
+
/** Custom tooltip shown during dragging. */
WMDropboxTooltipFunc tooltip;
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 0b7d5e5f1f4..47ee296823b 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -86,18 +86,23 @@ static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data)
wmWindowManager *wm = (wmWindowManager *)id;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
- BKE_LIB_FOREACHID_PROCESS(data, win->scene, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, win->scene, IDWALK_CB_USER_ONE);
/* This pointer can be NULL during old files reading, better be safe than sorry. */
if (win->workspace_hook != NULL) {
ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
- BKE_LIB_FOREACHID_PROCESS_ID(data, workspace, IDWALK_CB_NOP);
+ BKE_lib_query_foreachid_process(data, &workspace, IDWALK_CB_USER);
/* Allow callback to set a different workspace. */
BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
+ if (BKE_lib_query_foreachid_iter_stop(data)) {
+ return;
+ }
}
+
if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
- BKE_screen_foreach_id_screen_area(data, area);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
+ BKE_screen_foreach_id_screen_area(data, area));
}
}
}
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 9af90355a79..b9f0e09d106 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -40,9 +40,13 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_screen.h"
+
+#include "GHOST_C-api.h"
#include "BLO_readfile.h"
@@ -63,6 +67,7 @@
#include "WM_api.h"
#include "WM_types.h"
#include "wm_event_system.h"
+#include "wm_window.h"
/* ****************************************************** */
@@ -176,6 +181,7 @@ wmDrag *WM_event_start_drag(
}
break;
case WM_DRAG_ASSET:
+ case WM_DRAG_ASSET_CATALOG:
/* Move ownership of poin to wmDrag. */
drag->poin = poin;
drag->flags |= WM_DRAG_FREE_DATA;
@@ -202,6 +208,31 @@ wmDrag *WM_event_start_drag(
return drag;
}
+/**
+ * Additional work to cleanly end dragging. Additional because this doesn't actually remove the
+ * drag items. Should be called whenever dragging is stopped (successful or not, also when
+ * canceled).
+ */
+void wm_drags_exit(wmWindowManager *wm, wmWindow *win)
+{
+ bool any_active = false;
+ LISTBASE_FOREACH (const wmDrag *, drag, &wm->drags) {
+ if (drag->active_dropbox) {
+ any_active = true;
+ break;
+ }
+ }
+
+ /* If there is no active drop-box #wm_drags_check_ops() set a stop-cursor, which needs to be
+ * restored. */
+ if (!any_active) {
+ WM_cursor_modal_restore(win);
+ /* Ensure the correct area cursor is restored. */
+ win->tag_cursor_refresh = true;
+ WM_event_add_mousemove(win);
+ }
+}
+
void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy)
{
drag->imb = imb;
@@ -229,9 +260,15 @@ void WM_drag_data_free(int dragtype, void *poin)
void WM_drag_free(wmDrag *drag)
{
+ if (drag->active_dropbox && drag->active_dropbox->draw_deactivate) {
+ drag->active_dropbox->draw_deactivate(drag->active_dropbox, drag);
+ }
if (drag->flags & WM_DRAG_FREE_DATA) {
WM_drag_data_free(drag->type, drag->poin);
}
+ if (drag->free_disabled_info) {
+ MEM_SAFE_FREE(drag->disabled_info);
+ }
BLI_freelistN(&drag->ids);
LISTBASE_FOREACH_MUTABLE (wmDragAssetListItem *, asset_item, &drag->asset_items) {
if (asset_item->is_external) {
@@ -250,11 +287,11 @@ void WM_drag_free_list(struct ListBase *lb)
}
}
-static char *dropbox_tooltip(bContext *C, wmDrag *drag, const wmEvent *event, wmDropBox *drop)
+static char *dropbox_tooltip(bContext *C, wmDrag *drag, const int xy[2], wmDropBox *drop)
{
char *tooltip = NULL;
if (drop->tooltip) {
- tooltip = drop->tooltip(C, drag, event, drop);
+ tooltip = drop->tooltip(C, drag, xy, drop);
}
if (!tooltip) {
tooltip = BLI_strdup(WM_operatortype_name(drop->ot, drop->ptr));
@@ -269,15 +306,35 @@ static wmDropBox *dropbox_active(bContext *C,
wmDrag *drag,
const wmEvent *event)
{
+ if (drag->free_disabled_info) {
+ MEM_SAFE_FREE(drag->disabled_info);
+ }
+ drag->disabled_info = NULL;
+
LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
if (handler_base->type == WM_HANDLER_TYPE_DROPBOX) {
wmEventHandler_Dropbox *handler = (wmEventHandler_Dropbox *)handler_base;
if (handler->dropboxes) {
LISTBASE_FOREACH (wmDropBox *, drop, handler->dropboxes) {
- if (drop->poll(C, drag, event) &&
- WM_operator_poll_context(C, drop->ot, drop->opcontext)) {
+ if (!drop->poll(C, drag, event)) {
+ /* If the drop's poll fails, don't set the disabled-info. This would be too aggressive.
+ * Instead show it only if the drop box could be used in principle, but the operator
+ * can't be executed. */
+ continue;
+ }
+
+ if (WM_operator_poll_context(C, drop->ot, drop->opcontext)) {
return drop;
}
+
+ /* Attempt to set the disabled hint when the poll fails. Will always be the last hint set
+ * when there are multiple failing polls (could allow multiple disabled-hints too). */
+ bool free_disabled_info = false;
+ const char *disabled_hint = CTX_wm_operator_poll_msg_get(C, &free_disabled_info);
+ if (disabled_hint) {
+ drag->disabled_info = disabled_hint;
+ drag->free_disabled_info = free_disabled_info;
+ }
}
}
}
@@ -286,7 +343,7 @@ static wmDropBox *dropbox_active(bContext *C,
}
/* return active operator tooltip/name when mouse is in box */
-static char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event)
+static wmDropBox *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
wmDropBox *drop = dropbox_active(C, &win->handlers, drag, event);
@@ -298,13 +355,13 @@ static char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event)
ARegion *region = CTX_wm_region(C);
drop = dropbox_active(C, &region->handlers, drag, event);
}
- if (drop) {
- return dropbox_tooltip(C, drag, event, drop);
- }
- return NULL;
+ return drop;
}
-static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *event)
+/**
+ * Update dropping information for the current mouse position in \a event.
+ */
+static void wm_drop_update_active(bContext *C, wmDrag *drag, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
const int winsize_x = WM_window_pixels_x(win);
@@ -316,24 +373,30 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *e
return;
}
- drag->tooltip[0] = 0;
-
- /* check buttons (XXX todo rna and value) */
- if (UI_but_active_drop_name(C)) {
- BLI_strncpy(drag->tooltip, IFACE_("Paste name"), sizeof(drag->tooltip));
+ wmDropBox *drop_prev = drag->active_dropbox;
+ wmDropBox *drop = wm_dropbox_active(C, drag, event);
+ if (drop != drop_prev) {
+ if (drop_prev && drop_prev->draw_deactivate) {
+ drop_prev->draw_deactivate(drop_prev, drag);
+ BLI_assert(drop_prev->draw_data == NULL);
+ }
+ if (drop && drop->draw_activate) {
+ drop->draw_activate(drop, drag);
+ }
+ drag->active_dropbox = drop;
}
- else {
- char *tooltip = wm_dropbox_active(C, drag, event);
+}
- if (tooltip) {
- BLI_strncpy(drag->tooltip, tooltip, sizeof(drag->tooltip));
- MEM_freeN(tooltip);
- // WM_cursor_modal_set(win, WM_CURSOR_COPY);
- }
- // else
- // WM_cursor_modal_restore(win);
- /* unsure about cursor type, feels to be too much */
+void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop)
+{
+ /* Optionally copy drag information to operator properties. Don't call it if the
+ * operator fails anyway, it might do more than just set properties (e.g.
+ * typically import an asset). */
+ if (drop->copy && WM_operator_poll_context(C, drop->ot, drop->opcontext)) {
+ drop->copy(drag, drop);
}
+
+ wm_drags_exit(CTX_wm_manager(C), CTX_wm_window(C));
}
/* called in inner handler loop, region context */
@@ -341,8 +404,19 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ bool any_active = false;
LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) {
- wm_drop_operator_options(C, drag, event);
+ wm_drop_update_active(C, drag, event);
+
+ if (drag->active_dropbox) {
+ any_active = true;
+ }
+ }
+
+ /* Change the cursor to display that dropping isn't possible here. But only if there is something
+ * being dragged actually. Cursor will be restored in #wm_drags_exit(). */
+ if (!BLI_listbase_is_empty(&wm->drags)) {
+ WM_cursor_modal_set(CTX_wm_window(C), any_active ? WM_CURSOR_DEFAULT : WM_CURSOR_STOP);
}
}
@@ -407,11 +481,15 @@ bool WM_drag_is_ID_type(const wmDrag *drag, int idcode)
/**
* \note: Does not store \a asset in any way, so it's fine to pass a temporary.
*/
-wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset, const char *path, int import_type)
+wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset,
+ AssetMetaData *metadata,
+ const char *path,
+ int import_type)
{
wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset");
BLI_strncpy(asset_drag->name, ED_asset_handle_get_name(asset), sizeof(asset_drag->name));
+ asset_drag->metadata = metadata;
asset_drag->path = path;
asset_drag->id_type = ED_asset_handle_get_id_type(asset);
asset_drag->import_type = import_type;
@@ -435,8 +513,30 @@ wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode)
return (ELEM(idcode, 0, asset_drag->id_type)) ? asset_drag : NULL;
}
-static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
+struct AssetMetaData *WM_drag_get_asset_meta_data(const wmDrag *drag, int idcode)
+{
+ wmDragAsset *drag_asset = WM_drag_get_asset_data(drag, idcode);
+ if (drag_asset) {
+ return drag_asset->metadata;
+ }
+
+ ID *local_id = WM_drag_get_local_ID(drag, idcode);
+ if (local_id) {
+ return local_id->asset_data;
+ }
+
+ return NULL;
+}
+
+/**
+ * \param flag_extra: Additional linking flags (from #eFileSel_Params_Flag).
+ */
+ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, const int flag_extra)
{
+ /* Only support passing in limited flags. */
+ BLI_assert(flag_extra == (flag_extra & FILE_AUTOSELECT));
+ eFileSel_Params_Flag flag = flag_extra | FILE_ACTIVE_COLLECTION;
+
const char *name = asset_drag->name;
ID_Type idtype = asset_drag->id_type;
@@ -450,14 +550,8 @@ static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
switch ((eFileAssetImportType)asset_drag->import_type) {
case FILE_ASSET_IMPORT_LINK:
- return WM_file_link_datablock(bmain,
- scene,
- view_layer,
- view3d,
- asset_drag->path,
- idtype,
- name,
- FILE_ACTIVE_COLLECTION);
+ return WM_file_link_datablock(
+ bmain, scene, view_layer, view3d, asset_drag->path, idtype, name, flag);
case FILE_ASSET_IMPORT_APPEND:
return WM_file_append_datablock(bmain,
scene,
@@ -466,7 +560,7 @@ static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
asset_drag->path,
idtype,
name,
- BLO_LIBLINK_APPEND_RECURSIVE | FILE_ACTIVE_COLLECTION |
+ flag | BLO_LIBLINK_APPEND_RECURSIVE |
BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR);
case FILE_ASSET_IMPORT_APPEND_REUSE:
return WM_file_append_datablock(G_MAIN,
@@ -476,7 +570,7 @@ static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
asset_drag->path,
idtype,
name,
- BLO_LIBLINK_APPEND_RECURSIVE | FILE_ACTIVE_COLLECTION |
+ flag | BLO_LIBLINK_APPEND_RECURSIVE |
BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR |
BLO_LIBLINK_APPEND_LOCAL_ID_REUSE);
}
@@ -485,12 +579,24 @@ static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
return NULL;
}
+bool WM_drag_asset_will_import_linked(const wmDrag *drag)
+{
+ if (drag->type != WM_DRAG_ASSET) {
+ return false;
+ }
+
+ const wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0);
+ return asset_drag->import_type == FILE_ASSET_IMPORT_LINK;
+}
+
/**
* When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append
* that depending on what was chosen by the drag-box (currently append only in fact).
*
* Use #WM_drag_free_imported_drag_ID() as cancel callback of the drop-box, so that the asset
* import is rolled back if the drop operator fails.
+ *
+ * \param flag: #eFileSel_Params_Flag passed to linking code.
*/
ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
{
@@ -508,7 +614,7 @@ ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
}
/* Link/append the asset. */
- return wm_drag_asset_id_import(asset_drag);
+ return WM_drag_asset_id_import(asset_drag, 0);
}
/**
@@ -544,6 +650,15 @@ void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *
}
}
+wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const wmDrag *drag)
+{
+ if (drag->type != WM_DRAG_ASSET_CATALOG) {
+ return NULL;
+ }
+
+ return drag->poin;
+}
+
/**
* \note: Does not store \a asset in any way, so it's fine to pass a temporary.
*/
@@ -568,11 +683,12 @@ void WM_drag_add_asset_list_item(
drag_asset->asset_data.local_id = local_id;
}
else {
+ AssetMetaData *metadata = ED_asset_handle_get_metadata(asset);
char asset_blend_path[FILE_MAX_LIBEXTRA];
ED_asset_handle_get_full_library_path(C, asset_library_ref, asset, asset_blend_path);
drag_asset->is_external = true;
drag_asset->asset_data.external_info = WM_drag_create_asset_data(
- asset, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND);
+ asset, metadata, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND);
}
BLI_addtail(&drag->asset_items, drag_asset);
}
@@ -603,6 +719,17 @@ static void wm_drop_operator_draw(const char *name, int x, int y)
UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg);
}
+static void wm_drop_redalert_draw(const char *redalert_str, int x, int y)
+{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
+ float col_fg[4];
+
+ UI_GetThemeColor4fv(TH_REDALERT, col_fg);
+
+ UI_fontstyle_draw_simple_backdrop(fstyle, x, y, redalert_str, col_fg, col_bg);
+}
+
const char *WM_drag_get_item_name(wmDrag *drag)
{
switch (drag->type) {
@@ -629,132 +756,172 @@ const char *WM_drag_get_item_name(wmDrag *drag)
return "";
}
-static void drag_rect_minmax(rcti *rect, int x1, int y1, int x2, int y2)
+static void wm_drag_draw_icon(bContext *UNUSED(C),
+ wmWindow *UNUSED(win),
+ wmDrag *drag,
+ const int xy[2])
{
- if (rect->xmin > x1) {
- rect->xmin = x1;
- }
- if (rect->xmax < x2) {
- rect->xmax = x2;
+ int x, y;
+ if (drag->imb) {
+ x = xy[0] - drag->sx / 2;
+ y = xy[1] - drag->sy / 2;
+
+ float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTexScaled(&state,
+ x,
+ y,
+ drag->imb->x,
+ drag->imb->y,
+ GPU_RGBA8,
+ false,
+ drag->imb->rect,
+ drag->scale,
+ drag->scale,
+ 1.0f,
+ 1.0f,
+ col);
}
- if (rect->ymin > y1) {
- rect->ymin = y1;
- }
- if (rect->ymax < y2) {
- rect->ymax = y2;
+ else {
+ int padding = 4 * UI_DPI_FAC;
+ x = xy[0] - 2 * padding;
+ y = xy[1] - 2 * UI_DPI_FAC;
+
+ const uchar text_col[] = {255, 255, 255, 255};
+ UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false);
}
}
-/* called in wm_draw.c */
-/* if rect set, do not draw */
-void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
+static void wm_drag_draw_item_name(wmDrag *drag, const int x, const int y)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- wmWindowManager *wm = CTX_wm_manager(C);
- const int winsize_y = WM_window_pixels_y(win);
+ const uchar text_col[] = {255, 255, 255, 255};
+ UI_fontstyle_draw_simple(fstyle, x, y, WM_drag_get_item_name(drag), text_col);
+}
- int cursorx = win->eventstate->xy[0];
- int cursory = win->eventstate->xy[1];
- if (rect) {
- rect->xmin = rect->xmax = cursorx;
- rect->ymin = rect->ymax = cursory;
- }
+void WM_drag_draw_item_name_fn(bContext *UNUSED(C),
+ wmWindow *UNUSED(win),
+ wmDrag *drag,
+ const int xy[2])
+{
+ int x = xy[0] + 10 * UI_DPI_FAC;
+ int y = xy[1] + 1 * UI_DPI_FAC;
- /* Should we support multi-line drag draws? Maybe not, more types mixed won't work well. */
- GPU_blend(GPU_BLEND_ALPHA);
- LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) {
- const uchar text_col[] = {255, 255, 255, 255};
- int iconsize = UI_DPI_ICON_SIZE;
- int padding = 4 * UI_DPI_FAC;
+ wm_drag_draw_item_name(drag, x, y);
+}
- /* image or icon */
- int x, y;
- if (drag->imb) {
- x = cursorx - drag->sx / 2;
- y = cursory - drag->sy / 2;
+static void wm_drag_draw_tooltip(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2])
+{
+ if (!CTX_wm_region(C)) {
+ /* Some callbacks require the region. */
+ return;
+ }
+ int iconsize = UI_DPI_ICON_SIZE;
+ int padding = 4 * UI_DPI_FAC;
- if (rect) {
- drag_rect_minmax(rect, x, y, x + drag->sx, y + drag->sy);
- }
- else {
- float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTexScaled(&state,
- x,
- y,
- drag->imb->x,
- drag->imb->y,
- GPU_RGBA8,
- false,
- drag->imb->rect,
- drag->scale,
- drag->scale,
- 1.0f,
- 1.0f,
- col);
- }
- }
- else {
- x = cursorx - 2 * padding;
- y = cursory - 2 * UI_DPI_FAC;
+ char *tooltip = NULL;
+ if (drag->active_dropbox) {
+ tooltip = dropbox_tooltip(C, drag, xy, drag->active_dropbox);
+ }
- if (rect) {
- drag_rect_minmax(rect, x, y, x + iconsize, y + iconsize);
- }
- else {
- UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false);
- }
- }
+ if (!tooltip && !drag->disabled_info) {
+ return;
+ }
+
+ const int winsize_y = WM_window_pixels_y(win);
+ int x, y;
+ if (drag->imb) {
+ x = xy[0] - drag->sx / 2;
- /* item name */
- if (drag->imb) {
- x = cursorx - drag->sx / 2;
- y = cursory - drag->sy / 2 - iconsize;
+ if (xy[1] + drag->sy / 2 + padding + iconsize < winsize_y) {
+ y = xy[1] + drag->sy / 2 + padding;
}
else {
- x = cursorx + 10 * UI_DPI_FAC;
- y = cursory + 1 * UI_DPI_FAC;
+ y = xy[1] - drag->sy / 2 - padding - iconsize - padding - iconsize;
}
+ }
+ else {
+ x = xy[0] - 2 * padding;
- if (rect) {
- int w = UI_fontstyle_string_width(fstyle, WM_drag_get_item_name(drag));
- drag_rect_minmax(rect, x, y, x + w, y + iconsize);
+ if (xy[1] + iconsize + iconsize < winsize_y) {
+ y = (xy[1] + iconsize) + padding;
}
else {
- UI_fontstyle_draw_simple(fstyle, x, y, WM_drag_get_item_name(drag), text_col);
+ y = (xy[1] - iconsize) - padding;
}
+ }
- /* operator name with roundbox */
- if (drag->tooltip[0]) {
- if (drag->imb) {
- x = cursorx - drag->sx / 2;
+ if (tooltip) {
+ wm_drop_operator_draw(tooltip, x, y);
+ MEM_freeN(tooltip);
+ }
+ else if (drag->disabled_info) {
+ wm_drop_redalert_draw(drag->disabled_info, x, y);
+ }
+}
- if (cursory + drag->sy / 2 + padding + iconsize < winsize_y) {
- y = cursory + drag->sy / 2 + padding;
- }
- else {
- y = cursory - drag->sy / 2 - padding - iconsize - padding - iconsize;
- }
- }
- else {
- x = cursorx - 2 * padding;
+static void wm_drag_draw_default(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2])
+{
+ int xy_tmp[2] = {UNPACK2(xy)};
- if (cursory + iconsize + iconsize < winsize_y) {
- y = (cursory + iconsize) + padding;
- }
- else {
- y = (cursory - iconsize) - padding;
- }
- }
+ /* Image or icon. */
+ wm_drag_draw_icon(C, win, drag, xy_tmp);
- if (rect) {
- int w = UI_fontstyle_string_width(fstyle, WM_drag_get_item_name(drag));
- drag_rect_minmax(rect, x, y, x + w, y + iconsize);
- }
- else {
- wm_drop_operator_draw(drag->tooltip, x, y);
- }
+ /* Item name. */
+ if (drag->imb) {
+ int iconsize = UI_DPI_ICON_SIZE;
+ xy_tmp[0] = xy[0] - (drag->sx / 2);
+ xy_tmp[1] = xy[1] - (drag->sy / 2) - iconsize;
+ }
+ else {
+ xy_tmp[0] = xy[0] + 10 * UI_DPI_FAC;
+ xy_tmp[1] = xy[1] + 1 * UI_DPI_FAC;
+ }
+ wm_drag_draw_item_name(drag, UNPACK2(xy_tmp));
+
+ /* Operator name with roundbox. */
+ wm_drag_draw_tooltip(C, win, drag, xy);
+}
+
+void WM_drag_draw_default_fn(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2])
+{
+ wm_drag_draw_default(C, win, drag, xy);
+}
+
+/* Called in #wm_draw_window_onscreen. */
+void wm_drags_draw(bContext *C, wmWindow *win)
+{
+ int xy[2];
+ if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
+ wm_cursor_position_get(win, &xy[0], &xy[1]);
+ }
+ else {
+ xy[0] = win->eventstate->xy[0];
+ xy[1] = win->eventstate->xy[1];
+ }
+
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, UNPACK2(xy));
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, UNPACK2(xy));
+ if (region) {
+ BLI_assert(!CTX_wm_area(C) && !CTX_wm_region(C));
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+ }
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ /* Should we support multi-line drag draws? Maybe not, more types mixed won't work well. */
+ GPU_blend(GPU_BLEND_ALPHA);
+ LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) {
+ if (drag->active_dropbox && drag->active_dropbox->draw) {
+ drag->active_dropbox->draw(C, win, drag, xy);
+ continue;
}
+
+ wm_drag_draw_default(C, win, drag, xy);
}
GPU_blend(GPU_BLEND_NONE);
+ CTX_wm_area_set(C, NULL);
+ CTX_wm_region_set(C, NULL);
}
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index b5e81528e2b..8acce240046 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -856,9 +856,9 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
wm_gesture_draw(win);
}
- /* needs pixel coords in screen */
+ /* Needs pixel coords in screen. */
if (wm->drags.first) {
- wm_drags_draw(C, win, NULL);
+ wm_drags_draw(C, win);
}
GPU_debug_group_end();
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index 9ee114674ed..ef733837bf7 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -276,6 +276,28 @@ bool WM_event_is_mouse_drag_or_press(const wmEvent *event)
(ISMOUSE_BUTTON(event->type) && (event->val == KM_PRESS));
}
+/**
+ * Detect motion between selection (callers should only use this for selection picking),
+ * typically mouse press/click events.
+ *
+ * \param mval: Region relative coordinates, call with (-1, -1) resets the last cursor location.
+ * \returns True when there was motion since last called.
+ *
+ * NOTE(@campbellbarton): The logic used here isn't foolproof.
+ * It's possible that users move the cursor past #WM_EVENT_CURSOR_MOTION_THRESHOLD then back to
+ * a position within the threshold (between mouse clicks).
+ * In practice users never reported this since the threshold is very small (a few pixels).
+ * To prevent the unlikely case of values matching from another region,
+ * changing regions resets this value to (-1, -1).
+ */
+bool WM_cursor_test_motion_and_update(const int mval[2])
+{
+ static int mval_prev[2] = {-1, -1};
+ bool use_cycle = (len_manhattan_v2v2_int(mval, mval_prev) <= WM_EVENT_CURSOR_MOTION_THRESHOLD);
+ copy_v2_v2_int(mval_prev, mval);
+ return !use_cycle;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index df976d9a4cd..798f60fba3d 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -3055,12 +3055,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
ListBase *lb = (ListBase *)event->customdata;
LISTBASE_FOREACH_MUTABLE (wmDrag *, drag, lb) {
if (drop->poll(C, drag, event)) {
- /* Optionally copy drag information to operator properties. Don't call it if the
- * operator fails anyway, it might do more than just set properties (e.g.
- * typically import an asset). */
- if (drop->copy && WM_operator_poll_context(C, drop->ot, drop->opcontext)) {
- drop->copy(drag, drop);
- }
+ wm_drop_prepare(C, drag, drop);
/* Pass single matched wmDrag onto the operator. */
BLI_remlink(lb, drag);
@@ -3094,6 +3089,8 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
break;
}
}
+ /* Always exit all drags on a drop event, even if poll didn't succeed. */
+ wm_drags_exit(wm, win);
}
}
}
@@ -3390,6 +3387,7 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv
screen->do_draw_drag = true;
}
else if (event->type == EVT_ESCKEY) {
+ wm_drags_exit(wm, win);
WM_drag_free_list(&wm->drags);
screen->do_draw_drag = true;
@@ -3630,7 +3628,8 @@ void wm_event_do_handlers(bContext *C)
/* Clear tool-tip on mouse move. */
if (screen->tool_tip && screen->tool_tip->exit_on_event) {
if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- if (len_manhattan_v2v2_int(screen->tool_tip->event_xy, event->xy) > U.move_threshold) {
+ if (len_manhattan_v2v2_int(screen->tool_tip->event_xy, event->xy) >
+ WM_EVENT_CURSOR_MOTION_THRESHOLD) {
WM_tooltip_clear(C, win);
}
}
@@ -4010,10 +4009,12 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap
*
* Follow #wmEventHandler_KeymapDynamicFn signature.
*/
-void WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
- wmWindow *win,
- wmEventHandler_Keymap *handler,
- wmEventHandler_KeymapResult *km_result)
+static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
+ wmWindow *win,
+ wmEventHandler_Keymap *handler,
+ wmEventHandler_KeymapResult *km_result,
+ /* Extra arguments. */
+ const bool with_gizmos)
{
memset(km_result, 0x0, sizeof(*km_result));
@@ -4046,7 +4047,8 @@ void WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
if (tref_rt->flag & TOOLREF_FLAG_FALLBACK_KEYMAP) {
add_keymap = true;
}
- if (tref_rt->gizmo_group[0] != '\0') {
+
+ if (with_gizmos && (tref_rt->gizmo_group[0] != '\0')) {
wmGizmoMap *gzmap = NULL;
wmGizmoGroup *gzgroup = NULL;
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
@@ -4070,6 +4072,7 @@ void WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
}
}
}
+
if (add_keymap) {
keymap_id_list[keymap_id_list_len++] = tref_rt->keymap_fallback;
}
@@ -4097,32 +4100,20 @@ void WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
}
}
+void WM_event_get_keymap_from_toolsystem_with_gizmos(wmWindowManager *wm,
+ wmWindow *win,
+ wmEventHandler_Keymap *handler,
+ wmEventHandler_KeymapResult *km_result)
+{
+ wm_event_get_keymap_from_toolsystem_ex(wm, win, handler, km_result, true);
+}
+
void WM_event_get_keymap_from_toolsystem(wmWindowManager *wm,
- wmWindow *UNUSED(win),
+ wmWindow *win,
wmEventHandler_Keymap *handler,
wmEventHandler_KeymapResult *km_result)
{
- memset(km_result, 0x0, sizeof(*km_result));
-
- ScrArea *area = handler->dynamic.user_data;
- handler->keymap_tool = NULL;
- bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL;
- if (tref_rt && tref_rt->keymap[0]) {
- const char *keymap_id = tref_rt->keymap;
- {
- wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
- &wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW);
- /* We shouldn't use keymaps from unrelated spaces. */
- if (km != NULL) {
- handler->keymap_tool = area->runtime.tool;
- km_result->keymaps[km_result->keymaps_len++] = km;
- }
- else {
- printf(
- "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, area->runtime.tool->idname);
- }
- }
- }
+ wm_event_get_keymap_from_toolsystem_ex(wm, win, handler, km_result, false);
}
struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index e203281297b..67222cc07f9 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -1644,6 +1644,7 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C,
area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
if (area) {
v3d = area->spacedata.first;
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
}
}
@@ -1787,6 +1788,7 @@ static bool wm_file_write(bContext *C,
/* Call pre-save callbacks before writing preview,
* that way you can generate custom file thumbnail. */
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
+ ED_assets_pre_save(bmain);
/* Enforce full override check/generation on file save. */
BKE_lib_override_library_main_operations_create(bmain, true);
@@ -2104,6 +2106,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
}
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
+ ED_assets_pre_save(bmain);
/* check current window and close it if temp */
if (win && WM_window_is_temp_screen(win)) {
@@ -2139,7 +2142,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
}
printf("ok\n");
-
+ BKE_report(op->reports, RPT_INFO, "Startup file saved");
G.save_over = 0;
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index c88e577df6a..7d74ac9605b 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -583,8 +583,13 @@ static int foreach_libblock_append_callback(LibraryIDLinkCallbackData *cb_data)
/* While we do not want to add non-linkable ID (shape keys...) to the list of linked items,
* unfortunately they can use fully linkable valid IDs too, like actions. Those need to be
* processed, so we need to recursively deal with them here. */
- BKE_library_foreach_ID_link(
- cb_data->bmain, id, foreach_libblock_append_callback, data, IDWALK_NOP);
+ /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it
+ * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of
+ * shapekey referencing the shapekey itself). */
+ if (id != cb_data->id_self) {
+ BKE_library_foreach_ID_link(
+ cb_data->bmain, id, foreach_libblock_append_callback, data, IDWALK_NOP);
+ }
return IDWALK_RET_NOP;
}
@@ -807,7 +812,7 @@ static void wm_append_do(WMLinkAppendData *lapp_data,
BLI_assert(!ID_IS_LINKED(id));
- BKE_libblock_relink_to_newid_new(bmain, id);
+ BKE_libblock_relink_to_newid(bmain, id);
}
/* Remove linked IDs when a local existing data has been reused instead. */
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index d0693d37ef4..c382af03c4a 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -548,7 +548,6 @@ void WM_exit_ex(bContext *C, const bool do_python)
ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */
ED_assetlist_storage_exit();
- ED_view3d_cursor_snap_exit();
if (wm) {
/* Before BKE_blender_free! - since the ListBases get freed there. */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 89f0206d72e..1130ad9a558 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -3759,87 +3759,6 @@ static void WM_OT_stereo3d_set(wmOperatorType *ot)
/** \} */
-#ifdef WITH_XR_OPENXR
-
-static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
-{
- const bool session_exists = WM_xr_session_exists(xr_data);
-
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) {
- if (slink->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)slink;
-
- if (v3d->flag & V3D_XR_SESSION_MIRROR) {
- ED_view3d_xr_mirror_update(area, v3d, session_exists);
- }
-
- if (session_exists) {
- wmWindowManager *wm = bmain->wm.first;
- const Scene *scene = WM_windows_scene_get_from_screen(wm, screen);
-
- ED_view3d_xr_shading_update(wm, v3d, scene);
- }
- /* Ensure no 3D View is tagged as session root. */
- else {
- v3d->runtime.flag &= ~V3D_RUNTIME_XR_SESSION_ROOT;
- }
- }
- }
- }
- }
-
- WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
-}
-
-static void wm_xr_session_update_screen_on_exit_cb(const wmXrData *xr_data)
-{
- /* Just use G_MAIN here, storing main isn't reliable enough on file read or exit. */
- wm_xr_session_update_screen(G_MAIN, xr_data);
-}
-
-static int wm_xr_session_toggle_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- View3D *v3d = CTX_wm_view3d(C);
-
- /* Lazy-create xr context - tries to dynlink to the runtime, reading active_runtime.json. */
- if (wm_xr_init(wm) == false) {
- return OPERATOR_CANCELLED;
- }
-
- v3d->runtime.flag |= V3D_RUNTIME_XR_SESSION_ROOT;
- wm_xr_session_toggle(wm, win, wm_xr_session_update_screen_on_exit_cb);
- wm_xr_session_update_screen(bmain, &wm->xr);
-
- WM_event_add_notifier(C, NC_WM | ND_XR_DATA_CHANGED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_xr_session_toggle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle VR Session";
- ot->idname = "WM_OT_xr_session_toggle";
- ot->description =
- "Open a view for use with virtual reality headsets, or close it if already "
- "opened";
-
- /* callbacks */
- ot->exec = wm_xr_session_toggle_exec;
- ot->poll = ED_operator_view3d_active;
-
- /* XXX INTERNAL just to hide it from the search menu by default, an Add-on will expose it in the
- * UI instead. Not meant as a permanent solution. */
- ot->flag = OPTYPE_INTERNAL;
-}
-
-#endif /* WITH_XR_OPENXR */
-
/* -------------------------------------------------------------------- */
/** \name Operator Registration & Keymaps
* \{ */
@@ -3881,9 +3800,6 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_call_panel);
WM_operatortype_append(WM_OT_radial_control);
WM_operatortype_append(WM_OT_stereo3d_set);
-#ifdef WITH_XR_OPENXR
- WM_operatortype_append(WM_OT_xr_session_toggle);
-#endif
#if defined(WIN32)
WM_operatortype_append(WM_OT_console_toggle);
#endif
@@ -3891,6 +3807,10 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_previews_clear);
WM_operatortype_append(WM_OT_doc_view_manual_ui_context);
+#ifdef WITH_XR_OPENXR
+ wm_xr_operatortypes_register();
+#endif
+
/* gizmos */
WM_operatortype_append(GIZMOGROUP_OT_gizmo_select);
WM_operatortype_append(GIZMOGROUP_OT_gizmo_tweak);
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index d1eb10787e2..40e4d905fcd 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -172,8 +172,10 @@ void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTab
/* wm_dropbox.c */
void wm_dropbox_free(void);
+void wm_drags_exit(wmWindowManager *wm, wmWindow *win);
+void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop);
void wm_drags_check_ops(bContext *C, const wmEvent *event);
-void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect);
+void wm_drags_draw(bContext *C, wmWindow *win);
#ifdef __cplusplus
}
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
index 628d50f05bd..72d88bb3043 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
@@ -49,6 +49,16 @@ void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4])
copy_v3_v3(r_mat[3], pose->position);
}
+void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4])
+{
+ wm_xr_pose_to_mat(pose, r_mat);
+
+ BLI_assert(scale > 0.0f);
+ mul_v3_fl(r_mat[0], scale);
+ mul_v3_fl(r_mat[1], scale);
+ mul_v3_fl(r_mat[2], scale);
+}
+
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
{
float iquat[4];
@@ -57,15 +67,32 @@ void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
}
+void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
+{
+ float iquat[4];
+ invert_qt_qt_normalized(iquat, pose->orientation_quat);
+ quat_to_mat4(r_imat, iquat);
+
+ BLI_assert(scale > 0.0f);
+ scale = 1.0f / scale;
+ mul_v3_fl(r_imat[0], scale);
+ mul_v3_fl(r_imat[1], scale);
+ mul_v3_fl(r_imat[2], scale);
+
+ translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
+}
+
static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
const GHOST_XrDrawViewInfo *draw_view,
const XrSessionSettings *session_settings,
- float r_view_mat[4][4],
- float r_proj_mat[4][4])
+ const wmXrSessionState *session_state,
+ float r_viewmat[4][4],
+ float r_projmat[4][4])
{
GHOST_XrPose eye_pose;
- float eye_inv[4][4], base_inv[4][4];
+ float eye_inv[4][4], base_inv[4][4], nav_inv[4][4], m[4][4];
+ /* Calculate inverse eye matrix. */
copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat);
copy_v3_v3(eye_pose.position, draw_view->eye_pose.position);
if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
@@ -76,12 +103,14 @@ static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
}
wm_xr_pose_to_imat(&eye_pose, eye_inv);
- /* Calculate the base pose matrix (in world space!). */
- wm_xr_pose_to_imat(&draw_data->base_pose, base_inv);
- mul_m4_m4m4(r_view_mat, eye_inv, base_inv);
+ /* Apply base pose and navigation. */
+ wm_xr_pose_scale_to_imat(&draw_data->base_pose, draw_data->base_scale, base_inv);
+ wm_xr_pose_scale_to_imat(&session_state->nav_pose_prev, session_state->nav_scale_prev, nav_inv);
+ mul_m4_m4m4(m, eye_inv, base_inv);
+ mul_m4_m4m4(r_viewmat, m, nav_inv);
- perspective_m4_fov(r_proj_mat,
+ perspective_m4_fov(r_projmat,
draw_view->fov.angle_left,
draw_view->fov.angle_right,
draw_view->fov.angle_up,
@@ -131,7 +160,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
BLI_assert(WM_xr_session_is_ready(xr_data));
wm_xr_session_draw_data_update(session_state, settings, draw_view, draw_data);
- wm_xr_draw_matrices_create(draw_data, draw_view, settings, viewmat, winmat);
+ wm_xr_draw_matrices_create(draw_data, draw_view, settings, session_state, viewmat, winmat);
wm_xr_session_state_update(settings, draw_data, draw_view, session_state);
if (!wm_xr_session_surface_offscreen_ensure(surface_data, draw_view)) {
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
index 2cd0ba5c056..7de1f254224 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -33,6 +33,8 @@ typedef struct wmXrSessionState {
GHOST_XrPose viewer_pose;
/** The last known view matrix, calculated from above's viewer pose. */
float viewer_viewmat[4][4];
+ /** The last known viewer matrix, without navigation applied. */
+ float viewer_mat_base[4][4];
float focal_len;
/** Copy of XrSessionSettings.base_pose_ data to detect changes that need
@@ -43,6 +45,8 @@ typedef struct wmXrSessionState {
int prev_settings_flag;
/** Copy of wmXrDrawData.base_pose. */
GHOST_XrPose prev_base_pose;
+ /** Copy of wmXrDrawData.base_scale. */
+ float prev_base_scale;
/** Copy of GHOST_XrDrawViewInfo.local_pose. */
GHOST_XrPose prev_local_pose;
/** Copy of wmXrDrawData.eye_position_ofs. */
@@ -51,6 +55,15 @@ typedef struct wmXrSessionState {
bool force_reset_to_base_pose;
bool is_view_data_set;
+ /** Current navigation transforms. */
+ GHOST_XrPose nav_pose;
+ float nav_scale;
+ /** Navigation transforms from the last actions sync, used to calculate the viewer/controller
+ * poses. */
+ GHOST_XrPose nav_pose_prev;
+ float nav_scale_prev;
+ bool is_navigation_dirty;
+
/** Last known controller data. */
ListBase controllers; /* #wmXrController */
@@ -106,6 +119,8 @@ typedef struct wmXrDrawData {
* space). With positional tracking enabled, it should be the same as the base pose, when
* disabled it also contains a location delta from the moment the option was toggled. */
GHOST_XrPose base_pose;
+ /** Base scale (uniform, world space). */
+ float base_scale;
/** Offset to _substract_ from the OpenXR eye and viewer pose to get the wanted effective pose
* (e.g. a pose exactly at the landmark position). */
float eye_position_ofs[3]; /* Local/view space. */
@@ -123,9 +138,11 @@ typedef struct wmXrController {
/** Pose (in world space) that represents the user's hand when holding the controller. */
GHOST_XrPose grip_pose;
float grip_mat[4][4];
+ float grip_mat_base[4][4];
/** Pose (in world space) that represents the controller's aiming source. */
GHOST_XrPose aim_pose;
float aim_mat[4][4];
+ float aim_mat_base[4][4];
/** Controller model. */
struct GPUBatch *model;
@@ -192,7 +209,7 @@ void wm_xr_runtime_data_free(wmXrRuntimeData **runtime);
void wm_xr_session_data_free(wmXrSessionState *state);
wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm,
const wmXrRuntimeData *runtime_data);
-void wm_xr_session_draw_data_update(const wmXrSessionState *state,
+void wm_xr_session_draw_data_update(wmXrSessionState *state,
const XrSessionSettings *settings,
const GHOST_XrDrawViewInfo *draw_view,
wmXrDrawData *draw_data);
@@ -214,6 +231,8 @@ void wm_xr_session_controller_data_clear(wmXrSessionState *state);
/* wm_xr_draw.c */
void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]);
+void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4]);
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4]);
+void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4]);
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata);
void wm_xr_draw_controllers(const struct bContext *C, struct ARegion *region, void *customdata);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
new file mode 100644
index 00000000000..36af0147cb8
--- /dev/null
+++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
@@ -0,0 +1,1537 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup wm
+ *
+ * \name Window-Manager XR Operators
+ *
+ * Collection of XR-related operators.
+ */
+
+#include "BLI_kdopbvh.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+#include "BKE_screen.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "GHOST_Types.h"
+
+#include "GPU_immediate.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm_xr_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Conditions
+ * \{ */
+
+/* op->poll */
+static bool wm_xr_operator_sessionactive(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ return WM_xr_session_is_ready(&wm->xr);
+}
+
+static bool wm_xr_operator_test_event(const wmOperator *op, const wmEvent *event)
+{
+ if (event->type != EVT_XR_ACTION) {
+ return false;
+ }
+
+ BLI_assert(event->custom == EVT_DATA_XR);
+ BLI_assert(event->customdata);
+
+ wmXrActionData *actiondata = event->customdata;
+ return (actiondata->ot == op->type &&
+ IDP_EqualsProperties(actiondata->op_properties, op->properties));
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Session Toggle
+ *
+ * Toggles an XR session, creating an XR context if necessary.
+ * \{ */
+
+static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
+{
+ const bool session_exists = WM_xr_session_exists(xr_data);
+
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) {
+ if (slink->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)slink;
+
+ if (v3d->flag & V3D_XR_SESSION_MIRROR) {
+ ED_view3d_xr_mirror_update(area, v3d, session_exists);
+ }
+
+ if (session_exists) {
+ wmWindowManager *wm = bmain->wm.first;
+ const Scene *scene = WM_windows_scene_get_from_screen(wm, screen);
+
+ ED_view3d_xr_shading_update(wm, v3d, scene);
+ }
+ /* Ensure no 3D View is tagged as session root. */
+ else {
+ v3d->runtime.flag &= ~V3D_RUNTIME_XR_SESSION_ROOT;
+ }
+ }
+ }
+ }
+ }
+
+ WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
+}
+
+static void wm_xr_session_update_screen_on_exit_cb(const wmXrData *xr_data)
+{
+ /* Just use G_MAIN here, storing main isn't reliable enough on file read or exit. */
+ wm_xr_session_update_screen(G_MAIN, xr_data);
+}
+
+static int wm_xr_session_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ /* Lazily-create XR context - tries to dynamic-link to the runtime,
+ * reading `active_runtime.json`. */
+ if (wm_xr_init(wm) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ v3d->runtime.flag |= V3D_RUNTIME_XR_SESSION_ROOT;
+ wm_xr_session_toggle(wm, win, wm_xr_session_update_screen_on_exit_cb);
+ wm_xr_session_update_screen(bmain, &wm->xr);
+
+ WM_event_add_notifier(C, NC_WM | ND_XR_DATA_CHANGED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void WM_OT_xr_session_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle VR Session";
+ ot->idname = "WM_OT_xr_session_toggle";
+ ot->description =
+ "Open a view for use with virtual reality headsets, or close it if already "
+ "opened";
+
+ /* callbacks */
+ ot->exec = wm_xr_session_toggle_exec;
+ ot->poll = ED_operator_view3d_active;
+
+ /* XXX INTERNAL just to hide it from the search menu by default, an Add-on will expose it in the
+ * UI instead. Not meant as a permanent solution. */
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Grab Utilities
+ * \{ */
+
+typedef struct XrGrabData {
+ float mat_prev[4][4];
+ float mat_other_prev[4][4];
+ bool bimanual_prev;
+ bool loc_lock, locz_lock, rot_lock, rotz_lock, scale_lock;
+} XrGrabData;
+
+static void wm_xr_grab_init(wmOperator *op)
+{
+ BLI_assert(op->customdata == NULL);
+
+ op->customdata = MEM_callocN(sizeof(XrGrabData), __func__);
+}
+
+static void wm_xr_grab_uninit(wmOperator *op)
+{
+ MEM_SAFE_FREE(op->customdata);
+}
+
+static void wm_xr_grab_update(wmOperator *op, const wmXrActionData *actiondata)
+{
+ XrGrabData *data = op->customdata;
+
+ quat_to_mat4(data->mat_prev, actiondata->controller_rot);
+ copy_v3_v3(data->mat_prev[3], actiondata->controller_loc);
+
+ if (actiondata->bimanual) {
+ quat_to_mat4(data->mat_other_prev, actiondata->controller_rot_other);
+ copy_v3_v3(data->mat_other_prev[3], actiondata->controller_loc_other);
+ data->bimanual_prev = true;
+ }
+ else {
+ data->bimanual_prev = false;
+ }
+}
+
+static void orient_mat_z_normalized(float R[4][4], const float z_axis[3])
+{
+ const float scale = len_v3(R[0]);
+ float x_axis[3], y_axis[3];
+
+ cross_v3_v3v3(y_axis, z_axis, R[0]);
+ normalize_v3(y_axis);
+ mul_v3_v3fl(R[1], y_axis, scale);
+
+ cross_v3_v3v3(x_axis, R[1], z_axis);
+ normalize_v3(x_axis);
+ mul_v3_v3fl(R[0], x_axis, scale);
+
+ mul_v3_v3fl(R[2], z_axis, scale);
+}
+
+static void wm_xr_navlocks_apply(const float nav_mat[4][4],
+ const float nav_inv[4][4],
+ bool loc_lock,
+ bool locz_lock,
+ bool rotz_lock,
+ float r_prev[4][4],
+ float r_curr[4][4])
+{
+ /* Locked in base pose coordinates. */
+ float prev_base[4][4], curr_base[4][4];
+
+ mul_m4_m4m4(prev_base, nav_inv, r_prev);
+ mul_m4_m4m4(curr_base, nav_inv, r_curr);
+
+ if (rotz_lock) {
+ const float z_axis[3] = {0.0f, 0.0f, 1.0f};
+ orient_mat_z_normalized(prev_base, z_axis);
+ orient_mat_z_normalized(curr_base, z_axis);
+ }
+
+ if (loc_lock) {
+ copy_v3_v3(curr_base[3], prev_base[3]);
+ }
+ else if (locz_lock) {
+ curr_base[3][2] = prev_base[3][2];
+ }
+
+ mul_m4_m4m4(r_prev, nav_mat, prev_base);
+ mul_m4_m4m4(r_curr, nav_mat, curr_base);
+}
+
+/**
+ * Compute transformation delta for a one-handed grab interaction.
+ *
+ * \param actiondata: Contains current controller pose in world space.
+ * \param data: Contains previous controller pose in world space.
+ *
+ * The delta is computed as the difference between the current and previous
+ * controller poses i.e. delta = curr * prev^-1.
+ */
+static void wm_xr_grab_compute(const wmXrActionData *actiondata,
+ const XrGrabData *data,
+ const float nav_mat[4][4],
+ const float nav_inv[4][4],
+ bool reverse,
+ float r_delta[4][4])
+{
+ const bool nav_lock = (nav_mat && nav_inv);
+ float prev[4][4], curr[4][4];
+
+ if (!data->rot_lock) {
+ copy_m4_m4(prev, data->mat_prev);
+ zero_v3(prev[3]);
+ quat_to_mat4(curr, actiondata->controller_rot);
+ }
+ else {
+ unit_m4(prev);
+ unit_m4(curr);
+ }
+
+ if (!data->loc_lock || nav_lock) {
+ copy_v3_v3(prev[3], data->mat_prev[3]);
+ copy_v3_v3(curr[3], actiondata->controller_loc);
+ }
+
+ if (nav_lock) {
+ wm_xr_navlocks_apply(
+ nav_mat, nav_inv, data->loc_lock, data->locz_lock, data->rotz_lock, prev, curr);
+ }
+
+ if (reverse) {
+ invert_m4(curr);
+ mul_m4_m4m4(r_delta, prev, curr);
+ }
+ else {
+ invert_m4(prev);
+ mul_m4_m4m4(r_delta, curr, prev);
+ }
+}
+
+/**
+ * Compute transformation delta for a two-handed (bimanual) grab interaction.
+ *
+ * \param actiondata: Contains current controller poses in world space.
+ * \param data: Contains previous controller poses in world space.
+ *
+ * The delta is computed as the difference (delta = curr * prev^-1) between the current
+ * and previous transformations, where the transformations themselves are determined as follows:
+ * - Translation: Averaged controller positions.
+ * - Rotation: Rotation of axis line between controllers.
+ * - Scale: Distance between controllers.
+ */
+static void wm_xr_grab_compute_bimanual(const wmXrActionData *actiondata,
+ const XrGrabData *data,
+ const float nav_mat[4][4],
+ const float nav_inv[4][4],
+ bool reverse,
+ float r_delta[4][4])
+{
+ const bool nav_lock = (nav_mat && nav_inv);
+ float prev[4][4], curr[4][4];
+ unit_m4(prev);
+ unit_m4(curr);
+
+ if (!data->rot_lock) {
+ /* Rotation. */
+ float x_axis_prev[3], x_axis_curr[3], y_axis_prev[3], y_axis_curr[3], z_axis_prev[3],
+ z_axis_curr[3];
+ float m0[3][3], m1[3][3];
+ quat_to_mat3(m0, actiondata->controller_rot);
+ quat_to_mat3(m1, actiondata->controller_rot_other);
+
+ /* x-axis is the base line between the two controllers. */
+ sub_v3_v3v3(x_axis_prev, data->mat_prev[3], data->mat_other_prev[3]);
+ sub_v3_v3v3(x_axis_curr, actiondata->controller_loc, actiondata->controller_loc_other);
+ /* y-axis is the average of the controllers' y-axes. */
+ add_v3_v3v3(y_axis_prev, data->mat_prev[1], data->mat_other_prev[1]);
+ mul_v3_fl(y_axis_prev, 0.5f);
+ add_v3_v3v3(y_axis_curr, m0[1], m1[1]);
+ mul_v3_fl(y_axis_curr, 0.5f);
+ /* z-axis is the cross product of the two. */
+ cross_v3_v3v3(z_axis_prev, x_axis_prev, y_axis_prev);
+ cross_v3_v3v3(z_axis_curr, x_axis_curr, y_axis_curr);
+ /* Fix the y-axis to be orthogonal. */
+ cross_v3_v3v3(y_axis_prev, z_axis_prev, x_axis_prev);
+ cross_v3_v3v3(y_axis_curr, z_axis_curr, x_axis_curr);
+ /* Normalize. */
+ normalize_v3_v3(prev[0], x_axis_prev);
+ normalize_v3_v3(prev[1], y_axis_prev);
+ normalize_v3_v3(prev[2], z_axis_prev);
+ normalize_v3_v3(curr[0], x_axis_curr);
+ normalize_v3_v3(curr[1], y_axis_curr);
+ normalize_v3_v3(curr[2], z_axis_curr);
+ }
+
+ if (!data->loc_lock || nav_lock) {
+ /* Translation: translation of the averaged controller locations. */
+ add_v3_v3v3(prev[3], data->mat_prev[3], data->mat_other_prev[3]);
+ mul_v3_fl(prev[3], 0.5f);
+ add_v3_v3v3(curr[3], actiondata->controller_loc, actiondata->controller_loc_other);
+ mul_v3_fl(curr[3], 0.5f);
+ }
+
+ if (!data->scale_lock) {
+ /* Scaling: distance between controllers. */
+ float scale, v[3];
+
+ sub_v3_v3v3(v, data->mat_prev[3], data->mat_other_prev[3]);
+ scale = len_v3(v);
+ mul_v3_fl(prev[0], scale);
+ mul_v3_fl(prev[1], scale);
+ mul_v3_fl(prev[2], scale);
+
+ sub_v3_v3v3(v, actiondata->controller_loc, actiondata->controller_loc_other);
+ scale = len_v3(v);
+ mul_v3_fl(curr[0], scale);
+ mul_v3_fl(curr[1], scale);
+ mul_v3_fl(curr[2], scale);
+ }
+
+ if (nav_lock) {
+ wm_xr_navlocks_apply(
+ nav_mat, nav_inv, data->loc_lock, data->locz_lock, data->rotz_lock, prev, curr);
+ }
+
+ if (reverse) {
+ invert_m4(curr);
+ mul_m4_m4m4(r_delta, prev, curr);
+ }
+ else {
+ invert_m4(prev);
+ mul_m4_m4m4(r_delta, curr, prev);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Navigation Grab
+ *
+ * Navigates the scene by grabbing with XR controllers.
+ * \{ */
+
+static int wm_xr_navigation_grab_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+
+ wm_xr_grab_init(op);
+ wm_xr_grab_update(op, actiondata);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_xr_navigation_grab_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ return OPERATOR_CANCELLED;
+}
+
+static bool wm_xr_navigation_grab_can_do_bimanual(const wmXrActionData *actiondata,
+ const XrGrabData *data)
+{
+ /* Returns true if: 1) Bimanual interaction is currently occurring (i.e. inputs on both
+ controllers are pressed) and 2) bimanual interaction occurred on the last update. This second
+ part is needed to avoid "jumpy" navigation changes when transitioning from one-handed to
+ two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how navigation deltas
+ are calculated). */
+ return (actiondata->bimanual && data->bimanual_prev);
+}
+
+static bool wm_xr_navigation_grab_is_bimanual_ending(const wmXrActionData *actiondata,
+ const XrGrabData *data)
+{
+ return (!actiondata->bimanual && data->bimanual_prev);
+}
+
+static bool wm_xr_navigation_grab_is_locked(const XrGrabData *data, const bool bimanual)
+{
+ if (bimanual) {
+ return data->loc_lock && data->rot_lock && data->scale_lock;
+ }
+ /* Ignore scale lock, as one-handed interaction cannot change navigation scale. */
+ return data->loc_lock && data->rot_lock;
+}
+
+static void wm_xr_navigation_grab_apply(wmXrData *xr,
+ const wmXrActionData *actiondata,
+ const XrGrabData *data,
+ bool bimanual)
+{
+ GHOST_XrPose nav_pose;
+ float nav_scale;
+ float nav_mat[4][4], nav_inv[4][4], delta[4][4], out[4][4];
+
+ const bool need_navinv = (data->loc_lock || data->locz_lock || data->rotz_lock);
+
+ WM_xr_session_state_nav_location_get(xr, nav_pose.position);
+ WM_xr_session_state_nav_rotation_get(xr, nav_pose.orientation_quat);
+ WM_xr_session_state_nav_scale_get(xr, &nav_scale);
+
+ wm_xr_pose_scale_to_mat(&nav_pose, nav_scale, nav_mat);
+ if (need_navinv) {
+ wm_xr_pose_scale_to_imat(&nav_pose, nav_scale, nav_inv);
+ }
+
+ if (bimanual) {
+ wm_xr_grab_compute_bimanual(
+ actiondata, data, need_navinv ? nav_mat : NULL, need_navinv ? nav_inv : NULL, true, delta);
+ }
+ else {
+ wm_xr_grab_compute(
+ actiondata, data, need_navinv ? nav_mat : NULL, need_navinv ? nav_inv : NULL, true, delta);
+ }
+
+ mul_m4_m4m4(out, delta, nav_mat);
+
+ /* Limit scale to reasonable values. */
+ nav_scale = len_v3(out[0]);
+
+ if (!(nav_scale < xr->session_settings.clip_start ||
+ nav_scale > xr->session_settings.clip_end)) {
+ WM_xr_session_state_nav_location_set(xr, out[3]);
+ if (!data->rot_lock) {
+ mat4_to_quat(nav_pose.orientation_quat, out);
+ normalize_qt(nav_pose.orientation_quat);
+ WM_xr_session_state_nav_rotation_set(xr, nav_pose.orientation_quat);
+ }
+ if (!data->scale_lock && bimanual) {
+ WM_xr_session_state_nav_scale_set(xr, nav_scale);
+ }
+ }
+}
+
+static void wm_xr_navigation_grab_bimanual_state_update(const wmXrActionData *actiondata,
+ XrGrabData *data)
+{
+ if (actiondata->bimanual) {
+ if (!data->bimanual_prev) {
+ quat_to_mat4(data->mat_prev, actiondata->controller_rot);
+ copy_v3_v3(data->mat_prev[3], actiondata->controller_loc);
+ quat_to_mat4(data->mat_other_prev, actiondata->controller_rot_other);
+ copy_v3_v3(data->mat_other_prev[3], actiondata->controller_loc_other);
+ }
+ data->bimanual_prev = true;
+ }
+ else {
+ if (data->bimanual_prev) {
+ quat_to_mat4(data->mat_prev, actiondata->controller_rot);
+ copy_v3_v3(data->mat_prev[3], actiondata->controller_loc);
+ }
+ data->bimanual_prev = false;
+ }
+}
+
+static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+ XrGrabData *data = op->customdata;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrData *xr = &wm->xr;
+
+ const bool do_bimanual = wm_xr_navigation_grab_can_do_bimanual(actiondata, data);
+
+ data->loc_lock = RNA_boolean_get(op->ptr, "lock_location");
+ data->locz_lock = RNA_boolean_get(op->ptr, "lock_location_z");
+ data->rot_lock = RNA_boolean_get(op->ptr, "lock_rotation");
+ data->rotz_lock = RNA_boolean_get(op->ptr, "lock_rotation_z");
+ data->scale_lock = RNA_boolean_get(op->ptr, "lock_scale");
+
+ /* Check if navigation is locked. */
+ if (!wm_xr_navigation_grab_is_locked(data, do_bimanual)) {
+ /* Prevent unwanted snapping (i.e. "jumpy" navigation changes when transitioning from
+ two-handed to one-handed interaction) at the end of a bimanual interaction. */
+ if (!wm_xr_navigation_grab_is_bimanual_ending(actiondata, data)) {
+ wm_xr_navigation_grab_apply(xr, actiondata, data, do_bimanual);
+ }
+ }
+
+ wm_xr_navigation_grab_bimanual_state_update(actiondata, data);
+
+ /* Note: KM_PRESS and KM_RELEASE are the only two values supported by XR events during event
+ dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal
+ handling starts when an input is "pressed" (action state exceeds the action threshold) and
+ ends when the input is "released" (state falls below the threshold). */
+ switch (event->val) {
+ case KM_PRESS:
+ return OPERATOR_RUNNING_MODAL;
+ case KM_RELEASE:
+ wm_xr_grab_uninit(op);
+ return OPERATOR_FINISHED;
+ default:
+ BLI_assert_unreachable();
+ wm_xr_grab_uninit(op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void WM_OT_xr_navigation_grab(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "XR Navigation Grab";
+ ot->idname = "WM_OT_xr_navigation_grab";
+ ot->description = "Navigate the VR scene by grabbing with controllers";
+
+ /* callbacks */
+ ot->invoke = wm_xr_navigation_grab_invoke;
+ ot->exec = wm_xr_navigation_grab_exec;
+ ot->modal = wm_xr_navigation_grab_modal;
+ ot->poll = wm_xr_operator_sessionactive;
+
+ /* properties */
+ RNA_def_boolean(
+ ot->srna, "lock_location", false, "Lock Location", "Prevent changes to viewer location");
+ RNA_def_boolean(
+ ot->srna, "lock_location_z", false, "Lock Elevation", "Prevent changes to viewer elevation");
+ RNA_def_boolean(
+ ot->srna, "lock_rotation", false, "Lock Rotation", "Prevent changes to viewer rotation");
+ RNA_def_boolean(ot->srna,
+ "lock_rotation_z",
+ false,
+ "Lock Up Orientation",
+ "Prevent changes to viewer up orientation");
+ RNA_def_boolean(ot->srna, "lock_scale", false, "Lock Scale", "Prevent changes to viewer scale");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Raycast Utilities
+ * \{ */
+
+static const float g_xr_default_raycast_axis[3] = {0.0f, 0.0f, -1.0f};
+static const float g_xr_default_raycast_color[4] = {0.35f, 0.35f, 1.0f, 1.0f};
+
+typedef struct XrRaycastData {
+ bool from_viewer;
+ float origin[3];
+ float direction[3];
+ float end[3];
+ float color[4];
+ void *draw_handle;
+} XrRaycastData;
+
+static void wm_xr_raycast_draw(const bContext *UNUSED(C),
+ ARegion *UNUSED(region),
+ void *customdata)
+{
+ const XrRaycastData *data = customdata;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ if (data->from_viewer) {
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(data->color);
+
+ GPU_depth_test(GPU_DEPTH_NONE);
+ GPU_point_size(7.0f);
+
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, data->end);
+ immEnd();
+ }
+ else {
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_FLAT_COLOR);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+
+ immUniform1f("lineWidth", 3.0f * U.pixelsize);
+
+ GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immAttrSkip(col);
+ immVertex3fv(pos, data->origin);
+ immAttr4fv(col, data->color);
+ immVertex3fv(pos, data->end);
+ immEnd();
+ }
+
+ immUnbindProgram();
+}
+
+static void wm_xr_raycast_init(wmOperator *op)
+{
+ BLI_assert(op->customdata == NULL);
+
+ op->customdata = MEM_callocN(sizeof(XrRaycastData), __func__);
+
+ SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ if (!st) {
+ return;
+ }
+
+ ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_XR);
+ if (!art) {
+ return;
+ }
+
+ XrRaycastData *data = op->customdata;
+ data->draw_handle = ED_region_draw_cb_activate(
+ art, wm_xr_raycast_draw, op->customdata, REGION_DRAW_POST_VIEW);
+}
+
+static void wm_xr_raycast_uninit(wmOperator *op)
+{
+ if (!op->customdata) {
+ return;
+ }
+
+ SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ if (st) {
+ ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_XR);
+ if (art) {
+ XrRaycastData *data = op->customdata;
+ ED_region_draw_cb_exit(art, data->draw_handle);
+ }
+ }
+
+ MEM_freeN(op->customdata);
+}
+
+static void wm_xr_raycast_update(wmOperator *op,
+ const wmXrData *xr,
+ const wmXrActionData *actiondata)
+{
+ XrRaycastData *data = op->customdata;
+ float ray_length, axis[3];
+
+ data->from_viewer = RNA_boolean_get(op->ptr, "from_viewer");
+ RNA_float_get_array(op->ptr, "axis", axis);
+ RNA_float_get_array(op->ptr, "color", data->color);
+
+ if (data->from_viewer) {
+ float viewer_rot[4];
+ WM_xr_session_state_viewer_pose_location_get(xr, data->origin);
+ WM_xr_session_state_viewer_pose_rotation_get(xr, viewer_rot);
+ mul_qt_v3(viewer_rot, axis);
+ ray_length = (xr->session_settings.clip_start + xr->session_settings.clip_end) / 2.0f;
+ }
+ else {
+ copy_v3_v3(data->origin, actiondata->controller_loc);
+ mul_qt_v3(actiondata->controller_rot, axis);
+ ray_length = xr->session_settings.clip_end;
+ }
+
+ copy_v3_v3(data->direction, axis);
+ madd_v3_v3v3fl(data->end, data->origin, data->direction, ray_length);
+}
+
+static void wm_xr_raycast(Scene *scene,
+ Depsgraph *depsgraph,
+ const float origin[3],
+ const float direction[3],
+ float *ray_dist,
+ bool selectable_only,
+ float r_location[3],
+ float r_normal[3],
+ int *r_index,
+ Object **r_ob,
+ float r_obmat[4][4])
+{
+ /* Uses same raycast method as Scene.ray_cast(). */
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, 0);
+
+ ED_transform_snap_object_project_ray_ex(
+ sctx,
+ depsgraph,
+ NULL,
+ &(const struct SnapObjectParams){
+ .snap_select = (selectable_only ? SNAP_SELECTABLE : SNAP_ALL)},
+ origin,
+ direction,
+ ray_dist,
+ r_location,
+ r_normal,
+ r_index,
+ r_ob,
+ r_obmat);
+
+ ED_transform_snap_object_context_destroy(sctx);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Navigation Fly
+ *
+ * Navigates the scene by moving/turning relative to navigation space or the XR viewer or
+ * controller.
+ * \{ */
+
+#define XR_DEFAULT_FLY_SPEED_MOVE 0.054f
+#define XR_DEFAULT_FLY_SPEED_TURN 0.03f
+
+typedef enum eXrFlyMode {
+ XR_FLY_FORWARD = 0,
+ XR_FLY_BACK = 1,
+ XR_FLY_LEFT = 2,
+ XR_FLY_RIGHT = 3,
+ XR_FLY_UP = 4,
+ XR_FLY_DOWN = 5,
+ XR_FLY_TURNLEFT = 6,
+ XR_FLY_TURNRIGHT = 7,
+ XR_FLY_VIEWER_FORWARD = 8,
+ XR_FLY_VIEWER_BACK = 9,
+ XR_FLY_VIEWER_LEFT = 10,
+ XR_FLY_VIEWER_RIGHT = 11,
+ XR_FLY_CONTROLLER_FORWARD = 12,
+} eXrFlyMode;
+
+typedef struct XrFlyData {
+ float viewer_rot[4];
+ double time_prev;
+} XrFlyData;
+
+static void wm_xr_fly_init(wmOperator *op, const wmXrData *xr)
+{
+ BLI_assert(op->customdata == NULL);
+
+ XrFlyData *data = op->customdata = MEM_callocN(sizeof(XrFlyData), __func__);
+
+ WM_xr_session_state_viewer_pose_rotation_get(xr, data->viewer_rot);
+ data->time_prev = PIL_check_seconds_timer();
+}
+
+static void wm_xr_fly_uninit(wmOperator *op)
+{
+ MEM_SAFE_FREE(op->customdata);
+}
+
+static void wm_xr_fly_compute_move(eXrFlyMode mode,
+ float speed,
+ const float ref_quat[4],
+ const float nav_mat[4][4],
+ bool locz_lock,
+ float r_delta[4][4])
+{
+ float ref_axes[3][3];
+ quat_to_mat3(ref_axes, ref_quat);
+
+ unit_m4(r_delta);
+
+ switch (mode) {
+ /* Navigation space reference. */
+ case XR_FLY_FORWARD:
+ madd_v3_v3fl(r_delta[3], ref_axes[1], speed);
+ return;
+ case XR_FLY_BACK:
+ madd_v3_v3fl(r_delta[3], ref_axes[1], -speed);
+ return;
+ case XR_FLY_LEFT:
+ madd_v3_v3fl(r_delta[3], ref_axes[0], -speed);
+ return;
+ case XR_FLY_RIGHT:
+ madd_v3_v3fl(r_delta[3], ref_axes[0], speed);
+ return;
+ case XR_FLY_UP:
+ case XR_FLY_DOWN:
+ if (!locz_lock) {
+ madd_v3_v3fl(r_delta[3], ref_axes[2], (mode == XR_FLY_UP) ? speed : -speed);
+ }
+ return;
+ /* Viewer/controller space reference. */
+ case XR_FLY_VIEWER_FORWARD:
+ case XR_FLY_CONTROLLER_FORWARD:
+ negate_v3_v3(r_delta[3], ref_axes[2]);
+ break;
+ case XR_FLY_VIEWER_BACK:
+ copy_v3_v3(r_delta[3], ref_axes[2]);
+ break;
+ case XR_FLY_VIEWER_LEFT:
+ negate_v3_v3(r_delta[3], ref_axes[0]);
+ break;
+ case XR_FLY_VIEWER_RIGHT:
+ copy_v3_v3(r_delta[3], ref_axes[0]);
+ break;
+ /* Unused. */
+ case XR_FLY_TURNLEFT:
+ case XR_FLY_TURNRIGHT:
+ BLI_assert_unreachable();
+ return;
+ }
+
+ if (locz_lock) {
+ /* Lock elevation in navigation space. */
+ float z_axis[3], projected[3];
+
+ normalize_v3_v3(z_axis, nav_mat[2]);
+ project_v3_v3v3_normalized(projected, r_delta[3], z_axis);
+ sub_v3_v3(r_delta[3], projected);
+
+ normalize_v3(r_delta[3]);
+ }
+
+ mul_v3_fl(r_delta[3], speed);
+}
+
+static void wm_xr_fly_compute_turn(eXrFlyMode mode,
+ float speed,
+ const float viewer_mat[4][4],
+ const float nav_mat[4][4],
+ const float nav_inv[4][4],
+ float r_delta[4][4])
+{
+ BLI_assert(mode == XR_FLY_TURNLEFT || mode == XR_FLY_TURNRIGHT);
+
+ float z_axis[3], m[3][3], prev[4][4], curr[4][4];
+
+ /* Turn around Z-axis in navigation space. */
+ normalize_v3_v3(z_axis, nav_mat[2]);
+ axis_angle_normalized_to_mat3(m, z_axis, (mode == XR_FLY_TURNLEFT) ? speed : -speed);
+ copy_m4_m3(r_delta, m);
+
+ copy_m4_m4(prev, viewer_mat);
+ mul_m4_m4m4(curr, r_delta, viewer_mat);
+
+ /* Lock location in base pose space. */
+ wm_xr_navlocks_apply(nav_mat, nav_inv, true, false, false, prev, curr);
+
+ invert_m4(prev);
+ mul_m4_m4m4(r_delta, curr, prev);
+}
+
+static void wm_xr_basenav_rotation_calc(const wmXrData *xr,
+ const float nav_rotation[4],
+ float r_rotation[4])
+{
+ /* Apply nav rotation to base pose Z-rotation. */
+ float base_eul[3], base_quatz[4];
+ quat_to_eul(base_eul, xr->runtime->session_state.prev_base_pose.orientation_quat);
+ axis_angle_to_quat_single(base_quatz, 'Z', base_eul[2]);
+ mul_qt_qtqt(r_rotation, nav_rotation, base_quatz);
+}
+
+static int wm_xr_navigation_fly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ wm_xr_fly_init(op, &wm->xr);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_xr_navigation_fly_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ return OPERATOR_CANCELLED;
+}
+
+static int wm_xr_navigation_fly_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ if (event->val == KM_RELEASE) {
+ wm_xr_fly_uninit(op);
+ return OPERATOR_FINISHED;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+ XrFlyData *data = op->customdata;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrData *xr = &wm->xr;
+ eXrFlyMode mode;
+ bool turn, locz_lock, dir_lock, speed_frame_based;
+ bool speed_interp_cubic = false;
+ float speed, speed_max, speed_p0[2], speed_p1[2];
+ GHOST_XrPose nav_pose;
+ float nav_mat[4][4], delta[4][4], out[4][4];
+
+ const double time_now = PIL_check_seconds_timer();
+
+ mode = (eXrFlyMode)RNA_enum_get(op->ptr, "mode");
+ turn = (mode == XR_FLY_TURNLEFT || mode == XR_FLY_TURNRIGHT);
+
+ locz_lock = RNA_boolean_get(op->ptr, "lock_location_z");
+ dir_lock = RNA_boolean_get(op->ptr, "lock_direction");
+ speed_frame_based = RNA_boolean_get(op->ptr, "speed_frame_based");
+ speed = RNA_float_get(op->ptr, "speed_min");
+ speed_max = RNA_float_get(op->ptr, "speed_max");
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "speed_interpolation0");
+ if (prop && RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, speed_p0);
+ speed_interp_cubic = true;
+ }
+ else {
+ speed_p0[0] = speed_p0[1] = 0.0f;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "speed_interpolation1");
+ if (prop && RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, speed_p1);
+ speed_interp_cubic = true;
+ }
+ else {
+ speed_p1[0] = speed_p1[1] = 1.0f;
+ }
+
+ /* Ensure valid interpolation. */
+ if (speed_max < speed) {
+ speed_max = speed;
+ }
+
+ /* Interpolate between min/max speeds based on button state. */
+ switch (actiondata->type) {
+ case XR_BOOLEAN_INPUT:
+ speed = speed_max;
+ break;
+ case XR_FLOAT_INPUT:
+ case XR_VECTOR2F_INPUT: {
+ float state = (actiondata->type == XR_FLOAT_INPUT) ? fabsf(actiondata->state[0]) :
+ len_v2(actiondata->state);
+ float speed_t = (actiondata->float_threshold < 1.0f) ?
+ (state - actiondata->float_threshold) /
+ (1.0f - actiondata->float_threshold) :
+ 1.0f;
+ if (speed_interp_cubic) {
+ float start[2], end[2], p[2];
+
+ start[0] = 0.0f;
+ start[1] = speed;
+ speed_p0[1] = speed + speed_p0[1] * (speed_max - speed);
+ speed_p1[1] = speed + speed_p1[1] * (speed_max - speed);
+ end[0] = 1.0f;
+ end[1] = speed_max;
+
+ interp_v2_v2v2v2v2_cubic(p, start, speed_p0, speed_p1, end, speed_t);
+ speed = p[1];
+ }
+ else {
+ speed += speed_t * (speed_max - speed);
+ }
+ break;
+ }
+ case XR_POSE_INPUT:
+ case XR_VIBRATION_OUTPUT:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ if (!speed_frame_based) {
+ /* Adjust speed based on last update time. */
+ speed *= time_now - data->time_prev;
+ }
+ data->time_prev = time_now;
+
+ WM_xr_session_state_nav_location_get(xr, nav_pose.position);
+ WM_xr_session_state_nav_rotation_get(xr, nav_pose.orientation_quat);
+ wm_xr_pose_to_mat(&nav_pose, nav_mat);
+
+ if (turn) {
+ if (dir_lock) {
+ unit_m4(delta);
+ }
+ else {
+ GHOST_XrPose viewer_pose;
+ float viewer_mat[4][4], nav_inv[4][4];
+
+ WM_xr_session_state_viewer_pose_location_get(xr, viewer_pose.position);
+ WM_xr_session_state_viewer_pose_rotation_get(xr, viewer_pose.orientation_quat);
+ wm_xr_pose_to_mat(&viewer_pose, viewer_mat);
+ wm_xr_pose_to_imat(&nav_pose, nav_inv);
+
+ wm_xr_fly_compute_turn(mode, speed, viewer_mat, nav_mat, nav_inv, delta);
+ }
+ }
+ else {
+ float nav_scale, ref_quat[4];
+
+ /* Adjust speed for base and navigation scale. */
+ WM_xr_session_state_nav_scale_get(xr, &nav_scale);
+ speed *= xr->session_settings.base_scale * nav_scale;
+
+ switch (mode) {
+ /* Move relative to navigation space. */
+ case XR_FLY_FORWARD:
+ case XR_FLY_BACK:
+ case XR_FLY_LEFT:
+ case XR_FLY_RIGHT:
+ case XR_FLY_UP:
+ case XR_FLY_DOWN:
+ wm_xr_basenav_rotation_calc(xr, nav_pose.orientation_quat, ref_quat);
+ break;
+ /* Move relative to viewer. */
+ case XR_FLY_VIEWER_FORWARD:
+ case XR_FLY_VIEWER_BACK:
+ case XR_FLY_VIEWER_LEFT:
+ case XR_FLY_VIEWER_RIGHT:
+ if (dir_lock) {
+ copy_qt_qt(ref_quat, data->viewer_rot);
+ }
+ else {
+ WM_xr_session_state_viewer_pose_rotation_get(xr, ref_quat);
+ }
+ break;
+ /* Move relative to controller. */
+ case XR_FLY_CONTROLLER_FORWARD:
+ copy_qt_qt(ref_quat, actiondata->controller_rot);
+ break;
+ /* Unused. */
+ case XR_FLY_TURNLEFT:
+ case XR_FLY_TURNRIGHT:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ wm_xr_fly_compute_move(mode, speed, ref_quat, nav_mat, locz_lock, delta);
+ }
+
+ mul_m4_m4m4(out, delta, nav_mat);
+
+ WM_xr_session_state_nav_location_set(xr, out[3]);
+ if (turn) {
+ mat4_to_quat(nav_pose.orientation_quat, out);
+ WM_xr_session_state_nav_rotation_set(xr, nav_pose.orientation_quat);
+ }
+
+ if (event->val == KM_PRESS) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ /* XR events currently only support press and release. */
+ BLI_assert_unreachable();
+ wm_xr_fly_uninit(op);
+ return OPERATOR_CANCELLED;
+}
+
+static void WM_OT_xr_navigation_fly(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "XR Navigation Fly";
+ ot->idname = "WM_OT_xr_navigation_fly";
+ ot->description = "Move/turn relative to the VR viewer or controller";
+
+ /* callbacks */
+ ot->invoke = wm_xr_navigation_fly_invoke;
+ ot->exec = wm_xr_navigation_fly_exec;
+ ot->modal = wm_xr_navigation_fly_modal;
+ ot->poll = wm_xr_operator_sessionactive;
+
+ /* properties */
+ static const EnumPropertyItem fly_modes[] = {
+ {XR_FLY_FORWARD, "FORWARD", 0, "Forward", "Move along navigation forward axis"},
+ {XR_FLY_BACK, "BACK", 0, "Back", "Move along navigation back axis"},
+ {XR_FLY_LEFT, "LEFT", 0, "Left", "Move along navigation left axis"},
+ {XR_FLY_RIGHT, "RIGHT", 0, "Right", "Move along navigation right axis"},
+ {XR_FLY_UP, "UP", 0, "Up", "Move along navigation up axis"},
+ {XR_FLY_DOWN, "DOWN", 0, "Down", "Move along navigation down axis"},
+ {XR_FLY_TURNLEFT,
+ "TURNLEFT",
+ 0,
+ "Turn Left",
+ "Turn counter-clockwise around navigation up axis"},
+ {XR_FLY_TURNRIGHT, "TURNRIGHT", 0, "Turn Right", "Turn clockwise around navigation up axis"},
+ {XR_FLY_VIEWER_FORWARD,
+ "VIEWER_FORWARD",
+ 0,
+ "Viewer Forward",
+ "Move along viewer's forward axis"},
+ {XR_FLY_VIEWER_BACK, "VIEWER_BACK", 0, "Viewer Back", "Move along viewer's back axis"},
+ {XR_FLY_VIEWER_LEFT, "VIEWER_LEFT", 0, "Viewer Left", "Move along viewer's left axis"},
+ {XR_FLY_VIEWER_RIGHT, "VIEWER_RIGHT", 0, "Viewer Right", "Move along viewer's right axis"},
+ {XR_FLY_CONTROLLER_FORWARD,
+ "CONTROLLER_FORWARD",
+ 0,
+ "Controller Forward",
+ "Move along controller's forward axis"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const float default_speed_p0[2] = {0.0f, 0.0f};
+ static const float default_speed_p1[2] = {1.0f, 1.0f};
+
+ RNA_def_enum(ot->srna, "mode", fly_modes, XR_FLY_VIEWER_FORWARD, "Mode", "Fly mode");
+ RNA_def_boolean(
+ ot->srna, "lock_location_z", false, "Lock Elevation", "Prevent changes to viewer elevation");
+ RNA_def_boolean(ot->srna,
+ "lock_direction",
+ false,
+ "Lock Direction",
+ "Limit movement to viewer's intial direction");
+ RNA_def_boolean(ot->srna,
+ "speed_frame_based",
+ true,
+ "Frame Based Speed",
+ "Apply fixed movement deltas every update");
+ RNA_def_float(ot->srna,
+ "speed_min",
+ XR_DEFAULT_FLY_SPEED_MOVE / 3.0f,
+ 0.0f,
+ 1000.0f,
+ "Minimum Speed",
+ "Minimum move (turn) speed in meters (radians) per second or frame",
+ 0.0f,
+ 1000.0f);
+ RNA_def_float(ot->srna,
+ "speed_max",
+ XR_DEFAULT_FLY_SPEED_MOVE,
+ 0.0f,
+ 1000.0f,
+ "Maximum Speed",
+ "Maximum move (turn) speed in meters (radians) per second or frame",
+ 0.0f,
+ 1000.0f);
+ RNA_def_float_vector(ot->srna,
+ "speed_interpolation0",
+ 2,
+ default_speed_p0,
+ 0.0f,
+ 1.0f,
+ "Speed Interpolation 0",
+ "First cubic spline control point between min/max speeds",
+ 0.0f,
+ 1.0f);
+ RNA_def_float_vector(ot->srna,
+ "speed_interpolation1",
+ 2,
+ default_speed_p1,
+ 0.0f,
+ 1.0f,
+ "Speed Interpolation 1",
+ "Second cubic spline control point between min/max speeds",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Navigation Teleport
+ *
+ * Casts a ray from an XR controller's pose and teleports to any hit geometry.
+ * \{ */
+
+static void wm_xr_navigation_teleport(bContext *C,
+ wmXrData *xr,
+ const float origin[3],
+ const float direction[3],
+ float *ray_dist,
+ bool selectable_only,
+ const bool teleport_axes[3],
+ float teleport_t,
+ float teleport_ofs)
+{
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ float location[3];
+ float normal[3];
+ int index;
+ Object *ob = NULL;
+ float obmat[4][4];
+
+ wm_xr_raycast(scene,
+ depsgraph,
+ origin,
+ direction,
+ ray_dist,
+ selectable_only,
+ location,
+ normal,
+ &index,
+ &ob,
+ obmat);
+
+ /* Teleport. */
+ if (ob) {
+ float nav_location[3], nav_rotation[4], viewer_location[3];
+ float nav_axes[3][3], projected[3], v0[3], v1[3];
+ float out[3] = {0.0f, 0.0f, 0.0f};
+
+ WM_xr_session_state_nav_location_get(xr, nav_location);
+ WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
+ WM_xr_session_state_viewer_pose_location_get(xr, viewer_location);
+
+ wm_xr_basenav_rotation_calc(xr, nav_rotation, nav_rotation);
+ quat_to_mat3(nav_axes, nav_rotation);
+
+ /* Project locations onto navigation axes. */
+ for (int a = 0; a < 3; ++a) {
+ project_v3_v3v3_normalized(projected, nav_location, nav_axes[a]);
+ if (teleport_axes[a]) {
+ /* Interpolate between projected locations. */
+ project_v3_v3v3_normalized(v0, location, nav_axes[a]);
+ project_v3_v3v3_normalized(v1, viewer_location, nav_axes[a]);
+ sub_v3_v3(v0, v1);
+ madd_v3_v3fl(projected, v0, teleport_t);
+ /* Subtract offset. */
+ project_v3_v3v3_normalized(v0, normal, nav_axes[a]);
+ madd_v3_v3fl(projected, v0, teleport_ofs);
+ }
+ /* Add to final location. */
+ add_v3_v3(out, projected);
+ }
+
+ WM_xr_session_state_nav_location_set(xr, out);
+ }
+}
+
+static int wm_xr_navigation_teleport_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ wm_xr_raycast_init(op);
+
+ int retval = op->type->modal(C, op, event);
+
+ if ((retval & OPERATOR_RUNNING_MODAL) != 0) {
+ WM_event_add_modal_handler(C, op);
+ }
+
+ return retval;
+}
+
+static int wm_xr_navigation_teleport_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ return OPERATOR_CANCELLED;
+}
+
+static int wm_xr_navigation_teleport_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrData *xr = &wm->xr;
+
+ wm_xr_raycast_update(op, xr, actiondata);
+
+ switch (event->val) {
+ case KM_PRESS:
+ return OPERATOR_RUNNING_MODAL;
+ case KM_RELEASE: {
+ XrRaycastData *data = op->customdata;
+ bool selectable_only, teleport_axes[3];
+ float teleport_t, teleport_ofs, ray_dist;
+
+ RNA_boolean_get_array(op->ptr, "teleport_axes", teleport_axes);
+ teleport_t = RNA_float_get(op->ptr, "interpolation");
+ teleport_ofs = RNA_float_get(op->ptr, "offset");
+ selectable_only = RNA_boolean_get(op->ptr, "selectable_only");
+ ray_dist = RNA_float_get(op->ptr, "distance");
+
+ wm_xr_navigation_teleport(C,
+ xr,
+ data->origin,
+ data->direction,
+ &ray_dist,
+ selectable_only,
+ teleport_axes,
+ teleport_t,
+ teleport_ofs);
+
+ wm_xr_raycast_uninit(op);
+
+ return OPERATOR_FINISHED;
+ }
+ default:
+ /* XR events currently only support press and release. */
+ BLI_assert_unreachable();
+ wm_xr_raycast_uninit(op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void WM_OT_xr_navigation_teleport(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "XR Navigation Teleport";
+ ot->idname = "WM_OT_xr_navigation_teleport";
+ ot->description = "Set VR viewer location to controller raycast hit location";
+
+ /* callbacks */
+ ot->invoke = wm_xr_navigation_teleport_invoke;
+ ot->exec = wm_xr_navigation_teleport_exec;
+ ot->modal = wm_xr_navigation_teleport_modal;
+ ot->poll = wm_xr_operator_sessionactive;
+
+ /* properties */
+ static bool default_teleport_axes[3] = {true, true, true};
+
+ RNA_def_boolean_vector(ot->srna,
+ "teleport_axes",
+ 3,
+ default_teleport_axes,
+ "Teleport Axes",
+ "Enabled teleport axes in navigation space");
+ RNA_def_float(ot->srna,
+ "interpolation",
+ 1.0f,
+ 0.0f,
+ 1.0f,
+ "Interpolation",
+ "Interpolation factor between viewer and hit locations",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "offset",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Offset",
+ "Offset along hit normal to subtract from final location",
+ 0.0f,
+ FLT_MAX);
+ RNA_def_boolean(ot->srna,
+ "selectable_only",
+ true,
+ "Selectable Only",
+ "Only allow selectable objects to influence raycast result");
+ RNA_def_float(ot->srna,
+ "distance",
+ BVH_RAYCAST_DIST_MAX,
+ 0.0,
+ BVH_RAYCAST_DIST_MAX,
+ "",
+ "Maximum raycast distance",
+ 0.0,
+ BVH_RAYCAST_DIST_MAX);
+ RNA_def_boolean(
+ ot->srna, "from_viewer", false, "From Viewer", "Use viewer pose as raycast origin");
+ RNA_def_float_vector(ot->srna,
+ "axis",
+ 3,
+ g_xr_default_raycast_axis,
+ -1.0f,
+ 1.0f,
+ "Axis",
+ "Raycast axis in controller/viewer space",
+ -1.0f,
+ 1.0f);
+ RNA_def_float_color(ot->srna,
+ "color",
+ 4,
+ g_xr_default_raycast_color,
+ 0.0f,
+ 1.0f,
+ "Color",
+ "Raycast color",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Navigation Reset
+ *
+ * Resets XR navigation deltas relative to session base pose.
+ * \{ */
+
+static int wm_xr_navigation_reset_exec(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrData *xr = &wm->xr;
+ bool reset_loc, reset_rot, reset_scale;
+
+ reset_loc = RNA_boolean_get(op->ptr, "location");
+ reset_rot = RNA_boolean_get(op->ptr, "rotation");
+ reset_scale = RNA_boolean_get(op->ptr, "scale");
+
+ if (reset_loc) {
+ float loc[3];
+ if (!reset_scale) {
+ float nav_rotation[4], nav_scale;
+
+ WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
+ WM_xr_session_state_nav_scale_get(xr, &nav_scale);
+
+ /* Adjust location based on scale. */
+ mul_v3_v3fl(loc, xr->runtime->session_state.prev_base_pose.position, nav_scale);
+ sub_v3_v3(loc, xr->runtime->session_state.prev_base_pose.position);
+ mul_qt_v3(nav_rotation, loc);
+ negate_v3(loc);
+ }
+ else {
+ zero_v3(loc);
+ }
+ WM_xr_session_state_nav_location_set(xr, loc);
+ }
+
+ if (reset_rot) {
+ float rot[4];
+ unit_qt(rot);
+ WM_xr_session_state_nav_rotation_set(xr, rot);
+ }
+
+ if (reset_scale) {
+ if (!reset_loc) {
+ float nav_location[3], nav_rotation[4], nav_scale;
+ float nav_axes[3][3], v[3];
+
+ WM_xr_session_state_nav_location_get(xr, nav_location);
+ WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
+ WM_xr_session_state_nav_scale_get(xr, &nav_scale);
+
+ /* Offset any location changes when changing scale. */
+ mul_v3_v3fl(v, xr->runtime->session_state.prev_base_pose.position, nav_scale);
+ sub_v3_v3(v, xr->runtime->session_state.prev_base_pose.position);
+ mul_qt_v3(nav_rotation, v);
+ add_v3_v3(nav_location, v);
+
+ /* Reset elevation to base pose value. */
+ quat_to_mat3(nav_axes, nav_rotation);
+ project_v3_v3v3_normalized(v, nav_location, nav_axes[2]);
+ sub_v3_v3(nav_location, v);
+
+ WM_xr_session_state_nav_location_set(xr, nav_location);
+ }
+ WM_xr_session_state_nav_scale_set(xr, 1.0f);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void WM_OT_xr_navigation_reset(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "XR Navigation Reset";
+ ot->idname = "WM_OT_xr_navigation_reset";
+ ot->description = "Reset VR navigation deltas relative to session base pose";
+
+ /* callbacks */
+ ot->exec = wm_xr_navigation_reset_exec;
+ ot->poll = wm_xr_operator_sessionactive;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "location", true, "Location", "Reset location deltas");
+ RNA_def_boolean(ot->srna, "rotation", true, "Rotation", "Reset rotation deltas");
+ RNA_def_boolean(ot->srna, "scale", true, "Scale", "Reset scale deltas");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Registration
+ * \{ */
+
+void wm_xr_operatortypes_register(void)
+{
+ WM_operatortype_append(WM_OT_xr_session_toggle);
+ WM_operatortype_append(WM_OT_xr_navigation_grab);
+ WM_operatortype_append(WM_OT_xr_navigation_fly);
+ WM_operatortype_append(WM_OT_xr_navigation_teleport);
+ WM_operatortype_append(WM_OT_xr_navigation_reset);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 9f53db1347c..3224869b04a 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -66,11 +66,20 @@ static void wm_xr_session_create_cb(void)
Main *bmain = G_MAIN;
wmWindowManager *wm = bmain->wm.first;
wmXrData *xr_data = &wm->xr;
+ wmXrSessionState *state = &xr_data->runtime->session_state;
+ XrSessionSettings *settings = &xr_data->session_settings;
/* Get action set data from Python. */
BKE_callback_exec_null(bmain, BKE_CB_EVT_XR_SESSION_START_PRE);
wm_xr_session_actions_init(xr_data);
+
+ /* Initialize navigation. */
+ WM_xr_session_state_navigation_reset(state);
+ if (settings->base_scale < FLT_EPSILON) {
+ settings->base_scale = 1.0f;
+ }
+ state->prev_base_scale = settings->base_scale;
}
static void wm_xr_session_controller_data_free(wmXrSessionState *state)
@@ -128,8 +137,10 @@ void wm_xr_session_toggle(wmWindowManager *wm,
wmXrData *xr_data = &wm->xr;
if (WM_xr_session_exists(xr_data)) {
- GHOST_XrSessionEnd(xr_data->runtime->context);
+ /* Must set first, since #GHOST_XrSessionEnd() may immediately free the runtime. */
xr_data->runtime->session_state.is_started = false;
+
+ GHOST_XrSessionEnd(xr_data->runtime->context);
}
else {
GHOST_XrSessionBeginInfo begin_info;
@@ -167,7 +178,8 @@ bool WM_xr_session_is_ready(const wmXrData *xr)
static void wm_xr_session_base_pose_calc(const Scene *scene,
const XrSessionSettings *settings,
- GHOST_XrPose *r_base_pose)
+ GHOST_XrPose *r_base_pose,
+ float *r_base_scale)
{
const Object *base_pose_object = ((settings->base_pose_type == XR_BASE_POSE_OBJECT) &&
settings->base_pose_object) ?
@@ -198,6 +210,8 @@ static void wm_xr_session_base_pose_calc(const Scene *scene,
copy_v3_fl(r_base_pose->position, 0.0f);
axis_angle_to_quat_single(r_base_pose->orientation_quat, 'X', M_PI_2);
}
+
+ *r_base_scale = settings->base_scale;
}
static void wm_xr_session_draw_data_populate(wmXrData *xr_data,
@@ -213,7 +227,8 @@ static void wm_xr_session_draw_data_populate(wmXrData *xr_data,
r_draw_data->xr_data = xr_data;
r_draw_data->surface_data = g_xr_surface->customdata;
- wm_xr_session_base_pose_calc(r_draw_data->scene, settings, &r_draw_data->base_pose);
+ wm_xr_session_base_pose_calc(
+ r_draw_data->scene, settings, &r_draw_data->base_pose, &r_draw_data->base_scale);
}
wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm,
@@ -291,7 +306,7 @@ static wmXrSessionStateEvent wm_xr_session_state_to_event(const wmXrSessionState
return SESSION_STATE_EVENT_NONE;
}
-void wm_xr_session_draw_data_update(const wmXrSessionState *state,
+void wm_xr_session_draw_data_update(wmXrSessionState *state,
const XrSessionSettings *settings,
const GHOST_XrDrawViewInfo *draw_view,
wmXrDrawData *draw_data)
@@ -319,6 +334,8 @@ void wm_xr_session_draw_data_update(const wmXrSessionState *state,
else {
copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
}
+ /* Reset navigation. */
+ WM_xr_session_state_navigation_reset(state);
break;
case SESSION_STATE_EVENT_POSITION_TRACKING_TOGGLE:
if (use_position_tracking) {
@@ -348,29 +365,32 @@ void wm_xr_session_state_update(const XrSessionSettings *settings,
wmXrSessionState *state)
{
GHOST_XrPose viewer_pose;
- const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
- const bool use_absolute_tracking = settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING;
-
- mul_qt_qtqt(viewer_pose.orientation_quat,
- draw_data->base_pose.orientation_quat,
- draw_view->local_pose.orientation_quat);
- copy_v3_v3(viewer_pose.position, draw_data->base_pose.position);
- /* The local pose and the eye pose (which is copied from an earlier local pose) both are view
- * space, so Y-up. In this case we need them in regular Z-up. */
- if (use_position_tracking) {
- viewer_pose.position[0] += draw_view->local_pose.position[0];
- viewer_pose.position[1] -= draw_view->local_pose.position[2];
- viewer_pose.position[2] += draw_view->local_pose.position[1];
- }
- if (!use_absolute_tracking) {
- viewer_pose.position[0] -= draw_data->eye_position_ofs[0];
- viewer_pose.position[1] += draw_data->eye_position_ofs[2];
- viewer_pose.position[2] -= draw_data->eye_position_ofs[1];
- }
-
- copy_v3_v3(state->viewer_pose.position, viewer_pose.position);
- copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat);
- wm_xr_pose_to_imat(&viewer_pose, state->viewer_viewmat);
+ float viewer_mat[4][4], base_mat[4][4], nav_mat[4][4];
+
+ /* Calculate viewer matrix. */
+ copy_qt_qt(viewer_pose.orientation_quat, draw_view->local_pose.orientation_quat);
+ if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
+ zero_v3(viewer_pose.position);
+ }
+ else {
+ copy_v3_v3(viewer_pose.position, draw_view->local_pose.position);
+ }
+ if ((settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
+ sub_v3_v3(viewer_pose.position, draw_data->eye_position_ofs);
+ }
+ wm_xr_pose_to_mat(&viewer_pose, viewer_mat);
+
+ /* Apply base pose and navigation. */
+ wm_xr_pose_scale_to_mat(&draw_data->base_pose, draw_data->base_scale, base_mat);
+ wm_xr_pose_scale_to_mat(&state->nav_pose_prev, state->nav_scale_prev, nav_mat);
+ mul_m4_m4m4(state->viewer_mat_base, base_mat, viewer_mat);
+ mul_m4_m4m4(viewer_mat, nav_mat, state->viewer_mat_base);
+
+ /* Save final viewer pose and viewmat. */
+ mat4_to_loc_quat(state->viewer_pose.position, state->viewer_pose.orientation_quat, viewer_mat);
+ wm_xr_pose_scale_to_imat(
+ &state->viewer_pose, draw_data->base_scale * state->nav_scale_prev, state->viewer_viewmat);
+
/* No idea why, but multiplying by two seems to make it match the VR view more. */
state->focal_len = 2.0f *
fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left,
@@ -378,7 +398,10 @@ void wm_xr_session_state_update(const XrSessionSettings *settings,
copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
memcpy(&state->prev_base_pose, &draw_data->base_pose, sizeof(state->prev_base_pose));
+ state->prev_base_scale = draw_data->base_scale;
memcpy(&state->prev_local_pose, &draw_view->local_pose, sizeof(state->prev_local_pose));
+ copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
+
state->prev_settings_flag = settings->flag;
state->prev_base_pose_type = settings->base_pose_type;
state->prev_base_pose_object = settings->base_pose_object;
@@ -503,6 +526,74 @@ bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr,
return true;
}
+bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3])
+{
+ if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
+ zero_v3(r_location);
+ return false;
+ }
+
+ copy_v3_v3(r_location, xr->runtime->session_state.nav_pose.position);
+ return true;
+}
+
+void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3])
+{
+ if (WM_xr_session_exists(xr)) {
+ copy_v3_v3(xr->runtime->session_state.nav_pose.position, location);
+ xr->runtime->session_state.is_navigation_dirty = true;
+ }
+}
+
+bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4])
+{
+ if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
+ unit_qt(r_rotation);
+ return false;
+ }
+
+ copy_qt_qt(r_rotation, xr->runtime->session_state.nav_pose.orientation_quat);
+ return true;
+}
+
+void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4])
+{
+ if (WM_xr_session_exists(xr)) {
+ BLI_ASSERT_UNIT_QUAT(rotation);
+ copy_qt_qt(xr->runtime->session_state.nav_pose.orientation_quat, rotation);
+ xr->runtime->session_state.is_navigation_dirty = true;
+ }
+}
+
+bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale)
+{
+ if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
+ *r_scale = 1.0f;
+ return false;
+ }
+
+ *r_scale = xr->runtime->session_state.nav_scale;
+ return true;
+}
+
+void WM_xr_session_state_nav_scale_set(wmXrData *xr, float scale)
+{
+ if (WM_xr_session_exists(xr)) {
+ /* Clamp to reasonable values. */
+ CLAMP(scale, xr->session_settings.clip_start, xr->session_settings.clip_end);
+ xr->runtime->session_state.nav_scale = scale;
+ xr->runtime->session_state.is_navigation_dirty = true;
+ }
+}
+
+void WM_xr_session_state_navigation_reset(wmXrSessionState *state)
+{
+ zero_v3(state->nav_pose.position);
+ unit_qt(state->nav_pose.orientation_quat);
+ state->nav_scale = 1.0f;
+ state->is_navigation_dirty = true;
+}
+
/* -------------------------------------------------------------------- */
/** \name XR-Session Actions
*
@@ -522,16 +613,21 @@ void wm_xr_session_actions_init(wmXrData *xr)
static void wm_xr_session_controller_pose_calc(const GHOST_XrPose *raw_pose,
const float view_ofs[3],
const float base_mat[4][4],
+ const float nav_mat[4][4],
GHOST_XrPose *r_pose,
- float r_mat[4][4])
+ float r_mat[4][4],
+ float r_mat_base[4][4])
{
float m[4][4];
/* Calculate controller matrix in world space. */
wm_xr_pose_to_mat(raw_pose, m);
- /* Apply eye position and base pose offsets. */
+ /* Apply eye position offset. */
sub_v3_v3(m[3], view_ofs);
- mul_m4_m4m4(r_mat, base_mat, m);
+
+ /* Apply base pose and navigation. */
+ mul_m4_m4m4(r_mat_base, base_mat, m);
+ mul_m4_m4m4(r_mat, nav_mat, r_mat_base);
/* Save final pose. */
mat4_to_loc_quat(r_pose->position, r_pose->orientation_quat, r_mat);
@@ -547,7 +643,7 @@ static void wm_xr_session_controller_data_update(const XrSessionSettings *settin
BLI_assert(grip_action->count_subaction_paths == BLI_listbase_count(&state->controllers));
unsigned int subaction_idx = 0;
- float view_ofs[3], base_mat[4][4];
+ float view_ofs[3], base_mat[4][4], nav_mat[4][4];
if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
copy_v3_v3(view_ofs, state->prev_local_pose.position);
@@ -559,19 +655,24 @@ static void wm_xr_session_controller_data_update(const XrSessionSettings *settin
add_v3_v3(view_ofs, state->prev_eye_position_ofs);
}
- wm_xr_pose_to_mat(&state->prev_base_pose, base_mat);
+ wm_xr_pose_scale_to_mat(&state->prev_base_pose, state->prev_base_scale, base_mat);
+ wm_xr_pose_scale_to_mat(&state->nav_pose, state->nav_scale, nav_mat);
LISTBASE_FOREACH_INDEX (wmXrController *, controller, &state->controllers, subaction_idx) {
wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)grip_action->states)[subaction_idx],
view_ofs,
base_mat,
+ nav_mat,
&controller->grip_pose,
- controller->grip_mat);
+ controller->grip_mat,
+ controller->grip_mat_base);
wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)aim_action->states)[subaction_idx],
view_ofs,
base_mat,
+ nav_mat,
&controller->aim_pose,
- controller->aim_mat);
+ controller->aim_mat,
+ controller->aim_mat_base);
if (!controller->model) {
/* Notify GHOST to load/continue loading the controller model data. This can be called more
@@ -1094,10 +1195,26 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
return;
}
+ XrSessionSettings *settings = &xr->session_settings;
GHOST_XrContextHandle xr_context = xr->runtime->context;
wmXrSessionState *state = &xr->runtime->session_state;
wmXrActionSet *active_action_set = state->active_action_set;
+ if (state->is_navigation_dirty) {
+ memcpy(&state->nav_pose_prev, &state->nav_pose, sizeof(state->nav_pose_prev));
+ state->nav_scale_prev = state->nav_scale;
+ state->is_navigation_dirty = false;
+
+ /* Update viewer pose with any navigation changes since the last actions sync so that data
+ * is correct for queries. */
+ float m[4][4], viewer_mat[4][4];
+ wm_xr_pose_scale_to_mat(&state->nav_pose, state->nav_scale, m);
+ mul_m4_m4m4(viewer_mat, m, state->viewer_mat_base);
+ mat4_to_loc_quat(state->viewer_pose.position, state->viewer_pose.orientation_quat, viewer_mat);
+ wm_xr_pose_scale_to_imat(
+ &state->viewer_pose, settings->base_scale * state->nav_scale, state->viewer_viewmat);
+ }
+
int ret = GHOST_XrSyncActions(xr_context, active_action_set ? active_action_set->name : NULL);
if (!ret) {
return;
@@ -1108,7 +1225,7 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
wmWindow *win = wm_xr_session_root_window_or_fallback_get(wm, xr->runtime);
if (active_action_set->controller_grip_action && active_action_set->controller_aim_action) {
- wm_xr_session_controller_data_update(&xr->session_settings,
+ wm_xr_session_controller_data_update(settings,
active_action_set->controller_grip_action,
active_action_set->controller_aim_action,
xr_context,
diff --git a/source/blender/windowmanager/xr/wm_xr.h b/source/blender/windowmanager/xr/wm_xr.h
index 0f0fbe8bc00..caba6038c56 100644
--- a/source/blender/windowmanager/xr/wm_xr.h
+++ b/source/blender/windowmanager/xr/wm_xr.h
@@ -30,3 +30,6 @@ bool wm_xr_init(wmWindowManager *wm);
void wm_xr_exit(wmWindowManager *wm);
void wm_xr_session_toggle(wmWindowManager *wm, wmWindow *win, wmXrSessionExitFn session_exit_fn);
bool wm_xr_events_handle(wmWindowManager *wm);
+
+/* wm_xr_operators.c */
+void wm_xr_operatortypes_register(void);
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index de560e39606..816d3a60fc3 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -990,6 +990,13 @@ elseif(WIN32)
DESTINATION "."
)
+ if(WITH_BLENDER_THUMBNAILER)
+ install(
+ TARGETS BlendThumb
+ DESTINATION "."
+ )
+ endif()
+
if(WITH_DRACO)
install(
PROGRAMS $<TARGET_FILE:extern_draco>
diff --git a/source/tools b/source/tools
-Subproject 7c5acb95df918503d11cfc43172ce1390101928
+Subproject 2e8c879248822c8e500ed49d79acc605e5aa75b
diff --git a/tests/performance/benchmark b/tests/performance/benchmark
index a58c339e9f8..80556674dcc 100755
--- a/tests/performance/benchmark
+++ b/tests/performance/benchmark
@@ -4,6 +4,7 @@
import api
import argparse
import fnmatch
+import glob
import pathlib
import shutil
import sys
@@ -228,6 +229,9 @@ def cmd_reset(env: api.TestEnvironment, argv: List):
config.queue.write()
+ if args.test == '*':
+ shutil.rmtree(config.logs_dir)
+
def cmd_run(env: api.TestEnvironment, argv: List, update_only: bool):
# Run tests.
parser = argparse.ArgumentParser()
@@ -274,7 +278,17 @@ def cmd_graph(argv: List):
parser.add_argument('-o', '--output', type=str, required=True)
args = parser.parse_args(argv)
- graph = api.TestGraph([pathlib.Path(path) for path in args.json_file])
+ # For directories, use all json files in the directory.
+ json_files = []
+ for path in args.json_file:
+ path = pathlib.Path(path)
+ if path.is_dir():
+ for filepath in glob.iglob(str(path / '*.json')):
+ json_files.append(pathlib.Path(filepath))
+ else:
+ json_files.append(path)
+
+ graph = api.TestGraph(json_files)
graph.write(pathlib.Path(args.output))
def main():